summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.cvsignore37
-rw-r--r--BUILD/.cvsignore1
-rwxr-xr-xBUILD/compile-alpha7
-rwxr-xr-xBUILD/compile-alpha-ccc35
-rwxr-xr-xBUILD/compile-alpha-debug7
-rw-r--r--BUILD/compile-ia64-O012
-rw-r--r--BUILD/compile-ia64-O0-sgicc12
-rw-r--r--BUILD/compile-ia64-O212
-rw-r--r--BUILD/compile-ia64-O2-sgicc12
-rw-r--r--BUILD/compile-ia64-O68
-rwxr-xr-xBUILD/compile-pentium8
-rwxr-xr-xBUILD/compile-pentium-debug19
-rwxr-xr-xBUILD/compile-pentium-gcov16
-rwxr-xr-xBUILD/compile-pentium-myodbc6
-rwxr-xr-xBUILD/compile-solaris-sparc9
-rwxr-xr-xBUILD/compile-solaris-sparc-purify13
-rwxr-xr-xBUILD/test-alpha-ccc11
-rwxr-xr-xBuild-tools/Do-all-build-steps74
-rwxr-xr-xBuild-tools/Do-compile421
-rwxr-xr-xBuild-tools/Do-create-perl-rpms64
-rwxr-xr-xBuild-tools/Do-local-patch-file37
-rwxr-xr-xBuild-tools/Do-patch-file41
-rwxr-xr-xBuild-tools/Do-rpm127
-rwxr-xr-xBuild-tools/cvs-sanity-check15
-rwxr-xr-xBuild-tools/mysql-copyright212
-rwxr-xr-xBuild-tools/mysql-copyright-2162
-rw-r--r--Build-tools/newest116
-rw-r--r--Docs/.cvsignore40
-rw-r--r--Docs/Attic/myisam.doc901
-rwxr-xr-xDocs/Flags/australia.eps87
-rw-r--r--Docs/Flags/australia.gifbin0 -> 689 bytes
-rwxr-xr-xDocs/Flags/australia.txt0
-rwxr-xr-xDocs/Flags/austria.eps87
-rw-r--r--Docs/Flags/austria.gifbin0 -> 132 bytes
-rwxr-xr-xDocs/Flags/austria.txt0
-rw-r--r--Docs/Flags/brazil.eps87
-rw-r--r--Docs/Flags/brazil.gifbin0 -> 662 bytes
-rw-r--r--Docs/Flags/brazil.txt0
-rw-r--r--Docs/Flags/bulgaria.eps87
-rw-r--r--Docs/Flags/bulgaria.gifbin0 -> 141 bytes
-rw-r--r--Docs/Flags/bulgaria.txt0
-rwxr-xr-xDocs/Flags/canada.eps87
-rw-r--r--Docs/Flags/canada.gifbin0 -> 407 bytes
-rwxr-xr-xDocs/Flags/canada.txt0
-rw-r--r--Docs/Flags/chile.eps87
-rw-r--r--Docs/Flags/chile.gifbin0 -> 370 bytes
-rw-r--r--Docs/Flags/chile.txt0
-rw-r--r--Docs/Flags/china.eps87
-rw-r--r--Docs/Flags/china.gifbin0 -> 224 bytes
-rw-r--r--Docs/Flags/china.txt0
-rw-r--r--Docs/Flags/croatia.eps87
-rw-r--r--Docs/Flags/croatia.gifbin0 -> 659 bytes
-rw-r--r--Docs/Flags/croatia.txt0
-rwxr-xr-xDocs/Flags/czech-republic.eps87
-rw-r--r--Docs/Flags/czech-republic.gifbin0 -> 248 bytes
-rwxr-xr-xDocs/Flags/czech-republic.txt0
-rw-r--r--Docs/Flags/denmark.eps87
-rw-r--r--Docs/Flags/denmark.gifbin0 -> 253 bytes
-rw-r--r--Docs/Flags/denmark.txt0
-rw-r--r--Docs/Flags/estonia.eps87
-rw-r--r--Docs/Flags/estonia.gifbin0 -> 126 bytes
-rw-r--r--Docs/Flags/estonia.txt0
-rw-r--r--Docs/Flags/finland.eps87
-rw-r--r--Docs/Flags/finland.gifbin0 -> 192 bytes
-rw-r--r--Docs/Flags/finland.txt0
-rw-r--r--Docs/Flags/france.eps87
-rw-r--r--Docs/Flags/france.gifbin0 -> 158 bytes
-rw-r--r--Docs/Flags/france.txt0
-rwxr-xr-xDocs/Flags/germany.eps87
-rw-r--r--Docs/Flags/germany.gifbin0 -> 126 bytes
-rwxr-xr-xDocs/Flags/germany.txt0
-rwxr-xr-xDocs/Flags/great-britain.eps87
-rw-r--r--Docs/Flags/great-britain.gifbin0 -> 1193 bytes
-rwxr-xr-xDocs/Flags/great-britain.txt0
-rw-r--r--Docs/Flags/greece.eps87
-rw-r--r--Docs/Flags/greece.gifbin0 -> 282 bytes
-rw-r--r--Docs/Flags/greece.txt0
-rwxr-xr-xDocs/Flags/hungary.eps87
-rw-r--r--Docs/Flags/hungary.gifbin0 -> 141 bytes
-rwxr-xr-xDocs/Flags/hungary.txt0
-rw-r--r--Docs/Flags/iceland.eps87
-rw-r--r--Docs/Flags/iceland.gifbin0 -> 197 bytes
-rw-r--r--Docs/Flags/iceland.txt0
-rw-r--r--Docs/Flags/ireland.eps87
-rw-r--r--Docs/Flags/ireland.gifbin0 -> 158 bytes
-rw-r--r--Docs/Flags/ireland.txt0
-rw-r--r--Docs/Flags/island.eps0
-rw-r--r--Docs/Flags/island.gif0
-rw-r--r--Docs/Flags/island.txt0
-rwxr-xr-xDocs/Flags/israel.eps87
-rw-r--r--Docs/Flags/israel.gifbin0 -> 368 bytes
-rwxr-xr-xDocs/Flags/israel.txt0
-rwxr-xr-xDocs/Flags/italy.eps87
-rw-r--r--Docs/Flags/italy.gifbin0 -> 158 bytes
-rwxr-xr-xDocs/Flags/italy.txt0
-rwxr-xr-xDocs/Flags/japan.eps87
-rw-r--r--Docs/Flags/japan.gifbin0 -> 357 bytes
-rwxr-xr-xDocs/Flags/japan.txt0
-rw-r--r--Docs/Flags/kroatia.eps0
-rw-r--r--Docs/Flags/kroatia.gif0
-rw-r--r--Docs/Flags/kroatia.txt0
-rw-r--r--Docs/Flags/netherlands.eps87
-rw-r--r--Docs/Flags/netherlands.gifbin0 -> 141 bytes
-rw-r--r--Docs/Flags/netherlands.txt0
-rw-r--r--Docs/Flags/poland.eps87
-rw-r--r--Docs/Flags/poland.gifbin0 -> 132 bytes
-rw-r--r--Docs/Flags/poland.txt0
-rw-r--r--Docs/Flags/portugal.eps87
-rw-r--r--Docs/Flags/portugal.gifbin0 -> 633 bytes
-rw-r--r--Docs/Flags/portugal.txt0
-rw-r--r--Docs/Flags/romania.eps87
-rw-r--r--Docs/Flags/romania.gifbin0 -> 158 bytes
-rw-r--r--Docs/Flags/romania.txt0
-rwxr-xr-xDocs/Flags/russia.eps87
-rw-r--r--Docs/Flags/russia.gifbin0 -> 141 bytes
-rwxr-xr-xDocs/Flags/russia.txt0
-rw-r--r--Docs/Flags/singapore.eps87
-rw-r--r--Docs/Flags/singapore.gifbin0 -> 389 bytes
-rw-r--r--Docs/Flags/singapore.txt0
-rw-r--r--Docs/Flags/south-africa.eps87
-rw-r--r--Docs/Flags/south-africa.gifbin0 -> 650 bytes
-rw-r--r--Docs/Flags/south-africa.txt0
-rw-r--r--Docs/Flags/south-africa1.eps87
-rw-r--r--Docs/Flags/south-africa1.gifbin0 -> 650 bytes
-rw-r--r--Docs/Flags/south-africa1.txt0
-rwxr-xr-xDocs/Flags/south-korea.eps87
-rw-r--r--Docs/Flags/south-korea.gifbin0 -> 663 bytes
-rwxr-xr-xDocs/Flags/south-korea.txt0
-rw-r--r--Docs/Flags/spain.eps87
-rw-r--r--Docs/Flags/spain.gifbin0 -> 138 bytes
-rw-r--r--Docs/Flags/spain.txt0
-rwxr-xr-xDocs/Flags/sweden.eps87
-rw-r--r--Docs/Flags/sweden.gifbin0 -> 193 bytes
-rwxr-xr-xDocs/Flags/sweden.txt0
-rw-r--r--Docs/Flags/switzerland.eps87
-rw-r--r--Docs/Flags/switzerland.gifbin0 -> 237 bytes
-rw-r--r--Docs/Flags/switzerland.txt0
-rwxr-xr-xDocs/Flags/taiwan.eps87
-rw-r--r--Docs/Flags/taiwan.gifbin0 -> 377 bytes
-rwxr-xr-xDocs/Flags/taiwan.txt0
-rw-r--r--Docs/Flags/ukraine.eps87
-rw-r--r--Docs/Flags/ukraine.gifbin0 -> 132 bytes
-rw-r--r--Docs/Flags/ukraine.txt0
-rwxr-xr-xDocs/Flags/usa.eps87
-rw-r--r--Docs/Flags/usa.gifbin0 -> 731 bytes
-rwxr-xr-xDocs/Flags/usa.txt0
-rw-r--r--Docs/Images/Attic/html-fs.gifbin0 -> 3349 bytes
-rw-r--r--Docs/Images/Attic/mysql-01.gifbin0 -> 4097 bytes
-rw-r--r--Docs/Images/Attic/mysql-02.gifbin0 -> 4811 bytes
-rw-r--r--Docs/Images/Attic/mysql-03.gifbin0 -> 716 bytes
-rw-r--r--Docs/Images/Attic/mysql-04.gifbin0 -> 909 bytes
-rw-r--r--Docs/Images/Attic/mysql-05.gifbin0 -> 2192 bytes
-rw-r--r--Docs/Images/Attic/mysql-06.gifbin0 -> 3082 bytes
-rw-r--r--Docs/Images/Attic/mysql-07.gifbin0 -> 4209 bytes
-rw-r--r--Docs/Images/Attic/mysql-08.gifbin0 -> 1595 bytes
-rw-r--r--Docs/Images/Attic/mysql-09.gifbin0 -> 2627 bytes
-rw-r--r--Docs/Images/Attic/mysql-10.gifbin0 -> 2455 bytes
-rw-r--r--Docs/Images/Attic/mysql-11.gifbin0 -> 1436 bytes
-rw-r--r--Docs/Images/Attic/mysql-12.gifbin0 -> 2642 bytes
-rw-r--r--Docs/Images/Attic/mysql-13.gifbin0 -> 2914 bytes
-rw-r--r--Docs/Images/Attic/mysql-14.gifbin0 -> 2686 bytes
-rw-r--r--Docs/Images/Attic/mysql-15.gifbin0 -> 2310 bytes
-rw-r--r--Docs/Images/Attic/mysql-16.gifbin0 -> 19192 bytes
-rw-r--r--Docs/Images/Attic/mysql-17.gifbin0 -> 2059 bytes
-rw-r--r--Docs/Images/Attic/mysql-18.gifbin0 -> 918 bytes
-rw-r--r--Docs/Images/Attic/mysql-19.gifbin0 -> 2607 bytes
-rw-r--r--Docs/Images/Attic/mysql-compatible.jpgbin0 -> 2809 bytes
-rw-r--r--Docs/Images/Attic/mysql5.gifbin0 -> 2192 bytes
-rw-r--r--Docs/Images/Attic/mysql_anim-01.gifbin0 -> 15008 bytes
-rw-r--r--Docs/Images/Attic/mysql_anim-02.gifbin0 -> 21236 bytes
-rw-r--r--Docs/Images/Attic/mysql_anim-03.gifbin0 -> 16958 bytes
-rw-r--r--Docs/Images/Attic/mysql_anim-04.gifbin0 -> 12716 bytes
-rw-r--r--Docs/Images/Attic/mysql_anim-05.gifbin0 -> 22962 bytes
-rw-r--r--Docs/Images/Attic/mysql_anim-06.gifbin0 -> 42606 bytes
-rw-r--r--Docs/Images/Attic/powered-by-MySQL-transparent.gifbin0 -> 4209 bytes
-rw-r--r--Docs/Images/empty.pngbin0 -> 108 bytes
-rwxr-xr-xDocs/Images/flag-background.pnmbin0 -> 2170 bytes
-rw-r--r--Docs/Images/mysql-logo.gifbin0 -> 3082 bytes
-rw-r--r--Docs/LICENSE98
-rw-r--r--Docs/Makefile.am120
-rw-r--r--Docs/MySQL-logos/mysql-01.gifbin0 -> 4097 bytes
-rw-r--r--Docs/MySQL-logos/mysql-02.gifbin0 -> 4811 bytes
-rw-r--r--Docs/MySQL-logos/mysql-03.gifbin0 -> 716 bytes
-rw-r--r--Docs/MySQL-logos/mysql-04.gifbin0 -> 909 bytes
-rw-r--r--Docs/MySQL-logos/mysql-05.gifbin0 -> 2192 bytes
-rw-r--r--Docs/MySQL-logos/mysql-06.gifbin0 -> 3082 bytes
-rw-r--r--Docs/MySQL-logos/mysql-07.gifbin0 -> 4209 bytes
-rw-r--r--Docs/MySQL-logos/mysql-08.gifbin0 -> 1595 bytes
-rw-r--r--Docs/MySQL-logos/mysql-09.gifbin0 -> 2627 bytes
-rw-r--r--Docs/MySQL-logos/mysql-10.gifbin0 -> 2455 bytes
-rw-r--r--Docs/MySQL-logos/mysql-11.gifbin0 -> 1436 bytes
-rw-r--r--Docs/MySQL-logos/mysql-12.gifbin0 -> 2642 bytes
-rw-r--r--Docs/MySQL-logos/mysql-13.gifbin0 -> 2914 bytes
-rw-r--r--Docs/MySQL-logos/mysql-14.gifbin0 -> 2686 bytes
-rw-r--r--Docs/MySQL-logos/mysql-15.gifbin0 -> 2310 bytes
-rw-r--r--Docs/MySQL-logos/mysql-16.gifbin0 -> 19192 bytes
-rw-r--r--Docs/MySQL-logos/mysql-17.gifbin0 -> 2059 bytes
-rw-r--r--Docs/MySQL-logos/mysql-compatible.jpgbin0 -> 2809 bytes
-rw-r--r--Docs/MySQL-logos/mysql_anim-01.gifbin0 -> 15008 bytes
-rw-r--r--Docs/MySQL-logos/mysql_anim-02.gifbin0 -> 21236 bytes
-rw-r--r--Docs/MySQL-logos/mysql_anim-03.gifbin0 -> 16958 bytes
-rw-r--r--Docs/MySQL-logos/mysql_anim-04.gifbin0 -> 12716 bytes
-rw-r--r--Docs/MySQL-logos/mysql_anim-05.gifbin0 -> 22962 bytes
-rw-r--r--Docs/MySQL-logos/mysql_anim-06.gifbin0 -> 42606 bytes
-rw-r--r--Docs/Raw-Flags/afghanistan.gifbin0 -> 11155 bytes
-rw-r--r--Docs/Raw-Flags/albania.gifbin0 -> 8288 bytes
-rw-r--r--Docs/Raw-Flags/algeria.gifbin0 -> 5003 bytes
-rw-r--r--Docs/Raw-Flags/andorra.gifbin0 -> 21227 bytes
-rw-r--r--Docs/Raw-Flags/angola.gifbin0 -> 4836 bytes
-rw-r--r--Docs/Raw-Flags/antartica.gifbin0 -> 3185 bytes
-rw-r--r--Docs/Raw-Flags/antigua-and-barbuda.gifbin0 -> 5239 bytes
-rw-r--r--Docs/Raw-Flags/argentina.gifbin0 -> 5242 bytes
-rw-r--r--Docs/Raw-Flags/armenia.gifbin0 -> 1553 bytes
-rw-r--r--Docs/Raw-Flags/australia.gifbin0 -> 6493 bytes
-rw-r--r--Docs/Raw-Flags/austria.gifbin0 -> 1232 bytes
-rw-r--r--Docs/Raw-Flags/azerbaijan.gifbin0 -> 2931 bytes
-rw-r--r--Docs/Raw-Flags/bahamas.gifbin0 -> 2836 bytes
-rw-r--r--Docs/Raw-Flags/bahrein.gifbin0 -> 2380 bytes
-rw-r--r--Docs/Raw-Flags/bangladesh.gifbin0 -> 2505 bytes
-rw-r--r--Docs/Raw-Flags/barbados.gifbin0 -> 3178 bytes
-rw-r--r--Docs/Raw-Flags/belarus.gifbin0 -> 1232 bytes
-rw-r--r--Docs/Raw-Flags/belgium.gifbin0 -> 2525 bytes
-rw-r--r--Docs/Raw-Flags/belize.gifbin0 -> 28546 bytes
-rw-r--r--Docs/Raw-Flags/benin.gifbin0 -> 2107 bytes
-rw-r--r--Docs/Raw-Flags/bermuda.gifbin0 -> 4278 bytes
-rw-r--r--Docs/Raw-Flags/bhutan.gifbin0 -> 40300 bytes
-rw-r--r--Docs/Raw-Flags/bolivia.gifbin0 -> 11912 bytes
-rw-r--r--Docs/Raw-Flags/bosnia-and-herzegovina.gifbin0 -> 4143 bytes
-rw-r--r--Docs/Raw-Flags/botswana.gifbin0 -> 1451 bytes
-rw-r--r--Docs/Raw-Flags/brazil.gifbin0 -> 6650 bytes
-rw-r--r--Docs/Raw-Flags/brunei.gifbin0 -> 29444 bytes
-rw-r--r--Docs/Raw-Flags/bulgaria.gifbin0 -> 1553 bytes
-rw-r--r--Docs/Raw-Flags/burkina-faso.gifbin0 -> 2691 bytes
-rw-r--r--Docs/Raw-Flags/burma.gifbin0 -> 11558 bytes
-rw-r--r--Docs/Raw-Flags/burundi.gifbin0 -> 6742 bytes
-rw-r--r--Docs/Raw-Flags/cambodia.gifbin0 -> 12976 bytes
-rw-r--r--Docs/Raw-Flags/cameroon.gifbin0 -> 3531 bytes
-rw-r--r--Docs/Raw-Flags/canada.gifbin0 -> 3984 bytes
-rw-r--r--Docs/Raw-Flags/cape-verde.gifbin0 -> 3504 bytes
-rw-r--r--Docs/Raw-Flags/central-african-republic.gifbin0 -> 3769 bytes
-rw-r--r--Docs/Raw-Flags/chad.gifbin0 -> 2525 bytes
-rw-r--r--Docs/Raw-Flags/chile.gifbin0 -> 2890 bytes
-rw-r--r--Docs/Raw-Flags/china.gifbin0 -> 2054 bytes
-rw-r--r--Docs/Raw-Flags/colombia.gifbin0 -> 1531 bytes
-rw-r--r--Docs/Raw-Flags/comoros.gifbin0 -> 3049 bytes
-rw-r--r--Docs/Raw-Flags/congo.gifbin0 -> 3265 bytes
-rw-r--r--Docs/Raw-Flags/costa-rica.gifbin0 -> 1620 bytes
-rw-r--r--Docs/Raw-Flags/cote-d-ivoire.gifbin0 -> 2525 bytes
-rw-r--r--Docs/Raw-Flags/croatia.gifbin0 -> 13740 bytes
-rw-r--r--Docs/Raw-Flags/cuba.gifbin0 -> 3986 bytes
-rw-r--r--Docs/Raw-Flags/cyprus.gifbin0 -> 3929 bytes
-rw-r--r--Docs/Raw-Flags/czech-republic.gifbin0 -> 2726 bytes
-rw-r--r--Docs/Raw-Flags/denmark-original-incorrect.gifbin0 -> 1893 bytes
-rw-r--r--Docs/Raw-Flags/denmark.gifbin0 -> 13718 bytes
-rw-r--r--Docs/Raw-Flags/djibouti.gifbin0 -> 3462 bytes
-rw-r--r--Docs/Raw-Flags/dominica.gifbin0 -> 14390 bytes
-rw-r--r--Docs/Raw-Flags/dominican-republic.gifbin0 -> 8432 bytes
-rw-r--r--Docs/Raw-Flags/ecuador.gifbin0 -> 18692 bytes
-rw-r--r--Docs/Raw-Flags/egypt.gifbin0 -> 8423 bytes
-rw-r--r--Docs/Raw-Flags/el-salvador.gifbin0 -> 12073 bytes
-rw-r--r--Docs/Raw-Flags/equatorial-guinea.gifbin0 -> 8884 bytes
-rw-r--r--Docs/Raw-Flags/eritrea.gifbin0 -> 8154 bytes
-rw-r--r--Docs/Raw-Flags/estonia.gifbin0 -> 1553 bytes
-rw-r--r--Docs/Raw-Flags/ethiopia.gifbin0 -> 1553 bytes
-rw-r--r--Docs/Raw-Flags/fiji.gifbin0 -> 17779 bytes
-rw-r--r--Docs/Raw-Flags/finland.gifbin0 -> 1812 bytes
-rw-r--r--Docs/Raw-Flags/france.gifbin0 -> 2525 bytes
-rw-r--r--Docs/Raw-Flags/gabon.gifbin0 -> 1553 bytes
-rw-r--r--Docs/Raw-Flags/gambia.gifbin0 -> 1831 bytes
-rw-r--r--Docs/Raw-Flags/georgia.gifbin0 -> 1900 bytes
-rw-r--r--Docs/Raw-Flags/germany.gifbin0 -> 1553 bytes
-rw-r--r--Docs/Raw-Flags/ghana.gifbin0 -> 2394 bytes
-rw-r--r--Docs/Raw-Flags/great-britain.gifbin0 -> 8165 bytes
-rw-r--r--Docs/Raw-Flags/greece.gifbin0 -> 2173 bytes
-rw-r--r--Docs/Raw-Flags/greenland.gifbin0 -> 2612 bytes
-rw-r--r--Docs/Raw-Flags/grenada.gifbin0 -> 6780 bytes
-rw-r--r--Docs/Raw-Flags/guatemala.gifbin0 -> 19048 bytes
-rw-r--r--Docs/Raw-Flags/guinea-bissau.gifbin0 -> 3300 bytes
-rw-r--r--Docs/Raw-Flags/guinea.gifbin0 -> 2525 bytes
-rw-r--r--Docs/Raw-Flags/guyana.gifbin0 -> 5299 bytes
-rw-r--r--Docs/Raw-Flags/haiti.gifbin0 -> 24028 bytes
-rw-r--r--Docs/Raw-Flags/honduras.gifbin0 -> 2223 bytes
-rw-r--r--Docs/Raw-Flags/hungary.gifbin0 -> 1553 bytes
-rw-r--r--Docs/Raw-Flags/iceland.gifbin0 -> 2544 bytes
-rw-r--r--Docs/Raw-Flags/india.gifbin0 -> 4399 bytes
-rw-r--r--Docs/Raw-Flags/indonesia.gifbin0 -> 1205 bytes
-rw-r--r--Docs/Raw-Flags/iran.gifbin0 -> 7703 bytes
-rw-r--r--Docs/Raw-Flags/iraq.gifbin0 -> 4538 bytes
-rw-r--r--Docs/Raw-Flags/ireland.gifbin0 -> 2525 bytes
-rw-r--r--Docs/Raw-Flags/israel.gifbin0 -> 2808 bytes
-rw-r--r--Docs/Raw-Flags/italy.gifbin0 -> 2525 bytes
-rw-r--r--Docs/Raw-Flags/jamaica.gifbin0 -> 4749 bytes
-rw-r--r--Docs/Raw-Flags/japan.gifbin0 -> 2505 bytes
-rw-r--r--Docs/Raw-Flags/jordan.gifbin0 -> 3755 bytes
-rw-r--r--Docs/Raw-Flags/kazakhstan.gifbin0 -> 24988 bytes
-rw-r--r--Docs/Raw-Flags/kenya.gifbin0 -> 6806 bytes
-rw-r--r--Docs/Raw-Flags/kiribati.gifbin0 -> 9341 bytes
-rw-r--r--Docs/Raw-Flags/kuwait.gifbin0 -> 2926 bytes
-rw-r--r--Docs/Raw-Flags/kyrgyzstan.gifbin0 -> 7742 bytes
-rw-r--r--Docs/Raw-Flags/laos.gifbin0 -> 2402 bytes
-rw-r--r--Docs/Raw-Flags/latvia.gifbin0 -> 1142 bytes
-rw-r--r--Docs/Raw-Flags/lebanon.gifbin0 -> 2874 bytes
-rw-r--r--Docs/Raw-Flags/lesotho.gifbin0 -> 5568 bytes
-rw-r--r--Docs/Raw-Flags/liberia.gifbin0 -> 2889 bytes
-rw-r--r--Docs/Raw-Flags/libya.gifbin0 -> 787 bytes
-rw-r--r--Docs/Raw-Flags/liechtenstein.gifbin0 -> 9832 bytes
-rw-r--r--Docs/Raw-Flags/lithuania.gifbin0 -> 1553 bytes
-rw-r--r--Docs/Raw-Flags/luxembourg.gifbin0 -> 1553 bytes
-rw-r--r--Docs/Raw-Flags/macedonia.gifbin0 -> 6907 bytes
-rw-r--r--Docs/Raw-Flags/madagascar.gifbin0 -> 2061 bytes
-rw-r--r--Docs/Raw-Flags/malawi.gifbin0 -> 5622 bytes
-rw-r--r--Docs/Raw-Flags/malaysia.gifbin0 -> 4621 bytes
-rw-r--r--Docs/Raw-Flags/maldives.gifbin0 -> 2623 bytes
-rw-r--r--Docs/Raw-Flags/mali.gifbin0 -> 2525 bytes
-rw-r--r--Docs/Raw-Flags/malta.gifbin0 -> 7209 bytes
-rw-r--r--Docs/Raw-Flags/marshall.gifbin0 -> 6614 bytes
-rw-r--r--Docs/Raw-Flags/mauritania.gifbin0 -> 2511 bytes
-rw-r--r--Docs/Raw-Flags/mauritius.gifbin0 -> 1888 bytes
-rw-r--r--Docs/Raw-Flags/mexico.gifbin0 -> 16889 bytes
-rw-r--r--Docs/Raw-Flags/micronesia.gifbin0 -> 3092 bytes
-rw-r--r--Docs/Raw-Flags/moldova.gifbin0 -> 16586 bytes
-rw-r--r--Docs/Raw-Flags/monaco.gifbin0 -> 1205 bytes
-rw-r--r--Docs/Raw-Flags/mongolia.gifbin0 -> 5532 bytes
-rw-r--r--Docs/Raw-Flags/morocco.gifbin0 -> 4507 bytes
-rw-r--r--Docs/Raw-Flags/mozambique.gifbin0 -> 9086 bytes
-rw-r--r--Docs/Raw-Flags/namibia.gifbin0 -> 6725 bytes
-rw-r--r--Docs/Raw-Flags/nauru.gifbin0 -> 2209 bytes
-rw-r--r--Docs/Raw-Flags/nepal.gifbin0 -> 5658 bytes
-rw-r--r--Docs/Raw-Flags/netherlands.gifbin0 -> 1553 bytes
-rw-r--r--Docs/Raw-Flags/new-zealand.gifbin0 -> 7248 bytes
-rw-r--r--Docs/Raw-Flags/nicaragua.gifbin0 -> 8024 bytes
-rw-r--r--Docs/Raw-Flags/niger.gifbin0 -> 2381 bytes
-rw-r--r--Docs/Raw-Flags/nigeria.gifbin0 -> 1998 bytes
-rw-r--r--Docs/Raw-Flags/north-korea.gifbin0 -> 3044 bytes
-rw-r--r--Docs/Raw-Flags/norway.gifbin0 -> 2544 bytes
-rw-r--r--Docs/Raw-Flags/oman.gifbin0 -> 6957 bytes
-rw-r--r--Docs/Raw-Flags/pakistan.gifbin0 -> 3805 bytes
-rw-r--r--Docs/Raw-Flags/panama.gifbin0 -> 4459 bytes
-rw-r--r--Docs/Raw-Flags/papua-new-guinea.gifbin0 -> 5742 bytes
-rw-r--r--Docs/Raw-Flags/paraguay.gifbin0 -> 8733 bytes
-rw-r--r--Docs/Raw-Flags/peru.gifbin0 -> 14338 bytes
-rw-r--r--Docs/Raw-Flags/philippines.gifbin0 -> 7606 bytes
-rw-r--r--Docs/Raw-Flags/poland.gifbin0 -> 1205 bytes
-rw-r--r--Docs/Raw-Flags/portugal.gifbin0 -> 11287 bytes
-rw-r--r--Docs/Raw-Flags/qatar.gifbin0 -> 2380 bytes
-rw-r--r--Docs/Raw-Flags/romania.gifbin0 -> 2777 bytes
-rw-r--r--Docs/Raw-Flags/russia.gifbin0 -> 1553 bytes
-rw-r--r--Docs/Raw-Flags/rwanda.gifbin0 -> 3844 bytes
-rw-r--r--Docs/Raw-Flags/saint-kitts-and-nevis.gifbin0 -> 6152 bytes
-rw-r--r--Docs/Raw-Flags/saint-lucia.gifbin0 -> 4434 bytes
-rw-r--r--Docs/Raw-Flags/samoa.gifbin0 -> 2219 bytes
-rw-r--r--Docs/Raw-Flags/sao-tome-and-principe.gifbin0 -> 3978 bytes
-rw-r--r--Docs/Raw-Flags/saudi-arabia.gifbin0 -> 18855 bytes
-rw-r--r--Docs/Raw-Flags/senegal.gifbin0 -> 3532 bytes
-rw-r--r--Docs/Raw-Flags/seychelles.gifbin0 -> 3408 bytes
-rw-r--r--Docs/Raw-Flags/sierra-leone.gifbin0 -> 1553 bytes
-rw-r--r--Docs/Raw-Flags/singapore.gifbin0 -> 3207 bytes
-rw-r--r--Docs/Raw-Flags/slovakia.gifbin0 -> 4706 bytes
-rw-r--r--Docs/Raw-Flags/slovenia.gifbin0 -> 5351 bytes
-rw-r--r--Docs/Raw-Flags/solomon-islands.gifbin0 -> 4369 bytes
-rw-r--r--Docs/Raw-Flags/somalia.gifbin0 -> 2010 bytes
-rw-r--r--Docs/Raw-Flags/south-africa.gifbin0 -> 5116 bytes
-rw-r--r--Docs/Raw-Flags/south-korea.gifbin0 -> 6838 bytes
-rw-r--r--Docs/Raw-Flags/spain.gifbin0 -> 1252 bytes
-rw-r--r--Docs/Raw-Flags/sri-lanka.gifbin0 -> 14789 bytes
-rw-r--r--Docs/Raw-Flags/sudan.gifbin0 -> 3124 bytes
-rw-r--r--Docs/Raw-Flags/suriname.gifbin0 -> 2499 bytes
-rw-r--r--Docs/Raw-Flags/swaziland.gifbin0 -> 11362 bytes
-rw-r--r--Docs/Raw-Flags/sweden.gifbin0 -> 1812 bytes
-rw-r--r--Docs/Raw-Flags/sweden2.gifbin0 -> 1813 bytes
-rw-r--r--Docs/Raw-Flags/switzerland.gifbin0 -> 1632 bytes
-rw-r--r--Docs/Raw-Flags/syria.gifbin0 -> 2748 bytes
-rw-r--r--Docs/Raw-Flags/taiwan.gifbin0 -> 3866 bytes
-rw-r--r--Docs/Raw-Flags/tajikistan.gifbin0 -> 6245 bytes
-rw-r--r--Docs/Raw-Flags/tanzania.gifbin0 -> 4673 bytes
-rw-r--r--Docs/Raw-Flags/thailand.gifbin0 -> 1620 bytes
-rw-r--r--Docs/Raw-Flags/togo.gifbin0 -> 2815 bytes
-rw-r--r--Docs/Raw-Flags/tonga.gifbin0 -> 2066 bytes
-rw-r--r--Docs/Raw-Flags/trinidad-and-tobago.gifbin0 -> 2807 bytes
-rw-r--r--Docs/Raw-Flags/tunisia.gifbin0 -> 3881 bytes
-rw-r--r--Docs/Raw-Flags/turkey.gifbin0 -> 2557 bytes
-rw-r--r--Docs/Raw-Flags/turkmenistan.gifbin0 -> 26835 bytes
-rw-r--r--Docs/Raw-Flags/tuvalu.gifbin0 -> 7855 bytes
-rw-r--r--Docs/Raw-Flags/uganda.gifbin0 -> 5970 bytes
-rw-r--r--Docs/Raw-Flags/ukraine.gifbin0 -> 1205 bytes
-rw-r--r--Docs/Raw-Flags/united-arab-emirates.gifbin0 -> 2493 bytes
-rw-r--r--Docs/Raw-Flags/united-states-of-america.gifbin0 -> 6528 bytes
-rw-r--r--Docs/Raw-Flags/uruguay.gifbin0 -> 8709 bytes
-rw-r--r--Docs/Raw-Flags/usa.gifbin0 -> 6528 bytes
-rw-r--r--Docs/Raw-Flags/uzbekistan.gifbin0 -> 3968 bytes
-rw-r--r--Docs/Raw-Flags/vanuatu.gifbin0 -> 8928 bytes
-rw-r--r--Docs/Raw-Flags/venezuela.gifbin0 -> 10305 bytes
-rw-r--r--Docs/Raw-Flags/vietnam.gifbin0 -> 2010 bytes
-rw-r--r--Docs/Raw-Flags/vincent-and-grenadines.gifbin0 -> 4234 bytes
-rw-r--r--Docs/Raw-Flags/yemen.gifbin0 -> 1553 bytes
-rw-r--r--Docs/Raw-Flags/yugoslavia.gifbin0 -> 1553 bytes
-rw-r--r--Docs/Raw-Flags/zaire.gifbin0 -> 12709 bytes
-rw-r--r--Docs/Raw-Flags/zambia.gifbin0 -> 8598 bytes
-rw-r--r--Docs/Raw-Flags/zimbabwe.gifbin0 -> 10738 bytes
-rw-r--r--Docs/Support/.cvsignore2
-rwxr-xr-xDocs/Support/generate-flag-images37
-rwxr-xr-xDocs/Support/generate-mirror-listing.pl27
-rwxr-xr-xDocs/Support/generate-text-files.pl40
-rwxr-xr-xDocs/Support/make-makefile7
-rwxr-xr-xDocs/Support/texi2html2251
-rw-r--r--Docs/Support/texinfo.tex5868
-rw-r--r--Docs/To-be-included-in-the-manual/MySQL-for-dummies271
-rw-r--r--Docs/Translations/myodbc-br.texi272
-rw-r--r--Docs/Tutorial-MySQL-final.txt1643
-rw-r--r--Docs/internals.texi134
-rw-r--r--Docs/manual-license-spanish.texi709
-rw-r--r--Docs/manual.texi41455
-rw-r--r--Docs/myisam.txt901
-rw-r--r--Docs/mysqld_error.txt355
-rw-r--r--Docs/net_doc.txt944
-rw-r--r--Images/.cvsignore1
-rwxr-xr-xMakefile.am50
-rw-r--r--NEW-RPMS/.cvsignore1
-rw-r--r--README54
-rwxr-xr-xacconfig.h228
-rw-r--r--acinclude.m4944
-rw-r--r--client/.cvsignore14
-rw-r--r--client/Attic/libmysql.c2392
-rw-r--r--client/Attic/net.c628
-rw-r--r--client/Makefile.am43
-rw-r--r--client/completion_hash.cc249
-rw-r--r--client/completion_hash.h57
-rw-r--r--client/connect_test.c66
-rw-r--r--client/errmsg.c93
-rw-r--r--client/get_password.c214
-rw-r--r--client/insert_test.c65
-rw-r--r--client/list_test.c86
-rw-r--r--client/my_readline.h34
-rw-r--r--client/mysql.cc2060
-rw-r--r--client/mysqladmin.c1099
-rw-r--r--client/mysqldump.c1285
-rw-r--r--client/mysqlimport.c521
-rw-r--r--client/mysqlshow.c608
-rw-r--r--client/password.c192
-rw-r--r--client/readline.cc216
-rw-r--r--client/select_test.c75
-rw-r--r--client/showdb_test.c80
-rw-r--r--client/sql_string.cc728
-rw-r--r--client/sql_string.h183
-rw-r--r--client/ssl_test.c95
-rw-r--r--client/thread_test.c283
-rw-r--r--client/violite.c394
-rwxr-xr-xconfig.guess1131
-rwxr-xr-xconfig.sub1227
-rw-r--r--configure.in1839
-rw-r--r--dbug/.cvsignore3
-rw-r--r--dbug/Makefile.am62
-rw-r--r--dbug/dbug.c2076
-rw-r--r--dbug/dbug_analyze.c716
-rw-r--r--dbug/dbug_long.h159
-rw-r--r--dbug/doinstall.sh15
-rw-r--r--dbug/example1.c13
-rw-r--r--dbug/example2.c18
-rw-r--r--dbug/example3.c17
-rw-r--r--dbug/factorial.c17
-rw-r--r--dbug/install.sh64
-rw-r--r--dbug/main.c33
-rw-r--r--dbug/mklintlib.sh30
-rw-r--r--dbug/monty.doc12
-rw-r--r--dbug/qmake.cmd4
-rw-r--r--dbug/readme.prof70
-rw-r--r--dbug/sanity.c13
-rw-r--r--dbug/user.r937
-rw-r--r--dbug/vargs.h139
-rw-r--r--extra/.cvsignore10
-rw-r--r--extra/Attic/print_defaults.c125
-rw-r--r--extra/Makefile.am29
-rw-r--r--extra/comp_err.c275
-rw-r--r--extra/my_print_defaults.c125
-rw-r--r--extra/perror.c207
-rw-r--r--extra/replace.c1080
-rw-r--r--extra/resolveip.c204
-rw-r--r--heap/.cvsignore6
-rw-r--r--heap/ChangeLog8
-rw-r--r--heap/Makefile.am37
-rw-r--r--heap/_check.c81
-rw-r--r--heap/_rectest.c31
-rw-r--r--heap/heapdef.h81
-rw-r--r--heap/hp_block.c111
-rw-r--r--heap/hp_clear.c52
-rw-r--r--heap/hp_close.c51
-rw-r--r--heap/hp_create.c62
-rw-r--r--heap/hp_delete.c151
-rw-r--r--heap/hp_extra.c47
-rw-r--r--heap/hp_hash.c266
-rw-r--r--heap/hp_info.c58
-rw-r--r--heap/hp_open.c173
-rw-r--r--heap/hp_panic.c57
-rw-r--r--heap/hp_rename.c42
-rw-r--r--heap/hp_rfirst.c28
-rw-r--r--heap/hp_rkey.c51
-rw-r--r--heap/hp_rlast.c29
-rw-r--r--heap/hp_rnext.c56
-rw-r--r--heap/hp_rprev.c53
-rw-r--r--heap/hp_rrnd.c106
-rw-r--r--heap/hp_rsame.c57
-rw-r--r--heap/hp_scan.c72
-rw-r--r--heap/hp_static.c26
-rw-r--r--heap/hp_test1.c187
-rw-r--r--heap/hp_test2.c659
-rw-r--r--heap/hp_update.c67
-rw-r--r--heap/hp_write.c275
-rwxr-xr-xheap/make-ccc4
-rw-r--r--include/.cvsignore4
-rwxr-xr-xinclude/Attic/config-win32.h247
-rw-r--r--include/Attic/m_ctype.h.in231
-rwxr-xr-xinclude/Attic/mysql_com.h.in216
-rw-r--r--include/Makefile.am53
-rw-r--r--include/config-win.h291
-rw-r--r--include/dbug.h92
-rw-r--r--include/errmsg.h55
-rw-r--r--include/ft_global.h52
-rw-r--r--include/getopt.h133
-rw-r--r--include/global.h845
-rw-r--r--include/hash.h65
-rw-r--r--include/heap.h181
-rw-r--r--include/m_ctype.h157
-rw-r--r--include/m_string.h241
-rw-r--r--include/merge.h94
-rw-r--r--include/my_alarm.h60
-rw-r--r--include/my_base.h265
-rw-r--r--include/my_dir.h100
-rw-r--r--include/my_list.h47
-rw-r--r--include/my_net.h33
-rw-r--r--include/my_no_pthread.h32
-rw-r--r--include/my_nosys.h56
-rw-r--r--include/my_pthread.h538
-rw-r--r--include/my_sys.h555
-rw-r--r--include/my_tree.h75
-rw-r--r--include/myisam.h377
-rw-r--r--include/myisammrg.h92
-rw-r--r--include/myisampack.h207
-rw-r--r--include/mysql.h293
-rw-r--r--include/mysql_com.h242
-rwxr-xr-xinclude/mysql_version.h.in20
-rw-r--r--include/mysqld_error.h195
-rw-r--r--include/mysys_err.h57
-rw-r--r--include/nisam.h213
-rw-r--r--include/queues.h57
-rw-r--r--include/raid.h155
-rw-r--r--include/sslopt-case.h42
-rw-r--r--include/sslopt-longopts.h31
-rw-r--r--include/sslopt-usage.h25
-rw-r--r--include/sslopt-vars.h24
-rw-r--r--include/t_ctype.h239
-rw-r--r--include/thr_alarm.h100
-rw-r--r--include/thr_lock.h89
-rw-r--r--include/violite.h115
-rwxr-xr-xinstall-sh250
-rw-r--r--isam/.cvsignore10
-rw-r--r--isam/ChangeLog186
-rw-r--r--isam/Makefile.am51
-rw-r--r--isam/_cache.c92
-rw-r--r--isam/_dbug.c132
-rw-r--r--isam/_dynrec.c1245
-rw-r--r--isam/_key.c239
-rw-r--r--isam/_locking.c345
-rw-r--r--isam/_packrec.c1184
-rw-r--r--isam/_page.c137
-rw-r--r--isam/_search.c889
-rw-r--r--isam/_statrec.c265
-rw-r--r--isam/changed.c35
-rw-r--r--isam/close.c91
-rw-r--r--isam/create.c326
-rw-r--r--isam/delete.c615
-rw-r--r--isam/extra.c258
-rw-r--r--isam/info.c77
-rw-r--r--isam/isamchk.c3448
-rw-r--r--isam/isamdef.h416
-rw-r--r--isam/isamlog.c839
-rw-r--r--isam/log.c156
-rwxr-xr-xisam/make-ccc3
-rw-r--r--isam/open.c455
-rw-r--r--isam/pack_isam.c2051
-rw-r--r--isam/panic.c135
-rw-r--r--isam/range.c191
-rw-r--r--isam/rfirst.c34
-rw-r--r--isam/rkey.c63
-rw-r--r--isam/rlast.c34
-rw-r--r--isam/rnext.c66
-rw-r--r--isam/rprev.c63
-rw-r--r--isam/rrnd.c55
-rw-r--r--isam/rsame.c70
-rw-r--r--isam/rsamepos.c59
-rw-r--r--isam/sort.c558
-rw-r--r--isam/static.c45
-rw-r--r--isam/test1.c183
-rw-r--r--isam/test2.c852
-rw-r--r--isam/test3.c479
-rwxr-xr-xisam/test_all30
-rw-r--r--isam/test_all.res356
-rw-r--r--isam/update.c119
-rw-r--r--isam/write.c840
-rw-r--r--libmysql/.cvsignore10
-rw-r--r--libmysql/Makefile.am149
-rw-r--r--libmysql/acinclude.m491
-rw-r--r--libmysql/conf_to_src.c143
-rw-r--r--libmysql/configure.in230
-rw-r--r--libmysql/dll.c112
-rw-r--r--libmysql/errmsg.c82
-rw-r--r--libmysql/get_password.c212
-rw-r--r--libmysql/libmysql.c2533
-rw-r--r--libmysql/net.c680
-rw-r--r--libmysql/password.c192
-rw-r--r--libmysql/violite.c400
-rwxr-xr-xltconfig3023
-rw-r--r--ltmain.sh3975
-rw-r--r--man/.cvsignore2
-rw-r--r--man/Makefile.am22
-rw-r--r--man/mysql.1143
-rw-r--r--merge/.cvsignore3
-rw-r--r--merge/Makefile.am31
-rw-r--r--merge/_locking.c35
-rw-r--r--merge/close.c41
-rw-r--r--merge/create.c62
-rw-r--r--merge/delete.c29
-rw-r--r--merge/extra.c46
-rw-r--r--merge/info.c60
-rwxr-xr-xmerge/make-ccc3
-rw-r--r--merge/mrgdef.h29
-rw-r--r--merge/open.c138
-rw-r--r--merge/panic.c47
-rw-r--r--merge/rrnd.c110
-rw-r--r--merge/rsame.c36
-rw-r--r--merge/static.c26
-rw-r--r--merge/update.c31
-rwxr-xr-xmissing190
-rw-r--r--mit-pthreads/.cvsignore6
-rw-r--r--mit-pthreads/COPYRIGHT31
-rw-r--r--mit-pthreads/Changes-mysql194
-rw-r--r--mit-pthreads/FAQ122
-rw-r--r--mit-pthreads/GNUmakefile129
-rw-r--r--mit-pthreads/NOTES59
-rw-r--r--mit-pthreads/NOTES_OSR5_BUILD_SKUNKWARE9745
-rw-r--r--mit-pthreads/README40
-rw-r--r--mit-pthreads/TODO-mysql4
-rw-r--r--mit-pthreads/Whats_New198
-rw-r--r--mit-pthreads/bin/.cvsignore1
-rw-r--r--mit-pthreads/bin/Makefile.in48
-rw-r--r--mit-pthreads/bin/finger/.cvsignore1
-rwxr-xr-xmit-pthreads/bin/finger/Makefile.in60
-rwxr-xr-xmit-pthreads/bin/finger/finger.c231
-rwxr-xr-xmit-pthreads/bin/finger/net.c189
-rwxr-xr-xmit-pthreads/config/COPYING.GNU339
-rwxr-xr-xmit-pthreads/config/COPYRIGHT4
-rwxr-xr-xmit-pthreads/config/GNUmakefile.in129
-rw-r--r--mit-pthreads/config/Makefile.in56
-rw-r--r--mit-pthreads/config/acconfig.h73
-rwxr-xr-xmit-pthreads/config/aclocal.m494
-rwxr-xr-xmit-pthreads/config/config.flags.in80
-rwxr-xr-xmit-pthreads/config/config.guess504
-rwxr-xr-xmit-pthreads/config/config.h.in324
-rwxr-xr-xmit-pthreads/config/config.sub794
-rwxr-xr-xmit-pthreads/config/configure3330
-rwxr-xr-xmit-pthreads/config/configure.in739
-rwxr-xr-xmit-pthreads/config/configure.org2874
-rwxr-xr-xmit-pthreads/config/install-sh238
-rwxr-xr-xmit-pthreads/configure19
-rwxr-xr-xmit-pthreads/gen/GNUmakefile.inc9
-rw-r--r--mit-pthreads/gen/Makefile.inc24
-rw-r--r--mit-pthreads/gen/ctime.c1315
-rw-r--r--mit-pthreads/gen/difftime.c46
-rw-r--r--mit-pthreads/gen/directory.c322
-rw-r--r--mit-pthreads/gen/eprintf.c18
-rw-r--r--mit-pthreads/gen/getcwd.c248
-rw-r--r--mit-pthreads/gen/getpwent.c109
-rw-r--r--mit-pthreads/gen/getpwnamuid.c138
-rw-r--r--mit-pthreads/gen/getwd.c57
-rw-r--r--mit-pthreads/gen/isatty.c95
-rw-r--r--mit-pthreads/gen/popen.c117
-rw-r--r--mit-pthreads/gen/pwd_internal.c97
-rw-r--r--mit-pthreads/gen/pwd_internal.h29
-rw-r--r--mit-pthreads/gen/syslog.c216
-rw-r--r--mit-pthreads/gen/time.c51
-rw-r--r--mit-pthreads/gen/ttyname.c147
-rw-r--r--mit-pthreads/include/Makefile.inc30
-rwxr-xr-xmit-pthreads/include/arpa/inet.h61
-rwxr-xr-xmit-pthreads/include/arpa/nameser.h279
-rw-r--r--mit-pthreads/include/dirent.h97
-rw-r--r--mit-pthreads/include/endian.h95
-rw-r--r--mit-pthreads/include/errno.h52
-rw-r--r--mit-pthreads/include/math.h85
-rw-r--r--mit-pthreads/include/netdb.h146
-rw-r--r--mit-pthreads/include/pthread.h371
-rw-r--r--mit-pthreads/include/pthread/ac-types.h11
-rwxr-xr-xmit-pthreads/include/pthread/cleanup.h59
-rwxr-xr-xmit-pthreads/include/pthread/cond.h102
-rw-r--r--mit-pthreads/include/pthread/config.h5
-rwxr-xr-xmit-pthreads/include/pthread/debug_out.h44
-rwxr-xr-xmit-pthreads/include/pthread/fd.h122
-rwxr-xr-xmit-pthreads/include/pthread/fd_pipe.h54
-rwxr-xr-xmit-pthreads/include/pthread/kernel.h71
-rwxr-xr-xmit-pthreads/include/pthread/kthread.h67
-rwxr-xr-xmit-pthreads/include/pthread/mutex.h102
-rw-r--r--mit-pthreads/include/pthread/paths.h12
-rwxr-xr-xmit-pthreads/include/pthread/prio_queue.h78
-rwxr-xr-xmit-pthreads/include/pthread/pthread_attr.h122
-rwxr-xr-xmit-pthreads/include/pthread/pthread_once.h58
-rwxr-xr-xmit-pthreads/include/pthread/queue.h67
-rwxr-xr-xmit-pthreads/include/pthread/sleep.h63
-rwxr-xr-xmit-pthreads/include/pthread/specific.h66
-rwxr-xr-xmit-pthreads/include/pthread/state.def64
-rwxr-xr-xmit-pthreads/include/pthread/types.h46
-rwxr-xr-xmit-pthreads/include/pthread/unistd.h159
-rwxr-xr-xmit-pthreads/include/pthread/util.h89
-rwxr-xr-xmit-pthreads/include/pthread/version.h43
-rwxr-xr-xmit-pthreads/include/pthread/xtypes.h13
-rw-r--r--mit-pthreads/include/pwd.h93
-rw-r--r--mit-pthreads/include/resolv.h179
-rw-r--r--mit-pthreads/include/sched.h57
-rw-r--r--mit-pthreads/include/signal.h81
-rw-r--r--mit-pthreads/include/stdio.h371
-rw-r--r--mit-pthreads/include/stdlib.h127
-rw-r--r--mit-pthreads/include/string.h85
-rw-r--r--mit-pthreads/include/syslog.h101
-rw-r--r--mit-pthreads/include/time.h102
-rw-r--r--mit-pthreads/include/timers.h45
-rw-r--r--mit-pthreads/include/tzfile.h154
-rw-r--r--mit-pthreads/include/unistd.h183
-rw-r--r--mit-pthreads/lib/.cvsignore1
-rw-r--r--mit-pthreads/lib/Makefile.in48
-rw-r--r--mit-pthreads/lib/libpthreadutil/.cvsignore1
-rwxr-xr-xmit-pthreads/lib/libpthreadutil/Makefile.in65
-rwxr-xr-xmit-pthreads/lib/libpthreadutil/pthread_atexit.c135
-rwxr-xr-xmit-pthreads/lib/libpthreadutil/pthread_tad.c170
-rwxr-xr-xmit-pthreads/lib/libpthreadutil/pthreadutil.h75
-rwxr-xr-xmit-pthreads/machdep/alpha-osf1/__math.h16
-rwxr-xr-xmit-pthreads/machdep/alpha-osf1/__signal.h106
-rwxr-xr-xmit-pthreads/machdep/alpha-osf1/__stdio.h13
-rwxr-xr-xmit-pthreads/machdep/alpha-osf1/__stdlib.h3
-rwxr-xr-xmit-pthreads/machdep/alpha-osf1/__string.h19
-rwxr-xr-xmit-pthreads/machdep/alpha-osf1/__time.h21
-rwxr-xr-xmit-pthreads/machdep/alpha-osf1/__unistd.h6
-rwxr-xr-xmit-pthreads/machdep/alpha-osf1/cdefs.h62
-rwxr-xr-xmit-pthreads/machdep/alpha-osf1/compat.h1
-rwxr-xr-xmit-pthreads/machdep/alpha-osf1/dirent.h7
-rwxr-xr-xmit-pthreads/machdep/alpha-osf1/signal.h3
-rwxr-xr-xmit-pthreads/machdep/alpha-osf1/socket.h296
-rwxr-xr-xmit-pthreads/machdep/alpha-osf1/timers.h60
-rwxr-xr-xmit-pthreads/machdep/alpha-osf1/uio.h12
-rwxr-xr-xmit-pthreads/machdep/bsdi-1.1/compat.h43
-rwxr-xr-xmit-pthreads/machdep/bsdi-1.1/dirent.h73
-rwxr-xr-xmit-pthreads/machdep/bsdi-1.1/errno.h160
-rwxr-xr-xmit-pthreads/machdep/bsdi-1.1/socket.h277
-rwxr-xr-xmit-pthreads/machdep/bsdi-1.1/timers.h59
-rwxr-xr-xmit-pthreads/machdep/bsdi-2.0/__math.h6
-rwxr-xr-xmit-pthreads/machdep/bsdi-2.0/__path.h13
-rwxr-xr-xmit-pthreads/machdep/bsdi-2.0/__signal.h7
-rwxr-xr-xmit-pthreads/machdep/bsdi-2.0/__stdio.h7
-rwxr-xr-xmit-pthreads/machdep/bsdi-2.0/__stdlib.h60
-rwxr-xr-xmit-pthreads/machdep/bsdi-2.0/__string.h19
-rwxr-xr-xmit-pthreads/machdep/bsdi-2.0/__time.h63
-rwxr-xr-xmit-pthreads/machdep/bsdi-2.0/__unistd.h109
-rwxr-xr-xmit-pthreads/machdep/bsdi-2.0/compat.h65
-rwxr-xr-xmit-pthreads/machdep/bsdi-2.0/dirent.h65
-rwxr-xr-xmit-pthreads/machdep/bsdi-2.0/errno.h162
-rwxr-xr-xmit-pthreads/machdep/bsdi-2.0/time.h6
-rwxr-xr-xmit-pthreads/machdep/bsdi-2.0/timers.h45
-rwxr-xr-xmit-pthreads/machdep/bsdi-2.0/wait.h159
-rw-r--r--mit-pthreads/machdep/engine-alpha-netbsd-1.1.c196
-rw-r--r--mit-pthreads/machdep/engine-alpha-netbsd-1.1.h111
-rw-r--r--mit-pthreads/machdep/engine-alpha-netbsd-1.3.c204
-rw-r--r--mit-pthreads/machdep/engine-alpha-netbsd-1.3.h114
-rw-r--r--mit-pthreads/machdep/engine-alpha-osf1.c207
-rw-r--r--mit-pthreads/machdep/engine-alpha-osf1.h110
-rw-r--r--mit-pthreads/machdep/engine-arm32-netbsd-1.3.c203
-rw-r--r--mit-pthreads/machdep/engine-arm32-netbsd-1.3.h102
-rw-r--r--mit-pthreads/machdep/engine-hppa-hpux-10.20.c169
-rw-r--r--mit-pthreads/machdep/engine-hppa-hpux-10.20.h143
-rw-r--r--mit-pthreads/machdep/engine-hppa-hpux-9.03.c153
-rw-r--r--mit-pthreads/machdep/engine-hppa-hpux-9.03.h141
-rw-r--r--mit-pthreads/machdep/engine-i386-bsdi-1.1.c180
-rw-r--r--mit-pthreads/machdep/engine-i386-bsdi-1.1.h84
-rw-r--r--mit-pthreads/machdep/engine-i386-bsdi-2.0.c210
-rw-r--r--mit-pthreads/machdep/engine-i386-bsdi-2.0.h98
-rw-r--r--mit-pthreads/machdep/engine-i386-freebsd-1.1.c179
-rw-r--r--mit-pthreads/machdep/engine-i386-freebsd-1.1.h83
-rw-r--r--mit-pthreads/machdep/engine-i386-freebsd-2.0.c208
-rw-r--r--mit-pthreads/machdep/engine-i386-freebsd-2.0.h97
-rw-r--r--mit-pthreads/machdep/engine-i386-linux-1.0.c503
-rw-r--r--mit-pthreads/machdep/engine-i386-linux-1.0.h98
-rw-r--r--mit-pthreads/machdep/engine-i386-linux-2.0.c504
-rw-r--r--mit-pthreads/machdep/engine-i386-linux-2.0.h98
-rw-r--r--mit-pthreads/machdep/engine-i386-netbsd-0.9.c155
-rw-r--r--mit-pthreads/machdep/engine-i386-netbsd-0.9.h83
-rw-r--r--mit-pthreads/machdep/engine-i386-netbsd-1.0.c218
-rw-r--r--mit-pthreads/machdep/engine-i386-netbsd-1.0.h97
-rw-r--r--mit-pthreads/machdep/engine-i386-netbsd-1.3.c225
-rw-r--r--mit-pthreads/machdep/engine-i386-netbsd-1.3.h98
-rw-r--r--mit-pthreads/machdep/engine-i386-openbsd-2.0.c215
-rw-r--r--mit-pthreads/machdep/engine-i386-openbsd-2.0.h97
-rwxr-xr-xmit-pthreads/machdep/engine-i386-sco-3.2v5.c1072
-rw-r--r--mit-pthreads/machdep/engine-i386-sco-3.2v5.h104
-rw-r--r--mit-pthreads/machdep/engine-ip22-irix-5.2.c225
-rw-r--r--mit-pthreads/machdep/engine-ip22-irix-5.2.h108
-rw-r--r--mit-pthreads/machdep/engine-m68000-netbsd.c256
-rw-r--r--mit-pthreads/machdep/engine-m68000-netbsd.h107
-rw-r--r--mit-pthreads/machdep/engine-r2000-ultrix-4.2.c209
-rw-r--r--mit-pthreads/machdep/engine-r2000-ultrix-4.2.h107
-rw-r--r--mit-pthreads/machdep/engine-romp-bsd.c99
-rw-r--r--mit-pthreads/machdep/engine-romp-bsd.h100
-rw-r--r--mit-pthreads/machdep/engine-sparc-netbsd-1.3.c232
-rw-r--r--mit-pthreads/machdep/engine-sparc-netbsd-1.3.h106
-rw-r--r--mit-pthreads/machdep/engine-sparc-sunos-4.1.3.c227
-rw-r--r--mit-pthreads/machdep/engine-sparc-sunos-4.1.3.h105
-rw-r--r--mit-pthreads/machdep/engine-sparc-sunos-5.3.c308
-rw-r--r--mit-pthreads/machdep/engine-sparc-sunos-5.3.h129
-rwxr-xr-xmit-pthreads/machdep/freebsd-1.1/compat.h43
-rwxr-xr-xmit-pthreads/machdep/freebsd-1.1/dirent.h64
-rwxr-xr-xmit-pthreads/machdep/freebsd-1.1/socket.h267
-rwxr-xr-xmit-pthreads/machdep/freebsd-1.1/timers.h68
-rwxr-xr-xmit-pthreads/machdep/freebsd-2.0/__math.h6
-rwxr-xr-xmit-pthreads/machdep/freebsd-2.0/__path.h14
-rwxr-xr-xmit-pthreads/machdep/freebsd-2.0/__signal.h8
-rwxr-xr-xmit-pthreads/machdep/freebsd-2.0/__stdio.h8
-rwxr-xr-xmit-pthreads/machdep/freebsd-2.0/__stdlib.h66
-rwxr-xr-xmit-pthreads/machdep/freebsd-2.0/__string.h21
-rwxr-xr-xmit-pthreads/machdep/freebsd-2.0/__time.h70
-rwxr-xr-xmit-pthreads/machdep/freebsd-2.0/__unistd.h113
-rwxr-xr-xmit-pthreads/machdep/freebsd-2.0/compat.h43
-rwxr-xr-xmit-pthreads/machdep/freebsd-2.0/dirent.h64
-rwxr-xr-xmit-pthreads/machdep/freebsd-2.0/errno.h160
-rwxr-xr-xmit-pthreads/machdep/freebsd-2.0/timers.h45
-rwxr-xr-xmit-pthreads/machdep/freebsd-2.0/wait.h162
-rwxr-xr-xmit-pthreads/machdep/hpux-10.20/__math.h3
-rwxr-xr-xmit-pthreads/machdep/hpux-10.20/__signal.h28
-rwxr-xr-xmit-pthreads/machdep/hpux-10.20/__stdio.h11
-rwxr-xr-xmit-pthreads/machdep/hpux-10.20/__stdlib.h24
-rwxr-xr-xmit-pthreads/machdep/hpux-10.20/__string.h20
-rwxr-xr-xmit-pthreads/machdep/hpux-10.20/__time.h31
-rwxr-xr-xmit-pthreads/machdep/hpux-10.20/__unistd.h68
-rwxr-xr-xmit-pthreads/machdep/hpux-10.20/cdefs.h67
-rwxr-xr-xmit-pthreads/machdep/hpux-10.20/compat.h45
-rwxr-xr-xmit-pthreads/machdep/hpux-10.20/dirent.h61
-rwxr-xr-xmit-pthreads/machdep/hpux-10.20/socket.h171
-rwxr-xr-xmit-pthreads/machdep/hpux-10.20/stdtypes.h74
-rwxr-xr-xmit-pthreads/machdep/hpux-10.20/time.h228
-rwxr-xr-xmit-pthreads/machdep/hpux-10.20/timers.h71
-rwxr-xr-xmit-pthreads/machdep/hpux-10.20/uio.h25
-rwxr-xr-xmit-pthreads/machdep/hpux-10.20/wait.h92
-rwxr-xr-xmit-pthreads/machdep/hpux-9.03/__math.h3
-rwxr-xr-xmit-pthreads/machdep/hpux-9.03/__signal.h28
-rwxr-xr-xmit-pthreads/machdep/hpux-9.03/__stdio.h8
-rwxr-xr-xmit-pthreads/machdep/hpux-9.03/__stdlib.h24
-rwxr-xr-xmit-pthreads/machdep/hpux-9.03/__string.h20
-rwxr-xr-xmit-pthreads/machdep/hpux-9.03/__time.h31
-rwxr-xr-xmit-pthreads/machdep/hpux-9.03/__unistd.h66
-rwxr-xr-xmit-pthreads/machdep/hpux-9.03/cdefs.h61
-rwxr-xr-xmit-pthreads/machdep/hpux-9.03/compat.h45
-rwxr-xr-xmit-pthreads/machdep/hpux-9.03/dirent.h61
-rwxr-xr-xmit-pthreads/machdep/hpux-9.03/socket.h171
-rwxr-xr-xmit-pthreads/machdep/hpux-9.03/stdtypes.h74
-rwxr-xr-xmit-pthreads/machdep/hpux-9.03/time.h228
-rwxr-xr-xmit-pthreads/machdep/hpux-9.03/timers.h68
-rwxr-xr-xmit-pthreads/machdep/hpux-9.03/uio.h25
-rwxr-xr-xmit-pthreads/machdep/hpux-9.03/wait.h92
-rwxr-xr-xmit-pthreads/machdep/i386-sco-3.2v5/__math.h219
-rwxr-xr-xmit-pthreads/machdep/i386-sco-3.2v5/__signal.h109
-rwxr-xr-xmit-pthreads/machdep/i386-sco-3.2v5/__stdio.h113
-rwxr-xr-xmit-pthreads/machdep/i386-sco-3.2v5/__stdlib.h137
-rwxr-xr-xmit-pthreads/machdep/i386-sco-3.2v5/__string.h125
-rwxr-xr-xmit-pthreads/machdep/i386-sco-3.2v5/__time.h141
-rwxr-xr-xmit-pthreads/machdep/i386-sco-3.2v5/__unistd.h48
-rwxr-xr-xmit-pthreads/machdep/i386-sco-3.2v5/compat.h46
-rwxr-xr-xmit-pthreads/machdep/i386-sco-3.2v5/dirent.h145
-rwxr-xr-xmit-pthreads/machdep/i386-sco-3.2v5/posix/__signal.h69
-rwxr-xr-xmit-pthreads/machdep/i386-sco-3.2v5/socket.h490
-rwxr-xr-xmit-pthreads/machdep/i386-sco-3.2v5/syscall.h175
-rwxr-xr-xmit-pthreads/machdep/i386-sco-3.2v5/timers.h68
-rwxr-xr-xmit-pthreads/machdep/i386-sco-3.2v5/trash.can1
-rwxr-xr-xmit-pthreads/machdep/irix-5.2/__math.h4
-rwxr-xr-xmit-pthreads/machdep/irix-5.2/__signal.h15
-rwxr-xr-xmit-pthreads/machdep/irix-5.2/__stdio.h6
-rwxr-xr-xmit-pthreads/machdep/irix-5.2/__stdlib.h30
-rwxr-xr-xmit-pthreads/machdep/irix-5.2/__string.h5
-rwxr-xr-xmit-pthreads/machdep/irix-5.2/__time.h21
-rwxr-xr-xmit-pthreads/machdep/irix-5.2/__unistd.h8
-rwxr-xr-xmit-pthreads/machdep/irix-5.2/compat.h45
-rwxr-xr-xmit-pthreads/machdep/irix-5.2/dirent.h21
-rwxr-xr-xmit-pthreads/machdep/irix-5.2/socket.h304
-rwxr-xr-xmit-pthreads/machdep/irix-5.2/timers.h18
-rwxr-xr-xmit-pthreads/machdep/irix-5.2/wait.h104
-rwxr-xr-xmit-pthreads/machdep/linux-1.0/__math.h4
-rwxr-xr-xmit-pthreads/machdep/linux-1.0/__path.h14
-rwxr-xr-xmit-pthreads/machdep/linux-1.0/__signal.h24
-rwxr-xr-xmit-pthreads/machdep/linux-1.0/__stdio.h7
-rwxr-xr-xmit-pthreads/machdep/linux-1.0/__stdlib.h20
-rwxr-xr-xmit-pthreads/machdep/linux-1.0/__string.h18
-rwxr-xr-xmit-pthreads/machdep/linux-1.0/__time.h72
-rwxr-xr-xmit-pthreads/machdep/linux-1.0/__unistd.h56
-rwxr-xr-xmit-pthreads/machdep/linux-1.0/cdefs.h23
-rwxr-xr-xmit-pthreads/machdep/linux-1.0/compat.h47
-rwxr-xr-xmit-pthreads/machdep/linux-1.0/dirent.h27
-rwxr-xr-xmit-pthreads/machdep/linux-1.0/errno.h12
-rwxr-xr-xmit-pthreads/machdep/linux-1.0/socket.h193
-rwxr-xr-xmit-pthreads/machdep/linux-1.0/timers.h71
-rwxr-xr-xmit-pthreads/machdep/linux-1.0/uio.h15
-rwxr-xr-xmit-pthreads/machdep/linux-1.0/wait.h98
-rwxr-xr-xmit-pthreads/machdep/linux-2.0/__math.h4
-rwxr-xr-xmit-pthreads/machdep/linux-2.0/__path.h14
-rwxr-xr-xmit-pthreads/machdep/linux-2.0/__signal.h24
-rwxr-xr-xmit-pthreads/machdep/linux-2.0/__stdio.h7
-rwxr-xr-xmit-pthreads/machdep/linux-2.0/__stdlib.h20
-rwxr-xr-xmit-pthreads/machdep/linux-2.0/__string.h18
-rwxr-xr-xmit-pthreads/machdep/linux-2.0/__time.h78
-rwxr-xr-xmit-pthreads/machdep/linux-2.0/__unistd.h62
-rwxr-xr-xmit-pthreads/machdep/linux-2.0/cdefs.h36
-rwxr-xr-xmit-pthreads/machdep/linux-2.0/compat.h47
-rwxr-xr-xmit-pthreads/machdep/linux-2.0/dirent.h27
-rwxr-xr-xmit-pthreads/machdep/linux-2.0/errno.h12
-rw-r--r--mit-pthreads/machdep/linux-2.0/extra/bits/local_lim.h15
-rwxr-xr-xmit-pthreads/machdep/linux-2.0/extra/bits/socket.h193
-rwxr-xr-xmit-pthreads/machdep/linux-2.0/socket.h196
-rw-r--r--mit-pthreads/machdep/linux-2.0/socketcall.h0
-rwxr-xr-xmit-pthreads/machdep/linux-2.0/timers.h71
-rwxr-xr-xmit-pthreads/machdep/linux-2.0/uio.h15
-rwxr-xr-xmit-pthreads/machdep/linux-2.0/wait.h98
-rwxr-xr-xmit-pthreads/machdep/netbsd-0.9/dirent.h64
-rwxr-xr-xmit-pthreads/machdep/netbsd-1.0/__math.h6
-rwxr-xr-xmit-pthreads/machdep/netbsd-1.0/__path.h14
-rwxr-xr-xmit-pthreads/machdep/netbsd-1.0/__signal.h8
-rwxr-xr-xmit-pthreads/machdep/netbsd-1.0/__stdio.h8
-rwxr-xr-xmit-pthreads/machdep/netbsd-1.0/__stdlib.h60
-rwxr-xr-xmit-pthreads/machdep/netbsd-1.0/__string.h20
-rwxr-xr-xmit-pthreads/machdep/netbsd-1.0/__time.h69
-rwxr-xr-xmit-pthreads/machdep/netbsd-1.0/__unistd.h107
-rwxr-xr-xmit-pthreads/machdep/netbsd-1.0/compat.h43
-rwxr-xr-xmit-pthreads/machdep/netbsd-1.0/dirent.h64
-rwxr-xr-xmit-pthreads/machdep/netbsd-1.0/errno.h160
-rwxr-xr-xmit-pthreads/machdep/netbsd-1.0/time.h125
-rwxr-xr-xmit-pthreads/machdep/netbsd-1.0/timers.h45
-rwxr-xr-xmit-pthreads/machdep/netbsd-1.0/wait.h158
-rwxr-xr-xmit-pthreads/machdep/netbsd-1.1/__math.h6
-rwxr-xr-xmit-pthreads/machdep/netbsd-1.1/__path.h14
-rwxr-xr-xmit-pthreads/machdep/netbsd-1.1/__signal.h20
-rwxr-xr-xmit-pthreads/machdep/netbsd-1.1/__stdio.h8
-rwxr-xr-xmit-pthreads/machdep/netbsd-1.1/__stdlib.h60
-rwxr-xr-xmit-pthreads/machdep/netbsd-1.1/__string.h20
-rwxr-xr-xmit-pthreads/machdep/netbsd-1.1/__time.h69
-rwxr-xr-xmit-pthreads/machdep/netbsd-1.1/__unistd.h107
-rwxr-xr-xmit-pthreads/machdep/netbsd-1.1/compat.h43
-rwxr-xr-xmit-pthreads/machdep/netbsd-1.1/dirent.h95
-rwxr-xr-xmit-pthreads/machdep/netbsd-1.1/errno.h170
-rwxr-xr-xmit-pthreads/machdep/netbsd-1.1/time.h153
-rwxr-xr-xmit-pthreads/machdep/netbsd-1.1/timers.h45
-rwxr-xr-xmit-pthreads/machdep/netbsd-1.1/wait.h163
-rwxr-xr-xmit-pthreads/machdep/openbsd-2.0/__math.h6
-rwxr-xr-xmit-pthreads/machdep/openbsd-2.0/__path.h14
-rwxr-xr-xmit-pthreads/machdep/openbsd-2.0/__signal.h8
-rwxr-xr-xmit-pthreads/machdep/openbsd-2.0/__stdio.h8
-rwxr-xr-xmit-pthreads/machdep/openbsd-2.0/__stdlib.h66
-rwxr-xr-xmit-pthreads/machdep/openbsd-2.0/__string.h21
-rwxr-xr-xmit-pthreads/machdep/openbsd-2.0/__time.h70
-rwxr-xr-xmit-pthreads/machdep/openbsd-2.0/__unistd.h109
-rwxr-xr-xmit-pthreads/machdep/openbsd-2.0/compat.h43
-rwxr-xr-xmit-pthreads/machdep/openbsd-2.0/dirent.h64
-rwxr-xr-xmit-pthreads/machdep/openbsd-2.0/errno.h160
-rwxr-xr-xmit-pthreads/machdep/openbsd-2.0/timers.h45
-rwxr-xr-xmit-pthreads/machdep/openbsd-2.0/wait.h162
-rw-r--r--mit-pthreads/machdep/posix-alpha-osf1.h7
-rw-r--r--mit-pthreads/machdep/posix-bsdi-1.1.h34
-rw-r--r--mit-pthreads/machdep/posix-bsdi-2.0.h34
-rw-r--r--mit-pthreads/machdep/posix-freebsd-1.1.h33
-rw-r--r--mit-pthreads/machdep/posix-freebsd-2.0.h31
-rw-r--r--mit-pthreads/machdep/posix-hpux-10.20.h23
-rw-r--r--mit-pthreads/machdep/posix-hpux-9.03.h23
-rw-r--r--mit-pthreads/machdep/posix-i386-sco-3.2v5.h35
-rw-r--r--mit-pthreads/machdep/posix-irix-5.2.h31
-rw-r--r--mit-pthreads/machdep/posix-linux-1.0.h31
-rw-r--r--mit-pthreads/machdep/posix-linux-2.0.h31
-rw-r--r--mit-pthreads/machdep/posix-netbsd-0.9.h22
-rw-r--r--mit-pthreads/machdep/posix-netbsd-1.0.h31
-rw-r--r--mit-pthreads/machdep/posix-netbsd-1.1.h31
-rw-r--r--mit-pthreads/machdep/posix-openbsd-2.0.h31
-rw-r--r--mit-pthreads/machdep/posix-romp-bsd.h33
-rw-r--r--mit-pthreads/machdep/posix-sco-3.2v5.h35
-rw-r--r--mit-pthreads/machdep/posix-sunos-4.1.3.h27
-rw-r--r--mit-pthreads/machdep/posix-sunos-5.3.h22
-rw-r--r--mit-pthreads/machdep/posix-sunos-5.5.h22
-rw-r--r--mit-pthreads/machdep/posix-ultrix-4.2.h24
-rwxr-xr-xmit-pthreads/machdep/sco-3.2v5/__math.h219
-rwxr-xr-xmit-pthreads/machdep/sco-3.2v5/__signal.h109
-rwxr-xr-xmit-pthreads/machdep/sco-3.2v5/__stdio.h113
-rwxr-xr-xmit-pthreads/machdep/sco-3.2v5/__stdlib.h137
-rwxr-xr-xmit-pthreads/machdep/sco-3.2v5/__string.h125
-rwxr-xr-xmit-pthreads/machdep/sco-3.2v5/__time.h141
-rwxr-xr-xmit-pthreads/machdep/sco-3.2v5/__unistd.h48
-rwxr-xr-xmit-pthreads/machdep/sco-3.2v5/compat.h46
-rwxr-xr-xmit-pthreads/machdep/sco-3.2v5/dirent.h145
-rwxr-xr-xmit-pthreads/machdep/sco-3.2v5/posix/__signal.h69
-rwxr-xr-xmit-pthreads/machdep/sco-3.2v5/socket.h490
-rwxr-xr-xmit-pthreads/machdep/sco-3.2v5/syscall.h175
-rwxr-xr-xmit-pthreads/machdep/sco-3.2v5/timers.h68
-rwxr-xr-xmit-pthreads/machdep/sco-3.2v5/trash.can1
-rwxr-xr-xmit-pthreads/machdep/sunos-4.1.3/__math.h5
-rwxr-xr-xmit-pthreads/machdep/sunos-4.1.3/__path.h12
-rwxr-xr-xmit-pthreads/machdep/sunos-4.1.3/__signal.h11
-rwxr-xr-xmit-pthreads/machdep/sunos-4.1.3/__stdio.h4
-rwxr-xr-xmit-pthreads/machdep/sunos-4.1.3/__stdlib.h28
-rwxr-xr-xmit-pthreads/machdep/sunos-4.1.3/__string.h14
-rwxr-xr-xmit-pthreads/machdep/sunos-4.1.3/__time.h2
-rwxr-xr-xmit-pthreads/machdep/sunos-4.1.3/__unistd.h73
-rwxr-xr-xmit-pthreads/machdep/sunos-4.1.3/cdefs.h61
-rwxr-xr-xmit-pthreads/machdep/sunos-4.1.3/compat.h45
-rwxr-xr-xmit-pthreads/machdep/sunos-4.1.3/dirent.h64
-rwxr-xr-xmit-pthreads/machdep/sunos-4.1.3/fcntlcom.h163
-rwxr-xr-xmit-pthreads/machdep/sunos-4.1.3/signal.h98
-rwxr-xr-xmit-pthreads/machdep/sunos-4.1.3/stat.h94
-rwxr-xr-xmit-pthreads/machdep/sunos-4.1.3/time.h69
-rwxr-xr-xmit-pthreads/machdep/sunos-4.1.3/timers.h68
-rwxr-xr-xmit-pthreads/machdep/sunos-4.1.3/wait.h22
-rwxr-xr-xmit-pthreads/machdep/sunos-5.3/__math.h16
-rwxr-xr-xmit-pthreads/machdep/sunos-5.3/__signal.h19
-rwxr-xr-xmit-pthreads/machdep/sunos-5.3/__stdio.h6
-rwxr-xr-xmit-pthreads/machdep/sunos-5.3/__stdlib.h27
-rwxr-xr-xmit-pthreads/machdep/sunos-5.3/__string.h12
-rwxr-xr-xmit-pthreads/machdep/sunos-5.3/__time.h69
-rwxr-xr-xmit-pthreads/machdep/sunos-5.3/__unistd.h47
-rwxr-xr-xmit-pthreads/machdep/sunos-5.3/cdefs.h59
-rwxr-xr-xmit-pthreads/machdep/sunos-5.3/compat.h45
-rwxr-xr-xmit-pthreads/machdep/sunos-5.3/dirent.h64
-rwxr-xr-xmit-pthreads/machdep/sunos-5.3/socket.h180
-rwxr-xr-xmit-pthreads/machdep/sunos-5.3/timers.h72
-rwxr-xr-xmit-pthreads/machdep/sunos-5.3/uio.h40
-rwxr-xr-xmit-pthreads/machdep/sunos-5.5/__math.h16
-rwxr-xr-xmit-pthreads/machdep/sunos-5.5/__signal.h19
-rwxr-xr-xmit-pthreads/machdep/sunos-5.5/__stdio.h6
-rwxr-xr-xmit-pthreads/machdep/sunos-5.5/__stdlib.h27
-rwxr-xr-xmit-pthreads/machdep/sunos-5.5/__string.h12
-rwxr-xr-xmit-pthreads/machdep/sunos-5.5/__time.h69
-rwxr-xr-xmit-pthreads/machdep/sunos-5.5/__unistd.h47
-rwxr-xr-xmit-pthreads/machdep/sunos-5.5/cdefs.h59
-rwxr-xr-xmit-pthreads/machdep/sunos-5.5/compat.h45
-rwxr-xr-xmit-pthreads/machdep/sunos-5.5/dirent.h64
-rwxr-xr-xmit-pthreads/machdep/sunos-5.5/socket.h180
-rwxr-xr-xmit-pthreads/machdep/sunos-5.5/timers.h70
-rwxr-xr-xmit-pthreads/machdep/sunos-5.5/uio.h40
-rw-r--r--mit-pthreads/machdep/syscall-alpha-netbsd-1.1.S206
-rw-r--r--mit-pthreads/machdep/syscall-alpha-netbsd-1.3.S228
-rw-r--r--mit-pthreads/machdep/syscall-alpha-osf1.S97
-rw-r--r--mit-pthreads/machdep/syscall-arm32-netbsd-1.3.S193
-rw-r--r--mit-pthreads/machdep/syscall-hppa-hpux-10.20.S23
-rw-r--r--mit-pthreads/machdep/syscall-hppa-hpux-9.03.S23
-rw-r--r--mit-pthreads/machdep/syscall-i386-bsdi-1.1.S288
-rw-r--r--mit-pthreads/machdep/syscall-i386-bsdi-2.0.S294
-rw-r--r--mit-pthreads/machdep/syscall-i386-freebsd-1.1.S293
-rw-r--r--mit-pthreads/machdep/syscall-i386-freebsd-2.0.S240
-rw-r--r--mit-pthreads/machdep/syscall-i386-linux-1.0.S406
-rw-r--r--mit-pthreads/machdep/syscall-i386-linux-2.0.S389
-rw-r--r--mit-pthreads/machdep/syscall-i386-netbsd-0.9.S229
-rw-r--r--mit-pthreads/machdep/syscall-i386-netbsd-1.0.S158
-rw-r--r--mit-pthreads/machdep/syscall-i386-netbsd-1.1.S181
-rw-r--r--mit-pthreads/machdep/syscall-i386-netbsd-1.3.S200
-rw-r--r--mit-pthreads/machdep/syscall-i386-openbsd-2.0.S237
-rw-r--r--mit-pthreads/machdep/syscall-i386-sco-3.2v5.S442
-rw-r--r--mit-pthreads/machdep/syscall-ip22-irix-5.2.S106
-rw-r--r--mit-pthreads/machdep/syscall-m68000-netbsd.S83
-rw-r--r--mit-pthreads/machdep/syscall-r2000-ultrix-4.2.S166
-rw-r--r--mit-pthreads/machdep/syscall-romp-bsd.S327
-rw-r--r--mit-pthreads/machdep/syscall-sparc-netbsd-1.1.S102
-rw-r--r--mit-pthreads/machdep/syscall-sparc-netbsd-1.3.S172
-rw-r--r--mit-pthreads/machdep/syscall-sparc-sunos-4.1.3.S113
-rw-r--r--mit-pthreads/machdep/syscall-sparc-sunos-5.3.S65
-rw-r--r--mit-pthreads/machdep/syscall-sparc-sunos4.S113
-rw-r--r--mit-pthreads/machdep/syscall-template-alpha-netbsd-1.1.S46
-rw-r--r--mit-pthreads/machdep/syscall-template-alpha-netbsd-1.3.S53
-rw-r--r--mit-pthreads/machdep/syscall-template-alpha-osf1.S46
-rw-r--r--mit-pthreads/machdep/syscall-template-arm32-netbsd-1.3.S55
-rw-r--r--mit-pthreads/machdep/syscall-template-hppa-hpux-10.20.S27
-rw-r--r--mit-pthreads/machdep/syscall-template-hppa-hpux-9.03.S27
-rw-r--r--mit-pthreads/machdep/syscall-template-i386-bsdi-2.0.S48
-rw-r--r--mit-pthreads/machdep/syscall-template-i386-freebsd-2.0.S59
-rw-r--r--mit-pthreads/machdep/syscall-template-i386-netbsd-1.1.S49
-rw-r--r--mit-pthreads/machdep/syscall-template-i386-netbsd-1.3.S56
-rw-r--r--mit-pthreads/machdep/syscall-template-i386-netbsd1.0.S49
-rw-r--r--mit-pthreads/machdep/syscall-template-i386-openbsd-2.0.S48
-rw-r--r--mit-pthreads/machdep/syscall-template-i386-sco-3.2v5.S67
-rw-r--r--mit-pthreads/machdep/syscall-template-ip22-irix-5.2.S51
-rw-r--r--mit-pthreads/machdep/syscall-template-m68000-netbsd.S43
-rw-r--r--mit-pthreads/machdep/syscall-template-r2000-ultrix-4.2.S77
-rw-r--r--mit-pthreads/machdep/syscall-template-sparc-netbsd-1.1.S40
-rw-r--r--mit-pthreads/machdep/syscall-template-sparc-netbsd-1.3.S48
-rw-r--r--mit-pthreads/machdep/syscall-template-sparc-sunos-5.3.S45
-rw-r--r--mit-pthreads/machdep/syscall-template-sparc-sunos4.S40
-rwxr-xr-xmit-pthreads/machdep/ultrix-4.2/__math.h2
-rwxr-xr-xmit-pthreads/machdep/ultrix-4.2/__signal.h66
-rwxr-xr-xmit-pthreads/machdep/ultrix-4.2/__stdio.h7
-rwxr-xr-xmit-pthreads/machdep/ultrix-4.2/__stdlib.h21
-rwxr-xr-xmit-pthreads/machdep/ultrix-4.2/__string.h17
-rwxr-xr-xmit-pthreads/machdep/ultrix-4.2/__time.h69
-rwxr-xr-xmit-pthreads/machdep/ultrix-4.2/__unistd.h51
-rwxr-xr-xmit-pthreads/machdep/ultrix-4.2/cdefs.h66
-rwxr-xr-xmit-pthreads/machdep/ultrix-4.2/compat.h45
-rwxr-xr-xmit-pthreads/machdep/ultrix-4.2/dirent.h61
-rwxr-xr-xmit-pthreads/machdep/ultrix-4.2/errno.h180
-rwxr-xr-xmit-pthreads/machdep/ultrix-4.2/time.h83
-rwxr-xr-xmit-pthreads/machdep/ultrix-4.2/timers.h68
-rwxr-xr-xmit-pthreads/machdep/ultrix-4.2/wait.h121
-rw-r--r--mit-pthreads/machdep/unistd-i386-freebsd-1.1.h178
-rw-r--r--mit-pthreads/machdep/unistd-i386-linux-1.0.h59
-rw-r--r--mit-pthreads/machdep/unistd-i386-linux-2.0.h59
-rw-r--r--mit-pthreads/machdep/unistd-sparc-sunos-4.1.3.h215
-rw-r--r--mit-pthreads/net/GNUmakefile.inc14
-rw-r--r--mit-pthreads/net/Makefile.inc13
-rw-r--r--mit-pthreads/net/gethostbyaddr.c161
-rw-r--r--mit-pthreads/net/gethostbyname.c167
-rw-r--r--mit-pthreads/net/gethostent.c162
-rw-r--r--mit-pthreads/net/gethostname.c22
-rw-r--r--mit-pthreads/net/getnetbyaddr.c65
-rw-r--r--mit-pthreads/net/getnetbyname.c72
-rw-r--r--mit-pthreads/net/getnetent.c145
-rw-r--r--mit-pthreads/net/getproto.c65
-rw-r--r--mit-pthreads/net/getprotoent.c143
-rw-r--r--mit-pthreads/net/getprotoname.c73
-rw-r--r--mit-pthreads/net/getservbyname.c76
-rw-r--r--mit-pthreads/net/getservbyport.c68
-rw-r--r--mit-pthreads/net/getservent.c146
-rw-r--r--mit-pthreads/net/herror.c92
-rw-r--r--mit-pthreads/net/inet_addr.c156
-rw-r--r--mit-pthreads/net/inet_lnaof.c61
-rw-r--r--mit-pthreads/net/inet_makeaddr.c64
-rw-r--r--mit-pthreads/net/inet_netof.c60
-rw-r--r--mit-pthreads/net/inet_network.c98
-rw-r--r--mit-pthreads/net/inet_ntoa.c85
-rw-r--r--mit-pthreads/net/net_internal.c78
-rw-r--r--mit-pthreads/net/net_internal.h57
-rw-r--r--mit-pthreads/net/proto_internal.c78
-rw-r--r--mit-pthreads/net/proto_internal.h57
-rw-r--r--mit-pthreads/net/res_comp.c340
-rw-r--r--mit-pthreads/net/res_debug.c749
-rw-r--r--mit-pthreads/net/res_init.c55
-rw-r--r--mit-pthreads/net/res_internal.c576
-rw-r--r--mit-pthreads/net/res_internal.h84
-rw-r--r--mit-pthreads/net/res_mkquery.c212
-rw-r--r--mit-pthreads/net/res_query.c97
-rw-r--r--mit-pthreads/net/res_querydomain.c66
-rw-r--r--mit-pthreads/net/res_search.c168
-rw-r--r--mit-pthreads/net/res_send.c313
-rw-r--r--mit-pthreads/net/serv_internal.c80
-rw-r--r--mit-pthreads/net/serv_internal.h57
-rwxr-xr-xmit-pthreads/patches/Streepy.html2873
-rwxr-xr-xmit-pthreads/patches/Streepy2.html93
-rwxr-xr-xmit-pthreads/patches/bill_lear70
-rwxr-xr-xmit-pthreads/patches/chris_demetriou149
-rwxr-xr-xmit-pthreads/patches/mevans642
-rwxr-xr-xmit-pthreads/patches/p15390
-rwxr-xr-xmit-pthreads/patches/p15596
-rwxr-xr-xmit-pthreads/pg++32
-rwxr-xr-xmit-pthreads/pgcc32
-rw-r--r--mit-pthreads/pthreads/GNUmakefile.inc46
-rw-r--r--mit-pthreads/pthreads/Makefile.inc75
-rw-r--r--mit-pthreads/pthreads/_exit.c80
-rw-r--r--mit-pthreads/pthreads/cleanup.c84
-rw-r--r--mit-pthreads/pthreads/cond.c437
-rw-r--r--mit-pthreads/pthreads/condattr.c90
-rw-r--r--mit-pthreads/pthreads/dump_state.c88
-rw-r--r--mit-pthreads/pthreads/errno.c53
-rw-r--r--mit-pthreads/pthreads/fd.c1083
-rw-r--r--mit-pthreads/pthreads/fd_kern.c1950
-rw-r--r--mit-pthreads/pthreads/fd_pipe.c257
-rw-r--r--mit-pthreads/pthreads/fd_sysv.c897
-rw-r--r--mit-pthreads/pthreads/file.c129
-rw-r--r--mit-pthreads/pthreads/globals.c85
-rw-r--r--mit-pthreads/pthreads/info.c77
-rw-r--r--mit-pthreads/pthreads/init.cc9
-rw-r--r--mit-pthreads/pthreads/malloc.c383
-rw-r--r--mit-pthreads/pthreads/mutex.c371
-rw-r--r--mit-pthreads/pthreads/mutexattr.c90
-rw-r--r--mit-pthreads/pthreads/panic.c58
-rw-r--r--mit-pthreads/pthreads/prio_queue.c176
-rw-r--r--mit-pthreads/pthreads/process.c208
-rw-r--r--mit-pthreads/pthreads/pthread.c293
-rw-r--r--mit-pthreads/pthreads/pthread_attr.c255
-rw-r--r--mit-pthreads/pthreads/pthread_cancel.c258
-rw-r--r--mit-pthreads/pthreads/pthread_detach.c92
-rw-r--r--mit-pthreads/pthreads/pthread_init.c135
-rw-r--r--mit-pthreads/pthreads/pthread_join.c139
-rw-r--r--mit-pthreads/pthreads/pthread_kill.c93
-rw-r--r--mit-pthreads/pthreads/pthread_once.c59
-rw-r--r--mit-pthreads/pthreads/queue.c143
-rw-r--r--mit-pthreads/pthreads/readv.c85
-rw-r--r--mit-pthreads/pthreads/schedparam.c170
-rw-r--r--mit-pthreads/pthreads/select.c255
-rw-r--r--mit-pthreads/pthreads/sig.c452
-rw-r--r--mit-pthreads/pthreads/signal.c653
-rw-r--r--mit-pthreads/pthreads/sleep.c367
-rw-r--r--mit-pthreads/pthreads/specific.c198
-rw-r--r--mit-pthreads/pthreads/stat.c116
-rw-r--r--mit-pthreads/pthreads/wait.c159
-rw-r--r--mit-pthreads/pthreads/wrapper.c149
-rw-r--r--mit-pthreads/pthreads/writev.c89
-rwxr-xr-xmit-pthreads/scripts/GNUmakefile.inc24
-rw-r--r--mit-pthreads/scripts/Makefile.inc30
-rwxr-xr-xmit-pthreads/scripts/pgcc.sh32
-rwxr-xr-xmit-pthreads/stdio/GNUmakefile.inc26
-rw-r--r--mit-pthreads/stdio/Makefile.inc20
-rwxr-xr-xmit-pthreads/stdio/README41
-rw-r--r--mit-pthreads/stdio/clrerr.c51
-rw-r--r--mit-pthreads/stdio/fclose.c73
-rw-r--r--mit-pthreads/stdio/fdopen.c93
-rw-r--r--mit-pthreads/stdio/feof.c55
-rw-r--r--mit-pthreads/stdio/ferror.c55
-rw-r--r--mit-pthreads/stdio/fflush.c98
-rw-r--r--mit-pthreads/stdio/fgetc.c65
-rw-r--r--mit-pthreads/stdio/fgetline.c170
-rw-r--r--mit-pthreads/stdio/fgetpos.c85
-rw-r--r--mit-pthreads/stdio/fgets.c110
-rw-r--r--mit-pthreads/stdio/fileno.c55
-rw-r--r--mit-pthreads/stdio/findfp.c161
-rw-r--r--mit-pthreads/stdio/flags.c93
-rw-r--r--mit-pthreads/stdio/floatio.h47
-rw-r--r--mit-pthreads/stdio/fopen.c90
-rw-r--r--mit-pthreads/stdio/fprintf.c71
-rw-r--r--mit-pthreads/stdio/fpurge.c73
-rw-r--r--mit-pthreads/stdio/fputc.c73
-rw-r--r--mit-pthreads/stdio/fputs.c67
-rw-r--r--mit-pthreads/stdio/fread.c84
-rw-r--r--mit-pthreads/stdio/freopen.c149
-rw-r--r--mit-pthreads/stdio/fscanf.c73
-rw-r--r--mit-pthreads/stdio/fseek.c248
-rw-r--r--mit-pthreads/stdio/fsetpos.c54
-rw-r--r--mit-pthreads/stdio/ftell.c90
-rw-r--r--mit-pthreads/stdio/funopen.c105
-rw-r--r--mit-pthreads/stdio/fvwrite.c190
-rw-r--r--mit-pthreads/stdio/fvwrite.h54
-rw-r--r--mit-pthreads/stdio/fwalk.c132
-rw-r--r--mit-pthreads/stdio/fwrite.c80
-rw-r--r--mit-pthreads/stdio/getc.c58
-rw-r--r--mit-pthreads/stdio/getc_unlocked.c55
-rw-r--r--mit-pthreads/stdio/getchar.c58
-rw-r--r--mit-pthreads/stdio/getchar_unlocked.c54
-rw-r--r--mit-pthreads/stdio/gets.c71
-rw-r--r--mit-pthreads/stdio/getw.c51
-rw-r--r--mit-pthreads/stdio/glue.h49
-rw-r--r--mit-pthreads/stdio/local.h90
-rw-r--r--mit-pthreads/stdio/makebuf.c122
-rw-r--r--mit-pthreads/stdio/mktemp.c126
-rw-r--r--mit-pthreads/stdio/perror.c67
-rw-r--r--mit-pthreads/stdio/printf.c56
-rw-r--r--mit-pthreads/stdio/putc.c60
-rw-r--r--mit-pthreads/stdio/putc_unlocked.c56
-rw-r--r--mit-pthreads/stdio/putchar.c60
-rw-r--r--mit-pthreads/stdio/putchar_unlocked.c56
-rw-r--r--mit-pthreads/stdio/puts.c71
-rw-r--r--mit-pthreads/stdio/putw.c64
-rw-r--r--mit-pthreads/stdio/refill.c189
-rw-r--r--mit-pthreads/stdio/remove.c50
-rw-r--r--mit-pthreads/stdio/rewind.c55
-rw-r--r--mit-pthreads/stdio/rget.c58
-rw-r--r--mit-pthreads/stdio/scanf.c72
-rw-r--r--mit-pthreads/stdio/setbuf.c52
-rw-r--r--mit-pthreads/stdio/setbuffer.c64
-rw-r--r--mit-pthreads/stdio/setvbuf.c154
-rw-r--r--mit-pthreads/stdio/snprintf.c79
-rw-r--r--mit-pthreads/stdio/sprintf.c78
-rw-r--r--mit-pthreads/stdio/sscanf.c79
-rw-r--r--mit-pthreads/stdio/stdio.c104
-rw-r--r--mit-pthreads/stdio/strerror.c67
-rw-r--r--mit-pthreads/stdio/tempnam.c87
-rw-r--r--mit-pthreads/stdio/tmpfile.c80
-rw-r--r--mit-pthreads/stdio/tmpnam.c55
-rw-r--r--mit-pthreads/stdio/ungetc.c155
-rw-r--r--mit-pthreads/stdio/vfprintf.c788
-rw-r--r--mit-pthreads/stdio/vfscanf.c750
-rw-r--r--mit-pthreads/stdio/vprintf.c51
-rw-r--r--mit-pthreads/stdio/vscanf.c55
-rw-r--r--mit-pthreads/stdio/vsnprintf.c65
-rw-r--r--mit-pthreads/stdio/vsprintf.c62
-rw-r--r--mit-pthreads/stdio/vsscanf.c62
-rw-r--r--mit-pthreads/stdio/wbuf.c89
-rw-r--r--mit-pthreads/stdio/wsetup.c91
-rw-r--r--mit-pthreads/stdio/xprintf.c883
-rwxr-xr-xmit-pthreads/stdlib/GNUmakefile.inc7
-rw-r--r--mit-pthreads/stdlib/Makefile.inc10
-rw-r--r--mit-pthreads/stdlib/abort.c67
-rw-r--r--mit-pthreads/stdlib/atexit.h46
-rw-r--r--mit-pthreads/stdlib/exit.c89
-rw-r--r--mit-pthreads/stdlib/getopt.c135
-rw-r--r--mit-pthreads/stdlib/rand.c64
-rw-r--r--mit-pthreads/stdlib/random.c389
-rw-r--r--mit-pthreads/stdlib/strtod.c178
-rw-r--r--mit-pthreads/stdlib/strtol.c131
-rw-r--r--mit-pthreads/stdlib/strtoul.c109
-rw-r--r--mit-pthreads/stdlib/system.c83
-rwxr-xr-xmit-pthreads/string/GNUmakefile.inc7
-rw-r--r--mit-pthreads/string/Makefile.inc8
-rw-r--r--mit-pthreads/string/strtok.c119
-rw-r--r--mit-pthreads/tests/.cvsignore1
-rw-r--r--mit-pthreads/tests/Makefile.in164
-rwxr-xr-xmit-pthreads/tests/README26
-rw-r--r--mit-pthreads/tests/bench_fcntl.c82
-rw-r--r--mit-pthreads/tests/bench_pipe.c115
-rw-r--r--mit-pthreads/tests/bench_read.c88
-rw-r--r--mit-pthreads/tests/p_bench_getpid.c78
-rw-r--r--mit-pthreads/tests/p_bench_mutex.c78
-rw-r--r--mit-pthreads/tests/p_bench_pthread_create.c92
-rw-r--r--mit-pthreads/tests/p_bench_read.c103
-rw-r--r--mit-pthreads/tests/p_bench_semaphore.c82
-rw-r--r--mit-pthreads/tests/p_bench_yield.c123
-rw-r--r--mit-pthreads/tests/test_create.c35
-rw-r--r--mit-pthreads/tests/test_cwd.c11
-rw-r--r--mit-pthreads/tests/test_execve.c57
-rw-r--r--mit-pthreads/tests/test_fcntl.c32
-rw-r--r--mit-pthreads/tests/test_fork.c60
-rw-r--r--mit-pthreads/tests/test_netdb.c110
-rw-r--r--mit-pthreads/tests/test_pause.c19
-rw-r--r--mit-pthreads/tests/test_preemption.c38
-rw-r--r--mit-pthreads/tests/test_preemption_float.c98
-rw-r--r--mit-pthreads/tests/test_pthread_cond_timedwait.c93
-rw-r--r--mit-pthreads/tests/test_pthread_join.c78
-rw-r--r--mit-pthreads/tests/test_pthread_mutex.c221
-rw-r--r--mit-pthreads/tests/test_pw.c20
-rw-r--r--mit-pthreads/tests/test_readdir.c42
-rw-r--r--mit-pthreads/tests/test_select.c115
-rw-r--r--mit-pthreads/tests/test_setjmp.c13
-rw-r--r--mit-pthreads/tests/test_sleep.c46
-rw-r--r--mit-pthreads/tests/test_sock_1.c204
-rw-r--r--mit-pthreads/tests/test_sock_2.c116
-rw-r--r--mit-pthreads/tests/test_sock_2a.c87
-rw-r--r--mit-pthreads/tests/test_stdio_1.c124
-rw-r--r--mit-pthreads/tests/test_switch.c97
-rwxr-xr-xmkinstalldirs38
-rw-r--r--myisam/.cvsignore12
-rw-r--r--myisam/Attic/ft_global.h52
-rw-r--r--myisam/ChangeLog137
-rw-r--r--myisam/Makefile.am107
-rw-r--r--myisam/NEWS66
-rw-r--r--myisam/TODO7
-rw-r--r--myisam/ft_eval.c208
-rw-r--r--myisam/ft_eval.h46
-rw-r--r--myisam/ft_parser.c152
-rw-r--r--myisam/ft_search.c223
-rw-r--r--myisam/ft_static.c627
-rw-r--r--myisam/ft_stem.c20
-rw-r--r--myisam/ft_stopwords.c68
-rw-r--r--myisam/ft_test1.c265
-rw-r--r--myisam/ft_test1.h422
-rw-r--r--myisam/ft_update.c189
-rw-r--r--myisam/ftdefs.h99
-rw-r--r--myisam/fulltext.h42
-rwxr-xr-xmyisam/make-ccc5
-rw-r--r--myisam/mi_cache.c101
-rw-r--r--myisam/mi_changed.c34
-rw-r--r--myisam/mi_check.c2886
-rw-r--r--myisam/mi_checksum.c67
-rw-r--r--myisam/mi_close.c105
-rw-r--r--myisam/mi_create.c628
-rw-r--r--myisam/mi_dbug.c149
-rw-r--r--myisam/mi_delete.c780
-rw-r--r--myisam/mi_delete_all.c65
-rw-r--r--myisam/mi_delete_table.c53
-rw-r--r--myisam/mi_dynrec.c1537
-rw-r--r--myisam/mi_extra.c324
-rw-r--r--myisam/mi_info.c102
-rw-r--r--myisam/mi_key.c411
-rw-r--r--myisam/mi_locking.c456
-rw-r--r--myisam/mi_log.c158
-rw-r--r--myisam/mi_open.c994
-rw-r--r--myisam/mi_packrec.c1312
-rw-r--r--myisam/mi_page.c144
-rw-r--r--myisam/mi_panic.c111
-rw-r--r--myisam/mi_range.c199
-rw-r--r--myisam/mi_rename.c56
-rw-r--r--myisam/mi_rfirst.c27
-rw-r--r--myisam/mi_rkey.c89
-rw-r--r--myisam/mi_rlast.c27
-rw-r--r--myisam/mi_rnext.c84
-rw-r--r--myisam/mi_rnext_same.c79
-rw-r--r--myisam/mi_rprev.c82
-rw-r--r--myisam/mi_rrnd.c57
-rw-r--r--myisam/mi_rsame.c65
-rw-r--r--myisam/mi_rsamepos.c56
-rw-r--r--myisam/mi_scan.c46
-rw-r--r--myisam/mi_search.c1877
-rw-r--r--myisam/mi_static.c56
-rw-r--r--myisam/mi_statrec.c302
-rw-r--r--myisam/mi_test1.c640
-rw-r--r--myisam/mi_test2.c973
-rw-r--r--myisam/mi_test3.c485
-rw-r--r--myisam/mi_test_all.res48
-rwxr-xr-xmyisam/mi_test_all.sh120
-rw-r--r--myisam/mi_unique.c188
-rw-r--r--myisam/mi_update.c184
-rw-r--r--myisam/mi_write.c684
-rw-r--r--myisam/myisamchk.c1365
-rw-r--r--myisam/myisamdef.h621
-rw-r--r--myisam/myisamlog.c832
-rw-r--r--myisam/myisampack.c2140
-rw-r--r--myisam/sort.c531
-rwxr-xr-xmyisam/test_pack9
-rw-r--r--myisammrg/.cvsignore3
-rw-r--r--myisammrg/Makefile.am31
-rwxr-xr-xmyisammrg/make-ccc3
-rw-r--r--myisammrg/mymrgdef.h29
-rw-r--r--myisammrg/myrg_close.c40
-rw-r--r--myisammrg/myrg_create.c61
-rw-r--r--myisammrg/myrg_delete.c30
-rw-r--r--myisammrg/myrg_extra.c46
-rw-r--r--myisammrg/myrg_info.c59
-rw-r--r--myisammrg/myrg_locking.c35
-rw-r--r--myisammrg/myrg_open.c139
-rw-r--r--myisammrg/myrg_panic.c47
-rw-r--r--myisammrg/myrg_rrnd.c110
-rw-r--r--myisammrg/myrg_rsame.c30
-rw-r--r--myisammrg/myrg_static.c26
-rw-r--r--myisammrg/myrg_update.c26
-rwxr-xr-xmysql-test/mybin/mysql-test_install_db215
-rwxr-xr-xmysql-test/mysql-test-run262
-rw-r--r--mysql.projbin0 -> 118784 bytes
-rw-r--r--mysys/.cvsignore10
-rwxr-xr-xmysys/COPYING.LIB481
-rw-r--r--mysys/ChangeLog221
-rw-r--r--mysys/Makefile.am93
-rw-r--r--mysys/array.c177
-rw-r--r--mysys/charset.c532
-rw-r--r--mysys/checksum.c30
-rw-r--r--mysys/default.c362
-rw-r--r--mysys/errors.c84
-rw-r--r--mysys/getopt.c744
-rw-r--r--mysys/getopt1.c170
-rw-r--r--mysys/getvar.c105
-rw-r--r--mysys/hash.c586
-rw-r--r--mysys/list.c116
-rwxr-xr-xmysys/make-ccc4
-rw-r--r--mysys/make-conf.c73
-rw-r--r--mysys/mf_brkhant.c76
-rw-r--r--mysys/mf_cache.c83
-rw-r--r--mysys/mf_casecnv.c252
-rw-r--r--mysys/mf_dirname.c106
-rw-r--r--mysys/mf_fn_ext.c46
-rw-r--r--mysys/mf_format.c146
-rw-r--r--mysys/mf_getdate.c59
-rw-r--r--mysys/mf_iocache.c603
-rw-r--r--mysys/mf_keycache.c753
-rw-r--r--mysys/mf_loadpath.c54
-rw-r--r--mysys/mf_pack.c528
-rw-r--r--mysys/mf_pack2.c53
-rw-r--r--mysys/mf_path.c120
-rw-r--r--mysys/mf_qsort.c258
-rw-r--r--mysys/mf_qsort2.c21
-rw-r--r--mysys/mf_radix.c56
-rw-r--r--mysys/mf_same.c38
-rw-r--r--mysys/mf_sleep.c36
-rw-r--r--mysys/mf_sort.c43
-rw-r--r--mysys/mf_soundex.c102
-rw-r--r--mysys/mf_stripp.c47
-rw-r--r--mysys/mf_unixpath.c33
-rw-r--r--mysys/mf_util.c49
-rw-r--r--mysys/mf_wcomp.c68
-rw-r--r--mysys/mf_wfile.c132
-rw-r--r--mysys/mulalloc.c53
-rw-r--r--mysys/my_alarm.c34
-rw-r--r--mysys/my_alloc.c129
-rw-r--r--mysys/my_append.c66
-rw-r--r--mysys/my_chsize.c86
-rw-r--r--mysys/my_clock.c35
-rw-r--r--mysys/my_compress.c87
-rw-r--r--mysys/my_copy.c103
-rw-r--r--mysys/my_create.c84
-rw-r--r--mysys/my_delete.c36
-rw-r--r--mysys/my_div.c31
-rw-r--r--mysys/my_error.c122
-rw-r--r--mysys/my_fopen.c165
-rw-r--r--mysys/my_fstream.c170
-rw-r--r--mysys/my_getwd.c182
-rw-r--r--mysys/my_init.c301
-rw-r--r--mysys/my_lib.c607
-rw-r--r--mysys/my_lock.c161
-rw-r--r--mysys/my_lockmem.c101
-rw-r--r--mysys/my_lread.c54
-rw-r--r--mysys/my_lwrite.c47
-rw-r--r--mysys/my_malloc.c84
-rw-r--r--mysys/my_messnc.c36
-rw-r--r--mysys/my_mkdir.c44
-rw-r--r--mysys/my_net.c49
-rw-r--r--mysys/my_once.c88
-rw-r--r--mysys/my_open.c97
-rw-r--r--mysys/my_pread.c137
-rw-r--r--mysys/my_pthread.c476
-rw-r--r--mysys/my_quick.c45
-rw-r--r--mysys/my_read.c66
-rw-r--r--mysys/my_realloc.c65
-rw-r--r--mysys/my_redel.c98
-rw-r--r--mysys/my_rename.c60
-rw-r--r--mysys/my_seek.c57
-rw-r--r--mysys/my_static.c100
-rw-r--r--mysys/my_static.h82
-rw-r--r--mysys/my_tempnam.c142
-rw-r--r--mysys/my_thr_init.c194
-rw-r--r--mysys/my_vsnprintf.c94
-rw-r--r--mysys/my_wincond.c141
-rw-r--r--mysys/my_winthread.c111
-rw-r--r--mysys/my_write.c77
-rw-r--r--mysys/mysys_priv.h31
-rw-r--r--mysys/ptr_cmp.c158
-rw-r--r--mysys/queues.c141
-rw-r--r--mysys/raid.cc809
-rw-r--r--mysys/safemalloc.c518
-rw-r--r--mysys/string.c117
-rw-r--r--mysys/test_charset.c59
-rw-r--r--mysys/test_dir.c50
-rw-r--r--mysys/test_fn.c70
-rw-r--r--mysys/test_vsnprintf.c45
-rw-r--r--mysys/testhash.c291
-rw-r--r--mysys/thr_alarm.c874
-rw-r--r--mysys/thr_lock.c1288
-rw-r--r--mysys/thr_mutex.c214
-rw-r--r--mysys/thr_rwlock.c139
-rw-r--r--mysys/tree.c513
-rw-r--r--mysys/typelib.c106
-rw-r--r--readline/.cvsignore3
-rw-r--r--readline/COPYING339
-rw-r--r--readline/INSTALL176
-rw-r--r--readline/Makefile.am29
-rw-r--r--readline/README163
-rw-r--r--readline/ansi_stdlib.h41
-rw-r--r--readline/bind.c1996
-rw-r--r--readline/callback.c149
-rw-r--r--readline/chardefs.h142
-rw-r--r--readline/complete.c1755
-rwxr-xr-xreadline/configure2849
-rw-r--r--readline/configure.in143
-rw-r--r--readline/display.c1573
-rw-r--r--readline/emacs_keymap.c885
-rw-r--r--readline/funmap.c254
-rw-r--r--readline/histexpand.c1359
-rw-r--r--readline/histfile.c376
-rw-r--r--readline/histlib.h82
-rw-r--r--readline/history.c388
-rw-r--r--readline/history.h248
-rw-r--r--readline/histsearch.c200
-rw-r--r--readline/input.c459
-rw-r--r--readline/isearch.c449
-rw-r--r--readline/keymaps.c150
-rw-r--r--readline/keymaps.h100
-rw-r--r--readline/kill.c639
-rw-r--r--readline/macro.c277
-rw-r--r--readline/nls.c228
-rw-r--r--readline/parens.c156
-rw-r--r--readline/posixdir.h49
-rw-r--r--readline/posixjmp.h22
-rw-r--r--readline/posixstat.h142
-rw-r--r--readline/readline.c2156
-rw-r--r--readline/readline.h621
-rw-r--r--readline/rlconf.h61
-rw-r--r--readline/rldefs.h135
-rw-r--r--readline/rlstdc.h79
-rw-r--r--readline/rltty.c727
-rw-r--r--readline/rltty.h63
-rw-r--r--readline/rlwinsize.h58
-rw-r--r--readline/search.c377
-rw-r--r--readline/shell.c133
-rw-r--r--readline/signals.c394
-rw-r--r--readline/tcap.h60
-rw-r--r--readline/terminal.c555
-rw-r--r--readline/tilde.c438
-rw-r--r--readline/tilde.h65
-rw-r--r--readline/undo.c260
-rw-r--r--readline/util.c365
-rw-r--r--readline/vi_keymap.c877
-rw-r--r--readline/vi_mode.c1385
-rw-r--r--readline/xmalloc.c87
-rw-r--r--regex/.cvsignore5
-rw-r--r--regex/CHANGES19
-rw-r--r--regex/COPYRIGHT20
-rw-r--r--regex/Makefile.am42
-rw-r--r--regex/README32
-rw-r--r--regex/WHATSNEW92
-rw-r--r--regex/cclass.h21
-rw-r--r--regex/cname.h102
-rw-r--r--regex/debug.c243
-rw-r--r--regex/debug.ih14
-rw-r--r--regex/engine.c1026
-rw-r--r--regex/engine.ih35
-rw-r--r--regex/main.c509
-rw-r--r--regex/main.ih19
-rwxr-xr-xregex/make-ccc3
-rw-r--r--regex/regcomp.c1627
-rw-r--r--regex/regcomp.ih51
-rw-r--r--regex/regerror.c120
-rw-r--r--regex/regerror.ih12
-rw-r--r--regex/regex.3502
-rw-r--r--regex/regex.7233
-rw-r--r--regex/regex.h79
-rw-r--r--regex/regex2.h145
-rw-r--r--regex/regexec.c139
-rw-r--r--regex/regexp.c1348
-rw-r--r--regex/regfree.c38
-rw-r--r--regex/reginit.c71
-rw-r--r--regex/split.c316
-rw-r--r--regex/tests474
-rw-r--r--regex/utils.h22
-rw-r--r--repl-tests/include/master-slave.inc2
-rw-r--r--repl-tests/test-dump/run.test17
-rw-r--r--repl-tests/test-dump/table-dump-check.master2
-rw-r--r--repl-tests/test-dump/table-dump-select.master2
-rw-r--r--repl-tests/test-repl-ts/repl-timestamp.master2
-rw-r--r--repl-tests/test-repl-ts/run.test17
-rw-r--r--repl-tests/test-repl/foo-dump-master.master3
-rw-r--r--repl-tests/test-repl/foo-dump-slave.master3
-rwxr-xr-xrepl-tests/test-repl/run.test24
-rw-r--r--repl-tests/test-repl/sum-wlen-master.master2
-rw-r--r--repl-tests/test-repl/sum-wlen-slave.master2
-rw-r--r--scripts/.cvsignore15
-rw-r--r--scripts/Makefile.am104
-rwxr-xr-xscripts/make_binary_distribution.sh131
-rw-r--r--scripts/msql2mysql.sh16
-rw-r--r--scripts/mysql_config.sh74
-rwxr-xr-xscripts/mysql_convert_table_format.sh114
-rwxr-xr-xscripts/mysql_find_rows.sh148
-rw-r--r--scripts/mysql_fix_privilege_tables.sh110
-rw-r--r--scripts/mysql_install_db.sh342
-rwxr-xr-xscripts/mysql_setpermission.sh669
-rwxr-xr-xscripts/mysql_zap.sh156
-rwxr-xr-xscripts/mysqlaccess.conf45
-rwxr-xr-xscripts/mysqlaccess.sh3248
-rwxr-xr-xscripts/mysqlbug.sh380
-rwxr-xr-xscripts/mysqlhotcopy.sh591
-rwxr-xr-xscripts/safe_mysqld-watch.sh149
-rwxr-xr-xscripts/safe_mysqld.sh188
-rw-r--r--sql-bench/.cvsignore18
-rw-r--r--sql-bench/ChangeLog16
-rw-r--r--sql-bench/Data/ATIS/aircraft.txt135
-rw-r--r--sql-bench/Data/ATIS/airline.txt314
-rw-r--r--sql-bench/Data/ATIS/airport.txt9
-rw-r--r--sql-bench/Data/ATIS/airport_service.txt14
-rw-r--r--sql-bench/Data/ATIS/city.txt11
-rw-r--r--sql-bench/Data/ATIS/class_of_service.txt27
-rw-r--r--sql-bench/Data/ATIS/code_description.txt15
-rw-r--r--sql-bench/Data/ATIS/compound_class.txt149
-rw-r--r--sql-bench/Data/ATIS/connect_leg.txt351
-rw-r--r--sql-bench/Data/ATIS/connection.txt164
-rw-r--r--sql-bench/Data/ATIS/date_day.txt1826
-rw-r--r--sql-bench/Data/ATIS/day_name.txt7
-rw-r--r--sql-bench/Data/ATIS/dual_carrier.txt114
-rw-r--r--sql-bench/Data/ATIS/fare.txt534
-rw-r--r--sql-bench/Data/ATIS/flight.txt579
-rw-r--r--sql-bench/Data/ATIS/flight_class.txt2895
-rw-r--r--sql-bench/Data/ATIS/flight_day.txt448
-rw-r--r--sql-bench/Data/ATIS/flight_fare.txt2998
-rw-r--r--sql-bench/Data/ATIS/food_service.txt121
-rw-r--r--sql-bench/Data/ATIS/ground_service.txt33
-rw-r--r--sql-bench/Data/ATIS/month_name.txt12
-rw-r--r--sql-bench/Data/ATIS/restrict_carrier.txt612
-rw-r--r--sql-bench/Data/ATIS/restrict_class.txt4
-rw-r--r--sql-bench/Data/ATIS/restriction.txt65
-rw-r--r--sql-bench/Data/ATIS/state.txt63
-rw-r--r--sql-bench/Data/ATIS/stop.txt69
-rw-r--r--sql-bench/Data/ATIS/stop1.txt69
-rw-r--r--sql-bench/Data/ATIS/time_interval.txt12
-rw-r--r--sql-bench/Data/ATIS/time_zone.txt9
-rw-r--r--sql-bench/Data/ATIS/transport.txt4
-rw-r--r--sql-bench/Data/Wisconsin/onek.data1000
-rw-r--r--sql-bench/Data/Wisconsin/tenk.data10000
-rw-r--r--sql-bench/Makefile.am79
-rwxr-xr-xsql-bench/README97
-rw-r--r--sql-bench/Results-win32/ATIS-access_odbc-win98-cmp-access,mysql19
-rw-r--r--sql-bench/Results-win32/ATIS-db2_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase19
-rw-r--r--sql-bench/Results-win32/ATIS-informix_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase19
-rw-r--r--sql-bench/Results-win32/ATIS-ms-sql_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase19
-rw-r--r--sql-bench/Results-win32/ATIS-mysql-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase19
-rw-r--r--sql-bench/Results-win32/ATIS-mysql-win9819
-rw-r--r--sql-bench/Results-win32/ATIS-mysql-win98-cmp-access,mysql19
-rw-r--r--sql-bench/Results-win32/ATIS-mysql_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase19
-rw-r--r--sql-bench/Results-win32/ATIS-oracle_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase19
-rw-r--r--sql-bench/Results-win32/ATIS-solid_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase22
-rw-r--r--sql-bench/Results-win32/ATIS-sybase_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase19
-rw-r--r--sql-bench/Results-win32/RUN-access_odbc-win98-cmp-access,mysql68
-rw-r--r--sql-bench/Results-win32/RUN-db2_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase54
-rw-r--r--sql-bench/Results-win32/RUN-informix_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase60
-rw-r--r--sql-bench/Results-win32/RUN-ms-sql_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase60
-rw-r--r--sql-bench/Results-win32/RUN-mysql-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase60
-rw-r--r--sql-bench/Results-win32/RUN-mysql-win9874
-rw-r--r--sql-bench/Results-win32/RUN-mysql-win98-cmp-access,mysql67
-rw-r--r--sql-bench/Results-win32/RUN-mysql_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase60
-rw-r--r--sql-bench/Results-win32/RUN-oracle_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase59
-rw-r--r--sql-bench/Results-win32/RUN-solid_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase60
-rw-r--r--sql-bench/Results-win32/RUN-sybase_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase58
-rw-r--r--sql-bench/Results-win32/alter-table-access_odbc-win98-cmp-access,mysql16
-rw-r--r--sql-bench/Results-win32/alter-table-db2_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase10
-rw-r--r--sql-bench/Results-win32/alter-table-informix_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase14
-rw-r--r--sql-bench/Results-win32/alter-table-ms-sql_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase14
-rw-r--r--sql-bench/Results-win32/alter-table-mysql-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase14
-rw-r--r--sql-bench/Results-win32/alter-table-mysql-win9816
-rw-r--r--sql-bench/Results-win32/alter-table-mysql-win98-cmp-access,mysql16
-rw-r--r--sql-bench/Results-win32/alter-table-mysql_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase14
-rw-r--r--sql-bench/Results-win32/alter-table-oracle_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase14
-rw-r--r--sql-bench/Results-win32/alter-table-solid_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase14
-rw-r--r--sql-bench/Results-win32/alter-table-sybase_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase14
-rw-r--r--sql-bench/Results-win32/big-tables-access_odbc-win98-cmp-access,mysql19
-rw-r--r--sql-bench/Results-win32/big-tables-db2_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase19
-rw-r--r--sql-bench/Results-win32/big-tables-informix_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase19
-rw-r--r--sql-bench/Results-win32/big-tables-ms-sql_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase19
-rw-r--r--sql-bench/Results-win32/big-tables-mysql-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase19
-rw-r--r--sql-bench/Results-win32/big-tables-mysql-win9819
-rw-r--r--sql-bench/Results-win32/big-tables-mysql-win98-cmp-access,mysql19
-rw-r--r--sql-bench/Results-win32/big-tables-mysql_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase19
-rw-r--r--sql-bench/Results-win32/big-tables-oracle_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase19
-rw-r--r--sql-bench/Results-win32/big-tables-solid_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase19
-rw-r--r--sql-bench/Results-win32/big-tables-sybase_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase19
-rw-r--r--sql-bench/Results-win32/connect-access_odbc-win98-cmp-access,mysql33
-rw-r--r--sql-bench/Results-win32/connect-db2_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase6
-rw-r--r--sql-bench/Results-win32/connect-informix_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase21
-rw-r--r--sql-bench/Results-win32/connect-ms-sql_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase21
-rw-r--r--sql-bench/Results-win32/connect-mysql-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase21
-rw-r--r--sql-bench/Results-win32/connect-mysql-win9827
-rw-r--r--sql-bench/Results-win32/connect-mysql-win98-cmp-access,mysql27
-rw-r--r--sql-bench/Results-win32/connect-mysql_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase21
-rw-r--r--sql-bench/Results-win32/connect-oracle_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase21
-rw-r--r--sql-bench/Results-win32/connect-solid_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase21
-rw-r--r--sql-bench/Results-win32/connect-sybase_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase21
-rw-r--r--sql-bench/Results-win32/create-access_odbc-win98-cmp-access,mysql18
-rw-r--r--sql-bench/Results-win32/create-db2_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase20
-rw-r--r--sql-bench/Results-win32/create-informix_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase20
-rw-r--r--sql-bench/Results-win32/create-ms-sql_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase20
-rw-r--r--sql-bench/Results-win32/create-mysql-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase20
-rw-r--r--sql-bench/Results-win32/create-mysql-win9818
-rw-r--r--sql-bench/Results-win32/create-mysql-win98-cmp-access,mysql18
-rw-r--r--sql-bench/Results-win32/create-mysql_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase20
-rw-r--r--sql-bench/Results-win32/create-oracle_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase20
-rw-r--r--sql-bench/Results-win32/create-solid_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase20
-rw-r--r--sql-bench/Results-win32/create-sybase_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase20
-rw-r--r--sql-bench/Results-win32/insert-access_odbc-win98-cmp-access,mysql67
-rw-r--r--sql-bench/Results-win32/insert-db2_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase99
-rw-r--r--sql-bench/Results-win32/insert-informix_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase102
-rw-r--r--sql-bench/Results-win32/insert-ms-sql_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase57
-rw-r--r--sql-bench/Results-win32/insert-mysql-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase81
-rw-r--r--sql-bench/Results-win32/insert-mysql-win9872
-rw-r--r--sql-bench/Results-win32/insert-mysql-win98-cmp-access,mysql64
-rw-r--r--sql-bench/Results-win32/insert-mysql_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase81
-rw-r--r--sql-bench/Results-win32/insert-oracle_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase69
-rw-r--r--sql-bench/Results-win32/insert-solid_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase102
-rw-r--r--sql-bench/Results-win32/insert-sybase_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase99
-rw-r--r--sql-bench/Results-win32/select-access_odbc-win98-cmp-access,mysql19
-rw-r--r--sql-bench/Results-win32/select-db2_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase22
-rw-r--r--sql-bench/Results-win32/select-informix_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase19
-rw-r--r--sql-bench/Results-win32/select-ms-sql_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase19
-rw-r--r--sql-bench/Results-win32/select-mysql-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase19
-rw-r--r--sql-bench/Results-win32/select-mysql-win9816
-rw-r--r--sql-bench/Results-win32/select-mysql-win98-cmp-access,mysql19
-rw-r--r--sql-bench/Results-win32/select-mysql_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase19
-rw-r--r--sql-bench/Results-win32/select-oracle_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase22
-rw-r--r--sql-bench/Results-win32/select-solid_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase22
-rw-r--r--sql-bench/Results-win32/wisconsin-access_odbc-win98-cmp-access,mysql14
-rw-r--r--sql-bench/Results-win32/wisconsin-db2_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase14
-rw-r--r--sql-bench/Results-win32/wisconsin-informix_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase14
-rw-r--r--sql-bench/Results-win32/wisconsin-ms-sql_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase14
-rw-r--r--sql-bench/Results-win32/wisconsin-mysql-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase14
-rw-r--r--sql-bench/Results-win32/wisconsin-mysql-win9814
-rw-r--r--sql-bench/Results-win32/wisconsin-mysql-win98-cmp-access,mysql14
-rw-r--r--sql-bench/Results-win32/wisconsin-mysql_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase14
-rw-r--r--sql-bench/Results-win32/wisconsin-oracle_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase14
-rw-r--r--sql-bench/Results-win32/wisconsin-solid_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase14
-rw-r--r--sql-bench/Results/ATIS-Adabas-Linux_2.0.35_i686-cmp-adabas,mysql19
-rw-r--r--sql-bench/Results/ATIS-AdabasD-Linux_2.0.35_i686-cmp-adabasd,mysql19
-rw-r--r--sql-bench/Results/ATIS-msql-Linux_2.2.10_i686-cmp-msql,mysql18
-rw-r--r--sql-bench/Results/ATIS-mysql-3.21-Linux_2.2.1_i68619
-rw-r--r--sql-bench/Results/ATIS-mysql-HP_UX_B.10.20_9000_77819
-rw-r--r--sql-bench/Results/ATIS-mysql-Linux_2.0.35_i686-cmp-adabas,mysql19
-rw-r--r--sql-bench/Results/ATIS-mysql-Linux_2.0.36_i686-cmp-mysql,pg,solid19
-rw-r--r--sql-bench/Results/ATIS-mysql-Linux_2.2.10_i68619
-rw-r--r--sql-bench/Results/ATIS-mysql-Linux_2.2.10_i686-cmp-msql,mysql18
-rw-r--r--sql-bench/Results/ATIS-mysql-Linux_2.2.14_i686_xeon19
-rw-r--r--sql-bench/Results/ATIS-mysql-Linux_2.2.1_i686-cmp-adabas,mysql19
-rw-r--r--sql-bench/Results/ATIS-mysql-NT_4.019
-rw-r--r--sql-bench/Results/ATIS-mysql-SunOS_5.5.1_sun4u19
-rw-r--r--sql-bench/Results/ATIS-mysql-SunOS_5.7_sun4m19
-rw-r--r--sql-bench/Results/ATIS-mysql-SunOS_5.7_sun4u19
-rw-r--r--sql-bench/Results/ATIS-mysql-win9819
-rw-r--r--sql-bench/Results/ATIS-mysql_3.21-Linux_2.0.35_i68619
-rw-r--r--sql-bench/Results/ATIS-mysql_fast-Linux_2.2.10_i686-cmp-msql,mysql18
-rw-r--r--sql-bench/Results/ATIS-mysql_odbc-win9819
-rw-r--r--sql-bench/Results/ATIS-oracle-Linux_2.0.36_i686-cmp-mysql,oracle19
-rw-r--r--sql-bench/Results/ATIS-oracle_fast-Linux_2.0.36_i686-cmp-mysql,oracle25
-rw-r--r--sql-bench/Results/ATIS-pg-Linux_2.0.36_i686-cmp-mysql,pg,solid22
-rw-r--r--sql-bench/Results/ATIS-pg_fast-Linux_2.0.36_i686-cmp-mysql,pg,solid23
-rw-r--r--sql-bench/Results/ATIS-solid-Linux_2.0.36_i686-cmp-mysql,pg,solid19
-rw-r--r--sql-bench/Results/RUN-Adabas-Linux_2.0.35_i686-cmp-adabas,mysql60
-rw-r--r--sql-bench/Results/RUN-msql-Linux_2.2.10_i686-cmp-msql,mysql55
-rw-r--r--sql-bench/Results/RUN-mysql-3.21-Linux_2.2.1_i68661
-rw-r--r--sql-bench/Results/RUN-mysql-HP_UX_B.10.20_9000_77871
-rw-r--r--sql-bench/Results/RUN-mysql-Linux_2.0.35_i686-cmp-adabas,mysql60
-rw-r--r--sql-bench/Results/RUN-mysql-Linux_2.0.36_i686-cmp-mysql,pg,solid58
-rw-r--r--sql-bench/Results/RUN-mysql-Linux_2.2.10_i68671
-rw-r--r--sql-bench/Results/RUN-mysql-Linux_2.2.10_i686-cmp-msql,mysql55
-rw-r--r--sql-bench/Results/RUN-mysql-Linux_2.2.14_i686_xeon79
-rw-r--r--sql-bench/Results/RUN-mysql-Linux_2.2.1_i686-cmp-adabas,mysql60
-rw-r--r--sql-bench/Results/RUN-mysql-NT_4.078
-rw-r--r--sql-bench/Results/RUN-mysql-SunOS_5.5.1_sun4u62
-rw-r--r--sql-bench/Results/RUN-mysql-SunOS_5.7_sun4m62
-rw-r--r--sql-bench/Results/RUN-mysql-SunOS_5.7_sun4u72
-rw-r--r--sql-bench/Results/RUN-mysql-win9874
-rw-r--r--sql-bench/Results/RUN-mysql_3.21-Linux_2.0.35_i68659
-rw-r--r--sql-bench/Results/RUN-mysql_fast-Linux_2.2.10_i686-cmp-msql,mysql55
-rw-r--r--sql-bench/Results/RUN-mysql_odbc-win9862
-rw-r--r--sql-bench/Results/RUN-oracle-Linux_2.0.36_i686-cmp-mysql,oracle56
-rw-r--r--sql-bench/Results/RUN-oracle_fast-Linux_2.0.36_i686-cmp-mysql,oracle57
-rw-r--r--sql-bench/Results/RUN-pg-Linux_2.0.36_i686-cmp-mysql,pg,solid59
-rw-r--r--sql-bench/Results/RUN-pg_fast-Linux_2.0.36_i686-cmp-mysql,pg,solid60
-rw-r--r--sql-bench/Results/RUN-solid-Linux_2.0.36_i686-cmp-mysql,pg,solid59
-rw-r--r--sql-bench/Results/alter-table-Adabas-Linux_2.0.35_i686-cmp-adabas,mysql16
-rw-r--r--sql-bench/Results/alter-table-AdabasD-Linux_2.0.35_i686-cmp-adabasd,mysql16
-rw-r--r--sql-bench/Results/alter-table-msql-Linux_2.2.10_i686-cmp-msql,mysql6
-rw-r--r--sql-bench/Results/alter-table-mysql-3.21-Linux_2.2.1_i68616
-rw-r--r--sql-bench/Results/alter-table-mysql-HP_UX_B.10.20_9000_77816
-rw-r--r--sql-bench/Results/alter-table-mysql-Linux_2.0.35_i686-cmp-adabas,mysql16
-rw-r--r--sql-bench/Results/alter-table-mysql-Linux_2.0.36_i686-cmp-mysql,pg,solid14
-rw-r--r--sql-bench/Results/alter-table-mysql-Linux_2.2.10_i68616
-rw-r--r--sql-bench/Results/alter-table-mysql-Linux_2.2.10_i686-cmp-msql,mysql6
-rw-r--r--sql-bench/Results/alter-table-mysql-Linux_2.2.14_i686_xeon16
-rw-r--r--sql-bench/Results/alter-table-mysql-Linux_2.2.1_i686-cmp-adabas,mysql16
-rw-r--r--sql-bench/Results/alter-table-mysql-NT_4.016
-rw-r--r--sql-bench/Results/alter-table-mysql-SunOS_5.5.1_sun4u16
-rw-r--r--sql-bench/Results/alter-table-mysql-SunOS_5.7_sun4m16
-rw-r--r--sql-bench/Results/alter-table-mysql-SunOS_5.7_sun4u16
-rw-r--r--sql-bench/Results/alter-table-mysql-win9816
-rw-r--r--sql-bench/Results/alter-table-mysql_3.21-Linux_2.0.35_i68614
-rw-r--r--sql-bench/Results/alter-table-mysql_fast-Linux_2.2.10_i686-cmp-msql,mysql6
-rw-r--r--sql-bench/Results/alter-table-mysql_odbc-win9816
-rw-r--r--sql-bench/Results/alter-table-oracle-Linux_2.0.36_i686-cmp-mysql,oracle14
-rw-r--r--sql-bench/Results/alter-table-oracle_fast-Linux_2.0.36_i686-cmp-mysql,oracle14
-rw-r--r--sql-bench/Results/alter-table-pg-Linux_2.0.36_i686-cmp-mysql,pg,solid14
-rw-r--r--sql-bench/Results/alter-table-pg_fast-Linux_2.0.36_i686-cmp-mysql,pg,solid14
-rw-r--r--sql-bench/Results/alter-table-solid-Linux_2.0.36_i686-cmp-mysql,pg,solid14
-rw-r--r--sql-bench/Results/big-tables-Adabas-Linux_2.0.35_i686-cmp-adabas,mysql19
-rw-r--r--sql-bench/Results/big-tables-msql-Linux_2.2.10_i686-cmp-msql,mysql19
-rw-r--r--sql-bench/Results/big-tables-mysql-3.21-Linux_2.2.1_i68619
-rw-r--r--sql-bench/Results/big-tables-mysql-HP_UX_B.10.20_9000_77819
-rw-r--r--sql-bench/Results/big-tables-mysql-Linux_2.0.35_i686-cmp-adabas,mysql19
-rw-r--r--sql-bench/Results/big-tables-mysql-Linux_2.0.36_i686-cmp-mysql,pg,solid19
-rw-r--r--sql-bench/Results/big-tables-mysql-Linux_2.2.10_i68619
-rw-r--r--sql-bench/Results/big-tables-mysql-Linux_2.2.10_i686-cmp-msql,mysql19
-rw-r--r--sql-bench/Results/big-tables-mysql-Linux_2.2.14_i686_xeon19
-rw-r--r--sql-bench/Results/big-tables-mysql-Linux_2.2.1_i686-cmp-adabas,mysql19
-rw-r--r--sql-bench/Results/big-tables-mysql-NT_4.019
-rw-r--r--sql-bench/Results/big-tables-mysql-SunOS_5.5.1_sun4u19
-rw-r--r--sql-bench/Results/big-tables-mysql-SunOS_5.7_sun4m19
-rw-r--r--sql-bench/Results/big-tables-mysql-SunOS_5.7_sun4u19
-rw-r--r--sql-bench/Results/big-tables-mysql-win9819
-rw-r--r--sql-bench/Results/big-tables-mysql_3.21-Linux_2.0.35_i68619
-rw-r--r--sql-bench/Results/big-tables-mysql_fast-Linux_2.2.10_i686-cmp-msql,mysql19
-rw-r--r--sql-bench/Results/big-tables-mysql_odbc-win9819
-rw-r--r--sql-bench/Results/big-tables-oracle-Linux_2.0.36_i686-cmp-mysql,oracle19
-rw-r--r--sql-bench/Results/big-tables-oracle_fast-Linux_2.0.36_i686-cmp-mysql,oracle25
-rw-r--r--sql-bench/Results/big-tables-pg-Linux_2.0.36_i686-cmp-mysql,pg,solid19
-rw-r--r--sql-bench/Results/big-tables-pg_fast-Linux_2.0.36_i686-cmp-mysql,pg,solid25
-rw-r--r--sql-bench/Results/big-tables-solid-Linux_2.0.36_i686-cmp-mysql,pg,solid19
-rw-r--r--sql-bench/Results/connect-Adabas-Linux_2.0.35_i686-cmp-adabas,mysql21
-rw-r--r--sql-bench/Results/connect-msql-Linux_2.2.10_i686-cmp-msql,mysql21
-rw-r--r--sql-bench/Results/connect-mysql-3.21-Linux_2.2.1_i68627
-rw-r--r--sql-bench/Results/connect-mysql-HP_UX_B.10.20_9000_77827
-rw-r--r--sql-bench/Results/connect-mysql-Linux_2.0.35_i686-cmp-adabas,mysql21
-rw-r--r--sql-bench/Results/connect-mysql-Linux_2.0.36_i686-cmp-mysql,pg,solid21
-rw-r--r--sql-bench/Results/connect-mysql-Linux_2.2.10_i68627
-rw-r--r--sql-bench/Results/connect-mysql-Linux_2.2.10_i686-cmp-msql,mysql21
-rw-r--r--sql-bench/Results/connect-mysql-Linux_2.2.14_i686_xeon27
-rw-r--r--sql-bench/Results/connect-mysql-Linux_2.2.1_i686-cmp-adabas,mysql21
-rw-r--r--sql-bench/Results/connect-mysql-NT_4.030
-rw-r--r--sql-bench/Results/connect-mysql-SunOS_5.5.1_sun4u27
-rw-r--r--sql-bench/Results/connect-mysql-SunOS_5.7_sun4m27
-rw-r--r--sql-bench/Results/connect-mysql-SunOS_5.7_sun4u27
-rw-r--r--sql-bench/Results/connect-mysql-win9827
-rw-r--r--sql-bench/Results/connect-mysql_3.21-Linux_2.0.35_i68627
-rw-r--r--sql-bench/Results/connect-mysql_fast-Linux_2.2.10_i686-cmp-msql,mysql21
-rw-r--r--sql-bench/Results/connect-mysql_odbc-win9827
-rw-r--r--sql-bench/Results/connect-oracle-Linux_2.0.36_i686-cmp-mysql,oracle9
-rw-r--r--sql-bench/Results/connect-pg-Linux_2.0.36_i686-cmp-mysql,pg,solid21
-rw-r--r--sql-bench/Results/connect-pg_fast-Linux_2.0.36_i686-cmp-mysql,pg,solid29
-rw-r--r--sql-bench/Results/connect-solid-Linux_2.0.36_i686-cmp-mysql,pg,solid21
-rw-r--r--sql-bench/Results/create-Adabas-Linux_2.0.35_i686-cmp-adabas,mysql18
-rw-r--r--sql-bench/Results/create-msql-Linux_2.2.10_i686-cmp-msql,mysql20
-rw-r--r--sql-bench/Results/create-mysql-3.21-Linux_2.2.1_i68618
-rw-r--r--sql-bench/Results/create-mysql-HP_UX_B.10.20_9000_77818
-rw-r--r--sql-bench/Results/create-mysql-Linux_2.0.35_i686-cmp-adabas,mysql18
-rw-r--r--sql-bench/Results/create-mysql-Linux_2.0.36_i686-cmp-mysql,pg,solid20
-rw-r--r--sql-bench/Results/create-mysql-Linux_2.2.10_i68620
-rw-r--r--sql-bench/Results/create-mysql-Linux_2.2.10_i686-cmp-msql,mysql20
-rw-r--r--sql-bench/Results/create-mysql-Linux_2.2.14_i686_xeon18
-rw-r--r--sql-bench/Results/create-mysql-Linux_2.2.1_i686-cmp-adabas,mysql18
-rw-r--r--sql-bench/Results/create-mysql-NT_4.018
-rw-r--r--sql-bench/Results/create-mysql-SunOS_5.5.1_sun4u18
-rw-r--r--sql-bench/Results/create-mysql-SunOS_5.7_sun4m18
-rw-r--r--sql-bench/Results/create-mysql-SunOS_5.7_sun4u18
-rw-r--r--sql-bench/Results/create-mysql-win9818
-rw-r--r--sql-bench/Results/create-mysql_3.21-Linux_2.0.35_i68618
-rw-r--r--sql-bench/Results/create-mysql_fast-Linux_2.2.10_i686-cmp-msql,mysql20
-rw-r--r--sql-bench/Results/create-mysql_odbc-win9818
-rw-r--r--sql-bench/Results/create-oracle-Linux_2.0.36_i686-cmp-mysql,oracle20
-rw-r--r--sql-bench/Results/create-oracle_fast-Linux_2.0.36_i686-cmp-mysql,oracle30
-rw-r--r--sql-bench/Results/create-pg-Linux_2.0.36_i686-cmp-mysql,pg,solid56
-rw-r--r--sql-bench/Results/create-pg_fast-Linux_2.0.36_i686-cmp-mysql,pg,solid60
-rw-r--r--sql-bench/Results/create-solid-Linux_2.0.36_i686-cmp-mysql,pg,solid20
-rw-r--r--sql-bench/Results/insert-Adabas-Linux_2.0.35_i686-cmp-adabas,mysql63
-rw-r--r--sql-bench/Results/insert-msql-Linux_2.2.10_i686-cmp-msql,mysql67
-rw-r--r--sql-bench/Results/insert-mysql-3.21-Linux_2.2.1_i68651
-rw-r--r--sql-bench/Results/insert-mysql-HP_UX_B.10.20_9000_77881
-rw-r--r--sql-bench/Results/insert-mysql-Linux_2.0.35_i686-cmp-adabas,mysql51
-rw-r--r--sql-bench/Results/insert-mysql-Linux_2.0.36_i686-cmp-mysql,pg,solid51
-rw-r--r--sql-bench/Results/insert-mysql-Linux_2.2.10_i68672
-rw-r--r--sql-bench/Results/insert-mysql-Linux_2.2.10_i686-cmp-msql,mysql56
-rw-r--r--sql-bench/Results/insert-mysql-Linux_2.2.14_i686_xeon70
-rw-r--r--sql-bench/Results/insert-mysql-Linux_2.2.1_i686-cmp-adabas,mysql51
-rw-r--r--sql-bench/Results/insert-mysql-NT_4.070
-rw-r--r--sql-bench/Results/insert-mysql-SunOS_5.5.1_sun4u56
-rw-r--r--sql-bench/Results/insert-mysql-SunOS_5.7_sun4m68
-rw-r--r--sql-bench/Results/insert-mysql-SunOS_5.7_sun4u72
-rw-r--r--sql-bench/Results/insert-mysql-win9872
-rw-r--r--sql-bench/Results/insert-mysql_3.21-Linux_2.0.35_i68651
-rw-r--r--sql-bench/Results/insert-mysql_fast-Linux_2.2.10_i686-cmp-msql,mysql55
-rw-r--r--sql-bench/Results/insert-mysql_odbc-win9862
-rw-r--r--sql-bench/Results/insert-oracle-Linux_2.0.36_i686-cmp-mysql,oracle69
-rw-r--r--sql-bench/Results/insert-oracle_fast-Linux_2.0.36_i686-cmp-mysql,oracle101
-rw-r--r--sql-bench/Results/insert-pg-Linux_2.0.36_i686-cmp-mysql,pg,solid72
-rw-r--r--sql-bench/Results/insert-pg_fast-Linux_2.0.36_i686-cmp-mysql,pg,solid92
-rw-r--r--sql-bench/Results/insert-solid-Linux_2.0.36_i686-cmp-mysql,pg,solid63
-rw-r--r--sql-bench/Results/select-Adabas-Linux_2.0.35_i686-cmp-adabas,mysql22
-rw-r--r--sql-bench/Results/select-msql-Linux_2.2.10_i686-cmp-msql,mysql13
-rw-r--r--sql-bench/Results/select-mysql-3.21-Linux_2.2.1_i68622
-rw-r--r--sql-bench/Results/select-mysql-HP_UX_B.10.20_9000_77825
-rw-r--r--sql-bench/Results/select-mysql-Linux_2.0.35_i686-cmp-adabas,mysql19
-rw-r--r--sql-bench/Results/select-mysql-Linux_2.0.36_i686-cmp-mysql,pg,solid16
-rw-r--r--sql-bench/Results/select-mysql-Linux_2.2.10_i68616
-rw-r--r--sql-bench/Results/select-mysql-Linux_2.2.10_i686-cmp-msql,mysql13
-rw-r--r--sql-bench/Results/select-mysql-Linux_2.2.14_i686_xeon23
-rw-r--r--sql-bench/Results/select-mysql-Linux_2.2.1_i686-cmp-adabas,mysql19
-rw-r--r--sql-bench/Results/select-mysql-NT_4.023
-rw-r--r--sql-bench/Results/select-mysql-SunOS_5.5.1_sun4u19
-rw-r--r--sql-bench/Results/select-mysql-SunOS_5.7_sun4m25
-rw-r--r--sql-bench/Results/select-mysql-SunOS_5.7_sun4u16
-rw-r--r--sql-bench/Results/select-mysql-win9816
-rw-r--r--sql-bench/Results/select-mysql_3.21-Linux_2.0.35_i68622
-rw-r--r--sql-bench/Results/select-mysql_fast-Linux_2.2.10_i686-cmp-msql,mysql13
-rw-r--r--sql-bench/Results/select-mysql_odbc-win9819
-rw-r--r--sql-bench/Results/select-oracle-Linux_2.0.36_i686-cmp-mysql,oracle25
-rw-r--r--sql-bench/Results/select-oracle_fast-Linux_2.0.36_i686-cmp-mysql,oracle28
-rw-r--r--sql-bench/Results/select-pg-Linux_2.0.36_i686-cmp-mysql,pg,solid19
-rw-r--r--sql-bench/Results/select-pg_fast-Linux_2.0.36_i686-cmp-mysql,pg,solid25
-rw-r--r--sql-bench/Results/select-solid-Linux_2.0.36_i686-cmp-mysql,pg,solid19
-rw-r--r--sql-bench/Results/wisconsin-Adabas-Linux_2.0.35_i686-cmp-adabas,mysql14
-rw-r--r--sql-bench/Results/wisconsin-msql-Linux_2.2.10_i686-cmp-msql,mysql14
-rw-r--r--sql-bench/Results/wisconsin-mysql-3.21-Linux_2.2.1_i68614
-rw-r--r--sql-bench/Results/wisconsin-mysql-HP_UX_B.10.20_9000_77814
-rw-r--r--sql-bench/Results/wisconsin-mysql-Linux_2.0.35_i686-cmp-adabas,mysql14
-rw-r--r--sql-bench/Results/wisconsin-mysql-Linux_2.0.36_i686-cmp-mysql,pg,solid14
-rw-r--r--sql-bench/Results/wisconsin-mysql-Linux_2.2.10_i68614
-rw-r--r--sql-bench/Results/wisconsin-mysql-Linux_2.2.10_i686-cmp-msql,mysql14
-rw-r--r--sql-bench/Results/wisconsin-mysql-Linux_2.2.14_i686_xeon14
-rw-r--r--sql-bench/Results/wisconsin-mysql-Linux_2.2.1_i686-cmp-adabas,mysql14
-rw-r--r--sql-bench/Results/wisconsin-mysql-NT_4.014
-rw-r--r--sql-bench/Results/wisconsin-mysql-SunOS_5.5.1_sun4u14
-rw-r--r--sql-bench/Results/wisconsin-mysql-SunOS_5.7_sun4m14
-rw-r--r--sql-bench/Results/wisconsin-mysql-SunOS_5.7_sun4u14
-rw-r--r--sql-bench/Results/wisconsin-mysql-win9814
-rw-r--r--sql-bench/Results/wisconsin-mysql_3.21-Linux_2.0.35_i68614
-rw-r--r--sql-bench/Results/wisconsin-mysql_fast-Linux_2.2.10_i686-cmp-msql,mysql14
-rw-r--r--sql-bench/Results/wisconsin-mysql_odbc-win9814
-rw-r--r--sql-bench/Results/wisconsin-oracle-Linux_2.0.36_i686-cmp-mysql,oracle14
-rw-r--r--sql-bench/Results/wisconsin-oracle_fast-Linux_2.0.36_i686-cmp-mysql,oracle22
-rw-r--r--sql-bench/Results/wisconsin-pg-Linux_2.0.36_i686-cmp-mysql,pg,solid14
-rw-r--r--sql-bench/Results/wisconsin-pg_fast-Linux_2.0.36_i686-cmp-mysql,pg,solid22
-rw-r--r--sql-bench/Results/wisconsin-solid-Linux_2.0.36_i686-cmp-mysql,pg,solid14
-rwxr-xr-xsql-bench/bench-init.pl.sh514
-rwxr-xr-xsql-bench/compare-results.sh630
-rwxr-xr-xsql-bench/copy-db.sh371
-rwxr-xr-xsql-bench/crash-me.sh3442
-rw-r--r--sql-bench/example.bat7
-rw-r--r--sql-bench/limits/Adabas.cfg429
-rw-r--r--sql-bench/limits/Adabas.comment36
-rw-r--r--sql-bench/limits/Informix.cfg420
-rw-r--r--sql-bench/limits/Informix.comment26
-rw-r--r--sql-bench/limits/access.cfg501
-rw-r--r--sql-bench/limits/access.comment40
-rw-r--r--sql-bench/limits/access_odbc.cfg448
-rw-r--r--sql-bench/limits/db2.cfg422
-rw-r--r--sql-bench/limits/empress.cfg364
-rw-r--r--sql-bench/limits/empress.comment102
-rw-r--r--sql-bench/limits/interbase.cfg472
-rw-r--r--sql-bench/limits/mimer.cfg491
-rw-r--r--sql-bench/limits/ms-sql.cfg506
-rw-r--r--sql-bench/limits/ms-sql65.cfg418
-rw-r--r--sql-bench/limits/msql.cfg227
-rw-r--r--sql-bench/limits/mysql-3.22.cfg452
-rw-r--r--sql-bench/limits/mysql-3.23.cfg511
-rw-r--r--sql-bench/limits/mysql.cfg511
-rw-r--r--sql-bench/limits/oracle.cfg505
-rw-r--r--sql-bench/limits/pg.cfg504
-rw-r--r--sql-bench/limits/pg.comment30
-rw-r--r--sql-bench/limits/solid-nt4.cfg422
-rw-r--r--sql-bench/limits/solid.cfg422
-rw-r--r--sql-bench/limits/sybase.cfg422
-rwxr-xr-xsql-bench/print-limit-table360
-rw-r--r--sql-bench/pwd.bat2
-rwxr-xr-xsql-bench/run-all-tests.sh288
-rwxr-xr-xsql-bench/server-cfg.sh3030
-rwxr-xr-xsql-bench/test-ATIS.sh548
-rwxr-xr-xsql-bench/test-alter-table.sh180
-rwxr-xr-xsql-bench/test-big-tables.sh154
-rwxr-xr-xsql-bench/test-connect.sh287
-rwxr-xr-xsql-bench/test-create.sh259
-rwxr-xr-xsql-bench/test-insert.sh1312
-rwxr-xr-xsql-bench/test-select.sh353
-rwxr-xr-xsql-bench/test-wisconsin.sh344
-rw-r--r--sql-bench/uname.bat2
-rw-r--r--sql/.cvsignore12
-rw-r--r--sql/Attic/lex_hash.h416
-rw-r--r--sql/Attic/mini_client.c783
-rw-r--r--sql/Attic/mini_client_errors.c64
-rw-r--r--sql/Attic/mybinlogdump.cc138
-rw-r--r--sql/Attic/net_serv.c616
-rw-r--r--sql/ChangeLog3268
-rw-r--r--sql/Makefile.am126
-rwxr-xr-xsql/add_errmsg17
-rw-r--r--sql/cache_manager.cc150
-rw-r--r--sql/cache_manager.h65
-rw-r--r--sql/convert.cc465
-rw-r--r--sql/custom_conf.h28
-rw-r--r--sql/derror.cc146
-rw-r--r--sql/field.cc4576
-rw-r--r--sql/field.h1082
-rw-r--r--sql/field_conv.cc528
-rw-r--r--sql/filesort.cc957
-rw-r--r--sql/frm_crypt.cc37
-rw-r--r--sql/gen_lex_hash.cc560
-rw-r--r--sql/ha_berkeley.cc1398
-rw-r--r--sql/ha_berkeley.h141
-rw-r--r--sql/ha_hash.h31
-rw-r--r--sql/ha_heap.cc261
-rw-r--r--sql/ha_heap.h83
-rw-r--r--sql/ha_isam.cc390
-rw-r--r--sql/ha_isam.h87
-rw-r--r--sql/ha_isammrg.cc210
-rw-r--r--sql/ha_isammrg.h69
-rw-r--r--sql/ha_myisam.cc873
-rw-r--r--sql/ha_myisam.h96
-rw-r--r--sql/ha_myisammrg.cc209
-rw-r--r--sql/ha_myisammrg.h67
-rw-r--r--sql/handler.cc614
-rw-r--r--sql/handler.h307
-rw-r--r--sql/hash_filo.cc28
-rw-r--r--sql/hash_filo.h131
-rw-r--r--sql/hostname.cc235
-rw-r--r--sql/init.cc69
-rw-r--r--sql/item.cc680
-rw-r--r--sql/item.h432
-rw-r--r--sql/item_buff.cc119
-rw-r--r--sql/item_cmpfunc.cc1298
-rw-r--r--sql/item_cmpfunc.h567
-rw-r--r--sql/item_create.cc383
-rw-r--r--sql/item_create.h88
-rw-r--r--sql/item_func.cc1981
-rw-r--r--sql/item_func.h857
-rw-r--r--sql/item_strfunc.cc1719
-rw-r--r--sql/item_strfunc.h429
-rw-r--r--sql/item_sum.cc941
-rw-r--r--sql/item_sum.h464
-rw-r--r--sql/item_timefunc.cc1117
-rw-r--r--sql/item_timefunc.h370
-rwxr-xr-xsql/item_uniq.cc22
-rwxr-xr-xsql/item_uniq.h46
-rw-r--r--sql/key.cc266
-rw-r--r--sql/lex.h446
-rw-r--r--sql/lex_symbol.h37
-rw-r--r--sql/lock.cc386
-rw-r--r--sql/log.cc733
-rw-r--r--sql/log_event.cc685
-rw-r--r--sql/log_event.h354
-rw-r--r--sql/matherr.c43
-rw-r--r--sql/md5.c351
-rw-r--r--sql/md5.h80
-rw-r--r--sql/mf_iocache.cc641
-rw-r--r--sql/mini_client.cc801
-rw-r--r--sql/mini_client.h45
-rw-r--r--sql/my_lock.c82
-rw-r--r--sql/mysql_priv.h594
-rw-r--r--sql/mysqlbinlog.cc378
-rw-r--r--sql/mysqld.cc3433
-rw-r--r--sql/net_pkg.cc329
-rw-r--r--sql/net_serv.cc680
-rw-r--r--sql/nt_servc.cc400
-rw-r--r--sql/nt_servc.h80
-rw-r--r--sql/opt_range.cc2543
-rw-r--r--sql/opt_range.h106
-rw-r--r--sql/opt_sum.cc359
-rw-r--r--sql/password.c191
-rw-r--r--sql/procedure.cc71
-rw-r--r--sql/procedure.h124
-rw-r--r--sql/records.cc335
-rw-r--r--sql/share/.cvsignore2
-rwxr-xr-xsql/share/Makefile.am22
-rw-r--r--sql/share/charsets/Index37
-rw-r--r--sql/share/charsets/README43
-rw-r--r--sql/share/charsets/cp1251.conf74
-rw-r--r--sql/share/charsets/cp1257.conf74
-rw-r--r--sql/share/charsets/croat.conf74
-rw-r--r--sql/share/charsets/danish.conf74
-rw-r--r--sql/share/charsets/dec8.conf74
-rw-r--r--sql/share/charsets/dos.conf74
-rw-r--r--sql/share/charsets/estonia.conf74
-rw-r--r--sql/share/charsets/german1.conf74
-rw-r--r--sql/share/charsets/greek.conf74
-rw-r--r--sql/share/charsets/hebrew.conf74
-rw-r--r--sql/share/charsets/hp8.conf74
-rw-r--r--sql/share/charsets/hungarian.conf74
-rw-r--r--sql/share/charsets/koi8_ru.conf74
-rw-r--r--sql/share/charsets/koi8_ukr.conf74
-rw-r--r--sql/share/charsets/latin1.conf74
-rw-r--r--sql/share/charsets/latin2.conf74
-rw-r--r--sql/share/charsets/swe7.conf74
-rw-r--r--sql/share/charsets/usa7.conf74
-rw-r--r--sql/share/charsets/win1250.conf74
-rw-r--r--sql/share/charsets/win1251.conf74
-rw-r--r--sql/share/charsets/win1251ukr.conf74
-rw-r--r--sql/share/czech/errmsg.sysbin0 -> 9707 bytes
-rw-r--r--sql/share/czech/errmsg.txt209
-rw-r--r--sql/share/danish/errmsg.sysbin0 -> 10135 bytes
-rw-r--r--sql/share/danish/errmsg.txt198
-rw-r--r--sql/share/dutch/errmsg.sysbin0 -> 10351 bytes
-rw-r--r--sql/share/dutch/errmsg.txt195
-rw-r--r--sql/share/english/errmsg.sysbin0 -> 9516 bytes
-rw-r--r--sql/share/english/errmsg.txt195
-rw-r--r--sql/share/estonia/errmsg.sysbin0 -> 9492 bytes
-rw-r--r--sql/share/estonia/errmsg.txt199
-rw-r--r--sql/share/french/errmsg.sysbin0 -> 9957 bytes
-rw-r--r--sql/share/french/errmsg.txt195
-rw-r--r--sql/share/german/errmsg.sysbin0 -> 10736 bytes
-rw-r--r--sql/share/german/errmsg.txt198
-rw-r--r--sql/share/greek/errmsg.sysbin0 -> 11563 bytes
-rw-r--r--sql/share/greek/errmsg.txt195
-rw-r--r--sql/share/hungarian/errmsg.sysbin0 -> 10472 bytes
-rw-r--r--sql/share/hungarian/errmsg.txt197
-rw-r--r--sql/share/italian/errmsg.sysbin0 -> 11081 bytes
-rw-r--r--sql/share/italian/errmsg.txt195
-rw-r--r--sql/share/japanese/errmsg.sysbin0 -> 10263 bytes
-rw-r--r--sql/share/japanese/errmsg.txt197
-rw-r--r--sql/share/korean/errmsg.sysbin0 -> 10393 bytes
-rw-r--r--sql/share/korean/errmsg.txt195
-rwxr-xr-xsql/share/norwegian-ny/.cvsignore1
-rw-r--r--sql/share/norwegian-ny/errmsg.txt197
-rwxr-xr-xsql/share/norwegian/.cvsignore1
-rw-r--r--sql/share/norwegian/errmsg.txt197
-rw-r--r--sql/share/polish/errmsg.sysbin0 -> 10151 bytes
-rw-r--r--sql/share/polish/errmsg.txt199
-rw-r--r--sql/share/portuguese/errmsg.sysbin0 -> 10076 bytes
-rw-r--r--sql/share/portuguese/errmsg.txt195
-rw-r--r--sql/share/romania/errmsg.sysbin0 -> 11663 bytes
-rw-r--r--sql/share/romania/errmsg.txt199
-rw-r--r--sql/share/russian/errmsg.sysbin0 -> 9970 bytes
-rw-r--r--sql/share/russian/errmsg.txt198
-rw-r--r--sql/share/slovak/errmsg.sysbin0 -> 9736 bytes
-rw-r--r--sql/share/slovak/errmsg.txt203
-rw-r--r--sql/share/spanish/errmsg.sysbin0 -> 10092 bytes
-rw-r--r--sql/share/spanish/errmsg.txt196
-rw-r--r--sql/share/swedish/errmsg.OLD195
-rw-r--r--sql/share/swedish/errmsg.sysbin0 -> 9840 bytes
-rw-r--r--sql/share/swedish/errmsg.txt195
-rw-r--r--sql/slave.cc945
-rw-r--r--sql/sql_acl.cc2547
-rw-r--r--sql/sql_acl.h84
-rw-r--r--sql/sql_analyse.cc981
-rw-r--r--sql/sql_analyse.h292
-rw-r--r--sql/sql_base.cc2174
-rw-r--r--sql/sql_cache.cc98
-rw-r--r--sql/sql_class.cc593
-rw-r--r--sql/sql_class.h472
-rw-r--r--sql/sql_crypt.cc82
-rw-r--r--sql/sql_crypt.h38
-rw-r--r--sql/sql_db.cc300
-rw-r--r--sql/sql_delete.cc213
-rw-r--r--sql/sql_insert.cc1346
-rw-r--r--sql/sql_lex.cc810
-rw-r--r--sql/sql_lex.h149
-rw-r--r--sql/sql_list.cc22
-rw-r--r--sql/sql_list.h310
-rw-r--r--sql/sql_load.cc790
-rw-r--r--sql/sql_map.cc147
-rw-r--r--sql/sql_map.h59
-rw-r--r--sql/sql_parse.cc2627
-rw-r--r--sql/sql_select.cc6408
-rw-r--r--sql/sql_select.h291
-rw-r--r--sql/sql_show.cc1032
-rw-r--r--sql/sql_string.cc741
-rw-r--r--sql/sql_string.h183
-rw-r--r--sql/sql_table.cc1559
-rw-r--r--sql/sql_test.cc246
-rw-r--r--sql/sql_udf.cc471
-rw-r--r--sql/sql_udf.h144
-rw-r--r--sql/sql_update.cc266
-rw-r--r--sql/sql_yacc.yy2767
-rw-r--r--sql/structs.h160
-rw-r--r--sql/table.cc1121
-rw-r--r--sql/table.h136
-rw-r--r--sql/thr_malloc.cc88
-rw-r--r--sql/time.cc690
-rw-r--r--sql/udf_example.cc868
-rw-r--r--sql/unireg.cc581
-rw-r--r--sql/unireg.h136
-rw-r--r--sql/violite.c399
-rwxr-xr-xsql/watchdog_mysqld126
-rw-r--r--stamp-h.in1
-rw-r--r--strings/.cvsignore8
-rw-r--r--strings/Attic/bootstrap-ctype.c91
-rw-r--r--strings/Attic/ct_init.c6
-rw-r--r--strings/Attic/ctype-cp1251.c88
-rw-r--r--strings/Attic/ctype-cp1257.c88
-rw-r--r--strings/Attic/ctype-croat.c143
-rw-r--r--strings/Attic/ctype-danish.c144
-rw-r--r--strings/Attic/ctype-dec8.c140
-rw-r--r--strings/Attic/ctype-dos.c139
-rw-r--r--strings/Attic/ctype-estonia.c93
-rwxr-xr-xstrings/Attic/ctype-german1.c135
-rw-r--r--strings/Attic/ctype-greek.c855
-rw-r--r--strings/Attic/ctype-hebrew.c135
-rw-r--r--strings/Attic/ctype-hp8.c133
-rw-r--r--strings/Attic/ctype-hungarian.c113
-rw-r--r--strings/Attic/ctype-koi8_ru.c133
-rw-r--r--strings/Attic/ctype-koi8_ukr.c141
-rw-r--r--strings/Attic/ctype-latin1.c142
-rw-r--r--strings/Attic/ctype-latin2.c186
-rw-r--r--strings/Attic/ctype-swe7.c137
-rw-r--r--strings/Attic/ctype-usa7.c134
-rw-r--r--strings/Attic/ctype-win1250.c152
-rw-r--r--strings/Attic/ctype-win1251.c135
-rw-r--r--strings/Attic/ctype-win1251ukr.c142
-rw-r--r--strings/Attic/ctype.c.in20
-rw-r--r--strings/Attic/memory.h33
-rw-r--r--strings/Attic/ptr_cmp.c151
-rwxr-xr-xstrings/ChangeLog38
-rw-r--r--strings/Makefile.am84
-rw-r--r--strings/READ-ME82
-rw-r--r--strings/README82
-rw-r--r--strings/atof.c208
-rw-r--r--strings/bchange.c39
-rw-r--r--strings/bcmp.c63
-rw-r--r--strings/bcopy-duff.c50
-rw-r--r--strings/bfill.c81
-rw-r--r--strings/bmove.c63
-rw-r--r--strings/bmove512.c129
-rw-r--r--strings/bmove_upp-sparc.s40
-rw-r--r--strings/bmove_upp.c51
-rw-r--r--strings/bzero.c67
-rw-r--r--strings/conf_to_src.c143
-rw-r--r--strings/ctype-big5.c389
-rw-r--r--strings/ctype-czech.c510
-rw-r--r--strings/ctype-euc_kr.c198
-rw-r--r--strings/ctype-gb2312.c180
-rw-r--r--strings/ctype-gbk.c2722
-rw-r--r--strings/ctype-sjis.c317
-rw-r--r--strings/ctype-tis620.c656
-rw-r--r--strings/ctype-ujis.c183
-rw-r--r--strings/ctype.c68
-rw-r--r--strings/do_ctype.c200
-rw-r--r--strings/int2str.c155
-rw-r--r--strings/is_prefix.c34
-rw-r--r--strings/latin2.def478
-rw-r--r--strings/llstr.c36
-rw-r--r--strings/longlong2str-x86.s141
-rw-r--r--strings/longlong2str.c143
-rw-r--r--strings/macros.asm147
-rwxr-xr-xstrings/make-ccc3
-rw-r--r--strings/memcmp.c46
-rw-r--r--strings/memcpy.c35
-rw-r--r--strings/memset.c35
-rw-r--r--strings/ptr_cmp.asm180
-rw-r--r--strings/r_strinstr.c52
-rw-r--r--strings/str2int.c202
-rw-r--r--strings/str_test.c270
-rw-r--r--strings/strappend-sparc.s49
-rw-r--r--strings/strappend.c43
-rw-r--r--strings/strcat.c25
-rw-r--r--strings/strcend.c56
-rw-r--r--strings/strchr.c46
-rw-r--r--strings/strcmp.c20
-rw-r--r--strings/strcont.c46
-rw-r--r--strings/strend-sparc.s35
-rw-r--r--strings/strend.c33
-rw-r--r--strings/strfill.c36
-rw-r--r--strings/string.doc155
-rw-r--r--strings/strings-not-used.h22
-rw-r--r--strings/strings-x86.s406
-rw-r--r--strings/strings.asm1060
-rw-r--r--strings/strinstr-sparc.s43
-rw-r--r--strings/strinstr.c50
-rw-r--r--strings/strlen.c50
-rw-r--r--strings/strmake-sparc.s43
-rw-r--r--strings/strmake.c53
-rw-r--r--strings/strmov-sparc.s36
-rw-r--r--strings/strmov.c59
-rw-r--r--strings/strnlen.c36
-rw-r--r--strings/strnmov-sparc.s43
-rw-r--r--strings/strnmov.c36
-rw-r--r--strings/strrchr.c24
-rw-r--r--strings/strstr-sparc.s75
-rw-r--r--strings/strstr.c35
-rw-r--r--strings/strto.c204
-rw-r--r--strings/strtol.c23
-rw-r--r--strings/strtoll.c25
-rw-r--r--strings/strtoul.c24
-rw-r--r--strings/strtoull.c26
-rw-r--r--strings/strxmov-sparc.s49
-rw-r--r--strings/strxmov.asm103
-rw-r--r--strings/strxmov.c33
-rw-r--r--strings/strxnmov.c46
-rw-r--r--strings/t_ctype.h243
-rw-r--r--strings/udiv.c38
-rw-r--r--support-files/.cvsignore13
-rw-r--r--support-files/Attic/my-example.cnf.sh39
-rw-r--r--support-files/Attic/my-huge.cfg.sh60
-rw-r--r--support-files/Attic/my-large.cfg.sh60
-rw-r--r--support-files/Attic/my-medium.cfg.sh58
-rw-r--r--support-files/Attic/my-small.cfg.sh53
-rwxr-xr-xsupport-files/Makefile.am90
-rwxr-xr-xsupport-files/binary-configure.sh16
-rw-r--r--support-files/maxsql.spec.sh410
-rw-r--r--support-files/my-huge.cnf.sh64
-rw-r--r--support-files/my-large.cnf.sh64
-rw-r--r--support-files/my-medium.cnf.sh63
-rw-r--r--support-files/my-small.cnf.sh57
-rw-r--r--support-files/mysql-log-rotate.sh29
-rwxr-xr-xsupport-files/mysql.server-sys5.sh86
-rw-r--r--support-files/mysql.server.sh123
-rw-r--r--support-files/mysql.spec.sh396
-rw-r--r--tests/.cvsignore2
-rw-r--r--tests/Makefile.am27
-rw-r--r--tests/auto_increment.res114
-rw-r--r--tests/auto_increment.tst27
-rwxr-xr-xtests/big_record.pl58
-rwxr-xr-xtests/export.pl164
-rwxr-xr-xtests/fork2_test.pl210
-rwxr-xr-xtests/fork3_test.pl150
-rwxr-xr-xtests/fork_test.pl247
-rw-r--r--tests/function.res258
-rw-r--r--tests/function.tst80
-rw-r--r--tests/grant.pl545
-rw-r--r--tests/grant.res436
-rwxr-xr-xtests/insert_and_repair.pl180
-rwxr-xr-xtests/lock_test.pl94
-rw-r--r--tests/lock_test.res25
-rwxr-xr-xtests/mail_to_db.pl310
-rwxr-xr-xtests/pmail.pl195
-rwxr-xr-xtests/table_types.pl224
-rwxr-xr-xtests/test_delayed_insert.pl365
-rw-r--r--tests/udf_test30
-rw-r--r--tests/udf_test.res151
-rw-r--r--vio/.cvsignore1
-rw-r--r--vio/Makefile.am44
-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/version.cc7
-rw-r--r--vio/vio-global.h33
-rw-r--r--vio/vioelitexx.cc26
-rw-r--r--vio/violite.h101
-rw-r--r--vio/viotest-ssl.cc106
-rw-r--r--vio/viotest-sslconnect.cc82
-rw-r--r--vio/viotest.cc49
-rw-r--r--vio/viotypes.h32
2375 files changed, 454571 insertions, 0 deletions
diff --git a/.cvsignore b/.cvsignore
new file mode 100644
index 00000000000..ab83fba3a89
--- /dev/null
+++ b/.cvsignore
@@ -0,0 +1,37 @@
+.snprj
+COPYING
+COPYING.LIB
+INSTALL-SOURCE
+INSTALL-SOURCE-GENERIC
+Logs
+MIRRORS
+Makefile
+Makefile.in
+NEW-RPMS
+PUBLIC
+Projects
+TODO
+WIN-LICENSE
+aclocal.m4
+binary
+compile
+confdefs.h
+config.cache
+config.h
+config.log
+config.status
+configure
+configure.in-removed
+conftest.c
+conftest.s1
+conftest.s2
+conftest.subs
+internal-docs
+libtool
+linked_client_sources
+linked_server_sources
+mysql-copyright-120700-194832
+mysql-copyright-120700-221248
+skr
+stamp-h
+tmp
diff --git a/BUILD/.cvsignore b/BUILD/.cvsignore
new file mode 100644
index 00000000000..0114f18cab7
--- /dev/null
+++ b/BUILD/.cvsignore
@@ -0,0 +1 @@
+compile-pentium-test
diff --git a/BUILD/compile-alpha b/BUILD/compile-alpha
new file mode 100755
index 00000000000..ff70be8a5ab
--- /dev/null
+++ b/BUILD/compile-alpha
@@ -0,0 +1,7 @@
+make -k clean
+/bin/rm -f */.deps/*.P */*.o
+/bin/rm -f config.cache
+aclocal; autoheader; aclocal; automake; autoconf
+
+CFLAGS="-O6 -fomit-frame-pointer -mcpu=ev6 -Wa,-mev6" CXX=gcc CXXFLAGS="-O6 -mcpu=ev6 -Wa,-mev6 -fomit-frame-pointer -felide-constructors -fno-exceptions -fno-rtti" ./configure --prefix=/usr/local/mysql --disable-shared --with-extra-charsets=complex
+make
diff --git a/BUILD/compile-alpha-ccc b/BUILD/compile-alpha-ccc
new file mode 100755
index 00000000000..194ed099541
--- /dev/null
+++ b/BUILD/compile-alpha-ccc
@@ -0,0 +1,35 @@
+/bin/rm -f */.deps/*.P */*.o
+make -k clean
+/bin/rm -f */.deps/*.P */*.o
+/bin/rm -f config.cache mysql-*.tar.gz
+aclocal; autoheader; aclocal; automake; autoconf
+
+CC=ccc CFLAGS="-fast -O3 -fomit-frame-pointer" CXX=gcc CXXFLAGS="-O6 -fomit-frame-pointer -felide-constructors -fno-exceptions -fno-rtti -mcpu=ev6 -Wa,-mev6" CXXLDFLAGS='/usr/lib/compaq/libots-2.2.7/libots.so /usr/lib/compaq/cpml-5.0.0/libcpml_ev6.a' ./configure --prefix=/usr/local/mysql --disable-shared --with-extra-charsets=complex
+make
+if [ $? = 0 ]
+then
+ rm */.deps/*
+ bin/mysqladmin shutdown
+ make install
+ if [ $? = 0 ]
+ then
+ scripts/make_binary_distribution
+ fi
+fi
+
+exit
+
+# This should give better performance by compiling many files at once, but
+# according to our benchmarks there isn't any real difference.
+
+pwd=`pwd`
+for i in */make-ccc
+do
+ cd `dirname $i`
+ make-ccc
+ cd $pwd
+done
+cd sql
+rm mysqld .deps/*.P
+make mysqld
+cd $pwd
diff --git a/BUILD/compile-alpha-debug b/BUILD/compile-alpha-debug
new file mode 100755
index 00000000000..6672027445e
--- /dev/null
+++ b/BUILD/compile-alpha-debug
@@ -0,0 +1,7 @@
+make -k clean
+/bin/rm -f */.deps/*.P
+/bin/rm -f config.cache
+aclocal; autoheader; aclocal; automake; autoconf
+
+CFLAGS=-O6 CXX=gcc CXXFLAGS="-O6 -felide-constructors -fno-exceptions -fno-rtti" ./configure --prefix=/usr/local/mysql --with-debug
+make
diff --git a/BUILD/compile-ia64-O0 b/BUILD/compile-ia64-O0
new file mode 100644
index 00000000000..d07067289b4
--- /dev/null
+++ b/BUILD/compile-ia64-O0
@@ -0,0 +1,12 @@
+make -k clean
+/bin/rm -f */.deps/*.P config.cache
+
+aclocal; autoheader; aclocal; automake; autoconf
+
+CFLAGS="-O0 -fomit-frame-pointer" CXX=gcc CXXFLAGS="-O0 -fomit-frame-pointer -felide-constructors -fno-exceptions -fno-rtti" ./configure --prefix=/usr/local/mysql --enable-assembler --with-mysqld-ldflags=-all-static --disable-shared --with-extra-charsets=complex
+make
+strip sql/mysqld
+
+
+
+
diff --git a/BUILD/compile-ia64-O0-sgicc b/BUILD/compile-ia64-O0-sgicc
new file mode 100644
index 00000000000..c5e14eab033
--- /dev/null
+++ b/BUILD/compile-ia64-O0-sgicc
@@ -0,0 +1,12 @@
+make -k clean
+/bin/rm -f */.deps/*.P config.cache
+
+aclocal; autoheader; aclocal; automake; autoconf
+
+CC=sgicc CFLAGS="-O0" CXX=sgicc CXXFLAGS="-O0" ./configure --prefix=/usr/local/mysql --enable-assembler --with-mysqld-ldflags=-all-static --disable-shared --with-extra-charsets=complex
+make
+strip sql/mysqld
+
+
+
+
diff --git a/BUILD/compile-ia64-O2 b/BUILD/compile-ia64-O2
new file mode 100644
index 00000000000..140d34b2466
--- /dev/null
+++ b/BUILD/compile-ia64-O2
@@ -0,0 +1,12 @@
+make -k clean
+/bin/rm -f */.deps/*.P config.cache
+
+aclocal; autoheader; aclocal; automake; autoconf
+
+CFLAGS="-O2 -fomit-frame-pointer" CXX=gcc CXXFLAGS="-O2 -fomit-frame-pointer -felide-constructors -fno-exceptions -fno-rtti" ./configure --prefix=/usr/local/mysql --enable-assembler --with-mysqld-ldflags=-all-static --disable-shared --with-extra-charsets=complex
+make
+strip sql/mysqld
+
+
+
+
diff --git a/BUILD/compile-ia64-O2-sgicc b/BUILD/compile-ia64-O2-sgicc
new file mode 100644
index 00000000000..64b2ff17beb
--- /dev/null
+++ b/BUILD/compile-ia64-O2-sgicc
@@ -0,0 +1,12 @@
+make -k clean
+/bin/rm -f */.deps/*.P config.cache
+
+aclocal; autoheader; aclocal; automake; autoconf
+
+CC=sgicc CFLAGS="-O2" CXX=sgicc CXXFLAGS="-O2" ./configure --prefix=/usr/local/mysql --enable-assembler --with-mysqld-ldflags=-all-static --disable-shared --with-extra-charsets=complex
+make
+strip sql/mysqld
+
+
+
+
diff --git a/BUILD/compile-ia64-O6 b/BUILD/compile-ia64-O6
new file mode 100644
index 00000000000..8792c0e1479
--- /dev/null
+++ b/BUILD/compile-ia64-O6
@@ -0,0 +1,8 @@
+make -k clean
+/bin/rm -f */.deps/*.P config.cache
+
+aclocal; autoheader; aclocal; automake; autoconf
+
+CFLAGS="-O6 -fomit-frame-pointer" CXX=gcc CXXFLAGS="-O6 -fomit-frame-pointer -felide-constructors -fno-exceptions -fno-rtti" ./configure --prefix=/usr/local/mysql --enable-assembler --with-mysqld-ldflags=-all-static --disable-shared --with-extra-charsets=complex
+make
+strip sql/mysqld
diff --git a/BUILD/compile-pentium b/BUILD/compile-pentium
new file mode 100755
index 00000000000..29697ffdc88
--- /dev/null
+++ b/BUILD/compile-pentium
@@ -0,0 +1,8 @@
+make -k clean
+/bin/rm -f */.deps/*.P config.cache
+
+aclocal; autoheader; aclocal; automake; autoconf
+
+CFLAGS="-O6 -mpentiumpro -fomit-frame-pointer" CXX=gcc CXXFLAGS="-O6 -mpentiumpro -fomit-frame-pointer -felide-constructors -fno-exceptions -fno-rtti" ./configure --prefix=/usr/local/mysql --enable-assembler --with-mysqld-ldflags=-all-static --disable-shared --with-extra-charsets=complex
+make
+strip sql/mysqld
diff --git a/BUILD/compile-pentium-debug b/BUILD/compile-pentium-debug
new file mode 100755
index 00000000000..a8c2c98e0ef
--- /dev/null
+++ b/BUILD/compile-pentium-debug
@@ -0,0 +1,19 @@
+make -k clean
+/bin/rm -f */.deps/*.P config.cache
+
+aclocal; autoheader; aclocal; automake; autoconf
+
+# If you are not using codefusion add "-Wpointer-arith" to WARNINGS
+# The following warning flag will give too many warnings:
+# -Wshadow -Wunused -Winline (The later isn't usable in C++ as
+# __attribute()__ doesn't work with gnu C++)
+
+GLOBAL_WARNINGS="-Wimplicit -Wreturn-type -Wid-clash-51 -Wswitch -Wtrigraphs -Wcomment -W -Wchar-subscripts -Wuninitialized -Wformat -Wimplicit-function-dec -Wimplicit-int -Wparentheses -Wsign-compare -Wwrite-strings"
+C_WARNINGS="$GLOBAL_WARNINGS -Wunused"
+CC_WARNINGS="$GLOBAL_WARNINGS -Woverloaded-virtual -Wextern-inline -Wsign-promo -Wreorder -Wctor-dtor-privacy -Wnon-virtual-dtor"
+
+CFLAGS="-DFORCE_INIT_OF_VARS -O2 -mpentiumpro $C_WARNINGS" CXX=gcc \
+CXXFLAGS="-DFORCE_INIT_OF_VARS -O2 -mpentiumpro -felide-constructors -fno-exceptions -fno-rtti $CC_WARNINGS" \
+./configure --prefix=/usr/local/mysql --enable-assembler --with-mysqld-ldflags=-all-static --disable-shared --with-extra-charsets=complex --with-debug=full
+--with-berkeley-db=/usr/local/BerkeleyDB
+make
diff --git a/BUILD/compile-pentium-gcov b/BUILD/compile-pentium-gcov
new file mode 100755
index 00000000000..e28d211d6d2
--- /dev/null
+++ b/BUILD/compile-pentium-gcov
@@ -0,0 +1,16 @@
+make -k clean
+/bin/rm -f */.deps/*.P config.cache
+
+aclocal; autoheader; aclocal; automake; autoconf
+
+# If you are not using codefusion add "-Wpointer-arith" to WARNINGS
+# The following warning flag will give too many warnings:
+# -Wshadow -Wunused (The later isn't usable in C++ as
+# __attribute()__ doesn't work with gnu C++)
+
+GLOBAL_WARNINGS="-Wimplicit -Wreturn-type -Wid-clash-51 -Wswitch -Wtrigraphs -Wcomment -W -Wchar-subscripts -Wuninitialized -Wformat -Wimplicit-function-dec -Wimplicit-int -Wparentheses -Wsign-compare -Wwrite-strings"
+C_WARNINGS="$GLOBAL_WARNINGS -Wunused"
+CC_WARNINGS="$GLOBAL_WARNINGS -Woverloaded-virtual -Wextern-inline -Wsign-promo -Wreorder -Wctor-dtor-privacy -Wnon-virtual-dtor"
+
+CFLAGS="-O2 -mpentiumpro -fprofile-arcs -ftest-coverage $C_WARNINGS" CXX=gcc CXXFLAGS="-O2 -mpentiumpro -fprofile-arcs -ftest-coverage -felide-constructors -fno-exceptions -fno-rtti $CC_WARNINGS" ./configure --prefix=/usr/local/mysql --enable-assembler --with-mysqld-ldflags=-all-static --disable-shared --with-extra-charsets=complex --with-debug=full
+make
diff --git a/BUILD/compile-pentium-myodbc b/BUILD/compile-pentium-myodbc
new file mode 100755
index 00000000000..989f98eac60
--- /dev/null
+++ b/BUILD/compile-pentium-myodbc
@@ -0,0 +1,6 @@
+make -k clean
+/bin/rm -f */.deps/*.P config.cache
+
+aclocal; autoheader; aclocal; automake; autoconf
+
+CFLAGS="-O6 -mpentiumpro -fomit-frame-pointer" CXX=gcc CXXFLAGS="-O6 -mpentiumpro -fomit-frame-pointer -felide-constructors -fno-exceptions -fno-rtti" ./configure --prefix=/usr/local/mysql --enable-assembler --with-mysqld-ldflags=-all-static --with-extra-charsets=complex --without-server
diff --git a/BUILD/compile-solaris-sparc b/BUILD/compile-solaris-sparc
new file mode 100755
index 00000000000..0cfa8a4ecd0
--- /dev/null
+++ b/BUILD/compile-solaris-sparc
@@ -0,0 +1,9 @@
+gmake -k clean
+/bin/rm -f */.deps/*.P */*.o
+/bin/rm -f config.cache
+aclocal; autoheader; aclocal; automake; autoconf
+
+CFLAGS="-O6 -fomit-frame-pointer" CXX=gcc CXXFLAGS="-O6 -fomit-frame-pointer -f
+elide-constructors -fno-exceptions -fno-rtti" ./configure --prefix=/usr/local/m
+ysql --with-extra-charsets=complex
+gmake
diff --git a/BUILD/compile-solaris-sparc-purify b/BUILD/compile-solaris-sparc-purify
new file mode 100755
index 00000000000..2a48d71375d
--- /dev/null
+++ b/BUILD/compile-solaris-sparc-purify
@@ -0,0 +1,13 @@
+gmake -k clean
+/bin/rm -f */.deps/*.P */*.o
+/bin/rm -f config.cache
+aclocal; autoheader; aclocal; automake; autoconf
+
+GLOBAL_WARNINGS="-Wimplicit -Wreturn-type -Wid-clash-51 -Wswitch -Wtrigraphs -Wcomment -W -Wchar-subscripts -Wuninitialized -Wformat -Wimplicit-function-dec -Wimplicit-int -Wparentheses -Wsign-compare -Wwrite-strings"
+C_WARNINGS="$GLOBAL_WARNINGS -Wunused"
+CC_WARNINGS="$GLOBAL_WARNINGS -Woverloaded-virtual -Wextern-inline -Wsign-promo -Wreorder -Wctor-dtor-privacy -Wnon-virtual-dtor"
+
+CFLAGS="-DHAVE_PURIFY -O2 $C_WARNINGS" CXX=gcc \
+CXXFLAGS="-DHAVE_PURIFY -O2 -felide-constructors -fno-exceptions -fno-rtti $CC_WARNINGS" \
+./configure --prefix=/usr/local/mysql --enable-assembler --with-mysqld-ldflags=-all-static --disable-shared --with-debug=full
+gmake
diff --git a/BUILD/test-alpha-ccc b/BUILD/test-alpha-ccc
new file mode 100755
index 00000000000..c6f4abc0973
--- /dev/null
+++ b/BUILD/test-alpha-ccc
@@ -0,0 +1,11 @@
+cd /usr/local/mysql
+bin/mysqladmin shutdown
+libexec/mysqld --basedir . &
+cd sql-bench
+rm output/*
+perl run-all-tests --comment "Alpha DS20 2x500 MHz, 2G memory, key_buffer=16M; egcs 1.1.2 + ccc" --user=monty --password="ds20-gryta"
+perl run-all-tests --comment "Alpha DS20 2x500 MHz, 2G memory, key_buffer=16M; egcs 1.1.2 + ccc" --user=monty --password="ds20-gryta" --log --use-old
+mv output/* output-ccc
+perl run-all-tests --comment "Alpha DS20 2x500 MHz, 2G memory, key_buffer=16M; egcs 1.1.2 + ccc" --user=monty --password="ds20-gryta" --fast
+perl run-all-tests --comment "Alpha DS20 2x500 MHz, 2G memory, key_buffer=16M; egcs 1.1.2 + ccc" --user=monty --password="ds20-gryta" --log --use-old --fast
+mv output/* output-ccc
diff --git a/Build-tools/Do-all-build-steps b/Build-tools/Do-all-build-steps
new file mode 100755
index 00000000000..8e1d01232f8
--- /dev/null
+++ b/Build-tools/Do-all-build-steps
@@ -0,0 +1,74 @@
+#!/bin/bash
+
+WD=`pwd`
+TMP_SCRIPT=$WD/Logs/00-temp-for-do-all-build-steps.$$
+
+# We build on work
+to_host=`hostname`
+cc=gcc
+ccc=gcc
+EXTRA_CONFIG="--without-perl"
+
+echo "Building on $to_host"
+
+cat > $TMP_SCRIPT <<END
+# Show executed commands
+set -x
+# Move to the right place
+cd "$WD"
+
+CC=$cc CXX=$ccc
+export CC CXX
+
+gmake -k distclean
+rm -f NEW-RPMS/*
+
+# Stop on error
+set -e
+
+# Make everything readable for user and group
+# chmod -R u+rw,g+rw .
+
+/bin/rm -f */.deps/*.P
+/bin/rm -f config.cache
+
+aclocal; autoheader; aclocal; automake; autoconf
+
+# Since we have moved the configure.in stuff from readline to the
+# toplevel why do this? David 990630
+# (cd readline; aclocal; autoheader; aclocal; automake; autoconf)
+
+# A normal user starts here. We must use mit-threads. Otherwise it
+# does not end up in the distribution.
+./configure \
+ --with-unix-socket-path=/var/tmp/mysql.sock \
+ --with-low-memory \
+ --with-mit-threads=yes $EXTRA_CONFIG
+
+gmake # --jobs=4 does not work.
+
+time gmake distcheck \
+ EXTRA_CONF_ARGS="--with-unix-socket-path=/var/tmp/mysql.sock --with-low-memory $EXTRA_CONFIG"
+
+$WD/Build-tools/Do-rpm
+
+rm -f $TMP_SCRIPT
+END
+
+mkdir -p $WD/Logs
+log=$WD/Logs/Log-distcheck-`date +%y%m%d-%H%M`
+
+if test $to_host = "mysql-work"
+then
+ # Try to get the right user for MySQL builds on work so that all
+ # files is owned by the same user (mysql)
+ ssh -n $to_host -l my "time bash $TMP_SCRIPT" > $log 2>&1
+else
+ time bash $TMP_SCRIPT > $log 2>&1
+fi
+
+# Create a commercial MySQL distribution (mysqlcom-VER.tar.gz) from
+# the newly made source distribution
+
+DIST=`ls -t mysql-*.tar.gz | head -1`
+$WD/Build-tools/mysql-copyright --target=. $DIST
diff --git a/Build-tools/Do-compile b/Build-tools/Do-compile
new file mode 100755
index 00000000000..50d2fcd7977
--- /dev/null
+++ b/Build-tools/Do-compile
@@ -0,0 +1,421 @@
+#!/usr/bin/perl
+
+use Getopt::Long;
+$opt_distribution=$opt_user=$opt_result=$opt_config_options=$opt_config_env="";
+$opt_dbd_options=$opt_perl_options="";
+$opt_tmp="";
+$opt_help=$opt_Information=$opt_no_delete=$opt_debug=$opt_stage=$opt_rsh_mail=$opt_no_test=$opt_no_perl=$opt_with_low_memory=$opt_fast_benchmark=$opt_static_client=$opt_static_server=$opt_static_perl=$opt_sur=$opt_with_small_disk=$opt_local_perl=0;
+GetOptions("Information","help","distribution=s","user=s","result=s","no-delete","no-test","perl-files=s","debug","config-options=s","config-env=s","stage=i","rsh-mail","with-low-memory","fast-benchmark","tmp=s","static-client","static-server","static-perl","no-perl","local-perl","perl-options=s","sur","with-small-disk","dbd-options=s") || usage();
+
+usage() if ($opt_help || $opt_Information);
+usage() if (!$opt_distribution);
+
+chomp($host=`hostname`);
+print "$host: Compiling MySQL at $host, stage: $opt_stage\n" if ($opt_debug);
+$host =~ /^([^.-]*)/;
+$host=$1;
+$email="$opt_user\@mysql.com";
+$pwd = `pwd`; chomp($pwd);
+$log="$pwd/Logs/$host.log";
+$opt_distribution =~ /(mysql-[^\/]*)\.tar/;
+$ver=$1;
+$gcc_version=which("gcc");
+if (defined($gcc_version) && ! $opt_config_env)
+{
+ $tmp=`$gcc_version -v 2>&1`;
+ if ($tmp =~ /version 2\.7\./)
+ {
+ $opt_config_env= 'CC=gcc CFLAGS="-O2 -fomit-frame-pointer" CXX=gcc CXXFLAGS="-O2 -fomit-frame-pointer"';
+ }
+ else
+ {
+ $opt_config_env= 'CC=gcc CFLAGS="-O3 -fomit-frame-pointer" CXX=gcc CXXFLAGS="-O3 -fomit-frame-pointer -felide-constructors -fno-exceptions -fno-rtti"';
+ }
+}
+if ($opt_tmp)
+{
+ $ENV{'TMPDIR'}=$opt_tmp;
+}
+else
+{
+ $opt_tmp="/tmp";
+}
+$ENV{'PATH'}= "$pwd/$host/bin:" . $ENV{'PATH'};
+$rsh=which("rcmd","rsh");
+$make=which("gmake","make");
+$tar=which("gtar","tar");
+$sendmail=find("/usr/lib/sendmail","/usr/sbin/sendmail");
+$sur= $opt_sur ? "/my/local/bin/sur" : "";
+delete $ENV{'MYSQL_PWD'}; # Reset possibly password
+delete $ENV{'MY_BASEDIR_VERSION'};
+$ENV{'MYSQL_TCP_PORT'}="3334";
+$ENV{'MYSQL_UNIX_PORT'}=$mysql_unix_port="$opt_tmp/mysql.build";
+$ENV{"PERL5LIB"}="$pwd/$host/perl5:$pwd/$host/perl5/site_perl";
+
+if ($opt_stage == 0)
+{
+ print "$host: Removing old distribution\n" if ($opt_debug);
+ if (-x "$host/bin/mysqladmin")
+ {
+ log_system("$host/bin/mysqladmin --no-defaults -u root -S $mysql_unix_port -s shutdown");
+ }
+ system("touch $host/mysql-fix-for-glob");
+ rm_all(<$host/mysql-*>);
+ rm_all("$host/test");
+ system("mkdir $host") if (! -d $host);
+ system("mkdir $host/test") if (! -d "$host/test");
+ system("mkdir $host/bin") if (! -d "$host/bin");
+ system("mkdir Logs") if (! -d "Logs");
+ unlink($log);
+}
+
+open(LOG,">>$log") || abort("Can't open log file, error $?");
+select LOG;
+$|=1;
+select STDOUT;
+$|=1;
+
+safe_cd("$host");
+if ($opt_stage == 0)
+{
+ safe_system("gunzip < $opt_distribution | $tar xf -");
+}
+safe_cd($ver);
+if ($opt_stage <= 1)
+{
+ $opt_config_options.=" --with-low-memory" if ($opt_with_low_memory);
+ unlink("config.cache");
+ if ($opt_static_server)
+ {
+ $opt_config_options.=" --with-mysqld-ldflags=-all-static";
+ }
+ if ($opt_static_client)
+ {
+ $opt_config_options.=" --with-client-ldflags=-all-static";
+ }
+ $opt_config_options.= " --disable-shared"; # Default for binary versions
+ check_system("$opt_config_env ./configure --prefix=/usr/local/mysql \"--with-comment=Official MySQL binary\" --with-extra-charsets=complex $opt_config_options","Thank you for choosing MySQL");
+ if (-d "$pwd/$host/include-mysql")
+ {
+ safe_system("cp -r $pwd/$host/include-mysql/* $pwd/$host/$ver/include");
+ }
+}
+
+if ($opt_stage <= 2)
+{
+ unlink($opt_distribution) if (!$opt_no_delete);
+ safe_system("$make");
+}
+
+#
+# Create a binary distrubtion
+#
+if ($opt_stage <= 3)
+{
+ log_system("rm -fr mysql-* $pwd/$host/*.tar.gz");
+ log_system("strip sql/mysqld extra/comp_err client/mysql sql/mysqld client/mysqlshow extra/replace isam/isamchk client/mysqladmin client/mysqldump extra/perror");
+ check_system("scripts/make_binary_distribution $opt_tmp",".tar.gz created");
+ safe_system("mv mysql*.tar.gz $pwd/$host");
+ safe_system("cp client/mysqladmin $pwd/$host/bin");
+ safe_system("make clean") if ($opt_with_small_disk);
+}
+
+#
+# Unpack and test the binary distrubtion
+#
+
+if ($opt_stage <= 4 && !$opt_no_test)
+{
+ rm_all(<$pwd/$host/test/*>);
+ safe_cd("$pwd/$host/test");
+ $tar_file=<$pwd/$host/*.tar.gz>;
+ if (!defined($tar_file))
+ {
+ $tar_file=<$pwd/$host/*.tgz>;
+ }
+ safe_system("gunzip < $tar_file | $tar xf -");
+}
+
+$test_dir=<$pwd/$host/test/$ver-*>;
+if ($opt_stage <= 5 && !$opt_no_test)
+{
+ safe_cd($test_dir);
+ log_system("./bin/mysqladmin --no-defaults -u root -S $mysql_unix_port -s shutdown") || info("There was no mysqld running\n");
+ sleep(2);
+ log_system("rm -f ./data/mysql/*");
+ check_system("scripts/mysql_install_db --skip-locking","com/license");
+ safe_system("./bin/mysqld --no-defaults --basedir . --datadir ./data --skip-locking >> $log 2>&1 &");
+ sleep(2);
+}
+
+if ($opt_stage <= 6 && $opt_perl_files && !$opt_no_perl && !$opt_no_test)
+{
+ safe_cd($test_dir);
+ rm_all("perl");
+ safe_system("mkdir perl");
+ $ENV{'IN_MYSQL_DISTRIBUTION'}=1;
+ $ENV{'MYSQL_BUILD'}=$test_dir;
+
+ foreach $module (split(/,/,$opt_perl_files))
+ {
+ my $options;
+ safe_cd("$test_dir/perl");
+ if ($opt_debug)
+ {
+ safe_system("gunzip < $pwd/$module | tar xvf -");
+ }
+ else
+ {
+ safe_system("gunzip < $pwd/$module | tar xf -");
+ }
+ $module =~ m|([^/]+)\.tar\.gz|;
+ $module = $1;
+ safe_cd($module);
+ $options="";
+ $options= "--mysql-install --noprompt --mysql-incdir=$test_dir/include --mysql-libdir=$test_dir/lib -nomsql-install -nomsql1-install --mysql-test-db=test $opt_dbd_options" if ($module =~ /Msql-Mysql/);
+ $options.= " PREFIX=$pwd/$host INSTALLPRIVLIB=$pwd/$host/perl5 INSTALLSCRIPT=$pwd/$host/bin INSTALLSITELIB=$pwd/$host/perl5/site_perl INSTALLBIN=$pwd/$host/bin INSTALLMAN1DIR=$pwd/$host/man INSTALLMAN3DIR=$pwd/$host/man/man3" if ($opt_local_perl);
+ $options.= " $opt_perl_options" if (defined($opt_perl_options));
+ safe_system($opt_static_perl ? "perl Makefile.PL -static $options" : "perl Makefile.PL $options");
+ safe_system("$make ; $sur $make install");
+ }
+}
+
+
+if ($opt_stage <= 7 && !$opt_no_test)
+{
+ safe_cd("$test_dir/sql-bench");
+ log_system("rm -f limits/mysql.cfg");
+ safe_system("perl ./crash-me --force --batch-mode");
+}
+
+if ($opt_stage <= 8 && !$opt_no_test)
+{
+ safe_cd("$test_dir/sql-bench");
+ log_system("rm -f output/*");
+ $tmp= $opt_fast_benchmark ? "--fast --user root --small-test" : "";
+ check_system("perl ./run-all-tests --log --die-on-errors $tmp","RUN-mysql");
+}
+
+if ($opt_stage <= 9 && $opt_result)
+{
+ safe_system("rcp $pwd/$host/*.tar.gz $opt_result");
+}
+
+log_system("$pwd/$host/$ver/client/mysqladmin --no-defaults -S $mysql_unix_port -u root shutdown");
+print LOG "ok\n";
+close LOG;
+print "$host: ok\n";
+
+exit 0;
+
+
+sub usage
+{
+print <<EOF;
+$0 version 1.1
+
+$0 takes the following options:
+
+--help or --Information
+Show this help
+
+--user 'user_name'
+Mail 'user_name'\@analytikerna.se if something went wrong.
+If user is empty then no mail is sent.
+
+--distribution 'distribution_file'
+Name of the MySQL distribution file.
+
+--result 'result_dir'
+Send binary distribution to result_dir
+
+--no-delete
+Do not delete the distribution file.
+
+--perl-files=list of files
+Compile and install the given perl modules.
+
+--no-test
+Don not run crash-me or the benchmarks.
+
+--config-options 'some extra configure options'
+To add some extra options, like '--with-perl=yes'
+
+--config-env 'environment for configure'
+To set up the environment, like 'CC=cc CXX=gcc CXXFLAGS=-O3'
+
+--dbd-options 'options'
+Options for Makefile.PL when configuring msql-mysql-modules.
+
+--with-low-memory
+Use less memory when compiling.
+
+-- stage (1-6)
+Start script from some specific point.
+
+-- debug
+Print all shell commands on stdout.
+EOF
+exit 1;
+}
+
+sub abort
+{
+ my($message)=@_;
+ my($command,$mail_header_file);
+ print LOG "\n$message\n";
+ print "$host: $message\n" if ($opt_debug);
+ close LOG;
+
+ if ($opt_user)
+ {
+ $mail_header_file="$opt_tmp/do-command.$$";
+ open(TMP,">$mail_header_file");
+ print TMP "From: mysql\@$host.se\n";
+ print TMP "To: $email\n";
+ print TMP "Subject: MySQL compilation failed again\n\n";
+ close TMP;
+ $command=($opt_rsh_mail) ? "$rsh analytik" : "";
+ system("tail -30 $log > $log.mail");
+ system("cat $mail_header_file $log.mail | $command $sendmail -t -f $email");
+ unlink($mail_header_file);
+ unlink("$log.mail");
+ }
+ print LOG "Aborting\n";
+ exit 1;
+}
+
+sub info
+{
+ my($message)=@_;
+ print LOG "$message\n";
+ print "$host: $message\n";
+}
+
+sub log_system
+{
+ my($com)=@_;
+ print "$host: $com\n" if ($opt_debug);
+ if (defined($log))
+ {
+ print LOG "$com\n";
+ system("$com >> $log 2>&1") &&
+ print LOG ("Info: couldn't execute command, error: " . ($? / 256) ."\n");
+ }
+ else
+ {
+ system($com) && print "$host: Couldn't execute command, error: " . ($? / 256) ."\n";
+ }
+}
+
+
+sub safe_system
+{
+ my($com,$res)=@_;
+ print LOG "$com\n";
+ print "$host: $com\n" if ($opt_debug);
+ system("$com >> $log 2>&1") && abort("error: Couldn't execute command, error: " . ($? / 256));
+}
+
+sub check_system
+{
+ my($com,$res)=@_;
+ my ($error,$found);
+ print LOG "$com\n";
+ print "$host: $com\n" if ($opt_debug);
+ open (COM, "$com 2>&1 < /dev/null|") || abort("Got error " . ($?/256) ." opening pipe");
+ $found=0;
+ while (<COM>)
+ {
+ print LOG $_;
+ if (index($_,$res) >= 0)
+ {
+ $found=1;
+ last;
+ }
+ }
+ close COM;
+ abort("Couldn't find '$res' in the command result") if (!$found);
+ print "$host: Command ok\n" if ($opt_debug);
+}
+
+sub safe_cd
+{
+ my($dir)=@_;
+ print LOG "cd $dir\n";
+ print "$host: cd $dir\n" if ($opt_debug);
+ chdir($dir) || abort("Can't cd to $dir");
+}
+
+sub which
+{
+ my(@progs)=@_;
+ foreach $prog (@progs)
+ {
+ chomp($found=`which $prog | head -1`);
+ if ($? == 0 && $found ne "" && index($found," ") == -1)
+ {
+ $found =~ s|/+|/|g; # Make nicer output
+ return $found;
+ }
+ }
+ return undef();
+}
+
+sub find
+{
+ my (@progs)=@_;
+ foreach $prog (@progs)
+ {
+ return $prog if (-x $prog);
+ }
+ return undef();
+}
+
+#
+# Remove recursively all from a directory
+# This is needed because problems with NFS and open files
+#
+
+sub rm_all
+{
+ my(@rm_files)=@_;
+ my($dir,$current_dir,@files,@dirs);
+ $current_dir = `pwd`; chomp($current_dir);
+
+ foreach $dir (@rm_files)
+ {
+ if (-d $dir)
+ {
+ chdir($dir) || abort("Can't cd to $dir");
+ print "$host: Removing from $dir\n" if ($opt_debug);
+ while (<* .*>)
+ {
+ next if ($_ eq "." x (length($_)));
+ if (-d $_)
+ {
+# die "Can't remove directory that starts with ." if ($_ =~ /^\./ && $_ ne ".libs"); # Safety
+ push (@dirs,$_);
+ }
+ else
+ {
+ push (@files,$_);
+ }
+ }
+ if ($#files >= 0)
+ {
+ system("rm -f " . join(" ",@files)) && abort("Can't remove files from $dir");
+ }
+ foreach $dir (@dirs)
+ {
+ rm_all($dir);
+ }
+ chdir($current_dir) || abort("Can't cd to $current_dir");
+ log_system("rmdir $dir");
+ }
+ else
+ {
+ system("rm -f $dir") && abort("Can't remove file $dir");
+ }
+ }
+}
diff --git a/Build-tools/Do-create-perl-rpms b/Build-tools/Do-create-perl-rpms
new file mode 100755
index 00000000000..2aa71740b58
--- /dev/null
+++ b/Build-tools/Do-create-perl-rpms
@@ -0,0 +1,64 @@
+#!/bin/bash
+
+
+PM_FILES='Data-Dumper Data-ShowTable DBI Msql-Mysql-modules'
+FILE_EXT='tar.gz'
+ARCH=`uname -m | perl -p -e 's/^i[0-9]86$/i386/'`
+
+# directories
+[ -d /usr/src/redhat ] && RPM_SRC=/usr/src/redhat
+[ -d /usr/src/packages ] && RPM_SRC=/usr/src/packages
+SRC_DIR=/home/matt/work/pm_rpm/tarballs # pristine tarballs
+DEST_DIR=${RPM_SRC}/SOURCES # RPM SOURCES (building area)
+RPM_DEPOSIT=/var/tmp/ftp/RPMS # RPM production deposit
+SRPM_DEPOSIT=/var/tmp/ftp/SRPMS # SRPM production deposit
+
+# keyword replacement for SPEC templates
+REPLACE_KEY='REPLACE_VERSION'
+
+# paths to beloved programs
+NEWEST=/home/matt/work/build_pm_rpms/newest
+REPLACE=/usr/local/bin/replace
+
+
+#++
+# Copy the source tarballs up to staging area for RPM building.
+#--
+cd $SRC_DIR
+for i in $PM_FILES
+do
+ echo Copying $i...
+ cp ${SRC_DIR}/`$NEWEST -s $SRC_DIR -b $i -t $FILE_EXT` $DEST_DIR
+done
+
+
+#++
+# Do keyword replacements on the SPEC templates, and build RPMS
+#--
+cd ${RPM_SRC}/SPECS
+for i in $PM_FILES
+do
+ cat ${i}.spec.template | $REPLACE $REPLACE_KEY `$NEWEST -s $DEST_DIR -b $i -t $FILE_EXT -v` > ${i}.spec
+ rpm -ba ${i}.spec
+ rm ${i}.spec
+done
+
+
+#++
+# Copy new RPMS and SRPMS to production deposit
+#--
+cd $RPM_SRC
+
+# kludge code
+PM_FILES=`echo $PM_FILES | $REPLACE Msql-Mysql-modules DBD-Mysql`
+tmpv=`$NEWEST -s $DEST_DIR -b Msql-Mysql-modules -t $FILE_EXT -v`
+mv SOURCES/Msql-Mysql-modules-${tmpv}.${FILE_EXT} SOURCES/DBD-Mysql-${tmpv}.${FILE_EXT}
+
+
+for i in $PM_FILES
+do
+ cp RPMS/${ARCH}/${i}-`$NEWEST -s $DEST_DIR -b $i -t $FILE_EXT -v`-1.${ARCH}.rpm $RPM_DEPOSIT
+ cp SRPMS/${i}-`$NEWEST -s $DEST_DIR -b $i -t $FILE_EXT -v`-1.src.rpm $SRPM_DEPOSIT
+ rm SOURCES/`$NEWEST -s $DEST_DIR -b $i -t $FILE_EXT`
+done
+
diff --git a/Build-tools/Do-local-patch-file b/Build-tools/Do-local-patch-file
new file mode 100755
index 00000000000..708d06966d3
--- /dev/null
+++ b/Build-tools/Do-local-patch-file
@@ -0,0 +1,37 @@
+#!/bin/sh
+# make a patch file of a mysql distribution
+# takes as argument the previous version
+
+case $# in
+0) echo Usage: $0 previous_version; exit 1;;
+esac
+
+PVER=$1;
+VER=`grep SERVER_VERSION include/mysql_version.h | cut -d'"' -f2`
+NEW="mysql-$VER.tar.gz"
+OLD="mysql-$PVER.tar.gz"
+RESULT="mysql-$PVER-$VER.patch.gz"
+PATCH_DIR=/my/data/tcxwww/html/Downloads/Patches
+RESULT_DIR=/my/data/tcxwww/html/Downloads/MySQL-3.22
+
+if test ! -f $NEW
+then
+ echo "$NEW doesn't exist";
+ exit 1;
+fi
+
+if test ! -f $RESULT_DIR/$OLD
+then
+ echo "$RESULT_DIR/$OLD doesn't exist";
+ exit 1;
+fi
+
+mkdir patch
+cd patch
+gtar xfz ../$NEW
+gtar xfz $RESULT_DIR/$OLD
+cd mysql-$PVER
+diff --context --new-file --recursive . ../mysql-$VER | gzip -9 > ../../$RESULT
+cd ../..
+/bin/rm -rf patch
+
diff --git a/Build-tools/Do-patch-file b/Build-tools/Do-patch-file
new file mode 100755
index 00000000000..f5f2910bc71
--- /dev/null
+++ b/Build-tools/Do-patch-file
@@ -0,0 +1,41 @@
+#!/bin/sh
+# make a patch file of a mysql distribution
+# takes as argument the previous version
+
+case $# in
+0) echo Usage: $0 previous_version; exit 1;;
+esac
+
+PVER=$1;
+VER=`grep SERVER_VERSION include/mysql_version.h | cut -d'"' -f2`
+NEW="mysql-$VER.tar.gz"
+OLD="mysql-$PVER.tar.gz"
+RESULT="mysql-$PVER-$VER.patch.gz"
+PATCH_DIR=/my/web/Site/html/Downloads/Patches
+RESULT_DIR=/my/web/Site/html/Downloads/MySQL-3.23
+
+if test ! -f $NEW
+then
+ echo "$NEW doesn't exist";
+ exit 1;
+fi
+
+if test ! -f $RESULT_DIR/$OLD
+then
+ echo "$RESULT_DIR/$OLD doesn't exist";
+ exit 1;
+fi
+
+mkdir patch
+cd patch
+gtar xfz ../$NEW
+gtar xfz $RESULT_DIR/$OLD
+cd mysql-$PVER
+diff --context --new-file --recursive . ../mysql-$VER | gzip -9 > ../../$RESULT
+cd ../..
+/bin/rm -rf patch
+#chown mysql $RESULT $NEW binary/*
+chmod a+r,o-w $RESULT $NEW binary/*
+mv $RESULT $PATCH_DIR
+mv $NEW $RESULT_DIR
+cp binary/* NEW-RPMS/* $RESULT_DIR
diff --git a/Build-tools/Do-rpm b/Build-tools/Do-rpm
new file mode 100755
index 00000000000..f1847604840
--- /dev/null
+++ b/Build-tools/Do-rpm
@@ -0,0 +1,127 @@
+#!/bin/bash
+
+# We built on one of two machines
+bmachine=work
+smachine=work
+owner=my
+
+# Hard path!!
+bpath=`/bin/pwd`
+rpmdir="/usr/src/redhat"
+
+###### Perl STUFF #####
+
+# Perl version numbers. Should be autodetected from the files in the
+# Perl-mysql-modules/ directory.
+DBI_VERSION="1.11"
+DATA_SHOWTABLE_VERSION="3.3"
+DBD_MYSQL_VERSION="1.2209"
+MAKERPM="$rpmdir/SOURCES/makerpm.pl"
+
+#######################
+
+VER=`grep "AM_INIT_AUTOMAKE(mysql, " $bpath/configure.in | \
+ sed -e 's;AM_INIT_AUTOMAKE(mysql, ;;' -e 's;);;'`
+VER_NO_DASH=`echo $VER | sed -e "s|-.*$||"`
+
+echo "Building RPM for MySQL version $VER on $bmachine"
+
+log=$bpath/Logs/Log-RPM-`date +%y%m%d-%H%M`
+
+(
+set -x
+# Copy MySQL source and spec files
+scp $bpath/mysql-$VER.tar.gz $owner@$bmachine:$rpmdir/SOURCES
+scp $bpath/Docs/Images/mysql-logo.gif $owner@$bmachine:$rpmdir/SOURCES/mysql.gif
+scp $bpath/support-files/mysql-$VER.spec $owner@$bmachine:$rpmdir/SPECS
+
+# Copy perl things. Has to be uncompressed since Compress.pm is not
+# installed yet. Set CEXT to .gz when we support compression.
+CEXT=
+#scp $bpath/Perl-mysql-modules/To-SOURCES/* $owner@$bmachine:$rpmdir/SOURCES
+
+# This had to be installed on the target machince!
+# http://www.perl.com/CPAN/modules/by-module/Archive/Archive-Tar-0.21.tar.gz
+# cd /usr/lib/perl5/site_perl/5.005; ln -s ../* .; rm -f 5.005
+
+TMP_SCRIPT_MYSQL=00-temp-for-do-rpm.$$
+cat > $bpath/Logs/$TMP_SCRIPT_MYSQL <<END
+set -x
+
+# Check environment
+export MYSQL_BUILD_PATH="/usr/cygnus/redhat-980810/H-i386-pc-linux-gnu/bin/:/usr/bin:/bin"
+export MYSQL_BUILD_CFLAGS="-O6 -fomit-frame-pointer -mpentium"
+export MYSQL_BUILD_CXXFLAGS="-O6 -fomit-frame-pointer \
+ -felide-constructors -fno-exceptions -fno-rtti -mpentium"
+gcc -v
+
+# Make RPM
+rpm -ba $rpmdir/SPECS/mysql-$VER.spec
+rm -f /tmp/$TMP_SCRIPT_MYSQL
+END
+
+TMP_SCRIPT_PERL=00-temp-for-perl-rpm.$$
+cat > $bpath/Logs/$TMP_SCRIPT_PERL <<END
+set -x
+
+# First clean up so we do not get old versions when wildcard matching
+rm -f $rpmdir/SOURCES/DBI-*.spec
+rm -f $rpmdir/RPMS/i386/Perl-*.rpm
+rm -f $rpmdir/SRPMS/Perl-*.rpm
+rm -f $rpmdir/RPMS/i386/MySQL*-$VER_NO_DASH*.rpm
+rm -f $rpmdir/SRPMS/MySQL*-$VER_NO_DASH*.rpm
+
+chmod a+x ${MAKERPM}
+rm
+
+${MAKERPM} --verbose --package-name=DBI --package-version ${DBI_VERSION} \
+ --specs --source=DBI-${DBI_VERSION}.tar$CEXT
+
+rpm -ba $rpmdir/SPECS/DBI-${DBI_VERSION}.spec
+
+${MAKERPM} --verbose --package-name=Data-ShowTable \
+ --package-version ${DATA_SHOWTABLE_VERSION} \
+ --specs --source=Data-ShowTable-${DATA_SHOWTABLE_VERSION}.tar$CEXT
+
+rpm -ba $rpmdir/SPECS/Data-ShowTable-${DATA_SHOWTABLE_VERSION}.spec
+
+for v in ${DBD_MYSQL_VERSION}; do
+ ${MAKERPM}
+ --specs \
+ --source=Msql-Mysql-modules-$v.tar$CEXT \
+ --setup-dir=Msql-Mysql-modules-$v \
+ --package-name=DBD-mysql \
+ --package-version=$v \
+ --makemakeropts='--noprompt --mysql-install --mysql-install-nodbd \
+ --nomsql-install --nomsql1-install' \
+ --require=perl-Data-ShowTable --require=perl-DBI
+ rpm -ba $rpmdir/SPECS/DBD-mysql-$v.spec
+done
+
+for srcrpm in $rpmdir/SRPMS/perl-*.src.rpm
+do
+ rpm --rebuild $srcrpm
+done
+
+rm -f /tmp/$TMP_SCRIPT_PERL
+END
+
+# scp $bpath/Logs/$TMP_SCRIPT_MYSQL $owner@$bmachine:/tmp/$TMP_SCRIPT_MYSQL
+
+ssh $bmachine -l $owner bash $bpath/Logs/$TMP_SCRIPT_MYSQL
+
+# Build perl RPM (we currently need to be root to do this and that is
+# not possible)
+
+#scp $bpath/Logs/$TMP_SCRIPT_PERL $owner@$bmachine:/tmp/$TMP_SCRIPT_PERL
+#ssh $bmachine -l root bash /tmp/$TMP_SCRIPT_PERL
+
+# Copy RPMs back to the source dir. We must do this here since the
+# $bmachine may not have permission to access $smachine.
+scp $owner@$bmachine:$rpmdir/RPMS/i386/MySQL*-$VER_NO_DASH*.rpm $bpath/NEW-RPMS
+scp $owner@$bmachine:$rpmdir/SRPMS/MySQL*-$VER_NO_DASH*.rpm $bpath/NEW-RPMS
+
+# 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
+) > $log 2>&1
diff --git a/Build-tools/cvs-sanity-check b/Build-tools/cvs-sanity-check
new file mode 100755
index 00000000000..b3d57e98033
--- /dev/null
+++ b/Build-tools/cvs-sanity-check
@@ -0,0 +1,15 @@
+#! /bin/sh
+
+CVSROOT=my@work.mysql.com:/home/cvs
+CVS_RSH=ssh
+TMPDIR=/tmp
+cd $TMPDIR
+[ -d mysql ] && rm -rf mysql
+CVSROOT=$CVSROOT CVS_RSH=$CVS_RSH cvs -z 9 co mysql && cd mysql && \
+ chmod u+w -R * && BUILD/compile-pentium
+if test $? = 0
+then
+cd $TMPDIR && rm -rf mysql
+fi
+
+
diff --git a/Build-tools/mysql-copyright b/Build-tools/mysql-copyright
new file mode 100755
index 00000000000..a4eac33ded8
--- /dev/null
+++ b/Build-tools/mysql-copyright
@@ -0,0 +1,212 @@
+#!/usr/bin/perl -i
+
+# Untar a MySQL distribution, change the copyright texts,
+# pack it up again to a given directory
+
+$VER="1.1";
+
+use Getopt::Long;
+
+$opt_help= 0;
+$opt_target= "mysql-copyright-target-";
+$opt_target.= `date +%d%m%y-%H%M%S`;
+chop $opt_target;
+
+GetOptions("help","target=s") || usage();
+
+# fix the directory prefix for target dir
+
+$WD= `pwd`;
+chop $WD;
+$opt_target= $WD . '/' . $opt_target;
+
+&main();
+
+####
+#### main
+####
+
+sub main
+{
+ my $REG_BASENAME = '[a-z0-9A-Z\-\_\+]+';
+ my $REG_VERSION = '[0-9\.\-]+[a-z]?[0-9\.\-]+?(.alpha|.beta|.gamma|pre\d|[0-9\.\-a-z])?';
+ my $target;
+
+ usage() if (!$ARGV[0] || $opt_help);
+
+ `mkdir -p $opt_target`;
+ $pec= $? >> 8;
+ die "Couldn't make the target directory!\n" if ($pec);
+
+ for ($i=0; $ARGV[$i]; $i++)
+ {
+ my $distfile= $ARGV[$i];
+ my $dir;
+
+ $dir= "mysql-copyright-";
+ $dir.= `date +%d%m%y-%H%M%S`;
+ chop $dir;
+
+ if (!(mkdir "$dir", 0700))
+ {
+ die "Couldn't make directory $dir!";
+ }
+ if (!(chdir "$dir"))
+ {
+ abort($dir, "Couldn't cd to $dir!");
+ }
+ # if the distfile is mysql-3.22.22-alpha.tar.gz, then
+ # distname is 'mysql-3.22.22-alpha' and suffix '.tar.gz'
+ if ($distfile =~ m/^($REG_BASENAME)([\-\_])
+ ($REG_VERSION){1}([\.\-\+])
+ (.*)?$/xo)
+ {
+ $distname= $1.$2.$3;
+ $suffix= $5.$6;
+ $newdistname= $1."com".$2.$3;
+ }
+ # find out the extract path (should be same as distname!)
+ $destdir= `tar tvzf ../$distfile | head -1`;
+ # remove leading crab
+ $destdir =~ s/.*\d+:\d+:\d+[ ]//;
+ # remove newline and slash from the end
+ $destdir= substr($destdir, 0, -2);
+
+ if ("$destdir" ne "$distname")
+ {
+ print "Destination directory (the directory that will be extracted\n";
+ print "from the original distribution file) differs from the\n";
+ print "distribution name! Are you sure you want to continue? (Y/N) [N]:";
+ $ans= my_read(1);
+ abort($dir, "Aborted!") if ("$ans" ne "Y" && "$ans" ne "y");
+ }
+
+ # everything should be ok, continue with extracting..
+ `gtar xfz ../$distfile`;
+ $pec= $? >> 8;
+ abort($dir, "Extracting from tar failed!\n") if ($pec);
+
+ # remove the 'PUBLIC' file from distribution and copy LICENSE
+ # on the toplevel of the directory instead. file 'PUBLIC' shouldn't
+ # exist in the new mysql distributions, but let's be sure..
+ `rm -f $destdir/PUBLIC`;
+ `cp -a $WD/Docs/LICENSE $destdir/`;
+
+ # fix file copyrights
+ &fix_usage_copyright();
+ &add_copyright();
+
+ # rename the directory with new distribution name
+ `mv -f $destdir $newdistname`;
+
+ # tar the new distribution
+ `gtar cz -f $opt_target/$newdistname.tar.gz *`;
+ $pec= $? >> 8;
+ abort($dir, "Making new tar archive failed!\n") if ($pec);
+
+ # remove temporary directory
+ chdir "..";
+ `rm -rf $dir/`;
+ }
+ exit(0);
+}
+
+####
+#### mysqld and MySQL client programs have a usage printed with --help.
+#### This usage includes a copyright, which needs to be modified
+####
+
+sub fix_usage_copyright
+{
+ my @Cfiles = `find . -type f -name \"*.c*\"`;
+ foreach my $Cfile (@Cfiles)
+ {
+ chop $Cfile;
+ `replace \"This is free software,\\\\\\nand you are welcome to modify and redistribute it under the GPL license\" \"This is commercial software,\\\\nplease see the file LICENSE for details\" -- $Cfile`;
+ }
+}
+
+####
+#### change the copyright text in the beginning of the files
+####
+
+sub add_copyright
+{
+ my @files = `find . -type f -name "*"`;
+ foreach my $file (@files)
+ {
+ chop $file;
+ `$WD/Build-tools/mysql-copyright-2 $file`;
+ }
+}
+
+####
+#### read stdin
+####
+
+sub my_read
+{
+ ($length)= @_; # Max allowed length for the string.
+
+ $input= getc(STDIN);
+ if($input eq "\n")
+ {
+ return "\n";
+ }
+ for($new_input= getc(STDIN); $new_input ne "\n" ;)
+ {
+ if(length($input) < $length)
+ {
+ $input.= $new_input;
+ }
+ $new_input= getc(STDIN);
+ }
+ return $input;
+}
+
+####
+#### abort
+####
+
+sub abort
+{
+ my ($dir, $errstr)= @_;
+ # remove newly made directory and it's contents
+ print "$errstr\n";
+ chdir "..";
+ print "Removing directory $dir...\n";
+ `rm -rf $dir`;
+ exit(0);
+}
+
+####
+#### usage
+####
+
+sub usage
+{
+ print <<EOF;
+$0 version $VER by Jani Tolonen
+
+Description: The program takes one or more MySQL distributions as an
+argument(s), extracts them, changes the copyright text in the
+distribution files and makes a new distribution with suffix "com" in
+the basename to directory mysql-copyright-target-DATE, where the
+command was issued. For example: mysql-3.23.18-beta.tar.gz ->
+mysqlcom-3.23.18-beta.tar.gz. DATE is of form DDMMYY-HHMMSS. The
+target directory can be changed with option
+--target=... mysql-copyright consists of two perl programs, this one
+and another, mysql-copyright-2. Make sure the second part of the
+script is available to the main script.
+
+Usage:
+$0 [options] file1 [file2 file3...]
+
+Options:
+--help Show this help and exit.
+--target Target directory for new distribution files.
+ '.' can be used for the current directory.
+ (Default: $opt_target)
+EOF
+ exit(0);
+}
diff --git a/Build-tools/mysql-copyright-2 b/Build-tools/mysql-copyright-2
new file mode 100755
index 00000000000..5aeb4bb81db
--- /dev/null
+++ b/Build-tools/mysql-copyright-2
@@ -0,0 +1,162 @@
+#!/usr/bin/perl -i
+
+# Add the header to all given files
+# This program asumes that after the copyright there is a empty line
+#
+
+$opt_v= 0;
+require "getopts.pl";
+Getopts("v") || die "Aborted";
+
+@copyright=
+(
+ "Copyright (C) 2000 MySQL AB & MySQL Finland AB",
+ "",
+ "This software is distributed with NO WARRANTY OF ANY KIND. No author or",
+ "distributor accepts any responsibility for the consequences of using it, or",
+ "for whether it serves any particular purpose or works at all, unless he or",
+ "she says so in writing. Refer to the LICENSE file for details.",
+ "",
+ "Every copy of this file must include a copy of the License, normally in a",
+ "plain ASCII text file named LICENSE. The License grants you the right to",
+ "copy, modify and redistribute this file, but only under certain conditions",
+ "described in the License. Among other things, the License requires that",
+ "the copyright notice and this notice be preserved on all copies"
+);
+
+while (<>)
+{
+ if (!$first++)
+ {
+ add_copyright($_);
+ }
+ if ($in_copyright)
+ {
+ $in_copyright=check_in_copyright($_);
+ }
+ print $_ if (!$in_copyright);
+ if (eof)
+ {
+ $first=0; $in_copyright=1;
+ }
+}
+
+exit 0;
+
+sub add_copyright
+{
+ my ($line)=@_;
+ my ($row);
+
+ $in_copyright= $line =~ /copyright/i;
+ $found_end_copyright=$skip_this_line=0;
+
+ if (!($line =~ /Monty/ || $line =~ /MySQL AB/))
+ {
+ $in_copyright=0;
+ print STDERR "File with unknown copyright ", $ARGV,"\n" if ($opt_v);
+ return;
+ }
+ else
+ {
+ print STDERR "To be Changed: ", $ARGV, "\n" if ($opt_v);
+ }
+ if ($ARGV =~ /Makefile/ ||
+ $ARGV =~ /makefile/)
+ { # Makefile
+ $start_copyright="# ";
+ $line_copyright= "# ";
+ $end_copyright= "";
+ }
+ elsif ($line =~ "^#!")
+ { # Shell script
+ $start_copyright="# ";
+ $line_copyright= "# ";
+ $end_copyright= "";
+ $skip_this_line=1;
+ print $line;
+ while ($line=<>) # Copy all until new line or copyright
+ {
+ if ($line =~ /copyright/i)
+ {
+ last;
+ }
+ print $line;
+ last if ($line =~ /^(\s|\n)*$/);
+ }
+ $in_copyright=1;
+ }
+ elsif ($ARGV =~ /\.c$/ ||
+ $ARGV =~ /\.cc$/ ||
+ $ARGV =~ /\.h$/ ||
+ $ARGV =~ /\.yy$/ ||
+ $ARGV =~ /-x86\.s$/)
+ {
+ $start_copyright="/* ";
+ $line_copyright= " ";
+ $end_copyright= " */";
+ }
+ elsif ($ARGV =~ /\.s$/)
+ {
+ $start_copyright="! ";
+ $line_copyright= "! ";
+ $end_copyright= "";
+ }
+ elsif ($ARGV =~ /\.asm$/)
+ {
+ $start_copyright="; ";
+ $line_copyright= "; ";
+ $end_copyright= "";
+ }
+ else # Unknown file
+ {
+ $in_copyright=0;
+ print STDERR "Unknown file type ", $ARGV,"\n" if ($opt_v);
+ return;
+ }
+ $data=\@copyright;
+
+ for ($row=0 ; $row <= $#$data ; $row++)
+ {
+ print $row == 0 ? $start_copyright : $line_copyright;
+ print $data->[$row];
+ print $row != $#$data ? "\n" : $end_copyright . "\n";
+ }
+ print "\n";
+ $end_copyright =~ /\s*([^\s]+)\s*(([^\s].*)|)$/; # Remove pre and post spaces
+}
+
+#
+# Return 1 if in copyright
+#
+
+sub check_in_copyright
+{
+ my ($line)=@_;
+ $line =~ /^(.*[^\s])(\s|\n|\r)*$/; # Remove end space and newline
+ $line=$1;
+ if (!$line)
+ {
+ $found_end_copyright=1 if (!length($end_copyright));
+ return 1; # Skip empty lines
+ }
+ return 0 if ($found_end_copyright);
+ if ($end_copyright)
+ {
+ if (index($line,$end_copyright) != -1)
+ {
+ $found_end_copyright=1;
+ }
+ return 1;
+ }
+ if ($line =~ /copyright/i || index($line . " ",$line_copyright) == 0)
+ {
+ return 1;
+ }
+ if ($skip_this_line)
+ {
+ $skip_this_line=0;
+ return 1;
+ }
+ return 0; # Can't trust the empty copyright line yet
+}
diff --git a/Build-tools/newest b/Build-tools/newest
new file mode 100644
index 00000000000..367c9bd1f1b
--- /dev/null
+++ b/Build-tools/newest
@@ -0,0 +1,116 @@
+#!/usr/bin/perl
+
+package NEWEST;
+
+use Getopt::Long;
+use File::Basename;
+
+my $src_dir;
+my $basename;
+my $type = "tar.gz";
+my $versions;
+my $help;
+my %KEEPER;
+
+
+GetOptions(
+ "src_dir=s" => \$src_dir,
+ "basename=s" => \$basename,
+ "type=s" => \$type,
+ "versions!" => \$versions,
+ "help!" => \$help
+ );
+
+if (!defined $src_dir || !defined $basename) {
+ $help = 1;
+}
+
+if ($help) {
+ &help();
+ exit;
+}
+
+
+&extract_version(\$src_dir, \$basename, \$type, \%KEEPER);
+&print_max(\%KEEPER, \$type, \$versions, &find_max(\%KEEPER));
+
+
+
+sub extract_version {
+ my $src_dir = shift;
+ my $basename = shift;
+ my $type = shift;
+ my $KEEPER = shift;
+
+ while (glob("$${src_dir}/$${basename}*")) {
+ my $base = basename("$_",".$${type}");
+ my @ver = split /-/, $base;
+ my @nums = split /\./, $ver[$#ver];
+
+ my $new;
+ for (my $i=0; $i<$#nums+1; $i++) {
+ $new =~ s/^([0-9]*)([a-zA-Z]*)$/$1/;
+ $new .= 10000+$nums[$i];
+ $new .= $2;
+ }
+ $KEEPER->{"$new"} = [$base,$ver[$#ver]];
+ }
+
+ return;
+}
+
+
+
+sub find_max {
+ my $KEEPER = shift;
+
+ return reverse sort (keys %$KEEPER);
+}
+
+
+
+sub print_max {
+ my $KEEPER = shift;
+ my $type = shift;
+ my $versions = shift;
+ my $max_key = shift;
+
+ if ($${versions}) {
+ print "$KEEPER->{$max_key}->[1]\n";
+ }
+ else {
+ print "$KEEPER->{$max_key}->[0]" . ".$${type}\n";
+ }
+
+ return;
+}
+
+
+
+sub help {
+
+ print qq("newest" finds the tarball in a given directory with the newest version number
+and returns it's filename. "newest" is meant to be embedded in UNIX shell
+scripts.
+
+Usage:
+
+newest -(src_dir | s) /path/to/dir/with/tarballs
+ -(basename | b) BaseName (ex. BaseName-2.10.tar.gz)
+ -(type | t) Type of file (default: tar.gz)
+ -(versions | v) Print only version information
+ -(help | h) Prints usage help
+
+Ex: \$ /opt/bin/newest -s /opt/incoming/pm_modules -b Data-Dumper
+ Data-Dumper-2.101.tar.gz
+
+Both arguments, '-s' and '-b' are required; '-t' and '-v' are optional.
+
+);
+
+ return;
+}
+
+
+
+
diff --git a/Docs/.cvsignore b/Docs/.cvsignore
new file mode 100644
index 00000000000..777efb1eb7b
--- /dev/null
+++ b/Docs/.cvsignore
@@ -0,0 +1,40 @@
+COPYING
+COPYING.LIB
+INSTALL-BINARY
+Makefile
+Makefile.in
+Manual-updates
+before-gpl-changes-manual.texi
+include.texi
+manual-before-gpl.texi
+manual-tmp.aux
+manual-tmp.cp
+manual-tmp.fn
+manual-tmp.ky
+manual-tmp.log
+manual-tmp.pdf
+manual-tmp.pg
+manual-tmp.texi
+manual-tmp.toc
+manual-tmp.tp
+manual-tmp.vr
+manual.aux
+manual.cp
+manual.cps
+manual.fn
+manual.fns
+manual.html
+manual.ky
+manual.log
+manual.pdf
+manual.pg
+manual.toc
+manual.tp
+manual.txt
+manual.vr
+manual_a4.ps
+manual_a4.ps.gz
+manual_letter.ps
+manual_letter.ps.gz
+manual_toc.html
+mysql.info
diff --git a/Docs/Attic/myisam.doc b/Docs/Attic/myisam.doc
new file mode 100644
index 00000000000..e0b56e79548
--- /dev/null
+++ b/Docs/Attic/myisam.doc
@@ -0,0 +1,901 @@
+#.# mi_changed()
+
+int mi_is_changed(MI_INFO *mip)
+
+#.#.1 Description
+
+Reports whether any changes have occurred to the MyISAM table associated with mip.
+
+For information only, I notice that mi_changed() is a wrapper around this: (_mi_readinfo(info,F_RDLCK,1)).
+
+#.#.2 Return values
+
+Zero if the table has not changed. Non-zero (-1) if the table has changed.
+
+#.#.3 Errors
+
+Nothing specific yet identified.
+
+#.#.4 Examples
+
+if( mi_changed( mip )) printf( "file has changed" );
+====================
+#.# mi_close()
+
+int mi_close( MI_INFO *mip )
+
+#.#.1 Description
+
+Closes the MyISAM table associated with mip, a structure created by mi_open().
+Any locks on that file pointer are released.
+The MI_INFO structure mip is released.
+See also mi_panic() which can be used to close all open MyISAM files.
+mip is a pointer to the MI_INFO returned by mi_open().
+
+#.#.2 Return values
+
+Zero if successful. Non-zero if an error occurred.
+
+#.#.3 Errors
+
+Nothing specific yet identified.
+
+#.#.4 Examples
+
+result = mi_close(mip);
+====================
+#.# mi_create()
+
+int mi_create( const char *name, uint keys, MI_KEYDEF *keydefs,
+ uint columns, MI_COLUMNDEF *recinfo,
+ uint uniques, MI_UNIQUEDEF *uniquedefs,
+ MI_CREATE_INFO *ci, uint flags )
+
+#.#.1 Description
+
+Creates a new MyISAM table.
+Documentation for this function is not complete because I am not using mi_create directly.
+Because all our tables are used with MySQL, I create new tables using SQL "CREATE TABLE" via the C API.
+See MySQL Appendix B "Choosing a table type".
+MyISAM allows about 32 indexes. However the official MySQL limit is 16 until MySQL 4.0.
+
+The parameters are specified as follows:
+name The file pathname, excluding the suffixes.
+keys Number of indexes.
+keydefs A MI_KEYDEF structure containing key definitions.
+HA_KEYTYPE_END=0
+HA_KEYTYPE_TEXT=1, /* Key is sorted as letters */
+HA_KEYTYPE_BINARY=2, /* Key is sorted as unsigned chars
+HA_KEYTYPE_SHORT_INT=3,
+HA_KEYTYPE_LONG_INT=4,
+HA_KEYTYPE_FLOAT=5,
+HA_KEYTYPE_DOUBLE=6,
+HA_KEYTYPE_NUM=7, /* Not packed num with pre-space *
+HA_KEYTYPE_USHORT_INT=8,
+HA_KEYTYPE_ULONG_INT=9,
+HA_KEYTYPE_LONGLONG=10,
+HA_KEYTYPE_ULONGLONG=11,
+HA_KEYTYPE_INT24=12,
+HA_KEYTYPE_UINT24=13,
+HA_KEYTYPE_INT8=14,
+HA_KEYTYPE_VARTEXT=15, /* Key is sorted as letters */
+HA_KEYTYPE_VARBINARY=16 /* Key is sorted as unsigned chars
+columns The number of columns.
+recinfo A MI_COLUMNDEF structure containing column definitions.
+uniques The number of unique indexes.
+uniquedefs A MI_UNIQUEDEF structure containing unique index definitions.
+ci A MI_CREATE_INFO structure containing column definitions.
+flags a pointer to the record buffer that will contain the row.
+
+#.#.2 Return values
+
+Zero if the create is successful. Non-zero if an error occurs.
+
+#.#.3 Errors
+
+HA_WRONG_CREATE_OPTION
+ means that some of the arguments was wrong.
+appart from the above one can get any unix error that one can get from open(), write() or close().
+
+#.#.4 Examples
+
+if (mi_create(fn_format(name,filename,"",MI_NAME_IEXT, 4+ (opt_follow_links ? 16 : 0)),
+ share.base.keys - share.state.header.uniques, keyinfo, share.base.fields, recdef,
+ share.state.header.uniques, uniquedef, &create_info, HA_DONT_TOUCH_DATA))
+====================
+#.# mi_delete()
+
+int mi_delete(MI_INFO *mip, const byte *buf)
+
+#.#.1 Description
+
+Removes a row from a MyISAM table.
+
+mip is an MI_INFO pointer to the open handle.
+buf is the buffer containing the row that is to be deleted.
+
+#.#.2 Return values
+
+Zero if successful. Non-zero if an error occurred.
+
+#.#.3 Errors
+
+EACCES
+File was opened read-only.
+HA_ERR_KEY_NOT_FOUND
+No database read
+HA_ERR_RECORD_CHANGED
+The buffer contents were different to the actual row contents.
+HA_ERR_CRASHED
+The indexing has crashed.
+
+#.#.4 Examples
+
+if (mi_delete(file,read_record))
+====================
+#.# mi_delete_all()
+
+int mi_delete_all_rows(MI_INFO *mip)
+#.#.1 Description
+
+Removes ALL rows from a MyISAM table.
+This only clears the status information. The files are not truncated.
+
+mip is an MI_INFO pointer to the open handle.
+
+#.#.2 Return values
+
+Zero if successful. Non-zero if an error occurred.
+
+#.#.3 Errors
+
+EACCES
+File was opened read-only.
+
+#.#.4 Examples
+
+error = mi_delete_all( mip );
+====================
+#.# mi_extra()
+
+int mi_extra(MI_INFO *info, enum ha_extra_function function)
+
+#.#.1 Description
+
+Controls some special MyISAM modes.
+
+The function parameter can be:
+ HA_EXTRA_NORMAL=0 Optimize for space (def)
+HA_EXTRA_QUICK=1 Optimize for speed
+HA_EXTRA_RESET=2 Reset database to after open
+HA_EXTRA_CACHE=3 Cash record in HA_rrnd()
+HA_EXTRA_NO_CACHE=4 End cacheing of records (def)
+HA_EXTRA_NO_READCHECK=5 No readcheck on update
+HA_EXTRA_READCHECK=6 Use readcheck (def)
+HA_EXTRA_KEYREAD=7 Read only key to database
+HA_EXTRA_NO_KEYREAD=8 Normal read of records (def)
+HA_EXTRA_NO_USER_CHANGE=9 No user is allowed to write
+HA_EXTRA_KEY_CACHE=10
+HA_EXTRA_NO_KEY_CACHE=11
+HA_EXTRA_WAIT_LOCK=12 Wait until file is avalably (def)
+HA_EXTRA_NO_WAIT_LOCK=13 If file is locked, return quickly
+HA_EXTRA_WRITE_CACHE=14 Use write cache in ha_write()
+HA_EXTRA_FLUSH_CACHE=15 flush write_record_cache
+HA_EXTRA_NO_KEYS=16 Remove all update of keys
+HA_EXTRA_KEYREAD_CHANGE_POS=17 Keyread, but change pos
+xxxxchk -r must be used
+HA_EXTRA_REMEMBER_POS=18 Remember pos for next/prev
+HA_EXTRA_RESTORE_POS=19
+HA_EXTRA_REINIT_CACHE=20 init cache from current record
+HA_EXTRA_FORCE_REOPEN=21 Datafile have changed on disk
+HA_EXTRA_FLUSH Flush tables to disk
+HA_EXTRA_NO_ROWS Don't write rows
+
+#.#.2 Return values
+
+Zero if successful. Non-zero if an error occurred.
+
+#.#.3 Errors
+
+Nothing specific yet identified.
+
+#.#.4 Examples
+
+====================
+#.# mi_make_application_key()
+
+void mi_make_application_key(register MI_INFO *mip, uint keynr, uchar *key, const byte *record)
+
+#.#.1 Description
+
+Construct a key string for the given index, from the provided record buffer.
+Monty wrote this function to: "to create an external key for an application from your record. It should work for all keys except BLOB and true VARCHAR (not supported by MySQL yet), but I don't think you have either of these!" He just wrote it, so I expect it to included in releases from about 3.23.15. ??
+
+The parameters are:
+A MI_INFO pointer mip.
+The index number keynr.
+The buffer to contain the formatted key string key.
+The record buffer record.
+
+#.#.2 Return values
+
+The byte length of the created key string.
+
+#.#.3 Errors
+
+Nothing specific yet identified.
+
+#.#.4 Examples
+
+uint new_length=_mi_make_application_key(info,i,new_key,newrec);
+====================
+#.# mi_open()
+
+MI_INFO *mi_open( const char *name, int mode, uint handle_locking )
+
+#.#.1 Description
+
+Opens a MyISAM file for processing.
+mi_open() returns a MI_INFO structure pointer that you must use in subsequent operations on the MyISAM file. MI_INFO structures are defined in "myisam/myisamdef.h", which is included in your program via your include myisam.h - used by both MyISAM and MySQL.
+The name parameter must contain a null-terminated string without an extension, which is the filename of the MyISAM file to be processed.
+There is no automatic positioning nor key selection.
+Caution! It is extremely important to close MyISAM files after processing has finished, especially on operating systems without file-locking system calls. Failure to close MyISAM files using mi_close() or mi_panic() leaves the files locked on systems without these system calls.
+
+name Is the name of the file.
+mode Is the access mode parameter. Use one of the following access mode parameters:
+O_RDONLY to open for input only.
+O_RDWR opens the file for output.
+O_SHARE opens the file for both input and output. When used, O_SHARE should be added to O_RDONLY and O_RDWR.
+handle_locking is the locking mode parameter. Select from the following:
+HA_OPEN_ABORT_IF_LOCKED (0) exit with error if database is locked
+HA_OPEN_WAIT_IF_LOCKED (1) wait if database is locked
+HA_OPEN_IGNORE_IF_LOCKED (2) continue, but count-vars in st_i_info may be wrong. count-vars are automatically fixed after next isam request.
+
+#.#.2 Return values
+
+A pointer to MI_INFO for successfully open file. NULL if unsuccessful, when my_errno will contain the error code.
+
+#.#.3 Errors
+
+HA_ERR_OLD_FILE
+wrong options
+HA_ERR_CRASHED
+wrong header
+HA_ERR_UNSUPPORTED
+too many keys or keys too long
+HA_ERR_END_OF_FILE
+empty file?
+MY_FILE_ERROR
+?
+EACCES
+cannot open in write mode
+ENOMEM
+not enough memory
+Otherwise one has probably got a fatal error like HA_ERR_CRASHED or some I-O related error from the Operating System.
+
+#.#.4 Examples
+
+pfm = mi_open("/D1/adir/perform",O_SHARE | O_RDONLY, HA_OPEN_ABORT_IF_LOCKED);
+====================
+#.# mi_panic()
+
+int mi_panic( enum ha_panic_function flag )
+
+#.#.1 Description
+
+mi_panic() is used to close any MyISAM files before exiting, or to safeguard file updates when using a shell.
+The flag parameter specifies the function and can be:
+HA_PANIC_CLOSE Close all databases (MyISAM files).
+HA_PANIC_WRITE Unlock and write status, flushing all buffers to disk.
+HA_PANIC_READ Lock and read key info per HA_PANIC_WRITE.
+
+The CLOSE function also writes buffers before it closes and turns logging off by closing the log file..
+See also my_end(), a debugging function.
+One use is to do a WRITE, use a shell to run myisamchk, then do a READ.
+
+#.#.2 Return values
+
+Zero if successful. Non-zero if an error occurred.
+
+#.#.3 Errors
+
+Nothing specific yet identified.
+
+#.#.4 Examples
+
+result = mi_panic(HA_PANIC_CLOSE);
+====================
+#.# mi_position()
+
+my_off_t mi_position(MI_INFO *mip)
+
+#.#.1 Description
+
+Gets the byte position in the file of the last record read.
+
+mip is an MI_INFO pointer to the open handle.
+
+#.#.2 Return values
+
+Byte position if successful. Zero if an error occurred. ??
+
+#.#.3 Errors
+
+HA_OFFSET_ERROR
+if there wasn't any active row.
+
+#.#.4 Examples
+
+currentpos = mi_position( mip );
+====================
+#.# mi_rfirst()
+
+int mi_rfirst(MI_INFO *mip , byte *buf, int inx)
+
+#.#.1 Description
+
+Reads the first row in the MyISAM file according to the specified index.
+If one want's to read rows in physical sequences, then one should instead use mi_scan() or mi_rrnd().
+
+mip is an MI_INFO pointer to the open handle.
+buf is the record buffer that will contain the row.
+Inx is the index (key) number, which must be the same as currently selected.
+
+mi_rfirst() works by setting the current position mip->lastpos to HA_OFFSET_ERROR (undefined) then calling mi_rnext().
+
+#.#.2 Return values
+
+Zero if successful. Non-zero if an error occurred.
+
+#.#.3 Errors
+
+HA_ERR_END_OF_FILE
+End of file
+Otherwise one has probably got a fatal error like HA_ERR_CRASHED or some I-O related error from the Operating System.
+
+#.#.4 Examples
+
+error = mi_rfirst( mip, buffer, keynum);
+====================
+#.# mi_rkey()
+
+int mi_rkey(MI_INFO *mip, byte *buf, int inx, const byte *key, uint key_len, enum ha_rkey_function search_flag)
+
+#.#.1 Description
+
+Reads the next row after the last row read, using the current index.
+If one want's to read rows in physical sequences, then one should instead use mi_scan() or mi_rrnd().
+
+mip is an MI_INFO pointer to the open handle.
+buf is the record buffer that will contain the row.
+Inx is the index (key) number, which must be the same as currently selected.
+
+If (mip->lastpos) is HA_OFFSET_ERROR (undefined) then mi_rnext() gives the first row.
+If you specify a different index number than the last read used, you will get an error.
+If the last (current) row has been changed since we read it, mi_rnext() will reposition from the position where that row WAS, not where it is now. (This behaviour is similar to CISAM and better than used in Codebase.)
+
+mi_extra(HA_EXTRA_KEYREAD) can be called first, to cause mi_rkey to read the key but not the record. Then call mi_extra(HA_EXTRA_NO_KEYREAD) to resume normal behaviour.
+
+#.#.2 Return values
+
+Zero if successful. Non-zero if an error occurred.
+
+#.#.3 Errors
+
+HA_ERR_END_OF_FILE
+End of file
+Otherwise one has probably got a fatal error like HA_ERR_CRASHED or some I-O related error from the Operating System.
+
+#.#.4 Examples
+
+error = mi_rnext( mip, buffer, keynum );
+====================
+#.# mi_rlast()
+
+int mi_rlast(MI_INFO *mip , byte *buf, int inx)
+
+#.#.1 Description
+
+Reads the last row in the MyISAM file according to the specified index.
+If one want's to read rows in physical sequences, then one should instead use mi_scan() or mi_rrnd().
+mip is an MI_INFO pointer to the open handle.
+buf is a pointer to the record buffer that will contain the row.
+Inx is the index (key) number, which must be the same as currently selected.
+
+mi_rlast() works by setting the current position (mip->lastpos) to HA_OFFSET_ERROR (undefined) then calling mi_rprev().
+
+#.#.2 Return values
+
+Zero if successful. Non-zero if an error occurred.
+
+#.#.3 Errors
+
+HA_ERR_END_OF_FILE
+End of file
+Otherwise one has probably got a fatal error like HA_ERR_CRASHED or some I-O related error from the Operating System.
+
+#.#.4 Examples
+
+error = mi_rlast( mip, buffer, keynum);
+====================
+#.# mi_rnext()
+
+int mi_rnext(MI_INFO *mip , byte *buf, int inx )
+
+#.#.1 Description
+
+Reads the next row after the last row read, using the current index.
+If one want's to read rows in physical sequences, then one should instead use mi_scan() or mi_rrnd().
+
+mip is an MI_INFO pointer to the open handle.
+buf is the record buffer that will contain the row.
+Inx is the index (key) number, which must be the same as currently selected.
+
+If (mip->lastpos) is HA_OFFSET_ERROR (undefined) then mi_rnext() gives the first row.
+If you specify a different index number than the last read used, you will get an error.
+If the last (current) row has been changed since we read it, mi_rnext() will reposition from the position where that row WAS, not where it is now. (This behaviour is similar to CISAM and better than used in Codebase.)
+
+#.#.2 Return values
+
+Zero if successful. Non-zero if an error occurred.
+
+#.#.3 Errors
+
+HA_ERR_END_OF_FILE
+End of file
+Otherwise one has probably got a fatal error like HA_ERR_CRASHED or some I-O related error from the Operating System.
+
+#.#.4 Examples
+
+error = mi_rnext( mip, buffer, keynum );
+====================
+#.# mi_rrnd()
+
+int mi_rrnd( MI_INFO *mip , byte *buf, my_off_t filepos )
+
+#.#.1 Description
+
+Reads a row based on physical position.
+
+Position can be calculated from record number only when fixed record lengths are used:
+position = mip->s.pack.header_length + recnum * mip->s->base.reclength.
+If filepos= HA_OFFSET_ERROR then it reads the next row.
+And if (mip->lastpos == HA_OFFSET_ERROR) it reads the first row.
+
+mip is an MI_INFO pointer to the open handle.
+buf is the record buffer that will contain the row.
+filepos is the byte position in the file of the required record.
+
+#.#.2 Return values
+
+Zero if successful. Non-zero if an error occurred.
+
+#.#.3 Errors
+
+HA_ERR_RECORD_DELETED
+A deleted record was read.
+HA_ERR_END_OF_FILE
+End of file.
+
+#.#.4 Examples
+
+error = mi_rrnd( mip, buffer, mip->nextpos );
+====================
+#.# mi_rprev()
+
+int mi_rprev(MI_INFO *mip , byte *buf, int inx)
+
+#.#.1 Description
+
+Reads the row previous to the last row read, using the current index.
+If one wants to read rows in physical sequences, then one should instead use mi_scan() or mi_rrnd().
+
+If (mip->lastpos) is HA_OFFSET_ERROR (undefined) then mi_rnext() gives the last row in the index.
+If you specify a different index number than the last read used, you will get an error.
+If the last (current) row has been changed since we read it, mi_rprev() will reposition from the position where that row WAS, not where it is now. This behaviour is similar to CISAM and better than used in Codebase.
+
+mip is an MI_INFO pointer to the open handle.
+buf is the record buffer that will contain the row.
+Inx is the index (key) number, which must be the same as currently selected.
+
+#.#.2 Return values
+
+Zero if successful. Non-zero if an error occurred.
+
+#.#.3 Errors
+
+HA_ERR_END_OF_FILE
+End of file
+Otherwise one has probably got a fatal error like HA_ERR_CRASHED or some I-O related error from the Operating System.
+
+#.#.4 Examples
+
+error = mi_rprev( mip, buffer, keynum );
+====================
+#.# mi_rsame()
+
+int mi_rsame(MI_INFO *mip, byte *buf, int inx)
+
+#.#.1 Description
+
+Reads the current row to get its latest contents. This is useful to refresh the record buffer in case someone else has changed it.
+If inx is negative it reads by position. If inx is >= 0 it reads by key.
+With mi_rsame() one can switch to use any other index for the current row. This is good if you have a user application that lets the user do 'read-next' on a row. In this case, if the user want's to start scanning on another index, one simply has to do a mi_rsame() on the new index to activate this.
+
+mip is an MI_INFO pointer to the open handle.
+buf is the record buffer that will contain the row.
+inx is the index (key) number, or a negative number to select read by position not index. Maybe the negative number has to be (-1) to achieve this behaviour.
+
+#.#.2 Return values
+
+Zero if successful. Non-zero if an error occurred.
+
+#.#.3 Errors
+
+HA_ERR_WRONG_INDEX
+an incorrect index number was supplied
+HA_ERR_KEY_NOT_FOUND
+info->lastpos was not defined, or the record was already deleted.
+
+#.#.4 Examples
+
+error = mi_rsame( m5mip, rec_ptr, keynum );
+====================
+#.# mi_scan()
+
+int mi_scan(MI_INFO *mip, byte *buf)
+
+#.#.1 Description
+
+Reads the next row by physical position.
+
+Deleted rows are bypassed.
+mi_scan() uses a function pointer "read_rnd" that uses either lower level static or dynamic read functions, positioning from mip->nextpos. Read_rnd is defined in mi_open() depending if the table is Static (read*static - see mi_statrec.c), Compressed (read*pack - see mi_packrec.c), or Space packed or Blobs (read*dynamic - see mi_dynrec.c).
+See also mi_scan_init() which initialises ready to mi_scan() through the whole table.
+
+mip is an MI_INFO pointer to the open handle.
+buf is the record buffer that will contain the row.
+
+#.#.2 Return values
+
+Zero if successful. Non-zero if an error occurred.
+
+#.#.3 Errors
+
+HA_ERR_END_OF_FILE
+End of file
+Otherwise one has probably got a fatal error like HA_ERR_CRASHED or some I-O related error from the Operating System.
+
+#.#.4 Examples
+
+error = mi_scan( mip, recbuff );
+====================
+#.# mi_scan_init()
+
+int mi_scan_init(MI_INFO *mip[SB1])
+
+#.#.1 Description
+
+Initialises ready to mi_scan() through all rows.
+
+mip is an MI_INFO pointer to the open handle.
+
+#.#.2 Return values
+
+Zero if successful. Non-zero if an error occurred.
+
+#.#.3 Errors
+
+Nothing specific yet identified.
+
+#.#.4 Examples
+
+====================
+#.# mi_status()
+
+int mi_status(MI_INFO *mip, MI_ISAMINFO *x, uint flag)
+
+#.#.1 Description
+
+Gets information about the table.
+It is used to get/fill the MI_ISAMINFO struct with statistics data about the MySQL server. One can get information of the number of active rows, delete rows, file lengths...
+
+mip is an MI_INFO pointer to the open handle.
+flag is one of the following:
+HA_STATUS_POS Return position
+HA_STATUS_NO_LOCK Don't use external lock
+HA_STATUS_TIME Return update time
+HA_STATUS_CONST Return constants value
+HA_STATUS_VARIABLE
+HA_STATUS_ERRKEY
+HA_STATUS_AUTO
+
+#.#.2 Return values
+
+Zero.
+
+#.#.3 Errors
+
+Nothing specific yet identified.
+
+#.#.4 Examples
+
+====================
+#.# mi_update()
+
+int mi_update( MI_INFO *mip, const byte *oldbuf, byte *newbuf)
+
+#.#.1 Description
+
+Updates the contents of the current record.
+By default you must supply an oldbuf record buffer with the current record contents. This is compared with the file as a guard in case someone else has changed the record in the meantime. *
+
+mip is an MI_INFO pointer to the open handle.
+oldbuf is the record buffer that contains the current record contents.
+newbuf is the record buffer that contains the new record contents.
+
+*Sometimes you might want to force an update without checking whether another user has changed the record since you last read it. This is somewhat dangerous, so it should ideally not be used. That can be accomplished by wrapping the mi_update() call in two calls to mi_extra(), using these functions:
+HA_EXTRA_NO_READCHECK=5 No readcheck on update
+HA_EXTRA_READCHECK=6 Use readcheck (def)
+
+#.#.2 Return values
+
+Zero if successful. Non-zero if an error occurred.
+
+#.#.3 Errors
+
+EACCES
+The file was opened for read-only access.
+HA_ERR_RECORD_CHANGED
+ When mi_update() read the current record contents before updating, it differed from oldbuf.
+HA_ERR_CRASHED
+Key could not be found ??
+HA_ERR_FOUND_DUPP_KEY
+HA_ERR_RECORD_FILE_FULL
+
+#.#.4 Examples
+
+error = mi_update( mip, oldbuf, newbuf );
+====================
+#.# mi_write()
+
+int mi_write( MI_INFO *mip, byte *record)
+
+#.#.1 Description
+
+Writes a row to a MyISAM table.
+
+mip is an MI_INFO pointer to the open handle.
+The record contents are supplied in buf record buffer.
+
+#.#.2 Return values
+
+Zero if successful. Non-zero if an error occurred.
+
+#.#.3 Errors
+
+HA_ERR_FOUND_DUPP_KEY
+A record already existed with a unique key same as this new record.
+HA_ERR_RECORD_FILE_FULL
+The error is given if you hit a system limit or if you try to create more rows in a table that you reserverd room for with mi_create().
+ENOSPC
+The disk is full.
+EACCES
+The file was opened for read-only access.
+
+#.#.4 Examples
+
+error = mi_write( m5mip, recbuf );
+====================
+#.# my_end()
+
+void my_end(int infoflag)
+
+#.#.1 Description
+
+Shows debugging information about open MyISAM handles.
+my_end() exists primarily for MyISAM debugging.
+It would not normally be used in a production environment.
+It can give a nice summary of how you have used my_xxx() functions.
+It can be used to check that you have closed all files that you have opened.
+
+infoflag is the list function and can be:
+MY_CHECK_ERROR List which MyISAM handles are open.
+MY_GIVE_INFO Show runtime information.
+
+#.#.2 Return values
+
+Void
+
+#.#.3 Errors
+
+Nothing specific yet identified.
+
+#.#.4 Examples
+
+my_end(MY_CHECK_ERROR | MY_GIVE_INFO);
+====================
+#.# my_init()
+
+void my_init( void )
+
+#.#.1 Description
+
+Performs MyISAM initialisation for program startup, particularly if using threads.
+
+If using threads, be sure to call my_init() at start of program. (CFS does this in XPOPEN.) It is also safe to call my_init() when not using threads.
+
+#.#.2 Return values
+
+void
+Sometimes my_errno might be meaningful if a warning is generated during debugging.
+
+#.#.3 Errors
+
+Nothing specific yet identified.
+
+#.#.4 Examples
+
+my_init();
+====================
+#.# init_key_cache()
+
+int init_key_cache( long int use_mem, (uint) reserve_mem;
+
+#.#.1 Description
+
+Starts and controls caching of keys. Call init_key_cache() to reserve memory for key caching and to start the caching. (CFS does this in XPOPEN if MYCACHE is defined (regular size), or MYCACHELARGE or MYCACHESMALL.)
+
+Provide use_mem the number of bytes of memory to use for key caching by this process.
+reserve_mem should be 0. This is just for very old systems with very little memory.
+
+#.#.2 Return values
+
+The number of 1kb memory blocks now allocated to key caching. Zero if key caching cannot be started (check my_errno), or key caching was already active.
+
+#.#.3 Errors
+
+Nothing specific yet identified.
+
+#.#.4 Examples
+
+Blocks = init_key_cache( 65536L, IO_SIZE*4*10 );
+====================
+#.# _mi_make_key()
+
+uint _mi_make_key( MI_INFO *mip, uint keynr, uchar *key, const char *record, my_off_t filepos)
+
+#.#.1 Description
+
+Construct a key string for the given index, from the provided record buffer.
+??? When packed records are used ...
+This is an internal function, not for use by applications. Monty says: "This can't be used to create an external key for an application from your record."
+See mi_make_application_key() for a similar function that is useable by applications.
+
+The parameters are:
+A MI_INFO pointer mip.
+The index number keynr.
+The buffer to contain the formatted key string key.
+The record buffer record.
+??? A file position filepos or zero.
+
+#.#.2 Return values
+
+The byte length of the created key string.
+
+#.#.3 Errors
+
+Nothing specific yet identified.
+
+#.#.4 Examples
+
+uint new_length=_mi_make_key(info,i,new_key,newrec,pos);
+====================
+#.# _mi_print_key()
+
+void _mi_print_key(FILE *stream, MI_KEYSEG *keyseg, const uchar *key, uint length)
+
+#.#.1 Description
+
+Prints a key in a user understandable format.
+This is an internal function for debugging, not for use by applications.
+??? Not yet fully documented. I just include it here so that I know it exists.
+
+#.#.2 Return values
+
+A readable print of the key contents goes to the specified output.
+
+#.#.3 Errors
+
+Nothing specific yet identified.
+
+#.#.4 Examples
+
+_mi_print_key(stdout,share->keyinfo[info->errkey].seg,info->lastkey, USE_WHOLE_KEY);
+====================
+APPENDIX B Choosing a table type
+(excerpt from manual.txt in MySQL 3.23.8-alpha)
+
+With MySQL you can currently (version 3.23.5) choose between four usable table formats from a speed point of view.
+
+Static (Fixed-length) table characteristics
+* This is the default format. It's used when the table contains no `VARCHAR', `BLOB' or `TEXT' columns.
+* All `CHAR', `NUMERIC' and `DECIMAL' columns are space-padded to the column width.
+* Very quick.
+* Easy to cache.
+* Easy to reconstruct after a crash, because records are located in fixed positions.
+* Doesn't have to be reorganized (with `myisamchk') unless a huge number of records are deleted and you want to return free disk space to the operating system.
+* Usually requires more disk space than dynamic tables.
+
+Dynamic table characteristics
+* This format is used if the table contains any `VARCHAR', `BLOB' or `TEXT' columns.
+* All string columns are dynamic (except those with a length less than 4).
+* Each record is preceded by a bitmap indicating which columns are empty (`''') for string columns, or zero for numeric columns (this isn't the same as columns containing `NULL' values). If a string column has a length of zero after removal of trailing spaces, or a numeric column has a value of zero, it is marked in the bit map and not saved to disk. Non-empty strings are saved as a length byte plus the string contents.
+* Usually takes much less disk space than fixed-length tables.
+* Each record uses only as much space as is required. If a record becomes larger, it is split into as many pieces as required. This results in record fragmentation.
+* If you update a row with information that extends the row length, the row will be fragmented. In this case, you may have to run `myisamchk -r' from time to time to get better performance. Use `myisamchk -ei tbl_name' for some statistics.
+* Not as easy to reconstruct after a crash, because a record may be fragmented into many pieces and a link (fragment) may be missing.
+* The expected row length for dynamic sized records is:
+3
++ (number of columns + 7) / 8
++ (number of char columns)
++ packed size of numeric columns
++ length of strings
++ (number of NULL columns + 7) / 8
+There is a penalty of 6 bytes for each link. A dynamic record is linked whenever an update causes an enlargement of the record.
+Each new link will be at least 20 bytes, so the next enlargement will probably go in the same link. If not, there will be another link. You may check how many links there are with `myisamchk -ed'. All links may be removed with `myisamchk -r'.
+
+Compressed table characteristics
+* A read-only table made with the `myisampack' utility. All customers with extended *MySQL* email support are entitled to a copy of `myisampack' for their internal usage.
+* The uncompress code exists in all *MySQL* distributions so that even customers who don't have `myisampack' can read tables that were compressed with `myisampack'
+* Takes very little disk space. Minimises disk usage.
+* Each record is compressed separately (very little access overhead). The header for a record is fixed (1-3 bytes) depending on the biggest record in the table. Each column is compressed differently. Some of the compression types are:
+- There is usually a different Huffman table for each column.
+- Suffix space compression.
+- Prefix space compression.
+- Numbers with value `0' are stored using 1 bit.
+- If values in an integer column have a small range, the column is stored using the smallest possible type. For example, a `BIGINT' column (8 bytes) may be stored as a `TINYINT' column (1 byte) if all values are in the range `0' to `255'.
+- If a column has only a small set of possible values, the column type is converted to `ENUM'.
+- A column may use a combination of the above compressions.
+* Can handle fixed or dynamic length records, but not `BLOB' or `TEXT' columns.
+* Can be uncompressed with `myisamchk'.
+
+*MySQL* can support different index types, but the normal type is ISAM.
+This is a B-tree index and you can roughly calculate the size for the index file as `(key_length+4)*0.67', summed over all keys. (This is for the worst case when all keys are inserted in sorted order.)
+
+String indexes are space compressed. If the first index part is a string, it will also be prefix compressed.
+Space compression makes the index file smaller if the string column has a lot of trailing space or is a `VARCHAR' column that is not always used to the full length.
+Prefix compression helps if there are many strings with an identical prefix.
+
+In memory table characteristics
+HEAP tables only exists in memory so they are lost if `mysqld' is taken down or crashes. But since they are *very* fast they are usefull as anyway.
+
+The *MySQL* internal HEAP tables uses 100% dynamic hashing without overflow areas and don't have problems with delete.
+
+You can only access things by equality using a index (usually by the `=' operator) whith a heap table.
+The downside with HEAPS are:
+ 1. You need enough extra memory for all HEAP tables that you want to use at the same time.
+ 2. You can't search on a part of a index.
+ 3. You can't search for the next entry in order (that is to use the index to do a `ORDER BY').
+1. *MySQL* also cannot find out how approximately many rows there are between two values. This is used by the optimizer to chose which index to use. But on the other hand no disk seeks are even needed.
+====================
+#.# mi_()
+
+#.#.1 Description
+
+#.#.2 Return values
+
+Zero if successful. Non-zero if an error occurred.
+
+#.#.3 Errors
+
+Nothing specific yet identified.
+
+#.#.4 Examples
+[SB1]int _mi_read_rnd_static_record(MI_INFO *info, byte *buf, my_off_t filepos,
+ my_bool skipp_deleted_blocks)
+int _mi_read_dynamic_record(MI_INFO *info, my_off_t filepos, byte *buf)
+
+Printed on 17/03/00
+
+C-7
diff --git a/Docs/Flags/australia.eps b/Docs/Flags/australia.eps
new file mode 100755
index 00000000000..f98c03e2c83
--- /dev/null
+++ b/Docs/Flags/australia.eps
@@ -0,0 +1,87 @@
+%!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
+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
+grestore
+showpage
+%%Trailer
diff --git a/Docs/Flags/australia.gif b/Docs/Flags/australia.gif
new file mode 100644
index 00000000000..1f403f92503
--- /dev/null
+++ b/Docs/Flags/australia.gif
Binary files differ
diff --git a/Docs/Flags/australia.txt b/Docs/Flags/australia.txt
new file mode 100755
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/Docs/Flags/australia.txt
diff --git a/Docs/Flags/austria.eps b/Docs/Flags/austria.eps
new file mode 100755
index 00000000000..7a0b56f3690
--- /dev/null
+++ b/Docs/Flags/austria.eps
@@ -0,0 +1,87 @@
+%!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
+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
+d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4
+464646464646464646464646464646464646464646464646464646464646
+474747474747474747474747474747474747474747474747474747474747
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+grestore
+showpage
+%%Trailer
diff --git a/Docs/Flags/austria.gif b/Docs/Flags/austria.gif
new file mode 100644
index 00000000000..d72b945741a
--- /dev/null
+++ b/Docs/Flags/austria.gif
Binary files differ
diff --git a/Docs/Flags/austria.txt b/Docs/Flags/austria.txt
new file mode 100755
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/Docs/Flags/austria.txt
diff --git a/Docs/Flags/brazil.eps b/Docs/Flags/brazil.eps
new file mode 100644
index 00000000000..94cbbd42d20
--- /dev/null
+++ b/Docs/Flags/brazil.eps
@@ -0,0 +1,87 @@
+%!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
+000000000000000000000000000000000000000000000000000000000000
+b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000001eb8a41300000000000000000000000000
+b5b5b5b5b5b5b5b5b5b5b5b5b5beebe5bab5b5b5b5b5b5b5b5b5b5b5b5b5
+000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000164f1ffffe74f000000000000000000000000
+b5b5b5b5b5b5b5b5b5b5b5b5d2fbfffff8ccb5b5b5b5b5b5b5b5b5b5b5b5
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000001eb8fffffcfdffffa41300000000000000000000
+b5b5b5b5b5b5b5b5b5b5beebfffffefeffffe5bab5b5b5b5b5b5b5b5b5b5
+000000000000000000000000000003020000000000000000000000000000
+00000000000000000163f0fea8451c1e4eb8ffe750000000000000000000
+b5b5b5b5b5b5b5b5b5d2fbffe3c3b6b7c6e8fff8ccb5b5b5b5b5b5b5b5b5
+0000000000000000000000015ac1ebe9b84a000000000000000000000000
+000000000000001db7fffe6f18181818181889ffffa41300000000000000
+b5b5b5b5b5b5b5beeaffffd1b5b5b5b5b5b5d9ffffe5bab5b5b5b5b5b5b5
+000000000000000000000195efefefefefef7a0000000000000000000000
+00000000000163f0ffffa61818181818181818c1ffffe750000000000000
+b5b5b5b5b5b5d2fbffffe2b5b5b5b5b5b5b5b5ebfffff8ccb5b5b5b5b5b5
+000000000000000000005cefefefefefefefef4100000000000000000000
+000000001db7ffffffffd4b5bea7905c2b18185dffffffffa41300000000
+b5b5b5b5beeaffffffffeee4e6e0d9c9bbb5b5cbffffffffe5bbb5b5b5b5
+00000000000000000000c9f5f5f4f3f2f0efefa800000000000000000000
+00000063f0fffffffffa422122395f8aae661d30ffffffffffe74f000000
+b5b5b5d2fbfffffffffdc2b8b8bfcad7e2cdb7bdfffffffffff8ccb5b5b5
+00000000000000000006eff0f0f0f2f3f4f2efd700000000000000000000
+00000050e7fffffffffa1b1e181b1b1836909948ffffffffffdb3d000000
+b5b5b5ccf8fffffffffeb6b7b5b6b6b5bed9dcc4fffffffffff5c7b5b5b5
+00000000000000000005ecefefefefeff0f4f4d600000000000000000000
+0000000013a5ffffffff481c18181f1818196fdefffffffd900a00000000
+b5b5b5b5bbe5ffffffffc4b6b5b5b7b5b5b5cff2fffffffedfb8b5b5b5b5
+00000000000000000000beefefefefefefeff2a600000000000000000000
+00000000000050e7ffffb01823182218282e39d9ffffdb3d000000000000
+b5b5b5b5b5b5ccf8ffffe6b5b8b5b8b5babcbff3fffff5c7b5b5b5b5b5b5
+0000000000000000000051efefefefeff0f0ee3800000000000000000000
+0000000000000013a5ffff8018181b18283a99fffd900a00000000000000
+b5b5b5b5b5b5b5bbe5ffffd7b5b5b6b5babfdffffedfb8b5b5b5b5b5b5b5
+000000000000000000000084efefefeff0ef690000000000000000000000
+00000000000000000050e7ffba572b2d60c8ffdb3d000000000000000000
+b5b5b5b5b5b5b5b5b5ccf8ffe9c9bbbcccedfff5c7b5b5b5b5b5b5b5b5b5
+00000000000000000000000048aedcd9a539000000000000000000000000
+0000000000000000000013a5fffffffffffd900a00000000000000000000
+b5b5b5b5b5b5b5b5b5b5bbe5fffffffffffedfb8b5b5b5b5b5b5b5b5b5b5
+000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000050e7ffffdb3e000000000000000000000000
+b5b5b5b5b5b5b5b5b5b5b5b5ccf8fffff5c7b5b5b5b5b5b5b5b5b5b5b5b5
+000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000013a5910b00000000000000000000000000
+b5b5b5b5b5b5b5b5b5b5b5b5b5bbe5dfb8b5b5b5b5b5b5b5b5b5b5b5b5b5
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
+000000000000000000000000000000000000000000000000000000000000
+grestore
+showpage
+%%Trailer
diff --git a/Docs/Flags/brazil.gif b/Docs/Flags/brazil.gif
new file mode 100644
index 00000000000..82e12be5956
--- /dev/null
+++ b/Docs/Flags/brazil.gif
Binary files differ
diff --git a/Docs/Flags/brazil.txt b/Docs/Flags/brazil.txt
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/Docs/Flags/brazil.txt
diff --git a/Docs/Flags/bulgaria.eps b/Docs/Flags/bulgaria.eps
new file mode 100644
index 00000000000..6f4a07c616c
--- /dev/null
+++ b/Docs/Flags/bulgaria.eps
@@ -0,0 +1,87 @@
+%!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
+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
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
+000000000000000000000000000000000000000000000000000000000000
+8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d
+333333333333333333333333333333333333333333333333333333333333
+000000000000000000000000000000000000000000000000000000000000
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+grestore
+showpage
+%%Trailer
diff --git a/Docs/Flags/bulgaria.gif b/Docs/Flags/bulgaria.gif
new file mode 100644
index 00000000000..35c0b117062
--- /dev/null
+++ b/Docs/Flags/bulgaria.gif
Binary files differ
diff --git a/Docs/Flags/bulgaria.txt b/Docs/Flags/bulgaria.txt
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/Docs/Flags/bulgaria.txt
diff --git a/Docs/Flags/canada.eps b/Docs/Flags/canada.eps
new file mode 100755
index 00000000000..b770266de60
--- /dev/null
+++ b/Docs/Flags/canada.eps
@@ -0,0 +1,87 @@
+%!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
+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
+grestore
+showpage
+%%Trailer
diff --git a/Docs/Flags/canada.gif b/Docs/Flags/canada.gif
new file mode 100644
index 00000000000..322d4b985b7
--- /dev/null
+++ b/Docs/Flags/canada.gif
Binary files differ
diff --git a/Docs/Flags/canada.txt b/Docs/Flags/canada.txt
new file mode 100755
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/Docs/Flags/canada.txt
diff --git a/Docs/Flags/chile.eps b/Docs/Flags/chile.eps
new file mode 100644
index 00000000000..8a5411a32a3
--- /dev/null
+++ b/Docs/Flags/chile.eps
@@ -0,0 +1,87 @@
+%!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
+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
+000000000000000000000000000000000000000000000000000000000000
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+grestore
+showpage
+%%Trailer
diff --git a/Docs/Flags/chile.gif b/Docs/Flags/chile.gif
new file mode 100644
index 00000000000..e7afe88df8b
--- /dev/null
+++ b/Docs/Flags/chile.gif
Binary files differ
diff --git a/Docs/Flags/chile.txt b/Docs/Flags/chile.txt
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/Docs/Flags/chile.txt
diff --git a/Docs/Flags/china.eps b/Docs/Flags/china.eps
new file mode 100644
index 00000000000..97b87f4727f
--- /dev/null
+++ b/Docs/Flags/china.eps
@@ -0,0 +1,87 @@
+%!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
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+c6c6c6c6c6c6c7e1c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+000000000000037602000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+c6c6c6cfc6c6c6c9c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+000000250000000e00000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+c6c6c6efc9c6c6c7e1c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+000000b70e00000377010000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+c6d7f4fef7e2c7c6c9c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+004bccfcda7d03000d000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+c6c6e2fff2c6c6c7d3c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+00007dffc301000338010000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+c6c6e5d4e9c8c6c6d7c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+00008a3b9c0a00004c000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+c6c6c7c6c6c7c7d0c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+000003000003042a00000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+c6c6c6c6c6c6c6dac6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+000000000000015800000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+grestore
+showpage
+%%Trailer
diff --git a/Docs/Flags/china.gif b/Docs/Flags/china.gif
new file mode 100644
index 00000000000..4baf243f158
--- /dev/null
+++ b/Docs/Flags/china.gif
Binary files differ
diff --git a/Docs/Flags/china.txt b/Docs/Flags/china.txt
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/Docs/Flags/china.txt
diff --git a/Docs/Flags/croatia.eps b/Docs/Flags/croatia.eps
new file mode 100644
index 00000000000..db6566f8e31
--- /dev/null
+++ b/Docs/Flags/croatia.eps
@@ -0,0 +1,87 @@
+%!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
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+c6c6c6c6c6c6c6c6c6c6c6c6b6c1abafc0b8c6c6c6c6c6c6c6c6c6c6c6c6
+000000000000000000000000170d2f290f15000000000000000000000000
+0000000000000000000000001e0e312a111b000000000000000000000000
+c6c6c6c6c6c6c6c6c6c67a77748c474c29297380c6c6c6c6c6c6c6c6c6c6
+0000000000000000000076703536b1ac3d3c756e00000000000000000000
+0000000000000000000074715b4b908a838c756d00000000000000000000
+c6c6c6c6c6c6c6c6c6c22c1858652b257a5b6947c4c6c6c6c6c6c6c6c6c6
+00000000000000000013c5c93529b6ae755ca6c30c000000000000000000
+00000000000000000013bcc86157a5a5435a9bbb0c000000000000000000
+c6c6c6c6c6c6c6c6c6c65e3c4f60605f5d5466acc6c6c6c6c6c6c6c6c6c6
+0000000000000000000095d065397d794264674300000000000000000000
+000000000000000000009cdb876a878669856b4400000000000000000000
+d7d7d7d7d7d7d7d7d7d7bcb3cfd8c8cad8cdb1c1d7d7d7d7d7d7d7d7d7d7
+57575757575757575757592a345a0b155a292d6057575757575757575757
+575757575757575757575b2b345a0b155a292f6157575757575757575757
+f7f7f7f7f7f7f7f7f7f7e2c6e2f7ccd2f7dbc6e8f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f78d008af71e3af76b00adf7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f78d008bf71e3af76b00adf7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7eae9ded5e7e5d5e1e9ecf7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7b3af794ba5994b86afbff7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7b3af7a4ca59a4c87afbff7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7edf6ddc8f1ecc8e3f6edf7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7c1f0720ad7bc0a8ff0c5f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7c1f0720ad8bd0a90f0c5f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7e2c6e2f7ccd2f7dbc6e8f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f78e018bf71e3bf76b01adf7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f78e018bf71e3bf76b01adf7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7e7d9e0e5dbdce5ded8ecf7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7a75e819b666e9b795bbcf7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7a75f829b676e9b7a5cbcf7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f3f0dcc6f2ecc6e3edf6f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7e1d56f00dcbf008fc6f0f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7e1d56f00ddc00090c6f0f7f7f7f7f7f7f7f7f7f7
+4c4c4c4c4c4c4c4c4c4c4c79e1ead7d9eadd6a4c4c4c4c4c4c4c4c4c4c4c
+46464646464646464646463484b45461b476344646464646464646464646
+c8c8c8c8c8c8c8c8c8c8c88885b45562b47897c8c8c8c8c8c8c8c8c8c8c8
+0808080808080808080808085cd3cbd0ca4a080808080808080808080808
+0000000000000000000000002aa819319d1d000000000000000000000000
+b5b5b5b5b5b5b5b5b5b5b5b597bb1931b799b5b5b5b5b5b5b5b5b5b5b5b5
+0808080808080808080808080809201d0808080808080808080808080808
+000000000000000000000000000000000000000000000000000000000000
+b5b5b5b5b5b5b5b5b5b5b5b5b5b49ea1b5b5b5b5b5b5b5b5b5b5b5b5b5b5
+080808080808080808080808080808080808080808080808080808080808
+000000000000000000000000000000000000000000000000000000000000
+b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
+080808080808080808080808080808080808080808080808080808080808
+000000000000000000000000000000000000000000000000000000000000
+b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
+080808080808080808080808080808080808080808080808080808080808
+000000000000000000000000000000000000000000000000000000000000
+b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
+080808080808080808080808080808080808080808080808080808080808
+000000000000000000000000000000000000000000000000000000000000
+b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
+grestore
+showpage
+%%Trailer
diff --git a/Docs/Flags/croatia.gif b/Docs/Flags/croatia.gif
new file mode 100644
index 00000000000..643b89555f5
--- /dev/null
+++ b/Docs/Flags/croatia.gif
Binary files differ
diff --git a/Docs/Flags/croatia.txt b/Docs/Flags/croatia.txt
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/Docs/Flags/croatia.txt
diff --git a/Docs/Flags/czech-republic.eps b/Docs/Flags/czech-republic.eps
new file mode 100755
index 00000000000..afa50e9a82d
--- /dev/null
+++ b/Docs/Flags/czech-republic.eps
@@ -0,0 +1,87 @@
+%!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
+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
+000000000000000000000000000000000000000000000000000000000000
+b5b5b5b5b5b5b59f31000000000000000000000000000000000000000000
+08080808080954bcc6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+000000000000000000000000000000000000000000000000000000000000
+b5b5b5b5b5b46d0a00000000000000000000000000000000000000000000
+080808081f93c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+000000000000000000000000000000000000000000000000000000000000
+b5b5b5b59f31000000000000000000000000000000000000000000000000
+08080954bcc6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+000000000000000000000000000000000000000000000000000000000000
+b5b5b46d0a00000000000000000000000000000000000000000000000000
+081f92c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+000000000000000000000000000000000000000000000000000000000000
+b59f31000000000000000000000000000000000000000000000000000000
+53bcc6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+000000000000000000000000000000000000000000000000000000000000
+6e0a00000000000000000000000000000000000000000000000000000000
+grestore
+showpage
+%%Trailer
diff --git a/Docs/Flags/czech-republic.gif b/Docs/Flags/czech-republic.gif
new file mode 100644
index 00000000000..10d5a3c72e9
--- /dev/null
+++ b/Docs/Flags/czech-republic.gif
Binary files differ
diff --git a/Docs/Flags/czech-republic.txt b/Docs/Flags/czech-republic.txt
new file mode 100755
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/Docs/Flags/czech-republic.txt
diff --git a/Docs/Flags/denmark.eps b/Docs/Flags/denmark.eps
new file mode 100644
index 00000000000..2f397c4af16
--- /dev/null
+++ b/Docs/Flags/denmark.eps
@@ -0,0 +1,87 @@
+%!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
+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
+grestore
+showpage
+%%Trailer
diff --git a/Docs/Flags/denmark.gif b/Docs/Flags/denmark.gif
new file mode 100644
index 00000000000..1d8e687adcc
--- /dev/null
+++ b/Docs/Flags/denmark.gif
Binary files differ
diff --git a/Docs/Flags/denmark.txt b/Docs/Flags/denmark.txt
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/Docs/Flags/denmark.txt
diff --git a/Docs/Flags/estonia.eps b/Docs/Flags/estonia.eps
new file mode 100644
index 00000000000..e34768c3442
--- /dev/null
+++ b/Docs/Flags/estonia.eps
@@ -0,0 +1,87 @@
+%!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
+080808080808080808080808080808080808080808080808080808080808
+000000000000000000000000000000000000000000000000000000000000
+b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
+080808080808080808080808080808080808080808080808080808080808
+000000000000000000000000000000000000000000000000000000000000
+b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
+080808080808080808080808080808080808080808080808080808080808
+000000000000000000000000000000000000000000000000000000000000
+b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
+080808080808080808080808080808080808080808080808080808080808
+000000000000000000000000000000000000000000000000000000000000
+b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
+080808080808080808080808080808080808080808080808080808080808
+000000000000000000000000000000000000000000000000000000000000
+b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
+080808080808080808080808080808080808080808080808080808080808
+000000000000000000000000000000000000000000000000000000000000
+b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
+050505050505050505050505050505050505050505050505050505050505
+000000000000000000000000000000000000000000000000000000000000
+757575757575757575757575757575757575757575757575757575757575
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+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
+grestore
+showpage
+%%Trailer
diff --git a/Docs/Flags/estonia.gif b/Docs/Flags/estonia.gif
new file mode 100644
index 00000000000..b8bbf1dbb78
--- /dev/null
+++ b/Docs/Flags/estonia.gif
Binary files differ
diff --git a/Docs/Flags/estonia.txt b/Docs/Flags/estonia.txt
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/Docs/Flags/estonia.txt
diff --git a/Docs/Flags/finland.eps b/Docs/Flags/finland.eps
new file mode 100644
index 00000000000..c88fa4e2eaa
--- /dev/null
+++ b/Docs/Flags/finland.eps
@@ -0,0 +1,87 @@
+%!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
+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
+grestore
+showpage
+%%Trailer
diff --git a/Docs/Flags/finland.gif b/Docs/Flags/finland.gif
new file mode 100644
index 00000000000..a43a398f8f1
--- /dev/null
+++ b/Docs/Flags/finland.gif
Binary files differ
diff --git a/Docs/Flags/finland.txt b/Docs/Flags/finland.txt
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/Docs/Flags/finland.txt
diff --git a/Docs/Flags/france.eps b/Docs/Flags/france.eps
new file mode 100644
index 00000000000..6367b8b98ca
--- /dev/null
+++ b/Docs/Flags/france.eps
@@ -0,0 +1,87 @@
+%!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
+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
+grestore
+showpage
+%%Trailer
diff --git a/Docs/Flags/france.gif b/Docs/Flags/france.gif
new file mode 100644
index 00000000000..13fcbf29e66
--- /dev/null
+++ b/Docs/Flags/france.gif
Binary files differ
diff --git a/Docs/Flags/france.txt b/Docs/Flags/france.txt
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/Docs/Flags/france.txt
diff --git a/Docs/Flags/germany.eps b/Docs/Flags/germany.eps
new file mode 100755
index 00000000000..568543e3680
--- /dev/null
+++ b/Docs/Flags/germany.eps
@@ -0,0 +1,87 @@
+%!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
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+464646464646464646464646464646464646464646464646464646464646
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+efefefefefefefefefefefefefefefefefefefefefefefefefefefefefef
+999999999999999999999999999999999999999999999999999999999999
+000000000000000000000000000000000000000000000000000000000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6
+000000000000000000000000000000000000000000000000000000000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6
+000000000000000000000000000000000000000000000000000000000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6
+000000000000000000000000000000000000000000000000000000000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6
+000000000000000000000000000000000000000000000000000000000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6
+000000000000000000000000000000000000000000000000000000000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6
+000000000000000000000000000000000000000000000000000000000000
+grestore
+showpage
+%%Trailer
diff --git a/Docs/Flags/germany.gif b/Docs/Flags/germany.gif
new file mode 100644
index 00000000000..e25a855b3d2
--- /dev/null
+++ b/Docs/Flags/germany.gif
Binary files differ
diff --git a/Docs/Flags/germany.txt b/Docs/Flags/germany.txt
new file mode 100755
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/Docs/Flags/germany.txt
diff --git a/Docs/Flags/great-britain.eps b/Docs/Flags/great-britain.eps
new file mode 100755
index 00000000000..97a7ffc9b57
--- /dev/null
+++ b/Docs/Flags/great-britain.eps
@@ -0,0 +1,87 @@
+%!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
+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
+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
+grestore
+showpage
+%%Trailer
diff --git a/Docs/Flags/great-britain.gif b/Docs/Flags/great-britain.gif
new file mode 100644
index 00000000000..0f555d078b3
--- /dev/null
+++ b/Docs/Flags/great-britain.gif
Binary files differ
diff --git a/Docs/Flags/great-britain.txt b/Docs/Flags/great-britain.txt
new file mode 100755
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/Docs/Flags/great-britain.txt
diff --git a/Docs/Flags/greece.eps b/Docs/Flags/greece.eps
new file mode 100644
index 00000000000..3c022139c56
--- /dev/null
+++ b/Docs/Flags/greece.eps
@@ -0,0 +1,87 @@
+%!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
+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
+grestore
+showpage
+%%Trailer
diff --git a/Docs/Flags/greece.gif b/Docs/Flags/greece.gif
new file mode 100644
index 00000000000..1ede215a373
--- /dev/null
+++ b/Docs/Flags/greece.gif
Binary files differ
diff --git a/Docs/Flags/greece.txt b/Docs/Flags/greece.txt
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/Docs/Flags/greece.txt
diff --git a/Docs/Flags/hungary.eps b/Docs/Flags/hungary.eps
new file mode 100755
index 00000000000..e405fc3cffe
--- /dev/null
+++ b/Docs/Flags/hungary.eps
@@ -0,0 +1,87 @@
+%!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
+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
+464646464646464646464646464646464646464646464646464646464646
+c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8
+464646464646464646464646464646464646464646464646464646464646
+000000000000000000000000000000000000000000000000000000000000
+b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
+000000000000000000000000000000000000000000000000000000000000
+grestore
+showpage
+%%Trailer
diff --git a/Docs/Flags/hungary.gif b/Docs/Flags/hungary.gif
new file mode 100644
index 00000000000..eca0e109bbe
--- /dev/null
+++ b/Docs/Flags/hungary.gif
Binary files differ
diff --git a/Docs/Flags/hungary.txt b/Docs/Flags/hungary.txt
new file mode 100755
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/Docs/Flags/hungary.txt
diff --git a/Docs/Flags/iceland.eps b/Docs/Flags/iceland.eps
new file mode 100644
index 00000000000..c2a5529eb42
--- /dev/null
+++ b/Docs/Flags/iceland.eps
@@ -0,0 +1,87 @@
+%!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
+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
+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
+grestore
+showpage
+%%Trailer
diff --git a/Docs/Flags/iceland.gif b/Docs/Flags/iceland.gif
new file mode 100644
index 00000000000..ee4d17f5d04
--- /dev/null
+++ b/Docs/Flags/iceland.gif
Binary files differ
diff --git a/Docs/Flags/iceland.txt b/Docs/Flags/iceland.txt
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/Docs/Flags/iceland.txt
diff --git a/Docs/Flags/ireland.eps b/Docs/Flags/ireland.eps
new file mode 100644
index 00000000000..610b2086fd7
--- /dev/null
+++ b/Docs/Flags/ireland.eps
@@ -0,0 +1,87 @@
+%!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
+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
+grestore
+showpage
+%%Trailer
diff --git a/Docs/Flags/ireland.gif b/Docs/Flags/ireland.gif
new file mode 100644
index 00000000000..a550678761f
--- /dev/null
+++ b/Docs/Flags/ireland.gif
Binary files differ
diff --git a/Docs/Flags/ireland.txt b/Docs/Flags/ireland.txt
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/Docs/Flags/ireland.txt
diff --git a/Docs/Flags/island.eps b/Docs/Flags/island.eps
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/Docs/Flags/island.eps
diff --git a/Docs/Flags/island.gif b/Docs/Flags/island.gif
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/Docs/Flags/island.gif
diff --git a/Docs/Flags/island.txt b/Docs/Flags/island.txt
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/Docs/Flags/island.txt
diff --git a/Docs/Flags/israel.eps b/Docs/Flags/israel.eps
new file mode 100755
index 00000000000..3d3059a907a
--- /dev/null
+++ b/Docs/Flags/israel.eps
@@ -0,0 +1,87 @@
+%!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
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0
+f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4
+181818181818181818181818181818181818181818181818181818181818
+b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
+efefefefefefefefefefefefefefefefefefefefefefefefefefefefefef
+181818181818181818181818181818181818181818181818181818181818
+b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
+efefefefefefefefefefefefefefefefefefefefefefefefefefefefefef
+d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4
+edededededededededededededededededededededededededededededed
+f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7a5bef7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7dfe6f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f4f5f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f2ede4807aebedf3f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f5f4f1d4d2f3f4f6f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f3f3f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7c65e5296915755daf7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7e9cac6dbd9c8c7eef7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f5f2f1f4f4f2f1f6f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7809af7f78a90f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7d4dcf7f7d7d9f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f3f4f7f7f3f3f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f77d94f7f7868bf7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7d3daf7f7d6d7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f3f3f7f7f3f3f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7c15e508a835755d6f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7e7cac6d7d5c8c7edf7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f5f1f1f3f3f1f1f6f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f0837ef6f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f5d5d3f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f3f3f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7afc7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7e2e9f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f4f5f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2
+e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7
+f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5
+181818181818181818181818181818181818181818181818181818181818
+b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
+efefefefefefefefefefefefefefefefefefefefefefefefefefefefefef
+181818181818181818181818181818181818181818181818181818181818
+b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5b5
+efefefefefefefefefefefefefefefefefefefefefefefefefefefefefef
+bcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbc
+e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5
+f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7
+grestore
+showpage
+%%Trailer
diff --git a/Docs/Flags/israel.gif b/Docs/Flags/israel.gif
new file mode 100644
index 00000000000..f7cc613e27d
--- /dev/null
+++ b/Docs/Flags/israel.gif
Binary files differ
diff --git a/Docs/Flags/israel.txt b/Docs/Flags/israel.txt
new file mode 100755
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/Docs/Flags/israel.txt
diff --git a/Docs/Flags/italy.eps b/Docs/Flags/italy.eps
new file mode 100755
index 00000000000..20c7c7d5da3
--- /dev/null
+++ b/Docs/Flags/italy.eps
@@ -0,0 +1,87 @@
+%!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
+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
+grestore
+showpage
+%%Trailer
diff --git a/Docs/Flags/italy.gif b/Docs/Flags/italy.gif
new file mode 100644
index 00000000000..511dba800c7
--- /dev/null
+++ b/Docs/Flags/italy.gif
Binary files differ
diff --git a/Docs/Flags/italy.txt b/Docs/Flags/italy.txt
new file mode 100755
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/Docs/Flags/italy.txt
diff --git a/Docs/Flags/japan.eps b/Docs/Flags/japan.eps
new file mode 100755
index 00000000000..8dee6e497ba
--- /dev/null
+++ b/Docs/Flags/japan.eps
@@ -0,0 +1,87 @@
+%!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
+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
+grestore
+showpage
+%%Trailer
diff --git a/Docs/Flags/japan.gif b/Docs/Flags/japan.gif
new file mode 100644
index 00000000000..37ebca66f04
--- /dev/null
+++ b/Docs/Flags/japan.gif
Binary files differ
diff --git a/Docs/Flags/japan.txt b/Docs/Flags/japan.txt
new file mode 100755
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/Docs/Flags/japan.txt
diff --git a/Docs/Flags/kroatia.eps b/Docs/Flags/kroatia.eps
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/Docs/Flags/kroatia.eps
diff --git a/Docs/Flags/kroatia.gif b/Docs/Flags/kroatia.gif
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/Docs/Flags/kroatia.gif
diff --git a/Docs/Flags/kroatia.txt b/Docs/Flags/kroatia.txt
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/Docs/Flags/kroatia.txt
diff --git a/Docs/Flags/netherlands.eps b/Docs/Flags/netherlands.eps
new file mode 100644
index 00000000000..6f4d9906a11
--- /dev/null
+++ b/Docs/Flags/netherlands.eps
@@ -0,0 +1,87 @@
+%!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
+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
+grestore
+showpage
+%%Trailer
diff --git a/Docs/Flags/netherlands.gif b/Docs/Flags/netherlands.gif
new file mode 100644
index 00000000000..c09d3eb495c
--- /dev/null
+++ b/Docs/Flags/netherlands.gif
Binary files differ
diff --git a/Docs/Flags/netherlands.txt b/Docs/Flags/netherlands.txt
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/Docs/Flags/netherlands.txt
diff --git a/Docs/Flags/poland.eps b/Docs/Flags/poland.eps
new file mode 100644
index 00000000000..40d4363a515
--- /dev/null
+++ b/Docs/Flags/poland.eps
@@ -0,0 +1,87 @@
+%!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
+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
+000000000000000000000000000000000000000000000000000000000000
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+grestore
+showpage
+%%Trailer
diff --git a/Docs/Flags/poland.gif b/Docs/Flags/poland.gif
new file mode 100644
index 00000000000..756f9398ee3
--- /dev/null
+++ b/Docs/Flags/poland.gif
Binary files differ
diff --git a/Docs/Flags/poland.txt b/Docs/Flags/poland.txt
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/Docs/Flags/poland.txt
diff --git a/Docs/Flags/portugal.eps b/Docs/Flags/portugal.eps
new file mode 100644
index 00000000000..7bd24809850
--- /dev/null
+++ b/Docs/Flags/portugal.eps
@@ -0,0 +1,87 @@
+%!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
+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
+grestore
+showpage
+%%Trailer
diff --git a/Docs/Flags/portugal.gif b/Docs/Flags/portugal.gif
new file mode 100644
index 00000000000..91bf32addb2
--- /dev/null
+++ b/Docs/Flags/portugal.gif
Binary files differ
diff --git a/Docs/Flags/portugal.txt b/Docs/Flags/portugal.txt
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/Docs/Flags/portugal.txt
diff --git a/Docs/Flags/romania.eps b/Docs/Flags/romania.eps
new file mode 100644
index 00000000000..03b53f502a1
--- /dev/null
+++ b/Docs/Flags/romania.eps
@@ -0,0 +1,87 @@
+%!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
+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
+grestore
+showpage
+%%Trailer
diff --git a/Docs/Flags/romania.gif b/Docs/Flags/romania.gif
new file mode 100644
index 00000000000..2d38df262bf
--- /dev/null
+++ b/Docs/Flags/romania.gif
Binary files differ
diff --git a/Docs/Flags/romania.txt b/Docs/Flags/romania.txt
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/Docs/Flags/romania.txt
diff --git a/Docs/Flags/russia.eps b/Docs/Flags/russia.eps
new file mode 100755
index 00000000000..85c5899d891
--- /dev/null
+++ b/Docs/Flags/russia.eps
@@ -0,0 +1,87 @@
+%!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
+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
+grestore
+showpage
+%%Trailer
diff --git a/Docs/Flags/russia.gif b/Docs/Flags/russia.gif
new file mode 100644
index 00000000000..f72e7f78da6
--- /dev/null
+++ b/Docs/Flags/russia.gif
Binary files differ
diff --git a/Docs/Flags/russia.txt b/Docs/Flags/russia.txt
new file mode 100755
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/Docs/Flags/russia.txt
diff --git a/Docs/Flags/singapore.eps b/Docs/Flags/singapore.eps
new file mode 100644
index 00000000000..bc5faf248a7
--- /dev/null
+++ b/Docs/Flags/singapore.eps
@@ -0,0 +1,87 @@
+%!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
+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
+grestore
+showpage
+%%Trailer
diff --git a/Docs/Flags/singapore.gif b/Docs/Flags/singapore.gif
new file mode 100644
index 00000000000..7fbd3f87f62
--- /dev/null
+++ b/Docs/Flags/singapore.gif
Binary files differ
diff --git a/Docs/Flags/singapore.txt b/Docs/Flags/singapore.txt
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/Docs/Flags/singapore.txt
diff --git a/Docs/Flags/south-africa.eps b/Docs/Flags/south-africa.eps
new file mode 100644
index 00000000000..702df9d4e6a
--- /dev/null
+++ b/Docs/Flags/south-africa.eps
@@ -0,0 +1,87 @@
+%!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-africa.gif b/Docs/Flags/south-africa.gif
new file mode 100644
index 00000000000..7fd4ced4469
--- /dev/null
+++ b/Docs/Flags/south-africa.gif
Binary files differ
diff --git a/Docs/Flags/south-africa.txt b/Docs/Flags/south-africa.txt
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/Docs/Flags/south-africa.txt
diff --git a/Docs/Flags/south-africa1.eps b/Docs/Flags/south-africa1.eps
new file mode 100644
index 00000000000..702df9d4e6a
--- /dev/null
+++ b/Docs/Flags/south-africa1.eps
@@ -0,0 +1,87 @@
+%!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
new file mode 100644
index 00000000000..7fd4ced4469
--- /dev/null
+++ b/Docs/Flags/south-africa1.gif
Binary files differ
diff --git a/Docs/Flags/south-africa1.txt b/Docs/Flags/south-africa1.txt
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/Docs/Flags/south-africa1.txt
diff --git a/Docs/Flags/south-korea.eps b/Docs/Flags/south-korea.eps
new file mode 100755
index 00000000000..a363ab514c4
--- /dev/null
+++ b/Docs/Flags/south-korea.eps
@@ -0,0 +1,87 @@
+%!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
+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
+grestore
+showpage
+%%Trailer
diff --git a/Docs/Flags/south-korea.gif b/Docs/Flags/south-korea.gif
new file mode 100644
index 00000000000..0d8630ba963
--- /dev/null
+++ b/Docs/Flags/south-korea.gif
Binary files differ
diff --git a/Docs/Flags/south-korea.txt b/Docs/Flags/south-korea.txt
new file mode 100755
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/Docs/Flags/south-korea.txt
diff --git a/Docs/Flags/spain.eps b/Docs/Flags/spain.eps
new file mode 100644
index 00000000000..340fe9c7671
--- /dev/null
+++ b/Docs/Flags/spain.eps
@@ -0,0 +1,87 @@
+%!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
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7
+040404040404040404040404040404040404040404040404040404040404
+000000000000000000000000000000000000000000000000000000000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fdfdfdfdfdfdfdfdfdfdfdfdfdfdfdfdfdfdfdfdfdfdfdfdfdfdfdfdfdfd
+000000000000000000000000000000000000000000000000000000000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000000000000000000000000000000000000000000000000000000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000000000000000000000000000000000000000000000000000000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000000000000000000000000000000000000000000000000000000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000000000000000000000000000000000000000000000000000000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000000000000000000000000000000000000000000000000000000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+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
+grestore
+showpage
+%%Trailer
diff --git a/Docs/Flags/spain.gif b/Docs/Flags/spain.gif
new file mode 100644
index 00000000000..9d2e1be0fe7
--- /dev/null
+++ b/Docs/Flags/spain.gif
Binary files differ
diff --git a/Docs/Flags/spain.txt b/Docs/Flags/spain.txt
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/Docs/Flags/spain.txt
diff --git a/Docs/Flags/sweden.eps b/Docs/Flags/sweden.eps
new file mode 100755
index 00000000000..47cd1fa3e9c
--- /dev/null
+++ b/Docs/Flags/sweden.eps
@@ -0,0 +1,87 @@
+%!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
+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
+grestore
+showpage
+%%Trailer
diff --git a/Docs/Flags/sweden.gif b/Docs/Flags/sweden.gif
new file mode 100644
index 00000000000..e16ede8e641
--- /dev/null
+++ b/Docs/Flags/sweden.gif
Binary files differ
diff --git a/Docs/Flags/sweden.txt b/Docs/Flags/sweden.txt
new file mode 100755
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/Docs/Flags/sweden.txt
diff --git a/Docs/Flags/switzerland.eps b/Docs/Flags/switzerland.eps
new file mode 100644
index 00000000000..517919e3125
--- /dev/null
+++ b/Docs/Flags/switzerland.eps
@@ -0,0 +1,87 @@
+%!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
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+000000000000000000000000000000000000000000000000000000000000
+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
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+grestore
+showpage
+%%Trailer
diff --git a/Docs/Flags/switzerland.gif b/Docs/Flags/switzerland.gif
new file mode 100644
index 00000000000..98cef7c28d6
--- /dev/null
+++ b/Docs/Flags/switzerland.gif
Binary files differ
diff --git a/Docs/Flags/switzerland.txt b/Docs/Flags/switzerland.txt
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/Docs/Flags/switzerland.txt
diff --git a/Docs/Flags/taiwan.eps b/Docs/Flags/taiwan.eps
new file mode 100755
index 00000000000..a514bdf2af4
--- /dev/null
+++ b/Docs/Flags/taiwan.eps
@@ -0,0 +1,87 @@
+%!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
+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
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6c6
+000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000
+grestore
+showpage
+%%Trailer
diff --git a/Docs/Flags/taiwan.gif b/Docs/Flags/taiwan.gif
new file mode 100644
index 00000000000..5cfc3d46425
--- /dev/null
+++ b/Docs/Flags/taiwan.gif
Binary files differ
diff --git a/Docs/Flags/taiwan.txt b/Docs/Flags/taiwan.txt
new file mode 100755
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/Docs/Flags/taiwan.txt
diff --git a/Docs/Flags/ukraine.eps b/Docs/Flags/ukraine.eps
new file mode 100644
index 00000000000..fe2436fa554
--- /dev/null
+++ b/Docs/Flags/ukraine.eps
@@ -0,0 +1,87 @@
+%!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
+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
+000000000000000000000000000000000000000000000000000000000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000000000000000000000000000000000000000000000000000000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000000000000000000000000000000000000000000000000000000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000000000000000000000000000000000000000000000000000000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000000000000000000000000000000000000000000000000000000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000000000000000000000000000000000000000000000000000000000
+grestore
+showpage
+%%Trailer
diff --git a/Docs/Flags/ukraine.gif b/Docs/Flags/ukraine.gif
new file mode 100644
index 00000000000..b951bef5b2a
--- /dev/null
+++ b/Docs/Flags/ukraine.gif
Binary files differ
diff --git a/Docs/Flags/ukraine.txt b/Docs/Flags/ukraine.txt
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/Docs/Flags/ukraine.txt
diff --git a/Docs/Flags/usa.eps b/Docs/Flags/usa.eps
new file mode 100755
index 00000000000..31bd9996d11
--- /dev/null
+++ b/Docs/Flags/usa.eps
@@ -0,0 +1,87 @@
+%!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
+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
+grestore
+showpage
+%%Trailer
diff --git a/Docs/Flags/usa.gif b/Docs/Flags/usa.gif
new file mode 100644
index 00000000000..da9f4e27d6c
--- /dev/null
+++ b/Docs/Flags/usa.gif
Binary files differ
diff --git a/Docs/Flags/usa.txt b/Docs/Flags/usa.txt
new file mode 100755
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/Docs/Flags/usa.txt
diff --git a/Docs/Images/Attic/html-fs.gif b/Docs/Images/Attic/html-fs.gif
new file mode 100644
index 00000000000..73f9ab5bec6
--- /dev/null
+++ b/Docs/Images/Attic/html-fs.gif
Binary files differ
diff --git a/Docs/Images/Attic/mysql-01.gif b/Docs/Images/Attic/mysql-01.gif
new file mode 100644
index 00000000000..773453f8dd7
--- /dev/null
+++ b/Docs/Images/Attic/mysql-01.gif
Binary files differ
diff --git a/Docs/Images/Attic/mysql-02.gif b/Docs/Images/Attic/mysql-02.gif
new file mode 100644
index 00000000000..12d984b55e0
--- /dev/null
+++ b/Docs/Images/Attic/mysql-02.gif
Binary files differ
diff --git a/Docs/Images/Attic/mysql-03.gif b/Docs/Images/Attic/mysql-03.gif
new file mode 100644
index 00000000000..abb16f2aa59
--- /dev/null
+++ b/Docs/Images/Attic/mysql-03.gif
Binary files differ
diff --git a/Docs/Images/Attic/mysql-04.gif b/Docs/Images/Attic/mysql-04.gif
new file mode 100644
index 00000000000..e207e1790f7
--- /dev/null
+++ b/Docs/Images/Attic/mysql-04.gif
Binary files differ
diff --git a/Docs/Images/Attic/mysql-05.gif b/Docs/Images/Attic/mysql-05.gif
new file mode 100644
index 00000000000..f78b8a17b93
--- /dev/null
+++ b/Docs/Images/Attic/mysql-05.gif
Binary files differ
diff --git a/Docs/Images/Attic/mysql-06.gif b/Docs/Images/Attic/mysql-06.gif
new file mode 100644
index 00000000000..c660e1d1f4f
--- /dev/null
+++ b/Docs/Images/Attic/mysql-06.gif
Binary files differ
diff --git a/Docs/Images/Attic/mysql-07.gif b/Docs/Images/Attic/mysql-07.gif
new file mode 100644
index 00000000000..be309d0de1c
--- /dev/null
+++ b/Docs/Images/Attic/mysql-07.gif
Binary files differ
diff --git a/Docs/Images/Attic/mysql-08.gif b/Docs/Images/Attic/mysql-08.gif
new file mode 100644
index 00000000000..3d5b2135655
--- /dev/null
+++ b/Docs/Images/Attic/mysql-08.gif
Binary files differ
diff --git a/Docs/Images/Attic/mysql-09.gif b/Docs/Images/Attic/mysql-09.gif
new file mode 100644
index 00000000000..75d08592795
--- /dev/null
+++ b/Docs/Images/Attic/mysql-09.gif
Binary files differ
diff --git a/Docs/Images/Attic/mysql-10.gif b/Docs/Images/Attic/mysql-10.gif
new file mode 100644
index 00000000000..8d0a8551e9e
--- /dev/null
+++ b/Docs/Images/Attic/mysql-10.gif
Binary files differ
diff --git a/Docs/Images/Attic/mysql-11.gif b/Docs/Images/Attic/mysql-11.gif
new file mode 100644
index 00000000000..e5f3770a7bd
--- /dev/null
+++ b/Docs/Images/Attic/mysql-11.gif
Binary files differ
diff --git a/Docs/Images/Attic/mysql-12.gif b/Docs/Images/Attic/mysql-12.gif
new file mode 100644
index 00000000000..b045aaf3549
--- /dev/null
+++ b/Docs/Images/Attic/mysql-12.gif
Binary files differ
diff --git a/Docs/Images/Attic/mysql-13.gif b/Docs/Images/Attic/mysql-13.gif
new file mode 100644
index 00000000000..0d5aaf88f6f
--- /dev/null
+++ b/Docs/Images/Attic/mysql-13.gif
Binary files differ
diff --git a/Docs/Images/Attic/mysql-14.gif b/Docs/Images/Attic/mysql-14.gif
new file mode 100644
index 00000000000..9bce287b4b3
--- /dev/null
+++ b/Docs/Images/Attic/mysql-14.gif
Binary files differ
diff --git a/Docs/Images/Attic/mysql-15.gif b/Docs/Images/Attic/mysql-15.gif
new file mode 100644
index 00000000000..d70ffec83dd
--- /dev/null
+++ b/Docs/Images/Attic/mysql-15.gif
Binary files differ
diff --git a/Docs/Images/Attic/mysql-16.gif b/Docs/Images/Attic/mysql-16.gif
new file mode 100644
index 00000000000..9b30833dc1d
--- /dev/null
+++ b/Docs/Images/Attic/mysql-16.gif
Binary files differ
diff --git a/Docs/Images/Attic/mysql-17.gif b/Docs/Images/Attic/mysql-17.gif
new file mode 100644
index 00000000000..5b228496b66
--- /dev/null
+++ b/Docs/Images/Attic/mysql-17.gif
Binary files differ
diff --git a/Docs/Images/Attic/mysql-18.gif b/Docs/Images/Attic/mysql-18.gif
new file mode 100644
index 00000000000..71211350aa2
--- /dev/null
+++ b/Docs/Images/Attic/mysql-18.gif
Binary files differ
diff --git a/Docs/Images/Attic/mysql-19.gif b/Docs/Images/Attic/mysql-19.gif
new file mode 100644
index 00000000000..38e6691d9c6
--- /dev/null
+++ b/Docs/Images/Attic/mysql-19.gif
Binary files differ
diff --git a/Docs/Images/Attic/mysql-compatible.jpg b/Docs/Images/Attic/mysql-compatible.jpg
new file mode 100644
index 00000000000..cce9cf84b91
--- /dev/null
+++ b/Docs/Images/Attic/mysql-compatible.jpg
Binary files differ
diff --git a/Docs/Images/Attic/mysql5.gif b/Docs/Images/Attic/mysql5.gif
new file mode 100644
index 00000000000..f78b8a17b93
--- /dev/null
+++ b/Docs/Images/Attic/mysql5.gif
Binary files differ
diff --git a/Docs/Images/Attic/mysql_anim-01.gif b/Docs/Images/Attic/mysql_anim-01.gif
new file mode 100644
index 00000000000..f537d60da41
--- /dev/null
+++ b/Docs/Images/Attic/mysql_anim-01.gif
Binary files differ
diff --git a/Docs/Images/Attic/mysql_anim-02.gif b/Docs/Images/Attic/mysql_anim-02.gif
new file mode 100644
index 00000000000..cfd3e1cfc3e
--- /dev/null
+++ b/Docs/Images/Attic/mysql_anim-02.gif
Binary files differ
diff --git a/Docs/Images/Attic/mysql_anim-03.gif b/Docs/Images/Attic/mysql_anim-03.gif
new file mode 100644
index 00000000000..6ac6b3ebcc1
--- /dev/null
+++ b/Docs/Images/Attic/mysql_anim-03.gif
Binary files differ
diff --git a/Docs/Images/Attic/mysql_anim-04.gif b/Docs/Images/Attic/mysql_anim-04.gif
new file mode 100644
index 00000000000..d3150860ecf
--- /dev/null
+++ b/Docs/Images/Attic/mysql_anim-04.gif
Binary files differ
diff --git a/Docs/Images/Attic/mysql_anim-05.gif b/Docs/Images/Attic/mysql_anim-05.gif
new file mode 100644
index 00000000000..46f288ef71d
--- /dev/null
+++ b/Docs/Images/Attic/mysql_anim-05.gif
Binary files differ
diff --git a/Docs/Images/Attic/mysql_anim-06.gif b/Docs/Images/Attic/mysql_anim-06.gif
new file mode 100644
index 00000000000..3dc283dbfb6
--- /dev/null
+++ b/Docs/Images/Attic/mysql_anim-06.gif
Binary files differ
diff --git a/Docs/Images/Attic/powered-by-MySQL-transparent.gif b/Docs/Images/Attic/powered-by-MySQL-transparent.gif
new file mode 100644
index 00000000000..be309d0de1c
--- /dev/null
+++ b/Docs/Images/Attic/powered-by-MySQL-transparent.gif
Binary files differ
diff --git a/Docs/Images/empty.png b/Docs/Images/empty.png
new file mode 100644
index 00000000000..71ac39b37f0
--- /dev/null
+++ b/Docs/Images/empty.png
Binary files differ
diff --git a/Docs/Images/flag-background.pnm b/Docs/Images/flag-background.pnm
new file mode 100755
index 00000000000..2bd7b604298
--- /dev/null
+++ b/Docs/Images/flag-background.pnm
Binary files differ
diff --git a/Docs/Images/mysql-logo.gif b/Docs/Images/mysql-logo.gif
new file mode 100644
index 00000000000..c660e1d1f4f
--- /dev/null
+++ b/Docs/Images/mysql-logo.gif
Binary files differ
diff --git a/Docs/LICENSE b/Docs/LICENSE
new file mode 100644
index 00000000000..bd123fe42a5
--- /dev/null
+++ b/Docs/LICENSE
@@ -0,0 +1,98 @@
+ End-User License Agreement for MySQL Commercial Server
+
+ (Version 6, July 13, 2000)
+
+ Copyright (C) 2000, MySQL AB & MySQL Finland AB
+
+ Stockholm SWEDEN, Helsingfors FINLAND and Uppsala SWEDEN
+
+ All rights reserved.
+
+Definitions. This End-User License Agreement ("License") is a legal
+agreement between you, either an individual or a single entity,
+("Licensee") and MySQL AB, MySQL Finland AB and Detron HB ("Licensor")
+for the software product identified above, which includes computer
+software and may include associated media, printed materials, and
+online or electronic documentation ("Software"). The Software also
+includes any updates and supplements to the original Software product
+provided to you by Licensor. Any software provided along with the
+Software that is associated with a separate end-user license agreement
+is licensed to you under the terms of that license agreement.
+
+Agreement to the License. The Software is protected by copyright laws
+and international copyright treaties, as well as other intellectual
+property laws and treaties. The Software is licensed, not sold. If you
+do not agree to the terms of this License, do not install or use the
+Software. By installing, copying, modifying, downloading,
+distributing, accessing or otherwise using the Software, you agree to
+be bound by the following terms of this License:
+
+1. Grant for Authorized Use of the Software
+
+Licensor hereby grants to Licensee a non-exclusive, non-transferable
+right to use the Software in: - Installing. You may install copies of
+the Software for authorized use on your computers, including
+workstations, terminals and other digital electronic devices
+("Computer"). - Single Computer use. You may only use the Software on
+one Computer at a time regardless the number of Computers with
+installed copies. This right covers any number of concurrent users,
+CPUs and MySQL-servers with any number of copies running on one
+Computer.
+
+2. Description of Other Rights
+
+Licensor grants no other rights to the Software except as expressly
+set forth herein:
+
+- Copying. You may not copy the Software unless copies or adaptations
+ are meant for authorized use, archival purposes or when copying or
+ adaptation is a necessary step in the authorized use of the Software.
+
+- Distribution. You may not distribute the Software.
+
+- Modifying. You may modify the Software but you must reproduce all
+ copyright notices in the Software on all modified copies and
+ adaptations.
+
+- License transfer. You may resell or rent this License. If any
+ modifications have been made to the Software, you must include a
+ proper notification that the Software is modified.
+
+- Support services. Licensor may provide you with support services
+ related to the Software. Use and terms of support services are not
+ governed in this License.
+
+3. Term
+
+This license is effective until terminated. Licensor has the
+right to terminate your License immediately if you fail to comply with
+any term of this License.
+
+4. No Warranty
+
+The Software is provided "as is". Licensor makes no warranties,
+express or implied, arising from course of dealing or usage of trade,
+or statutory, as to any matter whatsoever. In particular, any and all
+warranties or merchantability, fitness for a particular purpose or
+non-infringement of third party rights are expressly excluded. The
+entire risk as to the quality and performance of the Software is with
+you. If the Software proves defective, you assume all the cost of
+necessary service, repair or correction.
+
+5. Limited Liability
+
+In no event will Licensor be liable to you for any consequential or
+incidental damages, including any lost profits or lost savings, or for
+any claim by any party, even if a Licensor representative has been
+advised of the possibility of such damages. Some states do not allow
+the exclusion or limitation of liability. Therefore, in any case, the
+entire liability of Licensor under any provision of this License is
+limited to the amount actually paid by you for the Software.
+
+6. Governing Law and Jurisdiction
+
+This License will be governed by the laws in force in
+Sweden. Jurisdiction is with Tingsrätten of Stockholm, Sweden.
+
+Should you have any questions concerning the validity of this License,
+please contact: mysql-licensing@mysql.com.
diff --git a/Docs/Makefile.am b/Docs/Makefile.am
new file mode 100644
index 00000000000..fbe0ca41619
--- /dev/null
+++ b/Docs/Makefile.am
@@ -0,0 +1,120 @@
+# Monty
+
+# Normally you do not need to remake the files here. But if you want
+# to you will need the GNU TeX-info utilities. To make a Postscript
+# files you also need TeX and dvips. To make the PDF file you will
+# need pdftex. We use the teTeX distribution for all of these.
+
+# We avoid default automake rules because of problems with .dvi file
+# and BSD makes
+
+# If you know how to fix any of this more elegantly please mail
+# david@mysql.com
+
+TEXI2HTML_FLAGS = -iso -number
+DVIPS = dvips
+MAKEINFO = @MAKEINFO@
+TEXINFO_TEX = Support/texinfo.tex
+
+noinst_SCRIPTS = Support/texi2html Support/generate-text-files.pl \
+ Support/generate-mirror-listing.pl
+info_TEXINFOS = manual.texi
+
+targets = manual.txt mysql.info manual.html manual.pdf
+
+BUILT_SOURCES = $(targets) manual_toc.html include.texi
+EXTRA_DIST = $(noinst_SCRIPTS) $(BUILT_SOURCES) mysqld_error.txt INSTALL-BINARY
+
+all: $(targets) txt_files
+
+txt_files: ../INSTALL-SOURCE ../COPYING ../COPYING.LIB \
+ ../MIRRORS INSTALL-BINARY
+
+# The PostScript version is so big that is not included in the
+# standard distribution. It is available for download from the home page.
+paper: manual_a4.ps manual_letter.ps
+
+#########################################################################
+
+# The Makefile contains the previous version so we can not use that
+include.texi: ../configure.in
+ echo -n "@c This file is autogenerated by the Makefile" > $@
+ echo -n "@set mysql_version " > $@
+ grep "AM_INIT_AUTOMAKE(mysql, " ../configure.in | \
+ sed -e 's;AM_INIT_AUTOMAKE(mysql, ;;' -e 's;);;' >> $@
+ echo -n "@set default_port " >> $@
+ grep "MYSQL_TCP_PORT_DEFAULT=" ../configure.in | \
+ sed -e 's;MYSQL_TCP_PORT_DEFAULT=;;' >> $@
+
+mysql.info: manual.texi include.texi
+ cd $(srcdir) && $(MAKEINFO) --no-split -I $(srcdir) $<
+
+manual.txt: manual.texi include.texi
+ cd $(srcdir) && \
+ $(MAKEINFO) -I $(srcdir) --no-headers --no-split --output $@ $<
+
+manual.html: manual.texi include.texi $(srcdir)/Support/texi2html
+ cd $(srcdir) && @PERL@ $(srcdir)/Support/texi2html $(TEXI2HTML_FLAGS) $<
+
+# Fix: add --output-comment with some interesting info?
+# Fix: @image worked with a older version of pdftex.
+# Comment: We need to run pdftex 2 times to get the cross references right.
+manual.pdf: manual.texi
+ cat manual.texi | sed -e 's|@image{[^}]*} *||g' > manual-tmp.texi; \
+ pdftex --interaction=nonstopmode '\input manual-tmp.texi'; \
+ pdftex --interaction=nonstopmode '\pdfcompresslevel=9' \
+ '\input manual-tmp.texi'; \
+ mv manual-tmp.pdf manual.pdf; \
+ rm -f manual-tmp.* ; \
+ touch $@
+
+# 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
+ TEXINPUTS=$(srcdir):$$TEXINPUTS \
+ MAKEINFO='$(MAKEINFO) -I $(srcdir)' \
+ $(TEXI2DVI) --batch --texinfo '@afourpaper' $<
+ $(DVIPS) -t a4 manual.dvi -o $@
+ touch $@
+
+# This is the American papersize version
+manual_letter.ps: manual.texi include.texi
+ TEXINPUTS=$(srcdir):$$TEXINPUTS \
+ MAKEINFO='$(MAKEINFO) -I $(srcdir)' \
+ $(TEXI2DVI) --batch $<
+ $(DVIPS) -t letter manual.dvi -o $@
+ touch $@
+
+# Include images for the manual in the distribution
+dist-hook:
+ BD=`cd $(top_srcdir); pwd`; \
+ if test ! -d $(distdir)/Flags; then mkdir -p $(distdir)/Flags; fi; \
+ cp -p $(srcdir)/Flags/*.gif $(srcdir)/Flags/*.eps $(srcdir)/Flags/*.txt \
+ $(distdir)/Flags;
+ echo "PostScript and PDF versions suitable for printing" \
+ > $(distdir)/manual.ps
+ echo "are available from http://www.mysql.com/Manual/" \
+ >> $(distdir)/manual.ps
+ echo "or any mirror site" \
+ >> $(distdir)/manual.ps
+
+GT = $(srcdir)/Support/generate-text-files.pl
+
+../INSTALL-SOURCE: mysql.info $(GT)
+ perl -w $(GT) mysql.info "Installing" "Compatibility" > $@
+
+# We put the description for the binary installation here so that
+# people who download source wont have to see it. It is moved up to
+# the toplevel by the script that makes the binary tar files.
+INSTALL-BINARY: mysql.info $(GT)
+ perl -w $(GT) mysql.info "Installing binary" "Installing source" > $@
+
+../COPYING: mysql.info $(GT)
+ perl -w $(GT) mysql.info "GPL license" "LGPL license" > $@
+
+../COPYING.LIB: mysql.info $(GT)
+ perl -w $(GT) mysql.info "LGPL license" "Function Index" > $@
+
+../MIRRORS: manual.texi $(srcdir)/Support/generate-mirror-listing.pl
+ perl -w $(srcdir)/Support/generate-mirror-listing.pl manual.texi > $@
diff --git a/Docs/MySQL-logos/mysql-01.gif b/Docs/MySQL-logos/mysql-01.gif
new file mode 100644
index 00000000000..773453f8dd7
--- /dev/null
+++ b/Docs/MySQL-logos/mysql-01.gif
Binary files differ
diff --git a/Docs/MySQL-logos/mysql-02.gif b/Docs/MySQL-logos/mysql-02.gif
new file mode 100644
index 00000000000..12d984b55e0
--- /dev/null
+++ b/Docs/MySQL-logos/mysql-02.gif
Binary files differ
diff --git a/Docs/MySQL-logos/mysql-03.gif b/Docs/MySQL-logos/mysql-03.gif
new file mode 100644
index 00000000000..abb16f2aa59
--- /dev/null
+++ b/Docs/MySQL-logos/mysql-03.gif
Binary files differ
diff --git a/Docs/MySQL-logos/mysql-04.gif b/Docs/MySQL-logos/mysql-04.gif
new file mode 100644
index 00000000000..e207e1790f7
--- /dev/null
+++ b/Docs/MySQL-logos/mysql-04.gif
Binary files differ
diff --git a/Docs/MySQL-logos/mysql-05.gif b/Docs/MySQL-logos/mysql-05.gif
new file mode 100644
index 00000000000..f78b8a17b93
--- /dev/null
+++ b/Docs/MySQL-logos/mysql-05.gif
Binary files differ
diff --git a/Docs/MySQL-logos/mysql-06.gif b/Docs/MySQL-logos/mysql-06.gif
new file mode 100644
index 00000000000..c660e1d1f4f
--- /dev/null
+++ b/Docs/MySQL-logos/mysql-06.gif
Binary files differ
diff --git a/Docs/MySQL-logos/mysql-07.gif b/Docs/MySQL-logos/mysql-07.gif
new file mode 100644
index 00000000000..be309d0de1c
--- /dev/null
+++ b/Docs/MySQL-logos/mysql-07.gif
Binary files differ
diff --git a/Docs/MySQL-logos/mysql-08.gif b/Docs/MySQL-logos/mysql-08.gif
new file mode 100644
index 00000000000..3d5b2135655
--- /dev/null
+++ b/Docs/MySQL-logos/mysql-08.gif
Binary files differ
diff --git a/Docs/MySQL-logos/mysql-09.gif b/Docs/MySQL-logos/mysql-09.gif
new file mode 100644
index 00000000000..75d08592795
--- /dev/null
+++ b/Docs/MySQL-logos/mysql-09.gif
Binary files differ
diff --git a/Docs/MySQL-logos/mysql-10.gif b/Docs/MySQL-logos/mysql-10.gif
new file mode 100644
index 00000000000..8d0a8551e9e
--- /dev/null
+++ b/Docs/MySQL-logos/mysql-10.gif
Binary files differ
diff --git a/Docs/MySQL-logos/mysql-11.gif b/Docs/MySQL-logos/mysql-11.gif
new file mode 100644
index 00000000000..e5f3770a7bd
--- /dev/null
+++ b/Docs/MySQL-logos/mysql-11.gif
Binary files differ
diff --git a/Docs/MySQL-logos/mysql-12.gif b/Docs/MySQL-logos/mysql-12.gif
new file mode 100644
index 00000000000..b045aaf3549
--- /dev/null
+++ b/Docs/MySQL-logos/mysql-12.gif
Binary files differ
diff --git a/Docs/MySQL-logos/mysql-13.gif b/Docs/MySQL-logos/mysql-13.gif
new file mode 100644
index 00000000000..0d5aaf88f6f
--- /dev/null
+++ b/Docs/MySQL-logos/mysql-13.gif
Binary files differ
diff --git a/Docs/MySQL-logos/mysql-14.gif b/Docs/MySQL-logos/mysql-14.gif
new file mode 100644
index 00000000000..9bce287b4b3
--- /dev/null
+++ b/Docs/MySQL-logos/mysql-14.gif
Binary files differ
diff --git a/Docs/MySQL-logos/mysql-15.gif b/Docs/MySQL-logos/mysql-15.gif
new file mode 100644
index 00000000000..d70ffec83dd
--- /dev/null
+++ b/Docs/MySQL-logos/mysql-15.gif
Binary files differ
diff --git a/Docs/MySQL-logos/mysql-16.gif b/Docs/MySQL-logos/mysql-16.gif
new file mode 100644
index 00000000000..9b30833dc1d
--- /dev/null
+++ b/Docs/MySQL-logos/mysql-16.gif
Binary files differ
diff --git a/Docs/MySQL-logos/mysql-17.gif b/Docs/MySQL-logos/mysql-17.gif
new file mode 100644
index 00000000000..5b228496b66
--- /dev/null
+++ b/Docs/MySQL-logos/mysql-17.gif
Binary files differ
diff --git a/Docs/MySQL-logos/mysql-compatible.jpg b/Docs/MySQL-logos/mysql-compatible.jpg
new file mode 100644
index 00000000000..cce9cf84b91
--- /dev/null
+++ b/Docs/MySQL-logos/mysql-compatible.jpg
Binary files differ
diff --git a/Docs/MySQL-logos/mysql_anim-01.gif b/Docs/MySQL-logos/mysql_anim-01.gif
new file mode 100644
index 00000000000..f537d60da41
--- /dev/null
+++ b/Docs/MySQL-logos/mysql_anim-01.gif
Binary files differ
diff --git a/Docs/MySQL-logos/mysql_anim-02.gif b/Docs/MySQL-logos/mysql_anim-02.gif
new file mode 100644
index 00000000000..cfd3e1cfc3e
--- /dev/null
+++ b/Docs/MySQL-logos/mysql_anim-02.gif
Binary files differ
diff --git a/Docs/MySQL-logos/mysql_anim-03.gif b/Docs/MySQL-logos/mysql_anim-03.gif
new file mode 100644
index 00000000000..6ac6b3ebcc1
--- /dev/null
+++ b/Docs/MySQL-logos/mysql_anim-03.gif
Binary files differ
diff --git a/Docs/MySQL-logos/mysql_anim-04.gif b/Docs/MySQL-logos/mysql_anim-04.gif
new file mode 100644
index 00000000000..d3150860ecf
--- /dev/null
+++ b/Docs/MySQL-logos/mysql_anim-04.gif
Binary files differ
diff --git a/Docs/MySQL-logos/mysql_anim-05.gif b/Docs/MySQL-logos/mysql_anim-05.gif
new file mode 100644
index 00000000000..46f288ef71d
--- /dev/null
+++ b/Docs/MySQL-logos/mysql_anim-05.gif
Binary files differ
diff --git a/Docs/MySQL-logos/mysql_anim-06.gif b/Docs/MySQL-logos/mysql_anim-06.gif
new file mode 100644
index 00000000000..3dc283dbfb6
--- /dev/null
+++ b/Docs/MySQL-logos/mysql_anim-06.gif
Binary files differ
diff --git a/Docs/Raw-Flags/afghanistan.gif b/Docs/Raw-Flags/afghanistan.gif
new file mode 100644
index 00000000000..2cd2b54d8f5
--- /dev/null
+++ b/Docs/Raw-Flags/afghanistan.gif
Binary files differ
diff --git a/Docs/Raw-Flags/albania.gif b/Docs/Raw-Flags/albania.gif
new file mode 100644
index 00000000000..d5c8e0c4251
--- /dev/null
+++ b/Docs/Raw-Flags/albania.gif
Binary files differ
diff --git a/Docs/Raw-Flags/algeria.gif b/Docs/Raw-Flags/algeria.gif
new file mode 100644
index 00000000000..db8e4a4f52f
--- /dev/null
+++ b/Docs/Raw-Flags/algeria.gif
Binary files differ
diff --git a/Docs/Raw-Flags/andorra.gif b/Docs/Raw-Flags/andorra.gif
new file mode 100644
index 00000000000..4191a68ed4c
--- /dev/null
+++ b/Docs/Raw-Flags/andorra.gif
Binary files differ
diff --git a/Docs/Raw-Flags/angola.gif b/Docs/Raw-Flags/angola.gif
new file mode 100644
index 00000000000..40cce332a4e
--- /dev/null
+++ b/Docs/Raw-Flags/angola.gif
Binary files differ
diff --git a/Docs/Raw-Flags/antartica.gif b/Docs/Raw-Flags/antartica.gif
new file mode 100644
index 00000000000..3f7eac3f31c
--- /dev/null
+++ b/Docs/Raw-Flags/antartica.gif
Binary files differ
diff --git a/Docs/Raw-Flags/antigua-and-barbuda.gif b/Docs/Raw-Flags/antigua-and-barbuda.gif
new file mode 100644
index 00000000000..8cdc6e9f69c
--- /dev/null
+++ b/Docs/Raw-Flags/antigua-and-barbuda.gif
Binary files differ
diff --git a/Docs/Raw-Flags/argentina.gif b/Docs/Raw-Flags/argentina.gif
new file mode 100644
index 00000000000..dce5943f382
--- /dev/null
+++ b/Docs/Raw-Flags/argentina.gif
Binary files differ
diff --git a/Docs/Raw-Flags/armenia.gif b/Docs/Raw-Flags/armenia.gif
new file mode 100644
index 00000000000..c59294998cf
--- /dev/null
+++ b/Docs/Raw-Flags/armenia.gif
Binary files differ
diff --git a/Docs/Raw-Flags/australia.gif b/Docs/Raw-Flags/australia.gif
new file mode 100644
index 00000000000..0a7174bc277
--- /dev/null
+++ b/Docs/Raw-Flags/australia.gif
Binary files differ
diff --git a/Docs/Raw-Flags/austria.gif b/Docs/Raw-Flags/austria.gif
new file mode 100644
index 00000000000..c4f251ccae3
--- /dev/null
+++ b/Docs/Raw-Flags/austria.gif
Binary files differ
diff --git a/Docs/Raw-Flags/azerbaijan.gif b/Docs/Raw-Flags/azerbaijan.gif
new file mode 100644
index 00000000000..455a21682a2
--- /dev/null
+++ b/Docs/Raw-Flags/azerbaijan.gif
Binary files differ
diff --git a/Docs/Raw-Flags/bahamas.gif b/Docs/Raw-Flags/bahamas.gif
new file mode 100644
index 00000000000..bdfcda7dcfc
--- /dev/null
+++ b/Docs/Raw-Flags/bahamas.gif
Binary files differ
diff --git a/Docs/Raw-Flags/bahrein.gif b/Docs/Raw-Flags/bahrein.gif
new file mode 100644
index 00000000000..3fa9f84a812
--- /dev/null
+++ b/Docs/Raw-Flags/bahrein.gif
Binary files differ
diff --git a/Docs/Raw-Flags/bangladesh.gif b/Docs/Raw-Flags/bangladesh.gif
new file mode 100644
index 00000000000..d16696cfdb2
--- /dev/null
+++ b/Docs/Raw-Flags/bangladesh.gif
Binary files differ
diff --git a/Docs/Raw-Flags/barbados.gif b/Docs/Raw-Flags/barbados.gif
new file mode 100644
index 00000000000..6370aff79ba
--- /dev/null
+++ b/Docs/Raw-Flags/barbados.gif
Binary files differ
diff --git a/Docs/Raw-Flags/belarus.gif b/Docs/Raw-Flags/belarus.gif
new file mode 100644
index 00000000000..68498ad61e8
--- /dev/null
+++ b/Docs/Raw-Flags/belarus.gif
Binary files differ
diff --git a/Docs/Raw-Flags/belgium.gif b/Docs/Raw-Flags/belgium.gif
new file mode 100644
index 00000000000..6822fd4d923
--- /dev/null
+++ b/Docs/Raw-Flags/belgium.gif
Binary files differ
diff --git a/Docs/Raw-Flags/belize.gif b/Docs/Raw-Flags/belize.gif
new file mode 100644
index 00000000000..9665a50b0ae
--- /dev/null
+++ b/Docs/Raw-Flags/belize.gif
Binary files differ
diff --git a/Docs/Raw-Flags/benin.gif b/Docs/Raw-Flags/benin.gif
new file mode 100644
index 00000000000..3b29c8a1210
--- /dev/null
+++ b/Docs/Raw-Flags/benin.gif
Binary files differ
diff --git a/Docs/Raw-Flags/bermuda.gif b/Docs/Raw-Flags/bermuda.gif
new file mode 100644
index 00000000000..e46e200e6ea
--- /dev/null
+++ b/Docs/Raw-Flags/bermuda.gif
Binary files differ
diff --git a/Docs/Raw-Flags/bhutan.gif b/Docs/Raw-Flags/bhutan.gif
new file mode 100644
index 00000000000..52ed6ad162e
--- /dev/null
+++ b/Docs/Raw-Flags/bhutan.gif
Binary files differ
diff --git a/Docs/Raw-Flags/bolivia.gif b/Docs/Raw-Flags/bolivia.gif
new file mode 100644
index 00000000000..8b2491294a9
--- /dev/null
+++ b/Docs/Raw-Flags/bolivia.gif
Binary files differ
diff --git a/Docs/Raw-Flags/bosnia-and-herzegovina.gif b/Docs/Raw-Flags/bosnia-and-herzegovina.gif
new file mode 100644
index 00000000000..c01717206ef
--- /dev/null
+++ b/Docs/Raw-Flags/bosnia-and-herzegovina.gif
Binary files differ
diff --git a/Docs/Raw-Flags/botswana.gif b/Docs/Raw-Flags/botswana.gif
new file mode 100644
index 00000000000..7ffc9b76f36
--- /dev/null
+++ b/Docs/Raw-Flags/botswana.gif
Binary files differ
diff --git a/Docs/Raw-Flags/brazil.gif b/Docs/Raw-Flags/brazil.gif
new file mode 100644
index 00000000000..92a2fe82ef1
--- /dev/null
+++ b/Docs/Raw-Flags/brazil.gif
Binary files differ
diff --git a/Docs/Raw-Flags/brunei.gif b/Docs/Raw-Flags/brunei.gif
new file mode 100644
index 00000000000..d64d5c381a0
--- /dev/null
+++ b/Docs/Raw-Flags/brunei.gif
Binary files differ
diff --git a/Docs/Raw-Flags/bulgaria.gif b/Docs/Raw-Flags/bulgaria.gif
new file mode 100644
index 00000000000..7df52d126b5
--- /dev/null
+++ b/Docs/Raw-Flags/bulgaria.gif
Binary files differ
diff --git a/Docs/Raw-Flags/burkina-faso.gif b/Docs/Raw-Flags/burkina-faso.gif
new file mode 100644
index 00000000000..803e1d6e9c1
--- /dev/null
+++ b/Docs/Raw-Flags/burkina-faso.gif
Binary files differ
diff --git a/Docs/Raw-Flags/burma.gif b/Docs/Raw-Flags/burma.gif
new file mode 100644
index 00000000000..44d63cc1e18
--- /dev/null
+++ b/Docs/Raw-Flags/burma.gif
Binary files differ
diff --git a/Docs/Raw-Flags/burundi.gif b/Docs/Raw-Flags/burundi.gif
new file mode 100644
index 00000000000..dee8e5ef7cd
--- /dev/null
+++ b/Docs/Raw-Flags/burundi.gif
Binary files differ
diff --git a/Docs/Raw-Flags/cambodia.gif b/Docs/Raw-Flags/cambodia.gif
new file mode 100644
index 00000000000..95314128b2c
--- /dev/null
+++ b/Docs/Raw-Flags/cambodia.gif
Binary files differ
diff --git a/Docs/Raw-Flags/cameroon.gif b/Docs/Raw-Flags/cameroon.gif
new file mode 100644
index 00000000000..5fcd73b81d3
--- /dev/null
+++ b/Docs/Raw-Flags/cameroon.gif
Binary files differ
diff --git a/Docs/Raw-Flags/canada.gif b/Docs/Raw-Flags/canada.gif
new file mode 100644
index 00000000000..e4aafab3ec2
--- /dev/null
+++ b/Docs/Raw-Flags/canada.gif
Binary files differ
diff --git a/Docs/Raw-Flags/cape-verde.gif b/Docs/Raw-Flags/cape-verde.gif
new file mode 100644
index 00000000000..dc2712c4e12
--- /dev/null
+++ b/Docs/Raw-Flags/cape-verde.gif
Binary files differ
diff --git a/Docs/Raw-Flags/central-african-republic.gif b/Docs/Raw-Flags/central-african-republic.gif
new file mode 100644
index 00000000000..8bd1dc3d15f
--- /dev/null
+++ b/Docs/Raw-Flags/central-african-republic.gif
Binary files differ
diff --git a/Docs/Raw-Flags/chad.gif b/Docs/Raw-Flags/chad.gif
new file mode 100644
index 00000000000..6dace6197af
--- /dev/null
+++ b/Docs/Raw-Flags/chad.gif
Binary files differ
diff --git a/Docs/Raw-Flags/chile.gif b/Docs/Raw-Flags/chile.gif
new file mode 100644
index 00000000000..30b16b6f335
--- /dev/null
+++ b/Docs/Raw-Flags/chile.gif
Binary files differ
diff --git a/Docs/Raw-Flags/china.gif b/Docs/Raw-Flags/china.gif
new file mode 100644
index 00000000000..211ebf52d3c
--- /dev/null
+++ b/Docs/Raw-Flags/china.gif
Binary files differ
diff --git a/Docs/Raw-Flags/colombia.gif b/Docs/Raw-Flags/colombia.gif
new file mode 100644
index 00000000000..f6f790c1b88
--- /dev/null
+++ b/Docs/Raw-Flags/colombia.gif
Binary files differ
diff --git a/Docs/Raw-Flags/comoros.gif b/Docs/Raw-Flags/comoros.gif
new file mode 100644
index 00000000000..13f8da6111e
--- /dev/null
+++ b/Docs/Raw-Flags/comoros.gif
Binary files differ
diff --git a/Docs/Raw-Flags/congo.gif b/Docs/Raw-Flags/congo.gif
new file mode 100644
index 00000000000..2d485dcca6d
--- /dev/null
+++ b/Docs/Raw-Flags/congo.gif
Binary files differ
diff --git a/Docs/Raw-Flags/costa-rica.gif b/Docs/Raw-Flags/costa-rica.gif
new file mode 100644
index 00000000000..d52b6dddb1b
--- /dev/null
+++ b/Docs/Raw-Flags/costa-rica.gif
Binary files differ
diff --git a/Docs/Raw-Flags/cote-d-ivoire.gif b/Docs/Raw-Flags/cote-d-ivoire.gif
new file mode 100644
index 00000000000..e7323be021f
--- /dev/null
+++ b/Docs/Raw-Flags/cote-d-ivoire.gif
Binary files differ
diff --git a/Docs/Raw-Flags/croatia.gif b/Docs/Raw-Flags/croatia.gif
new file mode 100644
index 00000000000..25c69200761
--- /dev/null
+++ b/Docs/Raw-Flags/croatia.gif
Binary files differ
diff --git a/Docs/Raw-Flags/cuba.gif b/Docs/Raw-Flags/cuba.gif
new file mode 100644
index 00000000000..0e2b6164b96
--- /dev/null
+++ b/Docs/Raw-Flags/cuba.gif
Binary files differ
diff --git a/Docs/Raw-Flags/cyprus.gif b/Docs/Raw-Flags/cyprus.gif
new file mode 100644
index 00000000000..7ee3602d91d
--- /dev/null
+++ b/Docs/Raw-Flags/cyprus.gif
Binary files differ
diff --git a/Docs/Raw-Flags/czech-republic.gif b/Docs/Raw-Flags/czech-republic.gif
new file mode 100644
index 00000000000..e99651120bb
--- /dev/null
+++ b/Docs/Raw-Flags/czech-republic.gif
Binary files differ
diff --git a/Docs/Raw-Flags/denmark-original-incorrect.gif b/Docs/Raw-Flags/denmark-original-incorrect.gif
new file mode 100644
index 00000000000..e1be8f21764
--- /dev/null
+++ b/Docs/Raw-Flags/denmark-original-incorrect.gif
Binary files differ
diff --git a/Docs/Raw-Flags/denmark.gif b/Docs/Raw-Flags/denmark.gif
new file mode 100644
index 00000000000..336f9a2f39f
--- /dev/null
+++ b/Docs/Raw-Flags/denmark.gif
Binary files differ
diff --git a/Docs/Raw-Flags/djibouti.gif b/Docs/Raw-Flags/djibouti.gif
new file mode 100644
index 00000000000..c30c7b47822
--- /dev/null
+++ b/Docs/Raw-Flags/djibouti.gif
Binary files differ
diff --git a/Docs/Raw-Flags/dominica.gif b/Docs/Raw-Flags/dominica.gif
new file mode 100644
index 00000000000..ae69b33be58
--- /dev/null
+++ b/Docs/Raw-Flags/dominica.gif
Binary files differ
diff --git a/Docs/Raw-Flags/dominican-republic.gif b/Docs/Raw-Flags/dominican-republic.gif
new file mode 100644
index 00000000000..e2620c5b50f
--- /dev/null
+++ b/Docs/Raw-Flags/dominican-republic.gif
Binary files differ
diff --git a/Docs/Raw-Flags/ecuador.gif b/Docs/Raw-Flags/ecuador.gif
new file mode 100644
index 00000000000..ff94fc4a173
--- /dev/null
+++ b/Docs/Raw-Flags/ecuador.gif
Binary files differ
diff --git a/Docs/Raw-Flags/egypt.gif b/Docs/Raw-Flags/egypt.gif
new file mode 100644
index 00000000000..ba6a51e67bf
--- /dev/null
+++ b/Docs/Raw-Flags/egypt.gif
Binary files differ
diff --git a/Docs/Raw-Flags/el-salvador.gif b/Docs/Raw-Flags/el-salvador.gif
new file mode 100644
index 00000000000..602af34927b
--- /dev/null
+++ b/Docs/Raw-Flags/el-salvador.gif
Binary files differ
diff --git a/Docs/Raw-Flags/equatorial-guinea.gif b/Docs/Raw-Flags/equatorial-guinea.gif
new file mode 100644
index 00000000000..c35e9e613d0
--- /dev/null
+++ b/Docs/Raw-Flags/equatorial-guinea.gif
Binary files differ
diff --git a/Docs/Raw-Flags/eritrea.gif b/Docs/Raw-Flags/eritrea.gif
new file mode 100644
index 00000000000..127a185547a
--- /dev/null
+++ b/Docs/Raw-Flags/eritrea.gif
Binary files differ
diff --git a/Docs/Raw-Flags/estonia.gif b/Docs/Raw-Flags/estonia.gif
new file mode 100644
index 00000000000..3462f84c4df
--- /dev/null
+++ b/Docs/Raw-Flags/estonia.gif
Binary files differ
diff --git a/Docs/Raw-Flags/ethiopia.gif b/Docs/Raw-Flags/ethiopia.gif
new file mode 100644
index 00000000000..5f3611ed09e
--- /dev/null
+++ b/Docs/Raw-Flags/ethiopia.gif
Binary files differ
diff --git a/Docs/Raw-Flags/fiji.gif b/Docs/Raw-Flags/fiji.gif
new file mode 100644
index 00000000000..b20bbd3d467
--- /dev/null
+++ b/Docs/Raw-Flags/fiji.gif
Binary files differ
diff --git a/Docs/Raw-Flags/finland.gif b/Docs/Raw-Flags/finland.gif
new file mode 100644
index 00000000000..b923a5b6850
--- /dev/null
+++ b/Docs/Raw-Flags/finland.gif
Binary files differ
diff --git a/Docs/Raw-Flags/france.gif b/Docs/Raw-Flags/france.gif
new file mode 100644
index 00000000000..3f34a4feada
--- /dev/null
+++ b/Docs/Raw-Flags/france.gif
Binary files differ
diff --git a/Docs/Raw-Flags/gabon.gif b/Docs/Raw-Flags/gabon.gif
new file mode 100644
index 00000000000..ec10b2ee0b0
--- /dev/null
+++ b/Docs/Raw-Flags/gabon.gif
Binary files differ
diff --git a/Docs/Raw-Flags/gambia.gif b/Docs/Raw-Flags/gambia.gif
new file mode 100644
index 00000000000..590a4242fdc
--- /dev/null
+++ b/Docs/Raw-Flags/gambia.gif
Binary files differ
diff --git a/Docs/Raw-Flags/georgia.gif b/Docs/Raw-Flags/georgia.gif
new file mode 100644
index 00000000000..ffa94298ec8
--- /dev/null
+++ b/Docs/Raw-Flags/georgia.gif
Binary files differ
diff --git a/Docs/Raw-Flags/germany.gif b/Docs/Raw-Flags/germany.gif
new file mode 100644
index 00000000000..4045cd0fa29
--- /dev/null
+++ b/Docs/Raw-Flags/germany.gif
Binary files differ
diff --git a/Docs/Raw-Flags/ghana.gif b/Docs/Raw-Flags/ghana.gif
new file mode 100644
index 00000000000..f87596c1a19
--- /dev/null
+++ b/Docs/Raw-Flags/ghana.gif
Binary files differ
diff --git a/Docs/Raw-Flags/great-britain.gif b/Docs/Raw-Flags/great-britain.gif
new file mode 100644
index 00000000000..093d611c60c
--- /dev/null
+++ b/Docs/Raw-Flags/great-britain.gif
Binary files differ
diff --git a/Docs/Raw-Flags/greece.gif b/Docs/Raw-Flags/greece.gif
new file mode 100644
index 00000000000..26b0b18a28f
--- /dev/null
+++ b/Docs/Raw-Flags/greece.gif
Binary files differ
diff --git a/Docs/Raw-Flags/greenland.gif b/Docs/Raw-Flags/greenland.gif
new file mode 100644
index 00000000000..3885b7c8352
--- /dev/null
+++ b/Docs/Raw-Flags/greenland.gif
Binary files differ
diff --git a/Docs/Raw-Flags/grenada.gif b/Docs/Raw-Flags/grenada.gif
new file mode 100644
index 00000000000..f429051f7eb
--- /dev/null
+++ b/Docs/Raw-Flags/grenada.gif
Binary files differ
diff --git a/Docs/Raw-Flags/guatemala.gif b/Docs/Raw-Flags/guatemala.gif
new file mode 100644
index 00000000000..6d3684ed31b
--- /dev/null
+++ b/Docs/Raw-Flags/guatemala.gif
Binary files differ
diff --git a/Docs/Raw-Flags/guinea-bissau.gif b/Docs/Raw-Flags/guinea-bissau.gif
new file mode 100644
index 00000000000..adcabbda0ab
--- /dev/null
+++ b/Docs/Raw-Flags/guinea-bissau.gif
Binary files differ
diff --git a/Docs/Raw-Flags/guinea.gif b/Docs/Raw-Flags/guinea.gif
new file mode 100644
index 00000000000..ecc584d2e3b
--- /dev/null
+++ b/Docs/Raw-Flags/guinea.gif
Binary files differ
diff --git a/Docs/Raw-Flags/guyana.gif b/Docs/Raw-Flags/guyana.gif
new file mode 100644
index 00000000000..55385b9a3f5
--- /dev/null
+++ b/Docs/Raw-Flags/guyana.gif
Binary files differ
diff --git a/Docs/Raw-Flags/haiti.gif b/Docs/Raw-Flags/haiti.gif
new file mode 100644
index 00000000000..fe6cdee72bb
--- /dev/null
+++ b/Docs/Raw-Flags/haiti.gif
Binary files differ
diff --git a/Docs/Raw-Flags/honduras.gif b/Docs/Raw-Flags/honduras.gif
new file mode 100644
index 00000000000..1136e352d91
--- /dev/null
+++ b/Docs/Raw-Flags/honduras.gif
Binary files differ
diff --git a/Docs/Raw-Flags/hungary.gif b/Docs/Raw-Flags/hungary.gif
new file mode 100644
index 00000000000..48e1741d8ea
--- /dev/null
+++ b/Docs/Raw-Flags/hungary.gif
Binary files differ
diff --git a/Docs/Raw-Flags/iceland.gif b/Docs/Raw-Flags/iceland.gif
new file mode 100644
index 00000000000..9ba19690ea3
--- /dev/null
+++ b/Docs/Raw-Flags/iceland.gif
Binary files differ
diff --git a/Docs/Raw-Flags/india.gif b/Docs/Raw-Flags/india.gif
new file mode 100644
index 00000000000..5e51de863f5
--- /dev/null
+++ b/Docs/Raw-Flags/india.gif
Binary files differ
diff --git a/Docs/Raw-Flags/indonesia.gif b/Docs/Raw-Flags/indonesia.gif
new file mode 100644
index 00000000000..bf6bec293c7
--- /dev/null
+++ b/Docs/Raw-Flags/indonesia.gif
Binary files differ
diff --git a/Docs/Raw-Flags/iran.gif b/Docs/Raw-Flags/iran.gif
new file mode 100644
index 00000000000..cdab0112459
--- /dev/null
+++ b/Docs/Raw-Flags/iran.gif
Binary files differ
diff --git a/Docs/Raw-Flags/iraq.gif b/Docs/Raw-Flags/iraq.gif
new file mode 100644
index 00000000000..2437eec12f8
--- /dev/null
+++ b/Docs/Raw-Flags/iraq.gif
Binary files differ
diff --git a/Docs/Raw-Flags/ireland.gif b/Docs/Raw-Flags/ireland.gif
new file mode 100644
index 00000000000..a69001e19a9
--- /dev/null
+++ b/Docs/Raw-Flags/ireland.gif
Binary files differ
diff --git a/Docs/Raw-Flags/israel.gif b/Docs/Raw-Flags/israel.gif
new file mode 100644
index 00000000000..e349db15526
--- /dev/null
+++ b/Docs/Raw-Flags/israel.gif
Binary files differ
diff --git a/Docs/Raw-Flags/italy.gif b/Docs/Raw-Flags/italy.gif
new file mode 100644
index 00000000000..8b2a67c75ab
--- /dev/null
+++ b/Docs/Raw-Flags/italy.gif
Binary files differ
diff --git a/Docs/Raw-Flags/jamaica.gif b/Docs/Raw-Flags/jamaica.gif
new file mode 100644
index 00000000000..16e30216ba6
--- /dev/null
+++ b/Docs/Raw-Flags/jamaica.gif
Binary files differ
diff --git a/Docs/Raw-Flags/japan.gif b/Docs/Raw-Flags/japan.gif
new file mode 100644
index 00000000000..a4cbf7ac5ca
--- /dev/null
+++ b/Docs/Raw-Flags/japan.gif
Binary files differ
diff --git a/Docs/Raw-Flags/jordan.gif b/Docs/Raw-Flags/jordan.gif
new file mode 100644
index 00000000000..ca4d16c2d22
--- /dev/null
+++ b/Docs/Raw-Flags/jordan.gif
Binary files differ
diff --git a/Docs/Raw-Flags/kazakhstan.gif b/Docs/Raw-Flags/kazakhstan.gif
new file mode 100644
index 00000000000..b687186342f
--- /dev/null
+++ b/Docs/Raw-Flags/kazakhstan.gif
Binary files differ
diff --git a/Docs/Raw-Flags/kenya.gif b/Docs/Raw-Flags/kenya.gif
new file mode 100644
index 00000000000..2b4ff6e682b
--- /dev/null
+++ b/Docs/Raw-Flags/kenya.gif
Binary files differ
diff --git a/Docs/Raw-Flags/kiribati.gif b/Docs/Raw-Flags/kiribati.gif
new file mode 100644
index 00000000000..0e4ba3832d3
--- /dev/null
+++ b/Docs/Raw-Flags/kiribati.gif
Binary files differ
diff --git a/Docs/Raw-Flags/kuwait.gif b/Docs/Raw-Flags/kuwait.gif
new file mode 100644
index 00000000000..007664b6d68
--- /dev/null
+++ b/Docs/Raw-Flags/kuwait.gif
Binary files differ
diff --git a/Docs/Raw-Flags/kyrgyzstan.gif b/Docs/Raw-Flags/kyrgyzstan.gif
new file mode 100644
index 00000000000..0a22c27173f
--- /dev/null
+++ b/Docs/Raw-Flags/kyrgyzstan.gif
Binary files differ
diff --git a/Docs/Raw-Flags/laos.gif b/Docs/Raw-Flags/laos.gif
new file mode 100644
index 00000000000..f9f43106038
--- /dev/null
+++ b/Docs/Raw-Flags/laos.gif
Binary files differ
diff --git a/Docs/Raw-Flags/latvia.gif b/Docs/Raw-Flags/latvia.gif
new file mode 100644
index 00000000000..a364abdabaa
--- /dev/null
+++ b/Docs/Raw-Flags/latvia.gif
Binary files differ
diff --git a/Docs/Raw-Flags/lebanon.gif b/Docs/Raw-Flags/lebanon.gif
new file mode 100644
index 00000000000..524b6c60b1c
--- /dev/null
+++ b/Docs/Raw-Flags/lebanon.gif
Binary files differ
diff --git a/Docs/Raw-Flags/lesotho.gif b/Docs/Raw-Flags/lesotho.gif
new file mode 100644
index 00000000000..de242ec77d1
--- /dev/null
+++ b/Docs/Raw-Flags/lesotho.gif
Binary files differ
diff --git a/Docs/Raw-Flags/liberia.gif b/Docs/Raw-Flags/liberia.gif
new file mode 100644
index 00000000000..f1b908e5fa0
--- /dev/null
+++ b/Docs/Raw-Flags/liberia.gif
Binary files differ
diff --git a/Docs/Raw-Flags/libya.gif b/Docs/Raw-Flags/libya.gif
new file mode 100644
index 00000000000..55a121435cc
--- /dev/null
+++ b/Docs/Raw-Flags/libya.gif
Binary files differ
diff --git a/Docs/Raw-Flags/liechtenstein.gif b/Docs/Raw-Flags/liechtenstein.gif
new file mode 100644
index 00000000000..fe24e828b0b
--- /dev/null
+++ b/Docs/Raw-Flags/liechtenstein.gif
Binary files differ
diff --git a/Docs/Raw-Flags/lithuania.gif b/Docs/Raw-Flags/lithuania.gif
new file mode 100644
index 00000000000..849d0a17d9a
--- /dev/null
+++ b/Docs/Raw-Flags/lithuania.gif
Binary files differ
diff --git a/Docs/Raw-Flags/luxembourg.gif b/Docs/Raw-Flags/luxembourg.gif
new file mode 100644
index 00000000000..9ec9d31a439
--- /dev/null
+++ b/Docs/Raw-Flags/luxembourg.gif
Binary files differ
diff --git a/Docs/Raw-Flags/macedonia.gif b/Docs/Raw-Flags/macedonia.gif
new file mode 100644
index 00000000000..174506e0021
--- /dev/null
+++ b/Docs/Raw-Flags/macedonia.gif
Binary files differ
diff --git a/Docs/Raw-Flags/madagascar.gif b/Docs/Raw-Flags/madagascar.gif
new file mode 100644
index 00000000000..18db5d26ff5
--- /dev/null
+++ b/Docs/Raw-Flags/madagascar.gif
Binary files differ
diff --git a/Docs/Raw-Flags/malawi.gif b/Docs/Raw-Flags/malawi.gif
new file mode 100644
index 00000000000..76ffcf0585d
--- /dev/null
+++ b/Docs/Raw-Flags/malawi.gif
Binary files differ
diff --git a/Docs/Raw-Flags/malaysia.gif b/Docs/Raw-Flags/malaysia.gif
new file mode 100644
index 00000000000..d29656ebefe
--- /dev/null
+++ b/Docs/Raw-Flags/malaysia.gif
Binary files differ
diff --git a/Docs/Raw-Flags/maldives.gif b/Docs/Raw-Flags/maldives.gif
new file mode 100644
index 00000000000..c0c53d9a868
--- /dev/null
+++ b/Docs/Raw-Flags/maldives.gif
Binary files differ
diff --git a/Docs/Raw-Flags/mali.gif b/Docs/Raw-Flags/mali.gif
new file mode 100644
index 00000000000..b2430b3de65
--- /dev/null
+++ b/Docs/Raw-Flags/mali.gif
Binary files differ
diff --git a/Docs/Raw-Flags/malta.gif b/Docs/Raw-Flags/malta.gif
new file mode 100644
index 00000000000..1db0ec66a8b
--- /dev/null
+++ b/Docs/Raw-Flags/malta.gif
Binary files differ
diff --git a/Docs/Raw-Flags/marshall.gif b/Docs/Raw-Flags/marshall.gif
new file mode 100644
index 00000000000..3574580b4da
--- /dev/null
+++ b/Docs/Raw-Flags/marshall.gif
Binary files differ
diff --git a/Docs/Raw-Flags/mauritania.gif b/Docs/Raw-Flags/mauritania.gif
new file mode 100644
index 00000000000..3cc19a06f7b
--- /dev/null
+++ b/Docs/Raw-Flags/mauritania.gif
Binary files differ
diff --git a/Docs/Raw-Flags/mauritius.gif b/Docs/Raw-Flags/mauritius.gif
new file mode 100644
index 00000000000..042083b74a7
--- /dev/null
+++ b/Docs/Raw-Flags/mauritius.gif
Binary files differ
diff --git a/Docs/Raw-Flags/mexico.gif b/Docs/Raw-Flags/mexico.gif
new file mode 100644
index 00000000000..978968cc2e3
--- /dev/null
+++ b/Docs/Raw-Flags/mexico.gif
Binary files differ
diff --git a/Docs/Raw-Flags/micronesia.gif b/Docs/Raw-Flags/micronesia.gif
new file mode 100644
index 00000000000..08ac921fbae
--- /dev/null
+++ b/Docs/Raw-Flags/micronesia.gif
Binary files differ
diff --git a/Docs/Raw-Flags/moldova.gif b/Docs/Raw-Flags/moldova.gif
new file mode 100644
index 00000000000..553aaefa510
--- /dev/null
+++ b/Docs/Raw-Flags/moldova.gif
Binary files differ
diff --git a/Docs/Raw-Flags/monaco.gif b/Docs/Raw-Flags/monaco.gif
new file mode 100644
index 00000000000..bf6bec293c7
--- /dev/null
+++ b/Docs/Raw-Flags/monaco.gif
Binary files differ
diff --git a/Docs/Raw-Flags/mongolia.gif b/Docs/Raw-Flags/mongolia.gif
new file mode 100644
index 00000000000..b5031d9fba5
--- /dev/null
+++ b/Docs/Raw-Flags/mongolia.gif
Binary files differ
diff --git a/Docs/Raw-Flags/morocco.gif b/Docs/Raw-Flags/morocco.gif
new file mode 100644
index 00000000000..3dbd19fc45a
--- /dev/null
+++ b/Docs/Raw-Flags/morocco.gif
Binary files differ
diff --git a/Docs/Raw-Flags/mozambique.gif b/Docs/Raw-Flags/mozambique.gif
new file mode 100644
index 00000000000..3bcafc6b40c
--- /dev/null
+++ b/Docs/Raw-Flags/mozambique.gif
Binary files differ
diff --git a/Docs/Raw-Flags/namibia.gif b/Docs/Raw-Flags/namibia.gif
new file mode 100644
index 00000000000..7d8ad5d8771
--- /dev/null
+++ b/Docs/Raw-Flags/namibia.gif
Binary files differ
diff --git a/Docs/Raw-Flags/nauru.gif b/Docs/Raw-Flags/nauru.gif
new file mode 100644
index 00000000000..234ec7db143
--- /dev/null
+++ b/Docs/Raw-Flags/nauru.gif
Binary files differ
diff --git a/Docs/Raw-Flags/nepal.gif b/Docs/Raw-Flags/nepal.gif
new file mode 100644
index 00000000000..8d536ee4d3b
--- /dev/null
+++ b/Docs/Raw-Flags/nepal.gif
Binary files differ
diff --git a/Docs/Raw-Flags/netherlands.gif b/Docs/Raw-Flags/netherlands.gif
new file mode 100644
index 00000000000..8b170f1e0e8
--- /dev/null
+++ b/Docs/Raw-Flags/netherlands.gif
Binary files differ
diff --git a/Docs/Raw-Flags/new-zealand.gif b/Docs/Raw-Flags/new-zealand.gif
new file mode 100644
index 00000000000..4345c82e5be
--- /dev/null
+++ b/Docs/Raw-Flags/new-zealand.gif
Binary files differ
diff --git a/Docs/Raw-Flags/nicaragua.gif b/Docs/Raw-Flags/nicaragua.gif
new file mode 100644
index 00000000000..366ea5098f5
--- /dev/null
+++ b/Docs/Raw-Flags/nicaragua.gif
Binary files differ
diff --git a/Docs/Raw-Flags/niger.gif b/Docs/Raw-Flags/niger.gif
new file mode 100644
index 00000000000..d95591ec177
--- /dev/null
+++ b/Docs/Raw-Flags/niger.gif
Binary files differ
diff --git a/Docs/Raw-Flags/nigeria.gif b/Docs/Raw-Flags/nigeria.gif
new file mode 100644
index 00000000000..b80eeb0c4ab
--- /dev/null
+++ b/Docs/Raw-Flags/nigeria.gif
Binary files differ
diff --git a/Docs/Raw-Flags/north-korea.gif b/Docs/Raw-Flags/north-korea.gif
new file mode 100644
index 00000000000..83de4035423
--- /dev/null
+++ b/Docs/Raw-Flags/north-korea.gif
Binary files differ
diff --git a/Docs/Raw-Flags/norway.gif b/Docs/Raw-Flags/norway.gif
new file mode 100644
index 00000000000..936d41fb6c3
--- /dev/null
+++ b/Docs/Raw-Flags/norway.gif
Binary files differ
diff --git a/Docs/Raw-Flags/oman.gif b/Docs/Raw-Flags/oman.gif
new file mode 100644
index 00000000000..df611c57ad2
--- /dev/null
+++ b/Docs/Raw-Flags/oman.gif
Binary files differ
diff --git a/Docs/Raw-Flags/pakistan.gif b/Docs/Raw-Flags/pakistan.gif
new file mode 100644
index 00000000000..455846aad70
--- /dev/null
+++ b/Docs/Raw-Flags/pakistan.gif
Binary files differ
diff --git a/Docs/Raw-Flags/panama.gif b/Docs/Raw-Flags/panama.gif
new file mode 100644
index 00000000000..47dd1b70c85
--- /dev/null
+++ b/Docs/Raw-Flags/panama.gif
Binary files differ
diff --git a/Docs/Raw-Flags/papua-new-guinea.gif b/Docs/Raw-Flags/papua-new-guinea.gif
new file mode 100644
index 00000000000..a59c0d5a25d
--- /dev/null
+++ b/Docs/Raw-Flags/papua-new-guinea.gif
Binary files differ
diff --git a/Docs/Raw-Flags/paraguay.gif b/Docs/Raw-Flags/paraguay.gif
new file mode 100644
index 00000000000..8a9ba1b2688
--- /dev/null
+++ b/Docs/Raw-Flags/paraguay.gif
Binary files differ
diff --git a/Docs/Raw-Flags/peru.gif b/Docs/Raw-Flags/peru.gif
new file mode 100644
index 00000000000..d07cfc047df
--- /dev/null
+++ b/Docs/Raw-Flags/peru.gif
Binary files differ
diff --git a/Docs/Raw-Flags/philippines.gif b/Docs/Raw-Flags/philippines.gif
new file mode 100644
index 00000000000..9c2a2667c3c
--- /dev/null
+++ b/Docs/Raw-Flags/philippines.gif
Binary files differ
diff --git a/Docs/Raw-Flags/poland.gif b/Docs/Raw-Flags/poland.gif
new file mode 100644
index 00000000000..f6a26701ee9
--- /dev/null
+++ b/Docs/Raw-Flags/poland.gif
Binary files differ
diff --git a/Docs/Raw-Flags/portugal.gif b/Docs/Raw-Flags/portugal.gif
new file mode 100644
index 00000000000..59d8bc06d68
--- /dev/null
+++ b/Docs/Raw-Flags/portugal.gif
Binary files differ
diff --git a/Docs/Raw-Flags/qatar.gif b/Docs/Raw-Flags/qatar.gif
new file mode 100644
index 00000000000..a61a85f7e6a
--- /dev/null
+++ b/Docs/Raw-Flags/qatar.gif
Binary files differ
diff --git a/Docs/Raw-Flags/romania.gif b/Docs/Raw-Flags/romania.gif
new file mode 100644
index 00000000000..2214685caf0
--- /dev/null
+++ b/Docs/Raw-Flags/romania.gif
Binary files differ
diff --git a/Docs/Raw-Flags/russia.gif b/Docs/Raw-Flags/russia.gif
new file mode 100644
index 00000000000..3f52bd7d490
--- /dev/null
+++ b/Docs/Raw-Flags/russia.gif
Binary files differ
diff --git a/Docs/Raw-Flags/rwanda.gif b/Docs/Raw-Flags/rwanda.gif
new file mode 100644
index 00000000000..71433f13b65
--- /dev/null
+++ b/Docs/Raw-Flags/rwanda.gif
Binary files differ
diff --git a/Docs/Raw-Flags/saint-kitts-and-nevis.gif b/Docs/Raw-Flags/saint-kitts-and-nevis.gif
new file mode 100644
index 00000000000..8036b6a1e5c
--- /dev/null
+++ b/Docs/Raw-Flags/saint-kitts-and-nevis.gif
Binary files differ
diff --git a/Docs/Raw-Flags/saint-lucia.gif b/Docs/Raw-Flags/saint-lucia.gif
new file mode 100644
index 00000000000..ff7043fe307
--- /dev/null
+++ b/Docs/Raw-Flags/saint-lucia.gif
Binary files differ
diff --git a/Docs/Raw-Flags/samoa.gif b/Docs/Raw-Flags/samoa.gif
new file mode 100644
index 00000000000..08f135c84dc
--- /dev/null
+++ b/Docs/Raw-Flags/samoa.gif
Binary files differ
diff --git a/Docs/Raw-Flags/sao-tome-and-principe.gif b/Docs/Raw-Flags/sao-tome-and-principe.gif
new file mode 100644
index 00000000000..046c6d9155b
--- /dev/null
+++ b/Docs/Raw-Flags/sao-tome-and-principe.gif
Binary files differ
diff --git a/Docs/Raw-Flags/saudi-arabia.gif b/Docs/Raw-Flags/saudi-arabia.gif
new file mode 100644
index 00000000000..02838b2aa3d
--- /dev/null
+++ b/Docs/Raw-Flags/saudi-arabia.gif
Binary files differ
diff --git a/Docs/Raw-Flags/senegal.gif b/Docs/Raw-Flags/senegal.gif
new file mode 100644
index 00000000000..e1de2967ce4
--- /dev/null
+++ b/Docs/Raw-Flags/senegal.gif
Binary files differ
diff --git a/Docs/Raw-Flags/seychelles.gif b/Docs/Raw-Flags/seychelles.gif
new file mode 100644
index 00000000000..3d647a269ee
--- /dev/null
+++ b/Docs/Raw-Flags/seychelles.gif
Binary files differ
diff --git a/Docs/Raw-Flags/sierra-leone.gif b/Docs/Raw-Flags/sierra-leone.gif
new file mode 100644
index 00000000000..41d5ca1c7eb
--- /dev/null
+++ b/Docs/Raw-Flags/sierra-leone.gif
Binary files differ
diff --git a/Docs/Raw-Flags/singapore.gif b/Docs/Raw-Flags/singapore.gif
new file mode 100644
index 00000000000..39e32de4179
--- /dev/null
+++ b/Docs/Raw-Flags/singapore.gif
Binary files differ
diff --git a/Docs/Raw-Flags/slovakia.gif b/Docs/Raw-Flags/slovakia.gif
new file mode 100644
index 00000000000..f997d1ca8e6
--- /dev/null
+++ b/Docs/Raw-Flags/slovakia.gif
Binary files differ
diff --git a/Docs/Raw-Flags/slovenia.gif b/Docs/Raw-Flags/slovenia.gif
new file mode 100644
index 00000000000..05ff9f74b32
--- /dev/null
+++ b/Docs/Raw-Flags/slovenia.gif
Binary files differ
diff --git a/Docs/Raw-Flags/solomon-islands.gif b/Docs/Raw-Flags/solomon-islands.gif
new file mode 100644
index 00000000000..7fe42e8cd8e
--- /dev/null
+++ b/Docs/Raw-Flags/solomon-islands.gif
Binary files differ
diff --git a/Docs/Raw-Flags/somalia.gif b/Docs/Raw-Flags/somalia.gif
new file mode 100644
index 00000000000..50876564aa8
--- /dev/null
+++ b/Docs/Raw-Flags/somalia.gif
Binary files differ
diff --git a/Docs/Raw-Flags/south-africa.gif b/Docs/Raw-Flags/south-africa.gif
new file mode 100644
index 00000000000..48164f22111
--- /dev/null
+++ b/Docs/Raw-Flags/south-africa.gif
Binary files differ
diff --git a/Docs/Raw-Flags/south-korea.gif b/Docs/Raw-Flags/south-korea.gif
new file mode 100644
index 00000000000..7e79e557a77
--- /dev/null
+++ b/Docs/Raw-Flags/south-korea.gif
Binary files differ
diff --git a/Docs/Raw-Flags/spain.gif b/Docs/Raw-Flags/spain.gif
new file mode 100644
index 00000000000..cbf0734548f
--- /dev/null
+++ b/Docs/Raw-Flags/spain.gif
Binary files differ
diff --git a/Docs/Raw-Flags/sri-lanka.gif b/Docs/Raw-Flags/sri-lanka.gif
new file mode 100644
index 00000000000..05926227dfd
--- /dev/null
+++ b/Docs/Raw-Flags/sri-lanka.gif
Binary files differ
diff --git a/Docs/Raw-Flags/sudan.gif b/Docs/Raw-Flags/sudan.gif
new file mode 100644
index 00000000000..666c5d7b951
--- /dev/null
+++ b/Docs/Raw-Flags/sudan.gif
Binary files differ
diff --git a/Docs/Raw-Flags/suriname.gif b/Docs/Raw-Flags/suriname.gif
new file mode 100644
index 00000000000..7b156242944
--- /dev/null
+++ b/Docs/Raw-Flags/suriname.gif
Binary files differ
diff --git a/Docs/Raw-Flags/swaziland.gif b/Docs/Raw-Flags/swaziland.gif
new file mode 100644
index 00000000000..78a0628f44f
--- /dev/null
+++ b/Docs/Raw-Flags/swaziland.gif
Binary files differ
diff --git a/Docs/Raw-Flags/sweden.gif b/Docs/Raw-Flags/sweden.gif
new file mode 100644
index 00000000000..e26546b7649
--- /dev/null
+++ b/Docs/Raw-Flags/sweden.gif
Binary files differ
diff --git a/Docs/Raw-Flags/sweden2.gif b/Docs/Raw-Flags/sweden2.gif
new file mode 100644
index 00000000000..999a2a68b88
--- /dev/null
+++ b/Docs/Raw-Flags/sweden2.gif
Binary files differ
diff --git a/Docs/Raw-Flags/switzerland.gif b/Docs/Raw-Flags/switzerland.gif
new file mode 100644
index 00000000000..4256c5a28d0
--- /dev/null
+++ b/Docs/Raw-Flags/switzerland.gif
Binary files differ
diff --git a/Docs/Raw-Flags/syria.gif b/Docs/Raw-Flags/syria.gif
new file mode 100644
index 00000000000..2dd2c0b9e8b
--- /dev/null
+++ b/Docs/Raw-Flags/syria.gif
Binary files differ
diff --git a/Docs/Raw-Flags/taiwan.gif b/Docs/Raw-Flags/taiwan.gif
new file mode 100644
index 00000000000..ab8f843d49c
--- /dev/null
+++ b/Docs/Raw-Flags/taiwan.gif
Binary files differ
diff --git a/Docs/Raw-Flags/tajikistan.gif b/Docs/Raw-Flags/tajikistan.gif
new file mode 100644
index 00000000000..e41305e5ade
--- /dev/null
+++ b/Docs/Raw-Flags/tajikistan.gif
Binary files differ
diff --git a/Docs/Raw-Flags/tanzania.gif b/Docs/Raw-Flags/tanzania.gif
new file mode 100644
index 00000000000..b5e266a059a
--- /dev/null
+++ b/Docs/Raw-Flags/tanzania.gif
Binary files differ
diff --git a/Docs/Raw-Flags/thailand.gif b/Docs/Raw-Flags/thailand.gif
new file mode 100644
index 00000000000..68dde61999b
--- /dev/null
+++ b/Docs/Raw-Flags/thailand.gif
Binary files differ
diff --git a/Docs/Raw-Flags/togo.gif b/Docs/Raw-Flags/togo.gif
new file mode 100644
index 00000000000..fec51e649c8
--- /dev/null
+++ b/Docs/Raw-Flags/togo.gif
Binary files differ
diff --git a/Docs/Raw-Flags/tonga.gif b/Docs/Raw-Flags/tonga.gif
new file mode 100644
index 00000000000..e684b7b4a95
--- /dev/null
+++ b/Docs/Raw-Flags/tonga.gif
Binary files differ
diff --git a/Docs/Raw-Flags/trinidad-and-tobago.gif b/Docs/Raw-Flags/trinidad-and-tobago.gif
new file mode 100644
index 00000000000..73f6a90b3f8
--- /dev/null
+++ b/Docs/Raw-Flags/trinidad-and-tobago.gif
Binary files differ
diff --git a/Docs/Raw-Flags/tunisia.gif b/Docs/Raw-Flags/tunisia.gif
new file mode 100644
index 00000000000..4e9872ec826
--- /dev/null
+++ b/Docs/Raw-Flags/tunisia.gif
Binary files differ
diff --git a/Docs/Raw-Flags/turkey.gif b/Docs/Raw-Flags/turkey.gif
new file mode 100644
index 00000000000..334fb57c703
--- /dev/null
+++ b/Docs/Raw-Flags/turkey.gif
Binary files differ
diff --git a/Docs/Raw-Flags/turkmenistan.gif b/Docs/Raw-Flags/turkmenistan.gif
new file mode 100644
index 00000000000..7b4af9ac158
--- /dev/null
+++ b/Docs/Raw-Flags/turkmenistan.gif
Binary files differ
diff --git a/Docs/Raw-Flags/tuvalu.gif b/Docs/Raw-Flags/tuvalu.gif
new file mode 100644
index 00000000000..0612803d157
--- /dev/null
+++ b/Docs/Raw-Flags/tuvalu.gif
Binary files differ
diff --git a/Docs/Raw-Flags/uganda.gif b/Docs/Raw-Flags/uganda.gif
new file mode 100644
index 00000000000..b2874526e53
--- /dev/null
+++ b/Docs/Raw-Flags/uganda.gif
Binary files differ
diff --git a/Docs/Raw-Flags/ukraine.gif b/Docs/Raw-Flags/ukraine.gif
new file mode 100644
index 00000000000..80abc1bb079
--- /dev/null
+++ b/Docs/Raw-Flags/ukraine.gif
Binary files differ
diff --git a/Docs/Raw-Flags/united-arab-emirates.gif b/Docs/Raw-Flags/united-arab-emirates.gif
new file mode 100644
index 00000000000..4d85bb0aeca
--- /dev/null
+++ b/Docs/Raw-Flags/united-arab-emirates.gif
Binary files differ
diff --git a/Docs/Raw-Flags/united-states-of-america.gif b/Docs/Raw-Flags/united-states-of-america.gif
new file mode 100644
index 00000000000..aaee9cef01f
--- /dev/null
+++ b/Docs/Raw-Flags/united-states-of-america.gif
Binary files differ
diff --git a/Docs/Raw-Flags/uruguay.gif b/Docs/Raw-Flags/uruguay.gif
new file mode 100644
index 00000000000..b772fcf47df
--- /dev/null
+++ b/Docs/Raw-Flags/uruguay.gif
Binary files differ
diff --git a/Docs/Raw-Flags/usa.gif b/Docs/Raw-Flags/usa.gif
new file mode 100644
index 00000000000..aaee9cef01f
--- /dev/null
+++ b/Docs/Raw-Flags/usa.gif
Binary files differ
diff --git a/Docs/Raw-Flags/uzbekistan.gif b/Docs/Raw-Flags/uzbekistan.gif
new file mode 100644
index 00000000000..27cfff2b4bb
--- /dev/null
+++ b/Docs/Raw-Flags/uzbekistan.gif
Binary files differ
diff --git a/Docs/Raw-Flags/vanuatu.gif b/Docs/Raw-Flags/vanuatu.gif
new file mode 100644
index 00000000000..936d22a1bee
--- /dev/null
+++ b/Docs/Raw-Flags/vanuatu.gif
Binary files differ
diff --git a/Docs/Raw-Flags/venezuela.gif b/Docs/Raw-Flags/venezuela.gif
new file mode 100644
index 00000000000..794f09cd856
--- /dev/null
+++ b/Docs/Raw-Flags/venezuela.gif
Binary files differ
diff --git a/Docs/Raw-Flags/vietnam.gif b/Docs/Raw-Flags/vietnam.gif
new file mode 100644
index 00000000000..0b9fc1add81
--- /dev/null
+++ b/Docs/Raw-Flags/vietnam.gif
Binary files differ
diff --git a/Docs/Raw-Flags/vincent-and-grenadines.gif b/Docs/Raw-Flags/vincent-and-grenadines.gif
new file mode 100644
index 00000000000..8a8689fbc39
--- /dev/null
+++ b/Docs/Raw-Flags/vincent-and-grenadines.gif
Binary files differ
diff --git a/Docs/Raw-Flags/yemen.gif b/Docs/Raw-Flags/yemen.gif
new file mode 100644
index 00000000000..f297f9fcef7
--- /dev/null
+++ b/Docs/Raw-Flags/yemen.gif
Binary files differ
diff --git a/Docs/Raw-Flags/yugoslavia.gif b/Docs/Raw-Flags/yugoslavia.gif
new file mode 100644
index 00000000000..ad7a1672692
--- /dev/null
+++ b/Docs/Raw-Flags/yugoslavia.gif
Binary files differ
diff --git a/Docs/Raw-Flags/zaire.gif b/Docs/Raw-Flags/zaire.gif
new file mode 100644
index 00000000000..489320d32a9
--- /dev/null
+++ b/Docs/Raw-Flags/zaire.gif
Binary files differ
diff --git a/Docs/Raw-Flags/zambia.gif b/Docs/Raw-Flags/zambia.gif
new file mode 100644
index 00000000000..7cb18f157e3
--- /dev/null
+++ b/Docs/Raw-Flags/zambia.gif
Binary files differ
diff --git a/Docs/Raw-Flags/zimbabwe.gif b/Docs/Raw-Flags/zimbabwe.gif
new file mode 100644
index 00000000000..49d042fb265
--- /dev/null
+++ b/Docs/Raw-Flags/zimbabwe.gif
Binary files differ
diff --git a/Docs/Support/.cvsignore b/Docs/Support/.cvsignore
new file mode 100644
index 00000000000..8772614a6b6
--- /dev/null
+++ b/Docs/Support/.cvsignore
@@ -0,0 +1,2 @@
+manual.html
+manual_toc.html
diff --git a/Docs/Support/generate-flag-images b/Docs/Support/generate-flag-images
new file mode 100755
index 00000000000..fa31fa7a4b8
--- /dev/null
+++ b/Docs/Support/generate-flag-images
@@ -0,0 +1,37 @@
+#!/bin/sh
+
+tmp=/tmp/temp-pic.pnm
+
+all="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=""
+
+set -x
+cd Img
+
+# for c in $all; do cp empty.png $c.pdf; done; exit
+
+for c in $new
+do
+ # For HTML version
+ giftopnm Raw-Flags/$c.gif | \
+ pnmscale -xsize 30 > $tmp
+ pnmpaste $tmp 1 1 flag-background.pnm > $c.pnm
+ rm -f $tmp
+ # For web 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 empty.png $c.pdf
+ # For TeX version
+ giftopnm /my/local/pictures/flags/$c.gif | \
+ pnmscale -xsize 30 | \
+ pnmtops -noturn > $c.eps
+ # For text version
+ echo -n "" > $c.txt
+done
diff --git a/Docs/Support/generate-mirror-listing.pl b/Docs/Support/generate-mirror-listing.pl
new file mode 100755
index 00000000000..1c6e579b330
--- /dev/null
+++ b/Docs/Support/generate-mirror-listing.pl
@@ -0,0 +1,27 @@
+#!/my/gnu/bin/perl -w -*- perl -*-
+
+# Generate a mirror listing
+
+line: while (<>) { last line if /START_OF_MIRROR_LISTING/;};
+
+print "MySQL mirror listing\n";
+
+line: while (<>)
+{
+ last line if /END_OF_MIRROR_LISTING/;
+ if (/^\@strong\{([A-Za-z ]+):\}$/)
+ {
+ print "\n*** $1\n";
+ }
+ elsif (m|^\@image\{Img/[a-z-]+\} ([A-Za-z]+) \[(.*)\]|)
+ {
+ print "\n$1 [$2]\n";
+ }
+ # A hacky URL regexp
+ # (m!^\@uref\{((http\|ftp)://[^,]*), (FTP\|WWW)\}!)
+ elsif (m!^\@uref\{((http|ftp)://[^,]*), (FTP|WWW)\}!)
+ {
+ $addr = $1;
+ print " $addr\n";
+ }
+}
diff --git a/Docs/Support/generate-text-files.pl b/Docs/Support/generate-text-files.pl
new file mode 100755
index 00000000000..570e579d926
--- /dev/null
+++ b/Docs/Support/generate-text-files.pl
@@ -0,0 +1,40 @@
+#!/my/gnu/bin/perl -w -*- perl -*-
+# Generate text files from top directory from the manual.
+
+$from = shift(@ARGV);
+$fnode = shift(@ARGV);
+$tnode = shift(@ARGV);
+
+open(IN, "$from") || die;
+
+$in = 0;
+
+while (<IN>)
+{
+ if ($in)
+ {
+ if (/Node: $tnode,/)
+ {
+ $in = 0;
+ }
+ elsif (/^File: mysql.info/ || (/^/))
+ {
+ # Just Skip node begginigs
+ }
+ else
+ {
+ print;
+ }
+ }
+ else
+ {
+ if (/Node: $fnode,/)
+ {
+ $in = 1;
+ # Skip first empty line
+ <IN>;
+ }
+ }
+}
+
+close(IN);
diff --git a/Docs/Support/make-makefile b/Docs/Support/make-makefile
new file mode 100755
index 00000000000..79cf06091fe
--- /dev/null
+++ b/Docs/Support/make-makefile
@@ -0,0 +1,7 @@
+#!/bin/sh
+# Use this when you have deleted Makefile and do not want to do a full
+# build to get it back
+
+cd ..
+automake --gnu Docs/Makefile
+CONFIG_FILES=Docs/Makefile CONFIG_HEADERS= sh ./config.status
diff --git a/Docs/Support/texi2html b/Docs/Support/texi2html
new file mode 100755
index 00000000000..fac665f3361
--- /dev/null
+++ b/Docs/Support/texi2html
@@ -0,0 +1,2251 @@
+#!PATH_TO_PERL -*- perl -*-
+# Add path to perl on the previous line and make this executable
+# if you want to use this as a normal script.
+'di ';
+'ig 00 ';
+#+##############################################################################
+# #
+# File: texi2html #
+# #
+# Description: Program to transform most Texinfo documents to HTML #
+# #
+#-##############################################################################
+
+# @(#)texi2html 1.52 971230 Written (mainly) by Lionel Cons, Lionel.Cons@cern.ch
+# Enhanced by David Axmark, david@detron.se
+
+# The man page for this program is included at the end of this file and can be
+# viewed using the command 'nroff -man texi2html'.
+# Please read the copyright at the end of the man page.
+
+#+++############################################################################
+# #
+# Constants #
+# #
+#---############################################################################
+
+$DEBUG_TOC = 1;
+$DEBUG_INDEX = 2;
+$DEBUG_BIB = 4;
+$DEBUG_GLOSS = 8;
+$DEBUG_DEF = 16;
+$DEBUG_HTML = 32;
+$DEBUG_USER = 64;
+
+$BIBRE = '\[[\w\/]+\]'; # RE for a bibliography reference
+$FILERE = '[\/\w.+-]+'; # RE for a file name
+$VARRE = '[^\s\{\}]+'; # RE for a variable name
+$NODERE = '[^@{}:\'`",]+'; # RE for a node name
+$NODESRE = '[^@{}:\'`"]+'; # RE for a list of node names
+$XREFRE = '[^@{}]+'; # RE for a xref (should use NODERE)
+
+$ERROR = "***"; # prefix for errors and warnings
+$THISPROG = "texi2html 1.52 (hacked by david\@detron.se)"; # program name and version
+$HOMEPAGE = "http://www.mathematik.uni-kl.de/~obachman/Texi2html/"; # program home page
+$TODAY = &pretty_date; # like "20 September 1993"
+$SPLITTAG = "<!-- SPLIT HERE -->\n"; # tag to know where to split
+$PROTECTTAG = "_ThisIsProtected_"; # tag to recognize protected sections
+$html2_doctype = '<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0 Strict Level 2//EN">';
+
+#
+# language dependent constants
+#
+#$LDC_SEE = 'see';
+#$LDC_SECTION = 'section';
+#$LDC_IN = 'in';
+#$LDC_TOC = 'Table of Contents';
+#$LDC_GOTO = 'Go to the';
+#$LDC_FOOT = 'Footnotes';
+# TODO: @def* shortcuts
+
+#$user_sub{"email"} = "fix_email";
+
+#
+# pre-defined indices
+#
+%predefined_index = (
+ 'cp', 'c',
+ 'fn', 'f',
+ 'vr', 'v',
+ 'ky', 'k',
+ 'pg', 'p',
+ 'tp', 't',
+ );
+
+#
+# valid indices
+#
+%valid_index = (
+ 'c', 1,
+ 'f', 1,
+ 'v', 1,
+ 'k', 1,
+ 'p', 1,
+ 't', 1,
+ );
+
+#
+# texinfo section names to level
+#
+%sec2level = (
+ 'top', 0,
+ 'chapter', 1,
+ 'unnumbered', 1,
+ 'majorheading', 1,
+ 'chapheading', 1,
+ 'appendix', 1,
+ 'section', 2,
+ 'unnumberedsec', 2,
+ 'heading', 2,
+ 'appendixsec', 2,
+ 'appendixsection', 2,
+ 'subsection', 3,
+ 'unnumberedsubsec', 3,
+ 'subheading', 3,
+ 'appendixsubsec', 3,
+ 'subsubsection', 4,
+ 'unnumberedsubsubsec', 4,
+ 'subsubheading', 4,
+ 'appendixsubsubsec', 4,
+ );
+
+#
+# accent map, TeX command to ISO name
+#
+%accent_map = (
+ '"', 'uml',
+ '~', 'tilde',
+ '^', 'circ',
+ '`', 'grave',
+ '\'', 'acute',
+ );
+
+#
+# texinfo "simple things" (@foo) to HTML ones
+#
+%simple_map = (
+ # cf. makeinfo.c
+ "*", "<BR>", # HTML+
+ " ", " ",
+ "\n", "\n",
+ "|", "",
+ # spacing commands
+ ":", "",
+ "!", "!",
+ "?", "?",
+ ".", ".",
+ );
+
+#
+# texinfo "things" (@foo{}) to HTML ones
+#
+%things_map = (
+ 'TeX', 'TeX',
+ 'br', '<P>', # paragraph break
+ 'bullet', '*',
+ 'copyright', '(C)',
+ 'dots', '...',
+ 'equiv', '==',
+ 'error', 'error-->',
+ 'expansion', '==>',
+ 'minus', '-',
+ 'point', '-!-',
+ 'print', '-|',
+ 'result', '=>',
+ 'today', $TODAY,
+ );
+
+#
+# texinfo styles (@foo{bar}) to HTML ones
+#
+%style_map = (
+ 'asis', '',
+ 'b', 'B',
+ 'cite', 'CITE',
+ 'code', 'CODE',
+ 'ctrl', '&do_ctrl', # special case
+ 'dfn', 'STRONG', # DFN tag is illegal in the standard
+ 'dmn', '', # useless
+ 'email', '&fix_email', # special
+ 'emph', 'EM',
+ 'file', '"TT', # will put quotes, cf. &apply_style
+ 'i', 'I',
+ 'kbd', 'KBD',
+ 'key', 'KBD',
+ 'r', '', # unsupported
+ 'samp', '"SAMP', # will put quotes, cf. &apply_style
+ 'sc', '&do_sc', # special case
+ 'strong', 'STRONG',
+ 't', 'TT',
+ 'titlefont', '', # useless
+ 'image', '&fix_image', # Image
+ 'url', '&fix_url', # URL
+ 'uref', '&fix_uref', # URL Reference
+ 'var', 'VAR',
+ 'w', '', # unsupported
+ );
+
+#
+# texinfo format (@foo/@end foo) to HTML ones
+#
+%format_map = (
+ 'display', 'PRE',
+ 'example', 'PRE',
+ 'format', 'PRE',
+ 'lisp', 'PRE',
+ 'quotation', 'BLOCKQUOTE',
+ 'smallexample', 'PRE',
+ 'smalllisp', 'PRE',
+ # lists
+ 'itemize', 'UL',
+ 'enumerate', 'OL',
+ # poorly supported
+ 'flushleft', 'PRE',
+ 'flushright', 'PRE',
+ );
+
+#
+# texinfo definition shortcuts to real ones
+#
+%def_map = (
+ # basic commands
+ 'deffn', 0,
+ 'defvr', 0,
+ 'deftypefn', 0,
+ 'deftypevr', 0,
+ 'defcv', 0,
+ 'defop', 0,
+ 'deftp', 0,
+ # basic x commands
+ 'deffnx', 0,
+ 'defvrx', 0,
+ 'deftypefnx', 0,
+ 'deftypevrx', 0,
+ 'defcvx', 0,
+ 'defopx', 0,
+ 'deftpx', 0,
+ # shortcuts
+ 'defun', 'deffn Function',
+ 'defmac', 'deffn Macro',
+ 'defspec', 'deffn {Special Form}',
+ 'defvar', 'defvr Variable',
+ 'defopt', 'defvr {User Option}',
+ 'deftypefun', 'deftypefn Function',
+ 'deftypevar', 'deftypevr Variable',
+ 'defivar', 'defcv {Instance Variable}',
+ 'defmethod', 'defop Method',
+ # x shortcuts
+ 'defunx', 'deffnx Function',
+ 'defmacx', 'deffnx Macro',
+ 'defspecx', 'deffnx {Special Form}',
+ 'defvarx', 'defvrx Variable',
+ 'defoptx', 'defvrx {User Option}',
+ 'deftypefunx', 'deftypefnx Function',
+ 'deftypevarx', 'deftypevrx Variable',
+ 'defivarx', 'defcvx {Instance Variable}',
+ 'defmethodx', 'defopx Method',
+ );
+
+#
+# things to skip
+#
+%to_skip = (
+ # comments
+ 'c', 1,
+ 'comment', 1,
+ # useless
+ 'contents', 1,
+ 'shortcontents', 1,
+ 'summarycontents', 1,
+ 'footnotestyle', 1,
+ 'end ifclear', 1,
+ 'end ifset', 1,
+ 'titlepage', 1,
+ 'end titlepage', 1,
+ # unsupported commands (formatting)
+ 'afourpaper', 1,
+ 'cropmarks', 1,
+ 'finalout', 1,
+ 'headings', 1,
+ 'need', 1,
+ 'page', 1,
+ 'setchapternewpage', 1,
+ 'everyheading', 1,
+ 'everyfooting', 1,
+ 'evenheading', 1,
+ 'evenfooting', 1,
+ 'oddheading', 1,
+ 'oddfooting', 1,
+ 'smallbook', 1,
+ 'vskip', 1,
+ 'filbreak', 1,
+ # unsupported formats
+ 'cartouche', 1,
+ 'end cartouche', 1,
+ 'group', 1,
+ 'end group', 1,
+ );
+
+#+++############################################################################
+# #
+# Argument parsing, initialisation #
+# #
+#---############################################################################
+
+%value = (); # hold texinfo variables
+
+$use_bibliography = 1;
+$use_acc = 0;
+$debug = 0;
+$doctype = '';
+$check = 0;
+$expandinfo = 0;
+$use_glossary = 0;
+$invisible_mark = '';
+$use_iso = 0;
+@include_dirs = ();
+$show_menu = 0;
+$number_sections = 0;
+$split_node = 0;
+$split_chapter = 0;
+$monolithic = 0;
+$verbose = 0;
+$opt_use_numbers = 0;
+$opt_empty_headers = 0;
+$opt_special_links = "";
+$usage = <<EOT;
+This is $THISPROG
+To convert a Texinfo file to HMTL: $0 [options] file
+where options can be:
+-expandinfo : use \@ifinfo sections, not \@iftex
+-glossary : handle a glossary
+-invisible name: use 'name' as an invisible anchor
+-I dir : search also for files in 'dir'
+-Dvar=value : define a variable, as with \@set
+-menu : handle menus
+-monolithic : output only one file including ToC
+-number : number sections
+-split_chapter : split on main sections
+-split_node : split on nodes
+-ref_num : use numeric names when spliting
+-empty_headers : no headers and implicit links (for inclusion into other documents)
+-usage : print usage instructions
+-verbose : verbose output
+To check converted files: $0 -check [-verbose] files
+EOT
+ #
+while ($#ARGV >= 0 && $ARGV[0] =~ /^-/)
+{
+ $_ = shift(@ARGV);
+ if (/^-acc$/) { $use_acc = 1; next; }
+ if (/^-d(ebug)?(\d+)?$/) { $debug = $2 || shift(@ARGV); next; }
+ if (/^-doctype$/) { $doctype = shift(@ARGV); next; }
+ if (/^-c(heck)?$/) { $check = 1; next; }
+ if (/^-e(xpandinfo)?$/) { $expandinfo = 1; next; }
+ if (/^-g(lossary)?$/) { $use_glossary = 1; next; }
+ if (/^-i(nvisible)?$/) { $invisible_mark = shift(@ARGV); next; }
+ if (/^-iso$/) { $use_iso = 1; next; }
+ if (/^-I(.+)?$/) { push(@include_dirs, $2 || shift(@ARGV)); next; }
+ if (/^-D([a-zA-Z0-9]+)=?(.+)?$/)
+ { $value{$1} = $2 ? $2 : 1; next; }
+ if (/^-m(enu)?$/) { $show_menu = 1; next; }
+ if (/^-mono(lithic)?$/) { $monolithic = 1; next; }
+ if (/^-n(umber)?$/) { $number_sections = 1; next; }
+ if (/^-ref_num$/) { $opt_use_numbers = 1; next; }
+ if (/^-empty_headers$/) { $opt_empty_headers = 1; next; }
+ if (/^-special_links$/) { $opt_special_links = $2 || shift(@ARGV); next; }
+ if (/^-s(plit)?_?(n(ode)?|c(hapter)?)?$/) {
+ if ($2 =~ /^n/) {
+ $split_node = 1;
+ } else {
+ $split_chapter = 1;
+ }
+ next;
+ }
+ if (/^-v(erbose)?$/) { $verbose = 1; next; }
+ die $usage;
+}
+if ($check) {
+ die $usage unless @ARGV > 0;
+ &check;
+ exit;
+}
+
+die "Can't use -special_links with -ref_num.\n"
+ if $opt_special_links && $opt_use_numbers;
+die "Must have -split_node with -special_links.\n"
+ if $opt_special_links && !$split_node;
+
+if (($split_node || $split_chapter) && $monolithic) {
+ warn "Can't use -monolithic with -split, -monolithic ignored.\n";
+ $monolithic = 0;
+}
+if ($expandinfo) {
+ $to_skip{'ifinfo'}++;
+ $to_skip{'end ifinfo'}++;
+} else {
+ $to_skip{'iftex'}++;
+ $to_skip{'end iftex'}++;
+}
+$invisible_mark = '<IMG SRC="invisible.xbm">' if $invisible_mark eq 'xbm';
+die $usage unless @ARGV == 1;
+$docu = shift(@ARGV);
+if ($docu =~ /.*\//) {
+ chop($docu_dir = $&);
+ $docu_name = $';
+} else {
+ $docu_dir = '.';
+ $docu_name = $docu;
+}
+unshift(@include_dirs, $docu_dir);
+$docu_name =~ s/\.te?x(i|info)?$//; # basename of the document
+
+$docu_doc = "$docu_name.html"; # document's contents
+$link_doc = $docu_doc;
+if ($monolithic) {
+ $docu_toc = $docu_foot = $docu_doc;
+} else {
+ $docu_toc = "${docu_name}_toc.html"; # document's table of contents
+ $docu_foot = "${docu_name}_foot.html"; # document's footnotes
+}
+
+#
+# variables
+#
+$value{'html'} = 1; # predefine html (the output format)
+$value{'texi2html'} = '1.52'; # predefine texi2html (the translator)
+# _foo: internal to track @foo
+foreach ('_author', '_title', '_subtitle',
+ '_settitle', '_setfilename') {
+ $value{$_} = ''; # prevent -w warnings
+}
+%node2sec = (); # node to section name
+%node2href = (); # node to HREF
+%bib2href = (); # bibliography reference to HREF
+%gloss2href = (); # glossary term to HREF
+@sections = (); # list of sections
+%tag2pro = (); # protected sections
+
+#
+# initial indexes
+#
+$bib_num = 0;
+$foot_num = 0;
+$gloss_num = 0;
+$idx_num = 0;
+$sec_num = 0;
+$doc_num = 0;
+$current_chapter_link = "";
+@maybe_wrong_links = ();
+$html_num = 0;
+
+#
+# can I use ISO8879 characters? (HTML+)
+#
+if ($use_iso) {
+ $things_map{'bullet'} = "&bull;";
+ $things_map{'copyright'} = "&copy;";
+ $things_map{'dots'} = "&hellip;";
+ $things_map{'equiv'} = "&equiv;";
+ $things_map{'expansion'} = "&rarr;";
+ $things_map{'point'} = "&lowast;";
+ $things_map{'result'} = "&rArr;";
+}
+
+#
+# read texi2html extensions (if any)
+#
+$extensions = 'texi2html.ext'; # extensions in working directory
+if (-f $extensions) {
+ print "# reading extensions from $extensions\n" if $verbose;
+ require($extensions);
+}
+($progdir = $0) =~ s/[^\/]+$//;
+if ($progdir && ($progdir ne './'))
+{
+ $extensions = "${progdir}texi2html.ext"; # extensions in texi2html directory
+ if (-f $extensions) {
+ print "# reading extensions from $extensions\n" if $verbose;
+ require($extensions);
+ }
+}
+
+ print "# reading from $docu\n" if $verbose;
+
+#+++############################################################################
+# #
+# Pass 1: read source, handle command, variable, simple substitution #
+# #
+#---############################################################################
+
+@lines = (); # whole document
+@toc_lines = (); # table of contents
+$toplevel = 0; # top level seen in hierarchy
+$curlevel = 0; # current level in TOC
+$node = ''; # current node name
+$in_table = 0; # am I inside a table
+$table_type = ''; # type of table ('', 'f', 'v')
+@tables = (); # nested table support
+$in_bibliography = 0; # am I inside a bibliography
+$in_glossary = 0; # am I inside a glossary
+$in_top = 0; # am I inside the top node
+$in_pre = 0; # am I inside a preformatted section
+$in_list = 0; # am I inside a list
+$in_html = 0; # am I inside an HTML section
+$first_line = 1; # is it the first line
+$dont_html = 0; # don't protect HTML on this line
+$split_num = 0; # split index
+$deferred_ref = ''; # deferred reference for indexes
+@html_stack = (); # HTML elements stack
+$html_element = ''; # current HTML element
+&html_reset;
+
+# build code for simple substitutions
+# the maps used (%simple_map and %things_map) MUST be aware of this
+# watch out for regexps, / and escaped characters!
+$subst_code = '';
+foreach (keys(%simple_map)) {
+ ($re = $_) =~ s/(\W)/\\$1/g; # protect regexp chars
+ $subst_code .= "s/\\\@$re/$simple_map{$_}/g;\n";
+}
+foreach (keys(%things_map)) {
+ $subst_code .= "s/\\\@$_\\{\\}/$things_map{$_}/g;\n";
+}
+if ($use_acc) {
+ # accentuated characters
+ foreach (keys(%accent_map)) {
+ if ($_ eq "`") {
+ $subst_code .= "s/$;3";
+ } elsif ($_ eq "'") {
+ $subst_code .= "s/$;4";
+ } else {
+ $subst_code .= "s/\\\@\\$_";
+ }
+ $subst_code .= "([aeiou])/&\${1}$accent_map{$_};/gi;\n";
+ }
+}
+eval("sub simple_substitutions { $subst_code }");
+
+&init_input;
+READ_LINE: while ($_ = &next_line)
+{
+ #
+ # remove \input on the first lines only
+ #
+ if ($first_line) {
+ next if /^\\input/;
+ $first_line = 0;
+ }
+ #
+ # parse texinfo tags
+ #
+ $tag = '';
+ $end_tag = '';
+ if (/^\s*\@end\s+(\w+)\b/) {
+ $end_tag = $1;
+ } elsif (/^\s*\@(\w+)\b/) {
+ $tag = $1;
+ }
+ #
+ # handle @ifhtml / @end ifhtml
+ #
+ if ($in_html) {
+ if ($end_tag eq 'ifhtml') {
+ $in_html = 0;
+ } else {
+ $tag2pro{$in_html} .= $_;
+ }
+ next;
+ } elsif ($tag eq 'ifhtml') {
+ $in_html = $PROTECTTAG . ++$html_num;
+ push(@lines, $in_html);
+ next;
+ }
+ #
+ # try to skip the line
+ #
+ if ($end_tag) {
+ next if $to_skip{"end $end_tag"};
+ } elsif ($tag) {
+ next if $to_skip{$tag};
+ last if $tag eq 'bye';
+ }
+ if ($in_top) {
+ # parsing the top node
+ if ($tag eq 'node' || $tag eq 'include' || $sec2level{$tag}) {
+ # no more in top
+ $in_top = 0;
+ } else {
+ # skip it
+ next;
+ }
+ }
+ #
+ # try to remove inlined comments
+ # syntax from tex-mode.el comment-start-skip
+ #
+ s/((^|[^\s*\@])(\@\@)*)\@c(omment)? .*/$1/;
+ # non-@ substitutions cf. texinfmt.el
+ # Since these changes break code examples in the source they were removed. David 990729
+ #s/``/\"/g;
+ #s/''/\"/g;
+ s/([\w ])---([\w ])/$1--$2/g;
+ #
+ # analyze the tag
+ #
+ if ($tag) {
+ # skip lines
+ &skip_until($tag), next if $tag eq 'ignore';
+ if ($expandinfo) {
+ &skip_until($tag), next if $tag eq 'iftex';
+ } else {
+ &skip_until($tag), next if $tag eq 'ifinfo';
+ }
+ &skip_until($tag), next if $tag eq 'tex';
+ # handle special tables
+ if ($tag eq 'table') {
+ $table_type = '';
+ } elsif ($tag eq 'ftable') {
+ $tag = 'table';
+ $table_type = 'f';
+ } elsif ($tag eq 'vtable') {
+ $tag = 'table';
+ $table_type = 'v';
+ }
+ # special cases
+ if ($tag eq 'top' || ($tag eq 'node' && /^\s*\@node\s+top\s*,/i)) {
+ $in_top = 1;
+ @lines = (); # ignore all lines before top (title page garbage)
+ next;
+ } elsif ($tag eq 'node') {
+ $in_top = 0;
+ warn "$ERROR Bad node line: $_" unless $_ =~ /^\s*\@node\s$NODESRE$/o;
+ $_ = &protect_html($_); # if node contains '&' for instance
+ s/^\s*\@node\s+//;
+ ($node) = split(/,/);
+ &normalise_node($node);
+ if ($split_node) {
+ ($doc_node_name[$doc_num + 1] = $node) =~ s|[ /]|_|g;
+ $doc_node_name_links[$doc_num + 1] = $current_chapter_link;
+ &next_doc;
+ push(@lines, $SPLITTAG) if $split_num++;
+ push(@sections, $node);
+ }
+ next;
+ } elsif ($tag eq 'include') {
+ if (/^\s*\@include\s+($FILERE)\s*$/o) {
+ $file = $1;
+ unless (-e $file) {
+ foreach $dir (@include_dirs) {
+ $file = "$dir/$1";
+ last if -e $file;
+ }
+ }
+ if (-e $file) {
+ &open($file);
+ print "# including $file\n" if $verbose;
+ } else {
+ warn "$ERROR Can't find $file, skipping";
+ }
+ } else {
+ warn "$ERROR Bad include line: $_";
+ }
+ next;
+ } elsif ($tag eq 'ifclear') {
+ if (/^\s*\@ifclear\s+($VARRE)\s*$/o) {
+ next unless defined($value{$1});
+ &skip_until($tag);
+ } else {
+ warn "$ERROR Bad ifclear line: $_";
+ }
+ next;
+ } elsif ($tag eq 'ifset') {
+ if (/^\s*\@ifset\s+($VARRE)\s*$/o) {
+ next if defined($value{$1});
+ &skip_until($tag);
+ } else {
+ warn "$ERROR Bad ifset line: $_";
+ }
+ next;
+ } elsif ($tag eq 'menu') {
+ unless ($show_menu) {
+ &skip_until($tag);
+ next;
+ }
+ &html_push_if($tag);
+ push(@lines, &html_debug("\n", __LINE__));
+ } elsif ($format_map{$tag}) {
+ $in_pre = 1 if $format_map{$tag} eq 'PRE';
+ &html_push_if($format_map{$tag});
+ push(@lines, &html_debug("\n", __LINE__));
+ $in_list++ if $format_map{$tag} eq 'UL' || $format_map{$tag} eq 'OL' ;
+ push(@lines, &debug("<$format_map{$tag}>\n", __LINE__));
+ next;
+ } elsif ($tag eq 'table') {
+ if (/^\s*\@[fv]?table\s+\@(\w+)\s*$/) {
+ $in_table = $1;
+ unshift(@tables, join($;, $table_type, $in_table));
+ push(@lines, &debug("<DL COMPACT>\n", __LINE__));
+ &html_push_if('DL');
+ push(@lines, &html_debug("\n", __LINE__));
+ } else {
+ warn "$ERROR Bad table line: $_";
+ }
+ next;
+ } elsif ($tag eq 'multitable') {
+ if (/^\s*\@multitable\s*\@columnfractions\s+([\.\d\s]+)\s*$/ ||
+ /^\s*\@multitable\s*({[^{}]+})+\s*$/)
+ {
+ $in_multitable = 1;
+ html_push('TABLE');
+ my($col_list) = $1;
+ $multitable_cols = ($col_list =~ /\@columnfractions/ ? s/[\d.]+\s+//g :
+ s/{[^{}]+}//g);
+ print "# Multitable with $multitable_cols columns\n"
+ if $debug and $DEBUG_USER;
+ push(@lines, &debug("<TABLE BORDER WIDTH=\"100%\">\n", __LINE__));
+ } else {
+ warn "$ERROR Bad table line: $_";
+ }
+ next;
+ } elsif ($tag eq 'synindex' || $tag eq 'syncodeindex') {
+ if (/^\s*\@$tag\s+(\w)\w\s+(\w)\w\s*$/) {
+ eval("*${1}index = *${2}index");
+ } else {
+ warn "$ERROR Bad syn*index line: $_";
+ }
+ next;
+ } elsif ($tag eq 'sp') {
+ push(@lines, &debug("<P>\n", __LINE__));
+ next;
+ } elsif ($tag eq 'setref') {
+ &protect_html; # if setref contains '&' for instance
+ if (/^\s*\@$tag\s*{($NODERE)}\s*$/) {
+ $setref = $1;
+ $setref =~ s/\s+/ /g; # normalize
+ $setref =~ s/ $//;
+ $node2sec{$setref} = $name;
+ $node2href{$setref} = "$link_doc#$docid";
+ push(@maybe_wrong_links, $setref);
+ } else {
+ warn "$ERROR Bad setref line: $_";
+ }
+ next;
+ } elsif ($tag eq 'defindex' || $tag eq 'defcodeindex') {
+ if (/^\s*\@$tag\s+(\w\w)\s*$/) {
+ $valid_index{$1} = 1;
+ } else {
+ warn "$ERROR Bad defindex line: $_";
+ }
+ next;
+ } elsif (defined($def_map{$tag})) {
+ if ($def_map{$tag}) {
+ s/^\s*\@$tag\s+//;
+ $tag = $def_map{$tag};
+ $_ = "\@$tag $_";
+ $tag =~ s/\s.*//;
+ }
+ } elsif (defined($user_sub{$tag})) {
+ s/^\s*\@$tag\s+//;
+ $sub = $user_sub{$tag};
+ print "# user $tag = $sub, arg: $_" if $debug & $DEBUG_USER;
+ if (defined(&$sub)) {
+ chop($_);
+ &$sub($_);
+ } else {
+ warn "$ERROR Bad user sub for $tag: $sub\n";
+ }
+ next;
+ }
+ if (defined($def_map{$tag})) {
+ s/^\s*\@$tag\s+//;
+ if ($tag =~ /x$/) {
+ # extra definition line
+ $tag = $`;
+ $is_extra = 1;
+ } else {
+ $is_extra = 0;
+ }
+ while (/\{([^\{\}]*)\}/) {
+ # this is a {} construct
+ ($before, $contents, $after) = ($`, $1, $');
+ # protect spaces
+ $contents =~ s/\s+/$;9/g;
+ # restore $_ protecting {}
+ $_ = "$before$;7$contents$;8$after";
+ }
+ @args = split(/\s+/, &protect_html($_));
+ foreach (@args) {
+ s/$;9/ /g; # unprotect spaces
+ s/$;7/\{/g; # ... {
+ s/$;8/\}/g; # ... }
+ }
+ $type = shift(@args);
+ $type =~ s/^\{(.*)\}$/$1/;
+ print "# def ($tag): {$type} ", join(', ', @args), "\n"
+ if $debug & $DEBUG_DEF;
+ $type .= ':'; # it's nicer like this
+ $name = shift(@args);
+ $name =~ s/^\{(.*)\}$/$1/;
+ if ($is_extra) {
+ $_ = &debug("<DT>", __LINE__);
+ } else {
+ $_ = &debug("<DL>\n<DT>", __LINE__);
+ }
+ if ($tag eq 'deffn' || $tag eq 'defvr' || $tag eq 'deftp') {
+ $_ .= "<U>$type</U> <B>$name</B>";
+ $_ .= " <I>@args</I>" if @args;
+ } elsif ($tag eq 'deftypefn' || $tag eq 'deftypevr'
+ || $tag eq 'defcv' || $tag eq 'defop') {
+ $ftype = $name;
+ $name = shift(@args);
+ $name =~ s/^\{(.*)\}$/$1/;
+ $_ .= "<U>$type</U> $ftype <B>$name</B>";
+ $_ .= " <I>@args</I>" if @args;
+ } else {
+ warn "$ERROR Unknown definition type: $tag\n";
+ $_ .= "<U>$type</U> <B>$name</B>";
+ $_ .= " <I>@args</I>" if @args;
+ }
+ $_ .= &debug("\n<DD>", __LINE__);
+ $name = &unprotect_html($name);
+ if ($tag eq 'deffn' || $tag eq 'deftypefn') {
+ unshift(@input_spool, "\@findex $name\n");
+ } elsif ($tag eq 'defop') {
+ unshift(@input_spool, "\@findex $name on $ftype\n");
+ } elsif ($tag eq 'defvr' || $tag eq 'deftypevr' || $tag eq 'defcv') {
+ unshift(@input_spool, "\@vindex $name\n");
+ } else {
+ unshift(@input_spool, "\@tindex $name\n");
+ }
+ $dont_html = 1;
+ }
+ } elsif ($end_tag) {
+ if ($format_map{$end_tag}) {
+ $in_pre = 0 if $format_map{$end_tag} eq 'PRE';
+ $in_list-- if $format_map{$end_tag} eq 'UL' || $format_map{$end_tag} eq 'OL' ;
+ &html_pop_if('LI', 'P');
+ &html_pop_if();
+ push(@lines, &debug("</$format_map{$end_tag}>\n", __LINE__));
+ push(@lines, &html_debug("\n", __LINE__));
+ } elsif ($end_tag eq 'table' ||
+ $end_tag eq 'ftable' ||
+ $end_tag eq 'vtable') {
+ shift(@tables);
+ if (@tables) {
+ ($table_type, $in_table) = split($;, $tables[0]);
+ } else {
+ $in_table = 0;
+ $table_type = '';
+ }
+ push(@lines, "</DL>\n");
+ &html_pop_if('DD');
+ &html_pop_if();
+ } elsif ($end_tag eq 'multitable') {
+ print "# end of multitable with $multitable_cols columns\n"
+ if $debug and $DEBUG_USER;
+ $in_multitable = 0;
+ push(@lines, "</TR>\n");
+ &html_pop_if('TR');
+ push(@lines, "</TABLE>\n");
+&html_pop_if('TABLE');
+ } elsif (defined($def_map{$end_tag})) {
+ push(@lines, &debug("</DL>\n", __LINE__));
+ } elsif ($end_tag eq 'menu') {
+ &html_pop_if();
+ push(@lines, $_); # must keep it for pass 2
+ }
+ next;
+ }
+ #
+ # misc things
+ #
+ # protect texi and HTML things
+ &protect_texi;
+ $_ = &protect_html($_) unless $dont_html;
+ $dont_html = 0;
+ # substitution (unsupported things)
+ s/^\s*\@center\s+//g;
+ s/^\s*\@exdent\s+//g;
+ s/\@noindent\s+//g;
+ s/\@refill\s+//g;
+ # other substitutions
+ &simple_substitutions;
+ s/\@value{($VARRE)}/$value{$1}/eg;
+ s/\@footnote\{/\@footnote$docu_doc\{/g; # mark footnotes, cf. pass 4
+ s|\s+\@tab\s*| </TD><TD> |g if ($in_multitable);
+
+ #
+ # analyze the tag again
+ #
+ if ($tag) {
+ if (defined($sec2level{$tag}) && $sec2level{$tag} > 0) {
+ if (/^\s*\@$tag\s+(.+)$/) {
+ $name = $1;
+ $name =~ s/\s+$//;
+ $level = $sec2level{$tag};
+ $name = &update_sec_num($tag, $level) . " $name"
+ if $number_sections && $tag !~ /^unnumbered/;
+ if ($tag =~ /heading$/) {
+ push(@lines, &html_debug("\n", __LINE__));
+ if ($html_element ne 'body') {
+ # We are in a nice pickle here. We are trying to get a H? heading
+ # even though we are not in the body level. So, we convert
+ # it to a nice, bold, line by itself.
+ $_ = &debug("\n\n<P><STRONG>$name</STRONG></P>\n\n", __LINE__);
+ } else {
+ $_ = &debug("<H$level>$name</H$level>\n", __LINE__);
+ &html_push_if('body');
+ }
+ print "# heading, section $name, level $level\n"
+ if $debug & $DEBUG_TOC;
+ } else {
+ if ($split_chapter) {
+ unless ($toplevel) {
+ # first time we see a "section"
+ unless ($level == 1) {
+ warn "$ERROR The first section found is not of level 1: $_";
+ warn "$ERROR I'll split on sections of level $level...\n";
+ }
+ $toplevel = $level;
+ };
+ if ($level == $toplevel) {
+ print "# Splitting at section $name\n"
+ if $debug & $DEBUG_TOC;
+ ($doc_node_name[$doc_num + 1] = $node) =~ s|[ /]|_|g;
+ &next_doc;
+ push(@lines, $SPLITTAG) if $split_num++;
+ push(@sections, $name);
+ }
+ } elsif ($split_node && $opt_special_links) {
+ $toplevel = $level unless $toplevel;
+ if ($level == $toplevel) {
+ ($current_chapter_link = $node) =~ s|[ /]|_|g;
+ # Set this again to the right value.
+ $doc_node_name_links[$doc_num] = $current_chapter_link;
+ ($docu_doc, $link_doc) = &doc_name($doc_num);
+ }
+ }
+ $sec_num++;
+ # Was "SEC$sec_num"
+ ($docid = "$node") =~ s|[ /]|_|g;
+ ($tocid = "$node") =~ s|[ /]|_|g;
+$docid = "SEC$sec_num" unless $docid;
+$tocid = "SEC$sec_num" unless $tocid;
+ # check biblio and glossary
+ $in_bibliography =
+ ($name =~ /^([A-Z]|\d+)?(\.\d+)*\s*bibliography$/i);
+ $in_glossary = ($name =~ /^([A-Z]|\d+)?(\.\d+)*\s*glossary$/i);
+ # check node
+ if ($node) {
+ if ($node2sec{$node}) {
+ warn "$ERROR Duplicate node found: $node\n";
+ } else {
+ $node2sec{$node} = $name;
+ $node2href{$node} = "$link_doc#$docid";
+ push(@maybe_wrong_links, $node);
+ print "# node $node, section $name, level $level\n"
+ if $debug & $DEBUG_TOC;
+ }
+ $node = '';
+ } else {
+ print "# no node, section $name, level $level\n"
+ if $debug & $DEBUG_TOC;
+ }
+ # update TOC
+ while ($level > $curlevel) {
+ $curlevel++;
+ push(@toc_lines, "<UL>\n");
+ }
+ while ($level < $curlevel) {
+ $curlevel--;
+ push(@toc_lines, "</UL>\n");
+ }
+ $_ = "<LI>" . &anchor($tocid, "$link_doc#$docid", $name, 1);
+ push(@toc_lines, &substitute_style($_));
+ # update DOC
+ push(@lines, &html_debug("\n", __LINE__));
+ &html_reset;
+ $_ = "<H$level>".&anchor($docid, $opt_empty_headers ? "" : "$docu_toc#$tocid",
+ $name)."</H$level>\n";
+ $_ = &debug($_, __LINE__);
+ push(@lines, &html_debug("\n", __LINE__));
+ }
+ # update DOC
+ foreach $line (split(/\n+/, $_)) {
+ push(@lines, "$line\n");
+ }
+ next;
+ } else {
+ warn "$ERROR Bad section line: $_";
+ }
+ } else {
+ # track variables
+ $value{$1} = $2, next if /^\s*\@set\s+($VARRE)\s+(.*)$/o;
+ delete $value{$1}, next if /^\s*\@clear\s+($VARRE)\s*$/o;
+ # store things
+ $value{'_setfilename'} = $1, next if /^\s*\@setfilename\s+(.*)$/;
+ $value{'_settitle'} = $1, next if /^\s*\@settitle\s+(.*)$/;
+ $value{'_author'} .= "$1\n", next if /^\s*\@author\s+(.*)$/;
+ $value{'_subtitle'} .= "$1\n", next if /^\s*\@subtitle\s+(.*)$/;
+ $value{'_title'} .= "$1\n", next if /^\s*\@title\s+(.*)$/;
+ # index
+ if (/^\s*\@(..?)index\s+/) {
+ unless ($valid_index{$1}) {
+ warn "$ERROR Undefined index command: $_";
+ next;
+ }
+ $id = 'IDX' . ++$idx_num;
+ $index = $1 . 'index';
+ $what = &substitute_style($');
+ $what =~ s/\s+$//;
+ print "# found $index for '$what' id $id\n"
+ if $debug & $DEBUG_INDEX;
+ eval(<<EOC);
+ if (defined(\$$index\{\$what\})) {
+ \$$index\{\$what\} .= "$;$link_doc#$id";
+ } else {
+ \$$index\{\$what\} = "$link_doc#$id";
+ }
+EOC
+ #
+ # dirty hack to see if I can put an invisible anchor...
+ #
+ if ($html_element eq 'P' ||
+ $html_element eq 'LI' ||
+ $html_element eq 'DT' ||
+ $html_element eq 'DD' ||
+ $html_element eq 'ADDRESS' ||
+ $html_element eq 'B' ||
+ $html_element eq 'BLOCKQUOTE' ||
+ $html_element eq 'PRE' ||
+ $html_element eq 'SAMP') {
+ push(@lines, &anchor($id, '', $invisible_mark, !$in_pre));
+ } elsif ($html_element eq 'body') {
+ push(@lines, &debug("<P>\n", __LINE__));
+ push(@lines, &anchor($id, '', $invisible_mark, !$in_pre));
+ &html_push('P');
+ } elsif ($html_element eq 'DL' ||
+ $html_element eq 'UL' ||
+ $html_element eq 'OL' ||
+ $html_element eq 'TR') {
+ $deferred_ref .=
+ &anchor($id, '', $invisible_mark, !$in_pre) . " ";
+ }
+ next;
+ }
+ # list item
+ if (/^\s*\@itemx?\s+/)
+ {
+ $what = $';
+ $what =~ s/\s+$//;
+
+ # add an index before the item if applicable
+ if ($table_type ne '' && !$in_multitable) {
+ print "# Adding table index (type $table_type) for $what\n"
+ if $debug & $DEBUG_INDEX;
+ # This is realy ugly. We should do a pass before this to
+ # add index entrys before instead.
+ if ($global_added_this_index) {
+ $global_added_this_index = 0;
+ } else {
+ unshift(@input_spool, "\@${table_type}index $what\n", $_);
+ $global_added_this_index = 1;
+ next READ_LINE;
+ }
+ }
+
+ if ($in_bibliography && $use_bibliography) {
+ if ($what =~ /^$BIBRE$/o) {
+ $id = 'BIB' . ++$bib_num;
+ $bib2href{$what} = "$link_doc#$id";
+ print "# found bibliography for '$what' id $id\n"
+ if $debug & $DEBUG_BIB;
+ $what = &anchor($id, '', $what);
+ }
+ } elsif ($in_glossary && $use_glossary) {
+ $id = 'GLOSS' . ++$gloss_num;
+ $entry = $what;
+ $entry =~ tr/A-Z/a-z/ unless $entry =~ /^[A-Z\s]+$/;
+ $gloss2href{$entry} = "$link_doc#$id";
+ print "# found glossary for '$entry' id $id\n"
+ if $debug & $DEBUG_GLOSS;
+ $what = &anchor($id, '', $what);
+ }
+ if ($in_multitable)
+ {
+ # All this is a **HACK**.
+ # It does only work for a FEW SIMPLE CASES !!!
+ push(@lines, &debug("</TR>\n", __LINE__))
+ unless $html_element eq 'TABLE';;
+&html_pop_if('TR');
+ $what =~ s|\s+\@tab\s*| </TD><TD> |g;
+ push(@lines, &debug("<TR><TD>$what\n", __LINE__));
+ &html_push('TR');
+ if ($deferred_ref)
+ {
+ push(@lines, &debug("$deferred_ref\n", __LINE__));
+ $deferred_ref = '';
+ }
+ next;
+ }
+ else
+ {
+ &html_pop_if('P');
+ if ($html_element eq 'DL' || $html_element eq 'DD') {
+ if ($things_map{$in_table} && !$what) {
+ # special case to allow @table @bullet for instance
+ push(@lines, &debug("<DT>$things_map{$in_table}\n", __LINE__));
+ } else {
+ push(@lines, &debug("<DT>\@$in_table\{$what\}\n", __LINE__));
+ }
+ push(@lines, "<DD>");
+ &html_push('DD') unless $html_element eq 'DD';
+ # Old index add was here
+ } else {
+ push(@lines, &debug("<LI>$what\n", __LINE__));
+ &html_push('LI') unless $html_element eq 'LI';
+ }
+ push(@lines, &html_debug("\n", __LINE__));
+ if ($deferred_ref) {
+ push(@lines, &debug("$deferred_ref\n", __LINE__));
+ $deferred_ref = '';
+ }
+ next;
+ }
+ }
+ }
+ }
+ # paragraph separator
+ if ($_ eq "\n") {
+ next if $#lines >= 0 && $lines[$#lines] eq "\n";
+ if ($html_element eq 'P') {
+ push(@lines, "\n");
+ $_ = &debug("</P>\n", __LINE__);
+ &html_pop;
+ }
+ } elsif ($html_element eq 'body' || $html_element eq 'BLOCKQUOTE') {
+ push(@lines, "<P>\n");
+ &html_push('P');
+ $_ = &debug($_, __LINE__);
+ }
+ # otherwise
+ push(@lines, $_);
+}
+
+# finish TOC
+$level = 0;
+while ($level < $curlevel)
+{
+ $curlevel--;
+ push(@toc_lines, "</UL>\n");
+}
+
+print "# end of pass 1\n" if $verbose;
+
+#+++############################################################################
+# #
+# Pass 2/3: handle style, menu, index, cross-reference #
+# #
+#---############################################################################
+
+@lines2 = (); # whole document (2nd pass)
+@lines3 = (); # whole document (3rd pass)
+$in_menu = 0; # am I inside a menu
+
+while (@lines)
+{
+ $_ = shift(@lines);
+ #
+ # special case (protected sections)
+ #
+ if (/^$PROTECTTAG/o) {
+ push(@lines2, $_);
+ next;
+ }
+ #
+ # menu
+ #
+ $in_menu = 1, push(@lines2, &debug("<UL>\n", __LINE__)), next if /^\s*\@menu\b/;
+ $in_menu = 0, push(@lines2, &debug("</UL>\n", __LINE__)), next if /^\s*\@end\s+menu\b/;
+ if ($in_menu) {
+ if (/^\*\s+($NODERE)::/o) {
+ $descr = $';
+ chop($descr);
+ &menu_entry($1, $1, $descr);
+ } elsif (/^\*\s+(.+):\s+([^\t,\.\n]+)[\t,\.\n]/) {
+ $descr = $';
+ chop($descr);
+ &menu_entry($1, $2, $descr);
+ } elsif (/^\*/) {
+ warn "$ERROR Bad menu line: $_";
+ } else { # description continued?
+ push(@lines2, $_);
+ }
+ next;
+ }
+ #
+ # printindex
+ #
+ if (/^\s*\@printindex\s+(\w\w)\b/) {
+ local($index, *ary, @keys, $key, $letter, $last_letter, @refs);
+ if ($predefined_index{$1}) {
+ $index = $predefined_index{$1} . 'index';
+ } else {
+ $index = $1 . 'index';
+ }
+ eval("*ary = *$index");
+ @keys = keys(%ary);
+ foreach $key (@keys) {
+ $_ = $key;
+ 1 while s/<(\w+)>\`(.*)\'<\/\1>/$2/; # remove HTML tags with quotes
+ 1 while s/<(\w+)>(.*)<\/\1>/$2/; # remove HTML tags
+ $_ = &unprotect_html($_);
+ &unprotect_texi;
+ tr/A-Z/a-z/; # lowercase
+ $key2alpha{$key} = $_;
+ print "# index $key sorted as $_\n"
+ if $key ne $_ && $debug & $DEBUG_INDEX;
+ }
+ $last_letter = undef;
+ foreach $key (sort byalpha @keys) {
+ $letter = substr($key2alpha{$key}, 0, 1);
+ $letter = substr($key2alpha{$key}, 0, 2) if $letter eq $;;
+ $letter = " " unless $letter =~ /[a-zA-Z]/;
+ if (!defined($last_letter) || $letter ne $last_letter) {
+ push(@lines2, "</DIR>\n") if defined($last_letter);
+ push(@lines2, "<H2>" . &protect_html(uc($letter)) . "</H2>\n");
+ push(@lines2, "<DIR>\n");
+ $last_letter = $letter;
+ }
+ @refs = ();
+ foreach (split(/$;/, $ary{$key})) {
+ push(@refs, &anchor('', $_, $key, 0));
+ }
+ push(@lines2, "<LI>" . join(", ", @refs) . "\n");
+ }
+ push(@lines2, "</DIR>\n") if defined($last_letter);
+ next;
+ }
+ #
+ # simple style substitutions
+ #
+ $_ = &substitute_style($_);
+ #
+ # xref
+ #
+ while (/\@(x|px|info|)ref{($XREFRE)(}?)/o) {
+ # note: Texinfo may accept other characters
+ ($type, $nodes, $full) = ($1, $2, $3);
+ ($before, $after) = ($`, $');
+ if (! $full && $after) {
+ warn "$ERROR Bad xref (no ending } on line): $_";
+ $_ = "$before$;0${type}ref\{$nodes$after";
+ next; # while xref
+ }
+ if ($type eq 'x') {
+ $type = 'See ';
+ } elsif ($type eq 'px') {
+ $type = 'see ';
+ } elsif ($type eq 'info') {
+ $type = 'See Info';
+ } elsif ($type eq 'u') {
+ $type = 'See ';
+ } else {
+ $type = '';
+ }
+ unless ($full) {
+ $next = shift(@lines);
+ $next = &substitute_style($next);
+ chop($nodes); # remove final newline
+ if ($next =~ /\}/) { # split on 2 lines
+ $nodes .= " $`";
+ $after = $';
+ } else {
+ $nodes .= " $next";
+ $next = shift(@lines);
+ $next = &substitute_style($next);
+ chop($nodes);
+ if ($next =~ /\}/) { # split on 3 lines
+ $nodes .= " $`";
+ $after = $';
+ } else {
+ warn "$ERROR Bad xref (no ending }): $_";
+ $_ = "$before$;0xref\{$nodes$after";
+ unshift(@lines, $next);
+ next; # while xref
+ }
+ }
+ }
+ $nodes =~ s/\s+/ /g; # remove useless spaces
+ @args = split(/\s*,\s*/, $nodes);
+ $node = $args[0]; # the node is always the first arg
+ &normalise_node($node);
+ $sec = $node2sec{$node};
+ if (@args == 5) { # reference to another manual
+ $sec = $args[2] || $node;
+ $man = $args[4] || $args[3];
+ $_ = "${before}${type}section `$sec' in \@cite{$man}$after";
+ } elsif ($type =~ /Info/) { # inforef
+ warn "$ERROR Wrong number of arguments: $_" unless @args == 3;
+ ($nn, $_, $in) = @args;
+ $_ = "${before}${type} file `$in', node `$nn'$after";
+ } elsif ($sec) {
+ $href = $node2href{$node};
+ $_ = "${before}${type}section " . &anchor('', $href, $sec) . $after;
+ } else {
+ warn "$ERROR Undefined node ($node): $_";
+ $_ = "$before$;0xref{$nodes}$after";
+ }
+ }
+ #
+ # try to guess bibliography references or glossary terms
+ #
+ # This checked for NAME="SEC\d". The current version is probably broken.
+ unless (/^<H\d><A NAME=\"/) {
+ if ($use_bibliography) {
+ $done = '';
+ while (/$BIBRE/o) {
+ ($pre, $what, $post) = ($`, $&, $');
+ $href = $bib2href{$what};
+ if (defined($href) && $post !~ /^[^<]*<\/A>/) {
+ $done .= $pre . &anchor('', $href, $what);
+ } else {
+ $done .= "$pre$what";
+ }
+ $_ = $post;
+ }
+ $_ = $done . $_;
+ }
+ if ($use_glossary) {
+ $done = '';
+ while (/\b\w+\b/) {
+ ($pre, $what, $post) = ($`, $&, $');
+ $entry = $what;
+ $entry =~ tr/A-Z/a-z/ unless $entry =~ /^[A-Z\s]+$/;
+ $href = $gloss2href{$entry};
+ if (defined($href) && $post !~ /^[^<]*<\/A>/) {
+ $done .= $pre . &anchor('', $href, $what);
+ } else {
+ $done .= "$pre$what";
+ }
+ $_ = $post;
+ }
+ $_ = $done . $_;
+ }
+ }
+ # otherwise
+ push(@lines2, $_);
+}
+print "# end of pass 2\n" if $verbose;
+
+#
+# split style substitutions
+#
+while (@lines2)
+{
+ $_ = shift(@lines2);
+ #
+ # special case (protected sections)
+ #
+ if (/^$PROTECTTAG/o) {
+ push(@lines3, $_);
+ next;
+ }
+ #
+ # split style substitutions
+ #
+ $old = '';
+ while ($old ne $_) {
+ $old = $_;
+ if (/\@(\w+)\{/) {
+ ($before, $style, $after) = ($`, $1, $');
+ if (defined($style_map{$style})) {
+ $_ = $after;
+ $text = '';
+ $after = '';
+ $failed = 1;
+ while (@lines2) {
+ if (/\}/) {
+ $text .= $`;
+ $after = $';
+ $failed = 0;
+ last;
+ } else {
+ $text .= $_;
+ $_ = shift(@lines2);
+ }
+ }
+ if ($failed) {
+ die "* Bad syntax (\@$style) after: $before\n";
+ } else {
+ $text = &apply_style($style, $text);
+ $_ = "$before$text$after";
+ }
+ }
+ }
+ }
+ # otherwise
+ push(@lines3, $_);
+}
+print "# end of pass 3\n" if $verbose;
+
+#+++############################################################################
+# #
+# Pass 4: foot notes, final cleanup #
+# #
+#---############################################################################
+
+@foot_lines = (); # footnotes
+@doc_lines = (); # final document
+$end_of_para = 0; # true if last line is <P>
+
+while (@lines3)
+{
+ $_ = shift(@lines3);
+ #
+ # special case (protected sections)
+ #
+ if (/^$PROTECTTAG/o) {
+ push(@doc_lines, $_);
+ $end_of_para = 0;
+ next;
+ }
+ #
+ # footnotes
+ #
+ while (/\@footnote([^\{\s]+)\{/) {
+ ($before, $d, $after) = ($`, $1, $');
+ $_ = $after;
+ $text = '';
+ $after = '';
+ $failed = 1;
+ while (@lines3) {
+ if (/\}/) {
+ $text .= $`;
+ $after = $';
+ $failed = 0;
+ last;
+ } else {
+ $text .= $_;
+ $_ = shift(@lines3);
+ }
+ }
+ if ($failed) {
+ die "* Bad syntax (\@footnote) after: $before\n";
+ } else {
+ $foot_num++;
+ $docid = "DOCF$foot_num";
+ $footid = "FOOT$foot_num";
+ $foot = "($foot_num)";
+ push(@foot_lines, "<H3>" . &anchor($footid, "$d#$docid", $foot) . "</H3>\n");
+ $text = "<P>$text" unless $text =~ /^\s*<P>/;
+ push(@foot_lines, "$text\n");
+ $_ = $before . &anchor($docid, "$docu_foot#$footid", $foot) . $after;
+ }
+ }
+ #
+ # remove unnecessary <P>
+ #
+ if (/^\s*<P>\s*$/) {
+ next if $end_of_para++;
+ } else {
+ $end_of_para = 0;
+ }
+ # otherwise
+ push(@doc_lines, $_);
+}
+print "# end of pass 4\n" if $verbose;
+
+#+++############################################################################
+# #
+# Pass 5: print things #
+# #
+#---############################################################################
+
+$header = <<EOT;
+<!-- This HTML file has been created by $THISPROG
+ from $docu on $TODAY -->
+EOT
+
+ $full_title = $value{'_title'} || $value{'_settitle'} || "Untitled Document";
+ $title = $value{'_settitle'} || $full_title;
+ $_ = &substitute_style($full_title);
+ &unprotect_texi;
+ s/\n$//; # rmv last \n (if any)
+ $full_title = "<H1>" . join("</H1>\n<H1>", split(/\n/, $_)) . "</H1>\n";
+
+#
+# print ToC
+#
+if (!$monolithic && @toc_lines)
+{
+ if (open(FILE, "> $docu_toc")) {
+ print "# creating $docu_toc...\n" if $verbose;
+ &print_toplevel_header("$title - Table of Contents");
+ &print_ruler;
+ &print(*toc_lines, FILE);
+ &print_toplevel_footer;
+ close(FILE);
+ } else {
+ warn "$ERROR Can't write (toc) to $docu_toc: $!\n";
+ }
+}
+
+#
+# print footnotes
+#
+if (!$monolithic && @foot_lines)
+{
+ if (open(FILE, "> $docu_foot")) {
+ print "# creating $docu_foot...\n" if $verbose;
+ &print_toplevel_header("$title - Footnotes");
+ &print_ruler;
+ &print(*foot_lines, FILE);
+ &print_toplevel_footer;
+ close(FILE);
+ } else {
+ warn "$ERROR Can't write (foot) to $docu_foot: $!\n";
+ }
+}
+
+#
+# print document
+#
+
+if ($split_chapter || $split_node)
+{ # split
+ $doc_num = 0;
+ $last_num = scalar(@sections);
+ $first_doc = &doc_name(1);
+ $last_doc = &doc_name($last_num);
+ while (@sections) {
+ $section = shift(@sections);
+ &next_doc;
+ # Remove added links part
+ if (open(FILE, ">$docu_doc")) {
+ print "# creating $docu_doc... ($section)\n" if $verbose;
+ &print_header("$title - $section") unless $opt_empty_headers;
+ $prev_doc = ($doc_num == 1 ? undef : &doc_name($doc_num - 1));
+ $next_doc = ($doc_num == $last_num ? undef : &doc_name($doc_num + 1));
+ $navigation = "Go to the ";
+ $navigation .= ($prev_doc ? &anchor('', $first_doc, "first") : "first");
+ $navigation .= ", ";
+ $navigation .= ($prev_doc ? &anchor('', $prev_doc, "previous") : "previous");
+ $navigation .= ", ";
+ $navigation .= ($next_doc ? &anchor('', $next_doc, "next") : "next");
+ $navigation .= ", ";
+ $navigation .= ($next_doc ? &anchor('', $last_doc, "last") : "last");
+ $navigation .= " section, " . &anchor('', $docu_toc, "table of contents") . ".\n";
+ print FILE $navigation unless $opt_empty_headers;
+ &print_ruler unless $opt_empty_headers;
+ # find corresponding lines
+ @tmp_lines = ();
+ while (@doc_lines) {
+ $_ = shift(@doc_lines);
+ last if ($_ eq $SPLITTAG);
+ push(@tmp_lines, $_);
+ }
+ &print(*tmp_lines, FILE);
+ &print_ruler unless $opt_empty_headers;
+ print FILE $navigation unless $opt_empty_headers;
+ &print_footer unless $opt_empty_headers;
+ close(FILE);
+ } else {
+ warn "$ERROR Can't write (doc) to $docu_doc: $!\n";
+ }
+ }
+}
+else
+{ # not split
+ if (open(FILE, ">$docu_doc")) {
+ print "# creating $docu_doc...\n" if $verbose;
+ if ($monolithic || !@toc_lines) {
+ &print_toplevel_header($title);
+ } else {
+ &print_header($title);
+ print FILE $full_title;
+ }
+ if ($monolithic && @toc_lines) {
+ &print_ruler;
+ print FILE "<H1>Table of Contents</H1>\n";
+ &print(*toc_lines, FILE);
+ }
+ &print_ruler;
+ &print(*doc_lines, FILE);
+ if ($monolithic && @foot_lines) {
+ &print_ruler;
+ print FILE "<H1>Footnotes</H1>\n";
+ &print(*foot_lines, FILE);
+ }
+ if ($monolithic || !@toc_lines) {
+ &print_toplevel_footer;
+ } else {
+ &print_footer;
+ }
+ close(FILE);
+ } else {
+ warn "$ERROR Can't write (doc2) to $docu_doc: $!\n";
+ }
+}
+
+print "# that's all folks\n" if $verbose;
+
+#+++############################################################################
+# #
+# Low level functions #
+# #
+#---############################################################################
+
+sub update_sec_num
+{
+ local($name, $level) = @_;
+
+ $level--; # here we start at 0
+ if ($name =~ /^appendix/) {
+ # appendix style
+ if (defined(@appendix_sec_num)) {
+ &incr_sec_num($level, @appendix_sec_num);
+ } else {
+ @appendix_sec_num = ('A', 0, 0, 0);
+ }
+ return(join('.', @appendix_sec_num[0..$level]));
+ } else {
+ # normal style
+ if (defined(@normal_sec_num)) {
+ &incr_sec_num($level, @normal_sec_num);
+ } else {
+ @normal_sec_num = (1, 0, 0, 0);
+ }
+ return(join('.', @normal_sec_num[0..$level]));
+ }
+}
+
+sub incr_sec_num
+{
+ local($level, $l);
+ $level = shift(@_);
+ $_[$level]++;
+ foreach $l ($level+1 .. 3) {
+ $_[$l] = 0;
+ }
+}
+
+sub check
+{
+ local($_, %seen, %context, $before, $match, $after);
+
+ while (<>) {
+ if (/\@(\*|\.|\:|\@|\{|\})/) {
+ $seen{$&}++;
+ $context{$&} .= "> $_" if $verbose;
+ $_ = "$`XX$'";
+ redo;
+ }
+ if (/\@(\w+)/) {
+ ($before, $match, $after) = ($`, $&, $');
+ if ($before =~ /\b[\w-]+$/ && $after =~ /^[\w-.]*\b/) { # e-mail address
+ $seen{'e-mail address'}++;
+ $context{'e-mail address'} .= "> $_" if $verbose;
+ } else {
+ $seen{$match}++;
+ $context{$match} .= "> $_" if $verbose;
+ }
+ $match =~ s/^\s*\@/X/;
+ $_ = "$before$match$after";
+ redo;
+ }
+ }
+
+ foreach (sort(keys(%seen))) {
+ if ($verbose) {
+ print "$_\n";
+ print $context{$_};
+ } else {
+ print "$_ ($seen{$_})\n";
+ }
+ }
+}
+
+sub open
+{
+ local($name) = @_;
+
+ ++$fh_name;
+ if (open($fh_name, $name)) {
+ unshift(@fhs, $fh_name);
+ } else {
+ warn "$ERROR Can't read file $name: $!\n";
+ }
+}
+
+sub init_input
+{
+ @fhs = (); # hold the file handles to read
+ @input_spool = (); # spooled lines to read
+ $fh_name = 'FH000';
+ &open($docu);
+}
+
+sub next_line
+{
+ local($fh, $line);
+
+ if (@input_spool) {
+ $line = shift(@input_spool);
+ return($line);
+ }
+ while (@fhs) {
+ $fh = $fhs[0];
+ $line = <$fh>;
+ return($line) if $line;
+ close($fh);
+ shift(@fhs);
+ }
+ return(undef);
+}
+
+# used in pass 1, use &next_line
+sub skip_until
+{
+ local($tag) = @_;
+ local($_);
+
+ while ($_ = &next_line) {
+ return if /^\s*\@end\s+$tag\s*$/;
+ }
+ die "* Failed to find '$tag' after: " . $lines[$#lines];
+}
+
+#
+# HTML stacking to have a better HTML output
+#
+
+sub html_reset
+{
+ @html_stack = ('html');
+ $html_element = 'body';
+}
+
+sub html_push
+{
+ local($what) = @_;
+ push(@html_stack, $html_element);
+ $html_element = $what;
+}
+
+sub html_push_if
+{
+ local($what) = @_;
+ push(@html_stack, $html_element)
+ if ($html_element && $html_element ne 'P');
+ $html_element = $what;
+}
+
+sub html_pop
+{
+ $html_element = pop(@html_stack);
+}
+
+sub html_pop_if
+{
+ local($elt);
+
+ if (@_) {
+ foreach $elt (@_) {
+ if ($elt eq $html_element) {
+ $html_element = pop(@html_stack) if @html_stack;
+ last;
+ }
+ }
+ } else {
+ $html_element = pop(@html_stack) if @html_stack;
+ }
+}
+
+sub html_debug
+{
+ local($what, $line) = @_;
+ return("<!-- $line @html_stack, $html_element -->$what")
+ if $debug & $DEBUG_HTML;
+ return($what);
+}
+
+# to debug the output...
+sub debug
+{
+ local($what, $line) = @_;
+ return("<!-- $line -->$what")
+ if $debug & $DEBUG_HTML;
+ return($what);
+}
+
+sub normalise_node
+{
+ $_[0] =~ s/\s+/ /g;
+ $_[0] =~ s/ $//;
+ $_[0] =~ s/^ //;
+}
+
+sub menu_entry
+{
+ local($entry, $node, $descr) = @_;
+ local($href);
+
+ &normalise_node($node);
+ $href = $node2href{$node};
+ if ($href) {
+ $descr =~ s/^\s+//;
+ $descr = ": $descr" if $descr;
+ push(@lines2, "<LI>" . &anchor('', $href, $entry) . "$descr\n");
+ } else {
+ warn "$ERROR Undefined node ($node): $_";
+ }
+}
+
+sub do_ctrl { "^$_[0]" }
+
+sub do_sc { "\U$_[0]\E" }
+
+sub fix_image
+{
+ my($text) = @_;
+ my($arg1, $ext);
+ $text =~ /^([^,]*)$/;
+ die "error in image: '$text'" unless defined($1);
+ $arg1 = $1;
+ $arg1 =~ s/@@/@/g;
+ $ext = "jpg" if -f "$arg1.jpg";
+ $ext = "gif" if -f "$arg1.gif";
+ if (defined($ext))
+ {
+ "<IMG SRC=\"$arg1.$ext\">";
+ }
+ else
+ {
+ warn "Image $arg1 not found";
+ "";
+ }
+}
+
+sub fix_url
+{
+ my($text) = @_;
+ $text =~ s/@@/@/g;
+ $text;
+}
+
+sub fix_uref
+{
+ my($text) = @_;
+ my($arg1, $arg2);
+ $text =~ /^([^,]*),?([^,]*)?$/;
+ die "error in uref: '$text'" unless defined($1);
+ $arg1 = $1;
+ $arg2 = (defined($2) && $2) ? $2 : $arg1;
+ $arg1 =~ s/@@/@/g;
+ $arg2 =~ s/@@/@/g;
+ "<a HREF=\"$arg1\">$arg2</a>";
+}
+
+sub fix_email
+{
+ my($text) = @_;
+ my($arg1, $arg2);
+ $text =~ /^([^,]*)(,[^,]*)?$/;
+ die "error in email: '$text'" unless defined($1);
+ $arg1 = $1;
+ $arg2 = defined($2) ? $2 : $arg1;
+ $arg1 =~ s/@@/@/g;
+ $arg2 =~ s/@@/@/g;
+ "<a HREF=\"mailto:$arg1\">$arg2</a>";
+}
+
+sub apply_style
+{
+ local($texi_style, $text) = @_;
+ local($style);
+
+ $style = $style_map{$texi_style};
+ if (defined($style)) { # known style
+ if ($style =~ /^\"/) { # add quotes
+ $style = $';
+ $text = "\`$text\'";
+ }
+ if ($style =~ /^\&/) { # custom
+ $style = $';
+ $text = &$style($text);
+ } elsif ($style) { # good style
+ $text = "<$style>$text</$style>";
+ } else { # no style
+ }
+ } else { # unknown style
+ $text = undef;
+ }
+ return($text);
+}
+
+# remove Texinfo styles
+sub remove_style
+{
+ local($_) = @_;
+ s/\@\w+{([^\{\}]+)}/$1/g;
+ return($_);
+}
+
+sub substitute_style
+{
+ local($_) = @_;
+ local($changed, $done, $style, $text);
+
+ $changed = 1;
+ while ($changed) {
+ $changed = 0;
+ $done = '';
+ while (/\@(\w+){([^\{\}]+)}/) {
+ $text = &apply_style($1, $2);
+ if ($text) {
+ $_ = "$`$text$'";
+ $changed = 1;
+ } else {
+ $done .= "$`\@$1";
+ $_ = "{$2}$'";
+ }
+ }
+ $_ = $done . $_;
+ }
+ return($_);
+}
+
+sub anchor
+{
+ local($name, $href, $text, $newline) = @_;
+ local($result);
+
+ $result = "<A";
+ $result .= " NAME=\"$name\"" if $name;
+ $result .= " HREF=\"$href\"" if $href;
+ $result .= ">$text</A>";
+ $result .= "\n" if $newline;
+ return($result);
+}
+
+sub pretty_date
+{
+ local(@MoY, $sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst);
+
+ @MoY = ('January', 'Febuary', 'March', 'April', 'May', 'June',
+ 'July', 'August', 'September', 'October', 'November', 'December');
+ ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime(time);
+ $year += ($year < 70) ? 2000 : 1900;
+ return("$mday $MoY[$mon] $year");
+}
+
+sub doc_name
+{
+ local($num) = @_;
+ my($real_name, $link_name);
+ $real_name = ($opt_use_numbers) ? $num : $doc_node_name[$num];
+ $link_name = ($opt_special_links) ?
+ $doc_node_name_links[$num] : $real_name;
+ # print "# num $num osl $opt_special_links link $link_name\n";
+ return("${docu_name}_$real_name.html",
+ "$opt_special_links${docu_name}_$link_name.html");
+}
+
+sub next_doc
+{
+ ($docu_doc, $link_doc) = &doc_name(++$doc_num);
+}
+
+sub print
+{
+ local(*lines, $fh) = @_;
+ local($_);
+
+ while (@lines) {
+ $_ = shift(@lines);
+ if (/^$PROTECTTAG/o) {
+ $_ = $tag2pro{$_};
+ } else {
+ &unprotect_texi;
+ }
+ print $fh $_;
+ }
+}
+
+sub print_ruler
+{
+ print FILE "<P><HR><P>\n";
+}
+
+sub print_header
+{
+ local($_);
+
+ # clean the title
+ $_ = &remove_style($_[0]);
+ &unprotect_texi;
+ # print the header
+ if ($doctype eq 'html2') {
+ print FILE $html2_doctype;
+ } elsif ($doctype) {
+ print FILE $doctype;
+ }
+ my($tags) = defined($value{"_body_tags"}) ? " " . $value{"_body_tags"} : "";
+ my($et) = defined($value{"_extra_head"}) ? " " . $value{"_extra_head"} : "";
+ $et = &unprotect_html($et);
+ print FILE <<EOT;
+ <HTML>
+ <HEAD>
+ $header
+ <TITLE>$_</TITLE>
+ $et
+ </HEAD>
+ <BODY$tags>
+EOT
+}
+
+sub print_toplevel_header
+{
+ local($_);
+
+ &print_header; # pass given arg...
+ print FILE $full_title;
+ if ($value{'_subtitle'}) {
+ $value{'_subtitle'} =~ s/\n+$//;
+ foreach (split(/\n/, $value{'_subtitle'})) {
+ $_ = &substitute_style($_);
+ &unprotect_texi;
+ print FILE "<H2>$_</H2>\n";
+ }
+ }
+ if ($value{'_author'}) {
+ $value{'_author'} =~ s/\n+$//;
+ foreach (split(/\n/, $value{'_author'})) {
+ $_ = &substitute_style($_);
+ &unprotect_texi;
+ s/[\w.-]+\@[\w.-]+/<A HREF="mailto:$&">$&<\/A>/g;
+ print FILE "<ADDRESS>$_</ADDRESS>\n";
+ }
+ }
+ print FILE "<P>\n";
+}
+
+sub print_footer
+{
+ print FILE <<EOT;
+ </BODY>
+ </HTML>
+EOT
+}
+
+sub print_toplevel_footer
+{
+ &print_ruler;
+ print FILE <<EOT;
+This document was generated on $TODAY using the
+<A HREF=\"$HOMEPAGE\">texi2html</A>
+translator version 1.52 (extended by davida\@detron.se).</P>
+EOT
+ &print_footer;
+}
+
+sub protect_texi
+{
+ # protect @ { } ` '
+ s/\@\@/$;0/go;
+ s/\@\{/$;1/go;
+ s/\@\}/$;2/go;
+ s/\@\`/$;3/go;
+ s/\@\'/$;4/go;
+}
+
+sub protect_html
+{
+ local($what) = @_;
+ # protect & < >
+ # Avoid loop in & replacement. This instead bugs out for &# in text..
+ $what =~ s/\&([^#]|$)/\&\#38;$1/g;
+ $what =~ s/\</\&\#60;/g;
+ $what =~ s/\>/\&\#62;/g;
+ # but recognize some HTML things
+ $what =~ s/\&\#60;\/A\&\#62;/<\/A>/g; # </A>
+ $what =~ s/\&\#60;A ([^\&]+)\&\#62;/<A $1>/g; # <A [^&]+>
+ $what =~ s/\&\#60;IMG ([^\&]+)\&\#62;/<IMG $1>/g; # <IMG [^&]+>
+ return($what);
+}
+
+sub unprotect_texi
+{
+ s/$;0/\@/go;
+ s/$;1/\{/go;
+ s/$;2/\}/go;
+ s/$;3/\`/go;
+ s/$;4/\'/go;
+}
+
+sub unprotect_html
+{
+ local($what) = @_;
+ $what =~ s/\&\#38;/\&/g;
+ $what =~ s/\&\#60;/\</g;
+ $what =~ s/\&\#62;/\>/g;
+ return($what);
+}
+
+sub byalpha
+{
+ $key2alpha{$a} cmp $key2alpha{$b};
+}
+
+##############################################################################
+
+ # These next few lines are legal in both Perl and nroff.
+
+ .00 ; # finish .ig
+
+ 'di \" finish diversion--previous line must be blank
+.nr nl 0-1 \" fake up transition to first page again
+.nr % 0 \" start at page 1
+'; __END__ ############# From here on it's a standard manual page ############
+.TH TEXI2HTML 1 "09/10/96"
+.AT 3
+.SH NAME
+texi2html \- a Texinfo to HTML converter
+.SH SYNOPSIS
+.B texi2html [options] file
+.PP
+.B texi2html -check [-verbose] files
+.SH DESCRIPTION
+.I Texi2html
+converts the given Texinfo file to a set of HTML files. It tries to handle
+most of the Texinfo commands. It creates hypertext links for cross-references,
+footnotes...
+.PP
+It also tries to add links from a reference to its corresponding entry in the
+bibliography (if any). It may also handle a glossary (see the
+.B \-glossary
+option).
+.PP
+.I Texi2html
+creates several files depending on the contents of the Texinfo file and on
+the chosen options (see FILES).
+.PP
+The HTML files created by
+.I texi2html
+are closer to TeX than to Info, that's why
+.I texi2html
+converts @iftex sections and not @ifinfo ones by default. You can reverse
+this with the \-expandinfo option.
+.SH OPTIONS
+.TP 12
+.B \-check
+Check the given file and give the list of all things that may be Texinfo commands.
+This may be used to check the output of
+.I texi2html
+to find the Texinfo commands that have been left in the HTML file.
+.TP
+.B \-expandinfo
+Expand @ifinfo sections, not @iftex ones.
+.TP
+.B \-glossary
+Use the section named 'Glossary' to build a list of terms and put links in the HTML
+document from each term toward its definition.
+.TP
+.B \-invisible \fIname\fP
+Use \fIname\fP to create invisible destination anchors for index links. This is a workaround
+for a known bug of many WWW browsers, including xmosaic.
+.TP
+.B \-I \fIdir\fP
+Look also in \fIdir\fP to find included files.
+.TP
+.B \-menu
+Show the Texinfo menus; by default they are ignored.
+.TP
+.B \-monolithic
+Output only one file, including the table of contents and footnotes.
+.TP
+.B \-number
+Number the sections.
+.TP
+.B \-split_chapter
+Split the output into several HTML files (one per main section:
+chapter, appendix...).
+.TP
+.B \-split_node
+Split the output into several HTML files (one per node).
+.TP
+.B \-usage
+Print usage instructions, listing the current available command-line options.
+.TP
+.B \-verbose
+Give a verbose output. Can be used with the
+.B \-check
+option.
+.PP
+.SH FILES
+By default
+.I texi2html
+creates the following files (foo being the name of the Texinfo file):
+.TP 16
+.B foo_toc.html
+The table of contents.
+.TP
+.B foo.html
+The document's contents.
+.TP
+.B foo_foot.html
+The footnotes (if any).
+.PP
+When used with the
+.B \-split
+option, it creates several files (one per chapter or node), named
+.B foo_n.html
+(n being the indice of the chapter or node), instead of the single
+.B foo.html
+file.
+.PP
+When used with the
+.B \-monolithic
+option, it creates only one file:
+.B foo.html
+.SH VARIABLES
+.I texi2html
+predefines the following variables: \fBhtml\fP, \fBtexi2html\fP.
+.SH ADDITIONAL COMMANDS
+.I texi2html
+implements the following non-Texinfo commands:
+.TP 16
+.B @ifhtml
+This indicates the start of an HTML section, this section will passed through
+without any modofication.
+.TP
+.B @end ifhtml
+This indcates the end of an HTML section.
+.SH VERSION
+This is \fItexi2html\fP version 1.52, 09/10/96.
+.PP
+The latest version of \fItexi2html\fP can be found in WWW, cf. URL
+http://wwwcn.cern.ch/dci/texi2html/
+.SH AUTHOR
+The main author is Lionel Cons, CERN CN/DCI/UWS, Lionel.Cons@cern.ch.
+Many other people around the net contributed to this program.
+.SH COPYRIGHT
+This program is the intellectual property of the European
+Laboratory for Particle Physics (known as CERN). No guarantee whatsoever is
+provided by CERN. No liability whatsoever is accepted for any loss or damage
+of any kind resulting from any defect or inaccuracy in this information or
+code.
+.PP
+CERN, 1211 Geneva 23, Switzerland
+.SH "SEE ALSO"
+GNU Texinfo Documentation Format,
+HyperText Markup Language (HTML),
+World Wide Web (WWW).
+.SH BUGS
+This program does not understand all Texinfo commands (yet).
+.PP
+TeX specific commands (normally enclosed in @iftex) will be
+passed unmodified.
+.ex
diff --git a/Docs/Support/texinfo.tex b/Docs/Support/texinfo.tex
new file mode 100644
index 00000000000..7421f884d22
--- /dev/null
+++ b/Docs/Support/texinfo.tex
@@ -0,0 +1,5868 @@
+% texinfo.tex -- TeX macros to handle Texinfo files.
+%
+% Load plain if necessary, i.e., if running under initex.
+\expandafter\ifx\csname fmtname\endcsname\relax\input plain\fi
+%
+\def\texinfoversion{1999-05-25.6}%
+%
+% Copyright (C) 1985, 86, 88, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99
+% Free Software Foundation, Inc.
+%
+% This texinfo.tex 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, or (at
+% your option) any later version.
+%
+% This texinfo.tex file is distributed in the hope that it will be
+% useful, but WITHOUT ANY WARRANTY; without even the implied warranty
+% of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+% General Public License for more details.
+%
+% You should have received a copy of the GNU General Public License
+% along with this texinfo.tex file; see the file COPYING. If not, write
+% to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+% Boston, MA 02111-1307, USA.
+%
+% In other words, you are welcome to use, share and improve this program.
+% You are forbidden to forbid anyone else to use, share and improve
+% what you give them. Help stamp out software-hoarding!
+%
+% Please try the latest version of texinfo.tex before submitting bug
+% reports; you can get the latest version from:
+% ftp://ftp.gnu.org/pub/gnu/texinfo.tex
+% (and all GNU mirrors, see http://www.gnu.org/order/ftp.html)
+% ftp://tug.org/tex/texinfo.tex
+% ftp://ctan.org/macros/texinfo/texinfo.tex
+% (and all CTAN mirrors, finger ctan@ctan.org for a list).
+% /home/gd/gnu/doc/texinfo.tex on the GNU machines.
+% The texinfo.tex in any given Texinfo distribution could well be out
+% of date, so if that's what you're using, please check.
+% There is a small home page for Texinfo at http://texinfo.org/.
+%
+% Send bug reports to bug-texinfo@gnu.org. Please include including a
+% complete document in each bug report with which we can reproduce the
+% problem. Patches are, of course, greatly appreciated.
+%
+% To process a Texinfo manual with TeX, it's most reliable to use the
+% texi2dvi shell script that comes with the distribution. For a simple
+% manual foo.texi, however, you can get away with this:
+% tex foo.texi
+% texindex foo.??
+% tex foo.texi
+% tex foo.texi
+% dvips foo.dvi -o # or whatever, to process the dvi file; this makes foo.ps.
+% The extra runs of TeX get the cross-reference information correct.
+% Sometimes one run after texindex suffices, and sometimes you need more
+% than two; texi2dvi does it as many times as necessary.
+%
+% It is possible to adapt texinfo.tex for other languages. You can get
+% the existing language-specific files from ftp://ftp.gnu.org/gnu/texinfo/.
+
+\message{Loading texinfo [version \texinfoversion]:}
+
+% If in a .fmt file, print the version number
+% and turn on active characters that we couldn't do earlier because
+% they might have appeared in the input file name.
+\everyjob{\message{[Texinfo version \texinfoversion]}%
+ \catcode`+=\active \catcode`\_=\active}
+
+% Save some parts of plain tex whose names we will redefine.
+\let\ptexb=\b
+\let\ptexbullet=\bullet
+\let\ptexc=\c
+\let\ptexcomma=\,
+\let\ptexdot=\.
+\let\ptexdots=\dots
+\let\ptexend=\end
+\let\ptexequiv=\equiv
+\let\ptexexclam=\!
+\let\ptexi=\i
+\let\ptexlbrace=\{
+\let\ptexrbrace=\}
+\let\ptexstar=\*
+\let\ptext=\t
+
+% We never want plain's outer \+ definition in Texinfo.
+% For @tex, we can use \tabalign.
+\let\+ = \relax
+
+% Get ready for pdf.
+\newif\ifpdf
+\ifx\pdfoutput\undefined\else
+ \input pdfcolor
+ \pdfoutput=1
+ \pdftrue
+\fi
+
+\message{Basics,}
+\chardef\other=12
+
+% If this character appears in an error message or help string, it
+% starts a new line in the output.
+\newlinechar = `^^J
+
+% Set up fixed words for English if not already set.
+\ifx\putwordAppendix\undefined \gdef\putwordAppendix{Appendix}\fi
+\ifx\putwordChapter\undefined \gdef\putwordChapter{Chapter}\fi
+\ifx\putwordfile\undefined \gdef\putwordfile{file}\fi
+\ifx\putwordin\undefined \gdef\putwordin{in}\fi
+\ifx\putwordIndexIsEmpty\undefined \gdef\putwordIndexIsEmpty{(Index is empty)}\fi
+\ifx\putwordIndexNonexistent\undefined \gdef\putwordIndexNonexistent{(Index is nonexistent)}\fi
+\ifx\putwordInfo\undefined \gdef\putwordInfo{Info}\fi
+\ifx\putwordInstanceVariableof\undefined \gdef\putwordInstanceVariableof{Instance Variable of}\fi
+\ifx\putwordMethodon\undefined \gdef\putwordMethodon{Method on}\fi
+\ifx\putwordNoTitle\undefined \gdef\putwordNoTitle{No Title}\fi
+\ifx\putwordof\undefined \gdef\putwordof{of}\fi
+\ifx\putwordon\undefined \gdef\putwordon{on}\fi
+\ifx\putwordpage\undefined \gdef\putwordpage{page}\fi
+\ifx\putwordsection\undefined \gdef\putwordsection{section}\fi
+\ifx\putwordSection\undefined \gdef\putwordSection{Section}\fi
+\ifx\putwordsee\undefined \gdef\putwordsee{see}\fi
+\ifx\putwordSee\undefined \gdef\putwordSee{See}\fi
+\ifx\putwordShortTOC\undefined \gdef\putwordShortTOC{Short Contents}\fi
+\ifx\putwordTOC\undefined \gdef\putwordTOC{Table of Contents}\fi
+%
+\ifx\putwordMJan\undefined \gdef\putwordMJan{January}\fi
+\ifx\putwordMFeb\undefined \gdef\putwordMFeb{February}\fi
+\ifx\putwordMMar\undefined \gdef\putwordMMar{March}\fi
+\ifx\putwordMApr\undefined \gdef\putwordMApr{April}\fi
+\ifx\putwordMMay\undefined \gdef\putwordMMay{May}\fi
+\ifx\putwordMJun\undefined \gdef\putwordMJun{June}\fi
+\ifx\putwordMJul\undefined \gdef\putwordMJul{July}\fi
+\ifx\putwordMAug\undefined \gdef\putwordMAug{August}\fi
+\ifx\putwordMSep\undefined \gdef\putwordMSep{September}\fi
+\ifx\putwordMOct\undefined \gdef\putwordMOct{October}\fi
+\ifx\putwordMNov\undefined \gdef\putwordMNov{November}\fi
+\ifx\putwordMDec\undefined \gdef\putwordMDec{December}\fi
+%
+\ifx\putwordDefmac\undefined \gdef\putwordDefmac{Macro}\fi
+\ifx\putwordDefspec\undefined \gdef\putwordDefspec{Special Form}\fi
+\ifx\putwordDefvar\undefined \gdef\putwordDefvar{Variable}\fi
+\ifx\putwordDefopt\undefined \gdef\putwordDefopt{User Option}\fi
+\ifx\putwordDeftypevar\undefined\gdef\putwordDeftypevar{Variable}\fi
+\ifx\putwordDeffunc\undefined \gdef\putwordDeffunc{Function}\fi
+\ifx\putwordDeftypefun\undefined\gdef\putwordDeftypefun{Function}\fi
+
+% Ignore a token.
+%
+\def\gobble#1{}
+
+\hyphenation{ap-pen-dix}
+\hyphenation{mini-buf-fer mini-buf-fers}
+\hyphenation{eshell}
+\hyphenation{white-space}
+
+% Margin to add to right of even pages, to left of odd pages.
+\newdimen \bindingoffset
+\newdimen \normaloffset
+\newdimen\pagewidth \newdimen\pageheight
+
+% Sometimes it is convenient to have everything in the transcript file
+% and nothing on the terminal. We don't just call \tracingall here,
+% since that produces some useless output on the terminal.
+%
+\def\gloggingall{\begingroup \globaldefs = 1 \loggingall \endgroup}%
+\ifx\eTeXversion\undefined
+\def\loggingall{\tracingcommands2 \tracingstats2
+ \tracingpages1 \tracingoutput1 \tracinglostchars1
+ \tracingmacros2 \tracingparagraphs1 \tracingrestores1
+ \showboxbreadth\maxdimen\showboxdepth\maxdimen
+}%
+\else
+\def\loggingall{\tracingcommands3 \tracingstats2
+ \tracingpages1 \tracingoutput1 \tracinglostchars1
+ \tracingmacros2 \tracingparagraphs1 \tracingrestores1
+ \tracingscantokens1 \tracingassigns1 \tracingifs1
+ \tracinggroups1 \tracingnesting2
+ \showboxbreadth\maxdimen\showboxdepth\maxdimen
+}%
+\fi
+
+% For @cropmarks command.
+% Do @cropmarks to get crop marks.
+%
+\newif\ifcropmarks
+\let\cropmarks = \cropmarkstrue
+%
+% Dimensions to add cropmarks at corners.
+% Added by P. A. MacKay, 12 Nov. 1986
+%
+\newdimen\outerhsize \newdimen\outervsize % set by the paper size routines
+\newdimen\cornerlong \cornerlong=1pc
+\newdimen\cornerthick \cornerthick=.3pt
+\newdimen\topandbottommargin \topandbottommargin=.75in
+
+% Main output routine.
+\chardef\PAGE = 255
+\output = {\onepageout{\pagecontents\PAGE}}
+
+\newbox\headlinebox
+\newbox\footlinebox
+
+% \onepageout takes a vbox as an argument. Note that \pagecontents
+% does insertions, but you have to call it yourself.
+\def\onepageout#1{%
+ \ifcropmarks \hoffset=0pt \else \hoffset=\normaloffset \fi
+ %
+ \ifodd\pageno \advance\hoffset by \bindingoffset
+ \else \advance\hoffset by -\bindingoffset\fi
+ %
+ % Do this outside of the \shipout so @code etc. will be expanded in
+ % the headline as they should be, not taken literally (outputting ''code).
+ \setbox\headlinebox = \vbox{\let\hsize=\pagewidth \makeheadline}%
+ \setbox\footlinebox = \vbox{\let\hsize=\pagewidth \makefootline}%
+ %
+ {%
+ % Have to do this stuff outside the \shipout because we want it to
+ % take effect in \write's, yet the group defined by the \vbox ends
+ % before the \shipout runs.
+ %
+ \escapechar = `\\ % use backslash in output files.
+ \indexdummies % don't expand commands in the output.
+ \normalturnoffactive % \ in index entries must not stay \, e.g., if
+ % the page break happens to be in the middle of an example.
+ \shipout\vbox{%
+ \ifcropmarks \vbox to \outervsize\bgroup
+ \hsize = \outerhsize
+ \vskip-\topandbottommargin
+ \vtop to0pt{%
+ \line{\ewtop\hfil\ewtop}%
+ \nointerlineskip
+ \line{%
+ \vbox{\moveleft\cornerthick\nstop}%
+ \hfill
+ \vbox{\moveright\cornerthick\nstop}%
+ }%
+ \vss}%
+ \vskip\topandbottommargin
+ \line\bgroup
+ \hfil % center the page within the outer (page) hsize.
+ \ifodd\pageno\hskip\bindingoffset\fi
+ \vbox\bgroup
+ \fi
+ %
+ \unvbox\headlinebox
+ \pagebody{#1}%
+ \ifdim\ht\footlinebox > 0pt
+ % Only leave this space if the footline is nonempty.
+ % (We lessened \vsize for it in \oddfootingxxx.)
+ % The \baselineskip=24pt in plain's \makefootline has no effect.
+ \vskip 2\baselineskip
+ \unvbox\footlinebox
+ \fi
+ %
+ \ifpdf\pdfmkdest{\the\pageno}\fi
+ %
+ \ifcropmarks
+ \egroup % end of \vbox\bgroup
+ \hfil\egroup % end of (centering) \line\bgroup
+ \vskip\topandbottommargin plus1fill minus1fill
+ \boxmaxdepth = \cornerthick
+ \vbox to0pt{\vss
+ \line{%
+ \vbox{\moveleft\cornerthick\nsbot}%
+ \hfill
+ \vbox{\moveright\cornerthick\nsbot}%
+ }%
+ \nointerlineskip
+ \line{\ewbot\hfil\ewbot}%
+ }%
+ \egroup % \vbox from first cropmarks clause
+ \fi
+ }% end of \shipout\vbox
+ }% end of group with \turnoffactive
+ \advancepageno
+ \ifnum\outputpenalty>-20000 \else\dosupereject\fi
+}
+
+\newinsert\margin \dimen\margin=\maxdimen
+
+\def\pagebody#1{\vbox to\pageheight{\boxmaxdepth=\maxdepth #1}}
+{\catcode`\@ =11
+\gdef\pagecontents#1{\ifvoid\topins\else\unvbox\topins\fi
+% marginal hacks, juha@viisa.uucp (Juha Takala)
+\ifvoid\margin\else % marginal info is present
+ \rlap{\kern\hsize\vbox to\z@{\kern1pt\box\margin \vss}}\fi
+\dimen@=\dp#1 \unvbox#1
+\ifvoid\footins\else\vskip\skip\footins\footnoterule \unvbox\footins\fi
+\ifr@ggedbottom \kern-\dimen@ \vfil \fi}
+}
+
+% Here are the rules for the cropmarks. Note that they are
+% offset so that the space between them is truly \outerhsize or \outervsize
+% (P. A. MacKay, 12 November, 1986)
+%
+\def\ewtop{\vrule height\cornerthick depth0pt width\cornerlong}
+\def\nstop{\vbox
+ {\hrule height\cornerthick depth\cornerlong width\cornerthick}}
+\def\ewbot{\vrule height0pt depth\cornerthick width\cornerlong}
+\def\nsbot{\vbox
+ {\hrule height\cornerlong depth\cornerthick width\cornerthick}}
+
+% Parse an argument, then pass it to #1. The argument is the rest of
+% the input line (except we remove a trailing comment). #1 should be a
+% macro which expects an ordinary undelimited TeX argument.
+%
+\def\parsearg#1{%
+ \let\next = #1%
+ \begingroup
+ \obeylines
+ \futurelet\temp\parseargx
+}
+
+% If the next token is an obeyed space (from an @example environment or
+% the like), remove it and recurse. Otherwise, we're done.
+\def\parseargx{%
+ % \obeyedspace is defined far below, after the definition of \sepspaces.
+ \ifx\obeyedspace\temp
+ \expandafter\parseargdiscardspace
+ \else
+ \expandafter\parseargline
+ \fi
+}
+
+% Remove a single space (as the delimiter token to the macro call).
+{\obeyspaces %
+ \gdef\parseargdiscardspace {\futurelet\temp\parseargx}}
+
+{\obeylines %
+ \gdef\parseargline#1^^M{%
+ \endgroup % End of the group started in \parsearg.
+ %
+ % First remove any @c comment, then any @comment.
+ % Result of each macro is put in \toks0.
+ \argremovec #1\c\relax %
+ \expandafter\argremovecomment \the\toks0 \comment\relax %
+ %
+ % Call the caller's macro, saved as \next in \parsearg.
+ \expandafter\next\expandafter{\the\toks0}%
+ }%
+}
+
+% Since all \c{,omment} does is throw away the argument, we can let TeX
+% do that for us. The \relax here is matched by the \relax in the call
+% in \parseargline; it could be more or less anything, its purpose is
+% just to delimit the argument to the \c.
+\def\argremovec#1\c#2\relax{\toks0 = {#1}}
+\def\argremovecomment#1\comment#2\relax{\toks0 = {#1}}
+
+% \argremovec{,omment} might leave us with trailing spaces, though; e.g.,
+% @end itemize @c foo
+% will have two active spaces as part of the argument with the
+% `itemize'. Here we remove all active spaces from #1, and assign the
+% result to \toks0.
+%
+% This loses if there are any *other* active characters besides spaces
+% in the argument -- _ ^ +, for example -- since they get expanded.
+% Fortunately, Texinfo does not define any such commands. (If it ever
+% does, the catcode of the characters in questionwill have to be changed
+% here.) But this means we cannot call \removeactivespaces as part of
+% \argremovec{,omment}, since @c uses \parsearg, and thus the argument
+% that \parsearg gets might well have any character at all in it.
+%
+\def\removeactivespaces#1{%
+ \begingroup
+ \ignoreactivespaces
+ \edef\temp{#1}%
+ \global\toks0 = \expandafter{\temp}%
+ \endgroup
+}
+
+% Change the active space to expand to nothing.
+%
+\begingroup
+ \obeyspaces
+ \gdef\ignoreactivespaces{\obeyspaces\let =\empty}
+\endgroup
+
+
+\def\flushcr{\ifx\par\lisppar \def\next##1{}\else \let\next=\relax \fi \next}
+
+%% These are used to keep @begin/@end levels from running away
+%% Call \inENV within environments (after a \begingroup)
+\newif\ifENV \ENVfalse \def\inENV{\ifENV\relax\else\ENVtrue\fi}
+\def\ENVcheck{%
+\ifENV\errmessage{Still within an environment; press RETURN to continue}
+\endgroup\fi} % This is not perfect, but it should reduce lossage
+
+% @begin foo is the same as @foo, for now.
+\newhelp\EMsimple{Press RETURN to continue.}
+
+\outer\def\begin{\parsearg\beginxxx}
+
+\def\beginxxx #1{%
+\expandafter\ifx\csname #1\endcsname\relax
+{\errhelp=\EMsimple \errmessage{Undefined command @begin #1}}\else
+\csname #1\endcsname\fi}
+
+% @end foo executes the definition of \Efoo.
+%
+\def\end{\parsearg\endxxx}
+\def\endxxx #1{%
+ \removeactivespaces{#1}%
+ \edef\endthing{\the\toks0}%
+ %
+ \expandafter\ifx\csname E\endthing\endcsname\relax
+ \expandafter\ifx\csname \endthing\endcsname\relax
+ % There's no \foo, i.e., no ``environment'' foo.
+ \errhelp = \EMsimple
+ \errmessage{Undefined command `@end \endthing'}%
+ \else
+ \unmatchedenderror\endthing
+ \fi
+ \else
+ % Everything's ok; the right environment has been started.
+ \csname E\endthing\endcsname
+ \fi
+}
+
+% There is an environment #1, but it hasn't been started. Give an error.
+%
+\def\unmatchedenderror#1{%
+ \errhelp = \EMsimple
+ \errmessage{This `@end #1' doesn't have a matching `@#1'}%
+}
+
+% Define the control sequence \E#1 to give an unmatched @end error.
+%
+\def\defineunmatchedend#1{%
+ \expandafter\def\csname E#1\endcsname{\unmatchedenderror{#1}}%
+}
+
+
+% Single-spacing is done by various environments (specifically, in
+% \nonfillstart and \quotations).
+\newskip\singlespaceskip \singlespaceskip = 12.5pt
+\def\singlespace{%
+ % Why was this kern here? It messes up equalizing space above and below
+ % environments. --karl, 6may93
+ %{\advance \baselineskip by -\singlespaceskip
+ %\kern \baselineskip}%
+ \setleading \singlespaceskip
+}
+
+%% Simple single-character @ commands
+
+% @@ prints an @
+% Kludge this until the fonts are right (grr).
+\def\@{{\tt\char64}}
+
+% This is turned off because it was never documented
+% and you can use @w{...} around a quote to suppress ligatures.
+%% Define @` and @' to be the same as ` and '
+%% but suppressing ligatures.
+%\def\`{{`}}
+%\def\'{{'}}
+
+% Used to generate quoted braces.
+\def\mylbrace {{\tt\char123}}
+\def\myrbrace {{\tt\char125}}
+\let\{=\mylbrace
+\let\}=\myrbrace
+\begingroup
+ % Definitions to produce actual \{ & \} command in an index.
+ \catcode`\{ = 12 \catcode`\} = 12
+ \catcode`\[ = 1 \catcode`\] = 2
+ \catcode`\@ = 0 \catcode`\\ = 12
+ @gdef@lbracecmd[\{]%
+ @gdef@rbracecmd[\}]%
+@endgroup
+
+% Accents: @, @dotaccent @ringaccent @ubaraccent @udotaccent
+% Others are defined by plain TeX: @` @' @" @^ @~ @= @v @H.
+\let\, = \c
+\let\dotaccent = \.
+\def\ringaccent#1{{\accent23 #1}}
+\let\tieaccent = \t
+\let\ubaraccent = \b
+\let\udotaccent = \d
+
+% Other special characters: @questiondown @exclamdown
+% Plain TeX defines: @AA @AE @O @OE @L (and lowercase versions) @ss.
+\def\questiondown{?`}
+\def\exclamdown{!`}
+
+% Dotless i and dotless j, used for accents.
+\def\imacro{i}
+\def\jmacro{j}
+\def\dotless#1{%
+ \def\temp{#1}%
+ \ifx\temp\imacro \ptexi
+ \else\ifx\temp\jmacro \j
+ \else \errmessage{@dotless can be used only with i or j}%
+ \fi\fi
+}
+
+% Be sure we're in horizontal mode when doing a tie, since we make space
+% equivalent to this in @example-like environments. Otherwise, a space
+% at the beginning of a line will start with \penalty -- and
+% since \penalty is valid in vertical mode, we'd end up putting the
+% penalty on the vertical list instead of in the new paragraph.
+{\catcode`@ = 11
+ % Avoid using \@M directly, because that causes trouble
+ % if the definition is written into an index file.
+ \global\let\tiepenalty = \@M
+ \gdef\tie{\leavevmode\penalty\tiepenalty\ }
+}
+
+% @: forces normal size whitespace following.
+\def\:{\spacefactor=1000 }
+
+% @* forces a line break.
+\def\*{\hfil\break\hbox{}\ignorespaces}
+
+% @. is an end-of-sentence period.
+\def\.{.\spacefactor=3000 }
+
+% @! is an end-of-sentence bang.
+\def\!{!\spacefactor=3000 }
+
+% @? is an end-of-sentence query.
+\def\?{?\spacefactor=3000 }
+
+% @w prevents a word break. Without the \leavevmode, @w at the
+% beginning of a paragraph, when TeX is still in vertical mode, would
+% produce a whole line of output instead of starting the paragraph.
+\def\w#1{\leavevmode\hbox{#1}}
+
+% @group ... @end group forces ... to be all on one page, by enclosing
+% it in a TeX vbox. We use \vtop instead of \vbox to construct the box
+% to keep its height that of a normal line. According to the rules for
+% \topskip (p.114 of the TeXbook), the glue inserted is
+% max (\topskip - \ht (first item), 0). If that height is large,
+% therefore, no glue is inserted, and the space between the headline and
+% the text is small, which looks bad.
+%
+\def\group{\begingroup
+ \ifnum\catcode13=\active \else
+ \errhelp = \groupinvalidhelp
+ \errmessage{@group invalid in context where filling is enabled}%
+ \fi
+ %
+ % The \vtop we start below produces a box with normal height and large
+ % depth; thus, TeX puts \baselineskip glue before it, and (when the
+ % next line of text is done) \lineskip glue after it. (See p.82 of
+ % the TeXbook.) Thus, space below is not quite equal to space
+ % above. But it's pretty close.
+ \def\Egroup{%
+ \egroup % End the \vtop.
+ \endgroup % End the \group.
+ }%
+ %
+ \vtop\bgroup
+ % We have to put a strut on the last line in case the @group is in
+ % the midst of an example, rather than completely enclosing it.
+ % Otherwise, the interline space between the last line of the group
+ % and the first line afterwards is too small. But we can't put the
+ % strut in \Egroup, since there it would be on a line by itself.
+ % Hence this just inserts a strut at the beginning of each line.
+ \everypar = {\strut}%
+ %
+ % Since we have a strut on every line, we don't need any of TeX's
+ % normal interline spacing.
+ \offinterlineskip
+ %
+ % OK, but now we have to do something about blank
+ % lines in the input in @example-like environments, which normally
+ % just turn into \lisppar, which will insert no space now that we've
+ % turned off the interline space. Simplest is to make them be an
+ % empty paragraph.
+ \ifx\par\lisppar
+ \edef\par{\leavevmode \par}%
+ %
+ % Reset ^^M's definition to new definition of \par.
+ \obeylines
+ \fi
+ %
+ % Do @comment since we are called inside an environment such as
+ % @example, where each end-of-line in the input causes an
+ % end-of-line in the output. We don't want the end-of-line after
+ % the `@group' to put extra space in the output. Since @group
+ % should appear on a line by itself (according to the Texinfo
+ % manual), we don't worry about eating any user text.
+ \comment
+}
+%
+% TeX puts in an \escapechar (i.e., `@') at the beginning of the help
+% message, so this ends up printing `@group can only ...'.
+%
+\newhelp\groupinvalidhelp{%
+group can only be used in environments such as @example,^^J%
+where each line of input produces a line of output.}
+
+% @need space-in-mils
+% forces a page break if there is not space-in-mils remaining.
+
+\newdimen\mil \mil=0.001in
+
+\def\need{\parsearg\needx}
+
+% Old definition--didn't work.
+%\def\needx #1{\par %
+%% This method tries to make TeX break the page naturally
+%% if the depth of the box does not fit.
+%{\baselineskip=0pt%
+%\vtop to #1\mil{\vfil}\kern -#1\mil\nobreak
+%\prevdepth=-1000pt
+%}}
+
+\def\needx#1{%
+ % Go into vertical mode, so we don't make a big box in the middle of a
+ % paragraph.
+ \par
+ %
+ % Don't add any leading before our big empty box, but allow a page
+ % break, since the best break might be right here.
+ \allowbreak
+ \nointerlineskip
+ \vtop to #1\mil{\vfil}%
+ %
+ % TeX does not even consider page breaks if a penalty added to the
+ % main vertical list is 10000 or more. But in order to see if the
+ % empty box we just added fits on the page, we must make it consider
+ % page breaks. On the other hand, we don't want to actually break the
+ % page after the empty box. So we use a penalty of 9999.
+ %
+ % There is an extremely small chance that TeX will actually break the
+ % page at this \penalty, if there are no other feasible breakpoints in
+ % sight. (If the user is using lots of big @group commands, which
+ % almost-but-not-quite fill up a page, TeX will have a hard time doing
+ % good page breaking, for example.) However, I could not construct an
+ % example where a page broke at this \penalty; if it happens in a real
+ % document, then we can reconsider our strategy.
+ \penalty9999
+ %
+ % Back up by the size of the box, whether we did a page break or not.
+ \kern -#1\mil
+ %
+ % Do not allow a page break right after this kern.
+ \nobreak
+}
+
+% @br forces paragraph break
+
+\let\br = \par
+
+% @dots{} output an ellipsis using the current font.
+% We do .5em per period so that it has the same spacing in a typewriter
+% font as three actual period characters.
+%
+\def\dots{%
+ \leavevmode
+ \hbox to 1.5em{%
+ \hskip 0pt plus 0.25fil minus 0.25fil
+ .\hss.\hss.%
+ \hskip 0pt plus 0.5fil minus 0.5fil
+ }%
+}
+
+% @enddots{} is an end-of-sentence ellipsis.
+%
+\def\enddots{%
+ \leavevmode
+ \hbox to 2em{%
+ \hskip 0pt plus 0.25fil minus 0.25fil
+ .\hss.\hss.\hss.%
+ \hskip 0pt plus 0.5fil minus 0.5fil
+ }%
+ \spacefactor=3000
+}
+
+
+% @page forces the start of a new page
+%
+\def\page{\par\vfill\supereject}
+
+% @exdent text....
+% outputs text on separate line in roman font, starting at standard page margin
+
+% This records the amount of indent in the innermost environment.
+% That's how much \exdent should take out.
+\newskip\exdentamount
+
+% This defn is used inside fill environments such as @defun.
+\def\exdent{\parsearg\exdentyyy}
+\def\exdentyyy #1{{\hfil\break\hbox{\kern -\exdentamount{\rm#1}}\hfil\break}}
+
+% This defn is used inside nofill environments such as @example.
+\def\nofillexdent{\parsearg\nofillexdentyyy}
+\def\nofillexdentyyy #1{{\advance \leftskip by -\exdentamount
+\leftline{\hskip\leftskip{\rm#1}}}}
+
+% @inmargin{TEXT} puts TEXT in the margin next to the current paragraph.
+
+\def\inmargin#1{%
+\strut\vadjust{\nobreak\kern-\strutdepth
+ \vtop to \strutdepth{\baselineskip\strutdepth\vss
+ \llap{\rightskip=\inmarginspacing \vbox{\noindent #1}}\null}}}
+\newskip\inmarginspacing \inmarginspacing=1cm
+\def\strutdepth{\dp\strutbox}
+
+%\hbox{{\rm#1}}\hfil\break}}
+
+% @include file insert text of that file as input.
+% Allow normal characters that we make active in the argument (a file name).
+\def\include{\begingroup
+ \catcode`\\=12
+ \catcode`~=12
+ \catcode`^=12
+ \catcode`_=12
+ \catcode`|=12
+ \catcode`<=12
+ \catcode`>=12
+ \catcode`+=12
+ \parsearg\includezzz}
+% Restore active chars for included file.
+\def\includezzz#1{\endgroup\begingroup
+ % Read the included file in a group so nested @include's work.
+ \def\thisfile{#1}%
+ \input\thisfile
+\endgroup}
+
+\def\thisfile{}
+
+% @center line outputs that line, centered
+
+\def\center{\parsearg\centerzzz}
+\def\centerzzz #1{{\advance\hsize by -\leftskip
+\advance\hsize by -\rightskip
+\centerline{#1}}}
+
+% @sp n outputs n lines of vertical space
+
+\def\sp{\parsearg\spxxx}
+\def\spxxx #1{\vskip #1\baselineskip}
+
+% @comment ...line which is ignored...
+% @c is the same as @comment
+% @ignore ... @end ignore is another way to write a comment
+
+\def\comment{\begingroup \catcode`\^^M=\other%
+\catcode`\@=\other \catcode`\{=\other \catcode`\}=\other%
+\commentxxx}
+{\catcode`\^^M=\other \gdef\commentxxx#1^^M{\endgroup}}
+
+\let\c=\comment
+
+% @paragraphindent NCHARS
+% We'll use ems for NCHARS, close enough.
+% We cannot implement @paragraphindent asis, though.
+%
+\def\asisword{asis} % no translation, these are keywords
+\def\noneword{none}
+%
+\def\paragraphindent{\parsearg\doparagraphindent}
+\def\doparagraphindent#1{%
+ \def\temp{#1}%
+ \ifx\temp\asisword
+ \else
+ \ifx\temp\noneword
+ \defaultparindent = 0pt
+ \else
+ \defaultparindent = #1em
+ \fi
+ \fi
+ \parindent = \defaultparindent
+}
+
+% @exampleindent NCHARS
+% We'll use ems for NCHARS like @paragraphindent.
+% It seems @exampleindent asis isn't necessary, but
+% I preserve it to make it similar to @paragraphindent.
+\def\exampleindent{\parsearg\doexampleindent}
+\def\doexampleindent#1{%
+ \def\temp{#1}%
+ \ifx\temp\asisword
+ \else
+ \ifx\temp\noneword
+ \lispnarrowing = 0pt
+ \else
+ \lispnarrowing = #1em
+ \fi
+ \fi
+}
+
+% @asis just yields its argument. Used with @table, for example.
+%
+\def\asis#1{#1}
+
+% @math means output in math mode.
+% We don't use $'s directly in the definition of \math because control
+% sequences like \math are expanded when the toc file is written. Then,
+% we read the toc file back, the $'s will be normal characters (as they
+% should be, according to the definition of Texinfo). So we must use a
+% control sequence to switch into and out of math mode.
+%
+% This isn't quite enough for @math to work properly in indices, but it
+% seems unlikely it will ever be needed there.
+%
+\let\implicitmath = $
+\def\math#1{\implicitmath #1\implicitmath}
+
+% @bullet and @minus need the same treatment as @math, just above.
+\def\bullet{\implicitmath\ptexbullet\implicitmath}
+\def\minus{\implicitmath-\implicitmath}
+
+% @refill is a no-op.
+\let\refill=\relax
+
+% If working on a large document in chapters, it is convenient to
+% be able to disable indexing, cross-referencing, and contents, for test runs.
+% This is done with @novalidate (before @setfilename).
+%
+\newif\iflinks \linkstrue % by default we want the aux files.
+\let\novalidate = \linksfalse
+
+% @setfilename is done at the beginning of every texinfo file.
+% So open here the files we need to have open while reading the input.
+% This makes it possible to make a .fmt file for texinfo.
+\def\setfilename{%
+ \iflinks
+ \readauxfile
+ \fi % \openindices needs to do some work in any case.
+ \openindices
+ \fixbackslash % Turn off hack to swallow `\input texinfo'.
+ \global\let\setfilename=\comment % Ignore extra @setfilename cmds.
+ %
+ % If texinfo.cnf is present on the system, read it.
+ % Useful for site-wide @afourpaper, etc.
+ % Just to be on the safe side, close the input stream before the \input.
+ \openin 1 texinfo.cnf
+ \ifeof1 \let\temp=\relax \else \def\temp{\input texinfo.cnf }\fi
+ \closein1
+ \temp
+ %
+ \comment % Ignore the actual filename.
+}
+
+% Called from \setfilename.
+%
+\def\openindices{%
+ \newindex{cp}%
+ \newcodeindex{fn}%
+ \newcodeindex{vr}%
+ \newcodeindex{tp}%
+ \newcodeindex{ky}%
+ \newcodeindex{pg}%
+}
+
+% @bye.
+\outer\def\bye{\pagealignmacro\tracingstats=1\ptexend}
+
+
+\message{pdf,}
+% adobe `portable' document format
+
+\newcount\tempnum
+\newcount\lnkcount
+\newtoks\filename
+\newcount\filenamelength
+\newcount\pgn
+
+\ifpdf
+\def\pdfmkdest#1{\pdfdest name{#1@} xyz}
+\def\pdfmkpgn#1{#1@}
+
+% Adding outlines to PDF; macros for calculating structure of outlines
+% come from Petr Olsak
+\def\expnumber#1{\expandafter\ifx\csname#1\endcsname\relax 0%
+ \else \csname#1\endcsname \fi}
+\def\advancenumber#1{\tempnum=\expnumber{#1}\relax
+ \advance\tempnum by1
+ \expandafter\xdef\csname#1\endcsname{\the\tempnum}}
+\def\pdfmakeoutlines{{%
+ \openin 1 \jobname.toc
+ \ifeof 1\else\bgroup
+ \closein 1
+ \def\code##1{##1}
+ \def\file##1{##1}
+ \def\TeX##1{TeX}
+ \def\tt{}
+ \def\char{char}
+ \def\samp##1{##1}
+ \def\kbd##1{##1}
+ \def\key##1{##1}
+ \def\rawbackslashxx{\string\\}
+ \def\chapentry ##1##2##3{}
+ \def\unnumbchapentry ##1##2{}
+ \def\secentry ##1##2##3##4{\advancenumber{chap##2}}
+ \def\unnumbsecentry ##1##2{}
+ \def\subsecentry ##1##2##3##4##5{\advancenumber{sec##2.##3}}
+ \def\unnumbsubsecentry ##1##2{}
+ \def\subsubsecentry ##1##2##3##4##5##6{\advancenumber{subsec##2.##3.##4}}
+ \def\unnumbsubsubsecentry ##1##2{}
+ \input \jobname.toc
+ \def\chapentry ##1##2##3{%
+ \pdfoutline goto name{\pdfmkpgn{##3}}count-\expnumber{chap##2}{##1}}
+ \def\unnumbchapentry ##1##2{%
+ \pdfoutline goto name{\pdfmkpgn{##2}}{##1}}
+ \def\secentry ##1##2##3##4{%
+ \pdfoutline goto name{\pdfmkpgn{##4}}count-\expnumber{sec##2.##3}{##1}}
+ \def\unnumbsecentry ##1##2{%
+ \pdfoutline goto name{\pdfmkpgn{##2}}{##1}}
+ \def\subsecentry ##1##2##3##4##5{%
+ \pdfoutline goto name{\pdfmkpgn{##5}}count-\expnumber{subsec##2.##3.##4}{##1}}
+ \def\unnumbsubsecentry ##1##2{%
+ \pdfoutline goto name{\pdfmkpgn{##2}}{##1}}
+ \def\subsubsecentry ##1##2##3##4##5##6{%
+ \pdfoutline goto name{\pdfmkpgn{##6}}{##1}}
+ \def\unnumbsubsubsecentry ##1##2{%
+ \pdfoutline goto name{\pdfmkpgn{##2}}{##1}}
+ \input \jobname.toc
+ \egroup\fi
+}}
+\pdfmakeoutlines
+
+\def\makelinks #1,{%
+ \def\params{#1}\def\E{END}%
+ \ifx\params\E
+ \let\nextmakelinks=\relax
+ \else
+ \let\nextmakelinks=\makelinks
+ \ifnum\lnkcount>0,\fi
+ \picknum{#1}%
+ \Blue\pdfannotlink attr{/Border [0 0 0]}
+ goto name{\pdfmkpgn{\the\pgn}}%
+ #1%
+ \advance\lnkcount by 1%
+ \Black\pdfendlink
+ \fi
+ \nextmakelinks
+}
+
+\def\picknum#1{\expandafter\pn#1}
+\def\pn#1{%
+ \def\p{#1}%
+ \ifx\p\lbrace
+ \let\nextpn=\ppn
+ \else
+ \let\nextpn=\ppnn
+ \def\first{#1}
+ \fi
+ \nextpn
+}
+\def\ppn#1{\pgn=#1\gobble}
+\def\ppnn{\pgn=\first}
+\def\pdfmklnk#1{\lnkcount=0\makelinks #1,END,}
+
+\def\addtokens#1#2{\edef\addtoks{\noexpand#1={\the#1#2}}\addtoks}
+\def\skipspaces#1{\def\PP{#1}\def\D{|}%
+ \ifx\PP\D\let\nextsp\relax
+ \else\let\nextsp\skipspaces
+ \ifx\p\space\else\addtokens{\filename}{\PP}%
+ \advance\filenamelength by 1
+ \fi
+ \fi
+ \nextsp}
+\def\getfilename#1{\filenamelength=0\expandafter\skipspaces#1|\relax}
+
+\def\pdflink#1{%
+ \leavevmode\Red
+ \begingroup
+ \normalturnoffactive\def\@{@}%
+ \pdfannotlink
+ attr{/Border [0 0 0]}%
+ user{/Subtype /Link /A << /S /URI /URI (#1) >>}%
+ \endgroup
+}
+
+\else
+\let\pdflink = \gobble
+\fi % end \ifpdf
+
+\message{fonts,}
+% Font-change commands.
+
+% Texinfo sort of supports the sans serif font style, which plain TeX does not.
+% So we set up a \sf analogous to plain's \rm, etc.
+\newfam\sffam
+\def\sf{\fam=\sffam \tensf}
+\let\li = \sf % Sometimes we call it \li, not \sf.
+
+% We don't need math for this one.
+\def\ttsl{\tenttsl}
+
+% Use Computer Modern fonts at \magstephalf (11pt).
+\newcount\mainmagstep
+\mainmagstep=\magstephalf
+
+% Set the font macro #1 to the font named #2, adding on the
+% specified font prefix (normally `cm').
+% #3 is the font's design size, #4 is a scale factor
+\def\setfont#1#2#3#4{\font#1=\fontprefix#2#3 scaled #4}
+
+% Use cm as the default font prefix.
+% To specify the font prefix, you must define \fontprefix
+% before you read in texinfo.tex.
+\ifx\fontprefix\undefined
+\def\fontprefix{cm}
+\fi
+% Support font families that don't use the same naming scheme as CM.
+\def\rmshape{r}
+\def\rmbshape{bx} %where the normal face is bold
+\def\bfshape{b}
+\def\bxshape{bx}
+\def\ttshape{tt}
+\def\ttbshape{tt}
+\def\ttslshape{sltt}
+\def\itshape{ti}
+\def\itbshape{bxti}
+\def\slshape{sl}
+\def\slbshape{bxsl}
+\def\sfshape{ss}
+\def\sfbshape{ss}
+\def\scshape{csc}
+\def\scbshape{csc}
+
+\ifx\bigger\relax
+\let\mainmagstep=\magstep1
+\setfont\textrm\rmshape{12}{1000}
+\setfont\texttt\ttshape{12}{1000}
+\else
+\setfont\textrm\rmshape{10}{\mainmagstep}
+\setfont\texttt\ttshape{10}{\mainmagstep}
+\fi
+% Instead of cmb10, you many want to use cmbx10.
+% cmbx10 is a prettier font on its own, but cmb10
+% looks better when embedded in a line with cmr10.
+\setfont\textbf\bfshape{10}{\mainmagstep}
+\setfont\textit\itshape{10}{\mainmagstep}
+\setfont\textsl\slshape{10}{\mainmagstep}
+\setfont\textsf\sfshape{10}{\mainmagstep}
+\setfont\textsc\scshape{10}{\mainmagstep}
+\setfont\textttsl\ttslshape{10}{\mainmagstep}
+\font\texti=cmmi10 scaled \mainmagstep
+\font\textsy=cmsy10 scaled \mainmagstep
+
+% A few fonts for @defun, etc.
+\setfont\defbf\bxshape{10}{\magstep1} %was 1314
+\setfont\deftt\ttshape{10}{\magstep1}
+\def\df{\let\tentt=\deftt \let\tenbf = \defbf \bf}
+
+% Fonts for indices and small examples (9pt).
+% We actually use the slanted font rather than the italic,
+% because texinfo normally uses the slanted fonts for that.
+% Do not make many font distinctions in general in the index, since they
+% aren't very useful.
+\setfont\ninett\ttshape{9}{1000}
+\setfont\ninettsl\ttslshape{10}{900}
+\setfont\indrm\rmshape{9}{1000}
+\setfont\indit\itshape{9}{1000}
+\setfont\indsl\slshape{9}{1000}
+\let\indtt=\ninett
+\let\indttsl=\ninettsl
+\let\indsf=\indrm
+\let\indbf=\indrm
+\setfont\indsc\scshape{10}{900}
+\font\indi=cmmi9
+\font\indsy=cmsy9
+
+% Fonts for title page:
+\setfont\titlerm\rmbshape{12}{\magstep3}
+\setfont\titleit\itbshape{10}{\magstep4}
+\setfont\titlesl\slbshape{10}{\magstep4}
+\setfont\titlett\ttbshape{12}{\magstep3}
+\setfont\titlettsl\ttslshape{10}{\magstep4}
+\setfont\titlesf\sfbshape{17}{\magstep1}
+\let\titlebf=\titlerm
+\setfont\titlesc\scbshape{10}{\magstep4}
+\font\titlei=cmmi12 scaled \magstep3
+\font\titlesy=cmsy10 scaled \magstep4
+\def\authorrm{\secrm}
+
+% Chapter (and unnumbered) fonts (17.28pt).
+\setfont\chaprm\rmbshape{12}{\magstep2}
+\setfont\chapit\itbshape{10}{\magstep3}
+\setfont\chapsl\slbshape{10}{\magstep3}
+\setfont\chaptt\ttbshape{12}{\magstep2}
+\setfont\chapttsl\ttslshape{10}{\magstep3}
+\setfont\chapsf\sfbshape{17}{1000}
+\let\chapbf=\chaprm
+\setfont\chapsc\scbshape{10}{\magstep3}
+\font\chapi=cmmi12 scaled \magstep2
+\font\chapsy=cmsy10 scaled \magstep3
+
+% Section fonts (14.4pt).
+\setfont\secrm\rmbshape{12}{\magstep1}
+\setfont\secit\itbshape{10}{\magstep2}
+\setfont\secsl\slbshape{10}{\magstep2}
+\setfont\sectt\ttbshape{12}{\magstep1}
+\setfont\secttsl\ttslshape{10}{\magstep2}
+\setfont\secsf\sfbshape{12}{\magstep1}
+\let\secbf\secrm
+\setfont\secsc\scbshape{10}{\magstep2}
+\font\seci=cmmi12 scaled \magstep1
+\font\secsy=cmsy10 scaled \magstep2
+
+% \setfont\ssecrm\bxshape{10}{\magstep1} % This size an font looked bad.
+% \setfont\ssecit\itshape{10}{\magstep1} % The letters were too crowded.
+% \setfont\ssecsl\slshape{10}{\magstep1}
+% \setfont\ssectt\ttshape{10}{\magstep1}
+% \setfont\ssecsf\sfshape{10}{\magstep1}
+
+%\setfont\ssecrm\bfshape{10}{1315} % Note the use of cmb rather than cmbx.
+%\setfont\ssecit\itshape{10}{1315} % Also, the size is a little larger than
+%\setfont\ssecsl\slshape{10}{1315} % being scaled magstep1.
+%\setfont\ssectt\ttshape{10}{1315}
+%\setfont\ssecsf\sfshape{10}{1315}
+
+%\let\ssecbf=\ssecrm
+
+% Subsection fonts (13.15pt).
+\setfont\ssecrm\rmbshape{12}{\magstephalf}
+\setfont\ssecit\itbshape{10}{1315}
+\setfont\ssecsl\slbshape{10}{1315}
+\setfont\ssectt\ttbshape{12}{\magstephalf}
+\setfont\ssecttsl\ttslshape{10}{1315}
+\setfont\ssecsf\sfbshape{12}{\magstephalf}
+\let\ssecbf\ssecrm
+\setfont\ssecsc\scbshape{10}{\magstep1}
+\font\sseci=cmmi12 scaled \magstephalf
+\font\ssecsy=cmsy10 scaled 1315
+% The smallcaps and symbol fonts should actually be scaled \magstep1.5,
+% but that is not a standard magnification.
+
+% In order for the font changes to affect most math symbols and letters,
+% we have to define the \textfont of the standard families. Since
+% texinfo doesn't allow for producing subscripts and superscripts, we
+% don't bother to reset \scriptfont and \scriptscriptfont (which would
+% also require loading a lot more fonts).
+%
+\def\resetmathfonts{%
+ \textfont0 = \tenrm \textfont1 = \teni \textfont2 = \tensy
+ \textfont\itfam = \tenit \textfont\slfam = \tensl \textfont\bffam = \tenbf
+ \textfont\ttfam = \tentt \textfont\sffam = \tensf
+}
+
+
+% The font-changing commands redefine the meanings of \tenSTYLE, instead
+% of just \STYLE. We do this so that font changes will continue to work
+% in math mode, where it is the current \fam that is relevant in most
+% cases, not the current font. Plain TeX does \def\bf{\fam=\bffam
+% \tenbf}, for example. By redefining \tenbf, we obviate the need to
+% redefine \bf itself.
+\def\textfonts{%
+ \let\tenrm=\textrm \let\tenit=\textit \let\tensl=\textsl
+ \let\tenbf=\textbf \let\tentt=\texttt \let\smallcaps=\textsc
+ \let\tensf=\textsf \let\teni=\texti \let\tensy=\textsy \let\tenttsl=\textttsl
+ \resetmathfonts}
+\def\titlefonts{%
+ \let\tenrm=\titlerm \let\tenit=\titleit \let\tensl=\titlesl
+ \let\tenbf=\titlebf \let\tentt=\titlett \let\smallcaps=\titlesc
+ \let\tensf=\titlesf \let\teni=\titlei \let\tensy=\titlesy
+ \let\tenttsl=\titlettsl
+ \resetmathfonts \setleading{25pt}}
+\def\titlefont#1{{\titlefonts\rm #1}}
+\def\chapfonts{%
+ \let\tenrm=\chaprm \let\tenit=\chapit \let\tensl=\chapsl
+ \let\tenbf=\chapbf \let\tentt=\chaptt \let\smallcaps=\chapsc
+ \let\tensf=\chapsf \let\teni=\chapi \let\tensy=\chapsy \let\tenttsl=\chapttsl
+ \resetmathfonts \setleading{19pt}}
+\def\secfonts{%
+ \let\tenrm=\secrm \let\tenit=\secit \let\tensl=\secsl
+ \let\tenbf=\secbf \let\tentt=\sectt \let\smallcaps=\secsc
+ \let\tensf=\secsf \let\teni=\seci \let\tensy=\secsy \let\tenttsl=\secttsl
+ \resetmathfonts \setleading{16pt}}
+\def\subsecfonts{%
+ \let\tenrm=\ssecrm \let\tenit=\ssecit \let\tensl=\ssecsl
+ \let\tenbf=\ssecbf \let\tentt=\ssectt \let\smallcaps=\ssecsc
+ \let\tensf=\ssecsf \let\teni=\sseci \let\tensy=\ssecsy \let\tenttsl=\ssecttsl
+ \resetmathfonts \setleading{15pt}}
+\let\subsubsecfonts = \subsecfonts % Maybe make sssec fonts scaled magstephalf?
+\def\indexfonts{%
+ \let\tenrm=\indrm \let\tenit=\indit \let\tensl=\indsl
+ \let\tenbf=\indbf \let\tentt=\indtt \let\smallcaps=\indsc
+ \let\tensf=\indsf \let\teni=\indi \let\tensy=\indsy \let\tenttsl=\indttsl
+ \resetmathfonts \setleading{12pt}}
+
+% Set up the default fonts, so we can use them for creating boxes.
+%
+\textfonts
+
+% Define these so they can be easily changed for other fonts.
+\def\angleleft{$\langle$}
+\def\angleright{$\rangle$}
+
+% Count depth in font-changes, for error checks
+\newcount\fontdepth \fontdepth=0
+
+% Fonts for short table of contents.
+\setfont\shortcontrm\rmshape{12}{1000}
+\setfont\shortcontbf\bxshape{12}{1000}
+\setfont\shortcontsl\slshape{12}{1000}
+
+%% Add scribe-like font environments, plus @l for inline lisp (usually sans
+%% serif) and @ii for TeX italic
+
+% \smartitalic{ARG} outputs arg in italics, followed by an italic correction
+% unless the following character is such as not to need one.
+\def\smartitalicx{\ifx\next,\else\ifx\next-\else\ifx\next.\else\/\fi\fi\fi}
+\def\smartslanted#1{{\sl #1}\futurelet\next\smartitalicx}
+\def\smartitalic#1{{\it #1}\futurelet\next\smartitalicx}
+
+\let\i=\smartitalic
+\let\var=\smartslanted
+\let\dfn=\smartslanted
+\let\emph=\smartitalic
+\let\cite=\smartslanted
+
+\def\b#1{{\bf #1}}
+\let\strong=\b
+
+% We can't just use \exhyphenpenalty, because that only has effect at
+% the end of a paragraph. Restore normal hyphenation at the end of the
+% group within which \nohyphenation is presumably called.
+%
+\def\nohyphenation{\hyphenchar\font = -1 \aftergroup\restorehyphenation}
+\def\restorehyphenation{\hyphenchar\font = `- }
+
+\def\t#1{%
+ {\tt \rawbackslash \frenchspacing #1}%
+ \null
+}
+\let\ttfont=\t
+\def\samp#1{`\tclose{#1}'\null}
+\setfont\smallrm\rmshape{8}{1000}
+\font\smallsy=cmsy9
+\def\key#1{{\smallrm\textfont2=\smallsy \leavevmode\hbox{%
+ \raise0.4pt\hbox{\angleleft}\kern-.08em\vtop{%
+ \vbox{\hrule\kern-0.4pt
+ \hbox{\raise0.4pt\hbox{\vphantom{\angleleft}}#1}}%
+ \kern-0.4pt\hrule}%
+ \kern-.06em\raise0.4pt\hbox{\angleright}}}}
+% The old definition, with no lozenge:
+%\def\key #1{{\ttsl \nohyphenation \uppercase{#1}}\null}
+\def\ctrl #1{{\tt \rawbackslash \hat}#1}
+
+% @file, @option are the same as @samp.
+\let\file=\samp
+\let\option=\samp
+
+% @code is a modification of @t,
+% which makes spaces the same size as normal in the surrounding text.
+\def\tclose#1{%
+ {%
+ % Change normal interword space to be same as for the current font.
+ \spaceskip = \fontdimen2\font
+ %
+ % Switch to typewriter.
+ \tt
+ %
+ % But `\ ' produces the large typewriter interword space.
+ \def\ {{\spaceskip = 0pt{} }}%
+ %
+ % Turn off hyphenation.
+ \nohyphenation
+ %
+ \rawbackslash
+ \frenchspacing
+ #1%
+ }%
+ \null
+}
+
+% We *must* turn on hyphenation at `-' and `_' in \code.
+% Otherwise, it is too hard to avoid overfull hboxes
+% in the Emacs manual, the Library manual, etc.
+
+% Unfortunately, TeX uses one parameter (\hyphenchar) to control
+% both hyphenation at - and hyphenation within words.
+% We must therefore turn them both off (\tclose does that)
+% and arrange explicitly to hyphenate at a dash.
+% -- rms.
+{
+ \catcode`\-=\active
+ \catcode`\_=\active
+ %
+ \global\def\code{\begingroup
+ \catcode`\-=\active \let-\codedash
+ \catcode`\_=\active \let_\codeunder
+ \codex
+ }
+ %
+ % If we end up with any active - characters when handling the index,
+ % just treat them as a normal -.
+ \global\def\indexbreaks{\catcode`\-=\active \let-\realdash}
+}
+
+\def\realdash{-}
+\def\codedash{-\discretionary{}{}{}}
+\def\codeunder{\ifusingtt{\normalunderscore\discretionary{}{}{}}{\_}}
+\def\codex #1{\tclose{#1}\endgroup}
+
+%\let\exp=\tclose %Was temporary
+
+% @kbd is like @code, except that if the argument is just one @key command,
+% then @kbd has no effect.
+
+% @kbdinputstyle -- arg is `distinct' (@kbd uses slanted tty font always),
+% `example' (@kbd uses ttsl only inside of @example and friends),
+% or `code' (@kbd uses normal tty font always).
+\def\kbdinputstyle{\parsearg\kbdinputstylexxx}
+\def\kbdinputstylexxx#1{%
+ \def\arg{#1}%
+ \ifx\arg\worddistinct
+ \gdef\kbdexamplefont{\ttsl}\gdef\kbdfont{\ttsl}%
+ \else\ifx\arg\wordexample
+ \gdef\kbdexamplefont{\ttsl}\gdef\kbdfont{\tt}%
+ \else\ifx\arg\wordcode
+ \gdef\kbdexamplefont{\tt}\gdef\kbdfont{\tt}%
+ \fi\fi\fi
+}
+\def\worddistinct{distinct}
+\def\wordexample{example}
+\def\wordcode{code}
+
+% Default is kbdinputdistinct. (Too much of a hassle to call the macro,
+% the catcodes are wrong for parsearg to work.)
+\gdef\kbdexamplefont{\ttsl}\gdef\kbdfont{\ttsl}
+
+\def\xkey{\key}
+\def\kbdfoo#1#2#3\par{\def\one{#1}\def\three{#3}\def\threex{??}%
+\ifx\one\xkey\ifx\threex\three \key{#2}%
+\else{\tclose{\kbdfont\look}}\fi
+\else{\tclose{\kbdfont\look}}\fi}
+
+% For @url, @env, @command quotes seem unnecessary, so use \code.
+\let\url=\code
+\let\env=\code
+\let\command=\code
+
+% @uref (abbreviation for `urlref') takes an optional (comma-separated)
+% second argument specifying the text to display and an optional third
+% arg as text to display instead of (rather than in addition to) the url
+% itself. First (mandatory) arg is the url. Perhaps eventually put in
+% a hypertex \special here.
+%
+\def\uref#1{\douref #1,,,\finish}
+\def\douref#1,#2,#3,#4\finish{%
+ \pdflink{#1}%
+ \setbox0 = \hbox{\ignorespaces #3}%
+ \ifdim\wd0 > 0pt
+ \unhbox0 % third arg given, show only that
+ \else
+ \setbox0 = \hbox{\ignorespaces #2}%
+ \ifdim\wd0 > 0pt
+ \ifpdf
+ \unhbox0 % PDF: 2nd arg given, show only it
+ \else
+ \unhbox0\ (\code{#1})% DVI: 2nd arg given, show both it and url
+ \fi
+ \else
+ \code{#1}% only url given, so show it
+ \fi
+ \fi
+ %
+ \ifpdf
+ \Black\pdfendlink
+ \fi
+}
+
+% rms does not like angle brackets --karl, 17may97.
+% So now @email is just like @uref, unless we are pdf.
+%
+%\def\email#1{\angleleft{\tt #1}\angleright}
+\ifpdf
+ \def\email#1{\doemail#1,,\finish}
+ \def\doemail#1,#2,#3\finish{%
+ \pdflink{mailto:#1}%
+ \setbox0 = \hbox{\ignorespaces #2}%
+ \ifdim\wd0>0pt\unhbox0\else\code{#1}\fi
+ \Black\pdfendlink
+ }
+\else
+ \let\email=\uref
+\fi
+
+% Check if we are currently using a typewriter font. Since all the
+% Computer Modern typewriter fonts have zero interword stretch (and
+% shrink), and it is reasonable to expect all typewriter fonts to have
+% this property, we can check that font parameter.
+%
+\def\ifmonospace{\ifdim\fontdimen3\font=0pt }
+
+% Typeset a dimension, e.g., `in' or `pt'. The only reason for the
+% argument is to make the input look right: @dmn{pt} instead of @dmn{}pt.
+%
+\def\dmn#1{\thinspace #1}
+
+\def\kbd#1{\def\look{#1}\expandafter\kbdfoo\look??\par}
+
+% @l was never documented to mean ``switch to the Lisp font'',
+% and it is not used as such in any manual I can find. We need it for
+% Polish suppressed-l. --karl, 22sep96.
+%\def\l#1{{\li #1}\null}
+
+% Explicit font changes: @r, @sc, undocumented @ii.
+\def\r#1{{\rm #1}} % roman font
+\def\sc#1{{\smallcaps#1}} % smallcaps font
+\def\ii#1{{\it #1}} % italic font
+
+% @acronym downcases the argument and prints in smallcaps.
+\def\acronym#1{{\smallcaps \lowercase{#1}}}
+
+% @pounds{} is a sterling sign.
+\def\pounds{{\it\$}}
+
+
+\message{page headings,}
+
+\newskip\titlepagetopglue \titlepagetopglue = 1.5in
+\newskip\titlepagebottomglue \titlepagebottomglue = 2pc
+
+% First the title page. Must do @settitle before @titlepage.
+\newif\ifseenauthor
+\newif\iffinishedtitlepage
+
+% Do an implicit @contents or @shortcontents after @end titlepage if the
+% user says @setcontentsaftertitlepage or @setshortcontentsaftertitlepage.
+%
+\newif\ifsetcontentsaftertitlepage
+ \let\setcontentsaftertitlepage = \setcontentsaftertitlepagetrue
+\newif\ifsetshortcontentsaftertitlepage
+ \let\setshortcontentsaftertitlepage = \setshortcontentsaftertitlepagetrue
+
+\def\shorttitlepage{\parsearg\shorttitlepagezzz}
+\def\shorttitlepagezzz #1{\begingroup\hbox{}\vskip 1.5in \chaprm \centerline{#1}%
+ \endgroup\page\hbox{}\page}
+
+\def\titlepage{\begingroup \parindent=0pt \textfonts
+ \let\subtitlerm=\tenrm
+ \def\subtitlefont{\subtitlerm \normalbaselineskip = 13pt \normalbaselines}%
+ %
+ \def\authorfont{\authorrm \normalbaselineskip = 16pt \normalbaselines}%
+ %
+ % Leave some space at the very top of the page.
+ \vglue\titlepagetopglue
+ %
+ % Now you can print the title using @title.
+ \def\title{\parsearg\titlezzz}%
+ \def\titlezzz##1{\leftline{\titlefonts\rm ##1}
+ % print a rule at the page bottom also.
+ \finishedtitlepagefalse
+ \vskip4pt \hrule height 4pt width \hsize \vskip4pt}%
+ % No rule at page bottom unless we print one at the top with @title.
+ \finishedtitlepagetrue
+ %
+ % Now you can put text using @subtitle.
+ \def\subtitle{\parsearg\subtitlezzz}%
+ \def\subtitlezzz##1{{\subtitlefont \rightline{##1}}}%
+ %
+ % @author should come last, but may come many times.
+ \def\author{\parsearg\authorzzz}%
+ \def\authorzzz##1{\ifseenauthor\else\vskip 0pt plus 1filll\seenauthortrue\fi
+ {\authorfont \leftline{##1}}}%
+ %
+ % Most title ``pages'' are actually two pages long, with space
+ % at the top of the second. We don't want the ragged left on the second.
+ \let\oldpage = \page
+ \def\page{%
+ \iffinishedtitlepage\else
+ \finishtitlepage
+ \fi
+ \oldpage
+ \let\page = \oldpage
+ \hbox{}}%
+% \def\page{\oldpage \hbox{}}
+}
+
+\def\Etitlepage{%
+ \iffinishedtitlepage\else
+ \finishtitlepage
+ \fi
+ % It is important to do the page break before ending the group,
+ % because the headline and footline are only empty inside the group.
+ % If we use the new definition of \page, we always get a blank page
+ % after the title page, which we certainly don't want.
+ \oldpage
+ \endgroup
+ %
+ % If they want short, they certainly want long too.
+ \ifsetshortcontentsaftertitlepage
+ \shortcontents
+ \contents
+ \global\let\shortcontents = \relax
+ \global\let\contents = \relax
+ \fi
+ %
+ \ifsetcontentsaftertitlepage
+ \contents
+ \global\let\contents = \relax
+ \global\let\shortcontents = \relax
+ \fi
+ %
+ \HEADINGSon
+}
+
+\def\finishtitlepage{%
+ \vskip4pt \hrule height 2pt width \hsize
+ \vskip\titlepagebottomglue
+ \finishedtitlepagetrue
+}
+
+%%% Set up page headings and footings.
+
+\let\thispage=\folio
+
+\newtoks\evenheadline % headline on even pages
+\newtoks\oddheadline % headline on odd pages
+\newtoks\evenfootline % footline on even pages
+\newtoks\oddfootline % footline on odd pages
+
+% Now make Tex use those variables
+\headline={{\textfonts\rm \ifodd\pageno \the\oddheadline
+ \else \the\evenheadline \fi}}
+\footline={{\textfonts\rm \ifodd\pageno \the\oddfootline
+ \else \the\evenfootline \fi}\HEADINGShook}
+\let\HEADINGShook=\relax
+
+% Commands to set those variables.
+% For example, this is what @headings on does
+% @evenheading @thistitle|@thispage|@thischapter
+% @oddheading @thischapter|@thispage|@thistitle
+% @evenfooting @thisfile||
+% @oddfooting ||@thisfile
+
+\def\evenheading{\parsearg\evenheadingxxx}
+\def\oddheading{\parsearg\oddheadingxxx}
+\def\everyheading{\parsearg\everyheadingxxx}
+
+\def\evenfooting{\parsearg\evenfootingxxx}
+\def\oddfooting{\parsearg\oddfootingxxx}
+\def\everyfooting{\parsearg\everyfootingxxx}
+
+{\catcode`\@=0 %
+
+\gdef\evenheadingxxx #1{\evenheadingyyy #1@|@|@|@|\finish}
+\gdef\evenheadingyyy #1@|#2@|#3@|#4\finish{%
+\global\evenheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}}
+
+\gdef\oddheadingxxx #1{\oddheadingyyy #1@|@|@|@|\finish}
+\gdef\oddheadingyyy #1@|#2@|#3@|#4\finish{%
+\global\oddheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}}
+
+\gdef\everyheadingxxx#1{\oddheadingxxx{#1}\evenheadingxxx{#1}}%
+
+\gdef\evenfootingxxx #1{\evenfootingyyy #1@|@|@|@|\finish}
+\gdef\evenfootingyyy #1@|#2@|#3@|#4\finish{%
+\global\evenfootline={\rlap{\centerline{#2}}\line{#1\hfil#3}}}
+
+\gdef\oddfootingxxx #1{\oddfootingyyy #1@|@|@|@|\finish}
+\gdef\oddfootingyyy #1@|#2@|#3@|#4\finish{%
+ \global\oddfootline = {\rlap{\centerline{#2}}\line{#1\hfil#3}}%
+ %
+ % Leave some space for the footline. Hopefully ok to assume
+ % @evenfooting will not be used by itself.
+ \global\advance\pageheight by -\baselineskip
+ \global\advance\vsize by -\baselineskip
+}
+
+\gdef\everyfootingxxx#1{\oddfootingxxx{#1}\evenfootingxxx{#1}}
+%
+}% unbind the catcode of @.
+
+% @headings double turns headings on for double-sided printing.
+% @headings single turns headings on for single-sided printing.
+% @headings off turns them off.
+% @headings on same as @headings double, retained for compatibility.
+% @headings after turns on double-sided headings after this page.
+% @headings doubleafter turns on double-sided headings after this page.
+% @headings singleafter turns on single-sided headings after this page.
+% By default, they are off at the start of a document,
+% and turned `on' after @end titlepage.
+
+\def\headings #1 {\csname HEADINGS#1\endcsname}
+
+\def\HEADINGSoff{
+\global\evenheadline={\hfil} \global\evenfootline={\hfil}
+\global\oddheadline={\hfil} \global\oddfootline={\hfil}}
+\HEADINGSoff
+% When we turn headings on, set the page number to 1.
+% For double-sided printing, put current file name in lower left corner,
+% chapter name on inside top of right hand pages, document
+% title on inside top of left hand pages, and page numbers on outside top
+% edge of all pages.
+\def\HEADINGSdouble{
+\global\pageno=1
+\global\evenfootline={\hfil}
+\global\oddfootline={\hfil}
+\global\evenheadline={\line{\folio\hfil\thistitle}}
+\global\oddheadline={\line{\thischapter\hfil\folio}}
+\global\let\contentsalignmacro = \chapoddpage
+}
+\let\contentsalignmacro = \chappager
+
+% For single-sided printing, chapter title goes across top left of page,
+% page number on top right.
+\def\HEADINGSsingle{
+\global\pageno=1
+\global\evenfootline={\hfil}
+\global\oddfootline={\hfil}
+\global\evenheadline={\line{\thischapter\hfil\folio}}
+\global\oddheadline={\line{\thischapter\hfil\folio}}
+\global\let\contentsalignmacro = \chappager
+}
+\def\HEADINGSon{\HEADINGSdouble}
+
+\def\HEADINGSafter{\let\HEADINGShook=\HEADINGSdoublex}
+\let\HEADINGSdoubleafter=\HEADINGSafter
+\def\HEADINGSdoublex{%
+\global\evenfootline={\hfil}
+\global\oddfootline={\hfil}
+\global\evenheadline={\line{\folio\hfil\thistitle}}
+\global\oddheadline={\line{\thischapter\hfil\folio}}
+\global\let\contentsalignmacro = \chapoddpage
+}
+
+\def\HEADINGSsingleafter{\let\HEADINGShook=\HEADINGSsinglex}
+\def\HEADINGSsinglex{%
+\global\evenfootline={\hfil}
+\global\oddfootline={\hfil}
+\global\evenheadline={\line{\thischapter\hfil\folio}}
+\global\oddheadline={\line{\thischapter\hfil\folio}}
+\global\let\contentsalignmacro = \chappager
+}
+
+% Subroutines used in generating headings
+% Produces Day Month Year style of output.
+\def\today{%
+ \number\day\space
+ \ifcase\month
+ \or\putwordMJan\or\putwordMFeb\or\putwordMMar\or\putwordMApr
+ \or\putwordMMay\or\putwordMJun\or\putwordMJul\or\putwordMAug
+ \or\putwordMSep\or\putwordMOct\or\putwordMNov\or\putwordMDec
+ \fi
+ \space\number\year}
+
+% @settitle line... specifies the title of the document, for headings.
+% It generates no output of its own.
+\def\thistitle{\putwordNoTitle}
+\def\settitle{\parsearg\settitlezzz}
+\def\settitlezzz #1{\gdef\thistitle{#1}}
+
+
+\message{tables,}
+% Tables -- @table, @ftable, @vtable, @item(x), @kitem(x), @xitem(x).
+
+% default indentation of table text
+\newdimen\tableindent \tableindent=.8in
+% default indentation of @itemize and @enumerate text
+\newdimen\itemindent \itemindent=.3in
+% margin between end of table item and start of table text.
+\newdimen\itemmargin \itemmargin=.1in
+
+% used internally for \itemindent minus \itemmargin
+\newdimen\itemmax
+
+% Note @table, @vtable, and @vtable define @item, @itemx, etc., with
+% these defs.
+% They also define \itemindex
+% to index the item name in whatever manner is desired (perhaps none).
+
+\newif\ifitemxneedsnegativevskip
+
+\def\itemxpar{\par\ifitemxneedsnegativevskip\nobreak\vskip-\parskip\nobreak\fi}
+
+\def\internalBitem{\smallbreak \parsearg\itemzzz}
+\def\internalBitemx{\itemxpar \parsearg\itemzzz}
+
+\def\internalBxitem "#1"{\def\xitemsubtopix{#1} \smallbreak \parsearg\xitemzzz}
+\def\internalBxitemx "#1"{\def\xitemsubtopix{#1} \itemxpar \parsearg\xitemzzz}
+
+\def\internalBkitem{\smallbreak \parsearg\kitemzzz}
+\def\internalBkitemx{\itemxpar \parsearg\kitemzzz}
+
+\def\kitemzzz #1{\dosubind {kw}{\code{#1}}{for {\bf \lastfunction}}%
+ \itemzzz {#1}}
+
+\def\xitemzzz #1{\dosubind {kw}{\code{#1}}{for {\bf \xitemsubtopic}}%
+ \itemzzz {#1}}
+
+\def\itemzzz #1{\begingroup %
+ \advance\hsize by -\rightskip
+ \advance\hsize by -\tableindent
+ \setbox0=\hbox{\itemfont{#1}}%
+ \itemindex{#1}%
+ \nobreak % This prevents a break before @itemx.
+ %
+ % If the item text does not fit in the space we have, put it on a line
+ % by itself, and do not allow a page break either before or after that
+ % line. We do not start a paragraph here because then if the next
+ % command is, e.g., @kindex, the whatsit would get put into the
+ % horizontal list on a line by itself, resulting in extra blank space.
+ \ifdim \wd0>\itemmax
+ %
+ % Make this a paragraph so we get the \parskip glue and wrapping,
+ % but leave it ragged-right.
+ \begingroup
+ \advance\leftskip by-\tableindent
+ \advance\hsize by\tableindent
+ \advance\rightskip by0pt plus1fil
+ \leavevmode\unhbox0\par
+ \endgroup
+ %
+ % We're going to be starting a paragraph, but we don't want the
+ % \parskip glue -- logically it's part of the @item we just started.
+ \nobreak \vskip-\parskip
+ %
+ % Stop a page break at the \parskip glue coming up. Unfortunately
+ % we can't prevent a possible page break at the following
+ % \baselineskip glue.
+ \nobreak
+ \endgroup
+ \itemxneedsnegativevskipfalse
+ \else
+ % The item text fits into the space. Start a paragraph, so that the
+ % following text (if any) will end up on the same line.
+ \noindent
+ % Do this with kerns and \unhbox so that if there is a footnote in
+ % the item text, it can migrate to the main vertical list and
+ % eventually be printed.
+ \nobreak\kern-\tableindent
+ \dimen0 = \itemmax \advance\dimen0 by \itemmargin \advance\dimen0 by -\wd0
+ \unhbox0
+ \nobreak\kern\dimen0
+ \endgroup
+ \itemxneedsnegativevskiptrue
+ \fi
+}
+
+\def\item{\errmessage{@item while not in a table}}
+\def\itemx{\errmessage{@itemx while not in a table}}
+\def\kitem{\errmessage{@kitem while not in a table}}
+\def\kitemx{\errmessage{@kitemx while not in a table}}
+\def\xitem{\errmessage{@xitem while not in a table}}
+\def\xitemx{\errmessage{@xitemx while not in a table}}
+
+% Contains a kludge to get @end[description] to work.
+\def\description{\tablez{\dontindex}{1}{}{}{}{}}
+
+% @table, @ftable, @vtable.
+\def\table{\begingroup\inENV\obeylines\obeyspaces\tablex}
+{\obeylines\obeyspaces%
+\gdef\tablex #1^^M{%
+\tabley\dontindex#1 \endtabley}}
+
+\def\ftable{\begingroup\inENV\obeylines\obeyspaces\ftablex}
+{\obeylines\obeyspaces%
+\gdef\ftablex #1^^M{%
+\tabley\fnitemindex#1 \endtabley
+\def\Eftable{\endgraf\afterenvbreak\endgroup}%
+\let\Etable=\relax}}
+
+\def\vtable{\begingroup\inENV\obeylines\obeyspaces\vtablex}
+{\obeylines\obeyspaces%
+\gdef\vtablex #1^^M{%
+\tabley\vritemindex#1 \endtabley
+\def\Evtable{\endgraf\afterenvbreak\endgroup}%
+\let\Etable=\relax}}
+
+\def\dontindex #1{}
+\def\fnitemindex #1{\doind {fn}{\code{#1}}}%
+\def\vritemindex #1{\doind {vr}{\code{#1}}}%
+
+{\obeyspaces %
+\gdef\tabley#1#2 #3 #4 #5 #6 #7\endtabley{\endgroup%
+\tablez{#1}{#2}{#3}{#4}{#5}{#6}}}
+
+\def\tablez #1#2#3#4#5#6{%
+\aboveenvbreak %
+\begingroup %
+\def\Edescription{\Etable}% Necessary kludge.
+\let\itemindex=#1%
+\ifnum 0#3>0 \advance \leftskip by #3\mil \fi %
+\ifnum 0#4>0 \tableindent=#4\mil \fi %
+\ifnum 0#5>0 \advance \rightskip by #5\mil \fi %
+\def\itemfont{#2}%
+\itemmax=\tableindent %
+\advance \itemmax by -\itemmargin %
+\advance \leftskip by \tableindent %
+\exdentamount=\tableindent
+\parindent = 0pt
+\parskip = \smallskipamount
+\ifdim \parskip=0pt \parskip=2pt \fi%
+\def\Etable{\endgraf\afterenvbreak\endgroup}%
+\let\item = \internalBitem %
+\let\itemx = \internalBitemx %
+\let\kitem = \internalBkitem %
+\let\kitemx = \internalBkitemx %
+\let\xitem = \internalBxitem %
+\let\xitemx = \internalBxitemx %
+}
+
+% This is the counter used by @enumerate, which is really @itemize
+
+\newcount \itemno
+
+\def\itemize{\parsearg\itemizezzz}
+
+\def\itemizezzz #1{%
+ \begingroup % ended by the @end itemize
+ \itemizey {#1}{\Eitemize}
+}
+
+\def\itemizey #1#2{%
+\aboveenvbreak %
+\itemmax=\itemindent %
+\advance \itemmax by -\itemmargin %
+\advance \leftskip by \itemindent %
+\exdentamount=\itemindent
+\parindent = 0pt %
+\parskip = \smallskipamount %
+\ifdim \parskip=0pt \parskip=2pt \fi%
+\def#2{\endgraf\afterenvbreak\endgroup}%
+\def\itemcontents{#1}%
+\let\item=\itemizeitem}
+
+% Set sfcode to normal for the chars that usually have another value.
+% These are `.?!:;,'
+\def\frenchspacing{\sfcode46=1000 \sfcode63=1000 \sfcode33=1000
+ \sfcode58=1000 \sfcode59=1000 \sfcode44=1000 }
+
+% \splitoff TOKENS\endmark defines \first to be the first token in
+% TOKENS, and \rest to be the remainder.
+%
+\def\splitoff#1#2\endmark{\def\first{#1}\def\rest{#2}}%
+
+% Allow an optional argument of an uppercase letter, lowercase letter,
+% or number, to specify the first label in the enumerated list. No
+% argument is the same as `1'.
+%
+\def\enumerate{\parsearg\enumeratezzz}
+\def\enumeratezzz #1{\enumeratey #1 \endenumeratey}
+\def\enumeratey #1 #2\endenumeratey{%
+ \begingroup % ended by the @end enumerate
+ %
+ % If we were given no argument, pretend we were given `1'.
+ \def\thearg{#1}%
+ \ifx\thearg\empty \def\thearg{1}\fi
+ %
+ % Detect if the argument is a single token. If so, it might be a
+ % letter. Otherwise, the only valid thing it can be is a number.
+ % (We will always have one token, because of the test we just made.
+ % This is a good thing, since \splitoff doesn't work given nothing at
+ % all -- the first parameter is undelimited.)
+ \expandafter\splitoff\thearg\endmark
+ \ifx\rest\empty
+ % Only one token in the argument. It could still be anything.
+ % A ``lowercase letter'' is one whose \lccode is nonzero.
+ % An ``uppercase letter'' is one whose \lccode is both nonzero, and
+ % not equal to itself.
+ % Otherwise, we assume it's a number.
+ %
+ % We need the \relax at the end of the \ifnum lines to stop TeX from
+ % continuing to look for a <number>.
+ %
+ \ifnum\lccode\expandafter`\thearg=0\relax
+ \numericenumerate % a number (we hope)
+ \else
+ % It's a letter.
+ \ifnum\lccode\expandafter`\thearg=\expandafter`\thearg\relax
+ \lowercaseenumerate % lowercase letter
+ \else
+ \uppercaseenumerate % uppercase letter
+ \fi
+ \fi
+ \else
+ % Multiple tokens in the argument. We hope it's a number.
+ \numericenumerate
+ \fi
+}
+
+% An @enumerate whose labels are integers. The starting integer is
+% given in \thearg.
+%
+\def\numericenumerate{%
+ \itemno = \thearg
+ \startenumeration{\the\itemno}%
+}
+
+% The starting (lowercase) letter is in \thearg.
+\def\lowercaseenumerate{%
+ \itemno = \expandafter`\thearg
+ \startenumeration{%
+ % Be sure we're not beyond the end of the alphabet.
+ \ifnum\itemno=0
+ \errmessage{No more lowercase letters in @enumerate; get a bigger
+ alphabet}%
+ \fi
+ \char\lccode\itemno
+ }%
+}
+
+% The starting (uppercase) letter is in \thearg.
+\def\uppercaseenumerate{%
+ \itemno = \expandafter`\thearg
+ \startenumeration{%
+ % Be sure we're not beyond the end of the alphabet.
+ \ifnum\itemno=0
+ \errmessage{No more uppercase letters in @enumerate; get a bigger
+ alphabet}
+ \fi
+ \char\uccode\itemno
+ }%
+}
+
+% Call itemizey, adding a period to the first argument and supplying the
+% common last two arguments. Also subtract one from the initial value in
+% \itemno, since @item increments \itemno.
+%
+\def\startenumeration#1{%
+ \advance\itemno by -1
+ \itemizey{#1.}\Eenumerate\flushcr
+}
+
+% @alphaenumerate and @capsenumerate are abbreviations for giving an arg
+% to @enumerate.
+%
+\def\alphaenumerate{\enumerate{a}}
+\def\capsenumerate{\enumerate{A}}
+\def\Ealphaenumerate{\Eenumerate}
+\def\Ecapsenumerate{\Eenumerate}
+
+% Definition of @item while inside @itemize.
+
+\def\itemizeitem{%
+\advance\itemno by 1
+{\let\par=\endgraf \smallbreak}%
+\ifhmode \errmessage{In hmode at itemizeitem}\fi
+{\parskip=0in \hskip 0pt
+\hbox to 0pt{\hss \itemcontents\hskip \itemmargin}%
+\vadjust{\penalty 1200}}%
+\flushcr}
+
+% @multitable macros
+% Amy Hendrickson, 8/18/94, 3/6/96
+%
+% @multitable ... @end multitable will make as many columns as desired.
+% Contents of each column will wrap at width given in preamble. Width
+% can be specified either with sample text given in a template line,
+% or in percent of \hsize, the current width of text on page.
+
+% Table can continue over pages but will only break between lines.
+
+% To make preamble:
+%
+% Either define widths of columns in terms of percent of \hsize:
+% @multitable @columnfractions .25 .3 .45
+% @item ...
+%
+% Numbers following @columnfractions are the percent of the total
+% current hsize to be used for each column. You may use as many
+% columns as desired.
+
+
+% Or use a template:
+% @multitable {Column 1 template} {Column 2 template} {Column 3 template}
+% @item ...
+% using the widest term desired in each column.
+%
+% For those who want to use more than one line's worth of words in
+% the preamble, break the line within one argument and it
+% will parse correctly, i.e.,
+%
+% @multitable {Column 1 template} {Column 2 template} {Column 3
+% template}
+% Not:
+% @multitable {Column 1 template} {Column 2 template}
+% {Column 3 template}
+
+% Each new table line starts with @item, each subsequent new column
+% starts with @tab. Empty columns may be produced by supplying @tab's
+% with nothing between them for as many times as empty columns are needed,
+% ie, @tab@tab@tab will produce two empty columns.
+
+% @item, @tab, @multitable or @end multitable do not need to be on their
+% own lines, but it will not hurt if they are.
+
+% Sample multitable:
+
+% @multitable {Column 1 template} {Column 2 template} {Column 3 template}
+% @item first col stuff @tab second col stuff @tab third col
+% @item
+% first col stuff
+% @tab
+% second col stuff
+% @tab
+% third col
+% @item first col stuff @tab second col stuff
+% @tab Many paragraphs of text may be used in any column.
+%
+% They will wrap at the width determined by the template.
+% @item@tab@tab This will be in third column.
+% @end multitable
+
+% Default dimensions may be reset by user.
+% @multitableparskip is vertical space between paragraphs in table.
+% @multitableparindent is paragraph indent in table.
+% @multitablecolmargin is horizontal space to be left between columns.
+% @multitablelinespace is space to leave between table items, baseline
+% to baseline.
+% 0pt means it depends on current normal line spacing.
+%
+\newskip\multitableparskip
+\newskip\multitableparindent
+\newdimen\multitablecolspace
+\newskip\multitablelinespace
+\multitableparskip=0pt
+\multitableparindent=6pt
+\multitablecolspace=12pt
+\multitablelinespace=0pt
+
+% Macros used to set up halign preamble:
+%
+\let\endsetuptable\relax
+\def\xendsetuptable{\endsetuptable}
+\let\columnfractions\relax
+\def\xcolumnfractions{\columnfractions}
+\newif\ifsetpercent
+
+% #1 is the part of the @columnfraction before the decimal point, which
+% is presumably either 0 or the empty string (but we don't check, we
+% just throw it away). #2 is the decimal part, which we use as the
+% percent of \hsize for this column.
+\def\pickupwholefraction#1.#2 {%
+ \global\advance\colcount by 1
+ \expandafter\xdef\csname col\the\colcount\endcsname{.#2\hsize}%
+ \setuptable
+}
+
+\newcount\colcount
+\def\setuptable#1{%
+ \def\firstarg{#1}%
+ \ifx\firstarg\xendsetuptable
+ \let\go = \relax
+ \else
+ \ifx\firstarg\xcolumnfractions
+ \global\setpercenttrue
+ \else
+ \ifsetpercent
+ \let\go\pickupwholefraction
+ \else
+ \global\advance\colcount by 1
+ \setbox0=\hbox{#1\unskip }% Add a normal word space as a separator;
+ % typically that is always in the input, anyway.
+ \expandafter\xdef\csname col\the\colcount\endcsname{\the\wd0}%
+ \fi
+ \fi
+ \ifx\go\pickupwholefraction
+ % Put the argument back for the \pickupwholefraction call, so
+ % we'll always have a period there to be parsed.
+ \def\go{\pickupwholefraction#1}%
+ \else
+ \let\go = \setuptable
+ \fi%
+ \fi
+ \go
+}
+
+% This used to have \hskip1sp. But then the space in a template line is
+% not enough. That is bad. So let's go back to just & until we
+% encounter the problem it was intended to solve again.
+% --karl, nathan@acm.org, 20apr99.
+\def\tab{&}
+
+% @multitable ... @end multitable definitions:
+%
+\def\multitable{\parsearg\dotable}
+\def\dotable#1{\bgroup
+ \vskip\parskip
+ \let\item\crcr
+ \tolerance=9500
+ \hbadness=9500
+ \setmultitablespacing
+ \parskip=\multitableparskip
+ \parindent=\multitableparindent
+ \overfullrule=0pt
+ \global\colcount=0
+ \def\Emultitable{\global\setpercentfalse\cr\egroup\egroup}%
+ %
+ % To parse everything between @multitable and @item:
+ \setuptable#1 \endsetuptable
+ %
+ % \everycr will reset column counter, \colcount, at the end of
+ % each line. Every column entry will cause \colcount to advance by one.
+ % The table preamble
+ % looks at the current \colcount to find the correct column width.
+ \everycr{\noalign{%
+ %
+ % \filbreak%% keeps underfull box messages off when table breaks over pages.
+ % Maybe so, but it also creates really weird page breaks when the table
+ % breaks over pages. Wouldn't \vfil be better? Wait until the problem
+ % manifests itself, so it can be fixed for real --karl.
+ \global\colcount=0\relax}}%
+ %
+ % This preamble sets up a generic column definition, which will
+ % be used as many times as user calls for columns.
+ % \vtop will set a single line and will also let text wrap and
+ % continue for many paragraphs if desired.
+ \halign\bgroup&\global\advance\colcount by 1\relax
+ \multistrut\vtop{\hsize=\expandafter\csname col\the\colcount\endcsname
+ %
+ % In order to keep entries from bumping into each other
+ % we will add a \leftskip of \multitablecolspace to all columns after
+ % the first one.
+ %
+ % If a template has been used, we will add \multitablecolspace
+ % to the width of each template entry.
+ %
+ % If the user has set preamble in terms of percent of \hsize we will
+ % use that dimension as the width of the column, and the \leftskip
+ % will keep entries from bumping into each other. Table will start at
+ % left margin and final column will justify at right margin.
+ %
+ % Make sure we don't inherit \rightskip from the outer environment.
+ \rightskip=0pt
+ \ifnum\colcount=1
+ % The first column will be indented with the surrounding text.
+ \advance\hsize by\leftskip
+ \else
+ \ifsetpercent \else
+ % If user has not set preamble in terms of percent of \hsize
+ % we will advance \hsize by \multitablecolspace.
+ \advance\hsize by \multitablecolspace
+ \fi
+ % In either case we will make \leftskip=\multitablecolspace:
+ \leftskip=\multitablecolspace
+ \fi
+ % Ignoring space at the beginning and end avoids an occasional spurious
+ % blank line, when TeX decides to break the line at the space before the
+ % box from the multistrut, so the strut ends up on a line by itself.
+ % For example:
+ % @multitable @columnfractions .11 .89
+ % @item @code{#}
+ % @tab Legal holiday which is valid in major parts of the whole country.
+ % Is automatically provided with highlighting sequences respectively marking
+ % characters.
+ \noindent\ignorespaces##\unskip\multistrut}\cr
+}
+
+\def\setmultitablespacing{% test to see if user has set \multitablelinespace.
+% If so, do nothing. If not, give it an appropriate dimension based on
+% current baselineskip.
+\ifdim\multitablelinespace=0pt
+%% strut to put in table in case some entry doesn't have descenders,
+%% to keep lines equally spaced
+\let\multistrut = \strut
+%% Test to see if parskip is larger than space between lines of
+%% table. If not, do nothing.
+%% If so, set to same dimension as multitablelinespace.
+\else
+\gdef\multistrut{\vrule height\multitablelinespace depth\dp0
+width0pt\relax} \fi
+\ifdim\multitableparskip>\multitablelinespace
+\global\multitableparskip=\multitablelinespace
+\global\advance\multitableparskip-7pt %% to keep parskip somewhat smaller
+ %% than skip between lines in the table.
+\fi%
+\ifdim\multitableparskip=0pt
+\global\multitableparskip=\multitablelinespace
+\global\advance\multitableparskip-7pt %% to keep parskip somewhat smaller
+ %% than skip between lines in the table.
+\fi}
+
+
+\message{conditionals,}
+% Prevent errors for section commands.
+% Used in @ignore and in failing conditionals.
+\def\ignoresections{%
+ \let\chapter=\relax
+ \let\unnumbered=\relax
+ \let\top=\relax
+ \let\unnumberedsec=\relax
+ \let\unnumberedsection=\relax
+ \let\unnumberedsubsec=\relax
+ \let\unnumberedsubsection=\relax
+ \let\unnumberedsubsubsec=\relax
+ \let\unnumberedsubsubsection=\relax
+ \let\section=\relax
+ \let\subsec=\relax
+ \let\subsubsec=\relax
+ \let\subsection=\relax
+ \let\subsubsection=\relax
+ \let\appendix=\relax
+ \let\appendixsec=\relax
+ \let\appendixsection=\relax
+ \let\appendixsubsec=\relax
+ \let\appendixsubsection=\relax
+ \let\appendixsubsubsec=\relax
+ \let\appendixsubsubsection=\relax
+ \let\contents=\relax
+ \let\smallbook=\relax
+ \let\titlepage=\relax
+}
+
+% Used in nested conditionals, where we have to parse the Texinfo source
+% and so want to turn off most commands, in case they are used
+% incorrectly.
+%
+\def\ignoremorecommands{%
+ \let\defcodeindex = \relax
+ \let\defcv = \relax
+ \let\deffn = \relax
+ \let\deffnx = \relax
+ \let\defindex = \relax
+ \let\defivar = \relax
+ \let\defmac = \relax
+ \let\defmethod = \relax
+ \let\defop = \relax
+ \let\defopt = \relax
+ \let\defspec = \relax
+ \let\deftp = \relax
+ \let\deftypefn = \relax
+ \let\deftypefun = \relax
+ \let\deftypeivar = \relax
+ \let\deftypevar = \relax
+ \let\deftypevr = \relax
+ \let\defun = \relax
+ \let\defvar = \relax
+ \let\defvr = \relax
+ \let\ref = \relax
+ \let\xref = \relax
+ \let\printindex = \relax
+ \let\pxref = \relax
+ \let\settitle = \relax
+ \let\setchapternewpage = \relax
+ \let\setchapterstyle = \relax
+ \let\everyheading = \relax
+ \let\evenheading = \relax
+ \let\oddheading = \relax
+ \let\everyfooting = \relax
+ \let\evenfooting = \relax
+ \let\oddfooting = \relax
+ \let\headings = \relax
+ \let\include = \relax
+ \let\lowersections = \relax
+ \let\down = \relax
+ \let\raisesections = \relax
+ \let\up = \relax
+ \let\set = \relax
+ \let\clear = \relax
+ \let\item = \relax
+}
+
+% Ignore @ignore ... @end ignore.
+%
+\def\ignore{\doignore{ignore}}
+
+% Ignore @ifinfo, @ifhtml, @ifnottex, @html, @menu, and @direntry text.
+%
+\def\ifinfo{\doignore{ifinfo}}
+\def\ifhtml{\doignore{ifhtml}}
+\def\ifnottex{\doignore{ifnottex}}
+\def\html{\doignore{html}}
+\def\menu{\doignore{menu}}
+\def\direntry{\doignore{direntry}}
+
+% @dircategory CATEGORY -- specify a category of the dir file
+% which this file should belong to. Ignore this in TeX.
+\let\dircategory = \comment
+
+% Ignore text until a line `@end #1'.
+%
+\def\doignore#1{\begingroup
+ % Don't complain about control sequences we have declared \outer.
+ \ignoresections
+ %
+ % Define a command to swallow text until we reach `@end #1'.
+ % This @ is a catcode 12 token (that is the normal catcode of @ in
+ % this texinfo.tex file). We change the catcode of @ below to match.
+ \long\def\doignoretext##1@end #1{\enddoignore}%
+ %
+ % Make sure that spaces turn into tokens that match what \doignoretext wants.
+ \catcode32 = 10
+ %
+ % Ignore braces, too, so mismatched braces don't cause trouble.
+ \catcode`\{ = 9
+ \catcode`\} = 9
+ %
+ % We must not have @c interpreted as a control sequence.
+ \catcode`\@ = 12
+ %
+ % Make the letter c a comment character so that the rest of the line
+ % will be ignored. This way, the document can have (for example)
+ % @c @end ifinfo
+ % and the @end ifinfo will be properly ignored.
+ % (We've just changed @ to catcode 12.)
+ \catcode`\c = 14
+ %
+ % And now expand that command.
+ \doignoretext
+}
+
+% What we do to finish off ignored text.
+%
+\def\enddoignore{\endgroup\ignorespaces}%
+
+\newif\ifwarnedobs\warnedobsfalse
+\def\obstexwarn{%
+ \ifwarnedobs\relax\else
+ % We need to warn folks that they may have trouble with TeX 3.0.
+ % This uses \immediate\write16 rather than \message to get newlines.
+ \immediate\write16{}
+ \immediate\write16{WARNING: for users of Unix TeX 3.0!}
+ \immediate\write16{This manual trips a bug in TeX version 3.0 (tex hangs).}
+ \immediate\write16{If you are running another version of TeX, relax.}
+ \immediate\write16{If you are running Unix TeX 3.0, kill this TeX process.}
+ \immediate\write16{ Then upgrade your TeX installation if you can.}
+ \immediate\write16{ (See ftp://ftp.gnu.org/pub/gnu/TeX.README.)}
+ \immediate\write16{If you are stuck with version 3.0, run the}
+ \immediate\write16{ script ``tex3patch'' from the Texinfo distribution}
+ \immediate\write16{ to use a workaround.}
+ \immediate\write16{}
+ \global\warnedobstrue
+ \fi
+}
+
+% **In TeX 3.0, setting text in \nullfont hangs tex. For a
+% workaround (which requires the file ``dummy.tfm'' to be installed),
+% uncomment the following line:
+%%%%%\font\nullfont=dummy\let\obstexwarn=\relax
+
+% Ignore text, except that we keep track of conditional commands for
+% purposes of nesting, up to an `@end #1' command.
+%
+\def\nestedignore#1{%
+ \obstexwarn
+ % We must actually expand the ignored text to look for the @end
+ % command, so that nested ignore constructs work. Thus, we put the
+ % text into a \vbox and then do nothing with the result. To minimize
+ % the change of memory overflow, we follow the approach outlined on
+ % page 401 of the TeXbook: make the current font be a dummy font.
+ %
+ \setbox0 = \vbox\bgroup
+ % Don't complain about control sequences we have declared \outer.
+ \ignoresections
+ %
+ % Define `@end #1' to end the box, which will in turn undefine the
+ % @end command again.
+ \expandafter\def\csname E#1\endcsname{\egroup\ignorespaces}%
+ %
+ % We are going to be parsing Texinfo commands. Most cause no
+ % trouble when they are used incorrectly, but some commands do
+ % complicated argument parsing or otherwise get confused, so we
+ % undefine them.
+ %
+ % We can't do anything about stray @-signs, unfortunately;
+ % they'll produce `undefined control sequence' errors.
+ \ignoremorecommands
+ %
+ % Set the current font to be \nullfont, a TeX primitive, and define
+ % all the font commands to also use \nullfont. We don't use
+ % dummy.tfm, as suggested in the TeXbook, because not all sites
+ % might have that installed. Therefore, math mode will still
+ % produce output, but that should be an extremely small amount of
+ % stuff compared to the main input.
+ %
+ \nullfont
+ \let\tenrm = \nullfont \let\tenit = \nullfont \let\tensl = \nullfont
+ \let\tenbf = \nullfont \let\tentt = \nullfont \let\smallcaps = \nullfont
+ \let\tensf = \nullfont
+ % Similarly for index fonts (mostly for their use in
+ % smallexample)
+ \let\indrm = \nullfont \let\indit = \nullfont \let\indsl = \nullfont
+ \let\indbf = \nullfont \let\indtt = \nullfont \let\indsc = \nullfont
+ \let\indsf = \nullfont
+ %
+ % Don't complain when characters are missing from the fonts.
+ \tracinglostchars = 0
+ %
+ % Don't bother to do space factor calculations.
+ \frenchspacing
+ %
+ % Don't report underfull hboxes.
+ \hbadness = 10000
+ %
+ % Do minimal line-breaking.
+ \pretolerance = 10000
+ %
+ % Do not execute instructions in @tex
+ \def\tex{\doignore{tex}}%
+ % Do not execute macro definitions.
+ % `c' is a comment character, so the word `macro' will get cut off.
+ \def\macro{\doignore{ma}}%
+}
+
+% @set VAR sets the variable VAR to an empty value.
+% @set VAR REST-OF-LINE sets VAR to the value REST-OF-LINE.
+%
+% Since we want to separate VAR from REST-OF-LINE (which might be
+% empty), we can't just use \parsearg; we have to insert a space of our
+% own to delimit the rest of the line, and then take it out again if we
+% didn't need it. Make sure the catcode of space is correct to avoid
+% losing inside @example, for instance.
+%
+\def\set{\begingroup\catcode` =10
+ \catcode`\-=12 \catcode`\_=12 % Allow - and _ in VAR.
+ \parsearg\setxxx}
+\def\setxxx#1{\setyyy#1 \endsetyyy}
+\def\setyyy#1 #2\endsetyyy{%
+ \def\temp{#2}%
+ \ifx\temp\empty \global\expandafter\let\csname SET#1\endcsname = \empty
+ \else \setzzz{#1}#2\endsetzzz % Remove the trailing space \setxxx inserted.
+ \fi
+ \endgroup
+}
+% Can't use \xdef to pre-expand #2 and save some time, since \temp or
+% \next or other control sequences that we've defined might get us into
+% an infinite loop. Consider `@set foo @cite{bar}'.
+\def\setzzz#1#2 \endsetzzz{\expandafter\gdef\csname SET#1\endcsname{#2}}
+
+% @clear VAR clears (i.e., unsets) the variable VAR.
+%
+\def\clear{\parsearg\clearxxx}
+\def\clearxxx#1{\global\expandafter\let\csname SET#1\endcsname=\relax}
+
+% @value{foo} gets the text saved in variable foo.
+{
+ \catcode`\_ = \active
+ %
+ % We might end up with active _ or - characters in the argument if
+ % we're called from @code, as @code{@value{foo-bar_}}. So \let any
+ % such active characters to their normal equivalents.
+ \gdef\value{\begingroup
+ \catcode`\-=12 \catcode`\_=12
+ \indexbreaks \let_\normalunderscore
+ \valuexxx}
+}
+\def\valuexxx#1{\expandablevalue{#1}\endgroup}
+
+% We have this subroutine so that we can handle at least some @value's
+% properly in indexes (we \let\value to this in \indexdummies). Ones
+% whose names contain - or _ still won't work, but we can't do anything
+% about that. The command has to be fully expandable, since the result
+% winds up in the index file. This means that if the variable's value
+% contains other Texinfo commands, it's almost certain it will fail
+% (although perhaps we could fix that with sufficient work to do a
+% one-level expansion on the result, instead of complete).
+%
+\def\expandablevalue#1{%
+ \expandafter\ifx\csname SET#1\endcsname\relax
+ {[No value for ``#1'']}%
+ \else
+ \csname SET#1\endcsname
+ \fi
+}
+
+% @ifset VAR ... @end ifset reads the `...' iff VAR has been defined
+% with @set.
+%
+\def\ifset{\parsearg\ifsetxxx}
+\def\ifsetxxx #1{%
+ \expandafter\ifx\csname SET#1\endcsname\relax
+ \expandafter\ifsetfail
+ \else
+ \expandafter\ifsetsucceed
+ \fi
+}
+\def\ifsetsucceed{\conditionalsucceed{ifset}}
+\def\ifsetfail{\nestedignore{ifset}}
+\defineunmatchedend{ifset}
+
+% @ifclear VAR ... @end ifclear reads the `...' iff VAR has never been
+% defined with @set, or has been undefined with @clear.
+%
+\def\ifclear{\parsearg\ifclearxxx}
+\def\ifclearxxx #1{%
+ \expandafter\ifx\csname SET#1\endcsname\relax
+ \expandafter\ifclearsucceed
+ \else
+ \expandafter\ifclearfail
+ \fi
+}
+\def\ifclearsucceed{\conditionalsucceed{ifclear}}
+\def\ifclearfail{\nestedignore{ifclear}}
+\defineunmatchedend{ifclear}
+
+% @iftex, @ifnothtml, @ifnotinfo always succeed; we read the text
+% following, through the first @end iftex (etc.). Make `@end iftex'
+% (etc.) valid only after an @iftex.
+%
+\def\iftex{\conditionalsucceed{iftex}}
+\def\ifnothtml{\conditionalsucceed{ifnothtml}}
+\def\ifnotinfo{\conditionalsucceed{ifnotinfo}}
+\defineunmatchedend{iftex}
+\defineunmatchedend{ifnothtml}
+\defineunmatchedend{ifnotinfo}
+
+% We can't just want to start a group at @iftex (for example) and end it
+% at @end iftex, since then @set commands inside the conditional have no
+% effect (they'd get reverted at the end of the group). So we must
+% define \Eiftex to redefine itself to be its previous value. (We can't
+% just define it to fail again with an ``unmatched end'' error, since
+% the @ifset might be nested.)
+%
+\def\conditionalsucceed#1{%
+ \edef\temp{%
+ % Remember the current value of \E#1.
+ \let\nece{prevE#1} = \nece{E#1}%
+ %
+ % At the `@end #1', redefine \E#1 to be its previous value.
+ \def\nece{E#1}{\let\nece{E#1} = \nece{prevE#1}}%
+ }%
+ \temp
+}
+
+% We need to expand lots of \csname's, but we don't want to expand the
+% control sequences after we've constructed them.
+%
+\def\nece#1{\expandafter\noexpand\csname#1\endcsname}
+
+% @defininfoenclose.
+\let\definfoenclose=\comment
+
+
+\message{indexing,}
+% Index generation facilities
+
+% Define \newwrite to be identical to plain tex's \newwrite
+% except not \outer, so it can be used within \newindex.
+{\catcode`\@=11
+\gdef\newwrite{\alloc@7\write\chardef\sixt@@n}}
+
+% \newindex {foo} defines an index named foo.
+% It automatically defines \fooindex such that
+% \fooindex ...rest of line... puts an entry in the index foo.
+% It also defines \fooindfile to be the number of the output channel for
+% the file that accumulates this index. The file's extension is foo.
+% The name of an index should be no more than 2 characters long
+% for the sake of vms.
+%
+\def\newindex#1{%
+ \iflinks
+ \expandafter\newwrite \csname#1indfile\endcsname
+ \openout \csname#1indfile\endcsname \jobname.#1 % Open the file
+ \fi
+ \expandafter\xdef\csname#1index\endcsname{% % Define @#1index
+ \noexpand\doindex{#1}}
+}
+
+% @defindex foo == \newindex{foo}
+
+\def\defindex{\parsearg\newindex}
+
+% Define @defcodeindex, like @defindex except put all entries in @code.
+
+\def\newcodeindex#1{%
+ \iflinks
+ \expandafter\newwrite \csname#1indfile\endcsname
+ \openout \csname#1indfile\endcsname \jobname.#1
+ \fi
+ \expandafter\xdef\csname#1index\endcsname{%
+ \noexpand\docodeindex{#1}}
+}
+
+\def\defcodeindex{\parsearg\newcodeindex}
+
+% @synindex foo bar makes index foo feed into index bar.
+% Do this instead of @defindex foo if you don't want it as a separate index.
+% The \closeout helps reduce unnecessary open files; the limit on the
+% Acorn RISC OS is a mere 16 files.
+\def\synindex#1 #2 {%
+ \expandafter\let\expandafter\synindexfoo\expandafter=\csname#2indfile\endcsname
+ \expandafter\closeout\csname#1indfile\endcsname
+ \expandafter\let\csname#1indfile\endcsname=\synindexfoo
+ \expandafter\xdef\csname#1index\endcsname{% define \xxxindex
+ \noexpand\doindex{#2}}%
+}
+
+% @syncodeindex foo bar similar, but put all entries made for index foo
+% inside @code.
+\def\syncodeindex#1 #2 {%
+ \expandafter\let\expandafter\synindexfoo\expandafter=\csname#2indfile\endcsname
+ \expandafter\closeout\csname#1indfile\endcsname
+ \expandafter\let\csname#1indfile\endcsname=\synindexfoo
+ \expandafter\xdef\csname#1index\endcsname{% define \xxxindex
+ \noexpand\docodeindex{#2}}%
+}
+
+% Define \doindex, the driver for all \fooindex macros.
+% Argument #1 is generated by the calling \fooindex macro,
+% and it is "foo", the name of the index.
+
+% \doindex just uses \parsearg; it calls \doind for the actual work.
+% This is because \doind is more useful to call from other macros.
+
+% There is also \dosubind {index}{topic}{subtopic}
+% which makes an entry in a two-level index such as the operation index.
+
+\def\doindex#1{\edef\indexname{#1}\parsearg\singleindexer}
+\def\singleindexer #1{\doind{\indexname}{#1}}
+
+% like the previous two, but they put @code around the argument.
+\def\docodeindex#1{\edef\indexname{#1}\parsearg\singlecodeindexer}
+\def\singlecodeindexer #1{\doind{\indexname}{\code{#1}}}
+
+\def\indexdummies{%
+\def\ { }%
+% Take care of the plain tex accent commands.
+\def\"{\realbackslash "}%
+\def\`{\realbackslash `}%
+\def\'{\realbackslash '}%
+\def\^{\realbackslash ^}%
+\def\~{\realbackslash ~}%
+\def\={\realbackslash =}%
+\def\b{\realbackslash b}%
+\def\c{\realbackslash c}%
+\def\d{\realbackslash d}%
+\def\u{\realbackslash u}%
+\def\v{\realbackslash v}%
+\def\H{\realbackslash H}%
+% Take care of the plain tex special European modified letters.
+\def\oe{\realbackslash oe}%
+\def\ae{\realbackslash ae}%
+\def\aa{\realbackslash aa}%
+\def\OE{\realbackslash OE}%
+\def\AE{\realbackslash AE}%
+\def\AA{\realbackslash AA}%
+\def\o{\realbackslash o}%
+\def\O{\realbackslash O}%
+\def\l{\realbackslash l}%
+\def\L{\realbackslash L}%
+\def\ss{\realbackslash ss}%
+% Take care of texinfo commands likely to appear in an index entry.
+% (Must be a way to avoid doing expansion at all, and thus not have to
+% laboriously list every single command here.)
+\def\@{@}% will be @@ when we switch to @ as escape char.
+% Need these in case \tex is in effect and \{ is a \delimiter again.
+% But can't use \lbracecmd and \rbracecmd because texindex assumes
+% braces and backslashes are used only as delimiters.
+\let\{ = \mylbrace
+\let\} = \myrbrace
+\def\_{{\realbackslash _}}%
+\def\w{\realbackslash w }%
+\def\bf{\realbackslash bf }%
+%\def\rm{\realbackslash rm }%
+\def\sl{\realbackslash sl }%
+\def\sf{\realbackslash sf}%
+\def\tt{\realbackslash tt}%
+\def\gtr{\realbackslash gtr}%
+\def\less{\realbackslash less}%
+\def\hat{\realbackslash hat}%
+\def\TeX{\realbackslash TeX}%
+\def\dots{\realbackslash dots }%
+\def\result{\realbackslash result}%
+\def\equiv{\realbackslash equiv}%
+\def\expansion{\realbackslash expansion}%
+\def\print{\realbackslash print}%
+\def\error{\realbackslash error}%
+\def\point{\realbackslash point}%
+\def\copyright{\realbackslash copyright}%
+\def\tclose##1{\realbackslash tclose {##1}}%
+\def\code##1{\realbackslash code {##1}}%
+\def\uref##1{\realbackslash uref {##1}}%
+\def\url##1{\realbackslash url {##1}}%
+\def\env##1{\realbackslash env {##1}}%
+\def\command##1{\realbackslash command {##1}}%
+\def\option##1{\realbackslash option {##1}}%
+\def\dotless##1{\realbackslash dotless {##1}}%
+\def\samp##1{\realbackslash samp {##1}}%
+\def\,##1{\realbackslash ,{##1}}%
+\def\t##1{\realbackslash t {##1}}%
+\def\r##1{\realbackslash r {##1}}%
+\def\i##1{\realbackslash i {##1}}%
+\def\b##1{\realbackslash b {##1}}%
+\def\sc##1{\realbackslash sc {##1}}%
+\def\cite##1{\realbackslash cite {##1}}%
+\def\key##1{\realbackslash key {##1}}%
+\def\file##1{\realbackslash file {##1}}%
+\def\var##1{\realbackslash var {##1}}%
+\def\kbd##1{\realbackslash kbd {##1}}%
+\def\dfn##1{\realbackslash dfn {##1}}%
+\def\emph##1{\realbackslash emph {##1}}%
+\def\acronym##1{\realbackslash acronym {##1}}%
+%
+% Handle some cases of @value -- where the variable name does not
+% contain - or _, and the value does not contain any
+% (non-fully-expandable) commands.
+\let\value = \expandablevalue
+%
+\unsepspaces
+% Turn off macro expansion
+\turnoffmacros
+}
+
+% If an index command is used in an @example environment, any spaces
+% therein should become regular spaces in the raw index file, not the
+% expansion of \tie (\\leavevmode \penalty \@M \ ).
+{\obeyspaces
+ \gdef\unsepspaces{\obeyspaces\let =\space}}
+
+% \indexnofonts no-ops all font-change commands.
+% This is used when outputting the strings to sort the index by.
+\def\indexdummyfont#1{#1}
+\def\indexdummytex{TeX}
+\def\indexdummydots{...}
+
+\def\indexnofonts{%
+% Just ignore accents.
+\let\,=\indexdummyfont
+\let\"=\indexdummyfont
+\let\`=\indexdummyfont
+\let\'=\indexdummyfont
+\let\^=\indexdummyfont
+\let\~=\indexdummyfont
+\let\==\indexdummyfont
+\let\b=\indexdummyfont
+\let\c=\indexdummyfont
+\let\d=\indexdummyfont
+\let\u=\indexdummyfont
+\let\v=\indexdummyfont
+\let\H=\indexdummyfont
+\let\dotless=\indexdummyfont
+% Take care of the plain tex special European modified letters.
+\def\oe{oe}%
+\def\ae{ae}%
+\def\aa{aa}%
+\def\OE{OE}%
+\def\AE{AE}%
+\def\AA{AA}%
+\def\o{o}%
+\def\O{O}%
+\def\l{l}%
+\def\L{L}%
+\def\ss{ss}%
+\let\w=\indexdummyfont
+\let\t=\indexdummyfont
+\let\r=\indexdummyfont
+\let\i=\indexdummyfont
+\let\b=\indexdummyfont
+\let\emph=\indexdummyfont
+\let\strong=\indexdummyfont
+\let\cite=\indexdummyfont
+\let\sc=\indexdummyfont
+%Don't no-op \tt, since it isn't a user-level command
+% and is used in the definitions of the active chars like <, >, |...
+%\let\tt=\indexdummyfont
+\let\tclose=\indexdummyfont
+\let\code=\indexdummyfont
+\let\url=\indexdummyfont
+\let\uref=\indexdummyfont
+\let\env=\indexdummyfont
+\let\command=\indexdummyfont
+\let\option=\indexdummyfont
+\let\file=\indexdummyfont
+\let\samp=\indexdummyfont
+\let\kbd=\indexdummyfont
+\let\key=\indexdummyfont
+\let\var=\indexdummyfont
+\let\TeX=\indexdummytex
+\let\dots=\indexdummydots
+\def\@{@}%
+}
+
+% To define \realbackslash, we must make \ not be an escape.
+% We must first make another character (@) an escape
+% so we do not become unable to do a definition.
+
+{\catcode`\@=0 \catcode`\\=\other
+ @gdef@realbackslash{\}}
+
+\let\indexbackslash=0 %overridden during \printindex.
+\let\SETmarginindex=\relax % put index entries in margin (undocumented)?
+
+% For \ifx comparisons.
+\def\emptymacro{\empty}
+
+% Most index entries go through here, but \dosubind is the general case.
+%
+\def\doind#1#2{\dosubind{#1}{#2}\empty}
+
+% Workhorse for all \fooindexes.
+% #1 is name of index, #2 is stuff to put there, #3 is subentry --
+% \empty if called from \doind, as we usually are. The main exception
+% is with defuns, which call us directly.
+%
+\def\dosubind#1#2#3{%
+ % Put the index entry in the margin if desired.
+ \ifx\SETmarginindex\relax\else
+ \insert\margin{\hbox{\vrule height8pt depth3pt width0pt #2}}%
+ \fi
+ {%
+ \count255=\lastpenalty
+ {%
+ \indexdummies % Must do this here, since \bf, etc expand at this stage
+ \escapechar=`\\
+ {%
+ \let\folio = 0% We will expand all macros now EXCEPT \folio.
+ \def\rawbackslashxx{\indexbackslash}% \indexbackslash isn't defined now
+ % so it will be output as is; and it will print as backslash.
+ %
+ \def\thirdarg{#3}%
+ %
+ % If third arg is present, precede it with space in sort key.
+ \ifx\thirdarg\emptymacro
+ \let\subentry = \empty
+ \else
+ \def\subentry{ #3}%
+ \fi
+ %
+ % First process the index entry with all font commands turned
+ % off to get the string to sort by.
+ {\indexnofonts \xdef\indexsorttmp{#2\subentry}}%
+ %
+ % Now the real index entry with the fonts.
+ \toks0 = {#2}%
+ %
+ % If third (subentry) arg is present, add it to the index
+ % string. And include a space.
+ \ifx\thirdarg\emptymacro \else
+ \toks0 = \expandafter{\the\toks0 \space #3}%
+ \fi
+ %
+ % Set up the complete index entry, with both the sort key
+ % and the original text, including any font commands. We write
+ % three arguments to \entry to the .?? file, texindex reduces to
+ % two when writing the .??s sorted result.
+ \edef\temp{%
+ \write\csname#1indfile\endcsname{%
+ \realbackslash entry{\indexsorttmp}{\folio}{\the\toks0}}%
+ }%
+ %
+ % If a skip is the last thing on the list now, preserve it
+ % by backing up by \lastskip, doing the \write, then inserting
+ % the skip again. Otherwise, the whatsit generated by the
+ % \write will make \lastskip zero. The result is that sequences
+ % like this:
+ % @end defun
+ % @tindex whatever
+ % @defun ...
+ % will have extra space inserted, because the \medbreak in the
+ % start of the @defun won't see the skip inserted by the @end of
+ % the previous defun.
+ %
+ % But don't do any of this if we're not in vertical mode. We
+ % don't want to do a \vskip and prematurely end a paragraph.
+ %
+ % Avoid page breaks due to these extra skips, too.
+ %
+ \iflinks
+ \ifvmode
+ \skip0 = \lastskip
+ \ifdim\lastskip = 0pt \else \nobreak\vskip-\lastskip \fi
+ \fi
+ %
+ \temp % do the write
+ %
+ %
+ \ifvmode \ifdim\skip0 = 0pt \else \nobreak\vskip\skip0 \fi \fi
+ \fi
+ }%
+ }%
+ \penalty\count255
+ }%
+}
+
+% The index entry written in the file actually looks like
+% \entry {sortstring}{page}{topic}
+% or
+% \entry {sortstring}{page}{topic}{subtopic}
+% The texindex program reads in these files and writes files
+% containing these kinds of lines:
+% \initial {c}
+% before the first topic whose initial is c
+% \entry {topic}{pagelist}
+% for a topic that is used without subtopics
+% \primary {topic}
+% for the beginning of a topic that is used with subtopics
+% \secondary {subtopic}{pagelist}
+% for each subtopic.
+
+% Define the user-accessible indexing commands
+% @findex, @vindex, @kindex, @cindex.
+
+\def\findex {\fnindex}
+\def\kindex {\kyindex}
+\def\cindex {\cpindex}
+\def\vindex {\vrindex}
+\def\tindex {\tpindex}
+\def\pindex {\pgindex}
+
+\def\cindexsub {\begingroup\obeylines\cindexsub}
+{\obeylines %
+\gdef\cindexsub "#1" #2^^M{\endgroup %
+\dosubind{cp}{#2}{#1}}}
+
+% Define the macros used in formatting output of the sorted index material.
+
+% @printindex causes a particular index (the ??s file) to get printed.
+% It does not print any chapter heading (usually an @unnumbered).
+%
+\def\printindex{\parsearg\doprintindex}
+\def\doprintindex#1{\begingroup
+ \dobreak \chapheadingskip{10000}%
+ %
+ \indexfonts \rm
+ \tolerance = 9500
+ \indexbreaks
+ %
+ % See if the index file exists and is nonempty.
+ % Change catcode of @ here so that if the index file contains
+ % \initial {@}
+ % as its first line, TeX doesn't complain about mismatched braces
+ % (because it thinks @} is a control sequence).
+ \catcode`\@ = 11
+ \openin 1 \jobname.#1s
+ \ifeof 1
+ % \enddoublecolumns gets confused if there is no text in the index,
+ % and it loses the chapter title and the aux file entries for the
+ % index. The easiest way to prevent this problem is to make sure
+ % there is some text.
+ \putwordIndexNonexistent
+ \else
+ %
+ % If the index file exists but is empty, then \openin leaves \ifeof
+ % false. We have to make TeX try to read something from the file, so
+ % it can discover if there is anything in it.
+ \read 1 to \temp
+ \ifeof 1
+ \putwordIndexIsEmpty
+ \else
+ % Index files are almost Texinfo source, but we use \ as the escape
+ % character. It would be better to use @, but that's too big a change
+ % to make right now.
+ \def\indexbackslash{\rawbackslashxx}%
+ \catcode`\\ = 0
+ \escapechar = `\\
+ \begindoublecolumns
+ \input \jobname.#1s
+ \enddoublecolumns
+ \fi
+ \fi
+ \closein 1
+\endgroup}
+
+% These macros are used by the sorted index file itself.
+% Change them to control the appearance of the index.
+
+\def\initial#1{{%
+ % Some minor font changes for the special characters.
+ \let\tentt=\sectt \let\tt=\sectt \let\sf=\sectt
+ %
+ % Remove any glue we may have, we'll be inserting our own.
+ \removelastskip
+ %
+ % We like breaks before the index initials, so insert a bonus.
+ \penalty -300
+ %
+ % Typeset the initial. Making this add up to a whole number of
+ % baselineskips increases the chance of the dots lining up from column
+ % to column. It still won't often be perfect, because of the stretch
+ % we need before each entry, but it's better.
+ %
+ % No shrink because it confuses \balancecolumns.
+ \vskip 1.67\baselineskip plus .5\baselineskip
+ \leftline{\secbf #1}%
+ \vskip .33\baselineskip plus .1\baselineskip
+ %
+ % Do our best not to break after the initial.
+ \nobreak
+}}
+
+% This typesets a paragraph consisting of #1, dot leaders, and then #2
+% flush to the right margin. It is used for index and table of contents
+% entries. The paragraph is indented by \leftskip.
+%
+\def\entry#1#2{\begingroup
+ %
+ % Start a new paragraph if necessary, so our assignments below can't
+ % affect previous text.
+ \par
+ %
+ % Do not fill out the last line with white space.
+ \parfillskip = 0in
+ %
+ % No extra space above this paragraph.
+ \parskip = 0in
+ %
+ % Do not prefer a separate line ending with a hyphen to fewer lines.
+ \finalhyphendemerits = 0
+ %
+ % \hangindent is only relevant when the entry text and page number
+ % don't both fit on one line. In that case, bob suggests starting the
+ % dots pretty far over on the line. Unfortunately, a large
+ % indentation looks wrong when the entry text itself is broken across
+ % lines. So we use a small indentation and put up with long leaders.
+ %
+ % \hangafter is reset to 1 (which is the value we want) at the start
+ % of each paragraph, so we need not do anything with that.
+ \hangindent = 2em
+ %
+ % When the entry text needs to be broken, just fill out the first line
+ % with blank space.
+ \rightskip = 0pt plus1fil
+ %
+ % A bit of stretch before each entry for the benefit of balancing columns.
+ \vskip 0pt plus1pt
+ %
+ % Start a ``paragraph'' for the index entry so the line breaking
+ % parameters we've set above will have an effect.
+ \noindent
+ %
+ % Insert the text of the index entry. TeX will do line-breaking on it.
+ #1%
+ % The following is kludged to not output a line of dots in the index if
+ % there are no page numbers. The next person who breaks this will be
+ % cursed by a Unix daemon.
+ \def\tempa{{\rm }}%
+ \def\tempb{#2}%
+ \edef\tempc{\tempa}%
+ \edef\tempd{\tempb}%
+ \ifx\tempc\tempd\ \else%
+ %
+ % If we must, put the page number on a line of its own, and fill out
+ % this line with blank space. (The \hfil is overwhelmed with the
+ % fill leaders glue in \indexdotfill if the page number does fit.)
+ \hfil\penalty50
+ \null\nobreak\indexdotfill % Have leaders before the page number.
+ %
+ % The `\ ' here is removed by the implicit \unskip that TeX does as
+ % part of (the primitive) \par. Without it, a spurious underfull
+ % \hbox ensues.
+ \ #2% The page number ends the paragraph.
+ \fi%
+ \par
+\endgroup}
+
+% Like \dotfill except takes at least 1 em.
+\def\indexdotfill{\cleaders
+ \hbox{$\mathsurround=0pt \mkern1.5mu ${\it .}$ \mkern1.5mu$}\hskip 1em plus 1fill}
+
+\def\primary #1{\line{#1\hfil}}
+
+\newskip\secondaryindent \secondaryindent=0.5cm
+
+\def\secondary #1#2{
+{\parfillskip=0in \parskip=0in
+\hangindent =1in \hangafter=1
+\noindent\hskip\secondaryindent\hbox{#1}\indexdotfill #2\par
+}}
+
+% Define two-column mode, which we use to typeset indexes.
+% Adapted from the TeXbook, page 416, which is to say,
+% the manmac.tex format used to print the TeXbook itself.
+\catcode`\@=11
+
+\newbox\partialpage
+\newdimen\doublecolumnhsize
+
+\def\begindoublecolumns{\begingroup % ended by \enddoublecolumns
+ % Grab any single-column material above us.
+ \output = {%
+ %
+ % Here is a possibility not foreseen in manmac: if we accumulate a
+ % whole lot of material, we might end up calling this \output
+ % routine twice in a row (see the doublecol-lose test, which is
+ % essentially a couple of indexes with @setchapternewpage off). In
+ % that case we just ship out what is in \partialpage with the normal
+ % output routine. Generally, \partialpage will be empty when this
+ % runs and this will be a no-op. See the indexspread.tex test case.
+ \ifvoid\partialpage \else
+ \onepageout{\pagecontents\partialpage}%
+ \fi
+ %
+ \global\setbox\partialpage = \vbox{%
+ % Unvbox the main output page.
+ \unvbox\PAGE
+ \kern-\topskip \kern\baselineskip
+ }%
+ }%
+ \eject % run that output routine to set \partialpage
+ %
+ % Use the double-column output routine for subsequent pages.
+ \output = {\doublecolumnout}%
+ %
+ % Change the page size parameters. We could do this once outside this
+ % routine, in each of @smallbook, @afourpaper, and the default 8.5x11
+ % format, but then we repeat the same computation. Repeating a couple
+ % of assignments once per index is clearly meaningless for the
+ % execution time, so we may as well do it in one place.
+ %
+ % First we halve the line length, less a little for the gutter between
+ % the columns. We compute the gutter based on the line length, so it
+ % changes automatically with the paper format. The magic constant
+ % below is chosen so that the gutter has the same value (well, +-<1pt)
+ % as it did when we hard-coded it.
+ %
+ % We put the result in a separate register, \doublecolumhsize, so we
+ % can restore it in \pagesofar, after \hsize itself has (potentially)
+ % been clobbered.
+ %
+ \doublecolumnhsize = \hsize
+ \advance\doublecolumnhsize by -.04154\hsize
+ \divide\doublecolumnhsize by 2
+ \hsize = \doublecolumnhsize
+ %
+ % Double the \vsize as well. (We don't need a separate register here,
+ % since nobody clobbers \vsize.)
+ \advance\vsize by -\ht\partialpage
+ \vsize = 2\vsize
+}
+
+% The double-column output routine for all double-column pages except
+% the last.
+%
+\def\doublecolumnout{%
+ \splittopskip=\topskip \splitmaxdepth=\maxdepth
+ % Get the available space for the double columns -- the normal
+ % (undoubled) page height minus any material left over from the
+ % previous page.
+ \dimen@ = \vsize
+ \divide\dimen@ by 2
+ %
+ % box0 will be the left-hand column, box2 the right.
+ \setbox0=\vsplit255 to\dimen@ \setbox2=\vsplit255 to\dimen@
+ \onepageout\pagesofar
+ \unvbox255
+ \penalty\outputpenalty
+}
+\def\pagesofar{%
+ % Re-output the contents of the output page -- any previous material,
+ % followed by the two boxes we just split, in box0 and box2.
+ \unvbox\partialpage
+ %
+ \hsize = \doublecolumnhsize
+ \wd0=\hsize \wd2=\hsize
+ \hbox to\pagewidth{\box0\hfil\box2}%
+}
+\def\enddoublecolumns{%
+ \output = {%
+ % Split the last of the double-column material. Leave it on the
+ % current page, no automatic page break.
+ \balancecolumns
+ %
+ % If we end up splitting too much material for the current page,
+ % though, there will be another page break right after this \output
+ % invocation ends. Having called \balancecolumns once, we do not
+ % want to call it again. Therefore, reset \output to its normal
+ % definition right away. (We hope \balancecolumns will never be
+ % called on to balance too much material, but if it is, this makes
+ % the output somewhat more palatable.)
+ \global\output = {\onepageout{\pagecontents\PAGE}}%
+ }%
+ \eject
+ \endgroup % started in \begindoublecolumns
+ %
+ % \pagegoal was set to the doubled \vsize above, since we restarted
+ % the current page. We're now back to normal single-column
+ % typesetting, so reset \pagegoal to the normal \vsize (after the
+ % \endgroup where \vsize got restored).
+ \pagegoal = \vsize
+}
+\def\balancecolumns{%
+ % Called at the end of the double column material.
+ \setbox0 = \vbox{\unvbox255}% like \box255 but more efficient, see p.120.
+ \dimen@ = \ht0
+ \advance\dimen@ by \topskip
+ \advance\dimen@ by-\baselineskip
+ \divide\dimen@ by 2 % target to split to
+ %debug\message{final 2-column material height=\the\ht0, target=\the\dimen@.}%
+ \splittopskip = \topskip
+ % Loop until we get a decent breakpoint.
+ {%
+ \vbadness = 10000
+ \loop
+ \global\setbox3 = \copy0
+ \global\setbox1 = \vsplit3 to \dimen@
+ \ifdim\ht3>\dimen@
+ \global\advance\dimen@ by 1pt
+ \repeat
+ }%
+ %debug\message{split to \the\dimen@, column heights: \the\ht1, \the\ht3.}%
+ \setbox0=\vbox to\dimen@{\unvbox1}%
+ \setbox2=\vbox to\dimen@{\unvbox3}%
+ %
+ \pagesofar
+}
+\catcode`\@ = \other
+
+
+\message{sectioning,}
+% Chapters, sections, etc.
+
+\newcount\chapno
+\newcount\secno \secno=0
+\newcount\subsecno \subsecno=0
+\newcount\subsubsecno \subsubsecno=0
+
+% This counter is funny since it counts through charcodes of letters A, B, ...
+% The \the is necessary, despite appearances, because \appendixletter is
+% expanded while writing the .toc file. \char\appendixno is not
+% expandable, thus it is written literally, thus all appendixes come out
+% with the same letter (or @) in the toc without it.
+\newcount\appendixno \appendixno = `\@
+\def\appendixletter{\char\the\appendixno}
+
+% Each @chapter defines this as the name of the chapter.
+% page headings and footings can use it. @section does likewise.
+\def\thischapter{}
+\def\thissection{}
+
+\newcount\absseclevel % used to calculate proper heading level
+\newcount\secbase\secbase=0 % @raise/lowersections modify this count
+
+% @raisesections: treat @section as chapter, @subsection as section, etc.
+\def\raisesections{\global\advance\secbase by -1}
+\let\up=\raisesections % original BFox name
+
+% @lowersections: treat @chapter as section, @section as subsection, etc.
+\def\lowersections{\global\advance\secbase by 1}
+\let\down=\lowersections % original BFox name
+
+% Choose a numbered-heading macro
+% #1 is heading level if unmodified by @raisesections or @lowersections
+% #2 is text for heading
+\def\numhead#1#2{\absseclevel=\secbase\advance\absseclevel by #1
+\ifcase\absseclevel
+ \chapterzzz{#2}
+\or
+ \seczzz{#2}
+\or
+ \numberedsubseczzz{#2}
+\or
+ \numberedsubsubseczzz{#2}
+\else
+ \ifnum \absseclevel<0
+ \chapterzzz{#2}
+ \else
+ \numberedsubsubseczzz{#2}
+ \fi
+\fi
+}
+
+% like \numhead, but chooses appendix heading levels
+\def\apphead#1#2{\absseclevel=\secbase\advance\absseclevel by #1
+\ifcase\absseclevel
+ \appendixzzz{#2}
+\or
+ \appendixsectionzzz{#2}
+\or
+ \appendixsubseczzz{#2}
+\or
+ \appendixsubsubseczzz{#2}
+\else
+ \ifnum \absseclevel<0
+ \appendixzzz{#2}
+ \else
+ \appendixsubsubseczzz{#2}
+ \fi
+\fi
+}
+
+% like \numhead, but chooses numberless heading levels
+\def\unnmhead#1#2{\absseclevel=\secbase\advance\absseclevel by #1
+\ifcase\absseclevel
+ \unnumberedzzz{#2}
+\or
+ \unnumberedseczzz{#2}
+\or
+ \unnumberedsubseczzz{#2}
+\or
+ \unnumberedsubsubseczzz{#2}
+\else
+ \ifnum \absseclevel<0
+ \unnumberedzzz{#2}
+ \else
+ \unnumberedsubsubseczzz{#2}
+ \fi
+\fi
+}
+
+% @chapter, @appendix, @unnumbered.
+\def\thischaptername{No Chapter Title}
+\outer\def\chapter{\parsearg\chapteryyy}
+\def\chapteryyy #1{\numhead0{#1}} % normally numhead0 calls chapterzzz
+\def\chapterzzz #1{%
+\secno=0 \subsecno=0 \subsubsecno=0
+\global\advance \chapno by 1 \message{\putwordChapter\space \the\chapno}%
+\chapmacro {#1}{\the\chapno}%
+\gdef\thissection{#1}%
+\gdef\thischaptername{#1}%
+% We don't substitute the actual chapter name into \thischapter
+% because we don't want its macros evaluated now.
+\xdef\thischapter{\putwordChapter{} \the\chapno: \noexpand\thischaptername}%
+\toks0 = {#1}%
+\edef\temp{\noexpand\writetocentry{\realbackslash chapentry{\the\toks0}%
+ {\the\chapno}}}%
+\temp
+\donoderef
+\global\let\section = \numberedsec
+\global\let\subsection = \numberedsubsec
+\global\let\subsubsection = \numberedsubsubsec
+}
+
+\outer\def\appendix{\parsearg\appendixyyy}
+\def\appendixyyy #1{\apphead0{#1}} % normally apphead0 calls appendixzzz
+\def\appendixzzz #1{%
+\secno=0 \subsecno=0 \subsubsecno=0
+\global\advance \appendixno by 1
+\message{\putwordAppendix\space \appendixletter}%
+\chapmacro {#1}{\putwordAppendix{} \appendixletter}%
+\gdef\thissection{#1}%
+\gdef\thischaptername{#1}%
+\xdef\thischapter{\putwordAppendix{} \appendixletter: \noexpand\thischaptername}%
+\toks0 = {#1}%
+\edef\temp{\noexpand\writetocentry{\realbackslash chapentry{\the\toks0}%
+ {\putwordAppendix{} \appendixletter}}}%
+\temp
+\appendixnoderef
+\global\let\section = \appendixsec
+\global\let\subsection = \appendixsubsec
+\global\let\subsubsection = \appendixsubsubsec
+}
+
+% @centerchap is like @unnumbered, but the heading is centered.
+\outer\def\centerchap{\parsearg\centerchapyyy}
+\def\centerchapyyy #1{{\let\unnumbchapmacro=\centerchapmacro \unnumberedyyy{#1}}}
+
+% @top is like @unnumbered.
+\outer\def\top{\parsearg\unnumberedyyy}
+
+\outer\def\unnumbered{\parsearg\unnumberedyyy}
+\def\unnumberedyyy #1{\unnmhead0{#1}} % normally unnmhead0 calls unnumberedzzz
+\def\unnumberedzzz #1{%
+\secno=0 \subsecno=0 \subsubsecno=0
+%
+% This used to be simply \message{#1}, but TeX fully expands the
+% argument to \message. Therefore, if #1 contained @-commands, TeX
+% expanded them. For example, in `@unnumbered The @cite{Book}', TeX
+% expanded @cite (which turns out to cause errors because \cite is meant
+% to be executed, not expanded).
+%
+% Anyway, we don't want the fully-expanded definition of @cite to appear
+% as a result of the \message, we just want `@cite' itself. We use
+% \the<toks register> to achieve this: TeX expands \the<toks> only once,
+% simply yielding the contents of <toks register>. (We also do this for
+% the toc entries.)
+\toks0 = {#1}\message{(\the\toks0)}%
+%
+\unnumbchapmacro {#1}%
+\gdef\thischapter{#1}\gdef\thissection{#1}%
+\toks0 = {#1}%
+\edef\temp{\noexpand\writetocentry{\realbackslash unnumbchapentry{\the\toks0}}}%
+\temp
+\unnumbnoderef
+\global\let\section = \unnumberedsec
+\global\let\subsection = \unnumberedsubsec
+\global\let\subsubsection = \unnumberedsubsubsec
+}
+
+% Sections.
+\outer\def\numberedsec{\parsearg\secyyy}
+\def\secyyy #1{\numhead1{#1}} % normally calls seczzz
+\def\seczzz #1{%
+\subsecno=0 \subsubsecno=0 \global\advance \secno by 1 %
+\gdef\thissection{#1}\secheading {#1}{\the\chapno}{\the\secno}%
+\toks0 = {#1}%
+\edef\temp{\noexpand\writetocentry{\realbackslash secentry{\the\toks0}%
+ {\the\chapno}{\the\secno}}}%
+\temp
+\donoderef
+\nobreak
+}
+
+\outer\def\appendixsection{\parsearg\appendixsecyyy}
+\outer\def\appendixsec{\parsearg\appendixsecyyy}
+\def\appendixsecyyy #1{\apphead1{#1}} % normally calls appendixsectionzzz
+\def\appendixsectionzzz #1{%
+\subsecno=0 \subsubsecno=0 \global\advance \secno by 1 %
+\gdef\thissection{#1}\secheading {#1}{\appendixletter}{\the\secno}%
+\toks0 = {#1}%
+\edef\temp{\noexpand\writetocentry{\realbackslash secentry{\the\toks0}%
+ {\appendixletter}{\the\secno}}}%
+\temp
+\appendixnoderef
+\nobreak
+}
+
+\outer\def\unnumberedsec{\parsearg\unnumberedsecyyy}
+\def\unnumberedsecyyy #1{\unnmhead1{#1}} % normally calls unnumberedseczzz
+\def\unnumberedseczzz #1{%
+\plainsecheading {#1}\gdef\thissection{#1}%
+\toks0 = {#1}%
+\edef\temp{\noexpand\writetocentry{\realbackslash unnumbsecentry{\the\toks0}}}%
+\temp
+\unnumbnoderef
+\nobreak
+}
+
+% Subsections.
+\outer\def\numberedsubsec{\parsearg\numberedsubsecyyy}
+\def\numberedsubsecyyy #1{\numhead2{#1}} % normally calls numberedsubseczzz
+\def\numberedsubseczzz #1{%
+\gdef\thissection{#1}\subsubsecno=0 \global\advance \subsecno by 1 %
+\subsecheading {#1}{\the\chapno}{\the\secno}{\the\subsecno}%
+\toks0 = {#1}%
+\edef\temp{\noexpand\writetocentry{\realbackslash subsecentry{\the\toks0}%
+ {\the\chapno}{\the\secno}{\the\subsecno}}}%
+\temp
+\donoderef
+\nobreak
+}
+
+\outer\def\appendixsubsec{\parsearg\appendixsubsecyyy}
+\def\appendixsubsecyyy #1{\apphead2{#1}} % normally calls appendixsubseczzz
+\def\appendixsubseczzz #1{%
+\gdef\thissection{#1}\subsubsecno=0 \global\advance \subsecno by 1 %
+\subsecheading {#1}{\appendixletter}{\the\secno}{\the\subsecno}%
+\toks0 = {#1}%
+\edef\temp{\noexpand\writetocentry{\realbackslash subsecentry{\the\toks0}%
+ {\appendixletter}{\the\secno}{\the\subsecno}}}%
+\temp
+\appendixnoderef
+\nobreak
+}
+
+\outer\def\unnumberedsubsec{\parsearg\unnumberedsubsecyyy}
+\def\unnumberedsubsecyyy #1{\unnmhead2{#1}} %normally calls unnumberedsubseczzz
+\def\unnumberedsubseczzz #1{%
+\plainsubsecheading {#1}\gdef\thissection{#1}%
+\toks0 = {#1}%
+\edef\temp{\noexpand\writetocentry{\realbackslash unnumbsubsecentry%
+ {\the\toks0}}}%
+\temp
+\unnumbnoderef
+\nobreak
+}
+
+% Subsubsections.
+\outer\def\numberedsubsubsec{\parsearg\numberedsubsubsecyyy}
+\def\numberedsubsubsecyyy #1{\numhead3{#1}} % normally numberedsubsubseczzz
+\def\numberedsubsubseczzz #1{%
+\gdef\thissection{#1}\global\advance \subsubsecno by 1 %
+\subsubsecheading {#1}
+ {\the\chapno}{\the\secno}{\the\subsecno}{\the\subsubsecno}%
+\toks0 = {#1}%
+\edef\temp{\noexpand\writetocentry{\realbackslash subsubsecentry{\the\toks0}%
+ {\the\chapno}{\the\secno}{\the\subsecno}{\the\subsubsecno}}}%
+\temp
+\donoderef
+\nobreak
+}
+
+\outer\def\appendixsubsubsec{\parsearg\appendixsubsubsecyyy}
+\def\appendixsubsubsecyyy #1{\apphead3{#1}} % normally appendixsubsubseczzz
+\def\appendixsubsubseczzz #1{%
+\gdef\thissection{#1}\global\advance \subsubsecno by 1 %
+\subsubsecheading {#1}
+ {\appendixletter}{\the\secno}{\the\subsecno}{\the\subsubsecno}%
+\toks0 = {#1}%
+\edef\temp{\noexpand\writetocentry{\realbackslash subsubsecentry{\the\toks0}%
+ {\appendixletter}{\the\secno}{\the\subsecno}{\the\subsubsecno}}}%
+\temp
+\appendixnoderef
+\nobreak
+}
+
+\outer\def\unnumberedsubsubsec{\parsearg\unnumberedsubsubsecyyy}
+\def\unnumberedsubsubsecyyy #1{\unnmhead3{#1}} %normally unnumberedsubsubseczzz
+\def\unnumberedsubsubseczzz #1{%
+\plainsubsubsecheading {#1}\gdef\thissection{#1}%
+\toks0 = {#1}%
+\edef\temp{\noexpand\writetocentry{\realbackslash unnumbsubsubsecentry%
+ {\the\toks0}}}%
+\temp
+\unnumbnoderef
+\nobreak
+}
+
+% These are variants which are not "outer", so they can appear in @ifinfo.
+% Actually, they should now be obsolete; ordinary section commands should work.
+\def\infotop{\parsearg\unnumberedzzz}
+\def\infounnumbered{\parsearg\unnumberedzzz}
+\def\infounnumberedsec{\parsearg\unnumberedseczzz}
+\def\infounnumberedsubsec{\parsearg\unnumberedsubseczzz}
+\def\infounnumberedsubsubsec{\parsearg\unnumberedsubsubseczzz}
+
+\def\infoappendix{\parsearg\appendixzzz}
+\def\infoappendixsec{\parsearg\appendixseczzz}
+\def\infoappendixsubsec{\parsearg\appendixsubseczzz}
+\def\infoappendixsubsubsec{\parsearg\appendixsubsubseczzz}
+
+\def\infochapter{\parsearg\chapterzzz}
+\def\infosection{\parsearg\sectionzzz}
+\def\infosubsection{\parsearg\subsectionzzz}
+\def\infosubsubsection{\parsearg\subsubsectionzzz}
+
+% These macros control what the section commands do, according
+% to what kind of chapter we are in (ordinary, appendix, or unnumbered).
+% Define them by default for a numbered chapter.
+\global\let\section = \numberedsec
+\global\let\subsection = \numberedsubsec
+\global\let\subsubsection = \numberedsubsubsec
+
+% Define @majorheading, @heading and @subheading
+
+% NOTE on use of \vbox for chapter headings, section headings, and such:
+% 1) We use \vbox rather than the earlier \line to permit
+% overlong headings to fold.
+% 2) \hyphenpenalty is set to 10000 because hyphenation in a
+% heading is obnoxious; this forbids it.
+% 3) Likewise, headings look best if no \parindent is used, and
+% if justification is not attempted. Hence \raggedright.
+
+
+\def\majorheading{\parsearg\majorheadingzzz}
+\def\majorheadingzzz #1{%
+{\advance\chapheadingskip by 10pt \chapbreak }%
+{\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000
+ \parindent=0pt\raggedright
+ \rm #1\hfill}}\bigskip \par\penalty 200}
+
+\def\chapheading{\parsearg\chapheadingzzz}
+\def\chapheadingzzz #1{\chapbreak %
+{\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000
+ \parindent=0pt\raggedright
+ \rm #1\hfill}}\bigskip \par\penalty 200}
+
+% @heading, @subheading, @subsubheading.
+\def\heading{\parsearg\plainsecheading}
+\def\subheading{\parsearg\plainsubsecheading}
+\def\subsubheading{\parsearg\plainsubsubsecheading}
+
+% These macros generate a chapter, section, etc. heading only
+% (including whitespace, linebreaking, etc. around it),
+% given all the information in convenient, parsed form.
+
+%%% Args are the skip and penalty (usually negative)
+\def\dobreak#1#2{\par\ifdim\lastskip<#1\removelastskip\penalty#2\vskip#1\fi}
+
+\def\setchapterstyle #1 {\csname CHAPF#1\endcsname}
+
+%%% Define plain chapter starts, and page on/off switching for it
+% Parameter controlling skip before chapter headings (if needed)
+
+\newskip\chapheadingskip
+
+\def\chapbreak{\dobreak \chapheadingskip {-4000}}
+\def\chappager{\par\vfill\supereject}
+\def\chapoddpage{\chappager \ifodd\pageno \else \hbox to 0pt{} \chappager\fi}
+
+\def\setchapternewpage #1 {\csname CHAPPAG#1\endcsname}
+
+\def\CHAPPAGoff{%
+\global\let\contentsalignmacro = \chappager
+\global\let\pchapsepmacro=\chapbreak
+\global\let\pagealignmacro=\chappager}
+
+\def\CHAPPAGon{%
+\global\let\contentsalignmacro = \chappager
+\global\let\pchapsepmacro=\chappager
+\global\let\pagealignmacro=\chappager
+\global\def\HEADINGSon{\HEADINGSsingle}}
+
+\def\CHAPPAGodd{
+\global\let\contentsalignmacro = \chapoddpage
+\global\let\pchapsepmacro=\chapoddpage
+\global\let\pagealignmacro=\chapoddpage
+\global\def\HEADINGSon{\HEADINGSdouble}}
+
+\CHAPPAGon
+
+\def\CHAPFplain{
+\global\let\chapmacro=\chfplain
+\global\let\unnumbchapmacro=\unnchfplain
+\global\let\centerchapmacro=\centerchfplain}
+
+% Plain chapter opening.
+% #1 is the text, #2 the chapter number or empty if unnumbered.
+\def\chfplain#1#2{%
+ \pchapsepmacro
+ {%
+ \chapfonts \rm
+ \def\chapnum{#2}%
+ \setbox0 = \hbox{#2\ifx\chapnum\empty\else\enspace\fi}%
+ \vbox{\hyphenpenalty=10000 \tolerance=5000 \parindent=0pt \raggedright
+ \hangindent = \wd0 \centerparametersmaybe
+ \unhbox0 #1\par}%
+ }%
+ \nobreak\bigskip % no page break after a chapter title
+ \nobreak
+}
+
+% Plain opening for unnumbered.
+\def\unnchfplain#1{\chfplain{#1}{}}
+
+% @centerchap -- centered and unnumbered.
+\let\centerparametersmaybe = \relax
+\def\centerchfplain#1{{%
+ \def\centerparametersmaybe{%
+ \advance\rightskip by 3\rightskip
+ \leftskip = \rightskip
+ \parfillskip = 0pt
+ }%
+ \chfplain{#1}{}%
+}}
+
+\CHAPFplain % The default
+
+\def\unnchfopen #1{%
+\chapoddpage {\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000
+ \parindent=0pt\raggedright
+ \rm #1\hfill}}\bigskip \par\nobreak
+}
+
+\def\chfopen #1#2{\chapoddpage {\chapfonts
+\vbox to 3in{\vfil \hbox to\hsize{\hfil #2} \hbox to\hsize{\hfil #1} \vfil}}%
+\par\penalty 5000 %
+}
+
+\def\centerchfopen #1{%
+\chapoddpage {\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000
+ \parindent=0pt
+ \hfill {\rm #1}\hfill}}\bigskip \par\nobreak
+}
+
+\def\CHAPFopen{
+\global\let\chapmacro=\chfopen
+\global\let\unnumbchapmacro=\unnchfopen
+\global\let\centerchapmacro=\centerchfopen}
+
+
+% Section titles.
+\newskip\secheadingskip
+\def\secheadingbreak{\dobreak \secheadingskip {-1000}}
+\def\secheading#1#2#3{\sectionheading{sec}{#2.#3}{#1}}
+\def\plainsecheading#1{\sectionheading{sec}{}{#1}}
+
+% Subsection titles.
+\newskip \subsecheadingskip
+\def\subsecheadingbreak{\dobreak \subsecheadingskip {-500}}
+\def\subsecheading#1#2#3#4{\sectionheading{subsec}{#2.#3.#4}{#1}}
+\def\plainsubsecheading#1{\sectionheading{subsec}{}{#1}}
+
+% Subsubsection titles.
+\let\subsubsecheadingskip = \subsecheadingskip
+\let\subsubsecheadingbreak = \subsecheadingbreak
+\def\subsubsecheading#1#2#3#4#5{\sectionheading{subsubsec}{#2.#3.#4.#5}{#1}}
+\def\plainsubsubsecheading#1{\sectionheading{subsubsec}{}{#1}}
+
+
+% Print any size section title.
+%
+% #1 is the section type (sec/subsec/subsubsec), #2 is the section
+% number (maybe empty), #3 the text.
+\def\sectionheading#1#2#3{%
+ {%
+ \expandafter\advance\csname #1headingskip\endcsname by \parskip
+ \csname #1headingbreak\endcsname
+ }%
+ {%
+ % Switch to the right set of fonts.
+ \csname #1fonts\endcsname \rm
+ %
+ % Only insert the separating space if we have a section number.
+ \def\secnum{#2}%
+ \setbox0 = \hbox{#2\ifx\secnum\empty\else\enspace\fi}%
+ %
+ \vbox{\hyphenpenalty=10000 \tolerance=5000 \parindent=0pt \raggedright
+ \hangindent = \wd0 % zero if no section number
+ \unhbox0 #3}%
+ }%
+ \ifdim\parskip<10pt \nobreak\kern10pt\nobreak\kern-\parskip\fi \nobreak
+}
+
+
+\message{toc,}
+% Table of contents.
+\newwrite\tocfile
+
+% Write an entry to the toc file, opening it if necessary.
+% Called from @chapter, etc. We supply {\folio} at the end of the
+% argument, which will end up as the last argument to the \...entry macro.
+%
+% We open the .toc file here instead of at @setfilename or any other
+% given time so that @contents can be put in the document anywhere.
+%
+\newif\iftocfileopened
+\def\writetocentry#1{%
+ \iftocfileopened\else
+ \immediate\openout\tocfile = \jobname.toc
+ \global\tocfileopenedtrue
+ \fi
+ \iflinks \write\tocfile{#1{\folio}}\fi
+}
+
+\newskip\contentsrightmargin \contentsrightmargin=1in
+\newcount\savepageno
+\newcount\lastnegativepageno \lastnegativepageno = -1
+
+% Finish up the main text and prepare to read what we've written
+% to \tocfile.
+%
+\def\startcontents#1{%
+ % If @setchapternewpage on, and @headings double, the contents should
+ % start on an odd page, unlike chapters. Thus, we maintain
+ % \contentsalignmacro in parallel with \pagealignmacro.
+ % From: Torbjorn Granlund <tege@matematik.su.se>
+ \contentsalignmacro
+ \immediate\closeout\tocfile
+ %
+ % Don't need to put `Contents' or `Short Contents' in the headline.
+ % It is abundantly clear what they are.
+ \unnumbchapmacro{#1}\def\thischapter{}%
+ \savepageno = \pageno
+ \begingroup % Set up to handle contents files properly.
+ \catcode`\\=0 \catcode`\{=1 \catcode`\}=2 \catcode`\@=11
+ % We can't do this, because then an actual ^ in a section
+ % title fails, e.g., @chapter ^ -- exponentiation. --karl, 9jul97.
+ %\catcode`\^=7 % to see ^^e4 as \"a etc. juha@piuha.ydi.vtt.fi
+ \raggedbottom % Worry more about breakpoints than the bottom.
+ \advance\hsize by -\contentsrightmargin % Don't use the full line length.
+ %
+ % Roman numerals for page numbers.
+ \ifnum \pageno>0 \pageno = \lastnegativepageno \fi
+}
+
+
+% Normal (long) toc.
+\def\contents{%
+ \startcontents{\putwordTOC}%
+ \openin 1 \jobname.toc
+ \ifeof 1 \else
+ \closein 1
+ \input \jobname.toc
+ \fi
+ \vfill \eject
+ \contentsalignmacro % in case @setchapternewpage odd is in effect
+ \endgroup
+ \lastnegativepageno = \pageno
+ \pageno = \savepageno
+}
+
+% And just the chapters.
+\def\summarycontents{%
+ \startcontents{\putwordShortTOC}%
+ %
+ \let\chapentry = \shortchapentry
+ \let\unnumbchapentry = \shortunnumberedentry
+ % We want a true roman here for the page numbers.
+ \secfonts
+ \let\rm=\shortcontrm \let\bf=\shortcontbf \let\sl=\shortcontsl
+ \rm
+ \hyphenpenalty = 10000
+ \advance\baselineskip by 1pt % Open it up a little.
+ \def\secentry ##1##2##3##4{}
+ \def\unnumbsecentry ##1##2{}
+ \def\subsecentry ##1##2##3##4##5{}
+ \def\unnumbsubsecentry ##1##2{}
+ \def\subsubsecentry ##1##2##3##4##5##6{}
+ \def\unnumbsubsubsecentry ##1##2{}
+ \openin 1 \jobname.toc
+ \ifeof 1 \else
+ \closein 1
+ \input \jobname.toc
+ \fi
+ \vfill \eject
+ \contentsalignmacro % in case @setchapternewpage odd is in effect
+ \endgroup
+ \lastnegativepageno = \pageno
+ \pageno = \savepageno
+}
+\let\shortcontents = \summarycontents
+
+\ifpdf
+ \pdfcatalog{/PageMode /UseOutlines}%
+\fi
+
+% These macros generate individual entries in the table of contents.
+% The first argument is the chapter or section name.
+% The last argument is the page number.
+% The arguments in between are the chapter number, section number, ...
+
+% Chapter-level things, for both the long and short contents.
+\def\chapentry#1#2#3{\dochapentry{#2\labelspace#1}{#3}}
+
+% See comments in \dochapentry re vbox and related settings
+\def\shortchapentry#1#2#3{%
+ \tocentry{\shortchaplabel{#2}\labelspace #1}{\doshortpageno{#3}}%
+}
+
+% Typeset the label for a chapter or appendix for the short contents.
+% The arg is, e.g. `Appendix A' for an appendix, or `3' for a chapter.
+% We could simplify the code here by writing out an \appendixentry
+% command in the toc file for appendices, instead of using \chapentry
+% for both, but it doesn't seem worth it.
+\setbox0 = \hbox{\shortcontrm \putwordAppendix }
+\newdimen\shortappendixwidth \shortappendixwidth = \wd0
+
+\def\shortchaplabel#1{%
+ % We typeset #1 in a box of constant width, regardless of the text of
+ % #1, so the chapter titles will come out aligned.
+ \setbox0 = \hbox{#1}%
+ \dimen0 = \ifdim\wd0 > \shortappendixwidth \shortappendixwidth \else 0pt \fi
+ %
+ % This space should be plenty, since a single number is .5em, and the
+ % widest letter (M) is 1em, at least in the Computer Modern fonts.
+ % (This space doesn't include the extra space that gets added after
+ % the label; that gets put in by \shortchapentry above.)
+ \advance\dimen0 by 1.1em
+ \hbox to \dimen0{#1\hfil}%
+}
+
+\def\unnumbchapentry#1#2{\dochapentry{#1}{#2}}
+\def\shortunnumberedentry#1#2{\tocentry{#1}{\doshortpageno{#2}}}
+
+% Sections.
+\def\secentry#1#2#3#4{\dosecentry{#2.#3\labelspace#1}{#4}}
+\def\unnumbsecentry#1#2{\dosecentry{#1}{#2}}
+
+% Subsections.
+\def\subsecentry#1#2#3#4#5{\dosubsecentry{#2.#3.#4\labelspace#1}{#5}}
+\def\unnumbsubsecentry#1#2{\dosubsecentry{#1}{#2}}
+
+% And subsubsections.
+\def\subsubsecentry#1#2#3#4#5#6{%
+ \dosubsubsecentry{#2.#3.#4.#5\labelspace#1}{#6}}
+\def\unnumbsubsubsecentry#1#2{\dosubsubsecentry{#1}{#2}}
+
+% This parameter controls the indentation of the various levels.
+\newdimen\tocindent \tocindent = 3pc
+
+% Now for the actual typesetting. In all these, #1 is the text and #2 is the
+% page number.
+%
+% If the toc has to be broken over pages, we want it to be at chapters
+% if at all possible; hence the \penalty.
+\def\dochapentry#1#2{%
+ \penalty-300 \vskip1\baselineskip plus.33\baselineskip minus.25\baselineskip
+ \begingroup
+ \chapentryfonts
+ \tocentry{#1}{\dopageno{#2}}%
+ \endgroup
+ \nobreak\vskip .25\baselineskip plus.1\baselineskip
+}
+
+\def\dosecentry#1#2{\begingroup
+ \secentryfonts \leftskip=\tocindent
+ \tocentry{#1}{\dopageno{#2}}%
+\endgroup}
+
+\def\dosubsecentry#1#2{\begingroup
+ \subsecentryfonts \leftskip=2\tocindent
+ \tocentry{#1}{\dopageno{#2}}%
+\endgroup}
+
+\def\dosubsubsecentry#1#2{\begingroup
+ \subsubsecentryfonts \leftskip=3\tocindent
+ \tocentry{#1}{\dopageno{#2}}%
+\endgroup}
+
+% Final typesetting of a toc entry; we use the same \entry macro as for
+% the index entries, but we want to suppress hyphenation here. (We
+% can't do that in the \entry macro, since index entries might consist
+% of hyphenated-identifiers-that-do-not-fit-on-a-line-and-nothing-else.)
+\def\tocentry#1#2{\begingroup
+ \vskip 0pt plus1pt % allow a little stretch for the sake of nice page breaks
+ % Do not use \turnoffactive in these arguments. Since the toc is
+ % typeset in cmr, so characters such as _ would come out wrong; we
+ % have to do the usual translation tricks.
+ \entry{#1}{#2}%
+\endgroup}
+
+% Space between chapter (or whatever) number and the title.
+\def\labelspace{\hskip1em \relax}
+
+\def\dopageno#1{{\rm #1}}
+\def\doshortpageno#1{{\rm #1}}
+
+\def\chapentryfonts{\secfonts \rm}
+\def\secentryfonts{\textfonts}
+\let\subsecentryfonts = \textfonts
+\let\subsubsecentryfonts = \textfonts
+
+
+\message{environments,}
+% @foo ... @end foo.
+
+% Since these characters are used in examples, it should be an even number of
+% \tt widths. Each \tt character is 1en, so two makes it 1em.
+% Furthermore, these definitions must come after we define our fonts.
+\newbox\dblarrowbox \newbox\longdblarrowbox
+\newbox\pushcharbox \newbox\bullbox
+\newbox\equivbox \newbox\errorbox
+
+%{\tentt
+%\global\setbox\dblarrowbox = \hbox to 1em{\hfil$\Rightarrow$\hfil}
+%\global\setbox\longdblarrowbox = \hbox to 1em{\hfil$\mapsto$\hfil}
+%\global\setbox\pushcharbox = \hbox to 1em{\hfil$\dashv$\hfil}
+%\global\setbox\equivbox = \hbox to 1em{\hfil$\ptexequiv$\hfil}
+% Adapted from the manmac format (p.420 of TeXbook)
+%\global\setbox\bullbox = \hbox to 1em{\kern.15em\vrule height .75ex width .85ex
+% depth .1ex\hfil}
+%}
+
+% @point{}, @result{}, @expansion{}, @print{}, @equiv{}.
+\def\point{$\star$}
+\def\result{\leavevmode\raise.15ex\hbox to 1em{\hfil$\Rightarrow$\hfil}}
+\def\expansion{\leavevmode\raise.1ex\hbox to 1em{\hfil$\mapsto$\hfil}}
+\def\print{\leavevmode\lower.1ex\hbox to 1em{\hfil$\dashv$\hfil}}
+\def\equiv{\leavevmode\lower.1ex\hbox to 1em{\hfil$\ptexequiv$\hfil}}
+
+% Adapted from the TeXbook's \boxit.
+{\tentt \global\dimen0 = 3em}% Width of the box.
+\dimen2 = .55pt % Thickness of rules
+% The text. (`r' is open on the right, `e' somewhat less so on the left.)
+\setbox0 = \hbox{\kern-.75pt \tensf error\kern-1.5pt}
+
+\global\setbox\errorbox=\hbox to \dimen0{\hfil
+ \hsize = \dimen0 \advance\hsize by -5.8pt % Space to left+right.
+ \advance\hsize by -2\dimen2 % Rules.
+ \vbox{
+ \hrule height\dimen2
+ \hbox{\vrule width\dimen2 \kern3pt % Space to left of text.
+ \vtop{\kern2.4pt \box0 \kern2.4pt}% Space above/below.
+ \kern3pt\vrule width\dimen2}% Space to right.
+ \hrule height\dimen2}
+ \hfil}
+
+% The @error{} command.
+\def\error{\leavevmode\lower.7ex\copy\errorbox}
+
+% @tex ... @end tex escapes into raw Tex temporarily.
+% One exception: @ is still an escape character, so that @end tex works.
+% But \@ or @@ will get a plain tex @ character.
+
+\def\tex{\begingroup
+ \catcode `\\=0 \catcode `\{=1 \catcode `\}=2
+ \catcode `\$=3 \catcode `\&=4 \catcode `\#=6
+ \catcode `\^=7 \catcode `\_=8 \catcode `\~=13 \let~=\tie
+ \catcode `\%=14
+ \catcode 43=12 % plus
+ \catcode`\"=12
+ \catcode`\==12
+ \catcode`\|=12
+ \catcode`\<=12
+ \catcode`\>=12
+ \escapechar=`\\
+ %
+ \let\b=\ptexb
+ \let\bullet=\ptexbullet
+ \let\c=\ptexc
+ \let\,=\ptexcomma
+ \let\.=\ptexdot
+ \let\dots=\ptexdots
+ \let\equiv=\ptexequiv
+ \let\!=\ptexexclam
+ \let\i=\ptexi
+ \let\{=\ptexlbrace
+ \let\+=\tabalign
+ \let\}=\ptexrbrace
+ \let\*=\ptexstar
+ \let\t=\ptext
+ %
+ \def\endldots{\mathinner{\ldots\ldots\ldots\ldots}}%
+ \def\enddots{\relax\ifmmode\endldots\else$\mathsurround=0pt \endldots\,$\fi}%
+ \def\@{@}%
+\let\Etex=\endgroup}
+
+% Define @lisp ... @endlisp.
+% @lisp does a \begingroup so it can rebind things,
+% including the definition of @endlisp (which normally is erroneous).
+
+% Amount to narrow the margins by for @lisp.
+\newskip\lispnarrowing \lispnarrowing=0.4in
+
+% This is the definition that ^^M gets inside @lisp, @example, and other
+% such environments. \null is better than a space, since it doesn't
+% have any width.
+\def\lisppar{\null\endgraf}
+
+% Make each space character in the input produce a normal interword
+% space in the output. Don't allow a line break at this space, as this
+% is used only in environments like @example, where each line of input
+% should produce a line of output anyway.
+%
+{\obeyspaces %
+\gdef\sepspaces{\obeyspaces\let =\tie}}
+
+% Define \obeyedspace to be our active space, whatever it is. This is
+% for use in \parsearg.
+{\sepspaces%
+\global\let\obeyedspace= }
+
+% This space is always present above and below environments.
+\newskip\envskipamount \envskipamount = 0pt
+
+% Make spacing and below environment symmetrical. We use \parskip here
+% to help in doing that, since in @example-like environments \parskip
+% is reset to zero; thus the \afterenvbreak inserts no space -- but the
+% start of the next paragraph will insert \parskip
+%
+\def\aboveenvbreak{{\advance\envskipamount by \parskip
+\endgraf \ifdim\lastskip<\envskipamount
+\removelastskip \penalty-50 \vskip\envskipamount \fi}}
+
+\let\afterenvbreak = \aboveenvbreak
+
+% \nonarrowing is a flag. If "set", @lisp etc don't narrow margins.
+\let\nonarrowing=\relax
+
+% @cartouche ... @end cartouche: draw rectangle w/rounded corners around
+% environment contents.
+\font\circle=lcircle10
+\newdimen\circthick
+\newdimen\cartouter\newdimen\cartinner
+\newskip\normbskip\newskip\normpskip\newskip\normlskip
+\circthick=\fontdimen8\circle
+%
+\def\ctl{{\circle\char'013\hskip -6pt}}% 6pt from pl file: 1/2charwidth
+\def\ctr{{\hskip 6pt\circle\char'010}}
+\def\cbl{{\circle\char'012\hskip -6pt}}
+\def\cbr{{\hskip 6pt\circle\char'011}}
+\def\carttop{\hbox to \cartouter{\hskip\lskip
+ \ctl\leaders\hrule height\circthick\hfil\ctr
+ \hskip\rskip}}
+\def\cartbot{\hbox to \cartouter{\hskip\lskip
+ \cbl\leaders\hrule height\circthick\hfil\cbr
+ \hskip\rskip}}
+%
+\newskip\lskip\newskip\rskip
+
+\long\def\cartouche{%
+\begingroup
+ \lskip=\leftskip \rskip=\rightskip
+ \leftskip=0pt\rightskip=0pt %we want these *outside*.
+ \cartinner=\hsize \advance\cartinner by-\lskip
+ \advance\cartinner by-\rskip
+ \cartouter=\hsize
+ \advance\cartouter by 18.4pt % allow for 3pt kerns on either
+% side, and for 6pt waste from
+% each corner char, and rule thickness
+ \normbskip=\baselineskip \normpskip=\parskip \normlskip=\lineskip
+ % Flag to tell @lisp, etc., not to narrow margin.
+ \let\nonarrowing=\comment
+ \vbox\bgroup
+ \baselineskip=0pt\parskip=0pt\lineskip=0pt
+ \carttop
+ \hbox\bgroup
+ \hskip\lskip
+ \vrule\kern3pt
+ \vbox\bgroup
+ \hsize=\cartinner
+ \kern3pt
+ \begingroup
+ \baselineskip=\normbskip
+ \lineskip=\normlskip
+ \parskip=\normpskip
+ \vskip -\parskip
+\def\Ecartouche{%
+ \endgroup
+ \kern3pt
+ \egroup
+ \kern3pt\vrule
+ \hskip\rskip
+ \egroup
+ \cartbot
+ \egroup
+\endgroup
+}}
+
+
+% This macro is called at the beginning of all the @example variants,
+% inside a group.
+\def\nonfillstart{%
+ \aboveenvbreak
+ \inENV % This group ends at the end of the body
+ \hfuzz = 12pt % Don't be fussy
+ \sepspaces % Make spaces be word-separators rather than space tokens.
+ \singlespace
+ \let\par = \lisppar % don't ignore blank lines
+ \obeylines % each line of input is a line of output
+ \parskip = 0pt
+ \parindent = 0pt
+ \emergencystretch = 0pt % don't try to avoid overfull boxes
+ % @cartouche defines \nonarrowing to inhibit narrowing
+ % at next level down.
+ \ifx\nonarrowing\relax
+ \advance \leftskip by \lispnarrowing
+ \exdentamount=\lispnarrowing
+ \let\exdent=\nofillexdent
+ \let\nonarrowing=\relax
+ \fi
+}
+
+% Define the \E... control sequence only if we are inside the particular
+% environment, so the error checking in \end will work.
+%
+% To end an @example-like environment, we first end the paragraph (via
+% \afterenvbreak's vertical glue), and then the group. That way we keep
+% the zero \parskip that the environments set -- \parskip glue will be
+% inserted at the beginning of the next paragraph in the document, after
+% the environment.
+%
+\def\nonfillfinish{\afterenvbreak\endgroup}
+
+% @lisp: indented, narrowed, typewriter font.
+\def\lisp{\begingroup
+ \nonfillstart
+ \let\Elisp = \nonfillfinish
+ \tt
+ \let\kbdfont = \kbdexamplefont % Allow @kbd to do something special.
+ \gobble % eat return
+}
+
+% @example: Same as @lisp.
+\def\example{\begingroup \def\Eexample{\nonfillfinish\endgroup}\lisp}
+
+% @small... is usually equivalent to the non-small (@smallbook
+% redefines). We must call \example (or whatever) last in the
+% definition, since it reads the return following the @example (or
+% whatever) command.
+%
+% This actually allows (for example) @end display inside an
+% @smalldisplay. Too bad, but makeinfo will catch the error anyway.
+%
+\def\smalldisplay{\begingroup\def\Esmalldisplay{\nonfillfinish\endgroup}\display}
+\def\smallexample{\begingroup\def\Esmallexample{\nonfillfinish\endgroup}\lisp}
+\def\smallformat{\begingroup\def\Esmallformat{\nonfillfinish\endgroup}\format}
+\def\smalllisp{\begingroup\def\Esmalllisp{\nonfillfinish\endgroup}\lisp}
+
+% Real @smallexample and @smalllisp (when @smallbook): use smaller fonts.
+% Originally contributed by Pavel@xerox.
+\def\smalllispx{\begingroup
+ \def\Esmalllisp{\nonfillfinish\endgroup}%
+ \def\Esmallexample{\nonfillfinish\endgroup}%
+ \indexfonts
+ \lisp
+}
+
+% @display: same as @lisp except keep current font.
+%
+\def\display{\begingroup
+ \nonfillstart
+ \let\Edisplay = \nonfillfinish
+ \gobble
+}
+
+% @smalldisplay (when @smallbook): @display plus smaller fonts.
+%
+\def\smalldisplayx{\begingroup
+ \def\Esmalldisplay{\nonfillfinish\endgroup}%
+ \indexfonts \rm
+ \display
+}
+
+% @format: same as @display except don't narrow margins.
+%
+\def\format{\begingroup
+ \let\nonarrowing = t
+ \nonfillstart
+ \let\Eformat = \nonfillfinish
+ \gobble
+}
+
+% @smallformat (when @smallbook): @format plus smaller fonts.
+%
+\def\smallformatx{\begingroup
+ \def\Esmallformat{\nonfillfinish\endgroup}%
+ \indexfonts \rm
+ \format
+}
+
+% @flushleft (same as @format).
+%
+\def\flushleft{\begingroup \def\Eflushleft{\nonfillfinish\endgroup}\format}
+
+% @flushright.
+%
+\def\flushright{\begingroup
+ \let\nonarrowing = t
+ \nonfillstart
+ \let\Eflushright = \nonfillfinish
+ \advance\leftskip by 0pt plus 1fill
+ \gobble
+}
+
+% @quotation does normal linebreaking (hence we can't use \nonfillstart)
+% and narrows the margins.
+%
+\def\quotation{%
+ \begingroup\inENV %This group ends at the end of the @quotation body
+ {\parskip=0pt \aboveenvbreak}% because \aboveenvbreak inserts \parskip
+ \singlespace
+ \parindent=0pt
+ % We have retained a nonzero parskip for the environment, since we're
+ % doing normal filling. So to avoid extra space below the environment...
+ \def\Equotation{\parskip = 0pt \nonfillfinish}%
+ %
+ % @cartouche defines \nonarrowing to inhibit narrowing at next level down.
+ \ifx\nonarrowing\relax
+ \advance\leftskip by \lispnarrowing
+ \advance\rightskip by \lispnarrowing
+ \exdentamount = \lispnarrowing
+ \let\nonarrowing = \relax
+ \fi
+}
+
+
+\message{defuns,}
+% @defun etc.
+
+% Allow user to change definition object font (\df) internally
+\def\setdeffont #1 {\csname DEF#1\endcsname}
+
+\newskip\defbodyindent \defbodyindent=.4in
+\newskip\defargsindent \defargsindent=50pt
+\newskip\deftypemargin \deftypemargin=12pt
+\newskip\deflastargmargin \deflastargmargin=18pt
+
+\newcount\parencount
+% define \functionparens, which makes ( and ) and & do special things.
+% \functionparens affects the group it is contained in.
+\def\activeparens{%
+\catcode`\(=\active \catcode`\)=\active \catcode`\&=\active
+\catcode`\[=\active \catcode`\]=\active}
+
+% Make control sequences which act like normal parenthesis chars.
+\let\lparen = ( \let\rparen = )
+
+{\activeparens % Now, smart parens don't turn on until &foo (see \amprm)
+
+% Be sure that we always have a definition for `(', etc. For example,
+% if the fn name has parens in it, \boldbrax will not be in effect yet,
+% so TeX would otherwise complain about undefined control sequence.
+\global\let(=\lparen \global\let)=\rparen
+\global\let[=\lbrack \global\let]=\rbrack
+
+\gdef\functionparens{\boldbrax\let&=\amprm\parencount=0 }
+\gdef\boldbrax{\let(=\opnr\let)=\clnr\let[=\lbrb\let]=\rbrb}
+% This is used to turn on special parens
+% but make & act ordinary (given that it's active).
+\gdef\boldbraxnoamp{\let(=\opnr\let)=\clnr\let[=\lbrb\let]=\rbrb\let&=\ampnr}
+
+% Definitions of (, ) and & used in args for functions.
+% This is the definition of ( outside of all parentheses.
+\gdef\oprm#1 {{\rm\char`\(}#1 \bf \let(=\opnested
+ \global\advance\parencount by 1
+}
+%
+% This is the definition of ( when already inside a level of parens.
+\gdef\opnested{\char`\(\global\advance\parencount by 1 }
+%
+\gdef\clrm{% Print a paren in roman if it is taking us back to depth of 0.
+ % also in that case restore the outer-level definition of (.
+ \ifnum \parencount=1 {\rm \char `\)}\sl \let(=\oprm \else \char `\) \fi
+ \global\advance \parencount by -1 }
+% If we encounter &foo, then turn on ()-hacking afterwards
+\gdef\amprm#1 {{\rm\&#1}\let(=\oprm \let)=\clrm\ }
+%
+\gdef\normalparens{\boldbrax\let&=\ampnr}
+} % End of definition inside \activeparens
+%% These parens (in \boldbrax) actually are a little bolder than the
+%% contained text. This is especially needed for [ and ]
+\def\opnr{{\sf\char`\(}\global\advance\parencount by 1 }
+\def\clnr{{\sf\char`\)}\global\advance\parencount by -1 }
+\let\ampnr = \&
+\def\lbrb{{\bf\char`\[}}
+\def\rbrb{{\bf\char`\]}}
+
+% Active &'s sneak into the index arguments, so make sure it's defined.
+{
+ \catcode`& = 13
+ \global\let& = \ampnr
+}
+
+% First, defname, which formats the header line itself.
+% #1 should be the function name.
+% #2 should be the type of definition, such as "Function".
+
+\def\defname #1#2{%
+% Get the values of \leftskip and \rightskip as they were
+% outside the @def...
+\dimen2=\leftskip
+\advance\dimen2 by -\defbodyindent
+\noindent
+\setbox0=\hbox{\hskip \deflastargmargin{\rm #2}\hskip \deftypemargin}%
+\dimen0=\hsize \advance \dimen0 by -\wd0 % compute size for first line
+\dimen1=\hsize \advance \dimen1 by -\defargsindent %size for continuations
+\parshape 2 0in \dimen0 \defargsindent \dimen1
+% Now output arg 2 ("Function" or some such)
+% ending at \deftypemargin from the right margin,
+% but stuck inside a box of width 0 so it does not interfere with linebreaking
+{% Adjust \hsize to exclude the ambient margins,
+% so that \rightline will obey them.
+\advance \hsize by -\dimen2
+\rlap{\rightline{{\rm #2}\hskip -1.25pc }}}%
+% Make all lines underfull and no complaints:
+\tolerance=10000 \hbadness=10000
+\advance\leftskip by -\defbodyindent
+\exdentamount=\defbodyindent
+{\df #1}\enskip % Generate function name
+}
+
+% Actually process the body of a definition
+% #1 should be the terminating control sequence, such as \Edefun.
+% #2 should be the "another name" control sequence, such as \defunx.
+% #3 should be the control sequence that actually processes the header,
+% such as \defunheader.
+
+\def\defparsebody #1#2#3{\begingroup\inENV% Environment for definitionbody
+\medbreak %
+% Define the end token that this defining construct specifies
+% so that it will exit this group.
+\def#1{\endgraf\endgroup\medbreak}%
+\def#2{\begingroup\obeylines\activeparens\spacesplit#3}%
+\parindent=0in
+\advance\leftskip by \defbodyindent
+\exdentamount=\defbodyindent
+\begingroup %
+\catcode 61=\active % 61 is `='
+\obeylines\activeparens\spacesplit#3}
+
+% #1 is the \E... control sequence to end the definition (which we define).
+% #2 is the \...x control sequence for consecutive fns (which we define).
+% #3 is the control sequence to call to resume processing.
+% #4, delimited by the space, is the class name.
+%
+\def\defmethparsebody#1#2#3#4 {\begingroup\inENV %
+\medbreak %
+% Define the end token that this defining construct specifies
+% so that it will exit this group.
+\def#1{\endgraf\endgroup\medbreak}%
+\def#2##1 {\begingroup\obeylines\activeparens\spacesplit{#3{##1}}}%
+\parindent=0in
+\advance\leftskip by \defbodyindent
+\exdentamount=\defbodyindent
+\begingroup\obeylines\activeparens\spacesplit{#3{#4}}}
+
+% @deftypemethod has an extra argument that nothing else does. Sigh.
+% #1 is the \E... control sequence to end the definition (which we define).
+% #2 is the \...x control sequence for consecutive fns (which we define).
+% #3 is the control sequence to call to resume processing.
+% #4, delimited by the space, is the class name.
+% #5 is the method's return type.
+%
+\def\deftypemethparsebody#1#2#3#4 #5 {\begingroup\inENV %
+\medbreak %
+% Define the end token that this defining construct specifies
+% so that it will exit this group.
+\def#1{\endgraf\endgroup\medbreak}%
+\def#2##1 ##2 {\begingroup\obeylines\activeparens\spacesplit{#3{##1}{##2}}}%
+\parindent=0in
+\advance\leftskip by \defbodyindent
+\exdentamount=\defbodyindent
+\begingroup\obeylines\activeparens\spacesplit{#3{#4}{#5}}}
+
+\def\defopparsebody #1#2#3#4#5 {\begingroup\inENV %
+\medbreak %
+% Define the end token that this defining construct specifies
+% so that it will exit this group.
+\def#1{\endgraf\endgroup\medbreak}%
+\def#2##1 ##2 {\def#4{##1}%
+\begingroup\obeylines\activeparens\spacesplit{#3{##2}}}%
+\parindent=0in
+\advance\leftskip by \defbodyindent
+\exdentamount=\defbodyindent
+\begingroup\obeylines\activeparens\spacesplit{#3{#5}}}
+
+% These parsing functions are similar to the preceding ones
+% except that they do not make parens into active characters.
+% These are used for "variables" since they have no arguments.
+
+\def\defvarparsebody #1#2#3{\begingroup\inENV% Environment for definitionbody
+\medbreak %
+% Define the end token that this defining construct specifies
+% so that it will exit this group.
+\def#1{\endgraf\endgroup\medbreak}%
+\def#2{\begingroup\obeylines\spacesplit#3}%
+\parindent=0in
+\advance\leftskip by \defbodyindent
+\exdentamount=\defbodyindent
+\begingroup %
+\catcode 61=\active %
+\obeylines\spacesplit#3}
+
+% This is used for \def{tp,vr}parsebody. It could probably be used for
+% some of the others, too, with some judicious conditionals.
+%
+\def\parsebodycommon#1#2#3{%
+ \begingroup\inENV %
+ \medbreak %
+ % Define the end token that this defining construct specifies
+ % so that it will exit this group.
+ \def#1{\endgraf\endgroup\medbreak}%
+ \def#2##1 {\begingroup\obeylines\spacesplit{#3{##1}}}%
+ \parindent=0in
+ \advance\leftskip by \defbodyindent
+ \exdentamount=\defbodyindent
+ \begingroup\obeylines
+}
+
+\def\defvrparsebody#1#2#3#4 {%
+ \parsebodycommon{#1}{#2}{#3}%
+ \spacesplit{#3{#4}}%
+}
+
+% This loses on `@deftp {Data Type} {struct termios}' -- it thinks the
+% type is just `struct', because we lose the braces in `{struct
+% termios}' when \spacesplit reads its undelimited argument. Sigh.
+% \let\deftpparsebody=\defvrparsebody
+%
+% So, to get around this, we put \empty in with the type name. That
+% way, TeX won't find exactly `{...}' as an undelimited argument, and
+% won't strip off the braces.
+%
+\def\deftpparsebody #1#2#3#4 {%
+ \parsebodycommon{#1}{#2}{#3}%
+ \spacesplit{\parsetpheaderline{#3{#4}}}\empty
+}
+
+% Fine, but then we have to eventually remove the \empty *and* the
+% braces (if any). That's what this does.
+%
+\def\removeemptybraces\empty#1\relax{#1}
+
+% After \spacesplit has done its work, this is called -- #1 is the final
+% thing to call, #2 the type name (which starts with \empty), and #3
+% (which might be empty) the arguments.
+%
+\def\parsetpheaderline#1#2#3{%
+ #1{\removeemptybraces#2\relax}{#3}%
+}%
+
+\def\defopvarparsebody #1#2#3#4#5 {\begingroup\inENV %
+\medbreak %
+% Define the end token that this defining construct specifies
+% so that it will exit this group.
+\def#1{\endgraf\endgroup\medbreak}%
+\def#2##1 ##2 {\def#4{##1}%
+\begingroup\obeylines\spacesplit{#3{##2}}}%
+\parindent=0in
+\advance\leftskip by \defbodyindent
+\exdentamount=\defbodyindent
+\begingroup\obeylines\spacesplit{#3{#5}}}
+
+% Split up #2 at the first space token.
+% call #1 with two arguments:
+% the first is all of #2 before the space token,
+% the second is all of #2 after that space token.
+% If #2 contains no space token, all of it is passed as the first arg
+% and the second is passed as empty.
+
+{\obeylines
+\gdef\spacesplit#1#2^^M{\endgroup\spacesplitfoo{#1}#2 \relax\spacesplitfoo}%
+\long\gdef\spacesplitfoo#1#2 #3#4\spacesplitfoo{%
+\ifx\relax #3%
+#1{#2}{}\else #1{#2}{#3#4}\fi}}
+
+% So much for the things common to all kinds of definitions.
+
+% Define @defun.
+
+% First, define the processing that is wanted for arguments of \defun
+% Use this to expand the args and terminate the paragraph they make up
+
+\def\defunargs#1{\functionparens \sl
+% Expand, preventing hyphenation at `-' chars.
+% Note that groups don't affect changes in \hyphenchar.
+% Set the font temporarily and use \font in case \setfont made \tensl a macro.
+{\tensl\hyphenchar\font=0}%
+#1%
+{\tensl\hyphenchar\font=45}%
+\ifnum\parencount=0 \else \errmessage{Unbalanced parentheses in @def}\fi%
+\interlinepenalty=10000
+\advance\rightskip by 0pt plus 1fil
+\endgraf\nobreak\vskip -\parskip\nobreak
+}
+
+\def\deftypefunargs #1{%
+% Expand, preventing hyphenation at `-' chars.
+% Note that groups don't affect changes in \hyphenchar.
+% Use \boldbraxnoamp, not \functionparens, so that & is not special.
+\boldbraxnoamp
+\tclose{#1}% avoid \code because of side effects on active chars
+\interlinepenalty=10000
+\advance\rightskip by 0pt plus 1fil
+\endgraf\nobreak\vskip -\parskip\nobreak
+}
+
+% Do complete processing of one @defun or @defunx line already parsed.
+
+% @deffn Command forward-char nchars
+
+\def\deffn{\defmethparsebody\Edeffn\deffnx\deffnheader}
+
+\def\deffnheader #1#2#3{\doind {fn}{\code{#2}}%
+\begingroup\defname {#2}{#1}\defunargs{#3}\endgroup %
+\catcode 61=\other % Turn off change made in \defparsebody
+}
+
+% @defun == @deffn Function
+
+\def\defun{\defparsebody\Edefun\defunx\defunheader}
+
+\def\defunheader #1#2{\doind {fn}{\code{#1}}% Make entry in function index
+\begingroup\defname {#1}{\putwordDeffunc}%
+\defunargs {#2}\endgroup %
+\catcode 61=\other % Turn off change made in \defparsebody
+}
+
+% @deftypefun int foobar (int @var{foo}, float @var{bar})
+
+\def\deftypefun{\defparsebody\Edeftypefun\deftypefunx\deftypefunheader}
+
+% #1 is the data type. #2 is the name and args.
+\def\deftypefunheader #1#2{\deftypefunheaderx{#1}#2 \relax}
+% #1 is the data type, #2 the name, #3 the args.
+\def\deftypefunheaderx #1#2 #3\relax{%
+\doind {fn}{\code{#2}}% Make entry in function index
+\begingroup\defname {\defheaderxcond#1\relax$$$#2}{\putwordDeftypefun}%
+\deftypefunargs {#3}\endgroup %
+\catcode 61=\other % Turn off change made in \defparsebody
+}
+
+% @deftypefn {Library Function} int foobar (int @var{foo}, float @var{bar})
+
+\def\deftypefn{\defmethparsebody\Edeftypefn\deftypefnx\deftypefnheader}
+
+% \defheaderxcond#1\relax$$$
+% puts #1 in @code, followed by a space, but does nothing if #1 is null.
+\def\defheaderxcond#1#2$$${\ifx#1\relax\else\code{#1#2} \fi}
+
+% #1 is the classification. #2 is the data type. #3 is the name and args.
+\def\deftypefnheader #1#2#3{\deftypefnheaderx{#1}{#2}#3 \relax}
+% #1 is the classification, #2 the data type, #3 the name, #4 the args.
+\def\deftypefnheaderx #1#2#3 #4\relax{%
+\doind {fn}{\code{#3}}% Make entry in function index
+\begingroup
+\normalparens % notably, turn off `&' magic, which prevents
+% at least some C++ text from working
+\defname {\defheaderxcond#2\relax$$$#3}{#1}%
+\deftypefunargs {#4}\endgroup %
+\catcode 61=\other % Turn off change made in \defparsebody
+}
+
+% @defmac == @deffn Macro
+
+\def\defmac{\defparsebody\Edefmac\defmacx\defmacheader}
+
+\def\defmacheader #1#2{\doind {fn}{\code{#1}}% Make entry in function index
+\begingroup\defname {#1}{\putwordDefmac}%
+\defunargs {#2}\endgroup %
+\catcode 61=\other % Turn off change made in \defparsebody
+}
+
+% @defspec == @deffn Special Form
+
+\def\defspec{\defparsebody\Edefspec\defspecx\defspecheader}
+
+\def\defspecheader #1#2{\doind {fn}{\code{#1}}% Make entry in function index
+\begingroup\defname {#1}{\putwordDefspec}%
+\defunargs {#2}\endgroup %
+\catcode 61=\other % Turn off change made in \defparsebody
+}
+
+% @defop CATEGORY CLASS OPERATION ARG...
+%
+\def\defop #1 {\def\defoptype{#1}%
+\defopparsebody\Edefop\defopx\defopheader\defoptype}
+%
+\def\defopheader #1#2#3{%
+\dosubind {fn}{\code{#2}}{\putwordon\ #1}% Make entry in function index
+\begingroup\defname {#2}{\defoptype\ \putwordon\ #1}%
+\defunargs {#3}\endgroup %
+}
+
+% @deftypemethod CLASS RETURN-TYPE METHOD ARG...
+%
+\def\deftypemethod{%
+ \deftypemethparsebody\Edeftypemethod\deftypemethodx\deftypemethodheader}
+%
+% #1 is the class name, #2 the data type, #3 the method name, #4 the args.
+\def\deftypemethodheader#1#2#3#4{%
+ \dosubind{fn}{\code{#3}}{\putwordon\ \code{#1}}% entry in function index
+ \begingroup
+ \defname{\defheaderxcond#2\relax$$$#3}{\putwordMethodon\ \code{#1}}%
+ \deftypefunargs{#4}%
+ \endgroup
+}
+
+% @deftypeivar CLASS TYPE VARNAME
+%
+\def\deftypeivar{%
+ \deftypemethparsebody\Edeftypeivar\deftypeivarx\deftypeivarheader}
+%
+% #1 is the class name, #2 the data type, #3 the variable name.
+\def\deftypeivarheader#1#2#3{%
+ \dosubind{vr}{\code{#3}}{\putwordof\ \code{#1}}% entry in variable index
+ \begingroup
+ \defname{#3}{\putwordInstanceVariableof\ \code{#1}}%
+ \defvarargs{#3}%
+ \endgroup
+}
+
+% @defmethod == @defop Method
+%
+\def\defmethod{\defmethparsebody\Edefmethod\defmethodx\defmethodheader}
+%
+% #1 is the class name, #2 the method name, #3 the args.
+\def\defmethodheader#1#2#3{%
+ \dosubind{fn}{\code{#2}}{\putwordon\ \code{#1}}% entry in function index
+ \begingroup
+ \defname{#2}{\putwordMethodon\ \code{#1}}%
+ \defunargs{#3}%
+ \endgroup
+}
+
+% @defcv {Class Option} foo-class foo-flag
+
+\def\defcv #1 {\def\defcvtype{#1}%
+\defopvarparsebody\Edefcv\defcvx\defcvarheader\defcvtype}
+
+\def\defcvarheader #1#2#3{%
+\dosubind {vr}{\code{#2}}{\putwordof\ #1}% Make entry in var index
+\begingroup\defname {#2}{\defcvtype\ \putwordof\ #1}%
+\defvarargs {#3}\endgroup %
+}
+
+% @defivar CLASS VARNAME == @defcv {Instance Variable} CLASS VARNAME
+%
+\def\defivar{\defvrparsebody\Edefivar\defivarx\defivarheader}
+%
+\def\defivarheader#1#2#3{%
+ \dosubind {vr}{\code{#2}}{\putwordof\ #1}% entry in var index
+ \begingroup
+ \defname{#2}{\putwordInstanceVariableof\ #1}%
+ \defvarargs{#3}%
+ \endgroup
+}
+
+% @defvar
+% First, define the processing that is wanted for arguments of @defvar.
+% This is actually simple: just print them in roman.
+% This must expand the args and terminate the paragraph they make up
+\def\defvarargs #1{\normalparens #1%
+\interlinepenalty=10000
+\endgraf\nobreak\vskip -\parskip\nobreak}
+
+% @defvr Counter foo-count
+
+\def\defvr{\defvrparsebody\Edefvr\defvrx\defvrheader}
+
+\def\defvrheader #1#2#3{\doind {vr}{\code{#2}}%
+\begingroup\defname {#2}{#1}\defvarargs{#3}\endgroup}
+
+% @defvar == @defvr Variable
+
+\def\defvar{\defvarparsebody\Edefvar\defvarx\defvarheader}
+
+\def\defvarheader #1#2{\doind {vr}{\code{#1}}% Make entry in var index
+\begingroup\defname {#1}{\putwordDefvar}%
+\defvarargs {#2}\endgroup %
+}
+
+% @defopt == @defvr {User Option}
+
+\def\defopt{\defvarparsebody\Edefopt\defoptx\defoptheader}
+
+\def\defoptheader #1#2{\doind {vr}{\code{#1}}% Make entry in var index
+\begingroup\defname {#1}{\putwordDefopt}%
+\defvarargs {#2}\endgroup %
+}
+
+% @deftypevar int foobar
+
+\def\deftypevar{\defvarparsebody\Edeftypevar\deftypevarx\deftypevarheader}
+
+% #1 is the data type. #2 is the name, perhaps followed by text that
+% is actually part of the data type, which should not be put into the index.
+\def\deftypevarheader #1#2{%
+\dovarind#2 \relax% Make entry in variables index
+\begingroup\defname {\defheaderxcond#1\relax$$$#2}{\putwordDeftypevar}%
+\interlinepenalty=10000
+\endgraf\nobreak\vskip -\parskip\nobreak
+\endgroup}
+\def\dovarind#1 #2\relax{\doind{vr}{\code{#1}}}
+
+% @deftypevr {Global Flag} int enable
+
+\def\deftypevr{\defvrparsebody\Edeftypevr\deftypevrx\deftypevrheader}
+
+\def\deftypevrheader #1#2#3{\dovarind#3 \relax%
+\begingroup\defname {\defheaderxcond#2\relax$$$#3}{#1}
+\interlinepenalty=10000
+\endgraf\nobreak\vskip -\parskip\nobreak
+\endgroup}
+
+% Now define @deftp
+% Args are printed in bold, a slight difference from @defvar.
+
+\def\deftpargs #1{\bf \defvarargs{#1}}
+
+% @deftp Class window height width ...
+
+\def\deftp{\deftpparsebody\Edeftp\deftpx\deftpheader}
+
+\def\deftpheader #1#2#3{\doind {tp}{\code{#2}}%
+\begingroup\defname {#2}{#1}\deftpargs{#3}\endgroup}
+
+% These definitions are used if you use @defunx (etc.)
+% anywhere other than immediately after a @defun or @defunx.
+%
+\def\defcvx#1 {\errmessage{@defcvx in invalid context}}
+\def\deffnx#1 {\errmessage{@deffnx in invalid context}}
+\def\defivarx#1 {\errmessage{@defivarx in invalid context}}
+\def\defmacx#1 {\errmessage{@defmacx in invalid context}}
+\def\defmethodx#1 {\errmessage{@defmethodx in invalid context}}
+\def\defoptx #1 {\errmessage{@defoptx in invalid context}}
+\def\defopx#1 {\errmessage{@defopx in invalid context}}
+\def\defspecx#1 {\errmessage{@defspecx in invalid context}}
+\def\deftpx#1 {\errmessage{@deftpx in invalid context}}
+\def\deftypefnx#1 {\errmessage{@deftypefnx in invalid context}}
+\def\deftypefunx#1 {\errmessage{@deftypefunx in invalid context}}
+\def\deftypeivarx#1 {\errmessage{@deftypeivarx in invalid context}}
+\def\deftypemethodx#1 {\errmessage{@deftypemethodx in invalid context}}
+\def\deftypevarx#1 {\errmessage{@deftypevarx in invalid context}}
+\def\deftypevrx#1 {\errmessage{@deftypevrx in invalid context}}
+\def\defunx#1 {\errmessage{@defunx in invalid context}}
+\def\defvarx#1 {\errmessage{@defvarx in invalid context}}
+\def\defvrx#1 {\errmessage{@defvrx in invalid context}}
+
+
+\message{macros,}
+% @macro.
+
+% To do this right we need a feature of e-TeX, \scantokens,
+% which we arrange to emulate with a temporary file in ordinary TeX.
+\ifx\eTeXversion\undefined
+ \newwrite\macscribble
+ \def\scanmacro#1{%
+ \begingroup \newlinechar`\^^M
+ % Undo catcode changes of \startcontents and \doprintindex
+ \catcode`\@=0 \catcode`\\=12 \escapechar=`\@
+ % Append \endinput to make sure that TeX does not see the ending newline.
+ \toks0={#1\endinput}%
+ \immediate\openout\macscribble=\jobname.tmp
+ \immediate\write\macscribble{\the\toks0}%
+ \immediate\closeout\macscribble
+ \let\xeatspaces\eatspaces
+ \input \jobname.tmp
+ \endgroup
+}
+\else
+\def\scanmacro#1{%
+\begingroup \newlinechar`\^^M
+% Undo catcode changes of \startcontents and \doprintindex
+\catcode`\@=0 \catcode`\\=12 \escapechar=`\@
+\let\xeatspaces\eatspaces\scantokens{#1\endinput}\endgroup}
+\fi
+
+\newcount\paramno % Count of parameters
+\newtoks\macname % Macro name
+\newif\ifrecursive % Is it recursive?
+\def\macrolist{} % List of all defined macros in the form
+ % \do\macro1\do\macro2...
+
+% Utility routines.
+% Thisdoes \let #1 = #2, except with \csnames.
+\def\cslet#1#2{%
+\expandafter\expandafter
+\expandafter\let
+\expandafter\expandafter
+\csname#1\endcsname
+\csname#2\endcsname}
+
+% Trim leading and trailing spaces off a string.
+% Concepts from aro-bend problem 15 (see CTAN).
+{\catcode`\@=11
+\gdef\eatspaces #1{\expandafter\trim@\expandafter{#1 }}
+\gdef\trim@ #1{\trim@@ @#1 @ #1 @ @@}
+\gdef\trim@@ #1@ #2@ #3@@{\trim@@@\empty #2 @}
+\def\unbrace#1{#1}
+\unbrace{\gdef\trim@@@ #1 } #2@{#1}
+}
+
+% Trim a single trailing ^^M off a string.
+{\catcode`\^^M=12\catcode`\Q=3%
+\gdef\eatcr #1{\eatcra #1Q^^MQ}%
+\gdef\eatcra#1^^MQ{\eatcrb#1Q}%
+\gdef\eatcrb#1Q#2Q{#1}%
+}
+
+% Macro bodies are absorbed as an argument in a context where
+% all characters are catcode 10, 11 or 12, except \ which is active
+% (as in normal texinfo). It is necessary to change the definition of \.
+
+% It's necessary to have hard CRs when the macro is executed. This is
+% done by making ^^M (\endlinechar) catcode 12 when reading the macro
+% body, and then making it the \newlinechar in \scanmacro.
+
+\def\macrobodyctxt{%
+ \catcode`\~=12
+ \catcode`\^=12
+ \catcode`\_=12
+ \catcode`\|=12
+ \catcode`\<=12
+ \catcode`\>=12
+ \catcode`\+=12
+ \catcode`\{=12
+ \catcode`\}=12
+ \catcode`\@=12
+ \catcode`\^^M=12
+ \usembodybackslash}
+
+\def\macroargctxt{%
+ \catcode`\~=12
+ \catcode`\^=12
+ \catcode`\_=12
+ \catcode`\|=12
+ \catcode`\<=12
+ \catcode`\>=12
+ \catcode`\+=12
+ \catcode`\@=12
+ \catcode`\\=12}
+
+% \mbodybackslash is the definition of \ in @macro bodies.
+% It maps \foo\ => \csname macarg.foo\endcsname => #N
+% where N is the macro parameter number.
+% We define \csname macarg.\endcsname to be \realbackslash, so
+% \\ in macro replacement text gets you a backslash.
+
+{\catcode`@=0 @catcode`@\=@active
+ @gdef@usembodybackslash{@let\=@mbodybackslash}
+ @gdef@mbodybackslash#1\{@csname macarg.#1@endcsname}
+}
+\expandafter\def\csname macarg.\endcsname{\realbackslash}
+
+\def\macro{\recursivefalse\parsearg\macroxxx}
+\def\rmacro{\recursivetrue\parsearg\macroxxx}
+
+\def\macroxxx#1{%
+ \getargs{#1}% now \macname is the macname and \argl the arglist
+ \ifx\argl\empty % no arguments
+ \paramno=0%
+ \else
+ \expandafter\parsemargdef \argl;%
+ \fi
+ \if1\csname ismacro.\the\macname\endcsname
+ \message{Warning: redefining \the\macname}%
+ \else
+ \expandafter\ifx\csname \the\macname\endcsname \relax
+ \else \errmessage{The name \the\macname\space is reserved}\fi
+ \global\cslet{macsave.\the\macname}{\the\macname}%
+ \global\expandafter\let\csname ismacro.\the\macname\endcsname=1%
+ % Add the macroname to \macrolist
+ \toks0 = \expandafter{\macrolist\do}%
+ \xdef\macrolist{\the\toks0
+ \expandafter\noexpand\csname\the\macname\endcsname}%
+ \fi
+ \begingroup \macrobodyctxt
+ \ifrecursive \expandafter\parsermacbody
+ \else \expandafter\parsemacbody
+ \fi}
+
+\def\unmacro{\parsearg\unmacroxxx}
+\def\unmacroxxx#1{%
+ \if1\csname ismacro.#1\endcsname
+ \global\cslet{#1}{macsave.#1}%
+ \global\expandafter\let \csname ismacro.#1\endcsname=0%
+ % Remove the macro name from \macrolist
+ \begingroup
+ \edef\tempa{\expandafter\noexpand\csname#1\endcsname}%
+ \def\do##1{%
+ \def\tempb{##1}%
+ \ifx\tempa\tempb
+ % remove this
+ \else
+ \toks0 = \expandafter{\newmacrolist\do}%
+ \edef\newmacrolist{\the\toks0\expandafter\noexpand\tempa}%
+ \fi}%
+ \def\newmacrolist{}%
+ % Execute macro list to define \newmacrolist
+ \macrolist
+ \global\let\macrolist\newmacrolist
+ \endgroup
+ \else
+ \errmessage{Macro #1 not defined}%
+ \fi
+}
+
+% This makes use of the obscure feature that if the last token of a
+% <parameter list> is #, then the preceding argument is delimited by
+% an opening brace, and that opening brace is not consumed.
+\def\getargs#1{\getargsxxx#1{}}
+\def\getargsxxx#1#{\getmacname #1 \relax\getmacargs}
+\def\getmacname #1 #2\relax{\macname={#1}}
+\def\getmacargs#1{\def\argl{#1}}
+
+% Parse the optional {params} list. Set up \paramno and \paramlist
+% so \defmacro knows what to do. Define \macarg.blah for each blah
+% in the params list, to be ##N where N is the position in that list.
+% That gets used by \mbodybackslash (above).
+
+% We need to get `macro parameter char #' into several definitions.
+% The technique used is stolen from LaTeX: let \hash be something
+% unexpandable, insert that wherever you need a #, and then redefine
+% it to # just before using the token list produced.
+%
+% The same technique is used to protect \eatspaces till just before
+% the macro is used.
+
+\def\parsemargdef#1;{\paramno=0\def\paramlist{}%
+ \let\hash\relax\let\xeatspaces\relax\parsemargdefxxx#1,;,}
+\def\parsemargdefxxx#1,{%
+ \if#1;\let\next=\relax
+ \else \let\next=\parsemargdefxxx
+ \advance\paramno by 1%
+ \expandafter\edef\csname macarg.\eatspaces{#1}\endcsname
+ {\xeatspaces{\hash\the\paramno}}%
+ \edef\paramlist{\paramlist\hash\the\paramno,}%
+ \fi\next}
+
+% These two commands read recursive and nonrecursive macro bodies.
+% (They're different since rec and nonrec macros end differently.)
+
+\long\def\parsemacbody#1@end macro%
+{\xdef\temp{\eatcr{#1}}\endgroup\defmacro}%
+\long\def\parsermacbody#1@end rmacro%
+{\xdef\temp{\eatcr{#1}}\endgroup\defmacro}%
+
+% This defines the macro itself. There are six cases: recursive and
+% nonrecursive macros of zero, one, and many arguments.
+% Much magic with \expandafter here.
+% \xdef is used so that macro definitions will survive the file
+% they're defined in; @include reads the file inside a group.
+\def\defmacro{%
+ \let\hash=##% convert placeholders to macro parameter chars
+ \ifrecursive
+ \ifcase\paramno
+ % 0
+ \expandafter\xdef\csname\the\macname\endcsname{%
+ \noexpand\scanmacro{\temp}}%
+ \or % 1
+ \expandafter\xdef\csname\the\macname\endcsname{%
+ \bgroup\noexpand\macroargctxt
+ \noexpand\braceorline
+ \expandafter\noexpand\csname\the\macname xxx\endcsname}%
+ \expandafter\xdef\csname\the\macname xxx\endcsname##1{%
+ \egroup\noexpand\scanmacro{\temp}}%
+ \else % many
+ \expandafter\xdef\csname\the\macname\endcsname{%
+ \bgroup\noexpand\macroargctxt
+ \noexpand\csname\the\macname xx\endcsname}%
+ \expandafter\xdef\csname\the\macname xx\endcsname##1{%
+ \expandafter\noexpand\csname\the\macname xxx\endcsname ##1,}%
+ \expandafter\expandafter
+ \expandafter\xdef
+ \expandafter\expandafter
+ \csname\the\macname xxx\endcsname
+ \paramlist{\egroup\noexpand\scanmacro{\temp}}%
+ \fi
+ \else
+ \ifcase\paramno
+ % 0
+ \expandafter\xdef\csname\the\macname\endcsname{%
+ \noexpand\norecurse{\the\macname}%
+ \noexpand\scanmacro{\temp}\egroup}%
+ \or % 1
+ \expandafter\xdef\csname\the\macname\endcsname{%
+ \bgroup\noexpand\macroargctxt
+ \noexpand\braceorline
+ \expandafter\noexpand\csname\the\macname xxx\endcsname}%
+ \expandafter\xdef\csname\the\macname xxx\endcsname##1{%
+ \egroup
+ \noexpand\norecurse{\the\macname}%
+ \noexpand\scanmacro{\temp}\egroup}%
+ \else % many
+ \expandafter\xdef\csname\the\macname\endcsname{%
+ \bgroup\noexpand\macroargctxt
+ \expandafter\noexpand\csname\the\macname xx\endcsname}%
+ \expandafter\xdef\csname\the\macname xx\endcsname##1{%
+ \expandafter\noexpand\csname\the\macname xxx\endcsname ##1,}%
+ \expandafter\expandafter
+ \expandafter\xdef
+ \expandafter\expandafter
+ \csname\the\macname xxx\endcsname
+ \paramlist{%
+ \egroup
+ \noexpand\norecurse{\the\macname}%
+ \noexpand\scanmacro{\temp}\egroup}%
+ \fi
+ \fi}
+
+\def\norecurse#1{\bgroup\cslet{#1}{macsave.#1}}
+
+% \braceorline decides whether the next nonwhitespace character is a
+% {. If so it reads up to the closing }, if not, it reads the whole
+% line. Whatever was read is then fed to the next control sequence
+% as an argument (by \parsebrace or \parsearg)
+\def\braceorline#1{\let\next=#1\futurelet\nchar\braceorlinexxx}
+\def\braceorlinexxx{%
+ \ifx\nchar\bgroup\else
+ \expandafter\parsearg
+ \fi \next}
+
+% We mant to disable all macros during \shipout so that they are not
+% expanded by \write.
+\def\turnoffmacros{\begingroup \def\do##1{\let\noexpand##1=\relax}%
+ \edef\next{\macrolist}\expandafter\endgroup\next}
+
+
+% @alias.
+\def\alias#1=#2{\gdef#1{#2}}
+
+
+\message{cross references,}
+% @xref etc.
+
+\newwrite\auxfile
+
+\newif\ifhavexrefs % True if xref values are known.
+\newif\ifwarnedxrefs % True if we warned once that they aren't known.
+
+% @inforef is relatively simple.
+\def\inforef #1{\inforefzzz #1,,,,**}
+\def\inforefzzz #1,#2,#3,#4**{\putwordSee{} \putwordInfo{} \putwordfile{} \file{\ignorespaces #3{}},
+ node \samp{\ignorespaces#1{}}}
+
+% @node's job is to define \lastnode.
+\def\node{\ENVcheck\parsearg\nodezzz}
+\def\nodezzz#1{\nodexxx [#1,]}
+\def\nodexxx[#1,#2]{\gdef\lastnode{#1}}
+\let\nwnode=\node
+\let\lastnode=\relax
+
+% The sectioning commands (@chapter, etc.) call these.
+\def\donoderef{%
+ \ifx\lastnode\relax\else
+ \expandafter\expandafter\expandafter\setref{\lastnode}%
+ {Ysectionnumberandtype}%
+ \global\let\lastnode=\relax
+ \fi
+}
+\def\unnumbnoderef{%
+ \ifx\lastnode\relax\else
+ \expandafter\expandafter\expandafter\setref{\lastnode}{Ynothing}%
+ \global\let\lastnode=\relax
+ \fi
+}
+\def\appendixnoderef{%
+ \ifx\lastnode\relax\else
+ \expandafter\expandafter\expandafter\setref{\lastnode}%
+ {Yappendixletterandtype}%
+ \global\let\lastnode=\relax
+ \fi
+}
+
+
+% @anchor{NAME} -- define xref target at arbitrary point.
+%
+{ \catcode`\@ = 11
+% From latex.ltx, to make @anchor truely invisible.
+\newdimen\@savsk
+\newcount\@savsf
+\gdef\@bsphack{\relax
+ \ifhmode \@savsk\lastskip \@savsf\spacefactor \fi
+}
+\gdef\@esphack{\relax
+ \ifhmode \spacefactor\@savsf
+ \ifdim\@savsk>\z@ \ignorespaces \fi
+ \fi
+}
+\gdef\anchor#1{\@bsphack \setref{#1}{Ynothing}\@esphack}
+}
+
+% \setref{NAME}{SNT} defines a cross-reference point NAME, namely
+% NAME-title, NAME-pg, and NAME-SNT. Called from \foonoderef. We have
+% to set \indexdummies so commands such as @code in a section title
+% aren't expanded. It would be nicer not to expand the titles in the
+% first place, but there's so many layers that that is hard to do.
+%
+\def\setref#1#2{{%
+ \indexdummies
+ \ifpdf \pdfmkdest{#1}\fi
+ \dosetq{#1-title}{Ytitle}%
+ \dosetq{#1-pg}{Ypagenumber}%
+ \dosetq{#1-snt}{#2}%
+}}
+
+% @xref, @pxref, and @ref generate cross-references. For \xrefX, #1 is
+% the node name, #2 the name of the Info cross-reference, #3 the printed
+% node name, #4 the name of the Info file, #5 the name of the printed
+% manual. All but the node name can be omitted.
+%
+\def\pxref#1{\putwordsee{} \xrefX[#1,,,,,,,]}
+\def\xref#1{\putwordSee{} \xrefX[#1,,,,,,,]}
+\def\ref#1{\xrefX[#1,,,,,,,]}
+\def\xrefX[#1,#2,#3,#4,#5,#6]{\begingroup
+ \def\printedmanual{\ignorespaces #5}%
+ \def\printednodename{\ignorespaces #3}%
+ \setbox1=\hbox{\printedmanual}%
+ \setbox0=\hbox{\printednodename}%
+ \ifdim \wd0 = 0pt
+ % No printed node name was explicitly given.
+ \expandafter\ifx\csname SETxref-automatic-section-title\endcsname\relax
+ % Use the node name inside the square brackets.
+ \def\printednodename{\ignorespaces #1}%
+ \else
+ % Use the actual chapter/section title appear inside
+ % the square brackets. Use the real section title if we have it.
+ \ifdim \wd1 > 0pt
+ % It is in another manual, so we don't have it.
+ \def\printednodename{\ignorespaces #1}%
+ \else
+ \ifhavexrefs
+ % We know the real title if we have the xref values.
+ \def\printednodename{\refx{#1-title}{}}%
+ \else
+ % Otherwise just copy the Info node name.
+ \def\printednodename{\ignorespaces #1}%
+ \fi%
+ \fi
+ \fi
+ \fi
+ %
+ % If we use \unhbox0 and \unhbox1 to print the node names, TeX does not
+ % insert empty discretionaries after hyphens, which means that it will
+ % not find a line break at a hyphen in a node names. Since some manuals
+ % are best written with fairly long node names, containing hyphens, this
+ % is a loss. Therefore, we give the text of the node name again, so it
+ % is as if TeX is seeing it for the first time.
+ \ifpdf
+ \leavevmode
+ \getfilename{#4}%
+ \ifnum\filenamelength>0
+ \pdfannotlink attr{/Border [0 0 0]}%
+ goto file{\the\filename.pdf} name{#1@}%
+ \else
+ \pdfannotlink attr{/Border [0 0 0]}%
+ goto name{#1@}%
+ \fi
+ \BlueGreen
+ \fi
+ %
+ \ifdim \wd1 > 0pt
+ \putwordsection{} ``\printednodename'' \putwordin{} \cite{\printedmanual}%
+ \else
+ % _ (for example) has to be the character _ for the purposes of the
+ % control sequence corresponding to the node, but it has to expand
+ % into the usual \leavevmode...\vrule stuff for purposes of
+ % printing. So we \turnoffactive for the \refx-snt, back on for the
+ % printing, back off for the \refx-pg.
+ {\normalturnoffactive
+ % Only output a following space if the -snt ref is nonempty; for
+ % @unnumbered and @anchor, it won't be.
+ \setbox2 = \hbox{\ignorespaces \refx{#1-snt}{}}%
+ \ifdim \wd2 > 0pt \refx{#1-snt}\space\fi
+ }%
+ % [mynode],
+ [\printednodename],\space
+ % page 3
+ \turnoffactive \putwordpage\tie\refx{#1-pg}{}%
+ \fi
+ \ifpdf \Black\pdfendlink \fi
+\endgroup}
+
+% \dosetq is the interface for calls from other macros
+
+% Use \normalturnoffactive so that punctuation chars such as underscore
+% and backslash work in node names. (\turnoffactive doesn't do \.)
+\def\dosetq#1#2{%
+ {\let\folio=0%
+ \normalturnoffactive
+ \edef\next{\write\auxfile{\internalsetq{#1}{#2}}}%
+ \iflinks
+ \next
+ \fi
+ }%
+}
+
+% \internalsetq {foo}{page} expands into
+% CHARACTERS 'xrdef {foo}{...expansion of \Ypage...}
+% When the aux file is read, ' is the escape character
+
+\def\internalsetq #1#2{'xrdef {#1}{\csname #2\endcsname}}
+
+% Things to be expanded by \internalsetq
+
+\def\Ypagenumber{\folio}
+
+\def\Ytitle{\thissection}
+
+\def\Ynothing{}
+
+\def\Ysectionnumberandtype{%
+\ifnum\secno=0 \putwordChapter\xreftie\the\chapno %
+\else \ifnum \subsecno=0 \putwordSection\xreftie\the\chapno.\the\secno %
+\else \ifnum \subsubsecno=0 %
+\putwordSection\xreftie\the\chapno.\the\secno.\the\subsecno %
+\else %
+\putwordSection\xreftie\the\chapno.\the\secno.\the\subsecno.\the\subsubsecno %
+\fi \fi \fi }
+
+\def\Yappendixletterandtype{%
+\ifnum\secno=0 \putwordAppendix\xreftie'char\the\appendixno{}%
+\else \ifnum \subsecno=0 \putwordSection\xreftie'char\the\appendixno.\the\secno %
+\else \ifnum \subsubsecno=0 %
+\putwordSection\xreftie'char\the\appendixno.\the\secno.\the\subsecno %
+\else %
+\putwordSection\xreftie'char\the\appendixno.\the\secno.\the\subsecno.\the\subsubsecno %
+\fi \fi \fi }
+
+\gdef\xreftie{'tie}
+
+% Use TeX 3.0's \inputlineno to get the line number, for better error
+% messages, but if we're using an old version of TeX, don't do anything.
+%
+\ifx\inputlineno\thisisundefined
+ \let\linenumber = \empty % Non-3.0.
+\else
+ \def\linenumber{\the\inputlineno:\space}
+\fi
+
+% Define \refx{NAME}{SUFFIX} to reference a cross-reference string named NAME.
+% If its value is nonempty, SUFFIX is output afterward.
+
+\def\refx#1#2{%
+ \expandafter\ifx\csname X#1\endcsname\relax
+ % If not defined, say something at least.
+ \angleleft un\-de\-fined\angleright
+ \iflinks
+ \ifhavexrefs
+ \message{\linenumber Undefined cross reference `#1'.}%
+ \else
+ \ifwarnedxrefs\else
+ \global\warnedxrefstrue
+ \message{Cross reference values unknown; you must run TeX again.}%
+ \fi
+ \fi
+ \fi
+ \else
+ % It's defined, so just use it.
+ \csname X#1\endcsname
+ \fi
+ #2% Output the suffix in any case.
+}
+
+% This is the macro invoked by entries in the aux file.
+%
+\def\xrdef#1{\begingroup
+ % Reenable \ as an escape while reading the second argument.
+ \catcode`\\ = 0
+ \afterassignment\endgroup
+ \expandafter\gdef\csname X#1\endcsname
+}
+
+% Read the last existing aux file, if any. No error if none exists.
+\def\readauxfile{\begingroup
+ \catcode`\^^@=\other
+ \catcode`\^^A=\other
+ \catcode`\^^B=\other
+ \catcode`\^^C=\other
+ \catcode`\^^D=\other
+ \catcode`\^^E=\other
+ \catcode`\^^F=\other
+ \catcode`\^^G=\other
+ \catcode`\^^H=\other
+ \catcode`\^^K=\other
+ \catcode`\^^L=\other
+ \catcode`\^^N=\other
+ \catcode`\^^P=\other
+ \catcode`\^^Q=\other
+ \catcode`\^^R=\other
+ \catcode`\^^S=\other
+ \catcode`\^^T=\other
+ \catcode`\^^U=\other
+ \catcode`\^^V=\other
+ \catcode`\^^W=\other
+ \catcode`\^^X=\other
+ \catcode`\^^Z=\other
+ \catcode`\^^[=\other
+ \catcode`\^^\=\other
+ \catcode`\^^]=\other
+ \catcode`\^^^=\other
+ \catcode`\^^_=\other
+ \catcode`\@=\other
+ \catcode`\^=\other
+ % It was suggested to define this as 7, which would allow ^^e4 etc.
+ % in xref tags, i.e., node names. But since ^^e4 notation isn't
+ % supported in the main text, it doesn't seem desirable. Furthermore,
+ % that is not enough: for node names that actually contain a ^
+ % character, we would end up writing a line like this: 'xrdef {'hat
+ % b-title}{'hat b} and \xrdef does a \csname...\endcsname on the first
+ % argument, and \hat is not an expandable control sequence. It could
+ % all be worked out, but why? Either we support ^^ or we don't.
+ %
+ % The other change necessary for this was to define \auxhat:
+ % \def\auxhat{\def^{'hat }}% extra space so ok if followed by letter
+ % and then to call \auxhat in \setq.
+ %
+ \catcode`\~=\other
+ \catcode`\[=\other
+ \catcode`\]=\other
+ \catcode`\"=\other
+ \catcode`\_=\other
+ \catcode`\|=\other
+ \catcode`\<=\other
+ \catcode`\>=\other
+ \catcode`\$=\other
+ \catcode`\#=\other
+ \catcode`\&=\other
+ \catcode`+=\other % avoid \+ for paranoia even though we've turned it off
+ % Make the characters 128-255 be printing characters
+ {%
+ \count 1=128
+ \def\loop{%
+ \catcode\count 1=\other
+ \advance\count 1 by 1
+ \ifnum \count 1<256 \loop \fi
+ }%
+ }%
+ % The aux file uses ' as the escape (for now).
+ % Turn off \ as an escape so we do not lose on
+ % entries which were dumped with control sequences in their names.
+ % For example, 'xrdef {$\leq $-fun}{page ...} made by @defun ^^
+ % Reference to such entries still does not work the way one would wish,
+ % but at least they do not bomb out when the aux file is read in.
+ \catcode`\{=1
+ \catcode`\}=2
+ \catcode`\%=\other
+ \catcode`\'=0
+ \catcode`\\=\other
+ %
+ \openin 1 \jobname.aux
+ \ifeof 1 \else
+ \closein 1
+ \input \jobname.aux
+ \global\havexrefstrue
+ \global\warnedobstrue
+ \fi
+ % Open the new aux file. TeX will close it automatically at exit.
+ \openout\auxfile=\jobname.aux
+\endgroup}
+
+
+% Footnotes.
+
+\newcount \footnoteno
+
+% The trailing space in the following definition for supereject is
+% vital for proper filling; pages come out unaligned when you do a
+% pagealignmacro call if that space before the closing brace is
+% removed. (Generally, numeric constants should always be followed by a
+% space to prevent strange expansion errors.)
+\def\supereject{\par\penalty -20000\footnoteno =0 }
+
+% @footnotestyle is meaningful for info output only.
+\let\footnotestyle=\comment
+
+\let\ptexfootnote=\footnote
+
+{\catcode `\@=11
+%
+% Auto-number footnotes. Otherwise like plain.
+\gdef\footnote{%
+ \global\advance\footnoteno by \@ne
+ \edef\thisfootno{$^{\the\footnoteno}$}%
+ %
+ % In case the footnote comes at the end of a sentence, preserve the
+ % extra spacing after we do the footnote number.
+ \let\@sf\empty
+ \ifhmode\edef\@sf{\spacefactor\the\spacefactor}\/\fi
+ %
+ % Remove inadvertent blank space before typesetting the footnote number.
+ \unskip
+ \thisfootno\@sf
+ \footnotezzz
+}%
+
+% Don't bother with the trickery in plain.tex to not require the
+% footnote text as a parameter. Our footnotes don't need to be so general.
+%
+% Oh yes, they do; otherwise, @ifset and anything else that uses
+% \parseargline fail inside footnotes because the tokens are fixed when
+% the footnote is read. --karl, 16nov96.
+%
+\long\gdef\footnotezzz{\insert\footins\bgroup
+ % We want to typeset this text as a normal paragraph, even if the
+ % footnote reference occurs in (for example) a display environment.
+ % So reset some parameters.
+ \interlinepenalty\interfootnotelinepenalty
+ \splittopskip\ht\strutbox % top baseline for broken footnotes
+ \splitmaxdepth\dp\strutbox
+ \floatingpenalty\@MM
+ \leftskip\z@skip
+ \rightskip\z@skip
+ \spaceskip\z@skip
+ \xspaceskip\z@skip
+ \parindent\defaultparindent
+ %
+ % Hang the footnote text off the number.
+ \hang
+ \textindent{\thisfootno}%
+ %
+ % Don't crash into the line above the footnote text. Since this
+ % expands into a box, it must come within the paragraph, lest it
+ % provide a place where TeX can split the footnote.
+ \footstrut
+ \futurelet\next\fo@t
+}
+\def\fo@t{\ifcat\bgroup\noexpand\next \let\next\f@@t
+ \else\let\next\f@t\fi \next}
+\def\f@@t{\bgroup\aftergroup\@foot\let\next}
+\def\f@t#1{#1\@foot}
+\def\@foot{\strut\egroup}
+
+}%end \catcode `\@=11
+
+% Set the baselineskip to #1, and the lineskip and strut size
+% correspondingly. There is no deep meaning behind these magic numbers
+% used as factors; they just match (closely enough) what Knuth defined.
+%
+\def\lineskipfactor{.08333}
+\def\strutheightpercent{.70833}
+\def\strutdepthpercent {.29167}
+%
+\def\setleading#1{%
+ \normalbaselineskip = #1\relax
+ \normallineskip = \lineskipfactor\normalbaselineskip
+ \normalbaselines
+ \setbox\strutbox =\hbox{%
+ \vrule width0pt height\strutheightpercent\baselineskip
+ depth \strutdepthpercent \baselineskip
+ }%
+}
+
+% @| inserts a changebar to the left of the current line. It should
+% surround any changed text. This approach does *not* work if the
+% change spans more than two lines of output. To handle that, we would
+% have adopt a much more difficult approach (putting marks into the main
+% vertical list for the beginning and end of each change).
+%
+\def\|{%
+ % \vadjust can only be used in horizontal mode.
+ \leavevmode
+ %
+ % Append this vertical mode material after the current line in the output.
+ \vadjust{%
+ % We want to insert a rule with the height and depth of the current
+ % leading; that is exactly what \strutbox is supposed to record.
+ \vskip-\baselineskip
+ %
+ % \vadjust-items are inserted at the left edge of the type. So
+ % the \llap here moves out into the left-hand margin.
+ \llap{%
+ %
+ % For a thicker or thinner bar, change the `1pt'.
+ \vrule height\baselineskip width1pt
+ %
+ % This is the space between the bar and the text.
+ \hskip 12pt
+ }%
+ }%
+}
+
+% For a final copy, take out the rectangles
+% that mark overfull boxes (in case you have decided
+% that the text looks ok even though it passes the margin).
+%
+\def\finalout{\overfullrule=0pt}
+
+% @image. We use the macros from epsf.tex to support this.
+% If epsf.tex is not installed and @image is used, we complain.
+%
+% Check for and read epsf.tex up front. If we read it only at @image
+% time, we might be inside a group, and then its definitions would get
+% undone and the next image would fail.
+\openin 1 = epsf.tex
+\ifeof 1 \else
+ \closein 1
+ % Do not bother showing banner with post-v2.7 epsf.tex (available in
+ % doc/epsf.tex until it shows up on ctan).
+ \def\epsfannounce{\toks0 = }%
+ \input epsf.tex
+\fi
+%
+% We will only complain once about lack of epsf.tex.
+\newif\ifwarnednoepsf
+\newhelp\noepsfhelp{epsf.tex must be installed for images to
+ work. It is also included in the Texinfo distribution, or you can get
+ it from ftp://tug.org/tex/epsf.tex.}
+%
+\def\image#1{%
+ \ifx\epsfbox\undefined
+ \ifwarnednoepsf \else
+ \errhelp = \noepsfhelp
+ \errmessage{epsf.tex not found, images will be ignored}%
+ \global\warnednoepsftrue
+ \fi
+ \else
+ \imagexxx #1,,,\finish
+ \fi
+}
+%
+% Arguments to @image:
+% #1 is (mandatory) image filename; we tack on .eps extension.
+% #2 is (optional) width, #3 is (optional) height.
+% #4 is just the usual extra ignored arg for parsing this stuff.
+\def\imagexxx#1,#2,#3,#4\finish{%
+ \ifx\pdfoutput\undefined
+ % \epsfbox itself resets \epsf?size at each figure.
+ \setbox0 = \hbox{\ignorespaces #2}\ifdim\wd0 > 0pt \epsfxsize=#2\relax \fi
+ \setbox0 = \hbox{\ignorespaces #3}\ifdim\wd0 > 0pt \epsfysize=#3\relax \fi
+ \begingroup
+ \catcode`\^^M = 5 % in case we're inside an example
+ % If the image is by itself, center it.
+ \ifvmode
+ \nobreak\bigskip
+ % Usually we'll have text after the image which will insert
+ % \parskip glue, so insert it here too to equalize the space
+ % above and below.
+ \nobreak\vskip\parskip
+ \nobreak
+ \centerline{\epsfbox{#1.eps}}%
+ \bigbreak
+ \else
+ % In the middle of a paragraph, no extra space.
+ \epsfbox{#1.eps}%
+ \fi
+ \endgroup
+ \else
+ \centerline{\pdfimage #1.pdf}%
+ \fi
+}
+
+
+\message{localization,}
+% and i18n.
+
+% @documentlanguage is usually given very early, just after
+% @setfilename. If done too late, it may not override everything
+% properly. Single argument is the language abbreviation.
+% It would be nice if we could set up a hyphenation file here.
+%
+\def\documentlanguage{\parsearg\dodocumentlanguage}
+\def\dodocumentlanguage#1{%
+ \tex % read txi-??.tex file in plain TeX.
+ % Read the file if it exists.
+ \openin 1 txi-#1.tex
+ \ifeof1
+ \errhelp = \nolanghelp
+ \errmessage{Cannot read language file txi-#1.tex}%
+ \let\temp = \relax
+ \else
+ \def\temp{\input txi-#1.tex }%
+ \fi
+ \temp
+ \endgroup
+}
+\newhelp\nolanghelp{The given language definition file cannot be found or
+is empty. Maybe you need to install it? In the current directory
+should work if nowhere else does.}
+
+
+% @documentencoding should change something in TeX eventually, most
+% likely, but for now just recognize it.
+\let\documentencoding = \comment
+
+
+% Page size parameters.
+%
+\newdimen\defaultparindent \defaultparindent = 15pt
+
+\chapheadingskip = 15pt plus 4pt minus 2pt
+\secheadingskip = 12pt plus 3pt minus 2pt
+\subsecheadingskip = 9pt plus 2pt minus 2pt
+
+% Prevent underfull vbox error messages.
+\vbadness = 10000
+
+% Don't be so finicky about underfull hboxes, either.
+\hbadness = 2000
+
+% Following George Bush, just get rid of widows and orphans.
+\widowpenalty=10000
+\clubpenalty=10000
+
+% Use TeX 3.0's \emergencystretch to help line breaking, but if we're
+% using an old version of TeX, don't do anything. We want the amount of
+% stretch added to depend on the line length, hence the dependence on
+% \hsize. We call this whenever the paper size is set.
+%
+\def\setemergencystretch{%
+ \ifx\emergencystretch\thisisundefined
+ % Allow us to assign to \emergencystretch anyway.
+ \def\emergencystretch{\dimen0}%
+ \else
+ \emergencystretch = .15\hsize
+ \fi
+}
+
+% Parameters in order: 1) textheight; 2) textwidth; 3) voffset;
+% 4) hoffset; 5) binding offset; 6) topskip. Then whoever calls us can
+% set \parskip and call \setleading for \baselineskip.
+%
+\def\internalpagesizes#1#2#3#4#5#6{%
+ \voffset = #3\relax
+ \topskip = #6\relax
+ \splittopskip = \topskip
+ %
+ \vsize = #1\relax
+ \advance\vsize by \topskip
+ \outervsize = \vsize
+ \advance\outervsize by 2\topandbottommargin
+ \pageheight = \vsize
+ %
+ \hsize = #2\relax
+ \outerhsize = \hsize
+ \advance\outerhsize by 0.5in
+ \pagewidth = \hsize
+ %
+ \normaloffset = #4\relax
+ \bindingoffset = #5\relax
+ %
+ \parindent = \defaultparindent
+ \setemergencystretch
+}
+
+% @letterpaper (the default).
+\def\letterpaper{{\globaldefs = 1
+ \parskip = 3pt plus 2pt minus 1pt
+ \setleading{13.2pt}%
+ %
+ % If page is nothing but text, make it come out even.
+ \internalpagesizes{46\baselineskip}{6in}{\voffset}{.25in}{\bindingoffset}{36pt}%
+}}
+
+% Use @smallbook to reset parameters for 7x9.5 (or so) format.
+\def\smallbook{{\globaldefs = 1
+ \parskip = 2pt plus 1pt
+ \setleading{12pt}%
+ %
+ \internalpagesizes{7.5in}{5.in}{\voffset}{.25in}{\bindingoffset}{16pt}%
+ %
+ \lispnarrowing = 0.3in
+ \tolerance = 700
+ \hfuzz = 1pt
+ \contentsrightmargin = 0pt
+ \deftypemargin = 0pt
+ \defbodyindent = .5cm
+ %
+ \let\smalldisplay = \smalldisplayx
+ \let\smallexample = \smalllispx
+ \let\smallformat = \smallformatx
+ \let\smalllisp = \smalllispx
+}}
+
+% Use @afourpaper to print on European A4 paper.
+\def\afourpaper{{\globaldefs = 1
+ \setleading{12pt}%
+ \parskip = 3pt plus 2pt minus 1pt
+ %
+ \internalpagesizes{53\baselineskip}{160mm}{\voffset}{4mm}{\bindingoffset}{44pt}%
+ %
+ \tolerance = 700
+ \hfuzz = 1pt
+}}
+
+% A specific text layout, 24x15cm overall, intended for A4 paper. Top margin
+% 29mm, hence bottom margin 28mm, nominal side margin 3cm.
+\def\afourlatex{{\globaldefs = 1
+ \setleading{13.6pt}%
+ %
+ \afourpaper
+ \internalpagesizes{237mm}{150mm}{3.6mm}{3.6mm}{3mm}{7mm}%
+ %
+ \globaldefs = 0
+}}
+
+% Use @afourwide to print on European A4 paper in wide format.
+\def\afourwide{%
+ \afourpaper
+ \internalpagesizes{9.5in}{6.5in}{\hoffset}{\normaloffset}{\bindingoffset}{7mm}%
+ %
+ \globaldefs = 0
+}
+
+% @pagesizes TEXTHEIGHT[,TEXTWIDTH]
+% Perhaps we should allow setting the margins, \topskip, \parskip,
+% and/or leading, also. Or perhaps we should compute them somehow.
+%
+\def\pagesizes{\parsearg\pagesizesxxx}
+\def\pagesizesxxx#1{\pagesizesyyy #1,,\finish}
+\def\pagesizesyyy#1,#2,#3\finish{{%
+ \setbox0 = \hbox{\ignorespaces #2}\ifdim\wd0 > 0pt \hsize=#2\relax \fi
+ \globaldefs = 1
+ %
+ \parskip = 3pt plus 2pt minus 1pt
+ \setleading{13.2pt}%
+ %
+ \internalpagesizes{#1}{\hsize}{\voffset}{\normaloffset}{\bindingoffset}{44pt}%
+}}
+
+% Set default to letter.
+%
+\letterpaper
+
+
+\message{and turning on texinfo input format.}
+
+% Define macros to output various characters with catcode for normal text.
+\catcode`\"=\other
+\catcode`\~=\other
+\catcode`\^=\other
+\catcode`\_=\other
+\catcode`\|=\other
+\catcode`\<=\other
+\catcode`\>=\other
+\catcode`\+=\other
+\catcode`\$=\other
+\def\normaldoublequote{"}
+\def\normaltilde{~}
+\def\normalcaret{^}
+\def\normalunderscore{_}
+\def\normalverticalbar{|}
+\def\normalless{<}
+\def\normalgreater{>}
+\def\normalplus{+}
+\def\normaldollar{$}
+
+% This macro is used to make a character print one way in ttfont
+% where it can probably just be output, and another way in other fonts,
+% where something hairier probably needs to be done.
+%
+% #1 is what to print if we are indeed using \tt; #2 is what to print
+% otherwise. Since all the Computer Modern typewriter fonts have zero
+% interword stretch (and shrink), and it is reasonable to expect all
+% typewriter fonts to have this, we can check that font parameter.
+%
+\def\ifusingtt#1#2{\ifdim \fontdimen3\font=0pt #1\else #2\fi}
+
+% Same as above, but check for italic font. Actually this also catches
+% non-italic slanted fonts since it is impossible to distinguish them from
+% italic fonts. But since this is only used by $ and it uses \sl anyway
+% this is not a problem.
+\def\ifusingit#1#2{\ifdim \fontdimen1\font>0pt #1\else #2\fi}
+
+% Turn off all special characters except @
+% (and those which the user can use as if they were ordinary).
+% Most of these we simply print from the \tt font, but for some, we can
+% use math or other variants that look better in normal text.
+
+\catcode`\"=\active
+\def\activedoublequote{{\tt\char34}}
+\let"=\activedoublequote
+\catcode`\~=\active
+\def~{{\tt\char126}}
+\chardef\hat=`\^
+\catcode`\^=\active
+\def^{{\tt \hat}}
+
+\catcode`\_=\active
+\def_{\ifusingtt\normalunderscore\_}
+% Subroutine for the previous macro.
+\def\_{\leavevmode \kern.06em \vbox{\hrule width.3em height.1ex}}
+
+\catcode`\|=\active
+\def|{{\tt\char124}}
+\chardef \less=`\<
+\catcode`\<=\active
+\def<{{\tt \less}}
+\chardef \gtr=`\>
+\catcode`\>=\active
+\def>{{\tt \gtr}}
+\catcode`\+=\active
+\def+{{\tt \char 43}}
+\catcode`\$=\active
+\def${\ifusingit{{\sl\$}}\normaldollar}
+%\catcode 27=\active
+%\def^^[{$\diamondsuit$}
+
+% Set up an active definition for =, but don't enable it most of the time.
+{\catcode`\==\active
+\global\def={{\tt \char 61}}}
+
+\catcode`+=\active
+\catcode`\_=\active
+
+% If a .fmt file is being used, characters that might appear in a file
+% name cannot be active until we have parsed the command line.
+% So turn them off again, and have \everyjob (or @setfilename) turn them on.
+% \otherifyactive is called near the end of this file.
+\def\otherifyactive{\catcode`+=\other \catcode`\_=\other}
+
+\catcode`\@=0
+
+% \rawbackslashxx output one backslash character in current font
+\global\chardef\rawbackslashxx=`\\
+%{\catcode`\\=\other
+%@gdef@rawbackslashxx{\}}
+
+% \rawbackslash redefines \ as input to do \rawbackslashxx.
+{\catcode`\\=\active
+@gdef@rawbackslash{@let\=@rawbackslashxx }}
+
+% \normalbackslash outputs one backslash in fixed width font.
+\def\normalbackslash{{\tt\rawbackslashxx}}
+
+% \catcode 17=0 % Define control-q
+\catcode`\\=\active
+
+% Used sometimes to turn off (effectively) the active characters
+% even after parsing them.
+@def@turnoffactive{@let"=@normaldoublequote
+@let\=@realbackslash
+@let~=@normaltilde
+@let^=@normalcaret
+@let_=@normalunderscore
+@let|=@normalverticalbar
+@let<=@normalless
+@let>=@normalgreater
+@let+=@normalplus
+@let$=@normaldollar}
+
+@def@normalturnoffactive{@let"=@normaldoublequote
+@let\=@normalbackslash
+@let~=@normaltilde
+@let^=@normalcaret
+@let_=@normalunderscore
+@let|=@normalverticalbar
+@let<=@normalless
+@let>=@normalgreater
+@let+=@normalplus
+@let$=@normaldollar}
+
+% Make _ and + \other characters, temporarily.
+% This is canceled by @fixbackslash.
+@otherifyactive
+
+% If a .fmt file is being used, we don't want the `\input texinfo' to show up.
+% That is what \eatinput is for; after that, the `\' should revert to printing
+% a backslash.
+%
+@gdef@eatinput input texinfo{@fixbackslash}
+@global@let\ = @eatinput
+
+% On the other hand, perhaps the file did not have a `\input texinfo'. Then
+% the first `\{ in the file would cause an error. This macro tries to fix
+% that, assuming it is called before the first `\' could plausibly occur.
+% Also back turn on active characters that might appear in the input
+% file name, in case not using a pre-dumped format.
+%
+@gdef@fixbackslash{%
+ @ifx\@eatinput @let\ = @normalbackslash @fi
+ @catcode`+=@active
+ @catcode`@_=@active
+}
+
+% Say @foo, not \foo, in error messages.
+@escapechar = `@@
+
+% These look ok in all fonts, so just make them not special.
+@catcode`@& = @other
+@catcode`@# = @other
+@catcode`@% = @other
+
+@c Set initial fonts.
+@textfonts
+@rm
+
+
+@c Local variables:
+@c eval: (add-hook 'write-file-hooks 'time-stamp)
+@c page-delimiter: "^\\\\message"
+@c time-stamp-start: "def\\\\texinfoversion{"
+@c time-stamp-format: "%:y-%02m-%02d.%H"
+@c time-stamp-end: "}"
+@c End:
diff --git a/Docs/To-be-included-in-the-manual/MySQL-for-dummies b/Docs/To-be-included-in-the-manual/MySQL-for-dummies
new file mode 100644
index 00000000000..7b669af18dc
--- /dev/null
+++ b/Docs/To-be-included-in-the-manual/MySQL-for-dummies
@@ -0,0 +1,271 @@
+===============================================================================
+installing/mysql/binary Fri Jul 17 13:03:03 1998 has
+===============================================================================
+
+ MySQL for dummies - Part 1
+ How to get the binary distribution running on a UNIX system
+
+ MySQL is a trademark of TcX, Sweden.
+
+===============================================================================
+
+Introduction:
+
+This is a simple cookbook for the helpless newbie taking his very first steps
+with MySQL, when he needs a few hints about the options and access rights
+installing the system and starting the basic modules, before he has "aha"ed
+on how simple and clean the basic structure of MySQL is. It will not help
+you with the intricacies and subtle possibilities of SQL as implemented in
+MySQL.
+
+The information in this document is all contained in the MySQL manual in a
+more or less obvious form, but for the newbie that document is a bit over-
+whelming in size, and it contains some new concepts that take some getting
+used to. Sorry if it is pitched too low for some readers. It is only
+intended to get the binary distribution up and running.
+
+I successfully got MySQL going on both a Sun SparcStation 1 running SunOS 4.1.2
+and 2 Linux systems running SuSE release 5.0, one with kernel version 2.0.30,
+one with 2.0.33 by doing exactly what is given here. If it doesn't work
+for you, I suggest the problem is with your system and not with the
+MySQL binary distribution.
+
+-- Howard Schultens hs@neuro-physiol.med.uni-goettingen.de
+
+-------------------------------------------------------------------------------
+
+Nomenclature:
+
+In the following, 'MySQL' refers to the entire database system distributed
+and licensed by TcX. 'mysql' means a specific program in this system.
+
+-------------------------------------------------------------------------------
+
+MySQL user administration and access rights ("privileges"):
+
+It is obvious that MySQL needs its own user management because it is a system
+that is implemented on a number of architectures -- you should be able to use
+it in an identical way on different operating systems. The MySQL user names
+and passwords have basically nothing at all to do with user names and
+passwords on whatever operating system you install it on. You will,
+unfortunately, have to install your users again on MySQL. But this system has
+some big advantages: it is a secure system that allows you to finely
+differentiate access rights based on WHO is using a database from WHERE. It
+does this by the use of its own database containing 3 tables "user" for the
+user names, "db" for the databases, and "host" for the machines that access
+databases. "user" and "db" are the most important for the newbie.
+
+Section 6 of the manual describes all this in detail.
+
+-------------------------------------------------------------------------------
+
+Doing it:
+
+In the following, "foo>" denotes the prompt from your system in user mode,
+"foo#" as root/superuser.
+
+
+1) Get the appropriate binary distribution from a mirror site or directly
+ from TcX at URL http://www.tcx.se. The file name has the form
+ mysql-VERSION-SYSTEM.tgz
+
+ VERSION = Version number, e.g. 3.21.33
+ SYSTEM = OS and architecture, e.g. sunos4.1.4-sparc
+
+ i.e., you would download a file mysql-3.21.33-sunos4.1.4-sparc.tgz.
+
+ This example is for SunOS, but it works exactly analogously on Linux.
+
+2) cd to /usr/local and unpack this with, e.g. the command
+
+ foo#gzip -c -d mysql-VERSION-SYSTEM.tgz|tar xvf -
+
+3) The files are stored in a directory /usr/local/mysql-VERSION-SYSTEM
+ Make a symbolic link to this directory:
+
+ foo#ln -s mysql-VERSION-SYSTEM mysql
+
+ At this point, you might want to create a special user for all your
+ MySQL stuff. I use "mysql". Then you could do
+
+ foo#chown -R mysql mysql-VERSION-SYSTEM
+
+4) FIRST, take care of all the PERL stuff:
+
+ o) You need PERL 5.004 or later already installed on your system. Take
+ care of this first if necessary.
+
+ a) cd to /usr/local/mysql/perl/DBI and do
+ foo#perl Makefile.PL
+ foo#make
+ foo#make test
+ foo#make install (if "make test" is successful)
+
+ b) cd to /usr/local/mysql/perl/Mysql/modules and do
+ foo#perl Makefile.PL
+ foo#make
+ foo#make test
+ foo#make install (if "make test" is successful)
+
+ c) As an option, you can install Data::ShowTable, but this is not absolutely
+ necessary for mysql. Get the PERL module Data-ShowTable-VER.tar.gz
+ (VER = version, eg. 3.3) from a CPAN mirror: I got mine at
+
+ ftp://ftp.gwdg.de/pub/languages/perl/CPAN/modules/by-category/06_Data_Type_Utilities/Data/Data-ShowTable-3.3.tar.gz
+
+ (You should be able to replace "ftp.gwdg.de" by the name of another
+ FTP mirror)
+
+ Put this into /usr/local/mysql/perl and unpack it.
+ You get a directory 'Data-ShowTable-VER'. cd into there and
+ (as root/superuser)
+ foo#perl Makefile.PL
+ foo#make
+ foo#make test
+ foo#make install (if "make test" is successful)
+
+5) cd to /usr/local/mysql and do
+ foo#scripts/mysql_install_db
+
+ you should be in /usr/local/mysql when you start the script.
+
+==>*NOTE* you might want to edit this script before you run it the first
+ time. See method 9b) below.
+
+ If this is successful, one or more copies of the mysql daemon, mysqld,
+ will be running. On SunOS 4.1.x, you get one. On Linux, 3 are running.
+
+-------------------------------------------------------------------------------
+In the rest of this, I will always suppose you are starting in the directory
+/usr/local/mysql, even if it seems mildly inconvenient
+-------------------------------------------------------------------------------
+
+6) You can now select the database 'test' and mess around with it using
+ the client program bin/mysql: start it with
+
+ foo>bin/mysql -u root test
+
+ This says, "start up the MySQL command-line client with the user name
+ 'root' and use the database named 'test', which is a subdirectory in
+ '/usr/local/mysql/data". (n.b. this is NOT the root user of your UNIX
+ system, it is a MySQL user with the same name. You will notice that you
+ don't need a password for this user to use mysql).
+
+ Actually, the way the system is set up by bin/mysql_install_db, you
+ don't even need a user name to access the database 'test'. You can start
+ the client simply with
+
+ foo>bin/mysql test
+
+ 'mysql' should start up with a greeting and a line telling you what your
+ connection id and server version is. At this point, the database 'test'
+ is empty, no tables or anything are defined.
+
+ When you issue SQL commands, DON'T FORGET THE FINAL SEMICOLON, or mysql acts
+ dumb:
+
+ mysql>select * from user
+ ->
+ ->
+
+ and you wonder what's going on. 'mysql' reminds you of this on startup.
+
+7) When you want to close down the server, do
+ foo>bin/mysqladmin shutdown
+
+8) I recommend editing the script bin/safe_mysqld for the binary release
+ so that it always starts up with the correct directories. I replaced
+ the entire header up to but not including
+
+ pidfile=$DATADIR/`/bin/hostname`.pid
+ log=$DATADIR/`/bin/hostname`.log
+ err=$DATADIR/`/bin/hostname`.err
+
+ with
+
+ MY_BASEDIR_VERSION=/usr/local/mysql
+ DATADIR=$MY_BASEDIR_VERSION/data
+ ledir=$MY_BASEDIR_VERSION/bin
+ cd $MY_BASEDIR_VERSION
+
+ This lets you start the mysql daemon from wherever you like.
+
+9) Now let's say you want to put some of your own databases and users into
+ the system. The simplest, most powerful, and dangerous way to do this is
+ to start up the mysql daemon again with:
+
+ foo>bin/mysqld --basedir=/usr/local/mysql --datadir=/usr/local/mysql/data -Sg
+
+ This skips loading the grant tables. The system is open to every kind of
+ mistake now, so be careful. Any user can muck up the grant tables, ie.
+ the lists of users, hosts, and databases themselves, so only use this
+ mode to do these first, very basic things.
+
+ Start the client again now, with
+ foo>bin/mysql mysql
+
+ This tells the client to use the database 'mysql', which is the directory
+ that contains the lists (ie. the tables) of all the users, hosts, and
+ databases in the system, so be careful!!!!!!!!!!!!
+
+ All of what follows is taken essentially from section 6 of the manual.
+
+ a) For the start, just define a couple of users for the MySQL system:
+ i) an administrator, such as 'mysql', with its own password, that
+ can do everything with the system:
+
+ mysql> insert into user values('localhost','mysql',password('xyzzy'),
+ 'Y','Y','Y','Y','Y','Y','Y','Y','Y','Y');
+
+ * For some reason, on my Linux system with a German keyboard, I have *
+ * to use the acute accent instead of the apostrophe, otherwise I get *
+ * parse errors. *
+
+ This defines the user name 'mysql' with password 'xyzzy' that can
+ do everything. To look at what you just did, type in
+
+ mysql> select * from user;
+
+ mysql types out a table with all the known users and their privileges.
+
+ ii) a privileged user for playing around:
+
+ mysql> insert into user values('localhost','john',password('blah0x1'),
+ 'Y','Y','Y','Y','Y','Y','Y','Y','Y','Y');
+
+ iii) create your own database for a todo list, phone numbers, whatever:
+
+ mysql> create database johns_DB;
+ mysql> insert into db values('localhost','johns_DB','john','Y','Y','Y','Y','Y','Y');
+
+ The first line creates the databse "johns_DB", but that doesn't
+ make it visible to mysql. The second line does that.
+
+ iv) When you are done installing users and databases, quit mysql and
+ issue the command
+
+ foo>bin/mysqladmin reload
+
+ b) Another method to do this was suggested by Sinisa Milivojevic, and that
+ is to edit the script /usr/local/mysql/scripts/mysql_install_db to
+ define the databases and install the more important users when you
+ start the system the very first time. This would have the advantage
+ that you can save the script and re-install the system with it if you
+ have to, automatically defining the important structures. It requires
+ a little more knowledge of the MySQL system to do this.
+
+ You might want to use this method anyway since it saves editing
+ mysql_install_db to have it install a superuser with a name other
+ than "root". The places to change are easy to find. You can, of
+ course, use the first method above and remove the user named 'root'
+ when you are done.
+
+
+===============================================================================
+
+If anyone is interested enough in this document to make suggestions on how
+to improve it, I would be glad to get emails on it. I hope it helps
+someone get going with MySQL a little easier.
+
+--Howard
+ hs@neuro-physiol.med.uni-goettingen.de
diff --git a/Docs/Translations/myodbc-br.texi b/Docs/Translations/myodbc-br.texi
new file mode 100644
index 00000000000..6cf7edd3e75
--- /dev/null
+++ b/Docs/Translations/myodbc-br.texi
@@ -0,0 +1,272 @@
+@chapter MySQL ODBC Suporte
+
+@menu
+* Quais ODBC OS:: Sistemas Operacionais são suportados por @strong{MyODBC}
+* Problemas ODBC:: Como informar problemas com @strong{MySQL} ODBC
+* Clientes MyODBC:: Programas que já foram testados com @strong{MyODBC}
+* Administrador ODBC:: Como preencher os diversos campos com o programa Administrador
+* ODBC e last_insert_id:: Como obter o valor de uma coluna @code{AUTO_INCREMENT} em ODBC
+* Informando bug do MyODBC:: Informando problemas com MyODBC
+@end menu
+
+@strong{MySQL} fornece suporte para ODBC através do programa @strong{MyODBC}.
+
+
+@node Quais ODBC OS, ODBC Problemas, ODBC, ODBC
+@section Sistemas Operacionais suportados por MyODBC
+
+@strong{MyODBC} é um driver 32-bit ODBC (2.50) nível 0 para Windows95
+e Windows NT. Nós esperamos que alguém porte o mesmo para o Windows 3.x.
+
+@node Problemas ODBC, clientes MyODBC, Quais ODBC OS, ODBC
+@section Como informar problemas com MyODBC
+
+@strong{MyODBC} tem sido testado com Access, Admndemo.exe, C++-Builder,
+Centura Team Developer (formalmente Gupta SQL/Windows), ColdFusion (no
+Solaris e NT com svc 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++ e Visual
+Basic.
+
+Se você souber de algum outro aplicativo que funcione com @strong{MyODBC}, por favor
+nos escreva sobre isso através do email @email{myodbc@@lists.mysql.com}.
+
+@node Clientes MyODBC, Administrador ODBC, Problemas com ODBC, ODBC
+@section Programas testados que funcionam com MyODBC
+
+A maioria dos programas que têm suporte para ODBC, funcionam com o @strong{MyODBC},
+mas cada um dos listados abaixo, têm sido testados por nós ou por informações de
+usuários que confirmaram o seu funcionamento.
+
+@table @asis
+@item @strong{Program}
+@strong{Comment}
+@item Access
+Como fazer Accces funcionar:
+@itemize @bullet
+@item
+Você deverá ter uma chave primária na tabela.
+@item
+Você deve ter um campo timestamp em todas as tabelas em que você quer controlar a
+atualização.
+
+@item
+Somente use campos doubles float. Access falha quando faz comparações com campos float
+simples.
+@item
+Configure a opção `Return matching rows' quando conectar com o @strong{MySQL}.
+@item
+O Access no NT acusará colunas @code{BLOB} como @code{OLE OBJECTS}.
+Se ao invés disso você quer colunas @code{MEMO}, deve trocar a coluna para
+@code{TEXT} usando @code{ALTER TABLE}.
+@item
+Access às vezes não lida adequadamente com colunas do tipo @code{DATE}.
+Se você tiver problemas com essas colunas, mude as colunas para @code{DATETIME}.
+@item
+Em certas situações, o Access cria consultas SQL ilegais que o
+@strong{MySQL} não pode processar. Você pode resolver isso selecionando o tipo de
+consulta @code{"Query|SQLSpecific|Pass-Through"} no menu do Access.
+@end itemize
+@item DataJunction
+Você tem que trocar para mandar @code{VARCHAR} ao invés de @code{ENUM}, porque
+o mesmo exporta o último de uma maneira que causa fadiga ao @strong{MySQL}.
+@item Excel
+Funciona. Algumas dicas:
+@itemize @bullet
+@item
+Se você tem problemas com datas, tente selecioná-las como strings usando a
+função @code{CONCAT()}. Por exemplo:
+@example
+select CONCAT(rise_time), CONCAT(set_time)
+ from sunrise_sunset;
+@end example
+Os dados de datas enviadas como string são corretamente reconhecidas pelo
+Excel97 como dados do tipo time.
+
+Neste exemplo o propósito de @code{CONCAT()} é enganar o ODBC, fazendo-o pensar
+que a coluna é do 'tipo string'. Sem o @code{CONCAT()}, ODBC sabe que a coluna
+é do tipo time e o Excel não entenderá isso.
+
+Note que isso é um bug no Excel, porque o mesmo converte automaticamente a
+string para time. Isto é muito bom quando o fonte é um arquivo
+texto, mas não se pode dizer o mesmo quando o fonte é uma conexão
+ODBC que informa o tipo exato para cada coluna.
+@end itemize
+@item odbcadmin
+Programa Teste para ODBC.
+@item Delphi
+Você deverá usar DBE 3.2 ou mais atualizado. Configure o campo de opção
+`Don't optimize column width' quando conectando com @strong{MySQL}.
+
+Também, há aqui um código muito útil que configura tanto a
+inserção ODBC e a inserção BDE para MyODBC (a inserção BDE requer um BDE
+Alias Editor que pode ser obtido de graça numa Delphi Super Page
+perto de você.): (Obrigado a Bryan Brunton @email{bryan@@flesherfab.com} por isto)
+
+@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('LANGDRIVER=');
+ 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
+
+@item C++Builder
+Testado com BDE 3.0. O único problema conhecido é que quando o esquema da tabela
+muda, os campos da consulta não são atualizados. BDE entretanto, parece não
+reconhecer chaves primárias, somente Índice PRIMARY, não entanto isto não
+tem sido um problema.
+
+@item Visual basic
+Para atualizar uma tabela, você deverá definir uma chave primária para a tabela.
+@end table
+
+@node Administrador ODBC, ODBC e last_insert_id, Clientes MyODBC, ODBC
+@section Como preencher os diversos campos com o programa Administrador
+
+Existem três possibilidades para especificar o nome do servidor em
+Windows95:
+
+@itemize @bullet
+@item
+Usando o endereço IP do servidor.
+@item
+Adicionar um arquivo @file{lmhosts} com a seguinte informação:
+
+@example
+ip nomeservidor
+@end example
+
+Por exemplo:
+
+@example
+194.216.84.21 my
+@end example
+
+@item
+Configurar o PC para usar DNS.
+@end itemize
+
+Exemplo de como preencher o ``ODBC setup'':
+@example
+Windows DSN name: teste
+Description: Este é o meu banco de dados teste
+MySql Database: teste
+Server: 194.216.84.21
+User: monty
+Password: minha_senha
+Port:
+@end example
+
+O valor para o campo @code{Windows DSN name} é qualquer nome que seja único
+em seu Windows ODBC setup.
+
+Você não precisa especificar os valores para os seguintes campos: @code{Server},
+@code{User}, @code{Password} ou @code{Port} na hora de configurar o ODBC.
+Entretanto, se você o faz, esses valores devem ser usados como padrão para fazer
+uma conexão. Você tem a opção de trocar os valores nesse instante.
+
+Se o número da porta não for especificado, o valor padrão da porta (@value{default_port})
+é usado.
+
+Se você especificar a opção @code{Read options from C:\my.cnf}, os
+grupos @code{client} e @code{odbc} devem ser lidos do arquivo @file{C:\my.cnf}.
+Você pode usar todas as opções que são usadas por @code{mysql_options()}.
+@xref{mysql_options, , @code{mysql_options}}.
+
+@node ODBC e last_insert_id, Informando bug do MyODBC, Administrador ODBC, ODBC
+@section Como obter o valor de uma coluna @code{AUTO_INCREMENT} no ODBC
+
+Um problema muito usual consiste em como saber o valor de uma coluna do tipo
+@code{INSERT} quando a mesma é gerada automaticamente. Com ODBC, você pode
+fazer uma coisa como esta (assumindo que @code{auto} é um campo @code{AUTO_INCREMENT}):
+
+@example
+INSERT INTO foo (auto,text) VALUES(NULL,'text');
+SELECT LAST_INSERT_ID();
+@end example
+
+Ou se você somente quer adicionar o valor noutra tabela, faça o
+seguinte:
+
+@example
+INSERT INTO foo (auto,text) VALUES(NULL,'text');
+INSERT INTO foo2 (id,text) VALUES(LAST_INSERT_ID(),'text');
+@end example
+
+Para o benefício de algumas aplicações ODBC (pelo menos Delphi e Access),
+a seguinte consulta pode ser usada para encontrar o valor do novo registro
+adicionado:
+
+@example
+SELECT * FROM tbl_name WHERE auto IS NULL;
+@end example
+
+@node Informando bug do MyODBC, , ODBC e last_insert_id, ODBC
+@section Informando problemas com MyODBC
+
+Se você encontra dificuldades com MyODBC, deve começar por fazer
+um arquivo log no Administrador ODBC (o log você tem quando
+solicita logs do ODBCADMIN) e um log @strong{MyODBC}. Para gerar um log @strong{MyODBC},
+clique a opção `Trace MyODBC' na tela de configuração da conexão
+@strong{MyODBC}.
+O log será escrito no arquivo @file{C:\myodbc.log}.
+Note que você deve usar a @code{MYSQL.DLL} e não a
+@code{MYSQL2.DLL} para que esta opção funcione!
+
+Verifique as consultas que MyODBC envia para o servidor @strong{MySQL};
+Você deverá ser capaz de encontrar isto através da pesquisa da
+string @code{>mysql_real_query} no arquivo @file{myodbc.log}.
+
+Você deve também tentar duplicar as consultas no monitor @code{mysql}
+ou @code{admndemo} para encontrar se o erro é do MyODBC ou do @strong{MySQL}.
+
+Se você encontrar algo errado, por favor envie somente as linhas
+relevantes (máximo 40 linhas) para o @email{myodbc@@lists.mysql.com}. Favor nunca
+enviar os arquivos log completos do MyODBC ou do ODBC !
+
+Se você não encontra o quê está errado, a última opção
+é fazer um arquivo (tar ou zip) que contenha um arquivo log do MyODBC,
+o arquivo log ODBC e um arquivo README que explique o problema.
+Você o manda para @uref{ftp://www.mysql.com/pub/mysql/secret}. Somente nós da TCX
+devemos ter acesso a esses arquivos que você manda e nós seremos muito discretos com
+os dados !
+
+Se você pode fazer um programa que também mostre o mesmo problema, favor mandá-lo
+também!
+
+Se o programa funciona com outro servidor SQL, você pode fazer um
+arquivo log que faça exatamente a mesma coisa com o outro servidor
+SQL.
+
+Lembre que quanto mais informação você nos fornece, o resultado é
+que nós podemos resolver o problema!
diff --git a/Docs/Tutorial-MySQL-final.txt b/Docs/Tutorial-MySQL-final.txt
new file mode 100644
index 00000000000..bd52554a611
--- /dev/null
+++ b/Docs/Tutorial-MySQL-final.txt
@@ -0,0 +1,1643 @@
+8 Tutorial MySQL
+=======================
+
+Este capítulo ofrece un tutorial de introducción a MySQL, mostrando cómo usar el programa cliente
+mysql para crear y usar una simple base de datos. mysql (al que algunas veces nos referimos como
+"monitor terminal" o simplemente "monitor") es un programa interactivo que te permite conectarte a
+un servidor MySQL, ejecutar consultas y observar los resultados. mysql puede ser usado también en
+modo batch: escribes tus consultas en un fichero de texto, para después pedirle a mysql que
+ejecute el contenido del fichero. Se cubren aquí esas dos formas de usar de usar mysql.
+
+Para ver una lista de opciones proporcionadas por mysql, lánzalo con las opción --help :
+
+ shell> mysql --help
+
+Este capítulo asume que mysql está instalado en tu máquina, y que hay disponible un servidor al que
+te puedes conectar. Si esto no es así, contacta con tu administrador MySQL. (Si el administrador
+eres tú, necesitarás consultar otra sección de este manual).
+
+El capítulo describe el proceso completo de configurar y usar una base de datos. Si estás interesado
+sólo en acceder una base de datos ya existente, querrás saltar las secciones que describen cómo
+crear la base de datos y las tablas que la contienen.
+
+Dado que este capítulo es un tutorial básico, se dejarán en el tintero muchos
+detalles. Consulta las secciones relevantes del manual para más información sobre los temas
+aquí cubiertos.
+
+
+8.1 Conectando y desconectando del servidor
+=============================================
+
+
+Para conectarse al servidor, generalmente necesitarás facilitar un nombre de usuario MySQL cuando
+lances el cliente mysql y, lo más probable, también un password. Si el servidor se está ejecutando
+en una máquina distinta a la que estás conectado, necesitarás especificar también un nombre de
+host. Contacta con tu administrador para averiguar qué parámetros de conexión necesitas usar para
+conectar (es decir, qué host, nombre de usuario y password usar). Una vez que conozcas los
+parámetros adecuados, deberás ser capaz de conectar de la siguiente forma:
+
+shell> mysql -h host -u user -p
+Enter password: *******
+Welcome to the MySQL monitor. Commands end with ; or \g.
+Your MySQL connection id is 459 to server version: 3.22.20a-log
+
+Type 'help' for help.
+
+mysql>
+
+El prompt te indica que mysql ya está listo para la introducción de comandos.
+
+Algunas instalaciones MySQL permiten a los usuarios conectarse como usuarios "anonymous" (sin
+nombre) al servidor ejecutándose en el host local. Si este es el caso en tu máquina, deberías ser
+capaz de conectar a ese servidor invocando mysql sin ninguna opción:
+
+shell> mysql
+
+Una vez que hayas conectado con éxito, puedes desconectarte en cualquier momento tecleando QUIT en
+el prompt mysql> :
+
+mysql> QUIT
+Bye
+
+También puedes desconectar tecleando control-D.
+
+La mayor parte de los ejemplos en las siguientes secciones asumen que estás conectado al
+servidor. Lo indicarán por el prompt mysql>
+
+
+8.2 Haciendo consultas
+========================
+
+Asegúrate de que estás conectado al servidor, como se ha discutido en secciones anteriores. El
+hacerlo no implica que tengas seleccionada ninguna base de datos con la que trabajar, pero está
+bien. En este punto, es más importante averiguar un poco sobre cómo lanzar consultas que lanzarse
+directamente a la creación de tablas, cargar datos en ellas y recuperar los datos de las
+mismas. Esta sección describe los principios básicos de la entrada de comandos, usando varias
+consultas que puedes probar para familiarizarte con la forma de trabajo de mysql.
+
+Aquí presentamos un comando simple que pide al servidor que nos diga su número de versión y fecha
+actual. Tecléalo como se muestra a continuación siguiendo el prompt mysql> y pulsa la tecla RETURN:
+
+
+mysql> SELECT VERSION(), CURRENT_DATE;
++-----------+--------------+
+| version() | CURRENT_DATE |
++-----------+--------------+
+| 3.22.23b | 2000-01-05 |
++-----------+--------------+
+1 row in set (0.06 sec)
+
+mysql>
+
+Esta consulta ilustra muchas cosas sobre mysql:
+
+* Un comando consiste normalmente de una sentencia SQL seguida por un punto y coma. (Existen algunas
+ excepciones donde no es necesario el punto y coma. QUIT, mencionado más adelante, es una de
+ ellas. Conoceremos otras más adelante.)
+
+* Cuando lanzas un comando, mysql lo envía al servidor para su ejecución y muestra los resultados,
+ después imprime otro mysql> para indicar que está listo para otro comando.
+
+* mysql muestra la salida de una consulta como una tabla (filas y columnas). La primera fila
+ contiene etiquetas para las columnas. Las siguientes filas son el resultado de la
+ consulta. Normalmente, las etiquetas de las columnas son los nombres de las columnas que has
+ obtenido de la base de datos. Si pides el valor de una expresión en vez de una columna de una
+ tabla (como en el ejemplo anterior), mysql etiqueta la columna usando la propia expresión.
+
+* mysql muestra el número de filas que se han dado como resultado, y cuánto tiempo llevó la
+ ejecución de la consulta, lo que te da una idea aproximada del rendimiento del servidor. Estos
+ valores son imprecisos porque representan tiempo real (no tiempo de CPU o máquina), y porque están
+ afectados por factores como la carga del servidor y la latencia de la red. (Por cuestiones de
+ brevedad, la línea "rows in set" no se mostrará en los ejemplos posteriores de este capítulo.)
+
+Las palabras clave pueden ser tecleadas en cualquier combinación mayúscula/minúscula. Las siguientes
+consultas son equivalentes:
+
+mysql> SELECT VERSION(), CURRENT_DATE;
+mysql> select version(), current_date;
+mysql> SeLeCt vErSiOn(), current_DATE;
+
+He aquí otra consulta. Demuestra que puedes usar mysql como una calculadora sencilla:
+
+mysql> SELECT SIN(PI()/4), (4+1)*5;
++-------------+---------+
+| SIN(PI()/4) | (4+1)*5 |
++-------------+---------+
+| 0.707107 | 25 |
++-------------+---------+
+
+Los comandos vistos hasta aquí han sido relativamente cortos, sentencias de una sola línea. También puedes
+insertar múltiples sentencias en una sola línea. Simplemente, termina cada una con un punto y coma:
+
+mysql> SELECT VERSION(); SELECT NOW();
+
++-----------+
+| version() |
++-----------+
+| 3.22.23b |
++-----------+
+
++---------------------+
+| NOW() |
++---------------------+
+| 2000-01-05 17:33:16 |
++---------------------+
+
+Un comando no necesita ser dado todo en una sóla línea, así pues, los comandos largos que requieran
+varias lineas no son un problema. mysql determina cuando termina tu sentencia buscando el punto y
+coma final, no buscando el final de la línea de entrada. (En otras palabras, mysql acepta entrada de
+libre formato: recoleta las líneas de entrada pero no las ejecutahasta que vea el punto y coma.)
+
+Aquí tenemos un simple ejemplo de múltiples líneas:
+
+mysql> SELECT
+ -> USER()
+ -> ,
+ -> CURRENT_DATE;
++----------------+--------------+
+| USER() | CURRENT_DATE |
++----------------+--------------+
+| root@localhost | 2000-01-05 |
++----------------+--------------+
+
+En este ejemplo, observa como cambia el prompt de mysql> a -> una vez que has insertado la primera
+línea de una consulta multi-línea. Esta es la forma en que mysql indica que no ha encontrado una
+sentencia completa y que está esperando por el resto. El prompt es tu amigo, dado que ofrece una
+retroalimentación (feedback) significativa. Si usas ese feedback, siempre sabrás a qué está
+esperando mysql.
+
+Si decides que no quieres ejecutar un comando que está en proceso de introducción, puedes cancelarlo
+tecleando \c :
+
+mysql> SELECT
+ -> USER
+ -> \c
+mysql>
+
+Observa aquí también el prompt. Ha vuelto a mysql> tras haber tecleado \c, ofreciendo un feedback
+que indica que mysql está listo para un nuevo comando.
+
+La siguiente tabla muestra cada uno de los prompts que puedes ver y resume qué es lo que significan
+y el estado en el que se encontrará mysql:
+
+Prompt Significado
+mysql> Listo para un nuevo comando
+ -> Esperando una nueva línea de una consulta multi-línea
+ '> Esperando la siguiente línea, se ha insertado una línea que comienza con (')
+ "> Esperando la siguiente línea, se ha insertado una línea que comienza con (")
+
+Las sentencias multi-línea ocurren comúnmente "por accidente" cuando intentas lanzar un comando en
+una única línea, pero olvidas el punto y coma del final. En este caso, mysql espera más entrada:
+
+mysql> SELECT USER()
+ ->
+
+Si esto es lo que te ocurre (crees que has introducido una sentencia pero la única respuesta es un
+prompt como ->), lo más probable es que mysql esté esperando por el punto y coma. Si no observas qué
+es lo que te dice el prompt, podrías quedarte esperando un buen rato antes de enterarte de qué es lo
+que sucede. Introduce un punto y coma para completar la sentencia, y mysql la ejecutará:
+
+mysql> SELECT USER()
+ -> ;
++----------------+
+| USER() |
++----------------+
+| root@localhost |
++----------------+
+
+Los prompts '> y "> ocurren durante la recogida de strings. En MySQL, puedes escribir strings
+encerrados por comillas simples (') o dobles (") (por ejemplo, 'hola' o "adios"), y mysql te permite
+introducir también strings que se cortan en múltiples líneas. Cuando veas un prompt como '> ó ">,
+significa que has introducido una línea que contenía un string que comenzaba por (') o ("), pero que
+no has introducido aún la comilla (simple o doble) de cierre. Esto está bien si realmente estabas
+introduciendo un string multi-línea, pero no es lo más normal. Lo que sí es más normal, es que los
+prompts '> ó "> indiquen que te has olvidado del caracter de cierre " ó '. Por ejemplo:
+
+mysql> SELECT * FROM mi_tabla WHERE nombre ="García AND edad < 30;
+ ">
+
+Si tecleas esta sentencia SELECT, después pulsas ENTER y esperas por el resultado, no sucederá
+nada. En lugar de preocuparte, "¿por qué tarda tanto esta consulta?", observa la pista que te ofrece
+el prompt "> . Esto te indica que mysql espera ver el resto de un string que aún no ha
+terminado. (¿Ves el error en la sentencia? La cadena "García ha perdido las comillas de cierre.)
+
+Llegados a este punto, ¿qué puedes hacer?. Lo más fácil es cancelar el comando. Sin embargo, no
+puedes teclear simplemente \c en este ejemplo, dado que mysql ¡lo interpretará como parte del string
+que está leyendo! En vez de eso, introduce las comillas de cierre (para que mysql sepa que ya has
+terminado de introducir el string), y después teclea \c :
+
+mysql> SELECT * FROM mi_tabla WHERE nombre ="García AND edad < 30;
+ "> "\c
+mysql>
+
+El prompt vuelve a cambiar a mysql>, indicando que mysql está listo para un nuevo comando.
+
+Es importante saber qué significan los prompts '> y ">, dado que si introduces por error un string
+sin cerrar, cualquier otra línea que introduzcas serán ignoradas por mysql - ¡incluyendo una línea
+que contenga QUIT! Esto puede ser bastante confuso, especialmente si no sabes que debes introducir
+la comilla de cierre antes de poder cancelar el comando actual.
+
+8.3 Creando y usando una base de datos
+==========================================
+
+Ahora que sabes como introducir comandos, es hora de acceder a la base de datos.
+
+Supon que tienes varias mascotas en tu casa (tu pequeño "zoo") y que te gustaría llevar un control
+de varios tipos de información sobre estos animales. Puedes hacerlo creando tablas que guarden tus
+datos y cargandolas con la información deseada. Después puedes responder a diferentes series de
+preguntas sobre tus animales extrayendo los datos de las tablas. Esta sección explica cómo hacer
+todo esto:
+
+* Cómo crear una base de datos
+* Cómo crear una tabla
+* Cómo cargar los datos en la tabla
+* Cómo extraer información de la tabla de varias maneras
+* Cómo usar múltiples tablas
+
+La base de datos del zoo será simple (deliberadamente), pero no es difícil pensar en situaciones del
+mundo real en las que se pudiera utilizar una base de datos similar. Por ejemplo, se podría usar una base
+de datos como ésta en una granja para llevar un control del ganado, o por un veterinario para
+controlar el historial de sus pacientes.
+
+Usa la sentencia SHOW para averiguar qué bases de datos existen actualmente en el servidor:
+
+mysql> SHOW DATABASES;
++----------+
+| Database |
++----------+
+| mysql |
+| test |
++----------+
+
+Probablemente, la lista de las bases de datos será diferente en tu máquina, pero las bases de datos
+mysql y test es probable que se encuentren en esa lista. Se requiere la base de datos mysql pues
+describe los privilegios de acceso de los usuarios. La base de datos test se ofrece como campo de
+pruebas para que los usuarios prueben ahí sus teorías.
+
+Si la base de datos test existe, intenta acceder a ella:
+
+mysql> USE test
+Database changed
+
+Observa que USE, como QUIT, no requiere un punto y coma. (Puedes terminar este tipo de sentencias
+con un punto y coma si quieres, pero no es necesario.) La sentencia USE es especial en otro sentido,
+también: debe ser tecleada en una sola línea.
+
+Puedes usar la base de datos test (si tienes acceso a ella) para los ejemplos que siguen, pero
+cualquier cosa que crees en dicha base de datos puede ser eliminada por cualquiera que tenga acceso
+a ella. Por esta razón, deberías pedir a tu administrador MySQL permisos para usar una base de datos
+propia. Suponte que le quieres llamar zoo. El administrador necesitará ejecutar entonces la
+siguiente orden:
+
+mysql> GRANT ALL ON zoo.* TO tu_nombre;
+
+donde tu_nombre es el nombre de usuario MySQL que tengas asignado.
+
+ejemplo:
+
+mysql> GRANT ALL ON zoo.* TO chessy@localhost;
+Query OK, 0 rows affected (0.08 sec)
+
+
+8.3.1 Creando y seleccionando una base de datos
+==================================================
+
+Si el administrador creó la base de datos para tí cuando te configuró los permisos, puedes comenzar
+a usarla. En otro caso, deberás crearla tú mismo:
+
+[chessy@bishito chessy]$ mysql -u chessy
+Welcome to the MySQL monitor. Commands end with ; or \g.
+Your MySQL connection id is 6 to server version: 3.22.23b
+
+Type 'help' for help.
+
+mysql> CREATE DATABASE zoo;
+Query OK, 1 row affected (0.02 sec)
+
+
+Bajo Unix, los nombres de bases de datos son sensibles a las mayúsculas/minúsculas (a diferencia de
+los comandos SQL), así que deberás referirte siempre a tu base de datos con el nombre zoo, no como
+Zoo, ZOO o cualquier otra variante. Es es así también para las tablas. (Bajo Windows, esta
+restricción desaparece, aunque deberías referirte a las bases de datos y a las tablas usando la
+misma sintaxis en tus consultas.)
+
+Crear una base de datos no la selecciona para su uso, debes hacerlo explícitamente. Para hacer que
+la base de datos zoo sea tu base de datos de trabajo, usa el comando:
+
+mysql> USE zoo;
+Database changed
+
+Tu base de datos sólo necesita ser creada una vez, pero debes seleccionarla para usarla cada vez que
+comiences una sesión mysql. Puedes hacerlo lanzando un comando USE como se ha visto en el
+ejemplo. Alternativamente, puedes seleccionar la base de datos desde la línea de comandos cuando
+lanzas mysql. Simplemente especifica su nombre tras los parámetros de conexión que hayas
+escrito. Por ejemplo:
+
+shell> mysql -h host -u user -p zoo
+Enter password: ********
+
+Observa que en la línea de comandos del ejemplo, zoo no es tu password. Si quieres introducir tu
+password como parámetro en la línea de comandos tras la opción -p, debes hacerlo sin teclear un
+espacio en blanco intermedio (es decir, como -pmi_password, no como -p mi_password). Sin embargo, no
+es recomendable poner tu password en la línea de comandos, pues hacerlo lo expone a posibles
+miradas de otros usuarios conectados a tu máquina.
+
+8.3.2 Creando una tabla
+============================
+
+Crear una tabla es la parte fácil, pero hasta este momento está vacía, como te dice la orden SHOW
+TABLES:
+
+mysql> SHOW TABLES;
+Empty set (0.00 sec)
+
+La parte más dura consiste en decidir cual va a ser la estructura de tu base de datos: qué tablas
+necesitarás, y qué columnas tendrá cada una de ellas.
+
+Querrás seguramente una tabla que contenga un registro por cada una de tus mascotas. Esta tabla
+puede llamarse mascotas, y debería contener, como mínimo, el nombre de cada animal. Dado que el
+nombre por sí solo no es muy interesante, la tabla debería contener otra información. Por ejemplo,
+si más de una persona de tu familia tiene mascotas, probablemente quieras listar el propietario de
+cada animal. También querrás guardar información descriptiva básica como puede ser la especie y el
+sexo de cada mascota.
+
+¿Qué pasa con la edad? Podría ser de interés, pero no es una buena cosa a guardar en una base de
+datos. La edad cambia a medida que pasa el tiempo, lo que significa que tendrás que actualizar tus
+registros a menudo. En vez de eso, es mejor almacenar un valor fijo como la edad de
+nacimiento. Después, cada vez que necesites saber la edad, puedes calcularla como la diferencia
+entre la fecha actual y la fecha de nacimiento. MySQL ofrece funciones para realizar cálculos
+aritméticos entre fechas, por lo que esto no es difícil. Almacenar la fecha de nacimiento en lugar
+de la edad tiene también otras ventajas:
+
+* Puedes usar la base de datos para generar recordatorios de cumpleaños de mascotas. (Si crees que
+ este tipo de consulta es algo tonta, observa que es la misma pregunta que necesitarás hacer en el
+ contexto de una base de datos de un negocio para identificar clientes a los que pronto necesitarás
+ mandar un saludo por su cumpleaños, para ese toque personal asistido por ordenador :-)
+
+* Puedes calcular la edad en relación a fechas distintas a la fecha actual. Por ejemplo, si
+ almacenas la fecha de muerte en la base de datos, puedes calcular fácilmente lo vieja que era una
+ mascota cuando murió.
+
+Seguramente puedas pensar en otros tipos de información que sería útil en la tabla mascota, pero los
+identificados hasta ahora son suficientes por el momento: nombre, propietarios, especie, sexo, fecha
+de nacimiento y muerte.
+
+Usa una sentencia CREATE TABLE para especificar la estructura de tu tabla:
+
+mysql> CREATE TABLE mascota (nombre VARCHAR(20), propietario VARCHAR(20),
+ -> especie VARCHAR(20), sexo CHAR(1), nacimiento DATE, muerte DATE);
+
+VARCHAR es una buena elección para las columnas nombre, propietario y especie dado que los valores
+de estas columnas variarán su longitud. Las longitudes de estas columnas no necesitan ser iguales, y
+no necesitan ser 20. Puedes elegir cualquier longitud entre 1 y 255, cualquiera que te parezca
+razonable. (Si realizar una elección pobre y resulta que más adelante necesitas un campo mayor,
+MySQL ofrece una sentencia ALTER TABLE.)
+
+El sexo del animal puede ser representado en una variedad de formas, por ejemplo, "m" y "f", o
+quizás "masculino" y "femenino". Es más simple usar un único caracter, "m" ó "f".
+
+El uso del tipo de datos DATE para las columnas de nacimiento y muerte es una opción bastante
+obvia.
+
+Ahora que ya has creado una tabla, SHOW TABLES debería producir alguna salida:
+
+mysql> SHOW TABLES;
++---------------+
+| Tables in zoo |
++---------------+
+| mascota |
++---------------+
+
+Para verificar que tu tabla fue creada de la forma que esperabas, usa una sentencia DESCRIBE:
+
+mysql> DESCRIBE mascota;
++-------------+-------------+------+-----+---------+-------+
+| Field | Type | Null | Key | Default | Extra |
++-------------+-------------+------+-----+---------+-------+
+| nombre | varchar(20) | YES | | NULL | |
+| propietario | varchar(20) | YES | | NULL | |
+| especie | varchar(20) | YES | | NULL | |
+| sexo | char(1) | YES | | NULL | |
+| nacimiento | date | YES | | NULL | |
+| muerte | date | YES | | NULL | |
++-------------+-------------+------+-----+---------+-------+
+
+Puedes usar DESCRIBE en cualquier momento, por ejemplo, si olvidas los nombres de las columnas de tu
+tabla o a qué tipo de datos pertenecen.
+
+8.3.3 Cargando datos en una tabla
+=====================================
+
+Una vez creada tu tabla, necesitas poblarla. Las sentencias LOAD DATA e INSERT son útiles para esto.
+
+Suponte que tus registros de mascotas pueden ser descritos como se muestra más abajo. (Observa que
+MySQL espera que las fechas se introduzcan en formato AAAA-MM-DD; esto podría ser diferente a lo que
+estás acostumbrado.)
+
+nombre propietario especie sexo nacimiento muerte
+Fluffy Harold gato f 1993-02-04
+Claws Gwen gato m 1994-03-17
+Buffy Harold perro f 1989-05-13
+Fang Benny perro m 1990-08-27
+Bowser Diane perro m 1998-08-31 1995-07-29
+Chirpy Gwen pájaro f 1998-09-11
+Whistler Gwen pájaro 1997-12-09
+Slim Benny serpiente m 1996-04-29
+
+Dado que estás comenzando con una tabla vacía, una forma sencilla de poblarla consiste en crear un
+fichero de texto conteniendo una fila para cada uno de tus animales, y después cargar el contenido del
+fichero en la tabla con una sola sentencia.
+
+Puedes crear un fichero de texto "mascota.txt" conteniendo un registro por línea, con valores separados
+por tabuladores, y dados en el orden en el que las columnas fueron listadas en la sentencia CREATE
+TABLE. Para valores perdidos (como sexos desconocidos, o fechas de muerte de animales que aún están
+vivos), puedes usar valores NULL. Para representar estos en tu fichero de texto, use \N. Por
+ejemplo, el registro para Whistler el pájaro sería algo como esto (donde el espacio en blanco entre
+valores es un simple caracter de tabulación):
+
+Whistler Gwen pájaro \N 1997-12-09 \N
+
+Para cargar el fichero de texto "mascota.txt" en la tabla mascota, usa este comando:
+
+mysql> LOAD DATA LOCAL INFILE "mascota.txt" INTO TABLE mascota;
+
+Puedes especificar el valor de separación de columna y el marcador de final de línea explícitamente
+en la sentencia LOAD DATA si lo deseas, pero por defecto equivalen a TAB y LF (intro). Estos valores
+por defecto son suficientes para que la sentencia que lee el fichero "mascota.txt" funcione
+correctamente.
+
+Cuando quieras añadir nuevos registros uno a uno, la sentencia INSERT es muy útil. En su forma más
+simple, ofreces valores para cada columna, en el orden en el que las columnas fueron listadas en la
+sentencia CREATE TABLE. Supón que Diane consige un nuevo hamster llamado Puffball. Podrías añadir un
+nuevo registro usando una sentencia INSERT como esta:
+
+mysql> INSERT INTO mascota
+ -> VALUES ('Puffball','Diane','hamster','f','1999-03-30',NULL);
+
+Observa que los valores string y fecha se espefican encerrados entre comillas. Observa también que,
+con INSERT, puedes insertar NULL directamente para representar un valor perdido. No usamos \N como
+hacíamos con LOAD DATA.
+
+De este ejemplo, deberías ser capaz de ver que hubiera dido mucho más costoso teclear todos los
+datos necesarios en la tabla mascota con sentencias INSERT que hacerlo como lo hemos hecho con una
+única sentencia LOAD DATA.
+
+
+8.3.4 Extrayendo información de una tabla
+===============================================
+
+
+La sentencia SELECT se usa para recabar información de una tabla. La forma
+general de la sentencia es:
+
+SELECT qué_seleccionar
+FROM de_qué_tabla
+WHERE condiciones_a_satisfacer
+
+qué_seleccionar indica qué es lo que quieres seleccionar. Puede ser una lista de
+columnas, o * para indicar "todas las columnas". de_qué_tabla indica la tabla de
+la que quieres extraer datos. La claúsula WHERE es opcional. Si está presente,
+condiciones_a_satisfacer especifica las codiciones que las filas deben cumplir
+para estar presentes en el resultado de la selección.
+
+8.3.4.1 Seleccionando todos los datos
+=======================================
+
+La forma más simplede SELECT recoge toda la información de una tabla:
+
+mysql> SELECT * FROM mascota;
++----------+-------------+-----------+------+------------+------------+
+| nombre | propietario | especie | sexo | nacimiento | muerte |
++----------+-------------+-----------+------+------------+------------+
+| Bluffy | Harold | gato | f | 1993-02-04 | NULL |
+| Claws | Gwen | gato | m | 1994-03-17 | NULL |
+| Buffy | Harold | perro | f | 1989-05-13 | NULL |
+| Fang | Benny | perro | m | 1990-08-27 | NULL |
+| Bowser | Diane | perro | m | 1998-08-31 | 1995-07-29 |
+| Chirpy | Gwen | pájaro | f | 1998-09-11 | NULL |
+| Whistler | Gwen | pájaro | NULL | 1997-12-09 | NULL |
+| Slim | Benny | serpiente | m | 1996-04-29 | NULL |
+| Puffball | Diane | hamster | f | 1999-03-30 | NULL |
++----------+-------------+-----------+------+------------+------------+
+
+Esta forma de SELECT es útil si quieres revisar tu tabla al completo, por
+ejemplo, tras haberla cargado con tu conjunto inicial de datos. Como suele
+suceder, la salida ya muestra un error en tu fichero de datos: Bowser ¡parece
+haber nacido tras su muerte! Consultando tus papeles originales sobre el
+pedigree del perro, descubres que la fecha correcta de nacimiento es 1989, no
+1998.
+
+Existen al menos un par de maneras de arreglar esto:
+
+* Edita el fichero "mascota.txt" para corregir el error, después vacía la tabla
+ y vuelve a cargarla usando DELETE y LOAD DATA:
+
+mysql> DELETE from mascota;
+mysql> LOAD DATA LOCAL INFILE "mascota.txt" INTO TABLE mascota;
+
+Sin embargo, si haces esto, debes re-escribir el registro para Puffball.
+
+* Arreglar sólo el registro erróneo con la sentencia UPDATE:
+
+mysql> UPDATE mascota SET nacimiento="1989-08-31" WHERE nombre="Bowser";
+
+Como se muestra más arriba, es fácil recuperar el cuerpo de una data. Pero
+típicamente no querrás hacer eso, en particular cuando la tabla sea muy
+larga. Generalmente, estarás más interesado en responder a una pregunta en
+particular, en cuyo caso deberás especificar algunas restricciones en la
+información que deseas. Veamos algunas consultas de selección en términos de
+preguntas sobre tus mascotas que se deben responder.
+
+8.3.4.2 Seleccionando filas en particular
+=============================================
+
+Puedes seleccionar sólo filas en particular de tu tabla. Por ejemplo, si quieres
+verificar el cambio que has realizado a la fecha de nacimiento de Bowser,
+selecciona el registro de Bowser de la siguiente forma:
+
+mysql> SELECT * FROM mascota WHERE nombre="Bowser";
++--------+-------------+---------+------+------------+------------+
+| nombre | propietario | especie | sexo | nacimiento | muerte |
++--------+-------------+---------+------+------------+------------+
+| Bowser | Diane | perro | m | 1989-08-31 | 1995-07-29 |
++--------+-------------+---------+------+------------+------------+
+
+La salida confirma que el año está correctamente registrado como 1989, no 1998.
+
+Las comparaciones de cadenas de texto son normalmente insensibles a las
+mayúsculas/minúsculas, por lo que puedes especificar el nombre como "bowser",
+"BOWSER", etc. El resultado de la consulta será el mismo.
+
+Puedes especificar condiciones en cualquier columna, no sólo el nombre. Por
+ejemplo, si quisieras saber qué animales nacieron a partir de 1998, examina la
+columna nacimiento:
+
+mysql> SELECT * FROM mascota WHERE nacimiento >= "1998-1-1";
++----------+-------------+---------+------+------------+--------+
+| nombre | propietario | especie | sexo | nacimiento | muerte |
++----------+-------------+---------+------+------------+--------+
+| Chirpy | Gwen | pájaro | f | 1998-09-11 | NULL |
+| Puffball | Diane | hamster | f | 1999-03-30 | NULL |
++----------+-------------+---------+------+------------+--------+
+
+Puedes combinar condiciones, por ejemplo, para localizar los perros hembra:
+
+mysql> SELECT * FROM mascota WHERE especie="perro" AND sexo="f";
++--------+-------------+---------+------+------------+--------+
+| nombre | propietario | especie | sexo | nacimiento | muerte |
++--------+-------------+---------+------+------------+--------+
+| Buffy | Harold | perro | f | 1989-05-13 | NULL |
++--------+-------------+---------+------+------------+--------+
+
+La consulta anterior usa el operador lógico AND. Existe también un operador OR:
+
+mysql> SELECT * FROM mascota WHERE especie="serpiente" OR especie="pájaro";
++----------+-------------+-----------+------+------------+--------+
+| nombre | propietario | especie | sexo | nacimiento | muerte |
++----------+-------------+-----------+------+------------+--------+
+| Chirpy | Gwen | pájaro | f | 1998-09-11 | NULL |
+| Whistler | Gwen | pájaro | NULL | 1997-12-09 | NULL |
+| Slim | Benny | serpiente | m | 1996-04-29 | NULL |
++----------+-------------+-----------+------+------------+--------+
+
+AND y OR pueden entremezclarse. Si lo haces, es una buena idea el utilizar
+paréntesis para indicar cómo deberían agruparse las condiciones:
+
+mysql> SELECT * FROM mascota WHERE (especie="gato" AND sexo="m")
+ -> OR (especie="perro" AND sexo="f");
++--------+-------------+---------+------+------------+--------+
+| nombre | propietario | especie | sexo | nacimiento | muerte |
++--------+-------------+---------+------+------------+--------+
+| Claws | Gwen | gato | m | 1994-03-17 | NULL |
+| Buffy | Harold | perro | f | 1989-05-13 | NULL |
++--------+-------------+---------+------+------------+--------+
+
+8.3.4.3 Seleccionando columnas en particular
+===================================================
+
+Si no quieres ver filas completas de tu tabla, simplemente nombra las columnas
+en las cuales estás interesado, separadas por comas. Por ejemplo, si quieres
+saber cuándo nacieron tus animales, selecciona las columnas nombre y nacimiento:
+
+mysql> SELECT nombre, nacimiento FROM mascota;
++----------+------------+
+| nombre | nacimiento |
++----------+------------+
+| Bluffy | 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 |
++----------+------------+
+
+Para averiguar quién posee mascotas, usa esta consulta:
+
+mysql> SELECT propietario FROM mascota;
++-------------+
+| propietario |
++-------------+
+| Harold |
+| Gwen |
+| Harold |
+| Benny |
+| Diane |
+| Gwen |
+| Gwen |
+| Benny |
+| Diane |
++-------------+
+
+Sin embargo, observa que la consulta simplemente obtiene el campo propietario de
+cada registro, y algunos de ellos aparecen más de una vez. Para minimizar la
+salida, obtén cada registro de salida único una sola vez añadiendo la palabra
+reservada DISTINCT:
+
+mysql> SELECT DISTINCT propietario FROM mascota;
++-------------+
+| propietario |
++-------------+
+| Benny |
+| Diane |
+| Gwen |
+| Harold |
++-------------+
+
+Puedes usar una claúsula WHERE para combinar la selección de filas con la
+selección de columnas. Por ejemplo, para conseguir sólo las fechas de nacimiento
+de perros y gatos, usa esta consulta:
+
+mysql> SELECT nombre, especie, nacimiento FROM mascota
+ -> WHERE especie = "perro" OR especie = "gato";
++--------+---------+------------+
+| nombre | especie | nacimiento |
++--------+---------+------------+
+| Bluffy | gato | 1993-02-04 |
+| Claws | gato | 1994-03-17 |
+| Buffy | perro | 1989-05-13 |
+| Fang | perro | 1990-08-27 |
+| Bowser | perro | 1989-08-31 |
++--------+---------+------------+
+
+8.3.4.4 Ordenando filas
+===========================
+
+Tal vez hayas observado que en los ejemplos anteriores las filas del resultado
+se muestran sin ningún tipo de orden en particular. Sin embargo, a menudo es más
+fácil de examinar la salida de una consulta cuando las filas están ordenadas de
+alguna manera en particular. Para ordenar un resultado, usa la claúsula ORDER
+BY.
+
+Aquí mostramos las fechas de nacimiento de los animales, ordenadas por fecha:
+
+mysql> SELECT nombre, nacimiento FROM mascota ORDER BY nacimiento;
++----------+------------+
+| nombre | nacimiento |
++----------+------------+
+| Buffy | 1989-05-13 |
+| Bowser | 1989-08-31 |
+| Fang | 1990-08-27 |
+| Bluffy | 1993-02-04 |
+| Claws | 1994-03-17 |
+| Slim | 1996-04-29 |
+| Whistler | 1997-12-09 |
+| Chirpy | 1998-09-11 |
+| Puffball | 1999-03-30 |
++----------+------------+
+
+Para ordenar de forma inversa, añade la palabra reservada DESC (descendente) al
+nombre de la columna por la que estás ordenando:
+
+mysql> SELECT nombre, nacimiento FROM mascota ORDER BY nacimiento DESC;
++----------+------------+
+| nombre | nacimiento |
++----------+------------+
+| Puffball | 1999-03-30 |
+| Chirpy | 1998-09-11 |
+| Whistler | 1997-12-09 |
+| Slim | 1996-04-29 |
+| Claws | 1994-03-17 |
+| Bluffy | 1993-02-04 |
+| Fang | 1990-08-27 |
+| Bowser | 1989-08-31 |
+| Buffy | 1989-05-13 |
++----------+------------+
+
+Puedes ordenar por múltiples columnas. Por ejemplo, para ordenar por tipo de
+animal, después por fecha de nacimiento dentro del mismo tipo de animal estando
+los animales más jóvenes primero, usa la siguiente consulta:
+
+mysql> SELECT nombre, especie, nacimiento FROM mascota ORDER BY especie, nacimiento DESC;
++----------+-----------+------------+
+| nombre | especie | nacimiento |
++----------+-----------+------------+
+| Claws | gato | 1994-03-17 |
+| Bluffy | gato | 1993-02-04 |
+| Puffball | hamster | 1999-03-30 |
+| Chirpy | pájaro | 1998-09-11 |
+| Whistler | pájaro | 1997-12-09 |
+| Fang | perro | 1990-08-27 |
+| Bowser | perro | 1989-08-31 |
+| Buffy | perro | 1989-05-13 |
+| Slim | serpiente | 1996-04-29 |
++----------+-----------+------------+
+
+Observa que la palabra reservada DESC se aplica sólo al nombre de columna que
+preceda a la palabra reservada (nacimiento); los valores especie siguen siendo
+ordenados en forma ascendente.
+
+8.3.4.5 Cálculos de fecha
+============================
+
+MySQL ofrece muchas funciones que puedes usar para realizar cálculos con fechas,
+por ejemplo, para calcular edades o extraer partes de fechas.
+
+Para determinar cuantos años tiene cada una de tus mascotas, puedes calcular la
+edad como la diferencia entre la fecha de nacimiento y la fecha actual. Puedes
+hacerlo convirtiendo las dos fechas a dias, coge la diferencia, y divídela por
+365 (el número de dias en un año):
+
+mysql> select nombre, (TO_DAYS(NOW())-TO_DAYS(nacimiento))/365 FROM mascota;
++----------+------------------------------------------+
+| nombre | (TO_DAYS(NOW())-TO_DAYS(nacimiento))/365 |
++----------+------------------------------------------+
+| Bluffy | 6.94 |
+| Claws | 5.83 |
+| Buffy | 10.68 |
+| Fang | 9.39 |
+| Bowser | 10.38 |
+| Chirpy | 1.34 |
+| Whistler | 2.10 |
+| Slim | 3.71 |
+| Puffball | 0.79 |
++----------+------------------------------------------+
+
+Aunque la consulta funcione, existen algunos puntos que podrían ser
+mejorados. Primero, el resultado podría ser revisado más fácilmente si las filas
+se presentaran ordenadas de alguna manera. Segundo, la cabecera de la columna
+edad no es muy significativa.
+
+El primer problema puede ser solucionado añadiendo una cláusula ORDER BY nombre
+para ordenar la salida por nombre. Para arreglar el tema del encabezamiento de
+columna, puedes darle un nombre a dicha columna de tal forma que aparezca una
+etiqueta diferente en la salida (esto es lo que se llama un alias de columna):
+
+mysql> select nombre, (TO_DAYS(NOW())-TO_DAYS(nacimiento))/365 AS edad
+ -> FROM mascota ORDER BY nombre;
++----------+-------+
+| nombre | edad |
++----------+-------+
+| Bluffy | 6.94 |
+| Bowser | 10.38 |
+| Buffy | 10.68 |
+| Chirpy | 1.34 |
+| Claws | 5.83 |
+| Fang | 9.39 |
+| Puffball | 0.79 |
+| Slim | 3.71 |
+| Whistler | 2.10 |
++----------+-------+
+
+Para ordenar la salida por edad en lugar de por nombre, puedes hacerlo usando
+símplemente una cláusula ORDER BY diferente:
+
+mysql> select nombre, (TO_DAYS(NOW())-TO_DAYS(nacimiento))/365 AS edad
+ -> FROM mascota ORDER BY edad;
++----------+-------+
+| nombre | edad |
++----------+-------+
+| Puffball | 0.79 |
+| Chirpy | 1.34 |
+| Whistler | 2.10 |
+| Slim | 3.71 |
+| Claws | 5.83 |
+| Bluffy | 6.94 |
+| Fang | 9.39 |
+| Bowser | 10.38 |
+| Buffy | 10.68 |
++----------+-------+
+
+Puede usarse una consulta similar para determinar la edad de la muerte para los
+animales que hayan muerto. Puedes determinar qué animales son estos comprobando
+si el valor muerte es NULL o no. Después, para aquellos que no tengan un valor
+NULL, calcular la diferencia entre los valores muerte y nacimiento:
+
+mysql> select nombre, nacimiento, muerte,
+ -> (TO_DAYS(NOW())-TO_DAYS(nacimiento))/365 AS edad
+ -> FROM mascota WHERE muerte IS NOT NULL ORDER BY edad;
++--------+------------+------------+-------+
+| nombre | nacimiento | muerte | edad |
++--------+------------+------------+-------+
+| Bowser | 1989-08-31 | 1995-07-29 | 10.38 |
++--------+------------+------------+-------+
+
+La consulta usa muerte IS NOT NULL en lugar de muerte != NULL dado que NULL es
+un valor especial. Esto se explica más adelante. [Puedes consultar la sección
+[Working with NULL] del manual de MySQL.
+
+¿Qué harías si quisieras saber qué animales cumplen años el mes que viene? Para
+este tipo de cálculos, año y día son irrelevantes, simplemente querrás extraer
+la parte mes de la columna nacimiento. MySQL ofrece muchas funciones de
+extracción de parte-de-fecha, como YEAR(),MONTH() y DAY(). La función apropiada
+para nuestro problema es MONTH(). Para ver cómo funciona, ejecuta una consulta
+rápida que muestre el valor de la fecha de nacimiento y el mes de nacimiento
+(MONTH(nacimiento)):
+
+mysql> SELECT nombre, nacimiento, MONTH(nacimiento) FROM mascota;
++----------+------------+-------------------+
+| nombre | nacimiento | MONTH(nacimiento) |
++----------+------------+-------------------+
+| Bluffy | 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 |
++----------+------------+-------------------+
+
+Buscar animales que hayan nacido en el mes próximo es también sencillo de
+realizar. Suponte que Abril es el mes actual. Entonces el valor del mes es 4 y
+lo que buscas son animales nacidos en Mayo (mes 5):
+
+mysql> SELECT nombre, nacimiento FROM mascota WHERE MONTH(nacimiento) = 5;
++--------+------------+
+| nombre | nacimiento |
++--------+------------+
+| Buffy | 1989-05-13 |
++--------+------------+
+
+Existe una pequeña complicación si el mes actual es Diciembre, por supuesto. No
+puedes añadir simplemente uno al número de mes (12) y buscar animales nacidos en
+el mes 13, dado que no existe tal mes. En lugar de eso, debes buscar animales
+nacidos en Enero (mes 1).
+
+Puedes escribir la consulta de tal forma que funcione independientemente del mes
+en el que estemos. De esa forma no tendrás que usar un número de mes en
+particular en la consulta. DATE_ADD() te permite añadir un intervalo de tiempo a
+una fecha dada. Si añades un mes al valor de NOW(), y después extraes la parte
+del mes con MONTH(), el resultado produce el mes del cumpleaños que buscamos:
+
+
+mysql> select NOW();
++---------------------+
+| NOW() |
++---------------------+
+| 2000-01-13 18:13:09 |
++---------------------+
+
+mysql> SELECT nombre, nacimiento FROM mascota
+ -> WHERE MONTH(nacimiento) = MONTH(DATE_ADD(NOW(),INTERVAL 1 MONTH));
++--------+------------+
+| nombre | nacimiento |
++--------+------------+
+| Bluffy | 1993-02-04 |
++--------+------------+
+
+Una manera difente de conseguir los mismos resultados es añadir 1 al mes actual
+para conseguir el mes siguiente (tras usar la función módulo (MOD) para
+convertir el valor de mes actual en 0 si estamos en Diciembre (mes 12)):
+
+mysql> SELECT nombre, nacimiento FROM mascota
+ -> WHERE MONTH(nacimiento) = MOD(MONTH(NOW()),12) +1;
++--------+------------+
+| nombre | nacimiento |
++--------+------------+
+| Bluffy | 1993-02-04 |
++--------+------------+
+
+
+8.3.4.6 Trabajando con valores NULL
+=======================================
+
+Los valores NULL pueden ser sorprenderte hasta que te acostumbras a
+usarlos. Conceptualmente, NULL significa "valor perdido" o "valor desconocido" y
+se trata de forma diferente que otros valores. Para realizar comparaciones
+respecto a NULL, no puedes utilizar los operadores de comparación aritméticos
+como =, < o != . Puedes realizar una demostración de esto, prueba la siguiente consulta:
+
+mysql> SELECT 1 = NULL, 1 != NULL, 1 < NULL, 1 > NULL;
++----------+-----------+----------+----------+
+| 1 = NULL | 1 != NULL | 1 < NULL | 1 > NULL |
++----------+-----------+----------+----------+
+| NULL | NULL | NULL | NULL |
++----------+-----------+----------+----------+
+
+Ciertamente, de estas comparaciones no se pueden extraer resultados
+significativos. Para conseguirlo, usa los operadores IS NULL y IS NOT NULL:
+
+mysql> SELECT 1 IS NULL, 1 IS NOT NULL;
++-----------+---------------+
+| 1 IS NULL | 1 IS NOT NULL |
++-----------+---------------+
+| 0 | 1 |
++-----------+---------------+
+
+En MySQL, 0 significa falso y 1 significa VERDADERO.
+
+Este tratamiento especial de NULL fue la causa de que en la sección anterior
+fuera necesario determinar qué animales ya no vivían usando "muerte IS NOT NULL"
+en lugar de "muerte != NULL".
+
+8.3.4.7 Asociación/Coincidencia de patrones (PATTERN MATCHING)
+================================================================
+
+MySQL ofrece las características de asociación de patrones estándar así como
+una forma de coincidencia de patrones basadas en expresiones regulares
+extendidas similares a las usadas por utilidades UNIX como vi, grep y sed.
+
+La asociación de patrones SQL te permite usar '_' para asociar cualquier
+caracter simple, y '%' para asociar un número arbitrario de caracteres
+(incluyendo cero caracteres). Los patrones SQL no toman en cuenta las
+diferencias entre mayúsculas y minúsculas. Se muestran debajo algunos
+ejemplos. Observa que no se utiliza = o != en el trabajo con patrones SQL;
+utiliza en su lugar los operadores de comparación LIKE o NOT LIKE.
+
+Para buscar nombres que comienzan por "b":
+
+mysql> SELECT * FROM mascota WHERE nombre LIKE "b%";
++--------+-------------+---------+------+------------+------------+
+| nombre | propietario | especie | sexo | nacimiento | muerte |
++--------+-------------+---------+------+------------+------------+
+| Bluffy | Harold | gato | f | 1993-02-04 | NULL |
+| Buffy | Harold | perro | f | 1989-05-13 | NULL |
+| Bowser | Diane | perro | m | 1989-08-31 | 1995-07-29 |
++--------+-------------+---------+------+------------+------------+
+
+Para buscar nombres que terminen por "fy":
+
+mysql> SELECT * FROM mascota WHERE nombre LIKE "%fy";
++--------+-------------+---------+------+------------+--------+
+| nombre | propietario | especie | sexo | nacimiento | muerte |
++--------+-------------+---------+------+------------+--------+
+| Bluffy | Harold | gato | f | 1993-02-04 | NULL |
+| Buffy | Harold | perro | f | 1989-05-13 | NULL |
++--------+-------------+---------+------+------------+--------+
+
+Para buscar nombres que contengan una "w":
+
+mysql> SELECT * FROM mascota WHERE nombre LIKE "%w%";
++----------+-------------+---------+------+------------+------------+
+| nombre | propietario | especie | sexo | nacimiento | muerte |
++----------+-------------+---------+------+------------+------------+
+| Claws | Gwen | gato | m | 1994-03-17 | NULL |
+| Bowser | Diane | perro | m | 1989-08-31 | 1995-07-29 |
+| Whistler | Gwen | pájaro | NULL | 1997-12-09 | NULL |
++----------+-------------+---------+------+------------+------------+
+
+Para buscar nombres de longitud cinco caracteres, usa el patrón "_" :
+
+mysql> SELECT * FROM mascota WHERE nombre LIKE "_____";
++--------+-------------+---------+------+------------+--------+
+| nombre | propietario | especie | sexo | nacimiento | muerte |
++--------+-------------+---------+------+------------+--------+
+| Claws | Gwen | gato | m | 1994-03-17 | NULL |
+| Buffy | Harold | perro | f | 1989-05-13 | NULL |
++--------+-------------+---------+------+------------+--------+
+
+El otro tipo de asociación de patrones ofrecido por MySQL utiliza expresiones
+regulares extendidas. Cuando se realiza una comprobación buscando una coincidencia
+para este tipo de patrón, se deben usar los operadores REGEXP y NOT REGEXP (o
+RLIKE y NOT RLIKE, dado que son sinónimos).
+
+Algunas características de las expresiones regulares extendidas son:
+
+* `.' se asocia con cualquier caracter (pero sólo uno)
+
+* Una clase de caracteres `[...]' se asocia con culquier caracter contenido
+ dentro de los corchetes. Por ejemplo, `[abc]' se asocia con 'a', 'b' ó
+
+* 'c'. Para nombrar un rango de caracteres, usa un guión. `[a-z]' se asocia con
+cualquier letra en minúscula, donde '[0-9]' se asocia con cualquier dígito.
+
+* '*' se asocia con 0 o más instancias de lo que preceda al asterisco. Por
+ ejemplo,'a*' coincide con cualquier número de a's,'[0-9]*' se asocia con
+ cualquier número de dígitos, y '.*' se asocia con cualquier cosa.
+
+* Las expresiones regulares son sensibles a las mayúsculas/minúsculas, pero
+ puedes utilizar una clase caracter para asociar ambos casos si los deseas. Por
+ ejemplo, '[aA]' coincide tanto con la letra a minúscula como con la letra A
+ mayúscula y '[a-zA-Z]' coincide con cualquier letra en cualquier modo
+ mayúscula/minúscula.
+
+* El patrón se asocia si ocurre en cualquier lugar dentro del valor a ser
+ probado (los patrones SQL coinciden sólo si se asocian con el valor
+ completo).
+
+* Para anclar un patrón de manera que se busque la coincidencia bien al comienzo
+ o bien al final del valor a ser comprobado, usa '^' al comienzo del patrón o
+ '$' al final del patrón, respectivamente.
+
+Para demostrar cómo funcionan las expresiones regulares, las consultas LIKE
+mostradas antes son reescritas debajo para usar REGEXP:
+
+Para buscar nombres que comiencen por "b", usa '^' para buscar la coincidencia
+al comienzo del nombre y '[bB]' para buscar la asociación tanto con la b
+minúscula como con la b mayúscula:
+
+mysql> SELECT * FROM mascota WHERE nombre REGEXP "^[bB]";
++--------+-------------+---------+------+------------+------------+
+| nombre | propietario | especie | sexo | nacimiento | muerte |
++--------+-------------+---------+------+------------+------------+
+| Bluffy | Harold | gato | f | 1993-02-04 | NULL |
+| Buffy | Harold | perro | f | 1989-05-13 | NULL |
+| Bowser | Diane | perro | m | 1989-08-31 | 1995-07-29 |
++--------+-------------+---------+------+------------+------------+
+
+Para buscar nombres que terminen por "fy", usa "$" para buscar la coincidencia
+al final del nombre:
+
+mysql> SELECT * FROM mascota WHERE nombre REGEXP "fy$";
++--------+-------------+---------+------+------------+--------+
+| nombre | propietario | especie | sexo | nacimiento | muerte |
++--------+-------------+---------+------+------------+--------+
+| Bluffy | Harold | gato | f | 1993-02-04 | NULL |
+| Buffy | Harold | perro | f | 1989-05-13 | NULL |
++--------+-------------+---------+------+------------+--------+
+
+Para buscar nombres que contengan una "w", utiliza "[wW]" para buscar la
+asociación tanto en mayúsculas como minúsculas:
+
+ mysql> SELECT * FROM mascota WHERE nombre REGEXP "[wW]";
++----------+-------------+---------+------+------------+------------+
+| nombre | propietario | especie | sexo | nacimiento | muerte |
++----------+-------------+---------+------+------------+------------+
+| Claws | Gwen | gato | m | 1994-03-17 | NULL |
+| Bowser | Diane | perro | m | 1989-08-31 | 1995-07-29 |
+| Whistler | Gwen | pájaro | NULL | 1997-12-09 | NULL |
++----------+-------------+---------+------+------------+------------+
+
+Dado que un patrón de una expresión regular se asocia si ocurre en cualquier
+lugar del valor, no es necesario poner un caracter comodín en ningún lado del
+patrón para conseguir que se asocie con el valor completo como harías si usaras
+un patrón SQL.
+
+Para buscar nombres conteniendo exactamente cinco caracteres, usa "^" y "$" para
+asociar el comienzo y el final de un nombre, y cinco instancias de "." entre
+ellos:
+
+mysql> SELECT * FROM mascota WHERE nombre REGEXP "^.....$";
++--------+-------------+---------+------+------------+--------+
+| nombre | propietario | especie | sexo | nacimiento | muerte |
++--------+-------------+---------+------+------------+--------+
+| Claws | Gwen | gato | m | 1994-03-17 | NULL |
+| Buffy | Harold | perro | f | 1989-05-13 | NULL |
++--------+-------------+---------+------+------------+--------+
+
+También podrías haber escrito la consulta anterior usando el operador '{n}'
+"repetir n veces":
+
+mysql> SELECT * FROM mascota WHERE nombre REGEXP "^.{5}$";
++--------+-------------+---------+------+------------+--------+
+| nombre | propietario | especie | sexo | nacimiento | muerte |
++--------+-------------+---------+------+------------+--------+
+| Claws | Gwen | gato | m | 1994-03-17 | NULL |
+| Buffy | Harold | perro | f | 1989-05-13 | NULL |
++--------+-------------+---------+------+------------+--------+
+
+
+8.3.4.8 Contando filas
+=======================
+
+Las bases de datos son usadas a menudo para responder a la pregunta, "¿cuantas
+veces aparece un determinado tipo de datos en una tabla?". Por ejemplo, podrías
+querer saber cuántas mascotas tienes, o cuántas mascotas tiene cada propietario,
+o podrías querer realizar varios tipos de censos respecto a tus animales.
+
+Contar el número total de animales que tienes es lo mismo que preguntar
+"¿cuántas filas hay en la tabla mascota?", dado que hay sólo una fila por
+mascota. La función COUNT() cuenta el número de resultados no-NULL , así pues,
+la consulta a realizar para contar el número de animales tiene la siguiente forma:
+
+mysql> SELECT COUNT(*) FROM mascota;
++----------+
+| COUNT(*) |
++----------+
+| 9 |
++----------+
+
+Antes, conseguiste los nombres de las personas que poseen una mascota. Puedes
+usar COUNT() para averiguar cuántas mascotas tiene cada propietario:
+
+mysql> SELECT propietario, COUNT(*) FROM mascota GROUP BY propietario;
++-------------+----------+
+| propietario | COUNT(*) |
++-------------+----------+
+| Benny | 2 |
+| Diane | 2 |
+| Gwen | 3 |
+| Harold | 2 |
++-------------+----------+
+
+Observa el uso de GROUP BY para agrupar todos los registros de cada
+propietario. Si no lo hubiéramos puesto, todo lo que conseguirias sería un
+mensaje de error:
+
+mysql> SELECT propietario, COUNT(propietario) FROM mascota;
+ERROR 1140: Mixing of GROUP columns (MIN(),MAX(),COUNT()...) with no GROUP
+columns is illegal if there is no GROUP BY clause
+
+COUNT() y GROUP BY son útiles para la caracterización de tus datos de varias
+formas. Los siguientes ejemplos muestran difentes maneras para realizar
+operaciones de censo animal.
+
+Número de animales por especies:
+
+mysql> SELECT especie, COUNT(*) FROM mascota GROUP BY especie;
++-----------+----------+
+| especie | COUNT(*) |
++-----------+----------+
+| gato | 2 |
+| hamster | 1 |
+| pájaro | 2 |
+| perro | 3 |
+| serpiente | 1 |
++-----------+----------+
+
+Número de animales por sexo:
+
+mysql> SELECT sexo , COUNT(*) FROM mascota GROUP BY sexo;
++------+----------+
+| sexo | COUNT(*) |
++------+----------+
+| NULL | 1 |
+| f | 4 |
+| m | 4 |
++------+----------+
+
+(En este resultado, NULL indica "sexo desconocido")
+
+El número de animales por combinación de especies y sexo:
+
+mysql> SELECT especie , sexo, COUNT(*) FROM mascota GROUP BY especie, sexo;
++-----------+------+----------+
+| especie | sexo | COUNT(*) |
++-----------+------+----------+
+| gato | f | 1 |
+| gato | m | 1 |
+| hamster | f | 1 |
+| pájaro | NULL | 1 |
+| pájaro | f | 1 |
+| perro | f | 1 |
+| perro | m | 2 |
+| serpiente | m | 1 |
++-----------+------+----------+
+
+No necesitas recuperar una tabla completa cuando uses COUNT(). Por ejemplo, la
+consulta anterior, cuando se realiza sólo sobre perros y gatos, se escribe así:
+
+mysql> SELECT especie , sexo, COUNT(*) FROM mascota
+ -> WHERE especie = "perro" OR especie = "gato"
+ -> GROUP BY especie, sexo;
++---------+------+----------+
+| especie | sexo | COUNT(*) |
++---------+------+----------+
+| gato | f | 1 |
+| gato | m | 1 |
+| perro | f | 1 |
+| perro | m | 2 |
++---------+------+----------+
+
+O, si quieres conocer el número de animales por sexo sólo para animales de sexo
+conocido:
+
+mysql> SELECT especie , sexo, COUNT(*) FROM mascota
+ -> WHERE sexo IS NOT NULL
+ -> GROUP BY especie, sexo;
++-----------+------+----------+
+| especie | sexo | COUNT(*) |
++-----------+------+----------+
+| gato | f | 1 |
+| gato | m | 1 |
+| hamster | f | 1 |
+| pájaro | f | 1 |
+| perro | f | 1 |
+| perro | m | 2 |
+| serpiente | m | 1 |
++-----------+------+----------+
+
+
+8.3.5 Usando más de una tabla
+===============================
+
+La tabla mascota guarda datos sobre las mascotas que posees. Si quieres guardar
+otra información sobre ellos, como eventos en sus vidas, visitas al veterinario
+o cuándo han tenido hermanos, necesitas otra tabla. ¿Cómo debería ser esta otra
+tabla?
+
+* Deberá contener el nombre de la mascota de tal forma que pudieras saber a qué
+ animal corresponde cada evento almacenado en la misma.
+
+* Necesitará una fecha para conocer cuándo ocurrió el evento.
+
+* Necesitará un campo para describir el evento
+
+* Si quieres ser capaz de categorizar los eventos, sería útil tener un campo de
+ tipo evento.
+
+Dadas estas consideraciones, la sentencia CREATE TABLE para la tabla "evento" se
+parecería a esto:
+
+mysql> CREATE TABLE evento (nombre VARCHAR(20), fecha DATE,
+ -> tipo VARCHAR(15), anotación VARCHAR(255));
+
+Como ocurría con la tabla mascota, es más fácil cargar los registros iniciales
+creando un fichero de texto delimitado por tabuladores conteniendo la
+información:
+
+Fluffy 1995-05-15 parto 4 cachorros, 3 hembras, 1 macho
+Buffy 1993-06-23 parto 5 cachorros, 2 hembras, 3 machos
+Buffy 1994-06-19 parto 3 cachorros, 3 hembras
+Chirpy 1999-03-21 veterinario necesitó enderezamiento de pico
+Slim 1997-08-03 veterinario costilla rota
+Bowser 1991-10-12 perrera
+Fang 1991-10-12 perrera
+Fang 1998-08-28 cumpleaños Se le regala un nuevo juguete de goma
+Claws 1998-03-17 cumpleaños Se le regala un nuevo collar de pulgas
+Whistler 1998-12-09 cumpleaños Primer cumpleaños
+
+
+Carga los registros así:
+
+mysql> LOAD DATA LOCAL INFILE "evento.txt" INTO TABLE evento;
+
+Basándote en lo que has aprendido de las consultas que has ejecutado em la tabla
+mascota, deberías ser capaz de realizar recuperaciones de datos en los registros
+de la tabla "evento"; los principios son los mismos. ¿Pero qué hacer cuando la
+tabla evento no sea suficiente por sí sola de responder a cuestiones que
+podrías llegar a realizar?
+
+Supón que quisieras averiguar las edades de cada mascota al tener cachorros. La
+tabla evento indica cuándo ha ocurrido esto, pero para calcular la edad de la
+madre, necesitas su fecha de nacimiento. Dado que eso está almacenado en la
+tabla mascota, necesitas ambas tablas para la consulta:
+
+mysql> SELECT mascota.nombre , (TO_DAYS(fecha) - TO_DAYS(nacimiento))/365 AS edad, anotación
+ -> FROM mascota, evento
+ -> WHERE mascota.nombre = evento.nombre AND tipo = "parto";
++--------+------+----------------------------------+
+| nombre | edad | anotación |
++--------+------+----------------------------------+
+| Fluffy | 2.27 | 4 cachorros, 3 hembras, 1 macho |
+| Buffy | 4.12 | 5 cachorros, 2 hembras, 3 machos |
+| Buffy | 5.10 | 3 cachorros, 3 hembras |
++--------+------+----------------------------------+
+
+Existen varios puntos que anotar sobre esta consulta:
+
+* La cláusula FROM lista dos tablas dado que la consulta necesita extraer
+ información de las dos.
+
+* Cuando se combina la información de múltiples tablas, necesitas especificar
+ cómo pueden ser asociados los registros de una tabla con los registros de la
+ otra. Esto es fácil dado que ambas tienen una columna nombre (N.T.: nombre es
+ una clave extranjera). La consulta usa la cláusula WHERE para combinar los
+ registros de las dos tablas basándose en los valores de nombre.
+
+* Dado que la columna nombre aparece en ambas tablas, debes ser específico sobre
+ a qué tabla te refieres cuando estés hablando de esa columna. Esto se realiza
+ poniendo el nombre de la tabla como prefijo de la columna.
+
+No necesitas tener dos tablas diferentes para realizar un join. En algunas
+ocasiones es útil realizar un join de una tabla consigo misma, si quieres comparar
+registros de una tabla con otros registros en la misma tabla. Por ejemplo, para buscar
+parejas de sexos entre tus mascotas, puedes enlazar la tabla mascota consigo
+mismo para emaparejar machos y hembras de las mismas especies:
+
+mysql> SELECT p1.nombre, p1.sexo, p2.nombre, p2.sexo, p1.especie
+ -> FROM mascota AS p1, mascota AS p2
+ -> WHERE p1.especie = p2.especie AND p1.sexo = "f" AND p2.sexo = "m";
++--------+------+--------+------+---------+
+| nombre | sexo | nombre | sexo | especie |
++--------+------+--------+------+---------+
+| Fluffy | f | Claws | m | gato |
+| Buffy | f | Fang | m | perro |
+| Buffy | f | Bowser | m | perro |
++--------+------+--------+------+---------+
+
+
+En esta consulta, especificamos un par de alias para el nombre de las tablas
+y ser capaces así de referirnos a las columnas y saber en todo momento a qué
+instancia de qué tabla se asocia cada referencia de columna.
+
+8.4 Obtener información sobre bases de datos y tablas
+================================================================
+
+¿Qué ocurre si olvidas el nombre de una base de datos o de una tabla, o cuál es
+la estructura de una tabla dada (ejm. : ¿cómo se llaman sus columnas?) MySQL
+soluciona este problema a través de numerosas sentencias que ofrecen información
+sobre las bases de datos y las tablas que soporta.
+
+Ya hemos visto SHOW DATABASES, que lista las bases de datos gestionadas por el
+servidor. Para averiguar qué base de datos está actualmente seleccionada, usa la
+función DATABASE():
+
+mysql> SELECT DATABASE();
++------------+
+| DATABASE() |
++------------+
+| zoo |
++------------+
+
+Si aún no has seleccionado ninguna base de datos, el resultado estará en blanco.
+
+Para averiguar qué tablas contiene la base de datos actual (por ejemplo, cuando
+no estás seguro sobre el nombre de una tabla), usa este comando:
+
+mysql> SHOW TABLES;
++---------------+
+| Tables in zoo |
++---------------+
+| evento |
+| mascota |
++---------------+
+
+Si quieres averiguar la estructura de una tabla, el comando DESCRIBE te será
+útil; muestra información sobre cada columna de una tabla:
+
+mysql> DESCRIBE mascota;
++-------------+-------------+------+-----+---------+-------+
+| Field | Type | Null | Key | Default | Extra |
++-------------+-------------+------+-----+---------+-------+
+| nombre | varchar(20) | YES | | NULL | |
+| propietario | varchar(20) | YES | | NULL | |
+| especie | varchar(20) | YES | | NULL | |
+| sexo | char(1) | YES | | NULL | |
+| nacimiento | date | YES | | NULL | |
+| muerte | date | YES | | NULL | |
++-------------+-------------+------+-----+---------+-------+
+
+Field indica el nombre de la columna, Type es el tipo de datos para la columna,
+Null indica si la columna puede contener o no valores NULL, Key indica si la
+columna está indexada o no, y Default especifica el valor por defecto para la
+columna.
+
+Si tienes índices en una tabla, SHOW INDEX FROM nombre_tabla te mostrará
+información sobre ellos.
+
+8.5 Usando mysql en modo batch
+=================================
+
+En las secciones previas, hemos usado mysql interactivamente para introducir
+consultas y observar los resultados. También puedes ejecutar mysql en modo
+batch. Para realizarlo, escribe los comandos que quieras ejecutar en un fichero,
+después pídele a mysql que lea su entrada desde el fichero:
+
+shell> mysql < fichero-batch
+
+(N.T.: en ocasiones se traduce como fichero por lotes)
+
+Si necesitas especificar parámetros de conexión en la línea de comandos, el
+comando podría parecerse a esto:
+
+shell> mysql -h host -u user -p < fichero-batch
+Enter password: ********
+
+Cuando usas MySQL de esta manera, estás creando un fichero script (de guión), y
+después ejecutando el script.
+
+¿Por qué usar un script? He aquí algunas razones:
+
+* Si ejecutas una consulta repetidamente (digamos, cada día o cada semana), el
+ construir un script con esta consulta te permite evitar volver a teclearla
+ cada vez que la ejecutes.
+
+* Puedes generar nuevas consultas a partir de consultas ya existentes similares
+ simplemente copiando y editando los ficheros script.
+
+* El modo batch puede ser también muy útil cuando estés desarrollando una
+ consulta, particularmente para comandos multi-línea o múltiples secuencias de
+ comandos de múltiples sentencias. Si cometes un error, no necesitas reescribir
+ todo. Símplemente edita el script para corregir el error, y después pídele a
+ mysql que lo vuelva a ejecutar.
+
+* Si tienes una consulta que produce resultados muy largos, puedes usar un
+ paginador para filtrar esta salida en lugar de ver cómo se desplaza fuera del
+ alcance de tu pantalla:
+
+
+shell> mysql < fichero_batch | more
+
+* Puedes redirigir la salida a un fichero para un procesamiento posterior:
+
+shell> mysql < fichero_batch > mysql.out
+
+* Puedes distribuir tu script a otras personas para que puedan ejecutar también
+ tus comandos.
+
+* Algunas situaciones no permiten un uso interactivo, por ejemplo, cuando
+ ejecutas una consulta como una tarea de cron. (N.T.: cron es un comando UNIX
+ que sirve para planificar y ejecutar comandos UNIX en el tiempo). En este
+ caso, debes usar el procesamiento por lotes.
+
+El formato de salida por defecto es diferente (más conciso) cuando ejecutas
+mysql en modo batch que cuando lo usas de manera interactiva. Por ejemplo, la
+salida de SELECT DISTINCT especie FROM mascota es la siguiente cuando se
+ejecuta de manera interactiva:
+
+mysql> SELECT DISTINCT especie FROM mascota;
++-----------+
+| especie |
++-----------+
+| gato |
+| hamster |
+| pájaro |
+| perro |
+| serpiente |
++-----------+
+
+Y la siguiente si se ejecuta en modo batch:
+
+especie
+gato
+hamster
+pájaro
+perro
+serpiente
+
+Si quieres obtener el formato de salida del modo interactivo también en modo
+batch, usa mysql -t. Para redirigir a salida estándar los comandos que se están
+ejecutando, usa mysql -vvv.
+
+
+
+8.6 Consultas del proyecto gemelos
+
+En Analytikerna y Lentus, hemos estado realizando el trabajo de campo y sistemas para
+un gran proyecto de investigación. Este proyecto es una colaboración entre el Instituto de
+Medicina Medioambiental en el Karolinska Institutet Stockholm y la Sección en Investigación
+Clínica en Envejecimiento y Psicología en la Universidad del Sur de California.
+
+El proyecto consistió en una parte de selección donde todos los gemelos en Suecia mayores de
+65 años eran entrevistados por teléfono. Los gemelos que reunían ciertos criterios pasaban a la
+siguiente fase. En esta fase posterior, los gemelos que querían participar eran visitados por
+un equipo doctor/enfermera. Algunos de los exámenes incluían exámenes físicos y neuropsicológicos,
+pruebas de laboratorio, neuroimágenes, valoración del estado psicológico, y recopilación de la
+historia familiar. Además, se recogieron datos sobre los factores de riesgo médicos y
+medioambientales.
+
+Puede encontrarse más información sobre los estudios de gemelos en :
+
+ http://www.imm.ki.se/TWIN/TWINUKW.HTM
+
+La última parte del proyecto se administra con un interfaz web escrito usando Perl y MySQL.
+Cada noche, todos los datos de las entrevistas son movidos a una base de datos MySQL.
+
+8.6.1 Buscar todos los gemelos no-distribuidos
+
+La siguiente consulta se usa para determinar quién pasa a la segunda parte del proyecto:
+
+ 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 from 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.death_date = 0 or
+ (((to_days(p2.death_date) - to_days(p2.birthday)) / 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) o
+ /* 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;
+
+Algunas explicaciones:
+
+`concat(p1.id, p1.tvab) + 0 as tvid'
+ Queremos ordenar por la concatenación de `id' y `tvab' en orden numérico.
+ Añadiendo `0' al resultado provocamos que *MySQL* trate el resultado como
+ un número.
+
+column `id'
+ Esto identifica un par de gemelos. Es una clave en todas las tablas.
+
+column `tvab'
+ Esto identifica un gemelo de una pareja. Tiene un valor de `1' ó `2'
+
+column `ptvab'
+ Esto es la inversa de `tvab'. Cuando `tvab' es `1' esto es `2', y
+ vice versa. Esto existe para ahorrarnos teclear y para hacer más fácil
+ la optimización de la consulta a MySQL.
+
+
+Esta consulta demuestra, entre otras cosas, cómo realizar búsquedas en una tabla
+enlazada con la misma tabla a través de un join (p1 y p2). En el ejemplo, ésto
+se usa para comprobar cuándo un gemelo de una pareja murió antes de cumplir 65.
+En caso afirmativo, la fila no es devuelta.
+
+Todo lo anterior existe en todas las tablas con información relacionada con los gemelos.
+Tenemos una clave tanto en id, tvab (todas las tablas) como en id,ptvab (person_data) para
+construir consultas más rápidas.
+
+En nuestra máquina de producción (una UltraSPARC 200MHz), esta consulta devuelve alrededor
+de 150-200 filas y tarda menos de un segundo.
+
+El número actual de registros en las tablas usadas arriba:
+
+Tabla Filas
+
+person_data 71074
+lentus 5291
+twin_project 5286
+twin_data 2012
+informant_data 663
+harmony 381
+postal_groups 100
+
+
+
+
+8.6.2 Mostrar una tabla con el estado de la pareja de gemelos.
+
+Cada entrevista finaliza con un código de estado llamado event. La consulta mostrada
+debajo se usa para imprimir una tabla sobre todas las parejas de gemelos combinadas por evento.
+Esto indica en cuántas parejas ambos gemelos han finalizado, en cuántas parejas
+ha finalizado un gemelo y el otro se rechazó, etc.
+
+ 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;
+
+
+
diff --git a/Docs/internals.texi b/Docs/internals.texi
new file mode 100644
index 00000000000..01f5b0a346c
--- /dev/null
+++ b/Docs/internals.texi
@@ -0,0 +1,134 @@
+\input texinfo @c -*-texinfo-*-
+@c Copyright 1998 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 shold 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
+@c %**end of header
+
+@ifinfo
+@format
+START-INFO-DIR-ENTRY
+* mysql-internals: (mysql-internals). @strong{MySQL} internals.
+END-INFO-DIR-ENTRY
+@end format
+@end ifinfo
+
+@titlepage
+@sp 10
+@center @titlefont{@strong{MySQL} Internals Manual.}
+@sp 10
+@center Copyright @copyright{} 1998 TcX AB, Detron HB and Monty Program KB
+@end titlepage
+
+@node Top, Introduction, (dir), (dir)
+
+@ifinfo
+This is a manual about @strong{MySQL} internals.
+@end ifinfo
+
+@menu
+@end menu
+
+@node caching
+@chapter How do MySQL handle caching
+
+MySQL has the following caches:
+(Note that the some of the filename has wrong spelling of cache :)
+
+@itemize @bullet
+@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. mysys/mf_keycash.c
+
+@item Record cache
+This is used for quick scanning of all records in a table.
+mysys/mf_iocash.c and isam/_cash.c
+
+@item Table cache
+This holds the last used tables. sql/sql_base.cc
+
+@item Hostname cache
+For quick lookup (with reverse name resolving). Is a must when one has a
+slow DNS. sql/hostname.cc
+
+@item Privilege cache
+To allow quick change between databases the last used privileges are
+cached for each user/database combination. 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 Join row cache.
+For every full join in a SELECT statement (a full join here means there
+was 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 do MySQL handle flush tables
+
+@itemize @bullet
+@item
+Flush tables is handled in sql/sql_base.cc::close_cached_tables().
+@Item
+The idea of flush tables is to force all tables to be closed. This
+is mainly to ensure that if someone adds a new table outside of
+MySQL (for example with 'cp') all threads will start using the new table.
+This will also ensure that all table changes are flushed to disk
+(but of course not as optimally as simple calling a sync on all tables)!
+@item
+When one does a 'flush tables', the variable '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
+all instanses of a table to be closed).
+@item
+The current refresh_version is also compared to the open refresh_version
+after a thread gets a lock on a table. If the 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
+sql/lock.cc::mysql_lock_tables() and sql/sql_base.cc::wait_for_tables().
+@item
+When all tables has been closed flush-tables will return an ok to client.
+@item
+If the thread that is doing flush-table has a lock on some tables,
+it will first closes the locked tables, wait until all other threads
+have also closed these and then reopen these and get the locks.
+After this it will give other threads a possibility to open the
+same tables.
+@end itemize
+
+@node Index
+@unnumbered Index
+
+@printindex fn
+
+@summarycontents
+@contents
+
+@bye
+
+Do text here do something ??
diff --git a/Docs/manual-license-spanish.texi b/Docs/manual-license-spanish.texi
new file mode 100644
index 00000000000..c9cf2bd53da
--- /dev/null
+++ b/Docs/manual-license-spanish.texi
@@ -0,0 +1,709 @@
+@cindex Licensing terms
+@cindex Support terms
+@node Licensing and Support, Installing, Questions, Top
+@chapter MySQL licensing and support
+
+@menu
+* Licensing policy:: Política de licenciamento do @strong{MySQL}
+* Copyright:: Direitos autorais usados por @strong{MySQL}
+* Commercial use:: Distribuindo comercialmente @strong{MySQL}
+* Licensing examples:: Exemplos de situações de licenciamento
+* Cost:: Preços de licenciamento e suporte @strong{MySQL}
+* Support:: Tipos de suporte comercial
+@end menu
+
+Este capítulo descreve os tipos de licenciamento e suporte do @strong{MySQL}, incluindo:
+
+@itemize @bullet
+@item
+Nossa política de licenciamento para sistemas operacionais não Microsoft e Microsoft
+
+@item
+Os direitos autorais sob os quais o @strong{MySQL} é distribuído
+(@pxref{Copyright})
+
+@item
+Exemplo de situações quando uma licença é necessária
+(@pxref{Licensing examples})
+
+@item
+Preços de licenciamento e suporte (@pxref{Cost}), e
+benefícios do suporte (@pxref{Support})
+@end itemize
+
+@cindex Licensing policy
+@node Licensing policy, Copyright, Licensing and Support, Licensing and Support
+@section MySQL licensing policy
+
+Os termos formais do licenciamento para sistemas operacionais não Microsoft tais como
+Unix ou OS/2 são especificados em @ref{Public license}. Basicamente, nossa política de
+licenciamento é como segue:
+
+@itemize @bullet
+@item
+Para uso interno normal, o @strong{MySQL} geralmente não custa nada. Você não precisa
+nos pagar se não o quiser.
+
+@item
+Uma licença é requerida se:
+
+@itemize @minus
+@item
+Você vende o servidor @strong{MySQL} diretamente ou como parte de outro produto ou serviço.
+
+@item
+Você cobra para instalar e manter um servidor @strong{MySQL} no local do cliente
+
+@item
+Você incluie o @strong{MySQL} numa distribuição que não é redistribuída
+e você cobra por alguma parte dessa distribuição
+@end itemize
+
+@item
+Para circunstâncias sob as quais uma licença do @strong{MySQL} é requerida,
+você necessita uma licença por mâquina que roda o servidor @code{mysqld}.
+Entretanto, uma mâquina com múltiplos processadores conta como uma mâquina
+simples e não há restrição no número de servidores que rodam numa só mâquina
+ou no número de clientes concurrentes conectados ao servidor em essa mâquina.
+
+@item
+Você não necessita uma licença para incluir código de programas clientes
+comerciais. O acesso de parte de clientes para o @strong{MySQL} é de
+domínio público. O código do cliente @code{mysql} de linha de comando
+incluie código da livraria @code{readline} que está sob a licença pública
+GNU.
+
+@item
+@cindex @code{myisampack}
+Para clientes que tem comprado 1 licença ou suporte MySQL, nós fornecemos
+funcionalidade adicional. Atualmente, isso significa o fornecimento do
+utilitário @code{myisampack} para banco de dados somente de leitura,
+rápidos e compactados. (O servidor incluie suporte para ler tais bancos
+de dados mas não a ferramenta de compactar usada para criar os mesmos).
+Quando os acordos de suporte gerem suficientes recursos, nós liberaremos
+esta ferramenta sob a mesma licença do servidor @strong{MySQL}.
+
+@item
+Se seu uso do @strong{MySQL} não requer uma licença, porém você gosta
+do @strong{MySQL} e deseja encorajar um maior desenvolvimento, você é
+certamente bem-vindo a adquirir uma licença de qualquer forma.
+
+@item
+Se usa o @strong{MySQL} num contexto comercial de tal forma
+que obtêm benefícios no seu uso, nós lhe solicitamos que apoie
+o desenvolvimento do @strong{MySQL} através da compra de algum
+nível de suporte. Nós achamos que se o @strong{MySQL} o ajuda
+em seu negócio, é razoável que solicitemos sua ajuda para o @strong{MySQL}.
+Por outro lado, se você nós faz perguntas de suporte, não somente está
+usando de graça algo no qual nós colocamos um enorme trabalho, você
+também está pedindo suporte de graça.
+@end itemize
+
+Para uso em sistemas operacionais Microsoft (Win95/Win98/WinNT),
+você precisa de uma licença @strong{MySQL} depois de 30 dias
+de experiência, com a exceção que licenças podem ser requeridas
+sem nenhum custo para uso educacional ou para suportar pesquisas
+de governo ou universidades. @xref{Winlicense}.
+Uma versão shareware do @strong{MySQL}-Win32 que você pode experimentar
+antes de comprar está disponível em @uref{http://www.mysql.com/mysql_w32.htmy}.
+Depois que você tenha pago, você terá uma senha que permite seu acesso a uma
+nova versão @strong{MySQL}-Win32.
+
+Se você tem uma pergunta se for o caso ou não de requerer uma licença para
+seu caso em particular do @strong{MySQL}, favor entrar em contato com nós.
+@xref{Contact information}.
+
+Se você requer uma licença @strong{MySQL}, a forma mais fácil para pagar
+a mesma é usar o formulário no seguro servidor TcX em @url{https://www.mysql.com/license.htmy}.
+Outras formas de pagamento são mencionadas em @ref{Payment information}.
+
+@cindex Copyright
+@node Copyright, Commercial use, Licensing policy, Licensing and Support
+@section Copyrights used by MySQL
+
+@menu
+* Copyright changes:: Possível futura mudança no direito autoral
+@end menu
+
+Existem vários direitos autorais diferentes na distribuição @strong{MySQL}:
+
+@enumerate
+@item
+
+O fonte específico @strong{MySQL}necessário para construir o @code{mysqlclient}
+livrarias e programas no diretório @file{client} está em domínio público.
+Cada arquivo que está em domínio público tem um cabeçalho que claramente notifica
+este estado. Isto incluie tudo no diretório @file{client}e algumas partes
+do @code{mysys}, @code{mystring} e @code{dbug} livrarias.
+
+@item
+Algumas pequenas partes do fonte (GNU @code{getopt}) estão cobertas pela
+``GNU LIBRARY LIBRARY GENERAL PUBLIC LICENSE''. Ver o arquivo
+@file{mysys/COPYING.LIB}.
+
+@item
+Algumas pequenas partes do fonte ( (GNU @code{readline}) estão cobertas pela
+``GNU GENERAL PUBLIC LICENSE''. Ver o arquivo @file{readline/COPYING}.
+
+@item
+Algumas partes do fonte (a @code{regexp} livraria) está coberta pelo estilo de
+direito autoral Berkeley.
+
+@item
+O outro fonte necessário para o servidor @strong{MySQL} em plataformas não Microsoft
+está coberta pela ``MySQL FREE PUBLIC LICENSE'', a qual é baseada na
+``Aladdin FREE PUBLIC LICENSE.'' @xref{Public license}. Quando o @strong{MySQL}
+está rodando em qualquer sistema operacional Microsoft, outro licenciamento é aplicado.
+@end enumerate
+
+Os seguintes pontos direcionam a filosofia sob nossa política de direito autoral:
+
+@itemize @bullet
+@item
+A livraria cliente SQL deve ser totalmente livre tal que a mesma pode ser incluída
+em produtos comerciais sem nenhuma limitação.
+
+@item
+Pessoas que querem livre acesso ao programa no qual nós temos colocado uma grande
+quantidade de trabalho, podem tê-lo, tal que não procurem ganhar dinheiro diretamente
+pela distribuição e para benefício.
+
+@item
+Pessoas que querem manter o direito da propriedade de seu programa, porém também
+querem o valor de nosso trabalho, podem pagar pelo previlégio.
+
+@item
+O uso normal em casa é de GRAÇA. Mas se você usa o @strong{MySQL} para algo
+importante para você, você pode ajudar o desenvolvimento futuro pela
+compra de uma licença ou contrato de suporte.@xref{Support}.
+@end itemize
+
+@node Copyright changes, , Copyright, Copyright
+@subsection Possible future copyright changes
+
+Nós poderemos optar para distribuir versões antigas do @strong{MySQL}
+com a GPL no futuro. Entretanto, essas versões devem ser identificadas
+como @strong{GNU MySQL}. Também, todas notas de direitos autorais dos
+arquivos relativos devem ser mudados para a GPL.
+
+@node Commercial use, Licensing examples, Copyright, Licensing and Support
+@section Distributing MySQL commercially
+
+Esta seção é um esclarecimento dos termos de licença que são a base na
+``MySQL FREE PUBLIC LICENSE'' (FPL). @xref{Public license}.
+
+O @strong{MySQL} pode ser @strong{usado} livremente , incluindo
+entidades comerciais para avaliação ou uso interno sem suporte.
+Entretanto, @strong{distribuição} para propósitos comerciais
+do @strong{MySQL}, ou qualquer coisa contendo ou derivando do @strong{MySQL}
+no seu todo ou parte, requer uma licença comercial escrita da TcX AB,
+a única entidade autorizada para garantir tais licenças.
+
+Você não pode incluir o @strong{MySQL} ``de graça'' num pacote contendo
+qualquer coisa pela qual um pagamento está sendo feito, exceto como
+notado abaixo:
+
+A intenção da exceção providenciada na segunda claúsula da licença é
+para permitir que organizações comerciais operando um servidor FTP ou
+uma agência de notícias possam distribuir livremente o @strong{MySQL},
+desde que:
+
+@enumerate
+@item
+A organização complace com as outras provisões da FPL, a qual
+incluie entre outras coisas um requerimento para distribuir o
+código fonte inteiro do @strong{MySQL} e qualquer outro trabalho
+derivado, e para distribuir a FPL em si junto com @strong{MySQL};
+
+@item
+A única cobrança para abaixar o @strong{MySQL} é a cobrança baseada
+na distribuição do serviço e não numa baseada no contexto da
+informação sendo recebida (ex: a cobrança deverá ser a mesma para
+o recebimento de uma coleção qualquer de bits do mesmo tamanho);
+
+@item
+O servidor ou BBS é acessível para o público em geral, ex. o número de
+telefone ou enedereço IP não é guardado em secreto, e qualquer um pode
+obter acesso para a informação (possivelmente pagando uma inscrição ou
+acesso cobrado que não é dependente ou relacionado para comprar qualquer
+outra coisa).
+@end enumerate
+
+Se você quer para distribuir programas em um contexto comercial que
+incorpora @strong{MySQL} e você @strong{não} quer encontrar essas
+condições, você deve contatar TcX AB para encontrar um licenciamento
+comercial, o qual envolve um pagamento. O único meio legal que
+você pode distribuir @strong{MySQL} ou qualquer coisa contendo @strong{MySQL}
+são pela distribuição do @strong{MySQL} sob os requerimentos da FPL, ou pela
+obtenção de uma licença comercial da TcX AB.
+
+@node Licensing examples, Cost, Commercial use, Licensing and Support
+@section Example licensing situations
+
+@menu
+* Products that use MySQL:: Vendendo produtos que usam @strong{MySQL}
+* MySQL services:: Vendendo serviços relacionados ao @strong{MySQL}
+* ISP:: Serviços de ISP com @strong{MySQL}
+* Web server:: Rodando um servidor web usando o @strong{MySQL}.
+@end menu
+
+Esta seção descreve algumas situações ilustrando se é o caso ou não que
+você deve licençar o servidor @strong{MySQL}. Geralmente esses exemplos
+envolvem o fornecimento do @strong{MySQL} como parte de um produto ou
+serviço que você está vendendo para um cliente, ou requer que o @strong{MySQL}
+seja usado em conjunto com seu produto. Em tais casos, é sua responsabilidade
+para obter uma licença para o cliente se uma é necessária (Este requerimento
+pode ser deixado de lado se seu cliente já tem uma licença @strong{MySQL}.
+Porém, o vendedor deve enviar informação do cliente e o número da licença
+para TcX, e a licença deverá ser completa, não uma licença OEM).
+
+Note que uma simples licença do @strong{MySQL} cobre qualquer número de
+CPUs/usuários/clientes/servidores @code{mysqld} numa só mâquina!
+
+@node Products that use MySQL, MySQL services, Licensing examples, Licensing examples
+@subsection Selling products that use MySQL
+
+Para determinar caso seja necessário ou não uma licença @strong{MySQL}
+quando vendendo a sua aplicação, você deve perguntar caso seja necessário
+para o funcionamento adequado de sua aplicação a contingência no uso do
+@strong{MySQL} e seja necessário você incluir o @strong{MySQL} com seu
+produto. Existem vários casos a considerar:
+
+@itemize @bullet
+@item
+Sua aplicação precisa do @strong{MySQL} para funcionar adequadamente ?
+
+Se o seu produto precisa do @strong{MySQL}, você necessita uma licença
+para cada mâquina que roda o servidor @code{mysqld}. Por exemplo,
+se você projeta uma aplicação sobre o @strong{MySQL}, então você tem
+feito realmente um produto comercial que necessita do servidor, tal que
+necessita de uma licença.
+
+Se sua aplicação não requer o @strong{MySQL}, você não necessita obter uma
+licença. Por exemplo, se o @strong{MySQL} apenas adiciona uma nova característica
+a seu produto (tal como adicionando loggin a um banco de dados e se o @strong{MySQL}
+é usado no lugar de um arquivo texto), o mesmo entra como um uso normal, e uma
+licença não precisa ser requerida.
+
+Em outras palavras, você necessita de uma licença se você vende um produto
+projetado para uso com o @strong{MySQL} ou que precisa do servidor @strong{MySQL}
+para um funcionamento completo. Isto é verdadeiro caso haja necessidade ou não de fornecer
+o @strong{MySQL} para seu cliente como parte da distribuição de seu produto.
+
+Isso também depende no que você está fazendo para o cliente. Você planeja fornecer
+a seu cliente com instruções e detalhes na instalação do @strong{MySQL} com seu
+programa ?. Então seu produto contencialmente precisa do @strong{MySQL};
+Sim é tal, você necessita comprar uma licença. Se você simplesmente usa um banco de
+dados que espera já estiver instalado no instante en seu programa é comprado, então
+provavelmente não necessita de uma licença.
+
+@item
+Você incluie o @strong{MySQL} numa distribuição e cobra pela mesma ?
+
+Se você incluie @strong{MySQL} com a distribuição que vende para os clientes,
+você necessita uma licença para cada mâquina que roda o servidor @code{mysqld},
+porque neste caso você está vendendo um sistema que incluie @strong{MySQL}.
+
+Isto é verdadeiro no caso que o @strong{MySQL} com seu produto seja requerido
+ou opcional.
+
+@item
+Você não requer nem incluie o @strong{MySQL} com seu produto ?
+
+Suponha que quer vender um produto projetado de uma maneira geral para usar
+com "qualquer banco de dados" e que pode ser configurado para usar qualquer
+uma das várias alternativas de sistemas de banco de dados (@strong{MySQL},
+PostgreSQL, ou qualquer outro. Isto é, seu produto não requer @strong{MySQL},
+mas pode suportar qualquer banco de dados com o nível base de funcionalidade
+e você não depende de qualquer coisa que somente @strong{MySQL} suporta.
+Nenhum de vocês paga para nós se o seu cliente realmente seleciona para
+usar @strong{MySQL}?
+
+Neste caso, se você não fornece, obtêm ou configura o @strong{MySQL} para
+o cliente e decide o cliente para usá-lo, nenhum de vocês precisa de uma
+licença. Se você faz um serviço, vide @ref{MySQL services, ,
+@strong{MySQL} serviços}.
+@end itemize
+
+@node MySQL services, ISP, Products that use MySQL, Licensing examples
+@subsection Selling MySQL-related services
+
+Se você faz uma instalação numa mâquina de um cliente do @strong{MySQL}
+e há cobrança pelo serviço (direta ou indiretamente), então você comprar
+uma licença @strong{MySQL}.
+
+Se você vende uma aplicação para a qual o @strong{MySQL} não é estritamente
+requerido, porém pode ser usado, uma licença deve indicada, dependendo
+como o @strong{MySQL} é configurado. Suponha que seu produto não requera e
+não incluia o @strong{MySQL} na sua distribuição, porém pode ser configurado
+para usar o @strong{MySQL} para os clientes que assim o desejar. (Este pode ser
+o caso, por exemplo, se seu produto pode usar qualquer um de servidores de
+banco de dados).
+
+Se o cliente obtêm e instala o @strong{MySQL}, nenhuma licença é necessária.
+Entretanto, se você faz o serviço para seu cliente, então é necessário uma
+licença, porque você está vendendo um serviço que incluie o @strong{MySQL}.
+
+@node ISP, Web server, MySQL services, Licensing examples
+@subsection ISP MySQL services
+
+Provedores de Serviço Internet (ISPs) às vezes hospedam servidores @strong{MySQL}
+para seus cliente.
+
+Se você é um ISP que permite a seus clientes instalar e administrar o
+@strong{MySQL} por si próprios na sua mâquina sem nenhuma assistência
+de sua parte, nem você nem o cliente precisa de uma licença @strong{MySQL}.
+
+Se você cobra para instalar e administrar o @strong{MySQL} como parte de seu
+serviço para o cliente, então você precisa de uma licença, porque está vendendo
+um serviço que incluie o @strong{MySQL}.
+
+@node Web server, , ISP, Licensing examples
+@subsection Running a web server using MySQL
+
+Se você usa o @strong{MySQL} em conjunto com um servidor web, você não tem
+que pagar uma licença.
+
+Isto é verdadeiro se você roda um servidor web comercial que usa @strong{MySQL},
+desde que você não esteja vendendo o @strong{MySQL}. Entretanto, neste caso
+nós gostariamos que você compre suporte @strong{MySQL}, porque @strong{MySQL}
+está ajudando a sua empresa.
+
+@cindex Costs, licensing and support
+@cindex Licensing costs
+@cindex Support costs
+@node Cost, Support, Licensing examples, Licensing and Support
+@section MySQL licensing and support costs
+
+@menu
+* Payment information:: Informação de Pagamento
+* Contact information:: Informação de contato
+@end menu
+
+Nossos preços atuais de licença são mostrados abaixo. Todos os preços são
+em US Dólar. Se você paga com cartão de crédito, a moeda é o EURO (European Union Euro),
+tais preços diferem levemente.
+
+@multitable @columnfractions .25 .2 .3
+@item @strong{Número de licenças} @tab @strong{Preço por cópia} @tab @strong{Total}
+@item 1 @tab US $200 @tab US $200
+@item 10 pacotes @tab US $150 @tab US $1500
+@item 50 pacotes @tab US $120 @tab US $6000
+@end multitable
+
+Para compras em alto volume (OEM), os seguintes preços são aplicados:
+
+@multitable @columnfractions .25 .2 .3 .25
+@item @strong{Número de licenças} @tab @strong{Preço por cópia} @tab @strong{Mínimo de uma vez} @tab @strong{Pagamento mínimo}
+@item 100-999 @tab US $40 @tab 100 @tab US $4000
+@item 1000-2499 @tab US $25 @tab 200 @tab US $5000
+@item 2500-4999 @tab US $20 @tab 400 @tab US $8000
+@end multitable
+
+Para compras OEM, você deve atuar como o intermediário para eventuais
+problemas ou solicitações de seus usuários. Nós também requeremos que
+clientes OEM tenham ao menos um contrato de suporte extended email.
+
+Se você tem uma margem baixa em alto volume de produtos, você pode falar
+com nós sobre outros termos (por exemplo, a porcentagem dos preços de
+venda). Se você faz, por favor seja informativo sobre seu produto, preço,
+mercado e qualquer outra informação que seja relevante.
+
+@cindex @code{myisampack}
+Depois de comprar 1 licença @strong{MySQL}, você terá uma cópia pessoal
+do utilitário @code{myisampack}. Você não está permitido em distribuir
+esse utilitário porém você pode distribuir tabelas compactadas com ele.
+
+Um preço completo de uma licença não é um acordo de suporte e incluie um
+mínimo suporte. Isto significa que nós tentamos responder qualquer pergunta
+relevante. Se a resposta está na documentação, nós direcionamos você à
+apropriada seção. Se você não tem comprado uma licença ou suporte, nós
+provavelmente não responderemos ao tudo.
+
+Se você descobre o que consideramos um real bug, nós estamos prontificados
+a solucionar o erro em qualquer caso. Porém se você paga por suporte nós
+o notificaremos sobre o andamento da solução ao invés de soluncioná-lo
+nos próximos lançamentos.
+
+Suporte mais amplo é vendido separadamente. Descrições do que incluie cada
+nível de suporte são dadas em @ref{Support}. Custos para os vários tipos
+comerciais de suporte são mostrados abaixo. O nível de preços de suporte
+estão em EURO (European Union Euro). Um EURO é aproximadamente 1.17 USD.
+
+@multitable @columnfractions .3 .3
+@item @strong{Tipo de suporte} @tab @strong{Custo por ano}
+@item Basic email support @tab EURO 170
+@item Extended email support @tab EURO 1000
+@item Login support @tab EURO 2000
+@item Extended login support @tab EURO 5000
+@end multitable
+
+Você pode atualizar um nível mais baixo sw suporte para um de maior
+nível, pela diferença entre os preços dos dois níveis.
+
+@cindex Payment information
+@node Payment information, Contact information, Cost, Cost
+@subsection Payment information
+
+Correntemente nós podemos tomar pagamentos SWIFT, cheques ou cartões de crédito.
+
+O pagamento poderá ser feito a:
+@example
+Postgirot Bank AB
+105 06 STOCKHOLM, SWEDEN
+
+TCX DataKonsult AB
+BOX 6434
+11382 STOCKHOLM, SWEDEN
+
+SWIFT address: PGSI SESS
+Número da Conta: 96 77 06 - 3
+@end example
+
+Especificar: licença e/ou suporte, seu nome e endereço de e-mail.
+
+Em europa e Japão você pode usar EuroGiro (que pode ser menos caro) para a mesma
+conta.
+
+Se você quer pagar através de cheque, faça-o nominal a ``Monty Program KB'' e mande
+um e-mail para o endereço abaixo:
+
+@example
+TCX DataKonsult AB
+BOX 6434, Torsgatan 21
+11382 STOCKHOLM, SWEDEN
+@end example
+
+Se você quer pagar com cartão de crédito usando a Internet, você pode
+usar o seguro formulário de licença da TcX:
+@uref{https://www.mysql.com/license.htmy.
+
+Você pode também imprimir uma cópia do formulário de licença, prenché-lo e mandá-lo
+via fax para:
+
+
++46-8-729 69 05
+
+Se você quer que nós uma cobrança para você, você pode usar o formulário de
+licença e escrever ``bill us'' no campo de comentários. Você pode também
+mandar uma mensagem via e-mail para @email{sales@@mysql.com} (@strong{not}
+@email{mysql@@lists.mysql.com}!) com a informação de sua companhia e pedir
+para nós para efetuar a cobrança.
+
+@cindex Contact information
+@node Contact information, , Payment information, Cost
+@subsection Contact information
+
+Para licenciamento comercial, ou se você têm qualquer pergunta sobre
+informação desta seção, por favor contatar a equipe de licenciamento
+do @strong{MySQL}. O mais preferido método é o e-mail para
+@email{mysql-licensing@@mysql.com}. Fax é também possível porém sua
+manipulação pode demorar muito (Fax +46-8-729 69 05).
+
+@example
+David Axmark
+Detron HB
+Kungsgatan 65 B
+753 21 UPPSALA
+SWEDEN
+Fone Voz +46-18-10 22 80 (Timezone GMT+1. Fala Sueco e Inglés)
+@end example
+
+@cindex Support, types
+@cindex Types of support
+@node Support, , Cost, Licensing and Support
+@section Types of commercial support
+
+@menu
+* Basic email support:: Basic email support
+* Extended email support:: Extended email support
+* Login support:: Login support
+* Extended login support:: Extended login support
+@end menu
+
+@node Basic email support, Extended email support, Support, Support
+@subsection Basic email support
+
+Basic email support é a opção mais barata de suporte e deverá ser vista
+como uma forma de suportar nosso desenvolvimento do @strong{MySQL} que
+uma real opção de suporte.
+
+Neste nível de suporte, a lista de e-mail do @strong{MySQL} é o preferido
+meio de comunicação. Perguntas normalmente podem ser enviadas para a
+principal lista de e-mail (@email{mysql@@lists.mysql.com}) ou uma das outras
+listas regulares (por exemplo, @email{mysql-win32@@lists.mysql.com} relacionada
+às perguntas para o @strong{MySQL} Windows, tal que qualquer pessoa pode já ter
+experimentado e resolvido o problema que você tem. @xref{Asking questions}.
+
+Entretanto, comprando o suporte basic email support, você também tem acesso
+ao e-mail @email{mysql-support@@mysql.com}, o qual não é disponível
+como parte do suporte mínimo que se tem quando se adquire uma licença @strong{MySQL}.
+Isto significa que para perguntas críticas, você pode mandar sua mensagem para
+@email{mysql-support@@mysql.com}. (Se a mensagem tem dados privados, você só
+deve mandar para o @email{mysql-support@@mysql.com}.)
+
+@emph{LEMBRE-SE!} para SEMPRE incluir o número de registro e data de
+término quando mandar uma mensagem para
+@email{mysql-support@@mysql.com}.
+
+Basic email support incluie os seguintes tipos de serviços:
+
+@itemize @bullet
+@item
+Se sua pergunta já está respondida no manual, nós o informamos da correta
+seção na qual pode encontrar a resposta. Se a resposta não está no manual,
+nós o colocamos na direção certa para resolver seu problema.
+
+@item
+Nós garantimos em tempo apropriado a resposta das mensagem de seu e-mail.
+Nós não podemos garantir que podemos resolver qualquer problema, porém ao
+menos você receve uma resposta se podemos contatá-lo por e-mail.
+
+@item
+Nós podemos ajudá-lo com problemas inesperados quando instala @strong{MySQL}
+a partir de uma distribuição binária em plataformas suportadas. Este nível de
+suporte não cobre instalação do @strong{MySQL} a partir de uma distribuição
+fonte. Plataformas ``Suportadas'' são aquelas plataformas nas quais o @strong{MySQL}
+é conhecido que funciona.
+@xref{Which OS}.
+
+@item
+Nós ajudaremos você com bugs e problemas de características. Qualquer
+bug que for encontrado nós o solucionamos no próximo lançamento do @strong{MySQL}.
+Se o bug é crítico para você, nós enviamos um e-mail com o patch
+tão logo como o bug é resolvido. Bugs críticos têm sempre para nós a maior
+prioridade, para assegurar que sejam solucionados tão pronto como possível.
+
+@item
+Suas sugestões para desenvolvimento posterior do @strong{MySQL} são tomadas
+em consideração. Obtendo o email support, você já ajuda o desenvolvimento
+posterior do @strong{MySQL}. Se você quer pôr mais, faça a atualização
+para um nível mais alto de suporte.
+
+@item
+Se você quer nós ajudar a otimizar seu sistema, você deve atualizar
+para um nível maior de suporte.
+
+@item
+@cindex @code{myisampack}
+Nós incluimos uma versão binária da ferramenta de compactação @code{myisampack}
+para criar rápidos bancos de dados compactados, somente de leitura. O atual
+servidor incluie suporte para ler esses bancos de dados mas não a ferramenta
+para criar os mesmos.
+@end itemize
+
+@node Extended email support, Login support, Basic email support, Support
+@subsection Extended email support
+
+Extended email support incluie tudo o do basic email support com estas
+adições:
+
+@itemize @bullet
+@item
+Seu e-mail será tratado antes dos e-amil dos usuários do basic email support
+e dos usuários não registrados.
+
+@item
+Suas sugestões para o próximo desenvolvimento do @strong{MySQL} receberá
+uma forte consideração. Simples extensões que fazem os gols do @strong{MySQL}
+são a implementação em questão de dias. adquirindo o extended email support
+você auxilia daqui para frente o desenvolvimento do @strong{MySQL}.
+
+@item
+Perguntas típicas que são cobertas pelo extended email support são:
+
+@itemize @minus
+@item
+Nós respondemos e (dentro do razoável) resolvemos as perguntas relacionadas
+a possíveis bugs no @strong{MySQL}. Tão pronto como os bugs são encontrados
+e corregidoa, nós mandamos por e-mail o pacth para ele.
+
+@item
+Nós auxiliamos com inesperados problemas quando você instala o @strong{MySQL}
+a partir do fonte ou distribuição binária nas plataformas suportadas.
+
+@item
+Nós responderemos perguntas sobre características perdidad e ofereceremos
+dicas como trabalhar e contornar elas.
+
+@item
+Nós forneceremos dicas na otimização do @code{mysqld}para sua situação.
+@end itemize
+
+@item
+Você está permitido a influenciar a prioridade de itens do TODO do @strong{MySQL}.
+Isso assegura que as características que você realmente precisa sejam implementadas
+rapidamente que as mesmas poderia ser de outra forma.
+@end itemize
+
+@node Login support, Extended login support, Extended email support, Support
+@subsection Login support
+
+O Login support incluie tudo do extended email support com estas adições:
+
+@itemize @bullet
+@item
+Seu e-mail terá prioridade sobre os usuários do suporte extended email.
+
+@item
+Suas sugestões para o próximo desenvolvimento do @strong{MySQL} será tomado
+com uma alta consideração. Extensões reais que podem ser implementadas num
+par de horas e que fazem os gols do @strong{MySQL} serão implementadas
+tão logo como possível.
+
+@item
+Se você tem um problema muito específico, nós tentaremos logar no seu
+sistema para resolver o problema ''no local''.
+
+@item
+Tal como qualquer outro vendedor de banco de dados, não podemos garantir que
+podemos recuperar qualquer dado de tabelas corrompidas, porém se o pior acontece
+nós poderemos a recuperar tanto quanto seja possível. O @strong{MySQL}tem provado
+ser muito seguro, porém qualquer é possível devido a circuntâncias fora de nosso
+controle (por exemplo, se seu sistema crash ou alguém kill o servidor executando
+um comando @code{kill -9}).
+
+@item
+Nós providenciaremos dicas na otimização de seu sistema e consultas.
+
+@item
+Você está permitido para chamar um desenvolvedor @strong{MySQL} (moderadamente) e
+discutir seu problemas relacionados com o @strong{MySQL}.
+@end itemize
+
+@node Extended login support, , Login support, Support
+@subsection Extended login support
+
+O Extended login support incluie tudo do login support com estas adições:
+
+@itemize @bullet
+@item
+Seu e-mail tem a mais alta prioridade possível.
+
+@item
+Nós ativamente examinamos seu sistema e ajudamos a otimizá-lo assim como suas
+consultas. Nós também podemos otimizar e/ou extender o @strong{MySQL}
+para suprir melhor suas necessidades.
+
+@item
+Você também pode solicitar extensões es peciais apenas para você. Por exemplo:
+@example
+mysql> select MY_CALCULATION(col_name1,col_name2) from tbl_name;
+@end example
+
+@item
+Nós podemos fornecer uma distribuição binária para todas as atualizações
+mais importantes do @strong{MySQL} para seu sistema, tão logo como podemos
+obter uma conta em um sistema similar. No pior dos casos, nós podemos requerer
+acesso para seu sistema para ser capaz de criar uma distribuição binária.
+
+@item
+Se você pode providenciar acomodações e pagar os custos de viagem para um
+desenvolvedor @strong{MySQL} para vistá-lo e oferecer ajuda com seus problemas.
+O suporte Extended login support entitula você para um encontro pessoal por
+ano, porém nós sempre somos muito flexíveis para levar para frente nossos
+clientes!.
+@end itemize
+
+@node Installing, Compatibility, Licensing and Support, Top
+
diff --git a/Docs/manual.texi b/Docs/manual.texi
new file mode 100644
index 00000000000..7eebc96a540
--- /dev/null
+++ b/Docs/manual.texi
@@ -0,0 +1,41455 @@
+\input texinfo @c -*-texinfo-*-
+@c Copyright 1997, 1998, 1999, 2000 TcX AB, Detron HB and 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 and SitePages first.
+@c *********************************************************
+@c
+@c %**start of header
+@setfilename mysql.info
+@c We want the types in the same index
+@syncodeindex tp fn
+@c Get version info. 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 colours: 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 @strong{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). @strong{MySQL} documentation.
+END-INFO-DIR-ENTRY
+@end format
+@end ifinfo
+
+@titlepage
+@sp 10
+@center @titlefont{@strong{MySQL} Reference Manual}
+@sp 10
+@center Copyright @copyright{} 1997, 1998, 1999, 2000 TcX AB, Detron HB and MySQL Finland AB
+@end titlepage
+
+@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
+@everyheading @thispage @| @| @thischapter
+@everyfooting @| @| Version: @value{mysql_version} Printed: @today{}
+@end iftex
+
+@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 @strong{MySQL}. This version is about the
+@value{mysql_version} version of @strong{MySQL}. For a @strong{3.20}
+version see the relevant distribution.
+@end ifinfo
+
+@menu
+* Introduction:: General Information about @strong{MySQL}
+* Questions:: @strong{MySQL} mailing lists and how to ask questions or report errors (bugs)
+* Licensing and Support:: @strong{MySQL} licensing and support
+* Installing:: Installing @strong{MySQL}
+* Compatibility:: How standards-compatible is @strong{MySQL}?
+* Privilege system:: The @strong{MySQL} access privilege system
+* Reference:: @strong{MySQL} language reference
+* Table types:: @strong{MySQL} table types
+* Tutorial:: @strong{MySQL} Tutorial
+* Server:: @strong{MySQL} Server
+* Replication:: Replication
+* Performance:: Getting maximum performance from @strong{MySQL}
+* MySQL Benchmarks:: The @strong{MySQL} benchmark suite
+* Tools:: @strong{MySQL} Utilities
+* Maintenance:: Maintaining a @strong{MySQL} installation
+* Adding functions:: Adding new functions to @strong{MySQL}
+* Adding procedures:: Adding new procedures to @strong{MySQL}
+* ODBC:: @strong{MySQL} ODBC Support
+* Common programs:: Using @strong{MySQL} with some common programs
+* Problems:: Problems
+* Common problems:: Solving some common problems with @strong{MySQL}
+* Clients:: @strong{MySQL} client tools and APIs
+* Comparisons:: How does @strong{MySQL} compare with other databases?
+* MySQL internals:: @strong{MySQL} internals
+* Environment variables:: @strong{MySQL} environment variables
+* Users:: Some @strong{MySQL} users
+* Contrib:: Contributed programs
+* Credits:: Contributors to @strong{MySQL}
+* News:: @strong{MySQL} change history
+* Bugs:: Known errors and design deficiencies in @strong{MySQL}
+* TODO:: List of things we want to add to @strong{MySQL} in the future (The TODO)
+* Porting:: Comments on porting to other systems
+* Regexp:: Description of @strong{MySQL} regular expression syntax
+* Unireg:: What is Unireg?
+* GPL license:: GNU General Public License
+* LGPL license:: GNU Library General Public License
+* Function Index:: SQL command, type and function index
+* Concept Index:: Concept Index
+
+@detailmenu --- The Detailed Node Listing ---
+
+General Information about MySQL
+
+* What-is:: What is @strong{MySQL}?
+* Manual-info:: About this manual
+* History:: History of @strong{MySQL}
+* MySQL-Books:: Books about MySQL
+* Features:: The main features of @strong{MySQL}
+* Stability:: How stable is @strong{MySQL}?
+* Year 2000 compliance:: Year 2000 compliance
+* General-SQL:: General SQL information and tutorials
+* Useful Links:: Useful @strong{MySQL}-related links
+
+About this manual
+
+* Manual conventions:: Conventions used in this manual
+
+MySQL mailing lists and how to ask questions or report errors (bugs)
+
+* Mailing-list:: The @strong{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
+
+MySQL licensing and support
+
+* Licensing policy:: @strong{MySQL} licensing policy
+* Copyright:: Copyrights used by @strong{MySQL}
+* Licensing examples:: Example licensing situations
+* Cost:: @strong{MySQL} licensing and support costs
+* Support:: Types of commercial support
+
+Copyrights used by MySQL
+
+* Copyright changes:: Possible future copyright changes
+
+Example licensing situations
+
+* Products that use MySQL:: Selling products that use @strong{MySQL}
+* ISP:: ISP @strong{MySQL} services
+* Web server:: Running a web server using @strong{MySQL}.
+
+@strong{MySQL} licensing and support costs
+
+* Payment information:: Payment information
+* Contact information:: Contact information
+
+Types of commercial support
+
+* Basic email support:: Basic email support
+* Extended email support:: Extended email support
+* Login support:: Login support
+* Extended login support:: Extended login support
+
+Installing MySQL
+
+* Getting MySQL:: How to get @strong{MySQL}
+* Which OS:: Operating systems supported by @strong{MySQL}
+* Which version:: Which @strong{MySQL} version to use
+* Many versions:: How and when updates are released
+* Installation layouts:: Installation layouts
+* Installing binary:: Installing a @strong{MySQL} binary distribution
+* Installing source:: Installing a @strong{MySQL} source distribution
+* Compilation problems:: Problems compiling?
+* MIT-pthreads:: MIT-pthreads notes
+* Perl support:: Perl installation comments
+* Source install system issues:: System-specific issues
+* Win32:: Win32 notes
+* OS/2:: OS/2 notes
+* MySQL binaries::
+* Post-installation:: Post-installation setup and testing
+* Upgrade:: Is there anything special to do when upgrading/downgrading @strong{MySQL}?
+
+Installing a MySQL binary distribution
+
+* Linux-RPM:: Linux RPM files
+* Building clients:: Building client programs
+* Binary install system issues:: System-specific issues
+
+System-specific issues
+
+* Binary notes-Linux:: Linux notes
+* Binary notes-HP-UX:: HP-UX notes
+
+Installing a MySQL source distribution
+
+* Quick install:: Quick installation overview
+* Applying patches:: Applying patches
+* configure options:: Typical @code{configure} options
+
+Perl installation comments
+
+* Perl installation:: Installing Perl on Unix
+* ActiveState Perl:: Installing ActiveState Perl on Win32
+* Win32 Perl:: Installing the @strong{MySQL} Perl distribution on Win32
+* Perl support problems:: Problems using the Perl @code{DBI}/@code{DBD} interface
+
+System-specific issues
+
+* Solaris:: Solaris notes
+* Solaris 2.7:: Solaris 2.7 / 2.8 notes
+* Solaris x86:: Solaris x86 notes
+* SunOS:: SunOS 4 notes
+* Linux:: Linux notes (all Linux versions)
+* Alpha-DEC-Unix:: Alpha-DEC-Unix notes
+* Alpha-DEC-OSF1:: Alpha-DEC-OSF1 notes
+* SGI-Irix:: SGI-Irix notes
+* FreeBSD:: FreeBSD notes
+* NetBSD:: NetBSD notes
+* OpenBSD:: OpenBSD 2.5 notes
+* BSDI:: BSD/OS notes
+* SCO:: SCO notes
+* SCO Unixware:: SCO Unixware 7.0 notes
+* IBM-AIX:: IBM-AIX notes
+* HP-UX 10.20:: HP-UX 10.20 notes
+* HP-UX 11.x:: HP-UX 11.x notes
+* MacOSX:: MacOSX notes
+
+Linux notes (all Linux versions)
+
+* Linux-x86:: Linux-x86 notes
+* Linux-RedHat50:: RedHat 5.0 notes
+* Linux-RedHat51:: RedHat 5.1 notes
+* Linux-SPARC:: Linux-SPARC notes
+* Linux-Alpha:: Linux-Alpha notes
+* MKLinux:: MkLinux notes
+* Qube2:: Qube2 Linux notes
+* Linux-Ia64::
+
+BSD/OS notes
+
+* BSDI2:: BSD/OS 2.x notes
+* BSDI3:: BSD/OS 3.x notes
+* BSDI4:: BSD/OS 4.x notes
+
+Win32 notes
+
+* Win32 installation:: Installing @strong{MySQL} on Win32
+* Win95 start:: Starting @strong{MySQL} on Win95 / Win98
+* NT start:: Starting @strong{MySQL} on NT / Win2000
+* Win32 running:: Running @strong{MySQL} on Win32
+* Win32 and SSH:: Connecting to a remote @strong{MySQL} from Win32 with SSH
+* Win32 symbolic links:: Splitting data across different disks under Win32
+* Win32 compiling::
+* Win32 vs Unix:: @strong{MySQL}-Win32 compared to Unix @strong{MySQL}
+
+Post-installation setup and testing
+
+* mysql_install_db:: Problems running @code{mysql_install_db}
+* Starting server:: Problems starting the @strong{MySQL} server
+* Automatic start:: Starting and stopping @strong{MySQL} automatically
+* Command-line options:: Command-line options
+* Option files:: Option files
+
+Is there anything special to do when upgrading/downgrading MySQL?
+
+* 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
+
+How standards-compatible is MySQL?
+
+* Extensions to ANSI:: @strong{MySQL} extensions to ANSI SQL92
+* Ansi mode:: Runnning @strong{MySQL} in ANSI mode
+* Differences from ANSI:: @strong{MySQL} differences compared to ANSI SQL92
+* Missing functions:: Functionality missing from @strong{MySQL}
+* Standards:: What standards does @strong{MySQL} follow?
+* Commit-rollback:: How to cope without @code{COMMIT}-@code{ROLLBACK}
+
+Functionality missing from MySQL
+
+* Missing Sub-selects:: Sub-selects
+* Missing SELECT INTO TABLE:: @code{SELECT INTO TABLE}
+* Missing Transactions:: Transactions
+* Missing Triggers:: Triggers
+* Missing Foreign Keys:: Foreign Keys
+* Missing Views:: Views
+* Missing comments:: @samp{--} as the start of a comment
+
+Foreign Keys
+
+* Broken Foreign KEY:: Reasons NOT to use foreign keys
+
+The MySQL access privilege system
+
+* General security:: General security
+* Security:: How to make @strong{MySQL} secure against crackers
+* What Privileges:: What the privilege system does
+* User names:: @strong{MySQL} user names and passwords
+* Connecting:: Connecting to the @strong{MySQL} server
+* Password security:: Keeping your password secure
+* Privileges provided:: Privileges provided by @strong{MySQL}
+* Privileges:: How the privilege system works
+* Connection access:: Access control, stage 1: Connection verification
+* Request access:: Access control, stage 2: Request verification
+* Privilege changes:: When privilege changes take effect
+* Default privileges:: Setting up the initial @strong{MySQL} privileges
+* Adding users:: Adding new user privileges to @strong{MySQL}
+* Passwords:: How to set up passwords
+* Access denied:: Causes of @code{Access denied} errors
+
+MySQL language reference
+
+* Literals:: Literals: how to write strings and numbers
+* Variables:: User variables
+* Column types:: Column types
+* Functions:: Functions
+* CREATE DATABASE:: @code{CREATE DATABASE} syntax
+* DROP DATABASE:: @code{DROP DATABASE} syntax
+* CREATE TABLE:: @code{CREATE TABLE} syntax
+* ALTER TABLE:: @code{ALTER TABLE} syntax
+* DROP TABLE:: @code{DROP TABLE} syntax
+* OPTIMIZE TABLE:: @code{OPTIMIZE TABLE} syntax
+* CHECK TABLE:: @code{CHECK TABLE} syntax
+* ANALYZE TABLE::
+* REPAIR TABLE:: @code{REPAIR TABLE} syntax
+* DELETE:: @code{DELETE} syntax
+* SELECT:: @code{SELECT} syntax
+* JOIN:: @code{JOIN} syntax
+* INSERT:: @code{INSERT} syntax
+* REPLACE:: @code{REPLACE} syntax
+* LOAD DATA:: @code{LOAD DATA INFILE} syntax
+* UPDATE:: @code{UPDATE} syntax
+* USE:: @code{USE} syntax
+* FLUSH:: @code{Flush} syntax (clearing caches)
+* KILL:: @code{KILL} syntax
+* SHOW:: @code{SHOW} syntax (Get information about tables, columns, ...)
+* EXPLAIN:: @code{EXPLAIN} syntax (Get information about a @code{SELECT})
+* DESCRIBE:: @code{DESCRIBE} syntax (Get information about names of columns)
+* COMMIT:: @code{BEGIN/COMMIT/ROLLBACK} syntax
+* LOCK TABLES:: @code{LOCK TABLES/UNLOCK TABLES} syntax
+* SET OPTION:: @code{SET OPTION} syntax
+* GRANT:: @code{GRANT} and @code{REVOKE} syntax
+* CREATE INDEX:: @code{CREATE INDEX} syntax
+* DROP INDEX:: @code{DROP INDEX} syntax
+* Comments:: Comment syntax
+* CREATE FUNCTION:: @code{CREATE FUNCTION} syntax
+* Reserved words:: Is @strong{MySQL} picky about reserved words?
+
+Literals: how to write strings and numbers
+
+* String syntax:: Strings
+* Number syntax:: Numbers
+* Hexadecimal values:: Hexadecimal values
+* NULL values:: @code{NULL} values
+* Legal names:: Database, table, index, column and alias names
+
+Database, table, index, column and alias names
+
+* Name case sensitivity:: Case sensitivity in names
+
+Column types
+
+* Storage requirements:: Column type storage requirements
+* Numeric types:: Numeric types
+* Date and time types:: Date and time types
+* String types:: String types
+* Choosing types:: Choosing the right type for a column
+* Indexes:: Column indexes
+* Multiple-column indexes:: Multiple-column indexes
+* Other-vendor column types:: Using column types from other database engines
+
+Date and time types
+
+* Y2K issues:: Y2K issues and date types
+* DATETIME:: The @code{DATETIME}, @code{DATE} and @code{TIMESTAMP} types
+* TIME:: The @code{TIME} type
+* YEAR:: The @code{YEAR} type
+
+String types
+
+* CHAR:: The @code{CHAR} and @code{VARCHAR} types
+* BLOB:: The @code{BLOB} and @code{TEXT} types
+* ENUM:: The @code{ENUM} type
+* SET:: The @code{SET} type
+
+Functions for use in @code{SELECT} and @code{WHERE} clauses
+
+* Grouping functions:: Grouping functions
+* Arithmetic functions:: Normal arithmetic operations
+* Bit functions:: Bit functions
+* Logical functions:: Logical operations
+* Comparison functions:: Comparison operators
+* String comparison functions:: String comparison functions
+* Casts:: Cast operators
+* Control flow functions:: Control flow functions
+* Mathematical functions:: Mathematical functions
+* String functions:: String functions
+* Date and time functions:: Date and time functions
+* Miscellaneous functions:: Miscellaneous functions
+* Group by functions:: Functions for @code{GROUP BY} clause
+
+@code{CREATE TABLE} syntax
+
+* Silent column changes:: Silent column changes
+
+@code{SHOW} syntax (Get information about tables, columns,...)
+
+* SHOW DATABASE INFO::
+* SHOW TABLE STATUS::
+* SHOW STATUS::
+* SHOW VARIABLES::
+* SHOW PROCESSLIST::
+* SHOW GRANTS::
+
+MySQL table types
+
+* MyISAM:: MyISAM tables
+* ISAM:: ISAM tables
+* HEAP:: HEAP tables
+* BDB:: BDB or Berkeley_db tables
+
+MyISAM tables
+
+* Key space:: Space needed for keys
+* MyISAM table formats:: MyISAM table formats
+
+MyISAM table formats
+
+* Static format:: Static (Fixed-length) table characteristics
+* Dynamic format:: Dynamic table characteristics
+* Compressed format:: Compressed table characteristics
+
+MySQL Tutorial
+
+* Connecting-disconnecting:: Connecting to and disconnecting from the server
+* Entering queries:: Entering queries
+* Examples:: Examples
+* Searching on two keys:: Searching on two keys
+* Database use:: Creating and using a database
+* Getting information:: Getting information about databases and tables
+* Batch mode:: Using @code{mysql} in batch mode
+* Twin:: Queries from twin project
+
+Examples of common queries
+
+* example-Maximum-column:: The maximum value for a column
+* example-Maximum-row:: The row holding the maximum of a certain column
+* example-Maximum-column-group:: Maximum of column: per group: only the values
+* example-Maximum-column-group-row:: The rows holding the group-wise maximum of a certain field
+* example-Foreign keys:: Using foreign keys
+
+Creating and using a database
+
+* Creating database:: Creating a database
+* Creating tables:: Creating a table
+* Loading tables:: Loading data into a table
+* Retrieving data:: Retrieving information from a table
+* Multiple tables:: Using more than one table
+
+Retrieving information from a table
+
+* Selecting all:: Selecting all data
+* Selecting rows:: Selecting particular rows
+* Selecting columns:: Selecting particular columns
+* Sorting rows:: Sorting rows
+* Date calculations:: Date calculations
+* Working with NULL:: Working with @code{NULL} values
+* Pattern matching:: Pattern matching
+* Counting rows:: Counting rows
+
+Queries from twin project
+
+* Twin pool:: Find all non-distributed twins
+* Twin event:: Show a table on twin pair status
+
+MySQL server functions
+
+* Languages:: What languages are supported by @strong{MySQL}?
+* Table size:: How big @strong{MySQL} tables can be
+
+What languages are supported by MySQL?
+
+* Character sets:: The character set used for data and sorting
+* Adding character set:: Adding a new character set
+* String collating:: String collating support
+* Multi-byte characters:: Multi-byte character support
+
+Replication in MySQL
+
+* Replication Intro:: Introduction
+* Replication Implementation:: Replication Implementation Overview
+* Replication HOWTO:: HOWTO
+* Replication Features:: Replication Features
+* Replication Options:: Replication Options in my.cnf
+* Replication SQL:: SQL Commands related to replication
+
+Getting maximum performance from MySQL
+
+* Optimize Basics:: Optimization overview
+* System:: System/Compile time and startup parameter tuning
+* Data size:: Get your data as small as possible
+* MySQL indexes:: How @strong{MySQL} uses indexes
+* Query Speed:: Speed of queries that access or update data
+* Tips:: Other optimization tips
+* Benchmarks:: Using your own benchmarks
+* Design:: Design choices
+* Design Limitations:: MySQL design limitations/tradeoffs
+* Portability:: Portability
+* Internal use:: What have we used MySQL for?
+
+System/Compile time and startup parameter tuning
+
+* Compile and link options:: How compiling and linking affects the speed of MySQL
+* Disk issues:: Disk issues
+* Server parameters:: Tuning server parameters
+* Table cache:: How MySQL opens and closes tables
+* Creating many tables:: Drawbacks of creating large numbers of tables in the same database
+* Open tables:: Why so many open tables?
+* Memory use:: How MySQL uses memory
+* Internal locking:: How MySQL locks tables
+* Table locking:: Table locking issues
+
+Disk issues
+
+* Symbolic links:: Using symbolic links for databases and tables
+
+Speed of queries that access or update data
+
+* Estimating performance:: Estimating query performance
+* SELECT speed:: Speed of @code{SELECT} queries
+* Where optimizations:: How MySQL optimizes @code{WHERE} clauses
+* LEFT JOIN optimization:: How MySQL optimizes @code{LEFT JOIN}
+* LIMIT optimization:: How MySQL optimizes @code{LIMIT}
+* Insert speed:: Speed of @code{INSERT} queries
+* Update speed:: Speed of @code{UPDATE} queries
+* Delete speed:: Speed of @code{DELETE} queries
+
+MySQL Utilites
+
+* Programs:: What do the executables do?
+* mysql:: The command line tool
+* mysqladmin:: Administering a @strong{MySQL} server
+* mysqldump:: Dumping the structure and data from @strong{MySQL} databases and tables
+* mysqlimport:: Importing data from text files
+* mysqlshow:: Showing databases, tables and columns
+* myisampack:: The @strong{MySQL} compressed read-only table generator
+
+Maintaining a MySQL installation
+
+* Table maintenance:: Table maintenance and crash recovery
+* Maintenance regimen:: Setting up a table maintenance regimen
+* Table-info:: Getting information about a table
+* Crash recovery:: Using @code{myisamchk} for crash recovery
+* Log files:: Log file maintenance
+
+Using @code{myisamchk} for table maintenance and crash recovery
+
+* myisamchk syntax:: @code{myisamchk} invocation syntax
+* myisamchk memory:: @code{myisamchk} memory usage
+
+@code{myisamchk} invocation syntax
+
+* myisamchk general options::
+* myisamchk check options::
+* myisamchk repair options::
+* myisamchk other options::
+
+Using @code{myisamchk} for crash recovery
+
+* Check:: How to check tables for errors
+* Repair:: How to repair tables
+* Optimization:: Table optimization
+
+Adding new functions to MySQL
+
+* Adding UDF:: Adding a new user-definable function
+* Adding native function:: Adding a new native function
+
+Adding a new user-definable function
+
+* 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
+
+Adding new procedures to MySQL
+
+* procedure analyse:: Procedure analyse
+* Writing a procedure:: Writing a procedure.
+
+MySQL ODBC Support
+
+* Which ODBC OS:: Operating systems supported by @strong{MyODBC}
+* ODBC administrator:: How to fill in the various fields in the ODBC administrator program
+* ODBC Problems:: How to report problems with @strong{MySQL} ODBC
+* MyODBC clients:: Programs known to work with @strong{MyODBC}
+* ODBC and last_insert_id:: How to get the value of an @code{AUTO_INCREMENT} column in ODBC
+* MyODBC bug report:: Reporting problems with MyODBC
+
+Using @code{MySQL} with some common programs
+
+* Apache:: Using @strong{MySQL} with Apache
+
+Problems and common errors
+
+* What is crashing:: How to determinate what is causing problems
+* Crashing:: What to do if @strong{MySQL} keeps crashing
+* Link errors:: Problems when linking with the @strong{MySQL} client library
+* Common errors:: Some common errors when using @strong{MySQL}
+* Full disk:: How @strong{MySQL} handles a full disk
+* Multiple sql commands:: How to run SQL commands from a text file
+* Temporary files:: Where @strong{MySQL} stores temporary files
+* Problems with mysql.sock:: How to protect @file{/tmp/mysql.sock}
+* Error Access denied:: @code{Access denied} error
+* Changing MySQL user :: How to run @strong{MySQL} as a normal user
+* Resetting permissions:: How to reset a forgotten password.
+* File permissions :: Problems with file permissions
+* Not enough file handles:: File not found
+* Using DATE:: Problems using @code{DATE} columns
+* Timezone problems:: Timezone problems
+* Case sensitivity:: Case sensitivity in searches
+* Problems with NULL:: Problems with @code{NULL} values
+* 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
+* ALTER TABLE problems:: Problems with @code{ALTER TABLE}.
+* Change column order:: How to change the order of columns in a table
+
+Some common errors when using MySQL
+
+* Gone away:: @code{MySQL server has gone away} error
+* Can not connect to server:: @code{Can't connect to [local] MySQL server} error
+* Blocked host:: @code{Host '...' is blocked} error
+* Too many connections:: @code{Too many connections} error
+* Out of memory:: @code{Out of memory} error
+* Packet too large:: @code{Packet too large} error
+* Communication errors::
+* Full table:: @code{The table is full} error
+* 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
+
+Solving some common problems with MySQL
+
+* Log Replication:: Database replication with update log
+* Backup:: Database backups
+* Update log:: The update log
+* Multiple servers:: Running multiple @strong{MySQL} servers on the same machine
+
+MySQL client tools and APIs
+
+* C:: @strong{MySQL} C API
+* C API datatypes:: C API datatypes
+* C API function overview:: C API function Overview
+* C API functions:: C API function descriptions
+* Perl:: @strong{MySQL} Perl API
+* Eiffel:: @strong{MySQL} Eiffel wrapper
+* Java:: @strong{MySQL} Java connectivity (JDBC)
+* PHP:: @strong{MySQL} PHP API
+* Cplusplus:: @strong{MySQL} C++ APIs
+* Python:: @strong{MySQL} Python APIs
+* Tcl:: @strong{MySQL} Tcl APIs
+
+C API function descriptions
+
+* 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_create_db:: @code{mysql_create_db()}
+* mysql_data_seek:: @code{mysql_data_seek()}
+* mysql_debug:: @code{mysql_debug()}
+* mysql_drop_db:: @code{mysql_drop_db()}
+* mysql_dump_debug_info:: @code{mysql_dump_debug_info()}
+* mysql_eof:: @code{mysql_eof()}
+* mysql_errno:: @code{mysql_errno()}
+* mysql_error:: @code{mysql_error()}
+* mysql_escape_string:: @code{mysql_escape_string()}
+* mysql_fetch_field:: @code{mysql_fetch_field()}
+* mysql_fetch_fields:: @code{mysql_fetch_fields()}
+* mysql_fetch_field_direct:: @code{mysql_fetch_field_direct()}
+* mysql_fetch_lengths:: @code{mysql_fetch_lengths()}
+* mysql_fetch_row:: @code{mysql_fetch_row()}
+* mysql_field_count:: @code{mysql_field_count()}
+* mysql_field_seek:: @code{mysql_field_seek()}
+* mysql_field_tell:: @code{mysql_field_tell()}
+* mysql_free_result:: @code{mysql_free_result()}
+* mysql_get_client_info:: @code{mysql_get_client_info()}
+* mysql_get_host_info:: @code{mysql_get_host_info()}
+* mysql_get_proto_info:: @code{mysql_get_proto_info()}
+* mysql_get_server_info:: @code{mysql_get_server_info()}
+* mysql_info:: @code{mysql_info()}
+* mysql_init:: @code{mysql_init()}
+* mysql_insert_id:: @code{mysql_insert_id()}
+* mysql_kill:: @code{mysql_kill()}
+* mysql_list_dbs:: @code{mysql_list_dbs()}
+* mysql_list_fields:: @code{mysql_list_fields()}
+* mysql_list_processes:: @code{mysql_list_processes()}
+* mysql_list_tables:: @code{mysql_list_tables()}
+* mysql_num_fields:: @code{mysql_num_fields()}
+* mysql_num_rows:: @code{mysql_num_rows()}
+* mysql_options:: @code{mysql_options()}
+* mysql_ping:: @code{mysql_ping()}
+* mysql_query:: @code{mysql_query()}
+* mysql_real_connect:: @code{mysql_real_connect()}
+* mysql_real_escape_string:: @code{mysql_real_escape_string()}
+* mysql_real_query:: @code{mysql_real_query()}
+* mysql_reload:: @code{mysql_reload()}
+* mysql_row_seek:: @code{mysql_row_seek()}
+* mysql_row_tell:: @code{mysql_row_tell()}
+* mysql_select_db:: @code{mysql_select_db()}
+* mysql_shutdown:: @code{mysql_shutdown()}
+* mysql_stat:: @code{mysql_stat()}
+* mysql_store_result:: @code{mysql_store_result()}
+* mysql_thread_id:: @code{mysql_thread_id()}
+* mysql_use_result:: @code{mysql_use_result()}
+* 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
+* Thread-safe clients:: How to make a thread-safe client
+
+MySQL Perl API
+
+* DBI with DBD:: @code{DBI} with @code{DBD::mysql}
+* Perl DBI Class:: The @code{DBI} interface
+* DBI-info:: More @code{DBI}/@code{DBD} information
+
+MySQL PHP API
+
+* PHP problems:: Common problems with MySQL and PHP
+
+How MySQL compares to other databases
+
+* Compare mSQL:: How @strong{MySQL} compares to @code{mSQL}
+* Compare PostgreSQL:: How @strong{MySQL} compares with PostgreSQL
+
+How MySQL compares to @code{mSQL}
+
+* Using mSQL tools:: How to convert @code{mSQL} tools for @strong{MySQL}
+* Protocol differences:: How @code{mSQL} and @strong{MySQL} client/server communications protocols differ
+* Syntax differences:: How @code{mSQL} 2.0 SQL syntax differs from @strong{MySQL}
+
+MySQL internals
+
+* MySQL threads:: MySQL threads
+
+MySQL change history
+
+* News-3.23.x:: Changes in release 3.23.x (Released as alpha)
+* News-3.22.x:: Changes in release 3.22.x (Recommended version)
+* News-3.21.x:: Changes in release 3.21.x
+* News-3.20.x:: Changes in release 3.20.x
+* News-3.19.x:: Changes in release 3.19.x
+
+Changes in release 3.23.x (Released as alpha)
+
+* News-3.23.22:: Changes in release 3.23.22
+* News-3.23.21:: Changes in release 3.23.21
+* News-3.23.20:: Changes in release 3.23.20
+* News-3.23.19:: Changes in release 3.23.19
+* News-3.23.18:: Changes in release 3.23.18
+* News-3.23.17:: Changes in release 3.23.17
+* News-3.23.16:: Changes in release 3.23.16
+* News-3.23.15:: Changes in release 3.23.15
+* News-3.23.14:: Changes in release 3.23.14
+* News-3.23.13:: Changes in release 3.23.13
+* News-3.23.12:: Changes in release 3.23.12
+* News-3.23.11:: Changes in release 3.23.11
+* News-3.23.10:: Changes in release 3.23.10
+* News-3.23.9:: Changes in release 3.23.9
+* News-3.23.8:: Changes in release 3.23.8
+* News-3.23.7:: Changes in release 3.23.7
+* News-3.23.6:: Changes in release 3.23.6
+* News-3.23.5:: Changes in release 3.23.5
+* News-3.23.4:: Changes in release 3.23.4
+* News-3.23.3:: Changes in release 3.23.3
+* News-3.23.2:: Changes in release 3.23.2
+* News-3.23.1:: Changes in release 3.23.1
+* News-3.23.0:: Changes in release 3.23.0
+
+Changes in release 3.22.x
+
+* News-3.22.35:: Changes in release 3.22.35
+* News-3.22.34:: Changes in release 3.22.34
+* News-3.22.33:: Changes in release 3.22.33
+* News-3.22.32:: Changes in release 3.22.32
+* News-3.22.31:: Changes in release 3.22.31
+* News-3.22.30:: Changes in release 3.22.30
+* News-3.22.29:: Changes in release 3.22.29
+* News-3.22.28:: Changes in release 3.22.28
+* News-3.22.27:: Changes in release 3.22.27
+* News-3.22.26:: Changes in release 3.22.26
+* News-3.22.25:: Changes in release 3.22.25
+* News-3.22.24:: Changes in release 3.22.24
+* News-3.22.23:: Changes in release 3.22.23
+* News-3.22.22:: Changes in release 3.22.22
+* News-3.22.21:: Changes in release 3.22.21
+* News-3.22.20:: Changes in release 3.22.20
+* News-3.22.19:: Changes in release 3.22.19
+* News-3.22.18:: Changes in release 3.22.18
+* News-3.22.17:: Changes in release 3.22.17
+* News-3.22.16:: Changes in release 3.22.16
+* News-3.22.15:: Changes in release 3.22.15
+* News-3.22.14:: Changes in release 3.22.14
+* News-3.22.13:: Changes in release 3.22.13
+* News-3.22.12:: Changes in release 3.22.12
+* News-3.22.11:: Changes in release 3.22.11
+* News-3.22.10:: Changes in release 3.22.10
+* News-3.22.9:: Changes in release 3.22.9
+* News-3.22.8:: Changes in release 3.22.8
+* News-3.22.7:: Changes in release 3.22.7
+* News-3.22.6:: Changes in release 3.22.6
+* News-3.22.5:: Changes in release 3.22.5
+* News-3.22.4:: Changes in release 3.22.4
+* News-3.22.3:: Changes in release 3.22.3
+* News-3.22.2:: Changes in release 3.22.2
+* News-3.22.1:: Changes in release 3.22.1
+* News-3.22.0:: Changes in release 3.22.0
+
+Changes in release 3.21.x
+
+* News-3.21.33:: Changes in release 3.21.33
+* News-3.21.32:: Changes in release 3.21.32
+* News-3.21.31:: Changes in release 3.21.31
+* News-3.21.30:: Changes in release 3.21.30
+* News-3.21.29:: Changes in release 3.21.29
+* News-3.21.28:: Changes in release 3.21.28
+* News-3.21.27:: Changes in release 3.21.27
+* News-3.21.26:: Changes in release 3.21.26
+* News-3.21.25:: Changes in release 3.21.25
+* News-3.21.24:: Changes in release 3.21.24
+* News-3.21.23:: Changes in release 3.21.23
+* News-3.21.22:: Changes in release 3.21.22
+* News-3.21.21a:: Changes in release 3.21.21a
+* News-3.21.21:: Changes in release 3.21.21
+* News-3.21.20:: Changes in release 3.21.20
+* News-3.21.19:: Changes in release 3.21.19
+* News-3.21.18:: Changes in release 3.21.18
+* News-3.21.17:: Changes in release 3.21.17
+* News-3.21.16:: Changes in release 3.21.16
+* News-3.21.15:: Changes in release 3.21.15
+* News-3.21.14b:: Changes in release 3.21.14b
+* News-3.21.14a:: Changes in release 3.21.14a
+* News-3.21.13:: Changes in release 3.21.13
+* News-3.21.12:: Changes in release 3.21.12
+* News-3.21.11:: Changes in release 3.21.11
+* News-3.21.10:: Changes in release 3.21.10
+* News-3.21.9:: Changes in release 3.21.9
+* News-3.21.8:: Changes in release 3.21.8
+* News-3.21.7:: Changes in release 3.21.7
+* News-3.21.6:: Changes in release 3.21.6
+* News-3.21.5:: Changes in release 3.21.5
+* News-3.21.4:: Changes in release 3.21.4
+* News-3.21.3:: Changes in release 3.21.3
+* News-3.21.2:: Changes in release 3.21.2
+* News-3.21.0:: Changes in release 3.21.0
+
+Changes in release 3.20.x
+
+* News-3.20.18:: Changes in release 3.20.18
+* News-3.20.17:: Changes in release 3.20.17
+* News-3.20.16:: Changes in release 3.20.16
+* News-3.20.15:: Changes in release 3.20.15
+* News-3.20.14:: Changes in release 3.20.14
+* News-3.20.13:: Changes in release 3.20.13
+* News-3.20.11:: Changes in release 3.20.11
+* News-3.20.10:: Changes in release 3.20.10
+* News-3.20.9:: Changes in release 3.20.9
+* News-3.20.8:: Changes in release 3.20.8
+* News-3.20.7:: Changes in release 3.20.7
+* News-3.20.6:: Changes in release 3.20.6
+* News-3.20.3:: Changes in release 3.20.3
+* News-3.20.0:: Changes in releases 3.20.0
+
+Changes in release 3.19.x
+
+* News-3.19.5:: Changes in release 3.19.5
+* News-3.19.4:: Changes in release 3.19.4
+* News-3.19.3:: Changes in release 3.19.3
+
+List of things we want to add to MySQL in the future (The TODO)
+
+* TODO future:: Things that must done in the very near future
+* TODO sometime:: Things that have to be done sometime
+* TODO unplanned:: Some things we don't have any plans to do
+
+Comments on porting to other systems
+
+* Debugging server:: Debugging a @strong{MySQL} server
+* Debugging client:: Debugging a @strong{MySQL} client
+* The DBUG package:: The DBUG package
+* Locking methods::
+* RTS-threads:: Comments about RTS threads
+* Thread packages:: Differences between different thread packages
+
+@end detailmenu
+@end menu
+
+@cindex Overview
+@cindex General Information
+@node Introduction, Questions, Top, Top
+@chapter General Information about MySQL
+
+@menu
+* What-is:: What is @strong{MySQL}?
+* Manual-info:: About this manual
+* History:: History of @strong{MySQL}
+* MySQL-Books:: Books about MySQL
+* Features:: The main features of @strong{MySQL}
+* Stability:: How stable is @strong{MySQL}?
+* Year 2000 compliance:: Year 2000 compliance
+* General-SQL:: General SQL information and tutorials
+* Useful Links:: Useful @strong{MySQL}-related links
+@end menu
+
+This is the @strong{MySQL} reference manual; it documents @strong{MySQL}
+version @value{mysql_version}. As @strong{MySQL} is work in progress,
+the manual gets updated frequently. So there is a very good chance that
+this version is out of date, unless you are looking at it on-line. 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 the information in the manual, you can try its
+searchable PHP version at @uref{http://www.mysql.com/documentation/manual.php} .
+
+@strong{MySQL} is a very fast, multi-threaded, multi-user and robust SQL
+(Structured Query Language) database server.
+
+@strong{MySQL} is free software. It is licensed with the @strong{GNU
+GENERAL PUBLIC LICENSE} @uref{http://www.gnu.org/}. @xref{Licensing and
+Support}.
+
+@uref{http://www.mysql.com/, The @strong{MySQL} home page}
+provides the latest information about @strong{MySQL}.
+
+The following list describes some useful sections of the manual:
+
+@itemize @bullet
+@item
+For a discussion of @strong{MySQL}'s capabilities, see @ref{Features}.
+
+@item
+For installation instructions, see @ref{Installing}. For tips on porting
+@strong{MySQL} to new machines or operating systems, see @ref{Porting}.
+
+@item
+For information about upgrading from a 3.21 release, see
+@ref{Upgrading-from-3.21}.
+
+@item
+For a tutorial introduction to @strong{MySQL}, see
+@ref{Tutorial}.
+
+@item
+For examples of 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}.
+
+@item
+For a list of currently known bugs and misfeatures, see @ref{Bugs}.
+
+@item
+For future plans, see @ref{TODO}.
+
+@item
+For a list of all the contributors to this project, see @ref{Credits}.
+@end itemize
+
+@strong{IMPORTANT:}
+
+@c if the @email is at the beginning of a line the texi2html fails
+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}.
+@xref{Bug reports}.
+The @code{mysqlbug} script should be used to generate bug reports.
+@c FIX! RPMs are also binary
+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.
+
+@c FIX! Remeber to create the alias!
+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
+@strong{MySQL}, see @ref{MySQL-Books}.
+
+@cindex @strong{MySQL}, what it is
+@node What-is, Manual-info, Introduction, Introduction
+@section What is MySQL
+
+@table @asis
+
+@item @strong{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 @strong{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.
+
+@item @strong{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 @strong{MySQL}
+stands for "Structured Query Language" - the most common standardized
+language used to access databases.
+
+@item @strong{MySQL} is Open Source Software
+
+Open source means that it is possible to use and modify for
+anyone. Anybody can download @strong{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. @strong{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 @strong{MySQL} into a
+commercial application you can buy a commercially licensed version from
+us.
+
+@item Why use @strong{MySQL}?
+
+@strong{MySQL} is very fast, reliable and easy to use. If that is what
+You are looking for you should give it a try. @strong{MySQL} also has a
+very practical set of features developed in very close cooperation with
+our users. You can find a performance comparison of @strong{MySQL}
+to some other database managers on our benchmark page. @xref{Benchmarks}.
+
+@strong{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, @strong{MySQL} today offers a rich and very
+useful set of functions. The connectivity, speed and security makes
+@strong{MySQL} highly suited for accessing databases on the Internet.
+
+@item The technical features of @strong{MySQL}
+
+For advanced technical information, @ref{Reference}. @strong{MySQL} is
+a client/server system that consists of an multi-threaded SQL server
+that supports different backends, several different client programs and
+libraries, administrative tools and a programming interface.
+
+@item @strong{MySQL} has a lot of contributed software available.
+
+This makes it much more likely that you will find that your favorite
+application/language already supports @strong{MySQL}.
+
+@end table
+
+@cindex How to pronounce @strong{MySQL}
+@cindex @strong{MySQL}, how to pronounce
+The official way to pronounce @strong{MySQL} is ``My Ess Que Ell'' (not
+MY-SEQUEL). But we try to avoid correcting people who say MY-SEQUEL
+
+@strong{MySQL} core values
+
+We want @strong{MySQL} to be
+
+@itemize @bullet
+@item
+The best and the most used database in the world
+@item
+Available to all and affordable for all
+@item
+Easy to use
+@item
+Continuously improved while remaining fast and safe
+@item
+Fun to use and fun to improve
+@item
+Free from bugs
+@end itemize
+
+@strong{MySQL AB} and the people of @strong{MySQL AB}
+
+@itemize @bullet
+@item
+Promote Open Source Philosophy and support the Open Source Community
+@item
+Aims to be good citizens
+@item
+Prefer partners that share our values and mind-set
+@item
+Answer mail and give support
+@item
+Is a virtual company networking with others
+@item
+Work against software patents
+@end itemize
+
+@cindex Manual information
+@node Manual-info, History, What-is, Introduction
+@section About this manual
+
+@menu
+* Manual conventions:: Conventions used in this manual
+@end menu
+
+This manual is currently available in Texinfo, plain text, Info, HTML,
+PostScript and PDF versions. Because of their size, PostScript and PDF
+versions are not included with the main @strong{MySQL} distribution, but
+are available for separate download at
+@uref{http://www.mysql.com/}.
+
+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}.
+
+This manual is written and maintained by David Axmark, Michael (Monty)
+Widenius and Paul DuBois. For other contributors, see @ref{Credits}.
+
+@node Manual conventions, , Manual-info, Manual-info
+@subsection Conventions used in this manual
+
+This manual uses certain typographical conventions:
+
+@table @asis
+@item @code{constant}
+Constant-width font is used for command names and options; SQL statements;
+database, table and column names; C and Perl code; and environment variables.
+Example: ``To see how @code{mysqladmin} works, invoke it with the
+@code{--help} option.''
+
+@item @file{filename}
+Constant-width font with surrounding quotes is used for filenames and
+pathnames. Example: ``The distribution is installed under the
+@file{/usr/local/} directory.''
+
+@item @samp{c}
+Constant-width font with surrounding quotes is also used to indicate
+character sequences. Example: ``To specify a wildcard, use the @samp{%}
+character.''
+
+@item @emph{italic}
+Italic font is used for emphasis, @emph{like this}.
+
+@item @strong{boldface}
+Boldface font is used for access privilege names (e.g., ``do not grant the
+@strong{process} privilege lightly'') and occasionally to convey
+@strong{especially strong emphasis}.
+@end table
+
+When commands are shown that are meant to be executed by a particular
+program, the program is indicated by the prompt shown with the command. For
+example, @code{shell>} indicates a command that you execute from your login
+shell, and @code{mysql>} indicates a command that you execute from the
+@code{mysql} client program:
+
+@example
+shell> type a shell command here
+mysql> type a mysql command here
+@end example
+
+Shell commands are shown using Bourne shell syntax. If you are using a
+@code{csh}-style shell, you may need to issue commands slightly differently.
+For example, the sequence to set an environment variable and run a command
+looks like this in Bourne shell syntax:
+
+@example
+shell> VARNAME=value some_command
+@end example
+
+For @code{csh}, you would execute the sequence like this:
+
+@example
+shell> setenv VARNAME value
+shell> some_command
+@end example
+
+Database, table and column names often 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:
+
+@example
+mysql> SELECT col_name FROM db_name.tbl_name;
+@end example
+
+This means that if you were to enter a similar statement, you would supply
+your own database, table and column names, perhaps like this:
+
+@example
+mysql> SELECT author_name FROM biblio_db.author_list;
+@end example
+
+SQL statements may be written in uppercase or lowercase. When this manual
+shows a SQL statement, uppercase is used for particular keywords if those
+keywords are under discussion (to emphasize them) and lowercase is used for
+the rest of the statement. For example, you might see the following in a
+discussion of the @code{SELECT} statement:
+
+@example
+mysql> SELECT count(*) FROM tbl_name;
+@end example
+
+On the other hand, in a discussion of the @code{COUNT()} function, the
+same statement would be written like this:
+
+@example
+mysql> select COUNT(*) from tbl_name;
+@end example
+
+If no particular emphasis is intended, all keywords are written uniformly
+in uppercase.
+
+In syntax descriptions, square brackets (@samp{[} and @samp{]}) are used
+to indicate optional words or clauses:
+
+@example
+DROP TABLE [IF EXISTS] tbl_name
+@end example
+
+When a syntax element consists of a number of alternatives, the alternatives
+are separated by vertical bars (@samp{|}). When one member from a set of
+choices may be chosen, the alternatives are listed within square brackets
+(@samp{[} and @samp{]}):
+
+@example
+TRIM([[BOTH | LEADING | TRAILING] [remstr] FROM] str)
+@end example
+
+When one member from a set of choices must be chosen, the alternatives are
+listed within braces (@samp{@{} and @samp{@}}):
+
+@example
+@{DESCRIBE | DESC@} tbl_name @{col_name | wild@}
+@end example
+
+@cindex @strong{MySQL} version
+@node History, MySQL-Books, Manual-info, Introduction
+@section History of MySQL
+
+We once started out with the intention of using @code{mSQL} to connect to our
+tables using our own fast low-level (ISAM) routines. However, after some
+testing we came to the conclusion that @code{mSQL} was not fast enough or
+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 @strong{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. So which of the two gave its name to @strong{MySQL} is
+still a mystery, even for us.
+
+@node MySQL-Books, Features, History, Introduction
+@section Books about MySQL
+
+While this manual is still the right place for up to date techical
+information, its primary goal is to contain everything there is to know
+about @strong{MySQL}. And it is sometimes nice to have a bound book to read
+in bed or while you travel. Here is a list of books about @strong{MySQL} (in
+English).
+
+@multitable @columnfractions .3 .7
+@item Title @tab @uref{http://www2.newriders.com/cfm/prod_book.cfm?RecordID=584,MySQL}
+@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.mysql.com/Contrib/Examples/samp_db.tar.gz, @code{samp_db.tar.gz}}
+@item Errata @tab @uref{http://www.mysql.com/documentation/pauls-mysql-book-errata.html, are available here}
+@end multitable
+Foreword by Michael ``Monty'' Widenius, @strong{MySQL} Moderator
+
+In @strong{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 @strong{MySQL}, and is an
+active member of the @strong{MySQL} community. The principal @strong{MySQL}
+developer, Monty Widenius, and a network of his fellow developers
+reviewed the manuscript, providing Paul with the kind of insight
+no one else could supply.
+
+Instead of merely giving you a general overview of @strong{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 @strong{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
+@strong{MySQL} databases, and also provides a comprehensive set of
+references to column types, operators, functions, SQL syntax,
+@strong{MySQL} programming, C API, Perl @code{DBI}, and PHP API.
+@strong{MySQL} simply gives you the kind of information you won't find
+anywhere else.
+
+If you use @strong{MySQL}, this book provides you with:
+@itemize @bullet
+@item
+An introduction to @strong{MySQL} and SQL
+@item
+Coverage of @strong{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 @strong{MySQL} access
+@item
+A comprehensive reference for @strong{MySQL}'s data types, operators,
+functions, and SQL statements and utilities
+@item
+Complete reference guides for @strong{MySQL}'s C API, the Perl @code{DBI} API,
+and PHP's @strong{MySQL}-related functions
+@end itemize
+
+@multitable @columnfractions .3 .7
+@item Title @tab @uref{http://www.oreilly.com/catalog/msql/noframes.html,MySQL & mSQL}
+@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 @strong{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 ample tutorial
+material.
+
+@multitable @columnfractions .3 .7
+@item Title @tab @uref{http://shop.barnesandnoble.com/bookSearch/isbnInquiry.asp?isbn=0672319144,Sams Teach Yourself MySQL in 21 Days}
+@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 N/A
+@item Price @tab $39.99
+@end multitable
+
+Sams Teach Yourself @strong{MySQL} in 21 Days is for intermediate Linux users
+who want to move into databases. A large share of the audience to be web
+developers needing a database to store large amounts of information that can
+be retrieved via the Web. Sams Teach Yourself @strong{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/her web site using practical,
+hands-on examples to follow.
+
+@multitable @columnfractions .3 .7
+@item Title @tab @uref{http://shop.barnesandnoble.com/bookSearch/isbnInquiry.asp?isbn=0761524452,E-Commerce Solutions with MySQL}
+@item Publisher @tab Prima
+@item Authors @tab N/A
+@item Pub Date @tab September 2000
+@item ISBN @tab 0761524452
+@item Pages @tab 500
+@item Price @tab $39.99
+@end multitable
+
+No description available.
+
+@multitable @columnfractions .3 .7
+@item Title @tab @uref{http://shop.barnesandnoble.com/bookSearch/isbnInquiry.asp?isbn=1861004281,Professional MySQL Programming}
+@item Publisher @tab Wrox
+@item Authors @tab N/A
+@item Pub Date @tab July 2000
+@item ISBN @tab 1861004281
+@item Pages @tab 1000
+@item Price @tab $49.99
+@end multitable
+
+No description available.
+
+@multitable @columnfractions .3 .7
+@item Title @tab @uref{http://shop.barnesandnoble.com/bookSearch/isbnInquiry.asp?isbn=0672317842,PHP3 and MySQL Web Development}
+@item Publisher @tab N/A
+@item Authors @tab William Jason Gilmore
+@item Pub Date @tab October 2000
+@item ISBN @tab 672317842
+@item Pages @tab N/A
+@item Price @tab $39.99
+@end multitable
+
+No description available.
+
+@node Features, Stability, MySQL-Books, Introduction
+@section The main features of MySQL
+
+The following list describes some of the important characteristics
+of @strong{MySQL}:
+
+@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.
+@itemize @bullet
+@item
+Fully multi-threaded using kernel threads. That means it easily can
+use multiple CPUs if available.
+
+@item
+C, C++, Eiffel, Java, Perl, PHP, Python and Tcl APIs. @xref{Clients}.
+
+@item
+Works on many different platforms. @xref{Which OS}.
+
+@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. @xref{Column
+types}.
+
+@item
+Very fast joins using an optimized one-sweep multi-join.
+
+@item
+Full operator and function support in the @code{SELECT} and @code{WHERE}
+parts of queries. Example:
+@example
+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 they can get! Usually there shouldn't be 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)}, @code{AVG()}, @code{STD()}, @code{SUM()},
+@code{MAX()} and @code{MIN()}).
+
+@item
+Support for @code{LEFT OUTER JOIN} with ANSI SQL and ODBC syntax.
+
+@item
+You can mix tables from different databases in the same query (as of
+version 3.22).
+
+@item
+A privilege and password system which is very flexible and secure, and
+which allows host-based verification. Passwords are secure because all
+password traffic when connecting to a server is encrypted.
+
+@item
+ODBC (Open-DataBase-Connectivity) support for Windows95 (with source). All
+ODBC 2.5 functions and many others. For example, you can use Access to
+connect to your @strong{MySQL} server. @xref{ODBC}.
+
+@item
+Very fast B-tree disk tables with index compression.
+
+@item
+16 indexes per table are allowed. Each index may consist of 1 to 16 columns
+or parts of columns. The maximum index length is 256 bytes (this may be
+changed when compiling @strong{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 @strong{MySQL} with some
+databases that contain 50,000,000 records.
+
+@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 @code{libtool} for portability.
+
+@item
+Written in C and C++. Tested with a broad range of different compilers.
+
+@item
+A very fast thread-based memory allocation system.
+
+@item
+No memory leaks. Tested with a commercial memory leakage detector
+(@code{purify}).
+
+@item
+Includes @code{myisamchk}, a very fast utility for table checking, optimization
+and repair.
+@xref{Maintenance}.
+
+@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.
+
+@item
+All data are 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 @strong{MySQL} server
+is started up. To see an example of very advanced sorting, look at the
+Czech sorting code. @strong{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
+how many rows were changed (affected). It is possible to return the number
+of rows matched instead by setting a flag when connecting to the server.
+
+@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
+All @strong{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 @strong{MySQL} server using TCP/IP connections or
+Unix sockets, or named pipes under NT.
+
+@item
+The @strong{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
+
+@cindex Stability
+@node Stability, Year 2000 compliance, Features, Introduction
+@section How stable is MySQL?
+
+This section addresses the questions, ``How stable is
+@strong{MySQL}?'' and, ``Can I depend on @strong{MySQL} in this project?''
+Here 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, @strong{MySQL} has worked without any problems in our projects since
+mid-1996. When @strong{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), and we hope that it will be possible to label
+one of the next releases ``stable''.
+
+Each release of @strong{MySQL} has been usable and there have been problems
+only when users start to use code from ``the gray zones''. Naturally, outside
+users can't know what the gray zones are; this section attempts to indicate
+those that are currently known. The descriptions deal with the 3.22.x
+version of @strong{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}.
+
+@strong{MySQL} is written in multiple layers and different independent
+modules. These modules are listed below with an indication of how
+well-tested each of them is:
+
+@table @strong
+@item The ISAM table handler --- Stable
+This manages storage and retrieval of all data in @strong{MySQL} 3.22
+and earlier versions. In all @strong{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 @strong{MySQL}, either.
+
+@item The MyISAM table handler --- Beta
+This is new in @strong{MySQL} 3.23. It's largely based on the ISAM table code
+but has a lot of new 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 3.20 releases, there were some limitations in
+the send/receive buffer size. As of 3.21.x, the buffer size is now dynamic up
+to a default of 24M.
+
+@item Standard client programs --- Stable
+These include @code{mysql}, @code{mysqladmin} and @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 --- Gamma
+
+@item Join optimizer --- Stable
+
+@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
+@strong{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 --- Gamma
+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 the 0.5
+release. 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. See Linux Notes for more details.
+
+@item Solaris 2.5+ pthreads --- Stable
+We use this for all our production work.
+
+@item MIT-pthreads (Other systems) --- Gamma
+There have been no reported bugs since 3.20.15 and no known bugs since
+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 --- Alpha - Beta
+The ports to other systems are still very new and may have bugs, possibly
+in @strong{MySQL}, but most often in the thread implementation itself.
+
+@item @code{LOAD DATA ...}, @code{INSERT ... SELECT} --- Stable
+Some people have thought they have 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 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} --- Gamma
+Big changes made in @strong{MySQL} 3.22.12.
+
+@item @strong{MyODBC} (uses ODBC SDK 2.5) --- Gamma
+It seems to work well with some programs.
+@end table
+
+MySQL AB provides email support for paying customers, but the @strong{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.
+
+@cindex Year 2000 compliance
+@node Year 2000 compliance, General-SQL, Stability, Introduction
+@section Year 2000 compliance
+
+@strong{MySQL} itself has no problems with Year 2000 (Y2K) compliance:
+
+@itemize @bullet
+@item
+@strong{MySQL} 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, @strong{MySQL} treats it as @code{2001}.
+
+@item
+All @strong{MySQL} date
+functions are stored in one file @file{sql/time.cc} and coded very carefully
+to be year 2000-safe.
+
+@item
+In @strong{MySQL} 3.22 and later versions, 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 @strong{MySQL} 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.
+
+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 @strong{MySQL} doesn't have
+any problems with dates until the year 2030!
+
+@example
+mysql> DROP TABLE IF EXISTS y2k;
+mysql> CREATE TABLE y2k (date date, date_time datetime, time_stamp timestamp);
+mysql> INSERT INTO y2k VALUES ("1998-12-31","1998-12-31 23:59:59",19981231235959);
+mysql> INSERT INTO y2k VALUES ("1999-01-01","1999-01-01 00:00:00",19990101000000);
+mysql> INSERT INTO y2k VALUES ("1999-09-09","1999-09-09 23:59:59",19990909235959);
+mysql> INSERT INTO y2k VALUES ("2000-01-01","2000-01-01 00:00:00",20000101000000);
+mysql> INSERT INTO y2k VALUES ("2000-02-28","2000-02-28 00:00:00",20000228000000);
+mysql> INSERT INTO y2k VALUES ("2000-02-29","2000-02-29 00:00:00",20000229000000);
+mysql> INSERT INTO y2k VALUES ("2000-03-01","2000-03-01 00:00:00",20000301000000);
+mysql> INSERT INTO y2k VALUES ("2000-12-31","2000-12-31 23:59:59",20001231235959);
+mysql> INSERT INTO y2k VALUES ("2001-01-01","2001-01-01 00:00:00",20010101000000);
+mysql> INSERT INTO y2k VALUES ("2004-12-31","2004-12-31 23:59:59",20041231235959);
+mysql> INSERT INTO y2k VALUES ("2005-01-01","2005-01-01 00:00:00",20050101000000);
+mysql> INSERT INTO y2k VALUES ("2030-01-01","2030-01-01 00:00:00",20300101000000);
+mysql> INSERT INTO y2k VALUES ("2050-01-01","2050-01-01 00:00:00",20500101000000);
+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
+
+This shows that the @code{DATE} and @code{DATETIME} types are will not
+give any problems with future dates (they handle dates until the year
+9999).
+
+The @code{TIMESTAMP} type, that is used to store the current time, has a
+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 @strong{MySQL} is Y2K-compliant, it is your responsibility to
+provide unambiguous input. See @ref{Y2K issues} for @strong{MySQL}'s rules
+for dealing with ambiguous date input data (data containing 2-digit year
+values).
+
+@node General-SQL, Useful Links, Year 2000 compliance, Introduction
+@section General SQL information and tutorials
+
+This book has been recommended by a several people on the @strong{MySQL}
+mailing list:
+
+@example
+Judith S. Bowman, Sandra L. Emerson and Marcy Darnovsky
+The Practical SQL Handbook: Using Structured Query Language
+Second Edition
+Addison-Wesley
+ISBN 0-201-62623-3
+http://www.awl.com
+@end example
+
+This book has also received some recommendations by @strong{MySQL} users:
+
+@example
+Martin Gruber
+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://www.geocities.com/SiliconValley/Vista/2207/sql1.html
+
+SQL in 21 Tagen (online book in German language):
+http://www.mut.de/leseecke/buecher/sql/inhalt.htm
+
+@node Useful Links, , General-SQL, Introduction
+@section Useful MySQL-related links
+
+Apart from the following links, you can find and download a lot of
+@strong{MySQL} programs, tools and APIs from the
+@uref{http://www.mysql.com/Contrib/, Contrib directory}.
+
+@subheading Tutorials
+@itemize @bullet
+
+@item @uref{http://www.devshed.com/resource/advanced/mysql/index.html, A
+beginner's tutorial of how to start using @strong{MySQL}}
+
+@item @uref{http://www.analysisandsolutions.com/code/mybasic.htm}
+Beginners @strong{MySQL} Tutorial on how to install and set up
+@strong{MySQL} on a Windows machine.
+
+@item @uref{http://www.devshed.com/Server_Side/MySQL/, A lot of @strong{MySQL} tutorials}
+
+@item @uref{http://www.linuxplanet.com/linuxplanet/tutorials/1046/1/,
+Setting Up a @strong{MySQL}-Based Website}
+
+@item @uref{http://www.hotwired.com/webmonkey/backend/tutorials/tutorial1.html, @strong{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/@strong{MySQL} Tutorial}
+
+@item @uref{http://www.useractive.com/, Hands on tutorial for @strong{MySQL}}
+@end itemize
+
+@subheading Porting MySQL / Using MySQL on different systems
+@itemize @bullet
+@item @uref{http://xclave.macnn.com/MySQL/,The MacOS Xclave}.
+Running @strong{MySQL} on MacOSX
+@item @uref{http://www.prnet.de/RegEx/mysql.html, MySql for MacOSX Server}
+@item @uref{http://www.lilback.com/macsql/, Client libraries for the Macintosh}
+@end itemize
+
+@subheading Perl related links
+@itemize @bullet
+@item
+@c Added 991122
+@uref{http://haven.e-cactus.com/dbi_mysql, Perl DBI with @strong{MySQL} FAQ}
+@end itemize
+
+@subheading MySQL discussion forums
+@itemize @bullet
+@item
+@uref{http://www.weberdev.com/, Examples using @strong{MySQL}; (check Top 20)}
+@item
+@uref{http://futurerealm.com/forum/futureforum.htm, FutureForum Web Discussion Software}
+@end itemize
+
+@c We should get longer descriptions for things in this category!
+@subheading Commercial applications that support MySQL
+@itemize @bullet
+@item
+@uref{http://www.supportwizard.com/, SupportWizard; Interactive helpdesk
+on the web (This product includes a licensed copy of @strong{MySQL})}
+@item
+@uref{http://www.stweb.org/, StWeb}
+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 @strong{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}
+@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 itemize
+
+@subheading SQL Clients/Report writers
+
+@itemize @bullet
+@item
+@uref{http://www.urbanresearch.com/software/utils/urbsql/index.html,
+@strong{MySQL} Editor/Utility for MS Windows Platforms.}
+@item
+@uref{http://www.xnot.com/kmysql, KDE @strong{MySQL} client}
+@item
+@c EMAIL: bilhaut_f@mail.cpod.fr (Frédérik Bilhaut)
+@uref{http://www.penguinpowered.com/~kmysql, KMySQL}
+KMySQL is a database client for KDE that primarily supports @strong{MySQL}.
+@item
+@uref{http://www.ecker-software.de, Win32 GUI client}
+A Win32 GUI client by David Ecker.
+@item
+@uref{http://www.icaap.org/software/kiosk/, Kiosk; a @strong{MySQL} client for
+database management}. Written in Perl. Will be a part of Bazaar.
+@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 @strong{MySQL} create statements and data in a lot of
+different formats (SQL, HTML, CVS, text, ZIP, GZIP...)
+@end itemize
+
+@subheading Distributions that include MySQL
+
+@itemize @bullet
+@item
+@uref{http://www.suse.com/, SuSE Linux (Suse 6.1 and above)}
+@end itemize
+
+@subheading Web development tools that support @strong{MySQL}
+
+@itemize @bullet
+@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 @strong{MySQL} and PHP}
+@item
+@uref{http://www.smartworker.org, SmartWorker is a platform for web application development}
+@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)}
+@item
+@uref{http://www.dbServ.de/, dbServ} is an extension to a web server to
+integrate databases 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}
+@c @item
+@c no answer from server 990830
+@c @uref{http://www.voicenet.com/~zellert/tjFM, A JDBC driver for @strong{MySQL}}
+@item
+@uref{http://www.wernhart.priv.at/php/, @strong{MySQL} + PHP demos}
+@item
+@uref{http://www.dbwww.com/, ForwardSQL: HTML interface to manipulate @strong{MySQL} databases}
+@item
+@uref{http://www.daa.com.au/~james/www-sql/, WWW-SQL: Display database
+information}
+@item
+@uref{http://www.minivend.com/minivend/, Minivend: A Web shopping cart}
+@item
+@uref{http://www.heitml.com/, HeiTML: A server-side extension of HTML and
+a 4GL language at the same time}
+@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}
+@item
+@uref{http://hawkeye.net/, Hawkeye Internet Server Suite}
+@item
+@uref{http://www.fastflow.com/, Network Database Connection For Linux}
+@item
+@uref{http://www.wdbi.net/,
+WDBI: Web browser as a universal front end to databases which supports
+@strong{MySQL} well.}
+@item
+@uref{http://www.webgroove.com/, WebGroove Script: HTML compiler and server-side scripting language}
+@item
+@uref{http://www.ihtml.com/, A server-side web site scripting language}
+@item
+@uref{ftp://ftp.igc.apc.org/pub/myodbc/README, How to use @strong{MySQL} with ColdFusion on Solaris}
+@item
+@uref{http://calistra.com/MySQL/,Calistra's ODBC @strong{MySQL} Administrator}
+@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 @strong{MySQL} and PostgreSQL
+through ODBC.
+@item
+@uref{http://phpclub.unet.ru/index_e.php3, PHPclub}. Tips and tricks for PHP
+@item
+@uref{http://www.penguinservices.com/scripts, @strong{MySQL} and Perl Scripts}
+@item
+@uref{http://www.widgetchuck.com, The Widgetchuck; Web Site Tools and Gadgets}
+@item
+@uref{http://www.adcycle.com/, AdCycle} advertising management software
+@item
+@uref{http://www.bidsystems.com/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}
+OMNIS Studio is a rapid application development (RAD) tool.
+@end itemize
+
+@subheading Database design tools with MySQL support
+@itemize @bullet
+@item
+@uref{http://www.mysql.com/dezign/index.html, "DeZign for
+databases" is a database development tool using an
+entity relationship diagram (ERD).}
+@end itemize
+
+@subheading Web servers with @strong{MySQL} tools
+
+@itemize @bullet
+@item
+@uref{http://bourbon.netvision.net.il/mysql/mod_auth_mysql/, An Apache
+authentication module}
+@item
+@uref{http://www.roxen.com/, The Roxen Challenger Web server}
+@end itemize
+
+@subheading Extensions for other programs
+
+@itemize @bullet
+@item
+@uref{http://www.seawood.org/msql_bind/, @strong{MySQL} support for BIND
+(The Internet Domain Name Server)}
+@item
+@uref{http://www.inet-interactive.com/sendmail, @strong{MySQL} support for
+Sendmail and Procmail}
+@end itemize
+
+@subheading Using @code{MySQL} with other programs
+
+@itemize @bullet
+@item
+@uref{http://www.iserver.com/support/addonhelp/database/mysql/msaccess.html, Using @strong{MySQL} with Access}
+@item
+@uref{http://www.iserver.com/support/contrib/perl5/modules.html,Installing new Perl modules that require locally installed modules}
+@end itemize
+
+@subheading ODBC related links
+
+@itemize @bullet
+@item
+@uref{http://www.iodbc.org/,Popular iODBC Driver Manager (libiodbc) now available in Open Source format}
+@item
+@uref{http://users.ids.net/~bjepson/freeODBC/,The FreeODBC Pages}
+@item
+@uref{http:/http://genix.net/unixODBC/,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 @strong{MySQL}-based ODBC drivers for Btrieve
+@end itemize
+
+@subheading @strong{API} related links
+
+@itemize @bullet
+@item
+@uref{http://www.amedea.cz/mysqlx/index.html, MySQL COM extension}
+With this COM objects You can use MySQL also on Windows platform with ASP
+pages or Delphi, Visual Basic, Visual C++, ... languages.
+@item
+@uref{http://www.jppp.com, www.jppp.com}
+Partially implemented TDataset-compatible components for @strong{MySQL}.
+@item
+@uref{http://www.riverstyx.net/qpopmysql/,qpopmysql}
+A patch to allow POP3 authentication from a @strong{MySQL} database.
+There's also a link to Paul Khavkine's patch for Procmail to allow
+any MTA to deliver to users in a @strong{MySQL} database.
+@item
+@uref{http://www.pbc.ottawa.on.ca,Visual Basic class generator for Active X}
+@item
+@uref{http://www.lilback.com/macsql/, Client libraries for the Macintosh}
+@c @item
+@c @uref{http://tfdec1.fys.kuleuven.ac.be/~michael/fpc-linux/mysql,
+@c @strong{MySQL} binding to Free Pascal}
+@item
+@uref{http://www.dedecker.net/jessie/scmdb/, SCMDB}.
+SCMDB is 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 itemize
+
+@subheading Other @strong{MySQL}-related links
+
+@itemize @bullet
+@item
+@uref{http://www.wix.com/mysql-hosting, Registry of Web providers who
+support @strong{MySQL}}
+@item
+@uref{http://www.softagency.co.jp/mysql/index.en.phtml, Links about using
+@strong{MySQL} in Japan/Asia}
+@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}
+@c @item
+@c Error 404 990830
+@c @uref{http://home.wxs.nl/cgi-bin/planeteers/pgidszoek.cgi, Full-text search engine using @strong{MySQL}}
+@item
+@uref{http://www.cynergi.net/non-secure/exportsql/, ExportSQL: A script
+to export data from Access95+}
+@item
+@uref{http://SAL.KachinaTech.COM/H/1/MYSQL.html, SAL (Scientific
+Applications on Linux) @strong{MySQL} entry}
+@c Removed 990510
+@c @item
+@c @uref{http://www.cgishop.com/bin/mysqllist, @strong{MySQL} Apps and
+@c Utilities Listing}
+@c @item
+@c @uref{http://www.luth.se/~goggi/proj/mysql/man/mysql.pdf, The
+@c @strong{MySQL} reference manual in Adobe PDF format}
+@item
+@uref{http://www.infotech-nj.com/itech/index.shtml, A consulting company
+which mentions @strong{MySQL} in the right company}
+@item
+@uref{http://www.pmpcs.com/, PMP Computer Solutions. Database developers using
+@strong{MySQL} and @code{mSQL}}
+@item
+@uref{http://www.aewa.org, Airborne Early Warning Association }
+@item
+@uref{http://abattoir.cc.ndsu.nodak.edu/~nem/mysql/udf/, @strong{MySQL} UDF Registry}
+@item
+@uref{http://21ccs.com/~gboersm/y2kmatrix/, Y2K tester}
+@end itemize
+
+@subheading SQL and database interfaces
+@itemize @bullet
+@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}
+@item
+@uref{http://www.binevolve.com/~tdarugar/tcl-sql, Tcl interface}
+@end itemize
+
+@subheading Examples of MySQL use
+
+@itemize @bullet
+@item
+@c Added 990601
+@c EMAIL: thuss@little6.com (Todd Huss)
+@uref{http://www.little6.com/about/linux/, Little6 Inc} An online contract and job finding site that is powered by @strong{MySQL}, PHP3 and Linux.
+@item
+@c Added 990521
+@c EMAIL: nh@delec.com (Hillbrecht Nicole)
+@uref{http://www.delec.com/is/products/prep/examples/BookShelf/index.html, DELECis} A tool which makes it very easy to create an automatically generated table documentation. They have used @strong{MySQL} as an example.
+@c @item
+@c Added 990531. Removed 000201 -> No answer from server
+@c EMAIL: sfambro@hotmail.com (Steve Fambro)
+@c @uref{http://shredder.elen.utah.edu/steve.html, Steve Fambro}
+@c Uses @strong{MySQL} and webmerger. There is an employee database, and a
+@c license plate database with all of the registered Utah vehicles (over
+@c 1.2 million). The License plate field is indexed.....so the *searches*
+@c are instantaneous.
+@item
+@c Added 990521
+@c EMAIL: info@worldrecords.com (Jim Rota)
+@uref{http://www.worldrecords.com, World Records} A search engine for information about music that uses @strong{MySQL} and PHP.
+@item
+@uref{http://www.webtechniques.com/archives/1998/01/note/,
+A Contact Database using @strong{MySQL} and PHP}
+@item
+@uref{http://modems.rosenet.net/mysql/, Web based interface and Community Calender 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.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 own cursors in VB}
+@item
+@uref{http://keilor.cs.umass.edu/pluribus/, 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 @strong{MySQL}.
+@item
+@c EMAIL: paul@sword.damocles.com (Paul Bannister)
+@uref{http://www.stopbit.com/, Stopbit}
+A technology news site using @strong{MySQL} and PHP
+@item
+@c Added 990604
+@c EMAIL: ah@dybdahl.dk
+@uref{http://www.jokes2000.com/scripts/, Example scripts at Jokes2000}
+@item
+@uref{http://www.linuxsupportline.com/~kalendar/ KDE based calendar manager}
+The calendar manager has both single user (file based) and multi user
+(@strong{MySQL} database) support.
+@item
+@uref{http://tim.desert.net/~tim/imger/,Example of storing/retrieving images with @strong{MySQL} and CGI}
+@item
+@uref{http://www.penguinservices.com/scripts, Online shopping cart system}
+@item
+@c Added 990928 from editor@city-gallery.com
+@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 @strong{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 in on the shared @strong{MySQL} server.
+@end itemize
+
+@subheading General database links
+@itemize @bullet
+@item
+@uref{http://www.pcslink.com/~ej/dbweb.html, Database Jump Site}
+@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/index.html,
+Perl @code{DBI}/@code{DBD} modules homepage}
+@item
+@uref{http://www.student.uni-koeln.de/cygwin/, Cygwin tools. UNIX on top of Windows}
+@item
+@uref{http://dbasecentral.com/, dbasecentral.com; Development and distribution of powerful and easy-to-use database applications and systems.}
+@item
+@uref{http://www.Tek-Tips.com, Tek-Tips Forums} 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.
+@end itemize
+
+There are also many web pages that use
+@strong{MySQL}. @xref{Users}. Send any additions to this list to
+@email{webmaster@@mysql.com}. We now require that you show a
+@strong{MySQL} logo somewhere (It is okay to have it on a ``used tools'' page
+or something similar) to be added.
+
+@cindex Reporting errors
+@cindex @strong{MySQL} mailing lists
+@node Questions, Licensing and Support, Introduction, Top
+@chapter MySQL mailing lists and how to ask questions or report errors (bugs)
+
+@menu
+* Mailing-list:: The @strong{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
+
+@node Mailing-list, Asking questions, Questions, Questions
+@section The MySQL mailing lists
+
+To subscribe to the main @strong{MySQL} mailing list, send a message to the
+electronic mail address @email{mysql-subscribe@@lists.mysql.com}.
+
+To unsubscribe from the main @strong{MySQL} mailing list, send a message to
+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 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 word, followed by
+your address with the @samp{@@} character in your address replaced by a
+@samp{=}. For example, to subscribe @code{john@@host.domain}, send a message
+to @code{mysql-subscribe-john=host.domain@@lists.mysql.com}.
+
+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}.
+
+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
+subscribing or unsubscribing to @email{mysql@@lists.mysql.com}, because any
+mail sent to that address is distributed automatically to thousands of other
+users.
+
+Your local site may have many subscribers to @email{mysql@@lists.mysql.com}.
+If so, it may have a local mailing list, so that messages sent from
+@code{lists.mysql.com} to your site are propagated to the local list. In such
+cases, please contact your system administrator to be added to or dropped
+from the local @strong{MySQL} list.
+
+The following @strong{MySQL} mailing lists exist:
+
+@table @code
+@item announce
+This is for announcement of new versions of @strong{MySQL} and related
+programs. This is a low volume list that we think all @strong{MySQL}
+users should be on.
+
+@item mysql
+The main list for general @strong{MySQL} discussion. Please note that some
+topics are better discussed on the more-specialized lists. If you post to the
+wrong list, you may not get an answer!
+
+@item mysql-digest
+The @code{mysql} list in digest form. That means you get all individual
+messages, sent as one large mail message once a day.
+
+@item bugs
+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 @strong{MySQL} version).
+Preferably, you should test the problem using the latest stable or
+development version of @strong{MySQL} before posting!
+Anyone should be able to repeat the bug by just using 'mysql test <
+script' on the included test case. All bugs posted on this list will be
+corrected or documented in the next @strong{MySQL} release! If there are only
+small code changes involved, we will also post a patch that fixes the problem.
+
+@item bugs-digest
+The @code{bugs} list in digest form
+
+@item developer
+A list for people who work on the @strong{MySQL} code. On this list one
+can also discuss @strong{MySQL} development and post patches.
+
+@item developer-digest
+A digest version of the @code{developer} list.
+
+@item java
+Discussion about @strong{MySQL} and Java. Mostly about the JDBC drivers.
+
+@item java-digest
+A digest version of the @code{java} list.
+
+@item win32
+All things concerning @strong{MySQL} on Microsoft operating systems such as
+Windows NT.
+
+@item win32-digest
+A digest version of the @code{win32} list.
+
+@item myodbc
+All things concerning connecting to @strong{MySQL} with ODBC.
+
+@item myodbc-digest
+A digest version of the @code{myodbc} list.
+
+@item plusplus
+All things concerning programming with the C++ API to @strong{MySQL}.
+
+@item plusplus-digest
+A digest version of the @code{plusplus} list.
+
+@item msql-mysql-modules
+A list about the Perl support in @strong{MySQL}.
+
+@item msql-mysql-modules-digest
+A digest version of the @code{msql-mysql-modules} list.
+@end table
+
+You subscribe or unsubscribe to all lists in the same way as described
+above. In your subscribe or unsubscribe message, just put the appropriate
+mailing list name rather than @code{mysql}. For example, to subscribe to or
+unsubscribe from the @code{myodbc} list, send a message to
+@email{myodbc-subscribe@@lists.mysql.com} or
+@email{myodbc-unsubscribe@@lists.mysql.com}.
+
+@cindex Net etiquette
+@node Asking questions, Bug reports, Mailing-list, Questions
+@section Asking questions or reporting bugs
+
+Before posting a bug report or question, please do the following:
+
+@itemize @bullet
+@item
+Start by searching the @strong{MySQL} online manual at:
+
+@example
+@uref{http://www.mysql.com/documentation/manual.php}
+@end example
+
+We try to keep the manual up to date by
+updating it frequently with solutions to newly found problems!
+
+@item
+Search the @strong{MySQL} mailing list archives:
+
+@example
+@uref{http://www.mysql.com/documentation/}
+@end example
+
+@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
+@uref{http://www.mysql.com/}.
+@end itemize
+
+If you can't find an answer in the manual or the archives, check with your
+local @strong{MySQL} expert. If you still can't find an answer to your
+question, go ahead and read the next section about how to send mail to
+@email{mysql@@lists.mysql.com}.
+
+@cindex Bug reports
+@cindex Reporting bugs
+@node Bug reports, Answering questions, Asking questions, Questions
+@section How to report bugs or problems
+
+Writing a good bug report takes patience, but doing it right the first
+time saves time for us and for you. A good bug report containing a full
+test case for the bug will make it very likely that we will fix it in
+the next release. This section will help you write your report correctly
+so that you don't waste your time doing things that may not help us much
+or at all.
+
+We encourage everyone to use the @code{mysqlbug} script to generate a bug
+report (or a report about any problem), if possible. @code{mysqlbug} can be
+found in the @file{scripts} directory in the source distribution, or, for a
+binary distribution, in the @file{bin} directory under your @strong{MySQL}
+installation directory. If you are unable to use @code{mysqlbug}, you should
+still include all the necessary information listed in this section.
+
+The @code{mysqlbug} script helps you generate a report by determining much
+of the following information automatically, but if something important is
+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.
+
+If you can make a test case which clearly shows the bug, you should post
+it to the @email{bugs@@list.mysql.com} 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 @strong{MySQL} version).
+Preferably, you should test the problem using the latest stable or development
+version of @strong{MySQL} before posting! Anyone should be able to repeat the
+bug by just using 'mysql test < script' on the included test case or run
+the shell / perl script that is included in the bug report. All bugs
+posted on this list will be corrected or documented in the next @strong{MySQL}
+release! If there are only small code changes involved, to correct this
+problem, we will also post a patch that fixes the problem.
+
+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
+details don't matter. A good principle is: if you are in doubt about stating
+something, state it! It is a thousand times faster and less troublesome to
+write a couple of lines more in your report than to be forced to ask again
+and wait for the answer because you didn't include enough information the
+first time.
+
+The most common errors are that people don't indicate the version number of
+the @strong{MySQL} distribution they are using, or don't indicate what
+platform they have @strong{MySQL} 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?'' and then we find that the feature
+requested wasn't implemented in that @strong{MySQL} version, or that a bug
+described in a report has been fixed already in newer @strong{MySQL}
+versions. Sometimes the error is platform dependent; in such cases, it is
+next to impossible to fix anything without knowing the operating system and
+the version number of the platform.
+
+Remember also to provide information about your compiler, if it is related to
+the problem. Often people find bugs in compilers and think the problem is
+@strong{MySQL} related. Most compilers are under development all the time and
+become better version by version, too. To determine whether or not your
+problem depends on your compiler, we need to know what compiler is used.
+Note that every compiling problem should be regarded as a bug report and
+reported accordingly.
+
+It is most helpful when a good description of the problem is included in the
+bug report. That is, a good example of all the things you did that led to
+the problem and the problem itself exactly described. The best reports are
+those that include a full example showing how to reproduce the bug or
+problem.
+
+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 sensitivity 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 genereate a MyODBC
+trace file. @xref{MyODBC bug report}.
+
+Please remember that many of the people who will read your report will
+do so using an 80-column display. When generating reports or examples
+using the @code{mysql} command line tool, you should therefore use
+the @code{--vertical} option (or the @code{\G} statement terminator)
+for output which would exceed the available width for such a display
+(for example, with the @code{EXPLAIN SELECT} statement; see the
+example below).
+
+Please include the following information in your report:
+
+@itemize @bullet
+@item
+The version number of the @strong{MySQL} distribution you are using (for
+example, @strong{MySQL} 3.22.22). You can find out which version you are
+running by executing @code{mysqladmin version}. @code{mysqladmin} can be
+found in the @file{bin} directory under your @strong{MySQL} installation
+directory.
+
+@item
+The manufacturer and model of the machine you are working on.
+
+@item
+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, include these values.
+
+@item
+If you are using a source distribution of @strong{MySQL}, the name and
+version number of the compiler used is needed.
+If you have a binary distribution, the distribution name is needed.
+
+@item
+If the problem occurs during compilation, include the exact error
+message(s) and also a few lines of context around the offending code in the
+file where the error occurred.
+
+@item
+If any database table is related to the problem, include the output from
+@code{mysqldump --no-data db_name tbl_name1 tbl_name2 ...} This is very easy
+to do and is a powerful way to get information about any table in a database
+that will help us create a situation matching the one you have.
+
+@item
+For speed-related bugs or problems with @code{SELECT} statements, you should
+always include the output of @code{EXPLAIN SELECT ...}, and at least the
+number of rows that the @code{SELECT} statement produces. The more
+information you give about your situation, the more likely it is that someone
+can help you! For example, the following is an example of a very good bug
+report (it should of course be posted with the @code{mysqlbug} script):
+
+Example run using the @code{mysql} command line tool (note the use of the
+@code{\G} statement terminator for statements whose output width would
+otherwise exceed that of an 80-column display device):
+
+@example
+mysql> SHOW VARIABLES;
+mysql> SHOW COLUMNS FROM ...\G
+ <output-from-SHOW-COLUMNS>
+mysql> EXPLAIN SELECT ...\G
+ <output-from-EXPLAIN>
+mysql> FLUSH STATUS;
+mysql> SELECT ...;
+ <A short version of the output from SELECT,
+ including the time taken to run the query>
+mysql> SHOW STATUS;
+ <output from SHOW STATUS>
+@end example
+
+@item
+If a bug or problem occurs while running @strong{MySQL}, 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't provide a script, you should at least include the output
+from @code{mysqladmin variables extended-status processlist} in your mail to
+provide some information of how your system is performing!
+
+@item
+If you think that @strong{MySQL} 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.
+
+@item
+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, table,
+etc.! 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 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 @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 an example using other names, but please regard this as the last
+choice.
+
+@item
+Include all the options given to the relevant programs, if possible. For
+example, indicate the options that you use when you start the @code{mysqld}
+daemon and that you use to run any @strong{MySQL} client programs. The
+options to programs like @code{mysqld} and @code{mysql}, and to the
+@code{configure} script are often keys to answers and very relevant! It is
+never a bad idea to include them anyway! If you use any modules, such as
+Perl or PHP, please include the version number(s) of those as well.
+
+@item
+If you can't produce a test case in a few rows, or if the test table
+is too big to be mailed to the mailing list (more than 10 rows), you should
+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 short description of the problem to @email{mysql@@lists.mysql.com}.
+
+@item
+If your question is related to the privilege system, please include the
+output of @code{mysqlaccess}, the output of @code{mysqladmin reload} and all
+the error messages you get when trying to connect! When you test your
+privileges, you should first run @code{mysqlaccess}. After this, execute
+@code{mysqladmin reload version}, and last you should try to connect with the
+program that gives you trouble. @code{mysqlaccess} can be found in the
+@file{bin} directory under your @strong{MySQL} installation directory.
+
+@item
+If you have a patch for a bug, that is good, but don't assume the patch is
+all we need, or that we will use it even if you don't provide some necessary
+information such as test cases showing the bug that your patch fixes. We
+might find problems with your patch or we might not understand it at all; if
+so, we can't use it.
+
+If we can't verify exactly what the patch is meant for, we won't use it.
+Test cases will help us here. Show that the patch will handle all the
+situations that may occur. If we find a borderline case (even a rare one)
+where the patch won't work, the patch may be useless.
+
+@item
+Guesses about what the bug is, why it occurs, or what it depends on,
+are usually wrong. Even we can't guess such things without first
+using a debugger to determine the real cause of a bug.
+
+@item
+Indicate in your mail message that you have checked the reference manual
+and mail archive so others know that you have tried to solve your
+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 @strong{MySQL} 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, @strong{MySQL} doesn't support your query. In this case, your
+only options are to implement the syntax yourself or email
+@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 @strong{MySQL}, you should check the @strong{MySQL} change history to see
+when the syntax was implemented. @xref{News}. In this case, you have the
+option of upgrading to a newer version of @strong{MySQL}.
+
+@item
+If you have a problem such that your data appears corrupt or you get
+errors when you access some particular table, you should first check and then
+try repairing your tables with @code{myisamchk}.
+@xref{Maintenance}.
+
+@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 may contain some
+information about what happened. 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 middle
+of an update! If you can find the source of why @code{mysqld} dies,
+it's much easier for us to provide you with a fix for the problem!
+@xref{What is crashing}.
+
+@item
+If possible, download the most recent version of @strong{MySQL} and check
+whether or not it solves your problem. All versions of @strong{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 @strong{MySQL} versions in minutes! @xref{Which version}.
+@end itemize
+
+If you are a support customer, please cross-post the bug report to
+@email{mysql-support@@mysql.com} for higher priority treatment, as well as to
+the appropriate mailing list to see if someone else has experienced (and
+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}.
+
+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
+summary to the mailing list so that others may have the benefit of
+responses you received that helped you solve your problem!
+
+@cindex Net etiquette
+@node Answering questions, , Bug reports, Questions
+@section Guidelines for answering questions on the mailing list
+
+If you consider your answer to have broad interest, you may want to post it
+to the mailing list instead of replying directly to the individual who
+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
+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!
+
+@cindex Licensing terms
+@cindex Support terms
+@node Licensing and Support, Installing, Questions, Top
+@chapter MySQL licensing and support
+
+@menu
+* Licensing policy:: @strong{MySQL} licensing policy
+* Copyright:: Copyrights used by @strong{MySQL}
+* Licensing examples:: Example licensing situations
+* Cost:: @strong{MySQL} licensing and support costs
+* Support:: Types of commercial support
+@end menu
+
+This chapter describes @strong{MySQL} support and licensing
+arrangements:
+
+@itemize @bullet
+
+@item The copyrights under which @strong{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
+
+@cindex Licensing policy
+@node Licensing policy, Copyright, Licensing and Support, Licensing and Support
+@section MySQL licensing policy
+
+The formal terms of the GPL license can be found at @ref{GPL license}.
+Basically, our licensing policy and intepretation of the GPL is as follows:
+
+Note that older versions of @strong{MySQL} are still using a more strict
+license. See the documentation for that version for more information.
+If you need a commercial @strong{MySQL} license, because the GPL license
+doesn't suit your application, you can buy one at
+https://order.mysql.com/license.htmy.
+
+For normal internal use, @strong{MySQL} costs nothing. You do not have
+to pay us if you do not want to.
+
+@heading A license is required if:
+
+@itemize @minus
+@item
+You link a part of the of @strong{MySQL} that has a GPL Copyright to a
+program which is not free software (embedded usage of the @strong{MySQL}
+server). In this case your application would also become GPL through the
+clause in the GPL license that acts as a virus. By licensing
+@strong{MySQL} from us under a commercial license you will avoid this
+problem.
+
+@item
+You have a commercial application that ONLY works with @strong{MySQL}
+and ships the application with the @strong{MySQL} server. This is
+because we view this a linking even if it is done over the network.
+
+@item You have a distribute @code{MySQL} and you don't provide the
+source code for your copy of the @strong{MySQL} server, as defined in
+the GPL license.
+@end itemize
+
+@heading 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 access part of @strong{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 @strong{MySQL} does not require a license, but you
+like @strong{MySQL} and want to encourage further development, you are
+certainly welcome to purchase a license or @strong{MySQL} support anyway.
+
+@item
+If you use @strong{MySQL} in a commercial context such that
+you profit by its use, we ask that you further the development of
+@strong{MySQL} by purchasing some level of support. We feel that if
+@strong{MySQL} helps your business, it is reasonable to ask that you help
+@strong{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 @strong{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 @strong{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 @strong{MySQL}, please read this again and then
+contact us. @xref{Contact information}.
+
+If you require a @strong{MySQL} license, the easiest way to pay for it
+is to use the license form on @strong{MySQL}'s secure server at
+https://order.mysql.com/license.htmy. Other forms of payment are
+discussed in @ref{Payment information}.
+
+@cindex Copyright
+@node Copyright, Licensing examples, Licensing policy, Licensing and Support
+@section Copyrights used by MySQL
+
+@menu
+* Copyright changes:: Possible future copyright changes
+@end menu
+
+There are several different copyrights on the @strong{MySQL} distribution:
+
+@enumerate
+@item
+The @strong{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 LIBRARY GENERAL PUBLIC 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 with this is that the SQL client library should be free enough
+so that it is possible to add @strong{MySQL} support in commercial products
+without any license. So in this case we choose the LGPL license.
+
+This means that you can use @strong{MySQL} for free with any program that uses
+any of the free software licences. @strong{MySQL} is also free for any end user
+for his own/company usage.
+
+But if you use @strong{MySQL} for something important to you, you may
+want to help secure its development by purchasing licenses or a support
+contract, @ref{Support}.
+
+@node Copyright changes, , Copyright, Copyright
+@subsection Copyright changes
+
+The stable versions are of @strong{MySQL} are still using a more strict
+license. See the documatation for that version for more information.
+
+@node Licensing examples, Cost, Copyright, Licensing and Support
+@section Example licensing situations
+
+@menu
+* Products that use MySQL:: Selling products that use @strong{MySQL}
+* ISP:: ISP @strong{MySQL} services
+* Web server:: Running a web server using @strong{MySQL}.
+@end menu
+
+This section describes some situations illustrating whether or not you
+must license the @strong{MySQL} server. Generally these examples
+involve providing @strong{MySQL} as a integrated part of a product.
+
+Note that a single @strong{MySQL} license covers any number of CPUs and
+@code{mysqld} servers on a machine! It also has not limit on the number
+of clients that connect to one server in any way.
+
+@node Products that use MySQL, ISP, Licensing examples, Licensing examples
+@subsection Selling products that use @strong{MySQL}
+
+To determine whether or not you need a @strong{MySQL} license when
+selling your application, you should ask whether the proper functioning
+of your application is depentent on the use of @strong{MySQL} and
+whether you include the @strong{MySQL} server with your product. There
+are several cases to consider:
+
+@itemize @bullet
+@item
+Does your application require @strong{MySQL} to function properly?
+
+If your product requires @strong{MySQL}, you need a license for any
+machine that runs the @code{mysqld} server. For example, if you've
+designed your application around @strong{MySQL}, then you've really made
+a commercial product that requires the engine, so you need a license.
+
+If your application does not require @strong{MySQL}, you need not obtain
+a license. For example, if @strong{MySQL} just added some new optional
+features to your product (such as adding logging to a database if
+@strong{MySQL} is used rather than logging to a text file), it should
+fall within normal use, and a license would not be required.
+
+In other words, you need a license if you sell a product designed
+specifically for use with @strong{MySQL} or that requires the
+@strong{MySQL} server to function at all. This is true whether or not
+you provide @strong{MySQL} for your client as part of your product
+distribution.
+
+It also depends on what you're doing for the client. Do you plan to
+provide your client with detailed instructions on installing
+@strong{MySQL} with your software? Then your product may be contingent
+on the use of @strong{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
+@subsection ISP @strong{MySQL} services
+
+Internet Service Providers (ISPs) often host @strong{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 ISP:s that has
+@strong{MySQL} support as this will give them the confidence that if
+they get some problem with their @strong{MySQL} installation, their ISP
+will be able to solve the problem for them (in some cases with the help
+from the @strong{MySQL} development team).
+
+All @code{ISPs} that wants to keep themself up to date should subscribe
+to our announce mailing list so that they can be aware of fatal issues
+that may be relevant for their @code{MySQL} installations.
+
+Note that if the @code{ISP} doesn't have a license for @code{MySQL},
+they should give their customers at least read access to the source of
+the @code{MySQL} installation so that their customer can verify that
+it's patched correctly.
+
+@node Web server, , ISP, Licensing examples
+@subsection Running a web server using @strong{MySQL}
+
+If you use @strong{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
+@strong{MySQL}, because you are not selling an embedded @strong{MySQL}
+version yourself. However, in this case we would like you to purchase
+@strong{MySQL} support, because @strong{MySQL} is helping your
+enterprise.
+
+@cindex Costs, licensing and support
+@cindex Licensing costs
+@cindex Support costs
+@node Cost, Support, Licensing examples, Licensing and Support
+@section @strong{MySQL} licensing and support costs
+
+@menu
+* Payment information:: Payment information
+* Contact information:: Contact information
+@end menu
+
+Our current license prices are shown below. These prices are now under
+review because of the change to a GPL copyright. New prices and terms
+will be posted on the @strong{MySQL} web site
+@uref{http://www.mysql.com/} as soon as they are ready.
+
+All prices are in US Dollars. If you pay by credit card, the currency is
+EURO (European Union Euro) so the prices will differ slightly.
+
+@multitable @columnfractions .25 .2 .3
+@item @strong{Number of licenses} @tab @strong{Price per copy} @tab @strong{Total}
+@item 1 @tab US $200 @tab US $200
+@item 10 pack @tab US $150 @tab US $1500
+@item 50 pack @tab US $120 @tab US $6000
+@end multitable
+
+For high volume (OEM) purchases, the following prices apply:
+
+@multitable @columnfractions .25 .2 .3 .25
+@item @strong{Number of licenses} @tab @strong{Price per copy} @tab @strong{Minimum at one time} @tab @strong{Minimum payment}
+@item 100-999 @tab US $40 @tab 100 @tab US $4000
+@item 1000-2499 @tab US $25 @tab 200 @tab US $5000
+@item 2500-4999 @tab US $20 @tab 400 @tab US $8000
+@end multitable
+
+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 email support contract. Note that
+OEM licenses only apply for products where the user doesn't have direct
+access to the @strong{MySQL} server (embedded system). In other words:
+The @strong{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 question. 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.17 USD.
+
+@multitable @columnfractions .3 .3
+@item @strong{Type of support} @tab @strong{Cost per year}
+@item Basic email support @tab EURO 170
+@item Extended email support @tab EURO 1000
+@item Login support @tab EURO 2000
+@item Extended login support @tab EURO 5000
+@end multitable
+
+You may upgrade from any
+lower level of support to a higher level of support for the difference
+between the prices of the two support levels.
+
+@cindex Payment information
+@node Payment information, Contact information, Cost, Cost
+@subsection Payment information
+
+Currently we can take SWIFT payments, cheques or credit cards.
+
+Payment should be made to:
+@example
+Postgirot Bank AB
+105 06 STOCKHOLM, SWEDEN
+
+TCX DataKonsult 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 email address.
+
+In Europe and Japan you can use EuroGiro (that should be less expensive) to the
+same account.
+
+If you want to pay by cheque, make it payable to ``MySQL Finland AB'' and
+mail it to the address below:
+
+@example
+TCX DataKonsult 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/license.htmy, 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} @email{mysql@@lists.mysql.com}!)
+with your company information and ask us to bill you.
+
+@cindex Contact information
+@node Contact information, , Payment information, Cost
+@subsection Contact information
+
+For commercial licensing, or if you have any questions about any of the
+information in this section, please contact the @strong{MySQL} licensing
+team. The much preferred method is by E-Mail to
+@email{mysql-licensing@@mysql.com}. Fax is also possible but handling of
+these may take much longer (Fax +46-8-729 69 05).
+
+@example
+David Axmark
+Detron HB
+Kungsgatan 65 B
+753 21 UPPSALA
+SWEDEN
+Voice Phone +46-18-10 22 80
+(Timezone GMT+1. Swedish and English spoken)
+@end example
+
+@cindex Support, types
+@cindex Types of support
+@node Support, , Cost, Licensing and Support
+@section Types of commercial support
+
+@menu
+* Basic email support:: Basic email support
+* Extended email support:: Extended email support
+* Login support:: Login support
+* Extended login support:: Extended login support
+@end menu
+
+@node Basic email support, Extended email support, Support, Support
+@subsection Basic email support
+
+Basic email support is a very inexpensive support option and should be
+thought of more as a way to support our development of @strong{MySQL}
+than as a real support option. We at @strong{MySQL} do give a lot of free support
+in all the different @strong{MySQL} lists and the money we get from
+basic eamil support is largely used to make this possible.
+
+At this support level, the @strong{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
+@strong{MySQL} questions), as someone else already may have experienced and
+solved the problem you have. @xref{Asking questions}.
+
+However, by purchasing basic email 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
+@strong{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}.)
+
+@emph{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, independent of your support level! @xref{Bug reports}.
+
+Basic email 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 email 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 email.
+
+@item
+We will help with unexpected problems when you install @strong{MySQL} from a
+binary distribution on supported platforms. This level of support does not
+cover installing @strong{MySQL} from a source distribution. ``Supported''
+platforms are those for which @strong{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 @strong{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, to ensure that they are
+fixed as soon as possible.
+
+@item
+Your suggestions for the further development of @strong{MySQL} will be
+taken into consideration. By taking email support you have already
+helped the further development of @strong{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.
+
+@item
+@cindex @code{myisampack}
+We include a binary version of the @code{myisampack} packing tool for
+creating fast compressed read-only databases. The current server includes
+support for reading such databases but not the packing tool used to
+create them.
+@end itemize
+
+@node Extended email support, Login support, Basic email support, Support
+@subsection Extended email support
+
+Extended email support includes everything in basic email support with
+these additions:
+
+@itemize @bullet
+@item
+Your email will be dealt with before mail from basic email support users and
+non-registered users.
+
+@item
+Your suggestions for the further development of @strong{MySQL} will
+receive strong consideration. Simple extensions that suit the basic
+goals of @strong{MySQL} are implemented in a matter of days. By taking
+extended email support you have already helped the further development
+of @strong{MySQL}.
+
+@item
+Typical questions that are covered by extended email support are:
+
+@itemize @minus
+@item
+We will answer and (within reason) solve questions that relate to possible
+bugs in @strong{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 @strong{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 @strong{MySQL}
+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
+@subsection Login support
+
+Login support includes everything in extended email support with
+these additions:
+
+@itemize @bullet
+@item
+Your email will be dealt with even before mail from extended email
+support users.
+
+@item
+Your suggestions for the further development of @strong{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
+@strong{MySQL} will be implemented as soon as possible.
+
+@item
+If you have a very specific problem, we can try to log in on your system
+to solve the problem ``in place.''
+
+@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. @strong{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).
+
+@item
+We will provide hints on optimizing your system and your queries.
+
+@item
+You are allowed to call a @strong{MySQL} developer (in moderation) and
+discuss your @strong{MySQL}-related problems.
+@end itemize
+
+@node Extended login support, , Login support, Support
+@subsection Extended login support
+
+Extended login support includes everything in login support with these
+additions:
+
+@itemize @bullet
+@item
+Your email 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 @strong{MySQL} to better
+suit your needs.
+
+@item
+You may also request special extensions just for you. For example:
+@example
+mysql> select MY_FUNC(col1,col2) from table;
+@end example
+
+@item
+We will provide a binary distribution of all important @strong{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.
+
+@item
+If you can provide accommodations and pay for traveler fares, you can even
+get a @strong{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 as always very flexible towards our customers!
+@end itemize
+
+@node Installing, Compatibility, Licensing and Support, Top
+@chapter Installing MySQL
+
+@menu
+* Getting MySQL:: How to get @strong{MySQL}
+* Which OS:: Operating systems supported by @strong{MySQL}
+* Which version:: Which @strong{MySQL} version to use
+* Many versions:: How and when updates are released
+* Installation layouts:: Installation layouts
+* Installing binary:: Installing a @strong{MySQL} binary distribution
+* Installing source:: Installing a @strong{MySQL} source distribution
+* Compilation problems:: Problems compiling?
+* MIT-pthreads:: MIT-pthreads notes
+* Perl support:: Perl installation comments
+* Source install system issues:: System-specific issues
+* Win32:: Win32 notes
+* OS/2:: OS/2 notes
+* MySQL binaries::
+* Post-installation:: Post-installation setup and testing
+* Upgrade:: Is there anything special to do when upgrading/downgrading @strong{MySQL}?
+@end menu
+
+This chapter describes how to obtain and install @strong{MySQL}:
+
+@itemize @bullet
+@item
+For a list of sites from which you can obtain @strong{MySQL}, see
+@ref{Getting MySQL, , Getting @strong{MySQL}}.
+
+@item
+To see which platforms are supported, see @ref{Which OS}.
+
+@item
+Several versions of @strong{MySQL} are available, in both binary and
+source distributions. To determine which version and type of
+distribution you should use, see @ref{Many versions}.
+
+@item
+Installation instructions for binary and source distributions are described
+in @ref{Installing binary}, and @ref{Installing source}. Each set of
+instructions includes a section on system-specific problems you may run
+into.
+
+@item
+For post-installation procedures, see @ref{Post-installation}. These
+procedures apply whether you install @strong{MySQL} using a binary or
+source distribution.
+@end itemize
+
+@cindex Downloading
+@cindex @strong{MySQL} version
+@cindex Version, latest
+@cindex Getting @strong{MySQL}
+@node Getting MySQL, Which OS, Installing, Installing
+@section How to get MySQL
+
+Check the @uref{http://www.mysql.com/, @strong{MySQL} home page} for
+information about the current version and for downloading instructions.
+
+If you have problems downloading from our main site, try using on 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}
+@item
+@c EMAIL: delian@naturella.com (Delian Delchev)
+@image{Flags/bulgaria} Bulgaria [Naturella] @
+@uref{http://archive.nat.bg/pub/mirror/mysql/, WWW}
+@uref{ftp://ftp.ntrl.net/pub/mirror/mysql/, FTP}
+@item
+@c Added: 990614
+@c EMAIL: vuksan@veus.hr (Vladimir Vuksan)
+@image{Flags/croatia} Croatia [HULK] @
+@uref{http://ftp.linux.hr/pub/mysql/, WWW}
+@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: mirrorman@borsen.dk (Michael Kyed)
+@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://SunSITE.auc.dk/mysql/, WWW}
+@uref{ftp://SunSITE.auc.dk/pub/databases/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@spamm.ee (Tõnu Samuel)
+@image{Flags/estonia} Estonia [OKinteractive] @
+@uref{http://mysql.mirror.ok.ee, WWW}
+@item
+@c Changed 990531
+@c EMAIL: Steeve.Devergne@minet.net (Steeve Devergne)
+@image{Flags/france} France [minet] @
+@uref{http://www.minet.net/devel/mysql/, WWW}
+@item
+@c EMAIL: Jaakko.Hyvatti@eunet.fi
+@image{Flags/finland} Finland [EUnet] @
+@uref{http://mysql.eunet.fi/, WWW}
+@item
+@c Added 990829
+@c EMAIL: tomi.hakala@clinet.fi (Tomi Hakala)
+@image{Flags/finland} Finland [clinet] @
+@uref{ftp://ftp.clinet.fi/mirrors/ftp.mysql.org/pub/mysql/, FTP}
+@item
+@c Added 981208
+@c EMAIL: noel@uni-bonn.de (Noel Koethe)
+@image{Flags/germany} Germany [Bonn University, Bonn] @
+@uref{http://www.wipol.uni-bonn.de/MySQL//, WWW}
+@uref{ftp://ftp.wipol.uni-bonn.de/pub/mirror/MySQL/, 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}
+@item
+@c Ok 980114. Removed 981208 (down > 3 days) ok 981214
+@c EMAIL: straub@gks.de (Hans-Peter Straub)
+@image{Flags/germany} Germany [Staufen] @
+@uref{http://mysql.staufen.de/, WWW}
+@item
+@c Added 990614
+@c EMAIL: thomas.rohde@ecrc.de (Thomas Rohde)
+@image{Flags/germany} Germany [Cable & Wireless] @
+@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}
+@c @item
+@c File not found 990730
+@c EMAIL: torlasz@xenia.sote.hu (Laszlo L. Tornoc)
+@c @image{Flags/hungary} Hungary [Xenia] @
+@c @uref{http://xenia.sote.hu/ftp/mirrors/www.mysql.com/, WWW}
+@c @uref{ftp://xenia.sote.hu/pub/mirrors/www.mysql.com/,FTP}
+@item
+@c EMAIL: mirrors@gm.is (Tomas Edwardsson)
+@image{Flags/iceland} Island [GM] @
+@uref{http://mysql.gm.is/, WWW}
+@uref{ftp://ftp.gm.is/pub/mysql, WWW}
+@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: irena@yacc.it
+@image{Flags/italy} Italy [Teta Srl] @
+@uref{http://www.teta.it/mysql/, WWW}
+@item
+@c Added 991121
+@c EMAIL: nick@iol.ie (Nick Hilliard)
+@image{Flags/ireland} Ireland [Ireland On-Line/Dublin] @
+@uref{http://mysql.iol.ie, WWW}
+@uref{ftp://ftp.iol.ie/pub/mysql, FTP}
+@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}
+@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}
+@item
+@c EMAIL: Equipa de suporte do Leirianet <support@leirianet.pt>
+@image{Flags/portugal} Portugal [lerianet] @
+@uref{http://mysql.leirianet.pt, WWW}
+@uref{ftp://ftp.leirianet.pt/pub/mysql/,FTP}
+@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)
+@item
+@image{Flags/russia} Russia [IZHCOM] @
+@uref{http://mysql.udm.net/, WWW}
+@uref{ftp://ftp.izhcom.ru/pub/mysql/,FTP}
+@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}
+@item
+@c EMAIL: sebi@dnttm.ro (Sebastian DEAC)
+@image{Flags/romania} Romania [Timisoara] @
+@uref{http://www.dnttm.ro/mysql, WWW}
+@uref{ftp://ftp.dnttm.ro/pub/mysql, FTP}
+@item
+@c EMAIL: tim@lbi.ro (Bogdan Surdu)
+@image{Flags/romania} Romania [Bucharest] @
+@uref{http://www.lbi.ro/MySQL, WWW}
+@uref{ftp://ftp.lbi.ro/mirrors/ftp.tcx.se, FTP}
+
+@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}
+
+@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}
+
+@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}
+
+@c @item
+@c @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 gareth@omnipotent.net (Gareth Watts)
+@image{Flags/great-britain} UK [Omnipotent/UK] @
+@uref{http://mysql.omnipotent.net/, WWW}
+@uref{ftp://mysql.omnipotent.net/, FTP}
+
+@item
+@c 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 unknown
+@c @image{Flags/great-britain} UK [MicroMuse] @
+@c @uref{ftp://ftp.micromuse.co.uk/pub/packages/unix/databases/mysql/, FTP}
+
+@item
+@c lmjm@icparc.ic.ac.uk (Lee McLoughlin)
+@image{Flags/great-britain} UK [SunSITE] @
+@uref{http://sunsite.org.uk/packages/mysql/, WWW}
+@uref{ftp://sunsite.org.uk/packages/mysql/, FTP}
+
+@item
+@c sander@paco.net (Alexander Ivanov)
+@image{Flags/ukraine} Ukraine [PACO] @
+@uref{http://mysql.paco.net.ua, WWW}
+@uref{ftp://mysql.paco.net.ua/, 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}
+
+@item
+@c not updated 990218. Added again 990918
+@c EMAIL: rhooper@cyberus.ca (Roy Hooper)
+@image{Flags/canada} Canada [Cyberus] @
+@uref{http://mysql.cyberus.ca/, WWW}
+@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}
+
+@item
+@c EMAIL: meltzer@icsnet.com (Jeffrey Meltzer)
+@c Added 000108
+@image{Flags/usa} USA [Meltzer/New York State] @
+@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}
+
+@item
+@c EMAIL: tcobb@staff.circle.net (Troy Cobb)
+@image{Flags/usa} USA [Circle Net/North Carolina] @
+@uref{http://www.mysql.net, WWW}
+
+@item
+@c EMAIL: paul@gina.net (Paul Vining)
+@c mirrors ftp.sunet.se
+@image{Flags/usa} USA [Gina net/Florida] @
+@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}
+
+@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}
+
+@item
+@c EMAIL: ftp-admin@digex.net
+@image{Flags/usa} USA [DIGEX] @
+@uref{ftp://ftp.digex.net/pub/packages/database/mysql/, FTP}
+
+@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}
+
+@end itemize
+
+@strong{South America:}
+
+@itemize @bullet
+@item
+@c EMAIL: gaiser@matrix.com.br (Roberto Gaiser)
+@image{Flags/brazil} Brazil [Matrix] @
+@uref{http://mysql.matrix.com.br, WWW}
+@item
+@c jpabuyer@vision.cl
+@image{Flags/chile} Chile [Vision] @
+@uref{http://mysql.vision.cl/, 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:}
+
+@itemize @bullet
+@item
+@c EMAIL: mirnshi@netchina.com.cn (Meng Lingbo)
+@image{Flags/china} China [Freecode] @
+@uref{http://mysql.freecode.com.cn, WWW}
+
+@item
+@c EMAIL: Vincent_Fong@innovator.com.hk (Vincent Fong)
+@image{Flags/china} China [Hong Kong] @
+@uref{http://mysql.islnet.net, WWW}
+
+@item
+@c EMAIL: george@netfirm.net (Hongsheng Zhu)
+@image{Flags/china} China [Netfirm] @
+@uref{http://mysql.netfirm.net, WWW}
+
+@item
+@c EMAIL: ahmlhs@nmsvr.chosun.com (Ho-sun Lee)
+@image{Flags/south-korea} Korea [KREONet] @
+@uref{http://linux.kreonet.re.kr/mysql/, WWW}
+
+@c @item
+@c ftp -> remove old files
+@c EX: ahmlhs@nmsvr.chosun.com (Ho-sun Lee)
+@c @image{Flags/south-korea} Korea [KREONet] @
+@c @uref{ftp://linux.kreonet.re.kr/pub/tools/db/mysql/, FTP}
+
+@item
+@c Ok 980805
+@c EMAIL: takeshi@SoftAgency.co.jp
+@image{Flags/japan} Japan [Soft Agency] @
+@uref{http://www.softagency.co.jp/MySQL, WWW}
+
+@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}
+
+@item
+@c Ok 981204
+@c EMAIL: hiroyuki@nucba.ac.jp (hiroyuki kurimoto)
+@image{Flags/japan} Japan [Nagoya Syouka University] @
+@uref{http://mirror.nucba.ac.jp/mirror/mysql, WWW}
+@uref{ftp://mirror.nucba.ac.jp/mirror/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}
+
+@item
+@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)
+@image{Flags/taiwan} Taiwan [HT] @
+@uref{http://mysql.ht.net.tw, WWW}
+
+@item
+@c EMAIL: linda@ttn.com.tw (Linda Hu)
+@image{Flags/taiwan} Taiwan [TTN] @
+@uref{http://mysql.ttn.net, WWW}
+
+@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}
+@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 @item @c **********************************
+@c No conntact 980106
+@c EX: serge@oneway.net
+@c @image{Flags/taiwan} Taiwan [Oneway] @
+@c @uref{ftp://ftp.oneway.com.tw/pub/mysql/, FTP}
+@end itemize
+
+@strong{Australia:}
+
+@itemize @bullet
+@item
+@c Added 980610
+@c EMAIL: jason@dstc.edu.au (Jason Andrade)
+@image{Flags/australia} Australia [AARNet/Queensland] @
+@uref{http://mirror.aarnet.edu.au/mysql, WWW}
+@uref{ftp://mirror.aarnet.edu.au/pub/mysql, FTP}
+
+@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}
+
+@item
+@c Ok 980623
+@c EMAIL: samh@bluep.com (Sam Hadzajlic)
+@image{Flags/australia} Australia [Blue Planet/Melbourne] @
+@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}
+
+@item
+@c Added 990531
+@c EMAIL: gavin@itworks.com.au (Gavin Cameron)
+@image{Flags/australia} Australia [ITworks Consulting/Victoria] @
+@uref{http://mysql.itworks.com.au, WWW}
+
+@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]}
+@end itemize
+
+@strong{Africa:}
+
+@itemize @bullet
+
+@item
+@c Ok 981010
+@c EMAIL: nick@mweb.com (Nick Rosenberg)
+@image{Flags/south-africa1} South-Africa [Mweb/] @
+@uref{http://www.mysql.mweb.co.za, WWW}
+
+@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}
+
+@end itemize
+
+@c END_OF_MIRROR_LISTING
+
+@node Which OS, Which version, Getting MySQL, Installing
+@section Operating systems supported by MySQL
+
+We use GNU Autoconf so it is possible to port @strong{MySQL} to all modern
+systems with working Posix threads and a C++ compiler. (To compile only the
+client code, a C++ compiler is required but not threads.) We use and develop
+the software ourselves primarily on Sun Solaris (versions 2.5 & 2.6) and to a
+lesser extent on RedHat Linux 5.0.
+
+@strong{MySQL} has been reported to compile sucessfully on the following
+operating system/thread package combinations. Note that for many operating
+systems, the native thread support works only in the latest versions.
+
+@itemize @bullet
+@item
+AIX 4.x with native threads. @xref{IBM-AIX}.
+@item
+BSDI 2.x with the included MIT-pthreads package. @xref{BSDI}.
+@item
+BSDI 3.0, 3.1 and 4.x with native threads. @xref{BSDI}.
+@item
+DEC UNIX 4.x with native threads. @xref{Alpha-DEC-Unix}.
+@item
+FreeBSD 2.x with the included MIT-pthreads package. @xref{FreeBSD}.
+@item
+FreeBSD 3.x with native threads. @xref{BSDI}.
+@item
+HP-UX 10.20 with the included MIT-pthreads package. @xref{HP-UX 10.20}.
+@item
+HP-UX 11.x with the native threads. @xref{HP-UX 11.x}.
+@item
+Linux 2.0+ with LinuxThreads 0.7.1 or @code{glibc} 2.0.7 . @xref{Linux}.
+@item
+MacOS X Server. @xref{MacOSX}.
+@item
+NetBSD 1.3/1.4 Intel and NetBSD 1.3 Alpha (Requires GNU make). @xref{NetBSD}.
+@item
+OpenBSD > 2.5 with native therads. OpenBSD < 2.5 with the included
+MIT-pthreads package. @xref{OpenBSD}.
+@item
+OS/2 Warp 3, FixPack 29 and OS/2 Warp 4, FixPack 4. @xref{OS/2}.
+@item
+SGI Irix 6.x with native threads. @xref{SGI-Irix}.
+@item
+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}.
+@item
+SCO UnixWare 7.0.1. @xref{SCO Unixware}.
+@item
+Tru64 Unix
+@item
+Win95, Win98, NT and Win2000. @xref{Win32}.
+@end itemize
+
+@cindex @strong{MySQL} binary distribution
+@cindex @strong{MySQL} source distribution
+@cindex Release numbers
+@cindex Version, choosing
+@cindex Choosing version
+@node Which version, Many versions, Which OS, Installing
+@section Which MySQL version to use
+
+The first decision to make is whether you want to use the latest development
+release or the last stable release:
+
+@itemize @bullet
+@item
+Normally, if you are beginning to use @strong{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 development release (currently
+@value{mysql_version}. This is because there are usually no really
+serious bugs in the development release, and you can easily test it on
+your machine with the @code{crash-me} and benchmark tests.
+@xref{Benchmarks}. Note that all @strong{MySQL} releases are
+checked with the @strong{MySQL} benchmarks and an extensive test suite
+before each release.
+
+@item
+Otherwise, if you are running an old system and want to upgrade, but
+don't want to take chances with the development version, you should
+upgrade to the latest in the same branch you are using (where only the
+last version number is newer than yours). We have tried to fix only
+fatal bugs and make small, relatively safe changes to that version.
+@end itemize
+
+The second decision to make is whether you want to use a source distribution or
+a binary distribution:
+
+@itemize @bullet
+@item
+If you want to run @strong{MySQL} on a platform for which a current binary
+distribution exists, use that. Generally, it will be easier to install
+than a source distribution.
+
+@item
+If you want to read (and/or modify) the C and C++ code that makes up
+@strong{MySQL}, you should get a source distribution. The source code is
+always the ultimate manual. Source distributions also contain more
+tests and examples than binary distributions.
+@end itemize
+
+The @strong{MySQL} naming scheme uses release numbers that consist of three
+numbers and a suffix. For example, a release name like
+@code{mysql-3.21.17-beta} is interpreted like this:
+
+@itemize @bullet
+@item
+The first number (@code{3}) describes the file format. All
+version 3 releases have the same file format. When a version 4 appears, every
+table will have to be converted to the new format (nice tools for this will
+be included, of course).
+
+@item
+The second number (@code{21}) is the release level. Normally there are two to
+choose from. One is the release/stable branch (currently @code{22}) and the
+other is the development branch (currently @code{23}) . Normally both are
+stable, but the development version may have quirks, missing documentation on
+new features or may fail to compile on some systems.
+
+@item
+The third number (@code{17}) is the version number within the
+release level. This is incremented for each new distribution. Usually you
+want the latest version for the release level you have choosen.
+
+@item
+The suffix (@code{beta}) indicates the stability level of the release.
+The possible suffixes are:
+
+@itemize @minus
+@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
+commands and extensions in most alpha releases. Active development that
+may involve major code changes can occur on an alpha release, but everything
+will be tested before doing a release. There should be no known bugs in any
+@code{MySQL} release.
+
+@item
+@code{beta} means that all new code has been tested. No major new
+features that could cause corruption on old code are added. There should
+be no known bugs. A version changes from alpha to beta when there
+haven't been any reported fatal bugs within an alpha version for at least
+a month and we don't plan to add any features that could make any old command
+more unreliable.
+
+@item
+@code{gamma} is a beta that has been around a while and seems to work fine.
+Only minor fixes are added. This is what many other companies call a release.
+
+@item
+If there is no suffix, it means that the version has been run for a
+while at many different sites with no reports of bugs other than
+platform-specific bugs. Only critical bug fixes are applied to the
+release. This is what we call a stable release.
+@end itemize
+@end itemize
+
+All versions of @strong{MySQL} are run through our standard tests and
+benchmarks to ensure that they are relatively safe to use. Because the
+standard tests are extended over time to check for all previously found bugs,
+the test suite keeps getting better.
+
+Note that all releases have been tested at least with:
+
+@table @asis
+@item An internal test suite
+This is part of a production system for a customer. It has many tables with
+hundreds of megabytes of data.
+
+@item The @strong{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.
+@xref{Benchmarks}.
+
+@item The @code{crash-me} test
+This tries to determine what features the database supports and what its
+capabilities and limitations are.
+@xref{Benchmarks}.
+@end table
+
+Another test is that we use the newest @strong{MySQL} version in our internal
+production environment, on at least one machine. We have more than 100
+gigabytes of data to work with.
+
+@node Many versions, Installation layouts, Which version, Installing
+@section How and when updates are released
+
+@strong{MySQL} is evolving quite rapidly here at MySQL AB and we want
+to share this with other @strong{MySQL} users. We try to make a release
+when we have very useful features that others seem to have a need for.
+
+We also try to help out users who request features that are easy to
+implement. We also take note of what our licensed users want to have and
+we especially take note of what our extended email supported customers
+want and try to help them out.
+
+No one has to download a new release. The News section will tell you if
+the new release has something you really want. @xref{News}.
+
+We use the following policy when updating @strong{MySQL}:
+
+@itemize @bullet
+@item
+For each minor update, the last number in the version string is incremented.
+When there are major new features or minor incompatibilities with previous
+versions, the second number in the version string is incremented. When the
+file format changes, the first number is increased.
+
+@item
+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.
+
+@item
+Binary distributions for some platforms will be made by us for major releases.
+Other people may make binary distributions for other systems but probably
+less frequently.
+
+@item
+We usually make patches available as soon as we have located and fixed
+small bugs.
+
+@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.
+
+@item
+If there is, by any chance, a fatal bug in a release we will make a new
+release as soon as possible. We would like other companies to do this,
+too. :)
+@end itemize
+
+The current stable release is 3.22; We have already moved active
+development to 3.23. Bugs will still be fixed in the stable version. We
+don't believe in a complete freeze, as this also leaves out bug fixes
+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''.
+
+@node Installation layouts, Installing binary, Many versions, Installing
+@section Installation layouts
+
+This section describes the default layout of the directories created by
+installing binary and source distributions.
+
+A binary distribution is installed by unpacking it at the installation
+location you choose (typically @file{/usr/local/mysql}) and creates the
+following directories in that location:
+
+@multitable @columnfractions .3 .7
+@item @strong{Directory} @tab @strong{Contents of directory}
+@item @file{bin} @tab Client programs and the @code{mysqld} server
+@item @file{data} @tab Log files, databases
+@item @file{include} @tab Include (header) files
+@item @file{lib} @tab Libraries
+@item @file{scripts} @tab @code{mysql_install_db}
+@item @file{share/mysql} @tab Error message files
+@item @file{sql-bench} @tab Benchmarks
+@end multitable
+
+A source distribution is installed after you configure and compile it. By
+default, the installation step installs files under @file{/usr/local}, in the
+following subdirectories:
+
+@multitable @columnfractions .3 .7
+@item @strong{Directory} @tab @strong{Contents of directory}
+@item @file{bin} @tab Client programs and scripts
+@item @file{include/mysql} @tab Include (header) files
+@item @file{info} @tab Documentation in Info format
+@item @file{lib/mysql} @tab Libraries
+@item @file{libexec} @tab The @code{mysqld} server
+@item @file{share/mysql} @tab Error message files
+@item @file{sql-bench} @tab Benchmarks and @code{crash-me} test
+@item @file{var} @tab Databases and log files.
+@end multitable
+
+Within an installation directory, the layout of a source installation differs
+from that of a binary installation in the following ways:
+
+@itemize @bullet
+@item
+The @code{mysqld} server is installed in the @file{libexec}
+directory rather than in the @file{bin} directory.
+
+@item
+The data directory is @file{var} rather than @file{data}.
+
+@item
+@code{mysql_install_db} is installed in the @file{/usr/local/bin} directory
+rather than in @file{/usr/local/mysql/scripts}.
+
+@item
+The header file and library directories are @file{include/mysql} and
+@file{lib/mysql} rather than @file{include} and @file{lib}.
+@end itemize
+
+You can create your own binary installation from a compiled source
+distribution, by executing the script @file{scripts/make_binary_distribution}.
+
+@node Installing binary, Installing source, Installation layouts, Installing
+@section Installing a MySQL binary distribution
+
+@menu
+* Linux-RPM:: Linux RPM files
+* Building clients:: Building client programs
+* Binary install system issues:: System-specific issues
+@end menu
+
+You need the following tools to install a @strong{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.
+@end itemize
+
+@cindex RPM
+@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}.
+
+The basic commands you must execute to install and use a @strong{MySQL}
+binary distribution are:
+
+@example
+shell> gunzip < mysql-VERSION-OS.tar.gz | tar xvf -
+shell> ln -s mysql-VERSION-OS mysql
+shell> cd mysql
+shell> scripts/mysql_install_db
+shell> bin/safe_mysqld &
+@end example
+
+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.
+
+Here follows a more detailed description:
+
+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
+@strong{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 @strong{MySQL}}.
+
+@strong{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 (e.g., @code{3.21.15}), and @code{OS} indicates
+the type of operating system for which the distribution is intended (e.g.,
+@code{pc-linux-gnu-i586}).
+
+@item
+Unpack the distribution and create the installation directory:
+
+@example
+shell> gunzip < 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 @strong{MySQL}
+programs properly. @xref{Environment variables}.
+
+@item scripts
+This directory contains the @code{mysql_install_db} script used to initialize
+the server access permissions.
+@end table
+
+@item
+If you would like to use @code{mysqlaccess} and have the @strong{MySQL}
+distribution in some nonstandard 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 @strong{MySQL} grant tables (necessary only if you haven't
+installed @strong{MySQL} before):
+@example
+shell> scripts/mysql_install_db
+@end example
+
+Note that @strong{MySQL} versions older than 3.22.10 started the
+@strong{MySQL} server when you run @code{mysql_install_db}. This is no
+longer true!
+
+@item
+If you want to install support for the Perl @code{DBI}/@code{DBD} interface,
+see @ref{Perl support}.
+
+@item
+If you would like @strong{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 @strong{MySQL} server with the following command:
+
+@example
+shell> bin/safe_mysqld &
+@end example
+
+@xref{Post-installation}.
+
+@cindex RPM
+@cindex RedHat Package Manager
+@c This node name is special
+@node Linux-RPM, Building clients, Installing binary, Installing binary
+@subsection Linux RPM notes
+
+The recommended way to install @strong{MySQL} on Linux is by using an RPM
+file. The @strong{MySQL} RPMs are currently being built on a RedHat 5.2
+system but should work on other versions of Linux that support @code{rpm} and
+use @code{glibc}.
+
+If you have problems with an RPM file, for example @code{Sorry, the host
+'xxxx' could not be looked up}, see @ref{Binary notes-Linux}.
+
+The RPM files you may want to use are:
+
+@itemize @bullet
+@item @code{MySQL-VERSION.i386.rpm}
+
+The @strong{MySQL} server. You will need this unless you only want to
+connect to another @strong{MySQL} server running on another machine.
+
+@item @code{MySQL-client-VERSION.i386.rpm}
+
+The standard @strong{MySQL} client programs. You probably always want to
+install this package.
+
+@item @code{MySQL-bench-VERSION.i386.rpm}
+
+Tests and benchmarks. Requires Perl and msql-mysql-modules RPMs.
+
+@item @code{MySQL-devel-VERSION.i386.rpm}
+
+Libraries and include files needed if you want to compile other
+@strong{MySQL} clients, such as the Perl modules.
+
+@item @code{MySQL-VERSION.src.rpm}
+
+This contains the source code for all of the above packages. It can also
+be used to try to build RPMs for other architectures (for example, Alpha
+or SPARC).
+@end itemize
+
+To see all files in an RPM package:
+@example
+shell> rpm -qpl MySQL-VERSION.i386.rpm
+@end example
+
+To perform a standard minimal installation, run this command:
+
+@example
+shell> rpm -i MySQL-VERSION.i386.rpm MySQL-client-VERSION.i386.rpm
+@end example
+
+To install just the client package:
+
+@example
+shell> rpm -i MySQL-client-VERSION.i386.rpm
+@end example
+
+The RPM places data in @file{/var/lib/mysql}. The RPM also creates the
+appropriate entries in @file{/etc/rc.d/} to start the server automatically
+at boot time. (This means that if you have performed a previous
+installation, you may want to make a copy of your previously-installed
+@strong{MySQL} startup file if you made any changes to it, so you don't lose
+your changes.)
+
+After installing the RPM file(s), the @file{mysqld} daemon should be running
+and you should now be able to start using @strong{MySQL}.
+@xref{Post-installation}.
+
+If something goes wrong, can find more information in the binary
+installation chapter. @xref{Installing binary}.
+
+
+@cindex Client programs, building
+@cindex Linking
+@node Building clients, Binary install system issues, Linux-RPM, Installing binary
+@subsection Building client programs
+
+If you compile @strong{MySQL} clients that you've written yourself or that
+you obtain from a third party, they must be linked using the
+@code{-lmysqlclient} option on the link command. You may also need to
+specify a @code{-L} option to tell the linker where to find the library. For
+example, if the library is installed in @file{/usr/local/mysql/lib}, use
+@code{-L/usr/local/mysql/lib -lmysqlclient} on the link command.
+
+For clients that use @strong{MySQL} header files, you may need to specify a
+@code{-I} option when you compile them (for example,
+@code{-I/usr/local/mysql/include}), so the compiler can find the header
+files.
+
+@node Binary install system issues, , Building clients, Installing binary
+@subsection System-specific issues
+
+@menu
+* Binary notes-Linux:: Linux notes
+* Binary notes-HP-UX:: HP-UX notes
+@end menu
+
+The following sections indicate some of the issues that have been observed
+on particular systems when installing @strong{MySQL} from a binary
+distribution.
+
+@node Binary notes-Linux, Binary notes-HP-UX, Binary install system issues, Binary install system issues
+@subsubsection Linux notes
+
+@strong{MySQL} needs at least Linux 2.0.
+
+The binary release is linked with @code{-static}, which means you not
+normally need not worry about which version of the system libraries you
+have. You need not install LinuxThreads, either. A program linked with
+@code{-static} is slightly bigger than a dynamically-linked program but
+also slightly faster (3-5%). One problem however is that you can't use
+user definable functions (UDFs) with a statically-linked program. If
+you are going to write or use UDF functions (this is something only for
+C or C++ programmers) you must compile @strong{MySQL} yourself, using
+dynamic linking.
+
+If you are using a @code{libc}-based system (instead of a @code{glibc2}
+system), you will probably get some problems with hostname resolving and
+getpwnam() with the binary release. (This is because @code{glibc}
+unfortunately depends on some external libraries to resolve hostnames
+and getwpent() , even when compiled with @code{-static}). In this case
+you probably get the following error message when you run
+@code{mysql_install_db}:
+
+@example
+Sorry, the host 'xxxx' could not be looked up
+@end example
+
+or the following error when you try to run mysqld with the @code{--user}
+option:
+
+@example
+getpwnam: No such file or directory
+@end example
+
+You can solve this problem one of the following ways:
+
+@itemize @bullet
+@item
+Get a @strong{MySQL} source distribution (an RPM or the @code{tar}
+distribution) and install this instead.
+@item
+Execute @code{mysql_install_db --force}; This will not execute the
+@code{resolveip} test in @code{mysql_install_db}. The downside is that
+you can't use host names in the grant tables; you must use IP numbers
+instead (except for @code{localhost}). If you are using an old @strong{MySQL}
+release that doesn't support @code{--force} you have to remove the
+@code{resolveip} test in @code{mysql_install} with an editor.
+@item
+Start mysqld with @code{su} instead of using @code{--user}.
+@end itemize
+
+The Linux-Intel binary and RPM releases of @strong{MySQL} are configured
+for the highest possible speed. We are always trying to use the fastest
+stable compiler available.
+
+@strong{MySQL} Perl support requires Perl 5.004_03 or newer.
+
+@node Binary notes-HP-UX, , Binary notes-Linux, Binary install system issues
+@subsubsection HP-UX notes
+
+Some of the binary distributions of @strong{MySQL} for HP-UX is
+distributed as an HP depot file and as a tar file. To use the depot
+file you must be running at least HP-UX 10.x to have access to HP's
+software depot tools.
+
+The HP version of @strong{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.
+@strong{MySQL} 3.22.26 and newer can also be built with HP's native
+thread package.
+
+Other configurations that may work:
+
+@itemize @bullet
+@item
+HP 9000/7xx running HP-UX 10.20+
+@item
+HP 9000/8xx running HP-UX 10.30
+@end itemize
+
+The following configurations almost definitely won't work:
+
+@itemize @bullet
+@item
+HP 9000/7xx or 8xx running HP-UX 10.x where x < 2
+@item
+HP 9000/7xx or 8xx running HP-UX 9.x
+@end itemize
+
+To install the distribution, use one of the commands below, where
+@code{/path/to/depot} is the full pathname of the depot file:
+
+@itemize @bullet
+@item
+To install everything, including the server, client and development tools:
+
+@example
+shell> /usr/sbin/swinstall -s /path/to/depot mysql.full
+@end example
+
+@item
+To install only the server:
+
+@example
+shell> /usr/sbin/swinstall -s /path/to/depot mysql.server
+@end example
+
+@item
+To install only the client package:
+
+@example
+shell> /usr/sbin/swinstall -s /path/to/depot mysql.client
+@end example
+
+@item
+To install only the development tools:
+
+@example
+shell> /usr/sbin/swinstall -s /path/to/depot mysql.developer
+@end example
+@end itemize
+
+The depot places binaries and libraries in @file{/opt/mysql} and data in
+@file{/var/opt/mysql}. The depot also creates the appropriate entries in
+@file{/sbin/init.d} and @file{/sbin/rc2.d} to start the server automatically
+at boot time. Obviously, this entails being @code{root} to install.
+
+To install the HP-UX tar distribution, you must have a copy of GNU @code{tar}.
+
+@node Installing source, Compilation problems, Installing binary, Installing
+@section Installing a MySQL source distribution
+
+You need the following tools to build and install @strong{MySQL} from source:
+
+@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.
+
+@item
+A working ANSI C++ compiler. @code{gcc} >= 2.8.1, @code{egcs} >=
+1.0.2, SGI C++ and SunPro C++ are some of the compilers that are known to
+work. @code{libg++} is not needed when using @code{gcc}. @code{gcc}
+2.7.x has a bug that makes it impossible to compile some perfectly legal
+C++ files, such as @file{sql/sql_base.cc}. If you only have @code{gcc} 2.7.x,
+you must upgrade your @code{gcc} to be able to compile @strong{MySQL}.
+
+@item
+A good @code{make} program. GNU @code{make} is always recommended and is
+sometimes required. If you have problems, we recommend trying GNU
+@code{make} 3.75 or newer.
+@end itemize
+
+@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{scripts} directory after you unpack the distribution. @xref{Bug
+reports}.
+
+@menu
+* Quick install:: Quick installation overview
+* Applying patches:: Applying patches
+* configure options:: Typical @code{configure} options
+@end menu
+
+@node Quick install, Applying patches, Installing source, Installing source
+@subsection Quick installation overview
+
+The basic commands you must execute to install a @strong{MySQL} source
+distribution are (from an unpacked @code{tar} file):
+
+@example
+shell> configure
+shell> make
+shell> make install
+shell> scripts/mysql_install_db
+shell> /usr/local/mysql/bin/safe_mysqld &
+@end example
+
+If you start from a source RPM, then do the following.
+
+@example
+shell> rpm --rebuild MySQL-VERSION.src.rpm
+@end example
+
+This will make a binary RPM that you can install.
+
+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.
+
+Here follows a more detailed description:
+
+To install a source distribution, follow the steps below, then proceed
+to @ref{Post-installation}, for post-installation initialization and testing.
+
+@enumerate
+@item
+Pick the directory under which you want to unpack the distribution, and move
+into it.
+
+@item
+Obtain a distribution file from one of the sites listed in
+@ref{Getting MySQL, , Getting @strong{MySQL}}.
+
+@strong{MySQL} source distributions are provided as compressed @code{tar}
+archives and have names like @file{mysql-VERSION.tar.gz}, where
+@code{VERSION} is a number like @value{mysql_version}.
+
+@item
+Unpack the distribution into the current directory:
+@example
+shell> gunzip < mysql-VERSION.tar.gz | tar xvf -
+@end example
+This command creates a directory named @file{mysql-VERSION}.
+
+@item
+Change into the top-level directory of the unpacked distribution:
+@example
+shell> cd mysql-VERSION
+@end example
+
+@item
+Configure the release and compile everything:
+@example
+shell> ./configure --prefix=/usr/local/mysql
+shell> make
+@end example
+When you run @code{configure}, you might want to specify some options.
+Run @code{./configure --help} for a list of options.
+@ref{configure options, , @code{configure} options}, discusses some of the
+more useful options.
+
+If @code{configure} fails, and you are going to send mail to
+@email{mysql@@lists.mysql.com} to ask for assistance, please include any
+lines from @file{config.log} that you think can help solve the problem. Also
+include the last couple of lines of output from @code{configure} if
+@code{configure} aborts. Post the bug report using the @code{mysqlbug}
+script. @xref{Bug reports}.
+
+If the compile fails, see @ref{Compilation problems}, for help with
+a number of common problems.
+
+@item
+Install everything:
+@example
+shell> make install
+@end example
+You might need to run this command as @code{root}.
+
+@item
+Create the @strong{MySQL} grant tables (necessary only if you haven't
+installed @strong{MySQL} before):
+@example
+shell> scripts/mysql_install_db
+@end example
+
+Note that @strong{MySQL} versions older than 3.22.10 started the
+@strong{MySQL} server when you run @code{mysql_install_db}. This is no
+longer true!
+
+@item
+If you want to install support for the Perl @code{DBI}/@code{DBD} interface,
+see @ref{Perl support}.
+
+@item
+If you would like @strong{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 installed, you should initialize and test your
+distribution.
+
+You can start the @strong{MySQL} server with the following command,
+where @code{BINDIR} is the directory in which @code{safe_mysqld} is
+installed (@file{/usr/local/bin} by default):
+
+@example
+shell> BINDIR/safe_mysqld &
+@end example
+
+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 running. @xref{Multiple
+servers}.
+
+@xref{Post-installation}.
+
+@node Applying patches, configure options, Quick install, Installing source
+@subsection 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
+@strong{MySQL} Web site.
+
+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 @strong{MySQL}
+source tree and run these commands:
+
+@example
+shell> patch -p1 < patch-file-name
+shell> rm config.cache
+shell> make clean
+@end example
+
+Patches from the FTP site are distributed as plain text files or as files
+compressed with @code{gzip}. Apply a plain patch as shown above for
+mailing list patches. To apply a compressed patch, change into the
+top-level directory of your @strong{MySQL} source tree and run these
+commands:
+
+@example
+shell> gunzip < patch-file-name.gz | patch -p1
+shell> rm config.cache
+shell> make clean
+@end example
+
+After applying a patch, follow the instructions for a normal source install,
+beginning with the @code{./configure} step. After running the @code{make
+install} step, restart your @strong{MySQL} server.
+
+You may need to bring down any currently running server before you run
+@code{make install}. (Use @code{mysqladmin shutdown} to do this.) Some
+systems do not allow you to install a new version of a program if it replaces
+the version that is currently executing.
+
+@node configure options, , Applying patches, Installing source
+@subsection Typical @code{configure} options
+
+The @code{configure} script gives you a great deal of control over how
+you configure your @strong{MySQL} distribution. Typically you do this
+using options on the @code{configure} command line. You can also affect
+@code{configure} using certain environment variables. @xref{Environment
+variables}. For a list of options supported by @code{configure}, run
+this command:
+
+@example
+shell> ./configure --help
+@end example
+
+Some of the more commonly-used @code{configure} options are described below:
+
+@itemize @bullet
+@item
+To compile just the @strong{MySQL} client libraries and client programs and
+not the server, use the @code{--without-server} option:
+
+@example
+shell> ./configure --without-server
+@end example
+
+If you don't have a C++ compiler, @code{mysql} will not compile (it is the
+one client program that requires C++). In this case,
+you can remove the code in @code{configure} that tests for the C++ compiler
+and then run @code{./configure} with the @code{--without-server} option. The
+compile step will still try to build @code{mysql}, but you can ignore any
+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 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:
+@example
+shell> ./configure --prefix=/usr/local/mysql
+shell> ./configure --prefix=/usr/local \
+ --localstatedir=/usr/local/mysql/data
+@end example
+The first command changes the installation prefix so that everything is
+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}.
+
+@item
+If you are using Unix and you want the @strong{MySQL} socket located somewhere
+other than the default location (normally in the directory @file{/tmp} or
+@file{/var/run}, use a @code{configure} command like this:
+@example
+shell> ./configure --with-unix-socket-path=/usr/local/mysql/tmp/mysql.sock
+@end example
+Note that the given file must be an absolute pathname!
+
+@item
+If you want to compile statically-linked programs (e.g., to make a binary
+distribution, to get more speed or to work around problems with some RedHat
+distributions), run @code{configure} like this:
+
+@example
+shell> ./configure --with-client-ldflags=-all-static \
+ --with-mysqld-ldflags=-all-static
+@end example
+
+@item
+If you are using @code{gcc} and don't have @code{libg++} or @code{libstdc++}
+installed, you can tell @code{configure} to use @code{gcc} as your C++
+compiler:
+
+@tindex CC environment variable
+@tindex Environment variable, CC
+@tindex CXX environment variable
+@tindex Environment variable, CXX
+@example
+shell> CC=gcc CXX=gcc ./configure
+@end example
+
+When you use @code{gcc} as your C++ compiler, it will not attempt to link in
+@code{libg++} or @code{libstdc++}.
+
+If the build fails and produces errors about your compiler or linker not
+being able to create the shared library @file{libmysqlclient.so.#} (@samp{#}
+is a version number), you can work around this problem by giving the
+@code{--disable-shared} option to @code{configure}. In this case,
+@code{configure} will not build a shared @code{libmysqlclient.so.#} library.
+
+@item
+You can configure @strong{MySQL} not to use @code{DEFAULT} column values for
+non-@code{NULL} columns (i.e., columns that are not allowed to be
+@code{NULL}). This causes @code{INSERT} statements to generate an error
+unless you explicitly specify values for all columns that require a
+non-@code{NULL} value. To suppress use of default values, run
+@code{configure} like this:
+
+@tindex CXXFLAGS environment variable
+@tindex Environment variable, CXXFLAGS
+@example
+shell> CXXFLAGS=-DDONT_USE_DEFAULT_FIELDS ./configure
+@end example
+
+@item
+By default, @strong{MySQL} uses the ISO-8859-1 (Latin1) character set. To
+change the default set, use the @code{--with-charset} option:
+@example
+shell> ./configure --with-charset=CHARSET
+@end example
+@code{CHARSET} may be one of @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},
+@code{win1251} or @code{win1251ukr}.
+@xref{Character sets}.
+
+If you want to convert characters between the server and the client,
+you should take a look at the @code{SET OPTION CHARACTER SET} command.
+@xref{SET OPTION, , @code{SET OPTION}}.
+
+@cindex @code{myisamchk}
+@strong{Warning:} If you change character sets after having created any
+tables, you will have to run @code{myisamchk -r -q} on every table. Your
+indexes may be sorted incorrectly otherwise. (This can happen if you
+install @strong{MySQL}, create some tables, then reconfigure
+@strong{MySQL} to use a different character set and reinstall it.)
+
+@item
+To configure
+@strong{MySQL} with debugging code, use the @code{--with-debug} option:
+@example
+shell> ./configure --with-debug
+@end example
+This causes a safe memory allocator to be included that can find some errors
+and that provides output about what is happening.
+@xref{Debugging server}.
+
+@item
+If your client programs are using threads, you need to compile the
+@strong{MySQL} client library to be thread safe with
+@code{--with-thread-safe-client}; this forces the library to use thread
+safe functions calls for some functions that are not thread safe by
+default. You pay a very small performance penalty by doing this, but
+generally it's quite safe to use this option.
+
+@item
+Options that pertain to particular systems can be found in the
+system-specific sections later in this chapter.
+@xref{Source install system issues}.
+@end itemize
+
+@node Compilation problems, MIT-pthreads, Installing source, Installing
+@section Problems compiling?
+
+All @strong{MySQL} programs compile cleanly for us with no warnings on
+Solaris using @code{gcc}. On other systems, warnings may occur due to
+differences in system include files. See @ref{MIT-pthreads}, for warnings
+that may occur when using MIT-pthreads. For other problems, check the list
+below.
+
+The solution to many problems involves reconfiguring. If you do need to
+reconfigure, take note of the following:
+
+@cindex Running @code{configure} after prior invocation
+@cindex @code{configure}, running after prior invocation
+@itemize @bullet
+@item
+If @code{configure} is run after it already has been run, it may use
+information that was gathered during its previous invocation. This
+information is stored in @file{config.cache}. When @code{configure} starts
+up, it looks for that file and reads its contents if it exists, on the
+assumption that the information is still correct. That assumption is invalid
+when you reconfigure.
+@item
+Each time you run @code{configure}, you must run @code{make} again
+to recompile. However, you may want to remove old object files from previous
+builds first, because they were compiled using different configuration options.
+@end itemize
+
+To prevent old configuration information or object files from being used,
+run these commands before rerunning @code{configure}:
+
+@example
+shell> rm config.cache
+shell> make clean
+@end example
+
+Alternatively, you can run @code{make distclean}.
+
+The list below describes some of the problems compiling @strong{MySQL}
+that have been found to occur most often:
+
+@itemize @bullet
+@item
+@cindex @code{cc1plus} problems
+@cindex @code{fatal signal 11}
+@cindex @code{sql_yacc.cc} problems
+@cindex Internal compiler errors
+@cindex Virtual memory problems while compiling
+If you get errors when compiling @file{sql_yacc.cc} such as the ones shown
+below, you have probably run out of memory or swap space:
+
+@example
+Internal compiler error: program cc1plus got fatal signal 11
+ or
+Out of virtual memory
+ or
+Virtual memory exhausted
+@end example
+
+The problem is that @code{gcc} requires huge amounts of memory to compile
+@file{sql_yacc.cc} with inline functions. Try running @code{configure} with
+the @code{--with-low-memory} option:
+
+@example
+shell> ./configure --with-low-memory
+@end example
+
+This option causes @code{-fno-inline} to be added to the compile line if you
+are using @code{gcc} and @code{-O0} if you are using something else. You
+should try the @code{--with-low-memory} option even if you have so much
+memory and swap space that you think you can't possibly have run out. This
+problem has been observed to occur even on systems with generous hardware
+configurations, and the @code{--with-low-memory} option usually fixes it.
+
+@item
+By default, @code{configure} picks @code{c++} as the compiler name and
+GNU @code{c++} links with @code{-lg++}. If you are using @code{gcc},
+that behavior can cause problems during configuration such as this:
+
+@cindex C++ compiler cannot create executables
+@example
+configure: error: installation or configuration problem:
+C++ compiler cannot create executables.
+@end example
+
+@tindex CXX environment variable
+@tindex Environment variable, CXX
+You might also observe problems during compilation related to
+@code{g++}, @code{libg++} or @code{libstdc++}.
+
+One cause of these problems is that you may not have @code{g++}, or you may
+have @code{g++} but not @code{libg++} or @code{libstdc++}. Take a look at
+the @file{config.log} file. It should contain the exact reason why your c++
+compiler didn't work! To work around these problems, you can use @code{gcc}
+as your C++ compiler. Try setting the environment variable @code{CXX} to
+@code{"gcc -O3"}. For example:
+
+@tindex CXX environment variable
+@tindex Environment variables, CXX
+@example
+shell> CXX="gcc -O3" ./configure
+@end example
+
+This works because @code{gcc} compiles C++ sources as well as @code{g++}
+does, but does not link in @code{libg++} or @code{libstdc++} by default.
+
+Another way to fix these problems, of course, is to install @code{g++},
+@code{libg++} and @code{libstdc++}.
+
+@item
+If your compile fails with errors such as any of the following,
+you must upgrade your version of @code{make} to GNU @code{make}:
+
+@example
+making all in mit-pthreads
+make: Fatal error in reader: Makefile, line 18:
+Badly formed macro assignment
+ or
+make: file `Makefile' line 18: Must be a separator (:
+ or
+pthread.h: No such file or directory
+@end example
+
+@cindex Solaris troubleshooting
+@cindex FreeBSD troubleshooting
+@cindex Troubleshooting, Solaris
+@cindex Troubleshooting, FreeBSD
+Solaris and FreeBSD are known to have troublesome @code{make} programs.
+
+GNU @code{make} version 3.75 is known to work.
+
+@tindex CC environment variable
+@tindex Environment variable, CC
+@tindex CXX environment variable
+@tindex Environment variable, CXX
+@tindex CFLAGS environment variable
+@tindex Environment variable, CFLAGS
+@tindex CXXFLAGS environment variable
+@tindex Environment variable, CXXFLAGS
+@item
+If you want to define flags to be used by your C or C++ compilers, do so by
+adding the flags to the @code{CFLAGS} and @code{CXXFLAGS} environment
+variables. You can also specify the compiler names this way using @code{CC}
+and @code{CXX}. For example:
+
+@example
+shell> CC=gcc
+shell> CFLAGS=-O6
+shell> CXX=gcc
+shell> CXXFLAGS=-O6
+shell> export CC CFLAGS CXX CXXFLAGS
+@end example
+
+See @ref{MySQL binaries}, for a list of flag definitions that have been found
+to be useful on various systems.
+
+@item
+If you get an error message like this,
+you need to upgrade your @code{gcc} compiler:
+
+@example
+client/libmysql.c:273: parse error before `__attribute__'
+@end example
+
+@code{gcc} 2.8.1 is known to work, but we recommend using @code{gcc} 2.95.2 or
+@code{egcs} 1.0.3a instead.
+
+@item
+If you get errors such as those shown below when compiling @code{mysqld},
+@code{configure} didn't correctly detect the type of the last argument to
+@code{accept()}, @code{getsockname()} or @code{getpeername()}:
+
+@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
+
+To fix this, edit the @file{config.h} file (which is generated by
+@code{configure}). Look for these lines:
+
+@example
+/* Define as the base type of the last arg to accept */
+#define SOCKET_SIZE_TYPE XXX
+@end example
+
+Change @code{XXX} to @code{size_t} or @code{int}, depending on your
+operating system. (Note that you will have to do this each time you run
+@code{configure}, because @code{configure} regenerates @file{config.h}.)
+
+@item
+The @file{sql_yacc.cc} file is generated from @file{sql_yacc.yy}. Normally
+the build process doesn't need to create @file{sql_yacc.cc}, because
+@strong{MySQL} comes with an already-generated copy. However, if you do need
+to recreate it, you might encounter this error:
+
+@example
+"sql_yacc.yy", line xxx fatal: default action causes potential...
+@end example
+
+This is a sign that your version of @code{yacc} is deficient.
+You probably need to install @code{bison} (the GNU version of @code{yacc})
+and use that instead.
+
+@item
+If you need to debug @code{mysqld} or a @strong{MySQL} client, run
+@code{configure} with the @code{--with-debug} option, then recompile and
+link your clients with the new client library.
+@xref{Debugging client}.
+@end itemize
+
+@node MIT-pthreads, Perl support, Compilation problems, Installing
+@section MIT-pthreads notes
+
+This section describes some of the issues involved in using MIT-pthreads.
+
+Note that on Linux you should NOT use MIT-pthreads but install LinuxThreads!
+@xref{Linux}.
+
+If your system does not provide native thread support, you will need to
+build @strong{MySQL} using the MIT-pthreads package. This includes
+most FreeBSD systems, SunOS 4.x, Solaris 2.4 and earlier, and some others.
+@xref{Which OS}.
+
+@itemize @bullet
+@item
+On most systems, you can force MIT-pthreads to be used by running
+@code{configure} with the @code{--with-mit-threads} option:
+
+@example
+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.
+
+@item
+MIT-pthreads doesn't support the @code{AF_UNIX} protocol used to implement
+Unix sockets. This means that if you compile using MIT-pthreads, all
+connections must be made using TCP/IP (which is a little slower). If you
+find after building @strong{MySQL} that you cannot connect to the local
+server, it may be that your client is attempting to connect to
+@code{localhost} using a Unix socket as the default. Try making a TCP/IP
+connection with @code{mysql} by using a host option (@code{-h} or
+@code{--host}) to specify the local host name explicitly.
+
+@item
+The checks that determine whether or not to use MIT-pthreads occur only
+during the part of the configuration process that deals with the server
+code. If you have configured the distribution using @code{--without-server}
+to build only the client code, clients will not know whether or not
+MIT-pthreads is being used and will use Unix socket connections by default.
+Because Unix sockets do not work under MIT-pthreads, this means you will need
+to use @code{-h} or @code{--host} when you run client programs.
+
+@item
+When @strong{MySQL} is compiled using MIT-pthreads, system locking is
+disabled by default for performance reasons. You can tell the server to use
+system locking with the @code{--use-locking} option.
+
+@item
+Sometimes the pthread @code{bind()} command fails to bind to a socket without
+any error message (at least on Solaris). The result is that all connections
+to the server fail. For example:
+
+@example
+shell> mysqladmin version
+mysqladmin: connect to server at '' failed;
+error: 'Can't connect to mysql server on localhost (146)'
+@end example
+
+The solution to this is to kill the @code{mysqld} server and restart it.
+This has only happened to us when we have forced the server down and done
+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{mysqladmin
+--sleep}. You must wait for the @code{sleep()} call to terminate before the
+interrupt is served and the process stops.
+
+@item
+When linking you may receive warning messages like these (at least on
+Solaris); they can be ignored:
+
+@example
+ld: warning: symbol `_iob' has 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' has 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
+Some other warnings also can be ignored:
+
+@example
+implicit declaration of function `int strtoll(...)'
+implicit declaration of function `int strtoul(...)'
+@end example
+
+@item
+We haven't gotten @code{readline} to work with MIT-pthreads. (This isn't
+needed, but may be interesting for someone.)
+@end itemize
+
+@node Perl support, Source install system issues, MIT-pthreads, Installing
+@section Perl installation comments
+
+@menu
+* Perl installation:: Installing Perl on Unix
+* ActiveState Perl:: Installing ActiveState Perl on Win32
+* Win32 Perl:: Installing the @strong{MySQL} Perl distribution on Win32
+* 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 @strong{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 5.004 or later. The
+interface @emph{will not work} if you have an older version of Perl.
+
+@strong{MySQL} Perl support also requires that you've installed
+@strong{MySQL} client programming support. If you installed @strong{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 release 3.22.8, Perl support is distributed separately from the main
+@strong{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
+@strong{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 @strong{MySQL},
+particularly if you notice symptoms such as all your @code{DBI} scripts
+dumping core after you upgrade @strong{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, Win32 Perl, Perl installation, Perl support
+@subsection Installing ActiveState Perl on Win32
+
+To install the @strong{MySQL} @code{DBD} module with ActiveState Perl on
+Win32, you should do the following:
+
+@itemize @bullet
+@item Open a DOS shell.
+@item If required, set the HTTP_proxy variable. For example, you might try:
+@code{set HTTP_proxy=my.proxy.com:3128}
+@item Start the PPM program: @code{C:\perl\bin\ppm.pl}
+@item If you have not already done so, install @code{DBI}: @code{install DBI}
+@item If this succeeds, install @code{ftp://ftp.de.uu.net/pub/CPAN/authors/id/JWIED/DBD-mysql-1.2212.x86.ppd}
+@end itemize
+
+The above should work at least with ActiveState Perl 5.6.
+
+If you can't get the above to work, you should instead install the
+@strong{MyODBC} driver and connect to @strong{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 Win32 Perl, Perl support problems, ActiveState Perl, Perl support
+@subsection Installing the MySQL Perl distribution on Win32
+
+The @strong{MySQL} Perl distribution contains @code{DBI},
+@code{DBD:MySQL} and @code{DBD:ODBC}.
+
+@itemize @bullet
+@item Get the Perl distribution for Win32 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, , Win32 Perl, Perl support
+@subsection Problems using the Perl @code{DBI}/@code{DBD} interface
+
+If Perl reports that it can't find the @code{../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 @code{Linux} you can add the pathname of the directory where
+@code{libmysqlclient.so} is located to the @file{/etc/ld.so.conf} file.
+
+@item
+@tindex LD_RUN_PATH environment variable
+@tindex Environment variable, LD_RUN_PATH
+Add the pathname of the directory where @code{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 @strong{MySQL} aren't both
+compiled with @code{gcc}. In this case, you can solve the mismatch by
+compiling both with @code{gcc}.
+
+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 Source install system issues, Win32, Perl support, Installing
+@section System-specific issues
+
+The following sections indicate some of the issues that have been observed to
+occur on particular systems when installing @strong{MySQL} from a source
+distribution.
+
+@menu
+* Solaris:: Solaris notes
+* Solaris 2.7:: Solaris 2.7 / 2.8 notes
+* Solaris x86:: Solaris x86 notes
+* SunOS:: SunOS 4 notes
+* Linux:: Linux notes (all Linux versions)
+* Alpha-DEC-Unix:: Alpha-DEC-Unix notes
+* Alpha-DEC-OSF1:: Alpha-DEC-OSF1 notes
+* SGI-Irix:: SGI-Irix notes
+* FreeBSD:: FreeBSD notes
+* NetBSD:: NetBSD notes
+* OpenBSD:: OpenBSD 2.5 notes
+* BSDI:: BSD/OS notes
+* SCO:: SCO notes
+* SCO Unixware:: SCO Unixware 7.0 notes
+* IBM-AIX:: IBM-AIX notes
+* HP-UX 10.20:: HP-UX 10.20 notes
+* HP-UX 11.x:: HP-UX 11.x notes
+* MacOSX:: MacOSX notes
+@end menu
+
+@node Solaris, Solaris 2.7, Source install system issues, Source install system issues
+@subsection Solaris notes
+
+On Solaris, you may run into trouble even before you get the @strong{MySQL}
+distribution unpacked! Solaris @code{tar} can't handle long file names, so
+you may see an error like this when you unpack @strong{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
+tar: directory checksum error
+@end example
+
+In this case, you must use GNU @code{tar} (@code{gtar}) to unpack the
+distribution. You can find a precompiled copy for Solaris at
+@uref{http://www.mysql.com/Downloads/}.
+
+Sun native threads work only on Solaris 2.5 and higher. For 2.4 and
+earlier versions, @strong{MySQL} will automatically use
+MIT-pthreads. @xref{MIT-pthreads}.
+
+If you get the following error from configure:
+
+@example
+checking for restartable system calls... configure: error can not run test
+programs while cross compiling
+@end example
+
+This means that you have something wrong with your compiler installation!
+In this case you should upgrade your compiler to a newer version. You may
+also be able to solve this problem by inserting the following row into the
+@code{config.cache} file:
+
+@example
+ac_cv_sys_restartable_syscalls=$@{ac_cv_sys_restartable_syscalls='no'@}
+@end example
+
+If you are using Solaris on a SPARC, the recommended compiler is
+@code{gcc} 2.95.2. You can find this at @uref{http://gcc.gnu.org/}.
+Note that @code{egs} 1.1.1 and @code{gcc} 2.8.1 don't work reliably on
+SPARC!
+
+The recommended @code{configure} line when using @code{gcc} 2.95.2 is:
+
+@example
+shell> CC=gcc CFLAGS="-O6" \
+ CXX=gcc CXXFLAGS="-O6 -felide-constructors -fno-exceptions -fno-rtti" \
+ ./configure --prefix=/usr/local/mysql --with-low-memory
+@end example
+
+If you have the Sun Workshop 4.2 compiler, you can run @code{configure} like
+this:
+
+CC=cc CFLAGS="-xstrconst -Xa -xO4 -native -mt" CXX=CC CXXFLAGS="-xO4 -native -noex -mt" ./configure --prefix=/usr/local/mysql
+
+@example
+shell> CC=cc CFLAGS="-Xa -fast -xO4 -native -xstrconst -mt" \
+ CXX=CC CXXFLAGS="-noex -XO4 -mt" \
+ ./configure
+@end example
+
+You may also have to edit the @code{configure} script to change this line:
+
+@example
+#if !defined(__STDC__) || __STDC__ != 1
+@end example
+
+to this:
+
+@example
+#if !defined(__STDC__)
+@end example
+
+If you turn on @code{__STDC__} with the @code{-Xc} option, the Sun compiler
+can't compile with the Solaris @file{pthread.h} header file. This is a Sun
+bug (broken compiler or broken include file).
+
+If @code{mysqld} issues the error message shown below when you run it, you have
+tried to compile @strong{MySQL} with the Sun compiler without enabling the
+multi-thread option (@code{-mt}):
+
+@example
+libc internal error: _rmutex_unlock: rmutex not held
+@end example
+
+Add @code{-mt} to @code{CFLAGS} and @code{CXXFLAGS} and try again.
+
+If you get the following error when compiling @strong{MySQL} with @code{gcc},
+it means that your @code{gcc} is not configured for your version of Solaris!
+
+@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
+
+The proper thing to do in this case is to get the newest version of
+@code{gcc} and compile it with your current @code{gcc} compiler! At
+least for Solaris 2.5, almost all binary versions of @code{gcc} have
+old, unusable include files that will break all programs that use
+threads (and possibly other programs)!
+
+Solaris doesn't provide static versions of all system libraries
+(@code{libpthreads} and @code{libdl}), so you can't compile @strong{MySQL}
+with @code{--static}. If you try to do so, you will get the error:
+
+@example
+ld: fatal: library -ldl: not found
+@end example
+
+If too many processes try to connect very rapidly to @code{mysqld}, you will
+see this error in the @strong{MySQL} log:
+
+@example
+Error in accept: Protocol error
+@end example
+
+You might try starting the server with the @code{--set-variable back_log=50}
+option as a workaround for this. @xref{Command-line options}.
+
+If you are linking your own @strong{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
+@end example
+
+The problem can be avoided by one of the following methods:
+
+@itemize @bullet
+@item
+Link the client with the following flag (instead of @code{-Lpath}):
+@code{-Wl,r/full-path-to-libmysqlclient.so}.
+@item
+Copy @code{libmysqclient.so} to @file{/usr/lib}.
+@item
+@tindex LD_RUN_PATH environment variable
+@tindex Environment variable, LD_RUN_PATH
+Add the pathname of the directory where @code{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 @code{libwrap.a} needs:
+
+@example
+--with-libwrap="/opt/NUtcpwrapper-7.6/lib/libwrap.a -lnsl -lsocket
+@end example
+
+If you have problems with that configure or @strong{MySQL} tries to link
+with @code{-lz} and you don't have this installed, you have two options:
+
+@itemize @bullet
+@item
+If you want to be able to use the compressed communication protocol,
+you need to get and install zlib from ftp.gnu.org.
+@item
+Configure with @code{--with-named-z-libs=no}
+@end itemize
+
+If you are using gcc and have problems with loading @code{UDF} functions
+into @code{MySQL}, try adding @code{-lgcc} to the link line for the
+@code{UDF} function.
+
+@node Solaris 2.7, Solaris x86, Solaris, Source install system issues
+@subsection Solaris 2.7 / 2.8 notes
+
+You can normally use a Solaris 2.6 binary on Solaris 2.7 and 2.8. Most
+of the Solaris 2.6 issues also apply for Solaris 2.7 and 2.8.
+
+Note that @strong{MySQL} 3.23.4 and above should be able to autodetect
+new versions of Solaris and enable workarounds for the following
+problems!
+
+Solaris 2.7 / 2.8 has some bugs in the include files. You may see the
+following error when you use @code{gcc}:
+
+@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
+
+If this occurs, you can do the following to fix the problem:
+
+Copy @code{/usr/include/widec.h} to
+@code{.../lib/gcc-lib/os/gcc-version/include} and change line 41 from:
+
+@example
+#if !defined(lint) && !defined(__lint)
+
+to
+
+#if !defined(lint) && !defined(__lint) && !defined(getwc)
+@end example
+
+Alternatively, you can edit @file{/usr/include/widec.h} directly. Either
+way, after you make the fix, you should remove @file{config.cache} and run
+@code{configure} again!
+
+If you get errors like this when you run @code{make}, it's because @code{configure}
+didn't detect the @file{curses.h} file (probably because of the error in
+@code{/usr/include/widec.h}:
+
+@example
+In file included from mysql.cc:50:
+/usr/include/term.h:1060: syntax error before `,'
+/usr/include/term.h:1081: syntax error before `;'
+@end example
+
+The solution to this is to do one of the following steps:
+
+@itemize @bullet
+@item
+Edit @file{/usr/include/widec.h} as indicted above and rerun configure
+@item
+Remove the @code{#define HAVE_TERM} line from @file{config.h} file and
+run @code{make} again.
+@item
+Configure with @code{CFLAGS=-DHAVE_CURSES CXXFLAGS=-DHAVE_CURSES ./configure}
+@end itemize
+
+@node Solaris x86, SunOS, Solaris 2.7, Source install system issues
+@subsection Solaris x86 notes
+
+If you are using @code{gcc} or @code{egcs} on Solaris x86 and you
+experience problems with core dumps under load, you should use the
+following @code{configure} command:
+
+@example
+shell> CC=gcc CFLAGS="-O6 -fomit-frame-pointer" \
+ CXX=gcc \
+ CXXFLAGS="-O6 -fomit-frame-pointer -felide-constructors -fno-exceptions -fno-rtti" \
+ ./configure --prefix=/usr/local/mysql
+@end example
+
+This will avoid problems with the @code{libstdc++} library and with C++
+exceptions.
+
+If this doesn't help, you should compile a debug version and run
+it with a trace file or under @code{gdb}. @xref{Debugging server}.
+
+@node SunOS, Linux, Solaris x86, Source install system issues
+@subsection SunOS 4 notes
+
+On SunOS 4, MIT-pthreads is needed to compile @strong{MySQL}, which in turn
+means you will need GNU @code{make}.
+
+Some SunOS 4 systems have problems with dynamic libraries and
+@code{libtool}. You can use the following @code{configure} line to avoid
+this problem:
+
+@example
+shell> ./configure --disable-shared --with-mysqld-ldflags=-all-static
+@end example
+
+When compiling @code{readline}, you may get warnings about duplicate defines.
+These may be ignored.
+
+When compiling @code{mysqld}, there will be some @code{implicit declaration
+of function} warnings. These may be ignored.
+
+@node Linux, Alpha-DEC-Unix, SunOS, Source install system issues
+@subsection Linux notes (all Linux versions)
+
+@strong{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
+@strong{MySQL}. @uref{http://www.mysql.com/Downloads/Linux}
+
+Note that @code{glibc} versions before and including 2.1.1 has a fatal
+bug in @code{pthread_mutex_timedwait} handling, which is used when you
+do @code{INSERT DELAYED}. If you are using @code{INSERT DELAYED}, you
+@strong{MUST} add the following patch to your glibc library:
+@uref{http://www.mysql.com/Downloads/Patches/glibc-pthread_cond_timedwait.patch}.
+@strong{MySQL} 3.23.7 and the @strong{MySQL} 3.22.32 contains a
+temporary workaround for this bug.
+
+If you plan to have 1000+ concurrent connections, you will need to make
+some changes to LinuxThreads, recompile it, and re-link MySQL against
+the new libpthread.a . Increase PTHREAD_THREADS_MAX in
+sysdeps/unix/sysv/linux/bits/local_lim.h to 4096 and decrease STACK_SIZE
+in internals.h to 256 KB . Note that MySQL will not be stable with
+around 1000 connections if STACK_SIZE is the default of 2 MB.
+
+If you have glibc 2.1.3-65 or newer, you don't have to increase STACK_SIZE;
+You can instead just change the @code{thread_stack} value for @code{mysqld}.
+
+If you use a lot of concurrent connections, you may suffer from a 2.2
+kernel "feature" that penalizes 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
+creation - which means it may take a long time to connect to MySQL ( as
+long as 1 minute), and it may take just as long to shut it down. On
+multiple CPU systems, we have observed a gradual drop in query speed as
+the number of clients increases. In the process of trying to find a
+solution, we have received a kernel patch from one of our users, who
+claimed it made a lot of difference for his site. We have done some
+limited testing in which the patch greatly improved the scalabitility of
+MySQL. The patch is available
+@uref{http://www.mysql.com/Downloads/Patches/linux-fork.patch,here} - be
+warned, though, that we assume no reponsibility for any damage that this
+patch could do - use at your own risk. We have also been told by the
+Linux kernel developers that this problem is fixed in 2.4, although we
+have not yet done any testing.
+
+If you can't start @code{mysqld} or if @code{mysql_install_db} doesn't work,
+please continue reading! This only happens on Linux system with problems in
+the LinuxThreads or @code{libc}/@code{glibc} libraries. There are a lot of
+simple workarounds to get @strong{MySQL} to work! The simplest is to use the
+binary version of @strong{MySQL} (not the RPM) for Linux x86. One nice
+aspect of this version is that it's probably 10% faster than any version you
+would compile yourself! @xref{Compile and link options}.
+
+One known problem with the binary distribution is that with older Linux
+systems that use @code{libc} (like RedHat 4.x or Slackware), you will get
+some non-fatal problems with hostname resolution
+@xref{Binary notes-Linux}.
+
+@code{myisamchk} hangs with @code{libc.so.5.3.12}. Upgrading to the newest
+@code{libc} fixes this problem.
+
+When using LinuxThreads you will see a minimum of three processes
+running. These are in fact threads. There will be one thread for the
+LinuxThreads manager, one thread to handle connections, and one thread
+to handle alarms and signals.
+
+Note that the linux kernel and the linuxthread library can by default
+only have 1024 threads. This means that you can only have up to 1021
+connections to MySQL on a unpatched system. The page
+@uref{http://www.volano.com/linuxnotes.html} contains information how to
+go around this limit.
+
+If you see a dead @code{mysqld} daemon process with @code{ps}, this usually
+means that you have found a bug in @strong{MySQL} or you have got a corrupted
+table. @xref{Crashing}.
+
+If you are using LinuxThreads and @code{mysqladmin shutdown} doesn't work,
+you must upgrade to LinuxThreads 0.7.1 or newer.
+
+If you are using RedHat, you might get errors like this:
+
+@example
+/usr/bin/perl is needed...
+/usr/sh is needed...
+/usr/sh is needed...
+@end example
+
+If so, you should upgrade your version of @code{rpm} to
+@file{rpm-2.4.11-1.i386.rpm} and @file{rpm-devel-2.4.11-1.i386.rpm} (or later).
+
+You can get the upgrades of libraries to RedHat 4.2 from
+@uref{ftp://ftp.redhat.com/updates/4.2/i386}. Or
+@uref{http://www.sunsite.unc.edu/pub/Linux/distributions/redhat/code/rpm/}
+for other distributions.
+
+If you are linking your own @strong{MySQL} client and get the error:
+
+@example
+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
+methods:
+
+@itemize @bullet
+@item
+Link the client with the following flag (instead of @code{-Lpath}):
+@code{-Wl,r/path-libmysqlclient.so}.
+@item
+Copy @code{libmysqclient.so} to @file{/usr/lib}.
+@item
+@tindex LD_RUN_PATH environment variable
+@tindex Environment variable, LD_RUN_PATH
+Add the pathname of the directory where @code{libmysqlclient.so} is located
+to the @code{LD_RUN_PATH} environment variable before running your client.
+@end itemize
+
+If you are using the Fujitsu compiler @code{(fcc / FCC)} you will have
+some problems compiling @strong{MySQL} because the Linux header files are very
+@code{gcc} oriented.
+
+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
+@end example
+
+@menu
+* Linux-x86:: Linux-x86 notes
+* Linux-RedHat50:: RedHat 5.0 notes
+* Linux-RedHat51:: RedHat 5.1 notes
+* Linux-SPARC:: Linux-SPARC notes
+* Linux-Alpha:: Linux-Alpha notes
+* MKLinux:: MkLinux notes
+* Qube2:: Qube2 Linux notes
+* Linux-Ia64::
+@end menu
+
+@node Linux-x86, Linux-RedHat50, Linux, Linux
+@subsubsection Linux-x86 notes
+
+@strong{MySQL} requires @code{libc} version 5.4.12 or newer. It's known to
+work with @code{libc} 5.4.46. @code{glibc} version 2.0.6 and later should
+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.
+
+On some older Linux distributions, @code{configure} may produce an error
+like this:
+
+@example
+Syntax error in sched.h. Change _P to __P in the /usr/include/sched.h file.
+See the Installation chapter in the Reference Manual.
+@end example
+
+Just do what the error message says and add an extra underscore to the
+@code{_P} macro that has only one underscore, then try again.
+
+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: 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, if you want @strong{MySQL} to start automatically when
+the system boots, do the following:
+
+@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} can be found in the @file{share/mysql} directory
+under the @strong{MySQL} installation directory, or in the
+@file{support-files} directory of the @strong{MySQL} source tree.
+
+If @code{mysqld} always core dumps when it starts up, the problem may be that
+you have an old @file{/lib/libc.a}. Try renaming it, then remove
+@file{sql/mysqld} and do a new @code{make install} and try again. This
+problem has been reported on some Slackware installations. RedHat 5.0 has
+also a similar problem with some new @code{glibc} versions.
+@xref{Linux-RedHat50}.
+
+If you get the following error when linking @code{mysqld},
+it means that your @file{libg++.a} is not installed correctly:
+
+@example
+/usr/lib/libc.a(putc.o): In function `_IO_putc':
+putc.o(.text+0x0): multiple definition of `_IO_putc'
+@end example
+
+You can avoid using @file{libg++.a} by running @code{configure} like this:
+
+@example
+shell> CXX=gcc ./configure
+@end example
+
+@node Linux-RedHat50, Linux-RedHat51, Linux-x86, Linux
+@subsubsection RedHat 5.0 notes
+
+If you have any problems with @strong{MySQL} on RedHat, you should start by
+upgrading @code{glibc} to the newest possible version!
+
+If you install all the official RedHat patches (including
+@code{glibc-2.0.7-19} and @code{glibc-devel-2.0.7-19}), both the
+binary and source distributions of @strong{MySQL} should work without
+any trouble!
+
+The updates are needed because there is a bug in @code{glibc} 2.0.5 in how
+@code{pthread_key_create} variables are freed. With @code{glibc} 2.0.5, you
+must use a statically-linked @strong{MySQL} binary distribution. If you
+want to compile from source, you must install the corrected version of
+LinuxThreads from @uref{http://www.mysql.com/Downloads/Linux} or upgrade your
+@code{glibc}.
+
+If you have an incorrect version of @code{glibc} or LinuxThreads, the symptom
+is that @code{mysqld} crashes after each connection. For example,
+@code{mysqladmin version} will crash @code{mysqld} when it finishes!
+
+Another symptom of incorrect libraries is that @code{mysqld} crashes at
+once when it starts. On some Linux systems, this can be fixed by configuring
+like this:
+
+@example
+shell> ./configure --with-mysqld-ldflags=-all-static
+@end example
+
+On Redhat 5.0, the easy way out is to install the @code{glibc} 2.0.7-19 RPM
+and run @code{configure} @strong{without} the
+@code{--with-mysqld-ldflags=-all-static} option.
+
+For the source distribution of @code{glibc} 2.0.7, a patch that is easy to
+apply and is tested with @strong{MySQL} may be found at:
+@example
+@uref{http://www.mysql.com/Download/Linux/glibc-2.0.7-total-patch.tar.gz}
+@end example
+
+If you experience crashes like these when you build @strong{MySQL}, you can
+always download the newest binary version of @strong{MySQL}. This is
+statically-linked to avoid library conflicts and should work on all Linux
+systems!
+
+@strong{MySQL} comes with an internal debugger that can generate
+trace files with a lot of information that can be used to find and solve a
+wide range of different problems.
+@xref{Debugging server}.
+
+@node Linux-RedHat51, Linux-SPARC, Linux-RedHat50, Linux
+@subsubsection RedHat 5.1 notes
+
+The @code{glibc} of RedHat 5.1 (@code{glibc} 2.0.7-13) has a memory leak, so
+to get a stable @strong{MySQL} version, you must upgrade @code{glibc} to
+2.0.7-19, downgrade @code{glibc} or use a binary version of @code{mysqld}. If
+you don't do this, you will encounter memory problems (out of memory, etc.,
+etc.). The most common error in this case is:
+
+@example
+Can't create a new thread (errno 11). If you are not out of available
+memory, you can consult the manual for any possible OS dependent bug
+@end example
+
+After you have upgraded to @code{glibc} 2.0.7-19, you can configure
+@strong{MySQL} with dynamic linking (the default), but you @strong{cannot}
+run @code{configure} with the @code{--with-mysqld-ldflags=-all-static} option
+until you have installed @code{glibc} 2.0.7-19 from source!
+
+You can check which version of @code{glibc} you have with @code{rpm -q glibc}.
+
+@node Linux-SPARC, Linux-Alpha, Linux-RedHat51, 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 before compiling.
+
+Some problems will require patching your Linux installation. The patch can
+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 0.6 or newer.
+
+Thanks to @email{jacques@@solucorp.qc.ca} for this information.
+
+@node Linux-Alpha, MKLinux, Linux-SPARC, Linux
+@subsubsection Linux-Alpha notes
+
+@strong{MySQL} 3.23.12 is the first @strong{MySQL} version that is
+tested on Linux-Alpha. If you plan to use @strong{MySQL} on
+Linux-Alpha, you should ensure that you have this version or newer.
+
+We have tested @strong{MySQL} on Alpha with our benchmarks + test suite and
+it appears to work nicely. The main thing we haven't yet had time to test
+is how things works with many concurrent users.
+
+When we compiled @strong{MySQL} we where using SuSE 6.3, kernel 2.2.13-SMP,
+egcs 1.1.2 and libc-2.1.2-28.
+
+We used the following configure line:
+
+@example
+CFLAGS="-O6 -fomit-frame-pointer" CXX=gcc CXXFLAGS="-O6 -fomit-frame-pointer -felide-constructors -fno-exceptions -fno-rtti" ./configure --prefix=/usr/local/mysql --disable-shared
+@end example
+
+If you have access to Compaq's C compiler, the following configure line
+will give you about 9 % more performance:
+@example
+CC=ccc CFLAGS="-fast -O3 -fomit-frame-pointer" CXX=gcc CXXFLAGS="-O6 -fomit-frame-pointer -felide-constructors -fno-exceptions -fno-rtti -mcpu=ev6 -Wa,-mev6" CXXLDFLAGS='/usr/lib/compaq/libots-2.2.7/libots.so /usr/lib/compaq/cpml-5.0.0/libcpml_ev6.a' ./configure --prefix=/usr/local/mysql --disable-shared
+@end example
+
+Note that the last example assumes your are using an Alpha EV6 processor.
+
+Some known problems when running @strong{MySQL} on Linux-Alpha:
+
+@itemize @bullet
+@item
+If you create many files ( > 10000) in one directory (as done by the
+@code{test-create} in the @strong{MySQL} benchmarks, mysqld may report
+the error @code{Can't create/write to file '...' (Errcode: 12)}. This
+is probably a bug in the Linux-Alpha kernel.
+@item
+Debugging threaded applications like @strong{MySQL} will not work with
+@code{gdb 4.18}. You should download and use gdb 5.0 instead!
+@item
+If you try linking mysqld staticly, the resulting image will core dump
+at start. In other words, @strong{DON'T} use
+@code{--with-mysqld-ldflags=-all-static}
+@end itemize
+
+We don't yet know if the following old information is still relevant, so we
+leave this here until we have had time to test Linux-Alpha properly.
+
+If you have problems with signals (@strong{MySQL} dies unexpectedly
+under high load) you may have found an OS bug with threads and
+signals. In this case you can tell @strong{MySQL} not to use signals by
+configuring with:
+
+@example
+shell> CFLAGS=-DDONT_USE_THR_ALARM \
+ CXXFLAGS=-DDONT_USE_THR_ALARM \
+ ./configure ...
+@end example
+
+This doesn't affect the performance of @strong{MySQL}, but has the side
+effect that you can't kill clients that are ``sleeping'' on a connection with
+@code{mysqladmin kill} or @code{mysqladmin shutdown}. Instead, the client
+will die when it issues its next command.
+
+@node MKLinux, Qube2, Linux-Alpha, Linux
+@subsubsection MkLinux notes
+
+@strong{MySQL} should work on MkLinux with the newest @code{glibc} package
+(tested with @code{glibc} 2.0.7).
+
+@node Qube2, Linux-Ia64, MKLinux, Linux
+@subsubsection Qube2 Linux notes
+
+To get @strong{MySQL} to work on Qube2, (Linux Mips), you need the
+newest @code{glibc} libraries (@code{glibc-2.0.7-29C2} is known to
+work). You must also use the @code{egcs} C++ compiler
+(@code{egcs-1.0.2-9}, @code{gcc 2.95.2} or newer).
+
+
+@node Linux-Ia64, , Qube2, Linux
+@subsubsection Linux Ia64 notes
+
+To get @code{MySQL} to compile on Linux Ia64, we had to do the following
+(we assume that this will be easier when next gcc version for ia64 is
+released).
+
+Using @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
+
+After this you have to edit @file{config.h} and remove the
+@code{HAVE_ATOMIC_ADD} line.
+
+After @code{make} you will get an error that @code{sql/opt_range.cc}
+will not compile (internal compiler error). To fix this, go to the sql
+directory and type @code{make} again. Copy the compile line, but change
+-O2 to -O0. The file should now compile.
+
+Now you can do:
+@example
+cd ..
+make
+make_install
+@end example
+
+and @strong{mysqld} should be ready to run.
+
+@node Alpha-DEC-Unix, Alpha-DEC-OSF1, Linux, Source install system issues
+@subsection Alpha-DEC-Unix notes
+
+When compiling threaded programs under Digital UNIX, the documentation
+recommends using the @code{-pthread} option for @code{cc} and @code{cxx} and
+the libraries @code{-lmach -lexc} (in addition to @code{-lpthread}). You
+should run @code{configure} something like this:
+
+@example
+shell> CC="cc -pthread" CXX="cxx -pthread -O" \
+ ./configure --with-named-thread-libs="-lpthread -lmach -lexc -lc"
+@end example
+
+When compiling @code{mysqld}, you may see a couple of warnings like this:
+
+@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
+
+You can safely ignore these warnings. They occur because @code{configure}
+can detect only errors, not warnings.
+
+If you start the server directly from the command line, you may have problems
+with it dying when you log out. (When you log out, your outstanding processes
+receive a @code{SIGHUP} signal.) If so, try starting the server like this:
+
+@example
+shell> nohup mysqld [options] &
+@end example
+
+@code{nohup} causes the command following it to ignore any @code{SIGHUP}
+signal sent from the terminal. Alternatively, start the server by running
+@code{safe_mysqld}, which invokes @code{mysqld} using @code{nohup} for you.
+
+@node Alpha-DEC-OSF1, SGI-Irix, Alpha-DEC-Unix, Source install system issues
+@subsection Alpha-DEC-OSF1 notes
+
+If you have problems compiling and have DEC @code{CC} and @code{gcc}
+installed, try running @code{configure} like this:
+
+@example
+shell> CC=cc CFLAGS=-O CXX=gcc CXXFLAGS=-O3 \
+ ./configure --prefix=/usr/local/mysql
+@end example
+
+If you get problems with the @file{c_asm.h} file, you can create and use
+a 'dummy' @file{c_asm.h} file with:
+
+@example
+shell> touch include/c_asm.h
+shell> CC=gcc CFLAGS=-I./include \
+ CXX=gcc CXXFLAGS=-O3 \
+ ./configure --prefix=/usr/local/mysql
+@end example
+
+Note that the following problems with the @code{ld} program can be fixed
+by downloading the latest DEC (Compaq) patch kit from:
+@uref{http://ftp.support.compaq.com/public/unix/}.
+
+On OSF1 V4.0D and compiler "DEC C V5.6-071 on Digital UNIX V4.0 (Rev. 878)"
+the compiler had some strange behavior (undefined @code{asm} symbols).
+@code{/bin/ld} also appears to be broken (problems with @code{_exit
+undefined} errors occuring while linking @code{mysqld}). On this system, we
+have managed to compile @strong{MySQL} with the following @code{configure}
+line, after replacing @code{/bin/ld} with the version from OSF 4.0C:
+
+@example
+shell> CC=gcc CXX=gcc CXXFLAGS=-O3 ./configure --prefix=/usr/local/mysql
+@end example
+
+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
+CXX=cxx -pthread
+CXXFLAGS=-O4 -ansi_alias -ansi_args -fast -inline speed -speculate all -arch host
+export CC CFLAGS CXX CXXFLAGS
+./configure --prefix=/usr/mysql/mysql --with-low-memory --enable-large-files --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
+this by removing the line in @file{config.h} that defines @code{'HAVE_ALLOCA'}.
+
+The @code{alloca()} function also may have an incorrect prototype in
+@code{/usr/include/alloca.h}. This warning resulting from this can be ignored.
+
+@code{configure} will use the following thread libraries automatically:
+@code{--with-named-thread-libs="-lpthread -lmach -lexc -lc"}.
+
+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 ....
+@end example
+
+If you have problems with signals (@strong{MySQL} dies unexpectedly
+under high load) you may have found an OS bug with threads and
+signals. In this case you can tell @strong{MySQL} not to use signals by
+configuring with:
+
+@example
+shell> CFLAGS=-DDONT_USE_THR_ALARM \
+ CXXFLAGS=-DDONT_USE_THR_ALARM \
+ ./configure ...
+@end example
+
+This doesn't affect the performance of @strong{MySQL}, but has the side
+effect that you can't kill clients that are ``sleeping'' on a connection with
+@code{mysqladmin kill} or @code{mysqladmin shutdown}. Instead, the client
+will die when it issues its next command.
+
+With @code{gcc} 2.95.2, you will probably run into the following compile error:
+
+@example
+sql_acl.cc:1456: Internal compiler error in `scan_region', at except.c:2566
+Please submit a full bug report.
+@end example
+
+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 can just change back to
+the top level directly and run @code{make} again.
+
+@node SGI-Irix, FreeBSD, Alpha-DEC-OSF1, Source install system issues
+@subsection SGI-Irix notes
+
+If you are using Irix 6.5.3 or newer @code{mysqld} will only be able to
+create threads if you run it as a user with @code{CAP_SCHED_MGT}
+privileges (like @code{root}) or give the @code{mysqld} server this privilege
+with the following shell command:
+
+@example
+shell> chcap "CAP_SCHED_MGT+epi" /opt/mysql/libexec/mysqld
+@end example
+
+You may have to undefine some things in @file{config.h} after running
+@code{configure} and before compiling.
+
+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 @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
+
+At the very minimum, you should install the latest kernel rollup, the
+latest @code{rld} rollup, and the latest @code{libc} rollup.
+
+You definately need all the POSIX patches on this page, for pthreads support:
+
+http://support.sgi.com/surfzone/patches/patchset/6.2_posix.rps.html
+
+If you get the something like the following error when compiling
+@file{mysql.cc}:
+
+@example
+"/usr/include/curses.h", line 82: error(1084): invalid combination of type
+@end example
+
+Then type the following in the top-level directory of your @strong{MySQL}
+source tree:
+
+@example
+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 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.
+
+If you are compiling with @code{gcc}, you can use the following
+@code{configure} command:
+
+@example
+shell> CC=gcc CXX=gcc CXXFLAGS=-O3 \
+ ./configure --prefix=/usr/local/mysql --with-thread-safe-client --with-named-thread-libs=-lpthread
+@end example
+
+@node FreeBSD, NetBSD, SGI-Irix, Source install system issues
+@subsection FreeBSD notes
+
+FreeBSD 3.x is recommended for running @strong{MySQL} since it 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}
+
+Using these gives you:
+@itemize @bullet
+@item
+A working @strong{MySQL} with all optimizations known to work on your version
+of FreeBSD enabled.
+@item
+Automatic configuration and build.
+@item
+Startup scripts installed in /usr/local/etc/rc.d
+@item
+Ability to see which files that are installed with pkg_info -L. And to
+remove them all with pkg_delete if you no longer want @strong{MySQL} on that
+machine.
+@end itemize
+
+It is recomended to use MIT-pthreads on FreeBSD 2.x and native threads on
+versions 3 and up. It is possible to run with with native threads on some late
+2.2.x versions but you may encounter problems shutting down mysqld.
+
+Be sure to have your name resolver setup correct. Otherwise you may
+experience resolver delays or failures when connecting to mysqld.
+
+Make sure that the @code{localhost} entry in the @file{/etc/hosts} file is
+correct (otherwise you will have problems connecting to the database). The
+@file{/etc/hosts} file should start with a line:
+
+@example
+127.0.0.1 localhost localhost.your.domain
+@end example
+
+If you notice that @code{configure} will use MIT-pthreads, you should read
+the MIT-pthreads notes. @xref{MIT-pthreads}.
+
+If you get an error from @code{make install} that it can't find
+@file{/usr/include/pthreads}, @code{configure} didn't detect that you need
+MIT-pthreads. This is fixed by executing these commands:
+
+@example
+shell> rm config.cache
+shell> ./configure --with-mit-threads
+@end example
+
+The behavior of FreeBSD @code{make} is slightly different from that of GNU
+@code{make}. If you have @code{make}-related problems, you should install GNU
+@code{make}.
+
+FreeBSD is also known to have a very low default file handle limit.
+@xref{Not enough file handles}. Uncomment the ulimit -n section in
+safe_mysqld or raise the limits for the mysqld user in /etc/login.conf
+(and rebuild it witg cap_mkdb /etc/login.conf) also be sure you set the
+appropriate Class for this user in the password file if you are not
+using the default (use: chpass mysqld-user-name)
+
+If you get problems with the current date in @strong{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}
+
+@node NetBSD, OpenBSD, FreeBSD, Source install system issues
+@subsection NetBSD notes
+
+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, BSDI, NetBSD, Source install system issues
+@subsection OpenBSD 2.5 notes
+
+On OpenBSD 2.5, you can compile @strong{MySQL} with native threads with the
+following options:
+
+@example
+CFLAGS=-pthread CXXFLAGS=-pthread ./configure --with-mit-threads=no
+@end example
+
+@node BSDI, SCO, OpenBSD, Source install system issues
+@subsection BSD/OS notes
+
+@menu
+* BSDI2:: BSD/OS 2.x notes
+* BSDI3:: BSD/OS 3.x notes
+* BSDI4:: BSD/OS 4.x notes
+@end menu
+
+@node BSDI2, BSDI3, BSDI, BSDI
+@subsubsection BSD/OS 2.x notes
+
+If you get the following error when compiling @strong{MySQL}, your
+@code{ulimit} value for virtual memory is too low:
+
+@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
+
+Try using @code{ulimit -v 80000} and run @code{make} again. If this
+doesn't work and you are using @code{bash}, try switching to @code{csh}
+or @code{sh}; some BSDI users have reported problems with @code{bash}
+and @code{ulimit}.
+
+If you are using @code{gcc}, you may also use have to use the
+@code{--with-low-memory} flag for @code{configure} to be able to compile
+@file{sql_yacc.cc}.
+
+If you get problems with the current date in @strong{MySQL}, setting the
+@code{TZ} variable will probably help. @xref{Environment variables}.
+
+@node BSDI3, BSDI4, BSDI2, BSDI
+@subsubsection BSD/OS 3.x notes
+
+Upgrade to BSD/OS 3.1. If that is not possible, install BSDIpatch M300-038.
+
+Use the following command when configuring @strong{MySQL}:
+
+@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
+
+The following is also known to work:
+
+@example
+shell> env CC=gcc CXX=gcc CXXFLAGS=-O3 \
+ ./configure \
+ --prefix=/usr/local/mysql \
+ --with-unix-socket-path=/var/mysql/mysql.sock
+@end example
+
+You can change the directory locations if you wish, or just use the
+defaults by not specifying any locations.
+
+If you have problems with performance under heavy load, try using the
+@code{--skip-thread-priority} option to @code{safe_mysqld}! This will run
+all threads with the same priority; on BSDI 3.1, this gives better
+performance (at least until BSDI fixes their thread scheduler).
+
+If you get the error @code{virtual memory exhausted} while compiling,
+you should try using @code{ulimit -v 80000} and run @code{make} again.
+If this doesn't work and you are using @code{bash}, try switching to
+@code{csh} or @code{sh}; some BSDI users have reported problems with
+@code{bash} and @code{ulimit}.
+
+@node BSDI4, , BSDI3, BSDI
+@subsubsection BSD/OS 4.x notes
+
+BSDI 4.x has some thread related bugs. If you want to use @strong{MySQL}
+on this, you should install all thread related patches. At least
+M400-023 should be installed.
+
+On some BSDI 4.x systems, you may get problems with shared libraries. The
+symptom is that you can't execute any client programs, like for example
+@code{mysqladmin}. In this case you need to reconfigure not to use
+shared libraries with the @code{--disable-shared} option to configure.
+
+@node SCO, SCO Unixware, BSDI, Source install system issues
+@subsection 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
+port to ``sco 3.2v4.2''.
+
+For the moment the recommended compiler on OpenServer is gcc 2.95.2. With this
+you should be able to compile @code{MySQL} with just:
+
+@example
+CC=gcc CXX=gcc ./configure ... (options)
+@end example
+
+@enumerate
+@item
+For OpenServer 5.0.X you need to use GDS in Skunkware 95 (95q4c). This
+is necessary because GNU @code{gcc} 2.7.2 in Skunkware 97 does not have
+GNU @code{as}. You can also use @code{egcs} 1.1.2 or newer
+@uref{http://www.egcs.com/}. If you are using @code{egcs} 1.1.2 you have
+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/
+@end example
+@item
+You need the port of GCC 2.5.? for this product and the Development
+system. They are required on this version of SCO UNIX. You cannot
+just use the GCC Dev system.
+@item
+You should get the FSU Pthreads package and install it first. This can be
+found at
+@uref{http://www.cs.wustl.edu/~schmidt/ACE_wrappers/FSU-threads.tar.gz}.
+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
+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.? There are a lot of problems
+without a good port. The port for this product requires the SCO UNIX
+Development system. Without it, you are missing the libraries and the
+linker that is needed.
+@item
+To build FSU Pthreads on your system, do the following:
+@enumerate
+@item
+Run @code{./configure} in the @file{threads/src} directory and select
+the SCO OpenServer option. This command copies @file{Makefile.SCO5} to
+@file{Makefile}.
+@item
+Run @code{make}.
+@item
+To install in the default @file{/usr/include} directory, login as root,
+then @code{cd} to the @file{thread/src} directory, and run @code{make
+install}.
+@end enumerate
+@item
+Remember to use GNU @code{make} when making @strong{MySQL}.
+@item
+On OSR 5.0.5, you should use the following configure line:
+@example
+shell> CC="gcc -DSCO" CXX="gcc -DSCO" ./configure
+@end example
+The @code{-DSCO} is needed to help configure detect some thread
+functions properly. If you forget @code{-DSCO}, you will get the following
+error message while compiling:
+@example
+my_pthread.c: In function `my_pthread_mutex_init':
+my_pthread.c:374: `pthread_mutexattr_default' undeclared (first use this function)
+@end example
+@item
+If you don't start @code{safe_mysqld} as root, you probably will get only the
+default 110 open files per process. @code{mysqld} will write a note about this
+in the log file.
+@item
+With SCO 3.2V5.0.5, you should use FSU Pthreads version 3.5c or newer.
+The following @code{configure} command should work:
+@example
+shell> CC="gcc -belf" ./configure --prefix=/usr/local/mysql --disable-shared
+@end example
+@item
+With SCO 3.2V4.2, you should use FSU Pthreads version 3.5c or newer.
+The following @code{configure} command should work:
+@example
+shell> CFLAGS="-D_XOPEN_XPG4" CXX=gcc CXXFLAGS="-D_XOPEN_XPG4" \
+ ./configure \
+ --with-debug --prefix=/usr/local/mysql \
+ --with-named-thread-libs="-lgthreads -lsocket -lgen -lgthreads" \
+ --with-named-curses-libs="-lcurses"
+@end example
+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 @strong{MySQL} source tree.
+@end enumerate
+
+SCO development notes:
+
+@itemize @bullet
+@item
+@strong{MySQL} should automatically detect FSU Pthreads and link @code{mysqld}
+with @code{-lgthreads -lsocket -lgthreads}.
+@item
+The SCO development libraries are reentrant in FSU Pthreads. SCO claims
+that its libraries' functions are reentrant, so they must be reentrant with
+FSU Pthreads. FSU Pthreads on OpenServer tries to use the SCO scheme to
+make reentrant library.
+@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 @file{libgthreads.so}.
+@item
+In FSU Pthreads, the following system calls are pthreads-aware: @code{read()},
+@code{write()}, @code{getmsg()}, @code{connect()}, @code{accept()},
+@code{select()} and @code{wait()}.
+@end itemize
+
+If you want to install DBI on SCO, you have to edit the @file{Makefiles} in
+DBI-xxx and each subdirectory:
+
+@example
+OLD: NEW:
+CC = cc CC = gcc -belf
+CCCDLFLAGS = -KPIC -W1,-Bexport CCCDLFLAGS = -fpic
+CCDLFLAGS = -wl,-Bexport CCDLFLAGS =
+
+LD = ld LD = gcc -belf -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 -belf -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
+
+This is because the Perl dynaloader will not load the @code{DBI} modules
+if they were compiled with @code{icc} or @code{cc}.
+
+Perl works best when compiled with @code{cc}.
+
+@node SCO Unixware, IBM-AIX, SCO, Source install system issues
+@subsection SCO Unixware 7.0 notes
+
+You must use a version of @strong{MySQL} at least as recent as 3.22.13, because
+that version fixes some portability problems under Unixware.
+
+We have been able to compile @strong{MySQL} with the following @code{configure}
+command on UnixWare 7.0.1:
+
+@example
+shell> CC=cc CXX=CC ./configure --prefix=/usr/local/mysql
+@end example
+
+If you want to use @code{gcc}, you must use @code{gcc} 2.95.2 or newer.
+
+@node IBM-AIX, HP-UX 10.20, SCO Unixware, Source install system issues
+@subsection IBM-AIX notes
+
+Automatic detection of @code{xlC} is missing from Autoconf, so a
+@code{configure} command something like this is needed when compiling
+@strong{MySQL}: (The example uses the IBM compiler)
+
+@example
+shell> CC="xlc_r" CFLAGS="-ma -O3 -qstrict -DHAVE_INT_8_16_32" \
+ CXX="xlC_r" CXXFLAGS="-ma -O3 -qstrict -DHAVE_INT_8_16_32" \
+ ./configure
+@end example
+
+If you change the @code{-O3} to @code{-O2} in the above configure line,
+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 @strong{MySQL}, you
+@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.) We recommend the following @code{configure} line with
+@code{egcs} and @code{gcc} on AIX:
+
+@example
+shell> CC=gcc \
+ CFLAGS="-DHAVE_INT_8_16_32" \
+ CXX=gcc \
+ CXXFLAGS="-felide-constructors -fno-exceptions -fno-rtti -DHAVE_INT_8_16_32" \" \
+ ./configure --prefix=/usr/local/mysql --with-debug --with-low-memory
+@end example
+
+If you have problems with signals (@strong{MySQL} dies unexpectedly
+under high load) you may have found an OS bug with threads and
+signals. In this case you can tell @strong{MySQL} not to use signals by
+configuring with:
+
+@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
+
+This doesn't affect the performance of @strong{MySQL}, but has the side
+effect that you can't kill clients that are ``sleeping'' on a connection with
+@code{mysqladmin kill} or @code{mysqladmin shutdown}. Instead, the client
+will die when it issues its next command.
+
+On some versions of AIX, linking with @code{libbind.a} makes @code{getservbyname} core
+dump. This is an AIX bug and should be reported to IBM.
+
+@node HP-UX 10.20, HP-UX 11.x, IBM-AIX, Source install system issues
+@subsection HP-UX 10.20 notes
+
+There are a couple of ``small'' problems when compiling @strong{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 one to use gcc 2.95 on HP-UX. Don't use high optimization
+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,
+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
+@end example
+
+If you are compiling @code{gcc} 2.95 yourself, you should NOT link it with
+the DCE libraries (@code{libdce.a} or @code{libcma.a}) if you want to compile
+@strong{MySQL} with MIT-pthreads. If you mix the DCE and MIT-pthreads
+packages you will get a @code{mysqld} to which you cannot connect. Remove
+the DCE libraries while you compile @code{gcc} 2.95!
+
+@node HP-UX 11.x, MacOSX, HP-UX 10.20, Source install system issues
+@subsection HP-UX 11.x notes
+
+For HPUX 11.x we recommend @strong{MySQL} 3.23.15 or later.
+
+If you are using @code{gcc} 2.95.1 on a unpatched HPUX 11.x system you will
+get the error:
+
+@example
+In file included from /usr/include/unistd.h:11,
+ from ../include/global.h:125,
+ from mysql_priv.h:15,
+ from item.cc:19:
+/usr/include/sys/unistd.h:184: declaration of C function `int pthread_atfork(void (*)(...), void (*)
+(...), void (*)(...))' conflicts with
+/usr/include/sys/pthread.h:440: previous declaration `int pthread_atfork(void (*)(), void (*)(), voi
+d (*)())' here
+In file included from item.h:306,
+ from mysql_priv.h:158,
+ from item.cc:19:
+@end example
+
+The problem is that HP-UX doesn't define @code{pthreads_atfork()} consistently.
+It has conflicting prototypes in
+@file{/usr/include/sys/unistd.h}:184 and
+@file{/usr/include/sys/pthread.h}:440 (I post the details below).
+
+One solution is to copy @file{/usr/include/sys/unistd.h} into
+@file{mysql/include} and edit @file{unistd.h} and change it to match
+the definition in @file{pthread.h}. Here's the 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
+
+After this, the following configure line should work:
+
+@example
+CFLAGS="-fomit-frame-pointer -O6 -fpic" CXX=gcc CXXFLAGS="-felide-constructors -fno-exceptions -fno-rtti -O6" ./configure --prefix=/usr/local/mysql --disable-shared
+@end example
+
+Here is some information that a HPUX 11.x user sent us about compile
+@strong{MySQL} with HPUX:x compiler
+
+@itemize @bullet
+@item
+@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.
+@end example
+@item
+@example
+ configuration:
+ ./configure --with-pthread \
+ --prefix=/source-control/mysql \
+ --with-named-thread-libs=-lpthread \
+ --with-low-memory
+@end example
+@item
+ added '#define _CTYPE_INCLUDED' to include/m_ctype.h. This
+ symbol is the one defined in HP's /usr/include/ctype.h:
+
+@example
+ /* 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
+@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 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 @strong{MySQL} (-O3) are not recognized
+by HP's compilers. I did not change the flags.
+@end itemize
+
+@node MacOSX, , HP-UX 11.x, Source install system issues
+@subsection MacOS X notes
+
+You can get @strong{MySQL} to work on MacOS X by following the links to
+the MacOS X ports. @xref{Useful Links}.
+
+@strong{MySQL} 3.23.7 should include all patches necessary to configure
+it on MacOSX. You must however first install the pthread package from
+@uref{http://www.prnet.de/RegEx/mysql.html,MySql for MacOSX Server}
+before configuring @strong{MySQL}.
+
+You might want to also add aliases to your shell's resource file to
+access @code{mysql} and @code{mysqladmin} from the command line.
+
+@example
+alias mysql '/usr/local/mysql/bin/mysql'
+alias mysqladmin '/usr/local/mysql/libexec/mysqladmin'
+@end example
+
+@node Win32, OS/2, Source install system issues, Installing
+@section Win32 notes
+
+This section describes installation and use of @strong{MySQL} on Win32. This
+is also described in the @file{README} file that comes with the
+@strong{MySQL} Win32 distribution.
+
+@menu
+* Win32 installation:: Installing @strong{MySQL} on Win32
+* Win95 start:: Starting @strong{MySQL} on Win95 / Win98
+* NT start:: Starting @strong{MySQL} on NT / Win2000
+* Win32 running:: Running @strong{MySQL} on Win32
+* Win32 and SSH:: Connecting to a remote @strong{MySQL} from Win32 with SSH
+* Win32 symbolic links:: Splitting data across different disks under Win32
+* Win32 compiling::
+* Win32 vs Unix:: @strong{MySQL}-Win32 compared to Unix @strong{MySQL}
+@end menu
+
+@node Win32 installation, Win95 start, Win32, Win32
+@subsection Installing MySQL on Win32
+
+If you don't have a registered version of @strong{MySQL}, you should first
+download the shareware version from:
+
+@uref{http://www.mysql.com/mysql_w32.htmy,@strong{MySQL} 3.22.x}
+
+If you plan to connect to @strong{MySQL} from some other program, you will
+probably also need the @strong{MyODBC} driver. You can find this at the
+@uref{http://www.mysql.com/downloads/api-myodbc.html,@strong{MyODBC} download page}.
+
+To install either distribution, unzip it in some empty directory and run the
+@code{Setup.exe} program.
+
+By default, @strong{MySQL}-Win32 is configured to be installed in
+@file{C:\mysql}. If you want to install @strong{MySQL} elsewhere, install it
+in @file{C:\mysql}, then move the installation to where you want it. If you
+do move @strong{MySQL}, you must tell @code{mysqld} where everything is by
+supplying options to @code{mysqld}. Use @code{C:\mysql\bin\mysqld --help} to
+display all options! For example, if you have moved the @strong{MySQL}
+distribution to @file{D:\programs\mysql}, you must start @code{mysqld} with:
+@code{D:\programs\mysql\bin\mysqld --basedir D:\programs\mysql}
+
+With the registered version of @strong{MySQL}, you can also create a
+@file{C:\my.cnf} file that holds any default options for the
+@strong{MySQL} server. Copy the file @file{\mysql\my-xxxxx.cnf} to
+@file{C:\my.cnf} and edit this to suit your setup. Note that you should
+specify all paths with @code{/} instead of @code{\}. If you use
+@code{\}, you need to specify this twice, as @code{\} is the escape
+character in @strong{MySQL}.
+@xref{Option files}.
+
+@node Win95 start, NT start, Win32 installation, Win32
+@subsection Starting MySQL on Win95 / Win98
+
+@strong{MySQL} uses TCP/IP to connect a client to a server. (This will
+allow any machine on your network to connect to your @strong{MySQL}
+server). Because of this, you must install TCP/IP on your machine before
+starting @strong{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! @strong{MySQL} requires
+Winsock 2! You can get the newest Winsock from
+@uref{http://www.microsoft.com,Microsoft}. Win98 has as default the new
+Winsock 2 library, so the above doesn't apply for Win98.
+
+There are 2 different @strong{MySQL} servers you can use:
+
+@multitable @columnfractions .15 .85
+@item @code{mysqld} @tab Compiled with full debugging and automatic memory allocation checking
+@item @code{mysqld-opt} @tab Optimized for a Pentium processor.
+@end multitable
+
+Both of the above should work on any Intel processor >= i386.
+
+To start the @code{mysqld} server, you should start an MS-DOS window and type:
+
+@example
+C:\mysql\bin\mysqld
+@end example
+
+This will start @code{mysqld} in the background without a window.
+
+You can kill the @strong{MySQL} server by executing:
+
+@example
+C:\mysql\bin\mysqladmin -u root shutdown
+@end example
+
+Note that Win95/Win98 don't support creation of named pipes. On
+Win95/Win98, you can only use named pipes to connect to a remote
+@strong{MySQL} running on an NT server.
+
+If @code{mysqld} doesn't start please check whether or not the
+@file{\mysql\mysql.err} file contains any reason for this. You can also
+try to start it with @code{mysqld --standalone}; In this case you may
+get some useful information on the screen that may help solve this.
+
+The last option is to start @code{mysqld} with @code{--debug}. In this
+case @code{mysqld} will write a log file in @file{\mysqld.trace}
+that should contain the reason why @code{mysqld} doesn't start. If you
+make a bug report about this, please only send the lines where something
+seams to go wrong to the mailing list!
+
+@node NT start, Win32 running, Win95 start, Win32
+@subsection Starting MySQL on NT / Win200
+
+The Win95/Win98 section also applies to @strong{MySQL} on NT / Win2000, with
+the following differences:
+
+To get @strong{MySQL} to work with TCP/IP on NT, 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 @strong{MySQL} as a service on NT/Win2000:
+
+@example
+C:\mysql\bin\mysqld-nt --install
+@end example
+
+(You could use the @code{mysqld} or @code{mysqld-opt} servers on NT,
+but those cannot be started as a service or use named pipes.)
+
+You can start and stop the @strong{MySQL} service with:
+
+@example
+NET START mysql
+NET STOP mysql
+@end example
+
+Note that in this case you can't use any other options for @code{mysqld-nt}!
+
+You can also run @code{mysqld-nt} as a standalone 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 starts 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}.
+
+The service is installed with the name @code{MySql}. Once installed, it must
+be started using Services Control Manager (SCM) Utility (found in 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 @strong{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.
+
+On NT you can get the following service error messages:
+
+@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
+@end multitable
+
+If you have problems installing @code{mysqld-nt} as a service, try starting
+it with the full path:
+
+@example
+C:\mysql\bin\mysqld-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 you don't want to start @code{mysqld-nt} as a service, you can start it as
+follows:
+
+@example
+C:\mysql\bin\mysqld-nt --standalone
+@end example
+
+or
+
+@example
+C:\mysql\bin\mysqld --standalone --debug
+@end example
+
+The last version gives you a debug trace in @file{C:\mysqld.trace}.
+
+@node Win32 running, Win32 and SSH, NT start, Win32
+@subsection Running MySQL on Win32
+
+@strong{MySQL} supports TCP/IP on all Win32 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:
+
+@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 . @tab Named pipes
+@item localhost @tab TCP/IP to current host
+@item hostname @tab TCP/IP
+@end multitable
+
+You can force a @strong{MySQL} client to use named pipes by specifying the
+@code{--pipe} option. Use the @code{--socket} option to specify the name of
+the pipe.
+
+You can test whether or not @strong{MySQL} is working by executing the
+following commands:
+
+@example
+C:\mysql\bin\mysqlshow
+C:\mysql\bin\mysqlshow -u root mysql
+C:\mysql\bin\mysqladmin version status proc
+C:\mysql\bin\mysql test
+@end example
+
+If @code{mysqld} is slow to answer to connections on Win95/Win98, there is
+probably a problem with your DNS. In this case, start @code{mysqld} with
+@code{--skip-name-resolve} and use only @code{localhost} and IP numbers in
+the @strong{MySQL} grant tables. You can also avoid DNS when connecting to a
+@code{mysqld-nt} @strong{MySQL} server running on NT by using the
+@code{--pipe} argument to specify use of named pipes. This works for most
+@strong{MySQL} clients.
+
+There are two versions of the @strong{MySQL} command line tool:
+@multitable @columnfractions .15 .85
+@item @code{mysql} @tab Compiled on native Win32, 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
+
+If you want to use @code{mysqlc.exe}, you must copy
+@file{C:\mysql\lib\cygwinb19.dll} to @file{\windows\system} (or similar
+place).
+
+The default privileges on Win32 give all local users full privileges
+to all databases. To make @strong{MySQL} 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 example starts by removing the anonymous user, that allows
+anyone to access the 'test' database)
+
+@example
+C:\mysql\bin\mysql mysql
+mysql> DELETE FROM user WHERE Host='localhost' AND User='';
+mysql> QUIT
+C:\mysql\bin\mysqladmin reload
+C:\mysql\bin\mysqladmin -u root password your_password
+@end example
+
+After you've set the password, if you want to take down the @code{mysqld}
+server, you can do so using this command:
+
+@example
+mysqladmin --user=root --password=your_password shutdown
+@end example
+
+If you are using the old shareware version of @strong{MySQL} 3.21 under
+Windows, the above command will fail with an error: @code{parse error
+near 'SET OPTION password'}. This is because the old shareware version,
+which is based on @strong{MySQL} 3.21, doesn't have the @code{SET PASSWORD}
+command. The fix is in this case is to upgrade to the 3.22 shareware
+version.
+
+With the newer @strong{MySQL} versions you can easily add new users
+and change privileges with @code{GRANT} and @code{REVOKE} commands.
+@xref{GRANT}.
+
+@node Win32 and SSH, Win32 symbolic links, Win32 running, Win32
+@subsection Connecting to a remote MySQL from Win32 with SSH
+
+Here is a note about how to connect to get a secure connection to remote MySQL
+server with SSH (by David Carlson).
+
+@itemize @bullet
+@item
+Install SSH client on your windows machine - I used a free SSH client
+from @uref{http://www.doc.ic.ac.uk/~ci2/ssh/}.
+Other useful links:
+@uref{http://www.npaci.edu/Security/npaci_security_software.html} and
+@uref{http://www.npaci.edu/Security/samples/ssh32_windows/index.html}.
+@item
+Start SSH. Set Host Name = yourmysqlserver name or IP address. Set
+userid=your userid to log in to your server
+@item
+Click on "local forwards". Set @code{local port: 3306},
+@code{host: localhost}, @code{remote port: 3306}
+@item
+Save everything, otherwise you'll have to redo it the next time.
+@item
+Log in to your server with SSH.
+@item
+Start some ODBC application (for example Access)
+@item
+Create a new file and link to mySQL using the ODBC driver the same way
+you normally do except for server, user "localhost".
+@end itemize
+
+That's it. It works very well with a direct Internet connection. I'm
+having problems with SSH conflicting with my Win95 network and Wingate -
+but that'll be the topic of a posting on another software company's
+usegroup!
+
+@findex Symbolic links
+@findex Using multiple disks to start data
+@node Win32 symbolic links, Win32 compiling, Win32 and SSH, Win32
+@subsection Splitting data across different disks under Win32
+
+On windows @strong{MySQL} 3.23.16 and above is compiled with the
+@code{-DUSE_SYMDIR} option. This allows you to put a database on
+different disk by adding a symbolic link to it (in a similar manner that
+symbolic links works on Unix).
+
+On windows you make a symbolic link to a database by creating a file
+that contains the path to the destination directory and saving this in
+the @code{mysql_data} directory under the filename @code{database.sym}.
+Note that the symbolic link will only be used if the directory
+@code{mysql_data_dir\database} doesn't exist.
+
+For example if you want to have database @code{foo} on @file{D:\data\foo} you
+should create the file @file{C:\mysql\data\foo.sym} that should contains the
+text @code{D:\data\foo}. After this, all tables created in the database
+@code{foo} will be created in @file{D:\data\foo}.
+
+@node Win32 compiling, Win32 vs Unix, Win32 symbolic links, Win32
+@subsection Compiling MySQL clients on Windows.
+
+In your source files, you should include @file{windows.h} before you include
+@code{mysql.h}:
+
+@example
+#if defined(_WIN32) || defined(_WIN64)
+#include <windows.h>
+#endif
+#include <mysql.h>
+@end example
+
+You can either link your code with the dynamic @file{libmysql.lib} library,
+which is just a wrapper to load in @file{libmysql.dll} on demand, or link
+with the static @file{mysqlclient.lib} library.
+
+Note that as the mysqlclient libraries are compiled as threaded libraries,
+you should also compile your code to be multi-threaded!
+
+@node Win32 vs Unix, , Win32 compiling, Win32
+@subsection MySQL-Win32 compared to Unix MySQL
+
+@strong{MySQL}-Win32 has by now proven itself to be very stable. This version
+of @strong{MySQL} has the same features as the corresponding Unix version
+with the following exceptions:
+
+@table @strong
+@item Win95 and threads
+Win95 leaks about 200 bytes of main memory for each thread creation. Because
+of this, you shouldn't run @code{mysqld} for an extended time on Win95 if
+you do many connections, because each connection in @strong{MySQL} creates
+a new thread! WinNT and Win98 don't suffer from this bug.
+
+@item Concurrent reads
+@strong{MySQL} depends on the @code{pread()} and @code{pwrite()} calls to be
+able to mix @code{INSERT} and @code{SELECT}. As windows doesn't support these
+calls, @strong{MySQL} can't currently handle concurrent reads on windows.
+We plan to fix this by adding an extra mutex to each open file and simulate
+@code{pread()}/@code{pwrite()}.
+
+@item Blocking read
+@strong{MySQL} uses a blocking read for each connection.
+This means that:
+
+@itemize @bullet
+@item
+A connection will not be disconnected automatically after 8 hours, as happens
+with the Unix version of @strong{MySQL}.
+
+@item
+If a connection ``hangs,'' it's impossible to break it without killing
+@strong{MySQL}.
+
+@item
+@code{mysqladmin kill} will not work on a sleeping connection.
+
+@item
+@code{mysqladmin shutdown} can't abort as long as there are sleeping
+connections.
+@end itemize
+
+We plan to fix this in the near future.
+
+@item UDF functions
+For the moment, @strong{MySQL}-Win32 does not support user definable functions.
+
+@item @code{DROP DATABASE}
+You can't drop a database that is in use by some thread.
+
+@item Killing @strong{MySQL} from the task manager
+You can't kill @strong{MySQL} from the task manager or with the shutdown
+utility in Windows95. You must take it down with @code{mysqladmin shutdown}.
+
+@item Case-insensitive names
+Filenames are case insensitive on Win32, so database and table names
+are also case insensitive in @strong{MySQL} for Win32. The only restriction is
+that database and table names must be given in the same case throughout a
+given statement. The following query would not work because it refers to
+a table both as @code{my_table} and as @code{MY_TABLE}:
+@example
+SELECT * FROM my_table WHERE MY_TABLE.col=1;
+@end example
+
+@item The @samp{\} directory character
+Pathname components in Win95 are separated by @samp{\} characters, which is
+also the escape character in @strong{MySQL}. If you are using @code{LOAD
+DATA INFILE} or @code{SELECT ... INTO OUTFILE}, you must double the @samp{\}
+character or use Unix style filenames @samp{/} characters:
+@example
+LOAD DATA INFILE "C:\\tmp\\skr.txt" INTO TABLE skr;
+SELECT * INTO OUTFILE 'C:/tmp/skr.txt' FROM skr;
+@end example
+
+@item @code{Can't open named pipe} error
+If you use the shareware version of @strong{MySQL}-Win32 on NT with the
+newest mysql-clients you will get the following error:
+
+@example
+error 2017: can't open named pipe to host: . pipe...
+@end example
+
+@tindex .my.cnf file
+This is because the release version of @strong{MySQL} uses
+named pipes on NT by default. You can avoid this error by using the
+@code{--host=localhost} option to the new @strong{MySQL} clients
+or create a file @file{C:\my.cnf} that contains the following information:
+
+@example
+[client]
+host = localhost
+@end example
+
+@item @code{Access denied for user} error
+If you get the error @code{Access denied for user: 'some-user@@unknown'
+to database 'mysql'} when accessing a @strong{MySQL} server on the same
+machine, this means that @strong{MySQL} can't resolve your host name
+properly.
+
+To fix this, you should create a file @file{\windows\hosts} with the
+following information:
+
+@example
+127.0.0.1 localhost
+@end example
+@end table
+
+Here are some open issues for anyone who might want to help us with the Win32
+release:
+
+@itemize @bullet
+@item
+Make a single user @code{MYSQL.DLL} server. This should include everything in
+a standard @strong{MySQL} server, except thread creation. This will make
+@strong{MySQL} much easier to use in applications that don't need a true
+client/server and don't need to access the server from other hosts.
+
+@item
+Add some nice ``start'' and ``shutdown'' icons to the @strong{MySQL} installation.
+
+@item
+Create a tool to manage registry entries for the @strong{MySQL} startup
+options. The registry entry reading is already coded into @code{mysqld.cc},
+but it should be recoded to be more ``parameter'' oriented.
+The tool should also be able to update the @file{\my.cnf} file if the user
+would prefer to use this 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 update the @file{C:\my.cnf} file
+instead.
+
+@item
+When you suspend a laptop running Win95, the @code{mysqld}
+daemon doesn't accept new connections when the laptop is resumed.
+We don't know if this is a problem with Win95, TCP/IP or @strong{MySQL}.
+
+@item
+It would be real nice to be able to kill @code{mysqld} from the
+task manager. For the moment, you must use @code{mysqladmin shutdown}.
+
+@item
+Port @code{readline} to Win32 for use in the @code{mysql} command line tool.
+
+@item
+GUI versions of the standard @strong{MySQL} clients (@code{mysql},
+@code{mysqlshow}, @code{mysqladmin}, and @code{mysqldump}) would be nice.
+
+@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 @code{mysqladmin kill} on Win32.
+
+@item
+Documentation of which Windows programs work with
+@strong{MySQL}-Win32/@strong{MyODBC} and what must be done to get them working.
+
+@item
+@code{mysqld} always starts in the "C" locale and not in the default locale.
+We would like to have @code{mysqld} use the current locale for the sort order.
+
+@item
+Port @code{sqlclient} to Win32 (almost done) and add more features to it!
+
+@item
+Add more options to MysqlManager.
+
+@item
+Change the communication protocol between the server and client to use Windows
+internal communication instead of sockets and TCP/IP.
+
+@item
+Implement UDF functions with @code{.DLL}s.
+
+@item
+Add macros to use the faster thread-safe increment/decrement methods
+provided by Win32.
+
+@end itemize
+
+Other Win32-specific issues are described in the @file{README} file that comes
+with the @strong{MySQL}-Win32 distribution.
+
+@node OS/2, MySQL binaries, Win32, Installing
+@section OS/2 notes
+
+@strong{MySQL} uses quite a few open files. Because of this, you
+should add something like the following to your @file{CONFIG.SYS} file:
+
+@example
+SET EMXOPT=-c -n -h1024
+@end example
+
+If you don't do this, you will probably run into the following error:
+
+@example
+File 'xxxx' not found (Errcode: 24)
+@end example
+
+When using @strong{MySQL} with OS/2 Warp 3, FixPack 29 or above is
+required. With OS/2 Warp 4, FixPack 4 or above is required. This is a
+requirement of the Pthreads library. @strong{MySQL} must be installed
+in a partition that supports long file names such as HPFS, FAT32, etc.
+
+The @file{INSTALL.CMD} script must be run from OS/2's own @file{CMD.EXE}
+and may not work with replacement shells such as @file{4OS2.EXE}.
+
+The @file{scripts/mysql-install-db} script has been renamed: it is now called
+@file{install.cmd} and is a REXX script which will set up the default
+@strong{MySQL} security settings and create the WorkPlace Shell icons
+for @strong{MySQL}.
+
+Dynamic module support is compiled in but not fully tested. Dynamic
+modules should be compiled using the Pthreads runtime library.
+
+@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{Note:} Due to limitations in OS/2, UDF module name stems must not
+exceed 8 characters. Modules are stored in the @file{/mysql2/udf}
+directory; the @code{safe-mysqld.cmd} script will put this directory in
+the @code{BEGINLIBPATH} environment variable. When using UDF modules,
+specified extensions are ignored --- it is assumed to be @file{.udf}.
+For example, in Unix, the shared module might be named @file{example.so}
+and you would load a function from it like this:
+
+@example
+CREATE FUNCTION metaphon RETURNS STRING SONAME "example.so";
+@end example
+
+Is OS/2, the module would be named @file{example.udf}, but you would not
+specify the module extension:
+
+@example
+CREATE FUNCTION metaphon RETURNS STRING SONAME "example";
+@end example
+
+@node MySQL binaries, Post-installation, OS/2, Installing
+@section MySQL binaries
+
+As a service, we at MySQL AB provides a set of binary distributions of
+@strong{MySQL} that are compiled at our site or at sites where customers
+kindly have given us access to their machines.
+
+These distributions are generated with
+@code{scripts/make_binary_distribution} and are configured with the
+following compilers and options:
+
+@table @asis
+@item SunOS 4.1.4 2 sun4c with @code{gcc} 2.7.2.1
+@code{CC=gcc CXX=gcc CXXFLAGS=-O3 ./configure --prefix=/usr/local/mysql --disable-shared --with-extra-charsets=complex}
+
+@item SunOS 5.5.1 sun4u with @code{egcs} 1.0.3a
+@code{CC=gcc CFLAGS="-O6 -fomit-frame-pointer" CXX=gcc CXXFLAGS="-O6 -fomit-frame-pointer -felide-constructors -fno-exceptions -fno-rtti" ./configure --prefix=/usr/local/mysql --with-low-memory --with-extra-charsets=complex}
+
+@item SunOS 5.6 sun4u with @code{egcs} 2.90.27
+@code{CC=gcc CFLAGS="-O6 -fomit-frame-pointer" CXX=gcc CXXFLAGS="-O6 -fomit-frame-pointer -felide-constructors -fno-exceptions -fno-rtti" ./configure --prefix=/usr/local/mysql --with-low-memory --with-extra-charsets=complex}
+
+@item SunOS 5.6 i86pc with @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 with @code{pgcc} 2.90.29 (@code{egcs} 1.0.3a)
+@code{CFLAGS="-O6 -mpentium -mstack-align-double -fomit-frame-pointer" CXX=gcc CXXFLAGS="-O6 -mpentium -mstack-align-double -fomit-frame-pointer -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 with x686 with @code{gcc} 2.95.2
+@code{CFLAGS="-O6 -mpentiumpro -fomit-frame-pointer" CXX=gcc CXXFLAGS="-O6 -mpentiumpro -fomit-frame-pointer -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 with @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 with @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 with @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 with @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 with @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 with @code{gcc} 2.7.2
+@code{CC=gcc CXX=gcc CXXFLAGS=-O3 ./configure --prefix=/usr/local/mysql --with-extra-charsets=complex}
+@end table
+
+Anyone who has more optimal options for any of the configurations listed
+above can always mail them to the developer's mailing list at
+@email{developer@@lists.mysql.com}.
+
+RPM distributions prior to @strong{MySQL} 3.22 are user-contributed.
+Beginning with 3.22, some RPMs are generated by us at MySQL AB.
+
+If you want to compile a debug version of @strong{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.
+
+@node Post-installation, Upgrade, MySQL binaries, Installing
+@section Post-installation setup and testing
+
+@menu
+* mysql_install_db:: Problems running @code{mysql_install_db}
+* Starting server:: Problems starting the @strong{MySQL} server
+* Automatic start:: Starting and stopping @strong{MySQL} automatically
+* Command-line options:: Command-line options
+* Option files:: Option files
+@end menu
+
+Once you've installed @strong{MySQL} (from either a binary or source
+distribution), you need to initialize 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.
+
+Normally you install the grant tables and start the server like this
+for installation from a source distribution:
+
+@example
+shell> ./scripts/mysql_install_db
+shell> cd mysql_installation_directory
+* Command-line options:: Command-line options
+shell> ./bin/safe_mysqld &
+@end example
+
+For a binary distribution, do this:
+
+@example
+shell> cd mysql_installation_directory
+shell> ./bin/mysql_install_db
+shell> ./bin/safe_mysqld &
+@end example
+
+Testing is most easily done from the top-level directory of the @strong{MySQL}
+distribution. For a binary distribution, this is your installation directory
+(typically something like @file{/usr/local/mysql}). For a source
+distribution, this is the main directory of your @strong{MySQL} source tree.
+
+In the commands shown below in this section and in the following
+subsections, @code{BINDIR} is the path to the location in which programs
+like @code{mysqladmin} and @code{safe_mysqld} are installed. For a
+binary distribution, this is the @file{bin} directory within the
+distribution. For a source distribution, @code{BINDIR} is probably
+@file{/usr/local/bin}, unless you specified an installation directory
+other than @file{/usr/local} when you ran @code{configure}.
+@code{EXECDIR} is the location in which the @code{mysqld} server is
+installed. For a binary distribution, this is the same as
+@code{BINDIR}. For a source distribution, @code{EXECDIR} is probably
+@file{/usr/local/libexec}.
+
+Testing is described in detail below:
+
+@enumerate
+@item
+If necessary, start the @code{mysqld} server and set up the initial
+@strong{MySQL} grant tables containing the privileges that determine how
+users are allowed to connect to the server. This is normally done with the
+@code{mysql_install_db} script:
+
+@example
+shell> scripts/mysql_install_db
+@end example
+
+Typically, @code{mysql_install_db} needs to be run only the first time you
+install @strong{MySQL}. Therefore, if you are upgrading an existing
+installation, you can skip this step. (However, @code{mysql_install_db} is
+quite safe to use and will not update any tables that already exist, so if
+you are unsure what to do, you can always run @code{mysql_install_db}.)
+
+@code{mysql_install_db} creates six tables (@code{user}, @code{db},
+@code{host}, @code{tables_priv}, @code{columns_priv} and @code{func}) in the
+@code{mysql} database. A description of the initial privileges is given in
+@ref{Default privileges}. Briefly, these privileges allow the @strong{MySQL}
+@code{root} user to do anything, and allow anybody to create or use databases
+with a name of @code{'test'} or starting with @code{'test_'}.
+
+If you don't set up the grant tables, the following error will appear in the
+log file when you start the server:
+
+@tindex host.frm, problems finding
+@example
+mysqld: Can't find file: 'host.frm'
+@end example
+
+The above may also happens with a binary @strong{MySQL} distribution if you
+don't start @strong{MySQL} by executing exactly @code{./bin/safe_mysqld}!
+
+You might need to run @code{mysql_install_db} as @code{root}. However,
+if you prefer, you can run the @strong{MySQL} server as an unprivileged
+(non-@code{root}) user, provided that user can read and write files in
+the database directory. Instructions for running @strong{MySQL} as an
+unprivileged user are given in @ref{Changing MySQL user, , Changing
+@strong{MySQL} user}.
+
+If you have problems with @code{mysql_install_db}, see
+@ref{mysql_install_db, , @code{mysql_install_db}}.
+
+There are some alternatives to running the @code{mysql_install_db}
+script as it is provided in the @strong{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 @strong{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!
+
+@item
+If you want to change things in the grant tables after installing them, you
+can run @code{mysql_install_db}, then use @code{mysql -u root mysql} to
+connect to the grant tables as the @strong{MySQL} @code{root} user and issue
+SQL statements to modify the grant tables directly.
+
+@item
+It is possible to recreate the grant tables completely after they have
+already been created. You might want to do this if you've already installed
+the tables but then want to recreate them after editing
+@code{mysql_install_db}.
+@end itemize
+
+For more information about these alternatives, see @ref{Default privileges}.
+
+@item
+Start the @strong{MySQL} server like this:
+@example
+shell> cd mysql_installation_directory
+shell> bin/safe_mysqld &
+@end example
+If you have problems starting the server, see @ref{Starting server}.
+
+@item
+Use @code{mysqladmin} to verify that the server is running. The following
+commands provide a simple test to check that the server is up and responding
+to connections:
+
+@example
+shell> BINDIR/mysqladmin version
+shell> BINDIR/mysqladmin variables
+@end example
+
+The output from @code{mysqladmin version} varies slightly depending on your
+platform and version of @strong{MySQL}, but should be similar to that shown
+below:
+
+@example
+shell> BINDIR/mysqladmin version
+mysqladmin Ver 6.3 Distrib 3.22.9-beta, for pc-linux-gnu on i686
+TCX Datakonsult AB, by Monty
+
+Server version 3.22.9-beta
+Protocol version 10
+Connection Localhost via UNIX socket
+TCP port 3306
+UNIX socket /tmp/mysql.sock
+Uptime: 16 sec
+
+Running threads: 1 Questions: 20 Reloads: 2 Open tables: 3
+@end example
+
+To get a feeling for what else you can do with @code{BINDIR/mysqladmin},
+invoke it with the @code{--help} option.
+
+@item
+Verify that you can shut down the server:
+
+@example
+shell> BINDIR/mysqladmin -u root shutdown
+@end example
+
+@item
+Verify that you can restart the server. Do this using @code{safe_mysqld} or
+by invoking @code{mysqld} directly. For example:
+
+@example
+shell> BINDIR/safe_mysqld --log &
+@end example
+
+If @code{safe_mysqld} fails, try running it from the @strong{MySQL}
+installation directory (if you are not already there). If that doesn't work,
+see @ref{Starting server}.
+
+@item
+Run some simple tests to verify that the server is working.
+The output should be similar to what is shown below:
+
+@example
+shell> BINDIR/mysqlshow
++-----------+
+| Databases |
++-----------+
+| mysql |
++-----------+
+
+shell> BINDIR/mysqlshow mysql
+Database: 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
+
+There is also a benchmark suite in the @file{sql-bench} directory (under the
+@strong{MySQL} installation directory) that you can use to compare how
+@strong{MySQL} performs on different platforms. The @file{sql-bench/Results}
+directory contains the results from many runs against different databases and
+platforms. To run all tests, execute these commands:
+
+@example
+shell> cd sql-bench
+shell> run-all-tests
+@end example
+
+If you don't have the @file{sql-bench} directory, you are probably using an
+RPM for a binary distribution. (Source distribution RPMs include the
+benchmark directory.) In this case, you must first install the benchmark
+suite before you can use it. Beginning with @strong{MySQL} 3.22, there are
+benchmark RPM files named @file{mysql-bench-VERSION-i386.rpm} that contain
+benchmark code and data.
+
+If you have a source distribution, you can also run the tests in the
+@file{tests} subdirectory. For example, to run @file{auto_increment.tst}, do
+this:
+
+@example
+shell> BINDIR/mysql -vvf test < ./tests/auto_increment.tst
+@end example
+
+The expected results are shown in the @file{./tests/auto_increment.res} file.
+@end enumerate
+
+@node mysql_install_db, Starting server, Post-installation, Post-installation
+@subsection Problems running @code{mysql_install_db}
+
+This section lists problems you might encounter when you run
+@code{mysql_install_db}:
+
+@table @strong
+@item @code{mysql_install_db} doesn't install the grant tables
+
+You may find that @code{mysql_install_db} fails to install the grant
+tables and terminates after displaying the following messages:
+
+@example
+starting mysqld daemon with databases from XXXXXX
+mysql daemon ended
+@end example
+
+In this case, you should examine the log file very carefully! The log
+should be located in the directory @file{XXXXXX} named by the error message,
+and should indicate why @code{mysqld} didn't start. If you don't understand
+what happened, include the log when you post a bug report using
+@code{mysqlbug}!
+@xref{Bug reports}.
+
+@item There is already a @code{mysqld} daemon running
+
+In this case, you have probably don't have to run @code{mysql_install_db} at
+all. You have to run @code{mysql_install_db} only once, when you install
+@strong{MySQL} the first time.
+
+@item Installing a second @code{mysqld} daemon doesn't work when one daemon is running
+
+This can happen when you already have an existing @strong{MySQL}
+installation, but want to put a new installation in a different place (e.g.,
+for testing, or perhaps you simply want to run two installations at the same
+time). Generally the problem that occurs when you try to run the second
+server is that it tries to use the same socket and port as the old one. In
+this case you will get the error message: @code{Can't start server: Bind on
+TCP/IP port: Address already in use} or @code{Can't start server : Bind on
+unix socket...} You can start the new server with a different socket and
+port as follows:
+
+@tindex MYSQL_UNIX_PORT environment variable
+@tindex MYSQL_TCP_PORT environment variable
+@tindex Environment variable, MYSQL_UNIX_PORT
+@tindex Environment variable, MYSQL_TCP_PORT
+@example
+shell> MYSQL_UNIX_PORT=/tmp/mysqld-new.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
+
+The environment variables appendix includes a list of other environment
+variables you can use to affect @code{mysqld}. @xref{Environment variables}.
+
+After this, you should edit your server boot script to start both daemons
+with different sockets and ports. For example, it could invoke
+@code{safe_mysqld} twice, but with different @code{--socket}, @code{--port}
+and @code{--basedir} options for each invocation.
+
+@item You don't have write access to @file{/tmp}
+
+If you don't have write access to create a socket file at the default place
+(in @file{/tmp}) or permission to create temporary files in @file{/tmp,}
+you will get an error when running @code{mysql_install_db} or when
+starting or using @code{mysqld}.
+
+You can specify a different socket and temporary directory as follows:
+
+@tindex TMPDIR environment variable
+@tindex MYSQL_UNIX_PORT environment variable
+@tindex Environment variable, TMPDIR
+@tindex Environment variable, MYSQL_UNIX_PORT
+@example
+shell> TMPDIR=/some_tmp_dir/
+shell> MYSQL_UNIX_PORT=/some_tmp_dir/mysqld.sock
+shell> export TMPDIR MYSQL_UNIX_PORT
+@end example
+
+@file{some_tmp_dir} should be the path to some directory for which you
+have write permission. @xref{Environment variables}.
+
+
+After this you should be able to run @code{mysql_install_db} and start
+the server with these commands:
+
+@example
+shell> scripts/mysql_install_db
+shell> BINDIR/safe_mysqld &
+@end example
+
+@item @code{mysqld} crashes immediately
+
+If you are running RedHat 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 @strong{MySQL} mail
+archives. Links to the mail archives are available at the online
+@uref{http://www.mysql.com/documentation/, @strong{MySQL} documentation page}.
+Also, see @ref{Linux}.
+
+You can also start @code{mysqld} manually using the @code{--skip-grant-tables}
+option and add the privilege information yourself using @code{mysql}:
+
+@example
+shell> BINDIR/safe_mysqld --skip-grant-tables &
+shell> BINDIR/mysql -u root mysql
+@end example
+
+From @code{mysql}, manually execute the SQL commands in
+@code{mysql_install_db}. Make sure you run @code{mysqladmin
+flush-privileges} or @code{mysqladmin reload} afterward to tell the server to
+reload the grant tables.
+@end table
+
+@node Starting server, Automatic start, mysql_install_db, Post-installation
+@subsection Problems starting the MySQL server
+
+Generally, you start the @code{mysqld} server in one of three ways:
+
+@itemize @bullet
+@item
+By invoking @code{mysql.server}. This script is used primarily at
+system startup and shutdown, and is described more fully in
+@ref{Automatic start}.
+@item
+By invoking @code{safe_mysqld}, which tries to determine the proper options
+for @code{mysqld} and then runs it with those options.
+@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
+@item
+By invoking @code{mysqld} directly.
+@end itemize
+
+Whichever method you use to start the server, if it fails to start up
+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\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:
+
+@example
+shell> tail host_name.err
+shell> tail host_name.log
+@end example
+
+If you find in the log file something like: the following:
+@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
+
+This means that you started mysqld with @code{--bdb-recover} and that
+Berkeley DB found something wrong with it's log files when it tried to
+recover your databases. To be able to continue, you should move away
+the old Berkeley DB log file from the database directory to some other
+place, where you can later examine these. The log files are named
+@file{log.0000000001}, where the number will increase over time.
+
+When the @code{mysqld} daemon starts up, it changes directory to the
+data directory. This is where it expects to write log files and the pid
+(process ID) file, and where it expects to find databases.
+
+The data directory location is hardwired in when the distribution is
+compiled. However, if @code{mysqld} expects to find the data directory
+somewhere other than where it really is on your system, it will not work
+properly. If you have problems with incorrect paths, you can find out
+what options @code{mysqld} allows and what the default path settings are by
+invoking @code{mysqld} with the @code{--help} option. You can override the
+defaults by specifying the correct pathnames as command-line arguments to
+@code{mysqld}. (These options can be used with @code{safe_mysqld} as well.)
+
+Normally you should need to tell @code{mysqld} only the base directory under
+which @strong{MySQL} is installed. You can do this with the @code{--basedir}
+option. You can also use @code{--help} to check the effect of changing path
+options (note that @code{--help} @emph{must} be the final option of the
+@code{mysqld} command). For example:
+
+@example
+shell> EXECDIR/mysqld --basedir=/usr/local --help
+@end example
+
+Once you determine the path settings you want, start the server without
+the @code{--help} option.
+
+If you get the following error, it means that some other program (or another
+@code{mysqld} server) is already using the TCP/IP port or socket
+@code{mysqld} is trying to use:
+
+@example
+Can't start server: Bind on TCP/IP port: Address already in use
+ or
+Can't start server : Bind on unix socket...
+@end example
+
+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
+@code{telnet: Unable to connect to remote host: Connection refused},
+something is using the TCP/IP port @code{mysqld} is trying to use.
+@xref{mysql_install_db, , @code{mysql_install_db}}, and @ref{Multiple
+servers}.
+
+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
+@strong{MySQL}, even if these install the server in slightly different
+locations. @code{safe_mysqld} expects one of these conditions to be true:
+
+@itemize @bullet
+@item
+The server and databases can be found relative to the directory from which
+@code{safe_mysqld} is invoked. @code{safe_mysqld} looks under its working
+directory for @file{bin} and @file{data} directories (for binary
+distributions) or for @file{libexec} and @file{var} directories (for source
+distributions). This condition should be met if you execute
+@code{safe_mysqld} from your @strong{MySQL} installation directory (for
+example, @file{/usr/local/mysql} for a binary distribution).
+
+@item
+If the server and databases cannot be found relative to its working directory,
+@code{safe_mysqld} attempts to locate them by absolute pathnames. Typical
+locations are @file{/usr/local/libexec} and @file{/usr/local/var}.
+The actual locations are determined when the distribution was built from which
+@code{safe_mysqld} comes. They should be correct if
+@strong{MySQL} was installed in a standard location.
+@end itemize
+
+Because @code{safe_mysqld} will try to find the server and databases relative
+to its own working directory, you can install a binary distribution of
+@strong{MySQL} anywhere, as long as you start @code{safe_mysqld} from the
+@strong{MySQL} installation directory:
+
+@example
+shell> cd mysql_installation_directory
+shell> bin/safe_mysqld &
+@end example
+
+If @code{safe_mysqld} fails, even when invoked from the @strong{MySQL}
+installation directory, you can modify it to use the path to @code{mysqld}
+and the pathname options that are correct for your system. Note that if you
+upgrade @strong{MySQL} in the future, your modified version of
+@code{safe_mysqld} will be overwritten, so you should make a copy of your
+edited version that you can reinstall.
+
+If @code{mysqld} is currently running, you can find out what path settings
+it is using by executing this command:
+
+@example
+shell> mysqladmin variables
+
+or
+
+shell> mysqladmin -h 'your-host-name' variables
+@end example
+
+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:
+
+@example
+127.0.0.1 localhost
+@end example
+
+This problem occurs only on systems that don't have a working thread
+library and for which @strong{MySQL} must be configured to use MIT-pthreads.
+
+On Windows, you can try to start @code{mysqld} as follows:
+
+@example
+C:\mysql\bin\mysqld --standalone --debug
+@end example
+
+This will not run in the background and it should also write a trace in
+@file{\mysqld.trace}, which may help you determine the source of your
+problems. @xref{Win32}.
+
+@node Automatic start, Command-line options, Starting server, Post-installation
+@subsection Starting and stopping MySQL automatically
+
+The @code{mysql.server} script can be used to start or stop the server,
+by invoking it with @code{start} or @code{stop} arguments:
+
+@example
+shell> mysql.server start
+shell> mysql.server stop
+@end example
+
+@code{mysql.server} can be found in the @file{share/mysql} directory
+under the @strong{MySQL} installation directory, or in the @file{support-files}
+directory of the @strong{MySQL} source tree.
+
+Before @code{mysql.server} starts the server, it changes directory to
+the @strong{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} into the proper directory before it
+runs @code{safe_mysqld}. If you want the server to run as some specific
+user, you can change the @code{mysql_daemon_user=root} line to use
+another user. You can also modify @code{mysql.server} to pass other
+options to @code{safe_mysqld}.
+
+@code{mysql.server stop} brings down server by sending a signal to it.
+You can take down the server manually by executing @code{mysqladmin shutdown}.
+
+You might want to add these start and stop commands to the appropriate places
+in your @file{/etc/rc*} files when you start using @strong{MySQL} for
+production applications. Note that if you modify @code{mysql.server}, then
+if you upgrade @strong{MySQL} sometime, your modified version will be
+overwritten, so you should make a copy of your edited version that you can
+reinstall.
+
+If your system uses @file{/etc/rc.local} to start external scripts, you
+should append the following to it:
+@example
+/bin/sh -c 'cd /usr/local/mysql ; ./bin/safe_mysqld &'
+@end example
+
+You can also add options for @code{mysql.server} in a global
+@file{/etc/my.cnf} file. A typical @file{/etc/my.cnf} file might look like
+this:
+
+@example
+[mysqld]
+datadir=/usr/local/mysql/var
+socket=/tmp/mysqld.sock
+port=3306
+
+[mysql.server]
+user=mysql
+basedir=/usr/local/mysql
+@end example
+
+The @code{mysql.server} script uses the following variables:
+@code{user}, @code{datadir}, @code{basedir}, @code{bindir} and @code{pid-file}.
+
+@xref{Option files}.
+
+@cindex Command-line options
+@node Command-line options, Option files, Automatic start, Post-installation
+@subsection Command-line options
+
+@code{mysqld} accepts the following command-line options:
+
+@table @code
+
+@item --ansi
+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 this.
+
+@item --big-tables
+Allow big result sets by saving all temporary sets on file. It solves
+most 'table full' errors, but also slows down the queries where
+in-memory tables would suffice. Since version 3.23.2 @strong{MySQL} is
+able to solve it automaticaly by using memory for small temporary
+tables and switching to disk tables where necessary.
+
+@item --bind-address=IP
+IP address to bind to.
+
+@item --character-sets-dir=path
+Directory where character sets are. @xref{Character sets}.
+
+@item --chroot=path
+Chroot mysqld daemon during startup.
+Recommended security measure. It will somewhat limit @code{LOAD DATA INFILE}
+and @code{SELECT ... INTO OUTFILE} though.
+
+@item -h, --datadir=path
+Path to the database root.
+
+@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 --delay-key-write-for-all-tables
+Don't flush key buffers between writes for any @code{MyISAM} table.
+@xref{Server parameters}.
+
+@item --enable-locking
+Enable system locking.
+
+@item -T, --exit-info
+Print some debug info at exit.
+
+@item --flush
+Flush all changes to disk after each SQL commands; Normally @strong{MySQL}
+only does a write of all changes to disk after each SQL command, and lets
+the operating system handle the syncing to disk.
+@xref{Crashing}.
+
+@item -?, --help
+Display short help and exit.
+
+@item --init-file=file
+Read SQL commands from this file at startup.
+
+@item -L, --language=...
+Client error messages in given language. May be given as a full path.
+@xref{Languages}.
+
+@item -l, --log[=file]
+Log connections and queries to file
+
+@item --log-update[=file]
+Log updates to @code{file.#} where @code{#} is a unique number if not given.
+@xref{Update log}.
+
+@item --log-isam[=file]
+Log all isam changes to file.
+
+@item --log-long-format
+Log some extra information to update 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 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}.
+
+@item --pid-file=path
+Path to pid file used by @code{safe_mysqld}.
+
+@item -P, --port=...
+Port number to listen for TCP/IP connections.
+
+@item -o, --old-protocol
+Use the 3.20 protocol for compatibility with some very old clients.
+@xref{Upgrading-from-3.20}.
+
+@item --one-thread
+Only use one thread (for debugging under Linux). @xref{Debugging server}.
+
+@item -O, --set-variable var=option
+Give a variable an 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}.
+
+@item -Sg, --skip-grant-tables
+This option causes the server not to use the privilege system at all. This
+gives everyone @emph{full access} to all databases! (You can tell a running
+server to start using the grant tables again by executing @code{mysqladmin
+flush-privileges} or @code{mysqladmin reload}.)
+
+@item --safe-mode
+Skip some optimize stages.
+Implies @code{--skip-delay-key-write}.
+
+@item --secure
+IP numbers returned by the @code{gethostbyname()} system call are
+checked to make sure they resolve back to the original hostname. This
+makes it harder for someone on the outside to get access by pretending
+to be another host. This option also adds some sanity checks of
+hostnames. The option is turned off by default in @strong{MySQL} 3.21
+because sometimes it takes a long time to perform backward resolutions.
+@strong{MySQL} 3.22 caches hostnames (unless @code{--skip-host-cache} is
+used) and has this option enabled by default.
+
+@item --skip-delay-key-write
+Ignore the @code{delay_key_write} option for all tables.
+@xref{Server parameters}.
+
+@item --skip-locking
+Don't use system locking. To use @code{isamchk} or @code{myisamchk} one has
+to shut down the server. @xref{Stability}. Note that in @strong{MySQL} 3.23
+one can use @code{REPAIR} and @code{CHECK} to repair/check @code{MyISAM}
+tables.
+
+@item --skip-name-resolve
+Hostnames are not resolved. All @code{Host} column values in the grant
+tables must be IP numbers or @code{localhost}.
+
+@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 recommended for systems where only local requests
+are allowed. However, this option is unsuitable for systems that use
+MIT-pthreads, because the MIT-pthreads package doesn't support Unix
+sockets.
+
+@item --skip-new
+Don't use new, possible wrong routines.
+Implies @code{--skip-delay-key-write}.
+This will also set default table type to @code{ISAM}. @xref{ISAM}.
+
+@item --skip-host-cache
+Never use host name cache for faster name-ip resolution, but query
+DNS server on every connect instead.
+
+@item --skip-show-database
+Don't allow 'SHOW DATABASE' commands, unless the user has
+@strong{process} privilege.
+
+@item --skip-thread-priority
+Disable using thread priorities for faster responce time.
+
+@item --socket=path
+Socket file to use for local connections instead of default
+@code{/tmp/mysql.sock}.
+
+@item -t, --tmpdir=path
+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 -V, --version
+output version information and exit
+
+@end table
+
+@cindex Default options
+@cindex Option files
+@node Option files, , Command-line options, Post-installation
+@subsection Option files
+
+@strong{MySQL} 3.22 can read default startup options for the server and
+for clients from option files.
+
+@strong{MySQL} reads default options from the following files on Unix:
+
+@tindex .my.cnf file
+@multitable @columnfractions .3 .7
+@item @strong{Filename} @tab @strong{Purpose}
+@item @code{/etc/my.cnf} @tab Global options
+@item @code{DATADIR/my.cnf} @tab Server-specific options
+@item @code{~/.my.cnf} @tab User-specific options
+@end multitable
+
+@code{DATADIR} is the @strong{MySQL} data directory (typically
+@file{/usr/local/mysql/data} for a binary installation, or
+@file{/usr/local/var} for a source installation). Note that this is the
+directory that was specified at configuration time, not the one specified
+with @code{--datadir} when @code{mysqld} starts up! (@code{--datadir} has no
+effect on where the server looks for option files, because it looks for them
+before it processes any command-line arguments.)
+
+@strong{MySQL} reads default options from the following files on Win32:
+
+@multitable @columnfractions .3 .7
+@item @strong{Filename} @tab @strong{Purpose}
+@item @code{windows-system-directory\my.ini}
+@item @code{C:\my.cnf} @tab Global options
+@item @code{C:\mysql\data\my.cnf} @tab Server-specific options
+@end multitable
+
+Note that you on Win32 should specify all paths with @code{/} instead of
+@code{\}. If you use @code{\}, you need to specify this twice, as
+@code{\} is the escape character in @strong{MySQL}.
+
+@cindex Environment variables
+@strong{MySQL} tries to read option files in the order listed above. If
+multiple option files exist, an option specified in a file read later takes
+precedence over the same option specified in a file read earlier. Options
+specified on the command line take precedence over options specified in any
+option file. Some options can be specified using environment variables.
+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}.
+
+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.
+
+An option file can contain lines of the following forms:
+
+@table @code
+@item #comment
+Comment lines start with @samp{#} or @samp{;}. Empty lines are ignored.
+
+@item [group]
+@code{group} is the name of the program or group for which you want to set
+options. After a group line, any @code{option} or @code{set-variable} lines
+apply to the named group until the end of the option file or another group
+line is given.
+
+@item option
+This is equivalent to @code{--option} on the command line.
+
+@item option=value
+This is equivalent to @code{--option=value} on the command line.
+
+@item set-variable = variable=value
+This is equivalent to @code{--set-variable variable=value} on the command line.
+This syntax must be used to set a @code{mysqld} variable.
+@end table
+
+The @code{client} group allows you to specify options that apply to all
+@strong{MySQL} clients (not @code{mysqld}). This is the perfect group to use
+to specify the password you use to connect to the server. (But make
+sure the option file is readable and writable only to yourself.)
+
+Note that for options and values, all leading and trailing blanks are
+automatically deleted. You may use the escape sequences @samp{\b},
+@samp{\t}, @samp{\n}, @samp{\r}, @samp{\\} and @samp{\s} in your value string
+(@samp{\s} == blank).
+
+Here is a typical global option file:
+
+@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
+
+Here is typical user option file:
+
+@example
+[client]
+# The following password will be sent to all standard MySQL clients
+password=my_password
+
+[mysql]
+no-auto-rehash
+@end example
+
+@tindex .my.cnf file
+If you have a source distribution, you will find sample configuration
+files named @file{my-xxxx.cnf} in the @file{support-files} directory.
+If you have a binary distribution, look in the @file{DIR/share/mysql}
+directory, where @code{DIR} is the pathname to the @strong{MySQL}
+installation directory (typically @file{/usr/local/mysql}). Currently
+there is sample configuration files for small, medium, large and very
+large systems. You can copy @file{my-xxxx.cnf} to your home directory
+(rename the copy to @file{.my.cnf}) to experiment with this.
+
+To tell a @strong{MySQL} program not to read any option files, specify
+@code{--no-defaults} as the first option on the command line. This
+@strong{MUST} be the first option or it will have no effect!
+If you want to check which options are used, you can give the option
+@code{--print-defaults} as the first option.
+
+If you want to force the use of a specific config file, you can use the option
+@code{--defaults-file=full-path-to-default-file}. If you do this, only the
+specified file will be read.
+
+Note for developers: Option file handling is implemented simply by
+processing all matching options (i.e., options in the appropriate group)
+before any command line arguments. This works nicely for programs that use
+the last instance of an option that is specified multiple times. If you have
+an old program that handles multiply-specified options this way but doesn't
+read option files, you need add only two lines to give it that capability.
+Check the source code of any of the standard @strong{MySQL} clients to see
+how to do this.
+
+@node Upgrade, , Post-installation, Installing
+@section Is there anything special to do when upgrading/downgrading MySQL?
+
+You can always move the @strong{MySQL} form and data files between
+different versions on the same architecture as long as you have the same
+base version of @strong{MySQL}. The current base version is
+3. If you change the character set when running @strong{MySQL} (which may
+also change the sort order), you must run @code{myisamchk -r -q} on all
+tables. Otherwise your indexes may not be ordered correctly.
+
+If you are paranoid and/or afraid of new versions, you can always rename your
+old @code{mysqld} to something like @code{mysqld}-'old-version-number'. If
+your new @code{mysqld} then does something unexpected, you can simply shut it
+down and restart with your old @code{mysqld}!
+
+When you do an upgrade you should also backup your old databases, of course.
+Sometimes it's good to be a little paranoid!
+
+After an upgrade, if you experience problems with recompiled client programs,
+like @code{Commands out of sync} or unexpected core dumps, you probably have
+used an old header or library file when compiling your programs. In this
+case you should check the date for your @file{mysql.h} file and
+@file{libmysqlclient.a} library to verify that they are from the new
+@strong{MySQL} distribution. If not, please recompile your programs!
+
+If you get some problems that the new @code{mysqld} server doesn't want to
+start or that you can't connect without a password, check that you don't
+have some old @file{my.cnf} file from your old installation! You can
+check this with: @code{program-name --print-defaults}. If this outputs
+anything other than the program name, you have an active @code{my.cnf}
+file that will may affect things!
+
+It is a good idea to rebuild and reinstall the @code{Msql-Mysql-modules}
+distribution whenever you install a new release of @strong{MySQL},
+particularly if you notice symptoms such as all your @code{DBI} scripts
+dumping core after you upgrade @strong{MySQL}.
+
+@menu
+* 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
+@node Upgrading-from-3.22, Upgrading-from-3.21, Upgrade, Upgrade
+@subsection Upgrading from a 3.22 version to 3.23
+
+@strong{MySQL} 3.23 supports tables of the new @code{MyISAM} type and
+the old @code{ISAM} type. You don't have to convert your old tables to
+use these with 3.23. By default, all new tables will be created with
+type @code{MyISAM} (unless you start @code{mysqld} with the
+@code{--default-table-type=isam} option. You can change an @code{ISAM}
+table to a @code{MyISAM} table with @code{ALTER TABLE} or the Perl script
+@code{mysql_convert_table_format}.
+
+3.22 and 3.21 clients will work without any problems with a 3.23 server.
+
+The following lists what you have to watch out for when upgrading to 3.23:
+
+@itemize @bullet
+@item The default return type of @code{IF} will now depend on both arguments
+and not only the first argument.
+@item @code{AUTO_INCREMENT} will not work with negative numbers.
+@item @code{INNER} and @code{DELAYED} are now reserved words.
+@item @code{FLOAT(X)} is now a true floating point types and not a value with
+a fixed number of decimals.
+@item When declaring @code{DECIMAL(length,dec)} the length argument no
+longer includes a place for the sign or the decimal point.
+@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 @strong{MySQL} with the @code{CXXFLAGS=-DLIKE_CMP_TOUPPER}
+flag.
+@item @code{REGEXP} is now case insensitive for normal (not binary) strings.
+@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 If you want your @code{mysqldump}s to be compatible between
+@strong{MySQL} 3.22 and 3.23, you should not use the @code{--opt} or
+@code{--full} option to @code{mysqldump}.
+@item Check all your calls to @code{DATE_FORMAT()} to make sure there is a
+@samp{%} before each format character. (Later @strong{MySQL} 3.22
+version did allow this syntax.
+@item
+@code{mysql_fetch_fields_direct} is now a function (it was a macro) and
+it returns a pointer to a @code{MYSQL_FIELD} instead of a
+@code{MYSQL_FIELD}.
+@item
+@code{mysql_num_fields()} can no longer be used on a @code{MYSQL*} object (it's
+now a function that takes @code{MYSQL_RES*} as an argument. You should now
+use @code{mysql_field_count()} instead.
+@item
+In @code{MySQL} 3.22, the output of @code{SELECT DISTINCT ...} was
+almost always sorted. In 3.23, you must use @code{GROUP BY} or
+@code{ORDER BY} to obtain sorted output.
+@item
+@code{SUM()} now returns @code{NULL}, instead of 0, if there is no matching
+rows. This is according to ANSI SQL.
+@item
+New restricted words: @code{CASE, THEN, WHEN, ELSE and END}
+@item An @code{AND} or @code{OR} with @code{NULL} values will now return
+@code{NULL} instead of 0. This mostly affects queries that uses @code{NOT}
+on an @code{AND/OR} expression as @code{NOT NULL} = @code{NULL}.
+@end itemize
+
+@cindex Compatibility, between MySQL versions
+@node Upgrading-from-3.21, Upgrading-from-3.20, Upgrading-from-3.22, Upgrade
+@subsection Upgrading from a 3.21 version to 3.22
+
+Nothing that affects compatibility has changed between 3.21 and 3.22. The
+only pitfall is that new tables that are created with @code{DATE} type
+columns will use the new way to store the date. You can't access these new
+fields from an old version of @code{mysqld}.
+
+After installing @strong{MySQL} 3.22, you should start the new server and
+then run the @code{mysql_fix_privilege_tables} script. This will add the new
+privileges that you need to use the @code{GRANT} command. If you forget
+this, you will get @code{Access denied} when you try to use @code{ALTER
+TABLE}, @code{CREATE INDEX} or @code{DROP INDEX}. If your @strong{MySQL} root
+user requires a password, you should give this as an argument to
+@code{mysql_fix_privilege_tables}.
+
+The C API interface to @code{mysql_real_connect()} has changed. If you have
+an old client program that calls this function, you must place a @code{0} for
+the new @code{db} argument (or recode the client to send the @code{db}
+element for faster connections). You must also call @code{mysql_init()}
+before calling @code{mysql_real_connect()}! This change was done to allow
+the new @code{mysql_options()} function to save options in the @code{MYSQL}
+handler structure.
+
+The @code{mysqld} variable @code{key_buffer} has changed names to
+@code{key_buffer_size}, but you can still use the old name in your
+startup files.
+
+@node Upgrading-from-3.20, Upgrading-to-arch, Upgrading-from-3.21, Upgrade
+@subsection Upgrading from a 3.20 version to 3.21
+
+If you are running a version older than 3.20.28 and want to
+switch to 3.21.x, you need to do the following:
+
+You can start the @code{mysqld} 3.21 server with @code{safe_mysqld
+--old-protocol} to use it with clients from the 3.20 distribution.
+In this case, the new client function @code{mysql_errno()} will not
+return any server error, only @code{CR_UNKNOWN_ERROR}, (but it
+works for client errors) and the server uses the old password() checking
+rather than the new one.
+
+If you are @strong{NOT} using the @code{--old-protocol} option to
+@code{mysqld}, you will need to make the following changes:
+
+@itemize @bullet
+@item
+All client code must be recompiled. If you are using ODBC, you must get
+the new @strong{MyODBC} 2.x driver.
+@item
+The script @code{scripts/add_long_password} must be run to convert the
+@code{Password} field in the @code{mysql.user} table to @code{CHAR(16)}.
+@item
+All passwords must be reassigned in the @code{mysql.user} table (to get 62-bit
+rather than 31-bit passwords).
+@item
+The table format hasn't changed, so you don't have to convert any tables.
+@end itemize
+
+@strong{MySQL} 3.20.28 and above can handle the new @code{user} table format
+without affecting clients. If you have a @strong{MySQL} version earlier than
+3.20.28, passwords will no longer work with it if you convert the @code{user}
+table. So to be safe, you should first upgrade to at least 3.20.28 and then
+upgrade to 3.21.x.
+
+@cindex Protocol mismatch
+The new client code works with a 3.20.x @code{mysqld} server, so
+if you experience problems with 3.21.x, you can use the old 3.20.x server
+without having to recompile the clients again.
+
+If you are not using the @code{--old-protocol} option to @code{mysqld},
+old clients will issue the error message:
+
+@example
+ERROR: Protocol mismatch. Server Version = 10 Client Version = 9
+@end example
+
+The new Perl @code{DBI}/@code{DBD} interface also supports the old
+@code{mysqlperl} interface. The only change you have to make if you use
+@code{mysqlperl} is to change the arguments to the @code{connect()} function.
+The new arguments are: @code{host}, @code{database}, @code{user},
+@code{password} (the @code{user} and @code{password} arguments have changed
+places).
+@xref{Perl DBI Class, , Perl @code{DBI} Class}.
+
+The following changes may affect queries in old applications:
+
+@itemize @bullet
+@item
+@code{HAVING} must now be specified before any @code{ORDER BY} clause.
+@item
+The parameters to @code{LOCATE()} have been swapped.
+@item
+There are some new reserved words. The most notable are @code{DATE},
+@code{TIME} and @code{TIMESTAMP}.
+@end itemize
+
+@node Upgrading-to-arch, , Upgrading-from-3.20, Upgrade
+@subsection Upgrading to another architecture
+
+If you are using @strong{MySQL} 3.23, you can copy the @code{.frm}, the
+@code{.MYI} and the @code{.MYD} files between different architectures
+that support the same floating point format. (@strong{MySQL} takes care
+of any byte swapping issues).
+
+The @strong{MySQL} @code{ISAM} data @file{*.ISD} and the index files
+@file{*.ISM} files) are architecture-dependent and in some case
+OS-dependent. If you want to move your applications to another machine
+that has a different architecture or OS than your current machine, you
+should not try to move a database by simply copying the files to the
+other machine. Use @code{mysqldump} instead.
+
+By default, @code{mysqldump} will create a file full of SQL statements.
+You can then transfer the file to the other machine and feed it as input
+to the @code{mysql} client.
+
+Try @code{mysqldump --help} to see what options are available.
+If you are moving the data to a newer version of @strong{MySQL}, you should use
+@code{mysqldump --opt} with the newer version to get a fast, compact dump.
+
+The easiest (although not the fastest) way to move a database between two
+machines is to run the following commands on the machine on which the
+database is located:
+
+@example
+shell> mysqladmin -h 'other hostname' create db_name
+shell> mysqldump --opt db_name \
+ | mysql -h 'other hostname' db_name
+@end example
+
+If you want to copy a database from a remote machine over a slow network,
+you can use:
+
+@example
+shell> mysqladmin create db_name
+shell> mysqldump -h 'other hostname' --opt --compress db_name \
+ | mysql db_name
+@end example
+
+You can also store the result in a file, then transfer the file to the
+target machine and load the file into the database there. For example,
+you can dump a database to a file on the source machine like this:
+
+@example
+shell> mysqldump --quick db_name | gzip > db_name.contents.gz
+@end example
+
+(The file created in this example is compressed.) Transfer the file
+containing the database contents to the target machine and run these commands
+there:
+
+@example
+shell> mysqladmin create db_name
+shell> gunzip < db_name.contents.gz | mysql db_name
+@end example
+
+@cindex @code{mysqldump}
+@cindex @code{mysqlimport}
+You can also use @code{mysqldump} and @code{mysqlimport} to accomplish
+the database transfer.
+For big tables, this is much faster than simply using @code{mysqldump}.
+In the commands shown below, @code{DUMPDIR} represents the full pathname
+of the directory you use to store the output from @code{mysqldump}.
+
+First, create the directory for the output files and dump the database:
+
+@example
+shell> mkdir DUMPDIR
+shell> mysqldump --tab=DUMPDIR db_name
+@end example
+
+Then transfer the files in the @code{DUMPDIR} directory to some corresponding
+directory on the target machine and load the files into @strong{MySQL}
+there:
+
+@example
+shell> mysqladmin create db_name # create database
+shell> cat DUMPDIR/*.sql | mysql db_name # create tables in database
+shell> mysqlimport db_name DUMPDIR/*.txt # load data into tables
+@end example
+
+Also, don't forget to copy the @code{mysql} database, because that's where the
+grant tables (@code{user}, @code{db}, @code{host}) are stored. You may have
+to run commands as the @strong{MySQL} @code{root} user on the new machine
+until you have the @code{mysql} database in place.
+
+After you import the @code{mysql} database on the new machine, execute
+@code{mysqladmin flush-privileges} so that the server reloads the grant table
+information.
+
+@cindex Compatibility, with ANSI SQL
+@node Compatibility, Privilege system, Installing, Top
+@chapter How standards-compatible is MySQL?
+
+@menu
+* Extensions to ANSI:: @strong{MySQL} extensions to ANSI SQL92
+* Ansi mode:: Runnning @strong{MySQL} in ANSI mode
+* Differences from ANSI:: @strong{MySQL} differences compared to ANSI SQL92
+* Missing functions:: Functionality missing from @strong{MySQL}
+* Standards:: What standards does @strong{MySQL} follow?
+* Commit-rollback:: How to cope without @code{COMMIT}-@code{ROLLBACK}
+@end menu
+
+@node Extensions to ANSI, Ansi mode, Compatibility, Compatibility
+@section MySQL extensions to ANSI SQL92
+
+@strong{MySQL} 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 @strong{MySQL} extensions, but is still portable, by using comments
+of the form @code{/*! ... */}. In this case, @strong{MySQL} will parse and
+execute the code within the comment as it would any other @strong{MySQL}
+statement, but other SQL servers will ignore the extensions. For example:
+
+@example
+SELECT /*! STRAIGHT_JOIN */ col_name FROM table1,table2 WHERE ...
+@end example
+
+If you add a version number after the @code{'!'}, the syntax will only be
+executed if the @strong{MySQL} version is equal or newer than the used
+version number:
+
+@example
+CREATE /*!32302 TEMPORARY */ TABLE (a int);
+@end example
+
+The above means that if you have 3.23.02 or newer, then @strong{MySQL} will use
+the @code{TEMPORARY} keyword.
+
+@strong{MySQL} extensions are listed below:
+
+@itemize @bullet
+@item
+The field types @code{MEDIUMINT}, @code{SET}, @code{ENUM} and the
+different @code{BLOB} and @code{TEXT} types.
+
+@item
+The field attributes @code{AUTO_INCREMENT}, @code{BINARY}, @code{NULL},
+@code{UNSIGNED} and @code{ZEROFILL}.
+
+@item
+All string comparisons are case insensitive by default, with sort
+ordering determined by the current character set (ISO-8859-1 Latin1 by
+default). If you don't like this, you should declare your columns with
+the @code{BINARY} attribute or use the @code{BINARY} cast, which causes
+comparisons to be done according to the ASCII order used on the
+@strong{MySQL} server host.
+
+@item
+@strong{MySQL} maps each database to a directory under the @strong{MySQL}
+data directory, and tables within a database to filenames in the database
+directory.
+This has two implications:
+
+@itemize @minus
+@item
+@cindex Database names, case sensitivity
+@cindex Table names, case sensitivity
+@cindex Case sensitivity, of database names
+@cindex Case sensitivity, of table names
+Database names and table names are case sensitive in @strong{MySQL} on
+operating systems that have case sensitive filenames (like most Unix
+systems). If you have a problem remembering table names, adopt a consistent
+convention, such as always creating databases and tables using lowercase
+names.
+
+@item
+Database, table, index, column or alias names may begin with a digit
+(but may not consist solely of digits).
+
+@item
+You can use standard system commands to backup, rename, move, delete and copy
+tables. For example, to rename a table, rename the @file{.MYD}, @file{.MYI}
+and @file{.frm} files to which the table corresponds.
+@end itemize
+
+@item
+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}.
+@strong{MySQL} dosen't support tablespaces like in:
+@code{create table ralph.my_table...IN my_tablespace}.
+
+@item
+@code{LIKE} is allowed on numeric columns.
+
+@item
+Use of @code{INTO OUTFILE} and @code{STRAIGHT_JOIN} in a @code{SELECT}
+statement. @xref{SELECT, , @code{SELECT}}.
+
+@item
+The @code{SQL_SMALL_RESULT} option in a @code{SELECT} statement.
+
+@item
+@code{EXPLAIN SELECT} to get a description on how tables are joined.
+
+@item
+Use of index names, indexes on a prefix of a field, and use of
+@code{INDEX} or @code{KEY} in a @code{CREATE TABLE}
+statement. @xref{CREATE TABLE, , @code{CREATE TABLE}}.
+
+@item
+Use of @code{TEMPORARY} or @code{IF NOT EXISTS} with @code{CREATE TABLE}.
+
+@item
+Use of @code{COUNT(DISTINCT list)} where 'list' is more than one element.
+
+@item
+Use of @code{CHANGE col_name}, @code{DROP col_name} or @code{DROP INDEX}
+in an @code{ALTER TABLE} statement. @xref{ALTER TABLE, , @code{ALTER TABLE}}.
+
+@item
+Use of @code{IGNORE} in an @code{ALTER TABLE} statement.
+
+@item
+Use of multiple @code{ADD}, @code{ALTER}, @code{DROP} or @code{CHANGE}
+clauses in an @code{ALTER TABLE} statement.
+
+@item
+Use of @code{DROP TABLE} with the keywords @code{IF EXISTS}.
+
+@item
+You can drop multiple tables with a single @code{DROP TABLE} statement.
+
+@item
+The @code{LIMIT} clause of the @code{DELETE} statement.
+
+@item
+The @code{DELAYED} clause of the @code{INSERT} and @code{REPLACE}
+statements.
+
+@item
+The @code{LOW_PRIORITY} clause of the @code{INSERT}, @code{REPLACE},
+@code{DELETE} and @code{UPDATE} statements.
+
+@cindex Oracle compatibility
+@cindex Compatibility, with Oracle
+@item
+Use of @code{LOAD DATA INFILE}. In many cases, this syntax is compatible with
+Oracle's @code{LOAD DATA INFILE}. @xref{LOAD DATA, , @code{LOAD DATA}}.
+
+@item
+The @code{OPTIMIZE TABLE} statement.
+@xref{OPTIMIZE TABLE, , @code{OPTIMIZE TABLE}}.
+
+@item
+The @code{SHOW} statement.
+@xref{SHOW, , @code{SHOW}}.
+
+@item
+Strings may be enclosed by either @samp{"} or @samp{'}, not just by @samp{'}.
+
+@item
+Use of the escape @samp{\} character.
+
+@item
+The @code{SET OPTION} statement. @xref{SET OPTION, , @code{SET OPTION}}.
+
+@item
+You don't need to name all selected columns in the @code{GROUP BY} part.
+This gives better performance for some very specific, but quite normal
+queries.
+@xref{Group by functions}.
+
+@item
+To make it easier for users that come from other SQL environments,
+@strong{MySQL} supports aliases for many functions. For example, all
+string functions support both ANSI SQL syntax and ODBC syntax.
+
+@item
+@strong{MySQL} understands the @code{||} and @code{&&} operators to mean
+logical OR and AND, as in the C programming language. In @strong{MySQL},
+@code{||} and @code{OR} are synonyms, as are @code{&&} and @code{AND}.
+Because of this nice syntax, @strong{MySQL} 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
+@strong{MySQL}.
+
+@item
+@code{CREATE DATABASE} or @code{DROP DATABASE}.
+@xref{CREATE DATABASE, , @code{CREATE DATABASE}}.
+
+@cindex PostgreSQL compatibility
+@cindex Compatibility, with PostgreSQL
+@item
+The @code{%} operator is a synonym for @code{MOD()}. That is,
+@code{N % M} is equivalent to @code{MOD(N,M)}. @code{%} is supported
+for C programmers and for compatibility with PostgreSQL.
+
+@item
+The @code{=}, @code{<>}, @code{<=} ,@code{<}, @code{>=},@code{>},
+@code{<<}, @code{>>}, @code{<=>}, @code{AND}, @code{OR} or @code{LIKE}
+operators may be used in column comparisons to the left of the
+@code{FROM} in @code{SELECT} statements. For example:
+
+@example
+mysql> SELECT col1=1 AND col2=2 FROM tbl_name;
+@end example
+
+@item
+The @code{LAST_INSERT_ID()} function.
+@xref{mysql_insert_id, , @code{mysql_insert_id()}}.
+
+@item
+The @code{REGEXP} and @code{NOT REGEXP} extended regular expression
+operators.
+
+@item
+@code{CONCAT()} or @code{CHAR()} with one argument or more than two
+arguments. (In @strong{MySQL}, 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{PERIOD_ADD()}, @code{PERIOD_DIFF()}, @code{TO_DAYS()}, or
+@code{WEEKDAY()} functions.
+
+@item
+Use of @code{TRIM()} to trim substrings. ANSI SQL only supports removal
+of single characters.
+
+@item
+The @code{GROUP BY} functions @code{STD()}, @code{BIT_OR()} and
+@code{BIT_AND()}.
+
+@item
+Use of @code{REPLACE} instead of @code{DELETE} + @code{INSERT}.
+@xref{REPLACE, , @code{REPLACE}}.
+
+@item
+The @code{FLUSH flush_option} statement.
+
+@item
+The possiblity 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;
+@end example
+
+@end itemize
+
+@node Ansi mode, Differences from ANSI, Extensions to ANSI, Compatibility
+@section Runnning MySQL in ANSI mode
+
+If you start mysqld with the @code{--ansi} option, the following behaviour
+of @strong{MySQL} changes.
+
+@itemize @bullet
+@item
+@code{||} is string concatenation instead of @code{OR}.
+@item
+One can have any number of spaces between a function name and the '('. This
+makes also all function names reserved words.
+@item
+@code{"} will be an identifier quote character (like the @strong{MySQL}
+@code{`} 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}.
+@end itemize
+
+@node Differences from ANSI, Missing functions, Ansi mode, Compatibility
+@section MySQL differences compared to ANSI SQL92
+
+We try to make @strong{MySQL} follow the ANSI SQL standard and the
+ODBC SQL standard, but in some cases @strong{MySQL} does some 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}.
+@item
+In some cases, @code{CHAR} columns are silently changed to @code{VARCHAR}
+columns. @xref{Silent column changes}.
+@item
+Privileges for a table is not automatically revoked when you delete a
+table. You must explicitly issue a @code{REVOKE} to revoke privileges for
+a table. @xref{GRANT, , @code{GRANT}}.
+@item
+@code{NULL AND FALSE} will evaluate to @code{NULL} and not to @code{FALSE}.
+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 Missing functions, Standards, Differences from ANSI, Compatibility
+@section Functionality missing from MySQL
+
+The following functionality is missing in the current version of
+@strong{MySQL}. For a prioritized list indicating when new extensions may be
+added to @strong{MySQL}, you should consult
+@uref{http://www.mysql.com/documentation/manual.php?section=TODO, the online
+@strong{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
+* Missing Views:: Views
+* Missing comments:: @samp{--} as the start of a comment
+@end menu
+
+@node Missing Sub-selects, Missing SELECT INTO TABLE, Missing functions, Missing functions
+@subsection Sub-selects
+
+The following will not yet work in @strong{MySQL}:
+
+@example
+SELECT * FROM table1 WHERE id IN (SELECT id FROM table2);
+SELECT * FROM table1 WHERE id NOT IN (SELECT id FROM table2);
+@end example
+
+However, in many cases you can rewrite the query without a sub select:
+
+@example
+SELECT table1.* FROM table1,table2 WHERE table1.id=table2.id;
+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
+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 @strong{MySQL}.
+
+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
+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
+@code{DELETE} statements automatically, using the @strong{MySQL}
+extension @code{CONCAT()} (in lieu of the standard @code{||} operator).
+For example:
+
+@example
+SELECT CONCAT('DELETE FROM tab1 WHERE pkid = ', tab1.pkid, ';')
+ FROM tab1, tab2
+ WHERE tab1.col1 = tab2.col2;
+@end example
+
+You can place this query in a script file and redirect input from it to
+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
+@end example
+
+@strong{MySQL} only supports @code{INSERT ... SELECT ...} and
+@code{REPLACE ... SELECT ...} Independent sub-selects will be probably
+be available in 3.24.0. You can now use the function @code{IN()} in
+other contexts, however.
+
+@node Missing SELECT INTO TABLE, Missing Transactions, Missing Sub-selects, Missing functions
+@subsection @code{SELECT INTO TABLE}
+
+@strong{MySQL} doesn't yet support the Oracle SQL extension:
+@code{SELECT ... INTO TABLE ...}. @strong{MySQL} supports instead the
+ANSI SQL syntax @code{INSERT INTO ... SELECT ...}, which is basically
+the same thing.
+
+Alternatively, you can use @code{SELECT INTO OUTFILE...} or @code{CREATE
+TABLE ... SELECT} to solve your problem.
+
+@node Missing Transactions, Missing Triggers, Missing SELECT INTO TABLE, Missing functions
+@subsection Transactions
+
+As @strong{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
+@strong{MySQL} not a transactional database?'' or ``Why does @strong{MySQL}
+not support transactions?''
+
+@strong{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 @strong{MySQL} 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
+corrupting activities are not commited to the database; the server is
+given the opportunity to do an automatic rollback and your database is
+saved.
+
+@strong{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
+@strong{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 @strong{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.
+
+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 or is necessary, and they
+may have to do a little more work with @strong{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 @strong{MySQL} has not addressed these
+issues. Reliability and integrity are foremost in our minds. Recent
+estimates are that there are more than 1,000,000 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 @strong{MySQL}'s stability and reliability.
+
+Lastly, in situations where integrity is of highest importance,
+@strong{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 relaease their read
+locks. With @code{INSERT DELAYED} you can queue inserts into a local queue,
+until the locks are released, without having to have the client wait
+for the insert to complete.
+
+``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 that there will never be an automatic
+rollback (which can happen on transaction based systems if you are not
+very careful). @strong{MySQL} also guarantees that there will not be
+any dirty reads. You can find some example of how to write atomic updates
+in the 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 @strong{MySQL}, there is a ``@strong{MySQL}
+way'' as we have outlined above. For those where safety is more important
+than speed, we recommend them to use the @code{BDB} tables for all their
+critical data. @xref{BDB}.
+
+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
+@subsection Stored procedures and triggers
+
+A stored procedure is a set of SQL commands that can be compiled and stored
+in the server. Once this has been done, clients don't need to keep reissuing
+the entire query but can refer to the stored procedure. This provides better
+performance because the query has to be parsed only once and less information
+needs to be sent between the server and the client. You can also raise the
+conceptual level by having libraries of functions in the server.
+
+A trigger is a stored procedure that is invoked when a particular event
+occurs. For example, you can install a stored procedure that is triggered
+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 @strong{MySQL} might get stored procedures, see @ref{TODO}.
+
+@node Missing Foreign Keys, Missing Views, Missing Triggers, Missing functions
+@subsection Foreign Keys
+
+Note that foreign keys in SQL are not used to join tables, but are used
+mostly for checking referential integrity. If you want to get results from
+multiple tables from a @code{SELECT} statement, you do this by joining
+tables!
+
+@example
+SELECT * from table1,table2 where table1.id = table2.id;
+@end example
+@xref{JOIN, , @code{JOIN}}. @xref{example-Foreign keys}.
+
+The @code{FOREIGN KEY} syntax in @strong{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. @strong{MySQL} only supports these clauses because some
+applications require them to exist (regardless of whether or not they
+work!).
+
+In @strong{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.
+
+@menu
+* Broken Foreign KEY:: Reasons NOT to use foreign keys
+@end menu
+
+@node Broken Foreign KEY, , Missing Foreign Keys, Missing Foreign Keys
+@subsubsection Reasons NOT to use foreign keys
+
+There are so many problems with @code{FOREIGN KEY}s that we don't
+know where to start:
+
+@itemize @bullet
+@item
+Foreign keys 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.
+
+@item
+The speed impact is terrible for @code{INSERT} and @code{UPDATE} statements,
+and in this case almost all @code{FOREIGN KEY} checks are useless because you
+usually insert records in the right tables in the right order, anyway.
+
+@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.
+
+@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).
+
+@item
+If you have foreign keys you can't dump and restore tables unless you do so
+in a very specific order.
+
+@item
+It's very easy to do ``allowed'' circular definitions that make the
+tables impossible to recreate each table with a single create statement,
+even if the definition works and is usable.
+@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 applicatons.
+
+@strong{MySQL} will soon store @code{FOREIGN KEY} definitions so that
+a client can ask for and receive an answer how the original connection was
+made. The current @file{.frm} file format does not have any place for it.
+
+@node Missing Views, Missing comments, Missing Foreign Keys, Missing functions
+@subsection Views
+
+@strong{MySQL} doesn't support views, but this is on the TODO.
+
+@node Missing comments, , Missing Views, Missing functions
+@subsection @samp{--} as the start of a comment
+
+Some other SQL databases use @samp{--} to start comments. @strong{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
+@strong{MySQL}.
+@xref{Comments}.
+
+@strong{MySQL} 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
+@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?
+
+Because @code{1--1} is legal in SQL, we think it is terrible that
+@samp{--} means start comment.
+
+In @strong{MySQL} 3.23 you can however use: @code{1-- This is a comment}
+
+The following discussing only concerns you if you are running an
+@strong{MySQL} version earlier than 3.23:
+
+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 \
+ | mysql database
+@end example
+
+instead of the usual:
+
+@example
+shell> mysql database < text-file-with-funny-comments.sql
+@end example
+
+You can also edit the command file ``in place'' to change the @samp{--}
+comments to @samp{#} comments:
+
+@example
+shell> replace " --" " #" -- text-file-with-funny-comments.sql
+@end example
+
+Change them back with this command:
+
+@example
+shell> replace " #" " --" -- text-file-with-funny-comments.sql
+@end example
+
+@node Standards, Commit-rollback, Missing functions, Compatibility
+@section What standards does MySQL follow?
+
+Entry level SQL92. ODBC level 0-2.
+
+@node Commit-rollback, , Standards, Compatibility
+@section How to cope without @code{COMMIT}/@code{ROLLBACK}
+
+The following mostly apply only for @code{ISAM}, @code{MyISAM} and
+@code{HEAP} tables; If you only use transaction safe tables (@code{BDB}
+tables) in an a update you can do @code{COMMIT} and @code{ROLLBACK} also
+with @code{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 @strong{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 these table types about 2-4 times
+slower than they are today.
+
+For the moment, we are much more for 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, @strong{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 have changed and test only that none of
+the changed data, or data that depend on the changed data, have 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 Row-level 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
+
+@strong{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 @strong{MySQL} changed the above query to:
+
+@example
+UPDATE tbl_name SET row_flag=1 WHERE id=ID and row_flag <> 1;
+@end example
+
+@node Privilege system, Reference, Compatibility, Top
+@chapter The MySQL access privilege system
+
+@strong{MySQL} has an advanced but non-standard security/privilege
+system. This section describes how it works.
+
+@menu
+* General security:: General security
+* Security:: How to make @strong{MySQL} secure against crackers
+* What Privileges:: What the privilege system does
+* User names:: @strong{MySQL} user names and passwords
+* Connecting:: Connecting to the @strong{MySQL} server
+* Password security:: Keeping your password secure
+* Privileges provided:: Privileges provided by @strong{MySQL}
+* Privileges:: How the privilege system works
+* Connection access:: Access control, stage 1: Connection verification
+* Request access:: Access control, stage 2: Request verification
+* Privilege changes:: When privilege changes take effect
+* Default privileges:: Setting up the initial @strong{MySQL} privileges
+* Adding users:: Adding new user privileges to @strong{MySQL}
+* Passwords:: How to set up passwords
+* Access denied:: Causes of @code{Access denied} errors
+@end menu
+
+@node General security, Security, Privilege system, Privilege system
+@section General security
+
+Anyone using @strong{MySQL} on a computer connected to the Internet
+should read this section to avoid the most common security mistakes.
+
+In discussing ``security'' we emphasize the necessity of fully protecting the
+entire server host (not simply the @strong{MySQL} server) against all types
+of applicable attacks: eavesdropping, altering, playback and Denial of
+Service. We do not cover all aspects of availability and fault tolerance
+here.
+
+@strong{MySQL} uses Access Control Lists (ACLs) security for all
+connections, queries, and other operations which a user may attempt to
+perform. There is also some support for SSL encrypted connections
+between @strong{MySQL} clients and servers. Many of the concepts
+discussed here are not specific to @strong{MySQL} at all; the same
+general ideas apply to almost all applications.
+
+When running @strong{MySQL}, follow these guidelines whenever possible:
+
+@itemize @bullet
+@item
+Learn the @strong{MySQL} access privilege system. The @code{GRANT} and
+@code{REVOKE} commands are used for restricting access to @strong{MySQL}. Do
+not grant any more privileges than necessary. Never grant privileges to all
+hosts.
+
+Checklist:
+@itemize @bullet
+@item
+Try @code{mysql -u root}. If you are able to connect successfully to the
+server without being asked for a password, you have problems. Any user (not
+just root) can connect to your @strong{MySQL} server with full privileges!
+Review the @strong{MySQL} installation instructions, paying particular
+attention to the item about setting a @code{root} password.
+@item
+Use the command @code{SHOW GRANTS} and check to see who has access to
+what. Remove those privileges which are not necessary using the @code{REVOKE}
+command.
+@end itemize
+
+@item
+Do not keep any plain-text passwords in your database. When your
+computer becomes compromised, the intruder can take the full list of
+passwords and use them. Instead use @code{MD5()} or another one-way
+hashing function.
+@item
+Do not use passwords from dictionaries. There are special programs to
+break them. Even passwords like ``xfish98'' are very bad. Much better is
+``duag98'' which contains the same word ``fish'' but typed one key to the
+left on a standard QWERTY keyboard. Another method is to use ``Mhall'' which
+is taken from first characters of sentence ``Mary had a little lamb''. This
+is easy to remember and type, but hard to guess for someone who does not know
+it.
+@item
+Invest in a firewall. This protects from at least 50% of all types of
+exploits in any software. Put @strong{MySQL} behind the firewall or in
+a demilitarized zone (DMZ).
+
+Checklist:
+@itemize @bullet
+@item
+Try to scan your ports from the Internet using a tool such as
+@code{nmap}. @strong{MySQL} uses port 3306 by default. This port should
+be inaccessible from untrusted hosts. Another simple way to check whether or not
+your @strong{MySQL} port is open is to type @code{telnet
+server_host 3306} from some remote machine, where
+@code{server_host} is the hostname of your @strong{MySQL}
+server. If you get a connection and some garbage characters, the port is
+open, and should be closed on your firewall or router, unless you really
+have a good reason to keep it open. If @code{telnet} just hangs,
+everything is OK, the port is blocked.
+@end itemize
+
+@item
+Do not trust any data entered by your users. They can try to trick your
+code by entering special or escaped character sequences in web forms,
+URLs, or whatever application you have built. Be sure that your
+application remains secure if user enters something like @code{; DROP
+DATABASE mysql;}. This is an extreme example, but large security leaks
+and data loss may occur as a result of hackers using similar techniques,
+if you do not prepare for them.
+
+Also remember to check numeric data. A common mistake is to protect only
+strings. Sometimes people think that if a database contains only publicly
+available data that it need not be protected. This is incorrect. At least
+Denial-of-Service type attacks can be performed on such
+databases. The simplest way to protect from this type of attack is to use
+apostrophes around the numeric constants: @code{SELECT * FROM table
+WHERE ID='234'} instead of @code{SELECT * FROM table WHERE ID=234}.
+@strong{MySQL} automatically converts this string to a number and
+meanwhile strips all non-numeric symbols from it.
+
+Checklist:
+@itemize @bullet
+@item
+All WWW applications:
+@itemize @bullet
+@item
+Try to enter @samp{'} and @samp{"} in all your Web forms. If you get any kind
+of @strong{MySQL} error, investigate the problem right away.
+@item
+Try to modify any dynamic URLs by adding @code{%22} (@samp{"}), @code{%23}
+(@samp{#}) and @code{%27} (@samp{'}) in the URL.
+@item
+Try to modify datatypes in dynamic URLs from numeric ones to character
+ones containing characters from previous example. Your application
+should be safe against this and similar attacks.
+@item
+Try to enter characters, spaces, special symbols instead of numbers in
+numeric fields. Your application should remove them before passing them to
+@strong{MySQL} or your application should generate an error. Passing
+unchecked values to @strong{MySQL} is very dangerous!
+@item
+Check data sizes before passing them to @strong{MySQL}.
+@item
+Consider having your application connect to the database using a
+different user name than the one you use for administrative purposes. Do not give
+your applications any more access privileges than what they need.
+@end itemize
+@item
+Users of PHP:
+@itemize @bullet
+@item
+Check out the @code{addslashes()} function.
+@end itemize
+@item
+Users of @strong{MySQL} C API:
+@itemize @bullet
+@item
+Check out the @code{mysql_escape()} API call.
+@end itemize
+@item
+Users of @strong{MySQL}++:
+@itemize @bullet
+@item
+Check out the @code{escape} and @code{quote} modifiers for query streams.
+@end itemize
+@item
+Users of Perl DBI
+@itemize @bullet
+@item
+Check out the @code{quote()} method.
+@end itemize
+@end itemize
+
+@item
+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. @strong{MySQL} supports internal SSL connections as of version 3.23.9.
+SSH port-forwarding can be used to create an encrypted (and compressed)
+tunnel for the communication.
+@item
+Learn to use the @code{tcpdump} and @code{strings} utilities. For most cases,
+you can check whether or not @strong{MySQL} data streams are unencrypted
+by issuing a command like the following:
+
+@example
+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
+actually mean that it is encrypted. If you need high security, you should
+consult with a security expert.
+@end itemize
+
+@node Security, What Privileges, General security, Privilege system
+@section How to make MySQL secure against crackers
+
+When you connect to a @strong{MySQL} server, you normally should use a
+password. The password is not transmitted in clear text over the
+connection.
+
+All other information is transferred as text that can be read by anyone
+that is able to watch the connection. If you are concerned about this,
+you can use the compressed protocol (in @strong{MySQL} 3.22 and above)
+to make things much harder. To make things even more secure you should
+use @code{ssh} (see @uref{http://www.cs.hut.fi/ssh}). With this, you
+can get an encrypted TCP/IP connection between a @strong{MySQL} server
+and a @strong{MySQL} client.
+
+To make a @strong{MySQL} system secure, you should strongly consider the
+following suggestions:
+
+@itemize @bullet
+@item
+Use passwords for all @strong{MySQL} users. Remember that anyone can log in
+as any other person as simply as @code{mysql -u other_user db_name} if
+@code{other_user} has no password. It is common behavior with client/server
+applications that the client may specify any user name. You can change the
+password of all users by editing the @code{mysql_install_db} script before
+you run it, or only the password for the @strong{MySQL} @code{root} user like
+this:
+
+@example
+shell> mysql -u root mysql
+mysql> UPDATE user SET Password=PASSWORD('new_password')
+ WHERE user='root';
+mysql> FLUSH PRIVILEGES;
+@end example
+
+@item
+Don't run the @strong{MySQL} daemon as the Unix @code{root} user.
+It is very dangerous as any user with @code{FILE} privileges will be able to
+create files
+as @code{root} (e.g. @code{~root/.bashrc}). To prevent this
+@code{mysqld} will refuse to run as @code{root} unless it is specified
+directly via @code{--user=root} option.
+
+@code{mysqld} can be run as any user instead. You can also create a new
+Unix user @code{mysql} to make everything even more secure. If you run
+@code{mysqld} as another Unix user, you don't need to change the
+@code{root} user name in the @code{user} table, because @strong{MySQL}
+user names have nothing to do with Unix user names. You can edit the
+@code{mysql.server} script to start @code{mysqld} as another Unix user.
+Normally this is done with the @code{su} command. For more details, see
+@ref{Changing MySQL user, , Changing @strong{MySQL} user}.
+
+@item
+If you put a password for the Unix @code{root} user in the @code{mysql.server}
+script, make sure this script is readable only by @code{root}.
+
+@item
+Check that the Unix user that @code{mysqld} runs as is the only user with
+read/write privileges in the database directories.
+
+@item
+On Unix platforms, do not run @code{mysqld} as root unless you really
+need to. Consider creating a user named @code{mysql} for that purpose.
+
+@item
+Don't give the @strong{process} privilege to all users. The output of
+@code{mysqladmin processlist} shows the text of the currently executing
+queries, so any user who is allowed to execute that command might be able to
+see if another user issues an @code{UPDATE user SET
+password=PASSWORD('not_secure')} query.
+
+@code{mysqld} reserves an extra connection for users who have the
+@strong{process} privilege, so that a @strong{MySQL} @code{root} user can log
+in and check things even if all normal connections are in use.
+
+@item
+Don't give the @strong{file} privilege to all users. Any user that has this
+privilege can write a file anywhere in the file system with the privileges of
+the @code{mysqld} daemon! To make this a bit safer, all files generated with
+@code{SELECT ... INTO OUTFILE} are readable to everyone, and you can't
+overwrite existing files.
+
+@tindex /etc/passwd
+The @strong{file} privilege may also be used to read any file accessible
+to the Unix user that the server runs as. This could be abused, for example,
+by using @code{LOAD DATA} to load @file{/etc/passwd} into a table, which
+can then be read with @code{SELECT}.
+
+@item
+If you don't trust your DNS, you should use IP numbers instead of hostnames
+in the grant tables. In principle, the @code{--secure} option to
+@code{mysqld} should make hostnames safe. In any case, you should be very
+careful about creating grant table entries using hostname values that
+contain wildcards!
+@end itemize
+
+The following @code{mysqld} options affect networking security:
+
+@table @code
+@item --secure
+IP numbers returned by the @code{gethostbyname()} system call are checked to
+make sure they resolve back to the original hostname. This makes it harder
+for someone on the outside to get access by pretending to be another host. This
+option also adds some sanity checks of hostnames. The option is turned off
+by default in @strong{MySQL} 3.21 because sometimes it takes a long time to
+perform backward resolutions. @strong{MySQL} 3.22 caches hostnames and has
+this option enabled by default.
+
+@item --skip-grant-tables
+This option causes the server not to use the privilege system at all. This
+gives everyone @emph{full access} to all databases! (You can tell a running
+server to start using the grant tables again by executing @code{mysqladmin
+flush-privileges} or @code{mysqladmin reload}.)
+
+@item --skip-name-resolve
+Hostnames are not resolved. All @code{Host} column values in the grant
+tables must be IP numbers or @code{localhost}.
+
+@item --skip-networking
+Don't allow TCP/IP connections over the network. All connections to
+@code{mysqld} must be made via Unix sockets. This option is unsuitable for
+systems that use MIT-pthreads, because the MIT-pthreads package doesn't
+support Unix sockets.
+@end table
+
+@node What Privileges, User names, Security, Privilege system
+@section What the privilege system does
+
+The primary function of the @strong{MySQL} privilege system is to
+authenticate a user connecting from a given host, and to associate that user
+with privileges on a database such as
+@strong{select}, @strong{insert}, @strong{update} and @strong{delete}.
+
+Additional functionality includes the ability to have an anonymous user and
+to grant privileges for @strong{MySQL}-specific functions such as @code{LOAD
+DATA INFILE} and administrative operations.
+
+@node User names, Connecting, What Privileges, Privilege system
+@section MySQL user names and passwords
+
+There are several distinctions between the way user names and passwords are
+used by @strong{MySQL}, and the way they are used by Unix or Windows:
+
+@itemize @bullet
+@item
+User names, as used by @strong{MySQL} for authentication purposes, have
+nothing to do with Unix user names (login names) or Windows user names. Most
+@strong{MySQL} clients by default try to log in using the current Unix user
+name as the @strong{MySQL} user name, but that is for convenience only.
+Client programs allow a different name to be specified with the @code{-u} or
+@code{--user} options. This means that you can't make a database secure in
+any way unless all @strong{MySQL} user names have passwords. Anyone may
+attempt to connect to the server using any name, and they will succeed if
+they specify any name that doesn't have a password.
+
+@item
+@strong{MySQL} user names can be up to 16 characters long; Unix user names
+typically are limited to 8 characters.
+
+@item
+@strong{MySQL} passwords have nothing to do with Unix passwords. There is no
+necessary connection between the password you use to log in to a Unix machine
+and the password you use to access a database on that machine.
+
+@item
+@strong{MySQL} encrypts passwords using a different algorithm than the one
+used during the Unix login process. See the descriptions of the
+@code{PASSWORD()} and @code{ENCRYPT()} functions in @ref{Miscellaneous
+functions}.
+@end itemize
+
+@node Connecting, Password security, User names, Privilege system
+@section Connecting to the MySQL server
+
+@strong{MySQL} client programs generally require that you specify connection
+parameters when you want to access a @strong{MySQL} server: the host you want
+to connect to, your user name and your password. For example, the
+@code{mysql} client can be started like this (optional arguments are enclosed
+between @samp{[} and @samp{]}):
+
+@example
+shell> mysql [-h host_name] [-u user_name] [-pyour_pass]
+@end example
+
+Alternate forms of the @code{-h}, @code{-u} and @code{-p} options are
+@code{--host=host_name}, @code{--user=user_name} and
+@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!
+Any user on your system may then find out your password by typing a command
+like: @code{ps auxww}. @xref{Option files}.
+
+@code{mysql} uses default values for connection parameters that are missing
+from the command line:
+
+@itemize @bullet
+@item
+The default hostname is @code{localhost}.
+
+@item
+The default user name is your Unix login name.
+
+@item
+No password is supplied if @code{-p} is missing.
+@end itemize
+
+Thus, for a Unix user @code{joe}, the following commands are equivalent:
+
+@example
+shell> mysql -h localhost -u joe
+shell> mysql -h localhost
+shell> mysql -u joe
+shell> mysql
+@end example
+
+Other @strong{MySQL} clients behave similarly.
+
+On Unix systems, you can specify different default values to be used when you
+make a connection, so that you need not enter them on the command line each
+time you invoke a client program. This can be done in a couple of ways:
+
+@itemize @bullet
+@item
+@tindex .my.cnf file
+You can specify connection parameters in the @code{[client]} section of the
+@file{.my.cnf} configuration file in your home directory. The relevant
+section of the file might look like this:
+
+@example
+[client]
+host=host_name
+user=user_name
+password=your_pass
+@end example
+
+@xref{Option files}.
+
+@item
+@tindex MYSQL_HOST environment variable
+@tindex Environment variable, MYSQL_HOST
+@tindex MYSQL_PWD environment variable
+@tindex Environment variable, MYSQL_PWD
+@tindex USER environment variable
+@tindex Environment variable, USER
+You can specify connection parameters using environment variables. The
+host can be specified for @code{mysql} using @code{MYSQL_HOST}. The
+@strong{MySQL} user name can be specified using @code{USER} (this is for
+Windows only). The password can be specified using @code{MYSQL_PWD}
+(but this is insecure; see next section). @xref{Environment variables}.
+@end itemize
+
+@node Password security, Privileges provided, Connecting, Privilege system
+@section Keeping your password secure
+
+It is inadvisable to specify your password in a way that exposes it to
+discovery by other users. The methods you can use to specify your password
+when you run client programs are listed below, along with an assessment of
+the risks of each method:
+
+@itemize @bullet
+@item
+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. (@strong{MySQL} clients typically overwrite
+the command line argument with zeroes during their initialization sequence,
+but there is still a brief interval during which the value is visible.)
+
+@item
+Use a @code{-p} or @code{--password} option (with no @code{your_pass} value
+specified). In this case, the client program solicits the password from
+the terminal:
+
+@example
+shell> mysql -u user_name -p
+Enter password: ********
+@end example
+
+The client echoes @samp{*} characters to the terminal as you enter your
+password so that onlookers cannot see it.
+
+It is more secure to enter your password this way than to specify it on the
+command line because it is not visible to other users. However, this method
+of entering a password is suitable only for programs that you run
+interactively. If you want to invoke a client from a script that runs
+non-interactively, there is no opportunity to enter the password from the
+terminal. On some systems, you may even find that the first line of your
+script is read and interpreted (incorrectly) as your password!
+
+@item
+@tindex .my.cnf file
+Store your password in a configuration file. For example, you can list your
+password in the @code{[client]} section of the @file{.my.cnf} file in your
+home directory:
+
+@example
+[client]
+password=your_pass
+@end example
+
+If you store your password in @file{.my.cnf}, the file should not be group or
+world readable or writable. Make sure the file's access mode is @code{400}
+or @code{600}.
+
+@xref{Option files}.
+@item
+You can store your password in the @code{MYSQL_PWD} environment variable, but
+this method must be considered extremely insecure and should not be used.
+Some versions of @code{ps} include an option to display the environment of
+running processes; your password will be in plain sight for all to see if
+you set @code{MYSQL_PWD}. Even on systems without such a version of
+@code{ps}, it is unwise to assume there is no other method to observe process
+environments. @xref{Environment variables}.
+@end itemize
+
+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 Privileges provided, Privileges, Password security, Privilege system
+@section Privileges provided by MySQL
+
+Privilege information is stored in the @code{user}, @code{db}, @code{host},
+@code{tables_priv} and @code{columns_priv} tables in the @code{mysql}
+database (that is, in the database named @code{mysql}). The @strong{MySQL}
+server reads the contents of these tables when it starts up and under the
+circumstances indicated in @ref{Privilege changes}.
+
+The names used in this manual to refer to the privileges provided by
+@strong{MySQL} are shown below, along with the table column name associated
+with each privilege in the grant tables and the context in which the
+privilege applies:
+
+@multitable @columnfractions .15 .25 .6
+@item @strong{Privilege} @tab @strong{Column} @tab @strong{Context}
+@item @strong{select} @tab @code{Select_priv} @tab tables
+@item @strong{insert} @tab @code{Insert_priv} @tab tables
+@item @strong{update} @tab @code{Update_priv} @tab tables
+@item @strong{delete} @tab @code{Delete_priv} @tab tables
+@item @strong{index} @tab @code{Index_priv} @tab tables
+@item @strong{alter} @tab @code{Alter_priv} @tab tables
+@item @strong{create} @tab @code{Create_priv} @tab databases, tables or indexes
+@item @strong{drop} @tab @code{Drop_priv} @tab databases or tables
+@item @strong{grant} @tab @code{Grant_priv} @tab databases or tables
+@item @strong{references} @tab @code{References_priv} @tab databases or tables
+@item @strong{reload} @tab @code{Reload_priv} @tab server administration
+@item @strong{shutdown} @tab @code{Shutdown_priv} @tab server administration
+@item @strong{process} @tab @code{Process_priv} @tab server administration
+@item @strong{file} @tab @code{File_priv} @tab file access on server
+@end multitable
+
+The @strong{select}, @strong{insert}, @strong{update} and @strong{delete}
+privileges allow you to perform operations on rows in existing tables in
+a database.
+
+@code{SELECT} statements require the @strong{select} privilege only if they
+actually retrieve rows from a table. You can execute certain @code{SELECT}
+statements even without permission to access any of the databases on the
+server. For example, you could use the @code{mysql} client as a simple
+calculator:
+
+@example
+mysql> SELECT 1+1;
+mysql> SELECT PI()*2;
+@end example
+
+The @strong{index} privilege allows you to create or drop (remove) indexes.
+
+The @strong{alter} privilege allows you to use @code{ALTER TABLE}.
+
+The @strong{create} and @strong{drop} privileges allow you to create new
+databases and tables, or to drop (remove) existing databases and tables.
+
+Note that if you grant the @strong{drop} privilege for the @code{mysql}
+database to a user, that user can drop the database in which the
+@strong{MySQL} access privileges are stored!
+
+The @strong{grant} privilege allows you to give to other users those
+privileges you yourself possess.
+
+The @strong{file} privilege gives you permission to read and write files on
+the server using the @code{LOAD DATA INFILE} and @code{SELECT ... INTO
+OUTFILE} statements. Any user to whom this privilege is granted can read or
+write any file that the @strong{MySQL} server can read or write.
+
+The remaining privileges are used for administrative operations, which are
+performed using the @code{mysqladmin} program. The table below shows which
+@code{mysqladmin} commands each administrative privilege allows you to
+execute:
+
+@multitable @columnfractions .15 .85
+@item @strong{Privilege} @tab @strong{Commands permitted to privilege holders}
+@item @strong{reload} @tab @code{reload}, @code{refresh},
+@code{flush-privileges},
+@code{flush-hosts}, @code{flush-logs}, @code{flush-tables}
+@item @strong{shutdown} @tab @code{shutdown}
+@item @strong{process} @tab @code{processlist}, @code{kill}
+@end multitable
+
+The @code{reload} command tells the server to reread the grant tables. The
+@code{refresh} command flushes all tables and opens and closes the log
+files. @code{flush-privileges} is a synonym for @code{reload}. The other
+@code{flush-*} commands perform functions similar to @code{refresh} but are
+more limited in scope, and may be preferable in some instances. For example,
+if you want to flush just the log files, @code{flush-logs} is a better choice
+than @code{refresh}.
+
+The @code{shutdown} command shuts down the server.
+
+The @code{processlist} command displays information about the threads
+executing within the server. The @code{kill} command kills server threads.
+You can always display or kill your own threads, but you need the
+@strong{process} privilege to display or kill threads initiated by other
+users.
+
+It is a good idea in general to grant privileges only to those users who need
+them, but you should exercise particular caution in granting certain
+privileges:
+
+@itemize @bullet
+@item
+The @strong{grant} privilege allows users to give away their privileges to
+other users. Two users with different privileges and with the @strong{grant}
+privilege are able to combine privileges.
+
+@item
+The @strong{alter} privilege may be used to subvert the privilege system
+by renaming tables.
+
+@item
+The @strong{file} privilege can be abused to read any world-readable file on
+the server into a database table, the contents of which can then be
+accessed using @code{SELECT}. This includes the contents of all databases
+hosted by the server!
+
+@item
+The @strong{shutdown} privilege can be abused to deny service to other
+users entirely, by terminating the server.
+
+@item
+The @strong{process} privilege can be used to view the plain text of
+currently executing queries, including queries that set or change passwords.
+
+@item
+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. However, with sufficient privileges,
+that same user can replace a password with a different one.)
+@end itemize
+
+There are some things that you cannot do with the @strong{MySQL}
+privilege system:
+
+@itemize @bullet
+@item
+You cannot explicitly specify that a given user should be denied access.
+That is, you cannot explicitly match a user and then refuse the connection.
+
+@item
+You cannot specify that a user has privileges to create or drop tables
+in a database but not to create or drop the database itself.
+@end itemize
+
+@node Privileges, Connection access, Privileges provided, Privilege system
+@section How the privilege system works
+
+The @strong{MySQL} privilege system ensures that all users may do exactly the
+things that they are supposed to be allowed to do. When you connect to a
+@strong{MySQL} server, your identity is determined by @strong{the host from
+which you connect} and @strong{the user name you specify}. The system grants
+privileges according to your identity and @strong{what you want to do}.
+
+@strong{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}.
+@strong{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}.
+
+@strong{MySQL} access control involves two stages:
+
+@itemize @bullet
+@item
+Stage 1: The server checks whether or not you are even allowed to connect.
+
+@item
+Stage 2: Assuming you can connect, the server checks each request you issue
+to see whether or not you have sufficient privileges to perform it. For
+example, if you try to select rows from a table in a database or drop a table
+from the database, the server makes sure you have the @strong{select}
+privilege for the table or the @strong{drop} privilege for the database.
+@end itemize
+
+The server uses the @code{user}, @code{db} and @code{host} tables in the
+@code{mysql} database at both stages of access control. The fields in these
+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{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
+@end multitable
+
+For the second stage of access control (request verification), the server
+may, if the request involves tables, additionally consult the
+@code{tables_priv} and @code{columns_priv} tables. The fields in these
+tables are shown below:
+
+@multitable @columnfractions .2 .25 .25
+@item @strong{Table name} @tab @code{tables_priv} @tab @code{columns_priv}
+
+@item @strong{Scope fields} @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{Privilege fields} @tab @code{Table_priv} @tab @code{Column_priv}
+@item @tab @code{Column_priv} @tab
+
+@item @strong{Other fields} @tab @code{Timestamp} @tab @code{Timestamp}
+@item @tab @code{Grantor} @tab
+@end multitable
+
+Each grant table contains scope fields and privilege fields.
+
+Scope fields determine the scope of each entry in the tables, i.e., the
+context in which the entry applies. For example, a @code{user} table entry
+with @code{Host} and @code{User} values of @code{'thomas.loc.gov'} and
+@code{'bob'} would be used for authenticating connections made to the server
+by @code{bob} from the host @code{thomas.loc.gov}. Similarly, a @code{db}
+table entry with @code{Host}, @code{User} and @code{Db} fields of
+@code{'thomas.loc.gov'}, @code{'bob'} and @code{'reports'} would be used when
+@code{bob} connects from the host @code{thomas.loc.gov} to access the
+@code{reports} database. The @code{tables_priv} and @code{columns_priv}
+tables contain scope fields indicating tables or table/column combinations
+to which each entry applies.
+
+@cindex Case sensitivity, in access checking
+For access-checking purposes, comparisons of @code{Host} values are
+case insensitive. @code{User}, @code{Password}, @code{Db} and
+@code{Table_name} values are case sensitive.
+@code{Column_name} values are case insensitive in @strong{MySQL} 3.22.12
+or later.
+
+Privilege fields indicate the privileges granted by a table entry, that is,
+what operations can be performed. The server combines the information in the
+various grant tables to form a complete description of a user's privileges.
+The rules used to do this are described in @ref{Request access}.
+
+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
+@code{tables_priv} and @code{columns_priv} tables)
+@item @code{Table_name} @tab @code{CHAR(60)}
+@item @code{Column_name} @tab @code{CHAR(60)}
+@end multitable
+
+In the @code{user}, @code{db} and @code{host} tables,
+all privilege fields are declared as @code{ENUM('N','Y')} --- each can have a
+value of @code{'N'} or @code{'Y'}, and the default value is @code{'N'}.
+
+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'}
+@end multitable
+
+Briefly, the server uses the grant tables like this:
+
+@itemize @bullet
+@item
+The @code{user} table scope fields determine whether to allow or reject
+incoming connections. For allowed connections, any privileges granted in
+the @code{user} table indicate the user's global (superuser) privileges.
+These privileges apply to @strong{all} databases on the server.
+
+@item
+The @code{db} and @code{host} tables are used together:
+
+@itemize @minus
+@item
+The @code{db} table scope fields determine which users can access which
+databases from which hosts. The privilege fields determine which operations
+are allowed.
+
+@item
+The @code{host} table is used as an extension of the @code{db} table when you
+want a given @code{db} table entry to apply to several hosts. For example,
+if you want a user to be able to use a database from several hosts in
+your network, leave the @code{Host} value empty in the user's @code{db} table
+entry, then populate the @code{host} table with an entry for each of those
+hosts. This mechanism is described more detail in @ref{Request access}.
+@end itemize
+
+@item
+The @code{tables_priv} and @code{columns_priv} tables are similar to
+the @code{db} table, but are more fine-grained: they apply at the
+table and column level rather than at the database level.
+@end itemize
+
+Note that administrative privileges (@strong{reload}, @strong{shutdown},
+etc.) are specified only in the @code{user} table. This is because
+administrative operations are operations on the server itself and are not
+database-specific, so there is no reason to list such privileges in the
+other grant tables. In fact, only the @code{user} table need
+be consulted to determine whether or not you can perform an administrative
+operation.
+
+The @strong{file} privilege is specified only in the @code{user} table, too.
+It is not an administrative privilege as such, but your ability to read or
+write files on the server host is independent of the database you are
+accessing.
+
+The @code{mysqld} server reads the contents of the grant tables once, when it
+starts up. Changes to the grant tables take effect as indicated in
+@ref{Privilege changes}.
+
+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,
+@ref{Security}.
+
+A useful
+diagnostic tool is the @code{mysqlaccess} script, which Yves Carlier has
+provided for the @strong{MySQL} distribution. Invoke @code{mysqlaccess} with
+the @code{--help} option to find out how it works.
+Note that @code{mysqlaccess} checks access using only the @code{user},
+@code{db} and @code{host} tables. It does not check table- or column-level
+privileges.
+
+@node Connection access, Request access, Privileges, Privilege system
+@section Access control, stage 1: Connection verification
+
+When you attempt to connect to a @strong{MySQL} server, the server accepts or
+rejects the connection based on your identity and whether or not you can
+verify your identity by supplying the correct password. If not, the server
+denies access to you completely. Otherwise, the server accepts the
+connection, then enters stage 2 and waits for requests.
+
+Your identity is based on two pieces of information:
+
+@itemize @bullet
+@item
+The host from which you connect
+
+@item
+Your @strong{MySQL} user name
+@end itemize
+
+Identity checking is performed using the three @code{user} table scope fields
+(@code{Host}, @code{User} and @code{Password}). The server accepts the
+connection only if a @code{user} table entry matches your hostname and user
+name, and you supply the correct password.
+
+Values in the @code{user} table scope fields may be specified as follows:
+
+@itemize @bullet
+@item
+A @code{Host} value may be a hostname or an IP number, or @code{'localhost'}
+to indicate the local host.
+
+@item
+@cindex Wildcards, in @code{mysql.user} table
+You can use the wildcard characters @samp{%} and @samp{_} in the @code{Host}
+field.
+
+@item
+A @code{Host} value of @code{'%'} matches any hostname. A blank @code{Host}
+value is equivalent to @code{'%'}. Note that these values match @emph{any
+host that can create a connection to your server!}
+
+@cindex Netmask notation, in @code{mysql.user} table
+@item
+As of MySQL 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
+GRANT ALL PRIVILEGES on db.* to david@'192.58.197.0/255.255.255.0';
+@end example
+
+This will allow everyone to connect from an IP where the following is true:
+
+@example
+user_ip & netmask = host_ip.
+@end example
+
+In the above example all IP:s in the interval 192.58.197.0 -
+192.58.197.255 can connect to the @strong{MySQL} server.
+
+@item
+@cindex Anonymous user
+Wildcard characters are not allowed in the @code{User} field, but you can
+specify a blank value, which matches any name. If the @code{user} table
+entry that matches an incoming connection has a blank user name, the user is
+considered to be the anonymous user (the user with no name), rather than the
+name that the client actually specified. This means that a blank user name
+is used for all further access checking for the duration of the connection
+(that is, during stage 2).
+
+@item
+The @code{Password} field can be blank. This does not mean that any password
+matches, it means the user must connect without specifying a password.
+@end itemize
+
+@findex PASSWORD()
+Non-blank @code{Password} values represent encrypted passwords.
+@strong{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) and compared to the
+already-encrypted version stored in the @code{user} table. If they match,
+the password is correct.
+
+The examples below show how various combinations of @code{Host} and
+@code{User} values in @code{user} table entries apply to incoming
+connections:
+
+@multitable @columnfractions .25 .15 .60
+@item @code{Host} @strong{value} @tab @code{User} @strong{value} @tab @strong{Connections matched by entry}
+@item @code{'thomas.loc.gov'} @tab @code{'fred'} @tab @code{fred}, connecting from @code{thomas.loc.gov}
+@item @code{'thomas.loc.gov'} @tab @code{''} @tab Any user, connecting from @code{thomas.loc.gov}
+@item @code{'%'} @tab @code{'fred'} @tab @code{fred}, connecting from any host
+@item @code{'%'} @tab @code{''} @tab Any user, connecting from any host
+@item @code{'%.loc.gov'} @tab @code{'fred'} @tab @code{fred}, connecting from any host in the @code{loc.gov} domain
+@item @code{'x.y.%'} @tab @code{'fred'} @tab @code{fred}, connecting from @code{x.y.net}, @code{x.y.com},@code{x.y.edu}, etc. (this is probably not useful)
+@item @code{'144.155.166.177'} @tab @code{'fred'} @tab @code{fred}, connecting from the host with IP address @code{144.155.166.177}
+@item @code{'144.155.166.%'} @tab @code{'fred'} @tab @code{fred}, connecting from any host in the @code{144.155.166} class C subnet
+@item @code{'144.155.166.0/24'} @tab @code{'fred'} @tab Same as previous example
+@end multitable
+
+Because you can use IP wildcard values in the @code{Host} field (e.g.,
+@code{'144.155.166.%'} to match every host on a subnet), there is the
+possibility that someone might try to exploit this capability by naming a
+host @code{144.155.166.somewhere.com}. To foil such attempts, @strong{MySQL}
+disallows matching on hostnames that start with digits and a dot. Thus, if
+you have a host named something like @code{1.2.foo.com}, its name will never
+match the @code{Host} column of the grant tables. Only an IP number can
+match an IP wildcard value.
+
+An incoming connection may be matched by more than one entry in the
+@code{user} table. For example, a connection from @code{thomas.loc.gov} by
+@code{fred} would be matched by several of the entries just shown above. How
+does the server choose which entry to use if more than one matches? The
+server resolves this question by sorting the @code{user} table after reading
+it at startup time, then looking through the entries in sorted order when a
+user attempts to connect. The first matching entry is the one that is used.
+
+@code{user} table sorting works as follows. Suppose the @code{user} table
+looks like this:
+
+@example
++-----------+----------+-
+| Host | User | ...
++-----------+----------+-
+| % | root | ...
+| % | jeffrey | ...
+| localhost | root | ...
+| localhost | | ...
++-----------+----------+-
+@end example
+
+When the server reads in the table, it orders the entries with the
+most-specific @code{Host} values first (@code{'%'} in the @code{Host} column
+means ``any host'' and is least specific). Entries with the same @code{Host}
+value are ordered with the most-specific @code{User} values first (a blank
+@code{User} value means ``any user'' and is least specific). The resulting
+sorted @code{user} table looks like this:
+
+@example
++-----------+----------+-
+| Host | User | ...
++-----------+----------+-
+| localhost | root | ...
+| localhost | | ...
+| % | jeffrey | ...
+| % | root | ...
++-----------+----------+-
+@end example
+
+@cindex Grant tables, sorting
+@cindex Sorting, grant tables
+@cindex @code{user} table, sorting
+When a connection is attempted, the server looks through the sorted entries
+and uses the first match found. For a connection from @code{localhost} by
+@code{jeffrey}, the entries with @code{'localhost'} in the @code{Host} column
+match first. Of those, the entry with the blank user name matches both the
+connecting hostname and user name. (The @code{'%'/'jeffrey'} entry would
+have matched, too, but it is not the first match in the table.)
+
+Here is another example. Suppose the @code{user} table looks like this:
+
+@example
++----------------+----------+-
+| Host | User | ...
++----------------+----------+-
+| % | jeffrey | ...
+| thomas.loc.gov | | ...
++----------------+----------+-
+@end example
+
+The sorted table looks like this:
+
+@example
++----------------+----------+-
+| Host | User | ...
++----------------+----------+-
+| thomas.loc.gov | | ...
+| % | jeffrey | ...
++----------------+----------+-
+@end example
+
+A connection from @code{thomas.loc.gov} by @code{jeffrey} is matched by the
+first entry, whereas a connection from @code{whitehouse.gov} by
+@code{jeffrey} is matched by the second.
+
+A common misconception is to think that for a given user name, all entries
+that explicitly name that user will be used first when the server attempts to
+find a match for the connection. This is simply not true. The previous
+example illustrates this, where a connection from @code{thomas.loc.gov} by
+@code{jeffrey} is first matched not by the entry containing @code{'jeffrey'}
+as the @code{User} field value, but by the entry with no user name!
+
+If you have problems connecting to the server, print out the @code{user}
+table and sort it by hand to see where the first match is being made.
+
+@node Request access, Privilege changes, Connection access, Privilege system
+@section Access control, stage 2: Request verification
+
+Once you establish a connection, the server enters stage 2. For each request
+that comes in on the connection, the server checks whether you have
+sufficient privileges to perform it, based on the type of operation you wish
+to perform. This is where the privilege fields in the grant tables come into
+play. These privileges can come from any of the @code{user}, @code{db},
+@code{host}, @code{tables_priv} or @code{columns_priv} tables. The grant
+tables are manipulated with @code{GRANT} and @code{REVOKE} commands.
+@xref{GRANT, , @code{GRANT}}. (You may find it helpful to refer to
+@ref{Privileges}, which lists the fields present in each of the grant
+tables.)
+
+The @code{user} table grants privileges that are assigned to you on a global
+basis and that apply no matter what the current database is. For example, if
+the @code{user} table grants you the @strong{delete} privilege, you can
+delete rows from any database on the server host! In other words,
+@code{user} table privileges are superuser privileges. It is wise to grant
+privileges in the @code{user} table only to superusers such as server or
+database administrators. For other users, you should leave the privileges
+in the @code{user} table set to @code{'N'} and grant privileges on a
+database-specific basis only, using the @code{db} and @code{host} tables.
+
+@cindex Anonymous user
+@cindex Wildcards, in @code{mysql.db} table
+@cindex Wildcards, in @code{mysql.host} table
+The @code{db} and @code{host} tables grant database-specific privileges.
+Values in the scope fields may be specified as follows:
+
+@itemize @bullet
+@item
+The
+wildcard characters @samp{%} and @samp{_} can be used in the @code{Host} and
+@code{Db} fields of either table.
+
+@item
+A @code{'%'} @code{Host} value in the @code{db} table means ``any host.'' A
+blank @code{Host} value in the @code{db} table means ``consult the
+@code{host} table for further information.''
+
+@item
+A @code{'%'} or blank @code{Host} value in the @code{host} table means ``any
+host.''
+
+@item
+A @code{'%'} or blank @code{Db} value in either table means ``any database.''
+
+@item
+A blank @code{User} value in either table matches the anonymous user.
+@end itemize
+
+@cindex Grant tables, sorting
+@cindex Sorting, grant tables
+@cindex @code{db} table, sorting
+@cindex @code{host} table, sorting
+The @code{db} and @code{host} tables are read in and sorted when the server
+starts up (at the same time that it reads the @code{user} table). The
+@code{db} table is sorted on the @code{Host}, @code{Db} and @code{User} scope
+fields, and the @code{host} table is sorted on the @code{Host} and @code{Db}
+scope fields. As with the @code{user} table, sorting puts the most-specific
+values first and least-specific values last, and when the server looks for
+matching entries, it uses the first match that it finds.
+
+
+@cindex Wildcards, in @code{mysql.tables_priv} table
+@cindex Wildcards, in @code{mysql.columns_priv} table
+The @code{tables_priv} and @code{columns_priv} tables grant table- and
+column-specific privileges. Values in the scope fields may be specified as
+follows:
+
+@itemize @bullet
+@item
+The wildcard characters @samp{%} and @samp{_}
+can be used in the @code{Host} field of either table.
+
+@item
+A @code{'%'} or blank @code{Host} value in either table means ``any host.''
+
+@item
+The @code{Db}, @code{Table_name} and @code{Column_name} fields cannot contain
+wildcards or be blank in either table.
+@end itemize
+
+The @code{tables_priv} and @code{columns_priv} tables are sorted on
+the @code{Host}, @code{Db} and @code{User} fields. This is similar to
+@code{db} table sorting, although the sorting is simpler because
+only the @code{Host} field may contain wildcards.
+
+The request verification process is described below. (If you are familiar
+with the access-checking source code, you will notice that the description
+here differs slightly from the algorithm used in the code. The description
+is equivalent to what the code actually does; it differs only to make the
+explanation simpler.)
+
+For administrative requests (@strong{shutdown}, @strong{reload}, etc.), the
+server checks only the @code{user} table entry, because that is the only table
+that specifies administrative privileges. Access is granted if the entry
+allows the requested operation and denied otherwise. For example, if you
+want to execute @code{mysqladmin shutdown} but your @code{user} table entry
+doesn't grant the @strong{shutdown} privilege to you, access is denied
+without even checking the @code{db} or @code{host} tables. (They
+contain no @code{Shutdown_priv} column, so there is no need to do so.)
+
+For database-related requests (@strong{insert}, @strong{update}, etc.), the
+server first checks the user's global (superuser) privileges by looking in
+the @code{user} table entry. If the entry allows the requested operation,
+access is granted. If the global privileges in the @code{user} table are
+insufficient, the server determines the user's database-specific privileges
+by checking the @code{db} and @code{host} tables:
+
+@enumerate
+@item
+The server looks in the @code{db} table for a match on the @code{Host},
+@code{Db} and @code{User} fields. The @code{Host} and @code{User} fields are
+matched to the connecting user's hostname and @strong{MySQL} user name. The
+@code{Db} field is matched to the database the user wants to access. If
+there is no entry for the @code{Host} and @code{User}, access is denied.
+
+@item
+If there is a matching @code{db} table entry and its @code{Host} field is
+not blank, that entry defines the user's database-specific privileges.
+
+@item
+If the matching @code{db} table entry's @code{Host} field is blank, it
+signifies that the @code{host} table enumerates which hosts should be allowed
+access to the database. In this case, a further lookup is done in the
+@code{host} table to find a match on the @code{Host} and @code{Db} fields.
+If no @code{host} table entry matches, access is denied. If there is a
+match, the user's database-specific privileges are computed as the
+intersection (@emph{not} the union!) of the privileges in the @code{db} and
+@code{host} table entries, i.e., the privileges that are @code{'Y'} in both
+entries. (This way you can grant general privileges in the @code{db} table
+entry and then selectively restrict them on a host-by-host basis using the
+@code{host} table entries.)
+@end enumerate
+
+After determining the database-specific privileges granted by the @code{db}
+and @code{host} table entries, the server adds them to the global privileges
+granted by the @code{user} table. If the result allows the requested
+operation, access is granted. Otherwise, the server checks the user's
+table and column privileges in the @code{tables_priv} and @code{columns_priv}
+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:
+
+@example
+global privileges
+OR (database privileges AND host privileges)
+OR table privileges
+OR column privileges
+@end example
+
+It may not be apparent why, if the global @code{user} entry privileges are
+initially found to be insufficient for the requested operation, the server
+adds those privileges to the database-, table- and column-specific privileges
+later. The reason is that a request might require more than one type of
+privilege. For example, if you execute an @code{INSERT ... SELECT}
+statement, you need both @strong{insert} and @strong{select} privileges.
+Your privileges might be such that the @code{user} table entry grants one
+privilege and the @code{db} table entry grants the other. In this case, you
+have the necessary privileges to perform the request, but the server cannot
+tell that from either table by itself; the privileges granted by the entries
+in both tables must be combined.
+
+The @code{host} table can be used to maintain a list of ``secure'' servers.
+At TcX, the @code{host} table contains a list of all machines on the local
+network. These are granted all privileges.
+
+You can also use the @code{host} table to indicate hosts that are @emph{not}
+secure. Suppose you have a machine @code{public.your.domain} that is located
+in a public area that you do not consider secure. You can allow access to
+all hosts on your network except that machine by using @code{host} table
+entries
+like this:
+
+@example
++--------------------+----+-
+| Host | Db | ...
++--------------------+----+-
+| public.your.domain | % | ... (all privileges set to 'N')
+| %.your.domain | % | ... (all privileges set to 'Y')
++--------------------+----+-
+@end example
+
+Naturally, you should always test your entries in the grant tables (e.g.,
+using @code{mysqlaccess}) to make sure your access privileges are actually
+set up the way you think they are.
+
+@node Privilege changes, Default privileges, Request access, Privilege system
+@section When privilege changes take effect
+
+When @code{mysqld} starts, all grant table contents are read into memory and
+become effective at that point.
+
+Modifications to the grant tables that you perform using @code{GRANT},
+@code{REVOKE}, or @code{SET PASSWORD} are noticed by the server immediately.
+
+If you modify the grant tables manually (using @code{INSERT}, @code{UPDATE},
+etc.), you should execute a @code{FLUSH PRIVILEGES} statement or run
+@code{mysqladmin flush-privileges} or @code{mysqladmin reload} to tell the
+server to reload the grant tables. Otherwise your changes will have @emph{no
+effect} until you restart the server. If you change the grant tables manually
+but forget to reload the privileges, you will be wondering why your changes
+don't seem to make any difference!
+
+When the server notices that the grant tables have been changed,
+existing client connections are affected as follows:
+
+@itemize @bullet
+@item
+Table and column privilege changes take effect with the client's next
+request.
+
+@item
+Database privilege changes take effect at the next @code{USE db_name}
+command.
+@end itemize
+
+Global privilege changes and password changes take effect the next time the
+client connects.
+
+@node Default privileges, Adding users, Privilege changes, Privilege system
+@section Setting up the initial MySQL privileges
+
+After installing @strong{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
+of privileges:
+
+@itemize @bullet
+@item
+The @strong{MySQL} @code{root} user is created as a superuser who can do
+anything. Connections must be made from the local host.
+
+@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.
+
+@item
+@cindex Anonymous user
+An anonymous user is created that can do anything with databases that have a
+name of @code{'test'} or starting with @code{'test_'}. Connections must be
+made from the local host. This means any local user can connect without a
+password and be treated as the anonymous user.
+
+@item
+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 Win32.
+@xref{Win32 running}.
+
+Because your installation is initially wide open, one of the first things you
+should do is specify a password for the @strong{MySQL}
+@code{root} user. You can do this as follows (note that you specify the
+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;
+@end example
+
+You can in @strong{MySQL} 3.22 and above use the @code{SET PASSWORD} statement:
+
+@example
+shell> mysql -u root mysql
+mysql> SET PASSWORD FOR root=PASSWORD('new_password');
+@end example
+
+Another way to set the password is by using the @code{mysqladmin} command:
+
+@example
+shell> mysqladmin -u root password new_password
+@end example
+
+Note that if you update the password in the @code{user} table directly using
+the first method, you must tell the server to reread the grant tables (with
+@code{FLUSH PRIVILEGES}), because the change will go unnoticed otherwise.
+
+Once the @code{root} password has been set, thereafter you must supply that
+password when you connect to the server as @code{root}.
+
+You may wish to leave the @code{root} password blank so that you don't need
+to specify it while you perform additional setup or testing. However, be sure
+to set it before using your installation for any real production work.
+
+See the @code{scripts/mysql_install_db} script to see how it sets up
+the default privileges. You can use this as a basis to see how to
+add other users.
+
+If you want the initial privileges to be different than those just described
+above, you can modify @code{mysql_install_db} before you run it.
+
+To recreate the grant tables completely, remove all the @file{*.frm},
+@file{*.MYI} and @file{*.MYD} files in the directory containing the
+@code{mysql} database. (This is the directory named @file{mysql} under
+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 @strong{MySQL} versions older than 3.22.10, you should NOT
+delete the @file{*.frm} files. If you accidentally do this, you should
+copy them back from your @strong{MySQL} distribution before running
+@code{mysql_install_db}.
+
+@node Adding users, Passwords, Default privileges, Privilege system
+@section Adding new user privileges to MySQL
+
+You can add users two different ways: by using @code{GRANT} statements
+or by manipulating the @strong{MySQL} grant tables directly. The
+preferred method is to use @code{GRANT} statements, because they are
+more concise and less error-prone.
+
+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
+defaults described in the previous section. This means that to make changes,
+you must be on the same machine where @code{mysqld} is running, you must
+connect as the @strong{MySQL} @code{root} user, and the @code{root} user must
+have the @strong{insert} privilege for the @code{mysql} database and the
+@strong{reload} administrative privilege. Also, if you have changed the
+@code{root} user password, you must specify it for the @code{mysql} commands
+below.
+
+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;
+mysql> GRANT ALL PRIVILEGES ON *.* TO monty@@"%"
+ IDENTIFIED BY 'some_pass' WITH GRANT OPTION;
+mysql> GRANT RELOAD,PROCESS ON *.* TO admin@@localhost;
+mysql> GRANT USAGE ON *.* TO dummy@@localhost;
+@end example
+
+These @code{GRANT} statements set up three new users:
+
+@table @code
+@item monty
+A full superuser who can connect to the server from anywhere, but who must
+use a password @code{'some_pass'} to do so. Note that we must issue
+@code{GRANT} statements for both @code{monty@@localhost} and
+@code{monty@@"%"}. If we don't add the entry with @code{localhost}, the
+anonymous user entry for @code{localhost} that is created by
+@code{mysql_install_db} will take precedence when we connect from the local
+host, because it has a more specific @code{Host} field value and thuse comes
+earlier in the @code{user} table sort order.
+
+@item admin
+A user who can connect from @code{localhost} without a password and who is
+granted the @strong{reload} and @strong{process} administrative privileges.
+This allows the user to execute the @code{mysqladmin reload},
+@code{mysqladmin refresh} and @code{mysqladmin flush-*} commands, as well as
+@code{mysqladmin processlist} . No database-related privileges are granted.
+(They can be granted later by issuing additional @code{GRANT} statements.)
+
+@item dummy
+A user who can connect without a password, but only from the local host. The
+global privileges are all set to @code{'N'} --- the @code{USAGE} privilege
+type allows you to create a user with no privileges. It is assumed that you
+will grant database-specific privileges later.
+@end table
+
+You can also add the same user access information directly by issuing
+@code{INSERT} statements and then telling the server to reload the grant
+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')
+mysql> INSERT INTO user VALUES('%','monty',PASSWORD('some_pass'),
+ '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
+
+Depending on your @strong{MySQL} version, you may have to use a different
+number of @code{'Y'} values above (versions prior to 3.22.11 had fewer
+privilege columns). For the @code{admin} user, the more readable extended
+@code{INSERT} syntax that is available starting with 3.22.11 is used.
+
+Note that to set up a superuser, you need only create a @code{user} table
+entry with the privilege fields set to @code{'Y'}. No @code{db} or
+@code{host} table entries are necessary.
+
+The privilege columns in the @code{user} table were not set explicitly in the
+last @code{INSERT} statement (for the @code{dummy} user), so those columns
+are assigned the default value of @code{'N'}. This is the same thing that
+@code{GRANT USAGE} does.
+
+The following example adds a user @code{custom} who can connect from hosts
+@code{localhost}, @code{server.domain} and @code{whitehouse.gov}. He wants
+to access the @code{bankaccount} database only from @code{localhost},
+the @code{expenses} database only from @code{whitehouse.gov} and
+the @code{customer} database from all three hosts. He wants
+to use the password @code{stupid} from all three hosts.
+
+To set up this user's privileges using @code{GRANT} statements, run these
+commands:
+
+@example
+shell> mysql --user=root mysql
+mysql> GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,DROP
+ 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';
+mysql> GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,DROP
+ ON customer.*
+ TO custom@@'%'
+ IDENTIFIED BY 'stupid';
+@end example
+
+To set up the user's privileges by modifying the grant tables directly,
+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'));
+mysql> INSERT INTO user (Host,User,Password)
+ VALUES('server.domain','custom',PASSWORD('stupid'));
+mysql> INSERT INTO user (Host,User,Password)
+ 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');
+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');
+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');
+mysql> FLUSH PRIVILEGES;
+@end example
+
+The first three @code{INSERT} statements add @code{user} table entries that
+allow user @code{custom} to connect from the various hosts with the given
+password, but grant no permissions to him (all privileges are set to the
+default value of @code{'N'}). The next three @code{INSERT} statements add
+@code{db} table entries that grant privileges to @code{custom} for the
+@code{bankaccount}, @code{expenses} and @code{customer} databases, but only
+when accessed from the proper hosts. As usual, when the grant tables are
+modified directly, the server must be told to reload them (with
+@code{FLUSH PRIVILEGES}) so that the privilege changes take effect.
+
+If you want to give a specific user access from any machine in a given
+domain, you can issue a @code{GRANT} statement like the following:
+
+@example
+mysql> GRANT ...
+ 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'),...);
+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 @strong{MySQL}
+Website}.
+
+@node Passwords, Access denied, Adding users, Privilege system
+@section How to set up passwords
+@cindex Passwords, setting
+@findex PASSWORD()
+
+The examples in the preceding sections illustrate an important principle:
+when you store a non-empty password using @code{INSERT} or @code{UPDATE}
+statements, you must use the @code{PASSWORD()} function to encrypt it. This
+is because the @code{user} table stores passwords in encrypted form, not as
+plaintext. If you forget that fact, you are likely to attempt to set
+passwords like this:
+
+@example
+shell> mysql -u root mysql
+mysql> INSERT INTO user (Host,User,Password)
+ VALUES('%','jeffrey','biscuit');
+mysql> FLUSH PRIVILEGES;
+@end example
+
+The result is that the plaintext value @code{'biscuit'} is stored as the
+password in the @code{user} table. When the user @code{jeffrey} attempts to
+connect to the server using this password, the @code{mysql} client encrypts
+it with @code{PASSWORD()} and sends the result to the server. The server
+compares the value in the @code{user} table (the encrypted value of
+@code{'biscuit'}) to the encrypted password (which is @emph{not}
+@code{'biscuit'}). The comparison fails and the server rejects the
+connection:
+
+@example
+shell> mysql -u jeffrey -pbiscuit test
+Access denied
+@end example
+
+Passwords must be encrypted when they are inserted in the @code{user}
+table, so the @code{INSERT} statement should have been specified like this
+instead:
+
+@example
+mysql> INSERT INTO user (Host,User,Password)
+ VALUES('%','jeffrey',PASSWORD('biscuit'));
+@end example
+
+You must also use the @code{PASSWORD()} function when you use @code{SET
+PASSWORD} statements:
+
+@example
+mysql> SET PASSWORD FOR jeffrey@@"%" = PASSWORD('biscuit');
+@end example
+
+If you set passwords using the @code{GRANT ... IDENTIFIED BY} statement
+or the @code{mysqladmin password} command, the @code{PASSWORD()} function
+is unnecessary. They both take care of encrypting the password for you,
+so you would specify a password of @code{'biscuit'} like this:
+
+@example
+mysql> GRANT USAGE ON *.* TO jeffrey@@"%" IDENTIFIED BY 'biscuit';
+@end example
+
+or
+
+@example
+shell> mysqladmin -u jeffrey password biscuit
+@end example
+
+@strong{NOTE:} @code{PASSWORD()} does not perform password encryption in the
+same way that Unix passwords are encrypted. You should not assume that if
+your Unix password and your @strong{MySQL} password are the same, that
+@code{PASSWORD()} will result in the same encrypted value as is stored in the
+Unix password file.
+@xref{User names}.
+
+@node Access denied, , Passwords, Privilege system
+@section Causes of @code{Access denied} errors
+
+If you encounter @code{Access denied} errors when you try to connect to the
+@strong{MySQL} server, the list below indicates some courses of
+action you can take to correct the problem:
+
+@itemize @bullet
+@item
+After installing @strong{MySQL}, did you run the @code{mysql_install_db} script
+to set up the initial grant table contents? If not, do
+so. @xref{Default privileges}. Test the initial privileges by
+executing this command:
+
+@example
+shell> mysql -u root test
+@end example
+
+The server should let you connect without error. You should also make sure
+you have a file @file{user.MYD} in the @strong{MySQL} database directory.
+Ordinarily, this is @file{PATH/var/mysql/user.MYD}, where @code{PATH} is the
+pathname to the @strong{MySQL} installation root.
+
+@item
+After a fresh installation, you should connect to the server and set up
+your users and their access permissions:
+
+@example
+shell> mysql -u root mysql
+@end example
+
+The server should let you connect because the @strong{MySQL} @code{root} user
+has no password initially. That is also a security risk, so setting the
+@code{root} password is something you should do while you're setting up
+your other @strong{MySQL} users.
+
+If you try to connect as @code{root} and get this error:
+
+@example
+Access denied for user: '@@unknown' to database mysql
+@end example
+
+this means that you don't have an entry in the @code{user} table with a
+@code{User} column value of @code{'root'} and that @code{mysqld} cannot
+resolve the hostname for your client. In this case, you must restart the
+server with the @code{--skip-grant-tables} option and edit your
+@file{/etc/hosts} or @file{\windows\hosts} file to add an entry for your
+host.
+
+@item
+@cindex @code{mysql_fix_privilege_tables}
+If you updated an existing @strong{MySQL} installation from a pre-3.22.11
+version to 3.22.11 or later, did you run the
+@code{mysql_fix_privilege_tables} script? If not, do so. The structure of
+the grant tables changed with @strong{MySQL} 3.22.11 when the @code{GRANT}
+statement became functional.
+
+@item
+If you make changes to the grant tables directly (using @code{INSERT} or
+@code{UPDATE} statement) and your changes seem to be ignored, remember that
+you must issue a @code{FLUSH PRIVILEGES} statement or execute a
+@code{mysqladmin flush-privileges} command to cause the server to reread the
+tables. Otherwise your changes have no effect until the next time the server
+is restarted. Remember that after you set the @code{root} password, you
+won't need to specify it until after you flush the privileges, because the
+server still won't know you've changed the password yet!
+
+@item
+If your privileges seem to have changed in the middle of a session, it may be
+that a superuser has changed them. Reloading the grant tables affects new
+client connections, but it also affects existing connections as indicated in
+@ref{Privilege changes}.
+
+@item
+For testing, start the @code{mysqld} daemon with the
+@code{--skip-grant-tables} option. Then you can change the @strong{MySQL}
+grant tables and use the @code{mysqlaccess} script to check whether or not
+your modifications have the desired effect. When you are satisfied with your
+changes, execute @code{mysqladmin flush-privileges} to tell the @code{mysqld}
+server to start using the new grant tables. @strong{Note:} Reloading the
+grant tables overrides the @code{--skip-grant-tables} option. This allows
+you to tell the server to begin using the grant tables again without bringing
+it down and restarting it.
+
+@item
+If you have access problems with a Perl, PHP, Python or ODBC program, try to
+connect to the server with @code{mysql -u user_name db_name} or @code{mysql
+-u user_name -pyour_pass db_name}. If you are able to connect using the
+@code{mysql} client, there is a problem with your program and not with the
+access privileges. (Notice 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.)
+
+@item
+If you can't get your password to work, remember that you must use
+the @code{PASSWORD()} function if you set the password with the
+@code{INSERT}, @code{UPDATE} or @code{SET PASSWORD} statements. The
+@code{PASSWORD()} function is unnecessary if you specify the password using
+the @code{GRANT ... INDENTIFIED BY} statement or the @code{mysqladmin
+password} command.
+@xref{Passwords}.
+
+@item
+@code{localhost} is a synonym for your local hostname, and is also the
+default host to which clients try to connect if you specify no host
+explicitly. However, connections to @code{localhost} do not work if you are
+running on a system that uses MIT-pthreads (@code{localhost} connections are
+made using Unix sockets, which are not supported by MIT-pthreads). To avoid
+this problem on such systems, you should use the @code{--host} option to name
+the server host explicitly. This will make a TCP/IP connection to the
+@code{mysqld} server. In this case, you must have your real hostname in
+@code{user} table entries on the server host. (This is true even if you are
+running a client program on the same host as the server.)
+
+@item
+If you get an @code{Access denied} error when trying to connect to the
+database with @code{mysql -u user_name db_name}, you may have a problem
+with the @code{user} table. Check this by executing @code{mysql -u root
+mysql} and issuing this SQL statement:
+
+@example
+mysql> SELECT * FROM user;
+@end example
+
+The result should include an entry with the @code{Host} and @code{User}
+columns matching your computer's hostname and your @strong{MySQL} user name.
+
+@item
+The @code{Access denied} error message will tell you who you are trying
+to log in as, the host from which you are trying to connect, and whether
+or not you were using a password. Normally, you should have one entry in
+the @code{user} table that exactly matches the hostname and user name
+that were given in the error message.
+
+@item
+If you get the following error when you try to connect from a different host
+than the one on which the @strong{MySQL} server is running, then there is no
+row in the @code{user} table that matches that host:
+
+@example
+Host ... is not allowed to connect to this MySQL server
+@end example
+
+You can fix this by using the command line tool @code{mysql} (on the
+server host!) to add a row to the @code{user}, @code{db} or @code{host}
+table for the user/hostname combination from which you are trying to
+connect and then execute @code{mysqladmin flush-privileges}. If you are
+not running @strong{MySQL} 3.22 and you don't know the IP number or
+hostname of the machine from which you are connecting, you should put an
+entry with @code{'%'} as the @code{Host} column value in the @code{user}
+table and restart @code{mysqld} with the @code{--log} option on the
+server machine. After trying to connect from the client machine, the
+information in the @strong{MySQL} log will indicate how you really did
+connect. (Then replace the @code{'%'} in the @code{user} table entry
+with the actual hostname that shows up in the log. Otherwise, you'll
+have a system that is insecure.)
+
+Another reason for this error on Linux is that you are using a binary
+@strong{MySQL} version that is compiled with a different glibc version
+than the one you are using. In this case you should either upgrade your
+OS/glibc or download the source @strong{MySQL} version and compile this
+yourself; A source RPM is normally trivial to compile and install, so
+normally this isn't a big problem.
+
+@item
+If @code{mysql -u root test} works but @code{mysql -h your_hostname -u root
+test} results in @code{Access denied}, then you may not have the correct name
+for your host in the @code{user} table. A common problem here is that the
+@code{Host} value in the user table entry specifies an unqualified hostname,
+but your system's name resolution routines return a fully-qualified domain
+name (or vice-versa). For example, if you have an entry with host
+@code{'tcx'} in the @code{user} table, but your DNS tells @strong{MySQL} that
+your hostname is @code{'tcx.subnet.se'}, the entry will not work. Try adding
+an entry to the @code{user} table that contains the IP number of your host as
+the @code{Host} column value. (Alternatively, you could add an entry to the
+@code{user} table with a @code{Host} value that contains a wildcard---for
+example, @code{'tcx.%'}. However, use of hostnames ending with @samp{%} is
+@emph{insecure} and is @emph{not} recommended!)
+
+@item
+If @code{mysql -u user_name test} works but @code{mysql -u user_name
+other_db_name} doesn't work, you don't have an entry for @code{other_db_name}
+listed in the @code{db} table.
+
+@item
+If @code{mysql -u user_name db_name} works when executed on the server
+machine, but @code{mysql -u host_name -u user_name db_name} doesn't work when
+executed on another client machine, you don't have the client machine listed
+in the @code{user} table or the @code{db} table.
+
+@item
+If you can't figure out why you get @code{Access denied}, remove from the
+@code{user} table all entries that have @code{Host} values containing
+wildcards (entries that contain @samp{%} or @samp{_}). A very common error
+is to insert a new entry with @code{Host}=@code{'%'} and
+@code{User}=@code{'some user'}, thinking that this will allow you to specify
+@code{localhost} to connect from the same machine. The reason that this
+doesn't work is that the default privileges include an entry with
+@code{Host}=@code{'localhost'} and @code{User}=@code{''}. Because that entry
+has a @code{Host} value @code{'localhost'} that is more specific than
+@code{'%'}, it is used in preference to the new entry when connecting from
+@code{localhost}! The correct procedure is to insert a second entry with
+@code{Host}=@code{'localhost'} and @code{User}=@code{'some_user'}, or to
+remove the entry with with @code{Host}=@code{'localhost'} and
+@code{User}=@code{''}.
+
+@item
+If you get the following error, you may have a problem with the @code{db} or
+@code{host} table:
+
+@example
+Access to database denied
+@end example
+
+If the entry selected from the @code{db} table has an empty value in the
+@code{Host} column, make sure there are one or more corresponding entries in
+the @code{host} table specifying which hosts the @code{db} table entry
+applies to.
+
+If you get the error when using the SQL commands @code{SELECT ...
+INTO OUTFILE} or @code{LOAD DATA INFILE}, your entry in the @code{user} table
+probably doesn't have the @strong{file} privilege enabled.
+
+@item
+@cindex Configuration files
+@cindex Environment variables
+@tindex .my.cnf file
+Remember that client programs will use connection parameters specified
+in configuration files or environment variables. @xref{Environment
+variables}. If a client seems to be sending the wrong default
+connection parameters when you don't specify them on the command line,
+check your environment and the @file{.my.cnf} file in your home
+directory. You might also check the system-wide @strong{MySQL}
+configuration files, though it is far less likely that client connection
+parameters will be specified there. @xref{Option files}. If you get
+@code{Access denied} when you run a client without any options, make
+sure you haven't specified an old password in any of your option files!
+@xref{Option files}.
+
+@item
+If everything else fails, start the @code{mysqld} daemon with a debugging
+option (for example, @code{--debug=d,general,query}). This will print host and
+user information about attempted connections, as well as information about
+each command issued. @xref{Debugging server}.
+
+@item
+If you have any other problems with the @strong{MySQL} grant tables and
+feel you must post the problem to the mailing list, always provide a
+dump of the @strong{MySQL} grant tables. You can dump the tables with
+the @code{mysqldump mysql} command. As always, post your problem using
+the @code{mysqlbug} script. @xref{Bug reports}. In some cases you may need
+to restart @code{mysqld} with @code{--skip-grant-tables} to be able to run
+@code{mysqldump}.
+@end itemize
+
+@node Reference, Table types, Privilege system, Top
+@chapter MySQL language reference
+
+@menu
+* Literals:: Literals: how to write strings and numbers
+* Variables:: User variables
+* Column types:: Column types
+* Functions:: Functions
+* CREATE DATABASE:: @code{CREATE DATABASE} syntax
+* DROP DATABASE:: @code{DROP DATABASE} syntax
+* CREATE TABLE:: @code{CREATE TABLE} syntax
+* ALTER TABLE:: @code{ALTER TABLE} syntax
+* DROP TABLE:: @code{DROP TABLE} syntax
+* OPTIMIZE TABLE:: @code{OPTIMIZE TABLE} syntax
+* CHECK TABLE:: @code{CHECK TABLE} syntax
+* ANALYZE TABLE::
+* REPAIR TABLE:: @code{REPAIR TABLE} syntax
+* DELETE:: @code{DELETE} syntax
+* SELECT:: @code{SELECT} syntax
+* JOIN:: @code{JOIN} syntax
+* INSERT:: @code{INSERT} syntax
+* REPLACE:: @code{REPLACE} syntax
+* LOAD DATA:: @code{LOAD DATA INFILE} syntax
+* UPDATE:: @code{UPDATE} syntax
+* USE:: @code{USE} syntax
+* FLUSH:: @code{Flush} syntax (clearing caches)
+* KILL:: @code{KILL} syntax
+* SHOW:: @code{SHOW} syntax (Get information about tables, columns, ...)
+* EXPLAIN:: @code{EXPLAIN} syntax (Get information about a @code{SELECT})
+* DESCRIBE:: @code{DESCRIBE} syntax (Get information about names of columns)
+* COMMIT:: @code{BEGIN/COMMIT/ROLLBACK} syntax
+* LOCK TABLES:: @code{LOCK TABLES/UNLOCK TABLES} syntax
+* SET OPTION:: @code{SET OPTION} syntax
+* GRANT:: @code{GRANT} and @code{REVOKE} syntax
+* CREATE INDEX:: @code{CREATE INDEX} syntax
+* DROP INDEX:: @code{DROP INDEX} syntax
+* Comments:: Comment syntax
+* CREATE FUNCTION:: @code{CREATE FUNCTION} syntax
+* Reserved words:: Is @strong{MySQL} picky about reserved words?
+@end menu
+
+
+@cindex Strings
+@cindex Strings, escaping characters
+@node Literals, Variables, Reference, Reference
+@section Literals: how to write strings and numbers
+
+@menu
+* String syntax:: Strings
+* Number syntax:: Numbers
+* Hexadecimal values:: Hexadecimal values
+* NULL values:: @code{NULL} values
+* Legal names:: Database, table, index, column and alias names
+@end menu
+
+@node String syntax, Number syntax, Literals, Literals
+@subsection Strings
+
+A string is a sequence of characters, surrounded by either single quote
+(@samp{'}) or double quote (@samp{"}) characters (only the single quote
+if you run in ANSI mode). Examples:
+
+@example
+'a string'
+"another string"
+@end example
+
+Within a string, certain sequences have special meaning. Each of these
+sequences begins with a backslash (@samp{\}), known as the @emph{escape
+character}. @strong{MySQL} recognizes the following escape sequences:
+
+@c these aren't really functions, but that's probably the most reasonable index
+@table @code
+@findex \0 (ASCII 0)
+@findex NUL
+@item \0
+An ASCII 0 (@code{NUL}) character.
+
+@findex \n (newline)
+@findex newline (\n)
+@item \n
+A newline character.
+
+@findex \t (tab)
+@findex tab (\t)
+@item \t
+A tab character.
+
+@findex \r (carriage return)
+@findex return (\r)
+@findex carriage return (\r)
+@item \r
+A carriage return character.
+
+@findex \b (backspace)
+@findex backspace (\b)
+@item \b
+A backspace character.
+
+@findex \' (single quote)
+@findex single quote (\')
+@item \'
+A single quote (@samp{'}) character.
+
+@findex \" (double quote)
+@findex double quote (\")
+@item \"
+A double quote (@samp{"}) character.
+
+@findex \\ (escape)
+@findex escape (\\)
+@item \\
+A backslash (@samp{\}) character.
+
+@findex % (wildcard character)
+@findex Wildcard character (%)
+@item \%
+A @samp{%} character. This is used to search for literal instances of
+@samp{%} in contexts where @samp{%} would otherwise be interpreted
+as a wildcard character. @xref{String comparison functions}.
+
+@findex _ (wildcard character)
+@findex Wildcard character (_)
+@item \_
+A @samp{_} character. This is used to search for literal instances of
+@samp{_} in contexts where @samp{_} would otherwise be interpreted
+as a wildcard character. @xref{String comparison functions}.
+@end table
+
+Note that if you use @samp{\%} or @samp{\_} in some string contexts, these
+will return the strings @samp{\%} and @samp{\_} and not @samp{%} and
+@samp{_}.
+
+@noindent
+There are several ways to include quotes within a string:
+
+@itemize @bullet
+@item
+A @samp{'} inside a string quoted with @samp{'} may be written as @samp{''}.
+
+@item
+A @samp{"} inside a string quoted with @samp{"} may be written as @samp{""}.
+
+@item
+You can precede the quote character with an escape character (@samp{\}).
+
+@item
+A @samp{'} inside a string quoted with @samp{"} needs no special treatment
+and need not be doubled or escaped. In the same way, @samp{"} inside a
+string quoted with @samp{'} needs no special treatment.
+@end itemize
+
+The @code{SELECT} statements shown below demonstrate how quoting and
+escaping work:
+
+@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 "This\nIs\nFour\nlines";
++--------------------+
+| This
+Is
+Four
+lines |
++--------------------+
+@end example
+
+@cindex Quoting binary data
+
+If you want to insert binary data into a @code{BLOB} column, the following
+characters must be represented by escape sequences:
+@table @code
+@item NUL
+ASCII 0. You should represent this by @samp{\0} (a backslash and an ASCII @samp{0} character).
+@item \
+ASCII 92, backslash. Represent this by @samp{\\}.
+@item '
+ASCII 39, single quote. Represent this by @samp{\'}.
+@item "
+ASCII 34, double quote. Represent this by @samp{\"}.
+@end table
+
+@cindex Quoting
+@cindex @code{BLOB}, inserting binary data
+@findex mysql_escape_string()
+@findex DBI->quote
+If you write C code, you can use the C API function
+@code{mysql_escape_string()} to escape characters for the @code{INSERT}
+statement. @xref{C API function overview}. In Perl, you can use the
+@code{quote} method of the @code{DBI} package to convert special
+characters to the proper escape sequences. @xref{Perl DBI Class, , Perl
+@code{DBI} Class}.
+
+You should use an escape function on any string that might contain any of the
+special characters listed above!
+
+@node Number syntax, Hexadecimal values, String syntax, Literals
+@subsection Numbers
+
+Integers are represented as a sequence of digits. Floats use @samp{.} as a
+decimal separator. Either type of number may be preceded by @samp{-} to
+indicate a negative value.
+
+Examples of valid integers:
+
+@example
+1221
+0
+-32
+@end example
+
+Examples of valid floating-point numbers:
+
+@example
+294.42
+-32032.6809e+10
+148.00
+@end example
+
+An integer may be used in a floating-point context; it is interpreted
+as the equivalent floating-point number.
+
+@tindex Hexadecimal values
+@node Hexadecimal values, NULL values, Number syntax, Literals
+@subsection Hexadecimal values
+
+@strong{MySQL} supports hexadecimal values. In number context these acts
+like an integer (64 bit precision). In string context these acts like a binary
+string where each pair of hex digits is converted to a character.
+
+@example
+mysql> SELECT 0xa+0
+ -> 10
+mysql> select 0x5061756c;
+ -> Paul
+@end example
+
+Hexadecimal strings is often used by ODBC to give values for BLOB columns.
+
+@tindex NULL value
+@node NULL values, Legal names, Hexadecimal values, Literals
+@subsection @code{NULL} values
+
+The @code{NULL} value means ``no data'' and is different from values such
+as @code{0} for numeric types or the empty string for string types.
+@xref{Problems with NULL, , Problems with @code{NULL}}.
+
+@code{NULL} may be represented by @code{\N} when using the text file import
+or export formats (@code{LOAD DATA INFILE}, @code{SELECT ... INTO OUTFILE}).
+@xref{LOAD DATA, , @code{LOAD DATA}}.
+
+@node Legal names, , NULL values, Literals
+@subsection Database, table, index, column and alias names
+
+@menu
+* Name case sensitivity:: Case sensitivity in names
+@end menu
+
+Database, table, index, column and alias names all follow the same rules in
+@strong{MySQL}:
+
+@tindex Quoting of identifiers
+@tindex `
+@tindex "
+Note that the rules changed starting with @strong{MySQL} 3.23.6 when we
+introduced quoting of identifiers (database, table and column names)
+with @code{`} (@code{"} will also work to quote identifiers if you run
+in ANSI mode).
+
+@multitable @columnfractions .15 .7 .78
+@item @strong{Identifier} @tab @strong{max length} @tab @strong{Allowed characters}
+@item Database @tab 64 @tab Any character that is allowed in a directory name execpt @code{/}.
+@item Table @tab 64 @tab Any character that is allowed in file name, except @code{/} or @code{.}
+@item Column @tab 64 @tab All characters
+@item Alias @tab 255 @tab All characters
+@end multitable
+
+Note that in addition to the above, you can't have ASCII(0) or ASCII(255) in
+an identifier.
+
+Note that if the identifer is a restricted word or contains special character
+you must always quote it with @code{`} when you use it:
+
+@example
+SELECT * from `select` where `select`.id > 100;
+@end example
+
+In previous versions of @strong{MySQL}, the name rules are as follows:
+
+@itemize @bullet
+@item
+A name may consist of alphanumeric characters from the current character set
+and also @samp{_} and @samp{$}. The default character set is ISO-8859-1
+Latin1; this may be changed with the @code{--default-character-set} option
+to @code{mysqld}.
+@xref{Character sets}.
+
+@item
+A name may start with any character that is legal in a name. In particular,
+a name may start with a number (this differs from many other database
+systems!). However, a name cannot consist @emph{only} of numbers.
+
+@item
+You cannot use the @samp{.} character in names because it is used to extend the
+format by which you can refer to columns (see immediately below).
+@end itemize
+
+It is recommended that you do not use names like @code{1e}, because
+an expression like @code{1e+1} is ambiguous. It may be interpreted as the
+expression @code{1e + 1} or as the number @code{1e+1}.
+
+In @strong{MySQL} you can refer to a column using any of the following forms:
+
+@multitable @columnfractions .35 .65
+@item @strong{Column reference} @tab @strong{Meaning}
+@item @code{col_name} @tab Column @code{col_name}
+from whichever table used in the query contains a column of that name
+@item @code{tbl_name.col_name} @tab Column @code{col_name} from table
+@code{tbl_name} of the current database
+@item @code{db_name.tbl_name.col_name} @tab Column @code{col_name} from table
+@code{tbl_name} of the database @code{db_name}. This form is available in
+@strong{MySQL} 3.22 or later.
+@item
+@code{`column_name`} @tab A column that is a keyword or contains special characters.
+@end multitable
+
+You need not specify a @code{tbl_name} or @code{db_name.tbl_name} prefix for
+a column reference in a statement unless the reference would be ambiguous.
+For example, suppose tables @code{t1} and @code{t2} each contain a column
+@code{c}, and you retrieve @code{c} in a @code{SELECT} statement that uses
+both @code{t1} and @code{t2}. In this case, @code{c} is ambiguous because it
+is not unique among the tables used in the statement, so you must indicate
+which table you mean by writing @code{t1.c} or @code{t2.c}. Similarly, if
+you are retrieving from a table @code{t} in database @code{db1} and from a
+table @code{t} in database @code{db2}, you must refer to columns in those
+tables as @code{db1.t.col_name} and @code{db2.t.col_name}.
+
+@cindex ODBC compatibility
+@cindex Compatibility, with ODBC
+The syntax @code{.tbl_name} means the table @code{tbl_name} in the current
+database. This syntax is accepted for ODBC compatibility, because some ODBC
+programs prefix table names with a @samp{.} character.
+
+@node Name case sensitivity, , Legal names, Legal names
+@subsubsection Case sensitivity in names
+@cindex Database names, case sensitivity
+@cindex Table names, case sensitivity
+@cindex Column names, case sensitivity
+@cindex Alias names, case sensitivity
+@cindex Case sensitivity, of database names
+@cindex Case sensitivity, of table names
+@cindex Case sensitivity, of column names
+@cindex Case sensitivity, of alias names
+
+In @strong{MySQL}, databases and tables correspond to directories and files
+within those directories. Consequently, the case sensitivity of the
+underlying operating system determines the case sensitivity of database and
+table names. This means database and table names are case sensitive in Unix
+and case insensitive in Win32.
+
+@strong{Note:} Although database and table names are case insensitive for
+Win32, you should not refer to a given database or table using different
+cases within the same query. The following query would not work because it
+refers to a table both as @code{my_table} and as @code{MY_TABLE}:
+
+@example
+mysql> SELECT * FROM my_table WHERE MY_TABLE.col=1;
+@end example
+
+Column names are case insensitive in all cases.
+
+Aliases on tables are case sensitive. The following query would not work
+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;
+@end example
+
+Aliases on columns are case insensitive.
+
+@node Variables, Column types, Literals, Reference
+@section User variables
+
+@strong{MySQL} supports thread specific variables with the
+@code{@@variablename} syntax. A variable name may consist of
+alphanumeric characters from the current character set and also
+@samp{_}, @samp{$}, and @samp{.} . The default character set is
+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
+and can store an integer, real or string value. All variables for
+a thread are automatically freed when the thread exits.
+
+You can set a variable with the @code{SET} syntax:
+
+@example
+SET @@variable= @{ integer expression | real expression | string expression @}
+[,@@variable= ...].
+@end example
+
+You can also set a variable in an expression with the @code{@@variable:=expr}
+syntax:
+
+@example
+select @@t1:=(@@t2:=1)+@@t3:=4,@@t1,@@t2,@@t3;
++----------------------+------+------+------+
+| @@t1:=(@@t2:=1)+@@t3:=4 | @@t1 | @@t2 | @@t3 |
++----------------------+------+------+------+
+| 5 | 5 | 1 | 4 |
++----------------------+------+------+------+
+@end example
+
+(We had to use the @code{:=} syntax here, because @code{=} was reserved for
+comparisons.)
+
+User variables may be used where expressions are allowed. Note that
+this does not currently include use in contexts where a number is explicitly
+required, such as in the @code{LIMIT} clause of a @code{SELECT} statement,
+or the @code{IGNORE number LINES} clause of a @code{LOAD DATA} statement.
+
+@strong{NOTE:} In a @code{SELECT} statement, each expression is only
+evaluated when it's sent to the client. This means that one can't
+in the @code{HAVING}, @code{GROUP BY} or @code{ORDER BY} clause refer to an
+expression that involves variables that are set in the @code{SELECT} part.
+For example, the following statement will NOT work as expected:
+
+@example
+SELECT (@@aa:=id) AS a, (@@aa+3) AS b FROM table_name HAVING b=5;
+@end example
+
+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.
+
+@node Column types, Functions, Variables, Reference
+@section Column types
+
+@strong{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
+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
+as the allowable formats in which you can specify values.
+
+The column types supported by @strong{MySQL} are listed below.
+The following code letters are used in the descriptions:
+
+@table @code
+@item M
+Indicates the maximum display size. The maximum legal display size is 255.
+
+@item D
+Applies to floating-point types and indicates the number of digits
+following the decimal point. The maximum possible value is 30, but
+should be no greater than @code{M}-2.
+@end table
+
+Square brackets (@samp{[} and @samp{]}) indicate parts of type specifiers
+that are optional.
+
+@tindex Types
+
+@c The @w{-number} stuff keeps a linebreak from occurring between
+@c the - and number.
+
+Note that if you specify @code{ZEROFILL} for a column, @strong{MySQL} will
+automatically add the @code{UNSIGNED} attribute to the column.
+
+@table @code
+@tindex TINYINT
+@item TINYINT[(M)] [UNSIGNED] [ZEROFILL]
+
+A very small integer. The signed range is @code{-128} to @code{127}. The
+unsigned range is @code{0} to @code{255}.
+
+@tindex SMALLINT
+@item SMALLINT[(M)] [UNSIGNED] [ZEROFILL]
+
+A small integer. The signed range is @code{-32768} to @code{32767}. The
+unsigned range is @code{0} to @code{65535}.
+
+@tindex MEDIUMINT
+@item MEDIUMINT[(M)] [UNSIGNED] [ZEROFILL]
+
+A medium-size integer. The signed range is @code{-8388608} to
+@code{8388607}. The unsigned range is @code{0} to @code{16777215}.
+
+@tindex INT
+@item INT[(M)] [UNSIGNED] [ZEROFILL]
+
+A normal-size integer. The signed range is @code{-2147483648} to
+@code{2147483647}. The unsigned range is @code{0} to @code{4294967295}.
+
+@tindex INTEGER
+@item INTEGER[(M)] [UNSIGNED] [ZEROFILL]
+
+This is a synonym for @code{INT}.
+
+@tindex BIGINT
+@item BIGINT[(M)] [UNSIGNED] [ZEROFILL]
+
+A large integer. The signed range is @code{-9223372036854775808} to
+@code{9223372036854775807}. The unsigned range is @code{0} to
+@code{18446744073709551615}. Note that all arithmetic is done using
+signed @code{BIGINT} or @code{DOUBLE} values, so you shouldn't use
+unsigned big integers larger than @code{9223372036854775807} (63 bits)
+except with bit functions! Note that @code{-}, @code{+} and @code{*}
+will use @code{BIGINT} arithmetic when both arguments are @code{INTEGER}
+values! This means that if you multiply two big integers (or results
+from functions that return integers) you may get unexpected results if
+the result is larger than @code{9223372036854775807}.
+
+@tindex FLOAT
+@tindex FLOAT(precision)
+@item FLOAT(precision) [ZEROFILL]
+
+A floating-point number. Cannot be unsigned. @code{precision} can be
+@code{<=24} for a single precision floating point number and between 25
+and 53 for a double precision floating point number.
+these types are like the @code{FLOAT} and @code{DOUBLE} types described
+immediately below. @code{FLOAT(X)} have the same ranges as the
+corresponding @code{FLOAT} and @code{DOUBLE} types, but the display
+size and number of decimals is undefined.
+
+In @strong{MySQL} 3.23, this is a true floating point value. In
+earlier @strong{MySQL} versions, @code{FLOAT(precision)} always has 2 decimals.
+
+@cindex ODBC compatibility
+@cindex Compatibility, with ODBC
+This syntax is provided for ODBC compatibility.
+
+@tindex FLOAT
+@tindex FLOAT(M,D)
+@item FLOAT[(M,D)] [ZEROFILL]
+
+A small (single-precision) floating-point number. Cannot be unsigned.
+Allowable values are @code{@w{-3.402823466E+38}} to
+@code{@w{-1.175494351E-38}}, @code{0} and @code{@w{1.175494351E-38}} to
+@code{3.402823466E+38}. The M is the display width and D is the
+number of decimals. @code{FLOAT} without an argument or with an argument of
+<= 24 stands for a single-precision floating point number.
+
+@tindex DOUBLE
+@tindex FLOAT(precision)
+@item DOUBLE[(M,D)] [ZEROFILL]
+
+A normal-size (double-precision) floating-point number. Cannot be
+unsigned. Allowable values are @code{@w{-1.7976931348623157E+308}} to
+@code{@w{-2.2250738585072014E-308}}, @code{0} and
+@code{2.2250738585072014E-308} to @code{1.7976931348623157E+308}. The M
+is the display width and D is the number of decimals. @code{DOUBLE}
+without an argument or @code{FLOAT(X)} where 25 <= X <= 53 stands for a
+double-precision floating point number.
+
+@tindex DOUBLE PRECISION
+@tindex REAL
+@item DOUBLE PRECISION[(M,D)] [ZEROFILL]
+@itemx REAL[(M,D)] [ZEROFILL]
+
+These are synonyms for @code{DOUBLE}.
+
+@tindex DECIMAL
+@item DECIMAL[(M[,D])] [ZEROFILL]
+
+An unpacked floating-point number. Cannot be unsigned. Behaves like a
+@code{CHAR} column: ``unpacked'' means the number is stored as a string,
+using one character for each digit of the value. The decimal point,
+and, for negative numbers, the @samp{-} sign is not counted in M. If
+@code{D} is 0, values will have no decimal point or fractional part.
+The maximum range of @code{DECIMAL} values is the same as for
+@code{DOUBLE}, but the actual range for a given @code{DECIMAL} column
+may be constrained by the choice of @code{M} and @code{D}.
+
+If @code{D} is left out it's set to 0. If @code{M} is left out it's set to 10.
+
+Note that in @strong{MySQL} 3.22 the @code{M} argument includes the sign
+and the decimal point.
+
+@tindex NUMERIC
+@item NUMERIC(M,D) [ZEROFILL]
+
+This is a synonym for @code{DECIMAL}.
+
+@tindex DATE
+@item DATE
+
+A date. The supported range is @code{'1000-01-01'} to @code{'9999-12-31'}.
+@strong{MySQL} displays @code{DATE} values in @code{'YYYY-MM-DD'} format, but
+allows you to assign values to @code{DATE} columns using either strings or
+numbers.
+
+@tindex DATETIME
+@item DATETIME
+
+A date and time combination. The supported range is @code{'1000-01-01
+00:00:00'} to @code{'9999-12-31 23:59:59'}. @strong{MySQL} displays
+@code{DATETIME} values in @code{'YYYY-MM-DD HH:MM:SS'} format, but allows you
+to assign values to @code{DATETIME} columns using either strings or numbers.
+
+@tindex TIMESTAMP
+@item TIMESTAMP[(M)]
+
+A timestamp. The range is @code{'1970-01-01 00:00:00'} to sometime in the
+year @code{2037}. @strong{MySQL} displays @code{TIMESTAMP} values in
+@code{YYYYMMDDHHMMSS}, @code{YYMMDDHHMMSS}, @code{YYYYMMDD} or @code{YYMMDD}
+format, depending on whether @code{M} is @code{14} (or missing), @code{12},
+@code{8} or @code{6}, but allows you to assign values to @code{TIMESTAMP}
+columns using either strings or numbers. A @code{TIMESTAMP} column is useful
+for recording the date and time of an @code{INSERT} or @code{UPDATE}
+operation because it is automatically set to the date and time of the most
+recent operation if you don't give it a value yourself. You can also set it
+to the current date and time by assigning it a @code{NULL} value. @xref{Date
+and time types}.
+
+@tindex TIME
+@item TIME
+
+A time. The range is @code{'-838:59:59'} to @code{'838:59:59'}.
+@strong{MySQL} displays @code{TIME} values in @code{'HH:MM:SS'} format, but
+allows you to assign values to @code{TIME} columns using either strings or
+numbers.
+
+@tindex YEAR
+@item YEAR[(2|4)]
+
+A year in 2- or 4- digit formats (default is 4-digit). The allowable values are
+@code{1901} to @code{2155}, and @code{0000} in the 4 year format and
+1970-2069 if you use the 2 digit format (70-69). @strong{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 @strong{MySQL} 3.22.)
+
+@tindex NATIONAL CHAR
+@tindex NCHAR
+@tindex CHAR
+@tindex CHARACTER
+@item [NATIONAL] CHAR(M) [BINARY]
+
+A fixed-length string that is always right-padded with spaces to the
+specified length when stored. The range of @code{M} is 1 to 255 characters.
+Trailing spaces are removed when the value is retrieved. @code{CHAR} values
+are sorted and compared in case-insensitive fashion according to the
+default character set unless the @code{BINARY} keyword is given.
+
+@code{NATIONAL CHAR} (short form @code{NCHAR}) is the ANSI SQL way to
+define that a CHAR column should use the default CHARACTER set. This is
+default in @code{MySQL}.
+
+@code{CHAR} is a shorthand for @code{CHARACTER}.
+
+@strong{MySQL} allows you to create a column of type
+@code{CHAR(0)}. This is mainly useful when you have to be compliant with
+some old applications that depend on the existence of a column but that do not
+actually use the value. This is also quite nice when you need a
+column that only can take 2 values: A @code{CHAR(0)}, that is not defined
+as @code{NOT NULL}, will only occupy one bit and can only take 2 values:
+@code{NULL} or @code{""}.
+
+@tindex CHARACTER VARYING
+@tindex CHAR VARYING
+@tindex VARCHAR
+@item [NATIONAL] VARCHAR(M) [BINARY]
+
+A variable-length string. 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 given. @xref{Silent column changes}.
+
+@code{VARCHAR} is a shorthand for @code{CHARACTER VARYING}.
+
+@tindex TINYBLOB
+@tindex TINYTEXT
+@item TINYBLOB
+@itemx TINYTEXT
+
+A @code{BLOB} or @code{TEXT} column with a maximum length of 255 (2^8 - 1)
+characters. @xref{Silent column changes}.
+
+@tindex BLOB
+@tindex TEXT
+@item BLOB
+@itemx TEXT
+
+A @code{BLOB} or @code{TEXT} column with a maximum length of 65535 (2^16 - 1)
+characters. @xref{Silent column changes}.
+
+@tindex MEDIUMBLOB
+@tindex MEDIUMTEXT
+@item MEDIUMBLOB
+@itemx MEDIUMTEXT
+
+A @code{BLOB} or @code{TEXT} column with a maximum length of 16777215
+(2^24 - 1) characters. @xref{Silent column changes}.
+
+@tindex LONGBLOB
+@tindex LONGTEXT
+@item LONGBLOB
+@itemx LONGTEXT
+
+A @code{BLOB} or @code{TEXT} column with a maximum length of 4294967295
+(2^32 - 1) characters. @xref{Silent column changes}.
+
+@tindex ENUM
+@item ENUM('value1','value2',...)
+
+An enumeration.
+A string object that can have only one value, chosen from the list of values
+@code{'value1'}, @code{'value2'}, @code{...}, or @code{NULL}. An @code{ENUM}
+can have a maximum of 65535 distinct values.
+
+@tindex SET
+@item SET('value1','value2',...)
+
+A set. A string object that can have zero or more values, each of which must
+be chosen from the list of values @code{'value1'}, @code{'value2'},
+@code{...} A @code{SET} can have a maximum of 64 members.
+@end table
+
+@menu
+* Storage requirements:: Column type storage requirements
+* Numeric types:: Numeric types
+* Date and time types:: Date and time types
+* String types:: String types
+* Choosing types:: Choosing the right type for a column
+* Indexes:: Column indexes
+* Multiple-column indexes:: Multiple-column indexes
+* Other-vendor column types:: Using column types from other database engines
+@end menu
+
+@cindex Storage requirements
+@node Storage requirements, Numeric types, Column types, Column types
+@subsection Column type storage requirements
+
+The storage requirements for each of the column types supported by
+@strong{MySQL} are listed below by category.
+
+@subheading Numeric types
+
+@multitable @columnfractions .35 .65
+@item @strong{Column type} @tab @strong{Storage required}
+@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 if X <= 24 or 8 if 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} bytes (@code{D}+2, if @code{M < D})
+@item @code{NUMERIC(M,D)} @tab @code{M} bytes (@code{D}+2, if @code{M < D})
+@end multitable
+
+@subheading Date and time types
+
+@multitable @columnfractions .35 .65
+@item @strong{Column type} @tab @strong{Storage required}
+@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
+
+@subheading String types
+
+@multitable @columnfractions .35 .65
+@item @strong{Column type} @tab @strong{Storage required}
+@item @code{CHAR(M)} @tab @code{M} bytes, @code{1 <= M <= 255}
+@item @code{VARCHAR(M)} @tab @code{L}+1 bytes, where @code{L <= M} and
+@code{1 <= M <= 255}
+@item @code{TINYBLOB}, @code{TINYTEXT} @tab @code{L}+1 bytes,
+where @code{L} < 2^8
+@item @code{BLOB}, @code{TEXT} @tab @code{L}+2 bytes,
+where @code{L} < 2^16
+@item @code{MEDIUMBLOB}, @code{MEDIUMTEXT} @tab @code{L}+3 bytes,
+where @code{L} < 2^24
+@item @code{LONGBLOB}, @code{LONGTEXT} @tab @code{L}+4 bytes,
+where @code{L} < 2^32
+@item @code{ENUM('value1','value2',...)} @tab 1 or 2 bytes, depending on
+the number of enumeration values (65535 values maximum)
+@item @code{SET('value1','value2',...)} @tab 1, 2, 3, 4 or 8 bytes, depending
+on the number of set members (64 members maximum)
+@end multitable
+
+@code{VARCHAR} and the @code{BLOB} and @code{TEXT} types are variable-length
+types, for which the storage requirements depend on the actual length of
+column values (represented by @code{L} in the preceding table), rather than
+on the type's maximum possible size. For example, a @code{VARCHAR(10)}
+column can hold a string with a maximum length of 10 characters. The actual
+storage required is the length of the string (@code{L}), plus 1 byte to
+record the length of the string. For the string @code{'abcd'}, @code{L} is 4
+and the storage requirement is 5 bytes.
+
+The @code{BLOB} and @code{TEXT} types require 1, 2, 3 or 4 bytes to record
+the length of the column value, depending on the maximum possible length of
+the type.
+
+If a table includes any variable-length column types, the record format will
+also be variable-length. Note that when a table is created, @strong{MySQL}
+may under certain conditions change a column from a variable-length type to a
+fixed-length type, or vice-versa. @xref{Silent column changes}.
+
+The size of an @code{ENUM} object is determined by the number of different
+enumeration values. 1 byte is used for enumerations with up to 255 possible
+values. 2 bytes are used for enumerations with up to 65535 values.
+
+The size of a @code{SET} object is determined by the number of different
+set members. If the set size is @code{N}, the object occupies @code{(N+7)/8}
+bytes, rounded up to 1, 2, 3, 4 or 8 bytes. A @code{SET} can have a maximum
+of 64 members.
+
+@node Numeric types, Date and time types, Storage requirements, Column types
+@subsection Numeric types
+
+@strong{MySQL} supports all of the ANSI/ISO SQL92 numeric types. These
+types include the exact numeric data types (@code{NUMERIC},
+@code{DECIMAL}, @code{INTEGER}, and @code{SMALLINT}), as well as the
+approximate numeric data types (@code{FLOAT}, @code{REAL}, and
+@code{DOUBLE PRECISION}). The keyword @code{INT} is a synonym for
+@code{INTEGER}, and the keyword @code{DEC} is a synonym for
+@code{DECIMAL}.
+
+The @code{NUMERIC} and @code{DECIMAL} types are implemented as the same
+type by @strong{MySQL}, as permitted by the SQL92 standard. They are
+used for values for which it is important to preserve exact precision,
+for example with monetary data. When declaring a column of one of these
+types the precision and scale can be (and usually is) specified; for
+example:
+
+@example
+ salary DECIMAL(9,2)
+@end example
+
+In this example, @code{9} (@code{precision}) represents the number of
+significant decimal digits which will be stored for values, and
+@code{2} (@code{scale}) represents the number of digits which will be
+stored following the decimal point. In this case, therefore, the range
+of values which can be stored in the @code{salary} column is from
+@code{-9999999.99} to @code{9999999.99}. In ANSI/ISO SQL92, the syntax
+@code{DECIMAL(p)} is equivalent to @code{DECIMAL(p,0)}. Similarly, the
+syntax @code{DECIMAL} is equivalent to @code{DECIMAL(p,0)}, where the
+implementation is allowed to decide the value of @code{p}.
+@strong{MySQL} does not currently support either of these variant forms
+of the @code{DECIMAL}/@code{NUMERIC} data types. This is not generally
+a serious problem, as the principal benefits of these types derive from
+the ability to control both precision and scale explicitly.
+
+@code{DECIMAL} and @code{NUMERIC} values are stored as strings, rather
+than as binary floating point numbers, in order to preserve the decimal
+precision of those values. One character is used for each digit of the
+value, the decimal point (if @code{scale} > 0) and the @samp{-} sign
+(for negative numbers). If @code{scale} is 0, @code{DECIMAL} and
+@code{NUMERIC} values contain no decimal point or fractional part.
+
+The maximum range of @code{DECIMAL} and @code{NUMERIC} values is the
+same as for @code{DOUBLE}, but the actual range for a given
+@code{DECIMAL} or @code{NUMERIC} column can be constrained by the
+@code{precision} or @code{scale} for a given column. When such a column
+is assigned a value with more digits following the decimal point than
+are allowed by the specified @code{scale}, the value is rounded to that
+@code{scale}. When a @code{DECIMAL} or @code{NUMERIC} column is
+assigned a value whose magnitude exceeds the range implied by the
+specified (or defaulted) @code{precision} and @code{scale},
+@strong{MySQL} stores the value representing the corresponding end
+point of that range.
+
+As an extension to the ANSI/ISO SQL92 standard, @strong{MySQL} also
+supports the integral types @code{TINYINT}, @code{MEDIUMINT}, and
+@code{BIGINT} as listed in the tables above. Another extension is
+supported by @strong{MySQL} for optionally specifying the display width
+of an integral value in parentheses following the base keyword for the
+type (for example, @code{INT(4)}). This optional width specification is
+used to left-pad the display of values whose width is less than the
+width specified for the column, but does not constrain the range of
+values which can be stored in the column, nor the number of digits which
+will be displayed for values whose width exceeds that specified for the
+column. When used in conjunction with the optional extension attribute
+@code{ZEROFILL} the default padding of spaces is replaced with zeroes.
+For example, for a column declared as @code{INT(5) ZEROFILL}, a value
+of @code{4} is retrieved as @code{00004}. Note that if you store larger
+values than the display width in an integral column, you may experience
+problems when @strong{MySQL} generates temporary tables for some
+complicated joins as in these case @strong{MySQL} trust that the data
+did fit into the original column width.
+
+All integral types can have an optional (non-standard) attribute
+@code{UNSIGNED}. Unsigned values can be used when you want to allow
+only positive numbers in a column and you need a little bigger numeric
+range for the column.
+
+The @code{FLOAT} type is used to represent approximate numeric data
+types. The ANSI/ISO SQL92 standard allows an optional specification of
+the precision (but not the range of the exponent) in bits following the
+keyword @code{FLOAT} in parentheses. The @strong{MySQL} implementation
+also supports this optional precision specification. When the keyword
+@code{FLOAT} is used for a column type without a precision
+specification, @strong{MySQL} uses four bytes to store the values. A
+variant syntax is also supported, with two numbers given in parentheses
+following the @code{FLOAT} keyword. With this option, the first number
+continues to represent the storage requirements for the value in bytes,
+and the second number specifies the number of digits to be stored and
+displayed following the decimal point (as with @code{DECIMAL} and
+@code{NUMERIC}). When @strong{MySQL} is asked to store a number for
+such a column with more decimal digits following the decimal point than
+specified for the column, the value is rounded to eliminate the extra
+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, @strong{MySQL} recognizes @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}, @strong{MySQL} implements both as 8-byte
+double-precision floating point values (when running in non-"Ansi mode").
+For maximum portability, code requiring storage of approximate numeric
+data values should use @code{FLOAT} or @code{DOUBLE PRECISION} with no
+specification of precision or number of decimal points.
+
+When asked to store a value in a numeric column that is outside the column
+type's allowable range, @strong{MySQL} clips the value to the appropriate
+endpoint of the range and stores the resulting value instead.
+
+For example, the range of an @code{INT} column is @code{-2147483648} to
+@code{2147483647}. If you try to insert @code{-9999999999} into an
+@code{INT} column, the value is clipped to the lower endpoint of the range,
+and @code{-2147483648} is stored instead. Similarly, if you try to insert
+@code{9999999999}, @code{2147483647} is stored instead.
+
+If the @code{INT} column is @code{UNSIGNED}, the size of the column's
+range is the same but its endpoints shift up to @code{0} and @code{4294967295}.
+If you try to store @code{-9999999999} and @code{9999999999},
+the values stored in the column become @code{0} and @code{4294967296}.
+
+Conversions that occur due to clipping are reported as ``warnings'' for
+@code{ALTER TABLE}, @code{LOAD DATA INFILE}, @code{UPDATE} and
+multi-row @code{INSERT} statements.
+
+@cindex Types, Date and Time
+@cindex Date and Time types
+@node Date and time types, String types, Numeric types, Column types
+@subsection Date and time types
+
+@menu
+* Y2K issues:: Y2K issues and date types
+* DATETIME:: The @code{DATETIME}, @code{DATE} and @code{TIMESTAMP} types
+* TIME:: The @code{TIME} type
+* YEAR:: The @code{YEAR} type
+@end menu
+
+The date and time types are @code{DATETIME}, @code{DATE},
+@code{TIMESTAMP}, @code{TIME} and @code{YEAR}. Each of these has a
+range of legal values, as well as a ``zero'' value that is used when you
+specify a really illegal value. Note that @strong{MySQL} allows you to store
+certain 'not strictly' legal date values, for example @code{1999-11-31}.
+The reason for this is that we think it's the responsibility of the
+application to handle date checking, not the SQL servers. To make the
+date checking 'fast', @strong{MySQL} only checks that the month is in
+the range of 0-12 and the day is in the range of 0-31. The above ranges
+are defined this way because @strong{MySQL} allows you to store, in a
+@code{DATE} or @code{DATETIME} column, dates where the day or month-day
+are zero. This is extremely useful for applications that need to store
+a birth-date for which you don't know the exact date. In this case you
+simply store the date like @code{1999-00-00} or @code{1999-01-00}. (You
+can of course not expect to get a correct value from functions like
+@code{DATE_SUB()} or @code{DATE_ADD} for dates like these).
+
+Here are some general considerations to keep in mind when working
+with date and time types:
+
+@itemize @bullet
+@item
+@strong{MySQL} retrieves values for a given date or time type in a standard
+format, but it attempts to interpret a variety of formats for values that
+you supply (e.g., when you specify a value to be assigned to or compared to a
+date or time type). Nevertheless, only the formats described in the
+following sections are supported. It is expected that you will supply legal
+values, and unpredictable results may occur if you use values in other
+formats.
+
+@item
+Although @strong{MySQL} tries to interpret values in several formats, it
+always expects the year part of date values to be leftmost. Dates must be
+given in year-month-day order (e.g., @code{'98-09-04'}), rather than in the
+month-day-year or day-month-year orders commonly used elsewhere (e.g.,
+@code{'09-04-98'}, @code{'04-09-98'}).
+
+@item
+@strong{MySQL} automatically converts a date or time type value to a number
+if the value is used in a numeric context, and vice versa.
+
+@item
+When @strong{MySQL} encounters a value for a date or time type that is
+out of range or otherwise illegal for the type (see start of this
+section), it converts the value to the ``zero'' value for that type.
+(The exception is that out-of-range @code{TIME} values are clipped to
+the appropriate endpoint of the @code{TIME} range.) The table below
+shows the format of the ``zero'' value for each type:
+
+@multitable @columnfractions .3 .7
+@item @strong{Column type} @tab @strong{``Zero'' value}
+@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} (length depends on display size)
+@item @code{TIME} @tab @code{'00:00:00'}
+@item @code{YEAR} @tab @code{0000}
+@end multitable
+
+@item
+The ``zero'' values are special, but you can store or refer to them
+explicitly using the values shown in the table. You can also do this
+using the values @code{'0'} or @code{0}, which are easier to write.
+
+@item
+``Zero'' date or time values used through @strong{MyODBC} are converted
+automatically to @code{NULL} in @strong{MyODBC} 2.50.12 and above, because
+ODBC can't handle such values.
+@end itemize
+
+@cindex Year 2000 issues
+@node Y2K issues, DATETIME, Date and time types, Date and time types
+@subsubsection Y2K issues and date types
+
+@strong{MySQL} itself is Y2K-safe (@pxref{Year 2000 compliance}),
+but input values presented to @strong{MySQL} may not be. Any input
+containing 2-digit year values is ambiguous, because the century is unknown.
+Such values must be interpreted into 4-digit form because @strong{MySQL} stores
+years internally using four digits.
+
+For @code{DATETIME}, @code{DATE}, @code{TIMESTAMP} and @code{YEAR} types,
+@strong{MySQL} interprets dates with ambiguous year values using the
+following rules:
+
+@itemize @bullet
+@item
+Year values in the range @code{00-69} are converted to @code{2000-2069}.
+
+@item
+Year values in the range @code{70-99} are converted to @code{1970-1999}.
+@end itemize
+
+Remember that these rules provide only reasonable guesses as to what your
+data mean. If the heuristics used by @strong{MySQL} don't produce the
+correct values, you should provide unambiguous input containing 4-digit
+year values.
+
+@code{ORDER BY} will sort 2 digit @code{YEAR/DATE/DATETIME} types properly.
+
+Note also that some functions like @code{MIN()} and @code{MAX()} will convert a
+@code{TIMESTAMP/DATE} to a number. This means that a timestamp with a 2
+digit year will not work properly with these functions. The fix in this
+case is to convert the @code{TIMESTAMP/DATE} to 4 digit year format or
+use something like @code{MIN(DATE_ADD(timestamp,INTERVAL 0 DAYS))}.
+
+@tindex DATETIME
+@tindex DATE
+@tindex TIMESTAMP
+@node DATETIME, TIME, Y2K issues, Date and time types
+@subsubsection The @code{DATETIME}, @code{DATE} and @code{TIMESTAMP} types
+
+The @code{DATETIME}, @code{DATE} and @code{TIMESTAMP} types are related.
+This section describes their characteristics, how they are similar and how
+they differ.
+
+The @code{DATETIME} type is used when you need values that contain both date
+and time information. @strong{MySQL} retrieves and displays @code{DATETIME}
+values in @code{'YYYY-MM-DD HH:MM:SS'} format. The supported range is
+@code{'1000-01-01 00:00:00'} to @code{'9999-12-31 23:59:59'}. (``Supported''
+means that although earlier values might work, there is no guarantee that
+they will.)
+
+The @code{DATE} type is used when you need only a date value, without a time
+part. @strong{MySQL} retrieves and displays @code{DATE} values in
+@code{'YYYY-MM-DD'} format. The supported range is @code{'1000-01-01'} to
+@code{'9999-12-31'}.
+
+The @code{TIMESTAMP} column type provides a type that you can use to
+automatically mark @code{INSERT} or @code{UPDATE} operations with the current
+date and time. If you have multiple @code{TIMESTAMP} columns, only the first
+one is updated automatically.
+
+Automatic updating of the first @code{TIMESTAMP} column occurs under any of
+the following conditions:
+
+@itemize @bullet
+@item
+The column is not specified explicitly in an @code{INSERT} or
+@code{LOAD DATA INFILE} statement.
+@item
+The column is not specified explicitly in an @code{UPDATE} statement and some
+other column changes value. (Note that an @code{UPDATE} that sets a column
+to the value it already has will not cause the @code{TIMESTAMP} column to be
+updated, because if you set a column to its current value, @strong{MySQL}
+ignores the update for efficiency.)
+@item
+You explicitly set the @code{TIMESTAMP} column to @code{NULL}.
+@end itemize
+
+@code{TIMESTAMP} columns other than the first may also be set to the current
+date and time. Just set the column to @code{NULL}, or to @code{NOW()}.
+
+You can set any @code{TIMESTAMP} column to a value different than the current
+date and time by setting it explicitly to the desired value. This is true
+even for the first @code{TIMESTAMP} column. You can use this property if,
+for example, you want a @code{TIMESTAMP} to be set to the current date and
+time when you create a row, but not to be changed whenever the row is updated
+later:
+
+@itemize @bullet
+@item
+Let @strong{MySQL} set the column when the row is created.
+This will initialize it to the current date and time.
+
+@item
+When you perform subsequent updates to other columns in the row, set
+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
+leave alone for subsequent updates.
+
+@code{TIMESTAMP} values may range from the beginning of 1970 to sometime in
+the year 2037, with a resolution of one second. Values are displayed as
+numbers.
+
+The format in which @strong{MySQL} retrieves and displays @code{TIMESTAMP}
+values depends on the display size, as illustrated by the table below. The
+`full' @code{TIMESTAMP} format is 14 digits, but @code{TIMESTAMP} columns may
+be created with shorter display sizes:
+
+@multitable @columnfractions .3 .7
+@item @strong{Column type} @tab @strong{Display format}
+@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
+
+All @code{TIMESTAMP} columns have the same storage size, regardless of
+display size. The most common display sizes are 6, 8, 12, and 14. You can
+specify an arbitrary display size at table creation time, but values of 0 or
+greater than 14 are coerced to 14. Odd-valued sizes in the range from 1 to
+13 are coerced to the next higher even number.
+
+You can specify @code{DATETIME}, @code{DATE} and @code{TIMESTAMP} values using
+any of a common set of formats:
+
+@itemize @bullet
+@item
+As a string in either @code{'YYYY-MM-DD HH:MM:SS'} or @code{'YY-MM-DD
+HH:MM:SS'} format. A ``relaxed'' syntax is allowed---any punctuation
+character may be used as the delimiter between date parts or time parts.
+For example, @code{'98-12-31 11:30:45'}, @code{'98.12.31 11+30+45'},
+@code{'98/12/31 11*30*45'} and @code{'98@@12@@31 11^30^45'} are
+equivalent.
+
+@item
+As a string in either @code{'YYYY-MM-DD'} or @code{'YY-MM-DD'} format.
+A ``relaxed'' syntax is allowed here, too. For example, @code{'98-12-31'},
+@code{'98.12.31'}, @code{'98/12/31'} and @code{'98@@12@@31'} are
+equivalent.
+
+@item
+As a string with no delimiters in either @code{'YYYYMMDDHHMMSS'} or
+@code{'YYMMDDHHMMSS'} format, provided that the string makes sense as a
+date. For example, @code{'19970523091528'} and @code{'970523091528'} are
+interpreted as @code{'1997-05-23 09:15:28'}, but @code{'971122129015'} is
+illegal (it has a nonsensical minute part) and becomes @code{'0000-00-00
+00:00:00'}.
+
+@item
+As a string with no delimiters in either @code{'YYYYMMDD'} or @code{'YYMMDD'}
+format, provided that the string makes sense as a date. For example,
+@code{'19970523'} and @code{'970523'} are interpreted as
+@code{'1997-05-23'}, but @code{'971332'} is illegal (it has nonsensical month
+and day parts) and becomes @code{'0000-00-00'}.
+
+@item
+As a number in either @code{YYYYMMDDHHMMSS} or @code{YYMMDDHHMMSS}
+format, provided that the number makes sense as a date. For example,
+@code{19830905132800} and @code{830905132800} are interpreted as
+@code{'1983-09-05 13:28:00'}.
+
+@item
+As a number in either @code{YYYYMMDD} or @code{YYMMDD}
+format, provided that the number makes sense as a date. For example,
+@code{19830905} and @code{830905} are interpreted as @code{'1983-09-05'}.
+
+@item
+As the result of a function that returns a value that is acceptable
+in a @code{DATETIME}, @code{DATE} or @code{TIMESTAMP} context, such as
+@code{NOW()} or @code{CURRENT_DATE}.
+@end itemize
+
+Illegal @code{DATETIME}, @code{DATE} or @code{TIMESTAMP} values are converted
+to the ``zero'' value of the appropriate type (@code{'0000-00-00 00:00:00'},
+@code{'0000-00-00'} or @code{00000000000000}).
+
+For values specified as strings that include date part delimiters, it is not
+necessary to specify two digits for month or day values that are less than
+@code{10}. @code{'1979-6-9'} is the same as @code{'1979-06-09'}. Similarly,
+for values specified as strings that include time part delimiters, it is not
+necessary to specify two digits for hour, month or second values that are
+less than @code{10}. @code{'1979-10-30 1:2:3'} is the same as
+@code{'1979-10-30 01:02:03'}.
+
+Values specified as numbers should be 6, 8, 12 or 14 digits long. If the
+number is 8 or 14 digits long, it is assumed to be in @code{YYYYMMDD} or
+@code{YYYYMMDDHHMMSS} format and that the year is given by the first 4
+digits. If the number is 6 or 12 digits long, it is assumed to be in
+@code{YYMMDD} or @code{YYMMDDHHMMSS} format and that the year is given by the
+first 2 digits. Numbers that are not one of these lengths are interpreted
+as though padded with leading zeros to the closest length.
+
+Values specified as non-delimited strings are interpreted using their length
+as given. If the string is 8 or 14 characters long, the year is assumed to
+be given by the first 4 characters. Otherwise the year is assumed to be
+given by the first 2 characters. The string is interpreted from left to
+right to find year, month, day, hour, minute and second values, for as many
+parts as are present in the string. This means you should not use strings
+that have fewer than 6 characters. For example, if you specify @code{'9903'},
+thinking that will represent March, 1999, you will find that @strong{MySQL}
+inserts a ``zero'' date into your table. This is because the year and month
+values are @code{99} and @code{03}, but the day part is missing (zero), so
+the value is not a legal date.
+
+@code{TIMESTAMP} columns store legal values using the full precision with
+which the value was specified, regardless of the display size. This has
+several implications:
+
+@itemize @bullet
+@item
+Always specify year, month, and day, even if your column types are
+@code{TIMESTAMP(4)} or @code{TIMESTAMP(2)}. Otherwise, the value will not
+be a legal date and @code{0} will be stored.
+
+@item
+If you use @code{ALTER TABLE} to widen a narrow @code{TIMESTAMP} column,
+information will be displayed that previously was ``hidden''.
+
+@item
+Similarly, narrowing a @code{TIMESTAMP} column does not cause information to
+be lost, except in the sense that less information is shown when the values
+are displayed.
+
+@item
+Although @code{TIMESTAMP} values are stored to full precision, the only
+function that operates directly on the underlying stored value is
+@code{UNIX_TIMESTAMP()}. Other functions operate on the formatted retrieved
+value. This means you cannot use functions such as @code{HOUR()} or
+@code{SECOND()} unless the relevant part of the @code{TIMESTAMP} value is
+included in the formatted value. For example, the @code{HH} part of a
+@code{TIMESTAMP} column is not displayed unless the display size is at least
+10, so trying to use @code{HOUR()} on shorter @code{TIMESTAMP} values
+produces a meaningless result.
+@end itemize
+
+You can to some extent assign values of one date type to an object
+of a different date type. However, there may be some alteration
+of the value or loss of information:
+
+@itemize @bullet
+@item
+If you assign a @code{DATE} value to a @code{DATETIME} or @code{TIMESTAMP}
+object, the time part of the resulting value is set to @code{'00:00:00'},
+because the @code{DATE} value contains no time information.
+
+@item
+If you assign a @code{DATETIME} or @code{TIMESTAMP} value to a @code{DATE}
+object, the time part of the resulting value is deleted, because the
+@code{DATE} type stores no time information.
+
+@item
+Remember that although @code{DATETIME}, @code{DATE} and @code{TIMESTAMP}
+values all can be specified using the same set of formats, the types do not
+all have the same range of values. For example, @code{TIMESTAMP} values
+cannot be earlier than @code{1970} or later than @code{2037}. This means
+that a date such as @code{'1968-01-01'}, while legal as a @code{DATETIME} or
+@code{DATE} value, is not a valid @code{TIMESTAMP} value and will be
+converted to @code{0} if assigned to such an object.
+@end itemize
+
+Be aware of certain pitfalls when specifying date values:
+
+@itemize @bullet
+@item
+The relaxed format allowed for values specified as strings can be deceiving.
+For example, a value such as @code{'10:11:12'} might look like a time value
+because of the @samp{:} delimiter, but if used in a date context will be
+interpreted as the year @code{'2010-11-12'}. The value @code{'10:45:15'}
+will be converted to @code{'0000-00-00'} because @code{'45'} is not a legal
+month.
+
+@item
+Year values specified as two digits are ambiguous, because the century is
+unknown. @strong{MySQL} interprets 2-digit year values using the following
+rules:
+
+@itemize @minus
+@item
+Year values in the range @code{00-69} are converted to @code{2000-2069}.
+
+@item
+Year values in the range @code{70-99} are converted to @code{1970-1999}.
+@end itemize
+@end itemize
+
+@tindex TIME
+@node TIME, YEAR, DATETIME, Date and time types
+@subsubsection The @code{TIME} type
+
+@strong{MySQL} retrieves and displays @code{TIME} values in @code{'HH:MM:SS'}
+format (or @code{'HHH:MM:SS'} format for large hours values). @code{TIME}
+values may range from @code{'-838:59:59'} to @code{'838:59:59'}. The reason
+the hours part may be so large is that the @code{TIME} type may be used not
+only to represent a time of day (which must be less than 24 hours), but also
+elapsed time or a time interval between two events (which may be much greater
+than 24 hours, or even negative).
+
+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
+@strong{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},
+@code{D HH:MM}, @code{D HH} or @code{SS}. Here @code{D} is days between 0-33.
+
+@item
+As a string with no delimiters in @code{'HHMMSS'} format, provided that
+it makes sense as a time. For example, @code{'101112'} is understood as
+@code{'10:11:12'}, but @code{'109712'} is illegal (it has a nonsensical
+minute part) and becomes @code{'00:00:00'}.
+
+@item
+As a number in @code{HHMMSS} format, provided that it makes sense as a time.
+For example, @code{101112} is understood as @code{'10:11:12'}. The following
+alternative formats are also understood: @code{SS}, @code{MMSS},@code{HHMMSS},
+@code{HHMMSS.fraction}. Note that @strong{MySQL} doesn't yet store the
+fraction part.
+
+@item
+As the result of a function that returns a value that is acceptable
+in a @code{TIME} context, such as @code{CURRENT_TIME}.
+@end itemize
+
+For @code{TIME} values specified as strings that include a time part
+delimiter, it is not necessary to specify two digits for hours, minutes or
+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. @strong{MySQL} interprets values using the assumption that the
+rightmost digits represent seconds. (@strong{MySQL} interprets @code{TIME}
+values as elapsed time, rather than as time of day.) For example, you might
+think of @code{'11:12'}, @code{'1112'} and @code{1112} as meaning
+@code{'11:12:00'} (12 minutes after 11 o'clock), but @strong{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'}.
+
+Values that lie outside the @code{TIME} range
+but are otherwise legal are clipped to the appropriate
+endpoint of the range. For example, @code{'-850:00:00'} and
+@code{'850:00:00'} are converted to @code{'-838:59:59'} and
+@code{'838:59:59'}.
+
+Illegal @code{TIME} values are converted to @code{'00:00:00'}. Note that
+because @code{'00:00:00'} is itself a legal @code{TIME} value, there is no way
+to tell, from a value of @code{'00:00:00'} stored in a table, whether the
+original value was specified as @code{'00:00:00'} or whether it was illegal.
+
+@tindex YEAR
+@node YEAR, , TIME, Date and time types
+@subsubsection The @code{YEAR} type
+
+The @code{YEAR} type is a 1-byte type used for representing years.
+
+@strong{MySQL} retrieves and displays @code{YEAR} values in @code{YYYY}
+format. The range is @code{1901} to @code{2155}.
+
+You can specify @code{YEAR} values in a variety of formats:
+
+@itemize @bullet
+@item
+As a four-digit string in the range @code{'1901'} to @code{'2155'}.
+
+@item
+As a four-digit number in the range @code{1901} to @code{2155}.
+
+@item
+As a two-digit string in the range @code{'00'} to @code{'99'}. Values in the
+ranges @code{'00'} to @code{'69'} and @code{'70'} to @code{'99'} are
+converted to @code{YEAR} values in the ranges @code{2000} to @code{2069} and
+@code{1970} to @code{1999}.
+
+@item
+As a two-digit number in the range @code{1} to @code{99}. Values in the
+ranges @code{1} to @code{69} and @code{70} to @code{99} are converted to
+@code{YEAR} values in the ranges @code{2001} to @code{2069} and @code{1970}
+to @code{1999}. Note that the range for two-digit numbers is slightly
+different than the range for two-digit strings, because you cannot specify zero
+directly as a number and have it be interpreted as @code{2000}. You
+@emph{must} specify it as a string @code{'0'} or @code{'00'} or it will be
+interpreted as @code{0000}.
+
+@item
+As the result of a function that returns a value that is acceptable
+in a @code{YEAR} context, such as @code{NOW()}.
+@end itemize
+
+Illegal @code{YEAR} values are converted to @code{0000}.
+
+@node String types, Choosing types, Date and time types, Column types
+@subsection String types
+
+The string types are @code{CHAR}, @code{VARCHAR}, @code{BLOB}, @code{TEXT},
+@code{ENUM} and @code{SET}.
+
+@tindex CHAR
+@tindex VARCHAR
+@menu
+* CHAR:: The @code{CHAR} and @code{VARCHAR} types
+* BLOB:: The @code{BLOB} and @code{TEXT} types
+* ENUM:: The @code{ENUM} type
+* SET:: The @code{SET} type
+@end menu
+
+@node CHAR, BLOB, String types, String types
+@subsubsection The @code{CHAR} and @code{VARCHAR} types
+
+The @code{CHAR} and @code{VARCHAR} types are similar, but differ in the
+way they are stored and retrieved.
+
+The length of a @code{CHAR} column is fixed to the length that you declare
+when you create the table. The length can be any value between 1 and 255.
+(As of @strong{MySQL} 3.23, the length of @code{CHAR} may be 0 to 255.)
+When @code{CHAR} values are stored, they are right-padded with spaces to the
+specified length. When @code{CHAR} values are retrieved, trailing spaces are
+removed.
+
+Values in @code{VARCHAR} columns are variable-length strings. You can
+declare a @code{VARCHAR} column to be any length between 1 and 255, just as
+for @code{CHAR} columns. However, in contrast to @code{CHAR}, @code{VARCHAR}
+values are stored using only as many characters as are needed, plus one byte
+to record the length. Values are not padded; instead, trailing spaces are
+removed when values are stored. (This space removal differs from the ANSI
+SQL specification.)
+
+If you assign a value to a @code{CHAR} or @code{VARCHAR} column that
+exceeds the column's maximum length, the value is truncated to fit.
+
+The table below illustrates the differences between the two types of columns
+by showing the result of storing various string values into @code{CHAR(4)}
+and @code{VARCHAR(4)} columns:
+
+@c Need to use @(space) to make sure second column values retain spacing
+@c in output for table below.
+
+@multitable @columnfractions .2 .15 .2 .2 .25
+@item @strong{Value} @tab @code{CHAR(4)} @tab @strong{Storage required} @tab @code{VARCHAR(4)} @tab @strong{Storage required}
+@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
+
+The values retrieved from the @code{CHAR(4)} and @code{VARCHAR(4)} columns
+will be the same in each case, because trailing spaces are removed from
+@code{CHAR} columns upon retrieval.
+
+Values in @code{CHAR} and @code{VARCHAR} columns are sorted and compared in
+case-insensitive fashion, unless the @code{BINARY} attribute was specified
+when the table was created. The @code{BINARY} attribute means that column
+values are sorted and compared in case-sensitive fashion according to the
+ASCII order of the machine where the @strong{MySQL} server is running.
+
+The @code{BINARY} attribute is ``sticky''. This means that if a column marked
+@code{BINARY} is used in an expression, the whole expression is compared as a
+@code{BINARY} value.
+
+@strong{MySQL} may silently change the type of a @code{CHAR} or @code{VARCHAR}
+column at table creation time.
+@xref{Silent column changes}.
+
+@tindex BLOB
+@tindex TEXT
+@node BLOB, ENUM, CHAR, String types
+@subsubsection The @code{BLOB} and @code{TEXT} types
+
+A @code{BLOB} is a binary large object that can hold a variable amount of
+data. The four @code{BLOB} types @code{TINYBLOB}, @code{BLOB},
+@code{MEDIUMBLOB} and @code{LONGBLOB} differ only in the maximum length of
+the values they can hold.
+@xref{Storage requirements}.
+
+The four @code{TEXT} types @code{TINYTEXT}, @code{TEXT}, @code{MEDIUMTEXT}
+and @code{LONGTEXT} correspond to the four @code{BLOB} types and have the
+same maximum lengths and storage requirements. The only difference between
+@code{BLOB} and @code{TEXT} types is that sorting and comparison is performed
+in case-sensitive fashion for @code{BLOB} values and case-insensitive fashion
+for @code{TEXT} values. In other words, a @code{TEXT} is a case-insensitive
+@code{BLOB}.
+
+If you assign a value to a @code{BLOB} or @code{TEXT} column that exceeds
+the column type's maximum length, the value is truncated to fit.
+
+In most respects, you can regard a @code{TEXT} column as a @code{VARCHAR}
+column that can be as big as you like. Similarly, you can regard a
+@code{BLOB} column as a @code{VARCHAR BINARY} column. The differences are:
+
+@itemize @bullet
+@item
+You can have indexes on @code{BLOB} and @code{TEXT} columns with
+@strong{MySQL} versions 3.23.2 and newer. Older versions of
+@strong{MySQL} did not support this.
+
+@item
+There is no trailing-space removal for @code{BLOB} and @code{TEXT} columns
+when values are stored, as there is for @code{VARCHAR} columns.
+
+@item
+@cindex Default values, @code{BLOB} and @code{TEXT} columns
+@cindex @code{BLOB} columns, default values
+@cindex @code{TEXT} columns, default values
+@code{BLOB} and @code{TEXT} columns cannot have @code{DEFAULT} values.
+@end itemize
+
+@strong{MyODBC} defines @code{BLOB} values as @code{LONGVARBINARY} and
+@code{TEXT} values as @code{LONGVARCHAR}.
+
+Because @code{BLOB} and @code{TEXT} values may be extremely long, you
+may run up against some constraints when using them:
+
+@itemize @bullet
+@item
+If you want to use @code{GROUP BY} or @code{ORDER BY} on a @code{BLOB} or
+@code{TEXT} column, you must convert the column value into a fixed-length
+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;
+@end example
+
+If you don't do this, only the first @code{max_sort_length} bytes of the
+column are used when sorting. The default value of @code{max_sort_length} is
+1024; this value can be changed using the @code{-O} option when starting the
+@code{mysqld} server. You can group on an expression involving @code{BLOB} or
+@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;
+@end example
+
+@item
+The maximum size of a @code{BLOB} or @code{TEXT} object is determined by its
+type, but the largest value you can actually transmit between the client and
+server is determined by the amount of available memory and the size of the
+communications buffers. You can change the message buffer size, but you must
+do so on both the server and client ends. @xref{Server parameters}.
+@end itemize
+
+Note that each @code{BLOB} or @code{TEXT} value is represented internally by
+a separately-allocated object. This is in contrast to all other column types,
+for which storage is allocated once per column when the table is opened.
+
+@tindex ENUM
+@node ENUM, SET, BLOB, String types
+@subsubsection The @code{ENUM} type
+
+An @code{ENUM} is a string object whose value normally is chosen from a list
+of allowed values that are enumerated explicitly in the column specification
+at table creation time.
+
+The value may also be the empty string (@code{""}) or @code{NULL} under
+certain circumstances:
+
+@itemize @bullet
+@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.
+
+@item
+If an @code{ENUM} is declared @code{NULL}, @code{NULL} is also a legal value
+for the column, and the default value is @code{NULL}. If an @code{ENUM} is
+declared @code{NOT NULL}, the default value is the first element of the
+list of allowed values.
+@end itemize
+
+Each enumeration value has an index:
+
+@itemize @bullet
+@item
+Values from the list of allowable elements in the column specification are
+numbered beginning with 1.
+
+@item
+The index value of the empty string error value is 0. This means that you
+can use the following @code{SELECT} statement to find rows into which invalid
+@code{ENUM} values were assigned:
+
+@example
+mysql> SELECT * FROM tbl_name WHERE enum_col=0;
+@end example
+
+@item
+The index of the @code{NULL} value is @code{NULL}.
+@end itemize
+
+For example, a column specified as @code{ENUM("one", "two", "three")} can
+have any of the values shown below. The index of each value is also shown:
+
+@multitable @columnfractions .2 .8
+@item @strong{Value} @tab @strong{Index}
+@item @code{NULL} @tab @code{NULL}
+@item @code{""} @tab 0
+@item @code{"one"} @tab 1
+@item @code{"two"} @tab 2
+@item @code{"three"} @tab 3
+@end multitable
+
+An enumeration can have a maximum of 65535 elements.
+
+Lettercase is irrelevant when you assign values to an @code{ENUM} column.
+However, values retrieved from the column later have lettercase matching the
+values that were used to specify the allowable values at table creation time.
+
+If you retrieve an @code{ENUM} in a numeric context, the column value's index
+is returned. If you store a number into an @code{ENUM}, the number is
+treated as an index, and the the value stored is the enumeration member with
+that index. (However, this will not work with @code{LOAD DATA}, which treats
+all input as strings.)
+
+@code{ENUM} values are sorted according to the order in which the enumeration
+members were listed in the column specification. (In other words,
+@code{ENUM} values are sorted according to their index numbers.) For
+example, @code{"a"} sorts before @code{"b"} for @code{ENUM("a", "b")}, but
+@code{"b"} sorts before @code{"a"} for @code{ENUM("b", "a")}. The empty
+string sorts before non-empty strings, and @code{NULL} values sort before
+all other enumeration values.
+
+If you want to get all possible values for an @code{ENUM} column, you should
+use: @code{SHOW COLUMNS FROM table_name LIKE enum_column_name} and parse
+the @code{ENUM} definition in the second column.
+
+@tindex SET
+@node SET, , ENUM, String types
+@subsubsection The @code{SET} type
+
+A @code{SET} is a string object that can have zero or more values, each of
+which must be chosen from a list of allowed values specified when the table
+is created. @code{SET} column values that consist of multiple set members
+are specified with members separated by commas (@samp{,}). A consequence of
+this is that @code{SET} member values cannot themselves contain commas.
+
+For example, a column specified as @code{SET("one", "two") NOT NULL} can have
+any of these values:
+
+@example
+""
+"one"
+"two"
+"one,two"
+@end example
+
+
+A @code{SET} can have a maximum of 64 different members.
+
+@strong{MySQL} stores @code{SET} values numerically, with the low-order bit
+of the stored value corresponding to the first set member. If you retrieve a
+@code{SET} value in a numeric context, the value retrieved has bits set
+corresponding to the set members that make up the column value. If a number
+is stored into a @code{SET} column, the bits that are set in the binary
+representation of the number determine the set members in the column value.
+Suppose a column is specified as @code{SET("a","b","c","d")}. Then the
+members have the following bit values:
+
+@multitable @columnfractions .2 .2 .6
+@item @code{SET} @strong{member} @tab @strong{Decimal value} @tab @strong{Binary value}
+@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
+
+If you assign a value of @code{9} to this column, that is @code{1001} in
+binary, so the first and fourth @code{SET} value members @code{"a"} and
+@code{"d"} are selected and the resulting value is @code{"a,d"}.
+
+For a value containing more than one @code{SET} element, it does not matter
+what order the elements are listed in when you insert the value. It also
+does not matter how many times a given element is listed in the value.
+When the value is retrieved later, each element in the value will appear
+once, with elements listed according to the order in which they were
+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.
+
+@code{SET} values are sorted numerically. @code{NULL} values sort before
+non-@code{NULL} @code{SET} values.
+
+Normally, you perform a @code{SELECT} on a @code{SET} column using
+the @code{LIKE} operator or the @code{FIND_IN_SET()} function:
+
+@example
+mysql> SELECT * FROM tbl_name WHERE set_col LIKE '%value%';
+mysql> SELECT * FROM tbl_name WHERE FIND_IN_SET('value',set_col)>0;
+@end example
+
+But the following will also work:
+
+@example
+mysql> SELECT * FROM tbl_name WHERE set_col = 'val1,val2';
+mysql> SELECT * FROM tbl_name WHERE set_col & 1;
+@end example
+
+The first of these statements looks for an exact match. The second looks
+for values containing the first set member.
+
+If you want to get all possible values for a @code{SET} column, you should
+use: @code{SHOW COLUMNS FROM table_name LIKE set_column_name} and parse
+the @code{SET} definition in the second column.
+
+@cindex Types, choosing
+@cindex Choosing types
+@node Choosing types, Indexes, String types, Column types
+@subsection Choosing the right type for a column
+
+For the most efficient use of storage, try to use the most precise type in
+all cases. For example, if an integer column will be used for values in the
+range between @code{1} and @code{99999}, @code{MEDIUMINT UNSIGNED} is the
+best type.
+
+Accurate representation of monetary values is a common problem. In
+@strong{MySQL}, you should use the @code{DECIMAL} type. This is stored as
+a string, so no loss of accuracy should occur. If accuracy is not
+too important, the @code{DOUBLE} type may also be good enough.
+
+For high precision, you can always convert to a fixed-point type stored
+in a @code{BIGINT}. This allows you to do all calculations with integers
+and convert results back to floating-point values only when necessary.
+
+@cindex Indexes
+@cindex Keys
+@node Indexes, Multiple-column indexes, Choosing types, Column types
+@subsection Column indexes
+
+All @strong{MySQL} column types can be indexed. Use of indexes on the
+relevant columns is the best way to improve the performance of @code{SELECT}
+operations.
+
+A table may have up to 16 indexes. The maximum index length is
+256 bytes, although this may be changed when compiling @strong{MySQL}.
+
+For @code{CHAR} and @code{VARCHAR} columns, you can index a prefix of a
+column. This is much faster and requires less disk space than indexing the
+whole column. The syntax to use in the @code{CREATE TABLE} statement to
+index a column prefix looks like this:
+
+@example
+KEY index_name (col_name(length))
+@end example
+
+The example below creates an index for the first 10 characters of the
+@code{name} column:
+
+@example
+mysql> CREATE TABLE test (
+ 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
+column, you cannot index the entire thing.
+
+@node Multiple-column indexes, Other-vendor column types, Indexes, Column types
+@subsection Multiple-column indexes
+
+@strong{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).
+
+A multiple-column index can be considered a sorted array containing values
+that are created by concatenating the values of the indexed columns.
+
+@strong{MySQL} uses multiple-column indexes in such a way that queries are
+fast when you specify a known quantity for the first column of the index in a
+@code{WHERE} clause, even if you don't specify values for the other columns.
+
+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));
+@end example
+
+Then the index @code{name} is an index over @code{last_name} and
+@code{first_name}. The index will be used for queries that specify
+values in a known range for @code{last_name}, or for both @code{last_name}
+and @code{first_name}.
+Therefore, the @code{name} index will be used in the following queries:
+
+@example
+mysql> SELECT * FROM test WHERE last_name="Widenius";
+
+mysql> SELECT * FROM test WHERE last_name="Widenius"
+ AND first_name="Michael";
+
+mysql> SELECT * FROM test WHERE last_name="Widenius"
+ AND (first_name="Michael" OR first_name="Monty");
+
+mysql> SELECT * FROM test WHERE last_name="Widenius"
+ AND first_name >="M" AND first_name < "N";
+@end example
+
+However, the @code{name} index will NOT be used in the following queries:
+
+@example
+mysql> SELECT * FROM test WHERE first_name="Michael";
+
+mysql> SELECT * FROM test WHERE last_name="Widenius"
+ OR first_name="Michael";
+@end example
+
+For more information on the manner in which @strong{MySQL} uses indexes to
+improve query performance, see @ref{MySQL indexes, , @strong{MySQL}
+indexes}.
+
+@cindex Type portability
+@node Other-vendor column types, , Multiple-column indexes, Column types
+@subsection Using column types from other database engines
+
+To make it easier to use code written for SQL implementations from other
+vendors, @strong{MySQL} maps column types as shown in the table below. These
+mappings make it easier to move table definitions from other database engines
+to @strong{MySQL}:
+
+@multitable @columnfractions .4 .6
+@item @strong{Other vendor type} @tab @strong{MySQL type}
+@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
+
+Column type mapping occurs at table creation time. If you create a table
+with types used by other vendors and then issue a @code{DESCRIBE tbl_name}
+statement, @strong{MySQL} reports the table structure using the equivalent
+@strong{MySQL} types.
+
+@cindex Functions for @code{SELECT} and @code{WHERE} clauses
+@node Functions, CREATE DATABASE, Column types, Reference
+@section Functions for use in @code{SELECT} and @code{WHERE} clauses
+
+A @code{select_expression} or @code{where_definition} in a SQL statement
+can consist of any expression using the functions described below.
+
+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
+parenthesis following it. This helps the @strong{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,
+though.
+
+@need 2000
+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);
+1 rows in set (0.00 sec)
+
++-----------+
+| mod(29,9) |
++-----------+
+| 2 |
++-----------+
+@end example
+
+Is displayed like this:
+
+@example
+mysql> select MOD(29,9);
+ -> 2
+@end example
+
+@menu
+* Grouping functions:: Grouping functions
+* Arithmetic functions:: Normal arithmetic operations
+* Bit functions:: Bit functions
+* Logical functions:: Logical operations
+* Comparison functions:: Comparison operators
+* String comparison functions:: String comparison functions
+* Casts:: Cast operators
+* Control flow functions:: Control flow functions
+* Mathematical functions:: Mathematical functions
+* String functions:: String functions
+* Date and time functions:: Date and time functions
+* Miscellaneous functions:: Miscellaneous functions
+* Group by functions:: Functions for @code{GROUP BY} clause
+@end menu
+
+@node Grouping functions, Arithmetic functions, Functions, Functions
+@subsection Grouping functions
+@cindex Grouping of expressions
+@table @code
+
+@findex () (parentheses)
+@findex parentheses ( and )
+@item ( ... )
+Parentheses. Use these to force the order of evaluation in an expression.
+@example
+mysql> select 1+2*3;
+ -> 7
+mysql> select (1+2)*3;
+ -> 9
+@end example
+@end table
+
+@node Arithmetic functions, Bit functions, Grouping functions, Functions
+@subsection Normal arithmetic operations
+
+The usual arithmetic operators are available. Note that in the case of
+@code{-}, @code{+} and @code{*}, the result is calculated with @code{BIGINT}
+(64-bit) precision if both arguments are integers!
+
+@cindex Arithmetic expressions
+@table @code
+@findex + (addition)
+@findex addition (+)
+@item +
+Addition
+@example
+mysql> select 3+5;
+ -> 8
+@end example
+
+@findex - (subtraction)
+@findex subtraction (-)
+@item -
+Subtraction
+@example
+mysql> select 3-5;
+ -> -2
+@end example
+
+@findex * (multiplication)
+@findex multiplication (*)
+@item *
+Multiplication
+@example
+mysql> select 3*5;
+ -> 15
+mysql> select 18014398509481984*18014398509481984.0;
+ -> 324518553658426726783156020576256.0
+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.
+
+@findex / (division)
+@findex division (/)
+@item /
+Division
+@example
+mysql> select 3/5;
+ -> 0.60
+@end example
+
+Division by zero produces a @code{NULL} result:
+
+@example
+mysql> select 102/(1-1);
+ -> NULL
+@end example
+
+A division will be calculated with @code{BIGINT} arithmetic only if performed
+in a context where its result is converted to an integer!
+@end table
+
+@findex Arithmetic functions
+@findex Bit functions
+@findex Functions, arithmetic
+@findex Functions, bit
+@node Bit functions, Logical functions, Arithmetic functions, Functions
+@subsection Bit functions
+
+@strong{MySQL} uses @code{BIGINT} (64-bit) arithmetic for bit operations, so
+these operators have a maximum range of 64 bits.
+
+@table @code
+@findex | (bitwise OR)
+@findex OR, bitwise
+@item |
+Bitwise OR
+@example
+mysql> select 29 | 15;
+ -> 31
+@end example
+
+@findex & (bitwise AND)
+@findex AND, bitwise
+@item &
+Bitwise AND
+@example
+mysql> select 29 & 15;
+ -> 13
+@end example
+
+@findex << (left shift)
+@item <<
+Shifts a longlong (@code{BIGINT}) number to the left.
+@example
+mysql> select 1 << 2
+ -> 4
+@end example
+
+@findex >> (right shift)
+@item >>
+Shifts a longlong (@code{BIGINT}) number to the right.
+@example
+mysql> select 4 >> 2
+ -> 1
+@end example
+
+@findex ~
+@item ~
+Invert all bits.
+@example
+mysql> select 5 & ~1
+ -> 4
+@end example
+
+@findex BIT_COUNT()
+@item BIT_COUNT(N)
+Returns the number of bits that are set in the argument @code{N}.
+@example
+mysql> select BIT_COUNT(29);
+ -> 4
+@end example
+@end table
+
+@findex Logical functions
+@findex Functions, logical
+@node Logical functions, Comparison functions, Bit functions, Functions
+@subsection Logical operations
+
+All logical functions return @code{1} (TRUE) or @code{0} (FALSE).
+
+@table @code
+@findex NOT, logical
+@findex ! (logical NOT)
+@item NOT
+@itemx !
+Logical NOT. Returns @code{1} if the argument is @code{0}, otherwise returns
+@code{0}.
+Exception: @code{NOT NULL} returns @code{NULL}.
+@example
+mysql> select NOT 1;
+ -> 0
+mysql> select NOT NULL;
+ -> NULL
+mysql> select ! (1+1);
+ -> 0
+mysql> select ! 1+1;
+ -> 1
+@end example
+The last example returns @code{1} because the expression evaluates
+the same way as @code{(!1)+1}.
+
+@findex OR, logical
+@findex || (logical OR)
+@item OR
+@itemx ||
+Logical OR. Returns @code{1} if either argument is not @code{0} and not
+@code{NULL}.
+@example
+mysql> select 1 || 0;
+ -> 1
+mysql> select 0 || 0;
+ -> 0
+mysql> select 1 || NULL;
+ -> 1
+
+@end example
+
+@findex AND, logical
+@findex && (logical AND)
+@item AND
+@itemx &&
+Logical AND. Returns @code{0} if either argument is @code{0} or @code{NULL},
+otherwise returns @code{1}.
+@example
+mysql> select 1 && NULL;
+ -> 0
+mysql> select 1 && 0;
+ -> 0
+@end example
+@end table
+
+@cindex Casts
+@cindex Type conversions
+@findex Comparison operators
+@node Comparison functions, String comparison functions, Logical functions, Functions
+@subsection Comparison operators
+
+Comparison operations result in a value of @code{1} (TRUE), @code{0} (FALSE)
+or @code{NULL}. These functions work for both numbers and strings. Strings
+are automatically converted to numbers and numbers to strings as needed (as
+in Perl).
+
+@strong{MySQL} performs comparisons using the following
+rules:
+
+@itemize @bullet
+@item
+If one or both arguments are @code{NULL}, the result of the comparison
+is @code{NULL}, except for the @code{<=>} operator.
+
+@item
+If both arguments in a comparison operation are strings, they are compared as
+strings.
+
+@item
+If both arguments are integers, they are compared as integers.
+
+@item
+Hexadecimal values are treated as binary strings if not compared to a number.
+
+@item
+@cindex ODBC compatibility
+@cindex Compatibility, with ODBC
+If one of the arguments is a @code{TIMESTAMP} or @code{DATETIME} column and
+the other argument is a constant, the constant is converted
+to a timestamp before the comparison is performed. This is done to be more
+ODBC-friendly.
+
+@item
+In all other cases, the arguments are compared as floating-point (real)
+numbers.
+@end itemize
+
+By default, string comparisons are done in case-independent fashion using the
+current character set (ISO-8859-1 Latin1 by default, which also works
+excellently for English).
+
+The examples below illustrate conversion of strings to numbers for comparison
+operations:
+
+@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 = (equal)
+@findex equal (=)
+@item =
+Equal
+@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 <> (not equal)
+@findex not equal (<>)
+@findex != (not equal)
+@findex not equal (!=)
+@item <>
+@itemx !=
+Not equal
+@example
+mysql> select '.01' <> '0.01';
+ -> 1
+mysql> select .01 <> '0.01';
+ -> 0
+mysql> select 'zapp' <> 'zappp';
+ -> 1
+@end example
+
+@findex <= (less than or equal)
+@findex less than or equal (<=)
+@item <=
+Less than or equal
+@example
+mysql> select 0.1 <= 2;
+ -> 1
+@end example
+
+@findex < (less than)
+@findex less than (<)
+@item <
+Less than
+@example
+mysql> select 2 <= 2;
+ -> 1
+@end example
+
+@findex >= (greater than or equal)
+@findex greater than or equal (>=)
+@item >=
+Greater than or equal
+@example
+mysql> select 2 >= 2;
+ -> 1
+@end example
+
+@findex > (greater than)
+@findex greater than (>)
+@item >
+Greater than
+@example
+mysql> select 2 > 2;
+ -> 0
+@end example
+
+@findex <=> (Equal to)
+@item <=>
+Null safe equal
+@example
+mysql> select 1 <=> 1, NULL <=> NULL, 1 <=> NULL;
+ -> 1 1 0
+@end example
+
+@findex IS NULL
+@findex IS NOT NULL
+@item IS NULL
+@itemx IS NOT NULL
+Test whether or not a value is or is not @code{NULL}
+@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 expr BETWEEN min AND max
+If @code{expr} is greater than or equal to @code{min} and @code{expr} is
+less than or equal to @code{max}, @code{BETWEEN} returns @code{1},
+otherwise it returns @code{0}. This is equivalent to the expression
+@code{(min <= expr AND expr <= max)} if all the arguments are of the
+same type. The first argument (@code{expr}) determines how the
+comparison is performed as follows:
+
+@itemize @bullet
+@item
+If @code{expr} is a @code{TIMESTAMP}, @code{DATE} or @code{DATETIME}
+column, min and max are formatted to the same format if they
+are constants.
+@item
+If @code{expr} is a case-insensitive string expression, a case-insensitive
+string comparison is done.
+@item
+If @code{expr} is a case-sensitive string expression, a case-sensitive
+string comparison is done.
+@item
+If @code{expr} is an integer expression, an integer comparison is done.
+@item
+Otherwise, a floating-point (real) comparison is done.
+@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 expr IN (value,...)
+Returns @code{1} if @code{expr} is any of the values in the @code{IN} list,
+else returns @code{0}. If all values are constants, then all values are
+evaluated according to the type of @code{expr} and sorted. The search for the
+item is then done using a binary search. This means @code{IN} is very quick
+if the @code{IN} value list consists entirely of constants. If @code{expr}
+is a case-sensitive string expression, the string comparison is performed in
+case-sensitive fashion.
+
+@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 expr NOT IN (value,...)
+Same as @code{NOT (expr IN (value,...))}.
+
+@findex ISNULL()
+@item ISNULL(expr)
+If @code{expr} is @code{NULL}, @code{ISNULL()} returns @code{1}, otherwise
+it returns @code{0}.
+@example
+mysql> select ISNULL(1+1);
+ -> 0
+mysql> select ISNULL(1/0);
+ -> 1
+@end example
+
+Note that a comparison of @code{NULL} values using @code{=} will always be
+false!
+
+@findex COALESCE()
+@item COALESCE(list)
+Returns first non-@code{NULL} element in list.
+
+@example
+mysql> select COALESCE(NULL,1);
+ -> 1
+mysql> select COALESCE(NULL,NULL,NULL);
+ -> NULL
+@end example
+
+@findex INTERVAL()
+@item INTERVAL(N,N1,N2,N3,...)
+Returns @code{0} if @code{N} < @code{N1}, @code{1} if @code{N} < @code{N2}
+and so on. All arguments are treated as integers. It is required that
+@code{N1} < @code{N2} < @code{N3} < @code{...} < @code{Nn} for this function
+to work correctly. This is because a binary search is used (very fast).
+
+@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
+
+@findex String comparison functions
+@findex Functions, string comparison
+@node String comparison functions, Casts, Comparison functions, Functions
+@subsection String comparison functions
+
+@cindex Case sensitivity, in string comparisons
+@cindex String comparisons, case sensitivity
+Normally, if any expression in a string comparison is case sensitive, the
+comparison is performed in case-sensitive fashion.
+
+@table @code
+@findex LIKE
+@item expr LIKE pat [ESCAPE 'escape-char']
+Pattern matching using
+SQL simple regular expression comparison. Returns @code{1} (TRUE) or @code{0}
+(FALSE). With @code{LIKE} you can use the following two wildcard characters
+in the pattern:
+
+@multitable @columnfractions .1 .9
+@item @code{%} @tab Matches any number of characters, even zero characters
+@item @code{_} @tab Matches exactly one character
+@end multitable
+
+@example
+mysql> select 'David!' LIKE 'David_';
+ -> 1
+mysql> select 'David!' LIKE '%D%v%';
+ -> 1
+@end example
+
+To test for literal instances of a wildcard character, precede the character
+with the escape character. If you don't specify the @code{ESCAPE} character,
+@samp{\} is assumed:
+
+@multitable @columnfractions .1 .9
+@item @code{\%} @tab Matches one @code{%} character
+@item @code{\_} @tab Matches one @code{_} character
+@end multitable
+
+@example
+mysql> select 'David!' LIKE 'David\_';
+ -> 0
+mysql> select 'David_' LIKE 'David\_';
+ -> 1
+@end example
+
+To specify a different escape character, use the @code{ESCAPE} clause:
+
+@example
+mysql> select 'David_' LIKE 'David|_' ESCAPE '|';
+ -> 1
+@end example
+
+@code{LIKE} is allowed on numeric expressions! (This is a @strong{MySQL}
+extension to the ANSI SQL @code{LIKE}.)
+
+@example
+mysql> select 10 LIKE '1%';
+ -> 1
+@end example
+
+Note: Because @strong{MySQL} uses the C escape syntax in strings (e.g.,
+@samp{\n}), you must double any @samp{\} that you use in your @code{LIKE}
+strings. For example, to search for @samp{\n}, specify it as @samp{\\n}. To
+search for @samp{\}, specify it as @samp{\\\\} (the backslashes are stripped
+once by the parser, and another time when the pattern match is done, leaving
+a single backslash to be matched).
+
+@findex NOT LIKE
+@item expr NOT LIKE pat [ESCAPE 'escape-char']
+Same as @code{NOT (expr LIKE pat [ESCAPE 'escape-char'])}.
+
+@cindex mSQL compatibility
+@cindex Compatibility, with mSQL
+@findex REGEXP
+@findex RLIKE
+@item expr REGEXP pat
+@itemx expr RLIKE pat
+Performs a pattern match of a string expression @code{expr} against a pattern
+@code{pat}. The pattern can be an extended regular expression.
+@xref{Regexp}. Returns @code{1} if @code{expr} matches @code{pat}, otherwise
+returns @code{0}. @code{RLIKE} is a synonym for @code{REGEXP}, provided for
+@code{mSQL} compatibility. Note: Because @strong{MySQL} uses the C escape
+syntax in strings (e.g., @samp{\n}), you must double any @samp{\} that you
+use in your @code{REGEXP} strings. In @code{MySQL} 3.23.4
+@code{REGEXP} is case insensitive for normal (not binary) strings.
+
+@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
+@end example
+
+@item
+@code{REGEXP} and @code{RLIKE} use the current character set (ISO-8859-1
+Latin1 by default) when deciding the type of a character.
+
+@findex NOT REGEXP
+@item expr NOT REGEXP pat
+@itemx expr NOT RLIKE pat
+Same as @code{NOT (expr REGEXP pat)}.
+
+@findex STRCMP()
+@item STRCMP(expr1,expr2)
+@code{STRCMP()}
+returns @code{0} if the strings are the same, @code{-1} if the first
+argument is smaller than the second according to the current sort order,
+and @code{1} otherwise.
+
+@example
+mysql> select STRCMP('text', 'text2');
+ -> -1
+mysql> select STRCMP('text2', 'text');
+ -> 1
+mysql> select STRCMP('text', 'text');
+ -> 0
+@end example
+@end table
+
+@findex Casts
+@node Casts, Control flow functions, String comparison functions, Functions
+@subsection Cast operators
+
+@table @code
+@findex BINARY
+@item @code{BINARY}
+The @code{BINARY} operator casts the string following it to a binary string.
+This is an easy way to force a column comparison to be case sensitive even
+if the column isn't defined as @code{BINARY} or @code{BLOB}.
+@example
+mysql> select "a" = "A";
+ -> 1
+mysql> select BINARY "a" = "A";
+ -> 0
+@end example
+
+@code{BINARY} was introduced in @strong{MySQL} 3.23.0
+@end table
+
+@findex Control flow functions
+@findex Functions, control flow
+@node Control flow functions, Mathematical functions, Casts, Functions
+@subsection Control flow functions
+
+@table @code
+@findex IFNULL()
+@item IFNULL(expr1,expr2)
+If @code{expr1} is not @code{NULL}, @code{IFNULL()} returns @code{expr1},
+else it returns @code{expr2}. @code{IFNULL()} returns a numeric or string
+value, depending on the context in which it is used.
+@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,'yes');
+ -> 'yes'
+@end example
+
+@findex NULLIF()
+@item NULLIF(expr1,expr2)
+If @code{expr1 = expr2} is true, return @code{NULL} else return @code{expr1}.
+This is the same as @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
+
+Note that @code{expr1} is evaluated twice in @strong{MySQL} if the arguments
+are equal.
+
+@findex IF()
+@item IF(expr1,expr2,expr3)
+If @code{expr1} is TRUE (@code{expr1 <> 0} and @code{expr1 <> NULL}) then
+@code{IF()} returns @code{expr2}, else it returns @code{expr3}.
+@code{IF()} returns a numeric or string value, depending on the context
+in which it is used.
+
+@example
+mysql> select IF(1>2,2,3);
+ -> 3
+mysql> select IF(1<2,'yes','no');
+ -> 'yes'
+mysql> select IF(strcmp('test','test1'),'no','yes');
+ -> 'no'
+@end example
+
+@code{expr1} is evaluated as an integer value, which means that if you are
+testing floating-point or string values, you should do so using a comparison
+operation.
+
+@example
+mysql> select IF(0.1,1,0);
+ -> 0
+mysql> select IF(0.1<>0,1,0);
+ -> 1
+@end example
+
+In the first case above, @code{IF(0.1)} returns @code{0} because @code{0.1}
+is converted to an integer value, resulting in a test of @code{IF(0)}. This
+may not be what you expect. In the second case, the comparison tests the
+original floating-point value to see whether it is non-zero. The result
+of the comparison is used as an integer.
+
+The default return type of @code{IF()} (which may matter when it stored into
+a temporary table) is calculated in @strong{MySQL} 3.23 as follows:
+
+@multitable @columnfractions .7 .3
+@item expr2 or expr3 returns string @tab string
+@item expr2 or expr3 returns a floating point value @tab floating point
+@item expr2 or expr3 returns an integer @tab integer
+@end multitable
+
+@findex CASE
+@item CASE value WHEN [compare-value] THEN result [WHEN [compare-value] THEN result ...] [ELSE result] END
+@item CASE WHEN [condition] THEN result [WHEN [condition] THEN result ...] [ELSE result] END
+
+The first version returns the @code{result} where
+@code{value=compare-value}. The second version returns the result for
+the first condition which is true. If there was no matching result
+value, then the result after @code{ELSE} is returned. If there is no
+@code{ELSE} part then @code{NULL} is returned.
+
+@example
+mysql> SELECT CASE 1 WHEN 1 THEN "one" WHEN 2 THEN "two" ELSE "more" END;
+ -> "one"
+mysql> SELECT CASE WHEN 1>0 THEN "true" ELSE "false" END;
+ -> "true"
+mysql> SELECT CASE BINARY "B" when "a" then 1 when "b" then 2 END;
+ -> NULL
+@end example
+@end table
+
+@findex Mathematical functions
+@findex Functions, mathematical
+@node Mathematical functions, String functions, Control flow functions, Functions
+@subsection Mathematical functions
+All mathematical functions return @code{NULL} in case of an error.
+
+@table @code
+@findex - (unary minus)
+@findex minus, unary (-)
+@findex unary minus (-)
+@item -
+Unary minus. Changes the sign of the argument.
+@example
+mysql> select - 2;
+ -> -2
+@end example
+
+Note that if this operator is used with a @code{BIGINT}, the return value is a
+@code{BIGINT}! This means that you should avoid using @code{-} on integers that
+may have the value of @code{-2^63}!
+
+@findex ABS()
+@item ABS(X)
+Returns the absolute value of @code{X}.
+@example
+mysql> select ABS(2);
+ -> 2
+mysql> select ABS(-32);
+ -> 32
+@end example
+
+This function is safe to use with @code{BIGINT} values.
+
+@findex SIGN()
+@item SIGN(X)
+Returns the sign of the argument as @code{-1}, @code{0} or @code{1}, depending
+on whether @code{X} is negative, zero, or positive.
+@example
+mysql> select SIGN(-32);
+ -> -1
+mysql> select SIGN(0);
+ -> 0
+mysql> select SIGN(234);
+ -> 1
+@end example
+
+@findex MOD()
+@findex % (modulo)
+@findex modulo (%)
+@item MOD(N,M)
+@itemx %
+Modulo (like the @code{%} operator in C).
+Returns the remainder of @code{N} divided by @code{M}.
+@example
+mysql> select MOD(234, 10);
+ -> 4
+mysql> select 253 % 7;
+ -> 1
+mysql> select MOD(29,9);
+ -> 2
+@end example
+
+This function is safe to use with @code{BIGINT} values.
+
+@findex FLOOR()
+@item FLOOR(X)
+Returns the largest integer value not greater than @code{X}.
+@example
+mysql> select FLOOR(1.23);
+ -> 1
+mysql> select FLOOR(-1.23);
+ -> -2
+@end example
+
+Note that the return value is converted to a @code{BIGINT}!
+
+@findex CEILING()
+@item CEILING(X)
+Returns the smallest integer value not less than @code{X}.
+@example
+mysql> select CEILING(1.23);
+ -> 2
+mysql> select CEILING(-1.23);
+ -> -1
+@end example
+
+Note that the return value is converted to a @code{BIGINT}!
+
+@findex ROUND()
+@item ROUND(X)
+Returns the argument @code{X}, rounded to the nearest integer.
+@example
+mysql> select ROUND(-1.23);
+ -> -1
+mysql> select ROUND(-1.58);
+ -> -2
+mysql> select ROUND(1.58);
+ -> 2
+@end example
+
+@findex ROUND()
+@item ROUND(X,D)
+Returns the argument @code{X}, rounded to a number with @code{D} decimals.
+If @code{D} is @code{0}, the result will have no decimal point or fractional
+part.
+
+@example
+mysql> select ROUND(1.298, 1);
+ -> 1.3
+mysql> select ROUND(1.298, 0);
+ -> 1
+@end example
+
+@findex EXP()
+@item EXP(X)
+Returns the value of @code{e} (the base of natural logarithms) raised to
+the power of @code{X}.
+@example
+mysql> select EXP(2);
+ -> 7.389056
+mysql> select EXP(-2);
+ -> 0.135335
+@end example
+@findex LOG()
+@item LOG(X)
+Returns the natural logarithm of @code{X}.
+@example
+mysql> select LOG(2);
+ -> 0.693147
+mysql> select LOG(-2);
+ -> NULL
+@end example
+If you want the log of a number @code{X} to some arbitary base @code{B}, use
+the formula @code{LOG(X)/LOG(B)}.
+
+@findex LOG10()
+@item LOG10(X)
+Returns the base-10 logarithm of @code{X}.
+@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)
+Returns the value of @code{X} raised to the power of @code{Y}.
+@example
+mysql> select POW(2,2);
+ -> 4.000000
+mysql> select POW(2,-2);
+ -> 0.250000
+@end example
+
+@findex SQRT()
+@item SQRT(X)
+Returns the non-negative square root of @code{X}.
+@example
+mysql> select SQRT(4);
+ -> 2.000000
+mysql> select SQRT(20);
+ -> 4.472136
+@end example
+
+@findex PI()
+@item PI()
+Returns the value of PI.
+@example
+mysql> select PI();
+ -> 3.141593
+@end example
+
+@findex COS()
+@item COS(X)
+Returns the cosine of @code{X}, where @code{X} is given in radians.
+@example
+mysql> select COS(PI());
+ -> -1.000000
+@end example
+
+@findex SIN()
+@item SIN(X)
+Returns the sine of @code{X}, where @code{X} is given in radians.
+@example
+mysql> select SIN(PI());
+ -> 0.000000
+@end example
+
+@findex TAN()
+@item TAN(X)
+Returns the tangent of @code{X}, where @code{X} is given in radians.
+@example
+mysql> select TAN(PI()+1);
+ -> 1.557408
+@end example
+
+@findex ACOS()
+@item ACOS(X)
+Returns the arc cosine of @code{X}, that is, the value whose cosine is
+@code{X}. Returns @code{NULL} if @code{X} is not in the range @code{-1} to
+@code{1}.
+@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)
+Returns the arc sine of @code{X}, that is, the value whose sine is
+@code{X}. Returns @code{NULL} if @code{X} is not in the range @code{-1} to
+@code{1}.
+@example
+mysql> select ASIN(0.2);
+ -> 0.201358
+mysql> select ASIN('foo');
+ -> 0.000000
+@end example
+
+@findex ATAN()
+@item ATAN(X)
+Returns the arc tangent of @code{X}, that is, the value whose tangent is
+@code{X}.
+@example
+mysql> select ATAN(2);
+ -> 1.107149
+mysql> select ATAN(-2);
+ -> -1.107149
+@end example
+
+@findex ATAN2()
+@item ATAN2(X,Y)
+Returns the arc tangent of the two variables @code{X} and @code{Y}. It is
+similar to calculating the arc tangent of @code{Y / X}, except that the
+signs of both arguments are used to determine the quadrant of the
+result.
+@example
+mysql> select ATAN(-2,2);
+ -> -0.785398
+mysql> select ATAN(PI(),0);
+ -> 1.570796
+@end example
+
+@findex COT()
+@item COT(X)
+Returns the cotangent of @code{X}.
+@example
+mysql> select COT(12);
+ -> -1.57267341
+mysql> select COT(0);
+ -> NULL
+@end example
+
+@findex RAND()
+@item RAND()
+@itemx RAND(N)
+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
+mysql> select RAND(20);
+ -> 0.1811
+mysql> select RAND(20);
+ -> 0.1811
+mysql> select RAND();
+ -> 0.2079
+mysql> select RAND();
+ -> 0.7888
+@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 @strong{MySQL} 3.23, you can however do:
+@code{SELECT * FROM table_name ORDER BY RAND()}
+
+This is useful to get a random sample of a set @code{SELECT * FROM
+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.
+
+@findex LEAST()
+@item LEAST(X,Y,...)
+With two or more arguments, returns the smallest (minimum-valued) argument.
+The arguments are compared using the following rules:
+
+@itemize @bullet
+@item
+If the return value is used in an @code{INTEGER} context, or all arguments
+are integer-valued, they are compared as integers.
+
+@item
+If the return value is used in a @code{REAL} context, or all arguments are
+real-valued, they are compared as reals.
+
+@item
+If any argument is a case-sensitive string, the arguments are compared
+as case-sensitive strings.
+
+@item
+In other cases, the arguments are compared as case-insensitive strings.
+@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 @strong{MySQL} versions prior to 3.22.5, you can use @code{MIN()} instead
+of @code{LEAST}.
+
+@findex GREATEST()
+@item GREATEST(X,Y,...)
+Returns the largest (maximum-valued) argument.
+The arguments are compared using the same rules as for @code{LEAST}.
+@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 @strong{MySQL} versions prior to 3.22.5, you can use @code{MAX()} instead
+of @code{GREATEST}.
+
+@findex DEGREES()
+@item DEGREES(X)
+Returns the argument @code{X}, converted from radians to degrees.
+@example
+mysql> select DEGREES(PI());
+ -> 180.000000
+@end example
+
+@findex RADIANS()
+@item RADIANS(X)
+Returns the argument @code{X}, converted from degrees to radians.
+@example
+mysql> select RADIANS(90);
+ -> 1.570796
+@end example
+
+@findex TRUNCATE()
+@item TRUNCATE(X,D)
+Returns the number @code{X}, truncated to @code{D} decimals. If @code{D}
+is @code{0}, the result will have no decimal point or fractional part.
+@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
+@end table
+
+@findex String functions
+@findex Functions, string
+@node String functions, Date and time functions, Mathematical functions, Functions
+@subsection String functions
+
+String-valued functions return @code{NULL} if the length of the result would
+be greater than the @code{max_allowed_packet} server parameter. @xref{Server
+parameters}.
+
+For functions that operate on string positions,
+the first position is numbered 1.
+
+@table @code
+@findex ASCII()
+@item ASCII(str)
+Returns the ASCII code value of the leftmost character of the string
+@code{str}. Returns @code{0} if @code{str} is the empty string. Returns
+@code{NULL} if @code{str} is @code{NULL}.
+
+@example
+mysql> select ASCII('2');
+ -> 50
+mysql> select ASCII(2);
+ -> 50
+mysql> select ASCII('dx');
+ -> 100
+@end example
+
+See also the @code{ORD()} function.
+
+@findex ORD()
+@item ORD(str)
+If the leftmost character of the string str is a multi-byte character,
+returns the code of multi-byte character by returning the ASCII code value
+of the character in the format of:
+@code{((first byte ASCII code)*256+(second byte ASCII code))[*256+third byte ASCII code...]}.
+If the leftmost character is not a multi-byte character, returns the same
+value as the like @code{ASCII()} function does.
+
+@example
+mysql> select ORD('2');
+ -> 50
+@end example
+
+@findex CONV()
+@item CONV(N,from_base,to_base)
+Converts numbers between different number bases. Returns a string
+representation of the number @code{N}, converted from base @code{from_base}
+to base @code{to_base}. Returns @code{NULL} if any argument is @code{NULL}.
+The argument @code{N} is interpreted as an integer, but may be specified as
+an integer or a string. The minimum base is @code{2} and the maximum base is
+@code{36}. If @code{to_base} is a negative number, @code{N} is regarded as a
+signed number. Otherwise, @code{N} is treated as unsigned. @code{CONV} works
+with 64-bit precision.
+
+@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)
+Returns a string representation of the binary value of @code{N}, where
+@code{N} is a longlong (@code{BIGINT}) number. This is equivalent to
+@code{CONV(N,10,2)}. Returns @code{NULL} if @code{N} is @code{NULL}.
+
+@example
+mysql> select BIN(12);
+ -> '1100'
+@end example
+
+@findex OCT()
+@item OCT(N)
+Returns a string representation of the octal value of @code{N}, where
+@code{N} is a longlong number. This is equivalent to @code{CONV(N,10,8)}.
+Returns @code{NULL} if @code{N} is @code{NULL}.
+
+@example
+mysql> select OCT(12);
+ -> '14'
+@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}.
+
+@example
+mysql> select HEX(255);
+ -> 'FF'
+@end example
+
+@findex CHAR()
+@item CHAR(N,...)
+@code{CHAR()} interprets the arguments as integers and returns a string
+consisting of the characters given by the ASCII code values of those
+integers. @code{NULL} values are skipped.
+
+@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(str1,str2,...)
+Returns the string that results from concatenating the arguments. Returns
+@code{NULL} if any argument is @code{NULL}. May have more than 2 arguments.
+A numeric argument is converted to the equivalent string form.
+@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(separator, str1, str2,...)
+
+@code{CONCAT_WS()} stands for CONCAT With Separator and is a special form of
+@code{CONCAT()}. The irst argument is the separator for the rest of the
+arguments. The separator can be a string as well as the rest of the
+arguments. If the separator is @code{NULL}, the result will be @code{NULL}.
+The function will skip any @code{NULL}s and empty strings, after the
+separator argument. The separator will be added between the strings to be
+concatenated.
+@example
+mysql> select CONCAT_WS(",","First name","Second name","Last Name");
+ -> 'First name,Second name,Last Name'
+mysql> select CONCAT_WS(",","First name",NULL,"Last Name");
+ -> 'First name,Last Name'
+@end example
+
+@findex LENGTH()
+@findex OCTET_LENGTH()
+@findex CHAR_LENGTH()
+@findex CHARACTER_LENGTH()
+@item LENGTH(str)
+@itemx OCTET_LENGTH(str)
+@itemx CHAR_LENGTH(str)
+@itemx CHARACTER_LENGTH(str)
+Returns the length of the string @code{str}.
+@example
+mysql> select LENGTH('text');
+ -> 4
+mysql> select OCTET_LENGTH('text');
+ -> 4
+@end example
+
+Note that for @code{CHAR_LENGTH()}, multi-byte characters are only counted once.
+
+@findex LOCATE()
+@findex POSITION()
+@item LOCATE(substr,str)
+@itemx POSITION(substr IN str)
+Returns the position of the first occurrence of substring @code{substr}
+in string @code{str}. Returns @code{0} if @code{substr} is not in @code{str}.
+@example
+mysql> select LOCATE('bar', 'foobarbar');
+ -> 4
+mysql> select LOCATE('xbar', 'foobar');
+ -> 0
+@end example
+
+This function is multi-byte safe.
+
+@findex LOCATE()
+@item LOCATE(substr,str,pos)
+Returns the position of the first occurrence of substring @code{substr} in
+string @code{str}, starting at position @code{pos}.
+Returns @code{0} if @code{substr} is not in @code{str}.
+@example
+mysql> select LOCATE('bar', 'foobarbar',5);
+ -> 7
+@end example
+
+This function is multi-byte safe.
+
+@findex INSTR()
+@item INSTR(str,substr)
+Returns the position of the first occurrence of substring @code{substr} in
+string @code{str}. This is the same as the two-argument form of
+@code{LOCATE()}, except that the arguments are swapped.
+
+@example
+mysql> select INSTR('foobarbar', 'bar');
+ -> 4
+mysql> select INSTR('xbar', 'foobar');
+ -> 0
+@end example
+
+This function is multi-byte safe.
+
+@findex LPAD()
+@item LPAD(str,len,padstr)
+Returns the string @code{str}, left-padded with the string
+@code{padstr} until @code{str} is @code{len} characters long.
+@example
+mysql> select LPAD('hi',4,'??');
+ -> '??hi'
+@end example
+
+@findex RPAD()
+@item RPAD(str,len,padstr)
+Returns the string @code{str}, right-padded with the string
+@code{padstr} until @code{str} is @code{len} characters long.
+@example
+mysql> select RPAD('hi',5,'?');
+ -> 'hi???'
+@end example
+
+@findex LEFT()
+@item LEFT(str,len)
+Returns the leftmost @code{len} characters from the string @code{str}.
+@example
+mysql> select LEFT('foobarbar', 5);
+ -> 'fooba'
+@end example
+
+This function is multi-byte safe.
+
+@findex RIGHT()
+@item RIGHT(str,len)
+Returns the rightmost @code{len} characters from the string @code{str}.
+@example
+mysql> select RIGHT('foobarbar', 4);
+ -> 'rbar'
+@end example
+
+This function is multi-byte safe.
+
+@findex SUBSTRING()
+@findex MID()
+@item SUBSTRING(str,pos,len)
+@itemx SUBSTRING(str FROM pos FOR len)
+@itemx MID(str,pos,len)
+Returns a substring @code{len} characters long from string @code{str},
+starting at position @code{pos}.
+The variant form that uses @code{FROM} is ANSI SQL92 syntax.
+@example
+mysql> select SUBSTRING('Quadratically',5,6);
+ -> 'ratica'
+@end example
+
+This function is multi-byte safe.
+
+@findex SUBSTRING()
+@item SUBSTRING(str,pos)
+@item SUBSTRING(str FROM pos)
+Returns a substring from string @code{str} starting at position @code{pos}.
+@example
+mysql> select SUBSTRING('Quadratically',5);
+ -> 'ratically'
+mysql> select SUBSTRING('foobarbar' FROM 4);
+ -> 'barbar'
+@end example
+
+This function is multi-byte safe.
+
+@findex SUBSTRING_INDEX()
+@item SUBSTRING_INDEX(str,delim,count)
+Returns the substring from string @code{str} before @code{count}
+occurrences of the delimiter @code{delim}.
+If @code{count} is positive, everything to the left of the final delimiter
+(counting from the left) is returned.
+If @code{count} is negative, everything to the right of the final delimiter
+(counting from the right) is returned.
+@example
+mysql> select SUBSTRING_INDEX('www.mysql.com', '.', 2);
+ -> 'www.mysql'
+mysql> select SUBSTRING_INDEX('www.mysql.com', '.', -2);
+ -> 'mysql.com'
+@end example
+
+This function is multi-byte safe.
+
+@findex LTRIM()
+@item LTRIM(str)
+Returns the string @code{str} with leading space characters removed.
+@example
+mysql> select LTRIM(' barbar');
+ -> 'barbar'
+@end example
+
+@findex RTRIM()
+@item RTRIM(str)
+Returns the string @code{str} with trailing space characters removed.
+@example
+mysql> select RTRIM('barbar ');
+ -> 'barbar'
+@end example
+
+This function is multi-byte safe.
+
+@findex TRIM()
+@item TRIM([[BOTH | LEADING | TRAILING] [remstr] FROM] str)
+Returns the string @code{str} with all @code{remstr} prefixes and/or suffixes
+removed. If none of the specifiers @code{BOTH}, @code{LEADING} or
+@code{TRAILING} are given, @code{BOTH} is assumed. If @code{remstr} is not
+specified, spaces are removed.
+@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
+
+This function is multi-byte safe.
+
+@findex SOUNDEX()
+@item SOUNDEX(str)
+Returns a soundex string from @code{str}. Two strings that sound ``about the
+same'' should have identical soundex strings. A ``standard'' soundex string
+is 4 characters long, but the @code{SOUNDEX()} function returns an
+arbitrarily long string. You can use @code{SUBSTRING()} on the result to get
+a ``standard'' soundex string. All non-alphanumeric characters are ignored
+in the given string. All international alpha characters outside the A-Z range
+are treated as vowels.
+
+@example
+mysql> select SOUNDEX('Hello');
+ -> 'H400'
+mysql> select SOUNDEX('Quadratically');
+ -> 'Q36324'
+@end example
+
+@findex SPACE()
+@item SPACE(N)
+Returns a string consisting of @code{N} space characters.
+@example
+mysql> select SPACE(6);
+ -> ' '
+@end example
+
+@findex REPLACE()
+@item REPLACE(str,from_str,to_str)
+Returns the string @code{str} with all all occurrences of the string
+@code{from_str} replaced by the string @code{to_str}.
+
+@example
+mysql> select REPLACE('www.mysql.com', 'w', 'Ww');
+ -> 'WwWwWw.mysql.com'
+@end example
+
+This function is multi-byte safe.
+
+@findex REPEAT()
+@item REPEAT(str,count)
+Returns a string consisting of the string @code{str} repeated @code{count}
+times. If @code{count <= 0}, returns an empty string. Returns @code{NULL} if
+@code{str} or @code{count} are @code{NULL}.
+
+@example
+mysql> select REPEAT('MySQL', 3);
+ -> 'MySQLMySQLMySQL'
+@end example
+
+@findex REVERSE()
+@item REVERSE(str)
+Returns the string @code{str} with the order of the characters reversed.
+@example
+mysql> select REVERSE('abc');
+ -> 'cba'
+@end example
+
+This function is multi-byte safe.
+
+@findex INSERT()
+@item INSERT(str,pos,len,newstr)
+Returns the string @code{str}, with the substring beginning at position
+@code{pos} and @code{len} characters long replaced by the string
+@code{newstr}.
+
+@example
+mysql> select INSERT('Quadratic', 3, 4, 'What');
+ -> 'QuWhattic'
+@end example
+
+This function is multi-byte safe.
+
+@findex ELT()
+@item ELT(N,str1,str2,str3,...)
+Returns @code{str1} if @code{N} = @code{1}, @code{str2} if @code{N} =
+@code{2}, and so on. Returns @code{NULL} if @code{N} is less than @code{1}
+or greater than the number of arguments. @code{ELT()} is the complement of
+@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(str,str1,str2,str3,...)
+Returns the index of @code{str} in the @code{str1}, @code{str2},
+@code{str3}, @code{...} list.
+Returns @code{0} if @code{str} is not found.
+@code{FIELD()} is the complement of @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(str,strlist)
+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!
+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
+@samp{,}.
+
+@example
+mysql> SELECT FIND_IN_SET('b','a,b,c,d');
+ -> 2
+@end example
+
+@findex MAKE_SET()
+@item MAKE_SET(bits,str1,str2,...)
+Returns a set (a string containing substrings separated by @samp{,}
+characters) consisting of the strings that have the corresponding bit in
+@code{bits} set. @code{str1} corresponds to bit 0, @code{str2} to bit 1,
+etc. @code{NULL} strings in @code{str1}, @code{str2}, @code{...}
+are not appended to the result.
+
+@example
+mysql> SELECT MAKE_SET(1,'a','b','c');
+ -> 'a'
+mysql> SELECT MAKE_SET(1 | 4,'hello','nice','world');
+ -> 'hello,world'
+mysql> SELECT MAKE_SET(0,'a','b','c');
+ -> ''
+@end example
+
+@findex EXPORT_SET()
+@item EXPORT_SET(bits,on,off,[separator,[number_of_bits]])
+Returns a string where for every bit set in 'bit', you get a 'on' string and for
+every reset bit you get an 'off' string. Each string is separated with 'separator'
+(default ',') and only 'number_of_bits' (default 64) of 'bits' is used.
+
+@example
+mysql> select EXPORT_SET(5,'Y','N',',',4)
+ -> Y,N,Y,N
+@end example
+
+@findex LCASE()
+@findex LOWER()
+@item LCASE(str)
+@itemx LOWER(str)
+Returns the string @code{str} with all characters changed to lowercase
+according to the current character set mapping (the default is ISO-8859-1
+Latin1).
+
+This function is multi-byte safe.
+
+@example
+mysql> select LCASE('QUADRATICALLY');
+ -> 'quadratically'
+@end example
+
+@findex UCASE()
+@findex UPPER()
+@item UCASE(str)
+@itemx UPPER(str)
+Returns the string @code{str} with all characters changed to uppercase
+according to the current character set mapping (the default is ISO-8859-1
+Latin1).
+
+@example
+mysql> select UCASE('Hej');
+ -> 'HEJ'
+@end example
+
+This function is multi-byte safe.
+
+@findex FILE
+@item LOAD_FILE(file_name)
+Reads the file and returns the file contents as a string. The file
+must be on the server, you must specify the full pathname to the
+file, and you must have the @strong{file} privilege. The file must
+be readable by all and be smaller than @code{max_allowed_packet}.
+
+If the file doesn't exist or can't be read due to one of the above reasons,
+the function returns @code{NULL}.
+
+@example
+mysql> UPDATE table_name
+ SET blob_column=LOAD_FILE("/tmp/picture")
+ WHERE id=1;
+@end example
+@end table
+
+If you are not using @strong{MySQL 3.23}, you have to do the reading of
+the file inside your application and create an @code{INSERT} statement
+to update the database with the file information. One way to do this, if
+you are using the @strong{MySQL}++ library, can be found at
+@uref{http://www.mysql.com/documentation/mysql++/mysql++-examples.html}.
+
+@strong{MySQL} automatically converts numbers to strings as necessary, and
+vice versa:
+
+@example
+mysql> SELECT 1+"1";
+ -> 2
+mysql> SELECT CONCAT(2,' test');
+ -> '2 test'
+@end example
+
+If you want to convert a number to a string explicitly, pass it as the
+argument to @code{CONCAT()}.
+
+If a string function is given a binary string as an argument, the resulting
+string is also a binary string. A number converted to a string is treated as
+a binary string. This only affects comparisons.
+
+@findex Date and time functions
+@findex Functions, date and time
+@node Date and time functions, Miscellaneous functions, String functions, Functions
+@subsection Date and time functions
+
+See @ref{Date and time types} for a description of the range of values
+each type has, and the valid formats in which date and time values may be
+specified.
+
+Here is an example that uses date functions. The query below selects
+all records with a @code{date_col} value from within the last 30 days:
+
+@example
+mysql> SELECT something FROM table
+ WHERE TO_DAYS(NOW()) - TO_DAYS(date_col) <= 30;
+@end example
+
+@table @code
+@findex DAYOFWEEK()
+@item DAYOFWEEK(date)
+Returns the weekday index
+for @code{date} (@code{1} = Sunday, @code{2} = Monday, ... @code{7} = Saturday).
+These index values correspond to the ODBC standard.
+@example
+mysql> select DAYOFWEEK('1998-02-03');
+ -> 3
+@end example
+
+@findex WEEKDAY()
+@item WEEKDAY(date)
+Returns the weekday index for
+@code{date} (@code{0} = Monday, @code{1} = Tuesday, ... @code{6} = Sunday).
+@example
+mysql> select WEEKDAY('1997-10-04 22:23:00');
+ -> 5
+mysql> select WEEKDAY('1997-11-05');
+ -> 2
+@end example
+
+@findex DAYOFMONTH()
+@item DAYOFMONTH(date)
+Returns the day of the month for @code{date}, in the range @code{1} to
+@code{31}.
+@example
+mysql> select DAYOFMONTH('1998-02-03');
+ -> 3
+@end example
+
+@findex DAYOFYEAR()
+@item DAYOFYEAR(date)
+Returns the day of the year for @code{date}, in the range @code{1} to
+@code{366}.
+@example
+mysql> select DAYOFYEAR('1998-02-03');
+ -> 34
+@end example
+
+@findex MONTH()
+@item MONTH(date)
+Returns the month for @code{date}, in the range @code{1} to @code{12}.
+@example
+mysql> select MONTH('1998-02-03');
+ -> 2
+@end example
+
+@findex DAYNAME()
+@item DAYNAME(date)
+Returns the name of the weekday for @code{date}.
+@example
+mysql> select DAYNAME("1998-02-05");
+ -> 'Thursday'
+@end example
+
+@findex MONTHNAME()
+@item MONTHNAME(date)
+Returns the name of the month for @code{date}.
+@example
+mysql> select MONTHNAME("1998-02-05");
+ -> 'February'
+@end example
+
+@findex QUARTER()
+@item QUARTER(date)
+Returns the quarter of the year for @code{date}, in the range @code{1}
+to @code{4}.
+@example
+mysql> select QUARTER('98-04-01');
+ -> 2
+@end example
+
+@findex WEEK()
+@item WEEK(date)
+@itemx WEEK(date,first)
+With a single argument, returns the week for @code{date}, in the range
+@code{0} to @code{53} (yes, there may be the beginnings of a week 53),
+for locations where Sunday is the first day of the week. The
+two-argument form of @code{WEEK()} allows you to specify whether the
+week starts on Sunday or Monday. The week starts on Sunday if the
+second argument is @code{0}, on Monday if the second argument is
+@code{1}.
+@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(date)
+Returns the year for @code{date}, in the range @code{1000} to @code{9999}.
+@example
+mysql> select YEAR('98-02-03');
+ -> 1998
+@end example
+
+@item YEARWEEK(date)
+@itemx YEARWEEK(date,first)
+Returns year and week for a date. The second arguments works exactly
+like the second argument to @code{WEEK()}. Note that the year may be
+different from the year in the date argument for the first and the last
+week of the year!
+@example
+mysql> select YEARWEEK('1987-01-01');
+ -> 198653
+@end example
+
+@findex HOUR()
+@item HOUR(time)
+Returns the hour for @code{time}, in the range @code{0} to @code{23}.
+@example
+mysql> select HOUR('10:05:03');
+ -> 10
+@end example
+
+@findex MINUTE()
+@item MINUTE(time)
+Returns the minute for @code{time}, in the range @code{0} to @code{59}.
+@example
+mysql> select MINUTE('98-02-03 10:05:03');
+ -> 5
+@end example
+
+@findex SECOND()
+@item SECOND(time)
+Returns the second for @code{time}, in the range @code{0} to @code{59}.
+@example
+mysql> select SECOND('10:05:03');
+ -> 3
+@end example
+
+@findex PERIOD_ADD()
+@item PERIOD_ADD(P,N)
+Adds @code{N} months to period @code{P} (in the format @code{YYMM} or
+@code{YYYYMM}). Returns a value in the format @code{YYYYMM}.
+
+Note that the period argument @code{P} is @emph{not} a date value.
+
+@example
+mysql> select PERIOD_ADD(9801,2);
+ -> 199803
+@end example
+
+@findex PERIOD_DIFF()
+@item PERIOD_DIFF(P1,P2)
+Returns the number of months between periods @code{P1} and @code{P2}.
+@code{P1} and @code{P2} should be in the format @code{YYMM} or @code{YYYYMM}.
+
+Note that the period arguments @code{P1} and @code{P2} are @emph{not}
+date values.
+
+@example
+mysql> select PERIOD_DIFF(9802,199703);
+ -> 11
+@end example
+
+@findex DATE_ADD()
+@findex DATE_SUB()
+@findex ADDDATE()
+@findex SUBDATE()
+@findex EXTRACT(type FROM date)
+@item DATE_ADD(date,INTERVAL expr type)
+@itemx DATE_SUB(date,INTERVAL expr type)
+@itemx ADDDATE(date,INTERVAL expr type)
+@itemx SUBDATE(date,INTERVAL expr type)
+
+These functions perform date arithmetic. They are new for @strong{MySQL}
+3.22. @code{ADDDATE()} and @code{SUBDATE()} are synonyms for
+@code{DATE_ADD()} and @code{DATE_SUB()}.
+
+In @strong{MySQL} 3.23, you can use @code{+} and @code{-} instead of
+@code{DATE_ADD()} and @code{DATE_SUB()}. (See example)
+
+@code{date} is a @code{DATETIME} or @code{DATE} value specifying the starting
+date. @code{expr} is an expression specifying the interval value to be added
+or substracted from the starting date. @code{expr} is a string; it may start
+with a @samp{-} for negative intervals. @code{type} is a keyword indicating
+how the expression should be interpreted.
+
+The @code{EXTRACT(type FROM date)} function returns the 'type'
+interval from the date.
+
+The following table shows how the @code{type} and @code{expr} arguments
+are related:
+
+@multitable @columnfractions .18 .3 .42
+@item @code{type} @strong{value} @tab @strong{Meaning} @tab @strong{Expected} @code{expr} @strong{format}
+@item @code{SECOND} @tab Seconds @tab @code{SECONDS}
+@item @code{MINUTE} @tab Minutes @tab @code{MINUTES}
+@item @code{HOUR} @tab Hours @tab @code{HOURS}
+@item @code{DAY} @tab Days @tab @code{DAYS}
+@item @code{MONTH} @tab Months @tab @code{MONTHS}
+@item @code{YEAR} @tab Years @tab @code{YEARS}
+@item @code{MINUTE_SECOND} @tab Minutes and seconds @tab @code{"MINUTES:SECONDS"}
+@item @code{HOUR_MINUTE} @tab Hours and minutes @tab @code{"HOURS:MINUTES"}
+@item @code{DAY_HOUR} @tab Days and hours @tab @code{"DAYS HOURS"}
+@item @code{YEAR_MONTH} @tab Years and months @tab @code{"YEARS-MONTHS"}
+@item @code{HOUR_SECOND} @tab Hours, minutes, @tab @code{"HOURS:MINUTES:SECONDS"}
+@item @code{DAY_MINUTE} @tab Days, hours, minutes @tab @code{"DAYS HOURS:MINUTES"}
+@item @code{DAY_SECOND} @tab Days, hours, minutes, seconds @tab @code{"DAYS HOURS:MINUTES:SECONDS"}
+@end multitable
+
+@strong{MySQL} allows any punctuation delimiter in the @code{expr} format.
+The ones shown in the table are the suggested delimiters. If the @code{date}
+argument is a @code{DATE} value and your calculations involve only
+@code{YEAR}, @code{MONTH} and @code{DAY} parts (that is, no time parts), the
+result is a @code{DATE} value. Otherwise the result is a @code{DATETIME}
+value.
+
+@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
+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
+
+If you specify an interval value that is too short (does not include all the
+interval parts that would be expected from the @code{type} keyword),
+@strong{MySQL} assumes you have left out the leftmost parts of the interval
+value. For example, if you specify a @code{type} of @code{DAY_SECOND}, the
+value of @code{expr} is expected to have days, hours, minutes and seconds
+parts. If you specify a value like @code{"1:10"}, @strong{MySQL} assumes
+that the days and hours parts are missing and the value represents minutes
+and seconds. In other words, @code{"1:10" DAY_SECOND} is interpreted in such
+a way that it is equivalent to @code{"1:10" MINUTE_SECOND}. This is
+analogous to the way that @strong{MySQL} interprets @code{TIME} values
+as representing elapsed time rather than as time of day.
+
+If you use really incorrect dates, the result is @code{NULL}. If you add
+@code{MONTH}, @code{YEAR_MONTH} or @code{YEAR} and the resulting date
+has a day that is larger than the maximum day for the new month, the day is
+adjusted to the maximum days in the new month.
+
+@example
+mysql> select DATE_ADD('1998-01-30', Interval 1 month);
+ -> 1998-02-28
+@end example
+
+Note from the preceding example that the word @code{INTERVAL} and the
+@code{type} keyword are not case sensitive.
+
+@findex TO_DAYS()
+@item TO_DAYS(date)
+Given a date @code{date}, returns a daynumber (the number of days since year
+0).
+
+@example
+mysql> select TO_DAYS(950501);
+ -> 728779
+mysql> select TO_DAYS('1997-10-07');
+ -> 729669
+@end example
+
+@code{TO_DAYS()} is not intended for use with values that precede the advent
+of the Gregorian calendar (1582), because it doesn't take into account the
+days that were lost when the calender was changed.
+
+@findex FROM_DAYS()
+@item FROM_DAYS(N)
+Given a daynumber @code{N}, returns a @code{DATE} value.
+
+@example
+mysql> select FROM_DAYS(729669);
+ -> '1997-10-07'
+@end example
+
+@code{FROM_DAYS()} is not intended for use with values that precede the
+advent of the Gregorian calendar (1582), because it doesn't take into account
+the days that were lost when the calender was changed.
+
+@findex DATE_FORMAT()
+@item DATE_FORMAT(date,format)
+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 .9
+@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.)
+@item @code{%Y} @tab Year, numeric, 4 digits
+@item @code{%y} @tab Year, numeric, 2 digits
+@item @code{%X} @tab Year for the week where Sunday is the first day of the week, numeric, 4 digits, used with '%V'
+@item @code{%x} @tab Year for the week, where Monday is the first day of the week, numeric, 4 digits, used with '%v'
+@item @code{%a} @tab Abbreviated weekday name (@code{Sun}..@code{Sat})
+@item @code{%d} @tab Day of the month, numeric (@code{00}..@code{31})
+@item @code{%e} @tab Day of the month, numeric (@code{0}..@code{31})
+@item @code{%m} @tab Month, numeric (@code{01}..@code{12})
+@item @code{%c} @tab Month, numeric (@code{1}..@code{12})
+@item @code{%b} @tab Abbreviated month name (@code{Jan}..@code{Dec})
+@item @code{%j} @tab Day of year (@code{001}..@code{366})
+@item @code{%H} @tab Hour (@code{00}..@code{23})
+@item @code{%k} @tab Hour (@code{0}..@code{23})
+@item @code{%h} @tab Hour (@code{01}..@code{12})
+@item @code{%I} @tab Hour (@code{01}..@code{12})
+@item @code{%l} @tab Hour (@code{1}..@code{12})
+@item @code{%i} @tab Minutes, numeric (@code{00}..@code{59})
+@item @code{%r} @tab Time, 12-hour (@code{hh:mm:ss [AP]M})
+@item @code{%T} @tab Time, 24-hour (@code{hh:mm:ss})
+@item @code{%S} @tab Seconds (@code{00}..@code{59})
+@item @code{%s} @tab Seconds (@code{00}..@code{59})
+@item @code{%p} @tab @code{AM} or @code{PM}
+@item @code{%w} @tab Day of the week (@code{0}=Sunday..@code{6}=Saturday)
+@item @code{%U} @tab Week (@code{0}..@code{53}), where Sunday is the first day of the week
+@item @code{%u} @tab Week (@code{0}..@code{53}), where Monday is the first day of the week
+@item @code{%V} @tab Week (@code{1}..@code{53}), where Sunday is the first day of the week. Used with '%X'
+@item @code{%v} @tab Week (@code{1}..@code{53}), where Monday is the first day of the week. Used with '%x'
+@item @code{%%} @tab A literal @samp{%}.
+@end multitable
+
+All other characters are just copied to the result without interpretation.
+
+@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
+
+As of @strong{MySQL} 3.23, the @code{%} character is required before
+format specifier characters. In earlier versions of @strong{MySQL},
+@code{%} was optional.
+
+@findex TIME_FORMAT()
+@item TIME_FORMAT(time,format)
+This is used like the @code{DATE_FORMAT()} function above, but the
+@code{format} string may contain only those format specifiers that handle
+hours, minutes and seconds. Other specifiers produce a @code{NULL} value or
+@code{0}.
+
+@findex CURDATE()
+@findex CURRENT_DATE
+@item CURDATE()
+@itemx CURRENT_DATE
+Returns today's date as a value in @code{'YYYY-MM-DD'} or @code{YYYYMMDD}
+format, depending on whether the function is used in a string or numeric
+context.
+
+@example
+mysql> select CURDATE();
+ -> '1997-12-15'
+mysql> select CURDATE() + 0;
+ -> 19971215
+@end example
+
+@findex CURTIME()
+@findex CURRENT_TIME
+@item CURTIME()
+@itemx CURRENT_TIME
+Returns the current time as a value in @code{'HH:MM:SS'} or @code{HHMMSS}
+format, depending on whether the function is used in a string or numeric
+context.
+
+@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
+Returns the current date and time as a value in @code{'YYYY-MM-DD HH:MM:SS'}
+or @code{YYYYMMDDHHMMSS} format, depending on whether the function is used in
+a string or numeric context.
+
+@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(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{YYMMDD} or @code{YYYYMMDD} in local time.
+
+@example
+mysql> select UNIX_TIMESTAMP();
+ -> 882226357
+mysql> select UNIX_TIMESTAMP('1997-10-04 22:23:00');
+ -> 875996580
+@end example
+
+When @code{UNIX_TIMESTAMP} is used on a @code{TIMESTAMP} column, the function
+will receive the 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.
+
+@findex FROM_UNIXTIME()
+@item FROM_UNIXTIME(unix_timestamp)
+Returns a representation of the @code{unix_timestamp} argument as a value in
+@code{'YYYY-MM-DD HH:MM:SS'} or @code{YYYYMMDDHHMMSS} format, depending on
+whether the function is used in a string or numeric context.
+
+@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_timestamp,format)
+Returns a string representation of the Unix timestamp, formatted according to
+the @code{format} string. @code{format} may contain the same specifiers as
+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'
+@end example
+
+@findex SEC_TO_TIME()
+@item SEC_TO_TIME(seconds)
+Returns the @code{seconds} argument, converted to hours, minutes and seconds,
+as a value in @code{'HH:MM:SS'} or @code{HHMMSS} format, depending on whether
+the function is used in a string or numeric context.
+
+@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(time)
+Returns the @code{time} argument, converted to seconds.
+@example
+mysql> select TIME_TO_SEC('22:23:00');
+ -> 80580
+mysql> select TIME_TO_SEC('00:39:38');
+ -> 2378
+@end example
+@end table
+
+@findex Miscellaneous functions
+@findex Functions, miscellaneous
+@node Miscellaneous functions, Group by functions, Date and time functions, Functions
+@subsection Miscellaneous functions
+
+@table @code
+@findex DATABASE()
+@item DATABASE()
+Returns the current database name.
+@example
+mysql> select DATABASE();
+ -> 'test'
+@end example
+
+If there is no current database, @code{DATABASE()} returns the empty string.
+
+@findex USER()
+@findex SYSTEM_USER()
+@findex SESSION_USER()
+@item USER()
+@itemx SYSTEM_USER()
+@itemx SESSION_USER()
+Returns the current @strong{MySQL} user name.
+@example
+mysql> select USER();
+ -> 'davida@@localhost'
+@end example
+
+In @strong{MySQL} 3.22.11 or later, this includes the client hostname as well as the
+user name. You can extract just the user name part like this (which works
+whether or not the value includes a hostname part):
+
+@example
+mysql> select substring_index(USER(),"@@",1);
+ -> 'davida'
+@end example
+
+@findex PASSWORD()
+@item PASSWORD(str)
+Calculates a password string from the plaintext password @code{str}. This is
+the function that is used for encrypting @strong{MySQL} passwords for storage
+in the @code{Password} column of the @code{user} grant table.
+
+@example
+mysql> select PASSWORD('badpwd');
+ -> '7f84554057dd964b'
+@end example
+
+@cindex Password encryption, reversibility of
+@code{PASSWORD()} encryption is non-reversible.
+
+@code{PASSWORD()} does not perform password encryption in the same way that
+Unix passwords are encrypted. You should not assume that if your Unix
+password and your @strong{MySQL} password are the same, @code{PASSWORD()}
+will result in the same encrypted value as is stored in the Unix password
+file. See @code{ENCRYPT()}.
+
+@findex ENCRYPT()
+@item ENCRYPT(str[,salt])
+Encrypt @code{str} using the Unix @code{crypt()} system call. The
+@code{salt} argument should be a string with two characters.
+(As of @strong{MySQL} 3.22.16, @code{salt} may be longer than two characters.)
+
+@example
+mysql> select ENCRYPT("hello");
+ -> 'VxuFAJXVARROc'
+@end example
+
+If @code{crypt()} is not available on your system, @code{ENCRYPT()} always
+returns @code{NULL}.
+
+@code{ENCRYPT()} ignores all but the first 8 characters of @code{str}, at
+least on some systems. This will be determined by the behavior of the
+underlying @code{crypt()} system call.
+
+@findex ENCODE()
+@item ENCODE(str,pass_str)
+Encrypt @code{str} using @code{pass_str} as the password.
+To decrypt the result, use @code{DECODE()}.
+
+The results is a binary string of the same length as @code{string}.
+If you want to save it in a column, use a @code{BLOB} column type.
+
+@findex DECODE()
+@item DECODE(crypt_str,pass_str)
+Descrypts the encrypted string @code{crypt_str} using @code{pass_str} as the
+password. @code{crypt_str} should be a string returned from
+@code{ENCODE()}.
+
+@findex MD5()
+@item MD5(string)
+Calculates a MD5 checksum for the string. Value is returned as a 32 long
+hex number that may, for example, be used as a hash key.
+
+@example
+mysql> select MD5("testing")
+ -> 'ae2b1fca515949e5d54fb22b8ed95575'
+@end example
+
+This is an "RSA Data Security, Inc. MD5 Message-Digest Algorithm".
+
+@findex LAST_INSERT_ID([expr])
+@item LAST_INSERT_ID([expr])
+Returns the last automatically generated value that was inserted into an
+@code{AUTO_INCREMENT} column.
+@xref{mysql_insert_id,, @code{mysql_insert_id()}}.
+
+@example
+mysql> select LAST_INSERT_ID();
+ -> 195
+@end example
+
+The last ID that was generated is maintained in the server on a
+per-connection basis. It will not be changed by another client. It will not
+even be changed if you update another @code{AUTO_INCREMENT} column with a
+non-magic value (that is, a value that is not @code{NULL} and not @code{0}).
+
+@cindex Sequence emulation
+If @code{expr} is given as an argument to @code{LAST_INSERT_ID()} in an
+@code{UPDATE} clause, then the value of the argument is returned as a
+@code{LAST_INSERT_ID()} value. This can be used to simulate sequences:
+
+First create the table:
+
+@example
+mysql> create table sequence (id int not null);
+mysql> insert into sequence values (0);
+@end example
+
+Then the table can be used to generate sequence numbers like this:
+
+@example
+mysql> update sequence set id=LAST_INSERT_ID(id+1);
+@end example
+
+You can generate sequences without calling @code{LAST_INSERT_ID()}, but the
+utility of using the function this way is that the ID value is maintained in
+the server as the last automatically generated value. You can retrieve the
+new ID as you would read any normal @code{AUTO_INCREMENT} value in
+@strong{MySQL}. For example, @code{LAST_INSERT_ID()} (without an argument)
+will return the new ID. The C API function @code{mysql_insert_id()}
+can also be used to get the value.
+
+@findex FORMAT()
+@item FORMAT(X,D)
+Formats the number @code{X} to a format like @code{'#,###,###.##'}, rounded
+to @code{D} decimals. If @code{D} is @code{0}, the result will have no
+decimal point or fractional part.
+
+@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()
+Returns a string indicating the @strong{MySQL} server version.
+@example
+mysql> select VERSION();
+ -> '3.23.13-log'
+@end example
+
+Note that if your version ends with @code{-log} this means that logging is
+enabled.
+
+@findex CONNECTION_ID()
+@item CONNECTION_ID()
+Returns the connection id (@code{thread_id}) for the connection.
+Every connection has its own unique id.
+@example
+mysql> select CONNECTION_ID();
+ -> 1
+@end example
+
+@findex GET_LOCK()
+@item GET_LOCK(str,timeout)
+Tries to obtain a lock with a name given by the string @code{str}, with a
+timeout of @code{timeout} seconds. Returns @code{1} if the lock was obtained
+successfully, @code{0} if the attempt timed out, or @code{NULL} if an error
+occurred (such as running out of memory or the thread was killed with
+@code{mysqladmin kill}). A lock is released when you execute
+@code{RELEASE_LOCK()}, execute a new @code{GET_LOCK()} or the thread
+terminates. This function can be used to implement application locks or to
+simulate record locks. It blocks requests by other clients for locks with
+the same name; clients that agree on a given lock string name can use the
+string to perform cooperative advisory locking.
+
+@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
+
+Note that the second @code{RELEASE_LOCK()} call returns @code{NULL} because
+the lock @code{"lock1"} was automatically released by the second
+@code{GET_LOCK()} call.
+
+@findex RELEASE_LOCK()
+@item RELEASE_LOCK(str)
+Releases the lock named by the string @code{str} that was obtained with
+@code{GET_LOCK()}. Returns @code{1} if the lock was released, @code{0} if the
+lock wasn't locked by this thread (in which case the lock is not released)
+and @code{NULL} if the named lock didn't exist. The lock will not exist if
+it was never obtained by a call to @code{GET_LOCK()} or if it already has
+been released.
+
+@findex BENCHMARK()
+@item BENCHMARK(count,expr)
+The @code{BENCHMARK()} function executes the expression @code{expr}
+repeatedly @code{count} times. It may be used to time how fast @strong{MySQL}
+processes the expression. The result value is always @code{0}. The intended
+use is in the @code{mysql} client, which reports query execution times.
+
+@example
+mysql> select BENCHMARK(1000000,encode("hello","goodbye"));
++----------------------------------------------+
+| BENCHMARK(1000000,encode("hello","goodbye")) |
++----------------------------------------------+
+| 0 |
++----------------------------------------------+
+1 row in set (4.74 sec)
+@end example
+
+The time reported is elapsed time on the client end, not CPU time on the
+server end. It may be advisable to execute @code{BENCHMARK()} several
+times, and interpret the result with regard to how heavily loaded the
+server machine is.
+
+@findex INET_NTOA()
+@item INET_NTOA(expr)
+Returns the network address (4 or 8 byte) for the numeric expression.
+
+@example
+mysql> select INET_NTOA(3520061480);
+ -> "209.207.224.40"
+@end example
+
+@findex INET_ATON()
+@item INET_ATON(expr)
+Returns an integer that represents the numeric value for a network address
+Addresses may be 4 or 8 byte addresses.
+
+@example
+mysql> select INET_ATON("209.207.224.40");
+ -> 3520061480
+@end example
+@end table
+
+@findex GROUP BY functions
+@findex Functions, GROUP BY
+@node Group by functions, , Miscellaneous functions, Functions
+@subsection Functions for use with @code{GROUP BY} clauses
+
+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 values.
+
+@example
+mysql> select COUNT(DISTINCT results) from student;
+@end example
+
+In @strong{MySQL} you can get the number of distinct expressions combinations
+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.
+
+@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 compatability.
+
+@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
+
+@strong{MySQL} has extended the use of @code{GROUP BY}. You can use columns or
+calculations in the @code{SELECT} expressions which 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 @strong{MySQL}, the name is redundant if you don't run in
+ANSI mode.
+
+Don't use this feature if the columns you omit from the @code{GROUP BY} part
+aren't unique in the group!
+
+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(sort,space(6-length(sort)),column),7,length(column)))
+@end example
+
+@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 Expressions, aliases for
+@cindex Aliases, for expressions
+Note that if you are using @strong{MySQL} 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 @code{MySQL} 3.23 you can do:
+
+@example
+mysql> SELECT id,FLOOR(value/100) FROM tbl_name ORDER BY RAND();
+@end example
+
+@findex CREATE DATABASE
+@node CREATE DATABASE, DROP DATABASE, Functions, Reference
+@section @code{CREATE DATABASE} syntax
+
+@example
+CREATE DATABASE [IF NOT EXISTS] db_name
+@end example
+
+@code{CREATE DATABASE} creates a database with the given name. Rules for
+allowable database names are given in @ref{Legal names}. An error occurs if
+the database already exists and you didn't specify @code{IF NOT EXISTS}.
+
+Databases in @strong{MySQL} are implemented as directories containing files
+that correspond to tables in the database. Because there are no tables in a
+database when it is initially created, the @code{CREATE DATABASE} statement
+only creates a directory under the @strong{MySQL} data directory.
+
+@cindex @code{mysqladmin}
+You can also create databases with @code{mysqladmin}.
+@xref{Programs}.
+
+@findex DROP DATABASE
+@node DROP DATABASE, CREATE TABLE, CREATE DATABASE, Reference
+@section @code{DROP DATABASE} syntax
+
+@example
+DROP DATABASE [IF EXISTS] db_name
+@end example
+
+@code{DROP DATABASE} drops all tables in the database and deletes the
+database. @strong{Be VERY careful with this command!}
+
+@code{DROP DATABASE} returns the number of files that were removed from the
+database directory. Normally, this is three times the number of tables,
+because each table corresponds to a @file{.MYD} file, a @file{.MYI} file and a
+@file{.frm} file.
+
+In @strong{MySQL} 3.22 or later, you can use the keywords @code{IF EXISTS} to
+prevent an error from occurring if the database doesn't exist.
+
+@cindex @code{mysqladmin}
+You can also drop databases with @code{mysqladmin}.
+@xref{Programs}.
+
+@findex CREATE TABLE
+@node CREATE TABLE, ALTER TABLE, DROP DATABASE, Reference
+@section @code{CREATE TABLE} syntax
+
+@menu
+* Silent column changes:: Silent column changes
+@end menu
+
+@example
+CREATE [TEMPORARY] TABLE [IF NOT EXISTS] tbl_name [(create_definition,...)]
+[table_options] [select_statement]
+
+create_definition:
+ col_name type [NOT NULL | NULL] [DEFAULT default_value] [AUTO_INCREMENT]
+ [PRIMARY KEY] [reference_definition]
+ or PRIMARY KEY (index_col_name,...)
+ or KEY [index_name] (index_col_name,...)
+ or INDEX [index_name] (index_col_name,...)
+ or UNIQUE [INDEX] [index_name] (index_col_name,...)
+ or [CONSTRAINT symbol] FOREIGN KEY index_name (index_col_name,...)
+ [reference_definition]
+ or CHECK (expr)
+
+type:
+ TINYINT[(length)] [UNSIGNED] [ZEROFILL]
+ or SMALLINT[(length)] [UNSIGNED] [ZEROFILL]
+ or MEDIUMINT[(length)] [UNSIGNED] [ZEROFILL]
+ or INT[(length)] [UNSIGNED] [ZEROFILL]
+ or INTEGER[(length)] [UNSIGNED] [ZEROFILL]
+ or BIGINT[(length)] [UNSIGNED] [ZEROFILL]
+ or REAL[(length,decimals)] [UNSIGNED] [ZEROFILL]
+ or DOUBLE[(length,decimals)] [UNSIGNED] [ZEROFILL]
+ or FLOAT[(length,decimals)] [UNSIGNED] [ZEROFILL]
+ or DECIMAL(length,decimals) [UNSIGNED] [ZEROFILL]
+ or NUMERIC(length,decimals) [UNSIGNED] [ZEROFILL]
+ or CHAR(length) [BINARY]
+ or VARCHAR(length) [BINARY]
+ or DATE
+ or TIME
+ or TIMESTAMP
+ or DATETIME
+ or TINYBLOB
+ or BLOB
+ or MEDIUMBLOB
+ or LONGBLOB
+ or TINYTEXT
+ or TEXT
+ or MEDIUMTEXT
+ or LONGTEXT
+ or ENUM(value1,value2,value3,...)
+ or SET(value1,value2,value3,...)
+
+index_col_name:
+ col_name [(length)]
+
+reference_definition:
+ REFERENCES tbl_name [(index_col_name,...)]
+ [MATCH FULL | MATCH PARTIAL]
+ [ON DELETE reference_option]
+ [ON UPDATE reference_option]
+
+reference_option:
+ RESTRICT | CASCADE | SET NULL | NO ACTION | SET DEFAULT
+
+table_options:
+ TYPE = @{ISAM | MYISAM | HEAP@}
+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 PASSWORD = "string"
+or DELAY_KEY_WRITE = @{0 | 1@}
+or ROW_FORMAT= @{ default | dynamic | static | compressed @}
+or RAID_TYPE= @{1 | STRIPED | RAID0 @} RAID_CHUNKS=# RAID_CHUNKSIZE=#;
+
+select_statement:
+ [IGNORE | REPLACE] SELECT ... (Some legal select statement)
+@end example
+
+@code{CREATE TABLE}
+creates a table with the given name in the current database. Rules for
+allowable table names are given in @ref{Legal names}. An error occurs if
+there is no current database or if the table already exists.
+
+In @strong{MySQL} 3.22 or later, the table name can be specified as
+@code{db_name.tbl_name}. This works whether or not there is a current
+database.
+
+In @strong{MySQL} 3.23, you can use the @code{TEMPORARY} keyword when 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).
+
+In @strong{MySQL} 3.23 or later, you can use the keywords @code{IF NOT EXISTS}
+so that an error does not occur if the table already exists. Note that there
+is no verification that the table structures are identical.
+
+Each table @code{tbl_name} is represented by some files in the database
+directory. In the case of MyISAM-type tables you will get:
+
+@multitable @columnfractions .2 .8
+@item @strong{File} @tab @strong{Purpose}
+@item @code{tbl_name.frm} @tab Table definition (form) file
+@item @code{tbl_name.MYD} @tab Data file
+@item @code{tbl_name.MYI} @tab Index file
+@end multitable
+
+For more information on the properties of the various column types, see
+@ref{Column types}.
+
+@itemize @bullet
+@item
+If neither @code{NULL} nor @code{NOT NULL} is specified, the column
+is treated as though @code{NULL} had been specified.
+
+@item
+An integer column may have the additional attribute @code{AUTO_INCREMENT}.
+When you insert a value of @code{NULL} (recommended) or @code{0} into an
+@code{AUTO_INCREMENT} column, the column is set to @code{value+1}, where
+@code{value} is the largest value for the column currently in the table.
+@code{AUTO_INCREMENT} sequences begin with @code{1}.
+@xref{mysql_insert_id, , @code{mysql_insert_id()}}.
+
+If you delete the row containing the maximum value for an
+@code{AUTO_INCREMENT} column, the value will be reused with an ISAM
+table but not with a @code{MyISAM} table. If you delete all rows in the
+table with @code{DELETE FROM table_name} (without a @code{WHERE}) in
+@code{AUTOCOMMIT} mode, the sequence starts over for both table types.
+
+@strong{Note:} There can be only one @code{AUTO_INCREMENT} column per
+table, and it must be indexed. @strong{MySQL} 3.23 will also only work
+properly if the auto_increment column only has positive
+values. Inserting a negative number is regarded as inserting a very large
+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 accidently get a auto_increment column that contains 0.
+
+@cindex ODBC compatibility
+@cindex Compatibility, with ODBC
+To make @strong{MySQL} compatible with some ODBC applications, you can find
+the last inserted row with the following query:
+
+@example
+SELECT * FROM tbl_name WHERE auto_col IS NULL
+@end example
+
+@item
+@code{NULL} values are handled differently for @code{TIMESTAMP} columns than
+for other column types. You cannot store a literal @code{NULL} in a
+@code{TIMESTAMP} column; setting the column to @code{NULL} sets it to the
+current date and time. Because @code{TIMESTAMP} columns behave this way, the
+@code{NULL} and @code{NOT NULL} attributes do not apply in the normal way and
+are ignored if you specify them.
+
+On the other hand, to make it easier for @strong{MySQL} clients to use
+@code{TIMESTAMP} columns, the server reports that such columns may be
+assigned @code{NULL} values (which is true), even though @code{TIMESTAMP}
+never actually will contain a @code{NULL} value. You can see this when you
+use @code{DESCRIBE tbl_name} to get a description of your table.
+
+Note that setting a @code{TIMESTAMP} column to @code{0} is not the same
+as setting it to @code{NULL}, because @code{0} is a valid @code{TIMESTAMP}
+value.
+
+@item
+If no @code{DEFAULT} value is specified for a column, @strong{MySQL}
+automatically assigns one.
+
+If the column may take @code{NULL} as a value, the default value is
+@code{NULL}.
+
+If the column is declared as @code{NOT NULL}, the default value depends on
+the column type:
+
+@itemize @minus
+@item
+For numeric types other than those declared with the @code{AUTO_INCREMENT}
+attribute, the default is @code{0}. For an @code{AUTO_INCREMENT} column, the
+default value is the next value in the sequence.
+
+@item
+For date and time types other than @code{TIMESTAMP}, the default is the
+appropriate ``zero'' value for the type. For the first @code{TIMESTAMP}
+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.
+@end itemize
+
+@item
+@code{KEY} is a synonym for @code{INDEX}.
+
+@item
+In @strong{MySQL}, a @code{UNIQUE} key can have only distinct values. An
+error occurs if you try to add a new row with a key that matches an existing
+row.
+
+@item
+A @code{PRIMARY KEY} is a unique @code{KEY} with the extra constraint
+that all key columns must be defined as @code{NOT NULL}. In @strong{MySQL}
+the key is named @code{PRIMARY}. A table can have only one @code{PRIMARY KEY}.
+If you don't have a @code{PRIMARY KEY} and some applications ask for the
+@code{PRIMARY KEY} in your tables, @strong{MySQL} will return the first
+@code{UNIQUE} key, which doesn't have any @code{NULL} columns, as the
+@code{PRIMARY KEY}.
+
+@item
+A @code{PRIMARY KEY} can be a multiple-column index. However, you cannot
+create a multiple-column index using the @code{PRIMARY KEY} key attibute in a
+column specification. Doing so will mark only that single column as primary.
+You must use the @code{PRIMARY KEY(index_col_name, ...)} syntax.
+
+@item
+If the @code{PRIMARY} or @code{UNIQUE} key consists of only one column and this
+is of type integer, you can also refer to it as @code{_rowid}
+(new in 3.23.11).
+
+@item
+If you don't assign a name to an index, the index will be assigned the same
+name as the first @code{index_col_name}, with an optional suffix (@code{_2},
+@code{_3}, @code{...}) to make it unique. You can see index names for a
+table using @code{SHOW INDEX FROM tbl_name}.
+@xref{SHOW, , @code{SHOW}}.
+
+@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
+@code{NULL} values. In other cases you must declare such columns
+@code{NOT NULL} or an error results.
+
+@item
+With @code{col_name(length)} syntax, you can specify an index which
+uses only a part of a @code{CHAR} or @code{VARCHAR} column. This can
+make the index file much smaller.
+@xref{Indexes}.
+
+@item
+@cindex @code{BLOB} columns, indexing
+@cindex Indexes, and @code{BLOB} columns
+@cindex @code{TEXT} columns, indexing
+@cindex Indexes, and @code{TEXT} columns
+Only the @code{MyISAM} table type supports indexing on @code{BLOB} and
+@code{TEXT} columns. When putting an index on a @code{BLOB} or @code{TEXT}
+column you MUST always specify the length of the index:
+@example
+CREATE TABLE test (blob_col BLOB, index(blob_col(10)));
+@end example
+
+@item
+When you use @code{ORDER BY} or @code{GROUP BY} with a @code{TEXT} or
+@code{BLOB} column, only the first @code{max_sort_length} bytes are used.
+@xref{BLOB, , @code{BLOB}}.
+
+@item
+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}.
+
+@item
+Each @code{NULL} column takes one bit extra, rounded up to the nearest byte.
+
+@item
+The maximum record length in bytes can be calculated as follows:
+
+@example
+row length = 1
+ + (sum of column lengths)
+ + (number of NULL columns + 7)/8
+ + (number of variable-length columns)
+@end example
+
+@item The @code{table_options} and @code{SELECT} options is only
+implemented in @strong{MySQL} 3.23 and above.
+
+The different table types are:
+
+@multitable @columnfractions .20 .80
+@item ISAM @tab The original table handler. @xref{ISAM}.
+@item MyISAM @tab The new binary portable table handler. @xref{MyISAM}.
+@item HEAP @tab The data for this table is only stored in memory. @xref{HEAP}.
+@item BDB or Berkeley_db @tab Transaction safe tables @xref{BDB}.
+@end multitable
+@xref{Table types}.
+
+The other table options are used to optimize 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 @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 tables with variable size records.
+@item @code{CHECKSUM} @tab Set this to 1 if you want @strong{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 smaller index. This usually makes updates slower and reads faster (MyISAM, ISAM).
+@item @code{PASSWORD} @tab Encrypt the @code{.frm} file with a password. This option doesn't do anything in the standard @strong{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 (for the future).
+@end multitable
+
+When you use a @code{MyISAM} table, @strong{MySQL} uses the product of
+@code{max_rows * avg_row_length} to decide how big the resulting table
+will be. If you don't specify any of the above options, the maximum size
+for a table will be 4G (or 2G if your operating systems only supports 2G
+tables).
+
+If you don't use @code{PACK_KEYS}, the default is to only pack strings,
+not numbers. If you use @code{PACK_KEYS=1}, numbers will be packed as well.
+
+When packing binary number keys, @strong{MySQL} will use prefix compression.
+This means that you will only get a big benefit of this if you have
+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
+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
+be stored in the same byte that is used to mark if a key is @code{NULL}).
+
+@item
+If you specify a @code{SELECT} after the @code{CREATE STATEMENT},
+@strong{MySQL} will create new fields for all elements in the
+@code{SELECT}. For example:
+
+@example
+mysql> CREATE TABLE test (a int not null auto_increment,
+ primary key (a), key(b))
+ TYPE=HEAP SELECT b,c from test2;
+@end example
+
+This will create a @code{HEAP} table with 3 columns. Note that the table will
+automatically be deleted if any errors occur while copying data
+into the table.
+@item
+The @code{RAID_TYPE} option will help you to break the 2G/4G limit on OSes
+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
+@strong{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} sub-directories named 00,
+01, 02 in the database directory. In each of these directories
+@code{MyISAM} will create an @code{table_name.MYD}. When writing data
+to the data file, the @code{RAID} handler will map the first
+@code{RAID_CHUNKSIZE} *1024 bytes to the first file, the next
+@code{RAID_CHUNKSIZE} *1024 bytes to the next file and so on.
+@end itemize
+
+
+@node Silent column changes, , CREATE TABLE, CREATE TABLE
+@subsection Silent column specification changes
+
+In some cases, @strong{MySQL} silently changes a column specification from
+that given in a @code{CREATE TABLE} statement. (This may also occur with
+@code{ALTER TABLE}.)
+
+@itemize @bullet
+@item
+@code{VARCHAR} columns with a length less than four are changed to
+@code{CHAR}.
+
+@item
+If any column in a table has a variable length, the entire row is
+variable-length as a result. Therefore, if a table contains any
+variable-length columns (@code{VARCHAR}, @code{TEXT} or @code{BLOB}),
+all @code{CHAR} columns longer than three characters are changed to
+@code{VARCHAR} columns. This doesn't affect how you use the columns in
+any way; in @strong{MySQL}, @code{VARCHAR} is just a different way to
+store characters. @strong{MySQL} performs this conversion because it
+saves space and makes table operations faster. @xref{Table types}.
+
+@item
+@code{TIMESTAMP} display sizes must be even and in the range from 2 to 14.
+If you specify a display size of 0 or greater than 14, the size is coerced
+to 14. Odd-valued sizes in the range from 1 to 13 are coerced
+to the next higher even number.
+
+@item
+You cannot store a literal @code{NULL} in a @code{TIMESTAMP} column; setting
+it to @code{NULL} sets it to the current date and time. Because
+@code{TIMESTAMP} columns behave this way, the @code{NULL} and @code{NOT NULL}
+attributes do not apply in the normal way and are ignored if you specify
+them. @code{DESCRIBE tbl_name} always reports that a @code{TIMESTAMP}
+column may be assigned @code{NULL} values.
+
+@item
+@strong{MySQL} maps certain column types used by other SQL database vendors
+to @strong{MySQL} types. @xref{Other-vendor column types}.
+@end itemize
+
+If you want to see whether or not @strong{MySQL} used a column type other
+than the one you specified, issue a @code{DESCRIBE tbl_name} statement after
+creating or altering your table.
+
+@cindex @code{myisampack}
+Certain other column type changes may occur if you compress a table
+using @code{myisampack}. @xref{Compressed format}.
+
+@findex ALTER TABLE
+@node ALTER TABLE, DROP TABLE, CREATE TABLE, Reference
+@section @code{ALTER TABLE} syntax
+
+@example
+ALTER [IGNORE] TABLE tbl_name alter_spec [, alter_spec ...]
+
+alter_specification:
+ ADD [COLUMN] create_definition [FIRST | AFTER column_name ]
+ or ADD [COLUMN] (create_definition, create_definition,...)
+ or ADD INDEX [index_name] (index_col_name,...)
+ or ADD PRIMARY KEY (index_col_name,...)
+ or ADD UNIQUE [index_name] (index_col_name,...)
+ or ALTER [COLUMN] col_name @{SET DEFAULT literal | DROP DEFAULT@}
+ or CHANGE [COLUMN] old_col_name create_definition
+ or MODIFY [COLUMN] create_definition
+ or DROP [COLUMN] col_name
+ or DROP PRIMARY KEY
+ or DROP INDEX index_name
+ or RENAME [AS] new_tbl_name
+ or table_options
+@end example
+
+@code{ALTER TABLE} allows you to change the structure of an existing table.
+For example, you can add or delete columns, create or destroy indexes, change
+the type of existing columns, or rename columns or the table itself. You can
+also change the comment for the table and type of the table.
+@xref{CREATE TABLE, , @code{CREATE TABLE}}.
+
+If you use @code{ALTER TABLE} to change a column specification but
+@code{DESCRIBE tbl_name} indicates that your column was not changed, it is
+possible that @strong{MySQL} ignored your modification for one of the reasons
+described in @ref{Silent column changes}. For example, if you try to change
+a @code{VARCHAR} column to @code{CHAR}, @strong{MySQL} will still use
+@code{VARCHAR} if the table contains other variable-length columns.
+
+@code{ALTER TABLE} works by making a temporary copy of the original table.
+The alteration is performed on the copy, then the original table is
+deleted and the new one is renamed. This is done in such a way that
+all updates are automatically redirected to the new table without
+any failed updates. While @code{ALTER TABLE} is executing, the original
+table is readable by other clients. Updates and writes to the table
+are stalled until the new table is ready.
+
+@itemize @bullet
+@item
+To use @code{ALTER TABLE}, you need @strong{select}, @strong{insert},
+@strong{delete}, @strong{update}, @strong{create} and @strong{drop}
+privileges on the table.
+
+@item
+@code{IGNORE} is a @strong{MySQL} extension to ANSI SQL92.
+It controls how @code{ALTER TABLE} works if there are duplicates on
+unique keys in the new table.
+If @code{IGNORE} isn't specified, the copy is aborted and rolled back.
+If @code{IGNORE} is specified, then for rows with duplicates on a unique
+key, only the first row is used; the others are deleted.
+
+@item
+You can issue multiple @code{ADD}, @code{ALTER}, @code{DROP} and
+@code{CHANGE} clauses in a single @code{ALTER TABLE} statement. This is a
+@strong{MySQL} extension to ANSI SQL92, which allows only one of each clause
+per @code{ALTER TABLE} statement.
+
+@item
+@code{CHANGE col_name}, @code{DROP col_name} and @code{DROP
+INDEX} are @strong{MySQL} extensions to ANSI SQL92.
+
+@item
+@code{MODIFY} is an Oracle extension to @code{ALTER TABLE}.
+
+@item
+The optional word @code{COLUMN} is a pure noise word and can be omitted.
+
+@item
+If you use @code{ALTER TABLE tbl_name RENAME AS new_name} without any other
+options, @strong{MySQL} simply renames the files that correspond to the table
+@code{tbl_name}. There is no need to create the temporary table.
+
+@item
+@code{create_definition} clauses use the same syntax for @code{ADD} and
+@code{CHANGE} as for @code{CREATE TABLE}. Note that this syntax includes
+the column name, not just the column type.
+@xref{CREATE TABLE, , @code{CREATE TABLE}}.
+
+@item
+You can rename a column using a @code{CHANGE old_col_name create_definition}
+clause. To do so, specify the old and new column names and the type that
+the column currently has. For example, to rename an @code{INTEGER} column
+from @code{a} to @code{b}, you can do this:
+
+@example
+mysql> ALTER TABLE t1 CHANGE a b INTEGER;
+@end example
+
+If you want to change a column's type but not the name, @code{CHANGE}
+syntax still requires two column names even if they are the same. For
+example:
+
+@example
+mysql> ALTER TABLE t1 CHANGE b b BIGINT NOT NULL;
+@end example
+
+However, as of @strong{MySQL} 3.22.16a, you can also use @code{MODIFY} to
+change a column's type without renaming it:
+
+@example
+mysql> ALTER TABLE t1 MODIFY b BIGINT NOT NULL;
+@end example
+
+@item
+If you use @code{CHANGE} or @code{MODIFY} to shorten a column for which
+an index exists on part of the column (for instance, if you have an index
+on the first 10 characters of a @code{VARCHAR} column), you cannot make
+the column shorter than the number of characters that are indexed.
+
+@item
+When you change a column type using @code{CHANGE} or @code{MODIFY},
+@strong{MySQL} tries to convert data to the new type as well as possible.
+
+@item
+In @strong{MySQL} 3.22 or later, you can use @code{FIRST} or @code{ADD ...
+AFTER col_name} to add a column at a specific position within a table row.
+The default is to add the column last.
+
+@item
+@code{ALTER COLUMN} specifies a new default value for a column
+or removes the old default value.
+If the old default is removed and the column can be @code{NULL}, the new
+default is @code{NULL}. If the column cannot be @code{NULL}, @strong{MySQL}
+assigns a default value.
+Default value assignment is described in
+@ref{CREATE TABLE, , @code{CREATE TABLE}}.
+
+@item
+@code{DROP INDEX} removes an index. This is a @strong{MySQL} extension to
+ANSI SQL92.
+
+@item
+If columns are dropped from a table, the columns are also removed from any
+index of which they are a part. If all columns that make up an index are
+dropped, the index is dropped as well.
+
+@item
+@code{DROP PRIMARY KEY} drops the primary index. If no such
+index exists, it drops the first @code{UNIQUE} index in the table.
+(@strong{MySQL} marks the first @code{UNIQUE} key as the @code{PRIMARY KEY}
+if no @code{PRIMARY KEY} was specified explicitly.)
+
+@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
+deleted due to duplication of unique key values.
+
+@item
+@cindex Foreign keys
+@cindex References
+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}.
+@end itemize
+
+Here is an example that shows some of the uses of @code{ALTER TABLE}. We
+begin with a table @code{t1} that is created as shown below:
+
+@example
+mysql> CREATE TABLE t1 (a INTEGER,b CHAR(10));
+@end example
+
+To rename the table from @code{t1} to @code{t2}:
+
+@example
+mysql> ALTER TABLE t1 RENAME t2;
+@end example
+
+To change column @code{a} from @code{INTEGER} to @code{TINYINT NOT NULL}
+(leaving the name the same), and to change column @code{b} from
+@code{CHAR(10)} to @code{CHAR(20)} as well as renaming it from @code{b} to
+@code{c}:
+
+@example
+mysql> ALTER TABLE t2 MODIFY a TINYINT NOT NULL, CHANGE b c CHAR(20);
+@end example
+
+To add a new @code{TIMESTAMP} column named @code{d}:
+
+@example
+mysql> ALTER TABLE t2 ADD d TIMESTAMP;
+@end example
+
+To add an index on column @code{d}, and make column @code{a} the primary key:
+
+@example
+mysql> ALTER TABLE t2 ADD INDEX (d), ADD PRIMARY KEY (a);
+@end example
+
+To remove column @code{c}:
+
+@example
+mysql> ALTER TABLE t2 DROP COLUMN c;
+@end example
+
+To add a new @code{AUTO_INCREMENT} integer column named @code{c}:
+
+@example
+mysql> ALTER TABLE t2 ADD c INT UNSIGNED NOT NULL AUTO_INCREMENT,
+ ADD INDEX (c);
+@end example
+
+Note that we indexed @code{c}, because @code{AUTO_INCREMENT} columns must be
+indexed, and also that we declare @code{c} as @code{NOT NULL}, because
+indexed columns cannot be @code{NULL}.
+
+When you add an @code{AUTO_INCREMENT} column, column values are filled in
+with sequence numbers for you automatically.
+
+See also @xref{ALTER TABLE problems, , @code{ALTER TABLE} problems}.
+
+@findex DROP TABLE
+@node DROP TABLE, OPTIMIZE TABLE, ALTER TABLE, Reference
+@section @code{DROP TABLE} syntax
+
+@example
+DROP TABLE [IF EXISTS] tbl_name [, tbl_name,...]
+@end example
+
+@code{DROP TABLE} removes one or more tables. All table data and the table
+definition are @emph{removed}, so @strong{be careful} with this command!
+
+In @strong{MySQL} 3.22 or later, you can use the keywords @code{IF EXISTS} to
+prevent an error from occurring for tables that don't exist.
+
+@findex OPTIMIZE TABLE
+@node OPTIMIZE TABLE, CHECK TABLE, DROP TABLE, Reference
+@section @code{OPTIMIZE TABLE} syntax
+
+@example
+OPTIMIZE TABLE tbl_name
+@end example
+
+@code{OPTIMIZE TABLE} should be used if you have deleted a large part of a
+table or if you have made many changes to a table with variable-length rows
+(tables that have @code{VARCHAR}, @code{BLOB} or @code{TEXT} columns).
+Deleted records are maintained in a linked list and subsequent @code{INSERT}
+operations reuse old record positions. You can use @code{OPTIMIZE TABLE} to
+reclaim the unused space.
+
+@code{OPTIMIZE TABLE} works by making a temporary copy of the original
+table; The old table is copied to the new table (without the unused
+rows), then the original table is deleted and the new one is
+renamed. While @code{OPTIMIZE TABLE} is executing, the original table is
+readable by other clients. Updates and writes to the table are stalled
+until the new table is ready. This is done in such a way that all updates
+are automatically redirected to the new table without any failed updates.
+
+@findex CHECK TABLE
+@node CHECK TABLE, ANALYZE TABLE, OPTIMIZE TABLE, Reference
+@section @code{CHECK TABLE} syntax
+
+@example
+CHECK TABLE tbl_name[,tbl_name...] [TYPE = QUICK]
+@end example
+
+Check the table(s) for errors. The command returns a table with the following
+columns:
+
+@multitable @columnfractions .35 .65
+@item Table @tab Table name
+@item Op @tab Always 'check'
+@item Msg_type @tab One of @code{status}, @code{error}, @code{info} or @code{warning}.
+@item Msg_text @tab The message.
+@end multitable
+
+Note that you can get many rows of information for each checked table. The
+last one row will be of @code{Msg_type status} and should normally be
+@code{OK}. If you don't get @code{OK}, you should normally run a repair of
+the table. @xref{Table maintenance}.
+
+If @code{TYPE=QUICK} is given then @strong{MySQL} will not scan the rows
+for table with fixed size records.
+
+@code{CHECK TABLE} only works on @code{MyISAM} tables and is the same things
+as running @code{myisamchk -m table_name} on the table.
+
+@findex ANALYZE TABLE
+@node ANALYZE TABLE, REPAIR TABLE, CHECK TABLE, Reference
+@section @code{ANALYZE TABLE} syntax
+
+@example
+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 is equivalent of running @code{myisamchk -a} on the table.
+
+@strong{MySQL} uses the stored key distribution to decide in which order
+tables should be joined when one does a join on something else than a
+constant.
+
+The command returns a table with the following columns:
+
+@multitable @columnfractions .35 .65
+@item Table @tab Table name
+@item Op @tab Always 'analyze
+@item Msg_type @tab One of @code{status}, @code{error}, @code{info} or @code{warning}.
+@item Msg_text @tab The message.
+@end multitable
+
+You can check the stored key distribution with the @code{SHOW INDEX} command.
+@xref{SHOW DATABASE INFO}.
+
+@findex REPAIR TABLE
+@node REPAIR TABLE, DELETE, ANALYZE TABLE, Reference
+@section @code{REPAIR TABLE} syntax
+
+@example
+REPAIR TABLE tbl_name[,tbl_name...] [TYPE = QUICK]
+@end example
+
+@code{REPAIR TABLE} only works on @code{MyISAM} tables and is the same things
+as running @code{myisamchk -r table_name} on the table.
+
+Repair the corrupted table. The command returns a table with the following
+columns:
+
+@multitable @columnfractions .35 .65
+@item Table @tab Table name
+@item Op @tab Always 'repair'
+@item Msg_type @tab One of @code{status}, @code{error}, @code{info} or @code{warning}.
+@item Msg_text @tab The message.
+@end multitable
+
+Note that you can get many rows of information for each repaired
+table. The last one row will be of @code{Msg_type status} and should
+normally be @code{OK}. If you don't get @code{OK}, you should try
+repairing the table with @code{myisamchk -o}, as @code{REPAIR TABLE}
+does not yet implement all the options of @code{myisamchk}. In the near
+future, we will make it more flexible.
+
+If @code{TYPE=QUICK} is given then @strong{MySQL} will try to do a
+@code{REPAIR} of only the index tree.
+
+@findex DELETE
+@node DELETE, SELECT, REPAIR TABLE, Reference
+@section @code{DELETE} syntax
+
+@example
+DELETE [LOW_PRIORITY] FROM tbl_name
+ [WHERE where_definition] [LIMIT rows]
+@end example
+
+@code{DELETE} deletes rows from @code{tbl_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, @strong{MySQL} does
+this by recreating the table as an empty table, which is much faster
+than deleting each row. In this case, @code{DELETE} returns zero as the
+number of affected records. (@strong{MySQL} can't return the number of
+rows that were actually deleted, because the recreate is done without
+opening the data files. As long as the table definition file
+@file{tbl_name.frm} is valid, the table can be recreated this way, even
+if the data or index files have become corrupted.).
+
+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;
+@end example
+
+Note that this is MUCH slower than @code{DELETE FROM tbl_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.
+@xref{OPTIMIZE TABLE, , @code{OPTIMIZE TABLE}}, and
+@ref{Optimization}.
+
+The @strong{MySQL}-specific @code{LIMIT rows} option to @code{DELETE} tells
+the server the maximum number of rows to be deleted before control is
+returned to the client. This can be used to ensure that a specific
+@code{DELETE} command doesn't take too much time. You can simply repeat
+the @code{DELETE} command until the number of affected rows is less than
+the @code{LIMIT} value.
+
+@findex SELECT
+@node SELECT, JOIN, DELETE, Reference
+@section @code{SELECT} syntax
+
+@example
+SELECT [STRAIGHT_JOIN] [SQL_SMALL_RESULT] [SQL_BIG_RESULT] [SQL_BUFFER_RESULT]
+ [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@}]
+ [HAVING where_definition]
+ [ORDER BY @{unsigned_integer | col_name | formula@} [ASC | DESC] ,...]
+ [LIMIT [offset,] rows]
+ [PROCEDURE procedure_name] ]
+@end example
+
+@code{SELECT} is used to retrieve rows selected from one or more tables.
+@code{select_expression} indicates the columns you want to retrieve.
+@code{SELECT} may also be used to retrieve rows computed without reference to
+any table. For example:
+
+@example
+mysql> SELECT 1 + 1;
+ -> 2
+@end example
+
+All keywords used must be given in exactly the order shown above. For example,
+a @code{HAVING} clause must come after any @code{GROUP BY} clause and before
+any @code{ORDER BY} clause.
+
+@itemize @bullet
+
+@item
+@cindex Aliases, on expressions
+@cindex Expression aliases
+A @code{SELECT} expression may be given an alias using @code{AS}. The alias
+is used as the expression's column name and can be used with
+@code{ORDER BY} or @code{HAVING} clauses. For example:
+
+@example
+mysql> select concat(last_name,', ',first_name) AS full_name
+ from mytable ORDER BY full_name;
+@end example
+
+@item
+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}}.
+
+@item
+You can refer to a column as @code{col_name}, @code{tbl_name.col_name} or
+@code{db_name.tbl_name.col_name}. You need not specify a @code{tbl_name} or
+@code{db_name.tbl_name} prefix for a column reference in a @code{SELECT}
+statement unless the reference would be ambiguous. See @ref{Legal names},
+for examples of ambiguity that require the more explicit column reference
+forms.
+
+@item
+@cindex Aliases, for tables
+@cindex Table aliases
+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;
+mysql> select t1.name, t2.salary from employee t1, info t2
+ where t1.name = t2.name;
+@end example
+
+@item
+Columns selected for output may be referred to in @code{ORDER BY} and
+@code{GROUP BY} clauses using column names, column aliases or column
+positions. Column positions begin with 1.
+
+@example
+mysql> select college, region, seed from tournament
+ ORDER BY region, seed;
+mysql> select college, region AS r, seed AS s from tournament
+ ORDER BY r, s;
+mysql> select college, region, seed from tournament
+ ORDER BY 2, 3;
+@end example
+
+To sort in reverse order, add the @code{DESC} (descending) keyword to the
+name of the column in the @code{ORDER BY} clause that you are sorting by.
+The default is ascending order; this may be specified explicitly using
+the @code{ASC} keyword.
+
+@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
+should be in the @code{WHERE} clause. For example, do not write this:
+
+@example
+mysql> select col_name from tbl_name HAVING col_name > 0;
+@end example
+
+Write this instead:
+
+@example
+mysql> select col_name from tbl_name WHERE col_name > 0;
+@end example
+
+In @strong{MySQL} 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;
+@end example
+
+In older @strong{MySQL} versions, you can write this instead:
+
+@example
+mysql> select user,max(salary) AS sum from users
+ 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 @strong{MySQL} extensions
+to ANSI SQL92.
+
+@item
+@code{HIGH_PRIORITY} will give the @code{SELECT} higher priority than
+a statement that updates a table. You should only use this for queries
+that are very fast and must be done at once. A @code{SELECT HIGH_PRIORITY}
+query will run if the table is locked for read even if there is an update
+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,
+@strong{MySQL} will directly use disk based temporary tables if needed.
+@strong{MySQL} will also in this case prefer sorting to doing a
+temporary table with a key on the @code{GROUP BY} elements.
+
+@item
+@code{SQL_BUFFER_RESULT} will put force the result to be put into a temporary
+table. This will help @strong{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
+@code{SQL_SMALL_RESULT}, a @strong{MySQL}-specific option, can be used
+with @code{GROUP BY} or @code{DISTINCT} to tell the optimizer that the
+result set will be small. In this case, @strong{MySQL} will use fast
+temporary tables to store the resulting table instead of using sorting. In
+@strong{MySQL} 3.23 this shouldn't normally be needed.
+
+@item
+@code{STRAIGHT_JOIN} forces the optimizer 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.
+@xref{EXPLAIN, , @code{EXPLAIN}}.
+
+@item
+The @code{LIMIT} clause can be used to constrain the number of rows returned
+by the @code{SELECT} statement. @code{LIMIT} takes one or two numeric
+arguments.
+
+If two arguments are given, the first specifies the offset of the first row to
+return, the second specifies the maximum number of rows to return.
+The offset of the initial row is 0 (not 1).
+
+@example
+mysql> select * from table LIMIT 5,10; # Retrieve rows 6-15
+@end example
+
+If one argument is given, it indicates the maximum number of rows to return.
+
+@example
+mysql> select * from table LIMIT 5; # Retrieve first 5 rows
+@end example
+
+In other words, @code{LIMIT n} is equivalent to @code{LIMIT 0,n}.
+
+@item
+@tindex /etc/passwd
+The @code{SELECT ... INTO OUTFILE 'file_name'} form of @code{SELECT} writes
+the selected rows to a file. The file is created on the server host, and
+cannot already exist (among other things, this prevents database tables and
+files such as @file{/etc/passwd} from being destroyed). You must have the
+@strong{file} privilege on the server host to use this form of @code{SELECT}.
+
+@code{SELECT ... INTO OUTFILE} is the complement of @code{LOAD DATA
+INFILE}; the syntax for the @code{export_options} part of the statement
+consists of the same @code{FIELDS} and @code{LINES} clauses that are used
+with the @code{LOAD DATA INFILE} statement.
+@xref{LOAD DATA, , @code{LOAD DATA}}.
+
+In the resulting text file, only the following characters are escaped by
+the @code{ESCAPED BY} character:
+
+@itemize @bullet
+@item The @code{ESCAPED BY} character
+@item The first character in @code{FIELDS TERMINATED BY}
+@item The first character in @code{LINES TERMINATED BY}
+@end itemize
+
+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
+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.
+
+As the resulting file doesn't have to conform to the SQL syntax, nothing
+else need be escaped.
+@end itemize
+
+@findex DUMPFILE
+If you use @code{INTO DUMPFILE} instead of @code{INTO OUTFILE} @strong{MySQL}
+will only write one row into the file, without any column or line
+terminations and without any escaping. This is useful if you want to
+store a blob in a file.
+
+@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 STRAIGHT_JOIN
+@node JOIN, INSERT, SELECT, Reference
+@section @code{JOIN} syntax
+
+@strong{MySQL} supports the following @code{JOIN} syntaxes for use in
+@code{SELECT} statements:
+
+@example
+table_reference, table_reference
+table_reference [CROSS] JOIN table_reference
+table_reference INNER JOIN table_reference join_condition
+table_reference STRAIGHT_JOIN table_reference
+table_reference LEFT [OUTER] JOIN table_reference join_condition
+table_reference LEFT [OUTER] JOIN table_reference
+table_reference NATURAL [LEFT [OUTER]] JOIN table_reference
+@{ oj table_reference LEFT OUTER JOIN table_reference ON conditional_expr @}
+@end example
+
+Where @code{table_reference} is defined as
+@example
+table_name [[AS] alias] [USE INDEX (key_list)] [IGNORE INDEX (key_list)]
+@end example
+
+and @code{join_condition} is defined as
+
+@example
+ON conditional_expr |
+USING (column_list)
+@end example
+
+Note that in version before 3.23.16 the @code{INNER JOIN} didn't take
+a join condition!
+
+@cindex ODBC compatibility
+@cindex Compatibility, with ODBC
+The last @code{LEFT OUTER JOIN} syntax shown above exists only for
+compatibility with ODBC.
+
+@itemize @bullet
+@item
+A table reference may be aliased using @code{tbl_name AS alias_name} or
+@code{tbl_name alias_name}.
+
+@example
+mysql> select t1.name, t2.salary from employee AS t1, info AS t2
+ where t1.name = t2.name;
+@end example
+
+@item
+@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 @code{WHERE} condition.
+
+@item
+The @code{ON} conditional is any conditional of the form that may be used in
+a @code{WHERE} clause.
+
+@item
+If there is no matching record for the right table in the @code{ON} or
+@code{USING} part in a @code{LEFT JOIN}, a row with all columns set to
+@code{NULL} is used for the right table. You can use this fact to find
+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;
+@end example
+
+This example finds all rows in @code{table1} with an @code{id} value that is
+not present in @code{table2} (i.e., 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.
+
+@item
+The @code{USING} @code{(column_list)} clause names a list of columns that must
+exist in both tables. A @code{USING} clause such as:
+
+@example
+A LEFT JOIN B USING (C1,C2,C3,...)
+@end example
+
+is defined to be semantically identical to an @code{ON} expression like
+this:
+
+@example
+A.C1=B.C1 AND A.C2=B.C2 AND A.C3=B.C3,...
+@end example
+
+@item
+The @code{NATURAL [LEFT] JOIN} of two tables is defined to be
+semantically equivalent to a @code{INNER JOIN} or a @code{LEFT JOIN}
+with a @code{USING} clause that names all columns that exist in both
+tables.
+
+@item
+@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.
+
+@item
+As of @strong{MySQL} 3.23.12, you can give hints about which
+index @strong{MySQL} should use when retrieving information from a
+table. This is useful if @code{EXPLAIN} shows that @strong{MySQL} is
+using the wrong index. By specifying @code{USE INDEX (key_list)}, you
+can tell @strong{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 @strong{MySQL} to not use some
+particular 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;
+@end example
+
+@xref{LEFT JOIN optimization, , @code{LEFT JOIN} optimization}.
+
+@findex INSERT
+@node INSERT, REPLACE, JOIN, Reference
+@section @code{INSERT} syntax
+
+@example
+ INSERT [LOW_PRIORITY | DELAYED] [IGNORE]
+ [INTO] tbl_name [(col_name,...)]
+ VALUES (expression,...),(...),...
+or INSERT [LOW_PRIORITY | DELAYED] [IGNORE]
+ [INTO] tbl_name [(col_name,...)]
+ SELECT ...
+or INSERT [LOW_PRIORITY | DELAYED] [IGNORE]
+ [INTO] tbl_name
+ SET col_name=expression, col_name=expression, ...
+@end example
+
+@code{INSERT} inserts new rows into an existing table. The @code{INSERT ...
+VALUES} form of the statement inserts rows based on explicitly-specified
+values. The @code{INSERT ... SELECT} form inserts rows selected from another
+table or tables. The @code{INSERT ... VALUES} form with multiple value lists
+is supported in @strong{MySQL} 3.22.5 or later. The
+@code{col_name=expression} syntax is supported in @strong{MySQL} 3.22.10 or
+later.
+
+@code{tbl_name} is the table into which rows should be inserted. The column
+name list or the @code{SET} clause indicates which columns the statement
+specifies values for.
+
+@itemize @bullet
+@item
+If you specify no column list for @code{INSERT ... VALUES} or @code{INSERT
+... SELECT}, values for all columns must be provided in the
+@code{VALUES()} list or by the @code{SELECT}. If you don't know the order of
+the columns in the table, use @code{DESCRIBE tbl_name} to find out.
+
+@item
+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}}.
+
+@item
+An @code{expression} may refer to any column that was set earlier in a value
+list. For example, you can say this:
+
+@example
+mysql> INSERT INTO tbl_name (col1,col2) VALUES(15,col1*2);
+@end example
+
+But not this:
+
+@example
+mysql> INSERT INTO tbl_name (col1,col2) VALUES(col2*2,15);
+@end example
+
+@item
+If you specify the keyword @code{LOW_PRIORITY}, execution of the
+@code{INSERT} is delayed until no other clients are reading from the table.
+In this case the client has to wait until the insert statement is completed,
+which may take a long time if the table is in heavy use. This is in
+contrast to @code{INSERT DELAYED} which lets the client continue at once.
+
+@item
+If you specify the keyword @code{IGNORE} in an @code{INSERT} with many value
+rows, any rows which duplicate an existing @code{PRIMARY} or @code{UNIQUE}
+key in the table are ignored and are not inserted. If you do not specify
+@code{IGNORE}, the insert is aborted if there is any row that duplicates an
+existing key value. You can check with the C API function
+@code{mysql_info()} how many rows were inserted into the table.
+
+@item
+If @strong{MySQL} was configured using the @code{DONT_USE_DEFAULT_FIELDS}
+option, @code{INSERT} statements generate an error unless you explicitly
+specify values for all columns that require a non-@code{NULL} value.
+@xref{configure options, , @code{configure} options}.
+
+@item
+The following conditions hold for a @code{INSERT INTO ... SELECT} statement:
+
+@itemize @minus
+@item
+The query cannot contain an @code{ORDER BY} clause.
+
+@item
+The target table of the @code{INSERT} statement cannot appear in the
+@code{FROM} clause of the @code{SELECT} part of the query, because it's
+forbidden in ANSI SQL to @code{SELECT} from the same table into which you are
+@code{INSERT}ing. (The problem is that the @code{SELECT} possibly would
+find records that were inserted earlier during the same run. When using
+sub-select clauses, the situation could easily be very confusing!)
+
+@item
+@code{AUTO_INCREMENT} columns work as usual.
+@end itemize
+@end itemize
+
+@findex mysql_info()
+If you use @code{INSERT ... SELECT} or a @code{INSERT ... VALUES}
+statement with multiple value lists, you can use the C API function
+@code{mysql_info()} to get information about the query. The format of the
+information string is shown below:
+
+@example
+Records: 100 Duplicates: 0 Warnings: 0
+@end example
+
+@code{Duplicates} indicates the number of rows that couldn't be inserted
+because they would duplicate some existing unique index value.
+@code{Warnings} indicates the number of attempts to insert column values that
+were problematic in some way. Warnings can occur under any of the following
+conditions:
+
+@itemize @bullet
+@item
+Inserting @code{NULL} into a column that has been declared @code{NOT NULL}.
+The column is set to its default value.
+
+@item
+Setting a numeric column to a value that lies outside the column's range.
+The value is clipped to the appropriate endpoint of the range.
+
+@item
+Setting a numeric column to a value such as @code{'10.34 a'}. The trailing
+garbage is stripped and the remaining numeric part is inserted. If the value
+doesn't make sense as a number at all, the column is set to @code{0}.
+
+@item
+Inserting a string into a @code{CHAR}, @code{VARCHAR}, @code{TEXT} or
+@code{BLOB} column that exceeds the column's maximum length. The value is
+truncated to the column's maximum length.
+
+@item
+Inserting a value into a date or time column that is illegal for the column
+type. The column is set to the appropriate ``zero'' value for the type.
+@end itemize
+
+@findex INSERT DELAYED
+@findex DELAYED
+
+The @code{DELAYED} option
+for the
+@code{INSERT} statement is a @strong{MySQL}-specific option that is very
+useful if you have clients that can't wait for the @code{INSERT} to complete.
+This is a common problem when you use @strong{MySQL} for logging and you also
+periodically run @code{SELECT} statements that take a long time to complete.
+@code{DELAYED} was introduced in @strong{MySQL} 3.22.15. It is a
+@strong{MySQL} extension to ANSI SQL92.
+
+When you use @code{INSERT DELAYED}, the client will get an ok at once
+and the row will be inserted when the table is not in use by any other thread.
+
+Another major benefit of using @code{INSERT DELAYED} is that inserts
+from many clients are bundled together and written in one block. This is much
+faster than doing many separate inserts.
+
+Note that currently the queued rows are only stored in memory until they are
+inserted into the table. This means that if you kill @code{mysqld}
+the hard way (@code{kill -9}) or if @code{mysqld} dies unexpectedly, any
+queued rows that weren't written to disk are lost!
+
+The following describes in detail what happens when you use the
+@code{DELAYED} option to @code{INSERT} or @code{REPLACE}. In this
+description, the ``thread'' is the thread that received an @code{INSERT
+DELAYED} command and ``handler'' is the thread that handles all
+@code{INSERT DELAYED} statements for a particular table.
+
+@itemize @bullet
+@item
+When a thread executes a @code{DELAYED} statement for a table, a handler
+thread is created to process all @code{DELAYED} statements for the table, if
+no such handler already exists.
+
+@item
+The thread checks whether or not the handler has acquired a @code{DELAYED}
+lock already; if not, it tells the handler thread to do so. The
+@code{DELAYED} lock can be obtained even if other threads have a @code{READ}
+or @code{WRITE} lock on the table. However, the handler will wait for all
+@code{ALTER TABLE} locks or @code{FLUSH TABLES} to ensure that the table
+structure is up to date.
+
+@item
+The thread executes the @code{INSERT} statement but instead of writing
+the row to the table it puts a copy of the final row into a queue that
+is managed by the handler thread. Any syntax errors are noticed by the
+thread and reported to the client program.
+
+@item
+The client can't report the number of duplicates or the @code{AUTO_INCREMENT}
+value for the resulting row; it can't obtain them from the server, because
+the @code{INSERT} returns before the insert operation has been completed. If
+you use the C API, the @code{mysql_info()} function doesn't return anything
+meaningful, for the same reason.
+
+@item
+The update log is updated by the handler thread when the row is inserted into
+the table. In case of multiple-row inserts, the update log is updated when
+the first row is inserted.
+
+@item
+After every @code{delayed_insert_limit} rows are written, the handler checks
+whether or not any @code{SELECT} statements are still pending. If so, it
+allows these to execute before continuing.
+
+@item
+When the handler has no more rows in its queue, the table is unlocked. If no
+new @code{INSERT DELAYED} commands are received within
+@code{delayed_insert_timeout} seconds, the handler terminates.
+
+@item
+If more than @code{delayed_queue_size} rows are pending already in a specific
+handler queue, the thread waits until there is room in the queue. This is
+useful to ensure that the @code{mysqld} server doesn't use all memory for the
+delayed memory queue.
+
+@item
+The handler thread will show up in the @strong{MySQL} process list
+with @code{delayed_insert} in the @code{Command} column. It will
+be killed if you execute a @code{FLUSH TABLES} command or kill it with
+@code{KILL thread_id}. However, it will first store all queued rows into the
+table before exiting. During this time it will not accept any new
+@code{INSERT} commands from another thread. If you execute an @code{INSERT
+DELAYED} command after this, a new handler thread will be created.
+
+@item
+Note that the above means that @code{INSERT DELAYED} commands have higher
+priority than normal @code{INSERT} commands if there is an @code{INSERT
+DELAYED} handler already running! Other update commands will have to wait
+until the @code{INSERT DELAYED} queue is empty, someone kills the handler
+thread (with @code{KILL thread_id}) or someone executes @code{FLUSH TABLES}.
+
+@item
+The following status variables provide information about @code{INSERT
+DELAYED} commands:
+
+@multitable @columnfractions .35 .65
+@item @code{Delayed_insert_threads} @tab Number of handler threads
+@item @code{Delayed_writes} @tab Number of rows written with @code{INSERT DELAYED}
+@item @code{Not_flushed_delayed_rows} @tab Number of rows waiting to be written
+@end multitable
+
+You can view these variables by issuing a @code{SHOW STATUS} statement or
+by executing a @code{mysqladmin extended-status} command.
+@end itemize
+
+Note that @code{INSERT DELAYED} is slower than a normal INSERT if the
+table is not in use. There is also the additional overhead for the
+server to handle a separate thread for each table on which you use
+@code{INSERT DELAYED}. This means that you should only use @code{INSERT
+DELAYED} when you are really sure you need it!
+
+@findex REPLACE
+@node REPLACE, LOAD DATA, INSERT, Reference
+@section @code{REPLACE} syntax
+
+@example
+ REPLACE [LOW_PRIORITY | DELAYED]
+ [INTO] tbl_name [(col_name,...)]
+ VALUES (expression,...)
+or REPLACE [LOW_PRIORITY | DELAYED]
+ [INTO] tbl_name [(col_name,...)]
+ SELECT ...
+or REPLACE [LOW_PRIORITY | DELAYED]
+ [INTO] tbl_name
+ SET col_name=expression, col_name=expression,...
+@end example
+
+@code{REPLACE} works exactly like @code{INSERT}, except that if an old
+record in the table has the same value as a new record on a unique index,
+the old record is deleted before the new record is inserted.
+@xref{INSERT, , @code{INSERT}}.
+
+@findex LOAD DATA INFILE
+@node LOAD DATA, UPDATE, REPLACE, Reference
+@section @code{LOAD DATA INFILE} syntax
+
+@example
+LOAD DATA [LOW_PRIORITY] [LOCAL] INFILE 'file_name.txt' [REPLACE | IGNORE]
+ INTO TABLE tbl_name
+ [FIELDS
+ [TERMINATED BY '\t']
+ [OPTIONALLY] ENCLOSED BY '']
+ [ESCAPED BY '\\' ]]
+ [LINES TERMINATED BY '\n']
+ [IGNORE number LINES]
+ [(col_name,...)]
+@end example
+
+The @code{LOAD DATA INFILE} statement reads rows from a text file into a
+table at a very high speed. If the @code{LOCAL} keyword is specified, the
+file is read from the client host. If @code{LOCAL} is not specified, the
+file must be located on the server. (@code{LOCAL} is available in
+@strong{MySQL} 3.22.6 or later.)
+
+For security reasons, when reading text files located on the server, the
+files must either reside in the database directory or be readable by all.
+Also, to use @code{LOAD DATA INFILE} on server files, you must have the
+@strong{file} privilege on the server host.
+@xref{Privileges provided}.
+
+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.
+
+Using @code{LOCAL} will be a bit slower than letting the server access the
+files directly, because the contents of the file must travel from the client
+host to the server host. On the other hand, you do not need the
+@strong{file} privilege to load local files.
+
+@cindex @code{mysqlimport}
+You can also load data files by using the @code{mysqlimport} utility; it
+operates by sending a @code{LOAD DATA INFILE} command to the server. The
+@code{--local} option causes @code{mysqlimport} to read data files from the
+client host. You can specify the @code{--compress} option to get better
+performance over slow networks if the client and server support the
+compressed protocol.
+
+When locating files on the server host, the server uses the following rules:
+
+@itemize @bullet
+@item
+If an absolute pathname is given, the server uses the pathname as is.
+
+@item
+If a relative pathname with one or more leading components is given,
+the server searches for the file relative to the server's data directory.
+
+@item
+If a filename with no leading components is given, the server looks for
+the file in the database directory of the current database.
+@end itemize
+
+Note that these rules mean a file given as @file{./myfile.txt} is read from
+the server's data directory, whereas a file given as @file{myfile.txt} is
+read from the database directory of the current database. For example,
+the following @code{LOAD DATA} statement reads the file @file{data.txt}
+from the database directory for @code{db1} because @code{db1} is the current
+database, even though the statement explicitly loads the file into a
+table in the @code{db2} database:
+
+@example
+mysql> USE db1;
+mysql> LOAD DATA INFILE "data.txt" INTO TABLE db2.my_table;
+@end example
+
+The @code{REPLACE} and @code{IGNORE} keywords control handling of input
+records that duplicate existing records on unique key values. If you specify
+@code{REPLACE}, new rows replace existing rows that have the same unique key
+value. If you specify @code{IGNORE}, input rows that duplicate an existing
+row on a unique key value are skipped. If you don't specify either option, an
+error occurs when a duplicate key value is found, and the rest of the text
+file is ignored.
+
+If you load data from a local file using the @code{LOCAL} keyword, the server
+has no way to stop transmission of the file in the middle of the operation,
+so the default bahavior is the same as if @code{IGNORE} is specified.
+
+@code{LOAD DATA INFILE} is the complement of @code{SELECT ... INTO OUTFILE}.
+@xref{SELECT, , @code{SELECT}}.
+To write data from a database to a file, use @code{SELECT ... INTO OUTFILE}.
+To read the file back into the database, use @code{LOAD DATA INFILE}.
+The syntax of the @code{FIELDS} and @code{LINES} clauses is the same for
+both commands. Both clauses are optional, but @code{FIELDS}
+must precede @code{LINES} if both are specified.
+
+If you specify a @code{FIELDS} clause,
+each of its subclauses (@code{TERMINATED BY}, @code{[OPTIONALLY] ENCLOSED
+BY} and @code{ESCAPED BY}) is also optional, except that you must
+specify at least one of them.
+
+If you don't specify a @code{FIELDS} clause, the defaults are the
+same as if you had written this:
+
+@example
+FIELDS TERMINATED BY '\t' ENCLOSED BY '' ESCAPED BY '\\'
+@end example
+
+If you don't specify a @code{LINES} clause, the default
+is the same as if you had written this:
+
+@example
+LINES TERMINATED BY '\n'
+@end example
+
+In other words, the defaults cause @code{LOAD DATA INFILE} to act as follows
+when reading input:
+
+@itemize @bullet
+@item
+Look for line boundaries at newlines
+
+@item
+Break lines into fields at tabs
+
+@item
+Do not expect fields to be enclosed within any quoting characters
+
+@item
+Interpret occurrences of tab, newline or @samp{\} preceded by
+@samp{\} as literal characters that are part of field values
+@end itemize
+
+Conversely, the defaults cause @code{SELECT ... INTO OUTFILE} to act as
+follows when writing output:
+
+@itemize @bullet
+@item
+Write tabs between fields
+
+@item
+Do not enclose fields within any quoting characters
+
+@item
+Use @samp{\} to escape instances of tab, newline or @samp{\} that occur
+within field values
+
+@item
+Write newlines at the ends of lines
+@end itemize
+
+Note that to write @code{FIELDS ESCAPED BY '\\'}, you must specify two
+backslashes for the value to be read as a single backslash.
+
+The @code{IGNORE number LINES} option can be used to ignore a header of
+column names at the start of the file:
+
+@example
+mysql> LOAD DATA INFILE "/tmp/file_name" into table test IGNORE 1 LINES;
+@end example
+
+When you use @code{SELECT ... INTO OUTFILE} in tandem with @code{LOAD
+DATA INFILE} to write data from a database into a file and then read
+the file back into the database later, the field and line handling
+options for both commands must match. Otherwise, @code{LOAD DATA
+INFILE} will not interpret the contents of the file properly. Suppose
+you use @code{SELECT ... INTO OUTFILE} to write a file with
+fields delimited by commas:
+
+@example
+mysql> SELECT * INTO OUTFILE 'data.txt'
+ 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 ',';
+@end example
+
+If instead you tried to read in the file with the statement shown below, it
+wouldn't work because it instructs @code{LOAD DATA INFILE} to look for
+tabs between fields:
+
+@example
+mysql> LOAD DATA INFILE 'data.txt' INTO TABLE table2
+ FIELDS TERMINATED BY '\t';
+@end example
+
+The likely result is that each input line would be interpreted as
+a single field.
+
+@code{LOAD DATA INFILE} can be used to read files obtained from
+external sources, too. For example, a file in dBASE format will have
+fields separated by commas and enclosed in double quotes. If lines in
+the file are terminated by newlines, the command shown below
+illustrates the field and line handling options you would use to load
+the file:
+
+@example
+mysql> LOAD DATA INFILE 'data.txt' INTO TABLE tbl_name
+ FIELDS TERMINATED BY ',' ENCLOSED BY '"'
+ LINES TERMINATED BY '\n';
+@end example
+
+Any of the field or line handling options may specify an empty string
+(@code{''}). If not empty, the @code{FIELDS [OPTIONALLY] ENCLOSED BY}
+and @code{FIELDS ESCAPED BY} values must be a single character. The
+@code{FIELDS TERMINATED BY} and @code{LINES TERMINATED BY} values may
+be more than one character. For example, to write lines that are
+terminated by carriage return-linefeed pairs, or to read a file
+containing such lines, specify a @code{LINES TERMINATED BY '\r\n'}
+clause.
+
+@code{FIELDS [OPTIONALLY] ENCLOSED BY} controls quoting of fields. For
+output (@code{SELECT ... INTO OUTFILE}), if you omit the word
+@code{OPTIONALLY}, all fields are enclosed by the @code{ENCLOSED BY}
+character. An example of such output (using a comma as the field
+delimiter) is shown below:
+
+@example
+"1","a string","100.20"
+"2","a string containing a , comma","102.20"
+"3","a string containing a \" quote","102.20"
+"4","a string containing a \", quote and comma","102.20"
+@end example
+
+If you specify @code{OPTIONALLY}, the @code{ENCLOSED BY} character is
+used only to enclose @code{CHAR} and @code{VARCHAR} fields:
+
+@example
+1,"a string",100.20
+2,"a string containing a , comma",102.20
+3,"a string containing a \" quote",102.20
+4,"a string containing a \", quote and comma",102.20
+@end example
+
+Note that occurrences of the @code{ENCLOSED BY} character within a
+field value are escaped by prefixing them with the @code{ESCAPED BY}
+character. Also note that if you specify an empty @code{ESCAPED BY}
+value, it is possible to generate output that cannot be read properly by
+@code{LOAD DATA INFILE}. For example, the output just shown above would
+appear as shown below if the escape character is empty. Observe that the
+second field in the fourth line contains a comma following the quote, which
+(erroneously) appears to terminate the field:
+
+@example
+1,"a string",100.20
+2,"a string containing a , comma",102.20
+3,"a string containing a " quote",102.20
+4,"a string containing a ", quote and comma",102.20
+@end example
+
+For input, the @code{ENCLOSED BY} character, if present, is stripped from the
+ends of field values. (This is true whether or not @code{OPTIONALLY} is
+specified; @code{OPTIONALLY} has no effect on input interpretation.)
+Occurrences of the @code{ENCLOSED BY} character preceded by the
+@code{ESCAPED BY} character are interpreted as part of the current field
+value. In addition, duplicated @code{ENCLOSED BY} characters occurring
+within fields are interpreted as single @code{ENCLOSED BY} characters if the
+field itself starts with that character. For example, if @code{ENCLOSED BY
+'"'} is specified, quotes are handled as shown below:
+
+@example
+"The ""BIG"" boss" -> The "BIG" boss
+The "BIG" boss -> The "BIG" boss
+The ""BIG"" boss -> The ""BIG"" boss
+@end example
+
+@code{FIELDS ESCAPED BY} controls how to write or read special characters.
+If the @code{FIELDS ESCAPED BY} character is not empty, it is used to prefix
+the following characters on output:
+@itemize @bullet
+@item
+The @code{FIELDS ESCAPED BY} character
+@item
+The @code{FIELDS [OPTIONALLY] ENCLOSED BY} character
+@item
+The first character of the @code{FIELDS TERMINATED BY} and
+@code{LINES TERMINATED BY} values
+@item
+ASCII @code{0} (what is actually written following the escape character is
+ASCII @code{'0'}, not a zero-valued byte)
+@end itemize
+
+If the @code{FIELDS ESCAPED BY} character is empty, no characters are escaped.
+It is probably not a good idea to specify an empty escape character,
+particularly if field values in your data contain any of the characters in
+the list just given.
+
+For input, if the @code{FIELDS ESCAPED BY} character is not empty, occurrences
+of that character are stripped and the following character is taken literally
+as part of a field value. The exceptions are an escaped @samp{0} or
+@samp{N} (e.g., @code{\0} or @code{\N} if the escape character is
+@samp{\}). These sequences are interpreted as ASCII @code{0} (a zero-valued
+byte) and @code{NULL}. See below for the rules on @code{NULL} handling.
+
+For more information about @samp{\}-escape syntax,
+see @ref{Literals}.
+
+In certain cases, field and line handling options interact:
+
+@itemize @bullet
+@item
+If @code{LINES TERMINATED BY} is an empty string and @code{FIELDS
+TERMINATED BY} is non-empty, lines are also terminated with
+@code{FIELDS TERMINATED BY}.
+@item
+If the @code{FIELDS TERMINATED BY} and @code{FIELDS ENCLOSED BY} values are
+both empty (@code{''}), a fixed-row (non-delimited) format is used. With
+fixed-row format, no delimiters are used between fields. Instead, column
+values are written and read using the ``display'' widths of the columns. For
+example, if a column is declared as @code{INT(7)}, values for the column are
+written using 7-character fields. On input, values for the column are
+obtained by reading 7 characters. Fixed-row format also affects handling of
+@code{NULL} values; see below. Note that fixed size format will not work
+if you are using a multi-byte character set.
+@end itemize
+
+Handling of @code{NULL} values varies, depending on the @code{FIELDS} and
+@code{LINES} options you use:
+
+@itemize @bullet
+@item
+For the default @code{FIELDS} and @code{LINES} values,
+@code{NULL} is written as @code{\N} for output and @code{\N} is read
+as @code{NULL} for input (assuming the @code{ESCAPED BY} character
+is @samp{\}).
+
+@item
+If @code{FIELDS ENCLOSED BY} is not empty, a field containing the literal
+word @code{NULL} as its value is read as a @code{NULL} value (this differs
+from the word @code{NULL} enclosed within @code{FIELDS ENCLOSED BY}
+characters, which is read as the string @code{'NULL'}).
+
+@item
+If @code{FIELDS ESCAPED BY} is empty, @code{NULL} is written as the word
+@code{NULL}.
+
+@item
+With fixed-row format (which happens when @code{FIELDS TERMINATED BY} and
+@code{FIELDS ENCLOSED BY} are both empty), @code{NULL} is written as an empty
+string. Note that this causes both @code{NULL} values and empty strings in
+the table to be indistinguishable when written to the file because they are
+both written as empty strings. If you need to be able to tell the two apart
+when reading the file back in, you should not use fixed-row format.
+@end itemize
+
+Some cases are not supported by @code{LOAD DATA INFILE}:
+@itemize @bullet
+
+@item
+Fixed-size rows (@code{FIELDS TERMINATED BY} and @code{FIELDS ENCLOSED
+BY} both empty) and @code{BLOB} or @code{TEXT} columns.
+
+@item
+If you specify one separator that is the same as or a prefix of another,
+@code{LOAD DATA INFILE} won't be able to interpret the input properly.
+For example, the following @code{FIELDS} clause would cause problems:
+
+@example
+FIELDS TERMINATED BY '"' ENCLOSED BY '"'
+@end example
+
+@item
+If @code{FIELDS ESCAPED BY} is empty, a field value that contains an occurrence
+of @code{FIELDS ENCLOSED BY} or @code{LINES TERMINATED BY}
+followed by the @code{FIELDS TERMINATED BY} value will cause @code{LOAD
+DATA INFILE} to stop reading a field or line too early.
+This happens because @code{LOAD DATA INFILE} cannot properly determine
+where the field or line value ends.
+@end itemize
+
+The following example loads all columns of the @code{persondata} table:
+
+@example
+mysql> LOAD DATA INFILE 'persondata.txt' INTO TABLE persondata;
+@end example
+
+No field list is specified, so @code{LOAD DATA INFILE} expects input rows
+to contain a field for each table column. The default @code{FIELDS} and
+@code{LINES} values are used.
+
+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,...);
+@end example
+
+You must also specify a field list if the order of the fields in the input
+file differs from the order of the columns in the table. Otherwise,
+@strong{MySQL} cannot tell how to match up input fields with table columns.
+
+If a row has too few fields, the columns for which no input field is present
+are set to default values. Default value assignment is described in
+@ref{CREATE TABLE, , @code{CREATE TABLE}}.
+
+An empty field value is interpreted differently than if the field value
+is missing:
+
+@itemize @bullet
+@item
+For string types, the column is set to the empty string.
+
+@item
+For numeric types, the column is set to @code{0}.
+
+@item
+For date and time types, the column is set to the appropriate ``zero''
+value for the type.
+@xref{Date and time types}.
+@end itemize
+
+@code{TIMESTAMP} columns are only set to the current date and time if there
+is a @code{NULL} value for the column, or (for the first @code{TIMESTAMP}
+column only) if the @code{TIMESTAMP} column is left out from the field list
+when a field list is specified.
+
+If an input row has too many fields, the extra fields are ignored and
+the number of warnings is incremented.
+
+@code{LOAD DATA INFILE} regards all input as strings, so you can't use
+numeric values for @code{ENUM} or @code{SET} columns the way you can with
+@code{INSERT} statements. All @code{ENUM} and @code{SET} values must be
+specified as strings!
+
+@findex mysql_info()
+If you are using the C API, you can get information about the query by
+calling the API function @code{mysql_info()} when the @code{LOAD DATA INFILE}
+query finishes. The format of the information string is shown below:
+
+@example
+Records: 1 Deleted: 0 Skipped: 0 Warnings: 0
+@end example
+
+Warnings occur under the same circumstances as when values are inserted
+via the @code{INSERT} statement (@pxref{INSERT, , @code{INSERT}}), except
+that @code{LOAD DATA INFILE} also generates warnings when there are too few
+or too many fields in the input row. The warnings are not stored anywhere;
+the number of warnings can only be used as an indication if everything went
+well. If you get warnings and want to know exactly why you got them, one way
+to do this is to use @code{SELECT ... INTO OUTFILE} into another file and
+compare this to your original input file.
+
+If you need @code{LOAD DATA INFILE} to read from a pipe, you can use the
+following trick:
+
+@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
+
+For more information about the efficiency of @code{INSERT} versus
+@code{LOAD DATA INFILE} and speeding up @code{LOAD DATA INFILE},
+@xref{Insert speed}.
+
+@findex UPDATE
+@node UPDATE, USE, LOAD DATA, Reference
+@section @code{UPDATE} syntax
+
+@example
+UPDATE [LOW_PRIORITY] [IGNORE] tbl_name SET col_name1=expr1,col_name2=expr2,...
+ [WHERE where_definition] [LIMIT #]
+@end example
+
+@code{UPDATE} updates columns in existing table rows with new values. The
+@code{SET} clause indicates which columns to modify and the values they
+should be given. The @code{WHERE} clause, if given, specifies which rows
+should be updated. Otherwise all rows are updated.
+
+If you specify the keyword @code{LOW_PRIORITY}, execution of the
+@code{UPDATE} is delayed until no other clients are reading from the table.
+
+If you specify the keyword @code{IGNORE}, the update statement will not
+abort even if we get duplicate key errors during the update. Rows that
+would cause conflicts will not be updated.
+
+If you access a column from @code{tbl_name} in an expression,
+@code{UPDATE} uses the current value of the column. For example, the
+following statement sets the @code{age} column to one more than its
+current value:
+
+@example
+mysql> UPDATE persondata SET age=age+1;
+@end example
+
+@code{UPDATE} assignments are evaluated from left to right. For example, the
+following statement doubles the @code{age} column, then increments it:
+
+@example
+mysql> UPDATE persondata SET age=age*2, age=age+1;
+@end example
+
+If you set a column to the value it currently has, @strong{MySQL} notices
+this and doesn't update it.
+
+@findex mysql_info()
+@code{UPDATE} returns the number of rows that were actually changed.
+In @strong{MySQL} 3.22 or later, the C API function @code{mysql_info()}
+returns the number of rows that were matched and updated and the number of
+warnings that occurred during the @code{UPDATE}.
+
+In @strong{MySQL} 3.23 you can use @code{LIMIT #} to ensure that only a given
+number of rows are changed.
+
+@findex USE
+@node USE, FLUSH, UPDATE, Reference
+@section @code{USE} syntax
+
+@example
+USE db_name
+@end example
+
+The @code{USE db_name} statement tells @strong{MySQL} to use the @code{db_name}
+database as the default database for subsequent queries. The database remains
+current until the end of the session, or until another @code{USE} statement
+is issued:
+
+@example
+mysql> USE db1;
+mysql> SELECT count(*) FROM mytable; # selects from db1.mytable
+mysql> USE db2;
+mysql> SELECT count(*) FROM mytable; # selects from db2.mytable
+@end example
+
+Making a particular database current by means of the @code{USE} statement
+does not preclude you from accessing tables in other databases. The example
+below accesses the @code{author} table from the @code{db1} database and the
+@code{editor} table from the @code{db2} database:
+
+@example
+mysql> USE db1;
+mysql> SELECT author_name,editor_name FROM author,db2.editor
+ WHERE author.editor_id = db2.editor.editor_id;
+@end example
+
+@cindex Sybase compatibility
+@cindex Compatibility, with Sybase
+The @code{USE} statement is provided for Sybase compatibility.
+
+@cindex @code{mysqladmin}
+@findex FLUSH
+@node FLUSH, KILL, USE, Reference
+@section @code{FLUSH} syntax (clearing caches)
+
+@example
+FLUSH flush_option [,flush_option]
+@end example
+
+You should use the @code{FLUSH} command if you want to clear some of the
+internal caches @strong{MySQL} uses. To execute @code{FLUSH}, you must have
+the @strong{reload} privilege.
+
+@code{flush_option} can be any of the following:
+
+@multitable @columnfractions .15 .85
+@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
+@code{max_connect_errors} errors occur in a row for a given host while
+connection to the @strong{MySQL} server, @strong{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
+@code{-O max_connection_errors=999999999} to avoid this error message.
+
+@item @code{LOGS} @tab Closes and reopens the standard and update log
+files. If you have specified the update log file without an extension,
+the extension number of the new update log file will be incremented by
+one relative to the previous file. If you have used an extension in the
+file name, @strong{MySQL} will close and reopen the update log file.
+@xref{Update log}.
+
+@item @code{PRIVILEGES} @tab Reloads the privileges from the grant tables in
+the @code{mysql} database.
+
+@item @code{TABLES} @tab Closes all open tables.
+
+@item @code{TABLES WITH READ LOCK} @tab Closes all open tables and locks all tables for all databases with a read until one executes @code{UNLOCK TABLES}.
+
+@item @code{STATUS} @tab Resets most status variables to zero.
+@end multitable
+
+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.
+
+@cindex @code{mysqladmin}
+@findex KILL
+@node KILL, SHOW, FLUSH, Reference
+@section @code{KILL} syntax
+
+@example
+KILL thread_id
+@end example
+
+Each connection to @code{mysqld} runs in a separate thread. You can see
+which threads are running with the @code{SHOW PROCESSLIST} command, and kill
+a thread with the @code{KILL thread_id} command.
+
+If you have the @strong{process} privilege, you can see and kill all threads.
+Otherwise, you can see and kill only your own threads.
+
+You can also use the @code{mysqladmin processlist} and @code{mysqladmin kill}
+commands to examine and kill threads.
+
+@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
+@node SHOW, EXPLAIN, KILL, Reference
+@section @code{SHOW} syntax (Get information about tables, columns,...)
+
+@example
+ SHOW DATABASES [LIKE wild]
+or SHOW TABLES [FROM db_name] [LIKE wild]
+or SHOW COLUMNS FROM tbl_name [FROM db_name] [LIKE wild]
+or SHOW INDEX FROM tbl_name [FROM db_name]
+or SHOW TABLE STATUS [FROM db_name] [LIKE wild]
+or SHOW STATUS [LIKE wild]
+or SHOW VARIABLES [LIKE wild]
+or SHOW [FULL] PROCESSLIST
+or SHOW GRANTS FOR user
+@end example
+
+@code{SHOW} provides information about databases, tables, columns or
+status information about the server. If the @code{LIKE wild} part is
+used, the @code{wild} string can be a string that uses the SQL @samp{%}
+and @samp{_} wildcard characters.
+
+@findex SHOW DATABASES
+@findex SHOW TABLES
+@findex SHOW COLUMNS
+@findex SHOW FIELDS
+@findex SHOW INDEX
+@findex SHOW KEYS
+@menu
+* SHOW DATABASE INFO::
+* SHOW TABLE STATUS::
+* SHOW STATUS::
+* SHOW VARIABLES::
+* SHOW PROCESSLIST::
+* SHOW GRANTS::
+@end menu
+
+@node SHOW DATABASE INFO, SHOW TABLE STATUS, SHOW, SHOW
+@subsection SHOW information about database, tables, columns and index
+
+You can use @code{db_name.tbl_name} as an alternative to the @code{tbl_name
+FROM db_name} syntax. These two statements are equivalent:
+
+@example
+mysql> SHOW INDEX FROM mytable FROM mydb;
+mysql> SHOW INDEX FROM mydb.mytable;
+@end example
+
+@code{SHOW DATABASES} lists the databases on the @strong{MySQL} server
+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
+will not show up in the output from @code{SHOW TABLES} or @code{mysqlshow
+db_name}.
+
+@code{SHOW COLUMNS} lists the columns in a given table. If the column
+types are different than you expect them to be based on a @code{CREATE
+TABLE} statement, note that @strong{MySQL} sometimes changes column
+types. @xref{Silent column changes}.
+
+The @code{DESCRIBE} statement provides information similar to
+@code{SHOW COLUMNS}.
+@xref{DESCRIBE, , @code{DESCRIBE}}.
+
+@code{SHOW FIELDS} is a synonym for @code{SHOW COLUMNS} and
+@code{SHOW KEYS} is a synonym for @code{SHOW INDEX}. You can also
+list a table's columns or indexes with @code{mysqlshow db_name tbl_name}
+or @code{mysqlshow -k db_name tbl_name}.
+
+@code{SHOW INDEX} returns the index information in a format that closely
+resembles the @code{SQLStatistics} call in ODBC. The following columns
+are returned:
+
+@multitable @columnfractions .35 .65
+@item @strong{Column} @tab @strong{Meaning}
+@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, starting with 1.
+@item @code{Column_name} @tab Column name.
+@item @code{Collation} @tab How the column is sorted in the index. In
+@strong{MySQL}, this can have values @code{A} (Ascending) or @code{NULL}
+(Not sorted).
+@item @code{Cardinality} @tab Number of unique values in the index.
+This is updated by running @code{isamchk -a}.
+@item @code{Sub_part} @tab Number of indexed characters if the column is
+only partly indexed. @code{NULL} if the entire key is indexed.
+@end multitable
+
+@node SHOW TABLE STATUS, SHOW STATUS, SHOW DATABASE INFO, SHOW
+@subsection SHOW status information about tables
+
+@code{SHOW TABLE STATUS} (new in version 3.23) works likes @code{SHOW
+STATUS}, but provides a lot of information about each table. You can
+also get this list using the @code{mysqlshow --status db_name} command.
+The following columns are returned:
+
+@multitable @columnfractions .30 .70
+@item @strong{Column} @tab @strong{Meaning}
+@item @code{Name} @tab Name of the table
+@item @code{Type} @tab Type of table (BDB, ISAM, MyISAM or HEAP)
+@item @code{Row_format} @tab The row storage format (Fixed, Dynamic, or Compressed)
+@item @code{Rows} @tab Number of rows
+@item @code{Avg_row_length} @tab Average row length
+@item @code{Data_length} @tab Length of the data file
+@item @code{Max_data_length} @tab Max length of the data file
+@item @code{Index_length} @tab Length of the index file
+@item @code{Data_free} @tab Number of allocated but not used bytes
+@item @code{Auto_increment} @tab Next autoincrement value
+@item @code{Create_time} @tab When the table was created
+@item @code{Update_time} @tab When the data file was last updated
+@item @code{Check_time} @tab When one last run a check on the table
+@item @code{Create_options} @tab Extra options used with @code{CREATE TABLE}
+@item @code{Comment} @tab The comment used when creating the table (or some information why @strong{MySQL} couldn't access the table information).
+@end multitable
+
+@node SHOW STATUS, SHOW VARIABLES, SHOW TABLE STATUS, SHOW
+@subsection SHOW status information
+
+@cindex @code{mysqladmin}
+@code{SHOW STATUS} provides server status information
+(like @code{mysqladmin extended-status}). The output resembles that shown
+below, though the format and numbers probably differ:
+
+@example
++--------------------------+-------+
+| Variable_name | Value |
++--------------------------+-------+
+| Aborted_clients | 0 |
+| Aborted_connects | 0 |
+| Bytes_received | 100 |
+| Bytes_sent | 2106 |
+| Connections | 4 |
+| Created_tmp_tables | 0 |
+| Delayed_insert_threads | 0 |
+| Delayed_writes | 0 |
+| Delayed_errors | 0 |
+| Flush_commands | 1 |
+| Handler_delete | 0 |
+| Handler_read_first | 1 |
+| Handler_read_key | 0 |
+| Handler_read_next | 2 |
+| Handler_read_prev | 0 |
+| Handler_read_rnd | 0 |
+| Handler_read_rnd_next | 25 |
+| Handler_update | 0 |
+| Handler_write | 0 |
+| Key_blocks_used | 1 |
+| Key_read_requests | 2 |
+| Key_reads | 1 |
+| Key_write_requests | 0 |
+| Key_writes | 0 |
+| Max_used_connections | 0 |
+| Not_flushed_key_blocks | 0 |
+| Not_flushed_delayed_rows | 0 |
+| Open_tables | 0 |
+| Open_files | 0 |
+| Open_streams | 0 |
+| Opened_tables | 6 |
+| Questions | 4 |
+| Slow_launch_threads | 0 |
+| Slow_queries | 0 |
+| Slave_running | OFF |
+| Threads_cached | 0 |
+| Threads_connected | 1 |
+| Threads_running | 1 |
+| Uptime | 1256 |
++--------------------------+-------+
+
+@end example
+
+The status variables listed above have the following meaning:
+
+@multitable @columnfractions .35 .65
+@item @code{Aborted_clients} @tab Number of connections that has been aborted because the client has died without closing the connection properly.
+@item @code{Aborted_connects} @tab Number of tries to connect to the @strong{MySQL} server that has failed.
+@item @code{Bytes_received} @tab Number of bytes received from the client
+@item @code{Bytes_sent} @tab Number of bytes received from the client
+@item @code{Connections} @tab Number of connection attempts to the @strong{MySQL} server.
+@item @code{Created_tmp_tables} @tab Number of implicit temporary tables that has been created while executing statements.
+@item @code{Delayed_insert_threads} @tab Number of delayed insert handler threads in use.
+@item @code{Delayed_writes} @tab Number of rows written with @code{INSERT DELAYED}.
+@item @code{Delayed_errors} @tab Number of rows written with @code{INSERT DELAYED} for which some error occurred (probably @code{duplicate key}).
+@item @code{Flush_commands} @tab Number of executed @code{FLUSH} commands.
+@item @code{Handler_delete} @tab Number of times a row was deleted from a table.
+@item @code{Handler_read_first} @tab Number of times the first entry was read from an index.
+If this is high, it suggests that the server is doing a lot of full index scans, for example,
+@code{SELECT col1 FROM foo}, assuming that col1 is indexed
+@item @code{Handler_read_key} @tab Number of requests to read a row based on a key. If this
+is high, it is a good indication that your queries and tables are properly indexed.
+@item @code{Handler_read_next} @tab Number of requests to read next row in key order. This
+will be incremented if you are querying an index column with a range contraint. This also
+will be incremented if you are doing an index scan.
+@item @code{Handler_read_rnd} @tab Number of requests to read a row based on a fixed position.
+This will be high if you are doing a lot of queries that require sorting of the result.
+@item @code{Handler_read_rnd_next} @tab Number of requests to read the next row in the datafile.
+This will be high if you are doing a lot of table scans - generally this suggests that you tables
+are not properly indexed or that you queries are not written to take advantaged of the indeces you
+have..
+@item @code{Handler_update} @tab Number of requests to update a row in a table.
+@item @code{Handler_write} @tab Number of requests to insert a row in a table.
+@item @code{Key_blocks_used} @tab The number of used blocks in the key cache.
+@item @code{Key_read_requests} @tab The number of requests to read a key block from the cache.
+@item @code{Key_reads} @tab The number of physical reads of a key block from disk.
+@item @code{Key_write_requests} @tab The number of requests to write a key block to the cache.
+@item @code{Key_writes} @tab The number of physical writes of a key block to disk.
+@item @code{Max_used_connections} @tab The maximum number of connections that has been in use simultaneously.
+@item @code{Not_flushed_key_blocks} @tab Keys blocks in the key cache that has changed but hasn't yet been flushed to disk.
+@item @code{Not_flushed_delayed_rows} @tab Number of rows waiting to be written in @code{INSERT DELAY} queues.
+@item @code{Open_tables} @tab Number of tables that are open.
+@item @code{Open_files} @tab Number of files that are open.
+@item @code{Open_streams} @tab Number of streams that are open (used mainly for logging)
+@item @code{Opened_tables} @tab Number of tables that has been opened.
+@item @code{Questions} @tab Number of queries sent to the server.
+@item @code{Slow_launch_threads} @tab Number of threads that has taken more than @code{slow_launch_time} to connect.
+@item @code{Slow_queries} @tab Number of queries that has taken more than @code{long_query_time}
+@item @code{Threads_cached} @tab Number of threads in the thread cache.
+@item @code{Threads_connected} @tab Number of currently open connections.
+@item @code{Threads_running} @tab Number of threads that are not sleeping.
+@item @code{Uptime} @tab How many seconds the server has been up.
+@end multitable
+
+Some comments about the above:
+
+@itemize @bullet
+@item
+If @code{Opened_tables} is big, then your @code{table_cache}
+variable is probably too small.
+@item
+If @code{key_reads} is big, then your @code{key_cache} is probably too
+small. The cache hit rate can be calculated with
+@code{key_reads}/@code{key_read_requests}.
+@item
+If @code{Handler_read_rnd} is big, then you have a probably a lot of queries
+that requires @strong{MySQL} to scan whole tables or you have joins that doesn't use
+keys properly.
+@end itemize
+
+@node SHOW VARIABLES, SHOW PROCESSLIST, SHOW STATUS, SHOW
+@subsection SHOW VARIABLES
+
+@code{SHOW VARIABLES} shows the values of the some of @strong{MySQL} system
+variables. You can also get this information using the @code{mysqladmin
+variables} command. If the default values are unsuitable, you can set most
+of these variables using command-line options when @code{mysqld} starts up.
+@xref{Command-line options}.
+
+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 | /usr/local/mysql/ |
+| bdb_cache_size | 1048540 |
+| bdb_home | /usr/local/mysql/data/ |
+| bdb_logdir | |
+| bdb_tmpdir | /tmp/ |
+| character_set | latin1 |
+| character_sets | latin1 |
+| connect_timeout | 5 |
+| concurrent_insert | ON |
+| datadir | /usr/local/mysql/data/ |
+| delay_key_write | ON |
+| delayed_insert_limit | 100 |
+| delayed_insert_timeout | 300 |
+| delayed_queue_size | 1000 |
+| join_buffer_size | 131072 |
+| flush | OFF |
+| flush_time | 0 |
+| init_file | |
+| interactive_timeout | 28800 |
+| key_buffer_size | 16776192 |
+| language | /usr/local/mysql/share/english/ |
+| 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 | 1047552 |
+| 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_sort_buffer_size | 8388608 |
+| net_buffer_length | 16384 |
+| net_retry_count | 10 |
+| pid_file | /usr/local/mysql/data/tik.pid |
+| port | 3306 |
+| protocol_version | 10 |
+| record_buffer | 131072 |
+| 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_stack | 131072 |
+| thread_cache_size | 3 |
+| tmp_table_size | 1048576 |
+| tmpdir | /tmp/ |
+| version | 3.23.21-beta-debug |
+| wait_timeout | 28800 |
++-----------------------------------+-----------------------+
+@end example
+
+Each option is described below. Values for buffer sizes, lengths and stack
+sizes are given in bytes. You can specify values with a suffix of @samp{K}
+or @samp{M} to indicate kilobytes or megabytes. For example, @code{16M}
+indicates 16 megabytes. The case of suffix letters does not matter;
+@code{16M} and @code{16m} are equivalent.
+
+@table @code
+@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 @strong{MySQL} can have. This
+comes into play when the main @strong{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
+stacked during this short time before @strong{MySQL} momentarily stops
+answering new requests. You need to increase this only if you expect a large
+number of connections in a short period of time.
+
+In other words, this value is the size of the listen queue for incoming
+TCP/IP connections. Your operating system has its own limit on the size
+of this queue. The manual page for the Unix @code{listen(2)} system
+call should have more details. Check your OS documentation for the
+maximum value for this variable. Attempting to set @code{back_log}
+higher than your operating system limit will be ineffective.
+
+@item @code{bdb_cache_size}
+The buffer that is allocated to cache index and rows for @code{BDB} tables.
+If you don't use @code{BDB} tables, you should set this to 0 or
+start @code{mysqld} with @code{--skip-bdb} o not waste memory for this cache.
+
+@item @code{concurrent_inserts}
+If @code{ON} (the default), @code{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 mysqld with @code{--safe}
+or @code{--skip-new}.
+
+@item @code{connect_timeout}
+The number of seconds the @code{mysqld} server is waiting for a connect
+packet before responding with @code{Bad handshake}.
+
+@item @code{delayed_insert_timeout}
+How long a @code{INSERT DELAYED} thread should wait for @code{INSERT}
+statements before terminating.
+
+@item @code{delayed_insert_limit}
+After inserting @code{delayed_insert_limit} rows, the @code{INSERT
+DELAYED} handler will check if there are any @code{SELECT} statements
+pending. If so, it allows these to execute before continuing.
+
+@item @code{delay_key_write}
+If enabled (is on by default), @strong{MySQL} will honor the
+@code{delay_key_write} option @code{CREATE TABLE}. This means that the
+key buffer for tables with this option will not get flushed on every
+index update, but only when a table is closed. This will speed up
+writes on keys a lot but you should add automatic checking of all tables
+with @code{myisamchk --fast --force} if you use this. Note that if you
+start @code{mysqld} with the @code{--delay-key-write-for-all-tables}
+option this means that all tables will be treated as if they were
+created with the @code{delay_key_write} option. You can clear this flag
+by starting @code{mysqld} with @code{--skip-new} or @code{--safe-mode}.
+
+@item @code{delayed_queue_size}
+What size queue (in rows) should be allocated for handling @code{INSERT
+DELAYED}. If the queue becomes full, any client that does @code{INSERT
+DELAYED} will wait until there is room in the queue again.
+
+@item @code{flush}
+This is @code{ON} if you have started @strong{MySQL} with the @code{--flush}
+option.
+
+@item @code{flush_time}
+If this is set to a non-zero value, then every @code{flush_time} seconds all
+tables will be closed (to free up resources and sync things to disk). We
+only recommend this option on Win95, Win98 or on system where you have
+very little resources.
+
+@item @code{init_file}
+The name of the file specified with the @code{--init-file} option when
+you start the server. This is a file of SQL statements you want the
+server to execute when it starts.
+
+@item @code{interactive_timeout}
+The number of seconds the server waits for activity on an interactive
+connection before closing it. An interactive client is defined as a
+client that uses the @code{CLIENT_INTERACTIVE} option to
+@code{mysql_real_connect()}. See also @code{wait_timeout}.
+
+@item @code{join_buffer_size}
+The size of the buffer that is used for full joins (joins that do not
+use indexes). The buffer is allocated one time for each full join
+between two tables. Increase this value to get a faster full join when
+adding indexes is not possible. (Normally the best way to get fast joins
+is to add indexes.)
+
+@c Make texi2html support index @anchor{Index cache size}. Then change
+@c some xrefs to point here
+@item @code{key_buffer_size}
+Index blocks are buffered and are shared by all threads.
+@code{key_buffer_size} is the size of the buffer used for index blocks.
+
+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 @strong{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 @strong{MySQL} does not cache
+data read, that you will have to leave some room for the OS filesystem
+cache.
+
+You can check the performance of the key buffer by doing @code{show
+status} and examine the variables @code{Key_read_requests},
+@code{Key_reads}, @code{Key_write_requests} and @code{Key_writes}. The
+@code{Key_reads/Key_read_request} ratio should normally be < 0.01.
+The @code{Key_write/Key_write_requests} is usually near 1 if you are
+using mostly updates/deletes but may be much smaller if you tend to
+do updates that affect many at the same time or if you are
+using @code{delay_key_write}. @xref{SHOW}.
+
+To get even more speed when writing many rows at the same time use
+@code{LOCK TABLES}. @xref{LOCK TABLES, , @code{LOCK TABLES}}.
+
+@item @code{lower_case_table_names}
+Change all table names to lower case on disk.
+
+@item @code{long_query_time}
+If a query takes longer than this (in seconds), the @code{Slow_queries} counter
+will be incremented.
+
+@item @code{max_allowed_packet}
+The maximum size of one packet. The message buffer is initialized 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.
+
+@item @code{max_connections}
+The number of simultaneous clients allowed. Increasing this value increases
+the number of file descriptors that @code{mysqld} requires. See below for
+comments on file descriptor limits. @xref{Too many connections}.
+
+@item @code{max_connect_errors}
+If there is more than this number of interrupted connections from a host
+this host will be blocked from further connections. You can unblock a host
+with the command @code{FLUSH HOSTS}.
+
+@item @code{max_delayed_threads}
+Don't start more than this number of threads to handle @code{INSERT DELAYED}
+statements. If you try to insert data into a new table after all @code{INSERT
+DELAYED} threads are in use, the row will be inserted as if the
+@code{DELAYED} attribute wasn't specified.
+
+@item @code{max_join_size}
+Joins that are probably going to read more than @code{max_join_size}
+records return an error. Set this value if your users tend to perform joins
+without a @code{WHERE} clause that take a long time and return
+millions of rows.
+
+@item @code{max_heap_table_size}
+Don't allow creation of heap tables bigger than this.
+
+@item @code{max_sort_length}
+The number of bytes to use when sorting @code{BLOB} or @code{TEXT}
+values (only the first @code{max_sort_length} bytes of each value
+are used; the rest are ignored).
+
+@item @code{max_tmp_tables}
+(This option doesn't yet do anything).
+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_sort_buffer_size}
+The buffer that is allocated when sorting the index when doing a @code{REPAIR}
+table.
+
+@item @code{net_buffer_length}
+The communication buffer is reset to this size between queries. This
+should not normally be changed, but if you have very little memory, you
+can set it to the expected size of a query. (That is, the expected length of
+SQL statements sent by clients. If statements exceed this length, the buffer
+is automatically enlarged, up to @code{max_allowed_packet} bytes.)
+
+@item @code{net_retry_count}
+If a read on a communication port is interrupted, retry this many times
+before giving up. This value should be quite high on @code{FreeBSD} as
+internal interrupts is sent to all threads.
+
+@item @code{net_read_timeout}
+Number of seconds to wait for more data from a connection before aborting
+the read. Note that when we don't expect data from a connection, the timeout
+is defined by @code{write_timeout}.
+
+@item @code{net_write_timeout}
+Number of seconds to wait for a block to be written to a connection before
+aborting the write.
+
+@item @code{record_buffer}
+Each thread that does a sequential scan allocates a buffer of this
+size for each table it scans. If you do many sequential scans, you may
+want to increase this value.
+
+@item @code{query_buffer_size}
+The initial allocation of the query buffer. If most of your queries are
+long (like when inserting blobs), you should increase this!
+
+@item @code{skip_show_databases}
+This prevents people from doing @code{SHOW DATABASES}, if they don't
+have the @code{PROCESS_PRIV} privilege. This can improve security if
+you're concerned about people being able to see what databases and
+tables other users have.
+
+@item @code{slow_launch_time}
+If the creating of the thread longer than this (in seconds), the
+@code{Slow_launch_threads} counter will be incremented.
+
+@item @code{sort_buffer}
+Each thread that needs to do a sort allocates a buffer of this
+size. Increase this value for faster @code{ORDER BY} or @code{GROUP BY}
+operations.
+@xref{Temporary files}.
+
+@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.
+@strong{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.
+
+For information about how the table cache works, see @ref{Table cache}.
+
+@item @code{thread_cache_size}
+How many threads we should keep keep in a cache for reuse. When a
+client disconnects the clients threads is put in the cache if there
+isn't more than @code{thread_cache_size} threads from before. All new
+threads are first taken from the cache and only when the cache is empty
+a new thread is created. This variable can be increased to improve
+performance if you have a lot of new connections (Normally this doesn't
+however give a notable performance improvement if you have a good
+thread implementation).
+
+@item @code{thread_concurrency}
+On Solaris, @code{mysqld} will call @code{thr_setconcurrency()} with
+this value. @code{thr_setconcurrency()} permits the application to give
+the threads system a hint, for the desired number of threads that should
+be run at the same time.
+
+@item @code{thread_stack}
+The stack size for each thread. Many of the limits detected by the
+@code{crash-me} test are dependent on this value. The default is
+large enough for normal operation. @xref{Benchmarks}.
+
+@item @code{tmp_table_size}
+If an in-memory temporary table exceeds this size, @strong{MySQL}
+will automatically convert it to an on-disk @code{MyISAM} table.
+Increase the value of @code{tmp_table_size} if you do many advanced
+@code{GROUP BY} queries and you have lots of memory.
+
+@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
+
+The manual section that describes tuning @strong{MySQL} contains some
+information of how to tune the above variables.
+
+@findex Threads
+@findex PROCESSLIST
+@node SHOW PROCESSLIST, SHOW GRANTS, SHOW VARIABLES, SHOW
+@subsection SHOW information about connected threads (processes)
+
+@code{SHOW 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, ,
+@code{KILL}}. If you don't use the the @code{FULL} option, then only
+the first 100 characters of each query will be shown.
+
+@node SHOW GRANTS, , SHOW PROCESSLIST, SHOW
+@subsection SHOW GRANTS (privileges) for a user
+
+@code{SHOW GRANTS FOR user} lists the grant commands that must be issued to
+duplicate the grants for a user.
+
+@example
+mysql> SHOW GRANTS FOR root@@localhost;
++---------------------------------------------------------------------+
+| Grants for root@@localhost |
++---------------------------------------------------------------------+
+| GRANT ALL PRIVILEGES ON *.* TO 'root'@@'localhost' WITH GRANT OPTION |
++---------------------------------------------------------------------+
+@end example
+
+@findex EXPLAIN
+@findex SELECT, optimizing
+@node EXPLAIN, DESCRIBE, SHOW, Reference
+@section @code{EXPLAIN} syntax (Get information about a @code{SELECT})
+
+@example
+ EXPLAIN tbl_name
+or EXPLAIN SELECT select_options
+@end example
+
+@code{EXPLAIN tbl_name} is a synonym for @code{DESCRIBE tbl_name} or
+@code{SHOW COLUMNS FROM tbl_name}.
+
+When you precede a @code{SELECT} statement with the keyword @code{EXPLAIN},
+@strong{MySQL} explains how it would process the @code{SELECT}, providing
+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
+@code{SELECT} statement, add a @code{STRAIGHT_JOIN} clause.
+
+For non-simple joins, @code{EXPLAIN} returns a row of information for each
+table used in the @code{SELECT} statement. The tables are listed in the order
+they would be read. @strong{MySQL} resolves all joins using a single-sweep
+multi-join method. This means that @strong{MySQL} reads a row from the first
+table, then finds a matching row in the second table, then in the third table
+and so on. When all tables are processed, it outputs the selected columns and
+backtracks through the table list until a table is found for which there are
+more matching rows. The next row is read from this table and the process
+continues with the next table.
+
+Output from @code{EXPLAIN} includes the following columns:
+
+@table @code
+@item table
+The table to which the row of output refers.
+
+@item type
+The join type. Information about the various types is given below.
+
+@item possible_keys
+The @code{possible_keys} column indicates which indexes @strong{MySQL}
+could use to find the rows in this table. Note that this column is
+totally independent of the order of the tables. That means that some of
+the keys in possible_keys may not be useable in practice with the
+generated table order.
+
+If this column is empty, there are no relevant indexes. In this case,
+you may be able to improve the performance of your query by examining
+the @code{WHERE} clause to see if it refers to some column or columns
+that would be suitable for indexing. If so, create an appropriate index
+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 @strong{MySQL} actually
+decided to use. The key is @code{NULL} if no index was chosen. If
+@strong{MySQL} chooses the wrong index, you can probably force
+@strong{MySQL} to use another index by using @code{myisamchk --analyze},
+@xref{myisamchk syntax}, or by using @code{USE INDEX/IGNORE INDEX}.
+@xref{JOIN}.
+
+@item key_len
+The @code{key_len} column indicates the length of the key that
+@strong{MySQL} decided to use. The length is @code{NULL} if the
+@code{key} is @code{NULL}. Note that this tell us how many parts of a
+multi-part key @strong{MySQL} will actually use.
+
+@item ref
+The @code{ref} column shows which columns or constants are used with the
+@code{key} to select rows from the table.
+
+@item rows
+The @code{rows} column indicates the number of rows @strong{MySQL}
+believes it must examine to execute the query.
+
+@item Extra
+This column contains additional information of how @strong{MySQL} will
+resolve the query. Here follows an explanation of the different text
+strings that can be found in this column:
+
+@table @code
+@item Not exists
+@strong{MySQL} was able to do a @code{LEFT JOIN} optimization on the
+query and will not examine more rows in this table for a row combination
+after it founds one rows that matches the @code{LEFT JOIN} criteria.
+@item @code{range checked for each record (index map: #)}
+@strong{MySQL} didn't find a real good index to use. It will instead for
+each row combination in the preceding tables do a check which index to
+use (if any) use this index to retrieve the rows from the table. This
+isn't very fast but is of course faster than having to do a join without
+an index.
+@item Using filesort
+@strong{MySQL} will need to do an extra pass to find out how to retrieve
+the rows in sorted order. The sort is done by going through all rows
+according to the @code{join type} and storing the sort key + pointer to
+the row for all rows that match the @code{WHERE}. Then the keys are
+sorted. Finally the rows are retrieved in sorted order.
+@item Using index
+The column information is retrieved from the table using only
+information in the index tree without having to do an additional seek to
+read the actually row. This can be done when all the used columns for
+the table are part of the same index.
+@item Using temporary
+To be able to resolve the query @strong{MySQL} will need to create a
+temporary table to hold the result. This typically happens if you do an
+@code{ORDER BY} on a different column set than you did an @code{GROUP
+BY} on.
+@item Where used
+A @code{WHERE} clause will be used to restrict which rows will be
+matched against the next table or sent to the client. If you don't have
+this information and the the table is of type @code{ALL} or @code{index}
+you may have something wrong in your query (if you don't intend to
+fetch/examine all rows from the table).
+@end table
+
+If you want to get your queries as fast as possible, you should look out for
+@code{Using filesort} and @code{Using temporary}.
+@end table
+
+The different join types are listed below, ordered from best to worst type:
+
+@cindex System table
+@cindex Table, system
+@table @code
+@item system
+The table has only one row (= system table). This is a special case of
+the @code{const} join type.
+
+@cindex Constant table
+@cindex Table, constant
+@item const
+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!
+
+@item eq_ref
+One row will be read from this table for each combination of rows from
+the previous tables. This the best possible join type, other than the
+@code{const} types. It is used when all parts of an index are used by
+the join and the index is @code{UNIQUE} or a @code{PRIMARY KEY}.
+
+@item ref
+All rows with matching index values will be read from this table for each
+combination of rows from the previous tables. @code{ref} is used if the join
+uses only a leftmost prefix of the key, or if the key is not @code{UNIQUE}
+or a @code{PRIMARY KEY} (in other words, if the join cannot select a single
+row based on the key value). If the key that is used matches only a few rows,
+this join type is good.
+
+@item range
+Only rows that are in a given range will be retrieved, using an index to
+select the rows. The @code{ref} column indicates which index is used.
+
+@item index
+This is the same as @code{ALL}, except that only the index tree is
+scanned. This is usually faster than @code{ALL}, as the index file is usually
+smaller than the data file.
+
+@item ALL
+A full table scan will be done for each combination of rows from the
+previous tables. This is normally not good if the table is the first
+table not marked @code{const}, and usually @strong{very} bad in all other
+cases. You normally can avoid @code{ALL} by adding more indexes, so that
+the row can be retrieved based on constant values or column values from
+earlier tables.
+@end table
+
+You can get a good indication of how good a join is by multiplying all values
+in the @code{rows} column of the @code{EXPLAIN} output. This should tell you
+roughly how many rows @strong{MySQL} must examine to execute the query. This
+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
+using the information provided by @code{EXPLAIN}.
+
+Suppose you have the @code{SELECT} statement shown below, that you examine
+using @code{EXPLAIN}:
+
+@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
+
+For this example, assume that:
+
+@itemize @bullet
+@item
+The columns being compared have been declared as follows:
+
+@multitable @columnfractions .1 .2 .7
+@item @strong{Table} @tab @strong{Column} @tab @strong{Column type}
+@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
+The tables have the indexes shown below:
+
+@multitable @columnfractions .1 .9
+@item @strong{Table} @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
+The @code{tt.ActualPC} values aren't evenly distributed.
+@end itemize
+
+Initially, before any optimizations have been performed, the @code{EXPLAIN}
+statement produces the following information:
+
+@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
+
+Because @code{type} is @code{ALL} for each table, this output indicates that
+@strong{MySQL} is doing a full join for all tables! This will take quite a
+long time, as the product of the number of rows in each table must be
+examined! For the case at hand, this is @code{74 * 2135 * 74 * 3872 =
+45,268,558,720} rows. If the tables were bigger, you can only imagine how
+long it would take...
+
+One problem here is that @strong{MySQL} can't (yet) use indexes on columns
+efficiently if they are declared differently. In this context,
+@code{VARCHAR} and @code{CHAR} are the same unless they are declared as
+different lengths. Because @code{tt.ActualPC} is declared as @code{CHAR(10)}
+and @code{et.EMPLOYID} is declared as @code{CHAR(15)}, there is a length
+mismatch.
+
+To fix this disparity between column lengths, use @code{ALTER TABLE} to
+lengthen @code{ActualPC} from 10 characters to 15 characters:
+
+@example
+mysql> ALTER TABLE tt MODIFY ActualPC VARCHAR(15);
+@end example
+
+Now @code{tt.ActualPC} and @code{et.EMPLOYID} are both @code{VARCHAR(15)}.
+Executing the @code{EXPLAIN} statement again 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
+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
+
+This is not perfect, but is much better (the product of the @code{rows}
+values is now less by a factor of 74). This version is executed in a couple
+of seconds.
+
+A second alteration can be made to eliminate the column length mismatches
+for the @code{tt.AssignedPC = et_1.EMPLOYID} and @code{tt.ClientID =
+do.CUSTNMBR} comparisons:
+
+@example
+mysql> ALTER TABLE tt MODIFY AssignedPC 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
+@end example
+
+This is ``almost'' as good as it can get.
+
+The remaining problem is that, by default, @strong{MySQL} assumes that values
+in the @code{tt.ActualPC} column are evenly distributed, and that isn't the
+case for the @code{tt} table. Fortunately, it is easy to tell @strong{MySQL}
+about this:
+
+@example
+shell> myisamchk --analyze PATH_TO_MYSQL_DATABASE/tt
+shell> mysqladmin refresh
+@end example
+
+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
+@end example
+
+Note that the @code{rows} column in the output from @code{EXPLAIN} is an
+``educated guess'' from the @strong{MySQL} join optimizer; To optimize 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
+the @code{FROM} clause.
+
+@findex DESC
+@findex DESCRIBE
+@node DESCRIBE, COMMIT, EXPLAIN, Reference
+@section @code{DESCRIBE} syntax (Get information about columns)
+
+@example
+@{DESCRIBE | DESC@} tbl_name @{col_name | wild@}
+@end example
+
+@code{DESCRIBE} provides information about a table's columns. @code{col_name}
+may be a column name or a string containing the SQL @samp{%} and @samp{_}
+wildcard characters.
+
+If the column types are different than you expect them to be based on a
+@code{CREATE TABLE} statement, note that @strong{MySQL} sometimes changes column
+types.
+@xref{Silent column changes}.
+
+@cindex Oracle compatibility
+@cindex Compatibility, with Oracle
+This statement is provided for Oracle compatibility.
+
+The @code{SHOW} statement provides similar information.
+@xref{SHOW, , @code{SHOW}}.
+
+
+@findex BEGIN
+@findex COMMIT
+@findex ROLLBACK
+@node COMMIT, LOCK TABLES, DESCRIBE, Reference
+@section @code{BEGIN/COMMIT/ROLLBACK} syntax
+
+By default, @strong{MySQL} runs in @code{autocommit} mode. This means that
+as soon as you execute an update, @strong{MySQL} will store the update on
+disk.
+
+If you are using @code{BDB} tables, you can put @strong{MySQL} into
+non-@code{autocommit} mode with the following command:
+
+@example
+SET AUTOCOMMIT=0
+@end example
+
+After this you must use @code{COMMIT} to store your changes to disk or
+@code{ROLLBACK} if you want to ignore the changes you have made since
+the beginning of your transaction.
+
+If you want to switch from @code{AUTOCOMMIT} mode for one serie of
+statements, you can use the @code{BEGIN} or @code{BEGIN WORK} statement.
+
+@example
+BEGIN;
+SELECT @@A:=SUM(salary) FROM table1 WHERE type=1;
+UPDATE table2 SET summmary=@@A WHERE type=1;
+COMMIT;
+@end example
+
+Note that if you are using non-transaction-safe tables, the changes will be
+stored at once, independent of the status of the @code{autocommit} mode.
+
+@findex LOCK TABLES
+@findex UNLOCK TABLES
+@node LOCK TABLES, SET OPTION, COMMIT, Reference
+@section @code{LOCK TABLES/UNLOCK TABLES} syntax
+
+@example
+LOCK TABLES tbl_name [AS alias] @{READ | [READ LOCAL] | [LOW_PRIORITY] WRITE@}
+ [, tbl_name @{READ | [LOW_PRIORITY] WRITE@} ...]
+...
+UNLOCK TABLES
+@end example
+
+@code{LOCK TABLES} locks tables for the current thread. @code{UNLOCK TABLES}
+releases any locks held by the current thread. All tables that are locked by
+the current thread are automatically unlocked when the thread issues another
+@code{LOCK TABLES}, or when the connection to the server is closed.
+
+If a thread obtains a @code{READ} lock on a table, that thread (and all other
+threads) can only read from the table. If a thread obtains a @code{WRITE}
+lock on a table, then only the thread holding the lock can @code{READ} from
+or @code{WRITE} to the table. Other threads are blocked.
+
+The difference between @code{READ LOCAL} and @code{READ} is that
+@code{READ LOCAL} allows non-conflicting @code{INSERT} statements to
+execute while the lock is held. This can't however be used if you are
+going to manipulate the database files outside @strong{MySQL} while you
+hold the lock.
+
+Each thread waits (without timing out) until it obtains all the locks it has
+requested.
+
+@code{WRITE} locks normally have higher priority than @code{READ} locks, to
+ensure that updates are processed as soon as possible. This means that if one
+thread obtains a @code{READ} lock and then another thread requests a
+@code{WRITE} lock, subsequent @code{READ} lock requests will wait until the
+@code{WRITE} thread has gotten the lock and released it. You can use
+@code{LOW_PRIORITY WRITE} locks to allow other threads to obtain @code{READ}
+locks while the thread is waiting for the @code{WRITE} lock. You should only
+use @code{LOW_PRIORITY WRITE} locks if you are sure that there will
+eventually be a time when no threads will have a @code{READ} lock.
+
+When you use @code{LOCK TABLES}, you must lock all tables that you are
+going to use and you must use the same alias that you are going to use in
+your queries! If you are using a table multiple times in a query (with
+aliases), you must get a lock for each alias! This policy ensures that
+table locking is deadlock free.
+
+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.
+
+Normally, you don't have to lock tables, as all single @code{UPDATE} statements
+are atomic; no other thread can interfere with any other currently executing
+SQL statement. There are a few cases when you would like to lock tables
+anyway:
+
+@itemize @bullet
+@item
+If you are going to run many operations on a bunch of tables, it's much
+faster to lock the tables you are going to use. The downside is, of course,
+that no other thread can update a @code{READ}-locked table and no other
+thread can read a @code{WRITE}-locked table.
+@item
+@strong{MySQL} doesn't support a transaction environment, so you must use
+@code{LOCK TABES} 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;
+mysql> UNLOCK TABLES;
+@end example
+
+Without @code{LOCK TABLES}, there is a chance that another thread might
+insert a new row in the @code{trans} table between execution of the
+@code{SELECT} and @code{UPDATE} statements.
+@end itemize
+
+By using incremental updates (@code{UPDATE customer SET
+value=value+new_value}) or the @code{LAST_INSERT_ID()} function, you can
+avoid using @code{LOCK TABLES} in many cases.
+
+You can also solve some cases by using the user-level lock functions
+@code{GET_LOCK()} and @code{RELEASE_LOCK()}. These locks are saved in a hash
+table in the server and implemented with @code{pthread_mutex_lock()} and
+@code{pthread_mutex_unlock()} for high speed.
+@xref{Miscellaneous functions}.
+
+See @ref{Internal locking}, for more information on locking policy.
+
+You can also lock all tables in all databases with read locks with the
+@code{FLUSH TABLES WITH READ LOCK} command. @xref{FLUSH}.
+
+@findex SET OPTION
+@node SET OPTION, GRANT, LOCK TABLES, Reference
+@section @code{SET} syntax
+
+@example
+SET [OPTION] SQL_VALUE_OPTION= value, ...
+@end example
+
+@code{SET OPTION} sets various options that affect the operation of the
+server or your client. Any option you set remains in effect until the
+current session ends, or until you set the option to a different value.
+
+@table @code
+@item CHARACTER SET character_set_name | DEFAULT
+This maps all strings from and to the client with the given mapping.
+Currently the only option for @code{character_set_name} is
+@code{cp1251_koi8}, but you can easily add new mappings by editing the
+@file{sql/convert.cc} file in the @strong{MySQL} source distribution. The
+default mapping can be restored by using a @code{character_set_name} value of
+@code{DEFAULT}.
+
+Note that the syntax for setting the @code{CHARACTER SET} option differs
+from the syntax for setting the other options.
+
+@item PASSWORD = PASSWORD('some password')
+@cindex Passwords, setting
+Set the password for the current user. Any non-anonymous user can change his
+own password!
+
+@item PASSWORD FOR user = PASSWORD('some password')
+@cindex Passwords, setting
+Set the password for a specific user on the current server host. Only a user
+with access to the @code{mysql} database can do this. The user should be
+given in @code{user@@hostname} format, where @code{user} and @code{hostname}
+are exactly as they are listed in the @code{User} and @code{Host} columns of
+the @code{mysql.user} table entry. For example, if you had an entry with
+@code{User} and @code{Host} fields of @code{'bob'} and @code{'%.loc.gov'},
+you would write:
+
+@example
+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";
+@end example
+
+@item SQL_AUTO_IS_NULL = 0 | 1
+If set to @code{1} (default) then one can find the last inserted row
+for a table with an auto_increment row with the following construct:
+@code{WHERE auto_increment_column IS NULL}. This is used by some
+ODBC programs like Access.
+
+@item SET AUTOCOMMIT= 0 | 1
+If set to @code{1} all changes to a table will be done at once. To start
+an multi command transaction you have to use the @code{BEGIN}
+statement. @xref{COMMIT}. If set to @code{0} you have to use @code{COMMIT} /
+@code{ROLLBACK} to accept/revoke that transaction. @xref{COMMIT}. Note
+that when you change from not @code{AUTOCOMMIT} mode to
+@code{AUTOCOMMIT} mode, @strong{MySQL} will do an automatic
+@code{COMMIT} on any open transactions.
+
+@item SQL_BIG_TABLES = 0 | 1
+@cindex The table is full
+If set to @code{1}, all temporary tables are stored on disk rather than in
+memory. This will be a little slower, but you will not get the error
+@code{The table tbl_name is full} for big @code{SELECT} operations that
+require a large temporary table. The default value for a new connection is
+@code{0} (i.e., use in-memory temporary tables).
+
+@item SQL_BIG_SELECTS = 0 | 1
+If set to @code{0}, @strong{MySQL} will abort if a @code{SELECT} is attempted
+that probably will take a very long time. This is useful when an inadvisable
+@code{WHERE} statement has been issued. A big query is defined as a
+@code{SELECT} that probably will have to examine more than
+@code{max_join_size} rows. The default value for a new connection is
+@code{1} (which will allow all @code{SELECT} statements).
+
+@item SQL_BUFFER_RESULT = 0 | 1
+@code{SQL_BUFFER_RESULT} will force the result from @code{SELECT}'s
+to be put into a temporary table. This will help @strong{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 SQL_LOW_PRIORITY_UPDATES = 0 | 1
+If set to @code{1}, all @code{INSERT}, @code{UPDATE}, @code{DELETE} and
+and @code{LOCK TABLE WRITE} statements wait until there is no pending
+@code{SELECT} or @code{LOCK TABLE READ} on the affected table.
+
+@item SQL_MAX_JOIN_SIZE = value | DEFAULT
+Don't allow @code{SELECT}'s that will probably need to examine more than
+@code{value} row combinations. By setting this value, you can catch
+@code{SELECT}'s where keys are not used properly and that would probably
+take a long time. Setting this to a value other than @code{DEFAULT} will reset
+the @code{SQL_BIG_SELECTS} flag. If you set the @code{SQL_BIG_SELECTS}
+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_SAFE_MODE = 0 | 1
+If set to @code{1}, @strong{MySQL} will abort if a @code{UPDATE} or
+@code{DELETE} is attempted that doesn't use a key or @code{LIMIT} in the
+@code{WHERE} clause. This makes it possible to catch wrong updates
+when creating SQL commands by hand.
+
+@item SQL_SELECT_LIMIT = value | DEFAULT
+The maximum number of records to return from @code{SELECT} statements. If
+a @code{SELECT} has a @code{LIMIT} clause, the @code{LIMIT} takes precedence
+over the value of @code{SQL_SELECT_LIMIT}. The default value for a new
+connection is ``unlimited''. If you have changed the limit, the default value
+can be restored by using a @code{SQL_SELECT_LIMIT} value of @code{DEFAULT}.
+
+@item SQL_LOG_OFF = 0 | 1
+If set to @code{1}, no logging will be done to the standard log for this
+client, if the client has the @strong{process} privilege. This does not
+affect the update log!
+
+@item SQL_LOG_UPDATE = 0 | 1
+If set to @code{0}, no logging will be done to the update log for the client,
+if the client has the @strong{process} privilege. This does not affect the
+standard log!
+
+@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.
+
+@item LAST_INSERT_ID = #
+Set the value to be returned from @code{LAST_INSERT_ID()}. This is stored in
+the update log when you use @code{LAST_INSERT_ID()} in a command that updates
+a table.
+
+@item INSERT_ID = #
+Set the value to be used by the following @code{INSERT} command when inserting
+an @code{AUTO_INCREMENT} value. This is mainly used with the update log.
+@end table
+
+@findex GRANT
+@findex REVOKE
+@node GRANT, CREATE INDEX, SET OPTION, Reference
+@section @code{GRANT} and @code{REVOKE} syntax
+
+@example
+GRANT priv_type [(column_list)] [, priv_type [(column_list)] ...]
+ ON @{tbl_name | * | *.* | db_name.*@}
+ TO user_name [IDENTIFIED BY 'password']
+ [, user_name [IDENTIFIED BY 'password'] ...]
+ [WITH GRANT OPTION]
+
+REVOKE priv_type [(column_list)] [, priv_type [(column_list)] ...]
+ ON @{tbl_name | * | *.* | db_name.*@}
+ FROM user_name [, user_name ...]
+@end example
+
+@code{GRANT} is implemented in @strong{MySQL} 3.22.11 or later. For
+earlier @strong{MySQL} versions, the @code{GRANT} statement does nothing.
+
+The @code{GRANT} and @code{REVOKE} commands allow system administrators to
+grant and revoke rights to @strong{MySQL} users at four privilege levels:
+
+@table @strong
+@item Global level
+Global privileges apply to all databases on a given server. These privileges
+are stored in the @code{mysql.user} table.
+
+@item Database level
+Database privileges apply to all tables in a given database. These privileges
+are stored in the @code{mysql.db} and @code{mysql.host} tables.
+
+@item Table level
+Table privileges apply to all columns in a given table. These privileges are
+stored in the @code{mysql.tables_priv} table.
+
+@item Column level
+Column privileges apply to single columns in a given table. These privileges are
+stored in the @code{mysql.columns_priv} table.
+@end table
+
+For examples of how @code{GRANT} works, see @ref{Adding users}.
+
+For the @code{GRANT} and @code{REVOKE} statements, @code{priv_type} may be
+specified as any of the following:
+
+@example
+ALL PRIVILEGES FILE RELOAD
+ALTER INDEX SELECT
+CREATE INSERT SHUTDOWN
+DELETE PROCESS UPDATE
+DROP REFERENCES USAGE
+@end example
+
+@code{ALL} is a synonym for @code{ALL PRIVILEGES}. @code{REFERENCES} is not
+yet implemented. @code{USAGE} is currently a synonym for ``no privileges''.
+It can be used when you want to create a user that has no privileges.
+
+To revoke the @strong{grant} privilege from a user, use a @code{priv_type}
+value of @code{GRANT OPTION}:
+
+@example
+REVOKE GRANT OPTION ON ... FROM ...;
+@end example
+
+The only @code{priv_type} values you can specify for a table are @code{SELECT},
+@code{INSERT}, @code{UPDATE}, @code{DELETE}, @code{CREATE}, @code{DROP},
+@code{GRANT}, @code{INDEX} and @code{ALTER}.
+
+The only @code{priv_type} values you can specify for a column (that is, when
+you use a @code{column_list} clause) are @code{SELECT}, @code{INSERT} and
+@code{UPDATE}.
+
+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
+@emph{don't} have a current database, you will affect the global privileges!)
+
+In order to accommodate granting rights to users from arbitrary hosts,
+@strong{MySQL} supports specifying the @code{user_name} value in the form
+@code{user@@host}. If you want to specify a @code{user} string
+containing special characters (such as @samp{-}), or a @code{host} string
+containing special characters or wildcard characters (such as @samp{%}), you
+can quote the user or host name (e.g., @code{'test-user'@@'test-hostname'}).
+
+You can specify wildcards in the hostname. For example,
+@code{user@@"%.loc.gov"} applies to @code{user} for any host in the
+@code{loc.gov} domain, and @code{user@@"144.155.166.%"} applies to @code{user}
+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 @strong{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 @strong{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:
+
+@example
+mysql> SELECT Host,User FROM mysql.user WHERE User='';
+@end example
+
+For the moment, @code{GRANT} only supports host, table, database and
+column names up to 60 characters long. A user name can be up to 16
+characters.
+
+The privileges for a table or column are formed from the
+logical OR of the privileges at each of the four privilege
+levels. For example, if the @code{mysql.user} table specifies that a
+user has a global @strong{select} privilege, this can't be denied by an
+entry at the database, table or column level.
+
+The privileges for a column can be calculated as follows:
+
+@example
+global privileges
+OR (database privileges AND host privileges)
+OR table privileges
+OR column privileges
+@end example
+
+In most cases, you grant rights to a user at only one of the privilege
+levels, so life isn't normally as complicated as above. :) The details of the
+privilege-checking procedure are presented in
+@ref{Privilege system}.
+
+If you grant privileges for a user/hostname combination that does not exist
+in the @code{mysql.user} table, an entry is added and remains there until
+deleted with a @code{DELETE} command. In other words, @code{GRANT} may
+create @code{user} table entries, but @code{REVOKE} will not remove them;
+you must do that explicitly using @code{DELETE}.
+
+@cindex Passwords, setting
+In @strong{MySQL} 3.22.12 or later,
+if a new user is created or if you have global grant privileges, the user's
+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
+@code{IDENTIFIED BY} clause, the user has no password. This is insecure.
+
+Passwords can also be set with the @code{SET PASSWORD} command.
+@xref{SET OPTION, , @code{SET OPTION}}.
+
+If you grant privileges for a database, an entry in the @code{mysql.db}
+table is created if needed. When all privileges for the database have been
+removed with @code{REVOKE}, this entry is deleted.
+
+If a user doesn't have any privileges on a table, the table is not displayed
+when the user requests a list of tables (e.g., with a @code{SHOW TABLES}
+statement).
+
+The @code{WITH GRANT OPTION} clause gives the user the ability to give
+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!
+
+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.
+
+Be aware that when you grant a user the @strong{grant} privilege at a
+particular privilege level, any privileges the user already possesses (or
+is given in the future!) at that level are also grantable by that user.
+Suppose you grant a user the @strong{insert} privilege on a database. If
+you then grant the @strong{select} privilege on the database and specify
+@code{WITH GRANT OPTION}, the user can give away not only the @strong{select}
+privilege, but also @strong{insert}. If you then grant the @strong{update}
+privilege to the user on the database, the user can give away the
+@strong{insert}, @strong{select} and @strong{update}.
+
+You should not grant @strong{alter} privileges to a normal user. If you
+do that, the user can try to subvert the privilege system by renaming
+tables!
+
+Note that if you are using table or column privileges for even one user, the
+server examines table and column privileges for all users and this will slow
+down @strong{MySQL} a bit.
+
+When @code{mysqld} starts, all privileges are read into memory.
+Database, table and column privileges take effect at once and
+user-level privileges take effect the next time the user connects.
+Modifications to the grant tables that you perform using @code{GRANT} or
+@code{REVOKE} are noticed by the server immediately.
+If you modify the grant tables manually (using @code{INSERT}, @code{UPDATE},
+etc.), you should execute a @code{FLUSH PRIVILEGES} statement or run
+@code{mysqladmin flush-privileges} to tell the server to reload the grant
+tables.
+@xref{Privilege changes}.
+
+@cindex ANSI SQL, differences from
+The biggest differences between the ANSI SQL and @strong{MySQL} versions of
+@code{GRANT} are:
+
+@itemize @bullet
+@item
+ANSI SQL doesn't have global or database-level privileges and ANSI SQL
+doesn't support all privilege types that @strong{MySQL} supports.
+
+@item
+When you drop a table in ANSI SQL, all privileges for the table are revoked.
+If you revoke a privilege in ANSI SQL, all privileges that were granted based
+on this privilege are also revoked. In @strong{MySQL}, privileges can be
+dropped only with explicit @code{REVOKE} commands or by manipulating the
+@strong{MySQL} grant tables.
+@end itemize
+
+@cindex Indexes
+@cindex Indexes, multi-part
+@cindex Multi-part index
+@findex CREATE INDEX
+@node CREATE INDEX, DROP INDEX, GRANT, Reference
+@section @code{CREATE INDEX} syntax
+
+@example
+CREATE [UNIQUE] INDEX index_name ON tbl_name (col_name[(length)],... )
+@end example
+
+The @code{CREATE INDEX} statement doesn't do anything in @strong{MySQL} prior
+to version 3.22. In 3.22 or later, @code{CREATE INDEX} is mapped to an
+@code{ALTER TABLE} statement to create indexes.
+@xref{ALTER TABLE, , @code{ALTER TABLE}}.
+
+Normally, you create all indexes on a table at the time the table itself
+is created with @code{CREATE TABLE}.
+@xref{CREATE TABLE, , @code{CREATE TABLE}}.
+@code{CREATE INDEX} allows you to add indexes to existing tables.
+
+A column list of the form @code{(col1,col2,...)} creates a multiple-column
+index. Index values are formed by concatenating the values of the given
+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
+statement shown below creates an index using the first 10 characters of
+the @code{name} column:
+
+@example
+mysql> CREATE INDEX part_of_name ON customer (name(10));
+@end example
+
+Because most names usually differ in the first 10 characters, this index should
+not be much slower than an index created from the entire @code{name} column.
+Also, using partial columns for indexes can make the index file much smaller,
+which could save a lot of disk space and might also speed up @code{INSERT}
+operations!
+
+Note that you can only add an index on a column that can have @code{NULL}
+values or on a @code{BLOB}/@code{TEXT} column if you are useing
+@strong{MySQL} version 3.23.2 or newer and are using the @code{MyISAM}
+table type.
+
+For more information about how @strong{MySQL} uses indexes, see
+@ref{MySQL indexes, , @strong{MySQL} indexes}.
+
+@findex DROP INDEX
+@node DROP INDEX, Comments, CREATE INDEX, Reference
+@section @code{DROP INDEX} syntax
+
+@example
+DROP INDEX index_name ON tbl_name
+@end example
+
+@code{DROP INDEX} drops the index named @code{index_name} from the table
+@code{tbl_name}. @code{DROP INDEX} doesn't do anything in @strong{MySQL}
+prior to version 3.22. In 3.22 or later, @code{DROP INDEX} is mapped to an
+@code{ALTER TABLE} statement to drop the index.
+@xref{ALTER TABLE, , @code{ALTER TABLE}}.
+
+@findex Comment syntax
+@node Comments, CREATE FUNCTION, DROP INDEX, Reference
+@section Comment syntax
+
+The @strong{MySQL} server supports the @code{# to end of line}, @code{--
+to end of line} and @code{/* in-line or multiple-line */} comment
+styles:
+
+@example
+mysql> select 1+1; # This comment continues to the end of line
+mysql> select 1+1; -- This comment continues to the end of line
+mysql> select 1 /* this is an in-line comment */ + 1;
+mysql> select 1+
+/*
+this is a
+multiple-line comment
+*/
+1;
+@end example
+
+Note that the @code{--} comment style requires you to have at least one space
+after the @code{--}!
+
+Although the server understands the comment syntax just described,
+there are some limitations on the way that the @code{mysql} client
+parses @code{/* ... */} comments:
+
+@itemize @bullet
+@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
+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{">}.
+
+@item
+A semicolon is taken to indicate the end of the current SQL statement
+and anything following it to indicate the beginning of the next statement.
+@end itemize
+
+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}.
+
+@strong{MySQL} doesn't support the @samp{--} ANSI SQL comment style.
+@xref{Missing comments}.
+
+@findex CREATE FUNCTION
+@findex DROP FUNCTION
+@findex UDF functions
+@findex User-defined functions
+@findex Functions, user-defined
+@node CREATE FUNCTION, Reserved words, Comments, Reference
+@section @code{CREATE FUNCTION/DROP FUNCTION} syntax
+
+@example
+CREATE [AGGREGATE] FUNCTION function_name RETURNS @{STRING|REAL|INTEGER@}
+ SONAME shared_library_name
+
+DROP FUNCTION function_name
+@end example
+
+A user-definable function (UDF) is a way to extend @strong{MySQL} with a new
+function that works like native (built in) @strong{MySQL} functions such as
+@code{ABS()} and @code{CONCAT()}.
+
+@code{AGGREGATE} is a new option for @strong{MySQL} 3.23. An
+@code{AGGREGATE} function works exactly like a native @strong{MySQL}
+@code{GROUP} function like @code{SUM} or @code{COUNT()}.
+
+@code{CREATE FUNCTION} saves the function's name, type and shared library
+name in the @code{mysql.func} system table. You must have the
+@strong{insert} and @strong{delete} privileges for the @code{mysql} database
+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.
+(An active function is one that has been loaded with @code{CREATE FUNCTION}
+and not removed with @code{DROP FUNCTION}.)
+
+For instructions on writing user-definable functions, see @ref{Adding
+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).
+
+@cindex Keywords
+@cindex Reserved words
+@cindex Reserved words, exceptions
+@node Reserved words, , CREATE FUNCTION, Reference
+@section Is MySQL picky about reserved words?
+
+A common problem stems from trying to create a table with column names that
+use the names of datatypes or functions built into @strong{MySQL}, such as
+@code{TIMESTAMP} or @code{GROUP}. You're allowed to do it (for example,
+@code{ABS} is an allowed column name), but whitespace is not allowed between
+a function name and the @samp{(} when using functions whose names are also
+column names.
+
+The following words are explicitly reserved in @strong{MySQL}. Most of
+them are forbidden by ANSI SQL92 as column and/or table names
+(for example, @code{group}).
+A few are reserved because @strong{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
+
+@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}
+@end multitable
+
+The following symbols (from the table above) are disallowed by ANSI SQL
+but allowed by @strong{MySQL} as column/table names. This is because some
+of these names are very natural names and a lot of people have already
+used them.
+
+@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
+
+@cindex Table types, Choosing
+@cindex BDB table type
+@cindex Berkeley_db table type
+@cindex ISAM table type
+@cindex HEAP table type
+@cindex MySQL table types
+@cindex MyISAM table type
+@node Table types, Tutorial, Reference, Top
+@chapter MySQL table types
+
+As of @strong{MySQL} 3.23.6, you can choose between three basic
+table formats. When you create a new table, you can tell @strong{MySQL}
+which table type it should use for the table. @strong{MySQL} will
+always create a @code{.frm} file to hold the table and column
+definitions. Depending on the table type the index and data will be
+stored in other files.
+
+The default table type in @strong{MySQL} is @code{MyISAM}. If you are
+trying to use a table type that is not incompiled or activated,
+@strong{MySQL} will instead create a table of type @code{MyISAM}.
+
+You can convert tables between different types with the @code{ALTER
+TABLE} statement. @xref{ALTER TABLE, , @code{ALTER TABLE}}.
+
+Note that @strong{MySQL} supports two different kind of
+tables. Transactions safe tables (@code{BDB}) and not transaction safe
+tables (@code{ISAM},@code{MyISAM} and @code{HEAP}.
+
+Advantages of transaction safe tables (TST)
+
+@itemize @bullet
+@item
+Safer; Even if @code{MySQL} crashes or you get hardware problems, you
+can get your data back; Either by automatic recovery or from a backup
++ the transaction log.
+@item
+You can combine many statements and accept these all in one go with
+the @code{COMMIT} command.
+@item
+You can execute @code{ROLLBACK} to ignore your changes (if you are not
+running in auto commit mode).
+@item
+If an update fails, all your changes will be restored. (With NTST tables all
+changes that has taken place are permanent)
+@end itemize
+
+Advantages of not transaction safe tables (NTST):
+
+@itemize @bullet
+@item
+Much faster as there is no transcation overhead.
+@item
+Will use less disk space as there is no overhead of transactions.
+@item
+Will use less memory to do updates.
+@end itemize
+
+You can combine TST and NTST tables in the same statements to get the best
+of both worlds.
+
+@menu
+* MyISAM:: MyISAM tables
+* ISAM:: ISAM tables
+* HEAP:: HEAP tables
+* BDB:: BDB or Berkeley_db tables
+@end menu
+
+@node MyISAM, ISAM, Table types, Table types
+@section MyISAM tables
+
+@code{MyISAM} is the default table type in @strong{MySQL} 3.23. It's
+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 file with the @code{.MYD} (MYData) extension.
+You can check/repair @code{MyISAM} tables with the @code{myisamchk}
+utility. @xref{Crash recovery}.
+
+The following is new in @code{MyISAM}:
+
+@itemize @bullet
+@item
+You can @code{INSERT} new rows in a table without deleted rows,
+while other threads are reading from the table.
+@item
+Support for big files (63-bit) on filesystems/operating systems that
+support big files.
+@item
+All data is stored with the low byte first. This makes the data machine and
+OS independent. The only requirement is that the machine uses two's-complement
+signed integers (as every machine for the last 20 years has)
+and IEEE floating point format (also totally dominant among mainstream
+machines). The only area of machines that may not support binary
+compatibility are embedded systems (because they sometimes have peculiar
+processors).
+@item
+All number keys are stored with high byte first to give better index
+compression.
+@item
+Internal handling of one @code{AUTO_INCREMENT} column. @code{MyISAM}
+will automatically update this on @code{INSERT/UPDATE}. The
+@code{AUTO_INCREMENT} value can be reset with @code{myisamchk}. This
+will make @code{AUTO_INCREMENT} columns faster (at least 10 %) and old
+numbers will not be reused as with the old ISAM. Note that when a
+@code{AUTO_INCREMENT} is defined on the end of a multi-part-key the old
+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.
+@item
+@code{BLOB} and @code{TEXT} columns can be indexed.
+@item
+@code{NULL} values are allowed in indexed columns. This takes 0-1
+bytes/key.
+@item
+Maximum key length is now 500 bytes by default. 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 enlarged to 32 as default. This can be
+enlarged to 64 without having to recompile @code{myisamchk}.
+@item
+There is a flag in the @code{MyISAM} file that indicates whether or not the
+table was closed correctly. This will soon be used for automatic repair
+in the @strong{MySQL} server.
+@item
+@code{myisamchk} will mark tables as checked if one runs it with
+@code{--update-state}. @code{myisamchk --fast} will only check those
+tables that don't have this mark.
+@item
+@code{myisamchk -a} stores statistics for key parts (and not only for
+whole keys as in @code{ISAM}).
+@item
+Dynamic size rows will now be much less fragmented when mixing deletes
+with updates and inserts. This is done by automatically combining adjacent
+deleted blocks and by extending blocks if the next block is deleted.
+@item
+@code{myisampack} can pack @code{BLOB} and @code{VARCHAR} columns.
+@end itemize
+
+@code{MyISAM} also supports the following things, which @strong{MySQL}
+will be able to use in the near future.
+
+@itemize @bullet
+@item
+Support for a true @code{VARCHAR} type; A @code{VARCHAR} column starts
+with a length stored in 2 bytes.
+@item
+Tables with @code{VARCHAR} may have fixed or dynamic record length.
+@item
+@code{VARCHAR} and @code{CHAR} may be up to 64K.
+All key segments have their own language definition. This will enable
+@strong{MySQL} to have different language definitions per column.
+@item
+A hashed computed index can be used for @code{UNIQUE}; This will allow
+you to have @code{UNIQUE} on any combination of columns in a table. (You
+can't search on a @code{UNIQUE} computed index, however.)
+@end itemize
+
+Note that index files are usually much smaller with @code{MyISAM} than with
+@code{ISAM}. This means that @code{MyISAM} will normally use less
+system resources than @code{ISAM}, but will need more CPU when inserting
+data into compressed index.
+
+@menu
+* Key space:: Space needed for keys
+* MyISAM table formats:: MyISAM table formats
+@end menu
+
+@node Key space, MyISAM table formats, MyISAM, MyISAM
+@subsection Space needed for keys
+
+@strong{MySQL} can support different index types, but the normal type is
+ISAM or MyISAM. These use a B-tree index and you can roughly calculate
+the size for the index file as @code{(key_length+4)/0.67}, summed over
+all keys. (This is for the worst case when all keys are inserted in
+sorted order and we don't have any compressed keys.)
+
+String indexes are space compressed. If the first index part is a
+string, it will also be prefix compressed. Space compression makes the
+index file smaller than the above figures if the string column has a lot
+of trailing space or is a @code{VARCHAR} column that is not always used
+to the full length. Prefix compression is used on keys that start
+with a string. Prefix compression helps if there are many strings
+with an identical prefix.
+
+In @code{MyISAM} tables, you can also prefix compress numbers by specifying
+@code{PACK_KEYS=1} when you create the table. This helps when you have
+many integer keys which have an identical prefix when the numbers are stored
+high-byte first.
+
+@node MyISAM table formats, , Key space, MyISAM
+@subsection MyISAM table formats
+
+@strong{MyISAM} supports 3 different table types. 2 of them are chosen
+automatically depending on the type of columns you are using. The third,
+compressed tables, can only be created with the @code{myisampack} tool.
+
+@menu
+* Static format:: Static (Fixed-length) table characteristics
+* Dynamic format:: Dynamic table characteristics
+* Compressed format:: Compressed table characteristics
+@end menu
+
+@node Static format, Dynamic format, MyISAM table formats, MyISAM table formats
+@subsubsection Static (Fixed-length) table characteristics
+
+This is the default format. It's used when the table contains no
+@code{VARCHAR}, @code{BLOB} or @code{TEXT} columns.
+
+This format is the simplest and most secure format. It is also the
+fastest of the on-disk formats. The speed comes from the easy way data
+can be found on disk. When looking up something with an index and static
+format it is very simple, just multiply the row number by the row length.
+
+Also when scanning a table it is very easy to read a constant number of
+records with each disk read.
+
+The security comes from if your computer crashes when writing to a
+fixed size MyISAM file, @code{myisamchk} can easily figure out where each
+row starts and ends. So it can usually reclaim all records except the
+partially written one. Note that in @strong{MySQL} all indexes can always be
+reconstructed.
+
+@itemize @bullet
+@item
+All @code{CHAR}, @code{NUMERIC} and @code{DECIMAL} columns are space-padded
+to the column width.
+@item
+Very quick.
+@item
+Easy to cache.
+@item
+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
+records are deleted and you want to return free disk space to the operating
+system.
+@item
+Usually requires more disk space than dynamic tables.
+@end itemize
+
+@node Dynamic format, Compressed format, Static format, MyISAM table formats
+@subsubsection Dynamic table characteristics
+
+This format is used if the table contains any @code{VARCHAR}, @code{BLOB}
+or @code{TEXT} columns or if the table was created with
+@code{ROW_FORMAT=dynamic}.
+
+This format is a litte more complex because each row has to have a header
+that says how long it is. One record can also end up at more than one
+location when it is made longer at an update.
+
+You can use @code{OPTIMIZE table} or @code{myisamchk} to defragment a
+table. If you have static data that you access/change a lot in the same
+table as some @code{VARCHAR} or @code{BLOB} columns, it might be a good
+idea to move the dynamic columns to other tables just to avoid
+fragmentation.
+
+@itemize @bullet
+@item
+All string columns are dynamic (except those with a length less than 4).
+@item
+Each record is preceded by a bitmap indicating which columns are empty
+(@code{''}) for string columns, or zero for numeric columns (this isn't
+the same as columns containing @code{NULL} values). If a string column
+has a length of zero after removal of trailing spaces, or a numeric
+column has a value of zero, it is marked in the bit map and not saved to
+disk. Non-empty strings are saved as a length byte plus the string
+contents.
+@item
+Usually takes much less disk space than fixed-length tables.
+@item
+Each record uses only as much space as is required. If a record becomes
+larger, it is split into as many pieces as required. This results in record
+fragmentation.
+@item
+If you update a row with information that extends the row length, the
+row will be fragmented. In this case, you may have to run @code{myisamchk
+-r} from time to time to get better performance. Use @code{myisamchk -ei
+tbl_name} for some statistics.
+@item
+Not as easy to reconstruct after a crash, because a record may be fragmented
+into many pieces and a link (fragment) may be missing.
+@item
+The expected row length for dynamic sized records is:
+
+@example
+3
++ (number of columns + 7) / 8
++ (number of char columns)
++ packed size of numeric columns
++ length of strings
++ (number of NULL columns + 7) / 8
+@end example
+
+There is a penalty of 6 bytes for each link. A dynamic record is linked
+whenever an update causes an enlargement of the record. Each new link will be
+at least 20 bytes, so the next enlargement will probably go in the same link.
+If not, there will be another link. You may check how many links there are
+with @code{myisamchk -ed}. All links may be removed with @code{myisamchk -r}.
+@end itemize
+
+@node Compressed format, , Dynamic format, MyISAM table formats
+@subsubsection Compressed table characteristics
+
+This is a read only type that is generated with the optional
+@code{myisampack} tool (@code{pack_isam} for @code{ISAM} tables).
+
+@itemize @bullet
+@item
+All MySQL distributions, even those that existed before @strong{MySQL}
+went GPL, can read tables that were compressed with @code{myisampack}.
+@item
+Compressed tables takes very little disk space. This minimizes disk usage which
+is very nice when using slow disks (like CD-ROMs).
+@item
+Each record is compressed separately (very little access overhead). The
+header for a record is fixed (1-3 bytes) depending on the biggest record in the
+table. Each column is compressed differently. Some of the compression types
+are:
+@itemize @minus
+@item
+There is usually a different Huffman table for each column.
+@item
+Suffix space compression.
+@item
+Prefix space compression.
+@item
+Numbers with value @code{0} are stored using 1 bit.
+@item
+If values in an integer column have a small range, the column is stored using
+the smallest possible type. For example, a @code{BIGINT} column (8 bytes) may
+be stored as a @code{TINYINT} column (1 byte) if all values are in the range
+@code{0} to @code{255}.
+@item
+If a column has only a small set of possible values, the column type is
+converted to @code{ENUM}.
+@item
+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.
+@item
+Can be uncompressed with @code{myisamchk}.
+@end itemize
+
+@node ISAM, HEAP, MyISAM, Table types
+@section ISAM tables
+
+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 file with the
+@code{.ISD} extension. You can check/repair ISAM tables with the
+@code{isamchk} utility. @xref{Crash recovery}.
+
+@code{ISAM} has the following features/properties:
+
+@itemize @bullet
+@item Compressed and fixed length keys
+@item Fixed and dynamic record length
+@item 16 keys with 16 key parts / key
+@item Max key length 256 (default)
+@item Data is stored in machine format; this is fast, but is machine/OS dependent.
+@end itemize
+
+Most of the things for @code{MyISAM} tables are also true for @code{ISAM}
+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 Can't handle tables > 4G.
+@item Only support prefix compression on strings
+@item Smaller key limits.
+@item Dynamic tables gets more fragmented.
+@item Tables are compressed with @code{pack_isam} rather than with @code{myisampack}.
+@end itemize
+
+@node HEAP, BDB, ISAM, Table types
+@section HEAP tables
+
+@code{HEAP} tables use a hashed index and are stored in memory. This
+makes them very fast, but if @strong{MySQL} crashes you will lose all
+data stored in them. @code{HEAP} is very useful for temporary tables!
+
+The @strong{MySQL} internal HEAP tables uses 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;
+mysql> SELECT COUNT(ip),AVG(down) FROM test;
+mysql> DROP TABLE test;
+@end example
+
+Here are some things you should consider when you use @code{HEAP} tables:
+
+@itemize @bullet
+@item
+You should always use specify @code{MAX_ROWS} in the @code{CREATE} statement
+to ensure that you accidently do not use all memory.
+@item
+Indexes will only be used with @code{=} and @code{<=>} (but are VERY fast).
+@item
+@code{HEAP} tables can only use whole keys to search for a row; compare this
+to @code{MyISAM} tables where any prefix of the key can be used to find rows.
+@item
+@code{HEAP} tables use a fixed record length format.
+@item
+@code{HEAP} doesn't support @code{BLOB}/@code{TEXT} columns.
+@item
+@code{HEAP} doesn't support @code{AUTO_INCREMENT} columns.
+@item
+@code{HEAP} doesn't support an index on a @code{NULL} column.
+@item
+You can have non-unique keys in a @code{HEAP} table (this isn't common for
+hashed tables).
+@item
+@code{HEAP} tables are shared between all clients (just like any other
+table).
+@item
+You can't search for the next entry in order (that is to use the index
+to do a @code{ORDER BY}).
+@item
+Data for @code{HEAP} tables are allocated in small blocks. The tables
+are 100% dynamic (on inserting). No overflow areas and no extra key
+space is needed. Deleted rows are put in a linked list and are
+reused when you insert new data into the table.
+@item
+You need enough extra memory for all HEAP tables that you want to use at
+the same time.
+@item
+To free memory, you should execute @code{DELETE FROM heap_table} or
+@code{DROP TABLE heap_table}.
+@item
+@strong{MySQL} cannot find out how approximately many rows there
+are between two values (this is used by the range optimizer to decide which
+index to use). This may affect some queries if you change a @code{MyISAM}
+table to a @code{HEAP} table.
+@item
+To ensure that you accidentally don't do anything stupid, you can't create
+@code{HEAP} tables bigger than @code{max_heap_table_size}.
+@end itemize
+
+Memory needed for one row in a @code{HEAP} table is:
+
+SUM_OVER_ALL_KEYS(max_length_of_key + sizeof(char*)*2) +
+ALIGN(length_of_row+1,sizeof(char*))
+
+@code{sizeof(char*)} is 4 on 32 bit machines and 8 on 64 bit machines.
+
+@node BDB, , HEAP, Table types
+@section BDB or Berkeley_db tables
+
+Berkeley DB (@uref{http://www.sleepycat.com}) has provided
+@strong{MySQL} with a transaction safe table handler. This will survive
+crashes and also provides @code{COMMIT} and @code{ROLLBACK} on
+transactions. In order to build MySQL 3.23.x (BDB support first appeared
+in 3.23.15) with support for @code{BDB} tables, you will need Berkeley
+DB 3.1.14 or newer which can be downloaded from
+@uref{http://www.mysql.com/downloads/mysql-3.23.html}; or also from
+Sleepycat's download page at
+@uref{http://www.sleepycat.com/download.html}.
+
+To install Berkeley DB first uncompress the @code{BDB} distribution
+and follow the instructions in the README provided in the distiribution
+directory. Basicly what you need to do is:
+@itemize @bullet
+@item
+cd build_[your_os]
+@item
+../dist/configure
+@item
+make
+@item
+make install
+@end itemize
+
+Please refer to the manual provided by @code{BDB} distribution for
+more/updated information.
+
+After this you need to configure your @strong{MySQL} with
+--with-berkeley-db=DIR The directory is the one where you installed
+@code{BDB} binaries with make install. (Usually it is
+/usr/local/BerkeleyDB.3.1/) You can give additional options to
+@strong{MySQL} configure, --with-berkeley-db-includes=DIR and
+--with-berkeley-db-libs=DIR, if the @code{BDB} includes and/or libs
+directory is not under the first directory. By default they are.
+Then complete the @strong{MySQL} installation as normal.
+
+Even if Berkeley DB is in itself very tested and reliably, the
+@strong{MySQL} interface is still very alpha, but we are actively
+improving and optimizing it to get it this stable real soon.
+
+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}.
+
+The following options to @code{mysqld} can be used to change the behavour of
+BDB tables:
+
+@multitable @columnfractions .30 .70
+@item --bdb-home= directory @tab Berkeley home direcory
+@item --bdb-lock-detect=# @tab Berkeley lock detect. One of (DEFAULT, OLDEST, RANDOM or YOUNGEST)
+@item --bdb-logdir=directory @tab Berkeley DB log file directory
+@item --bdb-nosync @tab Don't synchronously flush logs
+@item --bdb-recover @tab Start Berkeley DB in recover mode
+@item --bdb-tmpdir=directory @tab Berkeley DB tempfile name
+@item --skip-bdb @tab Don't use berkeley db.
+@end multitable
+
+If you use @code{--skip-bdb}, @strong{MySQL} will not initialize the
+Berkeley DB library and this will save a lot of memory. You can of course
+not use @code{BDB} tables if you are using this option.
+
+Normally you should start mysqld with @code{--bdb-recover} if you intend
+to use BDB tables. This may however give you problems when you try to
+start mysqld if the BDB log files are corrupted. @xref{Starting server}.
+
+Some characteristic of @code{BDB} tables:
+
+@itemize @bullet
+@item
+All @code{BDB} tables must have a primary key.
+@item
+If all columns you access in a @code{BDB} tables is part of the same index or
+part of the the primary key then @strong{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
+@code{LOCK TABLES} works on @code{BDB} tables as with other tables. If
+you don't use @code{LOCK TABLE}, @strong{MYSQL} will issue an internal
+multiple write lock on the table to ensure that the table will be
+properly locked if one another thread issues a table lock.
+@item
+@code{ALTER TABLE} doesn't yet work on @code{BDB} tables.
+@item
+Internal locking in @code{BDB} tables are done on page level.
+@item
+Scanning is slower than with @code{MyISAM} tables as one has data in BDB
+tables is stored in B-trees and not in a separate data file.
+@item
+One must in the application always be prepared to handle the case that
+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 with don't use
+@code{PACK_KEYS=0}.
+@item
+One must do a @code{FLUSH LOGS} from time to time to sync to get checkpoints
+for the @code{BDB} tables.
+@item
+As transaction logs take more place than ordinary logs it's more important
+to rotate and remove old logs when using @code{BDB} tables than using other table
+types.
+@end itemize
+
+Some things that we have to fix in the near future:
+
+@itemize @bullet
+@item
+Remove the requirement that @code{BDB} tables must have a primary key. This
+will be fixed by having an automatic hidden auto_increment column for
+the tables without a primary key.
+@item
+@code{LOCK TABLES} should work as for other @strong{MySQL} tables.
+@item
+@code{ALTER TABLE} doesn't yet work.
+@item
+@code{SHOW TABLE STATUS} doesn't yet provide that much information for BDB
+tables.
+@end itemize
+
+@node Tutorial, Server, Table types, Top
+@chapter MySQL Tutorial
+
+@menu
+* Connecting-disconnecting:: Connecting to and disconnecting from the server
+* Entering queries:: Entering queries
+* Examples:: Examples
+* Searching on two keys:: Searching on two keys
+* Database use:: Creating and using a database
+* Getting information:: Getting information about databases and tables
+* Batch mode:: Using @code{mysql} in batch mode
+* Twin:: Queries from twin project
+@end menu
+
+This chapter provides a tutorial introduction to @strong{MySQL} by showing
+how to use the @code{mysql} client program to create and use a simple
+database. @code{mysql} (sometimes referred to as the ``terminal monitor'' or
+just ``monitor'') is an interactive program that allows you to connect to a
+@strong{MySQL} server, run queries and view the results. @code{mysql} may
+also be used in batch mode: you place your queries in a file beforehand, then
+tell @code{mysql} to execute the contents of the file. Both ways of using
+@code{mysql} are covered here.
+
+To see a list of options provided by @code{mysql}, invoke it with
+the @code{--help} option:
+
+@example
+shell> mysql --help
+@end example
+
+This chapter assumes that @code{mysql} is installed on your machine, and that
+a @strong{MySQL} server is available to which you can connect. If this is
+not true, contact your @strong{MySQL} administrator. (If @emph{you} are the
+administrator, you will need to consult other sections of this manual.)
+
+The chapter describes the entire process of setting up and using a
+database. If you are interested only in accessing an already-existing
+database, you may want to skip over the sections that describe how to
+create the database and the tables it contains.
+
+Because this chapter is tutorial in nature, many details are necessarily left
+out. Consult the relevant sections of the manual for more
+information on the topics covered here.
+
+@node Connecting-disconnecting, Entering queries, Tutorial, Tutorial
+@section Connecting to and disconnecting from the server
+
+To connect to the server, you'll usually need to provide a @strong{MySQL}
+user name when you invoke @code{mysql} and, most likely, a password. If the
+server runs on a machine other than the one where you log in, you'll also
+need to specify a hostname. Contact your administrator to find out what
+connection parameters you should use to connect (i.e., what host, user name
+and password to use). Once you know the proper parameters, you should be
+able to connect like this:
+
+@example
+shell> mysql -h host -u user -p
+Enter password: ********
+@end example
+
+The @code{********} represents your password; enter it when @code{mysql}
+displays the @code{Enter password:} prompt.
+
+If that works, you should see some introductory information followed by a
+@code{mysql>} prompt:
+
+
+@example
+shell> mysql -h host -u user -p
+Enter password: ********
+Welcome to the MySQL monitor. Commands end with ; or \g.
+Your MySQL connection id is 459 to server version: 3.22.20a-log
+
+Type 'help' for help.
+
+mysql>
+@end example
+
+The prompt tells you that @code{mysql} is ready for you to enter commands.
+
+Some @strong{MySQL} installations allow users to connect as the ``anonymous''
+(unnamed) user to the server running on the local host. If this is the case
+on your machine, you should be able to connect to that server by invoking
+@code{mysql} without any options:
+
+@example
+shell> mysql
+@end example
+
+After you have connected successfully, you can disconnect any time by typing
+@code{QUIT} at the @code{mysql>} prompt:
+
+@example
+mysql> QUIT
+Bye
+@end example
+
+You can also disconnect by typing control-D.
+
+Most examples in the following sections assume you are connected to the
+server. They indicate this by the @code{mysql>} prompt.
+
+@node Entering queries, Examples, Connecting-disconnecting, Tutorial
+@section Entering queries
+
+Make sure you are connected to the server, as discussed in the previous
+section. Doing so will not in itself select any database to work with, but
+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.
+
+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:
+
+@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
+
+This query illustrates several things about @code{mysql}:
+
+@itemize @bullet
+@item
+A command normally consists of a SQL statement followed by a semicolon.
+(There are some exceptions where a semicolon is not needed. @code{QUIT},
+mentioned earlier, is one of them. We'll get to others later.)
+
+@item
+When you issue a command, @code{mysql} sends it to the server for execution
+and displays the results, then prints another @code{mysql>} to indicate
+that it is ready for another command.
+
+@item
+@code{mysql} displays query output as a table (rows and columns). The first
+row contains labels for the columns. The rows following are the query
+results. Normally, column labels are the names of the columns you fetch from
+database tables. If you're retrieving the value of an expression rather than
+a table column (as in the example just shown), @code{mysql} labels the column
+using the expression itself.
+
+@item
+@code{mysql} shows how many rows were returned, and how long the query took
+to execute, which gives you a rough idea of server performance. These values
+are imprecise because they represent wall clock time (not CPU or machine
+time), and because they are affected by factors such as server load and
+network latency. (For brevity, the ``rows in set'' line is not shown in
+the remaining examples in this chapter.)
+@end itemize
+
+Keywords may be entered in any lettercase. The following queries are
+equivalent:
+
+@example
+mysql> SELECT VERSION(), CURRENT_DATE;
+mysql> select version(), current_date;
+mysql> SeLeCt vErSiOn(), current_DATE;
+@end example
+
+Here's another query. It demonstrates that you can use @code{mysql} as a
+simple calculator:
+
+@example
+mysql> SELECT SIN(PI()/4), (4+1)*5;
++-------------+---------+
+| SIN(PI()/4) | (4+1)*5 |
++-------------+---------+
+| 0.707107 | 25 |
++-------------+---------+
+@end example
+
+The commands shown thus far have been relatively short, single-line
+statements. You can even enter multiple statements on a single line.
+Just end each one with a semicolon:
+
+@example
+mysql> SELECT VERSION(); SELECT NOW();
++--------------+
+| version() |
++--------------+
+| 3.22.20a-log |
++--------------+
+
++---------------------+
+| NOW() |
++---------------------+
+| 1999-03-19 00:15:33 |
++---------------------+
+@end example
+
+A command need not be given all on a single line, so lengthy commands that
+require several lines are not a problem. @code{mysql} determines where your
+statement ends by looking for the terminating semicolon, not by looking for
+the end of the input line. (In other words, @code{mysql}
+accepts free-format input: it collects input lines but does not execute them
+until it sees the semicolon.)
+
+Here's a simple multiple-line statement:
+
+@example
+mysql> SELECT
+ -> USER()
+ -> ,
+ -> CURRENT_DATE;
++--------------------+--------------+
+| USER() | CURRENT_DATE |
++--------------------+--------------+
+| joesmith@@localhost | 1999-03-18 |
++--------------------+--------------+
+@end example
+
+In this example, notice how the prompt changes from @code{mysql>} to
+@code{->} after you enter the first line of a multiple-line query. This is
+how @code{mysql} indicates that it hasn't seen a complete statement and is
+waiting for the rest. The prompt is your friend, because it provides
+valuable feedback. If you use that feedback, you will always be aware of
+what @code{mysql} is waiting for.
+
+If you decide you don't want to execute a command that you are in the
+process of entering, cancel it by typing @code{\c}:
+
+@example
+mysql> SELECT
+ -> USER()
+ -> \c
+mysql>
+@end example
+
+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
+they mean about the state that @code{mysql} is in:
+
+@multitable @columnfractions .10 .9
+@item @strong{Prompt} @tab @strong{Meaning}
+@item @code{mysql>} @tab Ready for new command
+@item @code{@ @ @ @ ->} @tab Waiting for next line of multiple-line command
+@item @code{@ @ @ @ '>} @tab Waiting for next line, collecting a string that begins
+with a single quote (@samp{'})
+@item @code{@ @ @ @ ">} @tab Waiting for next line, collecting a string that begins
+with a double quote (@samp{"})
+@end multitable
+
+Multiple-line statements commonly occur ``by accident'' when you intend to
+issue a command on a single line, but forget the terminating semicolon. In
+this case, @code{mysql} waits for more input:
+
+@example
+mysql> SELECT USER()
+ ->
+@end example
+
+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
+complete the statement, and @code{mysql} will execute it:
+
+@example
+mysql> SELECT USER()
+ -> ;
++--------------------+
+| USER() |
++--------------------+
+| joesmith@@localhost |
++--------------------+
+@end example
+
+The @code{'>} and @code{">} prompts occur during string collection.
+In @strong{MySQL}, you can write strings surrounded by either @samp{'}
+or @samp{"} characters (for example, @code{'hello'} or @code{"goodbye"}),
+and @code{mysql} lets you enter strings that span multiple lines. When you
+see a @code{'>} or @code{">} prompt, it means that you've entered a line
+containing a string that begins with a @samp{'} or @samp{"} quote character,
+but have not yet entered the matching quote that terminates the string.
+That's fine if you really are entering a multiple-line string, but how likely
+is that? Not very. More often, the @code{'>} and @code{">} prompts indicate
+that you've inadvertantly left out a quote character. For example:
+
+@example
+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
+result, nothing will happen. Instead of wondering, ``why does this
+query take so long?,'' notice the clue provided by the @code{">} prompt. It
+tells you that @code{mysql} expects to see the rest of an unterminated
+string. (Do you see the error in the statement? The string @code{"Smith} is
+missing the second quote.)
+
+At this point, what do you do? The simplest thing is to cancel the command.
+However, you cannot just type @code{\c} in this case, because @code{mysql}
+interprets it as part of the string that it is collecting! Instead, enter
+the closing quote character (so @code{mysql} knows you've finished the
+string), then type @code{\c}:
+
+@example
+mysql> SELECT * FROM my_table WHERE name = "Smith AND age < 30;
+ "> "\c
+mysql>
+@end example
+
+The prompt changes back to @code{mysql>}, indicating that @code{mysql}
+is ready for a new command.
+
+It's important to know what the @code{'>} and @code{">} prompts signify,
+because if you mistakenly enter an unterminated string, any further lines you
+type will appear to be ignored by @code{mysql} --- including a line
+containing @code{QUIT}! This can be quite confusing, especially if you
+don't know that you need to supply the terminating quote before you can
+cancel the current command.
+
+@node Examples, Searching on two keys, Entering queries, Tutorial
+@section Examples of common queries
+
+Here follows examples of how to solve some common problems with
+@strong{MySQL}.
+
+Some of the examples use the table @code{shop} to hold the price of each
+article (item number) for certain traders (dealers). Supposing that each
+trader has a single fixed price per article, then (@code{item},
+@code{trader}) is a primary key for the records.
+
+You can create the example table as:
+
+@example
+CREATE TABLE shop (
+ article INT(4) UNSIGNED ZEROFILL DEFAULT '0000' NOT NULL,
+ dealer CHAR(20) DEFAULT '' NOT NULL,
+ price DOUBLE(16,2) DEFAULT '0.00' NOT NULL,
+ PRIMARY KEY(article, 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
+
+Okay, so the example data is:
+
+@example
+SELECT * FROM shop
+
++---------+--------+-------+
+| article | dealer | price |
++---------+--------+-------+
+| 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:: The maximum value for a column
+* example-Maximum-row:: The row holding the maximum of a certain column
+* example-Maximum-column-group:: Maximum of column: per group: only the values
+* example-Maximum-column-group-row:: The rows holding the group-wise maximum of a certain field
+* example-Foreign keys:: Using foreign keys
+@end menu
+
+@node example-Maximum-column, example-Maximum-row, Examples, Examples
+@subsection The maximum value for a column
+
+``What's the highest item number?''
+
+@example
+SELECT MAX(article) AS article FROM shop
+
++---------+
+| article |
++---------+
+| 4 |
++---------+
+@end example
+
+@node example-Maximum-row, example-Maximum-column-group, example-Maximum-column, Examples
+@subsection The row holding the maximum of a certain column
+
+``Find number, dealer, and price of the most expensive article.''
+
+In ANSI SQL this is easily done with a sub-query:
+
+@example
+SELECT article, dealer, price
+FROM shop
+WHERE price=(SELECT MAX(price) FROM shop)
+@end example
+
+In @strong{MySQL} (which does not yet have sub-selects), just do it in
+two steps:
+
+@enumerate
+@item
+Get the maximum price value from the table with a @code{SELECT} statement.
+@item
+Using this value compile the actual query:
+@example
+SELECT article, dealer, price
+FROM shop
+WHERE price=19.95
+@end example
+@end enumerate
+
+Another solution is to sort all rows descending by price and only
+get the first row using the @strong{MySQL} specific @code{LIMIT} clause:
+
+@example
+SELECT article, dealer, price
+FROM shop
+ORDER BY price DESC
+LIMIT 1
+@end example
+
+@strong{Note}: If there are several most expensive articles (e.g. each 19.95)
+the @code{LIMIT} solution shows only one of them!
+
+@node example-Maximum-column-group, example-Maximum-column-group-row, example-Maximum-row, Examples
+@subsection Maximum of column: per group: only the values
+
+``What's the highest price per article?''
+
+@example
+SELECT article, MAX(price) AS price
+FROM shop
+GROUP BY article
+
++---------+-------+
+| article | price |
++---------+-------+
+| 0001 | 3.99 |
+| 0002 | 10.99 |
+| 0003 | 1.69 |
+| 0004 | 19.95 |
++---------+-------+
+@end example
+
+@node example-Maximum-column-group-row, example-Foreign keys, example-Maximum-column-group, Examples
+@subsection The rows holding the group-wise maximum of a certain field
+
+``For each article, find the dealer(s) with the most expensive price.''
+
+In ANSI SQL, I'd do it with a sub-query like this:
+
+@example
+SELECT article, dealer, price
+FROM shop s1
+WHERE price=(SELECT MAX(s2.price)
+ FROM shop s2
+ WHERE s1.article = s2.article)
+@end example
+
+In @strong{MySQL} it's best do it in several steps:
+
+@enumerate
+@item
+Get the list of (article,maxprice). @xref{example-Maximum-column-group-row}.
+@item
+For each article get the corresponding rows which have the stored maximum
+price.
+@end enumerate
+
+This can easily be done with a temporary table:
+
+@example
+CREATE TEMPORARY TABLE tmp (
+ article INT(4) UNSIGNED ZEROFILL DEFAULT '0000' NOT NULL,
+ price DOUBLE(16,2) DEFAULT '0.00' NOT NULL);
+
+LOCK TABLES article read;
+
+INSERT INTO tmp SELECT article, MAX(price) FROM shop GROUP BY article;
+
+SELECT article, dealer, price FROM shop, tmp
+WHERE shop.article=tmp.article AND shop.price=tmp.price;
+
+UNLOCK TABLES;
+
+DROP TABLE tmp;
+@end example
+
+If you don't use a @code{TEMPORARY} table, you must also lock the 'tmp' table.
+
+``Can it be done with a single query?''
+
+Yes, but only by using a quite inefficient trick that I call the
+``MAX-CONCAT trick'':
+
+@example
+SELECT article,
+ SUBSTRING( MAX( CONCAT(LPAD(price,6,'0'),dealer) ), 7) AS dealer,
+ 0.00+LEFT( MAX( CONCAT(LPAD(price,6,'0'),dealer) ), 6) AS price
+FROM shop
+GROUP BY article;
+
++---------+--------+-------+
+| article | dealer | price |
++---------+--------+-------+
+| 0001 | B | 3.99 |
+| 0002 | A | 10.99 |
+| 0003 | C | 1.69 |
+| 0004 | D | 19.95 |
++---------+--------+-------+
+@end example
+
+The last example can of course be made a bit more efficient by doing the
+splitting of the concatenated column in the client.
+
+@node example-Foreign keys, , example-Maximum-column-group-row, Examples
+@subsection Using foreign keys
+
+You don't need foreign keys to join 2 tables.
+
+The only thing @strong{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
+definition. If you use your keys like normal, it'll work just fine!
+
+
+@example
+CREATE TABLE persons (
+ id SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT,
+ name CHAR(60) NOT NULL,
+ PRIMARY KEY (id)
+);
+
+CREATE TABLE shirts (
+ id SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT,
+ style ENUM('t-shirt', 'polo', 'dress') NOT NULL,
+ color ENUM('red', 'blue', 'orange', 'white', 'black') NOT NULL,
+ owner SMALLINT UNSIGNED NOT NULL REFERENCES persons,
+ PRIMARY KEY (id)
+);
+
+
+INSERT INTO persons VALUES (NULL, 'Antonio Paz');
+
+INSERT INTO shirts 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 shirts 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;
++----+---------------------+
+| id | name |
++----+---------------------+
+| 1 | Antonio Paz |
+| 2 | Lilliana Angelovska |
++----+---------------------+
+
+SELECT * FROM shirts;
++----+---------+--------+-------+
+| id | style | color | owner |
++----+---------+--------+-------+
+| 1 | polo | blue | 1 |
+| 2 | dress | white | 1 |
+| 3 | t-shirt | blue | 1 |
+| 4 | dress | orange | 2 |
+| 5 | polo | red | 2 |
+| 6 | dress | blue | 2 |
+| 7 | t-shirt | white | 2 |
++----+---------+--------+-------+
+
+
+SELECT s.* FROM persons p, shirts s
+ WHERE p.name LIKE 'Lilliana%'
+ AND s.owner = p.id
+ AND s.color <> 'white';
+
++----+-------+--------+-------+
+| id | style | color | owner |
++----+-------+--------+-------+
+| 4 | dress | orange | 2 |
+| 5 | polo | red | 2 |
+| 6 | dress | blue | 2 |
++----+-------+--------+-------+
+@end example
+
+@findex UNION
+@node Searching on two keys, Database use, Examples, Tutorial
+@section Searching on two keys
+
+@strong{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):
+
+@example
+SELECT field1_index, field2_index FROM test_table WHERE field1_index = '1'
+OR field2_index = '1'
+@end example
+
+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).
+
+For the moment you can solve this very efficently by using a
+@code{TEMPORARY} table; This type of optimization is also very good if
+you are using very complicated queries where the SQL server does the
+optimizations in the wrong order.
+
+@example
+CREATE TEMPORARY TABLE tmp
+SELECT field1_index, field2_index FROM test_table WHERE field1_index = '1';
+INSERT INTO tmp
+SELECT field1_index, field2_index FROM test_table WHERE field2_index = '1';
+SELECT * from tmp;
+DROP TABLE tmp;
+@end example
+
+The above way to solve this query is in effect an @code{UNION} of two queries.
+
+@node Database use, Getting information, Searching on two keys, Tutorial
+@section Creating and using a database
+
+@menu
+* Creating database:: Creating a database
+* Creating tables:: Creating a table
+* Loading tables:: Loading data into a table
+* Retrieving data:: Retrieving information from a table
+* Multiple tables:: Using more than one table
+@end menu
+
+Now that you know how to enter commands, it's time to access a database.
+
+Suppose you have several pets in your home (your ``menagerie'') and you'd
+like to keep track of various types of information about them. You can do so
+by creating tables to hold your data and loading them with the desired
+information. Then you can answer different sorts of questions about your
+animals by retrieving data from the tables. This section shows how to do
+all that:
+
+@itemize @bullet
+@item
+How to create a database
+@item
+How to create a table
+@item
+How to load data into the table
+@item
+How to retrieve data from the table in various ways
+@item
+How to use multiple tables
+@end itemize
+
+The menagerie database will be simple (deliberately), but it is not difficult
+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.
+
+Use the @code{SHOW} statement to find out what databases currently exist
+on the server:
+
+@example
+mysql> SHOW DATABASES;
++----------+
+| Database |
++----------+
+| mysql |
+| test |
+| tmp |
++----------+
+@end example
+
+The list of databases is probably different on your machine, but the
+@code{mysql} and @code{test} databases are likely to be among them. The
+@code{mysql} database is required because it describes user access
+privileges. The @code{test} database is often provided as a workspace for
+users to try things out.
+
+If the @code{test} database exists, try to access it:
+
+@example
+mysql> USE test
+Database changed
+@end example
+
+Note that @code{USE}, like @code{QUIT}, does not require a semicolon. (You
+can terminate such statements with a semicolon if you like; it does no harm.)
+The @code{USE} statement is special in another way, too: it must be given on
+a single line.
+
+You can use the @code{test} database (if you have access to it) for the
+examples that follow, but anything you create in that database can be
+removed by anyone else with access to it. For this reason, you should
+probably ask your @strong{MySQL} administrator for permission to use a
+database of your own. Suppose you want to call yours @code{menagerie}. The
+administrator needs to execute a command like this:
+
+@example
+mysql> GRANT ALL ON menagerie.* TO your_mysql_name;
+@end example
+
+where @code{your_mysql_name} is the @strong{MySQL} user name assigned to
+you.
+
+@node Creating database, Creating tables, Database use, Database use
+@subsection Creating and selecting a database
+
+If the administrator creates your database for you when setting up your
+permissions, you can begin using it. Otherwise, you need to create it
+yourself:
+
+@example
+mysql> CREATE DATABASE menagerie;
+@end example
+
+Under Unix, database names are case sensitive (unlike SQL keywords), so you
+must always refer to your database as @code{menagerie}, not as
+@code{Menagerie}, @code{MENAGERIE} or some other variant. This is also true
+for table names. (Under Windows, this restriction does not apply, although
+you must refer to databases and tables using the same lettercase throughout a
+given query.)
+
+Creating a database does not select it for use, you must do that explicitly.
+To make @code{menagerie} the current database, use this command:
+
+@example
+mysql> USE menagerie
+Database changed
+@end example
+
+Your database needs to be created only once, but you must select it for use
+each time you begin a @code{mysql} session. You can do this by issuing a
+@code{USE} statement as shown above. Alternatively, you can select the
+database on the command line when you invoke @code{mysql}. Just specify its
+name after any connection parameters that you might need to provide. For
+example:
+
+@example
+shell> mysql -h host -u user -p menagerie
+Enter password: ********
+@end example
+
+Note that @code{menagerie} is not your password on the command just shown.
+If you want to supply your password on the command line after the @code{-p}
+option, you must do so with no intervening space (e.g., as
+@code{-pmypassword}, not as @code{-p mypassword}). However, putting your
+password on the command line is not recommended, because doing so exposes it
+to snooping by other users logged in on your machine.
+
+@node Creating tables, Loading tables, Creating database, Database use
+@subsection Creating a table
+
+Creating the database is the easy part, but at this point it's empty, as
+@code{SHOW TABLES} will tell you:
+
+@example
+mysql> SHOW TABLES;
+Empty set (0.00 sec)
+@end example
+
+The harder part is deciding what the structure of your database should be:
+what tables you will need, and what columns will be in each of them.
+
+You'll want a table that contains a record for each of your pets. This can
+be called the @code{pet} table, and it should contain, as a bare minimum,
+each animal's name. Because the name by itself is not very interesting, the
+table should contain other information. For example, if more than one person
+in your family keeps pets, you might want to list each animal's owner. You
+might also want to record some basic descriptive information such as species
+and sex.
+
+How about age? That might be of interest, but it's not a good thing to store
+in a database. Age changes as time passes, which means you'd have to update
+your records often. Instead, it's better to store a fixed value such as
+date of birth. Then, whenever you need age, you can calculate it as the
+difference between the current date and the birth date. @strong{MySQL}
+provides functions for doing date arithmetic, so this is not difficult.
+Storing birth date rather than age has other advantages, too:
+
+@itemize @bullet
+@item
+You can use the database for tasks such as generating reminders for upcoming
+pet birthdays. (If you think this type of query is somewhat silly, note that
+it is the same question you might ask in the context of a business database
+to identify clients to whom you'll soon need to send out birthday greetings,
+for that computer-assisted personal touch.)
+
+@item
+You can calculate age in relation to dates other than the current date. For
+example, if you store death date in the database, you can easily calculate
+how old a pet was when it died.
+@end itemize
+
+You can probably think of other types of information that would be useful in
+the @code{pet} table, but the ones identified so far are sufficient for now:
+name, owner, species, sex, birth and death.
+
+Use a @code{CREATE TABLE} statement to specify the layout of your table:
+
+@example
+mysql> CREATE TABLE pet (name VARCHAR(20), owner VARCHAR(20),
+ -> species VARCHAR(20), sex CHAR(1), birth DATE, death DATE);
+@end example
+
+@code{VARCHAR} is a good choice for the @code{name}, @code{owner} and
+@code{species} columns because the column values will vary in length. The
+lengths of those columns need not all be the same, and need not be
+@code{20}. You can pick any length from @code{1} to @code{255}, whatever
+seems most reasonable to you. (If you make a poor choice and it turns
+out later that you need a longer field, @strong{MySQL} provides an
+@code{ALTER TABLE} statement.)
+
+Animal sex can be represented in a variety of ways, for example, @code{"m"}
+and @code{"f"}, or perhaps @code{"male"} and @code{"female"}. It's simplest
+to use the single characters @code{"m"} and @code{"f"}.
+
+The use of the @code{DATE} data type for the @code{birth} and @code{death}
+columns is a fairly obvious choice.
+
+Now that you have created a table, @code{SHOW TABLES} should produce some
+output:
+
+@example
+mysql> SHOW TABLES;
++---------------------+
+| Tables in menagerie |
++---------------------+
+| pet |
++---------------------+
+@end example
+
+To verify that your table was created the way you expected, use
+a @code{DESCRIBE} statement:
+
+@example
+mysql> DESCRIBE pet;
++---------+-------------+------+-----+---------+-------+
+| Field | Type | Null | Key | Default | Extra |
++---------+-------------+------+-----+---------+-------+
+| name | varchar(20) | YES | | NULL | |
+| owner | varchar(20) | YES | | NULL | |
+| species | varchar(20) | YES | | NULL | |
+| sex | char(1) | YES | | NULL | |
+| birth | date | YES | | NULL | |
+| death | date | YES | | NULL | |
++---------+-------------+------+-----+---------+-------+
+@end example
+
+You can use @code{DESCRIBE} any time, for example, if you forget the names of
+the columns in your table or what types they are.
+
+@node Loading tables, Retrieving data, Creating tables, Database use
+@subsection Loading data into a table
+
+After creating your table, you need to populate it. The @code{LOAD DATA} and
+@code{INSERT} statements are useful for this.
+
+Suppose your pet records can be described as shown below.
+(Observe that @strong{MySQL} expects dates in @code{YYYY-MM-DD} format;
+this may be different than what you are used to.)
+
+@multitable @columnfractions .16 .16 .16 .16 .16 .16
+@item @strong{name} @tab @strong{owner} @tab @strong{species} @tab @strong{sex} @tab @strong{birth} @tab @strong{death}
+@item Fluffy @tab Harold @tab cat @tab f @tab 1993-02-04 @tab
+@item Claws @tab Gwen @tab cat @tab m @tab 1994-03-17 @tab
+@item Buffy @tab Harold @tab dog @tab f @tab 1989-05-13 @tab
+@item Fang @tab Benny @tab dog @tab m @tab 1990-08-27 @tab
+@item Bowser @tab Diane @tab dog @tab m @tab 1998-08-31 @tab 1995-07-29
+@item Chirpy @tab Gwen @tab bird @tab f @tab 1998-09-11 @tab
+@item Whistler @tab Gwen @tab bird @tab @tab 1997-12-09 @tab
+@item Slim @tab Benny @tab snake @tab m @tab 1996-04-29 @tab
+@end multitable
+
+Because you are beginning with an empty table, an easy way to populate it is to
+create a text file containing a row for each of your animals, then load the
+contents of the file into the table with a single statement.
+
+You could create a text file @file{pet.txt} containing one record per line,
+with values separated by tabs, and given in the order in which the columns
+were listed in the @code{CREATE TABLE} statement. For missing values (such
+as unknown sexes, or death dates for animals that are still living), you can
+use @code{NULL} values. To represent these in your text file, use
+@code{\N}. For example, the record for Whistler the bird would look like
+this (where the whitespace between values is a single tab character):
+
+@multitable @columnfractions .15 .15 .15 .15 .25 .15
+@item @code{Whistler} @tab @code{Gwen} @tab @code{bird} @tab @code{\N} @tab @code{1997-12-09} @tab @code{\N}
+@end multitable
+
+To load the text file @file{pet.txt} into the @code{pet} table, use this
+command:
+
+@example
+mysql> LOAD DATA LOCAL INFILE "pet.txt" INTO TABLE pet;
+@end example
+
+You can specify the column value separator and end of line marker explicitly
+in the @code{LOAD DATA} statement if you wish, but the defaults are tab and
+linefeed. These are sufficient for the statement to read the file
+@file{pet.txt} properly.
+
+When you want to add new records one at a time, the @code{INSERT} statement
+is useful. In its simplest form, you supply values for each column, in the
+order in which the columns were listed in the @code{CREATE TABLE} statement.
+Suppose Diane gets a new hamster named Puffball. You could add a new record
+using an @code{INSERT} statement like this:
+
+@example
+mysql> INSERT INTO pet
+ -> VALUES ('Puffball','Diane','hamster','f','1999-03-30',NULL);
+@end example
+
+Note that string and date values are specified as quoted strings here. Also,
+with @code{INSERT}, you can insert @code{NULL} directly to represent a
+missing value. You do not use @code{\N} like you do with @code{LOAD DATA}.
+
+From this example, you should be able to see that there would be a lot more
+typing involved to load
+your records initially using several @code{INSERT} statements rather
+than a single @code{LOAD DATA} statement.
+
+@node Retrieving data, Multiple tables, Loading tables, Database use
+@subsection Retrieving information from a table
+
+@menu
+* Selecting all:: Selecting all data
+* Selecting rows:: Selecting particular rows
+* Selecting columns:: Selecting particular columns
+* Sorting rows:: Sorting rows
+* Date calculations:: Date calculations
+* Working with NULL:: Working with @code{NULL} values
+* Pattern matching:: Pattern matching
+* Counting rows:: Counting rows
+@end menu
+
+The @code{SELECT} statement is used to pull information from a table.
+The general form of the statement is:
+
+@example
+SELECT what_to_select
+FROM which_table
+WHERE conditions_to_satisfy
+@end example
+
+@code{what_to_select} indicates what you want to see. This can be a list of
+columns, or @code{*} to indicate ``all columns.'' @code{which_table}
+indicates the table from which you want to retrieve data. The @code{WHERE}
+clause is optional. If it's present, @code{conditions_to_satisfy} specifies
+conditions that rows must satisfy to qualify for retrieval.
+
+@node Selecting all, Selecting rows, Retrieving data, Retrieving data
+@subsubsection Selecting all data
+
+The simplest form of @code{SELECT} retrieves everything from a table:
+
+@example
+mysql> SELECT * FROM pet;
++----------+--------+---------+------+------------+------------+
+| name | owner | species | sex | birth | death |
++----------+--------+---------+------+------------+------------+
+| Fluffy | Harold | cat | f | 1993-02-04 | NULL |
+| Claws | Gwen | cat | m | 1994-03-17 | NULL |
+| Buffy | Harold | dog | f | 1989-05-13 | NULL |
+| Fang | Benny | dog | m | 1990-08-27 | NULL |
+| Bowser | Diane | dog | m | 1998-08-31 | 1995-07-29 |
+| Chirpy | Gwen | bird | f | 1998-09-11 | NULL |
+| Whistler | Gwen | bird | NULL | 1997-12-09 | NULL |
+| Slim | Benny | snake | m | 1996-04-29 | NULL |
+| Puffball | Diane | hamster | f | 1999-03-30 | NULL |
++----------+--------+---------+------+------------+------------+
+@end example
+
+This form of @code{SELECT} is useful if you want to review your entire table,
+for instance, after you've just loaded it with your initial dataset. As it
+happens, the output just shown reveals an error in your data file: Bowser
+appears to have been born after he died! Consulting your original pedigree
+papers, you find that the correct birth year is 1989, not 1998.
+
+There are are least a couple of ways to fix this:
+
+@itemize @bullet
+@item
+Edit the file @file{pet.txt} to correct the error, then empty the table
+and reload it using @code{DELETE} and @code{LOAD DATA}:
+
+@example
+mysql> SET AUTOCOMMIT=1; # Used for quick recreate of the table
+mysql> DELETE FROM pet;
+mysql> LOAD DATA LOCAL INFILE "pet.txt" INTO TABLE pet;
+@end example
+
+However, if you do this, you must also re-enter the record for Puffball.
+
+@item
+Fix only the erroneous record with an @code{UPDATE} statement:
+
+@example
+mysql> UPDATE pet SET birth = "1989-08-31" WHERE name = "Bowser";
+@end example
+@end itemize
+
+As shown above, it is easy to retrieve an entire table. But typically you
+don't want to do that, particularly when the table becomes large. Instead,
+you're usually more interested in answering a particular question, in which
+case you specify some constraints on the information you want. Let's look at
+some selection queries in terms of questions about your pets that they
+answer.
+
+@node Selecting rows, Selecting columns, Selecting all, Retrieving data
+@subsubsection Selecting particular rows
+
+You can select only particular rows from your table. For example, if you want
+to verify the change that you made to Bowser's birth date, select Bowser's
+record like this:
+
+@example
+mysql> SELECT * FROM pet WHERE name = "Bowser";
++--------+-------+---------+------+------------+------------+
+| name | owner | species | sex | birth | death |
++--------+-------+---------+------+------------+------------+
+| Bowser | Diane | dog | m | 1989-08-31 | 1995-07-29 |
++--------+-------+---------+------+------------+------------+
+@end example
+
+The output confirms that the year is correctly recorded now as 1989, not 1998.
+
+String comparisons are normally case-insensitive, so you can specify the
+name as @code{"bowser"}, @code{"BOWSER"}, etc. The query result will be
+the same.
+
+You can specify conditions on any column, not just @code{name}. For example,
+if you want to know which animals were born after 1998, test the @code{birth}
+column:
+
+@example
+mysql> SELECT * FROM pet WHERE birth >= "1998-1-1";
++----------+-------+---------+------+------------+-------+
+| name | owner | species | sex | birth | death |
++----------+-------+---------+------+------------+-------+
+| Chirpy | Gwen | bird | f | 1998-09-11 | NULL |
+| Puffball | Diane | hamster | f | 1999-03-30 | NULL |
++----------+-------+---------+------+------------+-------+
+@end example
+
+You can combine conditions, for example, to locate female dogs:
+
+@example
+mysql> SELECT * FROM pet WHERE species = "dog" AND sex = "f";
++-------+--------+---------+------+------------+-------+
+| name | owner | species | sex | birth | death |
++-------+--------+---------+------+------------+-------+
+| Buffy | Harold | dog | f | 1989-05-13 | NULL |
++-------+--------+---------+------+------------+-------+
+@end example
+
+The preceding query uses the @code{AND} logical operator. There is also an
+@code{OR} operator:
+
+@example
+mysql> SELECT * FROM pet WHERE species = "snake" OR species = "bird";
++----------+-------+---------+------+------------+-------+
+| name | owner | species | sex | birth | death |
++----------+-------+---------+------+------------+-------+
+| Chirpy | Gwen | bird | f | 1998-09-11 | NULL |
+| Whistler | Gwen | bird | NULL | 1997-12-09 | NULL |
+| Slim | Benny | snake | m | 1996-04-29 | NULL |
++----------+-------+---------+------+------------+-------+
+@end example
+
+@code{AND} and @code{OR} may be intermixed. If you do that, it's a good idea
+to use parentheses to indicate how conditions should be grouped:
+
+@example
+mysql> SELECT * FROM pet WHERE (species = "cat" AND sex = "m")
+ -> OR (species = "dog" AND sex = "f");
++-------+--------+---------+------+------------+-------+
+| name | owner | species | sex | birth | death |
++-------+--------+---------+------+------------+-------+
+| Claws | Gwen | cat | m | 1994-03-17 | NULL |
+| Buffy | Harold | dog | f | 1989-05-13 | NULL |
++-------+--------+---------+------+------------+-------+
+@end example
+
+@node Selecting columns, Sorting rows, Selecting rows, Retrieving data
+@subsubsection Selecting particular columns
+
+
+If you don't want to see entire rows from your table, just name the columns
+in which you're interested, separated by commas. For example, if you want to
+know when your animals were born, select the @code{name} and @code{birth}
+columns:
+
+@example
+mysql> SELECT name, birth FROM pet;
++----------+------------+
+| name | birth |
++----------+------------+
+| 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
+
+To find out who owns pets, use this query:
+
+@example
+mysql> SELECT owner FROM pet;
++--------+
+| owner |
++--------+
+| Harold |
+| Gwen |
+| Harold |
+| Benny |
+| Diane |
+| Gwen |
+| Gwen |
+| Benny |
+| Diane |
++--------+
+@end example
+
+@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,
+retrieve each unique output record just once by adding the keyword
+@code{DISTINCT}:
+
+@example
+mysql> SELECT DISTINCT owner FROM pet;
++--------+
+| owner |
++--------+
+| Benny |
+| Diane |
+| Gwen |
+| Harold |
++--------+
+@end example
+
+You can use a @code{WHERE} clause to combine row selection with column
+selection. For example, to get birth dates for dogs and cats only,
+use this query:
+
+@example
+mysql> SELECT name, species, birth FROM pet
+ -> WHERE species = "dog" OR species = "cat";
++--------+---------+------------+
+| name | species | birth |
++--------+---------+------------+
+| Fluffy | cat | 1993-02-04 |
+| Claws | cat | 1994-03-17 |
+| Buffy | dog | 1989-05-13 |
+| Fang | dog | 1990-08-27 |
+| Bowser | dog | 1989-08-31 |
++--------+---------+------------+
+@end example
+
+@node Sorting rows, Date calculations, Selecting columns, Retrieving data
+@subsubsection Sorting rows
+
+You may have noticed in the preceding examples that the result rows are
+displayed in no particular order. However, it's often easier to examine
+query output when the rows are sorted in some meaningful way. To sort a
+result, use an @code{ORDER BY} clause.
+
+Here are animal birthdays, sorted by date:
+
+@example
+mysql> SELECT name, birth FROM pet ORDER BY birth;
++----------+------------+
+| name | birth |
++----------+------------+
+| 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
+
+To sort in reverse order, add the @code{DESC} (descending) keyword to the
+name of the column you are sorting by:
+
+@example
+mysql> SELECT name, birth FROM pet ORDER BY birth DESC;
++----------+------------+
+| name | birth |
++----------+------------+
+| 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
+
+You can sort on multiple columns. For example, to sort by type of
+animal, then by birth date within animal type with youngest animals first,
+use the following query:
+
+@example
+mysql> SELECT name, species, birth FROM pet ORDER BY species, birth DESC;
++----------+---------+------------+
+| name | species | birth |
++----------+---------+------------+
+| Chirpy | bird | 1998-09-11 |
+| Whistler | bird | 1997-12-09 |
+| Claws | cat | 1994-03-17 |
+| Fluffy | cat | 1993-02-04 |
+| Fang | dog | 1990-08-27 |
+| Bowser | dog | 1989-08-31 |
+| Buffy | dog | 1989-05-13 |
+| Puffball | hamster | 1999-03-30 |
+| Slim | snake | 1996-04-29 |
++----------+---------+------------+
+@end example
+
+Note that the @code{DESC} keyword applies only to the column name immediately
+preceding it (@code{birth}); @code{species} values are still sorted in
+ascending order.
+
+@node Date calculations, Working with NULL, Sorting rows, Retrieving data
+@subsubsection Date calculations
+
+@strong{MySQL} provides several functions that you can use to perform
+calculations on dates, for example, to calculate ages or extract
+parts of dates.
+
+To determine how many years old each of your pets is, compute age as the
+difference between the birth date and the current date. Do this by
+converting the two dates to days, take the difference, and divide by 365 (the
+number of days in a year):
+
+@example
+mysql> SELECT name, (TO_DAYS(NOW())-TO_DAYS(birth))/365 FROM pet;
++----------+-------------------------------------+
+| name | (TO_DAYS(NOW())-TO_DAYS(birth))/365 |
++----------+-------------------------------------+
+| Fluffy | 6.15 |
+| Claws | 5.04 |
+| Buffy | 9.88 |
+| Fang | 8.59 |
+| Bowser | 9.58 |
+| Chirpy | 0.55 |
+| Whistler | 1.30 |
+| Slim | 2.92 |
+| Puffball | 0.00 |
++----------+-------------------------------------+
+@end example
+
+Although the query works, there are some things about it that could be
+improved. First, the result could be scanned more easily if the rows were
+presented in some order. Second, the heading for the age column isn't very
+meaningful.
+
+The first problem can be handled by adding an @code{ORDER BY name} clause to
+sort the output by name. To deal with the column heading, provide a name for
+the column so that a different label appears in the output (this is called a
+column alias):
+
+@example
+mysql> SELECT name, (TO_DAYS(NOW())-TO_DAYS(birth))/365 AS age
+ -> FROM pet ORDER BY name;
++----------+------+
+| name | age |
++----------+------+
+| Bowser | 9.58 |
+| Buffy | 9.88 |
+| Chirpy | 0.55 |
+| Claws | 5.04 |
+| Fang | 8.59 |
+| Fluffy | 6.15 |
+| Puffball | 0.00 |
+| Slim | 2.92 |
+| Whistler | 1.30 |
++----------+------+
+@end example
+
+To sort the output by @code{age} rather than @code{name}, just use a
+different @code{ORDER BY} clause:
+
+@example
+mysql> SELECT name, (TO_DAYS(NOW())-TO_DAYS(birth))/365 AS age
+ -> FROM pet ORDER BY age;
++----------+------+
+| name | age |
++----------+------+
+| Puffball | 0.00 |
+| Chirpy | 0.55 |
+| Whistler | 1.30 |
+| Slim | 2.92 |
+| Claws | 5.04 |
+| Fluffy | 6.15 |
+| Fang | 8.59 |
+| Bowser | 9.58 |
+| Buffy | 9.88 |
++----------+------+
+@end example
+
+A similar query can be used to determine age at death for animals that have
+died. You determine which animals these are by checking whether or not the
+@code{death} value is @code{NULL}. Then, for those with non-@code{NULL}
+values, compute the difference between the @code{death} and @code{birth}
+values:
+
+@example
+mysql> SELECT name, birth, death, (TO_DAYS(death)-TO_DAYS(birth))/365 AS age
+ -> FROM pet WHERE death IS NOT NULL ORDER BY age;
++--------+------------+------------+------+
+| name | birth | death | age |
++--------+------------+------------+------+
+| Bowser | 1989-08-31 | 1995-07-29 | 5.91 |
++--------+------------+------------+------+
+@end example
+
+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}}.
+
+What if you want to know which animals have birthdays next month? For this
+type of calculation, year and day are irrelevant, you simply want to extract
+the month part of the @code{birth} column. @strong{MySQL} provides several
+date-part extraction functions, such as @code{YEAR()}, @code{MONTH()} and
+@code{DAYOFMONTH()}. @code{MONTH()} is the appropriate function here. To
+see how it works, run a simple query that displays the value of both
+@code{birth} and @code{MONTH(birth)}:
+
+@example
+mysql> SELECT name, birth, MONTH(birth) FROM pet;
++----------+------------+--------------+
+| name | birth | MONTH(birth) |
++----------+------------+--------------+
+| 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
+
+Finding animals with birthdays in the upcoming month is easy, too. Suppose
+the current month is April. Then the month value is @code{4} and you look
+for animals born in May (month 5) like this:
+
+@example
+mysql> SELECT name, birth FROM pet WHERE MONTH(birth) = 5;
++-------+------------+
+| name | birth |
++-------+------------+
+| Buffy | 1989-05-13 |
++-------+------------+
+@end example
+
+There is a small complication if the current month is December, of course.
+You don't just add one to the month number (@code{12}) and look for animals
+born in month 13, because there is no such month. Instead, you look for
+animals born in January (month 1).
+
+You can even write the query so that it works no matter what the current
+month is. That way you don't have to use a particular month number
+in the query. @code{DATE_ADD()} allows you to add a time interval to a
+given date. If you add a month to the value of @code{NOW()}, then extract
+the month part with @code{MONTH()}, the result produces the month in which to
+look for birthdays:
+
+@example
+mysql> SELECT name, birth FROM pet
+ -> WHERE MONTH(birth) = MONTH(DATE_ADD(NOW(), INTERVAL 1 MONTH));
+@end example
+
+A different way to accomplish the same task is to add @code{1} to get the
+next month after the current one (after using the modulo function (@code{MOD})
+to ``wrap around'' the month value to @code{0} if it is currently
+@code{12}):
+
+@example
+mysql> SELECT name, birth FROM pet
+ -> WHERE MONTH(birth) = MOD(MONTH(NOW()), 12) + 1;
+@end example
+
+Note that @code{MONTH} return a number between 1 and 12. And
+@code{MOD(something,12)} returns a number between 0 and 11. So the
+addition has to be after the @code{MOD()} oterwise we would go from
+November (11) to January (1).
+
+@node Working with NULL, Pattern matching, Date calculations, Retrieving data
+@subsubsection Working with @code{NULL} values
+
+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:
+
+@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
+
+Clearly you get no meaningful results from these comparisons. Use
+the @code{IS NULL} and @code{IS NOT NULL} operators instead:
+
+@example
+mysql> SELECT 1 IS NULL, 1 IS NOT NULL;
++-----------+---------------+
+| 1 IS NULL | 1 IS NOT NULL |
++-----------+---------------+
+| 0 | 1 |
++-----------+---------------+
+@end example
+
+In @strong{MySQL}, 0 means false and 1 means true.
+
+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}.
+
+@node Pattern matching, Counting rows, Working with NULL, Retrieving data
+@subsubsection Pattern matching
+
+@strong{MySQL} provides standard SQL pattern matching as well as a form of
+pattern matching based on extended regular expressions similar to those used
+by Unix utilities such as @code{vi}, @code{grep} and @code{sed}.
+
+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 @strong{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
+LIKE} comparison operators instead.
+
+To find names beginning with @samp{b}:
+
+@example
+mysql> SELECT * FROM pet WHERE name LIKE "b%";
++--------+--------+---------+------+------------+------------+
+| name | owner | species | sex | birth | death |
++--------+--------+---------+------+------------+------------+
+| Buffy | Harold | dog | f | 1989-05-13 | NULL |
+| Bowser | Diane | dog | m | 1989-08-31 | 1995-07-29 |
++--------+--------+---------+------+------------+------------+
+@end example
+
+To find names ending with @samp{fy}:
+
+@example
+mysql> SELECT * FROM pet WHERE name LIKE "%fy";
++--------+--------+---------+------+------------+-------+
+| name | owner | species | sex | birth | death |
++--------+--------+---------+------+------------+-------+
+| Fluffy | Harold | cat | f | 1993-02-04 | NULL |
+| Buffy | Harold | dog | f | 1989-05-13 | NULL |
++--------+--------+---------+------+------------+-------+
+@end example
+
+To find names containing a @samp{w}:
+
+@example
+mysql> SELECT * FROM pet WHERE name LIKE "%w%";
++----------+-------+---------+------+------------+------------+
+| name | owner | species | sex | birth | death |
++----------+-------+---------+------+------------+------------+
+| Claws | Gwen | cat | m | 1994-03-17 | NULL |
+| Bowser | Diane | dog | m | 1989-08-31 | 1995-07-29 |
+| Whistler | Gwen | bird | NULL | 1997-12-09 | NULL |
++----------+-------+---------+------+------------+------------+
+@end example
+
+To find names containing exactly five characters, use the @samp{_} pattern
+character:
+
+@example
+mysql> SELECT * FROM pet WHERE name LIKE "_____";
++-------+--------+---------+------+------------+-------+
+| name | owner | species | sex | birth | death |
++-------+--------+---------+------+------------+-------+
+| Claws | Gwen | cat | m | 1994-03-17 | NULL |
+| Buffy | Harold | dog | f | 1989-05-13 | NULL |
++-------+--------+---------+------+------------+-------+
+@end example
+
+The other type of pattern matching provided by @strong{MySQL} uses extended
+regular expressions. When you test for a match for this type of pattern, use
+the @code{REGEXP} and @code{NOT REGEXP} operators (or @code{RLIKE} and
+@code{NOT RLIKE}, which are synonyms).
+
+Some characteristics of extended regular expressions are:
+
+@itemize @bullet
+@item
+@samp{.} matches any single character.
+
+@item
+A character class @samp{[...]} matches any character within the brackets.
+For example, @samp{[abc]} matches @samp{a}, @samp{b} or @samp{c}. To name a
+range of characters, use a dash. @samp{[a-z]} matches any lowercase letter,
+whereas @samp{[0-9]} matches any digit.
+
+@item
+@samp{*} matches zero or more instances of the thing preceding it. For
+example, @samp{x*} matches any number of @samp{x} characters,
+@samp{[0-9]*} matches any number of digits, and @samp{.*} matches any
+number of anything.
+
+@item
+Regular expressions are case sensitive, but you can use a character class to
+match both lettercases if you wish. For example, @samp{[aA]} matches
+lowercase or uppercase @samp{a} and @samp{[a-zA-Z]} matches any letter in
+either case.
+
+@item
+The pattern matches if it occurs anywhere in the value being tested
+(SQL patterns match only if they match the entire value).
+
+@item
+To anchor a pattern so that it must match the beginning or end of the value
+being tested, use @samp{^} at the beginning or @samp{$} at the end of the
+pattern.
+@end itemize
+
+To demonstrate how extended regular expressions work, the @code{LIKE} queries
+shown above are rewritten below to use @code{REGEXP}:
+
+To find names beginning with @samp{b}, use @samp{^} to match the beginning of
+the name and @samp{[bB]} to match either lowercase or uppercase @samp{b}:
+
+@example
+mysql> SELECT * FROM pet WHERE name REGEXP "^[bB]";
++--------+--------+---------+------+------------+------------+
+| name | owner | species | sex | birth | death |
++--------+--------+---------+------+------------+------------+
+| Buffy | Harold | dog | f | 1989-05-13 | NULL |
+| Bowser | Diane | dog | m | 1989-08-31 | 1995-07-29 |
++--------+--------+---------+------+------------+------------+
+@end example
+
+To find names ending with @samp{fy}, use @samp{$} to match the end of the
+name:
+
+@example
+mysql> SELECT * FROM pet WHERE name REGEXP "fy$";
++--------+--------+---------+------+------------+-------+
+| name | owner | species | sex | birth | death |
++--------+--------+---------+------+------------+-------+
+| Fluffy | Harold | cat | f | 1993-02-04 | NULL |
+| Buffy | Harold | dog | f | 1989-05-13 | NULL |
++--------+--------+---------+------+------------+-------+
+@end example
+
+To find names containing a @samp{w}, use
+@samp{[wW]} to match either lowercase or uppercase @samp{w}:
+
+@example
+mysql> SELECT * FROM pet WHERE name REGEXP "[wW]";
++----------+-------+---------+------+------------+------------+
+| name | owner | species | sex | birth | death |
++----------+-------+---------+------+------------+------------+
+| Claws | Gwen | cat | m | 1994-03-17 | NULL |
+| Bowser | Diane | dog | m | 1989-08-31 | 1995-07-29 |
+| Whistler | Gwen | bird | NULL | 1997-12-09 | NULL |
++----------+-------+---------+------+------------+------------+
+@end example
+
+Because a regular expression pattern matches if it occurs anywhere in the
+value, it is not necessary in the previous query to put a wildcard on either
+side of the pattern to get it to match the entire value like it would be if
+you used a SQL pattern.
+
+To find names containing exactly five characters, use @samp{^} and @samp{$}
+to match the beginning and end of the name, and five instances of @samp{.}
+in between:
+
+@example
+mysql> SELECT * FROM pet WHERE name REGEXP "^.....$";
++-------+--------+---------+------+------------+-------+
+| name | owner | species | sex | birth | death |
++-------+--------+---------+------+------------+-------+
+| Claws | Gwen | cat | m | 1994-03-17 | NULL |
+| Buffy | Harold | dog | f | 1989-05-13 | NULL |
++-------+--------+---------+------+------------+-------+
+@end example
+
+You could also write the previous query using the @samp{@{n@}}
+``repeat-@code{n}-times'' operator:
+
+@example
+mysql> SELECT * FROM pet WHERE name REGEXP "^.@{5@}$";
++-------+--------+---------+------+------------+-------+
+| name | owner | species | sex | birth | death |
++-------+--------+---------+------+------------+-------+
+| Claws | Gwen | cat | m | 1994-03-17 | NULL |
+| Buffy | Harold | dog | f | 1989-05-13 | NULL |
++-------+--------+---------+------+------------+-------+
+@end example
+
+@node Counting rows, , Pattern matching, Retrieving data
+@subsubsection Counting rows
+
+Databases are often used to answer the question, ``How often does a certain
+type of data occur in a table?'' For example, you might want to know how
+many pets you have, or how many pets each owner has, or you might want to
+perform various kinds of censuses on your animals.
+
+Counting the total number of animals you have is the same question as ``How
+many rows are in the @code{pet} table?,'' because there is one record per pet.
+The @code{COUNT()} function counts the number of non-@code{NULL} results, so
+the query to count your animals looks like this:
+
+@example
+mysql> SELECT COUNT(*) FROM pet;
++----------+
+| COUNT(*) |
++----------+
+| 9 |
++----------+
+@end example
+
+Earlier, you retrieved the names of the people who owned pets. You can
+use @code{COUNT()} if you want to find out how many pets each owner has:
+
+@example
+mysql> SELECT owner, COUNT(*) FROM pet GROUP BY owner;
++--------+----------+
+| owner | COUNT(*) |
++--------+----------+
+| Benny | 2 |
+| Diane | 2 |
+| Gwen | 3 |
+| Harold | 2 |
++--------+----------+
+@end example
+
+Note the use of @code{GROUP BY} to group together all records for each
+@code{owner}. Without it, all you get is an error message:
+
+@example
+mysql> SELECT owner, COUNT(owner) 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()} and @code{GROUP BY} are useful for characterizing your
+data in various ways. The following examples show different ways to
+perform animal census operations.
+
+Number of animals per species:
+
+@example
+mysql> SELECT species, COUNT(*) FROM pet GROUP BY species;
++---------+----------+
+| species | COUNT(*) |
++---------+----------+
+| bird | 2 |
+| cat | 2 |
+| dog | 3 |
+| hamster | 1 |
+| snake | 1 |
++---------+----------+
+@end example
+
+Number of animals per sex:
+
+@example
+mysql> SELECT sex, COUNT(*) FROM pet GROUP BY sex;
++------+----------+
+| sex | COUNT(*) |
++------+----------+
+| NULL | 1 |
+| f | 4 |
+| m | 4 |
++------+----------+
+@end example
+
+(In this output, @code{NULL} indicates ``sex unknown.'')
+
+Number of animals per combination of species and sex:
+
+@example
+mysql> SELECT species, sex, COUNT(*) FROM pet GROUP BY species, sex;
++---------+------+----------+
+| species | sex | COUNT(*) |
++---------+------+----------+
+| bird | NULL | 1 |
+| bird | f | 1 |
+| cat | f | 1 |
+| cat | m | 1 |
+| dog | f | 1 |
+| dog | m | 2 |
+| hamster | f | 1 |
+| snake | m | 1 |
++---------+------+----------+
+@end example
+
+You need not retrieve an entire table when you use @code{COUNT()}. For
+example, the previous query, when performed just on dogs and cats, looks like
+this:
+
+@example
+mysql> SELECT species, sex, COUNT(*) FROM pet
+ -> WHERE species = "dog" OR species = "cat"
+ -> GROUP BY species, sex;
++---------+------+----------+
+| species | sex | COUNT(*) |
++---------+------+----------+
+| cat | f | 1 |
+| cat | m | 1 |
+| dog | f | 1 |
+| dog | m | 2 |
++---------+------+----------+
+@end example
+
+Or, if you wanted the number of animals per sex only for known-sex animals:
+
+@example
+mysql> SELECT species, sex, COUNT(*) FROM pet
+ -> WHERE sex IS NOT NULL
+ -> GROUP BY species, sex;
++---------+------+----------+
+| species | sex | COUNT(*) |
++---------+------+----------+
+| bird | f | 1 |
+| cat | f | 1 |
+| cat | m | 1 |
+| dog | f | 1 |
+| dog | m | 2 |
+| hamster | f | 1 |
+| snake | m | 1 |
++---------+------+----------+
+@end example
+
+@node Multiple tables, , Retrieving data, Database use
+@subsection Using more than one table
+
+The @code{pet} table keeps track of which pets you have. If you want to
+record other information about them, such as events in their lives like
+visits to the vet or when litters are born, you need another table. What
+should this table look like?
+
+@itemize @bullet
+@item
+It needs to contain the pet name so you know which animal each event pertains
+to.
+
+@item
+It needs a date so you know when the event occurred.
+
+@item
+It needs a field to describe the event.
+
+@item
+If you want to be able to categorize events, it would be useful to have an
+event type field.
+@end itemize
+
+Given these considerations, the @code{CREATE TABLE} statement for the
+@code{event} table might look like this:
+
+@example
+mysql> CREATE TABLE event (name VARCHAR(20), date DATE,
+ -> type VARCHAR(15), remark VARCHAR(255));
+@end example
+
+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 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 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
+@end multitable
+
+Load the records like this:
+
+@example
+mysql> LOAD DATA LOCAL INFILE "event.txt" INTO TABLE event;
+@end example
+
+Based on what you've learned from the queries you've run on the @code{pet}
+table, you should be able to perform retrievals on the records in the
+@code{event} table; the principles are the same. But when is the
+@code{event} table by itself insufficient to answer questions you might ask?
+
+Suppose you want to find out the ages of each pet when they had their
+litters. The @code{event} table indicates when this occurred, but to
+calculate 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
+ -> FROM pet, event
+ -> WHERE pet.name = event.name AND type = "litter";
++--------+------+-----------------------------+
+| name | age | remark |
++--------+------+-----------------------------+
+| Fluffy | 2.27 | 4 kittens, 3 female, 1 male |
+| Buffy | 4.12 | 5 puppies, 2 female, 3 male |
+| Buffy | 5.10 | 3 puppies, 3 female |
++--------+------+-----------------------------+
+@end example
+
+There are several things to note about this query:
+
+@itemize @bullet
+@item
+The @code{FROM} clause lists two tables because the query needs to pull
+information from both of them.
+
+@item
+When combining (joining) information from multiple tables, you need to
+specify how records in one table can be matched to records in the other.
+This is easy because they both have a @code{name} column. The query uses
+@code{WHERE} clause to match up records in the two tables based on the
+@code{name} values.
+
+@item
+Because the @code{name} column occurs in both tables, you must be specific
+about which table you mean when referring to the column. This is done
+by prepending the table name to the column name.
+@end itemize
+
+You need not have two different tables to perform a join. Sometimes it is
+useful to join a table to itself, if you want to compare records in a table
+to other records in that same table. For example, to find breeding pairs
+among your pets, you can join the @code{pet} table with itself to pair up
+males and females of like species:
+
+@example
+mysql> SELECT p1.name, p1.sex, p2.name, p2.sex, p1.species
+ -> FROM pet AS p1, pet AS p2
+ -> WHERE p1.species = p2.species AND p1.sex = "f" AND p2.sex = "m";
++--------+------+--------+------+---------+
+| name | sex | name | sex | species |
++--------+------+--------+------+---------+
+| Fluffy | f | Claws | m | cat |
+| Buffy | f | Fang | m | dog |
+| Buffy | f | Bowser | m | dog |
++--------+------+--------+------+---------+
+@end example
+
+In this query, we specify aliases for the table name in order to be able
+to refer to the columns and keep straight which instance of the table
+each column reference is associated with.
+
+@node Getting information, Batch mode, Database use, Tutorial
+@section Getting information about databases and tables
+
+What if you forget the name of a database or table, or what the structure of
+a given table is (e.g., what its columns are called)? @strong{MySQL}
+addresses this problem through several statements that provide information
+about the databases and tables it supports.
+
+You have already seen @code{SHOW DATABASES}, which lists the databases
+managed by the server. To find out which database is currently selected,
+use the @code{DATABASE()} function:
+
+@example
+mysql> SELECT DATABASE();
++------------+
+| DATABASE() |
++------------+
+| menagerie |
++------------+
+@end example
+
+If you haven't selected any database yet, the result is blank.
+
+To find out what tables the current database contains (for example, when
+you're not sure about the name of a table), use this command:
+
+@example
+mysql> SHOW TABLES;
++---------------------+
+| Tables in menagerie |
++---------------------+
+| event |
+| pet |
++---------------------+
+@end example
+
+If you want to find out about the structure of a table, the @code{DESCRIBE}
+command is useful; it displays information about each of a table's columns:
+
+@example
+mysql> DESCRIBE pet;
++---------+-------------+------+-----+---------+-------+
+| Field | Type | Null | Key | Default | Extra |
++---------+-------------+------+-----+---------+-------+
+| name | varchar(20) | YES | | NULL | |
+| owner | varchar(20) | YES | | NULL | |
+| species | varchar(20) | YES | | NULL | |
+| sex | char(1) | YES | | NULL | |
+| birth | date | YES | | NULL | |
+| death | date | YES | | NULL | |
++---------+-------------+------+-----+---------+-------+
+@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
+@code{NULL} values, @code{Key} indicates whether or not the column is
+indexed and @code{Default} specifies the column's default value.
+
+If you have indexes on a table,
+@code{SHOW INDEX FROM tbl_name} produces information about them.
+
+@node Batch mode, Twin, Getting information, Tutorial
+@section Using @code{mysql} in batch mode
+
+In the previous sections, you used @code{mysql} interactively to enter
+queries and view the results. You can also run @code{mysql} in batch
+mode. To do this, put the commands you want to run in a file, then
+tell @code{mysql} to read its input from the file:
+
+@example
+shell> mysql < batch-file
+@end example
+
+If you need to specify connection parameters on the command line, the
+command might look like this:
+
+@example
+shell> mysql -h host -u user -p < batch-file
+Enter password: ********
+@end example
+
+When you use @code{mysql} this way, you are creating a script file, then
+executing the script.
+
+Why use a script? Here are a few reasons:
+
+@itemize @bullet
+@item
+If you run a query repeatedly (say, every day or every week), making it a
+script allows you to avoid retyping it each time you execute it.
+
+@item
+You can generate new queries from existing ones that are similar by copying
+and editing script files.
+
+@item
+Batch mode can also be useful while you're developing a query, particularly
+for multiple-line commands or multiple-statement sequences of commands. If
+you make a mistake, you don't have to retype everything. Just edit your
+script to correct the error, then tell @code{mysql} to execute it again.
+
+@item
+If you have a query that produces a lot of output, you can run the output
+through a pager rather than watching it scroll off the top of your screen:
+
+@example
+shell> mysql < batch-file | more
+@end example
+
+@item
+You can catch the output in a file for further processing:
+
+@example
+shell> mysql < batch-file > mysql.out
+@end example
+
+@item
+You can distribute your script to other people so they can run the commands,
+too.
+
+@item
+Some situations do not allow for interactive use, for example, when you run
+a query from a @code{cron} job. In this case, you must use batch mode.
+@end itemize
+
+The default output format is different (more concise) when you run
+@code{mysql} in batch mode than when you use it interactively. For
+example, the output of @code{SELECT DISTINCT species FROM pet} looks like
+this when run interactively:
+
+@example
++---------+
+| species |
++---------+
+| bird |
+| cat |
+| dog |
+| hamster |
+| snake |
++---------+
+@end example
+
+But like this when run in batch mode:
+
+@example
+species
+bird
+cat
+dog
+hamster
+snake
+@end example
+
+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}.
+
+@node Twin, , Batch mode, Tutorial
+@section Queries from twin project
+
+At Analytikerna and Lentus, we have been doing the systems and field work
+for a big research project. This project is a collaboration between the
+Institute of Environmental Medicine at Karolinska Institutet Stockholm
+and the Section on Clinical Research in Aging and Psychology at the
+University of Southern California.
+
+The project involves a screening part where all twins in Sweden older
+than 65 years are interviewed by telephone. Twins who meet certain
+criteria are passed on to the next stage. In this latter stage, twins who
+want to participate are visited by a doctor/nurse team. Some of the
+examinations include physical and neuropsychological examination,
+laboratory testing, neuroimaging, psychological status assessment, and family
+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
+
+The latter part of the project is administered with a web interface
+written using Perl and @strong{MySQL}.
+
+Each night all data from the interviews are moved into a @strong{MySQL}
+database.
+
+@menu
+* Twin pool:: Find all non-distributed twins
+* Twin event:: Show a table on twin pair status
+@end menu
+
+@node Twin pool, Twin event, Twin, Twin
+@subsection Find all non-distributed twins
+
+The following query is used to determine who goes into the second part of the
+project:
+
+@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 from 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.death_date = 0 or
+ (((to_days(p2.death_date) - to_days(p2.birthday)) / 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
+
+Some explanations:
+@table @asis
+@item @code{concat(p1.id, p1.tvab) + 0 as tvid}
+We want to sort on the concatenated @code{id} and @code{tvab} in
+numerical order. Adding @code{0} to the result causes @strong{MySQL} to
+treat the result as a number.
+@item column @code{id}
+This identifies a pair of twins. It is a key in all tables.
+@item column @code{tvab}
+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
+@strong{MySQL} to optimize the query.
+@end table
+
+This query demonstrates, among other things, how to do lookups on a
+table from the same table with a join (@code{p1} and @code{p2}). In the example, this
+is used to check whether a twin's partner died before the age of 65. If so,
+the row is not returned.
+
+All of the above exist in all tables with twin-related information. We
+have a key on both @code{id,tvab} (all tables) and @code{id,ptvab}
+(@code{person_data}) to make queries faster.
+
+On our production machine (A 200MHz UltraSPARC), this query returns
+about 150-200 rows and takes less than one second.
+
+The current number of records in the tables used above:
+@multitable @columnfractions .3 .5
+@item @strong{Table} @tab @strong{Rows}
+@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
+@subsection Show a table on twin pair status
+
+Each interview ends with a status code called @code{event}. The query
+shown below is used to display a table over all twin pairs combined by
+event. This indicates in how many pairs both twins are finished, in how many
+pairs one twin is finished and the other refused, and so on.
+
+@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
+
+@cindex Server functions
+@node Server, Replication, Tutorial, Top
+@chapter MySQL server functions
+
+@menu
+* Languages:: What languages are supported by @strong{MySQL}?
+* Table size:: How big @strong{MySQL} tables can be
+@end menu
+
+@cindex Which languages @strong{MySQL} supports
+@cindex Language support
+@node Languages, Table size, Server, Server
+@section What languages are supported by MySQL?
+
+@code{mysqld} can issue error messages in the following languages: Czech,
+Dutch, English (the default), Estonia, French, German, Hungarian, Italian,
+Norwegian, Norwegian-ny, Polish, Portuguese, Spanish and Swedish.
+
+To start @code{mysqld} with a particular language, use either the
+@code{--language=lang} or @code{-L lang} options. For example:
+
+@example
+shell> mysqld --language=swedish
+@end example
+
+or:
+
+@example
+shell> mysqld --language=/usr/local/share/swedish
+@end example
+
+Note that all language names are specified in lowercase.
+
+The language files are located (by default) in
+@file{@var{mysql_base_dir}/share/@var{LANGUAGE}/}.
+
+To update the error message file, you should edit the @file{errmsg.txt} file
+and execute the following command to generate the @file{errmsg.sys} file:
+
+@example
+shell> comp_err errmsg.txt errmsg.sys
+@end example
+
+If you upgrade to a newer version of @strong{MySQL}, remember to repeat
+your changes with the new @file{errmsg.txt} file.
+
+@menu
+* Character sets:: The character set used for data and sorting
+* Adding character set:: Adding a new character set
+* String collating:: String collating support
+* Multi-byte characters:: Multi-byte character support
+@end menu
+
+@node Character sets, Adding character set, Languages, Languages
+@subsection The character set used for data and sorting
+
+By default, @strong{MySQL} uses the ISO-8859-1 (Latin1) character
+set. This is the character set used in the USA and western Europe.
+
+The character set determines what characters are allowed in names and how
+things are sorted by the @code{ORDER BY} and @code{GROUP BY} clauses of
+the @code{SELECT} statement.
+
+You can change the character set with the
+@code{--default-character-set} option when you start the server.
+The character sets available depend on the @code{--with-charset=charset}
+option to @code{configure}, and the character set configuration files
+listed in @file{SHAREDIR/charsets/Index}.
+@xref{Quick install}.
+
+When a client connects to a @strong{MySQL} server, the server sends the
+default character set in use to the client. The client will switch to
+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
+connection handle as the first parameter.
+
+If the client is compiled with different paths than where the server is
+installed and the user that configured @strong{MySQL} didn't included all
+character sets in the @strong{MySQL} binary one must specify for
+the client where it can find the additional character sets it will need
+if the server runs with a different character set than the client.
+
+On can specify this by putting in a @strong{MySQL} option file:
+
+@example
+[client]
+default-set-dir=/usr/local/mysql/share/mysql/charsets
+@end example
+
+where the path points to where the dynamic @strong{MySQL} character sets
+are stored.
+
+One can force the client to use specific character set by specifying:
+
+@example
+[client]
+default-character-set=character-set-name
+@end example
+
+but normally this is never needed.
+
+To add another character set to @strong{MySQL}, use the following procedure:
+
+@node Adding character set, String collating, Character sets, Languages
+@subsection Adding a new character set
+
+@enumerate
+@item
+Choose a name for the character set, denoted @code{MYSET} below.
+
+@item
+Decide if the set is simple or complex. If the character set
+does not need to use special string collating routines for
+sorting, and does not need mulit-byte character support, it is
+simple. If it needs either of those features, it is complex.
+
+@item
+If the character set is simple, then create the file
+@file{sql/share/charsets/MYSET.conf}, and add MYSET the
+@file{sql/share/charsets/Index} file. Read the
+@file{sql/share/charsets/README} for more instructions.
+
+@item
+Add the character set name to the @code{CHARSETS_AVAILABLE} and
+@code{COMPILED_CHARSETS} lists in @code{configure.in}.
+
+@item
+Reconfigure, recompile and test.
+
+@item
+If the character set is complex, create the file
+@file{strings/ctype-MYSET.c} in the @strong{MySQL} source distribution.
+
+@item
+Add MYSET to the end of the @file{sql/share/charsets/Index} file. Take
+note of its position in the file - this is its character set number,
+denoted @code{MYNUMBER} below.
+
+@item
+Look at one of the existing @file{ctype-*.c} files to see what needs to be
+defined. Note that the arrays in your file must have names like
+@code{ctype_MYSET}, @code{to_lower_MYSET} and so on.
+
+Near the top of the file, place a special comment like this:
+
+@example
+/*
+ * This comment is parsed by configure to create ctype.c,
+ * so don't change it unless you know what you are doing.
+ *
+ * .configure. number_MYSET=MYNUMBER
+ * .configure. strxfrm_multiply_MYSET=N
+ * .configure. mbmaxlen_MYSET=N
+ */
+@end example
+
+The @code{configure} program uses this comment to include
+the character set into the @strong{MySQL} library automatically.
+
+The strxfrm_multiply and mbmaxlen lines will be explained in
+the following sections. Only include them if you the string
+collating functions or the multi-byte character set functions,
+respectively.
+
+@code{to_lower[]} and @code{to_upper[]} are simple arrays that hold the
+lowercase and uppercase characters corresponding to each member of the
+character set. For example:
+
+@example
+to_lower['A'] should contain 'a'
+to_upper['a'] should contain 'A'
+@end example
+
+@code{sort_order[]} is a map indicating how characters should be ordered for
+comparison and sorting purposes. For many character sets, this is the same as
+@code{to_upper[]} (which means sorting will be case insensitive).
+@strong{MySQL} will sort characters based on the value of
+@code{sort_order[character]}. For more complicated sorting rules, see
+the discussion of string collating below.
+
+@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.)
+You can find the following bitmask definitions in @file{m_ctype.h}:
+
+@example
+#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 _B 0100 /* Blank */
+#define _X 0200 /* heXadecimal digit */
+@end example
+
+The @code{ctype[]} entry for each character should be the union of the
+applicable bitmask values that describe the character.
+For example, @code{'A'} is an uppercase character (@code{_U}) as well as a
+hexadecimal digit (@code{_X}), so @code{ctype['A'+1]} should contain the value:
+@example
+_U + _X = 01 + 0200 = 0201
+@end example
+
+@item
+Add support for the string collating or multi-byte features needed, as
+described in the following sections.
+
+@item
+Add the character set name to the @code{CHARSETS_AVAILABLE} and
+@code{COMPILED_CHARSETS} lists in @code{configure.in}.
+
+@item
+Reconfigure, recompile and test.
+@end enumerate
+
+@cindex String collating
+@node String collating, Multi-byte characters, Adding character set, Languages
+@subsection String collating support
+
+If the sorting rules for your language are too complex to be handled
+with the simple @code{sort_order[]} table, you need to use the string
+collating functions.
+
+Right now the best documentation on this is the character sets that are
+already implemented. Look at the big5, czech, gbk, sjis and tis160
+character sets for examples.
+
+You must specify the @code{strxfrm_multiply_MYSET=N} value in the
+special comment at the top of the file. @code{N} should be set to
+the maximum ratio the strings may grow during my_strxfrm_MYSET (it
+must be a positive integer).
+
+@cindex Multi-byte characters
+@node Multi-byte characters, , String collating, Languages
+@subsection Multi-byte character support
+
+If your character set includes multi-byte characters, you need to use
+the multi-byte character functions.
+
+Right now the best documentation on this is the character sets that are
+already implemented. Look at the euc_kr, gb2312, gbk, sjis and ujis
+character sets for examples.
+
+You must specify the @code{mbmaxlen_MYSET=N} value in the
+special comment at the top of the file. @code{N} should be set to
+the size in bytes of the largest character in the set.
+
+@cindex Table size
+@cindex Size of tables
+@node Table size, , Languages, Server
+@section How big MySQL tables can be
+
+@strong{MySQL} 3.22 has a 4G limit on table size. With the new
+@code{MyISAM} in @strong{MySQL} 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 .6 .4
+@item Linux-Intel @tab 2G (or 4G with reiserfs)
+@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 (?)
+@end multitable
+
+This means that the table size for @strong{MySQL} is normally limited by
+the operating system.
+
+By default, @strong{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}.
+
+If you need bigger tables than 4G (and your operating system supports
+this), you should set the @code{AVG_ROW_LENGTH} and @code{MAX_ROWS}
+parameter when you create your table. @xref{CREATE TABLE}. You can
+also set these later with @code{ALTER TABLE}. @xref{ALTER TABLE}.
+
+If you need to have bigger tables than 2G / 4G
+
+If your big table is going to be read-only, you could use
+@code{myisampack} to merge and compress many tables to one.
+@code{myisampack} usually compresses a table by at least 50%, so you can
+have, in effect, much bigger tables. @xref{myisampack, ,
+@code{myisampack}}.
+
+Another solution can be the included MERGE library, which allows you to
+handle a collection of identical tables as one. (Identical in this case
+means that all tables are created with identical column information.)
+Currently MERGE can only be used to scan a collection of tables because it
+doesn't support indexes. We will add indexes to this in the near future.
+
+@cindex Replication
+@node Replication, Performance, Server, Top
+@chapter Replication in MySQL
+@menu
+* Replication Intro:: Introduction
+* Replication Implementation:: Replication Implementation Overview
+* Replication HOWTO:: HOWTO
+* Replication Features:: Replication Features
+* Replication Options:: Replication Options in my.cnf
+* Replication SQL:: SQL Commands related to replication
+@end menu
+
+@node Replication Intro, Replication Implementation, Replication, Replication
+@section Introduction
+One way replication can be used both to increase robustness and
+speed. For robustness you have two systems and switch to the backup if
+you have problems with the master. The extra speed is achieved by
+sending a part of the non-updating queries to the replica server. Of
+course this only works if non-updating queries dominate, but that is the
+normal case.
+
+Starting in 3.23.15, @strong{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
+and an index file to binary logs to keep track of log rotation. The
+slave upon connecting informs the master where it left off sinse the
+last successfully propogated update, catches up on the updates, and then
+blocks and waits for the master to notify it of the new updates.
+
+@node Replication Implementation, Replication HOWTO, Replication Intro, Replication
+@section Replication Implementation Overview
+
+@strong{MySQL} internal replication uses the master-slave approach. One
+server is designated as the master, while the other ( or others) as
+slave(s). The master keeps a binary log of updates. The slave connects
+to the master, catches up on the missed updates, and then starts
+receiving updates immediately as they come to the master. If the
+connection is lost, the slave will reconnect. If the master goes down,
+the slave will keep trying to connect every @code{master-connect-retry}
+seconds until the master comes back up and the connection can be
+established. The slave keeps track of where it left off in the
+replication process, so it can use the info in the case it goes down and
+gets restarted later.
+
+@node Replication HOWTO, Replication Features, Replication Implementation, Replication
+@section HOWTO
+Below is a quick HOWTO on how to set up replication on your current system:
+
+@itemize @bullet
+@item
+Upgrade both slave and master to 3.23.15 or higher. We recommend that
+you use the latest 3.23 version on both the slave and the master. While
+3.23 is in beta, the versions may be not backwards compatible. In
+addition, the newer version will fix some bugs and add new features.
+@item
+Set up special replication user(s) on the master with the @code{FILE}
+privilege and permission to connect from all the slaves. If the user is
+only doing replication, you don't need to grant him other privileges.
+@item
+Take a snapshot of all the tables/databases on the master that could
+possibly be involved in the update queries before taking the next step
+@item
+In @code{my.cnf} on the master add @code{log-bin} and restart it. Make
+sure there are no important updates to the master between the time you
+have taken the snapshot and the time master is restarted with
+@code{log-bin} option
+@item
+Load the snapshot of the master to all the slaves
+@item
+Add the following to @code{my.cnf} on the slave(s):
+
+@example
+master-host=<hostname of the master>
+master-user=<replication user name>
+master-password=<replication user password>
+@end example
+
+replacting the values in <> with what is relevant to your system.
+
+@item Restart the slave(s)
+
+@end itemize
+
+After you have done the above, the master and the slave(s) should be in
+sync.
+
+@node Replication Features, Replication Options, Replication HOWTO, Replication
+@section Replication Features
+
+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
+@item
+@code{LOAD DATA INFILE} will be handled properly as long as the file
+still resides on the master server at the time of update
+propogation. @code{LOAD LOCAL DATA INFILE} will be skipped.
+@item
+Update queries that use user variables are not replication-safe (yet)
+@item
+If the query on the slave gets an error, the slave thread will
+terminate, and a message will appear in @code{.err} file. You should
+then connect to the slave manually, fix the cause of the error
+(eg. non-existent table), and then run @code{SLAVE START} sql command (
+available starting in 3.23.16, in 3.23.15 you will have to restart the
+server).
+@item
+If connection to the master is lost, the slave will retry immediately,
+and then in case of failure every @code{master-connect-retry} (default
+60) seconds. Because of this, it is safe to shut down the master, and
+then restart it after a while. The slave will also be able to deal with
+network connectivity outages.
+@item
+Shutting down the slave (cleanly) is also safe, as it keeps track of
+where it left off. Unclean shutdowns might produce problems, especially
+if disk cache was not synced before the system died. Your system fault
+tolerance will be greatly increased if you have a good UPS.
+@item
+If the master is listening on a non-standard port, you will also need to
+specify this with @code{master-port} parameter in @code{my.cnf} .
+@item
+In 3.23.15,all of the tables and databases will be replicated. Starting
+in 3.23.16, you can restrict replication to a set of databases with
+@code{replicate-do-db} directives in @code{my.cnf} or just excluse a set
+of databases with @code{replicate-ignore-db}.
+@item
+Starting in 3.23.16, @code{SET SQL_LOG_BIN = 0} will turn off
+replication (binary) logging on the master, and @code{SET SQL_LOG_BIN =
+1} will turn in back on - you must have the process privilege to do
+this.
+@item
+The slave thread does not log updates to the binary log of the slave,
+so it is possible to couple two servers in a mutual master-slave
+relationship. You can actually set up a load balancing scheme and do
+queries safely on either of the servers. Just do not expect to do LOCK
+TABLES on one server, then connect to the other and still have that
+lock :-) .
+@item
+Starting in 3.23.19 you can clean up stale replication leftovers when
+something goes wrong and you want a clean start with @code{FLUSH MASTER}
+and @code{FLUSH SLAVE} commands
+@item
+Starting in 3.23.21 you can use LOAD TABLE FROM MASTER for network
+backup and to set up replication initially.
+@end itemize
+
+@node Replication Options, Replication SQL, Replication Features, Replication
+@section Replication Options in my.cnf
+
+The table below explains the replications options in @code{my.cnf} . All
+of the are available starting in 3.23.15 unless indicated otherwise.
+
+@multitable @columnfractions .25 .25 .25 .25
+@item @strong{Option} @tab @strong{Description} @tab @strong{Where to set} @tab @strong{Example}
+@item @code{log-bin} @tab Should be set on the master. Tells it to keep a binary update
+log. If a parameter is specified, the log will be written to the specified location. @tab Master @tab
+@code{log-bin}
+@item @code{log-bin-index} @tab Because the user could issue @code{FLUSH LOGS} command, we need to
+know which log is currently active and which ones have been rotated out and it what sequence. This info
+is stored in the binary log index file. The default is `hostname`.index . You can use this option
+if you want to be a rebel. @tab Master @tab @code{log-bin-index=db.index}
+@item @code{master-host} @tab Master hostname or IP address for replication. If not set,
+the slave thread will not be started @tab Slave @tab @code{master-host=db-master.mycompany.com}
+@item @code{master-user} @tab The user the slave thread will authenticate as when connecting to
+the master. The user must have @code{FILE} privilige. If the master user is not set, user @code{test}
+ is assumed. @tab Slave @tab @code{master-user=scott}
+@item @code{master-password} @tab The password the slave thread will authenticate with when
+connecting to the master. If not set, empty password is assumed @tab Slave @tab
+@code{master-password=tiger}
+@item @code{master-port} @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. @tab Slave @tab @code{master-port=3306}
+@item @code{master-connect-retry} @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. @tab Slave @tab @code{master-connect-retry=60}
+@item @code{master-info-file} @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
+directory. Sasha: The only reason I see for ever changing the default
+is the desire to be rebelious.
+@tab Slave @tab @code{master-info-file=master.info}
+@item @code{replicate-do-db} @tab Tells the slave thread to restrict replication to the specified database. To specify more than one database, use the directive multiple times, once for each database.
+Note that this will only work if you do not use cross-database queries such as
+@code{UPDATE some_db.some_table SET foo='bar'} while having selected a different or
+no database. @tab Slave @tab @code{replicate-do-db=some_db}
+@item @code{replicate-ignore-db} @tab Tells the slave thread to not replicate to the specified
+database. To specify more than one database to ignore, use the directive multiple times,
+once for each database. You must not use cross database updates for this option. @tab Slave @tab @code{replicate-ignore-db=some_db}
+@item @code{sql-bin-update-same} @tab If set, setting @code{SQL_LOG_BIN} to a value will
+automatically set @code{SQL_LOG_UPDATE} to the same value and vice
+versa. @tab Master @tab @code{sql-bin-update-same}
+
+@item @code{log-slave-updates} @tab Tells the slave to log the updates from the slave thread to the binary log. Off by default. You will need to turn it on if you plan to daisy-chain the slaves @tab Slave @tab @code{log-slave-updates}
+
+@end multitable
+
+@node Replication SQL, , Replication Options, Replication
+@section SQL commands related to replication
+
+Replication can be controlled through the SQL interface. Below is the
+summary of commands:
+
+@multitable @columnfractions .30 .40 .30
+@item @strong{Command} @tab @strong{Description} @tab @strong{Where to run}
+@item @code{SLAVE START} @tab Starts the slave thread. @tab Slave
+@item @code{SLAVE STOP} @tab Stops the slave thread. @tab Slave
+@item @code{SET SQL_LOG_BIN=0} @tab Disables update logging @tab Master
+@item @code{SET SQL_LOG_BIN=1} @tab Re-enable update logging @tab Master
+@item @code{FLUSH MASTER} @tab Deletes all binary logs listed in the inded file, resetting the binlog index file to be empty. @tab Master
+@item @code{FLUSH SLAVE} @tab Makes the slave forget its replication position in the master logs @tab Slave
+@item @code{LOAD TABLE tblname FROM MASTER} @tab Downloads a copy of the table from master to the slave @tab Slave
+@end multitable
+
+@cindex Performance
+@cindex Optimization
+@node Performance, MySQL Benchmarks, Replication, Top
+@chapter Getting maximum performance from MySQL
+
+Optimization 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/application, the
+more optimal you want your system to become the more you will have to
+know about it.
+
+So this chapter will try to explain and give some examples of different
+ways to optimize @strong{MySQL}. But remember that there are always some
+(increasingly harder) ways to make the system even faster left to do.
+
+@menu
+* Optimize Basics:: Optimization overview
+* System:: System/Compile time and startup parameter tuning
+* Data size:: Get your data as small as possible
+* MySQL indexes:: How @strong{MySQL} uses indexes
+* Query Speed:: Speed of queries that access or update data
+* Tips:: Other optimization tips
+* Benchmarks:: Using your own benchmarks
+* Design:: Design choices
+* Design Limitations:: MySQL design limitations/tradeoffs
+* Portability:: Portability
+* Internal use:: What have we used MySQL for?
+@end menu
+
+@node Optimize Basics, System, Performance, Performance
+@section Optimization 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
+doing, and what your bottlenecks are.
+
+The most common bottlenecks are:
+@itemize @bullet
+@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.
+@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
+multiple disks.
+@item CPU cycles
+When we have got the data into main memory (or if it already were
+there) we need to process it to get to our result. When we have small
+tables compared to the memory this is the most common limiting
+factor. But then with small tables speed is usually not the problem.
+@item Memory bandwidth
+When the CPU needs more data than can fit in the CPU cache the main
+memory bandwidth becomes a bottleneck. This is an uncommon bottleneck
+for most systems but one should be aware of it.
+@end itemize
+
+@node System, Data size, Optimize Basics, Performance
+@section System/Compile time and startup parameter tuning
+
+We start with the system level things since some of these decisions have
+to be made very early. In other cases a fast look at this part may
+suffice because it not that important for the big gains. However, it is always
+nice to have a feeling about how much one could gain by changing things
+at this level.
+
+The default OS to use is really important! To get the most use of
+multiple CPU machines one should use Solaris (because the threads works
+really nice) or Linux (because the 2.2 kernel has really good SMP
+support). Also on 32bit machines Linux has a 2G file size limit by
+default. Hopefully this will be fixed soon when new filesystems is
+released (XFS/Reiserfs).
+
+Because we have not run @strong{MySQL} in production on that many platforms we
+advice you to test your intended platform before choosing it, if possible.
+
+Other tips:
+@itemize @bullet
+@item
+If you have enough RAM, you could remove all swap devices. Some
+operating systems will use a swap device in some contexts even if you
+have free memory.
+@item
+Use the @code{--skip-locking} @strong{MySQL} option to avoid external
+locking. Note that this will not impact @strong{MySQL}'s functionality as
+long as you only run one server. Just remember to take down the server (or
+lock relevant parts) before you run @code{myisamchk}. On some system
+this switch is mandatory because the external locking does not work in any
+case.
+
+The @code{--skip-locking} option is on by default when compiling with
+MIT-pthreads, because @code{flock()} isn't fully supported by
+MIT-pthreads on all platforms.
+
+The only case when you can't use @code{--skip-locking} is if you run
+multiple @strong{MySQL} @emph{servers} (not clients) on the same data, or run
+@code{myisamchk} on the table without first flushing and locking the
+@code{mysqld} server tables first.
+
+You can still use @code{LOCK TABLES} / @code{UNLOCK TABLES} even if you
+are using @code{--skip-locking}
+@end itemize
+
+@menu
+* Compile and link options:: How compiling and linking affects the speed of MySQL
+* Disk issues:: Disk issues
+* Server parameters:: Tuning server parameters
+* Table cache:: How MySQL opens and closes tables
+* Creating many tables:: Drawbacks of creating large numbers of tables in the same database
+* Open tables:: Why so many open tables?
+* Memory use:: How MySQL uses memory
+* Internal locking:: How MySQL locks tables
+* Table locking:: Table locking issues
+@end menu
+
+@node Compile and link options, Disk issues, System, System
+@subsection How compiling and linking affects the speed of MySQL
+
+Most of the following tests are done on Linux with the
+@strong{MySQL} benchmarks, but they should give some indication for
+other operating systems and workloads.
+
+You get the fastest executable when you link with @code{-static}.
+
+On Linux, you will get the fastest code when compiling with @code{pgcc}
+and @code{-O6}. To compile @file{sql_yacc.cc} with these options, you
+need about 200M memory because @code{gcc/pgcc} needs a lot of memory to
+make all functions inline. You should also set @code{CXX=gcc} when
+configuring @strong{MySQL} to avoid inclusion of the @code{libstdc++}
+library (it is not needed). Note that with some versions of @code{pgcc},
+the resulting code will only run on true Pentium processors, even if you
+use the compiler option that you want the resulting code to be working on
+all x586 type processors (Like AMD).
+
+By just using a better compiler and/or better compiler options you can
+get a 10-30 % speed increase in your application. This is particularly
+important if you compile the SQL server yourself!
+
+We have tested the both Cygnus CodeFusion and the Fujitsu compiler but
+when we tested them, neither was enough bug free enough to compile
+@strong{MySQL} with optimizations on.
+
+When you compile @strong{MySQL} you should only include support for the
+character sets that you are going to use. (Option @code{--with-charset=xxx}).
+The standard @strong{MySQL} binary distributions are compiled with support
+for all character sets.
+
+Here is a list of some mesurements that we have done:
+@itemize @bullet
+@item
+If you use @code{pgcc} and compile everything with @code{-O6}, the
+@code{mysqld} server is 11% faster than with @code{gcc} versions
+older than @code{gcc} 2.95.2.
+
+@item
+If you link dynamically (without @code{-static}), the result is 13%
+slower. Note that you still can use a dynamic linked @strong{MySQL}
+library. It is only the server that is critical for performance.
+
+@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},
+@strong{MySQL} will by default use sockets).
+
+@item
+On a Sun SPARCstation 10, @code{gcc} 2.7.3 is 13% faster than Sun Pro C++ 4.2.
+
+@item
+On Solaris 2.5.1, MIT-pthreads is 8-12% slower than Solaris native
+threads on a single processor. With more load/CPUs the difference should
+get bigger.
+@end itemize
+
+The @strong{MySQL}-Linux distribution provided by MySQL AB used to be
+compiled with @code{pgcc}, but we had to go back to regular gcc because
+of a bug in @code{pgcc} that would generate the code that does not run
+on AMD. We will continue using gcc until that bug is resolved. In the
+meantime, if you have a non-AMD machine, you can get a faster binary by
+compiling with @code{pgcc}. The standard MySqL Linux binary is linked
+statically to get it faster and more portable.
+
+
+@node Disk issues, Server parameters, Compile and link options, System
+@subsection Disk issues
+
+@itemize @bullet
+@item
+As mentioned before disks seeks are a big performance bottleneck. This
+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.
+@item
+Increase the number of available disk spindles (and thereby reduce
+the seek overhead) by either symlink files to different disks or stripe
+the disks.
+@table @strong
+@item Using symbolic links
+This means that you symlink the index and/or data file(s) from the
+normal data directory to another disk (that may also be striped). This
+makes both the seek and read times better (if the disks are not used for
+other things). @xref{Symbolic links}.
+@item Striping
+Striping means that you have many disks and put the first block on the
+first disk, the second block on the second disk, and the Nth on the (Nth
+mod number_of_disks) disk, and so on. This means if your normal data
+size is less than the stripe size (or perfectly aligned) you will get
+much better performance. Note that striping if very dependent on the OS
+and stripe-size. So benchmark your application with different
+stripe-sizes. @xref{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 difference in orders of magnitude. Note that
+you have to choose to optimize for random or sequential access.
+@end table
+@item
+For reliability you may want to use RAID 0+1 (striping + mirroring), but
+in this case you will need 2*N drives to hold N drives of data. This is
+probably the best option if you have the money for it! You may however
+also have to invest in some volume management software to handle it
+efficiently.
+@item
+A good option is to have semi-important data (that can be re-generated)
+on RAID 0 disk while store really important data (like host information
+and logs) on a RAID 0+1 or RAID N disks. RAID N can be a problem if you
+have many writes because of the time to update the parity bits.
+@item
+You may also set the parameters for the file system that the database
+uses. One easy change is to mount the file system with the noatime
+option. That makes it skip the updating of the last access time in the
+inode and by this will avoid some disk seeks.
+@item
+On Linux, you can get much more performance (up to 100 % under load is
+not uncommon) by using hdpram to configure your disks interface! The
+following should be quite good hdparm options for @code{MySQL} (and
+probably many other applications):
+@example
+hdparm -m 16 -d 1
+
+@end example
+
+Note that the performance/reliability when using the above depends on
+your hardware, so we strongly suggest that you test your system
+throughly after using @code{hdparm}! Please consult the @code{hdparm}
+man page for more information! If @code{hdparm} is not used wisely,
+filesystem corruption may result. Backup everything before experimenting!
+@item
+On many OS system you can mount the disks with the 'async' flag to set the file
+system to be updated asynchronously. If your computer is reasonable stable,
+this should give you more performance without sacrificing too much reliability.
+(This flag is on by default on Linux).
+@item
+If you don't need to know when a file was last accessed (which is not
+really useful on a databasa server), you can mount your file systems
+with the noatime flag.
+@end itemize
+
+@menu
+* Symbolic links:: Using symbolic links for databases and tables
+@end menu
+
+@node Symbolic links, , Disk issues, Disk issues
+@subsubsection Using symbolic links for databases and tables
+
+You can move tables and databases from the database directory to other
+locations and replace them with symbolic links to the new locations.
+You might want to do this, for example, to move a database to a file
+system with more free space.
+
+If @strong{MySQL} notices that a table is a symbolically-linked, it will
+resolve the symlink and use the table it points to instead. This works
+on all systems that support the @code{realpath()} call (at least Linux
+and Solaris support @code{realpath()})! On systems that don't support
+@code{realpath()}, you should not access the table through the real path
+and through the symlink at the same time! If you do, the table will be
+inconsistent after any update.
+
+@strong{MySQL} doesn't that you link one directory to multiple
+databases. Replacing a database directory with a symbolic link will
+work fine as long as you don't make a symbolic link between databases.
+Suppose you have a database @code{db1} under the @strong{MySQL} data
+directory, and then make a symlink @code{db2} that points to @code{db1}:
+
+@example
+shell> cd /path/to/datadir
+shell> ln -s db1 db2
+@end example
+
+Now, for any table @code{tbl_a} in @code{db1}, there also appears to be
+a table @code{tbl_a} in @code{db2}. If one thread updates @code{db1.tbl_a}
+and another thread updates @code{db2.tbl_a}, there will be problems.
+
+If you really need this, you must change the following code in
+@file{mysys/mf_format.c}:
+
+@example
+if (flag & 32 || (!lstat(to,&stat_buff) && S_ISLNK(stat_buff.st_mode)))
+@end example
+
+to
+
+@example
+if (1)
+@end example
+
+On windows you can use internal symbolic links to directories by compiling
+@strong{MySQL} with @code{-DUSE_SYMDIR}. This allows you to put different
+databases on different disks. @xref{Win32 symbolic links}.
+
+@cindex Startup parameters
+@node Server parameters, Table cache, Disk issues, System
+@subsection Tuning server parameters
+
+You can get the default buffer sizes used by the @code{mysqld} server
+with this command:
+
+@example
+shell> mysqld --help
+@end example
+
+This command produces a list of all @code{mysqld} options and configurable
+variables. The output includes the default values and looks something
+like this:
+
+@example
+Possible variables for option --set-variable (-O) are:
+back_log current value: 5
+bdb_cache_size current value: 1048540
+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_table_names current value: 0
+long_query_time current value: 10
+max_allowed_packet current value: 1048576
+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
+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
+
+If there is a @code{mysqld} server currently running, you can see what
+values it actually is using for the variables by executing this command:
+
+@example
+shell> mysqladmin variables
+@end example
+<<<<<<< manual.texi
+
+Each option is described below. Values for buffer sizes, lengths and stack
+sizes are given in bytes. You can specify values with a suffix of @samp{K}
+or @samp{M} to indicate kilobytes or megabytes. For example, @code{16M}
+indicates 16 megabytes. The case of suffix letters does not matter;
+@code{16M} and @code{16m} are equivalent.
+
+You can also see some statistics from a running server by issuing the command
+@code{SHOW STATUS}. @xref{SHOW}.
+
+@table @code
+@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 @strong{MySQL} can have. This
+comes into play when the main @strong{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
+stacked during this short time before @strong{MySQL} momentarily stops
+answering new requests. You need to increase this only if you expect a large
+number of connections in a short period of time.
+
+In other words, this value is the size of the listen queue for incoming
+TCP/IP connections. Your operating system has its own limit on the size
+of this queue. The manual page for the Unix @code{listen(2)} system
+call should have more details. Check your OS documentation for the
+maximum value for this variable. Attempting to set @code{back_log}
+higher than your operating system limit will be ineffective.
+
+@item @code{bdb_cache_size}
+The buffer that is allocated to cache index and rows for @code{BDB} tables.
+If you don't use @code{BDB} tables, you should set this to 0 or
+start @code{mysqld} with @code{--skip-bdb} o not waste memory for this cache.
+
+@item @code{concurrent_inserts}
+If @code{ON} (the default), @code{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 mysqld with @code{--safe}
+or @code{--skip-new}.
+
+@item @code{connect_timeout}
+The number of seconds the @code{mysqld} server is waiting for a connect
+packet before responding with @code{Bad handshake}.
+
+@item @code{delayed_insert_timeout}
+How long a @code{INSERT DELAYED} thread should wait for @code{INSERT}
+statements before terminating.
+
+@item @code{delayed_insert_limit}
+After inserting @code{delayed_insert_limit} rows, the @code{INSERT
+DELAYED} handler will check if there are any @code{SELECT} statements
+pending. If so, it allows these to execute before continuing.
+
+@item @code{delay_key_write}
+If enabled (is on by default), @strong{MySQL} will honor the
+@code{delay_key_write} option @code{CREATE TABLE}. This means that the
+key buffer for tables with this option will not get flushed on every
+index update, but only when a table is closed. This will speed up
+writes on keys a lot but you should add automatic checking of all tables
+with @code{myisamchk --fast --force} if you use this. Note that if you
+start @code{mysqld} with the @code{--delay-key-write-for-all-tables}
+option this means that all tables will be treated as if they were
+created with the @code{delay_key_write} option. You can clear this flag
+by starting @code{mysqld} with @code{--skip-new} or @code{--safe-mode}.
+
+@item @code{delayed_queue_size}
+What size queue (in rows) should be allocated for handling @code{INSERT
+DELAYED}. If the queue becomes full, any client that does @code{INSERT
+DELAYED} will wait until there is room in the queue again.
+
+@item @code{flush_time}
+If this is set to a non-zero value, then every @code{flush_time} seconds all
+tables will be closed (to free up resources and sync things to disk).
+
+@item @code{init_file}
+The name of the file specified with the @code{--init-file} option when
+you start the server. This is a file of SQL statements you want the
+server to execute when it starts.
+
+@item @code{interactive_timeout}
+The number of seconds the server waits for activity on an interactive
+connection before closing it. An interactive client is defined as a
+client that uses the @code{CLIENT_INTERACTIVE} option to
+@code{mysql_real_connect()}. See also @code{wait_timeout}.
+
+@item @code{join_buffer_size}
+The size of the buffer that is used for full joins (joins that do not
+use indexes). The buffer is allocated one time for each full join
+between two tables. Increase this value to get a faster full join when
+adding indexes is not possible. (Normally the best way to get fast joins
+is to add indexes.)
+
+@c Make texi2html support index @anchor{Index cache size}. Then change
+@c some xrefs to point here
+@item @code{key_buffer_size}
+Index blocks are buffered and are shared by all threads.
+@code{key_buffer_size} is the size of the buffer used for index blocks.
+
+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 @strong{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 @strong{MySQL} does not cache data
+read, that you will have to leave some room for the OS filesystem cache.
+
+You can check the performance of the key buffer by doing @code{show
+status} and examine the variables @code{Key_read_requests},
+@code{Key_reads}, @code{Key_write_requests} and @code{Key_writes}. The
+@code{Key_reads/Key_read_request} ratio should normally be < 0.01.
+The @code{Key_write/Key_write_requests} is usually near 1 if you are
+using mostly updates/deletes but may be much smaller if you tend to
+do updates that affect many at the same time or if you are
+using @code{delay_key_write}. @xref{SHOW}.
+
+To get even more speed when writing many rows at the same time use
+@code{LOCK TABLES}. @xref{LOCK TABLES, , @code{LOCK TABLES}}.
+
+@item @code{lower_case_table_names}
+Change all table names to lower case on disk.
+
+@item @code{long_query_time}
+If a query takes longer than this (in seconds), the @code{Slow_queries} counter
+will be incremented.
+
+@item @code{max_allowed_packet}
+The maximum size of one packet. The message buffer is initialized 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.
+
+@item @code{max_connections}
+The number of simultaneous clients allowed. Increasing this value increases
+the number of file descriptors that @code{mysqld} requires. See below for
+comments on file descriptor limits. @xref{Too many connections}.
+
+@item @code{max_connect_errors}
+If there is more than this number of interrupted connections from a host
+this host will be blocked from further connections. You can unblock a host
+with the command @code{FLUSH HOSTS}.
+
+@item @code{max_delayed_threads}
+Don't start more than this number of threads to handle @code{INSERT DELAYED}
+statements. If you try to insert data into a new table after all @code{INSERT
+DELAYED} threads are in use, the row will be inserted as if the
+@code{DELAYED} attribute wasn't specified.
+
+@item @code{max_join_size}
+Joins that are probably going to read more than @code{max_join_size}
+records return an error. Set this value if your users tend to perform joins
+without a @code{WHERE} clause that take a long time and return
+millions of rows.
+
+@item @code{max_heap_table_size}
+Don't allow creation of heap tables bigger than this.
+
+@item @code{max_sort_length}
+The number of bytes to use when sorting @code{BLOB} or @code{TEXT}
+values (only the first @code{max_sort_length} bytes of each value
+are used; the rest are ignored).
+
+@item @code{max_tmp_tables}
+(This option doesn't yet do anything).
+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_sort_buffer_size}
+The buffer that is allocated when sorting the index when doing a @code{REPAIR}
+table.
+
+@item @code{net_buffer_length}
+The communication buffer is reset to this size between queries. This
+should not normally be changed, but if you have very little memory, you
+can set it to the expected size of a query. (That is, the expected length of
+SQL statements sent by clients. If statements exceed this length, the buffer
+is automatically enlarged, up to @code{max_allowed_packet} bytes.)
+
+@item @code{net_retry_count}
+If a read on a communication port is interrupted, retry this many times
+before giving up. This value should be quite high on @code{FreeBSD} as
+internal interrupts is sent to all threads.
+
+@item @code{net_read_timeout}
+Number of seconds to wait for more data from a connection before aborting
+the read. Note that when we don't expect data from a connection, the timeout
+is defined by @code{write_timeout}.
+
+@item @code{net_write_timeout}
+Number of seconds to wait for a block to be written to a connection before
+aborting the write.
+=======
+>>>>>>> 1.148
+
+<<<<<<< manual.texi
+@item @code{record_buffer}
+Each thread that does a sequential scan allocates a buffer of this
+size for each table it scans. If you do many sequential scans, you may
+want to increase this value.
+=======
+or the @code{SHOW VARIABLES} in the @code{mysql} command client.
+>>>>>>> 1.148
+
+<<<<<<< manual.texi
+@item @code{query_buffer_size}
+The initial allocation of the query buffer. If most of your queries are
+long (like when inserting blobs), you should increase this!
+=======
+You can find a full description for all variables in the @code{SHOW VARIABLES}
+section in this manual. @xref{SHOW VARIABLES}.
+>>>>>>> 1.148
+
+<<<<<<< manual.texi
+@item @code{skip_show_databases}
+This prevents people from doing @code{SHOW DATABASES}, if they don't
+have the @code{PROCESS_PRIV} privilege. This can improve security if
+you're concerned about people being able to see what databases and
+tables other users have.
+
+@item @code{slow_launch_time}
+If the creating of the thread longer than this (in seconds), the
+@code{Slow_launch_threads} counter will be incremented.
+
+@item @code{sort_buffer}
+Each thread that needs to do a sort allocates a buffer of this
+size. Increase this value for faster @code{ORDER BY} or @code{GROUP BY}
+operations.
+@xref{Temporary files}.
+
+@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.
+@strong{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.
+
+For information about how the table cache works, see @ref{Table cache}.
+
+@item @code{thread_cache_size}
+How many threads we should keep keep in a cache for reuse. When a
+client disconnects the clients threads is put in the cache if there
+isn't more than @code{thread_cache_size} threads from before. All new
+threads are first taken from the cache and only when the cache is empty
+a new thread is created. This variable can be increased to improve
+performance if you have a lot of new connections (Normally this doesn't
+however give a notable performance improvement if you have a good
+thread implementation).
+
+@item @code{thread_concurrency}
+On Solaris, @code{mysqld} will call @code{thr_setconcurrency()} with
+this value. @code{thr_setconcurrency()} permits the application to give
+the threads system a hint, for the desired number of threads that should
+be run at the same time.
+
+@item @code{thread_stack}
+The stack size for each thread. Many of the limits detected by the
+@code{crash-me} test are dependent on this value. The default is
+large enough for normal operation. @xref{Benchmarks}.
+
+@item @code{tmp_table_size}
+If an in-memory temporary table exceeds this size, @strong{MySQL}
+will automatically convert it to an on-disk @code{MyISAM} table.
+Increase the value of @code{tmp_table_size} if you do many advanced
+@code{GROUP BY} queries and you have lots of memory.
+
+@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
+=======
+You can also see some statistics from a running server by issuing the command
+@code{SHOW STATUS}. @xref{SHOW STATUS}.
+>>>>>>> 1.148
+
+@strong{MySQL} uses algorithms that are very scalable, so you can usually
+run with very little memory. If you however give @strong{MySQL} more
+memory you will normally also get better performance.
+
+When tuning a @strong{MySQL} server, the two most important variables to use
+are @code{key_buffer_size} and @code{table_cache}. You should first feel
+confident that you have these right before trying to change any of the
+other variables.
+
+If you have much memory (>=256M) and many tables and want maximum performance
+with a moderate number of clients, you should use something like this:
+
+@example
+shell> safe_mysqld -O key_buffer=64M -O table_cache=256 \
+ -O sort_buffer=4M -O record_buffer=1M &
+@end example
+
+If you have only 128M and only a few tables, but you still do a lot of
+sorting, you can use something like:
+
+@example
+shell> safe_mysqld -O key_buffer=16M -O sort_buffer=1M
+@end example
+
+If you have little memory and lots of connections, use something like this:
+
+@example
+shell> safe_mysqld -O key_buffer=512k -O sort_buffer=100k \
+ -O record_buffer=100k &
+@end example
+
+or even:
+
+@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
+
+When you have installed @strong{MySQL}, the @file{Docs} 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.
+
+If there are very many connections, ``swapping problems'' may occur unless
+@code{mysqld} has been configured to use very little memory for each
+connection. @code{mysqld} performs better if you have enough memory for all
+connections, of course.
+
+Note that if you change an option to @code{mysqld}, it remains in effect only
+for that instance of the server.
+
+To see the effects of a parameter change, do something like this:
+
+@example
+shell> mysqld -O key_buffer=32m --help
+@end example
+
+Make sure that the @code{--help} option is last; otherwise, the effect of any
+options listed after it on the command line will not be reflected in the
+output.
+
+@cindex Table cache
+@findex table_cache
+@node Table cache, Creating many tables, Server parameters, System
+@subsection How MySQL opens and closes tables
+
+@code{table_cache}, @code{max_connections} and @code{max_tmp_tables}
+affect the maximum number of files the server keeps open. If you
+increase one or both of these values, you may run up against a limit
+imposed by your operating system on the per-process number of open file
+descriptors. However, you can increase the limit on many systems.
+Consult your OS documentation to find out how to do this, because the
+method for changing the limit varies widely from system to system.
+
+@code{table_cache} is related to @code{max_connections}. For example,
+for 200 concurrent running connections, you should have a table cache of
+at least @code{200 * n}, where @code{n} is the maximum number of tables
+in a join.
+
+The cache of open tables can grow to a maximum of @code{table_cache}
+(default 64; this can be changed with 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}.
+
+When the table cache fills up, the server uses the following procedure
+to locate a cache entry to use:
+
+@itemize @bullet
+@item
+Tables that are not currently in use are released, in least-recently-used
+order.
+
+@item
+If the cache is full and no tables can be released, but a new table needs to
+be opened, the cache is temporarily extended as necessary.
+
+@item
+If the cache is in a temporarily-extended state and a table goes from in-use
+to not-in-use state, the table is closed and released from the cache.
+@end itemize
+
+A table is opened for each concurrent access. This means that
+if you have two threads accessing the same table or access the table
+twice in the same query (with @code{AS}) the table needs to be opened twice.
+The first open of any table takes two file descriptors; each additional
+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.
+
+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
+haven't done alot of @code{flush tables}, you should increase your table
+cache. @xref{SHOW STATUS}.
+
+@node Creating many tables, Open tables, Table cache, System
+@subsection Drawbacks of creating large numbers of tables in the same database
+
+If you have many files in a directory, open, close and create operations will
+be slow. If you execute @code{SELECT} statements on many different tables,
+there will be a little overhead when the table cache is full, because for
+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, Memory use, Creating many tables, System
+@subsection Why so many 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.
+
+@strong{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.
+
+@cindex Memory use
+@node Memory use, Internal locking, Open tables, System
+@subsection How MySQL uses memory
+
+The list below indicates some of the ways that the @code{mysqld} server
+uses memory. Where applicable, the name of the server variable relevant
+to the memory use is given.
+
+@itemize @bullet
+@item
+The key buffer (variable @code{key_buffer_size}) is shared by all
+threads; Other buffers used by the server are allocated as
+needed. @xref{Server parameters}.
+
+@item
+Each connection uses some thread specific space; A stack (default 64K,
+variable @code{thread_stack}) a connection buffer (variable
+@code{net_buffer_length}), and a result buffer (variable
+@code{net_buffer_length}). The connection buffer and result buffer are
+dynamically enlarged up to @code{max_allowed_packet} when needed. When
+a query is running, a copy of the current query string is also allocated.
+
+@item
+All threads share the same base memory.
+
+@item
+Only the compressed ISAM / MyISAM tables are memory mapped. This is
+because the 32-bit memory space of 4GB is not large enough for most
+big tables. When systems with a 64-bit address-space become more
+common we may add general support for memory-mapping.
+
+@item
+Each request doing a sequential scan over a table allocates a read buffer
+(variable @code{record_buffer}).
+
+@item
+All joins are done in one pass and most joins can be done without even
+using a temporary table. Most temporary tables are memory-based (HEAP)
+tables. Temporary tables with a big record length (calculated as the
+sum of all column lengths) or that contain @code{BLOB} columns are
+stored on disk.
+
+One problem in @strong{MySQL} versions before 3.23.2 is that if a HEAP table
+exceeds the size of @code{tmp_table_size}, you get the error @code{The
+table tbl_name is full}. In newer versions this is handled by
+automatically changing the in-memory (HEAP) table to a disk-based
+(MyISAM) table as necessary. To work around this problem, you can
+increase the temporary table size by setting the @code{tmp_table_size}
+option to @code{mysqld}, or by setting the SQL option
+@code{SQL_BIG_TABLES} in the client program. @xref{SET OPTION, ,
+@code{SET OPTION}}. In @strong{MySQL} 3.20, the maximum size of the
+temporary table was @code{record_buffer*16}, so if you are using this
+version, you have to increase the value of @code{record_buffer}. You can
+also start @code{mysqld} with the @code{--big-tables} option to always
+store temporary tables on disk, however, this will affect the speed of
+many complicated queries.
+
+@item
+Most requests doing a sort allocates a sort buffer and 0-2 temporary
+files depending on the result set size. @xref{Temporary files}.
+
+@item
+Almost all parsing and calculating is done in a local memory store. No
+memory overhead is needed for small items and the normal slow memory
+allocation and freeing is avoided. Memory is allocated only for
+unexpectedly large strings (this is done with @code{malloc()} and
+@code{free()}).
+
+@item
+Each index file is opened once and the data file is opened once for each
+concurrently-running thread. For each concurrent thread, a table structure,
+column structures for each column, and a buffer of size @code{3 * n} is
+allocated (where @code{n} is the maximum row length, not counting @code{BLOB}
+columns). A @code{BLOB} uses 5 to 8 bytes plus the length of the @code{BLOB}
+data.
+
+@item
+For each table having @code{BLOB} columns, a buffer is enlarged dynamically
+to read in larger @code{BLOB} values. If you scan a table, a buffer as large
+as the largest @code{BLOB} value is allocated.
+
+@item
+Table handlers for all in-use tables are saved in a cache and managed as a
+FIFO. Normally the cache has 64 entries. If a table has been used by two
+running threads at the same time, the cache contains two entries for the
+table. @xref{Table cache}.
+
+@item
+A @code{mysqladmin flush-tables} command closes all tables that are not in
+use and marks all in-use tables to be closed when the currently executing
+thread finishes. This will effectively free most in-use memory.
+@end itemize
+
+@code{ps} and other system status programs may report that @code{mysqld}
+uses a lot of memory. This may be caused by thread-stacks on different
+memory addresses. For example, the Solaris version of @code{ps} counts
+the unused memory between stacks as used memory. You can verify this by
+checking available swap with @code{swap -s}. We have tested
+@code{mysqld} with commercial memory-leakage detectors, so there should
+be no memory leaks.
+
+@node Internal locking, Table locking, Memory use, System
+@subsection How MySQL locks tables
+
+You can find a discussion about different locking methods in the appendix.
+@xref{Locking methods}.
+
+All locking in @strong{MySQL} is deadlock-free. 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.
+
+The locking method @strong{MySQL} uses for @code{WRITE} locks works as follows:
+
+@itemize @bullet
+@item
+If there are no locks on the table, put a write lock on it.
+@item
+Otherwise, put the lock request in the write lock queue.
+@end itemize
+
+The locking method @strong{MySQL} uses for @code{READ} locks works as follows:
+
+@itemize @bullet
+@item
+If there are no write locks on the table, put a read lock on it.
+@item
+Otherwise, put the lock request in the read lock queue.
+@end itemize
+
+When a lock is released, the lock is made available to the threads
+in the write lock queue, then to the threads in the read lock queue.
+
+This means that if you have many updates on a table, @code{SELECT}
+statements will wait until there are no more updates.
+
+To work around this for the case where you want to do many @code{INSERT} and
+@code{SELECT} operations on a table, you can insert rows in a temporary
+table and update the real table with the records from the temporary table
+once in a while.
+
+This can be done with the following code:
+@example
+mysql> LOCK TABLES real_table WRITE, insert_table WRITE;
+mysql> insert into real_table select * from insert_table;
+mysql> delete from insert_table;
+mysql> UNLOCK TABLES;
+@end example
+
+You can use the @code{LOW_PRIORITY} options with @code{INSERT} if you
+want to prioritize retrieval in some specific cases. @xref{INSERT, ,
+@code{INSERT}}.
+
+You could also change the locking code in @file{mysys/thr_lock.c} to use a
+single queue. In this case, write locks and read locks would have the same
+priority, which might help some applications.
+
+@node Table locking, , Internal locking, System
+@subsection Table locking issues
+
+The table locking code in @strong{MySQL} is deadlock free.
+
+@strong{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
+row locking for most applications, but there are of course some
+pitfalls.
+
+For @code{BDB} tables, @strong{MySQL} only uses table locking of you
+explicitely lock the table with @code{LOCK TABLES} or execute an command that
+will modify every row in the table, like @code{ALTER TABLE}.
+
+In @strong{MySQL} 3.23.7 and above, you can insert rows into
+@code{MyISAM} tables at the same time as other threads are reading from
+the table. Note that currently this only works if there are no holes after
+deleted rows in the table at the time the insert is made.
+
+Table locking enables many threads to read from a table at the same
+time, but if a thread wants to write to a table, it must first get
+exclusive access. During the update all other threads that want to
+access this particular table will wait until the update is ready.
+
+As updates on tables normally are considered to be more important than
+@code{SELECT}, all statements that update a table have higher priority
+than statements that retrieve information from a table. This should
+ensure that updates are not 'starved' because one issues a lot of heavy
+queries against a specific table. (You can change this by using
+LOW_PRIORITY with the statement that does the update or
+@code{HIGH_PRIORITY} with the @code{SELECT} statement.
+
+Starting from @strong{MySQL 3.23.7} one can use the
+@code{max_write_lock_count} variable to force @strong{MySQL} to
+temporary give all @code{SELECT} statements, that waits for a table, a
+higher priority after a specific number of inserts on a table.
+
+Table locking is however not very good under the following senario:
+
+@itemize @bullet
+@item
+A client issues a @code{SELECT} that takes a long time to run.
+@item
+Another client then issues an @code{UPDATE} on a used table; This client
+will wait until the @code{SELECT} is finished
+@item
+Another client issues another @code{SELECT} statement on the same table; As
+@code{UPDATE} has higher priority than @code{SELECT}, this @code{SELECT}
+will wait for the @code{UPDATE} to finish. It will also wait for the first
+@code{SELECT} to finish!
+@end itemize
+
+Some possible solutions to this problem are:
+
+@itemize @bullet
+@item
+Try to get the @code{SELECT} statements to run faster; You may have to create
+some summary tables to do this.
+
+@item
+Start @code{mysqld} with @code{--low-priority-updates}. This will give
+all statements that update (modify) a table lower priority than a @code{SELECT}
+statement. In this case the last @code{SELECT} statement in the previous
+scenario would execute before the @code{INSERT} statement.
+
+@item
+You can give a specific @code{INSERT},@code{UPDATE} or @code{DELETE} statement
+lower priority with the @code{LOW_PRIORITY} attribute.
+
+@item
+Start @code{mysqld} with a low value for @strong{max_write_lock_count} to give
+@code{READ} locks after a certain number of @code{WRITE} locks.
+
+@item
+You can specify that all updates from a specific thread should be done with
+low priority by using the SQL command: @code{SET SQL_LOW_PRIORITY_UPDATES=1}.
+@xref{SET OPTION, , @code{SET OPTION}}.
+
+@item
+You can specify that a specific @code{SELECT} is very important with the
+@code{HIGH_PRIORITY} attribute. @xref{SELECT, , @code{SELECT}}.
+
+@item
+If you have problems with @code{INSERT} combined with @code{SELECT},
+switch to use the new @code{MyISAM} tables as these supports concurrent
+@code{SELECT}s and @code{INSERT}s.
+
+@item
+If you mainly mix @code{INSERT} and @code{SELECT} statements, the
+@code{DELAYED} attribute to @code{INSERT} will probably solve your problems.
+@xref{INSERT, , @code{INSERT}}.
+
+@item
+If you have problems with @code{SELECT} and @code{DELETE}, the @code{LIMIT}
+option to @code{DELETE} may help. @xref{DELETE, , @code{DELETE}}.
+@end itemize
+
+@node Data size, MySQL indexes, System, Performance
+@section Get your data as small as possible
+
+One of the most basic optimization 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
+done on smaller columns.
+
+@strong{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
+using the techniques listed below:
+
+@itemize @bullet
+@item
+Use the most efficient (smallest) types possible. @strong{MySQL} has a
+many specialized types that save disk space and memory.
+@item
+Use the smaller integer types if possible to get smaller tables. For
+example, @code{MEDIUMINT} is often better than @code{INT}.
+@item
+Declare columns to be @code{NOT NULL} if possible. It makes everything
+faster and you save one bit per column. Note that if you really need
+@code{NULL} in your application you should definitely use it, just avoid
+having it on all columns by default.
+@item
+If you don't have any variable-length columns (@code{VARCHAR},
+@code{TEXT} or @code{BLOB} columns), a fixed-size record format is
+used. This is faster but unfortunately may waste some space.
+@xref{MyISAM table formats}.
+@item
+Each table should have as short as possible primary index. This makes
+identification of one row easy and efficient.
+@item
+For each table you have to decide which storage/index method to
+use. @xref{Table types}.
+@item
+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
+first to get better compression of the index.
+@item
+If it's very likely that a column has a unique prefix on the first number
+of characters, it's better to only index this prefix. @strong{MySQL}
+supports an index on a part of a character column. Shorter indexes is
+faster not only because they take less disk space but also because they
+will give you more hits in the index cache and thus fewer disk
+seeks. @xref{Server parameters}.
+@item
+In some circumstances it can be beneficial to split a table that is
+scanned very often into two. This is especially true if it is a dynamic
+format table and it is possible to use a smaller static format table that
+can be used to find the relevant rows when scanning the table.
+@end itemize
+
+@node MySQL indexes, Query Speed, Data size, Performance
+@section How @strong{MySQL} uses indexes
+
+Indexes are used to find rows with a specific value of one column
+fast. Without an index @strong{MySQL} has to start with the first record
+and then read through the whole table until it finds the relevent
+rows. The bigger the table, the more this costs. If the table has an index
+for the colums in question, @strong{MySQL} can get fast a position to
+seek to in the middle of the data file without having to look at all the
+data. If a table has 1000 rows this is at least 100 times faster than
+reading sequentially. Note that if you need to access almost all 1000
+rows it is faster to read sequentially because we then avoid disk seeks.
+
+All @strong{MySQL} indexes (@code{PRIMARY}, @code{UNIQUE} and
+@code{INDEX}) are stored in B-trees. Strings are automatically prefix-
+and end-space compressed. @xref{CREATE INDEX, , @code{CREATE INDEX}}.
+
+Indexes are used to:
+@itemize @bullet
+@item
+Quickly find the rows that match a @code{WHERE} clause.
+
+@item
+Retrieve rows from other tables when performing joins.
+
+@item
+Find the @code{MAX()} or @code{MIN()} value for a specific indexed
+column.
+@example
+SELECT MIN(key_part2),MAX(key_part2) FROM table_name where key_part1=10
+@end example
+
+@item
+Sort or group a table if the sorting or grouping is done on a leftmost
+prefix of a usable key (e.g., @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 gthe index
+exactly, as long as all the not used 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
+
+@item
+In some cases a query can be optimized 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.
+
+@example
+SELECT key_part3 FROM table_name WHERE key_part1=1
+@end example
+
+@end itemize
+
+Suppose you issue the following @code{SELECT} statement:
+
+@example
+mysql> SELECT * FROM tbl_name WHERE col1=val1 AND col2=val2;
+@end example
+
+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
+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
+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)}.
+
+@strong{MySQL} can't use a partial index if the columns don't form a
+leftmost prefix of the index. Suppose you have the @code{SELECT}
+statements shown below:
+
+@example
+mysql> SELECT * FROM tbl_name WHERE col1=val1;
+mysql> SELECT * FROM tbl_name WHERE col2=val2;
+mysql> SELECT * FROM tbl_name WHERE col2=val2 AND col3=val3;
+@end example
+
+If an index exists on @code{(col1,col2,col3)}, only the first query
+shown above uses the index. The second and third queries do involve
+indexed columns, but @code{(col2)} and @code{(col2,col3)} are not
+leftmost prefixes of @code{(col1,col2,col3)}.
+
+@findex LIKE, and indexes
+@findex LIKE, and wildcards
+@cindex Indexes, and @code{LIKE}
+@cindex Wildcards, and @code{LIKE}
+@strong{MySQL} also uses indexes for @code{LIKE} comparisons if the argument
+to @code{LIKE} is a constant string that doesn't start with a wildcard
+character. For example, the following @code{SELECT} statements use indexes:
+
+@example
+mysql> select * from tbl_name where key_col LIKE "Patrick%";
+mysql> select * from tbl_name where key_col LIKE "Pat%_ck%";
+@end example
+
+In the first statement, only rows with @code{"Patrick" <= key_col <
+"Patricl"} are considered. In the second statement, only rows with
+@code{"Pat" <= key_col < "Pau"} are considered.
+
+The following @code{SELECT} statements will not use indexes:
+@example
+mysql> select * from tbl_name where key_col LIKE "%Patrick%";
+mysql> select * from tbl_name where key_col LIKE other_col;
+@end example
+
+In the first statement, the @code{LIKE} value begins with a wildcard character.
+In the second statement, the @code{LIKE} value is not a constant.
+
+@findex IS NULL, and indexes
+@cindex Indexes, and @code{IS NULL}
+Searching using @code{column_name IS NULL} will use indexes if column_name
+is an index.
+
+@strong{MySQL} normally uses the index that finds least number of rows. An
+index is used for columns that you compare with the following operators:
+@code{=}, @code{>}, @code{>=}, @code{<}, @code{<=}, @code{BETWEEN} and a
+@code{LIKE} with a non-wildcard 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
+index, a prefix of the index must be used in every @code{AND} group.
+
+The following @code{WHERE} clauses use indexes:
+@example
+... 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'" */
+... 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
+
+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 */
+@end example
+
+Note that in some cases @code{MySQL} will not use an index, even if one
+would be available. Some of the cases where this happens are:
+
+@itemize @bullet
+@item
+If the use of the index, would require @strong{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).
+Note that if you with such a query use @code{LIMIT} to only retrieve
+part of the rows, @strong{MySQL} will use an index anyway as it can this
+way much more quickly find the few rows to return in the result.
+@end itemize
+
+@node Query Speed, Tips, MySQL indexes, Performance
+@section Speed of queries that access or update data
+
+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 @strong{MySQL} will
+optimize 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.
+
+If your problem is with some explicit @strong{MySQL} function, you can
+always time this in the @strong{MySQL} client:
+
+@example
+mysql> select benchmark(1000000,1+1);
++------------------------+
+| benchmark(1000000,1+1) |
++------------------------+
+| 0 |
++------------------------+
+1 row in set (0.32 sec)
+@end example
+
+The above shows that @strong{MySQL} can execute 1,000,000 @code{+}
+expressions in 0.32 seconds on a @code{PentiumII 400MHz}.
+
+All @strong{MySQL} functions should be very optimized, 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.
+
+@menu
+* Estimating performance:: Estimating query performance
+* SELECT speed:: Speed of @code{SELECT} queries
+* Where optimizations:: How MySQL optimizes @code{WHERE} clauses
+* LEFT JOIN optimization:: How MySQL optimizes @code{LEFT JOIN}
+* LIMIT optimization:: How MySQL optimizes @code{LIMIT}
+* Insert speed:: Speed of @code{INSERT} queries
+* Update speed:: Speed of @code{UPDATE} queries
+* Delete speed:: Speed of @code{DELETE} queries
+@end menu
+
+@node Estimating performance, SELECT speed, Query Speed, Query Speed
+@subsection Estimating query performance
+
+In most cases you can estimate the performance by counting disk seeks.
+For small tables you can usually find the row in 1 disk seek (as the
+index is probably cached). For bigger tables, you can estimate that,
+(using B++ tree indexes), you will need: @code{log(row_count) /
+log(index_block_length / 3 * 2 / (index_length + data_pointer_length)) +
+1} seeks to find a row.
+
+In @strong{MySQL} an index block is usually 1024 bytes and the data
+pointer is usually 4 bytes, which gives for a 500,000 row table with a
+index length of 3 (medium integer) gives you:
+@code{log(500,000)/log(1024/3*2/(3+4)) + 1} = 4 seeks.
+
+As the above index would require about 500,000 * 7 * 3/2 = 5.2M,
+(assuming that the index buffers are filled to 2/3 (which is typical)
+you will probably have much of the index in memory and you will probably
+only need 1-2 calls to read data from the OS to find the row.
+
+For writes you will however need 4 seek requests (as above) to find
+where to place the new index and normally 2 seeks to update the index
+and write the row.
+
+Note that the above doesn't mean that your application will slowly
+degenerate by N log N! As long as everything is cached by the OS or SQL
+server things will only go marginally slower while the table gets
+bigger. After the data gets too big to be cached, things will start to
+go much slower until your applications is only bound by disk-seeks
+(which increase by N log N). To avoid this, increase the index cache as
+the data grows. @xref{Server parameters}.
+
+@node SELECT speed, Where optimizations, Estimating performance, Query Speed
+@subsection Speed of @code{SELECT} queries
+
+In general, when you want to make a slow @code{SELECT ... WHERE} faster, the
+first thing to check is whether or not you can add an index. @xref{MySQL
+indexes, , @strong{MySQL} indexes}. All references between different tables
+should usually be done with indexes. You can use the @code{EXPLAIN} command
+to determine which indexes are used for a @code{SELECT}.
+@xref{EXPLAIN, , @code{EXPLAIN}}.
+
+Some general tips:
+
+@itemize @bullet
+@item
+To help @strong{MySQL} optimize 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.). @strong{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.
+
+@item
+To sort an index and data according to an index, use @code{myisamchk
+--sort-index --sort-records=1} (if you want to sort on index 1). If you
+have a unique index from which you want to read all records in order
+according to that index, this is a good way to make that faster. Note
+however that this sorting isn't written optimally and will take a long
+time for a large table!
+@end itemize
+
+@cindex Optimizations
+@node Where optimizations, LEFT JOIN optimization, SELECT speed, Query Speed
+@subsection How MySQL optimizes @code{WHERE} clauses
+
+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
+@code{WHERE} in @code{DELETE} and @code{UPDATE} statements.
+
+Also note that this section is incomplete. @strong{MySQL} does many
+optimizations and we have not had time to document them all.
+
+Some of the optimizations performed by @strong{MySQL} are listed below:
+
+@itemize @bullet
+@item
+Removal of unnecessary parentheses:
+@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
+Constant folding:
+@example
+ (a<b AND b=c) AND a=5
+-> b>5 AND b=c AND a=5
+@end example
+@item
+Constant condition removal (needed because of constant folding):
+@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
+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.
+@item
+Early detection of invalid constant expressions. @strong{MySQL} quickly
+detects that some @code{SELECT} statements are impossible and returns no rows.
+@item
+@code{HAVING} is merged with @code{WHERE} if you don't use @code{GROUP BY}
+or group functions (@code{COUNT()}, @code{MIN()}...)
+@item
+For each sub-join, a simpler @code{WHERE} is constructed to get a fast
+@code{WHERE} evaluation for each sub-join and also to skip records as
+soon as possible.
+@cindex Constant table
+@cindex Table, constant
+@item
+All constant tables are read first, before any other tables in the query.
+A constant table is:
+@itemize @minus
+@item
+An empty table or a table with 1 row.
+@item
+A table that is used with a @code{WHERE} clause on a @code{UNIQUE}
+index, or a @code{PRIMARY KEY}, where all index parts are used with constant
+expressions and the index parts are defined as @code{NOT NULL}.
+@end itemize
+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;
+@end example
+
+@item
+The best join combination to join the tables is found by trying all
+possibilities. If all columns in @code{ORDER BY} and in @code{GROUP
+BY} come from the same table, then this table is preferred first when
+joining.
+@item
+If there is an @code{ORDER BY} clause and a different @code{GROUP BY} clause,
+or if the @code{ORDER BY} or @code{GROUP BY}
+contains columns from tables other than the first table in the join
+queue, a temporary table is created.
+@item
+If you use @code{SQL_SMALL_RESULT}, @strong{MySQL} will use an in-memory
+temporary table.
+@item
+As @code{DISTINCT} is converted to a @code{GROUP BY} on all columns,
+@code{DISTINCT} combined with @code{ORDER BY} will in many cases also need
+a temporary table.
+@item
+Each table index is queried and the best index that spans fewer than 30% of
+the rows is used. If no such index can be found, a quick table scan is used.
+@item
+In some cases, @strong{MySQL} can read rows from the index without even
+consulting the data file. If all columns used from the index are numeric,
+then only the index tree is used to resolve the query.
+@item
+Before each record is output, those that do not match the @code{HAVING} clause
+are skipped.
+@end itemize
+
+Some examples of queries that are very fast:
+
+@example
+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;
+mysql> SELECT ... FROM tbl_name
+ ORDER BY key_part1,key_part2,... LIMIT 10;
+mysql> SELECT ... FROM tbl_name
+ ORDER BY key_part1 DESC,key_part2 DESC,... LIMIT 10;
+@end example
+
+The following queries are resolved using only the index tree (assuming
+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;
+mysql> SELECT key_part2 FROM tbl_name GROUP BY key_part1;
+@end example
+
+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,...
+@end example
+
+@node LEFT JOIN optimization, LIMIT optimization, Where optimizations, Query Speed
+@subsection How MySQL optimizes @code{LEFT JOIN}
+
+@code{A LEFT JOIN B} is in @strong{MySQL} implemented as follows:
+
+@itemize @bullet
+@item
+The table @code{B} is set to be dependent on table @code{A} and all tables
+that @code{A} is dependent on.
+@item
+The table @code{A} is set to be dependent on all tables (except @code{B})
+that are used in the @code{LEFT JOIN} condition.
+@item
+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
+always read after all tables it is dependent on. If there is a circular
+dependence then @strong{MySQL} will issue an error.
+@item
+All standard @code{WHERE} optimizations are done.
+@item
+If there is a row in @code{A} that matches the @code{WHERE} clause, but there
+wasn't any row in @code{B} that matched the @code{LEFT JOIN} condition,
+then an extra @code{B} row is generated with all columns set to @code{NULL}.
+@item
+If you use @code{LEFT JOIN} to find rows that doesn't exist in some
+table and you have the following test: @code{column_name IS NULL} in the
+@code{WHERE} part, where column_name is a column that is declared as
+@code{NOT NULL}, then @code{MySQL} will stop searching after more rows
+(for a particular key combination) after it has found one row that
+matches the @code{LEFT JOIN} condition.
+@end itemize
+
+The table read order forced by @code{LEFT JOIN} and @code{STRAIGHT JOIN} will help
+the join optimizer (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
+@end example
+
+Then @strong{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
+@end example
+
+@node LIMIT optimization, Insert speed, LEFT JOIN optimization, Query Speed
+@subsection How MySQL optimizes @code{LIMIT}
+
+In some cases @strong{MySQL} will handle the query differently when you are
+using @code{LIMIT #} and not using @code{HAVING}:
+
+@itemize @bullet
+@item
+If you are selecting only a few rows with @code{LIMIT}, @strong{MySQL}
+will use indexes in some cases when it normally would prefer to do a
+full table scan.
+@item
+If you use @code{LIMIT #} with @code{ORDER BY}, @strong{MySQL} will end the
+sorting as soon as it has found the first @code{#} lines instead of sorting
+the whole table.
+@item
+When combining @code{LIMIT #} with @code{DISTINCT}, @strong{MySQL} will stop
+as soon as it finds @code{#} unique rows.
+@item
+In some cases a @code{GROUP BY} can be resolved by reading the key in order
+(or do a sort on the key) and then calculate summaries until the
+key value changes. In this case @code{LIMIT #} will not calculate any
+unnecessary @code{GROUP BY}'s.
+@item
+As soon as @strong{MySQL} has sent the first @code{#} rows to the client, it
+will abort the query.
+@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.
+@item
+The size of temporary tables uses the @code{LIMIT #} to calculate how much
+space is needed to resolve the query.
+@end itemize
+
+@node Insert speed, Update speed, LIMIT optimization, Query Speed
+@subsection Speed of @code{INSERT} queries
+
+The time to insert a record consists approximately of:
+
+@itemize @bullet
+@item
+Connect: (3)
+@item
+Sending query to server: (2)
+@item
+Parsing query: (2)
+@item
+Inserting record: (1 x size of record)
+@item
+Inserting indexes: (1 x number of indexes)
+@item
+Close: (1)
+@end itemize
+
+Where the numbers are somewhat proportional to the overall time. This
+does not take into consideration the initial overhead to open tables
+(which is done once for each concurrently-running query).
+
+The size of the table slows down the insertion of indexes by N log N
+(B-trees).
+
+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.
+@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
+@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
+is usually 20 times faster than using a lot of @code{INSERT} statements.
+@xref{LOAD DATA, , @code{LOAD DATA}}.
+@item
+It is possible with some extra work to make @code{LOAD DATA INFILE} run even
+faster when the table has many indexes. Use the following procedure:
+
+@enumerate
+@item
+Optionally create the table with @code{CREATE TABLE}. For example using
+@code{mysql} or Perl-DBI.
+
+@item
+Execute a @code{FLUSH TABLES} statement or the shell command @code{mysqladmin
+flush-tables}.
+
+@item
+Use @code{myisamchk --keys-used=0 -rq /path/to/db/tbl_name}. This will
+remove all usage of all indexes from the table.
+
+@item
+Insert data into the table with @code{LOAD DATA INFILE}. This will not
+update any indexes and will therefore be very fast.
+
+@item
+If you are going to only read the table in the future, run @code{myisampack}
+on it to make it smaller. @xref{Compressed format}.
+
+@item
+Recreate the indexes with @code{myisamchk -r -q
+/path/to/db/tbl_name}. This will create the index tree in memory before
+writing it to disk, which is much faster because it avoid lots of disk
+seeks. The resulting index tree is also perfectly balanced.
+
+@item
+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.
+@item
+You can speed up insertions by locking your tables:
+
+@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
+
+The main speed difference is that the index buffer is flushed to disk only
+once, after all @code{INSERT} statements have completed. Normally there would
+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.
+
+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:
+
+@example
+thread 1 does 1000 inserts
+thread 2, 3, and 4 does 1 insert
+thread 5 does 1000 inserts
+@end example
+
+If you don't use locking, 2, 3 and 4 will finish before 1 and 5. If you
+use locking, 2, 3 and 4 probably will not finish before 1 or 5, but the
+total time should be about 40% faster.
+
+As @code{INSERT}, @code{UPDATE} and @code{DELETE} operations are very
+fast in @strong{MySQL}, you will obtain better overall performance by
+adding locks around everything that does more than about 5 inserts or
+updates in a row. If you do very many inserts in a row, you could do a
+@code{LOCK TABLES} followed by a @code{UNLOCK TABLES} once in a while
+(about each 1000 rows) to allow other threads access to the table. This
+would still result in a nice performance gain.
+
+Of course, @code{LOAD DATA INFILE} is much faster still for loading data.
+@end itemize
+
+To get some more speed for both @code{LOAD DATA INFILE} and
+@code{INSERT}, enlarge the key buffer. @xref{Server parameters}.
+
+@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
+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.
+
+Also another way to get fast updates is to delay updates and then do
+many updates in a row later. Doing many updates in a row is much quicker
+than doing one at a time if you lock the table.
+
+Note that, with dynamic record format, updating a record to
+a longer total length may split the record. So if you do this often
+it is very important to @code{OPTIMIZE TABLE} sometimes.
+@xref{OPTIMIZE TABLE, , @code{OPTIMIZE TABLE}}.
+
+@node Delete speed, , Update speed, Query Speed
+@subsection Speed of @code{DELETE} queries
+
+The time to delete a record is exactly proportional to the number of
+indexes. To delete records more quickly, you can increase the size of
+the index cache. @xref{Server parameters}.
+
+It's also much faster to remove all rows than to remove a big part of the
+rows from a table.
+
+@node Tips, Benchmarks, Query Speed, Performance
+@section Other optimization tips
+
+Unsorted tips for faster systems:
+
+@itemize @bullet
+@item
+Use persistent connections to the database to avoid the connection
+overhead. If you can't use persistent connections and you are doing a
+lot of new connections to the database, you may want to change the value
+of the @code{thread_cache_size} variable. @xref{Server parameters}.
+@item
+Always check that all your queries really use the indexes you have created
+in the tables. In @strong{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
+lot. This is to avoid problems with table locking.
+@item
+The new @code{MyISAM} tables can insert rows in a table without deleted
+rows at the same time another table is reading from it. If this is important
+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
+In some cases it may make sense to introduce a column that is 'hashed'
+based on information from other columns. If this column is short and
+reasonably unique it may be much faster than a big index on many
+columns. In @strong{MySQL} its very easy to use this extra column:
+@code{SELECT * FROM table_name WHERE hash=MP5(concat(col1,col2))
+AND col_1='constant' AND col_2='constant'}
+@item
+For tables that changes a lot you should try to avoid all @code{VARCHAR}
+or @code{BLOB} columns. You will get dynamic row length as soon as you
+are using a single @code{VARCHAR} or @code{BLOB} columns. @xref{Table
+types}.
+@item
+It's not normally useful to split a table into different tables just
+because the rows gets 'big'. To access a row, the biggest performance
+hit is the disk seek to find the first byte of the row. After finding
+the data most new disks can read the whole row fast enough for most
+applications. The only cases it really matters to split up a table is if
+its a dynamic row size table (see above) that you can change to a fixed
+row size. Or if you very often need to scan the table and don't need
+most of the columns. @xref{Table types}.
+@item
+If you very often need to calculate things based on information from a
+lot of rows (like counts of things) it's probably much better to
+introduce a new table and update the counter in real time. An update of
+type @code{UPDATE table set count=count+1 where index_column=constant}
+is very fast!
+
+This is really important when you use databases like @strong{MySQL} that
+only has table locking (multiple readers / single writers). This will
+also give better performance with most databases as the row locking
+manager in this case will have less to do.
+@item
+If you need to collect statistics from big log tables, use summary tables
+instead of scanning the whole table. Maintaining the summaries should be
+much faster than trying to do statistics 'live'. It's much faster to
+re-generate new summary tables from the logs when things change
+(depending on business decisions) than to have to change the running
+application!
+@item
+If possible one should classify reports as 'live' or 'statistical',
+where data needed for statistical reports are only generated based on
+summary tables that are generated from the actual data.
+@item
+Take advantage of the fact that columns have default values. Insert
+values explicitly only when the value to be inserted differs from the
+default. This reduces the parsing that @strong{MySQL} need to do and
+improves the insert speed.
+@item
+In some cases it's convenient to pack and store data into a blob. In this
+case you have to add some extra code in your appliction to pack/unpack
+things in the blob but this may save a lot of accesses at some stage.
+This is practical when you have data that doesn't conform to a static
+table structure.
+@item
+Normally you should try to keep all data non-redundant (what
+is called 3rd normal form in database theory), but you should not be
+afraid of duplicating things or creating summary tables if you need these
+to gain more speed.
+@item
+Stored procedures or UDF (user defined functions) may be a good way to
+get more performance. In this case you should however always have a way
+to do this some other (slower) way if you use some database that doesn't
+support this.
+@item
+You can always gain something by caching queries/answers in your
+application and trying to do many inserts/updates at the same time. If
+your database supports lock tables (like @strong{MySQL} and Oracle),
+this should help to ensure that the index cache is only flushed once
+after all updates.
+@item
+Use @code{INSERT /*! DELAYED */} when you do not need to know when your
+data is written. This speeds things up because many records can be written
+with a single disk write.
+@item
+Use @code{INSERT /*! LOW_PRIORITY */} when you want your selects to be
+more important.
+@item
+Use @code{SELECT /*! HIGH_PRIORITY */} to get selects that jump the
+queue. That is the select is done even if there is somebody waiting to
+do a write.
+@item
+Use the multi-line @code{INSERT} statement to store many rows with one
+SQL command (many SQL servers supports this).
+@item
+Use @code{LOAD DATA INFILE} to load bigger amounts of data. This is
+faster than normal inserts and will be even faster when @code{myisamchk}
+is integrated in @code{mysqld}.
+@item
+Use @code{AUTO_INCREMENT} columns to make unique values.
+@item
+Use @code{OPTIMIZE TABLE} once in a while to avoid fragmentation when
+using dynamic table format. @xref{OPTIMIZE TABLE, , @code{OPTIMIZE TABLE}}.
+
+@item
+Use @code{HEAP} tables to get more speed when possible. @xref{Table
+types}.
+@item
+When using a normal web server setup, images should be stored as
+files. That is, store only a file reference in the database. The main
+reason for this is that a normal web server is much better at caching
+files than database contents. So it it's much easier to get a fast
+system if you are using files.
+@item
+Use in memory tables for non-critical data that are accessed often (like
+information about the last shown banner for users that doesn't have
+cookies).
+@item
+Columns with identical information in different tables should be
+declared identical and have identical names. Before version 3.23 you
+got slow joins otherwise.
+
+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
+interfaces for data storage that the different SQL servers support! For
+example by accessing the @strong{MySQL} @code{MyISAM} directly you could
+get a speed increase of 2-5 times compared to using the SQL interface.
+To be able to do this the data must however be on the same server as
+the application and usually it should only be accessed by one process
+(because external file locking is really slow). One could eliminate the
+above problems by introducing low-level @code{MyISAM} commands in the
+@strong{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.
+@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
+likely to be more compact than the text file (if you are using numerical
+data) and this will involve fewer disk accesses. You will also save
+code because you don't have to parse your text files to find line and
+column boundaries.
+@item
+You can also use replication to speed things up. @xref{Replication}.
+@item
+Declaring a table with @code{DELAY_KEY_WRITE=1} will make the updating of
+indexes faster as these are not logged to disk until the file is closed.
+The downside is that you should run @code{myisamchk} on these tables before
+you start @code{mysqld} to ensure that they are okay if something killed
+@code{mysqld} in the middle. As the key information can always be generated
+from the data you should not lose anything by using @code{DELAY_KEY_WRITE}.
+@end itemize
+
+@node Benchmarks, Design, Tips, Performance
+@section Using your own benchmarks
+
+You should definately benchmark your application and database to find
+out where the bottlenecks are. By fixing it (or by replacing the
+bottleneck with a 'dummy module') you can then easily identify the next
+bottleneck (and so on). Even if the overall performance for your
+application is sufficient you should at least make a plan for each
+bottleneck, and decide how to solve it if someday you really need the
+extra performance.
+
+For an example of portable benchmark programs look at the @strong{MySQL}
+benchmark suite. @xref{MySQL Benchmarks, , @strong{MySQL} Benchmarks}. You
+can take any program from this suite and modify it for your needs. By doing this,
+you can try different solutions to your problem and test which is really the
+fastest solution for you.
+
+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
+already in production.
+
+To avoid problems like this you should put some effort into benchmarking
+your whole application under the worst possible load! You can use Sasha's
+recent hack for this -
+@uref{http://www.mysql.com/Downloads/Contrib/mysql-bench-0.6.tar.gz, mysql-super-smack}.
+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 developement systems.
+
+@node Design, Design Limitations, Benchmarks, Performance
+@section Design choices
+
+@strong{MySQL} keeps row data and index data in separate files. Many (almost
+all) other databases mix row and index data in the same file. We believe that
+the @strong{MySQL} choice is better for a very wide range of modern systems.
+
+Another way to store the row data is to keep the information for each
+column in a separate area (examples are SDBM and Focus). This will cause a
+performance hit for every query that accesses more than one column. Because
+this degenerates so quickly when more than one column is accessed,
+we believe that this model is not good for general purpose databases.
+
+The more common case is that the index and data are stored together
+(like in Oracle/Sybase et al). In this case you will find the row
+information at the leaf page of the index. The good thing with this
+layout is that it, in many cases, depending on how well the index is
+cached, saves a disk read. The bad things with this layout is:
+
+@table @bullet
+@item
+Table scanning is much slower because you have to read through the indexes
+to get at the data.
+@item
+You can't use only the index table to retrieve data for a query.
+@item
+You lose a lot of space as you must duplicate indexes from the nodes
+(as you can't store the row in the nodes).
+@item
+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.
+@end table
+
+@node Design Limitations, Portability, Design, Performance
+@section MySQL design limitations/tradeoffs
+
+Because @strong{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.
+
+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.
+
+We are also working on some extensions to solve this problem for some
+common application niches.
+
+@node Portability, Internal use, Design Limitations, Performance
+@section Portability
+
+Because all SQL servers implement different parts of SQL, it takes work to
+write portable SQL applications. For very simple selects/inserts it is
+very easy but the more you need the harder it gets. If you want an
+application that is fast with many databases it becomes even harder!
+
+To make a complex application portable you need to choose a number of
+SQL servers that it should work with.
+
+You can use the @strong{MySQL} crash-me program/web-page
+@uref{http://www.mysql.com/information/crashme/choose.php} to find functions,
+types and limits you can use with a selection of database
+servers. Crash-me now tests far from everything possible but it
+is still comprehensive with about 450 things tested.
+
+For example, you shouldn't have column names longer than 18 characters
+if you want to be able to use Informix or DB2.
+
+Both the @strong{MySQL} benchmarks and crash-me programs are very
+database-independent. By taking a look at how we have handled this, you
+can get a feeling of what you have to do to write your application
+database-independent. The benchmarks themselves can be found in the
+@file{sql-bench} directory in the @strong{MySQL} source
+distribution. They are written in Perl with DBI database interface
+(which solves the access part of the problem).
+
+See @uref{http://www.mysql.com/information/benchmarks.html} the results
+from this benchmark.
+
+As you can see in these results all databases have some weak points. That
+is, they have different design compromises that lead to different
+behavior.
+
+If you strive for database independence you need to get a good feeling
+of each SQL server's bottlenecks. @strong{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
+(until they are flushed to disk). Transaction databases in general are
+not very good at generating summary tables from log tables as in this
+case row locking is almost useless.
+
+To get your application @emph{really} database-independent you need to define
+an easy extendable interface through which you manipulate your data. As
+C++ is available on most systems, it makes sense to use a C++ classes
+interface to the databases.
+
+If you use some specific feature for some database (like the
+@code{REPLACE} command in @strong{MySQL}), you should code a method for
+the other SQL servers to implement the same feature (but slower). With
+@strong{MySQL} you can use the @code{/*! */} syntax to add
+@strong{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, like in some
+web applications, a possibility is 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
+you can dynamically increase the cache and set the expire timeout higher
+until things get back to normal.
+
+In this case the table creation information should contain information
+of the initial size of the cache and how often the table should normally
+be refreshed.
+
+@node Internal use, , Portability, Performance
+@section What have we used MySQL for?
+
+During @strong{MySQL} initial development, the features of @strong{MySQL} were made to fit
+our largest customer. They handle data warehousing for a couple of the
+biggest retailers in Sweden.
+
+From all stores, we get weekly summaries of all bonus card transactions
+and we are expected to provide useful information for the store owners
+to help them find how their advertisement campaigns are affecting their
+customers.
+
+The data is quite huge (about 7 million summary transactions per month)
+and we have data for 4-10 years that we need to present to the users.
+We got weekly requests from the customers that they want to get
+'instant' access to new reports from this data.
+
+We solved this by storing all information per month in compressed
+'transaction' tables. We have a set of simple macros (script) that
+generates summary tables grouped by different criteria (product group,
+customer id, store ...) from the transaction tables. The reports are
+web pages that are dynamically generated by a small Perl script that
+parses a web page, executes the SQL statements in it and inserts the
+results. We would have used PHP or mod_perl instead but they were
+not available at that time.
+
+For graphical data we wrote a simple tool in @code{C} that can produce
+GIFs based on the result of a SQL query (with some processing of the
+result). This is also dynamically executed from the Perl script that
+parses the @code{HTML} files.
+
+In most cases a new report can simply be done by copying an existing
+script and modifying the SQL query in it. In some cases we will need to
+add more fields to an existing summary table or generate a new one, but
+this is also quite simple as we keep all transactions tables on disk.
+(Currently we have at least 50G of transactions tables and 200G of other
+customer data).
+
+We also let our customers access the summary tables directly with ODBC
+so that the advanced users can themselves experiment with the data.
+
+We haven't had any problems handling this with quite modest Sun Ultra
+SPARCstation (2x200 Mhz). We recently upgraded one of our servers to a 2
+CPU 400 Mhz UltraSPARC and we are now planning to start handling
+transactions on the product level, which would mean a ten-fold increase
+of data. We think we can keep up with this by just adding more disk to
+our systems.
+
+We are also experimenting with Intel-Linux to be able to get more CPU
+power cheaper. Now that we have the binary portable database format (new
+in 3.32) we will start to use this for some parts of the application.
+
+Our initial feelings are that Linux will perform much better on low to
+medium load but Solaris will perform better when you start to get a
+high load because of extreme disk IO, but we don't yet have anything
+conclusive about this. After some discussion with a Linux Kernel
+developer this might be a side effect of Linux giving so much resources
+to the batch job that the interactive performance gets very low. This
+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, Tools, Performance, Top
+@chapter The MySQL benchmark suite
+
+This should contain a technical description of the @strong{MySQL}
+benchmark suite (and @code{crash-me}) but that description is not
+written yet. Currently, you should look at the code and results in the
+@file{sql-bench} directory in the distribution (and of course on the Web page
+at @uref{http://www.mysql.com/crashme/choose.php} and (normally found in
+the @file{sql-bench} directory in the @strong{MySQL} distribution)).
+
+It is meant to be a benchmark that will tell any user what things a
+given SQL implementation performs well or poorly at.
+
+Note that this benchmark is single threaded so it measures the minimum
+time for the operations.
+
+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
+@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
+@end multitable
+
+In the above test @strong{MySQL} was run with a 8M index cache.
+
+Note that Oracle is not included because they asked to be removed. All
+Oracle benchmarks has to be passed by Oracle! We believe that makes
+Oracle benchmarks @strong{VERY} biased because the above benchmarks are
+supposed to show what a standard installation can do for a single
+client.
+
+@code{crash-me} tries to determine what features a database supports and
+what it's capabilities and limitations are by actually running
+queries. For example, it determines:
+
+@itemize @bullet
+@item
+What column types are supported
+@item
+How many indexes are supported
+@item
+What functions are supported
+@item
+How big a query can be
+@item
+How big a @code{VARCHAR} column can be
+@end itemize
+
+@node Tools, Maintenance, MySQL Benchmarks, Top
+@chapter MySQL Utilites
+
+@menu
+* Programs:: What do the executables do?
+* mysql:: The command line tool
+* mysqladmin:: Administering a @strong{MySQL} server
+* mysqldump:: Dumping the structure and data from @strong{MySQL} databases and tables
+* mysqlimport:: Importing data from text files
+* mysqlshow:: Showing databases, tables and columns
+* myisampack:: The @strong{MySQL} compressed read-only table generator
+@end menu
+
+@cindex Environment variables
+@node Programs, mysql, Tools, Tools
+@section Overview of the different MySQL programs
+
+All @strong{MySQL} clients that communicate with the server using the
+@code{mysqlclient} library use the following environment variables:
+
+@tindex MYSQL_UNIX_PORT environment variable
+@tindex Environment variable, MYSQL_UNIX_PORT
+@tindex MYSQL_TCP_PORT environment variable
+@tindex Environment variable, MYSQL_TCP_PORT
+@tindex MYSQL_PWD environment variable
+@tindex Environment variable, MYSQL_PWD
+@tindex MYSQL_DEBUG environment variable
+@tindex Environment variable, MYSQL_DEBUG
+@multitable @columnfractions .25 .75
+@item @strong{Name} @tab @strong{Description}
+@item @code{MYSQL_UNIX_PORT} @tab The default socket; used for connections to @code{localhost}
+@item @code{MYSQL_TCP_PORT} @tab The default TCP/IP port
+@item @code{MYSQL_PWD} @tab The default password
+@item @code{MYSQL_DEBUG} @tab Debug-trace options when debugging
+@item @code{TMPDIR} @tab The directory where temporary tables/files are created
+@end multitable
+
+Use of @code{MYSQL_PWD} is insecure.
+@xref{Connecting}.
+
+@tindex MYSQL_HISTFILE environment variable
+@tindex Environment variable, MYSQL_HISTFILE
+@tindex HOME environment variable
+@tindex Environment variable, HOME
+@cindex History file
+@cindex Command line history
+@tindex .mysql_history file
+The @file{mysql} client uses the file named in the @code{MYSQL_HISTFILE}
+environment variable to save the command line history. The default value for
+the history file is @file{$HOME/.mysql_history}, where @code{$HOME} is the
+value of the @code{HOME} environment variable. @xref{Environment variables}.
+
+All @strong{MySQL} programs take many different options. However, every
+@strong{MySQL} program provides a @code{--help} option that you can use
+to get a full description of the program's different options. For example, try
+@code{mysql --help}.
+
+You can override default options for all standard client programs with an
+option file. @ref{Option files}.
+
+The list below briefly describes the @strong{MySQL} programs:
+
+@table @code
+
+@cindex @code{myisamchk}
+@item myisamchk
+Utility to describe, check, optimize and repair @strong{MySQL} tables.
+Because @code{myisamchk} has many functions, it is described in its own
+chapter. @xref{Maintenance}.
+
+@cindex @code{make_binary_distribution}
+@item make_binary_distribution
+Makes a binary release of a compiled @strong{MySQL}. This could be sent
+by FTP to @file{/pub/mysql/Incoming} on @code{support.mysql.com} for the
+convenience of other @strong{MySQL} users.
+
+@cindex @code{msql2mysql}
+@item msql2mysql
+A shell script that converts @code{mSQL} programs to @strong{MySQL}. It doesn't
+handle all cases, but it gives a good start when converting.
+
+@cindex @code{mysqlaccess}
+@item mysqlaccess
+A script that checks the access privileges for a host, user and database
+combination.
+
+@cindex @code{mysqladmin}
+@item mysqladmin
+Utility for performing administrative operations, such as creating or
+dropping databases, reloading the grant tables, flushing tables to disk and
+reopening log files. @code{mysqladmin} can also be used to retrieve version,
+process and status information from the server.
+@xref{mysqladmin, , @code{mysqladmin}}.
+
+@cindex @code{mysqlbug}
+@item mysqlbug
+The @strong{MySQL} bug report script. This script should always be used when
+filing a bug report to the @strong{MySQL} list.
+
+@cindex @code{mysqld}
+@item mysqld
+The SQL daemon. This should always be running.
+
+@cindex @code{mysqldump}
+@item mysqldump
+Dumps a @strong{MySQL} database into a file as SQL statements or
+as tab-separated text files. Enhanced freeware originally by Igor Romanenko.
+@xref{mysqldump, , @code{mysqldump}}.
+
+@cindex @code{mysqlimport}
+@item mysqlimport
+Imports text files into their respective tables using @code{LOAD DATA
+INFILE}. @xref{mysqlimport, , @code{mysqlimport}}.
+
+@cindex @code{mysqlshow}
+@item mysqlshow
+Displays information about databases, tables, columns and indexes.
+
+@cindex @code{mysql_install_db}
+@item mysql_install_db
+Creates the @strong{MySQL} grant tables with default privileges. This is
+usually executed only once, when first installing @strong{MySQL}
+on a system.
+
+@cindex @code{replace}
+@item replace
+A utility program that is used by @code{msql2mysql}, but that has more
+general applicability as well. @code{replace} changes strings in place in
+files or on the standard input. Uses a finite state machine to match longer
+strings first. Can be used to swap strings. For example, this command
+swaps @code{a} and @code{b} in the given files:
+
+@example
+shell> replace a b b a -- file1 file2 ...
+@end example
+
+@cindex @code{safe_mysqld}
+
+@item safe_mysqld
+A script that starts the @code{mysqld} daemon with some safety features, such
+as restarting the server when an error occurs and logging runtime information
+to a log file.
+@end table
+
+@cindex Scripts
+@cindex @code{mysql}
+@node mysql, mysqladmin, Programs, Tools
+@section The command line tool
+
+@code{mysql} is a simple SQL shell (with GNU @code{readline} capabilities).
+It supports interactive and non-interactive use. When used interactively,
+query results are presented in an ASCII-table format. When used
+non-interactively (e.g., as a filter), the result is presented in
+tab-separated format. (The output format can be changed using command-line
+options.) You can run scripts simply like this:
+
+@example
+shell> mysql database < script.sql > output.tab
+@end example
+
+If you have problems due to insufficient memory in the client, use the
+@code{--quick} option! This forces @code{mysql} to use
+@code{mysql_use_result()} rather than @code{mysql_store_result()} to
+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.
+
+@code{mysql} supports the following options:
+
+@table @code
+@item -?, --help
+Display this help and exit
+@item -A, --no-auto-rehash
+No automatic rehashing. One has to use 'rehash' to get table and field
+completion. This gives a quicker start of mysql.
+@item -B, --batch
+Print results with a tab as separator, each row on a new line. Doesn't use
+history file.
+@item -C, --compress
+Use compression in server/client protocol.
+@item -#, --debug[=...]
+Debug log. Default is 'd:t:o,/tmp/mysql.trace'
+@item -D, --database=..
+Database to use; This is mainly useful in the @code{my.cnf} file.
+@item -e, --execute=...
+Execute command and quit. (Output like with --batch)
+@item -E, --vertical
+Print the output of a query (rows) vertically. Without this option you
+can also force this output by ending your statements with @code{\G}.
+@item -f, --force
+Continue even if we get a SQL error.
+@item -i, --ignore-space
+Ignore space after function names.
+@item -h, --host=...
+Connect to the given host.
+@item -H, --html
+Produce HTML output.
+@item -L, --skip-line-numbers
+Don't write line number for errors. Useful when one want's to compare result
+files that includes error messages.
+@item -n, --unbuffered
+Flush buffer after each query.
+@item -N, --skip-column-names
+Don't write column names in results.
+@item -O, --set-variable var=option
+Give a variable a value. @code{--help} lists variables.
+@item -o, --one-database
+Only update the default database. This is useful for skipping updates to
+other database in the update log.
+@item
+@item -p[password], --password[=...]
+Password to use when connecting to server. If password is not given on
+the command line, you will be prompted for it. Note that if you use the
+short form @code{-p} you can't have a space between the option and the
+password.
+@item -P --port=...
+TCP/IP port number to use for connection.
+@item -q, --quick
+Don't cache result, print it row-by-row. This may slow down the server
+if the output is suspended. Doesn't use history file.
+@item -r, --raw
+Write column values without escape conversion. Used with @code{--batch}
+@item -s, --silent
+Be more silent.
+@item -S --socket=...
+Socket file to use for connection.
+@item -t --table
+Output in table format. This is default in non-batch mode.
+@item -T, --exit-info
+Only used when debugging. --exit-info=0 will print some usage information
+on exit.
+@item -u, --user=#
+User for login if not current user.
+@item -U, --safe-updates[=#], --i-am-a-dummy[=#]
+Only allow @code{UPDATE} and @code{DELETE} that uses keys. See below for
+more information about this option. You can reset this option if you have
+it in your @code{my.cnf} file by using @code{--safe-updates=0}.
+@item -v, --verbose
+More verbose output (-v -v -v gives the table output format).
+@item -V, --version
+Output version information and exit.
+@item -w, --wait
+Wait and retry if connection is down instead of aborting.
+@end table
+
+If you type 'help' on the command line, @code{mysql} will print out the
+commands that it supports:
+
+@example
+mysql> help
+
+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
+edit (\e) Edit command with $EDITOR
+exit (\q) Exit mysql. Same as quit
+go (\g) Send command to mysql server
+ego (\G) Send command to mysql server; Display result vertically
+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
+status (\s) Get status information from the server
+use (\u) Use another database. Takes database name as argument
+@end example
+
+The @code{status} command gives you some information about the
+connection and the server you are using. If you are running in the
+@code{--safe-updates} mode, @code{status} will also print the values for
+the @code{mysql} variables that affects your queries.
+
+A useful startup option for beginners (introduced in @strong{MySQL} 3.23.11) is
+@code{--safe-mode} (or @code{--i-am-a-dummy} for users that has at some
+time done a @code{DELETE FROM table_name} but forgot the @code{WHERE}
+clause. When using this option, @code{mysql} sends the following
+command to the @strong{MySQL} server when opening the connection:
+
+@example
+SET SQL_SAFE_UPDATES=1,SQL_SELECT_LIMIT=#select_limit#,
+ SQL_MAX_JOIN_SIZE=#max_join_size#"
+@end example
+
+where @code{#select_limit#} and @code{#max_join_size#} are variables that
+can be set from the @code{mysql} command line. @xref{SET OPTION, @code{SET}}.
+
+The effect of the above is:
+
+@itemize @bullet
+@item
+You are not allowed to do an @code{UPDATE} or @code{DELETE} statements
+if you don't have a key constraint in the @code{WHERE} part. One can
+however force an @code{UPDATE/DELETE} by using @code{LIMIT}:
+@example
+UPDATE table_name SET not_key_column=# WHERE not_key_column=# LIMIT 1;
+@end example
+@item
+All big results are automatically limited to @code{#select_limit#} rows.
+@item
+@code{SELECT}'s that will probably need to examine more than
+@code{#max_join_size} row combinations will be aborted.
+@end itemize
+
+@node mysqladmin, mysqldump, mysql, Tools
+@section Administering a MySQL server
+
+Utility for performing administrative operations. The syntax is:
+
+@example
+shell> mysqladmin [OPTIONS] command [command-option] command ...
+@end example
+
+You can get a list of the options your version of @code{mysqladmin} supports
+by executing @code{mysqladmin --help}.
+
+The current @code{mysqladmin} supports the following commands:
+
+@multitable @columnfractions .3 .7
+@item create databasename @tab Create a new database.
+@item drop databasename @tab Delete a database and all its tables.
+@item extended-status @tab Gives an extended status message from the server.
+@item flush-hosts @tab Flush all cached hosts.
+@item flush-logs @tab Flush all logs.
+@item flush-tables @tab Flush all tables.
+@item flush-privileges @tab Reload grant tables (same as reload).
+@item kill id,id,... @tab Kill mysql threads.
+@item password @tab new-password Change old password to new-password.
+@item ping @tab Check if mysqld is alive.
+@item processlist @tab Show list of active threads in server.
+@item reload @tab Reload grant tables.
+@item refresh @tab Flush all tables and close and open logfiles.
+@item shutdown @tab Take server down.
+@item slave-start @tab Start slave replication thread.
+@item slave-stop @tab Stop slave replication thread.
+@item status @tab Gives a short status message from the server.
+@item variables @tab Prints variables available.
+@item version @tab Get version info from server.
+@end multitable
+
+All commands can be shortened to their unique prefix. For example:
+
+@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
+
+The @code{mysqladmin status} command result has the following columns:
+
+@multitable @columnfractions .3 .7
+@item Uptime @tab Number of seconds the @strong{MySQL} server has been up.
+@item Threads @tab Number of active threads (clients).
+@item Questions @tab Number of questions from clients since @code{mysqld} was started.
+@item Slow queries @tab Queries that have taken more than @code{long_query_time} seconds.
+@item Opens @tab How many tables @code{mysqld} has opened.
+@item Flush tables @tab Number of @code{flush ...}, @code{refresh} and @code{reload} commands.
+@item Open tables @tab Number of tables that are open now.
+@item Memory in use @tab Memory allocated directly by the mysqld code (only available when @strong{MySQL} is compiled with --with-debug).
+@item Max memory used @tab Maximum memory allocated directly by the mysqld code (only available when @strong{MySQL} is compiled with --with-debug).
+@end multitable
+
+If you do @code{myslqadmin shutdown} on a socket (in other words, on a
+the computer where @code{mysqld} is running), @code{mysqladmin} will
+wait until the @code{MySQL} @code{pid-file} is removed to ensure that
+the @code{mysqld server} has stopped properly.
+
+@node mysqldump, mysqlimport, mysqladmin, Tools
+@section Dumping the structure and data from MySQL databases and tables
+
+Utility to dump a database or a collection of database for backup or
+for transferring the data to another SQL server. The dump will contain SQL
+statements to create the table and/or populate the table.
+
+@example
+shell> mysqldump [OPTIONS] database [tables]
+OR mysqldump [OPTIONS] --databases [OPTIONS] DB1 [DB2 DB3...]
+OR mysqldump [OPTIONS] --all-databases [OPTIONS]
+@end example
+
+If you don't give any tables or use the @code{--databases} or
+@code{--all-databases}, the whole database(s) will be dumped.
+
+You can get a list of the options your version of @code{mysqldump} supports
+by executing @code{mysqldump --help}.
+
+Note that if you run @code{mysqldump} without @code{--quick} or
+@code{--opt}, @code{mysqldump} will load the whole result set into
+memory before dumping the result. This will probably be a problem if
+you are dumping a big database.
+
+@code{mysqldump} supports the following options:
+
+@table @code
+@item --add-locks
+Add @code{LOCK TABLES} before and @code{UNLOCK TABLE} after each table dump.
+(To get faster inserts into @strong{MySQL}).
+@item --add-drop-table
+Add a @code{drop table} before each create statement.
+@item -A, --all-databases
+Dump all the databases. This will be same as @code{--databases} with all
+databases selected.
+@item -a, --all
+Include all @strong{MySQL} specific create options.
+@item --allow-keywords
+Allow creation of column names that are keywords. This works by
+prefixing each column name with the table name.
+@item -c, --complete-insert
+Use complete insert statements (with column names).
+@item -C, --compress
+Compress all information between the client and the server if both support
+compression.
+@item -B, --databases
+To dump several databases. Note the difference in usage; In this case
+no tables are given. All name arguments are regarded as databasenames.
+@code{USE db_name;} will be included in the output before each new database.
+@item --delayed
+Insert rows with the @code{INSERT DELAYED} command.
+@item -e, --extended-insert
+Use the new multiline @code{INSERT} syntax. (Gives more compact and
+faster inserts statements.)
+@item -#, --debug[=option_string]
+Trace usage of the program (for debugging).
+@item --help
+Display a help message and exit.
+@item --fields-terminated-by=...
+@itemx --fields-enclosed-by=...
+@itemx --fields-optionally-enclosed-by=...
+@itemx --fields-escaped-by=...
+@itemx --lines-terminated-by=...
+These options are used with the @code{-T} option and have the same
+meaning as the corresponding clauses for @code{LOAD DATA INFILE}.
+@xref{LOAD DATA, , @code{LOAD DATA}}.
+@item -F, --flush-logs
+Flush log file in the @strong{MySQL} server before starting the dump.
+@item -f, --force,
+Continue even if we get a SQL error during a table dump.
+@item -h, --host=..
+Dump data from the @strong{MySQL} server on the named host. The default host
+is @code{localhost}.
+@item -l, --lock-tables.
+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 -n, --no-create-db
+'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 info (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!
+@item --opt
+Same as @code{--quick --add-drop-table --add-locks --extended-insert
+--lock-tables}. Should give you the fastest possible dump for reading
+into a @strong{MySQL} server.
+@item -pyour_pass, --password[=your_pass]
+The password to use when connecting to the server. If you specify
+no @samp{=your_pass} part,
+@code{mysqldump} you will be prompted for a password.
+@item -P port_num, --port=port_num
+The TCP/IP port number to use for connecting to a host. (This is used for
+connections to hosts other than @code{localhost}, for which Unix sockets are
+used.)
+@item -q, --quick
+Don't buffer query, dump directly to stdout; Uses @code{mysql_use_result()}
+to do this.
+@item -S /path/to/socket, --socket=/path/to/socket
+The socket file to use when connecting to @code{localhost} (which is the
+default host).
+@item --tables
+Overrides option --databases (-B).
+@item -T, --tab=path-to-some-directory
+Creates a @code{table_name.sql} file, that contains the SQL CREATE commands,
+and a @code{table_name.txt} file, that contains the data, for each give table.
+@strong{NOTE}: This only works if @code{mysqldump} is run on the same
+machine as the @code{mysqld} daemon. The format of the @code{.txt} file
+is made according to the @code{--fields-xxx} and @code{--lines--xxx} options.
+@item -u user_name, --user=user_name
+The @strong{MySQL} user name to use when connecting to the server. The
+default value is your Unix login name.
+@item -O var=option, --set-variable var=option
+Set the value of a variable. The possible variables are listed below.
+@item -v, --verbose
+Verbose mode. Print out more information 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!
+
+@example
+"--where=user='jimf'" "-wuserid>1" "-wuserid<1"
+@end example
+@item -O net_buffer_length=#, where # < 24M
+When creating multi-row-insert statements (as with option
+@code{--extended-insert} or @code{--opt}), @code{mysqldump} will create
+rows up to @code{net_buffer_length} length. If you increase this
+variable, you should also ensure that the @code{max_allowed_packet}
+variable in the @strong{MySQL} server is bigger than the
+@code{net_buffer_length}.
+@end table
+
+The most normal use of @code{mysqldump} is probably for making a backup of
+whole databases. @xref{Backup}.
+
+@example
+mysqldump --opt database > backup-file.sql
+@end example
+
+However, it's also very useful to populate another @strong{MySQL} server with
+information from a database:
+
+@example
+mysqldump --opt database | mysql ---host=remote-host -C database
+@end example
+
+It is possible to dump several databases with one command:
+
+@example
+mysqldump --databases database1 [database2 database3...] > my_databases.sql
+@end example
+
+If all the databases are wanted, one can use:
+
+@example
+mysqldump --all-databases > all_databases.sql
+@end example
+
+@node mysqlimport, mysqlshow, mysqldump, Tools
+@section Importing data from text files
+
+@code{mysqlimport} provides a command line interface to the @code{LOAD DATA
+INFILE} SQL statement. Most options to @code{mysqlimport} correspond
+directly to the same options to @code{LOAD DATA INFILE}.
+@xref{LOAD DATA, , @code{LOAD DATA}}.
+
+@code{mysqlimport} is invoked like this:
+
+@example
+shell> mysqlimport [options] database textfile1 [textfile2....]
+@end example
+
+For each text file named on the command line,
+@code{mysqlimport} strips any extension from the filename and uses the result
+to determine which table to import the file's contents into. For example,
+files named @file{patient.txt}, @file{patient.text} and @file{patient} would
+all be imported into a table named @code{patient}.
+
+@code{mysqlimport} supports the following options:
+
+@table @code
+@item -c, --columns=...
+This option takes a comma separated list of field names as an argument.
+The field list is passed to LOAD DATA INFILE MySQL sql command, which
+mysqlimport calls MySQL to execute. For more information, please see
+@code{LOAD DATA INFILE}. @xref{LOAD DATA, , @code{LOAD DATA}}.
+@item -C, --compress
+Compress all information between the client and the server if both support
+compression.
+
+@item -#, --debug[=option_string]
+Trace usage of the program (for debugging).
+
+@item -d, --delete
+Empty the table before importing the text file.
+
+@item --fields-terminated-by=...
+@itemx --fields-enclosed-by=...
+@itemx --fields-optionally-enclosed-by=...
+@itemx --fields-escaped-by=...
+@itemx --lines-terminated-by=...
+These options have the same meaning as the corresponding clauses for
+@code{LOAD DATA INFILE}. @xref{LOAD DATA, , @code{LOAD DATA}}.
+
+@item -f, --force
+Ignore errors. For example, if a table for a text file doesn't exist,
+continue processing any remaining files. Without @code{--force},
+@code{mysqlimport} exits if a table doesn't exist.
+
+@item --help
+Display a help message and exit.
+
+@item -h host_name, --host=host_name
+Import data to the @strong{MySQL} server on the named host. The default host
+is @code{localhost}.
+
+@item -i, --ignore
+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.
+
+@item -L, --local
+Read input files from the client. By default, text files are assumed to be on
+the server if you connect to @code{localhost} (which is the default host).
+
+@item -pyour_pass, --password[=your_pass]
+The password to use when connecting to the server. If you specify
+no @samp{=your_pass} part,
+@code{mysqlimport} you will be prompted for a password.
+
+@item -P port_num, --port=port_num
+The TCP/IP port number to use for connecting to a host. (This is used for
+connections to hosts other than @code{localhost}, for which Unix sockets are
+used.)
+
+@item -r, --replace
+The @code{--replace} and @code{--ignore} options control handling of input
+records that duplicate existing records on unique key values. If you specify
+@code{--replace}, new rows replace existing rows that have the same unique key
+value. If you specify @code{--ignore}, input rows that duplicate an existing
+row on a unique key value are skipped. If you don't specify either option, an
+error occurs when a duplicate key value is found, and the rest of the text
+file is ignored.
+
+@item -s, --silent
+Silent mode. Write output only when errors occur.
+
+@item -S /path/to/socket, --socket=/path/to/socket
+The socket file to use when connecting to @code{localhost} (which is the
+default host).
+
+@item -u user_name, --user=user_name
+The @strong{MySQL} user name to use when connecting to the server. The
+default value is your Unix login name.
+
+@item -v, --verbose
+Verbose mode. Print out more information what the program does.
+
+@item -V, --version
+Print version information and exit.
+@end table
+
+Here follows a sample run of using @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 Count 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 C o u n t 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 | Count Dracula |
++------+---------------+
+@end example
+
+@node mysqlshow, myisampack, mysqlimport, Tools
+@section Showing databases, tables and columns
+
+@code{mysqlshow} can be used to quickly look at which databases exist,
+their tables, and the table's columns.
+
+With the @code{mysql} program you can get the same information with the
+@code{SHOW} commands. @xref{SHOW}.
+
+@code{mysqlshow} is invoked like this:
+
+@example
+shell> mysqlshow [OPTIONS] [database [table [column]]]
+@end example
+
+@itemize @bullet
+@item
+If no database is given, all matching databases are shown.
+@item
+If no table is given, all matching tables in database are shown.
+@item
+If no column is given, all matching columns and column types in table
+are shown.
+@end itemize
+
+Note that in newer @strong{MySQL} versions you only see those
+database/tables/columns for which you have some privileges.
+
+If the last argument contains a shell or SQL wildcard (@code{*}, @code{?},
+@code{%} or @code{_}) then only what's matched by the wildcard is shown.
+This may cause some confusion when you try to display the columns for a
+table with a @code{_} as in this case @code{mysqlshow} only shows you
+the table names that matches the pattern. This is easily fixed by
+adding an extra @code{%} last on the command line (as a separate
+argument).
+
+@cindex @code{myisampack}
+@cindex @code{pack_isam}
+@node myisampack, , mysqlshow, Tools
+@section The MySQL compressed read-only table generator.
+
+@code{myisampack} is used to compress MyISAM tables and @code{pack_isam}
+is used to compress ISAM tables. Because ISAM tables are deprecated, we
+will only discuss @code{myisampack} here, but everything said about
+@code{myisampack} should also be true for @code{pack_isam}.
+
+@code{myisampack} works by compressing each column in the table separately.
+The information needed to decompress columns is read into memory when the
+table is opened. This results in much better performance when accessing
+individual records, because you only have to uncompress exactly one record, not
+a much larger disk block like when using Stacker on MS-DOS.
+Usually, @code{myisampack} packs the data file 40%-70%.
+
+@strong{MySQL} uses memory mapping (@code{mmap()}) on compressed tables and
+falls back to normal read/write file usage if @code{mmap()} doesn't work.
+
+There are currently two limitations with @code{myisampack}:
+@itemize @bullet
+@item
+After packing, the table is read only.
+@item
+@code{myisampack} can also pack @code{BLOB} or @code{TEXT} columns. The
+older @code{pack_isam} could not do this.
+@end itemize
+
+Fixing these limitations is on our TODO list but with low priority.
+
+@code{myisampack} is invoked like this:
+
+@example
+shell> myisampack [options] filename ...
+@end example
+
+Each filename should be the name of an index (@file{.MYI}) file. If you
+are not in the database directory, you should specify the pathname to the
+file. It is permissible to omit the @file{.MYI} extension.
+
+@code{myisampack} supports the following options:
+
+@table @code
+@item -b, --backup
+Make a backup of the table as @code{tbl_name.OLD}.
+
+@item -#, --debug=debug_options
+Output debug log. The @code{debug_options} string often is
+@code{'d:t:o,filename'}.
+
+@item -f, --force
+Force packing of the table even if it becomes bigger or if the temporary file
+exists. (@code{myisampack} creates a temporary file named @file{tbl_name.TMD}
+while it compresses the table. If you kill @code{myisampack}, the @file{.TMD}
+file may not be deleted. Normally, @code{myisampack} exits with an error if
+it finds that @file{tbl_name.TMD} exists. With @code{--force},
+@code{myisampack} packs the table anyway.
+
+@item -?, --help
+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.).
+
+@item -p #, --packlength=#
+Specify the record length storage size, in bytes. The value should be 1, 2
+or 3. (@code{myisampack} stores all rows with length pointers of 1, 2 or 3
+bytes. In most normal cases, @code{myisampack} can determine the right length
+value before it begins packing the file, but it may notice during the packing
+process that it could have used a shorter length. In this case,
+@code{myisampack} will print a note that the next time you pack the same file,
+you could use a shorter record length.)
+
+@item -s, --silent
+Silent mode. Write output only when errors occur.
+
+@item -t, --test
+Don't pack table, only test packing it.
+
+@item -T dir_name, --tmp_dir=dir_name
+Use the named directory as the location in which to write the temporary table.
+
+@item -v, --verbose
+Verbose mode. Write info about progress and packing result.
+
+@item -V, --version
+Display version information and exit.
+
+@item -w, --wait
+
+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
+
+The sequence of commands shown below illustrates a typical table compression
+session:
+
+@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
+
+The information printed by @code{myisampack} is described below:
+
+@table @code
+@item normal
+The number of columns for which no extra packing is used.
+
+@item empty-space
+The number of columns containing
+values that are only spaces; these will occupy 1 bit.
+
+@item empty-zero
+The number of columns containing
+values that are only binary 0's; these will occupy 1 bit.
+
+@item empty-fill
+The number of integer columns that don't occupy the full byte range of their
+type; these are changed to a smaller type (for example, an @code{INTEGER}
+column may be changed to @code{MEDIUMINT}).
+
+@item pre-space
+The number of decimal columns that are stored with leading space. In this
+case, each value will contain a count for the number of leading spaces.
+
+@item end-space
+The number of columns that have a lot of trailing space. In this case, each
+value will contain a count for the number of trailing spaces.
+
+@item table-lookup
+The column had only a small number of different values, and that were
+converted to an @code{ENUM} before Huffman compression.
+
+@item zero
+The number of columns for which all values are zero.
+
+@item Original trees
+The initial number of Huffman trees.
+
+@item After join
+The number of distinct Huffman trees left after joining
+trees to save some header space.
+@end table
+
+After a table has been compressed, @code{myisamchk -dvv} prints additional
+information about each field:
+
+@table @code
+@item Type
+The field type may contain the following descriptors:
+
+@table @code
+@item constant
+All rows have the same value.
+
+@item no endspace
+Don't store endspace.
+
+@item no endspace, not_always
+Don't store endspace and don't do end space compression for all values.
+
+@item no endspace, no empty
+Don't store endspace. Don't store empty values.
+
+@item table-lookup
+The column was converted to an @code{ENUM}.
+
+@item zerofill(n)
+The most significant @code{n} bytes in the value are always 0 and are not
+stored.
+
+@item no zeros
+Don't store zeros.
+
+@item always zero
+0 values are stored in 1 bit.
+@end table
+
+@item Huff tree
+The Huffman tree associated with the field.
+
+@item Bits
+The number of bits used in the Huffman tree.
+@end table
+
+After you have run @code{pack_isam}/@code{myisampack} you must run
+@code{isamchk}/@code{myisamchk} to recreate the index. At this time you
+can also sort the index blocks and create statistics that is needed for
+the @strong{MySQL} optimizer to work more efficiently.
+
+@example
+myisamchk -rq --analyze --sort-index table_name.MYI
+isamchk -rq --analyze --sort-index table_name.ISM
+@end example
+
+After you have installed the packed table into the @strong{MySQL} database
+directory you should do @code{mysqladmin flush-tables} to force @code{mysqld}
+to start using the new table.
+
+@node Maintenance, Adding functions, Tools, Top
+@chapter Maintaining a MySQL installation
+
+@menu
+* Table maintenance:: Table maintenance and crash recovery
+* Maintenance regimen:: Setting up a table maintenance regimen
+* Table-info:: Getting information about a table
+* Crash recovery:: Using @code{myisamchk} for crash recovery
+* Log files:: Log file maintenance
+@end menu
+
+@node Table maintenance, Maintenance regimen, Maintenance, Maintenance
+@section Using @code{myisamchk} for table maintenance and crash recovery
+
+Starting with @strong{MySQL} 3.23.13, you can check tables MyISAM with the
+@code{CHECK TABLE} command. @xref{CHECK TABLE}. You can repair tables
+with the @code{REPAIR TABLE} command. @xref{REPAIR TABLE}.
+
+To check/repair MyISAM tables (@code{.MYI} and @code{.MYD}) you should
+use the @code{myisamchk} utility. To check/repair ISAM tables
+(@code{.ISM} and @code{.ISD}) you should use the @code{isamchk}
+utility. @xref{Table types}.
+
+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 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
+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.
+@xref{OPTIMIZE TABLE, , @code{OPTIMIZE TABLE}}.
+
+@menu
+* myisamchk syntax:: @code{myisamchk} invocation syntax
+* myisamchk memory:: @code{myisamchk} memory usage
+@end menu
+
+@node myisamchk syntax, myisamchk memory, Table maintenance, Table maintenance
+@subsection @code{myisamchk} invocation syntax
+
+@code{myisamchk} is invoked like this:
+
+@example
+shell> myisamchk [options] tbl_name
+@end example
+
+The @code{options} specify what you want @code{myisamchk} to do. They are
+described below. (You can also get a list of options by invoking
+@code{myisamchk --help}.) With no options, @code{myisamchk} simply checks your
+table. To get more information or to tell @code{myisamchk} to take corrective
+action, specify options as described below and in the following sections.
+
+@code{tbl_name} is the database table you want to check. If you run
+@code{myisamchk} somewhere other than in the database directory, you must
+specify the path to the file, because @code{myisamchk} has no idea where your
+database is located. Actually, @code{myisamchk} doesn't care whether or not
+the files you are working on are located in a database directory; you can
+copy the files that correspond to a database table into another location and
+perform recovery operations on them there.
+
+You can name several tables on the @code{myisamchk} command line if you
+wish. You can also specify a name as an index file
+name (with the @file{.MYI} suffix), which allows you to specify all
+tables in a directory by using the pattern @file{*.MYI}.
+For example, if you are in a database directory, you can check all the
+tables in the directory like this:
+
+@example
+shell> myisamchk *.MYI
+@end example
+
+If you are not in the database directory, you can check all the tables there
+by specifying the path to the directory:
+
+@example
+shell> myisamchk /path/to/database_dir/*.MYI
+@end example
+
+You can even check all tables in all databases by specifying a wildcard
+with the path to the @strong{MySQL} data directory:
+
+@example
+shell> myisamchk /path/to/datadir/*/*.MYI
+@end example
+
+@code{myisamchk} supports the following options:
+
+@menu
+* myisamchk general options::
+* myisamchk check options::
+* myisamchk repair options::
+* myisamchk other options::
+@end menu
+
+@node myisamchk general options, myisamchk check options, myisamchk syntax, myisamchk syntax
+@subsubsection General options for myisamchk
+
+@table @code
+@item -# or --debug=debug_options
+Output debug log. The @code{debug_options} string often is
+@code{'d:t:o,filename'}.
+@item -? or --help
+Display a help message and exit.
+@item -O var=option, --set-variable var=option
+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 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{key_buffer_size} is only used when you check the table with @code{-e} or
+repair it with @code{-o}.
+@code{sort_buffer_size} is used when you repair the table with @code{-r}.
+
+If you want a faster repair, set the above variables to about 1/4 of your
+available memory. You can set both variables to big values as only one
+of the above buffers will be used at a time.
+
+@item -s or --silent
+Silent mode. Write output only when errors occur. You can use @code{-s}
+twice (@code{-ss}) to make @code{myisamchk} very silent.
+@item -v or --verbose
+Verbose mode. Print more information. This can be used with @code{-d} and
+@code{-e}. Use @code{-v} multiple times (@code{-vv}, @code{-vvv}) for more
+verbosity!
+@item -V or --version
+Print the @code{myisamchk} version and exit.
+@item -w or, --wait
+Instead of giving an error if the table is locked, wait until the table
+is unlocked before continuing. Note that if you are running @code{mysqld}
+on the table with @code{--skip-locking}, the table is can only be locked
+by another @code{myisamchk} command.
+@end table
+
+@node myisamchk check options, myisamchk repair options, myisamchk general options, myisamchk syntax
+@subsubsection Check options for myisamchk
+
+@table @code
+@item -c or --check
+Check table for errors. This is the default operation if you are not
+giving @code{myisamchk} any options that overrides this.
+
+@item -e or --extend-check
+Check the table VERY thoroughly (which is quite slow if you have many
+indexes). This options should only be used extreme cases. Normally,
+@code{myisamchk} or @code{myisamchk --medium-check} should in most
+cases be able to find out if there is any errors in the table.
+
+If you are using @code{--extended-check} and have much memory, you should
+increase the value of @code{key_buffer_size} a lot!
+
+@item -F or --fast
+Check only tables that hasn't been closed properly.
+@item -C or --check-only-changed
+Check only tables that has changed since last check.
+@item -f or --force
+Restart @code{myisamchk} with @code{-r} (repair) on the table, if
+@code{myisamchk} finds any errors in the table.
+@item -i or --information
+Print informational statistics about the table that is checked.
+@item -m or --medium-check
+Faster than extended-check, but only finds 99.99% of all errors.
+Should however be good enough for most cases.
+@item -U or --update-state
+Store in the @file{.MYI} file when the table was checked and if the
+table was crashed. This should be used to get full benefit of the
+@code{--check-only-changed} option, but you shouldn't use this if
+option if the @code{mysqld} server is using the table and you are
+running @code{mysqld} with @code{--skip-locking}.
+@item -T or --read-only
+Don't mark table as checked. This is useful if you use @code{myisamchk}
+to check a table that is in use by some other application that doesn't
+use locking (like @code{mysqld --skip-locking})
+@end table
+
+@node myisamchk repair options, myisamchk other options, myisamchk check options, myisamchk syntax
+@subsubsection Repair options for myisamchk
+
+The following options are used if you start @code{myisamchk} with
+@code{-r} or @code{-o}:
+
+@table @code
+@item -D # or --data-file-length=#
+Max length of data file (when recreating data file when it's 'full')
+@item -e or --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.
+@item -f or --force
+Overwrite old temporary files (@code{table_name.TMD}) instead of aborting.
+@item -k # or keys-used=#
+If you are using ISAM, tells the ISAM table handler to update only the
+first @code{#} indexes. If you are using @code{MyISAM} tells which keys
+to use, where each binary bit stands for one key (First key is bit 0).
+This can be used to get faster inserts! Deactivated indexes can be
+reactivated by using @code{myisamchk -r}. keys.
+@item -l or --no-symlinks
+Do not follow symbolic links. Normally @code{myisamchk} repairs the
+table a symlink points at.
+@item -r or --recover
+Can fix almost anything except unique keys that aren't unique.
+(which is a extremely unlikely error with ISAM/MyISAM tables).
+If you want to recover a table, this is the option to try first. Only if
+myisamchk reports that the table can't be recovered by @code{-r}, you
+should then try @code{-o}. (Note that in the unlikely case that @code{-r}
+fails, the data file is still intact).
+If you have lot's of memory, you should increase the size of
+@code{sort_buffer_size}!
+@item -o or --safe-recover
+Uses an old recovery method (reads through all rows in order and updates
+all index trees based on the found rows); this is a magnitude slower
+than @code{-r}, but can handle a couple of very unlikely cases that
+@code{-r} cannot handle. This recovery method also uses much less disk
+space than @code{-r}. Normally one should always first repair with
+@code{-r} and only if this fails use @code{-o}.
+
+If you have lot's of memory, you should increase the size of
+@code{key_buffer_size}!
+@item --character-sets-dir=...
+Directory where character sets are stored.
+@item --set-character-set=name
+Change the character set used by the index
+@item .t or --tmpdir=path
+Path where to store temporary files. If this is not set, @code{myisamchk} will
+use the environment variable @code{TMPDIR} for this.
+@item -q or --quick
+Faster repair by not modifying the data file. One can give a second
+@code{-q} to force @code{myisamchk} to modify the original datafile in case
+of duplicate keys
+@item -u or --unpack
+Unpack file packed with myisampack.
+@end table
+
+@node myisamchk other options, , myisamchk repair options, myisamchk syntax
+@subsubsection Other options for myisamchk
+
+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
+join the tables and which keys it should use.
+@code{myisamchk --describe --verbose table_name'} or using @code{SHOW KEYS} in
+@strong{MySQL}
+@item -d or --description
+Prints some information about table.
+@item -A or --set-auto-increment[=value]
+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.
+@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.
+@item -R or --sort-records=#
+Sorts records according to an index. This makes your data much more localized
+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!)
+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.
+@end table
+
+@node myisamchk memory, , myisamchk syntax, Table maintenance
+@subsection @code{myisamchk} memory usage
+
+Memory allocation is important when you run @code{myisamchk}.
+@code{myisamchk} uses no more memory than you specify with the @code{-O}
+options. If you are going to use @code{myisamchk} on very large files,
+you should first decide how much memory you want it to use. The default
+is to use only about 3M to fix things. By using larger values, you can
+get @code{myisamchk} to operate faster. For example, if you have more
+than 32M RAM, you could use options such as these (in addition to any
+other options you might specify):
+
+@example
+shell> myisamchk -O sort=16M -O key=16M -O read=1M -O write=1M ...
+@end example
+
+Using @code{-O sort=16M} should probably be enough for most cases.
+
+Be aware that @code{myisamchk} uses temporary files in @code{TMPDIR}. If
+@code{TMPDIR} points to a memory file system, you may easily get out of
+memory errors. If this happens, set @code{TMPDIR} to point at some directory
+with more space and restart @code{myisamchk}
+
+When repairing, @code{myisamchk} will also nead a lot of diskspace:
+
+@itemize @bullet
+@item
+Double the size of the record file (The original one and a copy). This
+space is not needed if one does a repair with @code{--quick}, as in this
+case only the index file will be recreated. This space is needed on the
+same disk as the original record file!
+@item
+Space for the new index file (that replaces the old one; The old
+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{--repair} (but not when using @code{--safe-repair}, 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
+@code{myisamchk -dv table}.
+This space is allocated on the temporary disk (specified by @code{TMPDIR} or
+@code{--tmpdir=#}).
+@end itemize
+
+If you have a problem with disk space during repair, you can try to use
+@code{--safe-repair} instead of @code{--repair}.
+
+@node Maintenance regimen, Table-info, Table maintenance, Maintenance
+@section Setting up a table maintenance regimen
+
+It is a good idea to perform table checks on a regular basis rather than
+waiting for problems to occur. For maintenance purposes, you can use
+@code{myisamchk -s} to check tables. The @code{-s} option causes
+@code{myisamchk} to run in silent mode, printing messages only when errors
+occur.
+
+@tindex .pid (process ID) file
+It's a good idea to check tables when the server starts up.
+For example, whenever the machine has done a reboot in the middle of an
+update, you usually need to check all the tables that could have been
+affected. (This is an ``expected crashed table''.) You could add a test to
+@code{safe_mysqld} that runs @code{myisamchk} to check all tables that have
+been modified during the last 24 hours if there is an old @file{.pid}
+(process ID) file left after a reboot. (The @file{.pid} file is created by
+@code{mysqld} when it starts up and removed when it terminates normally. The
+presence of a @file{.pid} file at system startup time indicates that
+@code{mysqld} terminated abnormally.)
+
+An even better test would be to check any table whose last-modified time
+is more recent than that of the @file{.pid} file.
+
+You should also check your tables regularly during normal system
+operation. At MySQL AB, we run a @code{cron} job to check all our important
+tables once a week, using a line like this in a @file{crontab} file:
+
+@example
+35 0 * * 0 /path/to/myisamchk -s /path/to/datadir/*/*.MYI
+@end example
+
+This prints out information about crashed tables so we can examine and repair
+them when needed.
+
+As we haven't had any unexpectedly crashed tables (tables that become
+corrupted for reasons other than hardware trouble)
+for a couple of years now (this is really true), once a week is
+more than enough for us.
+
+We recommend that to start with, you execute @code{myisamchk -s} each
+night on all tables that have been updated during the last 24 hours,
+until you come to trust @strong{MySQL} as much as we do.
+
+@node Table-info, Crash recovery, Maintenance regimen, Maintenance
+@section Getting information about a table
+
+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
+@item myisamchk -d tbl_name
+Runs @code{myisamchk} in ``describe mode'' to produce a description of your
+table. If you start the @strong{MySQL} server using the @code{--skip-locking}
+option, @code{myisamchk} may report an error for a table that is updated while
+it runs. However, because @code{myisamchk} doesn't change the table in describe
+mode, there isn't any risk of destroying data.
+
+@item myisamchk -d -v tbl_name
+To produce more information about what @code{myisamchk} is doing, add @code{-v}
+to tell it to run in verbose mode.
+
+@item myisamchk -eis tbl_name
+Shows only the most important information from a table. It is slow because it
+must read the whole table.
+
+@item myisamchk -eiv tbl_name
+This is like @code{-eis}, but tells you what is being done.
+@end table
+
+Example of @code{myisamchk -d} output:
+@example
+MyISAM file: company.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
+
+Example of @code{myisamchk -d -v} output:
+@example
+MyISAM file: company
+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
+
+Example of @code{myisamchk -eis} output:
+@example
+Checking MyISAM file: company
+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
+
+Example of @code{myisamchk -eiv} output:
+@example
+Checking MyISAM file: company
+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 and 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
+
+Here are the sizes of the data and index files for the table used in the
+preceding examples:
+
+@example
+-rw-rw-r-- 1 monty tcx 317235748 Jan 12 17:30 company.MYD
+-rw-rw-r-- 1 davida tcx 96482304 Jan 12 18:35 company.MYM
+@end example
+
+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
+@item ISAM file
+Name of the ISAM (index) file.
+
+@item Isam-version
+Version of ISAM format. Currently always 2.
+
+@item Creation time
+When the data file was created.
+
+@item Recover time
+When the index/data file was last reconstructed.
+
+@item Data records
+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}.
+
+@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
+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}.
+
+@item Datafile pointer
+The size of the data file pointer, in bytes. It is usually 2, 3, 4 or 5
+bytes. Most tables manage with 2 bytes, but this cannot be controlled
+from @strong{MySQL} yet. For fixed tables, this is a record address. For
+dynamic tables, this is a byte address.
+
+@item Keyfile pointer
+The size of the index file pointer, in bytes. It is usually 1, 2 or 3
+bytes. Most tables manage with 2 bytes, but this is calculated
+automatically by @strong{MySQL}. It is always a block address.
+
+@item Max datafile length
+How long the table's data file (@code{.MYD} file) can become, in bytes.
+
+@item Max keyfile length
+How long the table's key file (@code{.MYI} file) can become, in bytes.
+
+@item Recordlength
+How much space each record takes, in bytes.
+
+@item Record format
+The format used to store table rows.
+The examples shown above use @code{Fixed length}.
+Other possible values are @code{Compressed} and @code{Packed}.
+
+@item table description
+A list of all keys in the table. For each key, some low-level information
+is presented:
+
+@table @code
+@item Key
+This key's number.
+
+@item Start
+Where in the record this index part starts.
+
+@item Len
+How long this index part is. For packed numbers, this should always be
+the full length of the column. For strings, it may be shorter than the full
+length of the indexed column, because you can index a prefix of a string
+column.
+
+@item Index
+@code{unique} or @code{multip.} (multiple). Indicates whether or not one value
+can exist multiple times in this index.
+
+@item Type
+What data-type this index part has. This is an ISAM data-type
+with the options @code{packed}, @code{stripped} or @code{empty}.
+
+@item Root
+Address of the root index block.
+
+@item Blocksize
+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
+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
+
+@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
+high (very near the theoretical maximum).
+
+@item Packed
+@strong{MySQL} tries to pack keys with a common suffix. This can only be used
+for @code{CHAR}/@code{VARCHAR}/@code{DECIMAL} keys. For long strings like
+names, this can significantly reduce the space used. In the third example
+above, the 4th key is 10 characters long and a 60% reduction in space is
+achieved.
+
+@item Max levels
+How deep the B-tree for this key is. Large tables with long keys get high
+values.
+
+@item Records
+How many rows are in the table.
+
+@item M.recordlength
+The average record length. For tables with fixed-length records, this is the
+exact record length.
+
+@item Packed
+@strong{MySQL} strips spaces from the end of strings. The @code{Packed}
+value indicates the percentage savings achieved by doing this.
+
+@item Recordspace used
+What percentage of the data file is used.
+
+@item Empty space
+What percentage of the data file is unused.
+
+@item Blocks/Record
+Average number of blocks per record (i.e., 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}.
+
+@item Recordblocks
+How many blocks (links) are used. For fixed format, this is the same as the number
+of records.
+
+@item Deleteblocks
+How many blocks (links) are deleted.
+
+@item Recorddata
+How many bytes in the data file are used.
+
+@item Deleted data
+How many bytes in the data file are deleted (unused).
+
+@item Lost space
+If a record is updated to a shorter length, some space is lost. This is
+the sum of all such losses, in bytes.
+
+@item Linkdata
+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
+
+If a table has been compressed with @code{myisampack}, @code{myisamchk
+-d} prints additional information about each table column. See
+@ref{myisampack, , @code{myisampack}}, for an example of this
+information and a description of what it means.
+
+@node Crash recovery, Log files, Table-info, Maintenance
+@section Using @code{myisamchk} for crash recovery
+
+If you run @code{mysqld} with @code{--skip-locking} (which is the default on
+some systems, like Linux), you can't reliably use @code{myisamchk} to
+check a table when @code{mysqld} is using the same table. If you
+can be sure that no one is accessing the tables through @code{mysqld}
+while you run @code{myisamchk}, you only have to do @code{mysqladmin
+flush-tables} before you start checking the tables. If you can't
+guarantee the above, then you must take down @code{mysqld} while you
+check the tables. If you run @code{myisamchk} while @code{mysqld} is updating
+the tables, you may get a warning that a table is corrupt even if it
+isn't.
+
+If you are not using @code{--skip-locking}, you can use @code{myisamchk}
+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
+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}.
+
+The file format that @strong{MySQL} uses to store data has been extensively
+tested, but there are always external circumstances that may cause database
+tables to become corrupted:
+
+@itemize @bullet
+@item
+The @code{mysqld} process being killed in the middle of a write.
+@item
+Unexpected shutdown of the computer (for example, if the computer is turned
+off).
+@item
+A hardware error.
+@end itemize
+
+This chapter describes how to check for and deal with data corruption
+in @strong{MySQL} databases. If your tables get corrupted a lot you should
+try to find the reason for this! @xref{Debugging server}.
+
+When performing crash recovery, it is important to understand that each table
+@code{tbl_name} in a database corresponds to three files in the database
+directory:
+
+@multitable @columnfractions .2 .8
+@item @strong{File} @tab @strong{Purpose}
+@item @file{tbl_name.frm} @tab Table definition (form) file
+@item @file{tbl_name.MYD} @tab Data file
+@item @file{tbl_name.MYI} @tab Index file
+@end multitable
+
+Each of these three file types is subject to corruption in various ways, but
+problems occur most often in data files and index files.
+
+@code{myisamchk} works by creating a copy of the @file{.MYD} (data) file
+row by row. It ends the repair stage by removing the old @file{.MYD}
+file and renaming the new file to the original file name. If you use
+@code{--quick}, @code{myisamchk} does not create a temporary @file{.MYD}
+file, but instead assumes that the @file{.MYD} file is correct and only
+generates a new index file without touching the @file{.MYD} file. This
+is safe, because @code{myisamchk} automatically detects if the
+@file{.MYD} file is corrupt and aborts the repair in this case. You can
+also give two @code{--quick} options to @code{myisamchk}. In this case,
+@code{myisamchk} does not abort on some errors (like duplicate key) but
+instead tries to resolve them by modifying the @file{.MYD}
+file. Normally the use of two @code{--quick} options is useful only if
+you have too little free disk space to perform a normal repair. In this
+case you should at least make a backup before running @code{myisamchk}.
+
+@menu
+* Check:: How to check tables for errors
+* Repair:: How to repair tables
+* Optimization:: Table optimization
+@end menu
+
+@cindex Checking tables for errors
+@node Check, Repair, Crash recovery, Crash recovery
+@subsection How to check tables for errors
+
+To check a 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
+to check a table, you should normally run @code{myisamchk} without options or
+with either the @code{-s} or @code{--silent} option.
+
+@item myisamchk -m tbl_name
+This finds 99.999% of all errors. It checks first all index for errors and
+then it reads through all rows. It calculates a checksum for all keys in
+the rows and verifies that they checksum matches the checksum for the keys
+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
+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
+going, up through a maximum of 20 errors. In normal usage, a simple
+@code{myisamchk} (with no arguments other than the table name) is sufficient.
+
+@item myisamchk -e -i tbl_name
+Like the previous command, but the @code{-i} option tells @code{myisamchk} to
+print some informational statistics, too.
+@end table
+
+@node Repair, Optimization, Check, Crash recovery
+@subsection How to repair tables
+
+In the following we only talk about using @code{myisamchk} on @code{MyISAM}
+tables (extensions @code{.MYI} and @code{.MYD}). If you are using
+@code{ISAM} tables (extensions @code{.ISM} and @code{.ISD}), you should use
+@code{isamchk} instead.
+
+The symptoms of a corrupted table are usually that queries abort unexpectedly
+and you observe errors such as these:
+
+@itemize @bullet
+@item
+@file{tbl_name.frm} is locked against change
+@item
+Can't find file @file{tbl_name.MYI} (Errcode: ###)
+@item
+Got error ### from table handler (Error 135 is an exception in this case)
+@item
+Unexpected end of file
+@item
+Record file is crashed
+@end itemize
+
+In these cases, you must repair your tables. @code{myisamchk}
+can usually detect and fix most things that go wrong.
+
+The repair process involves up to four stages, described below. Before you
+begin, you should @code{cd} to the database directory and check the
+permissions of the table files. Make sure they are readable by the Unix user
+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 @strong{MySQL} 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 maintenence includes the options to
+@code{isamchk}/@code{myisamchk}. @xref{Table maintenance}.
+
+The following section is for the cases where the above command fails or
+if you want to use the extended features that isamchk/myisamchk provides.
+
+If you are going to repair a table from the command line, you must first
+take down the @code{mysqld} server. Note that when you do
+@code{mysqladmin shutdown} on a remote server, the @code{mysqld} server
+will still be alive for a while after @code{mysqladmin} returns until
+all queries are stopped and all keys have been flushed to disk.
+
+@noindent
+@strong{Stage 1: Checking your tables}
+
+Run @code{myisamchk *.MYI} or (@code{myisamchk -e *.MYI} if you have
+more time). Use the @code{-s} (silent) option to suppress unnecessary
+information.
+
+If the mysqld server is done you should use the --update option to tell
+@code{myisamchk} to mark the table as 'checked'.
+
+You have to repair only those tables for which @code{myisamchk} announces an
+error. For such tables, proceed to Stage 2.
+
+If you get weird errors when checking (such as @code{out of
+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
+sort_buffer=# -O key_buffer=#} (where # is about 1/4 of the available
+memory) to all @code{isamchk/myisamchk} commands.
+
+First, try @code{myisamchk -r -q tbl_name} (@code{-r -q} means ``quick
+recovery mode''). This will attempt to repair the index file without
+touching the data file. If the data file contains everything that it
+should and the delete links point at the correct locations within the
+data file, this should work, and the table is fixed. Start repairing the
+next table. Otherwise, use the following procedure:
+
+@enumerate
+@item
+Make a backup of the data file before continuing.
+
+@item
+Use @code{myisamchk -r tbl_name} (@code{-r} means ``recovery mode''). This will
+remove incorrect records and deleted records from the data file and
+reconstruct the index file.
+
+@item
+If the preceding step fails, use @code{myisamchk --safe-recover tbl_name}.
+Safe recovery mode uses an old recovery method that handles a few cases that
+regular recovery mode doesn't (but is slower).
+@end enumerate
+
+If you get weird errors when repairing (such as @code{out of
+memory} errors), or if @code{myisamchk} crashes, go to Stage 3.
+
+@noindent
+@strong{Stage 3: Difficult repair}
+
+You should only reach this stage if the first 16K block in the index file is
+destroyed or contains incorrect information, or if the index file is
+missing. In this case, it's necessary to create a new index file. Do so as
+follows:
+
+@enumerate
+@item
+Move the data file to some safe place.
+
+@item
+Use the table description file to create new (empty) data and index files:
+
+@example
+shell> mysql db_name
+mysql> SET AUTOCOMMIT=1;
+mysql> DELETE FROM tbl_name;
+mysql> quit
+@end example
+
+@item
+Copy the old data file back onto the newly created data file.
+(Don't just move the old file back onto the new file; you want to retain
+a copy in case something goes wrong.)
+@end enumerate
+
+Go back to Stage 2. @code{myisamchk -r -q} should work now. (This shouldn't
+be an endless loop).
+
+@noindent
+@strong{Stage 4: Very difficult repair}
+
+You should reach this stage only if the description file has also
+crashed. That should never happen, because the description file isn't changed
+after the table is created.
+
+@enumerate
+@item
+Restore the description file from a backup and go back to Stage 3. You can
+also restore the index file and go back to Stage 2. In the latter case, you
+should start with @code{myisamchk -r}.
+
+@item
+If you don't have a backup but know exactly how the table was created, create
+a copy of the table in another database. Remove the new data file, then move
+the description and index files from the other database to your crashed
+database. This gives you new description and index files, but leaves
+the data file alone. Go back to Stage 2 and attempt to reconstruct
+the index file.
+@end enumerate
+
+@node Optimization, , Repair, Crash recovery
+@subsection Table optimization
+
+To coalesce fragmented records and eliminate wasted space resulting from
+deleting or updating records, run @code{myisamchk} in recovery mode:
+
+@example
+shell> myisamchk -r tbl_name
+@end example
+
+You can optimize a table in the same way using the SQL @code{OPTIMIZE TABLE}
+statement. @code{OPTIMIZE TABLE} is easier, but @code{myisamchk} is faster.
+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}.
+
+@code{myisamchk} also has a number of other options you can use to improve
+the performance of a table:
+
+@table @code
+@item -S, --sort-index
+@item -R index_num, --sort-records=index_num
+@item -a, --analyze
+@end table
+
+For a full description of the option see @xref{myisamchk syntax}.
+
+@node Log files, , Crash recovery, Maintenance
+@section Log file maintenance
+
+When using @strong{MySQL} with log files, you will from time to time
+want to remove/backup old log files and tell @strong{MySQL} to start
+logging on new files. @xref{Update log}.
+
+On a Linux (@code{Redhat}) installation, you can use the
+@code{mysql-log-rotate} script for this. If you installed @strong{MySQL}
+from an RPM distribution, the script should have been installed
+automatically.
+
+On other systems you must install a short script yourself that you
+start from @code{cron} to handle log files.
+
+You can force @strong{MySQL} to start using new log files by using
+@code{mysqladmin flush-logs} or by using the SQL command @code{FLUSH LOGS}.
+If you are using @strong{MySQL} 3.21 you must use @code{mysqladmin refresh}.
+
+The above command does the following:
+
+@itemize @bullet
+@item
+If standard logging (@code{--log}) is used, closes and reopens the log file.
+(@file{mysql.log} as default).
+@item
+If update logging (@code{--log-update}) is used, closes the update log and
+opens a new log file with a higher sequence number.
+@end itemize
+
+If you are using only an update log, you only have to flush the logs and then
+move away the old update log files to a backup.
+If you are using the normal logging, you can do something like:
+
+@example
+shell> cd mysql-data-directory
+shell> mv mysql.log mysql.old
+shell> mysqladmin flush-logs
+@end example
+
+and then take a backup and remove @file{mysql.old}.
+
+@node Adding functions, Adding procedures, Maintenance, Top
+@chapter Adding new functions to MySQL
+
+There are two ways to add new functions to @strong{MySQL}:
+
+@itemize @bullet
+@item You can add the function through the user-definable function (UDF)
+interface. User-definable functions are added and removed dynamically using
+the @code{CREATE FUNCTION} and @code{DROP FUNCTION} statements.
+@xref{CREATE FUNCTION, , @code{CREATE FUNCTION}}.
+
+@item You can add the function as a native (built in) @strong{MySQL} function.
+Native functions are compiled into the @code{mysqld} server and become
+available on a permanent basis.
+@end itemize
+
+Each method has advantages and disadvantages:
+
+@itemize @bullet
+@item
+If you write a user-definable function, you must install the object file
+in addition to the server itself. If you compile your function into the
+server, you don't need to do that.
+@item
+You can add UDFs to a binary @strong{MySQL} distribution. Native functions
+require you to modify a source distribution.
+@item
+If you upgrade your @strong{MySQL} distribution, you can continue to use your
+previously-installed UDFs. For native functions, you must repeat your
+modifications each time you upgrade.
+@end itemize
+
+Whichever method you use to add new functions, they may be used just like
+native functions such as @code{ABS()} or @code{SOUNDEX()}.
+
+@menu
+* Adding UDF:: Adding a new user-definable function
+* Adding native function:: Adding a new native function
+@end menu
+
+@cindex Adding user-definable functions
+@cindex User-definable functions, adding
+@cindex Functions, user-definable, adding
+@node Adding UDF, Adding native function, Adding functions, Adding functions
+@section Adding a new user-definable function
+
+@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
+@end menu
+
+For the UDF mechanism to work, functions must be written in C or C++ and your
+operating system must support dynamic loading. The @strong{MySQL} source
+distribution includes a file @file{sql/udf_example.cc} that defines 5 new
+functions. Consult this file to see how UDF calling conventions work.
+
+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
+``xxx'' is used for an example function name. To distinquish between SQL and
+C/C++ usage, @code{XXX()} (uppercase) indicates a SQL function call, and
+@code{xxx()} (lowercase) indicates a C/C++ function call.
+
+The C/C++ functions that you write to implement the inferface for
+@code{XXX()} are:
+
+@table @asis
+@item @code{xxx()} (required)
+The main function. This is where the function result is computed.
+The correspondence between the SQL type and return type of your C/C++
+function is shown below:
+
+@multitable @columnfractions .2 .8
+@item @strong{SQL type} @tab @strong{C/C++ type}
+@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)
+The initialization function for @code{xxx()}. It can be used to:
+
+@itemize @bullet
+@item
+Check the number of arguments to @code{XXX()}.
+@item
+Check that the arguments are of a required type, or, alternatively,
+tell @strong{MySQL} to coerce arguments to the types you want when
+the main function is called.
+@item
+Allocate any memory required by the main function.
+@item
+Specify the maximum length of the result.
+@item
+Specify (for @code{REAL} functions) the maximum number of decimals.
+@item
+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.
+@end table
+
+When a SQL statement invokes @code{XXX()}, @strong{MySQL} calls the
+initialization 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
+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
+can perform any required cleanup.
+
+All functions must be thread-safe (not just the main function,
+but the initialization and deinitialization 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
+@subsection UDF calling sequences
+
+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
+function @code{XXX()} to return @code{STRING}, @code{INTEGER} or @code{REAL}
+in the @code{CREATE FUNCTION} statement:
+
+@noindent
+For @code{STRING} functions:
+
+@example
+char *xxx(UDF_INIT *initid, UDF_ARGS *args,
+ char *result, unsigned long *length,
+ char *is_null, char *error);
+@end example
+
+@noindent
+For @code{INTEGER} functions:
+
+@example
+long long xxx(UDF_INIT *initid, UDF_ARGS *args,
+ char *is_null, char *error);
+@end example
+
+@noindent
+For @code{REAL} functions:
+
+@example
+double xxx(UDF_INIT *initid, UDF_ARGS *args,
+ char *is_null, char *error);
+@end example
+
+The initialization and deinitialization functions are declared like this:
+
+@example
+my_bool xxx_init(UDF_INIT *initid, UDF_ARGS *args, char *message);
+
+void xxx_deinit(UDF_INIT *initid);
+@end example
+
+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.
+(To use the default for a member, leave it unchanged.)
+
+@table @code
+@item my_bool maybe_null
+@code{xxx_init()} should set @code{maybe_null} to @code{1} if @code{xxx()}
+can return @code{NULL}. The default value is @code{1} if any of the
+arguments are declared @code{maybe_null}.
+
+@item unsigned int decimals
+Number of decimals. The default value is the maximum number of decimals in
+the arguments passed to the main function. (For example, if the function is
+passed @code{1.34}, @code{1.345} and @code{1.3}, the default would be 3,
+because @code{1.345} has 3 decimals.
+
+@item unsigned int max_length
+The maximum length of the string result. The default value differs depending
+on the result type of the function. For string functions, the default is the
+length of the longest argument. For integer functions, the default is 21
+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.)
+
+@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
+between functions. In @code{xxx_init()}, allocate the memory and assign it
+to this pointer:
+
+@example
+initid->ptr = allocated_memory;
+@end example
+
+In @code{xxx()} and @code{xxx_deinit()}, refer to @code{initid->ptr} to use
+or deallocate the memory.
+@end table
+
+@node UDF arguments, UDF return values, UDF calling sequences, Adding UDF
+@subsection Argument processing
+
+The @code{args} parameter points to a @code{UDF_ARGS} structure which has the
+members listed below:
+
+@table @code
+@item unsigned int arg_count
+The number of arguments. Check this value in the initialization function
+if you want your function to be called with a particular number of arguments.
+For example:
+
+@example
+if (args->arg_count != 2)
+@{
+ strcpy(message,"XXX() requires two arguments");
+ return 1;
+@}
+@end example
+
+
+@item enum Item_result *arg_type
+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
+function. For example:
+
+@example
+if (args->arg_type[0] != STRING_RESULT ||
+ args->arg_type[1] != INT_RESULT)
+@{
+ strcpy(message,"XXX() requires a string and an integer");
+ return 1;
+@}
+@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}
+elements to the types you want. This causes @strong{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
+@code{xxx_init()}:
+
+@example
+args->arg_type[0] = STRING_RESULT;
+args->arg_type[1] = INT_RESULT;
+@end example
+
+@item char **args
+@code{args->args} communicates information to the initialization 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.)
+For a non-constant argument, @code{args->args[i]} is @code{0}.
+A constant argument is an expression that uses only constants, such as
+@code{3} or @code{4*7-2} or @code{SIN(3.14)}. A non-constant argument is an
+expression that refers to values that may change from row to row, such as
+column names or functions that are called with non-constant arguments.
+
+For each invocation of the main function, @code{args->args} contains the
+actual arguments that are passed for the row currently being processed.
+
+Functions can refer to an argument @code{i} as follows:
+
+@itemize @bullet
+@item
+An argument of type @code{STRING_RESULT} is given as a string pointer plus a
+length, to allow handling of binary data or data of arbitrary length. The
+string contents are available as @code{args->args[i]} and the string length
+is @code{args->lengths[i]}. You should not assume that strings are
+null-terminated.
+
+@item
+For an argument of type @code{INT_RESULT}, you must cast
+@code{args->args[i]} to a @code{long long} value:
+
+@example
+long long int_val;
+int_val = *((long long*) args->args[i]);
+@end example
+
+@item
+For an argument of type @code{REAL_RESULT}, you must cast
+@code{args->args[i]} to a @code{double} value:
+
+@example
+double real_val;
+real_val = *((double*) args->args[i]);
+@end example
+@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).
+@end table
+
+@node UDF return values, UDF compiling, UDF arguments, Adding UDF
+@subsection Return values and error handling
+
+The initialization 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
+@code{MYSQL_ERRMSG_SIZE} characters long, but you should try to keep the
+message to less than 80 characters so that it fits the width of a standard
+terminal screen.
+
+The return value of the main function @code{xxx()} is the function value, for
+@code{long long} and @code{double} functions. For string functions, the
+string is returned in the @code{result} and @code{length} arguments.
+@code{result} is a buffer at least 255 bytes long. Set these to the contents
+and length of the return value. For example:
+
+@example
+memcpy(result, "result string", 13);
+*length = 13;
+@end example
+
+The string function return value normally also points to the result.
+
+To indicate a return value of @code{NULL} in the main function, set
+@code{is_null} to @code{1}:
+
+@example
+*is_null = 1;
+@end example
+
+To indicate an error return in the main function, set the @code{error}
+parameter to @code{1}:
+
+@example
+*error = 1;
+@end example
+
+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
+@strong{MySQL} versions prior to 3.22.10, you should set both @code{*error}
+and @code{*is_null}:
+
+@example
+*error = 1;
+*is_null = 1;
+@end example
+
+@node UDF compiling, , UDF return values, Adding UDF
+@subsection Compiling and installing user-definable functions
+
+Files implementing UDFs must be compiled and installed on the host where the
+server runs. This process is described below for the example UDF file
+@file{udf_example.cc} that is included in the @strong{MySQL} source
+distribution. This file contains the following functions:
+
+@itemize @bullet
+@item
+@code{metaphon()} returns a metaphon string of the string argument.
+This is something like a soundex string, but it's more tuned for English.
+@item
+@code{myfunc_double()} returns the sum of the ASCII values of the
+characters in its arguments, divided by the sum of the length of its arguments.
+@item
+@code{myfunc_int()} returns the sum of the length of its arguments.
+@item
+@code{lookup()} returns the IP number for a hostname.
+@item
+@code{reverse_lookup()} returns the hostname for an IP number.
+The function may be called with a string @code{"xxx.xxx.xxx.xxx"} or
+four numbers.
+@end itemize
+
+A dynamically-loadable file should be compiled as a sharable object file,
+using a command something like this:
+
+@example
+shell> gcc -shared -o udf_example.so myfunc.cc
+@end example
+
+You can easily find out the correct compiler options for your system by
+running this command in the @file{sql} directory of your @strong{MySQL}
+source tree:
+
+@example
+shell> make udf_example.o
+@end example
+
+You should run a compile command similar to the one that @code{make} displays,
+except that you should remove the @code{-c} option near the end of the line
+and add @code{-o udf_example.so} to the end of the line. (On some systems,
+you may need to leave the @code{-c} on the command.)
+
+Once you compile a shared object containing UDFs, you must install it
+and tell @strong{MySQL} about it. Compiling a shared object from
+@file{udf_example.cc} produces a file named something like
+@file{udf_example.so} (the exact name may vary from platform to platform).
+Copy this file to some directory searched by @code{ld}, such as
+@file{/usr/lib}. On many systems, you can set the @code{LD_LIBRARY} or
+@code{LD_LIBRARY_PATH} environment variable to point at the directory where
+you have your UDF function files. The @code{dlopen} manual page tells you
+which variable you should use on your system. You should set this in
+@code{mysql.server} or @code{safe_mysqld} and restart @code{mysqld}.
+
+After the library is installed, notify @code{mysqld} about the new
+functions with these commands:
+
+@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";
+@end example
+
+Functions can be deleted using @code{DROP FUNCTION}:
+
+@example
+mysql> DROP FUNCTION metaphon;
+mysql> DROP FUNCTION myfunc_double;
+mysql> DROP FUNCTION myfunc_int;
+mysql> DROP FUNCTION lookup;
+mysql> DROP FUNCTION reverse_lookup;
+@end example
+
+The @code{CREATE FUNCTION} and @code{DROP FUNCTION} statements update the
+system table @code{func} in the @code{mysql} database. The function's name,
+type and shared library name are saved in the table. You must have the
+@strong{insert} and @strong{delete} privileges for the @code{mysql} database
+to create and drop functions.
+
+You should not use @code{CREATE FUNCTION} to add a function that has already
+been created. If you need to reinstall a function, you should remove it with
+@code{DROP FUNCTION} and then reinstall it with @code{CREATE FUNCTION}. You
+would need to do this, for example, if you recompile a new version of your
+function, so that @code{mysqld} gets the new version. Otherwise the server
+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
+one that has been loaded with @code{CREATE FUNCTION} and not removed with
+@code{DROP FUNCTION}.)
+
+@cindex Adding native functions
+@cindex Native functions, adding
+@cindex Functions, native, adding
+@node Adding native function, , Adding UDF, Adding functions
+@section Adding a new native function
+
+The procedure for adding a new native function is described below. Note that
+you cannot add native functions to a binary distribution because the procedure
+involves modifying @strong{MySQL} source code. You must compile
+@strong{MySQL} yourself from a source distribution. Also note that if you
+migrate to another version of @strong{MySQL} (e.g., when a new version is
+released), you will need to repeat the procedure with the new version.
+
+To add a new native @strong{MySQL} function, follow these steps:
+
+@enumerate
+@item
+Add one line to @file{lex.h} that defines the function name in the
+@code{sql_functions[]} array.
+@item
+Add two lines to @file{sql_yacc.yy}. One indicates the preprocessor
+symbol that @code{yacc} should define (this should be added at the
+beginning of the file). Then define the function parameters and add an
+``item'' with these parameters to the @code{simple_expr} parsing rule.
+For an example, check all occurrences of @code{SOUNDEX} in
+@file{sql_yacc.yy} to see how this is done.
+@item
+In @file{item_func.h}, declare a class inheriting from @code{Item_num_func} or
+@code{Item_str_func}, depending on whether your function returns a number or a
+string.
+@item
+In @file{item_func.cc}, add one of the following declarations, depending
+on whether you are defining a numeric or string function:
+@example
+double Item_func_newname::val()
+longlong Item_func_newname::val_int()
+String *Item_func_newname::Str(String *str)
+@end example
+@item
+You should probably also define the following function:
+@example
+void Item_func_newname::fix_length_and_dec()
+@end example
+This function should at least calculate @code{max_length} based on the
+given arguments. @code{max_length} is the maximum number of characters
+the function may return. This function should also set @code{maybe_null = 0}
+if the main function can't return a @code{NULL} value. The function can check
+if any of the function arguments can return @code{NULL} by checking the
+arguments @code{maybe_null} variable.
+@end enumerate
+
+All functions must be thread-safe.
+
+For string functions, there are some additional considerations to be aware of:
+@itemize @bullet
+@item
+The @code{String *str} argument provides a string
+buffer that may be used to hold the result.
+@item
+The function should return the string that holds the result.
+@item
+All current string functions try to avoid allocating any memory unless
+absolutely necessary!
+@end itemize
+
+@node Adding procedures, ODBC, Adding functions, Top
+@chapter Adding new procedures to MySQL
+
+In @strong{MySQL}, you can define a procedure in C++ that can access and
+modify the data in a query before it is sent to the client. The modification
+can be done on row by row or @code{GROUP BY} level.
+
+We have created an example procedure in @strong{MySQL} 3.23 to
+show you what can be done.
+
+@menu
+* procedure analyse:: Procedure analyse
+* Writing a procedure:: Writing a procedure.
+@end menu
+
+@node procedure analyse, Writing a procedure, Adding procedures, Adding procedures
+@section Procedure analyse
+
+@code{analyse([max elements,[max memory]])}
+
+This procedure is defined in the @file{sql/sql_analyse.cc}. This
+examines the result from your query and returns an analysis of the
+results.
+
+@itemize @bullet
+@item
+@code{max elements} (default 256) is the maximum number of distinct values
+@code{analyse} will notice per column. This is used by @code{analyse} to check if
+the optimal column type should be of type @code{ENUM}.
+@item
+@code{max memory} (default 8192) is the maximum memory @code{analyse} should
+allocate per column while trying to find all distinct values.
+@end itemize
+
+@example
+SELECT ... FROM ... WHERE ... PROCEDURE ANALYSE([max elements,[max memory]])
+@end example
+
+@node Writing a procedure, , procedure analyse, Adding procedures
+@section Writing a procedure.
+
+For the moment, the only documentation for this is the source. :(
+
+You can find all information about procedures by examining the following files:
+
+@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
+
+@cindex ODBC
+@cindex Windows
+@cindex MyODBC
+@node ODBC, Common programs, Adding procedures, Top
+@chapter MySQL ODBC Support
+
+@menu
+* Which ODBC OS:: Operating systems supported by @strong{MyODBC}
+* ODBC administrator:: How to fill in the various fields in the ODBC administrator program
+* ODBC Problems:: How to report problems with @strong{MySQL} ODBC
+* MyODBC clients:: Programs known to work with @strong{MyODBC}
+* ODBC and last_insert_id:: How to get the value of an @code{AUTO_INCREMENT} column in ODBC
+* MyODBC bug report:: Reporting problems with MyODBC
+@end menu
+
+@strong{MySQL} provides support for ODBC by means of the @strong{MyODBC}
+program.
+
+@node Which ODBC OS, ODBC administrator, ODBC, ODBC
+@section Operating systems supported by MyODBC
+
+@strong{MyODBC} is a 32-bit ODBC (2.50) level 0 driver for connecting
+an ODBC-aware application to @strong{MySQL}. @strong{MyODBC} works on
+Windows95, Windows98, NT and on most Unix platforms.
+
+Normally you only need to install @strong{MyODBC} on Windows machines.
+You only need @strong{MyODBC} for Unix if you have a program like
+ColdFusion that is running on the Unix machine and uses ODBC to connect
+to the databases.
+
+@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 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 @strong{MySQL} useful links page.
+@xref{Useful Links}.
+
+On Windows/NT you may get the following error when trying to install
+@strong{MyODBC}:
+
+@example
+An error occurred while copying C:\WINDOWS\SYSTEM\MFC30.DLL. Restart Windows
+and try installing again (before running any applications which use ODBC)
+@end example
+
+The problem in this case is that some other program is using ODBC and
+because of how windows is designed, you cannot in this case install new
+ODBC drivers with Microsoft's ODBC setup program. :( The solution to this
+is to reboot your computer in ``safe mode`` (You can choose this by
+pressing F8 just before your machine starts Windows during rebooting),
+install @strong{MyODBC} and reboot to normal mode.
+
+@itemize @bullet
+@item
+To make a connection to an Unix box from a Windows box, with an ODBC
+application (one that doesn't support @strong{MySQL} natively), you must
+first install @strong{MyODBC} on the Windows machine.
+@item
+The user and Windows machine must have the access privileges to the
+@strong{MySQL} server the Unix machine. This is set up with the @code{GRANT}
+command. @xref{GRANT,,@code{GRANT}}.
+@item
+You must create an ODBC DSN entry as follows:
+
+@itemize @bullet
+@item
+Open the Control Panel on the Windows machine.
+@item
+Double click the ODBC Data Sources 32 bits icon.
+@item
+Click the tab User DSN.
+@item
+Click the button Add.
+@item
+Select @strong{MySQL} in the screen Create New Data Source and click
+the Finish button.
+@item
+The @strong{MySQL} Driver default configuration screen is shown.
+@xref{ODBC administrator}.
+@end itemize
+
+@item
+Now start your application and select the ODBC driver with the DSN you
+specified in the ODBC administrator.
+@end itemize
+
+Notice that there are other configuration options in the screen of
+@strong{MySQL} (trace, don't prompt on connect, etc) that you can try if
+you run into problems.
+
+@node ODBC administrator, ODBC Problems, Which ODBC OS, ODBC
+@section How to fill in the various fields in the ODBC administrator program
+
+There are three possibilities for specifying the server name on
+Windows95:
+
+@itemize @bullet
+@item
+Use the IP address of the server.
+@item
+Add a file @file{\windows\lmhosts} with the following information:
+
+@example
+ip hostname
+@end example
+
+For example:
+
+@example
+194.216.84.21 my_hostname
+@end example
+
+@item
+Configure the PC to use DNS.
+@end itemize
+
+Example of how to fill in the @code{ODBC setup}
+@example
+Windows DSN name: test
+Description: This is my test database
+MySql Database: test
+Server: 194.216.84.21
+User: monty
+Password: my_password
+Port:
+@end example
+
+The value for the @code{Windows DSN name} field is any name that is unique
+in your Windows ODBC setup.
+
+You don't have to specify values for the @code{Server}, @code{User},
+@code{Password} or @code{Port} fields in the ODBC setup screen.
+However, if you do, the values will be used as the defaults later when
+you attempt to make a connection. You have the option of changing the
+values at that time.
+
+If the port number is not given, the default port (@value{default_port})
+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}}.
+
+@node ODBC Problems, MyODBC clients, ODBC administrator, ODBC
+@section How to report problems with MyODBC
+
+@strong{MyODBC} has been tested with Access, Admndemo.exe, C++-Builder,
+Borland Builder 4, Centura Team Developer (formerly Gupta SQL/Windows),
+ColdFusion (on Solaris and NT with svc 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++ and Visual Basic.
+
+If you know of any other applications that work with @strong{MyODBC}, please
+mail @email{myodbc@@lists.mysql.com} about this!
+
+With some programs you may get an error like:
+@code{Another user has modifies the record that you have modified}. In most
+cases this can be solved by doing one of the following things:
+
+@itemize @bullet
+@item
+Add a primary key for the table if there isn't one already.
+@item
+Add a timestamp column if there isn't one already.
+@item
+Only use double float fields. Some programs may fails when they comparing
+single floats.
+@end itemize
+
+If the above doesn't help, you should do a @code{MyODBC} trace file and
+from this try to figure out why things goes wrong.
+
+@node MyODBC clients, ODBC and last_insert_id, ODBC Problems, ODBC
+@section Programs known to work with MyODBC
+
+Most programs should work with @strong{MyODBC}, but for each of those
+listed below, we have tested it ourselves or gotten confirmation from
+some user that it works:
+
+@table @asis
+@item @strong{Program}
+@strong{Comment}
+@item Access
+To make Access work:
+@itemize @bullet
+@item
+You should have a primary key in the table.
+@item
+You should have a timestamp in all tables you want to be able to update.
+@item
+Only use double float fields. Access fails when comparing with single floats.
+@item
+Set the `Return matching rows' option field when connecting to @strong{MySQL}.
+@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}.
+@item
+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
+@strong{MySQL} can't understand. You can fix this by selecting
+@code{"Query|SQLSpecific|Pass-Through"} from the Access menu.
+
+@end itemize
+@item Borland Builder 4
+When you start a query you can use the property @code{Active} or use the
+method @code{Open}. Note that @code{Active} will start by automatically issue
+a @code{SELECT * FROM ...} query that may not be a good thing if your tables
+are big!
+@item ColdFusion (On Unix)
+The following information is taken from the ColdFusion documentation:
+
+Use the following information to configure ColdFusion Server for Linux
+to use the unixODBC driver with @strong{MyODBC} for @strong{MySQL} data
+sources. Allaire has verified that @strong{MyODBC} version 2.50.26
+works with @strong{MySQL} version 3.22.27 and ColdFusion for Linux. (Any
+newer version should also work). You can download @strong{MyODBC} at
+@uref{http://www.mysql.com/downloads/api-myodbc.html}
+
+ColdFusion 4.5.1 allows you to us the ColdFusion Administrator to add
+the @strong{MySQL} data source. However, the driver is not included with
+ColdFusion 4.5.1. Before the @strong{MySQL} driver will appear in the ODBC
+datasources drop-down list, you must build and copy the @strong{MyODBC} driver
+to @file{/opt/coldfusion/lib/libmyodbc.so}.
+
+@item DataJunction
+You have to change it to output @code{VARCHAR} rather than @code{ENUM}, as
+it exports the latter in a manner that causes @strong{MySQL} grief.
+@item Excel
+Works. Some tips:
+@itemize @bullet
+@item
+If you have problems with dates, try to select them as strings using the
+@code{CONCAT()} function. For example:
+@example
+select CONCAT(rise_time), CONCAT(set_time)
+ from sunrise_sunset;
+@end example
+Values retrieved as strings this way should be correctly recognized
+as time values by Excel97.
+
+The purpose of @code{CONCAT()} in this example is to fool ODBC into thinking
+the column is of ``string type''. Without the @code{CONCAT()}, ODBC knows the
+column is of time type, and Excel does not understand that.
+
+Note that this is a bug in Excel, because it automatically converts a
+string to a time. This would be great if the source was a text file, but
+is plain stupid when the source is an ODBC connection that reports
+exact types for each column.
+@end itemize
+@item odbcadmin
+Test program for ODBC.
+@item Delphi
+You must use DBE 3.2 or newer. Set the `Don't optimize column width'
+option field when connecting to @strong{MySQL}.
+
+Also, here is some potentially useful Delphi code that sets up both an
+ODBC entry and a BDE entry for @strong{MyODBC} (the BDE entry requires a BDE
+Alias Editor which may be had for free at a Delphi Super Page near
+you.): (Thanks to Bryan Brunton @email{bryan@@flesherfab.com} for this)
+
+@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('LANGDRIVER=');
+ 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
+
+@item C++Builder
+Tested with BDE 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
+been a problem.
+@item Visual Basic
+To be able to update a table, you must define a primary key for the table.
+
+Visual Basic with ADO can't handle big integers; This means that some queries
+like @code{SHOW PROCESSLIST} will not work properly. The fix is to set
+add the option @code{OPTION=16834} in the ODBC connect string or set
+the @code{Change BIGINT columns to INT} option in the MyODBC connect screen.
+@end table
+
+@node ODBC and last_insert_id, MyODBC bug report, MyODBC clients, ODBC
+@section How to get the value of an @code{AUTO_INCREMENT} column in ODBC
+
+A common problem is how to get the value of an automatically generated ID
+from an @code{INSERT}. With ODBC, you can do something like this (assuming
+that @code{auto} is an @code{AUTO_INCREMENT} field):
+
+@example
+INSERT INTO foo (auto,text) VALUES(NULL,'text');
+SELECT LAST_INSERT_ID();
+@end example
+
+Or, if you are just going to insert the ID into another table, you can do this:
+
+@example
+INSERT INTO foo (auto,text) VALUES(NULL,'text');
+INSERT INTO foo2 (id,text) VALUES(LAST_INSERT_ID(),'text');
+@end example
+
+For the benefit of some ODBC applications (at least Delphi and Access),
+the following query can be used to find a newly-inserted row:
+@example
+SELECT * FROM tbl_name WHERE auto IS NULL;
+@end example
+
+@node MyODBC bug report, , ODBC and last_insert_id, ODBC
+@section Reporting problems with MyODBC
+
+If you encounter difficulties with @strong{MyODBC}, you should start by
+making a log file from the ODBC manager (the log you get when requesting
+logs from ODBCADMIN) and a @strong{MyODBC} log. To get a @strong{MyODBC}
+log, tag the `Trace MyODBC' option flag in the @strong{MyODBC}
+connect/configure screen. The log will be written to file
+@file{C:\myodbc.log}. Note that you must use @code{MYSQL.DLL} and not
+@code{MYSQL2.DLL} for this option to work!
+
+Check the queries that MyODBC sends to the @strong{MySQL} server; You
+should be able to find this by searching after the string
+@code{>mysql_real_query} in the @file{myodbc.log} file.
+
+You should also try duplicating the queries in the @code{mysql} monitor
+or @code{admndemo} to find out if the error is MyODBC or @strong{MySQL}.
+
+If you find out something is wrong, please only send the relevant rows
+(max 40 rows) to the @email{myodbc@@lists.mysql.com}. Please never
+send the whole MyODBC or ODBC log file!
+
+If you are unable to find out what's wrong, the last option is to to
+make an archive (tar or zip) that contains a MyODBC log 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 MySQL AB
+will have access to the files you upload and we will be very discrete
+with the data!
+
+If you can create a program that also shows this problem, please
+upload this too!
+
+If the program works with some other SQL server, you should make an ODBC log
+file where you do exactly the same thing in the other SQL server.
+
+Remember that the more information you can supply to us, the more
+likely it is that we can fix the problem!
+
+@node Common programs, Problems, ODBC, Top
+@chapter Using @code{MySQL} with some common programs
+
+@menu
+* Apache:: Using @strong{MySQL} with Apache
+@end menu
+
+@node Apache, , Common programs, Common programs
+@section Using MySQL with Apache
+
+The contrib section includes programs that let you authenticate your
+users from a @strong{MySQL} database and also let you log your log files
+into a @strong{MySQL} table. @xref{Contrib}.
+
+You can change the Apache logging format to be easily readable by
+@code{MySQL} by putting the following into the Apache configuration file:
+
+@example
+LogFormat \
+ "\"%h\",%@{%Y%m%d%H%M%S@}t,%>s,\"%b\",\"%@{Content-Type@}o\", \
+ \"%U\",\"%@{Referer@}i\",\"%@{User-Agent@}i\""
+@end example
+
+In @strong{MySQL} you can do something like this:
+
+@example
+LOAD DATA INFILE '/local/access_log' INTO TABLE table_name
+FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"' ESCAPED BY '\\'
+@end example
+
+@node Problems, Common problems, Common programs, Top
+@chapter Problems and common errors
+
+@menu
+* What is crashing:: How to determinate what is causing problems
+* Crashing:: What to do if @strong{MySQL} keeps crashing
+* Link errors:: Problems when linking with the @strong{MySQL} client library
+* Common errors:: Some common errors when using @strong{MySQL}
+* Full disk:: How @strong{MySQL} handles a full disk
+* Multiple sql commands:: How to run SQL commands from a text file
+* Temporary files:: Where @strong{MySQL} stores temporary files
+* Problems with mysql.sock:: How to protect @file{/tmp/mysql.sock}
+* Error Access denied:: @code{Access denied} error
+* Changing MySQL user :: How to run @strong{MySQL} as a normal user
+* Resetting permissions:: How to reset a forgotten password.
+* File permissions :: Problems with file permissions
+* Not enough file handles:: File not found
+* Using DATE:: Problems using @code{DATE} columns
+* Timezone problems:: Timezone problems
+* Case sensitivity:: Case sensitivity in searches
+* Problems with NULL:: Problems with @code{NULL} values
+* 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
+* ALTER TABLE problems:: Problems with @code{ALTER TABLE}.
+* Change column order:: How to change the order of columns in a table
+@end menu
+
+@node What is crashing, Crashing, Problems, Problems
+@section How to determinate what is causing problems
+
+When you run into problems, the first thing you should do is to find out
+which program / piece of equipment is causing problems.
+
+@itemize @bullet
+@item
+If you have one of the following symptoms, then it is probably a hardware
+(like memory, motherboard, CPU, or harddisk) or kernel problem:
+@itemize @bullet
+@item
+The keyboard doesn't work. This can normally be checked by pressing
+Caps Lock; If the Caps Lock light doesn't change you have to replace
+your keyboard. (Before doing this, you should however try to reboot
+your computer and check all cables to the keyboard :)
+@item
+The mouse pointer doesn't move.
+@item
+The machine doesn't answer to a remote machine's pings.
+@item
+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).
+@end itemize
+
+In this case you should start by checking all your cables and run some
+diagnostic tool to check your hardware!
+You should also check if there are any patches, updates or service
+packs for your operating system that could likely solve your problems.
+Check also that all your libraries (like glibc) are up to date.
+
+It's always good to use a machine with ECC memory to discover
+memory problems early!
+@item
+If your keyboard is locked up, you may be able to fix this by
+logging into your machine from another machine and execute
+@code{kbd_mode -a} on it.
+
+@item
+Please examine your system log file, (/var/log/messages or similar) for
+reasons for your problems. If you think the problem is in @strong{MySQL}
+then you should also examine @strong{MySQL}'s log files. @xref{Update log}.
+
+@item
+If you don't think you have hardware problems, you should try to find
+out which program is causing problems.
+
+Try using @code{top}, @code{ps}, @code{taskmanager} or some similar program,
+to check which program is taking all CPU, or is locking the machine.
+
+@item
+Check with @code{top}, @code{df} or a similar programs if you are out of
+memory, disk space, open files or some other critical resource.
+
+@item
+If the problem is some runaway process, you can always try to kill if. If it
+doesn't want to die, this is probably a bug in the operating system.
+@end itemize
+
+If after you have examined all other possibilities and you have
+concluded that its the @strong{MySQL} server or a @strong{MySQL} client
+that is causing the problem, it's time to do a bug report for our
+mailing list or our support team. In the bug report, try to describe
+very detailed how the system is behaving and what you think is
+happening. You should also state why you think it's @strong{MySQL} that
+is causing the problems. Take in consideration all the situations in
+this chapter. State any problems exactly how they appear when you
+examine your system.. Use the 'cut and paste' method for any output
+and/or error messages from programs and/or log files!
+
+Try to describe very detailed which program is not working and all
+symptoms you see! We have in the past got many bug reports that just
+states "the system doesn't work". This doesn't provide us with any
+information of what could be the problem.
+
+If a program fails, it's always useful to know:
+
+@itemize @bullet
+@item
+Has the program in question made a segmentation fault (core dumped)?
+@item
+Is the program taking the whole CPU? Check with @code{top}. Let the
+program run for a while, it may be evaluating something heavy.
+@item
+If it's the @code{mysqld} server that is causing problems; Can you
+do @code{mysqladmin -u root ping}, or @code{mysqladmin -u root processlist}?
+@item
+What does a client program say (try with @code{mysql} for example)
+when you try to connect to the @strong{MySQL} server?
+Does the client jam? Do you get any output from the program?
+@end itemize
+
+When send a bug report, you should of course follow the outlines
+described in this manual. @xref{Asking questions}.
+
+@node Crashing, Link errors, What is crashing, Problems
+@section What to do if MySQL keeps crashing
+
+All @strong{MySQL} versions are tested on many platforms before they are
+released. This doesn't mean that there isn't any bugs in
+@strong{MySQL}, but that if there are bugs they are very few and can be
+hard to find. If you have a problem, it will always help if you try to
+find out exactly what crashes your system as you will have a much better
+chance of getting this fixed quickly.
+
+First you should try to find out whether the problem is that the
+@code{mysqld} daemon dies or whether your problem has to do with your
+client. You can check how long your @code{mysqld} server has been up by
+executing @code{mysqladmin version}. If @code{mysqld} has died, you may
+find the reason for this in the file
+@file{mysql-data-directory/'hostname'.err}.
+
+Many crashes of @strong{MySQL} is caused by corrupted index / data
+files. @strong{MySQL} will update the data on disk, with the
+@code{write()} system call, after every SQL statement and before the
+client is notified about the result (this is not true if you are running
+with @code{delayed_key_writes}, in which case only the data is written).
+This means that the data is safe even if mysqld crashes as the OS will
+ensure that the not flushed data is written to disk. You can force
+@strong{MySQL} to sync everything to disk after every SQL command by
+starting @code{mysqld} with @code{--flush}.
+
+The above means that normally you shouldn't get corrupted tables unless:
+
+@itemize @bullet
+@item
+Someone/something killed @code{mysqld} or the machine in the middle
+of an update.
+@item
+You have found a bug in @code{mysqld} that caused it to die in the
+middle of an update.
+@item
+Someone is manipulating the data/index files outside of @strong{mysqld}
+without locking the table properly.
+@item
+If you are running many @code{mysqld} servers on the same data on a
+system that doesn't support good file system locks (normally handled by
+the @code{lockd} deamon.) or if you are running
+multiple servers with @code{--skip-locking}
+@item
+You have a crashed index/data file that contains very wrong data that
+got mysqld confused.
+@item
+You have found a bug in the data storage code. This isn't that likely,
+but it's at least possible. In this case you can try to change the file
+type to another database handler by using @code{ALTER TABLE} on a
+repaired copy of the table!
+@end itemize
+
+Because it is very difficult to know why something is crashing, first try to
+check whether or not things that work for others crash for you. Please try
+the following things:
+
+@itemize @bullet
+@item
+Take down the @code{mysqld} daemon with @code{mysqladmin shutdown}, run
+@code{myisamchk --silent --force */*.MYI} on all tables and restart the
+@code{mysqld} daemon. This will ensure that you are running from a clean
+state. @xref{Maintenance}.
+
+@item
+Use @code{mysqld --log} and try to determine from the information in the log
+whether or not some specific query kills the server. 95% of all bugs are
+related to a particular query! Normally this is one of the last queries in
+the log file just before @strong{MySQL} restarted.
+
+You may be able to verify this using the following procedure:
+
+@itemize @bullet
+@item
+Take down the @strong{MySQL} daemon (with @code{mysqladmin shutdown})
+@item
+Make a backup of files in the @strong{MySQL} database directory.
+(As the server is stopped, you can just copy the files to some other
+directory)
+@item
+Check the tables with @code{myisamchk -s */*.MYI} to verify that all
+tables are correct. If any table is corrupted, repair it with
+@code{myisamchk -r path-to-table.MYI}. You should take the backup
+before checking the tables as the problem could be related to corrupted
+tables.
+@item
+Remove (or move away) any old log files from the @strong{MySQL} data directory.
+@item
+Start the server with @code{safe_mysqld --log-update} or
+@code{safe_mysqld --log --log-update}.
+@item
+If @code{mysqld} now dies, you have two options:
+@itemize @bullet
+@item
+First take a backup of your backup database. (Just copy the file(s)
+somewhere again). This is because we want to keep the original start
+situation untouched. Start a mysqld process on the other backup database
+(you can do this with option @code{--datadir=/path/to/backup/}).
+@item
+Just restore the backup on your original database and restart @code{mysqld}.
+You will not any lose information, because you have the @code{log-update} file.
+@end itemize
+@item
+
+Now you can test if the problem is a specific update statement by executing
+@code{mysql database_name < path-to-log-update-file}.
+
+You can also use the script @code{mysql_find_rows} to just execute some of the
+update statements if you want to narrow down the problem.
+
+If mysqld now crashes, then you have something repeatable
+available. Please mail @email{bugs@@lists.mysql.com}, or
+@email{developers@@mysql.com}, or (if you are a support customer) to
+@email{support@@mysql.com} about the problem and the @strong{MySQL} team
+will fix it as soon as possible.
+@end itemize
+
+@item
+Have you tried the benchmarks? They should test @strong{MySQL} rather well.
+You can also add code that simulates your application! The benchmarks can be
+found in the @file{bench} directory in the source distribution, or, for a
+binary distribution, in the @file{sql-bench} directory under your
+@strong{MySQL} installation directory.
+
+@item
+Try @code{fork_test.pl} and @code{fork2_test.pl}.
+
+@item
+Check the file @file{mysql-data-directory/'hostname'.err} for any errors.
+
+@item
+If you configure @strong{MySQL} for debugging, it will be much easier to
+gather information about possible errors if something goes wrong.
+Reconfigure @strong{MySQL} with the @code{--with-debug} option to
+@code{configure} and then recompile. @xref{Debugging server}.
+
+@item
+Configuring @strong{MySQL} for debugging causes a safe memory allocator to be
+included that can find some errors. It also provides a lot of output about
+what is happening.
+
+@item
+Have you applied the latest patches for your operating system?
+
+@item
+Use the @code{--skip-locking} option to @code{mysqld}. On some systems, the
+@code{lockd} lock manager does not work properly; the @code{--skip-locking}
+option tells @code{mysqld} not to use external locking. (This means that you
+cannot run 2 @code{mysqld} servers on the same data and that you must be
+careful if you use @code{myisamchk}, but it may be instructive to try the
+option as a test.)
+
+@item
+Have you tried @code{mysqladmin -u root processlist} when @code{mysqld}
+appears to be running but not responding? Sometimes @code{mysqld} is not
+comatose even though you might think so. The problem may be that all
+connections are in use, or there may be some internal lock problem.
+@code{mysqladmin processlist} will usually be able to make a connection even
+in these cases, and can provide useful information about the current number
+of connections and their status.
+
+@item
+Run the command @code{mysqladmin -i 5 status}
+in a separate window to produce statistics while you run your other queries.
+
+@item
+Try the following:
+@enumerate
+@item
+Start @code{mysqld} from @code{gdb} (or in another debugger).
+
+@item
+Run your test scripts.
+
+@item
+Print the backtrace and the local variables at the 3 lowest levels. In gdb you
+can do this with the following commands when @code{mysqld} has crashed inside
+gdb:
+
+@example
+backtrace
+info local
+up
+info local
+up
+info local
+@end example
+
+With gdb you can also examine which threads there exists with @code{info
+threads} and switch to a specific thread with @code{thread #}, where
+@code{#} is the thread id.
+@end enumerate
+
+@item
+Try to simulate your application with a Perl script to force
+@strong{MySQL} to crash or misbehave.
+
+@item
+Send a normal bug report. @xref{Bug reports}. Be even more detailed
+than usual. Because @strong{MySQL} works for many people, it may be that the
+crash results from something that exists only on your computer (for example,
+an error that is related to your particular system libraries).
+@item
+If you have a problem with table with dynamic length rows and you are
+not using @code{BLOB/TEXT} columns (but only @code{VARCHAR} columns) you
+can try to change all @code{VARCHAR} to @code{CHAR} with @code{ALTER
+TABLE}. This will force @strong{MySQL} to use fixed size rows. Fixed
+size rows take a little extra space, but are much more tolerant to
+corruption!
+
+The current dynamic row code has been in use at MySQL AB for at least 3
+years without any problems, but by nature dynamic length rows are more
+prone to errors, so it may be a good idea to try the above to see if it helps!
+@end itemize
+
+@node Link errors, Common errors, Crashing, Problems
+@section Problems when linking with the MySQL client library
+
+If you are linking your program and you get errors for unreferenced
+symbols that starts with @code{mysql_}, like the following:
+
+@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
+
+you should be able to solve this by adding @code{-Lpath-to-the-mysql-library
+-lmysqlclient} @strong{LAST} on your link line.
+
+If you get @code{undefined reference} errors for the @code{compress} function,
+add @code{-lgz} @strong{LAST} on your link line and try again!
+
+If you get @code{undefined reference} errors for functions that should
+exist on your system, like @code{connect}, check the man page, for the
+function in question, for which libraries you should add to the link
+line!
+
+If you get @code{undefined reference} errors for functions that doesn't
+exist on your system, like the following:
+
+@example
+mf_format.o(.text+0x201): undefined reference to `__lxstat'
+@end example
+
+It usually means that your library is compiled on a system that is not
+100 % compatible with yours. In this case you should download the
+latest @strong{MySQL} source distribution and compile this yourself.
+@xref{Installing source}.
+
+If you are trying to run a program and you then get errors for
+unreferenced symbols that starts with @code{mysql_} or that the
+@code{mysqlclient} library can't be found, this means that your system
+can't find the share @code{libmysqlclient.so} library.
+
+The fix for this is to either tell your system to search after shared
+libraries where the library is located by one of the following methods:
+
+@itemize @bullet
+@item
+Add the path to directory where you have @code{libmysqlclient.so} the
+@code{LD_LIBRARY_PATH} environment variable.
+@item
+Add the path to directory where you have @code{libmysqlclient.so} the
+@code{LD_LIBRARY} environment variable.
+@item
+Copy @code{libmysqlclient.so} to some place that is searched by your system,
+like @file{/lib} and update the shared library information by executing
+@code{ldconfig}.
+@end itemize
+
+Another way to solve this problem is to link your program staticly, with
+@code{-static}, or by removing the dynamic @strong{MySQL} libraries
+before linking your code. In the second case you should of course be
+sure that no other programs is using the dynamic libraries!
+
+@node Common errors, Full disk, Link errors, Problems
+@section Some common errors when using MySQL
+
+@menu
+* Gone away:: @code{MySQL server has gone away} error
+* Can not connect to server:: @code{Can't connect to [local] MySQL server} error
+* Blocked host:: @code{Host '...' is blocked} error
+* Too many connections:: @code{Too many connections} error
+* Out of memory:: @code{Out of memory} error
+* Packet too large:: @code{Packet too large} error
+* Communication errors::
+* Full table:: @code{The table is full} error
+* 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
+@end menu
+
+@node Gone away, Can not connect to server, Common errors, Common errors
+@subsection @code{MySQL server has gone away} error
+
+This section also covers the related @code{Lost connection to server
+during query} error.
+
+The most common reason for the @code{MySQL server has gone away} error
+is that the server timed out and closed the connection. By default, the
+server closes the connection after 8 hours if nothing has happened. You
+can change the time limit with by setting the @code{wait_timeout} variable when
+you start mysqld.
+
+You can check that the @strong{MySQL} hasn't died by executing
+@code{mysqladmin version} and examining the uptime.
+
+If you have a script, you just have to issue the query again for the client
+to do an automatic reconnection.
+
+You normally can get the following error codes in this case
+(which one you get is OS-dependent):
+
+@multitable @columnfractions .3 .7
+@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
+to the server, but it didn't get a full answer (or any answer) to the question.
+@end multitable
+
+You can also get these errors if you send a query to the server that is
+incorrect or too large. If @code{mysqld} gets a packet that is too large
+or out of order, it assumes that something has gone wrong with the client and
+closes the connection. If you need big queries (for example, if you are
+working with big @code{BLOB} columns), you can increase the query limit by
+starting @code{mysqld} with the @code{-O max_allowed_packet=#} option
+(default 1M). The extra memory is allocated on demand, so @code{mysqld} will
+use more memory only when you issue a big query or when @code{mysqld} must
+return a big result row!
+
+@node Can not connect to server, Blocked host, Gone away, Common errors
+@subsection @code{Can't connect to [local] MySQL server} error
+
+A @strong{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
+system (default @file{/tmp/mysqld.sock}), or TCP/IP, which connects
+through a port number. Unix sockets are faster than TCP/IP but can only
+be used when connecting to a server on the same computer. Unix sockets
+are used if you don't specify a hostname or if you specify the special
+hostname @code{localhost}.
+
+On Windows you can connect only with TCP/IP if the @code{mysqld} server
+is running on Win95/Win98. If it's running on NT, you can also connect
+with named pipes. The name of the named pipe is @code{MySQL}. If you
+don't give a hostname when connecting to @code{mysqld}, a @strong{MySQL} client
+will first try to connect to the named pipe and if this doesn't work it
+will connect to the TCP/IP port. You can force the use of named pipes
+on Windows by using @code{.} as the hostname.
+
+The error (2002) @code{Can't connect to ...} normally means that there
+isn't a @strong{MySQL} server running on the system or that you are
+using a wrong socket file or TCP/IP port when trying to connect to the
+@code{mysqld} server.
+
+Start by checking (using @code{ps} or the task manager on Windows) that
+there is a process running named @code{mysqld} on your server! If there
+isn't any @code{mysqld} process, you should start one. @xref{Starting
+server}.
+
+If a @code{mysqld} process is running, you can check the server by
+trying these different connections (the port number and socket pathname
+might be different in your setup, of course):
+
+@example
+shell> mysqladmin version
+shell> mysqladmin variables
+shell> mysqladmin -h `hostname` version variables
+shell> mysqladmin -h `hostname` --port=3306 version
+shell> mysqladmin -h 'ip for your host' version
+shell> mysqladmin --socket=/tmp/mysql.sock version
+@end example
+
+Note the use of backquotes rather than forward quotes with the @code{hostname}
+command; these cause the output of @code{hostname} (i.e., the current
+hostname) to be substituted into the @code{mysqladmin} command.
+
+Here are some reasons the @code{Can't connect to local MySQL server}
+error might occur:
+
+@itemize @bullet
+@item @code{mysqld} is not running.
+@item You are running on a system that uses MIT-pthreads.
+If you are running on a system that doesn't have native threads, @code{mysqld}
+uses the MIT-pthreads package.
+@xref{Which OS}.
+However, MIT-pthreads doesn't support Unix sockets, so on such a system you
+must always specify the hostname explicitly when connecting to the server.
+Try using this command to check the connection to the server:
+@example
+shell> mysqladmin -h `hostname` version
+@end example
+@item Someone has removed the Unix socket that @code{mysqld} uses (default
+@file{/tmp/mysqld.sock}). You might have a @code{cron} job that removes the
+@strong{MySQL} socket (e.g., a job that removes old files from the @file{/tmp}
+directory). You can always run @code{mysqladmin version} and
+check that the socket @code{mysqladmin} is trying to use really exists.
+The fix in this case is to change the @code{cron} job to not remove
+@file{mysqld.sock} or to place the socket somewhere else. You can specify
+a different socket location at @strong{MySQL} configuration time with this
+command:
+@example
+shell> ./configure --with-unix-socket-path=/path/to/socket
+@end example
+You can also start @code{safe_mysqld} with the
+@code{--socket=/path/to/socket} option and set the environment variable
+@code{MYSQL_UNIX_PORT} to the socket pathname before starting your
+@strong{MySQL} clients. @item You have started the @code{mysqld} server with
+the @code{--socket=/path/to/socket} option. If you change the socket
+pathname for the server, you must also notify the @strong{MySQL} clients
+about the new path. You can do this by setting the environment variable
+@code{MYSQL_UNIX_PORT} to the socket pathname or by providing the socket path
+as an argument to the clients. You can test the socket with this command:
+
+@example
+shell> mysqladmin --socket=/path/to/socket version
+@end example
+@item
+You are using Linux and one thread has died (core dumped). In this case
+you must kill the other @code{mysqld} threads (for example with the
+@code{mysql_zap} script before you can start a new @strong{MySQL}
+server. @xref{Crashing}.
+@end itemize
+
+If you get the error message @code{Can't connect to MySQL server on
+some_hostname}, you can try the following things to find out what is the
+problem:
+
+@itemize @bullet
+@item
+Check if the server up by doing @code{telnet your-host-name
+tcp-ip-port-number} and press @code{RETURN} a couple of times. If there
+is a @strong{MySQL} server running on this port you should get a
+responses that includes the version number of the running @strong{MySQL}
+server. If you get an error like @code{telnet: Unable to connect to
+remote host: Connection refused}, then there is no server running on the
+given port.
+@item
+Try connecting to the @code{mysqld} daemon on the local machine and check
+the TCP/IP port that mysqld it's configured to use (variable @code{port}) with
+@code{mysqladmin variables}.
+@item
+Check that your @code{mysqld} server is not started with the
+@code{--skip-networking} option.
+@end itemize
+
+@node Blocked host, Too many connections, Can not connect to server, Common errors
+@subsection @code{Host '...' is blocked} error
+
+If you get an error like this:
+
+@example
+Host 'hostname' is blocked because of many connection errors.
+Unblock with 'mysqladmin flush-hosts'
+@end example
+
+This means that @code{mysqld} has gotten a lot (@code{max_connect_errors})
+of connect requests from the host @code{'hostname'} that have been interrupted
+in the middle. After @code{max_connect_errors} failed requests, @code{mysqld}
+assumes that something is wrong (like an attack from a cracker), and
+blocks the site from further connections until someone executes the command
+@code{mysqladmin flush-hosts}.
+
+By default, @code{mysqld} blocks a host after 10 connection errors.
+You can easily adjust this by starting the server like this:
+
+@example
+shell> safe_mysqld -O max_connect_errors=10000 &
+@end example
+
+Note that if you get this error message for a given host, you should first
+check that there isn't anything wrong with TCP/IP connections from that
+host. If your TCP/IP connections aren't working, it won't do you any good to
+increase the value of the @code{max_connect_errors} variable!
+
+@node Too many connections, Out of memory, Blocked host, Common errors
+@subsection @code{Too many connections} error
+
+If you get the error @code{Too many connections} when you try to connect
+to @strong{MySQL}, this means that there is already @code{max_connections}
+clients connected to the @code{mysqld} server.
+
+If you need more connections than the default (100), then you should restart
+@code{mysqld} with a bigger value for the @code{max_connections} variable.
+
+Note that @code{mysqld} actually allows (@code{max_connections}+1) clients to connect.
+The last connection is reserved for a user with the @strong{process} privilege.
+By not giving this privilege to normal users (they shouldn't need this), an
+administrator with this privilege can login and use @code{SHOW PROCESSLIST}
+to find out what could be wrong. @xref{SHOW}.
+
+@node Out of memory, Packet too large, Too many connections, Common errors
+@subsection @code{Out of memory} error
+
+If you issue a query and get something like the following error:
+
+@example
+mysql: Out of memory at line 42, 'malloc.c'
+mysql: needed 8136 byte (8k), memory in use: 12481367 bytes (12189k)
+ERROR 2008: MySQL client ran out of memory
+@end example
+
+Note that the error refers to the @strong{MySQL} client @code{mysql}. The
+reason for this error is simply that the client does not have enough memory to
+store the whole result.
+
+To remedy the problem, first check that your query is correct. Is it
+reasonable that it should return so many rows? If so,
+you can use @code{mysql --quick}, which uses @code{mysql_use_result()}
+to retrieve the result set. This places less of a load on the client (but
+more on the server).
+
+@node Packet too large, Communication errors, Out of memory, Common errors
+@subsection @code{Packet too large} error
+
+When a @strong{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}.
+
+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=24M}
+option.
+
+@cindex Aborted connection
+@node Communication errors, Full table, Packet too large, Common errors
+@subsection Communication errors / Aborted connection
+
+If you find the error @code{Aborted connection} in the @code{hostname.err}
+log file this could be because on of the following reasons:
+
+@itemize @bullet
+@item
+The client had been sleeping more than @code{wait_timeout} without doing
+any requests. @xref{SHOW VARIABLES}.
+@item
+The client program ended abruptly in the middle of the transfer
+@item
+The client program did not call @code{mysql_close()} before exit
+@item
+Usage of duplex Ethernet protocol, both half and full with
+Linux. Many Linux Ethernet drivers have this bug. You should test
+for this bug by transferring a huge file via ftp between these tow
+machines. If a transfer goes in burst-pause-burst-pause .. mode then
+you are experiencing a Linux duplex syndrome. The only solution to
+this problem is switching of both half and full duplexing on hubs
+and switches
+@item
+Some problem with the thread library that causes interrupts on reads.
+@item
+Badly configured TCP/IP
+@item
+Faulty Ethernets or hubs or switches, cables .. This can be diagnosed
+properly only by replacing hardware
+@end itemize
+
+@cindex The table is full
+@node Full table, Commands out of sync, Communication errors, Common errors
+@subsection @code{The table is full} error
+
+This error occurs in older @strong{MySQL} versions when an in-memory temporary
+table becomes larger than @code{tmp_table_size} bytes. To avoid this
+problem, you can use the @code{-O tmp_table_size=#} option to
+@code{mysqld} to increase the temporary table size, or use the SQL
+option @code{SQL_BIG_TABLES} before you issue the problematic
+query. @xref{SET OPTION, , @code{SET OPTION}}.
+
+You can also start @code{mysqld} with the @code{--big-tables} option.
+This is exactly the same as using @code{SQL_BIG_TABLES} for all queries.
+
+In @strong{MySQL} 3.23 in-memory temporary tables will automaticly be
+converted to a disk based @code{MyISAM} table after the table size gets
+bigger than @code{tmp_table_size}.
+
+@cindex Commands out of sync
+@node Commands out of sync, Ignoring user, Full table, Common errors
+@subsection @code{Commands out of sync} error in client
+
+If you get @code{Commands out of sync; You can't run this command now}
+in your client code, you are calling client functions in the wrong order!
+
+This can happen, for example, if you are using @code{mysql_use_result()} and
+try to execute a new query before you have called @code{mysql_free_result()}.
+It can also happen if you try to execute two queries that return data without
+a @code{mysql_use_result()} or @code{mysql_store_result()} in between.
+
+@node Ignoring user, Cannot find table, Commands out of sync, Common errors
+@subsection @code{Ignoring user} error
+
+If you get the following error:
+
+@code{Found wrong password for user: 'some_user@@some_host'; Ignoring user}
+
+This means that when @code{mysqld} was started or when it reloaded the
+permissions tables, it found an entry in the @code{user} table with
+an invalid password. As a result, the entry is simply ignored by the
+permission system.
+
+Possible causes of and fixes for this problem:
+
+@itemize @bullet
+@item
+You may be running a new version of @code{mysqld} with an old
+@code{user} table.
+You can check this by executing @code{mysqlshow mysql user} to see if
+the password field is shorter than 16 characters. If so, you can correct this
+condition by running the @code{scripts/add_long_password} script.
+
+@item
+The user has an old password (8 chararacters long) and you didn't start
+@code{mysqld} with the @code{--old-protocol} option.
+Update the user in the @code{user} table with a new password or
+restart @code{mysqld} with @code{--old-protocol}.
+
+@item
+@findex PASSWORD()
+You have specified a password in the @code{user} table without using the
+@code{PASSWORD()} function. Use @code{mysql} to update the user in the
+@code{user} table with a new password. Make sure to use the @code{PASSWORD()}
+function:
+
+@example
+mysql> update user set password=PASSWORD('your password')
+ where user='XXX';
+@end example
+@end itemize
+
+@node Cannot find table, , Ignoring user, Common errors
+@subsection @code{Table 'xxx' doesn't exist} error
+
+If you get the error @code{Table 'xxx' doesn't exist} or @code{Can't
+find file: 'xxx' (errno: 2)}, this means that no table exists
+in the current database with the name @code{xxx}.
+
+Note that as @strong{MySQL} uses directories and files to store databases and
+tables, the database and table names are @strong{case sensitive}!
+(On Win32 the databases and tables names are not case sensitive, but all
+references to a given table within a query must use the same case!)
+
+You can check which tables you have in the current database with
+@code{SHOW TABLES}. @xref{SHOW, , @code{SHOW}}.
+
+@cindex Full disk
+@cindex Disk full
+@node Full disk, Multiple sql commands, Common errors, Problems
+@section How MySQL handles a full disk
+
+@noindent
+When a disk full condition occurs, @strong{MySQL} does the following:
+
+@itemize @bullet
+@item
+It checks once every minute to see whether or not there is enough space to
+write the current row. If there is enough space, it continues as if nothing had
+happened.
+@item
+Every 6 minutes it writes an entry to the log file warning about the disk
+full condition.
+@end itemize
+
+@noindent
+To alleviate the problem, you can take the following actions:
+
+@itemize @bullet
+@item
+To continue, you only have to free enough disk space to insert all records.
+@item
+To abort the thread, you must send a @code{mysqladmin kill} to the thread.
+The thread will be aborted the next time it checks the disk (in 1 minute).
+@item
+Note that other threads may be waiting for the table that caused the ``disk
+full'' condition. If you have several ``locked'' threads, killing the one
+thread that is waiting on the disk full condition will allow the other
+threads to continue.
+@end itemize
+
+@node Multiple sql commands, Temporary files, Full disk, Problems
+@section How to run SQL commands from a text file
+
+The @code{mysql} client typically is used interactively, like this:
+
+@example
+shell> mysql database
+@end example
+
+However, it's also possible to put your SQL commands in a file and tell
+@code{mysql} to read its input from that file. To do so, create a text
+file @file{text_file} that contains the commands you wish to execute.
+Then invoke @code{mysql} as shown below:
+
+@example
+shell> mysql database < text_file
+@end example
+
+You can also start your text file with a @code{USE db_name} statement. In
+this case, it is unnecessary to specify the database name on the command
+line:
+
+@example
+shell> mysql < text_file
+@end example
+
+@xref{Programs}.
+
+@node Temporary files, Problems with mysql.sock, Multiple sql commands, Problems
+@section Where MySQL stores temporary files
+
+@strong{MySQL} uses the value of the @code{TMPDIR} environment variable as
+the pathname of the directory in which to store temporary files. If you don't
+have @code{TMPDIR} set, @strong{MySQL} uses the system default, which is
+normally @file{/tmp} or @file{/usr/tmp}. If the file system containing your
+temporary file directory is too small, you should edit @code{safe_mysqld} to
+set @code{TMPDIR} to point to a directory in a file system where you have
+enough space! You can also set the temporary directory using the
+@code{--tmpdir} option to @code{mysqld}.
+
+@strong{MySQL} creates all temporary files as ``hidden files''. This ensures
+that the temporary files will be removed if @code{mysqld} is terminated. The
+disadvantage of using hidden files is that you will not see a big temporary
+file that fills up the file system in which the temporary file directory is
+located.
+
+When sorting (@code{ORDER BY} or @code{GROUP BY}), @strong{MySQL} normally
+uses one or two temporary files. The maximum disk-space needed is:
+
+@example
+(length of what is sorted + sizeof(database pointer))
+* number of matched rows
+* 2
+@end example
+
+@code{sizeof(database pointer)} is usually 4, but may grow in the future for
+really big tables.
+
+For some @code{SELECT} queries, @strong{MySQL} also creates temporary SQL
+tables. These are not hidden and have names of the form @file{SQL_*}.
+
+@code{ALTER TABLE} and @code{OPTIMIZE TABLE} create a temporary table in the
+same directory as the original table.
+
+@node Problems with mysql.sock, Error Access denied, Temporary files, Problems
+@section How to protect @file{/tmp/mysql.sock} from being deleted
+
+If you have problems with the fact that anyone can delete the
+@strong{MySQL} communication socket @file{/tmp/mysql.sock}, you can,
+on most versions of Unix, protect your @file{/tmp} file system by setting
+the @code{sticky} bit on it. Log in as @code{root} and do the following:
+
+@example
+shell> chmod +t /tmp
+@end example
+
+This will protect your @file{/tmp} file system so that files can be deleted
+only by their owners or the superuser (@code{root}).
+
+You can check if the @code{sticky} bit is set by executing @code{ls -ld /tmp}.
+If the last permission bit is @code{t}, the bit is set.
+
+@node Error Access denied, Changing MySQL user , Problems with mysql.sock, Problems
+@section @code{Access denied} error
+
+@xref{Privileges}. And especially see @ref{Access denied}.
+
+@node Changing MySQL user , Resetting permissions, Error Access denied, Problems
+@section How to run MySQL as a normal user
+
+The @strong{MySQL} server @code{mysqld} can be started and run by any user.
+In order to change @code{mysqld} to run as Unix user @code{user_name}, you must
+do the following:
+
+@enumerate
+@item
+Stop the server if it's running (use @code{mysqladmin shutdown}).
+
+@item
+Change the database directories and files so that @code{user_name} has
+privileges to read and write files in them (you may need to do this as
+the Unix @code{root} user):
+
+@example
+shell> chown -R user_name /path/to/mysql/datadir
+@end example
+
+If directories or files within the @strong{MySQL} data directory are
+symlinks, you'll also need to follow those links and change the directories
+and files they point to. @code{chown -R} may not follow symlinks for
+you.
+
+@item
+Start the server as user @code{user_name}, or, if you are using
+@strong{MySQL} 3.22 or later, start @code{mysqld} as the Unix @code{root}
+user and use the @code{--user=user_name} option. @code{mysqld} will switch
+to run as Unix user @code{user_name} before accepting any connections.
+
+@item
+If you are using the @code{mysql.server} script to start @code{mysqld} when
+the system is rebooted, you should edit @code{mysql.server} to use @code{su}
+to run @code{mysqld} as user @code{user_name}, or to invoke @code{mysqld}
+with the @code{--user} option. (No changes to @code{safe_mysqld} are
+necessary.)
+@end enumerate
+
+At this point, your @code{mysqld} process should be running fine and dandy as
+the Unix user @code{user_name}. One thing hasn't changed, though: the
+contents of the permissions tables. By default (right after running the
+permissions table install script @code{mysql_install_db}), the @strong{MySQL}
+user @code{root} is the only user with permission to access the @code{mysql}
+database or to create or drop databases. Unless you have changed those
+permissions, they still hold. This shouldn't stop you from accessing
+@strong{MySQL} as the @strong{MySQL} @code{root} user when you're logged in
+as a Unix user other than @code{root}; just specify the @code{-u root} option
+to the client program.
+
+Note that accessing @strong{MySQL} as @code{root}, by supplying @code{-u
+root} on the command line, has @emph{nothing} to do with @strong{MySQL} running
+as the Unix @code{root} user, or, indeed, as other Unix user. The access
+permissions and user names of @strong{MySQL} are completely separate from
+Unix user names. The only connection with Unix user names is that if you
+don't provide a @code{-u} option when you invoke a client program, the client
+will try to connect using your Unix login name as your @strong{MySQL} user
+name.
+
+If your Unix box itself isn't secured, you should probably at least put a
+password on the @strong{MySQL} @code{root} users in the access tables.
+Otherwise, any user with an account on that machine can run @code{mysql -u
+root db_name} and do whatever he likes.
+
+@node Resetting permissions, File permissions , Changing MySQL user , Problems
+@section How to reset a forgotten password.
+
+If you have forgotten the @code{root} user password for @strong{MySQL}, you
+can restore it with the following procedure.
+
+@enumerate
+@item
+Take down the mysqld server by sending a @code{kill} (not @code{kill
+-9}) to the @code{mysqld} server. The pid is stored in a @code{.pid}
+file which is normally in the @strong{MySQL} database directory:
+
+@example
+kill `cat /mysql-data-directory/hostname.pid`
+@end example
+
+You must be either the Unix @code{root} user or the same user the server
+runs as to do this.
+
+@item
+Restart @code{mysqld} with the @code{--skip-grant-tables} option.
+@item
+Connect to the mysqld server with @code{mysql -h hostname mysql} and change
+the password with a @code{GRANT} command. @xref{GRANT,,@code{GRANT}}.
+You can also do this with
+@code{mysqladmin -h hostname -u user password 'new password'}
+@item
+Load the privilege tables with: @code{mysqladmin -h hostname
+flush-privileges} or with the SQL command @code{FLUSH PRIVILEGES}.
+@end enumerate
+
+@node File permissions , Not enough file handles, Resetting permissions, Problems
+@section Problems with file permissions
+
+If you have problems with file permissions, for example, if @code{mysql}
+issues the following error message when you create a table:
+
+@example
+ERROR: Can't find file: 'path/with/filename.frm' (Errcode: 13)
+@end example
+
+@tindex UMASK environment variable
+@tindex Environment variable, UMASK
+Then the environment variable @code{UMASK} might be set incorrectly when
+@code{mysqld} starts up. The default umask value is @code{0660}. You can
+change this behavior by starting @code{safe_mysqld} as follows:
+
+@example
+shell> UMASK=384 # = 600 in octal
+shell> export UMASK
+shell> /path/to/safe_mysqld &
+@end example
+
+@tindex UMASK_DIR environment variable
+@tindex Environment variable, UMASK_DIR
+By default @strong{MySQL} will create database and @code{RAID}
+directories with permission type 0700. You can modify this behaviour by
+setting the the @code{UMASK_DIR} variable. If you set this, new
+directories are created with the combined @code{UMASK} and
+@code{UMASK_DIR}. For example, if you want to give group access to
+all new directories, you can do:
+
+@example
+shell> UMASK_DIR=504 # = 770 in octal
+shell> export UMASK_DIR
+shell> /path/to/safe_mysqld &
+@end example
+
+@xref{Environment variables}.
+
+@node Not enough file handles, Using DATE, File permissions , Problems
+@section File not found
+
+If you get @code{ERROR '...' not found (errno: 23)}, @code{Can't open
+file: ... (errno: 24)} or any other error with @code{errno 23} or
+@code{errno 24} from @strong{MySQL}, it means that you haven't allocated
+enough file descriptors for @strong{MySQL}. You can use the
+@code{perror} utility to get a description of what the error number
+means:
+
+@example
+shell> perror 23
+File table overflow
+shell> perror 24
+Too many open files
+@end example
+
+The problem here is that @code{mysqld} is trying to keep open too many
+files simultaneously. You can either tell @code{mysqld} not to open so
+many files at once, or increase the number of file descriptors
+available to @code{mysqld}.
+
+To tell @code{mysqld} to keep open fewer files at a time, you can make the
+table cache smaller by using the @code{-O table_cache=32} option
+to @code{safe_mysqld} (the default value is 64). Reducing the value of
+@code{max_connections} will also reduce the number of open files (the default
+value is 90).
+
+@tindex ulimit
+To change the number of file descriptors available to @code{mysqld}, modify
+the @code{safe_mysqld} script. There is a commented-out line
+@code{ulimit -n 256} in the script. You can remove the @code{'#'} character
+to uncomment this line, and change the number 256 to change the number of
+file descriptors available to @code{mysqld}.
+
+@code{ulimit} can increase the number of file descriptors, but only up to the
+limit imposed by the operating system. 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.
+
+Note that if you run the @code{tcsh} shell, @code{ulimit} will not work!
+@code{tcsh} will also report incorrect values when you ask for the current
+limits! In this case you should start @code{safe_mysqld} with @code{sh}!
+
+@node Using DATE, Timezone problems, Not enough file handles, Problems
+@section Problems using @code{DATE} columns
+
+The format of a @code{DATE} value is @code{'YYYY-MM-DD'}. According to ANSI
+SQL, no other format is allowed. You should use this format in @code{UPDATE}
+expressions and in the WHERE clause of @code{SELECT} statements. For
+example:
+
+@example
+mysql> SELECT * FROM tbl_name WHERE date >= '1997-05-05';
+@end example
+
+As a convenience, @strong{MySQL} automatically converts a date to a number if
+the date is used in a numeric context (and vice versa). It is also smart
+enough to allow a ``relaxed'' string form when updating and in a @code{WHERE}
+clause that compares a date to a @code{TIMESTAMP}, @code{DATE} or a
+@code{DATETIME} column. (Relaxed form means that any punctuation character
+may be used as the separator between parts. For example, @code{'1998-08-15'}
+and @code{'1998#08#15'} are equivalent.) @strong{MySQL} can also convert a
+string containing no separators (such as @code{'19980815'}), provided it
+makes sense as a date.
+
+The special date @code{'0000-00-00'} can be stored and retrieved as
+@code{'0000-00-00'.} When using a @code{'0000-00-00'} date through
+@strong{MyODBC}, it will automatically be converted to @code{NULL} in
+@strong{MyODBC} 2.50.12 and above, because ODBC can't handle this kind of
+date.
+
+Because @strong{MySQL} performs the conversions described above, the following
+statements work:
+
+@example
+mysql> INSERT INTO tbl_name (idate) VALUES (19970505);
+mysql> INSERT INTO tbl_name (idate) VALUES ('19970505');
+mysql> INSERT INTO tbl_name (idate) VALUES ('97-05-05');
+mysql> INSERT INTO tbl_name (idate) VALUES ('1997.05.05');
+mysql> INSERT INTO tbl_name (idate) VALUES ('1997 05 05');
+mysql> INSERT INTO tbl_name (idate) VALUES ('0000-00-00');
+
+mysql> SELECT idate FROM tbl_name WHERE idate >= '1997-05-05';
+mysql> SELECT idate FROM tbl_name WHERE idate >= 19970505;
+mysql> SELECT mod(idate,100) FROM tbl_name WHERE idate >= 19970505;
+mysql> SELECT idate FROM tbl_name WHERE idate >= '19970505';
+@end example
+
+@noindent
+However, the following will not work:
+
+@example
+mysql> SELECT idate FROM tbl_name WHERE STRCMP(idate,'19970505')=0;
+@end example
+
+@code{STRCMP()} is a string function, so it converts @code{idate} to
+a string and performs a string comparison. It does not convert
+@code{'19970505'} to a date and perform a date comparison.
+
+Note that @strong{MySQL} does no checking whether or not the date is
+correct. If you store an incorrect date, such as @code{'1998-2-31'}, the
+wrong date will be stored. If the date cannot be converted to any reasonable
+value, a @code{0} is stored in the @code{DATE} field. This is mainly a speed
+issue and we think it is up to the application to check the dates, and not
+the server.
+
+@cindex Timezone problems
+@tindex TZ environment variable
+@tindex Environment variable, TZ
+@node Timezone problems, Case sensitivity, Using DATE, Problems
+@section Timezone problems
+
+If you have a problem with @code{SELECT NOW()} returning values in GMT and
+not your local time, you have to set the @code{TZ} environment variable to
+your current timezone. This should be done for the environment in which
+the server runs, for example in @code{safe_mysqld} or @code{mysql.server}.
+@xref{Environment variables}.
+
+@cindex Case sensitivity, in searches
+@cindex Chinese
+@cindex Big5 Chinese character encoding
+@node Case sensitivity, Problems with NULL, Timezone problems, Problems
+@section Case sensitivity in searches
+
+By default, @strong{MySQL} searches are case-insensitive (although there are
+some character sets that are never case insensitive, such as @code{czech}).
+That means that if you search with @code{col_name LIKE 'a%'}, you will get all
+column values that start with @code{A} or @code{a}. If you want to make this
+search case-sensitive, use something like @code{INDEX(col_name, "A")=0} to
+check a prefix. Or use @code{STRCMP(col_name, "A") = 0} if the column value
+must be exactly @code{"A"}.
+
+Simple comparison operations (@code{>=, >, = , < , <=}, sorting and
+grouping) are based on each character's ``sort value''. Characters with
+the same sort value (like E, e and é) are treated as the same character!
+
+In older @strong{MySQL} versions @code{LIKE} comparisons where done on
+the uppercase value of each character (E == e but E <> é). In newer
+@strong{MySQL} versions @code{LIKE} works just like the other comparison
+operators.
+
+If you want a column always to be treated in case-sensitive fashion,
+declare it as @code{BINARY}. @xref{CREATE TABLE, , @code{CREATE TABLE}}.
+
+If you are using Chinese data in the so-called big5 encoding, you want to
+make all character columns @code{BINARY}. This works because the sorting
+order of big5 encoding characters is based on the order of ASCII codes.
+
+@cindex @code{NULL} values vs. empty values
+@tindex NULL
+@node Problems with NULL, Problems with alias, Case sensitivity, Problems
+@section Problems with @code{NULL} values
+
+The concept of the @code{NULL} value is a common source of confusion for
+newcomers to SQL, who often think that @code{NULL} is the same thing as an
+empty string @code{''}. This is not the case! For example, the following
+statements are completely different:
+
+@example
+mysql> INSERT INTO my_table (phone) VALUES (NULL);
+mysql> INSERT INTO my_table (phone) VALUES ("");
+@end example
+
+Both statements insert a value into the @code{phone} column, but the first
+inserts a @code{NULL} value and the second inserts an empty string. The
+meaning of the first can be regarded as ``phone number is not known'' and the
+meaning of the second can be regarded as ``she has no phone''.
+
+In SQL, the @code{NULL} value is always false in comparison to any
+other value, even @code{NULL}. 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. All columns in the following example return @code{NULL}:
+
+@example
+mysql> SELECT NULL,1+NULL,CONCAT('Invisible',NULL);
+@end example
+
+If you want to search for column values that are @code{NULL}, you
+cannot use the @code{=NULL} test. The following statement returns no
+rows, because @code{expr = NULL} is FALSE, for any expression:
+
+@example
+mysql> SELECT * FROM my_table WHERE phone = NULL;
+@end example
+
+To look for @code{NULL} values, you must use the @code{IS NULL} test.
+The following shows how to find the @code{NULL} phone number and the
+empty phone number:
+
+@example
+mysql> SELECT * FROM my_table WHERE phone IS NULL;
+mysql> SELECT * FROM my_table WHERE phone = "";
+@end example
+
+In @strong{MySQL}, as in many other SQL servers, you can't index
+columns that can have @code{NULL} values. You must declare such columns
+@code{NOT NULL}. Conversely, you cannot insert @code{NULL} into an indexed
+column.
+
+@findex LOAD DATA INFILE
+When reading data with @code{LOAD DATA INFILE}, empty columns are updated
+with @code{''}. If you want a @code{NULL} value in a column, you should use
+@code{\N} in the text file. The literal word @code{'NULL'} may also be used
+under some circumstances.
+@xref{LOAD DATA, , @code{LOAD DATA}}.
+
+When using @code{ORDER BY}, @code{NULL} values are presented first. If you
+sort in descending order using @code{DESC}, @code{NULL} values are presented
+last. When using @code{GROUP BY}, all @code{NULL} values are regarded as
+equal.
+
+To help with @code{NULL} handling, you can use the @code{IS NULL} and
+@code{IS NOT NULL} operators and the @code{IFNULL()} function.
+
+@cindex @code{TIMESTAMP}, and @code{NULL} values
+@cindex @code{AUTO_INCREMENT}, and @code{NULL} values
+@cindex @code{NULL} values, and @code{TIMESTAMP} columns
+@cindex @code{NULL} values, and @code{AUTO_INCREMENT} columns
+For some column types, @code{NULL} values are handled specially. If you
+insert @code{NULL} into the first @code{TIMESTAMP} column of a table, the
+current date and time is inserted. If you insert @code{NULL} into an
+@code{AUTO_INCREMENT} column, the next number in the sequence is inserted.
+
+@tindex alias
+@node Problems with alias, Deleting from related tables, Problems with NULL, Problems
+@section Problems with @code{alias}
+
+You can use an alias to refer to a column in the @code{GROUP BY},
+@code{ORDER BY} or in the @code{HAVING} part. Aliases can also be used
+to give columns more better names:
+
+@example
+SELECT SQRT(a*b) as rt FROM table_name GROUP BY rt HAVING rt > 0;
+SELECT id,COUNT(*) AS cnt FROM table_name GROUP BY id HAVING cnt > 0;
+SELECT id AS "Customer identity" FROM table_name;
+@end example
+
+Note that you ANSI SQL doesn't allow you to refer to an alias in a
+@code{WHERE} clause. This is because when the @code{WHERE} code is
+executed the column value may not yet be determinated. For example the
+following query is @strong{illegal}:
+
+@example
+SELECT id,COUNT(*) AS cnt FROM table_name WHERE cnt > 0 GROUP BY id;
+@end example
+
+The @code{WHERE} statement is executed to determinate which rows should
+be included in the @code{GROUP BY} part while @code{HAVING} is used to
+decide which rows from the result set should be used.
+
+@node Deleting from related tables, No matching rows, Problems with alias, Problems
+@section Deleting rows from related tables
+
+As @strong{MySQL} doesn't support sub-selects or use of more than one table
+in the @code{DELETE} statement, you should use the following approach to
+delete rows from 2 related tables:
+
+@enumerate
+@item
+@code{SELECT} the rows based on some @code{WHERE} condition in the main table.
+@item
+@code{DELETE} the rows in the main table based on the same condition.
+@item
+@code{DELETE FROM related_table WHERE related_column IN (selected_rows)}
+@end enumerate
+
+If the total number of characters in the query with
+@code{related_column} is more than 1,048,576 (the default value of
+@code{max_allowed_packet}, you should split it into smaller parts and
+execute multiple @code{DELETE} statements. You will probably get the
+fastest @code{DELETE} by only deleting 100-1000 @code{related_column}
+id's per query if the @code{related_column} is an index. If the
+@code{related_column} isn't an index, the speed is independent of the
+number of arguments in the @code{IN} clause.
+
+@node No matching rows, ALTER TABLE problems, Deleting from related tables, Problems
+@section Solving problems with no matching rows
+
+If you have a complicated query with many tables that doesn't return any
+rows, you should use the following procedure to find out what is wrong
+with your query:
+
+@enumerate
+@item
+Test the query with @code{EXPLAIN} and check if you can find something that is
+obviously wrong. @xref{EXPLAIN, , @code{EXPLAIN}}.
+
+@item
+Select only those fields that are used in the @code{WHERE} clause.
+
+@item
+Remove one table at a time from the query until it returns some rows.
+If the tables are big, it's a good idea to use @code{LIMIT 10} with the query.
+
+@item
+Do a @code{SELECT} for the column that should have matched a row,
+against 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!
+
+@item
+If you still can't figure out what's wrong, create a minimal test that can
+be run with @code{mysql test < query.sql} that shows your problems.
+You can create a test file with @code{mysqldump --quick database tables > query.sql}. Open the file in an editor, remove some insert lines (if there are
+too many of these) and add your select statement at the end of the file.
+
+Test that you still have your problem by doing:
+
+@example
+shell> mysqladmin create test2
+shell> mysql test2 < query.sql
+@end example
+
+Post the test file using @code{mysqlbug} to @email{mysql@@lists.mysql.com}.
+@end enumerate
+
+@node ALTER TABLE problems, Change column order, No matching rows, Problems
+@section Problems with @code{ALTER TABLE}.
+
+If @code{ALTER TABLE} dies with an error like this:
+
+@example
+Error on rename of './database/name.frm' to './database/B-a.frm' (Errcode: 17)
+@end example
+
+The problem may be that @strong{MySQL} has crashed in a previous @code{ALTER
+TABLE} and there is an old table named @file{A-something} or
+@file{B-something} lying around. In this case, go to the @strong{MySQL} data
+directory and delete all files that have names starting with @code{A-} or
+@code{B-}. (You may want to move them elsewhere instead of deleting them).
+
+@code{ALTER TABLE} works the following way:
+
+@itemize @bullet
+@item Create a new table named @file{A-xxx} with the requested changes.
+@item All rows from the old table are copied to @file{A-xxx}.
+@item The old table is renamed @file{B-xxx}.
+@item @file{A-xxx} is renamed to your old table name.
+@item @file{B-xxx} is deleted.
+@end itemize
+
+If something goes wrong with the renaming operation, @strong{MySQL} tries to
+undo the changes. If something goes seriously wrong (this shouldn't happen,
+of course), @strong{MySQL} may leave the old table as @file{B-xxx} but a
+simple rename should get your data back.
+
+@node Change column order, , ALTER TABLE problems, Problems
+@section How to change the order of columns in a table
+
+The whole point of SQL is to abstract the application from the data
+storage format. You should always specify the order in wish you wish to
+retrieve your data. For example:
+
+@example
+SELECT col_name1, col_name2, col_name3 FROM tbl_name;
+@end example
+
+will return columns in the order @code{col_name1}, @code{col_name2}, @code{col_name3}, whereas:
+
+@example
+SELECT col_name1, col_name3, col_name2 FROM tbl_name;
+@end example
+
+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
+retrieve the columns based on their position, because the order in which columns are
+returned @strong{CANNOT} be guaranteed over time; A simple change to
+your database may cause your application to fail rather dramatically.
+
+If you want to change the order of columns anyway, you can do it as follows:
+
+@enumerate
+@item
+Create a new table with the columns in the right order.
+@item
+Execute
+@code{INSERT INTO new_table SELECT fields-in-new_table-order FROM old_table}.
+@item
+Drop or rename @code{old_table}
+@item
+@code{ALTER TABLE new_table RENAME old_table}
+@end enumerate
+
+@node Common problems, Clients, Problems, Top
+@chapter Solving some common problems with MySQL
+
+@cindex Replication
+@menu
+* Log Replication:: Database replication with update log
+* Backup:: Database backups
+* Update log:: The update log
+* Multiple servers:: Running multiple @strong{MySQL} servers on the same machine
+@end menu
+
+@cindex Database replication
+@cindex Replication, database
+@node Log Replication, Backup, Common problems, Common problems
+@section Database replication with update log
+
+
+Now that master-slave internal replication is available starting in 3.23.15,
+this is the recommended way. However, it is still possible to replicate a database by
+using the update
+log. @xref{Update log}. This requires one database that acts as a master
+(to which data changes are made) and one or more other databases that act
+as slaves. To update a slave, just run @code{mysql < update_log}.
+Supply host, user and password options that are appropriate for the slave
+database, and use the update log from the master database as input.
+
+If you never delete anything from a table, you can use a @code{TIMESTAMP}
+column to find out which rows have been inserted or changed in the table
+since the last replication (by comparing to the time when you did the
+replication last time) and only copy these rows to the mirror.
+
+It is possible to make a two-way updating system using both the update
+log (for deletes) and timestamps (on both sides). But in that case you
+must be able to handle conflicts when the same data have been changed in
+both ends. You probably want to keep the old version to help with
+deciding what has been updated.
+
+Because replication in this case is done with SQL statements, you should not
+use the following functions in statements that update the database; they may
+not return the same value as in the original database:
+
+@itemize @bullet
+@item @code{DATABASE()}
+@item @code{GET_LOCK()} and @code{RELEASE_LOCK()}
+@item @code{RAND()}
+@item @code{USER()}, @code{SYSTEM_USER()} or @code{SESSION_USER()}
+@item @code{VERSION()}, @code{CONNECT_ID()}
+@end itemize
+
+All time functions are safe to use, as the timestamp is sent to the
+mirror if needed. @code{LAST_INSERT_ID()} is also safe to use.
+
+@cindex Backups
+@node Backup, Update log, Log Replication, Common problems
+@section Database backups
+
+Because @strong{MySQL} tables are stored as files, it is easy to do a
+backup. To get a consistent backup, do a @code{LOCK TABLES} on the
+relevant tables. @xref{LOCK TABLES, , @code{LOCK TABLES}}. You only need a
+read lock; this allows other threads to continue to query the tables while
+you are making a copy of the files in the database directory. If you want to
+make a SQL level backup of a table, you can use @code{SELECT INTO OUTFILE}.
+
+Another way to backup a database is to use the @code{mysqldump} program:
+@xref{mysqldump}.
+
+@enumerate
+@item
+Do a full backup of your databases:
+
+@example
+shell> mysqldump --tab=/path/to/some/dir --opt --full
+@end example
+
+You can also simply copy all table files (@file{*.frm}, @file{*.MYD} and
+@file{*.MYI} files), as long as the server isn't updating anything.
+The script @code{mysqlhotcopy} does use this method.
+
+@item
+@cindex Log file, names
+Stop @code{mysqld} if it's running, then start it with the
+@code{--log-update[=file_name]} option. @xref{Update log}. The update
+log file(s) provide you with the information you need to replicate
+changes to the database that are made subsequent to the point at which
+you executed @code{mysqldump}.
+@end enumerate
+
+If you have to restore something, try to recover your tables using
+@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 @strong{MySQL} with
+@code{--log-update}. @xref{Update log}.)
+
+@enumerate
+@item
+Restore the original @code{mysqldump} backup.
+@item
+Execute the following command to re-run the updates in the update logs:
+@example
+shell> ls -1 -t -r hostname.[0-9]* | xargs cat | mysql
+@end example
+@end enumerate
+
+@code{ls} is used to get all the update log files in the right order.
+
+You can also do selective backups with @code{SELECT * INTO OUTFILE 'file_name'
+FROM tbl_name} and restore with @code{LOAD DATA INFILE 'file_name' REPLACE
+...} To avoid duplicate records, you need a @code{PRIMARY KEY} or a
+@code{UNIQUE} key in the table. The @code{REPLACE} keyword causes old records
+to be replaced with new ones when a new record duplicates an old record on
+a unique key value.
+
+@cindex Update log
+@node Update log, Multiple servers, Backup, Common problems
+@section The update log
+
+When started with the @code{--log-update[=file_name]} option,
+@code{mysqld} writes a log file containing all SQL commands that update
+data. If no file name is given, it defaults to the name of the host
+machine, If file name is given, but it doesn't contain a path the file
+is written in the data directory. If file_name doesn't have an
+extension, @code{mysqld} will create log file names of type
+@code{file_name.#}, where @code{#} is a number that is incremented each
+time you execute @code{mysqladmin refresh} or @code{mysqladmin
+flush-logs}, the @code{FLUSH LOGS} statement, or restart the server.
+
+@strong{Note:} For the above scheme to work, you should NOT create
+own files with the same file name as the update log + some extensions
+that may be regarded as a number, in the directory used by the update log!
+
+If you use the @code{--log} or @code{-l} options, @code{mysqld} writes a
+general log with a filename of @file{hostname.log}, and restarts and
+refreshes do not cause a new log file to be generated (although it is closed
+and reopened). In this case you can copy it (on Unix) by doing:
+
+@example
+mv hostname.log hostname-old.log
+mysqladmin flush-logs
+cp hostname-old.log to-backup-directory
+rm hostname-old.log
+@end example
+
+By default, the @code{mysql.server} script starts the @strong{MySQL}
+server with the @code{-l} option. If you need better performance when
+you start using @strong{MySQL} in a production environment, you can
+remove the @code{-l} option from @code{mysql.server} or change it to
+@code{--log-update}.
+
+Update logging is smart because it logs only statements that really update
+data. So an @code{UPDATE} or a @code{DELETE} with a @code{WHERE} that finds no
+rows is not written to the log. It even skips @code{UPDATE} statements that
+set a column to the value it already has.
+
+If you want to update a database from update log files, you could do the
+following (assuming your update logs have names of the form
+@file{file_name.###}):
+
+@example
+shell> ls -1 -t -r file_name.[0-9]* | xargs cat | mysql
+@end example
+
+@code{ls} is used to get all the log files in the right order.
+
+This can be useful if you have to revert to backup files after a crash
+and you want to redo the updates that occurred between the time of the backup
+and the crash.
+
+@cindex Database replication
+@cindex Replication, database
+@cindex Database mirroring
+@cindex Mirroring, database
+You can also use the update logs when you have a mirrored database on
+another host and you want to replicate the changes that have been made
+to the master database. @xref{Log Replication}.
+
+@cindex Multiple servers
+@node Multiple servers, , Update log, Common problems
+@section Running multiple MySQL servers on the same machine
+
+There are circumstances when you might want to run multiple servers on the same
+machine. For example, you might want to test a new @strong{MySQL} release
+while leaving your existing production setup undisturbed. Or you might
+be an Internet service provider that wants to provide independent
+@strong{MySQL} installations for different customers.
+
+If you want to run multiple servers, the easiest way is to compile the servers
+with different TCP/IP ports and socket files so they are not
+both listening to the same TCP/IP port or socket file.
+
+Assume an existing server is configured for the default port number and
+socket file. Then configure the new server with a @code{configure} command
+something like this:
+
+@example
+shell> ./configure --with-tcp-port=port_number \
+ --with-unix-socket=file_name \
+ --prefix=/usr/local/mysql-3.22.9
+@end example
+
+Here @code{port_number} and @code{file_name} should be different than the
+default port number and socket file pathname, and the @code{--prefix} value
+should specify an installation directory different than the one under which
+the existing @strong{MySQL} installation is located.
+
+You can check the socket and port used by any currently-executing
+@strong{MySQL} server with this command:
+
+@example
+shell> mysqladmin -h hostname --port=port_number variables
+@end example
+
+If you have a @strong{MySQL} server running on the port you used, you will
+get a list of some of the most important configurable variables in
+@strong{MySQL}, including the socket name.
+
+You should also edit the initialization script for your machine (probably
+@file{mysql.server}) to start and kill multiple @code{mysqld} servers.
+
+You don't have to recompile a new @strong{MySQL} server just to start with
+a different port and socket. You can change the port and socket to be used
+by specifying them at runtime as options to @code{safe_mysqld}:
+
+@example
+shell> /path/to/safe_mysqld --socket=file_name --port=port_number
+@end example
+
+If you run the new server on the same database directory as another server
+with logging enabled, you should also specify the name of the log files
+to @code{safe_mysqld} with @code{--log} and @code{--log-update}. Otherwise,
+both servers may be trying to write to the same log file.
+
+@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}.
+
+When you want to connect to a @strong{MySQL} server that is running with
+a different port than the port that is compiled into your client, you
+can use one of the following methods:
+
+@itemize @bullet
+@item
+Start the client with @code{--host 'hostname' --port=port_numer} or
+@code{[--host localhost] --socket=file_name}.
+
+@item
+In your C or Perl programs, you can give the port and socket arguments
+when connecting to the @strong{MySQL} server.
+
+@item
+@tindex MYSQL_UNIX_PORT environment variable
+@tindex MYSQL_TCP_PORT environment variable
+@tindex Environment variable, MYSQL_UNIX_PORT
+@tindex Environment variable, MYSQL_TCP_PORT
+Set the @code{MYSQL_UNIX_PORT} and @code{MYSQL_TCP_PORT} environment variables
+to point to the Unix socket and TCP/IP port before you start your clients.
+If you normally use a specific socket or port, you should place commands
+to set these environment variables in your @file{.login} file.
+@xref{Environment variables}. @xref{Programs}.
+
+@item
+@tindex .my.cnf file
+Specify the default socket and TCP/IP port in the @file{.my.cnf} file in your
+home directory. @xref{Option files}.
+@end itemize
+
+@node Clients, Comparisons, Common problems, Top
+@chapter MySQL client tools and APIs
+
+@menu
+* C:: @strong{MySQL} C API
+* C API datatypes:: C API datatypes
+* C API function overview:: C API function Overview
+* C API functions:: C API function descriptions
+* Perl:: @strong{MySQL} Perl API
+* Eiffel:: @strong{MySQL} Eiffel wrapper
+* Java:: @strong{MySQL} Java connectivity (JDBC)
+* PHP:: @strong{MySQL} PHP API
+* Cplusplus:: @strong{MySQL} C++ APIs
+* Python:: @strong{MySQL} Python APIs
+* Tcl:: @strong{MySQL} Tcl APIs
+@end menu
+
+@node C, C API datatypes, Clients, Clients
+@section MySQL C API
+
+The C API code is distributed with @strong{MySQL}. It is included in the
+@code{mysqlclient} library and allows C programs to access a database.
+
+Many of the clients in the @strong{MySQL} source distribution are
+written in C. If you are looking for examples that demonstrate how to
+use the C API, take a look at these clients. You can find these in the
+@code{clients} directory in the @strong{MySQL} source distribution.
+
+Most of the other client APIs (all except Java) use the @code{mysqlclient}
+library to communicate with the @strong{MySQL} server. This means that, for
+example, you can take advantage of many of the same environment variables
+that are used by other client programs, because they are referenced from the
+library. See @ref{Programs}, for a list of these variables.
+
+The client has a maximum communication buffer size. The size of the buffer
+that is allocated initially (16K bytes) is automatically increased up to the
+maximum size (the default maximum is 24M). Because buffer sizes are increased
+only as demand warrants, simply increasing the default maximum limit does not
+in itself cause more resources to be used. This size check is mostly a check
+for erroneous queries and communication packets.
+
+The communication buffer must be large enough to contain a single SQL
+statement (for client-to-server traffic) and one row of returned data (for
+server-to-client traffic). Each thread's communication buffer is dynamically
+enlarged to handle any query or row up to the maximum limit. For example, if
+you have @code{BLOB} values that contain up to 16M of data, you must have a
+communication buffer limit of at least 16M (in both server and client). The
+client's default maximum is 24M, but the default maximum in the server is
+1M. You can increase this by changing the value of the
+@code{max_allowed_packet} parameter when the server is started. @xref{Server
+parameters}.
+
+The @strong{MySQL} server shrinks each communication buffer to
+@code{net_buffer_length} bytes after each query. For clients, the size of
+the buffer associated with a connection is not decreased until the connection
+is closed, at which time client memory is reclaimed.
+
+If you are programming with threads, you should compile the
+@strong{MySQL} C API with @code{--with-thread-safe-client}. This will make
+the C API thread safe per connection. You can let two threads share the same
+connection as long as you do the following:
+
+@table @asis
+@item
+Two threads can't send a query to the @strong{MySQL} 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.
+@item
+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.
+@end table
+
+@node C API datatypes, C API function overview, C, Clients
+@section C API datatypes
+@table @code
+
+@tindex MYSQL C type
+@item MYSQL
+This structure represents a handle to one database connection. It is
+used for almost all @strong{MySQL} functions.
+
+@tindex MYSQL_RES C type
+@item MYSQL_RES
+This structure represents the result of a query that returns rows
+(@code{SELECT}, @code{SHOW}, @code{DESCRIBE}, @code{EXPLAIN}). The
+information returned from a query is called the @emph{result set} in the
+remainder of this section.
+
+@tindex MYSQL_ROW C type
+@item MYSQL_ROW
+This is a type-safe representation of one row of data. It is currently
+implemented as an array of counted byte strings. (You cannot treat these as
+null-terminated strings if field values may contain binary data, because such
+values may contain null bytes internally.) Rows are obtained by calling
+@code{mysql_fetch_row()}.
+
+@tindex MYSQL_FIELD C type
+@item MYSQL_FIELD
+This structure contains information about a field, such as the field's
+name, type and size. Its members are described in more detail below.
+You may obtain the @code{MYSQL_FIELD} structures for each field by
+calling @code{mysql_fetch_field()} repeatedly. Field values are not part of
+this structure; they are contained in a @code{MYSQL_ROW} structure.
+
+
+@tindex MYSQL_FIELD_OFFSET C type
+@item MYSQL_FIELD_OFFSET
+This is a type-safe representation of an offset into a @strong{MySQL} field
+list. (Used by @code{mysql_field_seek()}.) Offsets are field numbers
+within a row, beginning at zero.
+
+@tindex my_ulonglong C type
+@tindex my_ulonglong values, printing
+@item my_ulonglong
+The type used for the number of rows and for @code{mysql_affected_rows()},
+@code{mysql_num_rows()} and @code{mysql_insert_id()}. This type provides a
+range of @code{0} to @code{1.84e19}.
+
+On some systems, attempting to print a value of type @code{my_ulonglong}
+will not work. To print such a value, convert it to @code{unsigned long}
+and use a @code{%lu} print format. Example:
+@example
+printf (Number of rows: %lu\n", (unsigned long) mysql_num_rows(result));
+@end example
+@end table
+
+@noindent
+The @code{MYSQL_FIELD} structure contains the members listed below:
+
+@table @code
+@item char * name
+The name of the field, as a null-terminated string.
+
+@item char * table
+The name of the table containing this field, if it isn't a calculated field.
+For calculated fields, the @code{table} value is an empty string.
+
+@item char * def
+The default value of this field, as a null-terminated string. This is set
+only if you use @code{mysql_list_fields()}.
+
+@item enum enum_field_types type
+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 @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
+@item @code{FIELD_TYPE_INT24} @tab @code{MEDIUMINT} field
+@item @code{FIELD_TYPE_LONGLONG} @tab @code{BIGINT} field
+@item @code{FIELD_TYPE_DECIMAL} @tab @code{DECIMAL} or @code{NUMERIC} field
+@item @code{FIELD_TYPE_FLOAT} @tab @code{FLOAT} field
+@item @code{FIELD_TYPE_DOUBLE} @tab @code{DOUBLE} or @code{REAL} field
+@item @code{FIELD_TYPE_TIMESTAMP} @tab @code{TIMESTAMP} field
+@item @code{FIELD_TYPE_DATE} @tab @code{DATE} field
+@item @code{FIELD_TYPE_TIME} @tab @code{TIME} field
+@item @code{FIELD_TYPE_DATETIME} @tab @code{DATETIME} field
+@item @code{FIELD_TYPE_YEAR} @tab @code{YEAR} field
+@item @code{FIELD_TYPE_STRING} @tab String (@code{CHAR} or @code{VARCHAR}) field
+@item @code{FIELD_TYPE_BLOB} @tab @code{BLOB} or @code{TEXT} field (use @code{max_length} to determine the maximum length)
+@item @code{FIELD_TYPE_SET} @tab @code{SET} field
+@item @code{FIELD_TYPE_ENUM} @tab @code{ENUM} field
+@item @code{FIELD_TYPE_NULL} @tab @code{NULL}-type field
+@item @code{FIELD_TYPE_CHAR} @tab Deprecated; use @code{FIELD_TYPE_TINY} instead
+@end multitable
+
+You can use the @code{IS_NUM()} macro to test whether or not a field has a
+numeric type. Pass the @code{type} value to @code{IS_NUM()} and it
+will evaluate to TRUE if the field is numeric:
+
+@example
+if (IS_NUM(field->type))
+ printf("Field is numeric\n");
+@end example
+
+@item unsigned int length
+The width of the field, as specified in the table definition.
+
+@item unsigned int max_length
+The maximum width of the field for the result set (the length of the longest
+field value for the rows actually in the result set). If you use
+@code{mysql_store_result()} or @code{mysql_list_fields()}, this contains the
+maximum length for the field. If you use @code{mysql_use_result()}, the
+value of this variable is zero.
+
+@item unsigned int flags
+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 @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
+@item @code{MULTIPLE_KEY_FLAG} @tab Field is part of a non-unique key.
+@item @code{UNSIGNED_FLAG} @tab Field has the @code{UNSIGNED} attribute
+@item @code{ZEROFILL_FLAG} @tab Field has the @code{ZEROFILL} attribute
+@item @code{BINARY_FLAG} @tab Field has the @code{BINARY} attribute
+@item @code{AUTO_INCREMENT_FLAG} @tab Field has the @code{AUTO_INCREMENT} attribute
+@item @code{ENUM_FLAG} @tab Field is an @code{ENUM} (deprecated)
+@item @code{BLOB_FLAG} @tab Field is a @code{BLOB} or @code{TEXT} (deprecated)
+@item @code{TIMESTAMP_FLAG} @tab Field is a @code{TIMESTAMP} (deprecated)
+@end multitable
+
+Use of the @code{BLOB_FLAG}, @code{ENUM_FLAG} and @code{TIMESTAMP_FLAG} flags
+is deprecated because they indicate the type of a field rather than an
+attribute of its type. It is preferable to test @code{field->type} against
+@code{FIELD_TYPE_BLOB}, @code{FIELD_TYPE_ENUM} or @code{FIELD_TYPE_TIMESTAMP}
+instead.
+
+@noindent
+The example below illustrates a typical use of the @code{flags} value:
+
+@example
+if (field->flags & NOT_NULL_FLAG)
+ printf("Field can't be null\n");
+@end example
+
+You may use the following convenience macros to determine the boolean
+status of the @code{flags} value:
+
+@multitable @columnfractions .3 .5
+@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)
+@end multitable
+
+@item unsigned int decimals
+The number of decimals for numeric fields.
+@end table
+
+@node C API function overview, C API functions, C API datatypes, Clients
+@section C API function overview
+
+The functions available in the C API are listed below and are described in
+greater detail in the next section.
+@xref{C API functions}.
+
+@multitable @columnfractions .3 .7
+@item @strong{mysql_affected_rows()} @tab
+Returns the number of rows affected by the last @code{UPDATE}, @code{DELETE} or
+@code{INSERT} query.
+
+@item @strong{mysql_close()} @tab
+Closes a server connection.
+
+@item @strong{mysql_connect()} @tab
+Connects to a @strong{MySQL} server. This function is deprecated; use
+@code{mysql_real_connect()} instead.
+
+@item @strong{mysql_change_user()} @tab
+Change user and database on an open connection.
+
+@item @code{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.
+
+@item @strong{mysql_data_seek()} @tab
+Seeks to an arbitrary row in a query result set.
+
+@item @strong{mysql_debug()} @tab
+Does a @code{DBUG_PUSH} with the given string.
+
+@item @strong{mysql_drop_db()} @tab
+Drops a database. This function is deprecated; use the SQL command
+@code{DROP DATABASE} instead.
+
+@item @strong{mysql_dump_debug_info()} @tab
+Makes the server write debug information to the log.
+
+@item @strong{mysql_eof()} @tab
+Determines whether or not the last row of a result set has been read.
+This function is deprecated; @code{mysql_errno()} or @code{mysql_error()}
+may be used instead.
+
+@item @strong{mysql_errno()} @tab
+Returns the error number for the most recently invoked @strong{MySQL} function.
+
+@item @strong{mysql_error()} @tab
+Returns the error message for the most recently invoked @strong{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.
+
+@item @strong{mysql_fetch_field()} @tab
+Returns the type of the next table field.
+
+@item @strong{mysql_fetch_field_direct()} @tab
+Returns the type of a table field, given a field number.
+
+@item @strong{mysql_fetch_fields()} @tab
+Returns an array of all field structures.
+
+@item @strong{mysql_fetch_lengths()} @tab
+Returns the lengths of all columns in the current row.
+
+@item @strong{mysql_fetch_row()} @tab
+Fetches the next row from the result set.
+
+@item @strong{mysql_field_seek()} @tab
+Puts the column cursor on a specified column.
+
+@item @strong{mysql_field_count()} @tab
+Returns the number of result columns for the most recent query.
+
+@item @strong{mysql_field_tell()} @tab
+Returns the position of the field cursor used for the last
+@code{mysql_fetch_field()}.
+
+@item @strong{mysql_free_result()} @tab
+Frees memory used by a result set.
+
+@item @strong{mysql_get_client_info()} @tab
+Returns client version information.
+
+@item @strong{mysql_get_host_info()} @tab
+Returns a string describing the connection.
+
+@item @strong{mysql_get_proto_info()} @tab
+Returns the protocol version used by the connection.
+
+@item @strong{mysql_get_server_info()} @tab
+Returns the server version number.
+
+@item @strong{mysql_info()} @tab
+Returns information about the most recently executed query.
+
+@item @strong{mysql_init()} @tab
+Gets or initializes a @code{MYSQL} structure.
+
+@item @strong{mysql_insert_id()} @tab
+Returns the ID generated for an @code{AUTO_INCREMENT} column by the previous
+query.
+
+@item @strong{mysql_kill()} @tab
+Kill a given thread.
+
+@item @strong{mysql_list_dbs()} @tab
+Returns database names matching a simple regular expression.
+
+@item @strong{mysql_list_fields()} @tab
+Returns field names matching a simple regular expression.
+
+@item @strong{mysql_list_processes()} @tab
+Returns a list of the current server threads.
+
+@item @strong{mysql_list_tables()} @tab
+Returns table names matching a simple regular expression.
+
+@item @strong{mysql_num_fields()} @tab
+Returns the number of columns in a result set.
+
+@item @strong{mysql_num_rows()} @tab
+Returns the number of rows in a result set.
+
+@item @strong{mysql_options()} @tab
+Set connect options for @code{mysql_connect()}.
+
+@item @strong{mysql_ping()} @tab
+Checks whether or not the connection to the server is working, reconnecting
+as necessary.
+
+@item @strong{mysql_query()} @tab
+Executes a SQL query specified as a null-terminated string.
+
+@item @strong{mysql_real_connect()} @tab
+Connects to a @strong{MySQL} server.
+
+@item @strong{mysql_real_query()} @tab
+Executes a SQL query specified as a counted string.
+
+@item @strong{mysql_reload()} @tab
+Tells the server to reload the grant tables.
+
+@item @strong{mysql_row_seek()} @tab
+Seeks to a row in a result set, using value returned from
+@code{mysql_row_tell()}.
+
+@item @strong{mysql_row_tell()} @tab
+Returns the row cursor position.
+
+@item @strong{mysql_select_db()} @tab
+Selects a database.
+
+@item @strong{mysql_shutdown()} @tab
+Shuts down the database server.
+
+@item @strong{mysql_start_slave()} @tab
+Starts slave replication thread
+
+@item @strong{mysql_stat()} @tab
+Returns the server status as a string.
+
+@item @strong{mysql_store_result()} @tab
+Retrieves a complete result set to the client.
+
+@item @strong{mysql_stop_slave()} @tab
+Stops slave replication thread
+
+@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 threadsafe.
+
+@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
+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
+@code{reconnect} flag (part of the MYSQL structure) to a value of
+@code{1}. This flag indicates, in the event that a query cannot be
+performed because of a lost connection, to try reconnecting to the
+server before giving up. When you are done with the connection, call
+@code{mysql_close()} to terminate it.
+
+While a connection is active, the client may send SQL queries to the server
+using @code{mysql_query()} or @code{mysql_real_query()}. The difference
+between the two is that @code{mysql_query()} expects the query to be
+specified as a null-terminated string whereas @code{mysql_real_query()}
+expects a counted string. If the string contains binary data (which may
+include null bytes), you must use @code{mysql_real_query()}.
+
+For each non-@code{SELECT} query (e.g., @code{INSERT}, @code{UPDATE},
+@code{DELETE}), you can found out how many rows were affected (changed)
+by calling @code{mysql_affected_rows()}.
+
+For @code{SELECT} queries, you retrieve the selected rows as a result set.
+(Note that some statements are @code{SELECT}-like in that they return rows.
+These include @code{SHOW}, @code{DESCRIBE} and @code{EXPLAIN}. They should
+be treated the same way as @code{SELECT} statements.)
+
+There are two ways for a client to process result sets. One way is to
+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
+not actually get any rows from the server.
+
+In both cases, you access rows by calling @code{mysql_fetch_row()}. With
+@code{mysql_store_result()}, @code{mysql_fetch_row()} accesses rows that have
+already been fetched from the server. With @code{mysql_use_result()},
+@code{mysql_fetch_row()} actually retrieves the row from the server.
+Information about the size of the data in each row is available by
+calling @code{mysql_fetch_lengths()}.
+
+After you are done with a result set, call @code{mysql_free_result()}
+to free the memory used for it.
+
+The two retrieval mechanisms are complementary. Client programs should
+choose the approach that is most appropriate for their requirements.
+In practice, clients tend to use @code{mysql_store_result()} more
+commonly.
+
+An advantage of @code{mysql_store_result()} is that because the rows have all
+been fetched to the client, you not only can access rows sequentially, you
+can move back and forth in the result set using @code{mysql_data_seek()} or
+@code{mysql_row_seek()} to change the current row position within the result
+set. You can also find out how many rows there are by calling
+@code{mysql_num_rows()}. On the other hand, the memory requirements for
+@code{mysql_store_result()} may be very high for large result sets and you
+are more likely to encounter out-of-memory conditions.
+
+An advantage of @code{mysql_use_result()} is that the client requires less
+memory for the result set because it maintains only one row at a time (and
+because there is less allocation overhead, @code{mysql_use_result()} can be
+faster). Disadvantages are that you must process each row quickly to avoid
+tying up the server, you don't have random access to rows within the result
+set (you can only access rows sequentially), and you don't know how many rows
+are in the result set until you have retrieved them all. Furthermore, you
+@emph{must} retrieve all the rows even if you determine in mid-retrieval that
+you've found the information you were looking for.
+
+The API makes it possible for clients to respond appropriately to
+queries (retrieving rows only as necessary) without knowing whether or
+not the query is a @code{SELECT}. You can do this by calling
+@code{mysql_store_result()} after each @code{mysql_query()} (or
+@code{mysql_real_query()}). If the result set call succeeds, the query
+was a @code{SELECT} and you can read the rows. If the result set call
+fails, call @code{mysql_field_count()} to determine whether or not a
+result was actually to be expected. If @code{mysql_field_count()}
+returns zero, the query returned no data (indicating that it was an
+@code{INSERT}, @code{UPDATE}, @code{DELETE}, etc.), and thus not
+expected to return rows. If @code{mysql_field_count()} is non-zero, the
+query should have returned rows, but didn't. This indicates that the
+query was a @code{SELECT} that failed. See the description for
+@code{mysql_field_count()} for an example of how this can be done.
+
+Both @code{mysql_store_result()} and @code{mysql_use_result()} allow you to
+obtain information about the fields that make up the result set (the number
+of fields, their names and types, etc.). You can access field information
+sequentially within the row by calling @code{mysql_fetch_field()} repeatedly,
+or by field number within the row by calling
+@code{mysql_fetch_field_direct()}. The current field cursor position may be
+changed by calling @code{mysql_field_seek()}. Setting the field cursor
+affects subsequent calls to @code{mysql_fetch_field()}. You can also get
+information for fields all at once by calling @code{mysql_fetch_fields()}.
+
+For detecting and reporting errors, @strong{MySQL} provides access to error
+information by means of the @code{mysql_errno()} and @code{mysql_error()}
+functions. These return the error code or error message for the most
+recently invoked function that can succeed or fail, allowing you to determine
+when an error occurred and what it was.
+
+@node C API functions, Perl, C API function overview, Clients
+@section C API function descriptions
+
+@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_create_db:: @code{mysql_create_db()}
+* mysql_data_seek:: @code{mysql_data_seek()}
+* mysql_debug:: @code{mysql_debug()}
+* mysql_drop_db:: @code{mysql_drop_db()}
+* mysql_dump_debug_info:: @code{mysql_dump_debug_info()}
+* mysql_eof:: @code{mysql_eof()}
+* mysql_errno:: @code{mysql_errno()}
+* mysql_error:: @code{mysql_error()}
+* mysql_escape_string:: @code{mysql_escape_string()}
+* mysql_fetch_field:: @code{mysql_fetch_field()}
+* mysql_fetch_fields:: @code{mysql_fetch_fields()}
+* mysql_fetch_field_direct:: @code{mysql_fetch_field_direct()}
+* mysql_fetch_lengths:: @code{mysql_fetch_lengths()}
+* mysql_fetch_row:: @code{mysql_fetch_row()}
+* mysql_field_count:: @code{mysql_field_count()}
+* mysql_field_seek:: @code{mysql_field_seek()}
+* mysql_field_tell:: @code{mysql_field_tell()}
+* mysql_free_result:: @code{mysql_free_result()}
+* mysql_get_client_info:: @code{mysql_get_client_info()}
+* mysql_get_host_info:: @code{mysql_get_host_info()}
+* mysql_get_proto_info:: @code{mysql_get_proto_info()}
+* mysql_get_server_info:: @code{mysql_get_server_info()}
+* mysql_info:: @code{mysql_info()}
+* mysql_init:: @code{mysql_init()}
+* mysql_insert_id:: @code{mysql_insert_id()}
+* mysql_kill:: @code{mysql_kill()}
+* mysql_list_dbs:: @code{mysql_list_dbs()}
+* mysql_list_fields:: @code{mysql_list_fields()}
+* mysql_list_processes:: @code{mysql_list_processes()}
+* mysql_list_tables:: @code{mysql_list_tables()}
+* mysql_num_fields:: @code{mysql_num_fields()}
+* mysql_num_rows:: @code{mysql_num_rows()}
+* mysql_options:: @code{mysql_options()}
+* mysql_ping:: @code{mysql_ping()}
+* mysql_query:: @code{mysql_query()}
+* mysql_real_connect:: @code{mysql_real_connect()}
+* mysql_real_escape_string:: @code{mysql_real_escape_string()}
+* mysql_real_query:: @code{mysql_real_query()}
+* mysql_reload:: @code{mysql_reload()}
+* mysql_row_seek:: @code{mysql_row_seek()}
+* mysql_row_tell:: @code{mysql_row_tell()}
+* mysql_select_db:: @code{mysql_select_db()}
+* mysql_shutdown:: @code{mysql_shutdown()}
+* mysql_stat:: @code{mysql_stat()}
+* mysql_store_result:: @code{mysql_store_result()}
+* mysql_thread_id:: @code{mysql_thread_id()}
+* mysql_use_result:: @code{mysql_use_result()}
+* 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
+* Thread-safe clients:: How to make a thread-safe client
+@end menu
+
+In the descriptions below, a parameter or return value of @code{NULL} means
+@code{NULL} in the sense of the C programming language, not a
+@strong{MySQL} @code{NULL} value.
+
+Functions that return a value generally return a pointer or an integer.
+Unless specified otherwise, functions returning a pointer return a
+non-@code{NULL} value to indicate success or a @code{NULL} value to indicate
+an error, and functions returning an integer return zero to indicate success
+or non-zero to indicate an error. Note that ``non-zero'' means just that.
+Unless the function description says otherwise, do not test against a value
+other than zero:
+
+@example
+if (result) /* correct */
+ ... error ...
+
+if (result < 0) /* incorrect */
+ ... error ...
+
+if (result == -1) /* incorrect */
+ ... error ...
+@end example
+
+When a function returns an error, the @strong{Errors} subsection of the
+function description lists the possible types of errors. You can
+find out which of these occurred by calling @code{mysql_errno()}.
+A string representation of the error may be obtained by calling
+@code{mysql_error()}.
+
+@findex @code{mysql_affected_rows()}
+@node mysql_affected_rows, mysql_close, C API functions, C API functions
+@subsection @code{mysql_affected_rows()}
+
+@code{my_ulonglong mysql_affected_rows(MYSQL *mysql)}
+
+@subsubheading Description
+
+Returns the number of rows affected (changed) by the last @code{UPDATE},
+@code{DELETE} or @code{INSERT} query. May be called immediately after
+@code{mysql_query()} for @code{UPDATE}, @code{DELETE} or @code{INSERT}
+statements. For @code{SELECT} statements, @code{mysql_affected_rows()}
+works like @code{mysql_num_rows()}.
+
+@code{mysql_affected_rows()} is currently implemented as a macro.
+
+@subsubheading Return values
+
+An integer greater than zero indicates the number of rows affected or
+retrieved. Zero indicates that no records matched the @code{WHERE} clause in
+the query or that no query has yet been executed. -1 indicates that the
+query returned an error or that, for a @code{SELECT} query,
+@code{mysql_affected_rows()} was called prior to calling
+@code{mysql_store_result()}.
+
+@subsubheading Errors
+
+None.
+
+@subsubheading Example
+
+@example
+mysql_query(&mysql,"UPDATE products SET cost=cost*1.25 WHERE group=10");
+printf("%d products updated",mysql_affected_rows(&mysql));
+@end example
+
+@findex @code{mysql_close()}
+@node mysql_close, mysql_connect, mysql_affected_rows, C API functions
+@subsection @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
+
+@table @code
+@item CR_COMMANDS_OUT_OF_SYNC
+Commands were executed in an improper order.
+
+@item CR_SERVER_GONE_ERROR
+The @strong{MySQL} server has gone away.
+
+@item CR_SERVER_LOST
+The connection to the server was lost during the query.
+
+@item CR_UNKNOWN_ERROR
+An unknown error occurred.
+@end table
+
+@findex @code{mysql_connect()}
+@node mysql_connect, mysql_change_user, mysql_close, C API functions
+@subsection @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 @strong{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()}.
+
+@findex @code{mysql_change_user()}
+@node mysql_change_user, mysql_character_set_name, mysql_connect, C API functions
+@subsection @code{mysql_change_user()}
+
+@code{my_bool mysql_change_user(MYSQL *mysql, const char *user, const
+char *password, const char *db)}
+
+@subsubheading Description
+
+Changes the user and causes the database specified by @code{db} to
+become the default (current) database on the connection specified by
+@code{mysql}. In subsequent queries, this database is the default for
+table references that do not include an explicit database specifier.
+
+This function was introduced in @strong{MySQL} 3.23.3.
+
+@code{mysql_change_user()} fails unless the connected user can be
+authenticated or if he doesn't have permission to use the database. In
+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
+
+Zero for success. Non-zero if an error occurred.
+
+@subsubheading Errors
+
+The same that you can get from @code{mysql_real_connect()}.
+
+@table @code
+@item CR_COMMANDS_OUT_OF_SYNC
+Commands were executed in an improper order.
+@item CR_SERVER_GONE_ERROR
+The @strong{MySQL} server has gone away.
+@item CR_SERVER_LOST
+The connection to the server was lost during the query.
+@item CR_UNKNOWN_ERROR
+An unknown error occurred.
+@item ER_UNKNOWN_COM_ERROR
+The @strong{MySQL} server doesn't implement this command (probably an old server)
+@item ER_ACCESS_DENIED_ERROR
+The user or password was wrong.
+@item ER_BAD_DB_ERROR
+The database didn't exists.
+@item ER_DBACCESS_DENIED_ERROR
+The user did not have access rights to the database.
+@item ER_WRONG_DB_NAME
+The database name was too long.
+@end table
+
+@subsubheading Example
+
+@example
+if (mysql_change_user(&mysql, "user", "password", "new_database"))
+@{
+ fprintf(stderr, "Failed to change user. Error: %s\n",
+ mysql_error(&mysql));
+@}
+@end example
+
+@findex @code{mysql_character_set_name()}
+@node mysql_character_set_name, mysql_create_db, mysql_change_user, C API functions
+@subsection @code{mysql_character_set_name()}
+
+@code{const char *mysql_character_set_name(MYSQL *mysql)}
+
+@subsubheading Description
+
+Returns the default character set for the current connection.
+
+@subsubheading Return values
+
+The default character set
+
+@subsubheading Errors
+None.
+
+
+@findex @code{mysql_create_db()}
+@node mysql_create_db, mysql_data_seek, mysql_character_set_name, C API functions
+@subsection @code{mysql_create_db()}
+
+@code{int mysql_create_db(MYSQL *mysql, const char *db)}
+
+@subsubheading Description
+Creates the database named by the @code{db} parameter.
+
+This function is deprecated. It is preferable to use @code{mysql_query()}
+to issue a SQL @code{CREATE DATABASE} statement instead.
+
+@subsubheading Return values
+
+Zero if the database was created successfully. Non-zero if an error
+occurred.
+
+@subsubheading Errors
+@table @code
+
+@item CR_COMMANDS_OUT_OF_SYNC
+Commands were executed in an improper order.
+
+@item CR_SERVER_GONE_ERROR
+The @strong{MySQL} server has gone away.
+
+@item CR_SERVER_LOST
+The connection to the server was lost during the query.
+
+@item CR_UNKNOWN_ERROR
+An unknown error occurred.
+@end table
+
+@subsubheading Example
+
+@example
+if(mysql_create_db(&mysql, "my_database"))
+@{
+ fprintf(stderr, "Failed to create new database. Error: %s\n",
+ mysql_error(&mysql));
+@}
+@end example
+
+@findex @code{mysql_data_seek()}
+@node mysql_data_seek, mysql_debug, mysql_create_db, C API functions
+@subsection @code{mysql_data_seek()}
+
+@code{void mysql_data_seek(MYSQL_RES *result, unsigned long long offset)}
+
+@subsubheading Description
+Seeks to an arbitrary row in a query result set. This requires that the
+result set structure contains the entire result of the query, so
+@code{mysql_data_seek()} may be used in conjunction only with
+@code{mysql_store_result()}, not with @code{mysql_use_result()}.
+
+The offset should be a value in the range from 0 to
+@code{mysql_num_rows(result)-1}.
+
+@subsubheading Return values
+
+None.
+
+@subsubheading Errors
+None.
+
+@findex @code{mysql_debug()}
+@node mysql_debug, mysql_drop_db, mysql_data_seek, C API functions
+@subsection @code{mysql_debug()}
+
+@code{void mysql_debug(char *debug)}
+
+@subsubheading Description
+Does a @code{DBUG_PUSH} with the given string. @code{mysql_debug()} uses the
+Fred Fish debug library. To use this function, you must compile the client
+library to support debugging.
+@xref{Debugging server}. @xref{Debugging client}.
+
+@subsubheading Return values
+
+None.
+
+@subsubheading Errors
+None.
+
+@subsubheading Example
+
+The call shown below causes the client library to generate a trace file in
+@file{/tmp/client.trace} on the client machine:
+
+@example
+mysql_debug("d:t:O,/tmp/client.trace");
+@end example
+
+@findex @code{mysql_drop_db()}
+@node mysql_drop_db, mysql_dump_debug_info, mysql_debug, C API functions
+@subsection @code{mysql_drop_db()}
+
+@code{int mysql_drop_db(MYSQL *mysql, const char *db)}
+
+@subsubheading Description
+Drops the database named by the @code{db} parameter.
+
+This function is deprecated. It is preferable to use @code{mysql_query()}
+to issue a SQL @code{DROP DATABASE} statement instead.
+
+@subsubheading Return values
+
+Zero if the database was dropped successfully. Non-zero if an error
+occurred.
+
+@subsubheading Errors
+
+@table @code
+@item CR_COMMANDS_OUT_OF_SYNC
+Commands were executed in an improper order.
+@item CR_SERVER_GONE_ERROR
+The @strong{MySQL} server has gone away.
+@item CR_SERVER_LOST
+The connection to the server was lost during the query.
+@item CR_UNKNOWN_ERROR
+An unknown error occurred.
+@end table
+
+@subsubheading Example
+
+@example
+if(mysql_drop_db(&mysql, "my_database"))
+ fprintf(stderr, "Failed to drop the database: Error: %s\n",
+ mysql_error(&mysql));
+@end example
+
+@findex @code{mysql_dump_debug_info()}
+@node mysql_dump_debug_info, mysql_eof, mysql_drop_db, C API functions
+@subsection @code{mysql_dump_debug_info()}
+
+@code{int mysql_dump_debug_info(MYSQL *mysql)}
+
+@subsubheading Description
+
+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
+
+Zero if the command was successful. Non-zero if an error occurred.
+
+@subsubheading Errors
+@table @code
+@item CR_COMMANDS_OUT_OF_SYNC
+Commands were executed in an improper order.
+@item CR_SERVER_GONE_ERROR
+The @strong{MySQL} server has gone away.
+@item CR_SERVER_LOST
+The connection to the server was lost during the query.
+@item CR_UNKNOWN_ERROR
+An unknown error occurred.
+@end table
+
+@findex @code{mysql_eof()}
+@node mysql_eof, mysql_errno, mysql_dump_debug_info, C API functions
+@subsection @code{mysql_eof()}
+
+@code{my_bool mysql_eof(MYSQL_RES *result)}
+
+@subsubheading Description
+
+This function is deprecated. @code{mysql_errno()} or @code{mysql_error()}
+may be used instead.
+
+@code{mysql_eof()} determines whether or not the last row of a result
+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()}.
+
+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
+you call @code{mysql_fetch_row()} repeatedly. Because an error may occur on
+the connection during this process, a @code{NULL} return value from
+@code{mysql_fetch_row()} does not necessarily mean the end of the result set
+was reached normally. In this case, you can use @code{mysql_eof()} to
+determine what happened. @code{mysql_eof()} returns a non-zero value if the
+end of the result set was reached and zero if an error occurred.
+
+Historically, @code{mysql_eof()} predates the standard @strong{MySQL} error
+functions @code{mysql_errno()} and @code{mysql_error()}. Because those error
+functions provide the same information, their use is preferred over
+@code{mysql_eof()}, which is now deprecated. (In fact, they provide more
+information, because @code{mysql_eof()} returns only a boolean value whereas
+the error functions indicate a reason for the error when one occurs.)
+
+@subsubheading Return values
+
+Zero if no error occurred. Non-zero if the end of the result set has been
+reached.
+
+@subsubheading Errors
+None.
+
+@subsubheading Example
+
+The following example shows how you might use @code{mysql_eof()}:
+
+@example
+mysql_query(&mysql,"SELECT * FROM some_table");
+result = mysql_use_result(&mysql);
+while((row = mysql_fetch_row(result)))
+@{
+ // do something with data
+@}
+if(!mysql_eof(result)) // mysql_fetch_row() failed due to an error
+@{
+ fprintf(stderr, "Error: %s\n", mysql_error(&mysql));
+@}
+@end example
+
+However, you can achieve the same effect with the standard @strong{MySQL}
+error functions:
+
+@example
+mysql_query(&mysql,"SELECT * FROM some_table");
+result = mysql_use_result(&mysql);
+while((row = mysql_fetch_row(result)))
+@{
+ // do something with data
+@}
+if(mysql_errno(&mysql)) // mysql_fetch_row() failed due to an error
+@{
+ fprintf(stderr, "Error: %s\n", mysql_error(&mysql));
+@}
+@end example
+
+@findex @code{mysql_errno()}
+@node mysql_errno, mysql_error, mysql_eof, C API functions
+@subsection @code{mysql_errno()}
+
+@code{unsigned int mysql_errno(MYSQL *mysql)}
+
+@subsubheading Description
+
+For the connection specified by @code{mysql}, @code{mysql_errno()} returns
+the error code for the most recently invoked API function that can succeed
+or fail. A return value of zero means that no error occurred. Client error
+message numbers are listed in the @strong{MySQL} @file{errmsg.h} header file.
+Server error message numbers are listed in @file{mysqld_error.h}
+
+@subsubheading Return values:
+
+An error code value. Zero if no error occurred.
+
+@subsubheading Errors
+None.
+
+@findex @code{mysql_error()}
+@node mysql_error, mysql_escape_string, mysql_errno, C API functions
+@subsection @code{mysql_error()}
+
+@code{char *mysql_error(MYSQL *mysql)}
+
+@subsubheading Description
+
+For the connection specified by @code{mysql}, @code{mysql_error()} returns
+the error message for the most recently invoked API function that can succeed
+or fail. An empty string (@code{""}) is returned if no error occurred.
+This means the following two tests are equivalent:
+
+@example
+if(mysql_errno(&mysql))
+@{
+ // an error occurred
+@}
+
+if(mysql_error(&mysql)[0] != '\0')
+@{
+ // an error occurred
+@}
+@end example
+
+The language of the client error messages may be changed by
+recompiling the @strong{MySQL} client library. Currently you can choose
+error messages in several different languages.
+@xref{Languages}.
+
+@subsubheading Return values
+
+A character string that describes the error. An empty string if no error
+occurred.
+
+@subsubheading Errors
+None.
+
+@findex @code{mysql_escape_string()}
+@node mysql_escape_string, mysql_fetch_field, mysql_error, C API functions
+@subsection @code{mysql_escape_string()}
+
+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.
+
+@findex @code{mysql_fetch_field()}
+@node mysql_fetch_field, mysql_fetch_fields, mysql_escape_string, C API functions
+@subsection @code{mysql_fetch_field()}
+
+@code{MYSQL_FIELD *mysql_fetch_field(MYSQL_RES *result)}
+
+@subsubheading Description
+
+Returns the definition of one column of a result set as a @code{MYSQL_FIELD}
+structure. Call this function repeatedly to retrieve information about all
+columns in the result set. @code{mysql_fetch_field()} returns @code{NULL}
+when no more fields are left.
+
+@code{mysql_fetch_field()} is reset to return information about the first
+field each time you execute a new @code{SELECT} query. The field returned by
+@code{mysql_fetch_field()} is also affected by calls to
+@code{mysql_field_seek()}.
+
+If you've called @code{mysql_query()} to perform a @code{SELECT} on a table
+but have not called @code{mysql_store_result()}, @strong{MySQL} returns the
+default blob length (8K bytes) if you call @code{mysql_fetch_field()} to ask
+for the length of a @code{BLOB} field. (The 8K size is chosen because
+@strong{MySQL} doesn't know the maximum length for the @code{BLOB}. This
+should be made configurable sometime.) Once you've retrieved the result set,
+@code{field->max_length} contains the length of the largest value for this
+column in the specific query.
+
+@subsubheading Return values
+
+The @code{MYSQL_FIELD} structure for the current column. @code{NULL}
+if no columns are left.
+
+@subsubheading Errors
+None.
+
+@subsubheading Example
+
+@example
+MYSQL_FIELD *field;
+
+while((field = mysql_fetch_field(result)))
+@{
+ printf("field name %s\n", field->name);
+@}
+@end example
+
+@findex @code{mysql_fetch_fields()}
+@node mysql_fetch_fields, mysql_fetch_field_direct, mysql_fetch_field, C API functions
+@subsection @code{mysql_fetch_fields()}
+
+@code{MYSQL_FIELD *mysql_fetch_fields(MYSQL_RES *result)}
+
+@subsubheading Description
+
+Returns an array of all @code{MYSQL_FIELD} structures for a result set.
+Each structure provides the field definition for one column of the result
+set.
+
+@subsubheading Return values
+
+An array of @code{MYSQL_FIELD} structures for all columns of a result set.
+
+@subsubheading Errors
+None.
+
+@subsubheading Example
+
+@example
+unsigned int num_fields;
+unsigned int i;
+MYSQL_FIELD *fields;
+
+num_fields = mysql_num_fields(result);
+fields = mysql_fetch_fields(result);
+for(i = 0; i < num_fields; i++)
+@{
+ printf("Field %u is %s\n", i, fields[i].name);
+@}
+@end example
+
+@findex @code{mysql_fetch_field_direct()}
+@node mysql_fetch_field_direct, mysql_fetch_lengths, mysql_fetch_fields, C API functions
+@subsection @code{mysql_fetch_field_direct()}
+
+@code{MYSQL_FIELD *mysql_fetch_field_direct(MYSQL_RES *result, unsigned int fieldnr)}
+
+@subsubheading Description
+
+Given a field number @code{fieldnr} for a column within a result set, returns
+that column's field definition as a @code{MYSQL_FIELD} structure. You may use
+this function to retrieve the definition for an arbitrary column. The value
+of @code{fieldnr} should be in the range from 0 to
+@code{mysql_num_fields(result)-1}.
+
+@subsubheading Return values
+
+The @code{MYSQL_FIELD} structure for the specified column.
+
+@subsubheading Errors
+None.
+
+@subsubheading Example
+
+@example
+unsigned int num_fields;
+unsigned int i;
+MYSQL_FIELD *field;
+
+num_fields = mysql_num_fields(result);
+for(i = 0; i < num_fields; i++)
+@{
+ field = mysql_fetch_field_direct(result, i);
+ printf("Field %u is %s\n", i, field->name);
+@}
+@end example
+
+@findex @code{mysql_fetch_lengths()}
+@node mysql_fetch_lengths, mysql_fetch_row, mysql_fetch_field_direct, C API functions
+@subsection @code{mysql_fetch_lengths()}
+
+@code{unsigned long *mysql_fetch_lengths(MYSQL_RES *result)}
+
+@subsubheading Description
+
+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
+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.
+
+The length for empty columns and for columns containing @code{NULL} values is
+zero. To see how to distinguish these two cases, see the description for
+@code{mysql_fetch_row()}.
+
+@subsubheading Return values
+
+An array of unsigned long integers representing the size of each column (not
+including any terminating null characters).
+@code{NULL} if an error occurred.
+
+@subsubheading Errors
+@code{mysql_fetch_lengths()} is valid only for the current row of the result
+set. It returns @code{NULL} if you call it before calling
+@code{mysql_fetch_row()} or after retrieving all rows in the result.
+
+@subsubheading Example
+
+@example
+MYSQL_ROW row;
+unsigned long *lengths;
+unsigned int num_fields;
+unsigned int i;
+
+row = mysql_fetch_row(result);
+if (row)
+@{
+ num_fields = mysql_num_fields(result);
+ lengths = mysql_fetch_lengths(result);
+ for(i = 0; i < num_fields; i++)
+ @{
+ printf("Column %u is %lu bytes in length.\n", i, lengths[i]);
+ @}
+@}
+@end example
+
+@findex @code{mysql_fetch_row()}
+@node mysql_fetch_row, mysql_field_count, mysql_fetch_lengths, C API functions
+@subsection @code{mysql_fetch_row()}
+
+@code{MYSQL_ROW mysql_fetch_row(MYSQL_RES *result)}
+
+@subsubheading Description
+
+Retrieves the next row of a result set. When used after
+@code{mysql_store_result()}, @code{mysql_fetch_row()} returns @code{NULL}
+when there are no more rows to retrieve. When used after
+@code{mysql_use_result()}, @code{mysql_fetch_row()} returns @code{NULL} when
+there are no more rows to retrieve or if an error occurred.
+
+The number of values in the row is given by @code{mysql_num_fields(result)}.
+If @code{row} holds the return value from a call to @code{mysql_fetch_row()},
+pointers to the values are accessed as @code{row[0]} to
+@code{row[mysql_num_fields(result)-1]}. @code{NULL} values in the row are
+indicated by @code{NULL} pointers.
+
+The lengths of the field values in the row may be obtained by calling
+@code{mysql_fetch_lengths()}. Empty fields and fields containing
+@code{NULL} both have length 0; you can distinguish these by checking
+the pointer for the field value. If the pointer is @code{NULL}, the field
+is @code{NULL}; otherwise the field is empty.
+
+@subsubheading Return values
+
+A @code{MYSQL_ROW} structure for the next row. @code{NULL} if
+there are no more rows to retrieve or if an error occurred.
+
+@subsubheading Errors
+
+@table @code
+@item CR_SERVER_LOST
+The connection to the server was lost during the query.
+@item CR_UNKNOWN_ERROR
+An unknown error occurred.
+@end table
+
+@subsubheading Example
+
+@example
+MYSQL_ROW row;
+unsigned int num_fields;
+unsigned int i;
+
+num_fields = mysql_num_fields(result);
+while ((row = mysql_fetch_row(result)))
+@{
+ unsigned long *lengths;
+ lengths = mysql_fetch_lengths(result);
+ for(i = 0; i < num_fields; i++)
+ @{
+ printf("[%.*s] ", (int) lengths[i], row[i] ? row[i] : "NULL");
+ @}
+ printf("\n");
+@}
+@end example
+
+@findex @code{mysql_field_count()}
+@node mysql_field_count, mysql_field_seek, mysql_fetch_row, C API functions
+@subsection @code{mysql_field_count()}
+
+@code{unsigned int mysql_field_count(MYSQL *mysql)}
+
+If you are using a version of @strong{MySQL} earlier than 3.22.24, you
+should use @code{unsigned int mysql_num_fields(MYSQL *mysql)} instead.
+
+@subsubheading Description
+
+Returns the number of columns for the most recent query on the connection.
+
+The normal use of this function is when @code{mysql_store_result()}
+returned @code{NULL} (and thus you have no result set pointer).
+In this case, you can call @code{mysql_field_count()} to
+determine whether or not @code{mysql_store_result()} should have produced a
+non-empty result. This allows the client program to take proper action
+without knowing whether or not the query was a @code{SELECT} (or
+@code{SELECT}-like) statement. The example shown below illustrates how this
+may be done.
+
+@xref{NULL mysql_store_result, , @code{NULL mysql_store_result()}}.
+
+@subsubheading Return values
+
+An unsigned integer representing the number of fields in a result set.
+
+@subsubheading Errors
+None.
+
+@subsubheading Example
+
+@example
+MYSQL_RES *result;
+unsigned int num_fields;
+unsigned int num_rows;
+
+if (mysql_query(&mysql,query_string))
+@{
+ // error
+@}
+else // query succeeded, process any data returned by it
+@{
+ result = mysql_store_result(&mysql);
+ if (result) // there are rows
+ @{
+ num_fields = mysql_num_fields(result);
+ // retrieve rows, then call mysql_free_result(result)
+ @}
+ else // mysql_store_result() returned nothing; should it have?
+ @{
+ if(mysql_field_count(&mysql) == 0)
+ @{
+ // query does not return data
+ // (it was not a SELECT)
+ num_rows = mysql_affected_rows(&mysql);
+ @}
+ else // mysql_store_result() should have returned data
+ @{
+ fprintf(stderr, "Error: %s\n", mysql_error(&mysql));
+ @}
+ @}
+@}
+@end example
+
+An alternative is to replace the @code{mysql_field_count(&mysql)} call with
+@code{mysql_errno(&mysql)}. In this case, you are checking directly for an
+error from @code{mysql_store_result()} rather than inferring from the value
+of @code{mysql_field_count()} whether or not the statement was a
+@code{SELECT}.
+
+@findex @code{mysql_field_seek()}
+@node mysql_field_seek, mysql_field_tell, mysql_field_count, C API functions
+@subsection @code{mysql_field_seek()}
+
+@code{MYSQL_FIELD_OFFSET mysql_field_seek(MYSQL_RES *result, MYSQL_FIELD_OFFSET offset)}
+
+@subsubheading Description
+
+Sets the field cursor to the given offset. The next call to
+@code{mysql_fetch_field()} will retrieve the field definition of the column
+associated with that offset.
+
+To seek to the beginning of a row, pass an @code{offset} value of zero.
+
+@subsubheading Return values
+
+The previous value of the field cursor.
+
+@subsubheading Errors
+None.
+
+@findex @code{mysql_field_tell()}
+@node mysql_field_tell, mysql_free_result, mysql_field_seek, C API functions
+@subsection @code{mysql_field_tell()}
+
+@code{MYSQL_FIELD_OFFSET mysql_field_tell(MYSQL_RES *result)}
+
+@subsubheading Description
+
+Returns the position of the field cursor used for the last
+@code{mysql_fetch_field()}. This value can be used as an argument to
+@code{mysql_field_seek()}.
+
+@subsubheading Return values
+
+The current offset of the field cursor.
+
+@subsubheading Errors
+None.
+
+@findex @code{mysql_free_result()}
+@node mysql_free_result, mysql_get_client_info, mysql_field_tell, C API functions
+@subsection @code{mysql_free_result()}
+
+@code{void mysql_free_result(MYSQL_RES *result)}
+
+@subsubheading Description
+
+Frees the memory allocated for a result set by @code{mysql_store_result()},
+@code{mysql_use_result()}, @code{mysql_list_dbs()}, etc. When you are done
+with a result set, you must free the memory it uses by calling
+@code{mysql_free_result()}.
+
+@subsubheading Return values
+
+None.
+
+@subsubheading Errors
+None.
+
+@findex @code{mysql_get_client_info()}
+@node mysql_get_client_info, mysql_get_host_info, mysql_free_result, C API functions
+@subsection @code{mysql_get_client_info()}
+
+@code{char *mysql_get_client_info(void)}
+
+@subsubheading Description
+
+Returns a string that represents the client library version.
+
+@subsubheading Return values
+
+A character string that represents the @strong{MySQL} client library version.
+
+@subsubheading Errors
+None.
+
+@findex @code{mysql_get_host_info()}
+@node mysql_get_host_info, mysql_get_proto_info, mysql_get_client_info, C API functions
+@subsection @code{mysql_get_host_info()}
+
+@code{char *mysql_get_host_info(MYSQL *mysql)}
+
+@subsubheading Description
+
+Returns a string describing the type of connection in use, including the
+server host name.
+
+@subsubheading Return values
+
+A character string representing the server host name and the connection type.
+
+@subsubheading Errors
+None.
+
+@findex @code{mysql_get_proto_info()}
+@node mysql_get_proto_info, mysql_get_server_info, mysql_get_host_info, C API functions
+@subsection @code{mysql_get_proto_info()}
+
+@code{unsigned int mysql_get_proto_info(MYSQL *mysql)}
+
+@subsubheading Description
+
+Returns the protocol version used by current connection.
+
+@subsubheading Return values
+
+An unsigned integer representing the protocol version used by the current
+connection.
+
+@subsubheading Errors
+None.
+
+@findex @code{mysql_get_server_info()}
+@node mysql_get_server_info, mysql_info, mysql_get_proto_info, C API functions
+@subsection @code{mysql_get_server_info()}
+
+@code{char *mysql_get_server_info(MYSQL *mysql)}
+
+@subsubheading Description
+
+Returns a string that represents the server version number.
+
+@subsubheading Return values
+
+A character string that represents the server version number.
+
+@subsubheading Errors
+None.
+
+@findex @code{mysql_info()}
+@node mysql_info, mysql_init, mysql_get_server_info, C API functions
+@subsection @code{mysql_info()}
+
+@code{char *mysql_info(MYSQL *mysql)}
+
+@subsubheading Description
+
+Retrieves a string providing information about the most recently executed
+query, but only for the statements listed below. For other statements,
+@code{mysql_info()} returns @code{NULL}. The format of the string varies
+depending on the type of query, as described below. The numbers are
+illustrative only; the string will contain values appropriate for the query.
+
+@table @code
+@item INSERT INTO ... SELECT ...
+String format: @code{Records: 100 Duplicates: 0 Warnings: 0}
+@item INSERT INTO ... VALUES (...),(...),(...)...
+String format: @code{Records: 3 Duplicates: 0 Warnings: 0}
+@item LOAD DATA INFILE ...
+String format: @code{Records: 1 Deleted: 0 Skipped: 0 Warnings: 0}
+@item ALTER TABLE
+String format: @code{Records: 3 Duplicates: 0 Warnings: 0}
+@item UPDATE
+String format: @code{Rows matched: 40 Changed: 40 Warnings: 0}
+@end table
+
+Note that @code{mysql_info()} returns a non-@code{NULL} value for the
+@code{INSERT ... VALUES} statement only if multiple value lists are
+specified in the statement.
+
+@subsubheading Return values
+
+A character string representing additional information about the most
+recently executed query. @code{NULL} if no information is available for the
+query.
+
+@subsubheading Errors
+None.
+
+@findex @code{mysql_init()}
+@node mysql_init, mysql_insert_id, mysql_info, C API functions
+@subsection @code{mysql_init()}
+
+@code{MYSQL *mysql_init(MYSQL *mysql)}
+
+@subsubheading Description
+
+Allocates or initializes 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
+@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
+insufficient memory to allocate a new object.
+
+@subsubheading Errors
+In case of insufficient memory, @code{NULL} is returned.
+
+@findex @code{mysql_insert_id()}
+@node mysql_insert_id, mysql_kill, mysql_init, C API functions
+@subsection @code{mysql_insert_id()}
+
+@code{my_ulonglong mysql_insert_id(MYSQL *mysql)}
+
+@subsubheading Description
+
+Returns the ID generated for an @code{AUTO_INCREMENT} column by the previous
+query. Use this function after you have performed an @code{INSERT} query
+into a table that contains an @code{AUTO_INCREMENT} field.
+
+Note that @code{mysql_insert_id()} returns @code{0} if the previous query
+does not generate an @code{AUTO_INCREMENT} value. If you need to save
+the value for later, be sure to call @code{mysql_insert_id()} immediately
+after the query that generates the value.
+
+Also note that the value of the SQL @code{LAST_INSERT_ID()} function always
+contains the most recently generated @code{AUTO_INCREMENT} value, and is
+not reset between queries because the value of that function is maintained
+in the server.
+
+@subsubheading Return values
+
+The value of the @code{AUTO_INCREMENT} field that was updated by the previous
+query. Returns zero if there was no previous query on the connection or if
+the query did not update an @code{AUTO_INCREMENT} value.
+
+@subsubheading Errors
+None.
+
+@findex @code{mysql_kill()}
+@node mysql_kill, mysql_list_dbs, mysql_insert_id, C API functions
+@subsection @code{mysql_kill()}
+
+@code{int mysql_kill(MYSQL *mysql, unsigned long pid)}
+
+@subsubheading Description
+
+Asks the server to kill the thread specified by @code{pid}.
+
+@subsubheading Return values
+
+Zero for success. Non-zero if an error occurred.
+
+@subsubheading Errors
+
+@table @code
+@item CR_COMMANDS_OUT_OF_SYNC
+Commands were executed in an improper order.
+@item CR_SERVER_GONE_ERROR
+The @strong{MySQL} server has gone away.
+@item CR_SERVER_LOST
+The connection to the server was lost during the query.
+@item CR_UNKNOWN_ERROR
+An unknown error occurred.
+@end table
+
+@findex @code{mysql_list_dbs()}
+@node mysql_list_dbs, mysql_list_fields, mysql_kill, C API functions
+@subsection @code{mysql_list_dbs()}
+
+@code{MYSQL_RES *mysql_list_dbs(MYSQL *mysql, const char *wild)}
+
+@subsubheading Description
+
+Returns a result set consisting of database names on the server that match
+the simple regular expression specified by the @code{wild} parameter.
+@code{wild} may contain the wildcard characters @samp{%} or @samp{_}, or may
+be a @code{NULL} pointer to match all databases. Calling
+@code{mysql_list_dbs()} is similar to executing the query @code{SHOW
+databases [LIKE wild]}.
+
+You must free the result set with @code{mysql_free_result()}.
+
+@subsubheading Return values
+
+A @code{MYSQL_RES} result set for success. @code{NULL} if an error occurred.
+
+@subsubheading Errors
+
+@table @code
+@item CR_COMMANDS_OUT_OF_SYNC
+Commands were executed in an improper order.
+@item CR_OUT_OF_MEMORY
+Out of memory.
+@item CR_SERVER_GONE_ERROR
+The @strong{MySQL} server has gone away.
+@item CR_SERVER_LOST
+The connection to the server was lost during the query.
+@item CR_UNKNOWN_ERROR
+An unknown error occurred.
+@end table
+
+@findex @code{mysql_list_fields()}
+@node mysql_list_fields, mysql_list_processes, mysql_list_dbs, C API functions
+@subsection @code{mysql_list_fields()}
+
+@code{MYSQL_RES *mysql_list_fields(MYSQL *mysql, const char *table, const char *wild)}
+
+@subsubheading Description
+
+Returns a result set consisting of field names in the given table that match
+the simple regular expression specified by the @code{wild} parameter.
+@code{wild} may contain the wildcard characters @samp{%} or @samp{_}, or may
+be a @code{NULL} pointer to match all fields. Calling
+@code{mysql_list_fields()} is similar to executing the query @code{SHOW
+COLUMNS FROM tbl_name [LIKE wild]}.
+
+Note that it's recommended that you use @code{SHOW COLUMNS FROM tbl_name}
+instead of @code{mysql_list_fields()}.
+
+You must free the result set with @code{mysql_free_result()}.
+
+@subsubheading Return values
+
+A @code{MYSQL_RES} result set for success. @code{NULL} if an error occurred.
+
+@subsubheading Errors
+
+@table @code
+@item CR_COMMANDS_OUT_OF_SYNC
+Commands were executed in an improper order.
+@item CR_SERVER_GONE_ERROR
+The @strong{MySQL} server has gone away.
+@item CR_SERVER_LOST
+The connection to the server was lost during the query.
+@item CR_UNKNOWN_ERROR
+An unknown error occurred.
+@end table
+
+@findex @code{mysql_list_processes()}
+@node mysql_list_processes, mysql_list_tables, mysql_list_fields, C API functions
+@subsection @code{mysql_list_processes()}
+
+@code{MYSQL_RES *mysql_list_processes(MYSQL *mysql)}
+
+@subsubheading Description
+
+Returns a result set describing the current server threads. This is the same
+kind of information as that reported by @code{mysqladmin processlist} or
+a @code{SHOW PROCESSLIST} query.
+
+You must free the result set with @code{mysql_free_result()}.
+
+@subsubheading Return values
+
+A @code{MYSQL_RES} result set for success. @code{NULL} if an error occurred.
+
+@subsubheading Errors
+
+@table @code
+@item CR_COMMANDS_OUT_OF_SYNC
+Commands were executed in an improper order.
+@item CR_SERVER_GONE_ERROR
+The @strong{MySQL} server has gone away.
+@item CR_SERVER_LOST
+The connection to the server was lost during the query.
+@item CR_UNKNOWN_ERROR
+An unknown error occurred.
+@end table
+
+@findex @code{mysql_list_tables()}
+@node mysql_list_tables, mysql_num_fields, mysql_list_processes, C API functions
+@subsection @code{mysql_list_tables()}
+
+@code{MYSQL_RES *mysql_list_tables(MYSQL *mysql, const char *wild)}
+
+@subsubheading Description
+
+Returns a result set consisting of table names in the current database that
+match the simple regular expression specified by the @code{wild} parameter.
+@code{wild} may contain the wildcard characters @samp{%} or @samp{_}, or may
+be a @code{NULL} pointer to match all tables. Calling
+@code{mysql_list_tables()} is similar to executing the query @code{SHOW
+tables [LIKE wild]}.
+
+You must free the result set with @code{mysql_free_result()}.
+
+@subsubheading Return values
+
+A @code{MYSQL_RES} result set for success. @code{NULL} if an error occurred.
+
+@subsubheading Errors
+
+@table @code
+@item CR_COMMANDS_OUT_OF_SYNC
+Commands were executed in an improper order.
+@item CR_SERVER_GONE_ERROR
+The @strong{MySQL} server has gone away.
+@item CR_SERVER_LOST
+The connection to the server was lost during the query.
+@item CR_UNKNOWN_ERROR
+An unknown error occurred.
+@end table
+
+@findex @code{mysql_num_fields()}
+@findex @code{mysql_field_count()}
+@node mysql_num_fields, mysql_num_rows, mysql_list_tables, C API functions
+@subsection @code{mysql_num_fields()}
+
+@code{unsigned int mysql_num_fields(MYSQL_RES *result)}
+
+or
+
+@code{unsigned int mysql_num_fields(MYSQL *mysql)}
+
+The second form doesn't work on @strong{MySQL} 3.22.24 or newer. To pass a
+@code{MYSQL*} argument, you must use
+@code{unsigned int mysql_field_count(MYSQL *mysql)} instead.
+
+@subsubheading Description
+
+Returns the number of columns in a result set.
+
+Note that you can get the number of columns either from a pointer to a result
+set or to a connection handle. You would use the connection handle if
+@code{mysql_store_result()} or @code{mysql_use_result()} returned
+@code{NULL} (and thus you have no result set pointer). In this case, you can
+call @code{mysql_field_count()} to determine whether or not
+@code{mysql_store_result()} should have produced a non-empty result. This
+allows the client program to take proper action without knowing whether or
+not the query was a @code{SELECT} (or @code{SELECT}-like) statement. The
+example shown below illustrates how this may be done.
+
+@xref{NULL mysql_store_result, , @code{NULL mysql_store_result()}}.
+
+@subsubheading Return values
+
+An unsigned integer representing the number of fields in a result set.
+
+@subsubheading Errors
+None.
+
+@subsubheading Example
+
+@example
+MYSQL_RES *result;
+unsigned int num_fields;
+unsigned int num_rows;
+
+if (mysql_query(&mysql,query_string))
+@{
+ // error
+@}
+else // query succeeded, process any data returned by it
+@{
+ result = mysql_store_result(&mysql);
+ if (result) // there are rows
+ @{
+ num_fields = mysql_num_fields(result);
+ // retrieve rows, then call mysql_free_result(result)
+ @}
+ else // mysql_store_result() returned nothing; should it have?
+ @{
+ if (mysql_errno(&mysql))
+ @{
+ fprintf(stderr, "Error: %s\n", mysql_error(&mysql));
+ @}
+ else if (mysql_field_count(&mysql) == 0)
+ @{
+ // query does not return data
+ // (it was not a SELECT)
+ num_rows = mysql_affected_rows(&mysql);
+ @}
+ @}
+@}
+@end example
+
+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.
+
+@findex @code{mysql_num_rows()}
+@node mysql_num_rows, mysql_options, mysql_num_fields, C API functions
+@subsection @code{mysql_num_rows()}
+
+@code{my_ulonglong mysql_num_rows(MYSQL_RES *result)}
+
+@subsubheading Description
+
+Returns the number of rows in the result set.
+
+The use of @code{mysql_num_rows()} depends on whether you use
+@code{mysql_store_result()} or @code{mysql_use_result()} to return the result
+set. If you use @code{mysql_store_result()}, @code{mysql_num_rows()} may be
+called immediately. If you use @code{mysql_use_result()},
+@code{mysql_num_rows()} will not return the correct value until all the rows
+in the result set have been retrieved.
+
+@subsubheading Return values
+
+The number of rows in the result set.
+
+@subsubheading Errors
+None.
+
+@findex @code{mysql_options()}
+@node mysql_options, mysql_ping, mysql_num_rows, C API functions
+@subsection @code{mysql_options()}
+
+@code{int mysql_options(MYSQL *mysql, enum mysql_option option, const char *arg)}
+
+@subsubheading Description
+
+Can be used to set extra connect options and affect behavior for a connection.
+This function may be called multiple times to set several options.
+
+@code{mysql_options()} should be called after @code{mysql_init()} and before
+@code{mysql_connect()} or @code{mysql_real_connect()}.
+
+The @code{option} argument is the option that you want to set; the @code{arg}
+argument is the value for the option. If the option is an integer, then
+@code{arg} should point to the value of the integer.
+
+Possible options values:
+
+@multitable @columnfractions .25 .25 .5
+@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_NAMED_PIPE} @tab Not used @tab Use named pipes to connect to a @strong{MySQL} server on NT.
+@item @code{MYSQL_INIT_COMMAND} @tab @code{char *} @tab Command to execute when connecting to the @strong{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}.
+@item @code{MYSQL_READ_DEFAULT_GROUP} @tab @code{char *} @tab Read options from the named group from @file{my.cnf} or the file specified with @code{MYSQL_READ_DEFAULT_FILE}.
+@end multitable
+
+Note that the group @code{client} is always read if you use
+@code{MYSQL_READ_DEFAULT_FILE} or @code{MYSQL_READ_DEFAULT_GROUP}.
+
+The specified group in the option file may contain the following options:
+
+@multitable @columnfractions .3 .7
+@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{host} @tab Default host name.
+@item @code{init-command} @tab Command to execute when connecting to @strong{MySQL} server. Will automatically be re-executed when reconnecting.
+@item @code{password} @tab Default password.
+@item @code{pipe} @tab Use named pipes to connect to a @strong{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 @code{timeout} @tab Connect timeout in seconds.
+@item @code{user} @tab Default user.
+@end multitable
+
+For more information about option files, see @ref{Option files}.
+
+@subsubheading Return values
+
+Zero for success. Non-zero if you used an unknown option.
+
+@subsubheading Example
+
+@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","user","passwd","database",0,NULL,0))
+@{
+ fprintf(stderr, "Failed to connect to database: Error: %s\n",
+ mysql_error(&mysql));
+@}
+@end example
+
+The above requests the client to use the compressed client/server protocol and
+read the additional options from the @code{odbc} section in the @code{my.cnf}
+file.
+
+@findex @code{mysql_ping()}
+@node mysql_ping, mysql_query, mysql_options, C API functions
+@subsection @code{mysql_ping()}
+
+@code{int mysql_ping(MYSQL *mysql)}
+
+@subsubheading Description
+
+Checks whether or not the connection to the server is working. If it has gone
+down, an automatic reconnection is attempted.
+
+This function can be used by clients that remain idle for a long while,
+to check whether or not the server has closed the connection and reconnect
+if necessary.
+
+@subsubheading Return values
+
+Zero if the server is alive. Non-zero if an error occurred.
+
+@subsubheading Errors
+
+@table @code
+@item CR_COMMANDS_OUT_OF_SYNC
+Commands were executed in an improper order.
+@item CR_SERVER_GONE_ERROR
+The @strong{MySQL} server has gone away.
+@item CR_UNKNOWN_ERROR
+An unknown error occurred.
+@end table
+
+@findex @code{mysql_query()}
+@node mysql_query, mysql_real_connect, mysql_ping, C API functions
+@subsection @code{mysql_query()}
+
+@code{int mysql_query(MYSQL *mysql, const char *query)}
+
+@subsubheading Description
+Executes the SQL query pointed to by the null-terminated string @code{query}.
+The query must consist of a single SQL statement. You should not add
+a terminating semicolon (@samp{;}) or @code{\g} to the statement.
+
+@code{mysql_query()} cannot be used for queries that contain binary data; you
+should use @code{mysql_real_query()} instead. (Binary data may contain the
+@samp{\0} character, which @code{mysql_query()} interprets as the end of 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}}.
+
+@subsubheading Return values
+
+Zero if the query was successful. Non-zero if an error occurred.
+
+@subsubheading Errors
+
+@table @code
+@item CR_COMMANDS_OUT_OF_SYNC
+Commands were executed in an improper order.
+@item CR_SERVER_GONE_ERROR
+The @strong{MySQL} server has gone away.
+@item CR_SERVER_LOST
+The connection to the server was lost during the query.
+@item CR_UNKNOWN_ERROR
+An unknown error occurred.
+@end table
+
+@findex @code{mysql_real_connect()}
+@node mysql_real_connect, mysql_real_escape_string, mysql_query, C API functions
+@subsection @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 Description
+
+@code{mysql_real_connect()} attempts to establish a connection to a
+@strong{MySQL} database engine running on @code{host}.
+@code{mysql_real_connect()} must complete successfully before you can execute
+any of the other API functions, with the exception of
+@code{mysql_get_client_info()}.
+
+The parameters are specified as follows:
+
+@itemize @bullet
+@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. See the
+example below.
+
+@item
+The value of @code{host} may be either a hostname or an IP address. If
+@code{host} is @code{NULL} or the string @code{"localhost"}, a connection to
+the local host is assumed. If the OS supports sockets (Unix) or named pipes
+(Win32), they are used instead of TCP/IP to connect to the server.
+
+@item
+The @code{user} parameter contains the user's @strong{MySQL} login ID. If
+@code{user} is @code{NULL}, the current user is assumed. Under Unix, this is
+the current login name. Under Windows ODBC, the current user name must be
+specified explicitly.
+@xref{ODBC administrator}.
+
+@item
+The @code{passwd} parameter contains the password for @code{user}. If
+@code{passwd} is @code{NULL}, only entries in the @code{user} table for the
+user that have a blank password field will be checked for a match. This
+allows the database administrator to set up the @strong{MySQL} privilege
+system in such a way that users get different privileges depending on whether
+or not they have specified a password.
+
+Note: Do not attempt to encrypt the password before calling
+@code{mysql_real_connect()}; password encryption is handled automatically by
+the client API.
+
+@item
+@code{db} is the database name.
+If @code{db} is not @code{NULL}, the connection will set the default
+database to this value.
+
+@item
+If @code{port} is not 0, the value will be used as the port number
+for the TCP/IP connection. Note that the @code{host} parameter
+determines the type of the connection.
+
+@item
+If @code{unix_socket} is not @code{NULL}, the string specifies the
+socket or named pipe that should be used. Note that the @code{host}
+parameter determines the type of the connection.
+
+@item
+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}
+@item @code{CLIENT_FOUND_ROWS} @tab Return the number of found (matched) rows, not the number of affected rows.
+@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_COMPRESS} @tab Use compression protocol.
+@item @code{CLIENT_ODBC} @tab The client is an ODBC client. This changes
+@code{mysqld} to be more ODBC-friendly.
+@end multitable
+@end itemize
+
+@subsubheading Return values
+
+A @code{MYSQL*} connection handle if the connection was successful,
+@code{NULL} if the connection was unsuccessful. For a successful connection,
+the return value is the same as the value of the first parameter, unless you
+pass @code{NULL} for that parameter.
+
+@subsubheading Errors
+
+@table @code
+@item CR_CONN_HOST_ERROR
+Failed to connect to the @strong{MySQL} server.
+
+@item CR_CONNECTION_ERROR
+Failed to connect to the local @strong{MySQL} server.
+
+@item CR_IPSOCK_ERROR
+Failed to create an IP socket.
+
+@item CR_OUT_OF_MEMORY
+Out of memory.
+
+@item CR_SOCKET_CREATE_ERROR
+Failed to create a Unix socket.
+
+@item CR_UNKNOWN_HOST
+Failed to find the IP address for the hostname.
+
+@item CR_VERSION_ERROR
+A protocol mismatch resulted from attempting to connect to a server with a
+client library that uses a different protocol version. This can happen if you
+use a very old client library to connect to a new server that wasn't started
+with the @code{--old-protocol} option.
+
+@item CR_NAMEDPIPEOPEN_ERROR;
+Failed to create a named pipe on Win32.
+
+@item CR_NAMEDPIPEWAIT_ERROR;
+Failed to wait for a named pipe on Win32.
+
+@item CR_NAMEDPIPESETSTATE_ERROR;
+Failed to get a pipe handler on Win32.
+@end table
+
+@subsubheading Example
+
+@example
+MYSQL mysql;
+
+mysql_init(&mysql);
+mysql_options(&mysql,MYSQL_READ_DEFAULT_GROUP,"your_prog_name");
+if (!mysql_real_connect(&mysql,"host","user","passwd","database",0,NULL,0))
+@{
+ fprintf(stderr, "Failed to connect to database: Error: %s\n",
+ mysql_error(&mysql));
+@}
+@end example
+
+By using @code{mysql_options()} the @strong{MySQL} library will read the
+@code{[client]} and @code{your_prog_name} sections in the @code{my.cnf}
+file which will ensure that your program will work, even if someone has
+set up @strong{MySQL} in some non-standard way.
+
+Note that upon connection, @code{mysql_real_connect()} sets the @code{reconnect}
+flag (part of the MYSQL structure) to a value of @code{1}. This flag indicates,
+in the event that a query cannot be performed because of a lost connection, to
+try reconnecting to the server before giving up.
+
+@findex @code{mysql_real_escape_string()}
+@node mysql_real_escape_string, mysql_real_query, mysql_real_connect, C API functions
+@subsection @code{mysql_real_escape_string()}
+
+@code{unsigned int mysql_real_escape_string(MYSQL *mysql, char *to, const char *from, unsigned int length)}
+
+@subsubheading Description
+
+Encodes the string in @code{from} to an escaped SQL string, taking into
+account the current charset of the connection, that can be sent to the
+server in a SQL statement, places the result in @code{to}, and adds a
+terminating null byte. Characters encoded are @code{NUL} (ASCII 0),
+@samp{\n}, @samp{\r}, @samp{\}, @samp{'}, @samp{"} and Control-Z
+(@pxref{Literals}).
+
+The string pointed to by @code{from} must be @code{length} bytes long. You
+must allocate the @code{to} buffer to be at least @code{length*2+1} bytes
+long. (In the worse case, each character may need to be encoded as using two
+bytes, and you need room for the terminating null byte.) When
+@code{mysql_escape_string()} returns, the contents of @code{to} will be a
+null-terminated string. The return value is the length of the encoded
+string, not including the terminating null character.
+
+@subsubheading Example
+
+@example
+char query[1000],*end;
+
+end = strmov(query,"INSERT INTO test_table values(");
+*end++ = '\'';
+end += mysql_real_escape_string(&mysql, end,"What's this",11);
+*end++ = '\'';
+*end++ = ',';
+*end++ = '\'';
+end += mysql_real_escape_string(&mysql, end,"binary data: \0\r\n",16);
+*end++ = '\'';
+*end++ = ')';
+
+if (mysql_real_query(&mysql,query,(unsigned int) (end - query)))
+@{
+ fprintf(stderr, "Failed to insert row, Error: %s\n",
+ mysql_error(&mysql));
+@}
+@end example
+
+The @code{strmov()} function used in the example is included in the
+@code{mysqlclient} library and works like @code{strcpy()} but returns a
+pointer to the terminating null of the first parameter.
+
+@subsubheading Return values
+
+The length of the value placed into @code{to}, not including the
+terminating null character.
+
+@subsubheading Errors
+None.
+
+@findex @code{mysql_real_query()}
+@node mysql_real_query, mysql_reload, mysql_real_escape_string, C API functions
+@subsection @code{mysql_real_query()}
+
+@code{int mysql_real_query(MYSQL *mysql, const char *query, unsigned int length)}
+
+@subsubheading Description
+
+Executes the SQL query pointed to by @code{query}, which should be a string
+@code{length} bytes long. The query must consist of a single SQL statement.
+You should not add a terminating semicolon (@samp{;}) or @code{\g} to the
+statement.
+
+You @emph{must} use @code{mysql_real_query()} rather than
+@code{mysql_query()} for queries that contain binary data, because binary data
+may contain the @samp{\0} character. In addition, @code{mysql_real_query()}
+is faster than @code{mysql_query()} because it does not call @code{strlen()} on
+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}}.
+
+@subsubheading Return values
+
+Zero if the query was successful. Non-zero if an error occurred.
+
+@subsubheading Errors
+
+@table @code
+@item CR_COMMANDS_OUT_OF_SYNC
+Commands were executed in an improper order.
+@item CR_SERVER_GONE_ERROR
+The @strong{MySQL} server has gone away.
+@item CR_SERVER_LOST
+The connection to the server was lost during the query.
+@item CR_UNKNOWN_ERROR
+An unknown error occurred.
+@end table
+
+@findex @code{mysql_reload()}
+@node mysql_reload, mysql_row_seek, mysql_real_query, C API functions
+@subsection @code{mysql_reload()}
+
+@code{int mysql_reload(MYSQL *mysql)}
+
+@subsubheading Description
+
+Asks the @strong{MySQL} server to reload the grant tables. The
+connected user must have the @strong{reload} privilege.
+
+This function is deprecated. It is preferable to use @code{mysql_query()}
+to issue a SQL @code{FLUSH PRIVILEGES} statement instead.
+
+@subsubheading Return values
+
+Zero for success. Non-zero if an error occurred.
+
+@subsubheading Errors
+
+@table @code
+@item CR_COMMANDS_OUT_OF_SYNC
+Commands were executed in an improper order.
+@item CR_SERVER_GONE_ERROR
+The @strong{MySQL} server has gone away.
+@item CR_SERVER_LOST
+The connection to the server was lost during the query.
+@item CR_UNKNOWN_ERROR
+An unknown error occurred.
+@end table
+
+@findex @code{mysql_row_seek()}
+@node mysql_row_seek, mysql_row_tell, mysql_reload, C API functions
+@subsection @code{mysql_row_seek()}
+
+@code{MYSQL_ROW_OFFSET mysql_row_seek(MYSQL_RES *result, MYSQL_ROW_OFFSET offset)}
+
+@subsubheading Description
+Sets the row cursor to an arbitrary row in a query result set. This requires
+that the result set structure contains the entire result of the query, so
+@code{mysql_row_seek()} may be used in conjunction only with
+@code{mysql_store_result()}, not with @code{mysql_use_result()}.
+
+The offset should be a value returned from a call to @code{mysql_row_tell()}
+or to @code{mysql_row_seek()}. This value is not simply a row number; if you
+want to seek to a row within a result set using a row number, use
+@code{mysql_data_seek()} instead.
+
+@subsubheading Return values
+
+The previous value of the row cursor. This value may be passed to a
+subsequent call to @code{mysql_row_seek()}.
+
+@subsubheading Errors
+None.
+
+@findex @code{mysql_row_tell()}
+@node mysql_row_tell, mysql_select_db, mysql_row_seek, C API functions
+@subsection @code{mysql_row_tell()}
+
+@code{MYSQL_ROW_OFFSET mysql_row_tell(MYSQL_RES *result)}
+
+@subsubheading Description
+
+Returns the current position of the row cursor for the last
+@code{mysql_fetch_row()}. This value can be used as an argument to
+@code{mysql_row_seek()}.
+
+You should use @code{mysql_row_tell()} only after @code{mysql_store_result()},
+not after @code{mysql_use_result()}.
+
+@subsubheading Return values
+
+The current offset of the row cursor.
+
+@subsubheading Errors
+None.
+
+@findex @code{mysql_select_db()}
+@node mysql_select_db, mysql_shutdown, mysql_row_tell, C API functions
+@subsection @code{mysql_select_db()}
+
+@code{int mysql_select_db(MYSQL *mysql, const char *db)}
+
+@subsubheading Description
+
+Causes the database specified by @code{db} to become the default (current)
+database on the connection specified by @code{mysql}. In subsequent queries,
+this database is the default for table references that do not include an
+explicit database specifier.
+
+@code{mysql_select_db()} fails unless the connected user can be authenticated
+as having permission to use the database.
+
+@subsubheading Return values
+
+Zero for success. Non-zero if an error occurred.
+
+@subsubheading Errors
+
+@table @code
+@item CR_COMMANDS_OUT_OF_SYNC
+Commands were executed in an improper order.
+@item CR_SERVER_GONE_ERROR
+The @strong{MySQL} server has gone away.
+@item CR_SERVER_LOST
+The connection to the server was lost during the query.
+@item CR_UNKNOWN_ERROR
+An unknown error occurred.
+@end table
+
+@findex @code{mysql_shutdown()}
+@node mysql_shutdown, mysql_stat, mysql_select_db, C API functions
+@subsection @code{mysql_shutdown()}
+
+@code{int mysql_shutdown(MYSQL *mysql)}
+
+@subsubheading Description
+
+Asks the database server to shutdown. The connected user must have
+@strong{shutdown} privileges.
+
+@subsubheading Return values
+
+Zero for success. Non-zero if an error occurred.
+
+@subsubheading Errors
+
+@table @code
+@item CR_COMMANDS_OUT_OF_SYNC
+Commands were executed in an improper order.
+@item CR_SERVER_GONE_ERROR
+The @strong{MySQL} server has gone away.
+@item CR_SERVER_LOST
+The connection to the server was lost during the query.
+@item CR_UNKNOWN_ERROR
+An unknown error occurred.
+@end table
+
+@findex @code{mysql_stat()}
+@node mysql_stat, mysql_store_result, mysql_shutdown, C API functions
+@subsection @code{mysql_stat()}
+
+@code{char *mysql_stat(MYSQL *mysql)}
+
+@subsubheading Description
+
+Returns a character string containing information similar to that provided by
+the @code{mysqladmin status} command. This includes uptime in seconds and
+the number of running threads, questions, reloads and open tables.
+
+@subsubheading Return values
+
+A character string describing the server status. @code{NULL} if an
+error occurred.
+
+@subsubheading Errors
+
+@table @code
+@item CR_COMMANDS_OUT_OF_SYNC
+Commands were executed in an improper order.
+@item CR_SERVER_GONE_ERROR
+The @strong{MySQL} server has gone away.
+@item CR_SERVER_LOST
+The connection to the server was lost during the query.
+@item CR_UNKNOWN_ERROR
+An unknown error occurred.
+@end table
+
+@findex @code{mysql_store_result()}
+@node mysql_store_result, mysql_thread_id, mysql_stat, C API functions
+@subsection @code{mysql_store_result()}
+
+@code{MYSQL_RES *mysql_store_result(MYSQL *mysql)}
+
+@subsubheading Description
+
+You must call @code{mysql_store_result()} or @code{mysql_use_result()}
+for every query which successfully retrieves data (@code{SELECT},
+@code{SHOW}, @code{DESCRIBE}, @code{EXPLAIN}).
+
+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}}.
+
+@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
+a result sets (If the query was for example an @code{INSERT} statement).
+
+@code{mysql_store_results()} returns also 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()}
+returns <> 0.
+
+An empty result set is returned if there are no rows returned. (An empty
+result set differs from a null pointer as a return value.)
+
+Once you have called @code{mysql_store_result()} and got a result back
+which isn't a null pointer, you may call @code{mysql_num_rows()} to find
+out how many rows are in the result set.
+
+You can call @code{mysql_fetch_row()} to fetch rows from the result set,
+or @code{mysql_row_seek()} and @code{mysql_row_tell()} to obtain or
+set the current row position within the result set.
+
+You must call @code{mysql_free_result()} once you are done with the result
+set.
+
+@xref{NULL mysql_store_result, , @code{NULL mysql_store_result()}}.
+
+@subsubheading Return values
+
+A @code{MYSQL_RES} result structure with the results. @code{NULL} if
+an error occurred.
+
+@subsubheading Errors
+
+@table @code
+@item CR_COMMANDS_OUT_OF_SYNC
+Commands were executed in an improper order.
+@item CR_OUT_OF_MEMORY
+Out of memory.
+@item CR_SERVER_GONE_ERROR
+The @strong{MySQL} server has gone away.
+@item CR_SERVER_LOST
+The connection to the server was lost during the query.
+@item CR_UNKNOWN_ERROR
+An unknown error occurred.
+@end table
+
+@findex @code{mysql_thread_id()}
+@node mysql_thread_id, mysql_use_result, mysql_store_result, C API functions
+@subsection @code{mysql_thread_id()}
+
+@code{unsigned long mysql_thread_id(MYSQL *mysql)}
+
+@subsubheading Description
+
+Returns the thread ID of the current connection. This value can be used as
+an argument to @code{mysql_kill()} to kill the thread.
+
+If the connection is lost and you reconnect with @code{mysql_ping()}, the
+thread ID will change. This means you should not get the thread ID and store
+it for later, you should get it when you need it.
+
+@subsubheading Return values
+
+The thread ID of the current connection.
+
+@subsubheading Errors
+None.
+
+@findex @code{mysql_use_result()}
+@node mysql_use_result, NULL mysql_store_result, mysql_thread_id, C API functions
+@subsection @code{mysql_use_result()}
+
+@code{MYSQL_RES *mysql_use_result(MYSQL *mysql)}
+
+@subsubheading Description
+
+You must call @code{mysql_store_result()} or @code{mysql_use_result()} for
+every query which successfully retrieves data (@code{SELECT}, @code{SHOW},
+@code{DESCRIBE}, @code{EXPLAIN}).
+
+@code{mysql_use_result()} initiates a result set retrieval but does not
+actually read the result set into the client like @code{mysql_store_result()}
+does. Instead, each row must be retrieved individually by making calls to
+@code{mysql_fetch_row()}. This reads the result of a query directly from the
+server without storing it in a temporary table or local buffer, which is
+somewhat faster and uses much less memory than @code{mysql_store_result()}.
+The client will only allocate memory for the current row and a communication
+buffer that may grow up to @code{max_allowed_packet} bytes.
+
+On the other hand, you shouldn't use @code{mysql_use_result()} if you are
+doing a lot of processing for each row on the client side, or if the output
+is sent to a screen on which the user may type a @code{^S} (stop scroll).
+This will tie up the server and prevent other threads from updating any
+tables from which the data is being fetched.
+
+When using @code{mysql_use_result()}, you must execute
+@code{mysql_fetch_row()} until a @code{NULL} value is returned, otherwise the
+unfetched rows will be returned as part of the result set for your next
+query. The C API will give the error @code{Commands out of sync; You can't
+run this command now} if you forget to do this!
+
+You may not use @code{mysql_data_seek()}, @code{mysql_row_seek()},
+@code{mysql_row_tell()}, @code{mysql_num_rows()} or
+@code{mysql_affected_rows()} with a result returned from
+@code{mysql_use_result()}, nor may you issue other queries until the
+@code{mysql_use_result()} has finished. (However, after you have fetched all
+the rows, @code{mysql_num_rows()} will accurately return the number of rows
+fetched.)
+
+You must call @code{mysql_free_result()} once you are done with the result
+set.
+
+@subsubheading Return values
+
+A @code{MYSQL_RES} result structure. @code{NULL} if an error occurred.
+
+@subsubheading Errors
+
+@table @code
+@item CR_COMMANDS_OUT_OF_SYNC
+Commands were executed in an improper order.
+@item CR_OUT_OF_MEMORY
+Out of memory.
+@item CR_SERVER_GONE_ERROR
+The @strong{MySQL} server has gone away.
+@item CR_SERVER_LOST
+The connection to the server was lost during the query.
+@item CR_UNKNOWN_ERROR
+An unknown error occurred.
+@end table
+
+@node NULL mysql_store_result, Query results, mysql_use_result, C API functions
+@subsection 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
+means one of the following conditions occurred:
+
+@itemize @bullet
+@item
+There was a @code{malloc()} failure (for example, if the result set was too
+large).
+
+@item
+The data couldn't be read (an error occurred on the connection).
+
+@item
+The query returned no data (e.g., it was an @code{INSERT}, @code{UPDATE}
+or @code{DELETE}).
+@end itemize
+
+You can always check whether or not the statement should have produced a
+non-empty result by calling @code{mysql_field_count()}. If
+@code{mysql_field_count()} returns zero, the result is empty and the last
+query was a statement that does not return values (for example, an
+@code{INSERT} or a @code{DELETE}). If @code{mysql_field_count()} returns a
+non-zero value, the statement should have produced a non-empty result.
+See the description of the @code{mysql_field_count()} function for an
+example.
+
+You can test for an error by calling @code{mysql_error()} or
+@code{mysql_errno()}.
+
+@node Query results, Getting unique ID, NULL mysql_store_result, C API functions
+@subsection What results can I get from a query?
+
+In addition to the result set returned by a query, you can also get the
+following information:
+
+@itemize @bullet
+@item
+@code{mysql_affected_rows()} returns the number of rows affected by the last
+query when doing an @code{INSERT}, @code{UPDATE} or @code{DELETE}. An
+exception is that if @code{DELETE} is used without a @code{WHERE} clause, the
+table is recreated empty, which is much faster! In this case,
+@code{mysql_affected_rows()} returns zero for the number of records
+affected.
+
+@item
+@code{mysql_num_rows()} returns the number of rows in a result set. With
+@code{mysql_store_result()}, @code{mysql_num_rows()} may be called as soon as
+@code{mysql_store_result()} returns. With @code{mysql_use_result()},
+@code{mysql_num_rows()} may be called only after you have fetched all the
+rows with @code{mysql_fetch_row()}.
+
+@item
+@code{mysql_insert_id()} returns the ID generated by the last
+query that inserted a row into a table with an @code{AUTO_INCREMENT} index.
+@xref{mysql_insert_id, , @code{mysql_insert_id()}}.
+
+@item
+Some queries (@code{LOAD DATA INFILE ...}, @code{INSERT INTO
+... SELECT ...}, @code{UPDATE}) return additional info. The result is
+returned by @code{mysql_info()}. See the description for @code{mysql_info()}
+for the format of the string that it returns. @code{mysql_info()} returns a
+@code{NULL} pointer if there is no additional information.
+@end itemize
+
+@node Getting unique ID, C API linking problems, Query results, C API functions
+@subsection How can I get the unique ID for the last inserted row?
+
+If you insert a record in a table containing a column that has the
+@code{AUTO_INCREMENT} attribute, you can get the most recently generated
+ID by calling the @code{mysql_insert_id()} function.
+
+You can also retrieve the ID by using the @code{LAST_INSERT_ID()} function in
+a query string that you pass to @code{mysql_query()}.
+
+You can check if an @code{AUTO_INCREMENT} index is used by executing
+the following code. This also checks if the query was an @code{INSERT} with
+an @code{AUTO_INCREMENT} index:
+
+@example
+if (mysql_error(&mysql)[0] == 0 &&
+ mysql_num_fields(result) == 0 &&
+ mysql_insert_id(&mysql) != 0)
+@{
+ used_id = mysql_insert_id(&mysql);
+@}
+@end example
+
+The most recently generated ID is maintained in the server on a
+per-connection basis. It will not be changed by another client. It will not
+even be changed if you update another @code{AUTO_INCREMENT} column with a
+non-magic value (that is, a value that is not @code{NULL} and not @code{0}).
+
+If you want to use the ID that was generated for one table and insert
+it into a second table, you can use SQL statements like this:
+
+@example
+INSERT INTO foo (auto,text)
+ VALUES(NULL,'text'); # generate ID by inserting NULL
+INSERT INTO foo2 (id,text)
+ VALUES(LAST_INSERT_ID(),'text'); # use ID in second table
+@end example
+
+@node C API linking problems, Thread-safe clients, Getting unique ID, C API functions
+@subsection Problems linking with the C API
+
+When linking with the C API, the following errors may occur on some systems:
+
+@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
+
+If this happens on your system, you must include the math library by
+adding @code{-lm} to the end of the compile/link line.
+
+@node Thread-safe clients, , C API linking problems, C API functions
+@subsection How to make a thread-safe client
+
+The client library is ``almost'' thread-safe. The biggest problem is
+that the subroutines in @file{net.c} that read from sockets are not
+interrupt-safe. This was done with the thought that you might want to
+have your own alarm that can break a long read to a server. If you
+install an interrupt handlers for the @code{SIGPIPE} interrupt,
+the socket handling should be thread safe.
+
+In the standard binaries we distribute on our web site, the client libraries
+are not normally compiled with the thread safe option.
+
+To get a really thread-safe client where you can interrupt the client
+from other threads and set timeouts when talking with the MySQL server,
+you should use the @code{-lmysys}, @code{-lstring} and @code{-ldbug}
+libraries and the @code{net_serv.o} code that the server uses.
+
+If you don't need interrupts or timeouts you can just compile the client
+library @code{(mysqlclient)} to be thread safe and use this. In this
+case you don't have to worry about the @code{net_serv.o} object file or
+the other @strong{MySQL} libraries.
+
+When using a threaded client and you want to use timeouts and interrupts,
+you can make great use of the routines in the @file{thr_alarm.c} file.
+If you are using routines from the @code{mysys} library, the only thing
+you must remember is to call @code{my_init()} first!
+
+All functions except @code{mysql_real_connect()} are by default
+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
+using @code{mysql_real_connect()} anyway.)
+
+To make @code{mysql_real_connect()} thread-safe, you must recompile the
+client library with this command:
+
+@example
+shell> ./configure --enable-thread-safe-client
+@end example
+
+This will ensure that the client library will use the header files required
+for thread safe programs and also that @code{mysql_real_connect()} will use
+a thread safe version of the @code{gethostbyname()} call.
+
+You may get some errors because of undefined symbols when linking the
+standard client, because the pthread libraries are not included by
+default.
+
+The resulting @file{libmysqlclient.a} library is now thread-safe. What this
+means is that client code is thread-safe as long as two threads don't query
+the same connection handle returned by @code{mysql_real_connect()} at the
+same time; the client/server protocol allows only one request at a time on a
+given connection. If you want to use multiple threads on the same
+connection, you must have a mutex lock around your @code{mysql_query()} and
+@code{mysql_store_result()} call combination. Once
+@code{mysql_store_result()} is ready, the lock can be released and other
+threads may query the same connection. (In other words, different threads
+can use different @code{MYSQL_RES} pointers that were created with
+@code{mysql_store_result()}, as long as they use the proper locking
+protocol.) If you program with POSIX threads, you can use
+@code{pthread_mutex_lock()} and @code{pthread_mutex_unlock()} to establish
+and release a mutex lock.
+
+If you used @code{mysql_use_result()} rather than @code{mysql_store_result()},
+the lock would need to surround @code{mysql_use_result()} and the calls
+to @code{mysql_fetch_row()}. However, it really is best for threaded
+clients not to use @code{mysql_use_result()}.
+
+@node Perl, Eiffel, C API functions, Clients
+@section MySQL Perl API
+
+This section documents the Perl @code{DBI} interface. The former interface
+was called @code{mysqlperl}. @code{DBI}/@code{DBD} now is the
+recommended Perl interface, so @code{mysqlperl} is obsolete and is not
+documented here.
+
+@menu
+* DBI with DBD:: @code{DBI} with @code{DBD::mysql}
+* Perl DBI Class:: The @code{DBI} interface
+* DBI-info:: More @code{DBI}/@code{DBD} information
+@end menu
+
+@node DBI with DBD, Perl DBI Class, Perl, Perl
+@subsection @code{DBI} with @code{DBD::mysql}
+
+@code{DBI} is a generic interface for many databases. That means that
+you can write a script that works with many different database engines
+without change. You need a DataBase Driver (DBD) defined for each
+database type. For @strong{MySQL}, this driver is called
+@code{DBD::mysql}.
+
+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}
+@end example
+For more information on Object Oriented Programming
+(OOP) as defined in Perl5, see the Perl OOP page:
+@example
+@uref{http://language.perl.com/info/documentation.html}
+@end example
+
+Installation instructions for @strong{MySQL} Perl support are given in
+@ref{Perl support}.
+
+@cindex @code{DBI} Perl module
+@node Perl DBI Class, DBI-info, DBI with DBD, Perl
+@subsection The @code{DBI} interface
+
+@noindent
+@strong{Portable DBI methods}
+
+@multitable @columnfractions .3 .7
+@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.
+@item @code{execute} @tab Executes prepared statements.
+@item @code{do} @tab Prepares and executes a SQL statement.
+@item @code{quote} @tab Quotes string or @code{BLOB} values to be inserted.
+@item @code{fetchrow_array} @tab Fetches the next row as an array of fields.
+@item @code{fetchrow_arrayref} @tab Fetches next row as a reference array of fields.
+@item @code{fetchrow_hashref} @tab Fetches next row as a reference to a hashtable.
+@item @code{fetchall_arrayref} @tab Fetches all data as an array of arrays.
+@item @code{finish} @tab Finishes a statement and lets the system free resources.
+@item @code{rows} @tab Returns the number of rows affected.
+@item @code{data_sources} @tab Returns an array of databases available on localhost.
+@item @code{ChopBlanks} @tab Controls whether @code{fetchrow_*} methods trim spaces.
+@item @code{NUM_OF_PARAMS} @tab The number of placeholders in the prepared statement.
+@item @code{NULLABLE} @tab Which columns can be @code{NULL}.
+@item @code{trace} @tab Perform tracing for debugging.
+@end multitable
+
+@noindent
+@strong{MySQL-specific methods}
+
+@multitable @columnfractions .3 .7
+@item @code{insertid} @tab The latest @code{AUTO_INCREMENT} value.
+@item @code{is_blob} @tab Which column are @code{BLOB} values.
+@item @code{is_key} @tab Which columns are keys.
+@item @code{is_num} @tab Which columns are numeric.
+@item @code{is_pri_key} @tab Which columns are primary keys.
+@item @code{is_not_null} @tab Which columns CANNOT be @code{NULL}. See @code{NULLABLE}.
+@item @code{length} @tab Maximum possible column sizes.
+@item @code{max_length} @tab Maximum column sizes actually present in result.
+@item @code{NAME} @tab Column names.
+@item @code{NUM_OF_FIELDS} @tab Number of fields returned.
+@item @code{table} @tab Table names in returned set.
+@item @code{type} @tab All column types.
+@end multitable
+
+The Perl methods are described in more detail in the following sections.
+Variables used for method return values have these meanings:
+
+@table @code
+@item $dbh
+Database handle
+
+@item $sth
+Statement handle
+
+@item $rc
+Return code (often a status)
+
+@item $rv
+Return value (often a row count)
+@end table
+
+@noindent
+@strong{Portable DBI methods}
+
+@table @code
+
+@findex DBI->connect()
+@findex connect() DBI method
+@item connect($data_source, $username, $password)
+Use the @code{connect} method to make a database connection to the data
+source. The @code{$data_source} value should begin with
+@code{DBI:driver_name:}.
+Example uses of @code{connect} with the @code{DBD::mysql} driver:
+@example
+$dbh = DBI->connect("DBI:mysql:$database", $user, $password);
+$dbh = DBI->connect("DBI:mysql:$database:$hostname",
+ $user, $password);
+$dbh = DBI->connect("DBI:mysql:$database:$hostname:$port",
+ $user, $password);
+@end example
+If the user name and/or password are undefined, @code{DBI} uses the
+values of the @code{DBI_USER} and @code{DBI_PASS} environment variables,
+respectively. If you don't specify a hostname, it defaults to
+@code{'localhost'}. If you don't specify a port number, it defaults to the
+default @strong{MySQL} port (@value{default_port}).
+
+As of @code{Msql-Mysql-modules} version 1.2009,
+the @code{$data_source} value allows certain modifiers:
+
+@table @code
+@item mysql_read_default_file=file_name
+Read @file{filename} as an option file. For information on option files,
+see @ref{Option files}.
+
+@item mysql_read_default_group=group_name
+The default group when reading an option file is normally the
+@code{[client]} group. By specifying the @code{mysql_read_default_group}
+option, the default group becomes the @code{[group_name]} group.
+
+@item mysql_compression=1
+Use compressed communication between the client and server (@strong{MySQL}
+3.22.3 or later).
+
+@item mysql_socket=/path/to/socket
+Specify the pathname of the Unix socket that is used to connect
+to the server (@strong{MySQL} 3.21.15 or later).
+@end table
+
+Multiple modifiers may be given; each must be preceded by a semicolon.
+
+For example, if you want to avoid hardcoding the user name and password into
+a @code{DBI} script, you can take them from the user's @file{~/.my.cnf}
+option file instead by writing your @code{connect} call like this:
+
+@example
+$dbh = DBI->connect("DBI:mysql:$database"
+ . ";mysql_read_default_file=$ENV@{HOME@}/.my.cnf",
+ $user, $password);
+@end example
+
+This call will read options defined for the @code{[client]} group in the
+option file. If you wanted to do the same thing, but use options specified
+for the @code{[perl]} group as well, you could use this:
+
+@example
+$dbh = DBI->connect("DBI:mysql:$database"
+ . ";mysql_read_default_file=$ENV@{HOME@}/.my.cnf"
+ . ";mysql_read_default_group=perl",
+ $user, $password);
+@end example
+
+@findex DBI->disconnect
+@findex disconnect DBI method
+@item disconnect
+The @code{disconnect} method disconnects the database handle from the database.
+This is typically called right before you exit from the program.
+Example:
+@example
+$rc = $dbh->disconnect;
+@end example
+
+@findex DBI->prepare()
+@findex prepare() DBI method
+@item prepare($statement)
+Prepares a SQL statement for execution by the database engine
+and returns a statement handle @code{($sth)} which you can use to invoke
+the @code{execute} method.
+Typically you handle @code{SELECT} statements (and @code{SELECT}-like statements
+such as @code{SHOW}, @code{DESCRIBE} and @code{EXPLAIN}) by means of
+@code{prepare} and @code{execute}.
+Example:
+@example
+$sth = $dbh->prepare($statement)
+ or die "Can't prepare $statement: $dbh->errstr\n";
+@end example
+
+@findex DBI->execute
+@findex execute DBI method
+@item execute
+The @code{execute} method executes a prepared statement. For
+non-@code{SELECT} statements, @code{execute} returns the number of rows
+affected. If no rows are affected, @code{execute} returns @code{"0E0"},
+which Perl treats as zero but regards as true. If an error occurs,
+@code{execute} returns @code{undef}. For @code{SELECT} statements,
+@code{execute} only starts the SQL query in the database; you need to use one
+of the @code{fetch_*} methods described below to retrieve the data.
+Example:
+@example
+$rv = $sth->execute
+ or die "can't execute the query: $sth->errstr;
+@end example
+
+@findex DBI->do()
+@findex do() DBI method
+@item do($statement)
+The @code{do} method prepares and executes a SQL statement and returns the
+number of rows affected. If no rows are affected, @code{do} returns
+@code{"0E0"}, which Perl treats as zero but regards as true. This method is
+generally used for non-@code{SELECT} statements which cannot be prepared in
+advance (due to driver limitations) or which do not need to executed more
+than once (inserts, deletes, etc.). Example:
+@example
+$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)
+than prepare/execute for statements that doesn't contain parameters.
+
+@findex DBI->quote()
+@findex quote() DBI method
+@cindex Quoting strings
+@cindex Strings, quoting
+@item quote($string)
+The @code{quote} method is used to "escape" any special characters contained in
+the string and to add the required outer quotation marks.
+Example:
+@example
+$sql = $dbh->quote($string)
+@end example
+
+@findex DBI->fetchrow_array
+@findex fetchrow_array DBI method
+@item fetchrow_array
+This method fetches the next row of data and returns it as an array of
+field values. Example:
+@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 method
+@item fetchrow_arrayref
+This method fetches the next row of data and returns it as a reference
+to an array of field values. Example:
+@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 method
+@item fetchrow_hashref
+This method fetches a row of data and returns a reference to a hash
+table containing field name/value pairs. This method is not nearly as
+efficient as using array references as demonstrated above. Example:
+@example
+while($hash_ref = $sth->fetchrow_hashref) @{
+ print qw($hash_ref->@{firstname@}\t$hash_ref->@{lastname@}\t\
+ $hash_ref- > title@}\n);
+@}
+@end example
+
+@findex DBI->fetchall_arrayref
+@findex fetchall_arrayref DBI method
+@item fetchall_arrayref
+This method is used to get all the data (rows) to be returned from the
+SQL statement. It returns a reference to an array of references to arrays
+for each row. You access or print the data by using a nested
+loop. Example:
+@example
+my $table = $sth->fetchall_arrayref
+ or die "$sth->errstr\n";
+my($i, $j);
+for $i ( 0 .. $#@{$table@} ) @{
+ for $j ( 0 .. $#@{$table->[$i]@} ) @{
+ print "$table->[$i][$j]\t";
+ @}
+ print "\n";
+@}
+@end example
+
+@findex DBI->finish
+@findex finish DBI method
+@item finish
+Indicates that no more data will be fetched from this statement
+handle. You call this method to free up the statement handle and any
+system resources associated with it. Example:
+@example
+$rc = $sth->finish;
+@end example
+
+@findex DBI->rows
+@findex rows DBI method
+@item rows
+Returns the number of rows changed (updated, deleted, etc.) by the last
+command. This is usually used after a non-@code{SELECT} @code{execute}
+statement. Example:
+@example
+$rv = $sth->rows;
+@end example
+
+@findex DBI->@{NULLABLE@}
+@findex NULLABLE DBI method
+@item NULLABLE
+Returns a reference to an array of boolean values; for each element of
+the array, a value of TRUE indicates that this
+column may contain @code{NULL} values.
+Example:
+@example
+$null_possible = $sth->@{NULLABLE@};
+@end example
+
+@findex DBI->@{NUM_OF_FIELDS@}
+@findex NUM_OF_FIELDS DBI method
+@item NUM_OF_FIELDS
+This attribute indicates
+the number of fields returned by a @code{SELECT} or @code{SHOW FIELDS}
+statement. You may use this for checking whether a statement returned a
+result: A zero value indicates a non-@code{SELECT} statement like
+@code{INSERT}, @code{DELETE} or @code{UPDATE}.
+Example:
+@example
+$nr_of_fields = $sth->@{NUM_OF_FIELDS@};
+@end example
+
+@findex DBI->data_sources()
+@findex data_sources() DBI method
+@item data_sources($driver_name)
+This method returns an array containing names of databases available to the
+@strong{MySQL} server on the host @code{'localhost'}.
+Example:
+@example
+@@dbs = DBI->data_sources("mysql");
+@end example
+
+@findex DBI->@{ChopBlanks@}
+@findex ChopBlanks DBI method
+@item ChopBlanks
+This attribute determines whether the @code{fetchrow_*} methods will chop
+leading and trailing blanks from the returned values.
+Example:
+@example
+$sth->@{'ChopBlanks'@} =1;
+@end example
+
+@findex DBI->trace
+@findex trace DBI method
+@item trace($trace_level)
+@itemx trace($trace_level, $trace_filename)
+The @code{trace} method enables or disables tracing. When invoked as a
+@code{DBI} class method, it affects tracing for all handles. When invoked as
+a database or statement handle method, it affects tracing for the given
+handle (and any future children of the handle). Setting @code{$trace_level}
+to 2 provides detailed trace information. Setting @code{$trace_level} to 0
+disables tracing. Trace output goes to the standard error output by
+default. If @code{$trace_filename} is specified, the file is opened in
+append mode and output for @emph{all} traced handles is written to that
+file. Example:
+@example
+DBI->trace(2); # trace everything
+DBI->trace(2,"/tmp/dbi.out"); # trace everything to /tmp/dbi.out
+$dth->trace(2); # trace this database handle
+$sth->trace(2); # trace this statement handle
+@end example
+
+@tindex DBI_TRACE environment variable
+@tindex Environment variable, DBI_TRACE
+You can also enable @code{DBI} tracing by setting the @code{DBI_TRACE}
+environment variable. Setting it to a numeric value is equivalent to calling
+@code{DBI->(value)}. Setting it to a pathname is equivalent to calling
+@code{DBI->(2,value)}.
+
+@end table
+
+@noindent
+@strong{MySQL-specific methods}
+
+The methods shown below are @strong{MySQL}-specific and not part of the
+@code{DBI} standard. Several of them are now deprecated:
+@code{is_blob}, @code{is_key}, @code{is_num}, @code{is_pri_key},
+@code{is_not_null}, @code{length}, @code{max_length}, and @code{table}.
+Where @code{DBI}-standard alternatives exist, they are noted below.
+
+@table @code
+@findex DBI->@{insertid@}
+@findex insertid DBI method
+@tindex AUTO_INCREMENT, using with DBI
+@item insertid
+If you use the @code{AUTO_INCREMENT} feature of @strong{MySQL}, the new
+auto-incremented values will be stored here.
+Example:
+@example
+$new_id = $sth->@{insertid@};
+@end example
+
+As an alternative, you can use @code{$dbh->@{'mysql_insertid'@}}.
+
+@findex DBI->@{is_blob@}
+@findex is_blob DBI method
+@item is_blob
+Returns a reference to an array of boolean values; for each element of the
+array, a value of TRUE indicates that the
+respective column is a @code{BLOB}.
+Example:
+@example
+$keys = $sth->@{is_blob@};
+@end example
+
+@findex DBI->@{is_key@}
+@findex is_key DBI method
+@item is_key
+Returns a reference to an array of boolean values; for each element of the
+array, a value of TRUE indicates that the
+respective column is a key.
+Example:
+@example
+$keys = $sth->@{is_key@};
+@end example
+
+@findex DBI->@{is_num@}
+@findex is_num DBI method
+@item is_num
+Returns a reference to an array of boolean values; for each element of the
+array, a value of TRUE indicates that the
+respective column contains numeric values.
+Example:
+@example
+$nums = $sth->@{is_num@};
+@end example
+
+@findex DBI->@{is_pri_key@}
+@findex is_pri_key DBI method
+@item is_pri_key
+Returns a reference to an array of boolean values; for each element of the
+array, a value of TRUE indicates that the respective column is a primary key.
+Example:
+@example
+$pri_keys = $sth->@{is_pri_key@};
+@end example
+
+@findex DBI->@{is_not_null@}
+@findex is_not_null DBI method
+@item is_not_null
+Returns a reference to an array of boolean values; for each element of the
+array, a value of FALSE indicates that this column may contain @code{NULL}
+values.
+Example:
+@example
+$not_nulls = $sth->@{is_not_null@};
+@end example
+
+@code{is_not_null} is deprecated; it is preferable to use the
+@code{NULLABLE} attribute (described above), because that is a DBI standard.
+
+@findex DBI->@{length@}
+@findex length DBI method
+@findex DBI->@{max_length@}
+@findex max_length DBI method
+@item length
+@itemx max_length
+Each of these methods returns a reference to an array of column sizes. The
+@code{length} array indicates the maximum possible sizes that each column may
+be (as declared in the table description). The @code{max_length} array
+indicates the maximum sizes actually present in the result table. Example:
+
+@example
+$lengths = $sth->@{length@};
+$max_lengths = $sth->@{max_length@};
+@end example
+
+@findex DBI->@{NAME@}
+@findex NAME DBI method
+@item NAME
+Returns a reference to an array of column names.
+Example:
+@example
+$names = $sth->@{NAME@};
+@end example
+
+@findex DBI->@{table@}
+@findex table DBI method
+@item table
+Returns a reference to an array of table names.
+Example:
+@example
+$tables = $sth->@{table@};
+@end example
+
+@findex DBI->@{type@}
+@findex type DBI method
+@item type
+Returns a reference to an array of column types.
+Example:
+@example
+$types = $sth->@{type@};
+@end example
+
+@end table
+
+@node DBI-info, , Perl DBI Class, Perl
+@subsection More @code{DBI}/@code{DBD} information
+
+You can use the @code{perldoc} command to get more information about
+@code{DBI}.
+
+@example
+perldoc DBI
+perldoc DBI::FAQ
+perldoc DBD::mysql
+@end example
+
+You can also use the @code{pod2man}, @code{pod2html}, etc., tools to
+translate to other formats.
+
+And of course 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}
+@end example
+
+@node Eiffel, Java, Perl, Clients
+@section MySQL Eiffel wrapper
+
+The @strong{MySQL} @uref{http://www.mysql.com/Downloads/Contrib/,Contrib directory}
+contains an Eiffel wrapper written by Michael Ravits.
+
+You can also find this at:
+@url{http://www.netpedia.net/hosting/newplayer/}
+
+@node Java, PHP, Eiffel, Clients
+@section MySQL Java connectivity (JDBC)
+
+There are 2 supported JDBC drivers for @strong{MySQL} (the twz and mm driver).
+You can find a copy of these at @uref{http://www.mysql.com/Downloads/Contrib/}.
+For documentation consult any JDBC documentation and the
+drivers own documentation for @strong{MySQL} specific features.
+
+@node PHP, Cplusplus, Java, Clients
+@section MySQL PHP API
+
+PHP is a server-side, HTML embedded scripting language that may be used to
+create dynamic web pages. It contains support for accessing several
+databases, including @strong{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 website}.
+
+@menu
+* PHP problems:: Common problems with MySQL and PHP
+@end menu
+
+@node PHP problems, , PHP, PHP
+@subsection Common problems with MySQL and PHP
+
+@itemize @bullet
+@item Error: "Maximum Execution Time Exeeded"
+This is a PHP limit; Go into the @file{php3.ini} file and set the maximum
+execution time up from 30 seconds to something higher, as needed.
+It is also not a bad idea to double the ram allowed per script to 16 instead of
+8 MB.
+@item Error: "Fatal error: Call to unsupported or undefined function mysql_connect() in .."
+This means that your PHP version isn't compiled with @strong{MySQL} support.
+You can either compile a dynamic @strong{MySQL} module and load it into PHP or
+recompile PHP with built-in @code{MySQL} support. This is described in
+detail in the PHP manual.
+@end itemize
+
+@node Cplusplus, Python, PHP, Clients
+@section MySQL C++ APIs
+
+Two API's are available in the @strong{MySQL}
+@uref{http://www.mysql.com/Contrib/,Contrib directory}.
+
+@node Python, Tcl, Cplusplus, Clients
+@section MySQL Python APIs
+
+The @strong{MySQL} @uref{http://www.mysql.com/Contrib/,Contrib directory}
+contains a Python
+interface written by Joseph Skinner.
+
+You can also use the Python interface to iODBC to access a
+@strong{MySQL} server.
+@uref{http://starship.skyport.net/~lemburg/,mxODBC}
+
+@node Tcl, , Python, Clients
+@section MySQL Tcl APIs
+
+@uref{http://www.binevolve.com/~tdarugar/tcl-sql/, Tcl at binevolve}.
+The
+@uref{http://www.mysql.com/Contrib,Contrib directory} contains a Tcl
+interface that is based on msqltcl 1.50.
+
+@node Comparisons, MySQL internals, Clients, Top
+@chapter How MySQL compares to other databases
+
+@menu
+* Compare mSQL:: How @strong{MySQL} compares to @code{mSQL}
+* Compare PostgreSQL:: How @strong{MySQL} compares with PostgreSQL
+@end menu
+
+@node Compare mSQL, Compare PostgreSQL, Comparisons, Comparisons
+@section How MySQL compares to @code{mSQL}
+
+This section has been written by the @strong{MySQL} developers, so it
+should be read with that in mind. But there are NO factual errors that
+we know of.
+
+For a list of all supported limits, functions and types, see the
+@uref{http://www.mysql.com/information/crash-me.php, @code{crash-me} web page}.
+
+@table @strong
+@item Performance
+
+For a true comparison of speed, consult the growing @strong{MySQL} benchmark
+suite. @xref{Benchmarks}.
+
+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.
+@item
+@code{INSERT} operations into very simple tables with few columns and keys.
+@item
+@code{CREATE TABLE} and @code{DROP TABLE}.
+@item
+@code{SELECT} on something that isn't an index. (A table scan is very
+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,
+@strong{MySQL} should perform much better.
+
+On the other hand, @strong{MySQL} is much faster than @code{mSQL} (and
+most other SQL implementions) on the following:
+
+@itemize @bullet
+@item
+Complex @code{SELECT} operations.
+@item
+Retrieving large results (@strong{MySQL} has a better, faster and safer
+protocol).
+@item
+Tables with variable-length strings, because @strong{MySQL} has more efficent
+handling and can have indexes on @code{VARCHAR} columns.
+@item
+Handling tables with many columns.
+@item
+Handling tables with large record lengths.
+@item
+@code{SELECT} with many expressions.
+@item
+@code{SELECT} on large tables.
+@item
+Handling many connections at the same time. @strong{MySQL} 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.
+@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 @strong{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!
+@xref{Benchmarks}.
+@item
+@code{ORDER BY} and @code{GROUP BY}.
+@item
+@code{DISTINCT}.
+@item
+Using @code{TEXT} or @code{BLOB} columns.
+@end itemize
+
+@item SQL Features
+
+@itemize @bullet
+@item @code{GROUP BY} and @code{HAVING}.
+@code{mSQL} does not support @code{GROUP BY} at all.
+@strong{MySQL} 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.
+
+@item @code{INSERT} and @code{UPDATE} with calculations.
+@strong{MySQL} can do calculations in an @code{INSERT} or @code{UPDATE}.
+For example:
+@example
+mysql> UPDATE SET x=x*10+y WHERE x<20;
+@end example
+
+@item Aliasing.
+@strong{MySQL} has column aliasing.
+
+@item Qualifying column names.
+In @strong{MySQL}, 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.
+@strong{MySQL} 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?
+
+@strong{MySQL} has very precise types, so you can create tables that take
+very little space. An example of a useful @strong{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{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 @strong{MySQL}
+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. @strong{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 email support. (You are required to get
+a license if you include @strong{MySQL} with a product that you sell,
+of course.)
+
+@item Perl interfaces
+@strong{MySQL} has basically the same interfaces to Perl as @code{mSQL} with
+some added features.
+
+@item JDBC (Java)
+@strong{MySQL} currently has 4 JDBC drivers:
+@itemize @bullet
+@item
+The gwe driver: A Java interface by GWE technologies (not supported anymore).
+@item
+The jms driver: An improved gwe driver by Xiaokun Kelvin ZHU
+@email{X.Zhu@@brad.ac.uk}.
+@item
+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.
+@item
+The mm driver: A type 4 JDBC driver by Mark Matthews
+@email{mmatthew@@ecn.purdue.edu}. This is released under the GPL.
+@end itemize
+
+The recommended drivers are the twz or mm driver. Both are reported to work
+excellently.
+
+We know that @code{mSQL} has a JDBC driver, but we have too little experience
+with it to compare.
+
+@item Rate of development
+@strong{MySQL} has a very small 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
+can view the @code{mSQL} @file{HISTORY} file for the last year and
+compare it with the News section of the @strong{MySQL} Reference Manual
+(@pxref{News}). It should be pretty obvious which one has developed
+most rapidly.
+
+@item Utility programs
+Both @code{mSQL} and @strong{MySQL} have many interesting third-party
+tools. Because it is very easy to port upward (from @code{mSQL} to
+@strong{MySQL}), almost all the interesting applications that are available for
+@code{mSQL} are also available for @strong{MySQL}.
+
+@strong{MySQL} comes with a simple @code{msql2mysql} program that fixes
+differences in spelling between @code{mSQL} and @strong{MySQL} 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
+@strong{MySQL} usually takes a couple of minutes.
+@end table
+
+@menu
+* Using mSQL tools:: How to convert @code{mSQL} tools for @strong{MySQL}
+* Protocol differences:: How @code{mSQL} and @strong{MySQL} client/server communications protocols differ
+* Syntax differences:: How @code{mSQL} 2.0 SQL syntax differs from @strong{MySQL}
+@end menu
+
+@node Using mSQL tools, Protocol differences, Compare mSQL, Compare mSQL
+@subsection How to convert @code{mSQL} tools for MySQL
+
+According to our experience, it would just take a few hours to convert tools
+such as @code{msql-tcl} and @code{msqljava} that use the
+@code{mSQL} C API so that they work with the @strong{MySQL} C API.
+
+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 @strong{MySQL}.
+@item
+Compile.
+@item
+Fix all compiler errors.
+@end enumerate
+
+Differences between the @code{mSQL} C API and the @strong{MySQL} C API are:
+@itemize @bullet
+@item
+@strong{MySQL} 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.
+@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.
+@item
+@strong{MySQL} 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 @strong{MySQL} supporting
+multiple connections to the server from the same process.
+@end itemize
+
+@node Protocol differences, Syntax differences, Using mSQL tools, Compare mSQL
+@subsection How @code{mSQL} and MySQL client/server communications protocols differ
+
+There are enough differences that it is impossible (or at least not easy)
+to support both.
+
+The most significant ways in which the @strong{MySQL} protocol differs
+from the @code{mSQL} protocol are listed below:
+
+@itemize @bullet
+@item
+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.
+@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).
+@item
+@strong{MySQL} can read in the result unbuffered (without having to store the
+full set in the client).
+@item
+If a single read/write takes more than 30 seconds, the server closes
+the connection.
+@item
+If a connection is idle for 8 hours, the server closes the connection.
+@end itemize
+
+@node Syntax differences, , Protocol differences, Compare mSQL
+@subsection How @code{mSQL} 2.0 SQL syntax differs from MySQL
+
+@noindent
+@strong{Column types}
+
+@table @code
+@item @strong{MySQL}
+Has the following additional types (among others; see
+@pxref{CREATE TABLE, , @code{CREATE TABLE}}):
+@itemize @bullet
+@item
+@code{ENUM} type for one of a set of strings.
+@item
+@code{SET} type for many of a set of strings.
+@item
+@code{BIGINT} type for 64-bit integers.
+@end itemize
+@item
+@strong{MySQL} also supports
+the following additional type attributes:
+@itemize @bullet
+@item
+@code{UNSIGNED} option for integer columns.
+@item
+@code{ZEROFILL} option for integer columns.
+@item
+@code{AUTO_INCREMENT} option for integer columns that are a
+@code{PRIMARY KEY}.
+@xref{mysql_insert_id, , @code{mysql_insert_id()}}.
+@item
+@code{DEFAULT} value for all columns.
+@end itemize
+@item mSQL2
+@code{mSQL} column types correspond to the @strong{MySQL} types shown below:
+@multitable @columnfractions .15 .85
+@item @code{mSQL} @strong{type} @tab @strong{Corresponding @strong{MySQL} type}
+@item @code{CHAR(len)} @tab @code{CHAR(len)}
+@item @code{TEXT(len)} @tab @code{TEXT(len)}. @code{len} is the maximal length.
+And @code{LIKE} works.
+@item @code{INT} @tab @code{INT}. With many more options!
+@item @code{REAL} @tab @code{REAL}. Or @code{FLOAT}. Both 4- and 8-byte versions are available.
+@item @code{UINT} @tab @code{INT UNSIGNED}
+@item @code{DATE} @tab @code{DATE}. Uses ANSI SQL format rather than @code{mSQL}'s own format.
+@item @code{TIME} @tab @code{TIME}
+@item @code{MONEY} @tab @code{DECIMAL(12,2)}. A fixed-point value with two decimals.
+@end multitable
+@end table
+
+@noindent
+@strong{Index creation}
+
+@table @code
+@item @strong{MySQL}
+Indexes may be specified at table creation time with the @code{CREATE TABLE}
+statement.
+@item mSQL
+Indexes must be created after the table has been created, with separate
+@code{CREATE INDEX} statements.
+@end table
+
+@noindent
+@strong{To insert a unique identifier into a table}
+
+@table @code
+@item @strong{MySQL}
+Use @code{AUTO_INCREMENT} as a column type
+specifier.
+@xref{mysql_insert_id, , @code{mysql_insert_id()}}.
+@item mSQL
+Create a @code{SEQUENCE} on a table and select the @code{_seq} column.
+@end table
+
+@noindent
+@strong{To obtain a unique identifier for a row}
+
+@table @code
+@item @strong{MySQL}
+Add a @code{PRIMARY KEY} or @code{UNIQUE} key to the table and use this.
+New in 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
+@code{_rowid}.
+@item mSQL
+Use the @code{_rowid} column. Observe that @code{_rowid} may change over time
+depending on many factors.
+@end table
+
+@noindent
+@strong{To get the time a column was last modified}
+
+@table @code
+@item @strong{MySQL}
+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.
+
+@item mSQL
+Use the @code{_timestamp} column.
+@end table
+
+@noindent
+@strong{@code{NULL} value comparisons}
+
+@table @code
+@item @strong{MySQL}
+@strong{MySQL} 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 @strong{MySQL}.
+@end table
+
+@noindent
+@strong{String comparisons}
+
+@table @code
+@item @strong{MySQL}
+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
+@code{BINARY} attribute, which causes comparisons to be done according to the
+ASCII order used on the @strong{MySQL} server host.
+@item mSQL
+All string comparisons are performed in case-sensitive fashion with
+sorting in ASCII order.
+@end table
+
+@noindent
+@strong{Case-insensitive searching}
+
+@table @code
+@item @strong{MySQL}
+@code{LIKE} is a case-insensitive or case-sensitive operator, depending on
+the columns involved. If possible, @strong{MySQL} uses indexes if the
+@code{LIKE} argument doesn't start with a wildcard character.
+@item mSQL
+Use @code{CLIKE}.
+@end table
+
+@noindent
+@strong{Handling of trailing spaces}
+
+@table @code
+@item @strong{MySQL}
+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
+Retains trailing space.
+@end table
+
+@noindent
+@strong{@code{WHERE} clauses}
+
+@table @code
+@item @strong{MySQL}
+@strong{MySQL} correctly prioritizes everything (@code{AND} is evaluated
+before @code{OR}). To get @code{mSQL} behavior in @strong{MySQL}, use
+parentheses (as shown 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
+@strong{MySQL}. 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 @strong{MySQL} 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))));
+@end example
+@end table
+
+@noindent
+@strong{Access control}
+
+@table @code
+@item @strong{MySQL}
+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
+@section How MySQL compares to PostgreSQL
+
+We would first like to note that @code{PostgreSQL} and @strong{MySQL}
+are both widely used products but their design goals are completely
+different. This means that for some applications @strong{MySQL} is more
+suitable and for others @code{PostgreSQL} is more suitable. When
+choosing which database to use you should first check if the databases
+feature set is good enough to satisfy your application. If you need
+speed then @strong{MySQL} is probably your best choice, if you need some
+of the extra features that @code{PostgreSQL} can offer you should use
+@code{PostgreSQL}.
+
+@code{PostgreSQL} has some more advanced features like user-defined
+types, triggers, rules and some transaction support (currently it's
+has about same symantic as @code{MySQL}'s transactions in that the
+transaction is not 100 % atomic) . However, PostgreSQL lacks
+many of the standard types and functions from ANSI SQL and ODBC. See the
+@uref{http://www.mysql.com/information/crash-me.php, @code{crash-me} web page}
+for a complete list of limits and which types and functions are supported
+or unsupported.
+
+Normally, @code{PostgreSQL} is a magnitude slower than
+@strong{MySQL}. @xref{Benchmarks}. This is due largely to they have only
+transaction safe tables and that their transactions system is not as
+sophisticated as Berkeley DB's. In @strong{MySQL} you can decide per
+table if you want the table to be fast or take the speed penalty of
+making it transaction safe.
+
+The most important things that @code{PostgreSQL} supports that @strong{MySQL}
+don't yet support:
+
+@table @code
+@item Sub select
+@item Foregin keys
+@item Stored procedures
+@item An extendable type system.
+@item A way to extend the SQL to handle new key types (like R-trees)
+@end table
+
+@strong{MySQL} on the other hand supports a many ANSI SQL constructs
+that @code{PostgreSQL} doesn't support; Most of these can be found at the
+@uref{http://www.mysql.com/information/crash-me.php, @code{crash-me} web page}.
+
+If you really need the rich type system @code{PostgreSQL} offers and you
+can afford the speed penalty of having to do everything transaction
+safe, you should take a look at @code{PostgreSQL}.
+
+@node MySQL internals, Environment variables, Comparisons, Top
+@chapter MySQL internals
+
+This chapter describes a lot of things that you need to know when
+working on the @strong{MySQL} code.
+
+@menu
+* MySQL threads:: MySQL threads
+@end menu
+
+@node MySQL threads, , MySQL internals, MySQL internals
+@section MySQL threads
+
+The @strong{MySQL} server creates the the following threads:
+
+@itemize @bullet
+@item
+The TCP/IP connection thread handles all connect requests and
+creates a new dedicated thread to handle the authentication and
+and SQL query processing for the connection.
+@item
+On 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 compiled with @code{-DUSE_ALARM_THREAD}, a dedicated thread that
+handles alarms is created. This is only used on some systems where
+there are some 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} , slave replication thread will be
+started to read and apply updates from the master.
+@end itemize
+
+@code{mysqladmin processlist} only shows the connection and @code{INSERT
+DELAYED} threads.
+
+
+@page
+@node Environment variables, Users, MySQL internals, Top
+@appendix Environment variables
+
+Here follows a list of all environment variables that are used directly or
+indirectly by @strong{MySQL}. Most of these can also be found at other
+places in this manual.
+
+Note that any options on the command line will take precedence over
+values specified in configuration files and environment variables, and
+values in configuration files take precedence over values in environment
+variables.
+
+In many cases its preferable to use a configure file instead of environment
+variables to modify the behaviour of @strong{MySQL}. @xref{Option files}.
+
+@tindex CCX environment variable
+@tindex Environment variable, CCX
+@tindex CC environment variable
+@tindex Environment variable, CC
+@tindex CFLAGS environment variable
+@tindex Environment variable, CFLAGS
+@tindex CXXFLAGS environment variable
+@tindex Environment variable, CXXFLAGS
+@tindex DBI_USER environment variable
+@tindex Environment variable, DBI_USER
+@tindex DBI_TRACE environment variable
+@tindex Environment variable, DBI_TRACE
+@tindex HOME environment variable
+@tindex Environment variable, HOME
+@tindex LD_RUN_PATH environment variable
+@tindex Environment variable, LD_RUN_PATH
+@tindex MYSQL_DEBUG environment variable
+@tindex Environment variable, MYSQL_DEBUG
+@tindex MYSQL_HISTFILE environment variable
+@tindex Environment variable, MYSQL_HISTFILE
+@tindex MYSQL_HOST environment variable
+@tindex Environment variable, MYSQL_HOST
+@tindex MYSQL_PWD environment variable
+@tindex Environment variable, MYSQL_PWD
+@tindex MYSQL_TCP_PORT environment variable
+@tindex Environment variable, MYSQL_TCP_PORT
+@tindex MYSQL_UNIX_PORT environment variable
+@tindex Environment variable, MYSQL_UNIX_PORT
+@tindex PATH environment variable
+@tindex Environment variable, PATH
+@tindex TMPDIR environment variable
+@tindex Environment variable, TMPDIR
+@tindex TZ environment variable
+@tindex Environment variable, TZ
+@tindex UMASK_DIR environment variable
+@tindex Environment variable, UMASK_DIR
+@tindex UMASK environment variable
+@tindex Environment variable, UMASK
+@tindex USER environment variable
+@tindex Environment variable, USER
+
+@multitable @columnfractions .2 .8
+@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.
+@item @code{CXXFLAGS} @tab Flags for your C++ compiler when running configure.
+@item @code{DBI_USER} @tab The default user name for Perl DBI.
+@item @code{DBI_TRACE} @tab Used when tracing Perl DBI.
+@item @code{HOME} @tab The default path for the @code{mysql} history file is @file{$HOME/.mysql_history}.
+@item @code{LD_RUN_PATH} @tab Used to specify where your @code{libmysqlclient.so} is.
+@item @code{MYSQL_DEBUG} @tab Debug-trace options when debugging
+@item @code{MYSQL_HISTFILE} @tab The path to the @code{mysql} history file.
+@item @code{MYSQL_HOST} @tab Default host name used by the @code{mysql} command line prompt.
+@item @code{MYSQL_PWD} @tab The default password when connecting to mysqld. Note that use of this is insecure!
+@item @code{MYSQL_TCP_PORT} @tab The default TCP/IP port.
+@item @code{MYSQL_UNIX_PORT} @tab The default socket; used for connections to @code{localhost}.
+@item @code{PATH} @tab Used by the shell to finds the @strong{MySQL} programs.
+@item @code{TMPDIR} @tab The directory where temporary tables/files are created.
+@item @code{TZ} @tab This should be set to your local timezone. @xref{Timezone problems}.
+@item @code{UMASK_DIR} @tab The user-directory creation mask when creating directories. Note that this is ANDed with @code{UMASK}!
+@item @code{UMASK} @tab The user-file creation mask when creating files.
+@item @code{USER} @tab The default user on Windows to use when connecting to @code{mysqld}.
+@end multitable
+
+@page
+@node Users, Contrib, Environment variables, Top
+@appendix Some MySQL users
+
+@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
+
+@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}
+
+@c Didn't answer 2000-07-11
+@c @item @uref{http://www.yahoosuck.com, Yahoosuck}
+
+@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.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, Fotball (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.i-run.com/html/cookbook.html,My-Recipe.com; Cookbook at i-run.com}
+
+@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 website databse (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
+
+@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
+
+@appendixsec Web sites that use MySQL as a backend
+
+@itemize @bullet
+
+@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 @strong{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}
+@end itemize
+
+@appendixsec Some Domain/Internet/Web and related services
+
+@itemize @bullet
+
+@item @uref{http://www.wix.com/mysql-hosting, Registry of Web providers that
+support @strong{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.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 providers search with reviews}
+Made with @strong{MySQL} and Modperl, all pages are generated dynamically out of
+the @strong{MySQL} database
+@end itemize
+
+@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://war.jgaa.com:8080/support/index.php3, Jgaa's Internet - Official Support Site}
+
+@item @uref{http://io.incluso.com, Ionline - online publication:} @strong{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)
+
+@end itemize
+
+@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 @strong{MySQL} and PHP)}
+
+@item @uref{http://wwits.net/programs/mysql.phtml, WWITS (Uses @strong{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 websites using MySQL}
+@c Added 990905; max@wamdesign.com
+
+@item @uref{http://www.berkeleyconsultants.com, Berkeley Consultants Group}
+
+@end itemize
+
+@appendixsec Programming
+
+@itemize @bullet
+@item @uref{http://www.perl.org/cpan-testers, The Perl CPAN Testers results page}
+@end itemize
+
+
+@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 @strong{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 @strong{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 inauctions 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 Contrib, Credits, Users, Top
+@appendix Contributed programs
+
+Many users of @strong{MySQL} have contributed @emph{very} useful support
+tools and addons.
+
+@ifclear web
+A list of what is available at @uref{http://www.mysql.com/Downloads/Contrib/}
+(or any mirror) is shown below.
+If you want to build @strong{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
+
+
+@uref{http://www.mysql.com/Downloads/Contrib/00-README, 00-README}
+This listing.
+
+@appendixsec API's
+
+@itemize @bullet
+@item Perl modules
+@itemize @bullet
+@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. Useful with @code{DBI}/@code{DBD} support for
+older perl installations.
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/DBI-1.13.tar.gz, DBI-1.13.tar.gz}
+Perl @code{DBI} module.
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/KAMXbase1.0.tar.gz,KAMXbase1.0.tar.gz}
+Convert between @file{.dbf} files and @strong{MySQL} tables. Perl
+module written by Pratap Pereira @email{pereira@@ee.eng.ohio-state.edu},
+extened 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.2214.tar.gz, Msql-Mysql-modules-1.2214.tar.gz}
+Perl @code{DBD} module to access mSQL and @strong{MySQL} databases..
+
+@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. Useful with @code{DBI}/@code{DBD} support.
+@end itemize
+
+@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}
+The mm JDBC driver for @strong{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}
+The mm JDBC driver for @strong{MySQL}. This is a pre-release beta version
+and is actively developed. By Mark Matthews
+(@email{mmatthew@@ecn.purdue.edu}).
+The two drivers above have an LGPL
+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.mysql.com/Downloads/Contrib/twz1jdbcForMysql-1.0.4-GA.tar.gz, 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.
+@c no answer from server 990830
+@c You can always find the latest driver at @uref{http://www.voicenet.com/~zellert/tjFM/}.
+@item
+@item @uref{http://www.mysql.com/Downloads/Contrib/pmdamysql.tgz,pmdamysql.tgz}
+A @strong{MySQL} PMDA. Provides @strong{MySQL} server status and configuration
+variables.
+@end itemize
+
+@item C++
+@itemize @bullet
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/mysql-c++-0.02.tar.gz, mysql-c++-0.02.tar.gz}
+@strong{MySQL} C++ wrapper library. By Roland Haenel,
+@email{rh@@ginster.net}.
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/MyDAO.tar.gz, MyDAO}
+@strong{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++}
+@strong{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}
+A C++ database independent library that supports @strong{MySQL}.
+@end itemize
+
+@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}
+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}
+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 @strong{MySQL}.}
+With source code. By Matthias Fichtner.
+
+@item @uref{http://www.productivity.org/projects/mysql/, @strong{TmySQL}
+A library to use @strong{MySQL} with Delphi}
+
+@item @uref{http://www.geocities.com/CapeCanaveral/2064/mysql.html, Delphi TDataset-component}
+@end itemize
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/mysql-ruby-2.2.0.tar.gz, mysql-ruby-2.2.0.tar.gz}
+@strong{MySQL} Ruby module. By TOMITA Masahiro @email{tommy@@tmtm.org}
+@uref{http://www.netlab.co.jp/ruby/,Ruby} is an Object-Oriented Interpreter Language.
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/JdmMysqlDriver-0.1.0.tar.gz,JdmMysqlDriver-0.1.0.tar.gz}
+A VisualWorks 3.0 Smalltalk driver for @strong{MySQL}. By
+@email{joshmiller@@earthlink.net}
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/Db.py, 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}
+Python interface for @strong{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_mex_1_1.tar.gz, mysql_mex_1_1.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}
+for more information.
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/mysqltcl-1.53.tar.gz, mysqltcl-1.53.tar.gz}
+Tcl interface for @strong{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}
+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}
+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
+can easily switch between and move to other database engines by
+implementing one file for the new backend without needing to make 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}
+DbFramework is a collection of classes for manipulating @strong{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}
+@strong{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}
+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}
+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}.
+Eiffel wrapper by Michael Ravits.
+@end itemize
+
+@appendixsec Clients
+
+@itemize @bullet
+@item Graphical clients
+@itemize @bullet
+@item @uref{http://www.mysql.com/download_clients.html, mysqlgui homepage}
+The @strong{MySQL} GUI client homepage. By Sinisa at MySQL AB.
+@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}
+An administration tool for the @strong{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/mysqlwinadmn.zip, mysqlwinadmn.zip}
+Win32 GUI (binary only) to administrate a database, by David B. Mansel,
+@email{david@@zhadum.org}.
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/netadmin.zip, netadmin.zip}
+An administrator tool for @strong{MySQL} on Windows 95/98 and Windows NT
+4.0. Only tested with @strong{MySQL} 3.23.5 - 3.23.7. Written using the
+Tmysql components.
+
+You can write queries and show tables, indexes, table syntax and
+administrate user,host and database and so on. The is still beta and
+have still 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}.
+
+@item @uref{http://www.mysql.com/Downloads/Win32/admin13.exe,Atronic's @strong{MySQL} client for Win32 1.3.0.0} and @uref{http://www.mysql.com/Downloads/Win32/admin13.readme,Atronic's @strong{MySQL} client readme}.
+Home page for this can be found at: @uref{http://www.artronic.hr}.
+@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/Contrib/xmysqladmin-1.0.tar.gz, xmysqladmin-1.0.tar.gz}
+An X based front end to the @strong{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 @strong{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
+@strong{MySQL}, Oracle, PostgreSQL and mSQL.
+@item @uref{http://www.multimania.com/bbrox/GtkSQL,GtkSQL}
+A query tool for @strong{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/Contrib/mascon1.exe, mascon1.exe}
+You can get the newest one from
+@uref{http://www.SciBit.com,http://www.SciBit.com}.
+@item @uref{http://www.virtualbeer.net/dbui/,DBUI}
+DBUI is a Gtk graphical database editor.
+@end itemize
+
+@item Web clients
+@itemize @bullet
+@item @uref{http://www.mysql.com/Downloads/Contrib/mysqladmin-atif-1.0.tar.gz, mysqladmin-atif-1.0.tar.gz}
+WWW @strong{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}
+A tool written in PHP-FI to administrate @strong{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}
+@strong{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}
+Updated version of @file{mysqladm.tar.gz}, by High Tide.
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/billowmysql.zip, 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}.
+
+@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/phpMyAdmin_2.0.1.tar.gz,phpMyAdmin_2.0.1.tar.gz}
+A set of PHP3-scripts to adminstrate @strong{MySQL} over the WWW.
+
+@item @uref{http://www.htmlwizard.net/phpMyAdmin/, phpMyAdmin home page}
+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}
+@strong{MySQL} administrator in PHP. By Ofni Thomas
+@email{othomas@@vaidsystems.com}.
+@end itemize
+@item @uref{http://www.mysql.com/Downloads/Contrib/mysql-editor.tar.gz,mysql-editor.tar.gz}
+This cgi scripts in Perl enables you to edit content of Mysql
+database. By Tomas Zeman.
+@item
+@uref{http://futurerealm.com/opensource/futuresql.htm, FutureSQL Web Database Administration Tool}.
+FutureSQL by Peter F. Brown, is a Free, Open Source Rapid Application
+Development web database administration tool, written in Perl,
+using @strong{MySQL}. It uses @code{DBI:DBD} and @code{CGI.pm}.
+
+FutureSQL allows one to easily setup config files to view, edit, delete
+and otherwise process records from a @strong{MySQL} database. It uses a data
+dictionary, configuration files and templates, and allows "pre-processing"
+and "post-processing" on both fields, records and operations.
+@end itemize
+
+
+@appendixsec Web tools
+
+@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 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://www.odbsoft.com/cook/sources.htm}
+This package has various functions for generating html code from a SQL
+table structure and for generating SQL statements (Select, Insert,
+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}
+SQL/HTML is an HTML database manager for @strong{MySQL} using @code{DBI} 1.06.
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/udmsearch-2.2.1b.tar.gz, UdmSearch 2.2.1b (stable version)}
+@item @uref{http://www.mysql.com/Downloads/Contrib/udmsearch-3.0.5.tar.gz, UdmSearch 3.0.5 (development version)}
+@item @uref{http://mysearch.udm.net, UdmSearch home page}
+A @strong{MySQL}- and PHP- based search engine over HTTP. 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}
+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}
+A CGI program that parses an HTML file containing special tags, parses
+them and inserts data from a @strong{MySQL} database.
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/genquery.zip, 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}
+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/DBIx-TextIndex-0.02.tar.gz, DBIx-TextIndex-0.02.tar.gz}
+Full-text searching with Perl on @code{BLOB}/@code{TEXT} columns by Daniel Koch.
+@end itemize
+
+@appendixsec Performance Benchmarking tools
+
+@itemize @bullet
+@item @uref{http://www.mysql.com/Downloads/Contrib/mysql-bench-0.6.tar.gz, mysql-super-smack and friends}
+User-customizable multi-threaded tool set to benchmark @strong{MySQL}. By Sasha Pachev.
+@end itemize
+
+@appendixsec Authentication tools
+
+@itemize @bullet
+@item @uref{http://www.mysql.com/Downloads/Contrib/ascend-radius-mysql-0.7.1.patch.gz,
+ascend-radius-mysql-0.7.1.patch.gz}
+This is authentication and logging patch using @strong{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/checkpassword-0.81-mysql-0.6.5.patch.gz,
+checkpassword-0.81-mysql-0.6.5.patch.gz}
+@strong{MySQL} authentication patch for QMAIL and checkpassword. These are
+useful for management user(mail,pop account) by @strong{MySQL}.
+By @email{takeshi@@SoftAgency.co.jp}
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/jradius-diff.gz, jradius-diff.gz}
+@strong{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}
+Apache authentication module for @strong{MySQL}. By Zeev Suraski,
+@email{bourbon@@netvision.net.il}.
+
+@strong{Please} register this module at:
+@url{http://bourbon.netvision.net.il/mysql/mod_auth_mysql/register.html}. The
+registering information is only used for statistical purposes and will
+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}
+@strong{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}
+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
+@strong{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}
+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}
+This module authenticates users via @code{pam}, using @strong{MySQL}.
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/nsapi_auth_mysql.tar, nsapi_auth_mysql.tar}
+Netscape Web Server API (NSAPI) functions to authenticate (BASIC) users
+against @strong{MySQL} tables. By Yuan John Jiang.
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/qmail-1.03-mysql-0.6.5.patch.gz,
+qmail-1.03-mysql-0.6.5.patch.gz}
+Patch for qmail to authenticate users from a @strong{MySQL} table.
+@item @uref{http://www.mysql.com/Downloads/Contrib/pwcheck_mysql-0.1.tar.gz,pwcheck_mysql-0.1.tar.gz}
+An authentication module for the Cyrus IMAP server. By Aaron Newsome.
+@end itemize
+
+@appendixsec Converters
+
+@itemize @bullet
+@item @uref{http://www.mysql.com/Downloads/Contrib/dbf2mysql-1.14.tgz, dbf2mysql-1.14.tgz}
+Convert between @file{.dbf} files and @strong{MySQL} tables. By Maarten
+Boekhold, @email{boekhold@@cindy.et.tudelft.nl}, William Volkman and
+Michael Widenius. This converter includes rudementary read-only support
+for MEMO fields.
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/dbf2mysql-1.13.tgz, dbf2mysql-1.13.tgz}
+Convert between @file{.dbf} files and @strong{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}
+Convert between FoxPro @file{.dbf} files and @strong{MySQL} tables on Win32.
+By Alexander Eltsyn, @email{ae@@nica.ru} or @email{ae@@usa.net}.
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/dump2h-1.20.gz, 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}
+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
+while converting, quotes @strong{all} special characters in text and
+binary data, and so on. It will also convert to @code{mSQL} v1 and v2,
+and is free of charge for anyone. See
+@uref{http://www.cynergi.net/prod/exportsql/} for 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}
+Paste this function into an Access module of a database which 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}
+A script that does the exact reverse of @code{exportsql.txt}. That is,
+it imports data from @strong{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
+your actual @strong{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/msql2mysqlWrapper-1.0.tgz, /msql2mysqlWrapper 1.0}
+A C wrapper from @code{mSQL} to @strong{MySQL}. By @email{alfred@@sb.net}
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/sqlconv.pl, sqlconv.pl}
+A simple script that can be used to copy fields from one @strong{MySQL} table to
+another in bulk. Basically, you can run @code{mysqldump} and pipe it to
+the @code{sqlconv.pl} script and the script will parse through the
+@code{mysqldump} output and will rearrange the fields so they can be
+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 (ie - fields in different order, etc.).
+By Steve Shreeve.
+@end itemize
+
+@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}
+Raw port of a SQL mode for XEmacs. Supports completion. Original by
+Peter D. Pezaris @email{pez@@atlantic2.sbi.com} and partial
+@strong{MySQL} port by David Axmark.
+
+@item @uref{http://www.mysql.com/Downloads/Win32/MyAccess97_Ver_1_01.zip, MyAccess97 1.01}
+MyAccess is an AddIn for Access 97 and handles a lot of maintanance work
+for @strong{MySQL} databases.
+
+@item @uref{http://www.mysql.com/Downloads/Win32/MyAccess2000_Ver_1_01.zip, MyAccess2000 1.01}
+MyAccess is an AddIn for Access 2000 and handles a lot of maintanance work
+for @strong{MySQL} databases.
+
+@uref{http://www.mysql.com/Downloads/Win32/MyAccess-1.01.readme,
+MyAccess-readme}. By Hubertus Hiden.
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/radius-0.3.tar.gz, radius-0.3.tar.gz}
+Patches for @code{radiusd} to make it support @strong{MySQL}. By Wim Bonis,
+@email{bonis@@kiss.de}.
+@end itemize
+
+@appendixsec Useful tools
+
+@itemize @bullet
+@item @uref{http://www.mysql.com/Downloads/Contrib/mysql_watchdog.pl, mysql_watchdog.pl}
+Monitor the @strong{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}
+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}
+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}.
+A perl script to keep remote copies of a @strong{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}.
+MySQLTutor. A tutor of @strong{MySQL} for beginners
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/MySQLDB.zip, MySQLDB.zip}
+A COM library for @strong{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}
+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}
+Perl script that uses reverse indexing to handle text searching.
+By Daniel Koch.
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/dbcheck, dbcheck}
+Perl script that takes a backup of a tables before running isamchk on them.
+By Elizabeth.
+@end itemize
+
+@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}
+@end itemize
+
+@appendixsec Useful functions
+@itemize @bullet
+@item @uref{http://www.mysql.com/Downloads/Contrib/mysnprintf.c,mysnprintf.c}
+sprintf() function for SQL queries that can escape blobs. By Chunhua Liu.
+@end itemize
+
+@appendixsec Uncategorized
+
+@itemize @bullet
+
+@item @uref{http://www.mysql.com/Downloads/Contrib/findres.pl, 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}
+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}
+Store @code{hylafax} outgoing faxes in a @strong{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}
+@strong{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}
+Patches to add logging to @strong{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}
+Patches to add logging to @strong{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}
+Previous versions of things found here that you probably won't be
+interested in.
+@end itemize
+
+
+@page
+@node Credits, News, Contrib, Top
+@appendix Contributors to MySQL
+
+Contributors to the @strong{MySQL} distribution are listed below, in
+somewhat random order:
+
+@table @asis
+@item Michael (Monty) Widenius
+Has written the following parts of @strong{MySQL}:
+@itemize @bullet
+@item
+All the main code in @code{mysqld}.
+@item
+New functions for the string library.
+@item
+Most of the @code{mysys} library.
+@item
+The @code{ISAM} and @code{MyISAM} libraries (B-tree index file
+handlers with index compression and different record formats).
+@item
+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!).
+@item
+@strong{MyODBC}, the ODBC driver for Windows95.
+@item
+Fixing bugs in MIT-pthreads to get it to work for @strong{MySQL}. 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
+@code{DB2mysql}.
+@item
+Most parts of crash-me and the @strong{MySQL} benchmarks.
+@end itemize
+@item David Axmark
+@itemize @bullet
+@item
+Coordinator and main writer for the @strong{Reference Manual}, including
+enhancements to @code{texi2html}. Also automatic website updating from
+this manual.
+@item
+Autoconf, Automake and @code{libtool} support.
+@item
+The licensing stuff.
+@item
+Parts of all the text files. (Nowadays only the @file{README} is
+left. The rest ended up in the manual.)
+@item
+Our Mail master.
+@item
+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...)
+@item
+Our original portability code (more than 10 years old now). Nowadays
+only some parts of @code{mysys} are left.
+@item
+Someone for Monty to call in the middle of the night when he just got
+that new feature to work. :-)
+@end itemize
+@item Paul DuBois
+Help with making the Reference Manual correct and understandable. That
+includes rewriting Monty's and David's attempts at English into English
+as other people know it.
+@item Gianmassimo Vigazzola @email{qwerg@@mbox.vol.it} or @email{qwerg@@tin.it}
+The initial port to Win32/NT.
+@item Kim Aldale
+Helped to rewrite Monty's and David's early attempts at English into
+English.
+@item Allan Larsson (The BOSS for TCX DataKonsult AB)
+For all the time he has allowed Monty to spend on this ``maybe useful''
+tool (@strong{MySQL}). Dedicated user (and bug finder) of Unireg &
+@strong{MySQL}.
+@item Per Eric Olsson
+For more or less constructive criticism and real testing of the dynamic
+record format.
+@item Irena Pancirov @email{irena@@mail.yacc.it}
+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
+@strong{MySQL} syntax a superset of @code{mSQL}. Many of the APIs ideas are
+borrowed from @code{mSQL} to make it easy to port free @code{mSQL} programs
+to @strong{MySQL}. @strong{MySQL} 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 @strong{MySQL}.
+(@code{mSQL} is copyrighted David J. Hughes.)
+@item Fred Fish
+For his excellent C debugging and trace library. Monty has made a number
+of smaller improvements to the library (speed and additional options).
+@item Richard A. O'Keefe
+For his public domain string library.
+@item Henry Spencer
+For his regex library, used in @code{WHERE column REGEXP regexp}.
+@item Free Software Foundation
+From whom we got an excellent compiler (@code{gcc}), the @code{libc} library
+(from which we have borrowed @file{strto.c} to get some code working in Linux)
+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.
+@item Patrick Lynch
+For helping us acquire @code{http://www.mysql.com/}.
+@item Fred Lindberg
+For setting up qmail to handle @strong{MySQL} mailing list and for the
+incredible help we got in managing the @strong{MySQL} mailing lists.
+@item Igor Romanenko @email{igor@@frog.kiev.ua}
+@code{mysqldump} (previously @code{msqldump}, but ported and enhanced by
+Monty).
+@item Tim Bunce, Alligator Descartes
+For the @code{DBD} (Perl) interface.
+@item Andreas Koenig @email{a.koenig@@mind.de}
+For the Perl interface to @strong{MySQL}.
+@item Eugene Chan @email{eugene@@acenet.com.sg}
+For porting PHP to @strong{MySQL}.
+@item Michael J. Miller Jr. @email{mke@@terrapin.turbolift.com}
+For the first @strong{MySQL} manual. And a lot of spelling/language
+fixes for the FAQ (that turned into the @strong{MySQL} manual a long
+time ago).
+@item Giovanni Maruzzelli @email{maruzz@@matrice.it}
+For porting iODBC (Unix ODBC).
+@item Chris Provenzano
+Portable user level pthreads. From the copyright: This product includes
+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 @strong{MySQL} 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.
+@item "TAMITO" @email{tommy@@valley.ne.jp}
+The @code{_MB} character set macros and the ujis and sjis character sets.
+@item Joshua Chamas @email{joshua@@chamas.com}
+Base for concurrent insert, extended date syntax, debugging on NT and
+answering on the @strong{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 @strong{MySQL} with a Java
+client.
+@item Dr Xiaokun Kelvin ZHU @email{X.Zhu@@brad.ac.uk}
+Further development of the JDBC driver and other @strong{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 @strong{MySQL}.
+@item Doug Sisk @email{sisk@@wix.com}
+For providing RPM packages of @strong{MySQL} for RedHat Linux.
+@item Diemand Alexander V. @email{axeld@@vial.ethz.ch}
+For providing RPM packages of @strong{MySQL} for RedHat Linux-Alpha.
+@item Antoni Pamies Olive @email{toni@@readysoft.es}
+For providing RPM versions of a lot of @strong{MySQL} clients for Intel
+and SPARC.
+@item Jay Bloodworth @email{jay@@pathways.sde.state.sc.us}
+For providing RPM versions for @strong{MySQL} 3.21 versions.
+@item Jochen Wiedmann @email{wiedmann@@neckar-alb.de}
+For maintaining the Perl @code{DBD::mysql} module.
+@item Therrien Gilbert @email{gilbert@@ican.net}, Jean-Marc Pouyot @email{jmp@@scalaire.fr}
+French error messages.
+@item Petr snajdr, @email{snajdr@@pvt.net}
+Czech error messages.
+@item Jaroslaw Lewandowski @email{jotel@@itnet.com.pl}
+Polish error messages.
+@item Miguel Angel Fernandez Roiz
+Spanish error messages.
+@item Roy-Magne Mo @email{rmo@@www.hivolda.no}
+Norwegian error messages and testing of 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}
+Italian error messages.
+@item Dirk Munzinger @email{dirk@@trinity.saar.de}
+German error messages.
+@item Billik Stefan @email{billik@@sun.uniag.sk}
+Slovak error messages.
+@item Stefan Saroiu @email{tzoompy@@cs.washington.edu}
+Romanian error messages.
+@item Peter Feher
+Hungarian error messages
+@item David Sacerdote @email{davids@@secnet.com}
+Ideas for secure checking of DNS hostnames.
+@item Wei-Jou Chen @email{jou@@nematic.ieo.nctu.edu.tw}
+Some support for Chinese(BIG5) characters.
+@item Wei He @email{hewei@@mail.ied.ac.cn}
+A lot of functionality for the Chinese(GBK) character set.
+@item Zeev Suraski @email{bourbon@@netvision.net.il}
+@code{FROM_UNIXTIME()} time formatting, @code{ENCRYPT()} functions, and
+@code{bison} advisor.
+Active mailing list member.
+@item Luuk de Boer @email{luuk@@wxs.nl}
+Ported (and extended) the benchmark suite to @code{DBI}/@code{DBD}. Have
+been of great help with @code{crash-me} and running benchmarks. Some new
+date functions. The mysql_setpermissions script.
+@item Jay Flaherty @email{fty@@utk.edu}
+Big parts of the Perl @code{DBI}/@code{DBD} section in the manual.
+@item Paul Southworth @email{pauls@@etext.org}, Ray Loyzaga @email{yar@@cs.su.oz.au}
+Proof-reading of the Reference Manual.
+@item Alexis Mikhailov @email{root@@medinf.chuvashia.su}
+User definable functions (UDFs); @code{CREATE FUNCTION} and
+@code{DROP FUNCTION}.
+@item Andreas F. Bobak @email{bobak@@relog.ch}
+The @code{AGGREGATE} extension to UDF functions.
+@item Ross Wakelin @email{R.Wakelin@@march.co.uk}
+Help to set up InstallShield for @strong{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 @strong{MySQL}.
+@item Curt Sampson @email{cjs@@portal.ca}
+Porting of MIT-pthreads to NetBSD/Alpha and NetBSD 1.3/i386.
+@item Sinisa Milivojevic @email{sinisa@@coresinc.com}
+Compression (with @code{zlib}) to the client/server protocol.
+Perfect hashing for the lexical analyzer phase.
+@item Antony T. Curtis @email{antony.curtis@@olcs.net}
+Porting of @strong{MySQL} to OS/2.
+@item Martin Ramsch @email{m.ramsch@@computer.org}
+Examples in the @strong{MySQL} Tutorial.
+@item Tim Bunce
+Author of @code{mysqlhotcopy}.
+@item Steve Harvey
+For making @code{mysqlaccess} more secure.
+@item Jeremy Cole @email{jeremy@@spaceapes.com}
+Proofreading and editing this fine manual.
+@item Valueclick Inc.
+For sponsoring the optimize section in this manual.
+@end table
+
+Other contributors, bugfinders and testers: 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 Hyv@"atti.
+
+And lots of bug report/patches from the folks on the mailing list.
+
+And a big tribute to those that help us answer questions on the
+@code{mysql@@lists.mysql.com} mailing list:
+
+@table @asis
+@item Daniel Koch @email{dkoch@@amcity.com}
+Irix setup.
+@item Luuk de Boer @email{luuk@@wxs.nl}
+Benchmark questions.
+@item Tim Sailer @email{tps@@users.buoy.com}
+@code{DBD-mysql} questions.
+@item Boyd Lynn Gerber @email{gerberb@@zenez.com}
+SCO related questions.
+@item Richard Mehalick @email{RM186061@@shellus.com}
+@code{xmysql}-related questions and basic installation questions.
+@item Zeev Suraski @email{bourbon@@netvision.net.il}
+Apache module configuration questions (log & auth), PHP-related
+questions, SQL syntax related questions and other general questions.
+@item Francesc Guasch @email{frankie@@citel.upc.es}
+General questions.
+@item Jonathan J Smith @email{jsmith@@wtp.net}
+Questions pertaining to OS-specifics with Linux, SQL syntax, and other
+things that might be needing some work.
+@item David Sklar @email{sklar@@student.net}
+Using @strong{MySQL} from PHP and Perl.
+@item Alistair MacDonald @email{A.MacDonald@@uel.ac.uk}
+Not yet specified, but is flexible and can handle Linux and maybe HP-UX.
+Will try to get user to use @code{mysqlbug}.
+@item John Lyon @email{jlyon@@imag.net}
+Questions about installing @strong{MySQL} on Linux systems, using either
+@file{.rpm} files, or compiling from source.
+@item Lorvid Ltd. @email{lorvid@@WOLFENET.com}
+Simple billing/license/support/copyright issues.
+@item Patrick Sherrill @email{patrick@@coconet.com}
+ODBC and VisualC++ interface questions.
+@item Randy Harmon @email{rjharmon@@uptimecomputers.com}
+@code{DBD}, Linux, some SQL syntax questions.
+@end table
+
+@node News, Bugs, Credits, Top
+@appendix MySQL change history
+
+Note that we tend to update the manual at the same time we implement new
+things to @strong{MySQL}. If you find a version listed below that you can't
+find on the
+@uref{http://www.mysql.com/downloads/,@strong{MySQL} download page},
+this means that the version has not yet been released!
+
+@menu
+* News-3.23.x:: Changes in release 3.23.x (Released as alpha)
+* News-3.22.x:: Changes in release 3.22.x (Recommended version)
+* News-3.21.x:: Changes in release 3.21.x
+* News-3.20.x:: Changes in release 3.20.x
+* News-3.19.x:: Changes in release 3.19.x
+@end menu
+
+@node News-3.23.x, News-3.22.x, News, News
+@appendixsec Changes in release 3.23.x (Released as alpha)
+
+The major difference between release 3.23 and releases 3.22 and 3.21 is that
+3.23 contains a new ISAM library (MyISAM), which is more tuned for SQL
+than the old ISAM was.
+
+The 3.23 release is under development, and things will be added at a
+fast pace to it. For the moment we recommend this version only for
+users that desperately need a new feature that is found only in this
+release (like big file support and machine-independent tables). (Note
+that all new functionality in @strong{MySQL} 3.23 is extensively tested, but as
+this release involves much new code, it's difficult to test everything).
+
+We are not adding any more new features that are likely to break any
+old code in @strong{MySQL} 3.23 so this version should stabilise pretty soon
+and will soon be declared beta, gamma and release.
+
+@menu
+* News-3.23.22:: Changes in release 3.23.22
+* News-3.23.21:: Changes in release 3.23.21
+* News-3.23.20:: Changes in release 3.23.20
+* News-3.23.19:: Changes in release 3.23.19
+* News-3.23.18:: Changes in release 3.23.18
+* News-3.23.17:: Changes in release 3.23.17
+* News-3.23.16:: Changes in release 3.23.16
+* News-3.23.15:: Changes in release 3.23.15
+* News-3.23.14:: Changes in release 3.23.14
+* News-3.23.13:: Changes in release 3.23.13
+* News-3.23.12:: Changes in release 3.23.12
+* News-3.23.11:: Changes in release 3.23.11
+* News-3.23.10:: Changes in release 3.23.10
+* News-3.23.9:: Changes in release 3.23.9
+* News-3.23.8:: Changes in release 3.23.8
+* News-3.23.7:: Changes in release 3.23.7
+* News-3.23.6:: Changes in release 3.23.6
+* News-3.23.5:: Changes in release 3.23.5
+* News-3.23.4:: Changes in release 3.23.4
+* News-3.23.3:: Changes in release 3.23.3
+* News-3.23.2:: Changes in release 3.23.2
+* News-3.23.1:: Changes in release 3.23.1
+* News-3.23.0:: Changes in release 3.23.0
+@end menu
+
+@node News-3.23.22, News-3.23.21, News-3.23.x, News-3.23.x
+@appendixsubsec Changes in release 3.23.22
+@itemize @bullet
+@item
+Fixed that @code{lex_hash.h} is created properly for each @code{MySQL}
+distribution.
+@item
+Fixed that @code{MASTER} and @code{COLLECTION} are not a reserved words.
+@item
+The log generated by @code{--slow-query-log} didn't contain the whole queries.
+@item
+Fixed that open transactions in BDB tables are rolled back if the
+connection is closed unexpectedly.
+@item
+Added workaround for a bug in gcc 2.96 (intel) and gcc 2.9 (Ia64) in
+gen_lex_hash.c.
+@item
+Fixed memory leak in the client library when using @code{host=..} in the
+@code{my.cnf} file.
+@item
+Optimized functions that manipulates the hours/minutes/seconds.
+@item
+Fixed bug when comparing the result of @code{DATE_ADD}/@code{DATE_SUB}
+against a number
+@item
+Changed the meaning of @code{-F, --fast} for @code{myisamchk}. Added option
+@code{-C, --check-only-changed} to @code{myisamchk}.
+@item
+Added @code{ANALYZE table_name} to update key statistics for tables.
+@item
+Changed binary items @code{0x...} to be default regarded as an integer
+@item
+Fix for SCO and @code{show proesslist}.
+@item
+Added @code{auto-rehash} on reconnect for the @code{mysql} client.
+@end itemize
+
+@node News-3.23.21, News-3.23.20, News-3.23.22, News-3.23.x
+@appendixsubsec Changes in release 3.23.21
+@itemize @bullet
+@item
+Added @code{mysql_character_set_name(MYSQL *mysql)} function to the MySQL API.
+@item
+Made the update log @code{ASCII 0} safe.
+@item
+Added the @code{mysql_config} script.
+@item
+Fixed problem when using @code{<} or @code{>} with a char column that was only
+partly indexed.
+@item
+One would get a core dump if the log file was not readable by the MySQL user.
+@item
+Changed @code{mysqladmin} to use the @code{CREATE DATABASE}/@code{DROP
+DATABASE} commands instead of the old deprecated API calls.
+@item
+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 table_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).
+@item
+Fixed bug in @code{REPAIR TABLE} so that it works with tables without index.
+@item
+Fixed buffer overrun in @code{DROP DATABASE}
+@item
+@code{LOAD TABLE FROM MASTER} is sufficiently bug-free to announce it as
+a feature.
+@item
+@code{MATCH} and @code{AGAINST} are now reserved words.
+@end itemize
+
+@node News-3.23.20, News-3.23.19, News-3.23.21, News-3.23.x
+@appendixsubsec Changes in release 3.23.20
+@itemize @bullet
+@item
+Fixed bug in 3.23.19; @code{DELETE FROM table_name} removed the .frm file.
+@end itemize
+
+@node News-3.23.19, News-3.23.18, News-3.23.20, News-3.23.x
+@appendixsubsec Changes in release 3.23.19
+@itemize @bullet
+@item
+Changed copyright for all files to GPL for the server code and utilities and
+LGPL for the client libraries.
+@item
+Fixed bug where all rows matching weren't updated on a @code{MyISAM} table
+when doing update based on key on a table with many keys and some key changed
+values.
+@item
+The Linux @strong{MySQL} RPM's and binaries are now staticly linked with
+a linuxthread version that has faster mutex handling when used with
+@strong{MySQL}.
+@item
+@code{ORDER BY} can now uses @code{REF} keys to find subset the rows
+that needs to be sorted.
+@item
+Changed name of @code{print_defaults} to @code{my_print_defaults} to avoid
+name confusion.
+@item
+Fixed @code{NULLIF()} to work according to ANSI SQL99.
+@item
+Added @code{net_read_timeout} and @code{net_write_timeout} as startup
+parameters to @code{mysqld}.
+@item
+Fixed bug that destroyed index when doing @code{myisamchk --sort-records}
+on a table with prefix compressed index.
+@item
+Added pack_isam and myisampack to the standard @strong{MySQL} distribution.
+@item
+Added the syntax @code{BEGIN WORK} (the same as @code{BEGIN}).
+@item
+Fixed core dump bug when using @code{ORDER BY} on a @code{CONV()} expression.
+@item Added @code{LOAD TABLE FROM MASTER}
+@item Added @code{FLUSH MASTER} and @code{FLUSH SLAVE}
+@item Fixed big/little endian problem in the replication
+@end itemize
+
+@node News-3.23.18, News-3.23.17, News-3.23.19, News-3.23.x
+@appendixsubsec Changes in release 3.23.18
+@itemize @bullet
+@item
+Fixed a problem from 3.23.17 when choosing character set on the client side.
+@item
+Added @code{FLUSH TABLES WITH READ LOCK} to make a global lock suitable to
+make a copy of @strong{MySQL} data files.
+@item
+@code{CREATE TABLE ... SELECT ... PROCEDURE} now works.
+@item
+Internal temporary tables will now uses compressed index when using
+@code{GROUP BY} on @code{VARCHAR/CHAR} columns.
+@item
+Fixed a problem when locking the same table with both a @code{READ} and a
+@code{WRITE} lock.
+@item
+Fixed problem with myisamchk and @code{RAID} tables.
+@end itemize
+
+@node News-3.23.17, News-3.23.16, News-3.23.18, News-3.23.x
+@appendixsubsec Changes in release 3.23.17
+@itemize @bullet
+@item
+Fixed a bug in @code{find_in_set()} when the first argument was @code{NULL}.
+@item
+Added table locks to Berkeley DB.
+@item
+Fixed a bug with @code{LEFT JOIN} and @code{ORDER BY} where the first
+table had only one matching row.
+@item
+Added 4 sample @code{my.cfg} 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).
+@item
+Changed syntax for @code{INNER JOIN} to match ANSI SQL.
+@item
+Added @code{NATURAL JOIN} syntax.
+@item
+A lot of fixes in the @code{BDB} interface.
+@item
+Added handling of @code{--no-defaults} and @code{--defaults-file} to
+@code{safe_mysqld.sh} and @code{mysql_install_db.sh}.
+@item
+Fixed bug in reading compressed tables with many threads.
+@item
+Fixed that @code{USE INDEX} works with @code{PRIMARY} keys.
+@item
+Added @code{BEGIN} statement to start a transaction in @code{AUTOCOMMIT} mode.
+@item
+Added symbolic links support for Win32.
+@item
+Changed protocol to let client know if the server is in AUTOCOMMIT mode
+and if there is a pending transaction. If there is a pending transaction
+the client library will give an error before reconnecting to the server to
+let the client know that the server did a rollback.
+The protocol is still backward compatible with old clients
+@item
+@code{KILL} now works on a thread that is locked on a 'write' to a dead client.
+@item
+Fixed memory leak in the replication slave thread.
+@item
+Added new option @code{log-slave-updates} to allow daisy-chaining the slaves.
+@item
+Fixed compile error on FreeBSD and other systems where @code{pthread_t}
+is not the same as @code{int}.
+@item
+Fixed master shutdown aborting the slave thread.
+@item
+Fixed a race condition in @code{INSERT DELAYED} code when doing
+@code{ALTER TABLE}.
+@item
+Added deadlock detection sanity checks to @code{INSERT DELAYED}
+@end itemize
+
+@node News-3.23.16, News-3.23.15, News-3.23.17, News-3.23.x
+@appendixsubsec Changes in release 3.23.16
+@itemize @bullet
+@item
+Added option @code{TYPE=QUICK} to @code{CHECK} and @code{REPAIR}.
+@item
+Fixed bug in @code{REPAIR TABLE} when the table was in use by other threads.
+@item
+Added a thread cache to make it possible to debug @strong{MySQL} with
+@code{gdb} when one does a lot of reconnects. This will also improve
+systems where you can't use persistent connections.
+@item
+Lots of fixes in the Berekely DB interface.
+@item
+@code{UPDATE IGNORE} will not abort if an update results in a
+@code{DUPLICATE_KEY} error.
+@item
+Put @code{CREATE TEMPORARY TABLE} commands in the update log.
+@item
+Fixed bug in handling of masked IP numbers in the privilege tables.
+@item
+Fixed bug with @code{delayed_key_writes} tables and @code{CHECK TABLE}.
+@item
+Added @code{replicate-do-db} and @code{replicate-ignore-db} options to
+restrict which databases get replicated
+@item
+Added @code{SQL_LOG_BIN} option
+@end itemize
+
+@node News-3.23.15, News-3.23.14, News-3.23.16, News-3.23.x
+@appendixsubsec Changes in release 3.23.15
+@itemize @bullet
+@item
+To start @code{mysqld} as @code{root}, you must now use the @code{--user=root} option.
+@item
+Added interface to Berkeley DB. (This is not yet functional; Play with it at
+your own risk!)
+@item
+Replication between master and slaves.
+@item
+Fixed bug that other threads could steal a lock when a thread had
+a lock on a table and did a @code{FLUSH TABLES} command.
+@item
+Added the @code{slow_launch_time} variable and the @code{Slow_launch_threads}
+status variable to @code{mysqld}. These can be examined with
+@code{mysqladmin variables} and @code{mysqladmin extended-status}.
+@item
+Added functions @code{INET_NTOA()} and @code{INET_ATON()}.
+@item
+The default type of @code{IF()} now depends on the second and
+third arguments and not only on the second argument.
+@item
+Fixed case when @code{myisamchk} could go into a loop when trying to
+repair a crashed table.
+@item
+Don't write @code{INSERT DELAYED} to update log if @code{SQL_LOG_UPDATE=0}.
+@item
+Fixed problem with @code{REPLACE} on @code{HEAP} tables.
+@item
+Added possible character sets and time zone to @code{SHOW VARIABLES}.
+@item
+Fixed bug in locking code that could result it locking problems with
+concurrent inserts under high load.
+@item
+Fixed a problem with @code{DELETE} of many rows on a table with
+compressed keys where @strong{MySQL} scanned the index to find the rows.
+@item
+Fixed problem with @code{CHECK} on table with deleted keyblocks.
+@item
+Fixed a bug in reconnect (at the client side) where it didn't free memory
+properly in some contexts.
+@item
+Fixed problems in update log when using @code{LAST_INSERT_ID()} to update
+a table with an auto_increment key.
+@item
+Added function @code{NULLIF()}.
+@item
+Fixed bug when using @code{LOAD DATA INFILE} on a table with
+@code{BLOB/TEXT} columns.
+@item
+Optimised MyISAM to be faster when inserting keys in sorted order.
+@item
+@code{EXPLAIN SELECT..} now also prints out whether @strong{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
+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}
+columns are constants in the @code{WHERE} clause. @xref{MySQL indexes}.
+@item
+@code{UPDATE} and @code{DELETE} on a whole unique key in the @code{WHERE} part,
+is now faster than before.
+@item
+Changed @code{RAID_CHUNKSIZE} to be in 1024 byte increments.
+@item
+Fixed coredump in LOAD_FILE(NULL).
+@end itemize
+
+@node News-3.23.14, News-3.23.13, News-3.23.15, News-3.23.x
+@appendixsubsec Changes in release 3.23.14
+@itemize @bullet
+@item
+Fixed a bug in @code{CONCAT()} where one of the arguments was a function
+that returned a modified argument.
+@item
+Fixed a critical bug in @code{myisamchk}, where it updated the header in
+the index file when one only checked the table. This confused the
+@code{mysqld} daemon if it updated the same table at the same time. Now
+the status in the index file is only updated if one uses
+@code{--update-state}. With older @code{myisamchk} versions you should
+use @code{--read-only} when only checking tables, if there is the
+slightest chance that the @code{mysqld} server is working on the table at the
+same time!
+@item
+Fixed that @code{DROP TABLE} is logged in the update log.
+@item
+Fixed problem when searching on @code{DECIMAL()} key field
+where the column data contained leading zeros.
+@item
+Fix bug in @code{myisamchk} when the auto_increment isn't the first key.
+@item
+Allow @code{DATETIME} in ISO8601 format: 2000-03-12T12:00:00
+@item
+Dynamic character sets. A @code{mysqld} binary can now handle many different
+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()}.
+@item
+Added the @code{UMASK_DIR} environment variable.
+@item
+Added function @code{CONNECTION_ID()}.
+@item
+When using @code{=} on @code{BLOB} or @code{VARCHAR BINARY} keys, where
+only a part of the column was indexed, the whole column of the result
+row wasn't compared.
+@item
+Fix for sjis character set and @code{ORDER BY}.
+@item
+When running in ANSI mode, don't allow columns to be used that aren't in
+the @code{GROUP BY} part.
+@end itemize
+
+@node News-3.23.13, News-3.23.12, News-3.23.14, News-3.23.x
+@appendixsubsec Changes in release 3.23.13
+@itemize @bullet
+@item
+Fixed problem when doing locks on the same table more than 2 times in
+the same @code{LOCK TABLE} command; This fixed the problem one got when running
+the test-ATIS test with @code{--fast} or @code{--check-only-changed}.
+@item
+Added option @code{SQL_BUFFER_RESULT} to @code{SELECT}.
+@item
+Removed end space from double/float numbers in results from temporary
+tables.
+Added @code{CHECK TABLE} command.
+@item
+Added changes for MyISAM in 3.23.12 that didn't get into the source
+distribution because of CVS problems.
+@item
+Fixed bug so that mysqladmin shutdown will wait for the local server to close
+down.
+@item
+Fixed a possible endless loop when calculating timestamp.
+@item
+Added print_defaults to the .rpm files. Removed mysqlbug from the client
+rpm file.
+@end itemize
+
+@node News-3.23.12, News-3.23.11, News-3.23.13, News-3.23.x
+@appendixsubsec Changes in release 3.23.12
+@itemize @bullet
+@item
+Fixed bug in @code{MyISAM} involving @code{REPLACE ... SELECT} which could
+give a corrupted table.
+@item
+Fixed bug in @code{myisamchk} where it wrongly reset the auto_increment value.
+@item
+LOTS of patches for Linux Alpha. @strong{MySQL} now appears to be relatively
+stable on Alpha.
+@item
+Changed @code{DISTINCT} on @code{HEAP} temporary tables to use hashed
+keys to quickly find duplicated rows. This mostly concerns queries of
+type @code{SELECT DISTINCT ... GROUP BY ..}. This fixes a problem where
+not all duplicates were removed in queries of the above type. In
+addition, the new code is MUCH faster.
+@item
+Added patches to make @code{MySQL} compile on MacOS X.
+@item
+Added option @code{IF NOT EXISTS} to @code{CREATE DATABASE}.
+@item
+Added options @code{--all-databases} and @code{--databases} to @code{mysqldump}
+to allow dumping of many databases at the same time.
+@item
+Fixed bug in compressed @code{DECIMAL()} index in @code{MyISAM} tables.
+@item
+Fixed bug when storing 0 into a timestamp.
+@item
+When doing @code{mysqladmin shutdown} on a local connection, @code{mysqladmin} now
+waits until the pidfile is gone before terminating.
+@item
+Fixed core dump with some @code{COUNT(DISTINCT ...)} queries.
+@item
+Fixed that @code{myisamchk} works properly with RAID:ed tables.
+@item
+Fixed problem with @code{LEFT JOIN} and @code{key_field IS NULL}.
+@item
+Fixed bug in @code{net_clear()} which could give the error @code{Aborted
+connection} in the @strong{MySQL} clients.
+@item
+Added options @code{USE INDEX (key_list)} and @code{IGNORE INDEX (key_list)} as
+join parameters in @code{SELECT}.
+@item
+@code{DELETE} and @code{RENAME} should now work on @code{RAID} tables.
+@end itemize
+
+@node News-3.23.11, News-3.23.10, News-3.23.12, News-3.23.x
+@appendixsubsec Changes in release 3.23.11
+@itemize @bullet
+@item
+Allow the @code{ALTER TABLE tbl_name ADD (field_list)} syntax.
+@item
+Fixed problem with optimizer that could sometimes use wrong keys.
+@item
+Fixed that @code{GRANT/REVOKE ALL PRIVILEGES} doesn't affect
+@code{GRANT OPTION}.
+@item
+Removed extra @code{)} from the output of @code{SHOW GRANTS}
+@item
+Fixed problem when storing numbers in timestamps.
+@item
+Fix problem with timezones that have half hour offsets.
+@item
+Allow the syntax @code{UNIQUE INDEX} in @code{CREATE} statements.
+@item
+@code{mysqlhotcopy} - fast on-line hot-backup utility for local
+@strong{MySQL} databases. By Tim Bunce.
+@item
+New more secure @code{mysqlaccess}. Thanks to Steve Harvey for this.
+@item
+Added options @code{--i-am-a-dummy} and @code{--safe-updates} to @code{mysql}.
+@item
+Added variables @code{select_limit} and @code{max_join_size} to @code{mysql}.
+@item
+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}).
+@item
+Changed that @code{LOCK TABLES .. READ} doesn't anymore allow concurrent
+inserts.
+@item
+Added option @code{--skip-delay-key-write} to @code{mysqld}.
+@item
+Fixed security problem in the protocol regarding password checking.
+@item
+@code{_rowid} can now be used as an alias for an integer type unique indexed
+column.
+@item
+Added back blocking of @code{SIGPIPE} when compiling with @code{--thread-safe-clients}
+to make things safe for old clients.
+@end itemize
+
+@node News-3.23.10, News-3.23.9, News-3.23.11, News-3.23.x
+@appendixsubsec Changes in release 3.23.10
+@itemize @bullet
+@item
+Fixed bug in 3.23.9 where memory wasn't properly freed when doing
+@code{LOCK TABLES}.
+@end itemize
+
+@node News-3.23.9, News-3.23.8, News-3.23.10, News-3.23.x
+@appendixsubsec Changes in release 3.23.9
+@itemize @bullet
+@item
+Fixed problem that affected queries that did arithmetic on group functions.
+@item
+Fixed problem with timestamps and @code{INSERT DELAYED}.
+@item
+Fixed that @code{date_column BETWEEN const_date AND const_date} works.
+@item
+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
+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
+inside the @code{mysql} client. Original patch by Matthew Vanecek.
+@item
+Fixed critical problem with the @code{WITH GRANT OPTION} option.
+@item
+Don't give an unnecessary @code{GRANT} error when using tables from many
+databases in the same query.
+@item
+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.
+@strong{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
+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
+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
+didn't change row type from dynamic to fixed.
+@item
+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}
+@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.
+@item
+Added print of default arguments options 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.
+@item
+Fixed core dump when doing @code{WHERE key_column=RAND(...)}
+@item
+Fixed optimization 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}.
+@item
+
+@end itemize
+
+@node News-3.23.8, News-3.23.7, News-3.23.9, News-3.23.x
+@appendixsubsec Changes in release 3.23.8
+@itemize @bullet
+@item
+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.
+@item
+Fixed a bug when deleting packed keys in @code{NISAM}.
+@item
+Fixed problem with @code{ISAM} when doing some @code{ORDER BY ... DESC} queries.
+@item
+Fixed bug when doing a join on a text key which didn't cover the whole key.
+@item
+Option @code{--delay-key-write} didn't enable delayed key writing.
+@item
+Fixed update of @code{TEXT} column which only involved case changes.
+@item
+Fixed that @code{INSERT DELAYED} doesn't update timestamps that are given.
+@item
+Added function @code{YEARWEEK()} and options @code{x}, @code{X}, @code{v} and
+@code{V} to @code{DATE_FORMAT()}.
+@item
+Fixed problem with @code{MAX(indexed_column)} and HEAP tables.
+@item
+Fixed problem with @code{BLOB NULL} keys and @code{LIKE} "prefix%".
+@item
+Fixed problem with @code{MyISAM} and fixed length rows < 5 bytes.
+@item
+Fixed problem that could cause @strong{MySQL} to touch freed memory when
+doing very complicated @code{GROUP BY} queries.
+@item
+Fixed core dump if you got a crashed table where an @code{ENUM} field value
+was too big.
+@end itemize
+
+@node News-3.23.7, News-3.23.6, News-3.23.8, News-3.23.x
+@appendixsubsec Changes in release 3.23.7
+@itemize @bullet
+@item
+Fixed workaround under Linux to avoid problems with @code{pthread_mutex_timedwait},
+which is used with @code{INSERT DELAYED}. @xref{Linux}.
+@item
+Fixed that one will get a 'disk full' error message if one gets disk full
+when doing sorting (instead of waiting until we got more disk space).
+@item
+Fixed a bug in @code{MyISAM} with keys > 250 characters.
+@item
+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
+@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}.
+@item
+The following functions are now multi-byte-safe:
+@code{LOCATE(substr,str)}, @code{POSITION(substr IN str)},
+@code{LOCATE(substr,str,pos)}, @code{INSTR(str,substr)},
+@code{LEFT(str,len)}, @code{RIGHT(str,len)},
+@code{SUBSTRING(str,pos,len)}, @code{SUBSTRING(str FROM pos FOR len)},
+@code{MID(str,pos,len)}, @code{SUBSTRING(str,pos)}, @code{SUBSTRING(str
+FROM pos)}, @code{SUBSTRING_INDEX(str,delim,count)}, @code{RTRIM(str)},
+@code{TRIM([[BOTH | TRAILING] [remstr] FROM] str)},
+@code{REPLACE(str,from_str,to_str)}, @code{REVERSE(str)},
+@code{INSERT(str,pos,len,newstr)}, @code{LCASE(str)}, @code{LOWER(str)},
+@code{UCASE(str)} and @code{UPPER(str)}; Patch by Wei He.
+@item
+Fix core dump when releasing a lock from a non-existant table.
+@item
+Remove locks on tables before starting to remove duplicates.
+@item
+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.
+@item
+Fixed bug in 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}.
+@item
+Changed the argument to @code{mysql_data_seek()} from @code{ulong} to
+@code{ulonglong}.
+@end itemize
+
+@node News-3.23.6, News-3.23.5, News-3.23.7, News-3.23.x
+@appendixsubsec Changes in release 3.23.6
+
+@itemize @bullet
+@item
+Added @code{mysqld} option @code{-O lower_case_table_names=@{0|1@}} to allow
+users to force table names to lower case.
+@item
+Added @code{SELECT ... INTO DUMPFILE}.
+@item
+Added mysqld option @code{--ansi} to make some functions @code{ANSI SQL}
+compatible.
+@item
+Temporary tables now starts 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
+overflows on FreeBSD.
+@item
+Made @code{[floor()} overflow safe on FreeBSD.
+@item
+Added option @code{--quote-names} to @code{mysqldump}
+@item
+Fixed bug that one could make a part of a @code{PRIMARY KEY NOT NULL}.
+@item
+Fixed @code{encrypt()} to be thread safe and not reuse buffer.
+@item
+Added @code{mysql_odbc_escape_string()} function to support big5 characters in
+MyOBC.
+@item
+Rewrote the table handler to use classes. This introduces a lot of new code,
+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.
+@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.
+@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}.
+@item
+Added option @code{ROW_FORMAT=@{default | dynamic | static | compressed@}} to
+@code{CREATE_TABLE}.
+@item
+@code{DELETE FROM table_name} didn't work on temporary tables.
+@item
+Changed function @code{CHAR_LENGTH()} to be multi-byte character safe.
+@item
+Added function @code{ORD(string)}.
+@end itemize
+
+@node News-3.23.5, News-3.23.4, News-3.23.6, News-3.23.x
+@appendixsubsec Changes in release 3.23.5
+
+@itemize @bullet
+@item
+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.
+@item
+Fixed cache overflow problem when using full joins without keys.
+@item
+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.
+@item
+Fixed problem when using an auto_increment column in two keys
+@item
+One can now with MyISAM have the auto_increment part as a 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}.
+@item
+@code{AS} on fieldname with @code{CREATE TABLE table_name SELECT ...} didn't
+work.
+@item
+Allow use of @code{NATIONAL} and @code{NCHAR} when defining character columns.
+This is the same as not using @code{BINARY}.
+@item
+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:
+@code{WHERE auto_increment_column IS NULL}. This seems to fix some problems
+with Access.
+@item
+@code{SET SQL_AUTO_IS_NULL=0|1} now turns on/off the handling of
+searching after the last inserted row with @code{WHERE
+auto_increment_column IS NULL}.
+@item
+Added new @code{mysqld} variable @code{concurrency} for Solaris.
+@item
+Added option @code{--relative} 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.
+@item
+Added support for the Chinese character set GBK.
+@item
+Fixed problem with @code{LOAD DATA INFILE} and @code{BLOB} columns.
+@item
+Added bit operator @code{~} (negation).
+@item
+Fixed problem with @code{UDF} functions.
+@end itemize
+
+@node News-3.23.4, News-3.23.3, News-3.23.5, News-3.23.x
+@appendixsubsec Changes in release 3.23.4
+
+@itemize @bullet
+@item
+Inserting a @code{DATETIME} into a @code{TIME} column will not anymore
+try to store 'days' in it.
+@item
+Fixed problem with storage of float/double on little endian machines.
+(This affected @code{SUM()}.)
+@item
+Added connect timeout on TCP/IP connections.
+@item
+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
+privileges to other users.
+@item
+New command: @code{SHOW GRANTS FOR user} (by Sinisa).
+@item
+New @code{date_add} syntax: @code{date/datetime + INTERVAL # interval_type}.
+By Joshua Chamas.
+@item
+Fixed privilege check for @code{LOAD DATA REPLACE}.
+@item
+Automatic fixing of broken include files on Solaris 2.7
+@item
+Some configure issues to fix problems with big file system detection.
+@item
+@code{REGEXP} is now case insensitive if you use non-binary strings.
+@end itemize
+
+@node News-3.23.3, News-3.23.2, News-3.23.4, News-3.23.x
+@appendixsubsec Changes in release 3.23.3
+
+@itemize @bullet
+Added patches for MIT-pthreads on NetBSD.
+@item
+Fixed range bug in 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()}.
+@item
+Added character set to @code{SHOW VARIABLES}.
+@item
+Added support of @code{--[whitespace]} comments.
+@item
+Allow @code{INSERT into tbl_name VALUES ()}, that is, you may now specify
+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).
+@item
+@code{SUM(..)} with @code{GROUP BY} returned 0 on some systems.
+@item
+Changed output for @code{SHOW TABLE STATUS}.
+@item
+Added @code{DELAY_KEY_WRITE} option to @code{CREATE TABLE}.
+@item
+Allow @code{AUTO_INCREMENT} on any key part.
+@item
+Fixed problem with @code{YEAR(NOW())} and @code{YEAR(CURDATE())}.
+@item
+Added @code{CASE} construct.
+@item
+New function @code{COALESCE()}.
+@end itemize
+
+@node News-3.23.2, News-3.23.1, News-3.23.3, News-3.23.x
+@appendixsubsec Changes in release 3.23.2
+
+@itemize @bullet
+@item
+Fixed range optimizer 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.
+@item
+@code{SET SQL_LOW_PRIORITY_UPDATES=1} gave parse error before.
+@item
+You can now update indexes 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)
+@item
+Fixed optimization 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.
+@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.
+@item
+The following join is now much faster:
+@code{SELECT ... FROM t1 LEFT JOIN t2 ON ... WHERE t2.not_null_column IS NULL}.
+@item
+@code{ORDER BY} and @code{GROUP BY} can be done on functions.
+@item
+Changed handling of 'const_item' to allow handling of @code{ORDER BY RAND()}.
+@item
+Indexes are now used for @code{WHERE key_column = function}.
+@item
+Indexes are now used for @code{WHERE key_column = column_name} even if
+the columns are not identically packed.
+@item
+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)
+@item
+Automatic change of HEAP temporary tables to MyISAM tables in case of
+'table is full' errors.
+@item
+Added option @code{--init-file=file_name} to @code{mysqld}.
+@item
+@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.
+@item
+New reserved words (required for @code{CASE}): @code{CASE, THEN, WHEN, ELSE and END}.
+@item
+New functions @code{EXPORT_SET()} and @code{MD5()}.
+@item
+Support for the GB2312 Chinese character set.
+@end itemize
+
+@node News-3.23.1, News-3.23.0, News-3.23.2, News-3.23.x
+@appendixsubsec Changes in release 3.23.1
+
+@itemize @bullet
+@item
+Fixed some compilation problems.
+@end itemize
+
+@node News-3.23.0, , News-3.23.1, News-3.23.x
+@appendixsubsec Changes in release 3.23.0
+
+@itemize @bullet
+A new table handler library (@code{MyISAM}) with a lot of new features.
+@xref{MyISAM}.
+@item
+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.
+@item
+New function @code{LOAD_FILE(filename)} to get the contents of a file as a
+string value.
+@item
+New operator @code{<=>} which will act as @code{=} but will return TRUE
+if both arguments are @code{NULL}. This is useful for comparing changes
+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
+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'} is now true.
+@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}.
+@item
+Added columns @code{packed} and @code{comment} to @code{SHOW INDEX}.
+@item
+Added comments to tables (with @code{CREATE TABLE ... COMMENT "xxx"}).
+@item
+Added @code{UNIQUE}, as in
+@code{CREATE TABLE table_name (col int not null UNIQUE)}
+@item
+New create syntax: @code{CREATE TABLE table_name SELECT ....}
+@item
+New create syntax: @code{CREATE TABLE IF NOT EXISTS ...}
+@item
+Allow creation of @code{CHAR(0)} columns.
+@item
+@code{DATE_FORMAT()} now requires @samp{%} before any format character.
+@item
+@code{DELAYED} is now a reserved word (sorry about that :( ).
+@item
+An example procedure is added: @code{analyse}, file: @file{sql_analyse.c}.
+This will describe the data in your query. Try the following:
+@example
+SELECT ... FROM ... WHERE ... PROCEDURE ANALYSE([max elements,[max memory]])
+@end example
+
+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.
+@item
+Added option @code{--skip-show-database} to @code{mysqld}.
+@item
+Check if 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 @strong{MySQL} 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}).
+@item
+@code{NULL IN (...)} now returns @code{NULL} instead of @code{0}. This will
+ensure that @code{null_column NOT IN (...)} doesn't match
+@code{NULL} values.
+@item
+Fix storage of floating point values in @code{TIME} columns.
+@item
+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
+@item [[DAYS] [H]H:]MM:]SS[.fraction]
+@item [[[[[H]H]H]H]MM]SS[.fraction]
+@end table
+@item
+Detect (and ignore) second fraction 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.
+@item
+Changed default number of connections to 100.
+@item
+Use bigger buffers when using @code{LOAD DATA INFILE}.
+@item
+@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!
+@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.
+@item
+@code{SELECT DISTINCT} is much faster; It uses the new @code{UNIQUE}
+functionality in @code{MyISAM}. One difference compared to @strong{MySQL} 3.22
+is that the output of @code{DISTINCT} is not sorted anymore.
+@item
+All C client API macros are now functions to make shared libraries more
+reliable. Because of this, you can no longer call @code{mysql_num_fields()} on
+a @code{MYSQL} object, you must use @code{mysql_field_count()} instead.
+@item
+Added use of @code{LIBEWRAP}; Patch by Henning P . Schmiedehausen.
+@item
+Don't allow @code{AUTO_INCREMENT} for other than numerical columns.
+@item
+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.
+@item
+Added @code{SQL_BIG_RESULT}; @code{SQL_SMALL_RESULT} is now default.
+@item
+Added a shared library RPM. This enchancement was contributed by David
+Fox (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
+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}.
+@end itemize
+
+@node News-3.22.x, News-3.21.x, News-3.23.x, News
+@appendixsec Changes in release 3.22.x
+
+The 3.22 version has faster and safer connect code and a lot of new nice
+enhancements. The reason for not including these changes in the 3.21 version
+is mainly that we are trying to avoid big changes to 3.21 to keep it as
+stable as possible. As there aren't really any MAJOR changes, upgrading to
+3.22 should be very easy and painless.
+@xref{Upgrading-from-3.21}.
+
+3.22 should also be used with the new @code{DBD-mysql} (1.20xx) driver
+that can use the new connect protocol!
+
+@menu
+* News-3.22.35:: Changes in release 3.22.35
+* News-3.22.34:: Changes in release 3.22.34
+* News-3.22.33:: Changes in release 3.22.33
+* News-3.22.32:: Changes in release 3.22.32
+* News-3.22.31:: Changes in release 3.22.31
+* News-3.22.30:: Changes in release 3.22.30
+* News-3.22.29:: Changes in release 3.22.29
+* News-3.22.28:: Changes in release 3.22.28
+* News-3.22.27:: Changes in release 3.22.27
+* News-3.22.26:: Changes in release 3.22.26
+* News-3.22.25:: Changes in release 3.22.25
+* News-3.22.24:: Changes in release 3.22.24
+* News-3.22.23:: Changes in release 3.22.23
+* News-3.22.22:: Changes in release 3.22.22
+* News-3.22.21:: Changes in release 3.22.21
+* News-3.22.20:: Changes in release 3.22.20
+* News-3.22.19:: Changes in release 3.22.19
+* News-3.22.18:: Changes in release 3.22.18
+* News-3.22.17:: Changes in release 3.22.17
+* News-3.22.16:: Changes in release 3.22.16
+* News-3.22.15:: Changes in release 3.22.15
+* News-3.22.14:: Changes in release 3.22.14
+* News-3.22.13:: Changes in release 3.22.13
+* News-3.22.12:: Changes in release 3.22.12
+* News-3.22.11:: Changes in release 3.22.11
+* News-3.22.10:: Changes in release 3.22.10
+* News-3.22.9:: Changes in release 3.22.9
+* News-3.22.8:: Changes in release 3.22.8
+* News-3.22.7:: Changes in release 3.22.7
+* News-3.22.6:: Changes in release 3.22.6
+* News-3.22.5:: Changes in release 3.22.5
+* News-3.22.4:: Changes in release 3.22.4
+* News-3.22.3:: Changes in release 3.22.3
+* News-3.22.2:: Changes in release 3.22.2
+* News-3.22.1:: Changes in release 3.22.1
+* News-3.22.0:: Changes in release 3.22.0
+@end menu
+
+@node News-3.22.35, News-3.22.34, News-3.22.x, News-3.22.x
+@appendixsubsec Changes in release 3.22.35
+@itemize @bullet
+@item
+Fixed problem with @code{STD()}.
+@item
+Merged changes from the newest @code{ISAM} library from 3.23.
+@item
+Fixed problem with @code{INSERT DELAYED}.
+@item
+Fixed a bug core dump when using a @code{LEFT JOIN}/@code{STRAIGHT_JOIN}
+on a table with only one row.
+@end itemize
+
+@node News-3.22.34, News-3.22.33, News-3.22.35, News-3.22.x
+@appendixsubsec Changes in release 3.22.34
+@itemize @bullet
+@item
+Fixed problem with @code{GROUP BY} on @code{TINYBLOB} columns; This
+caused bugzilla to not show rows in some queries.
+@item
+Had to do total recompile of the Windows binary version as VC++ didn't
+compile all relevant files for 3.22.33 :(
+@end itemize
+
+@node News-3.22.33, News-3.22.32, News-3.22.34, News-3.22.x
+@appendixsubsec Changes in release 3.22.33
+@itemize @bullet
+@item
+Fixed problems in windows when locking tables with @code{LOCK TABLE}
+@item
+Quicker kill of @code{SELECT DISTINCT} queries.
+@end itemize
+
+@node News-3.22.32, News-3.22.31, News-3.22.33, News-3.22.x
+@appendixsubsec Changes in release 3.22.32
+@itemize @bullet
+@item
+Fixed problem when storing numbers in timestamps.
+@item
+Fix problem with timezones that have half hour offsets.
+@item
+@code{mysqlhotcopy} - fast on-line hot-backup utility for local @strong{MySQL}
+databases. By Tim Bunce.
+@item
+New more secure @code{mysqlaccess}. Thanks to Steve Harvey for this.
+@item
+Fixed security problem in the protocol regarding password checking.
+@item
+Fixed problem that affected queries that did arithmetic on @code{GROUP} functions.
+@item
+Fixed a bug in the @code{ISAM} code when deleting rows on tables with
+packed indexes.
+@end itemize
+
+@node News-3.22.31, News-3.22.30, News-3.22.32, News-3.22.x
+@appendixsubsec Changes in release 3.22.31
+
+@itemize @bullet
+@item
+A few small fixes for the Win32 version.
+@end itemize
+
+
+@node News-3.22.30, News-3.22.29, News-3.22.31, News-3.22.x
+@appendixsubsec Changes in release 3.22.30
+
+@itemize @bullet
+@item
+Fixed optimizer 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))}.
+@item
+Added print of default arguments options to all clients.
+@item
+Fixed critical problem with the @code{WITH GRANT OPTION} option.
+@item
+Fixed non-critical Y2K problem when writing short date to log files.
+@end itemize
+
+@node News-3.22.29, News-3.22.28, News-3.22.30, News-3.22.x
+@appendixsubsec Changes in release 3.22.29
+
+@itemize @bullet
+@item
+Upgraded the configure and include files to match the latest 3.23 version.
+This should increase portability and make it easier to build shared libraries.
+@item
+Added latest patches to mit-pthreads for NetBSD.
+@item
+Fixed problem with timezones that are < GMT -11.
+@item
+Fixed a bug when deleting packed keys in NISAM.
+@item
+Fixed problem that could cause @strong{MySQL} to touch freed memory when
+doing very complicated @code{GROUP BY} queries.
+@item
+Fixed core dump if you got a crashed table where an @code{ENUM} field value
+was too big.
+@item
+Added @code{mysqlshutdown.exe} and @code{mysqlwatch.exe} to the Windows
+distribution.
+@item
+Fixed problem when doing @code{ORDER BY} on a reference key.
+@item
+Fixed that @code{INSERT DELAYED} doesn't update timestamps that are given.
+
+@end itemize
+
+@node News-3.22.28, News-3.22.27, News-3.22.29, News-3.22.x
+@appendixsubsec Changes in release 3.22.28
+
+@itemize @bullet
+@item
+Fixed problem with @code{LEFT JOIN} and @code{COUNT()} on a column which
+was declared @code{NULL} + and it had a @code{DEFAULT} value.
+@item
+Fixed core dump problem when using @code{CONCAT()} in a @code{WHERE} clause.
+@item
+Fixed problem with @code{AVG()} and @code{STD()} with @code{NULL} values.
+@end itemize
+
+@node News-3.22.27, News-3.22.26, News-3.22.28, News-3.22.x
+@appendixsubsec Changes in release 3.22.27
+
+@itemize @bullet
+@item
+Fixed prototype in @file{my_ctype.h} when using other character sets.
+@item
+Some configure issues to fix problems with big file system detection.
+@item
+Fixed problem when sorting on big blob columns.
+@item
+@code{ROUND()} will now work on Win32.
+@end itemize
+
+@node News-3.22.26, News-3.22.25, News-3.22.27, News-3.22.x
+@appendixsubsec Changes in release 3.22.26
+
+@itemize @bullet
+@item
+Fixed core dump with empty @code{BLOB/TEXT} column to @code{REVERSE()}.
+@item
+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).
+@item
+Fixed problem with @code{LOCK TABLES} combined with @code{DELETE FROM table}
+@item
+Fixed problem that INSERT ... SELECT didn't use SQL_BIG_TABLES.
+@item
+@code{SET SQL_LOW_PRIORITY_UPDATES=#} didn't work.
+@item
+Password wasn't updated correctly if privileges didn't change on:
+@code{GRANT ... IDENTIFIED BY}
+@item
+Fixed range optimizer 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.
+@end itemize
+
+@node News-3.22.25, News-3.22.24, News-3.22.26, News-3.22.x
+@appendixsubsec Changes in release 3.22.25
+
+@itemize @bullet
+@item
+Fixed some small problems with the installation.
+@end itemize
+
+@node News-3.22.24, News-3.22.23, News-3.22.25, News-3.22.x
+@appendixsubsec Changes in release 3.22.24
+
+@itemize @bullet
+@item
+@code{DATA} is not a reserved word anymore.
+@item
+Fixed optimizer bug with tables with only one row.
+@item
+Fixed bug when using @code{LOCK TABLES table_name READ; FLUSH TABLES;}
+@item
+Applied some patches for HP-UX.
+@item
+@code{isamchk} should now work on Win32.
+@item
+Changed @file{configure} to not use big file handling on Linux as this
+crashes some RedHat 6.0 systems
+@end itemize
+
+@node News-3.22.23, News-3.22.22, News-3.22.24, News-3.22.x
+@appendixsubsec Changes in release 3.22.23
+
+@itemize @bullet
+@item
+Upgraded to use Autoconf 2.13, Automake 1.4 and @code{libtool} 1.3.2.
+@item
+Better support for SCO in @code{configure}.
+@item
+Added option @code{--defaults-file=###} to option file handling to force use
+of only one specific option file.
+@item
+Extended @code{CREATE} syntax to ignore @strong{MySQL} 3.23 keywords.
+@item
+Fixed deadlock problem when using @code{INSERT DELAYED} on a table locked with
+@code{LOCK TABLES}.
+@item
+Fixed deadlock problem when using @code{DROP TABLE} on a table that was
+locked by another thread.
+@item
+Add logging of @code{GRANT/REVOKE} commands in the update log.
+@item
+Fixed @code{isamchk} to detect a new error condition.
+@item
+Fixed bug in @code{NATURAL LEFT JOIN}.
+@end itemize
+
+@node News-3.22.22, News-3.22.21, News-3.22.23, News-3.22.x
+@appendixsubsec Changes in release 3.22.22
+
+@itemize @bullet
+@item
+Fixed problem in the C API when you called @code{mysql_close()} directly after
+@code{mysql_init()}.
+@item
+Better client error message when you can't open socket.
+@item
+Fixed @code{delayed_insert_thread} counting when you couldn't create a new
+delayed_insert thread.
+@item
+Fixed bug in @code{CONCAT()} with many arguments.
+@item
+Added patches for DEC 3.2 and SCO.
+@item
+Fixed path-bug when installing @strong{MySQL} as a service on NT.
+@item
+The @strong{MySQL}-Win32 version is now compiled with VC++ 6.0 instead of
+with VC++ 5.0.
+@item
+New installation setup for @strong{MySQL}-Win32.
+@end itemize
+
+@node News-3.22.21, News-3.22.20, News-3.22.22, News-3.22.x
+@appendixsubsec Changes in release 3.22.21
+
+@itemize @bullet
+@item
+Fixed problem with @code{DELETE FROM TABLE} when table was locked by
+another thread.
+@item
+Fixed bug in @code{LEFT JOIN} involving empty tables.
+@item
+Changed the @code{mysql.db} column from @code{char(32)} to @code{char(60)}.
+@item
+@code{MODIFY} and @code{DELAYED} are not reserved words anymore.
+@item
+Fixed a bug when storing days in a @code{TIME} column.
+@item
+Fixed a problem with @code{Host '..' is not allowed to connect to this MySQL
+server} after one had inserted a new @strong{MySQL} user with a @code{GRANT}
+command.
+@item
+Changed to use @code{TCP_NODELAY} also on Linux (Should give faster TCP/IP
+connections).
+@end itemize
+
+@node News-3.22.20, News-3.22.19, News-3.22.21, News-3.22.x
+@appendixsubsec Changes in release 3.22.20
+
+@itemize @bullet
+@item
+Fixed @code{STD()} for big tables when result should be 0.
+@item
+The update log didn't have newlines on some operating systems.
+@item
+@code{INSERT DELAYED} had some garbage at end in the update log.
+@end itemize
+
+@node News-3.22.19, News-3.22.18, News-3.22.20, News-3.22.x
+@appendixsubsec Changes in release 3.22.19
+
+@itemize @bullet
+@item
+Fixed bug in @code{mysql_install_db} (from 3.22.17).
+@item
+Changed default key cache size to 8M.
+@item
+Fixed problem with queries that needed temporary tables with @code{BLOB}
+columns.
+@end itemize
+
+@node News-3.22.18, News-3.22.17, News-3.22.19, News-3.22.x
+@appendixsubsec Changes in release 3.22.18
+
+@itemize @bullet
+@item
+Fixes a fatal problem in 3.22.17 on Linux; After @code{shutdown}
+all threads didn't die properly.
+@item
+Added option @code{-O flush_time=#} to @code{mysqld}. This is mostly
+useful on Win32 and tells how often @strong{MySQL} should close all
+unused tables and flush all updated tables to disk.
+@item
+Fixed problem that a @code{VARCHAR} column compared with @code{CHAR} column
+didn't use keys efficiently.
+@end itemize
+
+@node News-3.22.17, News-3.22.16, News-3.22.18, News-3.22.x
+@appendixsubsec Changes in release 3.22.17
+
+@itemize @bullet
+@item
+Fixed a core dump problem when using @code{--log-update} and connecting
+without a default database.
+@item
+Fixed some @code{configure} and portability problems.
+@item
+Using @code{LEFT JOIN} on tables that had circular dependencies caused
+@code{mysqld} to hang forever.
+@end itemize
+
+@node News-3.22.16, News-3.22.15, News-3.22.17, News-3.22.x
+@appendixsubsec Changes in release 3.22.16
+
+@itemize @bullet
+@item
+@code{mysqladmin processlist} could kill the server if a new user logged in.
+@item
+@code{DELETE FROM tbl_name WHERE key_column=col_name} didn't find any matching
+rows. Fixed.
+@item
+@code{DATE_ADD(column,...)} didn't work.
+@item
+@code{INSERT DELAYED} could deadlock with status 'upgrading lock'
+@item
+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.
+@item
+Added the @code{MODIFY} keyword to @code{ALTER TABLE}.
+@end itemize
+
+@node News-3.22.15, News-3.22.14, News-3.22.16, News-3.22.x
+@appendixsubsec Changes in release 3.22.15
+
+@itemize @bullet
+@item
+@code{GRANT} used with @code{IDENTIFIED BY} didn't take effect until privileges
+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
+were multiple key definitions for a used column.
+@item
+@code{DATE} and @code{DATETIME} columns are now up to 5 times faster than
+before.
+@item
+@code{INSERT DELAYED} can be used to let the client do other things while the
+server inserts rows into a table.
+@item
+@code{LEFT JOIN USING (col1,col2)} didn't work if one used it with tables
+from 2 different databases.
+@item
+@code{LOAD DATA LOCAL INFILE} didn't work in the Unix version because of
+a missing file.
+@item
+Fixed problems with @code{VARCHAR}/@code{BLOB} on very short rows (< 4 bytes);
+error 127 could occur when deleting rows.
+@item
+Updating @code{BLOB/TEXT} through formulas didn't work for short (< 256 char)
+strings.
+@item
+When you did a @code{GRANT} on a new host, @code{mysqld} could die on the first
+connect from this host.
+@item
+Fixed bug when one used @code{ORDER BY} on column name that was the same
+name as an alias.
+@item
+Added @code{BENCHMARK(loop_count,expression)} function to time expressions.
+@end itemize
+
+@node News-3.22.14, News-3.22.13, News-3.22.15, News-3.22.x
+@appendixsubsec Changes in release 3.22.14
+
+@itemize @bullet
+@item
+Allow empty arguments to @code{mysqld} to make it easier to start from shell
+scripts.
+@item
+Setting a @code{TIMESTAMP} column to @code{NULL} didn't record the timestamp
+value in the update log.
+@item
+Fixed lock handler bug when one did
+@code{INSERT INTO TABLE ... SELECT ... GROUP BY}.
+@item
+Added a patch for @code{localtime_r()} on Win32 so that it will not crash
+anymore if your date is > 2039, but instead will return a time of all zero.
+@item
+Names for
+user-defined functions are no longer case sensitive.
+@item
+Added escape of @code{^Z} (ASCII 26) to @code{\Z} as @code{^Z} doesn't
+work with pipes on Win32.
+@item
+@code{mysql_fix_privileges} adds a new column to the @code{mysql.func} to
+support aggregate UDF functions in future @strong{MySQL} releases.
+@end itemize
+
+@node News-3.22.13, News-3.22.12, News-3.22.14, News-3.22.x
+@appendixsubsec Changes in release 3.22.13
+
+@itemize @bullet
+@item
+Saving @code{NOW()}, @code{CURDATE()} or @code{CURTIME()} directly in a
+column didn't work.
+@item
+@code{SELECT COUNT(*) ... LEFT JOIN ...} didn't work with no @code{WHERE} part.
+@item
+Updated @file{config.guess} to allow @strong{MySQL} to configure on
+UnixWare 7.0.x.
+@item
+Changed the implementation of @code{pthread_cond()} on the Win32 version.
+@code{get_lock()} now correctly times out on Win32!
+@end itemize
+
+@node News-3.22.12, News-3.22.11, News-3.22.13, News-3.22.x
+@appendixsubsec Changes in release 3.22.12
+
+@itemize @bullet
+@item
+Fixed problem when using @code{DATE_ADD()} and @code{DATE_SUB()} in a
+@code{WHERE} clause.
+@item
+You can now set the password for a user with the @code{GRANT ... TO user
+IDENTIFIED BY 'password'} syntax.
+@item
+Fixed bug in @code{GRANT} checking with @code{SELECT} on many tables.
+@item
+Added missing file @code{mysql_fix_privilege_tables} to the RPM
+distribution. This is not run by default because it relies on the client
+package.
+@item
+Added option @code{SQL_SMALL_RESULT} to @code{SELECT} to force use of
+fast temporary tables when you know that the result set will be small.
+@item
+Allow use of negative real numbers without a decimal point.
+@item
+Day number is now adjusted to maximum days in month if the resulting month
+after @code{DATE_ADD}/@code{DATE_SUB()} doesn't have enough days.
+@item
+Fix that @code{GRANT} compares columns in case-insensitive fashion.
+@item
+Fixed a bug in @file{sql_list.h} that made @code{ALTER TABLE} dump core in
+some contexts.
+@item
+The hostname in @code{user@@hostname} can now include @samp{.} and @samp{-}
+without quotes in the context of the @code{GRANT}, @code{REVOKE} and
+@code{SET PASSWORD FOR ...} statements.
+@item
+Fix for @code{isamchk} for tables which need big temporary files.
+@end itemize
+
+@node News-3.22.11, News-3.22.10, News-3.22.12, News-3.22.x
+@appendixsubsec Changes in release 3.22.11
+
+@itemize @bullet
+@item
+@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
+@code{DROP INDEX}.
+@item
+@code{GRANT} to allow/deny users table and column access.
+@item
+Changed @code{USER()} to return @code{user@@host}
+@item
+Changed the syntax for how to set @code{PASSWORD} for another user.
+@item
+New command @code{FLUSH STATUS} that sets most status variables to zero.
+@item
+New status variables: @code{aborted_threads}, @code{aborted_connects}.
+@item
+New option variable: @code{connection_timeout}.
+@item
+Added support for Thai sorting (by Pruet Boonma
+@email{pruet@@ds90.intanon.nectec.or.th}).
+@item
+Slovak and japanese error messages.
+@item
+Configuration and portability fixes.
+@item
+Added option @code{SET SQL_WARNINGS=1} to get a warning count also for simple
+inserts.
+@item
+@strong{MySQL} now uses @code{SIGTERM} instead of @code{SIGQUIT} with
+shutdown to work better on FreeBSD.
+@item
+Added option @code{\G} (print vertically) to @code{mysql}.
+@item
+@code{SELECT HIGH_PRIORITY} ... killed @code{mysqld}.
+@item
+@code{IS NULL} on a @code{AUTO_INCREMENT} column in a @code{LEFT JOIN} didn't
+work as expected.
+@item
+New function @code{MAKE_SET()}.
+@end itemize
+
+@node News-3.22.10, News-3.22.9, News-3.22.11, News-3.22.x
+@appendixsubsec Changes in release 3.22.10
+
+@itemize @bullet
+@item
+@code{mysql_install_db} no longer starts the @strong{MySQL} server! You
+should start @code{mysqld} with @code{safe_mysqld} after installing it! The
+@strong{MySQL} RPM will however start the server as before.
+@item
+Added @code{--bootstrap} option to @code{mysqld} and recoded
+@code{mysql_install_db} to use it. This will make it easier to install
+@strong{MySQL} with RPMs.
+@item
+Changed @code{+}, @code{-} (sign and minus), @code{*}, @code{/}, @code{%},
+@code{ABS()} and @code{MOD()} to be @code{BIGINT} aware (64-bit safe).
+@item
+Fixed a bug in @code{ALTER TABLE} that caused @code{mysqld} to crash.
+@item
+@strong{MySQL} now always reports the conflicting key values when a
+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
+Most errors in the @file{.err} log are now prefixed with a time stamp.
+@item
+Added option @code{MYSQL_INIT_COMMAND} to @code{mysql_options()} to make
+a query on connect or reconnect.
+@item
+Added option @code{MYSQL_READ_DEFAULT_FILE} and
+@code{MYSQL_READ_DEFAULT_GROUP} to @code{mysql_options()} to read the
+following parameters from the @strong{MySQL} option files: @code{port},
+@code{socket}, @code{compress}, @code{password}, @code{pipe}, @code{timeout},
+@code{user}, @code{init-command}, @code{host} and @code{database}.
+@item
+Added @code{maybe_null} to the UDF structure.
+@item
+Added option @code{IGNORE} to @code{INSERT} statemants 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
+a @code{CHAR} or @code{VARCHAR} column.
+@item
+New script @code{mysql_setpermission}, by Luuk de Boer, allows one
+to easily create new users with permissions for specific databases.
+@item
+Allow use of hexadecimal strings (0x...) when specifying a constant string
+(like in the column separators with @code{LOAD DATA INFILE}).
+@item
+Ported to OS/2 (thanks to Antony T. Curtis @email{antony.curtis@@olcs.net}).
+@item
+Added more variables to @code{SHOW STATUS} and changed format of output to
+be like @code{SHOW VARIABLES}.
+@item
+Added @code{extended-status} command to @code{mysqladmin} which will show the
+new status variables.
+@end itemize
+
+@node News-3.22.9, News-3.22.8, News-3.22.10, News-3.22.x
+@appendixsubsec Changes in release 3.22.9
+
+@itemize @bullet
+@item
+@code{SET SQL_LOG_UPDATE=0} caused a lockup of the server.
+@item
+New SQL command: @code{FLUSH [ TABLES | HOSTS | LOGS | PRIVILEGES ] [, ...]}
+@item
+New SQL command: @code{KILL} @code{thread_id}.
+@item
+Added casts and changed include files to make @strong{MySQL} easier to
+compile on AIX and DEC OSF1 4.x
+@item
+Fixed conversion problem when using @code{ALTER TABLE} from a @code{INT}
+to a short @code{CHAR()} column.
+@item
+Added @code{SELECT HIGH_PRIORITY}; This will get a lock for the
+@code{SELECT} even if there is a thread waiting for another
+@code{SELECT} to get a @code{WRITE LOCK}.
+@item
+Moved wild_compare to string class to be able to use @code{LIKE} on
+@code{BLOB}/@code{TEXT} columns with @code{\0}.
+@item
+Added @code{ESCAPE} option to @code{LIKE}.
+@item
+Added a lot more output to @code{mysqladmin debug}.
+@item
+You can now start @code{mysqld} on Win32 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.
+@end itemize
+
+@node News-3.22.8, News-3.22.7, News-3.22.9, News-3.22.x
+@appendixsubsec Changes in release 3.22.8
+
+@itemize @bullet
+@item
+Czech character sets should now work much better. You must also install
+@uref{http://www.mysql.com/Downloads/Patches/czech-3.22.8-patch}.
+This patch should also be installed if you are using a character set with
+uses @code{my_strcoll()}! The patch should always be safe to install (for any system),
+but as this patch changes ISAM internals it's not yet in the default
+distribution.
+@item
+@code{DATE_ADD()} and @code{DATE_SUB()} didn't work with group functions.
+@item
+@code{mysql} will now also try to reconnect on @code{USE DATABASE} commands.
+@item
+Fix problem with @code{ORDER BY} and @code{LEFT JOIN} and @code{const} tables.
+@item
+Fixed problem with @code{ORDER BY} if the first @code{ORDER BY} column
+was a key and the rest of the @code{ORDER BY} columns wasn't part of the key.
+@item
+Fixed a big problem with @code{OPTIMIZE TABLE}.
+@item
+@strong{MySQL} clients on NT will now by default first try to connect with
+named pipes and after this with TCP/IP.
+@item
+Fixed a problem with @code{DROP TABLE} and @code{mysqladmin shutdown} on Win32
+(a fatal bug from 3.22.6).
+@item
+Fixed problems with @code{TIME columns} and negative strings.
+@item
+Added an extra thread signal loop on shutdown to avoid some error messages
+from the client.
+@item
+@strong{MySQL} now uses the next available number as extension for the update
+log file.
+@item
+Added patches for UNIXWARE 7.
+@end itemize
+
+@node News-3.22.7, News-3.22.6, News-3.22.8, News-3.22.x
+@appendixsubsec Changes in release 3.22.7
+
+@itemize @bullet
+@item
+Added @code{LIMIT} clause for the @code{DELETE} statement.
+@item
+You can now use the @code{/*! ... */} syntax to hide @strong{MySQL}-specific
+keywords when you write portable code. @strong{MySQL} will parse the code
+inside the comments as if the surrounding @code{/*!} and @code{*/} comment
+characters didn't exist.
+@item
+@code{OPTIMIZE TABLE tbl_name} can now be used to reclaim disk space
+after many deletes. Currently, this uses @code{ALTER TABLE} to
+re-generate the table, but in the future it will use an integrated
+@code{isamchk} for more speed.
+@item
+Upgraded @code{libtool} to get the configure more portable.
+@item
+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
+and when using keys.
+@item
+You can now use @code{mysqladmin proc} to display information about your own
+threads. Only users with the @strong{Process_priv} privilege can get
+information about all threads.
+@item
+Added handling of formats @code{YYMMDD}, @code{YYYYMMDD},
+@code{YYMMDDHHMMSS} for numbers when using @code{DATETIME} and
+@code{TIMESTAMP} types. (Formerly these formats only worked with strings.)
+@item
+Added connect option @code{CLIENT_IGNORE_SPACE} to allow use of spaces
+after function names and before @samp{(} (Powerbuilder requires this).
+This will make all function names reserved words.
+@item
+Added the @code{--log-long-format} option to @code{mysqld} to enable timestamps
+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
+statements.
+@end itemize
+
+@node News-3.22.6, News-3.22.5, News-3.22.7, News-3.22.x
+@appendixsubsec Changes in release 3.22.6
+
+@itemize @bullet
+@item
+Faster @code{mysqldump}.
+@item
+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.
+@item
+Changed makefiles to support shared libraries.
+@item
+@strong{MySQL}-NT can now use named pipes, which means that you can now use
+@strong{MySQL}-NT without having to install TCP/IP.
+@end itemize
+
+@node News-3.22.5, News-3.22.4, News-3.22.6, News-3.22.x
+@appendixsubsec Changes in release 3.22.5
+
+@itemize @bullet
+@item
+All table lock handing is changed to avoid some very subtle
+deadlocks when using @code{DROP TABLE}, @code{ALTER TABLE}, @code{DELETE FROM
+TABLE} and @code{mysqladmin flush-tables} under heavy usage.
+Changed locking code to get better handling of locks of different types.
+@item
+Updated @code{DBI} to 1.00 and @code{DBD} to 1.2.0.
+@item
+Added a check that the error message file contains error messages suitable for
+the current version of @code{mysqld}. (To avoid errors if you accidentally
+try to use an old error message file.)
+@item
+All count structures in the client (@code{affected_rows()},
+@code{insert_id()},...) are now of type @code{BIGINT} to allow 64-bit values
+to be used.
+This required a minor change in the @strong{MySQL} protocol which should affect
+only old clients when using tables with @code{AUTO_INCREMENT} values > 24M.
+@item
+The return type of @code{mysql_fetch_lengths()} has changed from @code{uint *}
+to @code{ulong *}. This may give a warning for old clients but should work
+on most machines.
+@item
+Change @code{mysys} and @code{dbug} libraries to allocate all thread variables
+in one struct. This makes it easier to make a threaded @file{libmysql.dll}
+library.
+@item
+Use the result from @code{gethostname()} (instead of @code{uname()}) when
+constructing @file{.pid} file names.
+@item
+New better compressed server/client protocol.
+@item
+@code{COUNT()}, @code{STD()} and @code{AVG()} are extended to handle more than
+4G rows.
+@item
+You can now store values in the range @code{-838:59:59} <= x <=
+@code{838:59:59} in a @code{TIME} column.
+@item
+@strong{WARNING: INCOMPATIBLE CHANGE!!}
+If you set a @code{TIME} column to too short a value, @strong{MySQL} now
+assumes the value is given as: @code{[[[D ]HH:]MM:]SS} instead of
+@code{HH[:MM[:SS]]}.
+@item
+@code{TIME_TO_SEC()} and @code{SEC_TO_TIME()} can now handle negative times
+and hours up to 32767.
+@item
+Added new option
+@code{SET OPTION SQL_LOG_UPDATE=@{0|1@}} to allow users with
+the @strong{process} privilege to bypass the update log.
+(Modified patch from Sergey A Mukhin @email{violet@@rosnet.net}.)
+@item
+Fixed fatal bug in @code{LPAD()}.
+@item
+Initialize 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}.
+Connect errors are now reset for each correct connection.
+@item
+Increased the default value of @code{max_allowed_packet} to @code{1M} in
+@code{mysqld}.
+@item
+Added @code{--low-priority-updates} option to @code{mysqld}, to give
+table-modifying operations (@code{INSERT}, @code{REPLACE}, @code{UPDATE},
+@code{DELETE}) lower priority than retrievals. You can now use
+@code{@{INSERT | REPLACE | UPDATE | DELETE@} LOW_PRIORITY ...} You can
+also use @code{SET OPTION SQL_LOW_PRIORITY_UPDATES=@{0|1@}} to change
+the priority for one thread. One side effect is that @code{LOW_PRIORITY}
+is now a reserved word. :(
+@item
+Add support for @code{INSERT INTO table ... VALUES(...),(...),(...)},
+to allow inserting multiple rows with a single statement.
+@item
+@code{INSERT INTO tbl_name} is now also cached when used with @code{LOCK TABLES}.
+(Previously only @code{INSERT ... SELECT} and @code{LOAD DATA INFILE} were
+cached.)
+@item
+Allow @code{GROUP BY} functions with @code{HAVING}:
+@example
+mysql> SELECT col FROM table GROUP BY col HAVING COUNT(*)>0;
+@end example
+@item
+@code{mysqld} will now ignore trailing @samp{;} characters in queries. This
+is to make it easier to migrate from some other SQL servers that require the
+trailing @samp{;}.
+@item
+Fix for corrupted fixed-format output generated by @code{SELECT INTO OUTFILE}.
+@item
+@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!!}
+@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
+there is no @code{GROUP BY} specification.
+@item
+Added @code{--vertical} option to @code{mysql}, for printing results in
+vertical mode.
+@item
+Index-only optimization; some queries are now resolved using
+only indexes. Until @strong{MySQL} 4.0, this works only for numeric columns.
+@xref{MySQL indexes, , @strong{MySQL} indexes}.
+@item
+Lots of new benchmarks.
+@item
+A new C API chapter and lots of other improvements in the manual.
+@end itemize
+
+@node News-3.22.4, News-3.22.3, News-3.22.5, News-3.22.x
+@appendixsubsec Changes in release 3.22.4
+
+@itemize @bullet
+@item
+Added @code{--tmpdir} option to @code{mysqld}, for specifying the location
+of the temporary file directory.
+@item
+@strong{MySQL} now automatically changes a query from an ODBC client:
+@example
+SELECT ... FROM table WHERE auto_increment_column IS NULL
+@end example
+to:
+@example
+SELECT ... FROM table WHERE auto_increment_column == LAST_INSERT_ID()
+@end example
+This allows some ODBC programs (Delphi, Access) to retrieve the newly
+inserted row to fetch the @code{AUTO_INCREMENT} id.
+@item
+@code{DROP TABLE} now waits for all users to free a table before deleting it.
+@item
+Fixed small memory leak in the new connect protocol.
+@item
+New functions @code{BIN()}, @code{OCT()}, @code{HEX()} and @code{CONV()} for
+converting between different number bases.
+@item
+Added function @code{SUBSTRING()} with 2 arguments.
+@item
+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
+@code{GROUP BY}.
+@item
+@code{mysqld} now automatically disables system locking on Linux and Win32,
+and for systems that use MIT-pthreads. You can force the use of locking
+with the @code{--enable-locking} option.
+@item
+Added @code{--console} option to @code{mysqld}, to force a console window
+(for error messages) when using Win32.
+@item
+Fixed table locks for Win32.
+@item
+Allow @samp{$} in identifiers.
+@item
+Changed name of user-specific configuration file from @file{my.cnf} to
+@file{.my.cnf} (Unix only).
+@item
+Added @code{DATE_ADD()} and @code{DATE_SUB()} functions.
+@end itemize
+
+@node News-3.22.3, News-3.22.2, News-3.22.4, News-3.22.x
+@appendixsubsec Changes in release 3.22.3
+
+@itemize @bullet
+@item
+Fixed a lock problem (bug in @strong{MySQL} 3.22.1) when closing temporary tables.
+@item
+Added missing @code{mysql_ping()} to the client library.
+@item
+Added @code{--compress} option to all @strong{MySQL} clients.
+@item
+Changed @code{byte} to @code{char} in @file{mysql.h} and @file{mysql_com.h}.
+@end itemize
+
+@node News-3.22.2, News-3.22.1, News-3.22.3, News-3.22.x
+@appendixsubsec Changes in release 3.22.2
+
+@itemize @bullet
+@item
+Searching on multiple constant keys that matched more than 30% of the rows
+didn't always use the best possible key.
+@item
+New functions @code{<<}, @code{>>}, @code{RPAD()} and @code{LPAD()}.
+@item
+You can now save default options (like passwords) in a configuration file
+(@file{my.cnf}).
+@item
+Lots of small changes to get @code{ORDER BY} to work when no records are found
+when using fields that are not in @code{GROUP BY} (@strong{MySQL} extension).
+@item
+Added @code{--chroot} option to @code{mysqld}, to start @code{mysqld} in
+a chroot environment (by Nikki Chumakov @email{nikkic@@cityline.ru}).
+@item
+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.
+@item
+Added @code{--one-thread} option to @code{mysqld}, for debugging with
+LinuxThreads (or @code{glibc}). (This replaces the @code{-T32} flag)
+@item
+Added @code{DROP TABLE IF EXISTS} to prevent an error from occurring if the
+table doesn't exist.
+@item
+@code{IF} and @code{EXISTS} are now reserved words (they would have to
+be sooner or later).
+@item
+Added lots of new options to @code{mysqldump}.
+@item
+Server error messages are now in @file{mysqld_error.h}.
+@item
+The server/client protocol now supports compression.
+@item
+All bug fixes from @strong{MySQL} 3.21.32.
+@end itemize
+
+@node News-3.22.1, News-3.22.0, News-3.22.2, News-3.22.x
+@appendixsubsec Changes in release 3.22.1
+
+@itemize @bullet
+@item
+Added new C API function @code{mysql_ping()}.
+@item
+Added new API functions @code{mysql_init()} and @code{mysql_options()}.
+You now MUST call @code{mysql_init()} before you call
+@code{mysql_real_connect()}.
+You don't have to call @code{mysql_init()} if you only use
+@code{mysql_connect()}.
+@item
+Added @code{mysql_options(...,MYSQL_OPT_CONNECT_TIMEOUT,...)} so you can set a
+timeout for connecting to a server.
+@item
+Added @code{--timeout} option to @code{mysqladmin}, as a test of
+@code{mysql_options()}.
+@item
+Added @code{AFTER column} and @code{FIRST} options to
+@code{ALTER TABLE ... ADD columns}.
+This makes it possible to add a new column at some specific location
+within a row in an existing table.
+@item
+@code{WEEK()} now takes an optional argument to allow handling of weeks when
+the week starts on Monday (some European countries). By default,
+@code{WEEK()} assumes the week starts on Sunday.
+@item
+@code{TIME} columns weren't stored properly (bug in @strong{MySQL} 3.22.0).
+@item
+@code{UPDATE} now returns information about how many rows were
+matched and updated, and how many ``warnings'' occurred when doing the update.
+@item
+Fixed incorrect result from @code{FORMAT(-100,2)}.
+@item
+@code{ENUM} and @code{SET} columns were compared in binary (case-sensitive)
+fashion; changed to be case insensitive.
+@end itemize
+
+@node News-3.22.0, , News-3.22.1, News-3.22.x
+@appendixsubsec Changes in release 3.22.0
+
+@itemize @bullet
+@item
+New (backward compatible) connect protocol that allows you to
+specify the database to use when connecting, to get much faster
+connections to a specific database.
+
+The @code{mysql_real_connect()} call is changed to:
+
+@example
+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)
+@end example
+@item
+Each connection is handled by its own thread, rather than by the
+master @code{accept()} thread. This fixes permanently the telnet bug
+that was a topic on the mail list some time ago.
+@item
+All TCP/IP connections are now checked with backward resolution of
+the hostname to get better security. @code{mysqld} now has a local hostname
+resolver cache so connections should actually be faster than before,
+even with this feature.
+@item
+A site automatically will be blocked from future connections if someone
+repeatedly connects with an ``improper header'' (like when one uses telnet).
+@item
+You can now refer to tables in different databases with references of the form
+@code{tbl_name@@db_name} or @code{db_name.tbl_name}. This makes it possible to
+give a user read access to some tables and write access to others simply by
+keeping them in different databases!
+@item
+Added @code{--user} option to @code{mysqld}, to allow it to run
+as another Unix user (if it is started as the Unix @code{root} user).
+@item
+Added caching of users and access rights (for faster access rights checking)
+@item
+Normal users (not anonymous ones) can change their password with
+@code{mysqladmin password 'new_password'}. This uses encrypted passwords
+that are not logged in the normal @strong{MySQL} log!
+@item
+All important string functions are now coded in assembler for x86 Linux
+machines. This gives a speedup of 10% in many cases.
+@item
+For tables that have many columns, the column names are now hashed for
+much faster column name lookup (this will speed up some benchmark
+tests a lot!)
+@item
+Some benchmarks are changed to get better individual timing.
+(Some loops were so short that a specific test took < 2 seconds. The
+loops have been changed to take about 20 seconds to make it easier
+to compare different databases. A test that took 1-2 seconds before
+now takes 11-24 seconds, which is much better)
+@item
+Re-arranged @code{SELECT} code to handle some very specific queries
+involving group functions (like @code{COUNT(*)}) without a @code{GROUP BY} but
+with @code{HAVING}. The following now works:
+@example
+mysql> SELECT count(*) as C FROM table HAVING C > 1;
+@end example
+@item
+Changed the protocol for field functions to be faster and avoid some
+calls to @code{malloc()}.
+@item
+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
+queries).
+@item
+Allow @code{STRAIGHT_JOIN} to be used between two tables to force the optimizer
+to join them in a specific order.
+@item
+String functions now return @code{VARCHAR} rather than @code{CHAR} and
+the column type is now @code{VARCHAR} for fields saved as @code{VARCHAR}.
+This should make the @strong{MyODBC} driver better, but may break some old
+@strong{MySQL} clients that don't handle @code{FIELD_TYPE_VARCHAR} the same
+way as @code{FIELD_TYPE_CHAR}.
+@item
+@code{CREATE INDEX} and @code{DROP INDEX} are now implemented through
+@code{ALTER TABLE}.
+@code{CREATE TABLE} is still the recommended (fast) way to create indexes.
+@item
+Added @code{--set-variable} option @code{wait_timeout} to @code{mysqld}.
+@item
+Added time column to @code{mysqladmin processlist} to show how long a query
+has taken or how long a thread has slept.
+@item
+Added lots of new variables to @code{show variables} and some new to
+@code{show status}.
+@item
+Added new type @code{YEAR}. @code{YEAR} is stored in 1 byte with allowable
+values of 0, and 1901 to 2155.
+@item
+Added new @code{DATE} type that is stored in 3 bytes rather than 4 bytes.
+All new tables are created with the new date type if you don't use the
+@code{--old-protocol} option to @code{mysqld}.
+@item
+Fixed bug in record caches; for some queries, you could get
+@code{Error from table handler: #} on some operating systems.
+@item
+Added @code{--enable-assembler} option to @code{configure}, for x86 machines
+(tested on Linux + @code{gcc}). This will enable assembler functions for the
+most important string functions for more speed!
+@end itemize
+
+@node News-3.21.x, News-3.20.x, News-3.22.x, News
+@appendixsec Changes in release 3.21.x
+
+@menu
+* News-3.21.33:: Changes in release 3.21.33
+* News-3.21.32:: Changes in release 3.21.32
+* News-3.21.31:: Changes in release 3.21.31
+* News-3.21.30:: Changes in release 3.21.30
+* News-3.21.29:: Changes in release 3.21.29
+* News-3.21.28:: Changes in release 3.21.28
+* News-3.21.27:: Changes in release 3.21.27
+* News-3.21.26:: Changes in release 3.21.26
+* News-3.21.25:: Changes in release 3.21.25
+* News-3.21.24:: Changes in release 3.21.24
+* News-3.21.23:: Changes in release 3.21.23
+* News-3.21.22:: Changes in release 3.21.22
+* News-3.21.21a:: Changes in release 3.21.21a
+* News-3.21.21:: Changes in release 3.21.21
+* News-3.21.20:: Changes in release 3.21.20
+* News-3.21.19:: Changes in release 3.21.19
+* News-3.21.18:: Changes in release 3.21.18
+* News-3.21.17:: Changes in release 3.21.17
+* News-3.21.16:: Changes in release 3.21.16
+* News-3.21.15:: Changes in release 3.21.15
+* News-3.21.14b:: Changes in release 3.21.14b
+* News-3.21.14a:: Changes in release 3.21.14a
+* News-3.21.13:: Changes in release 3.21.13
+* News-3.21.12:: Changes in release 3.21.12
+* News-3.21.11:: Changes in release 3.21.11
+* News-3.21.10:: Changes in release 3.21.10
+* News-3.21.9:: Changes in release 3.21.9
+* News-3.21.8:: Changes in release 3.21.8
+* News-3.21.7:: Changes in release 3.21.7
+* News-3.21.6:: Changes in release 3.21.6
+* News-3.21.5:: Changes in release 3.21.5
+* News-3.21.4:: Changes in release 3.21.4
+* News-3.21.3:: Changes in release 3.21.3
+* News-3.21.2:: Changes in release 3.21.2
+* News-3.21.0:: Changes in release 3.21.0
+@end menu
+
+@node News-3.21.33, News-3.21.32, News-3.21.x, News-3.21.x
+@appendixsubsec Changes in release 3.21.33
+
+@itemize @bullet
+@item
+Fixed problem when sending @code{SIGHUP} to @code{mysqld};
+@code{mysqld} core dumped when starting from boot on some systems.
+@item
+Fixed problem with losing a little memory for some connections.
+@item
+@code{DELETE FROM tbl_name} without a @code{WHERE} condition is now done the
+long way when you use @code{LOCK TABLES} or if the table is in use, to
+avoid race conditions.
+@item
+@code{INSERT INTO TABLE (timestamp_column) VALUES (NULL);} didn't set timestamp.
+@end itemize
+
+@node News-3.21.32, News-3.21.31, News-3.21.33, News-3.21.x
+@appendixsubsec Changes in release 3.21.32
+
+@itemize @bullet
+@item
+Fixed some possible race conditions when doing many reopen/close on the same
+tables under heavy load! This can happen if you execute @code{mysqladmin
+refresh} often. This could in some very rare cases corrupt the header of the
+index file and cause error 126 or 138.
+
+@item
+Fixed fatal bug in @code{refresh()} when running with the
+@code{--skip-locking} option. There was a ``very small'' time gap after
+a @code{mysqladmin refresh} when a table could be corrupted if one
+thread updated a table while another thread did @code{mysqladmin
+refresh} and another thread started a new update ont the same table
+before the first thread had finished. A refresh (or
+@code{--flush-tables}) will now not return until all used tables are
+closed!
+@item
+@code{SELECT DISTINCT} with a @code{WHERE} clause that didn't match any rows
+returned a row in some contexts (bug only in 3.21.31).
+@item
+@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
+@code{Use_count: Wrong count for ...} in the error log file.
+@end itemize
+
+@node News-3.21.31, News-3.21.30, News-3.21.32, News-3.21.x
+@appendixsubsec Changes in release 3.21.31
+@itemize @bullet
+@item
+Fixed a sign extension problem for the @code{TINYINT} type on Irix.
+@item
+Fixed problem with @code{LEFT("constant_string",function)}.
+@item
+Fixed problem with @code{FIND_IN_SET()}.
+@item
+@code{LEFT JOIN} core dumped if the second table is used with a constant
+@code{WHERE/ON} expression that uniquely identifies one record.
+@item
+Fixed problems with @code{DATE_FORMAT()} and incorrect dates.
+@code{DATE_FORMAT()} now ignores @code{'%'} to make it possible to extend
+it more easily in the future.
+@end itemize
+
+@node News-3.21.30, News-3.21.29, News-3.21.31, News-3.21.x
+@appendixsubsec Changes in release 3.21.30
+@itemize @bullet
+@item
+@code{mysql} now returns an exit code > 0 if the query returned an error.
+@item
+Saving of command line history to file in @code{mysql} client.
+By Tommy Larsen @email{tommy@@mix.hive.no}.
+@item
+Fixed problem with empty lines that were ignored in @file{mysql.cc}.
+@item
+Save the pid of the signal handler thread in the pid file instead
+of the pid of the main thread.
+@item
+Added patch by @email{tommy@@valley.ne.jp} to support Japanese characters
+SJIS and UJIS.
+@item
+Changed @code{safe_mysqld} to redirect startup messages to
+@code{'hostname'.err} instead
+of @code{'hostname'.log} to reclaim file space on @code{mysqladmin refresh}.
+@item
+@code{ENUM} always had the first entry as default value.
+@item
+@code{ALTER TABLE} wrote two entries to the update log.
+@item
+@code{sql_acc()} now closes the @code{mysql} grant tables after a reload to
+save table space and memory.
+@item
+Changed @code{LOAD DATA} to use less memory with tables and @code{BLOB}
+columns.
+@item
+Sorting on a function which made a division / 0 produced a wrong set
+in some cases.
+@item
+Fixed @code{SELECT} problem with @code{LEFT()} when using the czech character
+set.
+@item
+Fixed problem in @code{isamchk}; it couldn't repair a packed table in a very
+unusual case.
+@item
+@code{SELECT} statements with @code{&} or @code{|} (bit functions) failed on
+columns with @code{NULL} values.
+@item
+When comparing a field = field, where one of the fields was a part key,
+only the length of the part key was compared.
+@end itemize
+
+@node News-3.21.29, News-3.21.28, News-3.21.30, News-3.21.x
+@appendixsubsec Changes in release 3.21.29
+@itemize @bullet
+@item
+@code{LOCK TABLES} + @code{DELETE from tbl_name} never removed locks properly.
+@item
+Fixed problem when grouping on an @code{OR} function.
+@item
+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.
+@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).
+@item
+Fixed bug in @code{WEEK("XXXX-xx-01")}.
+@end itemize
+
+@node News-3.21.28, News-3.21.27, News-3.21.29, News-3.21.x
+@appendixsubsec Changes in release 3.21.28
+@itemize @bullet
+@item
+Fixed socket permission (clients couldn't connect to Unix socket on Linux).
+@item
+Fixed bug in record caches; for some queries, you could get
+@code{Error from table handler: #} on some operating systems.
+@end itemize
+
+@node News-3.21.27, News-3.21.26, News-3.21.28, News-3.21.x
+@appendixsubsec Changes in release 3.21.27
+@itemize @bullet
+@item
+Added user level lock functions @code{GET_LOCK(string,timeout)},
+@code{RELEASE_LOCK(string)}.
+@item
+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
+@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
+@item
+@code{WHERE} with string_column_key = constant_string didn't always find
+all rows if the column had many values differing only with characters of
+the same sort value (like e and @'e).
+@item
+Strings keys looked up with 'ref' were not compared in case-sensitive fashion.
+@item
+Added @code{umask()} to make log files non-readable for normal users.
+@item
+Ignore users with old (8-byte) password on startup if not using
+@code{--old-protocol} option to @code{mysqld}.
+@item
+@code{SELECT} which matched all key fields returned the values in the
+case of the matched values, not of the found values. (Minor problem.)
+@end itemize
+
+@node News-3.21.26, News-3.21.25, News-3.21.27, News-3.21.x
+@appendixsubsec Changes in release 3.21.26
+@itemize @bullet
+@item
+@code{FROM_DAYS(0)} now returns "0000-00-00".
+@item
+In @code{DATE_FORMAT()}, PM and AM were swapped for hours 00 and 12.
+@item
+Extended the default maximum key size to 256.
+@item
+Fixed bug when using @code{BLOB}/@code{TEXT} in @code{GROUP BY} with many
+tables.
+@item
+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))}.
+@item
+Added some tests to the table order optimizer 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
+Linux machines.
+@end itemize
+
+@node News-3.21.25, News-3.21.24, News-3.21.26, News-3.21.x
+@appendixsubsec Changes in release 3.21.25
+@itemize @bullet
+@item
+Changed @code{typedef 'string'} to @code{typedef 'my_string'} for better
+portability.
+@item
+You can now kill threads that are waiting on a disk full condition.
+@item
+Fixed some problems with UDF functions.
+@item
+Added long options to @code{isamchk}. Try @code{isamchk --help}.
+@item
+Fixed a bug when using 8 bytes long (alpha); @code{filesort()} didn't work.
+Affects @code{DISTINCT}, @code{ORDER BY} and @code{GROUP BY} on 64-bit
+processors.
+@end itemize
+
+@node News-3.21.24, News-3.21.23, News-3.21.25, News-3.21.x
+@appendixsubsec Changes in release 3.21.24
+@itemize @bullet
+@item
+Dynamic loadable functions. Based on source from Alexis Mikhailov.
+@item
+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
+inside each other.
+@item
+Recoded @code{MIN()} and @code{MAX()} to work properly with strings and
+@code{HAVING}.
+@item
+Changed default umask value for new files from @code{0664} to @code{0660}.
+@item
+Fixed problem with @code{LEFT JOIN} and constant expressions in the @code{ON}
+part.
+@item
+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
+support.
+@item
+Upgraded @code{DBI} to 0.93.
+@end itemize
+
+@node News-3.21.23, News-3.21.22, News-3.21.24, News-3.21.x
+@appendixsubsec Changes in release 3.21.23
+@itemize @bullet
+@item
+The following symbols are now reserved words:
+@code{TIME}, @code{DATE}, @code{TIMESTAMP}, @code{TEXT}, @code{BIT},
+@code{ENUM}, @code{NO}, @code{ACTION}, @code{CHECK}, @code{YEAR},
+@code{MONTH}, @code{DAY}, @code{HOUR}, @code{MINUTE}, @code{SECOND},
+@code{STATUS}, @code{VARIABLES}.
+@item
+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
+case sensitive.
+@item
+Added @code{--skip-thread-priority} option to @code{mysqld}, for systems
+where @code{mysqld}'s thread scheduling doesn't work properly (BSDI 3.1).
+@item
+Added ODBC functions @code{DAYNAME()} and @code{MONTHNAME()}.
+@item
+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
+inside @code{AND}s.
+@item
+Added command @code{variables} to @code{mysqladmin}.
+@item
+A lot of small changes to the binary releases.
+@item
+Fixed a bug in the new protocol from @strong{MySQL} 3.21.20.
+@item
+Changed @code{ALTER TABLE} to work with Win32 (Win32 can't rename open files).
+Also fixed a couple of small bugs in the Win32 version.
+@item
+All standard @strong{MySQL} clients are now ported to @strong{MySQL}-Win32.
+@item
+@strong{MySQL} can now be started as a service on NT.
+@end itemize
+
+@node News-3.21.22, News-3.21.21a, News-3.21.23, News-3.21.x
+@appendixsubsec Changes in release 3.21.22
+@itemize @bullet
+@item
+Starting with this version, all @strong{MySQL} distributions will be
+configured, compiled and tested with @code{crash-me} and the benchmarks on
+the following platforms: SunOS 5.6 sun4u, SunOS 5.5.1 sun4u, SunOS 4.14 sun4c,
+SunOS 5.6 i86pc, Irix 6.3 mips5k, HP-UX 10.20 hppa, AIX 4.2.1 ppc,
+OSF1 V4.0 alpha, FreeBSD 2.2.2 i86pc and BSDI 3.1 i386.
+@item
+Fix @code{COUNT(*)} problems when the @code{WHERE} clause didn't match any
+records. (Bug from 3.21.17.)
+@item
+Removed that @code{NULL = NULL} is true. Now you must use @code{IS NULL}
+or @code{IS NOT NULL} to test whether or not a value is @code{NULL}.
+(This is according to ANSI SQL but may break
+old applications that are ported from @code{mSQL}.)
+You can get the old behavior by compiling with @code{-DmSQL_COMPLIANT}.
+@item
+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.
+@item
+Added functions @code{DAYOFYEAR()}, @code{DAYOFMONTH()}, @code{MONTH()},
+@code{YEAR()}, @code{WEEK()}, @code{QUARTER()}, @code{HOUR()}, @code{MINUTE()},
+@code{SECOND()} and @code{FIND_IN_SET()}.
+@item
+Added command @code{SHOW VARIABLES}.
+@item
+Added support of ``long constant strings'' from ANSI SQL:
+@example
+mysql> SELECT 'first ' 'second'; -> 'first second'
+@end example
+@item
+Upgraded mSQL-Mysql-modules to 1.1825.
+@item
+Upgraded @code{mysqlaccess} to 2.02.
+@item
+Fixed problem with Russian character set and @code{LIKE}.
+@item
+Ported to OpenBSD 2.1.
+@item
+New Dutch error messages.
+@end itemize
+
+@node News-3.21.21a, News-3.21.21, News-3.21.22, News-3.21.x
+@appendixsubsec Changes in release 3.21.21a
+@itemize @bullet
+@item
+Configure changes for some operating systems.
+@end itemize
+
+@node News-3.21.21, News-3.21.20, News-3.21.21a, News-3.21.x
+@appendixsubsec Changes in release 3.21.21
+@itemize @bullet
+@item
+Fixed optimizer bug when using
+@code{WHERE data_field = date_field2 AND date_field2 = constant}.
+@item
+Added command @code{SHOW STATUS}.
+@item
+Removed @file{manual.ps} from the source distribution to make it smaller.
+@end itemize
+
+@node News-3.21.20, News-3.21.19, News-3.21.21, News-3.21.x
+@appendixsubsec Changes in release 3.21.20
+@itemize @bullet
+@item
+Changed the maximum table name and column name lengths from 32 to 64.
+@item
+Aliases can now be of ``any'' length.
+@item
+Fixed @code{mysqladmin stat} to return the right number of queries.
+@item
+Changed protocol (downward compatible) to mark if a column has the
+@code{AUTO_INCREMENT} attribute or is a @code{TIMESTAMP}. This is needed for
+the new Java driver.
+@item
+Added Hebrew sorting order by Zeev Suraski.
+@item
+Solaris 2.6: Fixed @code{configure} bugs and increased maximum table size
+from 2G to 4G.
+@end itemize
+
+@node News-3.21.19, News-3.21.18, News-3.21.20, News-3.21.x
+@appendixsubsec Changes in release 3.21.19
+@itemize @bullet
+@item
+Upgraded @code{DBD} to 1823. This version implements @code{mysql_use_result} in
+@code{DBD-Mysql}.
+@item
+Benchmarks updated for empress (by Luuk).
+@item
+Fixed a case of slow range searching.
+@item
+Configure fixes (@file{Docs} directory).
+@item
+Added function @code{REVERSE()} (by Zeev Suraski).
+@end itemize
+
+@node News-3.21.18, News-3.21.17, News-3.21.19, News-3.21.x
+@appendixsubsec Changes in release 3.21.18
+@itemize @bullet
+@item
+Issue error message if client C functions are called in wrong order.
+@item
+Added automatic reconnect to the @file{libmysql.c} library. If a write command
+fails, an automatic reconnect is done.
+@item
+Small sort sets no longer use temporary files.
+@item
+Upgraded @code{DBI} to 0.91.
+@item
+Fixed a couple of problems with @code{LEFT OUTER JOIN}.
+@item
+Added @code{CROSS JOIN} syntax. @code{CROSS} is now a reserved word.
+@item
+Recoded @code{yacc}/@code{bison} stack allocation to be even safer and to allow
+@strong{MySQL} to handle even bigger expressions.
+@item
+Fixed a couple of problems with the update log.
+@item
+@code{ORDER BY} was slow when used with key ranges.
+@end itemize
+
+@node News-3.21.17, News-3.21.16, News-3.21.18, News-3.21.x
+@appendixsubsec Changes in release 3.21.17
+@itemize @bullet
+@item
+Changed documentation string of @code{--with-unix-socket-path} to avoid
+confusion.
+@item
+Added ODBC and ANSI SQL style @code{LEFT OUTER JOIN}.
+@item
+The following are new reserved words: @code{LEFT}, @code{NATURAL},
+@code{USING}.
+@item
+The client library now uses the value of the environment variable
+@code{MYSQL_HOST} as the default host if it's defined.
+@item
+@code{SELECT col_name, SUM(expr)} now returns @code{NULL} for @code{col_name}
+when there are matching rows.
+@item
+Fixed problem with comparing binary strings and @code{BLOB}s with ASCII
+characters over 127.
+@item
+Fixed lock problem: when freeing a read lock on a table with multiple
+read locks, a thread waiting for a write lock would have been given the lock.
+This shouldn't affect data integrity, but could possibly make @code{mysqld}
+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
+using bigger key caches.
+@end itemize
+
+@node News-3.21.16, News-3.21.15, News-3.21.17, News-3.21.x
+@appendixsubsec Changes in release 3.21.16
+
+@itemize @bullet
+@item
+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
+swapped according to ODBC standard. Fixed.
+@item
+Added function @code{TIME_TO_SEC()}.
+@item
+In some cases, default values were not used for @code{NOT NULL} fields.
+@item
+Timestamp wasn't always updated properly in @code{UPDATE SET ...} statements.
+@item
+Allow empty strings as default values for @code{BLOB} and @code{TEXT}, to
+be compatible with @code{mysqldump}.
+@end itemize
+
+@node News-3.21.15, News-3.21.14b, News-3.21.16, News-3.21.x
+@appendixsubsec Changes in release 3.21.15
+
+@itemize @bullet
+@item
+@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
+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}!)
+@item
+Changed Makefiles to hopefully work better with BSD systems. Also,
+@file{manual.dvi} is now included in the distribution to avoid having stupid
+@code{make} programs trying to rebuild it.
+@item
+@code{readline} library upgraded to version 2.1.
+@item
+A new sortorder german-1. That is a normal ISO-Latin1 with a german sort
+order.
+@item
+Perl @code{DBI}/@code{DBD} is now included in the distribution. @code{DBI}
+is now the recommended way to connect to @strong{MySQL} from Perl.
+@item
+New portable benchmark suite with @code{DBD}, with test results from
+@code{mSQL} 2.0.3, @strong{MySQL}, PostgreSQL 6.2.1 and Solid server 2.2.
+@item
+@code{crash-me} is now included with the benchmarks; This is a Perl program
+designed to find as many limits as possible in a SQL server. Tested with
+@code{mSQL}, PostgreSQL, Solid and @strong{MySQL}.
+@item
+Fixed bug in range-optimizer that crashed @strong{MySQL} on some queries.
+@item
+Table and column name completion for @code{mysql} command line tool, by Zeev
+Suraski and Andi Gutmans.
+@item
+Added new command @code{REPLACE} that works like @code{INSERT} but
+replaces conflicting records with the new record. @code{REPLACE INTO
+TABLE ... SELECT ...} works also.
+@item
+Added new commands @code{CREATE DATABASE db_name} and @code{DROP
+DATABASE db_name}.
+@item
+Added @code{RENAME} option to @code{ALTER TABLE}: @code{ALTER TABLE name
+RENAME AS new_name}.
+@item
+@code{make_binary_distribution} now includes @file{libgcc.a} in
+@file{libmysqlclient.a}. This should make linking work for people who don't
+have @code{gcc}.
+@item
+Changed @code{net_write()} to @code{my_net_write()} because of a name
+conflict with Sybase.
+@item
+@cindex ODBC compatibility
+@cindex Compatibility, with ODBC
+New function @code{DAYOFWEEK()} compatible with ODBC.
+@item
+Stack checking and @code{bison} memory overrun checking to make @strong{MySQL}
+safer with weird queries.
+@end itemize
+
+@node News-3.21.14b, News-3.21.14a, News-3.21.15, News-3.21.x
+@appendixsubsec Changes in release 3.21.14b
+
+@itemize @bullet
+@item
+Fixed a couple of small @code{configure} problems on some platforms.
+@end itemize
+
+@node News-3.21.14a, News-3.21.13, News-3.21.14b, News-3.21.x
+@appendixsubsec Changes in release 3.21.14a
+
+@itemize @bullet
+@item
+Ported to SCO Openserver 5.0.4 with FSU Pthreads.
+@item
+HP-UX 10.20 should work.
+@item
+Added new function @code{DATE_FORMAT()}.
+@item
+Added @code{NOT IN}.
+@item
+Added automatic removal of 'ODBC function conversions': @code{@{fn now() @}}
+@item
+Handle ODBC 2.50.3 option flags.
+@item
+Fixed comparison of @code{DATE} and @code{TIME} values with @code{NULL}.
+@item
+Changed language name from germany to german to be consistent with
+the other language names.
+@item
+Fixed sorting problem on functions returning a @code{FLOAT}. Previously, the
+values were converted to @code{INT}s before sorting.
+@item
+Fixed slow sorting when sorting on key field when using
+@code{key_column=constant}.
+@item
+Sorting on calculated @code{DOUBLE} values sorted on integer results instead.
+@item
+@code{mysql} no longer needs a database argument.
+@item
+Changed the place where @code{HAVING} should be. According to ANSI, it should
+be after @code{GROUP BY} but before @code{ORDER BY}. @strong{MySQL} 3.20
+incorrectly had it last.
+@item
+Added Sybase command @code{USE DATABASE} to start using another database.
+@item
+Added automatic adjusting of number of connections and table cache size
+if the maximum number of files that can be opened is less than needed.
+This should fix that @code{mysqld} doesn't crash even if you haven't done a
+@code{ulimit -n 256} before starting @code{mysqld}.
+@item
+Added lots of limit checks to make it safer when running with too little
+memory or when doing weird queries.
+@end itemize
+
+@node News-3.21.13, News-3.21.12, News-3.21.14a, News-3.21.x
+@appendixsubsec Changes in release 3.21.13
+
+@itemize @bullet
+@item
+Added retry of interrupted reads and clearing of @code{errno}.
+This makes Linux systems much safer!
+@item
+Fixed locking bug when using many aliases on the same table in the same
+@code{SELECT}.
+@item
+Fixed bug with @code{LIKE} on number key.
+@item
+New error message so you can check whether the connection was lost while
+the command was running or whether the connection was down from the start.
+@item
+Added @code{--table} option to @code{mysql} to print in table format.
+Moved time and row information after query result.
+Added automatic reconnect of lost connections.
+@item
+Added @code{!=} as a synonym for @code{<>}.
+@item
+Added function @code{VERSION()} to make easier logs.
+@item
+New multi-user test @file{tests/fork_test.pl} to put some strain on the
+thread library.
+@end itemize
+
+@node News-3.21.12, News-3.21.11, News-3.21.13, News-3.21.x
+@appendixsubsec Changes in release 3.21.12
+
+@itemize @bullet
+@item
+Fixed @code{ftruncate()} call in MIT-pthreads. This made @code{isamchk}
+destroy the @file{.ISM} files on (Free)BSD 2.x systems.
+@item
+Fixed broken @code{__P_} patch in MIT-pthreads.
+@item
+Many memory overrun checks. All string functions now return @code{NULL}
+if the returned string should be longer than @code{max_allowed_packet} bytes.
+@item
+Changed the name of the @code{INTERVAL} type to @code{ENUM}, because
+@code{INTERVAL} is used in ANSI SQL.
+@item
+In some cases, doing a @code{JOIN} + @code{GROUP} + @code{INTO OUTFILE},
+the result wasn't grouped.
+@item
+@code{LIKE} with @code{'_'} as last character didn't work. Fixed.
+@item
+Added extended ANSI SQL @code{TRIM()} function.
+@item
+Added @code{CURTIME()}.
+@item
+Added @code{ENCRYPT()} function by Zeev Suraski.
+@item
+Fixed better @code{FOREIGN KEY} syntax skipping. New reserved words:
+@code{MATCH}, @code{FULL}, @code{PARTIAL}.
+@item
+@code{mysqld} now allows IP number and hostname to the @code{--bind-address}
+option.
+@item
+Added @code{SET OPTION CHARACTER SET cp1251_koi8} to enable conversions of
+data to/from cp1251_koi8.
+@item
+Lots of changes for Win95 port. In theory, this version should now be
+easily portable to Win95.
+@item
+Changed the @code{CREATE COLUMN} syntax of @code{NOT NULL} columns to be after
+the @code{DEFAULT} value, as specified in the ANSI SQL standard. This will
+make @code{mysqldump} with @code{NOT NULL} and default values incompatible with
+@strong{MySQL} 3.20.
+@item
+Added many function name aliases so the functions can be used with
+ODBC or ANSI SQL92 syntax.
+@item
+Fixed syntax of @code{ALTER TABLE tbl_name ALTER COLUMN col_name SET DEFAULT
+NULL}.
+@item
+Added @code{CHAR} and @code{BIT} as synonyms for @code{CHAR(1)}.
+@item
+Fixed core dump when updating as a user who has only @strong{select} privilege.
+@item
+@code{INSERT ... SELECT ... GROUP BY} didn't work in some cases. An
+@code{Invalid use of group function} error occurred.
+@item
+When using @code{LIMIT}, @code{SELECT} now always uses keys instead of record
+scan. This will give better performance on @code{SELECT} and a @code{WHERE}
+that matches many rows.
+@item
+Added Russian error messages.
+@end itemize
+
+@node News-3.21.11, News-3.21.10, News-3.21.12, News-3.21.x
+@appendixsubsec Changes in release 3.21.11
+
+@itemize @bullet
+@item
+Configure changes.
+@item
+@strong{MySQL} now works with the new thread library on BSD/OS 3.0.
+@item
+Added new group functions @code{BIT_OR()} and @code{BIT_AND()}.
+@item
+Added compatibility functions @code{CHECK} and @code{REFERENCES}.
+@code{CHECK} is now a reserved word.
+@item
+Added @code{ALL} option to @code{GRANT} for better compatibility. (@code{GRANT}
+is still a dummy function.)
+@item
+Added partly-translated dutch messages.
+@item
+Fixed bug in @code{ORDER BY} and @code{GROUP BY} with @code{NULL} columns.
+@item
+Added function @code{last_insert_id()} to retrieve last @code{AUTO_INCREMENT}
+value. This is intended for clients to ODBC that can't use the
+@code{mysql_insert_id()} API function, but can be used by any client.
+@item
+Added @code{--flush-logs} option to @code{mysqladmin}.
+@item
+Added command @code{STATUS} to @code{mysql}.
+@item
+Fixed problem with @code{ORDER BY}/@code{GROUP BY} because of bug in @code{gcc}.
+@item
+Fixed problem with @code{INSERT ... SELECT ... GROUP BY}.
+@end itemize
+
+@node News-3.21.10, News-3.21.9, News-3.21.11, News-3.21.x
+@appendixsubsec Changes in release 3.21.10
+
+@itemize @bullet
+@item
+New @code{mysqlaccess}.
+@item
+@code{CREATE} now supports all ODBC types and the @code{mSQL} @code{TEXT} type.
+All ODBC 2.5 functions are also supported (added @code{REPEAT}). This provides
+better portability.
+@item
+Added text types @code{TINYTEXT}, @code{TEXT}, @code{MEDIUMTEXT} and
+@code{LONGTEXT}. These are actually @code{BLOB}types, but all searching is
+done in case-insensitive fashion.
+@item
+All old @code{BLOB} fields are now @code{TEXT} fields. This only
+changes that all searching on strings is done in case-sensitive fashion.
+You must do an @code{ALTER TABLE} and change the field type to @code{BLOB}
+if you want to have tests done in case-sensitive fashion.
+@item
+Fixed some @code{configure} issues.
+@item
+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
+@code{test-select} works.
+@end itemize
+
+@node News-3.21.9, News-3.21.8, News-3.21.10, News-3.21.x
+@appendixsubsec Changes in release 3.21.9
+
+@itemize @bullet
+@item
+Added @code{--enable-unix-socket=pathname} option to @code{configure}.
+@item
+Fixed a couple of portability problems with include files.
+@item
+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 @strong{MySQL} to
+run on SCO. @xref{SCO}.
+@end itemize
+
+@node News-3.21.8, News-3.21.7, News-3.21.9, News-3.21.x
+@appendixsubsec Changes in release 3.21.8
+
+@itemize @bullet
+@item
+Works now in Solaris 2.6.
+@item
+Added handling of calculation of @code{SUM()} functions.
+For example, you can now use @code{SUM(column)/COUNT(column)}.
+@item
+Added handling of trigometric functions:
+@code{PI()}, @code{ACOS()}, @code{ASIN()}, @code{ATAN()}, @code{COS()},
+@code{SIN()} and @code{TAN()}.
+@item
+New languages: norwegian, norwegian-ny and portuguese.
+@item
+Fixed parameter bug in @code{net_print()} in @file{procedure.cc}.
+@item
+Fixed a couple of memory leaks.
+@item
+Now allow also the old @code{SELECT ... INTO OUTFILE} syntax.
+@item
+Fixed bug with @code{GROUP BY} and @code{SELECT} on key with many values.
+@item
+@code{mysql_fetch_lengths()} sometimes returned incorrect lengths when you used
+@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}.
+@item
+Fixed problem when sorting on @code{NULL} fields.
+@item
+Fixed a couple of 64-bit (Alpha) problems.
+@item
+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
+argument).
+@item
+Added machine-dependent files for MIT-pthreads i386-SCO. There is probably
+more to do to get this to work on SCO 3.5.
+@end itemize
+
+@node News-3.21.7, News-3.21.6, News-3.21.8, News-3.21.x
+@appendixsubsec Changes in release 3.21.7
+
+@itemize @bullet
+@item
+Changed @file{Makefile.am} to take advantage of Automake 1.2.
+@item
+Added the beginnings of a benchmark suite.
+@item
+Added more secure password handling.
+@item
+Added new client function @code{mysql_errno()}, to get the error number of
+the error message. This makes error checking in the client much easier.
+This makes the new server incompatible with the 3.20.x server when running
+without @code{--old-protocol}. The client code is backward compatible.
+More information can be found in the @file{README} file!
+@item
+Fixed some problems when using very long, illegal names.
+@end itemize
+
+@node News-3.21.6, News-3.21.5, News-3.21.7, News-3.21.x
+@appendixsubsec Changes in release 3.21.6
+
+@itemize @bullet
+@item
+Fixed more portability issues (incorrect @code{sigwait} and @code{sigset}
+defines).
+@item
+@code{configure} should now be able to detect the last argument to
+@code{accept()}.
+@end itemize
+
+@node News-3.21.5, News-3.21.4, News-3.21.6, News-3.21.x
+@appendixsubsec Changes in release 3.21.5
+
+@itemize @bullet
+@item
+Should now work with FreeBSD 3.0 if used with
+@file{FreeBSD-3.0-libc_r-1.0.diff},
+which can be found at @uref{http://www.mysql.com/Downloads/Patches/}.
+@item
+Added new option @code{-O tmp_table_size=#} to @code{mysqld}.
+@item
+New function @code{FROM_UNIXTIME(timestamp)} which returns a date string in
+'YYYY-MM-DD HH:MM:DD' format.
+@item
+New function @code{SEC_TO_TIME(seconds)} which returns a string in
+'HH:MM:SS' format.
+@item
+New function @code{SUBSTRING_INDEX()}, originally by Zeev Suraski.
+@end itemize
+
+@node News-3.21.4, News-3.21.3, News-3.21.5, News-3.21.x
+@appendixsubsec Changes in release 3.21.4
+
+@itemize @bullet
+@item
+Should now configure and compile on OSF1 4.0 with the DEC compiler.
+@item
+Configuration and compilation on BSD/OS 3.0 works, but due to some bugs in
+BSD/OS 3.0, @code{mysqld} doesn't work on it yet.
+@item
+Configuration and compilation on FreeBSD 3.0 works, but I couldn't get
+@code{pthread_create} to work.
+@end itemize
+
+@node News-3.21.3, News-3.21.2, News-3.21.4, News-3.21.x
+@appendixsubsec Changes in release 3.21.3
+
+@itemize @bullet
+@item
+Added reverse check lookup of hostnames to get better security.
+@item
+Fixed some possible buffer overflows if filenames that are too long are used.
+@item
+@code{mysqld} doesn't accept hostnames that start with digits followed by a
+@code{'.'}, because the hostname may look like an IP number.
+@item
+Added @code{--skip-networking} option to @code{mysqld}, to only allow socket
+connections. (This will not work with MIT-pthreads!)
+@item
+Added check of too long table names for alias.
+@item
+Added check if database name is okay.
+@item
+Added check if too long table names.
+@item
+Removed incorrect @code{free()} that killed the server on
+@code{CREATE DATABASE} or @code{DROP DATABASE}.
+@item
+Changed some @code{mysqld} @code{-O} options to better names.
+@item
+Added @code{-O join_cache_size=#} option to @code{mysqld}.
+@item
+Added @code{-O max_join_size=#} option to @code{mysqld}, to be able to set a
+limit how big queries (in this case big = slow) one should be able to handle
+without specifying @code{SET OPTION SQL_BIG_SELECTS=1}. A # = is about 10
+examined records. The default is ``unlimited''.
+@item
+When comparing a @code{TIME}, @code{DATE}, @code{DATETIME} or @code{TIMESTAMP}
+column to a constant, the constant is converted to a time value before
+performing the comparison.
+This will make it easier to get ODBC (particularly Access97) to work with
+the above types. It should also make dates easier to use and the comparisons
+should be quicker than before.
+@item
+Applied patch from Jochen Wiedmann that allows @code{query()} in
+@code{mysqlperl} to take a query with @code{\0} in it.
+@item
+Storing a timestamp with a 2-digit year (@code{YYMMDD}) didn't work.
+@item
+Fix that timestamp wasn't automatically updated if set in an @code{UPDATE}
+clause.
+@item
+Now the automatic timestamp field is the FIRST timestamp field.
+@item
+@code{SELECT * INTO OUTFILE}, which didn't correctly if the outfile already
+existed.
+@item
+@code{mysql} now shows the thread ID when starting or doing a reconnect.
+@item
+Changed the default sort buffer size from 2M to 1M.
+@end itemize
+
+@node News-3.21.2, News-3.21.0, News-3.21.3, News-3.21.x
+@appendixsubsec Changes in release 3.21.2
+
+@itemize @bullet
+@item
+The range optimizer 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.
+At least the @code{isam} library should be relatively 64-bit clean.
+@item
+New @code{isamchk} which can detect and fix more problems.
+@item
+New options for @code{isamlog}.
+@item
+Using new version of Automake.
+@item
+Many small portability changes (from the AIX and alpha-digital port)
+Better checking of pthread(s) library.
+@item
+czech error messages by @email{snajdr@@pvt.net}.
+@item
+Decreased size of some buffers to get fewer problems on systems with little
+memory. Also added more checks to handle ``out of memory'' problems.
+@item
+@code{mysqladmin}: you can now do @code{mysqladmin kill 5,6,7,8} to kill
+multiple threads.
+@item
+When the maximum connection limit is reached, one extra connection by a user
+with the @strong{PROCESS_ACL} privilege is granted.
+@item
+Added @code{-O backlog=#} option to @code{mysqld}.
+@item
+Increased maximum packet size from 512K to 1024K for client.
+@item
+Almost all of the function code is now tested in the internal test suite.
+@item
+@code{ALTER TABLE} now returns warnings from field conversions.
+@item
+Port changed to 3306 (got it reserved from ISI).
+@item
+Added a fix for Visual FoxBase so that any schema name from a table
+specification is automatically removed.
+@item
+New function @code{ASCII()}.
+@item
+Removed function @code{BETWEEN(a,b,c)}. Use the standard ANSI
+synax instead: @code{expr BETWEEN expr AND expr}.
+@item
+@strong{MySQL} no longer has to use an extra temporary table when sorting
+on functions or @code{SUM()} functions.
+@item
+Fixed bug that you couldn't use @code{tbl_name.field_name} in @code{UPDATE}.
+@item
+Fixed @code{SELECT DISTINCT} when using 'hidden group'. For example:
+@example
+mysql> SELECT DISTINCT MOD(some_field,10) FROM test
+ GROUP BY some_field;
+@end example
+Note: @code{some_field} is normally in the @code{SELECT} part. ANSI SQL should
+require it.
+@end itemize
+
+@node News-3.21.0, , News-3.21.2, News-3.21.x
+@appendixsubsec Changes in release 3.21.0
+
+@itemize @bullet
+@item
+New reserved words used: @code{INTERVAL}, @code{EXPLAIN}, @code{READ},
+@code{WRITE}, @code{BINARY}.
+@item
+Added ODBC function @code{CHAR(num,...)}.
+@item
+New operator @code{IN}. This uses a binary search to find a match.
+@item
+New command @code{LOCK TABLES tbl_name [AS alias] @{READ|WRITE@} ...}
+@item
+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.
+@item
+For easier client code, the client should no longer use
+@code{FIELD_TYPE_TINY_BLOB}, @code{FIELD_TYPE_MEDIUM_BLOB},
+@code{FIELD_TYPE_LONG_BLOB} or @code{FIELD_TYPE_VAR_STRING} (as
+previously returned by @code{mysql_list_fields}). You should instead only use
+@code{FIELD_TYPE_BLOB} or @code{FIELD_TYPE_STRING}. If you want exact
+types, you should use the command @code{SHOW FIELDS}.
+@item
+Added varbinary syntax: @code{0x######} which can be used as a string
+(default) or a number.
+@item
+@code{FIELD_TYPE_CHAR} is renamed to @code{FIELD_TYPE_TINY}.
+@item
+Changed all fields to C++ classes.
+@item
+Removed FORM struct.
+@item
+Fields with @code{DEFAULT} values no longer need to be @code{NOT NULL}.
+@item
+New field types:
+@table @code
+@item ENUM
+A string which can take only a couple of defined values. The value is
+stored as a 1-3 byte number that is mapped automatically to a string.
+This is sorted according to string positions!
+@item SET
+A string which may have one or many string values separated with ','.
+The string is stored as a 1-, 2-, 3-, 4- or 8-byte number where each bit stands
+for a specific set member. This is sorted according to the unsigned value
+of the stored packed number.
+@end table
+@item
+Now all function calculation is done with @code{double} or @code{long long}.
+This will provide the full 64-bit range with bit functions and fix some
+conversions that previously could result in precision losses. One should
+avoid using @code{unsigned long long} columns with full 64-bit range
+(numbers bigger than 9223372036854775807) because calculations are done
+with @code{signed long long}.
+@item
+@code{ORDER BY} will now put @code{NULL} field values first. @code{GROUP BY}
+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
+constant. Example:
+@example
+mysql> SELECT * FROM tbl_name
+ WHERE key_part_1="customer"
+ AND key_part_2>=10 AND key_part_2<=10;
+@end example
+@end itemize
+
+@node News-3.20.x, News-3.19.x, News-3.21.x, News
+@appendixsec Changes in release 3.20.x
+
+Changes from 3.20.18 to 3.20.32b are not documented here because the
+3.21 release branched here. And the relevant changes are also
+documented as changes to the 3.21 version.
+
+@menu
+* News-3.20.18:: Changes in release 3.20.18
+* News-3.20.17:: Changes in release 3.20.17
+* News-3.20.16:: Changes in release 3.20.16
+* News-3.20.15:: Changes in release 3.20.15
+* News-3.20.14:: Changes in release 3.20.14
+* News-3.20.13:: Changes in release 3.20.13
+* News-3.20.11:: Changes in release 3.20.11
+* News-3.20.10:: Changes in release 3.20.10
+* News-3.20.9:: Changes in release 3.20.9
+* News-3.20.8:: Changes in release 3.20.8
+* News-3.20.7:: Changes in release 3.20.7
+* News-3.20.6:: Changes in release 3.20.6
+* News-3.20.3:: Changes in release 3.20.3
+* News-3.20.0:: Changes in releases 3.20.0
+@end menu
+
+@node News-3.20.18, News-3.20.17, News-3.20.x, News-3.20.x
+@appendixsubsec Changes in release 3.20.18
+
+@itemize @bullet
+@item
+Added @code{-p#} (remove @code{#} directories from path) to @code{isamlog}.
+All files are written with a relative path from the database directory
+Now @code{mysqld} shouldn't crash on shutdown when using the
+@code{--log-isam} option.
+@item
+New @code{mysqlperl} version. It is now compatible with @code{msqlperl-0.63}.
+@item
+New @code{DBD} module available at @uref{http://www.mysql.com/Downloads/Contrib/}
+site.
+@item
+Added group function @code{STD()} (standard deviation).
+@item
+The @code{mysqld} server is now compiled by default without debugging
+information. This will make the daemon smaller and faster.
+@item
+Now one usually only has to specify the @code{--basedir} option to
+@code{mysqld}. All other paths are relative in a normal installation.
+@item
+@code{BLOB} columns sometimes contained garbage when used with a @code{SELECT}
+on more than one table and @code{ORDER BY}.
+@item
+Fixed that calculations that are not in @code{GROUP BY} work as expected
+(ANSI SQL extension).
+Example:
+@example
+mysql> SELECT id,id+1 FROM table GROUP BY id;
+@end example
+@item
+The test of using @code{MYSQL_PWD} was reversed. Now @code{MYSQL_PWD} is
+enabled as default in the default release.
+@item
+Fixed conversion bug which caused @code{mysqld} to core dump with
+Arithmetic error on Sparc-386.
+@item
+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.
+@end itemize
+
+@node News-3.20.17, News-3.20.16, News-3.20.18, News-3.20.x
+@appendixsubsec Changes in release 3.20.17
+
+@itemize @bullet
+@item
+You can now use @code{BLOB} columns and the functions @code{IS NULL} and
+@code{IS NOT NULL} in the @code{WHERE} clause.
+@item
+All communication packets and row buffers are now allocated dynamically
+on demand. The default value of @code{max_allowed_packet} is now 64K for
+the server and 512K for the client. This is mainly used to catch
+incorrect packets that could trash all memory. The server limit may be
+changed when it is started.
+@item
+Changed stack usage to use less memory.
+@item
+Changed @code{safe_mysqld} to check for running daemon.
+@item
+The @code{ELT()} function is renamed to @code{FIELD()}. The new
+@code{ELT()} function returns a value based on an index: @code{FIELD()}
+is the inverse of @code{ELT()} Example: @code{ELT(2,"A","B","C")} returns
+@code{"B"}. @code{FIELD("B","A","B","C")} returns @code{2}.
+@item
+@code{COUNT(field)}, where @code{field} could have a @code{NULL} value, now
+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.
+@item
+Fixed some small bugs in the grant code.
+@item
+If hostname isn't found by @code{get_hostname}, only the IP is checked.
+Previously, you got @code{Access denied}.
+@item
+Inserts of timestamps with values didn't always work.
+@item
+@code{INSERT INTO ... SELECT ... WHERE} could give the error
+@code{Duplicated field}.
+@item
+Added some tests to @code{safe_mysqld} to make it ``safer''.
+@item
+@code{LIKE} was case sensitive in some places and case insensitive in others.
+Now @code{LIKE} is always case insensitive.
+@item
+@file{mysql.cc}: Allow @code{'#'} anywhere on the line.
+@item
+New command @code{SET OPTION SQL_SELECT_LIMIT=#}. See the FAQ for more details.
+@item
+New version of the @code{mysqlaccess} script.
+@item
+Change @code{FROM_DAYS()} and @code{WEEKDAY()} to also take a full
+@code{TIMESTAMP} or @code{DATETIME} as argument. Before they only took a
+number of type @code{YYYYMMDD} or @code{YYMMDD}.
+@item
+Added new function @code{UNIX_TIMESTAMP(timestamp_column)}.
+@end itemize
+
+@node News-3.20.16, News-3.20.15, News-3.20.17, News-3.20.x
+@appendixsubsec Changes in release 3.20.16
+
+@itemize @bullet
+@item
+More changes in MIT-pthreads to get them safer. Fixed also some link
+bugs at least in SunOS.
+@item
+Changed @code{mysqld} to work around a bug in MIT-pthreads. This makes multiple
+small @code{SELECT} operations 20 times faster. Now @code{lock_test.pl} should
+work.
+@item
+Added @code{mysql_FetchHash(handle)} to @code{mysqlperl}.
+@item
+The @code{mysqlbug} script is now distributed built to allow for reporting
+bugs that appear during the build with it.
+@item
+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
+column used as key to different tables.
+@item
+Added new latin2 and Russian KOI8 character tables.
+@item
+Added support for a dummy @code{GRANT} command to satisfy Powerbuilder.
+@end itemize
+
+@node News-3.20.15, News-3.20.14, News-3.20.16, News-3.20.x
+@appendixsubsec Changes in release 3.20.15
+
+@itemize @bullet
+@item
+Fixed fatal bug @code{packets out of order} when using MIT-pthreads.
+@item
+Removed possible loop when a thread waits for command from client
+and @code{fcntl()} fails. Thanks to Mike Bretz for finding this bug.
+@item
+Changed alarm loop in @file{mysqld.cc} because shutdown didn't always
+succeed in Linux.
+@item
+Removed use of @code{termbits} from @file{mysql.cc}. This conflicted with
+@code{glibc} 2.0.
+@item
+Fixed some syntax errors for at least BSD and Linux.
+@item
+Fixed bug when doing a @code{SELECT} as superuser without a database.
+@item
+Fixed bug when doing @code{SELECT} with group calculation to outfile.
+@end itemize
+
+@node News-3.20.14, News-3.20.13, News-3.20.15, News-3.20.x
+@appendixsubsec Changes in release 3.20.14
+
+@itemize @bullet
+@item
+If one gives @code{-p} or @code{--password} option to @code{mysql} without
+an argument, the user is solicited for the password from the tty.
+@item
+Added default password from @code{MYSQL_PWD} (by Elmar Haneke).
+@item
+Added command @code{kill} to @code{mysqladmin} to kill a specific
+@strong{MySQL} thread.
+@item
+Sometimes when doing a reconnect on a down connection this succeeded
+first on second try.
+@item
+Fixed adding an @code{AUTO_INCREMENT} key with @code{ALTER_TABLE}.
+@item
+@code{AVG()} gave too small value on some @code{SELECT}s with
+@code{GROUP BY} and @code{ORDER BY}.
+@item
+Added new @code{DATETIME} type (by Giovanni Maruzzelli
+@email{maruzz@@matrice.it}).
+@item
+Fixed that define @code{DONT_USE_DEFAULT_FIELDS} works.
+@item
+Changed to use a thread to handle alarms instead of signals on Solaris to
+avoid race conditions.
+@item
+Fixed default length of signed numbers. (George Harvey
+@email{georgeh@@pinacl.co.uk}.)
+@item
+Allow anything for @code{CREATE INDEX}.
+@item
+Add prezeros when packing numbers to @code{DATE}, @code{TIME} and
+@code{TIMESTAMP}.
+@item
+Fixed a bug in @code{OR} of multiple tables (gave empty set).
+@item
+Added many patches to MIT-pthreads. This fixes at least one lookup bug.
+@end itemize
+
+@node News-3.20.13, News-3.20.11, News-3.20.14, News-3.20.x
+@appendixsubsec Changes in release 3.20.13
+
+@itemize @bullet
+@item
+Added ANSI SQL94 @code{DATE} and @code{TIME} types.
+@item
+Fixed bug in @code{SELECT} with @code{AND}-@code{OR} levels.
+@item
+Added support for Slovenian characters. The @file{Contrib} directory contains
+source and instructions for adding other character sets.
+@item
+Fixed bug with @code{LIMIT} and @code{ORDER BY}.
+@item
+Allow @code{ORDER BY} and @code{GROUP BY} on items that aren't in the
+@code{SELECT} list.
+(Thanks to Wim Bonis @email{bonis@@kiss.de}, for pointing this out.)
+@item
+Allow setting of timestamp values in @code{INSERT}.
+@item
+Fixed bug with @code{SELECT ... WHERE ... = NULL}.
+@item
+Added changes for @code{glibc} 2.0. To get @code{glibc} to work, you should
+add the @file{gibc-2.0-sigwait-patch} before compiling @code{glibc}.
+@item
+Fixed bug in @code{ALTER TABLE} when changing a @code{NOT NULL} field to
+allow @code{NULL} values.
+@item
+Added some ANSI92 synonyms as field types to @code{CREATE TABLE}.
+@code{CREATE TABLE} now allows @code{FLOAT(4)} and @code{FLOAT(8)} to mean
+@code{FLOAT} and @code{DOUBLE}.
+@item
+New utility program @code{mysqlaccess} by @email{Yves.Carlier@@rug.ac.be}.
+This program shows the access rights for a specific user and the grant
+rows that determine this grant.
+@item
+Added @code{WHERE const op field} (by @email{bonis@@kiss.de}).
+@end itemize
+
+@node News-3.20.11, News-3.20.10, News-3.20.13, News-3.20.x
+@appendixsubsec Changes in release 3.20.11
+
+@itemize @bullet
+@item
+When using @code{SELECT ... INTO OUTFILE}, all temporary tables are ISAM
+instead of HEAP to allow big dumps.
+@item
+Changed date functions to be string functions. This fixed some ``funny''
+side effects when sorting on dates.
+@item
+Extended @code{ALTER TABLE} according to SQL92.
+@item
+Some minor compability changes.
+@item
+Added @code{--port} and @code{--socket} options to all utility programs and
+@code{mysqld}.
+@item
+Fixed MIT-pthreads @code{readdir_r()}. Now @code{mysqladmin create database}
+and @code{mysqladmin drop database} should work.
+@item
+Changed MIT-pthreads to use our @code{tempnam()}. This should fix the ``sort
+aborted'' bug.
+@item
+Added sync of records count in @code{sql_update}. This fixed slow updates
+on first connection. (Thanks to Vaclav Bittner for the test.)
+@end itemize
+
+@node News-3.20.10, News-3.20.9, News-3.20.11, News-3.20.x
+@appendixsubsec Changes in release 3.20.10
+
+@itemize @bullet
+@item
+New insert type: @code{INSERT INTO ... SELECT ...}
+@item
+@code{MEDIUMBLOB} fixed.
+@item
+Fixed bug in @code{ALTER TABLE} and @code{BLOB}s.
+@item
+@code{SELECT ... INTO OUTFILE} now creates the file in the current
+database directory.
+@item
+@code{DROP TABLE} now can take a list of tables.
+@item
+Oracle synonym @code{DESCRIBE} (@code{DESC}).
+@item
+Changes to @code{make_binary_distribution}.
+@item
+Added some comments to installation instructions about @code{configure}'s
+C++ link test.
+@item
+Added @code{--without-perl} option to @code{configure}.
+@item
+Lots of small portability changes.
+@end itemize
+
+@node News-3.20.9, News-3.20.8, News-3.20.10, News-3.20.x
+@appendixsubsec Changes in release 3.20.9
+
+@itemize @bullet
+@item
+@code{ALTER TABLE} didn't copy null bit. As a result, fields that were allowed
+to have @code{NULL} values were always @code{NULL}.
+@item
+@code{CREATE} didn't take numbers as @code{DEFAULT}.
+@item
+Some compatibility changes for SunOS.
+@item
+Removed @file{config.cache} from old distribution.
+@end itemize
+
+@node News-3.20.8, News-3.20.7, News-3.20.9, News-3.20.x
+@appendixsubsec Changes in release 3.20.8
+
+@itemize @bullet
+@item
+Fixed bug with @code{ALTER TABLE} and multi-part keys.
+@end itemize
+
+@node News-3.20.7, News-3.20.6, News-3.20.8, News-3.20.x
+@appendixsubsec Changes in release 3.20.7
+
+@itemize @bullet
+@item
+New commands: @code{ALTER TABLE}, @code{SELECT ... INTO OUTFILE} and
+@code{LOAD DATA INFILE}.
+@item
+New function: @code{NOW()}.
+@item
+Added new field @strong{file_priv} to @code{mysql/user} table.
+@item
+New script @code{add_file_priv} which adds the new field @strong{file_priv}
+to the @code{user} table. This script must be executed if you want to
+use the new @code{SELECT ... INTO} and @code{LOAD DATA INFILE ...} commands
+with a version of @strong{MySQL} earlier than 3.20.7.
+@item
+Fixed bug in locking code, which made @code{lock_test.pl} test fail.
+@item
+New files @file{NEW} and @file{BUGS}.
+@item
+Changed @file{select_test.c} and @file{insert_test.c} to include
+@file{config.h}.
+@item
+Added command @code{status} to @code{mysqladmin} for short logging.
+@item
+Increased maximum number of keys to 16 and maximum number of key parts to 15.
+@item
+Use of sub keys. A key may now be a prefix of a string field.
+@item
+Added @code{-k} option to @code{mysqlshow}, to get key information for a table.
+@item
+Added long options to @code{mysqldump}.
+@end itemize
+
+@node News-3.20.6, News-3.20.3, News-3.20.7, News-3.20.x
+@appendixsubsec Changes in release 3.20.6
+
+@itemize @bullet
+@item
+Portable to more systems because of MIT-pthreads, which will
+be used automatically if @code{configure} cannot find a @code{-lpthreads}
+library.
+@item
+Added GNU-style long options to almost all programs. Test with
+@code{@kbd{program} --help}.
+@item
+Some shared library support for Linux.
+@item
+The FAQ is now in @file{.texi} format and is available in @file{.html},
+@file{.txt} and @file{.ps} formats.
+@item
+Added new SQL function @code{RAND([init])}.
+@item
+Changed @code{sql_lex} to handle @code{\0} unquoted, but the client can't send
+the query through the C API, because it takes a str pointer.
+You must use @code{mysql_real_query()} to send the query.
+@item
+Added API function @code{mysql_get_client_info()}.
+@item
+@code{mysqld} now uses the @code{N_MAX_KEY_LENGTH} from @file{nisam.h} as
+the maximum allowed key length.
+@item
+The following now works:
+@example
+mysql> SELECT filter_nr,filter_nr FROM filter ORDER BY filter_nr;
+@end example
+Previously, this resulted in the error:
+@code{Column: 'filter_nr' in order clause is ambiguous}.
+@item
+@code{mysql} now outputs @code{'\0'}, @code{'\t'}, @code{'\n'} and @code{'\\'}
+when encountering ASCII 0, tab, newline or @code{'\'} while writing
+tab-separated output.
+This is to allow printing of binary data in a portable format.
+To get the old behavior, use @code{-r} (or @code{--raw}).
+@item
+Added german error messages (60 of 80 error messages translated).
+@item
+Added new API function @code{mysql_fetch_lengths(MYSQL_RES *)}, which
+returns an array of 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
+part.
+@item
+Added @code{SELECT} option @code{STRAIGHT_JOIN} to tell the optimizer that
+it should join tables in the given order.
+@item
+Added support for comments starting with @code{'--'} in @file{mysql.cc}
+(Postgres syntax).
+@item
+You can have @code{SELECT} expressions and table columns in a @code{SELECT}
+which are not used in the group part. This makes it efficient to implement
+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;
+@end example
+@item
+Fixed bug in @code{SUM(function)} (could cause a core dump).
+@item
+Changed @code{AUTO_INCREMENT} placement in the SQL query:
+@example
+INSERT into table (auto_field) values (0);
+@end example
+inserted 0, but it should insert an @code{AUTO_INCREMENT} value.
+@item
+@file{mysqlshow.c}: Added number of records in table. Had to change the
+client code a little to fix this.
+@item
+@code{mysql} now allows doubled @code{''} or @code{""} within strings for
+embedded @code{'} or @code{"}.
+@item
+New math functions:
+@code{EXP()}, @code{LOG()}, @code{SQRT()}, @code{ROUND()}, @code{CEILING()}.
+@end itemize
+
+@node News-3.20.3, News-3.20.0, News-3.20.6, News-3.20.x
+@appendixsubsec Changes in release 3.20.3
+
+@itemize @bullet
+@item
+The @code{configure} source now compiles a thread-free client library
+@code{-lmysqlclient}. This is the only library that needs to be linked
+with client applications. When using the binary releases, you must
+link with @code{-lmysql -lmysys -ldbug -lstrings} as before.
+@item
+New @code{readline} library from @code{bash-2.0}.
+@item
+LOTS of small changes to @code{configure} and makefiles (and related source).
+@item
+It should now be possible to compile in another directory using
+@code{VPATH}. Tested with GNU Make 3.75.
+@item
+@code{safe_mysqld} and @code{mysql.server} changed to be more compatible
+between the source and the binary releases.
+@item
+@code{LIMIT} now takes one or two numeric arguments.
+If one argument is given, it indicates the maximum number of rows in
+a result. If two arguments are given, the first argument indicates the offset
+of the first row to return, the second is the maximum number of rows.
+With this it's easy to do a poor man's next page/previous page WWW
+application.
+@item
+Changed name of SQL function @code{FIELDS()} to @code{ELT()}.
+Changed SQL function @code{INTERVALL()} to @code{INTERVAL()}.
+@item
+Made @code{SHOW COLUMNS} a synonym for @code{SHOW FIELDS}.
+Added compatibility syntax @code{FRIEND KEY} to @code{CREATE TABLE}. In
+@strong{MySQL}, this creates a non-unique key on the given columns.
+@item
+Added @code{CREATE INDEX} and @code{DROP INDEX} as compatibility functions.
+In @strong{MySQL}, @code{CREATE INDEX} only checks if the index exists and
+issues an error if it doesn't exist. @code{DROP INDEX} always succeeds.
+@item
+@file{mysqladmin.c}: added client version to version information.
+@item
+Fixed core dump bug in @code{sql_acl} (core on new connection).
+@item
+Removed @code{host}, @code{user} and @code{db} tables from database @code{test}
+in the distribution.
+@item
+@code{FIELD_TYPE_CHAR} can now be signed (-128 - 127) or unsigned (0 - 255)
+Previously, it was always unsigned.
+@item
+Bug fixes in @code{CONCAT()} and @code{WEEKDAY()}.
+@item
+Changed a lot of source to get @code{mysqld} to be compiled with SunPro
+compiler.
+@item
+SQL functions must now have a @code{'('} immediately after the function name
+(no intervening space).
+For example, @code{'user('} is regarded as beginning a function call, and
+@code{'user ('} is regarded as an identifier @code{user} followed by a
+@code{'('}, not as a function call.
+@end itemize
+
+@node News-3.20.0, , News-3.20.3, News-3.20.x
+@appendixsubsec Changes in release 3.20.0
+
+@itemize @bullet
+@item
+The source distribution is done with @code{configure} and Automake.
+It will make porting much easier. The @code{readline} library is included
+in the distribution.
+@item
+Separate client compilation:
+the client code should be very easy to compile on systems which
+don't have threads.
+@item
+The old Perl interface code is automatically compiled and installed.
+Automatic compiling of @code{DBD} will follow when the new @code{DBD} code
+is ported.
+@item
+Dynamic language support: @code{mysqld} can now be started with Swedish
+or English (default) error messages.
+@item
+New functions: @code{INSERT()}, @code{RTRIM()}, @code{LTRIM()} and
+@code{FORMAT()}.
+@item
+@code{mysqldump} now works correctly for all field types (even
+@code{AUTO_INCREMENT}). The format for @code{SHOW FIELDS FROM tbl_name}
+is changed so the @code{Type} column contains information suitable for
+@code{CREATE TABLE}. In previous releases, some @code{CREATE TABLE}
+information had to be patched when recreating tables.
+@item
+Some parser bugs from 3.19.5 (@code{BLOB} and @code{TIMESTAMP}) are corrected.
+@code{TIMESTAMP} now returns different date information depending on its
+create length.
+@item
+Changed parser to allow a database, table or field name to
+start with a number or @code{'_'}.
+@item
+All old C code from Unireg changed to C++ and cleaned up. This makes
+the daemon a little smaller and easier to understand.
+@item
+A lot of small bug fixes done.
+@item
+New @file{INSTALL} files (not final version) and some info regarding porting.
+@end itemize
+
+@node News-3.19.x, , News-3.20.x, News
+@appendixsec Changes in release 3.19.x
+
+@menu
+* News-3.19.5:: Changes in release 3.19.5
+* News-3.19.4:: Changes in release 3.19.4
+* News-3.19.3:: Changes in release 3.19.3
+@end menu
+
+@node News-3.19.5, News-3.19.4, News-3.19.x, News-3.19.x
+@appendixsubsec Changes in release 3.19.5
+
+@itemize @bullet
+@item
+Some new functions, some more optimization on joins.
+@item
+Should now compile clean on Linux (2.0.x).
+@item
+Added functions @code{DATABASE()}, @code{USER()}, @code{POW()},
+@code{LOG10()} (needed for ODBC).
+@item
+In a @code{WHERE} with an @code{ORDER BY} on fields from only one table,
+the table is now preferred as first table in a multi-join.
+@item
+@code{HAVING} and @code{IS NULL} or @code{IS NOT NULL} now works.
+@item
+A group on one column and a sort on a group function (@code{SUM()},
+@code{AVG()}...) didn't work together. Fixed.
+@item
+@code{mysqldump}: Didn't send password to server.
+@end itemize
+
+@node News-3.19.4, News-3.19.3, News-3.19.5, News-3.19.x
+@appendixsubsec Changes in release 3.19.4
+
+@itemize @bullet
+@item
+Fixed horrible locking bug when inserting in one thread and reading
+in another thread.
+@item
+Fixed one-off decimal bug. 1.00 was output as 1.0.
+@item
+Added attribute @code{'Locked'} to process list as info if a query is
+locked by another query.
+@item
+Fixed full magic timestamp. Timestamp length may now be 14, 12, 10, 8, 6, 4
+or 2 bytes.
+@item
+Sort on some numeric functions could sort incorrectly on last number.
+@item
+@code{IF(arg,syntax_error,syntax_error)} crashed.
+@item
+Added functions @code{CEILING()}, @code{ROUND()}, @code{EXP()}, @code{LOG()} and @code{SQRT()}.
+@item
+Enhanced @code{BETWEEN} to handle strings.
+@end itemize
+
+@node News-3.19.3, , News-3.19.4, News-3.19.x
+@appendixsubsec Changes in release 3.19.3
+
+@itemize @bullet
+@item
+Fixed @code{SELECT} with grouping on @code{BLOB} columns not to return
+incorrect @code{BLOB} info. Grouping, sorting and distinct on @code{BLOB}
+columns will not yet work as
+expected (probably it will group/sort by the first 7 characters in the
+@code{BLOB}). Grouping on formulas with a fixed string size (use @code{MID()}
+on a @code{BLOB}) should work.
+@item
+When doing a full join (no direct keys) on multiple tables with @code{BLOB}
+fields, the @code{BLOB} was garbage on output.
+@item
+Fixed @code{DISTINCT} with calculated columns.
+@end itemize
+
+@node Bugs, TODO, News, Top
+@appendix Known errors and design deficiencies in MySQL
+
+The following is known bugs in @strong{MySQL} 3.23.22 that will be fixed
+in the next release:
+@itemize @bullet
+@item
+Searching on part keys on BDB tables doesn't return all rows:
+
+@example
+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;
+@end example
+@end itemize
+
+Other known problems:
+
+@itemize @bullet
+@item
+You cannot build in another directory when using
+MIT-pthreads. Because this requires changes to MIT-pthreads, we are not
+likely to fix this.
+@item
+@code{BLOB} values can't ``reliably'' be used in @code{GROUP BY} or
+@code{ORDER BY} or @code{DISTINCT}. Only the first @code{max_sort_length}
+bytes (default 1024) are used when comparing @code{BLOB}bs in these cases.
+This can be changed with the @code{-O max_sort_length} option to
+@code{mysqld}. A workaround for most cases is to use a substring:
+@code{SELECT DISTINCT LEFT(blob,2048) FROM tbl_name}.
+@item
+Calculation is done with @code{BIGINT} or @code{DOUBLE} (both are
+normally 64 bits long). It depends on the function which precision one
+gets. The general rule is that bit functions are done with @code{BIGINT}
+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!
+@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 @strong{MySQL}, @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.
+@item
+@code{safe_mysqld} re-directs all messages from @code{mysqld} to the
+@code{mysqld} log. One problem with this is that if you execute
+@code{mysqladmin refresh} to close and reopen the log,
+@code{stdout} and @code{stderr} are still redirected to the old log.
+If you use @code{--log} extensively, you should edit @code{safe_mysqld} to
+log to @file{'hostname'.err} instead of @file{'hostname'.log} so you can
+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 you refer to a updated column, you will get the updated value instead of the
+original value. For example:
+@example
+mysql> UPDATE tbl_name SET KEY=KEY+1,KEY=KEY+1
+@end example
+will update @code{KEY} with @code{2} instead of with @code{1}.
+@item
+You can't use temporary tables more than once in the same query.
+
+@example
+select * from temporary_table, temporary_table as t2;
+@end example
+
+@item
+Because @strong{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 @strong{MySQL} than in other SQL servers:
+(This is just to ensure that @strong{MySQL} never need to do a rollback
+for a SQL command). This may be a little akward at times as column
+values must be checked in the application, but this will actually give
+you a nice speed increase as it allows @strong{MySQL} to do some
+optimizations that otherwice would be very hard to do.
+
+If you set a colum to a wrong value, @strong{MySQL} will instead of doing
+a rollback instead store the @code{best possible value} in the column.
+
+@itemize @bullet
+@item
+If you try to store a value outside of the range in a numerical column,
+@strong{MySQL} 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 @strong{MySQL} will store 0 into it.
+@item
+If you try to to store @code{NULL} into a column that doesn't take
+@code{NULL} values, @code{MySQL} will store 0 or @code{''} (empty
+string) in it instead. (This behavour can however be changed with the
+-DDONT_USE_DEFAULT_FIELDS compile option).
+@item
+@strong{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, @strong{MySQL} will store the special
+0000-00-00 date value in the column.
+@item
+If you set an @code{enum} to an not supported value, it will be set to
+the error value 'empty string', with numeric value 0.
+@end itemize
+@item
+If you execute a @code{PROCEDURE} on a query with returns an empty set then
+in some cases the @code{PROCEDURE} will not transform the columns.
+@end itemize
+
+The following is known bugs in earlier versions of @strong{MySQL}:
+
+@itemize @bullet
+@item
+You can get a hanged thread if you do a @code{DROP TABLE} on a table that is
+one among many tables that is locked with @code{LOCK TABLES}.
+
+@item
+In the following case you can get a core dump:
+@enumerate
+@item
+Delayed insert handler has pending inserts to a table.
+@item
+@code{LOCK table} with @code{WRITE}
+@item
+@code{FLUSH TABLES}
+@end enumerate
+
+@item
+Before @strong{MySQL} 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:
+
+@example
+UPDATE tbl_name SET KEY=KEY+1 WHERE KEY > 100;
+@end example
+
+A workaround is to use:
+
+@example
+mysql> UPDATE tbl_name SET KEY=KEY+1 WHERE KEY+0 > 100;
+@end example
+
+This will work because @strong{MySQL} will not use index on expressions in
+the @code{WHERE} clause.
+@item
+Before @strong{MySQL} 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.
+
+@cindex TODO
+@node TODO, Porting, Bugs, Top
+@appendix List of things we want to add to MySQL in the future (The TODO)
+
+@menu
+* TODO future:: Things that must done in the very 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
+
+Everything in this list is 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}.
+
+@node TODO future, TODO sometime, TODO, TODO
+@appendixsec Things that must done in the real near future
+
+@itemize @bullet
+@item
+Fail safe replication.
+@item
+Optimize, test and document transactions safe tables
+@item
+Subqueries. @code{select id from t where grp in (select grp from g where u > 100)}
+@item
+Port of @strong{MySQL} to BeOS.
+@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
+@code{RENAME table as table, table as table [,...]}
+@item
+Allow users to change startup options.
+@item
+FreeBSD and MIT-pthreads; Do sleeping threads take CPU?
+@item
+Check if locked threads take any CPU.
+@item
+Change to use mkstemp() instead of tempnam() for system that supports the call.
+We need to add a my_mkstemp() function in mysys and also change the cache
+code to not create the filename until we do the actual open.
+@item
+Allow join on key parts (optimization issue).
+@item
+Entry for @code{DECRYPT()}.
+@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
+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
+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 @code{ORDER BY} to update. This would be handy with functions like:
+@code{generate_id(start,step)}.
+@item
+Add an @code{IMAGE} option to @code{LOAD DATA INFILE} to not update
+@code{TIMESTAMP} and @code{AUTO_INCREMENT} fields.
+@item
+Make @code{LOAD DATA INFILE} understand a 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
+@item
+@code{LOAD DATA INFILE 'file_name' INTO TABLE 'table_name' ERRORS TO err_table_name}
+which would cause any errors/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
+We should extend @code{LOAD DATA INFILE} so that we can skip over extra
+columns in the text file.
+@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
+Fix @code{mysql.cc} to do fewer @code{malloc()} calls when hashing field
+names.
+@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
+Function @code{CASE}.
+@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. Key buffer read/write hits (logical and real).
+@code{ORDER BY}, @code{GROUP BY}, temporary tables created.
+@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}.
+@item
+Oracle like @code{CONNECT BY PRIOR ...} to search hierarchy structures.
+@item
+@code{RENAME DATABASE}
+@item
+@code{mysqladmin copy database new-database}.
+@item
+Processlist should show number of queries/thread.
+@item
+@code{DELETE} and @code{REPLACE} options to the @code{UPDATE} statement
+(this will delete rows when one gets a dupplicate 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
+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 when columns referenced in an @code{UPDATE} clause contains the old
+values before the update started.
+@item
+Allow update of varibles in @code{UPDATE} statements. For example:
+@code{UPDATE TABLE foo SET @@a=a+b,a=@@a, b=@@a+c}
+@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.
+@end itemize
+
+@node TODO sometime, TODO unplanned, TODO future, TODO
+@appendixsec Things that have to be done sometime
+
+@itemize @bullet
+@item
+Implement function: @code{get_changed_tables(timeout,table1,table2,...)}
+@item
+Atomic updates; This includes a language that one can even use for
+a set of stored procedures.
+@item
+@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
+Make a @code{mysqld} version which isn't multithreaded (3-5 days).
+@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
+Better dynamic record layout to avoid fragmentation.
+@item
+@code{UPDATE SET blob=read_blob_from_file('my_gif') where id=1;}
+@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 @strong{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
+Reuse threads for systems with a lot of connections.
+@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
+@appendixsec 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 Porting, Regexp, TODO, Top
+@appendix Comments on porting to other systems
+
+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
+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}.
+
+The @strong{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
+have POSIX threads.
+
+It is also possible to use another user level thread package named
+FSU Pthreads (see
+@uref{http://www.informatik.hu-berlin.de/~mueller/pthreads.html, FSU Pthreads
+home page}). This implementation is being used for the SCO port.
+
+See the @file{thr_lock.c} and @file{thr_alarm.c} programs in the @file{mysys}
+directory for some tests/examples of these problems.
+
+Both the server and the client need a working C++ compiler (we use @code{gcc}
+and have tried SparcWorks). Another compiler that is known to work is the
+Irix @code{cc}.
+
+To compile only the client use @code{./configure --without-server}.
+
+There is currently no support for only compiling the server, nor is it
+likly to be added unless someone has a good reason for it.
+
+If you want/need to change any @file{Makefile} or the configure script you must
+get Automake and Autoconf. We have used the @code{automake-1.2} and
+@code{autoconf-2.12} distributions.
+
+All steps needed to remake everything from the most basic files.
+
+@example
+/bin/rm */.deps/*.P
+/bin/rm -f config.cache
+aclocal
+autoheader
+aclocal
+automake
+autoconf
+./configure --with-debug --prefix='your installation directory'
+
+# The makefiles generated above need GNU make 3.75 or newer.
+# (called gmake below)
+gmake clean all install init-db
+@end example
+
+If you run into problems with a new port, you may have to do some debugging
+of @strong{MySQL}!
+@xref{Debugging server}.
+
+@strong{Note:} Before you start debugging @code{mysqld}, first get the test
+programs @code{mysys/thr_alarm} and @code{mysys/thr_lock} to work. This
+will ensure that your thread installation has even a remote chance to work!
+
+@menu
+* Debugging server:: Debugging a @strong{MySQL} server
+* Debugging client:: Debugging a @strong{MySQL} client
+* The DBUG package:: The DBUG package
+* Locking methods::
+* RTS-threads:: Comments about RTS threads
+* Thread packages:: Differences between different thread packages
+@end menu
+
+@node Debugging server, Debugging client, Porting, Porting
+@appendixsec Debugging a MySQL server
+
+If you are using some functionality that is very new in @strong{MySQL},
+you can try to run 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.
+@xref{Crashing}.
+
+If @code{mysqld} doesn't want to start, you should check that you don't have
+any @code{my.cnf} files that interfere with your setup!
+You can check your @code{my.cnf} arguments with @code{mysqld --print-defaults}
+and avoid using them by starting with @code{mysqld --no-defaults ...}.
+
+If you have some very specific problem, you can always try to debug
+@strong{MySQL}. To do this you must configure @strong{MySQL} with the
+option @code{--with-debug}. You can check whether or not
+@strong{MySQL} was compiled with debugging by doing: @code{mysqld
+--help}. If the @code{--debug} flag is listed with the options then you
+have debugging enabled. @code{mysqladmin ver} also 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="-O6" CXX=gcc CXXFLAGS="-O6 -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++
+exceptions (many compilers have problems with C++ exceptions in threaded
+code) and compile a @strong{MySQL} version with support for all character sets.
+
+If @code{mysqld} stops crashing when you compile it with
+@code{--with-debug}, you have probably found a compiler bug or a timing
+bug within @strong{MySQL}. In this case you can try to add @code{-g} to
+the @code{CFLAGS} and @code{CXXFLAGS} variables above and not use
+@code{--with-debug}. If @code{mysqld} now dies, you can at least attach
+to it with @code{gdb} or use @code{gdb} on the core file to find out
+what happened.
+
+If you can cause the @code{mysqld} server to crash quickly, you can try to
+create a trace file of this:
+
+Start the @code{mysqld} server with a trace log in @file{/tmp/mysql.trace}.
+The log file will get very @emph{BIG}.
+
+@code{mysqld --debug --log}
+
+or you can start it with
+
+@code{mysqld --debug=d,info,error,query,general,where:O,/tmp/mysql.trace}
+
+which only prints information with the most interesting tags.
+
+When you configure @strong{MySQL} for debugging you automatically enable a
+lot of extra safety check functions that monitor the health of @code{mysqld}.
+If they find something ``unexpected,'' an entry will be written to
+@code{stderr}, which @code{safe_mysqld} directs to the error log! This also
+means that if you are having some unexpected problems with @strong{MySQL} and
+are using a source distribution, the first thing you should do is to
+configure @strong{MySQL} for debugging! (The second thing, of course, is to
+send mail to @email{mysql@@lists.mysql.com} and ask for help. Please use the
+@code{mysqlbug} script for all bug reports or questions regarding the
+@strong{MySQL} version you are using!
+
+On most system you can also start @code{mysqld} from @code{gdb} to get
+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.
+
+It's very hard to debug @strong{MySQL} under @code{gdb} if you do a lot of
+new connections the whole time as @code{gdb} doesn't free the memory for
+old threads. You can avoid this problem by starting @code{mysqld} with
+@code{-O thread_cache_size= 'max_connections +1'}. In most cases just
+using @code{-O thread_cache_size= 5'} will help a lot!
+
+If you are using gdb 4.17.x or above on Linux, you should install a
+@file{.gdb} file, with the following information, in your current
+directory:
+
+@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
+
+If you have problems debugging threads with gdb, you should download
+gdb 5.x and try this instead. The new gdb version has very improved
+thread handling!
+
+Here follows an example how to debug mysqld:
+
+@example
+shell> gdb /usr/local/libexec/mysqld
+gdb> run
+...
+back # Do this when mysqld crashes
+info locals
+up
+info locals
+up
+...
+(until you get some information about local variables)
+
+quit
+@end example
+
+Include the above output in a mail generated with @code{mysqlbug} and
+mail this to @code{mysql@@lists.mysql.com}.
+
+If @code{mysqld} hangs you can try to use some system tools like
+@code{strace} or @code{/usr/proc/bin/pstack} to examine where
+@code{mysqld} has hung.
+
+If @code{mysqld} starts to eat up CPU or memory or if it ``hangs'', you
+can use @code{mysqladmin processlist status} to find out if someone is
+executing a query that takes a long time. It may be a good idea to
+run @code{mysqladmin -i10 processlist status} in some window if you are
+experiencing performance problems or problems when new clients can't connect.
+
+If @code{mysqld} dies or hangs, you should start @code{mysqld} with
+@code{--log}. When @code{mysqld} dies again, you can check in the log
+file for the query that killed @code{mysqld}. Note that before starting
+@code{mysqld} with @code{--log} you should check all your tables with
+@code{myisamchk}. @xref{Maintenance}.
+
+If you are using a log file, @code{mysqld --log}, you should check the
+'hostname' log files, that you can find in the database directory, for
+any queries that could cause a problem. Try the command @code{EXPLAIN}
+on all @code{SELECT} statements that takes a long time to ensure that
+mysqld are using indexes properly. @xref{EXPLAIN, , @code{EXPLAIN}}. You
+should also test complicated queries that didn't complete within the
+@code{mysql} command line tool.
+
+If you find the text @code{mysqld restarted} in the error log file (normally
+named @file{hostname.err}) you have probably found a query that causes
+@code{mysqld} to fail. If this happens you should check all your tables with
+@code{myisamchk} (@pxref{Maintenance}), and test the queries in the
+@strong{MySQL} log files to see if one doesn't work. If you find such a query,
+try first upgrading to the newest @strong{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/, @strong{MySQL}
+documentation page}.
+
+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
+following:
+
+@itemize @bullet
+@item
+Stop the mysqld daemon (with @code{mysqladmin shutdown})
+@item
+Check all tables with @code{myisamchk -s database/*.MYI}. Repair any
+wrong tables with @code{myisamchk -r database/table.MYI}.
+@item
+Start @code{mysqld} with @code{--log-update}. @xref{Update log}.
+@item
+When you have gotten a crashed table, stop the @code{mysqld server}.
+@item
+Restore the backup.
+@item
+Restart the @code{mysqld} server @strong{without} @code{--log-update}
+@item
+Re-execute the commands with @code{mysql < update-log}. The update log
+is saved in the @strong{MySQL} database directory with the name
+@code{your-hostname.#}.
+@item
+If the tables are corrupted again, you have found reproducible bug
+in the @code{ISAM} code! FTP the tables and the update log to
+@uref{ftp://support.mysql.com/pub/mysql/secret} and we will fix this as soon as
+possible!
+@end itemize
+
+The command @code{mysqladmin debug} will dump some information about
+locks in use, used memory and query usage to the mysql log file. This
+may help solve some problems. This command also provides some useful
+information even if you haven't compiled @strong{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
+@code{myisamchk}. @xref{Maintenance}. You should also check the slow
+queries with @code{EXPLAIN}.
+
+You should also read the OS-specific section in this manual for
+problems that may be unique to your environment.
+@xref{Source install system issues}.
+
+@findex DBI->trace
+@findex trace DBI method
+@tindex DBI_TRACE environment variable
+@tindex Environment variable, DBI_TRACE
+If you are using the Perl @code{DBI} interface, you can turn on
+debugging information by using the @code{trace} method or by
+setting the @code{DBI_TRACE} environment variable.
+@xref{Perl DBI Class, , Perl @code{DBI} Class}.
+
+@node Debugging client, The DBUG package, Debugging server, Porting
+@appendixsec Debugging a MySQL client
+
+To be able to debug a @strong{MySQL} client with the integrated debug package,
+you should configure @strong{MySQL} with @code{--with-debug}.
+@xref{configure options}.
+
+@tindex MYSQL_DEBUG environment variable
+@tindex Environment variable, MYSQL_DEBUG
+Before running a client, you should set the @code{MYSQL_DEBUG} environment
+variable:
+
+@example
+shell> MYSQL_DEBUG=d:t:O,/tmp/client.trace
+shell> export MYSQL_DEBUG
+@end example
+
+This causes clients to generate a trace file in @file{/tmp/client.trace}.
+
+If you have problems with your own client code, you should attempt to
+connect to the server and run your query using a client that is known to
+work. Do this by running @code{mysql} in debugging mode (assuming you
+have compiled @strong{MySQL} with debugging on):
+
+@example
+shell> mysql --debug=d:t:O,/tmp/client.trace
+@end example
+
+This will provide useful information in case you mail a bug report.
+@xref{Bug reports}.
+
+If your client crashes at some 'legal' looking code, you should check
+that your @file{mysql.h} include file matches your mysql library file.
+A very common mistake is to use an old @file{mysql.h} file from an old
+@strong{MySQL} installation with new @strong{MySQL} library.
+
+
+@node The DBUG package, Locking methods, Debugging client, Porting
+@appendixsec The DBUG package.
+
+The @strong{MySQL} server and most @strong{MySQL} clients are compiled
+with the DBUG package originally made by Fred Fish. When one has configured
+@strong{MySQL} for debugging, this package makes it possible to get a trace
+file of what the program is debugging.
+
+One uses the debug package by invoking the program with the
+@code{--debug="..."} or the @code{-#...} option.
+
+The debug control string is a sequence of colon separated fields
+as follows:
+
+@example
+<field_1>:<field_2>:...:<field_N>
+@end example
+
+Each field consists of a mandatory flag character followed by
+an optional "," and comma separated list of modifiers:
+
+@example
+flag[,modifier,modifier,...,modifier]
+@end example
+
+The currently recognized flag characters are:
+
+@multitable @columnfractions .1 .9
+@item d @tab Enable output from DBUG_<N> macros for for the current state. May be followed by a list of keywords which selects output only for the DBUG macros with that keyword. A 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. I.E. @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.
+@item F @tab Identify the source file name for each line of debug or trace output.
+@item i @tab Identify the process with the pid or thread id for each line of debug or trace output.
+@item g @tab Enable profiling. Create a file called 'dbugmon.out' containing information that can be used to profile the program. May be followed by a list of keywords that select profiling only for the functions in that list. A null list implies that all functions are considered.
+@item L @tab Identify the source file line number for each line of debug or trace output.
+@item n @tab Print the current function nesting depth for each line of debug or trace output.
+@item N @tab Number each line of dbug output.
+@item o @tab Redirect the debugger output stream to the specified file. The default output is stderr.
+@item O @tab As @code{O} but the file is really flushed between each write. When neaded the file is closed and reopened between each write.
+@item p @tab Limit debugger actions to specified processes. A process must be identified with the DBUG_PROCESS macro and match one in the list for debugger actions to occur.
+@item P @tab Print the current process name for each line of debug or trace output.
+@item r @tab When pushing a new state, do not inherit the previous state's function nesting level. Useful when the output is to start at the left margin.
+@item S @tab Do function _sanity(_file_,_line_) at each debugged function until _sanity() returns something that differs from 0. (Mostly used with safemalloc to find memory leaks)
+@item t @tab Enable function call/exit trace lines. May be followed by a list (containing only one modifier) giving a numeric maximum trace level, beyond which no output will occur for either debugging or tracing macros. The default is a compile time option.
+@end multitable
+
+Some examples of debug control strings which might appear on a shell
+command line (the "-#" is typically used to introduce a control string
+to an application program) are:
+
+@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 @strong{MySQL}, common tags to print (with the @code{d} option) are:
+@code{enter},@code{exit},@code{error},@code{warning},@code{info} and
+@code{loop}.
+
+@node Locking methods, RTS-threads, The DBUG package, Porting
+@appendixsec Locking methods
+
+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}
+tables one can freely mix @code{INSERT} and @code{SELECT} without locks
+(@code{Versioning}).
+
+Some database users claim that @strong{MySQL} cannot support near the
+number of concurrent users because it lacks row-level locking. This is
+a 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.
+
+Pros for row locking:
+
+@itemize @bullet
+@item
+Fewer lock conflicts when accessing different rows in many threads.
+@item
+Less changes for rollbacks.
+@item
+Makes it possbile to lock a single row a long time.
+@end itemize
+
+Cons:
+
+@itemize @bullet
+@item
+Takes more memory than page level or table locks.
+@item
+Is slower than page level or table locks when used one a big part of the table,
+because one has to do many more locks.
+@item
+Is definitely much worse than other locks if you do often do @code{GROUP
+BY} on a large part of the data or if one has to often scan the whole table.
+@item
+With higher level locks one can also more easily support locks of
+different types to tune the application as the lock overhead is less
+notable as for row level locks.
+@end itemize
+
+Table locks are superior to page level / row level locks in the
+following cases:
+
+@itemize @bullet
+@item
+Mostly reads
+@item
+Read and updates on strict keys; This is where one updates or deletes
+a row that can be fetched with one key read:
+@example
+UPDATE table_name SET column=value WHERE unique_key#
+DELETE FROM table_name WHERE unique_key=#
+@end example
+@item
+@code{SELECT} combined with @code{INSERT} (and very few @code{UPDATE}'s
+and @code{DELETE}'s.
+@item
+Many scans / @code{GROUP BY} on the whole table without any writers.
+@end itemize
+
+Other options than row / page level locking:
+
+Versioning (like we use in MySQL for concurrent inserts) where you can
+have one writer at the same time as many readers. This means that the
+database/table supports different views for the data depending on when
+one started to access it. Other names for this are time travel, copy
+on write or copy on demand.
+
+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 @strong{MySQL}). This works of course
+only in well-behaved applications.
+
+In many cases one can do an educated guess which locking type is best
+for the application but generally it's very hard to say that a given
+lock type is better than another; Everything depends on the application
+and different part of the application may require different lock types.
+
+Here follows some tips about locking in @strong{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 @strong{MySQL} setup is VERY 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.
+
+If one mix a insert and deletes on the same table then @code{INSERT DELAY}
+may be of great help.
+
+One can also use @code{LOCK TABLES} to speed up things (many updates within
+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 @strong{MySQL}, you
+may be able to solve these to convert some of your tables to @code{BDB} tables.
+@xref{BDB}.
+
+The optimization section in the manual covers a lot of different aspects of
+how to tune ones application. @xref{Tips}.
+
+@node RTS-threads, Thread packages, Locking methods, Porting
+@appendixsec Comments about RTS threads
+
+I have tried to use the RTS thread packages with @strong{MySQL} but
+stumbled on the following problems:
+
+They use an old version of a lot of POSIX calls and it is very tedious to
+make wrappers for all functions. I am inclined to think that it would
+be easier to change the thread libraries to the newest POSIX
+specification.
+
+Some wrappers are already written. See @file{mysys/my_pthread.c} for more info.
+
+At least the following should be changed:
+
+@code{pthread_get_specific} should use one argument.
+@code{sigwait} should take two arguments.
+A lot of functions (at least @code{pthread_cond_wait},
+@code{pthread_cond_timedwait})
+should return the error code on error. Now they return -1 and set @code{errno}.
+
+Another problem is that user-level threads use the @code{ALRM} signal and this
+aborts a lot of functions (@code{read}, @code{write}, @code{open}...).
+@strong{MySQL} should do a retry on interrupt on all of these but it is
+not that easy to verify it.
+
+The biggest unsolved problem is the following:
+
+To get thread-level alarms I changed @file{mysys/thr_alarm.c} to wait between
+alarms with @code{pthread_cond_timedwait()}, but this aborts with error
+@code{EINTR}. I tried to debug the thread library as to why this happens,
+but couldn't find any easy solution.
+
+If someone wants to try @strong{MySQL} with RTS threads I suggest the
+following:
+
+@itemize @bullet
+@item
+Change functions @strong{MySQL} uses from the thread library to POSIX.
+This shouldn't take that long.
+@item
+Compile all libraries with the @code{-DHAVE_rts_threads}.
+@item
+Compile @code{thr_alarm}.
+@item
+If there are some small differences in the implementation, they may be fixed
+by changing @file{my_pthread.h} and @file{my_pthread.c}.
+@item
+Run @code{thr_alarm}. If it runs without any ``warning'', ``error'' or aborted
+messages, you are on the right track. Here follows a successful run on
+Solaris:
+@example
+Main thread: 1
+Tread 0 (5) started
+Thread: 5 Waiting
+process_alarm
+Tread 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
+@appendixsec Differences between different thread packages
+
+@strong{MySQL} is very dependent on the thread package used. So when
+choosing a good platform for @strong{MySQL}, the thread package is very
+important.
+
+There are at least three types of thread packages:
+
+@itemize @bullet
+@item
+User threads in a single process. Thread switching is managed with
+alarms and the threads library manages all non-thread-safe functions
+with locks. Read, write and select operations are usually managed with a
+thread-specific select that switches to another thread if the running
+threads have to wait for data. If the user thread packages are
+integrated in the standard libs (FreeBSD and BSDI threads) the thread
+package requires less overhead than thread packages that have to map all
+unsafe calls (MIT-pthreads, FSU Pthreads and RTS threads). In some
+environments (for example, SCO), all system calls are thread-safe so the
+mapping can be done very easily (FSU Pthreads on SCO). Downside: All
+mapped calls take a little time and it's quite tricky to be able to
+handle all situations. There are usually also some system calls that are
+not handled by the thread package (like MIT-pthreads and sockets). Thread
+scheduling isn't always optimal.
+@item
+User threads in separate processes. Thread switching is done by the
+kernel and all data are shared between threads. The thread package
+manages the standard thread calls to allow sharing data between threads.
+LinuxThreads is using this method. Downside: Lots of processes. Thread
+creating is slow. If one thread dies the rest are usually left hanging
+and you must kill them all before restarting. Thread switching is
+somewhat expensive.
+@item
+Kernel threads. Thread switching is handled by the thread library or the
+kernel and is very fast. Everything is done in one process, but on some
+systems, @code{ps} may show the different threads. If one thread aborts, the
+whole process aborts. Most system calls are thread-safe and should
+require very little overhead. Solaris, HP-UX, AIX and OSF1 have kernel
+threads.
+@end itemize
+
+In some systems kernel threads are managed by integrating user
+level threads in the system libraries. In such cases, the thread
+switching can only be done by the thread library and the kernel isn't
+really ``thread aware''.
+
+@node Regexp, Unireg, Porting, Top
+@appendix Description of MySQL regular expression syntax
+
+A regular expression (regex) is a powerful way of specifying a complex search.
+
+@strong{MySQL} uses Henry Spencer's implementation of regular
+expressions, which is aimed to conform to POSIX
+1003.2. @strong{MySQL} uses the extended version.
+
+This is a simplistic reference that skips the details. To get more exact
+information, see Henry Spencer's @code{regex(7)} manual page that is
+included in the source distribution. @xref{Credits}.
+
+A regular expression describes a set of strings. The simplest regexp is
+one that has no special characters in it. For example, the regexp
+@code{hello} matches @code{hello} and nothing else.
+
+Non-trivial regular expressions use certain special constructs so that
+they can match more than one string. For example, the regexp
+@code{hello|word} matches either the string @code{hello} or the string
+@code{word}.
+
+As a more complex example, the regexp @code{B[an]*s} matches any of the
+strings @code{Bananas}, @code{Baaaaas}, @code{Bs} and any other string
+starting with a @code{B}, ending with an @code{s}, and containing any
+number of @code{a} or @code{n} characters in between.
+
+A regular expression may use any of the following special
+characters/constructs:
+@table @code
+@item ^
+Match the beginning of a string.
+@example
+mysql> select "fo\nfo" REGEXP "^fo$"; -> 0
+mysql> select "fofo" REGEXP "^fo"; -> 1
+@end example
+@item $
+Match the end of a string.
+@example
+mysql> select "fo\no" REGEXP "^fo\no$"; -> 1
+mysql> select "fo\no" REGEXP "^fo$"; -> 0
+@end example
+@item .
+Match any character (including newline).
+@example
+mysql> select "fofo" REGEXP "^f.*"; -> 1
+mysql> select "fo\nfo" REGEXP "^f.*"; -> 1
+@end example
+@item a*
+Match any sequence of zero or more @code{a} characters.
+@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+
+Match any sequence of one or more @code{a} characters.
+@example
+mysql> select "Ban" REGEXP "^Ba+n"; -> 1
+mysql> select "Bn" REGEXP "^Ba+n"; -> 0
+@end example
+@item a?
+Match either zero or one @code{a} character.
+@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
+Match either of the sequences @code{de} or @code{abc}.
+@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)*
+Match zero or more instances of the sequence @code{abc}.
+@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@}
+The is a more general way of writing regexps that match many
+occurrences of the previous atom.
+@table @code
+@item a*
+Can be written as @code{a@{0,@}}.
+@item a+
+Can be written as @code{a@{1,@}}.
+@item a?
+Can be written as @code{a@{0,1@}}.
+@end table
+To be more precise, an atom followed by a bound containing one integer
+@code{i} and no comma matches a sequence of exactly @code{i} matches of
+the atom. An atom followed by a bound containing one integer @code{i}
+and a comma matches a sequence of @code{i} or more matches of the atom.
+An atom followed by a bound containing two integers @code{i} and
+@code{j} matches a sequence of @code{i} through @code{j} (inclusive)
+matches of the atom.
+
+Both arguments must @code{0 >= value <= RE_DUP_MAX (default 255)}.
+If there are two arguments, the second must be greater than or equal to the
+first.
+@item [a-dX]
+@itemx [^a-dX]
+Matches
+any character which is (or is not, if ^ is used) either @code{a}, @code{b},
+@code{c}, @code{d} or @code{X}. To include a literal @code{]} character,
+it must immediately follow the opening bracket @code{[}. To include a
+literal @code{-} character, it must be written first or last. So
+@code{[0-9]} matches any decimal digit. Any character that does not have
+a defined meaning inside a @code{[]} pair has no special meaning and
+matches only itself.
+@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 [[.characters.]]
+The sequence of characters of that collating element. The sequence is a
+single element of the bracket expression's list. A bracket expression
+containing a multi-character collating element can thus match more than
+one character, e.g., if the collating sequence includes a @code{ch}
+collating element, then the regular expression @code{[[.ch.]]*c} matches the
+first five characters of @code{chchcc}.
+
+@item [=character_class=]
+An equivalence class, standing for the sequences of characters of all
+collating elements equivalent to that one, including itself.
+
+For example, if @code{o} and @code{(+)} are the members of an
+equivalence class, then @code{[[=o=]]}, @code{[[=(+)=]]}, and
+@code{[o(+)]} are all synonymous. An equivalence class may not be an
+endpoint of a range.
+
+@item [:character_class:]
+Within a bracket expression, the name of a character class enclosed in
+@code{[:} and @code{:]} stands for the list of all characters belonging
+to that class. Standard character class names are:
+
+@multitable @columnfractions .33 .33 .33
+@item alnum @tab digit @tab punct
+@item alpha @tab graph @tab space
+@item blank @tab lower @tab upper
+@item cntrl @tab print @tab xdigit
+@end multitable
+
+These stand for the character classes defined in the @code{ctype(3)} manual
+page. A locale may provide others. A character class may not be used as an
+endpoint of a range.
+@example
+mysql> select "justalnums" REGEXP "[[:alnum:]]+"; -> 1
+mysql> select "!!" REGEXP "[[:alnum:]]+"; -> 0
+@end example
+
+@item [[:<:]]
+@itemx [[:>:]]
+These match the null string at the beginning and end of a word
+respectively. A word is defined as a sequence of word characters which
+is neither preceded nor followed by word characters. A word character is
+an alnum character (as defined by @code{ctype(3)}) or an underscore
+(@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
+
+@node Unireg, GPL license, Regexp, Top
+@appendix What is Unireg?
+
+Unireg is our tty interface builder, but it uses a low level connection
+to our ISAM (which is used by @strong{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 @strong{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 @strong{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 @strong{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 @strong{MySQL}). Usually we compile the binary for the
+customer at their site.
+
+All new development is concentrated to @strong{MySQL}.
+
+@page
+@c This node name is special
+@node GPL license, LGPL license, Unireg, Top
+@appendix GNU General Public License
+
+@example
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ 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.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. 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.
+
+ 1. 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.
+
+ 2. 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:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) 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.
+
+ c) 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.)
+
+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.
+
+ 3. 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:
+
+ a) 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,
+
+ b) 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,
+
+ c) 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.)
+
+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.
+
+ 4. 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.
+
+ 5. 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.
+
+ 6. 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.
+
+ 7. 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.
+
+ 8. 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.
+
+ 9. 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.
+
+ 10. 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.
+
+ NO WARRANTY
+
+ 11. 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.
+
+ 12. 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 OF TERMS AND CONDITIONS
+
+ Appendix: 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.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+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:
+
+ Gnomovision version 69, Copyright (C) 19yy 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.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `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:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+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.
+
+@end example
+
+@page
+@node LGPL license, Function Index, GPL license, Top
+@appendix GNU Library General Public License
+
+@example
+ GNU LIBRARY GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1991 Free Software Foundation, Inc.
+ 675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the library GPL. It is
+ numbered 2 because it goes with version 2 of the ordinary GPL.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Library General Public License, applies to some
+specially designated Free Software Foundation software, and to any
+other libraries whose authors decide to use it. You can use it for
+your libraries, 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 library, or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link a program with the library, you must provide
+complete object files to the recipients so that they can relink them
+with the library, after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ Our method of protecting your rights has two steps: (1) copyright
+the library, and (2) offer you this license which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ Also, for each distributor's protection, we want to make certain
+that everyone understands that there is no warranty for this free
+library. If the library is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original
+version, 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 companies distributing free
+software will individually obtain patent licenses, thus in effect
+transforming the program into proprietary software. To prevent this,
+we have made it clear that any patent must be licensed for everyone's
+free use or not licensed at all.
+
+ Most GNU software, including some libraries, is covered by the ordinary
+GNU General Public License, which was designed for utility programs. This
+license, the GNU Library General Public License, applies to certain
+designated libraries. This license is quite different from the ordinary
+one; be sure to read it in full, and don't assume that anything in it is
+the same as in the ordinary license.
+
+ The reason we have a separate public license for some libraries is that
+they blur the distinction we usually make between modifying or adding to a
+program and simply using it. Linking a program with a library, without
+changing the library, is in some sense simply using the library, and is
+analogous to running a utility program or application program. However, in
+a textual and legal sense, the linked executable is a combined work, a
+derivative of the original library, and the ordinary General Public License
+treats it as such.
+
+ Because of this blurred distinction, using the ordinary General
+Public License for libraries did not effectively promote software
+sharing, because most developers did not use the libraries. We
+concluded that weaker conditions might promote sharing better.
+
+ However, unrestricted linking of non-free programs would deprive the
+users of those programs of all benefit from the free status of the
+libraries themselves. This Library General Public License is intended to
+permit developers of non-free programs to use free libraries, while
+preserving your freedom as a user of such programs to change the free
+libraries that are incorporated in them. (We have not seen how to achieve
+this as regards changes in header files, but we have achieved it as regards
+changes in the actual functions of the Library.) The hope is that this
+will lead to faster development of free libraries.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, while the latter only
+works together with the library.
+
+ Note that it is possible for a library to be covered by the ordinary
+General Public License rather than by this special one.
+
+ GNU LIBRARY GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library which
+contains a notice placed by the copyright holder or other authorized
+party saying it may be distributed under the terms of this Library
+General Public License (also called "this License"). Each licensee is
+addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, 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 library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete 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 distribute a copy of this License along with the
+Library.
+
+ 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.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+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 Library, 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 Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you 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.
+
+ If distribution of 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 satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also compile or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ c) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ d) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. 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.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library 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.
+
+ 9. 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 Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+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.
+
+ 11. 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 Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library 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 Library.
+
+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.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library 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.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Library 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 Library
+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 Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+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.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "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
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. 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 LIBRARY 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
+LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ Appendix: How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. 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.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ 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.
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
+@end example
+
+@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
+
+@summarycontents
+@contents
+
+@bye
diff --git a/Docs/myisam.txt b/Docs/myisam.txt
new file mode 100644
index 00000000000..e0b56e79548
--- /dev/null
+++ b/Docs/myisam.txt
@@ -0,0 +1,901 @@
+#.# mi_changed()
+
+int mi_is_changed(MI_INFO *mip)
+
+#.#.1 Description
+
+Reports whether any changes have occurred to the MyISAM table associated with mip.
+
+For information only, I notice that mi_changed() is a wrapper around this: (_mi_readinfo(info,F_RDLCK,1)).
+
+#.#.2 Return values
+
+Zero if the table has not changed. Non-zero (-1) if the table has changed.
+
+#.#.3 Errors
+
+Nothing specific yet identified.
+
+#.#.4 Examples
+
+if( mi_changed( mip )) printf( "file has changed" );
+====================
+#.# mi_close()
+
+int mi_close( MI_INFO *mip )
+
+#.#.1 Description
+
+Closes the MyISAM table associated with mip, a structure created by mi_open().
+Any locks on that file pointer are released.
+The MI_INFO structure mip is released.
+See also mi_panic() which can be used to close all open MyISAM files.
+mip is a pointer to the MI_INFO returned by mi_open().
+
+#.#.2 Return values
+
+Zero if successful. Non-zero if an error occurred.
+
+#.#.3 Errors
+
+Nothing specific yet identified.
+
+#.#.4 Examples
+
+result = mi_close(mip);
+====================
+#.# mi_create()
+
+int mi_create( const char *name, uint keys, MI_KEYDEF *keydefs,
+ uint columns, MI_COLUMNDEF *recinfo,
+ uint uniques, MI_UNIQUEDEF *uniquedefs,
+ MI_CREATE_INFO *ci, uint flags )
+
+#.#.1 Description
+
+Creates a new MyISAM table.
+Documentation for this function is not complete because I am not using mi_create directly.
+Because all our tables are used with MySQL, I create new tables using SQL "CREATE TABLE" via the C API.
+See MySQL Appendix B "Choosing a table type".
+MyISAM allows about 32 indexes. However the official MySQL limit is 16 until MySQL 4.0.
+
+The parameters are specified as follows:
+name The file pathname, excluding the suffixes.
+keys Number of indexes.
+keydefs A MI_KEYDEF structure containing key definitions.
+HA_KEYTYPE_END=0
+HA_KEYTYPE_TEXT=1, /* Key is sorted as letters */
+HA_KEYTYPE_BINARY=2, /* Key is sorted as unsigned chars
+HA_KEYTYPE_SHORT_INT=3,
+HA_KEYTYPE_LONG_INT=4,
+HA_KEYTYPE_FLOAT=5,
+HA_KEYTYPE_DOUBLE=6,
+HA_KEYTYPE_NUM=7, /* Not packed num with pre-space *
+HA_KEYTYPE_USHORT_INT=8,
+HA_KEYTYPE_ULONG_INT=9,
+HA_KEYTYPE_LONGLONG=10,
+HA_KEYTYPE_ULONGLONG=11,
+HA_KEYTYPE_INT24=12,
+HA_KEYTYPE_UINT24=13,
+HA_KEYTYPE_INT8=14,
+HA_KEYTYPE_VARTEXT=15, /* Key is sorted as letters */
+HA_KEYTYPE_VARBINARY=16 /* Key is sorted as unsigned chars
+columns The number of columns.
+recinfo A MI_COLUMNDEF structure containing column definitions.
+uniques The number of unique indexes.
+uniquedefs A MI_UNIQUEDEF structure containing unique index definitions.
+ci A MI_CREATE_INFO structure containing column definitions.
+flags a pointer to the record buffer that will contain the row.
+
+#.#.2 Return values
+
+Zero if the create is successful. Non-zero if an error occurs.
+
+#.#.3 Errors
+
+HA_WRONG_CREATE_OPTION
+ means that some of the arguments was wrong.
+appart from the above one can get any unix error that one can get from open(), write() or close().
+
+#.#.4 Examples
+
+if (mi_create(fn_format(name,filename,"",MI_NAME_IEXT, 4+ (opt_follow_links ? 16 : 0)),
+ share.base.keys - share.state.header.uniques, keyinfo, share.base.fields, recdef,
+ share.state.header.uniques, uniquedef, &create_info, HA_DONT_TOUCH_DATA))
+====================
+#.# mi_delete()
+
+int mi_delete(MI_INFO *mip, const byte *buf)
+
+#.#.1 Description
+
+Removes a row from a MyISAM table.
+
+mip is an MI_INFO pointer to the open handle.
+buf is the buffer containing the row that is to be deleted.
+
+#.#.2 Return values
+
+Zero if successful. Non-zero if an error occurred.
+
+#.#.3 Errors
+
+EACCES
+File was opened read-only.
+HA_ERR_KEY_NOT_FOUND
+No database read
+HA_ERR_RECORD_CHANGED
+The buffer contents were different to the actual row contents.
+HA_ERR_CRASHED
+The indexing has crashed.
+
+#.#.4 Examples
+
+if (mi_delete(file,read_record))
+====================
+#.# mi_delete_all()
+
+int mi_delete_all_rows(MI_INFO *mip)
+#.#.1 Description
+
+Removes ALL rows from a MyISAM table.
+This only clears the status information. The files are not truncated.
+
+mip is an MI_INFO pointer to the open handle.
+
+#.#.2 Return values
+
+Zero if successful. Non-zero if an error occurred.
+
+#.#.3 Errors
+
+EACCES
+File was opened read-only.
+
+#.#.4 Examples
+
+error = mi_delete_all( mip );
+====================
+#.# mi_extra()
+
+int mi_extra(MI_INFO *info, enum ha_extra_function function)
+
+#.#.1 Description
+
+Controls some special MyISAM modes.
+
+The function parameter can be:
+ HA_EXTRA_NORMAL=0 Optimize for space (def)
+HA_EXTRA_QUICK=1 Optimize for speed
+HA_EXTRA_RESET=2 Reset database to after open
+HA_EXTRA_CACHE=3 Cash record in HA_rrnd()
+HA_EXTRA_NO_CACHE=4 End cacheing of records (def)
+HA_EXTRA_NO_READCHECK=5 No readcheck on update
+HA_EXTRA_READCHECK=6 Use readcheck (def)
+HA_EXTRA_KEYREAD=7 Read only key to database
+HA_EXTRA_NO_KEYREAD=8 Normal read of records (def)
+HA_EXTRA_NO_USER_CHANGE=9 No user is allowed to write
+HA_EXTRA_KEY_CACHE=10
+HA_EXTRA_NO_KEY_CACHE=11
+HA_EXTRA_WAIT_LOCK=12 Wait until file is avalably (def)
+HA_EXTRA_NO_WAIT_LOCK=13 If file is locked, return quickly
+HA_EXTRA_WRITE_CACHE=14 Use write cache in ha_write()
+HA_EXTRA_FLUSH_CACHE=15 flush write_record_cache
+HA_EXTRA_NO_KEYS=16 Remove all update of keys
+HA_EXTRA_KEYREAD_CHANGE_POS=17 Keyread, but change pos
+xxxxchk -r must be used
+HA_EXTRA_REMEMBER_POS=18 Remember pos for next/prev
+HA_EXTRA_RESTORE_POS=19
+HA_EXTRA_REINIT_CACHE=20 init cache from current record
+HA_EXTRA_FORCE_REOPEN=21 Datafile have changed on disk
+HA_EXTRA_FLUSH Flush tables to disk
+HA_EXTRA_NO_ROWS Don't write rows
+
+#.#.2 Return values
+
+Zero if successful. Non-zero if an error occurred.
+
+#.#.3 Errors
+
+Nothing specific yet identified.
+
+#.#.4 Examples
+
+====================
+#.# mi_make_application_key()
+
+void mi_make_application_key(register MI_INFO *mip, uint keynr, uchar *key, const byte *record)
+
+#.#.1 Description
+
+Construct a key string for the given index, from the provided record buffer.
+Monty wrote this function to: "to create an external key for an application from your record. It should work for all keys except BLOB and true VARCHAR (not supported by MySQL yet), but I don't think you have either of these!" He just wrote it, so I expect it to included in releases from about 3.23.15. ??
+
+The parameters are:
+A MI_INFO pointer mip.
+The index number keynr.
+The buffer to contain the formatted key string key.
+The record buffer record.
+
+#.#.2 Return values
+
+The byte length of the created key string.
+
+#.#.3 Errors
+
+Nothing specific yet identified.
+
+#.#.4 Examples
+
+uint new_length=_mi_make_application_key(info,i,new_key,newrec);
+====================
+#.# mi_open()
+
+MI_INFO *mi_open( const char *name, int mode, uint handle_locking )
+
+#.#.1 Description
+
+Opens a MyISAM file for processing.
+mi_open() returns a MI_INFO structure pointer that you must use in subsequent operations on the MyISAM file. MI_INFO structures are defined in "myisam/myisamdef.h", which is included in your program via your include myisam.h - used by both MyISAM and MySQL.
+The name parameter must contain a null-terminated string without an extension, which is the filename of the MyISAM file to be processed.
+There is no automatic positioning nor key selection.
+Caution! It is extremely important to close MyISAM files after processing has finished, especially on operating systems without file-locking system calls. Failure to close MyISAM files using mi_close() or mi_panic() leaves the files locked on systems without these system calls.
+
+name Is the name of the file.
+mode Is the access mode parameter. Use one of the following access mode parameters:
+O_RDONLY to open for input only.
+O_RDWR opens the file for output.
+O_SHARE opens the file for both input and output. When used, O_SHARE should be added to O_RDONLY and O_RDWR.
+handle_locking is the locking mode parameter. Select from the following:
+HA_OPEN_ABORT_IF_LOCKED (0) exit with error if database is locked
+HA_OPEN_WAIT_IF_LOCKED (1) wait if database is locked
+HA_OPEN_IGNORE_IF_LOCKED (2) continue, but count-vars in st_i_info may be wrong. count-vars are automatically fixed after next isam request.
+
+#.#.2 Return values
+
+A pointer to MI_INFO for successfully open file. NULL if unsuccessful, when my_errno will contain the error code.
+
+#.#.3 Errors
+
+HA_ERR_OLD_FILE
+wrong options
+HA_ERR_CRASHED
+wrong header
+HA_ERR_UNSUPPORTED
+too many keys or keys too long
+HA_ERR_END_OF_FILE
+empty file?
+MY_FILE_ERROR
+?
+EACCES
+cannot open in write mode
+ENOMEM
+not enough memory
+Otherwise one has probably got a fatal error like HA_ERR_CRASHED or some I-O related error from the Operating System.
+
+#.#.4 Examples
+
+pfm = mi_open("/D1/adir/perform",O_SHARE | O_RDONLY, HA_OPEN_ABORT_IF_LOCKED);
+====================
+#.# mi_panic()
+
+int mi_panic( enum ha_panic_function flag )
+
+#.#.1 Description
+
+mi_panic() is used to close any MyISAM files before exiting, or to safeguard file updates when using a shell.
+The flag parameter specifies the function and can be:
+HA_PANIC_CLOSE Close all databases (MyISAM files).
+HA_PANIC_WRITE Unlock and write status, flushing all buffers to disk.
+HA_PANIC_READ Lock and read key info per HA_PANIC_WRITE.
+
+The CLOSE function also writes buffers before it closes and turns logging off by closing the log file..
+See also my_end(), a debugging function.
+One use is to do a WRITE, use a shell to run myisamchk, then do a READ.
+
+#.#.2 Return values
+
+Zero if successful. Non-zero if an error occurred.
+
+#.#.3 Errors
+
+Nothing specific yet identified.
+
+#.#.4 Examples
+
+result = mi_panic(HA_PANIC_CLOSE);
+====================
+#.# mi_position()
+
+my_off_t mi_position(MI_INFO *mip)
+
+#.#.1 Description
+
+Gets the byte position in the file of the last record read.
+
+mip is an MI_INFO pointer to the open handle.
+
+#.#.2 Return values
+
+Byte position if successful. Zero if an error occurred. ??
+
+#.#.3 Errors
+
+HA_OFFSET_ERROR
+if there wasn't any active row.
+
+#.#.4 Examples
+
+currentpos = mi_position( mip );
+====================
+#.# mi_rfirst()
+
+int mi_rfirst(MI_INFO *mip , byte *buf, int inx)
+
+#.#.1 Description
+
+Reads the first row in the MyISAM file according to the specified index.
+If one want's to read rows in physical sequences, then one should instead use mi_scan() or mi_rrnd().
+
+mip is an MI_INFO pointer to the open handle.
+buf is the record buffer that will contain the row.
+Inx is the index (key) number, which must be the same as currently selected.
+
+mi_rfirst() works by setting the current position mip->lastpos to HA_OFFSET_ERROR (undefined) then calling mi_rnext().
+
+#.#.2 Return values
+
+Zero if successful. Non-zero if an error occurred.
+
+#.#.3 Errors
+
+HA_ERR_END_OF_FILE
+End of file
+Otherwise one has probably got a fatal error like HA_ERR_CRASHED or some I-O related error from the Operating System.
+
+#.#.4 Examples
+
+error = mi_rfirst( mip, buffer, keynum);
+====================
+#.# mi_rkey()
+
+int mi_rkey(MI_INFO *mip, byte *buf, int inx, const byte *key, uint key_len, enum ha_rkey_function search_flag)
+
+#.#.1 Description
+
+Reads the next row after the last row read, using the current index.
+If one want's to read rows in physical sequences, then one should instead use mi_scan() or mi_rrnd().
+
+mip is an MI_INFO pointer to the open handle.
+buf is the record buffer that will contain the row.
+Inx is the index (key) number, which must be the same as currently selected.
+
+If (mip->lastpos) is HA_OFFSET_ERROR (undefined) then mi_rnext() gives the first row.
+If you specify a different index number than the last read used, you will get an error.
+If the last (current) row has been changed since we read it, mi_rnext() will reposition from the position where that row WAS, not where it is now. (This behaviour is similar to CISAM and better than used in Codebase.)
+
+mi_extra(HA_EXTRA_KEYREAD) can be called first, to cause mi_rkey to read the key but not the record. Then call mi_extra(HA_EXTRA_NO_KEYREAD) to resume normal behaviour.
+
+#.#.2 Return values
+
+Zero if successful. Non-zero if an error occurred.
+
+#.#.3 Errors
+
+HA_ERR_END_OF_FILE
+End of file
+Otherwise one has probably got a fatal error like HA_ERR_CRASHED or some I-O related error from the Operating System.
+
+#.#.4 Examples
+
+error = mi_rnext( mip, buffer, keynum );
+====================
+#.# mi_rlast()
+
+int mi_rlast(MI_INFO *mip , byte *buf, int inx)
+
+#.#.1 Description
+
+Reads the last row in the MyISAM file according to the specified index.
+If one want's to read rows in physical sequences, then one should instead use mi_scan() or mi_rrnd().
+mip is an MI_INFO pointer to the open handle.
+buf is a pointer to the record buffer that will contain the row.
+Inx is the index (key) number, which must be the same as currently selected.
+
+mi_rlast() works by setting the current position (mip->lastpos) to HA_OFFSET_ERROR (undefined) then calling mi_rprev().
+
+#.#.2 Return values
+
+Zero if successful. Non-zero if an error occurred.
+
+#.#.3 Errors
+
+HA_ERR_END_OF_FILE
+End of file
+Otherwise one has probably got a fatal error like HA_ERR_CRASHED or some I-O related error from the Operating System.
+
+#.#.4 Examples
+
+error = mi_rlast( mip, buffer, keynum);
+====================
+#.# mi_rnext()
+
+int mi_rnext(MI_INFO *mip , byte *buf, int inx )
+
+#.#.1 Description
+
+Reads the next row after the last row read, using the current index.
+If one want's to read rows in physical sequences, then one should instead use mi_scan() or mi_rrnd().
+
+mip is an MI_INFO pointer to the open handle.
+buf is the record buffer that will contain the row.
+Inx is the index (key) number, which must be the same as currently selected.
+
+If (mip->lastpos) is HA_OFFSET_ERROR (undefined) then mi_rnext() gives the first row.
+If you specify a different index number than the last read used, you will get an error.
+If the last (current) row has been changed since we read it, mi_rnext() will reposition from the position where that row WAS, not where it is now. (This behaviour is similar to CISAM and better than used in Codebase.)
+
+#.#.2 Return values
+
+Zero if successful. Non-zero if an error occurred.
+
+#.#.3 Errors
+
+HA_ERR_END_OF_FILE
+End of file
+Otherwise one has probably got a fatal error like HA_ERR_CRASHED or some I-O related error from the Operating System.
+
+#.#.4 Examples
+
+error = mi_rnext( mip, buffer, keynum );
+====================
+#.# mi_rrnd()
+
+int mi_rrnd( MI_INFO *mip , byte *buf, my_off_t filepos )
+
+#.#.1 Description
+
+Reads a row based on physical position.
+
+Position can be calculated from record number only when fixed record lengths are used:
+position = mip->s.pack.header_length + recnum * mip->s->base.reclength.
+If filepos= HA_OFFSET_ERROR then it reads the next row.
+And if (mip->lastpos == HA_OFFSET_ERROR) it reads the first row.
+
+mip is an MI_INFO pointer to the open handle.
+buf is the record buffer that will contain the row.
+filepos is the byte position in the file of the required record.
+
+#.#.2 Return values
+
+Zero if successful. Non-zero if an error occurred.
+
+#.#.3 Errors
+
+HA_ERR_RECORD_DELETED
+A deleted record was read.
+HA_ERR_END_OF_FILE
+End of file.
+
+#.#.4 Examples
+
+error = mi_rrnd( mip, buffer, mip->nextpos );
+====================
+#.# mi_rprev()
+
+int mi_rprev(MI_INFO *mip , byte *buf, int inx)
+
+#.#.1 Description
+
+Reads the row previous to the last row read, using the current index.
+If one wants to read rows in physical sequences, then one should instead use mi_scan() or mi_rrnd().
+
+If (mip->lastpos) is HA_OFFSET_ERROR (undefined) then mi_rnext() gives the last row in the index.
+If you specify a different index number than the last read used, you will get an error.
+If the last (current) row has been changed since we read it, mi_rprev() will reposition from the position where that row WAS, not where it is now. This behaviour is similar to CISAM and better than used in Codebase.
+
+mip is an MI_INFO pointer to the open handle.
+buf is the record buffer that will contain the row.
+Inx is the index (key) number, which must be the same as currently selected.
+
+#.#.2 Return values
+
+Zero if successful. Non-zero if an error occurred.
+
+#.#.3 Errors
+
+HA_ERR_END_OF_FILE
+End of file
+Otherwise one has probably got a fatal error like HA_ERR_CRASHED or some I-O related error from the Operating System.
+
+#.#.4 Examples
+
+error = mi_rprev( mip, buffer, keynum );
+====================
+#.# mi_rsame()
+
+int mi_rsame(MI_INFO *mip, byte *buf, int inx)
+
+#.#.1 Description
+
+Reads the current row to get its latest contents. This is useful to refresh the record buffer in case someone else has changed it.
+If inx is negative it reads by position. If inx is >= 0 it reads by key.
+With mi_rsame() one can switch to use any other index for the current row. This is good if you have a user application that lets the user do 'read-next' on a row. In this case, if the user want's to start scanning on another index, one simply has to do a mi_rsame() on the new index to activate this.
+
+mip is an MI_INFO pointer to the open handle.
+buf is the record buffer that will contain the row.
+inx is the index (key) number, or a negative number to select read by position not index. Maybe the negative number has to be (-1) to achieve this behaviour.
+
+#.#.2 Return values
+
+Zero if successful. Non-zero if an error occurred.
+
+#.#.3 Errors
+
+HA_ERR_WRONG_INDEX
+an incorrect index number was supplied
+HA_ERR_KEY_NOT_FOUND
+info->lastpos was not defined, or the record was already deleted.
+
+#.#.4 Examples
+
+error = mi_rsame( m5mip, rec_ptr, keynum );
+====================
+#.# mi_scan()
+
+int mi_scan(MI_INFO *mip, byte *buf)
+
+#.#.1 Description
+
+Reads the next row by physical position.
+
+Deleted rows are bypassed.
+mi_scan() uses a function pointer "read_rnd" that uses either lower level static or dynamic read functions, positioning from mip->nextpos. Read_rnd is defined in mi_open() depending if the table is Static (read*static - see mi_statrec.c), Compressed (read*pack - see mi_packrec.c), or Space packed or Blobs (read*dynamic - see mi_dynrec.c).
+See also mi_scan_init() which initialises ready to mi_scan() through the whole table.
+
+mip is an MI_INFO pointer to the open handle.
+buf is the record buffer that will contain the row.
+
+#.#.2 Return values
+
+Zero if successful. Non-zero if an error occurred.
+
+#.#.3 Errors
+
+HA_ERR_END_OF_FILE
+End of file
+Otherwise one has probably got a fatal error like HA_ERR_CRASHED or some I-O related error from the Operating System.
+
+#.#.4 Examples
+
+error = mi_scan( mip, recbuff );
+====================
+#.# mi_scan_init()
+
+int mi_scan_init(MI_INFO *mip[SB1])
+
+#.#.1 Description
+
+Initialises ready to mi_scan() through all rows.
+
+mip is an MI_INFO pointer to the open handle.
+
+#.#.2 Return values
+
+Zero if successful. Non-zero if an error occurred.
+
+#.#.3 Errors
+
+Nothing specific yet identified.
+
+#.#.4 Examples
+
+====================
+#.# mi_status()
+
+int mi_status(MI_INFO *mip, MI_ISAMINFO *x, uint flag)
+
+#.#.1 Description
+
+Gets information about the table.
+It is used to get/fill the MI_ISAMINFO struct with statistics data about the MySQL server. One can get information of the number of active rows, delete rows, file lengths...
+
+mip is an MI_INFO pointer to the open handle.
+flag is one of the following:
+HA_STATUS_POS Return position
+HA_STATUS_NO_LOCK Don't use external lock
+HA_STATUS_TIME Return update time
+HA_STATUS_CONST Return constants value
+HA_STATUS_VARIABLE
+HA_STATUS_ERRKEY
+HA_STATUS_AUTO
+
+#.#.2 Return values
+
+Zero.
+
+#.#.3 Errors
+
+Nothing specific yet identified.
+
+#.#.4 Examples
+
+====================
+#.# mi_update()
+
+int mi_update( MI_INFO *mip, const byte *oldbuf, byte *newbuf)
+
+#.#.1 Description
+
+Updates the contents of the current record.
+By default you must supply an oldbuf record buffer with the current record contents. This is compared with the file as a guard in case someone else has changed the record in the meantime. *
+
+mip is an MI_INFO pointer to the open handle.
+oldbuf is the record buffer that contains the current record contents.
+newbuf is the record buffer that contains the new record contents.
+
+*Sometimes you might want to force an update without checking whether another user has changed the record since you last read it. This is somewhat dangerous, so it should ideally not be used. That can be accomplished by wrapping the mi_update() call in two calls to mi_extra(), using these functions:
+HA_EXTRA_NO_READCHECK=5 No readcheck on update
+HA_EXTRA_READCHECK=6 Use readcheck (def)
+
+#.#.2 Return values
+
+Zero if successful. Non-zero if an error occurred.
+
+#.#.3 Errors
+
+EACCES
+The file was opened for read-only access.
+HA_ERR_RECORD_CHANGED
+ When mi_update() read the current record contents before updating, it differed from oldbuf.
+HA_ERR_CRASHED
+Key could not be found ??
+HA_ERR_FOUND_DUPP_KEY
+HA_ERR_RECORD_FILE_FULL
+
+#.#.4 Examples
+
+error = mi_update( mip, oldbuf, newbuf );
+====================
+#.# mi_write()
+
+int mi_write( MI_INFO *mip, byte *record)
+
+#.#.1 Description
+
+Writes a row to a MyISAM table.
+
+mip is an MI_INFO pointer to the open handle.
+The record contents are supplied in buf record buffer.
+
+#.#.2 Return values
+
+Zero if successful. Non-zero if an error occurred.
+
+#.#.3 Errors
+
+HA_ERR_FOUND_DUPP_KEY
+A record already existed with a unique key same as this new record.
+HA_ERR_RECORD_FILE_FULL
+The error is given if you hit a system limit or if you try to create more rows in a table that you reserverd room for with mi_create().
+ENOSPC
+The disk is full.
+EACCES
+The file was opened for read-only access.
+
+#.#.4 Examples
+
+error = mi_write( m5mip, recbuf );
+====================
+#.# my_end()
+
+void my_end(int infoflag)
+
+#.#.1 Description
+
+Shows debugging information about open MyISAM handles.
+my_end() exists primarily for MyISAM debugging.
+It would not normally be used in a production environment.
+It can give a nice summary of how you have used my_xxx() functions.
+It can be used to check that you have closed all files that you have opened.
+
+infoflag is the list function and can be:
+MY_CHECK_ERROR List which MyISAM handles are open.
+MY_GIVE_INFO Show runtime information.
+
+#.#.2 Return values
+
+Void
+
+#.#.3 Errors
+
+Nothing specific yet identified.
+
+#.#.4 Examples
+
+my_end(MY_CHECK_ERROR | MY_GIVE_INFO);
+====================
+#.# my_init()
+
+void my_init( void )
+
+#.#.1 Description
+
+Performs MyISAM initialisation for program startup, particularly if using threads.
+
+If using threads, be sure to call my_init() at start of program. (CFS does this in XPOPEN.) It is also safe to call my_init() when not using threads.
+
+#.#.2 Return values
+
+void
+Sometimes my_errno might be meaningful if a warning is generated during debugging.
+
+#.#.3 Errors
+
+Nothing specific yet identified.
+
+#.#.4 Examples
+
+my_init();
+====================
+#.# init_key_cache()
+
+int init_key_cache( long int use_mem, (uint) reserve_mem;
+
+#.#.1 Description
+
+Starts and controls caching of keys. Call init_key_cache() to reserve memory for key caching and to start the caching. (CFS does this in XPOPEN if MYCACHE is defined (regular size), or MYCACHELARGE or MYCACHESMALL.)
+
+Provide use_mem the number of bytes of memory to use for key caching by this process.
+reserve_mem should be 0. This is just for very old systems with very little memory.
+
+#.#.2 Return values
+
+The number of 1kb memory blocks now allocated to key caching. Zero if key caching cannot be started (check my_errno), or key caching was already active.
+
+#.#.3 Errors
+
+Nothing specific yet identified.
+
+#.#.4 Examples
+
+Blocks = init_key_cache( 65536L, IO_SIZE*4*10 );
+====================
+#.# _mi_make_key()
+
+uint _mi_make_key( MI_INFO *mip, uint keynr, uchar *key, const char *record, my_off_t filepos)
+
+#.#.1 Description
+
+Construct a key string for the given index, from the provided record buffer.
+??? When packed records are used ...
+This is an internal function, not for use by applications. Monty says: "This can't be used to create an external key for an application from your record."
+See mi_make_application_key() for a similar function that is useable by applications.
+
+The parameters are:
+A MI_INFO pointer mip.
+The index number keynr.
+The buffer to contain the formatted key string key.
+The record buffer record.
+??? A file position filepos or zero.
+
+#.#.2 Return values
+
+The byte length of the created key string.
+
+#.#.3 Errors
+
+Nothing specific yet identified.
+
+#.#.4 Examples
+
+uint new_length=_mi_make_key(info,i,new_key,newrec,pos);
+====================
+#.# _mi_print_key()
+
+void _mi_print_key(FILE *stream, MI_KEYSEG *keyseg, const uchar *key, uint length)
+
+#.#.1 Description
+
+Prints a key in a user understandable format.
+This is an internal function for debugging, not for use by applications.
+??? Not yet fully documented. I just include it here so that I know it exists.
+
+#.#.2 Return values
+
+A readable print of the key contents goes to the specified output.
+
+#.#.3 Errors
+
+Nothing specific yet identified.
+
+#.#.4 Examples
+
+_mi_print_key(stdout,share->keyinfo[info->errkey].seg,info->lastkey, USE_WHOLE_KEY);
+====================
+APPENDIX B Choosing a table type
+(excerpt from manual.txt in MySQL 3.23.8-alpha)
+
+With MySQL you can currently (version 3.23.5) choose between four usable table formats from a speed point of view.
+
+Static (Fixed-length) table characteristics
+* This is the default format. It's used when the table contains no `VARCHAR', `BLOB' or `TEXT' columns.
+* All `CHAR', `NUMERIC' and `DECIMAL' columns are space-padded to the column width.
+* Very quick.
+* Easy to cache.
+* Easy to reconstruct after a crash, because records are located in fixed positions.
+* Doesn't have to be reorganized (with `myisamchk') unless a huge number of records are deleted and you want to return free disk space to the operating system.
+* Usually requires more disk space than dynamic tables.
+
+Dynamic table characteristics
+* This format is used if the table contains any `VARCHAR', `BLOB' or `TEXT' columns.
+* All string columns are dynamic (except those with a length less than 4).
+* Each record is preceded by a bitmap indicating which columns are empty (`''') for string columns, or zero for numeric columns (this isn't the same as columns containing `NULL' values). If a string column has a length of zero after removal of trailing spaces, or a numeric column has a value of zero, it is marked in the bit map and not saved to disk. Non-empty strings are saved as a length byte plus the string contents.
+* Usually takes much less disk space than fixed-length tables.
+* Each record uses only as much space as is required. If a record becomes larger, it is split into as many pieces as required. This results in record fragmentation.
+* If you update a row with information that extends the row length, the row will be fragmented. In this case, you may have to run `myisamchk -r' from time to time to get better performance. Use `myisamchk -ei tbl_name' for some statistics.
+* Not as easy to reconstruct after a crash, because a record may be fragmented into many pieces and a link (fragment) may be missing.
+* The expected row length for dynamic sized records is:
+3
++ (number of columns + 7) / 8
++ (number of char columns)
++ packed size of numeric columns
++ length of strings
++ (number of NULL columns + 7) / 8
+There is a penalty of 6 bytes for each link. A dynamic record is linked whenever an update causes an enlargement of the record.
+Each new link will be at least 20 bytes, so the next enlargement will probably go in the same link. If not, there will be another link. You may check how many links there are with `myisamchk -ed'. All links may be removed with `myisamchk -r'.
+
+Compressed table characteristics
+* A read-only table made with the `myisampack' utility. All customers with extended *MySQL* email support are entitled to a copy of `myisampack' for their internal usage.
+* The uncompress code exists in all *MySQL* distributions so that even customers who don't have `myisampack' can read tables that were compressed with `myisampack'
+* Takes very little disk space. Minimises disk usage.
+* Each record is compressed separately (very little access overhead). The header for a record is fixed (1-3 bytes) depending on the biggest record in the table. Each column is compressed differently. Some of the compression types are:
+- There is usually a different Huffman table for each column.
+- Suffix space compression.
+- Prefix space compression.
+- Numbers with value `0' are stored using 1 bit.
+- If values in an integer column have a small range, the column is stored using the smallest possible type. For example, a `BIGINT' column (8 bytes) may be stored as a `TINYINT' column (1 byte) if all values are in the range `0' to `255'.
+- If a column has only a small set of possible values, the column type is converted to `ENUM'.
+- A column may use a combination of the above compressions.
+* Can handle fixed or dynamic length records, but not `BLOB' or `TEXT' columns.
+* Can be uncompressed with `myisamchk'.
+
+*MySQL* can support different index types, but the normal type is ISAM.
+This is a B-tree index and you can roughly calculate the size for the index file as `(key_length+4)*0.67', summed over all keys. (This is for the worst case when all keys are inserted in sorted order.)
+
+String indexes are space compressed. If the first index part is a string, it will also be prefix compressed.
+Space compression makes the index file smaller if the string column has a lot of trailing space or is a `VARCHAR' column that is not always used to the full length.
+Prefix compression helps if there are many strings with an identical prefix.
+
+In memory table characteristics
+HEAP tables only exists in memory so they are lost if `mysqld' is taken down or crashes. But since they are *very* fast they are usefull as anyway.
+
+The *MySQL* internal HEAP tables uses 100% dynamic hashing without overflow areas and don't have problems with delete.
+
+You can only access things by equality using a index (usually by the `=' operator) whith a heap table.
+The downside with HEAPS are:
+ 1. You need enough extra memory for all HEAP tables that you want to use at the same time.
+ 2. You can't search on a part of a index.
+ 3. You can't search for the next entry in order (that is to use the index to do a `ORDER BY').
+1. *MySQL* also cannot find out how approximately many rows there are between two values. This is used by the optimizer to chose which index to use. But on the other hand no disk seeks are even needed.
+====================
+#.# mi_()
+
+#.#.1 Description
+
+#.#.2 Return values
+
+Zero if successful. Non-zero if an error occurred.
+
+#.#.3 Errors
+
+Nothing specific yet identified.
+
+#.#.4 Examples
+[SB1]int _mi_read_rnd_static_record(MI_INFO *info, byte *buf, my_off_t filepos,
+ my_bool skipp_deleted_blocks)
+int _mi_read_dynamic_record(MI_INFO *info, my_off_t filepos, byte *buf)
+
+Printed on 17/03/00
+
+C-7
diff --git a/Docs/mysqld_error.txt b/Docs/mysqld_error.txt
new file mode 100644
index 00000000000..b8f0ba72ba5
--- /dev/null
+++ b/Docs/mysqld_error.txt
@@ -0,0 +1,355 @@
+/* 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
+"hashchk",
+#define ER_NISAMCHK 1001
+"isamchk",
+#define ER_NO 1002
+"NO",
+#define ER_YES 1003
+"YES",
+#define ER_CANT_CREATE_FILE 1004
+"Can't create file '%-.64s' (errno: %d)",
+#define ER_CANT_CREATE_TABLE 1005
+"Can't create table '%-.64s' (errno: %d)",
+#define ER_CANT_CREATE_DB 1006
+"Can't create database '%-.64s'. (errno: %d)",
+#define ER_DB_CREATE_EXISTS 1007
+"Can't create database '%-.64s'. Database exists",
+#define ER_DB_DROP_EXISTS 1008
+"Can't drop database '%-.64s'. Database doesn't exist",
+#define ER_DB_DROP_DELETE 1009
+"Error dropping database (can't delete '%-.64s', errno: %d)",
+#define ER_DB_DROP_RMDIR 1010
+"Error dropping database (can't rmdir '%-.64s', errno: %d)",
+#define ER_CANT_DELETE_FILE 1011
+"Error on delete of '%-.64s' (errno: %d)",
+#define ER_CANT_FIND_SYSTEM_REC 1012
+"Can't read record in system table",
+#define ER_CANT_GET_STAT 1013
+"Can't get status of '%-.64s' (errno: %d)",
+#define ER_CANT_GET_WD 1014
+"Can't get working directory (errno: %d)",
+#define ER_CANT_LOCK 1015
+"Can't lock file (errno: %d)",
+#define ER_CANT_OPEN_FILE 1016
+"Can't open file: '%-.64s'. (errno: %d)",
+#define ER_FILE_NOT_FOUND 1017
+"Can't find file: '%-.64s' (errno: %d)",
+#define ER_CANT_READ_DIR 1018
+"Can't read dir of '%-.64s' (errno: %d)",
+#define ER_CANT_SET_WD 1019
+"Can't change dir to '%-.64s' (errno: %d)",
+#define ER_CHECKREAD 1020
+"Record has changed since last read in table '%-.64s'",
+#define ER_DISK_FULL 1021
+"Disk full (%s). Waiting for someone to free some space....",
+#define ER_DUP_KEY 1022
+"Can't write, duplicate key in table '%-.64s'",
+#define ER_ERROR_ON_CLOSE 1023
+"Error on close of '%-.64s' (errno: %d)",
+#define ER_ERROR_ON_READ 1024
+"Error reading file '%-.64s' (errno: %d)",
+#define ER_ERROR_ON_RENAME 1025
+"Error on rename of '%-.64s' to '%-.64s' (errno: %d)",
+#define ER_ERROR_ON_WRITE 1026
+"Error writing file '%-.64s' (errno: %d)",
+#define ER_FILE_USED 1027
+"'%-.64s' is locked against change",
+#define ER_FILSORT_ABORT 1028
+"Sort aborted",
+#define ER_FORM_NOT_FOUND 1029
+"View '%-.64s' doesn't exist for '%-.64s'",
+#define ER_GET_ERRNO 1030
+"Got error %d from table handler",
+#define ER_ILLEGAL_HA 1031
+"Table handler for '%-.64s' doesn't have this option",
+#define ER_KEY_NOT_FOUND 1032
+"Can't find record in '%-.64s'",
+#define ER_NOT_FORM_FILE 1033
+"Incorrect information in file: '%-.64s'",
+#define ER_NOT_KEYFILE 1034
+"Incorrect key file for table: '%-.64s'. Try to repair it",
+#define ER_OLD_KEYFILE 1035
+"Old key file for table '%-.64s'; Repair it!",
+#define ER_OPEN_AS_READONLY 1036
+"Table '%-.64s' is read only",
+#define ER_OUTOFMEMORY 1037
+"Out of memory. Restart daemon and try again (needed %d bytes)",
+#define ER_OUT_OF_SORTMEMORY 1038
+"Out of sort memory. Increase daemon sort buffer size",
+#define ER_UNEXPECTED_EOF 1039
+"Unexpected eof found when reading file '%-.64s' (errno: %d)",
+#define ER_CON_COUNT_ERROR 1040
+"Too many connections",
+#define ER_OUT_OF_RESOURCES 1041
+"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
+"Can't get hostname for your address",
+#define ER_HANDSHAKE_ERROR 1043
+"Bad handshake",
+#define ER_DBACCESS_DENIED_ERROR 1044
+"Access denied for user: '%-.32s@%-.64s' to database '%-.64s'",
+#define ER_ACCESS_DENIED_ERROR 1045
+"Access denied for user: '%-.32s@%-.64s' (Using password: %s)",
+#define ER_NO_DB_ERROR 1046
+"No Database Selected",
+#define ER_UNKNOWN_COM_ERROR 1047
+"Unknown command",
+#define ER_BAD_NULL_ERROR 1048
+"Column '%-.64s' cannot be null",
+#define ER_BAD_DB_ERROR 1049
+"Unknown database '%-.64s'",
+#define ER_TABLE_EXISTS_ERROR 1050
+"Table '%-.64s' already exists",
+#define ER_BAD_TABLE_ERROR 1051
+"Unknown table '%-.64s'",
+#define ER_NON_UNIQ_ERROR 1052
+"Column: '%-.64s' in %-.64s is ambiguous",
+#define ER_SERVER_SHUTDOWN 1053
+"Server shutdown in progress",
+#define ER_BAD_FIELD_ERROR 1054
+"Unknown column '%-.64s' in '%-.64s'",
+#define ER_WRONG_FIELD_WITH_GROUP 1055
+"'%-.64s' isn't in GROUP BY",
+#define ER_WRONG_GROUP_FIELD 1056
+"Can't group on '%-.64s'",
+#define ER_WRONG_SUM_SELECT 1057
+"Statement has sum functions and columns in same statement",
+#define ER_WRONG_VALUE_COUNT 1058
+"Column count doesn't match value count",
+#define ER_TOO_LONG_IDENT 1059
+"Identifier name '%-.100s' is too long",
+#define ER_DUP_FIELDNAME 1060
+"Duplicate column name '%-.64s'",
+#define ER_DUP_KEYNAME 1061
+"Duplicate key name '%-.64s'",
+#define ER_DUP_ENTRY 1062
+"Duplicate entry '%-.64s' for key %d",
+#define ER_WRONG_FIELD_SPEC 1063
+"Incorrect column specifier for column '%-.64s'",
+#define ER_PARSE_ERROR 1064
+"%s near '%-.80s' at line %d",
+#define ER_EMPTY_QUERY 1065
+"Query was empty",
+#define ER_NONUNIQ_TABLE 1066
+"Not unique table/alias: '%-.64s'",
+#define ER_INVALID_DEFAULT 1067
+"Invalid default value for '%-.64s'",
+#define ER_MULTIPLE_PRI_KEY 1068
+"Multiple primary key defined",
+#define ER_TOO_MANY_KEYS 1069
+"Too many keys specified. Max %d keys allowed",
+#define ER_TOO_MANY_KEY_PARTS 1070
+"Too many key parts specified. Max %d parts allowed",
+#define ER_TOO_LONG_KEY 1071
+"Specified key was too long. Max key length is %d",
+#define ER_KEY_COLUMN_DOES_NOT_EXITS 1072
+"Key column '%-.64s' doesn't exist in table",
+#define ER_BLOB_USED_AS_KEY 1073
+"BLOB column '%-.64s' can't be used in key specification with the used table type",
+#define ER_TOO_BIG_FIELDLENGTH 1074
+"Too big column length for column '%-.64s' (max = %d). Use BLOB instead",
+#define ER_WRONG_AUTO_KEY 1075
+"Incorrect table definition; There can only be one auto column and it must be defined as a key",
+#define ER_READY 1076
+"%s: ready for connections\n",
+#define ER_NORMAL_SHUTDOWN 1077
+"%s: Normal shutdown\n",
+#define ER_GOT_SIGNAL 1078
+"%s: Got signal %d. Aborting!\n",
+#define ER_SHUTDOWN_COMPLETE 1079
+"%s: Shutdown Complete\n",
+#define ER_FORCING_CLOSE 1080
+"%s: Forcing close of thread %ld user: '%-.32s'\n",
+#define ER_IPSOCK_ERROR 1081
+"Can't create IP socket",
+#define ER_NO_SUCH_INDEX 1082
+"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
+"You can't use fixed rowlength with BLOBs. Please use 'fields terminated by'.",
+#define ER_TEXTFILE_NOT_READABLE 1085
+"The file '%-.64s' must be in the database directory or be readable by all",
+#define ER_FILE_EXISTS_ERROR 1086
+"File '%-.80s' already exists",
+#define ER_LOAD_INFO 1087
+"Records: %ld Deleted: %ld Skipped: %ld Warnings: %ld",
+#define ER_ALTER_INFO 1088
+"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
+"You can't delete all columns with ALTER TABLE. Use DROP TABLE instead",
+#define ER_CANT_DROP_FIELD_OR_KEY 1091
+"Can't DROP '%-.64s'. Check that column/key exists",
+#define ER_INSERT_INFO 1092
+"Records: %ld Duplicates: %ld Warnings: %ld",
+#define ER_INSERT_TABLE_USED 1093
+"INSERT TABLE '%-.64s' isn't allowed in FROM table list",
+#define ER_NO_SUCH_THREAD 1094
+"Unknown thread id: %lu",
+#define ER_KILL_DENIED_ERROR 1095
+"You are not owner of thread %lu",
+#define ER_NO_TABLES_USED 1096
+"No tables used",
+#define ER_TOO_BIG_SET 1097
+"Too many strings for column %-.64s and SET",
+#define ER_NO_UNIQUE_LOGFILE 1098
+"Can't generate a unique log-filename %-.64s.(1-999)\n",
+#define ER_TABLE_NOT_LOCKED_FOR_WRITE 1099
+"Table '%-.64s' was locked with a READ lock and can't be updated",
+#define ER_TABLE_NOT_LOCKED 1100
+"Table '%-.64s' was not locked with LOCK TABLES",
+#define ER_BLOB_CANT_HAVE_DEFAULT 1101
+"BLOB column '%-.64s' can't have a default value",
+#define ER_WRONG_DB_NAME 1102
+"Incorrect database name '%-.100s'",
+#define ER_WRONG_TABLE_NAME 1103
+"Incorrect table name '%-.100s'",
+#define ER_TOO_BIG_SELECT 1104
+"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
+"Unknown error",
+#define ER_UNKNOWN_PROCEDURE 1106
+"Unknown procedure '%-.64s'",
+#define ER_WRONG_PARAMCOUNT_TO_PROCEDURE 1107
+"Incorrect parameter count to procedure '%-.64s'",
+#define ER_WRONG_PARAMETERS_TO_PROCEDURE 1108
+"Incorrect parameters to procedure '%-.64s'",
+#define ER_UNKNOWN_TABLE 1109
+"Unknown table '%-.64s' in %-.32s",
+#define ER_FIELD_SPECIFIED_TWICE 1110
+"Column '%-.64s' specified twice",
+#define ER_INVALID_GROUP_FUNC_USE 1111
+"Invalid use of group function",
+#define ER_UNSUPPORTED_EXTENSION 1112
+"Table '%-.64s' uses an extension that doesn't exist in this MySQL version",
+#define ER_TABLE_MUST_HAVE_COLUMNS 1113
+"A table must have at least 1 column",
+#define ER_RECORD_FILE_FULL 1114
+"The table '%-.64s' is full",
+#define ER_UNKNOWN_CHARACTER_SET 1115
+"Unknown character set: '%-.64s'",
+#define ER_TOO_MANY_TABLES 1116
+"Too many tables. MySQL can only use %d tables in a join",
+#define ER_TOO_MANY_FIELDS 1117
+"Too many columns",
+#define ER_TOO_BIG_ROWSIZE 1118
+"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
+"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
+"Cross dependency found in OUTER JOIN. Examine your ON conditions",
+#define ER_NULL_COLUMN_IN_INDEX 1121
+"Column '%-.64s' is used with UNIQUE or INDEX but is not defined as NOT NULL",
+#define ER_CANT_FIND_UDF 1122
+"Can't load function '%-.64s'",
+#define ER_CANT_INITIALIZE_UDF 1123
+"Can't initialize function '%-.64s'; %-.80s",
+#define ER_UDF_NO_PATHS 1124
+"No paths allowed for shared library",
+#define ER_UDF_EXISTS 1125
+"Function '%-.64s' already exist",
+#define ER_CANT_OPEN_LIBRARY 1126
+"Can't open shared library '%-.64s' (errno: %d %-.64s)",
+#define ER_CANT_FIND_DL_ENTRY 1127
+"Can't find function '%-.64s' in library'",
+#define ER_FUNCTION_NOT_DEFINED 1128
+"Function '%-.64s' is not defined",
+#define ER_HOST_IS_BLOCKED 1129
+"Host '%-.64s' is blocked because of many connection errors. Unblock with 'mysqladmin flush-hosts'",
+#define ER_HOST_NOT_PRIVILEGED 1130
+"Host '%-.64s' is not allowed to connect to this MySQL server",
+#define ER_PASSWORD_ANONYMOUS_USER 1131
+"You are using MySQL as an anonymous users and anonymous users are not allowed to change passwords",
+#define ER_PASSWORD_NOT_ALLOWED 1132
+"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
+"Can't find any matching row in the user table",
+#define ER_UPDATE_INFO 1134
+"Rows matched: %ld Changed: %ld Warnings: %ld",
+#define ER_CANT_CREATE_THREAD 1135
+"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
+"Column count doesn't match value count at row %ld",
+#define ER_CANT_REOPEN_TABLE 1137
+"Can't reopen table: '%-.64s'",
+#define ER_INVALID_USE_OF_NULL 1138
+"Invalid use of NULL value",
+#define ER_REGEXP_ERROR 1139
+"Got error '%-.64s' from regexp",
+#define ER_MIX_OF_GROUP_FUNC_AND_FIELDS 1140
+"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
+"There is no such grant defined for user '%-.32s' on host '%-.64s'",
+#define ER_TABLEACCESS_DENIED_ERROR 1142
+"%-.16s command denied to user: '%-.32s@%-.64s' for table '%-.64s'",
+#define ER_COLUMNACCESS_DENIED_ERROR 1143
+"%-.16s command denied to user: '%-.32s@%-.64s' for column '%-.64s' in table '%-.64s'",
+#define ER_ILLEGAL_GRANT_FOR_TABLE 1144
+"Illegal GRANT/REVOKE command. Please consult the manual which privileges can be used.",
+#define ER_GRANT_WRONG_HOST_OR_USER 1145
+"The host or user argument to GRANT is too long",
+#define ER_NO_SUCH_TABLE 1146
+"Table '%-.64s.%-.64s' doesn't exist",
+#define ER_NONEXISTING_TABLE_GRANT 1147
+"There is no such grant defined for user '%-.32s' on host '%-.64s' on table '%-.64s'",
+#define ER_NOT_ALLOWED_COMMAND 1148
+"The used command is not allowed with this MySQL version",
+#define ER_SYNTAX_ERROR 1149
+"You have an error in your SQL syntax",
+#define ER_DELAYED_CANT_CHANGE_LOCK 1150
+"Delayed insert thread couldn't get requested lock for table %-.64s",
+#define ER_TOO_MANY_DELAYED_THREADS 1151
+"Too many delayed threads in use",
+#define ER_ABORTING_CONNECTION 1152
+"Aborted connection %ld to db: '%-.64s' user: '%-.32s' (%-.64s)",
+#define ER_NET_PACKET_TOO_LARGE 1153
+"Got a packet bigger than 'max_allowed_packet'",
+#define ER_NET_READ_ERROR_FROM_PIPE 1154
+"Got a read error from the connection pipe",
+#define ER_NET_FCNTL_ERROR 1155
+"Got an error from fcntl()",
+#define ER_NET_PACKETS_OUT_OF_ORDER 1156
+"Got packets out of order",
+#define ER_NET_UNCOMPRESS_ERROR 1157
+"Couldn't uncompress communication packet",
+#define ER_NET_READ_ERROR 1158
+"Got an error reading communication packets",
+#define ER_NET_READ_INTERRUPTED 1159
+"Got timeout reading communication packets",
+#define ER_NET_ERROR_ON_WRITE 1160
+"Got an error writing communication packets",
+#define ER_NET_WRITE_INTERRUPTED 1161
+"Got timeout writing communication packets",
+#define ER_TOO_LONG_STRING 1162
+"Result string is longer than max_allowed_packet",
+#define ER_TABLE_CANT_HANDLE_BLOB 1163
+"The used table type doesn't support BLOB/TEXT columns",
+#define ER_TABLE_CANT_HANDLE_AUTO_INCREMENT 1164
+"The used table type doesn't support AUTO_INCREMENT columns",
+#define ER_DELAYED_INSERT_TABLE_LOCKED 1165
+"INSERT DELAYED can't be used with table '%-.64s', because it is locked with LOCK TABLES",
+#define ER_WRONG_COLUMN_NAME 1166
+"Incorrect column name '%-.100s'",
+#define ER_WRONG_KEY_COLUMN 1167
+"The used table handler can't index column '%-.64s'",
+#define ER_WRONG_MRG_TABLE 1168
+"All tables in the MERGE table are not identically defined",
+#define ER_DUP_UNIQUE 1169
+"Can't write, because of unique constraint, to table '%-.64s'",
+#define ER_BLOB_KEY_WITHOUT_LENGTH 1170
+"BLOB column '%-.64s' used in key specification without a key length",
+#define ER_PRIMARY_CANT_HAVE_NULL 1171
+"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
+"Result consisted of more than one row",
+#define ER_REQUIRES_PRIMARY_KEY 1173
+"This table type requires a primary key",
+#define ER_NO_RAID_COMPILED 1174
+"This version of MySQL is not compiled with RAID support",
+#define ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE 1175
+"You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column",
diff --git a/Docs/net_doc.txt b/Docs/net_doc.txt
new file mode 100644
index 00000000000..e79ed9b5711
--- /dev/null
+++ b/Docs/net_doc.txt
@@ -0,0 +1,944 @@
+ MySQL Client - Server Protocol Ducumentation
+
+
+Introduction
+------------
+
+
+This paper has an objective of a through description of the
+client - server protocol which is embodied in MySQL. Particularly,
+this paper aims to document and describe:
+
+- manner in which MySQL server detects client connection requests and
+ creates connection
+- manner in which MySQL client C API call connects to server - the
+ entire protocol of sending / receiving data by MySQL server and C API
+ code
+- manner in which queries are sent by client C API calls to server
+- manner in which query results are sent by server
+- manner in which query results are resolved by server
+- sending and receiving of error messages
+
+
+This paper does not have the goal or describing nor documenting other
+related MySQL issues, like usage of thread libraries, MySQL standard
+library set, MySQL strings library and other MySQL specific libraries,
+type definitions and utilities.
+
+Issues that are covered by this paper are contained in the following
+source code files:
+
+- client/net.c and sql/net_serv.c, the two being identical
+- client/libmysql.c (not entire file is covered)
+- include/mysql_com.h
+- include/mysql.h
+- sql/mysqld.cc (not entire file is covered)
+- sql/net_pkg.cc
+- sql/sql_base.cc (not entire file is covered)
+- sql/sql_select.cc (not entire file is covered)
+- sql/sql_parse.cc (not entire file is covered)
+
+Beside this introduction this paper presents basic definitions,
+constants, structures and global variables, all related functions in
+server and in C API. Textual description of the entire protocol
+functioning is described in the last chapter of this paper.
+
+
+Constants, structures and global variables
+------------------------------------------
+
+This chapter will describe all constants, structures and
+global variables relevant to client - server protocol.
+
+Constants
+
+They are important as they contain default values, the ones
+that are valied if options are not set in any other way. Beside that
+MySQL source code does not contain a single non-defined constant in
+it's code. This description of constants does not include
+configuration and conditional compilation #defines.
+
+NAME_LEN - field and table name length, current value 64
+HOSTNAME_LENGTH - length of the host name, current value 64
+USERNAME_LENGTH - user name length, current vluae 16
+MYSQL_PORT - default TCP/IP port number, current value 3306
+MYSQL_UNIX_ADDR - full path of the default Unix socket file, current value
+ "/tmp/mysql.sock"
+MYSQL_NAMEDPIPE - full path of the default NT pipe file, current value
+ "MySQL"
+MYSQL_SERVICENAME - name of the MySQL Service on NT, current value "MySql"
+NET_HEADER_SIZE - size of the network header, when no
+ compression is used, current value 4
+COMP_HEADER_SIZE - additional size of network header when
+ compression is used, current value 3
+
+What follows are set of constants, defined in source only, which
+define capabilities of the client built with that version of C
+API. Simply, when some new feature is added in client, that client
+feature is defined, so that server can detect what capabilities a
+client program has.
+
+CLIENT_LONG_PASSWORD - client supports new more secure passwords
+CLIENT_LONG_FLAG - client uses longer flags
+CLIENT_CONNECT_WITH_DB - client can specify db on connect
+CLIENT_COMPRESS - client can use compression protocol
+CLIENT_ODBC - ODBC client
+CLIENT_LOCAL_FILES - client can use LOAD DATA INFILE LOCAL
+CLIENT_IGNORE_SPACE - client can Ignore spaces before '('
+CLIENT_CHANGE_USER - client supports the mysql_change_user()
+
+What follows are other constants, pertaining to timeouts and sizes
+
+MYSQL_ERRMSG_SIZE - maximum size of error message string, current value 200
+NET_READ_TIMEOUT - read timeout, current value 30 sec.
+NET_WRITE_TIMEOUT - write timeout, current value 60 sec.
+NET_WAIT_TIMEOUT - wait for new query timeout, current value 8*60*60
+ sec. i.e. 8 hours
+packet_error - value returned in case of socket errors, current
+ value -1
+TES_BLOCKING - used in debug mode for setting up blocking testing
+RETRY COUNT - number of times network read and write will be
+ retried, current value 1
+
+There are also error messages for last_errno, which depict system
+errors, and are used on the server only.
+
+ER_NET_PACKAGE_TOO_LARGE - packet is larger then max_allowed_packet
+ER_OUT_OF_RESOURCES - practically no more memory
+ER_NET_ERROR_ON_WRITE - error in writing to NT Named Pipe
+ER_NET_WRITE_INTERRUPTED - some signal or interrupt happened
+ during write
+ER_NET_READ_ERROR_FROM_PIPE - error in reading from NT Named Pipe
+ER_NET_FCNTL_ERROR - error in trying to set fcntl on socket
+ descriptor
+ER_NET_PACKETS_OUT_OF_ORDER - packet numbers on client and
+ server side differ
+ER_NET_UNCOMPRESS_ERROR - error in uncompress of compressed packet
+
+
+ Structs and eunms
+
+
+struct NET
+
+this is MySQL's network handle structure, used in all client / server
+read/write functions. On the server it is initialized and preserved in
+each thread. On the client, it is a part of MYSQL struct, which is
+MySQL handle used in all C API functions. This structure uniquely
+identifies a connection, either on the server or client side.
+This structure consists of the following
+fields:
+
+ Vio* vio; - explained above
+ HANDLE hPipe - Handle for NT Named Pipe file
+ my_socket fd - file descriptor used for both tcp socket and Unix socket file
+ int fcntl - contains info on fcntl options used on fd. Mostly
+ used for saving info if blocking is used or not
+ unsigned char *buff - network buffer used for storing data for
+ reading from / writing to socket
+ unsigned char,*buff_end - points to the end of buff
+ unsigned char *write_pos - present writing position in buff
+ unsigned char *read_pos - present reading postiion in
+ buff. This pointer is used for
+ reading data after calling
+ my_net_read function and function
+ that are just it's wrappers
+ char last_error[MYSQL_ERRMSG_SIZE] - holds last error message
+ unsigned int last_errno - holds last error code of the network
+ protocol. It's ossible values are
+ listed in above constants. It is
+ used only on the server side
+ unsigned int max_packet - holds current value of buff size
+ unsigned int timeout - stores read timeout value for that connection
+ unsigned int pkt_nr - stores a value of the current packet
+ number in a batch of packets. Used
+ primarily for detection of protocol
+ errors resulting in a mismatch
+ my_bool error - holds either 1 or 0 depending on the error condition
+ my_bool return_errno - if it's value != 0 then there is an
+ error in protocol mismatch between
+ client and server
+ my_bool compress - if true compression is used in the protocol
+ unsigned long remain_in_buf - used only in reading compressed
+ packets. Explained in my_net_read
+ unsigned long length - used only for storing a length of the
+ read packet. Explained in my_net_read
+ unsigned long buf_length - used only in reading compressed
+ packets. Explained in my_net_read
+ unsigned long where_b - used only in reading compressed
+ packets. Explained in my_net_read
+ short int more - used for reporting in mysql_list_processes
+ char save_char - used in reading compressed packets for saving
+ chars in order to make zero-delimited
+ strings. Explained in my_net_read
+
+Few typedefs will be defined for easier understanding of the text that
+follows.
+
+ typedef char **MYSQL_ROW - data containing one row of values
+ typedef unsigned int MYSQL_FIELD_OFFSET - offset in bytes of
+ the current field
+ typedef MYSQL_ROWS *MYSQL_ROW_OFFSET - offset in bytes of
+ the current row
+
+
+ struct MYSQL_FIELD - contains all info on the attributes of a
+specific column in a result set, plus info on lengths of the column in
+a result set. This struct is tagged as st_mysql_field. This structure
+consists of the following fields:
+
+ char *name - name of column
+ char *table - table of column if column was a field and not
+ expression or constant
+ char *def - default value (set by mysql_list_fields)
+ enum enum_field_types type - see above
+ unsigned int length - width of column in a current row
+ unsigned int max_length - maximum width of that column in
+ entire result set
+ unsigned int flags - corresponding to Extra in DESCRIBE
+ unsigned int decimals - number of decimals in field
+
+
+ struct MYSQL_ROWS - a node for each row in the single linked
+list forming entire result set. This struct is tagged as
+st_mysql_rows, and has two fields:
+
+ struct st_mysql_rows *next - pointer to a next one
+ MYSQL_ROW data - see above
+
+
+ struct MYSQL_DATA - contains all rows from result set. It is
+tagged as st_mysql_data and has following fields:
+
+ my_ulonglong rows - how many rows
+ unsigned int fields - how many columns
+ MYSQL_ROWS *data - see above. This is a first node of the
+ linked list
+ MEM_ROOT alloc - MEM_ROOT is MySQL memory allocation
+ structure, and this field is used to store
+ all fields and rows.
+
+
+ struct st_mysql_options - holds various client options, and
+contains following fields:
+
+ unsigned int connect_timeout - time in sec. for cennection
+ unsigned int client_flag - used to cold client capabilities
+ my_bool compress - boolean for compression
+ my_bool named_pipe - is Named Pipe used on NT
+ unsigned int port - what TCP port is used
+ char *host - host to connect to
+ char *init_command - command to be executed upon connection
+ char *user - account name on MySQL server
+ char *password - password for the above
+ char *unix_socket - full path for Unix socket file
+ char *db - default database
+ char *my_cnf_file - optional configuration file
+ char *my_cnf_group - optional header for options
+
+
+ struct MYSQL - MySQL client's handle. Required for any
+operation issed from client to server. Tagged as st_mysql and having
+following fields:
+
+ NET net - see above
+ char *host - host on which MySQL server is running
+ char *user - MySQL user name
+ char *passwd - password for above
+ char *unix_socket- full path of Unix socket file
+ char *server_version - version of the server
+ char *host_info - contains info on how has connection been
+ established, TCP port, socket or Named Pipe
+ char *info - used to store information on the query results,
+ like number of rows affected etc.
+ char *db - current database
+ unsigned int port -= TCP port in use
+ unsigned int client_flag - client capabilities
+ unsigned int server_capabilities - server capabilities
+ unsigned int protocol_version - version of the protocl
+ unsigned int field_count - used for storing number of fields
+ immidiately upon execution of a
+ query, but before fetching rows
+ unsigned long thread_id - server thread to which this connection is attached
+ my_ulonglong affected_rows - used for storing number of rows
+ immidiately upon execution of a
+ query, but before fetching rows
+ my_ulonglong insert_id - fetching LAST_INSERT_ID() through
+ client C API
+ my_ulonglong extra_info - used by mysqlshow
+ unsigned long packet_length - saving size of the first packet
+ upon execution of a query
+ enum mysql_status status - see above
+ MYSQL_FIELD *fields - see above
+ MEM_ROOT field_alloc - memory used for storing previous field
+ (fields)
+ my_bool free_me - boolean that flags if MYSQL was allocated in
+ mysql_init
+ my_bool reconnect - used to automatically reconnect
+ struct st_mysql_options options - see above
+ char scramble_buff[9] - key for scrambling password before
+ sending it to server
+
+
+ struct MYSQL_RES - tagged as st_mysql_res and used to store
+entire result set from a single query. Contains following fields:
+
+ my_ulonglong row_count - number of rows
+ unsigned int field_count - number of columns
+ unsigned int current_field - cursor for fetching fields
+ MYSQL_FIELD *fields - see above
+ MYSQL_DATA *data - see above, and used in buffered reads,
+ i.e. mysql_store_result only
+ MYSQL_ROWS *data_cursor - pointing to the field of above "data"
+ MEM_ROOT field_alloc - memory allocation for above "fields"
+ MYSQL_ROW row - used for storing row by row in unbuffered
+ reads, i.e. in mysql_use_result
+ MYSQL_ROW current_row - cursor to the current row for buffered
+ reads
+ unsigned long *lengths - column lengths of current row
+ MYSQL *handle - see above, used in unbuffered reads, i.e. in
+ mysql_use_resultq
+ my_bool eof - used my mysql_fetch_row as a marker for end of data
+
+
+
+
+ Global variables
+
+
+ unsigned long max_allowed_packet - maximum allowable value of
+ network buffer. Default
+ value - 1 Mb
+
+ unsigned long net_buffer_length - default, starting value of
+ network buffer - 8 Kb
+
+ unsigned long bytes_sent - total number of bytes written since
+ startup of the server
+
+ unsigned long bytes_received - total number of bytes read
+ since startup of the server
+
+
+ Synopsis of the basic client - server protocol
+ ----------------------------------------------
+
+ Purpose of this chapter is to provide a complete picture of
+the basic client - server protocol implemented in MySQL. It was felt
+it is necessary after writting descriptions for all of the functions
+involved in basic protocol. There are at present 11 functions
+involved, with several structures, many constants etc, which are all
+described in detail. But as a forest could not be seen from the trees,
+so a concept of the protocol could not be deciphered easily from a
+thourough documentation on minutae.
+
+ Althouch concept of the protocol was not changed with the
+introduction of vio system, embodied in violate.cc source file and VIO
+system, the introduction of these has changed a code substantially. Before
+VIO was introduced, functions for reading from / writing to network
+connection had to deal with various network standards. So, these functions
+depended on whether TCP port or Unix socket file or NT Named Pipe file is
+used. This is all changed now and single vio_ functions are called, while
+all this diversity is covered by vio_ functions.
+
+ In MySQL a specific buffered network input / output transport
+model has been implemented. Although each operating system mah have
+it's own buffering for network connections, MySQL has added it's own
+buffering model. This same for each of the three transport protocol
+types that are used in MySQL client - server communications, which are
+tcp sockets (on all systems), Unix socket files on Unix and Unix-like
+operating systems and Named Pipe files on NT. Alghouth tcp sockets
+are omnipresent, the later two types have been added for local
+connections. Those two connection types can be used in local modes
+only, i.e. when both client and server reside on the same host, and
+are introduced because they enable better speeds for local
+connections. This is especially usefull for WWW type of
+applications. Startup options of MySQl server allow that either tcp
+sockets or local connection (OS dependent) can be disallowed.
+
+ In order to be able to implement buffered input / output MySQL
+allocates a buffer. A starting size of this buffer is determined by a
+value of the global variable net_buffer_length, which can be changed
+at MySQL server startup. This is, as explained only a startup length
+of MySQL network buffer. As a signle item that has to be read /
+written can be larger then that value, MySQL will increase buffer size
+as long as that size reaches value of global variable
+max_aallowed_packet, which is also settable at server startup. Maximum
+value of this variable is limited by the way MySQL stores / reads
+sizes of packets to be sent / read, which means by the way MySQL
+formats packages.
+
+ Basically each packet consists of two parts, a header and
+data. In the case when compression is not used, header consists of 4
+bytes of which 3 contain a length of the packet to be sent and one
+holds a packet number. When compression is used there are
+onother 3 bytes which store a size of uncompressed data. Because of
+the way MySQL packs length into 3 bytes, plus due to the usage of some
+special values in the most significant byte, maximum size of
+max_allowed_packet is limited to 24 Mb at present. So, if compression
+is not used, at first 4 bytes are written to the buffer and then data
+itself. As MySQL buffers I/O logical packets are packet together until
+packets fill up entire size of the buffer. That size no less then
+net_buffer_size, but no greater then max_allowed_packet. So, actuall
+writting to the network is done when this buffer is filled up. As
+frequently sequence of buffers make a logicall unit, like a result
+set, then at the end of sending data, even if buffer is not full, data
+is written, i.e. flushed to the connection with a call of the
+net_flush function. In order to maintain that no single packet can be
+larger then this value, checks are made throughout a code, so that not
+signle field or command could exceed that value.
+
+ In order to maintain coherency in consicutive packets, each
+packet is numbered and their number stored as a part of a header, as
+explained above. Packets start with 0, so whenever a logical packet is
+written, that number is incremented. On the other side when packets
+are read, value that is fetched is compared with a value stored and if
+there is no mismatch that value is incremented too. Packet number is
+reset on the client side when unwanted connections are removed from
+the connection and on the server side when a new command hsa been
+started.
+
+
+ So, before writting, a buffer contains a sequence of logical
+packets, consisting of header plus data consequtively. In the case
+that compression is used, packet numbers are not stored in each header
+of the logical packets, but a whole buffer, or a part of it if
+flushing is done, containing one or more logical packets are
+compressed. In that case a new larger header, is formed, and all
+logical packets contained in the buffer are compressed together. This
+way only one packet is formed which makes several logical packets,
+which improves both speed and compression ratio. On the other side,
+when this large compressed packet is read, it is furst uncompressed,
+and then logical packets are sent, one by one, to the calling
+functions.
+
+
+ All this functionality is described in detail in the following
+chapter. It does not contain functions that form logical packets, or
+that read and write to connections but also functions that are used
+for initialisation, clearing of connections. There are functions at
+higher level dealing with sending fields, rows, establishing
+connections, sending commands, but those are not explained in the
+following chapter.
+
+
+ Functions utilized in client - server protocol
+ ----------------------------------------------
+
+ First of all, functions are described that are involved in
+praparing/ reading / writing data over TCP port , socket or named pipe
+file, and functions directly related to those. All of these functions
+are used both in server and client. Server and client specific code
+segments will be documented in each function description. Each MySQl
+function checks for errors in memory allocation / freeing, as well as
+in every OS call, like the one dealing with files and sockets, and for
+errors in indeginous MySQL function calls. This is expected, but has
+to be said, as not to repeat it in every function description.
+
+ Older versions of MySQL have utilized the following macros for
+reading from / writing to socket.
+
+ raw_net_read - calls OS function recv function that reads N
+ bytes from a socket into a buffer. Number of
+ bytes read is returned.
+
+ raw_net_write - calls OS funciton send to write N bytes from
+ a buffer to socket. Number of bytes written
+ is returned.
+
+ These macros are replaced with VIO (Virtual I/O) functions.
+
+
+ Function name: my_net_init
+
+ Parameters: struct NET *, enum_net_type, struct Vio
+
+ Return value : 1 for error, 0 for success
+
+ Function purpose: To initialize properly all NET fields,
+ allocate memory and set socket options
+
+ Function description
+
+ First of all, buff field of NET struct is allocated to the
+size of net_buffer_lenght, and on failure function exits with 0. All
+fields in NET are set to their default or starting values. As
+net_buffer_length and max_allowed_packet are configurable,
+max_allowed_packet is set equal to net_buffer_length it the later one
+is greater. max_packet if set for that NET to net_buffer_lenght, and
+buff_end points to buff end. vio feild is set to the second parameter.
+If it is a real connection, which is a case when second parameter is
+not null, then fd field is set by calling vio_fd function.read_pos and
+write_pos to buff, while remaining integers are set to 0. If function
+is run on the MySQL server on Unix and server is started in a test
+mode that would require testing of blocking, then vio_blocking
+function is called. Last, fast throughput mode is set by a call to
+vio_fastsend function.
+
+
+
+ Function name: net_end
+
+ Parameters: struct NET *
+
+ Return value : void
+
+ Function purpose: To release memory alloceted to buff
+
+
+
+ Function name: net_realloc (private, static function)
+
+ Parameters: struct NET, unlong (unsigned long)
+
+ Return value : 1 for error, 0 for success
+
+ Function purpose: To change memory allocated to buff
+
+ Function description
+
+ New length of buff field of NET struct is passed as second
+parameter. It is first checked versus max_allowd_packet and if greater
+error is returned. New length is aligned to 4096 boundary. Then , buff
+is reallocated, buff_end, max_packet and write_pas reset to the same
+values as in my_net_init.
+
+
+
+ Function name: net_clear (used on client side only)
+
+ Parameters: struct NET *
+
+ Return value : void
+
+ Function purpose: To read unread packets
+
+ Function description
+
+ This function is used on client side only, and is executed
+only if a program is not started in test mode. This function reads
+unread packets without processing them. First, non-blocking mode is
+set on systems that have not non-blocking mode defined. This is
+performed by checking a mode with vio_is_blocking function. and
+setting non-blocking mode by vio_blocking function. If this operation
+was successfull, then packets are read by vio_read function, to which
+vio field of NET is passed together with buff and max_packet field
+values. field of the same struct at a length of max_packet. If
+blocking was active before reading is performed, blocking is set with
+vio_blocking function. AFter reading has been performed, pkt_nr is
+reset to 0 and write_pos reset to buff. In order to clarify some
+matters non-blocking mode enables executing program to dissociate from
+a connection, so that error in connection would not hang entire
+program or it's thread.
+
+ Function name: net_flush
+
+ Parameters: struct NET *
+
+ Return value : 1 for error, 0 for success
+
+ Function purpose: To write remaining bytes in buff to socket
+
+ Function description
+
+ net_real_write (described below) is performed is write_pos
+differs from buff, both being fields of the only parameter. write_pos
+is reset to buff. This function has to be used, as MySQL uses buffered
+writes, as it will be more explained in a function net_write_buff.
+
+
+ Function name: my_net_write
+
+ Parameters: struct NET *, const char *, ulong
+
+ Return value : 1 for error, 0 for success
+
+ Function purpose: Write a logical packet in a first parameter
+ of second parameter length
+
+ Function description
+
+ The purpose of this function is to prepare a logical packet
+such that entire content of data, pointed to by second parametar and
+in length of third parameter is sent to the other side. In case of
+server, it is used for sending result sets, and in case of client it
+is used for sending local data. This function foremost prepares a
+header for the packet. Normal, header consists of 4 bytes, of which
+first 3 bytes contain a length of the packet, thereby limiting a
+maximum allowable length of a packet to 16 Mb, while a fourth byte
+contains a packet number, which is used when one large packet has to
+be divided into sequence of packets. This way each sub-packet gets
+it's number which should be matched on the other side. When
+compression is used another three bytes are added to packet header,
+thus packet header is in that case increased to 7 bytes. Additional
+three bytes are used to save a length of compressed data. As in
+connection that uses compression option, code packs packets together,,
+a header prepared by this function is later not used in writting to /
+reading from network, but only to distinguish logical packets within a
+buffered read operation.
+
+
+ This function, first stores a value for third parameter into a
+first 3 bytes of local char variable of NET_HEADER_SIZE size by usage
+of function int3store. Then, at this point, if compression is not
+used, pkt_nr is increased, and it's value stored in the last byte of
+the said local char[] variable. If compression is used 0 is stored in
+both values. Then those four bytes are sent to other side by the usage
+of the function net_write_buff(to be explained later on), and
+successfull, entire packet in second parameter of the length described
+in third parameter is sent by the usage of the same function.
+
+
+ Function name: net_write_command
+
+ Parameters: struct NET *, char, const char *, ulong
+
+ Return value : 1 for error, 0 for success
+
+ Function purpose: Send a command with a packet as in previous
+ function
+
+ Function description
+
+ This function is very similar to the previous one. The only
+difference is that first packet is enlarged by one byte, so that a
+command precedes a packet to be sent. This is implemented by
+increasing fist packet by one byte, which contains a command code. As
+command codes do not use a range of values that are used by chararcter
+sets, so when the other side receives a packet, first byte after
+header contains a command code. This function is used by client for
+sending all commands and queries, and by server in connection process
+and for sending errors.
+
+
+ Function name: net_write_buff (private, static function)
+
+ Parameters: struct NET *, const char *, uint
+
+ Return value : 1 for error, 0 for success
+
+ Function purpose: To write a packet of vany size by cutting it
+ and using next function for writing it
+
+ Function description
+
+ This function was created after compression feature has been
+added to MySQL. This function supposes that packets have already been
+properly formatted, regarding packet header etc. Principal reason for
+this function existst because a packet that is sent by client or
+server does not have to be less then max_packet. So this function
+first calculeates how much data has been left in a buff, by getting a
+difference between buff_end and write_pos and storing it to local
+variable left_length. Then a loop is run as long as a length to be
+sent is greater then length of left bytes (left_length). In a loop
+data from second parameter is copied to buff at write_pos, as much as
+it can be, i.e. by left_length. Then net_real_write function is called
+(see below) with NET, buff, and max_packet parameters. This function
+is the lowest level fucntion that writes data over established
+connection. In a loop, write_pos is reset to buff, a pointer to data
+(second parameter) is moved by teh amount of data sent (left_length),
+length of data to be sent (third parameter) is decreased by the amount
+sent (left_length) and left_length is reset to max_packet value, which
+ends a loop. This logic was necessary, as there could have been some
+data yet unsent (write_pos != buf), while data to be sent could be as
+large as necessary, thus requiring many loops. At the end of function,
+remaining data in second parameter are copied to buff at write_pos, by
+the remaining length of data to be sent (third parameter). So, in the
+next call of this function remaining data will be sent, as buff is
+used in a call to net_real_write. It is very important to note that if
+a packet to be sent is less then a number of bytes that are still
+available in buff, then there will be no writing over network, but
+only logical packets will be added one after another. This will
+accelerate network traffic, plus if a compression is used, the
+expected compression rate would be higher. That is why server or
+client functions that sends data uses at the end of data net_flush
+function described above.
+
+
+ Function name: net_real_write
+
+ Parameters: struct NET *, const char *, ulong
+
+ Return value : 1 for error, 0 for success
+
+ Function purpose: To write data to a socket or pipe, with
+ compression if used
+
+ Function description
+
+ First, more field is set to 2, to enable reporting in
+mysql_list_processes. Then if compression is enabled on that
+connection, a new local buffer (variable b) is initialized to the
+length of total header (normal header + compression header) and if no
+memory is available error is returned. This buffer (b) is used for
+holding a fineal, compressed packet to be written ove
+connection. Furthermore in compressiion initialization, Second
+parameter at length of third parameter is copied to the local buffer
+b, and MySQL's wrapped zlib's compression function is run at total
+header offset of the local buffer. Please, do note that this function
+does not test effectiveness of compression. If compression is turned
+on in some connection, it is used all of the time. Also, it is very
+important to be cognizant of the fact that this algorithm makes
+possible that a single compressed packet contains several logical
+packets. In this way compression rate is increased and network
+throughput is increased as well. However, this algorithm has
+consequences on the other sided, that reads compressed packet, which
+is covered in my_net_read function. After compression is done, a full
+compression header is properly formed with a packet number,
+compressed and uncompressed lengths. At the end of compression code,
+third parameter is increased by total header length, as the original
+header is not used (see above), and second parameter, pointer to data,
+is set to point to local buffer b, in order that a further flow of
+function is independent of compression. . If a function is executed
+on server side, a thread alarm initialized and if non-blocking is
+active set at NET_WRITE_TIMEOUT. Two local (char *) pointers are
+initialized, pos at beginning of second parameter, and end at end of
+data. Then a loop is run as long as all data is written, which means
+as long as pos != end. First vio_write function is called, with
+parameters of vio field, pos and size of data (end - pos). Number of
+bytes written over connection is saved in local variable (length). If
+error is returned local bool variable (interrupted) is set according
+to the return value of the vio_should_retry called with vio field as
+parameter. This bool variable indicates whether writing was
+interrupted in some way or not. Firther, error from vio_write is
+differently treated on Unix versus other OS's (Win32 or OS/2). On Unix
+an alarm is set if one is not in use, no bytes have been written and
+there has been no interruption. Also, in that case, if connection is
+not in blocking mode, a sub - loop is run as long as blocking is not
+set with vio_blocking function. Withing a loop another run of above
+vio_write is run based on return value of vio_is_retry function,
+-provided number of repeated writes is less then RETRY_COUNT. If that
+is not a case, error field of struct NET. is set to 1 and function
+exits. At the exit of sub-llop number of reruns already executed is
+reset to zero and another run of above vio_write function is
+attempted. If a function is run on Win32 and OS/2, and in the case
+that function flow was not interrupted and thread alarm is not in use,
+again a main loop is continued until pos != end. In the case that this
+function is executed on thread safe client program, a communication
+flow is tested on EINTR, caused by context switching, by use of
+vio_errno function, in which case a loop is continued. At the end of
+processing of the error from vio_write, error field of struct NET is
+set, and if on server last_errno field is set to
+ER_NET_WRITE_INTERRUPTED in the case thatb local bool variable
+(interrupted) is true or to ER_NET_ERROR_ON_WRITE. Before the end of
+loop, in order to make possible evaluation of the loop condition, pos
+is increased by a value writen in last iteration (length). Also global
+variable bytes_sent is increased by the same value, for status
+purposes. At the end of the functions more fields is reset, in case
+of compression, combression buffer (b) memory is released and if
+thread is still in use, it is ended and blocking state is reset to
+it's original state, and function returns error is all bytes are not
+written.
+
+
+
+ Function name: my_real_read (private, static function)
+
+ Parameters: struct NET *, ulong *
+
+ Return value : length of bytes read
+
+ Function purpose: low level network connection read function
+
+ Function description
+
+ This function has made as a separate one when compression was
+introduced in MySQL client - server protocol . It contains basic, low
+level network reading functionality, while all dealings with
+compressed packets are handled in next function. Compression in this
+function is only handled in as much to unfold a length of uncompressed
+data. First blocking state of connection is saved in local bool
+variable net_blocking, and field more is set 1 for deteiled reporting
+in mysqld_list_processes. A new thread alarm is initialized, in order
+to enable read timout handling, and if on server and a connection can
+block a program, the alarm is set at a value of timeout field. Local
+pointer is set to the position of the next logical packet, with it's
+header skipped, which is at field where_b offset from buff. Next, a
+two time run code is entered. A loop is run exactly two times becase
+first time number of bytes to be fetched (remain) are set to the
+header size, which is different when compression is used or not used
+on the connection. After first fetch has been done, number of packets
+that will be received in second iteration is well known, as fetched
+header contains a size of packet, packet number ,and in a case of
+compression a size of uncompressed packet. Then as long, as there are
+bytes to read a loop is entered with ffirst reading data from network
+connection with vio_read function, called with parameters of field
+vio, current position and remaining number of bytes, which value is
+hold by local variable (remain) initialized at a value of header size,
+which differs if compression is used. Number of bytes read are
+returned in local length variable. If error is returned local bool
+variable (interrupted) is set according to the return value of the
+vio_should_retry called with vio field as parameter. This bool
+variable indicates whether reading was interrupted in some way or not.
+Firther, error from vio_read is differently treated on Unix versus
+other OS's (Win32 or OS/2). On Unix an alarm is set if one is not in
+use, no bytes have been read and there has been no interruption. Also,
+in that case, if connection is not in blocking mode, a sub - loop is
+run as long as blocking is not set with vio_blocking function. Withing
+a loop another run of above vio_read is run based on return value of
+vio_is_retry function, -provided number of repeated writes is less
+then RETRY_COUNT. If that is not a case, error field of struct NET. is
+set to 1 and function exits. At the exit of sub-llop number of reruns
+already executed is reset to zero and another run of above vio_read
+function is attempted. If a function is run on Win32 and OS/2, and in
+the case that function flow was not interrupted and thread alarm is
+not in use, again a main loop is continued as long as there are bytes
+remaining. In the case that this function is executed on thread safe
+client program, then if a another run should be made, which is decided
+by the output of vio_should_retry function, in which case a loop is
+continued. At the end of processing of the error from vio_read, error
+field of struct NET is set, and if on server last_errno field is set
+to ER_NET_READ_INTERRUPTED in the case thatb local bool variable
+(interrupted) is true or to ER_NET_ERROR_ON_READ. In case of such an
+error this function exits and returns error. In a case when there is
+no error, number of remaining bytes (remain) is decreased by a number
+of bytes read, which should be zero, but in case it is not the entire
+code is still in while (remain > 0) loop, which will be exited
+immediately if it is. This has been done to accomodate errors in the
+traffic level and for the very slow connections. Current position in
+field buff is also moved by the amount of bytes read by vio_read
+funciton, and global variable bytes_received is increased by the same
+value in a thread safe manner. When a loop that is run until necessary
+bytes are read (remain) is finished, then if external loop is in it's
+first run, of the two, packet sequencing is tested on consistency by
+comparing a number contained at 4th byte in header with pkt_nre
+field. Header location is found at where_b offset to field_b. Usage of
+where_b is obligatory due to the possible compression usage. If there
+is no compression on a connection, then where_b is always 0. If there
+is a discrepancy, then first byte of the header is checked whether it
+is equal to 255, because when error is sent by a server, or by a
+client if it is sending data (like in LOAD DATA INFILE LOCAL...), then
+first byte in header is set to 255. If it is not 255, then an error on
+packets being out of order is printed. In any case, on server,
+last_errno field is set to ER_NET_PACKETS_OUT_OF_ORDER and a function
+returns with the error, i.e. value returned is packet_error. If a
+check on serial number of packet is successful, pkt_nr field is
+incremented in order to enable checking packet order with next packet
+and if compression is used, uncompressed length is extracted from a
+proper position in header and returned in the second parameter of this
+function. Length of the packet is saved, for the purpose of a proper
+return value from this function. Still in the first iteration of the
+main loop, a check must be made if field buff could accomodate entire
+package that comes, in it's compressed or uncompressed form. This is
+done in such a way, because zlib's compress and uncompress functions
+use a same memory area for compression / uncompression. Necessary
+field buff length is equal to current offset where data are (where_b
+which is zero for non-compression), plus the larger value of
+compressed or uncompressed package to be read in a second run. If this
+value is larger then a current length of field buff, which is read
+from field max_packet, then feild buff has to be reallocated. IF
+reallocation with net_realloc function fails, function is returned
+with error. Before a second loop is started, length to be read is set
+to the length of expected data and current position (pos) is set at
+where_b offset from field buff. At the end of function, if alarm is
+set, which is a case if it is run on server or on a client if a
+function is interrupted and another run of vio_read is attempted,
+alarm is ended and blocking state is resotred from the saved local bool
+variable net_blocking. Function returns number of bytes read or the
+error (packet_error).
+
+
+
+
+ Function name: my_net_read
+
+ Parameters: struct NET *
+
+ Return value : length of bytes read
+
+ Function purpose: Highest level general purpose reading function
+
+ Function description
+
+ First, if compression is not used, my_real_read is called,
+with struct NET * a first parameter, and pointer to local ulong
+complen as a second parameter, but it's value is not used here.
+Number of bytes read is returned in local ulong variable len. read_pos
+field is set to an offset of value of where_b field from field
+buff. where_b field actually denotes where in field buff is a current
+packet. If returned number of bytes read (local variable len) does not
+signal that an error in packet trnasmission occured, i.e. it is not
+set to packet_error, then a string contained in read_pos is zero
+terminated. Simply, the end of a string starting at read_pos, and
+ending at read_pos + len, is set to zero. This is done in that way,
+because mysql_use_result expects a zero terminated string, and
+function returns with a value local variable len. This ends this
+function in the case that compression is not used and a remaining code
+is executed only if compression is enabled on the connection. In
+order to explain how is compressed packet logically cut into
+meningfull packets, a full meaning of several NET feilds should be
+explained. First of all, fields in NET are used and not local
+variables, as all values should be saved between consecutive calls of
+this function. Simply, this function is called in order to return
+logical packets, but this function does not need to call my_real_read
+function everytime, because when a large packet is uncompressed, it
+may, but not necessarily so, contain several logical
+packets. Therefore, in oreder to preserve data on logical packets
+local variables are not used. Instead fields in NET struct are
+used. Field remain_in_buf denotes how many bytes of entire
+uncompressed packets is still contained withing buff. field buf_length
+saves a value of the length of entire uncompressed packet. field
+save_char is used to save a character at a position where a packet
+ends, which character has to be replaced with a zero, '\0', in order
+to make a logical packet zero delimited, for mysql_use_result. Field
+length stores a value of the length of compressed packet. Field
+read_pos as usual, points to the current reading position. This char *
+pointer is used by all fucntion calling this function in order to
+fetch their data. Field buff is not used for that purpose, but
+read_pos is used instead. This change was introduced with compression,
+when algorihtm accomodated grouping of several packets together. Now,
+that meanings of all relevant NET fields is complained, we can proceed
+with a flow of this functinn in case when compression is
+active. First, if there are remaining portions of compressed packet in
+a field buff, saved character value is set at a position where zero
+char '\0' was inserted to enable a string do be zero delimited for
+mysql_use_result. Then a loop is started. In the first part of the
+loop, if there are remaining bytes, local uchar *pos variable is set
+at a current position in field buff where a new packet starts. This
+position is an (buf_length - remain_in_buf) offset in field buff. As
+it is possible that next logical packet is not read to the full length
+in the remaining of the field buf, several things had to be
+inspected. It should be noted that data that is read from
+net_rweal_read contains only logical packets containing 4 byte headers
+only, being 4 byte headers prepared by my_net_write or
+net_write_command. But, when written, logical packet could be so
+divided that only a part of header is read in. Therefore after pointer
+to the start of the next packet has been saved, a check is made
+whether number of remaining bytes in buffer is less then 4, being 3
+bytes for length and one byte for packet number. If it is greater,
+then a length of the logical packet is extracted and saved a length
+field. Then a check is made whether entire packet is contained withing
+a buf, i.e. a check is made that a logical packet is fully contained
+in a buffer. In that case, number of bytes remaining in buffer is
+decreased by a full length of logical packet ( 4 + length field),
+read_pos is moved forward by 4 bytes to skip header and be set at a
+beginning of data in logical packet, length field is saved for a value
+to be returned in function and a loop is exited. In a case that
+entire logical packet is not contained within a buffer, then if length
+of the entire buffer differs from remaining length of logical packet,
+it (logical packet) is moved to the beginning of the field buff. If
+length of the entire buffer equals the remaining length of logical
+packet, where_b and buf_length fields are set to 0. This is done so
+that in both cases buffer is ready to accept next part of packet. In
+order to get a next part of a packet, still within a loop,
+my_real_read function is called and length of compressed packet is
+returned to a local len variable, and length of compressed data is
+returned in complen variable. In a case of non-compression value of
+complen is zero. If packet_error is from my_real_read function, this
+function returns also with packet_error. If it is not a packet_error
+my_uncompress function is called to uncompress data. It is called with
+offset of where_b data from field buff, as it is a postion where
+compressed packet starts, and with len and complen values, being
+lengths of compressed and uncompressed data. If there is no
+compression, 0 is returned for uncompressed size from my_real_read
+function, and my_uncompress wrapper function is made to skip zlib
+uncompress in that case. If error is returned fom my_uncompress,
+error field is set to 1, if on server last_errno is set to
+ER_NET_UNCOMPRESS_ERROR and loop is exited and function returns with
+packet_error. If not, buf_length and reamin_in_buf fields are set to
+the uncompressed size of buffer and a loop is continued. When a loop
+is exited save_char field is used to save a char at end of a logical
+packet, which is an offset of field len from position in field buff
+pointed by field read_os, in order that zero char is set at the same
+position, for mysql_use_result. Function returns a length of the
+logical packet without it's header.
diff --git a/Images/.cvsignore b/Images/.cvsignore
new file mode 100644
index 00000000000..6d0d61a83d5
--- /dev/null
+++ b/Images/.cvsignore
@@ -0,0 +1 @@
+logo_nusphere_b.tif
diff --git a/Makefile.am b/Makefile.am
new file mode 100755
index 00000000000..bd67f65f7c3
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,50 @@
+# Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; 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
+
+AUTOMAKE_OPTIONS = foreign
+TAR = gtar
+# These are built from source in the Docs directory
+EXTRA_DIST = INSTALL-SOURCE README \
+ COPYING COPYING.LIB MIRRORS
+SUBDIRS = include @docs_dirs@ @readline_dir@ libmysql client \
+ @sql_server_dirs@ scripts tests man \
+ @bench_dirs@ support-files
+
+# Relink after clean
+CLEANFILES = linked_client_sources linked_server_sources
+
+# This is just so that the linking is done early.
+config.h: linked_client_sources linked_server_sources
+
+linked_client_sources:
+ cd libmysql; $(MAKE) link_sources
+ echo timestamp > linked_client_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
+ echo timestamp > linked_server_sources
+
+# Create permission databases
+init-db: all
+ $(top_builddir)/scripts/mysql_install_db
+
+bin-dist: all
+ $(top_builddir)/scripts/make_binary_distribution
+
+.PHONY: init-db bin-dist
diff --git a/NEW-RPMS/.cvsignore b/NEW-RPMS/.cvsignore
new file mode 100644
index 00000000000..eee690e5a6c
--- /dev/null
+++ b/NEW-RPMS/.cvsignore
@@ -0,0 +1 @@
+MySQL-*.rpm
diff --git a/README b/README
new file mode 100644
index 00000000000..de6d2641bf0
--- /dev/null
+++ b/README
@@ -0,0 +1,54 @@
+This is a release of MySQL, a basically free SQL database server (more
+licence information in the PUBLIC file and in the reference manual).
+
+Please read the Upgrading section in the manual if emigration from
+3.20.# to 3.21.#. Otherwise it wont work!!
+
+The latest information about MySQL can be found at:
+http://www.mysql.com
+
+To see what it can do take a look at the features section in the
+manual.
+
+For installation instructions see the Installation chapter in the
+manual.
+
+For future plans see the TODO appendix in the manual.
+
+New features/bug fixes history is in the news appendix in the manual.
+
+For the currently known bugs/misfeatures (known errors) see the bugs
+appendix in the manual.
+
+For examples of SQL and benchmarking information see the bench
+directory.
+
+The manual mentioned above can be found in the Docs directory. The
+manual is available in the following formats: as text in
+Docs/manual.txt, as HTML in Docs/manual_toc.html, as GNU Info in
+Docs/mysql.info and as PostScript in Docs/manual.ps.
+
+For a contributed user manual see http://www.turbolift.com/mysql.
+
+MySQL is brought to you by: Michael (Monty) Widenius at TcX
+DataKonsult AB.
+
+For the other contributors see the Credits appendix in the manual.
+
+************************************************************
+
+IMPORTANT:
+
+Send bug (error) reports, questions and comments to the mailing list
+at mysql@lists.mysql.com
+
+Please use the 'mysqlbug' script when posting bug reports or questions
+about MySQL. mysqlbug will gather some information about your system
+and start your editor with a form in which you can describe your
+problem. Bug reports might be silently ignored by the MySQL
+maintainers if there is not a good reason included in the report as to
+why mysqlbug has not been used. A report that says 'MySQL does not
+work for me. Why?' is not consider a valid bug report.
+
+The mysqlbug script can be found in the 'scripts' directory in the
+distribution, that is 'there-you-installed-mysql/scripts'.
diff --git a/acconfig.h b/acconfig.h
new file mode 100755
index 00000000000..61b4e5caf8a
--- /dev/null
+++ b/acconfig.h
@@ -0,0 +1,228 @@
+/* acconfig.h
+ This file is in the public domain.
+
+ Descriptive text for the C preprocessor macros that
+ the distributed Autoconf macros can define.
+ No software package will use all of them; autoheader copies the ones
+ your configure.in uses into your configuration header file templates.
+
+ The entries are in sort -df order: alphabetical, case insensitive,
+ ignoring punctuation (such as underscores). Although this order
+ can split up related entries, it makes it easier to check whether
+ a given entry is in the file.
+
+ Leave the following blank line there!! Autoheader needs it. */
+
+
+/* Version of .frm files */
+#undef DOT_FRM_VERSION
+
+/* READLINE: */
+#undef FIONREAD_IN_SYS_IOCTL
+
+/* READLINE: Define if your system defines TIOCGWINSZ in sys/ioctl.h. */
+#undef GWINSZ_IN_SYS_IOCTL
+
+/* Handing of large files on Solaris 2.6 */
+#undef _FILE_OFFSET_BITS
+
+/* Do we have FIONREAD */
+#undef FIONREAD_IN_SYS_IOCTL
+
+/* atomic_add() from <asm/atomic.h> (Linux only) */
+#undef HAVE_ATOMIC_ADD
+
+/* atomic_sub() from <asm/atomic.h> (Linux only) */
+#undef HAVE_ATOMIC_SUB
+
+/* bool is not defined by all C++ compilators */
+#undef HAVE_BOOL
+
+/* Have berkeley db installed */
+#undef HAVE_BERKELEY_DB
+
+/* DSB style signals ? */
+#undef HAVE_BSD_SIGNALS
+
+/* Can netinet be included */
+#undef HAVE_BROKEN_NETINET_INCLUDES
+
+/* READLINE: */
+#undef HAVE_BSD_SIGNALS
+
+/* Define if we are using OSF1 DEC threads */
+#undef HAVE_DEC_THREADS
+
+/* Define if we are using OSF1 DEC threads on 3.2 */
+#undef HAVE_DEC_3_2_THREADS
+
+/* fp_except from ieeefp.h */
+#undef HAVE_FP_EXCEPT
+
+/* READLINE: */
+#undef HAVE_GETPW_DECLS
+
+/* In OSF 4.0f the 3'd argument to gethostname_r is hostent_data * */
+#undef HAVE_GETHOSTBYNAME_R_WITH_HOSTENT_DATA
+
+/* Solaris define gethostbyname_r with 5 arguments. glibc2 defines
+ this with 6 arguments */
+#undef HAVE_GLIBC2_STYLE_GETHOSTBYNAME_R
+
+/* Define if we have GNU readline */
+#undef HAVE_LIBREADLINE
+
+/* Define if have -lwrap */
+#undef HAVE_LIBWRAP
+
+/* Define if we are using Xavier Leroy's LinuxThreads */
+#undef HAVE_LINUXTHREADS
+
+/* Do we have lstat */
+#undef HAVE_LSTAT
+
+/* Do we use user level threads */
+#undef HAVE_mit_thread
+
+/* For some non posix threads */
+#undef HAVE_NONPOSIX_PTHREAD_GETSPECIFIC
+
+/* For some non posix threads */
+#undef HAVE_NONPOSIX_PTHREAD_MUTEX_INIT
+
+/* READLINE: */
+#undef HAVE_POSIX_SIGNALS
+
+/* Well.. */
+#undef HAVE_POSIX_SIGSETJMP
+
+/* sigwait with one argument */
+#undef HAVE_NONPOSIX_SIGWAIT
+
+/* pthread_attr_setscope */
+#undef HAVE_PTHREAD_ATTR_SETSCOPE
+
+/* POSIX readdir_r */
+#undef HAVE_READDIR_R
+
+/* POSIX sigwait */
+#undef HAVE_SIGWAIT
+
+/* Solaris define gethostbyaddr_r with 7 arguments. glibc2 defines
+ this with 8 arguments */
+#undef HAVE_SOLARIS_STYLE_GETHOST
+
+/* MIT pthreads does not support connecting with unix sockets */
+#undef HAVE_THREADS_WITHOUT_SOCKETS
+
+/* Timespec has a ts_sec instead of tv_sev */
+#undef HAVE_TIMESPEC_TS_SEC
+
+/* Have the tzname variable */
+#undef HAVE_TZNAME
+
+/* Define if the system files define uchar */
+#undef HAVE_UCHAR
+
+/* Define if the system files define uint */
+#undef HAVE_UINT
+
+/* Define if the system files define ulong */
+#undef HAVE_ULONG
+
+/* UNIXWARE7 threads are not posix */
+#undef HAVE_UNIXWARE7_THREADS
+
+/* new UNIXWARE7 threads that are not yet posix */
+#undef HAVE_UNIXWARE7_POSIX
+
+/* READLINE: */
+#undef HAVE_USG_SIGHOLD
+
+/* Handling of large files on Solaris 2.6 */
+#undef _LARGEFILE_SOURCE
+
+/* Handling of large files on Solaris 2.6 */
+#undef _LARGEFILE64_SOURCE
+
+/* Define if want -lwrap */
+#undef LIBWRAP
+
+/* Define to machine type name eg sun10 */
+#undef MACHINE_TYPE
+
+#undef MUST_REINSTALL_SIGHANDLERS
+
+/* Defined to used character set */
+#undef MY_CHARSET_CURRENT
+
+/* READLINE: no sys file*/
+#undef NO_SYS_FILE
+
+/* Program name */
+#undef PACKAGE
+
+/* mysql client protocoll version */
+#undef PROTOCOL_VERSION
+
+/* Define if qsort returns void */
+#undef QSORT_TYPE_IS_VOID
+
+/* Define as the return type of qsort (int or void). */
+#undef RETQSORTTYPE
+
+/* Size of off_t */
+#undef SIZEOF_OFF_T
+
+/* Define as the base type of the last arg to accept */
+#undef SOCKET_SIZE_TYPE
+
+#undef SPEED_T_IN_SYS_TYPES
+#undef SPRINTF_RETURNS_PTR
+#undef SPRINTF_RETURNS_INT
+#undef SPRINTF_RETURNS_GARBAGE
+
+/* Needed to get large file supportat HPUX 10.20 */
+#undef __STDC_EXT__
+
+#undef STRCOLL_BROKEN
+
+#undef STRUCT_DIRENT_HAS_D_FILENO
+#undef STRUCT_DIRENT_HAS_D_INO
+
+#undef STRUCT_WINSIZE_IN_SYS_IOCTL
+#undef STRUCT_WINSIZE_IN_TERMIOS
+
+/* Define to name of system eg solaris*/
+#undef SYSTEM_TYPE
+
+/* Define if you want to have threaded code. This may be undef on client code */
+#undef THREAD
+
+/* Should be client be thread safe */
+#undef THREAD_SAFE_CLIENT
+
+/* READLINE: */
+#undef TIOCSTAT_IN_SYS_IOCTL
+
+/* Use multi-byte character routines */
+#undef USE_MB
+#undef USE_MB_IDENT
+
+/* Use MySQL RAID */
+#undef USE_RAID
+
+/* Use strcoll() functions when comparing and sorting. */
+#undef USE_STRCOLL
+
+/* Program version */
+#undef VERSION
+
+/* READLINE: */
+#undef VOID_SIGHANDLER
+
+
+/* Leave that blank line there!! Autoheader needs it.
+ If you're adding to this file, keep in mind:
+ The entries are in sort -df order: alphabetical, case insensitive,
+ ignoring punctuation (such as underscores). */
diff --git a/acinclude.m4 b/acinclude.m4
new file mode 100644
index 00000000000..3db1e92a008
--- /dev/null
+++ b/acinclude.m4
@@ -0,0 +1,944 @@
+# Local macros for automake & autoconf
+
+# A local version of AC_CHECK_SIZEOF that includes sys/types.h
+dnl MYSQL_CHECK_SIZEOF(TYPE [, CROSS-SIZE])
+AC_DEFUN(MYSQL_CHECK_SIZEOF,
+[changequote(<<, >>)dnl
+dnl The name to #define.
+define(<<AC_TYPE_NAME>>, translit(sizeof_$1, [a-z *], [A-Z_P]))dnl
+dnl The cache variable name.
+define(<<AC_CV_NAME>>, translit(ac_cv_sizeof_$1, [ *], [_p]))dnl
+changequote([, ])dnl
+AC_MSG_CHECKING(size of $1)
+AC_CACHE_VAL(AC_CV_NAME,
+[AC_TRY_RUN([#include <stdio.h>
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+main()
+{
+ FILE *f=fopen("conftestval", "w");
+ if (!f) exit(1);
+ fprintf(f, "%d\n", sizeof($1));
+ exit(0);
+}], AC_CV_NAME=`cat conftestval`, AC_CV_NAME=0, ifelse([$2], , , AC_CV_NAME=$2))])dnl
+AC_MSG_RESULT($AC_CV_NAME)
+AC_DEFINE_UNQUOTED(AC_TYPE_NAME, $AC_CV_NAME)
+undefine([AC_TYPE_NAME])dnl
+undefine([AC_CV_NAME])dnl
+])
+
+#---START: Used in for client configure
+AC_DEFUN(MYSQL_TYPE_ACCEPT,
+[ac_save_CXXFLAGS="$CXXFLAGS"
+AC_CACHE_CHECK([base type of last arg to accept], mysql_cv_btype_last_arg_accept,
+AC_LANG_SAVE
+AC_LANG_CPLUSPLUS
+if test "$ac_cv_prog_gxx" = "yes"
+then
+ CXXFLAGS="$CXXFLAGS -Werror"
+fi
+mysql_cv_btype_last_arg_accept=none
+[AC_TRY_COMPILE([#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+],
+[int a = accept(1, (struct sockaddr *) 0, (socklen_t *) 0); return (a != 0);],
+mysql_cv_btype_last_arg_accept=socklen_t)]
+if test $mysql_cv_btype_last_arg_accept = none; then
+[AC_TRY_COMPILE([#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+],
+[int a = accept(1, (struct sockaddr *) 0, (size_t *) 0); return (a != 0);],
+mysql_cv_btype_last_arg_accept=size_t)]
+fi
+if test $mysql_cv_btype_last_arg_accept = none; then
+mysql_cv_btype_last_arg_accept=int
+fi)
+AC_LANG_RESTORE
+AC_DEFINE_UNQUOTED(SOCKET_SIZE_TYPE, $mysql_cv_btype_last_arg_accept)
+CXXFLAGS="$ac_save_CXXFLAGS"
+])
+#---END:
+
+dnl Find type of qsort
+AC_DEFUN(MYSQL_TYPE_QSORT,
+[AC_CACHE_CHECK([return type of qsort], mysql_cv_type_qsort,
+[AC_TRY_COMPILE([#include <stdlib.h>
+#ifdef __cplusplus
+extern "C"
+#endif
+void qsort(void *base, size_t nel, size_t width,
+ int (*compar) (const void *, const void *));
+],
+[int i;], mysql_cv_type_qsort=void, mysql_cv_type_qsort=int)])
+AC_DEFINE_UNQUOTED(RETQSORTTYPE, $mysql_cv_type_qsort)
+if test "$mysql_cv_type_qsort" = "void"
+then
+ AC_DEFINE_UNQUOTED(QSORT_TYPE_IS_VOID, 1)
+fi
+])
+
+AC_DEFUN(MYSQL_TIMESPEC_TS,
+[AC_CACHE_CHECK([if struct timespec has a ts_sec member], mysql_cv_timespec_ts,
+[AC_TRY_COMPILE([#include <pthread.h>
+#ifdef __cplusplus
+extern "C"
+#endif
+],
+[struct timespec abstime;
+
+abstime.ts_sec = time(NULL)+1;
+abstime.ts_nsec = 0;
+], mysql_cv_timespec_ts=yes, mysql_cv_timespec_ts=no)])
+if test "$mysql_cv_timespec_ts" = "yes"
+then
+ AC_DEFINE(HAVE_TIMESPEC_TS_SEC)
+fi
+])
+
+AC_DEFUN(MYSQL_TZNAME,
+[AC_CACHE_CHECK([if we have tzname variable], mysql_cv_tzname,
+[AC_TRY_COMPILE([#include <time.h>
+#ifdef __cplusplus
+extern "C"
+#endif
+],
+[ tzset();
+ return tzname[0] != 0;
+], mysql_cv_tzname=yes, mysql_cv_tzname=no)])
+if test "$mysql_cv_tzname" = "yes"
+then
+ AC_DEFINE(HAVE_TZNAME)
+fi
+])
+
+#---START: Used in for client configure
+AC_DEFUN(MYSQL_CHECK_ULONG,
+[AC_MSG_CHECKING(for type ulong)
+AC_CACHE_VAL(ac_cv_ulong,
+[AC_TRY_RUN([#include <stdio.h>
+#include <sys/types.h>
+main()
+{
+ ulong foo;
+ foo++;
+ exit(0);
+}], ac_cv_ulong=yes, ac_cv_ulong=no, ac_cv_ulong=no)])
+AC_MSG_RESULT($ac_cv_ulong)
+if test "$ac_cv_ulong" = "yes"
+then
+ AC_DEFINE(HAVE_ULONG)
+fi
+])
+
+AC_DEFUN(MYSQL_CHECK_UCHAR,
+[AC_MSG_CHECKING(for type uchar)
+AC_CACHE_VAL(ac_cv_uchar,
+[AC_TRY_RUN([#include <stdio.h>
+#include <sys/types.h>
+main()
+{
+ uchar foo;
+ foo++;
+ exit(0);
+}], ac_cv_uchar=yes, ac_cv_uchar=no, ac_cv_uchar=no)])
+AC_MSG_RESULT($ac_cv_uchar)
+if test "$ac_cv_uchar" = "yes"
+then
+ AC_DEFINE(HAVE_UCHAR)
+fi
+])
+
+AC_DEFUN(MYSQL_CHECK_UINT,
+[AC_MSG_CHECKING(for type uint)
+AC_CACHE_VAL(ac_cv_uint,
+[AC_TRY_RUN([#include <stdio.h>
+#include <sys/types.h>
+main()
+{
+ uint foo;
+ foo++;
+ exit(0);
+}], ac_cv_uint=yes, ac_cv_uint=no, ac_cv_uint=no)])
+AC_MSG_RESULT($ac_cv_uint)
+if test "$ac_cv_uint" = "yes"
+then
+ AC_DEFINE(HAVE_UINT)
+fi
+])
+
+#---END:
+
+AC_DEFUN(MYSQL_CHECK_FP_EXCEPT,
+[AC_MSG_CHECKING(for type fp_except)
+AC_CACHE_VAL(ac_cv_fp_except,
+[AC_TRY_RUN([#include <stdio.h>
+#include <sys/types.h>
+#include <ieeefp.h>
+main()
+{
+ fp_except foo;
+ foo++;
+ exit(0);
+}], ac_cv_fp_except=yes, ac_cv_fp_except=no, ac_cv_fp_except=no)])
+AC_MSG_RESULT($ac_cv_fp_except)
+if test "$ac_cv_fp_except" = "yes"
+then
+ AC_DEFINE(HAVE_FP_EXCEPT)
+fi
+])
+
+# From fileutils-3.14/aclocal.m4
+
+# @defmac AC_PROG_CC_STDC
+# @maindex PROG_CC_STDC
+# @ovindex CC
+# If the C compiler in not in ANSI C mode by default, try to add an option
+# to output variable @code{CC} to make it so. This macro tries various
+# options that select ANSI C on some system or another. It considers the
+# compiler to be in ANSI C mode if it defines @code{__STDC__} to 1 and
+# handles function prototypes correctly.
+#
+# Patched by monty to only check if __STDC__ is defined. With the original
+# check it's impossible to get things to work with the Sunpro compiler from
+# Workshop 4.2
+#
+# If you use this macro, you should check after calling it whether the C
+# compiler has been set to accept ANSI C; if not, the shell variable
+# @code{am_cv_prog_cc_stdc} is set to @samp{no}. If you wrote your source
+# code in ANSI C, you can make an un-ANSIfied copy of it by using the
+# program @code{ansi2knr}, which comes with Ghostscript.
+# @end defmac
+
+AC_DEFUN(AM_PROG_CC_STDC,
+[AC_REQUIRE([AC_PROG_CC])
+AC_MSG_CHECKING(for ${CC-cc} option to accept ANSI C)
+AC_CACHE_VAL(am_cv_prog_cc_stdc,
+[am_cv_prog_cc_stdc=no
+ac_save_CC="$CC"
+# Don't try gcc -ansi; that turns off useful extensions and
+# breaks some systems' header files.
+# AIX -qlanglvl=ansi
+# Ultrix and OSF/1 -std1
+# HP-UX -Aa -D_HPUX_SOURCE
+# SVR4 -Xc -D__EXTENSIONS__
+# removed "-Xc -D__EXTENSIONS__" beacause sun c++ does not like it.
+for ac_arg in "" -qlanglvl=ansi -std1 "-Aa -D_HPUX_SOURCE"
+do
+ CC="$ac_save_CC $ac_arg"
+ AC_TRY_COMPILE(
+[#if !defined(__STDC__)
+choke me
+#endif
+/* DYNIX/ptx V4.1.3 can't compile sys/stat.h with -Xc -D__EXTENSIONS__. */
+#ifdef _SEQUENT_
+# include <sys/types.h>
+# include <sys/stat.h>
+#endif
+], [
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};],
+[am_cv_prog_cc_stdc="$ac_arg"; break])
+done
+CC="$ac_save_CC"
+])
+AC_MSG_RESULT($am_cv_prog_cc_stdc)
+case "x$am_cv_prog_cc_stdc" in
+ x|xno) ;;
+ *) CC="$CC $am_cv_prog_cc_stdc" ;;
+esac
+])
+
+# serial 1
+
+AC_DEFUN(AM_PROG_INSTALL,
+[AC_REQUIRE([AC_PROG_INSTALL])
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL_PROGRAM}'
+AC_SUBST(INSTALL_SCRIPT)dnl
+])
+
+#
+# Check to make sure that the build environment is sane.
+#
+
+AC_DEFUN(AM_SANITY_CHECK,
+[AC_MSG_CHECKING([whether build environment is sane])
+sleep 1
+echo timestamp > conftestfile
+# Do this in a subshell so we don't clobber the current shell's
+# arguments. FIXME: maybe try `-L' hack like GETLOADAVG test?
+if (set X `ls -t $srcdir/configure conftestfile`; test "[$]2" = conftestfile)
+then
+ # Ok.
+ :
+else
+ AC_MSG_ERROR([newly created file is older than distributed files!
+Check your system clock])
+fi
+rm -f conftest*
+AC_MSG_RESULT(yes)])
+
+# Orginal from bash-2.0 aclocal.m4, Changed to use termcap last by monty.
+
+AC_DEFUN(MYSQL_CHECK_LIB_TERMCAP,
+[
+AC_CACHE_VAL(mysql_cv_termcap_lib,
+[AC_CHECK_LIB(ncurses, tgetent, mysql_cv_termcap_lib=libncurses,
+ [AC_CHECK_LIB(curses, tgetent, mysql_cv_termcap_lib=libcurses,
+ [AC_CHECK_LIB(termcap, tgetent, mysql_cv_termcap_lib=libtermcap,
+ mysql_cv_termcap_lib=NOT_FOUND)])])])
+AC_MSG_CHECKING(for termcap functions library)
+if test $mysql_cv_termcap_lib = NOT_FOUND; then
+AC_MSG_ERROR([No curses/termcap library found])
+elif test $mysql_cv_termcap_lib = libtermcap; then
+TERMCAP_LIB=-ltermcap
+elif test $mysql_cv_termcap_lib = libncurses; then
+TERMCAP_LIB=-lncurses
+else
+TERMCAP_LIB=-lcurses
+fi
+AC_MSG_RESULT($TERMCAP_LIB)
+])
+
+dnl Check type of signal routines (posix, 4.2bsd, 4.1bsd or v7)
+AC_DEFUN(MYSQL_SIGNAL_CHECK,
+[AC_REQUIRE([AC_TYPE_SIGNAL])
+AC_MSG_CHECKING(for type of signal functions)
+AC_CACHE_VAL(mysql_cv_signal_vintage,
+[
+ AC_TRY_LINK([#include <signal.h>],[
+ sigset_t ss;
+ struct sigaction sa;
+ sigemptyset(&ss); sigsuspend(&ss);
+ sigaction(SIGINT, &sa, (struct sigaction *) 0);
+ sigprocmask(SIG_BLOCK, &ss, (sigset_t *) 0);
+ ], mysql_cv_signal_vintage=posix,
+ [
+ AC_TRY_LINK([#include <signal.h>], [
+ int mask = sigmask(SIGINT);
+ sigsetmask(mask); sigblock(mask); sigpause(mask);
+ ], mysql_cv_signal_vintage=4.2bsd,
+ [
+ AC_TRY_LINK([
+ #include <signal.h>
+ RETSIGTYPE foo() { }], [
+ int mask = sigmask(SIGINT);
+ sigset(SIGINT, foo); sigrelse(SIGINT);
+ sighold(SIGINT); sigpause(SIGINT);
+ ], mysql_cv_signal_vintage=svr3, mysql_cv_signal_vintage=v7
+ )]
+ )]
+)
+])
+AC_MSG_RESULT($mysql_cv_signal_vintage)
+if test "$mysql_cv_signal_vintage" = posix; then
+AC_DEFINE(HAVE_POSIX_SIGNALS)
+elif test "$mysql_cv_signal_vintage" = "4.2bsd"; then
+AC_DEFINE(HAVE_BSD_SIGNALS)
+elif test "$mysql_cv_signal_vintage" = svr3; then
+AC_DEFINE(HAVE_USG_SIGHOLD)
+fi
+])
+
+AC_DEFUN(MYSQL_CHECK_GETPW_FUNCS,
+[AC_MSG_CHECKING(whether programs are able to redeclare getpw functions)
+AC_CACHE_VAL(mysql_cv_can_redecl_getpw,
+[AC_TRY_COMPILE([#include <sys/types.h>
+#include <pwd.h>
+extern struct passwd *getpwent();], [struct passwd *z; z = getpwent();],
+ mysql_cv_can_redecl_getpw=yes,mysql_cv_can_redecl_getpw=no)])
+AC_MSG_RESULT($mysql_cv_can_redecl_getpw)
+if test $mysql_cv_can_redecl_getpw = no; then
+AC_DEFINE(HAVE_GETPW_DECLS)
+fi
+])
+
+AC_DEFUN(MYSQL_HAVE_TIOCGWINSZ,
+[AC_MSG_CHECKING(for TIOCGWINSZ in sys/ioctl.h)
+AC_CACHE_VAL(mysql_cv_tiocgwinsz_in_ioctl,
+[AC_TRY_COMPILE([#include <sys/types.h>
+#include <sys/ioctl.h>], [int x = TIOCGWINSZ;],
+ mysql_cv_tiocgwinsz_in_ioctl=yes,mysql_cv_tiocgwinsz_in_ioctl=no)])
+AC_MSG_RESULT($mysql_cv_tiocgwinsz_in_ioctl)
+if test $mysql_cv_tiocgwinsz_in_ioctl = yes; then
+AC_DEFINE(GWINSZ_IN_SYS_IOCTL)
+fi
+])
+
+AC_DEFUN(MYSQL_HAVE_FIONREAD,
+[AC_MSG_CHECKING(for FIONREAD in sys/ioctl.h)
+AC_CACHE_VAL(mysql_cv_fionread_in_ioctl,
+[AC_TRY_COMPILE([#include <sys/types.h>
+#include <sys/ioctl.h>], [int x = FIONREAD;],
+ mysql_cv_fionread_in_ioctl=yes,mysql_cv_fionread_in_ioctl=no)])
+AC_MSG_RESULT($mysql_cv_fionread_in_ioctl)
+if test $mysql_cv_fionread_in_ioctl = yes; then
+AC_DEFINE(FIONREAD_IN_SYS_IOCTL)
+fi
+])
+
+AC_DEFUN(MYSQL_HAVE_TIOCSTAT,
+[AC_MSG_CHECKING(for TIOCSTAT in sys/ioctl.h)
+AC_CACHE_VAL(mysql_cv_tiocstat_in_ioctl,
+[AC_TRY_COMPILE([#include <sys/types.h>
+#include <sys/ioctl.h>], [int x = TIOCSTAT;],
+ mysql_cv_tiocstat_in_ioctl=yes,mysql_cv_tiocstat_in_ioctl=no)])
+AC_MSG_RESULT($mysql_cv_tiocstat_in_ioctl)
+if test $mysql_cv_tiocstat_in_ioctl = yes; then
+AC_DEFINE(TIOCSTAT_IN_SYS_IOCTL)
+fi
+])
+
+AC_DEFUN(MYSQL_STRUCT_DIRENT_D_INO,
+[AC_REQUIRE([AC_HEADER_DIRENT])
+AC_MSG_CHECKING(if struct dirent has a d_ino member)
+AC_CACHE_VAL(mysql_cv_dirent_has_dino,
+[AC_TRY_COMPILE([
+#include <stdio.h>
+#include <sys/types.h>
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#if defined(HAVE_DIRENT_H)
+# include <dirent.h>
+#else
+# define dirent direct
+# ifdef HAVE_SYS_NDIR_H
+# include <sys/ndir.h>
+# endif /* SYSNDIR */
+# ifdef HAVE_SYS_DIR_H
+# include <sys/dir.h>
+# endif /* SYSDIR */
+# ifdef HAVE_NDIR_H
+# include <ndir.h>
+# endif
+#endif /* HAVE_DIRENT_H */
+],[
+struct dirent d; int z; z = d.d_ino;
+], mysql_cv_dirent_has_dino=yes, mysql_cv_dirent_has_dino=no)])
+AC_MSG_RESULT($mysql_cv_dirent_has_dino)
+if test $mysql_cv_dirent_has_dino = yes; then
+AC_DEFINE(STRUCT_DIRENT_HAS_D_INO)
+fi
+])
+
+AC_DEFUN(MYSQL_TYPE_SIGHANDLER,
+[AC_MSG_CHECKING([whether signal handlers are of type void])
+AC_CACHE_VAL(mysql_cv_void_sighandler,
+[AC_TRY_COMPILE([#include <sys/types.h>
+#include <signal.h>
+#ifdef signal
+#undef signal
+#endif
+#ifdef __cplusplus
+extern "C"
+#endif
+void (*signal ()) ();],
+[int i;], mysql_cv_void_sighandler=yes, mysql_cv_void_sighandler=no)])dnl
+AC_MSG_RESULT($mysql_cv_void_sighandler)
+if test $mysql_cv_void_sighandler = yes; then
+AC_DEFINE(VOID_SIGHANDLER)
+fi
+])
+
+AC_DEFUN(MYSQL_CXX_BOOL,
+[
+AC_REQUIRE([AC_PROG_CXX])
+AC_MSG_CHECKING(if ${CXX} supports bool types)
+AC_CACHE_VAL(mysql_cv_have_bool,
+[
+AC_LANG_SAVE
+AC_LANG_CPLUSPLUS
+AC_TRY_COMPILE(,[bool b = true;],
+mysql_cv_have_bool=yes,
+mysql_cv_have_bool=no)
+AC_LANG_RESTORE
+])
+AC_MSG_RESULT($mysql_cv_have_bool)
+if test "$mysql_cv_have_bool" = yes; then
+AC_DEFINE(HAVE_BOOL)
+fi
+])dnl
+
+AC_DEFUN(MYSQL_STACK_DIRECTION,
+ AC_CACHE_CHECK(stack direction for C alloca, ac_cv_c_stack_direction,
+ [AC_TRY_RUN([find_stack_direction ()
+ {
+ static char *addr = 0;
+ auto char dummy;
+ if (addr == 0)
+ {
+ addr = &dummy;
+ return find_stack_direction ();
+ }
+ else
+ return (&dummy > addr) ? 1 : -1;
+ }
+ main ()
+ {
+ exit (find_stack_direction() < 0);
+ }], ac_cv_c_stack_direction=1, ac_cv_c_stack_direction=-1,
+ ac_cv_c_stack_direction=0)])
+ AC_DEFINE_UNQUOTED(STACK_DIRECTION, $ac_cv_c_stack_direction)
+)dnl
+
+AC_DEFUN(MYSQL_FUNC_ALLOCA,
+[
+# Since we have heard that alloca fails on IRIX never define it on a SGI machine
+if test ! "$host_vendor" = "sgi"
+then
+ AC_REQUIRE_CPP()dnl Set CPP; we run AC_EGREP_CPP conditionally.
+ # The Ultrix 4.2 mips builtin alloca declared by alloca.h only works
+ # for constant arguments. Useless!
+ AC_CACHE_CHECK([for working alloca.h], ac_cv_header_alloca_h,
+ [AC_TRY_LINK([#include <alloca.h>], [char *p = alloca(2 * sizeof(int));],
+ ac_cv_header_alloca_h=yes, ac_cv_header_alloca_h=no)])
+ if test $ac_cv_header_alloca_h = yes
+ then
+ AC_DEFINE(HAVE_ALLOCA)
+ fi
+
+ AC_CACHE_CHECK([for alloca], ac_cv_func_alloca_works,
+ [AC_TRY_LINK([
+ #ifdef __GNUC__
+ # define alloca __builtin_alloca
+ #else
+ # if HAVE_ALLOCA_H
+ # include <alloca.h>
+ # else
+ # ifdef _AIX
+ #pragma alloca
+ # else
+ # ifndef alloca /* predefined by HP cc +Olibcalls */
+ char *alloca ();
+ # endif
+ # endif
+ # endif
+ #endif
+ ], [char *p = (char *) alloca(1);],
+ ac_cv_func_alloca_works=yes, ac_cv_func_alloca_works=no)])
+ if test $ac_cv_func_alloca_works = yes; then
+ AC_DEFINE(HAVE_ALLOCA)
+ fi
+
+ if test $ac_cv_func_alloca_works = no; then
+ # The SVR3 libPW and SVR4 libucb both contain incompatible functions
+ # that cause trouble. Some versions do not even contain alloca or
+ # contain a buggy version. If you still want to use their alloca,
+ # use ar to extract alloca.o from them instead of compiling alloca.c.
+ ALLOCA=alloca.o
+ AC_DEFINE(C_ALLOCA)
+
+ AC_CACHE_CHECK(whether alloca needs Cray hooks, ac_cv_os_cray,
+ [AC_EGREP_CPP(webecray,
+ [#if defined(CRAY) && ! defined(CRAY2)
+ webecray
+ #else
+ wenotbecray
+ #endif
+ ], ac_cv_os_cray=yes, ac_cv_os_cray=no)])
+ if test $ac_cv_os_cray = yes; then
+ for ac_func in _getb67 GETB67 getb67; do
+ AC_CHECK_FUNC($ac_func, [AC_DEFINE_UNQUOTED(CRAY_STACKSEG_END, $ac_func)
+ break])
+ done
+ fi
+ fi
+ AC_SUBST(ALLOCA)dnl
+else
+ AC_MSG_RESULT("Skipped alloca tests")
+fi
+])
+
+AC_DEFUN(MYSQL_CHECK_LONGLONG_TO_FLOAT,
+[
+AC_MSG_CHECKING(if conversion of longlong to float works)
+AC_CACHE_VAL(ac_cv_conv_longlong_to_float,
+[AC_TRY_RUN([#include <stdio.h>
+typedef long long longlong;
+main()
+{
+ longlong ll=1;
+ float f;
+ FILE *file=fopen("conftestval", "w");
+ f = (float) ll;
+ fprintf(file,"%g\n",f);
+ close(file);
+ exit (0);
+}], ac_cv_conv_longlong_to_float=`cat conftestval`, ac_cv_conv_longlong_to_float=0, ifelse([$2], , , ac_cv_conv_longlong_to_float=$2))])dnl
+if test "$ac_cv_conv_longlong_to_float" = "1" -o "$ac_cv_conv_longlong_to_float" = "yes"
+then
+ ac_cv_conv_longlong_to_float=yes
+else
+ ac_cv_conv_longlong_to_float=no
+fi
+AC_MSG_RESULT($ac_cv_conv_longlong_to_float)
+])
+
+dnl ---------------------------------------------------------------------------
+dnl Macro: MYSQL_CHECK_BDB
+dnl Sets HAVE_BERKELEY_DB if inst library is found
+dnl Makes sure db version is >= 3.1.11
+dnl Looks in $srcdir for Berkeley distribution not told otherwise
+dnl ---------------------------------------------------------------------------
+
+AC_DEFUN([MYSQL_CHECK_BDB], [
+ AC_ARG_WITH([berkeley-db],
+ [\
+ --with-berkely-db[=DIR] Use BerkeleyDB located in DIR],
+ [bdb="$withval"],
+ [bdb=default])
+
+ AC_ARG_WITH([berkeley-db-includes],
+ [\
+ --with-berkeley-db-includes=DIR
+ Find Berkeley DB headers in DIR],
+ [bdb_includes="$withval"],
+ [bdb_includes=default])
+
+ AC_ARG_WITH([berkeley-db-libs],
+ [\
+ --with-berkeley-db-libs=DIR
+ Find Berkeley DB libraries in DIR],
+ [bdb_libs="$withval"],
+ [bdb_libs=default])
+
+ AC_MSG_CHECKING([for BerkeleyDB])
+
+dnl SORT OUT THE SUPPLIED ARGUMENTS TO DETERMINE WHAT TO DO
+dnl echo "DBG1: bdb='$bdb'; incl='$bdb_includes'; lib='$bdb_libs'"
+ have_berkeley_db=no
+ case "$bdb" in
+ no )
+ mode=no
+ AC_MSG_RESULT([no])
+ ;;
+ yes | default )
+ case "$bdb_includes---$bdb_libs" in
+ default---default )
+ mode=search-$bdb
+ AC_MSG_RESULT([searching...])
+ ;;
+ default---* | *---default | yes---* | *---yes )
+ AC_MSG_ERROR([if either 'includes' or 'libs' is specified, both must be specified])
+ ;;
+ * )
+ mode=supplied-two
+ AC_MSG_RESULT([supplied])
+ ;;
+ esac
+ ;;
+ * )
+ mode=supplied-one
+ AC_MSG_RESULT([supplied])
+ ;;
+ esac
+
+dnl echo "DBG2: [$mode] bdb='$bdb'; incl='$bdb_includes'; lib='$bdb_libs'"
+
+ case $mode in
+ no )
+ bdb_includes=
+ bdb_libs=
+ ;;
+ supplied-two )
+ MYSQL_CHECK_INSTALLED_BDB([$bdb_includes], [$bdb_libs])
+ case $bdb_dir_ok in
+ installed ) mode=yes ;;
+ * ) AC_MSG_ERROR([didn't find valid BerkeleyDB: $bdb_dir_ok]) ;;
+ esac
+ ;;
+ supplied-one )
+ MYSQL_CHECK_BDB_DIR([$bdb])
+ case $bdb_dir_ok in
+ source ) mode=compile ;;
+ installed ) mode=yes ;;
+ * ) AC_MSG_ERROR([didn't find valid BerkeleyDB: $bdb_dir_ok]) ;;
+ esac
+ ;;
+ search-* )
+ MYSQL_SEARCH_FOR_BDB
+ case $bdb_dir_ok in
+ source ) mode=compile ;;
+ installed ) mode=yes ;;
+ * )
+ # not found
+ case $mode in
+ *-yes ) AC_MSG_ERROR([no suitable BerkeleyDB found]) ;;
+ * ) mode=no ;;
+ esac
+ bdb_includes=
+ bdb_libs=
+ ;;
+ esac
+ ;;
+ *)
+ AC_MSG_ERROR([impossible case condition '$mode': please report this to bugs@lists.mysql.com])
+ ;;
+ esac
+
+dnl echo "DBG3: [$mode] bdb='$bdb'; incl='$bdb_includes'; lib='$bdb_libs'"
+ case $mode in
+ no )
+ AC_MSG_RESULT([Not using Berkeley DB])
+ ;;
+ yes )
+ have_berkeley_db="yes"
+ AC_MSG_RESULT([Using Berkeley DB in '$bdb_includes'])
+ ;;
+ compile )
+ have_berkeley_db="$bdb"
+ MYSQL_TOP_BUILDDIR([have_berkeley_db])
+ ;;
+ * )
+ AC_MSG_ERROR([impossible case condition '$mode': please report this to bugs@lists.mysql.com])
+ ;;
+ esac
+
+ AC_SUBST(bdb_includes)
+ AC_SUBST(bdb_libs)
+])
+
+AC_DEFUN([MYSQL_CHECK_INSTALLED_BDB], [
+dnl echo ["MYSQL_CHECK_INSTALLED_BDB ($1) ($2)"]
+ inc="$1"
+ lib="$2"
+ if test -f "$inc/db.h"
+ then
+ MYSQL_CHECK_BDB_VERSION([$inc/db.h],
+ [.*#define[ ]*], [[ ][ ]*])
+
+ if test X"$bdb_version_ok" = Xyes; then
+ save_LIBS="$LIBS"
+ LIBS="-L$lib $LIBS"
+ AC_CHECK_LIB(db,db_env_create, [
+ bdb_dir_ok=installed
+ MYSQL_TOP_BUILDDIR([inc])
+ MYSQL_TOP_BUILDDIR([lib])
+ bdb_includes="-I$inc"
+ bdb_libs="-L$lib -ldb"
+ ])
+ LIBS="$save_LIBS"
+ else
+ bdb_dir_ok="$bdb_version_ok"
+ fi
+ else
+ bdb_dir_ok="no db.h file in '$inc'"
+ fi
+])
+
+AC_DEFUN([MYSQL_CHECK_BDB_DIR], [
+dnl ([$bdb])
+dnl echo ["MYSQL_CHECK_BDB_DIR ($1)"]
+ dir="$1"
+
+ MYSQL_CHECK_INSTALLED_BDB([$dir/include], [$dir/lib])
+
+ if test X"bdb_dir_ok" != Xinstalled; then
+ # test to see if it's a source dir
+ rel="$dir/dist/RELEASE"
+ if test -f "$rel"; then
+ MYSQL_CHECK_BDB_VERSION([$rel], [], [=])
+ if test X"$bdb_version_ok" = Xyes; then
+ bdb_dir_ok=source
+ bdb="$dir"
+ MYSQL_TOP_BUILDDIR([dir])
+ bdb_includes="-I$dir/build_unix"
+ bdb_libs="-L$dir/build_unix -ldb"
+ else
+ bdb_dir_ok="$bdb_version_ok"
+ fi
+ else
+ bdb_dir_ok="'$dir' doesn't look like a BDB directory"
+ fi
+ fi
+])
+
+AC_DEFUN([MYSQL_SEARCH_FOR_BDB], [
+dnl echo ["MYSQL_SEARCH_FOR_BDB"]
+ bdb_dir_ok="no BerkeleyDB found"
+
+ for test_dir in db-*.*.* ../db-*.*.* /usr/local/BerkeleyDB*; do
+ MYSQL_CHECK_BDB_DIR([$test_dir])
+ if test X"$bdb_dir_ok" = Xsource || test X"$bdb_dir_ok" = Xinstalled; then
+ break
+ fi
+ done
+])
+
+dnl MYSQL_CHECK_BDB_VERSION takes 3 arguments:
+dnl 1) the file to look in
+dnl 2) the search pattern before DB_VERSION_XXX
+dnl 3) the search pattern between DB_VERSION_XXX and the number
+dnl It assumes that the number is the last thing on the line
+AC_DEFUN([MYSQL_CHECK_BDB_VERSION], [
+ db_major=`sed -e '/^[$2]DB_VERSION_MAJOR[$3]/ !d' -e 's///' [$1]`
+ db_minor=`sed -e '/^[$2]DB_VERSION_MINOR[$3]/ !d' -e 's///' [$1]`
+ db_patch=`sed -e '/^[$2]DB_VERSION_PATCH[$3]/ !d' -e 's///' [$1]`
+ test -z "$db_major" && db_major=0
+ test -z "$db_minor" && db_minor=0
+ test -z "$db_patch" && db_patch=0
+
+ if test $db_major -gt 3
+ then
+ bdb_version_ok=yes
+ elif test $db_major -eq 3 && test $db_minor -gt 1
+ then
+ bdb_version_ok=yes
+ elif test $db_major -eq 3 && test $db_minor -eq 1 && test $db_patch -ge 11
+ then
+ bdb_version_ok=yes
+ else
+ bdb_version_ok="invalid version $db_major.$db_minor.$db_patch"
+ bdb_version_ok="$bdb_version_ok (must be at least version 3.1.11)"
+ fi
+])
+
+AC_DEFUN([MYSQL_TOP_BUILDDIR], [
+ case $[$1] in
+ /* ) ;; # already an absolute path
+ * ) [$1]="'\$(top_builddir)/'$[$1]" ;;
+ esac
+])
+
+dnl ---------------------------------------------------------------------------
+dnl END OF MYSQL_CHECK_BDB SECTION
+dnl ---------------------------------------------------------------------------
+
+dnl ---------------------------------------------------------------------------
+dnl Got this from the GNU tar 1.13.11 distribution
+dnl by Paul Eggert <eggert@twinsun.com>
+dnl ---------------------------------------------------------------------------
+
+dnl By default, many hosts won't let programs access large files;
+dnl one must use special compiler options to get large-file access to work.
+dnl For more details about this brain damage please see:
+dnl http://www.sas.com/standards/large.file/x_open.20Mar96.html
+
+dnl Written by Paul Eggert <eggert@twinsun.com>.
+
+dnl Internal subroutine of AC_SYS_LARGEFILE.
+dnl AC_SYS_LARGEFILE_FLAGS(FLAGSNAME)
+AC_DEFUN(AC_SYS_LARGEFILE_FLAGS,
+ [AC_CACHE_CHECK([for $1 value to request large file support],
+ ac_cv_sys_largefile_$1,
+ [if ($GETCONF LFS_$1) >conftest.1 2>conftest.2 && test ! -s conftest.2
+ then
+ ac_cv_sys_largefile_$1=`cat conftest.1`
+ else
+ ac_cv_sys_largefile_$1=no
+ ifelse($1, CFLAGS,
+ [case "$host_os" in
+ # HP-UX 10.20 requires -D__STDC_EXT__ with gcc 2.95.1.
+changequote(, )dnl
+ hpux10.[2-9][0-9]* | hpux1[1-9]* | hpux[2-9][0-9]*)
+changequote([, ])dnl
+ if test "$GCC" = yes; then
+ ac_cv_sys_largefile_CFLAGS=-D__STDC_EXT__
+ fi
+ ;;
+ # IRIX 6.2 and later require cc -n32.
+changequote(, )dnl
+ irix6.[2-9]* | irix6.1[0-9]* | irix[7-9].* | irix[1-9][0-9]*)
+changequote([, ])dnl
+ if test "$GCC" != yes; then
+ ac_cv_sys_largefile_CFLAGS=-n32
+ fi
+ esac
+ if test "$ac_cv_sys_largefile_CFLAGS" != no; then
+ ac_save_CC="$CC"
+ CC="$CC $ac_cv_sys_largefile_CFLAGS"
+ AC_TRY_LINK(, , , ac_cv_sys_largefile_CFLAGS=no)
+ CC="$ac_save_CC"
+ fi])
+ fi
+ rm -f conftest*])])
+
+dnl Internal subroutine of AC_SYS_LARGEFILE.
+dnl AC_SYS_LARGEFILE_SPACE_APPEND(VAR, VAL)
+AC_DEFUN(AC_SYS_LARGEFILE_SPACE_APPEND,
+ [case $2 in
+ no) ;;
+ ?*)
+ case "[$]$1" in
+ '') $1=$2 ;;
+ *) $1=[$]$1' '$2 ;;
+ esac ;;
+ esac])
+
+dnl Internal subroutine of AC_SYS_LARGEFILE.
+dnl AC_SYS_LARGEFILE_MACRO_VALUE(C-MACRO, CACHE-VAR, COMMENT, CODE-TO-SET-DEFAULT)
+AC_DEFUN(AC_SYS_LARGEFILE_MACRO_VALUE,
+ [AC_CACHE_CHECK([for $1], $2,
+ [$2=no
+changequote(, )dnl
+ $4
+ for ac_flag in $ac_cv_sys_largefile_CFLAGS no; do
+ case "$ac_flag" in
+ -D$1)
+ $2=1 ;;
+ -D$1=*)
+ $2=`expr " $ac_flag" : '[^=]*=\(.*\)'` ;;
+ esac
+ done
+changequote([, ])dnl
+ ])
+ if test "[$]$2" != no; then
+ AC_DEFINE_UNQUOTED([$1], [$]$2, [$3])
+ fi])
+
+AC_DEFUN(AC_SYS_LARGEFILE,
+ [AC_REQUIRE([AC_CANONICAL_HOST])
+ AC_ARG_ENABLE(largefile,
+ [ --disable-large-files Omit support for large files])
+ if test "$enable_largefile" != no; then
+ AC_CHECK_TOOL(GETCONF, getconf)
+ AC_SYS_LARGEFILE_FLAGS(CFLAGS)
+ AC_SYS_LARGEFILE_FLAGS(LDFLAGS)
+ AC_SYS_LARGEFILE_FLAGS(LIBS)
+
+ for ac_flag in $ac_cv_sys_largefile_CFLAGS no; do
+ case "$ac_flag" in
+ no) ;;
+ -D_FILE_OFFSET_BITS=*) ;;
+ -D_LARGEFILE_SOURCE | -D_LARGEFILE_SOURCE=*) ;;
+ -D_LARGE_FILES | -D_LARGE_FILES=*) ;;
+ -D?* | -I?*)
+ AC_SYS_LARGEFILE_SPACE_APPEND(CPPFLAGS, "$ac_flag") ;;
+ *)
+ AC_SYS_LARGEFILE_SPACE_APPEND(CFLAGS, "$ac_flag") ;;
+ esac
+ done
+ AC_SYS_LARGEFILE_SPACE_APPEND(LDFLAGS, "$ac_cv_sys_largefile_LDFLAGS")
+ AC_SYS_LARGEFILE_SPACE_APPEND(LIBS, "$ac_cv_sys_largefile_LIBS")
+ AC_SYS_LARGEFILE_MACRO_VALUE(_FILE_OFFSET_BITS,
+ ac_cv_sys_file_offset_bits,
+ [Number of bits in a file offset, on hosts where this is settable.],
+ [case "$host_os" in
+ # HP-UX 10.20 and later
+ hpux10.[2-9][0-9]* | hpux1[1-9]* | hpux[2-9][0-9]*)
+ ac_cv_sys_file_offset_bits=64 ;;
+ esac])
+ AC_SYS_LARGEFILE_MACRO_VALUE(_LARGEFILE_SOURCE,
+ ac_cv_sys_largefile_source,
+ [Define to make fseeko etc. visible, on some hosts.],
+ [case "$host_os" in
+ # HP-UX 10.20 and later
+ hpux10.[2-9][0-9]* | hpux1[1-9]* | hpux[2-9][0-9]*)
+ ac_cv_sys_largefile_source=1 ;;
+ esac])
+ AC_SYS_LARGEFILE_MACRO_VALUE(_LARGE_FILES,
+ ac_cv_sys_large_files,
+ [Define for large files, on AIX-style hosts.],
+ [case "$host_os" in
+ # AIX 4.2 and later
+ aix4.[2-9]* | aix4.1[0-9]* | aix[5-9].* | aix[1-9][0-9]*)
+ ac_cv_sys_large_files=1 ;;
+ esac])
+ fi
+ ])
diff --git a/client/.cvsignore b/client/.cvsignore
new file mode 100644
index 00000000000..54bbaed97f5
--- /dev/null
+++ b/client/.cvsignore
@@ -0,0 +1,14 @@
+.deps
+.libs
+Makefile
+Makefile.in
+insert_test
+mysql
+mysql-test
+mysql_test
+mysqladmin
+mysqldump
+mysqlimport
+mysqlshow
+select_test
+thread_test
diff --git a/client/Attic/libmysql.c b/client/Attic/libmysql.c
new file mode 100644
index 00000000000..4f5e138fd53
--- /dev/null
+++ b/client/Attic/libmysql.c
@@ -0,0 +1,2392 @@
+/* Copyright Abandoned 1996 TCX DataKonsult AB & Monty Program KB & Detron HB
+ This file is public domain and comes with NO WARRANTY of any kind */
+
+#define DONT_USE_RAID
+#if defined(__WIN32__) || defined(WIN32)
+#include <winsock.h>
+#include <odbcinst.h>
+#endif
+#include <global.h>
+#include <my_sys.h>
+#include <mysys_err.h>
+#include <m_string.h>
+#include <m_ctype.h>
+#include "mysql.h"
+#include "mysql_version.h"
+#include "mysqld_error.h"
+#include "errmsg.h"
+#include <violite.h>
+#include <sys/stat.h>
+#include <signal.h>
+#ifdef HAVE_PWD_H
+#include <pwd.h>
+#endif
+#if !defined(MSDOS) && !defined(__WIN32__)
+#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
+#if defined(THREAD) && !defined(__WIN32__)
+#include <my_pthread.h> /* because of signal() */
+#endif
+#ifndef INADDR_NONE
+#define INADDR_NONE -1
+#endif
+
+static my_bool mysql_client_init=0;
+static MYSQL *current_mysql;
+uint mysql_port=0;
+my_string mysql_unix_port=0;
+
+#define CLIENT_CAPABILITIES (CLIENT_LONG_PASSWORD | CLIENT_LONG_FLAG | CLIENT_LOCAL_FILES)
+
+#if defined(MSDOS) || defined(__WIN32__)
+#define ERRNO WSAGetLastError()
+#define perror(A)
+#else
+#include <sys/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 remember_connection(MYSQL *mysql);
+static void read_user_name(char *name);
+static void append_wild(char *to,char *end,const char *wild);
+static my_bool mysql_reconnect(MYSQL *mysql);
+static int send_file_to_server(MYSQL *mysql,const char *filename);
+static sig_handler pipe_sig_handler(int sig);
+
+/*
+ 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.
+*/
+
+#if !defined(__WIN32__) && defined(SIGPIPE) && !defined(THREAD)
+#define init_sigpipe_variables sig_return old_signal_handler;
+#define set_sigpipe(mysql) if ((mysql)->client_flag & CLIENT_IGNORE_SIGPIPE) old_signal_handler=signal(SIGPIPE,pipe_sig_handler)
+#define reset_sigpipe(mysql) if ((mysql)->client_flag & CLIENT_IGNORE_SIGPIPE) signal(SIGPIPE,old_signal_handler);
+#else
+#define init_sigpipe_variables
+#define set_sigpipe(mysql)
+#define reset_sigpipe(mysql)
+#endif
+
+/****************************************************************************
+* 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().
+*
+* Base version coded by Steve Bernacki, Jr. <steve@navinet.net>
+*****************************************************************************/
+
+static int connect2(File s, const struct sockaddr *name, uint namelen, uint to)
+{
+#if defined(__WIN32__)
+ return connect(s, (struct sockaddr*) name, namelen);
+#else
+ int flags, res, s_err;
+ size_socket s_err_size = sizeof(uint);
+ fd_set sfds;
+ struct timeval tv;
+
+ /* If they passed us a timeout of zero, we should behave
+ * exactly like the normal connect() call does.
+ */
+
+ if (to == 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);
+ tv.tv_sec = (long) to;
+ tv.tv_usec = 0;
+ res = select(s+1, NULL, &sfds, NULL, &tv);
+ if (res <= 0) /* Never became writable */
+ 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 suceed */
+ errno = s_err;
+ return(-1); /* but return an error... */
+ }
+ return(0); /* It's all good! */
+#endif
+}
+
+/*
+** Create a named pipe connection
+*/
+
+#ifdef __WIN32__
+
+HANDLE create_named_pipe(NET *net, uint connect_timeout, char **arg_host,
+ char **arg_unix_socket)
+{
+ HANDLE hPipe=INVALID_HANDLE_VALUE;
+ char szPipeName [ 257 ];
+ DWORD dwMode;
+ int i;
+ my_bool testing_named_pipes=0;
+ char *host= *arg_host, *unix_socket= *arg_unix_socket;
+
+ if ( ! unix_socket || (unix_socket)[0] == 0x00)
+ unix_socket = mysql_unix_port;
+ if (!host || !strcmp(host,LOCAL_HOST))
+ host=LOCAL_HOST_NAMEDPIPE;
+
+ sprintf( szPipeName, "\\\\%s\\pipe\\%s", host, unix_socket);
+ DBUG_PRINT("info",("Server name: '%s'. Named Pipe: %s",
+ host, unix_socket));
+
+ for (i=0 ; i < 100 ; i++) /* Don't retry forever */
+ {
+ if ((hPipe = CreateFile(szPipeName,
+ GENERIC_READ | GENERIC_WRITE,
+ 0,
+ NULL,
+ OPEN_EXISTING,
+ 0,
+ NULL )) != INVALID_HANDLE_VALUE)
+ break;
+ if (GetLastError() != ERROR_PIPE_BUSY)
+ {
+ net->last_errno=CR_NAMEDPIPEOPEN_ERROR;
+ sprintf(net->last_error,ER(net->last_errno),host, unix_socket,
+ (ulong) GetLastError());
+ return INVALID_HANDLE_VALUE;
+ }
+ /* wait for for an other instance */
+ if (! WaitNamedPipe(szPipeName, connect_timeout*1000) )
+ {
+ net->last_errno=CR_NAMEDPIPEWAIT_ERROR;
+ sprintf(net->last_error,ER(net->last_errno),host, unix_socket,
+ (ulong) GetLastError());
+ return INVALID_HANDLE_VALUE;
+ }
+ }
+ if (hPipe == INVALID_HANDLE_VALUE)
+ {
+ net->last_errno=CR_NAMEDPIPEOPEN_ERROR;
+ sprintf(net->last_error,ER(net->last_errno),host, unix_socket,
+ (ulong) GetLastError());
+ return INVALID_HANDLE_VALUE;
+ }
+ dwMode = PIPE_READMODE_BYTE | PIPE_WAIT;
+ if ( !SetNamedPipeHandleState(hPipe, &dwMode, NULL, NULL) )
+ {
+ CloseHandle( hPipe );
+ net->last_errno=CR_NAMEDPIPESETSTATE_ERROR;
+ sprintf(net->last_error,ER(net->last_errno),host, unix_socket,
+ (ulong) GetLastError());
+ return INVALID_HANDLE_VALUE;
+ }
+ *arg_host=host ; *arg_unix_socket=unix_socket; /* connect arg */
+ return (hPipe);
+}
+#endif
+
+
+/*****************************************************************************
+** read a packet from server. Give error message if socket was down
+** or packet is an error message
+*****************************************************************************/
+
+static uint
+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=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);
+ my_free((gptr) cur,MYF(0));
+ }
+}
+
+
+static int
+simple_command(MYSQL *mysql,enum enum_server_command command, const char *arg,
+ uint length, my_bool skipp_check)
+{
+ NET *net= &mysql->net;
+ int result= -1;
+ init_sigpipe_variables
+
+ /* Don't give sigpipe errors if the client doesn't want them */
+ set_sigpipe(mysql);
+ if (mysql->net.vio == 0)
+ { /* Do reconnect if possible */
+ if (mysql_reconnect(mysql))
+ {
+ net->last_errno=CR_SERVER_GONE_ERROR;
+ strmov(net->last_error,ER(net->last_errno));
+ goto end;
+ }
+ }
+ if (mysql->status != MYSQL_STATUS_READY)
+ {
+ strmov(net->last_error,ER(mysql->net.last_errno=CR_COMMANDS_OUT_OF_SYNC));
+ goto end;
+ }
+
+ mysql->net.last_error[0]=0;
+ mysql->net.last_errno=0;
+ mysql->info=0;
+ mysql->affected_rows= ~(my_ulonglong) 0;
+ remember_connection(mysql);
+ net_clear(net); /* Clear receive buffer */
+ if (!arg)
+ arg="";
+
+ if (net_write_command(net,(uchar) command,arg,
+ length ? length :strlen(arg)))
+ {
+ DBUG_PRINT("error",("Can't send command to server. Error: %d",errno));
+ end_server(mysql);
+ if (mysql_reconnect(mysql) ||
+ net_write_command(net,(uchar) command,arg,
+ length ? length :strlen(arg)))
+ {
+ net->last_errno=CR_SERVER_GONE_ERROR;
+ strmov(net->last_error,ER(net->last_errno));
+ reset_sigpipe(mysql);
+ goto end;
+ }
+ }
+ result=0;
+ if (!skipp_check)
+ result= ((mysql->packet_length=net_safe_read(mysql)) == packet_error ?
+ -1 : 0);
+ end:
+ reset_sigpipe(mysql);
+ return result;
+}
+
+
+static void free_old_query(MYSQL *mysql)
+{
+ DBUG_ENTER("free_old_query");
+ if (mysql->fields)
+ free_root(&mysql->field_alloc);
+ init_alloc_root(&mysql->field_alloc,8192); /* 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(__WIN32__)
+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 __WIN32__
+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
+}
+
+
+/**************************************************************************
+** Store the server socket currently in use
+** Used by pipe_handler if error on socket interrupt
+**************************************************************************/
+
+static void
+remember_connection(MYSQL *mysql)
+{
+ current_mysql = mysql;
+}
+
+/**************************************************************************
+** Close the server connection if we get a SIGPIPE
+ ARGSUSED
+**************************************************************************/
+
+static sig_handler
+pipe_sig_handler(int sig __attribute__((unused)))
+{
+ DBUG_PRINT("info",("Hit by signal %d",sig));
+#ifdef DONT_REMEMBER_SIGNAL
+ (void) signal(SIGPIPE,pipe_sig_handler);
+#endif
+}
+
+
+/**************************************************************************
+** Shut down connection
+**************************************************************************/
+
+static void
+end_server(MYSQL *mysql)
+{
+ DBUG_ENTER("end_server");
+ if (mysql->net.vio != 0)
+ {
+ init_sigpipe_variables
+ DBUG_PRINT("info",("Net: %s", vio_description(mysql->net.vio)));
+ set_sigpipe(mysql);
+ vio_delete(mysql->net.vio);
+ reset_sigpipe(mysql);
+ 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);
+ 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",
+#ifdef HAVE_OPENSSL
+ "ssl_key" ,"ssl_cert" ,"ssl_ca" ,"ssl_capath",
+#endif /* HAVE_OPENSSL */
+ NullS
+};
+static TYPELIB option_types={array_elements(default_options)-1,(char*) "options",(char **) 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;
+#ifdef HAVE_OPENSSL
+ case 13: /* ssl_key */
+ my_free(options->ssl_key, MYF(MY_ALLOW_ZERO_PTR));
+ options->ssl_key = my_strdup(opt_arg, MYF(MY_WME));
+ break;
+ case 14: /* ssl_cert */
+ my_free(options->ssl_cert, MYF(MY_ALLOW_ZERO_PTR));
+ options->ssl_cert = my_strdup(opt_arg, MYF(MY_WME));
+ break;
+ case 15: /* ssl_ca */
+ my_free(options->ssl_ca, MYF(MY_ALLOW_ZERO_PTR));
+ options->ssl_ca = my_strdup(opt_arg, MYF(MY_WME));
+ break;
+ case 16: /* ssl_capath */
+ my_free(options->ssl_capath, MYF(MY_ALLOW_ZERO_PTR));
+ options->ssl_capath = my_strdup(opt_arg, MYF(MY_WME));
+ break;
+#endif /* HAVE_OPENSSL */
+ 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 (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); /* 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=(uint) 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)));
+#ifdef __WIN32__
+ mysql->options.connect_timeout=20;
+#endif
+ return mysql;
+}
+
+
+static void mysql_once_init()
+{
+ if (!mysql_client_init)
+ {
+ mysql_client_init=1;
+ my_init(); /* Will init threads */
+ init_client_errs();
+ if (!mysql_port)
+ {
+ mysql_port = MYSQL_PORT;
+#ifndef MSDOS
+ {
+ struct servent *serv_ptr;
+ char *env;
+ if ((serv_ptr = getservbyname("mysql", "tcp")))
+ mysql_port = (uint) ntohs((ushort) serv_ptr->s_port);
+ if ((env = getenv("MYSQL_TCP_PORT")))
+ mysql_port =(uint) atoi(env);
+ }
+#endif
+ }
+ if (!mysql_unix_port)
+ {
+ char *env;
+#ifdef __WIN32__
+ mysql_unix_port = (char*) MYSQL_NAMEDPIPE;
+#else
+ mysql_unix_port = (char*) MYSQL_UNIX_ADDR;
+#endif
+ if ((env = getenv("MYSQL_UNIX_PORT")))
+ mysql_unix_port = env;
+ }
+ mysql_debug(NullS);
+#if defined(SIGPIPE) && !defined(THREAD)
+ (void) signal(SIGPIPE,SIG_IGN);
+#endif
+ }
+#ifdef THREAD
+ else
+ my_thread_init(); /* Init if new thread */
+#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->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);
+ 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)
+{
+ 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;
+ delete reinterpret_cast<VioConnectorFd*>(mysql->connector_fd);
+ mysql->connector_fd = 0;
+ return 0;
+}
+#endif /* HAVE_OPENSSL */
+
+/**************************************************************************
+** 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],*end,*host_info;
+ int sock;
+ ulong ip_addr;
+ struct sockaddr_in sock_addr;
+ uint pkt_length;
+ NET *net;
+#ifdef __WIN32__
+ HANDLE hPipe=INVALID_HANDLE_VALUE;
+#endif
+#ifdef HAVE_SYS_UN_H
+ struct sockaddr_un UNIXaddr;
+#endif
+ init_sigpipe_variables
+ DBUG_ENTER("mysql_real_connect");
+
+ DBUG_PRINT("enter",("host: %s db: %s user: %s",
+ host ? host : "(Null)",
+ db ? db : "(Null)",
+ user ? user : "(Null)"));
+
+ /* Don't give sigpipe errors if the client doesn't want them */
+ set_sigpipe(mysql);
+ /* 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;
+#ifndef DONT_USE_MYSQL_PWD
+ if (!passwd)
+ passwd=getenv("MYSQL_PWD"); /* get it from environment (haneke) */
+#endif
+ }
+ if (!db || !db[0])
+ db=mysql->options.db;
+ if (!port)
+ port=mysql->options.port;
+ if (!unix_socket)
+ unix_socket=mysql->options.unix_socket;
+
+ remember_connection(mysql);
+ mysql->reconnect=1; /* Reconnect as default */
+ net= &mysql->net;
+ net->vio = 0; /* If something goes wrong */
+
+ /*
+ ** Grab a socket and connect it to the server
+ */
+
+#if defined(HAVE_SYS_UN_H)
+ if ((!host || !strcmp(host,LOCAL_HOST)) && (unix_socket || mysql_unix_port))
+ {
+ host=LOCAL_HOST;
+ if (!unix_socket)
+ unix_socket=mysql_unix_port;
+ host_info=(char*) ER(CR_LOCALHOST_CONNECTION);
+ DBUG_PRINT("info",("Using UNIX sock '%s'",unix_socket));
+ if ((sock = socket(AF_UNIX,SOCK_STREAM,0)) == SOCKET_ERROR)
+ {
+ net->last_errno=CR_SOCKET_CREATE_ERROR;
+ sprintf(net->last_error,ER(net->last_errno),ERRNO);
+ goto error;
+ }
+ net->vio = vio_new(sock, VIO_TYPE_SOCKET, TRUE);
+ bzero((char*) &UNIXaddr,sizeof(UNIXaddr));
+ UNIXaddr.sun_family = AF_UNIX;
+ strmov(UNIXaddr.sun_path, unix_socket);
+ if (connect2(sock,(struct sockaddr *) &UNIXaddr, sizeof(UNIXaddr),
+ mysql->options.connect_timeout) <0)
+ {
+ DBUG_PRINT("error",("Got error %d on connect to local server",ERRNO));
+ net->last_errno=CR_CONNECTION_ERROR;
+ sprintf(net->last_error,ER(net->last_errno),unix_socket,ERRNO);
+ goto error;
+ }
+ }
+ else
+#elif defined(__WIN32__)
+ {
+ if ((unix_socket ||
+ !host && is_NT() ||
+ host && !strcmp(host,LOCAL_HOST_NAMEDPIPE) ||
+ mysql->options.named_pipe || !have_tcpip))
+ {
+ sock=0;
+ if ((hPipe=create_named_pipe(net, mysql->options.connect_timeout,
+ (char**) &host, (char**) &unix_socket)) ==
+ INVALID_HANDLE_VALUE)
+ {
+ DBUG_PRINT("error",
+ ("host: '%s' socket: '%s' named_pipe: %d have_tcpip: %d",
+ host ? host : "<null>",
+ unix_socket ? unix_socket : "<null>",
+ (int) mysql->options.named_pipe,
+ (int) have_tcpip));
+ if (mysql->options.named_pipe ||
+ (host && !strcmp(host,LOCAL_HOST_NAMEDPIPE)) ||
+ (unix_socket && !strcmp(unix_socket,MYSQL_NAMEDPIPE)))
+ goto error; /* User only requested named pipes */
+ /* Try also with TCP/IP */
+ }
+ else
+ {
+ net->vio=vio_new_win32pipe(hPipe);
+ sprintf(host_info=buff, ER(CR_NAMEDPIPE_CONNECTION), host,
+ unix_socket);
+ }
+ }
+ }
+ if (hPipe == INVALID_HANDLE_VALUE)
+#endif
+ {
+ unix_socket=0; /* This is not used */
+ if (!port)
+ port=mysql_port;
+ if (!host)
+ host=LOCAL_HOST;
+ sprintf(host_info=buff,ER(CR_TCP_CONNECTION),host);
+ DBUG_PRINT("info",("Server name: '%s'. TCP sock: %d", host,port));
+ if ((sock = socket(AF_INET,SOCK_STREAM,0)) == SOCKET_ERROR)
+ {
+ net->last_errno=CR_IPSOCK_ERROR;
+ sprintf(net->last_error,ER(net->last_errno),ERRNO);
+ goto error;
+ }
+ net->vio = vio_new(sock,VIO_TYPE_TCPIP,FALSE);
+ bzero((char*) &sock_addr,sizeof(sock_addr));
+ sock_addr.sin_family = AF_INET;
+
+ /*
+ ** The server name may be a host name or IP address
+ */
+
+ if ((int) (ip_addr = inet_addr(host)) != (int) INADDR_NONE)
+ {
+ memcpy(&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)
+ {
+ net->last_errno=CR_UNKNOWN_HOST;
+ sprintf(net->last_error, ER(CR_UNKNOWN_HOST), host, tmp_errno);
+ goto error;
+ }
+ memcpy(&sock_addr.sin_addr,hp->h_addr, (size_t) hp->h_length);
+ }
+#else
+ {
+ struct hostent *hp;
+ if (!(hp=gethostbyname(host)))
+ {
+ net->last_errno=CR_UNKNOWN_HOST;
+ sprintf(net->last_error, ER(CR_UNKNOWN_HOST), host, errno);
+ goto error;
+ }
+ memcpy(&sock_addr.sin_addr,hp->h_addr, (size_t) hp->h_length);
+ }
+#endif
+ sock_addr.sin_port = (ushort) htons((ushort) port);
+ if (connect2(sock,(struct sockaddr *) &sock_addr, sizeof(sock_addr),
+ mysql->options.connect_timeout) <0)
+ {
+ DBUG_PRINT("error",("Got error %d on connect to '%s'",ERRNO,host));
+ net->last_errno= CR_CONN_HOST_ERROR;
+ sprintf(net->last_error ,ER(CR_CONN_HOST_ERROR), host, ERRNO);
+ goto error;
+ }
+ }
+
+ if (!net->vio || 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;
+ }
+ vio_keepalive(net->vio,TRUE);
+
+ /* Get version info */
+ mysql->protocol_version= PROTOCOL_VERSION; /* Assume this */
+ 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);
+ if (pkt_length > (uint) (end+9 - (char*) net->read_pos))
+ mysql->server_capabilities=uint2korr(end+9);
+
+ /* Save connection information */
+ if (!user) user="";
+ if (!passwd) passwd="";
+ if (!my_multi_malloc(MYF(0),
+ &mysql->host_info,strlen(host_info)+1,
+ &mysql->host,strlen(host)+1,
+ &mysql->unix_socket,unix_socket ? strlen(unix_socket)+1
+ :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",
+ mysql->server_version,mysql->server_capabilities));
+
+ /* Send client information for access check */
+ client_flag|=CLIENT_CAPABILITIES;
+
+#ifdef HAVE_OPENSSL
+ if (mysql->options.use_ssl)
+ client_flag|=CLIENT_SSL;
+#endif /* HAVE_OPENSSL */
+
+ if (db)
+ client_flag|=CLIENT_CONNECT_WITH_DB;
+#ifdef HAVE_COMPRESS
+ if (mysql->server_capabilities & CLIENT_COMPRESS &&
+ (mysql->options.compress || client_flag & CLIENT_COMPRESS))
+ client_flag|=CLIENT_COMPRESS; /* We will use compression */
+ else
+#endif
+ client_flag&= ~CLIENT_COMPRESS;
+
+#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;
+ }
+#endif /* HAVE_OPENSSL */
+
+ int2store(buff,client_flag);
+ mysql->client_flag=client_flag;
+
+#ifdef HAVE_OPENSSL
+ /* Oops.. are we careful enough to not send ANY information */
+ /* without encryption? */
+ if (client_flag & CLIENT_SSL)
+ {
+ if (my_net_write(net,buff,(uint) (2)) || net_flush(net))
+ 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);
+ }
+#endif /* HAVE_OPENSSL */
+
+ 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 && (mysql->server_capabilities & CLIENT_CONNECT_WITH_DB))
+ {
+ end=strmov(end+1,db);
+ mysql->db=my_strdup(db,MYF(MY_WME));
+ db=0;
+ }
+ if (my_net_write(net,buff,(uint) (end-buff)) || net_flush(net) ||
+ net_safe_read(mysql) == packet_error)
+ goto error;
+ if (client_flag & CLIENT_COMPRESS) /* We will use compression */
+ net->compress=1;
+ 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);
+}
+
+
+static my_bool mysql_reconnect(MYSQL *mysql)
+{
+ MYSQL tmp_mysql;
+ DBUG_ENTER("mysql_reconnect");
+
+ if (!mysql->reconnect || !mysql->host_info)
+ DBUG_RETURN(1);
+ mysql_init(&tmp_mysql);
+ tmp_mysql.options=mysql->options;
+ if (!mysql_real_connect(&tmp_mysql,mysql->host,mysql->user,mysql->passwd,
+ mysql->db, mysql->port, mysql->unix_socket,
+ mysql->client_flag))
+ DBUG_RETURN(1);
+ tmp_mysql.free_me=mysql->free_me;
+ mysql->free_me=0;
+ bzero((char*) &mysql->options,sizeof(&mysql->options));
+ mysql_close(mysql);
+ memcpy(mysql,&tmp_mysql,sizeof(tmp_mysql));
+ net_clear(&mysql->net);
+ mysql->affected_rows= ~(my_ulonglong) 0;
+ 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,(uint) (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,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,NullS,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.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));
+ /* 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,strlen(query));
+}
+
+
+int STDCALL
+mysql_real_query(MYSQL *mysql, const char *query,uint length)
+{
+ uchar *pos;
+ ulong field_count;
+ MYSQL_DATA *fields;
+ 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) ||
+ (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 (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 */
+ }
+ 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);
+}
+
+
+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
+ {
+ res->eof=1;
+ res->handle->status=MYSQL_STATUS_READY;
+ }
+ }
+ DBUG_RETURN((MYSQL_ROW) NULL);
+ }
+ {
+ MYSQL_ROW tmp;
+ if (!res->data_cursor)
+ 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(%d)",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 dosen'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,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, (uint) 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,(uint) strlen(db),0));
+}
+
+
+int STDCALL
+mysql_shutdown(MYSQL *mysql)
+{
+ DBUG_ENTER("mysql_shutdown");
+ DBUG_RETURN(simple_command(mysql,COM_SHUTDOWN,0,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,0));
+}
+
+char * STDCALL
+mysql_stat(MYSQL *mysql)
+{
+ DBUG_ENTER("mysql_stat");
+ if (simple_command(mysql,COM_STATISTICS,0,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,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;
+ 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 mysql_num_rows(MYSQL_RES *res)
+{
+ return res->row_count;
+}
+
+unsigned int mysql_num_fields(MYSQL_RES *res)
+{
+ return res->field_count;
+}
+
+my_bool mysql_eof(MYSQL_RES *res)
+{
+ return res->eof;
+}
+
+MYSQL_FIELD *mysql_fetch_field_direct(MYSQL_RES *res,uint fieldnr)
+{
+ return &(res)->fields[fieldnr];
+}
+
+MYSQL_FIELD *mysql_fetch_fields(MYSQL_RES *res)
+{
+ return (res)->fields;
+}
+
+MYSQL_ROWS *mysql_row_tell(MYSQL_RES *res)
+{
+ return res->data_cursor;
+}
+
+uint mysql_field_tell(MYSQL_RES *res)
+{
+ return (res)->current_field;
+}
+
+/* MYSQL */
+
+unsigned int mysql_field_count(MYSQL *mysql)
+{
+ return mysql->field_count;
+}
+
+my_ulonglong mysql_affected_rows(MYSQL *mysql)
+{
+ return (mysql)->affected_rows;
+}
+
+my_ulonglong mysql_insert_id(MYSQL *mysql)
+{
+ return (mysql)->insert_id;
+}
+
+uint mysql_errno(MYSQL *mysql)
+{
+ return (mysql)->net.last_errno;
+}
+
+char *mysql_error(MYSQL *mysql)
+{
+ return (mysql)->net.last_error;
+}
+
+char *mysql_info(MYSQL *mysql)
+{
+ return (mysql)->info;
+}
+
+ulong mysql_thread_id(MYSQL *mysql)
+{
+ return (mysql)->thread_id;
+}
+
+/****************************************************************************
+** 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)
+{
+ const char *to_start=to;
+ const char *end;
+ for (end=from+length; from != end ; from++)
+ {
+#ifdef USE_MB
+ int l;
+ if ((l = ismbchar(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(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;
+
+ 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 ((l = ismbchar(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(char *name)
+{
+ char *to;
+#ifdef USE_MB
+ char *end;
+ for (end=name; *end ; end++) ;
+#endif
+
+ for (to=name ; *name ; name++)
+ {
+#ifdef USE_MB
+ int l;
+ if( (l = ismbchar( name , end ) ) ) {
+ while (l--)
+ *to++ = *name++;
+ name--;
+ continue;
+ }
+#endif
+ if (*name == '\\' && name[1])
+ name++;
+ *to++= *name;
+ }
+ *to=0;
+}
diff --git a/client/Attic/net.c b/client/Attic/net.c
new file mode 100644
index 00000000000..4ea3f002bbc
--- /dev/null
+++ b/client/Attic/net.c
@@ -0,0 +1,628 @@
+/* Copyright Abandoned 1996 TCX DataKonsult AB & Monty Program KB & Detron HB
+ This file is public domain and comes with NO WARRANTY of any kind */
+
+/* Write and read of logical packets to/from socket
+** Writes are cached into net_buffer_length big packets.
+** Read packets are reallocated dynamicly when reading big packets.
+** Each logical packet has the following pre-info:
+** 3 byte length & 1 byte package-number.
+*/
+
+#ifdef _WIN32
+#include <winsock.h>
+#endif
+#include <global.h>
+#include <violite.h>
+#include <my_sys.h>
+#include <m_string.h>
+#include "mysql.h"
+#include <signal.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <violite.h>
+
+#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
+#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
+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))
+static 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 pthread_mutex_t LOCK_bytes_sent , LOCK_bytes_received;
+#else
+#undef thread_safe_add
+#define thread_safe_add(A,B,C)
+#endif
+
+/*
+** 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.
+*/
+
+#ifdef MYSQL_SERVER
+ulong max_allowed_packet=65536;
+extern uint test_flags;
+#else
+ulong max_allowed_packet=16*1024*1024L;
+#endif
+ulong net_buffer_length=8192; /* Default length. Enlarged if necessary */
+
+#define TEST_BLOCKING 8
+static int net_write_buff(NET *net,const char *packet,uint 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))))
+ return 1;
+ if (net_buffer_length > max_allowed_packet)
+ max_allowed_packet=net_buffer_length;
+ net->buff_end=net->buff+(net->max_packet=net_buffer_length);
+ net->vio = vio;
+ net->error=0; net->return_errno=0; net->return_status=0;
+ net->timeout=NET_READ_TIMEOUT; /* Timeout for read */
+ net->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;
+
+ if (vio != 0) /* If real connection */
+ {
+ net->fd = vio_fd(vio); /* For perl DBI/DBD */
+#if defined(MYSQL_SERVER) && !defined(___WIN__) && !defined(__EMX__)
+ if (!(test_flags & TEST_BLOCKING))
+ vio_blocking(vio, FALSE);
+#endif
+ vio_fastsend(vio,TRUE);
+ }
+ return 0;
+}
+
+void net_end(NET *net)
+{
+ my_free((gptr) net->buff,MYF(MY_ALLOW_ZERO_PTR));
+ net->buff=0;
+}
+
+/* Realloc the packet buffer */
+
+static my_bool net_realloc(NET *net, ulong length)
+{
+ uchar *buff;
+ ulong pkt_length;
+ if (length >= max_allowed_packet)
+ {
+ DBUG_PRINT("error",("Packet too large (%ld)", length));
+#ifdef MYSQL_SERVER
+ sql_print_error("Packet too large (%ld)\n", length);
+#else
+ fprintf(stderr,"Packet too large (%ld)\n", length);
+#endif
+ net->error=1;
+#ifdef MYSQL_SERVER
+ net->last_errno=ER_NET_PACKET_TOO_LARGE;
+#endif
+ return 1;
+ }
+ pkt_length = (length+IO_SIZE-1) & ~(IO_SIZE-1);
+ if (!(buff=(uchar*) my_realloc((char*) net->buff, pkt_length, MYF(MY_WME))))
+ {
+ net->error=1;
+#ifdef MYSQL_SERVER
+ net->last_errno=ER_OUT_OF_RESOURCES;
+#endif
+ return 1;
+ }
+ net->buff=net->write_pos=buff;
+ net->buff_end=buff+(net->max_packet=pkt_length);
+ return 0;
+}
+
+ /* Remove unwanted characters from connection */
+
+void net_clear(NET *net)
+{
+#ifndef EXTRA_DEBUG
+ int count;
+ 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)
+ 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->write_pos=net->buff;
+}
+
+ /* Flush write_buffer if not empty. */
+
+int net_flush(NET *net)
+{
+ int error=0;
+ DBUG_ENTER("net_flush");
+ if (net->buff != net->write_pos)
+ {
+ error=net_real_write(net,(char*) net->buff,
+ (uint) (net->write_pos - net->buff));
+ net->write_pos=net->buff;
+ }
+ DBUG_RETURN(error);
+}
+
+
+/*****************************************************************************
+** 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!
+*/
+
+int
+my_net_write(NET *net,const char *packet,ulong len)
+{
+ uchar buff[NET_HEADER_SIZE];
+ int3store(buff,len);
+ buff[3]= (net->compress) ? 0 : (uchar) (net->pkt_nr++);
+ if (net_write_buff(net,(char*) buff,NET_HEADER_SIZE))
+ return 1;
+ return net_write_buff(net,packet,len);
+}
+
+int
+net_write_command(NET *net,uchar command,const char *packet,ulong len)
+{
+ uchar buff[NET_HEADER_SIZE+1];
+ uint length=len+1; /* 1 extra byte for command */
+
+ 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));
+}
+
+
+static int
+net_write_buff(NET *net,const char *packet,uint len)
+{
+ uint left_length=(uint) (net->buff_end - net->write_pos);
+
+ while (len > left_length)
+ {
+ memcpy((char*) net->write_pos,packet,left_length);
+ if (net_real_write(net,(char*) net->buff,net->max_packet))
+ return 1;
+ net->write_pos=net->buff;
+ packet+=left_length;
+ len-=left_length;
+ left_length=net->max_packet;
+ }
+ memcpy((char*) net->write_pos,packet,len);
+ net->write_pos+=len;
+ return 0;
+}
+
+/* Read and write using timeouts */
+
+int
+net_real_write(NET *net,const char *packet,ulong len)
+{
+ int length;
+ char *pos,*end;
+ thr_alarm_t alarmed;
+#if (!defined(__WIN__) && !defined(__EMX__))
+ ALARM alarm_buff;
+#endif
+ uint retry_count=0;
+ my_bool net_blocking = vio_is_blocking(net->vio);
+ DBUG_ENTER("net_real_write");
+
+ if (net->error == 2)
+ DBUG_RETURN(-1); /* socket can't be used */
+
+ net->reading_or_writing=2;
+#ifdef HAVE_COMPRESS
+ if (net->compress)
+ {
+ 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))))
+ {
+#ifdef MYSQL_SERVER
+ net->last_errno=ER_OUT_OF_RESOURCES;
+ net->error=2;
+#endif
+ net->reading_or_writing=0;
+ DBUG_RETURN(1);
+ }
+ memcpy(b+header_length,packet,len);
+
+ if (my_compress((byte*) b+header_length,&len,&complen))
+ {
+ DBUG_PRINT("warning",
+ ("Compression error; Continuing without compression"));
+ complen=0;
+ }
+ int3store(&b[NET_HEADER_SIZE],complen);
+ int3store(b,len);
+ b[3]=(uchar) (net->pkt_nr++);
+ len+= header_length;
+ packet= (char*) b;
+ }
+#endif /* HAVE_COMPRESS */
+
+ /* DBUG_DUMP("net",packet,len); */
+#ifdef MYSQL_SERVER
+ thr_alarm_init(&alarmed);
+ if (net_blocking)
+ thr_alarm(&alarmed,NET_WRITE_TIMEOUT,&alarm_buff);
+#else
+ alarmed=0;
+#endif /* MYSQL_SERVER */
+
+ pos=(char*) packet; end=pos+len;
+ while (pos != end)
+ {
+ if ((int) (length=vio_write(net->vio,pos,(size_t) (end-pos))) <= 0)
+ {
+ my_bool interrupted = vio_should_retry(net->vio);
+#if (!defined(__WIN__) && !defined(__EMX__))
+ if ((interrupted || length==0) && !thr_alarm_in_use(alarmed))
+ {
+ if (!thr_alarm(&alarmed,NET_WRITE_TIMEOUT,&alarm_buff))
+ { /* Always true for client */
+ if (!vio_is_blocking(net->vio))
+ {
+ while (vio_blocking(net->vio, TRUE) < 0)
+ {
+ if (vio_should_retry(net->vio) && retry_count++ < RETRY_COUNT)
+ continue;
+#ifdef EXTRA_DEBUG
+ fprintf(stderr,
+ "%s: my_net_write: fcntl returned error %d, aborting thread\n",
+ my_progname,vio_errno(net->vio));
+#endif /* EXTRA_DEBUG */
+ net->error=2; /* Close socket */
+ goto end;
+ }
+ }
+ retry_count=0;
+ continue;
+ }
+ }
+ else
+#endif /* (!defined(__WIN__) && !defined(__EMX__)) */
+ if (thr_alarm_in_use(alarmed) && !thr_got_alarm(alarmed) &&
+ interrupted)
+ {
+ if (retry_count++ < RETRY_COUNT)
+ continue;
+#ifdef EXTRA_DEBUG
+ fprintf(stderr, "%s: write looped, aborting thread\n",
+ my_progname);
+#endif /* EXTRA_DEBUG */
+ }
+#if defined(THREAD_SAFE_CLIENT) && !defined(MYSQL_SERVER)
+ if (vio_errno(net->vio) == EINTR)
+ {
+ DBUG_PRINT("warning",("Interrupted write. Retrying..."));
+ continue;
+ }
+#endif /* defined(THREAD_SAFE_CLIENT) && !defined(MYSQL_SERVER) */
+ net->error=2; /* Close socket */
+#ifdef MYSQL_SERVER
+ net->last_errno= (interrupted ? ER_NET_WRITE_INTERRUPTED :
+ ER_NET_ERROR_ON_WRITE);
+#endif /* MYSQL_SERVER */
+ break;
+ }
+ pos+=length;
+ thread_safe_add(bytes_sent,length,&LOCK_bytes_sent);
+ }
+#ifndef __WIN__
+ end:
+#endif
+#ifdef HAVE_COMPRESS
+ if (net->compress)
+ my_free((char*) packet,MYF(0));
+#endif
+ if (thr_alarm_in_use(alarmed))
+ {
+ thr_end_alarm(&alarmed);
+ vio_blocking(net->vio, net_blocking);
+ }
+ net->reading_or_writing=0;
+ DBUG_RETURN(((int) (pos != end)));
+}
+
+
+/*****************************************************************************
+** Read something from server/clinet
+*****************************************************************************/
+
+
+static uint
+my_real_read(NET *net, ulong *complen)
+{
+ uchar *pos;
+ long length;
+ uint i,retry_count=0;
+ ulong len=packet_error;
+ thr_alarm_t alarmed;
+#if (!defined(__WIN__) && !defined(__EMX__)) || 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);
+ *complen = 0;
+
+ net->reading_or_writing=1;
+ thr_alarm_init(&alarmed);
+#ifdef MYSQL_SERVER
+ if (net_blocking)
+ thr_alarm(&alarmed,net->timeout,&alarm_buff);
+#endif /* MYSQL_SERVER */
+
+ pos = net->buff + net->where_b; /* net->packet -4 */
+ for (i=0 ; i < 2 ; i++)
+ {
+ while (remain > 0)
+ {
+ /* First read is done with non blocking mode */
+ if ((int) (length=vio_read(net->vio,(char*) pos,remain)) <= 0L)
+ {
+ my_bool interrupted = vio_should_retry(net->vio);
+
+ DBUG_PRINT("info",("vio_read returned %d, errno: %d",
+ length, vio_errno(net->vio)));
+#if (!defined(__WIN__) && !defined(__EMX__)) || defined(MYSQL_SERVER)
+ /*
+ We got an error that there was no data on the socket. We now set up
+ an alarm to not 'read forever', change the socket to non blocking
+ mode and try again
+ */
+ if ((interrupted || length == 0) && !thr_alarm_in_use(alarmed))
+ {
+ if (!thr_alarm(&alarmed,net->timeout,&alarm_buff)) /* Don't wait too long */
+ {
+ if (!vio_is_blocking(net->vio))
+ {
+ while (vio_blocking(net->vio,TRUE) < 0)
+ {
+ if (vio_should_retry(net->vio) &&
+ retry_count++ < RETRY_COUNT)
+ continue;
+ DBUG_PRINT("error",
+ ("fcntl returned error %d, aborting thread",
+ vio_errno(net->vio)));
+#ifdef EXTRA_DEBUG
+ fprintf(stderr,
+ "%s: read: fcntl returned error %d, aborting thread\n",
+ my_progname,vio_errno(net->vio));
+#endif /* EXTRA_DEBUG */
+ len= packet_error;
+ net->error=2; /* Close socket */
+#ifdef MYSQL_SERVER
+ net->last_errno=ER_NET_FCNTL_ERROR;
+#endif
+ goto end;
+ }
+ }
+ retry_count=0;
+ continue;
+ }
+ }
+#endif /* (!defined(__WIN__) && !defined(__EMX__)) || defined(MYSQL_SERVER) */
+ if (thr_alarm_in_use(alarmed) && !thr_got_alarm(alarmed) &&
+ interrupted)
+ { /* Probably in MIT threads */
+ if (retry_count++ < RETRY_COUNT)
+ continue;
+#ifdef EXTRA_DEBUG
+ fprintf(stderr, "%s: read looped with error %d, aborting thread\n",
+ my_progname,vio_errno(net->vio));
+#endif /* EXTRA_DEBUG */
+ }
+#if defined(THREAD_SAFE_CLIENT) && !defined(MYSQL_SERVER)
+ if (vio_should_retry(net->vio))
+ {
+ DBUG_PRINT("warning",("Interrupted read. Retrying..."));
+ continue;
+ }
+#endif
+ DBUG_PRINT("error",("Couldn't read packet: remain: %d errno: %d length: %d alarmed: %d", remain,vio_errno(net->vio),length,alarmed));
+ len= packet_error;
+ net->error=2; /* Close socket */
+#ifdef MYSQL_SERVER
+ net->last_errno= (interrupted ? ER_NET_READ_INTERRUPTED :
+ ER_NET_READ_ERROR);
+#endif
+ goto end;
+ }
+ remain -= (ulong) length;
+ pos+= (ulong) length;
+ thread_safe_add(bytes_received,(ulong) length,&LOCK_bytes_received);
+ }
+ if (i == 0)
+ { /* First parts is packet length */
+ ulong helping;
+ if (net->buff[net->where_b + 3] != (uchar) net->pkt_nr)
+ {
+ if (net->buff[net->where_b] != (uchar) 255)
+ {
+ DBUG_PRINT("error",
+ ("Packets out of order (Found: %d, expected %d)",
+ (int) net->buff[net->where_b + 3],
+ (uint) (uchar) net->pkt_nr));
+#ifdef EXTRA_DEBUG
+ fprintf(stderr,"Packets out of order (Found: %d, expected %d)\n",
+ (int) net->buff[net->where_b + 3],
+ (uint) (uchar) net->pkt_nr);
+#endif
+ }
+ len= packet_error;
+#ifdef MYSQL_SERVER
+ net->last_errno=ER_NET_PACKETS_OUT_OF_ORDER;
+#endif
+ goto end;
+ }
+ net->pkt_nr++;
+#ifdef HAVE_COMPRESS
+ if (net->compress)
+ {
+ /* complen is > 0 if package is really compressed */
+ *complen=uint3korr(&(net->buff[net->where_b + NET_HEADER_SIZE]));
+ }
+#endif
+
+ len=uint3korr(net->buff+net->where_b);
+ 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))
+ {
+ len= packet_error; /* Return error */
+ goto end;
+ }
+ }
+ pos=net->buff + net->where_b;
+ remain = len;
+ }
+ }
+
+end:
+ if (thr_alarm_in_use(alarmed))
+ {
+ thr_end_alarm(&alarmed);
+ vio_blocking(net->vio, net_blocking);
+ }
+ net->reading_or_writing=0;
+ return(len);
+}
+
+
+uint
+my_net_read(NET *net)
+{
+ ulong len,complen;
+
+#ifdef HAVE_COMPRESS
+ if (!net->compress)
+ {
+#endif
+ len = my_real_read (net,&complen);
+ 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 (;;)
+ {
+ if (net->remain_in_buf)
+ {
+ uchar *pos = net->buff + net->buf_length - net->remain_in_buf;
+ if (net->remain_in_buf >= 4)
+ {
+ net->length = uint3korr(pos);
+ if (net->length <= net->remain_in_buf - 4)
+ {
+ /* 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 */
+ }
+ }
+ /* Move data down to read next data packet after current one */
+ if (net->buf_length != net->remain_in_buf)
+ {
+ memmove(net->buff,pos,net->remain_in_buf);
+ net->buf_length=net->remain_in_buf;
+ }
+ 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 */
+#ifdef MYSQL_SERVER
+ net->last_errno=ER_NET_UNCOMPRESS_ERROR;
+#endif
+ break;
+ }
+ net->buf_length+=len;
+ net->remain_in_buf+=len;
+ }
+ if (len != packet_error)
+ {
+ net->save_char= net->read_pos[len]; /* Must be saved */
+ net->read_pos[len]=0; /* Safeguard for mysql_use_result */
+ }
+ return len;
+#endif
+}
diff --git a/client/Makefile.am b/client/Makefile.am
new file mode 100644
index 00000000000..e715a2c15d0
--- /dev/null
+++ b/client/Makefile.am
@@ -0,0 +1,43 @@
+# Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public 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 public domain and comes with NO WARRANTY of any kind
+
+INCLUDES = -I$(srcdir)/../include \
+ -I../include -I$(srcdir)/.. -I$(top_srcdir) \
+ -I..
+LIBS = @CLIENT_LIBS@
+LDADD = @CLIENT_EXTRA_LDFLAGS@ ../libmysql/libmysqlclient.la
+bin_PROGRAMS = mysql mysqladmin mysqlshow mysqldump mysqlimport
+noinst_PROGRAMS = insert_test select_test thread_test mysql-test
+noinst_HEADERS = sql_string.h completion_hash.h my_readline.h
+mysql_SOURCES = mysql.cc readline.cc sql_string.cc completion_hash.cc
+mysql_LDADD = @readline_link@ @TERMCAP_LIB@ $(LDADD) $(CXXLDFLAGS)
+mysql_DEPENDENCIES= $(LIBRARIES) $(pkglib_LTLIBRARIES)
+mysqladmin_DEPENDENCIES= $(LIBRARIES) $(pkglib_LTLIBRARIES)
+mysqlshow_DEPENDENCIES= $(LIBRARIES) $(pkglib_LTLIBRARIES)
+mysqldump_DEPENDENCIES= $(LIBRARIES) $(pkglib_LTLIBRARIES)
+mysqlimport_DEPENDENCIES= $(LIBRARIES) $(pkglib_LTLIBRARIES)
+insert_test_DEPENDENCIES= $(LIBRARIES) $(pkglib_LTLIBRARIES)
+select_test_DEPENDENCIES= $(LIBRARIES) $(pkglib_LTLIBRARIES)
+mysql_test_SOURCES= mysql-test.c
+mysql_test_DEPENDENCIES= $(LIBRARIES) $(pkglib_LTLIBRARIES)
+
+# Fix for mit-threads
+DEFS = -DUNDEF_THREADS_HACK
+
+thread_test.o: thread_test.c
+ $(COMPILE) -c @MT_INCLUDES@ $(INCLUDES) $<
diff --git a/client/completion_hash.cc b/client/completion_hash.cc
new file mode 100644
index 00000000000..006427f0295
--- /dev/null
+++ b/client/completion_hash.cc
@@ -0,0 +1,249 @@
+/* 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 */
+
+/* Quick & light hash implementation for tab completion purposes
+ *
+ * by Andi Gutmans <andi@zend.com>
+ * and Zeev Suraski <zeev@zend.com>
+ * Small portability changes by Monty. Changed also to use my_malloc/my_free
+ */
+
+#include <global.h>
+#include <m_string.h>
+#undef SAFEMALLOC // Speed things up
+#include <my_sys.h>
+#include "completion_hash.h"
+
+uint hashpjw(char *arKey, uint nKeyLength)
+{
+ uint h = 0, g, i;
+
+ for (i = 0; i < nKeyLength; i++) {
+ h = (h << 4) + arKey[i];
+ if ((g = (h & 0xF0000000))) {
+ h = h ^ (g >> 24);
+ h = h ^ g;
+ }
+ }
+ return h;
+}
+
+int completion_hash_init(HashTable *ht, uint nSize)
+{
+ ht->arBuckets = (Bucket **) my_malloc(nSize* sizeof(Bucket *),
+ MYF(MY_ZEROFILL | MY_WME));
+
+ if (!ht->arBuckets) {
+ ht->initialized = 0;
+ return FAILURE;
+ }
+ ht->pHashFunction = hashpjw;
+ ht->nTableSize = nSize;
+ ht->initialized = 1;
+ return SUCCESS;
+}
+
+
+int completion_hash_update(HashTable *ht, char *arKey, uint nKeyLength,
+ char *str)
+{
+ uint h, nIndex;
+
+ Bucket *p;
+
+ h = ht->pHashFunction(arKey, nKeyLength);
+ nIndex = h % ht->nTableSize;
+
+ if (nKeyLength <= 0) {
+ return FAILURE;
+ }
+ p = ht->arBuckets[nIndex];
+ while (p)
+ {
+ if ((p->h == h) && (p->nKeyLength == nKeyLength)) {
+ if (!memcmp(p->arKey, arKey, nKeyLength)) {
+ entry *n;
+
+ n = (entry *) my_malloc(sizeof(entry),
+ MYF(MY_WME));
+ n->pNext = p->pData;
+ n->str = str;
+ p->pData = n;
+ p->count++;
+
+ return SUCCESS;
+ }
+ }
+ p = p->pNext;
+ }
+
+ p = (Bucket *) my_malloc(sizeof(Bucket),MYF(MY_WME));
+
+ if (!p) {
+ 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));
+ return FAILURE;
+ }
+ p->pData->str = str;
+ p->pData->pNext = 0;
+ p->count = 1;
+
+ p->pNext = ht->arBuckets[nIndex];
+ ht->arBuckets[nIndex] = p;
+
+ return SUCCESS;
+}
+
+static Bucket *completion_hash_find(HashTable *ht, char *arKey,
+ uint nKeyLength)
+{
+ uint h, nIndex;
+ Bucket *p;
+
+ h = ht->pHashFunction(arKey, nKeyLength);
+ nIndex = h % ht->nTableSize;
+
+ p = ht->arBuckets[nIndex];
+ while (p)
+ {
+ if ((p->h == h) && (p->nKeyLength == nKeyLength)) {
+ if (!memcmp(p->arKey, arKey, nKeyLength)) {
+ return p;
+ }
+ }
+ p = p->pNext;
+ }
+ return (Bucket*) 0;
+}
+
+
+int completion_hash_exists(HashTable *ht, char *arKey, uint nKeyLength)
+{
+ uint h, nIndex;
+ Bucket *p;
+
+ h = ht->pHashFunction(arKey, nKeyLength);
+ nIndex = h % ht->nTableSize;
+
+ p = ht->arBuckets[nIndex];
+ while (p)
+ {
+ if ((p->h == h) && (p->nKeyLength == nKeyLength))
+ {
+ if (!strcmp(p->arKey, arKey)) {
+ return 1;
+ }
+ }
+ p = p->pNext;
+ }
+ return 0;
+}
+
+Bucket *find_all_matches(HashTable *ht, char *str, uint length,
+ uint *res_length)
+{
+ Bucket *b;
+
+ b = completion_hash_find(ht,str,length);
+ if (!b) {
+ *res_length = 0;
+ return (Bucket*) 0;
+ } else {
+ *res_length = length;
+ return b;
+ }
+}
+
+Bucket *find_longest_match(HashTable *ht, char *str, uint length,
+ uint *res_length)
+{
+ Bucket *b,*return_b;
+ char *s;
+ uint count;
+ uint lm;
+
+ b = completion_hash_find(ht,str,length);
+ if (!b) {
+ *res_length = 0;
+ return (Bucket*) 0;
+ }
+
+ count = b->count;
+ lm = length;
+ s = b->pData->str;
+
+ return_b = b;
+ while (s[lm]!=0 && (b=completion_hash_find(ht,s,lm+1))) {
+ if (b->count<count) {
+ *res_length=lm;
+ return return_b;
+ }
+ return_b=b;
+ lm++;
+ }
+ *res_length=lm;
+ return return_b;
+}
+
+
+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));
+ }
+ }
+ bzero((char*) ht->arBuckets,ht->nTableSize*sizeof(Bucket *));
+}
+
+
+void completion_hash_free(HashTable *ht)
+{
+ completion_hash_clean(ht);
+ my_free((gptr) ht->arBuckets,MYF(0));
+}
+
+
+void add_word(HashTable *ht,char *str)
+{
+ int i;
+ int length= (int) strlen(str);
+
+ for (i=1; i<=length; i++) {
+ completion_hash_update(ht, str, i, str);
+ }
+}
diff --git a/client/completion_hash.h b/client/completion_hash.h
new file mode 100644
index 00000000000..583a42bbbe5
--- /dev/null
+++ b/client/completion_hash.h
@@ -0,0 +1,57 @@
+/* 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 */
+
+#ifndef _HASH_
+#define _HASH_
+
+#define SUCCESS 0
+#define FAILURE 1
+
+#include <sys/types.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;
+} Bucket;
+
+typedef struct hashtable {
+ uint nTableSize;
+ uint initialized;
+ uint(*pHashFunction) (char *arKey, uint nKeyLength);
+ Bucket **arBuckets;
+} HashTable;
+
+extern int completion_hash_init(HashTable *ht, uint nSize);
+extern int completion_hash_update(HashTable *ht, char *arKey, uint nKeyLength, char *str);
+extern int hash_exists(HashTable *ht, char *arKey);
+extern Bucket *find_all_matches(HashTable *ht, char *str, uint length, uint *res_length);
+extern Bucket *find_longest_match(HashTable *ht, char *str, uint length, uint *res_length);
+extern void add_word(HashTable *ht,char *str);
+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_ */
diff --git a/client/connect_test.c b/client/connect_test.c
new file mode 100644
index 00000000000..661d448fdb0
--- /dev/null
+++ b/client/connect_test.c
@@ -0,0 +1,66 @@
+/* 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 <stdio.h>
+#include <stdlib.h>
+#include "mysql.h"
+
+static void change_user(MYSQL *sock,const char *user, const char *password,
+ const char *db,my_bool warning)
+{
+ if (mysql_change_user(sock,user,password,db) != warning)
+ {
+ fprintf(stderr,"Couldn't change user to: user: '%s', password: '%s', db: '%s': Error: %s\n",
+ user, password ? password : "", db ? db : "",
+ mysql_error(sock));
+ }
+}
+
+
+int main(int argc, char **argv)
+{
+ MYSQL *sock;
+
+ if (!(sock=mysql_init(0)))
+ {
+ fprintf(stderr,"Couldn't initialize mysql struct\n");
+ exit(1);
+ }
+ mysql_options(sock,MYSQL_READ_DEFAULT_GROUP,"connect");
+ if (!mysql_real_connect(sock,NULL,NULL,NULL,NULL,0,NULL,0))
+ {
+ fprintf(stderr,"Couldn't connect to engine!\n%s\n",mysql_error(sock));
+ perror("");
+ exit(1);
+ }
+
+ if (mysql_select_db(sock,"test"))
+ {
+ fprintf(stderr,"Couldn't select database test: Error: %s\n",
+ mysql_error(sock));
+ }
+
+ change_user(sock,"test_user","test_user","test",0);
+ change_user(sock,"test",NULL,"test",0);
+ change_user(sock,"test_user",NULL,"test",1);
+ change_user(sock,"test_user",NULL,NULL,1);
+ change_user(sock,"test_user","test_user","mysql",1);
+
+ mysql_close(sock);
+ exit(0);
+ return 0;
+}
diff --git a/client/errmsg.c b/client/errmsg.c
new file mode 100644
index 00000000000..e269f77ee36
--- /dev/null
+++ b/client/errmsg.c
@@ -0,0 +1,93 @@
+/* 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 library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ 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 */
+
+/* Error messages for MySQL clients */
+/* error messages for the demon is in share/language/errmsg.sys */
+
+#include <global.h>
+#include <my_sys.h>
+#include "errmsg.h"
+
+#ifdef GERMAN
+const char *client_errors[]=
+{
+ "Unbekannter MySQL Fehler",
+ "Kann UNIX-Socket nicht anlegen (%d)",
+ "Keine Verbindung zu lokalem MySQL Server, socket: '%-.64s' (%d)",
+ "Keine Verbindung zu MySQL Server auf %-.64s (%d)",
+ "Kann TCP/IP-Socket nicht anlegen (%d)",
+ "Unbekannter MySQL Server Host (%-.64s) (%d)",
+ "MySQL Server nicht vorhanden",
+ "Protokolle ungleich. Server Version = % d Client Version = %d",
+ "MySQL client got out of memory",
+ "Wrong host info",
+ "Localhost via UNIX socket",
+ "%s via TCP/IP",
+ "Error in server handshake",
+ "Lost connection to MySQL server during query",
+ "Commands out of sync; You can't run this command now",
+ "Verbindung ueber Named Pipe; Host: %-.64s",
+ "Kann nicht auf Named Pipe warten. Host: %-.64s pipe: %-.32s (%lu)",
+ "Kann Named Pipe nicht oeffnen. Host: %-.64s pipe: %-.32s (%lu)",
+ "Kann den Status der Named Pipe nicht setzen. Host: %-.64s pipe: %-.32s (%lu)"
+};
+
+#else /* ENGLISH */
+const char *client_errors[]=
+{
+ "Unknown MySQL error",
+ "Can't create UNIX socket (%d)",
+ "Can't connect to local MySQL server through socket '%-.64s' (%d)",
+ "Can't connect to MySQL server on '%-.64s' (%d)",
+ "Can't create TCP/IP socket (%d)",
+ "Unknown MySQL Server Host '%-.64s' (%d)",
+ "MySQL server has gone away",
+ "Protocol mismatch. Server Version = %d Client Version = %d",
+ "MySQL client run out of memory",
+ "Wrong host info",
+ "Localhost via UNIX socket",
+ "%s via TCP/IP",
+ "Error in server handshake",
+ "Lost connection to MySQL server during query",
+ "Commands out of sync; You can't run this command now",
+ "%s via named pipe",
+ "Can't wait for named pipe to host: %-.64s pipe: %-.32s (%lu)",
+ "Can't open named pipe to host: %-.64s pipe: %-.32s (%lu)",
+ "Can't set state of named pipe to host: %-.64s pipe: %-.32s (%lu)",
+};
+#endif
+
+
+void init_client_errs(void)
+{
+ errmsg[CLIENT_ERRMAP] = &client_errors[0];
+}
diff --git a/client/get_password.c b/client/get_password.c
new file mode 100644
index 00000000000..25069a14b75
--- /dev/null
+++ b/client/get_password.c
@@ -0,0 +1,214 @@
+/* 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 */
+
+/*
+** Ask for a password from tty
+** This is an own file to avoid conflicts with curses
+*/
+#include <global.h>
+#include <my_sys.h>
+#include "mysql.h"
+#include <m_string.h>
+#include <m_ctype.h>
+#include <dbug.h>
+
+#if defined(HAVE_BROKEN_GETPASS) && !defined(HAVE_GETPASSPHRASE)
+#undef HAVE_GETPASS
+#endif
+
+#ifdef HAVE_GETPASS
+#ifdef HAVE_PWD_H
+#include <pwd.h>
+#endif /* HAVE_PWD_H */
+#else /* ! HAVE_GETPASS */
+#ifndef __WIN__
+#include <sys/ioctl.h>
+#ifdef HAVE_TERMIOS_H /* For tty-password */
+#include <termios.h>
+#define TERMIO struct termios
+#else
+#ifdef HAVE_TERMIO_H /* For tty-password */
+#include <termio.h>
+#define TERMIO struct termio
+#else
+#include <sgtty.h>
+#define TERMIO struct sgttyb
+#endif
+#endif
+#ifdef alpha_linux_port
+#include <asm/ioctls.h> /* QQ; Fix this in configure */
+#include <asm/termiobits.h>
+#endif
+#else
+#include <conio.h>
+#endif /* __WIN__ */
+#endif /* HAVE_GETPASS */
+
+#ifdef HAVE_GETPASSPHRASE /* For Solaris */
+#define getpass(A) getpassphrase(A)
+#endif
+
+#ifdef __WIN__
+/* were just going to fake it here and get input from
+ the keyboard */
+
+char *get_tty_password(char *opt_message)
+{
+ char to[80];
+ char *pos=to,*end=to+sizeof(to)-1;
+ int i=0;
+ DBUG_ENTER("get_tty_password");
+ fprintf(stdout,opt_message ? opt_message : "Enter password: ");
+ for (;;)
+ {
+ char tmp;
+ tmp=_getch();
+ if (tmp == '\b' || (int) tmp == 127)
+ {
+ if (pos != to)
+ {
+ _cputs("\b \b");
+ pos--;
+ continue;
+ }
+ }
+ if (tmp == '\n' || tmp == '\r' || tmp == 3)
+ break;
+ if (iscntrl(tmp) || pos == end)
+ continue;
+ _cputs("*");
+ *(pos++) = tmp;
+ }
+ while (pos != to && isspace(pos[-1]) == ' ')
+ pos--; /* Allow dummy space at end */
+ *pos=0;
+ _cputs("\n");
+ DBUG_RETURN(my_strdup(to,MYF(MY_FAE)));
+}
+
+#else
+
+
+#ifndef HAVE_GETPASS
+/*
+** Can't use fgets, because readline will get confused
+** length is max number of chars in to, not counting \0
+* to will not include the eol characters.
+*/
+
+static void get_password(char *to,uint length,int fd,bool echo)
+{
+ char *pos=to,*end=to+length;
+
+ for (;;)
+ {
+ char tmp;
+ if (my_read(fd,&tmp,1,MYF(0)) != 1)
+ break;
+ if (tmp == '\b' || (int) tmp == 127)
+ {
+ if (pos != to)
+ {
+ if (echo)
+ {
+ fputs("\b \b",stdout);
+ fflush(stdout);
+ }
+ pos--;
+ continue;
+ }
+ }
+ if (tmp == '\n' || tmp == '\r' || tmp == 3)
+ break;
+ if (iscntrl(tmp) || pos == end)
+ continue;
+ if (echo)
+ {
+ fputc('*',stdout);
+ fflush(stdout);
+ }
+ *(pos++) = tmp;
+ }
+ while (pos != to && isspace(pos[-1]) == ' ')
+ pos--; /* Allow dummy space at end */
+ *pos=0;
+ return;
+}
+
+#endif /* ! HAVE_GETPASS */
+
+
+char *get_tty_password(char *opt_message)
+{
+#ifdef HAVE_GETPASS
+ char *passbuff;
+#else /* ! HAVE_GETPASS */
+ TERMIO org,tmp;
+#endif /* HAVE_GETPASS */
+ char buff[80];
+
+ DBUG_ENTER("get_tty_password");
+
+#ifdef HAVE_GETPASS
+ passbuff = getpass(opt_message ? opt_message : "Enter password: ");
+
+ /* copy the password to buff and clear original (static) buffer */
+ strnmov(buff, passbuff, sizeof(buff) - 1);
+#ifdef _PASSWORD_LEN
+ memset(passbuff, 0, _PASSWORD_LEN);
+#endif
+#else
+ if (isatty(fileno(stdout)))
+ {
+ fputs(opt_message ? opt_message : "Enter password: ",stdout);
+ fflush(stdout);
+ }
+#if defined(HAVE_TERMIOS_H)
+ tcgetattr(fileno(stdin), &org);
+ tmp = org;
+ tmp.c_lflag &= ~(ECHO | ISIG | ICANON);
+ 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)));
+ tcsetattr(fileno(stdin), TCSADRAIN, &org);
+#elif defined(HAVE_TERMIO_H)
+ ioctl(fileno(stdin), (int) TCGETA, &org);
+ tmp=org;
+ tmp.c_lflag &= ~(ECHO | ISIG | ICANON);
+ 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)));
+ ioctl(fileno(stdin),(int) TCSETA, &org);
+#else
+ gtty(fileno(stdin), &org);
+ tmp=org;
+ tmp.sg_flags &= ~ECHO;
+ tmp.sg_flags |= RAW;
+ stty(fileno(stdin), &tmp);
+ get_password(buff,sizeof(buff)-1,fileno(stdin),isatty(fileno(stdout)));
+ stty(fileno(stdin), &org);
+#endif
+ if (isatty(fileno(stdout)))
+ fputc('\n',stdout);
+#endif /* HAVE_GETPASS */
+
+ DBUG_RETURN(my_strdup(buff,MYF(MY_FAE)));
+}
+
+#endif /*__WIN__*/
diff --git a/client/insert_test.c b/client/insert_test.c
new file mode 100644
index 00000000000..640935d63b2
--- /dev/null
+++ b/client/insert_test.c
@@ -0,0 +1,65 @@
+/* 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 <stdio.h>
+#include <stdlib.h>
+#include "mysql.h"
+
+#define INSERT_QUERY "insert into test (name,num) values ('item %d', %d)"
+
+
+int main(int argc, char **argv)
+{
+ int count,num;
+ MYSQL *sock,mysql;
+ char qbuf[160];
+
+ if (argc != 3)
+ {
+ fprintf(stderr,"usage : insert_test <dbname> <Num>\n\n");
+ exit(1);
+ }
+
+ if (!(sock = mysql_connect(&mysql,NULL,0,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)
+ {
+ sprintf(qbuf,INSERT_QUERY,count,count);
+ if(mysql_query(sock,qbuf))
+ {
+ fprintf(stderr,"Query failed (%s)\n",mysql_error(sock));
+ exit(1);
+ }
+ count++;
+ }
+ mysql_close(sock);
+ exit(0);
+ return 0;
+}
diff --git a/client/list_test.c b/client/list_test.c
new file mode 100644
index 00000000000..718cc45e012
--- /dev/null
+++ b/client/list_test.c
@@ -0,0 +1,86 @@
+/* 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 library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ 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 */
+
+#ifdef __WIN__
+#include <windows.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include "mysql.h"
+
+#define SELECT_QUERY "select name from test where num = %d"
+
+
+int main(int argc, char **argv)
+{
+ int count, num;
+ MYSQL mysql,*sock;
+ MYSQL_RES *res;
+ char qbuf[160];
+
+ if (argc != 2)
+ {
+ fprintf(stderr,"usage : select_test <dbname>\n\n");
+ exit(1);
+ }
+
+ if (!(sock = mysql_connect(&mysql,NULL,0,0)))
+ {
+ fprintf(stderr,"Couldn't connect to engine!\n%s\n\n",mysql_error(&mysql));
+ perror("");
+ exit(1);
+ }
+
+ if (mysql_select_db(sock,argv[1]) < 0)
+ {
+ fprintf(stderr,"Couldn't select database %s!\n%s\n",argv[1],
+ mysql_error(sock));
+ exit(1);
+ }
+
+ if (!(res=mysql_list_dbs(sock,NULL)))
+ {
+ fprintf(stderr,"Couldn't list dbs!\n%s\n",mysql_error(sock));
+ exit(1);
+ }
+ mysql_free_result(res);
+ if (!(res=mysql_list_tables(sock,NULL)))
+ {
+ fprintf(stderr,"Couldn't list tables!\n%s\n",mysql_error(sock));
+ exit(1);
+ }
+ mysql_free_result(res);
+
+ mysql_close(sock);
+ exit(0);
+ return 0;
+}
diff --git a/client/my_readline.h b/client/my_readline.h
new file mode 100644
index 00000000000..c9a0e863870
--- /dev/null
+++ b/client/my_readline.h
@@ -0,0 +1,34 @@
+/* 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 */
+
+/* readline for batch mode */
+
+typedef struct st_line_buffer
+{
+ File file;
+ char *buffer; /* The buffer itself, grown as needed. */
+ char *end; /* Pointer at buffer end */
+ char *start_of_line,*end_of_line;
+ uint bufread; /* Number of bytes to get with each read(). */
+ uint eof;
+ ulong max_size;
+} LINE_BUFFER;
+
+extern LINE_BUFFER *batch_readline_init(ulong max_size,FILE *file);
+extern LINE_BUFFER *batch_readline_command(my_string str);
+extern char *batch_readline(LINE_BUFFER *buffer);
+extern void batch_readline_end(LINE_BUFFER *buffer);
diff --git a/client/mysql.cc b/client/mysql.cc
new file mode 100644
index 00000000000..2636b49cd83
--- /dev/null
+++ b/client/mysql.cc
@@ -0,0 +1,2060 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 command tool
+ * Commands compatible with mSQL by David J. Hughes
+ *
+ * Written by:
+ * Michael 'Monty' Widenius
+ * Andi Gutmans <andi@zend.com>
+ * Zeev Suraski <zeev@zend.com>
+ *
+ **/
+
+#include <global.h>
+#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__ // Skipp warnings in getopt.h
+#endif
+#include <getopt.h>
+#include "my_readline.h"
+#include <signal.h>
+
+gptr sql_alloc(unsigned size); // Don't use mysqld alloc for theese
+void sql_element_free(void *ptr);
+#include "sql_string.h"
+
+extern "C" {
+#if defined(HAVE_CURSES_H) && defined(HAVE_TERM_H)
+#include <curses.h>
+#include <term.h>
+#else
+#if defined(HAVE_TERMIOS_H)
+#include <termios.h>
+#include <unistd.h>
+#elif defined(HAVE_TERMBITS_H)
+#include <termbits.h>
+#elif defined(HAVE_ASM_TERMBITS_H) && (!defined __GLIBC__ || !(__GLIBC__ > 2 || __GLIBC__ == 2 && __GLIBC_MINOR__ > 0))
+#include <asm/termbits.h> // Standard linux
+#endif
+#undef VOID
+#if defined(HAVE_TERMCAP_H)
+#include <termcap.h>
+#else
+#ifdef HAVE_CURSES_H
+#include <curses.h>
+#endif
+#undef SYSV // hack to avoid syntax error
+#ifdef HAVE_TERM_H
+#include <term.h>
+#endif
+#endif
+#endif
+
+#undef bcmp // Fix problem with new readline
+#undef bzero
+#ifdef __WIN__
+#include <conio.h>
+#else
+#include <readline/readline.h>
+#define HAVE_READLINE
+#endif
+ //int vidattr(long unsigned int attrs); // Was missing in sun curses
+}
+
+#if !defined(HAVE_VIDATTR)
+#undef vidattr
+#define vidattr(A) {} // Can't get this to work
+#endif
+
+#ifdef __WIN__
+#define cmp_database(A,B) my_strcasecmp((A),(B))
+#else
+#define cmp_database(A,B) strcmp((A),(B))
+#endif
+
+#include "completion_hash.h"
+
+typedef struct st_status
+{
+ int exit_status;
+ ulong query_start_line;
+ char *file_name;
+ LINE_BUFFER *line_buff;
+ bool batch,add_to_history;
+} STATUS;
+
+
+static HashTable ht;
+
+enum enum_info_type { INFO_INFO,INFO_ERROR,INFO_RESULT};
+typedef enum enum_info_type INFO_TYPE;
+
+static MYSQL mysql; /* The connection */
+static bool info_flag=0,ignore_errors=0,wait_flag=0,quick=0,
+ connected=0,opt_raw_data=0,unbuffered=0,output_tables=0,
+ no_rehash=0,skip_updates=0,safe_updates=0,one_database=0,
+ opt_compress=0,
+ vertical=0,skip_line_numbers=0,skip_column_names=0,opt_html=0,
+ no_named_cmds=0;
+static uint verbose=0,opt_silent=0,opt_mysql_port=0;
+static my_string opt_mysql_unix_port=0;
+static int connect_flag=CLIENT_INTERACTIVE;
+static char *current_host,*current_db,*current_user=0,*opt_password=0,
+ *default_charset;
+static char *histfile;
+static String glob_buffer,old_buffer;
+static STATUS status;
+static ulong select_limit,max_join_size;
+
+#include "sslopt-vars.h"
+
+#ifndef DBUG_OFF
+const char *default_dbug_option="d:t:o,/tmp/mysql.trace";
+#endif
+
+/* The names of functions that actually do the manipulation. */
+static int get_options(int argc,char **argv);
+static int com_quit(String *str,char*),
+ com_go(String *str,char*), com_ego(String *str,char*),
+ com_edit(String *str,char*), com_print(String *str,char*),
+ com_help(String *str,char*), com_clear(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*);
+
+static int read_lines(bool execute_commands);
+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);
+
+/* A structure which contains information on the commands this program
+ can understand. */
+
+typedef struct {
+ const char *name; /* User printable name of the function. */
+ char cmd_char; /* msql command character */
+ int (*func)(String *str,char *); /* Function to call to do the job. */
+ bool takes_params; /* Max parameters for command */
+ const char *doc; /* Documentation for this function. */
+} COMMANDS;
+
+static COMMANDS commands[] = {
+ { "help", 'h',com_help, 0,"Display this text" },
+ { "?", 'h',com_help, 0,"Synonym for `help'" },
+ { "clear",'c',com_clear,0,"Clear command"},
+ { "connect",'r',com_connect,1,
+ "Reconnect to the server. Optional arguments are db and host" },
+ { "edit", 'e',com_edit, 0,"Edit command with $EDITOR"},
+ { "exit", 'q', com_quit, 0,"Exit mysql. Same as quit"},
+ { "go", 'g',com_go, 0,"Send command to mysql server" },
+ { "ego", 'G',com_ego, 0,
+ "Send command to mysql server; Display result vertically"},
+ { "print",'p',com_print,0,"Print current command" },
+ { "quit", 'q',com_quit, 0,"Quit mysql" },
+ { "rehash", '#', com_rehash, 0, "Rebuild completion hash" },
+ { "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"},
+ { "use",'u',com_use,1,
+ "Use another database. Takes database name as argument" },
+
+ { "create table",0,0,0,""}, /* Get bash expansion for some commmands */
+ { "create database",0,0,0,""},
+ { "drop",0,0,0,""},
+ { "select",0,0,0,""},
+ { "insert",0,0,0,""},
+ { "replace",0,0,0,""},
+ { "update",0,0,0,""},
+ { "delete",0,0,0,""},
+ { "explain",0,0,0,""},
+ { "show databases",0,0,0,""},
+ { "show fields from",0,0,0,""},
+ { "show keys from",0,0,0,""},
+ { "show tables",0,0,0,""},
+ { "load data from",0,0,0,""},
+ { "alter table",0,0,0,""},
+ { "set option",0,0,0,""},
+ { "lock tables",0,0,0,""},
+ { "unlock tables",0,0,0,""},
+ { (char *)NULL, 0,0,0,""},
+};
+
+static const char *load_default_groups[]= { "mysql","client",0 };
+
+#ifdef HAVE_READLINE
+extern "C" void add_history(char *command); /* From readline directory */
+extern "C" int read_history(char *command);
+extern "C" int write_history(char *command);
+static void initialize_readline (char *name);
+#endif
+
+static COMMANDS *find_command (char *name,char cmd_name);
+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_tab_data(MYSQL_RES *result);
+static void print_table_data_vertically(MYSQL_RES *result);
+static ulong start_timer(void);
+static void end_timer(ulong start_time,char *buff);
+static void mysql_end_timer(ulong start_time,char *buff);
+static void nice_time(double sec,char *buff,bool part_second);
+static sig_handler mysql_end(int sig);
+
+
+int main(int argc,char *argv[])
+{
+ char buff[80];
+
+ MY_INIT(argv[0]);
+ DBUG_ENTER("main");
+ DBUG_PROCESS(argv[0]);
+
+ if (!isatty(0) || !isatty(1))
+ {
+ status.batch=1; opt_silent=1;
+ ignore_errors=0;
+ }
+ else
+ status.add_to_history=1;
+ status.exit_status=1;
+ load_defaults("my",load_default_groups,&argc,&argv);
+ if (get_options(argc,(char **) argv))
+ {
+ my_end(0);
+ exit(1);
+ }
+ free_defaults(argv);
+ if (status.batch && !status.line_buff &&
+ !(status.line_buff=batch_readline_init(max_allowed_packet+512,stdin)))
+ exit(1);
+ glob_buffer.realloc(512);
+ completion_hash_init(&ht,50);
+ if (sql_connect(current_host,current_db,current_user,opt_password,
+ opt_silent))
+ {
+ if (connected)
+ mysql_close(&mysql);
+ glob_buffer.free();
+ old_buffer.free();
+ batch_readline_end(status.line_buff);
+ my_end(0);
+ exit(1);
+ }
+ if (!status.batch)
+ ignore_errors=1; // Don't abort monitor
+ signal(SIGINT, mysql_end); // Catch SIGINT to clean up
+
+ /*
+ ** Run in interactive mode like the ingres/postgres monitor
+ */
+
+ put_info("Welcome to the MySQL monitor. Commands end with ; or \\g.",
+ INFO_INFO);
+ sprintf((char*) glob_buffer.ptr(),
+ "Your MySQL connection id is %ld to server version: %s\n",
+ mysql_thread_id(&mysql),mysql_get_server_info(&mysql));
+ put_info((char*) glob_buffer.ptr(),INFO_INFO);
+
+#ifdef HAVE_READLINE
+ initialize_readline(my_progname);
+ if (!status.batch && !quick && !opt_html)
+ {
+ /*read-history from file, default ~/.mysql_history*/
+ if (getenv("MYSQL_HISTFILE"))
+ histfile=my_strdup(getenv("MYSQL_HISTFILE"),MYF(MY_WME));
+ else if (getenv("HOME"))
+ {
+ histfile=(char*) my_malloc(strlen(getenv("HOME"))
+ + strlen("/.mysql_history")+2,
+ MYF(MY_WME));
+ if (histfile)
+ sprintf(histfile,"%s/.mysql_history",getenv("HOME"));
+ }
+ if (histfile)
+ {
+ if (verbose)
+ printf("Reading history-file %s\n",histfile);
+ read_history(histfile);
+ }
+ }
+#endif
+ sprintf(buff, "Type '%s' for help.\n", no_named_cmds ? "\\h" : "help");
+ put_info(buff,INFO_INFO);
+ status.exit_status=read_lines(1); // read lines and execute them
+ mysql_end(0);
+#ifndef _lint
+ DBUG_RETURN(0); // Keep compiler happy
+#endif
+}
+
+sig_handler mysql_end(int sig)
+{
+ if (connected)
+ mysql_close(&mysql);
+#ifdef HAVE_READLINE
+ if (!status.batch && !quick && ! opt_html)
+ {
+ /* write-history */
+ if (verbose)
+ printf("Writing history-file %s\n",histfile);
+ write_history(histfile);
+ }
+ batch_readline_end(status.line_buff);
+ completion_hash_free(&ht);
+#endif
+ put_info(sig ? "Aborted" : "Bye", INFO_RESULT);
+ glob_buffer.free();
+ old_buffer.free();
+ my_free(opt_password,MYF(MY_ALLOW_ZERO_PTR));
+ my_free(opt_mysql_unix_port,MYF(MY_ALLOW_ZERO_PTR));
+ my_free(histfile,MYF(MY_ALLOW_ZERO_PTR));
+ my_free(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));
+ my_end(info_flag ? MY_CHECK_ERROR | MY_GIVE_INFO : 0);
+ exit(status.exit_status);
+}
+
+enum options {OPT_CHARSETS_DIR=256, OPT_DEFAULT_CHARSET} ;
+
+
+static struct option long_options[] =
+{
+ {"i-am-a-dummy", no_argument, 0, 'U'},
+ {"batch", no_argument, 0, 'B'},
+ {"character-sets-dir",required_argument,0, OPT_CHARSETS_DIR},
+ {"compress", no_argument, 0, 'C'},
+#ifndef DBUG_OFF
+ {"debug", optional_argument, 0, '#'},
+#endif
+ {"database", required_argument, 0, 'D'},
+ {"debug-info", no_argument, 0, 'T'},
+ {"default-character-set", required_argument, 0, OPT_DEFAULT_CHARSET},
+ {"execute", required_argument, 0, 'e'},
+ {"force", no_argument, 0, 'f'},
+ {"help", no_argument, 0, '?'},
+ {"html", no_argument, 0, 'H'},
+ {"host", required_argument, 0, 'h'},
+ {"ignore-spaces", no_argument, 0, 'i'},
+ {"no-auto-rehash",no_argument, 0, 'A'},
+ {"no-named-commands", no_argument, 0, 'g'},
+ {"one-database", no_argument, 0, 'o'},
+ {"password", optional_argument, 0, 'p'},
+#ifdef __WIN__
+ {"pipe", no_argument, 0, 'W'},
+#endif
+ {"port", required_argument, 0, 'P'},
+ {"quick", no_argument, 0, 'q'},
+ {"set-variable", required_argument, 0, 'O'},
+ {"raw", no_argument, 0, 'r'},
+ {"safe-updates", no_argument, 0, 'U'},
+ {"silent", no_argument, 0, 's'},
+ {"skip-column-names",no_argument, 0, 'N'},
+ {"skip-line-numbers",no_argument, 0, 'L'},
+ {"socket", required_argument, 0, 'S'},
+#include "sslopt-longopts.h"
+ {"table", no_argument, 0, 't'},
+#ifndef DONT_ALLOW_USER_CHANGE
+ {"user", required_argument, 0, 'u'},
+#endif
+ {"unbuffered", no_argument, 0, 'n'},
+ {"verbose", no_argument, 0, 'v'},
+ {"version", no_argument, 0, 'V'},
+ {"vertical", no_argument, 0, 'E'},
+ {"wait", no_argument, 0, 'w'},
+ {0, 0, 0, 0}
+};
+
+
+CHANGEABLE_VAR changeable_vars[] = {
+ { "max_allowed_packet", (long*) &max_allowed_packet,24*1024L*1024L,4096,
+ 24*1024L*1024L, MALLOC_OVERHEAD,1024},
+ { "net_buffer_length",(long*) &net_buffer_length,16384,1024,24*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},
+ { 0, 0, 0, 0, 0, 0, 0}
+};
+
+
+static void usage(int version)
+{
+ printf("%s Ver 10.8 Distrib %s, for %s (%s)\n",
+ my_progname, 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("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, --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\
+ Directory where character sets are\n\
+ -C, --compress Use compression in server/client protocol\n");
+#ifndef DBUG_OFF
+ printf("\
+ -#, --debug[=...] Debug log. Default is '%s'\n",default_dbug_option);
+#endif
+ printf("\
+ -D, --database=.. Database to use\n\
+ --default-character-set=...\n\
+ Set the default character set\n\
+ -e, --execute=... Execute command and quit.(Output like with --batch)\n\
+ -E, --vertical Print the output of a query (rows) vertically\n\
+ -f, --force Continue even if we get an sql error.\n\
+ -g, --no-named-commands\n\
+ Named commands are disabled. Use \\* form only\n\
+ -i, --ignore-space Ignore space after function names\n\
+ -h, --host=... Connect to host\n\
+ -H, --html Produce HTML output\n\
+ -L, --skip-line-numbers Don't write line number for errors\n\
+ -n, --unbuffered Flush buffer after each query\n\
+ -N, --skip-column-names Don't write column names in results\n\
+ -O, --set-variable var=option\n\
+ Give a variable an value. --help lists variables\n\
+ -o, --one-database Only update the default database. This is useful\n\
+ for skipping updates to other database in the update\n\
+ log.\n\
+ -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");
+#endif
+ printf("\n\
+ -P --port=... Port number to use for connection\n\
+ -q, --quick Don't cache result, print it row by row. This may\n\
+ slow down the server if the output is suspended.\n\
+ Doesn't use history file\n\
+ -r, --raw Write fields without conversion. Used with --batch\n\
+ -s, --silent Be more silent.\n\
+ -S --socket=... Socket file to use for connection\n");
+#include "sslopt-usage.h"
+ printf("\
+ -t --table Output in table format\n\
+ -T, --debug-info Print some debug info at exit\n");
+#ifndef DONT_ALLOW_USER_CHANGE
+ printf("\
+ -u, --user=# User for login if not current user\n");
+#endif
+ printf("\
+ -U, --safe-updates[=#], --i-am-a-dummy[=#]\n\
+ Only allow UPDATE and DELETE that uses keys\n\
+ -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");
+ for (uint i=0 ; changeable_vars[i].name ; i++)
+ printf("%-20s current value: %lu\n",
+ changeable_vars[i].name,
+ (ulong) *changeable_vars[i].varptr);
+}
+
+
+static int get_options(int argc, char **argv)
+{
+ int c,option_index=0;
+ bool tty_password=0;
+
+ set_all_changeable_vars(changeable_vars);
+ while ((c=getopt_long(argc,argv,"?ABCD:LfgHinNoqrstTUvVwWEe:h:O:P:S:u:#::p::",
+ long_options, &option_index)) != EOF)
+ {
+ switch(c) {
+ case OPT_DEFAULT_CHARSET:
+ default_charset= optarg;
+ break;
+ case OPT_CHARSETS_DIR:
+ charsets_dir= optarg;
+ break;
+ case 'D':
+ my_free(current_db,MYF(MY_ALLOW_ZERO_PTR));
+ current_db=my_strdup(optarg,MYF(MY_WME));
+ break;
+ case 'e':
+ status.batch=1;
+ status.add_to_history=0;
+ batch_readline_end(status.line_buff); // If multiple -e
+ if (!(status.line_buff=batch_readline_command(optarg)))
+ return 1;
+ ignore_errors=0;
+ break;
+ case 'f':
+ 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':
+ my_free(current_user,MYF(MY_ALLOW_ZERO_PTR));
+ current_user= my_strdup(optarg,MYF(MY_WME));
+ break;
+#endif
+ case 'U':
+ if (!optarg)
+ safe_updates=1;
+ else
+ safe_updates=atoi(optarg) != 0;
+ break;
+ case 'o':
+ one_database=skip_updates=1;
+ break;
+ case 'O':
+ if (set_changeable_var(optarg, changeable_vars))
+ {
+ usage(0);
+ return(1);
+ }
+ break;
+ case 'p':
+ if (optarg)
+ {
+ my_free(opt_password,MYF(MY_ALLOW_ZERO_PTR));
+ opt_password=my_strdup(optarg,MYF(MY_FAE));
+ while (*optarg) *optarg++= 'x'; // Destroy argument
+ }
+ 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 '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; break;
+ case 'A': no_rehash=1; break;
+ case 'g': no_named_cmds=1; break;
+ case 'H': opt_html=1; break;
+ case 'i': connect_flag|= CLIENT_IGNORE_SPACE; break;
+ case 'B':
+ if (!status.batch)
+ {
+ status.batch=1;
+ status.add_to_history=0;
+ opt_silent++; // more silent
+ }
+ break;
+ case 'C':
+ opt_compress=1;
+ 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;
+ case 'S':
+ my_free(opt_mysql_unix_port,MYF(MY_ALLOW_ZERO_PTR));
+ opt_mysql_unix_port= my_strdup(optarg,MYF(0));
+ break;
+ case 'W':
+#ifdef __WIN__
+ opt_mysql_unix_port=MYSQL_NAMEDPIPE;
+#endif
+ break;
+ case 'V': usage(1); exit(0);
+ case 'I':
+ case '?':
+ usage(0);
+ exit(0);
+#include "sslopt-case.h"
+ default:
+ fprintf(stderr,"illegal option: -%c\n",opterr);
+ usage(0);
+ exit(1);
+ }
+ }
+ if (default_charset)
+ {
+ if (set_default_charset_by_name(default_charset, MYF(MY_WME)))
+ exit(1);
+ }
+ argc-=optind;
+ argv+=optind;
+ if (argc > 1)
+ {
+ usage(0);
+ exit(1);
+ }
+ if (argc == 1)
+ {
+ my_free(current_db,MYF(MY_ALLOW_ZERO_PTR));
+ current_db= my_strdup(*argv,MYF(MY_WME));
+ }
+ if (!current_host)
+ { /* If we don't have a hostname have a look at MYSQL_HOST */
+ char *tmp=(char *) getenv("MYSQL_HOST");
+ if (tmp)
+ current_host = my_strdup(tmp,MYF(MY_WME));
+ }
+ if (tty_password)
+ opt_password=get_tty_password(NullS);
+ return(0);
+}
+
+
+static int read_lines(bool execute_commands)
+{
+#ifdef __WIN__
+ char linebuffer[254];
+#endif
+ char *line;
+ char in_string=0;
+ ulong line_number=0;
+ COMMANDS *com;
+ status.exit_status=1;
+
+ for (;;)
+ {
+ if (status.batch || !execute_commands)
+ {
+ line=batch_readline(status.line_buff);
+ line_number++;
+ if (!glob_buffer.length())
+ status.query_start_line=line_number;
+ }
+ else
+#ifdef __WIN__
+ {
+ printf(glob_buffer.is_empty() ? "mysql> " :
+ !in_string ? " -> " :
+ in_string == '\'' ?
+ " '> " : " \"> ");
+ linebuffer[0]=(char) sizeof(linebuffer);
+ line=_cgets(linebuffer);
+ }
+#else
+ line=readline((char*) (glob_buffer.is_empty() ? "mysql> " :
+ !in_string ? " -> " :
+ in_string == '\'' ?
+ " '> " : " \"> "));
+#endif
+ if (!line) // End of file
+ {
+ status.exit_status=0;
+ break;
+ }
+ if (!in_string && (line[0] == '#' ||
+ (line[0] == '-' && line[1] == '-') ||
+ line[0] == 0))
+ continue; // Skipp comment lines
+
+ /* Check if line is a mysql command line */
+ /* (We want to allow help, print and clear anywhere at line start */
+ if (execute_commands && !no_named_cmds && !in_string &&
+ (com=find_command(line,0)))
+ {
+ if ((*com->func)(&glob_buffer,line) > 0)
+ break;
+ if (glob_buffer.is_empty()) // If buffer was emptied
+ in_string=0;
+#ifdef HAVE_READLINE
+ if (status.add_to_history)
+ add_history(line);
+#endif
+ continue;
+ }
+ if (add_line(glob_buffer,line,&in_string))
+ break;
+ }
+ /* if in batch mode, send last query even if it doesn't end with \g or go */
+
+ if ((status.batch || !execute_commands) && !status.exit_status)
+ {
+ remove_cntrl(glob_buffer);
+ if (!glob_buffer.is_empty())
+ {
+ status.exit_status=1;
+ if (com_go(&glob_buffer,line) <= 0)
+ status.exit_status=0;
+ }
+ }
+ return status.exit_status;
+}
+
+
+static COMMANDS *find_command (char *name,char cmd_char)
+{
+ uint len;
+ char *end;
+
+ if (!name)
+ {
+ len=0;
+ end=0;
+ }
+ else
+ {
+ while (isspace(*name))
+ name++;
+ if (strchr(name,';') || strstr(name,"\\g"))
+ return ((COMMANDS *) 0);
+ if ((end=strcont(name," \t")))
+ {
+ len=(uint) (end - name);
+ while (isspace(*end))
+ end++;
+ if (!*end)
+ end=0; // no arguments to function
+ }
+ else
+ len=strlen(name);
+ }
+
+ for (uint i= 0; commands[i].name; i++)
+ {
+ if (commands[i].func &&
+ ((name && !my_casecmp(name,commands[i].name,len) &&
+ !commands[i].name[len] &&
+ (!end || (end && commands[i].takes_params))) ||
+ !name && commands[i].cmd_char == cmd_char))
+ return (&commands[i]);
+ }
+ return ((COMMANDS *) 0);
+}
+
+
+static bool add_line(String &buffer,char *line,char *in_string)
+{
+ uchar inchar;
+ char buff[80],*pos,*out;
+ COMMANDS *com;
+
+ if (!line[0] && buffer.is_empty())
+ return 0;
+#ifdef HAVE_READLINE
+ if (status.add_to_history && line[0])
+ add_history(line);
+#endif
+#ifdef USE_MB
+ char *strend=line+strlen(line);
+#endif
+
+ for (pos=out=line ; (inchar= (uchar) *pos) ; pos++)
+ {
+ if (isspace(inchar) && out == line && buffer.is_empty())
+ continue;
+#ifdef USE_MB
+ int l;
+/* if ((l = ismbchar(pos, pos+MBMAXLEN))) { Wei He: I think it's wrong! */
+ if (use_mb(default_charset_info) &&
+ (l = my_ismbchar(default_charset_info, pos, strend))) {
+ while (l--)
+ *out++ = *pos++;
+ pos--;
+ continue;
+ }
+#endif
+ if (inchar == '\\')
+ { // mSQL or postgreSQL style command ?
+ if (!(inchar = (uchar) *++pos))
+ break; // readline adds one '\'
+ if (*in_string || inchar == 'N')
+ { // Don't allow commands in string
+ *out++='\\';
+ *out++= (char) inchar;
+ continue;
+ }
+ if ((com=find_command(NullS,(char) inchar)))
+ {
+ const String tmp(line,(uint) (out-line));
+ buffer.append(tmp);
+ if ((*com->func)(&buffer,pos-1) > 0)
+ return 1; // Quit
+ if (com->takes_params)
+ {
+ for (pos++ ; *pos && *pos != ';' ; pos++) ; // Remove parameters
+ if (!*pos)
+ pos--;
+ }
+ out=line;
+ }
+ else
+ {
+ sprintf(buff,"Unknown command '\\%c'.",inchar);
+ if (put_info(buff,INFO_ERROR) > 0)
+ return 1;
+ *out++='\\';
+ *out++=(char) inchar;
+ continue;
+ }
+ }
+ else if (inchar == ';' && !*in_string)
+ { // ';' is end of command
+ if (out != line)
+ buffer.append(line,(uint) (out-line)); // Add this line
+ if ((com=find_command(buffer.c_ptr(),0)))
+ {
+ if ((*com->func)(&buffer,buffer.c_ptr()) > 0)
+ return 1; // Quit
+ }
+ else
+ {
+ int error=com_go(&buffer,0);
+ if (error)
+ {
+ return error < 0 ? 0 : 1; // < 0 is not fatal
+ }
+ }
+ buffer.length(0);
+ out=line;
+ }
+ else if (!*in_string && (inchar == '#' ||
+ inchar == '-' && pos[1] == '-' &&
+ isspace(pos[2])))
+ break; // comment to end of line
+ else
+ { // Add found char to buffer
+ if (inchar == *in_string)
+ *in_string=0;
+ else if (!*in_string && (inchar == '\'' || inchar == '"'))
+ *in_string=(char) inchar;
+ *out++ = (char) inchar;
+ }
+ }
+ if (out != line || !buffer.is_empty())
+ {
+ *out++='\n';
+ uint length=(uint) (out-line);
+ if (buffer.length() + length >= buffer.alloced_length())
+ buffer.realloc(buffer.length()+length+IO_SIZE);
+ if (buffer.append(line,length))
+ return 1;
+ }
+ return 0;
+}
+
+/* **************************************************************** */
+/* */
+/* Interface to Readline Completion */
+/* */
+/* **************************************************************** */
+
+#ifdef HAVE_READLINE
+
+static char *new_command_generator(char *text, int);
+static char **new_mysql_completion (char *text, int start, int end);
+
+/* Tell the GNU Readline library how to complete. We want to try to complete
+ on command names if this is the first word in the line, or on filenames
+ if not. */
+
+char **no_completion (char *text __attribute__ ((unused)),
+ char *word __attribute__ ((unused)))
+{
+ return 0; /* No filename completion */
+}
+
+static void initialize_readline (char *name)
+{
+ /* Allow conditional parsing of the ~/.inputrc file. */
+ rl_readline_name = name;
+
+ /* Tell the completer that we want a crack first. */
+ /* rl_attempted_completion_function = (CPPFunction *)mysql_completion;*/
+ rl_attempted_completion_function = (CPPFunction *) new_mysql_completion;
+ rl_completion_entry_function=(Function *) no_completion;
+}
+
+/* Attempt to complete on the contents of TEXT. START and END show the
+ region of TEXT that contains the word to complete. We can use the
+ entire line in case we want to do some simple parsing. Return the
+ array of matches, or NULL if there aren't any. */
+
+
+static char **new_mysql_completion (char *text,
+ int start __attribute__((unused)),
+ int end __attribute__((unused)))
+{
+ if (!status.batch && !quick)
+ return completion_matches(text, (CPFunction*) new_command_generator);
+ else
+ return (char**) 0;
+}
+
+static char *new_command_generator(char *text,int state)
+{
+ static int textlen;
+ char *ptr;
+ static Bucket *b;
+ static entry *e;
+ static uint i;
+
+ if (!state) {
+ textlen=strlen(text);
+ }
+
+ if (textlen>0) { /* lookup in the hash */
+ if (!state) {
+ uint len;
+
+ b = find_all_matches(&ht,text,strlen(text),&len);
+ if (!b) {
+ return NullS;
+ }
+ e = b->pData;
+ }
+
+ while (e) {
+ ptr= strdup(e->str);
+ e = e->pNext;
+ return ptr;
+ }
+ } else { /* traverse the entire hash, ugly but works */
+
+ if (!state) {
+ i=0;
+ /* find the first used bucket */
+ while (i<ht.nTableSize) {
+ if (ht.arBuckets[i]) {
+ b = ht.arBuckets[i];
+ e = b->pData;
+ break;
+ }
+ i++;
+ }
+ }
+ ptr= NullS;
+ while (e && !ptr) { /* find valid entry in bucket */
+ if (strlen(e->str)==b->nKeyLength) {
+ ptr = strdup(e->str);
+ }
+ /* find the next used entry */
+ e = e->pNext;
+ if (!e) { /* find the next used bucket */
+ b = b->pNext;
+ if (!b) {
+ i++;
+ while (i<ht.nTableSize) {
+ if (ht.arBuckets[i]) {
+ b = ht.arBuckets[i];
+ e = b->pData;
+ break;
+ }
+ i++;
+ }
+ } else {
+ e = b->pData;
+ }
+ }
+ }
+ if (ptr) {
+ return ptr;
+ }
+ }
+ return NullS;
+}
+
+
+/* Build up the completion hash */
+
+static void build_completion_hash(bool skip_rehash,bool write_info)
+{
+ COMMANDS *cmd=commands;
+ static MYSQL_RES *databases=0,*tables=0,*fields;
+ static char ***field_names= 0;
+ MYSQL_ROW database_row,table_row;
+ MYSQL_FIELD *sql_field;
+ char buf[NAME_LEN*2+2]; // table name plus field name plus 2
+ int i,j,num_fields;
+ DBUG_ENTER("build_completion_hash");
+
+ if (status.batch || quick)
+ 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) {
+ add_word(&ht,(char*) cmd->name);
+ cmd++;
+ }
+ if (skip_rehash)
+ DBUG_VOID_RETURN;
+
+ /* hash MySQL functions (to be implemented) */
+
+ /* hash all database names */
+ 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]);
+ }
+ }
+ /* hash all table names */
+ if (mysql_query(&mysql,"show tables")==0)
+ {
+ if (!(tables = mysql_store_result(&mysql)))
+ put_info(mysql_error(&mysql),INFO_INFO);
+ else
+ {
+ if (mysql_num_rows(tables) > 0 && !opt_silent && write_info)
+ {
+ printf("\
+Reading table information for completion of table and column names\n\
+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],
+ 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));
+ }
+ 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 */
+ 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)
+ DBUG_VOID_RETURN;
+ field_names[mysql_num_rows(tables)]='\0';
+ 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;
+ }
+ 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));
+ add_word(&ht,field_names[i][j]);
+ field_names[i][num_fields+j] = my_strdup(sql_field->name,MYF(0));
+ if (!completion_hash_exists(&ht,field_names[i][num_fields+j],
+ strlen(field_names[i][num_fields+j])))
+ add_word(&ht,field_names[i][num_fields+j]);
+ j++;
+ }
+ }
+ else
+ printf("Didn't find any fields in table '%s'\n",table_row[0]);
+ i++;
+ }
+ DBUG_VOID_RETURN;
+}
+
+
+ /* for gnu readline */
+
+#ifndef HAVE_INDEX
+#ifdef __cplusplus
+extern "C" {
+#endif
+extern char *index(const char *,pchar c),*rindex(const char *,pchar);
+
+char *index(const char *s,pchar c)
+{
+ for (;;)
+ {
+ if (*s == (char) c) return (char*) s;
+ if (!*s++) return NullS;
+ }
+}
+
+char *rindex(const char *s,pchar c)
+{
+ reg3 char *t;
+
+ t = NullS;
+ do if (*s == (char) c) t = (char*) s; while (*s++);
+ return (char*) t;
+}
+#ifdef __cplusplus
+}
+#endif
+#endif
+#endif /* HAVE_READLINE */
+
+static int reconnect(void)
+{
+ if (!status.batch)
+ {
+ put_info("No connection. Trying to reconnect...",INFO_INFO);
+ (void) com_connect((String *) 0, 0);
+ if(!no_rehash) com_rehash(NULL, NULL);
+ }
+ if (!connected)
+ return put_info("Can't connect to the server\n",INFO_ERROR);
+ return 0;
+}
+
+
+/***************************************************************************
+ The different commands
+***************************************************************************/
+
+static int
+com_help (String *buffer __attribute__((unused)),
+ char *line __attribute__((unused)))
+{
+ reg1 int i;
+
+ put_info("\nMySQL commands:",INFO_INFO);
+ for (i = 0; commands[i].name; i++)
+ {
+ if (commands[i].func)
+ printf("%s\t(\\%c)\t%s\n", commands[i].name,commands[i].cmd_char,
+ commands[i].doc);
+ }
+ if (connected)
+ printf("\nConnection id: %ld (Can be used with mysqladmin kill)\n\n",
+ mysql_thread_id(&mysql));
+ else
+ printf("Not connected! Reconnect with 'connect'!\n\n");
+ return 0;
+}
+
+
+ /* ARGSUSED */
+static int
+com_clear(String *buffer,char *line __attribute__((unused)))
+{
+ buffer->length(0);
+ return 0;
+}
+
+
+/*
+** Execute command
+** Returns: 0 if ok
+** -1 if not fatal error
+** 1 if fatal error
+*/
+
+
+static int
+com_go(String *buffer,char *line __attribute__((unused)))
+{
+ char buff[160],time_buff[32];
+ MYSQL_RES *result;
+ ulong timer;
+ uint error=0;
+
+ if (!status.batch)
+ {
+ old_buffer= *buffer; // Save for edit command
+ old_buffer.copy();
+ }
+
+ /* Remove garbage for nicer messages */
+ LINT_INIT(buff[0]);
+ remove_cntrl(*buffer);
+
+ if (buffer->is_empty())
+ {
+ if (status.batch) // Ignore empty quries
+ return 0;
+ return put_info("No query specified\n",INFO_ERROR);
+
+ }
+ if (!connected && reconnect())
+ {
+ buffer->length(0); // Remove query on error
+ return status.batch ? 1 : -1; // Fatal error
+ }
+ if (verbose)
+ (void) com_print(buffer,0);
+
+ if (skip_updates &&
+ (buffer->length() < 4 || my_sortcmp(buffer->ptr(),"SET ",4)))
+ {
+ (void) put_info("Ignoring query to other database",INFO_INFO);
+ return 0;
+ }
+
+ timer=start_timer();
+ for (uint retry=0;; retry++)
+ {
+ if (!mysql_real_query(&mysql,buffer->ptr(),buffer->length()))
+ break;
+ error=put_info(mysql_error(&mysql),INFO_ERROR, mysql_errno(&mysql));
+ if (mysql_errno(&mysql) != CR_SERVER_GONE_ERROR || retry > 1 || status.batch)
+ {
+ buffer->length(0); // Remove query on error
+ return error;
+ }
+ if (reconnect())
+ {
+ buffer->length(0); // Remove query on error
+ return error;
+ }
+ }
+ error=0;
+ buffer->length(0);
+
+ if (quick)
+ {
+ if (!(result=mysql_use_result(&mysql)) && mysql_field_count(&mysql))
+ {
+ return put_info(mysql_error(&mysql),INFO_ERROR,mysql_errno(&mysql));
+ }
+ }
+ else
+ {
+ if (!(result=mysql_store_result(&mysql)))
+ {
+ if (mysql_error(&mysql)[0])
+ {
+ return put_info(mysql_error(&mysql),INFO_ERROR,mysql_errno(&mysql));
+ }
+ }
+ }
+
+ if (verbose >= 3 || !opt_silent)
+ mysql_end_timer(timer,time_buff);
+ else
+ time_buff[0]=0;
+ if (result)
+ {
+ if (!mysql_num_rows(result) && ! quick)
+ {
+ sprintf(buff,"Empty set%s",time_buff);
+ }
+ else
+ {
+ if (opt_html)
+ print_table_data_html(result);
+ else if (vertical)
+ print_table_data_vertically(result);
+ else if (opt_silent && verbose <= 2 && !output_tables)
+ print_tab_data(result);
+ else
+ print_table_data(result);
+ sprintf(buff,"%ld %s in set%s",
+ (long) mysql_num_rows(result),
+ (long) mysql_num_rows(result) == 1 ? "row" : "rows",
+ time_buff);
+ }
+ }
+ else if (mysql_affected_rows(&mysql) == ~(ulonglong) 0)
+ sprintf(buff,"Query OK%s",time_buff);
+ else
+ sprintf(buff,"Query OK, %ld %s affected%s",
+ (long) mysql_affected_rows(&mysql),
+ (long) mysql_affected_rows(&mysql) == 1 ? "row" : "rows",
+ time_buff);
+ put_info(buff,INFO_RESULT);
+ if (mysql_info(&mysql))
+ put_info(mysql_info(&mysql),INFO_RESULT);
+ put_info("",INFO_RESULT); // Empty row
+
+ if (result && !mysql_eof(result)) /* Something wrong when using quick */
+ error=put_info(mysql_error(&mysql),INFO_ERROR,mysql_errno(&mysql));
+ else if (unbuffered)
+ fflush(stdout);
+ mysql_free_result(result);
+ return error; /* New command follows */
+}
+
+static int
+com_ego(String *buffer,char *line)
+{
+ int result;
+ bool oldvertical=vertical;
+ vertical=1;
+ result=com_go(buffer,line);
+ vertical=oldvertical;
+ return result;
+}
+
+
+static 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));
+ separator.copy("+",1);
+ while ((field = mysql_fetch_field(result)))
+ {
+ uint length=skip_column_names ? 0 : 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('+');
+ }
+ puts(separator.c_ptr());
+
+ if (!skip_column_names)
+ {
+ mysql_field_seek(result,0);
+ (void) fputs("|",stdout);
+ for (uint off=0; (field = mysql_fetch_field(result)) ; off++)
+ {
+ printf(" %-*s|",field->max_length,field->name);
+ num_flag[off]= IS_NUM(field->type);
+ }
+ (void) fputc('\n',stdout);
+ puts(separator.c_ptr());
+ }
+
+ while ((cur = mysql_fetch_row(result)))
+ {
+ (void) fputs("|",stdout);
+ mysql_field_seek(result,0);
+ for (uint off=0 ; off < mysql_num_fields(result); off++)
+ {
+ field = mysql_fetch_field(result);
+ uint length=field->max_length;
+ printf(num_flag[off] ? "%*s |" : " %-*s|",
+ length,cur[off] ? (char*) cur[off] : "NULL");
+ }
+ (void) fputc('\n',stdout);
+ }
+ puts(separator.c_ptr());
+ my_afree((gptr) num_flag);
+}
+
+static void
+print_table_data_html(MYSQL_RES *result)
+{
+ MYSQL_ROW cur;
+ MYSQL_FIELD *field;
+
+ mysql_field_seek(result,0);
+ printf("<TABLE BORDER=1>\n");
+ printf("<TR>\n");
+ if (!skip_column_names)
+ {
+ while((field = mysql_fetch_field(result)))
+ {
+ printf("<TH>%s</TH>",field->name ? (field->name[0] ? field->name:" &nbsp; "):"NULL");
+ }
+ puts("\n</TR>");
+ }
+ while ((cur = mysql_fetch_row(result)))
+ {
+ puts("<TR>");
+ for (uint i=0; i < mysql_num_fields(result); i++)
+ {
+ ulong *lengths=mysql_fetch_lengths(result);
+ fputs("<TD>",stdout);
+ safe_put_field(cur[i],lengths[i]);
+ fputs("</TD>",stdout);
+ }
+ puts("\n</TR>");
+ }
+ puts("</TABLE>");
+}
+
+
+
+static 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=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);
+ printf("*************************** %d. row ***************************\n",
+ row_count);
+ for (uint off=0; off < mysql_num_fields(result); off++)
+ {
+ field= mysql_fetch_field(result);
+ printf("%*s: ",(int) max_length,field->name);
+ printf("%s\n",cur[off] ? (char*) cur[off] : "NULL");
+ }
+ }
+}
+
+
+static void
+safe_put_field(const char *pos,ulong length)
+{
+ if (!pos)
+ fputs("NULL",stdout);
+ else
+ {
+ if (opt_raw_data)
+ fputs(pos,stdout);
+ else for (const char *end=pos+length ; pos != end ; pos++)
+ {
+#ifdef USE_MB
+ int l;
+ if (use_mb(default_charset_info) &&
+ (l = my_ismbchar(default_charset_info, pos, end))) {
+ while (l--)
+ putchar(*pos++);
+ pos--;
+ continue;
+ }
+#endif
+ if (!*pos)
+ fputs("\\0",stdout); // This makes everything hard
+ else if (*pos == '\t')
+ fputs("\\t",stdout); // This would destroy tab format
+ else if (*pos == '\n')
+ fputs("\\n",stdout); // This too
+ else if (*pos == '\\')
+ fputs("\\\\",stdout);
+ else
+ putchar(*pos);
+ }
+ }
+}
+
+
+static void
+print_tab_data(MYSQL_RES *result)
+{
+ MYSQL_ROW cur;
+ MYSQL_FIELD *field;
+ ulong *lengths;
+
+ if (opt_silent < 2 && !skip_column_names)
+ {
+ int first=0;
+ while ((field = mysql_fetch_field(result)))
+ {
+ if (first++)
+ (void) fputc('\t',stdout);
+ (void) fputs(field->name,stdout);
+ }
+ (void) fputc('\n',stdout);
+ }
+ while ((cur = mysql_fetch_row(result)))
+ {
+ lengths=mysql_fetch_lengths(result);
+ safe_put_field(cur[0],lengths[0]);
+ for (uint off=1 ; off < mysql_num_fields(result); off++)
+ {
+ (void) fputc('\t',stdout);
+ safe_put_field(cur[off],lengths[off]);
+ }
+ (void) fputc('\n',stdout);
+ }
+}
+
+
+static int
+com_edit(String *buffer,char *line __attribute__((unused)))
+{
+#ifdef __WIN__
+ put_info("Sorry, you can't send the result to an editor in Win32",
+ INFO_ERROR);
+#else
+ char *filename,buff[160];
+ int fd,tmp;
+ const char *editor;
+
+ filename = my_tempnam(NullS,"sql",MYF(MY_WME));
+ if ((fd = my_create(filename,0,O_CREAT | O_WRONLY, MYF(MY_WME))) < 0)
+ goto err;
+ if (buffer->is_empty() && !old_buffer.is_empty())
+ (void) my_write(fd,(byte*) old_buffer.ptr(),old_buffer.length(),
+ MYF(MY_WME));
+ else
+ (void) my_write(fd,(byte*) buffer->ptr(),buffer->length(),MYF(MY_WME));
+ (void) my_close(fd,MYF(0));
+
+ if (!(editor = (char *)getenv("EDITOR")) &&
+ !(editor = (char *)getenv("VISUAL")))
+ editor = "vi";
+ strxmov(buff,editor," ",filename,NullS);
+ (void) system(buff);
+
+ MY_STAT stat_arg;
+ if (!my_stat(filename,&stat_arg,MYF(MY_WME)))
+ goto err;
+ if ((fd = my_open(filename,O_RDONLY, MYF(MY_WME))) < 0)
+ goto err;
+ (void) buffer->alloc((uint) stat_arg.st_size);
+ if ((tmp=read(fd,(char*) buffer->ptr(),buffer->alloced_length())) >= 0L)
+ buffer->length((uint) tmp);
+ else
+ buffer->length(0);
+ (void) my_close(fd,MYF(0));
+ (void) my_delete(filename,MYF(MY_WME));
+err:
+ free(filename);
+#endif
+ return 0;
+}
+
+/* If arg is given, exit without errors. This happens on command 'quit' */
+
+static int
+com_quit(String *buffer __attribute__((unused)),
+ char *line __attribute__((unused)))
+{
+ status.exit_status=0;
+ return 1;
+}
+
+static int
+com_rehash(String *buffer __attribute__((unused)),
+ char *line __attribute__((unused)))
+{
+#ifdef HAVE_READLINE
+ build_completion_hash(0,0);
+#endif
+ return 0;
+}
+
+static int
+com_print(String *buffer,char *line __attribute__((unused)))
+{
+ puts("--------------");
+ (void) fputs(buffer->c_ptr(),stdout);
+ if (!buffer->length() || (*buffer)[buffer->length()-1] != '\n')
+ putchar('\n');
+ puts("--------------\n");
+ return 0; /* If empty buffer */
+}
+
+ /* ARGSUSED */
+static int
+com_connect(String *buffer, char *line)
+{
+ char *tmp,buff[256];
+ bool save_rehash=no_rehash;
+ int error;
+
+ if (buffer)
+ {
+ while (isspace(*line))
+ line++;
+ strnmov(buff,line,sizeof(buff)-1); // Don't destroy history
+ if (buff[0] == '\\') // Short command
+ buff[1]=' ';
+ tmp=(char *) strtok(buff," \t"); // Skipp connect command
+ if (tmp && (tmp=(char *) strtok(NullS," \t;")))
+ {
+ my_free(current_db,MYF(MY_ALLOW_ZERO_PTR));
+ current_db=my_strdup(tmp,MYF(MY_WME));
+ if ((tmp=(char *) strtok(NullS," \t;")))
+ {
+ my_free(current_host,MYF(MY_ALLOW_ZERO_PTR));
+ current_host=my_strdup(tmp,MYF(MY_WME));
+ }
+ }
+ else
+ no_rehash=1; // Quick re-connect
+ buffer->length(0); // command used
+ }
+ else
+ no_rehash=1;
+ error=sql_connect(current_host,current_db,current_user,opt_password,0);
+ no_rehash=save_rehash;
+
+ if (connected)
+ {
+ sprintf(buff,"Connection id: %ld",mysql_thread_id(&mysql));
+ put_info(buff,INFO_INFO);
+ sprintf(buff,"Current database: %s\n",
+ current_db ? current_db : "*** NO ONE ***");
+ put_info(buff,INFO_INFO);
+ }
+ return error;
+}
+
+
+static int com_source(String *buffer, char *line)
+{
+ char source_name[FN_REFLEN], *end, *param;
+ LINE_BUFFER *line_buff;
+ int error;
+ STATUS old_status;
+ FILE *sql_file;
+
+ /* Skip space from file name */
+ while (isspace(*line))
+ line++;
+ if (!(param = strchr(line, ' '))) // Skipp command name
+ return put_info("Usage: \\. <filename> | source <filename>", INFO_ERROR, 0);
+ while (isspace(*param))
+ param++;
+ end=strmake(source_name,param,sizeof(source_name)-1);
+ while (end > source_name && (isspace(end[-1]) || iscntrl(end[-1])))
+ end--;
+ end[0]=0;
+ /* open file name */
+ if (!(sql_file = my_fopen(source_name, O_RDONLY,MYF(0))))
+ {
+ char buff[FN_REFLEN+60];
+ sprintf(buff,"Failed to open file '%s', error: %d", source_name,errno);
+ return put_info(buff, INFO_ERROR, 0);
+ }
+
+ if (!(line_buff=batch_readline_init(max_allowed_packet+512,sql_file)))
+ {
+ my_fclose(sql_file,MYF(0));
+ return put_info("Can't initialize batch_readline", INFO_ERROR, 0);
+ }
+
+ /* Save old status */
+ old_status=status;
+ bfill((char*) &status,sizeof(status),(char) 0);
+
+ status.batch=old_status.batch; // Run in batch mode
+ status.line_buff=line_buff;
+ status.file_name=source_name;
+ glob_buffer.length(0); // Empty command buffer
+ error=read_lines(0); // Read lines from file
+ status=old_status; // Continue as before
+ my_fclose(sql_file,MYF(0));
+ batch_readline_end(line_buff);
+ return error;
+}
+
+
+ /* ARGSUSED */
+static int
+com_use(String *buffer __attribute__((unused)), char *line)
+{
+ char *tmp;
+ char buff[256];
+
+ while (isspace(*line))
+ line++;
+ strnmov(buff,line,sizeof(buff)-1); // Don't destroy history
+ if (buff[0] == '\\') // Short command
+ buff[1]=' ';
+ tmp=(char *) strtok(buff," \t;"); // Skipp connect command
+ if (!tmp || !(tmp=(char *) strtok(NullS," \t;")))
+ {
+ put_info("USE must be followed by a database name",INFO_ERROR);
+ return 0;
+ }
+ if (!current_db || cmp_database(current_db,tmp))
+ {
+ if (one_database)
+ skip_updates=1;
+ else
+ {
+ /*
+ reconnect once if connection is down or if connection was found to
+ be down during query
+ */
+ if (!connected && reconnect())
+ return status.batch ? 1 : -1; // Fatal error
+ if (mysql_select_db(&mysql,tmp))
+ {
+ if (mysql_errno(&mysql) != CR_SERVER_GONE_ERROR)
+ return put_info(mysql_error(&mysql),INFO_ERROR,mysql_errno(&mysql));
+
+ if (reconnect())
+ return status.batch ? 1 : -1; // Fatal error
+ if (mysql_select_db(&mysql,tmp))
+ return put_info(mysql_error(&mysql),INFO_ERROR,mysql_errno(&mysql));
+ }
+#ifdef HAVE_READLINE
+ build_completion_hash(no_rehash,1);
+#endif
+ my_free(current_db,MYF(MY_ALLOW_ZERO_PTR));
+ current_db=my_strdup(tmp,MYF(MY_WME));
+ }
+ }
+ else
+ skip_updates=0;
+ put_info("Database changed",INFO_INFO);
+ return 0;
+}
+
+
+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_init(&mysql);
+ if (opt_compress)
+ mysql_options(&mysql,MYSQL_OPT_COMPRESS,NullS);
+#ifdef HAVE_OPENSSL
+ if (opt_use_ssl)
+ mysql_ssl_set(&mysql, opt_ssl_key, opt_ssl_cert, opt_ssl_ca,
+ opt_ssl_capath);
+#endif
+ if (safe_updates)
+ {
+ char init_command[100];
+ sprintf(init_command,
+ "SET SQL_SAFE_UPDATES=1,SQL_SELECT_LIMIT=%lu,SQL_MAX_JOIN_SIZE=%lu",
+ select_limit,max_join_size);
+ mysql_options(&mysql, MYSQL_INIT_COMMAND, init_command);
+ }
+ if (!mysql_real_connect(&mysql,host,user,password,
+ database,opt_mysql_port,opt_mysql_unix_port,
+ connect_flag))
+ {
+ if (!silent ||
+ (mysql_errno(&mysql) != CR_CONN_HOST_ERROR &&
+ mysql_errno(&mysql) != CR_CONNECTION_ERROR))
+ {
+ put_info(mysql_error(&mysql),INFO_ERROR,mysql_errno(&mysql));
+ (void) fflush(stdout);
+ return ignore_errors ? -1 : 1; // Abort
+ }
+ return -1; // Retryable
+ }
+ connected=1;
+ mysql.reconnect=info_flag ? 1 : 0; // We want to know if this happens
+#ifdef HAVE_READLINE
+ build_completion_hash(no_rehash,1);
+#endif
+ return 0;
+}
+
+
+static int
+sql_connect(char *host,char *database,char *user,char *password,uint silent)
+{
+ bool message=0;
+ uint count=0;
+ int error;
+ for (;;)
+ {
+ if ((error=sql_real_connect(host,database,user,password,wait_flag)) >= 0)
+ {
+ if (count)
+ {
+ fputs("\n",stderr);
+ (void) fflush(stderr);
+ }
+ return error;
+ }
+ if (!wait_flag)
+ return ignore_errors ? -1 : 1;
+ if (!message && !silent)
+ {
+ message=1;
+ fputs("Waiting",stderr); (void) fflush(stderr);
+ }
+ (void) sleep(5);
+ if (!silent)
+ {
+ putc('.',stderr); (void) fflush(stderr);
+ count++;
+ }
+ }
+}
+
+
+
+static int
+com_status(String *buffer __attribute__((unused)),
+ char *line __attribute__((unused)))
+{
+ char *status;
+ puts("--------------");
+ usage(1); /* Print version */
+ if (connected)
+ {
+ MYSQL_RES *result;
+ LINT_INIT(result);
+ printf("\nConnection id:\t\t%ld\n",mysql_thread_id(&mysql));
+ if (!mysql_query(&mysql,"select DATABASE(),USER()") &&
+ (result=mysql_use_result(&mysql)))
+ {
+ MYSQL_ROW cur=mysql_fetch_row(result);
+ printf("Current database:\t%s\n",cur[0]);
+ printf("Current user:\t\t%s\n",cur[1]);
+ (void) mysql_fetch_row(result); // Read eof
+ }
+ }
+ else
+ {
+ vidattr(A_BOLD);
+ printf("\nNo connection\n");
+ vidattr(A_NORMAL);
+ return 0;
+ }
+ if (skip_updates)
+ {
+ vidattr(A_BOLD);
+ printf("\nAll updates ignored to this database\n");
+ vidattr(A_NORMAL);
+ }
+ printf("Server version\t\t%s\n", mysql_get_server_info(&mysql));
+ printf("Protocol version\t%d\n", mysql_get_proto_info(&mysql));
+ printf("Connection\t\t%s\n", mysql_get_host_info(&mysql));
+ printf("Language\t\t%s\n", mysql.charset->name);
+ if (strstr(mysql_get_host_info(&mysql),"TCP/IP") || ! mysql.unix_socket)
+ printf("TCP port\t\t%d\n", mysql.port);
+ else
+ printf("UNIX socket\t\t%s\n", mysql.unix_socket);
+ if ((status=mysql_stat(&mysql)) && !mysql_error(&mysql)[0])
+ {
+ char *pos,buff[40];
+ ulong sec;
+ pos=strchr(status,' ');
+ *pos++=0;
+ printf("%s\t\t\t",status); /* print label */
+ if ((status=str2int(pos,10,0,LONG_MAX,(long*) &sec)))
+ {
+ nice_time((double) sec,buff,0);
+ puts(buff); /* print nice time */
+ while (*status == ' ') status++; /* to next info */
+ }
+ if (status)
+ {
+ putchar('\n');
+ puts(status);
+ }
+ }
+ if (safe_updates)
+ {
+ vidattr(A_BOLD);
+ printf("\nNote that we are running in safe_update_mode:\n");
+ vidattr(A_NORMAL);
+ printf("\
+UPDATE and DELETE that doesn't use a key in the WHERE clause are not allowed\n\
+(One can force UPDATE/DELETE by adding LIMIT # at the end of the command)\n\
+SELECT has an automatic 'LIMIT %lu' if LIMIT is not used\n\
+Max number of examined row combination in a join is set to: %lu\n\n",
+select_limit,max_join_size);
+ }
+ puts("--------------\n");
+ return 0;
+}
+
+
+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)
+ {
+ (void) fflush(stdout);
+ fprintf(stderr,"ERROR");
+ if (error)
+ (void) fprintf(stderr," %d",error);
+ if (status.query_start_line && ! skip_line_numbers)
+ {
+ (void) fprintf(stderr," at line %lu",status.query_start_line);
+ if (status.file_name)
+ (void) fprintf(stderr," in file: '%s'", status.file_name);
+ }
+ (void) fprintf(stderr,": %s\n",str);
+ (void) fflush(stderr);
+ if (!ignore_errors)
+ return 1;
+ }
+ else if (info_type == INFO_RESULT && verbose > 1)
+ puts(str);
+ if (unbuffered)
+ fflush(stdout);
+ return info_type == INFO_ERROR ? -1 : 0;
+ }
+ if (!opt_silent || info_type == INFO_ERROR)
+ {
+ if (!inited)
+ {
+ inited=1;
+#ifdef HAVE_SETUPTERM
+ (void) setupterm((char *)0, 1, (int *) 0);
+#endif
+ }
+ if (info_type == INFO_ERROR)
+ {
+ putchar('\007'); /* This should make a bell */
+ vidattr(A_STANDOUT);
+ if (error)
+ (void) fprintf(stderr,"ERROR %d: ",error);
+ else
+ fputs("ERROR: ",stdout);
+ }
+ else
+ vidattr(A_BOLD);
+ (void) puts(str);
+ vidattr(A_NORMAL);
+ }
+ if (unbuffered)
+ fflush(stdout);
+ return info_type == INFO_ERROR ? -1 : 0;
+}
+
+static void remove_cntrl(String &buffer)
+{
+ char *start,*end;
+ end=(start=(char*) buffer.ptr())+buffer.length();
+ while (start < end && !isgraph(end[-1]))
+ end--;
+ buffer.length((uint) (end-start));
+}
+
+
+#ifdef __WIN__
+#include <time.h>
+#else
+#include <sys/times.h>
+#undef CLOCKS_PER_SEC
+#define CLOCKS_PER_SEC (sysconf(_SC_CLK_TCK))
+#endif
+
+static ulong start_timer(void)
+{
+#ifdef __WIN__
+ return clock();
+#else
+ struct tms tms_tmp;
+ return times(&tms_tmp);
+#endif
+}
+
+
+static void nice_time(double sec,char *buff,bool part_second)
+{
+ ulong tmp;
+ if (sec >= 3600.0*24)
+ {
+ tmp=(ulong) floor(sec/(3600.0*24));
+ sec-=3600.0*24*tmp;
+ buff=int2str((long) tmp,buff,10);
+ buff=strmov(buff,tmp > 1 ? " days " : " day ");
+ }
+ if (sec >= 3600.0)
+ {
+ tmp=(ulong) floor(sec/3600.0);
+ sec-=3600.0*tmp;
+ buff=int2str((long) tmp,buff,10);
+ buff=strmov(buff,tmp > 1 ? " hours " : " hour ");
+ }
+ if (sec >= 60.0)
+ {
+ tmp=(ulong) floor(sec/60.0);
+ sec-=60.0*tmp;
+ buff=int2str((long) tmp,buff,10);
+ buff=strmov(buff," min ");
+ }
+ if (part_second)
+ sprintf(buff,"%.2f sec",sec);
+ else
+ sprintf(buff,"%d sec",(int) sec);
+}
+
+
+static void end_timer(ulong start_time,char *buff)
+{
+ nice_time((double) (start_timer() - start_time) /
+ CLOCKS_PER_SEC,buff,1);
+}
+
+
+static void mysql_end_timer(ulong start_time,char *buff)
+{
+ buff[0]=' ';
+ buff[1]='(';
+ end_timer(start_time,buff+2);
+ strmov(strend(buff),")");
+}
+
+/* Keep sql_string library happy */
+
+gptr sql_alloc(unsigned int Size)
+{
+ return my_malloc(Size,MYF(MY_WME));
+}
+
+void sql_element_free(void *ptr)
+{
+ my_free((gptr) ptr,MYF(0));
+}
diff --git a/client/mysqladmin.c b/client/mysqladmin.c
new file mode 100644
index 00000000000..62c01fc1bfd
--- /dev/null
+++ b/client/mysqladmin.c
@@ -0,0 +1,1099 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* maintaince of mysql databases */
+
+
+#include <global.h>
+#include <my_sys.h>
+#include <m_string.h>
+#include <signal.h>
+#include "mysql.h"
+#include "errmsg.h"
+#include <getopt.h>
+#ifdef THREAD
+#include <my_pthread.h> /* because of signal() */
+#endif
+
+#define ADMIN_VERSION "8.8"
+#define MAX_MYSQL_VAR 64
+#define MAX_TIME_TO_WAIT 3600 /* Wait for shutdown */
+#define MAX_TRUNC_LENGTH 3
+
+char truncated_var_names[MAX_MYSQL_VAR][MAX_TRUNC_LENGTH];
+char ex_var_names[MAX_MYSQL_VAR][FN_REFLEN];
+ulonglong last_values[MAX_MYSQL_VAR];
+static int interval=0;
+static my_bool option_force=0,interrupted=0,new_line=0,option_silent=0,
+ opt_compress=0, opt_relative=0, opt_verbose=0, opt_vertical=0;
+static uint tcp_port = 0, option_wait = 0;
+static my_string unix_port=0;
+
+/* When using extended-status relatively, ex_val_max_len is the estimated
+ maximum length for any relative value printed by extended-status. The
+ idea is to try to keep the length of output as short as possible. */
+static uint ex_val_max_len[MAX_MYSQL_VAR];
+static my_bool ex_status_printed = 0; /* First output is not relative. */
+static uint ex_var_count, max_var_length, max_val_length;
+
+#include "sslopt-vars.h"
+
+static void print_version(void);
+static void usage(void);
+static my_bool sql_connect(MYSQL *mysql,const char *host, const char *user,
+ const char *password,uint wait);
+static my_bool execute_commands(MYSQL *mysql,int argc, char **argv);
+static int drop_db(MYSQL *mysql,const char *db);
+static sig_handler endprog(int signal_number);
+static void nice_time(ulong sec,char *buff);
+static void print_header(MYSQL_RES *result);
+static void print_top(MYSQL_RES *result);
+static void print_row(MYSQL_RES *result,MYSQL_ROW cur, uint row);
+static void print_relative_row(MYSQL_RES *result, MYSQL_ROW cur, uint row);
+static void print_relative_row_vert(MYSQL_RES *result, MYSQL_ROW cur, uint row);
+static void print_relative_header();
+static void print_relative_line();
+static void truncate_names();
+static my_bool get_pidfile(MYSQL *mysql, char *pidfile);
+static void wait_pidfile(char *pidfile);
+static void store_values(MYSQL_RES *result);
+
+/*
+ The order of commands must be the same as command_names,
+ except ADMIN_ERROR
+*/
+enum commands { ADMIN_ERROR, ADMIN_CREATE, ADMIN_DROP, ADMIN_SHUTDOWN,
+ ADMIN_RELOAD, ADMIN_REFRESH, ADMIN_VER, ADMIN_PROCESSLIST,
+ ADMIN_STATUS, ADMIN_KILL, ADMIN_DEBUG, ADMIN_VARIABLES,
+ ADMIN_FLUSH_LOGS, ADMIN_FLUSH_HOSTS, ADMIN_FLUSH_TABLES,
+ ADMIN_PASSWORD, ADMIN_PING, ADMIN_EXTENDED_STATUS,
+ ADMIN_FLUSH_STATUS, ADMIN_FLUSH_PRIVILEGES, ADMIN_START_SLAVE,
+ ADMIN_STOP_SLAVE, ADMIN_FLUSH_THREADS
+};
+static const char *command_names[]=
+{"create","drop","shutdown","reload","refresh",
+ "version", "processlist","status","kill","debug",
+ "variables","flush-logs","flush-hosts",
+ "flush-tables","password","ping",
+ "extended-status","flush-status",
+ "flush-privileges", "start-slave","stop-slave", "flush-threads", NullS};
+static TYPELIB command_typelib=
+{ array_elements(command_names)-1,"commands", command_names};
+
+enum options { OPT_CHARSETS_DIR=256 };
+
+static struct option long_options[] =
+{
+ {"compress", no_argument, 0, 'C'},
+ {"character-sets-dir",required_argument, 0, OPT_CHARSETS_DIR},
+ {"debug", optional_argument, 0, '#'},
+ {"force", no_argument, 0, 'f'},
+ {"help", no_argument, 0, '?'},
+ {"host", required_argument, 0, 'h'},
+ {"password", optional_argument, 0, 'p'},
+#ifdef __WIN__
+ {"pipe", no_argument, 0, 'W'},
+#endif
+ {"port", required_argument, 0, 'P'},
+ {"relative", no_argument, 0, 'r'},
+ {"silent", no_argument, 0, 's'},
+ {"socket", required_argument, 0, 'S'},
+ {"sleep", required_argument, 0, 'i'},
+#include "sslopt-longopts.h"
+ {"timeout", required_argument, 0, 't'},
+#ifndef DONT_ALLOW_USER_CHANGE
+ {"user", required_argument, 0, 'u'},
+#endif
+ {"verbose", no_argument, 0, 'v'},
+ {"version", no_argument, 0, 'V'},
+ {"vertical", no_argument, 0, 'E'},
+ {"wait", optional_argument, 0, 'w'},
+ {0, 0, 0, 0}
+};
+
+static const char *load_default_groups[]= { "mysqladmin","client",0 };
+
+int main(int argc,char *argv[])
+{
+ int c, error = 0,option_index=0;
+ MYSQL mysql;
+ char *host = NULL,*password=0,*user=0,**commands;
+ my_bool tty_password=0;
+ MY_INIT(argv[0]);
+ mysql_init(&mysql);
+ load_defaults("my",load_default_groups,&argc,&argv);
+
+ while ((c=getopt_long(argc,argv,"h:i:p::u:#::P:sS:Ct:fq?vVw::WrE",
+ long_options, &option_index)) != EOF)
+ {
+ switch(c) {
+ case 'C':
+ opt_compress=1;
+ break;
+ case 'h':
+ host = optarg;
+ break;
+ case 'q': /* Allow old 'q' option */
+ case 'f':
+ option_force++;
+ break;
+ case 'p':
+ if (optarg)
+ {
+ my_free(password,MYF(MY_ALLOW_ZERO_PTR));
+ password=my_strdup(optarg,MYF(MY_FAE));
+ while (*optarg) *optarg++= 'x'; /* Destroy argument */
+ }
+ else
+ tty_password=1;
+ break;
+#ifndef DONT_ALLOW_USER_CHANGE
+ case 'u':
+ user= my_strdup(optarg,MYF(0));
+ break;
+#endif
+ case 'i':
+ interval=atoi(optarg);
+ break;
+ case 'P':
+ tcp_port= (unsigned int) atoi(optarg);
+ break;
+ case 'r':
+ opt_relative = 1;
+ break;
+ case 'E':
+ opt_vertical = 1;
+ break;
+ case 's':
+ option_silent = 1;
+ break;
+ case 'S':
+ unix_port= optarg;
+ break;
+ case 'W':
+#ifdef __WIN__
+ unix_port=MYSQL_NAMEDPIPE;
+#endif
+ break;
+ case 't':
+ {
+ uint tmp=atoi(optarg);
+ mysql_options(&mysql,MYSQL_OPT_CONNECT_TIMEOUT, (char*) &tmp);
+ break;
+ }
+ case '#':
+ DBUG_PUSH(optarg ? optarg : "d:t:o,/tmp/mysqladmin.trace");
+ break;
+ case 'V':
+ print_version();
+ exit(0);
+ break;
+ case 'v':
+ opt_verbose=1;
+ break;
+ case 'w':
+ if (optarg)
+ {
+ if ((option_wait=atoi(optarg)) <= 0)
+ option_wait=1;
+ }
+ else
+ option_wait= ~0;
+ break;
+#include "sslopt-case.h"
+ default:
+ fprintf(stderr,"Illegal option character '%c'\n",opterr);
+ /* Fall throught */
+ case '?':
+ case 'I': /* Info */
+ error++;
+ break;
+ case OPT_CHARSETS_DIR:
+#if MYSQL_VERSION_ID > 32300
+ charsets_dir = optarg;
+#endif
+ break;
+ }
+ }
+ argc -= optind;
+ commands = argv + optind;
+ if (error || argc == 0)
+ {
+ usage();
+ exit(1);
+ }
+ if (tty_password)
+ password = get_tty_password(NullS);
+
+ VOID(signal(SIGINT,endprog)); /* Here if abort */
+ VOID(signal(SIGTERM,endprog)); /* Here if abort */
+
+ mysql_init(&mysql);
+ if (opt_compress)
+ mysql_options(&mysql,MYSQL_OPT_COMPRESS,NullS);
+#ifdef HAVE_OPENSSL
+ if (opt_use_ssl)
+ mysql_ssl_set(&mysql, opt_ssl_key, opt_ssl_cert, opt_ssl_ca,
+ opt_ssl_capath);
+#endif /* HAVE_OPENSSL */
+ if (sql_connect(&mysql,host,user,password,option_wait))
+ error = 1;
+ else
+ {
+ error = 0;
+ while (!interrupted)
+ {
+ new_line = 0;
+ if (execute_commands(&mysql,argc,commands) && !option_force)
+ {
+ if (option_wait && !interrupted)
+ {
+ mysql_close(&mysql);
+ if (!sql_connect(&mysql,host,user,password,option_wait))
+ continue; /* Retry */
+ }
+ error=1;
+ break;
+ }
+ if (interval)
+ {
+ sleep(interval);
+ if (new_line)
+ puts("");
+ }
+ else
+ break;
+ }
+ mysql_close(&mysql);
+ }
+ my_free(password,MYF(MY_ALLOW_ZERO_PTR));
+ my_free(user,MYF(MY_ALLOW_ZERO_PTR));
+ free_defaults(argv);
+ my_end(0);
+ exit(error);
+ return 0;
+}
+
+
+static sig_handler endprog(int signal_number __attribute__((unused)))
+{
+ interrupted=1;
+}
+
+
+static my_bool sql_connect(MYSQL *mysql,const char *host, const char *user,
+ const char *password,uint wait)
+{
+ my_bool info=0;
+
+ for (;;)
+ {
+ if (mysql_real_connect(mysql,host,user,password,NullS,tcp_port,unix_port,
+ 0))
+ {
+ if (info)
+ {
+ fputs("\n",stderr);
+ (void) fflush(stderr);
+ }
+ return 0;
+ }
+
+ if (!wait)
+ {
+ if (!option_silent)
+ {
+ if (!host)
+ host=LOCAL_HOST;
+ my_printf_error(0,"connect to server at '%s' failed\nerror: '%s'",
+ MYF(ME_BELL), host, mysql_error(mysql));
+ if (mysql_errno(mysql) == CR_CONNECTION_ERROR)
+ {
+ fprintf(stderr,
+ "Check that mysqld is running and that the socket: '%s' exists!\n",
+ unix_port ? unix_port : mysql_unix_port);
+ }
+ else if (mysql_errno(mysql) == CR_CONN_HOST_ERROR ||
+ mysql_errno(mysql) == CR_UNKNOWN_HOST)
+ {
+ fprintf(stderr,"Check that mysqld is running on %s",host);
+ fprintf(stderr," and that the port is %d.\n",
+ tcp_port ? tcp_port: mysql_port);
+ fprintf(stderr,"You can check this by doing 'telnet %s %d'\n",
+ host, tcp_port ? tcp_port: mysql_port);
+ }
+ }
+ return 1;
+ }
+ if (wait != (uint) ~0)
+ wait--; /* One less retry */
+ if ((mysql_errno(mysql) != CR_CONN_HOST_ERROR) &&
+ (mysql_errno(mysql) != CR_CONNECTION_ERROR))
+ {
+ fprintf(stderr,"Got error: %s\n", mysql_error(mysql));
+ if (!option_force)
+ return 1;
+ sleep(5);
+ }
+ else if (!info)
+ {
+ info=1;
+ fputs("Waiting for MySQL server to answer",stderr);
+ (void) fflush(stderr);
+ sleep(5);
+ }
+ else
+ {
+ putc('.',stderr);
+ (void) fflush(stderr);
+ sleep(5);
+ }
+ }
+}
+
+
+static my_bool execute_commands(MYSQL *mysql,int argc, char **argv)
+{
+ char *status;
+
+ for (; argc > 0 ; argv++,argc--)
+ {
+ switch (find_type(argv[0],&command_typelib,2)) {
+ case ADMIN_CREATE:
+ {
+ char buff[FN_REFLEN+20];
+ if (argc < 2)
+ {
+ my_printf_error(0,"Too few arguments to create",MYF(ME_BELL));
+ return 1;
+ }
+ sprintf(buff,"create database %.*s",FN_REFLEN,argv[1]);
+ if (mysql_query(mysql,buff))
+ return 1;
+ else
+ {
+ argc--; argv++;
+ }
+ break;
+ }
+ case ADMIN_DROP:
+ {
+ if (argc < 2)
+ {
+ my_printf_error(0,"Too few arguments to drop",MYF(ME_BELL));
+ return 1;
+ }
+ if (drop_db(mysql,argv[1]))
+ return 1;
+ else
+ {
+ argc--; argv++;
+ }
+ break;
+ }
+ case ADMIN_SHUTDOWN:
+ {
+ char pidfile[FN_REFLEN];
+ my_bool got_pidfile=0;
+ /* Only wait for pidfile on local connections */
+ /* If pidfile doesn't exist, continue without pid file checking */
+ if (mysql->unix_socket)
+ got_pidfile= !get_pidfile(mysql, pidfile);
+ if (mysql_shutdown(mysql))
+ {
+ my_printf_error(0,"shutdown failed; error: '%s'",MYF(ME_BELL),
+ mysql_error(mysql));
+ return 1;
+ }
+ mysql_close(mysql); /* Close connection to avoid error messages */
+ if (got_pidfile)
+ {
+ if (opt_verbose)
+ printf("Shutdown signal sent to server; Waiting for pid file to disappear\n");
+ wait_pidfile(pidfile); /* Wait until pid file is gone */
+ }
+ break;
+ }
+ case ADMIN_FLUSH_PRIVILEGES:
+ case ADMIN_RELOAD:
+ if (mysql_refresh(mysql,REFRESH_GRANT) < 0)
+ {
+ my_printf_error(0,"reload failed; error: '%s'",MYF(ME_BELL),
+ mysql_error(mysql));
+ return 1;
+ }
+ break;
+ case ADMIN_REFRESH:
+ if (mysql_refresh(mysql,
+ (uint) ~(REFRESH_GRANT | REFRESH_STATUS |
+ REFRESH_READ_LOCK)) < 0)
+ {
+ my_printf_error(0,"refresh failed; error: '%s'",MYF(ME_BELL),
+ mysql_error(mysql));
+ return 1;
+ }
+ break;
+ case ADMIN_FLUSH_THREADS:
+ if (mysql_refresh(mysql,(uint) REFRESH_THREADS) < 0)
+ {
+ my_printf_error(0,"refresh failed; error: '%s'",MYF(ME_BELL),
+ mysql_error(mysql));
+ return 1;
+ }
+ break;
+ case ADMIN_VER:
+ new_line=1;
+ print_version();
+ puts("TCX Datakonsult AB, by Monty\n");
+ printf("Server version\t\t%s\n", mysql_get_server_info(mysql));
+ printf("Protocol version\t%d\n", mysql_get_proto_info(mysql));
+ printf("Connection\t\t%s\n",mysql_get_host_info(mysql));
+ if (mysql->unix_socket)
+ printf("UNIX socket\t\t%s\n", mysql->unix_socket);
+ else
+ printf("TCP port\t\t%d\n", mysql->port);
+ status=mysql_stat(mysql);
+ {
+ char *pos,buff[40];
+ ulong sec;
+ pos=strchr(status,' ');
+ *pos++=0;
+ printf("%s\t\t\t",status); /* print label */
+ if ((status=str2int(pos,10,0,LONG_MAX,(long*) &sec)))
+ {
+ nice_time(sec,buff);
+ puts(buff); /* print nice time */
+ while (*status == ' ') status++; /* to next info */
+ }
+ }
+ putc('\n',stdout);
+ if (status)
+ puts(status);
+ break;
+ case ADMIN_PROCESSLIST:
+ {
+ MYSQL_RES *result;
+ MYSQL_ROW row;
+
+ if (mysql_query(mysql, (opt_verbose ? "show full processlist" :
+ "show processlist")) ||
+ !(result = mysql_store_result(mysql)))
+ {
+ my_printf_error(0,"process list failed; error: '%s'",MYF(ME_BELL),
+ mysql_error(mysql));
+ return 1;
+ }
+ print_header(result);
+ while ((row=mysql_fetch_row(result)))
+ print_row(result,row,0);
+ print_top(result);
+ mysql_free_result(result);
+ new_line=1;
+ break;
+ }
+ case ADMIN_STATUS:
+ status=mysql_stat(mysql);
+ if (status)
+ puts(status);
+ break;
+ case ADMIN_KILL:
+ {
+ uint error=0;
+ char *pos;
+ if (argc < 2)
+ {
+ my_printf_error(0,"Too few arguments to 'kill'",MYF(ME_BELL));
+ return 1;
+ }
+ pos=argv[1];
+ for (;;)
+ {
+ if (mysql_kill(mysql,(ulong) atol(pos)))
+ {
+ my_printf_error(0,"kill failed on %ld; error: '%s'",MYF(ME_BELL),
+ atol(pos), mysql_error(mysql));
+ error=1;
+ }
+ if (!(pos=strchr(pos,',')))
+ break;
+ pos++;
+ }
+ argc--; argv++;
+ if (error)
+ return error;
+ break;
+ }
+ case ADMIN_DEBUG:
+ if (mysql_dump_debug_info(mysql))
+ {
+ my_printf_error(0,"debug failed; error: '%s'",MYF(ME_BELL),
+ mysql_error(mysql));
+ return 1;
+ }
+ break;
+ case ADMIN_VARIABLES:
+ {
+ MYSQL_RES *res;
+ MYSQL_ROW row;
+
+ new_line=1;
+ if (mysql_query(mysql,"show variables") ||
+ !(res=mysql_store_result(mysql)))
+ {
+ my_printf_error(0,"unable to show variables; error: '%s'",MYF(ME_BELL),
+ mysql_error(mysql));
+ return 1;
+ }
+ print_header(res);
+ while ((row=mysql_fetch_row(res)))
+ print_row(res,row,0);
+ print_top(res);
+ mysql_free_result(res);
+ break;
+ }
+ case ADMIN_EXTENDED_STATUS:
+ {
+ MYSQL_RES *res;
+ MYSQL_ROW row;
+ uint rownr = 0;
+ void (*func) (MYSQL_RES*, MYSQL_ROW, uint);
+
+ new_line = 1;
+ if (mysql_query(mysql, "show status") ||
+ !(res = mysql_store_result(mysql)))
+ {
+ my_printf_error(0, "unable to show status; error: '%s'", MYF(ME_BELL),
+ mysql_error(mysql));
+ return 1;
+ }
+ if (!opt_vertical)
+ print_header(res);
+ else
+ {
+ if (!ex_status_printed)
+ {
+ store_values(res);
+ truncate_names(); /* Does some printing also */
+ }
+ else
+ {
+ print_relative_line();
+ print_relative_header();
+ print_relative_line();
+ }
+ }
+
+ /* void (*func) (MYSQL_RES*, MYSQL_ROW, uint); */
+ if (opt_relative && !opt_vertical)
+ func = print_relative_row;
+ else if (opt_vertical)
+ func = print_relative_row_vert;
+ else
+ func = print_row;
+
+ while ((row = mysql_fetch_row(res)))
+ (*func)(res, row, rownr++);
+ if (opt_vertical)
+ {
+ if (ex_status_printed)
+ {
+ putchar('\n');
+ print_relative_line();
+ }
+ }
+ else
+ print_top(res);
+
+ ex_status_printed = 1; /* From now on the output will be relative */
+ mysql_free_result(res);
+ break;
+ }
+ case ADMIN_FLUSH_LOGS:
+ {
+ if (mysql_refresh(mysql,REFRESH_LOG))
+ {
+ my_printf_error(0,"refresh failed; error: '%s'",MYF(ME_BELL),
+ mysql_error(mysql));
+ return 1;
+ }
+ break;
+ }
+ case ADMIN_FLUSH_HOSTS:
+ {
+ if (mysql_refresh(mysql,REFRESH_HOSTS))
+ {
+ my_printf_error(0,"refresh failed; error: '%s'",MYF(ME_BELL),
+ mysql_error(mysql));
+ return 1;
+ }
+ break;
+ }
+ case ADMIN_FLUSH_TABLES:
+ {
+ if (mysql_refresh(mysql,REFRESH_TABLES))
+ {
+ my_printf_error(0,"refresh failed; error: '%s'",MYF(ME_BELL),
+ mysql_error(mysql));
+ return 1;
+ }
+ break;
+ }
+ case ADMIN_FLUSH_STATUS:
+ {
+ if (mysql_refresh(mysql,REFRESH_STATUS))
+ {
+ my_printf_error(0,"refresh failed; error: '%s'",MYF(ME_BELL),
+ mysql_error(mysql));
+ return 1;
+ }
+ break;
+ }
+ case ADMIN_PASSWORD:
+ {
+ char buff[128],crypted_pw[33];
+
+ if(argc < 2)
+ {
+ my_printf_error(0,"Too few arguments to change password",MYF(ME_BELL));
+ return 1;
+ }
+ if (argv[1][0])
+ make_scrambled_password(crypted_pw,argv[1]);
+ else
+ crypted_pw[0]=0; /* No password */
+ sprintf(buff,"set password='%s',sql_log_off=0",crypted_pw);
+
+ if (mysql_query(mysql,"set sql_log_off=1"))
+ {
+ my_printf_error(0, "Can't turn off logging; error: '%s'",
+ MYF(ME_BELL),mysql_error(mysql));
+ return 1;
+ }
+ if (mysql_query(mysql,buff))
+ {
+ my_printf_error(0,"unable to change password; error: '%s'",
+ MYF(ME_BELL),mysql_error(mysql));
+ return 1;
+ }
+ argc--; argv++;
+ break;
+ }
+
+ case ADMIN_START_SLAVE:
+ if (mysql_query(mysql, "SLAVE START"))
+ {
+ my_printf_error(0, "Error starting slave: %s", MYF(ME_BELL),
+ mysql_error(mysql));
+ return 1;
+ }
+ else
+ puts("Slave started");
+ break;
+ case ADMIN_STOP_SLAVE:
+ if (mysql_query(mysql, "SLAVE STOP"))
+ {
+ my_printf_error(0, "Error stopping slave: %s", MYF(ME_BELL),
+ mysql_error(mysql));
+ return 1;
+ }
+ else
+ puts("Slave stopped");
+ break;
+
+ case ADMIN_PING:
+ mysql->reconnect=0; /* We want to know of reconnects */
+ if (!mysql_ping(mysql))
+ puts("mysqld is alive");
+ else
+ {
+ if (mysql_errno(mysql) == CR_SERVER_GONE_ERROR)
+ {
+ mysql->reconnect=1;
+ if (!mysql_ping(mysql))
+ puts("connection was down, but mysqld is now alive");
+ }
+ else
+ {
+ my_printf_error(0,"mysqld doesn't answer to ping, error: '%s'",
+ MYF(ME_BELL),mysql_error(mysql));
+ return 1;
+ }
+ }
+ mysql->reconnect=1; /* Automatic reconnect is default */
+ break;
+ default:
+ my_printf_error(0,"Unknown command: '%s'",MYF(ME_BELL),argv[0]);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+
+static void print_version(void)
+{
+ printf("%s Ver %s Distrib %s, for %s on %s\n",my_progname,ADMIN_VERSION,
+ MYSQL_SERVER_VERSION,SYSTEM_TYPE,MACHINE_TYPE);
+}
+
+
+static void usage(void)
+{
+ print_version();
+ 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");
+ puts("Administer program for the mysqld demon");
+ printf("Usage: %s [OPTIONS] command command....\n", my_progname);
+ printf("\n\
+ -#, --debug=... Output debug log. Often this is 'd:t:o,filename`\n\
+ -f, --force Don't ask for confirmation on drop database; with\n\
+ multiple commands, continue even if an error occurs\n\
+ -?, --help Display this help and exit\n\
+ --character-sets-dir=...\n\
+ Set the character set directory\n\
+ -C, --compress Use compression in server/client protocol\n\
+ -h, --host=# Connect to host\n\
+ -p, --password[=...] 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");
+#endif
+ printf("\
+ -P --port=... Port number to use for connection\n\
+ -i, --sleep=sec Execute commands again and again with a sleep between\n\
+ -r, --relative Show difference between current and previous values\n\
+ when used with -i. Currently works only with\n\
+ extended-status\n\
+ -E, --vertical Print output vertically. Is similar to --relative,\n\
+ but prints output vertically.\n\
+ -s, --silent Silently exit if one can't connect to server\n\
+ -S, --socket=... Socket file to use for connection\n");
+#include "sslopt-usage.h"
+ printf("\
+ -t, --timeout=... Timeout for connection to the mysqld server\n");
+#ifndef DONT_ALLOW_USER_CHANGE
+ printf("\
+ -u, --user=# User for login if not current user\n");
+#endif
+ printf("\
+ -v, --verbose Write more information\n\
+ -V, --version Output version information and exit\n\
+ -w, --wait[=retries] Wait and retry if connection is down\n");
+ print_defaults("my",load_default_groups);
+
+ puts("\nWhere command is a one or more of: (Commands may be shortened)\n\
+ create databasename Create a new database\n\
+ drop databasename Delete a database and all its tables\n\
+ extended-status Gives an extended status message from the server\n\
+ flush-hosts Flush all cached hosts\n\
+ flush-logs Flush all logs\n\
+ flush-status Clear status variables\n\
+ flush-tables Flush all tables\n\
+ flush-threads Flush the thread cache\n\
+ flush-privileges Reload grant tables (same as reload)\n\
+ kill id,id,... Kill mysql threads");
+#if MYSQL_VERSION_ID >= 32200
+ puts("\
+ password new-password Change old password to new-password");
+#endif
+ puts("\
+ ping Check if mysqld is alive\n\
+ processlist Show list of active threads in server\n\
+ reload Reload grant tables\n\
+ refresh Flush all tables and close and open logfiles\n\
+ shutdown Take server down\n\
+ status Gives a short status message from the server\n\
+ variables Prints variables available\n\
+ version Get version info from server");
+}
+
+static int drop_db(MYSQL *mysql, const char *db)
+{
+ char name_buff[FN_REFLEN+20], buf[10];
+ if (!option_force)
+ {
+ puts("Dropping the database is potentially a very bad thing to do.");
+ puts("Any data stored in the database will be destroyed.\n");
+ printf("Do you really want to drop the '%s' database [y/N]\n",db);
+ VOID(fgets(buf,sizeof(buf)-1,stdin));
+ if ((*buf != 'y') && (*buf != 'Y'))
+ {
+ puts("\nOK, aborting database drop!");
+ return -1;
+ }
+ }
+ sprintf(name_buff,"drop database %.*s",FN_REFLEN,db);
+ if (mysql_query(mysql,name_buff))
+ {
+ my_printf_error(0,"drop of '%s' failed;\nerror: '%s'",MYF(ME_BELL),
+ db,mysql_error(mysql));
+ return 1;
+ }
+ printf("Database \"%s\" dropped\n",db);
+ return 0;
+}
+
+
+static void nice_time(ulong sec,char *buff)
+{
+ ulong tmp;
+
+ if (sec >= 3600L*24)
+ {
+ tmp=sec/(3600L*24);
+ sec-=3600L*24*tmp;
+ buff=int2str(tmp,buff,10);
+ buff=strmov(buff,tmp > 1 ? " days " : " day ");
+ }
+ if (sec >= 3600L)
+ {
+ tmp=sec/3600L;
+ sec-=3600L*tmp;
+ buff=int2str(tmp,buff,10);
+ buff=strmov(buff,tmp > 1 ? " hours " : " hour ");
+ }
+ if (sec >= 60)
+ {
+ tmp=sec/60;
+ sec-=60*tmp;
+ buff=int2str(tmp,buff,10);
+ buff=strmov(buff," min ");
+ }
+ strmov(int2str(sec,buff,10)," sec");
+}
+
+
+static void print_header(MYSQL_RES *result)
+{
+ MYSQL_FIELD *field;
+
+ print_top(result);
+ mysql_field_seek(result,0);
+ putchar('|');
+ while ((field = mysql_fetch_field(result)))
+ {
+ printf(" %-*s|",field->max_length+1,field->name);
+ }
+ putchar('\n');
+ print_top(result);
+}
+
+
+static void print_top(MYSQL_RES *result)
+{
+ uint i,length;
+ MYSQL_FIELD *field;
+
+ putchar('+');
+ mysql_field_seek(result,0);
+ while((field = mysql_fetch_field(result)))
+ {
+ if ((length=strlen(field->name)) > field->max_length)
+ field->max_length=length;
+ else
+ length=field->max_length;
+ for (i=length+2 ; i--> 0 ; )
+ putchar('-');
+ putchar('+');
+ }
+ putchar('\n');
+}
+
+
+/* 3.rd argument, uint row, is not in use. Don't remove! */
+static void print_row(MYSQL_RES *result, MYSQL_ROW cur,
+ uint row __attribute__((unused)))
+{
+ uint i,length;
+ MYSQL_FIELD *field;
+
+ putchar('|');
+ mysql_field_seek(result,0);
+ for (i=0 ; i < mysql_num_fields(result); i++)
+ {
+ field = mysql_fetch_field(result);
+ length=field->max_length;
+ printf(" %-*s|",length+1,cur[i] ? (char*) cur[i] : "");
+ }
+ putchar('\n');
+}
+
+
+static void print_relative_row(MYSQL_RES *result, MYSQL_ROW cur, uint row)
+{
+ ulonglong tmp;
+ char buff[22];
+ MYSQL_FIELD *field;
+
+ mysql_field_seek(result, 0);
+ field = mysql_fetch_field(result);
+ printf("| %-*s|", 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,
+ llstr((tmp - last_values[row]), buff));
+ last_values[row] = tmp;
+}
+
+
+static void print_relative_row_vert(MYSQL_RES *result __attribute__((unused)),
+ MYSQL_ROW cur,
+ uint row __attribute__((unused)))
+{
+ uint length;
+ ulonglong tmp;
+ char buff[22];
+
+ if (!row)
+ putchar('|');
+
+ tmp = cur[1] ? strtoull(cur[1], NULL, 0) : (ulonglong) 0;
+ printf(" %-*s|", ex_val_max_len[row] + 1,
+ llstr((tmp - last_values[row]), buff));
+
+ /* Find the minimum row length needed to output the relative value */
+ if ((length=strlen(buff) > ex_val_max_len[row]) && ex_status_printed)
+ ex_val_max_len[row] = length;
+ last_values[row] = tmp;
+}
+
+
+static void store_values(MYSQL_RES *result)
+{
+ uint i;
+ MYSQL_ROW row;
+ MYSQL_FIELD *field;
+
+ field = mysql_fetch_field(result);
+ max_var_length = field->max_length;
+ field = mysql_fetch_field(result);
+ max_val_length = field->max_length;
+
+ for (i = 0; (row = mysql_fetch_row(result)); i++)
+ {
+ strmov(ex_var_names[i], row[0]);
+ last_values[i]=strtoull(row[1],NULL,10);
+ ex_val_max_len[i]=2; /* Default print width for values */
+ }
+ ex_var_count = i;
+ return;
+}
+
+
+static void print_relative_header()
+{
+ uint i;
+
+ putchar('|');
+ for (i = 0; i < ex_var_count; i++)
+ printf(" %-*s|", ex_val_max_len[i] + 1, truncated_var_names[i]);
+ putchar('\n');
+}
+
+
+static void print_relative_line()
+{
+ uint i;
+
+ putchar('+');
+ for (i = 0; i < ex_var_count; i++)
+ {
+ uint j;
+ for (j = 0; j < ex_val_max_len[i] + 2; j++)
+ putchar('-');
+ putchar('+');
+ }
+ putchar('\n');
+}
+
+
+static void truncate_names()
+{
+ uint i;
+ char *ptr,top_line[MAX_TRUNC_LENGTH+4+NAME_LEN+22+1],buff[22];
+
+ ptr=top_line;
+ *ptr++='+';
+ ptr=strfill(ptr,max_var_length+2,'-');
+ *ptr++='+';
+ ptr=strfill(ptr,MAX_TRUNC_LENGTH+2,'-');
+ *ptr++='+';
+ ptr=strfill(ptr,max_val_length+2,'-');
+ *ptr++='+';
+ *ptr=0;
+ puts(top_line);
+
+ for (i = 0 ; i < ex_var_count; i++)
+ {
+ uint sfx=1,j;
+ printf("| %-*s|", max_var_length + 1, ex_var_names[i]);
+ ptr = ex_var_names[i];
+ /* Make sure no two same truncated names will become */
+ for (j = 0; j < i; j++)
+ if (*truncated_var_names[j] == *ptr)
+ sfx++;
+
+ truncated_var_names[i][0]= *ptr; /* Copy first var char */
+ int10_to_str(sfx, truncated_var_names[i]+1,10);
+ printf(" %-*s|", MAX_TRUNC_LENGTH + 1, truncated_var_names[i]);
+ printf(" %-*s|\n", max_val_length + 1, llstr(last_values[i],buff));
+ }
+ puts(top_line);
+ return;
+}
+
+
+static my_bool get_pidfile(MYSQL *mysql, char *pidfile)
+{
+ MYSQL_RES* result;
+
+ if (mysql_query(mysql, "SHOW VARIABLES LIKE 'pid_file'"))
+ {
+ my_printf_error(0,"query failed; error: '%s'",MYF(ME_BELL),
+ mysql_error(mysql));
+ }
+ result = mysql_store_result(mysql);
+ if (result)
+ {
+ strmov(pidfile, mysql_fetch_row(result)[1]);
+ mysql_free_result(result);
+ return 0;
+ }
+ return 1; /* Error */
+}
+
+
+static void wait_pidfile(char *pidfile)
+{
+ char buff[FN_REFLEN];
+ int fd;
+ uint count=0;
+
+ system_filename(buff,pidfile);
+ while ((fd = open(buff, O_RDONLY)) >= 0 && count++ < MAX_TIME_TO_WAIT)
+ {
+ close(fd);
+ sleep(1);
+ }
+ if (fd >= 0)
+ {
+ close(fd);
+ fprintf(stderr,
+ "Warning; Aborted waiting on pid file: '%s' after %d seconds\n",
+ buff, count-1);
+ }
+}
diff --git a/client/mysqldump.c b/client/mysqldump.c
new file mode 100644
index 00000000000..ce687d815d8
--- /dev/null
+++ b/client/mysqldump.c
@@ -0,0 +1,1285 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* mysqldump.c - Dump a tables contents and format to an ASCII file
+**
+** The author's original notes follow :-
+**
+** ******************************************************
+** * *
+** * AUTHOR: Igor Romanenko (igor@frog.kiev.ua) *
+** * DATE: December 3, 1994 *
+** * WARRANTY: None, expressed, impressed, implied *
+** * or other *
+** * STATUS: Public domain *
+** * Adapted and optimized for MySQL by *
+** * Michael Widenius, Sinisa Milivojevic, Jani Tolonen *
+** * -w --where added 9/10/98 by Jim Faucette *
+** * slave code by David Saez Padros <david@ols.es> *
+** * *
+** ******************************************************
+*/
+/* SSL by
+** Andrei Errapart <andreie@no.spam.ee>
+** Tõnu Samuel <tonu@please.do.not.remove.this.spam.ee>
+**/
+
+#define DUMP_VERSION "8.8"
+
+#include <global.h>
+#include <my_sys.h>
+#include <m_string.h>
+#include <m_ctype.h>
+
+#include "mysql.h"
+#include "mysql_version.h"
+#include "mysqld_error.h"
+#include <getopt.h>
+
+/* Exit codes */
+
+#define EX_USAGE 1
+#define EX_MYSQLERR 2
+#define EX_CONSCHECK 3
+#define EX_EOM 4
+
+/* index into 'show fields from table' */
+
+#define SHOW_FIELDNAME 0
+#define SHOW_TYPE 1
+#define SHOW_NULL 2
+#define SHOW_DEFAULT 4
+#define SHOW_EXTRA 5
+#define QUOTE_CHAR '`'
+
+static char *add_load_option(char *ptr, const char *object,
+ const char *statement);
+
+static char *field_escape(char *to,const char *from,uint length);
+static my_bool verbose=0,tFlag=0,cFlag=0,dFlag=0,quick=0, extended_insert = 0,
+ lock_tables=0,ignore_errors=0,flush_logs=0,replace=0,
+ ignore=0,opt_drop=0,opt_keywords=0,opt_lock=0,opt_compress=0,
+ opt_delayed=0,create_options=0,opt_quoted=0,opt_databases=0,
+ opt_alldbs=0,opt_create_db=0,opt_first_slave=0;
+static MYSQL mysql_connection,*sock=0;
+static char insert_pat[12 * 1024],*password=0,*current_user=0,
+ *current_host=0,*path=0,*fields_terminated=0,
+ *lines_terminated=0, *enclosed=0, *opt_enclosed=0, *escaped=0,
+ *where=0, *default_charset;
+static uint opt_mysql_port=0;
+static my_string opt_mysql_unix_port=0;
+static int first_error=0;
+extern ulong net_buffer_length;
+static DYNAMIC_STRING extended_row;
+#include "sslopt-vars.h"
+
+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};
+
+static struct option long_options[] =
+{
+ {"all-databases", no_argument, 0, 'A'},
+ {"all", no_argument, 0, 'a'},
+ {"add-drop-table", no_argument, 0, OPT_DROP},
+ {"add-locks", no_argument, 0, OPT_LOCKS},
+ {"allow-keywords", no_argument, 0, OPT_KEYWORDS},
+ {"character-sets-dir",required_argument,0, OPT_CHARSETS_DIR},
+ {"complete-insert", no_argument, 0, 'c'},
+ {"compress", no_argument, 0, 'C'},
+ {"databases", no_argument, 0, 'B'},
+ {"debug", optional_argument, 0, '#'},
+ {"default-character-set", required_argument, 0, OPT_DEFAULT_CHARSET},
+ {"delayed-insert", no_argument, 0, OPT_DELAYED},
+ {"extended-insert", no_argument, 0, 'e'},
+ {"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},
+ {"first-slave", no_argument, 0, 'x'},
+ {"flush-logs", no_argument, 0, 'F'},
+ {"force", no_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-create-db", no_argument, 0, 'n'},
+ {"no-create-info", no_argument, 0, 't'},
+ {"no-data", no_argument, 0, 'd'},
+ {"opt", no_argument, 0, OPT_OPTIMIZE},
+ {"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"
+ {"tab", required_argument, 0, 'T'},
+ {"tables", no_argument, 0, OPT_TABLES},
+#ifndef DONT_ALLOW_USER_CHANGE
+ {"user", required_argument, 0, 'u'},
+#endif
+ {"verbose", no_argument, 0, 'v'},
+ {"version", no_argument, 0, 'V'},
+ {"where", required_argument, 0, 'w'},
+ {0, 0, 0, 0}
+};
+
+static const char *load_default_groups[]= { "mysqldump","client",0 };
+
+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}
+};
+
+static void safe_exit(int error);
+static void write_heder(FILE *sql_file, char *db_name);
+static void print_value(FILE *file, MYSQL_RES *result, MYSQL_ROW row,
+ const char *prefix,const char *name,
+ int string_value);
+static int dump_selected_tables(char *db, char **table_names, int tables);
+static int dump_all_tables_in_db(char *db);
+static int init_dumping(char *);
+static int dump_databases(char **);
+static int dump_all_databases();
+static char *quote_name(char *name, char *buff);
+
+static void print_version(void)
+{
+ printf("%s Ver %s Distrib %s, for %s (%s)\n",my_progname,DUMP_VERSION,
+ MYSQL_SERVER_VERSION,SYSTEM_TYPE,MACHINE_TYPE);
+} /* print_version */
+
+
+static void usage(void)
+{
+ uint i;
+ print_version();
+ puts("By Igor Romanenko, Monty, Jani & Sinisa");
+ 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] database [tables]\n", my_progname);
+ printf("OR %s [OPTIONS] --databases [OPTIONS] DB1 [DB2 DB3...]\n",
+ my_progname);
+ printf("OR %s [OPTIONS] --all-databases [OPTIONS]\n", my_progname);
+ printf("\n\
+ -A, --all-databases Dump all the databases. This will be same as\n\
+ --databases with all databases selected.\n\
+ -a, --all Include all MySQL specific create options.\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\
+ -B, --databases To dump several databases. Note the difference in\n\
+ usage; In this case no tables are given. All name\n\
+ arguments are regarded as databasenames.\n\
+ 'USE db_name;' will be included in the output\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-drop-table Add a 'drop table' before each create.\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, --flush-logs Flush logs file in server before starting dump.\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\
+ -n, --no-create-db 'CREATE DATABASE /*!32312 IF NOT EXISTS*/ db_name;'\n\
+ will not be put in the output. The above line will\n\
+ be added otherwise, if --databases or\n\
+ --all-databases option was given.\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\
+ --opt Same as --add-drop-table --add-locks --all\n\
+ --extended-insert --quick --lock-tables\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\
+ -Q, --quote-names Quote table and column names with `\n\
+ -S, --socket=... Socket file to use for connection.\n\
+ --tables Overrides option --databases (-B).\n");
+#include "sslopt-usage.h"
+ printf("\
+ -T, --tab=... Creates tab separated textfile for each table to\n\
+ given path. (creates .sql and .txt files).\n\
+ NOTE: This only works if mysqldump is run on\n\
+ the same machine as the mysqld daemon.\n");
+#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\
+ -w, --where= dump only selected records; QUOTES mandatory!\n\
+ EXAMPLES: \"--where=user=\'jimf\'\" \"-wuserid>1\" \"-wuserid<1\"\n\
+ Use -T (--tab=...) with --fields-...\n\
+ --fields-terminated-by=...\n\
+ Fields in the textfile are terminated by ...\n\
+ --fields-enclosed-by=...\n\
+ Fields in the importfile are enclosed by ...\n\
+ --fields-optionally-enclosed-by=...\n\
+ Fields in the i.file are opt. enclosed by ...\n\
+ --fields-escaped-by=...\n\
+ Fields in the i.file are escaped by ...\n\
+ --lines-terminated-by=...\n\
+ Lines in the i.file are terminated by ...\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 void write_heder(FILE *sql_file, char *db_name)
+{
+ fprintf(sql_file, "# MySQL dump %s\n#\n", DUMP_VERSION);
+ fprintf(sql_file, "# Host: %s Database: %s\n",
+ current_host ? current_host : "localhost", db_name ? db_name : "");
+ fputs("#--------------------------------------------------------\n",
+ sql_file);
+ fprintf(sql_file, "# Server version\t%s\n",
+ mysql_get_server_info(&mysql_connection));
+ return;
+} /* write_heder */
+
+
+static int get_options(int *argc,char ***argv)
+{
+ int c,option_index;
+ my_bool tty_password=0;
+
+ 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 'a':
+ create_options=1;
+ break;
+ case 'e':
+ extended_insert=1;
+ break;
+ case 'A':
+ opt_alldbs=1;
+ break;
+ case OPT_DEFAULT_CHARSET:
+ default_charset= optarg;
+ break;
+ case OPT_CHARSETS_DIR:
+ charsets_dir= optarg;
+ break;
+ case 'f':
+ ignore_errors=1;
+ break;
+ case 'F':
+ flush_logs=1;
+ break;
+ case 'h':
+ my_free(current_host,MYF(MY_ALLOW_ZERO_PTR));
+ current_host=my_strdup(optarg,MYF(MY_WME));
+ break;
+ case 'n':
+ opt_create_db = 1;
+ 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)
+ {
+ my_free(password,MYF(MY_ALLOW_ZERO_PTR));
+ password=my_strdup(optarg,MYF(MY_FAE));
+ while (*optarg) *optarg++= 'x'; /* Destroy 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 'B':
+ opt_databases = 1;
+ break;
+ case '#':
+ DBUG_PUSH(optarg ? optarg : "d:t:o");
+ break;
+ case 'c': cFlag=1; break;
+ case 'C':
+ opt_compress=1;
+ break;
+ case 'd': dFlag=1; break;
+ case 'l': lock_tables=1; break;
+ case 'q': quick=1; break;
+ case 'Q': opt_quoted=1; break;
+ case 't': tFlag=1; break;
+ case 'v': verbose=1; break;
+ case 'V': print_version(); exit(0);
+ case 'w':
+ where=optarg;
+ break;
+ case 'x':
+ opt_first_slave=1;
+ break;
+ 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_DROP:
+ opt_drop=1;
+ break;
+ case (int) OPT_KEYWORDS:
+ opt_keywords=1;
+ break;
+ case (int) OPT_LOCKS:
+ opt_lock=1;
+ break;
+ case (int) OPT_OPTIMIZE:
+ extended_insert=opt_drop=opt_lock=lock_tables=quick=create_options=1;
+ break;
+ case (int) OPT_DELAYED:
+ opt_delayed=1;
+ break;
+ case (int) OPT_TABLES:
+ opt_databases=0;
+ 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 (replace && ignore)
+ {
+ fprintf(stderr, "%s: You can't use --ignore (-i) and --replace (-r) at the same time.\n",my_progname);
+ return(1);
+ }
+ if ((opt_databases || opt_alldbs) && path)
+ {
+ fprintf(stderr,
+ "%s: --databases or --all-databases can't be used with --tab.\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 ((*argc < 1 && !opt_alldbs) || (*argc > 0 && opt_alldbs))
+ {
+ usage();
+ return 1;
+ }
+ if (tty_password)
+ password=get_tty_password(NullS);
+ return(0);
+} /* get_options */
+
+
+/*
+** DBerror -- prints mysql error message and exits the program.
+*/
+static 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 */
+
+
+static void safe_exit(int error)
+{
+ if (!first_error)
+ first_error= error;
+ if (ignore_errors)
+ return;
+ if (sock)
+ mysql_close(sock);
+ exit(error);
+}
+/* safe_exit */
+
+
+/*
+** dbConnect -- connects to the host and selects DB.
+** Also checks whether the tablename is a valid table name.
+*/
+static int dbConnect(char *host, char *user,char *passwd)
+{
+ DBUG_ENTER("dbConnect");
+ if (verbose)
+ {
+ fprintf(stderr, "# Connecting to %s...\n", host ? host : "localhost");
+ }
+ mysql_init(&mysql_connection);
+ if (opt_compress)
+ mysql_options(&mysql_connection,MYSQL_OPT_COMPRESS,NullS);
+#ifdef HAVE_OPENSSL
+ if (opt_use_ssl)
+ mysql_ssl_set(&mysql_connection, opt_ssl_key, opt_ssl_cert, opt_ssl_ca,
+ opt_ssl_capath);
+#endif
+ if (!(sock= mysql_real_connect(&mysql_connection,host,user,passwd,
+ NULL,opt_mysql_port,opt_mysql_unix_port,
+ 0)))
+ {
+ DBerror(&mysql_connection, "when trying to connect");
+ return 1;
+ }
+ return 0;
+} /* dbConnect */
+
+
+/*
+** dbDisconnect -- disconnects from the host.
+*/
+static void dbDisconnect(char *host)
+{
+ if (verbose)
+ fprintf(stderr, "# Disconnecting from %s...\n", host ? host : "localhost");
+ mysql_close(sock);
+} /* dbDisconnect */
+
+
+static void unescape(FILE *file,char *pos,uint length)
+{
+ char *tmp;
+ DBUG_ENTER("unescape");
+ if (!(tmp=(char*) my_malloc(length*2+1, MYF(MY_WME))))
+ {
+ ignore_errors=0; /* Fatal error */
+ safe_exit(EX_MYSQLERR); /* Force exit */
+ }
+ mysql_real_escape_string(&mysql_connection,tmp, pos, length);
+ fputc('\'', file);
+ fputs(tmp, file);
+ fputc('\'', file);
+ my_free(tmp, MYF(MY_WME));
+ DBUG_VOID_RETURN;
+} /* unescape */
+
+
+static my_bool test_if_special_chars(const char *str)
+{
+#if MYSQL_VERSION_ID >= 32300
+ for ( ; *str ; str++)
+ if (!isvar(*str) && *str != '$')
+ return 1;
+#endif
+ return 0;
+} /* test_if_special_chars */
+
+static char *quote_name(char *name, char *buff)
+{
+ char *end;
+ 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;
+ return buff;
+} /* quote_name */
+
+
+/*
+** getStructure -- retrievs database structure, prints out corresponding
+** CREATE statement and fills out insert_pat.
+** Return values: number of fields in table, 0 if error
+*/
+static uint getTableStructure(char *table, char* db)
+{
+ MYSQL_RES *tableRes;
+ MYSQL_ROW row;
+ my_bool init=0;
+ uint numFields;
+ char *strpos, *table_name;
+ const char *delayed;
+ char name_buff[NAME_LEN+3],table_buff[NAME_LEN+3];
+ FILE *sql_file = stdout;
+ DBUG_ENTER("getTableStructure");
+
+ delayed= opt_delayed ? " DELAYED " : "";
+
+ if (verbose)
+ fprintf(stderr, "# Retrieving table structure for table %s...\n", table);
+
+ table_name=quote_name(table,table_buff);
+ sprintf(insert_pat,"show fields from %s",table_name);
+ if (mysql_query(sock,insert_pat) || !(tableRes=mysql_store_result(sock)))
+ {
+ fprintf(stderr, "%s: Can't get info about table: '%s'\nerror: %s\n",
+ my_progname, table, mysql_error(sock));
+ if (sql_file != stdout)
+ my_fclose(sql_file, MYF(MY_WME));
+ safe_exit(EX_MYSQLERR);
+ DBUG_RETURN(0);
+ }
+
+ /* Make an sql-file, if path was given iow. option -T was given */
+ if (!tFlag)
+ {
+ if (path)
+ {
+ char filename[FN_REFLEN], tmp_path[FN_REFLEN];
+ strmov(tmp_path,path);
+ convert_dirname(tmp_path);
+ sql_file= my_fopen(fn_format(filename, table, tmp_path, ".sql", 4),
+ O_WRONLY, MYF(MY_WME));
+ if (!sql_file) /* If file couldn't be opened */
+ {
+ safe_exit(EX_MYSQLERR);
+ DBUG_RETURN(0);
+ }
+ write_heder(sql_file, db);
+ }
+ fprintf(sql_file, "\n#\n# Table structure for table '%s'\n#\n\n", table);
+ if (opt_drop)
+ fprintf(sql_file, "DROP TABLE IF EXISTS %s;\n",table_name);
+ fprintf(sql_file, "CREATE TABLE %s (\n", table_name);
+ }
+ if (cFlag)
+ sprintf(insert_pat, "INSERT %sINTO %s (", delayed, table_name);
+ else
+ {
+ sprintf(insert_pat, "INSERT %sINTO %s VALUES ", delayed, table_name);
+ if (!extended_insert)
+ strcat(insert_pat,"(");
+ }
+
+ strpos=strend(insert_pat);
+ while ((row=mysql_fetch_row(tableRes)))
+ {
+ ulong *lengths=mysql_fetch_lengths(tableRes);
+ if (init)
+ {
+ if (!tFlag)
+ fputs(",\n",sql_file);
+ if (cFlag)
+ strpos=strmov(strpos,", ");
+ }
+ init=1;
+ if (cFlag)
+ strpos=strmov(strpos,quote_name(row[SHOW_FIELDNAME],name_buff));
+ if (!tFlag)
+ {
+ if (opt_keywords)
+ fprintf(sql_file, " %s.%s %s", table_name,
+ quote_name(row[SHOW_FIELDNAME],name_buff), row[SHOW_TYPE]);
+ else
+ fprintf(sql_file, " %s %s", quote_name(row[SHOW_FIELDNAME],name_buff),
+ row[SHOW_TYPE]);
+ if (row[SHOW_DEFAULT])
+ {
+ fputs(" DEFAULT ", sql_file);
+ unescape(sql_file,row[SHOW_DEFAULT],lengths[SHOW_DEFAULT]);
+ }
+ if (!row[SHOW_NULL][0])
+ fputs(" NOT NULL", sql_file);
+ if (row[SHOW_EXTRA][0])
+ fprintf(sql_file, " %s",row[SHOW_EXTRA]);
+ }
+ }
+ numFields = (uint) mysql_num_rows(tableRes);
+ mysql_free_result(tableRes);
+ if (!tFlag)
+ {
+ char buff[20+FN_REFLEN];
+ uint keynr,primary_key;
+ sprintf(buff,"show keys from %s",table_name);
+ if (mysql_query(sock, buff))
+ {
+ fprintf(stderr, "%s: Can't get keys for table '%s' (%s)\n",
+ my_progname, table, mysql_error(sock));
+ if (sql_file != stdout)
+ my_fclose(sql_file, MYF(MY_WME));
+ safe_exit(EX_MYSQLERR);
+ DBUG_RETURN(0);
+ }
+
+ tableRes=mysql_store_result(sock);
+ /* Find first which key is primary key */
+ keynr=0;
+ primary_key=INT_MAX;
+ while ((row=mysql_fetch_row(tableRes)))
+ {
+ if (atoi(row[3]) == 1)
+ {
+ keynr++;
+#ifdef FORCE_PRIMARY_KEY
+ if (atoi(row[1]) == 0 && primary_key == INT_MAX)
+ primary_key=keynr;
+#endif
+ if (!strcmp(row[2],"PRIMARY"))
+ {
+ primary_key=keynr;
+ break;
+ }
+ }
+ }
+ mysql_data_seek(tableRes,0);
+ keynr=0;
+ while ((row=mysql_fetch_row(tableRes)))
+ {
+ if (atoi(row[3]) == 1)
+ {
+ if (keynr++)
+ putc(')', sql_file);
+ if (atoi(row[1])) /* Test if duplicate key */
+ /* Duplicate allowed */
+ fprintf(sql_file, ",\n KEY %s (",quote_name(row[2],name_buff));
+ else if (keynr == primary_key)
+ fputs(",\n PRIMARY KEY (",sql_file); /* First UNIQUE is primary */
+ else
+ fprintf(sql_file, ",\n UNIQUE %s (",quote_name(row[2],name_buff));
+ }
+ else
+ putc(',', sql_file);
+ fputs(quote_name(row[4],name_buff), sql_file);
+ if (row[7])
+ fprintf(sql_file, "(%s)",row[7]); /* Sub key */
+ }
+ if (keynr)
+ putc(')', sql_file);
+ fputs("\n)",sql_file);
+
+ /* Get MySQL specific create options */
+ if (create_options)
+ {
+ sprintf(buff,"show table status like '%s'",table);
+ if (mysql_query(sock, buff))
+ {
+ if (mysql_errno(sock) != ER_PARSE_ERROR)
+ { /* If old MySQL version */
+ if (verbose)
+ fprintf(stderr,
+ "# Warning: Couldn't get status information for table '%s' (%s)\n",
+ table,mysql_error(sock));
+ }
+ }
+ else if (!(tableRes=mysql_store_result(sock)) ||
+ !(row=mysql_fetch_row(tableRes)))
+ {
+ fprintf(stderr,
+ "Error: Couldn't read status information for table '%s' (%s)\n",
+ table,mysql_error(sock));
+ }
+ else
+ {
+ fputs("/*!",sql_file);
+ print_value(sql_file,tableRes,row,"type=","Type",0);
+ print_value(sql_file,tableRes,row,"","Create_options",0);
+ print_value(sql_file,tableRes,row,"comment=","Comment",1);
+ fputs(" */",sql_file);
+ }
+ mysql_free_result(tableRes); /* Is always safe to free */
+ }
+ fputs(";\n", sql_file);
+ }
+ if (cFlag)
+ {
+ strpos=strmov(strpos,") VALUES ");
+ if (!extended_insert)
+ strpos=strmov(strpos,"(");
+ }
+ DBUG_RETURN(numFields);
+} /* getTableStructure */
+
+
+static char *add_load_option(char *ptr,const char *object,
+ const char *statement)
+{
+ if (object)
+ {
+ ptr= strxmov(ptr," ",statement," '",NullS);
+ ptr= field_escape(ptr,object,strlen(object));
+ *ptr++= '\'';
+ }
+ return ptr;
+} /* add_load_option */
+
+
+/*
+** 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.
+*/
+
+static char *field_escape(char *to,const char *from,uint length)
+{
+ const char *end;
+ uint end_backslashes=0;
+
+ for (end= from+length; from != end; from++)
+ {
+ *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++= '\\';
+ return to;
+} /* field_escape */
+
+
+/*
+** dumpTable saves database contents as a series of INSERT statements.
+*/
+static void dumpTable(uint numFields, char *table)
+{
+ char query[1024], *end, buff[256],table_buff[NAME_LEN+3];
+ MYSQL_RES *res;
+ MYSQL_FIELD *field;
+ MYSQL_ROW row;
+ ulong rownr, row_break, total_length, init_length;
+
+ if (verbose)
+ fprintf(stderr, "# Sending SELECT query...\n");
+ if (path)
+ {
+ char filename[FN_REFLEN], tmp_path[FN_REFLEN];
+ strmov(tmp_path, path);
+ convert_dirname(tmp_path);
+ 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
+ filename wasn't deleted */
+ to_unix_path(filename);
+ sprintf(query, "SELECT * INTO OUTFILE '%s'", filename);
+ end= strend(query);
+ if (replace)
+ end= strmov(end, " REPLACE");
+ if (ignore)
+ end= strmov(end, " IGNORE");
+
+ if (fields_terminated || enclosed || opt_enclosed || escaped)
+ end= strmov(end, " FIELDS");
+ end= add_load_option(end, fields_terminated, " TERMINATED BY");
+ end= add_load_option(end, enclosed, " ENCLOSED BY");
+ end= add_load_option(end, opt_enclosed, " OPTIONALLY ENCLOSED BY");
+ end= add_load_option(end, escaped, " ESCAPED BY");
+ end= add_load_option(end, lines_terminated, " LINES TERMINATED BY");
+ *end= '\0';
+
+ sprintf(buff," FROM %s",table);
+ end= strmov(end,buff);
+ if (where)
+ end= strxmov(end, " WHERE ",where,NullS);
+ if (mysql_query(sock, query))
+ {
+ DBerror(sock, "when executing 'SELECT INTO OUTFILE'");
+ return;
+ }
+ }
+ else
+ {
+ printf("\n#\n# Dumping data for table '%s'\n", table);
+ sprintf(query, "SELECT * FROM %s", quote_name(table,table_buff));
+ if (where)
+ {
+ printf("# WHERE: %s\n",where);
+ strxmov(strend(query), " WHERE ",where,NullS);
+ }
+ puts("#\n");
+
+ if (mysql_query(sock, query))
+ {
+ DBerror(sock, "when retrieving data from server");
+ return;
+ }
+ if (quick)
+ res=mysql_use_result(sock);
+ else
+ res=mysql_store_result(sock);
+ if (!res)
+ {
+ DBerror(sock, "when retrieving data from server");
+ return;
+ }
+ if (verbose)
+ fprintf(stderr, "# Retrieving rows...\n");
+ if (mysql_num_fields(res) != numFields)
+ {
+ fprintf(stderr,"%s: Error in field count for table: '%s' ! Aborting.\n",
+ my_progname,table);
+ safe_exit(EX_CONSCHECK);
+ return;
+ }
+
+ if (opt_lock)
+ printf("LOCK TABLES %s WRITE;\n", quote_name(table,table_buff));
+
+ total_length=net_buffer_length; /* Force row break */
+ row_break=0;
+ rownr=0;
+ init_length=strlen(insert_pat)+4;
+
+ while ((row=mysql_fetch_row(res)))
+ {
+ uint i;
+ ulong *lengths=mysql_fetch_lengths(res);
+ rownr++;
+ if (!extended_insert)
+ fputs(insert_pat,stdout);
+ mysql_field_seek(res,0);
+
+ for (i = 0; i < mysql_num_fields(res); i++)
+ {
+ if (!(field = mysql_fetch_field(res)))
+ {
+ sprintf(query,"%s: Not enough fields from table '%s'! Aborting.\n",
+ my_progname,table);
+ fputs(query,stderr);
+ safe_exit(EX_CONSCHECK);
+ return;
+ }
+ if (extended_insert)
+ {
+ ulong length = lengths[i];
+ if (i == 0)
+ dynstr_set(&extended_row,"(");
+ else
+ dynstr_append(&extended_row,",");
+
+ if (row[i])
+ {
+ if (length)
+ {
+ if (!IS_NUM(field->type))
+ {
+ if (dynstr_realloc(&extended_row,length * 2+2))
+ {
+ fputs("Aborting dump (out of memory)",stderr);
+ safe_exit(EX_EOM);
+ }
+ dynstr_append(&extended_row,"\'");
+ extended_row.length +=
+ mysql_real_escape_string(&mysql_connection,
+ &extended_row.str[extended_row.length],row[i],length);
+ extended_row.str[extended_row.length]='\0';
+ dynstr_append(&extended_row,"\'");
+ }
+ else
+ dynstr_append(&extended_row,row[i]);
+ }
+ else
+ dynstr_append(&extended_row,"\'\'");
+ }
+ else if (dynstr_append(&extended_row,"NULL"))
+ {
+ fputs("Aborting dump (out of memory)",stderr);
+ safe_exit(EX_EOM);
+ }
+ }
+ else
+ {
+ if (i)
+ putchar(',');
+ if (row[i])
+ {
+ if (!IS_NUM(field->type))
+ unescape(stdout, row[i], lengths[i]);
+ else
+ fputs(row[i],stdout);
+ }
+ else
+ {
+ fputs("NULL",stdout);
+ }
+ }
+ }
+
+ if (extended_insert)
+ {
+ ulong row_length;
+ dynstr_append(&extended_row,")");
+ row_length = 2 + extended_row.length;
+ if (total_length + row_length < net_buffer_length)
+ {
+ total_length += row_length;
+ putchar(','); /* Always row break */
+ fputs(extended_row.str,stdout);
+ }
+ else
+ {
+ if (row_break)
+ puts(";");
+ row_break=1; /* This is first row */
+ fputs(insert_pat,stdout);
+ fputs(extended_row.str,stdout);
+ total_length = row_length+init_length;
+ }
+ }
+ else
+ {
+ puts(");");
+ }
+ }
+ if (extended_insert && row_break)
+ puts(";"); /* If not empty table */
+ fflush(stdout);
+ if (mysql_errno(sock))
+ {
+ sprintf(query,"%s: Error %d: %s when dumping table '%s' at row: %ld\n",
+ my_progname,
+ mysql_errno(sock),
+ mysql_error(sock),
+ table,
+ rownr);
+ fputs(query,stderr);
+ safe_exit(EX_CONSCHECK);
+ return;
+ }
+ if (opt_lock)
+ puts("UNLOCK TABLES;");
+ mysql_free_result(res);
+ }
+} /* dumpTable */
+
+
+static char *getTableName(int reset)
+{
+ static MYSQL_RES *res = NULL;
+ MYSQL_ROW row;
+
+ if (!res)
+ {
+ if (!(res = mysql_list_tables(sock,NullS)))
+ return(NULL);
+ }
+ if ((row = mysql_fetch_row(res)))
+ return((char*) row[0]);
+
+ if (reset)
+ mysql_data_seek(res,0); /* We want to read again */
+ else
+ {
+ mysql_free_result(res);
+ res = NULL;
+ }
+ return(NULL);
+} /* getTableName */
+
+
+static int dump_all_databases()
+{
+ MYSQL_ROW row;
+ MYSQL_RES *tableres;
+ int result=0;
+
+ if (mysql_query(sock, "SHOW DATABASES") ||
+ !(tableres = mysql_store_result(sock)))
+ {
+ my_printf_error(0, "Error: Couldn't execute 'SHOW DATABASES': %s",
+ MYF(0), mysql_error(sock));
+ return 1;
+ }
+ while ((row = mysql_fetch_row(tableres)))
+ {
+ if (dump_all_tables_in_db(row[0]))
+ result=1;
+ }
+ return result;
+}
+/* dump_all_databases */
+
+
+static int dump_databases(char **db_names)
+{
+ int result=0;
+ for ( ; *db_names ; db_names++)
+ {
+ if (dump_all_tables_in_db(*db_names))
+ result=1;
+ }
+ return result;
+} /* dump_databases */
+
+
+static int init_dumping(char *database)
+{
+ if (mysql_select_db(sock, database))
+ {
+ DBerror(sock, "when selecting the database");
+ return 1; /* If --force */
+ }
+ if (!path)
+ {
+ if (opt_databases || opt_alldbs)
+ {
+ printf("\n#\n# Current Database: %s\n#\n", database);
+ if (!opt_create_db)
+ printf("\nCREATE DATABASE /*!32312 IF NOT EXISTS*/ %s;\n", database);
+ printf("\nUSE %s;\n", database);
+ }
+ }
+ if (extended_insert)
+ if (init_dynamic_string(&extended_row, "", 1024, 1024))
+ exit(EX_EOM);
+ return 0;
+} /* init_dumping */
+
+
+static int dump_all_tables_in_db(char *database)
+{
+ char *table;
+ uint numrows;
+
+ if (init_dumping(database))
+ return 1;
+ if (lock_tables)
+ {
+ DYNAMIC_STRING query;
+ init_dynamic_string(&query, "LOCK TABLES ", 256, 1024);
+ for (numrows=0 ; (table = getTableName(1)) ; numrows++)
+ {
+ dynstr_append(&query, table);
+ dynstr_append(&query, " READ /*!32311 LOCAL */,");
+ }
+ if (numrows && mysql_real_query(sock, query.str, query.length-1))
+ DBerror(sock, "when using LOCK TABLES");
+ /* We shall continue here, if --force was given */
+ dynstr_free(&query);
+ }
+ if (flush_logs)
+ {
+ if (mysql_refresh(sock, REFRESH_LOG))
+ DBerror(sock, "when doing refresh");
+ /* We shall continue here, if --force was given */
+ }
+ while ((table = getTableName(0)))
+ {
+ numrows = getTableStructure(table, database);
+ if (!dFlag && numrows > 0)
+ dumpTable(numrows,table);
+ }
+ if (lock_tables)
+ mysql_query(sock,"UNLOCK_TABLES");
+ return 0;
+} /* dump_all_tables_in_db */
+
+
+
+static int dump_selected_tables(char *db, char **table_names, int tables)
+{
+ uint numrows;
+
+ if (init_dumping(db))
+ return 1;
+ if (lock_tables)
+ {
+ DYNAMIC_STRING query;
+ int i;
+
+ init_dynamic_string(&query, "LOCK TABLES ", 256, 1024);
+ for (i=0 ; i < tables ; i++)
+ {
+ dynstr_append(&query, table_names[i]);
+ dynstr_append(&query, " READ /*!32311 LOCAL */,");
+ }
+ if (mysql_real_query(sock, query.str, query.length-1))
+ DBerror(sock, "when doing LOCK TABLES");
+ /* We shall countinue here, if --force was given */
+ dynstr_free(&query);
+ }
+ if (flush_logs)
+ {
+ if (mysql_refresh(sock, REFRESH_LOG))
+ DBerror(sock, "when doing refresh");
+ /* We shall countinue here, if --force was given */
+ }
+ for (; tables > 0 ; tables-- , table_names++)
+ {
+ numrows = getTableStructure(*table_names, db);
+ if (!dFlag && numrows > 0)
+ dumpTable(numrows, *table_names);
+ }
+ if (lock_tables)
+ mysql_query(sock,"UNLOCK_TABLES");
+ return 0;
+} /* dump_selected_tables */
+
+
+/* Print a value with a prefix on file */
+static void print_value(FILE *file, MYSQL_RES *result, MYSQL_ROW row,
+ const char *prefix, const char *name,
+ int string_value)
+{
+ MYSQL_FIELD *field;
+ mysql_field_seek(result, 0);
+
+ for ( ; (field = mysql_fetch_field(result)) ; row++)
+ {
+ if (!strcmp(field->name,name))
+ {
+ if (row[0] && row[0][0] && strcmp(row[0],"0")) /* Skip default */
+ {
+ fputc(' ',file);
+ fputs(prefix, file);
+ if (string_value)
+ unescape(file,row[0],strlen(row[0]));
+ else
+ fputs(row[0], file);
+ return;
+ }
+ }
+ }
+ return; /* This shouldn't happen */
+} /* print_value */
+
+
+int main(int argc, char **argv)
+{
+ MY_INIT(argv[0]);
+ /*
+ ** Check out the args
+ */
+ if (get_options(&argc, &argv))
+ {
+ my_end(0);
+ exit(EX_USAGE);
+ }
+ if (dbConnect(current_host, current_user, password))
+ exit(EX_MYSQLERR);
+ if (!path)
+ write_heder(stdout, *argv);
+
+ if (opt_first_slave)
+ {
+ lock_tables=0; /* No other locks needed */
+ if (mysql_query(sock, "FLUSH TABLES WITH READ LOCK"))
+ {
+ my_printf_error(0, "Error: Couldn't execute 'FLUSH TABLES WITH READ LOCK': %s",
+ MYF(0), mysql_error(sock));
+ my_end(0);
+ return(first_error);
+ }
+ }
+ if (opt_alldbs)
+ dump_all_databases();
+ /* Only one database and selected table(s) */
+ else if (argc > 1 && !opt_databases)
+ dump_selected_tables(*argv, (argv + 1), (argc - 1));
+ /* One or more databases, all tables */
+ else
+ dump_databases(argv);
+
+ if (opt_first_slave)
+ {
+ if (mysql_query(sock, "FLUSH MASTER"))
+ {
+ my_printf_error(0, "Error: Couldn't execute 'FLUSH MASTER': %s",
+ MYF(0), mysql_error(sock));
+ }
+ if (mysql_query(sock, "UNLOCK TABLES"))
+ {
+ my_printf_error(0, "Error: Couldn't execute 'UNLOCK TABLES': %s",
+ MYF(0), mysql_error(sock));
+ }
+ }
+ dbDisconnect(current_host);
+ puts("");
+ my_free(password, MYF(MY_ALLOW_ZERO_PTR));
+ if (extended_insert)
+ dynstr_free(&extended_row);
+ my_end(0);
+ return(first_error);
+} /* main */
diff --git a/client/mysqlimport.c b/client/mysqlimport.c
new file mode 100644
index 00000000000..28cacaa58dc
--- /dev/null
+++ b/client/mysqlimport.c
@@ -0,0 +1,521 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/*
+** mysqlimport.c - Imports all given files
+** into a table(s).
+**
+** *************************
+** * *
+** * AUTHOR: Monty & Jani *
+** * DATE: June 24, 1997 *
+** * *
+** *************************
+*/
+#define IMPORT_VERSION "2.3"
+
+#include <global.h>
+#include <my_sys.h>
+#include <m_string.h>
+#include "mysql.h"
+#include "mysql_version.h"
+#include <getopt.h>
+
+
+static void db_error_with_table(MYSQL *mysql, char *table);
+static void db_error(MYSQL *mysql);
+static char *field_escape(char *to,const char *from,uint length);
+static char *add_load_option(char *ptr,const char *object,
+ const char *statement);
+
+static my_bool verbose=0,lock_tables=0,ignore_errors=0,delete=0,
+ replace=0,silent=0,ignore=0,opt_compress=0,opt_local_file=0;
+
+static MYSQL mysql_connection;
+static char *password=0, *current_user=0,
+ *current_host=0, *current_db=0, *fields_terminated=0,
+ *lines_terminated=0, *enclosed=0, *opt_enclosed=0,
+ *escaped=0, opt_low_priority=0, *opt_columns=0;
+static uint opt_mysql_port=0;
+static my_string opt_mysql_unix_port=0;
+#include "sslopt-vars.h"
+
+enum options {OPT_FTB=256, OPT_LTB, OPT_ENC, OPT_O_ENC, OPT_ESC,
+ OPT_LOW_PRIORITY, OPT_CHARSETS_DIR};
+
+static struct option long_options[] =
+{
+ {"character-sets-dir", required_argument, 0, OPT_CHARSETS_DIR},
+ {"columns", required_argument, 0, 'c'},
+ {"compress", no_argument, 0, 'C'},
+ {"debug", optional_argument, 0, '#'},
+ {"delete", no_argument, 0, 'd'},
+ {"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},
+ {"force", no_argument, 0, 'f'},
+ {"help", no_argument, 0, '?'},
+ {"host", required_argument, 0, 'h'},
+ {"ignore", no_argument, 0, 'i'},
+ {"lines-terminated-by", required_argument, 0, (int) OPT_LTB},
+ {"local", no_argument, 0, 'L'},
+ {"lock-tables", no_argument, 0, 'l'},
+ {"low-priority", no_argument, 0, (int) OPT_LOW_PRIORITY},
+ {"password", optional_argument, 0, 'p'},
+#ifdef __WIN__
+ {"pipe", no_argument, 0, 'W'},
+#endif
+ {"port", required_argument, 0, 'P'},
+ {"replace", no_argument, 0, 'r'},
+ {"silent", no_argument, 0, 's'},
+ {"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}
+};
+
+
+static const char *load_default_groups[]= { "mysqlimport","client",0 };
+
+static void print_version(void)
+{
+ printf("%s Ver %s Distrib %s, for %s (%s)\n" ,my_progname,
+ IMPORT_VERSION, MYSQL_SERVER_VERSION,SYSTEM_TYPE,MACHINE_TYPE);
+}
+
+
+
+static void usage(void)
+{
+ print_version();
+ 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("\
+Loads tables from text files in various formats. The base name of the\n\
+text file must be the name of the table that should be used.\n\
+If one uses sockets to connect to the MySQL server, the server will open and\n\
+read the text file directly. In other cases the client will open the text\n\
+file. The SQL command 'LOAD DATA INFILE' is used to import the rows.\n");
+
+ printf("\nUsage: %s [OPTIONS] database textfile...",my_progname);
+ printf("\n\
+ -#, --debug[=...] Output debug log. Often this is 'd:t:o,filename`\n\
+ -?, --help Displays this help and exits.\n\
+ --character-sets-dir=...\n\
+ Directory where character sets are\n\
+ -c, --columns=... Use only these columns to import the data to.\n\
+ Give the column names in a comma separated list.\n\
+ This is same as giving columns to LOAD DATA INFILE.\n\
+ -C, --compress Use compression in server/client protocol\n\
+ -d, --delete Deletes first all rows from table.\n\
+ -f, --force Continue even if we get an sql-error.\n\
+ -h, --host=... Connect to host.\n\
+ -i, --ignore If duplicate unique key was found, keep old row.\n\
+ -l, --lock-tables Lock all tables for write.\n\
+ -L, --local Read all files through the client\n\
+ --low-priority Use LOW_PRIORITY when updating the table\n\
+ -p, --password[=...] 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");
+#endif
+ printf("\
+ -P, --port=... Port number to use for connection.\n\
+ -r, --replace If duplicate unique key was found, replace old row.\n\
+ -s, --silent Be more silent.\n\
+ -S, --socket=... Socket file to use for connection.\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\
+ --fields-terminated-by=...\n\
+ Fields in the textfile are terminated by ...\n\
+ --fields-enclosed-by=...\n\
+ Fields in the importfile are enclosed by ...\n\
+ --fields-optionally-enclosed-by=...\n\
+ Fields in the i.file are opt. enclosed by ...\n\
+ --fields-escaped-by=...\n\
+ Fields in the i.file are escaped by ...\n\
+ --lines-terminated-by=...\n\
+ Lines in the i.file are terminated by ...\n\
+");
+ print_defaults("my",load_default_groups);
+}
+
+static int get_options(int *argc, char ***argv)
+{
+ int c, option_index;
+ my_bool tty_password=0;
+
+ while ((c=getopt_long(*argc,*argv,"#::p::c:h:u:P:S:CdfilLrsvV?IW",
+ long_options, &option_index)) != EOF)
+ {
+ switch(c) {
+ case 'c':
+ opt_columns= optarg;
+ break;
+ case 'C':
+ opt_compress=1;
+ break;
+ case OPT_CHARSETS_DIR:
+ charsets_dir= optarg;
+ break;
+ case 'd':
+ delete= 1;
+ break;
+ case 'f':
+ ignore_errors= 1;
+ break;
+ case 'h':
+ current_host= optarg;
+ break;
+ case 'i':
+ ignore= 1;
+ break;
+#ifndef DONT_ALLOW_USER_CHANGE
+ case 'u':
+ current_user= optarg;
+ break;
+#endif
+ case 'p':
+ if (optarg)
+ {
+ my_free(password,MYF(MY_ALLOW_ZERO_PTR));
+ password= my_strdup(optarg,MYF(MY_FAE));
+ while (*optarg) *optarg++= 'x'; /* Destroy argument */
+ }
+ else
+ tty_password= 1;
+ break;
+ case 'P':
+ opt_mysql_port= (unsigned int) atoi(optarg);
+ break;
+ case 'r':
+ replace= 1;
+ break;
+ case 's':
+ silent= 1;
+ break;
+ case 'S':
+ opt_mysql_unix_port= optarg;
+ break;
+#ifdef __WIN__
+ case 'W':
+ opt_mysql_unix_port=MYSQL_NAMEDPIPE;
+ opt_local_file=1;
+ break;
+#endif
+ case '#':
+ DBUG_PUSH(optarg ? optarg : "d:t:o");
+ break;
+ case 'l': lock_tables= 1; break;
+ case 'L': opt_local_file=1; break;
+ case 'v': verbose= 1; break;
+ case 'V': print_version(); exit(0);
+ 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;
+#include "sslopt-case.h"
+ }
+ }
+ if (enclosed && opt_enclosed)
+ {
+ fprintf(stderr, "You can't use ..enclosed.. and ..optionally-enclosed.. at the same time.\n");
+ return(1);
+ }
+ if (replace && ignore)
+ {
+ fprintf(stderr, "You can't use --ignore (-i) and --replace (-r) at the same time.\n");
+ return(1);
+ }
+ (*argc)-=optind;
+ (*argv)+=optind;
+ if (*argc < 2)
+ {
+ usage();
+ return 1;
+ }
+ current_db= *((*argv)++);
+ (*argc)--;
+ if (tty_password)
+ password=get_tty_password(NullS);
+ return(0);
+}
+
+
+
+static int write_to_table(char *filename, MYSQL *sock)
+{
+ char tablename[FN_REFLEN], hard_path[FN_REFLEN],
+ sql_statement[FN_REFLEN*2+256], *end;
+ my_bool local_file;
+ DBUG_ENTER("write_to_table");
+ DBUG_PRINT("enter",("filename: %s",filename));
+
+ local_file= sock->unix_socket == 0 || opt_local_file;
+
+ fn_format(tablename, filename, "", "", 1 | 2); /* removes path & ext. */
+ if (local_file)
+ strmov(hard_path,filename);
+ else
+ my_load_path(hard_path, filename, NULL); /* filename includes the path */
+
+ if (delete)
+ {
+ if (verbose)
+ fprintf(stdout, "Deleting the old data from table %s\n", tablename);
+ sprintf(sql_statement, "DELETE FROM %s", tablename);
+ if (mysql_query(sock, sql_statement))
+ {
+ db_error_with_table(sock, tablename);
+ DBUG_RETURN(1);
+ }
+ }
+ to_unix_path(hard_path);
+ if (verbose)
+ {
+ if (local_file)
+ fprintf(stdout, "Loading data from LOCAL file: %s into %s\n",
+ hard_path, tablename);
+ else
+ fprintf(stdout, "Loading data from SERVER file: %s into %s\n",
+ hard_path, tablename);
+ }
+ sprintf(sql_statement, "LOAD DATA %s %s INFILE '%s'",
+ opt_low_priority ? "LOW_PRIORITY" : "",
+ local_file ? "LOCAL" : "", hard_path);
+ end= strend(sql_statement);
+ if (replace)
+ end= strmov(end, " REPLACE");
+ if (ignore)
+ end= strmov(end, " IGNORE");
+ end= strmov(strmov(end, " INTO TABLE "), tablename);
+
+ if (fields_terminated || enclosed || opt_enclosed || escaped)
+ end= strmov(end, " FIELDS");
+ end= add_load_option(end, fields_terminated, " TERMINATED BY");
+ end= add_load_option(end, enclosed, " ENCLOSED BY");
+ end= add_load_option(end, opt_enclosed,
+ " OPTIONALLY ENCLOSED BY");
+ end= add_load_option(end, escaped, " ESCAPED BY");
+ end= add_load_option(end, lines_terminated, " LINES TERMINATED BY");
+ if (opt_columns)
+ end= strmov(strmov(strmov(end, " ("), opt_columns), ")");
+ *end= '\0';
+
+ if (mysql_query(sock, sql_statement))
+ {
+ db_error_with_table(sock, tablename);
+ DBUG_RETURN(1);
+ }
+ if (!silent)
+ {
+ if (mysql_info(sock)) /* If NULL-pointer, print nothing */
+ {
+ fprintf(stdout, "%s.%s: %s\n", current_db, tablename,
+ mysql_info(sock));
+ }
+ }
+ DBUG_RETURN(0);
+}
+
+
+
+static void lock_table(MYSQL *sock, int tablecount, char **raw_tablename)
+{
+ DYNAMIC_STRING query;
+ int i;
+ char tablename[FN_REFLEN];
+
+ if (verbose)
+ fprintf(stdout, "Locking tables for write\n");
+ init_dynamic_string(&query, "LOCK TABLES ", 256, 1024);
+ for (i=0 ; i < tablecount ; i++)
+ {
+ fn_format(tablename, raw_tablename[i], "", "", 1 | 2);
+ dynstr_append(&query, tablename);
+ dynstr_append(&query, " WRITE,");
+ }
+ if (mysql_real_query(sock, query.str, query.length-1))
+ db_error(sock); /* We shall countinue here, if --force was given */
+}
+
+
+
+
+static MYSQL *db_connect(char *host, char *database, char *user, char *passwd)
+{
+ MYSQL *sock;
+ if (verbose)
+ fprintf(stdout, "Connecting to %s\n", host ? host : "localhost");
+ mysql_init(&mysql_connection);
+ if (opt_compress)
+ mysql_options(&mysql_connection,MYSQL_OPT_COMPRESS,NullS);
+#ifdef HAVE_OPENSSL
+ if (opt_use_ssl)
+ mysql_ssl_set(&mysql_connection, opt_ssl_key, opt_ssl_cert, opt_ssl_ca,
+ opt_ssl_capath);
+#endif
+ if (!(sock= mysql_real_connect(&mysql_connection,host,user,passwd,
+ database,opt_mysql_port,opt_mysql_unix_port,
+ 0)))
+ {
+ ignore_errors=0; /* NO RETURN FROM db_error */
+ db_error(&mysql_connection);
+ }
+ if (verbose)
+ fprintf(stdout, "Selecting database %s\n", database);
+ if (mysql_select_db(sock, database))
+ {
+ ignore_errors=0;
+ db_error(&mysql_connection);
+ }
+ return sock;
+}
+
+
+
+static void db_disconnect(char *host, MYSQL *sock)
+{
+ if (verbose)
+ fprintf(stdout, "Disconnecting from %s\n", host ? host : "localhost");
+ mysql_close(sock);
+}
+
+
+
+static void safe_exit(int error, MYSQL *sock)
+{
+ if (ignore_errors)
+ return;
+ if (sock)
+ mysql_close(sock);
+ exit(error);
+}
+
+
+
+static void db_error_with_table(MYSQL *mysql, char *table)
+{
+ my_printf_error(0,"Error: %s, when using table: %s",
+ MYF(0), mysql_error(mysql), table);
+ safe_exit(1, mysql);
+}
+
+
+
+static void db_error(MYSQL *mysql)
+{
+ my_printf_error(0,"Error: %s", MYF(0), mysql_error(mysql));
+ safe_exit(1, mysql);
+}
+
+
+static char *add_load_option(char *ptr,const char *object,const char *statement)
+{
+ if (object)
+ {
+ ptr= strxmov(ptr," ",statement," '",NullS);
+ ptr= field_escape(ptr,object,strlen(object));
+ *ptr++= '\'';
+ }
+ return ptr;
+}
+
+/*
+** 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.
+*/
+
+static char *field_escape(char *to,const char *from,uint length)
+{
+ const char *end;
+ uint end_backslashes=0;
+
+ for (end= from+length; from != end; from++)
+ {
+ *to++= *from;
+ if (*from == '\\')
+ end_backslashes^=1; /* find odd number of backslashes */
+ else
+ {
+ if (*from == '\'' && !end_backslashes)
+ *to++= *from; /* We want a dublicate of "'" for MySQL */
+ end_backslashes=0;
+ }
+ }
+ /* Add missing backslashes if user has specified odd number of backs.*/
+ if (end_backslashes)
+ *to++= '\\';
+ return to;
+}
+
+
+
+int main(int argc, char **argv)
+{
+ int exitcode=0, error=0;
+ char **argv_to_free;
+ MYSQL *sock=0;
+ MY_INIT(argv[0]);
+
+ load_defaults("my",load_default_groups,&argc,&argv);
+ /* argv is changed in the program */
+ argv_to_free= argv;
+ if (get_options(&argc, &argv))
+ return(1);
+ if (!(sock= db_connect(current_host,current_db,current_user,password)))
+ return(1); /* purecov: deadcode */
+ if (lock_tables)
+ lock_table(sock, argc, argv);
+ for (; *argv != NULL; argv++)
+ if ((error=write_to_table(*argv, sock)))
+ if (exitcode == 0)
+ exitcode = error;
+ db_disconnect(current_host, sock);
+ my_free(password,MYF(MY_ALLOW_ZERO_PTR));
+ my_free(current_user,MYF(MY_ALLOW_ZERO_PTR));
+ free_defaults(argv_to_free);
+ my_end(0);
+ return(exitcode);
+}
diff --git a/client/mysqlshow.c b/client/mysqlshow.c
new file mode 100644
index 00000000000..6cf7cdf9963
--- /dev/null
+++ b/client/mysqlshow.c
@@ -0,0 +1,608 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* Show databases, tables or columns */
+
+#define SHOW_VERSION "8.2"
+
+#include <global.h>
+#include <my_sys.h>
+#include <m_string.h>
+#include "mysql.h"
+#include "mysql_version.h"
+#include "mysqld_error.h"
+#include <signal.h>
+#include <stdarg.h>
+#include <getopt.h>
+
+static my_string host=0,password=0,user=0;
+static my_bool opt_show_keys=0,opt_compress=0,opt_status=0;
+
+static void get_options(int *argc,char ***argv);
+static uint opt_mysql_port=0;
+static int list_dbs(MYSQL *mysql,const char *wild);
+static int list_tables(MYSQL *mysql,const char *db,const char *table);
+static int list_table_status(MYSQL *mysql,const char *db,const char *table);
+static int list_fields(MYSQL *mysql,const char *db,const char *table,
+ const char *field);
+static void print_header(const char *header,uint head_length,...);
+static void print_row(const char *header,uint head_length,...);
+static void print_trailer(uint length,...);
+static void print_res_header(MYSQL_RES *result);
+static void print_res_top(MYSQL_RES *result);
+static void print_res_row(MYSQL_RES *result,MYSQL_ROW cur);
+
+static const char *load_default_groups[]= { "mysqlshow","client",0 };
+static my_string opt_mysql_unix_port=0;
+#include "sslopt-vars.h"
+
+int main(int argc, char **argv)
+{
+ int error;
+ char *wild;
+ MYSQL mysql;
+ MY_INIT(argv[0]);
+ load_defaults("my",load_default_groups,&argc,&argv);
+ get_options(&argc,&argv);
+
+ wild=0;
+ if (argc && strcont(argv[argc-1],"*?%_"))
+ {
+ char *pos;
+
+ wild=argv[--argc];
+ for (pos=wild ; *pos ; pos++)
+ { /* Unix wildcards to sql */
+ if (*pos == '*')
+ *pos='%';
+ else if (*pos == '?')
+ *pos='_';
+ }
+ }
+ else if (argc == 3) /* We only want one field */
+ wild=argv[--argc];
+
+ if (argc > 2)
+ {
+ fprintf(stderr,"%s: Too many arguments\n",my_progname);
+ exit(1);
+ }
+ mysql_init(&mysql);
+ if (opt_compress)
+ mysql_options(&mysql,MYSQL_OPT_COMPRESS,NullS);
+#ifdef HAVE_OPENSSL
+ if (opt_use_ssl)
+ mysql_ssl_set(&mysql, opt_ssl_key, opt_ssl_cert, opt_ssl_ca,
+ opt_ssl_capath);
+#endif
+ if (!(mysql_real_connect(&mysql,host,user,password,
+ argv[0],opt_mysql_port,opt_mysql_unix_port,
+ 0)))
+ {
+ fprintf(stderr,"%s: %s\n",my_progname,mysql_error(&mysql));
+ exit(1);
+ }
+ /* if (!(mysql_connect(&mysql,host,user,password))) */
+
+
+ switch (argc)
+ {
+ case 0: error=list_dbs(&mysql,wild); break;
+ case 1:
+ if (opt_status)
+ error=list_table_status(&mysql,argv[0],wild);
+ else
+ error=list_tables(&mysql,argv[0],wild);
+ break;
+ default:
+ if (opt_status && ! wild)
+ error=list_table_status(&mysql,argv[0],argv[1]);
+ else
+ error=list_fields(&mysql,argv[0],argv[1],wild); break;
+ }
+ mysql_close(&mysql); /* Close & free connection */
+ if (password)
+ my_free(password,MYF(0));
+ my_end(0);
+ exit(error ? 1 : 0);
+ return 0; /* No compiler warnings */
+}
+
+
+static struct option long_options[] =
+{
+ {"character-sets-dir", required_argument, 0, 'c'},
+ {"compress", no_argument, 0, 'C'},
+ {"debug", optional_argument, 0, '#'},
+ {"help", no_argument, 0, '?'},
+ {"host", required_argument, 0, 'h'},
+ {"status", no_argument, 0, 'i'},
+ {"keys", no_argument, 0, 'k'},
+ {"password", optional_argument, 0, 'p'},
+ {"port", required_argument, 0, 'P'},
+#ifdef __WIN__
+ {"pipe", no_argument, 0, 'W'},
+#endif
+ {"socket", required_argument, 0, 'S'},
+#include "sslopt-longopts.h"
+#ifndef DONT_ALLOW_USER_CHANGE
+ {"user", required_argument, 0, 'u'},
+#endif
+ {"version", no_argument, 0, 'V'},
+ {0, 0, 0, 0}
+};
+
+
+static void print_version(void)
+{
+ printf("%s Ver %s Distrib %s, for %s (%s)\n",my_progname,SHOW_VERSION,
+ MYSQL_SERVER_VERSION,SYSTEM_TYPE,MACHINE_TYPE);
+}
+
+static void usage(void)
+{
+ print_version();
+ 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");
+ puts("Shows the structure of a mysql database (databases,tables and columns)\n");
+ printf("Usage: %s [OPTIONS] [database [table [column]]]\n",my_progname);
+ printf("\n\
+ -#, --debug=... output debug log. Often this is 'd:t:o,filename`\n\
+ -?, --help display this help and exit\n\
+ -c, --character-sets-dir=...\n\
+ Directory where character sets are\n\
+ -C, --compress Use compression in server/client protocol\n\
+ -h, --host=... connect to host\n\
+ -i, --status Shows a lot of extra information about each table\n\
+ -k, --keys show keys for table\n\
+ -p, --password[=...] 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");
+#endif
+ printf("\
+ -P --port=... Port number to use for connection\n\
+ -S --socket=... Socket file to use for connection\n");
+#include "sslopt-usage.h"
+#ifndef DONT_ALLOW_USER_CHANGE
+ printf("\
+ -u, --user=# user for login if not current user\n");
+#endif
+ printf("\
+ -V, --version output version information and exit\n");
+
+ puts("\n\
+If last argument contains a shell or SQL wildcard (*,?,% or _) then only\n\
+what\'s matched by the wildcard is shown.\n\
+If no database is given then all matching databases are shown.\n\
+If no table is given then all matching tables in database are shown\n\
+If no column is given then all matching columns and columntypes in table\n\
+are shown");
+ print_defaults("my",load_default_groups);
+}
+
+
+static void
+get_options(int *argc,char ***argv)
+{
+ int c,option_index;
+ my_bool tty_password=0;
+
+ while ((c=getopt_long(*argc,*argv,"c:h:p::u:#::P:S:Ck?VWi",long_options,
+ &option_index)) != EOF)
+ {
+ switch(c) {
+ case 'C':
+ opt_compress=1;
+ break;
+ case 'c':
+ charsets_dir= optarg;
+ break;
+ case 'h':
+ host = optarg;
+ break;
+ case 'i':
+ opt_status=1;
+ break;
+ case 'k':
+ opt_show_keys=1;
+ break;
+ case 'p':
+ if (optarg)
+ {
+ my_free(password,MYF(MY_ALLOW_ZERO_PTR));
+ password=my_strdup(optarg,MYF(MY_FAE));
+ while (*optarg) *optarg++= 'x'; /* Destroy argument */
+ }
+ else
+ tty_password=1;
+ break;
+#ifndef DONT_ALLOW_USER_CHANGE
+ case 'u':
+ user=optarg;
+ break;
+#endif
+ 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;
+#include "sslopt-case.h"
+ case '#':
+ DBUG_PUSH(optarg ? optarg : "d:t:o");
+ break;
+ case 'V':
+ print_version();
+ exit(0);
+ break;
+ default:
+ fprintf(stderr,"Illegal option character '%c'\n",opterr);
+ /* Fall throught */
+ case '?':
+ case 'I': /* Info */
+ usage();
+ exit(0);
+ }
+ }
+ (*argc)-=optind;
+ (*argv)+=optind;
+ if (tty_password)
+ password=get_tty_password(NullS);
+ return;
+}
+
+
+static int
+list_dbs(MYSQL *mysql,const char *wild)
+{
+ const char *header;
+ uint length;
+ MYSQL_FIELD *field;
+ MYSQL_RES *result;
+ MYSQL_ROW row;
+
+ if (!(result=mysql_list_dbs(mysql,wild)))
+ {
+ fprintf(stderr,"%s: Cannot list databases: %s\n",my_progname,
+ mysql_error(mysql));
+ return 1;
+ }
+ if (wild)
+ printf("Wildcard: %s\n",wild);
+
+ header="Databases";
+ length=strlen(header);
+ field=mysql_fetch_field(result);
+ if (length < field->max_length)
+ length=field->max_length;
+
+ print_header(header,length,NullS);
+ while ((row = mysql_fetch_row(result)))
+ print_row(row[0],length,0);
+ print_trailer(length,0);
+ mysql_free_result(result);
+ return 0;
+}
+
+
+static int
+list_tables(MYSQL *mysql,const char *db,const char *table)
+{
+ const char *header;
+ uint head_length;
+ MYSQL_FIELD *field;
+ MYSQL_RES *result;
+ MYSQL_ROW row;
+
+ if (mysql_select_db(mysql,db))
+ {
+ fprintf(stderr,"%s: Cannot connect to db %s: %s\n",my_progname,db,
+ mysql_error(mysql));
+ return 1;
+ }
+ if (!(result=mysql_list_tables(mysql,table)))
+ {
+ fprintf(stderr,"%s: Cannot list tables in %s: %s\n",my_progname,db,
+ mysql_error(mysql));
+ exit(1);
+ }
+ printf("Database: %s",db);
+ if (table)
+ printf(" Wildcard: %s",table);
+ putchar('\n');
+
+ header="Tables";
+ head_length=strlen(header);
+ field=mysql_fetch_field(result);
+ if (head_length < field->max_length)
+ head_length=field->max_length;
+
+ print_header(header,head_length,NullS);
+ while ((row = mysql_fetch_row(result)))
+ print_row(row[0],head_length,0);
+ print_trailer(head_length,0);
+ mysql_free_result(result);
+ return 0;
+}
+
+static int
+list_table_status(MYSQL *mysql,const char *db,const char *wild)
+{
+ char query[1024],*end;
+ MYSQL_RES *result;
+ MYSQL_ROW row;
+
+ end=strxmov(query,"show table status from ",db,NullS);
+ if (wild && wild[0])
+ strxmov(end," like '",wild,"'",NullS);
+ if (mysql_query(mysql,query) || !(result=mysql_store_result(mysql)))
+ {
+ fprintf(stderr,"%s: Cannot get status for db: %s, table: %s: %s\n",
+ my_progname,db,wild ? wild : "",mysql_error(mysql));
+ if (mysql_errno(mysql) == ER_PARSE_ERROR)
+ fprintf(stderr,"This error probably means that your MySQL server doesn't support the\n\'show table status' command.\n");
+ return 1;
+ }
+
+ printf("Database: %s",db);
+ if (wild)
+ printf(" Wildcard: %s",wild);
+ putchar('\n');
+
+ print_res_header(result);
+ while ((row=mysql_fetch_row(result)))
+ print_res_row(result,row);
+ print_res_top(result);
+ mysql_free_result(result);
+ return 0;
+}
+
+/*
+** list fields uses field interface as an example of how to parse
+** a MYSQL FIELD
+*/
+
+static int
+list_fields(MYSQL *mysql,const char *db,const char *table,
+ const char *wild)
+{
+ char query[1024],*end;
+ MYSQL_RES *result;
+ MYSQL_ROW row;
+
+ if (mysql_select_db(mysql,db))
+ {
+ fprintf(stderr,"%s: Cannot connect to db: %s: %s\n",my_progname,db,
+ mysql_error(mysql));
+ return 1;
+ }
+ end=strmov(strmov(query,"show columns from "),table);
+ if (wild && wild[0])
+ strxmov(end," like '",wild,"'",NullS);
+ if (mysql_query(mysql,query) || !(result=mysql_store_result(mysql)))
+ {
+ fprintf(stderr,"%s: Cannot list columns in db: %s, table: %s: %s\n",
+ my_progname,db,table,mysql_error(mysql));
+ return 1;
+ }
+
+ printf("Database: %s Table: %s Rows: %lu", db,table,
+ (ulong) mysql->extra_info);
+ if (wild && wild[0])
+ printf(" Wildcard: %s",wild);
+ putchar('\n');
+
+ print_res_header(result);
+ while ((row=mysql_fetch_row(result)))
+ print_res_row(result,row);
+ print_res_top(result);
+ if (opt_show_keys)
+ {
+ end=strmov(strmov(query,"show keys from "),table);
+ if (mysql_query(mysql,query) || !(result=mysql_store_result(mysql)))
+ {
+ fprintf(stderr,"%s: Cannot list keys in db: %s, table: %s: %s\n",
+ my_progname,db,table,mysql_error(mysql));
+ return 1;
+ }
+ if (mysql_num_rows(result))
+ {
+ print_res_header(result);
+ while ((row=mysql_fetch_row(result)))
+ print_res_row(result,row);
+ print_res_top(result);
+ }
+ else
+ puts("Table has no keys");
+ }
+ mysql_free_result(result);
+ return 0;
+}
+
+
+/*****************************************************************************
+** General functions to print a nice ascii-table from data
+*****************************************************************************/
+
+static void
+print_header(const char *header,uint head_length,...)
+{
+ va_list args;
+ uint length,i,str_length,pre_space;
+ const char *field;
+
+ va_start(args,head_length);
+ putchar('+');
+ field=header; length=head_length;
+ for (;;)
+ {
+ for (i=0 ; i < length+2 ; i++)
+ putchar('-');
+ putchar('+');
+ if (!(field=va_arg(args,my_string)))
+ break;
+ length=va_arg(args,uint);
+ }
+ va_end(args);
+ putchar('\n');
+
+ va_start(args,head_length);
+ field=header; length=head_length;
+ putchar('|');
+ for (;;)
+ {
+ str_length=strlen(field);
+ if (str_length > length)
+ str_length=length+1;
+ pre_space=(uint) (((int) length-(int) str_length)/2)+1;
+ for (i=0 ; i < pre_space ; i++)
+ putchar(' ');
+ for (i = 0 ; i < str_length ; i++)
+ putchar(field[i]);
+ length=length+2-str_length-pre_space;
+ for (i=0 ; i < length ; i++)
+ putchar(' ');
+ putchar('|');
+ if (!(field=va_arg(args,my_string)))
+ break;
+ length=va_arg(args,uint);
+ }
+ va_end(args);
+ putchar('\n');
+
+ va_start(args,head_length);
+ putchar('+');
+ field=header; length=head_length;
+ for (;;)
+ {
+ for (i=0 ; i < length+2 ; i++)
+ putchar('-');
+ putchar('+');
+ if (!(field=va_arg(args,my_string)))
+ break;
+ length=va_arg(args,uint);
+ }
+ va_end(args);
+ putchar('\n');
+}
+
+
+static void
+print_row(const char *header,uint head_length,...)
+{
+ va_list args;
+ const char *field;
+ uint i,length,field_length;
+
+ va_start(args,head_length);
+ field=header; length=head_length;
+ for (;;)
+ {
+ putchar('|');
+ putchar(' ');
+ fputs(field,stdout);
+ field_length=strlen(field);
+ for (i=field_length ; i <= length ; i++)
+ putchar(' ');
+ if (!(field=va_arg(args,my_string)))
+ break;
+ length=va_arg(args,uint);
+ }
+ va_end(args);
+ putchar('|');
+ putchar('\n');
+}
+
+
+static void
+print_trailer(uint head_length,...)
+{
+ va_list args;
+ uint length,i;
+
+ va_start(args,head_length);
+ length=head_length;
+ putchar('+');
+ for (;;)
+ {
+ for (i=0 ; i < length+2 ; i++)
+ putchar('-');
+ putchar('+');
+ if (!(length=va_arg(args,uint)))
+ break;
+ }
+ va_end(args);
+ putchar('\n');
+}
+
+
+static void print_res_header(MYSQL_RES *result)
+{
+ MYSQL_FIELD *field;
+
+ print_res_top(result);
+ mysql_field_seek(result,0);
+ putchar('|');
+ while ((field = mysql_fetch_field(result)))
+ {
+ printf(" %-*s|",field->max_length+1,field->name);
+ }
+ putchar('\n');
+ print_res_top(result);
+}
+
+
+static void print_res_top(MYSQL_RES *result)
+{
+ uint i,length;
+ MYSQL_FIELD *field;
+
+ putchar('+');
+ mysql_field_seek(result,0);
+ while((field = mysql_fetch_field(result)))
+ {
+ if ((length=strlen(field->name)) > field->max_length)
+ field->max_length=length;
+ else
+ length=field->max_length;
+ for (i=length+2 ; i--> 0 ; )
+ putchar('-');
+ putchar('+');
+ }
+ putchar('\n');
+}
+
+
+static void print_res_row(MYSQL_RES *result,MYSQL_ROW cur)
+{
+ uint i,length;
+ MYSQL_FIELD *field;
+ putchar('|');
+ mysql_field_seek(result,0);
+ for (i=0 ; i < mysql_num_fields(result); i++)
+ {
+ field = mysql_fetch_field(result);
+ length=field->max_length;
+ printf(" %-*s|",length+1,cur[i] ? (char*) cur[i] : "");
+ }
+ putchar('\n');
+}
diff --git a/client/password.c b/client/password.c
new file mode 100644
index 00000000000..0fd5861873a
--- /dev/null
+++ b/client/password.c
@@ -0,0 +1,192 @@
+/* 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 */
+
+/* password checking routines */
+/*****************************************************************************
+ The main idea is that no password are sent between client & server on
+ connection and that no password are saved in mysql in a decodable form.
+
+ On connection a random string is generated and sent to the client.
+ The client generates a new string with a random generator inited with
+ the hash values from the password and the sent string.
+ This 'check' string is sent to the server where it is compared with
+ a string generated from the stored hash_value of the password and the
+ random string.
+
+ The password is saved (in user.password) by using the PASSWORD() function in
+ mysql.
+
+ Example:
+ update user set password=PASSWORD("hello") where user="test"
+ This saves a hashed number as a string in the password field.
+*****************************************************************************/
+
+#include <global.h>
+#include <my_sys.h>
+#include <m_string.h>
+#include "mysql.h"
+
+
+void randominit(struct rand_struct *rand_st,ulong seed1, ulong seed2)
+{ /* For mysql 3.21.# */
+#ifdef HAVE_purify
+ bzero((char*) rand_st,sizeof(*rand_st)); /* Avoid UMC varnings */
+#endif
+ rand_st->max_value= 0x3FFFFFFFL;
+ rand_st->max_value_dbl=(double) rand_st->max_value;
+ rand_st->seed1=seed1%rand_st->max_value ;
+ rand_st->seed2=seed2%rand_st->max_value;
+}
+
+static void old_randominit(struct rand_struct *rand_st,ulong seed1)
+{ /* For mysql 3.20.# */
+ rand_st->max_value= 0x01FFFFFFL;
+ rand_st->max_value_dbl=(double) rand_st->max_value;
+ seed1%=rand_st->max_value;
+ rand_st->seed1=seed1 ; rand_st->seed2=seed1/2;
+}
+
+double rnd(struct rand_struct *rand_st)
+{
+ rand_st->seed1=(rand_st->seed1*3+rand_st->seed2) % rand_st->max_value;
+ rand_st->seed2=(rand_st->seed1+rand_st->seed2+33) % rand_st->max_value;
+ return (((double) rand_st->seed1)/rand_st->max_value_dbl);
+}
+
+void hash_password(ulong *result, const char *password)
+{
+ register ulong nr=1345345333L, add=7, nr2=0x12345671L;
+ ulong tmp;
+ for (; *password ; password++)
+ {
+ if (*password == ' ' || *password == '\t')
+ continue; /* skipp space in password */
+ tmp= (ulong) (uchar) *password;
+ nr^= (((nr & 63)+add)*tmp)+ (nr << 8);
+ nr2+=(nr2 << 8) ^ nr;
+ add+=tmp;
+ }
+ result[0]=nr & (((ulong) 1L << 31) -1L); /* Don't use sign bit (str2int) */;
+ result[1]=nr2 & (((ulong) 1L << 31) -1L);
+ return;
+}
+
+void make_scrambled_password(char *to,const char *password)
+{
+ ulong hash_res[2];
+ hash_password(hash_res,password);
+ sprintf(to,"%08lx%08lx",hash_res[0],hash_res[1]);
+}
+
+static inline uint char_val(char X)
+{
+ return (uint) (X >= '0' && X <= '9' ? X-'0' :
+ X >= 'A' && X <= 'Z' ? X-'A'+10 :
+ X-'a'+10);
+}
+
+/*
+** This code assumes that len(password) is divideable with 8 and that
+** res is big enough (2 in mysql)
+*/
+
+void get_salt_from_password(ulong *res,const char *password)
+{
+ res[0]=res[1]=0;
+ if (password)
+ {
+ while (*password)
+ {
+ ulong val=0;
+ uint i;
+ for (i=0 ; i < 8 ; i++)
+ val=(val << 4)+char_val(*password++);
+ *res++=val;
+ }
+ }
+ return;
+}
+
+void make_password_from_salt(char *to, ulong *hash_res)
+{
+ sprintf(to,"%08lx%08lx",hash_res[0],hash_res[1]);
+}
+
+
+/*
+ * Genererate a new message based on message and password
+ * The same thing is done in client and server and the results are checked.
+ */
+
+char *scramble(char *to,const char *message,const char *password,
+ my_bool old_ver)
+{
+ struct rand_struct rand_st;
+ ulong hash_pass[2],hash_message[2];
+ if (password && password[0])
+ {
+ char *to_start=to;
+ hash_password(hash_pass,password);
+ hash_password(hash_message,message);
+ if (old_ver)
+ old_randominit(&rand_st,hash_pass[0] ^ hash_message[0]);
+ else
+ randominit(&rand_st,hash_pass[0] ^ hash_message[0],
+ hash_pass[1] ^ hash_message[1]);
+ while (*message++)
+ *to++= (char) (floor(rnd(&rand_st)*31)+64);
+ if (!old_ver)
+ { /* Make it harder to break */
+ char extra=(char) (floor(rnd(&rand_st)*31));
+ while (to_start != to)
+ *(to_start++)^=extra;
+ }
+ }
+ *to=0;
+ return to;
+}
+
+
+my_bool check_scramble(const char *scrambled, const char *message,
+ ulong *hash_pass, my_bool old_ver)
+{
+ struct rand_struct rand_st;
+ ulong hash_message[2];
+ char buff[16],*to,extra; /* Big enough for check */
+ const char *pos;
+
+ hash_password(hash_message,message);
+ if (old_ver)
+ old_randominit(&rand_st,hash_pass[0] ^ hash_message[0]);
+ else
+ randominit(&rand_st,hash_pass[0] ^ hash_message[0],
+ hash_pass[1] ^ hash_message[1]);
+ to=buff;
+ for (pos=scrambled ; *pos ; pos++)
+ *to++=(char) (floor(rnd(&rand_st)*31)+64);
+ if (old_ver)
+ extra=0;
+ else
+ extra=(char) (floor(rnd(&rand_st)*31));
+ to=buff;
+ while (*scrambled)
+ {
+ if (*scrambled++ != (char) (*to++ ^ extra))
+ return 1; /* Wrong password */
+ }
+ return 0;
+}
diff --git a/client/readline.cc b/client/readline.cc
new file mode 100644
index 00000000000..95e98cb90c2
--- /dev/null
+++ b/client/readline.cc
@@ -0,0 +1,216 @@
+/* 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 */
+
+/* readline for batch mode */
+
+#include <global.h>
+#include <my_sys.h>
+#include <m_string.h>
+#include "my_readline.h"
+
+static bool init_line_buffer(LINE_BUFFER *buffer,File file,ulong size,
+ ulong max_size);
+static bool init_line_buffer_from_string(LINE_BUFFER *buffer,my_string str);
+static uint fill_buffer(LINE_BUFFER *buffer);
+static char *intern_read_line(LINE_BUFFER *buffer,uint *out_length);
+
+
+LINE_BUFFER *batch_readline_init(ulong max_size,FILE *file)
+{
+ LINE_BUFFER *line_buff;
+ if (!(line_buff=(LINE_BUFFER*) my_malloc(sizeof(*line_buff),MYF(MY_WME))))
+ return 0;
+ if (init_line_buffer(line_buff,fileno(file),IO_SIZE,max_size))
+ {
+ my_free((char*) line_buff,MYF(0));
+ return 0;
+ }
+ return line_buff;
+}
+
+
+char *batch_readline(LINE_BUFFER *line_buff)
+{
+ char *pos;
+ uint out_length;
+
+ if (!(pos=intern_read_line(line_buff,&out_length)))
+ return 0;
+ if (out_length && pos[out_length-1] == '\n')
+ out_length--; /* Remove '\n' */
+ pos[out_length]=0;
+ return pos;
+}
+
+
+void batch_readline_end(LINE_BUFFER *line_buff)
+{
+ if (line_buff)
+ {
+ my_free((gptr) line_buff->buffer,MYF(MY_ALLOW_ZERO_PTR));
+ my_free((char*) line_buff,MYF(0));
+ }
+}
+
+
+LINE_BUFFER *batch_readline_command(my_string str)
+{
+ LINE_BUFFER *line_buff;
+ if (!(line_buff=(LINE_BUFFER*) my_malloc(sizeof(*line_buff),MYF(MY_WME))))
+ return 0;
+ if (init_line_buffer_from_string(line_buff,str))
+ {
+ my_free((char*) line_buff,MYF(0));
+ return 0;
+ }
+ return line_buff;
+}
+
+
+/*****************************************************************************
+ Functions to handle buffered readings of lines from a stream
+******************************************************************************/
+
+static bool
+init_line_buffer(LINE_BUFFER *buffer,File file,ulong size,ulong max_buffer)
+{
+ bzero((char*) buffer,sizeof(buffer[0]));
+ buffer->file=file;
+ buffer->bufread=size;
+ buffer->max_size=max_buffer;
+ if (!(buffer->buffer = (char*) my_malloc(buffer->bufread+1,
+ MYF(MY_WME | MY_FAE))))
+ return 1;
+ buffer->end_of_line=buffer->end=buffer->buffer;
+ buffer->buffer[0]=0; /* For easy start test */
+ return 0;
+}
+
+
+static bool init_line_buffer_from_string(LINE_BUFFER *buffer,my_string str)
+{
+ uint length;
+ bzero((char*) buffer,sizeof(buffer[0]));
+ length=strlen(str);
+ if (!(buffer->buffer=buffer->start_of_line=buffer->end_of_line=
+ (char*)my_malloc(length+2,MYF(MY_FAE))))
+ return 1;
+ memcpy(buffer->buffer,str,length);
+ buffer->buffer[length]='\n';
+ buffer->buffer[length+1]=0;
+ buffer->end=buffer->buffer+length+1;
+ buffer->eof=1;
+ buffer->max_size=1;
+ return 0;
+}
+
+
+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. */
+
+
+static uint fill_buffer(LINE_BUFFER *buffer)
+{
+ uint read_count;
+ uint bufbytes= (uint) (buffer->end - buffer->start_of_line);
+
+ if (buffer->eof)
+ return 0; /* Everything read */
+
+ /* See if we need to grow the buffer. */
+
+ for (;;)
+ {
+ uint start_offset=(uint) (buffer->start_of_line - buffer->buffer);
+ read_count=(buffer->bufread - bufbytes)/IO_SIZE;
+ if ((read_count*=IO_SIZE))
+ break;
+ buffer->bufread *= 2;
+ if (!(buffer->buffer = (char*) my_realloc(buffer->buffer,
+ buffer->bufread+1,
+ MYF(MY_WME | MY_FAE))))
+ return (uint) -1;
+ buffer->start_of_line=buffer->buffer+start_offset;
+ buffer->end=buffer->buffer+bufbytes;
+ }
+
+ /* Shift stuff down. */
+ if (buffer->start_of_line != buffer->buffer)
+ {
+ bmove(buffer->buffer,buffer->start_of_line,(uint) bufbytes);
+ buffer->end=buffer->buffer+bufbytes;
+ }
+
+ /* Read in new stuff. */
+ if ((read_count= my_read(buffer->file, (byte*) buffer->end, read_count,
+ MYF(MY_WME))) == MY_FILE_ERROR)
+ return read_count;
+
+ DBUG_PRINT("fill_buff", ("Got %d bytes", read_count));
+
+ /* Kludge to pretend every nonempty file ends with a newline. */
+ if (!read_count && bufbytes && buffer->end[-1] != '\n')
+ {
+ buffer->eof = read_count = 1;
+ *buffer->end = '\n';
+ }
+ buffer->end_of_line=(buffer->start_of_line=buffer->buffer)+bufbytes;
+ buffer->end+=read_count;
+ *buffer->end=0; /* Sentinel */
+ return read_count;
+}
+
+
+
+char *intern_read_line(LINE_BUFFER *buffer,uint *out_length)
+{
+ char *pos;
+ uint length;
+ DBUG_ENTER("intern_read_line");
+
+ buffer->start_of_line=buffer->end_of_line;
+ for (;;)
+ {
+ pos=buffer->end_of_line;
+ while (*pos != '\n' && *pos)
+ pos++;
+ if (pos == buffer->end)
+ {
+ if ((uint) (pos - buffer->start_of_line) < buffer->max_size)
+ {
+ if (!(length=fill_buffer(buffer)) || length == (uint) -1)
+ DBUG_RETURN(0);
+ continue;
+ }
+ pos--; /* break line here */
+ }
+ buffer->end_of_line=pos+1;
+ *out_length=(uint) (pos + 1 - buffer->eof - buffer->start_of_line);
+ DBUG_RETURN(buffer->start_of_line);
+ }
+}
diff --git a/client/select_test.c b/client/select_test.c
new file mode 100644
index 00000000000..049f2b908be
--- /dev/null
+++ b/client/select_test.c
@@ -0,0 +1,75 @@
+/* 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 */
+
+
+#if defined(_WIN32) || defined(_WIN64)
+#include <windows.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include "mysql.h"
+
+#define SELECT_QUERY "select name from test where num = %d"
+
+
+int main(int argc, char **argv)
+{
+ int count, num;
+ MYSQL mysql,*sock;
+ MYSQL_RES *res;
+ char qbuf[160];
+
+ if (argc != 3)
+ {
+ fprintf(stderr,"usage : select_test <dbname> <num>\n\n");
+ exit(1);
+ }
+
+ mysql_init(&mysql);
+ if (!(sock = mysql_real_connect(&mysql,NULL,0,0,argv[1],0,NULL,0)))
+ {
+ fprintf(stderr,"Couldn't connect to engine!\n%s\n\n",mysql_error(&mysql));
+ perror("");
+ exit(1);
+ }
+
+ count = 0;
+ num = atoi(argv[2]);
+ while (count < num)
+ {
+ sprintf(qbuf,SELECT_QUERY,count);
+ if(mysql_query(sock,qbuf))
+ {
+ fprintf(stderr,"Query failed (%s)\n",mysql_error(sock));
+ exit(1);
+ }
+ if (!(res=mysql_store_result(sock)))
+ {
+ fprintf(stderr,"Couldn't get result from %s\n",
+ mysql_error(sock));
+ exit(1);
+ }
+#ifdef TEST
+ printf("number of fields: %d\n",mysql_num_fields(res));
+#endif
+ mysql_free_result(res);
+ count++;
+ }
+ mysql_close(sock);
+ exit(0);
+ return 0; /* Keep some compilers happy */
+}
diff --git a/client/showdb_test.c b/client/showdb_test.c
new file mode 100644
index 00000000000..f4c25999fe5
--- /dev/null
+++ b/client/showdb_test.c
@@ -0,0 +1,80 @@
+/* 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 program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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
+#include <stdio.h>
+#include <stdlib.h>
+#include "mysql.h"
+
+#define SELECT_QUERY "select name from test where num = %d"
+
+
+int main(int argc, char **argv)
+{
+ int count, num;
+ MYSQL mysql,*sock;
+ MYSQL_RES *res;
+ char qbuf[160];
+
+ if (argc != 3)
+ {
+ fprintf(stderr,"usage : select_test <dbname> <num>\n\n");
+ exit(1);
+ }
+
+ mysql_init(&mysql);
+ if (!(sock = mysql_real_connect(&mysql,NULL,0,0,argv[1],0,NULL,0)))
+ {
+ fprintf(stderr,"Couldn't connect to engine!\n%s\n\n",mysql_error(&mysql));
+ perror("");
+ exit(1);
+ }
+
+ count = 0;
+ num = atoi(argv[2]);
+ while (count < num)
+ {
+ sprintf(qbuf,SELECT_QUERY,count);
+ if(!(res=mysql_list_dbs(sock,NULL)))
+ {
+ fprintf(stderr,"Query failed (%s)\n",mysql_error(sock));
+ exit(1);
+ }
+ printf("number of fields: %d\n",mysql_num_rows(res));
+ mysql_free_result(res);
+ count++;
+ }
+ mysql_close(sock);
+ exit(0);
+ return 0; /* Keep some compilers happy */
+}
diff --git a/client/sql_string.cc b/client/sql_string.cc
new file mode 100644
index 00000000000..5c3e1068649
--- /dev/null
+++ b/client/sql_string.cc
@@ -0,0 +1,728 @@
+/* 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 originally from the mysql distribution. Coded by monty */
+
+#ifdef __GNUC__
+#pragma implementation // gcc: Class implementation
+#endif
+
+#include <global.h>
+#include <my_sys.h>
+#include <m_string.h>
+#include <m_ctype.h>
+#ifdef HAVE_FCONVERT
+#include <floatingpoint.h>
+#endif
+
+extern gptr sql_alloc(unsigned size);
+extern void sql_element_free(void *ptr);
+
+#include "sql_string.h"
+
+/*****************************************************************************
+** String functions
+*****************************************************************************/
+
+bool String::real_alloc(uint32 arg_length)
+{
+ arg_length=ALIGN_SIZE(arg_length+1);
+ if (Alloced_length < arg_length)
+ {
+ free();
+ if (!(Ptr=(char*) my_malloc(arg_length,MYF(MY_WME))))
+ {
+ str_length=0;
+ return TRUE;
+ }
+ Alloced_length=arg_length;
+ alloced=1;
+ }
+ Ptr[0]=0;
+ str_length=0;
+ return FALSE;
+}
+
+
+/*
+** Check that string is big enough. Set string[alloc_length] to 0
+** (for C functions)
+*/
+
+bool String::realloc(uint32 alloc_length)
+{
+ uint32 len=ALIGN_SIZE(alloc_length+1);
+ if (Alloced_length < len)
+ {
+ char *new_ptr;
+ if (alloced)
+ {
+ if ((new_ptr= (char*) my_realloc(Ptr,len,MYF(MY_WME))))
+ {
+ Ptr=new_ptr;
+ Alloced_length=len;
+ }
+ else
+ return TRUE; // Signal error
+ }
+ else if ((new_ptr= (char*) my_malloc(len,MYF(MY_WME))))
+ {
+ memcpy(new_ptr,Ptr,str_length);
+ new_ptr[str_length]=0;
+ Ptr=new_ptr;
+ Alloced_length=len;
+ alloced=1;
+ }
+ else
+ return TRUE; // Signal error
+ }
+ Ptr[alloc_length]=0; // This make other funcs shorter
+ return FALSE;
+}
+
+
+#ifdef NOT_NEEDED
+bool String::set(long num)
+{
+ if (alloc(14))
+ return TRUE;
+ str_length=(uint32) (int10_to_str(num,Ptr,-10)-Ptr);
+ return FALSE;
+}
+#endif
+
+bool String::set(longlong num)
+{
+ if (alloc(21))
+ return TRUE;
+ str_length=(uint32) (longlong10_to_str(num,Ptr,-10)-Ptr);
+ return FALSE;
+}
+
+bool String::set(ulonglong num)
+{
+ if (alloc(21))
+ return TRUE;
+ str_length=(uint32) (longlong10_to_str(num,Ptr,10)-Ptr);
+ return FALSE;
+}
+
+bool String::set(double num,uint decimals)
+{
+ char buff[331];
+ if (decimals >= NOT_FIXED_DEC)
+ {
+ sprintf(buff,"%.14g",num); // Enough for a DATETIME
+ return copy(buff,strlen(buff));
+ }
+#ifdef HAVE_FCONVERT
+ int decpt,sign;
+ char *pos,*to;
+
+ VOID(fconvert(num,(int) decimals,&decpt,&sign,buff+1));
+ if (!isdigit(buff[1]))
+ { // Nan or Inf
+ pos=buff+1;
+ if (sign)
+ {
+ buff[0]='-';
+ pos=buff;
+ }
+ return copy(pos,strlen(pos));
+ }
+ if (alloc((uint32) ((uint32) decpt+3+decimals)))
+ return TRUE;
+ to=Ptr;
+ if (sign)
+ *to++='-';
+
+ pos=buff+1;
+ if (decpt < 0)
+ { /* value is < 0 */
+ *to++='0';
+ if (!decimals)
+ goto end;
+ *to++='.';
+ if ((uint32) -decpt > decimals)
+ decpt= - (int) decimals;
+ decimals=(uint32) ((int) decimals+decpt);
+ while (decpt++ < 0)
+ *to++='0';
+ }
+ else if (decpt == 0)
+ {
+ *to++= '0';
+ if (!decimals)
+ goto end;
+ *to++='.';
+ }
+ else
+ {
+ while (decpt-- > 0)
+ *to++= *pos++;
+ if (!decimals)
+ goto end;
+ *to++='.';
+ }
+ while (decimals--)
+ *to++= *pos++;
+
+end:
+ *to=0;
+ str_length=(uint32) (to-Ptr);
+ return FALSE;
+#else
+#ifdef HAVE_SNPRINTF_
+ snprintf(buff,sizeof(buff), "%.*f",(int) decimals,num);
+#else
+ sprintf(buff,"%.*f",(int) decimals,num);
+#endif
+ return copy(buff,strlen(buff));
+#endif
+}
+
+
+bool String::copy()
+{
+ if (!alloced)
+ {
+ Alloced_length=0; // Force realloc
+ return realloc(str_length);
+ }
+ return FALSE;
+}
+
+bool String::copy(const String &str)
+{
+ if (alloc(str.str_length))
+ return TRUE;
+ str_length=str.str_length;
+ bmove(Ptr,str.Ptr,str_length); // May be overlapping
+ Ptr[str_length]=0;
+ return FALSE;
+}
+
+bool String::copy(const char *str,uint32 arg_length)
+{
+ if (alloc(arg_length))
+ return TRUE;
+ str_length=arg_length;
+ memcpy(Ptr,str,arg_length);
+ Ptr[arg_length]=0;
+ return FALSE;
+}
+
+/* This is used by mysql.cc */
+
+bool String::fill(uint32 max_length,char fill_char)
+{
+ if (str_length > max_length)
+ Ptr[str_length=max_length]=0;
+ else
+ {
+ if (realloc(max_length))
+ return TRUE;
+ bfill(Ptr+str_length,max_length-str_length,fill_char);
+ str_length=max_length;
+ }
+ return FALSE;
+}
+
+void String::strip_sp()
+{
+ while (str_length && isspace(Ptr[str_length-1]))
+ str_length--;
+}
+
+bool String::append(const String &s)
+{
+ if (realloc(str_length+s.length()))
+ return TRUE;
+ memcpy(Ptr+str_length,s.ptr(),s.length());
+ str_length+=s.length();
+ return FALSE;
+}
+
+bool String::append(const char *s,uint32 arg_length)
+{
+ if (!arg_length) // Default argument
+ arg_length=strlen(s);
+ if (realloc(str_length+arg_length))
+ return TRUE;
+ memcpy(Ptr+str_length,s,arg_length);
+ str_length+=arg_length;
+ return FALSE;
+}
+
+uint32 String::numchars()
+{
+#ifdef USE_MB
+ register uint32 n=0,mblen;
+ register const char *mbstr=Ptr;
+ register const char *end=mbstr+str_length;
+ if (use_mb(default_charset_info))
+ {
+ while (mbstr < end) {
+ if ((mblen=my_ismbchar(default_charset_info, mbstr,end))) mbstr+=mblen;
+ else ++mbstr;
+ ++n;
+ }
+ return n;
+ }
+ else
+#endif
+ return str_length;
+}
+
+int String::charpos(int i,uint32 offset)
+{
+#ifdef USE_MB
+ register uint32 mblen;
+ register const char *mbstr=Ptr+offset;
+ register const char *end=Ptr+str_length;
+ if (use_mb(default_charset_info))
+ {
+ if (i<=0) return i;
+ while (i && mbstr < end) {
+ if ((mblen=my_ismbchar(default_charset_info, mbstr,end))) mbstr+=mblen;
+ else ++mbstr;
+ --i;
+ }
+ if ( INT_MAX32-i <= (int) (mbstr-Ptr-offset))
+ return INT_MAX32;
+ else
+ return (mbstr-Ptr-offset)+i;
+ }
+ else
+#endif
+ return i;
+}
+
+int String::strstr(const String &s,uint32 offset)
+{
+ if (s.length()+offset <= str_length)
+ {
+ if (!s.length())
+ return 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 (*str++ == *search)
+ {
+ register char *i,*j;
+ i=(char*) str; j=(char*) search+1;
+ while (j != search_end)
+ if (*i++ != *j++) goto skipp;
+ return (int) (str-Ptr) -1;
+ }
+ }
+ }
+ return -1;
+}
+
+
+/*
+** Search string from end. Offset is offset to the end of string
+*/
+
+int String::strrstr(const String &s,uint32 offset)
+{
+ if (s.length() <= offset && offset <= str_length)
+ {
+ if (!s.length())
+ return offset; // Empty string is always found
+ register const char *str = Ptr+offset-1;
+ register const char *search=s.ptr()+s.length()-1;
+
+ const char *end=Ptr+s.length()-2;
+ const char *search_end=s.ptr()-1;
+skipp:
+ while (str != end)
+ {
+ if (*str-- == *search)
+ {
+ register char *i,*j;
+ i=(char*) str; j=(char*) search-1;
+ while (j != search_end)
+ if (*i-- != *j--) goto skipp;
+ return (int) (i-Ptr) +1;
+ }
+ }
+ }
+ return -1;
+}
+
+/*
+** replace substring with string
+** If wrong parameter or not enough memory, do nothing
+*/
+
+
+bool String::replace(uint32 offset,uint32 arg_length,const String &to)
+{
+ long diff = (long) to.length()-(long) arg_length;
+ if (offset+arg_length <= str_length)
+ {
+ if (diff < 0)
+ {
+ memcpy(Ptr+offset,to.ptr(),to.length());
+ bmove(Ptr+offset+to.length(),Ptr+offset+arg_length,
+ str_length-offset-arg_length);
+ }
+ else
+ {
+ if (diff)
+ {
+ if (realloc(str_length+(uint32) diff))
+ return TRUE;
+ bmove_upp(Ptr+str_length+diff,Ptr+str_length,
+ str_length-offset-arg_length);
+ }
+ memcpy(Ptr+offset,to.ptr(),to.length());
+ }
+ str_length+=(uint32) diff;
+ }
+ return FALSE;
+}
+
+
+int sortcmp(const String *x,const String *y)
+{
+ const char *s= x->ptr();
+ const char *t= y->ptr();
+ uint32 x_len=x->length(),y_len=y->length(),len=min(x_len,y_len);
+
+#ifdef USE_STRCOLL
+ if (use_strcoll(default_charset_info))
+ {
+#ifndef CMP_ENDSPACE
+ while (x_len && isspace(s[x_len-1]))
+ x_len--;
+ while (y_len && isspace(t[y_len-1]))
+ y_len--;
+#endif
+ return my_strnncoll(default_charset_info,
+ (unsigned char *)s,x_len,(unsigned char *)t,y_len);
+ }
+ else
+ {
+#endif /* USE_STRCOLL */
+ x_len-=len; // For easy end space test
+ y_len-=len;
+ while (len--)
+ {
+ if (my_sort_order[(uchar) *s++] != my_sort_order[(uchar) *t++])
+ return ((int) my_sort_order[(uchar) s[-1]] -
+ (int) my_sort_order[(uchar) t[-1]]);
+ }
+#ifndef CMP_ENDSPACE
+ /* Don't compare end space in strings */
+ {
+ if (y_len)
+ {
+ const char *end=t+y_len;
+ for (; t != end ; t++)
+ if (!isspace(*t))
+ return -1;
+ }
+ else
+ {
+ const char *end=s+x_len;
+ for (; s != end ; s++)
+ if (!isspace(*s))
+ return 1;
+ }
+ return 0;
+ }
+#else
+ return (int) (x_len-y_len);
+#endif /* CMP_ENDSPACE */
+#ifdef USE_STRCOLL
+ }
+#endif
+}
+
+
+int stringcmp(const String *x,const String *y)
+{
+ const char *s= x->ptr();
+ const char *t= y->ptr();
+ uint32 x_len=x->length(),y_len=y->length(),len=min(x_len,y_len);
+
+ while (len--)
+ {
+ if (*s++ != *t++)
+ return ((int) (uchar) s[-1] - (int) (uchar) t[-1]);
+ }
+ return (int) (x_len-y_len);
+}
+
+
+String *copy_if_not_alloced(String *to,String *from,uint32 from_length)
+{
+ if (from->Alloced_length >= from_length)
+ return from;
+ if (from->alloced || !to || from == to)
+ {
+ (void) from->realloc(from_length);
+ return from;
+ }
+ if (to->realloc(from_length))
+ return from; // Actually an error
+ to->str_length=min(from->str_length,from_length);
+ memcpy(to->Ptr,from->Ptr,to->str_length);
+ return to;
+}
+
+/* Make it easier to handle different charactersets */
+
+#ifdef USE_MB
+#define INC_PTR(A,B) A+=((use_mb_flag && \
+ my_ismbchar(default_charset_info,A,B)) ? \
+ my_ismbchar(default_charset_info,A,B) : 1)
+#else
+#define INC_PTR(A,B) A++
+#endif
+
+/*
+** Compare string against string with wildcard
+** 0 if matched
+** -1 if not matched with wildcard
+** 1 if matched with wildcard
+*/
+
+#ifdef LIKE_CMP_TOUPPER
+#define likeconv(A) (uchar) toupper(A)
+#else
+#define likeconv(A) (uchar) my_sort_order[(uchar) (A)]
+#endif
+
+static int wild_case_compare(const char *str,const char *str_end,
+ const char *wildstr,const char *wildend,
+ char escape)
+{
+ int result= -1; // Not found, using wildcards
+#ifdef USE_MB
+ bool use_mb_flag=use_mb(default_charset_info);
+#endif
+ while (wildstr != wildend)
+ {
+ while (*wildstr != wild_many && *wildstr != wild_one)
+ {
+ if (*wildstr == escape && wildstr+1 != wildend)
+ wildstr++;
+#ifdef USE_MB
+ int l;
+ if (use_mb_flag &&
+ (l = my_ismbchar(default_charset_info, wildstr, wildend)))
+ {
+ if (str+l > str_end || memcmp(str, wildstr, l) != 0)
+ return 1;
+ str += l;
+ wildstr += l;
+ }
+ else
+#endif
+ if (str == str_end || likeconv(*wildstr++) != likeconv(*str++))
+ return(1); // No match
+ if (wildstr == wildend)
+ 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);
+ INC_PTR(str,str_end);
+ } while (++wildstr < wildend && *wildstr == wild_one);
+ if (wildstr == wildend)
+ break;
+ }
+ if (*wildstr == wild_many)
+ { // Found wild_many
+ wildstr++;
+ /* Remove any '%' and '_' from the wild search string */
+ for ( ; wildstr != wildend ; wildstr++)
+ {
+ if (*wildstr == wild_many)
+ continue;
+ if (*wildstr == wild_one)
+ {
+ if (str == str_end)
+ return (-1);
+ INC_PTR(str,str_end);
+ continue;
+ }
+ break; // Not a wild character
+ }
+ if (wildstr == wildend)
+ return(0); // Ok if wild_many is last
+ if (str == str_end)
+ return -1;
+
+ uchar cmp;
+ if ((cmp= *wildstr) == escape && wildstr+1 != wildend)
+ cmp= *++wildstr;
+#ifdef USE_MB
+ const char* mb = wildstr;
+ int mblen;
+ if (use_mb_flag)
+ mblen = my_ismbchar(default_charset_info, wildstr, wildend);
+#endif
+ INC_PTR(wildstr,wildend); // This is compared trough cmp
+ cmp=likeconv(cmp);
+ do
+ {
+#ifdef USE_MB
+ if (use_mb_flag)
+ {
+ for (;;)
+ {
+ if (str >= str_end)
+ return -1;
+ if (mblen)
+ {
+ if (str+mblen <= str_end && memcmp(str, mb, mblen) == 0)
+ {
+ str += mblen;
+ break;
+ }
+ }
+ else if (!my_ismbchar(default_charset_info, str, str_end) &&
+ likeconv(*str) == cmp)
+ {
+ str++;
+ break;
+ }
+ INC_PTR(str, str_end);
+ }
+ }
+ else
+ {
+#endif /* USE_MB */
+ while (str != str_end && likeconv(*str) != cmp)
+ str++;
+ if (str++ == str_end) return (-1);
+#ifdef USE_MB
+ }
+#endif
+ {
+ int tmp=wild_case_compare(str,str_end,wildstr,wildend,escape);
+ if (tmp <= 0)
+ return (tmp);
+ }
+ } while (str != str_end && wildstr[0] != wild_many);
+ return(-1);
+ }
+ }
+ return (str != str_end ? 1 : 0);
+}
+
+
+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);
+}
+
+/*
+** The following is used when using LIKE on binary strings
+*/
+
+static int wild_compare(const char *str,const char *str_end,
+ const char *wildstr,const char *wildend,char escape)
+{
+ int result= -1; // Not found, using wildcards
+ while (wildstr != wildend)
+ {
+ while (*wildstr != wild_many && *wildstr != wild_one)
+ {
+ if (*wildstr == escape && wildstr+1 != wildend)
+ wildstr++;
+ if (str == str_end || *wildstr++ != *str++)
+ return(1);
+ if (wildstr == wildend)
+ 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);
+ str++;
+ } while (*++wildstr == wild_one && wildstr != wildend);
+ if (wildstr == wildend)
+ break;
+ }
+ if (*wildstr == wild_many)
+ { // Found wild_many
+ wildstr++;
+ /* Remove any '%' and '_' from the wild search string */
+ for ( ; wildstr != wildend ; wildstr++)
+ {
+ if (*wildstr == wild_many)
+ continue;
+ if (*wildstr == wild_one)
+ {
+ if (str == str_end)
+ return (-1);
+ str++;
+ continue;
+ }
+ break; // Not a wild character
+ }
+ if (wildstr == wildend)
+ return(0); // Ok if wild_many is last
+ if (str == str_end)
+ return -1;
+
+ char cmp;
+ if ((cmp= *wildstr) == escape && wildstr+1 != wildend)
+ cmp= *++wildstr;
+ wildstr++; // This is compared trough cmp
+ do
+ {
+ while (str != str_end && *str != cmp)
+ str++;
+ if (str++ == str_end) return (-1);
+ {
+ int tmp=wild_compare(str,str_end,wildstr,wildend,escape);
+ if (tmp <= 0)
+ return (tmp);
+ }
+ } while (str != str_end && wildstr[0] != wild_many);
+ return(-1);
+ }
+ }
+ 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);
+}
diff --git a/client/sql_string.h b/client/sql_string.h
new file mode 100644
index 00000000000..56a0a9b4eb2
--- /dev/null
+++ b/client/sql_string.h
@@ -0,0 +1,183 @@
+/* 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 originally from the mysql distribution. Coded by monty */
+
+#ifdef __GNUC__
+#pragma interface /* gcc class implementation */
+#endif
+
+#ifndef NOT_FIXED_DEC
+#define NOT_FIXED_DEC 31
+#endif
+
+class String
+{
+ char *Ptr;
+ uint32 str_length,Alloced_length;
+ bool alloced;
+public:
+ String()
+ { Ptr=0; str_length=Alloced_length=0; alloced=0; }
+ String(uint32 length_arg)
+ { alloced=0; Alloced_length=0; (void) real_alloc(length_arg); }
+ String(const char *str)
+ { Ptr=(char*) str; str_length=strlen(str); Alloced_length=0; alloced=0;}
+ String(const char *str,uint32 len)
+ { Ptr=(char*) str; str_length=len; Alloced_length=0; alloced=0;}
+ String(char *str,uint32 len)
+ { Ptr=(char*) str; Alloced_length=str_length=len; alloced=0;}
+ String(const String &str)
+ { Ptr=str.Ptr ; str_length=str.str_length ;
+ Alloced_length=str.Alloced_length; alloced=0; }
+
+ static void *operator new(size_t size) { return (void*) sql_alloc(size); }
+ static void operator delete(void *ptr_arg,size_t size) /*lint -e715 */
+ { sql_element_free(ptr_arg); }
+ ~String() { free(); }
+
+ inline uint32 length() const { return str_length;}
+ inline uint32 alloced_length() const { return Alloced_length;}
+ inline char& operator [] (uint32 i) const { return Ptr[i]; }
+ inline void length(uint32 len) { str_length=len ; }
+ inline bool is_empty() { return (str_length == 0); }
+ inline const char *ptr() const { return Ptr; }
+ inline char *c_ptr()
+ {
+ if (!Ptr || Ptr[str_length]) /* Should be safe */
+ (void) realloc(str_length);
+ return Ptr;
+ }
+ inline char *c_ptr_quick()
+ {
+ if (Ptr && str_length < Alloced_length)
+ Ptr[str_length]=0;
+ return Ptr;
+ }
+
+ void set(String &str,uint32 offset,uint32 arg_length)
+ {
+ free();
+ Ptr=(char*) str.ptr()+offset; str_length=arg_length; alloced=0;
+ if (str.Alloced_length)
+ Alloced_length=str.Alloced_length-offset;
+ else
+ Alloced_length=0;
+ }
+ inline void set(char *str,uint32 arg_length)
+ {
+ free();
+ Ptr=(char*) str; str_length=Alloced_length=arg_length ; alloced=0;
+ }
+ inline void set(const char *str,uint32 arg_length)
+ {
+ free();
+ Ptr=(char*) str; str_length=arg_length; Alloced_length=0 ; alloced=0;
+ }
+ inline void set_quick(char *str,uint32 arg_length)
+ {
+ if (!alloced)
+ {
+ Ptr=(char*) str; str_length=Alloced_length=arg_length;
+ }
+ }
+ bool set(longlong num);
+ /* bool set(long num); */
+ bool set(ulonglong num);
+ bool set(double num,uint decimals=2);
+ inline void free()
+ {
+ if (alloced)
+ {
+ alloced=0;
+ Alloced_length=0;
+ my_free(Ptr,MYF(0));
+ Ptr=0;
+ }
+ }
+
+ inline bool alloc(uint32 arg_length)
+ {
+ if (arg_length < Alloced_length)
+ return 0;
+ return real_alloc(arg_length);
+ }
+ bool real_alloc(uint32 arg_length); // Empties old string
+ bool realloc(uint32 arg_length);
+ inline void shrink(uint32 arg_length) // Shrink buffer
+ {
+ if (arg_length < Alloced_length)
+ {
+ char *new_ptr;
+ if (!(new_ptr=my_realloc(Ptr,arg_length,MYF(0))))
+ {
+ (void) my_free(Ptr,MYF(0));
+ real_alloc(arg_length);
+ }
+ else
+ {
+ Ptr=new_ptr;
+ Alloced_length=arg_length;
+ }
+ }
+ }
+ bool is_alloced() { return alloced; }
+ inline String& operator = (const String &s)
+ {
+ if (&s != this)
+ {
+ free();
+ Ptr=s.Ptr ; str_length=s.str_length ; Alloced_length=s.Alloced_length;
+ alloced=0;
+ }
+ return *this;
+ }
+
+ bool copy(); // Alloc string if not alloced
+ bool copy(const String &s); // Allocate new string
+ bool copy(const char *s,uint32 arg_length); // Allocate new string
+ bool append(const String &s);
+ bool append(const char *s,uint32 arg_length=0);
+ int strstr(const String &search,uint32 offset=0); // Returns offset to substring or -1
+ 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)
+ {
+ if (str_length < Alloced_length)
+ {
+ Ptr[str_length++]=chr;
+ }
+ else
+ {
+ if (realloc(str_length+1))
+ return 1;
+ Ptr[str_length++]=chr;
+ }
+ return 0;
+ }
+ bool fill(uint32 max_length,char fill);
+ void strip_sp();
+ inline void caseup() { ::caseup(Ptr,str_length); }
+ inline void casedn() { ::casedn(Ptr,str_length); }
+ friend int sortcmp(const String *a,const String *b);
+ friend int stringcmp(const String *a,const String *b);
+ friend String *copy_if_not_alloced(String *a,String *b,uint32 arg_length);
+ friend int wild_case_compare(String &match,String &wild,char escape);
+ friend int wild_compare(String &match,String &wild,char escape);
+ uint32 numchars();
+ int charpos(int i,uint32 offset=0);
+};
diff --git a/client/ssl_test.c b/client/ssl_test.c
new file mode 100644
index 00000000000..d1ec1776696
--- /dev/null
+++ b/client/ssl_test.c
@@ -0,0 +1,95 @@
+/* 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 program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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
+#include <stdio.h>
+#include <stdlib.h>
+#include "mysql.h"
+#include "config.h"
+#define SELECT_QUERY "select name from test where num = %d"
+
+
+int main(int argc, char **argv)
+{
+#ifdef HAVE_OPENSSL
+ int count, num;
+ MYSQL mysql,*sock;
+ MYSQL_RES *res;
+ char qbuf[160];
+
+ if (argc != 3)
+ {
+ fprintf(stderr,"usage : ssl_test <dbname> <num>\n\n");
+ exit(1);
+ }
+
+ mysql_init(&mysql);
+#ifdef HAVE_OPENSSL
+ mysql_ssl_set(&mysql,"../SSL/MySQL-client-key.pem","../SSL/MySQL-client-cert.pem","../SSL/MySQL-ca-cert.pem","../SSL/");
+#endif
+ if (!(sock = mysql_real_connect(&mysql,"127.0.0.1",0,0,argv[1],3306,NULL,0)))
+ {
+ fprintf(stderr,"Couldn't connect to engine!\n%s\n\n",mysql_error(&mysql));
+ perror("");
+ exit(1);
+ }
+ printf("Cipher:%s\n",mysql_ssl_cipher(&mysql));
+ count = 0;
+ num = atoi(argv[2]);
+ while (count < num)
+ {
+ sprintf(qbuf,SELECT_QUERY,count);
+ if(mysql_query(sock,qbuf))
+ {
+ fprintf(stderr,"Query failed (%s)\n",mysql_error(sock));
+ exit(1);
+ }
+ if (!(res=mysql_store_result(sock)))
+ {
+ fprintf(stderr,"Couldn't get result from query failed\n",
+ mysql_error(sock));
+ exit(1);
+ }
+#ifdef TEST
+ printf("number of fields: %d\n",mysql_num_fields(res));
+#endif
+ mysql_free_result(res);
+ count++;
+ }
+ mysql_close(sock);
+#else /* HAVE_OPENSSL */
+ printf("ssl_test: SSL not configured.\n");
+#endif /* HAVE_OPENSSL */
+ exit(0);
+ return 0; /* Keep some compilers happy */
+}
diff --git a/client/thread_test.c b/client/thread_test.c
new file mode 100644
index 00000000000..def3381eb89
--- /dev/null
+++ b/client/thread_test.c
@@ -0,0 +1,283 @@
+/* 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>
+#include <my_sys.h>
+#include <my_pthread.h>
+#include "mysql.h"
+#include <getopt.h>
+
+#ifndef THREAD
+
+int main(int argc, char **argv)
+{
+ printf("This test must be compiled with multithread support to work\n");
+ exit(1);
+}
+#else
+
+static my_bool version,verbose;
+static uint thread_count,number_of_tests=1000,number_of_threads=2;
+static pthread_cond_t COND_thread_count;
+static pthread_mutex_t LOCK_thread_count;
+
+static char *database,*host,*user,*password,*unix_socket,*query;
+uint tcp_port;
+
+#ifndef __WIN__
+void *test_thread(void *arg)
+#else
+unsigned __stdcall test_thread(void *arg)
+#endif
+{
+ MYSQL *mysql;
+ uint count;
+
+ mysql=mysql_init(NULL);
+ if (!mysql_real_connect(mysql,host,user,password,database,tcp_port,
+ unix_socket,0))
+ {
+ fprintf(stderr,"Couldn't connect to engine!\n%s\n\n",mysql_error(mysql));
+ perror("");
+ goto end;
+ }
+ if (verbose) { putchar('*'); fflush(stdout); }
+ for (count=0 ; count < number_of_tests ; count++)
+ {
+ MYSQL_RES *res;
+ if (mysql_query(mysql,query))
+ {
+ fprintf(stderr,"Query failed (%s)\n",mysql_error(mysql));
+ goto end;
+ }
+ if (!(res=mysql_store_result(mysql)))
+ {
+ fprintf(stderr,"Couldn't get result from %s\n", mysql_error(mysql));
+ goto end;
+ }
+ mysql_free_result(res);
+ if (verbose) { putchar('.'); fflush(stdout); }
+ }
+end:
+ if (verbose) { putchar('#'); fflush(stdout); }
+ mysql_close(mysql);
+ pthread_mutex_lock(&LOCK_thread_count);
+ thread_count--;
+ VOID(pthread_cond_signal(&COND_thread_count)); /* Tell main we are ready */
+ pthread_mutex_unlock(&LOCK_thread_count);
+ pthread_exit(0);
+ return 0;
+}
+
+
+static struct option long_options[] =
+{
+ {"help", no_argument, 0, '?'},
+ {"database", required_argument, 0, 'D'},
+ {"host", required_argument, 0, 'h'},
+ {"password", optional_argument, 0, 'p'},
+ {"user", required_argument, 0, 'u'},
+ {"version", no_argument, 0, 'V'},
+ {"verbose", no_argument, 0, 'v'},
+ {"query", required_argument, 0, 'Q'},
+ {"port", required_argument, 0, 'P'},
+ {"socket", required_argument, 0, 'S'},
+ {"test-count",required_argument, 0, 'c'},
+ {"thread-count",required_argument, 0, 't'},
+ {0, 0, 0, 0}
+};
+
+static const char *load_default_groups[]= { "client",0 };
+
+static void usage()
+{
+ printf("Connection to a mysql server with multiple threads\n");
+ if (version)
+ return;
+ puts("This software comes with ABSOLUTELY NO WARRANTY.\n");
+ printf("Usage: %s [OPTIONS] [database]\n", my_progname);
+ printf("\n\
+ -?, --help Display this help and exit\n\
+ -c #, --test-count=# Run test count times (default %d)\n",number_of_tests);
+ printf("\
+ -D, --database=.. Database to use\n\
+ -h, --host=... Connect to host\n\
+ -p[password], --password[=...]\n\
+ Password to use when connecting to server\n\
+ If password is not given it's asked from the tty.\n");
+ printf("\n\
+ -P --port=... Port number to use for connection\n\
+ -Q, --query=... Query to execute in each threads\n\
+ -S --socket=... Socket file to use for connection\n");
+ printf("\
+ -t --thread-count=# Number of threads to start (default: %d) \n\
+ -u, --user=# User for login if not current user\n\
+ -v, --verbose Write some progress indicators\n\
+ -V, --version Output version information and exit\n",
+ number_of_threads);
+
+ print_defaults("my",load_default_groups);
+
+ printf("\nExample usage:\n\n\
+%s -Q 'select * from mysql.user' -c %d -t %d\n",
+ my_progname, number_of_tests, number_of_threads);
+}
+
+
+static void get_options(int argc, char **argv)
+{
+ int c,option_index=0,error=0;
+ bool tty_password=0;
+ load_defaults("my",load_default_groups,&argc,&argv);
+
+ while ((c=getopt_long(argc,argv, "c:D:h:p::VQ:P:S:t:?I",
+ long_options, &option_index)) != EOF)
+ {
+ switch (c) {
+ case 'c':
+ number_of_tests=atoi(optarg);
+ break;
+ case 'D':
+ my_free(database,MYF(MY_ALLOW_ZERO_PTR));
+ database=my_strdup(optarg,MYF(MY_WME));
+ break;
+ case 'h':
+ host = optarg;
+ break;
+ case 'Q': /* Allow old 'q' option */
+ query= optarg;
+ break;
+ case 'p':
+ if (optarg)
+ {
+ my_free(password,MYF(MY_ALLOW_ZERO_PTR));
+ password=my_strdup(optarg,MYF(MY_FAE));
+ while (*optarg) *optarg++= 'x'; /* Destroy argument */
+ }
+ else
+ tty_password=1;
+ break;
+ case 'u':
+ my_free(user,MYF(MY_ALLOW_ZERO_PTR));
+ user= my_strdup(optarg,MYF(0));
+ break;
+ case 'P':
+ tcp_port= (unsigned int) atoi(optarg);
+ break;
+ case 'S':
+ my_free(unix_socket,MYF(MY_ALLOW_ZERO_PTR));
+ unix_socket= my_strdup(optarg,MYF(0));
+ break;
+ case 't':
+ number_of_threads=atoi(optarg);
+ break;
+ case 'v':
+ verbose=1;
+ break;
+ case 'V':
+ version=1;
+ usage();
+ exit(0);
+ break;
+ default:
+ fprintf(stderr,"Illegal option character '%c'\n",opterr);
+ /* Fall through */
+ case '?':
+ case 'I': /* Info */
+ error++;
+ break;
+ }
+ }
+ if (error || argc != optind)
+ {
+ usage();
+ exit(1);
+ }
+ free_defaults(argv);
+ if (tty_password)
+ password=get_tty_password(NullS);
+ return;
+}
+
+
+int main(int argc, char **argv)
+{
+ pthread_t tid;
+ pthread_attr_t thr_attr;
+ int i,error;
+ MY_INIT(argv[0]);
+ get_options(argc,argv);
+
+ if ((error=pthread_cond_init(&COND_thread_count,NULL)))
+ {
+ fprintf(stderr,"Got error: %d from pthread_cond_init (errno: %d)",
+ error,errno);
+ exit(1);
+ }
+ pthread_mutex_init(&LOCK_thread_count,NULL);
+
+ if ((error=pthread_attr_init(&thr_attr)))
+ {
+ fprintf(stderr,"Got error: %d from pthread_attr_init (errno: %d)",
+ error,errno);
+ exit(1);
+ }
+ if ((error=pthread_attr_setdetachstate(&thr_attr,PTHREAD_CREATE_DETACHED)))
+ {
+ fprintf(stderr,
+ "Got error: %d from pthread_attr_setdetachstate (errno: %d)",
+ error,errno);
+ exit(1);
+ }
+
+ printf("Init ok. Creating %d threads\n",number_of_threads);
+ for (i=1 ; i <= number_of_threads ; i++)
+ {
+ int *param= &i;
+
+ if (verbose) { putchar('+'); fflush(stdout); }
+ pthread_mutex_lock(&LOCK_thread_count);
+ if ((error=pthread_create(&tid,&thr_attr,test_thread,(void*) param)))
+ {
+ fprintf(stderr,"\nGot error: %d from pthread_create (errno: %d) when creating thread: %i\n",
+ error,errno,i);
+ pthread_mutex_unlock(&LOCK_thread_count);
+ exit(1);
+ }
+ thread_count++;
+ pthread_mutex_unlock(&LOCK_thread_count);
+ }
+
+ printf("Waiting for threads to finnish\n");
+ error=pthread_mutex_lock(&LOCK_thread_count);
+ while (thread_count)
+ {
+ if ((error=pthread_cond_wait(&COND_thread_count,&LOCK_thread_count)))
+ fprintf(stderr,"\nGot error: %d from pthread_cond_wait\n",error);
+ }
+ pthread_mutex_unlock(&LOCK_thread_count);
+ pthread_attr_destroy(&thr_attr);
+ printf("\nend\n");
+
+ my_end(0);
+ return 0;
+
+ exit(0);
+ return 0; /* Keep some compilers happy */
+}
+
+#endif /* THREAD */
diff --git a/client/violite.c b/client/violite.c
new file mode 100644
index 00000000000..f32c3c62a48
--- /dev/null
+++ b/client/violite.c
@@ -0,0 +1,394 @@
+/* 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
new file mode 100755
index 00000000000..cd4de2b0090
--- /dev/null
+++ b/config.guess
@@ -0,0 +1,1131 @@
+#! /bin/sh
+# Attempt to guess a canonical system name.
+# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999
+# Free Software Foundation, Inc.
+#
+# 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.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Written by Per Bothner <bothner@cygnus.com>.
+# The master version of this file is at the FSF in /home/gd/gnu/lib.
+# Please send patches to the Autoconf mailing list <autoconf@gnu.org>.
+#
+# This script attempts to guess a canonical system name similar to
+# config.sub. If it succeeds, it prints the system name on stdout, and
+# exits with 0. Otherwise, it exits with 1.
+#
+# The plan is that this can be called by configure scripts if you
+# don't specify an explicit system type (host/target name).
+#
+# Only a few systems have been added to this list; please add others
+# (but try to keep the structure clean).
+#
+
+# Use $HOST_CC if defined. $CC may point to a cross-compiler
+if test x"$CC_FOR_BUILD" = x; then
+ if test x"$HOST_CC" != x; then
+ CC_FOR_BUILD="$HOST_CC"
+ else
+ if test x"$CC" != x; then
+ CC_FOR_BUILD="$CC"
+ else
+ CC_FOR_BUILD=cc
+ fi
+ fi
+fi
+
+
+# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
+# (ghazi@noc.rutgers.edu 8/24/94.)
+if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
+ PATH=$PATH:/.attbin ; export PATH
+fi
+
+UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
+UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
+UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown
+UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
+
+dummy=dummy-$$
+trap 'rm -f $dummy.c $dummy.o $dummy; exit 1' 1 2 15
+
+# Note: order is significant - the case branches are not exclusive.
+
+case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
+ alpha:OSF1:*:*)
+ if test $UNAME_RELEASE = "V4.0"; then
+ UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
+ fi
+ # A Vn.n version is a released version.
+ # A Tn.n version is a released field test version.
+ # A Xn.n version is an unreleased experimental baselevel.
+ # 1.2 uses "1.2" for uname -r.
+ cat <<EOF >$dummy.s
+ .globl main
+ .ent main
+main:
+ .frame \$30,0,\$26,0
+ .prologue 0
+ .long 0x47e03d80 # implver $0
+ lda \$2,259
+ .long 0x47e20c21 # amask $2,$1
+ srl \$1,8,\$2
+ sll \$2,2,\$2
+ sll \$0,3,\$0
+ addl \$1,\$0,\$0
+ addl \$2,\$0,\$0
+ ret \$31,(\$26),1
+ .end main
+EOF
+ $CC_FOR_BUILD $dummy.s -o $dummy 2>/dev/null
+ if test "$?" = 0 ; then
+ ./$dummy
+ case "$?" in
+ 7)
+ UNAME_MACHINE="alpha"
+ ;;
+ 15)
+ UNAME_MACHINE="alphaev5"
+ ;;
+ 14)
+ UNAME_MACHINE="alphaev56"
+ ;;
+ 10)
+ UNAME_MACHINE="alphapca56"
+ ;;
+ 16)
+ UNAME_MACHINE="alphaev6"
+ ;;
+ esac
+ fi
+ rm -f $dummy.s $dummy
+ echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[VTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+ exit 0 ;;
+ Alpha\ *:Windows_NT*:*)
+ # How do we know it's Interix rather than the generic POSIX subsystem?
+ # Should we change UNAME_MACHINE based on the output of uname instead
+ # of the specific Alpha model?
+ echo alpha-pc-interix
+ exit 0 ;;
+ 21064:Windows_NT:50:3)
+ echo alpha-dec-winnt3.5
+ exit 0 ;;
+ Amiga*:UNIX_System_V:4.0:*)
+ echo m68k-cbm-sysv4
+ exit 0;;
+ amiga:NetBSD:*:*)
+ echo m68k-cbm-netbsd${UNAME_RELEASE}
+ exit 0 ;;
+ amiga:OpenBSD:*:*)
+ echo m68k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ *:[Aa]miga[Oo][Ss]:*:*)
+ echo ${UNAME_MACHINE}-unknown-amigaos
+ exit 0 ;;
+ arc64:OpenBSD:*:*)
+ echo mips64el-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ arc:OpenBSD:*:*)
+ echo mipsel-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ hkmips:OpenBSD:*:*)
+ echo mips-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ pmax:OpenBSD:*:*)
+ echo mipsel-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ sgi:OpenBSD:*:*)
+ echo mips-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ wgrisc:OpenBSD:*:*)
+ echo mipsel-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
+ echo arm-acorn-riscix${UNAME_RELEASE}
+ exit 0;;
+ arm32:NetBSD:*:*)
+ echo arm-unknown-netbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+ exit 0 ;;
+ SR2?01:HI-UX/MPP:*:*)
+ echo hppa1.1-hitachi-hiuxmpp
+ exit 0;;
+ Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
+ # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
+ if test "`(/bin/universe) 2>/dev/null`" = att ; then
+ echo pyramid-pyramid-sysv3
+ else
+ echo pyramid-pyramid-bsd
+ fi
+ exit 0 ;;
+ NILE*:*:*:dcosx)
+ echo pyramid-pyramid-svr4
+ exit 0 ;;
+ sun4H:SunOS:5.*:*)
+ echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit 0 ;;
+ sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
+ echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit 0 ;;
+ i86pc:SunOS:5.*:*)
+ echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit 0 ;;
+ sun4*:SunOS:6*:*)
+ # According to config.sub, this is the proper way to canonicalize
+ # SunOS6. Hard to guess exactly what SunOS6 will be like, but
+ # it's likely to be more like Solaris than SunOS4.
+ echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit 0 ;;
+ sun4*:SunOS:*:*)
+ case "`/usr/bin/arch -k`" in
+ Series*|S4*)
+ UNAME_RELEASE=`uname -v`
+ ;;
+ esac
+ # Japanese Language versions have a version number like `4.1.3-JL'.
+ echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
+ exit 0 ;;
+ sun3*:SunOS:*:*)
+ echo m68k-sun-sunos${UNAME_RELEASE}
+ exit 0 ;;
+ sun*:*:4.2BSD:*)
+ UNAME_RELEASE=`(head -1 /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
+ test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
+ case "`/bin/arch`" in
+ sun3)
+ echo m68k-sun-sunos${UNAME_RELEASE}
+ ;;
+ sun4)
+ echo sparc-sun-sunos${UNAME_RELEASE}
+ ;;
+ esac
+ exit 0 ;;
+ aushp:SunOS:*:*)
+ echo sparc-auspex-sunos${UNAME_RELEASE}
+ exit 0 ;;
+ atari*:NetBSD:*:*)
+ echo m68k-atari-netbsd${UNAME_RELEASE}
+ exit 0 ;;
+ atari*:OpenBSD:*:*)
+ echo m68k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ # The situation for MiNT is a little confusing. The machine name
+ # can be virtually everything (everything which is not
+ # "atarist" or "atariste" at least should have a processor
+ # > m68000). The system name ranges from "MiNT" over "FreeMiNT"
+ # to the lowercase version "mint" (or "freemint"). Finally
+ # the system name "TOS" denotes a system which is actually not
+ # MiNT. But MiNT is downward compatible to TOS, so this should
+ # be no problem.
+ atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit 0 ;;
+ atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit 0 ;;
+ *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit 0 ;;
+ milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
+ echo m68k-milan-mint${UNAME_RELEASE}
+ exit 0 ;;
+ hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
+ echo m68k-hades-mint${UNAME_RELEASE}
+ exit 0 ;;
+ *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
+ echo m68k-unknown-mint${UNAME_RELEASE}
+ exit 0 ;;
+ sun3*:NetBSD:*:*)
+ echo m68k-sun-netbsd${UNAME_RELEASE}
+ exit 0 ;;
+ sun3*:OpenBSD:*:*)
+ echo m68k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ mac68k:NetBSD:*:*)
+ echo m68k-apple-netbsd${UNAME_RELEASE}
+ exit 0 ;;
+ mac68k:OpenBSD:*:*)
+ echo m68k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ mvme68k:OpenBSD:*:*)
+ echo m68k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ mvme88k:OpenBSD:*:*)
+ echo m88k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ powerpc:machten:*:*)
+ echo powerpc-apple-machten${UNAME_RELEASE}
+ exit 0 ;;
+ macppc:NetBSD:*:*)
+ echo powerpc-apple-netbsd${UNAME_RELEASE}
+ exit 0 ;;
+ RISC*:Mach:*:*)
+ echo mips-dec-mach_bsd4.3
+ exit 0 ;;
+ RISC*:ULTRIX:*:*)
+ echo mips-dec-ultrix${UNAME_RELEASE}
+ exit 0 ;;
+ VAX*:ULTRIX*:*:*)
+ echo vax-dec-ultrix${UNAME_RELEASE}
+ exit 0 ;;
+ 2020:CLIX:*:* | 2430:CLIX:*:*)
+ echo clipper-intergraph-clix${UNAME_RELEASE}
+ exit 0 ;;
+ mips:*:*:UMIPS | mips:*:*:RISCos)
+ sed 's/^ //' << EOF >$dummy.c
+#ifdef __cplusplus
+ int main (int argc, char *argv[]) {
+#else
+ int main (argc, argv) int argc; char *argv[]; {
+#endif
+ #if defined (host_mips) && defined (MIPSEB)
+ #if defined (SYSTYPE_SYSV)
+ printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0);
+ #endif
+ #if defined (SYSTYPE_SVR4)
+ printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0);
+ #endif
+ #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
+ printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0);
+ #endif
+ #endif
+ exit (-1);
+ }
+EOF
+ $CC_FOR_BUILD $dummy.c -o $dummy \
+ && ./$dummy `echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` \
+ && rm $dummy.c $dummy && exit 0
+ rm -f $dummy.c $dummy
+ echo mips-mips-riscos${UNAME_RELEASE}
+ exit 0 ;;
+ Night_Hawk:Power_UNIX:*:*)
+ echo powerpc-harris-powerunix
+ exit 0 ;;
+ m88k:CX/UX:7*:*)
+ echo m88k-harris-cxux7
+ exit 0 ;;
+ m88k:*:4*:R4*)
+ echo m88k-motorola-sysv4
+ exit 0 ;;
+ m88k:*:3*:R3*)
+ echo m88k-motorola-sysv3
+ exit 0 ;;
+ AViiON:dgux:*:*)
+ # DG/UX returns AViiON for all architectures
+ UNAME_PROCESSOR=`/usr/bin/uname -p`
+ if [ $UNAME_PROCESSOR = mc88100 -o $UNAME_PROCESSOR = mc88110 ] ; then
+ if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx \
+ -o ${TARGET_BINARY_INTERFACE}x = x ] ; then
+ echo m88k-dg-dgux${UNAME_RELEASE}
+ else
+ echo m88k-dg-dguxbcs${UNAME_RELEASE}
+ fi
+ else echo i586-dg-dgux${UNAME_RELEASE}
+ fi
+ exit 0 ;;
+ M88*:DolphinOS:*:*) # DolphinOS (SVR3)
+ echo m88k-dolphin-sysv3
+ exit 0 ;;
+ M88*:*:R3*:*)
+ # Delta 88k system running SVR3
+ echo m88k-motorola-sysv3
+ exit 0 ;;
+ XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
+ echo m88k-tektronix-sysv3
+ exit 0 ;;
+ Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
+ echo m68k-tektronix-bsd
+ exit 0 ;;
+ *:IRIX*:*:*)
+ echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
+ exit 0 ;;
+ ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
+ echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id
+ exit 0 ;; # Note that: echo "'`uname -s`'" gives 'AIX '
+ i?86:AIX:*:*)
+ echo i386-ibm-aix
+ exit 0 ;;
+ *:AIX:2:3)
+ if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
+ sed 's/^ //' << EOF >$dummy.c
+ #include <sys/systemcfg.h>
+
+ main()
+ {
+ if (!__power_pc())
+ exit(1);
+ puts("powerpc-ibm-aix3.2.5");
+ exit(0);
+ }
+EOF
+ $CC_FOR_BUILD $dummy.c -o $dummy && ./$dummy && rm $dummy.c $dummy && exit 0
+ rm -f $dummy.c $dummy
+ echo rs6000-ibm-aix3.2.5
+ elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
+ echo rs6000-ibm-aix3.2.4
+ else
+ echo rs6000-ibm-aix3.2
+ fi
+ exit 0 ;;
+ *:AIX:*:4)
+ IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | head -1 | awk '{ print $1 }'`
+ if /usr/sbin/lsattr -EHl ${IBM_CPU_ID} | grep POWER >/dev/null 2>&1; then
+ IBM_ARCH=rs6000
+ else
+ IBM_ARCH=powerpc
+ fi
+ if [ -x /usr/bin/oslevel ] ; then
+ IBM_REV=`/usr/bin/oslevel`
+ else
+ IBM_REV=4.${UNAME_RELEASE}
+ fi
+ echo ${IBM_ARCH}-ibm-aix${IBM_REV}
+ exit 0 ;;
+ *:AIX:*:*)
+ echo rs6000-ibm-aix
+ exit 0 ;;
+ ibmrt:4.4BSD:*|romp-ibm:BSD:*)
+ echo romp-ibm-bsd4.4
+ exit 0 ;;
+ ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC NetBSD and
+ echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to
+ exit 0 ;; # report: romp-ibm BSD 4.3
+ *:BOSX:*:*)
+ echo rs6000-bull-bosx
+ exit 0 ;;
+ DPX/2?00:B.O.S.:*:*)
+ echo m68k-bull-sysv3
+ exit 0 ;;
+ 9000/[34]??:4.3bsd:1.*:*)
+ echo m68k-hp-bsd
+ exit 0 ;;
+ hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
+ echo m68k-hp-bsd4.4
+ exit 0 ;;
+ 9000/[34678]??:HP-UX:*:*)
+ case "${UNAME_MACHINE}" in
+ 9000/31? ) HP_ARCH=m68000 ;;
+ 9000/[34]?? ) HP_ARCH=m68k ;;
+ 9000/[678][0-9][0-9])
+ sed 's/^ //' << EOF >$dummy.c
+ #include <stdlib.h>
+ #include <unistd.h>
+
+ int main ()
+ {
+ #if defined(_SC_KERNEL_BITS)
+ long bits = sysconf(_SC_KERNEL_BITS);
+ #endif
+ long cpu = sysconf (_SC_CPU_VERSION);
+
+ switch (cpu)
+ {
+ case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
+ case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
+ case CPU_PA_RISC2_0:
+ #if defined(_SC_KERNEL_BITS)
+ switch (bits)
+ {
+ case 64: puts ("hppa2.0w"); break;
+ case 32: puts ("hppa2.0n"); break;
+ default: puts ("hppa2.0"); break;
+ } break;
+ #else /* !defined(_SC_KERNEL_BITS) */
+ puts ("hppa2.0"); break;
+ #endif
+ default: puts ("hppa1.0"); break;
+ }
+ exit (0);
+ }
+EOF
+ ($CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null ) && HP_ARCH=`./$dummy`
+ rm -f $dummy.c $dummy
+ esac
+ HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+ echo ${HP_ARCH}-hp-hpux${HPUX_REV}
+ exit 0 ;;
+ 3050*:HI-UX:*:*)
+ sed 's/^ //' << EOF >$dummy.c
+ #include <unistd.h>
+ int
+ main ()
+ {
+ long cpu = sysconf (_SC_CPU_VERSION);
+ /* The order matters, because CPU_IS_HP_MC68K erroneously returns
+ true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct
+ results, however. */
+ if (CPU_IS_PA_RISC (cpu))
+ {
+ switch (cpu)
+ {
+ case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
+ case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
+ case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
+ default: puts ("hppa-hitachi-hiuxwe2"); break;
+ }
+ }
+ else if (CPU_IS_HP_MC68K (cpu))
+ puts ("m68k-hitachi-hiuxwe2");
+ else puts ("unknown-hitachi-hiuxwe2");
+ exit (0);
+ }
+EOF
+ $CC_FOR_BUILD $dummy.c -o $dummy && ./$dummy && rm $dummy.c $dummy && exit 0
+ rm -f $dummy.c $dummy
+ echo unknown-hitachi-hiuxwe2
+ exit 0 ;;
+ 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
+ echo hppa1.1-hp-bsd
+ exit 0 ;;
+ 9000/8??:4.3bsd:*:*)
+ echo hppa1.0-hp-bsd
+ exit 0 ;;
+ *9??*:MPE/iX:*:*)
+ echo hppa1.0-hp-mpeix
+ exit 0 ;;
+ hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
+ echo hppa1.1-hp-osf
+ exit 0 ;;
+ hp8??:OSF1:*:*)
+ echo hppa1.0-hp-osf
+ exit 0 ;;
+ i?86:OSF1:*:*)
+ if [ -x /usr/sbin/sysversion ] ; then
+ echo ${UNAME_MACHINE}-unknown-osf1mk
+ else
+ echo ${UNAME_MACHINE}-unknown-osf1
+ fi
+ exit 0 ;;
+ parisc*:Lites*:*:*)
+ echo hppa1.1-hp-lites
+ exit 0 ;;
+ hppa*:OpenBSD:*:*)
+ echo hppa-unknown-openbsd
+ exit 0 ;;
+ C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
+ echo c1-convex-bsd
+ exit 0 ;;
+ C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
+ if getsysinfo -f scalar_acc
+ then echo c32-convex-bsd
+ else echo c2-convex-bsd
+ fi
+ exit 0 ;;
+ C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
+ echo c34-convex-bsd
+ exit 0 ;;
+ C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
+ echo c38-convex-bsd
+ exit 0 ;;
+ C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
+ echo c4-convex-bsd
+ exit 0 ;;
+ CRAY*X-MP:*:*:*)
+ echo xmp-cray-unicos
+ exit 0 ;;
+ CRAY*Y-MP:*:*:*)
+ echo ymp-cray-unicos${UNAME_RELEASE}
+ exit 0 ;;
+ CRAY*[A-Z]90:*:*:*)
+ echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
+ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
+ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/
+ exit 0 ;;
+ CRAY*TS:*:*:*)
+ echo t90-cray-unicos${UNAME_RELEASE}
+ exit 0 ;;
+ CRAY*T3E:*:*:*)
+ echo alpha-cray-unicosmk${UNAME_RELEASE}
+ exit 0 ;;
+ CRAY-2:*:*:*)
+ echo cray2-cray-unicos
+ exit 0 ;;
+ F300:UNIX_System_V:*:*)
+ FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+ FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
+ echo "f300-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+ exit 0 ;;
+ F301:UNIX_System_V:*:*)
+ echo f301-fujitsu-uxpv`echo $UNAME_RELEASE | sed 's/ .*//'`
+ exit 0 ;;
+ hp3[0-9][05]:NetBSD:*:*)
+ echo m68k-hp-netbsd${UNAME_RELEASE}
+ exit 0 ;;
+ hp300:OpenBSD:*:*)
+ echo m68k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ i?86:BSD/386:*:* | i?86:BSD/OS:*:*)
+ echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
+ exit 0 ;;
+ sparc*:BSD/OS:*:*)
+ echo sparc-unknown-bsdi${UNAME_RELEASE}
+ exit 0 ;;
+ *:BSD/OS:*:*)
+ echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
+ exit 0 ;;
+ *:FreeBSD:*:*)
+ if test -x /usr/bin/objformat; then
+ if test "elf" = "`/usr/bin/objformat`"; then
+ echo ${UNAME_MACHINE}-unknown-freebsdelf`echo ${UNAME_RELEASE}|sed -e 's/[-_].*//'`
+ exit 0
+ fi
+ fi
+ echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
+ exit 0 ;;
+ *:NetBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-netbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+ exit 0 ;;
+ *:OpenBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-openbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+ exit 0 ;;
+ i*:CYGWIN*:*)
+ echo ${UNAME_MACHINE}-pc-cygwin
+ exit 0 ;;
+ i*:MINGW*:*)
+ echo ${UNAME_MACHINE}-pc-mingw32
+ exit 0 ;;
+ i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
+ # How do we know it's Interix rather than the generic POSIX subsystem?
+ # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
+ # UNAME_MACHINE based on the output of uname instead of i386?
+ echo i386-pc-interix
+ exit 0 ;;
+ i*:UWIN*:*)
+ echo ${UNAME_MACHINE}-pc-uwin
+ exit 0 ;;
+ p*:CYGWIN*:*)
+ echo powerpcle-unknown-cygwin
+ exit 0 ;;
+ prep*:SunOS:5.*:*)
+ echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit 0 ;;
+ *:GNU:*:*)
+ echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
+ exit 0 ;;
+ *:Linux:*:*)
+ # uname on the ARM produces all sorts of strangeness, and we need to
+ # filter it out.
+ case "$UNAME_MACHINE" in
+ armv*) UNAME_MACHINE=$UNAME_MACHINE ;;
+ arm* | sa110*) UNAME_MACHINE="arm" ;;
+ esac
+
+ # The BFD linker knows what the default object file format is, so
+ # first see if it will tell us. cd to the root directory to prevent
+ # problems with other programs or directories called `ld' in the path.
+ ld_help_string=`cd /; ld --help 2>&1`
+ ld_supported_emulations=`echo $ld_help_string \
+ | sed -ne '/supported emulations:/!d
+ s/[ ][ ]*/ /g
+ s/.*supported emulations: *//
+ s/ .*//
+ p'`
+ case "$ld_supported_emulations" in
+ *ia64) echo "${UNAME_MACHINE}-unknown-linux" ; exit 0 ;;
+ i?86linux) echo "${UNAME_MACHINE}-pc-linux-gnuaout" ; exit 0 ;;
+ i?86coff) echo "${UNAME_MACHINE}-pc-linux-gnucoff" ; exit 0 ;;
+ sparclinux) echo "${UNAME_MACHINE}-unknown-linux-gnuaout" ; exit 0 ;;
+ armlinux) echo "${UNAME_MACHINE}-unknown-linux-gnuaout" ; exit 0 ;;
+ m68klinux) echo "${UNAME_MACHINE}-unknown-linux-gnuaout" ; exit 0 ;;
+ elf_i?86) echo "${UNAME_MACHINE}-pc-linux-gnu" ; exit 0 ;;
+ elf32ppc | elf32ppclinux)
+ # Determine Lib Version
+ cat >$dummy.c <<EOF
+#include <features.h>
+#if defined(__GLIBC__)
+extern char __libc_version[];
+extern char __libc_release[];
+#endif
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+#if defined(__GLIBC__)
+ printf("%s %s\n", __libc_version, __libc_release);
+#else
+ printf("unkown\n");
+#endif
+ return 0;
+}
+EOF
+ LIBC=""
+ $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null
+ if test "$?" = 0 ; then
+ ./$dummy | grep 1\.99 > /dev/null
+ if test "$?" = 0 ; then
+ LIBC="libc1"
+ fi
+ fi
+ rm -f $dummy.c $dummy
+ echo powerpc-unknown-linux-gnu${LIBC} ; exit 0 ;;
+ esac
+
+ if test "${UNAME_MACHINE}" = "alpha" ; then
+ sed 's/^ //' <<EOF >$dummy.s
+ .globl main
+ .ent main
+ main:
+ .frame \$30,0,\$26,0
+ .prologue 0
+ .long 0x47e03d80 # implver $0
+ lda \$2,259
+ .long 0x47e20c21 # amask $2,$1
+ srl \$1,8,\$2
+ sll \$2,2,\$2
+ sll \$0,3,\$0
+ addl \$1,\$0,\$0
+ addl \$2,\$0,\$0
+ ret \$31,(\$26),1
+ .end main
+EOF
+ LIBC=""
+ $CC_FOR_BUILD $dummy.s -o $dummy 2>/dev/null
+ if test "$?" = 0 ; then
+ ./$dummy
+ case "$?" in
+ 7)
+ UNAME_MACHINE="alpha"
+ ;;
+ 15)
+ UNAME_MACHINE="alphaev5"
+ ;;
+ 14)
+ UNAME_MACHINE="alphaev56"
+ ;;
+ 10)
+ UNAME_MACHINE="alphapca56"
+ ;;
+ 16)
+ UNAME_MACHINE="alphaev6"
+ ;;
+ esac
+
+ objdump --private-headers $dummy | \
+ grep ld.so.1 > /dev/null
+ if test "$?" = 0 ; then
+ LIBC="libc1"
+ fi
+ fi
+ rm -f $dummy.s $dummy
+ echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} ; exit 0
+ elif test "${UNAME_MACHINE}" = "mips" ; then
+ cat >$dummy.c <<EOF
+#ifdef __cplusplus
+ int main (int argc, char *argv[]) {
+#else
+ int main (argc, argv) int argc; char *argv[]; {
+#endif
+#ifdef __MIPSEB__
+ printf ("%s-unknown-linux-gnu\n", argv[1]);
+#endif
+#ifdef __MIPSEL__
+ printf ("%sel-unknown-linux-gnu\n", argv[1]);
+#endif
+ return 0;
+}
+EOF
+ $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null && ./$dummy "${UNAME_MACHINE}" && rm $dummy.c $dummy && exit 0
+ rm -f $dummy.c $dummy
+ else
+ # Either a pre-BFD a.out linker (linux-gnuoldld)
+ # or one that does not give us useful --help.
+ # GCC wants to distinguish between linux-gnuoldld and linux-gnuaout.
+ # If ld does not provide *any* "supported emulations:"
+ # that means it is gnuoldld.
+ echo "$ld_help_string" | grep >/dev/null 2>&1 "supported emulations:"
+ test $? != 0 && echo "${UNAME_MACHINE}-pc-linux-gnuoldld" && exit 0
+
+ case "${UNAME_MACHINE}" in
+ i?86)
+ VENDOR=pc;
+ ;;
+ *)
+ VENDOR=unknown;
+ ;;
+ esac
+ # Determine whether the default compiler is a.out or elf
+ cat >$dummy.c <<EOF
+#include <features.h>
+#ifdef __cplusplus
+ int main (int argc, char *argv[]) {
+#else
+ int main (argc, argv) int argc; char *argv[]; {
+#endif
+#ifdef __ELF__
+# ifdef __GLIBC__
+# if __GLIBC__ >= 2
+ printf ("%s-${VENDOR}-linux-gnu\n", argv[1]);
+# else
+ printf ("%s-${VENDOR}-linux-gnulibc1\n", argv[1]);
+# endif
+# else
+ printf ("%s-${VENDOR}-linux-gnulibc1\n", argv[1]);
+# endif
+#else
+ printf ("%s-${VENDOR}-linux-gnuaout\n", argv[1]);
+#endif
+ return 0;
+}
+EOF
+ $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null && ./$dummy "${UNAME_MACHINE}" && rm $dummy.c $dummy && exit 0
+ rm -f $dummy.c $dummy
+ fi ;;
+# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. earlier versions
+# are messed up and put the nodename in both sysname and nodename.
+ i?86:DYNIX/ptx:4*:*)
+ echo i386-sequent-sysv4
+ exit 0 ;;
+ i?86:UNIX_SV:4.2MP:2.*)
+ # Unixware is an offshoot of SVR4, but it has its own version
+ # number series starting with 2...
+ # I am not positive that other SVR4 systems won't match this,
+ # I just have to hope. -- rms.
+ # Use sysv4.2uw... so that sysv4* matches it.
+ echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
+ exit 0 ;;
+ i?86:UnixWare:5:7) # Unixware 7.0.0t (uname -v reports 7) has native threads
+ # uname -m incorrectly reports CPU type (uname -m reports i386 always)
+ # compiler supports following optimization flags:i386,i486,pentium,pentium_pro and blended
+ # compiler does NOT support: i586,i686,Pentium,Pentium Pro,pentiumpro,pentium_II or Pentium II
+ if /bin/uname machine 2>/dev/null >/dev/null ; then
+ (/bin/uname machine|egrep i80486 >/dev/null) && UNAME_MACHINE=i486
+ (/bin/uname machine|egrep 'Pentium' >/dev/null) && UNAME_MACHINE=pentium
+ (/bin/uname machine|egrep 'Pentium Pro' >/dev/null) && UNAME_MACHINE=pentium_pro
+ (/bin/uname machine|egrep 'Pentium II' >/dev/null) && UNAME_MACHINE=pentium_II
+ echo ${UNAME_MACHINE}-pc-unixware7.0.0
+ else
+ echo ${UNAME_MACHINE}-pc-unixware7.0.0
+ fi
+ exit 0 ;;
+ i?86:UnixWare:5:7.0.1) # Unixware 7.0.1 (uname -v reports 7.0.1) has POSIX threads
+ # uname -m incorrectly reports CPU type (uname -m reports i386 always)
+ # compiler supports following optimization flags:i386,i486,pentium,pentium_pro and blended
+ # compiler does NOT support: i586,i686,Pentium,Pentium Pro,pentiumpro,pentium_II or Pentium II
+ if /bin/uname machine 2>/dev/null >/dev/null ; then
+ (/bin/uname machine|egrep i80486 >/dev/null) && UNAME_MACHINE=i486
+ (/bin/uname machine|egrep 'Pentium' >/dev/null) && UNAME_MACHINE=pentium
+ (/bin/uname machine|egrep 'Pentium Pro' >/dev/null) && UNAME_MACHINE=pentium_pro
+ (/bin/uname machine|egrep 'Pentium II' >/dev/null) && UNAME_MACHINE=pentium_II
+ echo ${UNAME_MACHINE}-pc-unixware7.0.1
+ else
+ echo ${UNAME_MACHINE}-pc-unixware7.0.1
+ fi
+ exit 0 ;;
+ # SysVr5/Unixware7
+ i?86:*:5*:* | i?86:SYSTEM_V:5*:*)
+ if uname -a | grep SCO >/dev/null 2>/dev/null ; then
+ (/bin/uname -s|egrep UnixWare >/dev/null) && UNAME_VER=uw${UNAME_VERSION}
+ if /bin/uname -X 2>/dev/null >/dev/null ; then
+ (/bin/uname -X|egrep i80486 >/dev/null) && UNAME_MACHINE=i486
+ (/bin/uname -X|egrep '^Machine.*Pentium' >/dev/null) && UNAME_MACHINE=i586
+ fi
+ echo ${UNAME_MACHINE}-sco-sysv${UNAME_RELEASE}${UNAME_VER}
+ else
+ echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}
+ fi
+ exit 0 ;;
+
+ i?86:*:4.*:* | i?86:SYSTEM_V:4.*:*)
+ if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
+ echo ${UNAME_MACHINE}-univel-sysv${UNAME_RELEASE}
+ else
+ echo ${UNAME_MACHINE}-pc-sysv${UNAME_RELEASE}
+ fi
+ exit 0 ;;
+ i?86:*:5:7*)
+ UNAME_REL=`(/bin/uname -X|egrep Release|sed -e 's/.*= //')`
+ (/bin/uname -X|egrep i80486 >/dev/null) && UNAME_MACHINE=i486
+ (/bin/uname -X|egrep '^Machine.*Pentium' >/dev/null) && UNAME_MACHINE=i586
+ (/bin/uname -X|egrep '^Machine.*Pent.*II' >/dev/null) && UNAME_MACHINE=i686
+ (/bin/uname -X|egrep '^Machine.*Pentium Pro' >/dev/null) && UNAME_MACHINE=i585
+ echo ${UNAME_MACHINE}-${UNAME_SYSTEM}${UNAME_VERSION}-sysv${UNAME_RELEASE}
+ exit 0 ;;
+ i?86:*:3.2:*)
+ if test -f /usr/options/cb.name; then
+ UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
+ echo ${UNAME_MACHINE}-pc-isc$UNAME_REL
+ elif /bin/uname -X 2>/dev/null >/dev/null ; then
+ UNAME_REL=`(/bin/uname -X|egrep Release|sed -e 's/.*= //')`
+ (/bin/uname -X|egrep i80486 >/dev/null) && UNAME_MACHINE=i486
+ (/bin/uname -X|egrep '^Machine.*Pentium' >/dev/null) \
+ && UNAME_MACHINE=i586
+ (/bin/uname -X|egrep '^Machine.*Pent ?II' >/dev/null) \
+ && UNAME_MACHINE=i686
+ (/bin/uname -X|egrep '^Machine.*Pentium Pro' >/dev/null) \
+ && UNAME_MACHINE=i686
+ echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
+ else
+ echo ${UNAME_MACHINE}-pc-sysv32
+ fi
+ exit 0 ;;
+ pc:*:*:*)
+ # uname -m prints for DJGPP always 'pc', but it prints nothing about
+ # the processor, so we play safe by assuming i386.
+ echo i386-pc-msdosdjgpp
+ exit 0 ;;
+ Intel:Mach:3*:*)
+ echo i386-pc-mach3
+ exit 0 ;;
+ paragon:*:*:*)
+ echo i860-intel-osf1
+ exit 0 ;;
+ i860:*:4.*:*) # i860-SVR4
+ if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
+ echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
+ else # Add other i860-SVR4 vendors below as they are discovered.
+ echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4
+ fi
+ exit 0 ;;
+ mini*:CTIX:SYS*5:*)
+ # "miniframe"
+ echo m68010-convergent-sysv
+ exit 0 ;;
+ M68*:*:R3V[567]*:*)
+ test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;;
+ 3[34]??:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 4850:*:4.0:3.0)
+ OS_REL=''
+ test -r /etc/.relid \
+ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && echo i486-ncr-sysv4.3${OS_REL} && exit 0
+ /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+ && echo i586-ncr-sysv4.3${OS_REL} && exit 0 ;;
+ 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && echo i486-ncr-sysv4 && exit 0 ;;
+ m68*:LynxOS:2.*:*)
+ echo m68k-unknown-lynxos${UNAME_RELEASE}
+ exit 0 ;;
+ mc68030:UNIX_System_V:4.*:*)
+ echo m68k-atari-sysv4
+ exit 0 ;;
+ i?86:LynxOS:2.*:* | i?86:LynxOS:3.[01]*:*)
+ echo i386-unknown-lynxos${UNAME_RELEASE}
+ exit 0 ;;
+ TSUNAMI:LynxOS:2.*:*)
+ echo sparc-unknown-lynxos${UNAME_RELEASE}
+ exit 0 ;;
+ rs6000:LynxOS:2.*:* | PowerPC:LynxOS:2.*:*)
+ echo rs6000-unknown-lynxos${UNAME_RELEASE}
+ exit 0 ;;
+ SM[BE]S:UNIX_SV:*:*)
+ echo mips-dde-sysv${UNAME_RELEASE}
+ exit 0 ;;
+ RM*:ReliantUNIX-*:*:*)
+ echo mips-sni-sysv4
+ exit 0 ;;
+ RM*:SINIX-*:*:*)
+ echo mips-sni-sysv4
+ exit 0 ;;
+ *:SINIX-*:*:*)
+ if uname -p 2>/dev/null >/dev/null ; then
+ UNAME_MACHINE=`(uname -p) 2>/dev/null`
+ echo ${UNAME_MACHINE}-sni-sysv4
+ else
+ echo ns32k-sni-sysv
+ fi
+ exit 0 ;;
+ PENTIUM:CPunix:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
+ # says <Richard.M.Bartel@ccMail.Census.GOV>
+ echo i586-unisys-sysv4
+ exit 0 ;;
+ *:UNIX_System_V:4*:FTX*)
+ # From Gerald Hewes <hewes@openmarket.com>.
+ # How about differentiating between stratus architectures? -djm
+ echo hppa1.1-stratus-sysv4
+ exit 0 ;;
+ *:*:*:FTX*)
+ # From seanf@swdc.stratus.com.
+ echo i860-stratus-sysv4
+ exit 0 ;;
+ mc68*:A/UX:*:*)
+ echo m68k-apple-aux${UNAME_RELEASE}
+ exit 0 ;;
+ news*:NEWS-OS:*:6*)
+ echo mips-sony-newsos6
+ exit 0 ;;
+ R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
+ if [ -d /usr/nec ]; then
+ echo mips-nec-sysv${UNAME_RELEASE}
+ else
+ echo mips-unknown-sysv${UNAME_RELEASE}
+ fi
+ exit 0 ;;
+ BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only.
+ echo powerpc-be-beos
+ exit 0 ;;
+ BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only.
+ echo powerpc-apple-beos
+ exit 0 ;;
+ BePC:BeOS:*:*) # BeOS running on Intel PC compatible.
+ echo i586-pc-beos
+ exit 0 ;;
+ SX-4:SUPER-UX:*:*)
+ echo sx4-nec-superux${UNAME_RELEASE}
+ exit 0 ;;
+ SX-5:SUPER-UX:*:*)
+ echo sx5-nec-superux${UNAME_RELEASE}
+ exit 0 ;;
+ Power*:Rhapsody:*:*)
+ echo powerpc-apple-rhapsody${UNAME_RELEASE}
+ exit 0 ;;
+ *:Rhapsody:*:*)
+ echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE}
+ exit 0 ;;
+esac
+
+#echo '(No uname command or uname output not recognized.)' 1>&2
+#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2
+
+cat >$dummy.c <<EOF
+#ifdef _SEQUENT_
+# include <sys/types.h>
+# include <sys/utsname.h>
+#endif
+main ()
+{
+#if defined (sony)
+#if defined (MIPSEB)
+ /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed,
+ I don't know.... */
+ printf ("mips-sony-bsd\n"); exit (0);
+#else
+#include <sys/param.h>
+ printf ("m68k-sony-newsos%s\n",
+#ifdef NEWSOS4
+ "4"
+#else
+ ""
+#endif
+ ); exit (0);
+#endif
+#endif
+
+#if defined (__arm) && defined (__acorn) && defined (__unix)
+ printf ("arm-acorn-riscix"); exit (0);
+#endif
+
+#if defined (hp300) && !defined (hpux)
+ printf ("m68k-hp-bsd\n"); exit (0);
+#endif
+
+#if defined (NeXT)
+#if !defined (__ARCHITECTURE__)
+#define __ARCHITECTURE__ "m68k"
+#endif
+ int version;
+ version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
+ if (version < 4)
+ printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
+ else
+ printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version);
+ exit (0);
+#endif
+
+#if defined (MULTIMAX) || defined (n16)
+#if defined (UMAXV)
+ printf ("ns32k-encore-sysv\n"); exit (0);
+#else
+#if defined (CMU)
+ printf ("ns32k-encore-mach\n"); exit (0);
+#else
+ printf ("ns32k-encore-bsd\n"); exit (0);
+#endif
+#endif
+#endif
+
+#if defined (__386BSD__)
+ printf ("i386-pc-bsd\n"); exit (0);
+#endif
+
+#if defined (sequent)
+#if defined (i386)
+ printf ("i386-sequent-dynix\n"); exit (0);
+#endif
+#if defined (ns32000)
+ printf ("ns32k-sequent-dynix\n"); exit (0);
+#endif
+#endif
+
+#if defined (_SEQUENT_)
+ struct utsname un;
+
+ uname(&un);
+
+ if (strncmp(un.version, "V2", 2) == 0) {
+ printf ("i386-sequent-ptx2\n"); exit (0);
+ }
+ if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
+ printf ("i386-sequent-ptx1\n"); exit (0);
+ }
+ printf ("i386-sequent-ptx\n"); exit (0);
+
+#endif
+
+#if defined (vax)
+#if !defined (ultrix)
+ printf ("vax-dec-bsd\n"); exit (0);
+#else
+ printf ("vax-dec-ultrix\n"); exit (0);
+#endif
+#endif
+
+#if defined (alliant) && defined (i860)
+ printf ("i860-alliant-bsd\n"); exit (0);
+#endif
+
+ exit (1);
+}
+EOF
+
+$CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null && ./$dummy && rm $dummy.c $dummy && exit 0
+rm -f $dummy.c $dummy
+
+# Apollos put the system type in the environment.
+
+test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit 0; }
+
+# Convex versions that predate uname can use getsysinfo(1)
+
+if [ -x /usr/convex/getsysinfo ]
+then
+ case `getsysinfo -f cpu_type` in
+ c1*)
+ echo c1-convex-bsd
+ exit 0 ;;
+ c2*)
+ if getsysinfo -f scalar_acc
+ then echo c32-convex-bsd
+ else echo c2-convex-bsd
+ fi
+ exit 0 ;;
+ c34*)
+ echo c34-convex-bsd
+ exit 0 ;;
+ c38*)
+ echo c38-convex-bsd
+ exit 0 ;;
+ c4*)
+ echo c4-convex-bsd
+ exit 0 ;;
+ esac
+fi
+
+#echo '(Unable to guess system type)' 1>&2
+
+exit 1
diff --git a/config.sub b/config.sub
new file mode 100755
index 00000000000..a5b9229f850
--- /dev/null
+++ b/config.sub
@@ -0,0 +1,1227 @@
+#! /bin/sh
+# Configuration validation subroutine script, version 1.1.
+# Copyright (C) 1991, 92-97, 1998, 1999 Free Software Foundation, Inc.
+# This file is (in principle) common to ALL GNU software.
+# The presence of a machine in this file suggests that SOME GNU software
+# can handle that machine. It does not imply ALL GNU software can.
+#
+# 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.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Configuration subroutine to validate and canonicalize a configuration type.
+# Supply the specified configuration type as an argument.
+# If it is invalid, we print an error message on stderr and exit with code 1.
+# Otherwise, we print the canonical config type on stdout and succeed.
+
+# This file is supposed to be the same for all GNU packages
+# and recognize all the CPU types, system types and aliases
+# that are meaningful with *any* GNU software.
+# Each package is responsible for reporting which valid configurations
+# it does not support. The user should be able to distinguish
+# a failure to support a valid configuration from a meaningless
+# configuration.
+
+# The goal of this file is to map all the various variations of a given
+# machine specification into a single specification in the form:
+# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
+# or in some cases, the newer four-part form:
+# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
+# It is wrong to echo any other type of specification.
+
+if [ x$1 = x ]
+then
+ echo Configuration name missing. 1>&2
+ echo "Usage: $0 CPU-MFR-OPSYS" 1>&2
+ echo "or $0 ALIAS" 1>&2
+ echo where ALIAS is a recognized configuration type. 1>&2
+ exit 1
+fi
+
+# First pass through any local machine types.
+case $1 in
+ *local*)
+ echo $1
+ exit 0
+ ;;
+ *)
+ ;;
+esac
+
+# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
+# Here we must recognize all the valid KERNEL-OS combinations.
+maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
+case $maybe_os in
+ linux-gnu*)
+ os=-$maybe_os
+ basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
+ ;;
+ *)
+ basic_machine=`echo $1 | sed 's/-[^-]*$//'`
+ if [ $basic_machine != $1 ]
+ then os=`echo $1 | sed 's/.*-/-/'`
+ else os=; fi
+ ;;
+esac
+
+### Let's recognize common machines as not being operating systems so
+### that things like config.sub decstation-3100 work. We also
+### recognize some manufacturers as not being operating systems, so we
+### can provide default operating systems below.
+case $os in
+ -sun*os*)
+ # Prevent following clause from handling this invalid input.
+ ;;
+ -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \
+ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \
+ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
+ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
+ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
+ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
+ -apple)
+ os=
+ basic_machine=$1
+ ;;
+ -sim | -cisco | -oki | -wec | -winbond)
+ os=
+ basic_machine=$1
+ ;;
+ -scout)
+ ;;
+ -wrs)
+ os=vxworks
+ basic_machine=$1
+ ;;
+ -hiux*)
+ os=-hiuxwe2
+ ;;
+ -unixware7.0.0)
+ os=-unixware7.0.0
+ ;;
+ -unixware7.0.1)
+ os=-unixware7.0.1
+ ;;
+ -sco5)
+ os=-sco3.2v5
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco4)
+ os=-sco3.2v4
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco3.2.[4-9]*)
+ os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco3.2v[4-9]*)
+ # Don't forget version if it is 3.2v4 or newer.
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco*)
+ os=-sco3.2v2
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -udk*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -isc)
+ os=-isc2.2
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -clix*)
+ basic_machine=clipper-intergraph
+ ;;
+ -isc*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -lynx*)
+ os=-lynxos
+ ;;
+ -ptx*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'`
+ ;;
+ -windowsnt*)
+ os=`echo $os | sed -e 's/windowsnt/winnt/'`
+ ;;
+ -psos*)
+ os=-psos
+ ;;
+esac
+
+# Decode aliases for certain CPU-COMPANY combinations.
+case $basic_machine in
+ # Recognize the basic CPU types without company name.
+ # Some are omitted here because they have special meanings below.
+ tahoe | i860 | m32r | m68k | m68000 | m88k | ns32k | arc | arm \
+ | arme[lb] | pyramid | mn10200 | mn10300 | tron | a29k \
+ | 580 | i960 | h8300 \
+ | hppa | hppa1.0 | hppa1.1 | hppa2.0 | hppa2.0w | hppa2.0n \
+ | alpha | alphaev[4-7] | alphaev56 | alphapca5[67] \
+ | we32k | ns16k | clipper | i370 | sh | powerpc | powerpcle \
+ | 1750a | dsp16xx | pdp11 | mips16 | mips64 | mipsel | mips64el \
+ | mips64orion | mips64orionel | mipstx39 | mipstx39el \
+ | mips64vr4300 | mips64vr4300el | mips64vr4100 | mips64vr4100el \
+ | mips64vr5000 | miprs64vr5000el \
+ | sparc | sparclet | sparclite | sparc64 | sparcv9 | v850 | c4x \
+ | thumb | d10v)
+ basic_machine=$basic_machine-unknown
+ ;;
+ m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | z8k | v70 | h8500 | w65)
+ ;;
+
+ # We use `pc' rather than `unknown'
+ # because (1) that's what they normally are, and
+ # (2) the word "unknown" tends to confuse beginning users.
+ i[34567]86)
+ basic_machine=$basic_machine-pc
+ ;;
+ # Object if more than one company name word.
+ *-*-*)
+ echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+ exit 1
+ ;;
+ # Recognize the basic CPU types with company name.
+ vax-* | tahoe-* | i[34567]86-* | i860-* | m32r-* | m68k-* | m68000-* \
+ | m88k-* | sparc-* | ns32k-* | fx80-* | arc-* | arm-* | c[123]* \
+ | mips-* | pyramid-* | tron-* | a29k-* | romp-* | rs6000-* \
+ | power-* | none-* | 580-* | cray2-* | h8300-* | h8500-* | i960-* \
+ | xmp-* | ymp-* \
+ | hppa-* | hppa1.0-* | hppa1.1-* | hppa2.0-* | hppa2.0w-* | hppa2.0n-* \
+ | alpha-* | alphaev[4-7]-* | alphaev56-* | alphapca5[67]-* \
+ | we32k-* | cydra-* | ns16k-* | pn-* | np1-* | xps100-* \
+ | clipper-* | orion-* \
+ | sparclite-* | pdp11-* | sh-* | powerpc-* | powerpcle-* \
+ | sparc64-* | sparcv9-* | sparc86x-* | mips16-* | mips64-* | mipsel-* \
+ | mips64el-* | mips64orion-* | mips64orionel-* \
+ | mips64vr4100-* | mips64vr4100el-* | mips64vr4300-* | mips64vr4300el-* \
+ | mipstx39-* | mipstx39el-* \
+ | f301-* | armv*-* | t3e-* \
+ | m88110-* | m680[01234]0-* | m683?2-* | m68360-* | z8k-* | d10v-* \
+ | thumb-* | v850-* | d30v-* | tic30-* | c30-* | ia64-* )
+ ;;
+ # Recognize the various machine names and aliases which stand
+ # for a CPU type and a company and sometimes even an OS.
+ 386bsd)
+ basic_machine=i386-unknown
+ os=-bsd
+ ;;
+ 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
+ basic_machine=m68000-att
+ ;;
+ 3b*)
+ basic_machine=we32k-att
+ ;;
+ a29khif)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ adobe68k)
+ basic_machine=m68010-adobe
+ os=-scout
+ ;;
+ alliant | fx80)
+ basic_machine=fx80-alliant
+ ;;
+ altos | altos3068)
+ basic_machine=m68k-altos
+ ;;
+ am29k)
+ basic_machine=a29k-none
+ os=-bsd
+ ;;
+ amdahl)
+ basic_machine=580-amdahl
+ os=-sysv
+ ;;
+ amiga | amiga-*)
+ basic_machine=m68k-cbm
+ ;;
+ amigaos | amigados)
+ basic_machine=m68k-cbm
+ os=-amigaos
+ ;;
+ amigaunix | amix)
+ basic_machine=m68k-cbm
+ os=-sysv4
+ ;;
+ apollo68)
+ basic_machine=m68k-apollo
+ os=-sysv
+ ;;
+ apollo68bsd)
+ basic_machine=m68k-apollo
+ os=-bsd
+ ;;
+ aux)
+ basic_machine=m68k-apple
+ os=-aux
+ ;;
+ balance)
+ basic_machine=ns32k-sequent
+ os=-dynix
+ ;;
+ convex-c1)
+ basic_machine=c1-convex
+ os=-bsd
+ ;;
+ convex-c2)
+ basic_machine=c2-convex
+ os=-bsd
+ ;;
+ convex-c32)
+ basic_machine=c32-convex
+ os=-bsd
+ ;;
+ convex-c34)
+ basic_machine=c34-convex
+ os=-bsd
+ ;;
+ convex-c38)
+ basic_machine=c38-convex
+ os=-bsd
+ ;;
+ cray | ymp)
+ basic_machine=ymp-cray
+ os=-unicos
+ ;;
+ cray2)
+ basic_machine=cray2-cray
+ os=-unicos
+ ;;
+ [ctj]90-cray)
+ basic_machine=c90-cray
+ os=-unicos
+ ;;
+ crds | unos)
+ basic_machine=m68k-crds
+ ;;
+ da30 | da30-*)
+ basic_machine=m68k-da30
+ ;;
+ decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
+ basic_machine=mips-dec
+ ;;
+ delta | 3300 | motorola-3300 | motorola-delta \
+ | 3300-motorola | delta-motorola)
+ basic_machine=m68k-motorola
+ ;;
+ delta88)
+ basic_machine=m88k-motorola
+ os=-sysv3
+ ;;
+ dpx20 | dpx20-*)
+ basic_machine=rs6000-bull
+ os=-bosx
+ ;;
+ dpx2* | dpx2*-bull)
+ basic_machine=m68k-bull
+ os=-sysv3
+ ;;
+ ebmon29k)
+ basic_machine=a29k-amd
+ os=-ebmon
+ ;;
+ elxsi)
+ basic_machine=elxsi-elxsi
+ os=-bsd
+ ;;
+ encore | umax | mmax)
+ basic_machine=ns32k-encore
+ ;;
+ es1800 | OSE68k | ose68k | ose | OSE)
+ basic_machine=m68k-ericsson
+ os=-ose
+ ;;
+ fx2800)
+ basic_machine=i860-alliant
+ ;;
+ genix)
+ basic_machine=ns32k-ns
+ ;;
+ gmicro)
+ basic_machine=tron-gmicro
+ os=-sysv
+ ;;
+ h3050r* | hiux*)
+ basic_machine=hppa1.1-hitachi
+ os=-hiuxwe2
+ ;;
+ h8300hms)
+ basic_machine=h8300-hitachi
+ os=-hms
+ ;;
+ h8300xray)
+ basic_machine=h8300-hitachi
+ os=-xray
+ ;;
+ h8500hms)
+ basic_machine=h8500-hitachi
+ os=-hms
+ ;;
+ harris)
+ basic_machine=m88k-harris
+ os=-sysv3
+ ;;
+ hp300-*)
+ basic_machine=m68k-hp
+ ;;
+ hp300bsd)
+ basic_machine=m68k-hp
+ os=-bsd
+ ;;
+ hp300hpux)
+ basic_machine=m68k-hp
+ os=-hpux
+ ;;
+ hp3k9[0-9][0-9] | hp9[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hp9k2[0-9][0-9] | hp9k31[0-9])
+ basic_machine=m68000-hp
+ ;;
+ hp9k3[2-9][0-9])
+ basic_machine=m68k-hp
+ ;;
+ hp9k6[0-9][0-9] | hp6[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hp9k7[0-79][0-9] | hp7[0-79][0-9])
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k78[0-9] | hp78[0-9])
+ # FIXME: really hppa2.0-hp
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893)
+ # FIXME: really hppa2.0-hp
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[0-9][13679] | hp8[0-9][13679])
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[0-9][0-9] | hp8[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hppa-next)
+ os=-nextstep3
+ ;;
+ hppaosf)
+ basic_machine=hppa1.1-hp
+ os=-osf
+ ;;
+ hppro)
+ basic_machine=hppa1.1-hp
+ os=-proelf
+ ;;
+ i370-ibm* | ibm*)
+ basic_machine=i370-ibm
+ os=-mvs
+ ;;
+# I'm not sure what "Sysv32" means. Should this be sysv3.2?
+ i[34567]86v32)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv32
+ ;;
+ i[34567]86v4*)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv4
+ ;;
+ i[34567]86v)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv
+ ;;
+ i[34567]86sol2)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-solaris2
+ ;;
+ i386mach)
+ basic_machine=i386-mach
+ os=-mach
+ ;;
+ i386-vsta | vsta)
+ basic_machine=i386-unknown
+ os=-vsta
+ ;;
+ i386-go32 | go32)
+ basic_machine=i386-unknown
+ os=-go32
+ ;;
+ i386-mingw32 | mingw32)
+ basic_machine=i386-unknown
+ os=-mingw32
+ ;;
+ iris | iris4d)
+ basic_machine=mips-sgi
+ case $os in
+ -irix*)
+ ;;
+ *)
+ os=-irix4
+ ;;
+ esac
+ ;;
+ isi68 | isi)
+ basic_machine=m68k-isi
+ os=-sysv
+ ;;
+ m88k-omron*)
+ basic_machine=m88k-omron
+ ;;
+ magnum | m3230)
+ basic_machine=mips-mips
+ os=-sysv
+ ;;
+ merlin)
+ basic_machine=ns32k-utek
+ os=-sysv
+ ;;
+ miniframe)
+ basic_machine=m68000-convergent
+ ;;
+ *mint | *MiNT)
+ basic_machine=m68k-atari
+ os=-mint
+ ;;
+ mipsel*-linux*)
+ basic_machine=mipsel-unknown
+ os=-linux-gnu
+ ;;
+ mips*-linux*)
+ basic_machine=mips-unknown
+ os=-linux-gnu
+ ;;
+ mips3*-*)
+ basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
+ ;;
+ mips3*)
+ basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
+ ;;
+ monitor)
+ basic_machine=m68k-rom68k
+ os=-coff
+ ;;
+ msdos)
+ basic_machine=i386-unknown
+ os=-msdos
+ ;;
+ ncr3000)
+ basic_machine=i486-ncr
+ os=-sysv4
+ ;;
+ netbsd386)
+ basic_machine=i386-unknown
+ os=-netbsd
+ ;;
+ netwinder)
+ basic_machine=armv4l-corel
+ os=-linux
+ ;;
+ news | news700 | news800 | news900)
+ basic_machine=m68k-sony
+ os=-newsos
+ ;;
+ news1000)
+ basic_machine=m68030-sony
+ os=-newsos
+ ;;
+ news-3600 | risc-news)
+ basic_machine=mips-sony
+ os=-newsos
+ ;;
+ necv70)
+ basic_machine=v70-nec
+ os=-sysv
+ ;;
+ next | m*-next )
+ basic_machine=m68k-next
+ case $os in
+ -nextstep* )
+ ;;
+ -ns2*)
+ os=-nextstep2
+ ;;
+ *)
+ os=-nextstep3
+ ;;
+ esac
+ ;;
+ nh3000)
+ basic_machine=m68k-harris
+ os=-cxux
+ ;;
+ nh[45]000)
+ basic_machine=m88k-harris
+ os=-cxux
+ ;;
+ nindy960)
+ basic_machine=i960-intel
+ os=-nindy
+ ;;
+ mon960)
+ basic_machine=i960-intel
+ os=-mon960
+ ;;
+ np1)
+ basic_machine=np1-gould
+ ;;
+ op50n-* | op60c-*)
+ basic_machine=hppa1.1-oki
+ os=-proelf
+ ;;
+ OSE68000 | ose68000)
+ basic_machine=m68000-ericsson
+ os=-ose
+ ;;
+ os68k)
+ basic_machine=m68k-none
+ os=-os68k
+ ;;
+ pa-hitachi)
+ basic_machine=hppa1.1-hitachi
+ os=-hiuxwe2
+ ;;
+ paragon)
+ basic_machine=i860-intel
+ os=-osf
+ ;;
+ pbd)
+ basic_machine=sparc-tti
+ ;;
+ pbb)
+ basic_machine=m68k-tti
+ ;;
+ pc532 | pc532-*)
+ basic_machine=ns32k-pc532
+ ;;
+ pentium | p5 | k5 | k6 | nexen)
+ basic_machine=i586-pc
+ ;;
+ pentiumpro | p6 | 6x86)
+ basic_machine=i686-pc
+ ;;
+ pentiumii | pentium2)
+ basic_machine=i786-pc
+ ;;
+ pentium-* | p5-* | k5-* | k6-* | nexen-*)
+ basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentiumpro-* | p6-* | 6x86-*)
+ basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentiumii-* | pentium2-*)
+ basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pn)
+ basic_machine=pn-gould
+ ;;
+ power) basic_machine=rs6000-ibm
+ ;;
+ ppc) basic_machine=powerpc-unknown
+ ;;
+ ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ppcle | powerpclittle | ppc-le | powerpc-little)
+ basic_machine=powerpcle-unknown
+ ;;
+ ppcle-* | powerpclittle-*)
+ basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ps2)
+ basic_machine=i386-ibm
+ ;;
+ rom68k)
+ basic_machine=m68k-rom68k
+ os=-coff
+ ;;
+ rm[46]00)
+ basic_machine=mips-siemens
+ ;;
+ rtpc | rtpc-*)
+ basic_machine=romp-ibm
+ ;;
+ sa29200)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ sequent)
+ basic_machine=i386-sequent
+ ;;
+ sh)
+ basic_machine=sh-hitachi
+ os=-hms
+ ;;
+ sparclite-wrs)
+ basic_machine=sparclite-wrs
+ os=-vxworks
+ ;;
+ sps7)
+ basic_machine=m68k-bull
+ os=-sysv2
+ ;;
+ spur)
+ basic_machine=spur-unknown
+ ;;
+ st2000)
+ basic_machine=m68k-tandem
+ ;;
+ stratus)
+ basic_machine=i860-stratus
+ os=-sysv4
+ ;;
+ sun2)
+ basic_machine=m68000-sun
+ ;;
+ sun2os3)
+ basic_machine=m68000-sun
+ os=-sunos3
+ ;;
+ sun2os4)
+ basic_machine=m68000-sun
+ os=-sunos4
+ ;;
+ sun3os3)
+ basic_machine=m68k-sun
+ os=-sunos3
+ ;;
+ sun3os4)
+ basic_machine=m68k-sun
+ os=-sunos4
+ ;;
+ sun4os3)
+ basic_machine=sparc-sun
+ os=-sunos3
+ ;;
+ sun4os4)
+ basic_machine=sparc-sun
+ os=-sunos4
+ ;;
+ sun4sol2)
+ basic_machine=sparc-sun
+ os=-solaris2
+ ;;
+ sun3 | sun3-*)
+ basic_machine=m68k-sun
+ ;;
+ sun4)
+ basic_machine=sparc-sun
+ ;;
+ sun386 | sun386i | roadrunner)
+ basic_machine=i386-sun
+ ;;
+ symmetry)
+ basic_machine=i386-sequent
+ os=-dynix
+ ;;
+ t3e)
+ basic_machine=t3e-cray
+ os=-unicos
+ ;;
+ tx39)
+ basic_machine=mipstx39-unknown
+ ;;
+ tx39el)
+ basic_machine=mipstx39el-unknown
+ ;;
+ tower | tower-32)
+ basic_machine=m68k-ncr
+ ;;
+ udi29k)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ ultra3)
+ basic_machine=a29k-nyu
+ os=-sym1
+ ;;
+ v810 | necv810)
+ basic_machine=v810-nec
+ os=-none
+ ;;
+ vaxv)
+ basic_machine=vax-dec
+ os=-sysv
+ ;;
+ vms)
+ basic_machine=vax-dec
+ os=-vms
+ ;;
+ vpp*|vx|vx-*)
+ basic_machine=f301-fujitsu
+ ;;
+ vxworks960)
+ basic_machine=i960-wrs
+ os=-vxworks
+ ;;
+ vxworks68)
+ basic_machine=m68k-wrs
+ os=-vxworks
+ ;;
+ vxworks29k)
+ basic_machine=a29k-wrs
+ os=-vxworks
+ ;;
+ w65*)
+ basic_machine=w65-wdc
+ os=-none
+ ;;
+ w89k-*)
+ basic_machine=hppa1.1-winbond
+ os=-proelf
+ ;;
+ xmp)
+ basic_machine=xmp-cray
+ os=-unicos
+ ;;
+ xps | xps100)
+ basic_machine=xps100-honeywell
+ ;;
+ z8k-*-coff)
+ basic_machine=z8k-unknown
+ os=-sim
+ ;;
+ none)
+ basic_machine=none-none
+ os=-none
+ ;;
+
+# Here we handle the default manufacturer of certain CPU types. It is in
+# some cases the only manufacturer, in others, it is the most popular.
+ w89k)
+ basic_machine=hppa1.1-winbond
+ ;;
+ op50n)
+ basic_machine=hppa1.1-oki
+ ;;
+ op60c)
+ basic_machine=hppa1.1-oki
+ ;;
+ mips)
+ if [ x$os = x-linux-gnu ]; then
+ basic_machine=mips-unknown
+ else
+ basic_machine=mips-mips
+ fi
+ ;;
+ romp)
+ basic_machine=romp-ibm
+ ;;
+ rs6000)
+ basic_machine=rs6000-ibm
+ ;;
+ vax)
+ basic_machine=vax-dec
+ ;;
+ pdp11)
+ basic_machine=pdp11-dec
+ ;;
+ we32k)
+ basic_machine=we32k-att
+ ;;
+ sparc | sparcv9)
+ basic_machine=sparc-sun
+ ;;
+ cydra)
+ basic_machine=cydra-cydrome
+ ;;
+ orion)
+ basic_machine=orion-highlevel
+ ;;
+ orion105)
+ basic_machine=clipper-highlevel
+ ;;
+ mac | mpw | mac-mpw)
+ basic_machine=m68k-apple
+ ;;
+ pmac | pmac-mpw)
+ basic_machine=powerpc-apple
+ ;;
+ c4x*)
+ basic_machine=c4x-none
+ os=-coff
+ ;;
+ *)
+ echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+ exit 1
+ ;;
+esac
+
+# Here we canonicalize certain aliases for manufacturers.
+case $basic_machine in
+ *-digital*)
+ basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'`
+ ;;
+ *-commodore*)
+ basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'`
+ ;;
+ *)
+ ;;
+esac
+
+# Decode manufacturer-specific aliases for certain operating systems.
+
+if [ x"$os" != x"" ]
+then
+case $os in
+ # First match some system type aliases
+ # that might get confused with valid system types.
+ # -solaris* is a basic system type, with this one exception.
+ -solaris1 | -solaris1.*)
+ os=`echo $os | sed -e 's|solaris1|sunos4|'`
+ ;;
+ -solaris)
+ os=-solaris2
+ ;;
+ -svr4*)
+ os=-sysv4
+ ;;
+ -unixware7.0.0)
+ os=-unixware7.0.0
+ ;;
+ -unixware7.0.1)
+ os=-unixware7.0.1
+ ;;
+ -unixware*)
+ os=-sysv4.2uw
+ ;;
+ -gnu/linux*)
+ os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
+ ;;
+ # First accept the basic system types.
+ # The portable systems comes first.
+ # Each alternative MUST END IN A *, to match a version number.
+ # -sysv* is not here because it comes later, after sysvr4.
+ -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
+ | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\
+ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \
+ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
+ | -aos* \
+ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
+ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
+ | -hiux* | -386bsd* | -netbsd* | -openbsd* | -freebsd* | -riscix* \
+ | -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
+ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
+ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
+ | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
+ | -mingw32* | -linux-gnu* | -uxpv* | -beos* | -mpeix* | -udk* \
+ | -interix* | -uwin* | -rhapsody* | -openstep* | -oskit*)
+ # Remember, each alternative MUST END IN *, to match a version number.
+ ;;
+ -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
+ | -windows* | -osx | -abug | -netware* | -os9* | -beos* \
+ | -macos* | -mpw* | -magic* | -mon960* | -lnews*)
+ ;;
+ -mac*)
+ os=`echo $os | sed -e 's|mac|macos|'`
+ ;;
+ -linux*)
+ os=`echo $os | sed -e 's|linux|linux-gnu|'`
+ ;;
+ -sunos5*)
+ os=`echo $os | sed -e 's|sunos5|solaris2|'`
+ ;;
+ -sunos6*)
+ os=`echo $os | sed -e 's|sunos6|solaris3|'`
+ ;;
+ -osfrose*)
+ os=-osfrose
+ ;;
+ -osf*)
+ os=-osf
+ ;;
+ -utek*)
+ os=-bsd
+ ;;
+ -dynix*)
+ os=-bsd
+ ;;
+ -acis*)
+ os=-aos
+ ;;
+ -386bsd)
+ os=-bsd
+ ;;
+ -ctix* | -uts*)
+ os=-sysv
+ ;;
+ -ns2 )
+ os=-nextstep2
+ ;;
+ # Preserve the version number of sinix5.
+ -sinix5.*)
+ os=`echo $os | sed -e 's|sinix|sysv|'`
+ ;;
+ -sinix*)
+ os=-sysv4
+ ;;
+ -triton*)
+ os=-sysv3
+ ;;
+ -oss*)
+ os=-sysv3
+ ;;
+ -svr4)
+ os=-sysv4
+ ;;
+ -svr3)
+ os=-sysv3
+ ;;
+ -sysvr4)
+ os=-sysv4
+ ;;
+ # This must come after -sysvr4.
+ -sysv*)
+ ;;
+ -ose*)
+ os=-ose
+ ;;
+ -es1800*)
+ os=-ose
+ ;;
+ -xenix)
+ os=-xenix
+ ;;
+ -*mint | -*MiNT)
+ os=-mint
+ ;;
+ -none)
+ ;;
+ *)
+ # Get rid of the `-' at the beginning of $os.
+ os=`echo $os | sed 's/[^-]*-//'`
+ echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2
+ exit 1
+ ;;
+esac
+else
+
+# Here we handle the default operating systems that come with various machines.
+# The value should be what the vendor currently ships out the door with their
+# machine or put another way, the most popular os provided with the machine.
+
+# Note that if you're going to try to match "-MANUFACTURER" here (say,
+# "-sun"), then you have to tell the case statement up towards the top
+# that MANUFACTURER isn't an operating system. Otherwise, code above
+# will signal an error saying that MANUFACTURER isn't an operating
+# system, and we'll never get to this point.
+
+case $basic_machine in
+ *-acorn)
+ os=-riscix1.2
+ ;;
+ arm*-corel)
+ os=-linux
+ ;;
+ arm*-semi)
+ os=-aout
+ ;;
+ pdp11-*)
+ os=-none
+ ;;
+ *-dec | vax-*)
+ os=-ultrix4.2
+ ;;
+ m68*-apollo)
+ os=-domain
+ ;;
+ i386-sun)
+ os=-sunos4.0.2
+ ;;
+ m68000-sun)
+ os=-sunos3
+ # This also exists in the configure program, but was not the
+ # default.
+ # os=-sunos4
+ ;;
+ m68*-cisco)
+ os=-aout
+ ;;
+ mips*-cisco)
+ os=-elf
+ ;;
+ mips*-*)
+ os=-elf
+ ;;
+ *-tti) # must be before sparc entry or we get the wrong os.
+ os=-sysv3
+ ;;
+ sparc-* | *-sun)
+ os=-sunos4.1.1
+ ;;
+ *-be)
+ os=-beos
+ ;;
+ *-ibm)
+ os=-aix
+ ;;
+ *-wec)
+ os=-proelf
+ ;;
+ *-winbond)
+ os=-proelf
+ ;;
+ *-oki)
+ os=-proelf
+ ;;
+ *-hp)
+ os=-hpux
+ ;;
+ *-hitachi)
+ os=-hiux
+ ;;
+ i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
+ os=-sysv
+ ;;
+ *-cbm)
+ os=-amigaos
+ ;;
+ *-dg)
+ os=-dgux
+ ;;
+ *-dolphin)
+ os=-sysv3
+ ;;
+ m68k-ccur)
+ os=-rtu
+ ;;
+ m88k-omron*)
+ os=-luna
+ ;;
+ *-next )
+ os=-nextstep
+ ;;
+ *-sequent)
+ os=-ptx
+ ;;
+ *-crds)
+ os=-unos
+ ;;
+ *-ns)
+ os=-genix
+ ;;
+ i370-*)
+ os=-mvs
+ ;;
+ *-next)
+ os=-nextstep3
+ ;;
+ *-gould)
+ os=-sysv
+ ;;
+ *-highlevel)
+ os=-bsd
+ ;;
+ *-encore)
+ os=-bsd
+ ;;
+ *-sgi)
+ os=-irix
+ ;;
+ *-siemens)
+ os=-sysv4
+ ;;
+ *-masscomp)
+ os=-rtu
+ ;;
+ f301-fujitsu)
+ os=-uxpv
+ ;;
+ *-rom68k)
+ os=-coff
+ ;;
+ *-*bug)
+ os=-coff
+ ;;
+ *-apple)
+ os=-macos
+ ;;
+ *-atari*)
+ os=-mint
+ ;;
+ *)
+ os=-none
+ ;;
+esac
+fi
+
+# Here we handle the case where we know the os, and the CPU type, but not the
+# manufacturer. We pick the logical manufacturer.
+vendor=unknown
+case $basic_machine in
+ *-unknown)
+ case $os in
+ -riscix*)
+ vendor=acorn
+ ;;
+ -sunos*)
+ vendor=sun
+ ;;
+ -aix*)
+ vendor=ibm
+ ;;
+ -beos*)
+ vendor=be
+ ;;
+ -hpux*)
+ vendor=hp
+ ;;
+ -mpeix*)
+ vendor=hp
+ ;;
+ -hiux*)
+ vendor=hitachi
+ ;;
+ -unos*)
+ vendor=crds
+ ;;
+ -dgux*)
+ vendor=dg
+ ;;
+ -luna*)
+ vendor=omron
+ ;;
+ -genix*)
+ vendor=ns
+ ;;
+ -mvs*)
+ vendor=ibm
+ ;;
+ -ptx*)
+ vendor=sequent
+ ;;
+ -vxsim* | -vxworks*)
+ vendor=wrs
+ ;;
+ -aux*)
+ vendor=apple
+ ;;
+ -hms*)
+ vendor=hitachi
+ ;;
+ -mpw* | -macos*)
+ vendor=apple
+ ;;
+ -*mint | -*MiNT)
+ vendor=atari
+ ;;
+ esac
+ basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
+ ;;
+esac
+
+echo $basic_machine$os
diff --git a/configure.in b/configure.in
new file mode 100644
index 00000000000..6a7c90aea8a
--- /dev/null
+++ b/configure.in
@@ -0,0 +1,1839 @@
+dnl -*- ksh -*-
+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.22-beta)
+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=9: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
+MYSQL_NO_DASH_VERSION=`echo $VERSION | sed -e "s|-.*$||"`
+MYSQL_BASE_VERSION=`echo $MYSQL_NO_DASH_VERSION | sed -e "s|\.[[^.]]*$||"`
+F_PART=`echo $MYSQL_BASE_VERSION | sed -e "s|\.||g"| sed -e "s|[[a-zA-Z]]\+||"`
+L_PART=`echo $MYSQL_NO_DASH_VERSION | sed -e "s|^[[0-9]]\.[[0-9]]*\.||" | sed -e "s|^\(.\)$|0\\1|" | sed -e "s|[[a-z]]||"`
+MYSQL_VERSION_ID=${F_PART}${L_PART}
+
+# The port should be constant for a LONG time
+MYSQL_TCP_PORT_DEFAULT=3306
+MYSQL_UNIX_ADDR_DEFAULT="/tmp/mysql.sock"
+
+# Remember to add a directory sql/share/LANGUAGE
+AVAILABLE_LANGUAGES="\
+czech danish dutch english estonia french german greek hungarian \
+italian japanese korean norwegian norwegian-ny polish portuguese \
+romania russian slovak spanish swedish"
+
+#####
+#####
+
+AC_SUBST(MYSQL_NO_DASH_VERSION)
+AC_SUBST(MYSQL_BASE_VERSION)
+AC_SUBST(MYSQL_VERSION_ID)
+AC_SUBST(PROTOCOL_VERSION)
+AC_DEFINE_UNQUOTED(PROTOCOL_VERSION, $PROTOCOL_VERSION)
+AC_SUBST(DOT_FRM_VERSION)
+AC_DEFINE_UNQUOTED(DOT_FRM_VERSION, $DOT_FRM_VERSION)
+AC_SUBST(SHARED_LIB_VERSION)
+AC_SUBST(AVAILABLE_LANGUAGES)
+
+# Canonicalize the configuration name.
+SYSTEM_TYPE="$host_vendor-$host_os"
+MACHINE_TYPE="$host_cpu"
+AC_SUBST(SYSTEM_TYPE)
+AC_DEFINE_UNQUOTED(SYSTEM_TYPE, "$SYSTEM_TYPE")
+AC_SUBST(MACHINE_TYPE)
+AC_DEFINE_UNQUOTED(MACHINE_TYPE, "$MACHINE_TYPE")
+
+# Save some variables and the command line options for mysqlbug
+SAVE_CFLAGS="$CFLAGS"
+SAVE_CXXFLAGS="$CXXFLAGS"
+SAVE_LDFLAGS="$LDFLAGS"
+SAVE_CXXLDFLAGS="$CXXLDFLAGS"
+CONF_COMMAND="$0 $ac_configure_args"
+AC_SUBST(CONF_COMMAND)
+AC_SUBST(SAVE_CFLAGS)
+AC_SUBST(SAVE_CXXFLAGS)
+AC_SUBST(SAVE_LDFLAGS)
+AC_SUBST(SAVE_CXXLDFLAGS)
+AC_SUBST(CXXLDFLAGS)
+
+AC_PREREQ(2.12)dnl Minimum Autoconf version required.
+
+AM_MAINTAINER_MODE
+AC_ARG_PROGRAM
+AM_SANITY_CHECK
+# This is needed is SUBDIRS is set
+AC_PROG_MAKE_SET
+# This generates rules for webpage generation for the MySQL homepage.
+AM_CONDITIONAL(LOCAL, test -d ../web/SitePages)
+
+# This is need before AC_PROG_CC
+#
+
+if test "x${CFLAGS-}" = x ; then
+ cflags_is_set=no
+else
+ cflags_is_set=yes
+fi
+
+if test "x${CPPFLAGS-}" = x ; then
+ cppflags_is_set=no
+else
+ cppflags_is_set=yes
+fi
+
+if test "x${LDFLAGS-}" = x ; then
+ ldflags_is_set=no
+else
+ ldflags_is_set=yes
+fi
+
+# The following hack should ensure that configure doesn't add optimizing
+# or debugging flags to CFLAGS or CXXFLAGS
+CFLAGS="$CFLAGS "
+CXXFLAGS="$CXXFLAGS "
+
+dnl Checks for programs.
+AC_PROG_AWK
+AC_PROG_CC
+AC_PROG_CXX
+AC_PROG_CPP
+if test "$ac_cv_prog_gcc" = "yes"
+then
+ AS="$CC -c"
+ AC_SUBST(AS)
+else
+ AC_PATH_PROG(AS, as, as)
+fi
+# Still need ranlib for readline; local static use only so no libtool.
+AC_PROG_RANLIB
+# We use libtool
+AM_PROG_LIBTOOL
+
+#AC_LIBTOOL_DLOPEN AC_LIBTOOL_WIN32_DLL AC_DISABLE_FAST_INSTALL AC_DISABLE_SHARED AC_DISABLE_STATIC
+
+# AC_PROG_INSTALL We should only need a AM_PROG_INSTALL
+AC_PROG_INSTALL
+# Not critical since the generated file is distributed
+AC_PROG_YACC
+
+AC_MSG_CHECKING("return type of sprintf")
+
+#check the return type of sprintf
+AC_TRY_RUN([
+ int main()
+ {
+ char* s = "hello";
+ char buf[6];
+ if((int)sprintf(buf, s) == strlen(s))
+ return 0;
+
+ return -1;
+ }
+ ],
+AC_DEFINE(SPRINTF_RETURNS_INT) AC_MSG_RESULT("int"),
+ AC_TRY_RUN([
+ int main()
+ {
+ char* s = "hello";
+ char buf[6];
+ if((char*)sprintf(buf,s) == buf + strlen(s))
+ return 0;
+ return -1;
+ }
+], AC_DEFINE(SPRINTF_RETURNS_PTR) AC_MSG_RESULT("ptr"),
+ AC_DEFINE(SPRINTF_RETURNS_GARBAGE) AC_MSG_RESULT("garbage")))
+
+
+# option, cache_name, variable
+AC_DEFUN(AC_SYS_COMPILER_FLAG,
+[
+ AC_MSG_CHECKING($1)
+ OLD_CFLAGS="[$]CFLAGS"
+ AC_CACHE_VAL(mysql_cv_option_$2,
+ [
+ CFLAGS="[$]OLD_CFLAGS $1"
+ AC_TRY_RUN([int main(){exit(0);}],mysql_cv_option_$2=yes,mysql_cv_option_$2=no,mysql_cv_option_$2=no)
+ ])
+
+ CFLAGS="[$]OLD_CFLAGS"
+
+ if test x"[$]mysql_cv_option_$2" = "xyes" ; then
+ $3="[$]$3 $1"
+ AC_MSG_RESULT(yes)
+ $5
+ else
+ AC_MSG_RESULT(no)
+ $4
+ fi
+])
+
+# arch, option, cache_name, variable
+AC_DEFUN(AC_SYS_CPU_COMPILER_FLAG,
+[
+ if test "`uname -m 2>/dev/null`" = "$1" ; then
+ AC_SYS_COMPILER_FLAG($2,$3,$4)
+ fi
+])
+
+# os, option, cache_name, variable
+AC_DEFUN(AC_SYS_OS_COMPILER_FLAG,
+[
+ if test "x$mysql_cv_sys_os" = "x$1" ; then
+ AC_SYS_COMPILER_FLAG($2,$3,$4)
+ fi
+])
+
+# We need some special hacks when running slowaris
+AC_PATH_PROG(uname_prog, uname, no)
+
+# We should go through this and put all the explictly system dependent
+# stuff in one place
+AC_MSG_CHECKING(operating system)
+AC_CACHE_VAL(mysql_cv_sys_os,
+[
+if test "$uname_prog" != "no"; then
+ mysql_cv_sys_os="`uname`"
+else
+ mysql_cv_sys_os="Not Solaris"
+fi
+])
+AC_MSG_RESULT($mysql_cv_sys_os)
+
+# This should be rewritten to use $target_os
+case "$target_os" in
+ sco3.2v5*)
+ CFLAGS="$CFLAGS -DSCO"
+ LD='$(CC) $(CFLAGS)'
+ case "$CFLAGS" in
+ *-belf*)
+ AC_SYS_COMPILER_FLAG(-belf,sco_belf_option,CFLAGS,[],[
+ case "$LDFLAGS" in
+ *-belf*) ;;
+ *) echo "Adding -belf option to ldflags."
+ LDFLAGS="$LDFLAGS -belf"
+ ;;
+ esac
+ ])
+ ;;
+ *)
+ AC_SYS_COMPILER_FLAG(-belf,sco_belf_option,CFLAGS,[],[
+ case "$LDFLAGS" in
+ *-belf*) ;;
+ *)
+ echo "Adding -belf option to ldflags."
+ LDFLAGS="$LDFLAGS -belf"
+ ;;
+ esac
+ ])
+ ;;
+ esac
+ ;;
+ sysv5uw7*) LIBS="-lsocket -lnsl $LIBS"
+ if test "$GCC" != "yes"; then
+ # We are using built-in inline function
+ CFLAGS="$CFLAGS -Kalloca"
+ CXX="$CXX -DNO_CPLUSPLUS_ALLOCA"
+ else
+ CXX="$CXX -DNO_CPLUSPLUS_ALLOCA"
+ fi
+ ;;
+esac
+
+AC_SUBST(CC)
+AC_SUBST(CFLAGS)
+AC_SUBST(CXX)
+AC_SUBST(CXXFLAGS)
+AC_SUBST(LD)
+
+export CC CFLAGS LD LDFLAGS
+
+if test "$GXX" = "yes"
+then
+ # mysqld requires this when compiled with gcc
+ CXXFLAGS="$CXXFLAGS -fno-implicit-templates"
+fi
+
+# Avoid bug in fcntl on some versions of linux
+AC_MSG_CHECKING("if we should use 'skip-locking' as default for $target_os")
+# Any wariation of Linux
+if expr "$target_os" : "[[Ll]]inux.*" > /dev/null
+then
+ MYSQLD_DEFAULT_SWITCHES="--skip-locking"
+ IS_LINUX="true"
+ AC_MSG_RESULT("yes");
+else
+ MYSQLD_DEFAULT_SWITCHES=""
+ IS_LINUX="false"
+ AC_MSG_RESULT("no");
+fi
+AC_SUBST(MYSQLD_DEFAULT_SWITCHES)
+AC_SUBST(IS_LINUX)
+
+dnl Find paths to some shell programs
+AC_PATH_PROG(LN, ln, ln)
+# This must be able to take a -f flag like normal unix ln.
+AC_PATH_PROG(LN_CP_F, ln, ln)
+# If ln -f does not exists use -s (AFS systems)
+if test -n "$LN_CP_F"; then
+ LN_CP_F="$LN_CP_F -s"
+fi
+
+AC_PATH_PROG(MV, mv, mv)
+AC_PATH_PROG(RM, rm, rm)
+AC_PATH_PROG(CP, cp, cp)
+AC_PATH_PROG(SED, sed, sed)
+AC_PATH_PROG(CMP, cmp, cmp)
+AC_PATH_PROG(CHMOD, chmod, chmod)
+AC_PATH_PROG(HOSTNAME, hostname, hostname)
+dnl We use a path for perl so the script startup works
+AC_PATH_PROG(PERL5, perl5, no)
+AC_PATH_PROG(PERL, perl, no)
+if test "$PERL5" != no
+then
+ PERL=$PERL5
+ ac_cv_path_PERL=$ac_cv_path_PERL5
+fi
+AC_SUBST(HOSTNAME)
+AC_SUBST(PERL)
+AC_SUBST(PERL5)
+
+# Lock for PS
+AC_PATH_PROG(PS, ps, ps)
+AC_MSG_CHECKING("how to check if pid exists")
+PS=$ac_cv_path_PS
+# Linux style
+if $PS p $$ 2> /dev/null | grep $0 > /dev/null
+then
+ FIND_PROC="$PS p \$\$PID | grep mysqld > /dev/null"
+# Solaris
+elif $PS -p $$ 2> /dev/null | grep $0 > /dev/null
+then
+ FIND_PROC="$PS -p \$\$PID | grep mysqld > /dev/null"
+# BSD style
+elif $PS -uaxww 2> /dev/null | grep $0 > /dev/null
+then
+ FIND_PROC="$PS -uaxww | grep mysqld | grep \" \$\$PID \" > /dev/null"
+# SysV style
+elif $PS -ef 2> /dev/null | grep $0 > /dev/null
+then
+ FIND_PROC="$PS -ef | grep mysqld | grep \" \$\$PID \" > /dev/null"
+# Do anybody use this?
+elif $PS $$ 2> /dev/null | grep $0 > /dev/null
+then
+ FIND_PROC="$PS \$\$PID | grep mysqld > /dev/null"
+else
+ AC_MSG_ERROR([Could not find the right ps switches. Which OS is this ?. See the Installation chapter in the Reference Manual.])
+fi
+AC_SUBST(FIND_PROC)
+AC_MSG_RESULT("$FIND_PROC")
+
+# Check if a pid is valid
+AC_PATH_PROG(KILL, kill, kill)
+AC_MSG_CHECKING("for kill switches")
+if $ac_cv_path_KILL -0 $$
+then
+ CHECK_PID="$ac_cv_path_KILL -0 \$\$PID"
+elif kill -s 0 $$
+then
+ CHECK_PID="$ac_cv_path_KILL -s 0 \$\$PID"
+else
+ AC_MSG_WARN([kill -0 to check for pid seems to fail])
+ CHECK_PID="$ac_cv_path_KILL -s SIGCONT \$\$PID"
+fi
+AC_SUBST(CHECK_PID)
+AC_MSG_RESULT("$CHECK_PID")
+
+# We need a ANSI C compiler
+AM_PROG_CC_STDC
+
+if test "$am_cv_prog_cc_stdc" = "no"
+then
+ AC_MSG_ERROR([MySQL requiers a ANSI C compiler (and a C++ compiler). Try gcc. See the Installation chapter in the Reference Manual.])
+fi
+
+# Set flags if we wants to have MIT threads.
+AC_ARG_WITH(mit-threads,
+ [ --with-mit-threads Always use included thread lib.],
+ [ with_mit_threads=$withval ],
+ [ with_mit_threads=no ]
+ )
+
+if test "$with_mit_threads" = "yes"
+then
+ enable_largefile="no" # Will not work on Linux.
+fi
+
+# Set flags if we want to force to use pthreads
+AC_ARG_WITH(pthread,
+ [ --with-pthread Force use of pthread library.],
+ [ with_pthread=$withval ],
+ [ with_pthread=no ]
+ )
+
+# Force use of thread libs LIBS
+AC_ARG_WITH(named-thread-libs,
+ [ --with-named-thread-libs='-lib1 -lib2' Use libs instead of automatically-found thread libs.],
+ [ with_named_thread=$withval ],
+ [ with_named_thread=no ]
+ )
+
+# Force use of a curses libs
+AC_ARG_WITH(named-curses-libs,
+ [ --with-named-curses-libs='-lib1 -lib2' Use libs instead of automatically-found curses libs.],
+ [ with_named_curses=$withval ],
+ [ with_named_curses=no ]
+ )
+
+# Force use of a zlib (compress)
+AC_ARG_WITH(named-z-libs,
+ [ --with-named-z-libs='z' Use libs instead of automatically-found zlib libs.],
+ [ with_named_zlib=$withval ],
+ [ with_named_zlib=z ]
+ )
+
+AC_MSG_CHECKING(whether to use libwrap)
+AC_ARG_WITH(libwrap,
+[ --with-libwrap[=PATH] Compile in libwrap (tcp_wrappers) support.],
+[ case "$withval" in
+ no)
+ AC_MSG_RESULT(no)
+ ;;
+ yes)
+ AC_MSG_RESULT(yes)
+ AC_CHECK_LIB(wrap, request_init, [
+ AC_DEFINE(LIBWRAP)
+ WRAPLIBS="-lwrap"
+ AC_DEFINE(HAVE_LIBWRAP) ])
+ ;;
+ *)
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(LIBWRAP)
+ if test -d "$withval"; then
+ WRAPLIBS="-L$withval -lwrap"
+ else
+ WRAPLIBS="$withval"
+ fi
+ AC_DEFINE(HAVE_LIBWRAP)
+ OLDLIBS="$LIBS"
+ LIBS="$WRAPLIBS $LIBS"
+ AC_TRY_LINK([ int allow_severity; int deny_severity; ],
+ [ hosts_access(); ],
+ [],
+ [ AC_MSG_ERROR(Could not find the $withval library. You must first install tcp_wrappers.) ])
+ LIBS="$OLDLIBS"
+ ;;
+ esac ],
+ AC_MSG_RESULT(no)
+)
+
+AC_SUBST(WRAPLIBS)
+
+# Make thread safe client
+AC_ARG_ENABLE(thread-safe-client,
+ [ --enable-thread-safe-client Compile the client with threads.],
+ [ THREAD_SAFE_CLIENT=$enableval ],
+ [ THREAD_SAFE_CLIENT=no ]
+ )
+
+# Make thread safe client
+AC_ARG_ENABLE(assembler,
+ [ --enable-assembler Use assembler versions of some string functions if available.],
+ [ ENABLE_ASSEMBLER=$enableval ],
+ [ ENABLE_ASSEMBLER=no ]
+ )
+# For now we only support assembler on i386 and sparc systems
+AM_CONDITIONAL(ASSEMBLER_x86, test "$ENABLE_ASSEMBLER" = "yes" -a "$MACHINE_TYPE" = "i386")
+AM_CONDITIONAL(ASSEMBLER_sparc, test "$ENABLE_ASSEMBLER" = "yes" -a "$MACHINE_TYPE" = "sparc")
+AM_CONDITIONAL(ASSEMBLER, test ASSEMBLER_x86 = "" -o ASSEMBLER_x86 = "")
+
+AC_MSG_CHECKING(whether to use RAID)
+AC_ARG_WITH(raid,
+ [ --with-raid Compile in RAID (striping, mirroring, ...) support.],
+ [ AC_DEFINE(USE_RAID)
+ AC_MSG_RESULT(yes) ],
+ [ AC_MSG_RESULT(no) ]
+ )
+
+# Use this to set the place used for unix socket used to local communication.
+AC_ARG_WITH(unix-socket-path,
+ [ --with-unix-socket-path=absolute-file-name Where to put the unix-domain socket.],
+ [ MYSQL_UNIX_ADDR=$withval ],
+ [ MYSQL_UNIX_ADDR=$MYSQL_UNIX_ADDR_DEFAULT ]
+ )
+AC_SUBST(MYSQL_UNIX_ADDR)
+
+AC_ARG_WITH(tcp-port,
+ [ --with-tcp-port=port-number Which port to use for MySQL services (default $MYSQL_TCP_PORT_DEFAULT)],
+ [ MYSQL_TCP_PORT=$withval ],
+ [ MYSQL_TCP_PORT=$MYSQL_TCP_PORT_DEFAULT ]
+ )
+AC_SUBST(MYSQL_TCP_PORT)
+# We might want to document the assigned port in the manual.
+AC_SUBST(MYSQL_TCP_PORT_DEFAULT)
+
+# Use this to set the place used for unix socket used to local communication.
+AC_ARG_WITH(mysqld-user,
+ [ --with-mysqld-user=username What user mysqld daemon shall be run as.],
+ [ MYSQLD_USER=$withval ],
+ [ MYSQLD_USER=root ]
+ )
+AC_SUBST(MYSQLD_USER)
+
+# Use Paul Eggerts macros from GNU tar to check for large file
+# support.
+AC_SYS_LARGEFILE
+
+# Types that must be checked AFTER large file support is checked
+AC_TYPE_SIZE_T
+
+#--------------------------------------------------------------------
+# Check for system header files
+#--------------------------------------------------------------------
+
+AC_HEADER_DIRENT
+AC_HEADER_STDC
+AC_HEADER_SYS_WAIT
+AC_CHECK_HEADERS(fcntl.h float.h floatingpoint.h ieeefp.h limits.h \
+ memory.h pwd.h select.h \
+ stdlib.h stddef.h \
+ strings.h string.h synch.h sys/mman.h sys/socket.h netinet/in.h arpa/inet.h \
+ sys/timeb.h sys/types.h sys/un.h sys/vadvise.h sys/wait.h term.h \
+ unistd.h utime.h sys/utime.h termio.h termios.h sched.h crypt.h alloca.h)
+
+#--------------------------------------------------------------------
+# Check for system libraries. Adds the library to $LIBS
+# and defines HAVE_LIBM etc
+#--------------------------------------------------------------------
+
+AC_CHECK_LIB(m, floor)
+if test "$ac_cv_lib_m_floor" = "no"
+then
+ AC_CHECK_LIB(m, __infinity)
+fi
+AC_CHECK_LIB(nsl_r, gethostbyname_r)
+if test "$ac_cv_lib_nsl_r_gethostbyname_r" = "no"
+then
+ AC_CHECK_LIB(nsl, gethostbyname_r)
+fi
+LIBS_BEFORE_SOCKET=$LIBS
+LIBS=
+AC_CHECK_LIB(socket, socket)
+LIBS_SOCKET=$LIBS
+LIBS=
+AC_CHECK_LIB(gen, p2open)
+# This may get things to compile even if bind-8 is installed
+AC_CHECK_LIB(bind, bind)
+# For crypt() on Linux
+AC_CHECK_LIB(crypt,crypt)
+# For compress in zlib
+AC_CHECK_LIB($with_named_zlib,compress)
+
+if test "$IS_LINUX" = "true"; then
+ AC_MSG_CHECKING([for atomic operations])
+
+ atom_ops=
+ AC_TRY_RUN([
+#include <asm/atomic.h>
+int main()
+{
+ atomic_t v;
+
+ atomic_set(&v, 23);
+ atomic_add(5, &v);
+ return atomic_read(&v) == 28 ? 0 : -1;
+}
+ ], AC_DEFINE(HAVE_ATOMIC_ADD) atom_ops="${atom_ops}atomic_add ",
+ )
+ AC_TRY_RUN([
+#include <asm/atomic.h>
+int main()
+{
+ atomic_t v;
+
+ atomic_set(&v, 23);
+ atomic_sub(5, &v);
+ return atomic_read(&v) == 18 ? 0 : -1;
+}
+ ], AC_DEFINE(HAVE_ATOMIC_SUB) atom_ops="${atom_ops}atomic_sub ",
+ )
+
+ if test -z "$atom_ops"; then atom_ops="no"; fi
+ AC_MSG_RESULT($atom_ops)
+fi
+
+# Check for gtty if termio.h doesn't exists
+if test "$ac_cv_header_termio_h" = "no" -a "$ac_cv_header_termios_h" = "no"
+then
+ AC_CHECK_LIB(compat, gtty)
+fi
+# We make a special variable for client library's to avoid including
+# thread libs in the client.
+LIBS_AFTER_SOCKET=$LIBS
+LIBS="$LIBS_BEFORE_SOCKET $LIBS_SOCKET $LIBS_AFTER_SOCKET"
+NON_THREADED_CLIENT_LIBS="$LIBS"
+
+#
+# Some system specific hacks
+#
+
+case $SYSTEM_TYPE in
+ *solaris2.7*)
+ # Solaris 2.7 has a broken /usr/include/widec.h
+ # Make a fixed copy in ./include
+ echo "Fixing broken include files for $SYSTEM_TYPE"
+ echo " - Creating local copy of widec.h"
+ if test ! -d include
+ then
+ mkdir ./include
+ fi
+ builddir=`pwd`
+ sed -e "s|^#if[ ]*!defined(lint) && !defined(__lint)|#if !defined\(lint\) \&\& !defined\(__lint\) \&\& !defined\(getwc\)|" < /usr/include/widec.h > include/widec.h
+ CFLAGS="$CFLAGS -DHAVE_CURSES_H -I$builddir/include -DHAVE_RWLOCK_T"
+ CXXFLAGS="$CXXFLAGS -DHAVE_CURSES_H -I$builddir/include -DHAVE_RWLOCK_T"
+ ;;
+ *solaris2.5.1*)
+ echo "Enabling getpass() workaround for Solaris 2.5.1"
+ CFLAGS="$CFLAGS -DHAVE_BROKEN_GETPASS -DSOLARIS -DHAVE_RWLOCK_T";
+ CXXFLAGS="$CXXFLAGS -DHAVE_RWLOCK_T -DSOLARIS"
+ ;;
+ *solaris*)
+ CFLAGS="$CFLAGS -DHAVE_RWLOCK_T"
+ CXXFLAGS="$CXXFLAGS -DHAVE_RWLOCK_T"
+ ;;
+ *SunOS*)
+ echo "Enabling getpass() workaround for SunOS"
+ CFLAGS="$CFLAGS -DHAVE_BROKEN_GETPASS -DSOLARIS";
+ ;;
+ *hpux10.20*)
+ echo "Enabling snprintf workaround for hpux 10.20"
+ CFLAGS="$CFLAGS -DHAVE_BROKEN_SNPRINTF"
+ CXXFLAGS="$CXXFLAGS -DHAVE_BROKEN_SNPRINTF -D_INCLUDE_LONGLONG"
+ ;;
+ *hpux11.*)
+ echo "Enabling pread/pwrite workaround for hpux 11"
+ CFLAGS="$CFLAGS -DHAVE_BROKEN_PREAD -DDONT_USE_FINITE"
+ CXXFLAGS="$CXXFLAGS -DHAVE_BROKEN_PREAD -DDONT_USE_FINITE -D_INCLUDE_LONGLONG"
+ if test "$with_named_thread" = "no"
+ then
+ echo "Using --with-named-thread=-lpthread"
+ with_named_thread="-lpthread"
+ fi
+ ;;
+ *rhapsody*)
+ if test "$ac_cv_prog_gcc" = "yes"
+ then
+ CPPFLAGS="$CPPFLAGS -traditional-cpp "
+ CFLAGS="-DHAVE_CTHREADS_WRAPPER -DDO_NOT_REMOVE_THREAD_WRAPPERS"
+ CXXFLAGS="-DHAVE_CTHREADS_WRAPPER"
+ if test $with_named_curses = "no"
+ then
+ with_named_curses=""
+ fi
+ fi
+ ;;
+ *freebsd*)
+ echo "Adding fix for interrupted reads"
+ CXXFLAGS="$CXXFLAGS -DMYSQLD_NET_RETRY_COUNT=1000000"
+ ;;
+ *bsdi*)
+ echo "Adding fix for BSDI"
+ CFLAGS="$CFLAGS -D__BSD__"
+ ;;
+ *sgi-irix6*)
+ if test "$with_named_thread" = "no"
+ then
+ echo "Using --with-named-thread=-lpthread"
+ with_named_thread="-lpthread"
+ fi
+ CXXFLAGS="-D_BOOL"
+ ;;
+ *dec-osf4*)
+ echo "Adding fix to not use gethostbyname_r"
+ CFLAGS="$CFLAGS -DUNDEF_HAVE_GETHOSTBYNAME_R"
+ CXXFLAGS="$CXXFLAGS -DUNDEF_HAVE_GETHOSTBYNAME_R"
+ ;;
+ *aix4.3*)
+ echo "Adding defines for AIX"
+ CFLAGS="$CFLAGS -DHAVE_INT_8_16_32 -DUNDEF_HAVE_INITGROUPS"
+ CXXFLAGS="$CXXFLAGS -DHAVE_INT_8_16_32 -DUNDEF_HAVE_INITGROUPS"
+ ;;
+esac
+
+
+#---START: Used in for client configure
+# Check if we threads are in libc or if we should use
+# -lpthread, -lpthreads or mit-pthreads
+# We have to check libc last because else it fails on Solaris 2.6
+
+with_posix_threads="no"
+# Hack for DEC-UNIX (OSF1)
+if test "$with_named_thread" = "no" -a "$with_mit_threads" = "no"
+then
+ # Look for LinuxThreads.
+ AC_MSG_CHECKING("LinuxThreads")
+ res=`grep Linuxthreads /usr/include/pthread.h 2>/dev/null | wc -l`
+ if test "$res" -gt 0
+ then
+ AC_MSG_RESULT("Found")
+ AC_DEFINE(HAVE_LINUXTHREADS)
+ # Linux 2.0 sanity check
+ 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.
+ with_named_thread="-lpthread"
+ else
+ AC_MSG_RESULT("Not found")
+ # If this is a linux machine we should barf
+ if test "$IS_LINUX" = "true"
+ then
+ AC_MSG_ERROR([This is a linux system and Linuxthreads was not
+found. On linux Linuxthreads should be used. So install Linuxthreads
+(or a new glibc) and try again. See the Installation chapter in the
+Reference Manual.])
+ else
+ AC_MSG_CHECKING("DEC threads")
+ 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"
+ AC_DEFINE(HAVE_DEC_THREADS)
+ AC_MSG_RESULT("yes")
+ else
+ AC_MSG_RESULT("no")
+ AC_MSG_CHECKING("DEC 3.2 threads")
+ if test -f /usr/shlib/libpthreads.so -a -f /usr/lib/libmach.a -a -f /usr/ccs/lib/cmplrs/cc/libexc.a
+ then
+ with_named_thread="-lpthreads -lmach -lc_r"
+ AC_DEFINE(HAVE_DEC_THREADS)
+ AC_DEFINE(HAVE_DEC_3_2_THREADS)
+ with_osf32_threads="yes"
+ MYSQLD_DEFAULT_SWITCHES="--skip-thread-priority"
+ AC_MSG_RESULT("yes")
+ else
+ AC_MSG_RESULT("no")
+ fi
+ fi
+ fi
+ fi
+fi
+# Hack for SCO UNIX
+if test "$with_named_thread" = "no"
+then
+ AC_MSG_CHECKING("SCO threads")
+ if expr "$SYSTEM_TYPE" : ".*sco.*" > /dev/null
+ then
+ if test -f /usr/lib/libgthreads.a -o -f /usr/lib/libgthreads.so
+ then
+ LIBS="$LIBS_BEFORE_SOCKET $LIBS_AFTER_SOCKET"
+ with_named_thread="-lgthreads -lsocket -lgthreads"
+ # sched.h conflicts with fsu-threads
+ touch ./include/sched.h
+
+ # We must have gcc
+ if expr "$CC" : ".*gcc.*"
+ then
+ AC_MSG_RESULT("yes")
+ else
+ AC_MSG_ERROR([On SCO UNIX MySQL must be compiled with gcc. See the Installation chapter in the Reference Manual.]);
+ fi
+ AC_MSG_RESULT("yes")
+ elif test -f /usr/local/lib/libpthread.a -o -f /usr/local/lib/libpthread.so
+ then
+ LIBS="$LIBS_BEFORE_SOCKET $LIBS_AFTER_SOCKET"
+ with_named_thread="-lpthread -lsocket"
+ # sched.h conflicts with fsu-threads
+ # touch ./include/sched.h
+
+ AC_MSG_CHECKING("for gcc")
+ # We must have gcc
+ if expr "$CC" : ".*gcc.*"
+ then
+ AC_MSG_RESULT("yes")
+ else
+ AC_MSG_ERROR([On SCO UNIX MySQL must be compiled with gcc. See the Installation chapter in the Reference Manual.]);
+ fi
+ AC_MSG_RESULT("yes")
+ # Hack for SCO UnixWare 7.1
+ #
+ elif test "$with_named_thread" = "no"
+ then
+ AC_MSG_CHECKING("SCO UnixWare 7.1 native threads")
+ if expr "$SYSTEM_TYPE" : ".*sco.*" > /dev/null
+ then
+ if test -f /usr/lib/libthread.so -o -f /usr/lib/libthreadT.so
+ then
+ LIBS="$LIBS_BEFORE_SOCKET $LIBS_AFTER_SOCKET"
+ if expr "$CC" : ".*gcc.*"
+ then
+ with_named_thread="-pthread -lsocket -lnsl"
+ else
+ with_named_thread="-Kthread -lsocket -lnsl"
+ fi
+ if expr "$SYSTEM_TYPE" : ".*unixware7.0.0" > /dev/null
+ then
+ AC_DEFINE(HAVE_UNIXWARE7_THREADS)
+ else
+ AC_DEFINE(HAVE_UNIXWARE7_POSIX)
+ fi
+ # We must have cc
+ AC_MSG_CHECKING("for gcc")
+ if expr "$CC" : ".*gcc.*"
+ then
+ CC="$CC -pthread -DUNIXWARE_7";
+ CXX="$CXX -pthread -DUNIXWARE_7";
+ else
+ CC="$CC -Kthread -DUNIXWARE_7";
+ CXX="$CXX -Kthread -DUNIXWARE_7";
+ fi
+ AC_MSG_RESULT("yes")
+ else
+ { echo "configure: error: Can't find thread libs on SCO UnixWare7. See the Installation chapter in the Reference Manual." 1>&2; exit 1; };
+ fi
+ else
+ AC_MSG_RESULT("no")
+ fi
+ else
+ AC_MSG_ERROR([On SCO UNIX MySQL requires that the FSUThreads package is installed. See the Installation chapter in the Reference Manual.]);
+ fi
+ else
+ AC_MSG_RESULT("no")
+ fi
+fi
+# Hack for SCO UnixWare7
+#
+if test "$with_named_thread" = "no"
+then
+ AC_MSG_CHECKING("SCO UnixWare7 native threads")
+ if expr "$SYSTEM_TYPE" : ".*unixware7*" > /dev/null
+ then
+ if test -f /usr/lib/libthread.so -o -f /usr/lib/libthreadT.so
+ then
+ LIBS="$LIBS_BEFORE_SOCKET $LIBS_AFTER_SOCKET"
+ with_named_thread="-Kthread -lsocket -lnsl"
+ if expr "$SYSTEM_TYPE" : ".*unixware7.0.0" > /dev/null
+ then
+ AC_DEFINE(HAVE_UNIXWARE7_THREADS)
+ else
+ AC_DEFINE(HAVE_UNIXWARE7_POSIX)
+ fi
+ # We must have cc
+ AC_MSG_CHECKING("for gcc")
+ if expr "$CC" : ".*gcc.*"
+ then
+ { echo "configure: error: On SCO UnixWare7 MySQL must be compiled with cc. See the Installation chapter in the Reference Manual." 1>&2; exit 1; };
+ else
+ CC="$CC -Kthread -DUNIXWARE_7";
+ CXX="$CXX -Kthread -DUNIXWARE_7";
+ fi
+ AC_MSG_RESULT("yes")
+ else
+ { echo "configure: error: Can't find thread libs on SCO UnixWare7. See the Installation chapter in the Reference Manual." 1>&2; exit 1; };
+ fi
+ else
+ AC_MSG_RESULT("no")
+ fi
+fi
+
+# Hack for Siemens UNIX
+if test "$with_named_thread" = "no" -a "$with_mit_threads" = "no"
+then
+ AC_MSG_CHECKING("Siemens threads")
+ if test -f /usr/lib/libxnet.so -a "$SYSTEM_TYPE" = "sni-sysv4"
+ then
+ LIBS="$LIBS_BEFORE_SOCKET -lxnet $LIBS_AFTER_SOCKET"
+ NON_THREADED_CLIENT_LIBS="$NON_THREADED_CLIENT_LIBS -lxnet"
+ with_named_thread="-Kthread $LDFLAGS -lxnet"
+ LD_FLAGS=""
+ CFLAGS="-Kthread $CFLAGS"
+ CXXFLAGS="-Kthread $CXXFLAGS"
+ AC_MSG_RESULT("yes")
+ else
+ AC_MSG_RESULT("no")
+ fi
+fi
+
+# Use library named -lpthread
+if test "$with_named_thread" = "no" -a "$with_pthread" = "yes"
+then
+ with_named_thread="-lpthread"
+fi
+
+#---END:
+
+# Hack for Solaris >= 2.5
+# We want both the new and the old interface
+
+if test "$with_named_thread" = "no" -a "$with_mit_threads" = "no"
+then
+ AC_MSG_CHECKING("Solaris threads")
+ if test -f /usr/lib/libpthread.so -a -f /usr/lib/libthread.so
+ then
+ with_named_thread="-lpthread -lthread"
+ AC_MSG_RESULT("yes")
+ else
+ AC_MSG_RESULT("no")
+ fi
+fi
+
+# Should we use named pthread library ?
+AC_MSG_CHECKING("named thread libs:")
+if test "$with_named_thread" != "no"
+then
+ LIBS="$LIBS $with_named_thread"
+ with_posix_threads="yes"
+ with_mit_threads="no"
+ AC_MSG_RESULT("$with_named_thread")
+else
+ AC_MSG_RESULT("no")
+ if test "$with_mit_threads" = "no"
+ then
+ # pthread_create is in standard libraries (As in BSDI 3.0)
+ AC_MSG_CHECKING("for pthread_create in -libc");
+ AC_TRY_LINK(
+ [#include <pthread.h>],
+ [ (void) pthread_create((pthread_t*) 0,(pthread_attr_t*) 0, 0, 0); ],
+ with_posix_threads=yes, with_posix_threads=no)
+ AC_MSG_RESULT("$with_posix_threads")
+ if test "$with_posix_threads" = "no"
+ then
+ AC_MSG_CHECKING("for pthread_create in -lpthread");
+ ac_save_LIBS="$LIBS"
+ LIBS="$LIBS -lpthread"
+ AC_TRY_LINK(
+ [#include <pthread.h>],
+ [ (void) pthread_create((pthread_t*) 0,(pthread_attr_t*) 0, 0, 0); ],
+ with_posix_threads=yes, with_posix_threads=no)
+ AC_MSG_RESULT("$with_posix_threads")
+ if test "$with_posix_threads" = "no"
+ then
+ LIBS=" $ac_save_LIBS -lpthreads"
+ AC_MSG_CHECKING("for pthread_create in -lpthreads");
+ AC_TRY_LINK(
+ [#include <pthread.h>],
+ [ pthread_create((pthread_t*) 0,(pthread_attr_t*) 0, 0, 0); ],
+ with_posix_threads=yes, with_posix_threads=no)
+ AC_MSG_RESULT("$with_posix_threads")
+ if test "$with_posix_threads" = "no"
+ then
+ # This is for FreeBSD
+ LIBS="$ac_save_LIBS -pthread"
+ AC_MSG_CHECKING("for pthread_create in -pthread");
+ AC_TRY_LINK(
+ [#include <pthread.h>],
+ [ pthread_create((pthread_t*) 0,(pthread_attr_t*) 0, 0, 0); ],
+ with_posix_threads=yes, with_posix_threads=no)
+ AC_MSG_RESULT("$with_posix_threads")
+ if test "$with_posix_threads" = "no"
+ then
+ with_mit_threads="yes"
+ LIBS="$ac_save_LIBS"
+ fi
+ fi
+ fi
+ fi
+ fi
+fi
+
+#---START: Used in for client configure
+# Must be checked after, because strtok_r may be in -lpthread
+# On AIX strtok_r is in libc_r
+
+my_save_LIBS="$LIBS"
+AC_CHECK_LIB(pthread,strtok_r)
+LIBS="$my_save_LIBS"
+if test "$ac_cv_lib_pthread_strtok_r" = "no"
+then
+ my_save_LIBS="$LIBS"
+ AC_CHECK_LIB(c_r,strtok_r)
+ if test "$with_osf32_threads" = "yes" -o "$target_os" = "FreeBSD" -o "$target_os" = "freebsd"
+ then
+ LIBS="$my_save_LIBS"
+ fi
+ AC_CHECK_FUNCS(strtok_r pthread_init)
+else
+ AC_CHECK_FUNCS(strtok_r)
+fi
+#---END:
+
+if test "$THREAD_SAFE_CLIENT" = "no"
+then
+ CLIENT_LIBS=$NON_THREADED_CLIENT_LIBS
+else
+ CLIENT_LIBS=$LIBS
+ AC_DEFINE(THREAD_SAFE_CLIENT)
+fi
+AC_SUBST(CLIENT_LIBS)
+
+# for user definable functions (must be checked after threads on AIX)
+AC_CHECK_LIB(dl,dlopen)
+
+# System characteristics
+AC_SYS_RESTARTABLE_SYSCALLS
+
+# Build optimized or debug version ?
+# First check for gcc and g++
+if test "$ac_cv_prog_gcc" = "yes"
+then
+ DEBUG_CFLAGS="-g"
+ DEBUG_OPTIMIZE_CC="-O"
+ OPTIMIZE_CFLAGS="-O6"
+else
+ DEBUG_CFLAGS="-g"
+ DEBUG_OPTIMIZE_CC=""
+ OPTIMIZE_CFLAGS="-O"
+fi
+if test "$ac_cv_prog_cxx_g" = "yes"
+then
+ DEBUG_CXXFLAGS="-g"
+ DEBUG_OPTIMIZE_CXX="-O"
+ OPTIMIZE_CXXFLAGS="-O3"
+else
+ DEBUG_CXXFLAGS="-g"
+ DEBUG_OPTIMIZE_CXX=""
+ OPTIMIZE_CXXFLAGS="-O"
+fi
+AC_ARG_WITH(debug,
+ [ --without-debug Build a production version without debugging code],
+ [with_debug=$withval],
+ [with_debug=no])
+if test "$with_debug" = "yes"
+then
+ # Medium debug.
+ CFLAGS="$DEBUG_CFLAGS $DEBUG_OPTIMIZE_CC -DDBUG_ON -DSAFE_MUTEX $CFLAGS"
+ CXXFLAGS="$DEBUG_CXXFLAGS $DEBUG_OPTIMIZE_CXX -DSAFE_MUTEX $CXXFLAGS"
+elif test "$with_debug" = "full"
+then
+ # Full debug. Very slow in some cases
+ CFLAGS="$DEBUG_CFLAGS -DDBUG_ON -DSAFE_MUTEX -DSAFEMALLOC $CFLAGS"
+ CXXFLAGS="$DEBUG_CXXFLAGS -DSAFE_MUTEX -DSAFEMALLOC $CXXFLAGS"
+else
+ # Optimized version. No debug
+ CFLAGS="$OPTIMIZE_CFLAGS -DDBUG_OFF $CFLAGS"
+ CXXFLAGS="$OPTIMIZE_CXXFLAGS -DDBUG_OFF $CXXFLAGS"
+fi
+
+# Force static compilation to avoid linking probles/get more speed
+AC_ARG_WITH(mysqld-ldflags,
+ [ --with-mysqld-ldflags Extra linking arguments for mysqld],
+ [MYSQLD_EXTRA_LDFLAGS=$withval],
+ [MYSQLD_EXTRA_LDFLAGS=])
+AC_SUBST(MYSQLD_EXTRA_LDFLAGS)
+
+AC_ARG_WITH(client-ldflags,
+ [ --with-client-ldflags Extra linking arguments for clients],
+ [CLIENT_EXTRA_LDFLAGS=$withval],
+ [CLIENT_EXTRA_LDFLAGS=])
+AC_SUBST(CLIENT_EXTRA_LDFLAGS)
+
+# Avoid stupid bug on some OS
+AC_ARG_WITH(low-memory,
+ [ --with-low-memory Try to use less memory to compile to avoid memory limits],
+ [with_lowmem=$withval],
+ [with_lowmem=no])
+if test "$with_lowmem" = "yes"
+then
+ if test "$ac_cv_prog_gcc" = "yes"
+ then
+ LM_CFLAGS="-fno-inline"
+ else
+ LM_CFLAGS="-O0"
+ fi
+else
+ LM_CFLAGS=""
+fi
+AC_SUBST(LM_CFLAGS)
+
+AC_ARG_WITH(comment,
+ [ --with-comment Document compilation envrionment],
+ [with_comment=$withval],
+ [with_comment=no])
+if test "$with_comment" != "no"
+then
+ COMPILATION_COMMENT=$with_comment
+else
+ COMPILATION_COMMENT="Source distribution"
+fi
+AC_SUBST(COMPILATION_COMMENT)
+
+AC_MSG_CHECKING("need of special linking flags")
+if test "$IS_LINUX" = "true"
+then
+ LDFLAGS="$LDFLAGS -rdynamic"
+ AC_MSG_RESULT("-rdynamic")
+else
+ AC_MSG_RESULT("none")
+fi
+
+dnl Checks for typedefs, structures, and compiler characteristics.
+AC_C_CONST
+AC_C_INLINE
+AC_TYPE_OFF_T
+AC_STRUCT_ST_RDEV
+AC_HEADER_TIME
+AC_STRUCT_TM
+# AC_CHECK_SIZEOF return 0 when it does not find the size of a
+# type. We want a error instead.
+AC_CHECK_SIZEOF(char, 1)
+if test "$ac_cv_sizeof_char" -eq 0
+then
+ AC_MSG_ERROR([No size for char type.
+A likely cause for this could be that there isn't any
+static libraries installed. You can verify this by checking if you have libm.a
+in /lib, /usr/lib or some other standard place. If this is the problem,
+install the static libraries and try again. If this isn't the problem,
+examine config.log for possible errors. If you want to report this, use
+'scripts/mysqlbug' and include at least the last 20 rows from config.log!])
+fi
+AC_CHECK_SIZEOF(int, 4)
+if test "$ac_cv_sizeof_int" -eq 0
+then
+ AC_MSG_ERROR("No size for int type.")
+fi
+AC_CHECK_SIZEOF(long, 4)
+if test "$ac_cv_sizeof_long" -eq 0
+then
+ AC_MSG_ERROR("No size for long type.")
+fi
+AC_CHECK_SIZEOF(long long, 8)
+if test "$ac_cv_sizeof_long_long" -eq 0
+then
+ AC_MSG_ERROR("MySQL needs a long long type.")
+fi
+# off_t is not a builtin type
+MYSQL_CHECK_SIZEOF(off_t, 4)
+if test "$ac_cv_sizeof_off_t" -eq 0
+then
+ AC_MSG_ERROR("MySQL needs a off_t type.")
+fi
+# This always gives a warning. Ignore it unless you are cross compiling
+AC_C_BIGENDIAN
+#---START: Used in for client configure
+# Check base type of last arg to accept
+MYSQL_TYPE_ACCEPT
+#---END:
+# Find where the stack goes
+MYSQL_STACK_DIRECTION
+# We want to skip alloca on irix unconditionally. It may work on some version..
+MYSQL_FUNC_ALLOCA
+# Do struct timespec have members tv_sec or ts_sec
+MYSQL_TIMESPEC_TS
+# Do we have the tzname variable
+MYSQL_TZNAME
+# Do the system files define ulong
+MYSQL_CHECK_ULONG
+# Do the system files define uchar
+MYSQL_CHECK_UCHAR
+# Do the system files define uint
+MYSQL_CHECK_UINT
+#Check for fp_except in ieeefp.h
+MYSQL_CHECK_FP_EXCEPT
+# Do the c++ compiler have a bool type
+MYSQL_CXX_BOOL
+# Check some common bugs with gcc 2.8.# on sparc
+MYSQL_CHECK_LONGLONG_TO_FLOAT
+if test "$ac_cv_conv_longlong_to_float" != "yes"
+then
+ AC_MSG_ERROR([Your compiler can't convert a longlong value to a float!
+If you are using gcc 2.8.# you should upgrade to egcs 1.0.3 or newer and try
+again]);
+fi
+
+######################################################################
+# For readline-4.0 (We simply move the mimimum amount of stuff from
+# the readline configure.in here)
+
+MAKE_SHELL=/bin/sh
+AC_SUBST(MAKE_SHELL)
+
+# Already-done: stdlib.h string.h unistd.h termios.h
+AC_CHECK_HEADERS(varargs.h stdarg.h dirent.h locale.h ndir.h sys/dir.h \
+ sys/file.h sys/ndir.h sys/ptem.h sys/pte.h sys/select.h sys/stream.h \
+ curses.h termcap.h termio.h termbits.h asm/termbits.h grp.h)
+
+# Already-done: strcasecmp
+AC_CHECK_FUNCS(lstat putenv select setenv setlocale strcoll tcgetattr)
+
+AC_STAT_MACROS_BROKEN
+MYSQL_SIGNAL_CHECK
+MYSQL_CHECK_GETPW_FUNCS
+MYSQL_HAVE_TIOCGWINSZ
+MYSQL_HAVE_FIONREAD
+MYSQL_HAVE_TIOCSTAT
+MYSQL_STRUCT_DIRENT_D_INO
+MYSQL_TYPE_SIGHANDLER
+if test $with_named_curses = "no"
+then
+ MYSQL_CHECK_LIB_TERMCAP
+else
+ TERMCAP_LIB="$with_named_curses"
+fi
+AC_SUBST(TERMCAP_LIB)
+
+# End of readline stuff
+#########################################################################
+
+dnl Checks for library functions.
+AC_FUNC_MMAP
+AC_TYPE_SIGNAL
+MYSQL_TYPE_QSORT
+AC_FUNC_UTIME_NULL
+AC_FUNC_VPRINTF
+AC_CHECK_FUNCS(alarm bmove \
+ chsize ftruncate rint finite fpsetmask fpresetsticky\
+ cuserid fcntl fconvert \
+ getrusage getpwuid getcwd getrlimit getwd index stpcpy locking longjmp \
+ perror pread realpath rename \
+ socket strnlen madvise \
+ strtoul strtoull snprintf tempnam thr_setconcurrency \
+ gethostbyaddr_r gethostbyname_r getpwnam \
+ bfill bzero bcmp strstr strpbrk strerror\
+ tell atod memcpy memmove \
+ setupterm strcasecmp sighold \
+ vidattr setupterm lrand48 localtime_r \
+ sigset sigthreadmask pthread_sigmask pthread_setprio pthread_setprio_np \
+ pthread_setschedparam pthread_attr_setprio pthread_attr_setschedparam \
+ pthread_attr_create pthread_getsequence_np pthread_attr_setstacksize \
+ pthread_condattr_create rwlock_init pthread_rwlock_rdlock \
+ crypt compress dlopen dlerror fchmod getpass getpassphrase initgroups)
+
+# Sanity check: We chould not have any fseeko symbol unless
+# large_file_support=yes
+AC_CHECK_FUNCS(fseeko,
+[if test "$large_file_support" = no -a "$IS_LINUX" = "true";
+then
+ AC_MSG_ERROR("Found fseeko symbol but large_file_support is not enabled!");
+fi]
+)
+
+# Check definition of gethostbyaddr_r (glibc2 defines this with 8 arguments)
+ac_save_CXXFLAGS="$CXXFLAGS"
+AC_CACHE_CHECK([style of gethost* routines], mysql_cv_gethost_style,
+AC_LANG_SAVE
+AC_LANG_CPLUSPLUS
+if test "$ac_cv_prog_gxx" = "yes"
+then
+ CXXFLAGS="$CXXFLAGS -Werror"
+fi
+AC_TRY_COMPILE(
+[#ifndef SCO
+#define _REENTRANT
+#endif
+#include <pthread.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>],
+[int skr;
+ struct hostent *foo = gethostbyaddr_r((const char *) 0,
+ 0, 0, (struct hostent *) 0, (char *) NULL, 0, &skr); return (foo == 0);],
+mysql_cv_gethost_style=solaris, mysql_cv_gethost_style=other))
+AC_LANG_RESTORE
+CXXFLAGS="$ac_save_CXXFLAGS"
+if test "$mysql_cv_gethost_style" = "solaris"
+then
+ AC_DEFINE(HAVE_SOLARIS_STYLE_GETHOST)
+fi
+
+#---START: Used in for client configure
+
+# Check definition of gethostbyname_r (glibc2.0.100 is different from Solaris)
+ac_save_CXXFLAGS="$CXXFLAGS"
+AC_CACHE_CHECK([style of gethostname_r routines], mysql_cv_gethostname_style,
+AC_LANG_SAVE
+AC_LANG_CPLUSPLUS
+if test "$ac_cv_prog_gxx" = "yes"
+then
+ CXXFLAGS="$CXXFLAGS -Werror"
+fi
+AC_TRY_COMPILE(
+[#ifndef SCO
+#define _REENTRANT
+#endif
+#include <pthread.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>],
+[int skr;
+
+ skr = gethostbyname_r((const char *) 0,
+ (struct hostent*) 0, (char*) 0, 0, (struct hostent **) 0, &skr);],
+mysql_cv_gethostname_style=glibc2, mysql_cv_gethostname_style=other))
+AC_LANG_RESTORE
+CXXFLAGS="$ac_save_CXXFLAGS"
+if test "$mysql_cv_gethostname_style" = "glibc2"
+then
+ AC_DEFINE(HAVE_GLIBC2_STYLE_GETHOSTBYNAME_R)
+fi
+
+# Check 3rd argument of getthostbyname_r
+ac_save_CXXFLAGS="$CXXFLAGS"
+AC_CACHE_CHECK([3 argument to gethostname_r routines], mysql_cv_gethostname_arg,
+AC_LANG_SAVE
+AC_LANG_CPLUSPLUS
+if test "$ac_cv_prog_gxx" = "yes"
+then
+ CXXFLAGS="$CXXFLAGS -Werror"
+fi
+AC_TRY_COMPILE(
+[#ifndef SCO
+#define _REENTRANT
+#endif
+#include <pthread.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>],
+[int skr;
+
+ skr = gethostbyname_r((const char *) 0, (struct hostent*) 0, (hostent_data*) 0);],
+mysql_cv_gethostname_arg=hostent_data, mysql_cv_gethostname_arg=char))
+AC_LANG_RESTORE
+CXXFLAGS="$ac_save_CXXFLAGS"
+if test "$mysql_cv_gethostname_arg" = "hostent_data"
+then
+ AC_DEFINE(HAVE_GETHOSTBYNAME_R_WITH_HOSTENT_DATA)
+fi
+
+
+if test "$with_mit_threads" = "no"
+then
+ # Check definition of pthread_getspecific
+ AC_CACHE_CHECK("args to pthread_getspecific", mysql_cv_getspecific_args,
+ AC_TRY_COMPILE(
+[#ifndef SCO
+#define _REENTRANT
+#endif
+#define _POSIX_PTHREAD_SEMANTICS
+#include <pthread.h> ],
+[ void *pthread_getspecific(pthread_key_t key);
+pthread_getspecific((pthread_key_t) NULL); ],
+mysql_cv_getspecific_args=POSIX, mysql_cv_getspecific_args=other))
+ if test "$mysql_cv_getspecific_args" = "other"
+ then
+ AC_DEFINE(HAVE_NONPOSIX_PTHREAD_GETSPECIFIC)
+ fi
+
+ # Check definition of pthread_mutex_init
+ AC_CACHE_CHECK("args to pthread_mutex_init", mysql_cv_mutex_init_args,
+ AC_TRY_COMPILE(
+[#ifndef SCO
+#define _REENTRANT
+#endif
+#define _POSIX_PTHREAD_SEMANTICS
+#include <pthread.h> ],
+[
+ pthread_mutexattr_t attr;
+ pthread_mutex_t mp;
+ pthread_mutex_init(&mp,&attr); ],
+mysql_cv_mutex_init_args=POSIX, mysql_cv_mutex_init_args=other))
+ if test "$mysql_cv_mutex_init_args" = "other"
+ then
+ AC_DEFINE(HAVE_NONPOSIX_PTHREAD_MUTEX_INIT)
+ fi
+fi
+#---END:
+
+#---START: Used in for client configure
+# Check definition of readdir_r
+AC_CACHE_CHECK("args to readdir_r", mysql_cv_readdir_r,
+AC_TRY_LINK(
+[#ifndef SCO
+#define _REENTRANT
+#endif
+#define _POSIX_PTHREAD_SEMANTICS
+#include <pthread.h>
+#include <dirent.h>],
+[ int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result);
+readdir_r((DIR *) NULL, (struct dirent *) NULL, (struct dirent **) NULL); ],
+mysql_cv_readdir_r=POSIX, mysql_cv_readdir_r=other))
+if test "$mysql_cv_readdir_r" = "POSIX"
+then
+ AC_DEFINE(HAVE_READDIR_R)
+fi
+
+# Check definition av posix sigwait()
+AC_CACHE_CHECK("style of sigwait", mysql_cv_sigwait,
+AC_TRY_LINK(
+[#ifndef SCO
+#define _REENTRANT
+#endif
+#define _POSIX_PTHREAD_SEMANTICS
+#include <pthread.h>
+#include <signal.h>],
+[#ifndef _AIX
+sigset_t set;
+int sig;
+sigwait(&set,&sig);
+#endif],
+mysql_cv_sigwait=POSIX, mysql_cv_sigwait=other))
+if test "$mysql_cv_sigwait" = "POSIX"
+then
+ AC_DEFINE(HAVE_SIGWAIT)
+fi
+
+if test "$mysql_cv_sigwait" != "POSIX"
+then
+unset mysql_cv_sigwait
+# Check definition av posix sigwait()
+AC_CACHE_CHECK("style of sigwait", mysql_cv_sigwait,
+AC_TRY_LINK(
+[#ifndef SCO
+#define _REENTRANT
+#endif
+#define _POSIX_PTHREAD_SEMANTICS
+#include <pthread.h>
+#include <signal.h>],
+[sigset_t set;
+int sig;
+sigwait(&set);],
+mysql_cv_sigwait=NONPOSIX, mysql_cv_sigwait=other))
+if test "$mysql_cv_sigwait" = "NONPOSIX"
+then
+ AC_DEFINE(HAVE_NONPOSIX_SIGWAIT)
+fi
+fi
+#---END:
+
+# Check if pthread_attr_setscope() exists
+AC_CACHE_CHECK("for pthread_attr_setscope", mysql_cv_pthread_attr_setscope,
+AC_TRY_LINK(
+[#ifndef SCO
+#define _REENTRANT
+#endif
+#define _POSIX_PTHREAD_SEMANTICS
+#include <pthread.h>],
+[pthread_attr_t thr_attr;
+pthread_attr_setscope(&thr_attr,0);],
+mysql_cv_pthread_attr_setscope=yes, mysql_cv_pthread_attr_setscope=no))
+if test "$mysql_cv_pthread_attr_setscope" = "yes"
+then
+ AC_DEFINE(HAVE_PTHREAD_ATTR_SETSCOPE)
+fi
+
+# Check for bad includes
+AC_MSG_CHECKING("can netinet files be included")
+AC_TRY_COMPILE(
+[#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in_systm.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <netinet/tcp.h>],
+[ printf("1\n"); ],
+netinet_inc=yes, netinet_inc=no)
+if test "$netinet_inc" = "no"
+then
+ AC_DEFINE(HAVE_BROKEN_NETINET_INCLUDES)
+fi
+AC_MSG_RESULT("$netinet_inc")
+
+# Only build client code?
+AC_ARG_WITH(server,
+ [ --without-server Only build the client],
+ [with_server=$withval],
+ [with_server=yes]
+)
+
+# Shall we build the docs?
+AC_ARG_WITH(docs,
+ [ --without-docs Skip building of the documents],
+ [with_docs=$withval],
+ [with_docs=yes]
+)
+
+if test "$with_docs" = "yes"
+then
+ docs_dirs="Docs"
+else
+ docs_dirs=""
+fi
+AC_SUBST(docs_dirs)
+
+# Shall we build the bench code?
+AC_ARG_WITH(bench,
+ [ --without-bench Skip building of the benchmark],
+ [with_bench=$withval],
+ [with_bench=yes]
+)
+
+if test "$with_bench" = "yes"
+then
+ bench_dirs="sql-bench"
+else
+ bench_dirs=""
+fi
+AC_SUBST(bench_dirs)
+
+# Don't build readline, i have it already
+AC_ARG_WITH(readline,
+ [ --without-readline Use system readline instead of private copy],
+ [ with_readline=$withval ],
+ [ with_readline=yes ]
+ )
+if test "$with_readline" = "yes"
+then
+ readline_dir="readline"
+ readline_link="../readline/libreadline.a"
+else
+ # This requires readline to be in a standard place. Mosty for linux
+ # there readline may be a shared library.
+ readline_dir=""
+ readline_link="-lreadline"
+fi
+AC_SUBST(readline_dir)
+AC_SUBST(readline_link)
+
+# Choose a character set
+dnl in order to add new charset, you must add charset name to
+dnl CHARSETS_AVAILABLE list and add the charset name to
+dnl sql/share/charsets/Index. If the character set uses strcoll
+dnl or other special handling, you must also create
+dnl strings/ctype-$charset_name.c
+
+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 swe7 usa7 win1250 win1251 win1251ukr ujis sjis tis620"
+DEFAULT_CHARSET=latin1
+
+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 swe7 usa7 win1250 win1251 win1251ukr
+ ujis sjis tis620; default is latin1)],
+ [default_charset="$withval"],
+ [default_charset="$DEFAULT_CHARSET"])
+
+AC_ARG_WITH(extra-charsets,
+ [ --with-extra-charsets=cs1,cs2
+ use charsets in addition to default (none, complex,
+ all, or a list selected from the above sets)],
+ [extra_charsets="$withval"],
+ [extra_charsets="none"])
+
+AC_MSG_CHECKING("character sets")
+
+if test "$extra_charsets" = none; then
+ CHARSETS=""
+elif test "$extra_charsets" = complex; then
+ CHARSETS=`/bin/ls -1 $srcdir/strings/ctype-*.c | \
+ sed -e 's;^.*/ctype-;;' -e 's;.c$;;'`
+ CHARSETS=`echo $CHARSETS` # get rid of line breaks
+else
+ if test "$extra_charsets" = all; then
+ CHARSETS="$CHARSETS_AVAILABLE"
+ else
+ CHARSETS=`echo $extra_charsets | sed -e 's/,/ /g'`
+ fi
+fi
+
+# Ensure that the default_charset is first in CHARSETS
+TMP_CHARSETS="$default_charset "
+for i in $CHARSETS
+do
+ if test $i != $default_charset
+ then
+ TMP_CHARSETS="$TMP_CHARSETS $i"
+ fi
+done
+CHARSETS=$TMP_CHARSETS
+
+# Check if charsets are all good
+for cs in $CHARSETS
+do
+ charset_okay=0
+ for charset in $CHARSETS_AVAILABLE
+ do
+ if test $cs = $charset; then charset_okay=1; fi
+ done
+ if test $charset_okay = 0;
+ then
+ AC_MSG_ERROR([Charset $cs not available. (Available $CHARSETS_AVAILABLE).
+ See the Installation chapter in the Reference Manual.]);
+ fi
+done
+
+default_charset_has_source=0
+for cs in $COMPILED_CHARSETS
+do
+ if test $cs = $default_charset
+ then
+ default_charset_has_source=1
+ fi
+done
+
+CHARSET_SRCS=""
+CHARSETS_NEED_SOURCE=""
+CHARSET_DECLARATIONS=""
+CHARSET_COMP_CS_INIT="CHARSET_INFO compiled_charsets[[]] = {"
+
+want_use_strcoll=0
+want_use_mb=0
+
+index_file="$srcdir/sql/share/charsets/Index"
+
+for c in $CHARSETS
+do
+ # get the charset number from $index_file
+ subpat='^'"${c}"'[[\t ]]*#'
+ number=`$AWK 'sub("'"$subpat"'", "") { print }' $index_file`
+ # some sanity checking....
+ if test X"$number" = X
+ then
+ AC_MSG_ERROR([No number was found in $index_file for the $c character set. This is a bug in the MySQL distribution. Please report this message to bugs@lists.mysql.com.])
+ fi
+
+ cs_file="$srcdir/strings/ctype-$c.c"
+ if test -f $cs_file
+ then
+ CHARSET_SRCS="${CHARSET_SRCS}ctype-$c.c "
+ # get the strxfrm multiplier and max mb len from files
+ subpat='^.*\\.configure\\. strxfrm_multiply_'"${c}"'='
+ strx=`$AWK 'sub("'"$subpat"'", "") { print }' $cs_file`
+ subpat='^.*\\.configure\\. mbmaxlen_'"${c}"'='
+ maxl=`$AWK 'sub("'"$subpat"'", "") { print }' $cs_file`
+
+ CHARSET_DECLARATIONS="$CHARSET_DECLARATIONS
+
+/* declarations for the ${c} character set, filled in by configure */
+extern uchar ctype_${c}[[]], to_lower_${c}[[]], to_upper_${c}[[]], sort_order_${c}[[]];"
+ else
+ CHARSETS_NEED_SOURCE="$CHARSETS_NEED_SOURCE $c"
+ strx=''
+ maxl=''
+ fi
+
+ CHARSET_COMP_CS_INIT="$CHARSET_COMP_CS_INIT
+
+ /* this information is filled in by configure */
+ {
+ $number, /* number */
+ \"$c\", /* name */
+ ctype_${c},
+ to_lower_${c},
+ to_upper_${c},
+ sort_order_${c},"
+
+ if test -n "$strx"
+ then
+ want_use_strcoll=1
+
+ CHARSET_DECLARATIONS="$CHARSET_DECLARATIONS
+extern int my_strcoll_${c}(const uchar *, const uchar *);
+extern int my_strxfrm_${c}(uchar *, const uchar *, int);
+extern int my_strnncoll_${c}(const uchar *, int, const uchar *, int);
+extern int my_strnxfrm_${c}(uchar *, const uchar *, int, int);
+extern my_bool my_like_range_${c}(const char *, uint, pchar, uint,
+ char *, char *, uint *, uint *);"
+
+ CHARSET_COMP_CS_INIT="$CHARSET_COMP_CS_INIT
+ $strx, /* strxfrm_multiply */
+ my_strcoll_${c},
+ my_strxfrm_${c},
+ my_strnncoll_${c},
+ my_strnxfrm_${c},
+ my_like_range_${c},"
+ else
+ CHARSET_COMP_CS_INIT="$CHARSET_COMP_CS_INIT
+ 0, /* strxfrm_multiply */
+ NULL, /* strcoll */
+ NULL, /* strxfrm */
+ NULL, /* strnncoll */
+ NULL, /* strnxfrm */
+ NULL, /* like_range */"
+ fi
+
+ if test -n "$maxl"
+ then
+ want_use_mb=1
+
+ CHARSET_DECLARATIONS="$CHARSET_DECLARATIONS
+extern int ismbchar_${c}(const char *, const char *);
+extern my_bool ismbhead_${c}(uint);
+extern int mbcharlen_${c}(uint);"
+
+
+ CHARSET_COMP_CS_INIT="$CHARSET_COMP_CS_INIT
+ $maxl, /* mbmaxlen */
+ ismbchar_${c},
+ ismbhead_${c},
+ mbcharlen_${c}"
+ else
+ CHARSET_COMP_CS_INIT="$CHARSET_COMP_CS_INIT
+ 0, /* mbmaxlen */
+ NULL, /* ismbchar */
+ NULL, /* ismbhead */
+ NULL /* mbcharlen */"
+ fi
+ CHARSET_COMP_CS_INIT="$CHARSET_COMP_CS_INIT
+ },"
+done
+
+CHARSET_COMP_CS_INIT="$CHARSET_COMP_CS_INIT
+
+ /* this information is filled in by configure */
+ {
+ 0, /* end-of-list marker */
+ NullS,
+ \"\",
+ \"\",
+ \"\",
+ \"\",
+ 0,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ 0,
+ NULL,
+ NULL,
+ NULL
+ }
+};"
+
+
+if test $want_use_strcoll = 1
+then
+ AC_DEFINE(USE_STRCOLL)
+fi
+
+if test $want_use_mb = 1
+then
+ AC_DEFINE(USE_MB)
+ AC_DEFINE(USE_MB_IDENT)
+fi
+
+AC_SUBST(default_charset)
+AC_SUBST(CHARSET_SRCS)
+CHARSET_OBJS="`echo "$CHARSET_SRCS" | sed -e 's/\.c /.o /g'`"
+AC_SUBST(CHARSET_OBJS)
+AC_SUBST(CHARSETS_NEED_SOURCE)
+
+dnl We can't use AC_SUBST because these substitutions are too long.
+dnl I don't want to use sed, either, because there's a reason why
+dnl autoconf breaks up the substitution commands. So we'll just
+dnl write to a file and #include it.
+dnl AC_SUBST(CHARSET_DECLARATIONS)
+dnl AC_SUBST(CHARSET_COMP_CS_INIT)
+dnl sed -e "s%@CHARSET_DECLARATIONS@%$CHARSET_DECLARATIONS%g" \
+dnl -e "s%@CHARSET_COMP_CS_INIT@%$CHARSET_COMP_CS_INIT%g" \
+dnl $srcdir/strings/ctype.c.in > $srcdir/strings/ctype.c
+
+cat <<EOF > $srcdir/strings/ctype_autoconf.c
+/* This file is generated automatically by configure. */$CHARSET_DECLARATIONS
+
+$CHARSET_COMP_CS_INIT
+EOF
+
+AC_MSG_RESULT([default: $default_charset; compiled in: $CHARSETS])
+
+
+MYSQL_CHECK_BDB
+
+
+# If we have threads generate some library functions and test programs
+sql_server_dirs=
+server_scripts=
+if test "$with_server" = "yes"
+then
+ AC_DEFINE(THREAD)
+ # 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"
+ 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/build_unix $sql_server_dirs"
+
+ echo "CONFIGURING FOR BERKELEY DB"
+ (cd $bdb && cd build_unix && sh ../dist/configure) \
+ || AC_MSG_ERROR([could not configure Berkeley DB])
+
+ echo "Modifying Berkeley DB install target"
+ sed -e '/^install:/ c\
+install: all # modified by MySQL configure' \
+ "$bdb/build_unix/Makefile" > ac_BDB_Makefile
+
+ rm "$bdb/build_unix/Makefile" \
+ && cp ac_BDB_Makefile "$bdb/build_unix/Makefile" \
+ && rm ac_BDB_Makefile \
+ || AC_MSG_ERROR([could not modify Berkeley DB Makefile])
+
+ echo "END OF BERKELEY DB CONFIGURATION"
+ fi
+
+ AC_DEFINE(HAVE_BERKELEY_DB)
+ fi
+
+ if test "$with_posix_threads" = "no" -o "$with_mit_threads" = "yes"
+ then
+ # MIT user level threads
+ sql_server_dirs="mit-pthreads $sql_server_dirs"
+ AC_DEFINE(HAVE_mit_thread)
+ MT_INCLUDES="-I\$(top_srcdir)/mit-pthreads/include"
+ AC_SUBST(MT_INCLUDES)
+ MT_LD_ADD="\$(top_srcdir)/mit-pthreads/obj/libpthread.a"
+ AC_SUBST(MT_LD_ADD)
+ LIBS="$MT_LD_ADD $LIBS"
+ echo ""
+ echo "Configuring MIT Pthreads"
+ # We will never install so installation paths are not needed.
+ (cd mit-pthreads; sh ./configure)
+ echo "End of MIT Pthreads configuration"
+ echo ""
+ fi
+fi
+AC_SUBST(sql_server_dirs)
+AC_SUBST(server_scripts)
+
+if test "$with_posix_threads" = "no" -o "$with_mit_threads" = "yes"
+then
+ # MIT pthreads does not support connecting with unix sockets
+ AC_DEFINE(HAVE_THREADS_WITHOUT_SOCKETS)
+fi
+
+# Some usefull subst
+AC_SUBST(CC)
+AC_SUBST(GXX)
+
+# Output results
+AC_OUTPUT(Makefile extra/Makefile mysys/Makefile isam/Makefile \
+ strings/Makefile regex/Makefile heap/Makefile \
+ myisam/Makefile myisammrg/Makefile \
+ man/Makefile \
+ readline/Makefile libmysql/Makefile client/Makefile \
+ sql/Makefile sql/share/Makefile \
+ merge/Makefile dbug/Makefile scripts/Makefile \
+ include/Makefile sql-bench/Makefile \
+ tests/Makefile Docs/Makefile support-files/Makefile \
+ include/mysql_version.h
+ , , [test -z "$CONFIG_HEADERS" || echo timestamp > stamp-h])
+
+echo
+echo "MySQL has a Web site at http://www.mysql.com/ which carries details on the"
+echo "latest release, upcoming features, and other information to make your"
+echo "work or play with MySQL more productive. There you can also find"
+echo "information about mailing lists for MySQL discussion."
+echo
+echo "Remember to check the platform specific part in the reference manual for"
+echo "hints about installing on your platfrom. See the Docs directory."
+echo
+# This text is checked in ./Do-compile to se that the configure finished.
+echo "Thank you for choosing MySQL!"
+echo
diff --git a/dbug/.cvsignore b/dbug/.cvsignore
new file mode 100644
index 00000000000..e9955884756
--- /dev/null
+++ b/dbug/.cvsignore
@@ -0,0 +1,3 @@
+.deps
+Makefile
+Makefile.in
diff --git a/dbug/Makefile.am b/dbug/Makefile.am
new file mode 100644
index 00000000000..fac108ac238
--- /dev/null
+++ b/dbug/Makefile.am
@@ -0,0 +1,62 @@
+# 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
+
+INCLUDES = @MT_INCLUDES@ -I$(srcdir)/../include -I../include
+LDADD = libdbug.a ../strings/libmystrings.a
+pkglib_LIBRARIES = libdbug.a
+noinst_HEADERS = dbug_long.h
+libdbug_a_SOURCES = dbug.c sanity.c
+EXTRA_DIST = example1.c example2.c example3.c user.r monty.doc readme.prof \
+ main.c factorial.c
+
+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
+
+# Must be linked with libs thta are not compiled yet
+extra_progs: factorial dbug_analyze
+
+factorial: main.o factorial.o
+ @rm -f factorial
+ $(LINK) main.o factorial.o -lmysys
+
+dbug_analyze: dbug_analyze.o
+ @rm -f dbug_analyze
+ $(LINK) dbug_analyze.o -lmysys
+
+user.t: user.r $(NROFF_INC)
+ nroff -cm user.r > $@
+
+output1.r: $(PROGRAM)
+ factorial 1 2 3 4 5 | cat > $@
+
+output2.r: $(PROGRAM)
+ factorial -\#t:o 2 3 | cat >$@
+
+output3.r: $(PROGRAM)
+ factorial -\#d:t:o 3 | cat >$@
+
+output4.r: $(PROGRAM)
+ factorial -\#d,result:o 4 | cat >$@
+
+output5.r: $(PROGRAM)
+ factorial -\#d:f,factorial:F:L:o 3 | cat >$@
diff --git a/dbug/dbug.c b/dbug/dbug.c
new file mode 100644
index 00000000000..c004de587f2
--- /dev/null
+++ b/dbug/dbug.c
@@ -0,0 +1,2076 @@
+/******************************************************************************
+ * *
+ * N O T I C E *
+ * *
+ * Copyright Abandoned, 1987, Fred Fish *
+ * *
+ * *
+ * This previously copyrighted work has been placed into the public *
+ * domain by the author and may be freely used for any purpose, *
+ * private or commercial. *
+ * *
+ * Because of the number of inquiries I was receiving about the use *
+ * of this product in commercially developed works I have decided to *
+ * simply make it public domain to further its unrestricted use. I *
+ * specifically would be most happy to see this material become a *
+ * part of the standard Unix distributions by AT&T and the Berkeley *
+ * Computer Science Research Group, and a standard part of the GNU *
+ * system from the Free Software Foundation. *
+ * *
+ * I would appreciate it, as a courtesy, if this notice is left in *
+ * all copies and derivative works. Thank you. *
+ * *
+ * The author makes no warranty of any kind with respect to this *
+ * product and explicitly disclaims any implied warranties of mer- *
+ * chantability or fitness for any particular purpose. *
+ * *
+ ******************************************************************************
+ */
+
+
+/*
+ * FILE
+ *
+ * dbug.c runtime support routines for dbug package
+ *
+ * SCCS
+ *
+ * @(#)dbug.c 1.25 7/25/89
+ *
+ * DESCRIPTION
+ *
+ * These are the runtime support routines for the dbug package.
+ * The dbug package has two main components; the user include
+ * file containing various macro definitions, and the runtime
+ * support routines which are called from the macro expansions.
+ *
+ * Externally visible functions in the runtime support module
+ * use the naming convention pattern "_db_xx...xx_", thus
+ * they are unlikely to collide with user defined function names.
+ *
+ * AUTHOR(S)
+ *
+ * Fred Fish (base code)
+ * Enhanced Software Technologies, Tempe, AZ
+ * asuvax!mcdphx!estinc!fnf
+ *
+ * Binayak Banerjee (profiling enhancements)
+ * seismo!bpa!sjuvax!bbanerje
+ *
+ * Michael Widenius:
+ * DBUG_DUMP - To dump a pice of memory.
+ * PUSH_FLAG "O" - To be used insted of "o" if we don't
+ * want flushing (for slow systems)
+ * PUSH_FLAG "A" - as 'O', but we will append to the out file instead
+ * of creating a new one.
+ * Check of malloc on entry/exit (option "S")
+ */
+
+#ifdef DBUG_OFF
+#undef DBUG_OFF
+#endif
+#include <global.h>
+#include <m_string.h>
+#include <errno.h>
+#if defined(MSDOS) || defined(__WIN__)
+#include <process.h>
+#endif
+
+#ifdef _DBUG_CONDITION_
+#define _DBUG_START_CONDITION_ "d:t"
+#else
+#define _DBUG_START_CONDITION_ ""
+#endif
+
+/*
+ * Manifest constants that should not require any changes.
+ */
+
+#define EOS '\000' /* End Of String marker */
+
+/*
+ * Manifest constants which may be "tuned" if desired.
+ */
+
+#define PRINTBUF 1024 /* Print buffer size */
+#define INDENT 2 /* Indentation per trace level */
+#define MAXDEPTH 200 /* Maximum trace depth default */
+
+/*
+ * The following flags are used to determine which
+ * capabilities the user has enabled with the state
+ * push macro.
+ */
+
+#define TRACE_ON 000001 /* Trace enabled */
+#define DEBUG_ON 000002 /* Debug enabled */
+#define FILE_ON 000004 /* File name print enabled */
+#define LINE_ON 000010 /* Line number print enabled */
+#define DEPTH_ON 000020 /* Function nest level print enabled */
+#define PROCESS_ON 000040 /* Process name print enabled */
+#define NUMBER_ON 000100 /* Number each line of output */
+#define PROFILE_ON 000200 /* Print out profiling code */
+#define PID_ON 000400 /* Identify each line with process id */
+#define SANITY_CHECK_ON 001000 /* Check safemalloc on DBUG_ENTER */
+#define FLUSH_ON_WRITE 002000 /* Flush on every write */
+
+#define TRACING (stack -> flags & TRACE_ON)
+#define DEBUGGING (stack -> flags & DEBUG_ON)
+#define PROFILING (stack -> flags & PROFILE_ON)
+#define STREQ(a,b) (strcmp(a,b) == 0)
+
+/*
+ * Typedefs to make things more obvious.
+ */
+
+#ifndef __WIN__
+typedef int BOOLEAN;
+#else
+#define BOOLEAN BOOL
+#endif
+
+/*
+ * Make it easy to change storage classes if necessary.
+ */
+
+#define IMPORT extern /* Names defined externally */
+#define EXPORT /* Allocated here, available globally */
+#define AUTO auto /* Names to be allocated on stack */
+#define REGISTER register /* Names to be placed in registers */
+
+/*
+ * The default file for profiling. Could also add another flag
+ * (G?) which allowed the user to specify this.
+ *
+ * If the automatic variables get allocated on the stack in
+ * reverse order from their declarations, then define AUTOS_REVERSE.
+ * This is used by the code that keeps track of stack usage. For
+ * forward allocation, the difference in the dbug frame pointers
+ * represents stack used by the callee function. For reverse allocation,
+ * the difference represents stack used by the caller function.
+ *
+ */
+
+#define PROF_FILE "dbugmon.out"
+#define PROF_EFMT "E\t%ld\t%s\n"
+#define PROF_SFMT "S\t%lx\t%lx\t%s\n"
+#define PROF_XFMT "X\t%ld\t%s\n"
+
+#ifdef M_I386 /* predefined by xenix 386 compiler */
+#define AUTOS_REVERSE 1
+#endif
+
+/*
+ * Variables which are available externally but should only
+ * be accessed via the macro package facilities.
+ */
+
+EXPORT FILE *_db_fp_ = (FILE *) 0; /* Output stream, default stderr */
+EXPORT char *_db_process_ = (char*) "dbug"; /* Pointer to process name; argv[0] */
+EXPORT FILE *_db_pfp_ = (FILE *)0; /* Profile stream, 'dbugmon.out' */
+EXPORT BOOLEAN _db_on_ = FALSE; /* TRUE if debugging currently on */
+EXPORT BOOLEAN _db_pon_ = FALSE; /* TRUE if profile currently on */
+EXPORT BOOLEAN _no_db_ = FALSE; /* TRUE if no debugging at all */
+
+/*
+ * Externally supplied functions.
+ */
+
+#ifndef HAVE_PERROR
+static void perror (); /* Fake system/library error print routine */
+#endif
+
+IMPORT int _sanity(const char *file,uint line);
+
+/*
+ * The user may specify a list of functions to trace or
+ * debug. These lists are kept in a linear linked list,
+ * a very simple implementation.
+ */
+
+struct link {
+ char *str; /* Pointer to link's contents */
+ struct link *next_link; /* Pointer to the next link */
+};
+
+/*
+ * Debugging states can be pushed or popped off of a
+ * stack which is implemented as a linked list. Note
+ * that the head of the list is the current state and the
+ * stack is pushed by adding a new state to the head of the
+ * list or popped by removing the first link.
+ */
+
+struct state {
+ int flags; /* Current state flags */
+ int maxdepth; /* Current maximum trace depth */
+ uint delay; /* Delay after each output line */
+ int sub_level; /* Sub this from code_state->level */
+ FILE *out_file; /* Current output stream */
+ FILE *prof_file; /* Current profiling stream */
+ char name[FN_REFLEN]; /* Name of output file */
+ struct link *functions; /* List of functions */
+ struct link *p_functions; /* List of profiled functions */
+ struct link *keywords; /* List of debug keywords */
+ struct link *processes; /* List of process names */
+ struct state *next_state; /* Next state in the list */
+};
+
+
+/*
+ * Local variables not seen by user.
+ */
+
+
+static my_bool init_done = FALSE; /* Set to TRUE when initialization done */
+static struct state *stack=0;
+
+typedef struct st_code_state {
+ int lineno; /* Current debugger output line number */
+ int level; /* Current function nesting level */
+ const char *func; /* Name of current user function */
+ const char *file; /* Name of current user file */
+ char **framep; /* Pointer to current frame */
+ int jmplevel; /* Remember nesting level at setjmp () */
+ const char *jmpfunc; /* Remember current function for setjmp */
+ const char *jmpfile; /* Remember current file for setjmp */
+
+/*
+ * The following variables are used to hold the state information
+ * between the call to _db_pargs_() and _db_doprnt_(), during
+ * expansion of the DBUG_PRINT macro. This is the only macro
+ * that currently uses these variables.
+ *
+ * These variables are currently used only by _db_pargs_() and
+ * _db_doprnt_().
+ */
+
+ uint u_line; /* User source code line number */
+ const char *u_keyword; /* Keyword for current macro */
+ int locked; /* If locked with _db_lock_file */
+} CODE_STATE;
+
+ /* Parse a debug command string */
+static struct link *ListParse(char *ctlp);
+ /* Make a fresh copy of a string */
+static char *StrDup(const char *str);
+ /* Open debug output stream */
+static void DBUGOpenFile(const char *name, int append);
+#ifndef THREAD
+ /* Open profile output stream */
+static FILE *OpenProfile(const char *name);
+ /* Profile if asked for it */
+static BOOLEAN DoProfile(void);
+#endif
+ /* Return current user time (ms) */
+#ifndef THREAD
+static unsigned long Clock (void);
+#endif
+ /* Close debug output stream */
+static void CloseFile(FILE *fp);
+ /* Push current debug state */
+static void PushState(void);
+ /* Test for tracing enabled */
+static BOOLEAN DoTrace(CODE_STATE *state);
+ /* Test to see if file is writable */
+#if !(!defined(HAVE_ACCESS) || defined(MSDOS))
+static BOOLEAN Writable(char *pathname);
+ /* Change file owner and group */
+static void ChangeOwner(char *pathname);
+ /* Allocate memory for runtime support */
+#endif
+static char *DbugMalloc(int size);
+ /* Remove leading pathname components */
+static char *BaseName(const char *pathname);
+static void DoPrefix(uint line);
+static void FreeList(struct link *linkp);
+static void Indent(int indent);
+static BOOLEAN InList(struct link *linkp,const char *cp);
+static void dbug_flush(CODE_STATE *);
+static void DbugExit(const char *why);
+static int DelayArg(int value);
+ /* Supplied in Sys V runtime environ */
+ /* Break string into tokens */
+static char *static_strtok(char *s1,pchar chr);
+
+/*
+ * Miscellaneous printf format strings.
+ */
+
+#define ERR_MISSING_RETURN "%s: missing DBUG_RETURN or DBUG_VOID_RETURN macro in function \"%s\"\n"
+#define ERR_OPEN "%s: can't open debug output stream \"%s\": "
+#define ERR_CLOSE "%s: can't close debug file: "
+#define ERR_ABORT "%s: debugger aborting because %s\n"
+#define ERR_CHOWN "%s: can't change owner/group of \"%s\": "
+
+/*
+ * Macros and defines for testing file accessibility under UNIX and MSDOS.
+ */
+
+#if !defined(HAVE_ACCESS) || defined(MSDOS)
+#define EXISTS(pathname) (FALSE) /* Assume no existance */
+#define Writable(name) (TRUE)
+#else
+#define EXISTS(pathname) (access (pathname, F_OK) == 0)
+#define WRITABLE(pathname) (access (pathname, W_OK) == 0)
+#endif
+#ifndef MSDOS
+#define ChangeOwner(name)
+#endif
+
+/*
+ * Translate some calls among different systems.
+ */
+
+#if defined(unix) || defined(xenix) || defined(VMS) || defined(__NetBSD__)
+# define Delay(A) sleep((uint) A)
+#elif defined(AMIGA)
+IMPORT int Delay (); /* Pause for given number of ticks */
+#else
+static int Delay(int ticks);
+#endif
+
+
+/*
+** Macros to allow dbugging with threads
+*/
+
+#ifdef THREAD
+#include <my_pthread.h>
+pthread_mutex_t THR_LOCK_dbug;
+
+static void init_dbug_state(void)
+{
+ pthread_mutex_init(&THR_LOCK_dbug,NULL);
+}
+
+static CODE_STATE *code_state(void)
+{
+ CODE_STATE *state=0;
+ struct st_my_thread_var *tmp=my_thread_var;
+ if (tmp)
+ {
+ if (!(state=(CODE_STATE *) tmp->dbug))
+ {
+ state=(CODE_STATE*) DbugMalloc(sizeof(*state));
+ bzero((char*) state,sizeof(*state));
+ state->func="?func";
+ state->file="?file";
+ tmp->dbug=(gptr) state;
+ }
+ }
+ return state;
+}
+
+#else /* !THREAD */
+
+#define init_dbug_state()
+#define code_state() (&static_code_state)
+#define pthread_mutex_lock(A) {}
+#define pthread_mutex_unlock(A) {}
+static CODE_STATE static_code_state = { 0,0,"?func","?file",NULL,0,NULL,
+ NULL,0,"?",0};
+#endif
+
+
+/*
+ * FUNCTION
+ *
+ * _db_push_ push current debugger state and set up new one
+ *
+ * SYNOPSIS
+ *
+ * VOID _db_push_ (control)
+ * char *control;
+ *
+ * DESCRIPTION
+ *
+ * Given pointer to a debug control string in "control", pushes
+ * the current debug state, parses the control string, and sets
+ * up a new debug state.
+ *
+ * The only attribute of the new state inherited from the previous
+ * state is the current function nesting level. This can be
+ * overridden by using the "r" flag in the control string.
+ *
+ * The debug control string is a sequence of colon separated fields
+ * as follows:
+ *
+ * <field_1>:<field_2>:...:<field_N>
+ *
+ * Each field consists of a mandatory flag character followed by
+ * an optional "," and comma separated list of modifiers:
+ *
+ * flag[,modifier,modifier,...,modifier]
+ *
+ * The currently recognized flag characters are:
+ *
+ * d Enable output from DBUG_<N> macros for
+ * for the current state. May be followed
+ * by a list of keywords which selects output
+ * only for the DBUG macros with that keyword.
+ * A null list of keywords implies output for
+ * all macros.
+ *
+ * D Delay after each debugger output line.
+ * The argument is the number of tenths of seconds
+ * to delay, subject to machine capabilities.
+ * I.E. -#D,20 is delay two seconds.
+ *
+ * f 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.
+ *
+ * F Identify the source file name for each
+ * line of debug or trace output.
+ *
+ * i Identify the process with the pid for each line of
+ * debug or trace output.
+ *
+ * g Enable profiling. Create a file called 'dbugmon.out'
+ * containing information that can be used to profile
+ * the program. May be followed by a list of keywords
+ * that select profiling only for the functions in that
+ * list. A null list implies that all functions are
+ * considered.
+ *
+ * L Identify the source file line number for
+ * each line of debug or trace output.
+ *
+ * n Print the current function nesting depth for
+ * each line of debug or trace output.
+ *
+ * N Number each line of dbug output.
+ *
+ * o Redirect the debugger output stream to the
+ * specified file. The default output is stderr.
+ *
+ * O As O but the file is really flushed between each
+ * write. When neaded the file is closed and reopened
+ * between each write.
+ *
+ * p Limit debugger actions to specified processes.
+ * A process must be identified with the
+ * DBUG_PROCESS macro and match one in the list
+ * for debugger actions to occur.
+ *
+ * P Print the current process name for each
+ * line of debug or trace output.
+ *
+ * r When pushing a new state, do not inherit
+ * the previous state's function nesting level.
+ * Useful when the output is to start at the
+ * left margin.
+ *
+ * S Do function _sanity(_file_,_line_) at each
+ * debugged function until _sanity() returns
+ * something that differs from 0.
+ * (Moustly used with safemalloc)
+ *
+ * t Enable function call/exit trace lines.
+ * May be followed by a list (containing only
+ * one modifier) giving a numeric maximum
+ * trace level, beyond which no output will
+ * occur for either debugging or tracing
+ * macros. The default is a compile time
+ * option.
+ *
+ * Some examples of debug control strings which might appear
+ * on a shell command line (the "-#" is typically used to
+ * introduce a control string to an application program) are:
+ *
+ * -#d:t
+ * -#d:f,main,subr1:F:L:t,20
+ * -#d,input,output,files:n
+ *
+ * For convenience, any leading "-#" is stripped off.
+ *
+ */
+
+void _db_push_ (control)
+const char *control;
+{
+ reg1 char *scan;
+ reg2 struct link *temp;
+ CODE_STATE *state;
+ char *new_str;
+
+ if (! _db_fp_)
+ _db_fp_= stderr; /* Output stream, default stderr */
+
+ if (control && *control == '-')
+ {
+ if (*++control == '#')
+ control++;
+ }
+ if (*control)
+ _no_db_=0; /* We are using dbug after all */
+
+ new_str = StrDup (control);
+ PushState ();
+ state=code_state();
+
+ scan = static_strtok (new_str, ':');
+ for (; scan != NULL; scan = static_strtok ((char *)NULL, ':')) {
+ switch (*scan++) {
+ case 'd':
+ _db_on_ = TRUE;
+ stack -> flags |= DEBUG_ON;
+ if (*scan++ == ',') {
+ stack -> keywords = ListParse (scan);
+ }
+ break;
+ case 'D':
+ stack -> delay = 0;
+ if (*scan++ == ',') {
+ temp = ListParse (scan);
+ stack -> delay = DelayArg (atoi (temp -> str));
+ FreeList (temp);
+ }
+ break;
+ case 'f':
+ if (*scan++ == ',') {
+ stack -> functions = ListParse (scan);
+ }
+ break;
+ case 'F':
+ stack -> flags |= FILE_ON;
+ break;
+ case 'i':
+ stack -> flags |= PID_ON;
+ break;
+#ifndef THREAD
+ case 'g':
+ _db_pon_ = TRUE;
+ if (OpenProfile(PROF_FILE))
+ {
+ stack -> flags |= PROFILE_ON;
+ if (*scan++ == ',')
+ stack -> p_functions = ListParse (scan);
+ }
+ break;
+#endif
+ case 'L':
+ stack -> flags |= LINE_ON;
+ break;
+ case 'n':
+ stack -> flags |= DEPTH_ON;
+ break;
+ case 'N':
+ stack -> flags |= NUMBER_ON;
+ break;
+ case 'A':
+ case 'O':
+ stack -> flags |= FLUSH_ON_WRITE;
+ case 'a':
+ case 'o':
+ if (*scan++ == ',') {
+ temp = ListParse (scan);
+ DBUGOpenFile(temp -> str, (int) (scan[-2] == 'A' || scan[-2] == 'a'));
+ FreeList (temp);
+ } else {
+ DBUGOpenFile ("-",0);
+ }
+ break;
+ case 'p':
+ if (*scan++ == ',') {
+ stack -> processes = ListParse (scan);
+ }
+ break;
+ case 'P':
+ stack -> flags |= PROCESS_ON;
+ break;
+ case 'r':
+ stack->sub_level= state->level;
+ break;
+ case 't':
+ stack -> flags |= TRACE_ON;
+ if (*scan++ == ',') {
+ temp = ListParse (scan);
+ stack -> maxdepth = atoi (temp -> str);
+ FreeList (temp);
+ }
+ break;
+ case 'S':
+ stack -> flags |= SANITY_CHECK_ON;
+ break;
+ }
+ }
+ free (new_str);
+}
+
+
+/*
+ * FUNCTION
+ *
+ * _db_pop_ pop the debug stack
+ *
+ * DESCRIPTION
+ *
+ * Pops the debug stack, returning the debug state to its
+ * condition prior to the most recent _db_push_ invocation.
+ * Note that the pop will fail if it would remove the last
+ * valid state from the stack. This prevents user errors
+ * in the push/pop sequence from screwing up the debugger.
+ * Maybe there should be some kind of warning printed if the
+ * user tries to pop too many states.
+ *
+ */
+
+void _db_pop_ ()
+{
+ reg1 struct state *discard;
+ discard = stack;
+ if (discard != NULL && discard -> next_state != NULL) {
+ stack = discard -> next_state;
+ _db_fp_ = stack -> out_file;
+ _db_pfp_ = stack -> prof_file;
+ if (discard -> keywords != NULL) {
+ FreeList (discard -> keywords);
+ }
+ if (discard -> functions != NULL) {
+ FreeList (discard -> functions);
+ }
+ if (discard -> processes != NULL) {
+ FreeList (discard -> processes);
+ }
+ if (discard -> p_functions != NULL) {
+ FreeList (discard -> p_functions);
+ }
+ CloseFile (discard -> out_file);
+ if (discard -> prof_file)
+ CloseFile (discard -> prof_file);
+ free ((char *) discard);
+ if (!(stack->flags & DEBUG_ON))
+ _db_on_=0;
+ }
+ else
+ {
+ _db_on_=0;
+ }
+}
+
+
+/*
+ * FUNCTION
+ *
+ * _db_enter_ process entry point to user function
+ *
+ * SYNOPSIS
+ *
+ * VOID _db_enter_ (_func_, _file_, _line_,
+ * _sfunc_, _sfile_, _slevel_, _sframep_)
+ * char *_func_; points to current function name
+ * char *_file_; points to current file name
+ * int _line_; called from source line number
+ * char **_sfunc_; save previous _func_
+ * char **_sfile_; save previous _file_
+ * int *_slevel_; save previous nesting level
+ * char ***_sframep_; save previous frame pointer
+ *
+ * DESCRIPTION
+ *
+ * Called at the beginning of each user function to tell
+ * the debugger that a new function has been entered.
+ * Note that the pointers to the previous user function
+ * name and previous user file name are stored on the
+ * caller's stack (this is why the ENTER macro must be
+ * the first "executable" code in a function, since it
+ * allocates these storage locations). The previous nesting
+ * level is also stored on the callers stack for internal
+ * self consistency checks.
+ *
+ * Also prints a trace line if tracing is enabled and
+ * increments the current function nesting depth.
+ *
+ * Note that this mechanism allows the debugger to know
+ * what the current user function is at all times, without
+ * maintaining an internal stack for the function names.
+ *
+ */
+
+void _db_enter_ (_func_, _file_, _line_, _sfunc_, _sfile_, _slevel_,
+ _sframep_)
+const char *_func_;
+const char *_file_;
+uint _line_;
+const char **_sfunc_;
+const char **_sfile_;
+uint *_slevel_;
+char ***_sframep_ __attribute__((unused));
+{
+ reg1 CODE_STATE *state;
+
+ if (!_no_db_)
+ {
+ int save_errno=errno;
+ if (!init_done)
+ _db_push_ (_DBUG_START_CONDITION_);
+ state=code_state();
+
+ *_sfunc_ = state->func;
+ *_sfile_ = state->file;
+ state->func =(char*) _func_;
+ state->file = (char*) _file_; /* BaseName takes time !! */
+ *_slevel_ = ++state->level;
+#ifndef THREAD
+ *_sframep_ = state->framep;
+ state->framep = (char **) _sframep_;
+ if (DoProfile ())
+ {
+ long stackused;
+ if (*state->framep == NULL) {
+ stackused = 0;
+ } else {
+ stackused = ((long)(*state->framep)) - ((long)(state->framep));
+ stackused = stackused > 0 ? stackused : -stackused;
+ }
+ (void) fprintf (_db_pfp_, PROF_EFMT , Clock (), state->func);
+#ifdef AUTOS_REVERSE
+ (void) fprintf (_db_pfp_, PROF_SFMT, state->framep, stackused, *_sfunc_);
+#else
+ (void) fprintf (_db_pfp_, PROF_SFMT, (ulong) state->framep, stackused,
+ state->func);
+#endif
+ (void) fflush (_db_pfp_);
+ }
+#endif
+ if (DoTrace (state))
+ {
+ if (!state->locked)
+ pthread_mutex_lock(&THR_LOCK_dbug);
+ DoPrefix (_line_);
+ Indent (state -> level);
+ (void) fprintf (_db_fp_, ">%s\n", state->func);
+ dbug_flush (state); /* This does a unlock */
+ }
+#ifdef SAFEMALLOC
+ if (stack -> flags & SANITY_CHECK_ON)
+ if (_sanity(_file_,_line_)) /* Check of safemalloc */
+ stack -> flags &= ~SANITY_CHECK_ON;
+#endif
+ errno=save_errno;
+ }
+}
+
+/*
+ * FUNCTION
+ *
+ * _db_return_ process exit from user function
+ *
+ * SYNOPSIS
+ *
+ * VOID _db_return_ (_line_, _sfunc_, _sfile_, _slevel_)
+ * int _line_; current source line number
+ * char **_sfunc_; where previous _func_ is to be retrieved
+ * char **_sfile_; where previous _file_ is to be retrieved
+ * int *_slevel_; where previous level was stashed
+ *
+ * DESCRIPTION
+ *
+ * Called just before user function executes an explicit or implicit
+ * return. Prints a trace line if trace is enabled, decrements
+ * the current nesting level, and restores the current function and
+ * file names from the defunct function's stack.
+ *
+ */
+
+void _db_return_ (_line_, _sfunc_, _sfile_, _slevel_)
+uint _line_;
+const char **_sfunc_;
+const char **_sfile_;
+uint *_slevel_;
+{
+ CODE_STATE *state;
+
+ if (!_no_db_)
+ {
+ int save_errno=errno;
+ if (!init_done)
+ _db_push_ ("");
+ if (!(state=code_state()))
+ return; /* Only happens at end of program */
+ if (stack->flags & (TRACE_ON | DEBUG_ON | PROFILE_ON))
+ {
+ if (!state->locked)
+ pthread_mutex_lock(&THR_LOCK_dbug);
+ if (state->level != (int) *_slevel_)
+ (void) fprintf (_db_fp_, ERR_MISSING_RETURN, _db_process_,
+ state->func);
+ else
+ {
+#ifdef SAFEMALLOC
+ if (stack -> flags & SANITY_CHECK_ON)
+ if (_sanity(*_sfile_,_line_))
+ stack->flags &= ~SANITY_CHECK_ON;
+#endif
+#ifndef THREAD
+ if (DoProfile ())
+ (void) fprintf (_db_pfp_, PROF_XFMT, Clock(), state->func);
+#endif
+ if (DoTrace (state))
+ {
+ DoPrefix (_line_);
+ Indent (state->level);
+ (void) fprintf (_db_fp_, "<%s\n", state->func);
+ }
+ }
+ dbug_flush(state);
+ }
+ state->level = *_slevel_-1;
+ state->func = *_sfunc_;
+ state->file = *_sfile_;
+#ifndef THREAD
+ if (state->framep != NULL)
+ state->framep = (char **) *state->framep;
+#endif
+ errno=save_errno;
+ }
+}
+
+
+/*
+ * FUNCTION
+ *
+ * _db_pargs_ log arguments for subsequent use by _db_doprnt_()
+ *
+ * SYNOPSIS
+ *
+ * VOID _db_pargs_ (_line_, keyword)
+ * int _line_;
+ * char *keyword;
+ *
+ * DESCRIPTION
+ *
+ * The new universal printing macro DBUG_PRINT, which replaces
+ * all forms of the DBUG_N macros, needs two calls to runtime
+ * support routines. The first, this function, remembers arguments
+ * that are used by the subsequent call to _db_doprnt_().
+ *
+ */
+
+void _db_pargs_ (_line_, keyword)
+uint _line_;
+const char *keyword;
+{
+ CODE_STATE *state=code_state();
+ state->u_line = _line_;
+ state->u_keyword = (char*) keyword;
+}
+
+
+/*
+ * FUNCTION
+ *
+ * _db_doprnt_ handle print of debug lines
+ *
+ * SYNOPSIS
+ *
+ * VOID _db_doprnt_ (format, va_alist)
+ * char *format;
+ * va_dcl;
+ *
+ * DESCRIPTION
+ *
+ * When invoked via one of the DBUG macros, tests the current keyword
+ * set by calling _db_pargs_() to see if that macro has been selected
+ * for processing via the debugger control string, and if so, handles
+ * printing of the arguments via the format string. The line number
+ * of the DBUG macro in the source is found in u_line.
+ *
+ * Note that the format string SHOULD NOT include a terminating
+ * newline, this is supplied automatically.
+ *
+ */
+
+#include <stdarg.h>
+
+void _db_doprnt_ (const char *format,...)
+{
+ va_list args;
+ CODE_STATE *state;
+ state=code_state();
+
+ va_start(args,format);
+
+ if (_db_keyword_ (state->u_keyword)) {
+ int save_errno=errno;
+ if (!state->locked)
+ pthread_mutex_lock(&THR_LOCK_dbug);
+ DoPrefix (state->u_line);
+ if (TRACING) {
+ Indent (state->level + 1);
+ } else {
+ (void) fprintf (_db_fp_, "%s: ", state->func);
+ }
+ (void) fprintf (_db_fp_, "%s: ", state->u_keyword);
+ (void) vfprintf (_db_fp_, format, args);
+ va_end(args);
+ (void) fputc('\n',_db_fp_);
+ dbug_flush(state);
+ errno=save_errno;
+ }
+ va_end(args);
+}
+
+
+/*
+ * FUNCTION
+ *
+ * _db_dump_ dump a string until '\0' is found
+ *
+ * SYNOPSIS
+ *
+ * void _db_dump_ (_line_,keyword,memory,length)
+ * int _line_; current source line number
+ * char *keyword;
+ * char *memory; Memory to print
+ * int length; Bytes to print
+ *
+ * DESCRIPTION
+ * Dump N characters in a binary array.
+ * Is used to examine corrputed memory or arrays.
+ */
+
+void _db_dump_(_line_,keyword,memory,length)
+uint _line_,length;
+const char *keyword;
+const char *memory;
+{
+ int pos;
+ char dbuff[90];
+ CODE_STATE *state;
+ state=code_state();
+
+ if (_db_keyword_ ((char*) keyword))
+ {
+ if (!state->locked)
+ pthread_mutex_lock(&THR_LOCK_dbug);
+ DoPrefix (_line_);
+ if (TRACING)
+ {
+ Indent (state->level + 1);
+ pos= min(max(state->level-stack->sub_level,0)*INDENT,80);
+ }
+ else
+ {
+ fprintf(_db_fp_, "%s: ", state->func);
+ }
+ sprintf(dbuff,"%s: Memory: %lx Bytes: (%d)\n",
+ keyword,(ulong) memory, length);
+ (void) fputs(dbuff,_db_fp_);
+
+ pos=0;
+ while (length-- > 0)
+ {
+ uint tmp= *((unsigned char*) memory++);
+ if ((pos+=3) >= 80)
+ {
+ fputc('\n',_db_fp_);
+ pos=3;
+ }
+ fputc(_dig_vec[((tmp >> 4) & 15)], _db_fp_);
+ fputc(_dig_vec[tmp & 15], _db_fp_);
+ fputc(' ',_db_fp_);
+ }
+ (void) fputc('\n',_db_fp_);
+ dbug_flush(state);
+ }
+}
+
+/*
+ * FUNCTION
+ *
+ * ListParse parse list of modifiers in debug control string
+ *
+ * SYNOPSIS
+ *
+ * static struct link *ListParse (ctlp)
+ * char *ctlp;
+ *
+ * DESCRIPTION
+ *
+ * Given pointer to a comma separated list of strings in "cltp",
+ * parses the list, building a list and returning a pointer to it.
+ * The original comma separated list is destroyed in the process of
+ * building the linked list, thus it had better be a duplicate
+ * if it is important.
+ *
+ * Note that since each link is added at the head of the list,
+ * the final list will be in "reverse order", which is not
+ * significant for our usage here.
+ *
+ */
+
+static struct link *ListParse (ctlp)
+char *ctlp;
+{
+ REGISTER char *start;
+ REGISTER struct link *new;
+ REGISTER struct link *head;
+
+ head = NULL;
+ while (*ctlp != EOS) {
+ start = ctlp;
+ while (*ctlp != EOS && *ctlp != ',') {
+ ctlp++;
+ }
+ if (*ctlp == ',') {
+ *ctlp++ = EOS;
+ }
+ new = (struct link *) DbugMalloc (sizeof (struct link));
+ new -> str = StrDup (start);
+ new -> next_link = head;
+ head = new;
+ }
+ return (head);
+}
+
+/*
+ * FUNCTION
+ *
+ * InList test a given string for member of a given list
+ *
+ * SYNOPSIS
+ *
+ * static BOOLEAN InList (linkp, cp)
+ * struct link *linkp;
+ * char *cp;
+ *
+ * DESCRIPTION
+ *
+ * Tests the string pointed to by "cp" to determine if it is in
+ * the list pointed to by "linkp". Linkp points to the first
+ * link in the list. If linkp is NULL then the string is treated
+ * as if it is in the list (I.E all strings are in the null list).
+ * This may seem rather strange at first but leads to the desired
+ * operation if no list is given. The net effect is that all
+ * strings will be accepted when there is no list, and when there
+ * is a list, only those strings in the list will be accepted.
+ *
+ */
+
+static BOOLEAN InList (linkp, cp)
+struct link *linkp;
+const char *cp;
+{
+ REGISTER struct link *scan;
+ REGISTER BOOLEAN result;
+
+ if (linkp == NULL) {
+ result = TRUE;
+ } else {
+ result = FALSE;
+ for (scan = linkp; scan != NULL; scan = scan -> next_link) {
+ if (STREQ (scan -> str, cp)) {
+ result = TRUE;
+ break;
+ }
+ }
+ }
+ return (result);
+}
+
+
+/*
+ * FUNCTION
+ *
+ * PushState push current state onto stack and set up new one
+ *
+ * SYNOPSIS
+ *
+ * static VOID PushState ()
+ *
+ * DESCRIPTION
+ *
+ * Pushes the current state on the state stack, and initializes
+ * a new state. The only parameter inherited from the previous
+ * state is the function nesting level. This action can be
+ * inhibited if desired, via the "r" flag.
+ *
+ * The state stack is a linked list of states, with the new
+ * state added at the head. This allows the stack to grow
+ * to the limits of memory if necessary.
+ *
+ */
+
+static void PushState ()
+{
+ REGISTER struct state *new;
+
+ if (!init_done)
+ {
+ init_dbug_state();
+ init_done=TRUE;
+ }
+ (void) code_state(); /* Alloc memory */
+ new = (struct state *) DbugMalloc (sizeof (struct state));
+ new -> flags = 0;
+ new -> delay = 0;
+ new -> maxdepth = MAXDEPTH;
+ new -> sub_level=0;
+ new -> out_file = stderr;
+ new -> prof_file = (FILE*) 0;
+ new -> functions = NULL;
+ new -> p_functions = NULL;
+ new -> keywords = NULL;
+ new -> processes = NULL;
+ new -> next_state = stack;
+ stack=new;
+}
+
+
+/*
+ * FUNCTION
+ *
+ * DoTrace check to see if tracing is current enabled
+ *
+ * SYNOPSIS
+ *
+ * static BOOLEAN DoTrace (stack)
+ *
+ * DESCRIPTION
+ *
+ * Checks to see if tracing is enabled based on whether the
+ * user has specified tracing, the maximum trace depth has
+ * not yet been reached, the current function is selected,
+ * and the current process is selected. Returns TRUE if
+ * tracing is enabled, FALSE otherwise.
+ *
+ */
+
+static BOOLEAN DoTrace (CODE_STATE *state)
+{
+ reg2 BOOLEAN trace=FALSE;
+
+ if (TRACING &&
+ state->level <= stack -> maxdepth &&
+ InList (stack -> functions, state->func) &&
+ InList (stack -> processes, _db_process_))
+ trace = TRUE;
+ return (trace);
+}
+
+
+/*
+ * FUNCTION
+ *
+ * DoProfile check to see if profiling is current enabled
+ *
+ * SYNOPSIS
+ *
+ * static BOOLEAN DoProfile ()
+ *
+ * DESCRIPTION
+ *
+ * Checks to see if profiling is enabled based on whether the
+ * user has specified profiling, the maximum trace depth has
+ * not yet been reached, the current function is selected,
+ * and the current process is selected. Returns TRUE if
+ * profiling is enabled, FALSE otherwise.
+ *
+ */
+
+#ifndef THREAD
+static BOOLEAN DoProfile ()
+{
+ REGISTER BOOLEAN profile;
+ CODE_STATE *state;
+ state=code_state();
+
+ profile = FALSE;
+ if (PROFILING &&
+ state->level <= stack -> maxdepth &&
+ InList (stack -> p_functions, state->func) &&
+ InList (stack -> processes, _db_process_))
+ profile = TRUE;
+ return (profile);
+}
+#endif
+
+
+/*
+ * FUNCTION
+ *
+ * _db_keyword_ test keyword for member of keyword list
+ *
+ * SYNOPSIS
+ *
+ * BOOLEAN _db_keyword_ (keyword)
+ * char *keyword;
+ *
+ * DESCRIPTION
+ *
+ * Test a keyword to determine if it is in the currently active
+ * keyword list. As with the function list, a keyword is accepted
+ * if the list is null, otherwise it must match one of the list
+ * members. When debugging is not on, no keywords are accepted.
+ * After the maximum trace level is exceeded, no keywords are
+ * accepted (this behavior subject to change). Additionally,
+ * the current function and process must be accepted based on
+ * their respective lists.
+ *
+ * Returns TRUE if keyword accepted, FALSE otherwise.
+ *
+ */
+
+BOOLEAN _db_keyword_ (keyword)
+const char *keyword;
+{
+ REGISTER BOOLEAN result;
+ CODE_STATE *state;
+
+ if (!init_done)
+ _db_push_ ("");
+ state=code_state();
+ result = FALSE;
+ if (DEBUGGING &&
+ state->level <= stack -> maxdepth &&
+ InList (stack -> functions, state->func) &&
+ InList (stack -> keywords, keyword) &&
+ InList (stack -> processes, _db_process_))
+ result = TRUE;
+ return (result);
+}
+
+/*
+ * FUNCTION
+ *
+ * Indent indent a line to the given indentation level
+ *
+ * SYNOPSIS
+ *
+ * static VOID Indent (indent)
+ * int indent;
+ *
+ * DESCRIPTION
+ *
+ * Indent a line to the given level. Note that this is
+ * a simple minded but portable implementation.
+ * There are better ways.
+ *
+ * Also, the indent must be scaled by the compile time option
+ * of character positions per nesting level.
+ *
+ */
+
+static void Indent (indent)
+int indent;
+{
+ REGISTER int count;
+
+ indent= max(indent-1-stack->sub_level,0)*INDENT;
+ for (count = 0; count < indent ; count++)
+ {
+ if ((count % INDENT) == 0)
+ fputc('|',_db_fp_);
+ else
+ fputc(' ',_db_fp_);
+ }
+}
+
+
+/*
+ * FUNCTION
+ *
+ * FreeList free all memory associated with a linked list
+ *
+ * SYNOPSIS
+ *
+ * static VOID FreeList (linkp)
+ * struct link *linkp;
+ *
+ * DESCRIPTION
+ *
+ * Given pointer to the head of a linked list, frees all
+ * memory held by the list and the members of the list.
+ *
+ */
+
+static void FreeList (linkp)
+struct link *linkp;
+{
+ REGISTER struct link *old;
+
+ while (linkp != NULL) {
+ old = linkp;
+ linkp = linkp -> next_link;
+ if (old -> str != NULL) {
+ free (old -> str);
+ }
+ free ((char *) old);
+ }
+}
+
+
+/*
+ * FUNCTION
+ *
+ * StrDup make a duplicate of a string in new memory
+ *
+ * SYNOPSIS
+ *
+ * static char *StrDup (my_string)
+ * char *string;
+ *
+ * DESCRIPTION
+ *
+ * Given pointer to a string, allocates sufficient memory to make
+ * a duplicate copy, and copies the string to the newly allocated
+ * memory. Failure to allocated sufficient memory is immediately
+ * fatal.
+ *
+ */
+
+
+static char *StrDup (str)
+const char *str;
+{
+ reg1 char *new;
+ new = DbugMalloc ((int) strlen (str) + 1);
+ (void) strcpy (new, str);
+ return (new);
+}
+
+
+/*
+ * FUNCTION
+ *
+ * DoPrefix print debugger line prefix prior to indentation
+ *
+ * SYNOPSIS
+ *
+ * static VOID DoPrefix (_line_)
+ * int _line_;
+ *
+ * DESCRIPTION
+ *
+ * Print prefix common to all debugger output lines, prior to
+ * doing indentation if necessary. Print such information as
+ * current process name, current source file name and line number,
+ * and current function nesting depth.
+ *
+ */
+
+static void DoPrefix (_line_)
+uint _line_;
+{
+ CODE_STATE *state;
+ state=code_state();
+
+ state->lineno++;
+ if (stack -> flags & PID_ON) {
+#ifdef THREAD
+ (void) fprintf (_db_fp_, "%-7s: ", my_thread_name());
+#else
+ (void) fprintf (_db_fp_, "%5d: ", getpid ());
+#endif
+ }
+ if (stack -> flags & NUMBER_ON) {
+ (void) fprintf (_db_fp_, "%5d: ", state->lineno);
+ }
+ if (stack -> flags & PROCESS_ON) {
+ (void) fprintf (_db_fp_, "%s: ", _db_process_);
+ }
+ if (stack -> flags & FILE_ON) {
+ (void) fprintf (_db_fp_, "%14s: ", BaseName(state->file));
+ }
+ if (stack -> flags & LINE_ON) {
+ (void) fprintf (_db_fp_, "%5d: ", _line_);
+ }
+ if (stack -> flags & DEPTH_ON) {
+ (void) fprintf (_db_fp_, "%4d: ", state->level);
+ }
+}
+
+
+/*
+ * FUNCTION
+ *
+ * DBUGOpenFile open new output stream for debugger output
+ *
+ * SYNOPSIS
+ *
+ * static VOID DBUGOpenFile (name)
+ * char *name;
+ *
+ * DESCRIPTION
+ *
+ * Given name of a new file (or "-" for stdout) opens the file
+ * and sets the output stream to the new file.
+ *
+ */
+
+static void DBUGOpenFile (const char *name,int append)
+{
+ REGISTER FILE *fp;
+ REGISTER BOOLEAN newfile;
+
+ if (name != NULL)
+ {
+ strmov(stack->name,name);
+ if (strcmp (name, "-") == 0)
+ {
+ _db_fp_ = stdout;
+ stack -> out_file = _db_fp_;
+ stack -> flags |= FLUSH_ON_WRITE;
+ }
+ else
+ {
+ if (!Writable(name))
+ {
+ (void) fprintf (stderr, ERR_OPEN, _db_process_, name);
+ perror ("");
+ fflush(stderr);
+ }
+ else
+ {
+ newfile= !EXISTS (name);
+ if (!(fp = fopen(name, append ? "a+" : "w")))
+ {
+ (void) fprintf (stderr, ERR_OPEN, _db_process_, name);
+ perror ("");
+ fflush(stderr);
+ }
+ else
+ {
+ _db_fp_ = fp;
+ stack -> out_file = fp;
+ if (newfile) {
+ ChangeOwner (name);
+ }
+ }
+ }
+ }
+ }
+}
+
+
+/*
+ * FUNCTION
+ *
+ * OpenProfile open new output stream for profiler output
+ *
+ * SYNOPSIS
+ *
+ * static FILE *OpenProfile (name)
+ * char *name;
+ *
+ * DESCRIPTION
+ *
+ * Given name of a new file, opens the file
+ * and sets the profiler output stream to the new file.
+ *
+ * It is currently unclear whether the prefered behavior is
+ * to truncate any existing file, or simply append to it.
+ * The latter behavior would be desirable for collecting
+ * accumulated runtime history over a number of separate
+ * runs. It might take some changes to the analyzer program
+ * though, and the notes that Binayak sent with the profiling
+ * diffs indicated that append was the normal mode, but this
+ * does not appear to agree with the actual code. I haven't
+ * investigated at this time [fnf; 24-Jul-87].
+ */
+
+#ifndef THREAD
+static FILE *OpenProfile (const char *name)
+{
+ REGISTER FILE *fp;
+ REGISTER BOOLEAN newfile;
+
+ fp=0;
+ if (!Writable (name))
+ {
+ (void) fprintf (_db_fp_, ERR_OPEN, _db_process_, name);
+ perror ("");
+ dbug_flush(0);
+ (void) Delay (stack -> delay);
+ }
+ else
+ {
+ newfile= !EXISTS (name);
+ if (!(fp = fopen (name, "w")))
+ {
+ (void) fprintf (_db_fp_, ERR_OPEN, _db_process_, name);
+ perror ("");
+ dbug_flush(0);
+ }
+ else
+ {
+ _db_pfp_ = fp;
+ stack -> prof_file = fp;
+ if (newfile)
+ {
+ ChangeOwner (name);
+ }
+ }
+ }
+ return fp;
+}
+#endif
+
+/*
+ * FUNCTION
+ *
+ * CloseFile close the debug output stream
+ *
+ * SYNOPSIS
+ *
+ * static VOID CloseFile (fp)
+ * FILE *fp;
+ *
+ * DESCRIPTION
+ *
+ * Closes the debug output stream unless it is standard output
+ * or standard error.
+ *
+ */
+
+static void CloseFile (fp)
+FILE *fp;
+{
+ if (fp != stderr && fp != stdout) {
+ if (fclose (fp) == EOF) {
+ pthread_mutex_lock(&THR_LOCK_dbug);
+ (void) fprintf (_db_fp_, ERR_CLOSE, _db_process_);
+ perror ("");
+ dbug_flush(0);
+ }
+ }
+}
+
+
+/*
+ * FUNCTION
+ *
+ * DbugExit print error message and exit
+ *
+ * SYNOPSIS
+ *
+ * static VOID DbugExit (why)
+ * char *why;
+ *
+ * DESCRIPTION
+ *
+ * Prints error message using current process name, the reason for
+ * aborting (typically out of memory), and exits with status 1.
+ * This should probably be changed to use a status code
+ * defined in the user's debugger include file.
+ *
+ */
+
+static void DbugExit (const char *why)
+{
+ (void) fprintf (stderr, ERR_ABORT, _db_process_, why);
+ (void) fflush (stderr);
+ exit (1);
+}
+
+
+/*
+ * FUNCTION
+ *
+ * DbugMalloc allocate memory for debugger runtime support
+ *
+ * SYNOPSIS
+ *
+ * static long *DbugMalloc (size)
+ * int size;
+ *
+ * DESCRIPTION
+ *
+ * Allocate more memory for debugger runtime support functions.
+ * Failure to to allocate the requested number of bytes is
+ * immediately fatal to the current process. This may be
+ * rather unfriendly behavior. It might be better to simply
+ * print a warning message, freeze the current debugger state,
+ * and continue execution.
+ *
+ */
+
+static char *DbugMalloc (size)
+int size;
+{
+ register char *new;
+
+ if (!(new = malloc ((unsigned int) size)))
+ DbugExit ("out of memory");
+ return (new);
+}
+
+
+/*
+ * As strtok but two separators in a row are changed to one
+ * separator (to allow directory-paths in dos).
+ */
+
+static char *static_strtok (s1, separator)
+char *s1;
+pchar separator;
+{
+ static char *end = NULL;
+ reg1 char *rtnval,*cpy;
+
+ rtnval = NULL;
+ if (s1 != NULL)
+ end = s1;
+ if (end != NULL && *end != EOS)
+ {
+ rtnval=cpy=end;
+ do
+ {
+ if ((*cpy++ = *end++) == separator)
+ {
+ if (*end != separator)
+ {
+ cpy--; /* Point at separator */
+ break;
+ }
+ end++; /* Two separators in a row, skipp one */
+ }
+ } while (*end != EOS);
+ *cpy=EOS; /* Replace last separator */
+ }
+ return (rtnval);
+}
+
+
+/*
+ * FUNCTION
+ *
+ * BaseName strip leading pathname components from name
+ *
+ * SYNOPSIS
+ *
+ * static char *BaseName (pathname)
+ * char *pathname;
+ *
+ * DESCRIPTION
+ *
+ * Given pointer to a complete pathname, locates the base file
+ * name at the end of the pathname and returns a pointer to
+ * it.
+ *
+ */
+
+static char *BaseName (const char *pathname)
+{
+ register const char *base;
+
+ base = strrchr (pathname, FN_LIBCHAR);
+ if (base++ == NullS)
+ base = pathname;
+ return ((char*) base);
+}
+
+
+/*
+ * FUNCTION
+ *
+ * Writable test to see if a pathname is writable/creatable
+ *
+ * SYNOPSIS
+ *
+ * static BOOLEAN Writable (pathname)
+ * char *pathname;
+ *
+ * DESCRIPTION
+ *
+ * Because the debugger might be linked in with a program that
+ * runs with the set-uid-bit (suid) set, we have to be careful
+ * about opening a user named file for debug output. This consists
+ * of checking the file for write access with the real user id,
+ * or checking the directory where the file will be created.
+ *
+ * Returns TRUE if the user would normally be allowed write or
+ * create access to the named file. Returns FALSE otherwise.
+ *
+ */
+
+
+#ifndef Writable
+
+static BOOLEAN Writable (pathname)
+char *pathname;
+{
+ REGISTER BOOLEAN granted;
+ REGISTER char *lastslash;
+
+ granted = FALSE;
+ if (EXISTS (pathname)) {
+ if (WRITABLE (pathname)) {
+ granted = TRUE;
+ }
+ } else {
+ lastslash = strrchr (pathname, '/');
+ if (lastslash != NULL) {
+ *lastslash = EOS;
+ } else {
+ pathname = ".";
+ }
+ if (WRITABLE (pathname)) {
+ granted = TRUE;
+ }
+ if (lastslash != NULL) {
+ *lastslash = '/';
+ }
+ }
+ return (granted);
+}
+#endif
+
+
+/*
+ * FUNCTION
+ *
+ * ChangeOwner change owner to real user for suid programs
+ *
+ * SYNOPSIS
+ *
+ * static VOID ChangeOwner (pathname)
+ *
+ * DESCRIPTION
+ *
+ * For unix systems, change the owner of the newly created debug
+ * file to the real owner. This is strictly for the benefit of
+ * programs that are running with the set-user-id bit set.
+ *
+ * Note that at this point, the fact that pathname represents
+ * a newly created file has already been established. If the
+ * program that the debugger is linked to is not running with
+ * the suid bit set, then this operation is redundant (but
+ * harmless).
+ *
+ */
+
+#ifndef ChangeOwner
+static void ChangeOwner (pathname)
+char *pathname;
+{
+ if (chown (pathname, getuid (), getgid ()) == -1)
+ {
+ (void) fprintf (stderr, ERR_CHOWN, _db_process_, pathname);
+ perror ("");
+ (void) fflush (stderr);
+ }
+}
+#endif
+
+
+/*
+ * FUNCTION
+ *
+ * _db_setjmp_ save debugger environment
+ *
+ * SYNOPSIS
+ *
+ * VOID _db_setjmp_ ()
+ *
+ * DESCRIPTION
+ *
+ * Invoked as part of the user's DBUG_SETJMP macro to save
+ * the debugger environment in parallel with saving the user's
+ * environment.
+ *
+ */
+
+#ifdef HAVE_LONGJMP
+
+EXPORT void _db_setjmp_ ()
+{
+ CODE_STATE *state;
+ state=code_state();
+
+ state->jmplevel = state->level;
+ state->jmpfunc = state->func;
+ state->jmpfile = state->file;
+}
+
+/*
+ * FUNCTION
+ *
+ * _db_longjmp_ restore previously saved debugger environment
+ *
+ * SYNOPSIS
+ *
+ * VOID _db_longjmp_ ()
+ *
+ * DESCRIPTION
+ *
+ * Invoked as part of the user's DBUG_LONGJMP macro to restore
+ * the debugger environment in parallel with restoring the user's
+ * previously saved environment.
+ *
+ */
+
+EXPORT void _db_longjmp_ ()
+{
+ CODE_STATE *state;
+ state=code_state();
+
+ state->level = state->jmplevel;
+ if (state->jmpfunc) {
+ state->func = state->jmpfunc;
+ }
+ if (state->jmpfile) {
+ state->file = state->jmpfile;
+ }
+}
+#endif
+
+/*
+ * FUNCTION
+ *
+ * DelayArg convert D flag argument to appropriate value
+ *
+ * SYNOPSIS
+ *
+ * static int DelayArg (value)
+ * int value;
+ *
+ * DESCRIPTION
+ *
+ * Converts delay argument, given in tenths of a second, to the
+ * appropriate numerical argument used by the system to delay
+ * that that many tenths of a second. For example, on the
+ * amiga, there is a system call "Delay()" which takes an
+ * argument in ticks (50 per second). On unix, the sleep
+ * command takes seconds. Thus a value of "10", for one
+ * second of delay, gets converted to 50 on the amiga, and 1
+ * on unix. Other systems will need to use a timing loop.
+ *
+ */
+
+#ifdef AMIGA
+#define HZ (50) /* Probably in some header somewhere */
+#endif
+
+static int DelayArg (value)
+int value;
+{
+ uint delayarg = 0;
+
+#if (unix || xenix)
+ delayarg = value / 10; /* Delay is in seconds for sleep () */
+#endif
+#ifdef AMIGA
+ delayarg = (HZ * value) / 10; /* Delay in ticks for Delay () */
+#endif
+ return (delayarg);
+}
+
+
+/*
+ * A dummy delay stub for systems that do not support delays.
+ * With a little work, this can be turned into a timing loop.
+ */
+
+#if ! defined(Delay) && ! defined(AMIGA)
+static int Delay (ticks)
+int ticks;
+{
+ return ticks;
+}
+#endif
+
+
+/*
+ * FUNCTION
+ *
+ * perror perror simulation for systems that don't have it
+ *
+ * SYNOPSIS
+ *
+ * static VOID perror (s)
+ * char *s;
+ *
+ * DESCRIPTION
+ *
+ * Perror produces a message on the standard error stream which
+ * provides more information about the library or system error
+ * just encountered. The argument string s is printed, followed
+ * by a ':', a blank, and then a message and a newline.
+ *
+ * An undocumented feature of the unix perror is that if the string
+ * 's' is a null string (NOT a NULL pointer!), then the ':' and
+ * blank are not printed.
+ *
+ * This version just complains about an "unknown system error".
+ *
+ */
+
+#ifndef HAVE_PERROR
+static void perror (s)
+char *s;
+{
+ if (s && *s != EOS) {
+ (void) fprintf (stderr, "%s: ", s);
+ }
+ (void) fprintf (stderr, "<unknown system error>\n");
+}
+#endif /* HAVE_PERROR */
+
+
+ /* flush dbug-stream, free mutex lock & wait delay */
+ /* This is because some systems (MSDOS!!) dosn't flush fileheader */
+ /* and dbug-file isn't readable after a system crash !! */
+
+static void dbug_flush(CODE_STATE *state)
+{
+#ifndef THREAD
+ if (stack->flags & FLUSH_ON_WRITE)
+#endif
+ {
+#if defined(MSDOS) || defined(__WIN__)
+ if (_db_fp_ != stdout && _db_fp_ != stderr)
+ {
+ if (!(freopen(stack->name,"a",_db_fp_)))
+ {
+ (void) fprintf(stderr, ERR_OPEN, _db_process_);
+ fflush(stderr);
+ _db_fp_ = stdout;
+ stack -> out_file = _db_fp_;
+ stack -> flags|=FLUSH_ON_WRITE;
+ }
+ }
+ else
+#endif
+ {
+ (void) fflush (_db_fp_);
+ if (stack->delay)
+ (void) Delay (stack->delay);
+ }
+ }
+ if (!state || !state->locked)
+ pthread_mutex_unlock(&THR_LOCK_dbug);
+} /* dbug_flush */
+
+
+void _db_lock_file()
+{
+ CODE_STATE *state;
+ state=code_state();
+ pthread_mutex_lock(&THR_LOCK_dbug);
+ state->locked=1;
+}
+
+void _db_unlock_file()
+{
+ CODE_STATE *state;
+ state=code_state();
+ state->locked=0;
+ pthread_mutex_unlock(&THR_LOCK_dbug);
+}
+
+/*
+ * Here we need the definitions of the clock routine. Add your
+ * own for whatever system that you have.
+ */
+
+#ifdef HAVE_GETRUSAGE
+
+#include <sys/param.h>
+#include <sys/resource.h>
+
+/* extern int getrusage(int, struct rusage *); */
+
+/*
+ * Returns the user time in milliseconds used by this process so
+ * far.
+ */
+
+static unsigned long Clock ()
+{
+ struct rusage ru;
+
+ (void) getrusage (RUSAGE_SELF, &ru);
+ return ((ru.ru_utime.tv_sec * 1000) + (ru.ru_utime.tv_usec / 1000));
+}
+
+#else
+#if defined(MSDOS) || defined(__WIN__)
+
+static ulong Clock()
+{
+ return clock()*(1000/CLOCKS_PER_SEC);
+}
+#else
+#ifdef amiga
+
+struct DateStamp { /* Yes, this is a hack, but doing it right */
+ long ds_Days; /* is incredibly ugly without splitting this */
+ long ds_Minute; /* off into a separate file */
+ long ds_Tick;
+};
+
+static int first_clock = TRUE;
+static struct DateStamp begin;
+static struct DateStamp elapsed;
+
+static unsigned long Clock ()
+{
+ register struct DateStamp *now;
+ register unsigned long millisec = 0;
+ extern VOID *AllocMem ();
+
+ now = (struct DateStamp *) AllocMem ((long) sizeof (struct DateStamp), 0L);
+ if (now != NULL) {
+ if (first_clock == TRUE) {
+ first_clock = FALSE;
+ (void) DateStamp (now);
+ begin = *now;
+ }
+ (void) DateStamp (now);
+ millisec = 24 * 3600 * (1000 / HZ) * (now -> ds_Days - begin.ds_Days);
+ millisec += 60 * (1000 / HZ) * (now -> ds_Minute - begin.ds_Minute);
+ millisec += (1000 / HZ) * (now -> ds_Tick - begin.ds_Tick);
+ (void) FreeMem (now, (long) sizeof (struct DateStamp));
+ }
+ return (millisec);
+}
+
+#else
+
+#ifndef THREAD
+static unsigned long Clock ()
+{
+ return (0);
+}
+#endif
+#endif /* amiga */
+#endif /* MSDOS || __WIN__ */
+#endif /* RUSAGE */
+
+
+#ifdef NO_VARARGS
+
+/*
+ * Fake vfprintf for systems that don't support it. If this
+ * doesn't work, you are probably SOL...
+ */
+
+static int vfprintf (stream, format, ap)
+FILE *stream;
+char *format;
+va_list ap;
+{
+ int rtnval;
+ ARGS_DCL;
+
+ ARG0 = va_arg (ap, ARGS_TYPE);
+ ARG1 = va_arg (ap, ARGS_TYPE);
+ ARG2 = va_arg (ap, ARGS_TYPE);
+ ARG3 = va_arg (ap, ARGS_TYPE);
+ ARG4 = va_arg (ap, ARGS_TYPE);
+ ARG5 = va_arg (ap, ARGS_TYPE);
+ ARG6 = va_arg (ap, ARGS_TYPE);
+ ARG7 = va_arg (ap, ARGS_TYPE);
+ ARG8 = va_arg (ap, ARGS_TYPE);
+ ARG9 = va_arg (ap, ARGS_TYPE);
+ rtnval = fprintf (stream, format, ARGS_LIST);
+ return (rtnval);
+}
+
+#endif /* NO_VARARGS */
diff --git a/dbug/dbug_analyze.c b/dbug/dbug_analyze.c
new file mode 100644
index 00000000000..bcee5230527
--- /dev/null
+++ b/dbug/dbug_analyze.c
@@ -0,0 +1,716 @@
+/*
+ * Analyze the profile file (cmon.out) written out by the dbug
+ * routines with profiling enabled.
+ *
+ * Copyright June 1987, Binayak Banerjee
+ * All rights reserved.
+ *
+ * This program may be freely distributed under the same terms and
+ * conditions as Fred Fish's Dbug package.
+ *
+ * Compile with -- cc -O -s -o %s analyze.c
+ *
+ * Analyze will read an trace file created by the dbug package
+ * (when run with traceing enabled). It will then produce a
+ * summary on standard output listing the name of each traced
+ * function, the number of times it was called, the percentage
+ * of total calls, the time spent executing the function, the
+ * proportion of the total time and the 'importance'. The last
+ * is a metric which is obtained by multiplying the proportions
+ * of calls and the proportions of time for each function. The
+ * greater the importance, the more likely it is that a speedup
+ * could be obtained by reducing the time taken by that function.
+ *
+ * Note that the timing values that you obtain are only rough
+ * measures. The overhead of the dbug package is included
+ * within. However, there is no need to link in special profiled
+ * libraries and the like.
+ *
+ * CHANGES:
+ *
+ * 2-Mar-89: fnf
+ * Changes to support tracking of stack usage. This required
+ * reordering the fields in the profile log file to make
+ * parsing of different record types easier. Corresponding
+ * changes made in dbug runtime library. Also used this
+ * opportunity to reformat the code more to my liking (my
+ * apologies to Binayak Banerjee for "uglifying" his code).
+ *
+ * 24-Jul-87: fnf
+ * Because I tend to use functions names like
+ * "ExternalFunctionDoingSomething", I've rearranged the
+ * printout to put the function name last in each line, so
+ * long names don't screw up the formatting unless they are
+ * *very* long and wrap around the screen width...
+ *
+ * 24-Jul-87: fnf
+ * Modified to put out table very similar to Unix profiler
+ * by default, but also puts out original verbose table
+ * if invoked with -v flag.
+ */
+
+#include <global.h>
+#include <m_string.h>
+
+static char *my_name;
+static int verbose;
+
+/*
+ * Structure of the stack.
+ */
+
+#define PRO_FILE "dbugmon.out" /* Default output file name */
+#define STACKSIZ 100 /* Maximum function nesting */
+#define MAXPROCS 10000 /* Maximum number of function calls */
+
+# ifdef BSD
+# include <sysexits.h>
+# else
+# define EX_SOFTWARE 1
+# define EX_DATAERR 1
+# define EX_USAGE 1
+# define EX_OSERR 1
+# define EX_IOERR 1
+#ifndef EX_OK
+# define EX_OK 0
+#endif
+# endif
+
+#define __MERF_OO_ "%s: Malloc Failed in %s: %d\n"
+
+#define MALLOC(Ptr,Num,Typ) do /* Malloc w/error checking & exit */ \
+ if (!(Ptr = (Typ *)malloc((Num)*(sizeof(Typ))))) \
+ {fprintf(stderr,__MERF_OO_,my_name,__FILE__,__LINE__);\
+ exit(EX_OSERR);} while(0)
+
+#define Malloc(Ptr,Num,Typ) do /* Weaker version of above */\
+ if (!(Ptr = (Typ *)malloc((Num)*(sizeof(Typ))))) \
+ fprintf(stderr,__MERF_OO_,my_name,__FILE__,__LINE__);\
+ while(0)
+
+#define FILEOPEN(Fp,Fn,Mod) do /* File open with error exit */ \
+ if (!(Fp = fopen(Fn,Mod)))\
+ {fprintf(stderr,"%s: Couldn't open %s\n",my_name,Fn);\
+ exit(EX_IOERR);} while(0)
+
+#define Fileopen(Fp,Fn,Mod) do /* Weaker version of above */ \
+ if(!(Fp = fopen(Fn,Mod))) \
+ fprintf(stderr,"%s: Couldn't open %s\n",my_name,Fn);\
+ while(0)
+
+
+struct stack_t {
+ unsigned int pos; /* which function? */
+ unsigned long time; /* Time that this was entered */
+ unsigned long children; /* Time spent in called funcs */
+};
+
+static struct stack_t fn_stack[STACKSIZ+1];
+
+static unsigned int stacktop = 0; /* Lowest stack position is a dummy */
+
+static unsigned long tot_time = 0;
+static unsigned long tot_calls = 0;
+static unsigned long highstack = 0;
+static unsigned long lowstack = (ulong) ~0;
+
+/*
+ * top() returns a pointer to the top item on the stack.
+ * (was a function, now a macro)
+ */
+
+#define top() &fn_stack[stacktop]
+
+/*
+ * Push - Push the given record on the stack.
+ */
+
+void push (name_pos, time_entered)
+register unsigned int name_pos;
+register unsigned long time_entered;
+{
+ register struct stack_t *t;
+
+ DBUG_ENTER("push");
+ if (++stacktop > STACKSIZ) {
+ fprintf (DBUG_FILE,"%s: stack overflow (%s:%d)\n",
+ my_name, __FILE__, __LINE__);
+ exit (EX_SOFTWARE);
+ }
+ DBUG_PRINT ("push", ("%d %ld",name_pos,time_entered));
+ t = &fn_stack[stacktop];
+ t -> pos = name_pos;
+ t -> time = time_entered;
+ t -> children = 0;
+ DBUG_VOID_RETURN;
+}
+
+/*
+ * Pop - pop the top item off the stack, assigning the field values
+ * to the arguments. Returns 0 on stack underflow, or on popping first
+ * item off stack.
+ */
+
+unsigned int pop (name_pos, time_entered, child_time)
+register unsigned int *name_pos;
+register unsigned long *time_entered;
+register unsigned long *child_time;
+{
+ register struct stack_t *temp;
+ register unsigned int rtnval;
+
+ DBUG_ENTER ("pop");
+
+ if (stacktop < 1) {
+ rtnval = 0;
+ } else {
+ temp = &fn_stack[stacktop];
+ *name_pos = temp->pos;
+ *time_entered = temp->time;
+ *child_time = temp->children;
+ DBUG_PRINT ("pop", ("%d %d %d",*name_pos,*time_entered,*child_time));
+ rtnval = stacktop--;
+ }
+ DBUG_RETURN (rtnval);
+}
+
+/*
+ * We keep the function info in another array (serves as a simple
+ * symbol table)
+ */
+
+struct module_t {
+ char *name;
+ unsigned long m_time;
+ unsigned long m_calls;
+ unsigned long m_stkuse;
+};
+
+static struct module_t modules[MAXPROCS];
+
+/*
+ * We keep a binary search tree in order to look up function names
+ * quickly (and sort them at the end.
+ */
+
+struct bnode {
+ unsigned int lchild; /* Index of left subtree */
+ unsigned int rchild; /* Index of right subtree */
+ unsigned int pos; /* Index of module_name entry */
+};
+
+static struct bnode s_table[MAXPROCS];
+
+static unsigned int n_items = 0; /* No. of items in the array so far */
+
+/*
+ * Need a function to allocate space for a string and squirrel it away.
+ */
+
+char *strsave (s)
+char *s;
+{
+ register char *retval;
+ register unsigned int len;
+
+ DBUG_ENTER ("strsave");
+ DBUG_PRINT ("strsave", ("%s",s));
+ if (!s || (len = strlen (s)) == 0) {
+ DBUG_RETURN (0);
+ }
+ MALLOC (retval, ++len, char);
+ strcpy (retval, s);
+ DBUG_RETURN (retval);
+}
+
+/*
+ * add() - adds m_name to the table (if not already there), and returns
+ * the index of its location in the table. Checks s_table (which is a
+ * binary search tree) to see whether or not it should be added.
+ */
+
+unsigned int add (m_name)
+char *m_name;
+{
+ register unsigned int ind = 0;
+ register int cmp;
+
+ DBUG_ENTER ("add");
+ if (n_items == 0) { /* First item to be added */
+ s_table[0].pos = ind;
+ s_table[0].lchild = s_table[0].rchild = MAXPROCS;
+ addit:
+ modules[n_items].name = strsave (m_name);
+ modules[n_items].m_time = 0;
+ modules[n_items].m_calls = 0;
+ modules[n_items].m_stkuse = 0;
+ DBUG_RETURN (n_items++);
+ }
+ while (cmp = strcmp (m_name,modules[ind].name)) {
+ if (cmp < 0) { /* In left subtree */
+ if (s_table[ind].lchild == MAXPROCS) {
+ /* Add as left child */
+ if (n_items >= MAXPROCS) {
+ fprintf (DBUG_FILE,
+ "%s: Too many functions being profiled\n",
+ my_name);
+ exit (EX_SOFTWARE);
+ }
+ s_table[n_items].pos = s_table[ind].lchild = n_items;
+ s_table[n_items].lchild = s_table[n_items].rchild = MAXPROCS;
+#ifdef notdef
+ modules[n_items].name = strsave (m_name);
+ modules[n_items].m_time = modules[n_items].m_calls = 0;
+ DBUG_RETURN (n_items++);
+#else
+ goto addit;
+#endif
+
+ }
+ ind = s_table[ind].lchild; /* else traverse l-tree */
+ } else {
+ if (s_table[ind].rchild == MAXPROCS) {
+ /* Add as right child */
+ if (n_items >= MAXPROCS) {
+ fprintf (DBUG_FILE,
+ "%s: Too many functions being profiled\n",
+ my_name);
+ exit (EX_SOFTWARE);
+ }
+ s_table[n_items].pos = s_table[ind].rchild = n_items;
+ s_table[n_items].lchild = s_table[n_items].rchild = MAXPROCS;
+#ifdef notdef
+ modules[n_items].name = strsave (m_name);
+ modules[n_items].m_time = modules[n_items].m_calls = 0;
+ DBUG_RETURN (n_items++);
+#else
+ goto addit;
+#endif
+
+ }
+ ind = s_table[ind].rchild; /* else traverse r-tree */
+ }
+ }
+ DBUG_RETURN (ind);
+}
+
+/*
+ * process() - process the input file, filling in the modules table.
+ */
+
+void process (inf)
+FILE *inf;
+{
+ char buf[BUFSIZ];
+ char fn_name[64]; /* Max length of fn_name */
+ unsigned long fn_time;
+ unsigned long fn_sbot;
+ unsigned long fn_ssz;
+ unsigned long lastuse;
+ unsigned int pos;
+ unsigned long time;
+ unsigned int oldpos;
+ unsigned long oldtime;
+ unsigned long oldchild;
+ struct stack_t *t;
+
+ DBUG_ENTER ("process");
+ while (fgets (buf,BUFSIZ,inf) != NULL) {
+ switch (buf[0]) {
+ case 'E':
+ sscanf (buf+2, "%ld %64s", &fn_time, fn_name);
+ DBUG_PRINT ("erec", ("%ld %s", fn_time, fn_name));
+ pos = add (fn_name);
+ push (pos, fn_time);
+ break;
+ case 'X':
+ sscanf (buf+2, "%ld %64s", &fn_time, fn_name);
+ DBUG_PRINT ("xrec", ("%ld %s", fn_time, fn_name));
+ pos = add (fn_name);
+ /*
+ * An exited function implies that all stacked
+ * functions are also exited, until the matching
+ * function is found on the stack.
+ */
+ while (pop (&oldpos, &oldtime, &oldchild)) {
+ DBUG_PRINT ("popped", ("%d %d", oldtime, oldchild));
+ time = fn_time - oldtime;
+ t = top ();
+ t -> children += time;
+ DBUG_PRINT ("update", ("%s", modules[t -> pos].name));
+ DBUG_PRINT ("update", ("%d", t -> children));
+ time -= oldchild;
+ modules[oldpos].m_time += time;
+ modules[oldpos].m_calls++;
+ tot_time += time;
+ tot_calls++;
+ if (pos == oldpos) {
+ goto next_line; /* Should be a break2 */
+ }
+ }
+ /*
+ * Assume that item seen started at time 0.
+ * (True for function main). But initialize
+ * it so that it works the next time too.
+ */
+ t = top ();
+ time = fn_time - t -> time - t -> children;
+ t -> time = fn_time; t -> children = 0;
+ modules[pos].m_time += time;
+ modules[pos].m_calls++;
+ tot_time += time;
+ tot_calls++;
+ break;
+ case 'S':
+ sscanf (buf+2, "%lx %lx %64s", &fn_sbot, &fn_ssz, fn_name);
+ DBUG_PRINT ("srec", ("%lx %lx %s", fn_sbot, fn_ssz, fn_name));
+ pos = add (fn_name);
+ lastuse = modules[pos].m_stkuse;
+#if 0
+ /*
+ * Needs further thought. Stack use is determined by
+ * difference in stack between two functions with DBUG_ENTER
+ * macros. If A calls B calls C, where A and C have the
+ * macros, and B doesn't, then B's stack use will be lumped
+ * in with either A's or C's. If somewhere else A calls
+ * C directly, the stack use will seem to change. Just
+ * take the biggest for now...
+ */
+ if (lastuse > 0 && lastuse != fn_ssz) {
+ fprintf (stderr,
+ "warning - %s stack use changed (%lx to %lx)\n",
+ fn_name, lastuse, fn_ssz);
+ }
+#endif
+ if (fn_ssz > lastuse) {
+ modules[pos].m_stkuse = fn_ssz;
+ }
+ if (fn_sbot > highstack) {
+ highstack = fn_sbot;
+ } else if (fn_sbot < lowstack) {
+ lowstack = fn_sbot;
+ }
+ break;
+ default:
+ fprintf (stderr, "unknown record type '%s'\n", buf[0]);
+ break;
+ }
+ next_line:;
+ }
+
+ /*
+ * Now, we've hit eof. If we still have stuff stacked, then we
+ * assume that the user called exit, so give everything the exited
+ * time of fn_time.
+ */
+ while (pop (&oldpos,&oldtime,&oldchild)) {
+ time = fn_time - oldtime;
+ t = top ();
+ t -> children += time;
+ time -= oldchild;
+ modules[oldpos].m_time += time;
+ modules[oldpos].m_calls++;
+ tot_time += time;
+ tot_calls++;
+ }
+ DBUG_VOID_RETURN;
+}
+
+/*
+ * out_header () -- print out the header of the report.
+ */
+
+void out_header (outf)
+FILE *outf;
+{
+ DBUG_ENTER ("out_header");
+ if (verbose) {
+ fprintf (outf, "Profile of Execution\n");
+ fprintf (outf, "Execution times are in milliseconds\n\n");
+ fprintf (outf, " Calls\t\t\t Time\n");
+ fprintf (outf, " -----\t\t\t ----\n");
+ fprintf (outf, "Times\tPercentage\tTime Spent\tPercentage\n");
+ fprintf (outf, "Called\tof total\tin Function\tof total Importance\tFunction\n");
+ fprintf (outf, "======\t==========\t===========\t========== ==========\t========\t\n");
+ } else {
+ fprintf (outf, "%ld bytes of stack used, from %lx down to %lx\n\n",
+ highstack - lowstack, highstack, lowstack);
+ fprintf (outf,
+ " %%time sec #call ms/call %%calls weight stack name\n");
+ }
+ DBUG_VOID_RETURN;
+}
+
+/*
+ * out_trailer () - writes out the summary line of the report.
+ */
+
+void out_trailer (outf,sum_calls,sum_time)
+FILE *outf;
+unsigned long int sum_calls, sum_time;
+{
+ DBUG_ENTER ("out_trailer");
+ if (verbose) {
+ fprintf (outf, "======\t==========\t===========\t==========\t========\n");
+ fprintf (outf, "%6d\t%10.2f\t%11d\t%10.2f\t\t%-15s\n",
+ sum_calls, 100.0, sum_time, 100.0, "Totals");
+ }
+ DBUG_VOID_RETURN;
+}
+
+/*
+ * out_item () - prints out the output line for a single entry,
+ * and sets the calls and time fields appropriately.
+ */
+
+void out_item (outf, m,called,timed)
+FILE *outf;
+register struct module_t *m;
+unsigned long int *called, *timed;
+{
+ char *name = m -> name;
+ register unsigned int calls = m -> m_calls;
+ register unsigned long time = m -> m_time;
+ register unsigned long stkuse = m -> m_stkuse;
+ unsigned int import;
+ double per_time = 0.0;
+ double per_calls = 0.0;
+ double ms_per_call, ftime;
+
+ DBUG_ENTER ("out_item");
+
+ if (tot_time > 0) {
+ per_time = (double) (time * 100) / (double) tot_time;
+ }
+ if (tot_calls > 0) {
+ per_calls = (double) (calls * 100) / (double) tot_calls;
+ }
+ import = (unsigned int) (per_time * per_calls);
+
+ if (verbose) {
+ fprintf (outf, "%6d\t%10.2f\t%11d\t%10.2f %10d\t%-15s\n",
+ calls, per_calls, time, per_time, import, name);
+ } else {
+ ms_per_call = time;
+ ms_per_call /= calls;
+ ftime = time;
+ ftime /= 1000;
+ fprintf (outf, "%8.2f%8.3f%8u%8.3f%8.2f%8u%8u %-s\n",
+ per_time, ftime, calls, ms_per_call, per_calls, import,
+ stkuse, name);
+ }
+ *called = calls;
+ *timed = time;
+ DBUG_VOID_RETURN;
+}
+
+/*
+ * out_body (outf, root,s_calls,s_time) -- Performs an inorder traversal
+ * on the binary search tree (root). Calls out_item to actually print
+ * the item out.
+ */
+
+void out_body (outf, root,s_calls,s_time)
+FILE *outf;
+register unsigned int root;
+register unsigned long int *s_calls, *s_time;
+{
+ unsigned long int calls, time;
+
+ DBUG_ENTER ("out_body");
+ DBUG_PRINT ("out_body", ("%d,%d",*s_calls,*s_time));
+ if (root == MAXPROCS) {
+ DBUG_PRINT ("out_body", ("%d,%d",*s_calls,*s_time));
+ } else {
+ while (root != MAXPROCS) {
+ out_body (outf, s_table[root].lchild,s_calls,s_time);
+ out_item (outf, &modules[s_table[root].pos],&calls,&time);
+ DBUG_PRINT ("out_body", ("-- %d -- %d --", calls, time));
+ *s_calls += calls;
+ *s_time += time;
+ root = s_table[root].rchild;
+ }
+ DBUG_PRINT ("out_body", ("%d,%d", *s_calls, *s_time));
+ }
+ DBUG_VOID_RETURN;
+}
+
+/*
+ * output () - print out a nice sorted output report on outf.
+ */
+
+void output (outf)
+FILE *outf;
+{
+ unsigned long int sum_calls = 0;
+ unsigned long int sum_time = 0;
+
+ DBUG_ENTER ("output");
+ if (n_items == 0) {
+ fprintf (outf, "%s: No functions to trace\n", my_name);
+ exit (EX_DATAERR);
+ }
+ out_header (outf);
+ out_body (outf, 0,&sum_calls,&sum_time);
+ out_trailer (outf, sum_calls,sum_time);
+ DBUG_VOID_RETURN;
+}
+
+
+#define usage() fprintf (DBUG_FILE,"Usage: %s [-v] [prof-file]\n",my_name)
+
+#ifdef MSDOS
+extern int getopt(int argc, char **argv, char *opts);
+#endif
+extern int optind;
+extern char *optarg;
+
+int main (int argc, char **argv)
+{
+ register int c;
+ int badflg = 0;
+ FILE *infile;
+ FILE *outfile = {stdout};
+
+ DBUG_ENTER ("main");
+ DBUG_PROCESS (argv[0]);
+ my_name = argv[0];
+ while ((c = getopt (argc,argv,"#:v")) != EOF) {
+ switch (c) {
+ case '#': /* Debugging Macro enable */
+ DBUG_PUSH (optarg);
+ break;
+ case 'v': /* Verbose mode */
+ verbose++;
+ break;
+ default:
+ badflg++;
+ break;
+ }
+ }
+ if (badflg) {
+ usage ();
+ DBUG_RETURN (EX_USAGE);
+ }
+ if (optind < argc) {
+ FILEOPEN (infile, argv[optind], "r");
+ } else {
+ FILEOPEN (infile, PRO_FILE, "r");
+ }
+ process (infile);
+ output (outfile);
+ DBUG_RETURN (EX_OK);
+}
+
+#ifdef MSDOS
+
+/*
+ * From std-unix@ut-sally.UUCP (Moderator, John Quarterman) Sun Nov 3 14:34:15 1985
+ * Relay-Version: version B 2.10.3 4.3bsd-beta 6/6/85; site gatech.CSNET
+ * Posting-Version: version B 2.10.2 9/18/84; site ut-sally.UUCP
+ * Path: gatech!akgua!mhuxv!mhuxt!mhuxr!ulysses!allegra!mit-eddie!genrad!panda!talcott!harvard!seismo!ut-sally!std-unix
+ * From: std-unix@ut-sally.UUCP (Moderator, John Quarterman)
+ * Newsgroups: mod.std.unix
+ * Subject: public domain AT&T getopt source
+ * Message-ID: <3352@ut-sally.UUCP>
+ * Date: 3 Nov 85 19:34:15 GMT
+ * Date-Received: 4 Nov 85 12:25:09 GMT
+ * Organization: IEEE/P1003 Portable Operating System Environment Committee
+ * Lines: 91
+ * Approved: jsq@ut-sally.UUCP
+ *
+ * Here's something you've all been waiting for: the AT&T public domain
+ * source for getopt(3). It is the code which was given out at the 1985
+ * UNIFORUM conference in Dallas. I obtained it by electronic mail
+ * directly from AT&T. The people there assure me that it is indeed
+ * in the public domain.
+ *
+ * There is no manual page. That is because the one they gave out at
+ * UNIFORUM was slightly different from the current System V Release 2
+ * manual page. The difference apparently involved a note about the
+ * famous rules 5 and 6, recommending using white space between an option
+ * and its first argument, and not grouping options that have arguments.
+ * Getopt itself is currently lenient about both of these things White
+ * space is allowed, but not mandatory, and the last option in a group can
+ * have an argument. That particular version of the man page evidently
+ * has no official existence, and my source at AT&T did not send a copy.
+ * The current SVR2 man page reflects the actual behavor of this getopt.
+ * However, I am not about to post a copy of anything licensed by AT&T.
+ *
+ * I will submit this source to Berkeley as a bug fix.
+ *
+ * I, personally, make no claims or guarantees of any kind about the
+ * following source. I did compile it to get some confidence that
+ * it arrived whole, but beyond that you're on your own.
+ *
+ */
+
+/*LINTLIBRARY*/
+
+int opterr = 1;
+int optind = 1;
+int optopt;
+char *optarg;
+
+static void _ERR(s,c,argv)
+char *s;
+int c;
+char *argv[];
+{
+ char errbuf[3];
+
+ if (opterr) {
+ errbuf[0] = c;
+ errbuf[1] = '\n';
+ (void) fprintf(stderr, "%s", argv[0]);
+ (void) fprintf(stderr, "%s", s);
+ (void) fprintf(stderr, "%s", errbuf);
+ }
+}
+
+int getopt(argc, argv, opts)
+int argc;
+char **argv, *opts;
+{
+ static int sp = 1;
+ register int c;
+ register char *cp;
+
+ if(sp == 1)
+ if(optind >= argc ||
+ argv[optind][0] != '-' || argv[optind][1] == '\0')
+ return(EOF);
+ else if(strcmp(argv[optind], "--") == 0) {
+ optind++;
+ return(EOF);
+ }
+ optopt = c = argv[optind][sp];
+ if(c == ':' || (cp=strchr(opts, c)) == NULL) {
+ _ERR(": illegal option -- ", c, argv);
+ if(argv[optind][++sp] == '\0') {
+ optind++;
+ sp = 1;
+ }
+ return('?');
+ }
+ if(*++cp == ':') {
+ if(argv[optind][sp+1] != '\0')
+ optarg = &argv[optind++][sp+1];
+ else if(++optind >= argc) {
+ _ERR(": option requires an argument -- ", c, argv);
+ sp = 1;
+ return('?');
+ } else
+ optarg = argv[optind++];
+ sp = 1;
+ } else {
+ if(argv[optind][++sp] == '\0') {
+ sp = 1;
+ optind++;
+ }
+ optarg = NULL;
+ }
+ return(c);
+}
+
+#endif /* !unix && !xenix */
diff --git a/dbug/dbug_long.h b/dbug/dbug_long.h
new file mode 100644
index 00000000000..07266b51553
--- /dev/null
+++ b/dbug/dbug_long.h
@@ -0,0 +1,159 @@
+/******************************************************************************
+ * *
+ * N O T I C E *
+ * *
+ * Copyright Abandoned, 1987, Fred Fish *
+ * *
+ * *
+ * This previously copyrighted work has been placed into the public *
+ * domain by the author and may be freely used for any purpose, *
+ * private or commercial. *
+ * *
+ * Because of the number of inquiries I was receiving about the use *
+ * of this product in commercially developed works I have decided to *
+ * simply make it public domain to further its unrestricted use. I *
+ * specifically would be most happy to see this material become a *
+ * part of the standard Unix distributions by AT&T and the Berkeley *
+ * Computer Science Research Group, and a standard part of the GNU *
+ * system from the Free Software Foundation. *
+ * *
+ * I would appreciate it, as a courtesy, if this notice is left in *
+ * all copies and derivative works. Thank you. *
+ * *
+ * The author makes no warranty of any kind with respect to this *
+ * product and explicitly disclaims any implied warranties of mer- *
+ * chantability or fitness for any particular purpose. *
+ * *
+ ******************************************************************************
+ */
+
+/*
+ * FILE
+ *
+ * dbug.h user include file for programs using the dbug package
+ *
+ * SYNOPSIS
+ *
+ * #include <local/dbug.h>
+ *
+ * SCCS ID
+ *
+ * @(#)dbug.h 1.13 7/17/89
+ *
+ * DESCRIPTION
+ *
+ * Programs which use the dbug package must include this file.
+ * It contains the appropriate macros to call support routines
+ * in the dbug runtime library.
+ *
+ * To disable compilation of the macro expansions define the
+ * preprocessor symbol "DBUG_OFF". This will result in null
+ * macros expansions so that the resulting code will be smaller
+ * and faster. (The difference may be smaller than you think
+ * so this step is recommended only when absolutely necessary).
+ * In general, tradeoffs between space and efficiency are
+ * decided in favor of efficiency since space is seldom a
+ * problem on the new machines).
+ *
+ * All externally visible symbol names follow the pattern
+ * "_db_xxx..xx_" to minimize the possibility of a dbug package
+ * symbol colliding with a user defined symbol.
+ *
+ * The DBUG_<N> style macros are obsolete and should not be used
+ * in new code. Macros to map them to instances of DBUG_PRINT
+ * are provided for compatibility with older code. They may go
+ * away completely in subsequent releases.
+ *
+ * AUTHOR
+ *
+ * Fred Fish
+ * (Currently employed by Motorola Computer Division, Tempe, Az.)
+ * hao!noao!mcdsun!fnf
+ * (602) 438-3614
+ *
+ */
+
+/*
+ * Internally used dbug variables which must be global.
+ */
+
+#ifndef DBUG_OFF
+ extern int _db_on_; /* TRUE if debug currently enabled */
+ extern FILE *_db_fp_; /* Current debug output stream */
+ extern char *_db_process_; /* Name of current process */
+ extern int _db_keyword_ (); /* Accept/reject keyword */
+ extern void _db_push_ (); /* Push state, set up new state */
+ extern void _db_pop_ (); /* Pop previous debug state */
+ extern void _db_enter_ (); /* New user function entered */
+ extern void _db_return_ (); /* User function return */
+ extern void _db_pargs_ (); /* Remember args for line */
+ extern void _db_doprnt_ (); /* Print debug output */
+ extern void _db_setjmp_ (); /* Save debugger environment */
+ extern void _db_longjmp_ (); /* Restore debugger environment */
+ extern void _db_dump_(); /* Dump memory */
+# endif
+
+
+/*
+ * These macros provide a user interface into functions in the
+ * dbug runtime support library. They isolate users from changes
+ * in the MACROS and/or runtime support.
+ *
+ * The symbols "__LINE__" and "__FILE__" are expanded by the
+ * preprocessor to the current source file line number and file
+ * name respectively.
+ *
+ * WARNING --- Because the DBUG_ENTER macro allocates space on
+ * the user function's stack, it must precede any executable
+ * statements in the user function.
+ *
+ */
+
+# ifdef DBUG_OFF
+# define DBUG_ENTER(a1)
+# define DBUG_RETURN(a1) return(a1)
+# define DBUG_VOID_RETURN return
+# define DBUG_EXECUTE(keyword,a1)
+# define DBUG_PRINT(keyword,arglist)
+# define DBUG_2(keyword,format) /* Obsolete */
+# define DBUG_3(keyword,format,a1) /* Obsolete */
+# define DBUG_4(keyword,format,a1,a2) /* Obsolete */
+# define DBUG_5(keyword,format,a1,a2,a3) /* Obsolete */
+# define DBUG_PUSH(a1)
+# define DBUG_POP()
+# define DBUG_PROCESS(a1)
+# define DBUG_FILE (stderr)
+# define DBUG_SETJMP setjmp
+# define DBUG_LONGJMP longjmp
+# define DBUG_DUMP(keyword,a1)
+# else
+# define DBUG_ENTER(a) \
+ auto char *_db_func_; auto char *_db_file_; auto int _db_level_; \
+ auto char **_db_framep_; \
+ _db_enter_ (a,__FILE__,__LINE__,&_db_func_,&_db_file_,&_db_level_, \
+ &_db_framep_)
+# define DBUG_LEAVE \
+ (_db_return_ (__LINE__, &_db_func_, &_db_file_, &_db_level_))
+# define DBUG_RETURN(a1) return (DBUG_LEAVE, (a1))
+/* define DBUG_RETURN(a1) {DBUG_LEAVE; return(a1);} Alternate form */
+# define DBUG_VOID_RETURN {DBUG_LEAVE; return;}
+# define DBUG_EXECUTE(keyword,a1) \
+ {if (_db_on_) {if (_db_keyword_ (keyword)) { a1 }}}
+# define DBUG_PRINT(keyword,arglist) \
+ {if (_db_on_) {_db_pargs_(__LINE__,keyword); _db_doprnt_ arglist;}}
+# define DBUG_2(keyword,format) \
+ DBUG_PRINT(keyword,(format)) /* Obsolete */
+# define DBUG_3(keyword,format,a1) \
+ DBUG_PRINT(keyword,(format,a1)) /* Obsolete */
+# define DBUG_4(keyword,format,a1,a2) \
+ DBUG_PRINT(keyword,(format,a1,a2)) /* Obsolete */
+# define DBUG_5(keyword,format,a1,a2,a3) \
+ DBUG_PRINT(keyword,(format,a1,a2,a3)) /* Obsolete */
+# define DBUG_PUSH(a1) _db_push_ (a1)
+# define DBUG_POP() _db_pop_ ()
+# define DBUG_PROCESS(a1) (_db_process_ = a1)
+# define DBUG_FILE (_db_fp_)
+# define DBUG_SETJMP(a1) (_db_setjmp_ (), setjmp (a1))
+# define DBUG_LONGJMP(a1,a2) (_db_longjmp_ (), longjmp (a1, a2))
+# define DBUG_DUMP(keyword,a1,a2) _db_dump_(__LINE__,keyword,a1,a2)
+# endif
diff --git a/dbug/doinstall.sh b/dbug/doinstall.sh
new file mode 100644
index 00000000000..707f193c761
--- /dev/null
+++ b/dbug/doinstall.sh
@@ -0,0 +1,15 @@
+
+# Warning - first line left blank for sh/csh/ksh compatibility. Do not
+# remove it. fnf@Unisoft
+
+# doinstall.sh --- figure out environment and do recursive make with
+# appropriate pathnames. Works under SV or BSD.
+
+if [ -r /usr/include/search.h ]
+then
+ # System V
+ $* LLIB=/usr/lib
+else
+ # 4.2 BSD
+ $* LLIB=/usr/lib/lint
+fi
diff --git a/dbug/example1.c b/dbug/example1.c
new file mode 100644
index 00000000000..932e269cc4c
--- /dev/null
+++ b/dbug/example1.c
@@ -0,0 +1,13 @@
+
+#include <global.h>
+
+main (argc, argv)
+int argc;
+char *argv[];
+{
+ printf ("argv[0] = %d\n", argv[0]);
+ /*
+ * Rest of program
+ */
+ printf ("== done ==\n");
+}
diff --git a/dbug/example2.c b/dbug/example2.c
new file mode 100644
index 00000000000..482691a8a74
--- /dev/null
+++ b/dbug/example2.c
@@ -0,0 +1,18 @@
+
+#include <global.h>
+
+int debug = 0;
+
+main (argc, argv)
+int argc;
+char *argv[];
+{
+ /* printf ("argv = %x\n", argv) */
+ if (debug) printf ("argv[0] = %d\n", argv[0]);
+ /*
+ * Rest of program
+ */
+#ifdef DEBUG
+ printf ("== done ==\n");
+#endif
+}
diff --git a/dbug/example3.c b/dbug/example3.c
new file mode 100644
index 00000000000..b504edf2e61
--- /dev/null
+++ b/dbug/example3.c
@@ -0,0 +1,17 @@
+
+#include <global.h>
+
+main (argc, argv)
+int argc;
+char *argv[];
+{
+# ifdef DEBUG
+ printf ("argv[0] = %d\n", argv[0]);
+# endif
+ /*
+ * Rest of program
+ */
+# ifdef DEBUG
+ printf ("== done ==\n");
+# endif
+}
diff --git a/dbug/factorial.c b/dbug/factorial.c
new file mode 100644
index 00000000000..191c0468356
--- /dev/null
+++ b/dbug/factorial.c
@@ -0,0 +1,17 @@
+#ifdef DBUG_OFF /* We are testing dbug */
+#undef DBUG_OFF
+#endif
+
+#include <global.h>
+
+int factorial (value)
+register int value;
+{
+ DBUG_ENTER ("factorial");
+ DBUG_PRINT ("find", ("find %d factorial", value));
+ if (value > 1) {
+ value *= factorial (value - 1);
+ }
+ DBUG_PRINT ("result", ("result is %d", value));
+ DBUG_RETURN (value);
+}
diff --git a/dbug/install.sh b/dbug/install.sh
new file mode 100644
index 00000000000..7226e01b1cf
--- /dev/null
+++ b/dbug/install.sh
@@ -0,0 +1,64 @@
+
+# WARNING -- first line intentionally left blank for sh/csh/ksh
+# compatibility. Do not remove it! FNF, UniSoft Systems.
+#
+# Usage is:
+# install <from> <to>
+#
+# The file <to> is replaced with the file <from>, after first
+# moving <to> to a backup file. The backup file name is created
+# by prepending the filename (after removing any leading pathname
+# components) with "OLD".
+#
+# This script is currently not real robust in the face of signals
+# or permission problems. It also does not do (by intention) all
+# the things that the System V or BSD install scripts try to do
+#
+
+if [ $# -ne 2 ]
+then
+ echo "usage: $0 <from> <to>"
+ exit 1
+fi
+
+# Now extract the dirname and basename components. Unfortunately, BSD does
+# not have dirname, so we do it the hard way.
+
+fd=`expr $1'/' : '\(/\)[^/]*/$' \| $1'/' : '\(.*[^/]\)//*[^/][^/]*//*$' \| .`
+ff=`basename $1`
+td=`expr $2'/' : '\(/\)[^/]*/$' \| $2'/' : '\(.*[^/]\)//*[^/][^/]*//*$' \| .`
+tf=`basename $2`
+
+# Now test to make sure that they are not the same files.
+
+if [ $fd/$ff = $td/$tf ]
+then
+ echo "install: input and output are same files"
+ exit 2
+fi
+
+# Save a copy of the "to" file as a backup.
+
+if test -f $td/$tf
+then
+ if test -f $td/OLD$tf
+ then
+ rm -f $td/OLD$tf
+ fi
+ mv $td/$tf $td/OLD$tf
+ if [ $? != 0 ]
+ then
+ exit 3
+ fi
+fi
+
+# Now do the copy and return appropriate status
+
+cp $fd/$ff $td/$tf
+if [ $? != 0 ]
+then
+ exit 4
+else
+ exit 0
+fi
+
diff --git a/dbug/main.c b/dbug/main.c
new file mode 100644
index 00000000000..863b4d319c2
--- /dev/null
+++ b/dbug/main.c
@@ -0,0 +1,33 @@
+#ifdef DBUG_OFF /* We are testing dbug */
+#undef DBUG_OFF
+#endif
+
+#include <global.h> /* This includes dbug.h */
+
+int main (argc, argv)
+int argc;
+char *argv[];
+{
+ register int result, ix;
+ extern int factorial(int);
+#if defined(HAVE_PTHREAD_INIT) && defined(THREAD)
+ pthread_init(); /* Must be called before DBUG_ENTER */
+#endif
+ {
+ DBUG_ENTER ("main");
+ DBUG_PROCESS (argv[0]);
+ for (ix = 1; ix < argc && argv[ix][0] == '-'; ix++) {
+ switch (argv[ix][1]) {
+ case '#':
+ DBUG_PUSH (&(argv[ix][2]));
+ break;
+ }
+ }
+ for (; ix < argc; ix++) {
+ DBUG_PRINT ("args", ("argv[%d] = %s", ix, argv[ix]));
+ result = factorial (atoi(argv[ix]));
+ printf ("%d\n", result);
+ }
+ DBUG_RETURN (0);
+ }
+}
diff --git a/dbug/mklintlib.sh b/dbug/mklintlib.sh
new file mode 100644
index 00000000000..6963016f334
--- /dev/null
+++ b/dbug/mklintlib.sh
@@ -0,0 +1,30 @@
+
+# Warning - first line left blank for sh/csh/ksh compatibility. Do not
+# remove it. fnf@Unisoft
+
+# mklintlib --- make a lint library, under either System V or 4.2 BSD
+#
+# usage: mklintlib <infile> <outfile>
+#
+
+if test $# -ne 2
+then
+ echo "usage: mklintlib <infile> <outfile>"
+ exit 1
+fi
+
+if grep SIGTSTP /usr/include/signal.h >/dev/null
+then # BSD
+ if test -r /usr/include/whoami.h # 4.1
+ then
+ /lib/cpp -C -Dlint $1 >hlint
+ (/usr/lib/lint/lint1 <hlint >$2) 2>&1 | grep -v warning
+ else # 4.2
+ lint -Cxxxx $1
+ mv llib-lxxxx.ln $2
+ fi
+else # USG
+ cc -E -C -Dlint $1 | /usr/lib/lint1 -vx -Hhlint >$2
+ rm -f hlint
+fi
+exit 0 # don't kill make
diff --git a/dbug/monty.doc b/dbug/monty.doc
new file mode 100644
index 00000000000..c96f0742b26
--- /dev/null
+++ b/dbug/monty.doc
@@ -0,0 +1,12 @@
+Some extra options to DBUG_PUSH:
+
+O,logfile - As "o,logfile", but do a close and reopen each time anything
+ is written to the logfile. This is neaded when one expects
+ the program to crash anywhere, in which case one dosen't
+ (at least in MSDOS) get a full log-file.
+
+If one wants a logfile with a ': in the filename, one can get it by
+giving a double ':'. (As in "O,c::\tmp\log")
+
+DBUG_DUMP("keyword",memory-position,length) writes a hexdump of the
+given memory-area to the outputfile.
diff --git a/dbug/qmake.cmd b/dbug/qmake.cmd
new file mode 100644
index 00000000000..ebd4432f7fc
--- /dev/null
+++ b/dbug/qmake.cmd
@@ -0,0 +1,4 @@
+CL -I\my\include -AL -Gsm2 -FPi -DDBUG_OFF *.c
+rm \my\lib\dbug.lib
+lib.exe \my\lib\dbug dbug.obj sanity.obj;
+link /NOD /STACK:8000 main factoria,factoria,,DBUG+STRINGS+LLIBCEP+DOSCALLS;
diff --git a/dbug/readme.prof b/dbug/readme.prof
new file mode 100644
index 00000000000..cfffe376857
--- /dev/null
+++ b/dbug/readme.prof
@@ -0,0 +1,70 @@
+Hi,
+
+I'm sending you the modifications I made to your Dbug routines to
+allow profiling in a (relatively) machine independent fashion.
+I use your Dbug routines fairly extensively. Unfortunately, it's
+a royal pain to have to keep profiled versions of various libraries
+around. The modifications allow profiling without the need for this.
+
+How it works.
+------------
+
+Basically, I just added code in the dbug routines to write out a file
+called dbugmon.out (by default). This is an ascii file containing lines
+of the form:
+
+<function-name> E <time-entered>
+<function-name> X <time-exited>
+
+A second program (analyze) reads this file, and produces a report on
+standard output.
+
+Profiling is enabled through the `g' flag. It can take a list of
+procedure names for which profiling is enabled. By default, it
+profiles all procedures.
+
+The code in ``dbug.c'' opens the profile file for appending. This
+is in order that one can run a program several times, and get the
+sum total of all the times, etc.
+
+The only system dependent part that I'm aware of is the routine
+Clock() at the end of dbug.c. This returns the elapsed user time
+in milliseconds. The version which I have is for 4.3 BSD. As I
+don't have access to other systems, I'm not certain how this would
+change.
+
+An example of the report generated follows:
+
+ Profile of Execution
+ Execution times are in milliseconds
+
+ Calls Time
+ ----- ----
+ Times Percentage Time Spent Percentage
+Function Called of total in Function of total Importance
+======== ====== ========== =========== ========== ==========
+factorial 5 83.33 30 100.00 8333
+main 1 16.67 0 0.00 0
+======== ====== ========== =========== ==========
+Totals 6 100.00 30 100.00
+
+
+As you can see, it's quite self-evident. The ``Importance'' column is a
+metric obtained by multiplying the percentage of the calls and the percentage
+of the time. Functions with higher 'importance' benefit the most from
+being sped up.
+
+I'm really not certain how to add support for setjmp/longjmp, or for
+child processes, so I've ignored that for the time being. In most of
+the code that I write, it isn't necessary. If you have any good ideas,
+feel free to add them.
+
+This has been very useful to me. If you can use it as part of your
+dbug distribution, please feel free to do so.
+
+Regards,
+
+ Binayak Banerjee
+ {allegra | astrovax | bpa | burdvax}!sjuvax!bbanerje
+ bbanerje%sjuvax.sju.edu@relay.cs.net
+ July 9, 1987
diff --git a/dbug/sanity.c b/dbug/sanity.c
new file mode 100644
index 00000000000..d287a468028
--- /dev/null
+++ b/dbug/sanity.c
@@ -0,0 +1,13 @@
+/* Declarate _sanity() if not declared in main program */
+
+#include <global.h>
+
+extern int _sanity(const char *file,uint line);
+
+#if defined(SAFEMALLOC) && !defined(MASTER) /* Avoid errors in MySQL */
+int _sanity(const char * file __attribute__((unused)),
+ uint line __attribute__((unused)))
+{
+ return 0;
+}
+#endif
diff --git a/dbug/user.r b/dbug/user.r
new file mode 100644
index 00000000000..e8321243962
--- /dev/null
+++ b/dbug/user.r
@@ -0,0 +1,937 @@
+.\" @(#)user.r 1.13 10/29/86
+.\"
+.\" DBUG (Macro Debugger Package) nroff source
+.\"
+.\" nroff -mm user.r >user.t
+.\"
+.\" ===================================================
+.\"
+.\" === Some sort of black magic, but I forget...
+.tr ~
+.\" === Hyphenation control (1 = on)
+.\".nr Hy 1
+.\" === Force all first level headings to start on new page
+.nr Ej 1
+.\" === Set for breaks after headings for levels 1-3
+.nr Hb 3
+.\" === Set for space after headings for levels 1-3
+.nr Hs 3
+.\" === Set standard indent for one/half inch
+.nr Si 10
+.\" === Set page header
+.PH "/DBUG User Manual//\*(DT/"
+.\" === Set page footer
+.PF "// - % - //"
+.\" === Set page offset
+.\".po 0.60i
+.\" === Set line length
+.\".ll 6.5i
+.TL
+D B U G
+.P 0
+C Program Debugging Package
+.P 0
+by
+.AU "Fred Fish"
+.AF ""
+.SA 1
+.\" === All paragraphs indented.
+.nr Pt 1
+.AS 1
+This document introduces
+.I dbug ,
+a macro based C debugging
+package which has proven to be a very flexible and useful tool
+for debugging, testing, and porting C programs.
+
+.P
+All of the features of the
+.I dbug
+package can be enabled or disabled dynamically at execution time.
+This means that production programs will run normally when
+debugging is not enabled, and eliminates the need to maintain two
+separate versions of a program.
+
+.P
+Many of the things easily accomplished with conventional debugging
+tools, such as symbolic debuggers, are difficult or impossible with this
+package, and vice versa.
+Thus the
+.I dbug
+package should
+.I not
+be thought of as a replacement or substitute for
+other debugging tools, but simply as a useful
+.I addition
+to the
+program development and maintenance environment.
+
+.AE
+.MT 4
+.SK
+.B
+INTRODUCTION
+.R
+
+.P
+Almost every program development environment worthy of the name
+provides some sort of debugging facility.
+Usually this takes the form of a program which is capable of
+controlling execution of other programs and examining the internal
+state of other executing programs.
+These types of programs will be referred to as external debuggers
+since the debugger is not part of the executing program.
+Examples of this type of debugger include the
+.B adb
+and
+.B sdb
+debuggers provided with the
+.B UNIX\*F
+.FS
+UNIX is a trademark of AT&T Bell Laboratories.
+.FE
+operating system.
+
+.P
+One of the problems associated with developing programs in an environment
+with good external debuggers is that developed programs tend to have
+little or no internal instrumentation.
+This is usually not a problem for the developer since he is,
+or at least should be, intimately familiar with the internal organization,
+data structures, and control flow of the program being debugged.
+It is a serious problem for maintenance programmers, who
+are unlikely to have such familiarity with the program being
+maintained, modified, or ported to another environment.
+It is also a problem, even for the developer, when the program is
+moved to an environment with a primitive or unfamiliar debugger,
+or even no debugger.
+
+.P
+On the other hand,
+.I dbug
+is an example of an internal debugger.
+Because it requires internal instrumentation of a program,
+and its usage does not depend on any special capabilities of
+the execution environment, it is always available and will
+execute in any environment that the program itself will
+execute in.
+In addition, since it is a complete package with a specific
+user interface, all programs which use it will be provided
+with similar debugging capabilities.
+This is in sharp contrast to other forms of internal instrumentation
+where each developer has their own, usually less capable, form
+of internal debugger.
+In summary,
+because
+.I dbug
+is an internal debugger it provides consistency across operating
+environments,
+and because it is available to all developers it provides
+consistency across all programs in the same environment.
+
+.P
+The
+.I dbug
+package imposes only a slight speed penalty on executing
+programs, typically much less than 10 percent, and a modest size
+penalty, typically 10 to 20 percent.
+By defining a specific C preprocessor symbol both of these
+can be reduced to zero with no changes required to the
+source code.
+
+.P
+The following list is a quick summary of the capabilities
+of the
+.I dbug
+package.
+Each capability can be individually enabled or disabled
+at the time a program is invoked by specifying the appropriate
+command line arguments.
+.SP 1
+.ML o 1i
+.LI
+Execution trace showing function level control flow in a
+semi-graphically manner using indentation to indicate nesting
+depth.
+.LI
+Output the values of all, or any subset of, key internal variables.
+.LI
+Limit actions to a specific set of named functions.
+.LI
+Limit function trace to a specified nesting depth.
+.LI
+Label each output line with source file name and line number.
+.LI
+Label each output line with name of current process.
+.LI
+Push or pop internal debugging state to allow execution with
+built in debugging defaults.
+.LI
+Redirect the debug output stream to standard output (stdout)
+or a named file.
+The default output stream is standard error (stderr).
+The redirection mechanism is completely independent of
+normal command line redirection to avoid output conflicts.
+.LE
+
+.SK
+.B
+PRIMITIVE DEBUGGING TECHNIQUES
+.R
+
+.P
+Internal instrumentation is already a familiar concept
+to most programmers, since it is usually the first debugging
+technique learned.
+Typically, "print\ statements" are inserted in the source
+code at interesting points, the code is recompiled and executed,
+and the resulting output is examined in an attempt to determine
+where the problem is.
+
+The procedure is iterative, with each iteration yielding more
+and more output, and hopefully the source of the problem is
+discovered before the output becomes too large to deal with
+or previously inserted statements need to be removed.
+Figure 1 is an example of this type of primitive debugging
+technique.
+.DS I N
+.SP 2
+.so example1.r
+.SP 2
+.ll -5
+.ce
+Figure 1
+.ce
+Primitive Debugging Technique
+.ll +5
+.SP 2
+.DE
+
+.P
+Eventually, and usually after at least several iterations, the
+problem will be found and corrected.
+At this point, the newly inserted print statements must be
+dealt with.
+One obvious solution is to simply delete them all.
+Beginners usually do this a few times until they have to
+repeat the entire process every time a new bug pops up.
+The second most obvious solution is to somehow disable
+the output, either through the source code comment facility,
+creation of a debug variable to be switched on or off, or by using the
+C preprocessor.
+Figure 2 is an example of all three techniques.
+.DS I N
+.SP 2
+.so example2.r
+.SP 2
+.ll -5
+.ce
+Figure 2
+.ce
+Debug Disable Techniques
+.ll +5
+.SP 2
+.DE
+
+.P
+Each technique has its advantages and disadvantages with respect
+to dynamic vs static activation, source code overhead, recompilation
+requirements, ease of use, program readability, etc.
+Overuse of the preprocessor solution quickly leads to problems with
+source code readability and maintainability when multiple
+.B #ifdef
+symbols are to be defined or undefined based on specific types
+of debug desired.
+The source code can be made slightly more readable by suitable indentation
+of the
+.B #ifdef
+arguments to match the indentation of the code, but
+not all C preprocessors allow this.
+The only requirement for the standard
+.B UNIX
+C preprocessor is for the '#' character to appear
+in the first column, but even this seems
+like an arbitrary and unreasonable restriction.
+Figure 3 is an example of this usage.
+.DS I N
+.SP 2
+.so example3.r
+.SP 2
+.ll -5
+.ce
+Figure 3
+.ce
+More Readable Preprocessor Usage
+.ll +5
+.SP 2
+.DE
+
+.SK
+.B
+FUNCTION TRACE EXAMPLE
+.R
+
+.P
+We will start off learning about the capabilities of the
+.I dbug
+package by using a simple minded program which computes the
+factorial of a number.
+In order to better demonstrate the function trace mechanism, this
+program is implemented recursively.
+Figure 4 is the main function for this factorial program.
+.DS I N
+.SP 2
+.so main.r
+.SP 2
+.ll -5
+.ce
+Figure 4
+.ce
+Factorial Program Mainline
+.ll +5
+.SP 2
+.DE
+
+.P
+The
+.B main
+function is responsible for processing any command line
+option arguments and then computing and printing the factorial of
+each non-option argument.
+.P
+First of all, notice that all of the debugger functions are implemented
+via preprocessor macros.
+This does not detract from the readability of the code and makes disabling
+all debug compilation trivial (a single preprocessor symbol,
+.B DBUG_OFF ,
+forces the macro expansions to be null).
+.P
+Also notice the inclusion of the header file
+.B dbug.h
+from the local header file directory.
+(The version included here is the test version in the dbug source
+distribution directory).
+This file contains all the definitions for the debugger macros, which
+all have the form
+.B DBUG_XX...XX .
+
+.P
+The
+.B DBUG_ENTER
+macro informs that debugger that we have entered the
+function named
+.B main .
+It must be the very first "executable" line in a function, after
+all declarations and before any other executable line.
+The
+.B DBUG_PROCESS
+macro is generally used only once per program to
+inform the debugger what name the program was invoked with.
+The
+.B DBUG_PUSH
+macro modifies the current debugger state by
+saving the previous state and setting a new state based on the
+control string passed as its argument.
+The
+.B DBUG_PRINT
+macro is used to print the values of each argument
+for which a factorial is to be computed.
+The
+.B DBUG_RETURN
+macro tells the debugger that the end of the current
+function has been reached and returns a value to the calling
+function.
+All of these macros will be fully explained in subsequent sections.
+.P
+To use the debugger, the factorial program is invoked with a command
+line of the form:
+.DS CB N
+factorial -#d:t 1 2 3
+.DE
+The
+.B main
+function recognizes the "-#d:t" string as a debugger control
+string, and passes the debugger arguments ("d:t") to the
+.I dbug
+runtime support routines via the
+.B DBUG_PUSH
+macro.
+This particular string enables output from the
+.B DBUG_PRINT
+macro with the 'd' flag and enables function tracing with the 't' flag.
+The factorial function is then called three times, with the arguments
+"1", "2", and "3".
+Note that the DBUG_PRINT takes exactly
+.B two
+arguments, with the second argument (a format string and list
+of printable values) enclosed in parenthesis.
+.P
+Debug control strings consist of a header, the "-#", followed
+by a colon separated list of debugger arguments.
+Each debugger argument is a single character flag followed
+by an optional comma separated list of arguments specific
+to the given flag.
+Some examples are:
+.DS CB N
+-#d:t:o
+-#d,in,out:f,main:F:L
+.DE
+Note that previously enabled debugger actions can be disabled by the
+control string "-#".
+
+.P
+The definition of the factorial function, symbolized as "N!", is
+given by:
+.DS CB N
+N! = N * N-1 * ... 2 * 1
+.DE
+Figure 5 is the factorial function which implements this algorithm
+recursively.
+Note that this is not necessarily the best way to do factorials
+and error conditions are ignored completely.
+.DS I N
+.SP 2
+.so factorial.r
+.SP 2
+.ll -5
+.ce
+Figure 5
+.ce
+Factorial Function
+.ll +5
+.SP 2
+.DE
+
+.P
+One advantage (some may not consider it so) to using the
+.I dbug
+package is that it strongly encourages fully structured coding
+with only one entry and one exit point in each function.
+Multiple exit points, such as early returns to escape a loop,
+may be used, but each such point requires the use of an
+appropriate
+.B DBUG_RETURN
+or
+.B DBUG_VOID_RETURN
+macro.
+
+.P
+To build the factorial program on a
+.B UNIX
+system, compile and
+link with the command:
+.DS CB N
+cc -o factorial main.c factorial.c -ldbug
+.DE
+The "-ldbug" argument tells the loader to link in the
+runtime support modules for the
+.I dbug
+package.
+Executing the factorial program with a command of the form:
+.DS CB N
+factorial 1 2 3 4 5
+.DE
+generates the output shown in figure 6.
+.DS I N
+.SP 2
+.so output1.r
+.SP 2
+.ll -5
+.ce
+Figure 6
+.ce
+factorial 1 2 3 4 5
+.ll +5
+.SP 2
+.DE
+
+.P
+Function level tracing is enabled by passing the debugger
+the 't' flag in the debug control string.
+Figure 7 is the output resulting from the command
+"factorial\ -#t:o\ 3\ 2".
+.DS I N
+.SP 2
+.so output2.r
+.SP 2
+.ll -5
+.ce
+Figure 7
+.ce
+factorial -#t:o 3 2
+.ll +5
+.SP 2
+.DE
+
+.P
+Each entry to or return from a function is indicated by '>' for the
+entry point and '<' for the exit point, connected by
+vertical bars to allow matching points to be easily found
+when separated by large distances.
+
+.P
+This trace output indicates that there was an initial call
+to factorial from main (to compute 2!), followed by
+a single recursive call to factorial to compute 1!.
+The main program then output the result for 2! and called the
+factorial function again with the second argument, 3.
+Factorial called itself recursively to compute 2! and 1!, then
+returned control to main, which output the value for 3! and exited.
+
+.P
+Note that there is no matching entry point "main>" for the
+return point "<main" because at the time the
+.B DBUG_ENTER
+macro was reached in main, tracing was not enabled yet.
+It was only after the macro
+.B DBUG_PUSH
+was executing that tracing became enabled.
+This implies that the argument list should be processed as early as
+possible since all code preceding the first call to
+.B DBUG_PUSH
+is
+essentially invisible to
+.B dbug
+(this can be worked around by
+inserting a temporary
+.B DBUG_PUSH(argv[1])
+immediately after the
+.B DBUG_ENTER("main")
+macro.
+
+.P
+One last note,
+the trace output normally comes out on the standard error.
+Since the factorial program prints its result on the standard
+output, there is the possibility of the output on the terminal
+being scrambled if the two streams are not synchronized.
+Thus the debugger is told to write its output on the standard
+output instead, via the 'o' flag character.
+Note that no 'o' implies the default (standard error), a 'o'
+with no arguments means standard output, and a 'o'
+with an argument means used the named file.
+I.E, "factorial\ -#t:o,logfile\ 3\ 2" would write the trace
+output in "logfile".
+Because of
+.B UNIX
+implementation details, programs usually run
+faster when writing to stdout rather than stderr, though this
+is not a prime consideration in this example.
+
+.SK
+.B
+USE OF DBUG_PRINT MACRO
+.R
+
+.P
+The mechanism used to produce "printf" style output is the
+.B DBUG_PRINT
+macro.
+
+.P
+To allow selection of output from specific macros, the first argument
+to every
+.B DBUG_PRINT
+macro is a
+.I dbug
+keyword.
+When this keyword appears in the argument list of the 'd' flag in
+a debug control string, as in "-#d,keyword1,keyword2,...:t",
+output from the corresponding macro is enabled.
+The default when there is no 'd' flag in the control string is to
+enable output from all
+.B DBUG_PRINT
+macros.
+
+.P
+Typically, a program will be run once, with no keywords specified,
+to determine what keywords are significant for the current problem
+(the keywords are printed in the macro output line).
+Then the program will be run again, with the desired keywords,
+to examine only specific areas of interest.
+
+.P
+The second argument to a
+.B DBUG_PRINT
+macro is a standard printf style
+format string and one or more arguments to print, all
+enclosed in parenthesis so that they collectively become a single macro
+argument.
+This is how variable numbers of printf arguments are supported.
+Also note that no explicit newline is required at the end of the format string.
+As a matter of style, two or three small
+.B DBUG_PRINT
+macros are preferable
+to a single macro with a huge format string.
+Figure 8 shows the output for default tracing and debug.
+.DS I N
+.SP 2
+.so output3.r
+.SP 2
+.ll -5
+.ce
+Figure 8
+.ce
+factorial -#d:t:o 3
+.ll +5
+.SP 2
+.DE
+
+.P
+The output from the
+.B DBUG_PRINT
+macro is indented to match the trace output
+for the function in which the macro occurs.
+When debugging is enabled, but not trace, the output starts at the left
+margin, without indentation.
+
+.P
+To demonstrate selection of specific macros for output, figure
+9 shows the result when the factorial program is invoked with
+the debug control string "-#d,result:o".
+.DS I N
+.SP 2
+.so output4.r
+.SP 2
+.ll -5
+.ce
+Figure 9
+.ce
+factorial -#d,result:o 4
+.ll +5
+.SP 2
+.DE
+
+.P
+It is sometimes desirable to restrict debugging and trace actions
+to a specific function or list of functions.
+This is accomplished with the 'f' flag character in the debug
+control string.
+Figure 10 is the output of the factorial program when run with the
+control string "-#d:f,factorial:F:L:o".
+The 'F' flag enables printing of the source file name and the 'L'
+flag enables printing of the source file line number.
+.DS I N
+.SP 2
+.so output5.r
+.SP 2
+.ll -5
+.ce
+Figure 10
+.ce
+factorial -#d:f,factorial:F:L:o 3
+.ll +5
+.SP 2
+.DE
+
+.P
+The output in figure 10 shows that the "find" macro is in file
+"factorial.c" at source line 8 and the "result" macro is in the same
+file at source line 12.
+
+.SK
+.B
+SUMMARY OF MACROS
+.R
+
+.P
+This section summarizes the usage of all currently defined macros
+in the
+.I dbug
+package.
+The macros definitions are found in the user include file
+.B dbug.h
+from the standard include directory.
+
+.SP 2
+.BL 20
+.LI DBUG_ENTER\
+Used to tell the runtime support module the name of the function
+being entered.
+The argument must be of type "pointer to character".
+The
+DBUG_ENTER
+macro must precede all executable lines in the
+function just entered, and must come after all local declarations.
+Each
+DBUG_ENTER
+macro must have a matching
+DBUG_RETURN
+or
+DBUG_VOID_RETURN
+macro
+at the function exit points.
+DBUG_ENTER
+macros used without a matching
+DBUG_RETURN
+or
+DBUG_VOID_RETURN
+macro
+will cause warning messages from the
+.I dbug
+package runtime support module.
+.SP 1
+EX:\ DBUG_ENTER\ ("main");
+.SP 1
+.LI DBUG_RETURN\
+Used at each exit point of a function containing a
+DBUG_ENTER
+macro
+at the entry point.
+The argument is the value to return.
+Functions which return no value (void) should use the
+DBUG_VOID_RETURN
+macro.
+It
+is an error to have a
+DBUG_RETURN
+or
+DBUG_VOID_RETURN
+macro in a function
+which has no matching
+DBUG_ENTER
+macro, and the compiler will complain
+if the macros are actually used (expanded).
+.SP 1
+EX:\ DBUG_RETURN\ (value);
+.br
+EX:\ DBUG_VOID_RETURN;
+.SP 1
+.LI DBUG_PROCESS\
+Used to name the current process being executed.
+A typical argument for this macro is "argv[0]", though
+it will be perfectly happy with any other string.
+.SP 1
+EX:\ DBUG_PROCESS\ (argv[0]);
+.SP 1
+.LI DBUG_PUSH\
+Sets a new debugger state by pushing the current
+.B dbug
+state onto an
+internal stack and setting up the new state using the debug control
+string passed as the macro argument.
+The most common usage is to set the state specified by a debug
+control string retrieved from the argument list.
+Note that the leading "-#" in a debug control string specified
+as a command line argument must
+.B not
+be passed as part of the macro argument.
+The proper usage is to pass a pointer to the first character
+.B after
+the "-#" string.
+.SP 1
+EX:\ DBUG_PUSH\ (\&(argv[i][2]));
+.br
+EX:\ DBUG_PUSH\ ("d:t");
+.br
+EX:\ DBUG_PUSH\ ("");
+.SP 1
+.LI DBUG_POP\
+Restores the previous debugger state by popping the state stack.
+Attempting to pop more states than pushed will be ignored and no
+warning will be given.
+The
+DBUG_POP
+macro has no arguments.
+.SP 1
+EX:\ DBUG_POP\ ();
+.SP 1
+.LI DBUG_FILE\
+The
+DBUG_FILE
+macro is used to do explicit I/O on the debug output
+stream.
+It is used in the same manner as the symbols "stdout" and "stderr"
+in the standard I/O package.
+.SP 1
+EX:\ fprintf\ (DBUG_FILE,\ "Doing my own I/O!\n");
+.SP 1
+.LI DBUG_EXECUTE\
+The DBUG_EXECUTE macro is used to execute any arbitrary C code.
+The first argument is the debug keyword, used to trigger execution
+of the code specified as the second argument.
+This macro must be used cautiously because, like the
+DBUG_PRINT
+macro,
+it is automatically selected by default whenever the 'd' flag has
+no argument list (I.E., a "-#d:t" control string).
+.SP 1
+EX:\ DBUG_EXECUTE\ ("abort",\ abort\ ());
+.SP 1
+.LI DBUG_N\
+These macros, where N is in the range 2-5, are currently obsolete
+and will be removed in a future release.
+Use the new DBUG_PRINT macro.
+.LI DBUG_PRINT\
+Used to do printing via the "fprintf" library function on the
+current debug stream,
+DBUG_FILE.
+The first argument is a debug keyword, the second is a format string
+and the corresponding argument list.
+Note that the format string and argument list are all one macro argument
+and
+.B must
+be enclosed in parenthesis.
+.SP 1
+EX:\ DBUG_PRINT\ ("eof",\ ("end\ of\ file\ found"));
+.br
+EX:\ DBUG_PRINT\ ("type",\ ("type\ is\ %x", type));
+.br
+EX:\ DBUG_PRINT\ ("stp",\ ("%x\ ->\ %s", stp, stp\ ->\ name));
+.LI DBUG_SETJMP\
+Used in place of the setjmp() function to first save the current
+debugger state and then execute the standard setjmp call.
+This allows to the debugger to restore it's state when the
+DBUG_LONGJMP macro is used to invoke the standard longjmp() call.
+Currently all instances of DBUG_SETJMP must occur within the
+same function and at the same function nesting level.
+.SP 1
+EX:\ DBUG_SETJMP\ (env);
+.LI DBUG_LONGJMP\
+Used in place of the longjmp() function to first restore the
+previous debugger state at the time of the last DBUG_SETJMP
+and then execute the standard longjmp() call.
+Note that currently all DBUG_LONGJMP macros restore the state
+at the time of the last DBUG_SETJMP.
+It would be possible to maintain separate DBUG_SETJMP and DBUG_LONGJMP
+pairs by having the debugger runtime support module use the first
+argument to differentiate the pairs.
+.SP 1
+EX:\ DBUG_LONGJMP\ (env,val);
+.LE
+
+.SK
+.B
+DEBUG CONTROL STRING
+.R
+
+.P
+The debug control string is used to set the state of the debugger
+via the
+.B DBUG_PUSH
+macro.
+This section summarizes the currently available debugger options
+and the flag characters which enable or disable them.
+Argument lists enclosed in '[' and ']' are optional.
+.SP 2
+.BL 22
+.LI d[,keywords]
+Enable output from macros with specified keywords.
+A null list of keywords implies that all keywords are selected.
+.LI D[,time]
+Delay for specified time after each output line, to let output drain.
+Time is given in tenths of a second (value of 10 is one second).
+Default is zero.
+.LI f[,functions]
+Limit debugger actions to the specified list of functions.
+A null list of functions implies that all functions are selected.
+.LI F
+Mark each debugger output line with the name of the source file
+containing the macro causing the output.
+.LI L
+Mark each debugger output line with the source file line number of
+the macro causing the output.
+.LI n
+Mark each debugger output line with the current function nesting depth.
+.LI N
+Sequentially number each debugger output line starting at 1.
+This is useful for reference purposes when debugger output is
+interspersed with program output.
+.LI o[,file]
+Redirect the debugger output stream to the specified file.
+The default output stream is stderr.
+A null argument list causes output to be redirected to stdout.
+.LI p[,processes]
+Limit debugger actions to the specified processes.
+A null list implies all processes.
+This is useful for processes which run child processes.
+Note that each debugger output line can be marked with the name of
+the current process via the 'P' flag.
+The process name must match the argument passed to the
+.B DBUG_PROCESS
+macro.
+.LI P
+Mark each debugger output line with the name of the current process.
+Most useful when used with a process which runs child processes that
+are also being debugged.
+Note that the parent process must arrange for the debugger control
+string to be passed to the child processes.
+.LI r
+Used in conjunction with the
+.B DBUG_PUSH
+macro to reset the current
+indentation level back to zero.
+Most useful with
+.B DBUG_PUSH
+macros used to temporarily alter the
+debugger state.
+.LI t[,N]
+Enable function control flow tracing.
+The maximum nesting depth is specified by N, and defaults to
+200.
+.LE
+.SK
+.B
+HINTS AND MISCELLANEOUS
+.R
+
+.P
+One of the most useful capabilities of the
+.I dbug
+package is to compare the executions of a given program in two
+different environments.
+This is typically done by executing the program in the environment
+where it behaves properly and saving the debugger output in a
+reference file.
+The program is then run with identical inputs in the environment where
+it misbehaves and the output is again captured in a reference file.
+The two reference files can then be differentially compared to
+determine exactly where execution of the two processes diverges.
+
+.P
+A related usage is regression testing where the execution of a current
+version is compared against executions of previous versions.
+This is most useful when there are only minor changes.
+
+.P
+It is not difficult to modify an existing compiler to implement
+some of the functionality of the
+.I dbug
+package automatically, without source code changes to the
+program being debugged.
+In fact, such changes were implemented in a version of the
+Portable C Compiler by the author in less than a day.
+However, it is strongly encouraged that all newly
+developed code continue to use the debugger macros
+for the portability reasons noted earlier.
+The modified compiler should be used only for testing existing
+programs.
+
+.SK
+.B
+CAVEATS
+.R
+
+.P
+The
+.I dbug
+package works best with programs which have "line\ oriented"
+output, such as text processors, general purpose utilities, etc.
+It can be interfaced with screen oriented programs such as
+visual editors by redefining the appropriate macros to call
+special functions for displaying the debugger results.
+Of course, this caveat is not applicable if the debugger output
+is simply dumped into a file for post-execution examination.
+
+.P
+Programs which use memory allocation functions other than
+.B malloc
+will usually have problems using the standard
+.I dbug
+package.
+The most common problem is multiply allocated memory.
+.SP 2
+.\" .DE nroff dident like this. davida 900108
+.CS
+
+
diff --git a/dbug/vargs.h b/dbug/vargs.h
new file mode 100644
index 00000000000..4609c8301bb
--- /dev/null
+++ b/dbug/vargs.h
@@ -0,0 +1,139 @@
+/******************************************************************************
+ * *
+ * N O T I C E *
+ * *
+ * Copyright Abandoned, 1987, Fred Fish *
+ * *
+ * *
+ * This previously copyrighted work has been placed into the public *
+ * domain by the author and may be freely used for any purpose, *
+ * private or commercial. *
+ * *
+ * Because of the number of inquiries I was receiving about the use *
+ * of this product in commercially developed works I have decided to *
+ * simply make it public domain to further its unrestricted use. I *
+ * specifically would be most happy to see this material become a *
+ * part of the standard Unix distributions by AT&T and the Berkeley *
+ * Computer Science Research Group, and a standard part of the GNU *
+ * system from the Free Software Foundation. *
+ * *
+ * I would appreciate it, as a courtesy, if this notice is left in *
+ * all copies and derivative works. Thank you. *
+ * *
+ * The author makes no warranty of any kind with respect to this *
+ * product and explicitly disclaims any implied warranties of mer- *
+ * chantability or fitness for any particular purpose. *
+ * *
+ ******************************************************************************
+ */
+
+
+/*
+ * FILE
+ *
+ * vargs.h include file for environments without varargs.h
+ *
+ * SCCS
+ *
+ * @(#)vargs.h 1.2 5/8/88
+ *
+ * SYNOPSIS
+ *
+ * #include "vargs.h"
+ *
+ * DESCRIPTION
+ *
+ * This file implements a varargs macro set for use in those
+ * environments where there is no system supplied varargs. This
+ * generally works because systems which don't supply a varargs
+ * package are precisely those which don't strictly need a varargs
+ * package. Using this one then allows us to minimize source
+ * code changes. So in some sense, this is a "portable" varargs
+ * since it is only used for convenience, when it is not strictly
+ * needed.
+ *
+ */
+
+/*
+ * These macros allow us to rebuild an argument list on the stack
+ * given only a va_list. We can use these to fake a function like
+ * vfprintf, which gets a fixed number of arguments, the last of
+ * which is a va_list, by rebuilding a stack and calling the variable
+ * argument form fprintf. Of course this only works when vfprintf
+ * is not available in the host environment, and thus is not available
+ * for fprintf to call (which would give us an infinite loop).
+ *
+ * Note that ARGS_TYPE is a long, which lets us get several bytes
+ * at a time while also preventing lots of "possible pointer alignment
+ * problem" messages from lint. The messages are valid, because this
+ * IS nonportable, but then we should only be using it in very
+ * nonrestrictive environments, and using the real varargs where it
+ * really counts.
+ *
+ */
+
+#define ARG0 a0
+#define ARG1 a1
+#define ARG2 a2
+#define ARG3 a3
+#define ARG4 a4
+#define ARG5 a5
+#define ARG6 a6
+#define ARG7 a7
+#define ARG8 a8
+#define ARG9 a9
+
+#define ARGS_TYPE long
+#define ARGS_LIST ARG0,ARG1,ARG2,ARG3,ARG4,ARG5,ARG6,ARG7,ARG8,ARG9
+#define ARGS_DCL auto ARGS_TYPE ARGS_LIST
+
+/*
+ * A pointer of type "va_list" points to a section of memory
+ * containing an array of variable sized arguments of unknown
+ * number. This pointer is initialized by the va_start
+ * macro to point to the first byte of the first argument.
+ * We can then use it to walk through the argument list by
+ * incrementing it by the size of the argument being referenced.
+ */
+
+typedef char *va_list;
+
+/*
+ * The first variable argument overlays va_alist, which is
+ * nothing more than a "handle" which allows us to get the
+ * address of the first argument on the stack. Note that
+ * by definition, the va_dcl macro includes the terminating
+ * semicolon, which makes use of va_dcl in the source code
+ * appear to be missing a semicolon.
+ */
+
+#define va_dcl ARGS_TYPE va_alist;
+
+/*
+ * The va_start macro takes a variable of type "va_list" and
+ * initializes it. In our case, it initializes a local variable
+ * of type "pointer to char" to point to the first argument on
+ * the stack.
+ */
+
+#define va_start(list) list = (char *) &va_alist
+
+/*
+ * The va_end macro is a null operation for our use.
+ */
+
+#define va_end(list)
+
+/*
+ * The va_arg macro is the tricky one. This one takes
+ * a va_list as the first argument, and a type as the second
+ * argument, and returns a value of the appropriate type
+ * while advancing the va_list to the following argument.
+ * For our case, we first increment the va_list arg by the
+ * size of the type being recovered, cast the result to
+ * a pointer of the appropriate type, and then dereference
+ * that pointer as an array to get the previous arg (which
+ * is the one we wanted.
+ */
+
+#define va_arg(list,type) ((type *) (list += sizeof (type)))[-1]
diff --git a/extra/.cvsignore b/extra/.cvsignore
new file mode 100644
index 00000000000..e0042c405cc
--- /dev/null
+++ b/extra/.cvsignore
@@ -0,0 +1,10 @@
+.deps
+.libs
+Makefile
+Makefile.in
+comp_err
+my_print_defaults
+perror
+print_defaults
+replace
+resolveip
diff --git a/extra/Attic/print_defaults.c b/extra/Attic/print_defaults.c
new file mode 100644
index 00000000000..a6e67e4949e
--- /dev/null
+++ b/extra/Attic/print_defaults.c
@@ -0,0 +1,125 @@
+/* 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 */
+
+/*
+** print_default.c:
+** Print all parameters in a default file that will be given to some program.
+**
+** Written by Monty
+*/
+
+#include <global.h>
+#include <my_sys.h>
+#include <getopt.h>
+
+const char *config_file="my"; /* Default config file */
+
+static struct option long_options[] =
+{
+ {"config-file", required_argument, 0, 'c'},
+ {"defaults-file", required_argument, 0, 'c'},
+ {"no-defaults", no_argument, 0, 'd'},
+ {"help", no_argument, 0, '?'},
+ {"version", no_argument, 0, 'V'},
+ {0, 0, 0, 0}
+};
+
+static void usage(my_bool version)
+{
+ printf("%s Ver 1.1 for %s at %s\n",my_progname,SYSTEM_TYPE,
+ MACHINE_TYPE);
+ if (version)
+ return;
+ 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("Prints all arguments that is give to some program using the default files");
+ printf("Usage: %s [OPTIONS] groups\n",my_progname);
+ printf("\n\
+ -c, --config-file=# --defaults-file=#\n\
+ The config file to use (default '%s')\n\
+ --no-defaults Return an empty string (useful for scripts)\n\
+ -?, --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);
+}
+
+static int get_options(int *argc,char ***argv)
+{
+ int c,option_index;
+
+ while ((c=getopt_long(*argc,*argv,"c:V?I",
+ long_options, &option_index)) != EOF)
+ {
+ switch (c) {
+ case 'c':
+ config_file=optarg;
+ break;
+ case 'n':
+ exit(0);
+ case 'I':
+ case '?':
+ usage(0);
+ exit(0);
+ case 'V':
+ usage(1);
+ exit(0);
+ }
+ }
+ (*argc)-=optind;
+ (*argv)+=optind;
+ if (*argc < 1)
+ {
+ usage(0);
+ return 1;
+ }
+ return 0;
+}
+
+int main(int argc, char **argv)
+{
+ int count;
+ char **load_default_groups, *tmp_arguments[2],
+ **argument, **arguments;
+ MY_INIT(argv[0]);
+
+ /*
+ ** Check out the args
+ */
+ if (get_options(&argc,&argv))
+ exit(1);
+ if (!(load_default_groups=(char**) my_malloc((argc+2)*sizeof(char*),
+ MYF(MY_WME))))
+ exit(1);
+
+ for (count=0; *argv ; argv++,count++)
+ load_default_groups[count]= *argv;
+ load_default_groups[count]=0;
+
+ count=1;
+ arguments=tmp_arguments;
+ arguments[0]=my_progname;
+ arguments[1]=0;
+ load_defaults(config_file, (const char **) load_default_groups,
+ &count, &arguments);
+
+ for (argument= arguments+1 ; *argument ; argument++)
+ puts(*argument);
+ my_free((char*) load_default_groups,MYF(0));
+ free_defaults(arguments);
+
+ exit(0);
+}
diff --git a/extra/Makefile.am b/extra/Makefile.am
new file mode 100644
index 00000000000..8fd41221cfe
--- /dev/null
+++ b/extra/Makefile.am
@@ -0,0 +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
+
+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
+
+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
diff --git a/extra/comp_err.c b/extra/comp_err.c
new file mode 100644
index 00000000000..198bdffb0db
--- /dev/null
+++ b/extra/comp_err.c
@@ -0,0 +1,275 @@
+/* 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 */
+
+/* Saves all errmesg in a header file, updated by me, in a compact file */
+
+#include <global.h>
+#include <m_ctype.h>
+#include <my_sys.h>
+#include <m_string.h>
+
+#define MAXLENGTH 1000
+#define MAX_ROWS 1000
+#define MAX_FILES 10
+
+int row_count;
+uint file_pos[MAX_ROWS],file_row_pos[MAX_FILES];
+my_string saved_row[MAX_ROWS];
+uchar file_head[]= { 254,254,2,1 };
+
+static void get_options(int *argc,char **argv[]);
+static int count_rows(FILE *from,pchar c, pchar c2);
+static int remember_rows(FILE *from,pchar c);
+static int copy_rows(FILE *to);
+
+
+ /* Functions defined in this file */
+
+int main(int argc,char *argv[])
+{
+ int i,error,files,length;
+ uchar head[32];
+ FILE *from,*to;
+ MY_INIT(argv[0]);
+
+ get_options(&argc,&argv);
+ error=1;
+ row_count=files=0;
+
+ to=0;
+ for ( ; argc-- > 1 ; argv++)
+ {
+ file_row_pos[files++] = row_count;
+
+ if ((from = fopen(*argv,"r")) == NULL)
+ {
+ fprintf(stderr,"Can't open file '%s'\n",*argv);
+ return(1);
+ }
+
+ VOID(count_rows(from,'"','}')); /* Calculate start-info */
+ if (remember_rows(from,'}') < 0) /* Remember rows */
+ {
+ fprintf(stderr,"Can't find textrows in '%s'\n",*argv);
+ fclose(from);
+ goto end;
+ }
+ fclose(from);
+ }
+
+ if ((to=my_fopen(*argv,O_WRONLY | FILE_BINARY,MYF(0))) == NULL)
+ {
+ fprintf(stderr,"Can't create file '%s'\n",*argv);
+ return(1);
+ }
+
+ fseek(to,(long) (32+row_count*2),0);
+ if (copy_rows(to))
+ goto end;
+
+ length=ftell(to)-32-row_count*2;
+
+ bzero((gptr) head,32); /* Save Header & pointers */
+ bmove((byte*) head,(byte*) file_head,4);
+ head[4]=files;
+ int2store(head+6,length);
+ int2store(head+8,row_count);
+ for (i=0 ; i<files ; i++)
+ {
+ int2store(head+10+i+i,file_row_pos[i]);
+ }
+
+ fseek(to,0l,0);
+ if (fwrite(head,1,32,to) != 32)
+ goto end;
+
+ for (i=0 ; i<row_count ; i++)
+ {
+ int2store(head,file_pos[i]);
+ if (fwrite(head,1,2,to) != 2)
+ goto end;
+ }
+ error=0;
+ printf("Found %d messages in language file %s\n",row_count,*argv);
+
+ end:
+ if (to)
+ fclose(to);
+ if (error)
+ fprintf(stderr,"Can't uppdate messagefile %s, errno: %d\n",*argv,errno);
+
+ exit(error);
+ return(0);
+} /* main */
+
+
+ /* Read options */
+
+static void get_options(argc,argv)
+register int *argc;
+register char **argv[];
+{
+ int help=0;
+ char *pos,*progname;
+
+ progname= (*argv)[0];
+ while (--*argc >0 && *(pos = *(++*argv)) == '-' ) {
+ while (*++pos)
+ switch(*pos) {
+ case '#':
+ DBUG_PUSH (++pos);
+ *(pos--) = '\0'; /* Skippa argument */
+ break;
+ case 'V':
+ printf("%s (Compile errormessage) Ver 1.3\n",progname);
+ break;
+ case 'I':
+ case '?':
+ printf(" %s (Compile errormessage) Ver 1.3\n",progname);
+ puts("This software comes with ABSOLUTELY NO WARRANTY. This is free software,\nand you are welcome to modify and redistribute it under the GPL license\n");
+ printf("Usage: %s [-?] [-I] [-V] fromfile[s] tofile\n",progname);
+ puts("Options: -Info -Version\n");
+ help=1;
+ break;
+ default:
+ fprintf(stderr,"illegal option: -%c\n",*pos);
+ fprintf(stderr,"legal options: -?IV\n");
+ break;
+ }
+ }
+ if (*argc < 2)
+ {
+ if (!help)
+ printf("Usage: %s [-?] [-I] [-V] fromfile[s] tofile\n",progname);
+ exit(-1);
+ }
+ return;
+} /* get_options */
+
+
+ /* Count rows in from-file until row that start with char is found */
+
+static int count_rows(from,c,c2)
+FILE *from;
+pchar c,c2;
+{
+ int count;
+ long pos;
+ char rad[MAXLENGTH];
+ DBUG_ENTER("count_rows");
+
+ pos=ftell(from); count=0;
+ while (fgets(rad,MAXLENGTH,from) != NULL)
+ {
+ if (rad[0] == c || rad[0] == c2)
+ break;
+ count++;
+ pos=ftell(from);
+ }
+ fseek(from,pos,0); /* Position to beginning of last row */
+ DBUG_PRINT("exit",("count: %d",count));
+ DBUG_RETURN(count);
+} /* count_rows */
+
+
+ /* Read rows and remember them until row that start with char */
+ /* Converts row as a C-compiler would convert a textstring */
+
+static int remember_rows(from,c)
+FILE *from;
+pchar c;
+{
+ int i,nr,start_count,found_end;
+ char row[MAXLENGTH],*pos;
+ DBUG_ENTER("remember_rows");
+
+ start_count=row_count; found_end=0;
+ while (fgets(row,MAXLENGTH,from) != NULL)
+ {
+ if (row[0] == c)
+ {
+ found_end=1;
+ break;
+ }
+ for (pos=row ; *pos ;)
+ {
+ if (*pos == '\\')
+ {
+ switch (*++pos) {
+ case '\\':
+ case '"':
+ VOID(strmov(pos-1,pos));
+ break;
+ case 'n':
+ pos[-1]='\n';
+ VOID(strmov(pos,pos+1));
+ break;
+ default:
+ if (*pos >= '0' && *pos <'8')
+ {
+ nr=0;
+ for (i=0 ; i<3 && (*pos >= '0' && *pos <'8' ) ; i++)
+ nr=nr*8+ (*(pos++) -'0');
+ pos-=i;
+ pos[-1]=nr;
+ VOID(strmov(pos,pos+i));
+ }
+ else if (*pos)
+ VOID(strmov(pos-1,pos)); /* Remove '\' */
+ }
+ }
+ else pos++;
+ }
+ while (pos >row+1 && *pos != '"')
+ pos--;
+
+ if (!(saved_row[row_count] = (my_string) my_malloc((uint) (pos-row),
+ MYF(MY_WME))))
+ DBUG_RETURN(-1);
+ *pos=0;
+ VOID(strmov(saved_row[row_count],row+1));
+ row_count++;
+ }
+ if (row_count-start_count == 0 && ! found_end)
+ DBUG_RETURN(-1); /* Found nothing */
+ DBUG_RETURN(row_count-start_count);
+} /* remember_rows */
+
+
+ /* Copy rows from memory to file and remember position */
+
+
+static int copy_rows(to)
+FILE *to;
+{
+ int row_nr;
+ long start_pos;
+ DBUG_ENTER("copy_rows");
+
+ start_pos=ftell(to);
+ for (row_nr =0 ; row_nr < row_count; row_nr++)
+ {
+ file_pos[row_nr]= (int) (ftell(to)-start_pos);
+ if (fputs(saved_row[row_nr],to) == EOF || fputc('\0',to) == EOF)
+ {
+ fprintf(stderr,"Can't write to outputfile\n");
+ DBUG_RETURN(1);
+ }
+ my_free((gptr) saved_row[row_nr],MYF(0));
+ }
+ DBUG_RETURN(0);
+} /* copy_rows */
diff --git a/extra/my_print_defaults.c b/extra/my_print_defaults.c
new file mode 100644
index 00000000000..a6e67e4949e
--- /dev/null
+++ b/extra/my_print_defaults.c
@@ -0,0 +1,125 @@
+/* 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 */
+
+/*
+** print_default.c:
+** Print all parameters in a default file that will be given to some program.
+**
+** Written by Monty
+*/
+
+#include <global.h>
+#include <my_sys.h>
+#include <getopt.h>
+
+const char *config_file="my"; /* Default config file */
+
+static struct option long_options[] =
+{
+ {"config-file", required_argument, 0, 'c'},
+ {"defaults-file", required_argument, 0, 'c'},
+ {"no-defaults", no_argument, 0, 'd'},
+ {"help", no_argument, 0, '?'},
+ {"version", no_argument, 0, 'V'},
+ {0, 0, 0, 0}
+};
+
+static void usage(my_bool version)
+{
+ printf("%s Ver 1.1 for %s at %s\n",my_progname,SYSTEM_TYPE,
+ MACHINE_TYPE);
+ if (version)
+ return;
+ 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("Prints all arguments that is give to some program using the default files");
+ printf("Usage: %s [OPTIONS] groups\n",my_progname);
+ printf("\n\
+ -c, --config-file=# --defaults-file=#\n\
+ The config file to use (default '%s')\n\
+ --no-defaults Return an empty string (useful for scripts)\n\
+ -?, --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);
+}
+
+static int get_options(int *argc,char ***argv)
+{
+ int c,option_index;
+
+ while ((c=getopt_long(*argc,*argv,"c:V?I",
+ long_options, &option_index)) != EOF)
+ {
+ switch (c) {
+ case 'c':
+ config_file=optarg;
+ break;
+ case 'n':
+ exit(0);
+ case 'I':
+ case '?':
+ usage(0);
+ exit(0);
+ case 'V':
+ usage(1);
+ exit(0);
+ }
+ }
+ (*argc)-=optind;
+ (*argv)+=optind;
+ if (*argc < 1)
+ {
+ usage(0);
+ return 1;
+ }
+ return 0;
+}
+
+int main(int argc, char **argv)
+{
+ int count;
+ char **load_default_groups, *tmp_arguments[2],
+ **argument, **arguments;
+ MY_INIT(argv[0]);
+
+ /*
+ ** Check out the args
+ */
+ if (get_options(&argc,&argv))
+ exit(1);
+ if (!(load_default_groups=(char**) my_malloc((argc+2)*sizeof(char*),
+ MYF(MY_WME))))
+ exit(1);
+
+ for (count=0; *argv ; argv++,count++)
+ load_default_groups[count]= *argv;
+ load_default_groups[count]=0;
+
+ count=1;
+ arguments=tmp_arguments;
+ arguments[0]=my_progname;
+ arguments[1]=0;
+ load_defaults(config_file, (const char **) load_default_groups,
+ &count, &arguments);
+
+ for (argument= arguments+1 ; *argument ; argument++)
+ puts(*argument);
+ my_free((char*) load_default_groups,MYF(0));
+ free_defaults(arguments);
+
+ exit(0);
+}
diff --git a/extra/perror.c b/extra/perror.c
new file mode 100644
index 00000000000..b6d32d50868
--- /dev/null
+++ b/extra/perror.c
@@ -0,0 +1,207 @@
+/* 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 */
+
+/* Return error-text for system error messages and nisam messages */
+
+#define PERROR_VERSION "2.2"
+
+#include <global.h>
+#include <my_sys.h>
+#include <m_string.h>
+#include <errno.h>
+#include <getopt.h>
+
+
+static struct option long_options[] =
+{
+ {"help", no_argument, 0, '?'},
+ {"info", no_argument, 0, 'I'},
+ {"all", no_argument, 0, 'a'},
+ {"verbose", no_argument, 0, 'v'},
+ {"version", no_argument, 0, 'V'},
+ {0, 0, 0, 0}
+};
+
+typedef struct ha_errors {
+ int errcode;
+ const char *msg;
+} HA_ERRORS;
+
+static int verbose=0,print_all_codes=0;
+
+static HA_ERRORS ha_errlist[]=
+{
+ { 120,"Didn't find key on read or update" },
+ { 121,"Duplicate key on write or update" },
+ { 123,"Someone has changed the row since it was read; Update with is recoverable" },
+ { 124,"Wrong index given to function" },
+ { 126,"Index file is crashed / Wrong file format" },
+ { 127,"Record-file is crashed" },
+ { 131,"Command not supported by database" },
+ { 132,"Old database file" },
+ { 133,"No record read before update" },
+ { 134,"Record was already deleted (or record file crashed)" },
+ { 135,"No more room in record file" },
+ { 136,"No more room in index file" },
+ { 137,"No more records (read after end of file)" },
+ { 138,"Unsupported extension used for table" },
+ { 139,"Too big row (>= 24 M)"},
+ { 140,"Wrong create options"},
+ { 141,"Dupplicate unique on write or update"},
+ { 0,NullS },
+};
+
+
+static void print_version(void)
+{
+ printf("%s Ver %s, for %s (%s)\n",my_progname,PERROR_VERSION,
+ SYSTEM_TYPE,MACHINE_TYPE);
+}
+
+static void usage(void)
+{
+ print_version();
+ puts("This software comes with ABSOLUTELY NO WARRANTY. This is free software,\nand you are welcome to modify and redistribute it under the GPL license\n");
+ printf("Usage: %s [OPTIONS] [ERRORCODES]\n",my_progname);
+ printf("\n\
+ -?, --help Displays this help and exits.\n\
+ -I, --info Synonym for the above.");
+#ifdef HAVE_SYS_ERRLIST
+ printf("\n\
+ -a, --all Print all the error messages and the number.");
+#endif
+ printf("\n\
+ -v, --verbose Print info about various stages.\n\
+ -V, --version Displays version information and exits.\n");
+}
+
+
+static int get_options(int *argc,char ***argv)
+{
+ int c,option_index;
+
+ while ((c=getopt_long(*argc,*argv,"avVI?",long_options,
+ &option_index)) != EOF)
+ {
+ switch (c) {
+#ifdef HAVE_SYS_ERRLIST
+ case 'a':
+ print_all_codes=1;
+ break;
+#endif
+ case 'v':
+ verbose=1;
+ break;
+ case 'V':
+ print_version();
+ exit(0);
+ break;
+ case 'I':
+ case '?':
+ usage();
+ exit(0);
+ break;
+ default:
+ fprintf(stderr,"%s: Illegal option character '%c'\n",
+ my_progname,opterr);
+ return(1);
+ break;
+ }
+ }
+ (*argc)-=optind;
+ (*argv)+=optind;
+ if (!*argc && !print_all_codes)
+ {
+ usage();
+ return 1;
+ }
+ return 0;
+} /* get_options */
+
+
+static const char *get_ha_error_msg(int code)
+{
+ HA_ERRORS *ha_err_ptr;
+
+ for (ha_err_ptr=ha_errlist ; ha_err_ptr->errcode ;ha_err_ptr++)
+ if (ha_err_ptr->errcode == code)
+ return ha_err_ptr->msg;
+ return NullS;
+}
+
+
+int main(int argc,char *argv[])
+{
+ int error,code,found;
+ const char *msg;
+ MY_INIT(argv[0]);
+
+ if (get_options(&argc,&argv))
+ exit(1);
+
+ error=0;
+#ifdef HAVE_SYS_ERRLIST
+ if (print_all_codes)
+ {
+ HA_ERRORS *ha_err_ptr;
+ for (code=1 ; code < sys_nerr ; code++)
+ {
+ if (sys_errlist[code][0])
+ { /* Skipp if no error-text */
+ printf("%3d = %s\n",code,sys_errlist[code]);
+ }
+ }
+ for (ha_err_ptr=ha_errlist ; ha_err_ptr->errcode ;ha_err_ptr++)
+ printf("%3d = %s\n",ha_err_ptr->errcode,ha_err_ptr->msg);
+ }
+ else
+#endif
+ {
+ for ( ; argc-- > 0 ; argv++)
+ {
+ found=0;
+ code=atoi(*argv);
+ msg = strerror(code);
+ if (msg)
+ {
+ found=1;
+ if (verbose)
+ printf("%3d = %s\n",code,msg);
+ else
+ puts(msg);
+ }
+ if (!(msg=get_ha_error_msg(code)))
+ {
+ if (!found)
+ {
+ fprintf(stderr,"Illegal error code: %d\n",code);
+ error=1;
+ }
+ }
+ else
+ {
+ if (verbose)
+ printf("%3d = %s\n",code,msg);
+ else
+ puts(msg);
+ }
+ }
+ }
+ exit(error);
+ return error;
+}
+
diff --git a/extra/replace.c b/extra/replace.c
new file mode 100644
index 00000000000..44f117c7969
--- /dev/null
+++ b/extra/replace.c
@@ -0,0 +1,1080 @@
+/* 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 */
+
+/* Replace strings in textfile
+ This program replace strings in a file or on stdin/stdout.
+ It accepts a list of from-strings and to-strings and replaces all
+ occurents of from-strings to to-strings.
+ The first occurents of a found string is matched. If there are more than
+ one possibly replace the longer from-string is replaced.
+ Special characters in from string:
+ \^ Match start of line.
+ \$ Match end of line.
+ \b Match space-character, start of line or end of line.
+ For end \b the next replace starts locking at the end space-character.
+ An \b alone or in a string matches only a space-character.
+ \r, \t, \v as in C.
+ The programs make a DFA-state-machine of the strings and the speed isn't
+ dependent on the count of replace-strings (only of the number of replaces).
+ A line is assumed ending with \n or \0.
+ There are no limit exept memory on length of strings.
+
+ Written by Monty.
+ fill_buffer_retaining() is taken from gnu-grep and modified.
+*/
+
+#define DONT_USE_RAID
+#include <global.h>
+#include <m_ctype.h>
+#include <my_sys.h>
+#include <m_string.h>
+#include <errno.h>
+
+#define PC_MALLOC 256 /* Bytes for pointers */
+#define PS_MALLOC 512 /* Bytes for data */
+
+typedef struct st_pointer_array { /* when using array-strings */
+ TYPELIB typelib; /* Pointer to strings */
+ byte *str; /* Strings is here */
+ int7 *flag; /* Flag about each var. */
+ uint array_allocs,max_count,length,max_length;
+} POINTER_ARRAY;
+
+#define SPACE_CHAR 256
+#define START_OF_LINE 257
+#define END_OF_LINE 258
+#define LAST_CHAR_CODE 259
+
+typedef struct st_replace {
+ bool found;
+ struct st_replace *next[256];
+} REPLACE;
+
+typedef struct st_replace_found {
+ bool found;
+ char *replace_string;
+ uint to_offset;
+ int from_offset;
+} REPLACE_STRING;
+
+#ifndef WORD_BIT
+#define WORD_BIT (8*sizeof(uint))
+#endif
+
+ /* functions defined in this file */
+
+extern int main(int argc,char * *argv);
+static int static_get_options(int *argc,char * * *argv);
+static int get_replace_strings(int *argc,char * * *argv,
+ POINTER_ARRAY *from_array,
+ POINTER_ARRAY *to_array);
+int insert_pointer_name(POINTER_ARRAY *pa, my_string name);
+void free_pointer_array(POINTER_ARRAY *pa);
+static int convert_pipe(REPLACE *,FILE *,FILE *);
+static int convert_file(REPLACE *, my_string);
+REPLACE *init_replace(my_string *from, my_string *to,uint count, my_string
+ word_end_chars);
+uint replace_strings(REPLACE *rep, my_string *start,uint *max_length,
+ my_string from);
+static int initialize_buffer(void);
+static void reset_buffer(void);
+static void free_buffer(void);
+
+static int silent=0,verbose=0,updated=0;
+
+ /* The main program */
+
+int main(argc,argv)
+int argc;
+char *argv[];
+{
+ int i,error;
+ char word_end_chars[256],*pos;
+ POINTER_ARRAY from,to;
+ REPLACE *replace;
+ MY_INIT(argv[0]);
+
+ if (static_get_options(&argc,&argv))
+ exit(1);
+ if (get_replace_strings(&argc,&argv,&from,&to))
+ exit(1);
+
+ for (i=1,pos=word_end_chars ; i < 256 ; i++)
+ if (isspace(i))
+ *pos++=i;
+ *pos=0;
+ if (!(replace=init_replace((char**) from.typelib.type_names,
+ (char**) to.typelib.type_names,
+ (uint) from.typelib.count,word_end_chars)))
+ exit(1);
+ free_pointer_array(&from);
+ free_pointer_array(&to);
+ if (initialize_buffer())
+ return 1;
+
+ error=0;
+ if (argc == 0)
+ error=convert_pipe(replace,stdin,stdout);
+ else
+ {
+ while (argc--)
+ {
+ error=convert_file(replace,*(argv++));
+ }
+ }
+ free_buffer();
+ my_end(verbose ? MY_CHECK_ERROR | MY_GIVE_INFO : MY_CHECK_ERROR);
+ exit(error ? 2 : 0);
+ return 0; /* No compiler warning */
+} /* main */
+
+
+ /* reads options */
+ /* Initiates DEBUG - but no debugging here ! */
+
+static int static_get_options(argc,argv)
+register int *argc;
+register char **argv[];
+{
+ int help,version,opt;
+ char *pos;
+
+ silent=verbose=help=0;
+
+ while (--*argc > 0 && *(pos = *(++*argv)) == '-' && pos[1] != '-') {
+ while (*++pos)
+ {
+ version=0;
+ switch((opt= *pos)) {
+ case 's':
+ silent=1;
+ break;
+ case 'v':
+ verbose=1;
+ break;
+ case '#':
+ DBUG_PUSH (++pos);
+ pos= (char*) " "; /* Skipp rest of arguments */
+ break;
+ case 'V':
+ version=1;
+ case 'I':
+ case '?':
+ help=1; /* Help text written */
+ printf("%s Ver 1.3 for %s at %s\n",my_progname,SYSTEM_TYPE,
+ MACHINE_TYPE);
+ if (version)
+ break;
+ 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("This program replace strings in a file or on stdin/stdout.\n"
+ "It accepts a list of from-strings and to-strings and replaces\n"
+ "all occurents of from-strings to to-strings.\n"
+ "The first occurents of a found string is matched. Longer matches\n"
+ "are prefered before shorter matches.\n\n"
+ "Special characters in from string:\n"
+ " \\^ Match start of line.\n"
+ " \\$ Match end of line.\n"
+ " \\b Match space-character, start of line or end of line.\n"
+ " For a end \\b the next replace starts locking at the end\n"
+ " space-character. A \\b alone in a string matches only a\n"
+ " space-character.\n");
+ printf("Usage: %s [-?svIV] from to from to ... -- [files]\n", my_progname);
+ puts("or");
+ printf("Usage: %s [-?svIV] from to from to ... < fromfile > tofile\n", my_progname);
+ puts("");
+ puts("Options: -? or -I \"Info\" -s \"silent\" -v \"verbose\"");
+ break;
+ default:
+ fprintf(stderr,"illegal option: -%c\n",*pos);
+ break;
+ }
+ }
+ }
+ if (*argc == 0)
+ {
+ if (!help)
+ my_message(0,"No replace options given",MYF(ME_BELL));
+ exit(0); /* Don't use as pipe */
+ }
+ return(0);
+} /* static_get_options */
+
+
+static int get_replace_strings(argc,argv,from_array,to_array)
+register int *argc;
+register char **argv[];
+POINTER_ARRAY *from_array,*to_array;
+{
+ char *pos;
+
+ bzero((char*) from_array,sizeof(from_array[0]));
+ bzero((char*) to_array,sizeof(to_array[0]));
+ while (*argc > 0 && (*(pos = *(*argv)) != '-' || pos[1] != '-' || pos[2]))
+ {
+ insert_pointer_name(from_array,pos);
+ (*argc)--;
+ (*argv)++;
+ if (!*argc || !strcmp(**argv,"--"))
+ {
+ my_message(0,"No to-string for last from-string",MYF(ME_BELL));
+ return 1;
+ }
+ insert_pointer_name(to_array,**argv);
+ (*argc)--;
+ (*argv)++;
+ }
+ if (*argc)
+ { /* Skipp "--" argument */
+ (*argc)--;
+ (*argv)++;
+ }
+ return 0;
+}
+
+int insert_pointer_name(reg1 POINTER_ARRAY *pa,my_string name)
+{
+ uint i,length,old_count;
+ byte *new_pos;
+ const char **new_array;
+ DBUG_ENTER("insert_pointer_name");
+
+ if (! pa->typelib.count)
+ {
+ if (!(pa->typelib.type_names=(const char **)
+ my_malloc(((PC_MALLOC-MALLOC_OVERHEAD)/
+ (sizeof(my_string)+sizeof(*pa->flag))*
+ (sizeof(my_string)+sizeof(*pa->flag))),MYF(MY_WME))))
+ DBUG_RETURN(-1);
+ if (!(pa->str= (byte*) my_malloc((uint) (PS_MALLOC-MALLOC_OVERHEAD),
+ MYF(MY_WME))))
+ {
+ my_free((gptr) pa->typelib.type_names,MYF(0));
+ DBUG_RETURN (-1);
+ }
+ pa->max_count=(PC_MALLOC-MALLOC_OVERHEAD)/(sizeof(byte*)+
+ sizeof(*pa->flag));
+ pa->flag= (int7*) (pa->typelib.type_names+pa->max_count);
+ pa->length=0;
+ pa->max_length=PS_MALLOC-MALLOC_OVERHEAD;
+ pa->array_allocs=1;
+ }
+ length=strlen(name)+1;
+ if (pa->length+length >= pa->max_length)
+ {
+ if (!(new_pos= (byte*) my_realloc((gptr) pa->str,
+ (uint) (pa->max_length+PS_MALLOC),
+ MYF(MY_WME))))
+ DBUG_RETURN(1);
+ if (new_pos != pa->str)
+ {
+ my_ptrdiff_t diff=PTR_BYTE_DIFF(new_pos,pa->str);
+ for (i=0 ; i < pa->typelib.count ; i++)
+ pa->typelib.type_names[i]= ADD_TO_PTR(pa->typelib.type_names[i],diff,
+ char*);
+ pa->str=new_pos;
+ }
+ pa->max_length+=PS_MALLOC;
+ }
+ if (pa->typelib.count >= pa->max_count-1)
+ {
+ int len;
+ pa->array_allocs++;
+ len=(PC_MALLOC*pa->array_allocs - MALLOC_OVERHEAD);
+ if (!(new_array=(const char **) my_realloc((gptr) pa->typelib.type_names,
+ (uint) len/
+ (sizeof(byte*)+sizeof(*pa->flag))*
+ (sizeof(byte*)+sizeof(*pa->flag)),
+ MYF(MY_WME))))
+ DBUG_RETURN(1);
+ pa->typelib.type_names=new_array;
+ old_count=pa->max_count;
+ pa->max_count=len/(sizeof(byte*) + sizeof(*pa->flag));
+ pa->flag= (int7*) (pa->typelib.type_names+pa->max_count);
+ memcpy((byte*) pa->flag,(my_string) (pa->typelib.type_names+old_count),
+ old_count*sizeof(*pa->flag));
+ }
+ pa->flag[pa->typelib.count]=0; /* Reset flag */
+ pa->typelib.type_names[pa->typelib.count++]= pa->str+pa->length;
+ pa->typelib.type_names[pa->typelib.count]= NullS; /* Put end-mark */
+ VOID(strmov(pa->str+pa->length,name));
+ pa->length+=length;
+ DBUG_RETURN(0);
+} /* insert_pointer_name */
+
+
+ /* free pointer array */
+
+void free_pointer_array(pa)
+reg1 POINTER_ARRAY *pa;
+{
+ if (pa->typelib.count)
+ {
+ pa->typelib.count=0;
+ my_free((gptr) pa->typelib.type_names,MYF(0));
+ pa->typelib.type_names=0;
+ my_free((gptr) pa->str,MYF(0));
+ }
+ return;
+} /* free_pointer_array */
+
+
+ /* Code for replace rutines */
+
+#define SET_MALLOC_HUNC 64
+
+typedef struct st_rep_set {
+ uint *bits; /* Pointer to used sets */
+ short next[LAST_CHAR_CODE]; /* Pointer to next sets */
+ uint found_len; /* Best match to date */
+ int found_offset;
+ uint table_offset;
+ uint size_of_bits; /* For convinience */
+} REP_SET;
+
+typedef struct st_rep_sets {
+ uint count; /* Number of sets */
+ uint extra; /* Extra sets in buffer */
+ uint invisible; /* Sets not chown */
+ uint size_of_bits;
+ REP_SET *set,*set_buffer;
+ uint *bit_buffer;
+} REP_SETS;
+
+typedef struct st_found_set {
+ uint table_offset;
+ int found_offset;
+} FOUND_SET;
+
+typedef struct st_follow {
+ int chr;
+ uint table_offset;
+ uint len;
+} FOLLOWS;
+
+
+static int init_sets(REP_SETS *sets,uint states);
+static REP_SET *make_new_set(REP_SETS *sets);
+static void make_sets_invisible(REP_SETS *sets);
+static void free_last_set(REP_SETS *sets);
+static void free_sets(REP_SETS *sets);
+static void set_bit(REP_SET *set, uint bit);
+static void clear_bit(REP_SET *set, uint bit);
+static void or_bits(REP_SET *to,REP_SET *from);
+static void copy_bits(REP_SET *to,REP_SET *from);
+static int cmp_bits(REP_SET *set1,REP_SET *set2);
+static int get_next_bit(REP_SET *set,uint lastpos);
+static int find_set(REP_SETS *sets,REP_SET *find);
+static int find_found(FOUND_SET *found_set,uint table_offset,
+ int found_offset);
+static uint start_at_word(my_string pos);
+static uint end_of_word(my_string pos);
+static uint replace_len(my_string pos);
+
+static uint found_sets=0;
+
+
+ /* Init a replace structure for further calls */
+
+REPLACE *init_replace(my_string *from, my_string *to,uint count,
+ my_string word_end_chars)
+{
+ uint i,j,states,set_nr,len,result_len,max_length,found_end,bits_set,bit_nr;
+ int used_sets,chr,default_state;
+ char used_chars[LAST_CHAR_CODE],is_word_end[256];
+ my_string pos,to_pos,*to_array;
+ REP_SETS sets;
+ REP_SET *set,*start_states,*word_states,*new_set;
+ FOLLOWS *follow,*follow_ptr;
+ REPLACE *replace;
+ FOUND_SET *found_set;
+ REPLACE_STRING *rep_str;
+ DBUG_ENTER("init_replace");
+
+ /* Count number of states */
+ for (i=result_len=max_length=0 , states=2 ; i < count ; i++)
+ {
+ len=replace_len(from[i]);
+ if (!len)
+ {
+ errno=EINVAL;
+ my_message(0,"No to-string for last from-string",MYF(ME_BELL));
+ DBUG_RETURN(0);
+ }
+ states+=len+1;
+ result_len+=strlen(to[i])+1;
+ if (len > max_length)
+ max_length=len;
+ }
+ bzero((char*) is_word_end,sizeof(is_word_end));
+ for (i=0 ; word_end_chars[i] ; i++)
+ is_word_end[(uchar) word_end_chars[i]]=1;
+
+ if (init_sets(&sets,states))
+ DBUG_RETURN(0);
+ found_sets=0;
+ if (!(found_set= (FOUND_SET*) my_malloc(sizeof(FOUND_SET)*max_length*count,
+ MYF(MY_WME))))
+ {
+ free_sets(&sets);
+ DBUG_RETURN(0);
+ }
+ VOID(make_new_set(&sets)); /* Set starting set */
+ make_sets_invisible(&sets); /* Hide previus sets */
+ used_sets=-1;
+ word_states=make_new_set(&sets); /* Start of new word */
+ start_states=make_new_set(&sets); /* This is first state */
+ if (!(follow=(FOLLOWS*) my_malloc((states+2)*sizeof(FOLLOWS),MYF(MY_WME))))
+ {
+ free_sets(&sets);
+ my_free((gptr) found_set,MYF(0));
+ DBUG_RETURN(0);
+ }
+
+ /* Init follow_ptr[] */
+ for (i=0, states=1, follow_ptr=follow+1 ; i < count ; i++)
+ {
+ if (from[i][0] == '\\' && from[i][1] == '^')
+ {
+ set_bit(start_states,states+1);
+ if (!from[i][2])
+ {
+ start_states->table_offset=i;
+ start_states->found_offset=1;
+ }
+ }
+ else if (from[i][0] == '\\' && from[i][1] == '$')
+ {
+ set_bit(start_states,states);
+ set_bit(word_states,states);
+ if (!from[i][2] && start_states->table_offset == (uint) ~0)
+ {
+ start_states->table_offset=i;
+ start_states->found_offset=0;
+ }
+ }
+ else
+ {
+ set_bit(word_states,states);
+ if (from[i][0] == '\\' && (from[i][1] == 'b' && from[i][2]))
+ set_bit(start_states,states+1);
+ else
+ set_bit(start_states,states);
+ }
+ for (pos=from[i], len=0; *pos ; pos++)
+ {
+ if (*pos == '\\' && *(pos+1))
+ {
+ pos++;
+ switch (*pos) {
+ case 'b':
+ follow_ptr->chr = SPACE_CHAR;
+ break;
+ case '^':
+ follow_ptr->chr = START_OF_LINE;
+ break;
+ case '$':
+ follow_ptr->chr = END_OF_LINE;
+ break;
+ case 'r':
+ follow_ptr->chr = '\r';
+ break;
+ case 't':
+ follow_ptr->chr = '\t';
+ break;
+ case 'v':
+ follow_ptr->chr = '\v';
+ break;
+ default:
+ follow_ptr->chr = (uchar) *pos;
+ break;
+ }
+ }
+ else
+ follow_ptr->chr= (uchar) *pos;
+ follow_ptr->table_offset=i;
+ follow_ptr->len= ++len;
+ follow_ptr++;
+ }
+ follow_ptr->chr=0;
+ follow_ptr->table_offset=i;
+ follow_ptr->len=len;
+ follow_ptr++;
+ states+=(uint) len+1;
+ }
+
+
+ for (set_nr=0,pos=0 ; set_nr < sets.count ; set_nr++)
+ {
+ set=sets.set+set_nr;
+ default_state= 0; /* Start from beginning */
+
+ /* If end of found-string not found or start-set with current set */
+
+ for (i= (uint) ~0; (i=get_next_bit(set,i)) ;)
+ {
+ if (!follow[i].chr)
+ {
+ if (! default_state)
+ default_state= find_found(found_set,set->table_offset,
+ set->found_offset+1);
+ }
+ }
+ copy_bits(sets.set+used_sets,set); /* Save set for changes */
+ if (!default_state)
+ or_bits(sets.set+used_sets,sets.set); /* Can restart from start */
+
+ /* Find all chars that follows current sets */
+ bzero((char*) used_chars,sizeof(used_chars));
+ for (i= (uint) ~0; (i=get_next_bit(sets.set+used_sets,i)) ;)
+ {
+ used_chars[follow[i].chr]=1;
+ if ((follow[i].chr == SPACE_CHAR && !follow[i+1].chr &&
+ follow[i].len > 1) || follow[i].chr == END_OF_LINE)
+ used_chars[0]=1;
+ }
+
+ /* Mark word_chars used if \b is in state */
+ if (used_chars[SPACE_CHAR])
+ for (pos= word_end_chars ; *pos ; pos++)
+ used_chars[(int) (uchar) *pos] = 1;
+
+ /* Handle other used characters */
+ for (chr= 0 ; chr < 256 ; chr++)
+ {
+ if (! used_chars[chr])
+ set->next[chr]= chr ? default_state : -1;
+ else
+ {
+ new_set=make_new_set(&sets);
+ set=sets.set+set_nr; /* if realloc */
+ new_set->table_offset=set->table_offset;
+ new_set->found_len=set->found_len;
+ new_set->found_offset=set->found_offset+1;
+ found_end=0;
+
+ for (i= (uint) ~0 ; (i=get_next_bit(sets.set+used_sets,i)) ; )
+ {
+ if (!follow[i].chr || follow[i].chr == chr ||
+ (follow[i].chr == SPACE_CHAR &&
+ (is_word_end[chr] ||
+ (!chr && follow[i].len > 1 && ! follow[i+1].chr))) ||
+ (follow[i].chr == END_OF_LINE && ! chr))
+ {
+ if ((! chr || (follow[i].chr && !follow[i+1].chr)) &&
+ follow[i].len > found_end)
+ found_end=follow[i].len;
+ if (chr && follow[i].chr)
+ set_bit(new_set,i+1); /* To next set */
+ else
+ set_bit(new_set,i);
+ }
+ }
+ if (found_end)
+ {
+ new_set->found_len=0; /* Set for testing if first */
+ bits_set=0;
+ for (i= (uint) ~0; (i=get_next_bit(new_set,i)) ;)
+ {
+ if ((follow[i].chr == SPACE_CHAR ||
+ follow[i].chr == END_OF_LINE) && ! chr)
+ bit_nr=i+1;
+ else
+ bit_nr=i;
+ if (follow[bit_nr-1].len < found_end ||
+ (new_set->found_len &&
+ (chr == 0 || !follow[bit_nr].chr)))
+ clear_bit(new_set,i);
+ else
+ {
+ if (chr == 0 || !follow[bit_nr].chr)
+ { /* best match */
+ new_set->table_offset=follow[bit_nr].table_offset;
+ if (chr || (follow[i].chr == SPACE_CHAR ||
+ follow[i].chr == END_OF_LINE))
+ new_set->found_offset=found_end; /* New match */
+ new_set->found_len=found_end;
+ }
+ bits_set++;
+ }
+ }
+ if (bits_set == 1)
+ {
+ set->next[chr] = find_found(found_set,
+ new_set->table_offset,
+ new_set->found_offset);
+ free_last_set(&sets);
+ }
+ else
+ set->next[chr] = find_set(&sets,new_set);
+ }
+ else
+ set->next[chr] = find_set(&sets,new_set);
+ }
+ }
+ }
+
+ /* Alloc replace structure for the replace-state-machine */
+
+ if ((replace=(REPLACE*) my_malloc(sizeof(REPLACE)*(sets.count)+
+ sizeof(REPLACE_STRING)*(found_sets+1)+
+ sizeof(my_string)*count+result_len,
+ MYF(MY_WME | MY_ZEROFILL))))
+ {
+ rep_str=(REPLACE_STRING*) (replace+sets.count);
+ to_array=(my_string*) (rep_str+found_sets+1);
+ to_pos=(my_string) (to_array+count);
+ for (i=0 ; i < count ; i++)
+ {
+ to_array[i]=to_pos;
+ to_pos=strmov(to_pos,to[i])+1;
+ }
+ rep_str[0].found=1;
+ rep_str[0].replace_string=0;
+ for (i=1 ; i <= found_sets ; i++)
+ {
+ pos=from[found_set[i-1].table_offset];
+ rep_str[i].found= !bcmp(pos,"\\^",3) ? 2 : 1;
+ rep_str[i].replace_string=to_array[found_set[i-1].table_offset];
+ rep_str[i].to_offset=found_set[i-1].found_offset-start_at_word(pos);
+ rep_str[i].from_offset=found_set[i-1].found_offset-replace_len(pos)+
+ end_of_word(pos);
+ }
+ for (i=0 ; i < sets.count ; i++)
+ {
+ for (j=0 ; j < 256 ; j++)
+ if (sets.set[i].next[j] >= 0)
+ replace[i].next[j]=replace+sets.set[i].next[j];
+ else
+ replace[i].next[j]=(REPLACE*) (rep_str+(-sets.set[i].next[j]-1));
+ }
+ }
+ my_free((gptr) follow,MYF(0));
+ free_sets(&sets);
+ my_free((gptr) found_set,MYF(0));
+ DBUG_PRINT("exit",("Replace table has %d states",sets.count));
+ DBUG_RETURN(replace);
+}
+
+
+static int init_sets(REP_SETS *sets,uint states)
+{
+ bzero((char*) sets,sizeof(*sets));
+ sets->size_of_bits=((states+7)/8);
+ if (!(sets->set_buffer=(REP_SET*) my_malloc(sizeof(REP_SET)*SET_MALLOC_HUNC,
+ MYF(MY_WME))))
+ return 1;
+ if (!(sets->bit_buffer=(uint*) my_malloc(sizeof(uint)*sets->size_of_bits*
+ SET_MALLOC_HUNC,MYF(MY_WME))))
+ {
+ my_free((gptr) sets->set,MYF(0));
+ return 1;
+ }
+ return 0;
+}
+
+ /* Make help sets invisible for nicer codeing */
+
+static void make_sets_invisible(REP_SETS *sets)
+{
+ sets->invisible=sets->count;
+ sets->set+=sets->count;
+ sets->count=0;
+}
+
+static REP_SET *make_new_set(REP_SETS *sets)
+{
+ uint i,count,*bit_buffer;
+ REP_SET *set;
+ if (sets->extra)
+ {
+ sets->extra--;
+ set=sets->set+ sets->count++;
+ bzero((char*) set->bits,sizeof(uint)*sets->size_of_bits);
+ bzero((char*) &set->next[0],sizeof(set->next[0])*LAST_CHAR_CODE);
+ set->found_offset=0;
+ set->found_len=0;
+ set->table_offset= (uint) ~0;
+ set->size_of_bits=sets->size_of_bits;
+ return set;
+ }
+ count=sets->count+sets->invisible+SET_MALLOC_HUNC;
+ if (!(set=(REP_SET*) my_realloc((gptr) sets->set_buffer,
+ sizeof(REP_SET)*count,
+ MYF(MY_WME))))
+ return 0;
+ sets->set_buffer=set;
+ sets->set=set+sets->invisible;
+ if (!(bit_buffer=(uint*) my_realloc((gptr) sets->bit_buffer,
+ (sizeof(uint)*sets->size_of_bits)*count,
+ MYF(MY_WME))))
+ return 0;
+ sets->bit_buffer=bit_buffer;
+ for (i=0 ; i < count ; i++)
+ {
+ sets->set_buffer[i].bits=bit_buffer;
+ bit_buffer+=sets->size_of_bits;
+ }
+ sets->extra=SET_MALLOC_HUNC;
+ return make_new_set(sets);
+}
+
+static void free_last_set(REP_SETS *sets)
+{
+ sets->count--;
+ sets->extra++;
+ return;
+}
+
+static void free_sets(REP_SETS *sets)
+{
+ my_free((gptr)sets->set_buffer,MYF(0));
+ my_free((gptr)sets->bit_buffer,MYF(0));
+ return;
+}
+
+static void set_bit(REP_SET *set, uint bit)
+{
+ set->bits[bit / WORD_BIT] |= 1 << (bit % WORD_BIT);
+ return;
+}
+
+static void clear_bit(REP_SET *set, uint bit)
+{
+ set->bits[bit / WORD_BIT] &= ~ (1 << (bit % WORD_BIT));
+ return;
+}
+
+
+static void or_bits(REP_SET *to,REP_SET *from)
+{
+ reg1 uint i;
+ for (i=0 ; i < to->size_of_bits ; i++)
+ to->bits[i]|=from->bits[i];
+ return;
+}
+
+static void copy_bits(REP_SET *to,REP_SET *from)
+{
+ memcpy((byte*) to->bits,(byte*) from->bits,
+ (size_t) (sizeof(uint) * to->size_of_bits));
+}
+
+static int cmp_bits(REP_SET *set1,REP_SET *set2)
+{
+ return bcmp((byte*) set1->bits,(byte*) set2->bits,
+ sizeof(uint) * set1->size_of_bits);
+}
+
+
+ /* Get next set bit from set. */
+
+static int get_next_bit(REP_SET *set,uint lastpos)
+{
+ uint pos,*start,*end,bits;
+
+ start=set->bits+ ((lastpos+1) / WORD_BIT);
+ end=set->bits + set->size_of_bits;
+ bits=start[0] & ~((1 << ((lastpos+1) % WORD_BIT)) -1);
+
+ while (! bits && ++start < end)
+ bits=start[0];
+ if (!bits)
+ return 0;
+ pos=(uint) (start-set->bits)*WORD_BIT;
+ while (! (bits & 1))
+ {
+ bits>>=1;
+ pos++;
+ }
+ return pos;
+}
+
+ /* find if there is a same set in sets. If there is, use it and
+ free given set, else put in given set in sets and return it's
+ position */
+
+static int find_set(REP_SETS *sets,REP_SET *find)
+{
+ uint i;
+ for (i=0 ; i < sets->count-1 ; i++)
+ {
+ if (!cmp_bits(sets->set+i,find))
+ {
+ free_last_set(sets);
+ return i;
+ }
+ }
+ return i; /* return new postion */
+}
+
+ /* find if there is a found_set with same table_offset & found_offset
+ If there is return offset to it, else add new offset and return pos.
+ Pos returned is -offset-2 in found_set_structure because it's is
+ saved in set->next and set->next[] >= 0 points to next set and
+ set->next[] == -1 is reserved for end without replaces.
+ */
+
+static int find_found(FOUND_SET *found_set,uint table_offset, int found_offset)
+{
+ int i;
+ for (i=0 ; (uint) i < found_sets ; i++)
+ if (found_set[i].table_offset == table_offset &&
+ found_set[i].found_offset == found_offset)
+ return -i-2;
+ found_set[i].table_offset=table_offset;
+ found_set[i].found_offset=found_offset;
+ found_sets++;
+ return -i-2; /* return new postion */
+}
+
+ /* Return 1 if regexp starts with \b or ends with \b*/
+
+static uint start_at_word(my_string pos)
+{
+ return (((!bcmp(pos,"\\b",2) && pos[2]) || !bcmp(pos,"\\^",2)) ? 1 : 0);
+}
+
+static uint end_of_word(my_string pos)
+{
+ my_string end=strend(pos);
+ return ((end > pos+2 && !bcmp(end-2,"\\b",2)) ||
+ (end >= pos+2 && !bcmp(end-2,"\\$",2))) ?
+ 1 : 0;
+}
+
+
+static uint replace_len(my_string str)
+{
+ uint len=0;
+ while (*str)
+ {
+ if (str[0] == '\\' && str[1])
+ str++;
+ str++;
+ len++;
+ }
+ return len;
+}
+
+
+ /* The actual loop */
+
+uint replace_strings(REPLACE *rep, my_string *start,uint *max_length, my_string from)
+{
+ reg1 REPLACE *rep_pos;
+ reg2 REPLACE_STRING *rep_str;
+ my_string to,end,pos,new;
+
+ end=(to= *start) + *max_length-1;
+ rep_pos=rep+1;
+ for(;;)
+ {
+ while (!rep_pos->found)
+ {
+ rep_pos= rep_pos->next[(uchar) *from];
+ if (to == end)
+ {
+ (*max_length)+=8192;
+ if (!(new=my_realloc(*start,*max_length,MYF(MY_WME))))
+ return (uint) -1;
+ to=new+(to - *start);
+ end=(*start=new)+ *max_length-1;
+ }
+ *to++= *from++;
+ }
+ if (!(rep_str = ((REPLACE_STRING*) rep_pos))->replace_string)
+ return (uint) (to - *start)-1;
+ updated=1; /* Some my_string is replaced */
+ to-=rep_str->to_offset;
+ for (pos=rep_str->replace_string; *pos ; pos++)
+ {
+ if (to == end)
+ {
+ (*max_length)*=2;
+ if (!(new=my_realloc(*start,*max_length,MYF(MY_WME))))
+ return (uint) -1;
+ to=new+(to - *start);
+ end=(*start=new)+ *max_length-1;
+ }
+ *to++= *pos;
+ }
+ if (!*(from-=rep_str->from_offset) && rep_pos->found != 2)
+ return (uint) (to - *start);
+ rep_pos=rep;
+ }
+}
+
+static char *buffer; /* The buffer itself, grown as needed. */
+static int bufbytes; /* Number of bytes in the buffer. */
+static int bufread,my_eof; /* Number of bytes to get with each read(). */
+static uint bufalloc;
+static char *out_buff;
+static uint out_length;
+
+static int initialize_buffer()
+{
+ bufread = 8192;
+ bufalloc = bufread + bufread / 2;
+ if (!(buffer = my_malloc(bufalloc+1,MYF(MY_WME))))
+ return 1;
+ bufbytes=my_eof=0;
+ out_length=bufread;
+ if (!(out_buff=my_malloc(out_length,MYF(MY_WME))))
+ return(1);
+ return 0;
+}
+
+static void reset_buffer()
+{
+ bufbytes=my_eof=0;
+}
+
+static void free_buffer()
+{
+ my_free(buffer,MYF(MY_WME));
+ my_free(out_buff,MYF(MY_WME));
+}
+
+
+/* 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 int fill_buffer_retaining(fd,n)
+File fd;
+int n;
+{
+ int i;
+
+ /* See if we need to grow the buffer. */
+ if ((int) bufalloc - n <= bufread)
+ {
+ while ((int) bufalloc - n <= bufread)
+ {
+ bufalloc *= 2;
+ bufread *= 2;
+ }
+ buffer = my_realloc(buffer, bufalloc+1, MYF(MY_WME));
+ if (! buffer)
+ return(-1);
+ }
+
+ /* Shift stuff down. */
+ bmove(buffer,buffer+bufbytes-n,(uint) n);
+ bufbytes = n;
+
+ if (my_eof)
+ return 0;
+
+ /* Read in new stuff. */
+ if ((i=(int) my_read(fd, buffer + bufbytes, (uint) bufread,MYF(MY_WME))) < 0)
+ return -1;
+
+ /* Kludge to pretend every nonempty file ends with a newline. */
+ if (i == 0 && bufbytes > 0 && buffer[bufbytes - 1] != '\n')
+ {
+ my_eof = i = 1;
+ buffer[bufbytes] = '\n';
+ }
+
+ bufbytes += i;
+ return i;
+}
+
+ /* Return 0 if convert is ok */
+ /* Global variable update is set if something was changed */
+
+static int convert_pipe(rep,in,out)
+REPLACE *rep;
+FILE *in,*out;
+{
+ int retain,error;
+ uint length;
+ char save_char,*end_of_line,*start_of_line;
+ DBUG_ENTER("convert_pipe");
+
+ updated=retain=0;
+ reset_buffer();
+
+ while ((error=fill_buffer_retaining(fileno(in),retain)) > 0)
+ {
+ end_of_line=buffer ;
+ buffer[bufbytes]=0; /* Sentinel */
+ for (;;)
+ {
+ start_of_line=end_of_line;
+ while (end_of_line[0] != '\n' && end_of_line[0])
+ end_of_line++;
+ if (end_of_line == buffer+bufbytes)
+ {
+ retain=end_of_line - start_of_line;
+ break; /* No end of line, read more */
+ }
+ save_char=end_of_line[0];
+ end_of_line[0]=0;
+ end_of_line++;
+ if ((length=replace_strings(rep,&out_buff,&out_length,start_of_line)) ==
+ (uint) -1)
+ return 1;
+ if (!my_eof)
+ out_buff[length++]=save_char; /* Don't write added newline */
+ if (my_fwrite(out,out_buff,length,MYF(MY_WME | MY_NABP)))
+ DBUG_RETURN(1);
+ }
+ }
+ DBUG_RETURN(error);
+}
+
+
+static int convert_file(rep,name)
+REPLACE *rep;
+my_string name;
+{
+ int error;
+ FILE *in,*out;
+ char dir_buff[FN_REFLEN],*tempname;
+ DBUG_ENTER("convert_file");
+
+ if (!(in=my_fopen(name,O_RDONLY,MYF(MY_WME))))
+ DBUG_RETURN(1);
+ dirname_part(dir_buff,name);
+ tempname=my_tempnam(dir_buff,"PR",MYF(MY_WME));
+ if (!(out=my_fopen(tempname,(int) (O_WRONLY | O_CREAT),
+ MYF(MY_WME))))
+ {
+ (*free)(tempname);
+ my_fclose(in,MYF(0));
+ DBUG_RETURN(1);
+ }
+
+ error=convert_pipe(rep,in,out);
+ my_fclose(in,MYF(0)); my_fclose(out,MYF(0));
+
+ if (updated && ! error)
+ my_redel(name,tempname,MYF(MY_WME | MY_LINK_WARNING));
+ else
+ my_delete(tempname,MYF(MY_WME));
+ (*free)(tempname);
+ if (!silent && ! error)
+ {
+ if (updated)
+ printf("%s converted\n",name);
+ else if (verbose)
+ printf("%s left unchanged\n",name);
+ }
+ DBUG_RETURN(error);
+}
diff --git a/extra/resolveip.c b/extra/resolveip.c
new file mode 100644
index 00000000000..d739f8de244
--- /dev/null
+++ b/extra/resolveip.c
@@ -0,0 +1,204 @@
+/* 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 */
+
+/* Resolves IP's to hostname and hostnames to IP's */
+
+#define RESOLVE_VERSION "2.0"
+
+#include <global.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#ifndef HAVE_BROKEN_NETINET_INCLUDES
+#include <netinet/in.h>
+#endif
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <m_ctype.h>
+#include <my_sys.h>
+#include <getopt.h>
+
+#if !defined(_AIX) && !defined(HAVE_UNIXWARE7_THREADS) && !defined(HAVE_UNIXWARE7_POSIX) && !defined(h_errno)
+extern int h_errno;
+#endif
+
+static int silent=0;
+
+static struct option long_options[] =
+{
+ {"help", no_argument, 0, '?'},
+ {"info", no_argument, 0, 'I'},
+ {"silent", no_argument, 0, 's'},
+ {"version", no_argument, 0, 'V'},
+ {0, 0, 0, 0}
+};
+
+
+static void print_version(void)
+{
+ printf("%s Ver %s, for %s (%s)\n",my_progname,RESOLVE_VERSION,
+ SYSTEM_TYPE,MACHINE_TYPE);
+}
+
+
+static void usage(void)
+{
+ print_version();
+ 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("Get hostname based on IP-address or IP-address based on hostname.\n");
+ printf("Usage: %s [OPTIONS] hostname or IP-address\n",my_progname);
+ printf("\n\
+ -?, --help Displays this help and exits.\n\
+ -I, --info Synonym for the above.\n\
+ -s, --silent Be more silent.\n\
+ -V, --version Displays version information and exits.\n");
+}
+
+/*static my_string load_default_groups[]= { "resolveip","client",0 }; */
+
+static int get_options(int *argc,char ***argv)
+{
+ int c,option_index;
+
+ /* load_defaults("my",load_default_groups,argc,argv); */
+ while ((c=getopt_long(*argc,*argv,"?IsV",
+ long_options, &option_index)) != EOF)
+ {
+ switch (c) {
+ case 's':
+ silent=1;
+ break;
+ case 'V': print_version(); exit(0);
+ case 'I':
+ case '?':
+ usage();
+ exit(0);
+ default:
+ fprintf(stderr,"%s: Illegal option character '%c'\n",
+ my_progname,opterr);
+ return(1);
+ break;
+ }
+ }
+ (*argc)-=optind;
+ (*argv)+=optind;
+ if (*argc == 0)
+ {
+ usage();
+ return 1;
+ }
+ return 0;
+} /* get_options */
+
+
+
+int main(int argc, char **argv)
+{
+ struct hostent *hpaddr;
+ u_long taddr;
+ char *ip,**q;
+ int error=0;
+
+ MY_INIT(argv[0]);
+
+ if (get_options(&argc,&argv))
+ exit(1);
+
+ while (argc--)
+ {
+ ip = *argv++;
+
+ if (isdigit(ip[0]))
+ {
+ taddr = inet_addr(ip);
+ if (taddr == htonl(INADDR_BROADCAST))
+ {
+ puts("Broadcast");
+ continue;
+ }
+ if (taddr == htonl(INADDR_ANY))
+ {
+ if (!taddr)
+ puts("Null-IP-Addr");
+ else
+ puts("Old-Bcast");
+ continue;
+ }
+
+ hpaddr = gethostbyaddr((char*) &(taddr), sizeof(struct in_addr),AF_INET);
+ if (hpaddr)
+ {
+ if (silent)
+ puts(hpaddr->h_name);
+ else
+ {
+ printf ("Host name of %s is %s", ip,hpaddr->h_name);
+ for (q = hpaddr->h_aliases; *q != 0; q++)
+ (void) printf(", %s", *q);
+ puts("");
+ }
+ }
+ else
+ {
+ error=2;
+ fprintf(stderr,"%s: Unable to find hostname for '%s'\n",my_progname,
+ ip);
+ }
+ }
+ else
+ {
+ hpaddr = gethostbyname(ip);
+ if (!hpaddr)
+ {
+ const char *err;
+ fprintf(stderr,"%s: Unable to find hostid for '%s'",my_progname,ip);
+ switch (h_errno) {
+ case HOST_NOT_FOUND: err="host not found"; break;
+ case TRY_AGAIN: err="try again"; break;
+ case NO_RECOVERY: err="no recovery"; break;
+ case NO_DATA: err="no_data"; break;
+ default: err=0;
+ }
+ if (err)
+ fprintf(stderr,": %s\n",err);
+ else
+ fprintf(stderr,"\n");
+ error=2;
+ }
+ else if (silent)
+ {
+ struct in_addr in;
+ memcpy((char*) &in.s_addr, (char*) *hpaddr->h_addr_list,
+ sizeof (in.s_addr));
+ puts(inet_ntoa(in));
+ }
+ else
+ {
+ char **p;
+ for (p = hpaddr->h_addr_list; *p != 0; p++)
+ {
+ struct in_addr in;
+ memcpy(&in.s_addr, *p, sizeof (in.s_addr));
+ printf ("IP address of %s is %s\n",ip,inet_ntoa(in));
+ }
+ }
+ }
+ }
+ exit(error);
+}
+
+
+
diff --git a/heap/.cvsignore b/heap/.cvsignore
new file mode 100644
index 00000000000..675df8a3eb6
--- /dev/null
+++ b/heap/.cvsignore
@@ -0,0 +1,6 @@
+.deps
+.libs
+Makefile
+Makefile.in
+hp_test1
+hp_test2
diff --git a/heap/ChangeLog b/heap/ChangeLog
new file mode 100644
index 00000000000..9d3ced84cc9
--- /dev/null
+++ b/heap/ChangeLog
@@ -0,0 +1,8 @@
+Sun Sep 6 10:56:59 1992 Michael Widenius (monty@bitch)
+
+ * Added functions for first,next,last,prev and clear of database-heap
+ * Added optional index to rsame for compability.
+
+Fri Aug 14 14:34:35 1992 Michael Widenius (monty@bitch)
+
+ * changed file parameter to HP_INFO *
diff --git a/heap/Makefile.am b/heap/Makefile.am
new file mode 100644
index 00000000000..3977eb5bb64
--- /dev/null
+++ b/heap/Makefile.am
@@ -0,0 +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
+
+INCLUDES = @MT_INCLUDES@ -I$(srcdir)/../include -I../include
+LDADD = libheap.a ../mysys/libmysys.a ../dbug/libdbug.a \
+ ../strings/libmystrings.a
+pkglib_LIBRARIES = libheap.a
+noinst_PROGRAMS = hp_test1 hp_test2
+noinst_HEADERS = heapdef.h
+libheap_a_SOURCES = hp_open.c hp_extra.c hp_close.c hp_panic.c hp_info.c \
+ hp_rrnd.c hp_scan.c hp_update.c hp_write.c hp_delete.c \
+ hp_rsame.c hp_create.c hp_rename.c hp_rfirst.c \
+ hp_rnext.c hp_rlast.c hp_rprev.c hp_clear.c \
+ hp_rkey.c hp_block.c \
+ hp_hash.c _check.c _rectest.c hp_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 \
+ 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
diff --git a/heap/_check.c b/heap/_check.c
new file mode 100644
index 00000000000..77fa0262732
--- /dev/null
+++ b/heap/_check.c
@@ -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 */
+
+/* Check that heap-structure is ok */
+
+#include "heapdef.h"
+
+static int check_one_key(HP_KEYDEF *keydef,ulong records,ulong blength);
+
+/* Returns 0 if the HEAP is ok */
+
+int heap_check_heap(HP_INFO *info)
+{
+ int error;
+ uint key;
+ HP_SHARE *share=info->s;
+ DBUG_ENTER("heap_check_keys");
+
+ for (error=key=0 ; key < share->keys ; key++)
+ error|=check_one_key(share->keydef+key,share->records,share->blength);
+
+ DBUG_RETURN(error);
+}
+
+
+static int check_one_key(HP_KEYDEF *keydef, ulong records, ulong blength)
+{
+ int error;
+ uint i,found,max_links,seek,links;
+ uint rec_link; /* Only used with debugging */
+ HASH_INFO *hash_info;
+
+ error=0;
+ for (i=found=max_links=seek=0 ; i < records ; i++)
+ {
+ hash_info=hp_find_hash(&keydef->block,i);
+ if (_hp_mask(_hp_rec_hashnr(keydef,hash_info->ptr_to_rec),
+ blength,records) == i)
+ {
+ found++;
+ seek++;
+ links=1;
+ while ((hash_info=hash_info->next_key) && found < records + 1)
+ {
+ seek+= ++links;
+ if ((rec_link=_hp_mask(_hp_rec_hashnr(keydef,hash_info->ptr_to_rec),
+ blength,records))
+ != i)
+ {
+ DBUG_PRINT("error",("Record in wrong link: Link %d Record: %lx Record-link %d", i,hash_info->ptr_to_rec,rec_link));
+ error=1;
+ }
+ else
+ found++;
+ }
+ if (links > max_links) max_links=links;
+ }
+ }
+ if (found != records)
+ {
+ DBUG_PRINT("error",("Found %ld of %ld records"));
+ error=1;
+ }
+ DBUG_PRINT("info",
+ ("records: %ld seeks: %d max links: %d hitrate: %.2f",
+ records,seek,max_links,(float) seek / (float) records));
+ return error;
+}
diff --git a/heap/_rectest.c b/heap/_rectest.c
new file mode 100644
index 00000000000..3368fbeeffa
--- /dev/null
+++ b/heap/_rectest.c
@@ -0,0 +1,31 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 if a record has changed since last read */
+/* In heap this is only used when debugging */
+
+#include "heapdef.h"
+
+int _hp_rectest(register HP_INFO *info, register const byte *old)
+{
+ DBUG_ENTER("_hp_rectest");
+
+ if (memcmp(info->current_ptr,old,(size_t) info->s->reclength))
+ {
+ DBUG_RETURN((my_errno=HA_ERR_RECORD_CHANGED)); /* Record have changed */
+ }
+ DBUG_RETURN(0);
+} /* _heap_rectest */
diff --git a/heap/heapdef.h b/heap/heapdef.h
new file mode 100644
index 00000000000..19c3b7d7792
--- /dev/null
+++ b/heap/heapdef.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 */
+
+/* This file is included in all heap-files */
+
+#include <my_base.h> /* This includes global */
+#ifdef THREAD
+#include <my_pthread.h>
+#endif
+#include "heap.h" /* Structs & some defines */
+
+ /* Some extern variables */
+
+extern LIST *heap_open_list,*heap_share_list;
+
+#define test_active(info) \
+if (!(info->update & HA_STATE_AKTIV))\
+{ my_errno=HA_ERR_NO_ACTIVE_RECORD; DBUG_RETURN(-1); }
+#define hp_find_hash(A,B) ((HASH_INFO*) _hp_find_block((A),(B)))
+
+ /* Find pos for record and update it in info->current_ptr */
+#define _hp_find_record(info,pos) (info)->current_ptr= _hp_find_block(&(info)->s->block,pos)
+
+typedef struct st_hash_info
+{
+ struct st_hash_info *next_key;
+ byte *ptr_to_rec;
+} HASH_INFO;
+
+ /* Prototypes for intern functions */
+
+extern HP_SHARE *_hp_find_named_heap(const char *name);
+extern int _hp_rectest(HP_INFO *info,const byte *old);
+extern void _hp_delete_file_from_open_list(HP_INFO *info);
+extern byte *_hp_find_block(HP_BLOCK *info,ulong pos);
+extern int _hp_get_new_block(HP_BLOCK *info, ulong* alloc_length);
+extern void _hp_free(HP_SHARE *info);
+extern byte *_hp_free_level(HP_BLOCK *block,uint level,HP_PTRS *pos,
+ byte *last_pos);
+extern int _hp_write_key(HP_SHARE *info,HP_KEYDEF *keyinfo,
+ const byte *record,byte *recpos);
+extern int _hp_delete_key(HP_INFO *info,HP_KEYDEF *keyinfo,
+ const byte *record,byte *recpos,int flag);
+extern HASH_INFO *_heap_find_hash(HP_BLOCK *block,ulong pos);
+extern byte *_hp_search(HP_INFO *info,HP_KEYDEF *keyinfo,const byte *key,
+ uint nextflag);
+extern byte *_hp_search_next(HP_INFO *info, HP_KEYDEF *keyinfo,
+ const byte *key,
+ HASH_INFO *pos);
+extern ulong _hp_hashnr(HP_KEYDEF *keyinfo,const byte *key);
+extern ulong _hp_rec_hashnr(HP_KEYDEF *keyinfo,const byte *rec);
+extern ulong _hp_mask(ulong hashnr,ulong buffmax,ulong maxlength);
+extern void _hp_movelink(HASH_INFO *pos,HASH_INFO *next_link,
+ HASH_INFO *newlink);
+extern int _hp_rec_key_cmp(HP_KEYDEF *keydef,const byte *rec1,
+ const byte *rec2);
+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 int _hp_close(register HP_INFO *info);
+extern void _hp_clear(HP_SHARE *info);
+
+#ifdef THREAD
+extern pthread_mutex_t THR_LOCK_heap;
+#else
+#define pthread_mutex_lock(A)
+#define pthread_mutex_unlock(A)
+#endif
diff --git a/heap/hp_block.c b/heap/hp_block.c
new file mode 100644
index 00000000000..510d89d6d1e
--- /dev/null
+++ b/heap/hp_block.c
@@ -0,0 +1,111 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 on blocks; Keys and records are saved in blocks */
+
+#include "heapdef.h"
+
+ /* Find record according to record-position */
+
+byte *_hp_find_block(HP_BLOCK *block, ulong pos)
+{
+ reg1 int i;
+ reg3 HP_PTRS *ptr;
+
+ for (i=block->levels-1, ptr=block->root ; i > 0 ; i--)
+ {
+ ptr=(HP_PTRS*)ptr->blocks[pos/block->level_info[i].records_under_level];
+ pos%=block->level_info[i].records_under_level;
+ }
+ return (byte*) ptr+ pos*block->recbuffer;
+}
+
+
+ /* get one new block-of-records. Alloc ptr to block if neaded */
+ /* Interrupts are stopped to allow ha_panic in interrupts */
+
+int _hp_get_new_block(HP_BLOCK *block, ulong *alloc_length)
+{
+ reg1 uint i,j;
+ HP_PTRS *root;
+
+ for (i=0 ; i < block->levels ; i++)
+ if (block->level_info[i].free_ptrs_in_block)
+ break;
+
+ *alloc_length=sizeof(HP_PTRS)*i+block->records_in_block* block->recbuffer;
+ if (!(root=(HP_PTRS*) my_malloc(*alloc_length,MYF(0))))
+ return 1;
+
+ if (i == 0)
+ {
+ block->levels=1;
+ block->root=block->level_info[0].last_blocks=root;
+ }
+ else
+ {
+ dont_break(); /* Dont allow SIGHUP or SIGINT */
+ if ((uint) i == block->levels)
+ {
+ block->levels=i+1;
+ block->level_info[i].free_ptrs_in_block=HP_PTRS_IN_NOD-1;
+ ((HP_PTRS**) root)[0]= block->root;
+ block->root=block->level_info[i].last_blocks= root++;
+ }
+ block->level_info[i].last_blocks->
+ blocks[HP_PTRS_IN_NOD - block->level_info[i].free_ptrs_in_block--]=
+ (byte*) root;
+
+ for (j=i-1 ; j >0 ; j--)
+ {
+ block->level_info[j].last_blocks= root++;
+ block->level_info[j].last_blocks->blocks[0]=(byte*) root;
+ block->level_info[j].free_ptrs_in_block=HP_PTRS_IN_NOD-1;
+ }
+ block->level_info[0].last_blocks= root;
+ allow_break(); /* Allow SIGHUP & SIGINT */
+ }
+ return 0;
+}
+
+
+ /* free all blocks under level */
+
+byte *_hp_free_level(HP_BLOCK *block, uint level, HP_PTRS *pos, byte *last_pos)
+{
+ int i,max_pos;
+ byte *next_ptr;
+
+ if (level == 1)
+ next_ptr=(byte*) pos+block->recbuffer;
+ else
+ {
+ max_pos= (block->level_info[level-1].last_blocks == pos) ?
+ HP_PTRS_IN_NOD - block->level_info[level-1].free_ptrs_in_block :
+ HP_PTRS_IN_NOD;
+
+ next_ptr=(byte*) (pos+1);
+ for (i=0 ; i < max_pos ; i++)
+ next_ptr=_hp_free_level(block,level-1,
+ (HP_PTRS*) pos->blocks[i],next_ptr);
+ }
+ if ((byte*) pos != last_pos)
+ {
+ my_free((gptr) pos,MYF(0));
+ return last_pos;
+ }
+ return next_ptr; /* next memory position */
+}
diff --git a/heap/hp_clear.c b/heap/hp_clear.c
new file mode 100644
index 00000000000..702c2e09d29
--- /dev/null
+++ b/heap/hp_clear.c
@@ -0,0 +1,52 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 records from database
+ Identical as hp_create() and hp_open() but used HP_SHARE* instead of name and
+ database remains open.
+*/
+
+#include "heapdef.h"
+
+void heap_clear(HP_INFO *info)
+{
+ _hp_clear(info->s);
+}
+
+void _hp_clear(HP_SHARE *info)
+{
+ uint key;
+ DBUG_ENTER("_hp_clear");
+
+ if (info->block.levels)
+ VOID(_hp_free_level(&info->block,info->block.levels,info->block.root,
+ (byte*) 0));
+ info->block.levels=0;
+ for (key=0 ; key < info->keys ; key++)
+ {
+ HP_BLOCK *block= &info->keydef[key].block;
+ if (block->levels)
+ VOID(_hp_free_level(block,block->levels,block->root,(byte*) 0));
+ block->levels=0;
+ block->last_allocated=0;
+ }
+ info->records=info->deleted=info->data_length=info->index_length=0;;
+ info->blength=1;
+ info->changed=0;
+ info->del_link=0;
+ DBUG_VOID_RETURN;
+}
diff --git a/heap/hp_close.c b/heap/hp_close.c
new file mode 100644
index 00000000000..b1797d2e92f
--- /dev/null
+++ b/heap/hp_close.c
@@ -0,0 +1,51 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 heap-database */
+
+#include "heapdef.h"
+
+ /* Close a database open by hp_open() */
+ /* Data is not deallocated */
+
+int heap_close(HP_INFO *info)
+{
+ int tmp;
+ DBUG_ENTER("heap_close");
+ pthread_mutex_lock(&THR_LOCK_heap);
+ tmp= _hp_close(info);
+ pthread_mutex_unlock(&THR_LOCK_heap);
+ DBUG_RETURN(tmp);
+}
+
+
+int _hp_close(register HP_INFO *info)
+{
+ int error=0;
+ DBUG_ENTER("_hp_close");
+#ifndef DBUG_OFF
+ if (info->s->changed && heap_check_heap(info))
+ {
+ error=my_errno=HA_ERR_CRASHED;
+ }
+#endif
+ info->s->changed=0;
+ info->s->open_count--;
+ heap_open_list=list_delete(heap_open_list,&info->open_list);
+ my_free((gptr) info,MYF(0));
+ DBUG_RETURN(error);
+}
+
diff --git a/heap/hp_create.c b/heap/hp_create.c
new file mode 100644
index 00000000000..01c5f43adfd
--- /dev/null
+++ b/heap/hp_create.c
@@ -0,0 +1,62 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 is done by simply remove the database from memory if it exists.
+ Open creates the database when neaded
+*/
+
+#include "heapdef.h"
+
+int heap_create(const char *name)
+{
+ DBUG_ENTER("heap_create");
+ (void) heap_delete_all(name);
+ DBUG_RETURN(0);
+}
+
+int heap_delete_all(const char *name)
+{
+ reg1 HP_SHARE *info;
+ int found;
+ DBUG_ENTER("heap_delete_all");
+ pthread_mutex_lock(&THR_LOCK_heap);
+ if ((info=_hp_find_named_heap(name)))
+ {
+ if (info->open_count == 0)
+ _hp_free(info);
+ found=0;
+ }
+ else
+ {
+ found=my_errno=ENOENT;
+ }
+ pthread_mutex_unlock(&THR_LOCK_heap);
+ DBUG_RETURN(found);
+}
+
+void _hp_free(HP_SHARE *share)
+{
+ heap_share_list=list_delete(heap_share_list,&share->open_list);
+ _hp_clear(share); /* Remove blocks from memory */
+#ifdef THREAD
+ thr_lock_delete(&share->lock);
+ VOID(pthread_mutex_destroy(&share->intern_lock));
+#endif
+ my_free((gptr) share->name,MYF(0));
+ my_free((gptr) share,MYF(0));
+ return;
+}
diff --git a/heap/hp_delete.c b/heap/hp_delete.c
new file mode 100644
index 00000000000..a6e77fe5f27
--- /dev/null
+++ b/heap/hp_delete.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 */
+
+/* remove current record in heap-database */
+
+#include "heapdef.h"
+
+int heap_delete(HP_INFO *info, const byte *record)
+{
+ uint key;
+ byte *pos;
+ HP_SHARE *share=info->s;
+ DBUG_ENTER("heap_delete");
+ DBUG_PRINT("enter",("info: %lx record: %lx",info,record));
+
+ test_active(info);
+
+ if (info->opt_flag & READ_CHECK_USED && _hp_rectest(info,record))
+ DBUG_RETURN(my_errno); /* Record changed */
+ share->changed=1;
+
+ if ( --(share->records) < share->blength >> 1) share->blength>>=1;
+ pos=info->current_ptr;
+
+ for (key=0 ; key < share->keys ; key++)
+ {
+ if (_hp_delete_key(info,share->keydef+key,record,pos,
+ key == (uint) info->lastinx))
+ goto err;
+ }
+
+ info->update=HA_STATE_DELETED;
+ *((byte**) pos)=share->del_link;
+ share->del_link=pos;
+ pos[share->reclength]=0; /* Record deleted */
+ share->deleted++;
+ info->current_hash_ptr=0;
+ DBUG_RETURN(0);
+ err:
+ if( ++(share->records) == share->blength) share->blength+= share->blength;
+ DBUG_RETURN(my_errno);
+}
+
+ /* Remove one key from hash-table */
+ /* Flag is set if we want's to correct info->current_ptr */
+
+int _hp_delete_key(HP_INFO *info, register HP_KEYDEF *keyinfo,
+ const byte *record, byte *recpos, int flag)
+{
+ ulong blength,pos2,pos_hashnr,lastpos_hashnr;
+ HASH_INFO *lastpos,*gpos,*pos,*pos3,*empty,*last_ptr;
+ HP_SHARE *share=info->s;
+ DBUG_ENTER("_hp_delete_key");
+
+ blength=share->blength;
+ if (share->records+1 == blength) blength+= blength;
+ lastpos=hp_find_hash(&keyinfo->block,share->records);
+ last_ptr=0;
+
+ /* Search after record with key */
+ pos= hp_find_hash(&keyinfo->block,
+ _hp_mask(_hp_rec_hashnr(keyinfo,record),blength,
+ share->records+1));
+ gpos = pos3 = 0;
+
+ while (pos->ptr_to_rec != recpos)
+ {
+ if (flag && !_hp_rec_key_cmp(keyinfo,record,pos->ptr_to_rec))
+ last_ptr=pos; /* Previous same key */
+ gpos=pos;
+ if (!(pos=pos->next_key))
+ {
+ DBUG_RETURN(my_errno=HA_ERR_CRASHED); /* This shouldn't happend */
+ }
+ }
+
+ /* Remove link to record */
+
+ if (flag)
+ {
+ /* Save for heap_rnext/heap_rprev */
+ info->current_hash_ptr=last_ptr;
+ info->current_ptr = last_ptr ? last_ptr->ptr_to_rec : 0;
+ DBUG_PRINT("info",("Corrected current_ptr to point at: %lx",
+ info->current_ptr));
+ }
+ empty=pos;
+ if (gpos)
+ gpos->next_key=pos->next_key; /* unlink current ptr */
+ else if (pos->next_key)
+ {
+ empty=pos->next_key;
+ pos->ptr_to_rec=empty->ptr_to_rec;
+ pos->next_key=empty->next_key;
+ }
+
+ if (empty == lastpos) /* deleted last hash key */
+ DBUG_RETURN (0);
+
+ /* Move the last key (lastpos) */
+ lastpos_hashnr=_hp_rec_hashnr(keyinfo,lastpos->ptr_to_rec);
+ /* pos is where lastpos should be */
+ pos=hp_find_hash(&keyinfo->block,_hp_mask(lastpos_hashnr,share->blength,
+ share->records));
+ if (pos == empty) /* Move to empty position. */
+ {
+ empty[0]=lastpos[0];
+ DBUG_RETURN(0);
+ }
+ pos_hashnr=_hp_rec_hashnr(keyinfo,pos->ptr_to_rec);
+ /* pos3 is where the pos should be */
+ pos3= hp_find_hash(&keyinfo->block,
+ _hp_mask(pos_hashnr,share->blength,share->records));
+ if (pos != pos3)
+ { /* pos is on wrong posit */
+ empty[0]=pos[0]; /* Save it here */
+ pos[0]=lastpos[0]; /* This shold be here */
+ _hp_movelink(pos,pos3,empty); /* Fix link to pos */
+ DBUG_RETURN(0);
+ }
+ pos2= _hp_mask(lastpos_hashnr,blength,share->records+1);
+ if (pos2 == _hp_mask(pos_hashnr,blength,share->records+1))
+ { /* Identical key-positions */
+ if (pos2 != share->records)
+ {
+ empty[0]=lastpos[0];
+ _hp_movelink(lastpos,pos,empty);
+ DBUG_RETURN(0);
+ }
+ pos3= pos; /* Link pos->next after lastpos */
+ }
+ else pos3= 0; /* Different positions merge */
+
+ empty[0]=lastpos[0];
+ _hp_movelink(pos3,empty,pos->next_key);
+ pos->next_key=empty;
+ DBUG_RETURN(0);
+}
diff --git a/heap/hp_extra.c b/heap/hp_extra.c
new file mode 100644
index 00000000000..581ca1e8e56
--- /dev/null
+++ b/heap/hp_extra.c
@@ -0,0 +1,47 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* Extra functions we want to do with a database */
+/* - Set flags for quicker databasehandler */
+/* - Set databasehandler to normal */
+/* - Reset recordpointers as after open database */
+
+#include "heapdef.h"
+
+ /* set extra flags for database */
+
+int heap_extra(register HP_INFO *info, enum ha_extra_function function)
+{
+ DBUG_ENTER("heap_extra");
+
+ switch (function) {
+ case HA_EXTRA_RESET:
+ info->lastinx= -1;
+ info->current_record= (ulong) ~0L;
+ info->current_hash_ptr=0;
+ info->update=0;
+ break;
+ case HA_EXTRA_NO_READCHECK:
+ info->opt_flag&= ~READ_CHECK_USED; /* No readcheck */
+ break;
+ case HA_EXTRA_READCHECK:
+ info->opt_flag|= READ_CHECK_USED;
+ break;
+ default:
+ break;
+ }
+ DBUG_RETURN(0);
+} /* heap_extra */
diff --git a/heap/hp_hash.c b/heap/hp_hash.c
new file mode 100644
index 00000000000..28647ab7c94
--- /dev/null
+++ b/heap/hp_hash.c
@@ -0,0 +1,266 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 */
+
+#include "heapdef.h"
+#include <m_ctype.h>
+
+ /* Search after a record based on a key */
+ /* Sets info->current_ptr to found record */
+ /* next_flag: Search=0, next=1, prev =2, same =3 */
+
+byte *_hp_search(HP_INFO *info, HP_KEYDEF *keyinfo, const byte *key,
+ uint nextflag)
+{
+ reg1 HASH_INFO *pos,*prev_ptr;
+ int flag;
+ uint old_nextflag;
+ HP_SHARE *share=info->s;
+ DBUG_ENTER("_hp_search");
+
+ old_nextflag=nextflag;
+ flag=1;
+ prev_ptr=0;
+
+ if (share->records)
+ {
+ pos=hp_find_hash(&keyinfo->block,_hp_mask(_hp_hashnr(keyinfo,key),
+ share->blength,share->records));
+ do
+ {
+ if (!_hp_key_cmp(keyinfo,pos->ptr_to_rec,key))
+ {
+ switch (nextflag) {
+ case 0: /* Search after key */
+ DBUG_PRINT("exit",("found key at %d",pos->ptr_to_rec));
+ info->current_hash_ptr=pos;
+ DBUG_RETURN(info->current_ptr= pos->ptr_to_rec);
+ case 1: /* Search next */
+ if (pos->ptr_to_rec == info->current_ptr)
+ nextflag=0;
+ break;
+ case 2: /* Search previous */
+ if (pos->ptr_to_rec == info->current_ptr)
+ {
+ my_errno=HA_ERR_KEY_NOT_FOUND; /* If gpos == 0 */
+ info->current_hash_ptr=prev_ptr;
+ DBUG_RETURN(info->current_ptr=prev_ptr ? prev_ptr->ptr_to_rec : 0);
+ }
+ prev_ptr=pos; /* Prev. record found */
+ break;
+ case 3: /* Search same */
+ if (pos->ptr_to_rec == info->current_ptr)
+ {
+ info->current_hash_ptr=pos;
+ DBUG_RETURN(info->current_ptr);
+ }
+ }
+ }
+ if (flag)
+ {
+ flag=0; /* Reset flag */
+ if (hp_find_hash(&keyinfo->block,
+ _hp_mask(_hp_rec_hashnr(keyinfo,pos->ptr_to_rec),
+ share->blength,share->records)) != pos)
+ break; /* Wrong link */
+ }
+ }
+ while ((pos=pos->next_key));
+ }
+ my_errno=HA_ERR_KEY_NOT_FOUND;
+ if (nextflag == 2 && ! info->current_ptr)
+ {
+ /* Do a previous from end */
+ info->current_hash_ptr=prev_ptr;
+ DBUG_RETURN(info->current_ptr=prev_ptr ? prev_ptr->ptr_to_rec : 0);
+ }
+
+ if (old_nextflag && nextflag)
+ my_errno=HA_ERR_RECORD_CHANGED; /* Didn't find old record */
+ DBUG_PRINT("exit",("Error: %d",my_errno));
+ info->current_hash_ptr=0;
+ DBUG_RETURN((info->current_ptr= 0));
+}
+
+
+/*
+ Search next after last read; Assumes that the table hasn't changed
+ since last read !
+*/
+
+byte *_hp_search_next(HP_INFO *info, HP_KEYDEF *keyinfo, const byte *key,
+ HASH_INFO *pos)
+{
+ DBUG_ENTER("_hp_search_next");
+
+ while ((pos= pos->next_key))
+ {
+ if (!_hp_key_cmp(keyinfo,pos->ptr_to_rec,key))
+ {
+ info->current_hash_ptr=pos;
+ DBUG_RETURN (info->current_ptr= pos->ptr_to_rec);
+ }
+ }
+ my_errno=HA_ERR_KEY_NOT_FOUND;
+ DBUG_PRINT("exit",("Error: %d",my_errno));
+ info->current_hash_ptr=0;
+ DBUG_RETURN ((info->current_ptr= 0));
+}
+
+
+ /* Calculate pos according to keys */
+
+ulong _hp_mask(ulong hashnr, ulong buffmax, ulong maxlength)
+{
+ if ((hashnr & (buffmax-1)) < maxlength) return (hashnr & (buffmax-1));
+ return (hashnr & ((buffmax >> 1) -1));
+}
+
+
+ /* Change link from pos to new_link */
+
+void _hp_movelink(HASH_INFO *pos, HASH_INFO *next_link, HASH_INFO *newlink)
+{
+ HASH_INFO *old_link;
+ do
+ {
+ old_link=next_link;
+ }
+ while ((next_link=next_link->next_key) != pos);
+ old_link->next_key=newlink;
+ return;
+}
+
+
+ /* Calc hashvalue for a key */
+
+ulong _hp_hashnr(register HP_KEYDEF *keydef, register const byte *key)
+{
+ register ulong nr=1, nr2=4;
+ HP_KEYSEG *seg,*endseg;
+ uchar *pos;
+
+ for (seg=keydef->seg,endseg=seg+keydef->keysegs ; seg < endseg ; seg++)
+ {
+ if (seg->type == HA_KEYTYPE_TEXT)
+ {
+ for (pos=(uchar*) key,key+=seg->length ; pos < (uchar*) key ; pos++)
+ {
+ nr^=(ulong) ((((uint) nr & 63)+nr2)*((uint) my_sort_order[(uint) *pos]))+ (nr << 8);
+ nr2+=3;
+ }
+ }
+ else
+ {
+ for (pos=(uchar*) key,key+=seg->length ; pos < (uchar*) key ; pos++)
+ {
+ nr^=(ulong) ((((uint) nr & 63)+nr2)*((uint) *pos))+ (nr << 8);
+ nr2+=3;
+ }
+ }
+ }
+ return((ulong) nr);
+}
+
+ /* Calc hashvalue for a key in a record */
+
+ulong _hp_rec_hashnr(register HP_KEYDEF *keydef, register const byte *rec)
+{
+ register ulong nr=1, nr2=4;
+ HP_KEYSEG *seg,*endseg;
+ uchar *pos,*end;
+
+ for (seg=keydef->seg,endseg=seg+keydef->keysegs ; seg < endseg ; seg++)
+ {
+ if (seg->type == HA_KEYTYPE_TEXT)
+ {
+ for (pos=(uchar*) rec+seg->start,end=pos+seg->length ; pos < end ; pos++)
+ {
+ nr^=(ulong) ((((uint) nr & 63)+nr2)*((uint) my_sort_order[(uint) *pos]))+ (nr << 8);
+ nr2+=3;
+ }
+ }
+ else
+ {
+ for (pos=(uchar*) rec+seg->start,end=pos+seg->length ; pos < end ; pos++)
+ {
+ nr^=(ulong) ((((uint) nr & 63)+nr2)*((uint) *pos))+ (nr << 8);
+ nr2+=3;
+ }
+ }
+ }
+ return((ulong) nr);
+}
+
+ /* Compare keys for two records. Returns 0 if they are identical */
+
+int _hp_rec_key_cmp(HP_KEYDEF *keydef, const byte *rec1, const byte *rec2)
+{
+ HP_KEYSEG *seg,*endseg;
+
+ for (seg=keydef->seg,endseg=seg+keydef->keysegs ; seg < endseg ; seg++)
+ {
+ if (seg->type == HA_KEYTYPE_TEXT)
+ {
+ if (my_sortcmp(rec1+seg->start,rec2+seg->start,seg->length))
+ return 1;
+ }
+ else
+ {
+ if (bcmp(rec1+seg->start,rec2+seg->start,seg->length))
+ return 1;
+ }
+ }
+ return 0;
+}
+
+ /* Compare a key in a record to a hole 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++)
+ {
+ if (seg->type == HA_KEYTYPE_TEXT)
+ {
+ if (my_sortcmp(rec+seg->start,key,seg->length))
+ return 1;
+ }
+ else
+ {
+ if (bcmp(rec+seg->start,key,seg->length))
+ return 1;
+ }
+ key+=seg->length;
+ }
+ return 0;
+}
+
+
+ /* Copy a key from a record to a keybuffer */
+
+void _hp_make_key(HP_KEYDEF *keydef, byte *key, const byte *rec)
+{
+ HP_KEYSEG *seg,*endseg;
+
+ for (seg=keydef->seg,endseg=seg+keydef->keysegs ; seg < endseg ; seg++)
+ {
+ memcpy(key,rec+seg->start,(size_t) seg->length);
+ key+=seg->length;
+ }
+}
diff --git a/heap/hp_info.c b/heap/hp_info.c
new file mode 100644
index 00000000000..260ac31ab8e
--- /dev/null
+++ b/heap/hp_info.c
@@ -0,0 +1,58 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* Returns info about database status */
+
+#include "heapdef.h"
+
+
+byte *heap_position(HP_INFO *info)
+{
+ return ((info->update & HA_STATE_AKTIV) ? info->current_ptr :
+ (HEAP_PTR) 0);
+}
+
+
+#ifdef WANT_OLD_HEAP_VERSION
+
+/*
+ The following should NOT be used anymore as this can't be used together with
+ heap_rkey()
+*/
+
+ulong heap_position_old(HP_INFO *info)
+{
+ return ((info->update & HA_STATE_AKTIV) ? info->current_record :
+ (ulong) ~0L);
+}
+
+#endif /* WANT_OLD_HEAP_CODE */
+
+/* Note that heap_info does NOT return information about the
+ current position anymore; Use heap_position instead */
+
+int heap_info(reg1 HP_INFO *info,reg2 HEAPINFO *x,int flag)
+{
+ DBUG_ENTER("heap_info");
+ x->records = info->s->records;
+ x->deleted = info->s->deleted;
+ x->reclength = info->s->reclength;
+ x->data_length = info->s->data_length;
+ x->index_length= info->s->index_length;
+ x->max_records = info->s->max_records;
+ x->errkey = info->errkey;
+ DBUG_RETURN(0);
+} /* heap_info */
diff --git a/heap/hp_open.c b/heap/hp_open.c
new file mode 100644
index 00000000000..77de5ca824a
--- /dev/null
+++ b/heap/hp_open.c
@@ -0,0 +1,173 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 heap-database */
+
+#include "heapdef.h"
+#ifdef VMS
+#include "hp_static.c" /* Stupid vms-linker */
+#endif
+
+static void init_block(HP_BLOCK *block,uint reclength,ulong min_records,
+ ulong max_records);
+
+ /* open a heap database. */
+
+HP_INFO *heap_open(const char *name, int mode, uint keys, HP_KEYDEF *keydef,
+ uint reclength, ulong max_records, ulong min_records)
+{
+ uint i,j,key_segs,max_length,length;
+ HP_INFO *info;
+ HP_SHARE *share;
+ HP_KEYSEG *keyseg;
+ DBUG_ENTER("heap_open");
+
+ pthread_mutex_lock(&THR_LOCK_heap);
+ if (!(share=_hp_find_named_heap(name)))
+ {
+ for (i=key_segs=max_length=0 ; i < keys ; i++)
+ {
+ 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;
+ keydef[i].length=length;
+ if (length > max_length)
+ max_length=length;
+ }
+ if (!(share = (HP_SHARE*) my_malloc((uint) sizeof(HP_SHARE)+
+ keys*sizeof(HP_KEYDEF)+
+ key_segs*sizeof(HP_KEYSEG),
+ MYF(MY_ZEROFILL))))
+ {
+ pthread_mutex_unlock(&THR_LOCK_heap);
+ DBUG_RETURN(0);
+ }
+ share->keydef=(HP_KEYDEF*) (share+1);
+ keyseg=(HP_KEYSEG*) (share->keydef+keys);
+ init_block(&share->block,reclength+1,min_records,max_records);
+ /* Fix keys */
+ memcpy(share->keydef,keydef,(size_t) (sizeof(keydef[0])*keys));
+ for (i=0 ; i < keys ; i++)
+ {
+ share->keydef[i].seg=keyseg;
+ memcpy(keyseg,keydef[i].seg,
+ (size_t) (sizeof(keyseg[0])*keydef[i].keysegs));
+ keyseg+=keydef[i].keysegs;
+ init_block(&share->keydef[i].block,sizeof(HASH_INFO),min_records,
+ max_records);
+ }
+
+ share->min_records=min_records;
+ share->max_records=max_records;
+ share->data_length=share->index_length=0;
+ share->reclength=reclength;
+ share->blength=1;
+ share->keys=keys;
+ share->max_key_length=max_length;
+ share->changed=0;
+ if (!(share->name=my_strdup(name,MYF(0))))
+ {
+ my_free((gptr) share,MYF(0));
+ pthread_mutex_unlock(&THR_LOCK_heap);
+ DBUG_RETURN(0);
+ }
+#ifdef THREAD
+ thr_lock_init(&share->lock);
+ VOID(pthread_mutex_init(&share->intern_lock,NULL));
+#endif
+ share->open_list.data=(void*) share;
+ heap_share_list=list_add(heap_share_list,&share->open_list);
+ }
+ if (!(info= (HP_INFO*) my_malloc((uint) sizeof(HP_INFO)+
+ share->max_key_length,
+ MYF(MY_ZEROFILL))))
+ {
+ pthread_mutex_unlock(&THR_LOCK_heap);
+ DBUG_RETURN(0);
+ }
+ share->open_count++;
+#ifdef THREAD
+ thr_lock_data_init(&share->lock,&info->lock,NULL);
+#endif
+ info->open_list.data=(void*) info;
+ heap_open_list=list_add(heap_open_list,&info->open_list);
+ pthread_mutex_unlock(&THR_LOCK_heap);
+
+ info->s=share;
+ info->lastkey=(byte*) (info+1);
+ info->mode=mode;
+ info->current_record= (ulong) ~0L; /* No current record */
+ info->current_ptr=0;
+ info->current_hash_ptr=0;
+ info->lastinx= info->errkey= -1;
+ info->update=0;
+#ifndef DBUG_OFF
+ info->opt_flag=READ_CHECK_USED; /* Check when changing */
+#endif
+ DBUG_PRINT("exit",("heap: %lx reclength: %d records_in_block: %d",
+ info,share->reclength,share->block.records_in_block));
+ DBUG_RETURN(info);
+} /* heap_open */
+
+
+ /* map name to a heap-nr. If name isn't found return 0 */
+
+HP_SHARE *_hp_find_named_heap(const char *name)
+{
+ LIST *pos;
+ HP_SHARE *info;
+ DBUG_ENTER("heap_find");
+ DBUG_PRINT("enter",("name: %s",name));
+
+ for (pos=heap_share_list ; pos ; pos=pos->next)
+ {
+ info=(HP_SHARE*) pos->data;
+ if (!strcmp(name,info->name))
+ {
+ DBUG_PRINT("exit",("Old heap_database: %lx",info));
+ DBUG_RETURN(info);
+ }
+ }
+ DBUG_RETURN((HP_SHARE *)0);
+}
+
+
+static void init_block(HP_BLOCK *block, uint reclength, ulong min_records,
+ ulong max_records)
+{
+ uint i,recbuffer,records_in_block;
+
+ max_records=max(min_records,max_records);
+ if (!max_records)
+ max_records=1000; /* As good as quess as anything */
+ recbuffer=(uint) (reclength+sizeof(byte**)-1) & ~(sizeof(byte**)-1);
+ records_in_block=max_records/10;
+ if (records_in_block < 10 && max_records)
+ records_in_block=10;
+ if (!records_in_block || records_in_block*recbuffer >
+ (my_default_record_cache_size-sizeof(HP_PTRS)*HP_MAX_LEVELS))
+ records_in_block=(my_default_record_cache_size-sizeof(HP_PTRS)*
+ HP_MAX_LEVELS)/recbuffer+1;
+ block->records_in_block=records_in_block;
+ block->recbuffer=recbuffer;
+ block->last_allocated= 0L;
+
+ for (i=0 ; i <= HP_MAX_LEVELS ; i++)
+ block->level_info[i].records_under_level=
+ (!i ? 1 : i == 1 ? records_in_block :
+ HP_PTRS_IN_NOD * block->level_info[i-1].records_under_level);
+}
diff --git a/heap/hp_panic.c b/heap/hp_panic.c
new file mode 100644
index 00000000000..cfd370a56d0
--- /dev/null
+++ b/heap/hp_panic.c
@@ -0,0 +1,57 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "heapdef.h"
+
+ /* if flag == HA_PANIC_CLOSE then all files are removed for more
+ memory */
+
+int heap_panic(enum ha_panic_function flag)
+{
+ LIST *element,*next_open;
+ DBUG_ENTER("heap_panic");
+
+ pthread_mutex_lock(&THR_LOCK_heap);
+ for (element=heap_open_list ; element ; element=next_open)
+ {
+ HP_INFO *info=(HP_INFO*) element->data;
+ next_open=element->next; /* Save if close */
+ switch (flag) {
+ case HA_PANIC_CLOSE:
+ _hp_close(info);
+ break;
+ default:
+ break;
+ }
+ }
+ for (element=heap_share_list ; element ; element=next_open)
+ {
+ HP_SHARE *share=(HP_SHARE*) element->data;
+ next_open=element->next; /* Save if close */
+ switch (flag) {
+ case HA_PANIC_CLOSE:
+ {
+ if (!share->open_count)
+ _hp_free(share);
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ pthread_mutex_unlock(&THR_LOCK_heap);
+ DBUG_RETURN(0);
+} /* heap_panic */
diff --git a/heap/hp_rename.c b/heap/hp_rename.c
new file mode 100644
index 00000000000..267c16b589d
--- /dev/null
+++ b/heap/hp_rename.c
@@ -0,0 +1,42 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/*
+ Rename a table
+*/
+
+#include "heapdef.h"
+
+int heap_rename(const char *old_name, const char *new_name)
+{
+ reg1 HP_SHARE *info;
+ char *name_buff;
+ DBUG_ENTER("heap_rename");
+
+ pthread_mutex_lock(&THR_LOCK_heap);
+ if ((info=_hp_find_named_heap(old_name)))
+ {
+ if (!(name_buff=(char*) my_strdup(new_name,MYF(MY_WME))))
+ {
+ pthread_mutex_unlock(&THR_LOCK_heap);
+ DBUG_RETURN(my_errno);
+ }
+ my_free(info->name,MYF(0));
+ info->name=name_buff;
+ }
+ pthread_mutex_unlock(&THR_LOCK_heap);
+ DBUG_RETURN(0);
+}
diff --git a/heap/hp_rfirst.c b/heap/hp_rfirst.c
new file mode 100644
index 00000000000..e3b9654061d
--- /dev/null
+++ b/heap/hp_rfirst.c
@@ -0,0 +1,28 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "heapdef.h"
+
+/* Read first record with the current key */
+
+int heap_rfirst(HP_INFO *info, byte *record)
+{
+ DBUG_ENTER("heap_rfirst");
+ info->current_record=0;
+ info->current_hash_ptr=0;
+ info->update=HA_STATE_PREV_FOUND;
+ DBUG_RETURN(heap_rnext(info,record));
+}
diff --git a/heap/hp_rkey.c b/heap/hp_rkey.c
new file mode 100644
index 00000000000..872560b1a91
--- /dev/null
+++ b/heap/hp_rkey.c
@@ -0,0 +1,51 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "heapdef.h"
+
+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_PRINT("enter",("base: %lx inx: %d",info,inx));
+
+ if ((uint) inx >= share->keys)
+ {
+ DBUG_RETURN(my_errno=HA_ERR_WRONG_INDEX);
+ }
+ info->lastinx=inx;
+ info->current_record = (ulong) ~0L; /* For heap_rrnd() */
+
+ if (!(pos=_hp_search(info,share->keydef+inx,key,0)))
+ {
+ info->update=0;
+ DBUG_RETURN(my_errno);
+ }
+ memcpy(record,pos,(size_t) share->reclength);
+ info->update=HA_STATE_AKTIV;
+ if (!(share->keydef->flag & HA_NOSAME))
+ memcpy(info->lastkey,key,(size_t) share->keydef[inx].length);
+ DBUG_RETURN(0);
+}
+
+
+ /* Quick find of record */
+
+gptr heap_find(HP_INFO *info, int inx, const byte *key)
+{
+ return _hp_search(info,info->s->keydef+inx,key,0);
+}
diff --git a/heap/hp_rlast.c b/heap/hp_rlast.c
new file mode 100644
index 00000000000..38e07fde2bb
--- /dev/null
+++ b/heap/hp_rlast.c
@@ -0,0 +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 */
+
+#include "heapdef.h"
+
+ /* Read first record with the current key */
+
+
+int heap_rlast(HP_INFO *info, byte *record)
+{
+ DBUG_ENTER("heap_rlast");
+ info->current_ptr=0;
+ info->current_hash_ptr=0;
+ info->update=HA_STATE_NEXT_FOUND;
+ DBUG_RETURN(heap_rprev(info,record));
+}
diff --git a/heap/hp_rnext.c b/heap/hp_rnext.c
new file mode 100644
index 00000000000..1b775136655
--- /dev/null
+++ b/heap/hp_rnext.c
@@ -0,0 +1,56 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "heapdef.h"
+
+/* Read next record with the same key */
+
+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);
+
+ if (info->current_hash_ptr)
+ pos= _hp_search_next(info,share->keydef+info->lastinx, info->lastkey,
+ info->current_hash_ptr);
+ else
+ {
+ if (!info->current_ptr && (info->update & HA_STATE_NEXT_FOUND))
+ {
+ pos=0; /* Read next after last */
+ my_errno=HA_ERR_KEY_NOT_FOUND;
+ }
+ else if (!info->current_ptr && (info->update & HA_STATE_PREV_FOUND))
+ pos= _hp_search(info,share->keydef+info->lastinx, info->lastkey, 0);
+ else
+ pos= _hp_search(info,share->keydef+info->lastinx, info->lastkey, 1);
+ }
+
+ if (!pos)
+ {
+ info->update=HA_STATE_NEXT_FOUND; /* For heap_rprev */
+ if (my_errno == HA_ERR_KEY_NOT_FOUND)
+ my_errno=HA_ERR_END_OF_FILE;
+ DBUG_RETURN(my_errno);
+ }
+ memcpy(record,pos,(size_t) share->reclength);
+ info->update=HA_STATE_AKTIV | HA_STATE_NEXT_FOUND;
+ DBUG_RETURN(0);
+}
diff --git a/heap/hp_rprev.c b/heap/hp_rprev.c
new file mode 100644
index 00000000000..28a821c143e
--- /dev/null
+++ b/heap/hp_rprev.c
@@ -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 */
+
+#include "heapdef.h"
+
+ /* Read prev record for key */
+
+
+int heap_rprev(HP_INFO *info, byte *record)
+{
+ byte *pos;
+ HP_SHARE *share=info->s;
+ DBUG_ENTER("heap_rprev");
+
+ if (info->lastinx < 0)
+ DBUG_RETURN(my_errno=HA_ERR_WRONG_INDEX);
+
+ if (info->current_ptr || (info->update & HA_STATE_NEXT_FOUND))
+ {
+ if ((info->update & HA_STATE_DELETED))
+ pos= _hp_search(info,share->keydef+info->lastinx, info->lastkey, 3);
+ else
+ pos= _hp_search(info,share->keydef+info->lastinx, info->lastkey, 2);
+ }
+ else
+ {
+ pos=0; /* Read next after last */
+ my_errno=HA_ERR_KEY_NOT_FOUND;
+ }
+ if (!pos)
+ {
+ info->update=HA_STATE_PREV_FOUND; /* For heap_rprev */
+ if (my_errno == HA_ERR_KEY_NOT_FOUND)
+ my_errno=HA_ERR_END_OF_FILE;
+ DBUG_RETURN(my_errno);
+ }
+ memcpy(record,pos,(size_t) share->reclength);
+ info->update=HA_STATE_AKTIV | HA_STATE_PREV_FOUND;
+ DBUG_RETURN(0);
+}
diff --git a/heap/hp_rrnd.c b/heap/hp_rrnd.c
new file mode 100644
index 00000000000..63181967a29
--- /dev/null
+++ b/heap/hp_rrnd.c
@@ -0,0 +1,106 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* Read a record from a random position */
+
+#include "heapdef.h"
+
+/*
+ Returns one of following values:
+ 0 = Ok.
+ HA_ERR_RECORD_DELETED = Record is deleted.
+ HA_ERR_END_OF_FILE = EOF.
+*/
+
+int heap_rrnd(register HP_INFO *info, byte *record, byte *pos)
+{
+ HP_SHARE *share=info->s;
+ DBUG_ENTER("heap_rrnd");
+ DBUG_PRINT("enter",("info: %lx pos: %lx",info,pos));
+
+ info->lastinx= -1;
+ if (!(info->current_ptr= pos))
+ {
+ info->update= 0;
+ DBUG_RETURN(my_errno= HA_ERR_END_OF_FILE);
+ }
+ if (!info->current_ptr[share->reclength])
+ {
+ info->update= HA_STATE_PREV_FOUND | HA_STATE_NEXT_FOUND;
+ DBUG_RETURN(my_errno=HA_ERR_RECORD_DELETED);
+ }
+ info->update=HA_STATE_PREV_FOUND | HA_STATE_NEXT_FOUND | HA_STATE_AKTIV;
+ memcpy(record,info->current_ptr,(size_t) share->reclength);
+ DBUG_PRINT("exit",("found record at %lx",info->current_ptr));
+ info->current_hash_ptr=0; /* Can't use rnext */
+ DBUG_RETURN(0);
+} /* heap_rrnd */
+
+
+#ifdef WANT_OLD_HEAP_VERSION
+
+/*
+ If pos == -1 then read next record
+ Returns one of following values:
+ 0 = Ok.
+ HA_ERR_RECORD_DELETED = Record is deleted.
+ HA_ERR_END_OF_FILE = EOF.
+*/
+
+int heap_rrnd_old(register HP_INFO *info, byte *record, ulong pos)
+{
+ HP_SHARE *share=info->s;
+ DBUG_ENTER("heap_rrnd");
+ DBUG_PRINT("enter",("info: %lx pos: %ld",info,pos));
+
+ info->lastinx= -1;
+ if (pos == (ulong) -1)
+ {
+ pos= ++info->current_record;
+ if (pos % share->block.records_in_block && /* Quick next record */
+ pos < share->records+share->deleted &&
+ (info->update & HA_STATE_PREV_FOUND))
+ {
+ info->current_ptr+=share->block.recbuffer;
+ goto end;
+ }
+ }
+ else
+ info->current_record=pos;
+
+ if (pos >= share->records+share->deleted)
+ {
+ info->update= 0;
+ DBUG_RETURN(my_errno= HA_ERR_END_OF_FILE);
+ }
+
+ /* Find record number pos */
+ _hp_find_record(info,pos);
+
+end:
+ if (!info->current_ptr[share->reclength])
+ {
+ info->update= HA_STATE_PREV_FOUND | HA_STATE_NEXT_FOUND;
+ DBUG_RETURN(my_errno=HA_ERR_RECORD_DELETED);
+ }
+ info->update=HA_STATE_PREV_FOUND | HA_STATE_NEXT_FOUND | HA_STATE_AKTIV;
+ memcpy(record,info->current_ptr,(size_t) share->reclength);
+ DBUG_PRINT("exit",("found record at %lx",info->current_ptr));
+ info->current_hash_ptr=0; /* Can't use rnext */
+ DBUG_RETURN(0);
+} /* heap_rrnd */
+
+#endif /* WANT_OLD_HEAP_VERSION */
diff --git a/heap/hp_rsame.c b/heap/hp_rsame.c
new file mode 100644
index 00000000000..888fb349f5a
--- /dev/null
+++ b/heap/hp_rsame.c
@@ -0,0 +1,57 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* re-read current record */
+
+#include "heapdef.h"
+
+ /* If inx != -1 the new record is read according to index
+ (for next/prev). Record must in this case point to last record
+ Returncodes:
+ 0 = Ok.
+ HA_ERR_RECORD_DELETED = Record was removed
+ HA_ERR_KEY_NOT_FOUND = Record not found with key
+ */
+
+int heap_rsame(register HP_INFO *info, byte *record, int inx)
+{
+ HP_SHARE *share=info->s;
+ DBUG_ENTER("heap_rsame");
+
+ test_active(info);
+ if (info->current_ptr[share->reclength])
+ {
+ if (inx < -1 || inx >= (int) share->keys)
+ {
+ DBUG_RETURN(my_errno=HA_ERR_WRONG_INDEX);
+ }
+ else if (inx != -1)
+ {
+ info->lastinx=inx;
+ _hp_make_key(share->keydef+inx,info->lastkey,record);
+ if (!_hp_search(info,share->keydef+inx,info->lastkey,3))
+ {
+ info->update=0;
+ DBUG_RETURN(my_errno);
+ }
+ }
+ memcpy(record,info->current_ptr,(size_t) share->reclength);
+ DBUG_RETURN(0);
+ }
+ info->update=0;
+
+ DBUG_RETURN(my_errno=HA_ERR_RECORD_DELETED);
+}
diff --git a/heap/hp_scan.c b/heap/hp_scan.c
new file mode 100644
index 00000000000..b7684cd2673
--- /dev/null
+++ b/heap/hp_scan.c
@@ -0,0 +1,72 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* Scan through all rows */
+
+#include "heapdef.h"
+
+/*
+ Returns one of following values:
+ 0 = Ok.
+ HA_ERR_RECORD_DELETED = Record is deleted.
+ HA_ERR_END_OF_FILE = EOF.
+*/
+
+int heap_scan_init(register HP_INFO *info)
+{
+ DBUG_ENTER("heap_scan_init");
+ info->lastinx= -1;
+ info->current_record= (ulong) ~0L; /* No current record */
+ info->update=0;
+ info->next_block=0;
+ DBUG_RETURN(0);
+}
+
+int heap_scan(register HP_INFO *info, byte *record)
+{
+ HP_SHARE *share=info->s;
+ ulong pos;
+ DBUG_ENTER("heap_scan");
+
+ pos= ++info->current_record;
+ if (pos < info->next_block)
+ {
+ info->current_ptr+=share->block.recbuffer;
+ }
+ else
+ {
+ info->next_block+=share->block.records_in_block;
+ if (info->next_block >= share->records+share->deleted)
+ {
+ info->next_block= share->records+share->deleted;
+ if (pos >= info->next_block)
+ {
+ info->update= 0;
+ DBUG_RETURN(my_errno= HA_ERR_END_OF_FILE);
+ }
+ }
+ _hp_find_record(info,pos);
+ }
+ if (!info->current_ptr[share->reclength])
+ {
+ info->update= HA_STATE_PREV_FOUND | HA_STATE_NEXT_FOUND;
+ DBUG_RETURN(my_errno=HA_ERR_RECORD_DELETED);
+ }
+ info->update= HA_STATE_PREV_FOUND | HA_STATE_NEXT_FOUND | HA_STATE_AKTIV;
+ memcpy(record,info->current_ptr,(size_t) share->reclength);
+ info->current_hash_ptr=0; /* Can't use read_next */
+ DBUG_RETURN(0);
+} /* heap_scan */
diff --git a/heap/hp_static.c b/heap/hp_static.c
new file mode 100644
index 00000000000..5e5326ca76b
--- /dev/null
+++ b/heap/hp_static.c
@@ -0,0 +1,26 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 heap library. All definied here for easy making of
+ a shared library
+*/
+
+#ifndef _global_h
+#include "heapdef.h"
+#endif
+
+LIST *heap_open_list=0,*heap_share_list=0;
diff --git a/heap/hp_test1.c b/heap/hp_test1.c
new file mode 100644
index 00000000000..848157e831b
--- /dev/null
+++ b/heap/hp_test1.c
@@ -0,0 +1,187 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 heap-database */
+/* Programmet skapar en heap-databas. Till denna skrivs ett antal poster.
+ Databasen st{ngs. D{refter |ppnas den p} nytt och en del av posterna
+ raderas.
+*/
+
+#include <global.h>
+#include <my_sys.h>
+#include <m_string.h>
+#include "heap.h"
+
+static int get_options(int argc, char *argv[]);
+
+static int flag=0,verbose=0,remove_ant=0,flags[50];
+
+int main(int argc, char **argv)
+{
+ int i,j,error,deleted;
+ HP_INFO *file;
+ char record[128],key[32];
+ const char *filename;
+ HP_KEYDEF keyinfo[10];
+ HP_KEYSEG keyseg[4];
+ MY_INIT(argv[0]);
+
+ filename= "test1";
+ get_options(argc,argv);
+
+ keyinfo[0].keysegs=1;
+ keyinfo[0].seg=keyseg;
+ keyinfo[0].seg[0].type=HA_KEYTYPE_BINARY;
+ keyinfo[0].seg[0].start=1;
+ keyinfo[0].seg[0].length=6;
+ keyinfo[0].flag = HA_NOSAME;
+
+ deleted=0;
+ bzero((gptr) flags,sizeof(flags));
+
+ printf("- Creating heap-file\n");
+ heap_create(filename);
+ if (!(file=heap_open(filename,2,1,keyinfo,30,(ulong) flag*100000l,10l)))
+ goto err;
+ printf("- Writing records:s\n");
+ strmov(record," ..... key ");
+
+ for (i=49 ; i>=1 ; i-=2 )
+ {
+ j=i%25 +1;
+ sprintf(key,"%6d",j);
+ bmove(record+1,key,6);
+ error=heap_write(file,record);
+ if (heap_check_heap(file))
+ {
+ puts("Heap keys crashed");
+ goto err;
+ }
+ flags[j]=1;
+ if (verbose || error) printf("J= %2d heap_write: %d my_errno: %d\n",
+ j,error,my_errno);
+ }
+ if (heap_close(file))
+ goto err;
+ printf("- Reopening file\n");
+ if (!(file=heap_open(filename,2,1,keyinfo,30,(ulong) flag*100000l,10l)))
+ goto err;
+
+ printf("- Removing records\n");
+ for (i=1 ; i<=10 ; i++)
+ {
+ if (i == remove_ant) { VOID(heap_close(file)) ; return (0) ; }
+ sprintf(key,"%6d",(j=(int) ((rand() & 32767)/32767.*25)));
+ if ((error = heap_rkey(file,record,0,key)))
+ {
+ if (verbose || (flags[j] == 1 ||
+ (error && my_errno != HA_ERR_KEY_NOT_FOUND)))
+ printf("key: %s rkey: %3d my_errno: %3d\n",key,error,my_errno);
+ }
+ else
+ {
+ error=heap_delete(file,record);
+ if (error || verbose)
+ printf("key: %s delete: %d my_errno: %d\n",key,error,my_errno);
+ flags[j]=0;
+ if (! error)
+ deleted++;
+ }
+ if (heap_check_heap(file))
+ {
+ puts("Heap keys crashed");
+ goto err;
+ }
+ }
+
+ printf("- Reading records with key\n");
+ for (i=1 ; i<=25 ; i++)
+ {
+ sprintf(key,"%6d",i);
+ bmove(record+1,key,6);
+ my_errno=0;
+ error=heap_rkey(file,record,0,key);
+ if (verbose ||
+ (error == 0 && flags[i] != 1) ||
+ (error && (flags[i] != 0 || my_errno != HA_ERR_KEY_NOT_FOUND)))
+ {
+ printf("key: %s rkey: %3d my_errno: %3d record: %s\n",
+ key,error,my_errno,record+1);
+ }
+ }
+
+#ifdef OLD_HEAP_VERSION
+ {
+ int found;
+ printf("- Reading records with position\n");
+ for (i=1,found=0 ; i <= 30 ; i++)
+ {
+ my_errno=0;
+ if ((error=heap_rrnd(file,record,i == 1 ? 0L : (ulong) -1)) ==
+ HA_ERR_END_OF_FILE)
+ {
+ if (found != 25-deleted)
+ printf("Found only %d of %d records\n",found,25-deleted);
+ break;
+ }
+ if (!error)
+ found++;
+ if (verbose || (error != 0 && error != HA_ERR_RECORD_DELETED))
+ {
+ printf("pos: %2d ni_rrnd: %3d my_errno: %3d record: %s\n",
+ i-1,error,my_errno,record+1);
+ }
+ }
+ }
+#endif
+
+ if (heap_close(file) || heap_panic(HA_PANIC_CLOSE))
+ goto err;
+ my_end(MY_GIVE_INFO);
+ return(0);
+err:
+ printf("got error: %d when using heap-database\n",my_errno);
+ return(1);
+} /* main */
+
+
+/* Read options */
+
+static int get_options(int argc, char **argv)
+{
+ char *pos;
+
+ while (--argc >0 && *(pos = *(++argv)) == '-' ) {
+ switch(*++pos) {
+ case 'B': /* Big file */
+ flag=1;
+ break;
+ case 'v': /* verbose */
+ verbose=1;
+ break;
+ case 'm':
+ remove_ant=atoi(++pos);
+ break;
+ case 'V':
+ printf("hp_test1 Ver 3.0 \n");
+ exit(0);
+ case '#':
+ DBUG_PUSH (++pos);
+ break;
+ }
+ }
+ return 0;
+} /* get options */
diff --git a/heap/hp_test2.c b/heap/hp_test2.c
new file mode 100644
index 00000000000..179e2c7c399
--- /dev/null
+++ b/heap/hp_test2.c
@@ -0,0 +1,659 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* Test av isam-databas: stor test */
+
+#ifndef USE_MY_FUNC /* We want to be able to dbug this !! */
+#define USE_MY_FUNC
+#endif
+#ifdef DBUG_OFF
+#undef DBUG_OFF
+#endif
+#ifndef SAFEMALLOC
+#define SAFEMALLOC
+#endif
+
+#include "heapdef.h" /* Because of _hp_find_block */
+#include <signal.h>
+
+#define MAX_RECORDS 100000
+#define MAX_KEYS 3
+
+static int get_options(int argc, char *argv[]);
+static int rnd(int max_value);
+static sig_handler endprog(int sig_number);
+
+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 calc_check(byte *buf,uint length);
+
+ /* Huvudprogrammet */
+
+int main(argc,argv)
+int argc;
+char *argv[];
+{
+ register uint i,j;
+ uint ant,n1,n2,n3;
+ uint reclength,write_count,update,delete,check2,dupp_keys,found_key;
+ int error;
+ ulong pos;
+ unsigned long key_check;
+ char record[128],record2[128],record3[128],key[10];
+ const char *filename,*filename2;
+ HP_INFO *file,*file2;
+ HP_KEYDEF keyinfo[MAX_KEYS];
+ HP_KEYSEG keyseg[MAX_KEYS*5];
+ HEAP_PTR position;
+ MY_INIT(argv[0]); /* init my_sys library & pthreads */
+
+ filename= "test2";
+ filename2= "test2_2";
+ file=file2=0;
+ get_options(argc,argv);
+ reclength=37;
+
+ write_count=update=delete=0;
+ key_check=0;
+
+ keyinfo[0].seg=keyseg;
+ keyinfo[0].keysegs=1;
+ keyinfo[0].flag= 0;
+ keyinfo[0].seg[0].type=HA_KEYTYPE_BINARY;
+ keyinfo[0].seg[0].start=0;
+ keyinfo[0].seg[0].length=6;
+ 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[1].type=HA_KEYTYPE_TEXT;
+ keyinfo[1].seg[1].start=0; /* Tv}delad nyckel */
+ keyinfo[1].seg[1].length=6;
+ 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;
+
+ bzero((char*) key1,sizeof(key1));
+ bzero((char*) key3,sizeof(key3));
+
+ printf("- Creating heap-file\n");
+ if (heap_create(filename))
+ goto err;
+ if (!(file=heap_open(filename,2,keys,keyinfo,reclength,(ulong) flag*100000L,
+ (ulong) recant/2)))
+ goto err;
+ signal(SIGINT,endprog);
+
+ printf("- Writing records:s\n");
+ strmov(record," ..... key");
+
+ 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);
+
+ if (heap_write(file,record))
+ {
+ if (my_errno != HA_ERR_FOUND_DUPP_KEY || key3[n3] == 0)
+ {
+ printf("Error: %d in write at record: %d\n",my_errno,i);
+ goto err;
+ }
+ if (verbose) printf(" Double key: %d\n",n3);
+ }
+ else
+ {
+ if (key3[n3] == 1)
+ {
+ printf("Error: Didn't get error when writing second key: '%8d'\n",n3);
+ goto err;
+ }
+ write_count++; key1[n1]++; key3[n3]=1;
+ key_check+=n1;
+ }
+ if (testflag == 1 && heap_check_heap(file))
+ {
+ puts("Heap keys crashed");
+ goto err;
+ }
+ }
+ if (testflag == 1)
+ goto end;
+ if (heap_check_heap(file))
+ {
+ puts("Heap keys crashed");
+ goto err;
+ }
+
+ printf("- Delete\n");
+ for (i=0 ; i < write_count/10 ; i++)
+ {
+ for (j=rnd(1000)+1 ; j>0 && key1[j] == 0 ; j--) ;
+ if (j != 0)
+ {
+ sprintf(key,"%6d",j);
+ if (heap_rkey(file,record,0,key))
+ {
+ printf("can't find key1: \"%s\"\n",key);
+ goto err;
+ }
+#ifdef NOT_USED
+ if (file->current_ptr == _hp_find_block(&file->s->block,0) ||
+ file->current_ptr == _hp_find_block(&file->s->block,1))
+ continue; /* Don't remove 2 first records */
+#endif
+ if (heap_delete(file,record))
+ {
+ printf("error: %d; can't delete record: \"%s\"\n", my_errno,record);
+ goto err;
+ }
+ delete++;
+ key1[atoi(record+keyinfo[0].seg[0].start)]--;
+ key3[atoi(record+keyinfo[2].seg[0].start)]=0;
+ key_check-=atoi(record);
+ if (testflag == 2 && heap_check_heap(file))
+ {
+ puts("Heap keys crashed");
+ goto err;
+ }
+ }
+ else
+ puts("Warning: Skipping delete test because no dupplicate keys");
+ }
+ if (testflag==2) goto end;
+ if (heap_check_heap(file))
+ {
+ puts("Heap keys crashed");
+ goto err;
+ }
+
+ printf("- Update\n");
+ 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);
+ if (rnd(2) == 1)
+ {
+ if (heap_scan_init(file))
+ goto err;
+ j=rnd(write_count-delete);
+ while ((error=heap_scan(file,record) == HA_ERR_RECORD_DELETED) ||
+ (!error && j))
+ {
+ if (!error)
+ j--;
+ }
+ if (error)
+ goto err;
+ }
+ else
+ {
+ for (j=rnd(1000)+1 ; j>0 && key1[j] == 0 ; j--) ;
+ if (!key1[j])
+ continue;
+ sprintf(key,"%6d",j);
+ if (heap_rkey(file,record,0,key))
+ {
+ printf("can't find key1: \"%s\"\n",key);
+ goto err;
+ }
+ }
+ if (heap_update(file,record,record2))
+ {
+ if (my_errno != HA_ERR_FOUND_DUPP_KEY || key3[n3] == 0)
+ {
+ printf("error: %d; can't uppdate:\nFrom: \"%s\"\nTo: \"%s\"\n",
+ my_errno,record,record2);
+ goto err;
+ }
+ if (verbose)
+ printf("Double key when tryed to uppdate:\nFrom: \"%s\"\nTo: \"%s\"\n",record,record2);
+ }
+ else
+ {
+ key1[atoi(record+keyinfo[0].seg[0].start)]--;
+ key3[atoi(record+keyinfo[2].seg[0].start)]=0;
+ key1[n1]++; key3[n3]=1;
+ update++;
+ key_check=key_check-atoi(record)+n1;
+ }
+ if (testflag == 3 && heap_check_heap(file))
+ {
+ puts("Heap keys crashed");
+ goto err;
+ }
+ }
+ if (testflag == 3) goto end;
+ if (heap_check_heap(file))
+ {
+ puts("Heap keys crashed");
+ goto err;
+ }
+
+ for (i=999, dupp_keys=found_key=0 ; i>0 ; i--)
+ {
+ if (key1[i] > dupp_keys) { dupp_keys=key1[i]; found_key=i; }
+ sprintf(key,"%6d",found_key);
+ }
+
+ if (dupp_keys > 3)
+ {
+ if (!silent)
+ printf("- Read first key - next - delete - next -> last\n");
+ DBUG_PRINT("progpos",("first - next - delete - next -> last"));
+
+ if (heap_rkey(file,record,0,key))
+ goto err;
+ if (heap_rnext(file,record3)) goto err;
+ if (heap_delete(file,record3)) goto err;
+ key_check-=atoi(record3);
+ key1[atoi(record+keyinfo[0].seg[0].start)]--;
+ key3[atoi(record+keyinfo[2].seg[0].start)]=0;
+ delete++;
+ ant=2;
+ while ((error=heap_rnext(file,record3)) == 0 ||
+ error == HA_ERR_RECORD_DELETED)
+ if (! error)
+ ant++;
+ if (ant != dupp_keys)
+ {
+ printf("next: I can only find: %d records of %d\n",
+ ant,dupp_keys);
+ goto end;
+ }
+ dupp_keys--;
+ if (heap_check_heap(file))
+ {
+ puts("Heap keys crashed");
+ goto err;
+ }
+
+ if (!silent)
+ printf("- Read last key - delete - prev - prev - delete - prev -> first\n");
+
+ if (heap_rlast(file,record3)) goto err;
+ if (heap_delete(file,record3)) goto err;
+ key_check-=atoi(record3);
+ key1[atoi(record+keyinfo[0].seg[0].start)]--;
+ key3[atoi(record+keyinfo[2].seg[0].start)]=0;
+ delete++;
+ if (heap_rprev(file,record3) || heap_rprev(file,record3))
+ goto err;
+ if (heap_delete(file,record3)) goto err;
+ key_check-=atoi(record3);
+ key1[atoi(record+keyinfo[0].seg[0].start)]--;
+ key3[atoi(record+keyinfo[2].seg[0].start)]=0;
+ delete++;
+ ant=3;
+ while ((error=heap_rprev(file,record3)) == 0 ||
+ error == HA_ERR_RECORD_DELETED)
+ {
+ if (! error)
+ ant++;
+ }
+ if (ant != dupp_keys)
+ {
+ printf("next: I can only find: %d records of %d\n",
+ ant,dupp_keys);
+ goto end;
+ }
+ dupp_keys-=2;
+ if (heap_check_heap(file))
+ {
+ puts("Heap keys crashed");
+ goto err;
+ }
+ }
+ else
+ puts("Warning: Not enough duplicated keys: Skipping delete key check");
+
+ if (!silent)
+ printf("- Read (first) - next - delete - next -> last\n");
+ DBUG_PRINT("progpos",("first - next - delete - next -> last"));
+
+ if (heap_scan_init(file))
+ goto err;
+ while ((error=heap_scan(file,record3) == HA_ERR_RECORD_DELETED)) ;
+ if (error)
+ goto err;
+ if (heap_delete(file,record3)) goto err;
+ key_check-=atoi(record3);
+ delete++;
+ key1[atoi(record+keyinfo[0].seg[0].start)]--;
+ key3[atoi(record+keyinfo[2].seg[0].start)]=0;
+ ant=0;
+ while ((error=heap_scan(file,record3)) == 0 ||
+ error == HA_ERR_RECORD_DELETED)
+ if (! error)
+ ant++;
+ if (ant != write_count-delete)
+ {
+ printf("next: Found: %d records of %d\n",ant,write_count-delete);
+ goto end;
+ }
+ if (heap_check_heap(file))
+ {
+ puts("Heap keys crashed");
+ goto err;
+ }
+
+ puts("- Test if: Read rrnd - same - rkey - same");
+ DBUG_PRINT("progpos",("Read rrnd - same"));
+ pos=rnd(write_count-delete-5)+5;
+ heap_scan_init(file);
+ i=5;
+ while ((error=heap_scan(file,record)) == HA_ERR_RECORD_DELETED ||
+ (error == 0 && pos))
+ {
+ if (!error)
+ pos--;
+ if (i-- == 0)
+ {
+ bmove(record3,record,reclength);
+ position=heap_position(file);
+ }
+ }
+ if (error)
+ goto err;
+ bmove(record2,record,reclength);
+ if (heap_rsame(file,record,-1) || heap_rsame(file,record2,2))
+ goto err;
+ if (bcmp(record2,record,reclength))
+ {
+ puts("heap_rsame didn't find right record");
+ goto end;
+ }
+
+ puts("- Test of read through position");
+ if (heap_rrnd(file,record,position))
+ goto err;
+ if (bcmp(record3,record,reclength))
+ {
+ puts("heap_frnd didn't find right record");
+ goto end;
+ }
+
+ printf("- heap_info\n");
+ {
+ HEAPINFO info;
+ heap_info(file,&info,0);
+ /* We have to test with delete +1 as this may be the case if the last
+ inserted row was a duplicate key */
+ if (info.records != write_count-delete ||
+ (info.deleted != delete && info.deleted != delete+1))
+ {
+ puts("Wrong info from heap_info");
+ printf("Got: records: %ld(%d) deleted: %ld(%d)\n",
+ info.records,write_count-delete,info.deleted,delete);
+ }
+ }
+
+#ifdef OLD_HEAP_VERSION
+ {
+ uint check;
+ printf("- Read through all records with rnd\n");
+ if (heap_extra(file,HA_EXTRA_RESET) || heap_extra(file,HA_EXTRA_CACHE))
+ {
+ puts("got error from heap_extra");
+ goto end;
+ }
+ ant=check=0;
+ while ((error=heap_rrnd(file,record,(ulong) -1)) != HA_ERR_END_OF_FILE &&
+ ant < write_count + 10)
+ {
+ if (!error)
+ {
+ ant++;
+ check+=calc_check(record,reclength);
+ }
+ }
+ if (ant != write_count-delete)
+ {
+ printf("rrnd: I can only find: %d records of %d\n", ant,
+ write_count-delete);
+ goto end;
+ }
+ if (heap_extra(file,HA_EXTRA_NO_CACHE))
+ {
+ puts("got error from heap_extra(HA_EXTRA_NO_CACHE)");
+ goto end;
+ }
+ }
+#endif
+
+ printf("- Read through all records with scan\n");
+ if (heap_extra(file,HA_EXTRA_RESET) || heap_extra(file,HA_EXTRA_CACHE))
+ {
+ puts("got error from heap_extra");
+ goto end;
+ }
+ ant=check2=0;
+ heap_scan_init(file);
+ while ((error=heap_scan(file,record)) != HA_ERR_END_OF_FILE &&
+ ant < write_count + 10)
+ {
+ if (!error)
+ {
+ ant++;
+ check2+=calc_check(record,reclength);
+ }
+ }
+ if (ant != write_count-delete)
+ {
+ printf("scan: I can only find: %d records of %d\n", ant,
+ write_count-delete);
+ goto end;
+ }
+#ifdef OLD_HEAP_VERSION
+ if (check != check2)
+ {
+ puts("scan: Checksum didn't match reading with rrnd");
+ goto end;
+ }
+#endif
+
+
+ if (heap_extra(file,HA_EXTRA_NO_CACHE))
+ {
+ puts("got error from heap_extra(HA_EXTRA_NO_CACHE)");
+ goto end;
+ }
+
+ for (i=999, dupp_keys=found_key=0 ; i>0 ; i--)
+ {
+ if (key1[i] > dupp_keys) { dupp_keys=key1[i]; found_key=i; }
+ sprintf(key,"%6d",found_key);
+ }
+ printf("- Read through all keys with first-next-last-prev\n");
+ ant=0;
+ for (error=heap_rkey(file,record,0,key) ;
+ ! error ;
+ error=heap_rnext(file,record))
+ ant++;
+ if (ant != dupp_keys)
+ {
+ printf("first-next: I can only find: %d records of %d\n", ant,
+ dupp_keys);
+ goto end;
+ }
+
+ ant=0;
+ for (error=heap_rlast(file,record) ;
+ ! error ;
+ error=heap_rprev(file,record))
+ {
+ ant++;
+ check2+=calc_check(record,reclength);
+ }
+ if (ant != dupp_keys)
+ {
+ printf("last-prev: I can only find: %d records of %d\n", ant,
+ dupp_keys);
+ goto end;
+ }
+
+ if (testflag == 4) goto end;
+
+ printf("- Reading through all rows through keys\n");
+ if (!(file2=heap_open(filename,2,0,0,0,0,0)))
+ goto err;
+ if (heap_scan_init(file))
+ goto err;
+ while ((error=heap_scan(file,record)) != HA_ERR_END_OF_FILE)
+ {
+ if (error == 0)
+ {
+ if (heap_rkey(file2,record2,2,record+keyinfo[2].seg[0].start))
+ {
+ printf("can't find key3: \"%.8s\"\n",
+ record+keyinfo[2].seg[0].start);
+ goto err;
+ }
+ }
+ }
+ heap_close(file2);
+
+ printf("- Creating output heap-file 2\n");
+ if (!(file2=heap_open(filename2,2,1,keyinfo,reclength,0L,0L)))
+ goto err;
+
+ printf("- Copying and removing records\n");
+ if (heap_scan_init(file))
+ goto err;
+ while ((error=heap_scan(file,record)) != HA_ERR_END_OF_FILE)
+ {
+ if (error == 0)
+ {
+ if (heap_write(file2,record))
+ goto err;
+ key_check-=atoi(record);
+ write_count++;
+ if (heap_delete(file,record))
+ goto err;
+ delete++;
+ }
+ pos++;
+ }
+ if (heap_check_heap(file) || heap_check_heap(file2))
+ {
+ puts("Heap keys crashed");
+ goto err;
+ }
+
+ if (my_errno != HA_ERR_END_OF_FILE)
+ printf("error: %d from heap_rrnd\n",my_errno);
+ if (key_check)
+ printf("error: Some read got wrong: check is %ld\n",(long) key_check);
+
+end:
+ printf("\nFollowing test have been made:\n");
+ printf("Write records: %d\nUpdate records: %d\nDelete records: %d\n", write_count,update,delete);
+ heap_clear(file);
+ if (heap_close(file) || (file2 && heap_close(file2)))
+ goto err;
+ heap_delete_all(filename2);
+ heap_panic(HA_PANIC_CLOSE);
+ my_end(MY_GIVE_INFO);
+ return(0);
+err:
+ printf("Got error: %d when using heap-database\n",my_errno);
+ VOID(heap_close(file));
+ return(1);
+} /* main */
+
+
+ /* Read options */
+
+static int get_options(int argc,char *argv[])
+{
+ char *pos,*progname;
+ DEBUGGER_OFF;
+
+ progname= argv[0];
+
+ while (--argc >0 && *(pos = *(++argv)) == '-' ) {
+ switch(*++pos) {
+ case 'B': /* Big file */
+ flag=1;
+ break;
+ case 'v': /* verbose */
+ verbose=1;
+ break;
+ case 'm': /* records */
+ recant=atoi(++pos);
+ break;
+ case 's':
+ silent=1;
+ break;
+ case 't':
+ testflag=atoi(++pos); /* testmod */
+ break;
+ case 'V':
+ case 'I':
+ case '?':
+ printf("%s Ver 1.1 for %s at %s\n",progname,SYSTEM_TYPE,MACHINE_TYPE);
+ puts("TCX Datakonsult AB, by Monty, for your professional use\n");
+ printf("Usage: %s [-?ABIKLsWv] [-m#] [-t#]\n",progname);
+ exit(0);
+ case '#':
+ DEBUGGER_ON;
+ DBUG_PUSH (++pos);
+ break;
+ }
+ }
+ return 0;
+} /* get options */
+
+ /* Generate a random value in intervall 0 <=x <= n */
+
+static int rnd(max_value)
+int max_value;
+{
+ return (int) ((rand() & 32767)/32767.0*max_value);
+} /* rnd */
+
+
+static sig_handler endprog(int sig_number __attribute__((unused)))
+{
+#ifndef THREAD
+ if (my_dont_interrupt)
+ my_remember_signal(sig_number,endprog);
+ else
+#endif
+ {
+ heap_panic(HA_PANIC_CLOSE);
+ my_end(1);
+ exit(1);
+ }
+}
+
+static int calc_check(buf,length)
+byte *buf;
+uint length;
+{
+ int check=0;
+ while (length--)
+ check+= (int) (uchar) *(buf++);
+ return check;
+}
diff --git a/heap/hp_update.c b/heap/hp_update.c
new file mode 100644
index 00000000000..5eb4562ca5c
--- /dev/null
+++ b/heap/hp_update.c
@@ -0,0 +1,67 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 current record in heap-database */
+
+#include "heapdef.h"
+
+int heap_update(HP_INFO *info, const byte *old, const byte *new)
+{
+ uint key;
+ byte *pos;
+ HP_SHARE *share=info->s;
+ DBUG_ENTER("heap_update");
+
+ test_active(info);
+ pos=info->current_ptr;
+
+ if (info->opt_flag & READ_CHECK_USED && _hp_rectest(info,old))
+ DBUG_RETURN(my_errno); /* Record changed */
+ if (--(share->records) < share->blength >> 1) share->blength>>= 1;
+ share->changed=1;
+
+ for (key=0 ; key < share->keys ; key++)
+ {
+ if (_hp_rec_key_cmp(share->keydef+key,old,new))
+ {
+ if (_hp_delete_key(info,share->keydef+key,old,pos,key ==
+ (uint) info->lastinx) ||
+ _hp_write_key(share,share->keydef+key,new,pos))
+ goto err;
+ }
+ }
+
+ memcpy(pos,new,(size_t) share->reclength);
+ if (++(share->records) == share->blength) share->blength+= share->blength;
+ DBUG_RETURN(0);
+
+ err:
+ if (my_errno == HA_ERR_FOUND_DUPP_KEY)
+ {
+ info->errkey=key;
+ do
+ {
+ if (_hp_rec_key_cmp(share->keydef+key,old,new))
+ {
+ if (_hp_delete_key(info,share->keydef+key,new,pos,0) ||
+ _hp_write_key(share,share->keydef+key,old,pos))
+ break;
+ }
+ } while (key-- > 0);
+ }
+ if (++(share->records) == share->blength) share->blength+= share->blength;
+ DBUG_RETURN(my_errno);
+} /* heap_update */
diff --git a/heap/hp_write.c b/heap/hp_write.c
new file mode 100644
index 00000000000..e74183276f7
--- /dev/null
+++ b/heap/hp_write.c
@@ -0,0 +1,275 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 record to heap-databas */
+
+#include "heapdef.h"
+#ifdef __WIN__
+#include <fcntl.h>
+#endif
+
+#define LOWFIND 1
+#define LOWUSED 2
+#define HIGHFIND 4
+#define HIGHUSED 8
+
+static byte *next_free_record_pos(HP_SHARE *info);
+static HASH_INFO *_hp_find_free_hash(HP_SHARE *info, HP_BLOCK *block,
+ ulong records);
+
+int heap_write(HP_INFO *info, const byte *record)
+{
+ uint key;
+ byte *pos;
+ HP_SHARE *share=info->s;
+ DBUG_ENTER("heap_write");
+
+#ifndef DBUG_OFF
+ if (info->mode && O_RDONLY)
+ {
+ DBUG_RETURN(my_errno=EACCES);
+ }
+#endif
+ if (!(pos=next_free_record_pos(share)))
+ DBUG_RETURN(my_errno);
+ share->changed=1;
+
+ for (key=0 ; key < share->keys ; key++)
+ {
+ if (_hp_write_key(share,share->keydef+key,record,pos))
+ goto err;
+ }
+
+ memcpy(pos,record,(size_t) share->reclength);
+ pos[share->reclength]=1; /* Mark record as not deleted */
+ if (++share->records == share->blength)
+ share->blength+= share->blength;
+ info->current_ptr=pos;
+ info->current_hash_ptr=0;
+ info->update|=HA_STATE_AKTIV;
+ DBUG_RETURN(0);
+err:
+ info->errkey= key;
+ do
+ {
+ if (_hp_delete_key(info,share->keydef+key,record,pos,0))
+ break;
+ } while (key-- > 0);
+
+ share->deleted++;
+ *((byte**) pos)=share->del_link;
+ share->del_link=pos;
+ pos[share->reclength]=0; /* Record deleted */
+ DBUG_RETURN(my_errno);
+} /* heap_write */
+
+
+ /* Find where to place new record */
+
+static byte *next_free_record_pos(HP_SHARE *info)
+{
+ int block_pos;
+ byte *pos;
+ ulong length;
+ DBUG_ENTER("next_free_record_pos");
+
+ if (info->del_link)
+ {
+ pos=info->del_link;
+ info->del_link= *((byte**) pos);
+ info->deleted--;
+ DBUG_PRINT("exit",("Used old position: %lx",pos));
+ DBUG_RETURN(pos);
+ }
+ if (!(block_pos=(info->records % info->block.records_in_block)))
+ {
+ if (info->records > info->max_records && info->max_records)
+ {
+ my_errno=HA_ERR_RECORD_FILE_FULL;
+ DBUG_RETURN(NULL);
+ }
+ if (_hp_get_new_block(&info->block,&length))
+ DBUG_RETURN(NULL);
+ info->data_length+=length;
+ }
+ DBUG_PRINT("exit",("Used new position: %lx",
+ (byte*) info->block.level_info[0].last_blocks+block_pos*
+ info->block.recbuffer));
+ DBUG_RETURN((byte*) info->block.level_info[0].last_blocks+
+ block_pos*info->block.recbuffer);
+}
+
+
+ /* Write a hash-key to the hash-index */
+
+int _hp_write_key(register HP_SHARE *info, HP_KEYDEF *keyinfo,
+ const byte *record, byte *recpos)
+{
+ int flag;
+ ulong halfbuff,hashnr,first_index;
+ byte *ptr_to_rec,*ptr_to_rec2;
+ HASH_INFO *empty,*gpos,*gpos2,*pos;
+ DBUG_ENTER("hp_write_key");
+
+ LINT_INIT(gpos); LINT_INIT(gpos2);
+ LINT_INIT(ptr_to_rec); LINT_INIT(ptr_to_rec2);
+
+ flag=0;
+ if (!(empty= _hp_find_free_hash(info,&keyinfo->block,info->records)))
+ DBUG_RETURN(-1); /* No more memory */
+ halfbuff= (long) info->blength >> 1;
+ pos= hp_find_hash(&keyinfo->block,(first_index=info->records-halfbuff));
+
+ if (pos != empty) /* If some records */
+ {
+ do
+ {
+ hashnr=_hp_rec_hashnr(keyinfo,pos->ptr_to_rec);
+ if (flag == 0) /* First loop; Check if ok */
+ if (_hp_mask(hashnr,info->blength,info->records) != first_index)
+ break;
+ if (!(hashnr & halfbuff))
+ { /* Key will not move */
+ if (!(flag & LOWFIND))
+ {
+ if (flag & HIGHFIND)
+ {
+ flag=LOWFIND | HIGHFIND;
+ /* key shall be moved to the current empty position */
+ gpos=empty;
+ ptr_to_rec=pos->ptr_to_rec;
+ empty=pos; /* This place is now free */
+ }
+ else
+ {
+ flag=LOWFIND | LOWUSED; /* key isn't changed */
+ gpos=pos;
+ ptr_to_rec=pos->ptr_to_rec;
+ }
+ }
+ else
+ {
+ if (!(flag & LOWUSED))
+ {
+ /* Change link of previous LOW-key */
+ gpos->ptr_to_rec=ptr_to_rec;
+ gpos->next_key=pos;
+ flag= (flag & HIGHFIND) | (LOWFIND | LOWUSED);
+ }
+ gpos=pos;
+ ptr_to_rec=pos->ptr_to_rec;
+ }
+ }
+ else
+ { /* key will be moved */
+ if (!(flag & HIGHFIND))
+ {
+ flag= (flag & LOWFIND) | HIGHFIND;
+ /* key shall be moved to the last (empty) position */
+ gpos2 = empty; empty=pos;
+ ptr_to_rec2=pos->ptr_to_rec;
+ }
+ else
+ {
+ if (!(flag & HIGHUSED))
+ {
+ /* Change link of previous hash-key and save */
+ gpos2->ptr_to_rec=ptr_to_rec2;
+ gpos2->next_key=pos;
+ flag= (flag & LOWFIND) | (HIGHFIND | HIGHUSED);
+ }
+ gpos2=pos;
+ ptr_to_rec2=pos->ptr_to_rec;
+ }
+ }
+ }
+ while ((pos=pos->next_key));
+
+ if ((flag & (LOWFIND | LOWUSED)) == LOWFIND)
+ {
+ gpos->ptr_to_rec=ptr_to_rec;
+ gpos->next_key=0;
+ }
+ if ((flag & (HIGHFIND | HIGHUSED)) == HIGHFIND)
+ {
+ gpos2->ptr_to_rec=ptr_to_rec2;
+ gpos2->next_key=0;
+ }
+ }
+ /* Check if we are at the empty position */
+
+ pos=hp_find_hash(&keyinfo->block,_hp_mask(_hp_rec_hashnr(keyinfo,record),
+ info->blength,info->records+1));
+ if (pos == empty)
+ {
+ pos->ptr_to_rec=recpos;
+ pos->next_key=0;
+ }
+ else
+ {
+ /* Check if more records in same hash-nr family */
+ empty[0]=pos[0];
+ gpos=hp_find_hash(&keyinfo->block,
+ _hp_mask(_hp_rec_hashnr(keyinfo,pos->ptr_to_rec),
+ info->blength,info->records+1));
+ if (pos == gpos)
+ {
+ pos->ptr_to_rec=recpos;
+ pos->next_key=empty;
+ }
+ else
+ {
+ pos->ptr_to_rec=recpos;
+ pos->next_key=0;
+ _hp_movelink(pos,gpos,empty);
+ }
+
+ /* Check if dupplicated keys */
+ if ((keyinfo->flag & HA_NOSAME) && pos == gpos)
+ {
+ pos=empty;
+ do
+ {
+ if (! _hp_rec_key_cmp(keyinfo,record,pos->ptr_to_rec))
+ {
+ DBUG_RETURN(my_errno=HA_ERR_FOUND_DUPP_KEY);
+ }
+ } while ((pos=pos->next_key));
+ }
+ }
+ DBUG_RETURN(0);
+}
+
+ /* Returns ptr to block, and allocates block if neaded */
+
+static HASH_INFO *_hp_find_free_hash(HP_SHARE *info,
+ HP_BLOCK *block, ulong records)
+{
+ uint block_pos;
+ ulong length;
+
+ if (records < block->last_allocated)
+ return hp_find_hash(block,records);
+ if (!(block_pos=(records % block->records_in_block)))
+ {
+ if (_hp_get_new_block(block,&length))
+ return(NULL);
+ info->index_length+=length;
+ }
+ block->last_allocated=records+1;
+ return((HASH_INFO*) ((byte*) block->level_info[0].last_blocks+
+ block_pos*block->recbuffer));
+}
diff --git a/heap/make-ccc b/heap/make-ccc
new file mode 100755
index 00000000000..192647298ad
--- /dev/null
+++ b/heap/make-ccc
@@ -0,0 +1,4 @@
+ccc -I./../include -I../include -DDBUG_OFF -fast -O3 -c _check.c _rectest.c hp_block.c hp_clear.c hp_close.c hp_create.c hp_delete.c hp_extra.c hp_hash.c hp_info.c hp_open.c hp_panic.c hp_rename.c hp_rfirst.c hp_rkey.c hp_rlast.c hp_rnext.c hp_rprev.c hp_rrnd.c hp_rsame.c hp_scan.c hp_static.c hp_update.c hp_write.c
+rm libheap.a
+ar -cr libheap.a _check.o
+
diff --git a/include/.cvsignore b/include/.cvsignore
new file mode 100644
index 00000000000..fc53b1b5f65
--- /dev/null
+++ b/include/.cvsignore
@@ -0,0 +1,4 @@
+Makefile
+Makefile.in
+my_config.h
+mysql_version.h
diff --git a/include/Attic/config-win32.h b/include/Attic/config-win32.h
new file mode 100755
index 00000000000..e441749e038
--- /dev/null
+++ b/include/Attic/config-win32.h
@@ -0,0 +1,247 @@
+/* Defines for Win32 to make it compatible for MySQL */
+
+#include <sys/locking.h>
+#include <windows.h>
+#include <math.h> /* Because of rint() */
+#include <fcntl.h>
+#include <io.h>
+#include <malloc.h>
+
+#ifdef __NT__
+#define SYSTEM_TYPE "NT"
+#else
+#define SYSTEM_TYPE "Win95/Win98"
+#endif
+#define MACHINE_TYPE "i586" /* Define to machine type name */
+#ifndef __WIN32__
+#define __WIN32__ /* To make it easier in VC++ */
+#endif
+
+/* File and lock constants */
+#define O_SHARE 0x1000 /* Open file in sharing mode */
+#ifdef __BORLANDC__
+#define F_RDLCK LK_NBLCK /* read lock */
+#define F_WRLCK LK_NBRLCK /* write lock */
+#define F_UNLCK LK_UNLCK /* remove lock(s) */
+#else
+#define F_RDLCK _LK_NBLCK /* read lock */
+#define F_WRLCK _LK_NBRLCK /* write lock */
+#define F_UNLCK _LK_UNLCK /* remove lock(s) */
+#endif
+
+#define F_EXCLUSIVE 1 /* We have only exclusive locking */
+#define F_TO_EOF (INT_MAX32/2) /* size for lock of all file */
+#define F_OK 0 /* parameter to access() */
+
+#define S_IROTH S_IREAD /* for my_lib */
+
+#ifdef __BORLANDC__
+#define FILE_BINARY O_BINARY /* my_fopen in binary mode */
+#define O_TEMPORARY 0
+#define O_SHORT_LIVED 0
+#define SH_DENYNO _SH_DENYNO
+#else
+#define O_BINARY _O_BINARY /* compability with MSDOS */
+#define FILE_BINARY _O_BINARY /* my_fopen in binary mode */
+#define O_TEMPORARY _O_TEMPORARY
+#define O_SHORT_LIVED _O_SHORT_LIVED
+#define SH_DENYNO _SH_DENYNO
+#endif
+#define NO_OPEN_3 /* For my_create() */
+
+#define SIGQUIT SIGTERM /* No SIGQUIT */
+
+#undef _REENTRANT /* Crashes something for win32 */
+
+#define LONGLONG_MIN ((__int64) 0x8000000000000000)
+#define LONGLONG_MAX ((__int64) 0x7FFFFFFFFFFFFFFF)
+#define LL(A) ((__int64) A)
+
+/* Type information */
+
+typedef unsigned short ushort;
+typedef unsigned int uint;
+typedef unsigned int size_t;
+typedef unsigned __int64 ulonglong; /* Microsofts 64 bit types */
+typedef __int64 longlong;
+typedef int sigset_t;
+#define longlong_defined
+/* off_t should not be __int64 because of conflicts in header files;
+ Use my_off_t or os_off_t instead */
+typedef long off_t;
+typedef __int64 os_off_t;
+
+#define Socket_defined
+#define my_socket SOCKET
+#define bool BOOL
+#define SIGPIPE SIGINT
+#define RETQSORTTYPE void
+#define QSORT_TYPE_IS_VOID
+#define RETSIGTYPE void
+#define SOCKET_SIZE_TYPE int
+#define my_socket_defined
+#define bool_defined
+#define byte_defined
+#define HUGE_PTR
+#define STDCALL __stdcall /* Used by libmysql.dll */
+
+#ifndef UNDEF_THREAD_HACK
+#define THREAD
+#endif
+#define VOID_SIGHANDLER
+#define SIZEOF_CHAR 1
+#define SIZEOF_LONG 4
+#define SIZEOF_LONG_LONG 8
+#define SIZEOF_OFF_T 8
+#define HAVE_BROKEN_NETINET_INCLUDES
+#ifdef __NT__
+#define HAVE_NAMED_PIPE /* We can only create pipes on NT */
+#endif
+
+/* Convert some simple functions to Posix */
+
+#define sigset(A,B) signal((A),(B))
+#define finite(A) _finite(A)
+#define sleep(A) Sleep((A)*1000)
+
+#ifndef __BORLANDC__
+#define access(A,B) _access(A,B)
+#endif
+
+#if defined(__cplusplus)
+
+inline double rint(double nr)
+{
+ double f = floor(nr);
+ double c = ceil(nr);
+ return (((c-nr) >= (nr-f)) ? f :c);
+}
+
+inline double ulonglong2double(ulonglong value)
+{
+ longlong nr=(longlong) value;
+ if (nr >= 0)
+ return (double) nr;
+ return (18446744073709551616.0 + (double) nr);
+}
+
+#define my_off_t2double(A) ulonglong2double(A)
+#else
+#define inline __inline
+#endif
+
+#if SIZEOF_OFF_T > 4
+#define lseek(A,B,C) _lseeki64((A),(longlong) (B),(C))
+#define tell(A) _telli64(A)
+#endif
+
+#define STACK_DIRECTION -1
+
+/* Optimized store functions for Intel x86 */
+
+#define sint2korr(A) (*((int16 *) (A)))
+#define sint3korr(A) ((int32) ((((uchar) (A)[2]) & 128) ? \
+ (((uint32) 255L << 24) | \
+ (((uint32) (uchar) (A)[2]) << 16) |\
+ (((uint32) (uchar) (A)[1]) << 8) | \
+ ((uint32) (uchar) (A)[0])) : \
+ (((uint32) (uchar) (A)[2]) << 16) |\
+ (((uint32) (uchar) (A)[1]) << 8) | \
+ ((uint32) (uchar) (A)[0])))
+#define sint4korr(A) (*((long *) (A)))
+#define uint2korr(A) (*((uint16 *) (A)))
+#define uint3korr(A) (long) (*((unsigned long *) (A)) & 0xFFFFFF)
+#define uint4korr(A) (*((unsigned long *) (A)))
+#define uint5korr(A) ((ulonglong)(((uint32) ((uchar) (A)[0])) +\
+ (((uint32) ((uchar) (A)[1])) << 8) +\
+ (((uint32) ((uchar) (A)[2])) << 16) +\
+ (((uint32) ((uchar) (A)[3])) << 24)) +\
+ (((ulonglong) ((uchar) (A)[4])) << 32))
+#define uint8korr(A) (*((ulonglong *) (A)))
+#define sint8korr(A) (*((longlong *) (A)))
+#define int2store(T,A) *((uint16*) (T))= (uint16) (A)
+#define int3store(T,A) { *(T)= (uchar) ((A));\
+ *(T+1)=(uchar) (((uint) (A) >> 8));\
+ *(T+2)=(uchar) (((A) >> 16)); }
+#define int4store(T,A) *((long *) (T))= (long) (A)
+#define int5store(T,A) { *(T)= (uchar)((A));\
+ *((T)+1)=(uchar) (((A) >> 8));\
+ *((T)+2)=(uchar) (((A) >> 16));\
+ *((T)+3)=(uchar) (((A) >> 24)); \
+ *((T)+4)=(uchar) (((A) >> 32)); }
+#define int8store(T,A) *((ulonglong *) (T))= (ulonglong) (A)
+
+#define doubleget(V,M) { *((long *) &V) = *((long*) M); \
+ *(((long *) &V)+1) = *(((long*) M)+1); }
+#define doublestore(T,V) { *((long *) T) = *((long*) &V); \
+ *(((long *) T)+1) = *(((long*) &V)+1); }
+#define float4get(V,M) { *((long *) &(V)) = *((long*) (M)); }
+#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))
+
+
+#define HAVE_PERROR
+#define HAVE_VFPRINT
+#define HAVE_CHSIZE /* System has chsize() function */
+#define HAVE_RENAME /* Have rename() as function */
+#define HAVE_BINARY_STREAMS /* Have "b" flag in streams */
+#define HAVE_LONG_JMP /* Have long jump function */
+#define HAVE_LOCKING /* have locking() call */
+#define HAVE_ERRNO_AS_DEFINE /* errno is a define */
+#define HAVE_STDLIB /* everything is include in this file */
+#define HAVE_MEMCPY
+#define HAVE_MEMMOVE
+#define HAVE_GETCWD
+#define HAVE_TELL
+#define HAVE_TZNAME
+#define HAVE_PUTENV
+#define HAVE_SELECT
+#define HAVE_SETLOCALE
+#define HAVE_SOCKET /* Giangi */
+#define HAVE_FLOAT_H
+#define HAVE_LIMITS_H
+#define HAVE_STDDEF_H
+#define HAVE_RINT /* defined in this file */
+#define NO_FCNTL_NONBLOCK /* No FCNTL */
+#define HAVE_ALLOCA
+#define HAVE_COMPRESS
+
+#ifdef _MSC_VER
+#define HAVE_LDIV /* The optimizer breaks in zortech for ldiv */
+#define HAVE_ANSI_INCLUDE
+#define HAVE_SYS_UTIME_H
+#define HAVE_STRTOUL
+#endif
+#define my_reinterpret_cast(A) reinterpret_cast <A>
+#define my_const_cast(A) const_cast<A>
+
+/* MYSQL OPTIONS */
+
+#ifdef _CUSTOMCONFIG_
+#include <custom_conf.h>
+#else
+#define DEFAULT_MYSQL_HOME "c:\\mysql"
+#define PACKAGE "mysql"
+#define DEFAULT_BASEDIR "C:\\"
+#define SHAREDIR "share\\"
+#define DEFAULT_CHARSET_HOME "C:\\"
+#endif
+
+/* File name handling */
+
+#define FN_LIBCHAR '\\'
+#define FN_ROOTDIR "\\"
+#define FN_NETWORK_DRIVES /* Uses \\ to indicate network drives */
+#define FN_NO_CASE_SENCE /* Files are not case-sensitive */
+#define FN_LOWER_CASE TRUE /* Files are represented in lower case */
+#define MY_NFILE 127 /* This is only used to save filenames */
+
+
+#define thread_safe_increment(V,L) InterlockedIncrement((long*) &(V))
+/* The following is only used for statistics, so it should be good enough */
+#ifdef __NT__ /* This should also work on Win98 but .. */
+#define thread_safe_add(V,C,L) InterlockedExchangeAdd((long*) &(V),(C))
+#else
+#define thread_safe_add(V,C,L) InterlockedExchange((long*) &(V),(V)+(C))
+#endif
diff --git a/include/Attic/m_ctype.h.in b/include/Attic/m_ctype.h.in
new file mode 100644
index 00000000000..ea7782987e3
--- /dev/null
+++ b/include/Attic/m_ctype.h.in
@@ -0,0 +1,231 @@
+/* Copyright (C) 1996 TCX DataKonsult AB & Monty Program KB & Detron HB
+ For a more info consult the file COPYRIGHT distributed with this file */
+/*
+ A better inplementation of the UNIX ctype(3) library.
+ Notes: global.h should be included before ctype.h
+*/
+
+#ifndef _m_ctype_h
+#define _m_ctype_h
+
+#define MY_CHARSET_UNDEFINED 0
+#define MY_CHARSET_BIG5 1
+#define MY_CHARSET_CZECH 2
+#define MY_CHARSET_DEC8 3
+#define MY_CHARSET_DOS 4
+#define MY_CHARSET_GERMAN1 5
+#define MY_CHARSET_HP8 6
+#define MY_CHARSET_KOI8_RU 7
+#define MY_CHARSET_LATIN1 8
+#define MY_CHARSET_LATIN2 9
+#define MY_CHARSET_SWE7 10
+#define MY_CHARSET_USA7 11
+#define MY_CHARSET_UJIS 12
+#define MY_CHARSET_SJIS 13
+#define MY_CHARSET_CP1251 14
+#define MY_CHARSET_DANISH 15
+#define MY_CHARSET_HEBREW 16
+#define MY_CHARSET_WIN1251 17
+#define MY_CHARSET_TIS620 18
+#define MY_CHARSET_EUC_KR 19
+#define MY_CHARSET_ESTONIA 20
+#define MY_CHARSET_HUNGARIAN 21
+#define MY_CHARSET_KOI8_UKR 22
+#define MY_CHARSET_WIN1251UKR 23
+#define MY_CHARSET_GB2312 24
+#define MY_CHARSET_GREEK 25
+#define MY_CHARSET_WIN1250 26
+#define MY_CHARSET_CROAT 27
+#define MY_CHARSET_GBK 28
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __WIN32__
+#include <ctype.h>
+#endif
+/* 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. */
+
+#ifndef CTYPE_LIBRARY
+#define EXT extern
+#define D(x)
+#else
+#define EXT
+#define D(x) = x
+#endif
+
+#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 _B 0100 /* Blank */
+#define _X 0200 /* heXadecimal digit */
+
+extern uchar NEAR ctype_@mystrings_charset@[];
+extern uchar NEAR to_upper_@mystrings_charset@[];
+extern uchar NEAR to_lower_@mystrings_charset@[];
+extern uchar NEAR sort_order_@mystrings_charset@[];
+
+#define my_ctype ctype_@mystrings_charset@
+#define my_to_upper to_upper_@mystrings_charset@
+#define my_to_lower to_lower_@mystrings_charset@
+#define my_sort_order sort_order_@mystrings_charset@
+
+#ifndef __WIN32__
+#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)]
+#define tolower(c) (char) my_to_lower[(uchar) (c)]
+
+#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 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 isascii(c) (!((c) & ~0177))
+#define toascii(c) ((c) & 0177)
+
+#ifdef ctype
+#undef ctype
+#endif /* ctype */
+
+#endif /* __WIN32__ */
+
+/* Some macros that should be cleaned up a little */
+#define isvar(c) (isalnum(c) || (c) == '_')
+#define isvar_start(c) (isalpha(c) || (c) == '_')
+#define tocntrl(c) ((c) & 31)
+#define toprint(c) ((c) | 64)
+
+/* Support for Japanese(UJIS) characters, by tommy@valley.ne.jp */
+#if MY_CHARSET_CURRENT == MY_CHARSET_UJIS
+#define USE_MB
+#define USE_MB_IDENT
+#define isujis(c) ((0xa1<=((c)&0xff) && ((c)&0xff)<=0xfe))
+#define iskata(c) ((0xa1<=((c)&0xff) && ((c)&0xff)<=0xdf))
+#define isujis_ss2(c) (((c)&0xff) == 0x8e)
+#define isujis_ss3(c) (((c)&0xff) == 0x8f)
+#define ismbchar(p, end) ((*(uchar*)(p)<0x80)? 0:\
+ isujis(*(p)) && (end)-(p)>1 && isujis(*((p)+1))? 2:\
+ isujis_ss2(*(p)) && (end)-(p)>1 && iskata(*((p)+1))? 2:\
+ isujis_ss3(*(p)) && (end)-(p)>2 && isujis(*((p)+1)) && isujis(*((p)+2))? 3:\
+ 0)
+#define ismbhead(c) (isujis(c) || isujis_ss2(c) || isujis_ss3(c))
+#define mbcharlen(c) (isujis(c)? 2: isujis_ss2(c)? 2: isujis_ss3(c)? 3: 0)
+#define MBMAXLEN 3
+#endif
+
+/* Support for Japanese(SJIS) characters, by tommy@valley.ne.jp */
+#if MY_CHARSET_CURRENT == MY_CHARSET_SJIS
+#define USE_MB
+#define USE_MB_IDENT
+#define issjishead(c) ((0x81<=((c)&0xff) && ((c)&0xff)<=0x9f) || (0xe0<=((c)&0xff) && ((c)&0xff)<=0xfc))
+#define issjistail(c) ((0x40<=((c)&0xff) && ((c)&0xff)<=0x7e) || (0x80<=((c)&0xff) && ((c)&0xff)<=0xfc))
+#define ismbchar(p, end) (issjishead(*(p)) && (end)-(p)>1 && issjistail(*((p)+1))? 2: 0)
+#define ismbhead(c) issjishead(c)
+#define mbcharlen(c) (issjishead(c)? 2: 0)
+#define MBMAXLEN 2
+#endif
+
+/* Support for Chinese(BIG5) characters, by jou@nematic.ieo.nctu.edu.tw
+ modified by Wei He (hewei@mail.ied.ac.cn) */
+
+#if MY_CHARSET_CURRENT == MY_CHARSET_BIG5
+#define USE_MB
+#define USE_MB_IDENT
+#define isbig5head(c) (0xa1<=(uchar)(c) && (uchar)(c)<=0xf9)
+#define isbig5tail(c) ((0x40<=(uchar)(c) && (uchar)(c)<=0x7e) || \
+ (0xa1<=(uchar)(c) && (uchar)(c)<=0xfe))
+#define ismbchar(p, end) (isbig5head(*(p)) && (end)-(p)>1 && isbig5tail(*((p)+1))? 2: 0)
+#define ismbhead(c) isbig5head(c)
+#define mbcharlen(c) (isbig5head(c)? 2: 0)
+#define MBMAXLEN 2
+#
+#undef USE_STRCOLL
+#define USE_STRCOLL
+#endif
+
+/* Support for Chinese(GB2312) characters, by Miles Tsai (net-bull@126.com)
+ modified by Wei He (hewei@mail.ied.ac.cn) */
+
+#if MY_CHARSET_CURRENT == MY_CHARSET_GB2312
+#define USE_MB
+#define USE_MB_IDENT
+#define isgb2312head(c) (0xa1<=(uchar)(c) && (uchar)(c)<=0xf7)
+#define isgb2312tail(c) (0xa1<=(uchar)(c) && (uchar)(c)<=0xfe)
+#define ismbchar(p, end) (isgb2312head(*(p)) && (end)-(p)>1 && isgb2312tail(*((p)+1))? 2: 0)
+#define ismbhead(c) isgb2312head(c)
+#define mbcharlen(c) (isgb2312head(c)? 2:0)
+#define MBMAXLEN 2
+#endif
+
+/* Support for Chinese(GBK) characters, by hewei@mail.ied.ac.cn */
+
+#if MY_CHARSET_CURRENT == MY_CHARSET_GBK
+#define USE_MB
+#define USE_MB_IDENT
+#define isgbkhead(c) (0x81<=(uchar)(c) && (uchar)(c)<=0xfe)
+#define isgbktail(c) ((0x40<=(uchar)(c) && (uchar)(c)<=0x7e) || \
+ (0x80<=(uchar)(c) && (uchar)(c)<=0xfe))
+#define ismbchar(p, end) (isgbkhead(*(p)) && (end)-(p)>1 && isgbktail(*((p)+1))? 2: 0)
+#define ismbhead(c) isgbkhead(c)
+#define mbcharlen(c) (isgbkhead(c)? 2:0)
+#define MBMAXLEN 2
+#undef USE_STRCOLL
+#define USE_STRCOLL
+#endif
+
+/* Define, how much will the string grow under strxfrm */
+#if MY_CHARSET_CURRENT == MY_CHARSET_CZECH
+#undef USE_STRCOLL
+#define USE_STRCOLL
+#endif
+#if MY_CHARSET_CURRENT == MY_CHARSET_TIS620
+#undef USE_STRCOLL
+#define USE_STRCOLL
+#define USE_TIS620
+#include "t_ctype.h"
+#endif
+
+/* Support for Korean(EUC_KR) characters, by powerm90@tinc.co.kr and mrpark@tinc.co.kr */
+#if MY_CHARSET_CURRENT == MY_CHARSET_EUC_KR
+#define USE_MB
+#define USE_MB_IDENT
+#define iseuc_kr(c) ((0xa1<=(uchar)(c) && (uchar)(c)<=0xfe))
+#define ismbchar(p, end) ((*(uchar*)(p)<0x80)? 0:\
+ iseuc_kr(*(p)) && (end)-(p)>1 && iseuc_kr(*((p)+1))? 2:\
+ 0)
+#define ismbhead(c) (iseuc_kr(c))
+#define mbcharlen(c) (iseuc_kr(c) ? 2 : 0)
+#define MBMAXLEN 2
+#endif
+
+#ifdef USE_STRCOLL
+extern uint MY_STRXFRM_MULTIPLY;
+extern int my_strnxfrm(unsigned char *, unsigned char *, int, int);
+extern int my_strnncoll(const unsigned char *, int, const unsigned char *, int);
+extern int my_strxfrm(unsigned char *, unsigned char *, int);
+extern int my_strcoll(const unsigned char *, const unsigned char *);
+extern my_bool my_like_range(const char *ptr,uint ptr_length,pchar escape,
+ uint res_length, char *min_str,char *max_str,
+ uint *min_length,uint *max_length);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _m_ctype_h */
diff --git a/include/Attic/mysql_com.h.in b/include/Attic/mysql_com.h.in
new file mode 100755
index 00000000000..aaf9f3f475f
--- /dev/null
+++ b/include/Attic/mysql_com.h.in
@@ -0,0 +1,216 @@
+/* Copyright Abandoned 1996 TCX DataKonsult AB & Monty Program KB & Detron HB
+ This file is public domain and comes with NO WARRANTY of any kind */
+
+/*
+** Common definition between mysql server & client
+*/
+
+#ifndef _mysql_com_h
+#define _mysql_com_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define NAME_LEN 64 /* Field/table name length */
+#define HOSTNAME_LENGTH 60
+#define USERNAME_LENGTH 16
+
+#define LOCAL_HOST "localhost"
+#define LOCAL_HOST_NAMEDPIPE "."
+
+#ifndef _CUSTOMCONFIG_
+#define MYSQL_PORT @MYSQL_TCP_PORT@ /* Alloced by ISI for MySQL */
+#else
+#include "custom_conf.h"
+#endif
+
+#define MYSQL_UNIX_ADDR "@MYSQL_UNIX_ADDR@"
+#if defined(__EMX__) || defined(__OS2__)
+#undef MYSQL_UNIX_ADDR
+#define MYSQL_OS2_ADDR "\\socket\\MySQL"
+#define MYSQL_UNIX_ADDR MYSQL_OS2_ADDR
+#endif
+#if defined(__WIN32__) && !defined( _CUSTOMCONFIG_)
+#define MYSQL_NAMEDPIPE "MySQL"
+#define MYSQL_SERVICENAME "MySql"
+#endif /* __WIN32__ */
+
+enum enum_server_command {COM_SLEEP,COM_QUIT,COM_INIT_DB,COM_QUERY,
+ COM_FIELD_LIST,COM_CREATE_DB,COM_DROP_DB,COM_REFRESH,
+ COM_SHUTDOWN,COM_STATISTICS,
+ COM_PROCESS_INFO,COM_CONNECT,COM_PROCESS_KILL,
+ COM_DEBUG,COM_PING,COM_TIME,COM_DELAYED_INSERT,
+ COM_CHANGE_USER, COM_BINLOG_DUMP};
+
+#define NOT_NULL_FLAG 1 /* Field can't be NULL */
+#define PRI_KEY_FLAG 2 /* Field is part of a primary key */
+#define UNIQUE_KEY_FLAG 4 /* Field is part of a unique key */
+#define MULTIPLE_KEY_FLAG 8 /* Field is part of a key */
+#define BLOB_FLAG 16 /* Field is a blob */
+#define UNSIGNED_FLAG 32 /* Field is unsigned */
+#define ZEROFILL_FLAG 64 /* Field is zerofill */
+#define BINARY_FLAG 128
+/* The following are only sent to new clients */
+#define ENUM_FLAG 256 /* field is an enum */
+#define AUTO_INCREMENT_FLAG 512 /* field is a autoincrement field */
+#define TIMESTAMP_FLAG 1024 /* Field is a timestamp */
+#define SET_FLAG 2048 /* field is a set */
+#define PART_KEY_FLAG 16384 /* Intern; Part of some key */
+#define GROUP_FLAG 32768 /* Intern: Group field */
+#define UNIQUE_FLAG 65536 /* Intern: Used by sql_yacc */
+
+#define REFRESH_GRANT 1 /* Refresh grant tables */
+#define REFRESH_LOG 2 /* Start on new log file */
+#define REFRESH_TABLES 4 /* close all tables */
+#define REFRESH_HOSTS 8 /* Flush host cache */
+#define REFRESH_STATUS 16 /* Flush status variables */
+#define REFRESH_FAST 32768 /* Intern flag */
+
+#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 */
+#define CLIENT_CONNECT_WITH_DB 8 /* One can specify db on connect */
+#define CLIENT_NO_SCHEMA 16 /* Don't allow database.table.column */
+#define CLIENT_COMPRESS 32 /* Can use compression protocol */
+#define CLIENT_ODBC 64 /* Odbc client */
+#define CLIENT_LOCAL_FILES 128 /* Can use LOAD DATA LOCAL */
+#define CLIENT_IGNORE_SPACE 256 /* Ignore spaces before '(' */
+#define CLIENT_CHANGE_USER 512 /* Support the mysql_change_user() */
+#define CLIENT_INTERACTIVE 1024 /* This is an interactive client */
+#define CLIENT_SSL 2048 /* Switch to SSL after handshake */
+#define CLIENT_IGNORE_SIGPIPE 4096 /* IGNORE sigpipes */
+
+#define MYSQL_ERRMSG_SIZE 200
+#define NET_READ_TIMEOUT 30 /* Timeout on read */
+#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
+
+typedef struct st_net {
+ Vio* vio;
+ my_socket fd; /* For Perl DBI/dbd */
+ int fcntl;
+ unsigned char *buff,*buff_end,*write_pos,*read_pos;
+ char last_error[MYSQL_ERRMSG_SIZE];
+ unsigned int last_errno,max_packet,timeout,pkt_nr;
+ my_bool error,return_errno,compress;
+
+ unsigned long remain_in_buf,length, buf_length, where_b;
+ my_bool more;
+ char save_char;
+} NET;
+
+#define packet_error ((unsigned int) -1)
+
+enum enum_field_types { FIELD_TYPE_DECIMAL, FIELD_TYPE_TINY,
+ FIELD_TYPE_SHORT, FIELD_TYPE_LONG,
+ FIELD_TYPE_FLOAT, FIELD_TYPE_DOUBLE,
+ FIELD_TYPE_NULL, FIELD_TYPE_TIMESTAMP,
+ FIELD_TYPE_LONGLONG,FIELD_TYPE_INT24,
+ FIELD_TYPE_DATE, FIELD_TYPE_TIME,
+ FIELD_TYPE_DATETIME, FIELD_TYPE_YEAR,
+ FIELD_TYPE_NEWDATE,
+ FIELD_TYPE_ENUM=247,
+ FIELD_TYPE_SET=248,
+ FIELD_TYPE_TINY_BLOB=249,
+ FIELD_TYPE_MEDIUM_BLOB=250,
+ FIELD_TYPE_LONG_BLOB=251,
+ FIELD_TYPE_BLOB=252,
+ FIELD_TYPE_VAR_STRING=253,
+ FIELD_TYPE_STRING=254
+};
+
+#define FIELD_TYPE_CHAR FIELD_TYPE_TINY /* For compability */
+#define FIELD_TYPE_INTERVAL FIELD_TYPE_ENUM /* For compability */
+
+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);
+int net_flush(NET *net);
+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);
+
+struct rand_struct {
+ unsigned long seed1,seed2,max_value;
+ double max_value_dbl;
+};
+
+ /* The following is for user defined functions */
+
+enum Item_result {STRING_RESULT,REAL_RESULT,INT_RESULT};
+
+typedef struct st_udf_args
+{
+ unsigned int arg_count; /* Number of arguments */
+ enum Item_result *arg_type; /* Pointer to item_results */
+ char **args; /* Pointer to argument */
+ unsigned long *lengths; /* Length of string arguments */
+ char *maybe_null; /* Set to 1 for all maybe_null args */
+} UDF_ARGS;
+
+ /* This holds information about the result */
+
+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 */
+ char *ptr; /* free pointer for function data */
+ my_bool const_item; /* 0 if result is independent of arguments */
+} UDF_INIT;
+
+ /* Constants when using compression */
+#define NET_HEADER_SIZE 4 /* standard header size */
+#define COMP_HEADER_SIZE 3 /* compression header extra size */
+
+ /* Prototypes to password functions */
+
+void randominit(struct rand_struct *,unsigned long seed1,
+ unsigned long seed2);
+double rnd(struct rand_struct *);
+void make_scrambled_password(char *to,const char *password);
+void get_salt_from_password(unsigned long *res,const char *password);
+void make_password_from_salt(char *to, unsigned long *hash_res);
+char *scramble(char *to,const char *message,const char *password,
+ my_bool old_ver);
+my_bool check_scramble(const char *, const char *message,
+ unsigned long *salt,my_bool old_ver);
+char *get_tty_password(char *opt_message);
+void hash_password(unsigned long *result, const char *password);
+
+/* Some other useful functions */
+
+void my_init(void);
+void load_defaults(const char *conf_file, const char **groups,
+ int *argc, char ***argv);
+
+#define NULL_LENGTH ((unsigned long) ~0) /* For net_store_length */
+
+#ifdef __WIN32__
+#define socket_errno WSAGetLastError()
+#else
+#define socket_errno errno
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/include/Makefile.am b/include/Makefile.am
new file mode 100644
index 00000000000..8ba6ea9d41e
--- /dev/null
+++ b/include/Makefile.am
@@ -0,0 +1,53 @@
+# 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
+
+BUILT_SOURCES = my_config.h mysql_version.h m_ctype.h
+pkginclude_HEADERS = dbug.h m_string.h my_sys.h mysql.h mysql_com.h \
+ mysqld_error.h my_list.h \
+ my_pthread.h my_no_pthread.h raid.h errmsg.h \
+ my_config.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 \
+ nisam.h heap.h merge.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 \
+ mysql_version.h.in
+
+# mysql_version.h are generated
+SUPERCLEANFILES = mysql_version.h
+
+# Some include files that may be moved and patched by configure
+DISTCLEANFILES = $(distdir)/sched.h
+
+all-local: my_config.h my_global.h
+
+# Since we include my_config.h it better exist from the beginning
+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
+ $(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:
+ rm -f $(distdir)/mysql_version.h $(distdir)/my_config.h
diff --git a/include/config-win.h b/include/config-win.h
new file mode 100644
index 00000000000..3a541e9ca88
--- /dev/null
+++ b/include/config-win.h
@@ -0,0 +1,291 @@
+/* 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 */
+
+/* Defines for Win32 to make it compatible for MySQL */
+
+#include <sys/locking.h>
+#include <windows.h>
+#include <math.h> /* Because of rint() */
+#include <fcntl.h>
+#include <io.h>
+#include <malloc.h>
+
+#if defined(__NT__)
+#define SYSTEM_TYPE "NT"
+#elif defined(__WIN2000__)
+#define SYSTEM_TYPE "WIN2000"
+#else
+#define SYSTEM_TYPE "Win95/Win98"
+#endif
+
+#ifdef _WIN32
+#define MACHINE_TYPE "i32" /* Define to machine type name */
+#else
+#define MACHINE_TYPE "i64" /* Define to machine type name */
+#endif
+#ifndef __WIN__
+#define __WIN__ /* To make it easier in VC++ */
+#endif
+
+/* File and lock constants */
+#define O_SHARE 0x1000 /* Open file in sharing mode */
+#ifdef __BORLANDC__
+#define F_RDLCK LK_NBLCK /* read lock */
+#define F_WRLCK LK_NBRLCK /* write lock */
+#define F_UNLCK LK_UNLCK /* remove lock(s) */
+#else
+#define F_RDLCK _LK_NBLCK /* read lock */
+#define F_WRLCK _LK_NBRLCK /* write lock */
+#define F_UNLCK _LK_UNLCK /* remove lock(s) */
+#endif
+
+#define F_EXCLUSIVE 1 /* We have only exclusive locking */
+#define F_TO_EOF (INT_MAX32/2) /* size for lock of all file */
+#define F_OK 0 /* parameter to access() */
+
+#define S_IROTH S_IREAD /* for my_lib */
+
+#ifdef __BORLANDC__
+#define FILE_BINARY O_BINARY /* my_fopen in binary mode */
+#define O_TEMPORARY 0
+#define O_SHORT_LIVED 0
+#define SH_DENYNO _SH_DENYNO
+#else
+#define O_BINARY _O_BINARY /* compability with MSDOS */
+#define FILE_BINARY _O_BINARY /* my_fopen in binary mode */
+#define O_TEMPORARY _O_TEMPORARY
+#define O_SHORT_LIVED _O_SHORT_LIVED
+#define SH_DENYNO _SH_DENYNO
+#endif
+#define NO_OPEN_3 /* For my_create() */
+
+#define SIGQUIT SIGTERM /* No SIGQUIT */
+
+#undef _REENTRANT /* Crashes something for win32 */
+
+#define LONGLONG_MIN ((__int64) 0x8000000000000000)
+#define LONGLONG_MAX ((__int64) 0x7FFFFFFFFFFFFFFF)
+#define LL(A) ((__int64) A)
+
+/* Type information */
+
+typedef unsigned short ushort;
+typedef unsigned int uint;
+#ifndef _WIN64
+typedef unsigned int size_t;
+#endif
+typedef unsigned __int64 ulonglong; /* Microsofts 64 bit types */
+typedef __int64 longlong;
+typedef int sigset_t;
+#define longlong_defined
+/* off_t should not be __int64 because of conflicts in header files;
+ Use my_off_t or os_off_t instead */
+typedef long off_t;
+typedef __int64 os_off_t;
+
+#define Socket_defined
+#define my_socket SOCKET
+#define bool BOOL
+#define SIGPIPE SIGINT
+#define RETQSORTTYPE void
+#define QSORT_TYPE_IS_VOID
+#define RETSIGTYPE void
+#define SOCKET_SIZE_TYPE int
+#define my_socket_defined
+#define bool_defined
+#define byte_defined
+#define HUGE_PTR
+#define STDCALL __stdcall /* Used by libmysql.dll */
+
+#ifndef UNDEF_THREAD_HACK
+#define THREAD
+#endif
+#define VOID_SIGHANDLER
+#define SIZEOF_CHAR 1
+#define SIZEOF_LONG 4
+#define SIZEOF_LONG_LONG 8
+#define SIZEOF_OFF_T 8
+#define HAVE_BROKEN_NETINET_INCLUDES
+#ifdef __NT__
+#define HAVE_NAMED_PIPE /* We can only create pipes on NT */
+#endif
+
+/* Use all character sets in MySQL */
+#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))
+#define finite(A) _finite(A)
+#define sleep(A) Sleep((A)*1000)
+
+#ifndef __BORLANDC__
+#define access(A,B) _access(A,B)
+#endif
+
+#if defined(__cplusplus)
+
+inline double rint(double nr)
+{
+ double f = floor(nr);
+ double c = ceil(nr);
+ return (((c-nr) >= (nr-f)) ? f :c);
+}
+
+#ifdef _WIN64
+#define ulonglong2double(A) ((double) (A))
+#define my_off_t2double(A) ((double) (A))
+
+#else
+inline double ulonglong2double(ulonglong value)
+{
+ longlong nr=(longlong) value;
+ if (nr >= 0)
+ return (double) nr;
+ return (18446744073709551616.0 + (double) nr);
+}
+#define my_off_t2double(A) ulonglong2double(A)
+#endif /* _WIN64 */
+#else
+#define inline __inline
+#endif /* __cplusplus */
+
+#if SIZEOF_OFF_T > 4
+#define lseek(A,B,C) _lseeki64((A),(longlong) (B),(C))
+#define tell(A) _telli64(A)
+#endif
+
+#define STACK_DIRECTION -1
+
+/* Optimized store functions for Intel x86 */
+
+#define sint2korr(A) (*((int16 *) (A)))
+#define sint3korr(A) ((int32) ((((uchar) (A)[2]) & 128) ? \
+ (((uint32) 255L << 24) | \
+ (((uint32) (uchar) (A)[2]) << 16) |\
+ (((uint32) (uchar) (A)[1]) << 8) | \
+ ((uint32) (uchar) (A)[0])) : \
+ (((uint32) (uchar) (A)[2]) << 16) |\
+ (((uint32) (uchar) (A)[1]) << 8) | \
+ ((uint32) (uchar) (A)[0])))
+#define sint4korr(A) (*((long *) (A)))
+#define uint2korr(A) (*((uint16 *) (A)))
+#define uint3korr(A) (long) (*((unsigned long *) (A)) & 0xFFFFFF)
+#define uint4korr(A) (*((unsigned long *) (A)))
+#define uint5korr(A) ((ulonglong)(((uint32) ((uchar) (A)[0])) +\
+ (((uint32) ((uchar) (A)[1])) << 8) +\
+ (((uint32) ((uchar) (A)[2])) << 16) +\
+ (((uint32) ((uchar) (A)[3])) << 24)) +\
+ (((ulonglong) ((uchar) (A)[4])) << 32))
+#define uint8korr(A) (*((ulonglong *) (A)))
+#define sint8korr(A) (*((longlong *) (A)))
+#define int2store(T,A) *((uint16*) (T))= (uint16) (A)
+#define int3store(T,A) { *(T)= (uchar) ((A));\
+ *(T+1)=(uchar) (((uint) (A) >> 8));\
+ *(T+2)=(uchar) (((A) >> 16)); }
+#define int4store(T,A) *((long *) (T))= (long) (A)
+#define int5store(T,A) { *(T)= (uchar)((A));\
+ *((T)+1)=(uchar) (((A) >> 8));\
+ *((T)+2)=(uchar) (((A) >> 16));\
+ *((T)+3)=(uchar) (((A) >> 24)); \
+ *((T)+4)=(uchar) (((A) >> 32)); }
+#define int8store(T,A) *((ulonglong *) (T))= (ulonglong) (A)
+
+#define doubleget(V,M) { *((long *) &V) = *((long*) M); \
+ *(((long *) &V)+1) = *(((long*) M)+1); }
+#define doublestore(T,V) { *((long *) T) = *((long*) &V); \
+ *(((long *) T)+1) = *(((long*) &V)+1); }
+#define float4get(V,M) { *((long *) &(V)) = *((long*) (M)); }
+#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))
+
+
+#define HAVE_PERROR
+#define HAVE_VFPRINT
+#define HAVE_CHSIZE /* System has chsize() function */
+#define HAVE_RENAME /* Have rename() as function */
+#define HAVE_BINARY_STREAMS /* Have "b" flag in streams */
+#define HAVE_LONG_JMP /* Have long jump function */
+#define HAVE_LOCKING /* have locking() call */
+#define HAVE_ERRNO_AS_DEFINE /* errno is a define */
+#define HAVE_STDLIB /* everything is include in this file */
+#define HAVE_MEMCPY
+#define HAVE_MEMMOVE
+#define HAVE_GETCWD
+#define HAVE_TELL
+#define HAVE_TZNAME
+#define HAVE_PUTENV
+#define HAVE_SELECT
+#define HAVE_SETLOCALE
+#define HAVE_SOCKET /* Giangi */
+#define HAVE_FLOAT_H
+#define HAVE_LIMITS_H
+#define HAVE_STDDEF_H
+#define HAVE_RINT /* defined in this file */
+#define NO_FCNTL_NONBLOCK /* No FCNTL */
+#define HAVE_ALLOCA
+#define HAVE_COMPRESS
+
+#ifdef _MSC_VER
+#define HAVE_LDIV /* The optimizer breaks in zortech for ldiv */
+#define HAVE_ANSI_INCLUDE
+#define HAVE_SYS_UTIME_H
+#define HAVE_STRTOUL
+#endif
+#define my_reinterpret_cast(A) reinterpret_cast <A>
+#define my_const_cast(A) const_cast<A>
+
+/* MYSQL OPTIONS */
+
+#ifdef _CUSTOMCONFIG_
+#include <custom_conf.h>
+#else
+#define DEFAULT_MYSQL_HOME "c:\\mysql"
+#define PACKAGE "mysql"
+#define DEFAULT_BASEDIR "C:\\"
+#define SHAREDIR "share"
+#define DEFAULT_CHARSET_HOME "C:/mysql/"
+#endif
+
+/* File name handling */
+
+#define FN_LIBCHAR '\\'
+#define FN_ROOTDIR "\\"
+#define FN_NETWORK_DRIVES /* Uses \\ to indicate network drives */
+#define FN_NO_CASE_SENCE /* Files are not case-sensitive */
+#define FN_LOWER_CASE TRUE /* Files are represented in lower case */
+#define MY_NFILE 127 /* This is only used to save filenames */
+
+
+#define thread_safe_increment(V,L) InterlockedIncrement((long*) &(V))
+/* The following is only used for statistics, so it should be good enough */
+#ifdef __NT__ /* This should also work on Win98 but .. */
+#define thread_safe_add(V,C,L) InterlockedExchangeAdd((long*) &(V),(C))
+#define thread_safe_sub(V,C,L) InterlockedExchangeAdd((long*) &(V),-(long) (C))
+#define statistic_add(V,C,L) thread_safe_add((V),(C),(L))
+#else
+#define thread_safe_add(V,C,L) \
+ pthread_mutex_lock((L)); (V)+=(C); pthread_mutex_unlock((L));
+#define thread_safe_sub(V,C,L) \
+ pthread_mutex_lock((L)); (V)-=(C); pthread_mutex_unlock((L));
+#define statistic_add(V,C,L) (V)+=(C)
+#endif
+#define statistic_increment(V,L) thread_safe_increment((V),(L))
+
diff --git a/include/dbug.h b/include/dbug.h
new file mode 100644
index 00000000000..de6bbc66ed7
--- /dev/null
+++ b/include/dbug.h
@@ -0,0 +1,92 @@
+/* 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 */
+
+#ifndef _dbug_h
+#define _dbug_h
+#ifdef __cplusplus
+extern "C" {
+#endif
+#if !defined(DBUG_OFF) && !defined(_lint)
+extern int _db_on_,_no_db_;
+extern FILE *_db_fp_;
+extern char *_db_process_;
+extern int _db_keyword_(const char *keyword);
+extern void _db_setjmp_(void);
+extern void _db_longjmp_(void);
+extern void _db_push_(const char *control);
+extern void _db_pop_(void);
+extern void _db_enter_(const char *_func_,const char *_file_,uint _line_,
+ const char **_sfunc_,const char **_sfile_,
+ uint *_slevel_, char ***);
+extern void _db_return_(uint _line_,const char **_sfunc_,const char **_sfile_,
+ uint *_slevel_);
+extern void _db_pargs_(uint _line_,const char *keyword);
+extern void _db_doprnt_ _VARARGS((const char *format,...));
+extern void _db_dump_(uint _line_,const char *keyword,const char *memory,
+ uint length);
+extern void _db_lock_file();
+extern void _db_unlock_file();
+
+#define DBUG_ENTER(a) const char *_db_func_, *_db_file_; uint _db_level_; \
+ char **_db_framep_; \
+ _db_enter_ (a,__FILE__,__LINE__,&_db_func_,&_db_file_,&_db_level_, \
+ &_db_framep_)
+#define DBUG_LEAVE \
+ (_db_return_ (__LINE__, &_db_func_, &_db_file_, &_db_level_))
+#define DBUG_RETURN(a1) {DBUG_LEAVE; return(a1);}
+#define DBUG_VOID_RETURN {DBUG_LEAVE; return;}
+#define DBUG_EXECUTE(keyword,a1) \
+ {if (_db_on_) {if (_db_keyword_ (keyword)) { a1 }}}
+#define DBUG_PRINT(keyword,arglist) \
+ {if (_db_on_) {_db_pargs_(__LINE__,keyword); _db_doprnt_ arglist;}}
+#define DBUG_PUSH(a1) _db_push_ (a1)
+#define DBUG_POP() _db_pop_ ()
+#define DBUG_PROCESS(a1) (_db_process_ = a1)
+#define DBUG_FILE (_db_fp_)
+#define DBUG_SETJMP(a1) (_db_setjmp_ (), setjmp (a1))
+#define DBUG_LONGJMP(a1,a2) (_db_longjmp_ (), longjmp (a1, a2))
+#define DBUG_DUMP(keyword,a1,a2)\
+ {if (_db_on_) {_db_dump_(__LINE__,keyword,a1,a2);}}
+#define DBUG_IN_USE (_db_fp_ && _db_fp_ != stderr)
+#define DEBUGGER_OFF _no_db_=1;_db_on_=0;
+#define DEBUGGER_ON _no_db_=0
+#define DBUG_LOCK_FILE { _db_lock_file(); }
+#define DBUG_UNLOCK_FILE { _db_unlock_file(); }
+#else /* No debugger */
+
+#define DBUG_ENTER(a1)
+#define DBUG_RETURN(a1) return(a1)
+#define DBUG_VOID_RETURN return
+#define DBUG_EXECUTE(keyword,a1) {}
+#define DBUG_PRINT(keyword,arglist) {}
+#define DBUG_PUSH(a1) {}
+#define DBUG_POP() {}
+#define DBUG_PROCESS(a1) {}
+#define DBUG_FILE (stderr)
+#define DBUG_SETJMP setjmp
+#define DBUG_LONGJMP longjmp
+#define DBUG_DUMP(keyword,a1,a2) {}
+#define DBUG_IN_USE 0
+#define DEBUGGER_OFF
+#define DEBUGGER_ON
+#define DBUG_LOCK_FILE
+#define DBUG_UNLOCK_FILE
+#endif
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/include/errmsg.h b/include/errmsg.h
new file mode 100644
index 00000000000..b7afe11b615
--- /dev/null
+++ b/include/errmsg.h
@@ -0,0 +1,55 @@
+/* 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 */
+
+/* Error messages for mysql clients */
+/* error messages for the demon is in share/language/errmsg.sys */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+void init_client_errs(void);
+extern const char *client_errors[]; /* Error messages */
+#ifdef __cplusplus
+}
+#endif
+
+#define CR_MIN_ERROR 2000 /* For easier client code */
+#define CR_MAX_ERROR 2999
+#define ER(X) client_errors[(X)-CR_MIN_ERROR]
+#define CLIENT_ERRMAP 2 /* Errormap used by my_error() */
+
+#define CR_UNKNOWN_ERROR 2000
+#define CR_SOCKET_CREATE_ERROR 2001
+#define CR_CONNECTION_ERROR 2002
+#define CR_CONN_HOST_ERROR 2003
+#define CR_IPSOCK_ERROR 2004
+#define CR_UNKNOWN_HOST 2005
+#define CR_SERVER_GONE_ERROR 2006
+#define CR_VERSION_ERROR 2007
+#define CR_OUT_OF_MEMORY 2008
+#define CR_WRONG_HOST_INFO 2009
+#define CR_LOCALHOST_CONNECTION 2010
+#define CR_TCP_CONNECTION 2011
+#define CR_SERVER_HANDSHAKE_ERR 2012
+#define CR_SERVER_LOST 2013
+#define CR_COMMANDS_OUT_OF_SYNC 2014
+#define CR_NAMEDPIPE_CONNECTION 2015
+#define CR_NAMEDPIPEWAIT_ERROR 2016
+#define CR_NAMEDPIPEOPEN_ERROR 2017
+#define CR_NAMEDPIPESETSTATE_ERROR 2018
+#define CR_CANT_READ_CHARSET 2019
+#define CR_NET_PACKET_TOO_LARGE 2020
diff --git a/include/ft_global.h b/include/ft_global.h
new file mode 100644
index 00000000000..cbd4ba1a2c2
--- /dev/null
+++ b/include/ft_global.h
@@ -0,0 +1,52 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 */
+
+/* some definitions for full-text indices */
+
+/* #include "myisam.h" */
+
+#ifndef _ft_global_h
+#define _ft_global_h
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define FT_QUERY_MAXLEN 1024
+
+typedef struct ft_doc_rec {
+ my_off_t dpos;
+ double weight;
+} FT_DOC;
+
+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;
+
+int ft_init_stopwords(const char **);
+
+FT_DOCLIST * ft_init_search(void *, uint, byte *, uint, my_bool);
+double ft_read_next(FT_DOCLIST *, char *);
+#define ft_close_search(handler) my_free(((gptr)(handler)),MYF(0))
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/include/getopt.h b/include/getopt.h
new file mode 100644
index 00000000000..eb29226b1dc
--- /dev/null
+++ b/include/getopt.h
@@ -0,0 +1,133 @@
+/* Declarations for getopt.
+ Copyright (C) 1989, 90, 91, 92, 93, 94 Free Software Foundation, Inc.
+
+This file is part of the GNU C Library. Its master source is NOT part of
+the C library, however. The master source lives in /gd/gnu/lib.
+
+The GNU C Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+The GNU C 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 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. */
+
+#ifndef _GETOPT_H
+#define _GETOPT_H 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* For communication from `getopt' to the caller.
+ When `getopt' finds an option that takes an argument,
+ the argument value is returned here.
+ Also, when `ordering' is RETURN_IN_ORDER,
+ each non-option ARGV-element is returned here. */
+
+extern char *optarg;
+
+/* Index in ARGV of the next element to be scanned.
+ This is used for communication to and from the caller
+ and for communication between successive calls to `getopt'.
+
+ On entry to `getopt', zero means this is the first call; initialize.
+
+ When `getopt' returns EOF, this is the index of the first of the
+ non-option elements that the caller should itself scan.
+
+ Otherwise, `optind' communicates from one call to the next
+ how much of ARGV has been scanned so far. */
+
+extern int optind;
+
+/* Callers store zero here to inhibit the error message `getopt' prints
+ for unrecognized options. */
+
+extern int opterr;
+
+/* Set to an option character which was unrecognized. */
+
+extern int optopt;
+
+/* Describe the long-named options requested by the application.
+ The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector
+ of `struct option' terminated by an element containing a name which is
+ zero.
+
+ The field `has_arg' is:
+ no_argument (or 0) if the option does not take an argument,
+ required_argument (or 1) if the option requires an argument,
+ optional_argument (or 2) if the option takes an optional argument.
+
+ If the field `flag' is not NULL, it points to a variable that is set
+ to the value given in the field `val' when the option is found, but
+ left unchanged if the option is not found.
+
+ To have a long-named option do something other than set an `int' to
+ a compiled-in constant, such as set a value from `optarg', set the
+ option's `flag' field to zero and its `val' field to a nonzero
+ value (the equivalent single-letter option character, if there is
+ one). For long options that have a zero `flag' field, `getopt'
+ returns the contents of the `val' field. */
+
+struct option
+{
+#if defined (__STDC__) && __STDC__ || defined(__cplusplus)
+ const char *name;
+#else
+ char *name;
+#endif
+ /* has_arg can't be an enum because some compilers complain about
+ type mismatches in all the code that assumes it is an int. */
+ int has_arg;
+ int *flag;
+ int val;
+};
+
+/* Names for the values of the `has_arg' field of `struct option'. */
+
+#define no_argument 0
+#define required_argument 1
+#define optional_argument 2
+
+#if ( defined (__STDC__) && __STDC__ ) || defined(__cplusplus) || defined(MSDOS)
+#ifdef __GNU_LIBRARY__
+/* Many other libraries have conflicting prototypes for getopt, with
+ differences in the consts, in stdlib.h. To avoid compilation
+ errors, only prototype getopt for the GNU C library. */
+extern int getopt (int argc, char *const *argv, const char *shortopts);
+#else /* not __GNU_LIBRARY__ */
+extern int getopt (int argc, char *const *argv, const char *optstring);
+#endif /* __GNU_LIBRARY__ */
+extern int getopt_long (int argc, char *const *argv, const char *shortopts,
+ const struct option *longopts, int *longind);
+extern int getopt_long_only (int argc, char *const *argv,
+ const char *shortopts,
+ const struct option *longopts, int *longind);
+
+/* Internal only. Users should not call this directly. */
+extern int _getopt_internal (int argc, char *const *argv,
+ const char *shortopts,
+ const struct option *longopts, int *longind,
+ int long_only);
+#else /* not __STDC__ */
+extern int getopt ();
+extern int getopt_long ();
+extern int getopt_long_only ();
+
+extern int _getopt_internal ();
+#endif /* __STDC__ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _GETOPT_H */
diff --git a/include/global.h b/include/global.h
new file mode 100644
index 00000000000..bb7ee1b6cba
--- /dev/null
+++ b/include/global.h
@@ -0,0 +1,845 @@
+/* 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 is the main include file that should included 'first' in every
+ C file. */
+
+#ifndef _global_h
+#define _global_h
+
+#if defined(_WIN32) || defined(_WIN64)
+#include <config-win.h>
+#else
+#include <my_config.h>
+#endif
+#if defined(__cplusplus)
+#if defined(inline)
+#undef inline /* fix configure problem */
+#endif
+#endif /* _cplusplus */
+
+/* The client defines this to avoid all thread code */
+#if defined(UNDEF_THREADS_HACK) && !defined(THREAD_SAFE_CLIENT)
+#undef THREAD
+#undef HAVE_mit_thread
+#undef HAVE_LINUXTHREADS
+#undef HAVE_UNIXWARE7_THREADS
+#endif
+
+#ifdef HAVE_THREADS_WITHOUT_SOCKETS
+/* MIT pthreads does not work with unix sockets */
+#undef HAVE_SYS_UN_H
+#endif
+
+#define __EXTENSIONS__ 1 /* We want some extension */
+#ifndef __STDC_EXT__
+#define __STDC_EXT__ 1 /* To get large file support on hpux */
+#endif
+#if defined(THREAD) && defined(HAVE_LINUXTHREADS) && defined(HAVE_PTHREAD_RWLOCK_RDLOCK)
+#define _GNU_SOURCE 1
+#endif
+
+#if defined(THREAD) && !defined(__WIN__)
+#define _POSIX_PTHREAD_SEMANTICS /* We want posix threads */
+/* was #if defined(HAVE_LINUXTHREADS) || defined(HAVE_DEC_THREADS) || defined(HPUX) */
+#if !defined(SCO)
+#define _REENTRANT 1 /* Some thread libraries require this */
+#endif
+#if !defined(_THREAD_SAFE) && !defined(_AIX)
+#define _THREAD_SAFE /* Required for OSF1 */
+#endif
+#ifndef HAVE_mit_thread
+#ifdef HAVE_UNIXWARE7_THREADS
+#include <thread.h>
+#else
+#include <pthread.h> /* AIX must have this included first */
+#endif /* HAVE_UNIXWARE7_THREADS */
+#endif /* HAVE_mit_thread */
+#if !defined(SCO) && !defined(_REENTRANT)
+#define _REENTRANT 1 /* Threads requires reentrant code */
+#endif
+#endif /* THREAD */
+
+/* Go around some bugs in different OS and compilers */
+#ifdef _AIX /* By soren@t.dk */
+#define _H_STRINGS
+#define _SYS_STREAM_H
+#define _AIX32_CURSES
+#endif
+
+#ifdef HAVE_BROKEN_SNPRINTF /* HPUX 10.20 don't have this defined */
+#undef HAVE_SNPRINTF
+#endif
+#ifdef HAVE_BROKEN_PREAD /* These doesn't work on HPUX 11.x */
+#undef HAVE_PREAD
+#undef HAVE_PWRITE
+#endif
+
+#ifdef UNDEF_HAVE_GETHOSTBYNAME_R /* For OSF4.x */
+#undef HAVE_GETHOSTBYNAME_R
+#endif
+#ifdef UNDEF_HAVE_INITGROUPS /* For AIX 4.3 */
+#undef HAVE_INITGROUPS
+#endif
+
+/* Fix a bug in gcc 2.8.0 on IRIX 6.2 */
+#if SIZEOF_LONG == 4 && defined(__LONG_MAX__)
+#undef __LONG_MAX__ /* Is a longlong value in gcc 2.8.0 ??? */
+#define __LONG_MAX__ 2147483647
+#endif
+
+/* egcs 1.1.2 has a problem with memcpy on Alpha */
+#if defined(__GNUC__) && defined(__alpha__) && ! (__GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95))
+#define BAD_MEMCPY
+#endif
+
+/* In Linux-alpha we have atomic.h if we are using gcc */
+#if defined(HAVE_LINUXTHREADS) && defined(__GNUC__) && defined(__alpha__) && (__GNUC__ > 2 || ( __GNUC__ == 2 && __GNUC_MINOR__ >= 95))
+#define HAVE_ATOMIC_ADD
+#define HAVE_ATOMIC_SUB
+#endif
+
+#if defined(_lint) && !defined(lint)
+#define lint
+#endif
+#if SIZEOF_LONG_LONG > 4 && !defined(_LONG_LONG)
+#define _LONG_LONG 1 /* For AIX string library */
+#endif
+
+#ifndef stdin
+#include <stdio.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_STDDEF_H
+#include <stddef.h>
+#endif
+
+#include <math.h>
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
+#ifdef HAVE_FLOAT_H
+#include <float.h>
+#endif
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#ifdef HAVE_SYS_TIMEB_H
+#include <sys/timeb.h> /* Avoid warnings on SCO */
+#endif
+#if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H
+# include <sys/time.h>
+# else
+# include <time.h>
+# endif
+#endif /* TIME_WITH_SYS_TIME */
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#if defined(__cplusplus) && defined(NO_CPLUSPLUS_ALLOCA)
+#undef HAVE_ALLOCA
+#undef HAVE_ALLOCA_H
+#endif
+#ifdef HAVE_ALLOCA_H
+#include <alloca.h>
+#endif
+#ifdef HAVE_ATOMIC_ADD
+#define __SMP__
+#include <asm/atomic.h>
+#endif
+
+/* Go around some bugs in different OS and compilers */
+#if defined(_HPUX_SOURCE) && defined(HAVE_SYS_STREAM_H)
+#include <sys/stream.h> /* HPUX 10.20 defines ulong here. UGLY !!! */
+#define HAVE_ULONG
+#endif
+#ifdef DONT_USE_FINITE /* HPUX 11.x has is_finite() */
+#undef HAVE_FINITE
+#endif
+
+/* We can not live without these */
+
+#define USE_MYFUNC 1 /* Must use syscall indirection */
+#define MASTER 1 /* Compile without unireg */
+#define ENGLISH 1 /* Messages in English */
+#define POSIX_MISTAKE 1 /* regexp: Fix stupid spec error */
+#define USE_REGEX 1 /* We want the use the regex library */
+/* Do not define for ultra sparcs */
+#define USE_BMOVE512 1 /* Use this unless the system bmove is faster */
+
+/* Paranoid settings. Define I_AM_PARANOID if you are paranoid */
+#ifdef I_AM_PARANOID
+#define DONT_ALLOW_USER_CHANGE 1
+#define DONT_USE_MYSQL_PWD 1
+#endif
+
+/* #define USE_some_charset 1 was deprecated by changes to configure */
+/* my_ctype my_to_upper, my_to_lower, my_sort_order gain theit right value */
+/* automagically during configuration */
+
+/* Does the system remember a signal handler after a signal ? */
+#ifndef HAVE_BSD_SIGNALS
+#define DONT_REMEMBER_SIGNAL
+#endif
+
+/* Define void to stop lint from generating "null effekt" comments */
+#ifdef _lint
+int __void__;
+#define VOID(X) (__void__ = (int) (X))
+#else
+#undef VOID
+#define VOID(X) (X)
+#endif
+
+#if defined(_lint) || defined(FORCE_INIT_OF_VARS)
+#define LINT_INIT(var) var=0 /* No uninitialize-warning */
+#else
+#define LINT_INIT(var)
+#endif
+
+/* Define som useful general macros */
+#if defined(__cplusplus) && defined(__GNUC__)
+#define max(a, b) ((a) >? (b))
+#define min(a, b) ((a) <? (b))
+#elif !defined(max)
+#define max(a, b) ((a) > (b) ? (a) : (b))
+#define min(a, b) ((a) < (b) ? (a) : (b))
+#endif
+
+#if defined(__EMX__) || !defined(HAVE_UINT)
+typedef unsigned int uint;
+typedef unsigned short ushort;
+#endif
+
+#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)
+#define set_if_bigger(a,b) { if ((a) < (b)) (a)=(b); }
+#define set_if_smaller(a,b) { if ((a) > (b)) (a)=(b); }
+#define test_all_bits(a,b) (((a) & (b)) == (b))
+#define array_elements(A) ((uint) (sizeof(A)/sizeof(A[0])))
+#ifndef HAVE_RINT
+#define rint(A) floor((A)+0.5)
+#endif
+
+/* Define som general constants */
+#ifndef TRUE
+#define TRUE (1) /* Logical true */
+#define FALSE (0) /* Logical false */
+#endif
+
+#if defined(__GNUC__)
+#define function_volatile volatile
+#define my_reinterpret_cast(A) reinterpret_cast<A>
+#define my_const_cast(A) const_cast<A>
+#elif !defined(my_reinterpret_cast)
+#define my_reinterpret_cast(A) (A)
+#define my_const_cast(A) (A)
+#endif
+#if !defined(__attribute__) && (defined(__cplusplus) || !defined(__GNUC__) || __GNUC__ == 2 && __GNUC_MINOR__ < 8)
+#define __attribute__(A)
+#endif
+
+/* From old s-system.h */
+
+/* Support macros for non ansi & other old compilers. Since such
+ things are no longer supported we do nothing. We keep then since
+ some of our code may still be needed to upgrade old customers. */
+#define _VARARGS(X) X
+#define _STATIC_VARARGS(X) X
+#define _PC(X) X
+
+#if defined(DBUG_ON) && defined(DBUG_OFF)
+#undef DBUG_OFF
+#endif
+
+#if defined(_lint) && !defined(DBUG_OFF)
+#define DBUG_OFF
+#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 */
+#define NEAR_F /* No near function handling */
+
+/* Some types that is different between systems */
+
+typedef int File; /* File descriptor */
+#ifndef Socket_defined
+typedef int my_socket; /* File descriptor for sockets */
+#define INVALID_SOCKET -1
+#endif
+typedef RETSIGTYPE sig_handler; /* Function to handle signals */
+typedef void (*sig_return)();/* Returns type from signal */
+#if defined(__GNUC__) && !defined(_lint)
+typedef char pchar; /* Mixed prototypes can take char */
+typedef char puchar; /* Mixed prototypes can take char */
+typedef char pbool; /* Mixed prototypes can take char */
+typedef short pshort; /* Mixed prototypes can take short int */
+typedef float pfloat; /* Mixed prototypes can take float */
+#else
+typedef int pchar; /* Mixed prototypes can't take char */
+typedef uint puchar; /* Mixed prototypes can't take char */
+typedef int pbool; /* Mixed prototypes can't take char */
+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 *);
+#ifdef HAVE_mit_thread
+#define qsort_t void
+#undef QSORT_TYPE_IS_VOID
+#define QSORT_TYPE_IS_VOID
+#else
+#define qsort_t RETQSORTTYPE /* Broken GCC cant handle typedef !!!! */
+#endif
+#ifdef HAVE_mit_thread
+#define size_socket socklen_t /* Type of last arg to accept */
+#else
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+typedef SOCKET_SIZE_TYPE size_socket;
+#endif
+
+/* file create flags */
+
+#ifndef O_SHARE
+#define O_SHARE 0 /* Flag to my_open for shared files */
+#ifndef O_BINARY
+#define O_BINARY 0 /* Flag to my_open for binary files */
+#endif
+#define FILE_BINARY 0 /* Flag to my_fopen for binary streams */
+#ifdef HAVE_FCNTL
+#define HAVE_FCNTL_LOCK
+#define F_TO_EOF 0L /* Param to lockf() to lock rest of file */
+#endif
+#endif /* O_SHARE */
+#ifndef O_TEMPORARY
+#define O_TEMPORARY 0
+#endif
+#ifndef O_SHORT_LIVED
+#define O_SHORT_LIVED 0
+#endif
+
+/* #define USE_RECORD_LOCK */
+
+ /* Unsigned types supported by the compiler */
+#define UNSINT8 /* unsigned int8 (char) */
+#define UNSINT16 /* unsigned int16 */
+#define UNSINT32 /* unsigned int32 */
+
+ /* General constants */
+#define SC_MAXWIDTH 256 /* Max width of screen (for error messages) */
+#define FN_LEN 256 /* Max file name len */
+#define FN_HEADLEN 253 /* Max length of filepart of file name */
+#define FN_EXTLEN 20 /* Max length of extension (part of FN_LEN) */
+#define FN_REFLEN 512 /* Max length of full path-name */
+#define FN_EXTCHAR '.'
+#define FN_HOMELIB '~' /* ~/ is used as abbrev for home dir */
+#define FN_CURLIB '.' /* ./ is used as abbrev for current dir */
+#define FN_PARENTDIR ".." /* Parentdirectory; Must be a string */
+#define FN_DEVCHAR ':'
+
+#ifndef FN_LIBCHAR
+#define FN_LIBCHAR '/'
+#define FN_ROOTDIR "/"
+#define MY_NFILE 127 /* This is only used to save filenames */
+#endif
+
+/* #define EXT_IN_LIBNAME */
+/* #define FN_NO_CASE_SENCE */
+/* #define FN_UPPER_CASE TRUE */
+
+/* Io buffer size; Must be a power of 2 and a multiple of 512. May be
+ smaller what the disk page size. This influences the speed of the
+ isam btree library. eg to big to slow. */
+#define IO_SIZE 4096
+/* How much overhead does malloc have. The code often allocates
+ something like 1024-MALLOC_OVERHEAD bytes */
+#ifdef SAFEMALLOC
+#define MALLOC_OVERHEAD (8+24+4)
+#else
+#define MALLOC_OVERHEAD 8
+#endif
+ /* get memory in huncs */
+#define ONCE_ALLOC_INIT (uint) (4096-MALLOC_OVERHEAD)
+ /* Typical record cash */
+#define RECORD_CACHE_SIZE (uint) (64*1024-MALLOC_OVERHEAD)
+ /* Typical key cash */
+#define KEY_CACHE_SIZE (uint) (8*1024*1024-MALLOC_OVERHEAD)
+
+ /* 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 */
+#define USE_MY_STAT_STRUCT /* For my_lib */
+#endif
+
+/* Some things that this system does have */
+
+#ifndef HAVE_ITOA
+#define USE_MY_ITOA /* There is no itoa */
+#endif
+
+/* Some defines of functions for portability */
+
+#ifndef HAVE_ATOD
+#define atod atof
+#endif
+#ifdef USE_MY_ATOF
+#define atof my_atof
+extern void init_my_atof(void);
+extern double my_atof(const char*);
+#endif
+#undef remove /* Crashes MySQL on SCO 5.0.0 */
+#ifndef __WIN__
+#define closesocket(A) close(A)
+#ifndef ulonglong2double
+#define ulonglong2double(A) ((double) (A))
+#define my_off_t2double(A) ((double) (A))
+#endif
+#endif
+
+#ifndef offsetof
+#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+#endif
+#define ulong_to_double(X) ((double) (ulong) (X))
+#define SET_STACK_SIZE(X) /* Not needed on real machines */
+
+#if !defined(HAVE_mit_thread) && !defined(HAVE_STRTOK_R)
+#define strtok_r(A,B,C) strtok((A),(B))
+#endif
+
+#ifdef HAVE_LINUXTHREADS
+/* #define pthread_sigmask(A,B,C) sigprocmask((A),(B),(C)) */
+/* #define sigset(A,B) signal((A),(B)) */
+#endif
+
+/* Remove some things that mit_thread break or doesn't support */
+#if defined(HAVE_mit_thread) && defined(THREAD)
+#undef HAVE_PREAD
+#undef HAVE_REALPATH
+#undef HAVE_MLOCK
+#undef HAVE_TEMPNAM /* Use ours */
+#undef HAVE_PTHREAD_SETPRIO
+#endif
+
+/* This is from the old m-machine.h file */
+
+#if SIZEOF_LONG_LONG > 4
+#define HAVE_LONG_LONG 1
+#endif
+
+#if defined(HAVE_LONG_LONG) && !defined(LONGLONG_MIN)
+#define LONGLONG_MIN ((long long) 0x8000000000000000LL)
+#define LONGLONG_MAX ((long long) 0x7FFFFFFFFFFFFFFFLL)
+#endif
+
+#if SIZEOF_LONG == 4
+#define INT_MIN32 (long) 0x80000000L
+#define INT_MAX32 (long) 0x7FFFFFFFL
+#define INT_MIN24 ((long) 0xff800000L)
+#define INT_MAX24 0x007fffffL
+#define INT_MIN16 ((short int) 0x8000)
+#define INT_MAX16 0x7FFF
+#define INT_MIN8 ((char) 0x80)
+#define INT_MAX8 ((char) 0x7F)
+#else /* Probably Alpha */
+#define INT_MIN32 ((long) (int) 0x80000000)
+#define INT_MAX32 ((long) (int) 0x7FFFFFFF)
+#define INT_MIN24 ((long) (int) 0xff800000)
+#define INT_MAX24 ((long) (int) 0x007fffff)
+#define INT_MIN16 ((short int) 0xffff8000)
+#define INT_MAX16 ((short int) 0x00007FFF)
+#endif
+
+/* From limits.h instead */
+#ifndef DBL_MIN
+#define DBL_MIN 4.94065645841246544e-324
+#define FLT_MIN ((float)1.40129846432481707e-45)
+#endif
+#ifndef DBL_MAX
+#define DBL_MAX 1.79769313486231470e+308
+#define FLT_MAX ((float)3.40282346638528860e+38)
+#endif
+
+/* Max size that must be added to a so that we know Size to make
+ adressable obj. */
+typedef long my_ptrdiff_t;
+#define MY_ALIGN(A,L) (((A) + (L) - 1) & ~((L) - 1))
+#define ALIGN_SIZE(A) MY_ALIGN((A),sizeof(double))
+/* Size to make adressable obj. */
+#define ALIGN_PTR(A, t) ((t*) MY_ALIGN((A),sizeof(t)))
+ /* Offset of filed f in structure t */
+#define OFFSET(t, f) ((size_t)(char *)&((t *)0)->f)
+#define ADD_TO_PTR(ptr,size,type) (type) ((byte*) (ptr)+size)
+#define PTR_BYTE_DIFF(A,B) (my_ptrdiff_t) ((byte*) (A) - (byte*) (B))
+
+#define NullS (char *) 0
+/* Nowdays we do not support MessyDos */
+#ifndef NEAR
+#define NEAR /* Who needs segments ? */
+#define FAR /* On a good machine */
+#define HUGE_PTR
+#define STDCALL
+#endif
+
+/* Typdefs for easyier portability */
+
+#if defined(VOIDTYPE)
+typedef void *gptr; /* Generic pointer */
+#else
+typedef char *gptr; /* Generic pointer */
+#endif
+#ifndef HAVE_INT_8_16_32
+typedef char int8; /* Signed integer >= 8 bits */
+typedef short int16; /* Signed integer >= 16 bits */
+#endif
+#ifndef HAVE_UCHAR
+typedef unsigned char uchar; /* Short for unsigned char */
+#endif
+typedef unsigned char uint8; /* Short for unsigned integer >= 8 bits */
+typedef unsigned short uint16; /* Short for unsigned integer >= 16 bits */
+
+#if SIZEOF_INT == 4
+#ifndef HAVE_INT_8_16_32
+typedef int int32;
+#endif
+typedef unsigned int uint32; /* Short for unsigned integer >= 32 bits */
+#elif SIZEOF_LONG == 4
+#ifndef HAVE_INT_8_16_32
+typedef long int32;
+#endif
+typedef unsigned long uint32; /* Short for unsigned integer >= 32 bits */
+#else
+error "Neither int or long is of 4 bytes width"
+#endif
+
+#if !defined(HAVE_ULONG) && !defined(HAVE_LINUXTHREADS) && !defined(__USE_MISC)
+typedef unsigned long ulong; /* Short for unsigned long */
+#endif
+#ifndef longlong_defined
+#if defined(HAVE_LONG_LONG) && SIZEOF_LONG != 8
+typedef unsigned long long ulonglong; /* ulong or unsigned long long */
+typedef long long longlong;
+#else
+typedef unsigned long ulonglong; /* ulong or unsigned long long */
+typedef long longlong;
+#endif
+#endif
+
+#ifdef USE_RAID
+/* The following is done with a if to not get problems with pre-processors
+ with late define evaluation */
+#if SIZEOF_OFF_T == 4
+#define SYSTEM_SIZEOF_OFF_T 4
+#else
+#define SYSTEM_SIZEOF_OFF_T 8
+#endif
+#undef SIZEOF_OFF_T
+#define SIZEOF_OFF_T 8
+#endif
+
+#if SIZEOF_OFF_T > 4
+typedef ulonglong my_off_t;
+#else
+typedef unsigned long my_off_t;
+#endif
+#define MY_FILEPOS_ERROR (~(my_off_t) 0)
+#ifndef __WIN__
+typedef off_t os_off_t;
+#endif
+
+typedef uint8 int7; /* Most effective integer 0 <= x <= 127 */
+typedef short int15; /* Most effective integer 0 <= x <= 32767 */
+typedef char *my_string; /* String of characters */
+typedef unsigned long size_s; /* Size of strings (In string-funcs) */
+typedef int myf; /* Type of MyFlags in my_funcs */
+#ifndef byte_defined
+typedef char byte; /* Smallest addressable unit */
+#endif
+typedef char my_bool; /* Small bool */
+#if !defined(bool) && !defined(bool_defined) && (!defined(HAVE_BOOL) || !defined(__cplusplus))
+typedef char bool; /* Ordinary boolean values 0 1 */
+#endif
+ /* Macros for converting *constants* to the right type */
+#define INT8(v) (int8) (v)
+#define INT16(v) (int16) (v)
+#define INT32(v) (int32) (v)
+#define MYF(v) (myf) (v)
+
+/* Defines to make it possible to prioritize register assignments. No
+ longer needed with moder compilers */
+#ifndef USING_X
+#define reg1 register
+#define reg2 register
+#define reg3 register
+#define reg4 register
+#define reg5 register
+#define reg6 register
+#define reg7 register
+#define reg8 register
+#define reg9 register
+#define reg10 register
+#define reg11 register
+#define reg12 register
+#define reg13 register
+#define reg14 register
+#define reg15 register
+#define reg16 register
+#endif
+
+/* Defines for time function */
+#define SCALE_SEC 100
+#define SCALE_USEC 10000
+#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 */
+
+/*
+** Define-funktions for reading and storing in machine independent format
+** (low byte first)
+*/
+
+/* Optimized store functions for Intel x86 */
+#ifdef __i386__
+#define sint2korr(A) (*((int16 *) (A)))
+#define sint3korr(A) ((int32) ((((uchar) (A)[2]) & 128) ? \
+ (((uint32) 255L << 24) | \
+ (((uint32) (uchar) (A)[2]) << 16) |\
+ (((uint32) (uchar) (A)[1]) << 8) | \
+ ((uint32) (uchar) (A)[0])) : \
+ (((uint32) (uchar) (A)[2]) << 16) |\
+ (((uint32) (uchar) (A)[1]) << 8) | \
+ ((uint32) (uchar) (A)[0])))
+#define sint4korr(A) (*((long *) (A)))
+#define uint2korr(A) (*((uint16 *) (A)))
+#define uint3korr(A) (long) (*((unsigned long *) (A)) & 0xFFFFFF)
+#define uint4korr(A) (*((unsigned long *) (A)))
+#define uint5korr(A) ((ulonglong)(((uint32) ((uchar) (A)[0])) +\
+ (((uint32) ((uchar) (A)[1])) << 8) +\
+ (((uint32) ((uchar) (A)[2])) << 16) +\
+ (((uint32) ((uchar) (A)[3])) << 24)) +\
+ (((ulonglong) ((uchar) (A)[4])) << 32))
+#define uint8korr(A) (*((ulonglong *) (A)))
+#define sint8korr(A) (*((longlong *) (A)))
+#define int2store(T,A) *((uint16*) (T))= (uint16) (A)
+#define int3store(T,A) { *(T)= (uchar) ((A));\
+ *(T+1)=(uchar) (((uint) (A) >> 8));\
+ *(T+2)=(uchar) (((A) >> 16)); }
+#define int4store(T,A) *((long *) (T))= (long) (A)
+#define int5store(T,A) { *(T)= (uchar)((A));\
+ *((T)+1)=(uchar) (((A) >> 8));\
+ *((T)+2)=(uchar) (((A) >> 16));\
+ *((T)+3)=(uchar) (((A) >> 24)); \
+ *((T)+4)=(uchar) (((A) >> 32)); }
+#define int8store(T,A) *((ulonglong *) (T))= (ulonglong) (A)
+
+#define doubleget(V,M) { *((long *) &V) = *((long*) M); \
+ *(((long *) &V)+1) = *(((long*) M)+1); }
+#define doublestore(T,V) { *((long *) T) = *((long*) &V); \
+ *(((long *) T)+1) = *(((long*) &V)+1); }
+#define float4get(V,M) { *((long *) &(V)) = *((long*) (M)); }
+#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__ */
+
+#ifndef sint2korr
+#define sint2korr(A) (int16) (((int16) ((uchar) (A)[0])) +\
+ ((int16) ((int16) (A)[1]) << 8))
+#define sint3korr(A) ((int32) ((((uchar) (A)[2]) & 128) ? \
+ (((uint32) 255L << 24) | \
+ (((uint32) (uchar) (A)[2]) << 16) |\
+ (((uint32) (uchar) (A)[1]) << 8) | \
+ ((uint32) (uchar) (A)[0])) : \
+ (((uint32) (uchar) (A)[2]) << 16) |\
+ (((uint32) (uchar) (A)[1]) << 8) | \
+ ((uint32) (uchar) (A)[0])))
+#define sint4korr(A) (int32) (((int32) ((uchar) (A)[0])) +\
+ (((int32) ((uchar) (A)[1]) << 8)) +\
+ (((int32) ((uchar) (A)[2]) << 16)) +\
+ (((int32) ((int16) (A)[3]) << 24)))
+#define sint8korr(A) (longlong) uint8korr(A)
+#define uint2korr(A) (uint16) (((uint16) ((uchar) (A)[0])) +\
+ ((uint16) ((uchar) (A)[1]) << 8))
+#define uint3korr(A) (uint32) (((uint32) ((uchar) (A)[0])) +\
+ (((uint32) ((uchar) (A)[1])) << 8) +\
+ (((uint32) ((uchar) (A)[2])) << 16))
+#define uint4korr(A) (uint32) (((uint32) ((uchar) (A)[0])) +\
+ (((uint32) ((uchar) (A)[1])) << 8) +\
+ (((uint32) ((uchar) (A)[2])) << 16) +\
+ (((uint32) ((uchar) (A)[3])) << 24))
+#define uint5korr(A) ((ulonglong)(((uint32) ((uchar) (A)[0])) +\
+ (((uint32) ((uchar) (A)[1])) << 8) +\
+ (((uint32) ((uchar) (A)[2])) << 16) +\
+ (((uint32) ((uchar) (A)[3])) << 24)) +\
+ (((ulonglong) ((uchar) (A)[4])) << 32))
+#define uint8korr(A) ((ulonglong)(((uint32) ((uchar) (A)[0])) +\
+ (((uint32) ((uchar) (A)[1])) << 8) +\
+ (((uint32) ((uchar) (A)[2])) << 16) +\
+ (((uint32) ((uchar) (A)[3])) << 24)) +\
+ (((ulonglong) (((uint32) ((uchar) (A)[4])) +\
+ (((uint32) ((uchar) (A)[5])) << 8) +\
+ (((uint32) ((uchar) (A)[6])) << 16) +\
+ (((uint32) ((uchar) (A)[7])) << 24))) <<\
+ 32))
+#define int2store(T,A) { uint def_temp= (uint) (A) ;\
+ *((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)); \
+ /*lint -restore */}
+#define int4store(T,A) { *(T)=(char) ((A));\
+ *((T)+1)=(char) (((A) >> 8));\
+ *((T)+2)=(char) (((A) >> 16));\
+ *((T)+3)=(char) (((A) >> 24)); }
+#define int5store(T,A) { *(T)=((A));\
+ *((T)+1)=(((A) >> 8));\
+ *((T)+2)=(((A) >> 16));\
+ *((T)+3)=(((A) >> 24)); \
+ *((T)+4)=(((A) >> 32)); }
+#define int8store(T,A) { uint def_temp= (uint) (A), def_temp2= (uint) ((A) >> 32); \
+ int4store((T),def_temp); \
+ int4store((T+4),def_temp2); \
+ }
+#ifdef WORDS_BIGENDIAN
+#define float4store(T,A) { *(T)= ((byte *) &A)[3];\
+ *((T)+1)=(char) ((byte *) &A)[2];\
+ *((T)+2)=(char) ((byte *) &A)[1];\
+ *((T)+3)=(char) ((byte *) &A)[0]; }
+
+#define float4get(V,M) { float def_temp;\
+ ((byte*) &def_temp)[0]=(M)[3];\
+ ((byte*) &def_temp)[1]=(M)[2];\
+ ((byte*) &def_temp)[2]=(M)[1];\
+ ((byte*) &def_temp)[3]=(M)[0];\
+ (V)=def_temp; }
+#define float8store(T,V) { *(T)= ((byte *) &V)[7];\
+ *((T)+1)=(char) ((byte *) &V)[6];\
+ *((T)+2)=(char) ((byte *) &V)[5];\
+ *((T)+3)=(char) ((byte *) &V)[4];\
+ *((T)+4)=(char) ((byte *) &V)[3];\
+ *((T)+5)=(char) ((byte *) &V)[2];\
+ *((T)+6)=(char) ((byte *) &V)[1];\
+ *((T)+7)=(char) ((byte *) &V)[0]; }
+
+#define float8get(V,M) { double def_temp;\
+ ((byte*) &def_temp)[0]=(M)[7];\
+ ((byte*) &def_temp)[1]=(M)[6];\
+ ((byte*) &def_temp)[2]=(M)[5];\
+ ((byte*) &def_temp)[3]=(M)[4];\
+ ((byte*) &def_temp)[4]=(M)[3];\
+ ((byte*) &def_temp)[5]=(M)[2];\
+ ((byte*) &def_temp)[6]=(M)[1];\
+ ((byte*) &def_temp)[7]=(M)[0];\
+ (V) = def_temp; }
+#else
+#define float4get(V,M) memcpy_fixed((byte*) &V,(byte*) (M),sizeof(float))
+#define float4store(V,M) memcpy_fixed((byte*) V,(byte*) (&M),sizeof(float))
+#define float8get(V,M) doubleget((V),(M))
+#define float8store(V,M) doublestore((V),(M))
+#endif /* WORDS_BIGENDIAN */
+
+#endif /* sint2korr */
+
+/* Define-funktions for reading and storing in machine format from/to
+ short/long to/from some place in memory V should be a (not
+ register) variable, M is a pointer to byte */
+
+#ifdef WORDS_BIGENDIAN
+
+#define ushortget(V,M) { V = (uint16) (((uint16) ((uchar) (M)[1]))+\
+ ((uint16) ((uint16) (M)[0]) << 8)); }
+#define shortget(V,M) { V = (short) (((short) ((uchar) (M)[1]))+\
+ ((short) ((short) (M)[0]) << 8)); }
+#define longget(V,M) { int32 def_temp;\
+ ((byte*) &def_temp)[0]=(M)[0];\
+ ((byte*) &def_temp)[1]=(M)[1];\
+ ((byte*) &def_temp)[2]=(M)[2];\
+ ((byte*) &def_temp)[3]=(M)[3];\
+ (V)=def_temp; }
+#define ulongget(V,M) { uint32 def_temp;\
+ ((byte*) &def_temp)[0]=(M)[0];\
+ ((byte*) &def_temp)[1]=(M)[1];\
+ ((byte*) &def_temp)[2]=(M)[2];\
+ ((byte*) &def_temp)[3]=(M)[3];\
+ (V)=def_temp; }
+#define shortstore(T,A) { uint def_temp=(uint) (A) ;\
+ *(T+1)=(char)(def_temp); \
+ *(T+0)=(char)(def_temp >> 8); }
+#define longstore(T,A) { *((T)+3)=((A));\
+ *((T)+2)=(((A) >> 8));\
+ *((T)+1)=(((A) >> 16));\
+ *((T)+0)=(((A) >> 24)); }
+
+#define doubleget(V,M) memcpy((byte*) &V,(byte*) (M),sizeof(double))
+#define doublestore(T,V) memcpy((byte*) (T),(byte*) &V,sizeof(double))
+#define longlongget(V,M) memcpy((byte*) &V,(byte*) (M),sizeof(ulonglong))
+#define longlongstore(T,V) memcpy((byte*) (T),(byte*) &V,sizeof(ulonglong))
+
+#else
+
+#define ushortget(V,M) { V = uint2korr(M); }
+#define shortget(V,M) { V = sint2korr(M); }
+#define longget(V,M) { V = sint4korr(M); }
+#define ulongget(V,M) { V = uint4korr(M); }
+#define shortstore(T,V) int2store(T,V)
+#define longstore(T,V) int4store(T,V)
+#ifndef doubleget
+#define doubleget(V,M) memcpy_fixed((byte*) &V,(byte*) (M),sizeof(double))
+#define doublestore(T,V) memcpy_fixed((byte*) (T),(byte*) &V,sizeof(double))
+#endif
+#define longlongget(V,M) memcpy_fixed((byte*) &V,(byte*) (M),sizeof(ulonglong))
+#define longlongstore(T,V) memcpy_fixed((byte*) (T),(byte*) &V,sizeof(ulonglong))
+
+#endif /* WORDS_BIGENDIAN */
+
+/* sprintf does not always return the number of bytes :- */
+#ifdef SPRINTF_RETURNS_INT
+#define my_sprintf(buff,args) sprintf args
+#else
+#ifdef SPRINTF_RETURNS_PTR
+#define my_sprintf(buff,args) ((int)(sprintf args - buff))
+#else
+#define my_sprintf(buff,args) sprintf args,strlen(buff)
+#endif
+#endif
+
+
+#endif /* _global_h */
diff --git a/include/hash.h b/include/hash.h
new file mode 100644
index 00000000000..c98b0851645
--- /dev/null
+++ b/include/hash.h
@@ -0,0 +1,65 @@
+/* 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 */
+
+/* Dynamic hashing of record with different key-length */
+
+#ifndef _hash_h
+#define _hash_h
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef byte *(*hash_get_key)(const byte *,uint*,my_bool);
+typedef void (*hash_free_key)(void *);
+
+ /* flags for hash_init */
+#define HASH_CASE_INSENSITIVE 1
+
+typedef struct st_hash_info {
+ uint next; /* index to next key */
+ byte *data; /* data for current entry */
+} HASH_LINK;
+
+typedef struct st_hash {
+ uint key_offset,key_length; /* Length of key if const length */
+ uint records,blength,current_record;
+ uint flags;
+ DYNAMIC_ARRAY array; /* Place for hash_keys */
+ hash_get_key get_key;
+ void (*free)(void *);
+ uint (*calc_hashnr)(const byte *key,uint length);
+} HASH;
+
+my_bool hash_init(HASH *hash,uint default_array_elements, uint key_offset,
+ uint key_length, hash_get_key get_key,
+ void (*free_element)(void*), uint flags);
+void hash_free(HASH *tree);
+byte *hash_element(HASH *hash,uint idx);
+gptr hash_search(HASH *info,const byte *key,uint length);
+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);
+my_bool hash_check(HASH *hash); /* Only in debug library */
+
+#define hash_clear(H) bzero((char*) (H),sizeof(*(H)))
+#define hash_inited(H) ((H)->array.buffer != 0)
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/include/heap.h b/include/heap.h
new file mode 100644
index 00000000000..74b37b0c534
--- /dev/null
+++ b/include/heap.h
@@ -0,0 +1,181 @@
+/* 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 should be included when using heap_database_funktions */
+/* Author: Michael Widenius */
+
+#ifndef _heap_h
+#define _heap_h
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef _my_base_h
+#include <my_base.h>
+#endif
+#ifdef THREAD
+#include <my_pthread.h>
+#include <thr_lock.h>
+#endif
+
+ /* defines used by heap-funktions */
+
+#define HP_MAX_LEVELS 4 /* 128^5 records is enough */
+#define HP_PTRS_IN_NOD 128
+
+ /* struct used with heap_funktions */
+
+typedef struct st_heapinfo /* Struct from heap_info */
+{
+ ulong records; /* Records in database */
+ ulong deleted; /* Deleted records in database */
+ ulong max_records;
+ ulong data_length;
+ ulong index_length;
+ uint reclength; /* Length of one record */
+ int errkey;
+} HEAPINFO;
+
+
+ /* Structs used by heap-database-handler */
+
+typedef struct st_heap_ptrs
+{
+ byte *blocks[HP_PTRS_IN_NOD]; /* pointers to HP_PTRS or records */
+} HP_PTRS;
+
+struct st_level_info
+{
+ uint free_ptrs_in_block,records_under_level;
+ HP_PTRS *last_blocks; /* pointers to HP_PTRS or records */
+};
+
+typedef struct st_heap_block /* The data is saved in blocks */
+{
+ HP_PTRS *root;
+ struct st_level_info level_info[HP_MAX_LEVELS+1];
+ uint levels;
+ uint records_in_block; /* Records in a heap-block */
+ uint recbuffer; /* Length of one saved record */
+ ulong last_allocated; /* Blocks allocated, used by keys */
+} HP_BLOCK;
+
+typedef struct st_hp_keyseg /* Key-portion */
+{
+ uint start; /* Start of key in record (from 0) */
+ uint length; /* Keylength */
+ uint type;
+} HP_KEYSEG;
+
+typedef struct st_hp_keydef /* Key definition with open */
+{
+ uint flag; /* NOSAME */
+ uint keysegs; /* Number of key-segment */
+ uint length; /* Length of key (automatic) */
+ HP_KEYSEG *seg;
+ HP_BLOCK block; /* Where keys are saved */
+} HP_KEYDEF;
+
+typedef struct st_heap_share
+{
+ HP_BLOCK block;
+ HP_KEYDEF *keydef;
+ ulong min_records,max_records; /* Params to open */
+ ulong data_length,index_length;
+ uint records; /* records */
+ uint blength;
+ uint deleted; /* Deleted records in database */
+ uint reclength; /* Length of one record */
+ uint changed;
+ uint keys,max_key_length;
+ uint open_count;
+ byte *del_link; /* Link to next block with del. rec */
+ my_string name; /* Name of "memory-file" */
+#ifdef THREAD
+ THR_LOCK lock;
+ pthread_mutex_t intern_lock; /* Locking for use with _locking */
+#endif
+ LIST open_list;
+} HP_SHARE;
+
+struct st_hash_info;
+
+typedef struct st_heap_info
+{
+ HP_SHARE *s;
+ byte *current_ptr;
+ struct st_hash_info *current_hash_ptr;
+ ulong current_record,next_block;
+ int lastinx,errkey;
+ int mode; /* Mode of file (READONLY..) */
+ uint opt_flag,update;
+ byte *lastkey; /* Last used key with rkey */
+#ifdef THREAD
+ THR_LOCK_DATA lock;
+#endif
+ LIST open_list;
+} HP_INFO;
+
+ /* Prototypes for heap-functions */
+
+extern HP_INFO* heap_open(const char *name,int mode,uint keys,
+ HP_KEYDEF *keydef,uint reclength,
+ ulong max_records,ulong min_reloc);
+extern int heap_close(HP_INFO *info);
+extern int heap_write(HP_INFO *info,const byte *buff);
+extern int heap_update(HP_INFO *info,const byte *old,const byte *newdata);
+extern int heap_rrnd(HP_INFO *info,byte *buf,byte *pos);
+extern int heap_scan_init(HP_INFO *info);
+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_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);
+extern int heap_rsame(HP_INFO *info,byte *record,int inx);
+extern int heap_rnext(HP_INFO *info,byte *record);
+extern int heap_rprev(HP_INFO *info,byte *record);
+extern int heap_rfirst(HP_INFO *info,byte *record);
+extern int heap_rlast(HP_INFO *info,byte *record);
+extern void heap_clear(HP_INFO *info);
+extern int heap_rkey(HP_INFO *info,byte *record,int inx,const byte *key);
+extern gptr heap_find(HP_INFO *info,int inx,const byte *key);
+extern int heap_check_heap(HP_INFO *info);
+extern byte *heap_position(HP_INFO *info);
+
+/* The following is for programs that uses the old HEAP interface where
+ pointer to rows where a long instead of a (byte*).
+*/
+
+#if defined(WANT_OLD_HEAP_VERSION) || defined(OLD_HEAP_VERSION)
+extern int heap_rrnd_old(HP_INFO *info,byte *buf,ulong pos);
+extern ulong heap_position_old(HP_INFO *info);
+#endif
+#ifdef OLD_HEAP_VERSION
+typedef ulong HEAP_PTR;
+#define heap_position(A) heap_position_old(A)
+#define heap_rrnd(A,B,C) heap_rrnd_old(A,B,C)
+#else
+typedef byte *HEAP_PTR;
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/include/m_ctype.h b/include/m_ctype.h
new file mode 100644
index 00000000000..438b7b34c9a
--- /dev/null
+++ b/include/m_ctype.h
@@ -0,0 +1,157 @@
+/* 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 */
+
+/*
+ A better inplementation of the UNIX ctype(3) library.
+ Notes: global.h should be included before ctype.h
+*/
+
+#ifndef _m_ctype_h
+#define _m_ctype_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define CHARSET_DIR "charsets/"
+
+typedef struct charset_info_st
+{
+ uint number;
+ const char *name;
+ uchar *ctype;
+ uchar *to_lower;
+ uchar *to_upper;
+ uchar *sort_order;
+
+ uint strxfrm_multiply;
+ int (*strcoll)(const uchar *, const uchar *);
+ int (*strxfrm)(uchar *, const uchar *, int);
+ int (*strnncoll)(const uchar *, int, const uchar *, int);
+ int (*strnxfrm)(uchar *, const uchar *, int, int);
+ my_bool (*like_range)(const char *, uint, pchar, uint,
+ char *, char *, uint *, uint *);
+
+ uint mbmaxlen;
+ int (*ismbchar)(const char *, const char *);
+ my_bool (*ismbhead)(uint);
+ int (*mbcharlen)(uint);
+} CHARSET_INFO;
+
+/* strings/ctype.c */
+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[];
+
+#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_INCLUDED
+#define __CTYPE_INCLUDED
+#define _CTYPE_USING /* Don't put names in global namespace. */
+
+#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 _B 0100 /* Blank */
+#define _X 0200 /* heXadecimal digit */
+
+#define my_ctype (default_charset_info->ctype)
+#define my_to_upper (default_charset_info->to_upper)
+#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)]
+#define tolower(c) (char) my_to_lower[(uchar) (c)]
+
+#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 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 isascii(c) (!((c) & ~0177))
+#define toascii(c) ((c) & 0177)
+
+#ifdef ctype
+#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_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 use_strcoll(s) ((s)->strcoll != NULL)
+#define MY_STRXFRM_MULTIPLY (default_charset_info->strxfrm_multiply)
+#define my_strnxfrm(s, a, b, c, d) ((s)->strnxfrm((a), (b), (c), (d)))
+#define my_strnncoll(s, a, b, c, d) ((s)->strnncoll((a), (b), (c), (d)))
+#define my_strxfrm(s, a, b, c, d) ((s)->strnxfrm((a), (b), (c)))
+#define my_strcoll(s, a, b) ((s)->strcoll((a), (b)))
+#define my_like_range(s, a, b, c, d, e, f, g, h) \
+ ((s)->like_range((a), (b), (c), (d), (e), (f), (g), (h)))
+
+#define use_mb(s) ((s)->ismbchar != NULL)
+#define MBMAXLEN (default_charset_info->mbmaxlen)
+#define my_ismbchar(s, a, b) ((s)->ismbchar((a), (b)))
+#define my_ismbhead(s, a) ((s)->ismbhead((a)))
+#define my_mbcharlen(s, a) ((s)->mbcharlen((a)))
+
+/* Some macros that should be cleaned up a little */
+#define isvar(c) (isalnum(c) || (c) == '_')
+#define isvar_start(c) (isalpha(c) || (c) == '_')
+#define tocntrl(c) ((c) & 31)
+#define toprint(c) ((c) | 64)
+
+/* XXX: still need to take care of this one */
+#ifdef MY_CHARSET_TIS620
+#error The TIS620 charset is broken at the moment. Tell tim to fix it.
+#define USE_TIS620
+#include "t_ctype.h"
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _m_ctype_h */
diff --git a/include/m_string.h b/include/m_string.h
new file mode 100644
index 00000000000..c17e928ea37
--- /dev/null
+++ b/include/m_string.h
@@ -0,0 +1,241 @@
+/* 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 */
+
+/* There may be prolems include all of theese. Try to test in
+ configure with ones are needed? */
+
+/* This is needed for the definitions of strchr... on solaris */
+
+#ifndef _m_string_h
+#define _m_string_h
+#ifndef __USE_GNU
+#define __USE_GNU /* We want to use stpcpy */
+#endif
+#if defined(HAVE_STRINGS_H)
+#include <strings.h>
+#endif
+#if defined(HAVE_STRING_H)
+#include <string.h>
+#endif
+
+/* Correct some things for UNIXWARE7 */
+#ifdef HAVE_UNIXWARE7_THREADS
+#undef HAVE_STRINGS_H
+#undef HAVE_MEMORY_H
+#define HAVE_MEMCPY
+#ifndef HAVE_MEMMOVE
+#define HAVE_MEMMOVE
+#endif
+#undef HAVE_BCMP
+#undef bcopy
+#undef bcmp
+#undef bzero
+#endif /* HAVE_UNIXWARE7_THREADS */
+#ifdef _AIX
+#undef HAVE_BCMP
+#endif
+
+/* This is needed for the definitions of bzero... on solaris */
+#if defined(HAVE_STRINGS_H) && !defined(HAVE_mit_thread)
+#include <strings.h>
+#endif
+
+/* This is needed for the definitions of memcpy... on solaris */
+#if defined(HAVE_MEMORY_H) && !defined(__cplusplus)
+#include <memory.h>
+#endif
+
+#if !defined(HAVE_MEMCPY) && !defined(HAVE_MEMMOVE)
+# define memcpy(d, s, n) bcopy ((s), (d), (n))
+# define memset(A,C,B) bfill((A),(B),(C))
+# define memmove(d, s, n) bmove ((s), (d), (n))
+#elif defined(HAVE_MEMMOVE)
+# define bmove(d, s, n) memmove((d), (s), (n))
+#else
+# define memmove(d, s, n) bmove((d), (s), (n)) /* our bmove */
+#endif
+
+#if defined(HAVE_STPCPY) && !defined(HAVE_mit_thread)
+#define strmov(A,B) stpcpy((A),(B))
+#endif
+
+/* Unixware 7 */
+#if !defined(HAVE_BFILL)
+# define bfill(A,B,C) memset((A),(C),(B))
+# define bmove_allign(A,B,C) memcpy((A),(B),(C))
+#endif
+
+#if !defined(HAVE_BCMP)
+# define bcopy(s, d, n) memcpy((d), (s), (n))
+# define bcmp(A,B,C) memcmp((A),(B),(C))
+# define bzero(A,B) memset((A),0,(B))
+# define bmove_allign(A,B,C) memcpy((A),(B),(C))
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern char NEAR _dig_vec[]; /* Declared in int2str() */
+
+#ifdef BAD_STRING_COMPILER
+#define strmov(A,B) (memccpy(A,B,0,INT_MAX)-1)
+#else
+#define strmov_overlapp(A,B) strmov(A,B)
+#define strmake_overlapp(A,B,C) strmake(A,B,C)
+#endif
+
+#ifdef BAD_MEMCPY /* Problem with gcc on Alpha */
+#define memcpy_fixed(A,B,C) bmove((A),(B),(C))
+#else
+#define memcpy_fixed(A,B,C) memcpy((A),(B),(C))
+#endif
+
+#ifdef MSDOS
+#undef bmove_allign
+#define bmove512(A,B,C) bmove_allign(A,B,C)
+#define my_itoa(A,B,C) itoa(A,B,C)
+#define my_ltoa(A,B,C) ltoa(A,B,C)
+extern void bmove_allign(gptr dst,const gptr src,uint len);
+#endif
+
+#if (!defined(USE_BMOVE512) || defined(HAVE_purify)) && !defined(bmove512)
+#define bmove512(A,B,C) memcpy(A,B,C)
+#endif
+
+ /* Prototypes for string functions */
+
+#if !defined(bfill) && !defined(HAVE_BFILL)
+extern void bfill(gptr dst,uint len,pchar fill);
+#endif
+
+#if !defined(bzero) && !defined(HAVE_BZERO)
+extern void bzero(gptr dst,uint len);
+#endif
+
+#if !defined(bcmp) && !defined(HAVE_BCMP)
+extern int bcmp(const char *s1,const char *s2,uint len);
+#ifdef HAVE_purify
+extern int my_bcmp(const char *s1,const char *s2,uint len);
+#define bcmp(A,B,C) my_bcmp((A),(B),(C))
+#endif
+#endif
+
+#ifndef bmove512
+extern void bmove512(gptr dst,const gptr src,uint len);
+#endif
+
+#if !defined(HAVE_BMOVE) && !defined(bmove)
+extern void bmove(gptr dst,const char *src,uint len);
+#endif
+
+extern void bmove_upp(char *dst,const char *src,uint len);
+extern void bchange(char *dst,uint old_len,const char *src,
+ uint new_len,uint tot_len);
+extern void strappend(char *s,uint len,pchar fill);
+extern char *strend(const char *s);
+extern char *strcend(const char *, pchar);
+extern char *strfield(char *src,int fields,int chars,int blanks,
+ int tabch);
+extern char *strfill(my_string s,uint len,pchar fill);
+extern uint strinstr(const char *str,const char *search);
+extern uint r_strinstr(reg1 my_string str,int from, reg4 my_string search);
+extern char *strkey(char *dst,char *head,char *tail,char *flags);
+extern char *strmake(char *dst,const char *src,uint length);
+#ifndef strmake_overlapp
+extern char *strmake_overlapp(char *dst,const char *src, uint length);
+#endif
+
+#ifndef strmov
+extern char *strmov(char *dst,const char *src);
+#endif
+extern char *strnmov(char *dst,const char *src,uint n);
+extern char *strsuff(const char *src,const char *suffix);
+extern char *strcont(const char *src,const char *set);
+extern char *strxcat _VARARGS((char *dst,const char *src, ...));
+extern char *strxmov _VARARGS((char *dst,const char *src, ...));
+extern char *strxcpy _VARARGS((char *dst,const char *src, ...));
+extern char *strxncat _VARARGS((char *dst,uint len, const char *src, ...));
+extern char *strxnmov _VARARGS((char *dst,uint len, const char *src, ...));
+extern char *strxncpy _VARARGS((char *dst,uint len, const char *src, ...));
+
+/* Prototypes of normal stringfunctions (with may ours) */
+
+#ifdef WANT_STRING_PROTOTYPES
+extern char *strcat(char *, const char *);
+extern char *strchr(const char *, pchar);
+extern char *strrchr(const char *, pchar);
+extern char *strcpy(char *, const char *);
+extern int strcmp(const char *, const char *);
+#ifndef __GNUC__
+extern size_t strlen(const char *);
+#endif
+#endif
+#ifndef HAVE_STRNLEN
+extern uint strnlen(const char *s, uint n);
+#endif
+
+#if !defined(__cplusplus)
+#ifndef HAVE_STRPBRK
+extern char *strpbrk(const char *, const char *);
+#endif
+#ifndef HAVE_STRSTR
+extern char *strstr(const char *, const char *);
+#endif
+#endif
+extern int is_prefix(const char *, const char *);
+
+/* Conversion rutins */
+
+#ifdef USE_MY_ITOA
+extern char *my_itoa(int val,char *dst,int radix);
+extern char *my_ltoa(long val,char *dst,int radix);
+#endif
+
+extern char *llstr(longlong value,char *buff);
+#ifndef HAVE_STRTOUL
+extern long strtol(const char *str, char **ptr, int base);
+extern ulong strtoul(const char *str, char **ptr, int base);
+#endif
+
+extern char *int2str(long val,char *dst,int radix);
+extern char *int10_to_str(long val,char *dst,int radix);
+extern char *str2int(const char *src,int radix,long lower,long upper,
+ long *val);
+#if SIZEOF_LONG == SIZEOF_LONG_LONG
+#define longlong2str(A,B,C) int2str((A),(B),(C))
+#define longlong10_to_str(A,B,C) int10_to_str((A),(B),(C))
+#define strtoll(A,B,C) strtol((A),(B),(C))
+#define strtoull(A,B,C) strtoul((A),(B),(C))
+#ifndef HAVE_STRTOULL
+#define HAVE_STRTOULL
+#endif
+#else
+#ifdef HAVE_LONG_LONG
+extern char *longlong2str(longlong val,char *dst,int radix);
+extern char *longlong10_to_str(longlong val,char *dst,int radix);
+#if (!defined(HAVE_STRTOULL) || defined(HAVE_mit_thread)) || defined(NO_STRTOLL_PROTO)
+extern longlong strtoll(const char *str, char **ptr, int base);
+extern ulonglong strtoull(const char *str, char **ptr, int base);
+#endif
+#endif
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/include/merge.h b/include/merge.h
new file mode 100644
index 00000000000..b090e49b471
--- /dev/null
+++ b/include/merge.h
@@ -0,0 +1,94 @@
+/* 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 should be included when using merge_isam_funktions */
+/* Author: Michael Widenius */
+
+#ifndef _merge_h
+#define _merge_h
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef _my_base_h
+#include <my_base.h>
+#endif
+#ifndef _nisam_h
+#include <nisam.h>
+#endif
+
+#define MRG_NAME_EXT ".MRG"
+
+ /* Param to/from mrg_info */
+
+typedef struct st_mrg_info /* Struct from h_info */
+{
+ ulonglong records; /* Records in database */
+ ulonglong deleted; /* Deleted records in database */
+ ulonglong recpos; /* Pos for last used record */
+ ulonglong data_file_length;
+ uint reclength; /* Recordlength */
+ int errkey; /* With key was dupplicated on err */
+ uint options; /* HA_OPTIONS_... used */
+} MERGE_INFO;
+
+typedef struct st_mrg_table_info
+{
+ N_INFO *table;
+ ulonglong file_offset;
+} MRG_TABLE;
+
+typedef struct st_merge
+{
+ MRG_TABLE *open_tables,*current_table,*end_table,*last_used_table;
+ ulonglong records; /* records in tables */
+ ulonglong del; /* Removed records */
+ ulonglong data_file_length;
+ uint tables,options,reclength;
+ my_bool cache_in_use;
+ LIST open_list;
+} MRG_INFO;
+
+typedef ulong mrg_off_t;
+
+ /* Prototypes for merge-functions */
+
+extern int mrg_close(MRG_INFO *file);
+extern int mrg_delete(MRG_INFO *file,const byte *buff);
+extern MRG_INFO *mrg_open(const char *name,int mode,int wait_if_locked);
+extern int mrg_panic(enum ha_panic_function function);
+extern int mrg_rfirst(MRG_INFO *file,byte *buf,int inx);
+extern int mrg_rkey(MRG_INFO *file,byte *buf,int inx,const byte *key,
+ uint key_len, enum ha_rkey_function search_flag);
+extern int mrg_rrnd(MRG_INFO *file,byte *buf, mrg_off_t pos);
+extern int mrg_rsame(MRG_INFO *file,byte *record,int inx);
+extern int mrg_update(MRG_INFO *file,const byte *old,const byte *new_rec);
+extern int mrg_info(MRG_INFO *file,MERGE_INFO *x,int flag);
+extern int mrg_lock_database(MRG_INFO *file,int lock_type);
+extern int mrg_create(const char *name,const char **table_names);
+extern int mrg_extra(MRG_INFO *file,enum ha_extra_function function);
+extern ha_rows mrg_records_in_range(MRG_INFO *info,int inx,
+ const byte *start_key,uint start_key_len,
+ enum ha_rkey_function start_search_flag,
+ const byte *end_key,uint end_key_len,
+ enum ha_rkey_function end_search_flag);
+
+extern mrg_off_t mrg_position(MRG_INFO *info);
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/include/my_alarm.h b/include/my_alarm.h
new file mode 100644
index 00000000000..b6c5ca6a3f4
--- /dev/null
+++ b/include/my_alarm.h
@@ -0,0 +1,60 @@
+/* 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 */
+
+/*
+ File to include when we want to use alarm or a loop_counter to display
+ some information when a program is running
+*/
+#ifndef _my_alarm_h
+#define _my_alarm_h
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern int volatile my_have_got_alarm;
+extern ulong my_time_to_wait_for_lock;
+
+#if defined(HAVE_ALARM) && !defined(NO_ALARM_LOOP)
+#include <signal.h>
+#define ALARM_VARIABLES uint alarm_old=0; \
+ sig_return alarm_signal=0
+#define ALARM_INIT my_have_got_alarm=0 ; \
+ alarm_old=(uint) alarm(MY_HOW_OFTEN_TO_ALARM); \
+ alarm_signal=signal(SIGALRM,my_set_alarm_variable);
+#define ALARM_END VOID(signal(SIGALRM,alarm_signal)); \
+ VOID(alarm(alarm_old));
+#define ALARM_TEST my_have_got_alarm
+#ifdef DONT_REMEMBER_SIGNAL
+#define ALARM_REINIT VOID(alarm(MY_HOW_OFTEN_TO_ALARM)); \
+ VOID(signal(SIGALRM,my_set_alarm_variable));\
+ my_have_got_alarm=0;
+#else
+#define ALARM_REINIT VOID(alarm((uint) MY_HOW_OFTEN_TO_ALARM)); \
+ my_have_got_alarm=0;
+#endif /* DONT_REMEMBER_SIGNAL */
+#else
+#define ALARM_VARIABLES long alarm_pos=0,alarm_end_pos=MY_HOW_OFTEN_TO_WRITE-1
+#define ALARM_INIT
+#define ALARM_END
+#define ALARM_TEST (alarm_pos++ >= alarm_end_pos)
+#define ALARM_REINIT alarm_end_pos+=MY_HOW_OFTEN_TO_WRITE
+#endif /* HAVE_ALARM */
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/include/my_base.h b/include/my_base.h
new file mode 100644
index 00000000000..429c7132444
--- /dev/null
+++ b/include/my_base.h
@@ -0,0 +1,265 @@
+/* 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 includes constants used with all databases */
+/* Author: Michael Widenius */
+
+#ifndef _my_base_h
+#define _my_base_h
+
+#ifndef stdin /* Included first in handler */
+#define USES_TYPES /* my_dir with sys/types is included */
+#define CHSIZE_USED
+#include <global.h>
+#include <my_dir.h> /* This includes types */
+#include <my_sys.h>
+#include <m_string.h>
+#include <errno.h>
+#ifdef MSDOS
+#include <share.h> /* Neaded for sopen() */
+#endif
+#if !defined(USE_MY_FUNC) && !defined(THREAD)
+#include <my_nosys.h> /* For faster code, after test */
+#endif /* USE_MY_FUNC */
+#endif /* stdin */
+#include <my_list.h>
+
+/* The following is bits in the flag parameter to ha_open() */
+
+#define HA_OPEN_ABORT_IF_LOCKED 0 /* default */
+#define HA_OPEN_WAIT_IF_LOCKED 1
+#define HA_OPEN_IGNORE_IF_LOCKED 2
+#define HA_OPEN_TMP_TABLE 4
+#define HA_OPEN_DELAY_KEY_WRITE 8
+
+ /* The following is parameter to ha_rkey() how to use key */
+
+enum ha_rkey_function {
+ HA_READ_KEY_EXACT, /* Find first record else error */
+ HA_READ_KEY_OR_NEXT, /* Record or next record */
+ HA_READ_KEY_OR_PREV, /* Record or previous */
+ 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 */
+};
+
+ /* The following is parameter to ha_extra() */
+
+enum ha_extra_function {
+ HA_EXTRA_NORMAL=0, /* Optimize for space (def) */
+ HA_EXTRA_QUICK=1, /* Optimize for speed */
+ HA_EXTRA_RESET=2, /* Reset database to after open */
+ HA_EXTRA_CACHE=3, /* Cash record in HA_rrnd() */
+ HA_EXTRA_NO_CACHE=4, /* End cacheing of records (def) */
+ HA_EXTRA_NO_READCHECK=5, /* No readcheck on update */
+ HA_EXTRA_READCHECK=6, /* Use readcheck (def) */
+ HA_EXTRA_KEYREAD=7, /* Read only key to database */
+ HA_EXTRA_NO_KEYREAD=8, /* Normal read of records (def) */
+ HA_EXTRA_NO_USER_CHANGE=9, /* No user is allowed to write */
+ HA_EXTRA_KEY_CACHE=10,
+ HA_EXTRA_NO_KEY_CACHE=11,
+ HA_EXTRA_WAIT_LOCK=12, /* Wait until file is avalably (def) */
+ HA_EXTRA_NO_WAIT_LOCK=13, /* If file is locked, return quickly */
+ HA_EXTRA_WRITE_CACHE=14, /* Use write cache in ha_write() */
+ HA_EXTRA_FLUSH_CACHE=15, /* flush write_record_cache */
+ HA_EXTRA_NO_KEYS=16, /* Remove all update of keys */
+ HA_EXTRA_KEYREAD_CHANGE_POS=17, /* Keyread, but change pos */
+ /* xxxxchk -r must be used */
+ HA_EXTRA_REMEMBER_POS=18, /* Remember pos for next/prev */
+ HA_EXTRA_RESTORE_POS=19,
+ HA_EXTRA_REINIT_CACHE=20, /* init cache from current record */
+ HA_EXTRA_FORCE_REOPEN=21, /* Datafile have changed on disk */
+ HA_EXTRA_FLUSH, /* Flush tables to disk */
+ HA_EXTRA_NO_ROWS /* Don't write rows */
+};
+
+ /* The following is parameter to ha_panic() */
+
+enum ha_panic_function {
+ HA_PANIC_CLOSE, /* Close all databases */
+ HA_PANIC_WRITE, /* Unlock and write status */
+ HA_PANIC_READ /* Lock and read keyinfo */
+};
+
+ /* The following is parameter to ha_create(); keytypes */
+
+enum ha_base_keytype {
+ HA_KEYTYPE_END=0,
+ HA_KEYTYPE_TEXT=1, /* Key is sorted as letters */
+ HA_KEYTYPE_BINARY=2, /* Key is sorted as unsigned chars */
+ HA_KEYTYPE_SHORT_INT=3,
+ HA_KEYTYPE_LONG_INT=4,
+ HA_KEYTYPE_FLOAT=5,
+ HA_KEYTYPE_DOUBLE=6,
+ HA_KEYTYPE_NUM=7, /* Not packed num with pre-space */
+ HA_KEYTYPE_USHORT_INT=8,
+ HA_KEYTYPE_ULONG_INT=9,
+ HA_KEYTYPE_LONGLONG=10,
+ HA_KEYTYPE_ULONGLONG=11,
+ HA_KEYTYPE_INT24=12,
+ HA_KEYTYPE_UINT24=13,
+ HA_KEYTYPE_INT8=14,
+ HA_KEYTYPE_VARTEXT=15, /* Key is sorted as letters */
+ HA_KEYTYPE_VARBINARY=16 /* Key is sorted as unsigned chars */
+};
+
+#define HA_MAX_KEYTYPE 31 /* Must be log2-1 */
+
+ /* These flags kan be OR:ed to key-flag */
+
+#define HA_NOSAME 1 /* Set if not dupplicated records */
+#define HA_PACK_KEY 2 /* Pack string key to previous key */
+#define HA_AUTO_KEY 16
+#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 */
+
+ /* Automatic bits in key-flag */
+
+#define HA_SPACE_PACK_USED 4 /* Test for if SPACE_PACK used */
+#define HA_VAR_LENGTH_KEY 8
+#define HA_NULL_PART_KEY 64
+#ifndef ISAM_LIBRARY
+#define HA_SORT_ALLOWS_SAME 512 /* Intern bit when sorting records */
+#else
+/* poor old NISAM has 8-bit flags :-( */
+#define HA_SORT_ALLOWS_SAME 128 /* Intern bit when sorting records */
+#endif
+
+ /* These flags can be order to key-seg-flag */
+
+#define HA_SPACE_PACK 1 /* Pack space in key-seg */
+#define HA_PART_KEY 4 /* Used by MySQL for part-key-cols */
+#define HA_VAR_LENGTH 8
+#define HA_NULL_PART 16
+#define HA_BLOB_PART 32
+#define HA_SWAP_KEY 64
+#define HA_REVERSE_SORT 128 /* Sort key in reverse order */
+
+ /* optionbits for database */
+#define HA_OPTION_PACK_RECORD 1
+#define HA_OPTION_PACK_KEYS 2
+#define HA_OPTION_COMPRESS_RECORD 4
+#define HA_OPTION_LONG_BLOB_PTR 8 /* new ISAM format */
+#define HA_OPTION_TMP_TABLE 16
+#define HA_OPTION_CHECKSUM 32
+#define HA_OPTION_DELAY_KEY_WRITE 64
+#define HA_OPTION_NO_PACK_KEYS 128 /* Reserved for MySQL */
+#define HA_OPTION_TEMP_COMPRESS_RECORD ((uint) 16384) /* set by isamchk */
+#define HA_OPTION_READ_ONLY_DATA ((uint) 32768) /* Set by isamchk */
+
+ /* Bits in flag to ni_create() */
+
+#define HA_DONT_TOUCH_DATA 1 /* Don't empty datafile (isamchk) */
+#define HA_PACK_RECORD 2 /* Request packed record format */
+#define HA_CREATE_TMP_TABLE 4
+#define HA_CREATE_CHECKSUM 8
+#define HA_CREATE_DELAY_KEY_WRITE 64
+
+ /* Bits in flag to _status */
+
+#define HA_STATUS_POS 1 /* Return position */
+#define HA_STATUS_NO_LOCK 2 /* Don't use external lock */
+#define HA_STATUS_TIME 4 /* Return update time */
+#define HA_STATUS_CONST 8 /* Return constants values */
+#define HA_STATUS_VARIABLE 16
+#define HA_STATUS_ERRKEY 32
+#define HA_STATUS_AUTO 64
+
+ /* Errorcodes given by functions */
+
+#define HA_ERR_KEY_NOT_FOUND 120 /* Didn't find key on read or update */
+#define HA_ERR_FOUND_DUPP_KEY 121 /* Dupplicate key on write */
+#define HA_ERR_RECORD_CHANGED 123 /* Uppdate with is recoverable */
+#define HA_ERR_WRONG_INDEX 124 /* Wrong index given to function */
+#define HA_ERR_CRASHED 126 /* Indexfile is crashed */
+#define HA_ERR_WRONG_IN_RECORD 127 /* Record-file is crashed */
+#define HA_ERR_OUT_OF_MEM 128 /* Record-file is crashed */
+#define HA_ERR_WRONG_COMMAND 131 /* Command not supported */
+#define HA_ERR_OLD_FILE 132 /* old databasfile */
+#define HA_ERR_NO_ACTIVE_RECORD 133 /* No record read in update() */
+#define HA_ERR_RECORD_DELETED 134 /* Intern error-code */
+#define HA_ERR_RECORD_FILE_FULL 135 /* No more room in file */
+#define HA_ERR_INDEX_FILE_FULL 136 /* No more room in file */
+#define HA_ERR_END_OF_FILE 137 /* end in next/prev/first/last */
+#define HA_ERR_UNSUPPORTED 138 /* unsupported extension used */
+#define HA_ERR_TO_BIG_ROW 139 /* Too big row */
+#define HA_WRONG_CREATE_OPTION 140 /* Wrong create option */
+#define HA_ERR_FOUND_DUPP_UNIQUE 141 /* Dupplicate unique on write */
+#define HA_ERR_UNKNOWN_CHARSET 142 /* Can't open charset */
+#define HA_ERR_WRONG_TABLE_DEF 143
+
+ /* Other constants */
+
+#define HA_NAMELEN 64 /* Max length of saved filename */
+
+ /* Intern constants in databases */
+
+ /* bits in _search */
+#define SEARCH_FIND 1
+#define SEARCH_NO_FIND 2
+#define SEARCH_SAME 4
+#define SEARCH_BIGGER 8
+#define SEARCH_SMALLER 16
+#define SEARCH_SAVE_BUFF 32
+#define SEARCH_UPDATE 64
+#define SEARCH_PREFIX 128
+#define SEARCH_LAST 256
+
+ /* bits in opt_flag */
+#define QUICK_USED 1
+#define READ_CACHE_USED 2
+#define READ_CHECK_USED 4
+#define KEY_READ_USED 8
+#define WRITE_CACHE_USED 16
+#define OPT_NO_ROWS 32
+
+ /* bits in update */
+#define HA_STATE_CHANGED 1 /* Database has changed */
+#define HA_STATE_AKTIV 2 /* Has a current record */
+#define HA_STATE_WRITTEN 4 /* Record is written */
+#define HA_STATE_DELETED 8
+#define HA_STATE_NEXT_FOUND 16 /* Next found record (record before) */
+#define HA_STATE_PREV_FOUND 32 /* Prev found record (record after) */
+#define HA_STATE_NO_KEY 64 /* Last read didn't find record */
+#define HA_STATE_KEY_CHANGED 128
+#define HA_STATE_WRITE_AT_END 256 /* set in _ps_find_writepos */
+#define HA_STATE_BUFF_SAVED 512 /* If current keybuff is info->buff */
+#define HA_STATE_ROW_CHANGED 1024 /* To invalide ROW cache */
+#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_VARCHAR,FIELD_CHECK
+};
+
+enum data_file_type {
+ STATIC_RECORD,DYNAMIC_RECORD,COMPRESSED_RECORD
+};
+
+/* For number of records */
+#ifdef BIG_TABLES
+typedef my_off_t ha_rows;
+#else
+typedef ulong ha_rows;
+#endif
+
+#define HA_POS_ERROR (~ (ha_rows) 0)
+#define HA_OFFSET_ERROR (~ (my_off_t) 0)
+#endif /* _my_base_h */
diff --git a/include/my_dir.h b/include/my_dir.h
new file mode 100644
index 00000000000..1961ca79549
--- /dev/null
+++ b/include/my_dir.h
@@ -0,0 +1,100 @@
+/* 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 */
+
+#ifndef _my_dir_h
+#define _my_dir_h
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef MY_DIR_H
+#define MY_DIR_H
+
+#include <sys/stat.h>
+
+ /* Defines for my_dir and my_stat */
+
+#define MY_S_IFMT S_IFMT /* type of file */
+#define MY_S_IFDIR S_IFDIR /* directory */
+#define MY_S_IFCHR S_IFCHR /* character special */
+#define MY_S_IFBLK S_IFBLK /* block special */
+#define MY_S_IFREG S_IFREG /* regular */
+#define MY_S_IFIFO S_IFIFO /* fifo */
+#define MY_S_ISUID S_ISUID /* set user id on execution */
+#define MY_S_ISGID S_ISGID /* set group id on execution */
+#define MY_S_ISVTX S_ISVTX /* save swapped text even after use */
+#define MY_S_IREAD S_IREAD /* read permission, owner */
+#define MY_S_IWRITE S_IWRITE /* write permission, owner */
+#define MY_S_IEXEC S_IEXEC /* execute/search permission, owner */
+
+#define MY_S_ISDIR(m) (((m) & MY_S_IFMT) == MY_S_IFDIR)
+#define MY_S_ISCHR(m) (((m) & MY_S_IFMT) == MY_S_IFCHR)
+#define MY_S_ISBLK(m) (((m) & MY_S_IFMT) == MY_S_IFBLK)
+#define MY_S_ISREG(m) (((m) & MY_S_IFMT) == MY_S_IFREG)
+#define MY_S_ISFIFO(m) (((m) & MY_S_IFMT) == MY_S_IFIFO)
+
+#define MY_DONT_SORT 512 /* my_lib; Don't sort files */
+#define MY_WANT_STAT 1024 /* my_lib; stat files */
+
+ /* typedefs for my_dir & my_stat */
+
+#ifdef USE_MY_STAT_STRUCT
+
+typedef struct my_stat
+{
+ dev_t st_dev; /* major & minor device numbers */
+ ino_t st_ino; /* inode number */
+ ushort st_mode; /* file permissons (& suid sgid .. bits) */
+ short st_nlink; /* number of links to file */
+ ushort st_uid; /* user id */
+ ushort st_gid; /* group id */
+ dev_t st_rdev; /* more major & minor device numbers (???) */
+ off_t st_size; /* size of file */
+ time_t st_atime; /* time for last read */
+ time_t st_mtime; /* time for last contens modify */
+ time_t st_ctime; /* time for last inode or contents modify */
+} MY_STAT;
+
+#else
+
+#define MY_STAT struct stat /* Orginal struct have what we need */
+
+#endif /* USE_MY_STAT_STRUCT */
+
+typedef struct fileinfo /* Struct returned from my_dir & my_stat */
+{
+ char *name;
+ MY_STAT mystat;
+} FILEINFO;
+
+typedef struct st_my_dir /* Struct returned from my_dir */
+{
+ struct fileinfo *dir_entry;
+ uint number_off_files;
+} MY_DIR;
+
+extern MY_DIR *my_dir(const char *path,myf MyFlags);
+extern void my_dirend(MY_DIR *buffer);
+extern MY_STAT *my_stat(const char *path, MY_STAT *stat_area, myf my_flags);
+extern int my_fstat(int filenr, MY_STAT *stat_area, myf MyFlags);
+
+#endif /* MY_DIR_H */
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/include/my_list.h b/include/my_list.h
new file mode 100644
index 00000000000..7391db70e27
--- /dev/null
+++ b/include/my_list.h
@@ -0,0 +1,47 @@
+/* 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 */
+
+#ifndef _list_h_
+#define _list_h_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct st_list {
+ struct st_list *prev,*next;
+ void *data;
+} LIST;
+
+typedef int (*list_walk_action)(void *,void *);
+
+extern LIST *list_add(LIST *root,LIST *element);
+extern LIST *list_delete(LIST *root,LIST *element);
+extern LIST *list_cons(void *data,LIST *root);
+extern LIST *list_reverse(LIST *root);
+extern void list_free(LIST *root,pbool free_data);
+extern uint list_length(LIST *list);
+extern int list_walk(LIST *list,list_walk_action action,gptr argument);
+
+#define rest(a) ((a)->next)
+#define list_push(a,b) (a)=list_cons((b),(a))
+#define list_pop(A) {LIST *old=(A); (A)=list_delete(old,old) ; my_free((gptr) old,MYF(MY_FAE)); }
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/include/my_net.h b/include/my_net.h
new file mode 100644
index 00000000000..a02a564c527
--- /dev/null
+++ b/include/my_net.h
@@ -0,0 +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,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should 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 */
+#if !defined(MSDOS) && !defined(__WIN__) && !defined(__BEOS__)
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#endif /* !defined(MSDOS) && !defined(__WIN__) */
+
+void my_inet_ntoa(struct in_addr in, char *buf);
diff --git a/include/my_no_pthread.h b/include/my_no_pthread.h
new file mode 100644
index 00000000000..2ff8896fa74
--- /dev/null
+++ b/include/my_no_pthread.h
@@ -0,0 +1,32 @@
+/* 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 undefs some pthread mutex locks when one isn't using threads
+ to make thread safe code, that should also work in single thread
+ environment, easier to use.
+*/
+
+#if !defined(_my_no_pthread_h) && !defined(THREADS)
+#define _my_no_pthread_h
+
+#define pthread_mutex_init(A,B)
+#define pthread_mutex_lock(A)
+#define pthread_mutex_unlock(A)
+#define pthread_mutex_destroy(A)
+
+#endif
diff --git a/include/my_nosys.h b/include/my_nosys.h
new file mode 100644
index 00000000000..5991904f260
--- /dev/null
+++ b/include/my_nosys.h
@@ -0,0 +1,56 @@
+/* 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 */
+
+/*
+ Header to remove use of my_functions in functions where we need speed and
+ where calls to posix functions should work
+*/
+#ifndef _my_nosys_h
+#define _my_nosys_h
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef __MY_NOSYS__
+#define __MY_NOSYS__
+
+#ifdef MSDOS
+#include <io.h> /* Get prototypes for read()... */
+#endif
+#ifndef HAVE_STDLIB_H
+#include <malloc.h>
+#endif
+
+#undef my_read /* Can be predefined in raid.h */
+#undef my_write
+#undef my_seek
+#define my_read(a,b,c,d) my_quick_read(a,b,c,d)
+#define my_write(a,b,c,d) my_quick_write(a,b,c)
+extern uint my_quick_read(File Filedes,byte *Buffer,uint Count,myf myFlags);
+extern uint my_quick_write(File Filedes,const byte *Buffer,uint Count);
+
+#if !defined(SAFEMALLOC) && defined(USE_HALLOC)
+#define my_malloc(a,b) halloc(a,1)
+#define my_no_flags_free(a) hfree(a)
+#endif
+
+#endif /* __MY_NOSYS__ */
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/include/my_pthread.h b/include/my_pthread.h
new file mode 100644
index 00000000000..9c0d6d1b9d9
--- /dev/null
+++ b/include/my_pthread.h
@@ -0,0 +1,538 @@
+/* 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 */
+
+/* Defines to make different thread packages compatible */
+
+#ifndef _my_pthread_h
+#define _my_pthread_h
+
+#include <errno.h>
+#ifndef ETIME
+#define ETIME ETIMEDOUT // For FreeBSD
+#endif
+
+#if defined(__WIN__)
+
+typedef CRITICAL_SECTION pthread_mutex_t;
+typedef HANDLE pthread_t;
+typedef struct thread_attr {
+ DWORD dwStackSize ;
+ DWORD dwCreatingFlag ;
+ int priority ;
+} pthread_attr_t ;
+
+typedef struct { int dummy; } pthread_condattr_t;
+
+/* Implementation of posix conditions */
+
+typedef struct st_pthread_link {
+ DWORD thread_id;
+ struct st_pthread_link *next;
+} pthread_link;
+
+typedef struct {
+ uint32 waiting;
+ HANDLE semaphore;
+} pthread_cond_t;
+
+
+struct timespec { /* For pthread_cond_timedwait() */
+ time_t tv_sec;
+ long tv_nsec;
+};
+
+#define win_pthread_self my_thread_var->pthread_self
+#define pthread_handler_decl(A,B) unsigned __cdecl A(void *B)
+typedef unsigned (__cdecl *pthread_handler)(void *);
+
+int win_pthread_setspecific(void *A,void *B,uint length);
+int pthread_create(pthread_t *,pthread_attr_t *,pthread_handler,void *);
+int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr);
+int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
+int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
+ struct timespec *abstime);
+int pthread_cond_signal(pthread_cond_t *cond);
+int pthread_cond_broadcast(pthread_cond_t *cond);
+int pthread_cond_destroy(pthread_cond_t *cond);
+int pthread_attr_init(pthread_attr_t *connect_att);
+int pthread_attr_setstacksize(pthread_attr_t *connect_att,DWORD stack);
+int pthread_attr_setprio(pthread_attr_t *connect_att,int priority);
+int pthread_attr_destroy(pthread_attr_t *connect_att);
+struct tm *localtime_r(const time_t *timep,struct tm *tmp);
+
+void pthread_exit(unsigned A); /* was #define pthread_exit(A) ExitThread(A)*/
+
+#define ETIMEDOUT 145 /* Win32 doesn't have this */
+#define getpid() GetCurrentThreadId()
+#define pthread_self() win_pthread_self
+#define HAVE_LOCALTIME_R
+#define _REENTRANT
+#define HAVE_PTHREAD_ATTR_SETSTACKSIZE
+
+#ifdef USE_TLS /* For LIBMYSQL.DLL */
+#define pthread_key(T,V) DWORD V
+#define pthread_key_create(A,B) ((*A=TlsAlloc())==0xFFFFFFFF)
+#define pthread_getspecific(A) (TlsGetValue(A))
+#define my_pthread_getspecific(T,A) ((T) TlsGetValue(A))
+#define my_pthread_getspecific_ptr(T,V) ((T) TlsGetValue(A))
+#define my_pthread_setspecific_ptr(T,V) TlsSetValue(T,V)
+#define pthread_setspecific(A,B) TlsSetValue(A,B)
+#else
+#define pthread_key(T,V) __declspec(thread) T V
+#define pthread_key_create(A,B) pthread_dummy(0)
+#define pthread_getspecific(A) (&(A))
+#define my_pthread_getspecific(T,A) (&(A))
+#define my_pthread_getspecific_ptr(T,V) (V)
+#define my_pthread_setspecific_ptr(T,V) ((T)=(V),0)
+#define pthread_setspecific(A,B) win_pthread_setspecific(&(A),(B),sizeof(A))
+#endif /* USE_TLS */
+
+#define pthread_equal(A,B) ((A) == (B))
+#define pthread_mutex_init(A,B) InitializeCriticalSection(A)
+#define pthread_mutex_lock(A) (EnterCriticalSection(A),0)
+#define pthread_mutex_unlock(A) LeaveCriticalSection(A)
+#define pthread_mutex_destroy(A) DeleteCriticalSection(A)
+#define my_pthread_setprio(A,B) SetThreadPriority(GetCurrentThread(), (B))
+/* Dummy defines for easier code */
+#define pthread_kill(A,B) pthread_dummy(0)
+#define pthread_attr_setdetachstate(A,B) pthread_dummy(0)
+#define my_pthread_attr_setprio(A,B) pthread_attr_setprio(A,B)
+#define pthread_attr_setscope(A,B)
+#define pthread_detach_this_thread()
+#define pthread_condattr_init(A)
+#define pthread_condattr_destroy(A)
+
+//Irena: compiler does not like this:
+//#define my_pthread_getprio(pthread_t thread_id) pthread_dummy(0)
+#define my_pthread_getprio(thread_id) pthread_dummy(0)
+
+#elif defined(HAVE_UNIXWARE7_THREADS)
+
+#include <thread.h>
+#include <synch.h>
+
+#ifndef _REENTRANT
+#define _REENTRANT
+#endif
+
+#define HAVE_NONPOSIX_SIGWAIT
+#define pthread_t thread_t
+#define pthread_cond_t cond_t
+#define pthread_mutex_t mutex_t
+#define pthread_key_t thread_key_t
+typedef int pthread_attr_t; /* Needed by Unixware 7.0.0 */
+
+#define pthread_key_create(A,B) thr_keycreate((A),(B))
+
+#define pthread_handler_decl(A,B) void *A(void *B)
+#define pthread_key(T,V) pthread_key_t V
+
+void * my_pthread_getspecific_imp(pthread_key_t key);
+#define my_pthread_getspecific(A,B) ((A) my_pthread_getspecific_imp(B))
+#define my_pthread_getspecific_ptr(T,V) my_pthread_getspecific(T,V)
+
+#define pthread_setspecific(A,B) thr_setspecific(A,B)
+#define my_pthread_setspecific_ptr(T,V) pthread_setspecific(T,V)
+
+#define pthread_create(A,B,C,D) thr_create(NULL,65536L,(C),(D),THR_DETACHED,(A))
+#define pthread_cond_init(a,b) cond_init((a),USYNC_THREAD,NULL)
+#define pthread_cond_destroy(a) cond_destroy(a)
+#define pthread_cond_signal(a) cond_signal(a)
+#define pthread_cond_wait(a,b) cond_wait((a),(b))
+#define pthread_cond_timedwait(a,b,c) cond_timedwait((a),(b),(c))
+#define pthread_cond_broadcast(a) cond_broadcast(a)
+
+#define pthread_mutex_init(a,b) mutex_init((a),USYNC_THREAD,NULL)
+#define pthread_mutex_lock(a) mutex_lock(a)
+#define pthread_mutex_unlock(a) mutex_unlock(a)
+#define pthread_mutex_destroy(a) mutex_destroy(a)
+
+#define pthread_self() thr_self()
+#define pthread_exit(A) thr_exit(A)
+#define pthread_equal(A,B) (((A) == (B)) ? 1 : 0)
+#define pthread_kill(A,B) thr_kill((A),(B))
+#define HAVE_PTHREAD_KILL
+
+#define pthread_sigmask(A,B,C) thr_sigsetmask((A),(B),(C))
+
+extern int my_sigwait(sigset_t *set,int *sig);
+
+#define pthread_detach_this_thread() pthread_dummy(0)
+
+#define pthread_attr_init(A) pthread_dummy(0)
+#define pthread_attr_destroy(A) pthread_dummy(0)
+#define pthread_attr_setscope(A,B) pthread_dummy(0)
+#define pthread_attr_setdetachstate(A,B) pthread_dummy(0)
+#define my_pthread_setprio(A,B) pthread_dummy (0)
+#define my_pthread_getprio(A) pthread_dummy (0)
+#define my_pthread_attr_setprio(A,B) pthread_dummy(0)
+
+#else /* Normal threads */
+
+#ifdef HAVE_rts_threads
+#define sigwait org_sigwait
+#include <signal.h>
+#undef sigwait
+#endif
+#undef _REENTRANT /* Fix if _REENTRANT is in pthread.h */
+#include <pthread.h>
+#ifndef _REENTRANT
+#define _REENTRANT
+#endif
+#ifdef HAVE_THR_SETCONCURRENCY
+#include <thread.h> /* Probably solaris */
+#endif
+#ifdef HAVE_SCHED_H
+#include <sched.h>
+#endif
+#ifdef HAVE_SYNCH_H
+#include <synch.h>
+#endif
+#if defined(__EMX__) && (!defined(EMX_PTHREAD_REV) || (EMX_PTHREAD_REV < 2))
+#error Requires at least rev 2 of EMX pthreads library.
+#endif
+
+extern int my_pthread_getprio(pthread_t thread_id);
+
+#define pthread_key(T,V) pthread_key_t V
+#define my_pthread_getspecific_ptr(T,V) my_pthread_getspecific(T,(V))
+#define my_pthread_setspecific_ptr(T,V) pthread_setspecific(T,(void*) (V))
+#define pthread_detach_this_thread()
+#define pthread_handler_decl(A,B) void *A(void *B)
+typedef void *(* pthread_handler)(void *);
+
+/* safe mutex for debugging */
+
+typedef struct st_safe_mutex_t
+{
+ pthread_mutex_t global,mutex;
+ char *file;
+ uint line,count;
+ pthread_t thread;
+} safe_mutex_t;
+
+int safe_mutex_init(safe_mutex_t *mp, const pthread_mutexattr_t *attr);
+int safe_mutex_lock(safe_mutex_t *mp,const char *file, uint line);
+int safe_mutex_unlock(safe_mutex_t *mp,const char *file, uint line);
+int safe_mutex_destroy(safe_mutex_t *mp,const char *file, uint line);
+int safe_cond_wait(pthread_cond_t *cond, safe_mutex_t *mp,const char *file,
+ uint line);
+int safe_cond_timedwait(pthread_cond_t *cond, safe_mutex_t *mp,
+ struct timespec *abstime, const char *file, uint line);
+
+#ifdef SAFE_MUTEX
+#undef pthread_mutex_init
+#undef pthread_mutex_lock
+#undef pthread_mutex_unlock
+#undef pthread_mutex_destroy
+#undef pthread_mutex_wait
+#undef pthread_mutex_timedwait
+#undef pthread_mutex_t
+#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__)
+#define pthread_mutex_destroy(A) safe_mutex_destroy((A),__FILE__,__LINE__)
+#define pthread_cond_wait(A,B) safe_cond_wait((A),(B),__FILE__,__LINE__)
+#define pthread_cond_timedwait(A,B,C) safe_cond_timedwait((A),(B),(C),__FILE__,__LINE__)
+#define pthread_mutex_t safe_mutex_t
+#endif
+
+/* Test first for RTS or FSU threads */
+
+#if defined(PTHREAD_SCOPE_GLOBAL) && !defined(PTHREAD_SCOPE_SYSTEM)
+#define HAVE_rts_threads
+extern int my_pthread_create_detached;
+#define pthread_sigmask(A,B,C) sigprocmask((A),(B),(C))
+#define PTHREAD_CREATE_DETACHED &my_pthread_create_detached
+#define PTHREAD_SCOPE_SYSTEM PTHREAD_SCOPE_GLOBAL
+#define PTHREAD_SCOPE_PROCESS PTHREAD_SCOPE_LOCAL
+#define USE_ALARM_THREAD
+#elif defined(HAVE_mit_thread)
+#define USE_ALARM_THREAD
+#undef HAVE_LOCALTIME_R
+#define HAVE_LOCALTIME_R
+#undef HAVE_PTHREAD_ATTR_SETSCOPE
+#define HAVE_PTHREAD_ATTR_SETSCOPE
+#undef HAVE_GLIBC2_STYLE_GETHOSTBYNAME_R /* If we are running linux */
+#undef HAVE_RWLOCK_T
+#undef HAVE_RWLOCK_INIT
+#undef HAVE_PTHREAD_RWLOCK_RDLOCK
+#undef HAVE_SNPRINTF
+
+#define sigset(A,B) pthread_signal((A),(void (*)(int)) (B))
+#define signal(A,B) pthread_signal((A),(void (*)(int)) (B))
+#define my_pthread_attr_setprio(A,B)
+#endif /* defined(PTHREAD_SCOPE_GLOBAL) && !defined(PTHREAD_SCOPE_SYSTEM) */
+
+#if defined(_BSDI_VERSION) && _BSDI_VERSION < 199910
+int sigwait(const sigset_t *set, int *sig);
+#endif
+
+#if defined(HAVE_UNIXWARE7_POSIX)
+#undef HAVE_NONPOSIX_SIGWAIT
+#define HAVE_NONPOSIX_SIGWAIT /* sigwait takes only 1 argument */
+#endif
+
+#ifndef HAVE_NONPOSIX_SIGWAIT
+#define my_sigwait(A,B) sigwait((A),(B))
+#else
+int my_sigwait(sigset_t *set,int *sig);
+#endif
+
+#ifdef HAVE_NONPOSIX_PTHREAD_MUTEX_INIT
+#ifndef SAFE_MUTEX
+#define pthread_mutex_init(a,b) my_pthread_mutex_init((a),(b))
+extern int my_pthread_mutex_init(pthread_mutex_t *mp,
+ const pthread_mutexattr_t *attr);
+#endif /* SAFE_MUTEX */
+#define pthread_cond_init(a,b) my_pthread_cond_init((a),(b))
+extern int my_pthread_cond_init(pthread_cond_t *mp,
+ const pthread_condattr_t *attr);
+#endif /* HAVE_NONPOSIX_PTHREAD_MUTEX_INIT */
+
+#if defined(HAVE_SIGTHREADMASK) && !defined(HAVE_PTHREAD_SIGMASK)
+#define pthread_sigmask(A,B,C) sigthreadmask((A),(B),(C))
+#endif
+
+#if !defined(HAVE_SIGWAIT) && !defined(HAVE_mit_thread) && !defined(HAVE_rts_threads) && !defined(sigwait) && !defined(alpha_linux_port) && !defined(HAVE_NONPOSIX_SIGWAIT) && !defined(HAVE_DEC_3_2_THREADS) && !defined(_AIX)
+int sigwait(sigset_t *setp, int *sigp); /* Use our implemention */
+#endif
+#if !defined(HAVE_SIGSET) && !defined(HAVE_mit_thread) && !defined(sigset)
+#define sigset(A,B) do { struct sigaction s; sigset_t set; \
+ sigemptyset(&set); \
+ s.sa_handler = (B); \
+ s.sa_mask = set; \
+ s.sa_flags = 0; \
+ sigaction((A), &s, (struct sigaction *) NULL); \
+ } while (0)
+#endif
+
+#ifndef my_pthread_setprio
+#if defined(HAVE_PTHREAD_SETPRIO_NP) /* FSU threads */
+#define my_pthread_setprio(A,B) pthread_setprio_np((A),(B))
+#elif defined(HAVE_PTHREAD_SETPRIO)
+#define my_pthread_setprio(A,B) pthread_setprio((A),(B))
+#else
+extern void my_pthread_setprio(pthread_t thread_id,int prior);
+#endif
+#endif
+
+#ifndef my_pthread_attr_setprio
+#ifdef HAVE_PTHREAD_ATTR_SETPRIO
+#define my_pthread_attr_setprio(A,B) pthread_attr_setprio((A),(B))
+#else
+extern void my_pthread_attr_setprio(pthread_attr_t *attr, int priority);
+#endif
+#endif
+
+#if !defined(HAVE_PTHREAD_ATTR_SETSCOPE) || defined(HAVE_DEC_3_2_THREADS)
+#define pthread_attr_setscope(A,B)
+#undef HAVE_GETHOSTBYADDR_R /* No definition */
+#endif
+
+#ifndef HAVE_NONPOSIX_PTHREAD_GETSPECIFIC
+#define my_pthread_getspecific(A,B) ((A) pthread_getspecific(B))
+#else
+#define my_pthread_getspecific(A,B) ((A) my_pthread_getspecific_imp(B))
+void *my_pthread_getspecific_imp(pthread_key_t key);
+#endif
+
+#ifndef HAVE_LOCALTIME_R
+struct tm *localtime_r(const time_t *clock, struct tm *res);
+#endif
+
+#ifdef HAVE_PTHREAD_CONDATTR_CREATE
+/* DCE threads on HPUX 10.20 */
+#define pthread_condattr_init pthread_condattr_create
+#define pthread_condattr_destroy pthread_condattr_delete
+#endif
+
+#ifdef HAVE_CTHREADS_WRAPPER /* For MacOSX */
+#define pthread_cond_destroy(A) pthread_dummy(0)
+#define pthread_mutex_destroy(A) pthread_dummy(0)
+#define pthread_attr_delete(A) pthread_dummy(0)
+#define pthread_condattr_delete(A) pthread_dummy(0)
+#define pthread_attr_setstacksize(A,B) pthread_dummy(0)
+#define pthread_equal(A,B) ((A) == (B))
+#define pthread_cond_timedwait(a,b,c) pthread_cond_wait((a),(b))
+#define pthread_attr_init(A) pthread_attr_create(A)
+#define pthread_attr_destroy(A) pthread_attr_delete(A)
+#define pthread_attr_setdetachstate(A,B) pthread_dummy(0)
+#define pthread_create(A,B,C,D) pthread_create((A),*(B),(C),(D))
+#define pthread_sigmask(A,B,C) sigprocmask((A),(B),(C))
+#define pthread_kill(A,B) pthread_dummy(0)
+#undef pthread_detach_this_thread
+#define pthread_detach_this_thread() { pthread_t tmp=pthread_self() ; pthread_detach(&tmp); }
+#endif
+
+#if ((defined(HAVE_PTHREAD_ATTR_CREATE) && !defined(HAVE_SIGWAIT)) || defined(HAVE_DEC_3_2_THREADS)) && !defined(HAVE_CTHREADS_WRAPPER)
+/* This is set on AIX_3_2 and Siemens unix (and DEC OSF/1 3.2 too) */
+#define pthread_key_create(A,B) \
+ pthread_keycreate(A,(B) ?\
+ (pthread_destructor_t) (B) :\
+ (pthread_destructor_t) pthread_dummy)
+#define pthread_attr_init(A) pthread_attr_create(A)
+#define pthread_attr_destroy(A) pthread_attr_delete(A)
+#define pthread_attr_setdetachstate(A,B) pthread_dummy(0)
+#define pthread_create(A,B,C,D) pthread_create((A),*(B),(C),(D))
+#ifndef pthread_sigmask
+#define pthread_sigmask(A,B,C) sigprocmask((A),(B),(C))
+#endif
+#define pthread_kill(A,B) pthread_dummy(0)
+#undef pthread_detach_this_thread
+#define pthread_detach_this_thread() { pthread_t tmp=pthread_self() ; pthread_detach(&tmp); }
+#else /* HAVE_PTHREAD_ATTR_CREATE && !HAVE_SIGWAIT */
+#define HAVE_PTHREAD_KILL
+#endif
+
+#if defined(HAVE_PTHREAD_ATTR_CREATE) || defined(_AIX) || defined(HAVE_GLIBC2_STYLE_GETHOSTBYNAME_R)
+#if !defined(HPUX)
+struct hostent;
+#endif /* HPUX */
+struct hostent *my_gethostbyname_r(const char *name,
+ struct hostent *result, char *buffer,
+ int buflen, int *h_errnop);
+#if defined(HAVE_GLIBC2_STYLE_GETHOSTBYNAME_R)
+#define GETHOSTBYNAME_BUFF_SIZE 2048
+#else
+#define GETHOSTBYNAME_BUFF_SIZE sizeof(struct hostent_data)
+#endif /* defined(HAVE_GLIBC2_STYLE_GETHOSTBYNAME_R) */
+
+#else
+#ifdef HAVE_GETHOSTBYNAME_R_WITH_HOSTENT_DATA
+#define GETHOSTBYNAME_BUFF_SIZE sizeof(hostent_data)
+#define my_gethostbyname_r(A,B,C,D,E) gethostbyname_r((A),(B),(hostent_data*) (C))
+#else
+#define GETHOSTBYNAME_BUFF_SIZE 2048
+#define my_gethostbyname_r(A,B,C,D,E) gethostbyname_r((A),(B),(C),(D),(E))
+#endif /* HAVE_GETHOSTBYNAME_R_WITH_HOSTENT_DATA */
+#endif /* defined(HAVE_PTHREAD_ATTR_CREATE) || defined(_AIX) || defined(HAVE_GLIBC2_STYLE_GETHOSTBYNAME_R) */
+
+#endif /* defined(__WIN__) */
+
+/* READ-WRITE thread locking */
+
+#if defined(USE_MUTEX_INSTEAD_OF_RW_LOCKS)
+/* use these defs for simple mutex locking */
+#define rw_lock_t pthread_mutex_t
+#define my_rwlock_init(A,B) pthread_mutex_init((A),(B))
+#define rw_rdlock(A) pthread_mutex_lock((A))
+#define rw_wrlock(A) pthread_mutex_lock((A))
+#define rw_unlock(A) pthread_mutex_unlock((A))
+#define rwlock_destroy(A) pthread_mutex_destroy((A))
+#elif defined(HAVE_PTHREAD_RWLOCK_RDLOCK)
+#define rw_lock_t pthread_rwlock_t
+#define my_rwlock_init(A,B) pthread_rwlock_init((A),(B))
+#define rw_rdlock(A) pthread_rwlock_rdlock(A)
+#define rw_wrlock(A) pthread_rwlock_wrlock(A)
+#define rw_unlock(A) pthread_rwlock_unlock(A)
+#define rwlock_destroy(A) pthread_rwlock_destroy(A)
+#elif defined(HAVE_RWLOCK_INIT)
+#ifdef HAVE_RWLOCK_T /* For example Solaris 2.6-> */
+#define rw_lock_t rwlock_t
+#endif
+#define my_rwlock_init(A,B) rwlock_init((A),USYNC_THREAD,0)
+#else
+/* Use our own version of read/write locks */
+typedef struct _my_rw_lock_t {
+ pthread_mutex_t lock; /* lock for structure */
+ pthread_cond_t readers; /* waiting readers */
+ pthread_cond_t writers; /* waiting writers */
+ int state; /* -1:writer,0:free,>0:readers */
+ int waiters; /* number of waiting writers */
+} my_rw_lock_t;
+
+#define rw_lock_t my_rw_lock_t
+#define rw_rdlock(A) my_rw_rdlock((A))
+#define rw_wrlock(A) my_rw_wrlock((A))
+#define rw_unlock(A) my_rw_unlock((A))
+#define rwlock_destroy(A) my_rwlock_destroy((A))
+
+extern int my_rwlock_init( my_rw_lock_t *, void * );
+extern int my_rwlock_destroy( my_rw_lock_t * );
+extern int my_rw_rdlock( my_rw_lock_t * );
+extern int my_rw_wrlock( my_rw_lock_t * );
+extern int my_rw_unlock( my_rw_lock_t * );
+#endif /* USE_MUTEX_INSTEAD_OF_RW_LOCKS */
+
+#define GETHOSTBYADDR_BUFF_SIZE 2048
+
+#ifndef HAVE_THR_SETCONCURRENCY
+#define thr_setconcurrency(A) pthread_dummy(0)
+#endif
+#if !defined(HAVE_PTHREAD_ATTR_SETSTACKSIZE) && ! defined(pthread_attr_setstacksize)
+#define pthread_attr_setstacksize(A,B) pthread_dummy(0)
+#endif
+
+extern my_bool my_thread_global_init(void);
+extern void my_thread_global_end(void);
+extern my_bool my_thread_init(void);
+extern void my_thread_end(void);
+extern char *my_thread_name(void);
+extern long my_thread_id(void);
+extern int pthread_no_free(void *);
+extern int pthread_dummy(int);
+
+/* All thread specific variables are in the following struct */
+
+#define THREAD_NAME_SIZE 10
+
+struct st_my_thread_var
+{
+ int thr_errno;
+ int cmp_length;
+ volatile int abort;
+ long id;
+ pthread_cond_t suspend, *current_cond;
+ pthread_mutex_t mutex, *current_mutex;
+ pthread_t pthread_self;
+#ifndef DBUG_OFF
+ char name[THREAD_NAME_SIZE+1];
+ gptr dbug;
+#endif
+};
+
+extern struct st_my_thread_var *_my_thread_var(void) __attribute__ ((const));
+#define my_thread_var (_my_thread_var())
+#define my_errno my_thread_var->thr_errno
+
+ /* statistics_xxx functions are for not essential statistic */
+
+#ifndef thread_safe_increment
+#ifdef HAVE_ATOMIC_ADD
+#define thread_safe_increment(V,L) atomic_add(1,(atomic_t*) &V);
+#define thread_safe_add(V,C,L) atomic_add((C),(atomic_t*) &V);
+#define thread_safe_sub(V,C,L) atomic_sub((C),(atomic_t*) &V);
+#define statistic_increment(V,L) thread_safe_increment((V),(L))
+#define statistic_add(V,C,L) thread_safe_add((V),(C),(L))
+#else
+#define thread_safe_increment(V,L) \
+ pthread_mutex_lock((L)); (V)++; pthread_mutex_unlock((L));
+#define thread_safe_add(V,C,L) \
+ pthread_mutex_lock((L)); (V)+=(C); pthread_mutex_unlock((L));
+#define thread_safe_sub(V,C,L) \
+ pthread_mutex_lock((L)); (V)-=(C); pthread_mutex_unlock((L));
+#ifdef SAFE_STATISTICS
+#define statistic_increment(V,L) thread_safe_increment((V),(L))
+#define statistic_add(V,C,L) thread_safe_add((V),(C),(L))
+#else
+#define statistic_increment(V,L) (V)++
+#define statistic_add(V,C,L) (V)+=(C)
+#endif /* SAFE_STATISTICS */
+#endif /* HAVE_ATOMIC_ADD */
+#endif /* thread_safe_increment */
+#endif /* _my_ptread_h */
diff --git a/include/my_sys.h b/include/my_sys.h
new file mode 100644
index 00000000000..57734e9e534
--- /dev/null
+++ b/include/my_sys.h
@@ -0,0 +1,555 @@
+/* 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 */
+
+#ifndef _my_sys_h
+#define _my_sys_h
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef HAVE_AIOWAIT
+#include <sys/asynch.h> /* Used by record-cache */
+typedef struct my_aio_result {
+ aio_result_t result;
+ int pending;
+} my_aio_result;
+#endif
+
+#ifndef THREAD
+extern int NEAR my_errno; /* Last error in mysys */
+#else
+#include <my_pthread.h>
+#endif
+
+#ifndef _m_ctype_h
+#include <m_ctype.h> /* for CHARSET_INFO */
+#endif
+
+#include <stdarg.h>
+
+#define MYSYS_PROGRAM_USES_CURSES() { error_handler_hook = my_message_curses; mysys_uses_curses=1; }
+#define MYSYS_PROGRAM_DONT_USE_CURSES() { error_handler_hook = my_message_no_curses; mysys_uses_curses=0;}
+#define MY_INIT(name); { my_progname= name; my_init(); }
+
+#define MAXMAPS (4) /* Number of error message maps */
+#define ERRMOD (1000) /* Max number of errors in a map */
+#define ERRMSGSIZE (SC_MAXWIDTH) /* Max length of a error message */
+#define NRERRBUFFS (2) /* Buffers for parameters */
+#define MY_FILE_ERROR ((uint) ~0)
+
+ /* General bitmaps for my_func's */
+#define MY_FFNF 1 /* Fatal if file not found */
+#define MY_FNABP 2 /* Fatal if not all bytes read/writen */
+#define MY_NABP 4 /* Error if not all bytes read/writen */
+#define MY_FAE 8 /* Fatal if any error */
+#define MY_WME 16 /* Write message on error */
+#define MY_WAIT_IF_FULL 32 /* Wait and try again if disk full error */
+#define MY_RAID 64 /* Support for RAID (not the "Johnson&Johnson"-s one ;) */
+#define MY_LINK_WARNING 32 /* my_redel() gives warning if links */
+#define MY_COPYTIME 64 /* my_redel() copys time */
+#define MY_HOLD_ORIGINAL_MODES 128 /* my_copy() holds to file modes */
+#define MY_SEEK_NOT_DONE 32 /* my_lock may have to do a seek */
+#define MY_DONT_WAIT 64 /* my_lock() don't wait if can't lock */
+#define MY_ZEROFILL 32 /* my_malloc(), fill array with zero */
+#define MY_ALLOW_ZERO_PTR 64 /* my_realloc() ; zero ptr -> malloc */
+#define MY_FREE_ON_ERROR 128 /* my_realloc() ; Free old ptr on error */
+#define MY_HOLD_ON_ERROR 256 /* my_realloc() ; Return old ptr on error */
+#define MY_THREADSAFE 128 /* pread/pwrite: Don't allow interrupts */
+
+#define MY_CHECK_ERROR 1 /* Params to my_end; Check open-close */
+#define MY_GIVE_INFO 2 /* Give time info about process*/
+
+#define ME_HIGHBYTE 8 /* Shift for colours */
+#define ME_NOCUR 1 /* Don't use curses message */
+#define ME_OLDWIN 2 /* Use old window */
+#define ME_BELL 4 /* Ring bell then printing message */
+#define ME_HOLDTANG 8 /* Don't delete last keys */
+#define ME_WAITTOT 16 /* Wait for errtime secs of for a action */
+#define ME_WAITTANG 32 /* Wait for a user action */
+#define ME_NOREFRESH 64 /* Dont refresh screen */
+#define ME_NOINPUT 128 /* Dont use the input libary */
+#define ME_COLOUR1 ((1 << ME_HIGHBYTE)) /* Possibly error-colours */
+#define ME_COLOUR2 ((2 << ME_HIGHBYTE))
+#define ME_COLOUR3 ((3 << ME_HIGHBYTE))
+
+ /* My seek flags */
+#define MY_SEEK_SET 0
+#define MY_SEEK_CUR 1
+#define MY_SEEK_END 2
+
+ /* My charsets_list flags */
+#define MY_NO_SETS 0
+#define MY_COMPILED_SETS 1 /* show compiled-in sets */
+#define MY_CONFIG_SETS 2 /* sets that have a *.conf file */
+#define MY_INDEX_SETS 4 /* all sets listed in the Index file */
+#define MY_LOADED_SETS 8 /* the sets that are currently loaded */
+
+ /* Some constants */
+#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
+
+ /* defines when allocating data */
+
+#ifdef SAFEMALLOC
+#define my_malloc(SZ,FLAG) _mymalloc( SZ, __FILE__, __LINE__, FLAG )
+#define my_realloc(PTR,SZ,FLAG) _myrealloc( PTR, SZ, __FILE__, __LINE__, FLAG )
+#define my_checkmalloc() _sanity( __FILE__, __LINE__ )
+#define my_free(PTR,FLAG) _myfree( PTR, __FILE__, __LINE__,FLAG)
+#define my_memdup(A,B,C) _my_memdup(A,B,__FILE__,__LINE__,C)
+#define my_strdup(A,C) _my_strdup(A,__FILE__,__LINE__,C)
+#define QUICK_SAFEMALLOC sf_malloc_quick=1
+#define NORMAL_SAFEMALLOC sf_malloc_quick=0
+extern uint sf_malloc_prehunc,sf_malloc_endhunc,sf_malloc_quick;
+#else
+#define my_checkmalloc() (0)
+#define TERMINATE(A) {}
+#define QUICK_SAFEMALLOC
+#define NORMAL_SAFEMALLOC
+extern gptr my_malloc(uint Size,myf MyFlags);
+extern gptr my_realloc(gptr oldpoint,uint Size,myf MyFlags);
+extern void my_no_flags_free(gptr ptr);
+extern gptr my_memdup(const byte *from,uint length,myf MyFlags);
+extern my_string my_strdup(const char *from,myf MyFlags);
+#define my_free(PTR,FG) my_no_flags_free(PTR)
+#endif
+#ifdef HAVE_ALLOCA
+#define my_alloca(SZ) alloca((size_t) (SZ))
+#define my_afree(PTR) {}
+#else
+#define my_alloca(SZ) my_malloc(SZ,MYF(0))
+#define my_afree(PTR) my_free(PTR,MYF(MY_WME))
+#endif /* HAVE_ALLOCA */
+#ifdef MSDOS
+#ifdef __ZTC__
+void * __CDECL halloc(long count,size_t length);
+void __CDECL hfree(void *ptr);
+#endif
+#if defined(USE_HALLOC)
+#if defined(_VCM_) || defined(M_IC80386)
+#undef USE_HALLOC
+#endif
+#endif
+#ifdef USE_HALLOC
+#define malloc(a) halloc((long) (a),1)
+#define free(a) hfree(a)
+#endif
+#endif /* MSDOS */
+
+#ifdef HAVE_ERRNO_AS_DEFINE
+#include <errno.h> /* errno is a define */
+#else
+extern int errno; /* declare errno */
+#endif
+extern const char ** NEAR errmsg[];
+extern char NEAR errbuff[NRERRBUFFS][ERRMSGSIZE];
+extern char *home_dir; /* Home directory for user */
+extern char *my_progname; /* program-name (printed in errors) */
+extern char NEAR curr_dir[]; /* Current directory for user */
+extern int (*error_handler_hook)(uint my_err, const char *str,myf MyFlags);
+extern int (*fatal_error_handler_hook)(uint my_err, const char *str,
+ myf MyFlags);
+
+/* charsets */
+extern uint get_charset_number(const char *cs_name);
+extern const char *get_charset_name(uint cs_number);
+extern CHARSET_INFO *get_charset(uint cs_number, myf flags);
+extern my_bool set_default_charset(uint cs, myf flags);
+extern CHARSET_INFO *get_charset_by_name(const char *cs_name, myf flags);
+extern my_bool set_default_charset_by_name(const char *cs_name, myf flags);
+extern void free_charsets(void);
+extern char *list_charsets(myf want_flags); /* my_free() this string... */
+
+
+/* statisticts */
+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 uint my_file_opened,my_stream_opened;
+
+ /* Point to current my_message() */
+extern void (*my_sigtstp_cleanup)(void),
+ /* Executed before jump to shell */
+ (*my_sigtstp_restart)(void),
+ (*my_abort_hook)(int);
+ /* Executed when comming from shell */
+extern int NEAR my_umask, /* Default creation mask */
+ NEAR my_umask_dir,
+ NEAR my_recived_signals, /* Signals we have got */
+ NEAR my_safe_to_handle_signal, /* Set when allowed to SIGTSTP */
+ NEAR my_dont_interrupt; /* call remember_intr when set */
+extern my_bool NEAR mysys_uses_curses, my_use_symdir;
+extern long lCurMemory,lMaxMemory; /* from safemalloc */
+
+extern ulong my_default_record_cache_size;
+extern my_bool NEAR my_disable_locking,NEAR my_disable_async_io,
+ NEAR my_disable_flush_key_blocks;
+extern char wild_many,wild_one,wild_prefix;
+extern const char *charsets_dir;
+
+typedef struct wild_file_pack /* Struct to hold info when selecting files */
+{
+ uint wilds; /* How many wildcards */
+ uint not_pos; /* Start of not-theese-files */
+ my_string *wild; /* Pointer to wildcards */
+} WF_PACK;
+
+typedef struct st_typelib { /* Different types saved here */
+ uint count; /* How many types */
+ const char *name; /* Name of typelib */
+ const char **type_names;
+} TYPELIB;
+
+enum cache_type {READ_CACHE,WRITE_CACHE,READ_NET,WRITE_NET};
+enum flush_type { FLUSH_KEEP, FLUSH_RELEASE, FLUSH_IGNORE_CHANGED,
+ FLUSH_FORCE_WRITE};
+
+typedef struct st_record_cache /* Used when cacheing records */
+{
+ File file;
+ int rc_seek,error,inited;
+ uint rc_length,read_length,reclength;
+ my_off_t rc_record_pos,end_of_file;
+ byte *rc_buff,*rc_buff2,*rc_pos,*rc_end,*rc_request_pos;
+#ifdef HAVE_AIOWAIT
+ int use_async_io;
+ my_aio_result aio_result;
+#endif
+ enum cache_type type;
+} RECORD_CACHE;
+
+enum file_type { UNOPEN = 0, FILE_BY_OPEN, FILE_BY_CREATE,
+ STREAM_BY_FOPEN, STREAM_BY_FDOPEN };
+
+extern struct my_file_info
+{
+ my_string name;
+ enum file_type type;
+} my_file_info[MY_NFILE];
+
+
+typedef struct st_dynamic_array {
+ char *buffer;
+ uint elements,max_element;
+ uint alloc_increment;
+ uint size_of_element;
+} DYNAMIC_ARRAY;
+
+typedef struct st_dynamic_string {
+ char *str;
+ uint length,max_length,alloc_increment;
+} DYNAMIC_STRING;
+
+
+typedef struct st_io_cache /* Used when cacheing files */
+{
+ byte *rc_pos,*rc_end,*buffer,*rc_request_pos;
+ File file;
+ int seek_not_done,error;
+ uint buffer_length,read_length;
+ my_off_t pos_in_file,end_of_file;
+ myf myflags; /* Flags used to my_read/my_write */
+#ifdef HAVE_AIOWAIT
+ uint inited;
+ my_off_t aio_read_pos;
+ my_aio_result aio_result;
+#endif
+ enum cache_type type;
+ int (*read_function)(struct st_io_cache *,byte *,uint);
+ char *file_name; /* if used with 'open_cached_file' */
+} IO_CACHE;
+
+typedef int (*qsort2_cmp)(const void *, const void *, const void *);
+
+ /* defines for mf_iocache */
+
+ /* Test if buffer is inited */
+#define my_b_clear(info) (info)->buffer=0
+#define my_b_inited(info) (info)->buffer
+#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_function)((info),Buffer,Count))
+
+#define my_b_get(info) \
+ ((info)->rc_pos != (info)->rc_end ?\
+ ((info)->rc_pos++, (int) (uchar) (info)->rc_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))))
+
+#define my_b_fill_cache(info) \
+ (((info)->rc_end=(info)->rc_pos),(*(info)->read_function)(info,0,0))
+
+#define my_b_tell(info) ((info)->pos_in_file + \
+ ((info)->rc_pos - (info)->rc_request_pos))
+
+typedef struct st_changeable_var {
+ const char *name;
+ long *varptr;
+ long def_value,min_value,max_value,sub_size,block_size;
+} CHANGEABLE_VAR;
+
+
+/* structs for alloc_root */
+
+#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;
+ unsigned int min_malloc;
+ unsigned int block_size;
+ void (*error_handler)(void);
+} MEM_ROOT;
+#endif
+
+ /* Prototypes for mysys and my_func functions */
+
+extern int my_copy(const char *from,const char *to,myf MyFlags);
+extern int my_append(const char *from,const char *to,myf MyFlags);
+extern int my_delete(const char *name,myf MyFlags);
+extern int my_getwd(my_string buf,uint size,myf MyFlags);
+extern int my_setwd(const char *dir,myf MyFlags);
+extern int my_lock(File fd,int op,my_off_t start, my_off_t length,myf MyFlags);
+extern gptr my_once_alloc(uint Size,myf MyFlags);
+extern void my_once_free(void);
+extern my_string my_tempnam(const char *dir,const char *pfx,myf MyFlags);
+extern File my_open(const char *FileName,int Flags,myf MyFlags);
+extern File my_create(const char *FileName,int CreateFlags,
+ int AccsesFlags, myf MyFlags);
+extern int my_close(File Filedes,myf MyFlags);
+extern int my_mkdir(const char *dir, int Flags, myf MyFlags);
+extern uint my_read(File Filedes,byte *Buffer,uint Count,myf MyFlags);
+extern uint my_pread(File Filedes,byte *Buffer,uint Count,my_off_t offset,
+ myf MyFlags);
+extern int my_rename(const char *from,const char *to,myf MyFlags);
+extern my_off_t my_seek(File fd,my_off_t pos,int whence,myf MyFlags);
+extern my_off_t my_tell(File fd,myf MyFlags);
+extern uint my_write(File Filedes,const byte *Buffer,uint Count,
+ myf MyFlags);
+extern uint my_pwrite(File Filedes,const byte *Buffer,uint Count,
+ my_off_t offset,myf MyFlags);
+extern uint my_fread(FILE *stream,byte *Buffer,uint Count,myf MyFlags);
+extern uint my_fwrite(FILE *stream,const byte *Buffer,uint Count,
+ myf MyFlags);
+extern my_off_t my_fseek(FILE *stream,my_off_t pos,int whence,myf MyFlags);
+extern my_off_t my_ftell(FILE *stream,myf MyFlags);
+extern gptr _mymalloc(uint uSize,const char *sFile,
+ uint uLine, myf MyFlag);
+extern gptr _myrealloc(gptr pPtr,uint uSize,const char *sFile,
+ uint uLine, myf MyFlag);
+extern gptr my_multi_malloc _VARARGS((myf MyFlags, ...));
+extern void _myfree(gptr pPtr,const char *sFile,uint uLine, myf MyFlag);
+extern int _sanity(const char *sFile,unsigned int uLine);
+extern gptr _my_memdup(const byte *from,uint length,
+ const char *sFile, uint uLine,myf MyFlag);
+extern my_string _my_strdup(const char *from, const char *sFile, uint uLine,
+ myf MyFlag);
+#ifndef TERMINATE
+extern void TERMINATE(FILE *file);
+#endif
+extern void init_glob_errs(void);
+extern FILE *my_fopen(const char *FileName,int Flags,myf MyFlags);
+extern FILE *my_fdopen(File Filedes,int Flags,myf MyFlags);
+extern int my_fclose(FILE *fd,myf MyFlags);
+extern int my_chsize(File fd,my_off_t newlength,myf MyFlags);
+extern int my_error _VARARGS((int nr,myf MyFlags, ...));
+extern int my_printf_error _VARARGS((uint my_err, const char *format,
+ myf MyFlags, ...)
+ __attribute__ ((format (printf, 2, 4))));
+extern int my_vsnprintf( char *str, size_t n,
+ const char *format, va_list ap );
+
+extern int my_message(uint my_err, const char *str,myf MyFlags);
+extern int my_message_no_curses(uint my_err, const char *str,myf MyFlags);
+extern int my_message_curses(uint my_err, const char *str,myf MyFlags);
+extern void my_init(void);
+extern void my_end(int infoflag);
+extern int my_redel(const char *from, const char *to, int MyFlags);
+extern int my_copystat(const char *from, const char *to, int MyFlags);
+extern my_string my_filename(File fd);
+
+extern void dont_break(void);
+extern void allow_break(void);
+extern void my_remember_signal(int signal_number,sig_handler (*func)(int));
+extern void caseup(my_string str,uint length);
+extern void casedn(my_string str,uint length);
+extern void caseup_str(my_string str);
+extern void casedn_str(my_string str);
+extern void case_sort(my_string str,uint length);
+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 void convert_dirname(my_string name);
+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 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);
+extern uint cleanup_dirname(my_string to,const char *from);
+extern uint system_filename(my_string to,const char *from);
+extern my_string unpack_filename(my_string to,const char *from);
+extern my_string intern_filename(my_string to,const char *from);
+extern my_string directory_file_name(my_string dst, const char *src);
+extern int pack_filename(my_string to, const char *name, size_s max_length);
+extern my_string my_path(my_string to,const char *progname,
+ const char *own_pathname_part);
+extern my_string my_load_path(my_string to, const char *path,
+ const char *own_path_prefix);
+extern int wild_compare(const char *str,const char *wildstr);
+extern my_string my_strcasestr(const char *src,const char *suffix);
+extern int my_strcasecmp(const char *s,const char *t);
+extern int my_strsortcmp(const char *s,const char *t);
+extern int my_casecmp(const char *s,const char *t,uint length);
+extern int my_sortcmp(const char *s,const char *t,uint length);
+extern int my_sortncmp(const char *s,uint s_len, const char *t,uint t_len);
+extern WF_PACK *wf_comp(my_string str);
+extern int wf_test(struct wild_file_pack *wf_pack,const char *name);
+extern void wf_end(struct wild_file_pack *buffer);
+extern size_s stripp_sp(my_string str);
+extern void get_date(my_string to,int timeflag,time_t use_time);
+extern void soundex(my_string out_pntr, my_string in_pntr,pbool remove_garbage);
+extern int init_record_cache(RECORD_CACHE *info,uint cachesize,File file,
+ uint reclength,enum cache_type type,
+ pbool use_async_io);
+extern int read_cache_record(RECORD_CACHE *info,byte *to);
+extern int end_record_cache(RECORD_CACHE *info);
+extern int write_cache_record(RECORD_CACHE *info,my_off_t filepos,
+ const byte *record,uint length);
+extern int flush_write_cache(RECORD_CACHE *info);
+extern long my_clock(void);
+extern sig_handler sigtstp_handler(int signal_number);
+extern void handle_recived_signals(void);
+extern int init_key_cache(ulong use_mem,ulong leave_this_much_mem);
+extern byte *key_cache_read(File file,my_off_t filepos,byte* buff,uint length,
+ uint block_length,int return_buffer);
+extern int key_cache_write(File file,my_off_t filepos,byte* buff,uint length,
+ uint block_length,int force_write);
+extern int flush_key_blocks(int file, enum flush_type type);
+extern void end_key_cache(void);
+extern sig_handler my_set_alarm_variable(int signo);
+extern void my_string_ptr_sort(void *base,uint items,size_s size);
+extern void radixsort_for_str_ptr(uchar* base[], uint number_of_elements,
+ size_s size_of_element,uchar *buffer[]);
+extern qsort_t qsort2(void *base_ptr, size_t total_elems, size_t size,
+ qsort2_cmp cmp, void *cmp_argument);
+extern qsort2_cmp get_ptr_compare(uint);
+extern int init_io_cache(IO_CACHE *info,File file,uint cachesize,
+ enum cache_type type,my_off_t seek_offset,
+ pbool use_async_io, myf cache_myflags);
+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_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_block_write(IO_CACHE *info, const byte *Buffer,
+ uint Count, my_off_t pos);
+extern int flush_io_cache(IO_CACHE *info);
+extern int end_io_cache(IO_CACHE *info);
+extern my_bool open_cached_file(IO_CACHE *cache,const char *dir,
+ const char *prefix, uint cache_size,
+ myf cache_myflags);
+extern my_bool real_open_cached_file(IO_CACHE *cache);
+extern void close_cached_file(IO_CACHE *cache);
+extern my_bool init_dynamic_array(DYNAMIC_ARRAY *array,uint element_size,
+ uint init_alloc,uint alloc_increment);
+extern my_bool insert_dynamic(DYNAMIC_ARRAY *array,gptr element);
+extern byte *alloc_dynamic(DYNAMIC_ARRAY *array);
+extern byte *pop_dynamic(DYNAMIC_ARRAY*);
+extern my_bool set_dynamic(DYNAMIC_ARRAY *array,gptr element,uint array_index);
+extern void get_dynamic(DYNAMIC_ARRAY *array,gptr element,uint array_index);
+extern void delete_dynamic(DYNAMIC_ARRAY *array);
+extern void delete_dynamic_element(DYNAMIC_ARRAY *array, uint array_index);
+extern void freeze_size(DYNAMIC_ARRAY *array);
+#define dynamic_array_ptr(array,array_index) ((array)->buffer+(array_index)*(array)->size_of_element)
+#define dynamic_element(array,array_index,type) ((type)((array)->buffer) +(array_index))
+#define push_dynamic(A,B) insert_dynamic(A,B)
+
+extern int find_type(my_string x,TYPELIB *typelib,uint full_name);
+extern void make_type(my_string to,uint nr,TYPELIB *typelib);
+extern const char *get_type(TYPELIB *typelib,uint nr);
+extern my_bool init_dynamic_string(DYNAMIC_STRING *str, const char *init_str,
+ uint init_alloc,uint alloc_increment);
+extern my_bool dynstr_append(DYNAMIC_STRING *str, const char *append);
+extern my_bool dynstr_set(DYNAMIC_STRING *str, const char *init_str);
+extern my_bool dynstr_realloc(DYNAMIC_STRING *str, ulong additional_size);
+extern void dynstr_free(DYNAMIC_STRING *str);
+void set_all_changeable_vars(CHANGEABLE_VAR *vars);
+my_bool set_changeable_var(my_string str,CHANGEABLE_VAR *vars);
+my_bool set_changeable_varval(const char *var, ulong val,
+ CHANGEABLE_VAR *vars);
+#ifdef HAVE_MLOCK
+extern byte *my_malloc_lock(uint length,myf flags);
+extern void my_free_lock(byte *ptr,myf flags);
+#else
+#define my_malloc_lock(A,B) my_malloc((A),(B))
+#define my_free_lock(A,B) my_free((A),(B))
+#endif
+void init_alloc_root(MEM_ROOT *mem_root,uint block_size);
+gptr alloc_root(MEM_ROOT *mem_root,unsigned int Size);
+void free_root(MEM_ROOT *root);
+char *strdup_root(MEM_ROOT *root,const char *str);
+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);
+void free_defaults(char **argv);
+void print_defaults(const char *conf_file, const char **groups);
+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);
+
+#if defined(_MSC_VER) && !defined(__WIN__)
+extern void sleep(int sec);
+#endif
+#ifdef __WIN__
+extern my_bool have_tcpip; /* Is set if tcpip is used */
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+#include "raid.h"
+#endif /* _my_sys_h */
diff --git a/include/my_tree.h b/include/my_tree.h
new file mode 100644
index 00000000000..84815591e36
--- /dev/null
+++ b/include/my_tree.h
@@ -0,0 +1,75 @@
+/* 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 */
+
+#ifndef _tree_h
+#define _tree_h
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define MAX_TREE_HIGHT 40 /* = max 1048576 leafs in tree */
+#define ELEMENT_KEY(tree,element)\
+(tree->offset_to_key ? (void*)((byte*) element+tree->offset_to_key) :\
+ *((void**) (element+1)))
+
+#define tree_set_pointer(element,ptr) *((byte **) (element+1))=((byte*) (ptr))
+
+typedef enum { left_root_right, right_root_left } TREE_WALK;
+typedef uint32 element_count;
+typedef int (*tree_walk_action)(void *,element_count,void *);
+
+#ifdef MSDOS
+typedef struct st_tree_element {
+ struct st_tree_element *left,*right;
+ unsigned long count;
+ uchar colour; /* black is marked as 1 */
+} TREE_ELEMENT;
+#else
+typedef struct st_tree_element {
+ struct st_tree_element *left,*right;
+ uint32 count:31,
+ colour:1; /* black is marked as 1 */
+} TREE_ELEMENT;
+#endif /* MSDOS */
+
+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;
+ MEM_ROOT mem_root;
+ my_bool with_delete;
+ void (*free)(void *);
+} 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*));
+void delete_tree(TREE*);
+
+ /* Functions on leafs */
+TREE_ELEMENT *tree_insert(TREE *tree,void *key,uint key_size);
+void *tree_search(TREE *tree,void *key);
+int tree_walk(TREE *tree,tree_walk_action action,
+ void *argument, TREE_WALK visit);
+int tree_delete(TREE *tree,void *key);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/include/myisam.h b/include/myisam.h
new file mode 100644
index 00000000000..2b8f75b2050
--- /dev/null
+++ b/include/myisam.h
@@ -0,0 +1,377 @@
+/* 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 should be included when using myisam_funktions */
+
+#ifndef _myisam_h
+#define _myisam_h
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef _my_base_h
+#include <my_base.h>
+#endif
+#ifndef _m_ctype_h
+#include <m_ctype.h>
+#endif
+
+ /* defines used by myisam-funktions */
+
+/* The following defines can be increased if necessary */
+#define MI_MAX_KEY 32 /* Max allowed keys */
+#define MI_MAX_KEY_SEG 16 /* Max segments for key */
+#define MI_MAX_KEY_LENGTH 500
+
+#define MI_MAX_KEY_BUFF (MI_MAX_KEY_LENGTH+MI_MAX_KEY_SEG*6+8+8)
+#define MI_MAX_POSSIBLE_KEY_BUFF (1024+6+6) /* For myisam_chk */
+#define MI_MAX_POSSIBLE_KEY 64 /* For myisam_chk */
+#define MI_MAX_MSG_BUF 1024 /* used in CHECK TABLE, REPAIR TABLE */
+#define MI_NAME_IEXT ".MYI"
+#define MI_NAME_DEXT ".MYD"
+
+#define mi_portable_sizeof_char_ptr 8
+
+typedef uint32 ha_checksum;
+
+ /* Param to/from mi_info */
+
+typedef struct st_mi_isaminfo /* Struct from h_info */
+{
+ ha_rows records; /* Records in database */
+ ha_rows deleted; /* Deleted records in database */
+ my_off_t recpos; /* Pos for last used record */
+ my_off_t newrecpos; /* Pos if we write new record */
+ my_off_t dupp_key_pos; /* Position to record with dupp key */
+ my_off_t data_file_length, /* Length of data file */
+ max_data_file_length,
+ index_file_length,
+ max_index_file_length,
+ delete_length;
+ ulong reclength; /* Recordlength */
+ ulong mean_reclength; /* Mean recordlength (if packed) */
+ ulonglong auto_increment;
+ ulonglong key_map; /* Which keys are used */
+ uint keys; /* Number of keys in use */
+ uint options; /* HA_OPTIONS_... used */
+ int errkey, /* With key was dupplicated on err */
+ sortkey; /* clustered by this key */
+ File filenr; /* (uniq) filenr for datafile */
+ time_t create_time; /* When table was created */
+ time_t check_time;
+ time_t update_time;
+ uint reflength;
+ ulong record_offset;
+ ulong *rec_per_key; /* for sql optimizing */
+ uint raid_type,raid_chunks;
+ ulong raid_chunksize;
+} MI_ISAMINFO;
+
+
+typedef struct st_mi_create_info
+{
+ ha_rows max_rows;
+ ha_rows reloc_rows;
+ ulonglong auto_increment;
+ ulonglong data_file_length;
+ uint raid_type,raid_chunks;
+ ulong raid_chunksize;
+ uint old_options;
+ uint8 language;
+} MI_CREATE_INFO;
+
+struct st_myisam_info; /* For referense */
+typedef struct st_myisam_info MI_INFO;
+
+typedef struct st_mi_keyseg /* Key-portion */
+{
+ uint8 type; /* Type of key (for sort) */
+ uint8 language;
+ uint8 null_bit; /* bitmask to test for NULL */
+ uint8 bit_start,bit_end; /* if bit field */
+ uint16 flag;
+ uint16 length; /* Keylength */
+ uint32 start; /* Start of key in record */
+ uint32 null_pos; /* position to NULL indicator */
+ CHARSET_INFO *charset;
+} MI_KEYSEG;
+
+
+struct st_mi_s_param;
+
+typedef struct st_mi_keydef /* Key definition with open & info */
+{
+ uint16 keysegs; /* Number of key-segment */
+ uint16 flag; /* NOSAME, PACK_USED */
+
+ uint16 block_length; /* Length of keyblock (auto) */
+ uint16 underflow_block_length; /* When to execute underflow */
+ uint16 keylength; /* Tot length of keyparts (auto) */
+ uint16 minlength; /* min length of (packed) key (auto) */
+ uint16 maxlength; /* max length of (packed) key (auto) */
+ uint16 block_size; /* block_size (auto) */
+ uint32 version; /* For concurrent read/write */
+
+ MI_KEYSEG *seg,*end;
+ int (*bin_search)(struct st_myisam_info *info,struct st_mi_keydef *keyinfo,
+ uchar *page,uchar *key,
+ uint key_len,uint comp_flag,uchar * *ret_pos,
+ uchar *buff, my_bool *was_last_key);
+ uint (*get_key)(struct st_mi_keydef *keyinfo,uint nod_flag,uchar * *page,
+ uchar *key);
+ int (*pack_key)(struct st_mi_keydef *keyinfo,uint nod_flag,uchar *next_key,
+ uchar *org_key, uchar *prev_key, uchar *key,
+ struct st_mi_s_param *s_temp);
+ void (*store_key)(struct st_mi_keydef *keyinfo, uchar *key_pos,
+ struct st_mi_s_param *s_temp);
+} MI_KEYDEF;
+
+
+#define MI_UNIQUE_HASH_LENGTH 4
+
+typedef struct st_unique_def /* Segment definition of unique */
+{
+ uint16 keysegs; /* Number of key-segment */
+ uchar key; /* Mapped to which key */
+ uint8 null_are_equal;
+ MI_KEYSEG *seg,*end;
+} MI_UNIQUEDEF;
+
+typedef struct st_mi_decode_tree /* Decode huff-table */
+{
+ uint16 *table;
+ uint quick_table_bits;
+ byte *intervalls;
+} MI_DECODE_TREE;
+
+
+struct st_mi_bit_buff;
+
+/* Note that null markers should always be first in a row !
+ When creating a column, one should only specify:
+ type, length, null_bit and null_pos */
+
+typedef struct st_columndef /* column information */
+{
+ int16 type; /* en_fieldtype */
+ uint16 length; /* length of field */
+ uint32 offset; /* Offset to position in row */
+ uint8 null_bit; /* If column may be 0 */
+ uint16 null_pos; /* position for null marker */
+
+#ifndef NOT_PACKED_DATABASES
+ void (*unpack)(struct st_columndef *rec,struct st_mi_bit_buff *buff,
+ uchar *start,uchar *end);
+ enum en_fieldtype base_type;
+ uint space_length_bits,pack_type;
+ MI_DECODE_TREE *huff_tree;
+#endif
+} MI_COLUMNDEF;
+
+
+extern my_string myisam_log_filename; /* Name of logfile */
+extern uint myisam_block_size;
+extern my_bool myisam_flush,myisam_delay_key_write,
+ myisam_concurrent_insert;
+
+ /* Prototypes for myisam-functions */
+
+extern int mi_close(struct st_myisam_info *file);
+extern int mi_delete(struct st_myisam_info *file,const byte *buff);
+extern struct st_myisam_info *mi_open(const char *name,int mode,
+ uint wait_if_locked);
+extern int mi_panic(enum ha_panic_function function);
+extern int mi_rfirst(struct st_myisam_info *file,byte *buf,int inx);
+extern int mi_rkey(struct st_myisam_info *file,byte *buf,int inx,
+ const byte *key,
+ uint key_len, enum ha_rkey_function search_flag);
+extern int mi_rlast(struct st_myisam_info *file,byte *buf,int inx);
+extern int mi_rnext(struct st_myisam_info *file,byte *buf,int inx);
+extern int mi_rnext_same(struct st_myisam_info *info, byte *buf);
+extern int mi_rprev(struct st_myisam_info *file,byte *buf,int inx);
+extern int mi_rrnd(struct st_myisam_info *file,byte *buf, my_off_t pos);
+extern int mi_scan_init(struct st_myisam_info *file);
+extern int mi_scan(struct st_myisam_info *file,byte *buf);
+extern int mi_rsame(struct st_myisam_info *file,byte *record,int inx);
+extern int mi_rsame_with_pos(struct st_myisam_info *file,byte *record,
+ int inx, my_off_t pos);
+extern int mi_update(struct st_myisam_info *file,const byte *old,
+ byte *new_record);
+extern int mi_write(struct st_myisam_info *file,byte *buff);
+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 uniques, MI_UNIQUEDEF *uniquedef,
+ MI_CREATE_INFO *create_info, uint flags);
+extern int mi_delete_table(const char *name);
+extern int mi_rename(const char *from, const char *to);
+extern int mi_extra(struct st_myisam_info *file,
+ enum ha_extra_function function);
+extern ha_rows mi_records_in_range(struct st_myisam_info *info,int inx,
+ const byte *start_key,uint start_key_len,
+ enum ha_rkey_function start_search_flag,
+ const byte *end_key,uint end_key_len,
+ enum ha_rkey_function end_search_flag);
+extern int mi_log(int activate_log);
+extern int mi_is_changed(struct st_myisam_info *info);
+extern int mi_delete_all_rows(struct st_myisam_info *info);
+extern ulong _mi_calc_blob_length(uint length , const byte *pos);
+extern uint mi_get_pointer_length(ulonglong file_length, uint def);
+
+/* this is used to pass to mysql_myisamchk_table -- by Sasha Pachev */
+
+#define MYISAMCHK_REPAIR 1 /* equivalent to myisamchk -r*/
+#define MYISAMCHK_VERIFY 2 /* run equivalent of myisamchk -c,
+ * if corruption is detected, do myisamchk -r*/
+
+/* 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 O_NEW_INDEX 1 /* Bits set in out_flag */
+#define O_NEW_DATA 2
+
+/* these struct is used by my_check to tell it what to do */
+
+typedef struct st_sort_key_blocks { /* Used when sorting */
+ uchar *buff,*end_pos;
+ uchar lastkey[MI_MAX_POSSIBLE_KEY_BUFF];
+ uint last_length;
+ int inited;
+} SORT_KEY_BLOCKS;
+
+struct st_mi_check_param;
+
+typedef struct st_sort_info {
+ MI_INFO *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;
+ 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;
+ MI_KEYDEF *keyinfo;
+ MI_KEYSEG *keyseg;
+} SORT_INFO;
+
+
+typedef struct st_mi_check_param
+{
+ 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 opt_sort_key,total_files,max_level;
+ uint8 language;
+ my_bool using_global_keycache, opt_lock_memory, opt_follow_links;
+ uint testflag;
+ ha_rows total_records,total_deleted;
+ ulonglong auto_increment_value;
+ my_off_t search_after_block;
+ ulonglong max_data_file_length;
+ ulonglong keys_in_use;
+ my_off_t new_file_pos,key_file_blocks;
+ my_off_t keydata,totaldata,key_blocks;
+ ha_checksum record_checksum,glob_crc;
+ char temp_filename[FN_REFLEN],*isam_file_name,*tmpdir;
+ int tmpfile_createflag;
+ myf myf_rw;
+ IO_CACHE read_cache;
+ SORT_INFO sort_info;
+ ulonglong unique_count[MI_MAX_KEY_SEG+1];
+ ha_checksum key_crc[MI_MAX_POSSIBLE_KEY];
+ ulong rec_per_key_part[MI_MAX_KEY_SEG*MI_MAX_POSSIBLE_KEY];
+ void* thd;
+ char* table_name;
+ char* op_name;
+} MI_CHECK;
+
+
+typedef struct st_mi_sortinfo {
+ uint key_length;
+ ha_rows max_records;
+ SORT_INFO *sort_info;
+ char *tmpdir;
+ int (*key_cmp)(SORT_INFO *info, const void *, const void *);
+ int (*key_read)(SORT_INFO *info,void *buff);
+ int (*key_write)(SORT_INFO *info, const void *buff);
+ void (*lock_in_memory)(MI_CHECK *info);
+} MI_SORT_PARAM;
+
+/* functions in mi_check */
+void myisamchk_init(MI_CHECK *param);
+int chk_del(MI_CHECK *param, register MI_INFO *info, uint test_flag);
+int chk_size(MI_CHECK *param, MI_INFO *info);
+int chk_key(MI_CHECK *param, MI_INFO *info);
+int chk_data_link(MI_CHECK *param, MI_INFO *info,int extend);
+int mi_repair(MI_CHECK *param, register MI_INFO *info,
+ my_string name, int rep_quick);
+int mi_sort_index(MI_CHECK *param, register MI_INFO *info, my_string name);
+int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info,
+ const char * name, int rep_quick);
+int change_to_newfile(const char * filename, const char * old_ext,
+ const char * new_ext, uint raid_chunks);
+int lock_file(MI_CHECK *param, File file, my_off_t start, int lock_type,
+ const char *filetype, const char *filename);
+void lock_memory(MI_CHECK *param);
+int flush_blocks(MI_CHECK *param, File file);
+ void update_auto_increment_key(MI_CHECK *param, MI_INFO *info,
+ my_bool repair);
+int update_state_info(MI_CHECK *param, MI_INFO *info,uint update);
+int filecopy(MI_CHECK *param, File to,File from,my_off_t start,
+ my_off_t length, const char *type);
+int movepoint(MI_INFO *info,byte *record,my_off_t oldpos,
+ my_off_t newpos, uint prot_key);
+int sort_write_record(SORT_INFO *sort_info);
+ int write_data_suffix(MI_CHECK *param, MI_INFO *info);
+int _create_index_by_sort(MI_SORT_PARAM *info,my_bool no_messages,
+ ulong);
+int test_if_almost_full(MI_INFO *info);
+int recreate_table(MI_CHECK *param, MI_INFO **org_info, char *filename);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/include/myisammrg.h b/include/myisammrg.h
new file mode 100644
index 00000000000..cf18e407962
--- /dev/null
+++ b/include/myisammrg.h
@@ -0,0 +1,92 @@
+/* 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 should be included when using merge_isam_funktions */
+
+#ifndef _myisammrg_h
+#define _myisammrg_h
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef _my_base_h
+#include <my_base.h>
+#endif
+#ifndef _myisam_h
+#include <myisam.h>
+#endif
+
+#define MYRG_NAME_EXT ".MRG"
+
+ /* Param to/from myrg_info */
+
+typedef struct st_mymerge_info /* Struct from h_info */
+{
+ ulonglong records; /* Records in database */
+ ulonglong deleted; /* Deleted records in database */
+ ulonglong recpos; /* Pos for last used record */
+ ulonglong data_file_length;
+ uint reclength; /* Recordlength */
+ int errkey; /* With key was dupplicated on err */
+ uint options; /* HA_OPTIONS_... used */
+} MYMERGE_INFO;
+
+typedef struct st_myrg_table_info
+{
+ struct st_myisam_info *table;
+ ulonglong file_offset;
+} MYRG_TABLE;
+
+typedef struct st_myrg_info
+{
+ MYRG_TABLE *open_tables,*current_table,*end_table,*last_used_table;
+ ulonglong records; /* records in tables */
+ ulonglong del; /* Removed records */
+ ulonglong data_file_length;
+ uint tables,options,reclength;
+ my_bool cache_in_use;
+ LIST open_list;
+} MYRG_INFO;
+
+
+ /* Prototypes for merge-functions */
+
+extern int myrg_close(MYRG_INFO *file);
+extern int myrg_delete(MYRG_INFO *file,const byte *buff);
+extern MYRG_INFO *myrg_open(const char *name,int mode,int wait_if_locked);
+extern int myrg_panic(enum ha_panic_function function);
+extern int myrg_rfirst(MYRG_INFO *file,byte *buf,int inx);
+extern int myrg_rkey(MYRG_INFO *file,byte *buf,int inx,const byte *key,
+ uint key_len, enum ha_rkey_function search_flag);
+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_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);
+extern int myrg_extra(MYRG_INFO *file,enum ha_extra_function function);
+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,
+ const byte *end_key,uint end_key_len,
+ enum ha_rkey_function end_search_flag);
+
+extern ulonglong myrg_position(MYRG_INFO *info);
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/include/myisampack.h b/include/myisampack.h
new file mode 100644
index 00000000000..1e63b47fc48
--- /dev/null
+++ b/include/myisampack.h
@@ -0,0 +1,207 @@
+/* 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 */
+
+/*
+ Storing of values in high byte first order.
+
+ integer keys and file pointers are stored with high byte first to get
+ better compression
+*/
+
+#define mi_sint2korr(A) (int16) (((int16) ((uchar) (A)[1])) +\
+ ((int16) ((int16) (A)[0]) << 8))
+#define mi_sint3korr(A) ((int32) ((((uchar) (A)[0]) & 128) ? \
+ (((uint32) 255L << 24) | \
+ (((uint32) (uchar) (A)[0]) << 16) |\
+ (((uint32) (uchar) (A)[1]) << 8) | \
+ ((uint32) (uchar) (A)[2])) : \
+ (((uint32) (uchar) (A)[0]) << 16) |\
+ (((uint32) (uchar) (A)[1]) << 8) | \
+ ((uint32) (uchar) (A)[2])))
+#define mi_sint4korr(A) (int32) (((int32) ((uchar) (A)[3])) +\
+ (((int32) ((uchar) (A)[2]) << 8)) +\
+ (((int32) ((uchar) (A)[1]) << 16)) +\
+ (((int32) ((int16) (A)[0]) << 24)))
+#define mi_sint8korr(A) (longlong) mi_uint8korr(A)
+#define mi_uint2korr(A) (uint16) (((uint16) ((uchar) (A)[1])) +\
+ ((uint16) ((uchar) (A)[0]) << 8))
+#define mi_uint3korr(A) (uint32) (((uint32) ((uchar) (A)[2])) +\
+ (((uint32) ((uchar) (A)[1])) << 8) +\
+ (((uint32) ((uchar) (A)[0])) << 16))
+#define mi_uint4korr(A) (uint32) (((uint32) ((uchar) (A)[3])) +\
+ (((uint32) ((uchar) (A)[2])) << 8) +\
+ (((uint32) ((uchar) (A)[1])) << 16) +\
+ (((uint32) ((uchar) (A)[0])) << 24))
+#define mi_uint5korr(A) ((ulonglong)(((uint32) ((uchar) (A)[4])) +\
+ (((uint32) ((uchar) (A)[3])) << 8) +\
+ (((uint32) ((uchar) (A)[2])) << 16) +\
+ (((uint32) ((uchar) (A)[1])) << 24)) +\
+ (((ulonglong) ((uchar) (A)[0])) << 32))
+#define mi_uint6korr(A) ((ulonglong)(((uint32) ((uchar) (A)[5])) +\
+ (((uint32) ((uchar) (A)[4])) << 8) +\
+ (((uint32) ((uchar) (A)[3])) << 16) +\
+ (((uint32) ((uchar) (A)[2])) << 24)) +\
+ (((ulonglong) (((uint32) ((uchar) (A)[1])) +\
+ (((uint32) ((uchar) (A)[0]) << 8)))) <<\
+ 32))
+#define mi_uint7korr(A) ((ulonglong)(((uint32) ((uchar) (A)[6])) +\
+ (((uint32) ((uchar) (A)[5])) << 8) +\
+ (((uint32) ((uchar) (A)[4])) << 16) +\
+ (((uint32) ((uchar) (A)[3])) << 24)) +\
+ (((ulonglong) (((uint32) ((uchar) (A)[2])) +\
+ (((uint32) ((uchar) (A)[1])) << 8) +\
+ (((uint32) ((uchar) (A)[0])) << 16))) <<\
+ 32))
+#define mi_uint8korr(A) ((ulonglong)(((uint32) ((uchar) (A)[7])) +\
+ (((uint32) ((uchar) (A)[6])) << 8) +\
+ (((uint32) ((uchar) (A)[5])) << 16) +\
+ (((uint32) ((uchar) (A)[4])) << 24)) +\
+ (((ulonglong) (((uint32) ((uchar) (A)[3])) +\
+ (((uint32) ((uchar) (A)[2])) << 8) +\
+ (((uint32) ((uchar) (A)[1])) << 16) +\
+ (((uint32) ((uchar) (A)[0])) << 24))) <<\
+ 32))
+
+#define mi_int2store(T,A) { uint def_temp= (uint) (A) ;\
+ *((uchar*) ((T)+1))= (uchar)(def_temp); \
+ *((uchar*) ((T)+0))= (uchar)(def_temp >> 8); }
+#define mi_int3store(T,A) { /*lint -save -e734 */\
+ ulong def_temp= (ulong) (A);\
+ *(((T)+2))=(char) (def_temp);\
+ *((T)+1)= (char) (def_temp >> 8);\
+ *((T)+0)= (char) (def_temp >> 16);\
+ /*lint -restore */}
+#define mi_int4store(T,A) { ulong def_temp= (ulong) (A);\
+ *((T)+3)=(char) (def_temp);\
+ *((T)+2)=(char) (def_temp >> 8);\
+ *((T)+1)=(char) (def_temp >> 16);\
+ *((T)+0)=(char) (def_temp >> 24); }
+#define mi_int5store(T,A) { ulong def_temp= (ulong) (A),\
+ def_temp2= (ulong) ((A) >> 32);\
+ *((T)+4)=(char) (def_temp);\
+ *((T)+3)=(char) (def_temp >> 8);\
+ *((T)+2)=(char) (def_temp >> 16);\
+ *((T)+1)=(char) (def_temp >> 24);\
+ *((T)+0)=(char) (def_temp2); }
+#define mi_int6store(T,A) { ulong def_temp= (ulong) (A),\
+ def_temp2= (ulong) ((A) >> 32);\
+ *((T)+5)=(char) (def_temp);\
+ *((T)+4)=(char) (def_temp >> 8);\
+ *((T)+3)=(char) (def_temp >> 16);\
+ *((T)+2)=(char) (def_temp >> 24);\
+ *((T)+1)=(char) (def_temp2);\
+ *((T)+0)=(char) (def_temp2 >> 8); }
+#define mi_int7store(T,A) { ulong def_temp= (ulong) (A),\
+ def_temp2= (ulong) ((A) >> 32);\
+ *((T)+6)=(char) (def_temp);\
+ *((T)+5)=(char) (def_temp >> 8);\
+ *((T)+4)=(char) (def_temp >> 16);\
+ *((T)+3)=(char) (def_temp >> 24);\
+ *((T)+2)=(char) (def_temp2);\
+ *((T)+1)=(char) (def_temp2 >> 8);\
+ *((T)+0)=(char) (def_temp2 >> 16); }
+#define mi_int8store(T,A) { ulong def_temp3= (ulong) (A), \
+ def_temp4= (ulong) ((A) >> 32); \
+ mi_int4store((T),def_temp4); \
+ mi_int4store((T+4),def_temp3); \
+ }
+
+#ifdef WORDS_BIGENDIAN
+
+#define mi_float4store(T,A) { *(T)= ((byte *) &A)[0];\
+ *((T)+1)=(char) ((byte *) &A)[1];\
+ *((T)+2)=(char) ((byte *) &A)[2];\
+ *((T)+3)=(char) ((byte *) &A)[3]; }
+
+#define mi_float4get(V,M) { float def_temp;\
+ ((byte*) &def_temp)[0]=(M)[0];\
+ ((byte*) &def_temp)[1]=(M)[1];\
+ ((byte*) &def_temp)[2]=(M)[2];\
+ ((byte*) &def_temp)[3]=(M)[3];\
+ (V)=def_temp; }
+
+#define mi_float8store(T,V) { *(T)= ((byte *) &V)[0];\
+ *((T)+1)=(char) ((byte *) &V)[1];\
+ *((T)+2)=(char) ((byte *) &V)[2];\
+ *((T)+3)=(char) ((byte *) &V)[3];\
+ *((T)+4)=(char) ((byte *) &V)[4];\
+ *((T)+5)=(char) ((byte *) &V)[5];\
+ *((T)+6)=(char) ((byte *) &V)[6];\
+ *((T)+7)=(char) ((byte *) &V)[7]; }
+
+#define mi_float8get(V,M) { double def_temp;\
+ ((byte*) &def_temp)[0]=(M)[0];\
+ ((byte*) &def_temp)[1]=(M)[1];\
+ ((byte*) &def_temp)[2]=(M)[2];\
+ ((byte*) &def_temp)[3]=(M)[3];\
+ ((byte*) &def_temp)[4]=(M)[4];\
+ ((byte*) &def_temp)[5]=(M)[5];\
+ ((byte*) &def_temp)[6]=(M)[6];\
+ ((byte*) &def_temp)[7]=(M)[7]; \
+ (V)=def_temp; }
+#else
+
+#define mi_float4store(T,A) { *(T)= ((byte *) &A)[3];\
+ *((T)+1)=(char) ((byte *) &A)[2];\
+ *((T)+2)=(char) ((byte *) &A)[1];\
+ *((T)+3)=(char) ((byte *) &A)[0]; }
+
+#define mi_float4get(V,M) { float def_temp;\
+ ((byte*) &def_temp)[0]=(M)[3];\
+ ((byte*) &def_temp)[1]=(M)[2];\
+ ((byte*) &def_temp)[2]=(M)[1];\
+ ((byte*) &def_temp)[3]=(M)[0];\
+ (V)=def_temp; }
+
+#define mi_float8store(T,V) { *(T)= ((byte *) &V)[7];\
+ *((T)+1)=(char) ((byte *) &V)[6];\
+ *((T)+2)=(char) ((byte *) &V)[5];\
+ *((T)+3)=(char) ((byte *) &V)[4];\
+ *((T)+4)=(char) ((byte *) &V)[3];\
+ *((T)+5)=(char) ((byte *) &V)[2];\
+ *((T)+6)=(char) ((byte *) &V)[1];\
+ *((T)+7)=(char) ((byte *) &V)[0];}
+
+#define mi_float8get(V,M) { double def_temp;\
+ ((byte*) &def_temp)[0]=(M)[7];\
+ ((byte*) &def_temp)[1]=(M)[6];\
+ ((byte*) &def_temp)[2]=(M)[5];\
+ ((byte*) &def_temp)[3]=(M)[4];\
+ ((byte*) &def_temp)[4]=(M)[3];\
+ ((byte*) &def_temp)[5]=(M)[2];\
+ ((byte*) &def_temp)[6]=(M)[1];\
+ ((byte*) &def_temp)[7]=(M)[0];\
+ (V)=def_temp; }
+#endif
+
+/* Fix to avoid warnings when sizeof(ha_rows) == sizeof(long) */
+
+#ifdef BIG_TABLE
+#define mi_rowstore(T,A) mi_int8store(T,A)
+#define mi_rowkorr(T,A) mi_uint8korr(T)
+#else
+#define mi_rowstore(T,A) { mi_int4store(T,0); mi_int4store(((T)+4),A); }
+#define mi_rowkorr(T) mi_uint4korr((T)+4)
+#endif
+
+#if SIZEOF_OFF_T > 4
+#define mi_sizestore(T,A) mi_int8store(T,A)
+#define mi_sizekorr(T) mi_uint8korr(T)
+#else
+#define mi_sizestore(T,A) { if ((A) == HA_OFFSET_ERROR) bfill((char*) (T),8,255); else { mi_int4store((T),0); mi_int4store(((T)+4),A); }}
+#define mi_sizekorr(T) mi_uint4korr((T)+4)
+#endif
diff --git a/include/mysql.h b/include/mysql.h
new file mode 100644
index 00000000000..e83babb8fa8
--- /dev/null
+++ b/include/mysql.h
@@ -0,0 +1,293 @@
+/* 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 */
+
+/* defines for the libmysql library */
+
+#ifndef _mysql_h
+#define _mysql_h
+
+#ifndef MYSQL_SERVER
+#ifdef __cplusplus
+extern "C" {
+#endif
+#endif
+
+#ifndef _global_h /* If not standard header */
+#include <sys/types.h>
+typedef char my_bool;
+#if (defined(_WIN32) || defined(_WIN64)) && !defined(__WIN__)
+#define __WIN__
+#endif
+#if !defined(__WIN__)
+#define STDCALL
+#else
+#define STDCALL __stdcall
+#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;
+ 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
+#include "mysql_com.h"
+#include "mysql_version.h"
+
+extern unsigned int mysql_port;
+extern char *mysql_unix_port;
+
+#define IS_PRI_KEY(n) ((n) & PRI_KEY_FLAG)
+#define IS_NOT_NULL(n) ((n) & NOT_NULL_FLAG)
+#define IS_BLOB(n) ((n) & BLOB_FLAG)
+#define IS_NUM(t) ((t) <= FIELD_TYPE_INT24 || (t) == FIELD_TYPE_YEAR)
+
+typedef struct st_mysql_field {
+ char *name; /* Name of column */
+ char *table; /* Table of column if column was a field */
+ 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 int flags; /* Div flags */
+ unsigned int decimals; /* Number of decimals in field */
+} MYSQL_FIELD;
+
+typedef char **MYSQL_ROW; /* return data as array of strings */
+typedef unsigned int MYSQL_FIELD_OFFSET; /* offset to current field */
+
+#if defined(NO_CLIENT_LONG_LONG)
+typedef unsigned long my_ulonglong;
+#elif defined (__WIN__)
+typedef unsigned __int64 my_ulonglong;
+#else
+typedef unsigned long long my_ulonglong;
+#endif
+
+#define MYSQL_COUNT_ERROR (~(my_ulonglong) 0)
+
+typedef struct st_mysql_rows {
+ struct st_mysql_rows *next; /* list of rows */
+ MYSQL_ROW data;
+} MYSQL_ROWS;
+
+typedef MYSQL_ROWS *MYSQL_ROW_OFFSET; /* offset to current row */
+
+typedef struct st_mysql_data {
+ my_ulonglong rows;
+ unsigned int fields;
+ MYSQL_ROWS *data;
+ MEM_ROOT alloc;
+} 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? */
+};
+
+enum mysql_option { MYSQL_OPT_CONNECT_TIMEOUT, MYSQL_OPT_COMPRESS,
+ MYSQL_OPT_NAMED_PIPE, MYSQL_INIT_COMMAND,
+ MYSQL_READ_DEFAULT_FILE, MYSQL_READ_DEFAULT_GROUP,
+ MYSQL_SET_CHARSET_DIR, MYSQL_SET_CHARSET_NAME};
+
+enum mysql_status { MYSQL_STATUS_READY,MYSQL_STATUS_GET_RESULT,
+ MYSQL_STATUS_USE_RESULT};
+
+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 */
+ my_ulonglong affected_rows;
+ my_ulonglong insert_id; /* id if insert on table with NEXTNR */
+ my_ulonglong extra_info; /* Used by mysqlshow */
+ unsigned long packet_length;
+ 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;
+} 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;
+ MEM_ROOT field_alloc;
+ 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 */
+} MYSQL_RES;
+
+/* Functions to get information from the MYSQL and MYSQL_RES structures */
+/* Should definitely be used if one uses shared libraries */
+
+my_ulonglong STDCALL mysql_num_rows(MYSQL_RES *res);
+unsigned int STDCALL mysql_num_fields(MYSQL_RES *res);
+my_bool STDCALL mysql_eof(MYSQL_RES *res);
+MYSQL_FIELD *STDCALL mysql_fetch_field_direct(MYSQL_RES *res,
+ unsigned int fieldnr);
+MYSQL_FIELD * STDCALL mysql_fetch_fields(MYSQL_RES *res);
+MYSQL_ROWS * STDCALL mysql_row_tell(MYSQL_RES *res);
+unsigned int STDCALL mysql_field_tell(MYSQL_RES *res);
+
+unsigned int STDCALL mysql_field_count(MYSQL *mysql);
+my_ulonglong STDCALL mysql_affected_rows(MYSQL *mysql);
+my_ulonglong STDCALL mysql_insert_id(MYSQL *mysql);
+unsigned int STDCALL mysql_errno(MYSQL *mysql);
+char * STDCALL mysql_error(MYSQL *mysql);
+char * STDCALL mysql_info(MYSQL *mysql);
+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);
+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,
+ const char *db,
+ 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_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);
+int STDCALL mysql_shutdown(MYSQL *mysql);
+int STDCALL mysql_dump_debug_info(MYSQL *mysql);
+int STDCALL mysql_refresh(MYSQL *mysql,
+ unsigned int refresh_options);
+int STDCALL mysql_kill(MYSQL *mysql,unsigned long pid);
+int STDCALL mysql_ping(MYSQL *mysql);
+char * STDCALL mysql_stat(MYSQL *mysql);
+char * STDCALL mysql_get_server_info(MYSQL *mysql);
+char * STDCALL mysql_get_client_info(void);
+char * STDCALL mysql_get_host_info(MYSQL *mysql);
+unsigned int STDCALL mysql_get_proto_info(MYSQL *mysql);
+MYSQL_RES * STDCALL mysql_list_dbs(MYSQL *mysql,const char *wild);
+MYSQL_RES * STDCALL mysql_list_tables(MYSQL *mysql,const char *wild);
+MYSQL_RES * STDCALL mysql_list_fields(MYSQL *mysql, const char *table,
+ const char *wild);
+MYSQL_RES * STDCALL mysql_list_processes(MYSQL *mysql);
+MYSQL_RES * STDCALL mysql_store_result(MYSQL *mysql);
+MYSQL_RES * STDCALL mysql_use_result(MYSQL *mysql);
+int STDCALL mysql_options(MYSQL *mysql,enum mysql_option option,
+ const char *arg);
+void STDCALL mysql_free_result(MYSQL_RES *result);
+void STDCALL mysql_data_seek(MYSQL_RES *result,
+ my_ulonglong offset);
+MYSQL_ROW_OFFSET STDCALL mysql_row_seek(MYSQL_RES *result, MYSQL_ROW_OFFSET);
+MYSQL_FIELD_OFFSET STDCALL mysql_field_seek(MYSQL_RES *result,
+ MYSQL_FIELD_OFFSET offset);
+MYSQL_ROW STDCALL mysql_fetch_row(MYSQL_RES *result);
+unsigned long * STDCALL mysql_fetch_lengths(MYSQL_RES *result);
+MYSQL_FIELD * STDCALL mysql_fetch_field(MYSQL_RES *result);
+unsigned long STDCALL mysql_escape_string(char *to,const char *from,
+ unsigned long from_length);
+unsigned long STDCALL mysql_real_escape_string(MYSQL *mysql,
+ char *to,const char *from,
+ unsigned long length);
+void STDCALL mysql_debug(const char *debug);
+char * STDCALL mysql_odbc_escape_string(MYSQL *mysql,
+ char *to,
+ unsigned long to_length,
+ const char *from,
+ unsigned long from_length,
+ void *param,
+ char *
+ (*extend_buffer)
+ (void *, char *to,
+ unsigned long *length));
+void STDCALL myodbc_remove_escape(MYSQL *mysql,char *name);
+unsigned int STDCALL mysql_thread_safe(void);
+
+
+#define mysql_reload(mysql) mysql_refresh((mysql),REFRESH_GRANT)
+
+/* new api functions */
+
+#define HAVE_MYSQL_REAL_CONNECT
+
+#ifndef MYSQL_SERVER
+#ifdef __cplusplus
+}
+#endif
+#endif
+
+#endif
diff --git a/include/mysql_com.h b/include/mysql_com.h
new file mode 100644
index 00000000000..2a1471f735d
--- /dev/null
+++ b/include/mysql_com.h
@@ -0,0 +1,242 @@
+/* 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 */
+
+/*
+** Common definition between mysql server & client
+*/
+
+#ifndef _mysql_com_h
+#define _mysql_com_h
+
+
+#define NAME_LEN 64 /* Field/table name length */
+#define HOSTNAME_LENGTH 60
+#define USERNAME_LENGTH 16
+
+#define LOCAL_HOST "localhost"
+#define LOCAL_HOST_NAMEDPIPE "."
+
+#if defined(__EMX__) || defined(__OS2__)
+#undef MYSQL_UNIX_ADDR
+#define MYSQL_OS2_ADDR "\\socket\\MySQL"
+#define MYSQL_UNIX_ADDR MYSQL_OS2_ADDR
+#endif
+#if defined(__WIN__) && !defined( _CUSTOMCONFIG_)
+#define MYSQL_NAMEDPIPE "MySQL"
+#define MYSQL_SERVICENAME "MySql"
+#endif /* __WIN__ */
+
+enum enum_server_command {COM_SLEEP,COM_QUIT,COM_INIT_DB,COM_QUERY,
+ COM_FIELD_LIST,COM_CREATE_DB,COM_DROP_DB,COM_REFRESH,
+ COM_SHUTDOWN,COM_STATISTICS,
+ 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};
+
+#define NOT_NULL_FLAG 1 /* Field can't be NULL */
+#define PRI_KEY_FLAG 2 /* Field is part of a primary key */
+#define UNIQUE_KEY_FLAG 4 /* Field is part of a unique key */
+#define MULTIPLE_KEY_FLAG 8 /* Field is part of a key */
+#define BLOB_FLAG 16 /* Field is a blob */
+#define UNSIGNED_FLAG 32 /* Field is unsigned */
+#define ZEROFILL_FLAG 64 /* Field is zerofill */
+#define BINARY_FLAG 128
+/* The following are only sent to new clients */
+#define ENUM_FLAG 256 /* field is an enum */
+#define AUTO_INCREMENT_FLAG 512 /* field is a autoincrement field */
+#define TIMESTAMP_FLAG 1024 /* Field is a timestamp */
+#define SET_FLAG 2048 /* field is a set */
+#define PART_KEY_FLAG 16384 /* Intern; Part of some key */
+#define GROUP_FLAG 32768 /* Intern: Group field */
+#define UNIQUE_FLAG 65536 /* Intern: Used by sql_yacc */
+
+#define REFRESH_GRANT 1 /* Refresh grant tables */
+#define REFRESH_LOG 2 /* Start on new log file */
+#define REFRESH_TABLES 4 /* close all tables */
+#define REFRESH_HOSTS 8 /* Flush host cache */
+#define REFRESH_STATUS 16 /* Flush status variables */
+#define REFRESH_THREADS 32 /* Flush status variables */
+#define REFRESH_SLAVE 64 /* Reset master info and restart slave
+ thread */
+#define REFRESH_MASTER 128 /* Remove all bin logs in the index
+ and truncate the index */
+
+/* The following can't be set with mysql_refresh() */
+#define REFRESH_READ_LOCK 16384 /* Lock tables for read */
+#define REFRESH_FAST 32768 /* Intern flag */
+
+#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 */
+#define CLIENT_CONNECT_WITH_DB 8 /* One can specify db on connect */
+#define CLIENT_NO_SCHEMA 16 /* Don't allow database.table.column */
+#define CLIENT_COMPRESS 32 /* Can use compression protocol */
+#define CLIENT_ODBC 64 /* Odbc client */
+#define CLIENT_LOCAL_FILES 128 /* Can use LOAD DATA LOCAL */
+#define CLIENT_IGNORE_SPACE 256 /* Ignore spaces before '(' */
+#define CLIENT_CHANGE_USER 512 /* Support the mysql_change_user() */
+#define CLIENT_INTERACTIVE 1024 /* This is an interactive client */
+#define CLIENT_SSL 2048 /* Switch to SSL after handshake */
+#define CLIENT_IGNORE_SIGPIPE 4096 /* IGNORE sigpipes */
+#define CLIENT_TRANSACTIONS 8196 /* Client knows about transactions */
+
+#define SERVER_STATUS_IN_TRANS 1 /* Transaction has started */
+#define SERVER_STATUS_AUTOCOMMIT 2 /* Server in auto_commit mode */
+
+#define MYSQL_ERRMSG_SIZE 200
+#define NET_READ_TIMEOUT 30 /* Timeout on read */
+#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
+
+typedef struct st_net {
+ Vio* vio;
+ my_socket fd; /* For Perl DBI/dbd */
+ int fcntl;
+ unsigned char *buff,*buff_end,*write_pos,*read_pos;
+ 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
+ */
+ unsigned long remain_in_buf,length, buf_length, where_b;
+ unsigned int *return_status;
+ unsigned char reading_or_writing;
+ char save_char;
+} NET;
+
+#define packet_error ((unsigned int) -1)
+
+enum enum_field_types { FIELD_TYPE_DECIMAL, FIELD_TYPE_TINY,
+ FIELD_TYPE_SHORT, FIELD_TYPE_LONG,
+ FIELD_TYPE_FLOAT, FIELD_TYPE_DOUBLE,
+ FIELD_TYPE_NULL, FIELD_TYPE_TIMESTAMP,
+ FIELD_TYPE_LONGLONG,FIELD_TYPE_INT24,
+ FIELD_TYPE_DATE, FIELD_TYPE_TIME,
+ FIELD_TYPE_DATETIME, FIELD_TYPE_YEAR,
+ FIELD_TYPE_NEWDATE,
+ FIELD_TYPE_ENUM=247,
+ FIELD_TYPE_SET=248,
+ FIELD_TYPE_TINY_BLOB=249,
+ FIELD_TYPE_MEDIUM_BLOB=250,
+ FIELD_TYPE_LONG_BLOB=251,
+ FIELD_TYPE_BLOB=252,
+ FIELD_TYPE_VAR_STRING=253,
+ FIELD_TYPE_STRING=254
+};
+
+#define FIELD_TYPE_CHAR FIELD_TYPE_TINY /* For compability */
+#define FIELD_TYPE_INTERVAL FIELD_TYPE_ENUM /* For compability */
+
+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);
+int net_flush(NET *net);
+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);
+
+struct rand_struct {
+ unsigned long seed1,seed2,max_value;
+ double max_value_dbl;
+};
+
+ /* The following is for user defined functions */
+
+enum Item_result {STRING_RESULT,REAL_RESULT,INT_RESULT};
+
+typedef struct st_udf_args
+{
+ unsigned int arg_count; /* Number of arguments */
+ enum Item_result *arg_type; /* Pointer to item_results */
+ char **args; /* Pointer to argument */
+ unsigned long *lengths; /* Length of string arguments */
+ char *maybe_null; /* Set to 1 for all maybe_null args */
+} UDF_ARGS;
+
+ /* This holds information about the result */
+
+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 */
+ char *ptr; /* free pointer for function data */
+ my_bool const_item; /* 0 if result is independent of arguments */
+} UDF_INIT;
+
+ /* Constants when using compression */
+#define NET_HEADER_SIZE 4 /* standard header size */
+#define COMP_HEADER_SIZE 3 /* compression header extra size */
+
+ /* Prototypes to password functions */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void randominit(struct rand_struct *,unsigned long seed1,
+ unsigned long seed2);
+double rnd(struct rand_struct *);
+void make_scrambled_password(char *to,const char *password);
+void get_salt_from_password(unsigned long *res,const char *password);
+void make_password_from_salt(char *to, unsigned long *hash_res);
+char *scramble(char *to,const char *message,const char *password,
+ my_bool old_ver);
+my_bool check_scramble(const char *, const char *message,
+ unsigned long *salt,my_bool old_ver);
+char *get_tty_password(char *opt_message);
+void hash_password(unsigned long *result, const char *password);
+#ifdef __cplusplus
+}
+#endif
+
+/* Some other useful functions */
+
+void my_init(void);
+void load_defaults(const char *conf_file, const char **groups,
+ int *argc, char ***argv);
+
+#define NULL_LENGTH ((unsigned long) ~0) /* For net_store_length */
+
+#ifdef __WIN__
+#define socket_errno WSAGetLastError()
+#else
+#define socket_errno errno
+#endif
+
+#endif
diff --git a/include/mysql_version.h.in b/include/mysql_version.h.in
new file mode 100755
index 00000000000..7cfef34176e
--- /dev/null
+++ b/include/mysql_version.h.in
@@ -0,0 +1,20 @@
+/* Copyright Abandoned 1996,1999 TCX DataKonsult AB & Monty Program KB & Detron HB
+ This file is public domain and comes with NO WARRANTY of any kind */
+
+/* Version numbers for protocol & mysqld */
+
+#ifdef _CUSTOMCONFIG_
+ #include <custom_conf.h>
+#else
+#define PROTOCOL_VERSION @PROTOCOL_VERSION@
+#define MYSQL_SERVER_VERSION "@VERSION@"
+#define FRM_VER @DOT_FRM_VERSION@
+#define MYSQL_VERSION_ID @MYSQL_VERSION_ID@
+#define MYSQL_PORT @MYSQL_TCP_PORT@
+#define MYSQL_UNIX_ADDR "@MYSQL_UNIX_ADDR@"
+
+/* mysqld compile time options */
+#ifndef MYSQL_CHARSET
+#define MYSQL_CHARSET "@default_charset@"
+#endif
+#endif
diff --git a/include/mysqld_error.h b/include/mysqld_error.h
new file mode 100644
index 00000000000..9d3e879f4f5
--- /dev/null
+++ b/include/mysqld_error.h
@@ -0,0 +1,195 @@
+/* Definefile for errormessagenumbers */
+
+#define ER_HASHCHK 1000
+#define ER_NISAMCHK 1001
+#define ER_NO 1002
+#define ER_YES 1003
+#define ER_CANT_CREATE_FILE 1004
+#define ER_CANT_CREATE_TABLE 1005
+#define ER_CANT_CREATE_DB 1006
+#define ER_DB_CREATE_EXISTS 1007
+#define ER_DB_DROP_EXISTS 1008
+#define ER_DB_DROP_DELETE 1009
+#define ER_DB_DROP_RMDIR 1010
+#define ER_CANT_DELETE_FILE 1011
+#define ER_CANT_FIND_SYSTEM_REC 1012
+#define ER_CANT_GET_STAT 1013
+#define ER_CANT_GET_WD 1014
+#define ER_CANT_LOCK 1015
+#define ER_CANT_OPEN_FILE 1016
+#define ER_FILE_NOT_FOUND 1017
+#define ER_CANT_READ_DIR 1018
+#define ER_CANT_SET_WD 1019
+#define ER_CHECKREAD 1020
+#define ER_DISK_FULL 1021
+#define ER_DUP_KEY 1022
+#define ER_ERROR_ON_CLOSE 1023
+#define ER_ERROR_ON_READ 1024
+#define ER_ERROR_ON_RENAME 1025
+#define ER_ERROR_ON_WRITE 1026
+#define ER_FILE_USED 1027
+#define ER_FILSORT_ABORT 1028
+#define ER_FORM_NOT_FOUND 1029
+#define ER_GET_ERRNO 1030
+#define ER_ILLEGAL_HA 1031
+#define ER_KEY_NOT_FOUND 1032
+#define ER_NOT_FORM_FILE 1033
+#define ER_NOT_KEYFILE 1034
+#define ER_OLD_KEYFILE 1035
+#define ER_OPEN_AS_READONLY 1036
+#define ER_OUTOFMEMORY 1037
+#define ER_OUT_OF_SORTMEMORY 1038
+#define ER_UNEXPECTED_EOF 1039
+#define ER_CON_COUNT_ERROR 1040
+#define ER_OUT_OF_RESOURCES 1041
+#define ER_BAD_HOST_ERROR 1042
+#define ER_HANDSHAKE_ERROR 1043
+#define ER_DBACCESS_DENIED_ERROR 1044
+#define ER_ACCESS_DENIED_ERROR 1045
+#define ER_NO_DB_ERROR 1046
+#define ER_UNKNOWN_COM_ERROR 1047
+#define ER_BAD_NULL_ERROR 1048
+#define ER_BAD_DB_ERROR 1049
+#define ER_TABLE_EXISTS_ERROR 1050
+#define ER_BAD_TABLE_ERROR 1051
+#define ER_NON_UNIQ_ERROR 1052
+#define ER_SERVER_SHUTDOWN 1053
+#define ER_BAD_FIELD_ERROR 1054
+#define ER_WRONG_FIELD_WITH_GROUP 1055
+#define ER_WRONG_GROUP_FIELD 1056
+#define ER_WRONG_SUM_SELECT 1057
+#define ER_WRONG_VALUE_COUNT 1058
+#define ER_TOO_LONG_IDENT 1059
+#define ER_DUP_FIELDNAME 1060
+#define ER_DUP_KEYNAME 1061
+#define ER_DUP_ENTRY 1062
+#define ER_WRONG_FIELD_SPEC 1063
+#define ER_PARSE_ERROR 1064
+#define ER_EMPTY_QUERY 1065
+#define ER_NONUNIQ_TABLE 1066
+#define ER_INVALID_DEFAULT 1067
+#define ER_MULTIPLE_PRI_KEY 1068
+#define ER_TOO_MANY_KEYS 1069
+#define ER_TOO_MANY_KEY_PARTS 1070
+#define ER_TOO_LONG_KEY 1071
+#define ER_KEY_COLUMN_DOES_NOT_EXITS 1072
+#define ER_BLOB_USED_AS_KEY 1073
+#define ER_TOO_BIG_FIELDLENGTH 1074
+#define ER_WRONG_AUTO_KEY 1075
+#define ER_READY 1076
+#define ER_NORMAL_SHUTDOWN 1077
+#define ER_GOT_SIGNAL 1078
+#define ER_SHUTDOWN_COMPLETE 1079
+#define ER_FORCING_CLOSE 1080
+#define ER_IPSOCK_ERROR 1081
+#define ER_NO_SUCH_INDEX 1082
+#define ER_WRONG_FIELD_TERMINATORS 1083
+#define ER_BLOBS_AND_NO_TERMINATED 1084
+#define ER_TEXTFILE_NOT_READABLE 1085
+#define ER_FILE_EXISTS_ERROR 1086
+#define ER_LOAD_INFO 1087
+#define ER_ALTER_INFO 1088
+#define ER_WRONG_SUB_KEY 1089
+#define ER_CANT_REMOVE_ALL_FIELDS 1090
+#define ER_CANT_DROP_FIELD_OR_KEY 1091
+#define ER_INSERT_INFO 1092
+#define ER_INSERT_TABLE_USED 1093
+#define ER_NO_SUCH_THREAD 1094
+#define ER_KILL_DENIED_ERROR 1095
+#define ER_NO_TABLES_USED 1096
+#define ER_TOO_BIG_SET 1097
+#define ER_NO_UNIQUE_LOGFILE 1098
+#define ER_TABLE_NOT_LOCKED_FOR_WRITE 1099
+#define ER_TABLE_NOT_LOCKED 1100
+#define ER_BLOB_CANT_HAVE_DEFAULT 1101
+#define ER_WRONG_DB_NAME 1102
+#define ER_WRONG_TABLE_NAME 1103
+#define ER_TOO_BIG_SELECT 1104
+#define ER_UNKNOWN_ERROR 1105
+#define ER_UNKNOWN_PROCEDURE 1106
+#define ER_WRONG_PARAMCOUNT_TO_PROCEDURE 1107
+#define ER_WRONG_PARAMETERS_TO_PROCEDURE 1108
+#define ER_UNKNOWN_TABLE 1109
+#define ER_FIELD_SPECIFIED_TWICE 1110
+#define ER_INVALID_GROUP_FUNC_USE 1111
+#define ER_UNSUPPORTED_EXTENSION 1112
+#define ER_TABLE_MUST_HAVE_COLUMNS 1113
+#define ER_RECORD_FILE_FULL 1114
+#define ER_UNKNOWN_CHARACTER_SET 1115
+#define ER_TOO_MANY_TABLES 1116
+#define ER_TOO_MANY_FIELDS 1117
+#define ER_TOO_BIG_ROWSIZE 1118
+#define ER_STACK_OVERRUN 1119
+#define ER_WRONG_OUTER_JOIN 1120
+#define ER_NULL_COLUMN_IN_INDEX 1121
+#define ER_CANT_FIND_UDF 1122
+#define ER_CANT_INITIALIZE_UDF 1123
+#define ER_UDF_NO_PATHS 1124
+#define ER_UDF_EXISTS 1125
+#define ER_CANT_OPEN_LIBRARY 1126
+#define ER_CANT_FIND_DL_ENTRY 1127
+#define ER_FUNCTION_NOT_DEFINED 1128
+#define ER_HOST_IS_BLOCKED 1129
+#define ER_HOST_NOT_PRIVILEGED 1130
+#define ER_PASSWORD_ANONYMOUS_USER 1131
+#define ER_PASSWORD_NOT_ALLOWED 1132
+#define ER_PASSWORD_NO_MATCH 1133
+#define ER_UPDATE_INFO 1134
+#define ER_CANT_CREATE_THREAD 1135
+#define ER_WRONG_VALUE_COUNT_ON_ROW 1136
+#define ER_CANT_REOPEN_TABLE 1137
+#define ER_INVALID_USE_OF_NULL 1138
+#define ER_REGEXP_ERROR 1139
+#define ER_MIX_OF_GROUP_FUNC_AND_FIELDS 1140
+#define ER_NONEXISTING_GRANT 1141
+#define ER_TABLEACCESS_DENIED_ERROR 1142
+#define ER_COLUMNACCESS_DENIED_ERROR 1143
+#define ER_ILLEGAL_GRANT_FOR_TABLE 1144
+#define ER_GRANT_WRONG_HOST_OR_USER 1145
+#define ER_NO_SUCH_TABLE 1146
+#define ER_NONEXISTING_TABLE_GRANT 1147
+#define ER_NOT_ALLOWED_COMMAND 1148
+#define ER_SYNTAX_ERROR 1149
+#define ER_DELAYED_CANT_CHANGE_LOCK 1150
+#define ER_TOO_MANY_DELAYED_THREADS 1151
+#define ER_ABORTING_CONNECTION 1152
+#define ER_NET_PACKET_TOO_LARGE 1153
+#define ER_NET_READ_ERROR_FROM_PIPE 1154
+#define ER_NET_FCNTL_ERROR 1155
+#define ER_NET_PACKETS_OUT_OF_ORDER 1156
+#define ER_NET_UNCOMPRESS_ERROR 1157
+#define ER_NET_READ_ERROR 1158
+#define ER_NET_READ_INTERRUPTED 1159
+#define ER_NET_ERROR_ON_WRITE 1160
+#define ER_NET_WRITE_INTERRUPTED 1161
+#define ER_TOO_LONG_STRING 1162
+#define ER_TABLE_CANT_HANDLE_BLOB 1163
+#define ER_TABLE_CANT_HANDLE_AUTO_INCREMENT 1164
+#define ER_DELAYED_INSERT_TABLE_LOCKED 1165
+#define ER_WRONG_COLUMN_NAME 1166
+#define ER_WRONG_KEY_COLUMN 1167
+#define ER_WRONG_MRG_TABLE 1168
+#define ER_DUP_UNIQUE 1169
+#define ER_BLOB_KEY_WITHOUT_LENGTH 1170
+#define ER_PRIMARY_CANT_HAVE_NULL 1171
+#define ER_TOO_MANY_ROWS 1172
+#define ER_REQUIRES_PRIMARY_KEY 1173
+#define ER_NO_RAID_COMPILED 1174
+#define ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE 1175
+#define ER_KEY_DOES_NOT_EXITS 1176
+#define ER_CHECK_NO_SUCH_TABLE 1177
+#define ER_CHECK_NOT_IMPLEMENTED 1178
+#define ER_CANT_DO_THIS_DURING_AN_TRANSACTION 1179
+#define ER_ERROR_DURING_COMMIT 1180
+#define ER_ERROR_DURING_ROLLBACK 1181
+#define ER_ERROR_DURING_FLUSH_LOGS 1182
+#define ER_ERROR_DURING_CHECKPOINT 1183
+#define ER_NEW_ABORTING_CONNECTION 1184
+#define ER_DUMP_NOT_IMPLEMENTED 1185
+#define ER_FLUSH_MASTER_BINLOG_CLOSED 1186
+#define ER_INDEX_REBUILD 1187
+#define ER_MASTER 1188
+#define ER_MASTER_NET_READ 1189
+#define ER_MASTER_NET_WRITE 1190
+#define ER_FT_MATCHING_KEY_NOT_FOUND 1191
+#define ER_ERROR_MESSAGES 192
diff --git a/include/mysys_err.h b/include/mysys_err.h
new file mode 100644
index 00000000000..7f5c3e1908b
--- /dev/null
+++ b/include/mysys_err.h
@@ -0,0 +1,57 @@
+/* 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 */
+
+#ifndef _mysys_err_h
+#define _mysys_err_h
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define GLOB 0 /* Error maps */
+#define GLOBERRS 23 /* Max number of error messages in map's */
+#define EE(X) globerrs[ X ] /* Defines to add error to right map */
+
+extern const char * NEAR globerrs[]; /* my_error_messages is here */
+
+/* Error message numbers in global map */
+#define EE_FILENOTFOUND 0
+#define EE_CANTCREATEFILE 1
+#define EE_READ 2
+#define EE_WRITE 3
+#define EE_BADCLOSE 4
+#define EE_OUTOFMEMORY 5
+#define EE_DELETE 6
+#define EE_LINK 7
+#define EE_EOFERR 9
+#define EE_CANTLOCK 10
+#define EE_CANTUNLOCK 11
+#define EE_DIR 12
+#define EE_STAT 13
+#define EE_CANT_CHSIZE 14
+#define EE_CANT_OPEN_STREAM 15
+#define EE_GETWD 16
+#define EE_SETWD 17
+#define EE_LINK_WARNING 18
+#define EE_OPEN_WARNING 19
+#define EE_DISK_FULL 20
+#define EE_CANT_MKDIR 21
+#define EE_UNKNOWN_CHARSET 22
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/include/nisam.h b/include/nisam.h
new file mode 100644
index 00000000000..77ca12bbc5c
--- /dev/null
+++ b/include/nisam.h
@@ -0,0 +1,213 @@
+/* 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 should be included when using nisam_funktions */
+/* Author: Michael Widenius */
+
+#ifndef _nisam_h
+#define _nisam_h
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef _my_base_h
+#include <my_base.h>
+#endif
+ /* defines used by nisam-funktions */
+
+#define N_MAXKEY 16 /* Max allowed keys */
+#define N_MAXKEY_SEG 16 /* Max segments for key */
+#define N_MAX_KEY_LENGTH 256 /* May be increased up to 500 */
+#define N_MAX_KEY_BUFF (N_MAX_KEY_LENGTH+N_MAXKEY_SEG+sizeof(double)-1)
+#define N_MAX_POSSIBLE_KEY_BUFF 500+9
+
+#define N_NAME_IEXT ".ISM"
+#define N_NAME_DEXT ".ISD"
+#define NI_POS_ERROR (~ (ulong) 0)
+
+
+ /* Param to/from nisam_info */
+
+typedef struct st_n_isaminfo /* Struct from h_info */
+{
+ ulong records; /* Records in database */
+ ulong deleted; /* Deleted records in database */
+ ulong recpos; /* Pos for last used record */
+ ulong newrecpos; /* Pos if we write new record */
+ ulong dupp_key_pos; /* Position to record with dupp key */
+ ulong data_file_length, /* Length of data file */
+ max_data_file_length,
+ index_file_length,
+ max_index_file_length,
+ delete_length;
+ uint reclength; /* Recordlength */
+ uint mean_reclength; /* Mean recordlength (if packed) */
+ uint keys; /* How many keys used */
+ uint options; /* HA_OPTIONS_... used */
+ int errkey, /* With key was dupplicated on err */
+ sortkey; /* clustered by this key */
+ File filenr; /* (uniq) filenr for datafile */
+ time_t create_time; /* When table was created */
+ time_t isamchk_time;
+ time_t update_time;
+ ulong *rec_per_key; /* for sql optimizing */
+} N_ISAMINFO;
+
+
+ /* Info saved on file for each info-part */
+
+#ifdef __WATCOMC__
+#pragma pack(2)
+#define uint uint16 /* Same format as in MSDOS */
+#endif
+
+#ifdef __ZTC__
+#pragma ZTC align 2
+#define uint uint16 /* Same format as in MSDOS */
+#endif
+
+typedef struct st_n_save_keyseg /* Key-portion */
+{
+ uint8 type; /* Typ av nyckel (f|r sort) */
+ uint8 flag; /* HA_DIFF_LENGTH */
+ uint16 start; /* Start of key in record */
+ uint16 length; /* Keylength */
+} N_SAVE_KEYSEG;
+
+typedef struct st_n_save_keydef /* Key definition with create & info */
+{
+ uint8 flag; /* NOSAME, PACK_USED */
+ uint8 keysegs; /* Number of key-segment */
+ uint16 block_length; /* Length of keyblock (auto) */
+ uint16 keylength; /* Tot length of keyparts (auto) */
+ uint16 minlength; /* min length of (packed) key (auto) */
+ uint16 maxlength; /* max length of (packed) key (auto) */
+} N_SAVE_KEYDEF;
+
+typedef struct st_n_save_recinfo /* Info of record */
+{
+ int16 type; /* en_fieldtype */
+ uint16 length; /* length of field */
+} N_SAVE_RECINFO;
+
+
+#ifdef __ZTC__
+#pragma ZTC align
+#undef uint
+#endif
+
+#ifdef __WATCOMC__
+#pragma pack()
+#undef uint
+#endif
+
+
+struct st_isam_info; /* For referense */
+
+#ifndef ISAM_LIBRARY
+typedef struct st_isam_info N_INFO;
+#endif
+
+typedef struct st_n_keyseg /* Key-portion */
+{
+ N_SAVE_KEYSEG base;
+} N_KEYSEG;
+
+
+typedef struct st_n_keydef /* Key definition with open & info */
+{
+ N_SAVE_KEYDEF base;
+ N_KEYSEG seg[N_MAXKEY_SEG+1];
+ int (*bin_search)(struct st_isam_info *info,struct st_n_keydef *keyinfo,
+ uchar *page,uchar *key,
+ uint key_len,uint comp_flag,uchar * *ret_pos,
+ uchar *buff);
+ uint (*get_key)(struct st_n_keydef *keyinfo,uint nod_flag,uchar * *page,
+ uchar *key);
+} N_KEYDEF;
+
+
+typedef struct st_decode_tree /* Decode huff-table */
+{
+ uint16 *table;
+ uint quick_table_bits;
+ byte *intervalls;
+} DECODE_TREE;
+
+
+struct st_bit_buff;
+
+typedef struct st_n_recinfo /* Info of record */
+{
+ N_SAVE_RECINFO base;
+#ifndef NOT_PACKED_DATABASES
+ void (*unpack)(struct st_n_recinfo *rec,struct st_bit_buff *buff,
+ uchar *start,uchar *end);
+ enum en_fieldtype base_type;
+ uint space_length_bits,pack_type;
+ DECODE_TREE *huff_tree;
+#endif
+} N_RECINFO;
+
+
+extern my_string nisam_log_filename; /* Name of logfile */
+extern uint nisam_block_size;
+extern my_bool nisam_flush;
+
+ /* Prototypes for nisam-functions */
+
+extern int nisam_close(struct st_isam_info *file);
+extern int nisam_delete(struct st_isam_info *file,const byte *buff);
+extern struct st_isam_info *nisam_open(const char *name,int mode,
+ uint wait_if_locked);
+extern int nisam_panic(enum ha_panic_function function);
+extern int nisam_rfirst(struct st_isam_info *file,byte *buf,int inx);
+extern int nisam_rkey(struct st_isam_info *file,byte *buf,int inx,
+ const byte *key,
+ uint key_len, enum ha_rkey_function search_flag);
+extern int nisam_rlast(struct st_isam_info *file,byte *buf,int inx);
+extern int nisam_rnext(struct st_isam_info *file,byte *buf,int inx);
+extern int nisam_rprev(struct st_isam_info *file,byte *buf,int inx);
+extern int nisam_rrnd(struct st_isam_info *file,byte *buf,ulong pos);
+extern int nisam_rsame(struct st_isam_info *file,byte *record,int inx);
+extern int nisam_rsame_with_pos(struct st_isam_info *file,byte *record,
+ int inx,ulong pos);
+extern int nisam_update(struct st_isam_info *file,const byte *old,
+ const byte *new_record);
+extern int nisam_write(struct st_isam_info *file,const byte *buff);
+extern int nisam_info(struct st_isam_info *file,N_ISAMINFO *x,int flag);
+extern ulong nisam_position(struct st_isam_info *info);
+extern int nisam_lock_database(struct st_isam_info *file,int lock_type);
+extern int nisam_create(const char *name,uint keys,N_KEYDEF *keyinfo,
+ N_RECINFO *recinfo,ulong records,
+ ulong reloc,uint flags,uint options,
+ ulong data_file_length);
+extern int nisam_extra(struct st_isam_info *file,
+ enum ha_extra_function function);
+extern ulong nisam_records_in_range(struct st_isam_info *info,int inx,
+ const byte *start_key,uint start_key_len,
+ enum ha_rkey_function start_search_flag,
+ const byte *end_key,uint end_key_len,
+ enum ha_rkey_function end_search_flag);
+extern int nisam_log(int activate_log);
+extern int nisam_is_changed(struct st_isam_info *info);
+extern uint _calc_blob_length(uint length , const byte *pos);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/include/queues.h b/include/queues.h
new file mode 100644
index 00000000000..99001bfbf6d
--- /dev/null
+++ b/include/queues.h
@@ -0,0 +1,57 @@
+/* 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 */
+
+/*
+ Code for generell handling of priority Queues.
+ Implemention of queues from "Algoritms in C" by Robert Sedgewick.
+ Copyright Monty Program KB.
+ By monty.
+*/
+
+#ifndef _queues_h
+#define _queues_h
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct st_queue {
+ byte **root;
+ void *first_cmp_arg;
+ uint elements;
+ uint max_elements;
+ uint offset_to_key; /* compare is done on element+offset */
+ int max_at_top; /* Set if queue_top gives max */
+ int (*compare)(void *, byte *,byte *);
+} QUEUE;
+
+#define queue_top(queue) ((queue)->root[1])
+#define queue_element(queue,index) ((queue)->root[index+1])
+#define queue_end(queue) ((queue)->root[(queue)->elements])
+#define queue_replaced(queue) _downheap(queue,1)
+
+int init_queue(QUEUE *queue,uint max_elements,uint offset_to_key,
+ pbool max_at_top, int (*compare)(void *,byte *, byte *),
+ void *first_cmp_arg);
+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);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/include/raid.h b/include/raid.h
new file mode 100644
index 00000000000..119f2b9b3b8
--- /dev/null
+++ b/include/raid.h
@@ -0,0 +1,155 @@
+/* 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 */
+
+/* Parser needs these defines always, even if USE_RAID is not defined */
+#define RAID_TYPE_0 1 // Striping
+#define RAID_TYPE_x 2 // Some new modes
+#define RAID_TYPE_y 3 //
+
+#define RAID_DEFAULT_CHUNKS 4
+#define RAID_DEFAULT_CHUNKSIZE 256*1024 /* 256kB */
+
+extern const char *raid_type_string[];
+
+#if defined(USE_RAID)
+
+#ifdef __GNUC__
+#pragma interface /* gcc class implementation */
+#endif
+#include "my_dir.h"
+
+/* Trap all occurences of my_...() in source and use our wrapper around this function */
+
+#ifdef MAP_TO_USE_RAID
+#define my_read(A,B,C,D) my_raid_read(A,B,C,D)
+#define my_write(A,B,C,D) my_raid_write(A,B,C,D)
+#define my_pwrite(A,B,C,D,E) my_raid_pwrite(A,B,C,D,E)
+#define my_pread(A,B,C,D,E) my_raid_pread(A,B,C,D,E)
+#define my_chsize(A,B,C) my_raid_chsize(A,B,C)
+#define my_close(A,B) my_raid_close(A,B)
+#define my_tell(A,B) my_raid_tell(A,B)
+#define my_seek(A,B,C,D) my_raid_seek(A,B,C,D)
+#define my_lock(A,B,C,D,E) my_raid_lock(A,B,C,D,E)
+#define my_fstat(A,B,C) my_raid_fstat(A,B,C)
+#endif /* MAP_TO_USE_RAID */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ void init_raid(void);
+ void end_raid(void);
+
+ bool is_raid(File fd);
+ File my_raid_create(const char *FileName, int CreateFlags, int access_flags,
+ uint raid_type, uint raid_chunks, ulong raid_chunksize,
+ myf MyFlags);
+ File my_raid_open(const char *FileName, int Flags,
+ uint raid_type, uint raid_chunks, ulong raid_chunksize,
+ myf MyFlags);
+ int my_raid_rename(const char *from, const char *to, uint raid_chunks,
+ myf MyFlags);
+ int my_raid_delete(const char *from, uint raid_chunks, myf MyFlags);
+ int my_raid_redel(const char *old_name, const char *new_name,
+ uint raid_chunks, myf MyFlags);
+
+ my_off_t my_raid_seek(File fd, my_off_t pos, int whence, myf MyFlags);
+ my_off_t my_raid_tell(File fd, myf MyFlags);
+
+ uint my_raid_write(File,const byte *Buffer, uint Count, myf MyFlags);
+ uint my_raid_read(File Filedes, byte *Buffer, uint Count, myf MyFlags);
+
+ uint my_raid_pread(File Filedes, byte *Buffer, uint Count, my_off_t offset,
+ myf MyFlags);
+ uint my_raid_pwrite(int Filedes, const byte *Buffer, uint Count,
+ my_off_t offset, myf MyFlags);
+
+ int my_raid_lock(File,int locktype, my_off_t start, my_off_t length,
+ myf MyFlags);
+ int my_raid_chsize(File fd, my_off_t newlength, myf MyFlags);
+ int my_raid_close(File, myf MyFlags);
+ int my_raid_fstat(int Filedes, struct stat *buf, myf MyFlags);
+
+ const char *my_raid_type(int raid_type);
+
+#ifdef __cplusplus
+}
+
+class RaidName {
+ public:
+ RaidName(const char *FileName);
+ ~RaidName();
+ bool IsRaid();
+ int Rename(const char * from, const char * to, myf MyFlags);
+ private:
+ uint _raid_type; // RAID_TYPE_0 or RAID_TYPE_1 or RAID_TYPE_5
+ uint _raid_chunks; // 1..n
+ ulong _raid_chunksize; // 1..n in bytes
+};
+
+class RaidFd {
+ public:
+ RaidFd(uint raid_type, uint raid_chunks , ulong raid_chunksize);
+ ~RaidFd();
+ File Create(const char *FileName, int CreateFlags, int access_flags,
+ myf MyFlags);
+ File Open(const char *FileName, int Flags, myf MyFlags);
+ my_off_t Seek(my_off_t pos,int whence,myf MyFlags);
+ my_off_t Tell(myf MyFlags);
+ int Write(const byte *Buffer, uint Count, myf MyFlags);
+ int Read(const byte *Buffer, uint Count, myf MyFlags);
+ int Lock(int locktype, my_off_t start, my_off_t length, myf MyFlags);
+ int Chsize(File fd, my_off_t newlength, myf MyFlags);
+ int Fstat(int fd, MY_STAT *stat_area, myf MyFlags );
+ int Close(myf MyFlags);
+ static bool IsRaid(File fd);
+ static DYNAMIC_ARRAY _raid_map; /* Map of RaidFD* */
+ private:
+
+ uint _raid_type; // RAID_TYPE_0 or RAID_TYPE_1 or RAID_TYPE_5
+ uint _raid_chunks; // 1..n
+ ulong _raid_chunksize; // 1..n in bytes
+
+ ulong _total_block; // We are operating with block no x (can be 0..many).
+ uint _this_block; // can be 0.._raid_chunks
+ uint _remaining_bytes; // Maximum bytes that can be written in this block
+
+ my_off_t _position;
+ my_off_t _size; // Cached file size for faster seek(SEEK_END)
+ File _fd;
+ File *_fd_vector; /* Array of File */
+ off_t *_seek_vector; /* Array of cached seek positions */
+
+ inline void Calculate()
+ {
+ DBUG_ENTER("RaidFd::_Calculate");
+ DBUG_PRINT("info",("_position: %lu _raid_chunksize: %d, _size: %lu",
+ (ulong) _position, _raid_chunksize, (ulong) _size));
+
+ _total_block = (ulong) (_position / _raid_chunksize);
+ _this_block = _total_block % _raid_chunks; // can be 0.._raid_chunks
+ _remaining_bytes = (uint) (_raid_chunksize -
+ (_position - _total_block * _raid_chunksize));
+ DBUG_PRINT("info",
+ ("_total_block: %d this_block: %d _remaining_bytes:%d",
+ _total_block, _this_block, _remaining_bytes));
+ DBUG_VOID_RETURN;
+ }
+};
+
+#endif /* __cplusplus */
+#endif /* USE_RAID */
diff --git a/include/sslopt-case.h b/include/sslopt-case.h
new file mode 100644
index 00000000000..db636176b5c
--- /dev/null
+++ b/include/sslopt-case.h
@@ -0,0 +1,42 @@
+/* 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 */
+
+#ifdef HAVE_OPENSSL
+ case OPT_SSL_SSL:
+ opt_use_ssl = 1; //true
+ break;
+ case OPT_SSL_KEY:
+ opt_use_ssl = 1; //true
+ my_free(opt_ssl_key, MYF(MY_ALLOW_ZERO_PTR));
+ opt_ssl_key = my_strdup(optarg, MYF(0));
+ break;
+ case OPT_SSL_CERT:
+ opt_use_ssl = 1; //true
+ my_free(opt_ssl_cert, MYF(MY_ALLOW_ZERO_PTR));
+ opt_ssl_cert = my_strdup(optarg, MYF(0));
+ break;
+ case OPT_SSL_CA:
+ opt_use_ssl = 1; //true
+ my_free(opt_ssl_ca, MYF(MY_ALLOW_ZERO_PTR));
+ opt_ssl_ca = my_strdup(optarg, MYF(0));
+ 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));
+ break;
+#endif
diff --git a/include/sslopt-longopts.h b/include/sslopt-longopts.h
new file mode 100644
index 00000000000..2f58f0e9265
--- /dev/null
+++ b/include/sslopt-longopts.h
@@ -0,0 +1,31 @@
+/* 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 */
+
+#ifdef HAVE_OPENSSL
+
+#define OPT_SSL_SSL 200
+#define OPT_SSL_KEY 201
+#define OPT_SSL_CERT 202
+#define OPT_SSL_CA 203
+#define OPT_SSL_CAPATH 204
+ {"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},
+
+#endif /* HAVE_OPENSSL */
diff --git a/include/sslopt-usage.h b/include/sslopt-usage.h
new file mode 100644
index 00000000000..5b2b4a88709
--- /dev/null
+++ b/include/sslopt-usage.h
@@ -0,0 +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,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should 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 */
+
+#ifdef OPEN_SSL
+ puts("\
+ --ssl Use SSL for connection (automatically set with other flags\n\
+ --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)");
+#endif
diff --git a/include/sslopt-vars.h b/include/sslopt-vars.h
new file mode 100644
index 00000000000..597ab4d9fa6
--- /dev/null
+++ b/include/sslopt-vars.h
@@ -0,0 +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,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should 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 */
+
+#ifdef HAVE_OPENSSL
+static my_bool opt_use_ssl = 0;
+static char *opt_ssl_key = 0;
+static char *opt_ssl_cert = 0;
+static char *opt_ssl_ca = 0;
+static char *opt_ssl_capath = 0;
+#endif
diff --git a/include/t_ctype.h b/include/t_ctype.h
new file mode 100644
index 00000000000..f6e799828e6
--- /dev/null
+++ b/include/t_ctype.h
@@ -0,0 +1,239 @@
+/*
+ Copyright (C) 1998, 1999 by Pruet Boonma, all rights reserved.
+ Copyright (C) 1998 by Theppitak Karoonboonyanan, all rights reserved.
+ Permission to use, copy, modify, distribute and sell this software
+ and its documentation for any purpose is hereby granted without fee,
+ provided that the above copyright notice appear in all copies.
+ Smaphan Raruenrom and Pruet Boonma makes no representations about
+ the suitability of this software for any purpose. It is provided
+ "as is" without express or implied warranty.
+*/
+
+/* LC_COLLATE category + Level information */
+
+#ifndef _t_ctype_h
+#define _t_ctype_h
+
+#define TOT_LEVELS 5
+#define LAST_LEVEL 4 /* TOT_LEVELS - 1 */
+
+#define IGNORE 0
+
+
+/* level 1 symbols & order */
+enum l1_symbols {
+ L1_08 = TOT_LEVELS,
+ L1_18,
+ L1_28,
+ L1_38,
+ L1_48,
+ L1_58,
+ L1_68,
+ L1_78,
+ L1_88,
+ L1_98,
+ L1_A8,
+ L1_B8,
+ L1_C8,
+ L1_D8,
+ L1_E8,
+ L1_F8,
+ L1_G8,
+ L1_H8,
+ L1_I8,
+ L1_J8,
+ L1_K8,
+ L1_L8,
+ L1_M8,
+ L1_N8,
+ L1_O8,
+ L1_P8,
+ L1_Q8,
+ L1_R8,
+ L1_S8,
+ L1_T8,
+ L1_U8,
+ L1_V8,
+ L1_W8,
+ L1_X8,
+ L1_Y8,
+ L1_Z8,
+ L1_KO_KAI,
+ L1_KHO_KHAI,
+ L1_KHO_KHUAT,
+ L1_KHO_KHWAI,
+ L1_KHO_KHON,
+ L1_KHO_RAKHANG,
+ L1_NGO_NGU,
+ L1_CHO_CHAN,
+ L1_CHO_CHING,
+ L1_CHO_CHANG,
+ L1_SO_SO,
+ L1_CHO_CHOE,
+ L1_YO_YING,
+ L1_DO_CHADA,
+ L1_TO_PATAK,
+ L1_THO_THAN,
+ L1_THO_NANGMONTHO,
+ L1_THO_PHUTHAO,
+ L1_NO_NEN,
+ L1_DO_DEK,
+ L1_TO_TAO,
+ L1_THO_THUNG,
+ L1_THO_THAHAN,
+ L1_THO_THONG,
+ L1_NO_NU,
+ L1_BO_BAIMAI,
+ L1_PO_PLA,
+ L1_PHO_PHUNG,
+ L1_FO_FA,
+ L1_PHO_PHAN,
+ L1_FO_FAN,
+ L1_PHO_SAMPHAO,
+ L1_MO_MA,
+ L1_YO_YAK,
+ L1_RO_RUA,
+ L1_RU,
+ L1_LO_LING,
+ L1_LU,
+ L1_WO_WAEN,
+ L1_SO_SALA,
+ L1_SO_RUSI,
+ L1_SO_SUA,
+ L1_HO_HIP,
+ L1_LO_CHULA,
+ L1_O_ANG,
+ L1_HO_NOKHUK,
+ L1_NKHIT,
+ L1_SARA_A,
+ L1_MAI_HAN_AKAT,
+ L1_SARA_AA,
+ L1_SARA_AM,
+ L1_SARA_I,
+ L1_SARA_II,
+ L1_SARA_UE,
+ L1_SARA_UEE,
+ L1_SARA_U,
+ L1_SARA_UU,
+ L1_SARA_E,
+ L1_SARA_AE,
+ L1_SARA_O,
+ L1_SARA_AI_MAIMUAN,
+ L1_SARA_AI_MAIMALAI
+};
+
+/* level 2 symbols & order */
+enum l2_symbols {
+ L2_BLANK = TOT_LEVELS,
+ L2_THAII,
+ L2_YAMAK,
+ L2_PINTHU,
+ L2_GARAN,
+ L2_TYKHU,
+ L2_TONE1,
+ L2_TONE2,
+ L2_TONE3,
+ L2_TONE4
+};
+
+/* level 3 symbols & order */
+enum l3_symbols {
+ L3_BLANK = TOT_LEVELS,
+ L3_SPACE,
+ L3_NB_SACE,
+ L3_LOW_LINE,
+ L3_HYPHEN,
+ L3_COMMA,
+ L3_SEMICOLON,
+ L3_COLON,
+ L3_EXCLAMATION,
+ L3_QUESTION,
+ L3_SOLIDUS,
+ L3_FULL_STOP,
+ L3_PAIYAN_NOI,
+ L3_MAI_YAMOK,
+ L3_GRAVE,
+ L3_CIRCUMFLEX,
+ L3_TILDE,
+ L3_APOSTROPHE,
+ L3_QUOTATION,
+ L3_L_PARANTHESIS,
+ L3_L_BRACKET,
+ L3_L_BRACE,
+ L3_R_BRACE,
+ L3_R_BRACKET,
+ L3_R_PARENTHESIS,
+ L3_AT,
+ L3_BAHT,
+ L3_DOLLAR,
+ L3_FONGMAN,
+ L3_ANGKHANKHU,
+ L3_KHOMUT,
+ L3_ASTERISK,
+ L3_BK_SOLIDUS,
+ L3_AMPERSAND,
+ L3_NUMBER,
+ L3_PERCENT,
+ L3_PLUS,
+ L3_LESS_THAN,
+ L3_EQUAL,
+ L3_GREATER_THAN,
+ L3_V_LINE
+};
+
+/* level 4 symbols & order */
+enum l4_symbols {
+ L4_BLANK = TOT_LEVELS,
+ L4_MIN,
+ L4_CAP,
+ L4_EXT
+};
+
+enum level_symbols {
+ L_UPRUPR = TOT_LEVELS,
+ L_UPPER,
+ L_MIDDLE,
+ L_LOWER
+};
+
+#define _is(c) (t_ctype[(c)][LAST_LEVEL])
+#define _level 8
+#define _consnt 16
+#define _ldvowel 32
+#define _fllwvowel 64
+#define _uprvowel 128
+#define _lwrvowel 256
+#define _tone 512
+#define _diacrt1 1024
+#define _diacrt2 2048
+#define _combine 4096
+#define _stone 8192
+#define _tdig 16384
+#define _rearvowel (_fllwvowel | _uprvowel | _lwrvowel)
+#define _diacrt (_diacrt1 | _diacrt2)
+#define levelof(c) ( _is(c) & _level )
+#define isthai(c) ( (c) >= 128 )
+#define istalpha(c) ( _is(c) & (_consnt|_ldvowel|_rearvowel|\
+ _tone|_diacrt1|_diacrt2) )
+#define isconsnt(c) ( _is(c) & _consnt )
+#define isldvowel(c) ( _is(c) & _ldvowel )
+#define isfllwvowel(c) ( _is(c) & _fllwvowel )
+#define ismidvowel(c) ( _is(c) & (_ldvowel|_fllwvowel) )
+#define isuprvowel(c) ( _is(c) & _uprvowel )
+#define islwrvowel(c) ( _is(c) & _lwrvowel )
+#define isuprlwrvowel(c) ( _is(c) & (_lwrvowel | _uprvowel))
+#define isrearvowel(c) ( _is(c) & _rearvowel )
+#define isvowel(c) ( _is(c) & (_ldvowel|_rearvowel) )
+#define istone(c) ( _is(c) & _tone )
+#define isunldable(c) ( _is(c) & (_rearvowel|_tone|_diacrt1|_diacrt2) )
+#define iscombinable(c) ( _is(c) & _combine )
+#define istdigit(c) ( _is(c) & _tdig )
+#define isstone(c) ( _is(c) & _stone )
+#define isdiacrt1(c) ( _is(c) & _diacrt1)
+#define isdiacrt2(c) ( _is(c) & _diacrt2)
+#define isdiacrt(c) ( _is(c) & _diacrt)
+
+/* Function prototype called by sql/field.cc */
+void ThNormalize(uchar* ptr, uint field_length, const uchar* from, uint length);
+
+#endif
diff --git a/include/thr_alarm.h b/include/thr_alarm.h
new file mode 100644
index 00000000000..931896855f3
--- /dev/null
+++ b/include/thr_alarm.h
@@ -0,0 +1,100 @@
+/* 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 */
+
+/* Prototypes when using thr_alarm library functions */
+
+#ifndef _thr_alarm_h
+#define _thr_alarm_h
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct st_alarm {
+ ulong expire_time;
+ int alarmed; /* 1 when alarm is due */
+ pthread_t thread;
+ my_bool malloced;
+} ALARM;
+
+#ifndef USE_ALARM_THREAD
+#define USE_ONE_SIGNAL_HAND /* One must call process_alarm */
+#endif
+#ifdef HAVE_LINUXTHREADS
+#define THR_CLIENT_ALARM SIGALRM
+#else
+#define THR_CLIENT_ALARM SIGUSR1
+#endif
+#ifdef HAVE_rts_threads
+#undef USE_ONE_SIGNAL_HAND
+#define USE_ALARM_THREAD
+#define THR_SERVER_ALARM SIGUSR1
+#else
+#define THR_SERVER_ALARM SIGALRM
+#endif
+
+#ifdef DONT_USE_THR_ALARM
+
+#define USE_ALARM_THREAD
+#undef USE_ONE_SIGNAL_HAND
+
+typedef struct st_win_timer
+{
+ uint crono;
+} thr_alarm_t;
+
+#define thr_alarm_init(A) (A)->crono=0
+#define thr_alarm_in_use(A) (A).crono
+#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
+
+#ifdef __WIN__
+typedef struct st_win_timer
+{
+ uint crono;
+} thr_alarm_t;
+
+bool thr_got_alarm(thr_alarm_t *alrm);
+#define thr_alarm_init(A) (A)->crono=0
+#define thr_alarm_in_use(A) (A)->crono
+#define init_thr_alarm(A)
+#define thr_alarm_kill(A)
+#else
+
+typedef int* thr_alarm_t;
+#define thr_got_alarm(thr_alarm) (*thr_alarm)
+#define thr_alarm_init(A) (*A)=0
+#define thr_alarm_in_use(A) ((A) != 0)
+void init_thr_alarm(uint max_alarm);
+void thr_alarm_kill(pthread_t thread_id);
+sig_handler process_alarm(int);
+#endif /* __WIN__ */
+
+bool thr_alarm(thr_alarm_t *alarmed,uint sec, ALARM *buff);
+void thr_end_alarm(thr_alarm_t *alarmed);
+void end_thr_alarm(void);
+#endif /* DONT_USE_THR_ALARM */
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/include/thr_lock.h b/include/thr_lock.h
new file mode 100644
index 00000000000..288a762703d
--- /dev/null
+++ b/include/thr_lock.h
@@ -0,0 +1,89 @@
+/* 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 */
+
+/* For use with thr_lock:s */
+
+#ifndef _thr_lock_h
+#define _thr_lock_h
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <my_pthread.h>
+#include <my_list.h>
+
+struct st_thr_lock;
+
+enum thr_lock_type { TL_IGNORE=-1,
+ TL_UNLOCK, TL_READ, TL_READ_HIGH_PRIORITY,
+ TL_READ_NO_INSERT,
+ TL_WRITE_ALLOW_WRITE, TL_WRITE_ALLOW_READ,
+ TL_WRITE_CONCURRENT_INSERT,
+ TL_WRITE_DELAYED, TL_WRITE_LOW_PRIORITY, TL_WRITE,
+ TL_WRITE_ONLY};
+
+extern ulong max_write_lock_count;
+extern my_bool thr_lock_inited;
+
+typedef struct st_thr_lock_data {
+ pthread_t thread;
+ struct st_thr_lock_data *next,**prev;
+ struct st_thr_lock *lock;
+ pthread_cond_t *cond;
+ enum thr_lock_type type;
+ ulong thread_id;
+ void *status_param; /* Param to status functions */
+} THR_LOCK_DATA;
+
+struct st_lock_list {
+ THR_LOCK_DATA *data,**last;
+};
+
+typedef struct st_thr_lock {
+ LIST list;
+ pthread_mutex_t mutex;
+ struct st_lock_list read_wait;
+ struct st_lock_list read;
+ struct st_lock_list write_wait;
+ struct st_lock_list write;
+/* write_lock_count is incremented for write locks and reset on read locks */
+ ulong write_lock_count;
+ uint read_no_write_count;
+ void (*get_status)(void*); /* When one gets a lock */
+ void (*copy_status)(void*,void*);
+ void (*update_status)(void*); /* Before release of write */
+ my_bool (*check_status)(void *);
+} THR_LOCK;
+
+
+my_bool init_thr_lock(void); /* Must be called once/thread */
+void thr_lock_init(THR_LOCK *lock);
+void thr_lock_delete(THR_LOCK *lock);
+void thr_lock_data_init(THR_LOCK *lock,THR_LOCK_DATA *data,
+ void *status_param);
+int thr_lock(THR_LOCK_DATA *data,enum thr_lock_type lock_type);
+void thr_unlock(THR_LOCK_DATA *data);
+int thr_multi_lock(THR_LOCK_DATA **data,uint count);
+void thr_multi_unlock(THR_LOCK_DATA **data,uint count);
+void thr_abort_locks(THR_LOCK *lock);
+void thr_print_locks(void); /* For debugging */
+my_bool thr_upgrade_write_delay_lock(THR_LOCK_DATA *data);
+my_bool thr_reschedule_write_lock(THR_LOCK_DATA *data);
+#ifdef __cplusplus
+}
+#endif
+#endif /* _thr_lock_h */
diff --git a/include/violite.h b/include/violite.h
new file mode 100644
index 00000000000..e7c3e8ede81
--- /dev/null
+++ b/include/violite.h
@@ -0,0 +1,115 @@
+/* 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 */
+
+/*
+ * 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/install-sh b/install-sh
new file mode 100755
index 00000000000..ebc66913e94
--- /dev/null
+++ b/install-sh
@@ -0,0 +1,250 @@
+#! /bin/sh
+#
+# install - install a program, script, or datafile
+# This comes from X11R5 (mit/util/scripts/install.sh).
+#
+# Copyright 1991 by the Massachusetts Institute of Technology
+#
+# Permission to use, copy, modify, distribute, and sell this software and its
+# documentation for any purpose is hereby granted without fee, provided that
+# the above copyright notice appear in all copies and that both that
+# copyright notice and this permission notice appear in supporting
+# documentation, and that the name of M.I.T. not be used in advertising or
+# publicity pertaining to distribution of the software without specific,
+# written prior permission. M.I.T. makes no representations about the
+# suitability of this software for any purpose. It is provided "as is"
+# without express or implied warranty.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# `make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch. It can only install one file at a time, a restriction
+# shared with many OS's install programs.
+
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit="${DOITPROG-}"
+
+
+# put in absolute paths if you don't have them in your path; or use env. vars.
+
+mvprog="${MVPROG-mv}"
+cpprog="${CPPROG-cp}"
+chmodprog="${CHMODPROG-chmod}"
+chownprog="${CHOWNPROG-chown}"
+chgrpprog="${CHGRPPROG-chgrp}"
+stripprog="${STRIPPROG-strip}"
+rmprog="${RMPROG-rm}"
+mkdirprog="${MKDIRPROG-mkdir}"
+
+transformbasename=""
+transform_arg=""
+instcmd="$mvprog"
+chmodcmd="$chmodprog 0755"
+chowncmd=""
+chgrpcmd=""
+stripcmd=""
+rmcmd="$rmprog -f"
+mvcmd="$mvprog"
+src=""
+dst=""
+dir_arg=""
+
+while [ x"$1" != x ]; do
+ case $1 in
+ -c) instcmd="$cpprog"
+ shift
+ continue;;
+
+ -d) dir_arg=true
+ shift
+ continue;;
+
+ -m) chmodcmd="$chmodprog $2"
+ shift
+ shift
+ continue;;
+
+ -o) chowncmd="$chownprog $2"
+ shift
+ shift
+ continue;;
+
+ -g) chgrpcmd="$chgrpprog $2"
+ shift
+ shift
+ continue;;
+
+ -s) stripcmd="$stripprog"
+ shift
+ continue;;
+
+ -t=*) transformarg=`echo $1 | sed 's/-t=//'`
+ shift
+ continue;;
+
+ -b=*) transformbasename=`echo $1 | sed 's/-b=//'`
+ shift
+ continue;;
+
+ *) if [ x"$src" = x ]
+ then
+ src=$1
+ else
+ # this colon is to work around a 386BSD /bin/sh bug
+ :
+ dst=$1
+ fi
+ shift
+ continue;;
+ esac
+done
+
+if [ x"$src" = x ]
+then
+ echo "install: no input file specified"
+ exit 1
+else
+ true
+fi
+
+if [ x"$dir_arg" != x ]; then
+ dst=$src
+ src=""
+
+ if [ -d $dst ]; then
+ instcmd=:
+ else
+ instcmd=mkdir
+ fi
+else
+
+# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
+# might cause directories to be created, which would be especially bad
+# if $src (and thus $dsttmp) contains '*'.
+
+ if [ -f $src -o -d $src ]
+ then
+ true
+ else
+ echo "install: $src does not exist"
+ exit 1
+ fi
+
+ if [ x"$dst" = x ]
+ then
+ echo "install: no destination specified"
+ exit 1
+ else
+ true
+ fi
+
+# If destination is a directory, append the input filename; if your system
+# does not like double slashes in filenames, you may need to add some logic
+
+ if [ -d $dst ]
+ then
+ dst="$dst"/`basename $src`
+ else
+ true
+ fi
+fi
+
+## this sed command emulates the dirname command
+dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
+
+# Make sure that the destination directory exists.
+# this part is taken from Noah Friedman's mkinstalldirs script
+
+# Skip lots of stat calls in the usual case.
+if [ ! -d "$dstdir" ]; then
+defaultIFS='
+'
+IFS="${IFS-${defaultIFS}}"
+
+oIFS="${IFS}"
+# Some sh's can't handle IFS=/ for some reason.
+IFS='%'
+set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
+IFS="${oIFS}"
+
+pathcomp=''
+
+while [ $# -ne 0 ] ; do
+ pathcomp="${pathcomp}${1}"
+ shift
+
+ if [ ! -d "${pathcomp}" ] ;
+ then
+ $mkdirprog "${pathcomp}"
+ else
+ true
+ fi
+
+ pathcomp="${pathcomp}/"
+done
+fi
+
+if [ x"$dir_arg" != x ]
+then
+ $doit $instcmd $dst &&
+
+ if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
+ if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
+ if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
+ if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
+else
+
+# If we're going to rename the final executable, determine the name now.
+
+ if [ x"$transformarg" = x ]
+ then
+ dstfile=`basename $dst`
+ else
+ dstfile=`basename $dst $transformbasename |
+ sed $transformarg`$transformbasename
+ fi
+
+# don't allow the sed command to completely eliminate the filename
+
+ if [ x"$dstfile" = x ]
+ then
+ dstfile=`basename $dst`
+ else
+ true
+ fi
+
+# Make a temp file name in the proper directory.
+
+ dsttmp=$dstdir/#inst.$$#
+
+# Move or copy the file name to the temp name
+
+ $doit $instcmd $src $dsttmp &&
+
+ trap "rm -f ${dsttmp}" 0 &&
+
+# and set any options; do chmod last to preserve setuid bits
+
+# If any of these fail, we abort the whole thing. If we want to
+# ignore errors from any of these, just make sure not to ignore
+# errors from the above "$doit $instcmd $src $dsttmp" command.
+
+ if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
+ if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
+ if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
+ if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
+
+# Now rename the file to the real destination.
+
+ $doit $rmcmd -f $dstdir/$dstfile &&
+ $doit $mvcmd $dsttmp $dstdir/$dstfile
+
+fi &&
+
+
+exit 0
diff --git a/isam/.cvsignore b/isam/.cvsignore
new file mode 100644
index 00000000000..dc55807a96b
--- /dev/null
+++ b/isam/.cvsignore
@@ -0,0 +1,10 @@
+.deps
+.libs
+Makefile
+Makefile.in
+isamchk
+isamlog
+pack_isam
+test1
+test2
+test3
diff --git a/isam/ChangeLog b/isam/ChangeLog
new file mode 100644
index 00000000000..4a9e3e03954
--- /dev/null
+++ b/isam/ChangeLog
@@ -0,0 +1,186 @@
+2000-04-26 Michael Widenius <monty@mysql.com>
+
+* Fixed bug when doing read_next after a delete/insert which balanced key
+ pages (In this case one internal buffer was wrongly reused)
+
+1999-11-23 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Changed prefix from ni_ to nisam_ to avoid problems on MacOS X.
+
+1999-08-17 Michael Widenius <monty@tik.pp.sci.fi>
+
+* Changed last parameter to mi_open() to be a bit flag instead of an int.
+
+1998-10-01 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Fixed bug in key packing when using some USE_STRCOLL character sets.
+
+Thu Aug 20 23:17:41 1998 Michael Widenius <monty@bitch.pp.sci.fi>
+
+* isamchk.c: Sometimes isamchk --sort-table caused isamchk to die.
+
+1998-06-28 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Fixed some possible race conditions when using with MySQL and
+ many reopen/close of the same tables under heavy load!
+* Changed isamchk to re-pack records when doing a repair to make it more safer.
+
+Thu Mar 12 21:44:08 1998 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Added a safty test to _ni_rec_unpack.
+
+Wed Nov 26 01:52:55 1997 <monty@monty.pp.sci.fi>
+
+* Fixed small problem when reading delete-marked records with rkey, rnext and
+ rprev. In normal applications this should never happen.
+
+Thu Nov 20 14:01:21 1997 <monty@monty.pp.sci.fi>
+
+* Fixed range key bug when using compressed key where the first part wasn't
+ compressed.
+* Converted everything to use prototypes.
+
+Mon Sep 29 13:16:27 1997 <monty@monty.pp.sci.fi>
+
+* Fixed problem with isamchk and compressed records files with record_reflength
+ < 4 (Gave wrong key when using isamchk -rq).
+
+Fri Sep 26 16:06:37 1997 <monty@monty.pp.sci.fi>
+
+* Fixed bug in range calculation.
+
+Thu Aug 14 14:44:33 1997 <monty@monty.pp.sci.fi>
+
+* Removed a couple of unnecessary seeks from 'delete static record'
+
+Tue Jul 1 22:04:16 1997 <monty@monty.pp.sci.fi>
+
+* Added checking of 'wrong packed records' when using 'isamchk -e' or
+ isamchk -ro.
+
+Fri Feb 7 22:22:28 1997 Michael Widenius <monty@bitch.sci.fi>
+
+* Fixed use of packed tables with threads (One static variable left)
+
+Thu Jan 23 09:05:22 1997 Michael Widenius <monty@bitch.sci.fi>
+
+* Changed create to detect keys > 127 and not pack them. Now one can
+ define keys with a length of up to (nisam_block_size-18)/2
+ by changeing N_MAX_KEY_LENGTH.
+
+Fri Jan 10 21:01:44 1997 Michael Widenius <monty@bitch.sci.fi>
+
+* added signed chars as key type.
+
+Fri Apr 26 14:31:05 1996 Michael Widenius <monty@bitch.clinet.fi (Michael Widenius)>
+
+* create.c: All keyfile blocks are now IO_SIZE big (for better keycashing).
+
+Tue Mar 12 22:42:52 1996 Michael Widenius <monty@bitch.clinet.fi (Michael Widenius)>
+
+* isamchk.c: Changed to print info if system table
+* write.c: Don't allow more than 1 record in system table.
+
+Fri Feb 2 16:40:32 1996 Michael Widenius <monty@bitch.clinet.fi (Michael Widenius)>
+
+* isamchk.c; Check that delete-link-chain is ok before trying to delete with 'q'.
+
+Thu Jan 11 13:21:23 1996 Michael Widenius <monty@bitch.clinet.fi (Michael Widenius)>
+
+* All same isam files now shares a structure to allow many opens off the same
+ file
+
+Sat Nov 25 12:33:53 1995 Michael Widenius <monty@bitch.clinet.fi (Michael Widenius)>
+
+* All functions now used my_errno instead of errno
+
+Mon Oct 23 12:32:02 1995 Michael Widenius <monty@bitch.clinet.fi (Michael Widenius)>
+
+* isamchk.c: Don't print that database should be fixed on automatic rep.
+
+Sun Aug 27 20:13:56 1995 Michael Widenius <monty@bitch.analytikerna.se (Michael Widenius)>
+
+* _dynrec.c added flush_io_cash() if someone did a read when using
+ WRITE CASHING.
+
+Thu Apr 20 01:41:24 1995 Michael Widenius (monty@bitch)
+
+* fixed errno when got error of 'key-not-found' when updateing or
+ deleting record.
+
+Tue Jan 17 19:37:48 1995 Michael Widenius (monty@bitch)
+
+* isamchk can now unpack databases.
+* prolinted all files.
+
+Fri May 27 15:01:06 1994 Michael Widenius (monty@bitch)
+
+* Don't lock packed databases.
+
+Sat Apr 16 22:41:23 1994 Michael Widenius (monty@bitch)
+
+* Added new function read_rsame_with_pos.
+
+Wed Mar 30 15:52:19 1994 Michael Widenius (monty@bitch)
+
+* Added creation and recover date to indexfile and isamchk.
+
+Sat Mar 26 15:03:37 1994 Michael Widenius (monty@bitch)
+
+* change is_panic() to close all files on ha_panic(write) on systems
+ (VMS) with can't open one file twice.
+
+Fri Feb 4 21:09:56 1994 Michael Widenius (monty@bitch)
+
+* READ_CASH on packed files now makes them mem-mapped if possibly
+
+Sat Sep 18 14:56:32 1993 Michael Widenius (monty at bitch)
+
+* changed _search to use pointer to buffer when reading keys.
+
+Mon Aug 16 19:45:29 1993 Michael Widenius (monty at bitch)
+
+* isamchk and packisam resolves symbolic links before file is used.
+ This forces temp-files on same disk as orginal file and rename
+ of temp-files dosen't destroy symbolic links.
+
+Mon May 31 18:26:08 1993 Michael Widenius (monty at bitch)
+
+* Added crc-check of records when packing for safe test if pack ok.
+
+Tue Mar 2 19:16:00 1993 Michael Widenius (monty@bitch)
+
+* Added logging of records with ni_log().
+
+Fri Jan 29 00:56:58 1993 Michael Widenius (monty@bitch)
+
+* Fixed bug in _read_rnd_static_record ; A lock was made for
+ each record even if it was in cash.
+
+Sun Nov 15 12:51:36 1992 Michael Widenius (monty@bitch)
+
+* last change breaked _dynrec, when not compileing with dbug.
+
+Fri Nov 6 03:46:38 1992 Michael Widenius (monty@bitch)
+
+* Fixed bugg when using packed records and reclength < 8 byte.
+
+Wed Oct 28 22:23:32 1992 Michael Widenius (monty@bitch)
+
+* Changed _cash.c to use io_cash to allow use of aioread.
+
+Fri Oct 23 00:45:53 1992 Michael Widenius (monty@bitch)
+
+* Added MY_WAIT_IF_FULL to pack_isam.
+
+Sat Oct 17 14:51:15 1992 Michael Widenius (monty@bitch)
+
+* Added use of subset of keys (isamchk -k#)
+
+Mon Oct 5 21:53:18 1992 Michael Widenius (monty@bitch)
+
+* Remove reloc of database ; Gives only problems with isamchk.
+
+Mon Aug 17 03:17:09 1992 Michael Widenius (monty@bitch)
+
+* Changed isam to use io_cash instead of rec_cash
diff --git a/isam/Makefile.am b/isam/Makefile.am
new file mode 100644
index 00000000000..2d80ba70bf7
--- /dev/null
+++ b/isam/Makefile.am
@@ -0,0 +1,51 @@
+# Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+INCLUDES = @MT_INCLUDES@ -I$(srcdir)/../include -I../include
+LDADD = @CLIENT_EXTRA_LDFLAGS@ libnisam.a ../mysys/libmysys.a \
+ ../dbug/libdbug.a ../strings/libmystrings.a
+pkglib_LIBRARIES = libnisam.a
+bin_PROGRAMS = isamchk isamlog pack_isam
+isamchk_DEPENDENCIES= $(LIBRARIES)
+isamlog_DEPENDENCIES= $(LIBRARIES)
+pack_isam_DEPENDENCIES= $(LIBRARIES)
+noinst_PROGRAMS = test1 test2 test3
+noinst_HEADERS = isamdef.h
+test1_DEPENDENCIES= $(LIBRARIES)
+test2_DEPENDENCIES= $(LIBRARIES)
+test3_DEPENDENCIES= $(LIBRARIES)
+libnisam_a_SOURCES = open.c extra.c info.c rkey.c rnext.c \
+ _search.c _page.c _key.c _locking.c \
+ rrnd.c _cache.c _statrec.c _packrec.c \
+ _dynrec.c update.c write.c delete.c \
+ rprev.c rfirst.c rlast.c rsame.c rsamepos.c \
+ panic.c close.c create.c range.c _dbug.c \
+ log.c changed.c static.c
+isamchk_SOURCES = isamchk.c sort.c
+CLEANFILES = test?.IS? isam.log
+# Omit dependency for ../mit-pthreads/include/ things
+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 wait.h
+
+# Move to automake rules ?
+prolint:; plparse -b -u -hF1 "-width(0,0)" "-format=%f:%l:\s%t:%n\s%m" \
+ "-elib(????)" "+elib(?3??)" my.lnt $(nisam_SOURCES)
diff --git a/isam/_cache.c b/isam/_cache.c
new file mode 100644
index 00000000000..53619126660
--- /dev/null
+++ b/isam/_cache.c
@@ -0,0 +1,92 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* Functions for read record cacheing with nisam */
+/* Used instead of my_b_read() to allow for no-cacheed seeks */
+
+#include "isamdef.h"
+
+#define READING_NEXT 1
+#define READING_HEADER 2
+
+ /* Copy block from cache if it`s in it. If re_read_if_possibly is */
+ /* set read to cache (if after current file-position) else read to */
+ /* buff */
+
+int _nisam_read_cache(IO_CACHE *info, byte *buff, ulong pos, uint length,
+ int flag)
+{
+ uint read_length,in_buff_length;
+ ulong offset;
+ char *in_buff_pos;
+
+ if (pos < info->pos_in_file)
+ {
+ read_length= (uint) min((ulong) length,(ulong) (info->pos_in_file-pos));
+ info->seek_not_done=1;
+ VOID(my_seek(info->file,pos,MY_SEEK_SET,MYF(0)));
+ if (my_read(info->file,buff,read_length,MYF(MY_NABP)))
+ return 1;
+ if (!(length-=read_length))
+ return 0;
+ pos+=read_length;
+ buff+=read_length;
+ }
+ if ((offset=pos - (ulong) info->pos_in_file) <
+ (ulong) (info->rc_end - info->rc_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);
+ if (!(length-=in_buff_length))
+ return 0;
+ pos+=in_buff_length;
+ buff+=in_buff_length;
+ }
+ else
+ in_buff_length=0;
+ if (flag & READING_NEXT)
+ {
+ if (pos != ((info)->pos_in_file +
+ (uint) ((info)->rc_end - (info)->rc_request_pos)))
+ {
+ info->pos_in_file=pos; /* Force start here */
+ info->rc_pos=info->rc_end=info->rc_request_pos; /* Everything used */
+ info->seek_not_done=1;
+ }
+ else
+ info->rc_pos=info->rc_end; /* All block used */
+ if (!(*info->read_function)(info,buff,length))
+ return 0;
+ if (!(flag & READING_HEADER) || info->error == -1 ||
+ (uint) info->error+in_buff_length < 3)
+ return 1;
+ if (BLOCK_INFO_HEADER_LENGTH < in_buff_length + (uint) info->error)
+ bzero(buff+info->error,BLOCK_INFO_HEADER_LENGTH - in_buff_length -
+ (uint) info->error);
+ return 0;
+ }
+ info->seek_not_done=1;
+ VOID(my_seek(info->file,pos,MY_SEEK_SET,MYF(0)));
+ if ((read_length=my_read(info->file,buff,length,MYF(0))) == length)
+ return 0;
+ if (!(flag & READING_HEADER) || (int) read_length == -1 ||
+ read_length+in_buff_length < 3)
+ return 1;
+ bzero(buff+read_length,BLOCK_INFO_HEADER_LENGTH - in_buff_length -
+ read_length);
+ return 0;
+} /* _nisam_read_cache */
diff --git a/isam/_dbug.c b/isam/_dbug.c
new file mode 100644
index 00000000000..644d0e420d6
--- /dev/null
+++ b/isam/_dbug.c
@@ -0,0 +1,132 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* Support rutiner with are using with dbug */
+
+#include "isamdef.h"
+
+ /* Print a key in user understandable format */
+
+void _nisam_print_key(FILE *stream, register N_KEYSEG *keyseg, const uchar *key)
+{
+ int flag;
+ short int s_1;
+ long int l_1;
+ float f_1;
+ double d_1;
+ uchar *end;
+
+ VOID(fputs("Key: \"",stream));
+ flag=0;
+ for (; keyseg->base.type ;keyseg++)
+ {
+ if (flag++)
+ VOID(putc('-',stream));
+ end= (uchar*) key+ keyseg->base.length;
+ switch (keyseg->base.type) {
+ case HA_KEYTYPE_BINARY:
+ if (!(keyseg->base.flag & HA_SPACE_PACK) && keyseg->base.length == 1)
+ { /* packed binary digit */
+ VOID(fprintf(stream,"%d",(uint) *key++));
+ break;
+ }
+ /* fall through */
+ case HA_KEYTYPE_TEXT:
+ case HA_KEYTYPE_NUM:
+ if (keyseg->base.flag & HA_SPACE_PACK)
+ {
+ VOID(fprintf(stream,"%.*s",(int) *key,key+1));
+ key+= (int) *key+1;
+ }
+ else
+ {
+ VOID(fprintf(stream,"%.*s",(int) keyseg->base.length,key));
+ key=end;
+ }
+ break;
+ case HA_KEYTYPE_INT8:
+ VOID(fprintf(stream,"%d",(int) *((signed char*) key)));
+ key=end;
+ break;
+ case HA_KEYTYPE_SHORT_INT:
+ shortget(s_1,key);
+ VOID(fprintf(stream,"%d",(int) s_1));
+ key=end;
+ break;
+ case HA_KEYTYPE_USHORT_INT:
+ {
+ ushort u_1;
+ ushortget(u_1,key);
+ VOID(fprintf(stream,"%u",(uint) u_1));
+ key=end;
+ break;
+ }
+ case HA_KEYTYPE_LONG_INT:
+ longget(l_1,key);
+ VOID(fprintf(stream,"%ld",l_1));
+ key=end;
+ break;
+ case HA_KEYTYPE_ULONG_INT:
+ longget(l_1,key);
+ VOID(fprintf(stream,"%lu",(ulong) l_1));
+ key=end;
+ break;
+ case HA_KEYTYPE_INT24:
+ VOID(fprintf(stream,"%d",sint3korr(key)));
+ key=end;
+ break;
+ case HA_KEYTYPE_UINT24:
+ VOID(fprintf(stream,"%ld",uint3korr(key)));
+ key=end;
+ break;
+ case HA_KEYTYPE_FLOAT:
+ bmove((byte*) &f_1,(byte*) key,(int) sizeof(float));
+ VOID(fprintf(stream,"%g",(double) f_1));
+ key=end;
+ break;
+ case HA_KEYTYPE_DOUBLE:
+ doubleget(d_1,key);
+ VOID(fprintf(stream,"%g",d_1));
+ key=end;
+ break;
+#ifdef HAVE_LONG_LONG
+ case HA_KEYTYPE_LONGLONG:
+ {
+ char buff[21];
+ longlong tmp;
+ longlongget(tmp,key);
+ longlong2str(tmp,buff,-10);
+ VOID(fprintf(stream,"%s",buff));
+ key=end;
+ break;
+ }
+ case HA_KEYTYPE_ULONGLONG:
+ {
+ char buff[21];
+ longlong tmp;
+ longlongget(tmp,key);
+ longlong2str(tmp,buff,10);
+ VOID(fprintf(stream,"%s",buff));
+ key=end;
+ break;
+ }
+#endif
+ default: break; /* This never happens */
+ }
+ }
+ VOID(fputs("\n",stream));
+ return;
+} /* print_key */
diff --git a/isam/_dynrec.c b/isam/_dynrec.c
new file mode 100644
index 00000000000..6d4a491304c
--- /dev/null
+++ b/isam/_dynrec.c
@@ -0,0 +1,1245 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+ /* Functions to handle space-packed-records and blobs */
+
+#include "isamdef.h"
+
+/* Enough for comparing if number is zero */
+static char zero_string[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
+
+static int write_dynamic_record(N_INFO *info,const byte *record,
+ uint reclength);
+static int _nisam_find_writepos(N_INFO *info,uint reclength,ulong *filepos,
+ uint *length);
+static int update_dynamic_record(N_INFO *info,ulong filepos,byte *record,
+ uint reclength);
+static int delete_dynamic_record(N_INFO *info,ulong filepos,
+ uint second_read);
+static int _nisam_cmp_buffer(File file, const byte *buff, ulong filepos,
+ uint length);
+
+#ifdef THREAD
+/* Play it safe; We have a small stack when using threads */
+#undef my_alloca
+#undef my_afree
+#define my_alloca(A) my_malloc((A),MYF(0))
+#define my_afree(A) my_free((A),MYF(0))
+#endif
+
+ /* Interface function from N_INFO */
+
+int _nisam_write_dynamic_record(N_INFO *info, const byte *record)
+{
+ uint reclength=_nisam_rec_pack(info,info->rec_buff,record);
+ return (write_dynamic_record(info,info->rec_buff,reclength));
+}
+
+int _nisam_update_dynamic_record(N_INFO *info, ulong pos, const byte *record)
+{
+ uint length=_nisam_rec_pack(info,info->rec_buff,record);
+ return (update_dynamic_record(info,pos,info->rec_buff,length));
+}
+
+int _nisam_write_blob_record(N_INFO *info, const byte *record)
+{
+ byte *rec_buff;
+ int error;
+ uint reclength,extra;
+
+ extra=ALIGN_SIZE(MAX_DYN_BLOCK_HEADER)+N_SPLITT_LENGTH+
+ DYN_DELETE_BLOCK_HEADER;
+ if (!(rec_buff=(byte*) my_alloca(info->s->base.pack_reclength+
+ _calc_total_blob_length(info,record)+
+ extra)))
+ return(-1);
+ reclength=_nisam_rec_pack(info,rec_buff+ALIGN_SIZE(MAX_DYN_BLOCK_HEADER),
+ record);
+ error=write_dynamic_record(info,rec_buff+ALIGN_SIZE(MAX_DYN_BLOCK_HEADER),
+ reclength);
+ my_afree(rec_buff);
+ return(error);
+}
+
+
+int _nisam_update_blob_record(N_INFO *info, ulong pos, const byte *record)
+{
+ byte *rec_buff;
+ int error;
+ uint reclength,extra;
+
+ extra=ALIGN_SIZE(MAX_DYN_BLOCK_HEADER)+N_SPLITT_LENGTH+
+ DYN_DELETE_BLOCK_HEADER;
+ if (!(rec_buff=(byte*) my_alloca(info->s->base.pack_reclength+
+ _calc_total_blob_length(info,record)+
+ extra)))
+ return(-1);
+ reclength=_nisam_rec_pack(info,rec_buff+ALIGN_SIZE(MAX_DYN_BLOCK_HEADER),
+ record);
+ error=update_dynamic_record(info,pos,
+ rec_buff+ALIGN_SIZE(MAX_DYN_BLOCK_HEADER),
+ reclength);
+ my_afree(rec_buff);
+ return(error);
+}
+
+int _nisam_delete_dynamic_record(N_INFO *info)
+{
+ return delete_dynamic_record(info,info->lastpos,0);
+}
+
+
+ /* Write record to data-file */
+
+static int write_dynamic_record(N_INFO *info, const byte *record, uint reclength)
+{
+ int flag;
+ uint length;
+ ulong filepos;
+ DBUG_ENTER("write_dynamic_record");
+
+ flag=0;
+ while (reclength)
+ {
+ if (_nisam_find_writepos(info,reclength,&filepos,&length))
+ goto err;
+ if (_nisam_write_part_record(info,filepos,length,info->s->state.dellink,
+ (byte**) &record,&reclength,&flag))
+ goto err;
+ }
+
+ DBUG_RETURN(0);
+ err:
+ DBUG_RETURN(1);
+}
+
+
+ /* Get a block for data ; The given data-area must be used !! */
+
+static int _nisam_find_writepos(N_INFO *info,
+ uint reclength, /* record length */
+ ulong *filepos, /* Return file pos */
+ uint *length) /* length of block at filepos */
+{
+ BLOCK_INFO block_info;
+ DBUG_ENTER("_nisam_find_writepos");
+
+ if (info->s->state.dellink != NI_POS_ERROR)
+ {
+ *filepos=info->s->state.dellink;
+ block_info.second_read=0;
+ info->rec_cache.seek_not_done=1;
+ if (!(_nisam_get_block_info(&block_info,info->dfile,info->s->state.dellink) &
+ BLOCK_DELETED))
+ {
+ my_errno=HA_ERR_WRONG_IN_RECORD;
+ DBUG_RETURN(-1);
+ }
+ info->s->state.dellink=block_info.next_filepos;
+ info->s->state.del--;
+ info->s->state.empty-= block_info.block_len;
+ *length= block_info.block_len;
+ }
+ else
+ {
+ if (info->s->state.data_file_length > info->s->base.max_data_file_length)
+ {
+ my_errno=HA_ERR_RECORD_FILE_FULL;
+ DBUG_RETURN(-1);
+ }
+ *filepos=info->s->state.data_file_length; /* New block last */
+ if ((*length=reclength+3 + test(reclength > 65532)) <
+ info->s->base.min_block_length)
+ *length=info->s->base.min_block_length;
+ info->s->state.data_file_length+= *length;
+ info->s->state.splitt++;
+ info->update|=HA_STATE_WRITE_AT_END;
+ }
+ DBUG_RETURN(0);
+} /* _nisam_find_writepos */
+
+
+ /* Write a block to datafile */
+
+int _nisam_write_part_record(N_INFO *info,
+ ulong filepos, /* points at empty block */
+ uint length, /* length of block */
+ ulong next_filepos, /* Next empty block */
+ byte **record, /* pointer to record ptr */
+ uint *reclength, /* length of *record */
+ int *flag) /* *flag == 0 if header */
+{
+ uint head_length,res_length,extra_length,long_block,del_length;
+ byte *pos,*record_end;
+ uchar temp[N_SPLITT_LENGTH+DYN_DELETE_BLOCK_HEADER];
+ DBUG_ENTER("_nisam_write_part_record");
+
+ res_length=extra_length=0;
+ if (length > *reclength + N_SPLITT_LENGTH)
+ { /* Splitt big block */
+ res_length=length- *reclength - 3 - N_EXTEND_BLOCK_LENGTH;
+ length-= res_length; /* Use this for first part */
+ }
+ long_block= (length < 65535L && *reclength < 65535L) ? 0 : 1;
+ if (length-long_block == *reclength+3 || length == *reclength + 4)
+ { /* Exact what we need */
+ temp[0]=(uchar) (1+ *flag); /* 1, or 9 */
+ if (long_block)
+ {
+ int3store(temp+1,*reclength);
+ }
+ else
+ {
+ int2store(temp+1,*reclength);
+ }
+ head_length=3+long_block;
+ if (length-long_block == *reclength+4)
+ {
+ length--;
+ temp[0]++; /* 2 or 10 */
+ extra_length++; /* One empty */
+ }
+ }
+ else if (length-long_block < *reclength+5)
+ { /* To short block */
+ if (next_filepos == NI_POS_ERROR)
+ next_filepos=info->s->state.dellink != NI_POS_ERROR ?
+ info->s->state.dellink : info->s->state.data_file_length;
+ if (*flag == 0) /* First block */
+ {
+ head_length=5+4+long_block*2;
+ temp[0]=4;
+ if (long_block)
+ {
+ int3store(temp+1,*reclength);
+ int3store(temp+4,length-head_length);
+ int4store((byte*) temp+7,next_filepos);
+ }
+ else
+ {
+ int2store(temp+1,*reclength);
+ int2store(temp+3,length-head_length);
+ int4store((byte*) temp+5,next_filepos);
+ }
+ }
+ else
+ {
+ head_length=3+4+long_block;
+ temp[0]=12;
+ if (long_block)
+ {
+ int3store(temp+1,length-head_length);
+ int4store((byte*) temp+4,next_filepos);
+ }
+ else
+ {
+ int2store(temp+1,length-head_length);
+ int4store((byte*) temp+3,next_filepos);
+ }
+ }
+ }
+ else
+ { /* Block with empty info last */
+ head_length=5+long_block*2;
+ temp[0]= (uchar) (3+ *flag); /* 3 or 11 */
+ if (long_block)
+ {
+ int3store(temp+1,*reclength);
+ int3store(temp+4,length-7);
+ }
+ else
+ {
+ int2store(temp+1,*reclength);
+ int2store(temp+3,length-5);
+ }
+ extra_length= length- *reclength-head_length;
+ length= *reclength+head_length; /* Write only what is needed */
+ }
+ temp[0]+=(uchar) (long_block*4);
+ DBUG_DUMP("header",(byte*) temp,head_length);
+
+ /* Make a long block for one write */
+ record_end= *record+length-head_length;
+ del_length=(res_length ? DYN_DELETE_BLOCK_HEADER : 0);
+ bmove((byte*) (*record-head_length),(byte*) temp,head_length);
+ memcpy(temp,record_end,(size_t) (extra_length+del_length));
+ bzero((byte*) record_end,extra_length);
+ if (res_length)
+ {
+ pos=record_end+extra_length;
+ pos[0]= '\0';
+ int3store(pos+1,res_length);
+ int4store(pos+4,info->s->state.dellink);
+ info->s->state.dellink= filepos+length+extra_length;
+ info->s->state.del++;
+ info->s->state.empty+=res_length;
+ info->s->state.splitt++;
+ }
+ if (info->opt_flag & WRITE_CACHE_USED && info->update & HA_STATE_WRITE_AT_END)
+ {
+ if (my_b_write(&info->rec_cache,(byte*) *record-head_length,
+ length+extra_length+del_length))
+ goto err;
+ }
+ else
+ {
+ info->rec_cache.seek_not_done=1;
+ if (my_pwrite(info->dfile,(byte*) *record-head_length,length+extra_length+
+ del_length,filepos,MYF(MY_NABP | MY_WAIT_IF_FULL)))
+ goto err;
+ }
+ memcpy(record_end,temp,(size_t) (extra_length+del_length));
+ *record=record_end;
+ *reclength-=(length-head_length);
+ *flag=8;
+
+ DBUG_RETURN(0);
+err:
+ DBUG_PRINT("exit",("errno: %d",my_errno));
+ DBUG_RETURN(1);
+} /*_nisam_write_part_record */
+
+
+ /* update record from datafile */
+
+static int update_dynamic_record(N_INFO *info, ulong filepos, byte *record, uint reclength)
+{
+ int flag;
+ uint error,length;
+ BLOCK_INFO block_info;
+ DBUG_ENTER("update_dynamic_record");
+
+ flag=block_info.second_read=0;
+ while (reclength > 0)
+ {
+ if (filepos != info->s->state.dellink)
+ {
+ block_info.next_filepos= NI_POS_ERROR;
+ if ((error=_nisam_get_block_info(&block_info,info->dfile,filepos))
+ & (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR |
+ BLOCK_FATAL_ERROR))
+ {
+ if (!(error & BLOCK_FATAL_ERROR))
+ my_errno=HA_ERR_WRONG_IN_RECORD;
+ goto err;
+ }
+ length=(uint) (block_info.filepos-filepos) + block_info.block_len;
+ }
+ else
+ {
+ if (_nisam_find_writepos(info,reclength,&filepos,&length))
+ goto err;
+ }
+ if (_nisam_write_part_record(info,filepos,length,block_info.next_filepos,
+ &record,&reclength,&flag))
+ goto err;
+ if ((filepos=block_info.next_filepos) == NI_POS_ERROR)
+ filepos=info->s->state.dellink;
+ }
+
+ if (block_info.next_filepos != NI_POS_ERROR)
+ if (delete_dynamic_record(info,block_info.next_filepos,1))
+ goto err;
+ DBUG_RETURN(0);
+err:
+ DBUG_RETURN(1);
+}
+
+ /* Delete datarecord from database */
+ /* info->rec_cache.seek_not_done is updated in cmp_record */
+
+static int delete_dynamic_record(N_INFO *info, ulong filepos, uint second_read)
+{
+ uint length,b_type;
+ BLOCK_INFO block_info;
+ DBUG_ENTER("delete_dynamic_record");
+
+ block_info.second_read=second_read;
+ do
+ {
+ if ((b_type=_nisam_get_block_info(&block_info,info->dfile,filepos))
+ & (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR |
+ BLOCK_FATAL_ERROR) ||
+ (length=(uint) (block_info.filepos-filepos) +block_info.block_len) <
+ N_MIN_BLOCK_LENGTH)
+ {
+ my_errno=HA_ERR_WRONG_IN_RECORD;
+ DBUG_RETURN(1);
+ }
+ block_info.header[0]=0;
+ length=(uint) (block_info.filepos-filepos) +block_info.block_len;
+ int3store(block_info.header+1,length);
+ int4store(block_info.header+4,info->s->state.dellink);
+ if (my_pwrite(info->dfile,(byte*) block_info.header,8,filepos,
+ MYF(MY_NABP)))
+ DBUG_RETURN(1);
+ info->s->state.dellink = filepos;
+ info->s->state.del++;
+ info->s->state.empty+=length;
+ filepos=block_info.next_filepos;
+ } while (!(b_type & BLOCK_LAST));
+ DBUG_RETURN(0);
+}
+
+
+ /* Pack a record. Return new reclength */
+
+uint _nisam_rec_pack(N_INFO *info, register byte *to, register const byte *from)
+{
+ uint length,new_length,flag,bit,i;
+ char *pos,*end,*startpos,*packpos;
+ enum en_fieldtype type;
+ reg3 N_RECINFO *rec;
+ N_BLOB *blob;
+ DBUG_ENTER("_nisam_rec_pack");
+
+ flag=0 ; bit=1;
+ startpos=packpos=to; to+= info->s->base.pack_bits; blob=info->blobs;
+ rec=info->s->rec;
+
+ for (i=info->s->base.fields ; i-- > 0; from+= (rec++)->base.length)
+ {
+ length=(uint) rec->base.length;
+ if ((type = (enum en_fieldtype) rec->base.type) != FIELD_NORMAL)
+ {
+ if (type == FIELD_BLOB)
+ {
+ if (!blob->length)
+ flag|=bit;
+ else
+ {
+ char *temp_pos;
+ memcpy((byte*) to,from,(size_t) length);
+ memcpy_fixed(&temp_pos,from+length,sizeof(char*));
+ memcpy(to+length,temp_pos,(size_t) blob->length);
+ to+=length+blob->length;
+ }
+ blob++;
+ from+=sizeof(char*); /* Skipp blob-pointer */
+ }
+ else if (type == FIELD_SKIPP_ZERO)
+ {
+ if (memcmp((byte*) from,zero_string,length) == 0)
+ flag|=bit;
+ else
+ {
+ memcpy((byte*) to,from,(size_t) length); to+=length;
+ }
+ }
+ else if (type == FIELD_SKIPP_ENDSPACE ||
+ type == FIELD_SKIPP_PRESPACE)
+ {
+ pos= (byte*) from; end= (byte*) from + length;
+ if (type == FIELD_SKIPP_ENDSPACE)
+ { /* Pack trailing spaces */
+ while (end > from && *(end-1) == ' ')
+ end--;
+ }
+ else
+ { /* Pack pref-spaces */
+ while (pos < end && *pos == ' ')
+ pos++;
+ }
+ new_length=(uint) (end-pos);
+ if (new_length +1 + test(rec->base.length > 255 && new_length > 127)
+ < length)
+ {
+ if (rec->base.length > 255 && new_length > 127)
+ {
+ to[0]=(char) ((new_length & 127)+128);
+ to[1]=(char) (new_length >> 7);
+ to+=2;
+ }
+ else
+ *to++= (char) new_length;
+ memcpy((byte*) to,pos,(size_t) new_length); to+=new_length;
+ flag|=bit;
+ }
+ else
+ {
+ memcpy(to,from,(size_t) length); to+=length;
+ }
+ }
+ else if (type == FIELD_ZERO)
+ continue; /* Don't store this */
+ else
+ {
+ memcpy(to,from,(size_t) length); to+=length;
+ continue; /* Normal field */
+ }
+ if ((bit= bit << 1) >= 256)
+ {
+ *packpos++ = (char) (uchar) flag;
+ bit=1; flag=0;
+ }
+ }
+ else
+ {
+ memcpy(to,from,(size_t) length); to+=length;
+ }
+ }
+ if (bit != 1)
+ *packpos= (char) (uchar) flag;
+ DBUG_PRINT("exit",("packed length: %d",(int) (to-startpos)));
+ DBUG_RETURN((uint) (to-startpos));
+} /* _nisam_rec_pack */
+
+
+
+/*
+** Check if a record was correctly packed. Used only by isamchk
+** Returns 0 if record is ok.
+*/
+
+my_bool _nisam_rec_check(N_INFO *info,const char *from)
+{
+ uint length,new_length,flag,bit,i;
+ char *pos,*end,*packpos,*to;
+ enum en_fieldtype type;
+ reg3 N_RECINFO *rec;
+ DBUG_ENTER("_nisam_rec_check");
+
+ packpos=info->rec_buff; to= info->rec_buff+info->s->base.pack_bits;
+ rec=info->s->rec;
+ flag= *packpos; bit=1;
+
+ for (i=info->s->base.fields ; i-- > 0; from+= (rec++)->base.length)
+ {
+ length=(uint) rec->base.length;
+ if ((type = (enum en_fieldtype) rec->base.type) != FIELD_NORMAL)
+ {
+ if (type == FIELD_BLOB)
+ {
+ uint blob_length= _calc_blob_length(length,from);
+ if (!blob_length && !(flag & bit))
+ goto err;
+ if (blob_length)
+ to+=length+ blob_length;
+ from+=sizeof(char*);
+ }
+ else if (type == FIELD_SKIPP_ZERO)
+ {
+ if (memcmp((byte*) from,zero_string,length) == 0)
+ {
+ if (!(flag & bit))
+ goto err;
+ }
+ else
+ to+=length;
+ }
+ else if (type == FIELD_SKIPP_ENDSPACE ||
+ type == FIELD_SKIPP_PRESPACE)
+ {
+ pos= (byte*) from; end= (byte*) from + length;
+ if (type == FIELD_SKIPP_ENDSPACE)
+ { /* Pack trailing spaces */
+ while (end > from && *(end-1) == ' ')
+ end--;
+ }
+ else
+ { /* Pack pre-spaces */
+ while (pos < end && *pos == ' ')
+ pos++;
+ }
+ new_length=(uint) (end-pos);
+ if (new_length +1 + test(rec->base.length > 255 && new_length > 127)
+ < length)
+ {
+ if (!(flag & bit))
+ goto err;
+ if (rec->base.length > 255 && new_length > 127)
+ {
+ if (to[0] != (char) ((new_length & 127)+128) ||
+ to[1] != (char) (new_length >> 7))
+ goto err;
+ to+=2;
+ }
+ else if (*to++ != (char) new_length)
+ goto err;
+ to+=new_length;
+ }
+ else
+ to+=length;
+ }
+ else
+ {
+ if (type != FIELD_ZERO)
+ to+=length; /* Not packed field */
+ continue;
+ }
+ if ((bit= bit << 1) >= 256)
+ {
+ flag= *++packpos;
+ bit=1;
+ }
+ }
+ else
+ {
+ to+=length;
+ }
+ }
+ if (bit != 1)
+ *packpos= (char) (uchar) flag;
+ if (info->packed_length == (uint) (to - info->rec_buff) &&
+ (bit == 1 || !(flag & ~(bit - 1))))
+ DBUG_RETURN(0);
+
+ err:
+ DBUG_RETURN(1);
+}
+
+
+
+ /* Unpacks a record */
+ /* Returns -1 and my_errno =HA_ERR_RECORD_DELETED if reclength isn't */
+ /* right. Returns reclength (>0) if ok */
+
+uint _nisam_rec_unpack(register N_INFO *info, register byte *to, byte *from,
+ uint found_length)
+{
+ uint flag,bit,length,rec_length,min_pack_length;
+ enum en_fieldtype type;
+ byte *from_end,*to_end,*packpos;
+ reg3 N_RECINFO *rec,*end_field;
+ DBUG_ENTER("_nisam_rec_unpack");
+
+ to_end=to + info->s->base.reclength;
+ from_end=from+found_length;
+ flag= (uchar) *from; bit=1; packpos=from;
+ if (found_length < info->s->base.min_pack_length)
+ goto err;
+ from+= info->s->base.pack_bits;
+ min_pack_length=info->s->base.min_pack_length - info->s->base.pack_bits;
+
+ for (rec=info->s->rec , end_field=rec+info->s->base.fields ;
+ rec < end_field ; to+= rec_length, rec++)
+ {
+ rec_length=rec->base.length;
+ if ((type = (enum en_fieldtype) rec->base.type) != FIELD_NORMAL)
+ {
+ if (type == FIELD_ZERO)
+ continue; /* Skipp this */
+ if (flag & bit)
+ {
+ if (type == FIELD_BLOB)
+ {
+ bzero((byte*) to,rec_length+sizeof(char*));
+ to+=sizeof(char*);
+ }
+ else if (type == FIELD_SKIPP_ZERO)
+ bzero((byte*) to,rec_length);
+ else if (type == FIELD_SKIPP_ENDSPACE ||
+ type == FIELD_SKIPP_PRESPACE)
+ {
+ if (rec->base.length > 255 && *from & 128)
+ {
+ if (from + 1 >= from_end)
+ goto err;
+ length= (*from & 127)+ ((uint) (uchar) *(from+1) << 7); from+=2;
+ }
+ else
+ {
+ if (from == from_end)
+ goto err;
+ length= (uchar) *from++;
+ }
+ min_pack_length--;
+ if (length >= rec_length ||
+ min_pack_length + length > (uint) (from_end - from))
+ goto err;
+ if (type == FIELD_SKIPP_ENDSPACE)
+ {
+ memcpy(to,(byte*) from,(size_t) length);
+ bfill((byte*) to+length,rec_length-length,' ');
+ }
+ else
+ {
+ bfill((byte*) to,rec_length-length,' ');
+ memcpy(to+rec_length-length,(byte*) from,(size_t) length);
+ }
+ from+=length;
+ }
+ }
+ else if (type == FIELD_BLOB)
+ {
+ ulong blob_length=_calc_blob_length(rec_length,from);
+ if ((ulong) (from_end-from) - rec_length < blob_length ||
+ min_pack_length > (uint) (from_end -(from+rec_length+blob_length)))
+ goto err;
+ memcpy((byte*) to,(byte*) from,(size_t) rec_length);
+ from+=rec_length;
+ /* memcpy crasches alpha egcs 1.1.2 */
+ bmove((byte*) to+rec_length,(byte*) &from,sizeof(char*));
+ from+=blob_length;
+ to+=sizeof(char*);
+ }
+ else
+ {
+ if (type == FIELD_SKIPP_ENDSPACE || type == FIELD_SKIPP_PRESPACE)
+ min_pack_length--;
+ if (min_pack_length + rec_length > (uint) (from_end - from))
+ goto err;
+ memcpy(to,(byte*) from,(size_t) rec_length); from+=rec_length;
+ }
+ if ((bit= bit << 1) >= 256)
+ {
+ flag= (uchar) *++packpos; bit=1;
+ }
+ }
+ else
+ {
+ if (min_pack_length > (uint) (from_end - from))
+ goto err;
+ min_pack_length-=rec_length;
+ memcpy(to,(byte*) from,(size_t) rec_length); from+=rec_length;
+ }
+ }
+ if (to == to_end && from == from_end && (bit == 1 || !(flag & ~(bit-1))))
+ DBUG_RETURN((info->packed_length=found_length));
+ err:
+ my_errno=HA_ERR_RECORD_DELETED;
+ DBUG_PRINT("error",("to_end: %lx -> %lx from_end: %lx -> %lx",
+ to,to_end,from,from_end));
+ DBUG_DUMP("from",(byte*) info->rec_buff,info->s->base.min_pack_length);
+ DBUG_RETURN(MY_FILE_ERROR);
+} /* _nisam_rec_unpack */
+
+
+ /* Calc length of blob. Update info in blobs->length */
+
+uint _calc_total_blob_length(N_INFO *info, const byte *record)
+{
+ uint i,length;
+ N_BLOB *blob;
+
+ for (i=length=0, blob= info->blobs; i++ < info->s->base.blobs ; blob++)
+ {
+ blob->length=_calc_blob_length(blob->pack_length,record + blob->offset);
+ length+=blob->length;
+ }
+ return length;
+}
+
+
+uint _calc_blob_length(uint length, const byte *pos)
+{
+ switch (length) {
+ case 1:
+ return (uint) (uchar) *pos;
+ case 2:
+ {
+ short j; shortget(j,pos);
+ return (uint) (unsigned short) j;
+ }
+#ifdef MSDOS
+ break; /* skipp microsoft warning */
+#endif
+ case 3:
+ return uint3korr(pos);
+ case 4:
+ {
+ long j; longget(j,pos);
+ return (uint) j;
+ }
+#ifdef MSDOS
+ break;
+#endif
+ default:
+ break;
+ }
+ return 0; /* Impossible */
+}
+
+ /* Read record from datafile */
+ /* Returns 0 if ok, -1 if error */
+
+int _nisam_read_dynamic_record(N_INFO *info, ulong filepos, byte *buf)
+{
+ int flag;
+ uint b_type,left_length;
+ byte *to;
+ BLOCK_INFO block_info;
+ File file;
+ DBUG_ENTER("ni_read_dynamic_record");
+
+ if (filepos != NI_POS_ERROR)
+ {
+ LINT_INIT(to);
+ LINT_INIT(left_length);
+ file=info->dfile;
+ block_info.next_filepos=filepos; /* for easyer loop */
+ flag=block_info.second_read=0;
+ do
+ {
+ if (info->opt_flag & WRITE_CACHE_USED &&
+ info->rec_cache.pos_in_file <= block_info.next_filepos &&
+ flush_io_cache(&info->rec_cache))
+ goto err;
+ info->rec_cache.seek_not_done=1;
+ if ((b_type=_nisam_get_block_info(&block_info,file,
+ block_info.next_filepos))
+ & (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR |
+ BLOCK_FATAL_ERROR))
+ {
+ if (b_type & (BLOCK_SYNC_ERROR | BLOCK_DELETED))
+ my_errno=HA_ERR_RECORD_DELETED;
+ goto err;
+ }
+ if (flag == 0) /* First block */
+ {
+ flag=1;
+ if (block_info.rec_len > (uint) info->s->base.max_pack_length)
+ goto panic;
+ if (info->s->base.blobs)
+ {
+ if (!(to=fix_rec_buff_for_blob(info,block_info.rec_len)))
+ goto err;
+ }
+ else
+ to= info->rec_buff;
+ left_length=block_info.rec_len;
+ }
+ if (left_length < block_info.data_len || ! block_info.data_len)
+ goto panic; /* Wrong linked record */
+ if (my_pread(file,(byte*) to,block_info.data_len,block_info.filepos,
+ MYF(MY_NABP)))
+ goto panic;
+ left_length-=block_info.data_len;
+ to+=block_info.data_len;
+ } while (left_length);
+
+ info->update|= HA_STATE_AKTIV; /* We have a aktive record */
+ VOID(_nisam_writeinfo(info,0));
+ DBUG_RETURN(_nisam_rec_unpack(info,buf,info->rec_buff,block_info.rec_len) !=
+ MY_FILE_ERROR ? 0 : -1);
+ }
+ VOID(_nisam_writeinfo(info,0));
+ DBUG_RETURN(-1); /* Wrong data to read */
+
+panic:
+ my_errno=HA_ERR_WRONG_IN_RECORD;
+err:
+ VOID(_nisam_writeinfo(info,0));
+ DBUG_RETURN(-1);
+}
+
+
+byte *fix_rec_buff_for_blob(N_INFO *info, uint length)
+{
+ uint extra;
+ if (! info->rec_buff || length > info->alloced_rec_buff_length)
+ {
+ byte *newptr;
+ extra=ALIGN_SIZE(MAX_DYN_BLOCK_HEADER)+N_SPLITT_LENGTH+
+ DYN_DELETE_BLOCK_HEADER;
+ if (!(newptr=(byte*) my_realloc((gptr) info->rec_alloc,length+extra,
+ MYF(MY_ALLOW_ZERO_PTR))))
+ return newptr;
+ info->rec_alloc=newptr;
+ info->rec_buff=newptr+ALIGN_SIZE(DYN_DELETE_BLOCK_HEADER);
+ info->alloced_rec_buff_length=length;
+ }
+ return info->rec_buff;
+}
+
+
+ /* Compare of record one disk with packed record in memory */
+
+int _nisam_cmp_dynamic_record(register N_INFO *info, register const byte *record)
+{
+ uint flag,reclength,b_type;
+ ulong filepos;
+ byte *buffer;
+ BLOCK_INFO block_info;
+ DBUG_ENTER("_nisam_cmp_dynamic_record");
+
+ /* We are going to do changes; dont let anybody disturb */
+ dont_break(); /* Dont allow SIGHUP or SIGINT */
+
+ if (info->opt_flag & WRITE_CACHE_USED)
+ {
+ info->update&= ~HA_STATE_WRITE_AT_END;
+ if (flush_io_cache(&info->rec_cache))
+ DBUG_RETURN(-1);
+ }
+ info->rec_cache.seek_not_done=1;
+
+ /* If nobody have touched the database we don't have to test rec */
+
+ buffer=info->rec_buff;
+ if ((info->opt_flag & READ_CHECK_USED))
+ { /* If check isn't disabled */
+ if (info->s->base.blobs)
+ {
+ if (!(buffer=(byte*) my_alloca(info->s->base.pack_reclength+
+ _calc_total_blob_length(info,record))))
+ DBUG_RETURN(-1);
+ }
+ reclength=_nisam_rec_pack(info,buffer,record);
+ record= buffer;
+
+ filepos=info->lastpos;
+ flag=block_info.second_read=0;
+ block_info.next_filepos=filepos;
+ while (reclength > 0)
+ {
+ if ((b_type=_nisam_get_block_info(&block_info,info->dfile,
+ block_info.next_filepos))
+ & (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR |
+ BLOCK_FATAL_ERROR))
+ {
+ if (b_type & (BLOCK_SYNC_ERROR | BLOCK_DELETED))
+ my_errno=HA_ERR_RECORD_CHANGED;
+ goto err;
+ }
+ if (flag == 0) /* First block */
+ {
+ flag=1;
+ if (reclength != block_info.rec_len)
+ {
+ my_errno=HA_ERR_RECORD_CHANGED;
+ goto err;
+ }
+ } else if (reclength < block_info.data_len)
+ {
+ my_errno=HA_ERR_WRONG_IN_RECORD;
+ goto err;
+ }
+ reclength-=block_info.data_len;
+ if (_nisam_cmp_buffer(info->dfile,record,block_info.filepos,
+ block_info.data_len))
+ {
+ my_errno=HA_ERR_RECORD_CHANGED;
+ goto err;
+ }
+ flag=1;
+ record+=block_info.data_len;
+ }
+ }
+ my_errno=0;
+ err:
+ if (buffer != info->rec_buff)
+ my_afree((gptr) buffer);
+ DBUG_RETURN(my_errno);
+}
+
+
+ /* Compare file to buffert */
+
+static int _nisam_cmp_buffer(File file, const byte *buff, ulong filepos, uint length)
+{
+ uint next_length;
+ char temp_buff[IO_SIZE*2];
+ DBUG_ENTER("_nisam_cmp_buffer");
+
+ VOID(my_seek(file,filepos,MY_SEEK_SET,MYF(0)));
+ next_length= IO_SIZE*2 - (uint) (filepos & (IO_SIZE-1));
+
+ while (length > IO_SIZE*2)
+ {
+ if (my_read(file,temp_buff,next_length,MYF(MY_NABP)))
+ goto err;
+ if (memcmp((byte*) buff,temp_buff,IO_SIZE))
+ DBUG_RETURN(1);
+ buff+=next_length;
+ length-= next_length;
+ next_length=IO_SIZE*2;
+ }
+ if (my_read(file,temp_buff,length,MYF(MY_NABP)))
+ goto err;
+ DBUG_RETURN(memcmp((byte*) buff,temp_buff,length));
+err:
+ DBUG_RETURN(1);
+}
+
+
+int _nisam_read_rnd_dynamic_record(N_INFO *info, byte *buf, register ulong filepos, int skipp_deleted_blocks)
+{
+ int flag,info_read,fatal_errcode;
+ uint left_len,b_type;
+ byte *to;
+ BLOCK_INFO block_info;
+ ISAM_SHARE *share=info->s;
+ DBUG_ENTER("_nisam_read_rnd_dynamic_record");
+
+ info_read=0;
+ fatal_errcode= -1;
+ LINT_INIT(to);
+
+#ifndef NO_LOCKING
+ if (info->lock_type == F_UNLCK)
+ {
+#ifndef UNSAFE_LOCKING
+ if (share->r_locks == 0 && share->w_locks == 0)
+ {
+ if (my_lock(share->kfile,F_RDLCK,0L,F_TO_EOF,
+ MYF(MY_SEEK_NOT_DONE) | info->lock_wait))
+ DBUG_RETURN(fatal_errcode);
+ }
+#else
+ info->tmp_lock_type=F_RDLCK;
+#endif
+ }
+ else
+ info_read=1; /* memory-keyinfoblock is ok */
+#endif /* !NO_LOCKING */
+
+ flag=block_info.second_read=0;
+ left_len=1;
+ do
+ {
+ if (filepos >= share->state.data_file_length)
+ {
+#ifndef NO_LOCKING
+ if (!info_read)
+ { /* Check if changed */
+ info_read=1;
+ info->rec_cache.seek_not_done=1;
+ if (my_pread(share->kfile,(char*) &share->state.header,
+ share->state_length, 0L,MYF(MY_NABP)))
+ goto err;
+ }
+ if (filepos >= share->state.data_file_length)
+#endif
+ {
+ my_errno= HA_ERR_END_OF_FILE;
+ goto err;
+ }
+ }
+ if (info->opt_flag & READ_CACHE_USED)
+ {
+ if (_nisam_read_cache(&info->rec_cache,(byte*) block_info.header,filepos,
+ sizeof(block_info.header),
+ test(!flag && skipp_deleted_blocks) | 2))
+ goto err;
+ b_type=_nisam_get_block_info(&block_info,-1,filepos);
+ }
+ else
+ {
+ if (info->opt_flag & WRITE_CACHE_USED &&
+ info->rec_cache.pos_in_file <= filepos &&
+ flush_io_cache(&info->rec_cache))
+ DBUG_RETURN(-1);
+ info->rec_cache.seek_not_done=1;
+ b_type=_nisam_get_block_info(&block_info,info->dfile,filepos);
+ }
+
+ if (b_type & (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR |
+ BLOCK_FATAL_ERROR))
+ {
+ if ((b_type & (BLOCK_DELETED | BLOCK_SYNC_ERROR))
+ && skipp_deleted_blocks)
+ {
+ filepos=block_info.filepos+block_info.block_len;
+ block_info.second_read=0;
+ continue; /* Search after next_record */
+ }
+ if (b_type & (BLOCK_DELETED | BLOCK_SYNC_ERROR))
+ {
+ my_errno=HA_ERR_RECORD_DELETED;
+ info->lastpos=block_info.filepos;
+ info->nextpos=block_info.filepos+block_info.block_len;
+ fatal_errcode=1;
+ }
+ goto err;
+ }
+ if (flag == 0) /* First block */
+ {
+ if (block_info.rec_len > (uint) share->base.max_pack_length)
+ goto panic;
+ info->lastpos=filepos;
+ if (share->base.blobs)
+ {
+ if (!(to=fix_rec_buff_for_blob(info,block_info.rec_len)))
+ goto err;
+ }
+ else
+ to= info->rec_buff;
+ left_len=block_info.rec_len;
+ }
+ if (left_len < block_info.data_len)
+ goto panic; /* Wrong linked record */
+
+ if (info->opt_flag & READ_CACHE_USED)
+ {
+ if (_nisam_read_cache(&info->rec_cache,(byte*) to,block_info.filepos,
+ block_info.data_len,
+ test(!flag && skipp_deleted_blocks)))
+ goto err;
+ }
+ else
+ {
+ VOID(my_seek(info->dfile,block_info.filepos,MY_SEEK_SET,MYF(0)));
+ if (my_read(info->dfile,(byte*) to,block_info.data_len,MYF(MY_NABP)))
+ goto err;
+ }
+ if (flag++ == 0)
+ {
+ info->nextpos=block_info.filepos+block_info.block_len;
+ skipp_deleted_blocks=0;
+ }
+ left_len-=block_info.data_len;
+ to+=block_info.data_len;
+ filepos=block_info.next_filepos;
+ } while (left_len);
+
+ info->update|= HA_STATE_AKTIV | HA_STATE_KEY_CHANGED;
+ VOID(_nisam_writeinfo(info,0));
+ if (_nisam_rec_unpack(info,buf,info->rec_buff,block_info.rec_len) !=
+ MY_FILE_ERROR)
+ DBUG_RETURN(0);
+ DBUG_RETURN(fatal_errcode); /* Wrong record */
+
+panic:
+ my_errno=HA_ERR_WRONG_IN_RECORD; /* Something is fatal wrong */
+err:
+ VOID(_nisam_writeinfo(info,0));
+ DBUG_RETURN(fatal_errcode);
+}
+
+
+ /* Read and process header from a dynamic-record-file */
+
+uint _nisam_get_block_info(BLOCK_INFO *info, File file, ulong filepos)
+{
+ uint return_val=0,length;
+ uchar *header=info->header;
+
+ if (file >= 0)
+ {
+ VOID(my_seek(file,filepos,MY_SEEK_SET,MYF(0)));
+ if ((length=my_read(file,(char*) header,BLOCK_INFO_HEADER_LENGTH,MYF(0)))
+ == MY_FILE_ERROR)
+ return BLOCK_FATAL_ERROR;
+ if (length != BLOCK_INFO_HEADER_LENGTH)
+ { /* Test if short block */
+ if (length < 3)
+ {
+ my_errno=HA_ERR_WRONG_IN_RECORD; /* Garbage */
+ return BLOCK_FATAL_ERROR;
+ }
+ bzero((byte*) header+length,BLOCK_INFO_HEADER_LENGTH-length);
+ }
+ }
+ DBUG_DUMP("header",(byte*) header,BLOCK_INFO_HEADER_LENGTH);
+ if (info->second_read)
+ {
+ if (info->header[0] <= 8)
+ return_val=BLOCK_SYNC_ERROR;
+ }
+ else
+ {
+ if (info->header[0] > 8)
+ return_val=BLOCK_SYNC_ERROR;
+ }
+ info->next_filepos= (ulong) NI_POS_ERROR; /* Dummy ifall no next block */
+
+ switch (info->header[0]) {
+ case 0:
+ if ((info->block_len=(uint) uint3korr(header+1)) < N_MIN_BLOCK_LENGTH)
+ return BLOCK_FATAL_ERROR;
+ info->filepos=filepos;
+ info->next_filepos=uint4korr(header+4);
+ if (info->next_filepos == (uint32) ~0) /* Fix for 64 bit long */
+ info->next_filepos=NI_POS_ERROR;
+ return return_val | BLOCK_DELETED; /* Deleted block */
+ case 1:
+ info->rec_len=info->data_len=info->block_len=uint2korr(header+1);
+ info->filepos=filepos+3;
+ return return_val | BLOCK_FIRST | BLOCK_LAST;
+ case 2:
+ info->block_len=(info->rec_len=info->data_len=uint2korr(header+1))+1;
+ info->filepos=filepos+3;
+ return return_val | BLOCK_FIRST | BLOCK_LAST;
+ case 3:
+ info->rec_len=info->data_len=uint2korr(header+1);
+ info->block_len=uint2korr(header+3);
+ info->filepos=filepos+5;
+ return return_val | BLOCK_FIRST | BLOCK_LAST;
+ case 4:
+ info->rec_len=uint2korr(header+1);
+ info->block_len=info->data_len=uint2korr(header+3);
+ info->next_filepos=uint4korr(header+5);
+ info->second_read=1;
+ info->filepos=filepos+9;
+ return return_val | BLOCK_FIRST;
+#if defined(_MSC_VER) || !defined(__WIN__)
+ case 5:
+ info->rec_len=info->data_len=info->block_len=uint3korr(header+1);
+ info->filepos=filepos+4;
+ return return_val | BLOCK_FIRST | BLOCK_LAST;
+ case 6:
+ info->block_len=(info->rec_len=info->data_len=uint3korr(header+1))+1;
+ info->filepos=filepos+4;
+ return return_val | BLOCK_FIRST | BLOCK_LAST;
+ case 7:
+ info->rec_len=info->data_len=uint3korr(header+1);
+ info->block_len=uint3korr(header+4);
+ info->filepos=filepos+7;
+ return return_val | BLOCK_FIRST | BLOCK_LAST;
+ case 8:
+ info->rec_len=uint3korr(header+1);
+ info->block_len=info->data_len=uint3korr(header+4);
+ info->next_filepos=uint4korr(header+7);
+ info->second_read=1;
+ info->filepos=filepos+11;
+ return return_val | BLOCK_FIRST;
+#endif
+ case 9:
+ info->data_len=info->block_len=uint2korr(header+1);
+ info->filepos=filepos+3;
+ return return_val | BLOCK_LAST;
+ case 10:
+ info->block_len=(info->data_len=uint2korr(header+1))+1;
+ info->filepos=filepos+3;
+ return return_val | BLOCK_LAST;
+ case 11:
+ info->data_len=uint2korr(header+1);
+ info->block_len=uint2korr(header+3);
+ info->filepos=filepos+5;
+ return return_val | BLOCK_LAST;
+ case 12:
+ info->data_len=info->block_len=uint2korr(header+1);
+ info->next_filepos=uint4korr(header+3);
+ info->second_read=1;
+ info->filepos=filepos+7;
+ return return_val;
+#if defined(_MSC_VER) || !defined(__WIN__)
+ case 13:
+ info->data_len=info->block_len=uint3korr(header+1);
+ info->filepos=filepos+4;
+ return return_val | BLOCK_LAST;
+ case 14:
+ info->block_len=(info->data_len=uint3korr(header+1))+1;
+ info->filepos=filepos+4;
+ return return_val | BLOCK_LAST;
+ case 15:
+ info->data_len=uint3korr(header+1);
+ info->block_len=uint3korr(header+4);
+ info->filepos=filepos+7;
+ return return_val | BLOCK_LAST;
+ case 16:
+ info->data_len=info->block_len=uint3korr(header+1);
+ info->next_filepos=uint4korr(header+4);
+ info->second_read=1;
+ info->filepos=filepos+8;
+ return return_val;
+#endif
+ default:
+ my_errno=HA_ERR_WRONG_IN_RECORD; /* Garbage */
+ return BLOCK_ERROR;
+ }
+}
diff --git a/isam/_key.c b/isam/_key.c
new file mode 100644
index 00000000000..62f080af172
--- /dev/null
+++ b/isam/_key.c
@@ -0,0 +1,239 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* Functions to handle keys */
+
+#include "isamdef.h"
+#include "m_ctype.h"
+
+static void _nisam_put_key_in_record(N_INFO *info,uint keynr,byte *record);
+
+ /* Make a intern key from a record */
+ /* If ascii key convert according to sortorder */
+ /* Ret: Length of key */
+
+uint _nisam_make_key(register N_INFO *info, uint keynr, uchar *key, const char *record, ulong filepos)
+{
+ uint length;
+ byte *pos,*end;
+ uchar *start;
+ reg1 N_KEYSEG *keyseg;
+ enum ha_base_keytype type;
+ DBUG_ENTER("_nisam_make_key");
+
+ start=key;
+ for (keyseg=info->s->keyinfo[keynr].seg ; keyseg->base.type ;keyseg++)
+ {
+ type=(enum ha_base_keytype) keyseg->base.type;
+ if (keyseg->base.flag & HA_SPACE_PACK)
+ {
+ pos= (byte*) record+keyseg->base.start; end=pos+keyseg->base.length;
+ if (type != HA_KEYTYPE_NUM)
+ {
+ while (end > pos && end[-1] == ' ')
+ end--;
+ }
+ else
+ {
+ while (pos < end && pos[0] == ' ')
+ pos++;
+ }
+ *key++= (uchar) (length=(uint) (end-pos));
+ memcpy((byte*) key,(byte*) pos,(size_t) length);
+#ifdef USE_STRCOLL
+ if (!use_strcoll(default_charset_info))
+#endif
+ {
+ if (type == HA_KEYTYPE_TEXT)
+ case_sort((byte*) key,length);
+ }
+ key+=length;
+ }
+ else
+ {
+ memcpy((byte*) key,(byte*) record+keyseg->base.start,
+ (size_t) keyseg->base.length);
+#ifdef USE_STRCOLL
+ if (!use_strcoll(default_charset_info))
+#endif
+ {
+ if (type == HA_KEYTYPE_TEXT)
+ case_sort((byte*) key,(uint) keyseg->base.length);
+ }
+#ifdef NAN_TEST
+ else if (type == HA_KEYTYPE_FLOAT)
+ {
+ float nr;
+ bmove((byte*) &nr,(byte*) key,sizeof(float));
+ if (nr == (float) FLT_MAX)
+ {
+ nr= (float) FLT_MAX;
+ bmove((byte*) key,(byte*) &nr,sizeof(float));
+ }
+ }
+ else if (type == HA_KEYTYPE_DOUBLE)
+ {
+ double nr;
+ bmove((byte*) &nr,(byte*) key,sizeof(double));
+ if (nr == DBL_MAX)
+ {
+ nr=DBL_MAX;
+ bmove((byte*) key,(byte*) &nr,sizeof(double));
+ }
+ }
+#endif
+ key+= keyseg->base.length;
+ }
+ }
+ _nisam_dpointer(info,key,filepos);
+ DBUG_PRINT("exit",("keynr: %d",keynr));
+ DBUG_DUMP("key",(byte*) start,(uint) (key-start)+keyseg->base.length);
+ DBUG_EXECUTE("key",_nisam_print_key(DBUG_FILE,info->s->keyinfo[keynr].seg,start););
+ DBUG_RETURN((uint) (key-start)); /* Return keylength */
+} /* _nisam_make_key */
+
+
+ /* Pack a key to intern format from given format (c_rkey) */
+ /* if key_length is set returns new length of key */
+
+uint _nisam_pack_key(register N_INFO *info, uint keynr, uchar *key, uchar *old, uint key_length)
+
+
+
+ /* Length of used key */
+{
+ int k_length;
+ uint length;
+ uchar *pos,*end;
+ reg1 N_KEYSEG *keyseg;
+ enum ha_base_keytype type;
+ DBUG_ENTER("_nisam_pack_key");
+
+ if ((k_length=(int) key_length) <= 0)
+ k_length=N_MAX_KEY_BUFF;
+
+ for (keyseg=info->s->keyinfo[keynr].seg ;
+ keyseg->base.type && k_length >0;
+ k_length-=keyseg->base.length, old+=keyseg->base.length, keyseg++)
+ {
+ length=min((uint) keyseg->base.length,(uint) k_length);
+ type=(enum ha_base_keytype) keyseg->base.type;
+ if (keyseg->base.flag & HA_SPACE_PACK)
+ {
+ pos=old; end=pos+length;
+ if (type != HA_KEYTYPE_NUM)
+ {
+ while (end > pos && end[-1] == ' ')
+ end--;
+ }
+ else
+ {
+ while (pos < end && pos[0] == ' ')
+ pos++;
+ }
+ *key++ = (uchar) (length=(uint) (end-pos));
+ memcpy((byte*) key,pos,(size_t) length);
+ }
+ else
+ memcpy((byte*) key,old,(size_t) length);
+#ifdef USE_STRCOLL
+ if (!use_strcoll(default_charset_info))
+#endif
+ {
+ if (type == HA_KEYTYPE_TEXT)
+ case_sort((byte*) key,length);
+ }
+ key+= length;
+ }
+ if (!keyseg->base.type)
+ {
+ if (k_length >= 0) /* Hole key */
+ key_length=0;
+ }
+ else
+ { /* Part-key ; fill with null */
+ length= (uint) -k_length; /* unused part of last key */
+ do
+ {
+ length+= (keyseg->base.flag & HA_SPACE_PACK) ? 1 :
+ keyseg->base.length;
+ keyseg++;
+ } while (keyseg->base.type);
+ bzero((byte*) key,length);
+ }
+ DBUG_RETURN(key_length); /* Return part-keylength */
+} /* _nisam_pack_key */
+
+
+ /* Put a key in record */
+ /* Used when only-keyread is wanted */
+
+static void _nisam_put_key_in_record(register N_INFO *info, uint keynr, byte *record)
+{
+ uint length;
+ reg2 byte *key;
+ byte *pos;
+ reg1 N_KEYSEG *keyseg;
+ DBUG_ENTER("_nisam_put_key_in_record");
+
+ key=(byte*) info->lastkey;
+ for (keyseg=info->s->keyinfo[keynr].seg ; keyseg->base.type ;keyseg++)
+ {
+ if (keyseg->base.flag & HA_SPACE_PACK)
+ {
+ length= (uint) (uchar) *key++;
+ pos= record+keyseg->base.start;
+ if (keyseg->base.type != (int) HA_KEYTYPE_NUM)
+ {
+ memcpy(pos,key,(size_t) length);
+ bfill(pos+length,keyseg->base.length-length,' ');
+ }
+ else
+ {
+ bfill(pos,keyseg->base.length-length,' ');
+ memcpy(pos+keyseg->base.length-length,key,(size_t) length);
+ }
+ key+=length;
+ }
+ else
+ {
+ memcpy(record+keyseg->base.start,(byte*) key,
+ (size_t) keyseg->base.length);
+ key+= keyseg->base.length;
+ }
+ }
+ DBUG_VOID_RETURN;
+} /* _nisam_put_key_in_record */
+
+
+ /* Here when key reads are used */
+
+int _nisam_read_key_record(N_INFO *info, ulong filepos, byte *buf)
+{
+ VOID(_nisam_writeinfo(info,0));
+ if (filepos != NI_POS_ERROR)
+ {
+ if (info->lastinx >= 0)
+ { /* Read only key */
+ _nisam_put_key_in_record(info,(uint) info->lastinx,buf);
+ info->update|= HA_STATE_AKTIV; /* We should find a record */
+ return 0;
+ }
+ my_errno=HA_ERR_WRONG_INDEX;
+ return(-1);
+ }
+ return(-1); /* Wrong data to read */
+}
diff --git a/isam/_locking.c b/isam/_locking.c
new file mode 100644
index 00000000000..ca38c611812
--- /dev/null
+++ b/isam/_locking.c
@@ -0,0 +1,345 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/*
+ locking of isam-tables.
+ reads info from a isam-table. Must be first request before doing any furter
+ calls to any isamfunktion. Is used to allow many process use the same
+ isamdatabase.
+ */
+
+#include "isamdef.h"
+#ifdef __WIN__
+#include <errno.h>
+#endif
+
+ /* lock table by F_UNLCK, F_RDLCK or F_WRLCK */
+
+int nisam_lock_database(N_INFO *info, int lock_type)
+{
+ int error;
+ uint count;
+ ISAM_SHARE *share;
+ uint flag;
+ DBUG_ENTER("nisam_lock_database");
+
+ flag=error=0;
+#ifndef NO_LOCKING
+ share=info->s;
+ if (share->base.options & HA_OPTION_READ_ONLY_DATA ||
+ info->lock_type == lock_type)
+ DBUG_RETURN(0);
+ pthread_mutex_lock(&share->intern_lock);
+ switch (lock_type) {
+ case F_UNLCK:
+ if (info->lock_type == F_RDLCK)
+ count= --share->r_locks;
+ else
+ count= --share->w_locks;
+ if (info->lock_type == F_WRLCK && !share->w_locks &&
+ flush_key_blocks(share->kfile,FLUSH_KEEP))
+ error=my_errno;
+ if (info->opt_flag & (READ_CACHE_USED | WRITE_CACHE_USED))
+ if (end_io_cache(&info->rec_cache))
+ error=my_errno;
+
+ if (!count)
+ {
+ if (share->changed && !share->w_locks)
+ {
+ share->state.process= share->last_process=share->this_process;
+ share->state.loop= info->last_loop= ++info->this_loop;
+ share->state.uniq= info->last_uniq= info->this_uniq;
+ if (my_pwrite(share->kfile,(char*) &share->state.header,
+ share->state_length,0L,MYF(MY_NABP)))
+ error=my_errno;
+ share->changed=0;
+#ifdef __WIN__
+ if (nisam_flush)
+ {
+ _commit(share->kfile);
+ _commit(info->dfile);
+ }
+ else
+ share->not_flushed=1;
+#endif
+ }
+ if (share->r_locks)
+ { /* Only read locks left */
+ flag=1;
+ if (my_lock(share->kfile,F_RDLCK,0L,F_TO_EOF,
+ MYF(MY_WME | MY_SEEK_NOT_DONE)) && !error)
+ error=my_errno;
+ }
+ else if (!share->w_locks)
+ { /* No more locks */
+ flag=1;
+ if (my_lock(share->kfile,F_UNLCK,0L,F_TO_EOF,
+ MYF(MY_WME | MY_SEEK_NOT_DONE)) && !error)
+ error=my_errno;
+ }
+ }
+ info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
+ info->lock_type= F_UNLCK;
+ break;
+ case F_RDLCK:
+ if (info->lock_type == F_WRLCK)
+ { /* Change RW to READONLY */
+ if (share->w_locks == 1)
+ {
+ flag=1;
+ if (my_lock(share->kfile,lock_type,0L,F_TO_EOF,
+ MYF(MY_SEEK_NOT_DONE)))
+ {
+ error=my_errno;
+ break;
+ }
+ }
+ share->w_locks--;
+ share->r_locks++;
+ info->lock_type=lock_type;
+ break;
+ }
+ if (!share->r_locks && !share->w_locks)
+ {
+ flag=1;
+#ifdef HAVE_FCNTL
+ if (my_lock(share->kfile,lock_type,0L,F_TO_EOF,info->lock_wait))
+ {
+ error=my_errno;
+ break;
+ }
+ if (my_pread(share->kfile,
+ (char*) &share->state.header,share->state_length,0L,
+ MYF(MY_NABP)))
+ {
+ error=my_errno;
+ VOID(my_lock(share->kfile,F_UNLCK,0L,F_TO_EOF,MYF(MY_SEEK_NOT_DONE)));
+ my_errno=error;
+ break;
+ }
+#else
+ VOID(my_seek(share->kfile,0L,MY_SEEK_SET,MYF(0)));
+ if (my_lock(share->kfile,lock_type,0L,F_TO_EOF,info->lock_wait))
+ {
+ error=my_errno;
+ break;
+ }
+ if (my_read(share->kfile,
+ (char*) &share->state.header,share->state_length,
+ MYF(MY_NABP)))
+ {
+ error=my_errno;
+ VOID(my_lock(share->kfile,F_UNLCK,0L,F_TO_EOF,info->lock_wait));
+ my_errno=error;
+ break;
+ }
+#endif
+ }
+ VOID(_nisam_test_if_changed(info));
+ share->r_locks++;
+ info->lock_type=lock_type;
+ break;
+ case F_WRLCK:
+ if (info->lock_type == F_RDLCK)
+ { /* Change RW to READONLY */
+ if (share->r_locks == 1)
+ {
+ flag=1;
+ if (my_lock(share->kfile,lock_type,0L,F_TO_EOF,
+ MYF(info->lock_wait | MY_SEEK_NOT_DONE)))
+ {
+ error=my_errno;
+ break;
+ }
+ share->r_locks--;
+ share->w_locks++;
+ info->lock_type=lock_type;
+ break;
+ }
+ }
+ if (!(share->base.options & HA_OPTION_READ_ONLY_DATA) && !share->w_locks)
+ {
+ flag=1;
+ VOID(my_seek(share->kfile,0L,MY_SEEK_SET,MYF(0)));
+ if (my_lock(share->kfile,lock_type,0L,F_TO_EOF,info->lock_wait))
+ {
+ error=my_errno;
+ break;
+ }
+ if (!share->r_locks)
+ {
+ if (my_read(share->kfile,
+ (char*) &share->state.header,share->state_length,
+ MYF(MY_NABP)))
+ {
+ error=my_errno;
+ VOID(my_lock(share->kfile,F_UNLCK,0L,F_TO_EOF,info->lock_wait));
+ my_errno=error;
+ break;
+ }
+ }
+ }
+ VOID(_nisam_test_if_changed(info));
+ info->lock_type=lock_type;
+ share->w_locks++;
+ break;
+ default:
+ break; /* Impossible */
+ }
+ pthread_mutex_unlock(&share->intern_lock);
+#if defined(FULL_LOG) || defined(_lint)
+ lock_type|=(int) (flag << 8); /* Set bit to set if real lock */
+ nisam_log_command(LOG_LOCK,info,(byte*) &lock_type,sizeof(lock_type),
+ error);
+#endif
+#endif
+ DBUG_RETURN(error);
+} /* nisam_lock_database */
+
+
+ /* Is used before access to database is granted */
+
+int _nisam_readinfo(register N_INFO *info, int lock_type, int check_keybuffer)
+{
+ ISAM_SHARE *share;
+ DBUG_ENTER("_nisam_readinfo");
+
+ share=info->s;
+ if (info->lock_type == F_UNLCK)
+ {
+ if (!share->r_locks && !share->w_locks)
+ {
+#ifndef HAVE_FCNTL
+ VOID(my_seek(share->kfile,0L,MY_SEEK_SET,MYF(0)));
+#endif
+#ifndef NO_LOCKING
+#ifdef UNSAFE_LOCKING
+ if ((info->tmp_lock_type=lock_type) != F_RDLCK)
+#endif
+ if (my_lock(share->kfile,lock_type,0L,F_TO_EOF,info->lock_wait))
+ DBUG_RETURN(1);
+#endif
+#ifdef HAVE_FCNTL
+ if (my_pread(share->kfile,
+ (char*) &share->state.header,share->state_length,0L,
+ MYF(MY_NABP)))
+#else
+ if (my_read(share->kfile,
+ (char*) &share->state.header,share->state_length,
+ MYF(MY_NABP)))
+#endif
+ {
+#ifndef NO_LOCKING
+ int error=my_errno;
+ VOID(my_lock(share->kfile,F_UNLCK,0L,F_TO_EOF,
+ MYF(MY_SEEK_NOT_DONE)));
+ my_errno=error;
+#endif
+ DBUG_RETURN(1);
+ }
+ }
+ if (check_keybuffer)
+ VOID(_nisam_test_if_changed(info));
+ }
+ else if (lock_type == F_WRLCK && info->lock_type == F_RDLCK)
+ {
+ my_errno=EACCES; /* Not allowed to change */
+ DBUG_RETURN(-1); /* when have read_lock() */
+ }
+ DBUG_RETURN(0);
+} /* _nisam_readinfo */
+
+
+ /* Every isam-function that uppdates the isam-database must! end */
+ /* with this request */
+ /* ARGSUSED */
+
+int _nisam_writeinfo(register N_INFO *info, uint flags)
+{
+ int error,olderror;
+ ISAM_SHARE *share;
+ DBUG_ENTER("_nisam_writeinfo");
+
+ error=0;
+ share=info->s;
+ if (share->r_locks == 0 && share->w_locks == 0)
+ {
+ olderror=my_errno; /* Remember last error */
+ if (flags)
+ { /* Two threads can't be here */
+ share->state.process= share->last_process= share->this_process;
+ share->state.loop= info->last_loop= ++info->this_loop;
+ share->state.uniq= info->last_uniq= info->this_uniq;
+ if ((error=my_pwrite(share->kfile,(char*) &share->state.header,
+ share->state_length,0L,MYF(MY_NABP)) != 0))
+ olderror=my_errno;
+#ifdef __WIN__
+ if (nisam_flush)
+ {
+ _commit(share->kfile);
+ _commit(info->dfile);
+ }
+#endif
+ }
+ if (flags != 2)
+ {
+#ifndef NO_LOCKING
+#ifdef UNSAFE_LOCKING
+ if (info->tmp_lock_type != F_RDLCK)
+#endif
+ {
+ if (my_lock(share->kfile,F_UNLCK,0L,F_TO_EOF,
+ MYF(MY_WME | MY_SEEK_NOT_DONE)) && !error)
+ DBUG_RETURN(1);
+ }
+ }
+#endif
+ my_errno=olderror;
+ }
+ else if (flags)
+ share->changed= 1; /* Mark keyfile changed */
+ DBUG_RETURN(error);
+} /* _nisam_writeinfo */
+
+
+ /* Test if someone has changed the database */
+ /* (Should be called after readinfo) */
+
+int _nisam_test_if_changed(register N_INFO *info)
+{
+#ifndef NO_LOCKING
+ {
+ ISAM_SHARE *share=info->s;
+ if (share->state.process != share->last_process ||
+ share->state.loop != info->last_loop ||
+ share->state.uniq != info->last_uniq)
+ { /* Keyfile has changed */
+ if (share->state.process != share->this_process)
+ VOID(flush_key_blocks(share->kfile,FLUSH_RELEASE));
+ share->last_process=share->state.process;
+ info->last_loop= share->state.loop;
+ info->last_uniq= share->state.uniq;
+ info->update|= HA_STATE_WRITTEN; /* Must use file on next */
+ info->data_changed= 1; /* For nisam_is_changed */
+ return 1;
+ }
+ }
+#endif
+ return (!(info->update & HA_STATE_AKTIV) ||
+ (info->update & (HA_STATE_WRITTEN | HA_STATE_DELETED |
+ HA_STATE_KEY_CHANGED)));
+} /* _nisam_test_if_changed */
diff --git a/isam/_packrec.c b/isam/_packrec.c
new file mode 100644
index 00000000000..5c387f011ad
--- /dev/null
+++ b/isam/_packrec.c
@@ -0,0 +1,1184 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+ /* Functions to compressed records */
+
+#include "isamdef.h"
+
+#define IS_CHAR ((uint) 32768) /* Bit if char (not offset) in tree */
+
+#if INT_MAX > 65536L
+#define BITS_SAVED 32
+#define MAX_QUICK_TABLE_BITS 9 /* Because we may shift in 24 bits */
+#else
+#define BITS_SAVED 16
+#define MAX_QUICK_TABLE_BITS 6
+#endif
+
+#define get_bit(BU) ((BU)->bits ? \
+ (BU)->current_byte & ((bit_type) 1 << --(BU)->bits) :\
+ (fill_buffer(BU), (BU)->bits= BITS_SAVED-1,\
+ (BU)->current_byte & ((bit_type) 1 << (BITS_SAVED-1))))
+#define skipp_to_next_byte(BU) ((BU)->bits&=~7)
+#define get_bits(BU,count) (((BU)->bits >= count) ? (((BU)->current_byte >> ((BU)->bits-=count)) & mask[count]) : fill_and_get_bits(BU,count))
+
+#define decode_bytes_test_bit(bit) \
+ if (low_byte & (1 << (7-bit))) \
+ pos++; \
+ if (*pos & IS_CHAR) \
+ { bits-=(bit+1); break; } \
+ pos+= *pos
+
+
+ static void read_huff_table(BIT_BUFF *bit_buff,DECODE_TREE *decode_tree,
+ uint16 **decode_table,byte **intervall_buff,
+ uint16 *tmp_buff);
+static void make_quick_table(uint16 *to_table,uint16 *decode_table,
+ uint *next_free,uint value,uint bits,
+ uint max_bits);
+static void fill_quick_table(uint16 *table,uint bits, uint max_bits,
+ uint value);
+static uint copy_decode_table(uint16 *to_pos,uint offset,
+ uint16 *decode_table);
+static uint find_longest_bitstream(uint16 *table);
+static void (*get_unpack_function(N_RECINFO *rec))(N_RECINFO *field,
+ BIT_BUFF *buff,
+ uchar *to,
+ uchar *end);
+static void uf_zerofill_skipp_zero(N_RECINFO *rec,BIT_BUFF *bit_buff,
+ uchar *to,uchar *end);
+static void uf_skipp_zero(N_RECINFO *rec,BIT_BUFF *bit_buff,
+ uchar *to,uchar *end);
+static void uf_space_normal(N_RECINFO *rec,BIT_BUFF *bit_buff,
+ uchar *to,uchar *end);
+static void uf_space_endspace_selected(N_RECINFO *rec,BIT_BUFF *bit_buff,
+ uchar *to, uchar *end);
+static void uf_endspace_selected(N_RECINFO *rec,BIT_BUFF *bit_buff,
+ uchar *to,uchar *end);
+static void uf_space_endspace(N_RECINFO *rec,BIT_BUFF *bit_buff,
+ uchar *to,uchar *end);
+static void uf_endspace(N_RECINFO *rec,BIT_BUFF *bit_buff,
+ uchar *to,uchar *end);
+static void uf_space_prespace_selected(N_RECINFO *rec,BIT_BUFF *bit_buff,
+ uchar *to, uchar *end);
+static void uf_prespace_selected(N_RECINFO *rec,BIT_BUFF *bit_buff,
+ uchar *to,uchar *end);
+static void uf_space_prespace(N_RECINFO *rec,BIT_BUFF *bit_buff,
+ uchar *to,uchar *end);
+static void uf_prespace(N_RECINFO *rec,BIT_BUFF *bit_buff,
+ uchar *to,uchar *end);
+static void uf_zerofill_normal(N_RECINFO *rec,BIT_BUFF *bit_buff,
+ uchar *to,uchar *end);
+static void uf_constant(N_RECINFO *rec,BIT_BUFF *bit_buff,
+ uchar *to,uchar *end);
+static void uf_intervall(N_RECINFO *rec,BIT_BUFF *bit_buff,
+ uchar *to,uchar *end);
+static void uf_zero(N_RECINFO *rec,BIT_BUFF *bit_buff,
+ uchar *to,uchar *end);
+static void decode_bytes(N_RECINFO *rec,BIT_BUFF *bit_buff,
+ uchar *to,uchar *end);
+static uint decode_pos(BIT_BUFF *bit_buff,DECODE_TREE *decode_tree);
+static void init_bit_buffer(BIT_BUFF *bit_buff,char *buffer,uint length);
+static uint fill_and_get_bits(BIT_BUFF *bit_buff,uint count);
+static void fill_buffer(BIT_BUFF *bit_buff);
+static uint max_bit(uint value);
+#ifdef HAVE_MMAP
+static void _nisam_mempack_get_block_info(BLOCK_INFO *info,uint ref_length,
+ uchar *header);
+#endif
+
+static uint mask[]=
+{
+ 0x00000000,
+ 0x00000001, 0x00000003, 0x00000007, 0x0000000f,
+ 0x0000001f, 0x0000003f, 0x0000007f, 0x000000ff,
+ 0x000001ff, 0x000003ff, 0x000007ff, 0x00000fff,
+ 0x00001fff, 0x00003fff, 0x00007fff, 0x0000ffff,
+#if BITS_SAVED > 16
+ 0x0001ffff, 0x0003ffff, 0x0007ffff, 0x000fffff,
+ 0x001fffff, 0x003fffff, 0x007fffff, 0x00ffffff,
+ 0x01ffffff, 0x03ffffff, 0x07ffffff, 0x0fffffff,
+ 0x1fffffff, 0x3fffffff, 0x7fffffff, 0xffffffff,
+#endif
+ };
+
+
+ /* Read all packed info, allocate memory and fix field structs */
+
+my_bool _nisam_read_pack_info(N_INFO *info, pbool fix_keys)
+{
+ File file;
+ int diff_length;
+ uint i,trees,huff_tree_bits,rec_reflength,length;
+ uint16 *decode_table,*tmp_buff;
+ ulong elements,intervall_length;
+ char *disk_cache,*intervall_buff;
+ uchar header[32];
+ ISAM_SHARE *share=info->s;
+ BIT_BUFF bit_buff;
+ DBUG_ENTER("_nisam_read_pack_info");
+
+ if (nisam_quick_table_bits < 4)
+ nisam_quick_table_bits=4;
+ else if (nisam_quick_table_bits > MAX_QUICK_TABLE_BITS)
+ nisam_quick_table_bits=MAX_QUICK_TABLE_BITS;
+
+ file=info->dfile;
+ my_errno=0;
+ if (my_read(file,(byte*) header,sizeof(header),MYF(MY_NABP)))
+ {
+ if (!my_errno)
+ my_errno=HA_ERR_END_OF_FILE;
+ DBUG_RETURN(1);
+ }
+ if (memcmp((byte*) header,(byte*) nisam_pack_file_magic,4))
+ {
+ my_errno=HA_ERR_WRONG_IN_RECORD;
+ DBUG_RETURN(1);
+ }
+ share->pack.header_length=uint4korr(header+4);
+ share->min_pack_length=(uint) uint4korr(header+8);
+ share->max_pack_length=(uint) uint4korr(header+12);
+ set_if_bigger(share->base.pack_reclength,share->max_pack_length);
+ elements=uint4korr(header+16);
+ intervall_length=uint4korr(header+20);
+ trees=uint2korr(header+24);
+ share->pack.ref_length=header[26];
+ rec_reflength=header[27];
+ diff_length=(int) rec_reflength - (int) share->base.rec_reflength;
+ if (fix_keys)
+ share->rec_reflength=rec_reflength;
+ share->base.min_block_length=share->min_pack_length+share->pack.ref_length;
+
+ if (!(share->decode_trees=(DECODE_TREE*)
+ my_malloc((uint) (trees*sizeof(DECODE_TREE)+
+ intervall_length*sizeof(byte)),
+ MYF(MY_WME))))
+ DBUG_RETURN(1);
+ intervall_buff=(byte*) (share->decode_trees+trees);
+
+ length=(uint) (elements*2+trees*(1 << nisam_quick_table_bits));
+ if (!(share->decode_tables=(uint16*)
+ my_malloc((length+512)*sizeof(uint16)+
+ (uint) (share->pack.header_length+7),
+ MYF(MY_WME | MY_ZEROFILL))))
+ {
+ my_free((gptr) share->decode_trees,MYF(0));
+ DBUG_RETURN(1);
+ }
+ tmp_buff=share->decode_tables+length;
+ disk_cache=(byte*) (tmp_buff+512);
+
+ if (my_read(file,disk_cache,
+ (uint) (share->pack.header_length-sizeof(header)),
+ MYF(MY_NABP)))
+ {
+ my_free((gptr) share->decode_trees,MYF(0));
+ my_free((gptr) share->decode_tables,MYF(0));
+ DBUG_RETURN(1);
+ }
+
+ huff_tree_bits=max_bit(trees ? trees-1 : 0);
+ init_bit_buffer(&bit_buff,disk_cache,
+ (uint) (share->pack.header_length-sizeof(header)));
+ /* Read new info for each field */
+ for (i=0 ; i < share->base.fields ; i++)
+ {
+ share->rec[i].base_type=(enum en_fieldtype) get_bits(&bit_buff,4);
+ share->rec[i].pack_type=(uint) get_bits(&bit_buff,4);
+ share->rec[i].space_length_bits=get_bits(&bit_buff,4);
+ share->rec[i].huff_tree=share->decode_trees+(uint) get_bits(&bit_buff,
+ huff_tree_bits);
+ share->rec[i].unpack=get_unpack_function(share->rec+i);
+ }
+ skipp_to_next_byte(&bit_buff);
+ decode_table=share->decode_tables;
+ for (i=0 ; i < trees ; i++)
+ read_huff_table(&bit_buff,share->decode_trees+i,&decode_table,
+ &intervall_buff,tmp_buff);
+ decode_table=(uint16*)
+ my_realloc((gptr) share->decode_tables,
+ (uint) ((byte*) decode_table - (byte*) share->decode_tables),
+ MYF(MY_HOLD_ON_ERROR));
+ {
+ my_ptrdiff_t diff=PTR_BYTE_DIFF(decode_table,share->decode_tables);
+ share->decode_tables=decode_table;
+ for (i=0 ; i < trees ; i++)
+ share->decode_trees[i].table=ADD_TO_PTR(share->decode_trees[i].table,
+ diff, uint16*);
+ }
+
+ /* Fix record-ref-length for keys */
+ if (fix_keys)
+ {
+ for (i=0 ; i < share->base.keys ; i++)
+ {
+ share->keyinfo[i].base.keylength+=(uint16) diff_length;
+ share->keyinfo[i].base.minlength+=(uint16) diff_length;
+ share->keyinfo[i].base.maxlength+=(uint16) diff_length;
+ share->keyinfo[i].seg[share->keyinfo[i].base.keysegs].base.length=
+ (uint16) rec_reflength;
+ }
+ }
+
+ if (bit_buff.error || bit_buff.pos < bit_buff.end)
+ { /* info_length was wrong */
+ my_errno=HA_ERR_WRONG_IN_RECORD;
+ my_free((gptr) share->decode_trees,MYF(0));
+ my_free((gptr) share->decode_tables,MYF(0));
+ DBUG_RETURN(1);
+ }
+ DBUG_RETURN(0);
+}
+
+
+ /* Read on huff-code-table from datafile */
+
+static void read_huff_table(BIT_BUFF *bit_buff, DECODE_TREE *decode_tree,
+ uint16 **decode_table, byte **intervall_buff,
+ uint16 *tmp_buff)
+{
+ uint min_chr,elements,char_bits,offset_bits,size,intervall_length,table_bits,
+ next_free_offset;
+ uint16 *ptr,*end;
+
+ LINT_INIT(ptr);
+ if (!get_bits(bit_buff,1))
+ {
+ min_chr=get_bits(bit_buff,8);
+ elements=get_bits(bit_buff,9);
+ char_bits=get_bits(bit_buff,5);
+ offset_bits=get_bits(bit_buff,5);
+ intervall_length=0;
+ ptr=tmp_buff;
+ }
+ else
+ {
+ min_chr=0;
+ elements=get_bits(bit_buff,15);
+ intervall_length=get_bits(bit_buff,16);
+ char_bits=get_bits(bit_buff,5);
+ offset_bits=get_bits(bit_buff,5);
+ decode_tree->quick_table_bits=0;
+ ptr= *decode_table;
+ }
+ size=elements*2-2;
+
+ for (end=ptr+size ; ptr < end ; ptr++)
+ {
+ if (get_bit(bit_buff))
+ *ptr= (uint16) get_bits(bit_buff,offset_bits);
+ else
+ *ptr= (uint16) (IS_CHAR + (get_bits(bit_buff,char_bits) + min_chr));
+ }
+ skipp_to_next_byte(bit_buff);
+
+ decode_tree->table= *decode_table;
+ decode_tree->intervalls= *intervall_buff;
+ if (! intervall_length)
+ {
+ table_bits=find_longest_bitstream(tmp_buff);
+ if (table_bits > nisam_quick_table_bits)
+ table_bits=nisam_quick_table_bits;
+ next_free_offset= (1 << table_bits);
+ make_quick_table(*decode_table,tmp_buff,&next_free_offset,0,table_bits,
+ table_bits);
+ (*decode_table)+= next_free_offset;
+ decode_tree->quick_table_bits=table_bits;
+ }
+ else
+ {
+ (*decode_table)=end;
+ bit_buff->pos-= bit_buff->bits/8;
+ memcpy(*intervall_buff,bit_buff->pos,(size_t) intervall_length);
+ (*intervall_buff)+=intervall_length;
+ bit_buff->pos+=intervall_length;
+ bit_buff->bits=0;
+ }
+ return;
+}
+
+
+static void make_quick_table(uint16 *to_table, uint16 *decode_table, uint *next_free_offset, uint value, uint bits, uint max_bits)
+{
+ if (!bits--)
+ {
+ to_table[value]= (uint16) *next_free_offset;
+ *next_free_offset=copy_decode_table(to_table, *next_free_offset,
+ decode_table);
+ return;
+ }
+ if (!(*decode_table & IS_CHAR))
+ {
+ make_quick_table(to_table,decode_table+ *decode_table,
+ next_free_offset,value,bits,max_bits);
+ }
+ else
+ fill_quick_table(to_table+value,bits,max_bits,(uint) *decode_table);
+ decode_table++;
+ value|= (1 << bits);
+ if (!(*decode_table & IS_CHAR))
+ {
+ make_quick_table(to_table,decode_table+ *decode_table,
+ next_free_offset,value,bits,max_bits);
+ }
+ else
+ fill_quick_table(to_table+value,bits,max_bits,(uint) *decode_table);
+ return;
+}
+
+
+static void fill_quick_table(uint16 *table, uint bits, uint max_bits, uint value)
+{
+ uint16 *end;
+ value|=(max_bits-bits) << 8;
+ for (end=table+ (1 << bits) ;
+ table < end ;
+ *table++ = (uint16) value | IS_CHAR) ;
+}
+
+
+static uint copy_decode_table(uint16 *to_pos, uint offset, uint16 *decode_table)
+{
+ uint prev_offset;
+ prev_offset= offset;
+
+ if (!(*decode_table & IS_CHAR))
+ {
+ to_pos[offset]=2;
+ offset=copy_decode_table(to_pos,offset+2,decode_table+ *decode_table);
+ }
+ else
+ {
+ to_pos[offset]= *decode_table;
+ offset+=2;
+ }
+ decode_table++;
+
+ if (!(*decode_table & IS_CHAR))
+ {
+ to_pos[prev_offset+1]=(uint16) (offset-prev_offset-1);
+ offset=copy_decode_table(to_pos,offset,decode_table+ *decode_table);
+ }
+ else
+ to_pos[prev_offset+1]= *decode_table;
+ return offset;
+}
+
+
+static uint find_longest_bitstream(uint16 *table)
+{
+ uint length=1,length2;
+ if (!(*table & IS_CHAR))
+ length=find_longest_bitstream(table+ *table)+1;
+ table++;
+ if (!(*table & IS_CHAR))
+ {
+ length2=find_longest_bitstream(table+ *table)+1;
+ length=max(length,length2);
+ }
+ return length;
+}
+
+
+ /* Read record from datafile */
+ /* Returns length of packed record, -1 if error */
+
+int _nisam_read_pack_record(N_INFO *info, ulong filepos, byte *buf)
+{
+ BLOCK_INFO block_info;
+ File file;
+ DBUG_ENTER("_nisam_read_pack_record");
+
+ if (filepos == NI_POS_ERROR)
+ DBUG_RETURN(-1); /* _search() didn't find record */
+
+ file=info->dfile;
+ if (_nisam_pack_get_block_info(&block_info,info->s->pack.ref_length,file,
+ filepos))
+ goto err;
+ if (my_read(file,(byte*) info->rec_buff,block_info.rec_len,MYF(MY_NABP)))
+ goto panic;
+ info->update|= HA_STATE_AKTIV;
+ DBUG_RETURN(_nisam_pack_rec_unpack(info,buf,info->rec_buff,
+ block_info.rec_len));
+panic:
+ my_errno=HA_ERR_WRONG_IN_RECORD;
+err:
+ DBUG_RETURN(-1);
+}
+
+
+
+int _nisam_pack_rec_unpack(register N_INFO *info, register byte *to,
+ byte *from, uint reclength)
+{
+ byte *end_field;
+ reg3 N_RECINFO *end;
+ N_RECINFO *current_field;
+ ISAM_SHARE *share=info->s;
+ DBUG_ENTER("_nisam_pack_rec_unpack");
+
+ init_bit_buffer(&info->bit_buff,from,reclength);
+
+ for (current_field=share->rec, end=current_field+share->base.fields ;
+ current_field < end ;
+ current_field++,to=end_field)
+ {
+ end_field=to+current_field->base.length;
+ (*current_field->unpack)(current_field,&info->bit_buff,(uchar*) to,
+ (uchar*) end_field);
+ }
+ if (! info->bit_buff.error &&
+ info->bit_buff.pos - info->bit_buff.bits/8 == info->bit_buff.end)
+ DBUG_RETURN(0);
+ my_errno=HA_ERR_WRONG_IN_RECORD;
+ info->update&= ~HA_STATE_AKTIV;
+ DBUG_RETURN(-1);
+} /* _nisam_pack_rec_unpack */
+
+
+ /* Return function to unpack field */
+
+static void (*get_unpack_function(N_RECINFO *rec))(N_RECINFO *, BIT_BUFF *, uchar *, uchar *)
+{
+ switch (rec->base_type) {
+ case FIELD_SKIPP_ZERO:
+ if (rec->pack_type & PACK_TYPE_ZERO_FILL)
+ return &uf_zerofill_skipp_zero;
+ return &uf_skipp_zero;
+ case FIELD_NORMAL:
+ if (rec->pack_type & PACK_TYPE_SPACE_FIELDS)
+ return &uf_space_normal;
+ if (rec->pack_type & PACK_TYPE_ZERO_FILL)
+ return &uf_zerofill_normal;
+ return &decode_bytes;
+ case FIELD_SKIPP_ENDSPACE:
+ if (rec->pack_type & PACK_TYPE_SPACE_FIELDS)
+ {
+ if (rec->pack_type & PACK_TYPE_SELECTED)
+ return &uf_space_endspace_selected;
+ return &uf_space_endspace;
+ }
+ if (rec->pack_type & PACK_TYPE_SELECTED)
+ return &uf_endspace_selected;
+ return &uf_endspace;
+ case FIELD_SKIPP_PRESPACE:
+ if (rec->pack_type & PACK_TYPE_SPACE_FIELDS)
+ {
+ if (rec->pack_type & PACK_TYPE_SELECTED)
+ return &uf_space_prespace_selected;
+ return &uf_space_prespace;
+ }
+ if (rec->pack_type & PACK_TYPE_SELECTED)
+ return &uf_prespace_selected;
+ return &uf_prespace;
+ case FIELD_CONSTANT:
+ return &uf_constant;
+ case FIELD_INTERVALL:
+ return &uf_intervall;
+ case FIELD_ZERO:
+ return &uf_zero;
+ case FIELD_BLOB: /* Write this sometimes.. */
+ case FIELD_LAST:
+ default:
+ return 0; /* This should never happend */
+ }
+}
+
+ /* De different functions to unpack a field */
+
+static void uf_zerofill_skipp_zero(N_RECINFO *rec, BIT_BUFF *bit_buff, uchar *to, uchar *end)
+{
+ if (get_bit(bit_buff))
+ bzero((char*) to,(uint) (end-to));
+ else
+ {
+#ifdef WORDS_BIGENDIAN
+ bzero((char*) to,rec->space_length_bits);
+ decode_bytes(rec,bit_buff,to+rec->space_length_bits,end);
+#else
+ end-=rec->space_length_bits;
+ decode_bytes(rec,bit_buff,to,end);
+ bzero((byte*) end,rec->space_length_bits);
+#endif
+ }
+}
+
+static void uf_skipp_zero(N_RECINFO *rec, BIT_BUFF *bit_buff, uchar *to, uchar *end)
+{
+ if (get_bit(bit_buff))
+ bzero((char*) to,(uint) (end-to));
+ else
+ decode_bytes(rec,bit_buff,to,end);
+}
+
+static void uf_space_normal(N_RECINFO *rec, BIT_BUFF *bit_buff, uchar *to, uchar *end)
+{
+ if (get_bit(bit_buff))
+ bfill((byte*) to,(end-to),' ');
+ else
+ decode_bytes(rec,bit_buff,to,end);
+}
+
+static void uf_space_endspace_selected(N_RECINFO *rec, BIT_BUFF *bit_buff, uchar *to, uchar *end)
+{
+ uint spaces;
+ if (get_bit(bit_buff))
+ bfill((byte*) to,(end-to),' ');
+ else
+ {
+ if (get_bit(bit_buff))
+ {
+ if ((spaces=get_bits(bit_buff,rec->space_length_bits))+to > end)
+ {
+ bit_buff->error=1;
+ return;
+ }
+ if (to+spaces != end)
+ decode_bytes(rec,bit_buff,to,end-spaces);
+ bfill((byte*) end-spaces,spaces,' ');
+ }
+ else
+ decode_bytes(rec,bit_buff,to,end);
+ }
+}
+
+static void uf_endspace_selected(N_RECINFO *rec, BIT_BUFF *bit_buff, uchar *to, uchar *end)
+{
+ uint spaces;
+ if (get_bit(bit_buff))
+ {
+ if ((spaces=get_bits(bit_buff,rec->space_length_bits))+to > end)
+ {
+ bit_buff->error=1;
+ return;
+ }
+ if (to+spaces != end)
+ decode_bytes(rec,bit_buff,to,end-spaces);
+ bfill((byte*) end-spaces,spaces,' ');
+ }
+ else
+ decode_bytes(rec,bit_buff,to,end);
+}
+
+static void uf_space_endspace(N_RECINFO *rec, BIT_BUFF *bit_buff, uchar *to, uchar *end)
+{
+ uint spaces;
+ if (get_bit(bit_buff))
+ bfill((byte*) to,(end-to),' ');
+ else
+ {
+ if ((spaces=get_bits(bit_buff,rec->space_length_bits))+to > end)
+ {
+ bit_buff->error=1;
+ return;
+ }
+ if (to+spaces != end)
+ decode_bytes(rec,bit_buff,to,end-spaces);
+ bfill((byte*) end-spaces,spaces,' ');
+ }
+}
+
+static void uf_endspace(N_RECINFO *rec, BIT_BUFF *bit_buff, uchar *to,
+ uchar *end)
+{
+ uint spaces;
+ if ((spaces=get_bits(bit_buff,rec->space_length_bits))+to > end)
+ {
+ bit_buff->error=1;
+ return;
+ }
+ if (to+spaces != end)
+ decode_bytes(rec,bit_buff,to,end-spaces);
+ bfill((byte*) end-spaces,spaces,' ');
+}
+
+static void uf_space_prespace_selected(N_RECINFO *rec, BIT_BUFF *bit_buff, uchar *to, uchar *end)
+{
+ uint spaces;
+ if (get_bit(bit_buff))
+ bfill((byte*) to,(end-to),' ');
+ else
+ {
+ if (get_bit(bit_buff))
+ {
+ if ((spaces=get_bits(bit_buff,rec->space_length_bits))+to > end)
+ {
+ bit_buff->error=1;
+ return;
+ }
+ bfill((byte*) to,spaces,' ');
+ if (to+spaces != end)
+ decode_bytes(rec,bit_buff,to+spaces,end);
+ }
+ else
+ decode_bytes(rec,bit_buff,to,end);
+ }
+}
+
+
+static void uf_prespace_selected(N_RECINFO *rec, BIT_BUFF *bit_buff, uchar *to, uchar *end)
+{
+ uint spaces;
+ if (get_bit(bit_buff))
+ {
+ if ((spaces=get_bits(bit_buff,rec->space_length_bits))+to > end)
+ {
+ bit_buff->error=1;
+ return;
+ }
+ bfill((byte*) to,spaces,' ');
+ if (to+spaces != end)
+ decode_bytes(rec,bit_buff,to+spaces,end);
+ }
+ else
+ decode_bytes(rec,bit_buff,to,end);
+}
+
+
+static void uf_space_prespace(N_RECINFO *rec, BIT_BUFF *bit_buff, uchar *to, uchar *end)
+{
+ uint spaces;
+ if (get_bit(bit_buff))
+ bfill((byte*) to,(end-to),' ');
+ else
+ {
+ if ((spaces=get_bits(bit_buff,rec->space_length_bits))+to > end)
+ {
+ bit_buff->error=1;
+ return;
+ }
+ bfill((byte*) to,spaces,' ');
+ if (to+spaces != end)
+ decode_bytes(rec,bit_buff,to+spaces,end);
+ }
+}
+
+static void uf_prespace(N_RECINFO *rec, BIT_BUFF *bit_buff, uchar *to, uchar *end)
+{
+ uint spaces;
+ if ((spaces=get_bits(bit_buff,rec->space_length_bits))+to > end)
+ {
+ bit_buff->error=1;
+ return;
+ }
+ bfill((byte*) to,spaces,' ');
+ if (to+spaces != end)
+ decode_bytes(rec,bit_buff,to+spaces,end);
+}
+
+static void uf_zerofill_normal(N_RECINFO *rec, BIT_BUFF *bit_buff, uchar *to, uchar *end)
+{
+#ifdef WORDS_BIGENDIAN
+ bzero((char*) to,rec->space_length_bits);
+ decode_bytes(rec,bit_buff,(uchar*) to+rec->space_length_bits,end);
+#else
+ end-=rec->space_length_bits;
+ decode_bytes(rec,bit_buff,(uchar*) to,end);
+ bzero((byte*) end,rec->space_length_bits);
+#endif
+}
+
+static void uf_constant(N_RECINFO *rec,
+ BIT_BUFF *bit_buff __attribute__((unused)),
+ uchar *to, uchar *end)
+{
+ memcpy(to,rec->huff_tree->intervalls,(size_t) (end-to));
+}
+
+static void uf_intervall(N_RECINFO *rec, BIT_BUFF *bit_buff, uchar *to, uchar *end)
+{
+ reg1 uint field_length=(uint) (end-to);
+ memcpy(to,rec->huff_tree->intervalls+field_length*decode_pos(bit_buff,
+ rec->huff_tree),
+ (size_t) field_length);
+}
+
+
+/*ARGSUSED*/
+static void uf_zero(N_RECINFO *rec __attribute__((unused)),
+ BIT_BUFF *bit_buff __attribute__((unused)),
+ uchar *to, uchar *end)
+{
+ bzero((char*) to,(uint) (end-to));
+}
+
+
+ /* Functions to decode of buffer of bits */
+
+#if BITS_SAVED == 64
+
+static void decode_bytes(rec,bit_buff,to,end)
+N_RECINFO *rec;
+BIT_BUFF *bit_buff;
+uchar *to,*end;
+{
+ reg1 uint bits,low_byte;
+ reg3 uint16 *pos;
+ reg4 uint table_bits,table_and;
+ DECODE_TREE *decode_tree;
+
+ decode_tree=rec->decode_tree;
+ bits=bit_buff->bits; /* Save in reg for quicker access */
+ table_bits=decode_tree->quick_table_bits;
+ table_and= (1 << table_bits)-1;
+
+ do
+ {
+ if (bits <= 32)
+ {
+ if (bit_buff->pos > bit_buff->end+4)
+ return; /* Can't be right */
+ bit_buff->current_byte= (bit_buff->current_byte << 32) +
+ ((((uint) bit_buff->pos[3])) +
+ (((uint) bit_buff->pos[2]) << 8) +
+ (((uint) bit_buff->pos[1]) << 16) +
+ (((uint) bit_buff->pos[0]) << 24));
+ bit_buff->pos+=4;
+ bits+=32;
+ }
+ /* First use info in quick_table */
+ low_byte=(uint) (bit_buff->current_byte >> (bits - table_bits)) & table_and;
+ low_byte=decode_tree->table[low_byte];
+ if (low_byte & IS_CHAR)
+ {
+ *to++ = (low_byte & 255); /* Found char in quick table */
+ bits-= ((low_byte >> 8) & 31); /* Remove bits used */
+ }
+ else
+ { /* Map through rest of decode-table */
+ pos=decode_tree->table+low_byte;
+ bits-=table_bits;
+ for (;;)
+ {
+ low_byte=(uint) (bit_buff->current_byte >> (bits-8));
+ decode_bytes_test_bit(0);
+ decode_bytes_test_bit(1);
+ decode_bytes_test_bit(2);
+ decode_bytes_test_bit(3);
+ decode_bytes_test_bit(4);
+ decode_bytes_test_bit(5);
+ decode_bytes_test_bit(6);
+ decode_bytes_test_bit(7);
+ bits-=8;
+ }
+ *to++ = *pos;
+ }
+ } while (to != end);
+
+ bit_buff->bits=bits;
+ return;
+}
+
+#else
+
+static void decode_bytes(N_RECINFO *rec, BIT_BUFF *bit_buff, uchar *to, uchar *end)
+{
+ reg1 uint bits,low_byte;
+ reg3 uint16 *pos;
+ reg4 uint table_bits,table_and;
+ DECODE_TREE *decode_tree;
+
+ decode_tree=rec->huff_tree;
+ bits=bit_buff->bits; /* Save in reg for quicker access */
+ table_bits=decode_tree->quick_table_bits;
+ table_and= (1 << table_bits)-1;
+
+ do
+ {
+ if (bits < table_bits)
+ {
+ if (bit_buff->pos > bit_buff->end+1)
+ return; /* Can't be right */
+#if BITS_SAVED == 32
+ bit_buff->current_byte= (bit_buff->current_byte << 24) +
+ (((uint) ((uchar) bit_buff->pos[2]))) +
+ (((uint) ((uchar) bit_buff->pos[1])) << 8) +
+ (((uint) ((uchar) bit_buff->pos[0])) << 16);
+ bit_buff->pos+=3;
+ bits+=24;
+#else
+ if (bits) /* We must have at leasts 9 bits */
+ {
+ bit_buff->current_byte= (bit_buff->current_byte << 8) +
+ (uint) ((uchar) bit_buff->pos[0]);
+ bit_buff->pos++;
+ bits+=8;
+ }
+ else
+ {
+ bit_buff->current_byte= ((uint) ((uchar) bit_buff->pos[0]) << 8) +
+ ((uint) ((uchar) bit_buff->pos[1]));
+ bit_buff->pos+=2;
+ bits+=16;
+ }
+#endif
+ }
+ /* First use info in quick_table */
+ low_byte=(bit_buff->current_byte >> (bits - table_bits)) & table_and;
+ low_byte=decode_tree->table[low_byte];
+ if (low_byte & IS_CHAR)
+ {
+ *to++ = (low_byte & 255); /* Found char in quick table */
+ bits-= ((low_byte >> 8) & 31); /* Remove bits used */
+ }
+ else
+ { /* Map through rest of decode-table */
+ pos=decode_tree->table+low_byte;
+ bits-=table_bits;
+ for (;;)
+ {
+ if (bits < 8)
+ { /* We don't need to check end */
+#if BITS_SAVED == 32
+ bit_buff->current_byte= (bit_buff->current_byte << 24) +
+ (((uint) ((uchar) bit_buff->pos[2]))) +
+ (((uint) ((uchar) bit_buff->pos[1])) << 8) +
+ (((uint) ((uchar) bit_buff->pos[0])) << 16);
+ bit_buff->pos+=3;
+ bits+=24;
+#else
+ bit_buff->current_byte= (bit_buff->current_byte << 8) +
+ (uint) ((uchar) bit_buff->pos[0]);
+ bit_buff->pos+=1;
+ bits+=8;
+#endif
+ }
+ low_byte=(uint) (bit_buff->current_byte >> (bits-8));
+ decode_bytes_test_bit(0);
+ decode_bytes_test_bit(1);
+ decode_bytes_test_bit(2);
+ decode_bytes_test_bit(3);
+ decode_bytes_test_bit(4);
+ decode_bytes_test_bit(5);
+ decode_bytes_test_bit(6);
+ decode_bytes_test_bit(7);
+ bits-=8;
+ }
+ *to++ = (uchar) *pos;
+ }
+ } while (to != end);
+
+ bit_buff->bits=bits;
+ return;
+}
+#endif /* BIT_SAVED == 64 */
+
+
+static uint decode_pos(BIT_BUFF *bit_buff, DECODE_TREE *decode_tree)
+{
+ uint16 *pos=decode_tree->table;
+ for (;;)
+ {
+ if (get_bit(bit_buff))
+ pos++;
+ if (*pos & IS_CHAR)
+ return (uint) (*pos & ~IS_CHAR);
+ pos+= *pos;
+ }
+}
+
+
+int _nisam_read_rnd_pack_record(N_INFO *info, byte *buf,
+ register ulong filepos,
+ int skipp_deleted_blocks)
+{
+ uint b_type;
+ BLOCK_INFO block_info;
+ ISAM_SHARE *share=info->s;
+ DBUG_ENTER("_nisam_read_rnd_pack_record");
+
+ if (filepos >= share->state.data_file_length)
+ {
+ my_errno= HA_ERR_END_OF_FILE;
+ goto err;
+ }
+
+ if (info->opt_flag & READ_CACHE_USED)
+ {
+ if (_nisam_read_cache(&info->rec_cache,(byte*) block_info.header,filepos,
+ share->pack.ref_length, skipp_deleted_blocks))
+ goto err;
+ b_type=_nisam_pack_get_block_info(&block_info,share->pack.ref_length,-1,
+ filepos);
+ }
+ else
+ b_type=_nisam_pack_get_block_info(&block_info,share->pack.ref_length,
+ info->dfile,filepos);
+ if (b_type)
+ goto err;
+#ifndef DBUG_OFF
+ if (block_info.rec_len > share->max_pack_length)
+ {
+ my_errno=HA_ERR_WRONG_IN_RECORD;
+ goto err;
+ }
+#endif
+ if (info->opt_flag & READ_CACHE_USED)
+ {
+ if (_nisam_read_cache(&info->rec_cache,(byte*) info->rec_buff,
+ block_info.filepos, block_info.rec_len,
+ skipp_deleted_blocks))
+ goto err;
+ }
+ else
+ {
+ if (my_read(info->dfile,(byte*) info->rec_buff,block_info.rec_len,
+ MYF(MY_NABP)))
+ goto err;
+ }
+ info->packed_length=block_info.rec_len;
+ info->lastpos=filepos;
+ info->nextpos=block_info.filepos+block_info.rec_len;
+ info->update|= HA_STATE_AKTIV | HA_STATE_KEY_CHANGED;
+
+ DBUG_RETURN (_nisam_pack_rec_unpack(info,buf,info->rec_buff,
+ block_info.rec_len));
+err:
+ DBUG_RETURN(-1);
+}
+
+
+ /* Read and process header from a huff-record-file */
+
+uint _nisam_pack_get_block_info(BLOCK_INFO *info, uint ref_length, File file,
+ ulong filepos)
+{
+ uchar *header=info->header;
+
+ if (file >= 0)
+ {
+ VOID(my_seek(file,filepos,MY_SEEK_SET,MYF(0)));
+ if (my_read(file,(char*) header,ref_length,MYF(MY_NABP)))
+ return BLOCK_FATAL_ERROR;
+ }
+ DBUG_DUMP("header",(byte*) header,ref_length);
+
+ switch (ref_length) {
+ case 1:
+ info->rec_len=header[0];
+ info->filepos=filepos+1;
+ break;
+ case 2:
+ info->rec_len=uint2korr(header);
+ info->filepos=filepos+2;
+ break;
+ case 3:
+ info->rec_len=(uint) (uint3korr(header));
+ info->filepos=filepos+3;
+ break;
+ default: break;
+ }
+ return 0;
+}
+
+
+ /* routines for bit buffer */
+ /* Buffer must be 6 byte bigger */
+static void init_bit_buffer(BIT_BUFF *bit_buff, char *buffer, uint length)
+{
+ bit_buff->pos=(uchar*) buffer;
+ bit_buff->end=(uchar*) buffer+length;
+ bit_buff->bits=bit_buff->error=0;
+ bit_buff->current_byte=0; /* Avoid purify errors */
+}
+
+static uint fill_and_get_bits(BIT_BUFF *bit_buff, uint count)
+{
+ uint tmp;
+ count-=bit_buff->bits;
+ tmp=(bit_buff->current_byte & mask[bit_buff->bits]) << count;
+ fill_buffer(bit_buff);
+ bit_buff->bits=BITS_SAVED - count;
+ return tmp+(bit_buff->current_byte >> (BITS_SAVED - count));
+}
+
+ /* Fill in empty bit_buff->current_byte from buffer */
+ /* Sets bit_buff->error if buffer is exhausted */
+
+static void fill_buffer(BIT_BUFF *bit_buff)
+{
+ if (bit_buff->pos >= bit_buff->end)
+ {
+ bit_buff->error= 1;
+ bit_buff->current_byte=0;
+ return;
+ }
+#if BITS_SAVED == 64
+ bit_buff->current_byte= ((((uint) ((uchar) bit_buff->pos[7]))) +
+ (((uint) ((uchar) bit_buff->pos[6])) << 8) +
+ (((uint) ((uchar) bit_buff->pos[5])) << 16) +
+ (((uint) ((uchar) bit_buff->pos[4])) << 24) +
+ ((ulonglong)
+ ((((uint) ((uchar) bit_buff->pos[3]))) +
+ (((uint) ((uchar) bit_buff->pos[2])) << 8) +
+ (((uint) ((uchar) bit_buff->pos[1])) << 16) +
+ (((uint) ((uchar) bit_buff->pos[0])) << 24)) << 32));
+ bit_buff->pos+=8;
+#else
+#if BITS_SAVED == 32
+ bit_buff->current_byte= (((uint) ((uchar) bit_buff->pos[3])) +
+ (((uint) ((uchar) bit_buff->pos[2])) << 8) +
+ (((uint) ((uchar) bit_buff->pos[1])) << 16) +
+ (((uint) ((uchar) bit_buff->pos[0])) << 24));
+ bit_buff->pos+=4;
+#else
+ bit_buff->current_byte= (uint) (((uint) ((uchar) bit_buff->pos[1]))+
+ (((uint) ((uchar) bit_buff->pos[0])) << 8));
+ bit_buff->pos+=2;
+#endif
+#endif
+}
+
+ /* Get number of bits neaded to represent value */
+
+static uint max_bit(register uint value)
+{
+ reg2 uint power=1;
+
+ while ((value>>=1))
+ power++;
+ return (power);
+}
+
+
+/*****************************************************************************
+ Some redefined functions to handle files when we are using memmap
+*****************************************************************************/
+
+#ifdef HAVE_MMAP
+
+#include <sys/mman.h>
+
+static int _nisam_read_mempack_record(N_INFO *info,ulong filepos,byte *buf);
+static int _nisam_read_rnd_mempack_record(N_INFO*, byte *,ulong, int);
+
+#ifndef MAP_NORESERVE
+#define MAP_NORESERVE 0 /* For irix */
+#endif
+#ifndef MAP_FAILED
+#define MAP_FAILED -1
+#endif
+
+my_bool _nisam_memmap_file(N_INFO *info)
+{
+ byte *file_map;
+ ISAM_SHARE *share=info->s;
+ DBUG_ENTER("_nisam_memmap_file");
+
+ if (!info->s->file_map)
+ {
+ if (my_seek(info->dfile,0L,MY_SEEK_END,MYF(0)) <
+ share->state.data_file_length+MEMMAP_EXTRA_MARGIN)
+ {
+ DBUG_PRINT("warning",("File isn't extended for memmap"));
+ DBUG_RETURN(0);
+ }
+ file_map=(byte*)
+ mmap(0,share->state.data_file_length+MEMMAP_EXTRA_MARGIN,PROT_READ,
+ MAP_SHARED | MAP_NORESERVE,info->dfile,0L);
+ if (file_map == (byte*) MAP_FAILED)
+ {
+ DBUG_PRINT("warning",("mmap failed: errno: %d",errno));
+ my_errno=errno;
+ DBUG_RETURN(0);
+ }
+ info->s->file_map=file_map;
+ }
+ info->opt_flag|= MEMMAP_USED;
+ info->read_record=share->read_record=_nisam_read_mempack_record;
+ share->read_rnd=_nisam_read_rnd_mempack_record;
+ DBUG_RETURN(1);
+}
+
+
+void _nisam_unmap_file(N_INFO *info)
+{
+ if (info->s->file_map)
+ (void) munmap((caddr_t) info->s->file_map,
+ (size_t) info->s->state.data_file_length+
+ MEMMAP_EXTRA_MARGIN);
+}
+
+
+static void _nisam_mempack_get_block_info(BLOCK_INFO *info, uint ref_length,
+ uchar *header)
+{
+ if (ref_length == 1) /* This is most usual */
+ info->rec_len=header[0];
+ else if (ref_length == 2)
+ info->rec_len=uint2korr(header);
+ else
+ info->rec_len=(uint) (uint3korr(header));
+}
+
+
+static int _nisam_read_mempack_record(N_INFO *info, ulong filepos, byte *buf)
+{
+ BLOCK_INFO block_info;
+ ISAM_SHARE *share=info->s;
+ DBUG_ENTER("ni_read_mempack_record");
+
+ if (filepos == NI_POS_ERROR)
+ DBUG_RETURN(-1); /* _search() didn't find record */
+
+ _nisam_mempack_get_block_info(&block_info,share->pack.ref_length,
+ (uchar*) share->file_map+filepos);
+ DBUG_RETURN(_nisam_pack_rec_unpack(info,buf,share->file_map+
+ share->pack.ref_length+filepos,
+ block_info.rec_len));
+}
+
+
+/*ARGSUSED*/
+static int _nisam_read_rnd_mempack_record(N_INFO *info, byte *buf,
+ register ulong filepos,
+ int skipp_deleted_blocks
+ __attribute__((unused)))
+{
+ BLOCK_INFO block_info;
+ ISAM_SHARE *share=info->s;
+ DBUG_ENTER("_nisam_read_rnd_mempack_record");
+
+ if (filepos >= share->state.data_file_length)
+ {
+ my_errno=HA_ERR_END_OF_FILE;
+ goto err;
+ }
+
+ _nisam_mempack_get_block_info(&block_info,share->pack.ref_length,
+ (uchar*) share->file_map+filepos);
+#ifndef DBUG_OFF
+ if (block_info.rec_len > info->s->max_pack_length)
+ {
+ my_errno=HA_ERR_WRONG_IN_RECORD;
+ goto err;
+ }
+#endif
+ info->packed_length=block_info.rec_len;
+ info->lastpos=filepos;
+ info->nextpos=filepos+share->pack.ref_length+block_info.rec_len;
+ info->update|= HA_STATE_AKTIV | HA_STATE_KEY_CHANGED;
+
+ DBUG_RETURN (_nisam_pack_rec_unpack(info,buf,share->file_map+
+ share->pack.ref_length+filepos,
+ block_info.rec_len));
+err:
+ DBUG_RETURN(-1);
+}
+
+#endif /* HAVE_MMAP */
diff --git a/isam/_page.c b/isam/_page.c
new file mode 100644
index 00000000000..6f6d632e85d
--- /dev/null
+++ b/isam/_page.c
@@ -0,0 +1,137 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* L{ser och skriver nyckelblock */
+
+#include "isamdef.h"
+#ifdef __WIN__
+#include <errno.h>
+#endif
+
+ /* Fetch a key-page in memory */
+
+uchar *_nisam_fetch_keypage(register N_INFO *info, N_KEYDEF *keyinfo,
+ my_off_t page, uchar *buff, int return_buffer)
+{
+ uchar *tmp;
+ tmp=(uchar*) key_cache_read(info->s->kfile,page,(byte*) buff,
+ (uint) keyinfo->base.block_length,
+ (uint) keyinfo->base.block_length,
+ return_buffer);
+ if (tmp == info->buff)
+ {
+ info->update|=HA_STATE_BUFF_SAVED;
+ info->int_pos=(ulong) page;
+ info->buff_used=1;
+ }
+ else
+ {
+ info->update&= ~HA_STATE_BUFF_SAVED;
+ if (tmp)
+ info->int_pos=(ulong) page;
+ else
+ {
+ info->int_pos=NI_POS_ERROR;
+ DBUG_PRINT("error",("Got errno: %d from key_cache_read",my_errno));
+ my_errno=HA_ERR_CRASHED;
+ }
+ }
+ return tmp;
+} /* _nisam_fetch_keypage */
+
+
+ /* Write a key-page on disk */
+
+int _nisam_write_keypage(register N_INFO *info, register N_KEYDEF *keyinfo,
+ my_off_t page, uchar *buff)
+{
+ reg3 uint length;
+#ifndef QQ /* Safety check */
+ if (page < info->s->base.keystart ||
+ page+keyinfo->base.block_length > info->s->state.key_file_length ||
+ page & (nisam_block_size-1))
+ {
+ DBUG_PRINT("error",("Trying to write outside key region: %lu",
+ (long) page));
+ my_errno=EINVAL;
+ return(-1);
+ }
+ DBUG_PRINT("page",("write page at: %lu",(long) page,buff));
+ DBUG_DUMP("buff",(byte*) buff,getint(buff));
+#endif
+
+ if ((length=keyinfo->base.block_length) > IO_SIZE*2 &&
+ info->s->state.key_file_length != page+length)
+ length= ((getint(buff)+IO_SIZE-1) & (uint) ~(IO_SIZE-1));
+#ifdef HAVE_purify
+ {
+ length=getint(buff);
+ bzero((byte*) buff+length,keyinfo->base.block_length-length);
+ length=keyinfo->base.block_length;
+ }
+#endif
+ return (key_cache_write(info->s->kfile,page,(byte*) buff,length,
+ (uint) keyinfo->base.block_length,
+ (int) (info->lock_type != F_UNLCK)));
+} /* nisam_write_keypage */
+
+
+ /* Remove page from disk */
+
+int _nisam_dispose(register N_INFO *info, N_KEYDEF *keyinfo, my_off_t pos)
+{
+ uint keynr= (uint) (keyinfo - info->s->keyinfo);
+ ulong old_link; /* ulong is ok here */
+ DBUG_ENTER("_nisam_dispose");
+
+ old_link=info->s->state.key_del[keynr];
+ info->s->state.key_del[keynr]=(ulong) pos;
+ DBUG_RETURN(key_cache_write(info->s->kfile,pos,(byte*) &old_link,
+ sizeof(long),
+ (uint) keyinfo->base.block_length,
+ (int) (info->lock_type != F_UNLCK)));
+} /* _nisam_dispose */
+
+
+ /* Make new page on disk */
+
+ulong _nisam_new(register N_INFO *info, N_KEYDEF *keyinfo)
+{
+ uint keynr= (uint) (keyinfo - info->s->keyinfo);
+ ulong pos;
+ DBUG_ENTER("_nisam_new");
+
+ if ((pos=info->s->state.key_del[keynr]) == NI_POS_ERROR)
+ {
+ if (info->s->state.key_file_length >= info->s->base.max_key_file_length)
+ {
+ my_errno=HA_ERR_INDEX_FILE_FULL;
+ DBUG_RETURN(NI_POS_ERROR);
+ }
+ pos=info->s->state.key_file_length;
+ info->s->state.key_file_length+= keyinfo->base.block_length;
+ }
+ else
+ {
+ if (!key_cache_read(info->s->kfile,pos,
+ (byte*) &info->s->state.key_del[keynr],
+ (uint) sizeof(long),
+ (uint) keyinfo->base.block_length,0))
+ pos= NI_POS_ERROR;
+ }
+ DBUG_PRINT("exit",("Pos: %d",pos));
+ DBUG_RETURN(pos);
+} /* _nisam_new */
diff --git a/isam/_search.c b/isam/_search.c
new file mode 100644
index 00000000000..3c3f62c3a2a
--- /dev/null
+++ b/isam/_search.c
@@ -0,0 +1,889 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* S|ker efter positionen f|r en nyckel samt d{rmedh|rande funktioner */
+
+#include "isamdef.h"
+#include "m_ctype.h"
+
+#define CMP(a,b) (a<b ? -1 : a == b ? 0 : 1)
+
+ /* Check index */
+
+int _nisam_check_index(N_INFO *info, int inx)
+{
+ if (inx == -1) /* Use last index */
+ inx=info->lastinx;
+ if (inx >= (int) info->s->state.keys || inx < 0)
+ {
+ my_errno=HA_ERR_WRONG_INDEX;
+ return -1;
+ }
+ if (info->lastinx != inx) /* Index changed */
+ {
+ info->lastinx = inx;
+ info->lastpos = NI_POS_ERROR;
+ info->update= ((info->update & (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED)) |
+ HA_STATE_NEXT_FOUND | HA_STATE_PREV_FOUND);
+ }
+ if (info->opt_flag & WRITE_CACHE_USED && flush_io_cache(&info->rec_cache))
+ return(-1);
+ return(inx);
+} /* ni_check_index */
+
+
+ /* S|ker reda p} positionen f|r ett record p} basen av en nyckel */
+ /* Positionen l{ggs i info->lastpos */
+ /* Returns -1 if not found and 1 if search at upper levels */
+
+int _nisam_search(register N_INFO *info, register N_KEYDEF *keyinfo, uchar *key, uint key_len, uint nextflag, register ulong pos)
+{
+ int error,flag;
+ uint nod_flag;
+ uchar *keypos,*maxpos;
+ uchar lastkey[N_MAX_KEY_BUFF],*buff;
+ DBUG_ENTER("_nisam_search");
+ DBUG_PRINT("enter",("pos: %ld nextflag: %d lastpos: %ld",
+ pos,nextflag,info->lastpos));
+
+ if (pos == NI_POS_ERROR)
+ {
+ my_errno=HA_ERR_KEY_NOT_FOUND; /* Didn't find key */
+ info->lastpos= NI_POS_ERROR;
+ if (!(nextflag & (SEARCH_SMALLER | SEARCH_BIGGER | SEARCH_LAST)))
+ DBUG_RETURN(-1); /* Not found ; return error */
+ DBUG_RETURN(1); /* Search at upper levels */
+ }
+
+ if (!(buff=_nisam_fetch_keypage(info,keyinfo,pos,info->buff,
+ test(!(nextflag & SEARCH_SAVE_BUFF)))))
+ goto err;
+ DBUG_DUMP("page",(byte*) buff,getint(buff));
+
+ flag=(*keyinfo->bin_search)(info,keyinfo,buff,key,key_len,nextflag,
+ &keypos,lastkey);
+ nod_flag=test_if_nod(buff);
+ maxpos=buff+getint(buff)-1;
+
+ if (flag)
+ {
+ if ((error=_nisam_search(info,keyinfo,key,key_len,nextflag,
+ _nisam_kpos(nod_flag,keypos))) <= 0)
+ DBUG_RETURN(error);
+
+ if (flag >0)
+ {
+ if ((nextflag & (SEARCH_SMALLER | SEARCH_LAST)) &&
+ keypos == buff+2+nod_flag)
+ DBUG_RETURN(1); /* Bigger than key */
+ }
+ else if (nextflag & SEARCH_BIGGER && keypos >= maxpos)
+ DBUG_RETURN(1); /* Smaller than key */
+ }
+ else
+ {
+ if (nextflag & SEARCH_FIND && (!(keyinfo->base.flag & HA_NOSAME)
+ || key_len) && nod_flag)
+ {
+ if ((error=_nisam_search(info,keyinfo,key,key_len,SEARCH_FIND,
+ _nisam_kpos(nod_flag,keypos))) >= 0 ||
+ my_errno != HA_ERR_KEY_NOT_FOUND)
+ DBUG_RETURN(error);
+ info->int_pos= NI_POS_ERROR; /* Buffer not in memory */
+ }
+ }
+ if (pos != info->int_pos)
+ {
+ uchar *old_buff=buff;
+ if (!(buff=_nisam_fetch_keypage(info,keyinfo,pos,info->buff,
+ test(!(nextflag & SEARCH_SAVE_BUFF)))))
+ goto err;
+ keypos=buff+(keypos-old_buff);
+ maxpos=buff+(maxpos-old_buff);
+ }
+
+ if ((nextflag & (SEARCH_SMALLER | SEARCH_LAST)) && flag != 0)
+ {
+ keypos=_nisam_get_last_key(info,keyinfo,buff,lastkey,keypos);
+ if ((nextflag & SEARCH_LAST) &&
+ _nisam_key_cmp(keyinfo->seg, info->lastkey, key, key_len, SEARCH_FIND))
+ {
+ my_errno=HA_ERR_KEY_NOT_FOUND; /* Didn't find key */
+ goto err;
+ }
+ }
+
+ VOID((*keyinfo->get_key)(keyinfo,nod_flag,&keypos,lastkey));
+ VOID(_nisam_move_key(keyinfo,info->lastkey,lastkey));
+ info->lastpos=_nisam_dpos(info,nod_flag,keypos);
+ info->int_keypos=info->buff+ (keypos-buff);
+ info->int_maxpos=info->buff+ (maxpos-buff);
+ info->page_changed=0;
+ info->buff_used= (info->buff != buff);
+ info->last_search_keypage=info->int_pos;
+
+ DBUG_PRINT("exit",("found key at %ld",info->lastpos));
+ DBUG_RETURN(0);
+err:
+ DBUG_PRINT("exit",("Error: %d",my_errno));
+ info->lastpos= NI_POS_ERROR;
+ DBUG_RETURN (-1);
+} /* _nisam_search */
+
+
+ /* Search after key in page-block */
+ /* If packed key puts smaller or identical key in buff */
+ /* ret_pos point to where find or bigger key starts */
+ /* ARGSUSED */
+
+int _nisam_bin_search(N_INFO *info, register N_KEYDEF *keyinfo, uchar *page,
+ uchar *key, uint key_len, uint comp_flag, uchar **ret_pos,
+ uchar *buff __attribute__((unused)))
+{
+ reg4 int start,mid,end;
+ int flag;
+ uint totlength,nod_flag;
+ DBUG_ENTER("_nisam_bin_search");
+
+ LINT_INIT(flag);
+ totlength=keyinfo->base.keylength+(nod_flag=test_if_nod(page));
+ start=0; mid=1;
+ end= (int) ((getint(page)-2-nod_flag)/totlength-1);
+ DBUG_PRINT("test",("getint: %d end: %d",getint(page),end));
+ page+=2+nod_flag;
+
+ while (start != end)
+ {
+ mid= (start+end)/2;
+ if ((flag=_nisam_key_cmp(keyinfo->seg,page+(uint) mid*totlength,key,key_len,
+ comp_flag))
+ >= 0)
+ end=mid;
+ else
+ start=mid+1;
+ }
+ if (mid != start)
+ flag=_nisam_key_cmp(keyinfo->seg,page+(uint) start*totlength,key,key_len,
+ comp_flag);
+ if (flag < 0)
+ start++; /* point at next, bigger key */
+ *ret_pos=page+(uint) start*totlength;
+ DBUG_PRINT("exit",("flag: %d keypos: %d",flag,start));
+ DBUG_RETURN(flag);
+} /* _nisam_bin_search */
+
+
+ /* Used instead of _nisam_bin_search() when key is packed */
+ /* Puts smaller or identical key in buff */
+ /* Key is searched sequentially */
+
+int _nisam_seq_search(N_INFO *info, register N_KEYDEF *keyinfo, uchar *page, uchar *key, uint key_len, uint comp_flag, uchar **ret_pos, uchar *buff)
+{
+ int flag;
+ uint nod_flag,length;
+ uchar t_buff[N_MAX_KEY_BUFF],*end;
+ DBUG_ENTER("_nisam_seq_search");
+
+ LINT_INIT(flag); LINT_INIT(length);
+ end= page+getint(page);
+ nod_flag=test_if_nod(page);
+ page+=2+nod_flag;
+ *ret_pos=page;
+ while (page < end)
+ {
+ length=(*keyinfo->get_key)(keyinfo,nod_flag,&page,t_buff);
+ if ((flag=_nisam_key_cmp(keyinfo->seg,t_buff,key,key_len,comp_flag)) >= 0)
+ break;
+#ifdef EXTRA_DEBUG
+ DBUG_PRINT("loop",("page: %lx key: '%s' flag: %d",page,t_buff,flag));
+#endif
+ memcpy(buff,t_buff,length);
+ *ret_pos=page;
+ }
+ if (flag == 0)
+ memcpy(buff,t_buff,length); /* Result is first key */
+ DBUG_PRINT("exit",("flag: %d ret_pos: %lx",flag,*ret_pos));
+ DBUG_RETURN(flag);
+} /* _nisam_seq_search */
+
+
+ /* Get pos to a key_block */
+
+ulong _nisam_kpos(uint nod_flag, uchar *after_key)
+{
+ after_key-=nod_flag;
+ switch (nod_flag) {
+ case 3:
+ return uint3korr(after_key)*512L;
+ case 2:
+ return uint2korr(after_key)*512L;
+ case 1:
+ return (uint) (*after_key)*512L;
+ case 0: /* At leaf page */
+ default: /* Impossible */
+ return(NI_POS_ERROR);
+ }
+} /* _kpos */
+
+
+ /* Save pos to a key_block */
+
+void _nisam_kpointer(register N_INFO *info, register uchar *buff, ulong pos)
+{
+ pos/=512L;
+ switch (info->s->base.key_reflength) {
+ case 3: int3store(buff,pos); break;
+ case 2: int2store(buff,(uint) pos); break;
+ case 1: buff[0]= (uchar) pos; break;
+ default: abort(); /* impossible */
+ }
+} /* _nisam_kpointer */
+
+
+ /* Calc pos to a data-record */
+
+ulong _nisam_dpos(N_INFO *info, uint nod_flag, uchar *after_key)
+{
+ ulong pos;
+ after_key-=(nod_flag + info->s->rec_reflength);
+ switch (info->s->rec_reflength) {
+ case 4:
+ pos= (ulong) uint4korr(after_key);
+ break;
+ case 3:
+ pos= (ulong) uint3korr(after_key);
+ break;
+ case 2:
+ pos= (ulong) uint2korr(after_key);
+ break;
+ default:
+ pos=0L; /* Shut compiler up */
+ }
+ return (info->s->base.options &
+ (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)) ? pos :
+ pos*info->s->base.reclength;
+}
+
+ /* save pos to record */
+
+void _nisam_dpointer(N_INFO *info, uchar *buff, ulong pos)
+{
+ if (!(info->s->base.options &
+ (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)))
+ pos/=info->s->base.reclength;
+
+ switch (info->s->rec_reflength) {
+ case 4: int4store(buff,pos); break;
+ case 3: int3store(buff,pos); break;
+ case 2: int2store(buff,(uint) pos); break;
+ default: abort(); /* Impossible */
+ }
+} /* _nisam_dpointer */
+
+
+ /*
+ ** Compare two keys with is bigger
+ ** Returns <0, 0, >0 acording to with is bigger
+ ** Key_length specifies length of key to use. Number-keys can't
+ ** be splitted
+ ** If flag <> SEARCH_FIND compare also position
+ */
+int _nisam_key_cmp(register N_KEYSEG *keyseg, register uchar *a, register uchar *b, uint key_length, uint nextflag)
+{
+ reg4 int flag,length_diff;
+ int16 s_1,s_2;
+ int32 l_1,l_2;
+ uint32 u_1,u_2;
+ float f_1,f_2;
+ double d_1,d_2;
+ reg5 uchar *end;
+
+ if (!(nextflag & (SEARCH_FIND | SEARCH_NO_FIND | SEARCH_LAST))
+ || key_length == 0)
+ key_length=N_MAX_KEY_BUFF*2;
+
+ for ( ; (int) key_length >0 ; key_length-= (keyseg++)->base.length)
+ {
+ end= a+ min(keyseg->base.length,key_length);
+ switch ((enum ha_base_keytype) keyseg->base.type) {
+ case HA_KEYTYPE_TEXT: /* Ascii; Key is converted */
+ case HA_KEYTYPE_BINARY:
+ if (keyseg->base.flag & HA_SPACE_PACK)
+ {
+ uchar *as, *bs;
+ int length,b_length;
+
+ as=a++; bs=b++;
+ length= (length_diff= ((int) *as - (b_length= (int) *bs))) < 0 ?
+ (int) *as : b_length;
+ end= a+ min(key_length,(uint) length);
+
+#ifdef USE_STRCOLL
+ if (use_strcoll(default_charset_info)) {
+ if (((enum ha_base_keytype) keyseg->base.type) == HA_KEYTYPE_BINARY)
+ {
+ while (a < end)
+ if ((flag= (int) *a++ - (int) *b++))
+ return ((keyseg->base.flag & HA_REVERSE_SORT) ? -flag : flag);
+ }
+ else
+ {
+ if ((flag = my_strnncoll(default_charset_info,
+ a, (end-a), b, b_length)))
+ return (keyseg->base.flag & HA_REVERSE_SORT) ? -flag : flag;
+ b+= (uint) (end-a);
+ a=end;
+ }
+ }
+ else
+#endif
+ {
+ while (a < end)
+ if ((flag= (int) *a++ - (int) *b++))
+ return ((keyseg->base.flag & HA_REVERSE_SORT) ? -flag : flag);
+ }
+ if (key_length < (uint) keyseg->base.length)
+ { /* key_part */
+ if (length_diff)
+ {
+ if (length_diff < 0 || (uint) *as <= key_length)
+ return ((keyseg->base.flag & HA_REVERSE_SORT) ?
+ -length_diff : length_diff);
+ for (length= (int) key_length-b_length; length-- > 0 ;)
+ {
+ if (*a++ != ' ')
+ return ((keyseg->base.flag & HA_REVERSE_SORT) ? -1 : 1);
+ }
+ }
+ if (nextflag & SEARCH_NO_FIND) /* Find record after key */
+ return (nextflag & SEARCH_BIGGER) ? -1 : 1;
+ return 0;
+ }
+ else
+ {
+ if (length_diff)
+ return ((keyseg->base.flag & HA_REVERSE_SORT) ?
+ -length_diff : length_diff);
+ }
+ a=as+ (uint) *as+1 ; b= bs+ b_length+1; /* to next key */
+ }
+ else
+ {
+#ifdef USE_STRCOLL
+ if (use_strcoll(default_charset_info)) {
+ if (((enum ha_base_keytype) keyseg->base.type) == HA_KEYTYPE_BINARY)
+ {
+ while (a < end)
+ if ((flag= (int) *a++ - (int) *b++))
+ return ((keyseg->base.flag & HA_REVERSE_SORT) ? -flag : flag);
+ }
+ else
+ {
+ if ((flag = my_strnncoll(default_charset_info,
+ a, (end-a), b, (end-a))))
+ return (keyseg->base.flag & HA_REVERSE_SORT) ? -flag : flag;
+ b+= (uint) (end-a);
+ a=end;
+ }
+ }
+ else
+#endif
+ {
+ while (a < end)
+ if ((flag= (int) *a++ - (int) *b++))
+ return ((keyseg->base.flag & HA_REVERSE_SORT) ? -flag : flag);
+ }
+ }
+ break;
+ case HA_KEYTYPE_INT8:
+ {
+ int i_1= (int) *((signed char*) a);
+ int i_2= (int) *((signed char*) b);
+ if ((flag = CMP(i_1,i_2)))
+ return ((keyseg->base.flag & HA_REVERSE_SORT) ? -flag : flag);
+ a= end;
+ b++;
+ break;
+ }
+ case HA_KEYTYPE_SHORT_INT:
+ shortget(s_1,a);
+ shortget(s_2,b);
+ if ((flag = CMP(s_1,s_2)))
+ return ((keyseg->base.flag & HA_REVERSE_SORT) ? -flag : flag);
+ a= end;
+ b+= 2; /* sizeof(short int); */
+ break;
+ case HA_KEYTYPE_USHORT_INT:
+ {
+ uint16 us_1,us_2;
+ ushortget(us_1,a);
+ ushortget(us_2,b);
+ if ((flag = CMP(us_1,us_2)))
+ return ((keyseg->base.flag & HA_REVERSE_SORT) ? -flag : flag);
+ a= end;
+ b+=2; /* sizeof(short int); */
+ break;
+ }
+ case HA_KEYTYPE_LONG_INT:
+ longget(l_1,a);
+ longget(l_2,b);
+ if ((flag = CMP(l_1,l_2)))
+ return ((keyseg->base.flag & HA_REVERSE_SORT) ? -flag : flag);
+ a= end;
+ b+= 4; /* sizeof(long int); */
+ break;
+ case HA_KEYTYPE_ULONG_INT:
+ ulongget(u_1,a);
+ ulongget(u_2,b);
+ if ((flag = CMP(u_1,u_2)))
+ return ((keyseg->base.flag & HA_REVERSE_SORT) ? -flag : flag);
+ a= end;
+ b+= 4; /* sizeof(long int); */
+ break;
+ case HA_KEYTYPE_INT24:
+ l_1=sint3korr(a);
+ l_2=sint3korr(b);
+ if ((flag = CMP(l_1,l_2)))
+ return ((keyseg->base.flag & HA_REVERSE_SORT) ? -flag : flag);
+ a= end;
+ b+= 3;
+ break;
+ case HA_KEYTYPE_UINT24:
+ l_1=(long) uint3korr(a);
+ l_2=(long) uint3korr(b);
+ if ((flag = CMP(l_1,l_2)))
+ return ((keyseg->base.flag & HA_REVERSE_SORT) ? -flag : flag);
+ a= end;
+ b+= 3;
+ break;
+ case HA_KEYTYPE_FLOAT:
+ bmove((byte*) &f_1,(byte*) a,(int) sizeof(float));
+ bmove((byte*) &f_2,(byte*) b,(int) sizeof(float));
+ if ((flag = CMP(f_1,f_2)))
+ return ((keyseg->base.flag & HA_REVERSE_SORT) ? -flag : flag);
+ a= end;
+ b+= sizeof(float);
+ break;
+ case HA_KEYTYPE_DOUBLE:
+ doubleget(d_1,a);
+ doubleget(d_2,b);
+ if ((flag = CMP(d_1,d_2)))
+ return ((keyseg->base.flag & HA_REVERSE_SORT) ? -flag : flag);
+ a= end;
+ b+= sizeof(double);
+ break;
+ case HA_KEYTYPE_NUM: /* Numeric key */
+ {
+ int swap_flag=keyseg->base.flag & HA_REVERSE_SORT;
+ if (keyseg->base.flag & HA_SPACE_PACK)
+ {
+ int alength,blength;
+
+ if (swap_flag)
+ swap(uchar*,a,b);
+ alength= *a++; blength= *b++;
+ if ((flag=(int) (keyseg->base.length-key_length)) < 0)
+ flag=0;
+ if (alength != blength+flag)
+ {
+ if ((alength > blength+flag && *a != '-') ||
+ (alength < blength+flag && *b == '-'))
+ return 1;
+ else
+ return -1;
+ }
+ if (*a == '-' && *b == '-')
+ {
+ swap_flag=1;
+ swap(uchar*,a,b);
+ }
+ end=a+alength;
+ while (a < end)
+ if (*a++ != *b++)
+ {
+ a--; b--;
+ if (isdigit((char) *a) && isdigit((char) *b))
+ return ((int) *a - (int) *b);
+ if (*a == '-' || isdigit((char) *b))
+ return (-1);
+ if (*b == '-' || *b++ == ' ' || isdigit((char) *a))
+ return (1);
+ if (*a++ == ' ')
+ return (-1);
+ }
+ }
+ else
+ {
+ for ( ; a < end && *a == ' ' && *b == ' ' ; a++, b++) ;
+ if (*a == '-' && *b == '-')
+ swap_flag=1;
+ if (swap_flag)
+ {
+ end=b+(int) (end-a);
+ swap(uchar*,a,b);
+ }
+ while (a < end)
+ if (*a++ != *b++)
+ {
+ a--; b--;
+ if (isdigit((char) *a) && isdigit((char) *b))
+ return ((int) *a - (int) *b);
+ if (*a == '-' || isdigit((char) *b))
+ return (-1);
+ if (*b == '-' || *b++ == ' ' || isdigit((char) *a))
+ return (1);
+ if (*a++ == ' ')
+ return -1;
+ }
+ }
+ if (swap_flag)
+ swap(uchar*,a,b);
+ break;
+ }
+#ifdef HAVE_LONG_LONG
+ case HA_KEYTYPE_LONGLONG:
+ {
+ longlong ll_a,ll_b;
+ longlongget(ll_a,a);
+ longlongget(ll_b,b);
+ if ((flag = CMP(ll_a,ll_b)))
+ return ((keyseg->base.flag & HA_REVERSE_SORT) ? -flag : flag);
+ a= end;
+ b+= sizeof(longlong);
+ break;
+ }
+ case HA_KEYTYPE_ULONGLONG:
+ {
+ ulonglong ll_a,ll_b;
+ longlongget(ll_a,a);
+ longlongget(ll_b,b);
+ if ((flag = CMP(ll_a,ll_b)))
+ return ((keyseg->base.flag & HA_REVERSE_SORT) ? -flag : flag);
+ a= end;
+ b+= sizeof(ulonglong);
+ break;
+ }
+#endif
+ case HA_KEYTYPE_END: /* Ready */
+ case HA_KEYTYPE_VARTEXT: /* Impossible */
+ case HA_KEYTYPE_VARBINARY: /* Impossible */
+ goto end;
+ }
+ }
+end:
+ if (!(nextflag & SEARCH_FIND))
+ {
+ if (nextflag & (SEARCH_NO_FIND | SEARCH_LAST)) /* Find record after key */
+ return (nextflag & (SEARCH_BIGGER | SEARCH_LAST)) ? -1 : 1;
+ LINT_INIT(l_1); LINT_INIT(l_2);
+ switch (keyseg->base.length) {
+ case 4:
+ u_1= (ulong) uint4korr(a);
+ u_2= (ulong) uint4korr(b);
+ break;
+ case 3:
+ u_1= (ulong) uint3korr(a);
+ u_2= (ulong) uint3korr(b);
+ break;
+ case 2:
+ u_1= (ulong) uint2korr(a);
+ u_2= (ulong) uint2korr(b);
+ break;
+ default: abort(); /* Impossible */
+ }
+ flag = CMP(u_1,u_2);
+
+ if (nextflag & SEARCH_SAME)
+ return (flag); /* read same */
+ if (nextflag & SEARCH_BIGGER)
+ return (flag <= 0 ? -1 : 1); /* read next */
+ return (flag < 0 ? -1 : 1); /* read previous */
+ }
+ return 0;
+} /* _nisam_key_cmp */
+
+
+ /* Get key from key-block */
+ /* page points at previous key; its advanced to point at next key */
+ /* key should contain previous key */
+ /* Returns length of found key + pointers */
+ /* nod_flag is a flag if we are on nod */
+
+uint _nisam_get_key(register N_KEYDEF *keyinfo, uint nod_flag,
+ register uchar **page, register uchar *key)
+{
+ reg1 N_KEYSEG *keyseg;
+ uchar *start,*start_key;
+ uint length,c_length;
+
+ LINT_INIT(start);
+ start_key=key; c_length=0;
+ for (keyseg=keyinfo->seg ; keyseg->base.type ;keyseg++)
+ {
+ if (keyseg->base.flag & (HA_SPACE_PACK | HA_PACK_KEY))
+ {
+ start=key;
+ if (keyseg->base.flag & HA_SPACE_PACK)
+ key++;
+ if ((length= *(*page)++) & 128)
+ {
+ key+= (c_length=(length & 127));
+ if (c_length == 0) /* Same key */
+ {
+ key+= *start; /* Same diff_key as prev */
+ length=0;
+ }
+ else
+ {
+ if (keyseg->base.flag & HA_SPACE_PACK)
+ length= *(*page)++;
+ else
+ length=keyseg->base.length-length+128; /* Rest of key */
+ /* Prevent core dumps if wrong data formats */
+ if (length > keyseg->base.length)
+ length=0;
+ }
+ }
+ }
+ else
+ length=keyseg->base.length;
+ memcpy((byte*) key,(byte*) *page,(size_t) length); key+=length;
+ if (keyseg->base.flag & HA_SPACE_PACK)
+ *start= (uchar) ((key-start)-1);
+ *page+=length;
+ }
+ length=keyseg->base.length+nod_flag;
+ bmove((byte*) key,(byte*) *page,length);
+ *page+=length;
+ return((uint) (key-start_key)+keyseg->base.length);
+} /* _nisam_get_key */
+
+
+ /* same as _nisam_get_key but used with fixed length keys */
+
+uint _nisam_get_static_key(register N_KEYDEF *keyinfo, uint nod_flag, register uchar **page, register uchar *key)
+{
+ memcpy((byte*) key,(byte*) *page,
+ (size_t) (keyinfo->base.keylength+nod_flag));
+ *page+=keyinfo->base.keylength+nod_flag;
+ return(keyinfo->base.keylength);
+} /* _nisam_get_static_key */
+
+
+ /* Get last key from key-block, starting from keypos */
+ /* Return pointer to where keystarts */
+
+uchar *_nisam_get_last_key(N_INFO *info, N_KEYDEF *keyinfo, uchar *keypos, uchar *lastkey, uchar *endpos)
+{
+ uint nod_flag;
+ uchar *lastpos;
+
+ nod_flag=test_if_nod(keypos);
+ if (! (keyinfo->base.flag & (HA_PACK_KEY | HA_SPACE_PACK_USED)))
+ {
+ lastpos=endpos-keyinfo->base.keylength-nod_flag;
+ if (lastpos > keypos)
+ bmove((byte*) lastkey,(byte*) lastpos,keyinfo->base.keylength+nod_flag);
+ }
+ else
+ {
+ lastpos=0 ; keypos+=2+nod_flag;
+ lastkey[0]=0;
+ while (keypos < endpos)
+ {
+ lastpos=keypos;
+ VOID(_nisam_get_key(keyinfo,nod_flag,&keypos,lastkey));
+ }
+ }
+ return lastpos;
+} /* _nisam_get_last_key */
+
+
+ /* Calculate length of key */
+
+uint _nisam_keylength(N_KEYDEF *keyinfo, register uchar *key)
+{
+ reg1 N_KEYSEG *keyseg;
+ uchar *start;
+
+ if (! (keyinfo->base.flag & HA_SPACE_PACK_USED))
+ return (keyinfo->base.keylength);
+
+ start=key;
+ for (keyseg=keyinfo->seg ; keyseg->base.type ; keyseg++)
+ {
+ if (keyseg->base.flag & HA_SPACE_PACK)
+ key+= *key+1;
+ else
+ key+= keyseg->base.length;
+ }
+ return((uint) (key-start)+keyseg->base.length);
+} /* _nisam_keylength */
+
+
+ /* Move a key */
+
+uchar *_nisam_move_key(N_KEYDEF *keyinfo, uchar *to, uchar *from)
+{
+ reg1 uint length;
+ memcpy((byte*) to, (byte*) from,
+ (size_t) (length=_nisam_keylength(keyinfo,from)));
+ return to+length;
+}
+
+ /* Find next/previous record with same key */
+ /* This can't be used when database is touched after last read */
+
+int _nisam_search_next(register N_INFO *info, register N_KEYDEF *keyinfo,
+ uchar *key, uint nextflag, ulong pos)
+{
+ int error;
+ uint nod_flag;
+ uchar lastkey[N_MAX_KEY_BUFF];
+ DBUG_ENTER("_nisam_search_next");
+ DBUG_PRINT("enter",("nextflag: %d lastpos: %d int_keypos: %lx",
+ nextflag,info->lastpos,info->int_keypos));
+ DBUG_EXECUTE("key",_nisam_print_key(DBUG_FILE,keyinfo->seg,key););
+
+ if ((nextflag & SEARCH_BIGGER && info->int_keypos >= info->int_maxpos) ||
+ info->int_pos == NI_POS_ERROR || info->page_changed)
+ DBUG_RETURN(_nisam_search(info,keyinfo,key,0,nextflag | SEARCH_SAVE_BUFF,
+ pos));
+
+ if (info->buff_used)
+ {
+ if (!_nisam_fetch_keypage(info,keyinfo,info->last_search_keypage,
+ info->buff,0))
+ {
+ info->lastpos= NI_POS_ERROR;
+ DBUG_RETURN(-1);
+ }
+ info->buff_used=0;
+ }
+
+ /* Last used buffer is in info->buff */
+
+ nod_flag=test_if_nod(info->buff);
+ VOID(_nisam_move_key(keyinfo,lastkey,key));
+
+ if (nextflag & SEARCH_BIGGER) /* Next key */
+ {
+ ulong tmp_pos=_nisam_kpos(nod_flag,info->int_keypos);
+ if (tmp_pos != NI_POS_ERROR)
+ {
+ if ((error=_nisam_search(info,keyinfo,key,0,nextflag | SEARCH_SAVE_BUFF,
+ tmp_pos)) <=0)
+ DBUG_RETURN(error);
+ }
+ VOID((*keyinfo->get_key)(keyinfo,nod_flag,&info->int_keypos,lastkey));
+ }
+ else /* Previous key */
+ {
+ info->int_keypos=_nisam_get_last_key(info,keyinfo,info->buff,lastkey,
+ info->int_keypos);
+ if (info->int_keypos == info->buff+2)
+ DBUG_RETURN(_nisam_search(info,keyinfo,key,0,nextflag | SEARCH_SAVE_BUFF,
+ pos));
+ if ((error=_nisam_search(info,keyinfo,key,0,nextflag | SEARCH_SAVE_BUFF,
+ _nisam_kpos(nod_flag,info->int_keypos))) <= 0)
+ DBUG_RETURN(error);
+ }
+
+ info->int_keypos=_nisam_get_last_key(info,keyinfo,info->buff,lastkey,
+ info->int_keypos);
+ VOID(_nisam_move_key(keyinfo,info->lastkey,lastkey));
+ VOID((*keyinfo->get_key)(keyinfo,nod_flag,&info->int_keypos,info->lastkey));
+ info->lastpos=_nisam_dpos(info,nod_flag,info->int_keypos);
+ DBUG_PRINT("exit",("found key at %d",info->lastpos));
+ DBUG_RETURN(0);
+} /* _nisam_search_next */
+
+
+ /* S|ker reda p} positionen f|r f|rsta recordet i ett index */
+ /* Positionen l{ggs i info->lastpos */
+
+int _nisam_search_first(register N_INFO *info, register N_KEYDEF *keyinfo, register ulong pos)
+{
+ uint nod_flag;
+ uchar *page;
+ DBUG_ENTER("_nisam_search_first");
+
+ if (pos == NI_POS_ERROR)
+ {
+ my_errno=HA_ERR_KEY_NOT_FOUND;
+ info->lastpos= NI_POS_ERROR;
+ DBUG_RETURN(-1);
+ }
+
+ do
+ {
+ if (!_nisam_fetch_keypage(info,keyinfo,pos,info->buff,0))
+ {
+ info->lastpos= NI_POS_ERROR;
+ DBUG_RETURN(-1);
+ }
+ nod_flag=test_if_nod(info->buff);
+ page=info->buff+2+nod_flag;
+ } while ((pos=_nisam_kpos(nod_flag,page)) != NI_POS_ERROR);
+
+ VOID((*keyinfo->get_key)(keyinfo,nod_flag,&page,info->lastkey));
+ info->int_keypos=page; info->int_maxpos=info->buff+getint(info->buff)-1;
+ info->lastpos=_nisam_dpos(info,nod_flag,page);
+ info->page_changed=info->buff_used=0;
+ info->last_search_keypage=info->int_pos;
+
+ DBUG_PRINT("exit",("found key at %d",info->lastpos));
+ DBUG_RETURN(0);
+} /* _nisam_search_first */
+
+
+ /* S|ker reda p} positionen f|r sista recordet i ett index */
+ /* Positionen l{ggs i info->lastpos */
+
+int _nisam_search_last(register N_INFO *info, register N_KEYDEF *keyinfo, register ulong pos)
+{
+ uint nod_flag;
+ uchar *buff,*page;
+ DBUG_ENTER("_nisam_search_last");
+
+ if (pos == NI_POS_ERROR)
+ {
+ my_errno=HA_ERR_KEY_NOT_FOUND; /* Didn't find key */
+ info->lastpos= NI_POS_ERROR;
+ DBUG_RETURN(-1);
+ }
+
+ buff=info->buff;
+ do
+ {
+ if (!_nisam_fetch_keypage(info,keyinfo,pos,buff,0))
+ {
+ info->lastpos= NI_POS_ERROR;
+ DBUG_RETURN(-1);
+ }
+ page= buff+getint(buff);
+ nod_flag=test_if_nod(buff);
+ } while ((pos=_nisam_kpos(nod_flag,page)) != NI_POS_ERROR);
+
+ VOID(_nisam_get_last_key(info,keyinfo,buff,info->lastkey,page));
+ info->lastpos=_nisam_dpos(info,nod_flag,page);
+ info->int_keypos=info->int_maxpos=page;
+ info->page_changed=info->buff_used=0;
+ info->last_search_keypage=info->int_pos;
+
+ DBUG_PRINT("exit",("found key at %d",info->lastpos));
+ DBUG_RETURN(0);
+} /* _nisam_search_last */
diff --git a/isam/_statrec.c b/isam/_statrec.c
new file mode 100644
index 00000000000..d93f4fe27f5
--- /dev/null
+++ b/isam/_statrec.c
@@ -0,0 +1,265 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+ /* Functions to handle fixed-length-records */
+
+#include "isamdef.h"
+
+
+int _nisam_write_static_record(N_INFO *info, const byte *record)
+{
+ uchar temp[4]; /* Not sizeof(long) */
+
+ if (info->s->state.dellink != NI_POS_ERROR)
+ {
+ ulong filepos=info->s->state.dellink;
+ info->rec_cache.seek_not_done=1; /* We have done a seek */
+ VOID(my_seek(info->dfile,info->s->state.dellink+1,MY_SEEK_SET,MYF(0)));
+
+ if (my_read(info->dfile,(char*) &temp[0],sizeof(temp), MYF(MY_NABP)))
+ goto err;
+ info->s->state.dellink=uint4korr(temp);
+ if (info->s->state.dellink == (uint32) ~0) /* Fix for 64 bit long */
+ info->s->state.dellink=NI_POS_ERROR;
+ info->s->state.del--;
+ info->s->state.empty-=info->s->base.reclength;
+ VOID(my_seek(info->dfile,filepos,MY_SEEK_SET,MYF(0)));
+ if (my_write(info->dfile, (char*) record, info->s->base.reclength,
+ MYF(MY_NABP)))
+ goto err;
+ }
+ else
+ {
+ if (info->s->state.data_file_length > info->s->base.max_data_file_length)
+ {
+ my_errno=HA_ERR_RECORD_FILE_FULL;
+ return(2);
+ }
+ if (info->opt_flag & WRITE_CACHE_USED)
+ { /* Cash in use */
+ if (my_b_write(&info->rec_cache, (byte*) record, info->s->base.reclength))
+ goto err;
+ }
+ else
+ {
+ info->rec_cache.seek_not_done=1; /* We have done a seek */
+ VOID(my_seek(info->dfile,info->s->state.data_file_length,
+ MY_SEEK_SET,MYF(0)));
+ if (my_write(info->dfile,(char*) record,info->s->base.reclength,
+ MYF(MY_NABP | MY_WAIT_IF_FULL)))
+ goto err;
+ }
+ info->s->state.data_file_length+=info->s->base.reclength;
+ info->s->state.splitt++;
+ }
+ return 0;
+ err:
+ return 1;
+}
+
+int _nisam_update_static_record(N_INFO *info, ulong pos, const byte *record)
+{
+ info->rec_cache.seek_not_done=1; /* We have done a seek */
+ VOID(my_seek(info->dfile,pos,MY_SEEK_SET,MYF(0)));
+ return (my_write(info->dfile,(char*) record,info->s->base.reclength,
+ MYF(MY_NABP)) != 0);
+}
+
+
+int _nisam_delete_static_record(N_INFO *info)
+{
+ uchar temp[5]; /* 1+sizeof(uint32) */
+
+ info->s->state.del++;
+ info->s->state.empty+=info->s->base.reclength;
+ temp[0]= '\0'; /* Mark that record is deleted */
+ int4store(temp+1,info->s->state.dellink);
+ info->s->state.dellink = info->lastpos;
+ info->rec_cache.seek_not_done=1;
+ VOID(my_seek(info->dfile,info->lastpos,MY_SEEK_SET,MYF(0)));
+ return (my_write(info->dfile,(byte*) temp,(uint) sizeof(temp),
+ MYF(MY_NABP)) != 0);
+}
+
+
+int _nisam_cmp_static_record(register N_INFO *info, register const byte *old)
+{
+ DBUG_ENTER("_nisam_rectest");
+
+ /* We are going to do changes; dont let anybody disturb */
+ dont_break(); /* Dont allow SIGHUP or SIGINT */
+
+ if (info->opt_flag & WRITE_CACHE_USED)
+ {
+ if (flush_io_cache(&info->rec_cache))
+ {
+ DBUG_RETURN(-1);
+ }
+ info->rec_cache.seek_not_done=1; /* We have done a seek */
+ }
+
+ if ((info->opt_flag & READ_CHECK_USED))
+ { /* If check isn't disabled */
+ info->rec_cache.seek_not_done=1; /* We have done a seek */
+ VOID(my_seek(info->dfile,info->lastpos,MY_SEEK_SET,MYF(0)));
+ if (my_read(info->dfile, (char*) info->rec_buff, info->s->base.reclength,
+ MYF(MY_NABP)))
+ DBUG_RETURN(-1);
+ if (memcmp((byte*) info->rec_buff, (byte*) old,
+ (uint) info->s->base.reclength))
+ {
+ DBUG_DUMP("read",old,info->s->base.reclength);
+ DBUG_DUMP("disk",info->rec_buff,info->s->base.reclength);
+ my_errno=HA_ERR_RECORD_CHANGED; /* Record have changed */
+ DBUG_RETURN(1);
+ }
+ }
+ DBUG_RETURN(0);
+}
+
+ /* Read a fixed-length-record */
+ /* Returns 0 if Ok. */
+ /* 1 if record is deleted */
+ /* MY_FILE_ERROR on read-error or locking-error */
+
+int _nisam_read_static_record(register N_INFO *info, register ulong pos,
+ register byte *record)
+{
+ int error;
+
+ if (pos != NI_POS_ERROR)
+ {
+ if (info->opt_flag & WRITE_CACHE_USED &&
+ info->rec_cache.pos_in_file <= pos &&
+ flush_io_cache(&info->rec_cache))
+ return(-1);
+ info->rec_cache.seek_not_done=1; /* We have done a seek */
+
+ error=my_pread(info->dfile,(char*) record,info->s->base.reclength,
+ pos,MYF(MY_NABP)) != 0;
+ if (info->s->r_locks == 0 && info->s->w_locks == 0)
+ VOID(_nisam_writeinfo(info,0));
+ if (! error)
+ {
+ if (!*record) return(1); /* Record is deleted */
+ info->update|= HA_STATE_AKTIV; /* Record is read */
+ my_errno=HA_ERR_RECORD_DELETED;
+ return(0);
+ }
+ return(-1); /* Error on read */
+ }
+ VOID(_nisam_writeinfo(info,0)); /* No such record */
+ return(-1);
+} /* _nisam_read_record */
+
+
+int _nisam_read_rnd_static_record(N_INFO *info, byte *buf,
+ register ulong filepos,
+ int skipp_deleted_blocks)
+{
+ int locked,error,cache_read;
+ uint cache_length;
+ ISAM_SHARE *share=info->s;
+ DBUG_ENTER("_nisam_read_rnd_static_record");
+
+ cache_read=0;
+ LINT_INIT(cache_length);
+ if (info->opt_flag & WRITE_CACHE_USED &&
+ (info->rec_cache.pos_in_file <= filepos || skipp_deleted_blocks) &&
+ flush_io_cache(&info->rec_cache))
+ DBUG_RETURN(-1);
+ if (info->opt_flag & READ_CACHE_USED)
+ { /* Cash in use */
+ if (filepos == my_b_tell(&info->rec_cache) &&
+ (skipp_deleted_blocks || !filepos))
+ {
+ cache_read=1; /* Read record using cache */
+ cache_length=(uint) (info->rec_cache.rc_end - info->rec_cache.rc_pos);
+ }
+ else
+ info->rec_cache.seek_not_done=1; /* Filepos is changed */
+ }
+#ifndef NO_LOCKING
+ locked=0;
+ if (info->lock_type == F_UNLCK)
+ {
+ if (filepos >= share->state.data_file_length)
+ { /* Test if new records */
+ if (_nisam_readinfo(info,F_RDLCK,0))
+ DBUG_RETURN(-1);
+ locked=1;
+ }
+ else
+ { /* We don't nead new info */
+#ifndef UNSAFE_LOCKING
+ if ((! cache_read || share->base.reclength > cache_length) &&
+ share->r_locks == 0 && share->w_locks == 0)
+ { /* record not in cache */
+ if (my_lock(share->kfile,F_RDLCK,0L,F_TO_EOF,
+ MYF(MY_SEEK_NOT_DONE) | info->lock_wait))
+ DBUG_RETURN(-1);
+ locked=1;
+ }
+#else
+ info->tmp_lock_type=F_RDLCK;
+#endif
+ }
+ }
+#endif
+ if (filepos >= share->state.data_file_length)
+ {
+#ifndef NO_LOCKING
+ DBUG_PRINT("test",("filepos: %ld (%ld) records: %ld del: %ld",
+ filepos/share->base.reclength,filepos,
+ share->state.records, share->state.del));
+ VOID(_nisam_writeinfo(info,0));
+#endif
+ my_errno=HA_ERR_END_OF_FILE;
+ DBUG_RETURN(-1);
+ }
+ info->lastpos= filepos;
+ info->nextpos= filepos+share->base.reclength;
+
+ if (! cache_read) /* No cacheing */
+ {
+ error=_nisam_read_static_record(info,filepos,buf);
+ if (error > 0)
+ my_errno=HA_ERR_RECORD_DELETED;
+ DBUG_RETURN(error);
+ }
+
+ /* Read record with cacheing */
+ error=my_b_read(&info->rec_cache,(byte*) buf,share->base.reclength);
+
+#ifndef NO_LOCKING
+ if (locked)
+ VOID(_nisam_writeinfo(info,0)); /* Unlock keyfile */
+#endif
+ if (!error)
+ {
+ if (!buf[0])
+ { /* Record is removed */
+ my_errno=HA_ERR_RECORD_DELETED;
+ DBUG_RETURN(1);
+ }
+ /* Found and may be updated */
+ info->update|= HA_STATE_AKTIV | HA_STATE_KEY_CHANGED;
+ DBUG_RETURN(0);
+ }
+ if (info->rec_cache.error != -1 || my_errno == 0)
+ my_errno=HA_ERR_WRONG_IN_RECORD;
+ DBUG_RETURN(-1); /* Something wrong (EOF?) */
+}
diff --git a/isam/changed.c b/isam/changed.c
new file mode 100644
index 00000000000..4f87a45aa2d
--- /dev/null
+++ b/isam/changed.c
@@ -0,0 +1,35 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* Check if somebody has changed table since last check. */
+
+#include "isamdef.h"
+
+ /* Return 0 if table isn't changed */
+
+int nisam_is_changed(N_INFO *info)
+{
+ int result;
+ DBUG_ENTER("nisam_is_changed");
+#ifndef NO_LOCKING
+ if (_nisam_readinfo(info,F_RDLCK,1)) DBUG_RETURN(-1);
+ VOID(_nisam_writeinfo(info,0));
+#endif
+ result=(int) info->data_changed;
+ info->data_changed=0;
+ DBUG_PRINT("exit",("result: %d",result));
+ DBUG_RETURN(result);
+}
diff --git a/isam/close.c b/isam/close.c
new file mode 100644
index 00000000000..6741e7b23f0
--- /dev/null
+++ b/isam/close.c
@@ -0,0 +1,91 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* close a isam-database */
+
+#include "isamdef.h"
+
+int nisam_close(register N_INFO *info)
+{
+ int error=0,flag;
+ ISAM_SHARE *share=info->s;
+ DBUG_ENTER("nisam_close");
+ DBUG_PRINT("enter",("base: %lx reopen: %u locks: %u",
+ info,(uint) share->reopen,
+ (uint) (share->w_locks+share->r_locks)));
+
+ pthread_mutex_lock(&THR_LOCK_isam);
+ if (info->lock_type == F_EXTRA_LCK)
+ info->lock_type=F_UNLCK; /* HA_EXTRA_NO_USER_CHANGE */
+
+#ifndef NO_LOCKING
+ if (info->lock_type != F_UNLCK)
+ VOID(nisam_lock_database(info,F_UNLCK));
+#else
+ info->lock_type=F_UNLCK;
+ share->w_locks--;
+ if (_nisam_writeinfo(info,test(share->changed)))
+ error=my_errno;
+#endif
+ pthread_mutex_lock(&share->intern_lock);
+
+ if (share->base.options & HA_OPTION_READ_ONLY_DATA)
+ share->r_locks--;
+ if (info->opt_flag & (READ_CACHE_USED | WRITE_CACHE_USED))
+ {
+ if (end_io_cache(&info->rec_cache))
+ error=my_errno;
+ info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
+ }
+ flag= !--share->reopen;
+ nisam_open_list=list_delete(nisam_open_list,&info->open_list);
+ pthread_mutex_unlock(&share->intern_lock);
+
+ if (flag)
+ {
+ if (share->kfile >= 0 && flush_key_blocks(share->kfile,FLUSH_RELEASE))
+ error=my_errno;
+ if (share->kfile >= 0 && my_close(share->kfile,MYF(0)))
+ error = my_errno;
+#ifdef HAVE_MMAP
+ _nisam_unmap_file(info);
+#endif
+ if (share->decode_trees)
+ {
+ my_free((gptr) share->decode_trees,MYF(0));
+ my_free((gptr) share->decode_tables,MYF(0));
+ }
+#ifdef THREAD
+ thr_lock_delete(&share->lock);
+ VOID(pthread_mutex_destroy(&share->intern_lock));
+#endif
+ my_free((gptr) info->s,MYF(0));
+ }
+ pthread_mutex_unlock(&THR_LOCK_isam);
+ if (info->dfile >= 0 && my_close(info->dfile,MYF(0)))
+ error = my_errno;
+
+ nisam_log_command(LOG_CLOSE,info,NULL,0,error);
+ my_free((gptr) info->rec_alloc,MYF(0));
+ my_free((gptr) info,MYF(0));
+
+ if (error)
+ {
+ my_errno=error;
+ DBUG_RETURN(-1);
+ }
+ DBUG_RETURN(0);
+} /* nisam_close */
diff --git a/isam/create.c b/isam/create.c
new file mode 100644
index 00000000000..9b5e9eaece4
--- /dev/null
+++ b/isam/create.c
@@ -0,0 +1,326 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* Skapar en isam-databas */
+
+#include "isamdef.h"
+#if defined(MSDOS) || defined(__WIN__)
+#ifdef __WIN__
+#include <fcntl.h>
+#else
+#include <process.h> /* Prototype for getpid */
+#endif
+#endif
+
+ /*
+ ** Old options is used when recreating database, from isamchk
+ ** Note that the minimun reclength that MySQL allows for static rows
+ ** are 5. (Will be fixed in the next generation)
+ */
+
+int nisam_create(const char *name,uint keys,N_KEYDEF *keyinfo,
+ N_RECINFO *recinfo,
+ ulong records,ulong reloc, uint flags,uint old_options,
+ ulong data_file_length)
+{
+ register uint i,j;
+ File dfile,file;
+ int errpos,save_errno;
+ uint fields,length,max_key_length,packed,pointer,reclength,min_pack_length,
+ key_length,info_length,key_segs,options,min_key_length_skipp,max_block,
+ base_pos;
+ char buff[max(FN_REFLEN,512)];
+ ulong tot_length,pack_reclength;
+ enum en_fieldtype type;
+ ISAM_SHARE share;
+ N_KEYDEF *keydef;
+ N_KEYSEG *keyseg;
+ N_RECINFO *rec;
+ DBUG_ENTER("nisam_create");
+
+ LINT_INIT(dfile);
+ pthread_mutex_lock(&THR_LOCK_isam);
+ errpos=0;
+ options=0;
+ base_pos=512; /* Enough for N_STATE_INFO */
+ bzero((byte*) &share,sizeof(share));
+ if ((file = my_create(fn_format(buff,name,"",N_NAME_IEXT,4),0,
+ O_RDWR | O_TRUNC,MYF(MY_WME))) < 0)
+ goto err;
+ errpos=1;
+ VOID(fn_format(buff,name,"",N_NAME_DEXT,2+4));
+ if (!(flags & HA_DONT_TOUCH_DATA))
+ {
+ if ((dfile = my_create(buff,0,O_RDWR | O_TRUNC,MYF(MY_WME))) < 0)
+ goto err;
+ errpos=2;
+ }
+ else if (!(old_options & HA_OPTION_TEMP_COMPRESS_RECORD))
+ options=old_options & (HA_OPTION_COMPRESS_RECORD |
+ HA_OPTION_READ_ONLY_DATA | HA_OPTION_PACK_RECORD);
+ if (reloc > records)
+ reloc=records; /* Check if wrong parameter */
+
+ /* Start by checking fields and field-types used */
+ reclength=0;
+ for (rec=recinfo, fields=packed=min_pack_length=0, pack_reclength=0L;
+ rec->base.type != (int) FIELD_LAST;
+ rec++,fields++)
+ {
+ reclength+=rec->base.length;
+ if ((type=(enum en_fieldtype) rec->base.type))
+ {
+ packed++;
+ if (type == FIELD_BLOB)
+ {
+ share.base.blobs++;
+ rec->base.length-= sizeof(char*); /* Don't calc pointer */
+ if (pack_reclength != NI_POS_ERROR)
+ {
+ if (rec->base.length == 4)
+ pack_reclength= (ulong) NI_POS_ERROR;
+ else
+ pack_reclength+=sizeof(char*)+(1 << (rec->base.length*8));
+ }
+ }
+ else if (type == FIELD_SKIPP_PRESPACE ||
+ type == FIELD_SKIPP_ENDSPACE)
+ {
+ if (pack_reclength != NI_POS_ERROR)
+ pack_reclength+= rec->base.length > 255 ? 2 : 1;
+ min_pack_length++;
+ }
+ else if (type == FIELD_ZERO)
+ packed--;
+ else if (type != FIELD_SKIPP_ZERO)
+ {
+ min_pack_length+=rec->base.length;
+ packed--; /* Not a pack record type */
+ }
+ }
+ else
+ min_pack_length+=rec->base.length;
+ }
+ if ((packed & 7) == 1)
+ { /* Bad packing, try to remove a zero-field */
+ while (rec != recinfo)
+ {
+ rec--;
+ if (rec->base.type == (int) FIELD_SKIPP_ZERO && rec->base.length == 1)
+ {
+ rec->base.type=(int) FIELD_NORMAL;
+ packed--;
+ min_pack_length++;
+ break;
+ }
+ }
+ }
+ if (packed && !(options & HA_OPTION_COMPRESS_RECORD))
+ options|=HA_OPTION_PACK_RECORD; /* Must use packed records */
+
+ packed=(packed+7)/8;
+ if (pack_reclength != NI_POS_ERROR)
+ pack_reclength+= reclength+packed;
+ min_pack_length+=packed;
+
+ if (options & HA_OPTION_COMPRESS_RECORD)
+ {
+ if (data_file_length >= (1L << 24))
+ pointer=4;
+ else if (data_file_length >= (1L << 16))
+ pointer=3;
+ else
+ pointer=2;
+ }
+ else if (((records == 0L && pack_reclength < 255) ||
+ options & HA_OPTION_PACK_RECORD) ||
+ records >= (ulong) 16000000L ||
+ pack_reclength == (ulong) NI_POS_ERROR ||
+ ((options & HA_OPTION_PACK_RECORD) &&
+ pack_reclength+4 >= (ulong) 14000000L/records))
+ pointer=4;
+ else if (records == 0L || records >= (ulong) 65000L ||
+ ((options & HA_OPTION_PACK_RECORD) &&
+ pack_reclength+4 >= (ulong) 60000L/records))
+ pointer=3;
+ else
+ pointer=2;
+
+ max_block=max_key_length=0; tot_length=key_segs=0;
+ for (i=0, keydef=keyinfo ; i < keys ; i++ , keydef++)
+ {
+ share.state.key_root[i]= share.state.key_del[i]= NI_POS_ERROR;
+ share.base.rec_per_key[i]= (keydef->base.flag & HA_NOSAME) ? 1L : 0L;
+ min_key_length_skipp=length=0;
+ key_length=pointer;
+
+ if (keydef->base.flag & HA_PACK_KEY &&
+ keydef->seg[0].base.length > 127)
+ keydef->base.flag&= ~HA_PACK_KEY; /* Can't pack long keys */
+ if (keydef->base.flag & HA_PACK_KEY)
+ {
+ if ((keydef->seg[0].base.flag & HA_SPACE_PACK) &&
+ keydef->seg[0].base.type == (int) HA_KEYTYPE_NUM)
+ keydef->seg[0].base.flag&= ~HA_SPACE_PACK;
+ if (!(keydef->seg[0].base.flag & HA_SPACE_PACK))
+ length++;
+ keydef->seg[0].base.flag|=HA_PACK_KEY; /* for easyer intern test */
+ options|=HA_OPTION_PACK_KEYS; /* Using packed keys */
+ if (!(keydef->seg[0].base.flag & HA_SPACE_PACK))
+ min_key_length_skipp+=keydef->seg[0].base.length;
+ }
+ keydef->base.keysegs=0;
+ for (keyseg=keydef->seg ; keyseg->base.type ; keyseg++)
+ {
+ keydef->base.keysegs++;
+ if (keyseg->base.length > 127)
+ keyseg->base.flag&= ~(HA_SPACE_PACK | HA_PACK_KEY);
+ if (keyseg->base.flag & HA_SPACE_PACK)
+ {
+ keydef->base.flag |= HA_SPACE_PACK_USED;
+ options|=HA_OPTION_PACK_KEYS; /* Using packed keys */
+ length++;
+ min_key_length_skipp+=keyseg->base.length;
+ }
+ key_length+= keyseg->base.length;
+ }
+ bzero((gptr) keyseg,sizeof(keyseg[0]));
+ keyseg->base.length=(uint16) pointer; /* Last key part is pointer */
+ key_segs+=keydef->base.keysegs;
+ length+=key_length;
+ keydef->base.block_length=nisam_block_size;
+ keydef->base.keylength= (uint16) key_length;
+ keydef->base.minlength= (uint16) (length-min_key_length_skipp);
+ keydef->base.maxlength= (uint16) length;
+
+ if ((uint) keydef->base.block_length > max_block)
+ max_block=(uint) keydef->base.block_length;
+ if (length > max_key_length)
+ max_key_length= length;
+ tot_length+= (records/(ulong) (((uint) keydef->base.block_length-5)/
+ (length*2)))*
+ (ulong) keydef->base.block_length;
+ }
+ info_length=(uint) (base_pos+sizeof(N_BASE_INFO)+keys*sizeof(N_SAVE_KEYDEF)+
+ (keys+key_segs)*sizeof(N_SAVE_KEYSEG)+
+ fields*sizeof(N_SAVE_RECINFO));
+
+ bmove(share.state.header.file_version,(byte*) nisam_file_magic,4);
+ old_options=options| (old_options & HA_OPTION_TEMP_COMPRESS_RECORD ?
+ HA_OPTION_COMPRESS_RECORD |
+ HA_OPTION_TEMP_COMPRESS_RECORD: 0);
+ int2store(share.state.header.options,old_options);
+ int2store(share.state.header.header_length,info_length);
+ int2store(share.state.header.state_info_length,sizeof(N_STATE_INFO));
+ int2store(share.state.header.base_info_length,sizeof(N_BASE_INFO));
+ int2store(share.state.header.base_pos,base_pos);
+
+ share.state.dellink = NI_POS_ERROR;
+ share.state.process= (ulong) getpid();
+ share.state.uniq= (ulong) file;
+ share.state.loop= 0;
+ share.state.version= (ulong) time((time_t*) 0);
+ share.base.options=options;
+ share.base.rec_reflength=pointer;
+ share.base.key_reflength=((!tot_length || tot_length > 30000000L) ? 3 :
+ tot_length > 120000L ? 2 : 1);
+ share.base.keys= share.state.keys = keys;
+ share.base.keystart = share.state.key_file_length=MY_ALIGN(info_length,
+ nisam_block_size);
+ share.base.max_block=max_block;
+ share.base.max_key_length=ALIGN_SIZE(max_key_length+4);
+ share.base.records=records;
+ share.base.reloc=reloc;
+ share.base.reclength=reclength;
+ share.base.pack_reclength=reclength+packed-share.base.blobs*sizeof(char*);
+ share.base.max_pack_length=pack_reclength;
+ share.base.min_pack_length=min_pack_length;
+ share.base.pack_bits=packed;
+ share.base.fields=fields;
+ share.base.pack_fields=packed;
+ share.base.sortkey= (ushort) ~0;
+ share.base.max_data_file_length= (pointer == 4) ? ~0L :
+ (options & (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)) ?
+ (1L << (pointer*8)) :
+ (pointer == 3 && reclength >= 256L) ? NI_POS_ERROR :
+ ((ulong) reclength * (1L << (pointer*8)));
+ share.base.max_key_file_length= (share.base.key_reflength == 3 ?
+ NI_POS_ERROR :
+ (1L << (share.base.key_reflength*8))*512);
+ share.base.min_block_length=
+ (share.base.pack_reclength+3 < N_EXTEND_BLOCK_LENGTH &&
+ ! share.base.blobs) ?
+ max(share.base.pack_reclength,N_MIN_BLOCK_LENGTH) :
+ N_EXTEND_BLOCK_LENGTH;
+ if (! (flags & HA_DONT_TOUCH_DATA))
+ share.base.create_time= (long) time((time_t*) 0);
+
+ bzero(buff,base_pos);
+ if (my_write(file,(char*) &share.state,sizeof(N_STATE_INFO),MYF(MY_NABP)) ||
+ my_write(file,buff,base_pos-sizeof(N_STATE_INFO),MYF(MY_NABP)) ||
+ my_write(file,(char*) &share.base,sizeof(N_BASE_INFO),MYF(MY_NABP)))
+ goto err;
+
+ for (i=0 ; i < share.base.keys ; i++)
+ {
+ if (my_write(file,(char*) &keyinfo[i].base,sizeof(N_SAVE_KEYDEF),
+ MYF(MY_NABP)))
+ goto err;
+ for (j=0 ; j <= keyinfo[i].base.keysegs ; j++)
+ {
+ if (my_write(file,(char*) &keyinfo[i].seg[j].base,sizeof(N_SAVE_KEYSEG),
+ MYF(MY_NABP)))
+ goto err;
+ }
+ }
+ for (i=0 ; i < share.base.fields ; i++)
+ if (my_write(file,(char*) &recinfo[i].base, (uint) sizeof(N_SAVE_RECINFO),
+ MYF(MY_NABP)))
+ goto err;
+
+ /* Enlarge files */
+ if (my_chsize(file,(ulong) share.base.keystart,MYF(0)))
+ goto err;
+
+ if (! (flags & HA_DONT_TOUCH_DATA))
+ {
+#ifdef USE_RELOC
+ if (my_chsize(dfile,share.base.min_pack_length*reloc,MYF(0)))
+ goto err;
+#endif
+ errpos=1;
+ if (my_close(dfile,MYF(0)))
+ goto err;
+ }
+ errpos=0;
+ pthread_mutex_unlock(&THR_LOCK_isam);
+ if (my_close(file,MYF(0)))
+ goto err;
+ DBUG_RETURN(0);
+
+err:
+ pthread_mutex_unlock(&THR_LOCK_isam);
+ save_errno=my_errno;
+ switch (errpos) {
+ case 2:
+ VOID(my_close(dfile,MYF(0)));
+ /* fall through */
+ case 1:
+ VOID(my_close(file,MYF(0)));
+ }
+ my_errno=save_errno; /* R{tt felkod tillbaka */
+ DBUG_RETURN(-1);
+} /* nisam_create */
diff --git a/isam/delete.c b/isam/delete.c
new file mode 100644
index 00000000000..9c66e241147
--- /dev/null
+++ b/isam/delete.c
@@ -0,0 +1,615 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* Tar bort ett record fr}n en isam-databas */
+
+#include "isamdef.h"
+#ifdef __WIN__
+#include <errno.h>
+#endif
+#include <assert.h>
+
+static int d_search(N_INFO *info,N_KEYDEF *keyinfo,uchar *key,ulong page,
+ uchar *anc_buff);
+static int del(N_INFO *info,N_KEYDEF *keyinfo,uchar *key,uchar *anc_buff,
+ ulong leaf_page,uchar *leaf_buff,uchar *keypos,
+ ulong next_block,uchar *ret_key);
+static int underflow(N_INFO *info,N_KEYDEF *keyinfo,uchar *anc_buff,
+ ulong leaf_page, uchar *leaf_buff,uchar *keypos);
+static uint remove_key(N_KEYDEF *keyinfo,uint nod_flag,uchar *keypos,
+ uchar *lastkey,uchar *page_end);
+
+
+int nisam_delete(N_INFO *info,const byte *record)
+{
+ uint i;
+ uchar *old_key;
+ int save_errno;
+ uint32 lastpos;
+ ISAM_SHARE *share=info->s;
+ DBUG_ENTER("nisam_delete");
+
+ /* Test if record is in datafile */
+
+ if (!(info->update & HA_STATE_AKTIV))
+ {
+ my_errno=HA_ERR_KEY_NOT_FOUND; /* No database read */
+ DBUG_RETURN(-1);
+ }
+ if (share->base.options & HA_OPTION_READ_ONLY_DATA)
+ {
+ my_errno=EACCES;
+ DBUG_RETURN(-1);
+ }
+#ifndef NO_LOCKING
+ if (_nisam_readinfo(info,F_WRLCK,1)) DBUG_RETURN(-1);
+#endif
+ if ((*share->compare_record)(info,record))
+ goto err; /* Fel vid kontroll-l{sning */
+
+ /* Remove all keys from the .ISAM file */
+
+ old_key=info->lastkey+share->base.max_key_length;
+ for (i=0 ; i < share->state.keys ; i++ )
+ {
+ VOID(_nisam_make_key(info,i,old_key,record,info->lastpos));
+ if (_nisam_ck_delete(info,i,old_key)) goto err;
+ }
+
+ if ((*share->delete_record)(info))
+ goto err; /* Remove record from database */
+
+ info->update= HA_STATE_CHANGED | HA_STATE_ROW_CHANGED | HA_STATE_DELETED;
+ share->state.records--;
+
+ lastpos= (uint32) info->lastpos;
+ nisam_log_command(LOG_DELETE,info,(byte*) &lastpos,sizeof(lastpos),0);
+ VOID(_nisam_writeinfo(info,1));
+ allow_break(); /* Allow SIGHUP & SIGINT */
+ DBUG_RETURN(0);
+
+err:
+ save_errno=my_errno;
+ lastpos= (uint32) info->lastpos;
+ nisam_log_command(LOG_DELETE,info,(byte*) &lastpos, sizeof(lastpos),0);
+ VOID(_nisam_writeinfo(info,1));
+ info->update|=HA_STATE_WRITTEN; /* Buffer changed */
+ allow_break(); /* Allow SIGHUP & SIGINT */
+ my_errno=save_errno;
+ if (save_errno == HA_ERR_KEY_NOT_FOUND)
+ my_errno=HA_ERR_CRASHED;
+
+ DBUG_RETURN(-1);
+} /* nisam_delete */
+
+
+ /* Tar bort en nyckel till isam-nyckelfilen */
+
+int _nisam_ck_delete(register N_INFO *info, uint keynr, uchar *key)
+{
+ int error;
+ uint nod_flag;
+ ulong old_root;
+ uchar *root_buff;
+ N_KEYDEF *keyinfo;
+ DBUG_ENTER("_nisam_ck_delete");
+
+ if ((old_root=info->s->state.key_root[keynr]) == NI_POS_ERROR)
+ {
+ my_errno=HA_ERR_CRASHED;
+ DBUG_RETURN(-1);
+ }
+ keyinfo=info->s->keyinfo+keynr;
+ if (!(root_buff= (uchar*) my_alloca((uint) keyinfo->base.block_length+
+ N_MAX_KEY_BUFF*2)))
+ DBUG_RETURN(-1);
+ if (!_nisam_fetch_keypage(info,keyinfo,old_root,root_buff,0))
+ {
+ error= -1;
+ goto err;
+ }
+ if ((error=d_search(info,keyinfo,key,old_root,root_buff)) >0)
+ {
+ if (error == 2)
+ {
+ DBUG_PRINT("test",("Enlarging of root when deleting"));
+ error=_nisam_enlarge_root(info,keynr,key);
+ }
+ else
+ {
+ error=0;
+ if (getint(root_buff) <= (nod_flag=test_if_nod(root_buff))+3)
+ {
+ if (nod_flag)
+ info->s->state.key_root[keynr]=_nisam_kpos(nod_flag,
+ root_buff+2+nod_flag);
+ else
+ info->s->state.key_root[keynr]= NI_POS_ERROR;
+ if (_nisam_dispose(info,keyinfo,old_root))
+ error= -1;
+ }
+ }
+ }
+err:
+ my_afree((gptr) root_buff);
+ DBUG_RETURN(error);
+} /* _nisam_ck_delete */
+
+
+ /* Tar bort en nyckel under root */
+ /* Returnerar 1 om nuvarande buffert minskade */
+ /* Returnerar 2 om nuvarande buffert |kar */
+
+static int d_search(register N_INFO *info, register N_KEYDEF *keyinfo, uchar *key, ulong page, uchar *anc_buff)
+{
+ int flag,ret_value,save_flag;
+ uint length,nod_flag;
+ uchar *leaf_buff,*keypos,*next_keypos;
+ ulong leaf_page,next_block;
+ uchar lastkey[N_MAX_KEY_BUFF];
+ DBUG_ENTER("d_search");
+ DBUG_DUMP("page",(byte*) anc_buff,getint(anc_buff));
+
+ flag=(*keyinfo->bin_search)(info,keyinfo,anc_buff,key,0,SEARCH_SAME,&keypos,
+ lastkey);
+ nod_flag=test_if_nod(anc_buff);
+
+ leaf_buff=0;
+ LINT_INIT(leaf_page);
+ if (nod_flag)
+ {
+ leaf_page=_nisam_kpos(nod_flag,keypos);
+ if (!(leaf_buff= (uchar*) my_alloca((uint) keyinfo->base.block_length+
+ N_MAX_KEY_BUFF*2)))
+ {
+ my_errno=ENOMEM;
+ DBUG_RETURN(-1);
+ }
+ if (!_nisam_fetch_keypage(info,keyinfo,leaf_page,leaf_buff,0))
+ goto err;
+ }
+
+ if (flag != 0)
+ {
+ if (!nod_flag)
+ {
+ my_errno=HA_ERR_CRASHED; /* This should newer happend */
+ goto err;
+ }
+ save_flag=0;
+ ret_value=d_search(info,keyinfo,key,leaf_page,leaf_buff);
+ }
+ else
+ { /* Found key */
+ next_keypos=keypos; /* Find where next block is */
+ VOID((*keyinfo->get_key)(keyinfo,nod_flag,&next_keypos,lastkey));
+ next_block=_nisam_kpos(nod_flag,next_keypos);
+ length=getint(anc_buff);
+ length-= remove_key(keyinfo,nod_flag,keypos,lastkey,anc_buff+length);
+ putint(anc_buff,length,nod_flag);
+ if (!nod_flag)
+ { /* On leaf page */
+ if (_nisam_write_keypage(info,keyinfo,page,anc_buff))
+ DBUG_RETURN(-1);
+ DBUG_RETURN(length <= (uint) keyinfo->base.block_length/2);
+ }
+ save_flag=1;
+ ret_value=del(info,keyinfo,key,anc_buff,leaf_page,leaf_buff,keypos,
+ next_block,lastkey);
+ }
+ if (ret_value >0)
+ {
+ save_flag=1;
+ if (ret_value == 1)
+ ret_value= underflow(info,keyinfo,anc_buff,leaf_page,leaf_buff,keypos);
+ else
+ { /* This happens only with packed keys */
+ DBUG_PRINT("test",("Enlarging of key when deleting"));
+ VOID(_nisam_get_last_key(info,keyinfo,anc_buff,lastkey,keypos));
+ ret_value=_nisam_insert(info,keyinfo,key,anc_buff,keypos,lastkey,
+ (uchar*) 0,(uchar*) 0,0L);
+ }
+ }
+ if (ret_value == 0 && getint(anc_buff) > keyinfo->base.block_length)
+ {
+ save_flag=1;
+ ret_value=_nisam_splitt_page(info,keyinfo,key,anc_buff,lastkey) | 2;
+ }
+ if (save_flag)
+ ret_value|=_nisam_write_keypage(info,keyinfo,page,anc_buff);
+ else
+ {
+ DBUG_DUMP("page",(byte*) anc_buff,getint(anc_buff));
+ }
+ my_afree((byte*) leaf_buff);
+ DBUG_RETURN(ret_value);
+err:
+ my_afree((byte*) leaf_buff);
+ DBUG_PRINT("exit",("Error: %d",my_errno));
+ DBUG_RETURN (-1);
+} /* d_search */
+
+
+ /* Remove a key that has a page-reference */
+
+static int del(register N_INFO *info, register N_KEYDEF *keyinfo, uchar *key,
+ uchar *anc_buff, ulong leaf_page, uchar *leaf_buff,
+ uchar *keypos, /* Pos to where deleted key was */
+ ulong next_block,
+ uchar *ret_key) /* key before keypos in anc_buff */
+{
+ int ret_value,length;
+ uint a_length,nod_flag;
+ ulong next_page;
+ uchar keybuff[N_MAX_KEY_BUFF],*endpos,*next_buff,*key_start;
+ ISAM_SHARE *share=info->s;
+ S_PARAM s_temp;
+ DBUG_ENTER("del");
+ DBUG_PRINT("enter",("leaf_page: %ld keypos: %lx",leaf_page,keypos));
+ DBUG_DUMP("leaf_buff",(byte*) leaf_buff,getint(leaf_buff));
+
+ endpos=leaf_buff+getint(leaf_buff);
+ key_start=_nisam_get_last_key(info,keyinfo,leaf_buff,keybuff,endpos);
+
+ if ((nod_flag=test_if_nod(leaf_buff)))
+ {
+ next_page= _nisam_kpos(nod_flag,endpos);
+ if (!(next_buff= (uchar*) my_alloca((uint) keyinfo->base.block_length+
+ N_MAX_KEY_BUFF)))
+ DBUG_RETURN(-1);
+ if (!_nisam_fetch_keypage(info,keyinfo,next_page,next_buff,0))
+ ret_value= -1;
+ else
+ {
+ DBUG_DUMP("next_page",(byte*) next_buff,getint(next_buff));
+ if ((ret_value=del(info,keyinfo,key,anc_buff,next_page,next_buff,
+ keypos,next_block,ret_key)) >0)
+ {
+ endpos=leaf_buff+getint(leaf_buff);
+ if (ret_value == 1)
+ {
+ ret_value=underflow(info,keyinfo,leaf_buff,next_page,
+ next_buff,endpos);
+ if (ret_value == 0 && getint(leaf_buff) > keyinfo->base.block_length)
+ {
+ ret_value=_nisam_splitt_page(info,keyinfo,key,leaf_buff,ret_key) | 2;
+ }
+ }
+ else
+ {
+ DBUG_PRINT("test",("Inserting of key when deleting"));
+ VOID(_nisam_get_last_key(info,keyinfo,leaf_buff,keybuff,endpos));
+ ret_value=_nisam_insert(info,keyinfo,key,leaf_buff,endpos,keybuff,
+ (uchar*) 0,(uchar*) 0,0L);
+ }
+ }
+ if (_nisam_write_keypage(info,keyinfo,leaf_page,leaf_buff))
+ goto err;
+ }
+ my_afree((byte*) next_buff);
+ DBUG_RETURN(ret_value);
+ }
+
+ /* Remove last key from leaf page */
+
+ putint(leaf_buff,key_start-leaf_buff,nod_flag);
+ if (_nisam_write_keypage(info,keyinfo,leaf_page,leaf_buff))
+ goto err;
+
+ /* Place last key in ancestor page on deleted key position */
+
+ a_length=getint(anc_buff);
+ endpos=anc_buff+a_length;
+ VOID(_nisam_get_last_key(info,keyinfo,anc_buff,ret_key,keypos));
+ length=_nisam_get_pack_key_length(keyinfo,share->base.key_reflength,
+ keypos == endpos ? (uchar*) 0 : keypos,
+ ret_key,keybuff,&s_temp);
+ if (length > 0)
+ bmove_upp((byte*) endpos+length,(byte*) endpos,(uint) (endpos-keypos));
+ else
+ bmove(keypos,keypos-length, (int) (endpos-keypos)+length);
+ _nisam_store_key(keyinfo,keypos,&s_temp);
+ /* Save pointer to next leaf */
+ VOID((*keyinfo->get_key)(keyinfo,share->base.key_reflength,&keypos,ret_key));
+ _nisam_kpointer(info,keypos - share->base.key_reflength,next_block);
+ putint(anc_buff,a_length+length,share->base.key_reflength);
+
+ DBUG_RETURN( getint(leaf_buff) <= (uint) keyinfo->base.block_length/2 );
+err:
+ DBUG_RETURN(-1);
+} /* del */
+
+
+ /* Balances adjacent pages if underflow occours */
+
+static int underflow(register N_INFO *info, register N_KEYDEF *keyinfo,
+ uchar *anc_buff,
+ ulong leaf_page, /* Ancestor page and underflow page */
+ uchar *leaf_buff,
+ uchar *keypos) /* Position to pos after key */
+{
+ int t_length;
+ uint length,anc_length,buff_length,leaf_length,p_length,s_length,nod_flag;
+ ulong next_page;
+ uchar anc_key[N_MAX_KEY_BUFF],leaf_key[N_MAX_KEY_BUFF],
+ *buff,*endpos,*next_keypos,*half_pos,*temp_pos;
+ S_PARAM s_temp;
+ ISAM_SHARE *share=info->s;
+ DBUG_ENTER("underflow");
+ DBUG_PRINT("enter",("leaf_page: %ld keypos: %lx",leaf_page,keypos));
+ DBUG_DUMP("anc_buff",(byte*) anc_buff,getint(anc_buff));
+ DBUG_DUMP("leaf_buff",(byte*) leaf_buff,getint(leaf_buff));
+
+ buff=info->buff;
+ next_keypos=keypos;
+ nod_flag=test_if_nod(leaf_buff);
+ p_length=2+nod_flag;
+ anc_length=getint(anc_buff);
+ leaf_length=getint(leaf_buff);
+ info->page_changed=1;
+
+ if ((keypos < anc_buff+anc_length && (share->rnd++ & 1)) ||
+ keypos == anc_buff+2+share->base.key_reflength)
+ { /* Use page right of anc-page */
+ DBUG_PRINT("test",("use right page"));
+
+ VOID((*keyinfo->get_key)(keyinfo,share->base.key_reflength,&next_keypos,
+ buff));
+ next_page= _nisam_kpos(share->base.key_reflength,next_keypos);
+ if (!_nisam_fetch_keypage(info,keyinfo,next_page,buff,0))
+ goto err;
+ buff_length=getint(buff);
+ DBUG_DUMP("next",(byte*) buff,buff_length);
+
+ /* find keys to make a big key-page */
+ bmove((byte*) next_keypos-share->base.key_reflength,(byte*) buff+2,
+ share->base.key_reflength);
+ VOID(_nisam_get_last_key(info,keyinfo,anc_buff,anc_key,next_keypos));
+ VOID(_nisam_get_last_key(info,keyinfo,leaf_buff,leaf_key,
+ leaf_buff+leaf_length));
+
+ /* merge pages and put parting key from anc_buff between */
+ t_length=(int) _nisam_get_pack_key_length(keyinfo,nod_flag,buff+p_length,
+ (leaf_length == nod_flag+2 ?
+ (uchar*) 0 : leaf_key),
+ anc_key,&s_temp);
+ length=buff_length-p_length;
+ endpos=buff+length+leaf_length+t_length;
+ bmove_upp((byte*) endpos, (byte*) buff+buff_length,length);
+ memcpy((byte*) buff, (byte*) leaf_buff,(size_t) leaf_length);
+ _nisam_store_key(keyinfo,buff+leaf_length,&s_temp);
+ buff_length=(uint) (endpos-buff);
+ putint(buff,buff_length,nod_flag);
+
+ /* remove key from anc_buff */
+
+ s_length=remove_key(keyinfo,share->base.key_reflength,keypos,anc_key,
+ anc_buff+anc_length);
+ putint(anc_buff,(anc_length-=s_length),share->base.key_reflength);
+
+ if (buff_length <= keyinfo->base.block_length)
+ { /* Keys in one page */
+ memcpy((byte*) leaf_buff,(byte*) buff,(size_t) buff_length);
+ if (_nisam_dispose(info,keyinfo,next_page))
+ goto err;
+ }
+ else
+ { /* Page is full */
+ VOID(_nisam_get_last_key(info,keyinfo,anc_buff,anc_key,keypos));
+ half_pos=_nisam_find_half_pos(info,keyinfo,buff,leaf_key);
+ length=(uint) (half_pos-buff);
+ memcpy((byte*) leaf_buff,(byte*) buff,(size_t) length);
+ putint(leaf_buff,length,nod_flag);
+ endpos=anc_buff+anc_length;
+
+ /* Correct new keypointer to leaf_page */
+ length=(*keyinfo->get_key)(keyinfo,nod_flag,&half_pos,leaf_key);
+ _nisam_kpointer(info,leaf_key+length,next_page);
+ /* Save key in anc_buff */
+ t_length=(int) _nisam_get_pack_key_length(keyinfo,
+ share->base.key_reflength,
+ keypos == endpos ?
+ (uchar*) 0 : keypos,
+ anc_key,leaf_key,&s_temp);
+ if (t_length >= 0)
+ bmove_upp((byte*) endpos+t_length,(byte*) endpos,
+ (uint) (endpos-keypos));
+ else
+ bmove(keypos,keypos-t_length,(uint) (endpos-keypos)+t_length);
+ _nisam_store_key(keyinfo,keypos,&s_temp);
+ putint(anc_buff,(anc_length+=t_length),share->base.key_reflength);
+
+ /* Store new page */
+ if (nod_flag)
+ bmove((byte*) buff+2,(byte*) half_pos-nod_flag,(size_t) nod_flag);
+ VOID((*keyinfo->get_key)(keyinfo,nod_flag,&half_pos,leaf_key));
+ t_length=(int) _nisam_get_pack_key_length(keyinfo,nod_flag,(uchar*) 0,
+ (uchar*) 0, leaf_key,&s_temp);
+ s_temp.n_length= *half_pos; /* For _nisam_store_key */
+ length=(buff+getint(buff))-half_pos;
+ bmove((byte*) buff+p_length+t_length,(byte*) half_pos,(size_t) length);
+ _nisam_store_key(keyinfo,buff+p_length,&s_temp);
+ putint(buff,length+t_length+p_length,nod_flag);
+
+ if (_nisam_write_keypage(info,keyinfo,next_page,buff))
+ goto err;
+ }
+ if (_nisam_write_keypage(info,keyinfo,leaf_page,leaf_buff))
+ goto err;
+ DBUG_RETURN(anc_length <= (uint) keyinfo->base.block_length/2);
+ }
+
+ DBUG_PRINT("test",("use left page"));
+
+ keypos=_nisam_get_last_key(info,keyinfo,anc_buff,anc_key,keypos);
+ next_page= _nisam_kpos(share->base.key_reflength,keypos);
+ if (!_nisam_fetch_keypage(info,keyinfo,next_page,buff,0))
+ goto err;
+ buff_length=getint(buff);
+ endpos=buff+buff_length;
+ DBUG_DUMP("prev",(byte*) buff,buff_length);
+
+ /* find keys to make a big key-page */
+ bmove((byte*) next_keypos - share->base.key_reflength,(byte*) leaf_buff+2,
+ share->base.key_reflength);
+ next_keypos=keypos;
+ VOID((*keyinfo->get_key)(keyinfo,share->base.key_reflength,&next_keypos,
+ anc_key));
+ VOID(_nisam_get_last_key(info,keyinfo,buff,leaf_key,endpos));
+
+ /* merge pages and put parting key from anc_buff between */
+ t_length=(int) _nisam_get_pack_key_length(keyinfo,nod_flag,
+ leaf_buff+p_length,
+ (leaf_length == nod_flag+2 ?
+ (uchar*) 0 : leaf_key),
+ anc_key,&s_temp);
+ if (t_length >= 0)
+ bmove((byte*) endpos+t_length,(byte*) leaf_buff+p_length,
+ (size_t) (leaf_length-p_length));
+ else /* We gained space */
+ bmove((byte*) endpos,(byte*) leaf_buff+((int) p_length-t_length),
+ (size_t) (leaf_length-p_length+t_length));
+
+ _nisam_store_key(keyinfo,endpos,&s_temp);
+ buff_length=buff_length+leaf_length-p_length+t_length;
+ putint(buff,buff_length,nod_flag);
+
+ /* remove key from anc_buff */
+ s_length=remove_key(keyinfo,share->base.key_reflength,keypos,anc_key,
+ anc_buff+anc_length);
+ putint(anc_buff,(anc_length-=s_length),share->base.key_reflength);
+
+ if (buff_length <= keyinfo->base.block_length)
+ { /* Keys in one page */
+ if (_nisam_dispose(info,keyinfo,leaf_page))
+ goto err;
+ }
+ else
+ { /* Page is full */
+ VOID(_nisam_get_last_key(info,keyinfo,anc_buff,anc_key,keypos));
+ endpos=half_pos=_nisam_find_half_pos(info,keyinfo,buff,leaf_key);
+
+ /* Correct new keypointer to leaf_page */
+ length=(*keyinfo->get_key)(keyinfo,nod_flag,&half_pos,leaf_key);
+ _nisam_kpointer(info,leaf_key+length,leaf_page);
+ /* Save key in anc_buff */
+ DBUG_DUMP("anc_buff",(byte*) anc_buff,anc_length);
+ DBUG_DUMP("key",(byte*) leaf_key,16);
+
+ temp_pos=anc_buff+anc_length;
+ t_length=(int) _nisam_get_pack_key_length(keyinfo,
+ share->base.key_reflength,
+ keypos == temp_pos ? (uchar*) 0
+ : keypos,
+ anc_key,leaf_key,&s_temp);
+ if (t_length > 0)
+ bmove_upp((byte*) temp_pos+t_length,(byte*) temp_pos,
+ (uint) (temp_pos-keypos));
+ else
+ bmove(keypos,keypos-t_length,(uint) (temp_pos-keypos)+t_length);
+ _nisam_store_key(keyinfo,keypos,&s_temp);
+ putint(anc_buff,(anc_length+=t_length),share->base.key_reflength);
+
+ /* Store new page */
+ if (nod_flag)
+ bmove((byte*) leaf_buff+2,(byte*) half_pos-nod_flag,(size_t) nod_flag);
+ VOID((*keyinfo->get_key)(keyinfo,nod_flag,&half_pos,leaf_key));
+ t_length=(int) _nisam_get_pack_key_length(keyinfo,nod_flag, (uchar*) 0,
+ (uchar*) 0, leaf_key, &s_temp);
+ s_temp.n_length= *half_pos; /* For _nisam_store_key */
+ length=(uint) ((buff+buff_length)-half_pos);
+ bmove((byte*) leaf_buff+p_length+t_length,(byte*) half_pos,
+ (size_t) length);
+ _nisam_store_key(keyinfo,leaf_buff+p_length,&s_temp);
+ putint(leaf_buff,length+t_length+p_length,nod_flag);
+ putint(buff,endpos-buff,nod_flag);
+ if (_nisam_write_keypage(info,keyinfo,leaf_page,leaf_buff))
+ goto err;
+ }
+ if (_nisam_write_keypage(info,keyinfo,next_page,buff))
+ goto err;
+ DBUG_RETURN(anc_length <= (uint) keyinfo->base.block_length/2);
+err:
+ DBUG_RETURN(-1);
+} /* underflow */
+
+
+ /* remove a key from packed buffert */
+ /* returns how many chars was removed */
+
+static uint remove_key(N_KEYDEF *keyinfo, uint nod_flag,
+ uchar *keypos, /* Where key starts */
+ uchar *lastkey, /* key to be removed */
+ uchar *page_end) /* End of page */
+{
+ int r_length,s_length,first,diff_flag;
+ uchar *start;
+ DBUG_ENTER("remove_key");
+ DBUG_PRINT("enter",("keypos: %lx page_end: %lx",keypos,page_end));
+
+ start=keypos;
+ if (!(keyinfo->base.flag & (HA_PACK_KEY | HA_SPACE_PACK_USED)))
+ s_length=(int) (keyinfo->base.keylength+nod_flag);
+ else
+ { /* Let keypos point at next key */
+ VOID((*keyinfo->get_key)(keyinfo,nod_flag,&keypos,lastkey));
+ s_length=(keypos-start);
+ if (keyinfo->base.flag & HA_PACK_KEY)
+ {
+ diff_flag= (keyinfo->seg[0].base.flag & HA_SPACE_PACK);
+ first= *start;
+ if (keypos != page_end && *keypos & 128 && first != 128)
+ { /* Referens length */
+ if ((r_length= *keypos++ & 127) == 0)
+ { /* Same key after */
+ if (first & 128)
+ start++; /* Skipp ref length */
+ if (diff_flag)
+ start+= *start+1; /* Skipp key length */
+ else
+ start+=keyinfo->seg[0].base.length- (first & 127);
+ s_length=(keypos-start); /* Remove pointers and next-key-flag */
+ }
+ else if (! (first & 128))
+ { /* Deleted key was not compressed */
+ if (diff_flag)
+ {
+ *start= (uchar) (r_length+ *keypos);
+ start+=r_length+1; /* Let ref-part remain */
+ s_length=(keypos-start)+1; /* Skipp everything between */
+ }
+ else
+ {
+ start+=r_length+1; /* Let ref-part remain */
+ s_length=(keypos-start); /* Skipp everything between */
+ }
+ }
+ else if ((first & 127) < r_length)
+ { /* mid-part of key is used */
+ r_length-=(first & 127);
+ start++; /* Ref remains the same */
+ if (diff_flag)
+ *start++= (uchar) (*keypos++ + r_length);
+ start+= r_length;
+ s_length=(keypos-start); /* Skipp everything between */
+ }
+ }
+ }
+ }
+ bmove((byte*) start,(byte*) start+s_length,
+ (uint) (page_end-start-s_length));
+ DBUG_RETURN((uint) s_length);
+} /* remove_key */
diff --git a/isam/extra.c b/isam/extra.c
new file mode 100644
index 00000000000..dc9b6ce2d19
--- /dev/null
+++ b/isam/extra.c
@@ -0,0 +1,258 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* Extra functions we want to do with a database */
+/* - Set flags for quicker databasehandler */
+/* - Set databasehandler to normal */
+/* - Reset recordpointers as after open database */
+
+#include "isamdef.h"
+#ifdef HAVE_MMAP
+#include <sys/mman.h>
+#endif
+#ifdef __WIN__
+#include <errno.h>
+#endif
+
+ /* set extra flags for database */
+
+int nisam_extra(N_INFO *info, enum ha_extra_function function)
+{
+ int error=0;
+ DBUG_ENTER("nisam_extra");
+
+ switch (function) {
+ case HA_EXTRA_RESET:
+ info->lastinx= 0; /* Use first index as def */
+ info->int_pos=info->lastpos= NI_POS_ERROR;
+ info->page_changed=1;
+ /* Next/prev gives first/last */
+ if (info->opt_flag & READ_CACHE_USED)
+ {
+ VOID(flush_io_cache(&info->rec_cache));
+ reinit_io_cache(&info->rec_cache,READ_CACHE,0,
+ (pbool) (info->lock_type != F_UNLCK),
+ (pbool) test(info->update & HA_STATE_ROW_CHANGED));
+ }
+ info->update=((info->update & HA_STATE_CHANGED) |
+ HA_STATE_NEXT_FOUND | HA_STATE_PREV_FOUND);
+ break;
+ case HA_EXTRA_CACHE:
+#ifndef NO_LOCKING
+ if (info->lock_type == F_UNLCK && (info->options & HA_OPTION_PACK_RECORD))
+ {
+ error=1; /* Not possibly if not locked */
+ my_errno=EACCES;
+ break;
+ }
+#endif
+#if defined(HAVE_MMAP) && defined(HAVE_MADVICE)
+ if ((info->options & HA_OPTION_COMPRESS_RECORD))
+ {
+ pthread_mutex_lock(&info->s->intern_lock);
+ if (_nisam_memmap_file(info))
+ {
+ /* We don't nead MADV_SEQUENTIAL if small file */
+ madvise(info->s->file_map,info->s->state.data_file_length,
+ info->s->state.data_file_length <= RECORD_CACHE_SIZE*16 ?
+ MADV_RANDOM : MADV_SEQUENTIAL);
+ pthread_mutex_unlock(&info->s->intern_lock);
+ break;
+ }
+ pthread_mutex_unlock(&info->s->intern_lock);
+ }
+#endif
+ if (info->opt_flag & WRITE_CACHE_USED)
+ {
+ info->opt_flag&= ~WRITE_CACHE_USED;
+ if ((error=end_io_cache(&info->rec_cache)))
+ break;
+ }
+ if (!(info->opt_flag &
+ (READ_CACHE_USED | WRITE_CACHE_USED | MEMMAP_USED)))
+ {
+ if (!(init_io_cache(&info->rec_cache,info->dfile,
+ (uint) min(info->s->state.data_file_length+1,
+ my_default_record_cache_size),
+ READ_CACHE,0L,(pbool) (info->lock_type != F_UNLCK),
+ MYF(MY_WAIT_IF_FULL))))
+ {
+ info->opt_flag|=READ_CACHE_USED;
+ info->update&= ~HA_STATE_ROW_CHANGED;
+ }
+ /* info->rec_cache.end_of_file=info->s->state.data_file_length; */
+ }
+ break;
+ case HA_EXTRA_REINIT_CACHE:
+ if (info->opt_flag & READ_CACHE_USED)
+ {
+ reinit_io_cache(&info->rec_cache,READ_CACHE,info->nextpos,
+ (pbool) (info->lock_type != F_UNLCK),
+ (pbool) test(info->update & HA_STATE_ROW_CHANGED));
+ info->update&= ~HA_STATE_ROW_CHANGED;
+ /* info->rec_cache.end_of_file=info->s->state.data_file_length; */
+ }
+ break;
+ case HA_EXTRA_WRITE_CACHE:
+#ifndef NO_LOCKING
+ if (info->lock_type == F_UNLCK)
+ {
+ error=1; /* Not possibly if not locked */
+ break;
+ }
+#endif
+ if (!(info->opt_flag & (READ_CACHE_USED | WRITE_CACHE_USED)))
+ if (!(init_io_cache(&info->rec_cache,info->dfile,0,
+ WRITE_CACHE,info->s->state.data_file_length,
+ (pbool) (info->lock_type != F_UNLCK),
+ MYF(MY_WAIT_IF_FULL))))
+ {
+ info->opt_flag|=WRITE_CACHE_USED;
+ info->update&= ~HA_STATE_ROW_CHANGED;
+ }
+ break;
+ case HA_EXTRA_NO_CACHE:
+ if (info->opt_flag & (READ_CACHE_USED | WRITE_CACHE_USED))
+ {
+ info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
+ error=end_io_cache(&info->rec_cache);
+ }
+#if defined(HAVE_MMAP) && defined(HAVE_MADVICE)
+ if (info->opt_flag & MEMMAP_USED)
+ madvise(info->s->file_map,info->s->state.data_file_length,MADV_RANDOM);
+#endif
+ break;
+ case HA_EXTRA_FLUSH_CACHE:
+ if (info->opt_flag & WRITE_CACHE_USED)
+ error=flush_io_cache(&info->rec_cache);
+ break;
+ case HA_EXTRA_NO_READCHECK:
+ info->opt_flag&= ~READ_CHECK_USED; /* No readcheck */
+ break;
+ case HA_EXTRA_READCHECK:
+ info->opt_flag|= READ_CHECK_USED;
+ break;
+ case HA_EXTRA_KEYREAD: /* Read only keys to record */
+ case HA_EXTRA_REMEMBER_POS:
+ info->opt_flag |= REMEMBER_OLD_POS;
+ bmove((byte*) info->lastkey+info->s->base.max_key_length*2,
+ (byte*) info->lastkey,info->s->base.max_key_length);
+ info->save_update= info->update;
+ info->save_lastinx= info->lastinx;
+ info->save_lastpos= info->lastpos;
+ if (function == HA_EXTRA_REMEMBER_POS)
+ break;
+ /* fall through */
+ case HA_EXTRA_KEYREAD_CHANGE_POS:
+ info->opt_flag |= KEY_READ_USED;
+ info->read_record=_nisam_read_key_record;
+ break;
+ case HA_EXTRA_NO_KEYREAD:
+ case HA_EXTRA_RESTORE_POS:
+ if (info->opt_flag & REMEMBER_OLD_POS)
+ {
+ bmove((byte*) info->lastkey,
+ (byte*) info->lastkey+info->s->base.max_key_length*2,
+ info->s->base.max_key_length);
+ info->update= info->save_update | HA_STATE_WRITTEN;
+ info->lastinx= info->save_lastinx;
+ info->lastpos= info->save_lastpos;
+ }
+ info->read_record= info->s->read_record;
+ info->opt_flag&= ~(KEY_READ_USED | REMEMBER_OLD_POS);
+ break;
+ case HA_EXTRA_NO_USER_CHANGE: /* Database is somehow locked agains changes */
+ info->lock_type= F_EXTRA_LCK; /* Simulate as locked */
+ break;
+ case HA_EXTRA_WAIT_LOCK:
+ info->lock_wait=0;
+ break;
+ case HA_EXTRA_NO_WAIT_LOCK:
+ info->lock_wait=MY_DONT_WAIT;
+ break;
+ case HA_EXTRA_NO_KEYS:
+#ifndef NO_LOCKING
+ if (info->lock_type == F_UNLCK)
+ {
+ error=1; /* Not possibly if not lock */
+ break;
+ }
+#endif
+ info->s->state.keys=0;
+ info->s->state.key_file_length=info->s->base.keystart;
+ info->s->changed=1; /* Update on close */
+ break;
+ case HA_EXTRA_FORCE_REOPEN:
+ pthread_mutex_lock(&THR_LOCK_isam);
+ info->s->last_version= 0L; /* Impossible version */
+#ifdef __WIN__
+ /* Close the isam and data files as Win32 can't drop an open table */
+ if (flush_key_blocks(info->s->kfile,FLUSH_RELEASE))
+ error=my_errno;
+ if (info->opt_flag & (READ_CACHE_USED | WRITE_CACHE_USED))
+ {
+ info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
+ error=end_io_cache(&info->rec_cache);
+ }
+ if (info->lock_type != F_UNLCK && ! info->was_locked)
+ {
+ info->was_locked=info->lock_type;
+ if (nisam_lock_database(info,F_UNLCK))
+ error=my_errno;
+ }
+ if (info->s->kfile >= 0 && my_close(info->s->kfile,MYF(0)))
+ error=my_errno;
+ {
+ LIST *list_element ;
+ for (list_element=nisam_open_list ;
+ list_element ;
+ list_element=list_element->next)
+ {
+ N_INFO *tmpinfo=(N_INFO*) list_element->data;
+ if (tmpinfo->s == info->s)
+ {
+ if (tmpinfo->dfile >= 0 && my_close(tmpinfo->dfile,MYF(0)))
+ error = my_errno;
+ tmpinfo->dfile=-1;
+ }
+ }
+ }
+ info->s->kfile=-1; /* Files aren't open anymore */
+#endif
+ pthread_mutex_unlock(&THR_LOCK_isam);
+ break;
+ case HA_EXTRA_FLUSH:
+#ifdef __WIN__
+ if (info->s->not_flushed)
+ {
+ info->s->not_flushed=0;
+ if (_commit(info->s->kfile))
+ error=errno;
+ if (_commit(info->dfile))
+ error=errno;
+ }
+ break;
+#endif
+ case HA_EXTRA_NORMAL: /* Theese isn't in use */
+ case HA_EXTRA_QUICK:
+ case HA_EXTRA_KEY_CACHE:
+ case HA_EXTRA_NO_KEY_CACHE:
+ default:
+ break;
+ }
+ nisam_log_command(LOG_EXTRA,info,(byte*) &function,sizeof(function),error);
+ DBUG_RETURN(error);
+} /* nisam_extra */
diff --git a/isam/info.c b/isam/info.c
new file mode 100644
index 00000000000..43c15af908d
--- /dev/null
+++ b/isam/info.c
@@ -0,0 +1,77 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* Ger tillbaka en struct med information om isam-filen */
+
+#include "isamdef.h"
+#ifdef __WIN__
+#include <sys/stat.h>
+#endif
+
+ulong nisam_position(N_INFO *info)
+{
+ return info->lastpos;
+}
+
+ /* If flag == 1 one only gets pos of last record */
+ /* if flag == 2 one get current info (no sync from database */
+
+int nisam_info(N_INFO *info, register N_ISAMINFO *x, int flag)
+{
+ struct stat state;
+ ISAM_SHARE *share=info->s;
+ DBUG_ENTER("nisam_info");
+
+ x->recpos = info->lastpos;
+ if (flag & (HA_STATUS_TIME | HA_STATUS_CONST | HA_STATUS_VARIABLE |
+ HA_STATUS_ERRKEY | HA_STATUS_NO_LOCK))
+ {
+#ifndef NO_LOCKING
+ if (!(flag & HA_STATUS_NO_LOCK))
+ {
+ pthread_mutex_lock(&share->intern_lock);
+ VOID(_nisam_readinfo(info,F_RDLCK,0));
+ VOID(_nisam_writeinfo(info,0));
+ pthread_mutex_unlock(&share->intern_lock);
+ }
+#endif
+ x->records = share->state.records;
+ x->deleted = share->state.del;
+ x->delete_length= share->state.empty;
+ x->keys = share->state.keys;
+ x->reclength = share->base.reclength;
+ x->mean_reclength= share->state.records ?
+ (share->state.data_file_length-share->state.empty)/share->state.records :
+ share->min_pack_length;
+ x->data_file_length=share->state.data_file_length;
+ x->max_data_file_length=share->base.max_data_file_length;
+ x->index_file_length=share->state.key_file_length;
+ x->max_index_file_length=share->base.max_key_file_length;
+ x->filenr = info->dfile;
+ x->errkey = info->errkey;
+ x->dupp_key_pos= info->dupp_key_pos;
+ x->options = share->base.options;
+ x->create_time=share->base.create_time;
+ x->isamchk_time=share->base.isamchk_time;
+ x->rec_per_key=share->base.rec_per_key;
+ if ((flag & HA_STATUS_TIME) && !fstat(info->dfile,&state))
+ x->update_time=state.st_mtime;
+ else
+ x->update_time=0;
+ x->sortkey= -1; /* No clustering */
+ }
+ DBUG_RETURN(0);
+} /* nisam_info */
diff --git a/isam/isamchk.c b/isam/isamchk.c
new file mode 100644
index 00000000000..97d190b7115
--- /dev/null
+++ b/isam/isamchk.c
@@ -0,0 +1,3448 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* Descript, check and repair of ISAM tables */
+
+#include "isamdef.h"
+
+#include <m_ctype.h>
+#include <stdarg.h>
+#include <getopt.h>
+#ifdef HAVE_SYS_VADVICE_H
+#include <sys/vadvise.h>
+#endif
+#ifdef HAVE_SYS_MMAN_H
+#include <sys/mman.h>
+#endif
+SET_STACK_SIZE(9000) /* Minimum stack size for program */
+
+#define T_VERBOSE 1
+#define T_SILENT 2
+#define T_DESCRIPT 4
+#define T_EXTEND 8
+#define T_INFO 16
+#define T_REP 32
+#define T_OPT 64 /* Not currently used */
+#define T_FORCE_CREATE 128
+#define T_WRITE_LOOP 256
+#define T_UNPACK 512
+#define T_STATISTICS 1024
+#define T_VERY_SILENT 2048
+#define T_SORT_RECORDS 4096
+#define T_SORT_INDEX 8192
+#define T_WAIT_FOREVER 16384
+#define T_REP_BY_SORT 32768
+
+
+#define O_NEW_INDEX 1 /* Bits set in out_flag */
+#define O_NEW_DATA 2
+
+#if defined(_MSC_VER) && !defined(__WIN__)
+#define USE_BUFFER_INIT 250L*1024L
+#define READ_BUFFER_INIT ((uint) 32768-MALLOC_OVERHEAD)
+#define SORT_BUFFER_INIT (uint) (65536L-MALLOC_OVERHEAD)
+#define MIN_SORT_BUFFER (1024*16-MALLOC_OVERHEAD)
+#else
+#define USE_BUFFER_INIT (((1024L*512L-MALLOC_OVERHEAD)/IO_SIZE)*IO_SIZE)
+#define READ_BUFFER_INIT (1024L*256L-MALLOC_OVERHEAD)
+#define SORT_BUFFER_INIT (2048L*1024L-MALLOC_OVERHEAD)
+#define MIN_SORT_BUFFER (4096-MALLOC_OVERHEAD)
+#endif
+
+#define NEAD_MEM ((uint) 10*4*(IO_SIZE+32)+32) /* Nead for recursion */
+#define MAXERR 20
+#define BUFFERS_WHEN_SORTING 16 /* Alloc for sort-key-tree */
+#define WRITE_COUNT MY_HOW_OFTEN_TO_WRITE
+#define INDEX_TMP_EXT ".TMM"
+#define DATA_TMP_EXT ".TMD"
+#define MYF_RW MYF(MY_NABP | MY_WME | MY_WAIT_IF_FULL)
+
+#define UPDATE_TIME 1
+#define UPDATE_STAT 2
+#define UPDATE_SORT 4
+
+typedef struct st_sort_key_blocks { /* Used when sorting */
+ uchar *buff,*end_pos;
+ uchar lastkey[N_MAX_POSSIBLE_KEY_BUFF];
+ uint last_length;
+ int inited;
+} SORT_KEY_BLOCKS;
+
+typedef struct st_sort_info {
+ N_INFO *info;
+ enum data_file_type new_data_file_type;
+ SORT_KEY_BLOCKS *key_block,*key_block_end;
+ uint key,find_length;
+ ulong pos,max_pos,filepos,start_recpos,filelength,dupp,max_records,unique,
+ buff_length;
+ my_bool fix_datafile;
+ char *record,*buff;
+ N_KEYDEF *keyinfo;
+ N_KEYSEG *keyseg;
+} SORT_INFO;
+
+enum options {OPT_CHARSETS_DIR=256};
+
+static ulong use_buffers=0,read_buffer_length=0,write_buffer_length=0,
+ sort_buffer_length=0,sort_key_blocks=0,crc=0,unique_count=0;
+static uint testflag=0,out_flag=0,warning_printed=0,error_printed=0,
+ rep_quick=0,verbose=0,opt_follow_links=1;
+static uint opt_sort_key=0,total_files=0,max_level=0,max_key=N_MAXKEY;
+static ulong keydata=0,totaldata=0,key_blocks=0;
+static ulong new_file_pos=0,record_checksum=0,key_file_blocks=0,decode_bits;
+static ulong total_records=0,total_deleted=0;
+static ulong search_after_block=NI_POS_ERROR;
+static byte *record_buff;
+static char **defaults_alloc;
+static const char *type_names[]=
+{ "?","text","binary", "short", "long", "float",
+ "double","number","unsigned short",
+ "unsigned long","longlong","ulonglong","int24",
+ "uint24","int8","?",},
+ *packed_txt="packed ",
+ *diff_txt="stripped ",
+ *field_pack[]={"","no endspace", "no prespace",
+ "no zeros", "blob", "constant", "table-lookup",
+ "always zero","?","?",};
+
+static char temp_filename[FN_REFLEN], *isam_file_name, *default_charset;
+static IO_CACHE read_cache;
+static SORT_INFO sort_info;
+static int tmpfile_createflag=O_RDWR | O_TRUNC | O_EXCL;
+
+static const char *load_default_groups[]= { "isamchk",0 };
+
+ /* Functions defined in this file */
+
+extern int main(int argc,char * *argv);
+extern void print_error _VARARGS((const char *fmt,...));
+static void print_warning _VARARGS((const char *fmt,...));
+static void print_info _VARARGS((const char *fmt,...));
+static int nisamchk(char *filename);
+static void get_options(int *argc,char * * *argv);
+static int chk_del(N_INFO *info,uint testflag);
+static int check_k_link(N_INFO *info,uint nr);
+static int chk_size(N_INFO *info);
+static int chk_key(N_INFO *info);
+static int chk_index(N_INFO *info,N_KEYDEF *keyinfo,ulong page,uchar *buff,
+ ulong *keys,uint level);
+static uint isam_key_length(N_INFO *info,N_KEYDEF *keyinfo);
+static unsigned long calc_checksum(ulong count);
+static int chk_data_link(N_INFO *info,int extend);
+static int rep(N_INFO *info,char *name);
+static int writekeys(N_INFO *info,byte *buff,ulong filepos);
+static void descript(N_INFO *info,char *name);
+static int movepoint(N_INFO *info,byte *record,ulong oldpos,ulong newpos,
+ uint prot_key);
+static void lock_memory(void);
+static int flush_blocks(File file);
+static int sort_records(N_INFO *,my_string,uint,int);
+static int sort_index(N_INFO *info,my_string name);
+static int sort_record_index(N_INFO *info,N_KEYDEF *keyinfo,ulong page,
+ uchar *buff,uint sortkey,File new_file);
+static int sort_one_index(N_INFO *info,N_KEYDEF *keyinfo,uchar *buff,
+ File new_file);
+static int change_to_newfile(const char * filename,const char * old_ext,
+ const char * new_ext);
+static int lock_file(File file,ulong start,int lock_type,const char* filetype,
+ const char *filename);
+static int filecopy(File to,File from,ulong start,ulong length,
+ const char * type);
+
+static void print_version(void);
+static int rep_by_sort(N_INFO *info,my_string name);
+static int sort_key_read(void *key);
+static int sort_get_next_record(void);
+static int sort_write_record(void);
+static int sort_key_cmp(const void *not_used, const void *a,const void *b);
+static int sort_key_write(const void *a);
+static ulong get_record_for_key(N_INFO *info,N_KEYDEF *keyinfo,
+ uchar *key);
+static int sort_insert_key(reg1 SORT_KEY_BLOCKS *key_block,uchar *key,
+ ulong prev_block);
+static int sort_delete_record(void);
+static void usage(void);
+static int flush_pending_blocks(void);
+static SORT_KEY_BLOCKS *alloc_key_blocks(uint blocks,uint buffer_length);
+static int test_if_almost_full(N_INFO *info);
+static int recreate_database(N_INFO **info,char *filename);
+static void save_integer(byte *pos,uint pack_length,ulong value);
+static int write_data_suffix(N_INFO *info);
+static int update_state_info(N_INFO *info,uint update);
+
+
+ /* Main program */
+
+int main(argc,argv)
+int argc;
+char **argv;
+{
+ int error;
+ MY_INIT(argv[0]);
+
+ get_options(&argc,(char***) &argv);
+ nisam_quick_table_bits=(uint) decode_bits;
+ error=0;
+ while (--argc >= 0)
+ {
+ error|= nisamchk(*(argv++));
+ VOID(fflush(stdout));
+ VOID(fflush(stderr));
+ if ((error_printed | warning_printed) && (testflag & T_FORCE_CREATE) &&
+ (!(testflag & (T_REP | T_REP_BY_SORT | T_SORT_RECORDS |
+ T_SORT_INDEX))))
+ {
+ testflag|=T_REP;
+ error|=nisamchk(argv[-1]);
+ testflag&= ~T_REP;
+ VOID(fflush(stdout));
+ VOID(fflush(stderr));
+ }
+ if (argc && (!(testflag & T_SILENT) || testflag & T_INFO))
+ {
+ puts("\n---------\n");
+ VOID(fflush(stdout));
+ }
+ }
+ if (total_files > 1)
+ { /* Only if descript */
+ if (!(testflag & T_SILENT) || testflag & T_INFO)
+ puts("\n---------\n");
+ printf("\nTotal of all %d ISAM-files:\nData records: %8lu Deleted blocks: %8lu\n",total_files,total_records,total_deleted);
+ }
+ free_defaults(defaults_alloc);
+ my_end(testflag & T_INFO ? MY_CHECK_ERROR | MY_GIVE_INFO : MY_CHECK_ERROR);
+ exit(error);
+#ifndef _lint
+ return 0; /* No compiler warning */
+#endif
+} /* main */
+
+
+static CHANGEABLE_VAR changeable_vars[] = {
+ { "key_buffer_size",(long*) &use_buffers,(long) USE_BUFFER_INIT,
+ (long) MALLOC_OVERHEAD, (long) ~0L,(long) MALLOC_OVERHEAD,(long) IO_SIZE },
+ { "read_buffer_size", (long*) &read_buffer_length,(long) READ_BUFFER_INIT,
+ (long) MALLOC_OVERHEAD,(long) ~0L,(long) MALLOC_OVERHEAD,(long) 1L },
+ { "write_buffer_size", (long*) &write_buffer_length,(long) READ_BUFFER_INIT,
+ (long) MALLOC_OVERHEAD,(long) ~0L,(long) MALLOC_OVERHEAD,(long) 1L },
+ { "sort_buffer_size",(long*) &sort_buffer_length,(long) SORT_BUFFER_INIT,
+ (long) (MIN_SORT_BUFFER+MALLOC_OVERHEAD),(long) ~0L,
+ (long) MALLOC_OVERHEAD,(long) 1L },
+ { "sort_key_blocks",(long*) &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,} };
+
+
+static struct option long_options[] =
+{
+ {"analyze", no_argument, 0, 'a'},
+ {"character-sets-dir", required_argument, 0, OPT_CHARSETS_DIR},
+#ifndef DBUG_OFF
+ {"debug", required_argument, 0, '#'},
+#endif
+ {"default-character-set", required_argument, 0, 'C'},
+ {"description", no_argument, 0, 'd'},
+ {"extend-check", no_argument, 0, 'e'},
+ {"information", no_argument, 0, 'i'},
+ {"force", no_argument, 0, 'f'},
+ {"help", no_argument, 0, '?'},
+ {"keys-used", required_argument, 0, 'k'},
+ {"no-symlinks", no_argument, 0, 'l'},
+ {"quick", no_argument, 0, 'q'},
+ {"recover", no_argument, 0, 'r'},
+ {"safe-recover", no_argument, 0, 'o'},
+ {"block-search", required_argument, 0, 'b'},
+ {"set-variable", required_argument, 0, 'O'},
+ {"silent", no_argument, 0, 's'},
+ {"sort-index", no_argument, 0, 'S'},
+ {"sort-records", required_argument, 0, 'R'},
+ {"unpack", no_argument, 0, 'u'},
+ {"verbose", no_argument, 0, 'v'},
+ {"version", no_argument, 0, 'V'},
+ {"wait", no_argument, 0, 'w'},
+ {0, 0, 0, 0}
+};
+
+static void print_version(void)
+{
+ printf("%s Ver 5.15 for %s at %s\n",my_progname,SYSTEM_TYPE,
+ MACHINE_TYPE);
+}
+
+static void usage(void)
+{
+ uint i;
+ print_version();
+ puts("TCX Datakonsult AB, by Monty, for your professional use");
+ puts("This software comes with NO WARRANTY: see the PUBLIC for details.\n");
+ puts("Description, check and repair of ISAM tables.");
+ puts("Used without options all tables on the command will be checked for errors");
+ printf("Usage: %s [OPTIONS] tables[.ISM]\n", my_progname);
+ puts("\n\
+ -a, --analyze Analyze distribution of keys. Will make some joins in\n\
+ MySQL faster.\n\
+ -#, --debug=... Output debug log. Often this is 'd:t:o,filename`\n\
+ --character-sets-dir=...\n\
+ Directory where character sets are\n\
+ -C, --default-character-set=...\n\
+ Set the default character set\n\
+ -d, --description Prints some information about table.\n\
+ -e, --extend-check Check the table VERY thoroughly. One need use this\n\
+ only in extreme cases as isamchk should normally find\n\
+ all errors even without this switch\n\
+ -f, --force Overwrite old temporary files.\n\
+ If one uses -f when checking tables (running isamchk\n\
+ without -r), isamchk will automatically restart with\n\
+ -r on any wrong table.\n\
+ -?, --help Display this help and exit.\n\
+ -i, --information Print statistics information about the table\n\
+ -k, --keys-used=# Used with '-r'. Tell ISAM to update only the first\n\
+ # keys. This can be used to get faster inserts!\n\
+ -l, --no-symlinks Do not follow symbolic links when repairing. Normally\n\
+ isamchk repairs the table a symlink points at.\n\
+ -q, --quick Used with -r to get a faster repair. (The data file\n\
+ isn't touched.) One can give a second '-q' to force\n\
+ isamchk to modify the original datafile.");
+ puts("\
+ -r, --recover Can fix almost anything except unique keys that aren't\n\
+ unique.\n\
+ -o, --safe-recover Uses old recovery method; slower than '-r' but can\n\
+ handle a couple of cases that '-r' cannot handle.\n\
+ -O, --set-variable var=option\n\
+ Change the value of a variable.\n\
+ -s, --silent Only print errors. One can use two -s to make isamchk\n\
+ very silent\n\
+ -S, --sort-index Sort index blocks. This speeds up 'read-next' in\n\
+ applications\n\
+ -R, --sort-records=#\n\
+ Sort records according to an index. This makes your\n\
+ data much more localized and may speed up things\n\
+ (It may be VERY slow to do a sort the first time!)\n\
+ -u, --unpack Unpack file packed with pack_isam.\n\
+ -v, --verbose Print more information. This can be used with\n\
+ -d and -e. Use many -v for more verbosity!\n\
+ -V, --version Print version and exit.\n\
+ -w, --wait Wait if table is locked.");
+ 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);
+}
+
+ /* Check table */
+
+static int nisamchk(my_string filename)
+{
+ int error,lock_type,recreate;
+ N_INFO *info;
+ File datafile;
+ char fixed_name[FN_REFLEN];
+ ISAM_SHARE *share;
+ DBUG_ENTER("nisamchk");
+
+ out_flag=error=warning_printed=error_printed=recreate=0;
+ datafile=0;
+ isam_file_name=filename; /* For error messages */
+ if (!(info=nisam_open(filename,
+ (testflag & T_DESCRIPT) ? O_RDONLY : O_RDWR,
+ (testflag & T_WAIT_FOREVER) ? HA_OPEN_WAIT_IF_LOCKED :
+ (testflag & T_DESCRIPT) ? HA_OPEN_IGNORE_IF_LOCKED :
+ HA_OPEN_ABORT_IF_LOCKED)))
+ {
+ /* Avoid twice printing of isam file name */
+ error_printed=1;
+ switch (my_errno) {
+ case HA_ERR_CRASHED:
+ print_error("'%s' is not a ISAM-table",filename);
+ break;
+ case HA_ERR_OLD_FILE:
+ print_error("'%s' is a old type of ISAM-table", filename);
+ break;
+ case HA_ERR_END_OF_FILE:
+ print_error("Couldn't read compleat header from '%s'", filename);
+ break;
+ case EAGAIN:
+ print_error("'%s' is locked. Use -w to wait until unlocked",filename);
+ break;
+ case ENOENT:
+ print_error("File '%s' doesn't exist",filename);
+ break;
+ case EACCES:
+ print_error("You don't have permission to use '%s'",filename);
+ break;
+ default:
+ print_error("%d when opening ISAM-table '%s'",
+ my_errno,filename);
+ break;
+ }
+ DBUG_RETURN(1);
+ }
+ share=info->s;
+ share->base.options&= ~HA_OPTION_READ_ONLY_DATA; /* We are modifing it */
+ share->r_locks=0;
+ if ((testflag & (T_REP_BY_SORT | T_REP | T_STATISTICS |
+ T_SORT_RECORDS | T_SORT_INDEX)) &&
+ ((testflag & T_UNPACK && share->data_file_type == COMPRESSED_RECORD) ||
+ share->state_length != sizeof(share->state) ||
+ uint2korr(share->state.header.base_info_length) !=
+ sizeof(share->base) ||
+ (max_key && ! share->state.keys && share->base.keys) ||
+ test_if_almost_full(info) ||
+ info->s->state.header.file_version[3] != nisam_file_magic[3]))
+ {
+ if (recreate_database(&info,filename))
+ {
+ VOID(fprintf(stderr,
+ "ISAM-table '%s' is not fixed because of errors\n",
+ filename));
+ return(-1);
+ }
+ recreate=1;
+ if (!(testflag & (T_REP | T_REP_BY_SORT)))
+ {
+ testflag|=T_REP_BY_SORT; /* if only STATISTICS */
+ if (!(testflag & T_SILENT))
+ printf("- '%s' has old table-format. Recreating index\n",filename);
+ if (!rep_quick)
+ rep_quick=1;
+ }
+ share=info->s;
+ share->r_locks=0;
+ }
+
+ if (testflag & T_DESCRIPT)
+ {
+ total_files++;
+ total_records+=share->state.records; total_deleted+=share->state.del;
+ descript(info,filename);
+ }
+ else
+ {
+ if (testflag & (T_REP+T_REP_BY_SORT+T_OPT+T_SORT_RECORDS+T_SORT_INDEX))
+ lock_type = F_WRLCK; /* table is changed */
+ else
+ lock_type= F_RDLCK;
+ if (info->lock_type == F_RDLCK)
+ info->lock_type=F_UNLCK; /* Read only table */
+ if (_nisam_readinfo(info,lock_type,0))
+ {
+ print_error("Can't lock indexfile of '%s', error: %d",
+ filename,my_errno);
+ error_printed=0;
+ goto end2;
+ }
+ share->w_locks++; /* Mark (for writeinfo) */
+ if (lock_file(info->dfile,0L,lock_type,"datafile of",filename))
+ goto end;
+ info->lock_type= F_EXTRA_LCK; /* Simulate as locked */
+ info->tmp_lock_type=lock_type;
+ datafile=info->dfile;
+ if (testflag & (T_REP+T_REP_BY_SORT+T_SORT_RECORDS+T_SORT_INDEX))
+ {
+ if (testflag & (T_REP+T_REP_BY_SORT))
+ share->state.keys=min(share->base.keys,max_key);
+ VOID(fn_format(fixed_name,filename,"",N_NAME_IEXT,
+ 4+ (opt_follow_links ? 16 : 0)));
+
+ if (rep_quick && (error=chk_del(info,testflag & ~T_VERBOSE)))
+ print_error("Quick-recover aborted; Run recovery without switch 'q'");
+ else
+ {
+ if (testflag & T_REP_BY_SORT &&
+ (share->state.keys || (rep_quick && !max_key && ! recreate)))
+ error=rep_by_sort(info,fixed_name);
+ else if (testflag & (T_REP | T_REP_BY_SORT))
+ error=rep(info,fixed_name);
+ }
+ if (!error && testflag & T_SORT_RECORDS)
+ {
+ if (out_flag & O_NEW_DATA)
+ { /* Change temp file to org file */
+ VOID(lock_file(datafile,0L,F_UNLCK,"datafile of",filename));
+ VOID(my_close(datafile,MYF(MY_WME))); /* Close old file */
+ VOID(my_close(info->dfile,MYF(MY_WME))); /* Close new file */
+ error|=change_to_newfile(fixed_name,N_NAME_DEXT,DATA_TMP_EXT);
+ if ((info->dfile=my_open(fn_format(temp_filename,fixed_name,"",
+ N_NAME_DEXT,2+4),
+ O_RDWR | O_SHARE,
+ MYF(MY_WME))) <= 0 ||
+ lock_file(info->dfile,0L,F_WRLCK,"datafile",temp_filename))
+ error=1;
+ out_flag&= ~O_NEW_DATA; /* We are using new datafile */
+ read_cache.file=info->dfile;
+ }
+ if (! error)
+ error=sort_records(info,fixed_name,opt_sort_key,
+ test(!(testflag & T_REP)));
+ datafile=info->dfile; /* This is now locked */
+ }
+ if (!error && testflag & T_SORT_INDEX)
+ error=sort_index(info,fixed_name);
+ }
+ else
+ {
+ if (!(testflag & T_SILENT) || testflag & T_INFO)
+ printf("Checking ISAM file: %s\n",filename);
+ if (!(testflag & T_SILENT))
+ printf("Data records: %7ld Deleted blocks: %7ld\n",
+ share->state.records,share->state.del);
+ share->state.keys=min(share->state.keys,max_key);
+ error =chk_size(info);
+ error|=chk_del(info,testflag);
+ error|=chk_key(info);
+ if (!rep_quick)
+ {
+ if (testflag & T_EXTEND)
+ VOID(init_key_cache(use_buffers,(uint) NEAD_MEM));
+ VOID(init_io_cache(&read_cache,datafile,(uint) read_buffer_length,
+ READ_CACHE,share->pack.header_length,1,
+ MYF(MY_WME)));
+ lock_memory();
+ error|=chk_data_link(info,testflag & T_EXTEND);
+ error|=flush_blocks(share->kfile);
+ VOID(end_io_cache(&read_cache));
+ }
+ }
+ }
+end:
+ if (!(testflag & T_DESCRIPT))
+ {
+ if (info->update & (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED))
+ error|=update_state_info(info,
+ ((testflag & (T_REP | T_REP_BY_SORT)) ?
+ UPDATE_TIME | UPDATE_STAT : 0) |
+ ((testflag & T_SORT_RECORDS) ?
+ UPDATE_SORT : 0));
+ VOID(lock_file(share->kfile,0L,F_UNLCK,"indexfile",filename));
+ if (datafile > 0)
+ VOID(lock_file(datafile,0L,F_UNLCK,"datafile of",filename));
+ info->update&= ~(HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
+ }
+ share->w_locks--;
+end2:
+ if (datafile && datafile != info->dfile)
+ VOID(my_close(datafile,MYF(MY_WME)));
+ if (nisam_close(info))
+ {
+ print_error("%d when closing ISAM-table '%s'",my_errno,filename);
+ DBUG_RETURN(1);
+ }
+ if (error == 0)
+ {
+ if (out_flag & O_NEW_DATA)
+ error|=change_to_newfile(fixed_name,N_NAME_DEXT,DATA_TMP_EXT);
+ if (out_flag & O_NEW_INDEX)
+ error|=change_to_newfile(fixed_name,N_NAME_IEXT,INDEX_TMP_EXT);
+ }
+ VOID(fflush(stdout)); VOID(fflush(stderr));
+ if (error_printed)
+ {
+ if (testflag & (T_REP+T_REP_BY_SORT+T_SORT_RECORDS+T_SORT_INDEX))
+ VOID(fprintf(stderr,
+ "ISAM-table '%s' is not fixed because of errors\n",
+ filename));
+ else if (! (error_printed & 2) && !(testflag & T_FORCE_CREATE))
+ VOID(fprintf(stderr,
+ "ISAM-table '%s' is corrupted\nFix it using switch \"-r\" or \"-o\"\n",
+ filename));
+ }
+ else if (warning_printed &&
+ ! (testflag & (T_REP+T_REP_BY_SORT+T_SORT_RECORDS+T_SORT_INDEX+
+ T_FORCE_CREATE)))
+ VOID(fprintf(stderr, "ISAM-table '%s' is useable but should be fixed\n",
+ filename));
+ VOID(fflush(stderr));
+ DBUG_RETURN(error);
+} /* nisamchk */
+
+
+ /* Read options */
+
+static void get_options(register int *argc,register char ***argv)
+{
+ int c,option_index=0;
+
+ load_defaults("my",load_default_groups,argc,argv);
+ defaults_alloc= *argv;
+ set_all_changeable_vars(changeable_vars);
+ if (isatty(fileno(stdout)))
+ testflag|=T_WRITE_LOOP;
+ while ((c=getopt_long(*argc,*argv,"adeif?lqrosSuvVw#:b:k:O:R:C:",
+ long_options, &option_index)) != EOF)
+ {
+ switch(c) {
+ case 'a':
+ testflag|= T_STATISTICS;
+ break;
+ case 'C':
+ default_charset=optarg;
+ break;
+ case OPT_CHARSETS_DIR:
+ charsets_dir = optarg;
+ break;
+ case 'b':
+ search_after_block=strtoul(optarg,NULL,10);
+ break;
+ case 's': /* silent */
+ if (testflag & T_SILENT)
+ testflag|=T_VERY_SILENT;
+ testflag|= T_SILENT;
+ testflag&= ~T_WRITE_LOOP;
+ break;
+ case 'w':
+ testflag|= T_WAIT_FOREVER;
+ break;
+ case 'd': /* description if isam-file */
+ testflag|= T_DESCRIPT;
+ break;
+ case 'e': /* extend check */
+ testflag|= T_EXTEND;
+ break;
+ case 'i':
+ testflag|= T_INFO;
+ break;
+ case 'f':
+ tmpfile_createflag= O_RDWR | O_TRUNC;
+ testflag|=T_FORCE_CREATE;
+ break;
+ case 'k':
+ max_key= (uint) atoi(optarg);
+ break;
+ case 'l':
+ opt_follow_links=0;
+ break;
+ case 'r': /* Repair table */
+ testflag= (testflag & ~T_REP) | T_REP_BY_SORT;
+ break;
+ case 'o':
+ testflag= (testflag & ~T_REP_BY_SORT) | T_REP;
+ my_disable_async_io=1; /* More safety */
+ break;
+ case 'q':
+ rep_quick++;
+ break;
+ case 'u':
+ testflag|= T_UNPACK | T_REP_BY_SORT;
+ break;
+ case 'v': /* Verbose */
+ testflag|= T_VERBOSE;
+ verbose++;
+ break;
+ case 'O':
+ if (set_changeable_var(optarg, changeable_vars))
+ {
+ usage();
+ exit(1);
+ }
+ break;
+ case 'R': /* Sort records */
+ testflag|= T_SORT_RECORDS;
+ opt_sort_key=(uint) atoi(optarg)-1;
+ if (opt_sort_key >= N_MAXKEY)
+ {
+ fprintf(stderr,
+ "The value of the sort key is bigger than max key: %d.\n",
+ N_MAXKEY);
+ exit(1);
+ }
+ break;
+ case 'S': /* Sort index */
+ testflag|= T_SORT_INDEX;
+ break;
+ case '#':
+ DBUG_PUSH(optarg ? optarg : "d:t:o,/tmp/isamchk.trace");
+ break;
+ case 'V':
+ print_version();
+ exit(0);
+ case '?':
+ usage();
+ exit(0);
+ }
+ }
+ (*argc)-=optind;
+ (*argv)+=optind;
+ if (*argc == 0)
+ {
+ usage();
+ exit(-1);
+ }
+ if ((testflag & T_UNPACK) && (rep_quick || (testflag & T_SORT_RECORDS)))
+ {
+ VOID(fprintf(stderr,
+ "%s: --unpack can't be used with --quick or --sort-records\n",
+ my_progname));
+ exit(1);
+ }
+ if (default_charset)
+ {
+ if (set_default_charset_by_name(default_charset, MYF(MY_WME)))
+ exit(1);
+ }
+ return;
+} /* get options */
+
+
+ /* Check delete links */
+
+static int chk_del(info,test_flag)
+reg1 N_INFO *info;
+uint test_flag;
+{
+ reg2 ulong i;
+ uint j,delete_link_length;
+ ulong empty,next_link;
+ uchar buff[8];
+ DBUG_ENTER("chk_del");
+ if (!(test_flag & T_SILENT)) puts("- check delete-chain");
+
+ record_checksum=0L;
+ key_file_blocks=info->s->base.keystart;
+ for (j =0 ; j < info->s->state.keys ; j++)
+ if (check_k_link(info,j))
+ goto wrong;
+ delete_link_length=(info->s->base.options & HA_OPTION_PACK_RECORD) ? 8 : 5;
+
+ next_link=info->s->state.dellink;
+ if (info->s->state.del == 0)
+ {
+ if (test_flag & T_VERBOSE)
+ {
+ puts("No recordlinks");
+ }
+ }
+ else
+ {
+ if (test_flag & T_VERBOSE)
+ printf("Recordlinks: ");
+ empty=0;
+ for (i= info->s->state.del ; i > 0L && next_link != NI_POS_ERROR ; i--)
+ {
+ if (test_flag & T_VERBOSE) printf("%10lu",next_link);
+ if (next_link >= info->s->state.data_file_length)
+ goto wrong;
+ if (my_pread(info->dfile,(char*) buff,delete_link_length,
+ next_link,MYF(MY_NABP)))
+ {
+ if (test_flag & T_VERBOSE) puts("");
+ print_error("Can't read delete-link at filepos: %lu",
+ (ulong) next_link);
+ DBUG_RETURN(1);
+ }
+ if (*buff != '\0')
+ {
+ if (test_flag & T_VERBOSE) puts("");
+ print_error("Record at pos: %lu is not remove-marked",
+ (ulong) next_link);
+ goto wrong;
+ }
+ if (info->s->base.options & HA_OPTION_PACK_RECORD)
+ {
+ next_link=uint4korr(buff+4);
+ empty+=uint3korr(buff+1);
+ }
+ else
+ {
+ record_checksum+=next_link;
+ next_link=uint4korr(buff+1);
+ empty+=info->s->base.reclength;
+ }
+ if (next_link == (uint32) ~0) /* Fix for 64 bit long */
+ next_link=NI_POS_ERROR;
+ }
+ if (empty != info->s->state.empty)
+ {
+ if (test_flag & T_VERBOSE) puts("");
+ print_warning("Not used space is supposed to be: %lu but is: %lu",
+ (ulong) info->s->state.empty,(ulong) empty);
+ info->s->state.empty=empty;
+ }
+ if (i != 0 || next_link != NI_POS_ERROR)
+ goto wrong;
+
+ if (test_flag & T_VERBOSE) puts("\n");
+ }
+ DBUG_RETURN(0);
+wrong:
+ if (test_flag & T_VERBOSE) puts("");
+ print_error("delete-link-chain corrupted");
+ DBUG_RETURN(1);
+} /* chk_del */
+
+
+ /* Kontrollerar l{nkarna i nyckelfilen */
+
+static int check_k_link(info,nr)
+register N_INFO *info;
+uint nr;
+{
+ ulong next_link,records;
+ DBUG_ENTER("check_k_link");
+
+ if (testflag & T_VERBOSE)
+ printf("index %2d: ",nr+1);
+
+ next_link=info->s->state.key_del[nr];
+ records= (info->s->state.key_file_length /
+ info->s->keyinfo[nr].base.block_length);
+ while (next_link != NI_POS_ERROR && records > 0)
+ {
+ if (testflag & T_VERBOSE) printf("%10lu",next_link);
+ if (next_link > info->s->state.key_file_length ||
+ next_link & (info->s->blocksize-1))
+ DBUG_RETURN(1);
+ if (my_pread(info->s->kfile,(char*) &next_link,sizeof(long),next_link,
+ MYF(MY_NABP)))
+ DBUG_RETURN(1);
+ records--;
+ key_file_blocks+=info->s->keyinfo[nr].base.block_length;
+ }
+ if (testflag & T_VERBOSE)
+ {
+ if (next_link != NI_POS_ERROR)
+ printf("%10lu\n",next_link);
+ else
+ puts("");
+ }
+ DBUG_RETURN (next_link != NI_POS_ERROR);
+} /* check_k_link */
+
+
+ /* Kontrollerar storleken p} filerna */
+
+static int chk_size(register N_INFO *info)
+{
+ int error=0;
+ register my_off_t skr,size;
+ DBUG_ENTER("chk_size");
+
+ if (!(testflag & T_SILENT)) puts("- check file-size");
+
+ size=my_seek(info->s->kfile,0L,MY_SEEK_END,MYF(0));
+ if ((skr=(my_off_t) info->s->state.key_file_length) != size)
+ {
+ if (skr > size)
+ {
+ error=1;
+ print_error("Size of indexfile is: %-8lu Should be: %lu",
+ (ulong) size, (ulong) skr);
+ }
+ else
+ print_warning("Size of indexfile is: %-8lu Should be: %lu",
+ (ulong) size,(ulong) skr);
+ }
+ if (!(testflag & T_VERY_SILENT) &&
+ ! (info->s->base.options & HA_OPTION_COMPRESS_RECORD) &&
+ info->s->state.key_file_length >
+ (ulong) (ulong_to_double(info->s->base.max_key_file_length)*0.9))
+ print_warning("Keyfile is almost full, %10lu of %10lu used",
+ info->s->state.key_file_length,
+ info->s->base.max_key_file_length-1);
+
+ size=my_seek(info->dfile,0L,MY_SEEK_END,MYF(0));
+ skr=(my_off_t) info->s->state.data_file_length;
+ if (info->s->base.options & HA_OPTION_COMPRESS_RECORD)
+ skr+= MEMMAP_EXTRA_MARGIN;
+#ifdef USE_RELOC
+ if (info->data_file_type == STATIC_RECORD &&
+ skr < (my_off_t) info->s->base.reloc*info->s->base.min_pack_length)
+ skr=(my_off_t) info->s->base.reloc*info->s->base.min_pack_length;
+#endif
+ if (skr != size)
+ {
+ info->s->state.data_file_length=(ulong) size; /* Skipp other errors */
+ if (skr > size && skr != size + MEMMAP_EXTRA_MARGIN)
+ {
+ error=1;
+ print_error("Size of datafile is: %-8lu Should be: %lu",
+ (ulong) size,(ulong) skr);
+ }
+ else
+ {
+ print_warning("Size of datafile is: %-8lu Should be: %lu",
+ (ulong) size,(ulong) skr);
+
+ }
+ }
+ if (!(testflag & T_VERY_SILENT) &&
+ !(info->s->base.options & HA_OPTION_COMPRESS_RECORD) &&
+ info->s->state.data_file_length >
+ (ulong) (ulong_to_double(info->s->base.max_data_file_length)*0.9))
+ print_warning("Datafile is almost full, %10lu of %10lu used",
+ info->s->state.data_file_length,
+ info->s->base.max_data_file_length-1);
+ DBUG_RETURN(error);
+} /* chk_size */
+
+
+ /* Kontrollerar nycklarna */
+
+static int chk_key(info)
+register N_INFO *info;
+{
+ uint key;
+ ulong keys,all_keydata,all_totaldata,key_totlength,length,
+ init_checksum,old_record_checksum;
+ ISAM_SHARE *share=info->s;
+ N_KEYDEF *keyinfo;
+ DBUG_ENTER("chk_key");
+
+ if (!(testflag & T_SILENT)) puts("- check index reference");
+
+ all_keydata=all_totaldata=key_totlength=old_record_checksum=0;
+ init_checksum=record_checksum;
+ if (!(share->base.options &
+ (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)))
+ old_record_checksum=calc_checksum(share->state.records+share->state.del-1)*
+ share->base.reclength;
+ for (key= 0,keyinfo= &share->keyinfo[0]; key < share->state.keys ;
+ key++,keyinfo++)
+ {
+ record_checksum=init_checksum;
+ unique_count=0L;
+ if ((!(testflag & T_SILENT)) && share->state.keys >1)
+ printf ("- check data record references index: %d\n",key+1);
+ if (share->state.key_root[key] == NI_POS_ERROR &&
+ share->state.records == 0)
+ continue;
+ if (!_nisam_fetch_keypage(info,keyinfo,share->state.key_root[key],info->buff,
+ 0))
+ {
+ print_error("Can't read indexpage from filepos: %lu",
+ (ulong) share->state.key_root[key]);
+ DBUG_RETURN(-1);
+ }
+ key_file_blocks+=keyinfo->base.block_length;
+ keys=keydata=totaldata=key_blocks=0; max_level=0;
+ if (chk_index(info,keyinfo,share->state.key_root[key],info->buff,&keys,1))
+ DBUG_RETURN(-1);
+ if (keys != share->state.records)
+ {
+ print_error("Found %lu keys of %lu",(ulong) keys,
+ (ulong) share->state.records);
+ DBUG_RETURN(-1);
+ }
+ if (!key && (share->base.options &
+ (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)))
+ old_record_checksum=record_checksum;
+ else if (old_record_checksum != record_checksum)
+ {
+ if (key)
+ print_error("Key %u doesn't point at same records that key 1",
+ key+1);
+ else
+ print_error("Key 1 doesn't point at all records");
+ DBUG_RETURN(-1);
+ }
+ length=(ulong) isam_key_length(info,keyinfo)*keys + key_blocks*2;
+ if (testflag & T_INFO && totaldata != 0L && keys != 0L)
+ printf("Key: %2d: Keyblocks used: %3d%% Packed: %4d%% Max levels: %2d\n",
+ key+1,
+ (int) (keydata*100.0/totaldata),
+ (int) ((long) (length-keydata)*100.0/(double) length),
+ max_level);
+ all_keydata+=keydata; all_totaldata+=totaldata; key_totlength+=length;
+ share->base.rec_per_key[key]=
+ unique_count ? ((share->state.records+unique_count/2)/
+ unique_count) : 1L;
+ }
+ if (testflag & T_INFO)
+ {
+ if (all_totaldata != 0L && share->state.keys != 1)
+ printf("Total: Keyblocks used: %3d%% Packed: %4d%%\n\n",
+ (int) (all_keydata*100.0/all_totaldata),
+ (int) ((long) (key_totlength-all_keydata)*100.0/
+ (double) key_totlength));
+ else if (all_totaldata != 0L && share->state.keys)
+ puts("");
+ }
+ if (key_file_blocks != share->state.key_file_length)
+ print_warning("Some data are unreferenced in keyfile");
+ record_checksum-=init_checksum; /* Remove delete links */
+ if (testflag & T_STATISTICS)
+ DBUG_RETURN(update_state_info(info,UPDATE_STAT));
+ DBUG_RETURN(0);
+} /* chk_key */
+
+
+ /* Check if index is ok */
+
+static int chk_index(info,keyinfo,page,buff,keys,level)
+N_INFO *info;
+N_KEYDEF *keyinfo;
+ulong page,*keys;
+uchar *buff;
+uint level;
+{
+ int flag;
+ uint used_length,comp_flag,nod_flag;
+ uchar key[N_MAX_POSSIBLE_KEY_BUFF],*temp_buff,*keypos,*endpos;
+ ulong next_page,record;
+ DBUG_ENTER("chk_index");
+ DBUG_DUMP("buff",(byte*) buff,getint(buff));
+
+ if (!(temp_buff=(uchar*) my_alloca((uint) keyinfo->base.block_length)))
+ {
+ print_error("Not Enough memory");
+ DBUG_RETURN(-1);
+ }
+
+ if (keyinfo->base.flag & HA_NOSAME)
+ comp_flag=SEARCH_FIND; /* Not dupplicates */
+ else
+ comp_flag=SEARCH_SAME; /* Keys in positionorder */
+ nod_flag=test_if_nod(buff);
+ used_length=getint(buff);
+ keypos=buff+2+nod_flag;
+ endpos=buff+used_length;
+
+ keydata+=used_length; totaldata+=keyinfo->base.block_length; /* INFO */
+ key_blocks++;
+ if (level > max_level)
+ max_level=level;
+
+ if (used_length > keyinfo->base.block_length)
+ {
+ print_error("Wrong pageinfo at page: %lu",(ulong) page);
+ goto err;
+ }
+ for ( ;; )
+ {
+ if (nod_flag)
+ {
+ next_page=_nisam_kpos(nod_flag,keypos);
+ if (next_page > info->s->state.key_file_length ||
+ (nod_flag && (next_page & (info->s->blocksize -1))))
+ {
+ my_off_t max_length=my_seek(info->s->kfile,0L,MY_SEEK_END,MYF(0));
+ print_error("Wrong pagepointer: %lu at page: %lu",
+ (ulong) next_page,(ulong) page);
+
+ if (next_page+info->s->blocksize > max_length)
+ goto err;
+ info->s->state.key_file_length=(ulong) (max_length &
+ ~ (my_off_t)
+ (info->s->blocksize-1));
+ }
+ if (!_nisam_fetch_keypage(info,keyinfo,next_page,temp_buff,0))
+ {
+ print_error("Can't read key from filepos: %lu",(ulong) next_page);
+ goto err;
+ }
+ key_file_blocks+=keyinfo->base.block_length;
+ if (chk_index(info,keyinfo,next_page,temp_buff,keys,level+1))
+ goto err;
+ }
+ if (keypos >= endpos ||
+ (*keyinfo->get_key)(keyinfo,nod_flag,&keypos,key) == 0)
+ break;
+ if ((*keys)++ &&
+ (flag=_nisam_key_cmp(keyinfo->seg,info->lastkey,key,0,comp_flag)) >=0)
+ {
+ DBUG_DUMP("old",(byte*) info->lastkey,
+ _nisam_keylength(keyinfo,info->lastkey));
+ DBUG_DUMP("new",(byte*) key,_nisam_keylength(keyinfo,key));
+
+ if (comp_flag == SEARCH_FIND && flag == 0)
+ print_error("Found dupplicated key at page %lu",(ulong) page);
+ else
+ print_error("Key in wrong position at page %lu",(ulong) page);
+ goto err;
+ }
+ if (testflag & T_STATISTICS)
+ {
+ if (*keys == 1L ||
+ _nisam_key_cmp(keyinfo->seg,info->lastkey,key,0,SEARCH_FIND))
+ unique_count++;
+ }
+ VOID(_nisam_move_key(keyinfo,(uchar*) info->lastkey,key));
+ record= _nisam_dpos(info,nod_flag,keypos);
+ if (record >= info->s->state.data_file_length)
+ {
+ print_error("Found key at page %lu that points to record outside datafile",page);
+ DBUG_PRINT("test",("page: %lu record: %lu filelength: %lu",
+ (ulong) page,(ulong) record,
+ (ulong) info->s->state.data_file_length));
+ DBUG_DUMP("key",(byte*) info->lastkey,info->s->base.max_key_length);
+ goto err;
+ }
+ record_checksum+=record;
+ }
+ if (keypos != endpos)
+ {
+ print_error("Keyblock size at page %lu is not correct. Block length: %d key length: %d",(ulong) page, used_length, (keypos - buff));
+ goto err;
+ }
+ my_afree((byte*) temp_buff);
+ DBUG_RETURN(0);
+ err:
+ my_afree((byte*) temp_buff);
+ DBUG_RETURN(1);
+} /* chk_index */
+
+
+ /* Calculate a checksum of 1+2+3+4...N = N*(N+1)/2 without overflow */
+
+static ulong calc_checksum(count)
+ulong count;
+{
+ ulong sum,a,b;
+ DBUG_ENTER("calc_checksum");
+
+ sum=0;
+ a=count; b=count+1;
+ if (a & 1)
+ b>>=1;
+ else
+ a>>=1;
+ while (b)
+ {
+ if (b & 1)
+ sum+=a;
+ a<<=1; b>>=1;
+ }
+ DBUG_PRINT("exit",("sum: %lx",sum));
+ DBUG_RETURN(sum);
+} /* calc_checksum */
+
+
+ /* Calc length of key in normal isam */
+
+static uint isam_key_length(info,keyinfo)
+N_INFO *info;
+reg1 N_KEYDEF *keyinfo;
+{
+ uint length;
+ N_KEYSEG *keyseg;
+ DBUG_ENTER("isam_key_length");
+
+ length= info->s->rec_reflength;
+ for (keyseg=keyinfo->seg ; keyseg->base.type ; keyseg++)
+ length+= keyseg->base.length;
+
+ DBUG_PRINT("exit",("length: %d",length));
+ DBUG_RETURN(length);
+} /* key_length */
+
+
+ /* Check that record-link is ok */
+
+static int chk_data_link(info,extend)
+reg1 N_INFO *info;
+int extend;
+{
+ int error,got_error,flag;
+ uint key,left_length,b_type;
+ ulong records,del_blocks,used,empty,pos,splitts,start_recpos,
+ del_length,link_used,intern_record_checksum,start_block;
+ byte *record,*to;
+ N_KEYDEF *keyinfo;
+ BLOCK_INFO block_info;
+ DBUG_ENTER("chk_data_link");
+
+ if (! (info->s->base.options & (HA_OPTION_PACK_RECORD |
+ HA_OPTION_COMPRESS_RECORD)) &&
+ ! extend)
+ DBUG_RETURN(0);
+
+ if (!(testflag & T_SILENT))
+ {
+ if (extend)
+ puts("- check records and index references");
+ else
+ puts("- check record links");
+ }
+
+ if (!(record= (byte*) my_alloca(info->s->base.reclength)))
+ {
+ print_error("Not Enough memory");
+ DBUG_RETURN(-1);
+ }
+ records=used=link_used=splitts=del_blocks=del_length=
+ intern_record_checksum=crc=0L;
+ LINT_INIT(left_length); LINT_INIT(start_recpos); LINT_INIT(to);
+ got_error=error=0;
+ empty=pos=info->s->pack.header_length;
+
+ while (pos < info->s->state.data_file_length)
+ {
+ switch (info->s->data_file_type) {
+ case STATIC_RECORD:
+ if (my_b_read(&read_cache,(byte*) record,info->s->base.reclength))
+ goto err;
+ start_recpos=pos;
+ pos+=info->s->base.reclength;
+ splitts++;
+ if (*record == '\0')
+ {
+ del_blocks++;
+ del_length+=info->s->base.reclength;
+ continue; /* Record removed */
+ }
+ used+=info->s->base.reclength;
+ break;
+ case DYNAMIC_RECORD:
+ flag=block_info.second_read=0;
+ block_info.next_filepos=pos;
+ do
+ {
+ if (_nisam_read_cache(&read_cache,(byte*) block_info.header,
+ (start_block=block_info.next_filepos),
+ sizeof(block_info.header),test(! flag) | 2))
+ goto err;
+ b_type=_nisam_get_block_info(&block_info,-1,start_block);
+ if (b_type & (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR |
+ BLOCK_FATAL_ERROR))
+ {
+ if (b_type & BLOCK_SYNC_ERROR)
+ {
+ if (flag)
+ {
+ print_error("Unexpected byte: %d at link: %lu",
+ (int) block_info.header[0],(ulong) start_block);
+ goto err2;
+ }
+ pos=block_info.filepos+block_info.block_len;
+ goto next;
+ }
+ if (b_type & BLOCK_DELETED)
+ {
+ if (block_info.block_len < info->s->base.min_block_length ||
+ block_info.block_len-4 > (uint) info->s->base.max_pack_length)
+ {
+ print_error("Deleted block with impossible length %u at %lu",
+ block_info.block_len,(ulong) pos);
+ goto err2;
+ }
+ del_blocks++;
+ del_length+=block_info.block_len;
+ pos=block_info.filepos+block_info.block_len;
+ splitts++;
+ goto next;
+ }
+ print_error("Wrong bytesec: %d-%d-%d at linkstart: %lu",
+ block_info.header[0],block_info.header[1],
+ block_info.header[2],(ulong) start_block);
+ goto err2;
+ }
+ if (info->s->state.data_file_length < block_info.filepos+
+ block_info.block_len)
+ {
+ print_error("Recordlink that points outside datafile at %lu",
+ (ulong) pos);
+ got_error=1;
+ break;
+ }
+ splitts++;
+ if (!flag++) /* First block */
+ {
+ start_recpos=pos;
+ pos=block_info.filepos+block_info.block_len;
+ if (block_info.rec_len > (uint) info->s->base.max_pack_length)
+ {
+ print_error("Found too long record at %lu",(ulong) start_recpos);
+ got_error=1;
+ break;
+ }
+ if (info->s->base.blobs)
+ {
+ if (!(to=fix_rec_buff_for_blob(info,block_info.rec_len)))
+ {
+ print_error("Not enough memory for blob at %lu",
+ (ulong) start_recpos);
+ got_error=1;
+ break;
+ }
+ }
+ else
+ to= info->rec_buff;
+ left_length=block_info.rec_len;
+ }
+ if (left_length < block_info.data_len)
+ {
+ print_error("Found too long record at %lu",(ulong) start_recpos);
+ got_error=1; break;
+ }
+ if (_nisam_read_cache(&read_cache,(byte*) to,block_info.filepos,
+ (uint) block_info.data_len, test(flag == 1)))
+ goto err;
+ to+=block_info.data_len;
+ link_used+= block_info.filepos-start_block;
+ used+= block_info.filepos - start_block + block_info.data_len;
+ empty+=block_info.block_len-block_info.data_len;
+ left_length-=block_info.data_len;
+ if (left_length)
+ {
+ if (b_type & BLOCK_LAST)
+ {
+ print_error("Record link to short for record at %lu",
+ (ulong) start_recpos);
+ got_error=1;
+ break;
+ }
+ if (info->s->state.data_file_length < block_info.next_filepos)
+ {
+ print_error("Found next-recordlink that points outside datafile at %lu",
+ (ulong) block_info.filepos);
+ got_error=1;
+ break;
+ }
+ }
+ } while (left_length);
+ if (! got_error)
+ {
+ if (_nisam_rec_unpack(info,record,info->rec_buff,block_info.rec_len) ==
+ MY_FILE_ERROR)
+ {
+ print_error("Found wrong record at %lu",(ulong) start_recpos);
+ got_error=1;
+ }
+ if (testflag & (T_EXTEND | T_VERBOSE))
+ {
+ if (_nisam_rec_check(info,record))
+ {
+ print_error("Found wrong packed record at %lu",
+ (ulong) start_recpos);
+ got_error=1;
+ }
+ }
+ }
+ else if (!flag)
+ pos=block_info.filepos+block_info.block_len;
+ break;
+ case COMPRESSED_RECORD:
+ if (_nisam_read_cache(&read_cache,(byte*) block_info.header,pos, 3,1))
+ goto err;
+ start_recpos=pos;
+ splitts++;
+ VOID(_nisam_pack_get_block_info(&block_info,info->s->pack.ref_length,-1,
+ start_recpos));
+ pos=start_recpos+info->s->pack.ref_length+block_info.rec_len;
+ if (block_info.rec_len < (uint) info->s->min_pack_length ||
+ block_info.rec_len > (uint) info->s->max_pack_length)
+ {
+ print_error("Found block with wrong recordlength: %d at %lu",
+ block_info.rec_len,(ulong) start_recpos);
+ got_error=1;
+ break;
+ }
+ if (_nisam_read_cache(&read_cache,(byte*) info->rec_buff,
+ block_info.filepos, block_info.rec_len,1))
+ goto err;
+ if (_nisam_pack_rec_unpack(info,record,info->rec_buff,block_info.rec_len))
+ {
+ print_error("Found wrong record at %lu",(ulong) start_recpos);
+ got_error=1;
+ }
+ crc^=checksum(record,info->s->base.reclength);
+ link_used+=info->s->pack.ref_length;
+ used+=block_info.rec_len+info->s->pack.ref_length;
+ }
+ if (! got_error)
+ {
+ intern_record_checksum+=start_recpos;
+ records++;
+ if (testflag & T_WRITE_LOOP && records % WRITE_COUNT == 0)
+ {
+ printf("%lu\r",(ulong) records); VOID(fflush(stdout));
+ }
+
+ if (extend)
+ {
+ for (key=0,keyinfo= info->s->keyinfo; key<info->s->state.keys;
+ key++,keyinfo++)
+ {
+ VOID(_nisam_make_key(info,key,info->lastkey,record,start_recpos));
+ if (_nisam_search(info,keyinfo,info->lastkey,0,SEARCH_SAME,
+ info->s->state.key_root[key]))
+ {
+ print_error("Record at: %10lu Can't find key for index: %2d",
+ start_recpos,key+1);
+ if (error++ > MAXERR || !(testflag & T_VERBOSE))
+ goto err2;
+ }
+ }
+ }
+ }
+ else
+ {
+ got_error=0;
+ if (error++ > MAXERR || !(testflag & T_VERBOSE))
+ goto err2;
+ }
+ next:; /* Next record */
+ }
+ if (testflag & T_WRITE_LOOP)
+ {
+ VOID(fputs(" \r",stdout)); VOID(fflush(stdout));
+ }
+ if (records != info->s->state.records)
+ {
+ print_error("Record-count is not ok; is %-10lu Should be: %lu",
+ (ulong) records,(ulong) info->s->state.records);
+ error=1;
+ }
+ else if (record_checksum != intern_record_checksum && info->s->state.keys)
+ {
+ print_error("Keypointers and records dosen't match");
+ error=1;
+ }
+ if (used+empty+del_length != info->s->state.data_file_length)
+ {
+ print_warning("Found %lu record-data and %lu unused data and %lu deleted-data\nTotal %lu, Should be: %lu",
+ (ulong) used,(ulong) empty,(ulong) del_length,
+ (ulong) (used+empty+del_length),
+ (ulong) info->s->state.data_file_length);
+ }
+ if (del_blocks != info->s->state.del)
+ {
+ print_warning("Found %10lu deleted blocks Should be: %lu",
+ (ulong) del_blocks,(ulong) info->s->state.del);
+ }
+ if (splitts != info->s->state.splitt)
+ {
+ print_warning("Found %10lu parts Should be: %lu parts",
+ (ulong) splitts,(ulong) info->s->state.splitt);
+ }
+ if ((info->s->base.options & HA_OPTION_COMPRESS_RECORD) &&
+ crc != info->s->state.uniq)
+ print_warning("Wrong checksum for records; Restore uncompressed table");
+
+ if (testflag & T_INFO)
+ {
+ if (warning_printed || error_printed)
+ puts("");
+ if (used != 0 && ! error_printed)
+ {
+ printf("Records:%17lu M.recordlength:%8lu Packed:%14.0f%%\n",
+ records, (used-link_used)/records,
+ (info->s->base.blobs ? 0 :
+ (ulong_to_double(info->s->base.reclength*records)-used)/
+ ulong_to_double(info->s->base.reclength*records)*100.0));
+ printf("Recordspace used:%8.0f%% Empty space:%11d%% Blocks/Record: %6.2f\n",
+ (ulong_to_double(used-link_used)/ulong_to_double(used-link_used+empty)*100.0),
+ (!records ? 100 : (int) (ulong_to_double(del_length+empty)/used*100.0)),
+ ulong_to_double(splitts - del_blocks) / records);
+ }
+ printf("Record blocks:%12lu Delete blocks:%10lu\n",
+ splitts-del_blocks,del_blocks);
+ printf("Record data: %12lu Deleted data :%10lu\n",
+ used-link_used,del_length);
+ printf("Lost space: %12lu Linkdata: %10lu\n",
+ empty,link_used);
+ }
+ my_afree((gptr) record);
+ DBUG_RETURN (error);
+ err:
+ print_error("got error: %d when reading datafile",my_errno);
+ err2:
+ my_afree((gptr) record);
+ DBUG_RETURN(1);
+} /* chk_data_link */
+
+
+ /* Recover old table by reading each record and writing all keys */
+ /* Save new datafile-name in temp_filename */
+
+static int rep(info,name)
+reg1 N_INFO *info;
+my_string name;
+{
+ int error,got_error;
+ uint i;
+ ulong start_records,new_header_length,del;
+ File new_file;
+ ISAM_SHARE *share=info->s;
+ DBUG_ENTER("rep");
+
+ start_records=share->state.records;
+ new_header_length=(testflag & T_UNPACK) ? 0L : share->pack.header_length;
+ got_error=1;
+ new_file= -1;
+ if (!(testflag & T_SILENT))
+ {
+ printf("- recovering ISAM-table '%s'\n",name);
+ printf("Data records: %lu\n",(ulong) share->state.records);
+ }
+
+ VOID(init_key_cache(use_buffers,NEAD_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;
+ if (!rep_quick)
+ if (init_io_cache(&info->rec_cache,-1,(uint) write_buffer_length,
+ WRITE_CACHE, new_header_length, 1,
+ MYF(MY_WME | MY_WAIT_IF_FULL)))
+ goto err;
+ info->opt_flag|=WRITE_CACHE_USED;
+ sort_info.start_recpos=0;
+ sort_info.buff=0; sort_info.buff_length=0;
+ if (!(sort_info.record=(byte*) my_alloca((uint) share->base.reclength)))
+ {
+ print_error("Not Enough memory");
+ goto err;
+ }
+
+ if (!rep_quick)
+ {
+ if ((new_file=my_create(fn_format(temp_filename,name,"",DATA_TMP_EXT,
+ 2+4),
+ 0,tmpfile_createflag,MYF(0))) < 0)
+ {
+ print_error("Can't create new tempfile: '%s'",temp_filename);
+ goto err;
+ }
+ if (filecopy(new_file,info->dfile,0L,new_header_length,"datafile-header"))
+ goto err;
+ share->state.dellink= NI_POS_ERROR;
+ info->rec_cache.file=new_file;
+ if (testflag & T_UNPACK)
+ share->base.options&= ~HA_OPTION_COMPRESS_RECORD;
+ }
+
+ sort_info.info=info;
+ sort_info.pos=sort_info.max_pos=share->pack.header_length;
+ sort_info.filepos=new_header_length;
+ read_cache.end_of_file=sort_info.filelength=(ulong)
+ my_seek(info->dfile,0L,MY_SEEK_END,MYF(0));
+ sort_info.dupp=0;
+ sort_info.fix_datafile= (my_bool) (! rep_quick);
+ sort_info.max_records=LONG_MAX;
+ if ((sort_info.new_data_file_type=share->data_file_type) ==
+ COMPRESSED_RECORD && testflag & T_UNPACK)
+ {
+ if (share->base.options & HA_OPTION_PACK_RECORD)
+ sort_info.new_data_file_type = DYNAMIC_RECORD;
+ else
+ sort_info.new_data_file_type = STATIC_RECORD;
+ }
+
+ del=share->state.del;
+ share->state.records=share->state.del=share->state.empty=
+ share->state.splitt=0;
+ info->update= (short) (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
+ for (i=0 ; i < N_MAXKEY ; i++)
+ share->state.key_del[i]=share->state.key_root[i]= NI_POS_ERROR;
+ share->state.key_file_length=share->base.keystart;
+
+ lock_memory(); /* Everything is alloced */
+ while (!(error=sort_get_next_record()))
+ {
+ if (writekeys(info,(byte*) sort_info.record,sort_info.filepos))
+ {
+ if (my_errno != HA_ERR_FOUND_DUPP_KEY) goto err;
+ DBUG_DUMP("record",(byte*) sort_info.record,share->base.pack_reclength);
+ print_info("Dupplicate key %2d for record at %10lu against new record at %10lu",info->errkey+1,sort_info.start_recpos,info->int_pos);
+ if (testflag & T_VERBOSE)
+ {
+ VOID(_nisam_make_key(info,(uint) info->errkey,info->lastkey,
+ sort_info.record,0L));
+ _nisam_print_key(stdout,share->keyinfo[info->errkey].seg,info->lastkey);
+ }
+ sort_info.dupp++;
+ if (rep_quick == 1)
+ {
+ error_printed=1;
+ goto err;
+ }
+ continue;
+ }
+ if (sort_write_record())
+ goto err;
+ }
+ if (error > 0 || write_data_suffix(info) ||
+ flush_io_cache(&info->rec_cache) || read_cache.error < 0)
+ goto err;
+
+ if (testflag & T_WRITE_LOOP)
+ {
+ VOID(fputs(" \r",stdout)); VOID(fflush(stdout));
+ }
+ if (my_chsize(share->kfile,share->state.key_file_length,MYF(0)))
+ {
+ print_warning("Can't change size of indexfile, error: %d",my_errno);
+ goto err;
+ }
+
+ if (rep_quick && del+sort_info.dupp != share->state.del)
+ {
+ print_error("Couldn't fix table with quick recovery: Found wrong number of deleted records");
+ print_error("Run recovery again without -q");
+ got_error=1;
+ goto err;
+ }
+
+ if (!rep_quick)
+ {
+ info->dfile=new_file;
+ share->state.data_file_length=sort_info.filepos;
+ share->state.splitt=share->state.records; /* Only hole records */
+ out_flag|=O_NEW_DATA; /* Data in new file */
+ share->state.version=(ulong) time((time_t*) 0); /* Force reopen */
+ }
+ else
+ share->state.data_file_length=sort_info.max_pos;
+
+ if (!(testflag & T_SILENT))
+ {
+ if (start_records != share->state.records)
+ printf("Data records: %lu\n",(ulong) share->state.records);
+ if (sort_info.dupp)
+ print_warning("%lu records have been removed",(ulong) sort_info.dupp);
+ }
+
+ got_error=0;
+err:
+ if (got_error)
+ {
+ if (! error_printed)
+ print_error("%d for record at pos %lu",my_errno,
+ (ulong) sort_info.start_recpos);
+ if (new_file >= 0)
+ {
+ VOID(my_close(new_file,MYF(0)));
+ VOID(my_delete(temp_filename,MYF(MY_WME)));
+ }
+ }
+ if (sort_info.record)
+ {
+ my_afree(sort_info.record);
+ }
+ my_free(sort_info.buff,MYF(MY_ALLOW_ZERO_PTR));
+ VOID(end_io_cache(&read_cache));
+ info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
+ VOID(end_io_cache(&info->rec_cache));
+ got_error|=flush_blocks(share->kfile);
+ if (!got_error && testflag & T_UNPACK)
+ {
+ share->state.header.options[0]&= (uchar) ~HA_OPTION_COMPRESS_RECORD;
+ share->pack.header_length=0;
+ share->data_file_type=sort_info.new_data_file_type;
+ }
+ DBUG_RETURN(got_error);
+} /* rep */
+
+
+ /* Uppdaterar nyckelfilen i samband med reparation */
+
+static int writekeys(register N_INFO *info,byte *buff,ulong filepos)
+{
+ register uint i;
+ uchar *key;
+ DBUG_ENTER("writekeys");
+
+ key=info->lastkey+info->s->base.max_key_length;
+ for (i=0 ; i < info->s->state.keys ; i++)
+ {
+ VOID(_nisam_make_key(info,i,key,buff,filepos));
+ if (_nisam_ck_write(info,i,key)) goto err;
+ }
+ DBUG_RETURN(0);
+
+ err:
+ if (my_errno == HA_ERR_FOUND_DUPP_KEY)
+ {
+ info->errkey=(int) i; /* This key was found */
+ while ( i-- > 0 )
+ {
+ VOID(_nisam_make_key(info,i,key,buff,filepos));
+ if (_nisam_ck_delete(info,i,key)) break;
+ }
+ }
+ DBUG_PRINT("error",("errno: %d",my_errno));
+ DBUG_RETURN(-1);
+} /* writekeys */
+
+
+ /* Write info about table */
+
+static void descript(info,name)
+reg1 N_INFO *info;
+my_string name;
+{
+ uint key,field,start,len;
+ reg3 N_KEYDEF *keyinfo;
+ reg2 N_KEYSEG *keyseg;
+ reg4 const char *text;
+ char buff[40],length[10],*pos,*end;
+ enum en_fieldtype type;
+ ISAM_SHARE *share=info->s;
+ DBUG_ENTER("describe");
+
+ printf("\nISAM file: %s\n",name);
+ if (testflag & T_VERBOSE)
+ {
+ printf("Isam-version: %d\n",(int) share->state.header.file_version[3]);
+ if (share->base.create_time)
+ {
+ get_date(buff,1,share->base.create_time);
+ printf("Creation time: %s\n",buff);
+ }
+ if (share->base.isamchk_time)
+ {
+ get_date(buff,1,share->base.isamchk_time);
+ printf("Recover time: %s\n",buff);
+ }
+ }
+ printf("Data records: %10lu Deleted blocks: %10lu\n",
+ share->state.records,share->state.del);
+ if (testflag & T_SILENT)
+ DBUG_VOID_RETURN; /* This is enough */
+
+ if (testflag & T_VERBOSE)
+ {
+#ifdef USE_RELOC
+ printf("Init-relocation: %10lu\n",share->base.reloc);
+#endif
+ printf("Datafile Parts: %10lu Deleted data: %10lu\n",
+ share->state.splitt,share->state.empty);
+ printf("Datafile pointer (bytes):%6d Keyfile pointer (bytes):%6d\n",
+ share->rec_reflength,share->base.key_reflength);
+ if (info->s->base.reloc == 1L && info->s->base.records == 1L)
+ puts("This is a one-record table");
+ else
+ {
+ if (share->base.max_data_file_length != NI_POS_ERROR ||
+ share->base.max_key_file_length != NI_POS_ERROR)
+ printf("Max datafile length: %10lu Max keyfile length: %10lu\n",
+ share->base.max_data_file_length-1,
+ share->base.max_key_file_length-1);
+ }
+ }
+
+ printf("Recordlength: %10d\n",(int) share->base.reclength);
+ VOID(fputs("Record format: ",stdout));
+ if (share->base.options & HA_OPTION_COMPRESS_RECORD)
+ puts("Compressed");
+ else if (share->base.options & HA_OPTION_PACK_RECORD)
+ puts("Packed");
+ else
+ puts("Fixed length");
+ if (share->state.keys != share->base.keys)
+ printf("Using only %d keys of %d possibly keys\n",share->state.keys,
+ share->base.keys);
+
+ puts("\ntable description:");
+ printf("Key Start Len Index Type");
+ if (testflag & T_VERBOSE)
+ printf(" Root Blocksize Rec/key");
+ VOID(putchar('\n'));
+
+ for (key=0, keyinfo= &share->keyinfo[0] ; key < share->base.keys;
+ key++,keyinfo++)
+ {
+ keyseg=keyinfo->seg;
+ if (keyinfo->base.flag & HA_NOSAME) text="unique ";
+ else text="multip.";
+
+ pos=buff;
+ if (keyseg->base.flag & HA_REVERSE_SORT)
+ *pos++ = '-';
+ pos=strmov(pos,type_names[keyseg->base.type]);
+ *pos++ = ' ';
+ *pos=0;
+ if (keyinfo->base.flag & HA_PACK_KEY)
+ pos=strmov(pos,packed_txt);
+ if (keyseg->base.flag & HA_SPACE_PACK)
+ pos=strmov(pos,diff_txt);
+ printf("%-4d%-6d%-3d %-8s%-21s",
+ key+1,keyseg->base.start+1,keyseg->base.length,text,buff);
+ if (testflag & T_VERBOSE)
+ printf(" %9ld %9d %9ld",
+ share->state.key_root[key],keyinfo->base.block_length,
+ share->base.rec_per_key[key]);
+ VOID(putchar('\n'));
+ while ((++keyseg)->base.type)
+ {
+ pos=buff;
+ if (keyseg->base.flag & HA_REVERSE_SORT)
+ *pos++ = '-';
+ pos=strmov(pos,type_names[keyseg->base.type]);
+ *pos++= ' ';
+ if (keyseg->base.flag & HA_SPACE_PACK)
+ pos=strmov(pos,diff_txt);
+ *pos=0;
+ printf(" %-6d%-3d %-24s\n",
+ keyseg->base.start+1,keyseg->base.length,buff);
+ }
+ }
+ if (verbose > 1)
+ {
+ printf("\nField Start Length Type");
+ if (share->base.options & HA_OPTION_COMPRESS_RECORD)
+ printf(" Huff tree Bits");
+ VOID(putchar('\n'));
+ start=1;
+ for (field=0 ; field < share->base.fields ; field++)
+ {
+ if (share->base.options & HA_OPTION_COMPRESS_RECORD)
+ type=share->rec[field].base_type;
+ else
+ type=(enum en_fieldtype) share->rec[field].base.type;
+ end=strmov(buff,field_pack[type]);
+#ifndef NOT_PACKED_DATABASES
+ if (share->base.options & HA_OPTION_COMPRESS_RECORD)
+ {
+ if (share->rec[field].pack_type & PACK_TYPE_SELECTED)
+ end=strmov(end,", not_always");
+ if (share->rec[field].pack_type & PACK_TYPE_SPACE_FIELDS)
+ end=strmov(end,", no empty");
+ if (share->rec[field].pack_type & PACK_TYPE_ZERO_FILL)
+ {
+ sprintf(end,", zerofill(%d)",share->rec[field].space_length_bits);
+ end=strend(end);
+ }
+ }
+ if (buff[0] == ',')
+ strmov(buff,buff+2);
+#endif
+ len=(uint) (int2str((long) share->rec[field].base.length,length,10) -
+ length);
+ if (type == FIELD_BLOB)
+ {
+ length[len]='+';
+ VOID(int2str((long) sizeof(char*),length+len+1,10));
+ }
+ printf("%-6d%-6d%-7s%-35s",field+1,start,length,buff);
+#ifndef NOT_PACKED_DATABASES
+ if (share->base.options & HA_OPTION_COMPRESS_RECORD)
+ {
+ if (share->rec[field].huff_tree)
+ printf("%3d %2d",
+ (uint) (share->rec[field].huff_tree-share->decode_trees)+1,
+ share->rec[field].huff_tree->quick_table_bits);
+ }
+#endif
+ VOID(putchar('\n'));
+ start+=share->rec[field].base.length;
+ if (type == FIELD_BLOB)
+ start+=sizeof(char*);
+ }
+ }
+ DBUG_VOID_RETURN;
+} /* describe */
+
+
+ /* Change all key-pointers that points to a records */
+
+static int movepoint(info,record,oldpos,newpos,prot_key)
+register N_INFO *info;
+byte *record;
+ulong oldpos,newpos;
+uint prot_key;
+{
+ register uint i;
+ uchar *key;
+ DBUG_ENTER("movepoint");
+
+ key=info->lastkey+info->s->base.max_key_length;
+ for (i=0 ; i < info->s->state.keys; i++)
+ {
+ if (i != prot_key)
+ {
+ VOID(_nisam_make_key(info,i,key,record,oldpos));
+ if (info->s->keyinfo[i].base.flag & HA_NOSAME)
+ { /* Change pointer direct */
+ uint nod_flag;
+ N_KEYDEF *keyinfo;
+ keyinfo=info->s->keyinfo+i;
+ if (_nisam_search(info,keyinfo,key,USE_HOLE_KEY,
+ (uint) (SEARCH_SAME | SEARCH_SAVE_BUFF),
+ info->s->state.key_root[i]))
+ DBUG_RETURN(-1);
+ nod_flag=test_if_nod(info->buff);
+ _nisam_dpointer(info,info->int_keypos-nod_flag-
+ info->s->rec_reflength,newpos);
+ if (_nisam_write_keypage(info,keyinfo,info->int_pos,info->buff))
+ DBUG_RETURN(-1);
+ }
+ else
+ { /* Change old key to new */
+ if (_nisam_ck_delete(info,i,key))
+ DBUG_RETURN(-1);
+ VOID(_nisam_make_key(info,i,key,record,newpos));
+ if (_nisam_ck_write(info,i,key))
+ DBUG_RETURN(-1);
+ }
+ }
+ }
+ DBUG_RETURN(0);
+} /* movepoint */
+
+
+ /* Tell system that we want all memory for our cache */
+
+static void lock_memory(void)
+{
+#ifdef SUN_OS /* Key-cacheing thrases on sun 4.1 */
+ int success;
+
+ success = mlockall(MCL_CURRENT); /* or plock(DATLOCK); */
+
+ if (geteuid() == 0 && success != 0)
+ print_warning("Failed to lock memory. errno %d",my_errno);
+#endif
+} /* lock_memory */
+
+
+ /* Flush all changed blocks to disk */
+
+static int flush_blocks(file)
+File file;
+{
+ if (flush_key_blocks(file,FLUSH_RELEASE))
+ {
+ print_error("%d when trying to write bufferts",my_errno);
+ return(1);
+ }
+ end_key_cache();
+ return 0;
+} /* flush_blocks */
+
+
+ /* Sort records according to one key */
+
+static int sort_records(info,name,sort_key,write_info)
+register N_INFO *info;
+my_string name;
+uint sort_key;
+int write_info;
+{
+ int got_error;
+ uint key;
+ N_KEYDEF *keyinfo;
+ File new_file;
+ uchar *temp_buff;
+ ulong old_record_count;
+ ISAM_SHARE *share=info->s;
+ DBUG_ENTER("sort_records");
+
+ keyinfo= &share->keyinfo[sort_key];
+ got_error=1;
+ temp_buff=0; record_buff=0;
+ new_file= -1;
+
+ if (sort_key >= share->state.keys)
+ {
+ print_error("Can't sort table '%s' on key %d. It has only %d keys",
+ name,sort_key+1,share->state.keys);
+ error_printed=0;
+ DBUG_RETURN(-1);
+ }
+ if (!(testflag & T_SILENT))
+ {
+ printf("- Sorting records in ISAM-table '%s'\n",name);
+ if (write_info)
+ printf("Data records: %7lu Deleted: %7lu\n",
+ share->state.records,share->state.del);
+ }
+ if (share->state.key_root[sort_key] == NI_POS_ERROR)
+ DBUG_RETURN(0); /* Nothing to do */
+
+ init_key_cache(use_buffers,NEAD_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)))
+ goto err;
+ info->opt_flag|=WRITE_CACHE_USED;
+
+ if (!(temp_buff=(uchar*) my_alloca((uint) keyinfo->base.block_length)))
+ {
+ print_error("Not Enough memory");
+ goto err;
+ }
+ if (!(record_buff=(byte*) my_alloca((uint) share->base.reclength)))
+ {
+ print_error("Not Enough memory");
+ goto err;
+ }
+ if ((new_file=my_create(fn_format(temp_filename,name,"",DATA_TMP_EXT,2+4),
+ 0,tmpfile_createflag,MYF(0))) <= 0)
+ {
+ print_error("Can't create new tempfile: '%s'",temp_filename);
+ goto err;
+ }
+ if (filecopy(new_file,info->dfile,0L,share->pack.header_length,
+ "datafile-header"))
+ goto err;
+ info->rec_cache.file=new_file; /* Use this file for cacheing*/
+
+ lock_memory();
+ for (key=0 ; key < share->state.keys ; key++)
+ share->keyinfo[key].base.flag|= HA_SORT_ALLOWS_SAME;
+
+ if (my_pread(share->kfile,(byte*) temp_buff,
+ (uint) keyinfo->base.block_length,
+ share->state.key_root[sort_key],
+ MYF(MY_NABP+MY_WME)))
+ {
+ print_error("Can't read indexpage from filepos: %lu",
+ (ulong) share->state.key_root[sort_key]);
+ goto err;
+ }
+
+ /* Setup param for sort_write_record */
+ bzero((char*) &sort_info,sizeof(sort_info));
+ sort_info.info=info;
+ sort_info.new_data_file_type=share->data_file_type;
+ sort_info.fix_datafile=1;
+ sort_info.filepos=share->pack.header_length;
+ sort_info.record=record_buff;
+ old_record_count=share->state.records;
+ share->state.records=0;
+
+ if (sort_record_index(info,keyinfo,share->state.key_root[sort_key],temp_buff,
+ sort_key,new_file) ||
+ write_data_suffix(info) ||
+ flush_io_cache(&info->rec_cache))
+ goto err;
+
+ if (share->state.records != old_record_count)
+ {
+ print_error("found %lu of %lu records",
+ (ulong) share->state.records,(ulong) old_record_count);
+ goto err;
+ }
+
+ /* Put same locks as old file */
+ if (lock_file(new_file,0L,F_WRLCK,"tempfile",temp_filename))
+ goto err;
+ VOID(lock_file(info->dfile,0L,F_UNLCK,"datafile of",name));
+ VOID(my_close(info->dfile,MYF(MY_WME)));
+ out_flag|=O_NEW_DATA; /* Data in new file */
+
+ info->dfile=new_file; /* Use new indexfile */
+ share->state.del=share->state.empty=0;
+ share->state.dellink= NI_POS_ERROR;
+ share->state.data_file_length=sort_info.filepos;
+ share->state.splitt=share->state.records; /* Only hole records */
+ share->state.version=(ulong) time((time_t*) 0);
+
+ info->update= (short) (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
+
+ if (testflag & T_WRITE_LOOP)
+ {
+ VOID(fputs(" \r",stdout)); VOID(fflush(stdout));
+ }
+ got_error=0;
+
+err:
+ if (got_error && new_file >= 0)
+ {
+ VOID(my_close(new_file,MYF(MY_WME)));
+ VOID(my_delete(temp_filename,MYF(MY_WME)));
+ }
+ if (temp_buff)
+ {
+ my_afree((gptr) temp_buff);
+ }
+ if (record_buff)
+ {
+ my_afree(record_buff);
+ }
+ info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
+ VOID(end_io_cache(&info->rec_cache));
+ share->base.sortkey=sort_key;
+ DBUG_RETURN(flush_blocks(share->kfile) | got_error);
+} /* sort_records */
+
+
+ /* Sort records recursive using one index */
+
+static int sort_record_index(info,keyinfo,page,buff,sort_key,new_file)
+N_INFO *info;
+N_KEYDEF *keyinfo;
+ulong page;
+uchar *buff;
+uint sort_key;
+File new_file;
+{
+ uint nod_flag,used_length;
+ uchar *temp_buff,*keypos,*endpos;
+ ulong next_page,rec_pos;
+ uchar lastkey[N_MAX_KEY_BUFF];
+ DBUG_ENTER("sort_record_index");
+
+ nod_flag=test_if_nod(buff);
+ temp_buff=0;
+
+ if (nod_flag)
+ {
+ if (!(temp_buff=(uchar*) my_alloca((uint) keyinfo->base.block_length)))
+ {
+ print_error("Not Enough memory");
+ DBUG_RETURN(-1);
+ }
+ }
+ used_length=getint(buff);
+ keypos=buff+2+nod_flag;
+ endpos=buff+used_length;
+ for ( ;; )
+ {
+ _sanity(__FILE__,__LINE__);
+ if (nod_flag)
+ {
+ next_page=_nisam_kpos(nod_flag,keypos);
+ if (my_pread(info->s->kfile,(byte*) temp_buff,
+ (uint) keyinfo->base.block_length, next_page,
+ MYF(MY_NABP+MY_WME)))
+ {
+ print_error("Can't read keys from filepos: %lu",(ulong) next_page);
+ goto err;
+ }
+ if (sort_record_index(info,keyinfo,next_page,temp_buff,sort_key,
+ new_file))
+ goto err;
+ }
+ _sanity(__FILE__,__LINE__);
+ if (keypos >= endpos ||
+ (*keyinfo->get_key)(keyinfo,nod_flag,&keypos,lastkey) == 0)
+ break;
+ rec_pos= _nisam_dpos(info,nod_flag,keypos);
+
+ if ((*info->s->read_rnd)(info,record_buff,rec_pos,0))
+ {
+ print_error("%d when reading datafile",my_errno);
+ goto err;
+ }
+ if (rec_pos != sort_info.filepos)
+ {
+ _nisam_dpointer(info,keypos-nod_flag-info->s->rec_reflength,
+ sort_info.filepos);
+ if (movepoint(info,record_buff,rec_pos,sort_info.filepos,sort_key))
+ {
+ print_error("%d when updating key-pointers",my_errno);
+ goto err;
+ }
+ }
+ if (sort_write_record())
+ goto err;
+ }
+ bzero((byte*) buff+used_length,keyinfo->base.block_length-used_length);
+ if (my_pwrite(info->s->kfile,(byte*) buff,(uint) keyinfo->base.block_length,
+ page,MYF_RW))
+ {
+ print_error("%d when updating keyblock",my_errno);
+ goto err;
+ }
+ if (temp_buff)
+ my_afree((gptr) temp_buff);
+ DBUG_RETURN(0);
+err:
+ if (temp_buff)
+ my_afree((gptr) temp_buff);
+ DBUG_RETURN(1);
+} /* sort_record_index */
+
+
+ /* Sort index for more efficent reads */
+
+static int sort_index(info,name)
+register N_INFO *info;
+my_string name;
+{
+ reg2 uint key;
+ reg1 N_KEYDEF *keyinfo;
+ File new_file;
+ ulong index_pos[N_MAXKEY];
+ DBUG_ENTER("sort_index");
+
+ if (!(testflag & T_SILENT))
+ printf("- Sorting index for ISAM-table '%s'\n",name);
+
+ if ((new_file=my_create(fn_format(temp_filename,name,"",INDEX_TMP_EXT,2+4),
+ 0,tmpfile_createflag,MYF(0))) <= 0)
+ {
+ print_error("Can't create new tempfile: '%s'",temp_filename);
+ DBUG_RETURN(-1);
+ }
+ if (filecopy(new_file,info->s->kfile,0L,(ulong) info->s->base.keystart,
+ "headerblock"))
+ goto err;
+
+ new_file_pos=info->s->base.keystart;
+ for (key= 0,keyinfo= &info->s->keyinfo[0]; key < info->s->state.keys ;
+ key++,keyinfo++)
+ {
+ if (info->s->state.key_root[key] != NI_POS_ERROR)
+ {
+ index_pos[key]=new_file_pos; /* Write first block here */
+ if (!_nisam_fetch_keypage(info,keyinfo,info->s->state.key_root[key],
+ info->buff,0))
+ {
+ print_error("Can't read indexpage from filepos: %lu",
+ (ulong) info->s->state.key_root[key]);
+ goto err;
+ }
+ if (sort_one_index(info,keyinfo,info->buff,new_file))
+ goto err;
+ }
+ else
+ index_pos[key]= NI_POS_ERROR; /* No blocks */
+ }
+
+ /* Put same locks as old file */
+ if (lock_file(new_file,0L,F_WRLCK,"tempfile",temp_filename))
+ goto err;
+ info->s->state.version=(ulong) time((time_t*) 0);
+ VOID(_nisam_writeinfo(info,1)); /* This unlocks table */
+ VOID(my_close(info->s->kfile,MYF(MY_WME)));
+ out_flag|=O_NEW_INDEX; /* Data in new file */
+
+ info->s->kfile=new_file;
+ info->s->state.key_file_length=new_file_pos;
+ info->update= (short) (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
+ for (key=0 ; key < info->s->state.keys ; key++)
+ {
+ info->s->state.key_root[key]=index_pos[key];
+ info->s->state.key_del[key]= NI_POS_ERROR;
+ }
+ DBUG_RETURN(0);
+
+err:
+ VOID(my_close(new_file,MYF(MY_WME)));
+ VOID(my_delete(temp_filename,MYF(MY_WME)));
+ DBUG_RETURN(-1);
+} /* sort_index */
+
+
+ /* Sort records recursive using one index */
+
+static int sort_one_index(info,keyinfo,buff,new_file)
+N_INFO *info;
+N_KEYDEF *keyinfo;
+uchar *buff;
+File new_file;
+{
+ uint length,nod_flag,used_length;
+ uchar *temp_buff,*keypos,*endpos;
+ ulong new_page_pos,next_page;
+ DBUG_ENTER("sort_one_index");
+
+ temp_buff=0;
+ new_page_pos=new_file_pos;
+ new_file_pos+=keyinfo->base.block_length;
+
+ if ((nod_flag=test_if_nod(buff)))
+ {
+ if (!(temp_buff=(uchar*) my_alloca((uint) keyinfo->base.block_length)))
+ {
+ print_error("Not Enough memory");
+ DBUG_RETURN(-1);
+ }
+
+ used_length=getint(buff);
+ keypos=buff+2+nod_flag;
+ endpos=buff+used_length;
+ for ( ;; )
+ {
+ if (nod_flag)
+ {
+ next_page=_nisam_kpos(nod_flag,keypos);
+ _nisam_kpointer(info,keypos-nod_flag,new_file_pos); /* Save new pos */
+ if (!_nisam_fetch_keypage(info,keyinfo,next_page,temp_buff,0))
+ {
+ print_error("Can't read keys from filepos: %lu",
+ (ulong) next_page);
+ goto err;
+ }
+ if (sort_one_index(info,keyinfo,temp_buff,new_file))
+ goto err;
+ }
+ if (keypos >= endpos ||
+ ((*keyinfo->get_key)(keyinfo,nod_flag,&keypos,info->lastkey)) == 0)
+ break;
+ }
+ my_afree((gptr) temp_buff);
+ }
+
+ /* Fill block with zero and write it to new file */
+
+ length=getint(buff);
+ bzero((byte*) buff+length,keyinfo->base.block_length-length);
+ if (my_pwrite(new_file,(byte*) buff,(uint) keyinfo->base.block_length,
+ new_page_pos,MYF(MY_NABP | MY_WAIT_IF_FULL)))
+ {
+ print_error("Can't write indexblock, error: %d",my_errno);
+ goto err;
+ }
+ DBUG_RETURN(0);
+err:
+ if (temp_buff)
+ my_afree((gptr) temp_buff);
+ DBUG_RETURN(1);
+} /* sort_one_index */
+
+
+ /* Change to use new file */
+ /* Copy stats from old file to new file, deletes orginal and */
+ /* changes new file name to old file name */
+
+static int change_to_newfile(filename,old_ext,new_ext)
+const char *filename,*old_ext,*new_ext;
+{
+ char old_filename[FN_REFLEN],new_filename[FN_REFLEN];
+
+ return my_redel(fn_format(old_filename,filename,"",old_ext,2+4),
+ fn_format(new_filename,filename,"",new_ext,2+4),
+ MYF(MY_WME+MY_LINK_WARNING));
+} /* change_to_newfile */
+
+
+ /* Locks a hole file */
+ /* Gives error-message if file can't be locked */
+
+static int lock_file(file,start,lock_type,filetype,filename)
+File file;
+ulong start;
+int lock_type;
+const char *filetype,*filename;
+{
+#ifndef NO_LOCKING
+ if (my_lock(file,lock_type,start,F_TO_EOF,
+ testflag & T_WAIT_FOREVER ? MYF(MY_SEEK_NOT_DONE) :
+ MYF(MY_SEEK_NOT_DONE | MY_DONT_WAIT)))
+ {
+ print_error(" %d when %s %s '%s'",my_errno,
+ lock_type == F_UNLCK ? "unlocking": "locking",
+ filetype,filename);
+ error_printed=2; /* Don't give that data is crashed */
+ return 1;
+ }
+#endif
+ return 0;
+} /* lock_file */
+
+
+ /* Copy a block between two files */
+
+static int filecopy(File to,File from,ulong start,ulong length,
+ const char *type)
+{
+ char tmp_buff[IO_SIZE],*buff;
+ ulong buff_length;
+ DBUG_ENTER("filecopy");
+
+ buff_length=min(write_buffer_length,length);
+ if (!(buff=my_malloc(buff_length,MYF(0))))
+ {
+ buff=tmp_buff; buff_length=IO_SIZE;
+ }
+
+ VOID(my_seek(from,start,MY_SEEK_SET,MYF(0)));
+ while (length > buff_length)
+ {
+ if (my_read(from,(byte*) buff,buff_length,MYF(MY_NABP)) ||
+ my_write(to,(byte*) buff,buff_length,MYF(MY_NABP | MY_WAIT_IF_FULL)))
+ goto err;
+ length-= buff_length;
+ }
+ if (my_read(from,(byte*) buff,(uint) length,MYF(MY_NABP)) ||
+ my_write(to,(byte*) buff,(uint) length,MYF(MY_NABP | MY_WAIT_IF_FULL)))
+ goto err;
+ if (buff != tmp_buff)
+ my_free(buff,MYF(0));
+ DBUG_RETURN(0);
+err:
+ if (buff != tmp_buff)
+ my_free(buff,MYF(0));
+ print_error("Can't copy %s to tempfile, error %d",type,my_errno);
+ DBUG_RETURN(1);
+}
+
+
+ /* Fix table using sorting */
+ /* saves new table in temp_filename */
+
+static int rep_by_sort(info,name)
+reg1 N_INFO *info;
+my_string name;
+{
+ int got_error;
+ uint i,length;
+ ulong start_records,new_header_length,del;
+ File new_file;
+ SORT_PARAM sort_param;
+ ISAM_SHARE *share=info->s;
+ DBUG_ENTER("rep_by_sort");
+
+ start_records=share->state.records;
+ got_error=1;
+ new_file= -1;
+ new_header_length=(testflag & T_UNPACK) ? 0 : share->pack.header_length;
+ if (!(testflag & T_SILENT))
+ {
+ printf("- recovering ISAM-table '%s'\n",name);
+ printf("Data records: %lu\n",(ulong) start_records);
+ }
+ bzero((char*) &sort_info,sizeof(sort_info));
+ if (!(sort_info.key_block=alloc_key_blocks((uint) sort_key_blocks,
+ share->base.max_block))
+ || init_io_cache(&read_cache,info->dfile,(uint) read_buffer_length,
+ READ_CACHE,share->pack.header_length,1,MYF(MY_WME)) ||
+ (! rep_quick &&
+ init_io_cache(&info->rec_cache,info->dfile,(uint) write_buffer_length,
+ WRITE_CACHE,new_header_length,1,
+ MYF(MY_WME | MY_WAIT_IF_FULL))))
+ goto err;
+ sort_info.key_block_end=sort_info.key_block+sort_key_blocks;
+ info->opt_flag|=WRITE_CACHE_USED;
+ info->rec_cache.file=info->dfile; /* for sort_delete_record */
+
+ if (!(sort_info.record=(byte*) my_alloca((uint) share->base.reclength)))
+ {
+ print_error("Not enough memory for extra record");
+ goto err;
+ }
+ if (!rep_quick)
+ {
+ if ((new_file=my_create(fn_format(temp_filename,name,"",DATA_TMP_EXT,
+ 2+4),
+ 0,tmpfile_createflag,MYF(0))) < 0)
+ {
+ print_error("Can't create new tempfile: '%s'",temp_filename);
+ goto err;
+ }
+ if (filecopy(new_file,info->dfile,0L,new_header_length,"datafile-header"))
+ goto err;
+ if (testflag & T_UNPACK)
+ share->base.options&= ~HA_OPTION_COMPRESS_RECORD;
+ share->state.dellink= NI_POS_ERROR;
+ info->rec_cache.file=new_file;
+ }
+
+ info->update= (short) (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
+ for (i=0 ; i < N_MAXKEY ; i++)
+ share->state.key_del[i]=share->state.key_root[i]= NI_POS_ERROR;
+ share->state.key_file_length=share->base.keystart;
+
+ sort_info.info=info;
+ if ((sort_info.new_data_file_type=share->data_file_type) ==
+ COMPRESSED_RECORD && testflag & T_UNPACK)
+ {
+ if (share->base.options & HA_OPTION_PACK_RECORD)
+ sort_info.new_data_file_type = DYNAMIC_RECORD;
+ else
+ sort_info.new_data_file_type = STATIC_RECORD;
+ }
+
+ sort_info.filepos=new_header_length;
+ sort_info.dupp=0;
+ read_cache.end_of_file=sort_info.filelength=
+ (ulong) my_seek(read_cache.file,0L,MY_SEEK_END,MYF(0));
+
+ if (share->data_file_type == DYNAMIC_RECORD)
+ length=max(share->base.min_pack_length+1,share->base.min_block_length);
+ else if (share->data_file_type == COMPRESSED_RECORD)
+ length=share->base.min_block_length;
+ else
+ length=share->base.reclength;
+ sort_param.max_records=sort_info.max_records=sort_info.filelength/length+1;
+ sort_param.key_cmp=sort_key_cmp;
+ sort_param.key_write=sort_key_write;
+ sort_param.key_read=sort_key_read;
+ sort_param.lock_in_memory=lock_memory;
+ del=share->state.del;
+
+ for (sort_info.key=0 ; sort_info.key < share->state.keys ; sort_info.key++)
+ {
+ if ((!(testflag & T_SILENT)))
+ printf ("- Fixing index %d\n",sort_info.key+1);
+ sort_info.max_pos=sort_info.pos=share->pack.header_length;
+ sort_info.keyinfo=share->keyinfo+sort_info.key;
+ sort_info.keyseg=sort_info.keyinfo->seg;
+ sort_info.fix_datafile= (my_bool) (sort_info.key == 0 && ! rep_quick);
+ sort_info.unique=0;
+ sort_param.key_length=share->rec_reflength;
+ for (i=0 ; sort_info.keyseg[i].base.type ; i++)
+ sort_param.key_length+=sort_info.keyseg[i].base.length+
+ (sort_info.keyseg[i].base.flag & HA_SPACE_PACK ? 1 : 0);
+ share->state.records=share->state.del=share->state.empty=share->state.splitt=0;
+
+ if (_create_index_by_sort(&sort_param,
+ (pbool) (!(testflag & T_VERBOSE)),
+ (uint) sort_buffer_length))
+ goto err;
+ /* Set for next loop */
+ sort_param.max_records=sort_info.max_records=share->state.records;
+ share->base.rec_per_key[sort_info.key]=
+ sort_info.unique ? ((sort_info.max_records+sort_info.unique/2)/
+ sort_info.unique)
+ : 1L;
+
+ if (sort_info.fix_datafile)
+ {
+ info->dfile=new_file;
+ share->state.data_file_length=sort_info.filepos;
+ share->state.splitt=share->state.records; /* Only hole records */
+ share->state.version=(ulong) time((time_t*) 0);
+ out_flag|=O_NEW_DATA; /* Data in new file */
+ read_cache.end_of_file=sort_info.filepos;
+ if (write_data_suffix(info) || end_io_cache(&info->rec_cache))
+ goto err;
+ share->data_file_type=sort_info.new_data_file_type;
+ share->pack.header_length=new_header_length;
+ }
+ else
+ share->state.data_file_length=sort_info.max_pos;
+
+ if (flush_pending_blocks())
+ goto err;
+
+ read_cache.file=info->dfile; /* re-init read cache */
+ reinit_io_cache(&read_cache,READ_CACHE,share->pack.header_length,1,1);
+ }
+
+ if (testflag & T_WRITE_LOOP)
+ {
+ VOID(fputs(" \r",stdout)); VOID(fflush(stdout));
+ }
+
+ if (rep_quick && del+sort_info.dupp != share->state.del)
+ {
+ print_error("Couldn't fix table with quick recovery: Found wrong number of deleted records");
+ print_error("Run recovery again without -q");
+ got_error=1;
+ goto err;
+ }
+
+ if (rep_quick != 1)
+ {
+ ulong skr=share->state.data_file_length+
+ (share->base.options & HA_OPTION_COMPRESS_RECORD ?
+ MEMMAP_EXTRA_MARGIN : 0);
+#ifdef USE_RELOC
+ if (share->data_file_type == STATIC_RECORD &&
+ skr < share->base.reloc*share->base.min_pack_length)
+ skr=share->base.reloc*share->base.min_pack_length;
+#endif
+ if (skr != sort_info.filelength)
+ if (my_chsize(info->dfile,skr,MYF(0)))
+ print_warning("Can't change size of datafile, error: %d",my_errno);
+ }
+ if (my_chsize(share->kfile,share->state.key_file_length,MYF(0)))
+ print_warning("Can't change size of indexfile, error: %d",my_errno);
+
+ if (!(testflag & T_SILENT))
+ {
+ if (start_records != share->state.records)
+ printf("Data records: %lu\n",(ulong) share->state.records);
+ if (sort_info.dupp)
+ print_warning("%lu records have been removed",(ulong) sort_info.dupp);
+ }
+ got_error=0;
+
+err:
+ if (got_error)
+ {
+ if (! error_printed)
+ print_error("%d when fixing table",my_errno);
+ if (new_file >= 0)
+ {
+ VOID(end_io_cache(&info->rec_cache));
+ VOID(my_close(new_file,MYF(0)));
+ VOID(my_delete(temp_filename,MYF(MY_WME)));
+ }
+ }
+ if (sort_info.key_block)
+ my_free((gptr) sort_info.key_block,MYF(0));
+ if (sort_info.record)
+ {
+ my_afree(sort_info.record);
+ }
+ VOID(end_io_cache(&read_cache));
+ VOID(end_io_cache(&info->rec_cache));
+ info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
+ if (!got_error && testflag & T_UNPACK)
+ {
+ share->state.header.options[0]&= (uchar) ~HA_OPTION_COMPRESS_RECORD;
+ share->pack.header_length=0;
+ }
+ DBUG_RETURN(got_error);
+} /* rep_by_sort */
+
+
+ /* Read next record and return next key */
+
+static int sort_key_read(key)
+void *key;
+{
+ int error;
+ N_INFO *info;
+ DBUG_ENTER("sort_key_read");
+
+ info=sort_info.info;
+
+ if ((error=sort_get_next_record()))
+ DBUG_RETURN(error);
+ if (info->s->state.records == sort_info.max_records)
+ {
+ print_error("Found too many records; Can`t continue");
+ DBUG_RETURN(1);
+ }
+ VOID(_nisam_make_key(info,sort_info.key,key,sort_info.record,
+ sort_info.filepos));
+ DBUG_RETURN(sort_write_record());
+} /* sort_key_read */
+
+
+ /* Read next record from file using parameters in sort_info */
+ /* Return -1 if end of file, 0 if ok and > 0 if error */
+
+static int sort_get_next_record()
+{
+ int searching;
+ uint found_record,b_type,left_length;
+ ulong pos;
+ byte *to;
+ BLOCK_INFO block_info;
+ N_INFO *info;
+ ISAM_SHARE *share;
+ DBUG_ENTER("sort_get_next_record");
+
+ info=sort_info.info;
+ share=info->s;
+ switch (share->data_file_type) {
+ case STATIC_RECORD:
+ for (;;)
+ {
+ if (my_b_read(&read_cache,sort_info.record,share->base.reclength))
+ DBUG_RETURN(-1);
+ sort_info.start_recpos=sort_info.pos;
+ if (!sort_info.fix_datafile)
+ sort_info.filepos=sort_info.pos;
+ sort_info.max_pos=(sort_info.pos+=share->base.reclength);
+ share->state.splitt++;
+ if (*sort_info.record)
+ DBUG_RETURN(0);
+ if (!sort_info.fix_datafile)
+ {
+ share->state.del++;
+ share->state.empty+=share->base.reclength;
+ }
+ }
+ case DYNAMIC_RECORD:
+ LINT_INIT(to);
+ pos=sort_info.pos;
+ searching=(sort_info.fix_datafile && (testflag & T_EXTEND));
+ for (;;)
+ {
+ found_record=block_info.second_read= 0;
+ left_length=1;
+ do
+ {
+ if (pos > sort_info.max_pos)
+ sort_info.max_pos=pos;
+ if (found_record && pos == search_after_block)
+ print_info("Block: %lu used by record at %lu",
+ search_after_block,
+ sort_info.start_recpos);
+ if (_nisam_read_cache(&read_cache,(byte*) block_info.header,pos,
+ BLOCK_INFO_HEADER_LENGTH, test(! found_record) | 2))
+ {
+ if (found_record)
+ {
+ print_info("Can't read whole record at %lu (errno: %d)",
+ (ulong) sort_info.start_recpos,errno);
+ goto try_next;
+ }
+ DBUG_RETURN(-1);
+ }
+ if (searching && ! sort_info.fix_datafile)
+ {
+ error_printed=1;
+ DBUG_RETURN(1); /* Something wrong with data */
+ }
+ if (((b_type=_nisam_get_block_info(&block_info,-1,pos)) &
+ (BLOCK_ERROR | BLOCK_FATAL_ERROR)) ||
+ ((b_type & BLOCK_FIRST) &&
+ (block_info.rec_len < (uint) share->base.min_pack_length ||
+ block_info.rec_len > (uint) share->base.max_pack_length)))
+ {
+ uint i;
+ if (testflag & T_VERBOSE || searching == 0)
+ print_info("Wrong bytesec: %3d-%3d-%3d at %10lu; Skipped",
+ block_info.header[0],block_info.header[1],
+ block_info.header[2],pos);
+ if (found_record)
+ goto try_next;
+ block_info.second_read=0;
+ searching=1;
+ for (i=1 ; i < 11 ; i++) /* Skipp from read string */
+ if (block_info.header[i] >= 1 && block_info.header[i] <= 16)
+ break;
+ pos+=(ulong) i;
+ continue;
+ }
+ if (block_info.block_len+ (uint) (block_info.filepos-pos) <
+ share->base.min_block_length ||
+ block_info.block_len-4 > (uint) share->base.max_pack_length)
+ {
+ if (!searching)
+ print_info("Found block with impossible length %u at %lu; Skipped",
+ block_info.block_len+ (uint) (block_info.filepos-pos),
+ (ulong) pos);
+ if (found_record)
+ goto try_next;
+ searching=1;
+ pos++;
+ block_info.second_read=0;
+ continue;
+ }
+ if (b_type & (BLOCK_DELETED | BLOCK_SYNC_ERROR))
+ {
+ if (!sort_info.fix_datafile && (b_type & BLOCK_DELETED))
+ {
+ share->state.empty+=block_info.block_len;
+ share->state.del++;
+ share->state.splitt++;
+ }
+ if (found_record)
+ goto try_next;
+ /* Check if impossible big deleted block */
+ if (block_info.block_len > share->base.max_pack_length +4)
+ searching=1;
+ if (searching)
+ pos++;
+ else
+ pos=block_info.filepos+block_info.block_len;
+ block_info.second_read=0;
+ continue;
+ }
+
+ share->state.splitt++;
+ if (! found_record++)
+ {
+ sort_info.find_length=left_length=block_info.rec_len;
+ sort_info.start_recpos=pos;
+ if (!sort_info.fix_datafile)
+ sort_info.filepos=sort_info.start_recpos;
+ if (sort_info.fix_datafile && (testflag & T_EXTEND))
+ sort_info.pos=block_info.filepos+1;
+ else
+ sort_info.pos=block_info.filepos+block_info.block_len;
+ if (share->base.blobs)
+ {
+ if (!(to=fix_rec_buff_for_blob(info,block_info.rec_len)))
+ {
+ print_error("Not enough memory for blob at %lu",
+ (ulong) sort_info.start_recpos);
+ DBUG_RETURN(-1);
+ }
+ }
+ else
+ to= info->rec_buff;
+ }
+ if (left_length < block_info.data_len || ! block_info.data_len)
+ {
+ print_info("Found block with too small length at %lu; Skipped",
+ (ulong) sort_info.start_recpos);
+ goto try_next;
+ }
+ if (block_info.filepos + block_info.data_len > read_cache.end_of_file)
+ {
+ print_info("Found block that points outside data file at %lu",
+ (ulong) sort_info.start_recpos);
+ goto try_next;
+ }
+ if (_nisam_read_cache(&read_cache,to,block_info.filepos,
+ block_info.data_len, test(found_record == 1)))
+ {
+ print_info("Read error for block at: %lu (error: %d); Skipped",
+ (ulong) block_info.filepos,my_errno);
+ goto try_next;
+ }
+ left_length-=block_info.data_len;
+ to+=block_info.data_len;
+ pos=block_info.next_filepos;
+ if (pos == NI_POS_ERROR && left_length)
+ {
+ print_info("Wrong block with wrong total length starting at %lu",
+ (ulong) sort_info.start_recpos);
+ goto try_next;
+ }
+ if (pos + BLOCK_INFO_HEADER_LENGTH > read_cache.end_of_file)
+ {
+ print_info("Found link that points at %lu (outside data file) at %lu",
+ (ulong) pos,(ulong) sort_info.start_recpos);
+ goto try_next;
+ }
+ } while (left_length);
+
+ if (_nisam_rec_unpack(info,sort_info.record,info->rec_buff,
+ sort_info.find_length) != MY_FILE_ERROR)
+ {
+ if (read_cache.error < 0)
+ DBUG_RETURN(1);
+ if ((testflag & (T_EXTEND | T_REP)) || searching)
+ {
+ if (_nisam_rec_check(info, sort_info.record))
+ {
+ print_info("Found wrong packed record at %lu",
+ (ulong) sort_info.start_recpos);
+ goto try_next;
+ }
+ }
+ DBUG_RETURN(0);
+ }
+ try_next:
+ pos=sort_info.start_recpos+1;
+ searching=1;
+ }
+ case COMPRESSED_RECORD:
+ for (searching=0 ;; searching=1, sort_info.pos++)
+ {
+ if (_nisam_read_cache(&read_cache,(byte*) block_info.header,sort_info.pos,
+ share->pack.ref_length,1))
+ DBUG_RETURN(-1);
+ if (searching && ! sort_info.fix_datafile)
+ {
+ error_printed=1;
+ DBUG_RETURN(1); /* Something wrong with data */
+ }
+ sort_info.start_recpos=sort_info.pos;
+ VOID(_nisam_pack_get_block_info(&block_info,share->pack.ref_length,-1,
+ sort_info.pos));
+ if (!block_info.rec_len &&
+ sort_info.pos + MEMMAP_EXTRA_MARGIN == read_cache.end_of_file)
+ DBUG_RETURN(-1);
+ if (block_info.rec_len < (uint) share->min_pack_length ||
+ block_info.rec_len > (uint) share->max_pack_length)
+ {
+ if (! searching)
+ print_info("Found block with wrong recordlength: %d at %lu\n",
+ block_info.rec_len, (ulong) sort_info.pos);
+ continue;
+ }
+ if (_nisam_read_cache(&read_cache,(byte*) info->rec_buff,
+ block_info.filepos, block_info.rec_len,1))
+ {
+ if (! searching)
+ print_info("Couldn't read hole record from %lu",
+ (ulong) sort_info.pos);
+ continue;
+ }
+ if (_nisam_pack_rec_unpack(info,sort_info.record,info->rec_buff,
+ block_info.rec_len))
+ {
+ if (! searching)
+ print_info("Found wrong record at %lu",(ulong) sort_info.pos);
+ continue;
+ }
+ if (!sort_info.fix_datafile)
+ sort_info.filepos=sort_info.pos;
+ sort_info.max_pos=(sort_info.pos+=share->pack.ref_length+
+ block_info.rec_len);
+ share->state.splitt++;
+ info->packed_length=block_info.rec_len;
+ DBUG_RETURN(0);
+ }
+ }
+ DBUG_RETURN(1); /* Impossible */
+}
+
+
+ /* Write record to new file */
+
+static int sort_write_record()
+{
+ int flag;
+ uint block_length,reclength;
+ byte *from;
+ uchar *block_buff[3];
+ N_INFO *info;
+ ISAM_SHARE *share;
+ DBUG_ENTER("sort_write_record");
+
+ info=sort_info.info;
+ share=info->s;
+ if (sort_info.fix_datafile)
+ {
+ switch (sort_info.new_data_file_type) {
+ case STATIC_RECORD:
+ if (my_b_write(&info->rec_cache,sort_info.record, share->base.reclength))
+ {
+ print_error("%d when writing to datafile",my_errno);
+ DBUG_RETURN(1);
+ }
+ sort_info.filepos+=share->base.reclength;
+ break;
+ case DYNAMIC_RECORD:
+ if (! info->blobs)
+ from=info->rec_buff;
+ else
+ {
+ /* must be sure that local buffer is big enough */
+ reclength=info->s->base.pack_reclength+
+ _calc_total_blob_length(info,sort_info.record)+
+ ALIGN_SIZE(MAX_DYN_BLOCK_HEADER)+N_SPLITT_LENGTH+
+ DYN_DELETE_BLOCK_HEADER;
+ if (sort_info.buff_length < reclength)
+ {
+ if (!(sort_info.buff=my_realloc(sort_info.buff, (uint) reclength,
+ MYF(MY_FREE_ON_ERROR |
+ MY_ALLOW_ZERO_PTR))))
+ DBUG_RETURN(1);
+ sort_info.buff_length=reclength;
+ }
+ from=sort_info.buff+ALIGN_SIZE(MAX_DYN_BLOCK_HEADER);
+ }
+ reclength=_nisam_rec_pack(info,from,sort_info.record);
+ block_length=reclength+ 3 +test(reclength > 65532L);
+ if (block_length < share->base.min_block_length)
+ block_length=share->base.min_block_length;
+ flag=0;
+ info->update|=HA_STATE_WRITE_AT_END;
+ if (_nisam_write_part_record(info,0L,block_length,NI_POS_ERROR,
+ &from,&reclength,&flag))
+ {
+ print_error("%d when writing to datafile",my_errno);
+ DBUG_RETURN(1);
+ }
+ sort_info.filepos+=block_length;
+ break;
+ case COMPRESSED_RECORD:
+ reclength=info->packed_length;
+ save_integer((byte*) block_buff,share->pack.ref_length,reclength);
+ if (my_b_write(&info->rec_cache,(byte*) block_buff,share->pack.ref_length)
+ || my_b_write(&info->rec_cache,(byte*) info->rec_buff,reclength))
+ {
+ print_error("%d when writing to datafile",my_errno);
+ DBUG_RETURN(1);
+ }
+ sort_info.filepos+=reclength+share->pack.ref_length;
+ break;
+ }
+ }
+ share->state.records++;
+ if (testflag & T_WRITE_LOOP && share->state.records % WRITE_COUNT == 0)
+ {
+ printf("%lu\r",(ulong) share->state.records); VOID(fflush(stdout));
+ }
+ DBUG_RETURN(0);
+} /* sort_write_record */
+
+
+ /* Compare two keys from _create_index_by_sort */
+
+static int sort_key_cmp(const void *not_used __attribute__((unused)),
+ const void *a,const void *b)
+{
+ return (_nisam_key_cmp(sort_info.keyseg,*((uchar**) a),*((uchar**) b),0,
+ SEARCH_SAME));
+} /* sort_key_cmp */
+
+
+static int sort_key_write(a)
+const void *a;
+{
+ int cmp=sort_info.key_block->inited ?
+ _nisam_key_cmp(sort_info.keyseg,sort_info.key_block->lastkey,(uchar*) a,
+ 0,SEARCH_FIND) : -1L;
+ if ((sort_info.keyinfo->base.flag & HA_NOSAME) &&
+ cmp == 0)
+ {
+ sort_info.dupp++;
+ print_warning("Dupplicate key for record at %10lu against record at %10lu",
+ sort_info.info->lastpos=get_record_for_key(sort_info.info,
+ sort_info.keyinfo,
+ (uchar*) a),
+ get_record_for_key(sort_info.info,sort_info.keyinfo,
+ sort_info.key_block->lastkey));
+ if (testflag & T_VERBOSE)
+ _nisam_print_key(stdout,sort_info.keyseg,(uchar*) a);
+ return(sort_delete_record());
+ }
+ if (cmp)
+ sort_info.unique++;
+#ifndef DBUG_OFF
+ if (cmp > 0)
+ {
+ print_error("Fatal intern error: Keys are not in order from sort");
+ return(1);
+ }
+#endif
+ return (sort_insert_key(sort_info.key_block,(uchar*) a,NI_POS_ERROR));
+} /* sort_key_write */
+
+
+ /* get pointer to record from a key */
+
+static ulong get_record_for_key(info,keyinfo,key)
+N_INFO *info;
+N_KEYDEF *keyinfo;
+uchar *key;
+{
+ return _nisam_dpos(info,0,key+_nisam_keylength(keyinfo,key));
+} /* get_record_for_key */
+
+
+ /* Insert a key in sort-key-blocks */
+
+static int sort_insert_key(key_block,key,prev_block)
+reg1 SORT_KEY_BLOCKS *key_block;
+uchar *key;
+ulong prev_block;
+{
+ uint a_length,t_length,nod_flag;
+ ulong filepos;
+ uchar *anc_buff,*lastkey;
+ S_PARAM s_temp;
+ N_INFO *info;
+ DBUG_ENTER("sort_insert_key");
+
+ anc_buff=key_block->buff;
+ info=sort_info.info;
+ lastkey=key_block->lastkey;
+ nod_flag= (key_block == sort_info.key_block ? 0 :
+ sort_info.info->s->base.key_reflength);
+
+ if (!key_block->inited)
+ {
+ key_block->inited=1;
+ if (key_block == sort_info.key_block_end)
+ {
+ print_error("To many keyblocklevels; Try increasing sort_key_blocks");
+ DBUG_RETURN(1);
+ }
+ a_length=2+nod_flag;
+ key_block->end_pos=anc_buff+2;
+ lastkey=0; /* No previous key in block */
+ }
+ else
+ a_length=getint(anc_buff);
+
+ /* Save pointer to previous block */
+ if (nod_flag)
+ _nisam_kpointer(info,key_block->end_pos,prev_block);
+
+ t_length=_nisam_get_pack_key_length(sort_info.keyinfo,nod_flag,
+ (uchar*) 0,lastkey,key,&s_temp);
+ _nisam_store_key(sort_info.keyinfo,key_block->end_pos+nod_flag,&s_temp);
+ a_length+=t_length;
+ putint(anc_buff,a_length,nod_flag);
+ key_block->end_pos+=t_length;
+ if (a_length <= sort_info.keyinfo->base.block_length)
+ {
+ VOID(_nisam_move_key(sort_info.keyinfo,key_block->lastkey,key));
+ key_block->last_length=a_length-t_length;
+ DBUG_RETURN(0);
+ }
+
+ /* Fill block with end-zero and write filled block */
+ putint(anc_buff,key_block->last_length,nod_flag);
+ bzero((byte*) anc_buff+key_block->last_length,
+ sort_info.keyinfo->base.block_length- key_block->last_length);
+ if ((filepos=_nisam_new(info,sort_info.keyinfo)) == NI_POS_ERROR)
+ return 1;
+ if (my_pwrite(info->s->kfile,(byte*) anc_buff,
+ (uint) sort_info.keyinfo->base.block_length,filepos,MYF_RW))
+ DBUG_RETURN(1);
+ DBUG_DUMP("buff",(byte*) anc_buff,getint(anc_buff));
+
+ /* Write separator-key to block in next level */
+ if (sort_insert_key(key_block+1,key_block->lastkey,filepos))
+ DBUG_RETURN(1);
+
+ /* clear old block and write new key in it */
+ key_block->inited=0;
+ DBUG_RETURN(sort_insert_key(key_block,key,prev_block));
+} /* sort_insert_key */
+
+
+ /* Delete record when we found a dupplicated key */
+
+static int sort_delete_record()
+{
+ uint i;
+ int old_file,error;
+ uchar *key;
+ N_INFO *info;
+ DBUG_ENTER("sort_delete_record");
+
+ if (rep_quick == 1)
+ {
+ VOID(fputs("Quick-recover aborted; Run recovery without switch 'q' or with switch -qq\n",stderr));
+ error_printed=1;
+ DBUG_RETURN(1);
+ }
+ info=sort_info.info;
+ if (info->s->base.options & HA_OPTION_COMPRESS_RECORD)
+ {
+ VOID(fputs("Recover aborted; Can't run standard recovery on compressed tables\nwith errors in data-file\nUse switch '--safe-recover' to fix it\n",stderr));
+ error_printed=1;
+ DBUG_RETURN(1);
+ }
+
+ old_file=info->dfile;
+ info->dfile=info->rec_cache.file;
+ if (sort_info.key)
+ {
+ key=info->lastkey+info->s->base.max_key_length;
+ if ((*info->s->read_rnd)(info,sort_info.record,info->lastpos,0) < 0)
+ {
+ print_error("Can't read record to be removed");
+ info->dfile=old_file;
+ DBUG_RETURN(1);
+ }
+
+ for (i=0 ; i < sort_info.key ; i++)
+ {
+ VOID(_nisam_make_key(info,i,key,sort_info.record,info->lastpos));
+ if (_nisam_ck_delete(info,i,key))
+ {
+ print_error("Can't delete key %d from record to be removed",i+1);
+ info->dfile=old_file;
+ DBUG_RETURN(1);
+ }
+ }
+ }
+ error=flush_io_cache(&info->rec_cache) || (*info->s->delete_record)(info);
+ info->dfile=old_file; /* restore actual value */
+ info->s->state.records--;
+ DBUG_RETURN(error);
+} /* sort_delete_record */
+
+
+ /* Fix all pending blocks and flush everything to disk */
+
+static int flush_pending_blocks()
+{
+ uint nod_flag,length;
+ ulong filepos;
+ N_INFO *info;
+ SORT_KEY_BLOCKS *key_block;
+ DBUG_ENTER("flush_pending_blocks");
+
+ filepos= NI_POS_ERROR; /* if empty file */
+ info=sort_info.info;
+ nod_flag=0;
+ for (key_block=sort_info.key_block ; key_block->inited ; key_block++)
+ {
+ key_block->inited=0;
+ length=getint(key_block->buff);
+ if (nod_flag)
+ _nisam_kpointer(info,key_block->end_pos,filepos);
+ if ((filepos=_nisam_new(info,sort_info.keyinfo)) == NI_POS_ERROR)
+ DBUG_RETURN(1);
+ bzero((byte*) key_block->buff+length,
+ sort_info.keyinfo->base.block_length-length);
+ if (my_pwrite(info->s->kfile,(byte*) key_block->buff,
+ (uint) sort_info.keyinfo->base.block_length,filepos,MYF_RW))
+ DBUG_RETURN(1);
+ DBUG_DUMP("buff",(byte*) key_block->buff,length);
+ nod_flag=1;
+ }
+ info->s->state.key_root[sort_info.key]=filepos; /* Last is root for tree */
+ DBUG_RETURN(0);
+} /* flush_pending_blocks */
+
+
+ /* alloc space and pointers for key_blocks */
+
+static SORT_KEY_BLOCKS *alloc_key_blocks(blocks,buffer_length)
+uint blocks,buffer_length;
+{
+ reg1 uint i;
+ SORT_KEY_BLOCKS *block;
+ DBUG_ENTER("alloc_key_blocks");
+
+ if (!(block=(SORT_KEY_BLOCKS*) my_malloc((sizeof(SORT_KEY_BLOCKS)+
+ buffer_length+IO_SIZE)*blocks,
+ MYF(0))))
+ {
+ print_error("Not Enough memory for sort-key-blocks");
+ return(0);
+ }
+ for (i=0 ; i < blocks ; i++)
+ {
+ block[i].inited=0;
+ block[i].buff=(uchar*) (block+blocks)+(buffer_length+IO_SIZE)*i;
+ }
+ DBUG_RETURN(block);
+} /* alloc_key_blocks */
+
+
+ /* print warnings and errors */
+ /* VARARGS */
+
+static void print_info(const char * fmt,...)
+{
+ va_list args;
+
+ va_start(args,fmt);
+ VOID(vfprintf(stdout, fmt, args));
+ VOID(fputc('\n',stdout));
+ va_end(args);
+ return;
+}
+
+/* VARARGS */
+
+static void print_warning(const char * fmt,...)
+{
+ va_list args;
+ DBUG_ENTER("print_warning");
+
+ if (!warning_printed && !error_printed)
+ {
+ fflush(stdout);
+ if (testflag & T_SILENT)
+ fprintf(stderr,"%s: ISAM file %s\n",my_progname,isam_file_name);
+ }
+ warning_printed=1;
+ va_start(args,fmt);
+ fprintf(stderr,"%s: warning: ",my_progname);
+ VOID(vfprintf(stderr, fmt, args));
+ VOID(fputc('\n',stderr));
+ va_end(args);
+ DBUG_VOID_RETURN;
+}
+
+/* VARARGS */
+
+void print_error(const char *fmt,...)
+{
+ va_list args;
+ DBUG_ENTER("print_error");
+ DBUG_PRINT("enter",("format: %s",fmt));
+
+ if (!warning_printed && !error_printed)
+ {
+ fflush(stdout);
+ if (testflag & T_SILENT)
+ fprintf(stderr,"%s: ISAM file %s\n",my_progname,isam_file_name);
+ }
+ error_printed|=1;
+ va_start(args,fmt);
+ fprintf(stderr,"%s: error: ",my_progname);
+ VOID(vfprintf(stderr, fmt, args));
+ VOID(fputc('\n',stderr));
+ va_end(args);
+ DBUG_VOID_RETURN;
+}
+
+ /* Check if file is almost full */
+
+static int test_if_almost_full(info)
+N_INFO *info;
+{
+ double diff= 0.9;
+ if (info->s->base.options & HA_OPTION_COMPRESS_RECORD)
+ { /* Fix problem with pack_isam */
+ diff=1.0;
+ if (info->s->base.rec_reflength == 4)
+ info->s->base.max_data_file_length= (uint32) ~0L;
+ else
+ info->s->base.max_data_file_length=
+ 1L << (info->s->base.rec_reflength);
+ }
+ return (my_seek(info->s->kfile,0L,MY_SEEK_END,MYF(0)) >
+ (ulong) (info->s->base.max_key_file_length*diff) ||
+ my_seek(info->dfile,0L,MY_SEEK_END,MYF(0)) >
+ (ulong) (info->s->base.max_data_file_length*diff));
+}
+
+ /* Recreate table with bigger more alloced record-data */
+
+static int recreate_database(org_info,filename)
+N_INFO **org_info;
+char *filename;
+{
+ int error;
+ N_INFO info;
+ ISAM_SHARE share;
+ N_KEYDEF *keyinfo;
+ N_RECINFO *recinfo,*rec,*end;
+ uint unpack;
+ ulong max_records;
+ char name[FN_REFLEN];
+
+ error=1; /* Default error */
+ info= **org_info;
+ share= *(*org_info)->s;
+ unpack= (share.base.options & HA_OPTION_COMPRESS_RECORD) &&
+ (testflag & T_UNPACK);
+ if (!(keyinfo=(N_KEYDEF*) my_alloca(sizeof(N_KEYDEF)*share.base.keys)))
+ return 0;
+ memcpy((byte*) keyinfo,(byte*) share.keyinfo,
+ (size_t) (sizeof(N_KEYDEF)*share.base.keys));
+ if (!(recinfo=(N_RECINFO*)
+ my_alloca(sizeof(N_RECINFO)*(share.base.fields+1))))
+ {
+ my_afree((gptr) keyinfo);
+ return 1;
+ }
+ memcpy((byte*) recinfo,(byte*) share.rec,
+ (size_t) (sizeof(N_RECINFO)*(share.base.fields+1)));
+ for (rec=recinfo,end=recinfo+share.base.fields; rec != end ; rec++)
+ {
+ if (rec->base.type == (int) FIELD_BLOB)
+ rec->base.length+=sizeof(char*);
+ else if (unpack && !(share.base.options & HA_OPTION_PACK_RECORD))
+ rec->base.type=(int) FIELD_NORMAL;
+ }
+
+ if (share.base.options & HA_OPTION_COMPRESS_RECORD)
+ share.base.records=max_records=share.state.records;
+ else if (share.base.min_pack_length)
+ max_records=(ulong) (my_seek(info.dfile,0L,MY_SEEK_END,MYF(0)) /
+ (ulong) share.base.min_pack_length);
+ else
+ max_records=0;
+ unpack= (share.base.options & HA_OPTION_COMPRESS_RECORD) &&
+ (testflag & T_UNPACK);
+ share.base.options&= ~HA_OPTION_TEMP_COMPRESS_RECORD;
+ VOID(nisam_close(*org_info));
+ if (nisam_create(fn_format(name,filename,"",N_NAME_IEXT,
+ 4+ (opt_follow_links ? 16 : 0)),
+ share.base.keys,keyinfo,recinfo,
+ max(max_records,share.base.records),share.base.reloc,
+ HA_DONT_TOUCH_DATA,
+ share.base.options |
+ (unpack ? HA_OPTION_TEMP_COMPRESS_RECORD
+ : 0),
+ (ulong) my_seek(info.dfile,0L,MY_SEEK_END,MYF(0))))
+ {
+ print_error("Got error %d when trying to recreate indexfile",my_errno);
+ goto end;
+ }
+ *org_info=nisam_open(name,O_RDWR,
+ (testflag & T_WAIT_FOREVER) ? HA_OPEN_WAIT_IF_LOCKED :
+ (testflag & T_DESCRIPT) ? HA_OPEN_IGNORE_IF_LOCKED :
+ HA_OPEN_ABORT_IF_LOCKED);
+ if (!*org_info)
+ {
+ print_error("Got error %d when trying to open re-created indexfile",
+ my_errno);
+ goto end;
+ }
+ /* We are modifing */
+ (*org_info)->s->base.options&= ~HA_OPTION_READ_ONLY_DATA;
+ VOID(_nisam_readinfo(*org_info,F_WRLCK,0));
+ (*org_info)->s->state.records=share.state.records;
+ if (share.base.create_time)
+ (*org_info)->s->base.create_time=share.base.create_time;
+ (*org_info)->s->state.uniq=(*org_info)->this_uniq=
+ share.state.uniq;
+ (*org_info)->s->state.del=share.state.del;
+ (*org_info)->s->state.dellink=share.state.dellink;
+ (*org_info)->s->state.empty=share.state.empty;
+ (*org_info)->s->state.data_file_length=share.state.data_file_length;
+ if (update_state_info(*org_info,UPDATE_TIME | UPDATE_STAT))
+ goto end;
+ error=0;
+end:
+ my_afree((gptr) keyinfo);
+ my_afree((gptr) recinfo);
+ return error;
+}
+
+ /* Store long in 1,2,3 or 4 bytes */
+
+static void save_integer(pos,pack_length,value)
+byte *pos;
+uint pack_length;
+ulong value;
+{
+ switch (pack_length) {
+ case 4: int4store(pos,value); break;
+ case 3: int3store(pos,value); break;
+ case 2: int2store(pos,(uint) value); break;
+ case 1: pos[0]= (char) (uchar) value; break;
+ default: break;
+ }
+ return;
+}
+
+ /* write suffix to data file if neaded */
+
+static int write_data_suffix(info)
+N_INFO *info;
+{
+ if (info->s->base.options & HA_OPTION_COMPRESS_RECORD &&
+ sort_info.fix_datafile)
+ {
+ char buff[MEMMAP_EXTRA_MARGIN];
+ bzero(buff,sizeof(buff));
+ if (my_b_write(&info->rec_cache,buff,sizeof(buff)))
+ {
+ print_error("%d when writing to datafile",my_errno);
+ return 1;
+ }
+ read_cache.end_of_file+=sizeof(buff);
+ }
+ return 0;
+}
+
+
+ /* Update state and isamchk_time of indexfile */
+
+static int update_state_info(info,update)
+N_INFO *info;
+uint update;
+{
+ ISAM_SHARE *share=info->s;
+ uint base_pos=uint2korr(info->s->state.header.base_pos);
+
+ if (update & (UPDATE_STAT | UPDATE_SORT | UPDATE_TIME))
+ {
+ if (offsetof(N_BASE_INFO,rec_per_key) >
+ uint2korr(share->state.header.base_info_length))
+ {
+ VOID(fputs("Internal error: Trying to change base of old table\n",
+ stderr));
+ }
+ else
+ {
+ if (update & UPDATE_TIME)
+ {
+ share->base.isamchk_time= (long) time((time_t*) 0);
+ if (!share->base.create_time)
+ share->base.create_time=share->base.isamchk_time;
+ if (my_pwrite(share->kfile,(gptr) &share->base.create_time,
+ sizeof(long)*2,
+ base_pos+offsetof(N_BASE_INFO,create_time),
+ MYF(MY_NABP)))
+ goto err;
+ }
+ if (update & (UPDATE_STAT | UPDATE_SORT))
+ {
+ if (my_pwrite(share->kfile,(gptr) share->base.rec_per_key,
+ sizeof(long)*share->state.keys+sizeof(uint),
+ base_pos+offsetof(N_BASE_INFO,rec_per_key),
+ MYF(MY_NABP)))
+ goto err;
+ }
+ }
+ }
+ { /* Force update of status */
+ int error;
+ uint r_locks=share->r_locks,w_locks=share->w_locks;
+ share->r_locks=share->w_locks=0;
+ error=_nisam_writeinfo(info,2);
+ share->r_locks=r_locks; share->w_locks=w_locks;
+ if (!error)
+ return 0;
+ }
+err:
+ print_error("%d when updateing keyfile",my_errno);
+ return 1;
+}
diff --git a/isam/isamdef.h b/isam/isamdef.h
new file mode 100644
index 00000000000..da08b5f6a14
--- /dev/null
+++ b/isam/isamdef.h
@@ -0,0 +1,416 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* Denna fil includeras i alla isam-filer */
+
+#define ISAM_LIBRARY
+#include <nisam.h> /* Structs & some defines */
+#ifdef THREAD
+#include <my_pthread.h>
+#include <thr_lock.h>
+#else
+#include <my_no_pthread.h>
+#endif
+
+#ifdef my_write
+#undef my_write /* We want test if disk full */
+#endif
+#undef HA_SORT_ALLOWS_SAME
+#define HA_SORT_ALLOWS_SAME 128 /* Can't be > 128 in NISAM */
+
+#ifdef __WATCOMC__
+#pragma pack(2)
+#define uint uint16 /* Same format as in MSDOS */
+#endif
+#ifdef __ZTC__
+#pragma ZTC align 2
+#define uint uint16 /* Same format as in MSDOS */
+#endif
+#if defined(__WIN__) && defined(_MSC_VER)
+#pragma pack(push,isamdef,2)
+#define uint uint16
+#endif
+
+typedef struct st_state_info
+{
+ struct { /* Fileheader */
+ uchar file_version[4];
+ uchar options[2];
+ uchar header_length[2];
+ uchar state_info_length[2];
+ uchar base_info_length[2];
+ uchar base_pos[2];
+ uchar not_used[2];
+ } header;
+
+ ulong records; /* Antal record i databasen */
+ ulong del; /* Antalet borttagna poster */
+ ulong dellink; /* L{nk till n{sta borttagna */
+ ulong key_file_length;
+ ulong data_file_length;
+ ulong splitt; /* Antal splittrade delar */
+ ulong empty; /* Outnyttjat utrymme */
+ ulong process; /* Vem som senast uppdatera */
+ ulong loop; /* not used anymore */
+ ulong uniq; /* Unik nr i denna process */
+ ulong key_root[N_MAXKEY]; /* Pekare till rootblocken */
+ ulong key_del[N_MAXKEY]; /* Del-l{nkar f|r n-block */
+ ulong sec_index_changed; /* Updated when new sec_index */
+ ulong sec_index_used; /* 1 bit for each sec index in use */
+ ulong version; /* timestamp of create */
+ uint keys; /* Keys in use for database */
+} N_STATE_INFO;
+
+
+typedef struct st_base_info
+{
+ ulong keystart; /* Var nycklarna b|rjar */
+ ulong records,reloc; /* Parameter vid skapandet */
+ ulong max_pack_length; /* Max possibly length of packed rec.*/
+ ulong max_data_file_length;
+ ulong max_key_file_length;
+ uint reclength; /* length of unpacked record */
+ uint options; /* Options used */
+ uint pack_reclength; /* Length of full packed rec. */
+ uint min_pack_length;
+ uint min_block_length;
+ uint rec_reflength; /* = 2 or 3 or 4 */
+ uint key_reflength; /* = 2 or 3 or 4 */
+ uint keys; /* Keys defined for database */
+ uint blobs; /* Number of blobs */
+ uint max_block; /* Max blockl{ngd anv{nd */
+ uint max_key_length; /* L{ngsta nyckel-l{ngden */
+ uint fields, /* Antal f{lt i databasen */
+ pack_fields, /* Packade f{lt i databasen */
+ pack_bits; /* Length of packed bits */
+ time_t create_time; /* Time when created database */
+ time_t isamchk_time; /* Time for last recover */
+ ulong rec_per_key[N_MAXKEY]; /* for sql optimizing */
+ uint sortkey; /* sorted by this key */
+} N_BASE_INFO;
+
+
+#ifdef __ZTC__
+#pragma ZTC align
+#undef uint
+#endif
+#ifdef __WATCOMC__
+#pragma pack()
+#undef uint
+#endif
+#if defined(__WIN__) && defined(_MSC_VER)
+#pragma pack(pop,isamdef)
+#undef uint
+#endif
+
+ /* Structs used intern in database */
+
+typedef struct st_n_blob /* Info of record */
+{
+ uint offset; /* Offset to blob in record */
+ uint pack_length; /* Type of packed length */
+ uint length; /* Calc:ed for each record */
+} N_BLOB;
+
+
+typedef struct st_isam_pack {
+ ulong header_length;
+ uint ref_length;
+} N_PACK;
+
+
+typedef struct st_isam_share { /* Shared between opens */
+ N_STATE_INFO state;
+ N_BASE_INFO base;
+ N_KEYDEF *keyinfo; /* Nyckelinfo */
+ N_RECINFO *rec; /* Pointer till recdata */
+ N_PACK pack; /* Data about packed records */
+ N_BLOB *blobs; /* Pointer to blobs */
+ char *filename; /* Name of indexfile */
+ byte *file_map; /* mem-map of file if possible */
+ ulong this_process; /* processid */
+ ulong last_process; /* For table-change-check */
+ ulong last_version; /* Version on start */
+ uint rec_reflength; /* rec_reflength in use now */
+ int kfile; /* Shared keyfile */
+ int mode; /* mode of file on open */
+ int reopen; /* How many times reopened */
+ uint state_length;
+ uint w_locks,r_locks; /* Number of read/write locks */
+ uint min_pack_length; /* Theese is used by packed data */
+ uint max_pack_length;
+ uint blocksize; /* blocksize of keyfile */
+ my_bool changed,not_flushed; /* If changed since lock */
+ int rnd; /* rnd-counter */
+ DECODE_TREE *decode_trees;
+ uint16 *decode_tables;
+ enum data_file_type data_file_type;
+ int (*read_record)(struct st_isam_info*, ulong, byte*);
+ int (*write_record)(struct st_isam_info*, const byte*);
+ int (*update_record)(struct st_isam_info*, ulong, const byte*);
+ int (*delete_record)(struct st_isam_info*);
+ int (*read_rnd)(struct st_isam_info*, byte*, ulong, int);
+ int (*compare_record)(struct st_isam_info*, const byte *);
+#ifdef THREAD
+ THR_LOCK lock;
+ pthread_mutex_t intern_lock; /* Locking for use with _locking */
+#endif
+} ISAM_SHARE;
+
+
+typedef uint bit_type;
+
+typedef struct st_bit_buff { /* Used for packing of record */
+ bit_type current_byte;
+ uint bits;
+ uchar *pos,*end;
+ uint error;
+} BIT_BUFF;
+
+
+typedef struct st_isam_info {
+ ISAM_SHARE *s; /* Shared between open:s */
+ N_BLOB *blobs; /* Pointer to blobs */
+ int dfile; /* The datafile */
+ BIT_BUFF bit_buff;
+ uint options;
+ uint opt_flag; /* Optim. for space/speed */
+ uint update; /* If file changed since open */
+ char *filename; /* parameter to open filename */
+ ulong this_uniq; /* uniq filenumber or thread */
+ ulong last_uniq; /* last uniq number */
+ ulong this_loop; /* counter for this open */
+ ulong last_loop; /* last used counter */
+ ulong lastpos, /* Last record position */
+ nextpos; /* Position to next record */
+ ulong int_pos; /* Intern variabel */
+ ulong dupp_key_pos; /* Position to record with dupp key */
+ ulong last_search_keypage;
+ ulong save_lastpos;
+ uint packed_length; /* Length of found, packed record */
+ uint alloced_rec_buff_length; /* Max recordlength malloced */
+ uchar *buff, /* Temp area for key */
+ *lastkey; /* Last used search key */
+ byte *rec_buff, /* Tempbuff for recordpack */
+ *rec_alloc; /* Malloced area for record */
+ uchar *int_keypos, /* Intern variabel */
+ *int_maxpos; /* Intern variabel */
+ int lastinx; /* Last used index */
+ int errkey; /* Got last error on this key */
+ uint data_changed; /* Somebody has changed data */
+ int lock_type; /* How database was locked */
+ int tmp_lock_type; /* When locked by readinfo */
+ int was_locked; /* Was locked in panic */
+ myf lock_wait; /* is 0 or MY_DONT_WAIT */
+ my_bool page_changed;
+ my_bool buff_used;
+ uint save_update; /* When using KEY_READ */
+ int save_lastinx;
+ int (*read_record)(struct st_isam_info*, ulong, byte*);
+ LIST open_list;
+ IO_CACHE rec_cache; /* When cacheing records */
+#ifdef THREAD
+ THR_LOCK_DATA lock;
+#endif
+} N_INFO;
+
+
+ /* Some defines used by isam-funktions */
+
+#define USE_HOLE_KEY 0 /* Use hole key in _nisam_search() */
+#define F_EXTRA_LCK -1
+
+ /* bits in opt_flag */
+#define MEMMAP_USED 32
+#define REMEMBER_OLD_POS 64
+
+#define getint(x) ((uint) (uint16) *((int16*) (x)) & 32767)
+#define putint(x,y,nod) (*((uint16*) (x))= ((nod ? (uint16) 32768 : 0)+(uint16) (y)))
+#ifdef WORDS_BIGENDIAN
+#define test_if_nod(x) (x[0] & 128 ? info->s->base.key_reflength : 0)
+#else
+#define test_if_nod(x) (x[1] & 128 ? info->s->base.key_reflength : 0)
+#endif
+
+#define N_MIN_BLOCK_LENGTH 8 /* Because of delete-link */
+#define N_EXTEND_BLOCK_LENGTH 20 /* Don't use to small record-blocks */
+#define N_SPLITT_LENGTH ((N_EXTEND_BLOCK_LENGTH+3)*2)
+#define MAX_DYN_BLOCK_HEADER 11 /* Max prefix of record-block */
+#define DYN_DELETE_BLOCK_HEADER 8 /* length of delete-block-header */
+#define MEMMAP_EXTRA_MARGIN 7 /* Write this as a suffix for file */
+#define INDEX_BLOCK_MARGIN 16 /* Safety margin for .ISM tables */
+
+#define PACK_TYPE_SELECTED 1 /* Bits in field->pack_type */
+#define PACK_TYPE_SPACE_FIELDS 2
+#define PACK_TYPE_ZERO_FILL 4
+
+#ifdef THREAD
+extern pthread_mutex_t THR_LOCK_isam;
+#endif
+
+ /* Some extern variables */
+
+extern LIST *nisam_open_list;
+extern uchar NEAR nisam_file_magic[],NEAR nisam_pack_file_magic[];
+extern uint NEAR nisam_read_vec[],nisam_quick_table_bits;
+extern File nisam_log_file;
+
+ /* This is used by _nisam_get_pack_key_length och _nisam_store_key */
+
+typedef struct st_s_param
+{
+ uint ref_length,key_length,
+ n_ref_length,
+ n_length,
+ totlength,
+ part_of_prev_key,prev_length;
+ uchar *key, *prev_key;
+} S_PARAM;
+
+ /* Prototypes for intern functions */
+
+extern int _nisam_read_dynamic_record(N_INFO *info,ulong filepos,byte *buf);
+extern int _nisam_write_dynamic_record(N_INFO*, const byte*);
+extern int _nisam_update_dynamic_record(N_INFO*, ulong, const byte*);
+extern int _nisam_delete_dynamic_record(N_INFO *info);
+extern int _nisam_cmp_dynamic_record(N_INFO *info,const byte *record);
+extern int _nisam_read_rnd_dynamic_record(N_INFO *, byte *,ulong, int);
+extern int _nisam_write_blob_record(N_INFO*, const byte*);
+extern int _nisam_update_blob_record(N_INFO*, ulong, const byte*);
+extern int _nisam_read_static_record(N_INFO *info,ulong filepos,byte *buf);
+extern int _nisam_write_static_record(N_INFO*, const byte*);
+extern int _nisam_update_static_record(N_INFO*, ulong, const byte*);
+extern int _nisam_delete_static_record(N_INFO *info);
+extern int _nisam_cmp_static_record(N_INFO *info,const byte *record);
+extern int _nisam_read_rnd_static_record(N_INFO*, byte *,ulong, int);
+extern int _nisam_ck_write(N_INFO *info,uint keynr,uchar *key);
+extern int _nisam_enlarge_root(N_INFO *info,uint keynr,uchar *key);
+extern int _nisam_insert(N_INFO *info,N_KEYDEF *keyinfo,uchar *key,
+ uchar *anc_buff,uchar *key_pos,uchar *key_buff,
+ uchar *father_buff, uchar *father_keypos,
+ ulong father_page);
+extern int _nisam_splitt_page(N_INFO *info,N_KEYDEF *keyinfo,uchar *key,
+ uchar *buff,uchar *key_buff);
+extern uchar *_nisam_find_half_pos(N_INFO *info,N_KEYDEF *keyinfo,uchar *page,
+ uchar *key);
+extern uint _nisam_get_pack_key_length(N_KEYDEF *keyinfo,uint nod_flag,
+ uchar *key_pos,uchar *key_buff,
+ uchar *key, S_PARAM *s_temp);
+extern void _nisam_store_key(N_KEYDEF *keyinfo,uchar *key_pos,
+ S_PARAM *s_temp);
+extern int _nisam_ck_delete(N_INFO *info,uint keynr,uchar *key);
+extern int _nisam_readinfo(N_INFO *info,int lock_flag,int check_keybuffer);
+extern int _nisam_writeinfo(N_INFO *info, uint flag);
+extern int _nisam_test_if_changed(N_INFO *info);
+extern int _nisam_check_index(N_INFO *info,int inx);
+extern int _nisam_search(N_INFO *info,N_KEYDEF *keyinfo,uchar *key,uint key_len,uint nextflag,ulong pos);
+extern int _nisam_bin_search(struct st_isam_info *info,N_KEYDEF *keyinfo,uchar *page,uchar *key,uint key_len,uint comp_flag,uchar * *ret_pos,uchar *buff);
+extern int _nisam_seq_search(N_INFO *info,N_KEYDEF *keyinfo,uchar *page,uchar *key,uint key_len,uint comp_flag,uchar * *ret_pos,uchar *buff);
+extern ulong _nisam_kpos(uint nod_flag,uchar *after_key);
+extern void _nisam_kpointer(N_INFO *info,uchar *buff,ulong pos);
+extern ulong _nisam_dpos(N_INFO *info, uint nod_flag,uchar *after_key);
+extern void _nisam_dpointer(N_INFO *info, uchar *buff,ulong pos);
+extern int _nisam_key_cmp(N_KEYSEG *keyseg,uchar *a,uchar *b,
+ uint key_length,uint nextflag);
+extern uint _nisam_get_key(N_KEYDEF *keyinfo,uint nod_flag,uchar * *page,uchar *key);
+extern uint _nisam_get_static_key(N_KEYDEF *keyinfo,uint nod_flag,uchar * *page,uchar *key);
+extern uchar *_nisam_get_last_key(N_INFO *info,N_KEYDEF *keyinfo,uchar *keypos,uchar *lastkey,uchar *endpos);
+extern uint _nisam_keylength(N_KEYDEF *keyinfo,uchar *key);
+extern uchar *_nisam_move_key(N_KEYDEF *keyinfo,uchar *to,uchar *from);
+extern int _nisam_search_next(N_INFO *info,N_KEYDEF *keyinfo,uchar *key,uint nextflag,ulong pos);
+extern int _nisam_search_first(N_INFO *info,N_KEYDEF *keyinfo,ulong pos);
+extern int _nisam_search_last(N_INFO *info,N_KEYDEF *keyinfo,ulong pos);
+extern uchar *_nisam_fetch_keypage(N_INFO *info,N_KEYDEF *keyinfo,my_off_t page,
+ uchar *buff,int return_buffer);
+extern int _nisam_write_keypage(N_INFO *info,N_KEYDEF *keyinfo,my_off_t page,
+ uchar *buff);
+extern int _nisam_dispose(N_INFO *info,N_KEYDEF *keyinfo,my_off_t pos);
+extern ulong _nisam_new(N_INFO *info,N_KEYDEF *keyinfo);
+extern uint _nisam_make_key(N_INFO *info,uint keynr,uchar *key,
+ const char *record,ulong filepos);
+extern uint _nisam_pack_key(N_INFO *info,uint keynr,uchar *key,uchar *old,uint key_length);
+extern int _nisam_read_key_record(N_INFO *info,ulong filepos,byte *buf);
+extern int _nisam_read_cache(IO_CACHE *info,byte *buff,ulong pos,
+ uint length,int re_read_if_possibly);
+extern byte *fix_rec_buff_for_blob(N_INFO *info,uint blob_length);
+extern uint _nisam_rec_unpack(N_INFO *info,byte *to,byte *from,
+ uint reclength);
+my_bool _nisam_rec_check(N_INFO *info,const char *from);
+extern int _nisam_write_part_record(N_INFO *info,ulong filepos,uint length,
+ ulong next_filepos,byte **record,
+ uint *reclength,int *flag);
+extern void _nisam_print_key(FILE *stream,N_KEYSEG *keyseg,const uchar *key);
+extern my_bool _nisam_read_pack_info(N_INFO *info,pbool fix_keys);
+extern int _nisam_read_pack_record(N_INFO *info,ulong filepos,byte *buf);
+extern int _nisam_read_rnd_pack_record(N_INFO*, byte *,ulong, int);
+extern int _nisam_pack_rec_unpack(N_INFO *info,byte *to,byte *from,
+ uint reclength);
+
+typedef struct st_sortinfo {
+ uint key_length;
+ ulong max_records;
+ int (*key_cmp)(const void *, const void *, const void *);
+ int (*key_read)(void *buff);
+ int (*key_write)(const void *buff);
+ void (*lock_in_memory)(void);
+} SORT_PARAM;
+
+int _create_index_by_sort(SORT_PARAM *info,pbool no_messages,
+ uint sortbuff_size);
+
+#define BLOCK_INFO_HEADER_LENGTH 11
+
+typedef struct st_block_info { /* Parameter to _nisam_get_block_info */
+ uchar header[BLOCK_INFO_HEADER_LENGTH];
+ uint rec_len;
+ uint data_len;
+ uint block_len;
+ ulong filepos; /* Must be ulong on Alpha! */
+ ulong next_filepos;
+ uint second_read;
+} BLOCK_INFO;
+
+ /* bits in return from _nisam_get_block_info */
+
+#define BLOCK_FIRST 1
+#define BLOCK_LAST 2
+#define BLOCK_DELETED 4
+#define BLOCK_ERROR 8 /* Wrong data */
+#define BLOCK_SYNC_ERROR 16 /* Right data at wrong place */
+#define BLOCK_FATAL_ERROR 32 /* hardware-error */
+
+enum nisam_log_commands {
+ LOG_OPEN,LOG_WRITE,LOG_UPDATE,LOG_DELETE,LOG_CLOSE,LOG_EXTRA,LOG_LOCK
+};
+
+#define nisam_log_simple(a,b,c,d) if (nisam_log_file >= 0) _nisam_log(a,b,c,d)
+#define nisam_log_command(a,b,c,d,e) if (nisam_log_file >= 0) _nisam_log_command(a,b,c,d,e)
+#define nisam_log_record(a,b,c,d,e) if (nisam_log_file >= 0) _nisam_log_record(a,b,c,d,e)
+
+extern uint _nisam_get_block_info(BLOCK_INFO *,File, ulong);
+extern uint _nisam_rec_pack(N_INFO *info,byte *to,const byte *from);
+extern uint _nisam_pack_get_block_info(BLOCK_INFO *, uint, File, ulong);
+extern uint _calc_total_blob_length(N_INFO *info,const byte *record);
+extern void _nisam_log(enum nisam_log_commands command,N_INFO *info,
+ const byte *buffert,uint length);
+extern void _nisam_log_command(enum nisam_log_commands command,
+ N_INFO *info, const byte *buffert,
+ uint length, int result);
+extern void _nisam_log_record(enum nisam_log_commands command,N_INFO *info,
+ const byte *record,ulong filepos,
+ int result);
+extern my_bool _nisam_memmap_file(N_INFO *info);
+extern void _nisam_unmap_file(N_INFO *info);
diff --git a/isam/isamlog.c b/isam/isamlog.c
new file mode 100644
index 00000000000..ddeea8a267d
--- /dev/null
+++ b/isam/isamlog.c
@@ -0,0 +1,839 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* write whats in isam.log */
+
+#ifndef USE_MY_FUNC
+#define USE_MY_FUNC
+#endif
+
+#include "isamdef.h"
+#include <my_tree.h>
+#include <stdarg.h>
+#ifdef HAVE_GETRUSAGE
+#include <sys/resource.h>
+#endif
+
+#define FILENAME(A) (A ? A->show_name : "Unknown")
+
+struct file_info {
+ long process;
+ int filenr,id;
+ my_string name,show_name,record;
+ N_INFO *isam;
+ bool closed,used;
+ ulong accessed;
+};
+
+struct test_if_open_param {
+ my_string name;
+ int max_id;
+};
+
+struct st_access_param
+{
+ ulong min_accessed;
+ struct file_info *found;
+};
+
+#define NO_FILEPOS (ulong) ~0L
+
+extern int main(int argc,char * *argv);
+static void get_options(int *argc,char ***argv);
+static int examine_log(my_string file_name,char **table_names);
+static int read_string(IO_CACHE *file,gptr *to,uint length);
+static int file_info_compare(void *a,void *b);
+static int test_if_open(struct file_info *key,element_count count,
+ struct test_if_open_param *param);
+static void fix_blob_pointers(N_INFO *isam,byte *record);
+static uint set_maximum_open_files(uint);
+static int test_when_accessed(struct file_info *key,element_count count,
+ struct st_access_param *access_param);
+static void file_info_free(struct file_info *info);
+static int close_some_file(TREE *tree);
+static int reopen_closed_file(TREE *tree,struct file_info *file_info);
+static int find_record_with_key(struct file_info *file_info,byte *record);
+static void printf_log(const char *str,...);
+static bool cmp_filename(struct file_info *file_info,my_string name);
+
+static uint verbose=0,update=0,test_info=0,max_files=0,re_open_count=0,
+ recover=0,prefix_remove=0;
+static my_string log_filename=0,filepath=0,write_filename=0,record_pos_file=0;
+static ulong com_count[10][3],number_of_commands=(ulong) ~0L,start_offset=0,
+ record_pos= NO_FILEPOS,isamlog_filepos,isamlog_process;
+static const char *command_name[]=
+{"open","write","update","delete","close","extra","lock","re-open",NullS};
+
+
+int main(argc,argv)
+int argc;
+char **argv;
+{
+ int error,i,first;
+ ulong total_count,total_error,total_recover;
+ MY_INIT(argv[0]);
+
+ log_filename=nisam_log_filename;
+ get_options(&argc,&argv);
+ /* Nr of isam-files */
+ max_files=(set_maximum_open_files(min(max_files,8))-6)/2;
+
+ if (update)
+ printf("Trying to %s isamfiles according to log '%s'\n",
+ (recover ? "recover" : "update"),log_filename);
+ error= examine_log(log_filename,argv);
+ if (update && ! error)
+ puts("isamfile:s updated successfully");
+ total_count=total_error=total_recover=0;
+ for (i=first=0 ; command_name[i] ; i++)
+ {
+ if (com_count[i][0])
+ {
+ if (!first++)
+ {
+ if (verbose || update)
+ puts("");
+ puts("Commands Used count Errors Recover errors");
+ }
+ printf("%-12s%9ld%10ld%17ld\n",command_name[i],com_count[i][0],
+ com_count[i][1],com_count[i][2]);
+ total_count+=com_count[i][0];
+ total_error+=com_count[i][1];
+ total_recover+=com_count[i][2];
+ }
+ }
+ if (total_count)
+ printf("%-12s%9ld%10ld%17ld\n","Total",total_count,total_error,
+ total_recover);
+ if (re_open_count)
+ printf("Had to do %d re-open because of too few possibly open files\n",
+ re_open_count);
+ VOID(nisam_panic(HA_PANIC_CLOSE));
+ my_end(test_info ? MY_CHECK_ERROR | MY_GIVE_INFO : MY_CHECK_ERROR);
+ exit(error);
+ return 0; /* No compiler warning */
+} /* main */
+
+
+static void get_options(argc,argv)
+register int *argc;
+register char ***argv;
+{
+ int help,version;
+ const char *usage;
+ char *pos, option;
+
+ help=0;
+ usage="Usage: %s [-?iruvIV] [-c #] [-f #] [-F filepath/] [-o #] [-R file recordpos] [-w write_file] [log-filename [table ...]] \n";
+ pos= (char*) "";
+
+ while (--*argc > 0 && *(pos = *(++*argv)) == '-' ) {
+ while (*++pos)
+ {
+ version=0;
+ switch((option=*pos)) {
+ case '#':
+ DBUG_PUSH (++pos);
+ pos= (char*) " "; /* Skipp rest of arg */
+ break;
+ case 'c':
+ if (! *++pos)
+ {
+ if (!--*argc)
+ goto err;
+ else
+ pos= *(++*argv);
+ }
+ number_of_commands=(ulong) atol(pos);
+ pos= (char*) " ";
+ break;
+ case 'u':
+ update=1;
+ break;
+ case 'f':
+ if (! *++pos)
+ {
+ if (!--*argc)
+ goto err;
+ else
+ pos= *(++*argv);
+ }
+ max_files=(uint) atoi(pos);
+ pos= (char*) " ";
+ break;
+ case 'i':
+ test_info=1;
+ break;
+ case 'o':
+ if (! *++pos)
+ {
+ if (!--*argc)
+ goto err;
+ else
+ pos= *(++*argv);
+ }
+ start_offset=(ulong) atol(pos);
+ pos= (char*) " ";
+ break;
+ case 'p':
+ if (! *++pos)
+ {
+ if (!--*argc)
+ goto err;
+ else
+ pos= *(++*argv);
+ }
+ prefix_remove=atoi(pos);
+ break;
+ case 'r':
+ update=1;
+ recover++;
+ break;
+ case 'R':
+ if (! *++pos)
+ {
+ if (!--*argc)
+ goto err;
+ else
+ pos= *(++*argv);
+ }
+ record_pos_file=pos;
+ if (!--*argc)
+ goto err;
+ record_pos=(ulong) atol(*(++*argv));
+ pos= (char*) " ";
+ break;
+ case 'v':
+ verbose++;
+ break;
+ case 'w':
+ if (! *++pos)
+ {
+ if (!--*argc)
+ goto err;
+ else
+ pos= *(++*argv);
+ }
+ write_filename=pos;
+ pos= (char*) " ";
+ break;
+ case 'F':
+ if (! *++pos)
+ {
+ if (!--*argc)
+ goto err;
+ else
+ pos= *(++*argv);
+ }
+ filepath=pos;
+ pos= (char*) " ";
+ break;
+ case 'V':
+ version=1;
+ /* Fall through */
+ case 'I':
+ case '?':
+ printf("%s Ver 3.1 for %s at %s\n",my_progname,SYSTEM_TYPE,
+ MACHINE_TYPE);
+ puts("TCX Datakonsult AB, by Monty, for your professional use\n");
+ if (version)
+ break;
+ puts("Write info about whats in a nisam log file.");
+ printf("If no file name is given %s is used\n",log_filename);
+ puts("");
+ printf(usage,my_progname);
+ puts("");
+ puts("Options: -? or -I \"Info\" -V \"version\" -c \"do only # commands\"");
+ puts(" -f \"max open files\" -F \"filepath\" -i \"extra info\"");
+ puts(" -o \"offset\" -p # \"remove # components from path\"");
+ puts(" -r \"recover\" -R \"file recordposition\"");
+ puts(" -u \"update\" -v \"verbose\" -w \"write file\"");
+ puts("\nOne can give a second and a third '-v' for more verbose.");
+ puts("Normaly one does a update (-u).");
+ puts("If a recover is done all writes and all possibly updates and deletes is done\nand errors are only counted.");
+ puts("If one gives table names as arguments only these tables will be updated\n");
+ help=1;
+ break;
+ default:
+ printf("illegal option: \"-%c\"\n",*pos);
+ break;
+ }
+ }
+ }
+ if (! *argc)
+ {
+ if (help)
+ exit(0);
+ (*argv)++;
+ }
+ if (*argc >= 1)
+ {
+ log_filename=pos;
+ (*argc)--;
+ (*argv)++;
+ }
+ return;
+ err:
+ VOID(fprintf(stderr,"option \"%c\" used without or with wrong argument\n",
+ option));
+ exit(1);
+}
+
+
+static int examine_log(my_string file_name, char **table_names)
+{
+ uint command,result,files_open;
+ ulong access_time,length;
+ uint32 filepos;
+ int lock_command,ni_result;
+ char isam_file_name[FN_REFLEN];
+ uchar head[20];
+ gptr buff;
+ struct test_if_open_param open_param;
+ IO_CACHE cache;
+ File file;
+ FILE *write_file;
+ enum ha_extra_function extra_command;
+ TREE tree;
+ struct file_info file_info,*curr_file_info;
+ DBUG_ENTER("examine_log");
+
+ if ((file=my_open(file_name,O_RDONLY,MYF(MY_WME))) < 0)
+ DBUG_RETURN(1);
+ write_file=0;
+ if (write_filename)
+ {
+ if (!(write_file=my_fopen(write_filename,O_WRONLY,MYF(MY_WME))))
+ {
+ my_close(file,MYF(0));
+ DBUG_RETURN(1);
+ }
+ }
+
+ init_io_cache(&cache,file,0,READ_CACHE,start_offset,0,MYF(0));
+ bzero((gptr) com_count,sizeof(com_count));
+ init_tree(&tree,0,sizeof(file_info),(qsort_cmp) file_info_compare,0,
+ (void(*)(void*)) file_info_free);
+ VOID(init_key_cache(KEY_CACHE_SIZE,(uint) (10*4*(IO_SIZE+MALLOC_OVERHEAD))));
+
+ files_open=0; access_time=0;
+ while (access_time++ != number_of_commands &&
+ !my_b_read(&cache,(byte*) head,9))
+ {
+ isamlog_filepos=my_b_tell(&cache)-9L;
+ file_info.filenr=uint2korr(head+1);
+ isamlog_process=file_info.process=(long) uint4korr(head+3);
+ result=uint2korr(head+7);
+ if ((curr_file_info=(struct file_info*) tree_search(&tree,&file_info)))
+ {
+ curr_file_info->accessed=access_time;
+ if (update && curr_file_info->used && curr_file_info->closed)
+ {
+ if (reopen_closed_file(&tree,curr_file_info))
+ {
+ command=sizeof(com_count)/sizeof(com_count[0][0])/3;
+ result=0;
+ goto com_err;
+ }
+ }
+ }
+ command=(uint) head[0];
+ if (command < sizeof(com_count)/sizeof(com_count[0][0])/3 &&
+ (!curr_file_info || curr_file_info->used))
+ {
+ com_count[command][0]++;
+ if (result)
+ com_count[command][1]++;
+ }
+ switch ((enum nisam_log_commands) command) {
+ case LOG_OPEN:
+ com_count[command][0]--; /* Must be counted explicite */
+ if (result)
+ com_count[command][1]--;
+
+ if (curr_file_info)
+ printf("\nWarning: %s is opened twice with same process and filenumber\n",
+ curr_file_info->show_name);
+ if (my_b_read(&cache,(byte*) head,2))
+ goto err;
+ file_info.name=0;
+ file_info.show_name=0;
+ file_info.record=0;
+ if (read_string(&cache,(gptr*) &file_info.name,(uint) uint2korr(head)))
+ goto err;
+ {
+ uint i;
+ char *pos=file_info.name,*to;
+ for (i=0 ; i < prefix_remove ; i++)
+ {
+ char *next;
+ if (!(next=strchr(pos,FN_LIBCHAR)))
+ break;
+ pos=next+1;
+ }
+ to=isam_file_name;
+ if (filepath)
+ {
+ strmov(isam_file_name,filepath);
+ convert_dirname(isam_file_name);
+ to=strend(isam_file_name);
+ }
+ strmov(to,pos);
+ fn_ext(isam_file_name)[0]=0; /* Remove extension */
+ }
+ open_param.name=file_info.name;
+ open_param.max_id=0;
+ VOID(tree_walk(&tree,(tree_walk_action) test_if_open,(void*) &open_param,
+ left_root_right));
+ file_info.id=open_param.max_id+1;
+ file_info.show_name=my_memdup(isam_file_name,
+ (uint) strlen(isam_file_name)+6,
+ MYF(MY_WME));
+ if (file_info.id > 1)
+ sprintf(strend(file_info.show_name),"<%d>",file_info.id);
+ file_info.closed=1;
+ file_info.accessed=access_time;
+ file_info.used=1;
+ if (table_names[0])
+ {
+ char **name;
+ file_info.used=0;
+ for (name=table_names ; *name ; name++)
+ {
+ if (!strcmp(*name,isam_file_name))
+ file_info.used=1; /* Update/log only this */
+ }
+ }
+ if (update && file_info.used)
+ {
+ if (files_open >= max_files)
+ {
+ if (close_some_file(&tree))
+ goto com_err;
+ files_open--;
+ }
+ if (!(file_info.isam= nisam_open(isam_file_name,O_RDWR,
+ HA_OPEN_WAIT_IF_LOCKED)))
+ goto com_err;
+ if (!(file_info.record=my_malloc(file_info.isam->s->base.reclength,
+ MYF(MY_WME))))
+ goto end;
+ files_open++;
+ file_info.closed=0;
+ }
+ VOID(tree_insert(&tree,(gptr) &file_info,0));
+ if (file_info.used)
+ {
+ if (verbose && !record_pos_file)
+ printf_log("%s: open",file_info.show_name);
+ com_count[command][0]++;
+ if (result)
+ com_count[command][1]++;
+ }
+ break;
+ case LOG_CLOSE:
+ if (verbose && !record_pos_file &&
+ (!table_names[0] || (curr_file_info && curr_file_info->used)))
+ printf_log("%s: %s -> %d",FILENAME(curr_file_info),
+ command_name[command],result);
+ if (curr_file_info)
+ {
+ if (!curr_file_info->closed)
+ files_open--;
+ file_info_free(curr_file_info);
+ VOID(tree_delete(&tree,(gptr) curr_file_info));
+ }
+ break;
+ case LOG_EXTRA:
+ if (my_b_read(&cache,(byte*) head,sizeof(extra_command)))
+ goto err;
+ memcpy_fixed(&extra_command,head,sizeof(extra_command));
+ if (verbose && !record_pos_file &&
+ (!table_names[0] || (curr_file_info && curr_file_info->used)))
+ printf_log("%s: %s(%d) -> %d",FILENAME(curr_file_info),
+ command_name[command], extra_command,result);
+ if (update && curr_file_info && !curr_file_info->closed)
+ {
+ if (nisam_extra(curr_file_info->isam,extra_command) != (int) result)
+ {
+ VOID(fprintf(stderr,
+ "Warning: error %d, expected %d on command %s at %lx\n",
+ my_errno,result,command_name[command],isamlog_filepos));
+ }
+ }
+ break;
+ case LOG_DELETE:
+ if (my_b_read(&cache,(byte*) head,sizeof(filepos)))
+ goto err;
+ memcpy_fixed(&filepos,head,sizeof(filepos));
+ if (verbose && (!record_pos_file ||
+ ((record_pos == filepos || record_pos == NO_FILEPOS) &&
+ !cmp_filename(curr_file_info,record_pos_file))) &&
+ (!table_names[0] || (curr_file_info && curr_file_info->used)))
+ printf_log("%s: %s at %ld -> %d",FILENAME(curr_file_info),
+ command_name[command],(long) filepos,result);
+ if (update && curr_file_info && !curr_file_info->closed)
+ {
+ if (nisam_rrnd(curr_file_info->isam,curr_file_info->record,filepos))
+ {
+ if (!recover)
+ goto com_err;
+ com_count[command][2]++; /* Mark error */
+ }
+ ni_result=nisam_delete(curr_file_info->isam,curr_file_info->record);
+ if ((ni_result == 0 && result) ||
+ (ni_result && (uint) my_errno != result))
+ {
+ if (!recover)
+ goto com_err;
+ if (ni_result)
+ com_count[command][2]++; /* Mark error */
+ }
+ }
+ break;
+ case LOG_WRITE:
+ case LOG_UPDATE:
+ if (my_b_read(&cache,(byte*) head,8))
+ goto err;
+ filepos=uint4korr(head);
+ length=uint4korr(head+4);
+ buff=0;
+ if (read_string(&cache,&buff,(uint) length))
+ goto err;
+ if ((!record_pos_file ||
+ ((record_pos == filepos || record_pos == NO_FILEPOS) &&
+ !cmp_filename(curr_file_info,record_pos_file))) &&
+ (!table_names[0] || (curr_file_info && curr_file_info->used)))
+ {
+ if (write_file &&
+ (my_fwrite(write_file,buff,length,MYF(MY_WAIT_IF_FULL | MY_NABP))))
+ goto end;
+ if (verbose)
+ printf_log("%s: %s at %ld, length=%ld -> %d",
+ FILENAME(curr_file_info),
+ command_name[command], filepos,length,result);
+ }
+ if (update && curr_file_info && !curr_file_info->closed)
+ {
+ if (curr_file_info->isam->s->base.blobs)
+ fix_blob_pointers(curr_file_info->isam,buff);
+ if ((enum nisam_log_commands) command == LOG_UPDATE)
+ {
+ if (nisam_rrnd(curr_file_info->isam,curr_file_info->record,filepos))
+ {
+ if (!recover)
+ {
+ result=0;
+ goto com_err;
+ }
+ if (recover == 1 || result ||
+ find_record_with_key(curr_file_info,buff))
+ {
+ com_count[command][2]++; /* Mark error */
+ break;
+ }
+ }
+ ni_result=nisam_update(curr_file_info->isam,curr_file_info->record,
+ buff);
+ if ((ni_result == 0 && result) ||
+ (ni_result && (uint) my_errno != result))
+ {
+ if (!recover)
+ goto com_err;
+ if (ni_result)
+ com_count[command][2]++; /* Mark error */
+ }
+ }
+ else
+ {
+ ni_result=nisam_write(curr_file_info->isam,buff);
+ if ((ni_result == 0 && result) ||
+ (ni_result && (uint) my_errno != result))
+ {
+ if (!recover)
+ goto com_err;
+ if (ni_result)
+ com_count[command][2]++; /* Mark error */
+ }
+ if (! recover && filepos != curr_file_info->isam->lastpos)
+ {
+ printf("Warning: Wrote at position: %ld, should have been %ld",
+ curr_file_info->isam->lastpos,(long) filepos);
+ goto com_err;
+ }
+ }
+ }
+ my_free(buff,MYF(0));
+ break;
+ case LOG_LOCK:
+ if (my_b_read(&cache,(byte*) head,sizeof(lock_command)))
+ goto err;
+ memcpy_fixed(&lock_command,head,sizeof(lock_command));
+ if (verbose && !record_pos_file &&
+ (!table_names[0] || (curr_file_info && curr_file_info->used)))
+ printf_log("%s: %s(%d) -> %d\n",FILENAME(curr_file_info),
+ command_name[command],lock_command,result);
+ if (update && curr_file_info && !curr_file_info->closed)
+ {
+ if (nisam_lock_database(curr_file_info->isam,lock_command) !=
+ (int) result)
+ goto com_err;
+ }
+ break;
+ default:
+ VOID(fprintf(stderr,
+ "Error: found unknown command %d in logfile, aborted\n",
+ command));
+ goto end;
+ }
+ }
+ end_key_cache();
+ delete_tree(&tree);
+ VOID(end_io_cache(&cache));
+ VOID(my_close(file,MYF(0)));
+ if (write_file && my_fclose(write_file,MYF(MY_WME)))
+ DBUG_RETURN(1);
+ DBUG_RETURN(0);
+
+ err:
+ VOID(fprintf(stderr,"Got error %d when reading from logfile\n",my_errno));
+ goto end;
+ com_err:
+ VOID(fprintf(stderr,"Got error %d, expected %d on command %s at %lx\n",
+ my_errno,result,command_name[command],isamlog_filepos));
+ end:
+ end_key_cache();
+ delete_tree(&tree);
+ VOID(end_io_cache(&cache));
+ VOID(my_close(file,MYF(0)));
+ if (write_file)
+ VOID(my_fclose(write_file,MYF(MY_WME)));
+ DBUG_RETURN(1);
+}
+
+
+static int read_string(file,to,length)
+IO_CACHE *file;
+reg1 gptr *to;
+reg2 uint length;
+{
+ DBUG_ENTER("read_string");
+
+ if (*to)
+ my_free((gptr) *to,MYF(0));
+ if (!(*to= (gptr) my_malloc(length+1,MYF(MY_WME))) ||
+ my_b_read(file,(byte*) *to,length))
+ {
+ if (*to)
+ my_free(*to,MYF(0));
+ *to= 0;
+ DBUG_RETURN(1);
+ }
+ *((char*) *to+length)= '\0';
+ DBUG_RETURN (0);
+} /* read_string */
+
+
+static int file_info_compare(a,b)
+void *a;
+void *b;
+{
+ long lint;
+
+ if ((lint=((struct file_info*) a)->process -
+ ((struct file_info*) b)->process))
+ return lint < 0L ? -1 : 1;
+ return ((struct file_info*) a)->filenr - ((struct file_info*) b)->filenr;
+}
+
+ /* ARGSUSED */
+
+static int test_if_open (key,count,param)
+struct file_info *key;
+element_count count __attribute__((unused));
+struct test_if_open_param *param;
+{
+ if (!strcmp(key->name,param->name) && key->id > param->max_id)
+ param->max_id=key->id;
+ return 0;
+}
+
+
+static void fix_blob_pointers(info,record)
+N_INFO *info;
+byte *record;
+{
+ byte *pos;
+ N_BLOB *blob,*end;
+
+ pos=record+info->s->base.reclength;
+ for (end=info->blobs+info->s->base.blobs, blob= info->blobs;
+ blob != end ;
+ blob++)
+ {
+ bmove(record+blob->offset+blob->pack_length,&pos,sizeof(char*));
+ pos+=_calc_blob_length(blob->pack_length,record+blob->offset);
+ }
+}
+
+static uint set_maximum_open_files(maximum_files)
+uint maximum_files;
+{
+#if defined(HAVE_GETRUSAGE) && defined(RLIMIT_NOFILE)
+ struct rlimit rlimit;
+ int old_max;
+
+ if (maximum_files > MY_NFILE)
+ maximum_files=MY_NFILE; /* Don't crash my_open */
+
+ if (!getrlimit(RLIMIT_NOFILE,&rlimit))
+ {
+ old_max=rlimit.rlim_max;
+ if (maximum_files && (int) maximum_files > old_max)
+ rlimit.rlim_max=maximum_files;
+ rlimit.rlim_cur=rlimit.rlim_max;
+ if (setrlimit(RLIMIT_NOFILE,&rlimit))
+ {
+ if (old_max != (int) maximum_files)
+ { /* Set as much as we can */
+ rlimit.rlim_max=rlimit.rlim_cur=old_max;
+ setrlimit(RLIMIT_NOFILE,&rlimit);
+ }
+ }
+ getrlimit(RLIMIT_NOFILE,&rlimit); /* Read if broken setrlimit */
+ if (maximum_files && maximum_files < rlimit.rlim_cur)
+ VOID(fprintf(stderr,"Warning: Error from setrlimit: Max open files is %d\n",old_max));
+ return rlimit.rlim_cur;
+ }
+#endif
+ return min(maximum_files,MY_NFILE);
+}
+
+ /* close the file with hasn't been accessed for the longest time */
+ /* ARGSUSED */
+
+static int test_when_accessed (key,count,access_param)
+struct file_info *key;
+element_count count __attribute__((unused));
+struct st_access_param *access_param;
+{
+ if (key->accessed < access_param->min_accessed && ! key->closed)
+ {
+ access_param->min_accessed=key->accessed;
+ access_param->found=key;
+ }
+ return 0;
+}
+
+
+static void file_info_free(fileinfo)
+struct file_info *fileinfo;
+{
+ if (update)
+ {
+ if (!fileinfo->closed)
+ VOID(nisam_close(fileinfo->isam));
+ if (fileinfo->record)
+ my_free(fileinfo->record,MYF(0));
+ }
+ my_free(fileinfo->name,MYF(0));
+ my_free(fileinfo->show_name,MYF(0));
+}
+
+
+
+static int close_some_file(tree)
+TREE *tree;
+{
+ struct st_access_param access_param;
+
+ access_param.min_accessed=LONG_MAX;
+ access_param.found=0;
+
+ VOID(tree_walk(tree,(tree_walk_action) test_when_accessed,
+ (void*) &access_param,left_root_right));
+ if (!access_param.found)
+ return 1; /* No open file that is possibly to close */
+ if (nisam_close(access_param.found->isam))
+ return 1;
+ access_param.found->closed=1;
+ return 0;
+}
+
+
+static int reopen_closed_file(tree,fileinfo)
+TREE *tree;
+struct file_info *fileinfo;
+{
+ char name[FN_REFLEN];
+ if (close_some_file(tree))
+ return 1; /* No file to close */
+ strmov(name,fileinfo->show_name);
+ if (fileinfo->id > 1)
+ *strrchr(name,'<')='\0'; /* Remove "<id>" */
+
+ if (!(fileinfo->isam= nisam_open(name,O_RDWR,HA_OPEN_WAIT_IF_LOCKED)))
+ return 1;
+ fileinfo->closed=0;
+ re_open_count++;
+ return 0;
+}
+
+ /* Try to find record with uniq key */
+
+static int find_record_with_key(file_info,record)
+struct file_info *file_info;
+byte *record;
+{
+ uint key;
+ N_INFO *info=file_info->isam;
+ uchar tmp_key[N_MAX_KEY_BUFF];
+
+ for (key=0 ; key < info->s->state.keys ; key++)
+ {
+ if (info->s->keyinfo[key].base.flag & HA_NOSAME)
+ {
+ VOID(_nisam_make_key(info,key,tmp_key,record,0L));
+ return nisam_rkey(info,file_info->record,(int) key,(char*) tmp_key,0,
+ HA_READ_KEY_EXACT);
+ }
+ }
+ return 1;
+}
+
+
+static void printf_log(const char *format,...)
+{
+ va_list args;
+ va_start(args,format);
+ if (verbose > 2)
+ printf("%9ld:",isamlog_filepos);
+ if (verbose > 1)
+ printf("%5ld ",isamlog_process); /* Write process number */
+ (void) vprintf((char*) format,args);
+ putchar('\n');
+ va_end(args);
+}
+
+
+static bool cmp_filename(file_info,name)
+struct file_info *file_info;
+my_string name;
+{
+ if (!file_info)
+ return 1;
+ return strcmp(file_info->name,name) ? 1 : 0;
+}
diff --git a/isam/log.c b/isam/log.c
new file mode 100644
index 00000000000..a95b53b5110
--- /dev/null
+++ b/isam/log.c
@@ -0,0 +1,156 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* Logging of isamcommands and records on logfile */
+
+#include "isamdef.h"
+#if defined(MSDOS) || defined(__WIN__)
+#include <errno.h>
+#include <fcntl.h>
+#ifndef __WIN__
+#include <process.h>
+#endif
+#endif
+#ifdef VMS
+#include <processes.h>
+#endif
+
+#ifdef THREAD
+#undef GETPID
+#define GETPID() (log_type == 1 ? getpid() : (long) my_thread_id());
+#else
+#define GETPID() getpid()
+#endif
+
+ /* Activate logging if flag is 1 and reset logging if flag is 0 */
+
+static int log_type=0;
+
+int nisam_log(int activate_log)
+{
+ int error=0;
+ char buff[FN_REFLEN];
+ DBUG_ENTER("nisam_log");
+
+ log_type=activate_log;
+ if (activate_log)
+ {
+ if (nisam_log_file < 0)
+ {
+ if ((nisam_log_file = my_create(fn_format(buff,nisam_log_filename,
+ "",".log",4),
+ 0,(O_RDWR | O_BINARY | O_APPEND),MYF(0)))
+ < 0)
+ DBUG_RETURN(1);
+ }
+ }
+ else if (nisam_log_file >= 0)
+ {
+ error=my_close(nisam_log_file,MYF(0));
+ nisam_log_file= -1;
+ }
+ DBUG_RETURN(error);
+}
+
+
+ /* Logging of records and commands on logfile */
+ /* All logs starts with command(1) dfile(2) process(4) result(2) */
+
+void _nisam_log(enum nisam_log_commands command, N_INFO *info, const byte *buffert, uint length)
+{
+ char buff[11];
+ int error,old_errno;
+ ulong pid=(ulong) GETPID();
+ old_errno=my_errno;
+ bzero(buff,sizeof(buff));
+ buff[0]=(char) command;
+ int2store(buff+1,info->dfile);
+ int4store(buff+3,pid);
+ int2store(buff+9,length);
+
+ pthread_mutex_lock(&THR_LOCK_isam);
+ error=my_lock(nisam_log_file,F_WRLCK,0L,F_TO_EOF,MYF(MY_SEEK_NOT_DONE));
+ VOID(my_write(nisam_log_file,buff,sizeof(buff),MYF(0)));
+ VOID(my_write(nisam_log_file,buffert,length,MYF(0)));
+ if (!error)
+ error=my_lock(nisam_log_file,F_UNLCK,0L,F_TO_EOF,MYF(MY_SEEK_NOT_DONE));
+ pthread_mutex_unlock(&THR_LOCK_isam);
+ my_errno=old_errno;
+}
+
+
+void _nisam_log_command(enum nisam_log_commands command, N_INFO *info, const byte *buffert, uint length, int result)
+{
+ char buff[9];
+ int error,old_errno;
+ ulong pid=(ulong) GETPID();
+
+ old_errno=my_errno;
+ buff[0]=(char) command;
+ int2store(buff+1,info->dfile);
+ int4store(buff+3,pid);
+ int2store(buff+7,result);
+ pthread_mutex_lock(&THR_LOCK_isam);
+ error=my_lock(nisam_log_file,F_WRLCK,0L,F_TO_EOF,MYF(MY_SEEK_NOT_DONE));
+ VOID(my_write(nisam_log_file,buff,sizeof(buff),MYF(0)));
+ if (buffert)
+ VOID(my_write(nisam_log_file,buffert,length,MYF(0)));
+ if (!error)
+ error=my_lock(nisam_log_file,F_UNLCK,0L,F_TO_EOF,MYF(MY_SEEK_NOT_DONE));
+ pthread_mutex_unlock(&THR_LOCK_isam);
+ my_errno=old_errno;
+}
+
+
+void _nisam_log_record(enum nisam_log_commands command, N_INFO *info, const byte *record, ulong filepos, int result)
+{
+ char buff[17],*pos;
+ int error,old_errno;
+ uint length;
+ ulong pid=(ulong) GETPID();
+
+ old_errno=my_errno;
+ if (!info->s->base.blobs)
+ length=info->s->base.reclength;
+ else
+ length=info->s->base.reclength+ _calc_total_blob_length(info,record);
+ buff[0]=(char) command;
+ int2store(buff+1,info->dfile);
+ int4store(buff+3,pid);
+ int2store(buff+7,result);
+ int4store(buff+9,filepos);
+ int4store(buff+13,length);
+ pthread_mutex_lock(&THR_LOCK_isam);
+ error=my_lock(nisam_log_file,F_WRLCK,0L,F_TO_EOF,MYF(MY_SEEK_NOT_DONE));
+ VOID(my_write(nisam_log_file,buff,sizeof(buff),MYF(0)));
+ VOID(my_write(nisam_log_file,(byte*) record,info->s->base.reclength,MYF(0)));
+ if (info->s->base.blobs)
+ {
+ N_BLOB *blob,*end;
+
+ for (end=info->blobs+info->s->base.blobs, blob= info->blobs;
+ blob != end ;
+ blob++)
+ {
+ bmove(&pos,record+blob->offset+blob->pack_length,sizeof(char*));
+ VOID(my_write(nisam_log_file,pos,blob->length,MYF(0)));
+ }
+ }
+ if (!error)
+ error=my_lock(nisam_log_file,F_UNLCK,0L,F_TO_EOF,MYF(MY_SEEK_NOT_DONE));
+ pthread_mutex_unlock(&THR_LOCK_isam);
+ my_errno=old_errno;
+}
diff --git a/isam/make-ccc b/isam/make-ccc
new file mode 100755
index 00000000000..d9a95dbc14b
--- /dev/null
+++ b/isam/make-ccc
@@ -0,0 +1,3 @@
+ccc -DHAVE_CONFIG_H -I. -I. -I.. -I./../include -I../include -DDBUG_OFF -fast -O3 -fomit-frame-pointer -c _cache.c _dbug.c _dynrec.c _key.c _locking.c _packrec.c _page.c _search.c _statrec.c changed.c close.c create.c delete.c extra.c info.c log.c open.c panic.c range.c rfirst.c rkey.c rlast.c rnext.c rprev.c rrnd.c rsame.c rsamepos.c static.c update.c write.c
+rm libnisam.a
+ar -cr libnisam.a _cache.o
diff --git a/isam/open.c b/isam/open.c
new file mode 100644
index 00000000000..8a6e0eb5814
--- /dev/null
+++ b/isam/open.c
@@ -0,0 +1,455 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* open a isam-database */
+
+#include "isamdef.h"
+#if defined(MSDOS) || defined(__WIN__)
+#ifdef __WIN__
+#include <fcntl.h>
+#else
+#include <process.h> /* Prototype for getpid */
+#endif
+#endif
+#ifdef VMS
+#include "static.c"
+#endif
+
+static void setup_functions(ISAM_SHARE *info);
+static void setup_key_functions(N_KEYDEF *keyinfo);
+
+#define get_next_element(to,pos,size) { memcpy((char*) to,pos,(size_t) size); \
+ pos+=size;}
+
+/******************************************************************************
+** Return the shared struct if the table is already open.
+** In MySQL the server will handle version issues.
+******************************************************************************/
+
+static N_INFO *test_if_reopen(char *filename)
+{
+ LIST *pos;
+
+ for (pos=nisam_open_list ; pos ; pos=pos->next)
+ {
+ N_INFO *info=(N_INFO*) pos->data;
+ ISAM_SHARE *share=info->s;
+ if (!strcmp(share->filename,filename) && share->last_version)
+ return info;
+ }
+ return 0;
+}
+
+
+/******************************************************************************
+ open a isam database.
+ By default exit with error if database is locked
+ if handle_locking & HA_OPEN_WAIT_IF_LOCKED then wait if database is locked
+ if handle_locking & HA_OPEN_IGNORE_IF_LOCKED then continue, but count-vars
+ in st_i_info may be wrong. count-vars are automaticly fixed after next
+ isam request.
+******************************************************************************/
+
+
+N_INFO *nisam_open(const char *name, int mode, uint handle_locking)
+{
+ int lock_error,kfile,open_mode,save_errno;
+ uint i,j,len,errpos,head_length,base_pos,offset,info_length,extra;
+ char name_buff[FN_REFLEN],*disk_cache,*disk_pos;
+ N_INFO info,*m_info,*old_info;
+ ISAM_SHARE share_buff,*share;
+ DBUG_ENTER("nisam_open");
+
+ LINT_INIT(m_info);
+ kfile= -1;
+ lock_error=1;
+ errpos=0;
+ head_length=sizeof(share_buff.state.header);
+ bzero((byte*) &info,sizeof(info));
+
+ VOID(fn_format(name_buff,name,"",N_NAME_IEXT,4+16+32));
+ pthread_mutex_lock(&THR_LOCK_isam);
+ if (!(old_info=test_if_reopen(name_buff)))
+ {
+ share= &share_buff;
+ bzero((gptr) &share_buff,sizeof(share_buff));
+
+ if ((kfile=my_open(name_buff,(open_mode=O_RDWR) | O_SHARE,MYF(0))) < 0)
+ {
+ if ((errno != EROFS && errno != EACCES) ||
+ mode != O_RDONLY ||
+ (kfile=my_open(name_buff,(open_mode=O_RDONLY) | O_SHARE,MYF(0))) < 0)
+ goto err;
+ }
+ errpos=1;
+ if (my_read(kfile,(char*) share->state.header.file_version,head_length,
+ MYF(MY_NABP)))
+ goto err;
+
+ if (memcmp((byte*) share->state.header.file_version,
+ (byte*) nisam_file_magic, 3) ||
+ share->state.header.file_version[3] == 0 ||
+ (uchar) share->state.header.file_version[3] > 3)
+ {
+ DBUG_PRINT("error",("Wrong header in %s",name_buff));
+ DBUG_DUMP("error_dump",(char*) share->state.header.file_version,
+ head_length);
+ my_errno=HA_ERR_CRASHED;
+ goto err;
+ }
+ if (uint2korr(share->state.header.options) &
+ ~(HA_OPTION_PACK_RECORD | HA_OPTION_PACK_KEYS |
+ HA_OPTION_COMPRESS_RECORD | HA_OPTION_READ_ONLY_DATA |
+ HA_OPTION_TEMP_COMPRESS_RECORD))
+ {
+ DBUG_PRINT("error",("wrong options: 0x%lx",
+ uint2korr(share->state.header.options)));
+ my_errno=HA_ERR_OLD_FILE;
+ goto err;
+ }
+ info_length=uint2korr(share->state.header.header_length);
+ base_pos=uint2korr(share->state.header.base_pos);
+ if (!(disk_cache=(char*) my_alloca(info_length)))
+ {
+ my_errno=ENOMEM;
+ goto err;
+ }
+ errpos=2;
+
+ VOID(my_seek(kfile,0L,MY_SEEK_SET,MYF(0)));
+#ifndef NO_LOCKING
+ if (!(handle_locking & HA_OPEN_TMP_TABLE))
+ {
+ if ((lock_error=my_lock(kfile,F_RDLCK,0L,F_TO_EOF,
+ MYF(handle_locking & HA_OPEN_WAIT_IF_LOCKED ?
+ 0 : MY_DONT_WAIT))) &&
+ !(handle_locking & HA_OPEN_IGNORE_IF_LOCKED))
+ goto err;
+ }
+#endif
+ errpos=3;
+ if (my_read(kfile,disk_cache,info_length,MYF(MY_NABP)))
+ goto err;
+ len=uint2korr(share->state.header.state_info_length);
+ if (len != sizeof(N_STATE_INFO))
+ {
+ DBUG_PRINT("warning",
+ ("saved_state_info_length: %d base_info_length: %d",
+ len,sizeof(N_STATE_INFO)));
+ }
+ if (len > sizeof(N_STATE_INFO))
+ len=sizeof(N_STATE_INFO);
+ share->state_length=len;
+ memcpy(&share->state.header.file_version[0],disk_cache,(size_t) len);
+ len=uint2korr(share->state.header.base_info_length);
+ if (len != sizeof(N_BASE_INFO))
+ {
+ DBUG_PRINT("warning",("saved_base_info_length: %d base_info_length: %d",
+ len,sizeof(N_BASE_INFO)));
+ if (len <= offsetof(N_BASE_INFO,sortkey))
+ share->base.sortkey=(ushort) ~0;
+ }
+ memcpy((char*) (byte*) &share->base,disk_cache+base_pos,
+ (size_t) min(len,sizeof(N_BASE_INFO)));
+ disk_pos=disk_cache+base_pos+len;
+ share->base.options=uint2korr(share->state.header.options);
+ if (share->base.max_key_length > N_MAX_KEY_BUFF)
+ {
+ my_errno=HA_ERR_UNSUPPORTED;
+ goto err;
+ }
+ if (share->base.options & HA_OPTION_COMPRESS_RECORD)
+ share->base.max_key_length+=2; /* For safety */
+
+ if (!my_multi_malloc(MY_WME,
+ &share,sizeof(*share),
+ &share->keyinfo,share->base.keys*sizeof(N_KEYDEF),
+ &share->rec,(share->base.fields+1)*sizeof(N_RECINFO),
+ &share->blobs,sizeof(N_BLOB)*share->base.blobs,
+ &share->filename,strlen(name_buff)+1,
+ NullS))
+ goto err;
+ errpos=4;
+ *share=share_buff;
+ strmov(share->filename,name_buff);
+
+ /* Fix key in used if old nisam-database */
+ if (share->state_length <= offsetof(N_STATE_INFO,keys))
+ share->state.keys=share->base.keys;
+
+ share->blocksize=min(IO_SIZE,nisam_block_size);
+ for (i=0 ; i < share->base.keys ; i++)
+ {
+ get_next_element(&share->keyinfo[i].base,disk_pos,sizeof(N_SAVE_KEYDEF));
+ setup_key_functions(share->keyinfo+i);
+ set_if_smaller(share->blocksize,share->keyinfo[i].base.block_length);
+ for (j=0 ; j <= share->keyinfo[i].base.keysegs ; j++)
+ {
+ get_next_element(&share->keyinfo[i].seg[j],disk_pos,
+ sizeof(N_SAVE_KEYSEG));
+ }
+ }
+ if (!share->blocksize)
+ {
+ my_errno=HA_ERR_CRASHED;
+ goto err;
+ }
+
+ for (i=j=offset=0 ; i < share->base.fields ; i++)
+ {
+ get_next_element(&share->rec[i].base,disk_pos,sizeof(N_SAVE_RECINFO));
+#ifndef NOT_PACKED_DATABASES
+ share->rec[i].pack_type=0;
+ share->rec[i].huff_tree=0;
+#endif
+ if (share->rec[i].base.type == (int) FIELD_BLOB)
+ {
+ share->blobs[j].pack_length=share->rec[i].base.length;
+ share->blobs[j].offset=offset;
+ j++;
+ offset+=sizeof(char*);
+ }
+ offset+=share->rec[i].base.length;
+ }
+ share->rec[i].base.type=(int) FIELD_LAST;
+
+#ifndef NO_LOCKING
+ if (! lock_error)
+ {
+ VOID(my_lock(kfile,F_UNLCK,0L,F_TO_EOF,MYF(MY_SEEK_NOT_DONE)));
+ lock_error=1; /* Database unlocked */
+ }
+#endif
+
+ if ((info.dfile=my_open(fn_format(name_buff,name,"",N_NAME_DEXT,2+4),
+ mode | O_SHARE,
+ MYF(MY_WME))) < 0)
+ goto err;
+ errpos=5;
+
+ share->kfile=kfile;
+ share->mode=open_mode;
+ share->this_process=(ulong) getpid();
+ share->rnd= (int) share->this_process; /* rnd-counter for splitts */
+#ifndef DBUG_OFF
+ share->rnd=0; /* To make things repeatable */
+#endif
+ share->last_process= share->state.process;
+ if (!(share->last_version=share->state.version))
+ share->last_version=1; /* Safety */
+ share->rec_reflength=share->base.rec_reflength; /* May be changed */
+
+ share->data_file_type=STATIC_RECORD;
+ if (share->base.options & HA_OPTION_COMPRESS_RECORD)
+ {
+ share->data_file_type = COMPRESSED_RECORD;
+ share->base.options|= HA_OPTION_READ_ONLY_DATA;
+ info.s=share;
+ if (_nisam_read_pack_info(&info,
+ (pbool) test(!(share->base.options &
+ (HA_OPTION_PACK_RECORD |
+ HA_OPTION_TEMP_COMPRESS_RECORD)))))
+ goto err;
+ }
+ else if (share->base.options & HA_OPTION_PACK_RECORD)
+ share->data_file_type = DYNAMIC_RECORD;
+ my_afree((gptr) disk_cache);
+ setup_functions(share);
+#ifdef THREAD
+ thr_lock_init(&share->lock);
+ VOID(pthread_mutex_init(&share->intern_lock,NULL));
+#endif
+ }
+ else
+ {
+ share= old_info->s;
+ if (mode == O_RDWR && share->mode == O_RDONLY)
+ {
+ my_errno=EACCES; /* Can't open in write mode*/
+ goto err;
+ }
+ if ((info.dfile=my_open(fn_format(name_buff,old_info->filename,"",
+ N_NAME_DEXT,2+4),
+ mode | O_SHARE,MYF(MY_WME))) < 0)
+ {
+ my_errno=errno;
+ goto err;
+ }
+ errpos=5;
+ }
+
+ /* alloc and set up private structure parts */
+ if (!my_multi_malloc(MY_WME,
+ &m_info,sizeof(N_INFO),
+ &info.blobs,sizeof(N_BLOB)*share->base.blobs,
+ &info.buff,(share->base.max_block*2+
+ share->base.max_key_length),
+ &info.lastkey,share->base.max_key_length*3+1,
+ &info.filename,strlen(name)+1,
+ NullS))
+ goto err;
+ errpos=6;
+ strmov(info.filename,name);
+ memcpy(info.blobs,share->blobs,sizeof(N_BLOB)*share->base.blobs);
+
+ info.s=share;
+ info.lastpos= NI_POS_ERROR;
+ info.update= (short) (HA_STATE_NEXT_FOUND+HA_STATE_PREV_FOUND);
+ info.opt_flag=READ_CHECK_USED;
+ info.alloced_rec_buff_length=share->base.pack_reclength;
+ info.this_uniq= (ulong) info.dfile; /* Uniq number in process */
+ info.this_loop=0; /* Update counter */
+ info.last_uniq= share->state.uniq;
+ info.last_loop= share->state.loop;
+ info.options=share->base.options |
+ (mode == O_RDONLY ? HA_OPTION_READ_ONLY_DATA : 0);
+ info.lock_type=F_UNLCK;
+ info.errkey= -1;
+ pthread_mutex_lock(&share->intern_lock);
+ info.read_record=share->read_record;
+ share->reopen++;
+ if (share->base.options & HA_OPTION_READ_ONLY_DATA)
+ {
+ info.lock_type=F_RDLCK;
+ share->r_locks++;
+ info.this_uniq=share->state.uniq; /* Row checksum */
+ }
+#ifndef NO_LOCKING
+ if (handle_locking & HA_OPEN_TMP_TABLE)
+#endif
+ {
+ share->w_locks++; /* We don't have to update status */
+ info.lock_type=F_WRLCK;
+ }
+ pthread_mutex_unlock(&share->intern_lock);
+
+ /* Allocate buffer for one record */
+
+ extra=0;
+ if (share->base.options & HA_OPTION_PACK_RECORD)
+ extra=ALIGN_SIZE(MAX_DYN_BLOCK_HEADER)+N_SPLITT_LENGTH+
+ DYN_DELETE_BLOCK_HEADER;
+ if (!(info.rec_alloc=(byte*) my_malloc(share->base.pack_reclength+extra+
+ 6,
+ MYF(MY_WME | MY_ZEROFILL))))
+ goto err;
+ if (extra)
+ info.rec_buff=info.rec_alloc+ALIGN_SIZE(MAX_DYN_BLOCK_HEADER);
+ else
+ info.rec_buff=info.rec_alloc;
+
+ *m_info=info;
+#ifdef THREAD
+ thr_lock_data_init(&share->lock,&m_info->lock,NULL);
+#endif
+
+ m_info->open_list.data=(void*) m_info;
+ nisam_open_list=list_add(nisam_open_list,&m_info->open_list);
+
+ pthread_mutex_unlock(&THR_LOCK_isam);
+ nisam_log_simple(LOG_OPEN,m_info,share->filename,
+ (uint) strlen(share->filename));
+ DBUG_RETURN(m_info);
+
+err:
+ save_errno=my_errno ? my_errno : HA_ERR_END_OF_FILE;
+ switch (errpos) {
+ case 6:
+ my_free((gptr) m_info,MYF(0));
+ /* fall through */
+ case 5:
+ VOID(my_close(info.dfile,MYF(0)));
+ if (old_info)
+ break; /* Don't remove open table */
+ /* fall through */
+ case 4:
+ my_free((gptr) share,MYF(0));
+ /* fall through */
+ case 3:
+#ifndef NO_LOCKING
+ if (! lock_error)
+ VOID(my_lock(kfile, F_UNLCK, 0L, F_TO_EOF, MYF(MY_SEEK_NOT_DONE)));
+#endif
+ /* fall through */
+ case 2:
+ my_afree((gptr) disk_cache);
+ /* fall through */
+ case 1:
+ VOID(my_close(kfile,MYF(0)));
+ /* fall through */
+ case 0:
+ default:
+ break;
+ }
+ pthread_mutex_unlock(&THR_LOCK_isam);
+ my_errno=save_errno;
+ DBUG_RETURN (NULL);
+} /* nisam_open */
+
+
+ /* Set up functions in structs */
+
+static void setup_functions(register ISAM_SHARE *share)
+{
+ if (share->base.options & HA_OPTION_COMPRESS_RECORD)
+ {
+ share->read_record=_nisam_read_pack_record;
+ share->read_rnd=_nisam_read_rnd_pack_record;
+ }
+ else if (share->base.options & HA_OPTION_PACK_RECORD)
+ {
+ share->read_record=_nisam_read_dynamic_record;
+ share->read_rnd=_nisam_read_rnd_dynamic_record;
+ share->delete_record=_nisam_delete_dynamic_record;
+ share->compare_record=_nisam_cmp_dynamic_record;
+ if (share->base.blobs)
+ {
+ share->update_record=_nisam_update_blob_record;
+ share->write_record=_nisam_write_blob_record;
+ }
+ else
+ {
+ share->write_record=_nisam_write_dynamic_record;
+ share->update_record=_nisam_update_dynamic_record;
+ }
+ }
+ else
+ {
+ share->read_record=_nisam_read_static_record;
+ share->read_rnd=_nisam_read_rnd_static_record;
+ share->delete_record=_nisam_delete_static_record;
+ share->compare_record=_nisam_cmp_static_record;
+ share->update_record=_nisam_update_static_record;
+ share->write_record=_nisam_write_static_record;
+ }
+ return;
+}
+
+
+static void setup_key_functions(register N_KEYDEF *keyinfo)
+{
+ if (keyinfo->base.flag & (HA_PACK_KEY | HA_SPACE_PACK_USED))
+ {
+ keyinfo->bin_search=_nisam_seq_search;
+ keyinfo->get_key=_nisam_get_key;
+ }
+ else
+ {
+ keyinfo->bin_search=_nisam_bin_search;
+ keyinfo->get_key=_nisam_get_static_key;
+ }
+ return;
+}
diff --git a/isam/pack_isam.c b/isam/pack_isam.c
new file mode 100644
index 00000000000..9193f52a863
--- /dev/null
+++ b/isam/pack_isam.c
@@ -0,0 +1,2051 @@
+/* Copyright (C) 1979-1999 TcX AB & Monty Program KB & Detron HB
+
+ This software is distributed with NO WARRANTY OF ANY KIND. No author or
+ distributor accepts any responsibility for the consequences of using it, or
+ for whether it serves any particular purpose or works at all, unless he or
+ she says so in writing. Refer to the Free Public License (the "License")
+ for full details.
+ Every copy of this file must include a copy of the License, normally in a
+ plain ASCII text file named PUBLIC. The License grants you the right to
+ copy, modify and redistribute this file, but only under certain conditions
+ described in the License. Among other things, the License requires that
+ the copyright notice and this notice be preserved on all copies. */
+
+/* Pack isam file*/
+
+#ifndef USE_MY_FUNC
+#define USE_MY_FUNC /* We nead at least my_malloc */
+#endif
+
+#include "isamdef.h"
+#include <queues.h>
+#include <my_tree.h>
+#include "mysys_err.h"
+#ifdef MSDOS
+#include <io.h>
+#endif
+#ifndef __GNU_LIBRARY__
+#define __GNU_LIBRARY__ /* Skipp warnings in getopt.h */
+#endif
+#include <getopt.h>
+
+#if INT_MAX > 32767
+#define BITS_SAVED 32
+#else
+#define BITS_SAVED 16
+#endif
+
+#define IS_OFFSET ((uint) 32768) /* Bit if offset or char in tree */
+#define HEAD_LENGTH 32
+#define ALLOWED_JOIN_DIFF 256 /* Diff allowed to join trees */
+
+#define DATA_TMP_EXT ".TMD"
+#define OLD_EXT ".OLD"
+#define WRITE_COUNT MY_HOW_OFTEN_TO_WRITE
+
+#ifdef __WIN__
+static double ulonglong2double(ulonglong value)
+{
+ longlong nr=(longlong) value;
+ if (nr >= 0)
+ return (double) nr;
+ return (18446744073709551616.0 + (double) nr);
+}
+
+#if SIZEOF_OFF_T > 4
+#define my_off_t2double(A) ulonglong2double(A)
+#else
+#define my_off_t2double(A) ((double) (A))
+#endif /* SIZEOF_OFF_T > 4 */
+#endif
+
+struct st_file_buffer {
+ File file;
+ char *buffer,*pos,*end;
+ my_off_t pos_in_file;
+ int bits;
+ uint byte;
+};
+
+struct st_huff_tree;
+struct st_huff_element;
+
+typedef struct st_huff_counts {
+ uint field_length,max_zero_fill;
+ uint pack_type;
+ uint max_end_space,max_pre_space,length_bits,min_space;
+ enum en_fieldtype field_type;
+ struct st_huff_tree *tree; /* Tree for field */
+ my_off_t counts[256];
+ my_off_t end_space[8];
+ my_off_t pre_space[8];
+ my_off_t tot_end_space,tot_pre_space,zero_fields,empty_fields,bytes_packed;
+ TREE int_tree;
+ byte *tree_buff;
+ byte *tree_pos;
+} HUFF_COUNTS;
+
+typedef struct st_huff_element HUFF_ELEMENT;
+
+struct st_huff_element {
+ my_off_t count;
+ union un_element {
+ struct st_nod {
+ HUFF_ELEMENT *left,*right;
+ } nod;
+ struct st_leaf {
+ HUFF_ELEMENT *null;
+ uint element_nr; /* Number of element */
+ } leaf;
+ } a;
+};
+
+
+typedef struct st_huff_tree {
+ HUFF_ELEMENT *root,*element_buffer;
+ HUFF_COUNTS *counts;
+ uint tree_number;
+ uint elements;
+ my_off_t bytes_packed;
+ uint tree_pack_length;
+ uint min_chr,max_chr,char_bits,offset_bits,max_offset,height;
+ ulong *code;
+ uchar *code_len;
+} HUFF_TREE;
+
+
+typedef struct st_isam_mrg {
+ N_INFO **file,**current,**end;
+ uint count;
+ uint min_pack_length; /* Theese is used by packed data */
+ uint max_pack_length;
+ uint ref_length;
+ my_off_t records;
+} MRG_INFO;
+
+
+extern int main(int argc,char * *argv);
+static void get_options(int *argc,char ***argv);
+static N_INFO *open_isam_file(char *name,int mode);
+static bool open_isam_files(MRG_INFO *mrg,char **names,uint count);
+static int compress(MRG_INFO *file,char *join_name);
+static HUFF_COUNTS *init_huff_count(N_INFO *info,my_off_t records);
+static void free_counts_and_tree_and_queue(HUFF_TREE *huff_trees,
+ uint trees,
+ HUFF_COUNTS *huff_counts,
+ uint fields);
+static int compare_tree(const uchar *s,const uchar *t);
+static int get_statistic(MRG_INFO *mrg,HUFF_COUNTS *huff_counts);
+static void check_counts(HUFF_COUNTS *huff_counts,uint trees,
+ my_off_t records);
+static int test_space_compress(HUFF_COUNTS *huff_counts,my_off_t records,
+ uint max_space_length,my_off_t *space_counts,
+ my_off_t tot_space_count,
+ enum en_fieldtype field_type);
+static HUFF_TREE* make_huff_trees(HUFF_COUNTS *huff_counts,uint trees);
+static int make_huff_tree(HUFF_TREE *tree,HUFF_COUNTS *huff_counts);
+static int compare_huff_elements(void *not_used, byte *a,byte *b);
+static int save_counts_in_queue(byte *key,element_count count,
+ HUFF_TREE *tree);
+static my_off_t calc_packed_length(HUFF_COUNTS *huff_counts,uint flag);
+static uint join_same_trees(HUFF_COUNTS *huff_counts,uint trees);
+static int make_huff_decode_table(HUFF_TREE *huff_tree,uint trees);
+static void make_traverse_code_tree(HUFF_TREE *huff_tree,
+ HUFF_ELEMENT *element,uint size,
+ ulong code);
+static int write_header(MRG_INFO *isam_file, uint header_length,uint trees,
+ my_off_t tot_elements,my_off_t filelength);
+static void write_field_info(HUFF_COUNTS *counts, uint fields,uint trees);
+static my_off_t write_huff_tree(HUFF_TREE *huff_tree,uint trees);
+static uint *make_offset_code_tree(HUFF_TREE *huff_tree,
+ HUFF_ELEMENT *element,
+ uint *offset);
+static uint max_bit(uint value);
+static int compress_isam_file(MRG_INFO *file,HUFF_COUNTS *huff_counts);
+static char *make_new_name(char *new_name,char *old_name);
+static char *make_old_name(char *new_name,char *old_name);
+static void init_file_buffer(File file,pbool read_buffer);
+static int flush_buffer(uint neaded_length);
+static void end_file_buffer(void);
+static void write_bits(ulong value,uint bits);
+static void flush_bits(void);
+static void save_integer(byte *pos,uint pack_length,my_off_t value);
+static void save_state(N_INFO *isam_file,MRG_INFO *mrg,my_off_t new_length,
+ ulong crc);
+static int save_state_mrg(File file,MRG_INFO *isam_file,my_off_t new_length,
+ ulong crc);
+static int mrg_close(MRG_INFO *mrg);
+static int mrg_rrnd(MRG_INFO *info,byte *buf);
+static void mrg_reset(MRG_INFO *mrg);
+
+
+static int backup=0,error_on_write=0,test_only=0,verbose=0,silent=0,
+ write_loop=0,force_pack=0,opt_wait=0,isamchk_neaded=0;
+static int tmpfile_createflag=O_RDWR | O_TRUNC | O_EXCL;
+static uint tree_buff_length=8196-MALLOC_OVERHEAD,force_pack_ref_length;
+static char tmp_dir[FN_REFLEN]={0},*join_table;
+static my_off_t intervall_length;
+static ulong crc;
+static struct st_file_buffer file_buffer;
+static QUEUE queue;
+static HUFF_COUNTS *global_count;
+static char zero_string[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
+static const char *load_default_groups[]= { "pack_isam",0 };
+
+ /* The main program */
+
+int main(int argc, char **argv)
+{
+ int error,ok;
+ MRG_INFO merge;
+ MY_INIT(argv[0]);
+
+ load_defaults("my",load_default_groups,&argc,&argv);
+ get_options(&argc,&argv);
+
+ error=ok=isamchk_neaded=0;
+ if (join_table)
+ { /* Join files into one */
+ if (open_isam_files(&merge,argv,(uint) argc) ||
+ compress(&merge,join_table))
+ error=1;
+ }
+ else while (argc--)
+ {
+ N_INFO *isam_file;
+ if (!(isam_file=open_isam_file(*argv++,O_RDWR)))
+ error=1;
+ else
+ {
+ merge.file= &isam_file;
+ merge.current=0;
+ merge.count=1;
+ if (compress(&merge,0))
+ error=1;
+ else
+ ok=1;
+ }
+ }
+ if (ok && isamchk_neaded && !silent)
+ puts("Remember to run isamchk -rq on compressed databases");
+ VOID(fflush(stdout)); VOID(fflush(stderr));
+ my_end(verbose ? MY_CHECK_ERROR | MY_GIVE_INFO : MY_CHECK_ERROR);
+ exit(error ? 2 : 0);
+#ifndef _lint
+ return 0; /* No compiler warning */
+#endif
+}
+
+
+static struct option long_options[] =
+{
+ {"backup", no_argument, 0, 'b'},
+ {"debug", optional_argument, 0, '#'},
+ {"force", no_argument, 0, 'f'},
+ {"join", required_argument, 0, 'j'},
+ {"help", no_argument, 0, '?'},
+ {"packlength",required_argument, 0, 'p'},
+ {"silent", no_argument, 0, 's'},
+ {"tmpdir", required_argument, 0, 'T'},
+ {"test", no_argument, 0, 't'},
+ {"verbose", no_argument, 0, 'v'},
+ {"version", no_argument, 0, 'V'},
+ {"wait", no_argument, 0, 'w'},
+ {0, 0, 0, 0}
+};
+
+static void print_version(void)
+{
+ printf("%s Ver 5.8 for %s on %s\n",my_progname,SYSTEM_TYPE,MACHINE_TYPE);
+}
+
+static void usage(void)
+{
+ print_version();
+ puts("Copyright (C) 1994-2000 TcX AB & Monty Program KB & Detron HB.");
+ puts("This is not free software. You must have a licence to use this program");
+ puts("This software comes with ABSOLUTELY NO WARRANTY\n");
+ puts("Pack a ISAM-table to take much smaller space");
+ puts("Keys are not updated, so you must run isamchk -rq on any table");
+ puts("that has keys after you have compressed it");
+ puts("You should give the .ISM file as the filename argument");
+
+ printf("\nUsage: %s [OPTIONS] filename...\n", my_progname);
+ puts("\n\
+ -b, --backup Make a backup of the table as table_name.OLD\n\
+ -f, --force Force packing of table even if it's gets bigger or\n\
+ tempfile exists.\n\
+ -j, --join='new_table_name'\n\
+ Join all given tables into 'new_table_name'.\n\
+ All tables MUST have the identical layout.\n\
+ -p, --packlength=# Force storage size of recordlength (1,2 or 3)\n\
+ -s, --silent Be more silent.\n\
+ -t, --test Don't pack table, only test packing it\n\
+ -v, --verbose Write info about progress and packing result\n\
+ -w, --wait Wait and retry if table is in use\n\
+ -T, --tmpdir=# Use temporary directory to store temporary table\n\
+ -#, --debug=... output debug log. Often this is 'd:t:o,filename`\n\
+ -?, --help display this help and exit\n\
+ -V, --version output version information and exit\n");
+ print_defaults("my",load_default_groups);
+};
+
+ /* reads options */
+ /* Initiates DEBUG - but no debugging here ! */
+
+static void get_options(int *argc,char ***argv)
+{
+ int c,option_index=0;
+ uint length;
+
+ my_progname= argv[0][0];
+ if (isatty(fileno(stdout)))
+ write_loop=1;
+
+ while ((c=getopt_long(*argc,*argv,"bfj:p:stvwT:#::?V",long_options,
+ &option_index)) != EOF)
+ {
+ switch(c) {
+ case 'b':
+ backup=1;
+ break;
+ case 'f':
+ force_pack=1;
+ tmpfile_createflag=O_RDWR | O_TRUNC;
+ break;
+ case 'j':
+ join_table=optarg;
+ break;
+ case 'p':
+ force_pack_ref_length=(uint) atoi(optarg);
+ if (force_pack_ref_length > 3)
+ force_pack_ref_length=0;
+ break;
+ case 's':
+ write_loop=verbose=0; silent=1;
+ break;
+ case 't':
+ test_only=verbose=1;
+ break;
+ case 'T':
+ length=(uint) (strmov(tmp_dir,optarg)-tmp_dir);
+ if (length != dirname_length(tmp_dir))
+ {
+ tmp_dir[length]=FN_LIBCHAR;
+ tmp_dir[length+1]=0;
+ }
+ break;
+ case 'v':
+ verbose=1; silent=0;
+ break;
+ case 'w':
+ opt_wait=1;
+ break;
+ case '#':
+ DBUG_PUSH(optarg ? optarg : "d:t:o");
+ break;
+ case 'V': print_version(); exit(0);
+ case 'I':
+ case '?':
+ usage();
+ exit(0);
+ default:
+ fprintf(stderr,"%s: Illegal option: -%c\n",my_progname,opterr);
+ usage();
+ exit(1);
+ }
+ }
+ (*argc)-=optind;
+ (*argv)+=optind;
+ if (!*argc)
+ {
+ usage();
+ exit(1);
+ }
+ if (join_table)
+ {
+ backup=0; /* Not needed */
+ tmp_dir[0]=0;
+ }
+ return;
+}
+
+
+static N_INFO *open_isam_file(char *name,int mode)
+{
+ N_INFO *isam_file;
+ ISAM_SHARE *share;
+ DBUG_ENTER("open_isam_file");
+
+ if (!(isam_file=nisam_open(name,mode,(opt_wait ? HA_OPEN_WAIT_IF_LOCKED :
+ HA_OPEN_ABORT_IF_LOCKED))))
+ {
+ VOID(fprintf(stderr,"%s gave error %d on open\n",name,my_errno));
+ DBUG_RETURN(0);
+ }
+ share=isam_file->s;
+ if (share->base.blobs)
+ {
+ VOID(fprintf(stderr,"%s has blobs, can't pack it\n",name));
+ VOID(nisam_close(isam_file));
+ DBUG_RETURN(0);
+ }
+ if (share->base.options & HA_OPTION_COMPRESS_RECORD && !join_table)
+ {
+ if (!force_pack)
+ {
+ VOID(fprintf(stderr,"%s is already compressed\n",name));
+ VOID(nisam_close(isam_file));
+ DBUG_RETURN(0);
+ }
+ if (verbose)
+ puts("Recompressing already compressed table");
+ share->base.options&= ~HA_OPTION_READ_ONLY_DATA; /* We are modifing it */
+ }
+ if (! force_pack && share->state.records != 0 &&
+ (share->state.records <= 1 ||
+ share->state.data_file_length < 1024) && ! join_table)
+ {
+ VOID(fprintf(stderr,"%s is too small to compress\n",name));
+ VOID(nisam_close(isam_file));
+ DBUG_RETURN(0);
+ }
+ VOID(nisam_lock_database(isam_file,F_WRLCK));
+ DBUG_RETURN(isam_file);
+}
+
+
+static bool open_isam_files(MRG_INFO *mrg,char **names,uint count)
+{
+ uint i,j;
+ mrg->count=0;
+ mrg->current=0;
+ mrg->file=(N_INFO**) my_malloc(sizeof(N_INFO*)*count,MYF(MY_FAE));
+ for (i=0; i < count ; i++)
+ {
+ if (!(mrg->file[i]=open_isam_file(names[i],O_RDONLY)))
+ goto error;
+ }
+ /* Check that files are identical */
+ for (j=0 ; j < count-1 ; j++)
+ {
+ N_RECINFO *m1,*m2,*end;
+ if (mrg->file[j]->s->base.reclength != mrg->file[j+1]->s->base.reclength ||
+ mrg->file[j]->s->base.fields != mrg->file[j+1]->s->base.fields)
+ goto diff_file;
+ m1=mrg->file[j]->s->rec;
+ end=m1+mrg->file[j]->s->base.fields;
+ m2=mrg->file[j+1]->s->rec;
+ for ( ; m1 != end ; m1++,m2++)
+ {
+ if ((m1->base.type != m2->base.type && ! force_pack) ||
+ m1->base.length != m2->base.length)
+ goto diff_file;
+ }
+ }
+ mrg->count=count;
+ return 0;
+
+ diff_file:
+ fprintf(stderr,"%s: Tables '%s' and '%s' are not identical\n",
+ my_progname,names[j],names[j+1]);
+ error:
+ while (i--)
+ nisam_close(mrg->file[i]);
+ return 1;
+}
+
+
+static int compress(MRG_INFO *mrg,char *result_table)
+{
+ int error;
+ File new_file,join_isam_file;
+ N_INFO *isam_file;
+ ISAM_SHARE *share;
+ char org_name[FN_REFLEN],new_name[FN_REFLEN],temp_name[FN_REFLEN];
+ uint i,header_length,fields,trees,used_trees;
+ my_off_t old_length,new_length,tot_elements;
+ HUFF_COUNTS *huff_counts;
+ HUFF_TREE *huff_trees;
+ DBUG_ENTER("compress");
+
+ isam_file=mrg->file[0]; /* Take this as an example */
+ share=isam_file->s;
+ new_file=join_isam_file= -1;
+ trees=fields=0;
+ huff_trees=0;
+ huff_counts=0;
+
+ /* Create temporary or join file */
+
+ if (backup)
+ VOID(fn_format(org_name,isam_file->filename,"",N_NAME_DEXT,2));
+ else
+ VOID(fn_format(org_name,isam_file->filename,"",N_NAME_DEXT,2+4+16));
+ if (!test_only && result_table)
+ {
+ /* Make a new indexfile based on first file in list */
+ uint length;
+ char *buff;
+ strmov(org_name,result_table); /* Fix error messages */
+ VOID(fn_format(new_name,result_table,"",N_NAME_IEXT,2));
+ if ((join_isam_file=my_create(new_name,0,tmpfile_createflag,MYF(MY_WME)))
+ < 0)
+ goto err;
+ length=share->base.keystart;
+ if (!(buff=my_malloc(length,MYF(MY_WME))))
+ goto err;
+ if (my_pread(share->kfile,buff,length,0L,MYF(MY_WME | MY_NABP)) ||
+ my_write(join_isam_file,buff,length,
+ MYF(MY_WME | MY_NABP | MY_WAIT_IF_FULL)))
+ {
+ my_free(buff,MYF(0));
+ goto err;
+ }
+ my_free(buff,MYF(0));
+ VOID(fn_format(new_name,result_table,"",N_NAME_DEXT,2));
+ }
+ else if (!tmp_dir[0])
+ VOID(make_new_name(new_name,org_name));
+ else
+ VOID(fn_format(new_name,org_name,tmp_dir,DATA_TMP_EXT,1+2+4));
+ if (!test_only &&
+ (new_file=my_create(new_name,0,tmpfile_createflag,MYF(MY_WME))) < 0)
+ goto err;
+
+ /* Start calculating statistics */
+
+ mrg->records=0;
+ for (i=0 ; i < mrg->count ; i++)
+ mrg->records+=mrg->file[i]->s->state.records;
+ if (write_loop || verbose)
+ {
+ printf("Compressing %s: (%lu records)\n",
+ result_table ? new_name : org_name,(ulong) mrg->records);
+ }
+ trees=fields=share->base.fields;
+ huff_counts=init_huff_count(isam_file,mrg->records);
+ QUICK_SAFEMALLOC;
+ if (write_loop || verbose)
+ printf("- Calculating statistics\n");
+ if (get_statistic(mrg,huff_counts))
+ goto err;
+ NORMAL_SAFEMALLOC;
+ old_length=0;
+ for (i=0; i < mrg->count ; i++)
+ old_length+= (mrg->file[i]->s->state.data_file_length -
+ mrg->file[i]->s->state.empty);
+
+ if (init_queue(&queue,256,0,0,compare_huff_elements,0))
+ goto err;
+ check_counts(huff_counts,fields,mrg->records);
+ huff_trees=make_huff_trees(huff_counts,trees);
+ if ((int) (used_trees=join_same_trees(huff_counts,trees)) < 0)
+ goto err;
+ if (make_huff_decode_table(huff_trees,fields))
+ goto err;
+
+ init_file_buffer(new_file,0);
+ file_buffer.pos_in_file=HEAD_LENGTH;
+ if (! test_only)
+ VOID(my_seek(new_file,file_buffer.pos_in_file,MY_SEEK_SET,MYF(0)));
+
+ write_field_info(huff_counts,fields,used_trees);
+ if (!(tot_elements=write_huff_tree(huff_trees,trees)))
+ goto err;
+ header_length=(uint) file_buffer.pos_in_file+
+ (uint) (file_buffer.pos-file_buffer.buffer);
+
+ /* Compress file */
+ if (write_loop || verbose)
+ printf("- Compressing file\n");
+ error=compress_isam_file(mrg,huff_counts);
+ new_length=file_buffer.pos_in_file;
+ if (!error && !test_only)
+ {
+ char buff[MEMMAP_EXTRA_MARGIN]; /* End marginal for memmap */
+ bzero(buff,sizeof(buff));
+ error=my_write(file_buffer.file,buff,sizeof(buff),
+ MYF(MY_WME | MY_NABP | MY_WAIT_IF_FULL)) != 0;
+ }
+ if (!error)
+ error=write_header(mrg,header_length,used_trees,tot_elements,
+ new_length);
+ end_file_buffer();
+
+ if (verbose && mrg->records)
+ printf("Min record length: %6d Max length: %6d Mean total length: %6d\n",
+ mrg->min_pack_length,mrg->max_pack_length,
+ (long) new_length/mrg->records);
+
+ if (!test_only)
+ {
+ error|=my_close(new_file,MYF(MY_WME));
+ if (!result_table)
+ {
+ error|=my_close(isam_file->dfile,MYF(MY_WME));
+ isam_file->dfile= -1; /* Tell nisam_close file is closed */
+ }
+ }
+
+ free_counts_and_tree_and_queue(huff_trees,trees,huff_counts,fields);
+ if (! test_only && ! error)
+ {
+ if (result_table)
+ {
+ error=save_state_mrg(join_isam_file,mrg,new_length,crc);
+ }
+ else
+ {
+ if (backup)
+ {
+ if (my_rename(org_name,make_old_name(temp_name,isam_file->filename),
+ MYF(MY_WME)))
+ error=1;
+ else
+ {
+ if (tmp_dir[0])
+ {
+ if (!(error=my_copy(new_name,org_name,MYF(MY_WME))))
+ VOID(my_delete(new_name,MYF(MY_WME)));
+ }
+ else
+ error=my_rename(new_name,org_name,MYF(MY_WME));
+ if (!error)
+ VOID(my_copystat(temp_name,org_name,MYF(MY_COPYTIME)));
+ }
+ }
+ else
+ {
+ if (tmp_dir[0])
+ {
+
+ if (!(error=my_copy(new_name,org_name,
+ MYF(MY_WME | MY_HOLD_ORIGINAL_MODES
+ | MY_COPYTIME))))
+ VOID(my_delete(new_name,MYF(MY_WME)));
+ }
+ else
+ error=my_redel(org_name,new_name,MYF(MY_WME | MY_COPYTIME));
+ }
+ if (! error)
+ save_state(isam_file,mrg,new_length,crc);
+ }
+ }
+ error|=mrg_close(mrg);
+ if (join_isam_file >= 0)
+ error|=my_close(join_isam_file,MYF(MY_WME));
+ if (error)
+ {
+ VOID(fprintf(stderr,"Aborting: %s is not compressed\n",org_name));
+ DBUG_RETURN(-1);
+ }
+ if (write_loop || verbose)
+ {
+ if (old_length)
+ printf("%.4g%% \n",
+ my_off_t2double(old_length-new_length)*100.0/
+ my_off_t2double(old_length));
+ else
+ puts("Empty file saved in compressed format");
+ }
+ DBUG_RETURN(0);
+
+ err:
+ free_counts_and_tree_and_queue(huff_trees,trees,huff_counts,fields);
+ if (new_file >= 0)
+ VOID(my_close(new_file,MYF(0)));
+ if (join_isam_file >= 0)
+ VOID(my_close(join_isam_file,MYF(0)));
+ mrg_close(mrg);
+ VOID(fprintf(stderr,"Aborted: %s is not compressed\n",org_name));
+ DBUG_RETURN(-1);
+}
+
+ /* Init a huff_count-struct for each field and init it */
+
+static HUFF_COUNTS *init_huff_count(N_INFO *info,my_off_t records)
+{
+ reg2 uint i;
+ reg1 HUFF_COUNTS *count;
+ if ((count = (HUFF_COUNTS*) my_malloc(info->s->base.fields*sizeof(HUFF_COUNTS),
+ MYF(MY_ZEROFILL | MY_WME))))
+ {
+ for (i=0 ; i < info->s->base.fields ; i++)
+ {
+ enum en_fieldtype type;
+ count[i].field_length=info->s->rec[i].base.length;
+ type= count[i].field_type= (enum en_fieldtype) info->s->rec[i].base.type;
+ if (type == FIELD_INTERVALL ||
+ type == FIELD_CONSTANT ||
+ type == FIELD_ZERO)
+ type = FIELD_NORMAL;
+ if (count[i].field_length <= 8 &&
+ (type == FIELD_NORMAL ||
+ type == FIELD_SKIPP_ZERO))
+ count[i].max_zero_fill= count[i].field_length;
+ init_tree(&count[i].int_tree,0,-1,(qsort_cmp) compare_tree,0,NULL);
+ if (records)
+ count[i].tree_pos=count[i].tree_buff =
+ my_malloc(count[i].field_length > 1 ? tree_buff_length : 2,
+ MYF(MY_WME));
+ }
+ }
+ return count;
+}
+
+
+ /* Free memory used by counts and trees */
+
+static void free_counts_and_tree_and_queue(HUFF_TREE *huff_trees, uint trees, HUFF_COUNTS *huff_counts, uint fields)
+{
+ register uint i;
+
+ if (huff_trees)
+ {
+ for (i=0 ; i < trees ; i++)
+ {
+ if (huff_trees[i].element_buffer)
+ my_free((gptr) huff_trees[i].element_buffer,MYF(0));
+ if (huff_trees[i].code)
+ my_free((gptr) huff_trees[i].code,MYF(0));
+ }
+ my_free((gptr) huff_trees,MYF(0));
+ }
+ if (huff_counts)
+ {
+ for (i=0 ; i < fields ; i++)
+ {
+ if (huff_counts[i].tree_buff)
+ {
+ my_free((gptr) huff_counts[i].tree_buff,MYF(0));
+ delete_tree(&huff_counts[i].int_tree);
+ }
+ }
+ my_free((gptr) huff_counts,MYF(0));
+ }
+ delete_queue(&queue); /* This is safe to free */
+ return;
+}
+
+ /* Read through old file and gather some statistics */
+
+static int get_statistic(MRG_INFO *mrg,HUFF_COUNTS *huff_counts)
+{
+ int error;
+ uint length,reclength;
+ byte *record,*pos,*next_pos,*end_pos,*start_pos;
+ my_off_t record_count;
+ HUFF_COUNTS *count,*end_count;
+ TREE_ELEMENT *element;
+ DBUG_ENTER("get_statistic");
+
+ reclength=mrg->file[0]->s->base.reclength;
+ record=(byte*) my_alloca(reclength);
+ end_count=huff_counts+mrg->file[0]->s->base.fields;
+ record_count=crc=0;
+
+ mrg_reset(mrg);
+ while ((error=mrg_rrnd(mrg,record)) >= 0)
+ {
+ if (! error)
+ {
+ crc^=checksum(record,reclength);
+ for (pos=record,count=huff_counts ;
+ count < end_count ;
+ count++,
+ pos=next_pos)
+ {
+ next_pos=end_pos=(start_pos=pos)+count->field_length;
+
+ /* Put value in tree if there is room for it */
+ if (count->tree_buff)
+ {
+ global_count=count;
+ if (!(element=tree_insert(&count->int_tree,pos,0)) ||
+ element->count == 1 &&
+ count->tree_buff + tree_buff_length <
+ count->tree_pos + count->field_length ||
+ count->field_length == 1 &&
+ count->int_tree.elements_in_tree > 1)
+ {
+ delete_tree(&count->int_tree);
+ my_free(count->tree_buff,MYF(0));
+ count->tree_buff=0;
+ }
+ else
+ {
+ if (element->count == 1)
+ { /* New element */
+ memcpy(count->tree_pos,pos,(size_t) count->field_length);
+ tree_set_pointer(element,count->tree_pos);
+ count->tree_pos+=count->field_length;
+ }
+ }
+ }
+
+ /* Save character counters and space-counts and zero-field-counts */
+ if (count->field_type == FIELD_NORMAL ||
+ count->field_type == FIELD_SKIPP_ENDSPACE)
+ {
+ for ( ; end_pos > pos ; end_pos--)
+ if (end_pos[-1] != ' ')
+ break;
+ if (end_pos == pos)
+ {
+ count->empty_fields++;
+ count->max_zero_fill=0;
+ continue;
+ }
+ length= (uint) (next_pos-end_pos);
+ count->tot_end_space+=length;
+ if (length < 8)
+ count->end_space[length]++;
+ if (count->max_end_space < length)
+ count->max_end_space = length;
+ }
+ if (count->field_type == FIELD_NORMAL ||
+ count->field_type == FIELD_SKIPP_PRESPACE)
+ {
+ for (pos=start_pos; pos < end_pos ; pos++)
+ if (pos[0] != ' ')
+ break;
+ if (end_pos == pos)
+ {
+ count->empty_fields++;
+ count->max_zero_fill=0;
+ continue;
+ }
+ length= (uint) (pos-start_pos);
+ count->tot_pre_space+=length;
+ if (length < 8)
+ count->pre_space[length]++;
+ if (count->max_pre_space < length)
+ count->max_pre_space = length;
+ }
+ if (count->field_length <= 8 &&
+ (count->field_type == FIELD_NORMAL ||
+ count->field_type == FIELD_SKIPP_ZERO))
+ {
+ uint i;
+ if (!memcmp((byte*) start_pos,zero_string,count->field_length))
+ {
+ count->zero_fields++;
+ continue;
+ }
+#ifdef BYTE_ORDER_HIGH_FIRST
+ for (i =0 ; i < count->max_zero_fill && ! start_pos[i] ; i++) ;
+ if (i < count->max_zero_fill)
+ count->max_zero_fill=i;
+#else
+ for (i =0 ; i < count->max_zero_fill && ! end_pos[-1 - (int) i] ; i++) ;
+ if (i < count->max_zero_fill)
+ count->max_zero_fill=i;
+#endif
+ }
+ for (pos=start_pos ; pos < end_pos ; pos++)
+ count->counts[(uchar) *pos]++;
+ }
+ record_count++;
+ if (write_loop && record_count % WRITE_COUNT == 0)
+ {
+ printf("%lu\r",(ulong) record_count); VOID(fflush(stdout));
+ }
+ }
+ }
+ if (write_loop)
+ {
+ printf(" \r"); VOID(fflush(stdout));
+ }
+ mrg->records=record_count;
+ my_afree((gptr) record);
+ DBUG_RETURN(0);
+}
+
+static int compare_huff_elements(void *not_used, byte *a, byte *b)
+{
+ return *((my_off_t*) a) < *((my_off_t*) b) ? -1 :
+ (*((my_off_t*) a) == *((my_off_t*) b) ? 0 : 1);
+}
+
+ /* Check each tree if we should use pre-space-compress, end-space-
+ compress, empty-field-compress or zero-field-compress */
+
+static void check_counts(HUFF_COUNTS *huff_counts, uint trees, my_off_t records)
+{
+ uint space_fields,fill_zero_fields,field_count[(int) FIELD_ZERO+1];
+ my_off_t old_length,new_length,length;
+ DBUG_ENTER("check_counts");
+
+ bzero((gptr) field_count,sizeof(field_count));
+ space_fields=fill_zero_fields=0;
+
+ for (; trees-- ; huff_counts++)
+ {
+ huff_counts->field_type=FIELD_NORMAL;
+ huff_counts->pack_type=0;
+
+ if (huff_counts->zero_fields || ! records)
+ {
+ my_off_t old_space_count;
+ if (huff_counts->zero_fields == records)
+ {
+ huff_counts->field_type= FIELD_ZERO;
+ huff_counts->bytes_packed=0;
+ huff_counts->counts[0]=0;
+ goto found_pack;
+ }
+ old_space_count=huff_counts->counts[' '];
+ huff_counts->counts[' ']+=huff_counts->tot_end_space+
+ huff_counts->tot_pre_space +
+ huff_counts->empty_fields * huff_counts->field_length;
+ old_length=calc_packed_length(huff_counts,0)+records/8;
+ length=huff_counts->zero_fields*huff_counts->field_length;
+ huff_counts->counts[0]+=length;
+ new_length=calc_packed_length(huff_counts,0);
+ if (old_length < new_length && huff_counts->field_length > 1)
+ {
+ huff_counts->field_type=FIELD_SKIPP_ZERO;
+ huff_counts->counts[0]-=length;
+ huff_counts->bytes_packed=old_length- records/8;
+ goto found_pack;
+ }
+ huff_counts->counts[' ']=old_space_count;
+ }
+ huff_counts->bytes_packed=calc_packed_length(huff_counts,0);
+ if (huff_counts->empty_fields)
+ {
+ if (huff_counts->field_length > 2 &&
+ huff_counts->empty_fields + (records - huff_counts->empty_fields)*
+ (1+max_bit(max(huff_counts->max_pre_space,
+ huff_counts->max_end_space))) <
+ records * max_bit(huff_counts->field_length))
+ {
+ huff_counts->pack_type |= PACK_TYPE_SPACE_FIELDS;
+ }
+ else
+ {
+ length=huff_counts->empty_fields*huff_counts->field_length;
+ if (huff_counts->tot_end_space || ! huff_counts->tot_pre_space)
+ {
+ huff_counts->tot_end_space+=length;
+ huff_counts->max_end_space=huff_counts->field_length;
+ if (huff_counts->field_length < 8)
+ huff_counts->end_space[huff_counts->field_length]+=
+ huff_counts->empty_fields;
+ }
+ else
+ {
+ huff_counts->tot_pre_space+=length;
+ huff_counts->max_pre_space=huff_counts->field_length;
+ if (huff_counts->field_length < 8)
+ huff_counts->pre_space[huff_counts->field_length]+=
+ huff_counts->empty_fields;
+ }
+ }
+ }
+ if (huff_counts->tot_end_space)
+ {
+ huff_counts->counts[' ']+=huff_counts->tot_pre_space;
+ if (test_space_compress(huff_counts,records,huff_counts->max_end_space,
+ huff_counts->end_space,
+ huff_counts->tot_end_space,FIELD_SKIPP_ENDSPACE))
+ goto found_pack;
+ huff_counts->counts[' ']-=huff_counts->tot_pre_space;
+ }
+ if (huff_counts->tot_pre_space)
+ {
+ if (test_space_compress(huff_counts,records,huff_counts->max_pre_space,
+ huff_counts->pre_space,
+ huff_counts->tot_pre_space,FIELD_SKIPP_PRESPACE))
+ goto found_pack;
+ }
+
+ found_pack: /* Found field-packing */
+
+ /* Test if we can use zero-fill */
+
+ if (huff_counts->max_zero_fill &&
+ (huff_counts->field_type == FIELD_NORMAL ||
+ huff_counts->field_type == FIELD_SKIPP_ZERO))
+ {
+ huff_counts->counts[0]-=huff_counts->max_zero_fill*
+ (huff_counts->field_type == FIELD_SKIPP_ZERO ?
+ records - huff_counts->zero_fields : records);
+ huff_counts->pack_type|=PACK_TYPE_ZERO_FILL;
+ huff_counts->bytes_packed=calc_packed_length(huff_counts,0);
+ }
+
+ /* Test if intervall-field is better */
+
+ if (huff_counts->tree_buff)
+ {
+ HUFF_TREE tree;
+
+ tree.element_buffer=0;
+ if (!make_huff_tree(&tree,huff_counts) &&
+ tree.bytes_packed+tree.tree_pack_length < huff_counts->bytes_packed)
+ {
+ if (tree.elements == 1)
+ huff_counts->field_type=FIELD_CONSTANT;
+ else
+ huff_counts->field_type=FIELD_INTERVALL;
+ huff_counts->pack_type=0;
+ }
+ else
+ {
+ my_free((gptr) huff_counts->tree_buff,MYF(0));
+ delete_tree(&huff_counts->int_tree);
+ huff_counts->tree_buff=0;
+ }
+ if (tree.element_buffer)
+ my_free((gptr) tree.element_buffer,MYF(0));
+ }
+ if (huff_counts->pack_type & PACK_TYPE_SPACE_FIELDS)
+ space_fields++;
+ if (huff_counts->pack_type & PACK_TYPE_ZERO_FILL)
+ fill_zero_fields++;
+ field_count[huff_counts->field_type]++;
+ }
+ if (verbose)
+ printf("\nnormal: %3d empty-space: %3d empty-zero: %3d empty-fill: %3d\npre-space: %3d end-space: %3d table-lookup: %3d zero: %3d\n",
+ field_count[FIELD_NORMAL],space_fields,
+ field_count[FIELD_SKIPP_ZERO],fill_zero_fields,
+ field_count[FIELD_SKIPP_PRESPACE],
+ field_count[FIELD_SKIPP_ENDSPACE],
+ field_count[FIELD_INTERVALL],
+ field_count[FIELD_ZERO]);
+ DBUG_VOID_RETURN;
+}
+
+ /* Test if we can use space-compression and empty-field-compression */
+
+static int
+test_space_compress(HUFF_COUNTS *huff_counts, my_off_t records,
+ uint max_space_length, my_off_t *space_counts,
+ my_off_t tot_space_count, enum en_fieldtype field_type)
+{
+ int min_pos;
+ uint length_bits,i;
+ my_off_t space_count,min_space_count,min_pack,new_length,skipp;
+
+ length_bits=max_bit(max_space_length);
+
+ /* Default no end_space-packing */
+ space_count=huff_counts->counts[(uint) ' '];
+ min_space_count= (huff_counts->counts[(uint) ' ']+= tot_space_count);
+ min_pack=calc_packed_length(huff_counts,0);
+ min_pos= -2;
+ huff_counts->counts[(uint) ' ']=space_count;
+
+ /* Test with allways space-count */
+ new_length=huff_counts->bytes_packed+length_bits*records/8;
+ if (new_length+1 < min_pack)
+ {
+ min_pos= -1;
+ min_pack=new_length;
+ min_space_count=space_count;
+ }
+ /* Test with length-flag */
+ for (skipp=0L, i=0 ; i < 8 ; i++)
+ {
+ if (space_counts[i])
+ {
+ if (i)
+ huff_counts->counts[(uint) ' ']+=space_counts[i];
+ skipp+=huff_counts->pre_space[i];
+ new_length=calc_packed_length(huff_counts,0)+
+ (records+(records-skipp)*(1+length_bits))/8;
+ if (new_length < min_pack)
+ {
+ min_pos=(int) i;
+ min_pack=new_length;
+ min_space_count=huff_counts->counts[(uint) ' '];
+ }
+ }
+ }
+
+ huff_counts->counts[(uint) ' ']=min_space_count;
+ huff_counts->bytes_packed=min_pack;
+ switch (min_pos) {
+ case -2:
+ return(0); /* No space-compress */
+ case -1: /* Always space-count */
+ huff_counts->field_type=field_type;
+ huff_counts->min_space=0;
+ huff_counts->length_bits=max_bit(max_space_length);
+ break;
+ default:
+ huff_counts->field_type=field_type;
+ huff_counts->min_space=(uint) min_pos;
+ huff_counts->pack_type|=PACK_TYPE_SELECTED;
+ huff_counts->length_bits=max_bit(max_space_length);
+ break;
+ }
+ return(1); /* Using space-compress */
+}
+
+
+ /* Make a huff_tree of each huff_count */
+
+static HUFF_TREE* make_huff_trees(HUFF_COUNTS *huff_counts, uint trees)
+{
+ uint tree;
+ HUFF_TREE *huff_tree;
+ DBUG_ENTER("make_huff_trees");
+
+ if (!(huff_tree=(HUFF_TREE*) my_malloc(trees*sizeof(HUFF_TREE),
+ MYF(MY_WME | MY_ZEROFILL))))
+ DBUG_RETURN(0);
+
+ for (tree=0 ; tree < trees ; tree++)
+ {
+ if (make_huff_tree(huff_tree+tree,huff_counts+tree))
+ {
+ while (tree--)
+ my_free((gptr) huff_tree[tree].element_buffer,MYF(0));
+ my_free((gptr) huff_tree,MYF(0));
+ DBUG_RETURN(0);
+ }
+ }
+ DBUG_RETURN(huff_tree);
+}
+
+ /* Update huff_tree according to huff_counts->counts or
+ huff_counts->tree_buff */
+
+static int make_huff_tree(HUFF_TREE *huff_tree, HUFF_COUNTS *huff_counts)
+{
+ uint i,found,bits_packed,first,last;
+ my_off_t bytes_packed;
+ HUFF_ELEMENT *a,*b,*new;
+
+ first=last=0;
+ if (huff_counts->tree_buff)
+ {
+ found= (uint) (huff_counts->tree_pos - huff_counts->tree_buff) /
+ huff_counts->field_length;
+ first=0; last=found-1;
+ }
+ else
+ {
+ for (i=found=0 ; i < 256 ; i++)
+ {
+ if (huff_counts->counts[i])
+ {
+ if (! found++)
+ first=i;
+ last=i;
+ }
+ }
+ if (found < 2)
+ found=2;
+ }
+
+ if (queue.max_elements < found)
+ {
+ delete_queue(&queue);
+ if (init_queue(&queue,found,0,0,compare_huff_elements,0))
+ return -1;
+ }
+
+ if (!huff_tree->element_buffer)
+ {
+ if (!(huff_tree->element_buffer=
+ (HUFF_ELEMENT*) my_malloc(found*2*sizeof(HUFF_ELEMENT),MYF(MY_WME))))
+ return 1;
+ }
+ else
+ {
+ HUFF_ELEMENT *temp;
+ if (!(temp=
+ (HUFF_ELEMENT*) my_realloc((gptr) huff_tree->element_buffer,
+ found*2*sizeof(HUFF_ELEMENT),
+ MYF(MY_WME))))
+ return 1;
+ huff_tree->element_buffer=temp;
+ }
+
+ huff_counts->tree=huff_tree;
+ huff_tree->counts=huff_counts;
+ huff_tree->min_chr=first;
+ huff_tree->max_chr=last;
+ huff_tree->char_bits=max_bit(last-first);
+ huff_tree->offset_bits=max_bit(found-1)+1;
+
+ if (huff_counts->tree_buff)
+ {
+ huff_tree->elements=0;
+ tree_walk(&huff_counts->int_tree,
+ (int (*)(void*, element_count,void*)) save_counts_in_queue,
+ (gptr) huff_tree, left_root_right);
+ huff_tree->tree_pack_length=(1+15+16+5+5+
+ (huff_tree->char_bits+1)*found+
+ (huff_tree->offset_bits+1)*
+ (found-2)+7)/8 +
+ (uint) (huff_tree->counts->tree_pos-
+ huff_tree->counts->tree_buff);
+ }
+ else
+ {
+ huff_tree->elements=found;
+ huff_tree->tree_pack_length=(9+9+5+5+
+ (huff_tree->char_bits+1)*found+
+ (huff_tree->offset_bits+1)*
+ (found-2)+7)/8;
+
+ for (i=first, found=0 ; i <= last ; i++)
+ {
+ if (huff_counts->counts[i])
+ {
+ new=huff_tree->element_buffer+(found++);
+ new->count=huff_counts->counts[i];
+ new->a.leaf.null=0;
+ new->a.leaf.element_nr=i;
+ queue.root[found]=(byte*) new;
+ }
+ }
+ while (found < 2)
+ { /* Our huff_trees request at least 2 elements */
+ new=huff_tree->element_buffer+(found++);
+ new->count=0;
+ new->a.leaf.null=0;
+ if (last)
+ new->a.leaf.element_nr=huff_tree->min_chr=last-1;
+ else
+ new->a.leaf.element_nr=huff_tree->max_chr=last+1;
+ queue.root[found]=(byte*) new;
+ }
+ }
+ queue.elements=found;
+
+ for (i=found/2 ; i > 0 ; i--)
+ _downheap(&queue,i);
+ bytes_packed=0; bits_packed=0;
+ for (i=1 ; i < found ; i++)
+ {
+ a=(HUFF_ELEMENT*) queue_remove(&queue,0);
+ b=(HUFF_ELEMENT*) queue.root[1];
+ new=huff_tree->element_buffer+found+i;
+ new->count=a->count+b->count;
+ bits_packed+=(uint) (new->count & 7);
+ bytes_packed+=new->count/8;
+ new->a.nod.left=a; /* lesser in left */
+ new->a.nod.right=b;
+ queue.root[1]=(byte*) new;
+ queue_replaced(&queue);
+ }
+ huff_tree->root=(HUFF_ELEMENT*) queue.root[1];
+ huff_tree->bytes_packed=bytes_packed+(bits_packed+7)/8;
+ return 0;
+}
+
+static int compare_tree(register const uchar *s, register const uchar *t)
+{
+ uint length;
+ for (length=global_count->field_length; length-- ;)
+ if (*s++ != *t++)
+ return (int) s[-1] - (int) t[-1];
+ return 0;
+}
+
+ /* Used by make_huff_tree to save intervall-counts in queue */
+
+static int save_counts_in_queue(byte *key, element_count count, HUFF_TREE *tree)
+{
+ HUFF_ELEMENT *new;
+
+ new=tree->element_buffer+(tree->elements++);
+ new->count=count;
+ new->a.leaf.null=0;
+ new->a.leaf.element_nr= (uint) (key- tree->counts->tree_buff) /
+ tree->counts->field_length;
+ queue.root[tree->elements]=(byte*) new;
+ return 0;
+}
+
+
+ /* Calculate length of file if given counts should be used */
+ /* Its actually a faster version of make_huff_tree */
+
+static my_off_t calc_packed_length(HUFF_COUNTS *huff_counts, uint add_tree_lenght)
+{
+ uint i,found,bits_packed,first,last;
+ my_off_t bytes_packed;
+ HUFF_ELEMENT element_buffer[256];
+ DBUG_ENTER("calc_packed_length");
+
+ first=last=0;
+ for (i=found=0 ; i < 256 ; i++)
+ {
+ if (huff_counts->counts[i])
+ {
+ if (! found++)
+ first=i;
+ last=i;
+ queue.root[found]=(byte*) &huff_counts->counts[i];
+ }
+ }
+ if (!found)
+ DBUG_RETURN(0); /* Empty tree */
+ if (found < 2)
+ queue.root[++found]=(byte*) &huff_counts->counts[last ? 0 : 1];
+
+ queue.elements=found;
+
+ bytes_packed=0; bits_packed=0;
+ if (add_tree_lenght)
+ bytes_packed=(8+9+5+5+(max_bit(last-first)+1)*found+
+ (max_bit(found-1)+1+1)*(found-2) +7)/8;
+ for (i=(found+1)/2 ; i > 0 ; i--)
+ _downheap(&queue,i);
+ for (i=0 ; i < found-1 ; i++)
+ {
+ HUFF_ELEMENT *a,*b,*new;
+ a=(HUFF_ELEMENT*) queue_remove(&queue,0);
+ b=(HUFF_ELEMENT*) queue.root[1];
+ new=element_buffer+i;
+ new->count=a->count+b->count;
+ bits_packed+=(uint) (new->count & 7);
+ bytes_packed+=new->count/8;
+ queue.root[1]=(byte*) new;
+ queue_replaced(&queue);
+ }
+ DBUG_RETURN(bytes_packed+(bits_packed+7)/8);
+}
+
+
+ /* Remove trees that don't give any compression */
+
+static uint join_same_trees(HUFF_COUNTS *huff_counts, uint trees)
+{
+ uint k,tree_number;
+ HUFF_COUNTS count,*i,*j,*last_count;
+
+ last_count=huff_counts+trees;
+ for (tree_number=0, i=huff_counts ; i < last_count ; i++)
+ {
+ if (!i->tree->tree_number)
+ {
+ i->tree->tree_number= ++tree_number;
+ if (i->tree_buff)
+ continue; /* Don't join intervall */
+ for (j=i+1 ; j < last_count ; j++)
+ {
+ if (! j->tree->tree_number && ! j->tree_buff)
+ {
+ for (k=0 ; k < 256 ; k++)
+ count.counts[k]=i->counts[k]+j->counts[k];
+ if (calc_packed_length(&count,1) <=
+ i->tree->bytes_packed + j->tree->bytes_packed+
+ i->tree->tree_pack_length+j->tree->tree_pack_length+
+ ALLOWED_JOIN_DIFF)
+ {
+ memcpy((byte*) i->counts,(byte*) count.counts,
+ sizeof(count.counts[0])*256);
+ my_free((gptr) j->tree->element_buffer,MYF(0));
+ j->tree->element_buffer=0;
+ j->tree=i->tree;
+ bmove((byte*) i->counts,(byte*) count.counts,
+ sizeof(count.counts[0])*256);
+ if (make_huff_tree(i->tree,i))
+ return (uint) -1;
+ }
+ }
+ }
+ }
+ }
+ if (verbose)
+ printf("Original trees: %d After join: %d\n",trees,tree_number);
+ return tree_number; /* Return trees left */
+}
+
+
+ /* Fill in huff_tree decode tables */
+
+static int make_huff_decode_table(HUFF_TREE *huff_tree, uint trees)
+{
+ uint elements;
+ for ( ; trees-- ; huff_tree++)
+ {
+ if (huff_tree->tree_number > 0)
+ {
+ elements=huff_tree->counts->tree_buff ? huff_tree->elements : 256;
+ if (!(huff_tree->code =
+ (ulong*) my_malloc(elements*
+ (sizeof(ulong)+sizeof(uchar)),
+ MYF(MY_WME | MY_ZEROFILL))))
+ return 1;
+ huff_tree->code_len=(uchar*) (huff_tree->code+elements);
+ make_traverse_code_tree(huff_tree,huff_tree->root,32,0);
+ }
+ }
+ return 0;
+}
+
+
+static void make_traverse_code_tree(HUFF_TREE *huff_tree, HUFF_ELEMENT *element,
+ uint size, ulong code)
+{
+ uint chr;
+ if (!element->a.leaf.null)
+ {
+ chr=element->a.leaf.element_nr;
+ huff_tree->code_len[chr]=(uchar) (32-size);
+ huff_tree->code[chr]= (code >> size);
+ if (huff_tree->height < 32-size)
+ huff_tree->height= 32-size;
+ }
+ else
+ {
+ size--;
+ make_traverse_code_tree(huff_tree,element->a.nod.left,size,code);
+ make_traverse_code_tree(huff_tree,element->a.nod.right,size,
+ code+((ulong) 1L << size));
+ }
+ return;
+}
+
+
+ /* Write header to new packed data file */
+
+static int write_header(MRG_INFO *mrg,uint head_length,uint trees,
+ my_off_t tot_elements,my_off_t filelength)
+{
+ byte *buff=file_buffer.pos;
+
+ bzero(buff,HEAD_LENGTH);
+ memcpy(buff,nisam_pack_file_magic,4);
+ int4store(buff+4,head_length);
+ int4store(buff+8, mrg->min_pack_length);
+ int4store(buff+12,mrg->max_pack_length);
+ int4store(buff+16,tot_elements);
+ int4store(buff+20,intervall_length);
+ int2store(buff+24,trees);
+ buff[26]=(char) mrg->ref_length;
+ /* Save record pointer length */
+ buff[27]= (uchar) (filelength >= (1L << 24) ? 4 :
+ filelength >= (1L << 16) ? 3 : 2);
+ if (test_only)
+ return 0;
+ VOID(my_seek(file_buffer.file,0L,MY_SEEK_SET,MYF(0)));
+ return my_write(file_buffer.file,file_buffer.pos,HEAD_LENGTH,
+ MYF(MY_WME | MY_NABP | MY_WAIT_IF_FULL)) != 0;
+}
+
+ /* Write fieldinfo to new packed file */
+
+static void write_field_info(HUFF_COUNTS *counts, uint fields, uint trees)
+{
+ reg1 uint i;
+ uint huff_tree_bits;
+ huff_tree_bits=max_bit(trees ? trees-1 : 0);
+
+ for (i=0 ; i++ < fields ; counts++)
+ {
+ write_bits((ulong) (int) counts->field_type,4);
+ write_bits(counts->pack_type,4);
+ if (counts->pack_type & PACK_TYPE_ZERO_FILL)
+ write_bits(counts->max_zero_fill,4);
+ else
+ write_bits(counts->length_bits,4);
+ write_bits((ulong) counts->tree->tree_number-1,huff_tree_bits);
+ }
+ flush_bits();
+ return;
+}
+
+ /* Write all huff_trees to new datafile. Return tot count of
+ elements in all trees
+ Returns 0 on error */
+
+static my_off_t write_huff_tree(HUFF_TREE *huff_tree, uint trees)
+{
+ uint i,int_length;
+ uint *packed_tree,*offset,length;
+ my_off_t elements;
+
+ for (i=length=0 ; i < trees ; i++)
+ if (huff_tree[i].tree_number > 0 && huff_tree[i].elements > length)
+ length=huff_tree[i].elements;
+ if (!(packed_tree=(uint*) my_alloca(sizeof(uint)*length*2)))
+ {
+ my_error(EE_OUTOFMEMORY,MYF(ME_BELL),sizeof(uint)*length*2);
+ return 0;
+ }
+
+ intervall_length=0;
+ for (elements=0; trees-- ; huff_tree++)
+ {
+ if (huff_tree->tree_number == 0)
+ continue; /* Deleted tree */
+ elements+=huff_tree->elements;
+ huff_tree->max_offset=2;
+ if (huff_tree->elements <= 1)
+ offset=packed_tree;
+ else
+ offset=make_offset_code_tree(huff_tree,huff_tree->root,packed_tree);
+ huff_tree->offset_bits=max_bit(huff_tree->max_offset);
+ if (huff_tree->max_offset >= IS_OFFSET)
+ { /* This should be impossible */
+ VOID(fprintf(stderr,"Tree offset got too big: %d, aborted\n",
+ huff_tree->max_offset));
+ my_afree((gptr) packed_tree);
+ return 0;
+ }
+
+#ifdef EXTRA_DBUG
+ printf("pos: %d elements: %d tree-elements: %d char_bits: %d\n",
+ (uint) (file_buffer.pos-file_buffer.buffer),
+ huff_tree->elements, (offset-packed_tree),huff_tree->char_bits);
+#endif
+ if (!huff_tree->counts->tree_buff)
+ {
+ write_bits(0,1);
+ write_bits(huff_tree->min_chr,8);
+ write_bits(huff_tree->elements,9);
+ write_bits(huff_tree->char_bits,5);
+ write_bits(huff_tree->offset_bits,5);
+ int_length=0;
+ }
+ else
+ {
+ int_length=(uint) (huff_tree->counts->tree_pos -
+ huff_tree->counts->tree_buff);
+ write_bits(1,1);
+ write_bits(huff_tree->elements,15);
+ write_bits(int_length,16);
+ write_bits(huff_tree->char_bits,5);
+ write_bits(huff_tree->offset_bits,5);
+ intervall_length+=int_length;
+ }
+ length=(uint) (offset-packed_tree);
+ if (length != huff_tree->elements*2-2)
+ printf("error: Huff-tree-length: %d != calc_length: %d\n",
+ length,huff_tree->elements*2-2);
+
+ for (i=0 ; i < length ; i++)
+ {
+ if (packed_tree[i] & IS_OFFSET)
+ write_bits(packed_tree[i] - IS_OFFSET+ ((ulong) 1L << huff_tree->offset_bits),
+ huff_tree->offset_bits+1);
+ else
+ write_bits(packed_tree[i]-huff_tree->min_chr,huff_tree->char_bits+1);
+ }
+ flush_bits();
+ if (huff_tree->counts->tree_buff)
+ {
+ for (i=0 ; i < int_length ; i++)
+ write_bits((uint) (uchar) huff_tree->counts->tree_buff[i],8);
+ }
+ flush_bits();
+ }
+ my_afree((gptr) packed_tree);
+ return elements;
+}
+
+
+static uint *make_offset_code_tree(HUFF_TREE *huff_tree, HUFF_ELEMENT *element,
+ uint *offset)
+{
+ uint *prev_offset;
+
+ prev_offset= offset;
+ if (!element->a.nod.left->a.leaf.null)
+ {
+ offset[0] =(uint) element->a.nod.left->a.leaf.element_nr;
+ offset+=2;
+ }
+ else
+ {
+ prev_offset[0]= IS_OFFSET+2;
+ offset=make_offset_code_tree(huff_tree,element->a.nod.left,offset+2);
+ }
+ if (!element->a.nod.right->a.leaf.null)
+ {
+ prev_offset[1]=element->a.nod.right->a.leaf.element_nr;
+ return offset;
+ }
+ else
+ {
+ uint temp=(uint) (offset-prev_offset-1);
+ prev_offset[1]= IS_OFFSET+ temp;
+ if (huff_tree->max_offset < temp)
+ huff_tree->max_offset = temp;
+ return make_offset_code_tree(huff_tree,element->a.nod.right,offset);
+ }
+}
+
+ /* Get number of bits neaded to represent value */
+
+static uint max_bit(register uint value)
+{
+ reg2 uint power=1;
+
+ while ((value>>=1))
+ power++;
+ return (power);
+}
+
+
+static int compress_isam_file(MRG_INFO *mrg, HUFF_COUNTS *huff_counts)
+{
+ int error;
+ uint i,max_calc_length,pack_ref_length,min_record_length,max_record_length,
+ intervall,field_length;
+ my_off_t record_count,max_allowed_length;
+ ulong length;
+ byte *record,*pos,*end_pos,*record_pos,*start_pos;
+ HUFF_COUNTS *count,*end_count;
+ HUFF_TREE *tree;
+ N_INFO *isam_file=mrg->file[0];
+ DBUG_ENTER("compress_isam_file");
+
+ if (!(record=(byte*) my_alloca(isam_file->s->base.reclength)))
+ return -1;
+ end_count=huff_counts+isam_file->s->base.fields;
+ min_record_length= (uint) ~0;
+ max_record_length=0;
+
+ for (i=max_calc_length=0 ; i < isam_file->s->base.fields ; i++)
+ {
+ if (!(huff_counts[i].pack_type & PACK_TYPE_ZERO_FILL))
+ huff_counts[i].max_zero_fill=0;
+ if (huff_counts[i].field_type == FIELD_CONSTANT ||
+ huff_counts[i].field_type == FIELD_ZERO)
+ continue;
+ if (huff_counts[i].field_type == FIELD_INTERVALL)
+ max_calc_length+=huff_counts[i].tree->height;
+ else
+ max_calc_length+=
+ (huff_counts[i].field_length - huff_counts[i].max_zero_fill)*
+ huff_counts[i].tree->height+huff_counts[i].length_bits;
+ }
+ max_calc_length/=8;
+ if (max_calc_length <= 255)
+ pack_ref_length=1;
+ else if (max_calc_length <= 65535)
+ pack_ref_length=2;
+ else
+ pack_ref_length=3;
+ if (force_pack_ref_length)
+ pack_ref_length=force_pack_ref_length;
+ max_allowed_length= 1L << (pack_ref_length*8);
+ record_count=0;
+
+ mrg_reset(mrg);
+ while ((error=mrg_rrnd(mrg,record)) >= 0)
+ {
+ if (! error)
+ {
+ if (flush_buffer(max_calc_length+pack_ref_length))
+ break;
+ record_pos=file_buffer.pos;
+ file_buffer.pos+=pack_ref_length;
+ for (start_pos=record, count= huff_counts; count < end_count ; count++)
+ {
+ end_pos=start_pos+(field_length=count->field_length);
+ tree=count->tree;
+
+ if (count->pack_type & PACK_TYPE_SPACE_FIELDS)
+ {
+ for (pos=start_pos ; *pos == ' ' && pos < end_pos; pos++) ;
+ if (pos == end_pos)
+ {
+ write_bits(1,1);
+ start_pos=end_pos;
+ continue;
+ }
+ write_bits(0,1);
+ }
+
+#ifdef BYTE_ORDER_HIGH_FIRST
+ start_pos+=count->max_zero_fill;
+#else
+ end_pos-=count->max_zero_fill;
+#endif
+ field_length-=count->max_zero_fill;
+
+ switch(count->field_type) {
+ case FIELD_SKIPP_ZERO:
+ if (!memcmp((byte*) start_pos,zero_string,field_length))
+ {
+ write_bits(1,1);
+ start_pos=end_pos;
+ break;
+ }
+ write_bits(0,1);
+ /* Fall through */
+ case FIELD_NORMAL:
+ for ( ; start_pos < end_pos ; start_pos++)
+ write_bits(tree->code[(uchar) *start_pos],
+ (uint) tree->code_len[(uchar) *start_pos]);
+ break;
+ case FIELD_SKIPP_ENDSPACE:
+ for (pos=end_pos ; pos > start_pos && pos[-1] == ' ' ; pos--) ;
+ length=(uint) (end_pos-pos);
+ if (count->pack_type & PACK_TYPE_SELECTED)
+ {
+ if (length > count->min_space)
+ {
+ write_bits(1,1);
+ write_bits(length,count->length_bits);
+ }
+ else
+ {
+ write_bits(0,1);
+ pos=end_pos;
+ }
+ }
+ else
+ write_bits(length,count->length_bits);
+ for ( ; start_pos < pos ; start_pos++)
+ write_bits(tree->code[(uchar) *start_pos],
+ (uint) tree->code_len[(uchar) *start_pos]);
+ start_pos=end_pos;
+ break;
+ case FIELD_SKIPP_PRESPACE:
+ for (pos=start_pos ; pos < end_pos && pos[0] == ' ' ; pos++) ;
+ length=(uint) (pos-start_pos);
+ if (count->pack_type & PACK_TYPE_SELECTED)
+ {
+ if (length > count->min_space)
+ {
+ write_bits(1,1);
+ write_bits(length,count->length_bits);
+ }
+ else
+ {
+ pos=start_pos;
+ write_bits(0,1);
+ }
+ }
+ else
+ write_bits(length,count->length_bits);
+ for (start_pos=pos ; start_pos < end_pos ; start_pos++)
+ write_bits(tree->code[(uchar) *start_pos],
+ (uint) tree->code_len[(uchar) *start_pos]);
+ break;
+ case FIELD_CONSTANT:
+ case FIELD_ZERO:
+ start_pos=end_pos;
+ break;
+ case FIELD_INTERVALL:
+ global_count=count;
+ pos=(byte*) tree_search(&count->int_tree,start_pos);
+ intervall=(uint) (pos - count->tree_buff)/field_length;
+ write_bits(tree->code[intervall],(uint) tree->code_len[intervall]);
+ start_pos=end_pos;
+ break;
+ case FIELD_BLOB:
+ VOID(fprintf(stderr,"Can't pack files with blobs. Aborting\n"));
+ DBUG_RETURN(1);
+ case FIELD_LAST:
+ case FIELD_VARCHAR:
+ case FIELD_CHECK:
+ abort(); /* Impossible */
+ }
+#ifndef BYTE_ORDER_HIGH_FIRST
+ start_pos+=count->max_zero_fill;
+#endif
+ }
+ flush_bits();
+ length=(ulong) (file_buffer.pos-record_pos)-pack_ref_length;
+ save_integer(record_pos,pack_ref_length,length);
+ if (length < (ulong) min_record_length)
+ min_record_length=(uint) length;
+ if (length > (ulong) max_record_length)
+ {
+ max_record_length=(uint) length;
+ if (max_record_length >= max_allowed_length)
+ {
+ fprintf(stderr,
+ "Error: Found record with packed-length: %d, max is: %d\n",
+ max_record_length,max_allowed_length);
+ error=1;
+ break;
+ }
+ }
+ if (write_loop && ++record_count % WRITE_COUNT == 0)
+ {
+ printf("%lu\r",(ulong) record_count); VOID(fflush(stdout));
+ }
+ }
+ else if (my_errno != HA_ERR_RECORD_DELETED)
+ break;
+ }
+ if (error < 0)
+ {
+ error=0;
+ if (my_errno != HA_ERR_END_OF_FILE)
+ {
+ fprintf(stderr,"%s: Got error %d reading records\n",my_progname,my_errno);
+ error= 1;
+ }
+ }
+
+ my_afree((gptr) record);
+ mrg->ref_length=pack_ref_length;
+ mrg->min_pack_length=max_record_length ? min_record_length : 0;
+ mrg->max_pack_length=max_record_length;
+ if (verbose && max_record_length &&
+ max_record_length < max_allowed_length/256)
+ printf("Record-length is %d bytes, could have been %d bytes\nYou can change this by using -p=%d next time you pack this file\n",
+ pack_ref_length,
+ max_record_length/256+1,
+ max_record_length/256+1);
+ DBUG_RETURN(error || error_on_write || flush_buffer((uint) ~0));
+}
+
+
+static char *make_new_name(char *new_name, char *old_name)
+{
+ return fn_format(new_name,old_name,"",DATA_TMP_EXT,2+4);
+}
+
+static char *make_old_name(char *new_name, char *old_name)
+{
+ return fn_format(new_name,old_name,"",OLD_EXT,2+4);
+}
+
+ /* rutines for bit writing buffer */
+
+static void init_file_buffer(File file, pbool read_buffer)
+{
+ file_buffer.file=file;
+ file_buffer.buffer=my_malloc(ALIGN_SIZE(RECORD_CACHE_SIZE),MYF(MY_WME));
+ file_buffer.end=file_buffer.buffer+ALIGN_SIZE(RECORD_CACHE_SIZE)-4;
+ file_buffer.pos_in_file=0;
+ error_on_write=0;
+ if (read_buffer)
+ {
+
+ file_buffer.pos=file_buffer.end;
+ file_buffer.bits=0;
+ }
+ else
+ {
+ file_buffer.pos=file_buffer.buffer;
+ file_buffer.bits=BITS_SAVED;
+ }
+ file_buffer.byte=0;
+}
+
+
+static int flush_buffer(uint neaded_length)
+{
+ uint length;
+ if ((uint) (file_buffer.end - file_buffer.pos) > neaded_length)
+ return 0;
+ length=(uint) (file_buffer.pos-file_buffer.buffer);
+ file_buffer.pos=file_buffer.buffer;
+ file_buffer.pos_in_file+=length;
+ if (test_only)
+ return 0;
+ return (error_on_write|=test(my_write(file_buffer.file,file_buffer.buffer,
+ length,
+ MYF(MY_WME | MY_NABP |
+ MY_WAIT_IF_FULL))));
+}
+
+static void end_file_buffer(void)
+{
+ my_free((gptr) file_buffer.buffer,MYF(0));
+}
+
+ /* output `bits` low bits of `value' */
+
+static void write_bits (register ulong value, register uint bits)
+{
+ if ((file_buffer.bits-=(int) bits) >= 0)
+ {
+ file_buffer.byte|=value << file_buffer.bits;
+ }
+ else
+ {
+ reg3 uint byte_buff;
+ bits= (uint) -file_buffer.bits;
+ byte_buff=file_buffer.byte | (uint) (value >> bits);
+#if BITS_SAVED == 32
+ *file_buffer.pos++= (byte) (byte_buff >> 24) ;
+ *file_buffer.pos++= (byte) (byte_buff >> 16) ;
+#endif
+ *file_buffer.pos++= (byte) (byte_buff >> 8) ;
+ *file_buffer.pos++= (byte) byte_buff;
+
+ value&=((ulong) 1L << bits)-1;
+#if BITS_SAVED == 16
+ if (bits >= sizeof(uint))
+ {
+ bits-=8;
+ *file_buffer.pos++= (uchar) (value >> bits);
+ value&= ((ulong) 1L << bits)-1;
+ if (bits >= sizeof(uint))
+ {
+ bits-=8;
+ *file_buffer.pos++= (uchar) (value >> bits);
+ value&= ((ulong) 1L << bits)-1;
+ }
+ }
+#endif
+ if (file_buffer.pos >= file_buffer.end)
+ VOID(flush_buffer((uint) ~0));
+ file_buffer.bits=(int) (BITS_SAVED - bits);
+ file_buffer.byte=(uint) (value << (BITS_SAVED - bits));
+ }
+ return;
+}
+
+ /* Flush bits in bit_buffer to buffer */
+
+static void flush_bits (void)
+{
+ uint bits,byte_buff;
+
+ bits=(file_buffer.bits) & ~7;
+ byte_buff = file_buffer.byte >> bits;
+ bits=BITS_SAVED - bits;
+ while (bits > 0)
+ {
+ bits-=8;
+ *file_buffer.pos++= (byte) (uchar) (byte_buff >> bits) ;
+ }
+ file_buffer.bits=BITS_SAVED;
+ file_buffer.byte=0;
+ return;
+}
+
+ /* Store long in 1,2,3,4 or 5 bytes */
+
+static void save_integer(byte *pos, uint pack_length, my_off_t value)
+{
+ switch (pack_length) {
+ case 5: int5store(pos,(ulonglong) value); break;
+ default: int4store(pos,(ulong) value); break;
+ case 3: int3store(pos,(ulong) value); break;
+ case 2: int2store(pos,(uint) value); break;
+ case 1: pos[0]= (byte) (uchar) value; break;
+ }
+ return;
+}
+
+
+/****************************************************************************
+** functions to handle the joined files
+****************************************************************************/
+
+static void save_state(N_INFO *isam_file,MRG_INFO *mrg,my_off_t new_length,
+ ulong crc)
+{
+ ISAM_SHARE *share=isam_file->s;
+ uint options=uint2korr(share->state.header.options);
+ DBUG_ENTER("save_state");
+
+ options|= HA_OPTION_COMPRESS_RECORD | HA_OPTION_READ_ONLY_DATA;
+ int2store(share->state.header.options,options);
+
+ share->state.data_file_length=(ulong) new_length;
+ share->state.del=share->state.empty=0;
+ share->state.dellink= (ulong) NI_POS_ERROR;
+ share->state.splitt=(ulong) mrg->records;
+ share->state.version=(ulong) time((time_t*) 0);
+ share->state.keys=0;
+ share->state.key_file_length=share->base.keystart;
+
+ isam_file->update|=(HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
+ isam_file->this_uniq=crc; /* Save crc here */
+ share->changed=1; /* Force write of header */
+ VOID(my_chsize(share->kfile,share->state.key_file_length,
+ MYF(0)));
+ if (share->state.keys != share->base.keys)
+ isamchk_neaded=1;
+ DBUG_VOID_RETURN;
+}
+
+
+static int save_state_mrg(File file,MRG_INFO *mrg,my_off_t new_length,
+ ulong crc)
+{
+ N_STATE_INFO state;
+ N_INFO *isam_file=mrg->file[0];
+ uint options;
+ DBUG_ENTER("save_state_mrg");
+
+ memcpy(&state,&isam_file->s->state,sizeof(state));
+ options= (uint2korr(state.header.options) | HA_OPTION_COMPRESS_RECORD |
+ HA_OPTION_READ_ONLY_DATA);
+ int2store(state.header.options,options);
+ state.data_file_length=(ulong) new_length;
+ state.del=state.empty=0;
+ state.dellink= (ulong) NI_POS_ERROR;
+ state.records=state.splitt=(ulong) mrg->records;
+ state.version=(ulong) time((time_t*) 0);
+ state.keys=0;
+ state.key_file_length=isam_file->s->base.keystart;
+ state.uniq=crc;
+ if (state.keys != isam_file->s->base.keys)
+ isamchk_neaded=1;
+ DBUG_RETURN (my_pwrite(file,(char*) &state.header,
+ isam_file->s->state_length,0L,
+ MYF(MY_NABP | MY_WME)) != 0);
+}
+
+
+/* reset for mrg_rrnd */
+
+static void mrg_reset(MRG_INFO *mrg)
+{
+ if (mrg->current)
+ {
+ nisam_extra(*mrg->current,HA_EXTRA_NO_CACHE);
+ mrg->current=0;
+ }
+}
+
+static int mrg_rrnd(MRG_INFO *info,byte *buf)
+{
+ int error;
+ N_INFO *isam_info;
+ my_off_t filepos;
+
+ if (!info->current)
+ {
+ isam_info= *(info->current=info->file);
+ info->end=info->current+info->count;
+ nisam_extra(isam_info,HA_EXTRA_CACHE);
+ nisam_extra(isam_info,HA_EXTRA_RESET);
+ filepos=isam_info->s->pack.header_length;
+ }
+ else
+ {
+ isam_info= *info->current;
+ filepos= isam_info->nextpos;
+ }
+
+ for (;;)
+ {
+ isam_info->update&= (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
+ if ((error=(*isam_info->s->read_rnd)(isam_info,(byte*) buf,
+ (ulong) filepos, 1)) >= 0 ||
+ my_errno != HA_ERR_END_OF_FILE)
+ return (error);
+ nisam_extra(isam_info,HA_EXTRA_NO_CACHE);
+ if (info->current+1 == info->end)
+ return(-1);
+ info->current++;
+ isam_info= *info->current;
+ filepos=isam_info->s->pack.header_length;
+ nisam_extra(isam_info,HA_EXTRA_CACHE);
+ nisam_extra(isam_info,HA_EXTRA_RESET);
+ }
+}
+
+
+static int mrg_close(MRG_INFO *mrg)
+{
+ uint i;
+ int error=0;
+ for (i=0 ; i < mrg->count ; i++)
+ error|=nisam_close(mrg->file[i]);
+ return error;
+}
diff --git a/isam/panic.c b/isam/panic.c
new file mode 100644
index 00000000000..52a5d1eb3b6
--- /dev/null
+++ b/isam/panic.c
@@ -0,0 +1,135 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include "isamdef.h"
+
+ /* if flag == HA_PANIC_CLOSE then all misam files are closed */
+ /* if flag == HA_PANIC_WRITE then all misam files are unlocked and
+ all changed data in single user misam is written to file */
+ /* if flag == HA_PANIC_READ then all misam files that was locked when
+ nisam_panic(HA_PANIC_WRITE) was done is locked. A ni_readinfo() is
+ done for all single user files to get changes in database */
+
+
+int nisam_panic(enum ha_panic_function flag)
+{
+ int error=0;
+ LIST *list_element,*next_open;
+ N_INFO *info;
+ DBUG_ENTER("nisam_panic");
+
+ pthread_mutex_lock(&THR_LOCK_isam);
+ for (list_element=nisam_open_list ; list_element ; list_element=next_open)
+ {
+ next_open=list_element->next; /* Save if close */
+ info=(N_INFO*) list_element->data;
+ switch (flag) {
+ case HA_PANIC_CLOSE:
+ pthread_mutex_unlock(&THR_LOCK_isam); /* Not exactly right... */
+ if (nisam_close(info))
+ error=my_errno;
+ pthread_mutex_lock(&THR_LOCK_isam);
+ break;
+ case HA_PANIC_WRITE: /* Do this to free databases */
+#ifdef CANT_OPEN_FILES_TWICE
+ if (info->s->base.options & HA_OPTION_READ_ONLY_DATA)
+ break;
+#endif
+ if (flush_key_blocks(info->s->kfile,FLUSH_RELEASE))
+ error=my_errno;
+ if (info->opt_flag & WRITE_CACHE_USED)
+ if (flush_io_cache(&info->rec_cache))
+ error=my_errno;
+ if (info->opt_flag & READ_CACHE_USED)
+ {
+ if (flush_io_cache(&info->rec_cache))
+ error=my_errno;
+ reinit_io_cache(&info->rec_cache,READ_CACHE,0,
+ (pbool) (info->lock_type != F_UNLCK),1);
+ }
+#ifndef NO_LOCKING
+ if (info->lock_type != F_UNLCK && ! info->was_locked)
+ {
+ info->was_locked=info->lock_type;
+ if (nisam_lock_database(info,F_UNLCK))
+ error=my_errno;
+ }
+#else
+ {
+ int save_status=info->s->w_locks; /* Only w_locks! */
+ info->s->w_locks=0;
+ if (_nisam_writeinfo(info, test(info->update & HA_STATE_CHANGED)))
+ error=my_errno;
+ info->s->w_locks=save_status;
+ info->update&= ~HA_STATE_CHANGED; /* Not changed */
+ }
+#endif /* NO_LOCKING */
+#ifdef CANT_OPEN_FILES_TWICE
+ if (info->s->kfile >= 0 && my_close(info->s->kfile,MYF(0)))
+ error = my_errno;
+ if (info->dfile >= 0 && my_close(info->dfile,MYF(0)))
+ error = my_errno;
+ info->s->kfile=info->dfile= -1; /* Files aren't open anymore */
+ break;
+#endif
+ case HA_PANIC_READ: /* Restore to before WRITE */
+#ifdef CANT_OPEN_FILES_TWICE
+ { /* Open closed files */
+ char name_buff[FN_REFLEN];
+ if (info->s->kfile < 0)
+ if ((info->s->kfile= my_open(fn_format(name_buff,info->filename,"",
+ N_NAME_IEXT,4),info->mode,
+ MYF(MY_WME))) < 0)
+ error = my_errno;
+ if (info->dfile < 0)
+ {
+ if ((info->dfile= my_open(fn_format(name_buff,info->filename,"",
+ N_NAME_DEXT,4),info->mode,
+ MYF(MY_WME))) < 0)
+ error = my_errno;
+ info->rec_cache.file=info->dfile;
+ }
+ }
+#endif
+#ifndef NO_LOCKING
+ if (info->was_locked)
+ {
+ if (nisam_lock_database(info, info->was_locked))
+ error=my_errno;
+ info->was_locked=0;
+ }
+#else
+ {
+ int lock_type,w_locks;
+ lock_type=info->lock_type ; w_locks=info->s->w_locks;
+ info->lock_type=0; info->s->w_locks=0;
+ if (_nisam_readinfo(info,0,1)) /* Read changed data */
+ error=my_errno;
+ info->lock_type=lock_type; info->s->w_locks=w_locks;
+ }
+ /* Don't use buffer when doing next */
+ info->update|=HA_STATE_WRITTEN;
+#endif /* NO_LOCKING */
+ break;
+ }
+ }
+ if (flag == HA_PANIC_CLOSE)
+ VOID(nisam_log(0)); /* Close log if neaded */
+ pthread_mutex_unlock(&THR_LOCK_isam);
+ if (!error) DBUG_RETURN(0);
+ my_errno=error;
+ DBUG_RETURN(-1);
+} /* nisam_panic */
diff --git a/isam/range.c b/isam/range.c
new file mode 100644
index 00000000000..5594991cfc3
--- /dev/null
+++ b/isam/range.c
@@ -0,0 +1,191 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/*
+ Gives a approximated number of how many records there is between two keys.
+ Used when optimizing querries.
+ */
+
+#include "isamdef.h"
+
+static ulong _nisam_record_pos(N_INFO *info,const byte *key,uint key_len,
+ enum ha_rkey_function search_flag);
+static double _nisam_search_pos(N_INFO *info,N_KEYDEF *keyinfo,uchar *key,
+ uint key_len,uint nextflag,ulong pos);
+static uint _nisam_keynr(N_INFO *info,N_KEYDEF *keyinfo,uchar *page,
+ uchar *keypos,uint *ret_max_key);
+
+
+ /* If start_key = 0 assume read from start */
+ /* If end_key = 0 assume read to end */
+ /* Returns NI_POS_ERROR on error */
+
+ulong nisam_records_in_range(N_INFO *info, int inx, const byte *start_key,
+ uint start_key_len,
+ enum ha_rkey_function start_search_flag,
+ const byte *end_key, uint end_key_len,
+ enum ha_rkey_function end_search_flag)
+{
+ ulong start_pos,end_pos;
+ DBUG_ENTER("nisam_records_in_range");
+
+ if ((inx = _nisam_check_index(info,inx)) < 0)
+ DBUG_RETURN(NI_POS_ERROR);
+
+#ifndef NO_LOCKING
+ if (_nisam_readinfo(info,F_RDLCK,1))
+ DBUG_RETURN(NI_POS_ERROR);
+#endif
+ info->update&= (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
+ start_pos= (start_key ?
+ _nisam_record_pos(info,start_key,start_key_len,start_search_flag) :
+ 0L);
+ end_pos= (end_key ?
+ _nisam_record_pos(info,end_key,end_key_len,end_search_flag) :
+ info->s->state.records+1L);
+ VOID(_nisam_writeinfo(info,0));
+ if (start_pos == NI_POS_ERROR || end_pos == NI_POS_ERROR)
+ DBUG_RETURN(NI_POS_ERROR);
+ DBUG_PRINT("info",("records: %ld",end_pos-start_pos));
+ DBUG_RETURN(end_pos < start_pos ? 0L :
+ (end_pos == start_pos ? 1L : end_pos-start_pos));
+}
+
+
+ /* Find relative position (in records) for key in index-tree */
+
+static ulong _nisam_record_pos(N_INFO *info, const byte *key, uint key_len,
+ enum ha_rkey_function search_flag)
+{
+ uint inx=(uint) info->lastinx;
+ N_KEYDEF *keyinfo=info->s->keyinfo+inx;
+ uchar *key_buff;
+ double pos;
+
+ DBUG_ENTER("_nisam_record_pos");
+ DBUG_PRINT("enter",("search_flag: %d",search_flag));
+
+ if (key_len >= (keyinfo->base.keylength-info->s->rec_reflength)
+ && !(keyinfo->base.flag & HA_SPACE_PACK_USED))
+ key_len=USE_HOLE_KEY;
+ key_buff=info->lastkey+info->s->base.max_key_length;
+ key_len=_nisam_pack_key(info,inx,key_buff,(uchar*) key,key_len);
+ DBUG_EXECUTE("key",_nisam_print_key(DBUG_FILE,keyinfo->seg,
+ (uchar*) key_buff););
+ pos=_nisam_search_pos(info,keyinfo,key_buff,key_len,
+ nisam_read_vec[search_flag] | SEARCH_SAVE_BUFF,
+ info->s->state.key_root[inx]);
+ if (pos >= 0.0)
+ {
+ DBUG_PRINT("exit",("pos: %ld",(ulong) (pos*info->s->state.records)));
+ DBUG_RETURN((ulong) (pos*info->s->state.records+0.5));
+ }
+ DBUG_RETURN(NI_POS_ERROR);
+}
+
+
+ /* This is a modified version of _nisam_search */
+ /* Returns offset for key in indextable (decimal 0.0 <= x <= 1.0) */
+
+static double _nisam_search_pos(register N_INFO *info, register N_KEYDEF *keyinfo,
+ uchar *key, uint key_len, uint nextflag,
+ register ulong pos)
+{
+ int flag;
+ uint nod_flag,keynr,max_keynr;
+ uchar *keypos,*buff;
+ double offset;
+ DBUG_ENTER("_nisam_search_pos");
+
+ if (pos == NI_POS_ERROR)
+ DBUG_RETURN(0.5);
+
+ if (!(buff=_nisam_fetch_keypage(info,keyinfo,pos,info->buff,1)))
+ goto err;
+ flag=(*keyinfo->bin_search)(info,keyinfo,buff,key,key_len,nextflag,
+ &keypos,info->lastkey);
+ nod_flag=test_if_nod(buff);
+ keynr=_nisam_keynr(info,keyinfo,buff,keypos,&max_keynr);
+
+ if (flag)
+ {
+ /*
+ ** Didn't found match. keypos points at next (bigger) key
+ * Try to find a smaller, better matching key.
+ ** Matches keynr + [0-1]
+ */
+ if ((offset=_nisam_search_pos(info,keyinfo,key,key_len,nextflag,
+ _nisam_kpos(nod_flag,keypos))) < 0)
+ DBUG_RETURN(offset);
+ }
+ else
+ {
+ /*
+ ** Found match. Keypos points at the start of the found key
+ ** Matches keynr+1
+ */
+ offset=1.0; /* Matches keynr+1 */
+ if (nextflag & SEARCH_FIND && (!(keyinfo->base.flag & HA_NOSAME)
+ || key_len) && nod_flag)
+ {
+ /*
+ ** There may be identical keys in the tree. Try to match on of those.
+ ** Matches keynr + [0-1]
+ */
+ if ((offset=_nisam_search_pos(info,keyinfo,key,key_len,SEARCH_FIND,
+ _nisam_kpos(nod_flag,keypos))) < 0)
+ DBUG_RETURN(offset); /* Read error */
+ }
+ }
+ DBUG_PRINT("info",("keynr: %d offset: %g max_keynr: %d nod: %d flag: %d",
+ keynr,offset,max_keynr,nod_flag,flag));
+ DBUG_RETURN((keynr+offset)/(max_keynr+1));
+err:
+ DBUG_PRINT("exit",("Error: %d",my_errno));
+ DBUG_RETURN (-1.0);
+}
+
+
+ /* Get keynummer of current key and max number of keys in nod */
+
+static uint _nisam_keynr(N_INFO *info, register N_KEYDEF *keyinfo, uchar *page, uchar *keypos, uint *ret_max_key)
+{
+ uint nod_flag,keynr,max_key;
+ uchar t_buff[N_MAX_KEY_BUFF],*end;
+
+ end= page+getint(page);
+ nod_flag=test_if_nod(page);
+ page+=2+nod_flag;
+
+ if (!(keyinfo->base.flag &
+ (HA_PACK_KEY | HA_SPACE_PACK | HA_SPACE_PACK_USED)))
+ {
+ *ret_max_key= (uint) (end-page)/(keyinfo->base.keylength+nod_flag);
+ return (uint) (keypos-page)/(keyinfo->base.keylength+nod_flag);
+ }
+
+ max_key=keynr=0;
+ while (page < end)
+ {
+ t_buff[0]=0; /* Don't move packed key */
+ VOID((*keyinfo->get_key)(keyinfo,nod_flag,&page,t_buff));
+ max_key++;
+ if (page == keypos)
+ keynr=max_key;
+ }
+ *ret_max_key=max_key;
+ return(keynr);
+}
diff --git a/isam/rfirst.c b/isam/rfirst.c
new file mode 100644
index 00000000000..82fd3994bdf
--- /dev/null
+++ b/isam/rfirst.c
@@ -0,0 +1,34 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* L{ser f|rsta posten som har samma isam-nyckel */
+
+#include "isamdef.h"
+
+ /*
+ L{ser f|rsta posten med samma isamnyckel som f|reg}ende l{sning.
+ Man kan ha gjort write, update eller delete p} f|reg}ende post.
+ OBS! [ven om man {ndrade isamnyckeln p} f|reg}ende post l{ses
+ posten i avseende p} f|reg}ende isam-nyckel-l{sning !!
+ */
+
+int nisam_rfirst(N_INFO *info, byte *buf, int inx)
+{
+ DBUG_ENTER("nisam_rfirst");
+ info->lastpos= NI_POS_ERROR;
+ info->update|= HA_STATE_PREV_FOUND;
+ DBUG_RETURN(nisam_rnext(info,buf,inx));
+} /* nisam_rfirst */
diff --git a/isam/rkey.c b/isam/rkey.c
new file mode 100644
index 00000000000..8f1f2f11ab5
--- /dev/null
+++ b/isam/rkey.c
@@ -0,0 +1,63 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* L{ser p} basen av en isam_nyckel */
+
+#include "isamdef.h"
+
+
+ /* Read a record using key */
+ /* Ordinary search_flag is 0 ; Give error if no record with key */
+
+int nisam_rkey(N_INFO *info, byte *buf, int inx, const byte *key, uint key_len, enum ha_rkey_function search_flag)
+{
+ uchar *key_buff;
+ ISAM_SHARE *share=info->s;
+ DBUG_ENTER("nisam_rkey");
+ DBUG_PRINT("enter",("base: %lx inx: %d search_flag: %d",
+ info,inx,search_flag));
+
+ if ((inx = _nisam_check_index(info,inx)) < 0)
+ DBUG_RETURN(-1);
+ info->update&= (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
+ if (key_len >= (share->keyinfo[inx].base.keylength - share->rec_reflength)
+ && !(info->s->keyinfo[inx].base.flag & HA_SPACE_PACK_USED))
+ key_len=USE_HOLE_KEY;
+ key_buff=info->lastkey+info->s->base.max_key_length;
+ key_len=_nisam_pack_key(info,(uint) inx,key_buff,(uchar*) key,key_len);
+ DBUG_EXECUTE("key",_nisam_print_key(DBUG_FILE,share->keyinfo[inx].seg,
+ (uchar*) key););
+
+#ifndef NO_LOCKING
+ if (_nisam_readinfo(info,F_RDLCK,1))
+ goto err;
+#endif
+
+ VOID(_nisam_search(info,info->s->keyinfo+inx,key_buff,key_len,
+ nisam_read_vec[search_flag],info->s->state.key_root[inx]));
+ if ((*info->read_record)(info,info->lastpos,buf) >= 0)
+ {
+ info->update|= HA_STATE_AKTIV; /* Record is read */
+ DBUG_RETURN(0);
+ }
+
+ info->lastpos = NI_POS_ERROR; /* Didn't find key */
+ VOID(_nisam_move_key(info->s->keyinfo+inx,info->lastkey,key_buff));
+ if (search_flag == HA_READ_AFTER_KEY)
+ info->update|=HA_STATE_NEXT_FOUND; /* Previous gives last row */
+err:
+ DBUG_RETURN(-1);
+} /* nisam_rkey */
diff --git a/isam/rlast.c b/isam/rlast.c
new file mode 100644
index 00000000000..df2b1bc39af
--- /dev/null
+++ b/isam/rlast.c
@@ -0,0 +1,34 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* L{ser sista posten som har samma isam-nyckel */
+
+#include "isamdef.h"
+
+ /*
+ L{ser sista posten med samma isamnyckel som f|reg}ende l{sning.
+ Man kan ha gjort write, update eller delete p} f|reg}ende post.
+ OBS! [ven om man {ndrade isamnyckeln p} f|reg}ende post l{ses
+ posten i avseende p} f|reg}ende isam-nyckel-l{sning !!
+ */
+
+int nisam_rlast(N_INFO *info, byte *buf, int inx)
+{
+ DBUG_ENTER("nisam_rlast");
+ info->lastpos= NI_POS_ERROR;
+ info->update|= HA_STATE_NEXT_FOUND;
+ DBUG_RETURN(nisam_rprev(info,buf,inx));
+} /* nisam_rlast */
diff --git a/isam/rnext.c b/isam/rnext.c
new file mode 100644
index 00000000000..ebe00fc2fa1
--- /dev/null
+++ b/isam/rnext.c
@@ -0,0 +1,66 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* L{ser n{sta post med samma isam-nyckel */
+
+#include "isamdef.h"
+
+ /*
+ L{ser n{sta post med samma isamnyckel som f|reg}ende l{sning.
+ Man kan ha gjort write, update eller delete p} f|reg}ende post.
+ OBS! [ven om man {ndrade isamnyckeln p} f|reg}ende post l{ses
+ posten i avseende p} f|reg}ende isam-nyckel-l{sning !!
+ */
+
+int nisam_rnext(N_INFO *info, byte *buf, int inx)
+{
+ int error;
+ uint flag;
+ DBUG_ENTER("nisam_rnext");
+
+ if ((inx = _nisam_check_index(info,inx)) < 0)
+ DBUG_RETURN(-1);
+ flag=SEARCH_BIGGER; /* Read next */
+ if (info->lastpos == NI_POS_ERROR && info->update & HA_STATE_PREV_FOUND)
+ flag=0; /* Read first */
+
+#ifndef NO_LOCKING
+ if (_nisam_readinfo(info,F_RDLCK,1)) DBUG_RETURN(-1);
+#endif
+ if (!flag)
+ error=_nisam_search_first(info,info->s->keyinfo+inx,
+ info->s->state.key_root[inx]);
+ else if (_nisam_test_if_changed(info) == 0)
+ error=_nisam_search_next(info,info->s->keyinfo+inx,info->lastkey,flag,
+ info->s->state.key_root[inx]);
+ else
+ error=_nisam_search(info,info->s->keyinfo+inx,info->lastkey,0,flag,
+ info->s->state.key_root[inx]);
+
+ /* Don't clear if database-changed */
+ info->update&= (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED |
+ HA_STATE_BUFF_SAVED);
+ info->update|= HA_STATE_NEXT_FOUND;
+
+ if (error && my_errno == HA_ERR_KEY_NOT_FOUND)
+ my_errno=HA_ERR_END_OF_FILE;
+ if ((*info->read_record)(info,info->lastpos,buf) >=0)
+ {
+ info->update|= HA_STATE_AKTIV; /* Record is read */
+ DBUG_RETURN(0);
+ }
+ DBUG_RETURN(-1);
+} /* nisam_rnext */
diff --git a/isam/rprev.c b/isam/rprev.c
new file mode 100644
index 00000000000..18b1e31502c
--- /dev/null
+++ b/isam/rprev.c
@@ -0,0 +1,63 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* L{ser f|reg}ende post med samma isam-nyckel */
+
+#include "isamdef.h"
+
+ /*
+ L{ser f|reg}ende post med samma isamnyckel som f|reg}ende l{sning.
+ Man kan ha gjort write, update eller delete p} f|reg}ende post.
+ OBS! [ven om man {ndrade isamnyckeln p} f|reg}ende post l{ses
+ posten i avseende p} f|reg}ende isam-nyckel-l{sning !!
+ */
+
+int nisam_rprev(N_INFO *info, byte *buf, int inx)
+{
+ int error;
+ register uint flag;
+ DBUG_ENTER("nisam_rprev");
+
+ if ((inx = _nisam_check_index(info,inx)) < 0)
+ DBUG_RETURN(-1);
+ flag=SEARCH_SMALLER; /* Read previous */
+ if (info->lastpos == NI_POS_ERROR && info->update & HA_STATE_NEXT_FOUND)
+ flag=0; /* Read last */
+
+#ifndef NO_LOCKING
+ if (_nisam_readinfo(info,F_RDLCK,1)) DBUG_RETURN(-1);
+#endif
+ if (!flag)
+ error=_nisam_search_last(info,info->s->keyinfo+inx,info->s->state.key_root[inx]);
+ else if (_nisam_test_if_changed(info) == 0)
+ error=_nisam_search_next(info,info->s->keyinfo+inx,info->lastkey,flag,
+ info->s->state.key_root[inx]);
+ else
+ error=_nisam_search(info,info->s->keyinfo+inx,info->lastkey,0,flag,
+ info->s->state.key_root[inx]);
+
+ info->update&= (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED |
+ HA_STATE_BUFF_SAVED);
+ info->update|= HA_STATE_PREV_FOUND;
+ if (error && my_errno == HA_ERR_KEY_NOT_FOUND)
+ my_errno=HA_ERR_END_OF_FILE;
+ if ((*info->read_record)(info,info->lastpos,buf) >=0)
+ {
+ info->update|= HA_STATE_AKTIV; /* Record is read */
+ DBUG_RETURN(0);
+ }
+ DBUG_RETURN(-1);
+} /* nisam_rprev */
diff --git a/isam/rrnd.c b/isam/rrnd.c
new file mode 100644
index 00000000000..7fd197a6d58
--- /dev/null
+++ b/isam/rrnd.c
@@ -0,0 +1,55 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* Read a record with random-access. The position to the record must
+ get by N_INFO. The next record can be read with pos= -1 */
+
+
+#include "isamdef.h"
+
+/*
+ If filepos == NI_POS_ERROR, read next
+ Returns:
+ 0 = Ok.
+ 1 = Row was deleted
+ -1 = EOF (check errno to verify)
+*/
+
+int nisam_rrnd(N_INFO *info, byte *buf, register ulong filepos)
+{
+ int skipp_deleted_blocks;
+ DBUG_ENTER("nisam_rrnd");
+
+ skipp_deleted_blocks=0;
+
+ if (filepos == NI_POS_ERROR)
+ {
+ skipp_deleted_blocks=1;
+ if (info->lastpos == NI_POS_ERROR) /* First read ? */
+ filepos= info->s->pack.header_length; /* Read first record */
+ else
+ filepos= info->nextpos;
+ }
+
+ info->lastinx= -1; /* Can't forward or backward */
+ /* Init all but update-flag */
+ info->update&= (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
+
+ if (info->opt_flag & WRITE_CACHE_USED && flush_io_cache(&info->rec_cache))
+ DBUG_RETURN(my_errno);
+
+ DBUG_RETURN ((*info->s->read_rnd)(info,buf,filepos,skipp_deleted_blocks));
+}
diff --git a/isam/rsame.c b/isam/rsame.c
new file mode 100644
index 00000000000..fe617cf258c
--- /dev/null
+++ b/isam/rsame.c
@@ -0,0 +1,70 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* L{ser nuvarande record med direktl{sning */
+/* Klarar b}de poster l{sta med nyckel och rrnd. */
+
+#include "isamdef.h"
+
+ /* Funktionen ger som resultat:
+ 0 = Ok.
+ 1 = Posten borttagen
+ -1 = EOF (eller motsvarande: se errno) */
+
+
+int nisam_rsame(N_INFO *info, byte *record, int inx)
+
+
+ /* If inx >= 0 find record using key */
+{
+ DBUG_ENTER("nisam_rsame");
+
+ if (inx >= (int) info->s->state.keys || inx < -1)
+ {
+ my_errno=HA_ERR_WRONG_INDEX;
+ DBUG_RETURN(-1);
+ }
+ if (info->lastpos == NI_POS_ERROR || info->update & HA_STATE_DELETED)
+ {
+ my_errno=HA_ERR_KEY_NOT_FOUND; /* No current record */
+ DBUG_RETURN(-1);
+ }
+ info->update&= (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
+
+ /* L{s record fr}n datafilen */
+
+#ifndef NO_LOCKING
+ if (_nisam_readinfo(info,F_RDLCK,1))
+ DBUG_RETURN(-1);
+#endif
+
+ if (inx >= 0)
+ {
+ info->lastinx=inx;
+ VOID(_nisam_make_key(info,(uint) inx,info->lastkey,record,info->lastpos));
+ VOID(_nisam_search(info,info->s->keyinfo+inx,info->lastkey,0,SEARCH_SAME,
+ info->s->state.key_root[inx]));
+ }
+
+ if ((*info->read_record)(info,info->lastpos,record) == 0)
+ DBUG_RETURN(0);
+ if (my_errno == HA_ERR_RECORD_DELETED)
+ {
+ my_errno=HA_ERR_KEY_NOT_FOUND;
+ DBUG_RETURN(1);
+ }
+ DBUG_RETURN(-1);
+} /* nisam_rsame */
diff --git a/isam/rsamepos.c b/isam/rsamepos.c
new file mode 100644
index 00000000000..500dfc60e38
--- /dev/null
+++ b/isam/rsamepos.c
@@ -0,0 +1,59 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* read record through position and fix key-position */
+/* As nisam_rsame but supply a position */
+
+#include "isamdef.h"
+
+
+ /*
+ ** If inx >= 0 update index pointer
+ ** Returns one of the following values:
+ ** 0 = Ok.
+ ** 1 = Record deleted
+ ** -1 = EOF (or something similar. More information in my_errno)
+ */
+
+int nisam_rsame_with_pos(N_INFO *info, byte *record, int inx, ulong filepos)
+{
+ DBUG_ENTER("nisam_rsame_with_pos");
+
+ if (inx >= (int) info->s->state.keys || inx < -1)
+ {
+ my_errno=HA_ERR_WRONG_INDEX;
+ DBUG_RETURN(-1);
+ }
+
+ info->update&= (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
+ if ((*info->s->read_rnd)(info,record,filepos,0))
+ {
+ if (my_errno == HA_ERR_RECORD_DELETED)
+ {
+ my_errno=HA_ERR_KEY_NOT_FOUND;
+ DBUG_RETURN(1);
+ }
+ DBUG_RETURN(-1);
+ }
+ info->lastpos=filepos;
+ info->lastinx=inx;
+ if (inx >= 0)
+ {
+ VOID(_nisam_make_key(info,(uint) inx,info->lastkey,record,info->lastpos));
+ info->update|=HA_STATE_KEY_CHANGED; /* Don't use indexposition */
+ }
+ DBUG_RETURN(0);
+} /* nisam_rsame_pos */
diff --git a/isam/sort.c b/isam/sort.c
new file mode 100644
index 00000000000..72c4c7564f8
--- /dev/null
+++ b/isam/sort.c
@@ -0,0 +1,558 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/*
+ Creates a index for a database by reading keys, sorting them and outputing
+ them in sorted order through SORT_INFO functions.
+*/
+
+#include "isamdef.h"
+#if defined(MSDOS) || defined(__WIN__)
+#include <fcntl.h>
+#else
+#include <stddef.h>
+#endif
+#include <queues.h>
+
+ /* static variabels */
+
+#define MERGEBUFF 15
+#define MERGEBUFF2 31
+#define MIN_SORT_MEMORY (4096-MALLOC_OVERHEAD)
+#define MYF_RW MYF(MY_NABP | MY_WME | MY_WAIT_IF_FULL)
+
+typedef struct st_buffpek { /* Struktur om sorteringsbuffrarna */
+ my_off_t file_pos; /* Position var bufferten finns */
+ ulong count; /* Antal nycklar i bufferten */
+ uchar *base,*key; /* Pekare inom sort_key - indexdel */
+ uint mem_count; /* Antal nycklar kvar i minnet */
+ uint max_keys; /* Max keys in buffert */
+} BUFFPEK;
+
+extern void print_error _VARARGS((const char *fmt,...));
+
+ /* functions defined in this file */
+
+static ulong NEAR_F find_all_keys(SORT_PARAM *info,uint keys,
+ uchar * *sort_keys,
+ BUFFPEK *buffpek,int *maxbuffer,
+ FILE **tempfile, my_string tempname);
+static int NEAR_F write_keys(SORT_PARAM *info,uchar * *sort_keys,
+ uint count, BUFFPEK *buffpek,FILE **tempfile,
+ my_string tempname);
+static int NEAR_F write_index(SORT_PARAM *info,uchar * *sort_keys,
+ uint count);
+static int NEAR_F merge_many_buff(SORT_PARAM *info,uint keys,
+ uchar * *sort_keys,
+ BUFFPEK *buffpek,int *maxbuffer,
+ FILE * *t_file, my_string tempname);
+static uint NEAR_F read_to_buffer(FILE *fromfile,BUFFPEK *buffpek,
+ uint sort_length);
+static int NEAR_F merge_buffers(SORT_PARAM *info,uint keys,FILE *from_file,
+ FILE *to_file, uchar * *sort_keys,
+ BUFFPEK *lastbuff,BUFFPEK *Fb,
+ BUFFPEK *Tb);
+static int NEAR_F merge_index(SORT_PARAM *,uint,uchar **,BUFFPEK *, int,
+ FILE *);
+static char **make_char_array(uint fields,uint length,myf my_flag);
+static FILE *opentemp(my_string name);
+static void closetemp(char *name,FILE *stream);
+
+
+ /* Creates a index of sorted keys */
+ /* Returns 0 if everything went ok */
+
+int _create_index_by_sort(info,no_messages,sortbuff_size)
+SORT_PARAM *info;
+pbool no_messages;
+uint sortbuff_size;
+{
+ int error,maxbuffer,skr;
+ uint memavl,old_memavl,keys,sort_length;
+ BUFFPEK *buffpek;
+ char tempname[FN_REFLEN];
+ ulong records;
+ uchar **sort_keys;
+ FILE *tempfile;
+ DBUG_ENTER("_create_index_by_sort");
+
+ tempfile=0; buffpek= (BUFFPEK *) NULL; sort_keys= (uchar **) NULL; error= 1;
+ maxbuffer=1;
+
+ memavl=max(sortbuff_size,MIN_SORT_MEMORY);
+ records= info->max_records;
+ sort_length= info->key_length;
+ LINT_INIT(keys);
+
+ while (memavl >= MIN_SORT_MEMORY)
+ {
+ if ((records+1)*(sort_length+sizeof(char*)) < (ulong) memavl)
+ keys= records+1;
+ else
+ do
+ {
+ skr=maxbuffer;
+ if (memavl < sizeof(BUFFPEK)*(uint) maxbuffer ||
+ (keys=(memavl-sizeof(BUFFPEK)*(uint) maxbuffer)/
+ (sort_length+sizeof(char*))) <= 1)
+ {
+ print_error("Sortbuffer to small");
+ goto err;
+ }
+ }
+ while ((maxbuffer= (int) (records/(keys-1)+1)) != skr);
+
+ if ((sort_keys= (uchar **) make_char_array(keys,sort_length,MYF(0))))
+ {
+ if ((buffpek = (BUFFPEK*) my_malloc((uint) (sizeof(BUFFPEK)*
+ (uint) maxbuffer),
+ MYF(0))))
+ break;
+ else
+ my_free((gptr) sort_keys,MYF(0));
+ }
+ old_memavl=memavl;
+ if ((memavl=memavl/4*3) < MIN_SORT_MEMORY && old_memavl > MIN_SORT_MEMORY)
+ memavl=MIN_SORT_MEMORY;
+ }
+ if (memavl < MIN_SORT_MEMORY)
+ {
+ print_error("Sortbuffer to small");
+ goto err;
+ }
+ (*info->lock_in_memory)(); /* Everything is allocated */
+
+ if (!no_messages)
+ printf(" - Searching for keys, allocating buffer for %d keys\n",keys);
+
+ if ((records=find_all_keys(info,keys,sort_keys,buffpek,&maxbuffer,&tempfile,
+ tempname))
+ == (ulong) -1)
+ goto err;
+ if (maxbuffer == 0)
+ {
+ if (!no_messages)
+ printf(" - Dumping %lu keys\n",records);
+ if (write_index(info,sort_keys,(uint) records))
+ goto err;
+ }
+ else
+ {
+ keys=(keys*(sort_length+sizeof(char*)))/sort_length;
+ if (maxbuffer >= MERGEBUFF2)
+ {
+ if (!no_messages)
+ printf(" - Merging %lu keys\n",records);
+ if (merge_many_buff(info,keys,sort_keys,buffpek,&maxbuffer,&tempfile,
+ tempname))
+ goto err;
+ }
+ if (!no_messages)
+ puts(" - Last merge and dumping keys");
+ if (merge_index(info,keys,sort_keys,buffpek,maxbuffer,tempfile))
+ goto err;
+ }
+ error =0;
+
+err:
+ if (sort_keys)
+ my_free((gptr) sort_keys,MYF(0));
+ if (buffpek)
+ my_free((gptr) buffpek,MYF(0));
+ if (tempfile)
+ closetemp(tempname,tempfile);
+
+ DBUG_RETURN(error ? -1 : 0);
+} /* _create_index_by_sort */
+
+
+ /* Search after all keys and place them in a temp. file */
+
+static ulong NEAR_F find_all_keys(info,keys,sort_keys,buffpek,maxbuffer,
+ tempfile,tempname)
+SORT_PARAM *info;
+uint keys;
+uchar **sort_keys;
+BUFFPEK *buffpek;
+int *maxbuffer;
+FILE **tempfile;
+my_string tempname;
+{
+ int error;
+ uint index,indexpos;
+ DBUG_ENTER("find_all_keys");
+
+ index=indexpos=error=0;
+
+ while (!(error=(*info->key_read)(sort_keys[index])))
+ {
+ if ((uint) ++index == keys)
+ {
+ if (indexpos >= (uint) *maxbuffer ||
+ write_keys(info,sort_keys,index-1,buffpek+indexpos,tempfile,
+ tempname))
+ DBUG_RETURN(NI_POS_ERROR);
+ memcpy(sort_keys[0],sort_keys[index-1],(size_t) info->key_length);
+ index=1; indexpos++;
+ }
+ }
+ if (error > 0)
+ DBUG_RETURN(NI_POS_ERROR); /* Aborted by get_key */
+ if (indexpos)
+ if (indexpos >= (uint) *maxbuffer ||
+ write_keys(info,sort_keys,index,buffpek+indexpos,tempfile,tempname))
+ DBUG_RETURN(NI_POS_ERROR);
+ *maxbuffer=(int) indexpos;
+ DBUG_RETURN(indexpos*(keys-1)+index);
+} /* find_all_keys */
+
+
+ /* Write all keys in memory to file for later merge */
+
+static int NEAR_F write_keys(info,sort_keys,count,buffpek,tempfile,tempname)
+SORT_PARAM *info;
+reg1 uchar **sort_keys;
+uint count;
+BUFFPEK *buffpek;
+reg2 FILE **tempfile;
+my_string tempname;
+{
+ DBUG_ENTER("write_keys");
+
+ qsort2((byte*) sort_keys,count,sizeof(byte*),(qsort2_cmp) info->key_cmp,
+ NullS);
+ if (! *tempfile && ! (*tempfile=opentemp(tempname)))
+ DBUG_RETURN(1);
+ buffpek->file_pos=my_ftell(*tempfile,MYF(0));
+ buffpek->count=count;
+ while (count--)
+ if (my_fwrite(*tempfile,(byte*)*sort_keys++,info->key_length,MYF_RW))
+ DBUG_RETURN(1);
+ DBUG_RETURN(0);
+} /* write_keys */
+
+
+ /* Write index */
+
+static int NEAR_F write_index(info,sort_keys,count)
+SORT_PARAM *info;
+reg1 uchar **sort_keys;
+reg2 uint count;
+{
+ DBUG_ENTER("write_index");
+
+ qsort2((gptr) sort_keys,(size_t) count,sizeof(byte*),
+ (qsort2_cmp) info->key_cmp, NullS);
+ while (count--)
+ if ((*info->key_write)(*sort_keys++))
+ DBUG_RETURN(-1);
+ DBUG_RETURN(0);
+} /* write_index */
+
+
+ /* Merge buffers to make < MERGEBUFF2 buffers */
+
+static int NEAR_F merge_many_buff(info,keys,sort_keys,buffpek,maxbuffer,t_file,
+ t_name)
+SORT_PARAM *info;
+uint keys;
+uchar **sort_keys;
+int *maxbuffer;
+BUFFPEK *buffpek;
+FILE **t_file;
+my_string t_name;
+{
+ register int i;
+ FILE *from_file,*to_file,*temp;
+ FILE *t_file2;
+ char t_name2[FN_REFLEN];
+ BUFFPEK *lastbuff;
+ DBUG_ENTER("merge_many_buff");
+
+ if (!(t_file2=opentemp(t_name2)))
+ DBUG_RETURN(1);
+
+ from_file= *t_file ; to_file= t_file2;
+ while (*maxbuffer >= MERGEBUFF2)
+ {
+ lastbuff=buffpek;
+ for (i=0 ; i <= *maxbuffer-MERGEBUFF*3/2 ; i+=MERGEBUFF)
+ {
+ if (merge_buffers(info,keys,from_file,to_file,sort_keys,lastbuff++,
+ buffpek+i,buffpek+i+MERGEBUFF-1))
+ break;
+ }
+ if (merge_buffers(info,keys,from_file,to_file,sort_keys,lastbuff++,
+ buffpek+i,buffpek+ *maxbuffer))
+ break;
+ *maxbuffer= (int) (lastbuff-buffpek)-1;
+ temp=from_file; from_file=to_file; to_file=temp;
+ VOID(my_fseek(to_file,0L,MY_SEEK_SET,MYF(0)));
+ }
+ if (to_file == *t_file)
+ {
+ closetemp(t_name,to_file);
+ *t_file=t_file2;
+ VOID(strmov(t_name,t_name2));
+ }
+ else closetemp(t_name2,to_file);
+
+ DBUG_RETURN(*maxbuffer >= MERGEBUFF2); /* Return 1 if interrupted */
+} /* merge_many_buff */
+
+
+ /* Read data to buffer */
+ /* This returns (uint) -1 if something goes wrong */
+
+static uint NEAR_F read_to_buffer(fromfile,buffpek,sort_length)
+FILE *fromfile;
+BUFFPEK *buffpek;
+uint sort_length;
+{
+ register uint count;
+ uint length;
+
+ if ((count=(uint) min((ulong) buffpek->max_keys,buffpek->count)))
+ {
+ VOID(my_fseek(fromfile,buffpek->file_pos,MY_SEEK_SET,MYF(0)));
+ if (my_fread(fromfile,(byte*) buffpek->base,
+ (length= sort_length*count),MYF_RW))
+ return((uint) -1);
+ buffpek->key=buffpek->base;
+ buffpek->file_pos+= length; /* New filepos */
+ buffpek->count-= count;
+ buffpek->mem_count= count;
+ }
+ return (count*sort_length);
+} /* read_to_buffer */
+
+
+ /* Merge buffers to one buffer */
+ /* If to_file == 0 then use info->key_write */
+
+static int NEAR_F merge_buffers(info,keys,from_file,to_file,sort_keys,lastbuff,
+ Fb,Tb)
+SORT_PARAM *info;
+uint keys;
+FILE *from_file,*to_file;
+uchar **sort_keys;
+BUFFPEK *lastbuff,*Fb,*Tb;
+{
+ int error;
+ uint sort_length,maxcount;
+ ulong count;
+ my_off_t to_start_filepos;
+ uchar *strpos;
+ BUFFPEK *buffpek,**refpek;
+ QUEUE queue;
+ DBUG_ENTER("merge_buffers");
+
+ count=error=0;
+ maxcount=keys/((uint) (Tb-Fb) +1);
+ sort_length=info->key_length;
+
+ LINT_INIT(to_start_filepos);
+ if (to_file)
+ to_start_filepos=my_ftell(to_file,MYF(0));
+ strpos=(uchar*) sort_keys;
+
+ if (init_queue(&queue,(uint) (Tb-Fb)+1,offsetof(BUFFPEK,key),0,
+ (int (*)(void *, byte *,byte *)) info->key_cmp,0))
+ DBUG_RETURN(1);
+
+ for (buffpek= Fb ; buffpek <= Tb && error != -1 ; buffpek++)
+ {
+ count+= buffpek->count;
+ buffpek->base= strpos;
+ buffpek->max_keys=maxcount;
+ strpos+= (uint) (error=(int) read_to_buffer(from_file,buffpek,
+ sort_length));
+ queue_insert(&queue,(void*) buffpek);
+ }
+ if (error == -1)
+ goto err;
+
+ while (queue.elements > 1)
+ {
+ for (;;)
+ {
+ buffpek=(BUFFPEK*) queue_top(&queue);
+ if (to_file)
+ {
+ if (my_fwrite(to_file,(byte*) buffpek->key,(uint) sort_length,
+ MYF_RW | MY_WAIT_IF_FULL))
+ {
+ error=1; goto err;
+ }
+ }
+ else
+ {
+ if ((*info->key_write)((void*) buffpek->key))
+ {
+ error=1; goto err;
+ }
+ }
+ buffpek->key+=sort_length;
+ if (! --buffpek->mem_count)
+ {
+ if (!(error=(int) read_to_buffer(from_file,buffpek,sort_length)))
+ {
+ uchar *base=buffpek->base;
+ uint max_keys=buffpek->max_keys;
+
+ VOID(queue_remove(&queue,0));
+
+ /* Put room used by buffer to use in other buffer */
+ for (refpek= (BUFFPEK**) &queue_top(&queue);
+ refpek <= (BUFFPEK**) &queue_end(&queue);
+ refpek++)
+ {
+ buffpek= *refpek;
+ if (buffpek->base+buffpek->max_keys*sort_length == base)
+ {
+ buffpek->max_keys+=max_keys;
+ break;
+ }
+ else if (base+max_keys*sort_length == buffpek->base)
+ {
+ buffpek->base=base;
+ buffpek->max_keys+=max_keys;
+ break;
+ }
+ }
+ break; /* One buffer have been removed */
+ }
+ }
+ queue_replaced(&queue); /* Top element has been replaced */
+ }
+ }
+ buffpek=(BUFFPEK*) queue_top(&queue);
+ buffpek->base=(uchar *) sort_keys;
+ buffpek->max_keys=keys;
+ do
+ {
+ if (to_file)
+ {
+ if (my_fwrite(to_file,(byte*) buffpek->key,
+ (uint) (sort_length*buffpek->mem_count),
+ MYF_RW | MY_WAIT_IF_FULL))
+ {
+ error=1; goto err;
+ }
+ }
+ else
+ {
+ register uchar *end;
+ strpos= buffpek->key;
+ for (end=strpos+buffpek->mem_count*sort_length;
+ strpos != end ;
+ strpos+=sort_length)
+ {
+ if ((*info->key_write)((void*) strpos))
+ {
+ error=1; goto err;
+ }
+ }
+ }
+ }
+ while ((error=(int) read_to_buffer(from_file,buffpek,sort_length)) != -1 &&
+ error != 0);
+
+ lastbuff->count=count;
+ if (to_file)
+ lastbuff->file_pos=to_start_filepos; /* New block starts here */
+err:
+ delete_queue(&queue);
+ DBUG_RETURN(error);
+} /* merge_buffers */
+
+
+ /* Do a merge to output-file (save only positions) */
+
+static int NEAR_F merge_index(info,keys,sort_keys,buffpek,maxbuffer,tempfile)
+SORT_PARAM *info;
+uint keys;
+uchar **sort_keys;
+BUFFPEK *buffpek;
+int maxbuffer;
+FILE *tempfile;
+{
+ DBUG_ENTER("merge_index");
+ if (merge_buffers(info,keys,tempfile,(FILE*) 0,sort_keys,buffpek,buffpek,
+ buffpek+maxbuffer))
+ DBUG_RETURN(1);
+ DBUG_RETURN(0);
+} /* merge_index */
+
+
+ /* Make a pointer of arrays to keys */
+
+static char **make_char_array(fields,length,my_flag)
+register uint fields;
+uint length;
+myf my_flag;
+{
+ register char **pos;
+ char **old_pos,*char_pos;
+ DBUG_ENTER("make_char_array");
+
+ if ((old_pos= (char**) my_malloc( fields*(length+sizeof(char*)), my_flag)))
+ {
+ pos=old_pos; char_pos=((char*) (pos+fields)) -length;
+ while (fields--)
+ *(pos++) = (char_pos+= length);
+ }
+
+ DBUG_RETURN(old_pos);
+} /* make_char_array */
+
+
+ /* |ppnar en tempor{rfil som kommer att raderas efter anv{nding */
+
+static FILE *opentemp(name)
+my_string name;
+{
+ FILE *stream;
+ reg1 my_string str_pos;
+ DBUG_ENTER("opentemp");
+
+ if (!(str_pos=my_tempnam(NullS,"ST",MYF(MY_WME))))
+ DBUG_RETURN(0);
+ VOID(strmov(name,str_pos));
+ (*free)(str_pos); /* Inte via vanliga malloc */
+
+ stream=my_fopen(name,(int) (O_RDWR | FILE_BINARY | O_CREAT | O_TEMPORARY),
+ MYF(MY_WME));
+#if O_TEMPORARY == 0 && !defined(CANT_DELETE_OPEN_FILES)
+ VOID(my_delete(name,MYF(MY_WME | ME_NOINPUT)));
+#endif
+ DBUG_PRINT("exit",("stream: %lx",stream));
+ DBUG_RETURN (stream);
+} /* opentemp */
+
+
+static void closetemp(char *name __attribute__((unused)) ,FILE *stream)
+{
+ DBUG_ENTER("closetemp");
+
+ if (stream)
+ VOID(my_fclose(stream,MYF(MY_WME)));
+#ifdef CANT_DELETE_OPEN_FILES
+ if (name)
+ VOID(my_delete(name,MYF(MY_WME)));
+#endif
+ DBUG_VOID_RETURN;
+} /* closetemp */
diff --git a/isam/static.c b/isam/static.c
new file mode 100644
index 00000000000..941c4defea2
--- /dev/null
+++ b/isam/static.c
@@ -0,0 +1,45 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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
+ a shared library
+*/
+
+#ifndef _global_h
+#include "isamdef.h"
+#endif
+
+LIST *nisam_open_list=0;
+uchar NEAR nisam_file_magic[]=
+{ (uchar) 254, (uchar) 254,'\005', '\002', };
+uchar NEAR nisam_pack_file_magic[]=
+{ (uchar) 254, (uchar) 254,'\006', '\001', };
+my_string nisam_log_filename= (char*) "isam.log";
+File nisam_log_file= -1;
+uint nisam_quick_table_bits=9;
+uint nisam_block_size=1024; /* Best by test */
+my_bool nisam_flush=0;
+
+/* read_vec[] is used for converting between P_READ_KEY.. and SEARCH_ */
+/* Position is , == , >= , <= , > , < */
+
+uint NEAR nisam_read_vec[]=
+{
+ SEARCH_FIND, SEARCH_FIND | SEARCH_BIGGER, SEARCH_FIND | SEARCH_SMALLER,
+ SEARCH_NO_FIND | SEARCH_BIGGER, SEARCH_NO_FIND | SEARCH_SMALLER,
+ SEARCH_FIND, SEARCH_LAST
+};
diff --git a/isam/test1.c b/isam/test1.c
new file mode 100644
index 00000000000..1ec5d8b0318
--- /dev/null
+++ b/isam/test1.c
@@ -0,0 +1,183 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include "isamdef.h"
+
+static void get_options(int argc, char *argv[]);
+
+static int rec_pointer_size=0,verbose=0,remove_ant=0,pack_keys=1,flags[50],
+ packed_field=FIELD_SKIPP_PRESPACE;
+
+int main(argc,argv)
+int argc;
+char *argv[];
+{
+ N_INFO *file;
+ int i,j,error,deleted,found;
+ char record[128],key[32],*filename,read_record[128];
+ N_KEYDEF keyinfo[10];
+ N_RECINFO recinfo[10];
+ MY_INIT(argv[0]);
+
+ filename= (char*) "test1";
+ my_init();
+ get_options(argc,argv);
+ keyinfo[0].seg[0].base.type=HA_KEYTYPE_NUM;
+ keyinfo[0].seg[0].base.flag=(uint8) (pack_keys ?
+ HA_PACK_KEY | HA_SPACE_PACK : 0);
+ keyinfo[0].seg[0].base.start=0;
+ keyinfo[0].seg[0].base.length=6;
+ keyinfo[0].seg[1].base.type=HA_KEYTYPE_END;
+ keyinfo[0].base.flag = (uint8) (pack_keys ?
+ HA_NOSAME | HA_PACK_KEY : HA_NOSAME);
+
+ recinfo[0].base.type=packed_field; recinfo[0].base.length=6;
+ recinfo[1].base.type=FIELD_NORMAL; recinfo[1].base.length=24;
+ recinfo[2].base.type=FIELD_LAST;
+
+ deleted=0;
+ bzero((byte*) flags,sizeof(flags));
+
+ printf("- Creating isam-file\n");
+ if (nisam_create(filename,1,keyinfo,recinfo,
+ (ulong) (rec_pointer_size ? (1L << (rec_pointer_size*8))/40 :
+ 0),10l,0,0,0L))
+ goto err;
+ if (!(file=nisam_open(filename,2,HA_OPEN_ABORT_IF_LOCKED)))
+ goto err;
+ printf("- Writing key:s\n");
+ strmov(record," ..... key"); strappend(record,30,' ');
+
+ my_errno=0;
+ for (i=49 ; i>=1 ; i-=2 )
+ {
+ j=i%25 +1;
+ sprintf(key,"%6d",j);
+ bmove(record,key,6);
+ error=nisam_write(file,record);
+ flags[j]=1;
+ if (verbose || error)
+ printf("J= %2d nisam_write: %d errno: %d\n", j,error,my_errno);
+ }
+ if (nisam_close(file)) goto err;
+ printf("- Reopening file\n");
+ if (!(file=nisam_open(filename,2,HA_OPEN_ABORT_IF_LOCKED))) goto err;
+ printf("- Removing keys\n");
+ for (i=1 ; i<=10 ; i++)
+ {
+ if (i == remove_ant) { VOID(nisam_close(file)) ; exit(0) ; }
+ sprintf(key,"%6d",(j=(int) ((rand() & 32767)/32767.*25)));
+ my_errno=0;
+ if ((error = nisam_rkey(file,read_record,0,key,0,HA_READ_KEY_EXACT)))
+ {
+ if (verbose || (flags[j] == 1 ||
+ (error && my_errno != HA_ERR_KEY_NOT_FOUND)))
+ printf("key: %s nisam_rkey: %3d errno: %3d\n",key,error,my_errno);
+ }
+ else
+ {
+ error=nisam_delete(file,read_record);
+ if (verbose || error)
+ printf("key: %s nisam_delete: %3d errno: %3d\n",key,error,my_errno);
+ flags[j]=0;
+ if (! error)
+ deleted++;
+ }
+ }
+ printf("- Reading records with key\n");
+ for (i=1 ; i<=25 ; i++)
+ {
+ sprintf(key,"%6d",i);
+ bmove(record,key,6);
+ my_errno=0;
+ error=nisam_rkey(file,read_record,0,key,0,HA_READ_KEY_EXACT);
+ if (verbose ||
+ (error == 0 && flags[i] != 1) ||
+ (error && (flags[i] != 0 || my_errno != HA_ERR_KEY_NOT_FOUND)))
+ {
+ printf("key: %s nisam_rkey: %3d errno: %3d record: %s\n",
+ key,error,my_errno,record+1);
+ }
+ }
+
+ printf("- Reading records with position\n");
+ for (i=1,found=0 ; i <= 30 ; i++)
+ {
+ my_errno=0;
+ if ((error=nisam_rrnd(file,read_record,i == 1 ? 0L : NI_POS_ERROR)) == -1)
+ {
+ if (found != 25-deleted)
+ printf("Found only %d of %d records\n",found,25-deleted);
+ break;
+ }
+ if (!error)
+ found++;
+ if (verbose || (error != 0 && error != 1))
+ {
+ printf("pos: %2d nisam_rrnd: %3d errno: %3d record: %s\n",
+ i-1,error,my_errno,read_record+1);
+ }
+ }
+ if (nisam_close(file)) goto err;
+ my_end(MY_CHECK_ERROR);
+
+ exit(0);
+err:
+ printf("got error: %3d when using nisam-database\n",my_errno);
+ exit(1);
+ return 0; /* skipp warning */
+} /* main */
+
+
+ /* l{ser optioner */
+ /* OBS! intierar endast DEBUG - ingen debuggning h{r ! */
+
+static void get_options(argc,argv)
+int argc;
+char *argv[];
+{
+ char *pos;
+
+ while (--argc >0 && *(pos = *(++argv)) == '-' ) {
+ switch(*++pos) {
+ case 'R': /* Length of record pointer */
+ rec_pointer_size=atoi(++pos);
+ if (rec_pointer_size > 3)
+ rec_pointer_size=0;
+ break;
+ case 'P':
+ pack_keys=0; /* Don't use packed key */
+ break;
+ case 'S':
+ packed_field=FIELD_NORMAL; /* static-size record*/
+ break;
+ case 'v': /* verbose */
+ verbose=1;
+ break;
+ case 'm':
+ remove_ant=atoi(++pos);
+ break;
+ case 'V':
+ printf("isamtest1 Ver 1.0 \n");
+ exit(0);
+ case '#':
+ DEBUGGER_ON;
+ DBUG_PUSH (++pos);
+ break;
+ }
+ }
+ return;
+} /* get options */
diff --git a/isam/test2.c b/isam/test2.c
new file mode 100644
index 00000000000..6ed041ad8c5
--- /dev/null
+++ b/isam/test2.c
@@ -0,0 +1,852 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* Test av isam-databas: stor test */
+
+#ifndef USE_MY_FUNC /* We want to be able to dbug this !! */
+#define USE_MY_FUNC
+#endif
+#ifdef DBUG_OFF
+#undef DBUG_OFF
+#endif
+#ifndef SAFEMALLOC
+#define SAFEMALLOC
+#endif
+
+#include "isamdef.h"
+
+#define STANDAR_LENGTH 37
+#define NISAM_KEYS 6
+#if !defined(MSDOS) && !defined(labs)
+#define labs(a) abs(a)
+#endif
+
+static void get_options(int argc, char *argv[]);
+static uint rnd(uint max_value);
+static void fix_length(byte *record,uint length);
+static void put_blob_in_record(char *blob_pos,char **blob_buffer);
+static void copy_key(struct st_isam_info *info,uint inx,
+ uchar *record,uchar *key);
+
+static int verbose=0,testflag=0,pack_type=HA_SPACE_PACK,
+ first_key=0,async_io=0,key_cacheing=0,write_cacheing=0,locking=0,
+ rec_pointer_size=0,pack_fields=1,use_log=0;
+static uint keys=NISAM_KEYS,recant=1000;
+static uint use_blob=0;
+static uint16 key1[1000],key3[5000];
+static char record[300],record2[300],key[100],key2[100],
+ read_record[300],read_record2[300],read_record3[300];
+
+
+ /* Test program */
+
+int main(argc,argv)
+int argc;
+char *argv[];
+{
+ uint i;
+ int j,n1,n2,n3,error,k;
+ uint write_count,update,dupp_keys,delete,start,length,blob_pos,
+ reclength,ant;
+ ulong lastpos,range_records,records;
+ N_INFO *file;
+ N_KEYDEF keyinfo[10];
+ N_RECINFO recinfo[10];
+ N_ISAMINFO info;
+ char *filename,*blob_buffer;
+ MY_INIT(argv[0]);
+
+ filename= (char*) "test2.ISM";
+ get_options(argc,argv);
+ if (! async_io)
+ my_disable_async_io=1;
+
+ reclength=STANDAR_LENGTH+60+(use_blob ? 8 : 0);
+ blob_pos=STANDAR_LENGTH+60;
+ keyinfo[0].seg[0].base.start=0;
+ keyinfo[0].seg[0].base.length=6;
+ keyinfo[0].seg[0].base.type=HA_KEYTYPE_TEXT;
+ keyinfo[0].seg[0].base.flag=(uint8) pack_type;
+ keyinfo[0].seg[1].base.type=0;
+ keyinfo[0].base.flag = (uint8) (pack_type ? HA_PACK_KEY : 0);
+ keyinfo[1].seg[0].base.start=7;
+ keyinfo[1].seg[0].base.length=6;
+ keyinfo[1].seg[0].base.type=HA_KEYTYPE_BINARY;
+ keyinfo[1].seg[0].base.flag=0;
+ keyinfo[1].seg[1].base.start=0; /* Tv}delad nyckel */
+ keyinfo[1].seg[1].base.length=6;
+ keyinfo[1].seg[1].base.type=HA_KEYTYPE_NUM;
+ keyinfo[1].seg[1].base.flag=HA_REVERSE_SORT;
+ keyinfo[1].seg[2].base.type=0;
+ keyinfo[1].base.flag =0;
+ keyinfo[2].seg[0].base.start=12;
+ keyinfo[2].seg[0].base.length=8;
+ keyinfo[2].seg[0].base.type=HA_KEYTYPE_BINARY;
+ keyinfo[2].seg[0].base.flag=HA_REVERSE_SORT;
+ keyinfo[2].seg[1].base.type=0;
+ keyinfo[2].base.flag =HA_NOSAME;
+ keyinfo[3].seg[0].base.start=0;
+ keyinfo[3].seg[0].base.length=reclength-(use_blob ? 8 : 0);
+ keyinfo[3].seg[0].base.type=HA_KEYTYPE_TEXT;
+ keyinfo[3].seg[0].base.flag=(uint8) pack_type;
+ keyinfo[3].seg[1].base.type=0;
+ keyinfo[3].base.flag = (uint8) (pack_type ? HA_PACK_KEY : 0);
+ keyinfo[4].seg[0].base.start=0;
+ keyinfo[4].seg[0].base.length=5;
+ keyinfo[4].seg[0].base.type=HA_KEYTYPE_TEXT;
+ keyinfo[4].seg[0].base.flag=0;
+ keyinfo[4].seg[1].base.type=0;
+ keyinfo[4].base.flag = (uint8) (pack_type ? HA_PACK_KEY : 0);
+ keyinfo[5].seg[0].base.start=0;
+ keyinfo[5].seg[0].base.length=4;
+ keyinfo[5].seg[0].base.type=HA_KEYTYPE_TEXT;
+ keyinfo[5].seg[0].base.flag=(uint8) pack_type;
+ keyinfo[5].seg[1].base.type=0;
+ keyinfo[5].base.flag = (uint8) (pack_type ? HA_PACK_KEY : 0);
+
+ recinfo[0].base.type=pack_fields ? FIELD_SKIPP_PRESPACE : 0;
+ recinfo[0].base.length=7;
+ recinfo[1].base.type=pack_fields ? FIELD_SKIPP_PRESPACE : 0;
+ recinfo[1].base.length=5;
+ recinfo[2].base.type=pack_fields ? FIELD_SKIPP_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.length=4;
+ recinfo[5].base.type=pack_fields ? FIELD_SKIPP_ENDSPACE : 0;
+ recinfo[5].base.length=60;
+ if (use_blob)
+ {
+ recinfo[6].base.type=FIELD_BLOB;
+ recinfo[6].base.length=4+sizeof(char*); /* 4 byte ptr, 4 byte length */
+ recinfo[7].base.type= FIELD_LAST;
+ }
+ else
+ recinfo[6].base.type= FIELD_LAST;
+
+ write_count=update=dupp_keys=delete=0;
+ blob_buffer=0;
+
+ for (i=999 ; i>0 ; i--) key1[i]=0;
+ for (i=4999 ; i>0 ; i--) key3[i]=0;
+
+ printf("- Creating isam-file\n");
+ /* DBUG_PUSH(""); */
+ my_delete(filename,MYF(0)); /* Remove old locks under gdb */
+ file= 0;
+ if (nisam_create(filename,keys,&keyinfo[first_key],&recinfo[0],
+ (ulong) (rec_pointer_size ? (1L << (rec_pointer_size*8))/
+ reclength : 0),100l,0,0,0L))
+ goto err;
+ if (use_log)
+ nisam_log(1);
+ if (!(file=nisam_open(filename,2,HA_OPEN_ABORT_IF_LOCKED)))
+ goto err;
+ printf("- Writing key:s\n");
+ if (key_cacheing)
+ init_key_cache(IO_SIZE*16,(uint) IO_SIZE*4*10); /* Use a small cache */
+ if (locking)
+ nisam_lock_database(file,F_WRLCK);
+ if (write_cacheing)
+ nisam_extra(file,HA_EXTRA_WRITE_CACHE);
+
+ for (i=0 ; i < recant ; i++)
+ {
+ n1=rnd(1000); n2=rnd(100); n3=rnd(5000);
+ sprintf(record,"%6d:%4d:%8d:Pos: %4d ",n1,n2,n3,write_count);
+ longstore(record+STANDAR_LENGTH-4,(long) i);
+ fix_length(record,(uint) STANDAR_LENGTH+rnd(60));
+ put_blob_in_record(record+blob_pos,&blob_buffer);
+ DBUG_PRINT("test",("record: %d",i));
+
+ if (nisam_write(file,record))
+ {
+ if (my_errno != HA_ERR_FOUND_DUPP_KEY || key3[n3] == 0)
+ {
+ printf("Error: %d in write at record: %d\n",my_errno,i);
+ goto err;
+ }
+ if (verbose) printf(" Double key: %d\n",n3);
+ }
+ else
+ {
+ if (key3[n3] == 1 && first_key <3 && first_key+keys >= 3)
+ {
+ printf("Error: Didn't get error when writing second key: '%8d'\n",n3);
+ goto err;
+ }
+ write_count++; key1[n1]++; key3[n3]=1;
+ }
+
+ /* Check if we can find key without flushing database */
+ if (i == recant/2)
+ {
+ for (j=rnd(1000) ; j>0 && key1[j] == 0 ; j--) ;
+ if (!j)
+ for (j=999 ; j>0 && key1[j] == 0 ; j--) ;
+ sprintf(key,"%6d",j);
+ if (nisam_rkey(file,read_record,0,key,0,HA_READ_KEY_EXACT))
+ {
+ printf("Test in loop: Can't find key: \"%s\"\n",key);
+ goto err;
+ }
+ }
+ }
+ if (testflag==1) goto end;
+
+ if (write_cacheing)
+ if (nisam_extra(file,HA_EXTRA_NO_CACHE))
+ {
+ puts("got error from nisam_extra(HA_EXTRA_NO_CACHE)");
+ goto end;
+ }
+
+ printf("- Delete\n");
+ for (i=0 ; i<recant/10 ; i++)
+ {
+ for (j=rnd(1000) ; j>0 && key1[j] == 0 ; j--) ;
+ if (j != 0)
+ {
+ sprintf(key,"%6d",j);
+ if (nisam_rkey(file,read_record,0,key,0,HA_READ_KEY_EXACT))
+ {
+ printf("can't find key1: \"%s\"\n",key);
+ goto err;
+ }
+ if (nisam_delete(file,read_record))
+ {
+ printf("error: %d; can't delete record: \"%s\"\n", my_errno,read_record);
+ goto err;
+ }
+ delete++;
+ key1[atoi(read_record+keyinfo[0].seg[0].base.start)]--;
+ key3[atoi(read_record+keyinfo[2].seg[0].base.start)]=0;
+ }
+ }
+ if (testflag==2) goto end;
+
+ printf("- Update\n");
+ for (i=0 ; i<recant/10 ; i++)
+ {
+ n1=rnd(1000); n2=rnd(100); n3=rnd(5000);
+ sprintf(record2,"%6d:%4d:%8d:XXX: %4d ",n1,n2,n3,update);
+ longstore(record2+STANDAR_LENGTH-4,(long) i);
+ fix_length(record2,(uint) STANDAR_LENGTH+rnd(60));
+
+ for (j=rnd(1000) ; j>0 && key1[j] == 0 ; j--) ;
+ if (j != 0)
+ {
+ sprintf(key,"%6d",j);
+ if (nisam_rkey(file,read_record,0,key,0,HA_READ_KEY_EXACT))
+ {
+ printf("can't find key1: \"%s\"\n",key);
+ goto err;
+ }
+ if (use_blob)
+ {
+ if (i & 1)
+ put_blob_in_record(record+blob_pos,&blob_buffer);
+ else
+ bmove(record+blob_pos,read_record+blob_pos,8);
+ }
+ if (nisam_update(file,read_record,record2))
+ {
+ if (my_errno != HA_ERR_FOUND_DUPP_KEY || key3[n3] == 0)
+ {
+ printf("error: %d; can't uppdate:\nFrom: \"%s\"\nTo: \"%s\"\n",
+ my_errno,read_record,record2);
+ goto err;
+ }
+ if (verbose)
+ printf("Double key when tryed to uppdate:\nFrom: \"%s\"\nTo: \"%s\"\n",record,record2);
+ }
+ else
+ {
+ key1[atoi(read_record+keyinfo[0].seg[0].base.start)]--;
+ key3[atoi(read_record+keyinfo[2].seg[0].base.start)]=0;
+ key1[n1]++; key3[n3]=1;
+ update++;
+ }
+ }
+ }
+ if (testflag==3) goto end;
+
+ printf("- Same key: first - next -> last - prev -> first\n");
+ DBUG_PRINT("progpos",("first - next -> last - prev -> first"));
+ for (i=999, dupp_keys=j=0 ; i>0 ; i--)
+ {
+ if (key1[i] >dupp_keys) { dupp_keys=key1[i]; j=i; }
+ }
+ sprintf(key,"%6d",j);
+ if (verbose) printf(" Using key: \"%s\" Keys: %d\n",key,dupp_keys);
+ if (nisam_rkey(file,read_record,0,key,0,HA_READ_KEY_EXACT)) goto err;
+ if (nisam_rsame(file,read_record2,-1)) goto err;
+ if (memcmp(read_record,read_record2,reclength) != 0)
+ {
+ printf("nisam_rsame didn't find same record\n");
+ goto end;
+ }
+ nisam_info(file,&info,0);
+ if (nisam_rfirst(file,read_record2,0) ||
+ nisam_rsame_with_pos(file,read_record2,0,info.recpos) ||
+ memcmp(read_record,read_record2,reclength) != 0)
+ {
+ printf("nisam_rsame_with_pos didn't find same record\n");
+ goto end;
+ }
+ {
+ int skr=nisam_rnext(file,read_record2,0);
+ if ((skr && my_errno != HA_ERR_END_OF_FILE) ||
+ nisam_rprev(file,read_record2,-1) ||
+ memcmp(read_record,read_record2,reclength) != 0)
+ {
+ printf("nisam_rsame_with_pos lost position\n");
+ goto end;
+ }
+ }
+ ant=1;
+ start=keyinfo[0].seg[0].base.start; length=keyinfo[0].seg[0].base.length;
+ while (nisam_rnext(file,read_record2,0) == 0 &&
+ memcmp(read_record2+start,key,length) == 0) ant++;
+ if (ant != dupp_keys)
+ {
+ printf("next: I can only find: %d keys of %d\n",ant,dupp_keys);
+ goto end;
+ }
+ ant=0;
+ while (nisam_rprev(file,read_record3,0) == 0 &&
+ bcmp(read_record3+start,key,length) == 0) ant++;
+ if (ant != dupp_keys)
+ {
+ printf("prev: I can only find: %d records of %d\n",ant,dupp_keys);
+ goto end;
+ }
+
+ printf("- All keys: first - next -> last - prev -> first\n");
+ DBUG_PRINT("progpos",("All keys: first - next -> last - prev -> first"));
+ ant=1;
+ if (nisam_rfirst(file,read_record,0))
+ {
+ printf("Can't find first record\n");
+ goto end;
+ }
+ while (nisam_rnext(file,read_record3,0) == 0 && ant < write_count+10)
+ ant++;
+ if (ant != write_count - delete)
+ {
+ printf("next: I found: %d records of %d\n",ant,write_count - delete);
+ goto end;
+ }
+ if (nisam_rlast(file,read_record2,0) ||
+ bcmp(read_record2,read_record3,reclength))
+ {
+ printf("Can't find last record\n");
+ DBUG_DUMP("record2",(byte*) read_record2,reclength);
+ DBUG_DUMP("record3",(byte*) read_record3,reclength);
+ goto end;
+ }
+ ant=1;
+ while (nisam_rprev(file,read_record3,0) == 0 && ant < write_count+10)
+ ant++;
+ if (ant != write_count - delete)
+ {
+ printf("prev: I found: %d records of %d\n",ant,write_count);
+ goto end;
+ }
+ if (bcmp(read_record,read_record3,reclength))
+ {
+ printf("Can't find first record\n");
+ goto end;
+ }
+
+ printf("- Test if: Read first - next - prev - prev - next == first\n");
+ DBUG_PRINT("progpos",("- Read first - next - prev - prev - next == first"));
+ if (nisam_rfirst(file,read_record,0) ||
+ nisam_rnext(file,read_record3,0) ||
+ nisam_rprev(file,read_record3,0) ||
+ nisam_rprev(file,read_record3,0) == 0 ||
+ nisam_rnext(file,read_record3,0))
+ goto err;
+ if (bcmp(read_record,read_record3,reclength) != 0)
+ printf("Can't find first record\n");
+
+ printf("- Test if: Read last - prev - next - next - prev == last\n");
+ DBUG_PRINT("progpos",("Read last - prev - next - next - prev == last"));
+ if (nisam_rlast(file,read_record2,0) ||
+ nisam_rprev(file,read_record3,0) ||
+ nisam_rnext(file,read_record3,0) ||
+ nisam_rnext(file,read_record3,0) == 0 ||
+ nisam_rprev(file,read_record3,0))
+ goto err;
+ if (bcmp(read_record2,read_record3,reclength))
+ printf("Can't find last record\n");
+
+ puts("- Test read key-part");
+ strmov(key2,key);
+ for(i=strlen(key2) ; i-- > 1 ;)
+ {
+ key2[i]=0;
+ if (nisam_rkey(file,read_record,0,key2,(uint) i,HA_READ_KEY_EXACT)) goto err;
+ if (bcmp(read_record+start,key,(uint) i))
+ {
+ puts("Didn't find right record");
+ goto end;
+ }
+ }
+ if (dupp_keys > 2)
+ {
+ printf("- Read key (first) - next - delete - next -> last\n");
+ DBUG_PRINT("progpos",("first - next - delete - next -> last"));
+ if (nisam_rkey(file,read_record,0,key,0,HA_READ_KEY_EXACT)) goto err;
+ if (nisam_rnext(file,read_record3,0)) goto err;
+ if (nisam_delete(file,read_record3)) goto err;
+ delete++;
+ ant=1;
+ while (nisam_rnext(file,read_record3,0) == 0 &&
+ bcmp(read_record3+start,key,length) == 0) ant++;
+ if (ant != dupp_keys-1)
+ {
+ printf("next: I can only find: %d keys of %d\n",ant,dupp_keys-1);
+ goto end;
+ }
+ }
+ if (dupp_keys>4)
+ {
+ printf("- Read last of key - prev - delete - prev -> first\n");
+ DBUG_PRINT("progpos",("last - prev - delete - prev -> first"));
+ if (nisam_rprev(file,read_record3,0)) goto err;
+ if (nisam_rprev(file,read_record3,0)) goto err;
+ if (nisam_delete(file,read_record3)) goto err;
+ delete++;
+ ant=1;
+ while (nisam_rprev(file,read_record3,0) == 0 &&
+ bcmp(read_record3+start,key,length) == 0) ant++;
+ if (ant != dupp_keys-2)
+ {
+ printf("next: I can only find: %d keys of %d\n",ant,dupp_keys-2);
+ goto end;
+ }
+ }
+ if (dupp_keys > 6)
+ {
+ printf("- Read first - delete - next -> last\n");
+ DBUG_PRINT("progpos",("first - delete - next -> last"));
+ if (nisam_rkey(file,read_record3,0,key,0,HA_READ_KEY_EXACT)) goto err;
+ if (nisam_delete(file,read_record3)) goto err;
+ delete++;
+ ant=1;
+ if (nisam_rnext(file,read_record,0))
+ goto err; /* Skall finnas poster */
+ while (nisam_rnext(file,read_record3,0) == 0 &&
+ bcmp(read_record3+start,key,length) == 0) ant++;
+ if (ant != dupp_keys-3)
+ {
+ printf("next: I can only find: %d keys of %d\n",ant,dupp_keys-3);
+ goto end;
+ }
+
+ printf("- Read last - delete - prev -> first\n");
+ DBUG_PRINT("progpos",("last - delete - prev -> first"));
+ if (nisam_rprev(file,read_record3,0)) goto err;
+ if (nisam_delete(file,read_record3)) goto err;
+ delete++;
+ ant=0;
+ while (nisam_rprev(file,read_record3,0) == 0 &&
+ bcmp(read_record3+start,key,length) == 0) ant++;
+ if (ant != dupp_keys-4)
+ {
+ printf("next: I can only find: %d keys of %d\n",ant,dupp_keys-4);
+ goto end;
+ }
+ }
+
+ puts("- Test if: Read rrnd - same");
+ DBUG_PRINT("progpos",("Read rrnd - same"));
+ for (i=0 ; i < write_count ; i++)
+ {
+ if (nisam_rrnd(file,read_record,i == 0 ? 0L : NI_POS_ERROR) == 0)
+ break;
+ }
+ if (i == write_count)
+ goto err;
+
+ bmove(read_record2,read_record,reclength);
+ for (i=2 ; i-- > 0 ;)
+ {
+ if (nisam_rsame(file,read_record2,(int) i)) goto err;
+ if (bcmp(read_record,read_record2,reclength) != 0)
+ {
+ printf("is_rsame didn't find same record\n");
+ goto end;
+ }
+ }
+ puts("- Test nisam_records_in_range");
+ nisam_info(file,&info,HA_STATUS_VARIABLE);
+ for (i=0 ; i < info.keys ; i++)
+ {
+ if (nisam_rfirst(file,read_record,(int) i) ||
+ nisam_rlast(file,read_record2,(int) i))
+ goto err;
+ copy_key(file,(uint) i,(uchar*) read_record,(uchar*) key);
+ copy_key(file,(uint) i,(uchar*) read_record2,(uchar*) key2);
+ range_records=nisam_records_in_range(file,(int) i,key,0,HA_READ_KEY_EXACT,
+ key2,0,HA_READ_AFTER_KEY);
+ if (range_records < info.records*8/10 ||
+ range_records > info.records*12/10)
+ {
+ printf("ni_records_range returned %lu; Should be about %lu\n",
+ range_records,info.records);
+ goto end;
+ }
+ if (verbose)
+ {
+ printf("ni_records_range returned %ld; Exact is %ld (diff: %4.2g %%)\n",
+ range_records,info.records,
+ labs((long) range_records - (long) info.records)*100.0/
+ info.records);
+
+ }
+ }
+ for (i=0 ; i < 5 ; i++)
+ {
+ for (j=rnd(1000) ; j>0 && key1[j] == 0 ; j--) ;
+ for (k=rnd(1000) ; k>0 && key1[k] == 0 ; k--) ;
+ if (j != 0 && k != 0)
+ {
+ if (j > k)
+ swap(int,j,k);
+ sprintf(key,"%6d",j);
+ sprintf(key2,"%6d",k);
+ range_records=nisam_records_in_range(file,0,key,0,HA_READ_AFTER_KEY,
+ key2,0,HA_READ_BEFORE_KEY);
+ records=0;
+ for (j++ ; j < k ; j++)
+ records+=key1[j];
+ if ((long) range_records < (long) records*7/10-2 ||
+ (long) range_records > (long) records*13/10+2)
+ {
+ printf("ni_records_range returned %ld; Should be about %ld\n",
+ range_records,records);
+ goto end;
+ }
+ if (verbose && records)
+ {
+ printf("ni_records_range returned %ld; Exact is %ld (diff: %4.2g %%)\n",
+ range_records,records,
+ labs((long) range_records-(long) records)*100.0/records);
+
+ }
+ }
+ }
+
+ printf("- nisam_info\n");
+ nisam_info(file,&info,0);
+ if (info.records != write_count-delete || info.deleted > delete + update
+ || info.keys != keys)
+ {
+ puts("Wrong info from nisam_info");
+ printf("Got: records: %ld delete: %ld i_keys: %d\n",
+ info.records,info.deleted,info.keys);
+ }
+ if (verbose)
+ {
+ char buff[80];
+ get_date(buff,3,info.create_time);
+ printf("info: Created %s\n",buff);
+ get_date(buff,3,info.isamchk_time);
+ printf("info: checked %s\n",buff);
+ get_date(buff,3,info.update_time);
+ printf("info: Modified %s\n",buff);
+ }
+
+ nisam_panic(HA_PANIC_WRITE);
+ nisam_panic(HA_PANIC_READ);
+ if (nisam_is_changed(file))
+ puts("Warning: nisam_is_changed reported that datafile was changed");
+
+ printf("- nisam_extra(CACHE) + nisam_rrnd.... + nisam_extra(NO_CACHE)\n");
+ if (nisam_extra(file,HA_EXTRA_RESET) || nisam_extra(file,HA_EXTRA_CACHE))
+ {
+ if (locking || (!use_blob && !pack_fields))
+ {
+ puts("got error from nisam_extra(HA_EXTRA_CACHE)");
+ goto end;
+ }
+ }
+ ant=0;
+ while ((error=nisam_rrnd(file,record,NI_POS_ERROR)) >= 0 &&
+ ant < write_count + 10)
+ ant+= error ? 0 : 1;
+ if (ant != write_count-delete)
+ {
+ printf("rrnd with cache: I can only find: %d records of %d\n",
+ ant,write_count-delete);
+ goto end;
+ }
+ if (nisam_extra(file,HA_EXTRA_NO_CACHE))
+ {
+ puts("got error from nisam_extra(HA_EXTRA_NO_CACHE)");
+ goto end;
+ }
+
+ if (testflag == 4) goto end;
+
+ printf("- Removing keys\n");
+ lastpos = NI_POS_ERROR;
+ /* DBUG_POP(); */
+ nisam_extra(file,HA_EXTRA_RESET);
+ while ((error=nisam_rrnd(file,read_record,NI_POS_ERROR)) >=0)
+ {
+ nisam_info(file,&info,1);
+ if (lastpos >= info.recpos && lastpos != NI_POS_ERROR)
+ {
+ printf("nisam_rrnd didn't advance filepointer; old: %ld, new: %ld\n",
+ lastpos,info.recpos);
+ goto err;
+ }
+ lastpos=info.recpos;
+ if (error == 0)
+ {
+ if (nisam_rsame(file,read_record,-1))
+ {
+ printf("can't find record %lx\n",info.recpos);
+ goto err;
+ }
+ if (use_blob)
+ {
+ ulong blob_length,pos;
+ uchar *ptr;
+ longget(blob_length,read_record+blob_pos+4);
+ ptr=(uchar*) blob_length;
+ longget(blob_length,read_record+blob_pos);
+ for (pos=0 ; pos < blob_length ; pos++)
+ {
+ if (ptr[pos] != (uchar) (blob_length+pos))
+ {
+ printf("found blob with wrong info at %ld\n",lastpos);
+ use_blob=0;
+ break;
+ }
+ }
+ }
+ if (nisam_delete(file,read_record))
+ {
+ printf("can't delete record: %s\n",read_record);
+ goto err;
+ }
+ delete++;
+ }
+ }
+ if (my_errno != HA_ERR_END_OF_FILE && my_errno != HA_ERR_RECORD_DELETED)
+ printf("error: %d from nisam_rrnd\n",my_errno);
+ if (write_count != delete)
+ {
+ printf("Deleted only %d of %d records\n",write_count,delete);
+ goto err;
+ }
+end:
+ if (nisam_close(file))
+ goto err;
+ nisam_panic(HA_PANIC_CLOSE); /* Should close log */
+ printf("\nFollowing test have been made:\n");
+ printf("Write records: %d\nUpdate records: %d\nSame-key-read: %d\nDelete records: %d\n", write_count,update,dupp_keys,delete);
+ if (rec_pointer_size)
+ printf("Record pointer size: %d\n",rec_pointer_size);
+ if (key_cacheing)
+ puts("Key cacheing used");
+ if (write_cacheing)
+ puts("Write cacheing used");
+ if (async_io && locking)
+ puts("Asyncron io with locking used");
+ else if (locking)
+ puts("Locking used");
+ if (use_blob)
+ puts("blobs used");
+ end_key_cache();
+ if (blob_buffer)
+ my_free(blob_buffer,MYF(0));
+ my_end(MY_CHECK_ERROR | MY_GIVE_INFO);
+ return(0);
+err:
+ printf("got error: %d when using NISAM-database\n",my_errno);
+ if (file)
+ VOID(nisam_close(file));
+ return(1);
+} /* main */
+
+
+ /* l{ser optioner */
+ /* OBS! intierar endast DEBUG - ingen debuggning h{r ! */
+
+static void get_options(argc,argv)
+int argc;
+char *argv[];
+{
+ char *pos,*progname;
+ DEBUGGER_OFF;
+
+ progname= argv[0];
+
+ while (--argc >0 && *(pos = *(++argv)) == '-' ) {
+ switch(*++pos) {
+ case 'b':
+ if (*++pos)
+ nisam_block_size= MY_ALIGN(atoi(pos),512);
+ set_if_bigger(nisam_block_size,8192); /* Max block size */
+ set_if_smaller(nisam_block_size,1024);
+ break;
+ case 'B':
+ use_blob=1;
+ break;
+ case 'K': /* Use key cacheing */
+ key_cacheing=1;
+ break;
+ case 'W': /* Use write cacheing */
+ write_cacheing=1;
+ if (*++pos)
+ my_default_record_cache_size=atoi(pos);
+ break;
+ case 'i':
+ if (*++pos)
+ srand(atoi(pos));
+ break;
+ case 'l':
+ use_log=1;
+ break;
+ case 'L':
+ locking=1;
+ break;
+ case 'A': /* use asyncron io */
+ async_io=1;
+ if (*++pos)
+ my_default_record_cache_size=atoi(pos);
+ break;
+ case 'v': /* verbose */
+ verbose=1;
+ break;
+ case 'm': /* records */
+ recant=atoi(++pos);
+ break;
+ case 'f':
+ if ((first_key=atoi(++pos)) <0 || first_key >= NISAM_KEYS)
+ first_key=0;
+ break;
+ case 'k':
+ if ((keys=(uint) atoi(++pos)) < 1 ||
+ keys > (uint) (NISAM_KEYS-first_key))
+ keys=NISAM_KEYS-first_key;
+ break;
+ case 'P':
+ pack_type=0; /* Don't use DIFF_LENGTH */
+ break;
+ case 'R': /* Length of record pointer */
+ rec_pointer_size=atoi(++pos);
+ if (rec_pointer_size > 3)
+ rec_pointer_size=0;
+ break;
+ case 'S':
+ pack_fields=0; /* Static-length-records */
+ break;
+ case 't':
+ testflag=atoi(++pos); /* testmod */
+ break;
+ case '?':
+ case 'I':
+ case 'V':
+ printf("%s Ver 1.4 for %s at %s\n",progname,SYSTEM_TYPE,MACHINE_TYPE);
+ puts("TCX Datakonsult AB, by Monty, for your professional use\n");
+ printf("Usage: %s [-?ABIKLPRSVWltv] [-b#] [-k#] [-f#] [-m#] [-t#]\n",progname);
+ exit(0);
+ case '#':
+ DEBUGGER_ON;
+ DBUG_PUSH (++pos);
+ break;
+ default:
+ printf("Illegal option: '%c'\n",*pos);
+ break;
+ }
+ }
+ return;
+} /* get options */
+
+ /* Ge ett randomv{rde inom ett intervall 0 <=x <= n */
+
+static uint rnd(max_value)
+uint max_value;
+{
+ return (uint) ((rand() & 32767)/32767.0*max_value);
+} /* rnd */
+
+
+ /* G|r en record av skiftande length */
+
+static void fix_length(rec,length)
+byte *rec;
+uint length;
+{
+ bmove(rec+STANDAR_LENGTH,
+ "0123456789012345678901234567890123456789012345678901234567890",
+ length-STANDAR_LENGTH);
+ strfill(rec+length,STANDAR_LENGTH+60-length,' ');
+} /* fix_length */
+
+
+ /* Put maybe a blob in record */
+
+static void put_blob_in_record(blob_pos,blob_buffer)
+char *blob_pos,**blob_buffer;
+{
+ ulong i,length;
+ if (use_blob)
+ {
+ if (rnd(10) == 0)
+ {
+ if (! *blob_buffer &&
+ !(*blob_buffer=my_malloc((uint) use_blob,MYF(MY_WME))))
+ {
+ use_blob=0;
+ return;
+ }
+ length=rnd(use_blob);
+ for (i=0 ; i < length ; i++)
+ (*blob_buffer)[i]=(char) (length+i);
+ longstore(blob_pos,length);
+ bmove(blob_pos+4,(char*) blob_buffer,sizeof(char*));
+ }
+ else
+ {
+ longstore(blob_pos,0);
+ }
+ }
+ return;
+}
+
+
+static void copy_key(info,inx,rec,key_buff)
+N_INFO *info;
+uint inx;
+uchar *rec,*key_buff;
+{
+ N_KEYSEG *keyseg;
+
+ for (keyseg=info->s->keyinfo[inx].seg ; keyseg->base.type ; keyseg++)
+ {
+ memcpy(key_buff,rec+keyseg->base.start,(size_t) keyseg->base.length);
+ key_buff+=keyseg->base.length;
+ }
+ return;
+}
diff --git a/isam/test3.c b/isam/test3.c
new file mode 100644
index 00000000000..935c194106d
--- /dev/null
+++ b/isam/test3.c
@@ -0,0 +1,479 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* Test av locking */
+
+#include "nisam.h"
+#include <sys/types.h>
+#ifdef HAVE_SYS_WAIT_H
+# include <sys/wait.h>
+#endif
+#ifndef WEXITSTATUS
+# define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
+#endif
+#ifndef WIFEXITED
+# define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
+#endif
+
+
+#if defined(HAVE_LRAND48)
+#define rnd(X) (lrand48() % X)
+#define rnd_init(X) srand48(X)
+#else
+#define rnd(X) (random() % X)
+#define rnd_init(X) srandom(X)
+#endif
+
+
+const char *filename= "test3.ISM";
+uint tests=10,forks=10,key_cacheing=0,use_log=0;
+
+static void get_options(int argc, char *argv[]);
+void start_test(int id);
+int test_read(N_INFO *,int),test_write(N_INFO *,int,int),
+ test_update(N_INFO *,int,int),test_rrnd(N_INFO *,int);
+
+struct record {
+ char id[8];
+ uint32 nr;
+ char text[10];
+} record;
+
+
+int main(int argc,char **argv)
+{
+ int status,wait_ret;
+ uint i;
+ N_KEYDEF keyinfo[10];
+ N_RECINFO recinfo[10];
+ MY_INIT(argv[0]);
+
+ get_options(argc,argv);
+
+ keyinfo[0].seg[0].base.start=0;
+ keyinfo[0].seg[0].base.length=8;
+ keyinfo[0].seg[0].base.type=HA_KEYTYPE_TEXT;
+ keyinfo[0].seg[0].base.flag=HA_SPACE_PACK;
+ keyinfo[0].seg[1].base.type=0;
+ keyinfo[0].base.flag = (uint8) HA_PACK_KEY;
+ keyinfo[1].seg[0].base.start=8;
+ keyinfo[1].seg[0].base.length=sizeof(uint32);
+ keyinfo[1].seg[0].base.type=HA_KEYTYPE_LONG_INT;
+ keyinfo[1].seg[0].base.flag=0;
+ keyinfo[1].seg[1].base.type=0;
+ keyinfo[1].base.flag =HA_NOSAME;
+
+ recinfo[0].base.type=0;
+ recinfo[0].base.length=sizeof(record.id);
+ recinfo[1].base.type=0;
+ recinfo[1].base.length=sizeof(record.nr);
+ recinfo[2].base.type=0;
+ recinfo[2].base.length=sizeof(record.text);
+ recinfo[3].base.type=FIELD_LAST;
+
+ puts("- Creating isam-file");
+ my_delete(filename,MYF(0)); /* Remove old locks under gdb */
+ if (nisam_create(filename,2,&keyinfo[0],&recinfo[0],10000,0,0,0,0L))
+ exit(1);
+
+ rnd_init(0);
+ printf("- Starting %d processes\n",forks); fflush(stdout);
+ for (i=0 ; i < forks; i++)
+ {
+ if (!fork())
+ {
+ start_test(i+1);
+ sleep(1);
+ return 0;
+ }
+ VOID(rnd(1));
+ }
+
+ for (i=0 ; i < forks ; i++)
+ while ((wait_ret=wait(&status)) && wait_ret == -1);
+ return 0;
+}
+
+
+static void get_options(argc,argv)
+int argc;
+char *argv[];
+{
+ char *pos,*progname;
+ DEBUGGER_OFF;
+
+ progname= argv[0];
+
+ while (--argc >0 && *(pos = *(++argv)) == '-' ) {
+ switch(*++pos) {
+ case 'l':
+ use_log=1;
+ break;
+ case 'f':
+ forks=atoi(++pos);
+ break;
+ case 't':
+ tests=atoi(++pos);
+ break;
+ case 'K': /* Use key cacheing */
+ key_cacheing=1;
+ break;
+ case 'A': /* All flags */
+ use_log=key_cacheing=1;
+ break;
+ case '?':
+ case 'I':
+ case 'V':
+ printf("%s Ver 1.0 for %s at %s\n",progname,SYSTEM_TYPE,MACHINE_TYPE);
+ puts("TCX Datakonsult AB, by Monty, for your professional use\n");
+ puts("Test av locking with threads\n");
+ printf("Usage: %s [-?lKA] [-f#] [-t#]\n",progname);
+ exit(0);
+ case '#':
+ DEBUGGER_ON;
+ DBUG_PUSH (++pos);
+ break;
+ default:
+ printf("Illegal option: '%c'\n",*pos);
+ break;
+ }
+ }
+ return;
+}
+
+
+void start_test(int id)
+{
+ uint i;
+ int error,lock_type;
+ N_ISAMINFO isam_info;
+ N_INFO *file,*file1,*file2,*lock;
+
+ if (use_log)
+ nisam_log(1);
+ if (!(file1=nisam_open(filename,O_RDWR,HA_OPEN_WAIT_IF_LOCKED)) ||
+ !(file2=nisam_open(filename,O_RDWR,HA_OPEN_WAIT_IF_LOCKED)))
+ {
+ fprintf(stderr,"Can't open isam-file: %s\n",filename);
+ exit(1);
+ }
+ if (key_cacheing && rnd(2) == 0)
+ init_key_cache(65536L,(uint) IO_SIZE*4*10);
+ printf("Process %d, pid: %d\n",id,getpid()); fflush(stdout);
+
+ for (error=i=0 ; i < tests && !error; i++)
+ {
+ file= (rnd(2) == 1) ? file1 : file2;
+ lock=0 ; lock_type=0;
+ if (rnd(10) == 0)
+ {
+ if (nisam_lock_database(lock=(rnd(2) ? file1 : file2),
+ lock_type=(rnd(2) == 0 ? F_RDLCK : F_WRLCK)))
+ {
+ fprintf(stderr,"%2d: start: Can't lock table %d\n",id,my_errno);
+ error=1;
+ break;
+ }
+ }
+ switch (rnd(4)) {
+ case 0: error=test_read(file,id); break;
+ case 1: error=test_rrnd(file,id); break;
+ case 2: error=test_write(file,id,lock_type); break;
+ case 3: error=test_update(file,id,lock_type); break;
+ }
+ if (lock)
+ nisam_lock_database(lock,F_UNLCK);
+ }
+ if (!error)
+ {
+ nisam_info(file1,&isam_info,0);
+ printf("%2d: End of test. Records: %ld Deleted: %ld\n",
+ id,isam_info.records,isam_info.deleted);
+ fflush(stdout);
+ }
+
+ nisam_close(file1);
+ nisam_close(file2);
+ if (use_log)
+ nisam_log(0);
+ if (error)
+ {
+ printf("%2d: Aborted\n",id); fflush(stdout);
+ exit(1);
+ }
+}
+
+
+int test_read(N_INFO *file,int id)
+{
+ uint i,lock,found,next,prev;
+ ulong find;
+
+ lock=0;
+ if (rnd(2) == 0)
+ {
+ lock=1;
+ if (nisam_lock_database(file,F_RDLCK))
+ {
+ fprintf(stderr,"%2d: Can't lock table %d\n",id,my_errno);
+ return 1;
+ }
+ }
+
+ found=next=prev=0;
+ for (i=0 ; i < 100 ; i++)
+ {
+ find=rnd(100000);
+ if (!nisam_rkey(file,record.id,1,(byte*) &find,
+ sizeof(find),HA_READ_KEY_EXACT))
+ found++;
+ else
+ {
+ if (my_errno != HA_ERR_KEY_NOT_FOUND)
+ {
+ fprintf(stderr,"%2d: Got error %d from read in read\n",id,my_errno);
+ return 1;
+ }
+ else if (!nisam_rnext(file,record.id,1))
+ next++;
+ else
+ {
+ if (my_errno != HA_ERR_END_OF_FILE)
+ {
+ fprintf(stderr,"%2d: Got error %d from rnext in read\n",id,my_errno);
+ return 1;
+ }
+ else if (!nisam_rprev(file,record.id,1))
+ prev++;
+ else
+ {
+ if (my_errno != HA_ERR_END_OF_FILE)
+ {
+ fprintf(stderr,"%2d: Got error %d from rnext in read\n",
+ id,my_errno);
+ return 1;
+ }
+ }
+ }
+ }
+ }
+ if (lock)
+ {
+ if (nisam_lock_database(file,F_UNLCK))
+ {
+ fprintf(stderr,"%2d: Can't unlock table\n",id);
+ return 1;
+ }
+ }
+ printf("%2d: read: found: %5d next: %5d prev: %5d\n",
+ id,found,next,prev);
+ fflush(stdout);
+ return 0;
+}
+
+
+int test_rrnd(N_INFO *file,int id)
+{
+ uint count,lock;
+
+ lock=0;
+ if (rnd(2) == 0)
+ {
+ lock=1;
+ if (nisam_lock_database(file,F_RDLCK))
+ {
+ fprintf(stderr,"%2d: Can't lock table (%d)\n",id,my_errno);
+ nisam_close(file);
+ return 1;
+ }
+ if (rnd(2) == 0)
+ nisam_extra(file,HA_EXTRA_CACHE);
+ }
+
+ count=0;
+ if (nisam_rrnd(file,record.id,0L))
+ {
+ if (my_errno == HA_ERR_END_OF_FILE)
+ goto end;
+ fprintf(stderr,"%2d: Can't read first record (%d)\n",id,my_errno);
+ return 1;
+ }
+ for (count=1 ; !nisam_rrnd(file,record.id,NI_POS_ERROR) ;count++) ;
+ if (my_errno != HA_ERR_END_OF_FILE)
+ {
+ fprintf(stderr,"%2d: Got error %d from rrnd\n",id,my_errno);
+ return 1;
+ }
+
+end:
+ if (lock)
+ {
+ nisam_extra(file,HA_EXTRA_NO_CACHE);
+ if (nisam_lock_database(file,F_UNLCK))
+ {
+ fprintf(stderr,"%2d: Can't unlock table\n",id);
+ exit(0);
+ }
+ }
+ printf("%2d: rrnd: %5d\n",id,count); fflush(stdout);
+ return 0;
+}
+
+
+int test_write(N_INFO *file,int id,int lock_type)
+{
+ uint i,tries,count,lock;
+
+ lock=0;
+ if (rnd(2) == 0 || lock_type == F_RDLCK)
+ {
+ lock=1;
+ if (nisam_lock_database(file,F_WRLCK))
+ {
+ if (lock_type == F_RDLCK && my_errno == EDEADLK)
+ {
+ printf("%2d: write: deadlock\n",id); fflush(stdout);
+ return 0;
+ }
+ fprintf(stderr,"%2d: Can't lock table (%d)\n",id,my_errno);
+ nisam_close(file);
+ return 1;
+ }
+ if (rnd(2) == 0)
+ nisam_extra(file,HA_EXTRA_WRITE_CACHE);
+ }
+
+ sprintf(record.id,"%7d",getpid());
+ strmov(record.text,"Testing...");
+
+ tries=(uint) rnd(100)+10;
+ for (i=count=0 ; i < tries ; i++)
+ {
+ record.nr=rnd(80000)+20000;
+ if (!nisam_write(file,record.id))
+ count++;
+ else
+ {
+ if (my_errno != HA_ERR_FOUND_DUPP_KEY)
+ {
+ fprintf(stderr,"%2d: Got error %d (errno %d) from write\n",id,my_errno,
+ errno);
+ return 1;
+ }
+ }
+ }
+ if (lock)
+ {
+ nisam_extra(file,HA_EXTRA_NO_CACHE);
+ if (nisam_lock_database(file,F_UNLCK))
+ {
+ fprintf(stderr,"%2d: Can't unlock table\n",id);
+ exit(0);
+ }
+ }
+ printf("%2d: write: %5d\n",id,count); fflush(stdout);
+ return 0;
+}
+
+
+int test_update(N_INFO *file,int id,int lock_type)
+{
+ uint i,lock,found,next,prev,update;
+ ulong find;
+ struct record new_record;
+
+ lock=0;
+ if (rnd(2) == 0 || lock_type == F_RDLCK)
+ {
+ lock=1;
+ if (nisam_lock_database(file,F_WRLCK))
+ {
+ if (lock_type == F_RDLCK && my_errno == EDEADLK)
+ {
+ printf("%2d: write: deadlock\n",id); fflush(stdout);
+ return 0;
+ }
+ fprintf(stderr,"%2d: Can't lock table (%d)\n",id,my_errno);
+ return 1;
+ }
+ }
+ bzero((char*) &new_record,sizeof(new_record));
+ strmov(new_record.text,"Updated");
+
+ found=next=prev=update=0;
+ for (i=0 ; i < 100 ; i++)
+ {
+ find=rnd(100000);
+ if (!nisam_rkey(file,record.id,1,(byte*) &find,
+ sizeof(find),HA_READ_KEY_EXACT))
+ found++;
+ else
+ {
+ if (my_errno != HA_ERR_KEY_NOT_FOUND)
+ {
+ fprintf(stderr,"%2d: Got error %d from read in update\n",id,my_errno);
+ return 1;
+ }
+ else if (!nisam_rnext(file,record.id,1))
+ next++;
+ else
+ {
+ if (my_errno != HA_ERR_END_OF_FILE)
+ {
+ fprintf(stderr,"%2d: Got error %d from rnext in update\n",
+ id,my_errno);
+ return 1;
+ }
+ else if (!nisam_rprev(file,record.id,1))
+ prev++;
+ else
+ {
+ if (my_errno != HA_ERR_END_OF_FILE)
+ {
+ fprintf(stderr,"%2d: Got error %d from rnext in update\n",
+ id,my_errno);
+ return 1;
+ }
+ continue;
+ }
+ }
+ }
+ memcpy_fixed(new_record.id,record.id,sizeof(record.id));
+ new_record.nr=rnd(20000)+40000;
+ if (!nisam_update(file,record.id,new_record.id))
+ update++;
+ else
+ {
+ if (my_errno != HA_ERR_RECORD_CHANGED &&
+ my_errno != HA_ERR_RECORD_DELETED &&
+ my_errno != HA_ERR_FOUND_DUPP_KEY)
+ {
+ fprintf(stderr,"%2d: Got error %d from update\n",id,my_errno);
+ return 1;
+ }
+ }
+ }
+ if (lock)
+ {
+ if (nisam_lock_database(file,F_UNLCK))
+ {
+ fprintf(stderr,"Can't unlock table,id, error%d\n",my_errno);
+ return 1;
+ }
+ }
+ printf("%2d: update: %5d\n",id,update); fflush(stdout);
+ return 0;
+}
diff --git a/isam/test_all b/isam/test_all
new file mode 100755
index 00000000000..5de37e44585
--- /dev/null
+++ b/isam/test_all
@@ -0,0 +1,30 @@
+echo "test2 -L -K -W -P"
+test2 -L -K -W -P
+echo "test2 -L -K -W -P -A"
+test2 -L -K -W -P -A
+echo "test2 -L -K -W -P -S -R1 -m500"
+test2 -L -K -W -P -S -R1 -m500
+echo "test2 -L -K -R1 -m2000 ; Should give error 135"
+test2 -L -K -R1 -m2000
+echo "test2 -L -K -P -S -R3 -m50 -b1000000"
+test2 -L -K -P -S -R3 -m50 -b1000000
+echo "test2 -L -B"
+test2 -L -B
+echo "test2 -L -K -W -P -m50 -l"
+test2 -L -K -W -P -m50 -l
+isamlog
+echo "test2 -L -K -W -P -m50 -l -b100"
+test2 -L -K -W -P -m50 -l -b100
+isamlog
+echo "time test2"
+time test2
+echo "time test2 -K"
+time test2 -K
+echo "time test2 -L"
+time test2 -L
+echo "time test2 -L -K"
+time test2 -L -K
+echo "time test2 -L -K -W"
+time test2 -L -K -W
+echo "time test2 -L -K -W -S"
+time test2 -L -K -W -S
diff --git a/isam/test_all.res b/isam/test_all.res
new file mode 100644
index 00000000000..756a05f869c
--- /dev/null
+++ b/isam/test_all.res
@@ -0,0 +1,356 @@
+test2 -L -K -W -P
+- Creating isam-file
+- Writing key:s
+- Delete
+- Update
+- Same key: first - next -> last - prev -> first
+- All keys: first - next -> last - prev -> first
+- Test if: Read first - next - prev - prev - next == first
+- Test if: Read last - prev - next - next - prev == last
+- Test read key-part
+- Read key (first) - next - delete - next -> last
+- Read last of key - prev - delete - prev -> first
+- Test if: Read rrnd - same
+- Test ni_records_in_range
+- ni_info
+- ni_extra(CACHE) + ni_rrnd.... + ni_extra(NO_CACHE)
+- Removing keys
+
+Following test have been made:
+Write records: 915
+Update records: 82
+Same-key-read: 6
+Delete records: 915
+Key cacheing used
+Write cacheing used
+Locking used
+test2 -L -K -W -P -A
+- Creating isam-file
+- Writing key:s
+- Delete
+- Update
+- Same key: first - next -> last - prev -> first
+- All keys: first - next -> last - prev -> first
+- Test if: Read first - next - prev - prev - next == first
+- Test if: Read last - prev - next - next - prev == last
+- Test read key-part
+- Read key (first) - next - delete - next -> last
+- Read last of key - prev - delete - prev -> first
+- Test if: Read rrnd - same
+- Test ni_records_in_range
+- ni_info
+- ni_extra(CACHE) + ni_rrnd.... + ni_extra(NO_CACHE)
+- Removing keys
+
+Following test have been made:
+Write records: 915
+Update records: 82
+Same-key-read: 6
+Delete records: 915
+Key cacheing used
+Write cacheing used
+Asyncron io with locking used
+test2 -L -K -W -P -S -R1 -m500
+- Creating isam-file
+- Writing key:s
+- Delete
+- Update
+- Same key: first - next -> last - prev -> first
+- All keys: first - next -> last - prev -> first
+- Test if: Read first - next - prev - prev - next == first
+- Test if: Read last - prev - next - next - prev == last
+- Test read key-part
+- Read key (first) - next - delete - next -> last
+- Test if: Read rrnd - same
+- Test ni_records_in_range
+- ni_info
+- ni_extra(CACHE) + ni_rrnd.... + ni_extra(NO_CACHE)
+- Removing keys
+
+Following test have been made:
+Write records: 484
+Update records: 48
+Same-key-read: 3
+Delete records: 484
+Record pointer size: 1
+Key cacheing used
+Write cacheing used
+Locking used
+test2 -L -K -R1 -m2000 ; Should give error 135
+- Creating isam-file
+- Writing key:s
+Error: 135 in write at record: 1122
+got error: 135 when using NISAM-database
+test2 -L -K -P -S -R3 -m50 -b1000000
+- Creating isam-file
+- Writing key:s
+- Delete
+- Update
+- Same key: first - next -> last - prev -> first
+- All keys: first - next -> last - prev -> first
+- Test if: Read first - next - prev - prev - next == first
+- Test if: Read last - prev - next - next - prev == last
+- Test read key-part
+- Test if: Read rrnd - same
+- Test ni_records_in_range
+- ni_info
+- ni_extra(CACHE) + ni_rrnd.... + ni_extra(NO_CACHE)
+- Removing keys
+
+Following test have been made:
+Write records: 50
+Update records: 5
+Same-key-read: 2
+Delete records: 50
+Record pointer size: 3
+Key cacheing used
+Locking used
+test2 -L -B
+- Creating isam-file
+- Writing key:s
+- Delete
+- Update
+- Same key: first - next -> last - prev -> first
+- All keys: first - next -> last - prev -> first
+- Test if: Read first - next - prev - prev - next == first
+- Test if: Read last - prev - next - next - prev == last
+- Test read key-part
+- Read key (first) - next - delete - next -> last
+- Read last of key - prev - delete - prev -> first
+- Test if: Read rrnd - same
+- Test ni_records_in_range
+- ni_info
+- ni_extra(CACHE) + ni_rrnd.... + ni_extra(NO_CACHE)
+- Removing keys
+
+Following test have been made:
+Write records: 912
+Update records: 81
+Same-key-read: 5
+Delete records: 912
+Locking used
+blobs used
+test2 -L -K -W -P -m50 -l
+- Creating isam-file
+- Writing key:s
+- Delete
+- Update
+- Same key: first - next -> last - prev -> first
+- All keys: first - next -> last - prev -> first
+- Test if: Read first - next - prev - prev - next == first
+- Test if: Read last - prev - next - next - prev == last
+- Test read key-part
+- Test if: Read rrnd - same
+- Test ni_records_in_range
+- ni_info
+- ni_extra(CACHE) + ni_rrnd.... + ni_extra(NO_CACHE)
+- Removing keys
+
+Following test have been made:
+Write records: 50
+Update records: 5
+Same-key-read: 2
+Delete records: 50
+Key cacheing used
+Write cacheing used
+Locking used
+Commands Used count Errors Recover errors
+open 3 0 0
+write 150 0 0
+update 15 0 0
+delete 150 0 0
+close 3 0 0
+extra 18 0 0
+Total 339 0 0
+test2 -L -K -W -P -m50 -l -b100
+- Creating isam-file
+- Writing key:s
+- Delete
+- Update
+- Same key: first - next -> last - prev -> first
+- All keys: first - next -> last - prev -> first
+- Test if: Read first - next - prev - prev - next == first
+- Test if: Read last - prev - next - next - prev == last
+- Test read key-part
+- Test if: Read rrnd - same
+- Test ni_records_in_range
+- ni_info
+- ni_extra(CACHE) + ni_rrnd.... + ni_extra(NO_CACHE)
+- Removing keys
+
+Following test have been made:
+Write records: 50
+Update records: 5
+Same-key-read: 2
+Delete records: 50
+Key cacheing used
+Write cacheing used
+Locking used
+Commands Used count Errors Recover errors
+open 4 0 0
+write 200 0 0
+update 20 0 0
+delete 200 0 0
+close 4 0 0
+extra 24 0 0
+Total 452 0 0
+time test2
+- Creating isam-file
+- Writing key:s
+- Delete
+- Update
+- Same key: first - next -> last - prev -> first
+- All keys: first - next -> last - prev -> first
+- Test if: Read first - next - prev - prev - next == first
+- Test if: Read last - prev - next - next - prev == last
+- Test read key-part
+- Read key (first) - next - delete - next -> last
+- Read last of key - prev - delete - prev -> first
+- Test if: Read rrnd - same
+- Test ni_records_in_range
+- ni_info
+- ni_extra(CACHE) + ni_rrnd.... + ni_extra(NO_CACHE)
+- Removing keys
+
+Following test have been made:
+Write records: 915
+Update records: 82
+Same-key-read: 6
+Delete records: 915
+4.77user 6.81system 0:15.07elapsed 76%CPU (0avgtext+0avgdata 0maxresident)k
+0inputs+0outputs (0major+0minor)pagefaults 0swaps
+time test2 -K
+- Creating isam-file
+- Writing key:s
+- Delete
+- Update
+- Same key: first - next -> last - prev -> first
+- All keys: first - next -> last - prev -> first
+- Test if: Read first - next - prev - prev - next == first
+- Test if: Read last - prev - next - next - prev == last
+- Test read key-part
+- Read key (first) - next - delete - next -> last
+- Read last of key - prev - delete - prev -> first
+- Test if: Read rrnd - same
+- Test ni_records_in_range
+- ni_info
+- ni_extra(CACHE) + ni_rrnd.... + ni_extra(NO_CACHE)
+- Removing keys
+
+Following test have been made:
+Write records: 915
+Update records: 82
+Same-key-read: 6
+Delete records: 915
+Key cacheing used
+6.09user 4.33system 0:11.66elapsed 89%CPU (0avgtext+0avgdata 0maxresident)k
+0inputs+0outputs (0major+0minor)pagefaults 0swaps
+time test2 -L
+- Creating isam-file
+- Writing key:s
+- Delete
+- Update
+- Same key: first - next -> last - prev -> first
+- All keys: first - next -> last - prev -> first
+- Test if: Read first - next - prev - prev - next == first
+- Test if: Read last - prev - next - next - prev == last
+- Test read key-part
+- Read key (first) - next - delete - next -> last
+- Read last of key - prev - delete - prev -> first
+- Test if: Read rrnd - same
+- Test ni_records_in_range
+- ni_info
+- ni_extra(CACHE) + ni_rrnd.... + ni_extra(NO_CACHE)
+- Removing keys
+
+Following test have been made:
+Write records: 915
+Update records: 82
+Same-key-read: 6
+Delete records: 915
+Locking used
+5.01user 5.20system 0:10.86elapsed 94%CPU (0avgtext+0avgdata 0maxresident)k
+0inputs+0outputs (0major+0minor)pagefaults 0swaps
+time test2 -L -K
+- Creating isam-file
+- Writing key:s
+- Delete
+- Update
+- Same key: first - next -> last - prev -> first
+- All keys: first - next -> last - prev -> first
+- Test if: Read first - next - prev - prev - next == first
+- Test if: Read last - prev - next - next - prev == last
+- Test read key-part
+- Read key (first) - next - delete - next -> last
+- Read last of key - prev - delete - prev -> first
+- Test if: Read rrnd - same
+- Test ni_records_in_range
+- ni_info
+- ni_extra(CACHE) + ni_rrnd.... + ni_extra(NO_CACHE)
+- Removing keys
+
+Following test have been made:
+Write records: 915
+Update records: 82
+Same-key-read: 6
+Delete records: 915
+Key cacheing used
+Locking used
+5.63user 0.97system 0:07.85elapsed 84%CPU (0avgtext+0avgdata 0maxresident)k
+0inputs+0outputs (0major+0minor)pagefaults 0swaps
+time test2 -L -K -W
+- Creating isam-file
+- Writing key:s
+- Delete
+- Update
+- Same key: first - next -> last - prev -> first
+- All keys: first - next -> last - prev -> first
+- Test if: Read first - next - prev - prev - next == first
+- Test if: Read last - prev - next - next - prev == last
+- Test read key-part
+- Read key (first) - next - delete - next -> last
+- Read last of key - prev - delete - prev -> first
+- Test if: Read rrnd - same
+- Test ni_records_in_range
+- ni_info
+- ni_extra(CACHE) + ni_rrnd.... + ni_extra(NO_CACHE)
+- Removing keys
+
+Following test have been made:
+Write records: 915
+Update records: 82
+Same-key-read: 6
+Delete records: 915
+Key cacheing used
+Write cacheing used
+Locking used
+5.28user 1.32system 0:08.86elapsed 74%CPU (0avgtext+0avgdata 0maxresident)k
+0inputs+0outputs (0major+0minor)pagefaults 0swaps
+time test2 -L -K -W -S
+- Creating isam-file
+- Writing key:s
+- Delete
+- Update
+- Same key: first - next -> last - prev -> first
+- All keys: first - next -> last - prev -> first
+- Test if: Read first - next - prev - prev - next == first
+- Test if: Read last - prev - next - next - prev == last
+- Test read key-part
+- Read key (first) - next - delete - next -> last
+- Read last of key - prev - delete - prev -> first
+- Test if: Read rrnd - same
+- Test ni_records_in_range
+- ni_info
+- ni_extra(CACHE) + ni_rrnd.... + ni_extra(NO_CACHE)
+- Removing keys
+
+Following test have been made:
+Write records: 915
+Update records: 82
+Same-key-read: 6
+Delete records: 915
+Key cacheing used
+Write cacheing used
+Locking used
+5.32user 0.62system 0:06.13elapsed 96%CPU (0avgtext+0avgdata 0maxresident)k
+0inputs+0outputs (0major+0minor)pagefaults 0swaps
diff --git a/isam/update.c b/isam/update.c
new file mode 100644
index 00000000000..ffcea740986
--- /dev/null
+++ b/isam/update.c
@@ -0,0 +1,119 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* Uppdaterare nuvarande record i en pisam-databas */
+
+#include "isamdef.h"
+#ifdef __WIN__
+#include <errno.h>
+#endif
+
+ /* Updaterar senaste l{sta record i databasen */
+
+int nisam_update(register N_INFO *info, const byte *oldrec, const byte *newrec)
+{
+ int flag,key_changed,save_errno;
+ reg3 ulong pos;
+ uint i,length;
+ uchar old_key[N_MAX_KEY_BUFF],*new_key;
+ DBUG_ENTER("nisam_update");
+
+ if (!(info->update & HA_STATE_AKTIV))
+ {
+ my_errno=HA_ERR_KEY_NOT_FOUND;
+ DBUG_RETURN(-1);
+ }
+ if (info->s->base.options & HA_OPTION_READ_ONLY_DATA)
+ {
+ my_errno=EACCES;
+ DBUG_RETURN(-1);
+ }
+ pos=info->lastpos;
+#ifndef NO_LOCKING
+ if (_nisam_readinfo(info,F_WRLCK,1)) DBUG_RETURN(-1);
+#endif
+ if ((*info->s->compare_record)(info,oldrec))
+ {
+ save_errno=my_errno;
+ goto err_end; /* Record has changed */
+ }
+ if (info->s->state.key_file_length >=
+ info->s->base.max_key_file_length -
+ info->s->blocksize* INDEX_BLOCK_MARGIN *info->s->state.keys)
+ {
+ my_errno=HA_ERR_INDEX_FILE_FULL;
+ goto err_end;
+ }
+
+ /* Flyttar de element i isamfilen som m}ste flyttas */
+
+ new_key=info->lastkey+info->s->base.max_key_length;
+ key_changed=HA_STATE_KEY_CHANGED; /* We changed current database */
+ /* Remove key that didn't change */
+ for (i=0 ; i < info->s->state.keys ; i++)
+ {
+ length=_nisam_make_key(info,i,new_key,newrec,pos);
+ if (length != _nisam_make_key(info,i,old_key,oldrec,pos) ||
+ memcmp((byte*) old_key,(byte*) new_key,length))
+ {
+ if ((int) i == info->lastinx)
+ key_changed|=HA_STATE_WRITTEN; /* Mark that keyfile changed */
+ if (_nisam_ck_delete(info,i,old_key)) goto err;
+ if (_nisam_ck_write(info,i,new_key)) goto err;
+ }
+ }
+
+ if ((*info->s->update_record)(info,pos,newrec))
+ goto err;
+
+ info->update= (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED | HA_STATE_AKTIV |
+ key_changed);
+ nisam_log_record(LOG_UPDATE,info,newrec,info->lastpos,0);
+ VOID(_nisam_writeinfo(info,test(key_changed)));
+ allow_break(); /* Allow SIGHUP & SIGINT */
+ DBUG_RETURN(0);
+
+err:
+ DBUG_PRINT("error",("key: %d errno: %d",i,my_errno));
+ save_errno=my_errno;
+ if (my_errno == HA_ERR_FOUND_DUPP_KEY || my_errno == HA_ERR_RECORD_FILE_FULL)
+ {
+ info->errkey= (int) i;
+ flag=0;
+ do
+ {
+ length=_nisam_make_key(info,i,new_key,newrec,pos);
+ if (length != _nisam_make_key(info,i,old_key,oldrec,pos) ||
+ memcmp((byte*) old_key,(byte*) new_key,length))
+ {
+ if ((flag++ && _nisam_ck_delete(info,i,new_key)) ||
+ _nisam_ck_write(info,i,old_key))
+ break;
+ }
+ } while (i-- != 0);
+ }
+ info->update= (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED | HA_STATE_AKTIV |
+ key_changed);
+ err_end:
+ nisam_log_record(LOG_UPDATE,info,newrec,info->lastpos,my_errno);
+ VOID(_nisam_writeinfo(info,1));
+ allow_break(); /* Allow SIGHUP & SIGINT */
+ if (save_errno == HA_ERR_KEY_NOT_FOUND)
+ my_errno=HA_ERR_CRASHED;
+ else
+ my_errno=save_errno;
+ DBUG_RETURN(-1);
+} /* nisam_update */
diff --git a/isam/write.c b/isam/write.c
new file mode 100644
index 00000000000..110dc70fe53
--- /dev/null
+++ b/isam/write.c
@@ -0,0 +1,840 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* Skriver ett record till en isam-databas */
+
+#include "isamdef.h"
+#ifdef __WIN__
+#include <errno.h>
+#endif
+
+ /* Functions declared in this file */
+
+static int w_search(N_INFO *info,N_KEYDEF *keyinfo,uchar *key,
+ ulong pos, uchar *father_buff, uchar *father_keypos,
+ ulong father_page);
+static int _nisam_balance_page(N_INFO *info,N_KEYDEF *keyinfo,uchar *key,
+ uchar *curr_buff,uchar *father_buff,
+ uchar *father_keypos,ulong father_page);
+
+
+ /* Write new record to database */
+
+int nisam_write(N_INFO *info, const byte *record)
+{
+ uint i;
+ ulong filepos;
+ uchar *buff;
+ DBUG_ENTER("nisam_write");
+ DBUG_PRINT("enter",("isam: %d data: %d",info->s->kfile,info->dfile));
+
+ if (info->s->base.options & HA_OPTION_READ_ONLY_DATA)
+ {
+ my_errno=EACCES;
+ DBUG_RETURN(-1);
+ }
+#ifndef NO_LOCKING
+ if (_nisam_readinfo(info,F_WRLCK,1)) DBUG_RETURN(-1);
+#endif
+ dont_break(); /* Dont allow SIGHUP or SIGINT */
+#if !defined(NO_LOCKING) && defined(USE_RECORD_LOCK)
+ if (!info->locked && my_lock(info->dfile,F_WRLCK,0L,F_TO_EOF,
+ MYF(MY_SEEK_NOT_DONE) | info->lock_wait))
+ goto err;
+#endif
+ filepos= ((info->s->state.dellink != NI_POS_ERROR) ?
+ info->s->state.dellink :
+ info->s->state.data_file_length);
+
+ if (info->s->base.reloc == 1L && info->s->base.records == 1L &&
+ info->s->state.records == 1L)
+ { /* System file */
+ my_errno=HA_ERR_RECORD_FILE_FULL;
+ goto err2;
+ }
+ if (info->s->state.key_file_length >=
+ info->s->base.max_key_file_length -
+ info->s->blocksize* INDEX_BLOCK_MARGIN *info->s->state.keys)
+ {
+ my_errno=HA_ERR_INDEX_FILE_FULL;
+ goto err2;
+ }
+
+ /* Write all keys to indextree */
+ buff=info->lastkey+info->s->base.max_key_length;
+ for (i=0 ; i < info->s->state.keys ; i++)
+ {
+ VOID(_nisam_make_key(info,i,buff,record,filepos));
+ if (_nisam_ck_write(info,i,buff)) goto err;
+ }
+
+ if ((*info->s->write_record)(info,record))
+ goto err;
+
+ info->update= (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED |HA_STATE_AKTIV |
+ HA_STATE_WRITTEN);
+ info->s->state.records++;
+ info->lastpos=filepos;
+ nisam_log_record(LOG_WRITE,info,record,filepos,0);
+ VOID(_nisam_writeinfo(info,1));
+ allow_break(); /* Allow SIGHUP & SIGINT */
+ DBUG_RETURN(0);
+
+err:
+ if (my_errno == HA_ERR_FOUND_DUPP_KEY || my_errno == HA_ERR_RECORD_FILE_FULL)
+ {
+ info->errkey= (int) i;
+ while ( i-- > 0)
+ {
+ VOID(_nisam_make_key(info,i,buff,record,filepos));
+ if (_nisam_ck_delete(info,i,buff))
+ break;
+ }
+ }
+ info->update=(HA_STATE_CHANGED | HA_STATE_ROW_CHANGED | HA_STATE_WRITTEN);
+err2:
+ nisam_log_record(LOG_WRITE,info,record,filepos,my_errno);
+ VOID(_nisam_writeinfo(info,1));
+ allow_break(); /* Allow SIGHUP & SIGINT */
+ DBUG_RETURN(-1);
+} /* nisam_write */
+
+
+ /* Write one key to btree */
+
+int _nisam_ck_write(register N_INFO *info, uint keynr, uchar *key)
+{
+ int error;
+ DBUG_ENTER("_nisam_ck_write");
+
+ if ((error=w_search(info,info->s->keyinfo+keynr,key,
+ info->s->state.key_root[keynr], (uchar *) 0, (uchar*) 0,
+ 0L)) > 0)
+ error=_nisam_enlarge_root(info,keynr,key);
+ DBUG_RETURN(error);
+} /* _nisam_ck_write */
+
+
+ /* Make a new root with key as only pointer */
+
+int _nisam_enlarge_root(register N_INFO *info, uint keynr, uchar *key)
+{
+ uint t_length,nod_flag;
+ reg2 N_KEYDEF *keyinfo;
+ S_PARAM s_temp;
+ ISAM_SHARE *share=info->s;
+ DBUG_ENTER("_nisam_enlarge_root");
+
+ info->page_changed=1;
+ nod_flag= (share->state.key_root[keynr] != NI_POS_ERROR) ?
+ share->base.key_reflength : 0;
+ _nisam_kpointer(info,info->buff+2,share->state.key_root[keynr]); /* if nod */
+ keyinfo=share->keyinfo+keynr;
+ t_length=_nisam_get_pack_key_length(keyinfo,nod_flag,(uchar*) 0,(uchar*) 0,
+ key,&s_temp);
+ putint(info->buff,t_length+2+nod_flag,nod_flag);
+ _nisam_store_key(keyinfo,info->buff+2+nod_flag,&s_temp);
+ if ((share->state.key_root[keynr]= _nisam_new(info,keyinfo)) ==
+ NI_POS_ERROR ||
+ _nisam_write_keypage(info,keyinfo,share->state.key_root[keynr],info->buff))
+ DBUG_RETURN(-1);
+ DBUG_RETURN(0);
+} /* _nisam_enlarge_root */
+
+
+ /* S|ker reda p} vart nyckeln skall s{ttas och placerar den dit */
+ /* Returnerar -1 om fel ; 0 om ok. 1 om nyckel propagerar upp}t */
+
+static int w_search(register N_INFO *info, register N_KEYDEF *keyinfo,
+ uchar *key, ulong page, uchar *father_buff,
+ uchar *father_keypos, ulong father_page)
+{
+ int error,flag;
+ uint comp_flag,nod_flag;
+ uchar *temp_buff,*keypos;
+ uchar keybuff[N_MAX_KEY_BUFF];
+ DBUG_ENTER("w_search");
+ DBUG_PRINT("enter",("page: %ld",page));
+
+ if (page == NI_POS_ERROR)
+ DBUG_RETURN(1); /* No key, make new */
+
+ if (keyinfo->base.flag & HA_SORT_ALLOWS_SAME)
+ comp_flag=SEARCH_BIGGER; /* Put after same key */
+ else if (keyinfo->base.flag & HA_NOSAME)
+ comp_flag=SEARCH_FIND; /* No dupplicates */
+ else
+ comp_flag=SEARCH_SAME; /* Keys in rec-pos order */
+
+ if (!(temp_buff= (uchar*) my_alloca((uint) keyinfo->base.block_length+
+ N_MAX_KEY_BUFF)))
+ DBUG_RETURN(-1);
+ if (!_nisam_fetch_keypage(info,keyinfo,page,temp_buff,0))
+ goto err;
+
+ flag=(*keyinfo->bin_search)(info,keyinfo,temp_buff,key,0,comp_flag,&keypos,
+ keybuff);
+ nod_flag=test_if_nod(temp_buff);
+ if (flag == 0)
+ {
+ my_errno=HA_ERR_FOUND_DUPP_KEY;
+ /* get position to record with dupplicated key */
+ VOID((*keyinfo->get_key)(keyinfo,nod_flag,&keypos,keybuff));
+ info->dupp_key_pos=_nisam_dpos(info,test_if_nod(temp_buff),keypos);
+ my_afree((byte*) temp_buff);
+ DBUG_RETURN(-1);
+ }
+ if ((error=w_search(info,keyinfo,key,_nisam_kpos(nod_flag,keypos),
+ temp_buff,keypos,page)) >0)
+ {
+ error=_nisam_insert(info,keyinfo,key,temp_buff,keypos,keybuff,father_buff,
+ father_keypos,father_page);
+ if (_nisam_write_keypage(info,keyinfo,page,temp_buff))
+ goto err;
+ }
+ my_afree((byte*) temp_buff);
+ DBUG_RETURN(error);
+err:
+ my_afree((byte*) temp_buff);
+ DBUG_PRINT("exit",("Error: %d",my_errno));
+ DBUG_RETURN (-1);
+} /* w_search */
+
+
+ /* Insert new key at right of key_pos */
+ /* Returns 2 if key contains key to upper level */
+
+int _nisam_insert(register N_INFO *info, register N_KEYDEF *keyinfo,
+ uchar *key, uchar *anc_buff, uchar *key_pos, uchar *key_buff,
+ uchar *father_buff, uchar *father_key_pos, ulong father_page)
+{
+ uint a_length,t_length,nod_flag;
+ uchar *endpos;
+ int key_offset;
+ S_PARAM s_temp;
+ DBUG_ENTER("_nisam_insert");
+ DBUG_PRINT("enter",("key_pos: %lx",key_pos));
+ DBUG_EXECUTE("key",_nisam_print_key(DBUG_FILE,keyinfo->seg,key););
+
+ nod_flag=test_if_nod(anc_buff);
+ a_length=getint(anc_buff);
+ endpos= anc_buff+ a_length;
+ t_length=_nisam_get_pack_key_length(keyinfo,nod_flag,
+ (key_pos == endpos ? (uchar*) 0 : key_pos),
+ (key_pos == anc_buff+2+nod_flag ?
+ (uchar*) 0 : key_buff),key,&s_temp);
+#ifndef DBUG_OFF
+ if (key_pos != anc_buff+2+nod_flag)
+ DBUG_DUMP("prev_key",(byte*) key_buff,_nisam_keylength(keyinfo,key_buff));
+ if (keyinfo->base.flag & HA_PACK_KEY)
+ {
+ DBUG_PRINT("test",("t_length: %d ref_len: %d",
+ t_length,s_temp.ref_length));
+ DBUG_PRINT("test",("n_ref_len: %d n_length: %d key: %lx",
+ s_temp.n_ref_length,s_temp.n_length,s_temp.key));
+ }
+#endif
+ key_offset = (endpos-key_pos);
+ if((int) t_length < 0)
+ key_offset += (int) t_length;
+ if (key_offset < 0)
+ {
+ DBUG_PRINT("error",("Found a bug: negative key_offset %d\n", key_offset));
+ DBUG_RETURN(-1);
+ }
+ if ((int) t_length >= 0) /* t_length is almost always > 0 */
+ bmove_upp((byte*) endpos+t_length,(byte*) endpos,(uint)key_offset );
+ else
+ {
+ /* This may happen if a key was deleted and the next key could be
+ compressed better than before */
+ DBUG_DUMP("anc_buff",(byte*) anc_buff,a_length);
+
+ bmove(key_pos,key_pos - (int) t_length,(uint)key_offset);
+ }
+ _nisam_store_key(keyinfo,key_pos,&s_temp);
+ a_length+=t_length;
+ putint(anc_buff,a_length,nod_flag);
+ if (a_length <= keyinfo->base.block_length)
+ DBUG_RETURN(0); /* There is room on page */
+
+ /* Page is full */
+
+ if (!(keyinfo->base.flag & (HA_PACK_KEY | HA_SPACE_PACK_USED)) &&
+ father_buff)
+ DBUG_RETURN(_nisam_balance_page(info,keyinfo,key,anc_buff,father_buff,
+ father_key_pos,father_page));
+ DBUG_RETURN(_nisam_splitt_page(info,keyinfo,key,anc_buff,key_buff));
+} /* _nisam_insert */
+
+
+ /* splitt a full page in two and assign emerging item to key */
+
+int _nisam_splitt_page(register N_INFO *info, register N_KEYDEF *keyinfo,
+ uchar *key, uchar *buff, uchar *key_buff)
+{
+ uint length,a_length,key_ref_length,t_length,nod_flag;
+ uchar *key_pos,*pos;
+ ulong new_pos;
+ S_PARAM s_temp;
+ DBUG_ENTER("ni_splitt_page");
+ DBUG_DUMP("buff",(byte*) buff,getint(buff));
+
+ nod_flag=test_if_nod(buff);
+ key_ref_length=2+nod_flag;
+ key_pos=_nisam_find_half_pos(info,keyinfo,buff,key_buff);
+ length=(uint) (key_pos-buff);
+ a_length=getint(buff);
+ putint(buff,length,nod_flag);
+ info->page_changed=1;
+
+ /* Correct new page pointer */
+ VOID((*keyinfo->get_key)(keyinfo,nod_flag,&key_pos,key_buff));
+ if (nod_flag)
+ {
+ DBUG_PRINT("test",("Splitting nod"));
+ pos=key_pos-nod_flag;
+ memcpy((byte*) info->buff+2,(byte*) pos,(size_t) nod_flag);
+ }
+
+ /* Move midle item to key and pointer to new page */
+ if ((new_pos=_nisam_new(info,keyinfo)) == NI_POS_ERROR)
+ DBUG_RETURN(-1);
+ _nisam_kpointer(info,_nisam_move_key(keyinfo,key,key_buff),new_pos);
+
+ /* Store new page */
+ VOID((*keyinfo->get_key)(keyinfo,nod_flag,&key_pos,key_buff));
+ t_length=_nisam_get_pack_key_length(keyinfo,nod_flag,(uchar *) 0, (uchar*) 0,
+ key_buff, &s_temp);
+ s_temp.n_length= *key_pos; /* Needed by ni_store_key */
+ length=(uint) ((buff+a_length)-key_pos);
+ memcpy((byte*) info->buff+key_ref_length+t_length,(byte*) key_pos,
+ (size_t) length);
+ _nisam_store_key(keyinfo,info->buff+key_ref_length,&s_temp);
+ putint(info->buff,length+t_length+key_ref_length,nod_flag);
+
+ if (_nisam_write_keypage(info,keyinfo,new_pos,info->buff))
+ DBUG_RETURN(-1);
+ DBUG_DUMP("key",(byte*) key,_nisam_keylength(keyinfo,key));
+ DBUG_RETURN(2); /* Middle key up */
+} /* _nisam_splitt_page */
+
+
+ /* find out how much more room a key will take */
+
+#ifdef QQ
+uint _nisam_get_pack_key_length(N_KEYDEF *keyinfo, uint nod_flag, uchar *key_pos, uchar *key_buff, uchar *key, S_PARAM *s_temp)
+
+ /* If nod: Length of nod-pointer */
+ /* Position to pos after key in buff */
+ /* Last key before current key */
+ /* Current key */
+ /* How next key will be packed */
+{
+ reg1 N_KEYSEG *keyseg;
+ int length;
+ uint key_length,ref_length,n_length,diff_flag,same_length;
+ uchar *start,*end,*key_end;
+
+ s_temp->key=key;
+ if (!(keyinfo->base.flag & HA_PACK_KEY))
+ return (s_temp->totlength=_nisam_keylength(keyinfo,key)+nod_flag);
+ s_temp->ref_length=s_temp->n_ref_length=s_temp->n_length=0;
+ s_temp->prev_length=0;
+
+ same_length=0; keyseg=keyinfo->seg;
+ key_length=_nisam_keylength(keyinfo,key)+nod_flag;
+
+ if (keyseg->base.flag & HA_SPACE_PACK)
+ {
+ diff_flag=1;
+ end=key_end= key+ *key+1;
+ if (key_buff)
+ {
+ if (*key == *key_buff && *key)
+ same_length=1; /* Don't use key-pack if length == 0 */
+ else if (*key > *key_buff)
+ end=key+ *key_buff+1;
+ key_buff++;
+ }
+ key++;
+ }
+ else
+ {
+ diff_flag=0;
+ key_end=end= key+keyseg->base.length;
+ }
+
+ start=key;
+ if (key_buff)
+ while (key < end && *key == *key_buff)
+ {
+ key++; key_buff++;
+ }
+
+ s_temp->key=key; s_temp->key_length= (uint) (key_end-key);
+
+ if (same_length && key == key_end)
+ {
+ s_temp->ref_length=128;
+ length=(int) key_length-(int)(key_end-start); /* Same as prev key */
+ if (key_pos)
+ {
+ s_temp->n_length= *key_pos;
+ key_pos=0; /* Can't combine with next */
+ }
+ }
+ else
+ {
+ if (start != key)
+ { /* Starts as prev key */
+ s_temp->ref_length= (uint) (key-start)+128;
+ length=(int) (1+key_length-(uint) (key-start));
+ }
+ else
+ length=(int) (key_length+ (1-diff_flag)); /* Not packed key */
+ }
+ s_temp->totlength=(uint) length;
+
+ DBUG_PRINT("test",("tot_length: %d length: %d uniq_key_length: %d",
+ key_length,length,s_temp->key_length));
+
+ /* If something after that is not 0 length test if we can combine */
+
+ if (key_pos && (n_length= *key_pos))
+ {
+ key_pos++;
+ ref_length=0;
+ if (n_length & 128)
+ {
+ if ((ref_length=n_length & 127))
+ if (diff_flag)
+ n_length= *key_pos++; /* Length of key-part */
+ else
+ n_length=keyseg->base.length - ref_length;
+ }
+ else
+ if (*start == *key_pos && diff_flag && start != key_end)
+ length++; /* One new pos for ref.len */
+
+ DBUG_PRINT("test",("length: %d key_pos: %lx",length,key_pos));
+ if (n_length != 128)
+ { /* Not same key after */
+ key=start+ref_length;
+ while (n_length > 0 && key < key_end && *key == *key_pos)
+ {
+ key++; key_pos++;
+ ref_length++;
+ n_length--;
+ length--; /* We gained one char */
+ }
+
+ if (n_length == 0 && diff_flag)
+ {
+ n_length=128; /* Same as prev key */
+ length--; /* We don't need key-length */
+ }
+ else if (ref_length)
+ s_temp->n_ref_length=ref_length | 128;
+ }
+ s_temp->n_length=n_length;
+ }
+ return (uint) length;
+} /* _nisam_get_pack_key_length */
+
+#else
+
+uint
+_nisam_get_pack_key_length(N_KEYDEF *keyinfo,
+ uint nod_flag, /* If nod: Length of nod-pointer */
+ uchar *key_pos, /* Position to pos after key in buff */
+ uchar *key_buff,/* Last key before current key */
+ uchar *key, /* Current key */
+ S_PARAM *s_temp/* How next key will be packed */
+ )
+{
+ reg1 N_KEYSEG *keyseg;
+ int length;
+ uint key_length,ref_length,n_length,diff_flag,same_length,org_key_length=0;
+ uchar *start,*end,*key_end;
+
+ s_temp->key=key;
+ if (!(keyinfo->base.flag & HA_PACK_KEY))
+ return (s_temp->totlength=_nisam_keylength(keyinfo,key)+nod_flag);
+ s_temp->ref_length=s_temp->n_ref_length=s_temp->n_length=0;
+
+ same_length=0; keyseg=keyinfo->seg;
+ key_length=_nisam_keylength(keyinfo,key)+nod_flag;
+ s_temp->prev_key=key_buff;
+
+ if (keyseg->base.flag & HA_SPACE_PACK)
+ {
+ diff_flag=1;
+ end=key_end= key+ *key+1;
+ if (key_buff)
+ {
+ org_key_length= (uint) *key_buff;
+ if (*key == *key_buff && *key)
+ same_length=1; /* Don't use key-pack if length == 0 */
+ else if (*key > *key_buff)
+ end=key+ org_key_length+1;
+ key_buff++;
+ }
+ key++;
+ }
+ else
+ {
+ diff_flag=0;
+ key_end=end= key+(org_key_length=keyseg->base.length);
+ }
+
+ start=key;
+ if (key_buff)
+ while (key < end && *key == *key_buff)
+ {
+ key++; key_buff++;
+ }
+
+ s_temp->key=key; s_temp->key_length= (uint) (key_end-key);
+
+ if (same_length && key == key_end)
+ {
+ s_temp->ref_length=128;
+ length=(int) key_length-(int)(key_end-start); /* Same as prev key */
+ if (key_pos)
+ { /* Can't combine with next */
+ s_temp->n_length= *key_pos; /* Needed by _nisam_store_key */
+ key_pos=0;
+ }
+ }
+ else
+ {
+ if (start != key)
+ { /* Starts as prev key */
+ s_temp->ref_length= (uint) (key-start)+128;
+ length=(int) (1+key_length-(uint) (key-start));
+ }
+ else
+ length=(int) (key_length+ (1-diff_flag)); /* Not packed key */
+ }
+ s_temp->totlength=(uint) length;
+ s_temp->prev_length=0;
+ DBUG_PRINT("test",("tot_length: %d length: %d uniq_key_length: %d",
+ key_length,length,s_temp->key_length));
+
+ /* If something after that is not 0 length test if we can combine */
+
+ if (key_pos && (n_length= *key_pos++))
+ {
+ if (n_length == 128)
+ {
+ /*
+ We put a different key between two identical keys
+ Extend next key to have same prefix as this key
+ */
+ if (s_temp->ref_length)
+ { /* make next key longer */
+ s_temp->part_of_prev_key= s_temp->ref_length;
+ s_temp->prev_length= org_key_length - (s_temp->ref_length-128);
+ s_temp->n_length= s_temp->prev_length;
+ s_temp->prev_key+= diff_flag + (s_temp->ref_length - 128);
+ length+= s_temp->prev_length+diff_flag;
+ }
+ else
+ { /* Can't use prev key */
+ s_temp->part_of_prev_key=0;
+ s_temp->prev_length= org_key_length;
+ s_temp->n_length= org_key_length;
+ s_temp->prev_key+= diff_flag; /* To start of key */
+ length+= org_key_length;
+ }
+ return (uint) length;
+ }
+
+ if (n_length & 128)
+ {
+ ref_length=n_length & 127;
+ if (diff_flag) /* If SPACE_PACK */
+ n_length= *key_pos++; /* Length of key-part */
+ else
+ n_length=keyseg->base.length - ref_length;
+
+ /* Test if new keys has fewer characters that match the previous key */
+ if (!s_temp->ref_length)
+ { /* Can't use prev key */
+ s_temp->part_of_prev_key= 0;
+ s_temp->prev_length= ref_length;
+ s_temp->n_length= n_length+ref_length;
+ s_temp->prev_key+= diff_flag; /* To start of key */
+ return (uint) length+ref_length-diff_flag;
+ }
+ if (ref_length+128 > s_temp->ref_length)
+ {
+ /* We must copy characters from the original key to the next key */
+ s_temp->part_of_prev_key= s_temp->ref_length;
+ s_temp->prev_length= ref_length+128 - s_temp->ref_length;
+ s_temp->n_length= n_length + s_temp->prev_length;
+ s_temp->prev_key+= diff_flag + s_temp->ref_length -128;
+ return (uint) length + s_temp->prev_length;
+ }
+ }
+ else
+ {
+ ref_length=0;
+ if (*start == *key_pos && diff_flag && start != key_end)
+ length++; /* One new pos for ref.len */
+ }
+ DBUG_PRINT("test",("length: %d key_pos: %lx",length,key_pos));
+
+ key=start+ref_length;
+ while (n_length > 0 && key < key_end && *key == *key_pos)
+ {
+ key++; key_pos++;
+ ref_length++;
+ n_length--;
+ length--; /* We gained one char */
+ }
+
+ if (n_length == 0 && diff_flag)
+ {
+ n_length=128; /* Same as prev key */
+ length--; /* We don't need key-length */
+ }
+ else if (ref_length)
+ s_temp->n_ref_length=ref_length | 128;
+ s_temp->n_length=n_length;
+ }
+ return (uint) length;
+} /* _nisam_get_pack_key_length */
+#endif
+
+
+ /* store a key in page-buffert */
+
+void _nisam_store_key(N_KEYDEF *keyinfo, register uchar *key_pos,
+ register S_PARAM *s_temp)
+{
+ uint length;
+ uchar *start;
+
+ if (! (keyinfo->base.flag & HA_PACK_KEY))
+ {
+ memcpy((byte*) key_pos,(byte*) s_temp->key,(size_t) s_temp->totlength);
+ return;
+ }
+ start=key_pos;
+ if ((*key_pos=(uchar) s_temp->ref_length))
+ key_pos++;
+ if (s_temp->ref_length == 0 ||
+ (s_temp->ref_length > 128 &&
+ (keyinfo->seg[0].base.flag & HA_SPACE_PACK)))
+ *key_pos++= (uchar) s_temp->key_length;
+ bmove((byte*) key_pos,(byte*) s_temp->key,
+ (length=s_temp->totlength-(uint) (key_pos-start)));
+ key_pos+=length;
+
+ if (s_temp->prev_length)
+ {
+ /* Extend next key because new key didn't have same prefix as prev key */
+ if (s_temp->part_of_prev_key)
+ *key_pos++ = s_temp->part_of_prev_key;
+ if (keyinfo->seg[0].base.flag & HA_SPACE_PACK)
+ *key_pos++= s_temp->n_length;
+ memcpy(key_pos, s_temp->prev_key, s_temp->prev_length);
+ return;
+ }
+
+ if ((*key_pos = (uchar) s_temp->n_ref_length))
+ {
+ if (! (keyinfo->seg[0].base.flag & HA_SPACE_PACK))
+ return; /* Don't save keylength */
+ key_pos++; /* Store ref for next key */
+ }
+ *key_pos = (uchar) s_temp->n_length;
+ return;
+} /* _nisam_store_key */
+
+
+ /* Calculate how to much to move to split a page in two */
+ /* Returns pointer and key for get_key() to get mid key */
+ /* There is at last 2 keys after pointer in buff */
+
+uchar *_nisam_find_half_pos(N_INFO *info, N_KEYDEF *keyinfo, uchar *page, uchar *key)
+{
+ uint keys,length,key_ref_length,nod_flag;
+ uchar *end,*lastpos;
+ DBUG_ENTER("_nisam_find_half_pos");
+
+ nod_flag=test_if_nod(page);
+ key_ref_length=2+nod_flag;
+ length=getint(page)-key_ref_length;
+ page+=key_ref_length;
+ if (!(keyinfo->base.flag & (HA_PACK_KEY | HA_SPACE_PACK_USED)))
+ {
+ keys=(length/(keyinfo->base.keylength+nod_flag))/2;
+ DBUG_RETURN(page+keys*(keyinfo->base.keylength+nod_flag));
+ }
+
+ end=page+length/2-key_ref_length; /* This is aprox. half */
+ *key='\0';
+ do
+ {
+ lastpos=page;
+ VOID((*keyinfo->get_key)(keyinfo,nod_flag,&page,key));
+ } while (page < end);
+
+ DBUG_PRINT("exit",("returns: %lx page: %lx half: %lx",lastpos,page,end));
+ DBUG_RETURN(lastpos);
+} /* _nisam_find_half_pos */
+
+
+ /* Balance page with not packed keys with page on right/left */
+ /* returns 0 if balance was done */
+
+static int _nisam_balance_page(register N_INFO *info, N_KEYDEF *keyinfo,
+ uchar *key, uchar *curr_buff, uchar *father_buff,
+ uchar *father_key_pos, ulong father_page)
+{
+ my_bool right;
+ uint k_length,father_length,father_keylength,nod_flag,curr_keylength,
+ right_length,left_length,new_right_length,new_left_length,extra_length,
+ length,keys;
+ uchar *pos,*buff,*extra_buff;
+ ulong next_page,new_pos;
+ byte tmp_part_key[N_MAX_KEY_BUFF];
+ DBUG_ENTER("_nisam_balance_page");
+
+ k_length=keyinfo->base.keylength;
+ father_length=getint(father_buff);
+ father_keylength=k_length+info->s->base.key_reflength;
+ nod_flag=test_if_nod(curr_buff);
+ curr_keylength=k_length+nod_flag;
+ info->page_changed=1;
+
+ if ((father_key_pos != father_buff+father_length && (info->s->rnd++ & 1)) ||
+ father_key_pos == father_buff+2+info->s->base.key_reflength)
+ {
+ right=1;
+ next_page= _nisam_kpos(info->s->base.key_reflength,
+ father_key_pos+father_keylength);
+ buff=info->buff;
+ DBUG_PRINT("test",("use right page: %lu",next_page));
+ }
+ else
+ {
+ right=0;
+ father_key_pos-=father_keylength;
+ next_page= _nisam_kpos(info->s->base.key_reflength,father_key_pos);
+ /* Fix that curr_buff is to left */
+ buff=curr_buff; curr_buff=info->buff;
+ DBUG_PRINT("test",("use left page: %lu",next_page));
+ } /* father_key_pos ptr to parting key */
+
+ if (!_nisam_fetch_keypage(info,keyinfo,next_page,info->buff,0))
+ goto err;
+ DBUG_DUMP("next",(byte*) info->buff,getint(info->buff));
+
+ /* Test if there is room to share keys */
+
+ left_length=getint(curr_buff);
+ right_length=getint(buff);
+ keys=(left_length+right_length-4-nod_flag*2)/curr_keylength;
+
+ if ((right ? right_length : left_length) + curr_keylength <=
+ keyinfo->base.block_length)
+ { /* Merge buffs */
+ new_left_length=2+nod_flag+(keys/2)*curr_keylength;
+ new_right_length=2+nod_flag+((keys+1)/2)*curr_keylength;
+ putint(curr_buff,new_left_length,nod_flag);
+ putint(buff,new_right_length,nod_flag);
+
+ if (left_length < new_left_length)
+ { /* Move keys buff -> leaf */
+ pos=curr_buff+left_length;
+ memcpy((byte*) pos,(byte*) father_key_pos, (size_t) k_length);
+ memcpy((byte*) pos+k_length, (byte*) buff+2,
+ (size_t) (length=new_left_length - left_length - k_length));
+ pos=buff+2+length;
+ memcpy((byte*) father_key_pos,(byte*) pos,(size_t) k_length);
+ bmove((byte*) buff+2,(byte*) pos+k_length,new_right_length);
+ }
+ else
+ { /* Move keys -> buff */
+
+ bmove_upp((byte*) buff+new_right_length,(byte*) buff+right_length,
+ right_length-2);
+ length=new_right_length-right_length-k_length;
+ memcpy((byte*) buff+2+length,father_key_pos,(size_t) k_length);
+ pos=curr_buff+new_left_length;
+ memcpy((byte*) father_key_pos,(byte*) pos,(size_t) k_length);
+ memcpy((byte*) buff+2,(byte*) pos+k_length,(size_t) length);
+ }
+
+ if (_nisam_write_keypage(info,keyinfo,next_page,info->buff) ||
+ _nisam_write_keypage(info,keyinfo,father_page,father_buff))
+ goto err;
+ DBUG_RETURN(0);
+ }
+
+ /* curr_buff[] and buff[] are full, lets splitt and make new nod */
+
+ extra_buff=info->buff+info->s->base.max_block;
+ new_left_length=new_right_length=2+nod_flag+(keys+1)/3*curr_keylength;
+ if (keys == 5) /* Too few keys to balance */
+ new_left_length-=curr_keylength;
+ extra_length=nod_flag+left_length+right_length-new_left_length-new_right_length-curr_keylength;
+ DBUG_PRINT("info",("left_length: %d right_length: %d new_left_length: %d new_right_length: %d extra_length: %d",
+ left_length, right_length,
+ new_left_length, new_right_length,
+ extra_length));
+ putint(curr_buff,new_left_length,nod_flag);
+ putint(buff,new_right_length,nod_flag);
+ putint(extra_buff,extra_length+2,nod_flag);
+
+ /* move first largest keys to new page */
+ pos=buff+right_length-extra_length;
+ memcpy((byte*) extra_buff+2,pos,(size_t) extra_length);
+
+ /* Save new parting key */
+ memcpy(tmp_part_key, pos-k_length,k_length);
+
+ /* Make place for new keys */
+ bmove_upp((byte*) buff+new_right_length,(byte*) pos-k_length,
+ right_length-extra_length-k_length-2);
+ /* Copy keys from left page */
+ pos= curr_buff+new_left_length;
+ memcpy((byte*) buff+2,(byte*) pos+k_length,
+ (size_t) (length=left_length-new_left_length-k_length));
+ /* Copy old parting key */
+ memcpy((byte*) buff+2+length,father_key_pos,(size_t) k_length);
+
+ /* Move new parting keys up */
+ memcpy((byte*) (right ? key : father_key_pos),pos, (size_t) k_length);
+ memcpy((byte*) (right ? father_key_pos : key), tmp_part_key, k_length);
+
+ if ((new_pos=_nisam_new(info,keyinfo)) == NI_POS_ERROR)
+ goto err;
+ _nisam_kpointer(info,key+k_length,new_pos);
+ if (_nisam_write_keypage(info,keyinfo,(right ? new_pos : next_page),
+ info->buff) ||
+ _nisam_write_keypage(info,keyinfo,(right ? next_page : new_pos),extra_buff))
+ goto err;
+
+ DBUG_RETURN(1); /* Middle key up */
+
+err:
+ DBUG_RETURN(-1);
+} /* _nisam_balance_page */
diff --git a/libmysql/.cvsignore b/libmysql/.cvsignore
new file mode 100644
index 00000000000..a58235fee47
--- /dev/null
+++ b/libmysql/.cvsignore
@@ -0,0 +1,10 @@
+*.lo
+.deps
+.libs
+Makefile
+Makefile.in
+conf_to_src
+config.status
+configure
+ctype_extra_sources.c
+libmysqlclient.la
diff --git a/libmysql/Makefile.am b/libmysql/Makefile.am
new file mode 100644
index 00000000000..78c52be3d31
--- /dev/null
+++ b/libmysql/Makefile.am
@@ -0,0 +1,149 @@
+# 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)
+INCLUDES = -I$(srcdir)/../include -I../include \
+ -I$(srcdir)/.. -I$(top_srcdir) -I..
+LIBS = @CLIENT_LIBS@
+LDADD = @CLIENT_EXTRA_LDFLAGS@ libmysqlclient.la
+pkglib_LTLIBRARIES = libmysqlclient.la
+
+noinst_PROGRAMS = conf_to_src
+
+# We need .lo, not .o files for everything.
+CHARSET_OBJS=@CHARSET_OBJS@
+LTCHARSET_OBJS= ${CHARSET_OBJS:.o=.lo}
+
+libmysqlclient_la_SOURCES = libmysql.c net.c violite.c password.c \
+ get_password.c errmsg.c
+
+mystringsobjects = strmov.lo strxmov.lo strnmov.lo strmake.lo strend.lo \
+ strnlen.lo strfill.lo is_prefix.lo \
+ int2str.lo str2int.lo strinstr.lo strcont.lo \
+ strcend.lo \
+ bchange.lo bmove.lo bmove_upp.lo longlong2str.lo \
+ strtoull.lo strtoll.lo llstr.lo strto.lo \
+ ctype.lo $(LTCHARSET_OBJS)
+mystringsextra= strto.c ctype_autoconf.c
+dbugobjects = dbug.lo # IT IS IN SAFEMALLOC.C sanity.lo
+mysysheaders = mysys_priv.h my_static.h
+mysysobjects1 = my_init.lo my_static.lo my_malloc.lo my_realloc.lo \
+ my_create.lo my_delete.lo my_tempnam.lo my_open.lo \
+ mf_casecnv.lo my_read.lo my_write.lo errors.lo \
+ my_error.lo my_getwd.lo my_div.lo \
+ mf_pack.lo my_messnc.lo mf_dirname.lo mf_fn_ext.lo\
+ mf_wcomp.lo typelib.lo safemalloc.lo my_alloc.lo \
+ mf_format.lo mf_path.lo mf_unixpath.lo my_fopen.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
+# Not needed in the minimum library
+mysysobjects2 = getopt.lo getopt1.lo getvar.lo my_lib.lo
+mysysobjects = $(mysysobjects1) $(mysysobjects2)
+libmysqlclient_la_LIBADD = $(mysysobjects) $(mystringsobjects) $(dbugobjects)
+libmysqlclient_la_LDFLAGS = -version-info @SHARED_LIB_VERSION@
+CLEANFILES = $(libmysqlclient_la_LIBADD) $(SHLIBOBJS) \
+ libmysqclient.la
+DEFS = -DUNDEF_THREADS_HACK \
+ -DDEFAULT_CHARSET_HOME="\"$(MYSQLBASEdir)\"" \
+ -DDATADIR="\"$(MYSQLDATAdir)\"" \
+ -DSHAREDIR="\"$(MYSQLSHAREdir)\""
+
+# The automatic dependencies miss this
+bmove_upp.lo: $(LTCHARSET_OBJS)
+ctype.c: ctype_extra_sources.c
+
+# This is called from the toplevel makefile
+link_sources:
+ set -x; \
+ ss=`echo $(mystringsobjects) | sed "s;\.lo;.c;g"`; \
+ ds=`echo $(dbugobjects) | sed "s;\.lo;.c;g"`; \
+ ms=`echo $(mysysobjects) | 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 $(mystringsextra); do \
+ rm -f $(srcdir)/$$f; \
+ @LN_CP_F@ $(srcdir)/../strings/$$f $(srcdir)/$$f; \
+ done; \
+ for f in $$ds; do \
+ rm -f $(srcdir)/$$f; \
+ @LN_CP_F@ $(srcdir)/../dbug/$$f $(srcdir)/$$f; \
+ done; \
+ for f in $$ms $(mysysheaders); do \
+ rm -f $(srcdir)/$$f; \
+ @LN_CP_F@ $(srcdir)/../mysys/$$f $(srcdir)/$$f; \
+ done;
+
+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"` \
+ $(mystringsextra) ctype_extra_sources.c \
+ ../linked_client_sources
+
+ctype_extra_sources.c: conf_to_src
+ ./conf_to_src $(top_srcdir) @CHARSETS_NEED_SOURCE@ > \
+ $(srcdir)/ctype_extra_sources.c
+conf_to_src_SOURCES = conf_to_src.c
+conf_to_src_LDADD=
+
+# This part requires GNUmake
+#
+# This makes a distribution file with only the files needed to compile
+# a minimal MySQL client library
+#
+# For a really minimal distribution (without debugging code) we could
+# 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 \
+ 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
+# Get a list of the needed objects
+lobjs = $(mysysobjects1) $(dbugobjects) $(mystringsobjects)
+
+do-lib-dist:
+ dir=libmysql-$(MYSQL_NO_DASH_VERSION); \
+ srcs1=`echo $(lobjs) | sed "s;\.lo;.c;g"`; \
+ srcs2=$(libmysqlclient_la_SOURCES); \
+ srcs="$$srcs1 $$srcs2"; \
+ objs1=`echo $(lobjs) | sed "s;\.lo;.o;g"`; \
+ objs2=`echo $(libmysqlclient_la_SOURCES) | sed "s;\.c;.o;g"`; \
+ objs="$$objs1 $$objs2"; \
+ rm -rf $$dir; \
+ mkdir $$dir; \
+ cp $$srcs $(mysysheaders) $$dir; \
+ for i in $(nh); do cp ../include/$$i $$dir; done; \
+ echo "# A very minimal Makefile to compile" > $$dir/Makefile; \
+ echo "# the minimized libmysql library" >> $$dir/Makefile; \
+ echo "# This file is autogenerated from Makefile.am" >> $$dir/Makefile; \
+ echo 'CFLAGS= -I. -DUNDEF_THREADS_HACK' >>$$dir/Makefile; \
+ echo "obj=$$objs" >>$$dir/Makefile; \
+ echo 'all: libmysql.a' >>$$dir/Makefile; \
+ echo 'libmysql.a: $$(obj)' >>$$dir/Makefile; \
+ echo ' $$(AR) r $$@ $$?' >>$$dir/Makefile; \
+ gtar cvzf $$dir.tar.gz $$dir; \
+ cd $$dir; gmake
diff --git a/libmysql/acinclude.m4 b/libmysql/acinclude.m4
new file mode 100644
index 00000000000..c0211f3759f
--- /dev/null
+++ b/libmysql/acinclude.m4
@@ -0,0 +1,91 @@
+# Local macros for automake & autoconf
+
+AC_DEFUN(MYSQL_TYPE_ACCEPT,
+[ac_save_CXXFLAGS="$CXXFLAGS"
+AC_CACHE_CHECK([base type of last arg to accept], mysql_cv_btype_last_arg_accept,
+AC_LANG_SAVE
+AC_LANG_CPLUSPLUS
+if test "$ac_cv_prog_gxx" = "yes"
+then
+ CXXFLAGS="$CXXFLAGS -Werror"
+fi
+mysql_cv_btype_last_arg_accept=none
+[AC_TRY_COMPILE([#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+],
+[int a = accept(1, (struct sockaddr *) 0, (socklen_t *) 0);],
+mysql_cv_btype_last_arg_accept=socklen_t)]
+if test $mysql_cv_btype_last_arg_accept = none; then
+[AC_TRY_COMPILE([#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+],
+[int a = accept(1, (struct sockaddr *) 0, (size_t *) 0);],
+mysql_cv_btype_last_arg_accept=size_t)]
+fi
+if test $mysql_cv_btype_last_arg_accept = none; then
+mysql_cv_btype_last_arg_accept=int
+fi)
+AC_LANG_RESTORE
+AC_DEFINE_UNQUOTED(SOCKET_SIZE_TYPE, $mysql_cv_btype_last_arg_accept)
+CXXFLAGS="$ac_save_CXXFLAGS"
+])
+
+
+#---START: Used in for client configure
+AC_DEFUN(MYSQL_CHECK_ULONG,
+[AC_MSG_CHECKING(for type ulong)
+AC_CACHE_VAL(ac_cv_ulong,
+[AC_TRY_RUN([#include <stdio.h>
+#include <sys/types.h>
+main()
+{
+ ulong foo;
+ foo++;
+ exit(0);
+}], ac_cv_ulong=yes, ac_cv_ulong=no, ac_cv_ulong=no)])
+AC_MSG_RESULT($ac_cv_ulong)
+if test "$ac_cv_ulong" = "yes"
+then
+ AC_DEFINE(HAVE_ULONG)
+fi
+])
+
+AC_DEFUN(MYSQL_CHECK_UCHAR,
+[AC_MSG_CHECKING(for type uchar)
+AC_CACHE_VAL(ac_cv_uchar,
+[AC_TRY_RUN([#include <stdio.h>
+#include <sys/types.h>
+main()
+{
+ uchar foo;
+ foo++;
+ exit(0);
+}], ac_cv_uchar=yes, ac_cv_uchar=no, ac_cv_uchar=no)])
+AC_MSG_RESULT($ac_cv_uchar)
+if test "$ac_cv_uchar" = "yes"
+then
+ AC_DEFINE(HAVE_UCHAR)
+fi
+])
+
+AC_DEFUN(MYSQL_CHECK_UINT,
+[AC_MSG_CHECKING(for type uint)
+AC_CACHE_VAL(ac_cv_uint,
+[AC_TRY_RUN([#include <stdio.h>
+#include <sys/types.h>
+main()
+{
+ uint foo;
+ foo++;
+ exit(0);
+}], ac_cv_uint=yes, ac_cv_uint=no, ac_cv_uint=no)])
+AC_MSG_RESULT($ac_cv_uint)
+if test "$ac_cv_uint" = "yes"
+then
+ AC_DEFINE(HAVE_UINT)
+fi
+])
+
+#---END:
diff --git a/libmysql/conf_to_src.c b/libmysql/conf_to_src.c
new file mode 100644
index 00000000000..f75f5af6276
--- /dev/null
+++ b/libmysql/conf_to_src.c
@@ -0,0 +1,143 @@
+/* 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 */
+
+/* can't use -lmysys because this prog is used to create -lstrings */
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define CHARSETS_SUBDIR "sql/share/charsets"
+#define CTYPE_TABLE_SIZE 257
+#define TO_LOWER_TABLE_SIZE 256
+#define TO_UPPER_TABLE_SIZE 256
+#define SORT_ORDER_TABLE_SIZE 256
+#define ROW_LEN 16
+
+void print_arrays_for(char *set);
+
+char *prog;
+char buf[1024], *p, *endptr;
+
+int
+main(int argc, char **argv)
+{
+ prog = *argv;
+
+ if (argc < 2) {
+ fprintf(stderr, "usage: %s source-dir [charset [, charset]]\n", prog);
+ exit(EXIT_FAILURE);
+ }
+
+ --argc; ++argv; /* skip program name */
+
+ if (chdir(*argv) != 0) {
+ fprintf(stderr, "%s: can't cd to %s\n", prog, *argv);
+ exit(EXIT_FAILURE);
+ }
+ --argc; ++argv;
+
+ if (chdir(CHARSETS_SUBDIR) != 0) {
+ fprintf(stderr, "%s: can't cd to %s\n", prog, CHARSETS_SUBDIR);
+ exit(EXIT_FAILURE);
+ }
+
+ while (argc--)
+ print_arrays_for(*argv++);
+
+ exit(EXIT_SUCCESS);
+}
+
+void
+print_array(FILE *f, char *set, char *name, int n)
+{
+ int i;
+ char val[100];
+
+ printf("uchar %s_%s[] = {\n", name, set);
+
+ p = buf;
+ *buf = '\0';
+ for (i = 0; i < n; ++i)
+ {
+ /* get a word from f */
+ endptr = p;
+ for (;;)
+ {
+ while (isspace(*endptr))
+ ++endptr;
+ if (*endptr && *endptr != '#') /* not comment */
+ break;
+ if ((fgets(buf, sizeof(buf), f)) == NULL)
+ return; /* XXX: break silently */
+ endptr = buf;
+ }
+
+ p = val;
+ while (!isspace(*endptr))
+ *p++ = *endptr++;
+ *p = '\0';
+ p = endptr;
+
+ /* write the value out */
+
+ if (i == 0 || i % ROW_LEN == n % ROW_LEN)
+ printf(" ");
+
+ printf("%3d", (unsigned char) strtol(val, (char **) NULL, 16));
+
+ if (i < n - 1)
+ printf(",");
+
+ if ((i+1) % ROW_LEN == n % ROW_LEN)
+ printf("\n");
+ }
+
+ printf("};\n\n");
+}
+
+void
+print_arrays_for(char *set)
+{
+ FILE *f;
+
+ sprintf(buf, "%s.conf", set);
+
+ if ((f = fopen(buf, "r")) == NULL) {
+ fprintf(stderr, "%s: can't read conf file for charset %s\n", prog, set);
+ exit(EXIT_FAILURE);
+ }
+
+ printf("\
+/* The %s character set. Generated automatically by configure and\n\
+ * the %s program\n\
+ */\n\n",
+ set, prog);
+
+ /* it would be nice if this used the code in mysys/charset.c, but... */
+ print_array(f, set, "ctype", CTYPE_TABLE_SIZE);
+ print_array(f, set, "to_lower", TO_LOWER_TABLE_SIZE);
+ print_array(f, set, "to_upper", TO_UPPER_TABLE_SIZE);
+ print_array(f, set, "sort_order", SORT_ORDER_TABLE_SIZE);
+ printf("\n");
+
+ fclose(f);
+
+ return;
+}
diff --git a/libmysql/configure.in b/libmysql/configure.in
new file mode 100644
index 00000000000..22179a33971
--- /dev/null
+++ b/libmysql/configure.in
@@ -0,0 +1,230 @@
+dnl Process this file with autoconf to produce a configure script.
+AC_INIT(libmysql.c)
+dnl The version number should be autogenerated from the toplevel configure.in
+AM_INIT_AUTOMAKE(libmysql, 3.23.11-alpha)
+AM_CONFIG_HEADER(my_config.h)
+
+dnl Checks for programs.
+AC_PROG_CC
+AC_PROG_LN_S
+AC_PROG_RANLIB
+
+# We use libtool
+AM_PROG_LIBTOOL
+
+dnl Checks for header files.
+AC_HEADER_STDC
+AC_CHECK_HEADERS(sgtty.h sys/ioctl.h)
+# Maybe some can be removed but I got sick of adding them on at a time
+# /David
+AC_CHECK_HEADERS(fcntl.h float.h floatingpoint.h ieeefp.h limits.h \
+ memory.h pwd.h select.h \
+ stdlib.h stddef.h \
+ strings.h string.h synch.h sys/mman.h sys/socket.h \
+ sys/timeb.h sys/types.h sys/un.h sys/vadvise.h sys/wait.h term.h \
+ unistd.h utime.h sys/utime.h termio.h termios.h sched.h crypt.h alloca.h)
+
+
+dnl Checks for typedefs, structures, and compiler characteristics.
+AC_C_CONST
+AC_C_INLINE
+AC_CHECK_SIZEOF(char, 1)
+if test "$ac_cv_sizeof_char" -eq 0
+then
+ AC_MSG_ERROR([No size for char type.
+A likely cause for this could be that there isn't any static libraries
+installed. You can verify this by checking if you have libm.a in /lib,
+/usr/lib or some other standard place. If this is the problem,
+install the static libraries and try again. If this isn't the
+problem, examine config.log for possible errors. If you want to
+report this include ALL system information and include at least the
+last 20 rows from config.log!])
+fi
+AC_CHECK_SIZEOF(int, 4)
+if test "$ac_cv_sizeof_int" -eq 0
+then
+ AC_MSG_ERROR("No size for int type.")
+fi
+AC_CHECK_SIZEOF(long, 4)
+if test "$ac_cv_sizeof_long" -eq 0
+then
+ AC_MSG_ERROR("No size for long type.")
+fi
+AC_CHECK_SIZEOF(long long, 8)
+if test "$ac_cv_sizeof_long_long" -eq 0
+then
+ AC_MSG_ERROR("MySQL needs a long long type.")
+fi
+AC_TYPE_SIZE_T
+AC_HEADER_TIME
+AC_TYPE_UID_T
+
+# Do the system files define ulong
+MYSQL_CHECK_ULONG
+# Do the system files define uchar
+MYSQL_CHECK_UCHAR
+# Do the system files define uint
+MYSQL_CHECK_UINT
+
+#---START: Used in for client configure
+# Check base type of last arg to accept
+MYSQL_TYPE_ACCEPT
+#---END:
+
+dnl Checks for library functions.
+AC_TYPE_SIGNAL
+# Standard MySQL list
+AC_CHECK_FUNCS(alarm bmove \
+ chsize ftruncate rint finite fpsetmask fpresetsticky\
+ cuserid fcntl fconvert \
+ getrusage getpwuid getcwd getrlimit getwd index locking longjmp \
+ perror pread realpath rename \
+ socket strnlen madvise \
+ strtoul strtoull snprintf tempnam thr_setconcurrency \
+ gethostbyaddr_r gethostbyname_r getpwnam \
+ bfill bzero bcmp strstr strpbrk strerror\
+ tell atod memcpy memmove \
+ setupterm strcasecmp sighold \
+ vidattr setupterm lrand48 localtime_r \
+ sigset sigthreadmask pthread_sigmask pthread_setprio pthread_setprio_np \
+ pthread_setschedparam pthread_attr_setprio pthread_attr_setschedparam \
+ pthread_attr_create pthread_getsequence_np pthread_attr_setstacksize \
+ pthread_condattr_create rwlock_init \
+ crypt dlopen dlerror fchmod getpass getpassphrase)
+
+# This is special for libmysql
+AC_CHECK_FUNCS(strtok_r)
+
+#---START: Used in for client configure
+
+# Check definition of gethostbyname_r (glibc2.0.100 is different from Solaris)
+ac_save_CXXFLAGS="$CXXFLAGS"
+AC_CACHE_CHECK([style of gethostname_r routines], mysql_cv_gethostname_style,
+AC_LANG_SAVE
+AC_LANG_CPLUSPLUS
+if test "$ac_cv_prog_gxx" = "yes"
+then
+ CXXFLAGS="$CXXFLAGS -Werror"
+fi
+AC_TRY_COMPILE(
+[#ifndef SCO
+#define _REENTRANT
+#endif
+#include <pthread.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>],
+[int skr;
+
+ int res = gethostbyname_r((const char *) 0,
+ (struct hostent*) 0, (char*) 0, 0, (struct hostent **) 0, &skr);],
+mysql_cv_gethostname_style=glibc2, mysql_cv_gethostname_style=other))
+AC_LANG_RESTORE
+CXXFLAGS="$ac_save_CXXFLAGS"
+if test "$mysql_cv_gethostname_style" = "glibc2"
+then
+ AC_DEFINE(HAVE_GLIBC2_STYLE_GETHOSTBYNAME_R)
+fi
+
+if test "$with_mit_threads" = "no"
+then
+ # Check definition of pthread_getspecific
+ AC_CACHE_CHECK("args to pthread_getspecific", mysql_cv_getspecific_args,
+ AC_TRY_COMPILE(
+[#ifndef SCO
+#define _REENTRANT
+#endif
+#define _POSIX_PTHREAD_SEMANTICS
+#include <pthread.h> ],
+[ void *pthread_getspecific(pthread_key_t key);
+pthread_getspecific((pthread_key_t) NULL); ],
+mysql_cv_getspecific_args=POSIX, mysql_cv_getspecific_args=other))
+ if test "$mysql_cv_getspecific_args" = "other"
+ then
+ AC_DEFINE(HAVE_NONPOSIX_PTHREAD_GETSPECIFIC)
+ fi
+
+ # Check definition of pthread_mutex_init
+ AC_CACHE_CHECK("args to pthread_mutex_init", mysql_cv_mutex_init_args,
+ AC_TRY_COMPILE(
+[#ifndef SCO
+#define _REENTRANT
+#endif
+#define _POSIX_PTHREAD_SEMANTICS
+#include <pthread.h> ],
+[
+ pthread_mutexattr_t attr;
+ pthread_mutex_t mp;
+ pthread_mutex_init(&mp,&attr); ],
+mysql_cv_mutex_init_args=POSIX, mysql_cv_mutex_init_args=other))
+ if test "$mysql_cv_mutex_init_args" = "other"
+ then
+ AC_DEFINE(HAVE_NONPOSIX_PTHREAD_MUTEX_INIT)
+ fi
+fi
+#---END:
+
+#---START: Used in for client configure
+# Check definition of readdir_r
+AC_CACHE_CHECK("args to readdir_r", mysql_cv_readdir_r,
+AC_TRY_LINK(
+[#ifndef SCO
+#define _REENTRANT
+#endif
+#define _POSIX_PTHREAD_SEMANTICS
+#include <pthread.h>
+#include <dirent.h>],
+[ int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result);
+readdir_r((DIR *) NULL, (struct dirent *) NULL, (struct dirent **) NULL); ],
+mysql_cv_readdir_r=POSIX, mysql_cv_readdir_r=other))
+if test "$mysql_cv_readdir_r" = "POSIX"
+then
+ AC_DEFINE(HAVE_READDIR_R)
+fi
+
+# Check definition av posix sigwait()
+AC_CACHE_CHECK("style of sigwait", mysql_cv_sigwait,
+AC_TRY_LINK(
+[#ifndef SCO
+#define _REENTRANT
+#endif
+#define _POSIX_PTHREAD_SEMANTICS
+#include <pthread.h>
+#include <signal.h>],
+[#ifndef _AIX
+sigset_t set;
+int sig;
+sigwait(&set,&sig);
+#endif],
+mysql_cv_sigwait=POSIX, mysql_cv_sigwait=other))
+if test "$mysql_cv_sigwait" = "POSIX"
+then
+ AC_DEFINE(HAVE_SIGWAIT)
+fi
+
+if test "$mysql_cv_sigwait" != "POSIX"
+then
+unset mysql_cv_sigwait
+# Check definition av posix sigwait()
+AC_CACHE_CHECK("style of sigwait", mysql_cv_sigwait,
+AC_TRY_LINK(
+[#ifndef SCO
+#define _REENTRANT
+#endif
+#define _POSIX_PTHREAD_SEMANTICS
+#include <pthread.h>
+#include <signal.h>],
+[sigset_t set;
+int sig;
+sigwait(&set);],
+mysql_cv_sigwait=NONPOSIX, mysql_cv_sigwait=other))
+if test "$mysql_cv_sigwait" = "NONPOSIX"
+then
+ AC_DEFINE(HAVE_NONPOSIX_SIGWAIT)
+fi
+fi
+#---END:
+
+AC_OUTPUT(Makefile)
diff --git a/libmysql/dll.c b/libmysql/dll.c
new file mode 100644
index 00000000000..4c952c5889e
--- /dev/null
+++ b/libmysql/dll.c
@@ -0,0 +1,112 @@
+/* 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 */
+
+/*
+** Handling initialization of the dll library
+*/
+
+#include <global.h>
+#include <my_sys.h>
+#include <my_pthread.h>
+
+static bool libmysql_inited=0;
+
+void libmysql_init(void)
+{
+ if (libmysql_inited)
+ return;
+ libmysql_inited=1;
+ my_init();
+ {
+ DBUG_ENTER("libmysql_init");
+#ifdef LOG_ALL
+ DBUG_PUSH("d:t:S:O,c::\\tmp\\libmysql.log");
+#else
+ if (getenv("LIBMYSQL_LOG") != NULL)
+ DBUG_PUSH(getenv("LIBMYSQL_LOG"));
+#endif
+ DBUG_VOID_RETURN;
+ }
+}
+
+#ifdef __WIN__
+
+static int inited=0,threads=0;
+HINSTANCE NEAR s_hModule; /* Saved module handle */
+DWORD main_thread;
+
+BOOL APIENTRY LibMain(HANDLE hInst,DWORD ul_reason_being_called,
+ LPVOID lpReserved)
+{
+ switch (ul_reason_being_called) {
+ case DLL_PROCESS_ATTACH: /* case of libentry call in win 3.x */
+ if (!inited++)
+ {
+ s_hModule=hInst;
+ libmysql_init();
+ main_thread=GetCurrentThreadId();
+ }
+ break;
+ case DLL_THREAD_ATTACH:
+ threads++;
+ my_thread_init();
+ break;
+ case DLL_PROCESS_DETACH: /* case of wep call in win 3.x */
+ if (!--inited) /* Safety */
+ {
+ /* my_thread_init() */ /* This may give extra safety */
+ my_end(0);
+ }
+ break;
+ case DLL_THREAD_DETACH:
+ /* Main thread will free by my_end() */
+ threads--;
+ if (main_thread != GetCurrentThreadId())
+ my_thread_end();
+ break;
+ default:
+ break;
+ } /* switch */
+
+ return TRUE;
+
+ UNREFERENCED_PARAMETER(lpReserved);
+} /* LibMain */
+
+int __stdcall DllMain(HANDLE hInst,DWORD ul_reason_being_called,LPVOID lpReserved)
+{
+ return LibMain(hInst,ul_reason_being_called,lpReserved);
+}
+
+#elif defined(WINDOWS)
+
+/****************************************************************************
+** This routine is called by LIBSTART.ASM at module load time. All it
+** does in this sample is remember the DLL module handle. The module
+** handle is needed if you want to do things like load stuff from the
+** resource file (for instance string resources).
+****************************************************************************/
+
+int _export FAR PASCAL libmain(HANDLE hModule,short cbHeapSize,
+ UCHAR FAR *lszCmdLine)
+{
+ s_hModule = hModule;
+ libmysql_init();
+ return TRUE;
+}
+
+#endif
diff --git a/libmysql/errmsg.c b/libmysql/errmsg.c
new file mode 100644
index 00000000000..194542afd7f
--- /dev/null
+++ b/libmysql/errmsg.c
@@ -0,0 +1,82 @@
+/* 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 */
+
+/* Error messages for MySQL clients */
+/* error messages for the demon is in share/language/errmsg.sys */
+
+#include <global.h>
+#include <my_sys.h>
+#include "errmsg.h"
+
+#ifdef GERMAN
+const char *client_errors[]=
+{
+ "Unbekannter MySQL Fehler",
+ "Kann UNIX-Socket nicht anlegen (%d)",
+ "Keine Verbindung zu lokalem MySQL Server, socket: '%-.64s' (%d)",
+ "Keine Verbindung zu MySQL Server auf %-.64s (%d)",
+ "Kann TCP/IP-Socket nicht anlegen (%d)",
+ "Unbekannter MySQL Server Host (%-.64s) (%d)",
+ "MySQL Server nicht vorhanden",
+ "Protokolle ungleich. Server Version = % d Client Version = %d",
+ "MySQL client got out of memory",
+ "Wrong host info",
+ "Localhost via UNIX socket",
+ "%s via TCP/IP",
+ "Error in server handshake",
+ "Lost connection to MySQL server during query",
+ "Commands out of sync; You can't run this command now",
+ "Verbindung ueber Named Pipe; Host: %-.64s",
+ "Kann nicht auf Named Pipe warten. Host: %-.64s pipe: %-.32s (%lu)",
+ "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'"
+};
+
+#else /* ENGLISH */
+const char *client_errors[]=
+{
+ "Unknown MySQL error",
+ "Can't create UNIX socket (%d)",
+ "Can't connect to local MySQL server through socket '%-.64s' (%d)",
+ "Can't connect to MySQL server on '%-.64s' (%d)",
+ "Can't create TCP/IP socket (%d)",
+ "Unknown MySQL Server Host '%-.64s' (%d)",
+ "MySQL server has gone away",
+ "Protocol mismatch. Server Version = %d Client Version = %d",
+ "MySQL client run out of memory",
+ "Wrong host info",
+ "Localhost via UNIX socket",
+ "%s via TCP/IP",
+ "Error in server handshake",
+ "Lost connection to MySQL server during query",
+ "Commands out of sync; You can't run this command now",
+ "%s via named pipe",
+ "Can't wait for named pipe to host: %-.64s pipe: %-.32s (%lu)",
+ "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'"
+};
+#endif
+
+
+void init_client_errs(void)
+{
+ errmsg[CLIENT_ERRMAP] = &client_errors[0];
+}
diff --git a/libmysql/get_password.c b/libmysql/get_password.c
new file mode 100644
index 00000000000..d61c40a9559
--- /dev/null
+++ b/libmysql/get_password.c
@@ -0,0 +1,212 @@
+/* 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 */
+
+/*
+** Ask for a password from tty
+** This is an own file to avoid conflicts with curses
+*/
+#include <global.h>
+#include <my_sys.h>
+#include "mysql.h"
+#include <m_string.h>
+#include <m_ctype.h>
+#include <dbug.h>
+
+#if defined(HAVE_BROKEN_GETPASS) && !defined(HAVE_GETPASSPHRASE)
+#undef HAVE_GETPASS
+#endif
+
+#ifdef HAVE_GETPASS
+#ifdef HAVE_PWD_H
+#include <pwd.h>
+#endif /* HAVE_PWD_H */
+#else /* ! HAVE_GETPASS */
+#ifndef __WIN__
+#include <sys/ioctl.h>
+#ifdef HAVE_TERMIOS_H /* For tty-password */
+#include <termios.h>
+#define TERMIO struct termios
+#else
+#ifdef HAVE_TERMIO_H /* For tty-password */
+#include <termio.h>
+#define TERMIO struct termio
+#else
+#include <sgtty.h>
+#define TERMIO struct sgttyb
+#endif
+#endif
+#ifdef alpha_linux_port
+#include <asm/ioctls.h> /* QQ; Fix this in configure */
+#include <asm/termiobits.h>
+#endif
+#else
+#include <conio.h>
+#endif /* __WIN__ */
+#endif /* HAVE_GETPASS */
+
+#ifdef HAVE_GETPASSPHRASE /* For Solaris */
+#define getpass(A) getpassphrase(A)
+#endif
+
+#ifdef __WIN__
+/* were just going to fake it here and get input from
+ the keyboard */
+
+char *get_tty_password(char *opt_message)
+{
+ char to[80];
+ char *pos=to,*end=to+sizeof(to)-1;
+ int i=0;
+ DBUG_ENTER("get_tty_password");
+ fprintf(stdout,opt_message ? opt_message : "Enter password: ");
+ for (;;)
+ {
+ char tmp;
+ tmp=_getch();
+ if (tmp == '\b' || (int) tmp == 127)
+ {
+ if (pos != to)
+ {
+ _cputs("\b \b");
+ pos--;
+ continue;
+ }
+ }
+ if (tmp == '\n' || tmp == '\r' || tmp == 3)
+ break;
+ if (iscntrl(tmp) || pos == end)
+ continue;
+ _cputs("*");
+ *(pos++) = tmp;
+ }
+ while (pos != to && isspace(pos[-1]) == ' ')
+ pos--; /* Allow dummy space at end */
+ *pos=0;
+ _cputs("\n");
+ DBUG_RETURN(my_strdup(to,MYF(MY_FAE)));
+}
+
+#else
+
+
+#ifndef HAVE_GETPASS
+/*
+** Can't use fgets, because readline will get confused
+** length is max number of chars in to, not counting \0
+* to will not include the eol characters.
+*/
+
+static void get_password(char *to,uint length,int fd,bool echo)
+{
+ char *pos=to,*end=to+length;
+
+ for (;;)
+ {
+ char tmp;
+ if (my_read(fd,&tmp,1,MYF(0)) != 1)
+ break;
+ if (tmp == '\b' || (int) tmp == 127)
+ {
+ if (pos != to)
+ {
+ if (echo)
+ {
+ fputs("\b \b",stdout);
+ fflush(stdout);
+ }
+ pos--;
+ continue;
+ }
+ }
+ if (tmp == '\n' || tmp == '\r' || tmp == 3)
+ break;
+ if (iscntrl(tmp) || pos == end)
+ continue;
+ if (echo)
+ {
+ fputc('*',stdout);
+ fflush(stdout);
+ }
+ *(pos++) = tmp;
+ }
+ while (pos != to && isspace(pos[-1]) == ' ')
+ pos--; /* Allow dummy space at end */
+ *pos=0;
+ return;
+}
+#endif /* ! HAVE_GETPASS */
+
+
+char *get_tty_password(char *opt_message)
+{
+#ifdef HAVE_GETPASS
+ char *passbuff;
+#else /* ! HAVE_GETPASS */
+ TERMIO org,tmp;
+#endif /* HAVE_GETPASS */
+ char buff[80];
+
+ DBUG_ENTER("get_tty_password");
+
+#ifdef HAVE_GETPASS
+ passbuff = getpass(opt_message ? opt_message : "Enter password: ");
+
+ /* copy the password to buff and clear original (static) buffer */
+ strnmov(buff, passbuff, sizeof(buff) - 1);
+#ifdef _PASSWORD_LEN
+ memset(passbuff, 0, _PASSWORD_LEN);
+#endif
+#else
+ if (isatty(fileno(stdout)))
+ {
+ fputs(opt_message ? opt_message : "Enter password: ",stdout);
+ fflush(stdout);
+ }
+#if defined(HAVE_TERMIOS_H)
+ tcgetattr(fileno(stdin), &org);
+ tmp = org;
+ tmp.c_lflag &= ~(ECHO | ISIG | ICANON);
+ 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)));
+ tcsetattr(fileno(stdin), TCSADRAIN, &org);
+#elif defined(HAVE_TERMIO_H)
+ ioctl(fileno(stdin), (int) TCGETA, &org);
+ tmp=org;
+ tmp.c_lflag &= ~(ECHO | ISIG | ICANON);
+ 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)));
+ ioctl(fileno(stdin),(int) TCSETA, &org);
+#else
+ gtty(fileno(stdin), &org);
+ tmp=org;
+ tmp.sg_flags &= ~ECHO;
+ tmp.sg_flags |= RAW;
+ stty(fileno(stdin), &tmp);
+ get_password(buff,sizeof(buff)-1,fileno(stdin),isatty(fileno(stdout)));
+ stty(fileno(stdin), &org);
+#endif
+ if (isatty(fileno(stdout)))
+ fputc('\n',stdout);
+#endif /* HAVE_GETPASS */
+
+ DBUG_RETURN(my_strdup(buff,MYF(MY_FAE)));
+}
+#endif /*__WIN__*/
diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c
new file mode 100644
index 00000000000..2b9cd7d2461
--- /dev/null
+++ b/libmysql/libmysql.c
@@ -0,0 +1,2533 @@
+/* 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 */
+
+#define DONT_USE_RAID
+#if defined(__WIN__) || defined(_WIN32) || defined(_WIN64)
+#include <winsock.h>
+#include <odbcinst.h>
+#endif
+#include <global.h>
+#include <my_sys.h>
+#include <mysys_err.h>
+#include <m_string.h>
+#include <m_ctype.h>
+#include "mysql.h"
+#include "mysql_version.h"
+#include "mysqld_error.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
+#if defined(THREAD) && !defined(__WIN__)
+#include <my_pthread.h> /* because of signal() */
+#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_LOCAL_FILES | 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 my_bool mysql_reconnect(MYSQL *mysql);
+static int send_file_to_server(MYSQL *mysql,const char *filename);
+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);
+
+/*
+ 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.
+*/
+
+#if !defined(__WIN__) && defined(SIGPIPE) && !defined(THREAD)
+#define init_sigpipe_variables sig_return old_signal_handler=(sig_return) 0;
+#define set_sigpipe(mysql) if ((mysql)->client_flag & CLIENT_IGNORE_SIGPIPE) old_signal_handler=signal(SIGPIPE,pipe_sig_handler)
+#define reset_sigpipe(mysql) if ((mysql)->client_flag & CLIENT_IGNORE_SIGPIPE) signal(SIGPIPE,old_signal_handler);
+#else
+#define init_sigpipe_variables
+#define set_sigpipe(mysql)
+#define reset_sigpipe(mysql)
+#endif
+
+/****************************************************************************
+* 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().
+*
+* Base version coded by Steve Bernacki, Jr. <steve@navinet.net>
+*****************************************************************************/
+
+static int connect2(File s, const struct sockaddr *name, uint namelen, uint to)
+{
+#if defined(__WIN__)
+ return connect(s, (struct sockaddr*) name, namelen);
+#else
+ int flags, res, s_err;
+ size_socket 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 (to == 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) to;
+ tv.tv_usec = 0;
+ if ((res = select(s+1, NULL, &sfds, NULL, &tv)) >= 0)
+ break;
+ now_time=time(NULL);
+ to-= (uint) (now_time - start_time);
+ if (errno != EINTR || (int) to <= 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 suceed */
+ errno = s_err;
+ return(-1); /* but return an error... */
+ }
+ return(0); /* It's all good! */
+#endif
+}
+
+/*
+** Create a named pipe connection
+*/
+
+#ifdef __WIN__
+
+HANDLE create_named_pipe(NET *net, uint connect_timeout, char **arg_host,
+ char **arg_unix_socket)
+{
+ HANDLE hPipe=INVALID_HANDLE_VALUE;
+ char szPipeName [ 257 ];
+ DWORD dwMode;
+ int i;
+ my_bool testing_named_pipes=0;
+ char *host= *arg_host, *unix_socket= *arg_unix_socket;
+
+ if ( ! unix_socket || (unix_socket)[0] == 0x00)
+ unix_socket = mysql_unix_port;
+ if (!host || !strcmp(host,LOCAL_HOST))
+ host=LOCAL_HOST_NAMEDPIPE;
+
+ sprintf( szPipeName, "\\\\%s\\pipe\\%s", host, unix_socket);
+ DBUG_PRINT("info",("Server name: '%s'. Named Pipe: %s",
+ host, unix_socket));
+
+ for (i=0 ; i < 100 ; i++) /* Don't retry forever */
+ {
+ if ((hPipe = CreateFile(szPipeName,
+ GENERIC_READ | GENERIC_WRITE,
+ 0,
+ NULL,
+ OPEN_EXISTING,
+ 0,
+ NULL )) != INVALID_HANDLE_VALUE)
+ break;
+ if (GetLastError() != ERROR_PIPE_BUSY)
+ {
+ net->last_errno=CR_NAMEDPIPEOPEN_ERROR;
+ sprintf(net->last_error,ER(net->last_errno),host, unix_socket,
+ (ulong) GetLastError());
+ return INVALID_HANDLE_VALUE;
+ }
+ /* wait for for an other instance */
+ if (! WaitNamedPipe(szPipeName, connect_timeout*1000) )
+ {
+ net->last_errno=CR_NAMEDPIPEWAIT_ERROR;
+ sprintf(net->last_error,ER(net->last_errno),host, unix_socket,
+ (ulong) GetLastError());
+ return INVALID_HANDLE_VALUE;
+ }
+ }
+ if (hPipe == INVALID_HANDLE_VALUE)
+ {
+ net->last_errno=CR_NAMEDPIPEOPEN_ERROR;
+ sprintf(net->last_error,ER(net->last_errno),host, unix_socket,
+ (ulong) GetLastError());
+ return INVALID_HANDLE_VALUE;
+ }
+ dwMode = PIPE_READMODE_BYTE | PIPE_WAIT;
+ if ( !SetNamedPipeHandleState(hPipe, &dwMode, NULL, NULL) )
+ {
+ CloseHandle( hPipe );
+ net->last_errno=CR_NAMEDPIPESETSTATE_ERROR;
+ sprintf(net->last_error,ER(net->last_errno),host, unix_socket,
+ (ulong) GetLastError());
+ return INVALID_HANDLE_VALUE;
+ }
+ *arg_host=host ; *arg_unix_socket=unix_socket; /* connect arg */
+ return (hPipe);
+}
+#endif
+
+
+/*****************************************************************************
+** read a packet from server. Give error message if socket was down
+** or packet is an error message
+*****************************************************************************/
+
+static uint
+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);
+ my_free((gptr) cur,MYF(0));
+ }
+}
+
+
+static int
+simple_command(MYSQL *mysql,enum enum_server_command command, const char *arg,
+ uint length, my_bool skipp_check)
+{
+ NET *net= &mysql->net;
+ int result= -1;
+ init_sigpipe_variables
+
+ /* Don't give sigpipe errors if the client doesn't want them */
+ set_sigpipe(mysql);
+ if (mysql->net.vio == 0)
+ { /* Do reconnect if possible */
+ if (mysql_reconnect(mysql))
+ {
+ net->last_errno=CR_SERVER_GONE_ERROR;
+ strmov(net->last_error,ER(net->last_errno));
+ goto end;
+ }
+ }
+ if (mysql->status != MYSQL_STATUS_READY)
+ {
+ strmov(net->last_error,ER(mysql->net.last_errno=CR_COMMANDS_OUT_OF_SYNC));
+ goto end;
+ }
+
+ mysql->net.last_error[0]=0;
+ mysql->net.last_errno=0;
+ mysql->info=0;
+ mysql->affected_rows= ~(my_ulonglong) 0;
+ net_clear(net); /* Clear receive buffer */
+ if (!arg)
+ arg="";
+
+ if (net_write_command(net,(uchar) command,arg,
+ length ? length : (ulong) strlen(arg)))
+ {
+ DBUG_PRINT("error",("Can't send command to server. Error: %d",errno));
+ end_server(mysql);
+ if (mysql_reconnect(mysql) ||
+ net_write_command(net,(uchar) command,arg,
+ length ? length : (ulong) strlen(arg)))
+ {
+ net->last_errno=CR_SERVER_GONE_ERROR;
+ strmov(net->last_error,ER(net->last_errno));
+ goto end;
+ }
+ }
+ result=0;
+ if (!skipp_check)
+ result= ((mysql->packet_length=net_safe_read(mysql)) == packet_error ?
+ -1 : 0);
+ end:
+ reset_sigpipe(mysql);
+ return result;
+}
+
+
+static void free_old_query(MYSQL *mysql)
+{
+ DBUG_ENTER("free_old_query");
+ if (mysql->fields)
+ free_root(&mysql->field_alloc);
+ init_alloc_root(&mysql->field_alloc,8192); /* 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
+}
+
+
+/**************************************************************************
+** Close the server connection if we get a SIGPIPE
+ ARGSUSED
+**************************************************************************/
+
+static sig_handler
+pipe_sig_handler(int sig __attribute__((unused)))
+{
+ DBUG_PRINT("info",("Hit by signal %d",sig));
+#ifdef DONT_REMEMBER_SIGNAL
+ (void) signal(SIGPIPE,pipe_sig_handler);
+#endif
+}
+
+
+/**************************************************************************
+** Shut down connection
+**************************************************************************/
+
+static void
+end_server(MYSQL *mysql)
+{
+ DBUG_ENTER("end_server");
+ if (mysql->net.vio != 0)
+ {
+ init_sigpipe_variables
+ DBUG_PRINT("info",("Net: %s", vio_description(mysql->net.vio)));
+ set_sigpipe(mysql);
+ vio_delete(mysql->net.vio);
+ reset_sigpipe(mysql);
+ 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);
+ 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;
+#ifdef HAVE_OPENSSL
+ case 13: /* ssl_key */
+ my_free(options->ssl_key, MYF(MY_ALLOW_ZERO_PTR));
+ options->ssl_key = my_strdup(opt_arg, MYF(MY_WME));
+ break;
+ case 14: /* ssl_cert */
+ my_free(options->ssl_cert, MYF(MY_ALLOW_ZERO_PTR));
+ options->ssl_cert = my_strdup(opt_arg, MYF(MY_WME));
+ break;
+ case 15: /* ssl_ca */
+ my_free(options->ssl_ca, MYF(MY_ALLOW_ZERO_PTR));
+ options->ssl_ca = my_strdup(opt_arg, MYF(MY_WME));
+ break;
+ case 16: /* ssl_capath */
+ my_free(options->ssl_capath, MYF(MY_ALLOW_ZERO_PTR));
+ options->ssl_capath = my_strdup(opt_arg, MYF(MY_WME));
+ break;
+#else
+ case 13: /* Ignore SSL options */
+ case 14:
+ case 15:
+ case 16:
+ break;
+#endif /* HAVE_OPENSSL */
+ 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 (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); /* 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=(uint) 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)));
+#ifdef __WIN__
+ mysql->options.connect_timeout=20;
+#endif
+#if defined(SIGPIPE) && defined(THREAD)
+ if (!((mysql)->client_flag & CLIENT_IGNORE_SIGPIPE))
+ (void) signal(SIGPIPE,pipe_sig_handler);
+#endif
+ return mysql;
+}
+
+
+static void mysql_once_init()
+{
+ if (!mysql_client_init)
+ {
+ mysql_client_init=1;
+ my_init(); /* Will init threads */
+ init_client_errs();
+ if (!mysql_port)
+ {
+ mysql_port = MYSQL_PORT;
+#ifndef MSDOS
+ {
+ struct servent *serv_ptr;
+ char *env;
+ if ((serv_ptr = getservbyname("mysql", "tcp")))
+ mysql_port = (uint) ntohs((ushort) serv_ptr->s_port);
+ if ((env = getenv("MYSQL_TCP_PORT")))
+ mysql_port =(uint) atoi(env);
+ }
+#endif
+ }
+ if (!mysql_unix_port)
+ {
+ char *env;
+#ifdef __WIN__
+ mysql_unix_port = (char*) MYSQL_NAMEDPIPE;
+#else
+ mysql_unix_port = (char*) MYSQL_UNIX_ADDR;
+#endif
+ if ((env = getenv("MYSQL_UNIX_PORT")))
+ mysql_unix_port = env;
+ }
+ mysql_debug(NullS);
+#if defined(SIGPIPE) && !defined(THREAD)
+ (void) signal(SIGPIPE,SIG_IGN);
+#endif
+ }
+#ifdef THREAD
+ else
+ my_thread_init(); /* Init if new thread */
+#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->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);
+ 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)
+{
+ 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;
+ mysql->connector_fd->delete();
+ mysql->connector_fd = 0;
+ return 0;
+}
+#endif /* HAVE_OPENSSL */
+
+/**************************************************************************
+** 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;
+ int sock;
+ uint32 ip_addr;
+ struct sockaddr_in sock_addr;
+ uint pkt_length;
+ NET *net= &mysql->net;
+#ifdef __WIN__
+ HANDLE hPipe=INVALID_HANDLE_VALUE;
+#endif
+#ifdef HAVE_SYS_UN_H
+ struct sockaddr_un UNIXaddr;
+#endif
+ init_sigpipe_variables
+ DBUG_ENTER("mysql_real_connect");
+
+ DBUG_PRINT("enter",("host: %s db: %s user: %s",
+ host ? host : "(Null)",
+ db ? db : "(Null)",
+ user ? user : "(Null)"));
+
+ /* Don't give sigpipe errors if the client doesn't want them */
+ set_sigpipe(mysql);
+ 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;
+#ifndef DONT_USE_MYSQL_PWD
+ if (!passwd)
+ passwd=getenv("MYSQL_PWD"); /* get it from environment (haneke) */
+#endif
+ }
+ if (!db || !db[0])
+ db=mysql->options.db;
+ if (!port)
+ port=mysql->options.port;
+ if (!unix_socket)
+ unix_socket=mysql->options.unix_socket;
+
+ mysql->reconnect=1; /* Reconnect as default */
+ mysql->server_status=SERVER_STATUS_AUTOCOMMIT;
+
+ /*
+ ** Grab a socket and connect it to the server
+ */
+
+#if defined(HAVE_SYS_UN_H)
+ if ((!host || !strcmp(host,LOCAL_HOST)) && (unix_socket || mysql_unix_port))
+ {
+ host=LOCAL_HOST;
+ if (!unix_socket)
+ unix_socket=mysql_unix_port;
+ host_info=(char*) ER(CR_LOCALHOST_CONNECTION);
+ DBUG_PRINT("info",("Using UNIX sock '%s'",unix_socket));
+ if ((sock = socket(AF_UNIX,SOCK_STREAM,0)) == SOCKET_ERROR)
+ {
+ net->last_errno=CR_SOCKET_CREATE_ERROR;
+ sprintf(net->last_error,ER(net->last_errno),ERRNO);
+ goto error;
+ }
+ net->vio = vio_new(sock, VIO_TYPE_SOCKET, TRUE);
+ bzero((char*) &UNIXaddr,sizeof(UNIXaddr));
+ UNIXaddr.sun_family = AF_UNIX;
+ strmov(UNIXaddr.sun_path, unix_socket);
+ if (connect2(sock,(struct sockaddr *) &UNIXaddr, sizeof(UNIXaddr),
+ mysql->options.connect_timeout) <0)
+ {
+ DBUG_PRINT("error",("Got error %d on connect to local server",ERRNO));
+ net->last_errno=CR_CONNECTION_ERROR;
+ sprintf(net->last_error,ER(net->last_errno),unix_socket,ERRNO);
+ goto error;
+ }
+ }
+ else
+#elif defined(__WIN__)
+ {
+ if ((unix_socket ||
+ !host && is_NT() ||
+ host && !strcmp(host,LOCAL_HOST_NAMEDPIPE) ||
+ mysql->options.named_pipe || !have_tcpip))
+ {
+ sock=0;
+ if ((hPipe=create_named_pipe(net, mysql->options.connect_timeout,
+ (char**) &host, (char**) &unix_socket)) ==
+ INVALID_HANDLE_VALUE)
+ {
+ DBUG_PRINT("error",
+ ("host: '%s' socket: '%s' named_pipe: %d have_tcpip: %d",
+ host ? host : "<null>",
+ unix_socket ? unix_socket : "<null>",
+ (int) mysql->options.named_pipe,
+ (int) have_tcpip));
+ if (mysql->options.named_pipe ||
+ (host && !strcmp(host,LOCAL_HOST_NAMEDPIPE)) ||
+ (unix_socket && !strcmp(unix_socket,MYSQL_NAMEDPIPE)))
+ goto error; /* User only requested named pipes */
+ /* Try also with TCP/IP */
+ }
+ else
+ {
+ net->vio=vio_new_win32pipe(hPipe);
+ sprintf(host_info=buff, ER(CR_NAMEDPIPE_CONNECTION), host,
+ unix_socket);
+ }
+ }
+ }
+ if (hPipe == INVALID_HANDLE_VALUE)
+#endif
+ {
+ unix_socket=0; /* This is not used */
+ if (!port)
+ port=mysql_port;
+ if (!host)
+ host=LOCAL_HOST;
+ sprintf(host_info=buff,ER(CR_TCP_CONNECTION),host);
+ DBUG_PRINT("info",("Server name: '%s'. TCP sock: %d", host,port));
+ if ((sock = socket(AF_INET,SOCK_STREAM,0)) == SOCKET_ERROR)
+ {
+ net->last_errno=CR_IPSOCK_ERROR;
+ sprintf(net->last_error,ER(net->last_errno),ERRNO);
+ goto error;
+ }
+ net->vio = vio_new(sock,VIO_TYPE_TCPIP,FALSE);
+ bzero((char*) &sock_addr,sizeof(sock_addr));
+ sock_addr.sin_family = AF_INET;
+
+ /*
+ ** The server name may be a host name or IP address
+ */
+
+ 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)
+ {
+ net->last_errno=CR_UNKNOWN_HOST;
+ sprintf(net->last_error, ER(CR_UNKNOWN_HOST), host, tmp_errno);
+ goto error;
+ }
+ memcpy(&sock_addr.sin_addr,hp->h_addr, (size_t) hp->h_length);
+ }
+#else
+ {
+ struct hostent *hp;
+ if (!(hp=gethostbyname(host)))
+ {
+ net->last_errno=CR_UNKNOWN_HOST;
+ sprintf(net->last_error, ER(CR_UNKNOWN_HOST), host, errno);
+ goto error;
+ }
+ memcpy(&sock_addr.sin_addr,hp->h_addr, (size_t) hp->h_length);
+ }
+#endif
+ sock_addr.sin_port = (ushort) htons((ushort) port);
+ if (connect2(sock,(struct sockaddr *) &sock_addr, sizeof(sock_addr),
+ mysql->options.connect_timeout) <0)
+ {
+ DBUG_PRINT("error",("Got error %d on connect to '%s'",ERRNO,host));
+ net->last_errno= CR_CONN_HOST_ERROR;
+ sprintf(net->last_error ,ER(CR_CONN_HOST_ERROR), host, ERRNO);
+ goto error;
+ }
+ }
+
+ if (!net->vio || 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;
+ }
+ vio_keepalive(net->vio,TRUE);
+
+ /* Get version info */
+ mysql->protocol_version= PROTOCOL_VERSION; /* Assume this */
+ 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;
+ sprintf(net->last_error,ER(net->last_errno),
+ charset_name ? charset_name : "unknown",
+ mysql->options.charset_dir ? mysql->options.charset_dir :
+ "default");
+ goto error;
+ }
+
+ /* Save connection information */
+ if (!user) user="";
+ if (!passwd) passwd="";
+ 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;
+
+#ifdef HAVE_OPENSSL
+ if (mysql->options.use_ssl)
+ client_flag|=CLIENT_SSL;
+#endif /* HAVE_OPENSSL */
+
+ if (db)
+ client_flag|=CLIENT_CONNECT_WITH_DB;
+#ifdef HAVE_COMPRESS
+ if (mysql->server_capabilities & CLIENT_COMPRESS &&
+ (mysql->options.compress || client_flag & CLIENT_COMPRESS))
+ client_flag|=CLIENT_COMPRESS; /* We will use compression */
+ else
+#endif
+ client_flag&= ~CLIENT_COMPRESS;
+
+#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;
+ }
+#endif /* HAVE_OPENSSL */
+
+ int2store(buff,client_flag);
+ mysql->client_flag=client_flag;
+
+#ifdef HAVE_OPENSSL
+ /* Oops.. are we careful enough to not send ANY information */
+ /* without encryption? */
+ if (client_flag & CLIENT_SSL)
+ {
+ if (my_net_write(net,buff,(uint) (2)) || net_flush(net))
+ 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);
+ }
+#endif /* HAVE_OPENSSL */
+
+ 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 && (mysql->server_capabilities & CLIENT_CONNECT_WITH_DB))
+ {
+ end=strmov(end+1,db);
+ mysql->db=my_strdup(db,MYF(MY_WME));
+ db=0;
+ }
+ if (my_net_write(net,buff,(uint) (end-buff)) || net_flush(net) ||
+ net_safe_read(mysql) == packet_error)
+ goto error;
+ if (client_flag & CLIENT_COMPRESS) /* We will use compression */
+ net->compress=1;
+ 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);
+}
+
+
+static my_bool mysql_reconnect(MYSQL *mysql)
+{
+ MYSQL tmp_mysql;
+ DBUG_ENTER("mysql_reconnect");
+
+ if (!mysql->reconnect ||
+ (mysql->server_status & SERVER_STATUS_IN_TRANS) || !mysql->host_info)
+ {
+ /* Allov reconnect next time */
+ mysql->server_status&= ~SERVER_STATUS_IN_TRANS;
+ DBUG_RETURN(1);
+ }
+ mysql_init(&tmp_mysql);
+ tmp_mysql.options=mysql->options;
+ if (!mysql_real_connect(&tmp_mysql,mysql->host,mysql->user,mysql->passwd,
+ mysql->db, mysql->port, mysql->unix_socket,
+ mysql->client_flag))
+ DBUG_RETURN(1);
+ tmp_mysql.free_me=mysql->free_me;
+ mysql->free_me=0;
+ bzero((char*) &mysql->options,sizeof(mysql->options));
+ mysql_close(mysql);
+ *mysql=tmp_mysql;
+ net_clear(&mysql->net);
+ mysql->affected_rows= ~(my_ulonglong) 0;
+ 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,(uint) (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,(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);
+}
+
+
+/*************************************************************************
+** 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,NullS,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, (uint) strlen(query));
+}
+
+
+int STDCALL
+mysql_real_query(MYSQL *mysql, const char *query, uint length)
+{
+ uchar *pos;
+ ulong field_count;
+ MYSQL_DATA *fields;
+ 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) ||
+ (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);
+}
+
+
+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 dosen'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,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, (uint) 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,(uint) strlen(db),0));
+}
+
+
+int STDCALL
+mysql_shutdown(MYSQL *mysql)
+{
+ DBUG_ENTER("mysql_shutdown");
+ DBUG_RETURN(simple_command(mysql,COM_SHUTDOWN,0,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,0));
+}
+
+char * STDCALL
+mysql_stat(MYSQL *mysql)
+{
+ DBUG_ENTER("mysql_stat");
+ if (simple_command(mysql,COM_STATISTICS,0,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,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/libmysql/net.c b/libmysql/net.c
new file mode 100644
index 00000000000..643b5e031cf
--- /dev/null
+++ b/libmysql/net.c
@@ -0,0 +1,680 @@
+/* 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 */
+
+/* Write and read of logical packets to/from socket
+** Writes are cached into net_buffer_length big packets.
+** Read packets are reallocated dynamicly when reading big packets.
+** Each logical packet has the following pre-info:
+** 3 byte length & 1 byte package-number.
+*/
+
+#ifdef __WIN__
+#include <winsock.h>
+#endif
+#include <global.h>
+#include <violite.h>
+#include <my_sys.h>
+#include <m_string.h>
+#include "mysql.h"
+#include "mysqld_error.h"
+#include <signal.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <violite.h>
+
+#ifdef MYSQL_SERVER
+ulong max_allowed_packet=65536;
+extern ulong net_read_timeout,net_write_timeout;
+extern uint test_flags;
+#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>
+#endif
+#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
+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))
+static 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 pthread_mutex_t LOCK_bytes_sent , LOCK_bytes_received;
+#else
+#undef statistic_add
+#define statistic_add(A,B,C)
+#endif
+
+/*
+** 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.
+*/
+
+#define TEST_BLOCKING 8
+static int net_write_buff(NET *net,const char *packet,uint 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))))
+ return 1;
+ if (net_buffer_length > max_allowed_packet)
+ max_allowed_packet=net_buffer_length;
+ net->buff_end=net->buff+(net->max_packet=net_buffer_length);
+ 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->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;
+
+ if (vio != 0) /* If real connection */
+ {
+ net->fd = vio_fd(vio); /* For perl DBI/DBD */
+#if defined(MYSQL_SERVER) && !defined(___WIN__) && !defined(__EMX__)
+ if (!(test_flags & TEST_BLOCKING))
+ vio_blocking(vio, FALSE);
+#endif
+ vio_fastsend(vio,TRUE);
+ }
+ return 0;
+}
+
+void net_end(NET *net)
+{
+ my_free((gptr) net->buff,MYF(MY_ALLOW_ZERO_PTR));
+ net->buff=0;
+}
+
+/* Realloc the packet buffer */
+
+static my_bool net_realloc(NET *net, ulong length)
+{
+ uchar *buff;
+ ulong pkt_length;
+ if (length >= max_allowed_packet)
+ {
+ DBUG_PRINT("error",("Packet too large (%lu)", length));
+ net->error=1;
+ 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))))
+ {
+ net->error=1;
+#ifdef MYSQL_SERVER
+ net->last_errno=ER_OUT_OF_RESOURCES;
+#endif
+ return 1;
+ }
+ net->buff=net->write_pos=buff;
+ net->buff_end=buff+(net->max_packet=pkt_length);
+ return 0;
+}
+
+ /* Remove unwanted characters from connection */
+
+void net_clear(NET *net)
+{
+#ifndef EXTRA_DEBUG
+ int count;
+ 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)
+ 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->write_pos=net->buff;
+}
+
+ /* Flush write_buffer if not empty. */
+
+int net_flush(NET *net)
+{
+ int error=0;
+ DBUG_ENTER("net_flush");
+ if (net->buff != net->write_pos)
+ {
+ error=net_real_write(net,(char*) net->buff,
+ (uint) (net->write_pos - net->buff));
+ net->write_pos=net->buff;
+ }
+ DBUG_RETURN(error);
+}
+
+
+/*****************************************************************************
+** 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!
+*/
+
+int
+my_net_write(NET *net,const char *packet,ulong len)
+{
+ uchar buff[NET_HEADER_SIZE];
+ int3store(buff,len);
+ buff[3]= (net->compress) ? 0 : (uchar) (net->pkt_nr++);
+ if (net_write_buff(net,(char*) buff,NET_HEADER_SIZE))
+ return 1;
+ return net_write_buff(net,packet,len);
+}
+
+int
+net_write_command(NET *net,uchar command,const char *packet,ulong len)
+{
+ uchar buff[NET_HEADER_SIZE+1];
+ uint length=len+1; /* 1 extra byte for command */
+
+ 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));
+}
+
+
+static int
+net_write_buff(NET *net,const char *packet,uint len)
+{
+ uint left_length=(uint) (net->buff_end - net->write_pos);
+
+ while (len > left_length)
+ {
+ memcpy((char*) net->write_pos,packet,left_length);
+ if (net_real_write(net,(char*) net->buff,net->max_packet))
+ return 1;
+ net->write_pos=net->buff;
+ packet+=left_length;
+ len-=left_length;
+ left_length=net->max_packet;
+ }
+ memcpy((char*) net->write_pos,packet,len);
+ net->write_pos+=len;
+ return 0;
+}
+
+/* Read and write using timeouts */
+
+int
+net_real_write(NET *net,const char *packet,ulong len)
+{
+ int length;
+ char *pos,*end;
+ thr_alarm_t alarmed;
+#if (!defined(__WIN__) && !defined(__EMX__))
+ ALARM alarm_buff;
+#endif
+ uint retry_count=0;
+ my_bool net_blocking = vio_is_blocking(net->vio);
+ DBUG_ENTER("net_real_write");
+
+ if (net->error == 2)
+ DBUG_RETURN(-1); /* socket can't be used */
+
+ net->reading_or_writing=2;
+#ifdef HAVE_COMPRESS
+ if (net->compress)
+ {
+ 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))))
+ {
+#ifdef MYSQL_SERVER
+ net->last_errno=ER_OUT_OF_RESOURCES;
+ net->error=2;
+#endif
+ net->reading_or_writing=0;
+ DBUG_RETURN(1);
+ }
+ memcpy(b+header_length,packet,len);
+
+ if (my_compress((byte*) b+header_length,&len,&complen))
+ {
+ DBUG_PRINT("warning",
+ ("Compression error; Continuing without compression"));
+ complen=0;
+ }
+ int3store(&b[NET_HEADER_SIZE],complen);
+ int3store(b,len);
+ b[3]=(uchar) (net->pkt_nr++);
+ len+= header_length;
+ packet= (char*) b;
+ }
+#endif /* HAVE_COMPRESS */
+
+ /* DBUG_DUMP("net",packet,len); */
+#ifdef MYSQL_SERVER
+ thr_alarm_init(&alarmed);
+ if (net_blocking)
+ thr_alarm(&alarmed,(uint) net_write_timeout,&alarm_buff);
+#else
+ alarmed=0;
+#endif /* MYSQL_SERVER */
+
+ pos=(char*) packet; end=pos+len;
+ while (pos != end)
+ {
+ if ((int) (length=vio_write(net->vio,pos,(size_t) (end-pos))) <= 0)
+ {
+ my_bool interrupted = vio_should_retry(net->vio);
+#if (!defined(__WIN__) && !defined(__EMX__))
+ if ((interrupted || length==0) && !thr_alarm_in_use(alarmed))
+ {
+ if (!thr_alarm(&alarmed,(uint) net_write_timeout,&alarm_buff))
+ { /* Always true for client */
+ if (!vio_is_blocking(net->vio))
+ {
+ while (vio_blocking(net->vio, TRUE) < 0)
+ {
+ if (vio_should_retry(net->vio) && retry_count++ < RETRY_COUNT)
+ continue;
+#ifdef EXTRA_DEBUG
+ fprintf(stderr,
+ "%s: my_net_write: fcntl returned error %d, aborting thread\n",
+ my_progname,vio_errno(net->vio));
+#endif /* EXTRA_DEBUG */
+ net->error=2; /* Close socket */
+ goto end;
+ }
+ }
+ retry_count=0;
+ continue;
+ }
+ }
+ else
+#endif /* (!defined(__WIN__) && !defined(__EMX__)) */
+ if (thr_alarm_in_use(alarmed) && !thr_got_alarm(alarmed) &&
+ interrupted)
+ {
+ if (retry_count++ < RETRY_COUNT)
+ continue;
+#ifdef EXTRA_DEBUG
+ fprintf(stderr, "%s: write looped, aborting thread\n",
+ my_progname);
+#endif /* EXTRA_DEBUG */
+ }
+#if defined(THREAD_SAFE_CLIENT) && !defined(MYSQL_SERVER)
+ if (vio_errno(net->vio) == EINTR)
+ {
+ DBUG_PRINT("warning",("Interrupted write. Retrying..."));
+ continue;
+ }
+#endif /* defined(THREAD_SAFE_CLIENT) && !defined(MYSQL_SERVER) */
+ net->error=2; /* Close socket */
+#ifdef MYSQL_SERVER
+ net->last_errno= (interrupted ? ER_NET_WRITE_INTERRUPTED :
+ ER_NET_ERROR_ON_WRITE);
+#endif /* MYSQL_SERVER */
+ break;
+ }
+ pos+=length;
+ statistic_add(bytes_sent,length,&LOCK_bytes_sent);
+ }
+#ifndef __WIN__
+ end:
+#endif
+#ifdef HAVE_COMPRESS
+ if (net->compress)
+ my_free((char*) packet,MYF(0));
+#endif
+ if (thr_alarm_in_use(alarmed))
+ {
+ thr_end_alarm(&alarmed);
+ vio_blocking(net->vio, net_blocking);
+ }
+ net->reading_or_writing=0;
+ DBUG_RETURN(((int) (pos != end)));
+}
+
+
+/*****************************************************************************
+** Read something from server/clinet
+*****************************************************************************/
+
+#ifdef MYSQL_SERVER
+
+/*
+ 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)
+{
+ char buff[1024];
+ ALARM alarm_buff;
+ uint retry_count=0;
+ if (!thr_alarm_in_use(alarmed))
+ {
+ if (!thr_alarm(alarmed,net->timeout,&alarm_buff) ||
+ (!vio_is_blocking(net->vio) && vio_blocking(net->vio,TRUE) < 0))
+ return; // Can't setup, abort
+ }
+ while (remain > 0)
+ {
+ ulong length;
+ 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)
+ { /* Probably in MIT threads */
+ if (retry_count++ < RETRY_COUNT)
+ continue;
+ }
+ return;
+ }
+ remain -=(ulong) length;
+ statistic_add(bytes_received,(ulong) length,&LOCK_bytes_received);
+ }
+}
+#endif /* MYSQL_SERVER */
+
+
+static uint
+my_real_read(NET *net, ulong *complen)
+{
+ uchar *pos;
+ long length;
+ uint i,retry_count=0;
+ ulong len=packet_error;
+ thr_alarm_t alarmed;
+#if (!defined(__WIN__) && !defined(__EMX__)) || 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);
+ *complen = 0;
+
+ net->reading_or_writing=1;
+ thr_alarm_init(&alarmed);
+#ifdef MYSQL_SERVER
+ if (net_blocking)
+ thr_alarm(&alarmed,net->timeout,&alarm_buff);
+#endif /* MYSQL_SERVER */
+
+ pos = net->buff + net->where_b; /* net->packet -4 */
+ for (i=0 ; i < 2 ; i++)
+ {
+ while (remain > 0)
+ {
+ /* First read is done with non blocking mode */
+ if ((int) (length=vio_read(net->vio,(char*) pos,remain)) <= 0L)
+ {
+ my_bool interrupted = vio_should_retry(net->vio);
+
+ DBUG_PRINT("info",("vio_read returned %d, errno: %d",
+ length, vio_errno(net->vio)));
+#if (!defined(__WIN__) && !defined(__EMX__)) || defined(MYSQL_SERVER)
+ /*
+ We got an error that there was no data on the socket. We now set up
+ an alarm to not 'read forever', change the socket to non blocking
+ mode and try again
+ */
+ if ((interrupted || length == 0) && !thr_alarm_in_use(alarmed))
+ {
+ if (!thr_alarm(&alarmed,net->timeout,&alarm_buff)) /* Don't wait too long */
+ {
+ if (!vio_is_blocking(net->vio))
+ {
+ while (vio_blocking(net->vio,TRUE) < 0)
+ {
+ if (vio_should_retry(net->vio) &&
+ retry_count++ < RETRY_COUNT)
+ continue;
+ DBUG_PRINT("error",
+ ("fcntl returned error %d, aborting thread",
+ vio_errno(net->vio)));
+#ifdef EXTRA_DEBUG
+ fprintf(stderr,
+ "%s: read: fcntl returned error %d, aborting thread\n",
+ my_progname,vio_errno(net->vio));
+#endif /* EXTRA_DEBUG */
+ len= packet_error;
+ net->error=2; /* Close socket */
+#ifdef MYSQL_SERVER
+ net->last_errno=ER_NET_FCNTL_ERROR;
+#endif
+ goto end;
+ }
+ }
+ retry_count=0;
+ continue;
+ }
+ }
+#endif /* (!defined(__WIN__) && !defined(__EMX__)) || defined(MYSQL_SERVER) */
+ if (thr_alarm_in_use(alarmed) && !thr_got_alarm(alarmed) &&
+ interrupted)
+ { /* Probably in MIT threads */
+ if (retry_count++ < RETRY_COUNT)
+ continue;
+#ifdef EXTRA_DEBUG
+ fprintf(stderr, "%s: read looped with error %d, aborting thread\n",
+ my_progname,vio_errno(net->vio));
+#endif /* EXTRA_DEBUG */
+ }
+#if defined(THREAD_SAFE_CLIENT) && !defined(MYSQL_SERVER)
+ if (vio_should_retry(net->vio))
+ {
+ DBUG_PRINT("warning",("Interrupted read. Retrying..."));
+ continue;
+ }
+#endif
+ DBUG_PRINT("error",("Couldn't read packet: remain: %d errno: %d length: %d alarmed: %d", remain,vio_errno(net->vio),length,alarmed));
+ len= packet_error;
+ net->error=2; /* Close socket */
+#ifdef MYSQL_SERVER
+ net->last_errno= (interrupted ? ER_NET_READ_INTERRUPTED :
+ ER_NET_READ_ERROR);
+#endif
+ goto end;
+ }
+ remain -= (ulong) length;
+ pos+= (ulong) length;
+ statistic_add(bytes_received,(ulong) length,&LOCK_bytes_received);
+ }
+ if (i == 0)
+ { /* First parts is packet length */
+ ulong helping;
+ if (net->buff[net->where_b + 3] != (uchar) net->pkt_nr)
+ {
+ if (net->buff[net->where_b] != (uchar) 255)
+ {
+ DBUG_PRINT("error",
+ ("Packets out of order (Found: %d, expected %d)",
+ (int) net->buff[net->where_b + 3],
+ (uint) (uchar) net->pkt_nr));
+#ifdef EXTRA_DEBUG
+ fprintf(stderr,"Packets out of order (Found: %d, expected %d)\n",
+ (int) net->buff[net->where_b + 3],
+ (uint) (uchar) net->pkt_nr);
+#endif
+ }
+ len= packet_error;
+#ifdef MYSQL_SERVER
+ net->last_errno=ER_NET_PACKETS_OUT_OF_ORDER;
+#endif
+ goto end;
+ }
+ net->pkt_nr++;
+#ifdef HAVE_COMPRESS
+ if (net->compress)
+ {
+ /* complen is > 0 if package is really compressed */
+ *complen=uint3korr(&(net->buff[net->where_b + NET_HEADER_SIZE]));
+ }
+#endif
+
+ len=uint3korr(net->buff+net->where_b);
+ 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))
+ {
+#ifdef MYSQL_SERVER
+ if (i == 1)
+ my_net_skip_rest(net, len, &alarmed);
+#endif
+ len= packet_error; /* Return error */
+ goto end;
+ }
+ }
+ pos=net->buff + net->where_b;
+ remain = len;
+ }
+ }
+
+end:
+ if (thr_alarm_in_use(alarmed))
+ {
+ thr_end_alarm(&alarmed);
+ vio_blocking(net->vio, net_blocking);
+ }
+ net->reading_or_writing=0;
+ return(len);
+}
+
+uint
+my_net_read(NET *net)
+{
+ ulong len,complen;
+
+#ifdef HAVE_COMPRESS
+ if (!net->compress)
+ {
+#endif
+ len = my_real_read (net,&complen);
+ 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 (;;)
+ {
+ if (net->remain_in_buf)
+ {
+ uchar *pos = net->buff + net->buf_length - net->remain_in_buf;
+ if (net->remain_in_buf >= 4)
+ {
+ net->length = uint3korr(pos);
+ if (net->length <= net->remain_in_buf - 4)
+ {
+ /* 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 */
+ }
+ }
+ /* Move data down to read next data packet after current one */
+ if (net->buf_length != net->remain_in_buf)
+ {
+ memmove(net->buff,pos,net->remain_in_buf);
+ net->buf_length=net->remain_in_buf;
+ }
+ 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 */
+#ifdef MYSQL_SERVER
+ net->last_errno=ER_NET_UNCOMPRESS_ERROR;
+#endif
+ break;
+ }
+ net->buf_length+=len;
+ net->remain_in_buf+=len;
+ }
+ if (len != packet_error)
+ {
+ net->save_char= net->read_pos[len]; /* Must be saved */
+ net->read_pos[len]=0; /* Safeguard for mysql_use_result */
+ }
+ return len;
+#endif
+}
diff --git a/libmysql/password.c b/libmysql/password.c
new file mode 100644
index 00000000000..0fd5861873a
--- /dev/null
+++ b/libmysql/password.c
@@ -0,0 +1,192 @@
+/* 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 */
+
+/* password checking routines */
+/*****************************************************************************
+ The main idea is that no password are sent between client & server on
+ connection and that no password are saved in mysql in a decodable form.
+
+ On connection a random string is generated and sent to the client.
+ The client generates a new string with a random generator inited with
+ the hash values from the password and the sent string.
+ This 'check' string is sent to the server where it is compared with
+ a string generated from the stored hash_value of the password and the
+ random string.
+
+ The password is saved (in user.password) by using the PASSWORD() function in
+ mysql.
+
+ Example:
+ update user set password=PASSWORD("hello") where user="test"
+ This saves a hashed number as a string in the password field.
+*****************************************************************************/
+
+#include <global.h>
+#include <my_sys.h>
+#include <m_string.h>
+#include "mysql.h"
+
+
+void randominit(struct rand_struct *rand_st,ulong seed1, ulong seed2)
+{ /* For mysql 3.21.# */
+#ifdef HAVE_purify
+ bzero((char*) rand_st,sizeof(*rand_st)); /* Avoid UMC varnings */
+#endif
+ rand_st->max_value= 0x3FFFFFFFL;
+ rand_st->max_value_dbl=(double) rand_st->max_value;
+ rand_st->seed1=seed1%rand_st->max_value ;
+ rand_st->seed2=seed2%rand_st->max_value;
+}
+
+static void old_randominit(struct rand_struct *rand_st,ulong seed1)
+{ /* For mysql 3.20.# */
+ rand_st->max_value= 0x01FFFFFFL;
+ rand_st->max_value_dbl=(double) rand_st->max_value;
+ seed1%=rand_st->max_value;
+ rand_st->seed1=seed1 ; rand_st->seed2=seed1/2;
+}
+
+double rnd(struct rand_struct *rand_st)
+{
+ rand_st->seed1=(rand_st->seed1*3+rand_st->seed2) % rand_st->max_value;
+ rand_st->seed2=(rand_st->seed1+rand_st->seed2+33) % rand_st->max_value;
+ return (((double) rand_st->seed1)/rand_st->max_value_dbl);
+}
+
+void hash_password(ulong *result, const char *password)
+{
+ register ulong nr=1345345333L, add=7, nr2=0x12345671L;
+ ulong tmp;
+ for (; *password ; password++)
+ {
+ if (*password == ' ' || *password == '\t')
+ continue; /* skipp space in password */
+ tmp= (ulong) (uchar) *password;
+ nr^= (((nr & 63)+add)*tmp)+ (nr << 8);
+ nr2+=(nr2 << 8) ^ nr;
+ add+=tmp;
+ }
+ result[0]=nr & (((ulong) 1L << 31) -1L); /* Don't use sign bit (str2int) */;
+ result[1]=nr2 & (((ulong) 1L << 31) -1L);
+ return;
+}
+
+void make_scrambled_password(char *to,const char *password)
+{
+ ulong hash_res[2];
+ hash_password(hash_res,password);
+ sprintf(to,"%08lx%08lx",hash_res[0],hash_res[1]);
+}
+
+static inline uint char_val(char X)
+{
+ return (uint) (X >= '0' && X <= '9' ? X-'0' :
+ X >= 'A' && X <= 'Z' ? X-'A'+10 :
+ X-'a'+10);
+}
+
+/*
+** This code assumes that len(password) is divideable with 8 and that
+** res is big enough (2 in mysql)
+*/
+
+void get_salt_from_password(ulong *res,const char *password)
+{
+ res[0]=res[1]=0;
+ if (password)
+ {
+ while (*password)
+ {
+ ulong val=0;
+ uint i;
+ for (i=0 ; i < 8 ; i++)
+ val=(val << 4)+char_val(*password++);
+ *res++=val;
+ }
+ }
+ return;
+}
+
+void make_password_from_salt(char *to, ulong *hash_res)
+{
+ sprintf(to,"%08lx%08lx",hash_res[0],hash_res[1]);
+}
+
+
+/*
+ * Genererate a new message based on message and password
+ * The same thing is done in client and server and the results are checked.
+ */
+
+char *scramble(char *to,const char *message,const char *password,
+ my_bool old_ver)
+{
+ struct rand_struct rand_st;
+ ulong hash_pass[2],hash_message[2];
+ if (password && password[0])
+ {
+ char *to_start=to;
+ hash_password(hash_pass,password);
+ hash_password(hash_message,message);
+ if (old_ver)
+ old_randominit(&rand_st,hash_pass[0] ^ hash_message[0]);
+ else
+ randominit(&rand_st,hash_pass[0] ^ hash_message[0],
+ hash_pass[1] ^ hash_message[1]);
+ while (*message++)
+ *to++= (char) (floor(rnd(&rand_st)*31)+64);
+ if (!old_ver)
+ { /* Make it harder to break */
+ char extra=(char) (floor(rnd(&rand_st)*31));
+ while (to_start != to)
+ *(to_start++)^=extra;
+ }
+ }
+ *to=0;
+ return to;
+}
+
+
+my_bool check_scramble(const char *scrambled, const char *message,
+ ulong *hash_pass, my_bool old_ver)
+{
+ struct rand_struct rand_st;
+ ulong hash_message[2];
+ char buff[16],*to,extra; /* Big enough for check */
+ const char *pos;
+
+ hash_password(hash_message,message);
+ if (old_ver)
+ old_randominit(&rand_st,hash_pass[0] ^ hash_message[0]);
+ else
+ randominit(&rand_st,hash_pass[0] ^ hash_message[0],
+ hash_pass[1] ^ hash_message[1]);
+ to=buff;
+ for (pos=scrambled ; *pos ; pos++)
+ *to++=(char) (floor(rnd(&rand_st)*31)+64);
+ if (old_ver)
+ extra=0;
+ else
+ extra=(char) (floor(rnd(&rand_st)*31));
+ to=buff;
+ while (*scrambled)
+ {
+ if (*scrambled++ != (char) (*to++ ^ extra))
+ return 1; /* Wrong password */
+ }
+ return 0;
+}
diff --git a/libmysql/violite.c b/libmysql/violite.c
new file mode 100644
index 00000000000..349a6fbd849
--- /dev/null
+++ b/libmysql/violite.c
@@ -0,0 +1,400 @@
+/* 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>
+
+#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) */
+ 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, "socket (%d)", vio->sd);
+#if !defined(___WIN__) && !defined(__EMX__)
+#if !defined(NO_FCNTL_NONBLOCK)
+ vio->fcntl_mode = fcntl(sd, F_GETFL);
+#endif
+#else /* !defined(__WIN__) && !defined(__EMX__) */
+ {
+ /* set to blocking mode by default */
+ ulong arg=0;
+ 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 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));
+#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));
+#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 (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, my_bool onoff)
+{
+ int r=0;
+ DBUG_ENTER("vio_fastsend");
+ DBUG_PRINT("enter", ("onoff:%d", (int) onoff));
+
+#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 = errno;
+ return en == EAGAIN || en == EINTR || en == 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("error", ("close() failed, error: %d",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", 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/ltconfig b/ltconfig
new file mode 100755
index 00000000000..a6d3dfd4567
--- /dev/null
+++ b/ltconfig
@@ -0,0 +1,3023 @@
+#! /bin/sh
+
+# ltconfig - Create a system-specific libtool.
+# Copyright (C) 1996-1999 Free Software Foundation, Inc.
+# Originally by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996
+#
+# 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.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# A lot of this script is taken from autoconf-2.10.
+
+# Check that we are running under the correct shell.
+SHELL=${CONFIG_SHELL-/bin/sh}
+echo=echo
+if test "X$1" = X--no-reexec; then
+ # Discard the --no-reexec flag, and continue.
+ shift
+elif test "X$1" = X--fallback-echo; then
+ # Avoid inline document here, it may be left over
+ :
+elif test "X`($echo '\t') 2>/dev/null`" = 'X\t'; then
+ # Yippee, $echo works!
+ :
+else
+ # Restart under the correct shell.
+ exec "$SHELL" "$0" --no-reexec ${1+"$@"}
+fi
+
+if test "X$1" = X--fallback-echo; then
+ # used as fallback echo
+ shift
+ cat <<EOF
+$*
+EOF
+ exit 0
+fi
+
+# Find the correct PATH separator. Usually this is `:', but
+# DJGPP uses `;' like DOS.
+if test "X${PATH_SEPARATOR+set}" != "Xset"; then
+ UNAME=${UNAME-`uname 2>/dev/null`}
+ case X$UNAME in
+ *-DOS) PATH_SEPARATOR=';' ;;
+ *) PATH_SEPARATOR=':' ;;
+ esac
+fi
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+if test "${CDPATH+set}" = set; then CDPATH=; export CDPATH; fi
+
+if test "X${echo_test_string+set}" != "Xset"; then
+ # find a string as large as possible, as long as the shell can cope with it
+ for cmd in 'sed 50q "$0"' 'sed 20q "$0"' 'sed 10q "$0"' 'sed 2q "$0"' 'echo test'; do
+ # expected sizes: less than 2Kb, 1Kb, 512 bytes, 16 bytes, ...
+ if (echo_test_string="`eval $cmd`") 2>/dev/null &&
+ echo_test_string="`eval $cmd`" &&
+ (test "X$echo_test_string" = "X$echo_test_string") 2>/dev/null; then
+ break
+ fi
+ done
+fi
+
+if test "X`($echo '\t') 2>/dev/null`" != 'X\t' ||
+ test "X`($echo "$echo_test_string") 2>/dev/null`" != X"$echo_test_string"; then
+ # The Solaris, AIX, and Digital Unix default echo programs unquote
+ # backslashes. This makes it impossible to quote backslashes using
+ # echo "$something" | sed 's/\\/\\\\/g'
+ #
+ # So, first we look for a working echo in the user's PATH.
+
+ IFS="${IFS= }"; save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR}"
+ for dir in $PATH /usr/ucb; do
+ if (test -f $dir/echo || test -f $dir/echo$ac_exeext) &&
+ test "X`($dir/echo '\t') 2>/dev/null`" = 'X\t' &&
+ test "X`($dir/echo "$echo_test_string") 2>/dev/null`" = X"$echo_test_string"; then
+ echo="$dir/echo"
+ break
+ fi
+ done
+ IFS="$save_ifs"
+
+ if test "X$echo" = Xecho; then
+ # We didn't find a better echo, so look for alternatives.
+ if test "X`(print -r '\t') 2>/dev/null`" = 'X\t' &&
+ test "X`(print -r "$echo_test_string") 2>/dev/null`" = X"$echo_test_string"; then
+ # This shell has a builtin print -r that does the trick.
+ echo='print -r'
+ elif (test -f /bin/ksh || test -f /bin/ksh$ac_exeext) &&
+ test "X$CONFIG_SHELL" != X/bin/ksh; then
+ # If we have ksh, try running ltconfig again with it.
+ ORIGINAL_CONFIG_SHELL="${CONFIG_SHELL-/bin/sh}"
+ export ORIGINAL_CONFIG_SHELL
+ CONFIG_SHELL=/bin/ksh
+ export CONFIG_SHELL
+ exec "$CONFIG_SHELL" "$0" --no-reexec ${1+"$@"}
+ else
+ # Try using printf.
+ echo='printf "%s\n"'
+ if test "X`($echo '\t') 2>/dev/null`" = 'X\t' &&
+ test "X`($echo "$echo_test_string") 2>/dev/null`" = X"$echo_test_string"; then
+ # Cool, printf works
+ :
+ elif test "X`("$ORIGINAL_CONFIG_SHELL" "$0" --fallback-echo '\t') 2>/dev/null`" = 'X\t' &&
+ test "X`("$ORIGINAL_CONFIG_SHELL" "$0" --fallback-echo "$echo_test_string") 2>/dev/null`" = X"$echo_test_string"; then
+ CONFIG_SHELL="$ORIGINAL_CONFIG_SHELL"
+ export CONFIG_SHELL
+ SHELL="$CONFIG_SHELL"
+ export SHELL
+ echo="$CONFIG_SHELL $0 --fallback-echo"
+ elif test "X`("$CONFIG_SHELL" "$0" --fallback-echo '\t') 2>/dev/null`" = 'X\t' &&
+ test "X`("$CONFIG_SHELL" "$0" --fallback-echo "$echo_test_string") 2>/dev/null`" = X"$echo_test_string"; then
+ echo="$CONFIG_SHELL $0 --fallback-echo"
+ else
+ # maybe with a smaller string...
+ prev=:
+
+ for cmd in 'echo test' 'sed 2q "$0"' 'sed 10q "$0"' 'sed 20q "$0"' 'sed 50q "$0"'; do
+ if (test "X$echo_test_string" = "X`eval $cmd`") 2>/dev/null; then
+ break
+ fi
+ prev="$cmd"
+ done
+
+ if test "$prev" != 'sed 50q "$0"'; then
+ echo_test_string=`eval $prev`
+ export echo_test_string
+ exec "${ORIGINAL_CONFIG_SHELL}" "$0" ${1+"$@"}
+ else
+ # Oops. We lost completely, so just stick with echo.
+ echo=echo
+ fi
+ fi
+ fi
+ fi
+fi
+
+# Sed substitution that helps us do robust quoting. It backslashifies
+# metacharacters that are still active within double-quoted strings.
+Xsed='sed -e s/^X//'
+sed_quote_subst='s/\([\\"\\`$\\\\]\)/\\\1/g'
+
+# Same as above, but do not quote variable references.
+double_quote_subst='s/\([\\"\\`\\\\]\)/\\\1/g'
+
+# Sed substitution to delay expansion of an escaped shell variable in a
+# double_quote_subst'ed string.
+delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g'
+
+# The name of this program.
+progname=`$echo "X$0" | $Xsed -e 's%^.*/%%'`
+
+# Constants:
+PROGRAM=ltconfig
+PACKAGE=libtool
+VERSION=1.3.3
+TIMESTAMP=" (1.385.2.181 1999/07/02 15:49:11)"
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.c 1>&5'
+ac_link='${CC-cc} -o conftest $CFLAGS $CPPFLAGS $LDFLAGS conftest.c $LIBS 1>&5'
+rm="rm -f"
+
+help="Try \`$progname --help' for more information."
+
+# Global variables:
+default_ofile=libtool
+can_build_shared=yes
+enable_shared=yes
+# All known linkers require a `.a' archive for static linking (except M$VC,
+# which needs '.lib').
+enable_static=yes
+enable_fast_install=yes
+enable_dlopen=unknown
+enable_win32_dll=no
+ltmain=
+silent=
+srcdir=
+ac_config_guess=
+ac_config_sub=
+host=
+nonopt=
+ofile="$default_ofile"
+verify_host=yes
+with_gcc=no
+with_gnu_ld=no
+need_locks=yes
+ac_ext=c
+objext=o
+libext=a
+exeext=
+cache_file=
+
+old_AR="$AR"
+old_CC="$CC"
+old_CFLAGS="$CFLAGS"
+old_CPPFLAGS="$CPPFLAGS"
+old_LDFLAGS="$LDFLAGS"
+old_LD="$LD"
+old_LN_S="$LN_S"
+old_LIBS="$LIBS"
+old_NM="$NM"
+old_RANLIB="$RANLIB"
+old_DLLTOOL="$DLLTOOL"
+old_OBJDUMP="$OBJDUMP"
+old_AS="$AS"
+
+# Parse the command line options.
+args=
+prev=
+for option
+do
+ case "$option" in
+ -*=*) optarg=`echo "$option" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
+ *) optarg= ;;
+ esac
+
+ # If the previous option needs an argument, assign it.
+ if test -n "$prev"; then
+ eval "$prev=\$option"
+ prev=
+ continue
+ fi
+
+ case "$option" in
+ --help) cat <<EOM
+Usage: $progname [OPTION]... [HOST [LTMAIN]]
+
+Generate a system-specific libtool script.
+
+ --debug enable verbose shell tracing
+ --disable-shared do not build shared libraries
+ --disable-static do not build static libraries
+ --disable-fast-install do not optimize for fast installation
+ --enable-dlopen enable dlopen support
+ --enable-win32-dll enable building dlls on win32 hosts
+ --help display this help and exit
+ --no-verify do not verify that HOST is a valid host type
+-o, --output=FILE specify the output file [default=$default_ofile]
+ --quiet same as \`--silent'
+ --silent do not print informational messages
+ --srcdir=DIR find \`config.guess' in DIR
+ --version output version information and exit
+ --with-gcc assume that the GNU C compiler will be used
+ --with-gnu-ld assume that the C compiler uses the GNU linker
+ --disable-lock disable file locking
+ --cache-file=FILE configure cache file
+
+LTMAIN is the \`ltmain.sh' shell script fragment or \`ltmain.c' program
+that provides basic libtool functionality.
+
+HOST is the canonical host system name [default=guessed].
+EOM
+ exit 0
+ ;;
+
+ --debug)
+ echo "$progname: enabling shell trace mode"
+ set -x
+ ;;
+
+ --disable-shared) enable_shared=no ;;
+
+ --disable-static) enable_static=no ;;
+
+ --disable-fast-install) enable_fast_install=no ;;
+
+ --enable-dlopen) enable_dlopen=yes ;;
+
+ --enable-win32-dll) enable_win32_dll=yes ;;
+
+ --quiet | --silent) silent=yes ;;
+
+ --srcdir) prev=srcdir ;;
+ --srcdir=*) srcdir="$optarg" ;;
+
+ --no-verify) verify_host=no ;;
+
+ --output | -o) prev=ofile ;;
+ --output=*) ofile="$optarg" ;;
+
+ --version) echo "$PROGRAM (GNU $PACKAGE) $VERSION$TIMESTAMP"; exit 0 ;;
+
+ --with-gcc) with_gcc=yes ;;
+ --with-gnu-ld) with_gnu_ld=yes ;;
+
+ --disable-lock) need_locks=no ;;
+
+ --cache-file=*) cache_file="$optarg" ;;
+
+ -*)
+ echo "$progname: unrecognized option \`$option'" 1>&2
+ echo "$help" 1>&2
+ exit 1
+ ;;
+
+ *)
+ if test -z "$ltmain"; then
+ ltmain="$option"
+ elif test -z "$host"; then
+# This generates an unnecessary warning for sparc-sun-solaris4.1.3_U1
+# if test -n "`echo $option| sed 's/[-a-z0-9.]//g'`"; then
+# echo "$progname: warning \`$option' is not a valid host type" 1>&2
+# fi
+ host="$option"
+ else
+ echo "$progname: too many arguments" 1>&2
+ echo "$help" 1>&2
+ exit 1
+ fi ;;
+ esac
+done
+
+if test -z "$ltmain"; then
+ echo "$progname: you must specify a LTMAIN file" 1>&2
+ echo "$help" 1>&2
+ exit 1
+fi
+
+if test ! -f "$ltmain"; then
+ echo "$progname: \`$ltmain' does not exist" 1>&2
+ echo "$help" 1>&2
+ exit 1
+fi
+
+# Quote any args containing shell metacharacters.
+ltconfig_args=
+for arg
+do
+ case "$arg" in
+ *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*)
+ ltconfig_args="$ltconfig_args '$arg'" ;;
+ *) ltconfig_args="$ltconfig_args $arg" ;;
+ esac
+done
+
+# A relevant subset of AC_INIT.
+
+# File descriptor usage:
+# 0 standard input
+# 1 file creation
+# 2 errors and warnings
+# 3 some systems may open it to /dev/tty
+# 4 used on the Kubota Titan
+# 5 compiler messages saved in config.log
+# 6 checking for... messages and results
+if test "$silent" = yes; then
+ exec 6>/dev/null
+else
+ exec 6>&1
+fi
+exec 5>>./config.log
+
+# NLS nuisances.
+# Only set LANG and LC_ALL to C if already set.
+# These must not be set unconditionally because not all systems understand
+# e.g. LANG=C (notably SCO).
+if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi
+if test "${LANG+set}" = set; then LANG=C; export LANG; fi
+
+if test -n "$cache_file" && test -r "$cache_file"; then
+ echo "loading cache $cache_file within ltconfig"
+ . $cache_file
+fi
+
+if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then
+ # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu.
+ if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then
+ ac_n= ac_c='
+' ac_t=' '
+ else
+ ac_n=-n ac_c= ac_t=
+ fi
+else
+ ac_n= ac_c='\c' ac_t=
+fi
+
+if test -z "$srcdir"; then
+ # Assume the source directory is the same one as the path to LTMAIN.
+ srcdir=`$echo "X$ltmain" | $Xsed -e 's%/[^/]*$%%'`
+ test "$srcdir" = "$ltmain" && srcdir=.
+fi
+
+trap "$rm conftest*; exit 1" 1 2 15
+if test "$verify_host" = yes; then
+ # Check for config.guess and config.sub.
+ ac_aux_dir=
+ for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do
+ if test -f $ac_dir/config.guess; then
+ ac_aux_dir=$ac_dir
+ break
+ fi
+ done
+ if test -z "$ac_aux_dir"; then
+ echo "$progname: cannot find config.guess in $srcdir $srcdir/.. $srcdir/../.." 1>&2
+ echo "$help" 1>&2
+ exit 1
+ fi
+ ac_config_guess=$ac_aux_dir/config.guess
+ ac_config_sub=$ac_aux_dir/config.sub
+
+ # Make sure we can run config.sub.
+ if $SHELL $ac_config_sub sun4 >/dev/null 2>&1; then :
+ else
+ echo "$progname: cannot run $ac_config_sub" 1>&2
+ echo "$help" 1>&2
+ exit 1
+ fi
+
+ echo $ac_n "checking host system type""... $ac_c" 1>&6
+
+ host_alias=$host
+ case "$host_alias" in
+ "")
+ if host_alias=`$SHELL $ac_config_guess`; then :
+ else
+ echo "$progname: cannot guess host type; you must specify one" 1>&2
+ echo "$help" 1>&2
+ exit 1
+ fi ;;
+ esac
+ host=`$SHELL $ac_config_sub $host_alias`
+ echo "$ac_t$host" 1>&6
+
+ # Make sure the host verified.
+ test -z "$host" && exit 1
+
+elif test -z "$host"; then
+ echo "$progname: you must specify a host type if you use \`--no-verify'" 1>&2
+ echo "$help" 1>&2
+ exit 1
+else
+ host_alias=$host
+fi
+
+# Transform linux* to *-*-linux-gnu*, to support old configure scripts.
+case "$host_os" in
+linux-gnu*) ;;
+linux*) host=`echo $host | sed 's/^\(.*-.*-linux\)\(.*\)$/\1-gnu\2/'`
+esac
+
+host_cpu=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
+host_vendor=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
+host_os=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
+
+case "$host_os" in
+aix3*)
+ # AIX sometimes has problems with the GCC collect2 program. For some
+ # reason, if we set the COLLECT_NAMES environment variable, the problems
+ # vanish in a puff of smoke.
+ if test "${COLLECT_NAMES+set}" != set; then
+ COLLECT_NAMES=
+ export COLLECT_NAMES
+ fi
+ ;;
+esac
+
+# Determine commands to create old-style static archives.
+old_archive_cmds='$AR cru $oldlib$oldobjs'
+old_postinstall_cmds='chmod 644 $oldlib'
+old_postuninstall_cmds=
+
+# Set a sane default for `AR'.
+test -z "$AR" && AR=ar
+
+# Set a sane default for `OBJDUMP'.
+test -z "$OBJDUMP" && OBJDUMP=objdump
+
+# If RANLIB is not set, then run the test.
+if test "${RANLIB+set}" != "set"; then
+ result=no
+
+ echo $ac_n "checking for ranlib... $ac_c" 1>&6
+ IFS="${IFS= }"; save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR}"
+ for dir in $PATH; do
+ test -z "$dir" && dir=.
+ if test -f $dir/ranlib || test -f $dir/ranlib$ac_exeext; then
+ RANLIB="ranlib"
+ result="ranlib"
+ break
+ fi
+ done
+ IFS="$save_ifs"
+
+ echo "$ac_t$result" 1>&6
+fi
+
+if test -n "$RANLIB"; then
+ old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib"
+ old_postinstall_cmds="\$RANLIB \$oldlib~$old_postinstall_cmds"
+fi
+
+# Set sane defaults for `DLLTOOL', `OBJDUMP', and `AS', used on cygwin.
+test -z "$DLLTOOL" && DLLTOOL=dlltool
+test -z "$OBJDUMP" && OBJDUMP=objdump
+test -z "$AS" && AS=as
+
+# Check to see if we are using GCC.
+if test "$with_gcc" != yes || test -z "$CC"; then
+ # If CC is not set, then try to find GCC or a usable CC.
+ if test -z "$CC"; then
+ echo $ac_n "checking for gcc... $ac_c" 1>&6
+ IFS="${IFS= }"; save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR}"
+ for dir in $PATH; do
+ test -z "$dir" && dir=.
+ if test -f $dir/gcc || test -f $dir/gcc$ac_exeext; then
+ CC="gcc"
+ break
+ fi
+ done
+ IFS="$save_ifs"
+
+ if test -n "$CC"; then
+ echo "$ac_t$CC" 1>&6
+ else
+ echo "$ac_t"no 1>&6
+ fi
+ fi
+
+ # Not "gcc", so try "cc", rejecting "/usr/ucb/cc".
+ if test -z "$CC"; then
+ echo $ac_n "checking for cc... $ac_c" 1>&6
+ IFS="${IFS= }"; save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR}"
+ cc_rejected=no
+ for dir in $PATH; do
+ test -z "$dir" && dir=.
+ if test -f $dir/cc || test -f $dir/cc$ac_exeext; then
+ if test "$dir/cc" = "/usr/ucb/cc"; then
+ cc_rejected=yes
+ continue
+ fi
+ CC="cc"
+ break
+ fi
+ done
+ IFS="$save_ifs"
+ if test $cc_rejected = yes; then
+ # We found a bogon in the path, so make sure we never use it.
+ set dummy $CC
+ shift
+ if test $# -gt 0; then
+ # We chose a different compiler from the bogus one.
+ # However, it has the same name, so the bogon will be chosen
+ # first if we set CC to just the name; use the full file name.
+ shift
+ set dummy "$dir/cc" "$@"
+ shift
+ CC="$@"
+ fi
+ fi
+
+ if test -n "$CC"; then
+ echo "$ac_t$CC" 1>&6
+ else
+ echo "$ac_t"no 1>&6
+ fi
+
+ if test -z "$CC"; then
+ echo "$progname: error: no acceptable cc found in \$PATH" 1>&2
+ exit 1
+ fi
+ fi
+
+ # Now see if the compiler is really GCC.
+ with_gcc=no
+ echo $ac_n "checking whether we are using GNU C... $ac_c" 1>&6
+ echo "$progname:581: checking whether we are using GNU C" >&5
+
+ $rm conftest.c
+ cat > conftest.c <<EOF
+#ifdef __GNUC__
+ yes;
+#endif
+EOF
+ if { ac_try='${CC-cc} -E conftest.c'; { (eval echo $progname:589: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
+ with_gcc=yes
+ fi
+ $rm conftest.c
+ echo "$ac_t$with_gcc" 1>&6
+fi
+
+# Allow CC to be a program name with arguments.
+set dummy $CC
+compiler="$2"
+
+echo $ac_n "checking for object suffix... $ac_c" 1>&6
+$rm conftest*
+echo 'int i = 1;' > conftest.c
+echo "$progname:603: checking for object suffix" >& 5
+if { (eval echo $progname:604: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>conftest.err; }; then
+ # Append any warnings to the config.log.
+ cat conftest.err 1>&5
+
+ for ac_file in conftest.*; do
+ case $ac_file in
+ *.c) ;;
+ *) objext=`echo $ac_file | sed -e s/conftest.//` ;;
+ esac
+ done
+else
+ cat conftest.err 1>&5
+ echo "$progname: failed program was:" >&5
+ cat conftest.c >&5
+fi
+$rm conftest*
+echo "$ac_t$objext" 1>&6
+
+echo $ac_n "checking for executable suffix... $ac_c" 1>&6
+if eval "test \"`echo '$''{'ac_cv_exeext'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_cv_exeext="no"
+ $rm conftest*
+ echo 'main () { return 0; }' > conftest.c
+ echo "$progname:629: checking for executable suffix" >& 5
+ if { (eval echo $progname:630: \"$ac_link\") 1>&5; (eval $ac_link) 2>conftest.err; }; then
+ # Append any warnings to the config.log.
+ cat conftest.err 1>&5
+
+ for ac_file in conftest.*; do
+ case $ac_file in
+ *.c | *.err | *.$objext ) ;;
+ *) ac_cv_exeext=.`echo $ac_file | sed -e s/conftest.//` ;;
+ esac
+ done
+ else
+ cat conftest.err 1>&5
+ echo "$progname: failed program was:" >&5
+ cat conftest.c >&5
+ fi
+ $rm conftest*
+fi
+if test "X$ac_cv_exeext" = Xno; then
+ exeext=""
+else
+ exeext="$ac_cv_exeext"
+fi
+echo "$ac_t$ac_cv_exeext" 1>&6
+
+echo $ac_n "checking for $compiler option to produce PIC... $ac_c" 1>&6
+pic_flag=
+special_shlib_compile_flags=
+wl=
+link_static_flag=
+no_builtin_flag=
+
+if test "$with_gcc" = yes; then
+ wl='-Wl,'
+ link_static_flag='-static'
+
+ case "$host_os" in
+ beos* | irix5* | irix6* | osf3* | osf4*)
+ # PIC is the default for these OSes.
+ ;;
+ aix*)
+ # Below there is a dirty hack to force normal static linking with -ldl
+ # The problem is because libdl dynamically linked with both libc and
+ # libC (AIX C++ library), which obviously doesn't included in libraries
+ # list by gcc. This cause undefined symbols with -static flags.
+ # This hack allows C programs to be linked with "-static -ldl", but
+ # we not sure about C++ programs.
+ link_static_flag="$link_static_flag ${wl}-lC"
+ ;;
+ cygwin* | mingw* | os2*)
+ # We can build DLLs from non-PIC.
+ ;;
+ amigaos*)
+ # FIXME: we need at least 68020 code to build shared libraries, but
+ # adding the `-m68020' flag to GCC prevents building anything better,
+ # like `-m68040'.
+ pic_flag='-m68020 -resident32 -malways-restore-a4'
+ ;;
+ sysv4*MP*)
+ if test -d /usr/nec; then
+ pic_flag=-Kconform_pic
+ fi
+ ;;
+ *)
+ pic_flag='-fPIC'
+ ;;
+ esac
+else
+ # PORTME Check for PIC flags for the system compiler.
+ case "$host_os" in
+ aix3* | aix4*)
+ # All AIX code is PIC.
+ link_static_flag='-bnso -bI:/lib/syscalls.exp'
+ ;;
+
+ hpux9* | hpux10* | hpux11*)
+ # Is there a better link_static_flag that works with the bundled CC?
+ wl='-Wl,'
+ link_static_flag="${wl}-a ${wl}archive"
+ pic_flag='+Z'
+ ;;
+
+ irix5* | irix6*)
+ wl='-Wl,'
+ link_static_flag='-non_shared'
+ # PIC (with -KPIC) is the default.
+ ;;
+
+ cygwin* | mingw* | os2*)
+ # We can build DLLs from non-PIC.
+ ;;
+
+ osf3* | osf4*)
+ # All OSF/1 code is PIC.
+ wl='-Wl,'
+ link_static_flag='-non_shared'
+ ;;
+
+ sco3.2v5*)
+ pic_flag='-Kpic'
+ link_static_flag='-dn'
+ special_shlib_compile_flags='-belf'
+ ;;
+
+ solaris*)
+ pic_flag='-KPIC'
+ link_static_flag='-Bstatic'
+ wl='-Wl,'
+ ;;
+
+ sunos4*)
+ pic_flag='-PIC'
+ link_static_flag='-Bstatic'
+ wl='-Qoption ld '
+ ;;
+
+ sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+ pic_flag='-KPIC'
+ link_static_flag='-Bstatic'
+ wl='-Wl,'
+ ;;
+
+ uts4*)
+ pic_flag='-pic'
+ link_static_flag='-Bstatic'
+ ;;
+ sysv4*MP*)
+ if test -d /usr/nec ;then
+ pic_flag='-Kconform_pic'
+ link_static_flag='-Bstatic'
+ fi
+ ;;
+ *)
+ can_build_shared=no
+ ;;
+ esac
+fi
+
+if test -n "$pic_flag"; then
+ echo "$ac_t$pic_flag" 1>&6
+
+ # Check to make sure the pic_flag actually works.
+ echo $ac_n "checking if $compiler PIC flag $pic_flag works... $ac_c" 1>&6
+ $rm conftest*
+ echo "int some_variable = 0;" > conftest.c
+ save_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS $pic_flag -DPIC"
+ echo "$progname:776: checking if $compiler PIC flag $pic_flag works" >&5
+ if { (eval echo $progname:777: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>conftest.err; } && test -s conftest.$objext; then
+ # Append any warnings to the config.log.
+ cat conftest.err 1>&5
+
+ case "$host_os" in
+ hpux9* | hpux10* | hpux11*)
+ # On HP-UX, both CC and GCC only warn that PIC is supported... then they
+ # create non-PIC objects. So, if there were any warnings, we assume that
+ # PIC is not supported.
+ if test -s conftest.err; then
+ echo "$ac_t"no 1>&6
+ can_build_shared=no
+ pic_flag=
+ else
+ echo "$ac_t"yes 1>&6
+ pic_flag=" $pic_flag"
+ fi
+ ;;
+ *)
+ echo "$ac_t"yes 1>&6
+ pic_flag=" $pic_flag"
+ ;;
+ esac
+ else
+ # Append any errors to the config.log.
+ cat conftest.err 1>&5
+ can_build_shared=no
+ pic_flag=
+ echo "$ac_t"no 1>&6
+ fi
+ CFLAGS="$save_CFLAGS"
+ $rm conftest*
+else
+ echo "$ac_t"none 1>&6
+fi
+
+# Check to see if options -o and -c are simultaneously supported by compiler
+echo $ac_n "checking if $compiler supports -c -o file.o... $ac_c" 1>&6
+$rm -r conftest 2>/dev/null
+mkdir conftest
+cd conftest
+$rm conftest*
+echo "int some_variable = 0;" > conftest.c
+mkdir out
+# According to Tom Tromey, Ian Lance Taylor reported there are C compilers
+# that will create temporary files in the current directory regardless of
+# the output directory. Thus, making CWD read-only will cause this test
+# to fail, enabling locking or at least warning the user not to do parallel
+# builds.
+chmod -w .
+save_CFLAGS="$CFLAGS"
+CFLAGS="$CFLAGS -o out/conftest2.o"
+echo "$progname:829: checking if $compiler supports -c -o file.o" >&5
+if { (eval echo $progname:830: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>out/conftest.err; } && test -s out/conftest2.o; then
+
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ if test -s out/conftest.err; then
+ echo "$ac_t"no 1>&6
+ compiler_c_o=no
+ else
+ echo "$ac_t"yes 1>&6
+ compiler_c_o=yes
+ fi
+else
+ # Append any errors to the config.log.
+ cat out/conftest.err 1>&5
+ compiler_c_o=no
+ echo "$ac_t"no 1>&6
+fi
+CFLAGS="$save_CFLAGS"
+chmod u+w .
+$rm conftest* out/*
+rmdir out
+cd ..
+rmdir conftest
+$rm -r conftest 2>/dev/null
+
+if test x"$compiler_c_o" = x"yes"; then
+ # Check to see if we can write to a .lo
+ echo $ac_n "checking if $compiler supports -c -o file.lo... $ac_c" 1>&6
+ $rm conftest*
+ echo "int some_variable = 0;" > conftest.c
+ save_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS -c -o conftest.lo"
+ echo "$progname:862: checking if $compiler supports -c -o file.lo" >&5
+if { (eval echo $progname:863: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>conftest.err; } && test -s conftest.lo; then
+
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ if test -s conftest.err; then
+ echo "$ac_t"no 1>&6
+ compiler_o_lo=no
+ else
+ echo "$ac_t"yes 1>&6
+ compiler_o_lo=yes
+ fi
+ else
+ # Append any errors to the config.log.
+ cat conftest.err 1>&5
+ compiler_o_lo=no
+ echo "$ac_t"no 1>&6
+ fi
+ CFLAGS="$save_CFLAGS"
+ $rm conftest*
+else
+ compiler_o_lo=no
+fi
+
+# Check to see if we can do hard links to lock some files if needed
+hard_links="nottested"
+if test "$compiler_c_o" = no && test "$need_locks" != no; then
+ # do not overwrite the value of need_locks provided by the user
+ echo $ac_n "checking if we can lock with hard links... $ac_c" 1>&6
+ hard_links=yes
+ $rm conftest*
+ ln conftest.a conftest.b 2>/dev/null && hard_links=no
+ touch conftest.a
+ ln conftest.a conftest.b 2>&5 || hard_links=no
+ ln conftest.a conftest.b 2>/dev/null && hard_links=no
+ echo "$ac_t$hard_links" 1>&6
+ $rm conftest*
+ if test "$hard_links" = no; then
+ echo "*** WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2
+ need_locks=warn
+ fi
+else
+ need_locks=no
+fi
+
+if test "$with_gcc" = yes; then
+ # Check to see if options -fno-rtti -fno-exceptions are supported by compiler
+ echo $ac_n "checking if $compiler supports -fno-rtti -fno-exceptions ... $ac_c" 1>&6
+ $rm conftest*
+ echo "int some_variable = 0;" > conftest.c
+ save_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS -fno-rtti -fno-exceptions -c conftest.c"
+ echo "$progname:914: checking if $compiler supports -fno-rtti -fno-exceptions" >&5
+ if { (eval echo $progname:915: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>conftest.err; } && test -s conftest.o; then
+
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ if test -s conftest.err; then
+ echo "$ac_t"no 1>&6
+ compiler_rtti_exceptions=no
+ else
+ echo "$ac_t"yes 1>&6
+ compiler_rtti_exceptions=yes
+ fi
+ else
+ # Append any errors to the config.log.
+ cat conftest.err 1>&5
+ compiler_rtti_exceptions=no
+ echo "$ac_t"no 1>&6
+ fi
+ CFLAGS="$save_CFLAGS"
+ $rm conftest*
+
+ if test "$compiler_rtti_exceptions" = "yes"; then
+ no_builtin_flag=' -fno-builtin -fno-rtti -fno-exceptions'
+ else
+ no_builtin_flag=' -fno-builtin'
+ fi
+
+fi
+
+# Check for any special shared library compilation flags.
+if test -n "$special_shlib_compile_flags"; then
+ echo "$progname: warning: \`$CC' requires \`$special_shlib_compile_flags' to build shared libraries" 1>&2
+ if echo "$old_CC $old_CFLAGS " | egrep -e "[ ]$special_shlib_compile_flags[ ]" >/dev/null; then :
+ else
+ echo "$progname: add \`$special_shlib_compile_flags' to the CC or CFLAGS env variable and reconfigure" 1>&2
+ can_build_shared=no
+ fi
+fi
+
+echo $ac_n "checking if $compiler static flag $link_static_flag works... $ac_c" 1>&6
+$rm conftest*
+echo 'main(){return(0);}' > conftest.c
+save_LDFLAGS="$LDFLAGS"
+LDFLAGS="$LDFLAGS $link_static_flag"
+echo "$progname:958: checking if $compiler static flag $link_static_flag works" >&5
+if { (eval echo $progname:959: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+ echo "$ac_t$link_static_flag" 1>&6
+else
+ echo "$ac_t"none 1>&6
+ link_static_flag=
+fi
+LDFLAGS="$save_LDFLAGS"
+$rm conftest*
+
+if test -z "$LN_S"; then
+ # Check to see if we can use ln -s, or we need hard links.
+ echo $ac_n "checking whether ln -s works... $ac_c" 1>&6
+ $rm conftest.dat
+ if ln -s X conftest.dat 2>/dev/null; then
+ $rm conftest.dat
+ LN_S="ln -s"
+ else
+ LN_S=ln
+ fi
+ if test "$LN_S" = "ln -s"; then
+ echo "$ac_t"yes 1>&6
+ else
+ echo "$ac_t"no 1>&6
+ fi
+fi
+
+# Make sure LD is an absolute path.
+if test -z "$LD"; then
+ ac_prog=ld
+ if test "$with_gcc" = yes; then
+ # Check if gcc -print-prog-name=ld gives a path.
+ echo $ac_n "checking for ld used by GCC... $ac_c" 1>&6
+ echo "$progname:991: checking for ld used by GCC" >&5
+ ac_prog=`($CC -print-prog-name=ld) 2>&5`
+ case "$ac_prog" in
+ # Accept absolute paths.
+ [\\/]* | [A-Za-z]:[\\/]*)
+ re_direlt='/[^/][^/]*/\.\./'
+ # Canonicalize the path of ld
+ ac_prog=`echo $ac_prog| sed 's%\\\\%/%g'`
+ while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do
+ ac_prog=`echo $ac_prog| sed "s%$re_direlt%/%"`
+ done
+ test -z "$LD" && LD="$ac_prog"
+ ;;
+ "")
+ # If it fails, then pretend we are not using GCC.
+ ac_prog=ld
+ ;;
+ *)
+ # If it is relative, then search for the first ld in PATH.
+ with_gnu_ld=unknown
+ ;;
+ esac
+ elif test "$with_gnu_ld" = yes; then
+ echo $ac_n "checking for GNU ld... $ac_c" 1>&6
+ echo "$progname:1015: checking for GNU ld" >&5
+ else
+ echo $ac_n "checking for non-GNU ld""... $ac_c" 1>&6
+ echo "$progname:1018: checking for non-GNU ld" >&5
+ fi
+
+ if test -z "$LD"; then
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR}"
+ for ac_dir in $PATH; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
+ LD="$ac_dir/$ac_prog"
+ # Check to see if the program is GNU ld. I'd rather use --version,
+ # but apparently some GNU ld's only accept -v.
+ # Break only if it was the GNU/non-GNU ld that we prefer.
+ if "$LD" -v 2>&1 < /dev/null | egrep '(GNU|with BFD)' > /dev/null; then
+ test "$with_gnu_ld" != no && break
+ else
+ test "$with_gnu_ld" != yes && break
+ fi
+ fi
+ done
+ IFS="$ac_save_ifs"
+ fi
+
+ if test -n "$LD"; then
+ echo "$ac_t$LD" 1>&6
+ else
+ echo "$ac_t"no 1>&6
+ fi
+
+ if test -z "$LD"; then
+ echo "$progname: error: no acceptable ld found in \$PATH" 1>&2
+ exit 1
+ fi
+fi
+
+# Check to see if it really is or is not GNU ld.
+echo $ac_n "checking if the linker ($LD) is GNU ld... $ac_c" 1>&6
+# I'd rather use --version here, but apparently some GNU ld's only accept -v.
+if $LD -v 2>&1 </dev/null | egrep '(GNU|with BFD)' 1>&5; then
+ with_gnu_ld=yes
+else
+ with_gnu_ld=no
+fi
+echo "$ac_t$with_gnu_ld" 1>&6
+
+# See if the linker supports building shared libraries.
+echo $ac_n "checking whether the linker ($LD) supports shared libraries... $ac_c" 1>&6
+
+allow_undefined_flag=
+no_undefined_flag=
+need_lib_prefix=unknown
+need_version=unknown
+# when you set need_version to no, make sure it does not cause -set_version
+# flags to be left without arguments
+archive_cmds=
+archive_expsym_cmds=
+old_archive_from_new_cmds=
+export_dynamic_flag_spec=
+whole_archive_flag_spec=
+thread_safe_flag_spec=
+hardcode_libdir_flag_spec=
+hardcode_libdir_separator=
+hardcode_direct=no
+hardcode_minus_L=no
+hardcode_shlibpath_var=unsupported
+runpath_var=
+always_export_symbols=no
+export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | sed '\''s/.* //'\'' | sort | uniq > $export_symbols'
+# include_expsyms should be a list of space-separated symbols to be *always*
+# included in the symbol list
+include_expsyms=
+# exclude_expsyms can be an egrep regular expression of symbols to exclude
+# it will be wrapped by ` (' and `)$', so one must not match beginning or
+# end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc',
+# as well as any symbol that contains `d'.
+exclude_expsyms="_GLOBAL_OFFSET_TABLE_"
+# Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out
+# platforms (ab)use it in PIC code, but their linkers get confused if
+# the symbol is explicitly referenced. Since portable code cannot
+# rely on this symbol name, it's probably fine to never include it in
+# preloaded symbol tables.
+
+case "$host_os" in
+cygwin* | mingw*)
+ # FIXME: the MSVC++ port hasn't been tested in a loooong time
+ # When not using gcc, we currently assume that we are using
+ # Microsoft Visual C++.
+ if test "$with_gcc" != yes; then
+ with_gnu_ld=no
+ fi
+ ;;
+
+esac
+
+ld_shlibs=yes
+if test "$with_gnu_ld" = yes; then
+ # If archive_cmds runs LD, not CC, wlarc should be empty
+ wlarc='${wl}'
+
+ # See if GNU ld supports shared libraries.
+ case "$host_os" in
+ aix3* | aix4*)
+ # On AIX, the GNU linker is very broken
+ ld_shlibs=no
+ cat <<EOF 1>&2
+
+*** Warning: the GNU linker, at least up to release 2.9.1, is reported
+*** to be unable to reliably create shared libraries on AIX.
+*** Therefore, libtool is disabling shared libraries support. If you
+*** really care for shared libraries, you may want to modify your PATH
+*** so that a non-GNU linker is found, and then restart.
+
+EOF
+ ;;
+
+ amigaos*)
+ archive_cmds='$rm $objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $objdir/a2ixlibrary.data~$AR cru $lib $libobjs~$RANLIB $lib~(cd $objdir && a2ixlibrary -32)'
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_minus_L=yes
+
+ # Samuel A. Falvo II <kc5tja@dolphin.openprojects.net> reports
+ # that the semantics of dynamic libraries on AmigaOS, at least up
+ # to version 4, is to share data among multiple programs linked
+ # with the same dynamic library. Since this doesn't match the
+ # behavior of shared libraries on other platforms, we can use
+ # them.
+ ld_shlibs=no
+ ;;
+
+ beos*)
+ if $LD --help 2>&1 | egrep ': supported targets:.* elf' > /dev/null; then
+ allow_undefined_flag=unsupported
+ # Joseph Beckenbach <jrb3@best.com> says some releases of gcc
+ # support --undefined. This deserves some investigation. FIXME
+ archive_cmds='$CC -nostart $libobjs $deplibs $linkopts ${wl}-soname $wl$soname -o $lib'
+ else
+ ld_shlibs=no
+ fi
+ ;;
+
+ cygwin* | mingw*)
+ # hardcode_libdir_flag_spec is actually meaningless, as there is
+ # no search path for DLLs.
+ hardcode_libdir_flag_spec='-L$libdir'
+ allow_undefined_flag=unsupported
+ always_export_symbols=yes
+
+ # Extract the symbol export list from an `--export-all' def file,
+ # then regenerate the def file from the symbol export list, so that
+ # the compiled dll only exports the symbol export list.
+ export_symbols_cmds='test -f $objdir/$soname-ltdll.c || sed -e "/^# \/\* ltdll\.c starts here \*\//,/^# \/\* ltdll.c ends here \*\// { s/^# //; p; }" -e d < $0 > $objdir/$soname-ltdll.c~
+ test -f $objdir/$soname-ltdll.$objext || (cd $objdir && $CC -c $soname-ltdll.c)~
+ $DLLTOOL --export-all --exclude-symbols DllMain@12,_cygwin_dll_entry@12,_cygwin_noncygwin_dll_entry@12 --output-def $objdir/$soname-def $objdir/$soname-ltdll.$objext $libobjs $convenience~
+ sed -e "1,/EXPORTS/d" -e "s/ @ [0-9]* ; *//" < $objdir/$soname-def > $export_symbols'
+
+ archive_expsym_cmds='echo EXPORTS > $objdir/$soname-def~
+ _lt_hint=1;
+ for symbol in `cat $export_symbols`; do
+ echo " \$symbol @ \$_lt_hint ; " >> $objdir/$soname-def;
+ _lt_hint=`expr 1 + \$_lt_hint`;
+ done~
+ test -f $objdir/$soname-ltdll.c || sed -e "/^# \/\* ltdll\.c starts here \*\//,/^# \/\* ltdll.c ends here \*\// { s/^# //; p; }" -e d < $0 > $objdir/$soname-ltdll.c~
+ test -f $objdir/$soname-ltdll.$objext || (cd $objdir && $CC -c $soname-ltdll.c)~
+ $CC -Wl,--base-file,$objdir/$soname-base -Wl,--dll -nostartfiles -Wl,-e,__cygwin_dll_entry@12 -o $lib $objdir/$soname-ltdll.$objext $libobjs $deplibs $linkopts~
+ $DLLTOOL --as=$AS --dllname $soname --exclude-symbols DllMain@12,_cygwin_dll_entry@12,_cygwin_noncygwin_dll_entry@12 --def $objdir/$soname-def --base-file $objdir/$soname-base --output-exp $objdir/$soname-exp~
+ $CC -Wl,--base-file,$objdir/$soname-base $objdir/$soname-exp -Wl,--dll -nostartfiles -Wl,-e,__cygwin_dll_entry@12 -o $lib $objdir/$soname-ltdll.$objext $libobjs $deplibs $linkopts~
+ $DLLTOOL --as=$AS --dllname $soname --exclude-symbols DllMain@12,_cygwin_dll_entry@12,_cygwin_noncygwin_dll_entry@12 --def $objdir/$soname-def --base-file $objdir/$soname-base --output-exp $objdir/$soname-exp~
+ $CC $objdir/$soname-exp -Wl,--dll -nostartfiles -Wl,-e,__cygwin_dll_entry@12 -o $lib $objdir/$soname-ltdll.$objext $libobjs $deplibs $linkopts'
+
+ old_archive_from_new_cmds='$DLLTOOL --as=$AS --dllname $soname --def $objdir/$soname-def --output-lib $objdir/$libname.a'
+ ;;
+
+ netbsd*)
+ if $LD --help 2>&1 | egrep ': supported targets:.* elf' > /dev/null; then
+ archive_cmds='$CC -shared $libobjs $deplibs $linkopts ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds='$CC -shared $libobjs $deplibs $linkopts ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ else
+ archive_cmds='$LD -Bshareable $libobjs $deplibs $linkopts -o $lib'
+ # can we support soname and/or expsyms with a.out? -oliva
+ fi
+ ;;
+
+ solaris*)
+ if $LD -v 2>&1 | egrep 'BFD 2\.8' > /dev/null; then
+ ld_shlibs=no
+ cat <<EOF 1>&2
+
+*** Warning: The releases 2.8.* of the GNU linker cannot reliably
+*** create shared libraries on Solaris systems. Therefore, libtool
+*** is disabling shared libraries support. We urge you to upgrade GNU
+*** binutils to release 2.9.1 or newer. Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+EOF
+ elif $LD --help 2>&1 | egrep ': supported targets:.* elf' > /dev/null; then
+ archive_cmds='$CC -shared $libobjs $deplibs $linkopts ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds='$CC -shared $libobjs $deplibs $linkopts ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ else
+ ld_shlibs=no
+ fi
+ ;;
+
+ sunos4*)
+ archive_cmds='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linkopts'
+ wlarc=
+ hardcode_direct=yes
+ hardcode_shlibpath_var=no
+ ;;
+
+ *)
+ if $LD --help 2>&1 | egrep ': supported targets:.* elf' > /dev/null; then
+ archive_cmds='$CC -shared $libobjs $deplibs $linkopts ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds='$CC -shared $libobjs $deplibs $linkopts ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ else
+ ld_shlibs=no
+ fi
+ ;;
+ esac
+
+ if test "$ld_shlibs" = yes; then
+ runpath_var=LD_RUN_PATH
+ hardcode_libdir_flag_spec='${wl}--rpath ${wl}$libdir'
+ export_dynamic_flag_spec='${wl}--export-dynamic'
+ case $host_os in
+ cygwin* | mingw*)
+ # dlltool doesn't understand --whole-archive et. al.
+ whole_archive_flag_spec=
+ ;;
+ *)
+ whole_archive_flag_spec="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+ ;;
+ esac
+ fi
+else
+ # PORTME fill in a description of your system's linker (not GNU ld)
+ case "$host_os" in
+ aix3*)
+ allow_undefined_flag=unsupported
+ always_export_symbols=yes
+ archive_expsym_cmds='$LD -o $objdir/$soname $libobjs $deplibs $linkopts -bE:$export_symbols -T512 -H512 -bM:SRE~$AR cru $lib $objdir/$soname'
+ # Note: this linker hardcodes the directories in LIBPATH if there
+ # are no directories specified by -L.
+ hardcode_minus_L=yes
+ if test "$with_gcc" = yes && test -z "$link_static_flag"; then
+ # Neither direct hardcoding nor static linking is supported with a
+ # broken collect2.
+ hardcode_direct=unsupported
+ fi
+ ;;
+
+ aix4*)
+ hardcode_libdir_flag_spec='${wl}-b ${wl}nolibpath ${wl}-b ${wl}libpath:$libdir:/usr/lib:/lib'
+ hardcode_libdir_separator=':'
+ if test "$with_gcc" = yes; then
+ collect2name=`${CC} -print-prog-name=collect2`
+ if test -f "$collect2name" && \
+ strings "$collect2name" | grep resolve_lib_name >/dev/null
+ then
+ # We have reworked collect2
+ hardcode_direct=yes
+ else
+ # We have old collect2
+ hardcode_direct=unsupported
+ # It fails to find uninstalled libraries when the uninstalled
+ # path is not listed in the libpath. Setting hardcode_minus_L
+ # to unsupported forces relinking
+ hardcode_minus_L=yes
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_libdir_separator=
+ fi
+ shared_flag='-shared'
+ else
+ shared_flag='${wl}-bM:SRE'
+ 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}'
+ 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
+ always_export_symbols=yes ;;
+ esac
+ ;;
+
+ amigaos*)
+ archive_cmds='$rm $objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $objdir/a2ixlibrary.data~$AR cru $lib $libobjs~$RANLIB $lib~(cd $objdir && a2ixlibrary -32)'
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_minus_L=yes
+ # see comment about different semantics on the GNU ld section
+ ld_shlibs=no
+ ;;
+
+ cygwin* | mingw*)
+ # When not using gcc, we currently assume that we are using
+ # Microsoft Visual C++.
+ # hardcode_libdir_flag_spec is actually meaningless, as there is
+ # no search path for DLLs.
+ hardcode_libdir_flag_spec=' '
+ allow_undefined_flag=unsupported
+ # Tell ltmain to make .lib files, not .a files.
+ libext=lib
+ # FIXME: Setting linknames here is a bad hack.
+ archive_cmds='$CC -o $lib $libobjs $linkopts `echo "$deplibs" | sed -e '\''s/ -lc$//'\''` -link -dll~linknames='
+ # The linker will automatically build a .lib file if we build a DLL.
+ old_archive_from_new_cmds='true'
+ # FIXME: Should let the user specify the lib program.
+ old_archive_cmds='lib /OUT:$oldlib$oldobjs'
+ fix_srcfile_path='`cygpath -w $srcfile`'
+ ;;
+
+ freebsd1*)
+ ld_shlibs=no
+ ;;
+
+ # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor
+ # support. Future versions do this automatically, but an explicit c++rt0.o
+ # does not break anything, and helps significantly (at the cost of a little
+ # extra space).
+ freebsd2.2*)
+ archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linkopts /usr/lib/c++rt0.o'
+ hardcode_libdir_flag_spec='-R$libdir'
+ hardcode_direct=yes
+ hardcode_shlibpath_var=no
+ ;;
+
+ # Unfortunately, older versions of FreeBSD 2 do not have this feature.
+ freebsd2*)
+ archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linkopts'
+ hardcode_direct=yes
+ hardcode_minus_L=yes
+ hardcode_shlibpath_var=no
+ ;;
+
+ # FreeBSD 3 and greater uses gcc -shared to do shared libraries.
+ freebsd*)
+ archive_cmds='$CC -shared -o $lib $libobjs $deplibs $linkopts'
+ hardcode_libdir_flag_spec='-R$libdir'
+ hardcode_direct=yes
+ hardcode_shlibpath_var=no
+ ;;
+
+ hpux9* | hpux10* | hpux11*)
+ case "$host_os" in
+ hpux9*) archive_cmds='$rm $objdir/$soname~$LD -b +b $install_libdir -o $objdir/$soname $libobjs $deplibs $linkopts~test $objdir/$soname = $lib || mv $objdir/$soname $lib' ;;
+ *) archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linkopts' ;;
+ esac
+ hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
+ hardcode_libdir_separator=:
+ hardcode_direct=yes
+ hardcode_minus_L=yes # Not in the search PATH, but as the default
+ # location of the library.
+ export_dynamic_flag_spec='${wl}-E'
+ ;;
+
+ irix5* | irix6*)
+ if test "$with_gcc" = yes; then
+ archive_cmds='$CC -shared $libobjs $deplibs $linkopts ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${objdir}/so_locations -o $lib'
+ else
+ archive_cmds='$LD -shared $libobjs $deplibs $linkopts -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib'
+ fi
+ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+ hardcode_libdir_separator=:
+ ;;
+
+ netbsd*)
+ if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
+ archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linkopts' # a.out
+ else
+ archive_cmds='$LD -shared -o $lib $libobjs $deplibs $linkopts' # ELF
+ fi
+ hardcode_libdir_flag_spec='${wl}-R$libdir'
+ hardcode_direct=yes
+ hardcode_shlibpath_var=no
+ ;;
+
+ openbsd*)
+ archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linkopts'
+ hardcode_libdir_flag_spec='-R$libdir'
+ hardcode_direct=yes
+ hardcode_shlibpath_var=no
+ ;;
+
+ os2*)
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_minus_L=yes
+ allow_undefined_flag=unsupported
+ archive_cmds='$echo "LIBRARY $libname INITINSTANCE" > $objdir/$libname.def~$echo "DESCRIPTION \"$libname\"" >> $objdir/$libname.def~$echo DATA >> $objdir/$libname.def~$echo " SINGLE NONSHARED" >> $objdir/$libname.def~$echo EXPORTS >> $objdir/$libname.def~emxexp $libobjs >> $objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $linkopts $objdir/$libname.def'
+ old_archive_from_new_cmds='emximp -o $objdir/$libname.a $objdir/$libname.def'
+ ;;
+
+ osf3* | osf4*)
+ if test "$with_gcc" = yes; then
+ allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*'
+ archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $linkopts ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${objdir}/so_locations -o $lib'
+ else
+ allow_undefined_flag=' -expect_unresolved \*'
+ archive_cmds='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linkopts -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib'
+ fi
+ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+ hardcode_libdir_separator=:
+ ;;
+
+ sco3.2v5*)
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linkopts'
+ hardcode_shlibpath_var=no
+ runpath_var=LD_RUN_PATH
+ hardcode_runpath_var=yes
+ ;;
+
+ solaris*)
+ no_undefined_flag=' -z text'
+ # $CC -shared without GNU ld will not create a library from C++
+ # object files and a static libstdc++, better avoid it by now
+ archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linkopts'
+ archive_expsym_cmds='$echo "{ global:" > $lib.exp~cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
+ $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linkopts~$rm $lib.exp'
+ hardcode_libdir_flag_spec='-R$libdir'
+ hardcode_shlibpath_var=no
+ case "$host_os" in
+ solaris2.[0-5] | solaris2.[0-5].*) ;;
+ *) # Supported since Solaris 2.6 (maybe 2.5.1?)
+ whole_archive_flag_spec='-z allextract$convenience -z defaultextract' ;;
+ esac
+ ;;
+
+ sunos4*)
+ archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linkopts'
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_direct=yes
+ hardcode_minus_L=yes
+ hardcode_shlibpath_var=no
+ ;;
+
+ sysv4)
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linkopts'
+ runpath_var='LD_RUN_PATH'
+ hardcode_shlibpath_var=no
+ hardcode_direct=no #Motorola manual says yes, but my tests say they lie
+ ;;
+
+ sysv4.3*)
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linkopts'
+ hardcode_shlibpath_var=no
+ export_dynamic_flag_spec='-Bexport'
+ ;;
+
+ uts4*)
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linkopts'
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_shlibpath_var=no
+ ;;
+
+ dgux*)
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linkopts'
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_shlibpath_var=no
+ ;;
+
+ sysv4*MP*)
+ if test -d /usr/nec ;then
+ # archive_cmds='$LD -G -z text -h $soname -o $lib$libobjs$deplibs'
+ archive_cmds='$LD -G -h $soname -o $lib$libobjs$deplibs'
+ hardcode_shlibpath_var=no
+ runpath_var=LD_RUN_PATH
+ hardcode_runpath_var=yes
+ ld_shlibs=yes
+ fi
+ ;;
+
+ unixware7* | sysv5*)
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linkopts'
+ runpath_var='LD_RUN_PATH'
+ hardcode_shlibpath_var=no
+ ;;
+
+ *)
+ ld_shlibs=no
+ ;;
+ esac
+fi
+echo "$ac_t$ld_shlibs" 1>&6
+test "$ld_shlibs" = no && can_build_shared=no
+
+if test -z "$NM"; then
+ echo $ac_n "checking for BSD-compatible nm... $ac_c" 1>&6
+ case "$NM" in
+ [\\/]* | [A-Za-z]:[\\/]*) ;; # Let the user override the test with a path.
+ *)
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR}"
+ for ac_dir in $PATH /usr/ucb /usr/ccs/bin /bin; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/nm || test -f $ac_dir/nm$ac_exeext; then
+ # Check to see if the nm accepts a BSD-compat flag.
+ # Adding the `sed 1q' prevents false positives on HP-UX, which says:
+ # nm: unknown option "B" ignored
+ if ($ac_dir/nm -B /dev/null 2>&1 | sed '1q'; exit 0) | egrep /dev/null >/dev/null; then
+ NM="$ac_dir/nm -B"
+ break
+ elif ($ac_dir/nm -p /dev/null 2>&1 | sed '1q'; exit 0) | egrep /dev/null >/dev/null; then
+ NM="$ac_dir/nm -p"
+ break
+ else
+ NM=${NM="$ac_dir/nm"} # keep the first match, but
+ continue # so that we can try to find one that supports BSD flags
+ fi
+ fi
+ done
+ IFS="$ac_save_ifs"
+ test -z "$NM" && NM=nm
+ ;;
+ esac
+ echo "$ac_t$NM" 1>&6
+fi
+
+# Check for command to grab the raw symbol name followed by C symbol from nm.
+echo $ac_n "checking command to parse $NM output... $ac_c" 1>&6
+
+# These are sane defaults that work on at least a few old systems.
+# [They come from Ultrix. What could be older than Ultrix?!! ;)]
+
+# Character class describing NM global symbol codes.
+symcode='[BCDEGRST]'
+
+# Regexp to match symbols that can be accessed directly from C.
+sympat='\([_A-Za-z][_A-Za-z0-9]*\)'
+
+# Transform the above into a raw symbol and a C symbol.
+symxfrm='\1 \2\3 \3'
+
+# Transform an extracted symbol line into a proper C declaration
+global_symbol_to_cdecl="sed -n -e 's/^. .* \(.*\)$/extern char \1;/p'"
+
+# Define system-specific variables.
+case "$host_os" in
+aix*)
+ symcode='[BCDT]'
+ ;;
+cygwin* | mingw*)
+ symcode='[ABCDGISTW]'
+ ;;
+hpux*) # Its linker distinguishes data from code symbols
+ global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern char \1();/p' -e 's/^. .* \(.*\)$/extern char \1;/p'"
+ ;;
+irix*)
+ symcode='[BCDEGRST]'
+ ;;
+solaris*)
+ symcode='[BDT]'
+ ;;
+sysv4)
+ symcode='[DFNSTU]'
+ ;;
+esac
+
+# If we're using GNU nm, then use its standard symbol codes.
+if $NM -V 2>&1 | egrep '(GNU|with BFD)' > /dev/null; then
+ symcode='[ABCDGISTW]'
+fi
+
+# Try without a prefix undercore, then with it.
+for ac_symprfx in "" "_"; do
+
+ # Write the raw and C identifiers.
+ global_symbol_pipe="sed -n -e 's/^.*[ ]\($symcode\)[ ][ ]*\($ac_symprfx\)$sympat$/$symxfrm/p'"
+
+ # Check to see that the pipe works correctly.
+ pipe_works=no
+ $rm conftest*
+ cat > conftest.c <<EOF
+#ifdef __cplusplus
+extern "C" {
+#endif
+char nm_test_var;
+void nm_test_func(){}
+#ifdef __cplusplus
+}
+#endif
+main(){nm_test_var='a';nm_test_func();return(0);}
+EOF
+
+ echo "$progname:1592: checking if global_symbol_pipe works" >&5
+ if { (eval echo $progname:1593: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; } && test -s conftest.$objext; then
+ # Now try to grab the symbols.
+ nlist=conftest.nm
+ if { echo "$progname:1596: eval \"$NM conftest.$objext | $global_symbol_pipe > $nlist\"" >&5; eval "$NM conftest.$objext | $global_symbol_pipe > $nlist 2>&5"; } && test -s "$nlist"; then
+
+ # Try sorting and uniquifying the output.
+ if sort "$nlist" | uniq > "$nlist"T; then
+ mv -f "$nlist"T "$nlist"
+ else
+ rm -f "$nlist"T
+ fi
+
+ # Make sure that we snagged all the symbols we need.
+ if egrep ' nm_test_var$' "$nlist" >/dev/null; then
+ if egrep ' nm_test_func$' "$nlist" >/dev/null; then
+ cat <<EOF > conftest.c
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+EOF
+ # Now generate the symbol file.
+ eval "$global_symbol_to_cdecl"' < "$nlist" >> conftest.c'
+
+ cat <<EOF >> conftest.c
+#if defined (__STDC__) && __STDC__
+# define lt_ptr_t void *
+#else
+# define lt_ptr_t char *
+# define const
+#endif
+
+/* The mapping between symbol names and symbols. */
+const struct {
+ const char *name;
+ lt_ptr_t address;
+}
+lt_preloaded_symbols[] =
+{
+EOF
+ sed 's/^. \(.*\) \(.*\)$/ {"\2", (lt_ptr_t) \&\2},/' < "$nlist" >> conftest.c
+ cat <<\EOF >> conftest.c
+ {0, (lt_ptr_t) 0}
+};
+
+#ifdef __cplusplus
+}
+#endif
+EOF
+ # Now try linking the two files.
+ mv conftest.$objext conftstm.$objext
+ save_LIBS="$LIBS"
+ save_CFLAGS="$CFLAGS"
+ LIBS="conftstm.$objext"
+ CFLAGS="$CFLAGS$no_builtin_flag"
+ if { (eval echo $progname:1648: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+ pipe_works=yes
+ else
+ echo "$progname: failed program was:" >&5
+ cat conftest.c >&5
+ fi
+ LIBS="$save_LIBS"
+ else
+ echo "cannot find nm_test_func in $nlist" >&5
+ fi
+ else
+ echo "cannot find nm_test_var in $nlist" >&5
+ fi
+ else
+ echo "cannot run $global_symbol_pipe" >&5
+ fi
+ else
+ echo "$progname: failed program was:" >&5
+ cat conftest.c >&5
+ fi
+ $rm conftest* conftst*
+
+ # Do not use the global_symbol_pipe unless it works.
+ if test "$pipe_works" = yes; then
+ break
+ else
+ global_symbol_pipe=
+ fi
+done
+if test "$pipe_works" = yes; then
+ echo "${ac_t}ok" 1>&6
+else
+ echo "${ac_t}failed" 1>&6
+fi
+
+if test -z "$global_symbol_pipe"; then
+ global_symbol_to_cdecl=
+fi
+
+# Check hardcoding attributes.
+echo $ac_n "checking how to hardcode library paths into programs... $ac_c" 1>&6
+hardcode_action=
+if test -n "$hardcode_libdir_flag_spec" || \
+ test -n "$runpath_var"; then
+
+ # We can hardcode non-existant directories.
+ if test "$hardcode_direct" != no &&
+ # If the only mechanism to avoid hardcoding is shlibpath_var, we
+ # have to relink, otherwise we might link with an installed library
+ # when we should be linking with a yet-to-be-installed one
+ ## test "$hardcode_shlibpath_var" != no &&
+ test "$hardcode_minus_L" != no; then
+ # Linking always hardcodes the temporary library directory.
+ hardcode_action=relink
+ else
+ # We can link without hardcoding, and we can hardcode nonexisting dirs.
+ hardcode_action=immediate
+ fi
+else
+ # We cannot hardcode anything, or else we can only hardcode existing
+ # directories.
+ hardcode_action=unsupported
+fi
+echo "$ac_t$hardcode_action" 1>&6
+
+
+reload_flag=
+reload_cmds='$LD$reload_flag -o $output$reload_objs'
+echo $ac_n "checking for $LD option to reload object files... $ac_c" 1>&6
+# PORTME Some linkers may need a different reload flag.
+reload_flag='-r'
+echo "$ac_t$reload_flag" 1>&6
+test -n "$reload_flag" && reload_flag=" $reload_flag"
+
+# PORTME Fill in your ld.so characteristics
+library_names_spec=
+libname_spec='lib$name'
+soname_spec=
+postinstall_cmds=
+postuninstall_cmds=
+finish_cmds=
+finish_eval=
+shlibpath_var=
+shlibpath_overrides_runpath=unknown
+version_type=none
+dynamic_linker="$host_os ld.so"
+sys_lib_dlsearch_path_spec="/lib /usr/lib"
+sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
+file_magic_cmd=
+file_magic_test_file=
+deplibs_check_method='unknown'
+# Need to set the preceding variable on all platforms that support
+# interlibrary dependencies.
+# 'none' -- dependencies not supported.
+# `unknown' -- same as none, but documents that we really don't know.
+# 'pass_all' -- all dependencies passed with no checks.
+# 'test_compile' -- check by making test program.
+# 'file_magic [regex]' -- check by looking for files in library path
+# which responds to the $file_magic_cmd with a given egrep regex.
+# If you have `file' or equivalent on your system and you're not sure
+# whether `pass_all' will *always* work, you probably want this one.
+echo $ac_n "checking dynamic linker characteristics... $ac_c" 1>&6
+case "$host_os" in
+aix3*)
+ version_type=linux
+ library_names_spec='${libname}${release}.so$versuffix $libname.a'
+ shlibpath_var=LIBPATH
+
+ # AIX has no versioning support, so we append a major version to the name.
+ soname_spec='${libname}${release}.so$major'
+ ;;
+
+aix4*)
+ version_type=linux
+ # AIX has no versioning support, so currently we can not hardcode correct
+ # soname into executable. Probably we can add versioning support to
+ # collect2, so additional links can be useful in future.
+ # We preserve .a as extension for shared libraries though AIX4.2
+ # and later linker supports .so
+ library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.a'
+ shlibpath_var=LIBPATH
+ deplibs_check_method=pass_all
+ ;;
+
+amigaos*)
+ library_names_spec='$libname.ixlibrary $libname.a'
+ # Create ${libname}_ixlibrary.a entries in /sys/libs.
+ finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$echo "X$lib" | $Xsed -e '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $rm /sys/libs/${libname}_ixlibrary.a; $show "(cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a)"; (cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a) || exit 1; done'
+ ;;
+
+beos*)
+ library_names_spec='${libname}.so'
+ dynamic_linker="$host_os ld.so"
+ shlibpath_var=LIBRARY_PATH
+ deplibs_check_method=pass_all
+ lt_cv_dlopen="load_add_on"
+ lt_cv_dlopen_libs=
+ lt_cv_dlopen_self=yes
+ ;;
+
+bsdi4*)
+ version_type=linux
+ library_names_spec='${libname}.so$major ${libname}.so'
+ soname_spec='${libname}.so'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib)'
+ file_magic_cmd=/usr/bin/file
+ file_magic_test_file=/shlib/libc.so
+ sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib"
+ sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib"
+ # the default ld.so.conf also contains /usr/contrib/lib and
+ # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow
+ # libtool to hard-code these into programs
+ ;;
+
+cygwin* | mingw*)
+ version_type=windows
+ need_version=no
+ need_lib_prefix=no
+ if test "$with_gcc" = yes; then
+ library_names_spec='${libname}`echo ${release} | sed -e 's/[.]/-/g'`${versuffix}.dll $libname.a'
+ else
+ library_names_spec='${libname}`echo ${release} | sed -e 's/[.]/-/g'`${versuffix}.dll $libname.lib'
+ fi
+ dynamic_linker='Win32 ld.exe'
+ deplibs_check_method='file_magic file format pei*-i386(.*architecture: i386)?'
+ file_magic_cmd='${OBJDUMP} -f'
+ # FIXME: first we should search . and the directory the executable is in
+ shlibpath_var=PATH
+ lt_cv_dlopen="LoadLibrary"
+ lt_cv_dlopen_libs=
+ ;;
+
+freebsd1*)
+ dynamic_linker=no
+ ;;
+
+freebsd*)
+ objformat=`test -x /usr/bin/objformat && /usr/bin/objformat || echo aout`
+ version_type=freebsd-$objformat
+ case "$version_type" in
+ freebsd-elf*)
+ deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB shared object'
+ file_magic_cmd=/usr/bin/file
+ file_magic_test_file=`echo /usr/lib/libc.so*`
+ library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so $libname.so'
+ need_version=no
+ need_lib_prefix=no
+ ;;
+ freebsd-*)
+ deplibs_check_method=unknown
+ library_names_spec='${libname}${release}.so$versuffix $libname.so$versuffix'
+ need_version=yes
+ ;;
+ esac
+ finish_cmds='PATH="\$PATH:/sbin" OBJFORMAT="'"$objformat"'" ldconfig -m $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ case "$host_os" in
+ freebsd2* | freebsd3.[01]*)
+ shlibpath_overrides_runpath=yes
+ ;;
+ *) # from 3.2 on
+ shlibpath_overrides_runpath=no
+ ;;
+ esac
+ ;;
+
+gnu*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so${major} ${libname}.so'
+ soname_spec='${libname}${release}.so$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
+hpux9* | hpux10* | hpux11*)
+ # Give a soname corresponding to the major version so that dld.sl refuses to
+ # link against other versions.
+ dynamic_linker="$host_os dld.sl"
+ version_type=sunos
+ need_lib_prefix=no
+ need_version=no
+ shlibpath_var=SHLIB_PATH
+ shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH
+ library_names_spec='${libname}${release}.sl$versuffix ${libname}${release}.sl$major $libname.sl'
+ soname_spec='${libname}${release}.sl$major'
+ # HP-UX runs *really* slowly unless shared libraries are mode 555.
+ postinstall_cmds='chmod 555 $lib'
+ ;;
+
+irix5* | irix6*)
+ version_type=irix
+ need_lib_prefix=no
+ need_version=no
+ soname_spec='${libname}${release}.so.$major'
+ library_names_spec='${libname}${release}.so.$versuffix ${libname}${release}.so.$major ${libname}${release}.so $libname.so'
+ case "$host_os" in
+ irix5*)
+ libsuff= shlibsuff=
+ # this will be overridden with pass_all, but let us keep it just in case
+ deplibs_check_method="file_magic ELF 32-bit MSB dynamic lib MIPS - version 1"
+ ;;
+ *)
+ case "$LD" in # libtool.m4 will add one of these switches to LD
+ *-32|*"-32 ") libsuff= shlibsuff= libmagic=32-bit;;
+ *-n32|*"-n32 ") libsuff=32 shlibsuff=N32 libmagic=N32;;
+ *-64|*"-64 ") libsuff=64 shlibsuff=64 libmagic=64-bit;;
+ *) libsuff= shlibsuff= libmagic=never-match;;
+ esac
+ # this will be overridden with pass_all, but let us keep it just in case
+ deplibs_check_method="file_magic ELF ${libmagic} MSB mips-[1234] dynamic lib MIPS - version 1"
+ ;;
+ esac
+ shlibpath_var=LD_LIBRARY${shlibsuff}_PATH
+ shlibpath_overrides_runpath=no
+ sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}"
+ sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}"
+ file_magic_cmd=/usr/bin/file
+ file_magic_test_file=`echo /lib${libsuff}/libc.so*`
+ deplibs_check_method='pass_all'
+ ;;
+
+# No shared lib support for Linux oldld, aout, or coff.
+linux-gnuoldld* | linux-gnuaout* | linux-gnucoff*)
+ dynamic_linker=no
+ ;;
+
+# This must be Linux ELF.
+linux-gnu*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so'
+ soname_spec='${libname}${release}.so$major'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )'
+ file_magic_cmd=/usr/bin/file
+ file_magic_test_file=`echo /lib/libc.so* /lib/libc-*.so`
+
+ if test -f /lib/ld.so.1; then
+ dynamic_linker='GNU ld.so'
+ else
+ # Only the GNU ld.so supports shared libraries on MkLinux.
+ case "$host_cpu" in
+ powerpc*) dynamic_linker=no ;;
+ *) dynamic_linker='Linux ld.so' ;;
+ esac
+ fi
+ ;;
+
+netbsd*)
+ version_type=sunos
+ if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
+ library_names_spec='${libname}${release}.so$versuffix ${libname}.so$versuffix'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+ dynamic_linker='NetBSD (a.out) ld.so'
+ else
+ library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major ${libname}${release}.so ${libname}.so'
+ soname_spec='${libname}${release}.so$major'
+ dynamic_linker='NetBSD ld.elf_so'
+ fi
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
+openbsd*)
+ version_type=sunos
+ if test "$with_gnu_ld" = yes; then
+ need_lib_prefix=no
+ need_version=no
+ fi
+ library_names_spec='${libname}${release}.so$versuffix ${libname}.so$versuffix'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
+os2*)
+ libname_spec='$name'
+ need_lib_prefix=no
+ library_names_spec='$libname.dll $libname.a'
+ dynamic_linker='OS/2 ld.exe'
+ shlibpath_var=LIBPATH
+ ;;
+
+osf3* | osf4*)
+ version_type=osf
+ need_version=no
+ soname_spec='${libname}${release}.so'
+ library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so $libname.so'
+ shlibpath_var=LD_LIBRARY_PATH
+ # this will be overridden with pass_all, but let us keep it just in case
+ deplibs_check_method='file_magic COFF format alpha shared library'
+ file_magic_cmd=/usr/bin/file
+ file_magic_test_file=/shlib/libc.so
+ deplibs_check_method='pass_all'
+ sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib"
+ sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec"
+ ;;
+
+sco3.2v5*)
+ version_type=osf
+ soname_spec='${libname}${release}.so$major'
+ library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so'
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
+solaris*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so'
+ soname_spec='${libname}${release}.so$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ # ldd complains unless libraries are executable
+ postinstall_cmds='chmod +x $lib'
+ deplibs_check_method="file_magic ELF [0-9][0-9]-bit [LM]SB dynamic lib"
+ file_magic_cmd=/usr/bin/file
+ file_magic_test_file=/lib/libc.so
+ ;;
+
+sunos4*)
+ version_type=sunos
+ library_names_spec='${libname}${release}.so$versuffix ${libname}.so$versuffix'
+ finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ if test "$with_gnu_ld" = yes; then
+ need_lib_prefix=no
+ fi
+ need_version=yes
+ ;;
+
+sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+ version_type=linux
+ library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so'
+ soname_spec='${libname}${release}.so$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ case "$host_vendor" in
+ ncr)
+ deplibs_check_method='pass_all'
+ ;;
+ motorola)
+ need_lib_prefix=no
+ need_version=no
+ shlibpath_overrides_runpath=no
+ sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib'
+ deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib) M[0-9][0-9]* Version [0-9]'
+ file_magic_cmd=/usr/bin/file
+ file_magic_test_file=`echo /usr/lib/libc.so*`
+ ;;
+ esac
+ ;;
+
+uts4*)
+ version_type=linux
+ library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so'
+ soname_spec='${libname}${release}.so$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
+dgux*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so'
+ soname_spec='${libname}${release}.so$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
+sysv4*MP*)
+ if test -d /usr/nec ;then
+ version_type=linux
+ library_names_spec='$libname.so.$versuffix $libname.so.$major $libname.so'
+ soname_spec='$libname.so.$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ fi
+ ;;
+
+*)
+ dynamic_linker=no
+ ;;
+esac
+echo "$ac_t$dynamic_linker" 1>&6
+test "$dynamic_linker" = no && can_build_shared=no
+
+# Report the final consequences.
+echo "checking if libtool supports shared libraries... $can_build_shared" 1>&6
+
+# Only try to build win32 dlls if AC_LIBTOOL_WIN32_DLL was used in
+# configure.in, otherwise build static only libraries.
+case "$host_os" in
+cygwin* | mingw* | os2*)
+ if test x$can_build_shared = xyes; then
+ test x$enable_win32_dll = xno && can_build_shared=no
+ echo "checking if package supports dlls... $can_build_shared" 1>&6
+ fi
+;;
+esac
+
+if test -n "$file_magic_test_file" && test -n "$file_magic_cmd"; then
+ case "$deplibs_check_method" in
+ "file_magic "*)
+ file_magic_regex="`expr \"$deplibs_check_method\" : \"file_magic \(.*\)\"`"
+ if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
+ egrep "$file_magic_regex" > /dev/null; then
+ :
+ else
+ cat <<EOF 1>&2
+
+*** Warning: the command libtool uses to detect shared libraries,
+*** $file_magic_cmd, produces output that libtool cannot recognize.
+*** The result is that libtool may fail to recognize shared libraries
+*** as such. This will affect the creation of libtool libraries that
+*** depend on shared libraries, but programs linked with such libtool
+*** libraries will work regardless of this problem. Nevertheless, you
+*** may want to report the problem to your system manager and/or to
+*** bug-libtool@gnu.org
+
+EOF
+ fi ;;
+ esac
+fi
+
+echo $ac_n "checking whether to build shared libraries... $ac_c" 1>&6
+test "$can_build_shared" = "no" && enable_shared=no
+
+# On AIX, shared libraries and static libraries use the same namespace, and
+# are all built from PIC.
+case "$host_os" in
+aix3*)
+ test "$enable_shared" = yes && enable_static=no
+ if test -n "$RANLIB"; then
+ archive_cmds="$archive_cmds~\$RANLIB \$lib"
+ postinstall_cmds='$RANLIB $lib'
+ fi
+ ;;
+
+aix4*)
+ test "$enable_shared" = yes && enable_static=no
+ ;;
+esac
+
+echo "$ac_t$enable_shared" 1>&6
+
+# Make sure either enable_shared or enable_static is yes.
+test "$enable_shared" = yes || enable_static=yes
+
+echo "checking whether to build static libraries... $enable_static" 1>&6
+
+if test "$hardcode_action" = relink; then
+ # Fast installation is not supported
+ enable_fast_install=no
+elif test "$shlibpath_overrides_runpath" = yes ||
+ test "$enable_shared" = no; then
+ # Fast installation is not necessary
+ enable_fast_install=needless
+fi
+
+echo $ac_n "checking for objdir... $ac_c" 1>&6
+rm -f .libs 2>/dev/null
+mkdir .libs 2>/dev/null
+if test -d .libs; then
+ objdir=.libs
+else
+ # MS-DOS does not allow filenames that begin with a dot.
+ objdir=_libs
+fi
+rmdir .libs 2>/dev/null
+echo "$ac_t$objdir" 1>&6
+
+if test "x$enable_dlopen" != xyes; then
+ enable_dlopen=unknown
+ enable_dlopen_self=unknown
+ enable_dlopen_self_static=unknown
+else
+if eval "test \"`echo '$''{'lt_cv_dlopen'+set}'`\" != set"; then
+ lt_cv_dlopen=no lt_cv_dlopen_libs=
+echo $ac_n "checking for dlopen in -ldl""... $ac_c" 1>&6
+echo "$progname:2170: checking for dlopen in -ldl" >&5
+ac_lib_var=`echo dl'_'dlopen | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-ldl $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 2178 "ltconfig"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char dlopen();
+
+int main() {
+dlopen()
+; return 0; }
+EOF
+if { (eval echo $progname:2188: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "$progname: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"
+else
+ echo "$ac_t""no" 1>&6
+echo $ac_n "checking for dlopen""... $ac_c" 1>&6
+echo "$progname:2207: checking for dlopen" >&5
+if eval "test \"`echo '$''{'ac_cv_func_dlopen'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2212 "ltconfig"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char dlopen(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char dlopen();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_dlopen) || defined (__stub___dlopen)
+choke me
+#else
+dlopen();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo $progname:2234: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_dlopen=yes"
+else
+ echo "$progname: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_dlopen=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_func_'dlopen`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ lt_cv_dlopen="dlopen"
+else
+ echo "$ac_t""no" 1>&6
+echo $ac_n "checking for dld_link in -ldld""... $ac_c" 1>&6
+echo "$progname:2251: checking for dld_link in -ldld" >&5
+ac_lib_var=`echo dld'_'dld_link | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-ldld $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 2259 "ltconfig"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char dld_link();
+
+int main() {
+dld_link()
+; return 0; }
+EOF
+if { (eval echo $progname:2269: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "$progname: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld"
+else
+ echo "$ac_t""no" 1>&6
+echo $ac_n "checking for shl_load""... $ac_c" 1>&6
+echo "$progname:2288: checking for shl_load" >&5
+if eval "test \"`echo '$''{'ac_cv_func_shl_load'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2293 "ltconfig"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char shl_load(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char shl_load();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_shl_load) || defined (__stub___shl_load)
+choke me
+#else
+shl_load();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo $progname:2315: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_shl_load=yes"
+else
+ echo "$progname: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_shl_load=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'shl_load`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ lt_cv_dlopen="shl_load"
+else
+ echo "$ac_t""no" 1>&6
+echo $ac_n "checking for shl_load in -ldld""... $ac_c" 1>&6
+echo "$progname:2333: checking for shl_load in -ldld" >&5
+ac_lib_var=`echo dld'_'shl_load | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-ldld $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 2341 "ltconfig"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char shl_load();
+
+int main() {
+shl_load()
+; return 0; }
+EOF
+if { (eval echo $progname:2352: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "$progname: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld"
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+
+fi
+
+
+fi
+
+
+fi
+
+
+fi
+
+fi
+
+ if test "x$lt_cv_dlopen" != xno; then
+ enable_dlopen=yes
+ fi
+
+ case "$lt_cv_dlopen" in
+ dlopen)
+for ac_hdr in dlfcn.h; do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "$progname:2395: checking for $ac_hdr" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2400 "ltconfig"
+#include <$ac_hdr>
+int fnord = 0;
+EOF
+ac_try="$ac_compile conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo $progname:2405: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=yes"
+else
+ echo "$ac_err" >&5
+ echo "$progname: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+ if test "x$ac_cv_header_dlfcn_h" = xyes; then
+ CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H"
+ fi
+ eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\"
+ LIBS="$lt_cv_dlopen_libs $LIBS"
+
+ echo $ac_n "checking whether a program can dlopen itself""... $ac_c" 1>&6
+echo "$progname:2433: checking whether a program can dlopen itself" >&5
+if test "${lt_cv_dlopen_self+set}" = set; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test "$cross_compiling" = yes; then
+ lt_cv_dlopen_self=cross
+ else
+ cat > conftest.c <<EOF
+#line 2441 "ltconfig"
+
+#if HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef RTLD_GLOBAL
+# define LTDL_GLOBAL RTLD_GLOBAL
+#else
+# ifdef DL_GLOBAL
+# define LTDL_GLOBAL DL_GLOBAL
+# else
+# define LTDL_GLOBAL 0
+# endif
+#endif
+
+/* We may have to define LTDL_LAZY_OR_NOW in the command line if we
+ find out it does not work in some platform. */
+#ifndef LTDL_LAZY_OR_NOW
+# ifdef RTLD_LAZY
+# define LTDL_LAZY_OR_NOW RTLD_LAZY
+# else
+# ifdef DL_LAZY
+# define LTDL_LAZY_OR_NOW DL_LAZY
+# else
+# ifdef RTLD_NOW
+# define LTDL_LAZY_OR_NOW RTLD_NOW
+# else
+# ifdef DL_NOW
+# define LTDL_LAZY_OR_NOW DL_NOW
+# else
+# define LTDL_LAZY_OR_NOW 0
+# endif
+# endif
+# endif
+# endif
+#endif
+
+fnord() { int i=42;}
+main() { void *self, *ptr1, *ptr2; self=dlopen(0,LTDL_GLOBAL|LTDL_LAZY_OR_NOW);
+ if(self) { ptr1=dlsym(self,"fnord"); ptr2=dlsym(self,"_fnord");
+ if(ptr1 || ptr2) { dlclose(self); exit(0); } } exit(1); }
+
+EOF
+if { (eval echo $progname:2487: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null
+then
+ lt_cv_dlopen_self=yes
+else
+ echo "$progname: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ lt_cv_dlopen_self=no
+fi
+rm -fr conftest*
+fi
+
+fi
+
+echo "$ac_t""$lt_cv_dlopen_self" 1>&6
+
+ if test "$lt_cv_dlopen_self" = yes; then
+ LDFLAGS="$LDFLAGS $link_static_flag"
+ echo $ac_n "checking whether a statically linked program can dlopen itself""... $ac_c" 1>&6
+echo "$progname:2506: checking whether a statically linked program can dlopen itself" >&5
+if test "${lt_cv_dlopen_self_static+set}" = set; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test "$cross_compiling" = yes; then
+ lt_cv_dlopen_self_static=cross
+ else
+ cat > conftest.c <<EOF
+#line 2514 "ltconfig"
+
+#if HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef RTLD_GLOBAL
+# define LTDL_GLOBAL RTLD_GLOBAL
+#else
+# ifdef DL_GLOBAL
+# define LTDL_GLOBAL DL_GLOBAL
+# else
+# define LTDL_GLOBAL 0
+# endif
+#endif
+
+/* We may have to define LTDL_LAZY_OR_NOW in the command line if we
+ find out it does not work in some platform. */
+#ifndef LTDL_LAZY_OR_NOW
+# ifdef RTLD_LAZY
+# define LTDL_LAZY_OR_NOW RTLD_LAZY
+# else
+# ifdef DL_LAZY
+# define LTDL_LAZY_OR_NOW DL_LAZY
+# else
+# ifdef RTLD_NOW
+# define LTDL_LAZY_OR_NOW RTLD_NOW
+# else
+# ifdef DL_NOW
+# define LTDL_LAZY_OR_NOW DL_NOW
+# else
+# define LTDL_LAZY_OR_NOW 0
+# endif
+# endif
+# endif
+# endif
+#endif
+
+fnord() { int i=42;}
+main() { void *self, *ptr1, *ptr2; self=dlopen(0,LTDL_GLOBAL|LTDL_LAZY_OR_NOW);
+ if(self) { ptr1=dlsym(self,"fnord"); ptr2=dlsym(self,"_fnord");
+ if(ptr1 || ptr2) { dlclose(self); exit(0); } } exit(1); }
+
+EOF
+if { (eval echo $progname:2560: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null
+then
+ lt_cv_dlopen_self_static=yes
+else
+ echo "$progname: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ lt_cv_dlopen_self_static=no
+fi
+rm -fr conftest*
+fi
+
+fi
+
+echo "$ac_t""$lt_cv_dlopen_self_static" 1>&6
+fi
+ ;;
+ esac
+
+ case "$lt_cv_dlopen_self" in
+ yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;;
+ *) enable_dlopen_self=unknown ;;
+ esac
+
+ case "$lt_cv_dlopen_self_static" in
+ yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;;
+ *) enable_dlopen_self_static=unknown ;;
+ esac
+fi
+
+# Copy echo and quote the copy, instead of the original, because it is
+# used later.
+ltecho="$echo"
+if test "X$ltecho" = "X$CONFIG_SHELL $0 --fallback-echo"; then
+ ltecho="$CONFIG_SHELL \$0 --fallback-echo"
+fi
+LTSHELL="$SHELL"
+
+LTCONFIG_VERSION="$VERSION"
+
+# Only quote variables if we're using ltmain.sh.
+case "$ltmain" in
+*.sh)
+ # Now quote all the things that may contain metacharacters.
+ for var in ltecho old_CC old_CFLAGS old_CPPFLAGS \
+ old_LD old_LDFLAGS old_LIBS \
+ old_NM old_RANLIB old_LN_S old_DLLTOOL old_OBJDUMP old_AS \
+ AR CC LD LN_S NM LTSHELL LTCONFIG_VERSION \
+ reload_flag reload_cmds wl \
+ pic_flag link_static_flag no_builtin_flag export_dynamic_flag_spec \
+ thread_safe_flag_spec whole_archive_flag_spec libname_spec \
+ library_names_spec soname_spec \
+ RANLIB old_archive_cmds old_archive_from_new_cmds old_postinstall_cmds \
+ old_postuninstall_cmds archive_cmds archive_expsym_cmds postinstall_cmds postuninstall_cmds \
+ file_magic_cmd export_symbols_cmds deplibs_check_method allow_undefined_flag no_undefined_flag \
+ finish_cmds finish_eval global_symbol_pipe global_symbol_to_cdecl \
+ hardcode_libdir_flag_spec hardcode_libdir_separator \
+ sys_lib_search_path_spec sys_lib_dlsearch_path_spec \
+ compiler_c_o compiler_o_lo need_locks exclude_expsyms include_expsyms; do
+
+ case "$var" in
+ reload_cmds | old_archive_cmds | old_archive_from_new_cmds | \
+ old_postinstall_cmds | old_postuninstall_cmds | \
+ export_symbols_cmds | archive_cmds | archive_expsym_cmds | \
+ postinstall_cmds | postuninstall_cmds | \
+ finish_cmds | sys_lib_search_path_spec | sys_lib_dlsearch_path_spec)
+ # Double-quote double-evaled strings.
+ eval "$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$double_quote_subst\" -e \"\$sed_quote_subst\" -e \"\$delay_variable_subst\"\`\\\""
+ ;;
+ *)
+ eval "$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$sed_quote_subst\"\`\\\""
+ ;;
+ esac
+ done
+
+ case "$ltecho" in
+ *'\$0 --fallback-echo"')
+ ltecho=`$echo "X$ltecho" | $Xsed -e 's/\\\\\\\$0 --fallback-echo"$/$0 --fallback-echo"/'`
+ ;;
+ esac
+
+ trap "$rm \"$ofile\"; exit 1" 1 2 15
+ echo "creating $ofile"
+ $rm "$ofile"
+ cat <<EOF > "$ofile"
+#! $SHELL
+
+# `$echo "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services.
+# Generated automatically by $PROGRAM (GNU $PACKAGE $VERSION$TIMESTAMP)
+# NOTE: Changes made to this file will be lost: look at ltconfig or ltmain.sh.
+#
+# Copyright (C) 1996-1999 Free Software Foundation, Inc.
+# Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public 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 a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Sed that helps us avoid accidentally triggering echo(1) options like -n.
+Xsed="sed -e s/^X//"
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+if test "\${CDPATH+set}" = set; then CDPATH=; export CDPATH; fi
+
+### BEGIN LIBTOOL CONFIG
+EOF
+ cfgfile="$ofile"
+ ;;
+
+*)
+ # Double-quote the variables that need it (for aesthetics).
+ for var in old_CC old_CFLAGS old_CPPFLAGS \
+ old_LD old_LDFLAGS old_LIBS \
+ old_NM old_RANLIB old_LN_S old_DLLTOOL old_OBJDUMP old_AS; do
+ eval "$var=\\\"\$var\\\""
+ done
+
+ # Just create a config file.
+ cfgfile="$ofile.cfg"
+ trap "$rm \"$cfgfile\"; exit 1" 1 2 15
+ echo "creating $cfgfile"
+ $rm "$cfgfile"
+ cat <<EOF > "$cfgfile"
+# `$echo "$cfgfile" | sed 's%^.*/%%'` - Libtool configuration file.
+# Generated automatically by $PROGRAM (GNU $PACKAGE $VERSION$TIMESTAMP)
+EOF
+ ;;
+esac
+
+cat <<EOF >> "$cfgfile"
+# Libtool was configured as follows, on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+#
+# CC=$old_CC CFLAGS=$old_CFLAGS CPPFLAGS=$old_CPPFLAGS \\
+# LD=$old_LD LDFLAGS=$old_LDFLAGS LIBS=$old_LIBS \\
+# NM=$old_NM RANLIB=$old_RANLIB LN_S=$old_LN_S \\
+# DLLTOOL=$old_DLLTOOL OBJDUMP=$old_OBJDUMP AS=$old_AS \\
+# $0$ltconfig_args
+#
+# Compiler and other test output produced by $progname, useful for
+# debugging $progname, is in ./config.log if it exists.
+
+# The version of $progname that generated this script.
+LTCONFIG_VERSION=$LTCONFIG_VERSION
+
+# Shell to use when invoking shell scripts.
+SHELL=$LTSHELL
+
+# Whether or not to build shared libraries.
+build_libtool_libs=$enable_shared
+
+# Whether or not to build static libraries.
+build_old_libs=$enable_static
+
+# Whether or not to optimize for fast installation.
+fast_install=$enable_fast_install
+
+# The host system.
+host_alias=$host_alias
+host=$host
+
+# An echo program that does not interpret backslashes.
+echo=$ltecho
+
+# The archiver.
+AR=$AR
+
+# The default C compiler.
+CC=$CC
+
+# The linker used to build libraries.
+LD=$LD
+
+# Whether we need hard or soft links.
+LN_S=$LN_S
+
+# A BSD-compatible nm program.
+NM=$NM
+
+# Used on cygwin: DLL creation program.
+DLLTOOL="$DLLTOOL"
+
+# Used on cygwin: object dumper.
+OBJDUMP="$OBJDUMP"
+
+# Used on cygwin: assembler.
+AS="$AS"
+
+# The name of the directory that contains temporary libtool files.
+objdir=$objdir
+
+# How to create reloadable object files.
+reload_flag=$reload_flag
+reload_cmds=$reload_cmds
+
+# How to pass a linker flag through the compiler.
+wl=$wl
+
+# Object file suffix (normally "o").
+objext="$objext"
+
+# Old archive suffix (normally "a").
+libext="$libext"
+
+# Executable file suffix (normally "").
+exeext="$exeext"
+
+# Additional compiler flags for building library objects.
+pic_flag=$pic_flag
+
+# Does compiler simultaneously support -c and -o options?
+compiler_c_o=$compiler_c_o
+
+# Can we write directly to a .lo ?
+compiler_o_lo=$compiler_o_lo
+
+# Must we lock files when doing compilation ?
+need_locks=$need_locks
+
+# Do we need the lib prefix for modules?
+need_lib_prefix=$need_lib_prefix
+
+# Do we need a version for libraries?
+need_version=$need_version
+
+# Whether dlopen is supported.
+dlopen=$enable_dlopen
+
+# Whether dlopen of programs is supported.
+dlopen_self=$enable_dlopen_self
+
+# Whether dlopen of statically linked programs is supported.
+dlopen_self_static=$enable_dlopen_self_static
+
+# Compiler flag to prevent dynamic linking.
+link_static_flag=$link_static_flag
+
+# Compiler flag to turn off builtin functions.
+no_builtin_flag=$no_builtin_flag
+
+# Compiler flag to allow reflexive dlopens.
+export_dynamic_flag_spec=$export_dynamic_flag_spec
+
+# Compiler flag to generate shared objects directly from archives.
+whole_archive_flag_spec=$whole_archive_flag_spec
+
+# Compiler flag to generate thread-safe objects.
+thread_safe_flag_spec=$thread_safe_flag_spec
+
+# Library versioning type.
+version_type=$version_type
+
+# Format of library name prefix.
+libname_spec=$libname_spec
+
+# List of archive names. First name is the real one, the rest are links.
+# The last name is the one that the linker finds with -lNAME.
+library_names_spec=$library_names_spec
+
+# The coded name of the library, if different from the real name.
+soname_spec=$soname_spec
+
+# Commands used to build and install an old-style archive.
+RANLIB=$RANLIB
+old_archive_cmds=$old_archive_cmds
+old_postinstall_cmds=$old_postinstall_cmds
+old_postuninstall_cmds=$old_postuninstall_cmds
+
+# Create an old-style archive from a shared archive.
+old_archive_from_new_cmds=$old_archive_from_new_cmds
+
+# Commands used to build and install a shared archive.
+archive_cmds=$archive_cmds
+archive_expsym_cmds=$archive_expsym_cmds
+postinstall_cmds=$postinstall_cmds
+postuninstall_cmds=$postuninstall_cmds
+
+# Method to check whether dependent libraries are shared objects.
+deplibs_check_method=$deplibs_check_method
+
+# Command to use when deplibs_check_method == file_magic.
+file_magic_cmd=$file_magic_cmd
+
+# Flag that allows shared libraries with undefined symbols to be built.
+allow_undefined_flag=$allow_undefined_flag
+
+# Flag that forces no undefined symbols.
+no_undefined_flag=$no_undefined_flag
+
+# Commands used to finish a libtool library installation in a directory.
+finish_cmds=$finish_cmds
+
+# Same as above, but a single script fragment to be evaled but not shown.
+finish_eval=$finish_eval
+
+# Take the output of nm and produce a listing of raw symbols and C names.
+global_symbol_pipe=$global_symbol_pipe
+
+# Transform the output of nm in a proper C declaration
+global_symbol_to_cdecl=$global_symbol_to_cdecl
+
+# This is the shared library runtime path variable.
+runpath_var=$runpath_var
+
+# This is the shared library path variable.
+shlibpath_var=$shlibpath_var
+
+# Is shlibpath searched before the hard-coded library search path?
+shlibpath_overrides_runpath=$shlibpath_overrides_runpath
+
+# How to hardcode a shared library path into an executable.
+hardcode_action=$hardcode_action
+
+# Flag to hardcode \$libdir into a binary during linking.
+# This must work even if \$libdir does not exist.
+hardcode_libdir_flag_spec=$hardcode_libdir_flag_spec
+
+# Whether we need a single -rpath flag with a separated argument.
+hardcode_libdir_separator=$hardcode_libdir_separator
+
+# Set to yes if using DIR/libNAME.so during linking hardcodes DIR into the
+# resulting binary.
+hardcode_direct=$hardcode_direct
+
+# Set to yes if using the -LDIR flag during linking hardcodes DIR into the
+# resulting binary.
+hardcode_minus_L=$hardcode_minus_L
+
+# Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into
+# the resulting binary.
+hardcode_shlibpath_var=$hardcode_shlibpath_var
+
+# Compile-time system search path for libraries
+sys_lib_search_path_spec=$sys_lib_search_path_spec
+
+# Run-time system search path for libraries
+sys_lib_dlsearch_path_spec=$sys_lib_dlsearch_path_spec
+
+# Fix the shell variable \$srcfile for the compiler.
+fix_srcfile_path="$fix_srcfile_path"
+
+# Set to yes if exported symbols are required.
+always_export_symbols=$always_export_symbols
+
+# The commands to list exported symbols.
+export_symbols_cmds=$export_symbols_cmds
+
+# Symbols that should not be listed in the preloaded symbols.
+exclude_expsyms=$exclude_expsyms
+
+# Symbols that must always be exported.
+include_expsyms=$include_expsyms
+
+EOF
+
+case "$ltmain" in
+*.sh)
+ echo '### END LIBTOOL CONFIG' >> "$ofile"
+ echo >> "$ofile"
+ case "$host_os" in
+ aix3*)
+ cat <<\EOF >> "$ofile"
+
+# AIX sometimes has problems with the GCC collect2 program. For some
+# reason, if we set the COLLECT_NAMES environment variable, the problems
+# vanish in a puff of smoke.
+if test "${COLLECT_NAMES+set}" != set; then
+ COLLECT_NAMES=
+ export COLLECT_NAMES
+fi
+EOF
+ ;;
+ esac
+
+ # Append the ltmain.sh script.
+ sed '$q' "$ltmain" >> "$ofile" || (rm -f "$ofile"; exit 1)
+
+ chmod +x "$ofile"
+ ;;
+
+*)
+ # Compile the libtool program.
+ echo "FIXME: would compile $ltmain"
+ ;;
+esac
+
+test -n "$cache_file" || exit 0
+
+# AC_CACHE_SAVE
+trap '' 1 2 15
+cat > confcache <<\EOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs. It is not useful on other systems.
+# If it contains results you don't want to keep, you may remove or edit it.
+#
+# By default, configure uses ./config.cache as the cache file,
+# creating it if it does not exist already. You can give configure
+# the --cache-file=FILE option to use a different cache file; that is
+# what configure does when it calls configure scripts in
+# subdirectories, so they share the cache.
+# Giving --cache-file=/dev/null disables caching, for debugging configure.
+# config.status only pays attention to the cache file if you give it the
+# --recheck option to rerun configure.
+#
+EOF
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, don't put newlines in cache variables' values.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(set) 2>&1 |
+ case `(ac_space=' '; set | grep ac_space) 2>&1` in
+ *ac_space=\ *)
+ # `set' does not quote correctly, so add quotes (double-quote substitution
+ # turns \\\\ into \\, and sed turns \\ into \).
+ sed -n \
+ -e "s/'/'\\\\''/g" \
+ -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p"
+ ;;
+ *)
+ # `set' quotes correctly as required by POSIX, so do not add quotes.
+ sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p'
+ ;;
+ esac >> confcache
+if cmp -s $cache_file confcache; then
+ :
+else
+ if test -w $cache_file; then
+ echo "updating cache $cache_file"
+ cat confcache > $cache_file
+ else
+ echo "not updating unwritable cache $cache_file"
+ fi
+fi
+rm -f confcache
+
+exit 0
+
+# Local Variables:
+# mode:shell-script
+# sh-indentation:2
+# End:
diff --git a/ltmain.sh b/ltmain.sh
new file mode 100644
index 00000000000..ae10cad021b
--- /dev/null
+++ b/ltmain.sh
@@ -0,0 +1,3975 @@
+# ltmain.sh - Provide generalized library-building support services.
+# NOTE: Changing this file will not affect anything until you rerun ltconfig.
+#
+# Copyright (C) 1996-1999 Free Software Foundation, Inc.
+# Originally by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public 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 a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Check that we have a working $echo.
+if test "X$1" = X--no-reexec; then
+ # Discard the --no-reexec flag, and continue.
+ shift
+elif test "X$1" = X--fallback-echo; then
+ # Avoid inline document here, it may be left over
+ :
+elif test "X`($echo '\t') 2>/dev/null`" = 'X\t'; then
+ # Yippee, $echo works!
+ :
+else
+ # Restart under the correct shell, and then maybe $echo will work.
+ exec $SHELL "$0" --no-reexec ${1+"$@"}
+fi
+
+if test "X$1" = X--fallback-echo; then
+ # used as fallback echo
+ shift
+ cat <<EOF
+$*
+EOF
+ exit 0
+fi
+
+# The name of this program.
+progname=`$echo "$0" | sed 's%^.*/%%'`
+modename="$progname"
+
+# Constants.
+PROGRAM=ltmain.sh
+PACKAGE=libtool
+VERSION=1.3.3
+TIMESTAMP=" (1.385.2.181 1999/07/02 15:49:11)"
+
+default_mode=
+help="Try \`$progname --help' for more information."
+magic="%%%MAGIC variable%%%"
+mkdir="mkdir"
+mv="mv -f"
+rm="rm -f"
+
+# Sed substitution that helps us do robust quoting. It backslashifies
+# metacharacters that are still active within double-quoted strings.
+Xsed='sed -e 1s/^X//'
+sed_quote_subst='s/\([\\`\\"$\\\\]\)/\\\1/g'
+SP2NL='tr \040 \012'
+NL2SP='tr \015\012 \040\040'
+
+# NLS nuisances.
+# Only set LANG and LC_ALL to C if already set.
+# These must not be set unconditionally because not all systems understand
+# e.g. LANG=C (notably SCO).
+# We save the old values to restore during execute mode.
+if test "${LC_ALL+set}" = set; then
+ save_LC_ALL="$LC_ALL"; LC_ALL=C; export LC_ALL
+fi
+if test "${LANG+set}" = set; then
+ save_LANG="$LANG"; LANG=C; export LANG
+fi
+
+if test "$LTCONFIG_VERSION" != "$VERSION"; then
+ echo "$modename: ltconfig version \`$LTCONFIG_VERSION' does not match $PROGRAM version \`$VERSION'" 1>&2
+ echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2
+ exit 1
+fi
+
+if test "$build_libtool_libs" != yes && test "$build_old_libs" != yes; then
+ echo "$modename: not configured to build any kind of library" 1>&2
+ echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2
+ exit 1
+fi
+
+# Global variables.
+mode=$default_mode
+nonopt=
+prev=
+prevopt=
+run=
+show="$echo"
+show_help=
+execute_dlfiles=
+lo2o="s/\\.lo\$/.${objext}/"
+o2lo="s/\\.${objext}\$/.lo/"
+
+# Parse our command line options once, thoroughly.
+while test $# -gt 0
+do
+ arg="$1"
+ shift
+
+ case "$arg" in
+ -*=*) optarg=`$echo "X$arg" | $Xsed -e 's/[-_a-zA-Z0-9]*=//'` ;;
+ *) optarg= ;;
+ esac
+
+ # If the previous option needs an argument, assign it.
+ if test -n "$prev"; then
+ case "$prev" in
+ execute_dlfiles)
+ eval "$prev=\"\$$prev \$arg\""
+ ;;
+ *)
+ eval "$prev=\$arg"
+ ;;
+ esac
+
+ prev=
+ prevopt=
+ continue
+ fi
+
+ # Have we seen a non-optional argument yet?
+ case "$arg" in
+ --help)
+ show_help=yes
+ ;;
+
+ --version)
+ echo "$PROGRAM (GNU $PACKAGE) $VERSION$TIMESTAMP"
+ exit 0
+ ;;
+
+ --config)
+ sed -e '1,/^### BEGIN LIBTOOL CONFIG/d' -e '/^### END LIBTOOL CONFIG/,$d' $0
+ exit 0
+ ;;
+
+ --debug)
+ echo "$progname: enabling shell trace mode"
+ set -x
+ ;;
+
+ --dry-run | -n)
+ run=:
+ ;;
+
+ --features)
+ echo "host: $host"
+ if test "$build_libtool_libs" = yes; then
+ echo "enable shared libraries"
+ else
+ echo "disable shared libraries"
+ fi
+ if test "$build_old_libs" = yes; then
+ echo "enable static libraries"
+ else
+ echo "disable static libraries"
+ fi
+ exit 0
+ ;;
+
+ --finish) mode="finish" ;;
+
+ --mode) prevopt="--mode" prev=mode ;;
+ --mode=*) mode="$optarg" ;;
+
+ --quiet | --silent)
+ show=:
+ ;;
+
+ -dlopen)
+ prevopt="-dlopen"
+ prev=execute_dlfiles
+ ;;
+
+ -*)
+ $echo "$modename: unrecognized option \`$arg'" 1>&2
+ $echo "$help" 1>&2
+ exit 1
+ ;;
+
+ *)
+ nonopt="$arg"
+ break
+ ;;
+ esac
+done
+
+if test -n "$prevopt"; then
+ $echo "$modename: option \`$prevopt' requires an argument" 1>&2
+ $echo "$help" 1>&2
+ exit 1
+fi
+
+if test -z "$show_help"; then
+
+ # Infer the operation mode.
+ if test -z "$mode"; then
+ case "$nonopt" in
+ *cc | *++ | gcc* | *-gcc*)
+ mode=link
+ for arg
+ do
+ case "$arg" in
+ -c)
+ mode=compile
+ break
+ ;;
+ esac
+ done
+ ;;
+ *db | *dbx | *strace | *truss)
+ mode=execute
+ ;;
+ *install*|cp|mv)
+ mode=install
+ ;;
+ *rm)
+ mode=uninstall
+ ;;
+ *)
+ # If we have no mode, but dlfiles were specified, then do execute mode.
+ test -n "$execute_dlfiles" && mode=execute
+
+ # Just use the default operation mode.
+ if test -z "$mode"; then
+ if test -n "$nonopt"; then
+ $echo "$modename: warning: cannot infer operation mode from \`$nonopt'" 1>&2
+ else
+ $echo "$modename: warning: cannot infer operation mode without MODE-ARGS" 1>&2
+ fi
+ fi
+ ;;
+ esac
+ fi
+
+ # Only execute mode is allowed to have -dlopen flags.
+ if test -n "$execute_dlfiles" && test "$mode" != execute; then
+ $echo "$modename: unrecognized option \`-dlopen'" 1>&2
+ $echo "$help" 1>&2
+ exit 1
+ fi
+
+ # Change the help message to a mode-specific one.
+ generic_help="$help"
+ help="Try \`$modename --help --mode=$mode' for more information."
+
+ # These modes are in order of execution frequency so that they run quickly.
+ case "$mode" in
+ # libtool compile mode
+ compile)
+ modename="$modename: compile"
+ # Get the compilation command and the source file.
+ base_compile=
+ lastarg=
+ srcfile="$nonopt"
+ suppress_output=
+
+ user_target=no
+ for arg
+ do
+ # Accept any command-line options.
+ case "$arg" in
+ -o)
+ if test "$user_target" != "no"; then
+ $echo "$modename: you cannot specify \`-o' more than once" 1>&2
+ exit 1
+ fi
+ user_target=next
+ ;;
+
+ -static)
+ build_old_libs=yes
+ continue
+ ;;
+ esac
+
+ case "$user_target" in
+ next)
+ # The next one is the -o target name
+ user_target=yes
+ continue
+ ;;
+ yes)
+ # We got the output file
+ user_target=set
+ libobj="$arg"
+ continue
+ ;;
+ esac
+
+ # Accept the current argument as the source file.
+ lastarg="$srcfile"
+ srcfile="$arg"
+
+ # Aesthetically quote the previous argument.
+
+ # Backslashify any backslashes, double quotes, and dollar signs.
+ # These are the only characters that are still specially
+ # interpreted inside of double-quoted scrings.
+ lastarg=`$echo "X$lastarg" | $Xsed -e "$sed_quote_subst"`
+
+ # Double-quote args containing other shell metacharacters.
+ # Many Bourne shells cannot handle close brackets correctly in scan
+ # sets, so we specify it separately.
+ case "$lastarg" in
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*)
+ lastarg="\"$lastarg\""
+ ;;
+ esac
+
+ # Add the previous argument to base_compile.
+ if test -z "$base_compile"; then
+ base_compile="$lastarg"
+ else
+ base_compile="$base_compile $lastarg"
+ fi
+ done
+
+ case "$user_target" in
+ set)
+ ;;
+ no)
+ # Get the name of the library object.
+ libobj=`$echo "X$srcfile" | $Xsed -e 's%^.*/%%'`
+ ;;
+ *)
+ $echo "$modename: you must specify a target with \`-o'" 1>&2
+ exit 1
+ ;;
+ esac
+
+ # Recognize several different file suffixes.
+ # If the user specifies -o file.o, it is replaced with file.lo
+ xform='[cCFSfmso]'
+ case "$libobj" in
+ *.ada) xform=ada ;;
+ *.adb) xform=adb ;;
+ *.ads) xform=ads ;;
+ *.asm) xform=asm ;;
+ *.c++) xform=c++ ;;
+ *.cc) xform=cc ;;
+ *.cpp) xform=cpp ;;
+ *.cxx) xform=cxx ;;
+ *.f90) xform=f90 ;;
+ *.for) xform=for ;;
+ esac
+
+ libobj=`$echo "X$libobj" | $Xsed -e "s/\.$xform$/.lo/"`
+
+ case "$libobj" in
+ *.lo) obj=`$echo "X$libobj" | $Xsed -e "$lo2o"` ;;
+ *)
+ $echo "$modename: cannot determine name of library object from \`$libobj'" 1>&2
+ exit 1
+ ;;
+ esac
+
+ if test -z "$base_compile"; then
+ $echo "$modename: you must specify a compilation command" 1>&2
+ $echo "$help" 1>&2
+ exit 1
+ fi
+
+ # Delete any leftover library objects.
+ if test "$build_old_libs" = yes; then
+ removelist="$obj $libobj"
+ else
+ removelist="$libobj"
+ fi
+
+ $run $rm $removelist
+ trap "$run $rm $removelist; exit 1" 1 2 15
+
+ # Calculate the filename of the output object if compiler does
+ # not support -o with -c
+ if test "$compiler_c_o" = no; then
+ output_obj=`$echo "X$srcfile" | $Xsed -e 's%^.*/%%' -e 's%\..*$%%'`.${objext}
+ lockfile="$output_obj.lock"
+ removelist="$removelist $output_obj $lockfile"
+ trap "$run $rm $removelist; exit 1" 1 2 15
+ else
+ need_locks=no
+ lockfile=
+ fi
+
+ # Lock this critical section if it is needed
+ # We use this script file to make the link, it avoids creating a new file
+ if test "$need_locks" = yes; then
+ until ln "$0" "$lockfile" 2>/dev/null; do
+ $show "Waiting for $lockfile to be removed"
+ sleep 2
+ done
+ elif test "$need_locks" = warn; then
+ if test -f "$lockfile"; then
+ echo "\
+*** ERROR, $lockfile exists and contains:
+`cat $lockfile 2>/dev/null`
+
+This indicates that another process is trying to use the same
+temporary object file, and libtool could not work around it because
+your compiler does not support \`-c' and \`-o' together. If you
+repeat this compilation, it may succeed, by chance, but you had better
+avoid parallel builds (make -j) in this platform, or get a better
+compiler."
+
+ $run $rm $removelist
+ exit 1
+ fi
+ echo $srcfile > "$lockfile"
+ fi
+
+ if test -n "$fix_srcfile_path"; then
+ eval srcfile=\"$fix_srcfile_path\"
+ fi
+
+ # Only build a PIC object if we are building libtool libraries.
+ if test "$build_libtool_libs" = yes; then
+ # Without this assignment, base_compile gets emptied.
+ fbsd_hideous_sh_bug=$base_compile
+
+ # All platforms use -DPIC, to notify preprocessed assembler code.
+ command="$base_compile $pic_flag -DPIC $srcfile"
+ if test "$build_old_libs" = yes; then
+ lo_libobj="$libobj"
+ dir=`$echo "X$libobj" | $Xsed -e 's%/[^/]*$%%'`
+ if test "X$dir" = "X$libobj"; then
+ dir="$objdir"
+ else
+ dir="$dir/$objdir"
+ fi
+ libobj="$dir/"`$echo "X$libobj" | $Xsed -e 's%^.*/%%'`
+
+ if test -d "$dir"; then
+ $show "$rm $libobj"
+ $run $rm $libobj
+ else
+ $show "$mkdir $dir"
+ $run $mkdir $dir
+ status=$?
+ if test $status -ne 0 && test ! -d $dir; then
+ exit $status
+ fi
+ fi
+ fi
+ if test "$compiler_o_lo" = yes; then
+ output_obj="$libobj"
+ command="$command -o $output_obj"
+ elif test "$compiler_c_o" = yes; then
+ output_obj="$obj"
+ command="$command -o $output_obj"
+ fi
+
+ $run $rm "$output_obj"
+ $show "$command"
+ if $run eval "$command"; then :
+ else
+ test -n "$output_obj" && $run $rm $removelist
+ exit 1
+ fi
+
+ if test "$need_locks" = warn &&
+ test x"`cat $lockfile 2>/dev/null`" != x"$srcfile"; then
+ echo "\
+*** ERROR, $lockfile contains:
+`cat $lockfile 2>/dev/null`
+
+but it should contain:
+$srcfile
+
+This indicates that another process is trying to use the same
+temporary object file, and libtool could not work around it because
+your compiler does not support \`-c' and \`-o' together. If you
+repeat this compilation, it may succeed, by chance, but you had better
+avoid parallel builds (make -j) in this platform, or get a better
+compiler."
+
+ $run $rm $removelist
+ exit 1
+ fi
+
+ # Just move the object if needed, then go on to compile the next one
+ if test x"$output_obj" != x"$libobj"; then
+ $show "$mv $output_obj $libobj"
+ if $run $mv $output_obj $libobj; then :
+ else
+ error=$?
+ $run $rm $removelist
+ exit $error
+ fi
+ fi
+
+ # If we have no pic_flag, then copy the object into place and finish.
+ if test -z "$pic_flag" && test "$build_old_libs" = yes; then
+ # Rename the .lo from within objdir to obj
+ if test -f $obj; then
+ $show $rm $obj
+ $run $rm $obj
+ fi
+
+ $show "$mv $libobj $obj"
+ if $run $mv $libobj $obj; then :
+ else
+ error=$?
+ $run $rm $removelist
+ exit $error
+ fi
+
+ # Now arrange that obj and lo_libobj become the same file
+ $show "$LN_S $obj $lo_libobj"
+ if $run $LN_S $obj $lo_libobj; then
+ exit 0
+ else
+ error=$?
+ $run $rm $removelist
+ exit $error
+ fi
+ fi
+
+ # Allow error messages only from the first compilation.
+ suppress_output=' >/dev/null 2>&1'
+ fi
+
+ # Only build a position-dependent object if we build old libraries.
+ if test "$build_old_libs" = yes; then
+ command="$base_compile $srcfile"
+ if test "$compiler_c_o" = yes; then
+ command="$command -o $obj"
+ output_obj="$obj"
+ fi
+
+ # Suppress compiler output if we already did a PIC compilation.
+ command="$command$suppress_output"
+ $run $rm "$output_obj"
+ $show "$command"
+ if $run eval "$command"; then :
+ else
+ $run $rm $removelist
+ exit 1
+ fi
+
+ if test "$need_locks" = warn &&
+ test x"`cat $lockfile 2>/dev/null`" != x"$srcfile"; then
+ echo "\
+*** ERROR, $lockfile contains:
+`cat $lockfile 2>/dev/null`
+
+but it should contain:
+$srcfile
+
+This indicates that another process is trying to use the same
+temporary object file, and libtool could not work around it because
+your compiler does not support \`-c' and \`-o' together. If you
+repeat this compilation, it may succeed, by chance, but you had better
+avoid parallel builds (make -j) in this platform, or get a better
+compiler."
+
+ $run $rm $removelist
+ exit 1
+ fi
+
+ # Just move the object if needed
+ if test x"$output_obj" != x"$obj"; then
+ $show "$mv $output_obj $obj"
+ if $run $mv $output_obj $obj; then :
+ else
+ error=$?
+ $run $rm $removelist
+ exit $error
+ fi
+ fi
+
+ # Create an invalid libtool object if no PIC, so that we do not
+ # accidentally link it into a program.
+ if test "$build_libtool_libs" != yes; then
+ $show "echo timestamp > $libobj"
+ $run eval "echo timestamp > \$libobj" || exit $?
+ else
+ # Move the .lo from within objdir
+ $show "$mv $libobj $lo_libobj"
+ if $run $mv $libobj $lo_libobj; then :
+ else
+ error=$?
+ $run $rm $removelist
+ exit $error
+ fi
+ fi
+ fi
+
+ # Unlock the critical section if it was locked
+ if test "$need_locks" != no; then
+ $rm "$lockfile"
+ fi
+
+ exit 0
+ ;;
+
+ # libtool link mode
+ link)
+ modename="$modename: link"
+ C_compiler="$CC" # save it, to compile generated C sources
+ CC="$nonopt"
+ case "$host" in
+ *-*-cygwin* | *-*-mingw* | *-*-os2*)
+ # It is impossible to link a dll without this setting, and
+ # we shouldn't force the makefile maintainer to figure out
+ # which system we are compiling for in order to pass an extra
+ # flag for every libtool invokation.
+ # allow_undefined=no
+
+ # FIXME: Unfortunately, there are problems with the above when trying
+ # to make a dll which has undefined symbols, in which case not
+ # even a static library is built. For now, we need to specify
+ # -no-undefined on the libtool link line when we can be certain
+ # that all symbols are satisfied, otherwise we get a static library.
+ allow_undefined=yes
+
+ # This is a source program that is used to create dlls on Windows
+ # Don't remove nor modify the starting and closing comments
+# /* ltdll.c starts here */
+# #define WIN32_LEAN_AND_MEAN
+# #include <windows.h>
+# #undef WIN32_LEAN_AND_MEAN
+# #include <stdio.h>
+#
+# #ifndef __CYGWIN__
+# # ifdef __CYGWIN32__
+# # define __CYGWIN__ __CYGWIN32__
+# # endif
+# #endif
+#
+# #ifdef __cplusplus
+# extern "C" {
+# #endif
+# BOOL APIENTRY DllMain (HINSTANCE hInst, DWORD reason, LPVOID reserved);
+# #ifdef __cplusplus
+# }
+# #endif
+#
+# #ifdef __CYGWIN__
+# #include <cygwin/cygwin_dll.h>
+# DECLARE_CYGWIN_DLL( DllMain );
+# #endif
+# HINSTANCE __hDllInstance_base;
+#
+# BOOL APIENTRY
+# DllMain (HINSTANCE hInst, DWORD reason, LPVOID reserved)
+# {
+# __hDllInstance_base = hInst;
+# return TRUE;
+# }
+# /* ltdll.c ends here */
+ # This is a source program that is used to create import libraries
+ # on Windows for dlls which lack them. Don't remove nor modify the
+ # starting and closing comments
+# /* impgen.c starts here */
+# /* Copyright (C) 1999 Free Software Foundation, Inc.
+#
+# This file is part of GNU libtool.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public 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> /* for printf() */
+# #include <unistd.h> /* for open(), lseek(), read() */
+# #include <fcntl.h> /* for O_RDONLY, O_BINARY */
+# #include <string.h> /* for strdup() */
+#
+# static unsigned int
+# pe_get16 (fd, offset)
+# int fd;
+# int offset;
+# {
+# unsigned char b[2];
+# lseek (fd, offset, SEEK_SET);
+# read (fd, b, 2);
+# return b[0] + (b[1]<<8);
+# }
+#
+# static unsigned int
+# pe_get32 (fd, offset)
+# int fd;
+# int offset;
+# {
+# unsigned char b[4];
+# lseek (fd, offset, SEEK_SET);
+# read (fd, b, 4);
+# return b[0] + (b[1]<<8) + (b[2]<<16) + (b[3]<<24);
+# }
+#
+# static unsigned int
+# pe_as32 (ptr)
+# void *ptr;
+# {
+# unsigned char *b = ptr;
+# return b[0] + (b[1]<<8) + (b[2]<<16) + (b[3]<<24);
+# }
+#
+# int
+# main (argc, argv)
+# int argc;
+# char *argv[];
+# {
+# int dll;
+# unsigned long pe_header_offset, opthdr_ofs, num_entries, i;
+# unsigned long export_rva, export_size, nsections, secptr, expptr;
+# unsigned long name_rvas, nexp;
+# unsigned char *expdata, *erva;
+# char *filename, *dll_name;
+#
+# filename = argv[1];
+#
+# dll = open(filename, O_RDONLY|O_BINARY);
+# if (!dll)
+# return 1;
+#
+# dll_name = filename;
+#
+# for (i=0; filename[i]; i++)
+# if (filename[i] == '/' || filename[i] == '\\' || filename[i] == ':')
+# dll_name = filename + i +1;
+#
+# pe_header_offset = pe_get32 (dll, 0x3c);
+# opthdr_ofs = pe_header_offset + 4 + 20;
+# num_entries = pe_get32 (dll, opthdr_ofs + 92);
+#
+# if (num_entries < 1) /* no exports */
+# return 1;
+#
+# export_rva = pe_get32 (dll, opthdr_ofs + 96);
+# export_size = pe_get32 (dll, opthdr_ofs + 100);
+# nsections = pe_get16 (dll, pe_header_offset + 4 +2);
+# secptr = (pe_header_offset + 4 + 20 +
+# pe_get16 (dll, pe_header_offset + 4 + 16));
+#
+# expptr = 0;
+# for (i = 0; i < nsections; i++)
+# {
+# char sname[8];
+# unsigned long secptr1 = secptr + 40 * i;
+# unsigned long vaddr = pe_get32 (dll, secptr1 + 12);
+# unsigned long vsize = pe_get32 (dll, secptr1 + 16);
+# unsigned long fptr = pe_get32 (dll, secptr1 + 20);
+# lseek(dll, secptr1, SEEK_SET);
+# read(dll, sname, 8);
+# if (vaddr <= export_rva && vaddr+vsize > export_rva)
+# {
+# expptr = fptr + (export_rva - vaddr);
+# if (export_rva + export_size > vaddr + vsize)
+# export_size = vsize - (export_rva - vaddr);
+# break;
+# }
+# }
+#
+# expdata = (unsigned char*)malloc(export_size);
+# lseek (dll, expptr, SEEK_SET);
+# read (dll, expdata, export_size);
+# erva = expdata - export_rva;
+#
+# nexp = pe_as32 (expdata+24);
+# name_rvas = pe_as32 (expdata+32);
+#
+# printf ("EXPORTS\n");
+# for (i = 0; i<nexp; i++)
+# {
+# unsigned long name_rva = pe_as32 (erva+name_rvas+i*4);
+# printf ("\t%s @ %ld ;\n", erva+name_rva, 1+ i);
+# }
+#
+# return 0;
+# }
+# /* impgen.c ends here */
+ ;;
+ *)
+ allow_undefined=yes
+ ;;
+ esac
+ compile_command="$CC"
+ finalize_command="$CC"
+
+ compile_rpath=
+ finalize_rpath=
+ compile_shlibpath=
+ finalize_shlibpath=
+ convenience=
+ old_convenience=
+ deplibs=
+ linkopts=
+
+ if test -n "$shlibpath_var"; then
+ # get the directories listed in $shlibpath_var
+ eval lib_search_path=\`\$echo \"X \${$shlibpath_var}\" \| \$Xsed -e \'s/:/ /g\'\`
+ else
+ lib_search_path=
+ fi
+ # now prepend the system-specific ones
+ eval lib_search_path=\"$sys_lib_search_path_spec\$lib_search_path\"
+ eval sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\"
+
+ avoid_version=no
+ dlfiles=
+ dlprefiles=
+ dlself=no
+ export_dynamic=no
+ export_symbols=
+ export_symbols_regex=
+ generated=
+ libobjs=
+ link_against_libtool_libs=
+ ltlibs=
+ module=no
+ objs=
+ prefer_static_libs=no
+ preload=no
+ prev=
+ prevarg=
+ release=
+ rpath=
+ xrpath=
+ perm_rpath=
+ temp_rpath=
+ thread_safe=no
+ vinfo=
+
+ # We need to know -static, to get the right output filenames.
+ for arg
+ do
+ case "$arg" in
+ -all-static | -static)
+ if test "X$arg" = "X-all-static"; then
+ if test "$build_libtool_libs" = yes && test -z "$link_static_flag"; then
+ $echo "$modename: warning: complete static linking is impossible in this configuration" 1>&2
+ fi
+ if test -n "$link_static_flag"; then
+ dlopen_self=$dlopen_self_static
+ fi
+ else
+ if test -z "$pic_flag" && test -n "$link_static_flag"; then
+ dlopen_self=$dlopen_self_static
+ fi
+ fi
+ build_libtool_libs=no
+ build_old_libs=yes
+ prefer_static_libs=yes
+ break
+ ;;
+ esac
+ done
+
+ # See if our shared archives depend on static archives.
+ test -n "$old_archive_from_new_cmds" && build_old_libs=yes
+
+ # Go through the arguments, transforming them on the way.
+ while test $# -gt 0; do
+ arg="$1"
+ shift
+
+ # If the previous option needs an argument, assign it.
+ if test -n "$prev"; then
+ case "$prev" in
+ output)
+ compile_command="$compile_command @OUTPUT@"
+ finalize_command="$finalize_command @OUTPUT@"
+ ;;
+ esac
+
+ case "$prev" in
+ dlfiles|dlprefiles)
+ if test "$preload" = no; then
+ # Add the symbol object into the linking commands.
+ compile_command="$compile_command @SYMFILE@"
+ finalize_command="$finalize_command @SYMFILE@"
+ preload=yes
+ fi
+ case "$arg" in
+ *.la | *.lo) ;; # We handle these cases below.
+ force)
+ if test "$dlself" = no; then
+ dlself=needless
+ export_dynamic=yes
+ fi
+ prev=
+ continue
+ ;;
+ self)
+ if test "$prev" = dlprefiles; then
+ dlself=yes
+ elif test "$prev" = dlfiles && test "$dlopen_self" != yes; then
+ dlself=yes
+ else
+ dlself=needless
+ export_dynamic=yes
+ fi
+ prev=
+ continue
+ ;;
+ *)
+ if test "$prev" = dlfiles; then
+ dlfiles="$dlfiles $arg"
+ else
+ dlprefiles="$dlprefiles $arg"
+ fi
+ prev=
+ ;;
+ esac
+ ;;
+ expsyms)
+ export_symbols="$arg"
+ if test ! -f "$arg"; then
+ $echo "$modename: symbol file \`$arg' does not exist"
+ exit 1
+ fi
+ prev=
+ continue
+ ;;
+ expsyms_regex)
+ export_symbols_regex="$arg"
+ prev=
+ continue
+ ;;
+ release)
+ release="-$arg"
+ prev=
+ continue
+ ;;
+ rpath | xrpath)
+ # We need an absolute path.
+ case "$arg" in
+ [\\/]* | [A-Za-z]:[\\/]*) ;;
+ *)
+ $echo "$modename: only absolute run-paths are allowed" 1>&2
+ exit 1
+ ;;
+ esac
+ if test "$prev" = rpath; then
+ case "$rpath " in
+ *" $arg "*) ;;
+ *) rpath="$rpath $arg" ;;
+ esac
+ else
+ case "$xrpath " in
+ *" $arg "*) ;;
+ *) xrpath="$xrpath $arg" ;;
+ esac
+ fi
+ prev=
+ continue
+ ;;
+ *)
+ eval "$prev=\"\$arg\""
+ prev=
+ continue
+ ;;
+ esac
+ fi
+
+ prevarg="$arg"
+
+ case "$arg" in
+ -all-static)
+ if test -n "$link_static_flag"; then
+ compile_command="$compile_command $link_static_flag"
+ finalize_command="$finalize_command $link_static_flag"
+ fi
+ continue
+ ;;
+
+ -allow-undefined)
+ # FIXME: remove this flag sometime in the future.
+ $echo "$modename: \`-allow-undefined' is deprecated because it is the default" 1>&2
+ continue
+ ;;
+
+ -avoid-version)
+ avoid_version=yes
+ continue
+ ;;
+
+ -dlopen)
+ prev=dlfiles
+ continue
+ ;;
+
+ -dlpreopen)
+ prev=dlprefiles
+ continue
+ ;;
+
+ -export-dynamic)
+ export_dynamic=yes
+ continue
+ ;;
+
+ -export-symbols | -export-symbols-regex)
+ if test -n "$export_symbols" || test -n "$export_symbols_regex"; then
+ $echo "$modename: not more than one -exported-symbols argument allowed"
+ exit 1
+ fi
+ if test "X$arg" = "X-export-symbols"; then
+ prev=expsyms
+ else
+ prev=expsyms_regex
+ fi
+ continue
+ ;;
+
+ -L*)
+ dir=`$echo "X$arg" | $Xsed -e 's/^-L//'`
+ # We need an absolute path.
+ case "$dir" in
+ [\\/]* | [A-Za-z]:[\\/]*) ;;
+ *)
+ absdir=`cd "$dir" && pwd`
+ if test -z "$absdir"; then
+ $echo "$modename: warning: cannot determine absolute directory name of \`$dir'" 1>&2
+ $echo "$modename: passing it literally to the linker, although it might fail" 1>&2
+ absdir="$dir"
+ fi
+ dir="$absdir"
+ ;;
+ esac
+ case " $deplibs " in
+ *" $arg "*) ;;
+ *) deplibs="$deplibs $arg";;
+ esac
+ case " $lib_search_path " in
+ *" $dir "*) ;;
+ *) lib_search_path="$lib_search_path $dir";;
+ esac
+ case "$host" in
+ *-*-cygwin* | *-*-mingw* | *-*-os2*)
+ dllsearchdir=`cd "$dir" && pwd || echo "$dir"`
+ case ":$dllsearchpath:" in
+ ::) dllsearchpath="$dllsearchdir";;
+ *":$dllsearchdir:"*) ;;
+ *) dllsearchpath="$dllsearchpath:$dllsearchdir";;
+ esac
+ ;;
+ esac
+ ;;
+
+ -l*)
+ if test "$arg" = "-lc"; then
+ case "$host" in
+ *-*-cygwin* | *-*-mingw* | *-*-os2* | *-*-beos*)
+ # These systems don't actually have c library (as such)
+ continue
+ ;;
+ esac
+ elif test "$arg" = "-lm"; then
+ case "$host" in
+ *-*-cygwin* | *-*-beos*)
+ # These systems don't actually have math library (as such)
+ continue
+ ;;
+ esac
+ fi
+ deplibs="$deplibs $arg"
+ ;;
+
+ -module)
+ module=yes
+ continue
+ ;;
+
+ -no-undefined)
+ allow_undefined=no
+ continue
+ ;;
+
+ -o) prev=output ;;
+
+ -release)
+ prev=release
+ continue
+ ;;
+
+ -rpath)
+ prev=rpath
+ continue
+ ;;
+
+ -R)
+ prev=xrpath
+ continue
+ ;;
+
+ -R*)
+ dir=`$echo "X$arg" | $Xsed -e 's/^-R//'`
+ # We need an absolute path.
+ case "$dir" in
+ [\\/]* | [A-Za-z]:[\\/]*) ;;
+ *)
+ $echo "$modename: only absolute run-paths are allowed" 1>&2
+ exit 1
+ ;;
+ esac
+ case "$xrpath " in
+ *" $dir "*) ;;
+ *) xrpath="$xrpath $dir" ;;
+ esac
+ continue
+ ;;
+
+ -static)
+ # If we have no pic_flag, then this is the same as -all-static.
+ if test -z "$pic_flag" && test -n "$link_static_flag"; then
+ compile_command="$compile_command $link_static_flag"
+ finalize_command="$finalize_command $link_static_flag"
+ fi
+ continue
+ ;;
+
+ -thread-safe)
+ thread_safe=yes
+ continue
+ ;;
+
+ -version-info)
+ prev=vinfo
+ continue
+ ;;
+
+ # Some other compiler flag.
+ -* | +*)
+ # Unknown arguments in both finalize_command and compile_command need
+ # to be aesthetically quoted because they are evaled later.
+ arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`
+ case "$arg" in
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*)
+ arg="\"$arg\""
+ ;;
+ esac
+ ;;
+
+ *.o | *.obj | *.a | *.lib)
+ # A standard object.
+ objs="$objs $arg"
+ ;;
+
+ *.lo)
+ # A library object.
+ if test "$prev" = dlfiles; then
+ dlfiles="$dlfiles $arg"
+ if test "$build_libtool_libs" = yes && test "$dlopen" = yes; then
+ prev=
+ continue
+ else
+ # If libtool objects are unsupported, then we need to preload.
+ prev=dlprefiles
+ fi
+ fi
+
+ if test "$prev" = dlprefiles; then
+ # Preload the old-style object.
+ dlprefiles="$dlprefiles "`$echo "X$arg" | $Xsed -e "$lo2o"`
+ prev=
+ fi
+ libobjs="$libobjs $arg"
+ ;;
+
+ *.la)
+ # A libtool-controlled library.
+
+ dlname=
+ libdir=
+ library_names=
+ old_library=
+
+ # Check to see that this really is a libtool archive.
+ if (sed -e '2q' $arg | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then :
+ else
+ $echo "$modename: \`$arg' is not a valid libtool archive" 1>&2
+ exit 1
+ fi
+
+ # If the library was installed with an old release of libtool,
+ # it will not redefine variable installed.
+ installed=yes
+
+ # Read the .la file
+ # If there is no directory component, then add one.
+ case "$arg" in
+ */* | *\\*) . $arg ;;
+ *) . ./$arg ;;
+ esac
+
+ # Get the name of the library we link against.
+ linklib=
+ for l in $old_library $library_names; do
+ linklib="$l"
+ done
+
+ if test -z "$linklib"; then
+ $echo "$modename: cannot find name of link library for \`$arg'" 1>&2
+ exit 1
+ fi
+
+ # Find the relevant object directory and library name.
+ name=`$echo "X$arg" | $Xsed -e 's%^.*/%%' -e 's/\.la$//' -e 's/^lib//'`
+
+ if test "X$installed" = Xyes; then
+ dir="$libdir"
+ else
+ dir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'`
+ if test "X$dir" = "X$arg"; then
+ dir="$objdir"
+ else
+ dir="$dir/$objdir"
+ fi
+ fi
+
+ if test -n "$dependency_libs"; then
+ # Extract -R and -L from dependency_libs
+ temp_deplibs=
+ for deplib in $dependency_libs; do
+ case "$deplib" in
+ -R*) temp_xrpath=`$echo "X$deplib" | $Xsed -e 's/^-R//'`
+ case " $rpath $xrpath " in
+ *" $temp_xrpath "*) ;;
+ *) xrpath="$xrpath $temp_xrpath";;
+ esac;;
+ -L*) case "$compile_command $temp_deplibs " in
+ *" $deplib "*) ;;
+ *) temp_deplibs="$temp_deplibs $deplib";;
+ esac
+ temp_dir=`$echo "X$deplib" | $Xsed -e 's/^-L//'`
+ case " $lib_search_path " in
+ *" $temp_dir "*) ;;
+ *) lib_search_path="$lib_search_path $temp_dir";;
+ esac
+ ;;
+ *) temp_deplibs="$temp_deplibs $deplib";;
+ esac
+ done
+ dependency_libs="$temp_deplibs"
+ fi
+
+ if test -z "$libdir"; then
+ # It is a libtool convenience library, so add in its objects.
+ convenience="$convenience $dir/$old_library"
+ old_convenience="$old_convenience $dir/$old_library"
+ deplibs="$deplibs$dependency_libs"
+ compile_command="$compile_command $dir/$old_library$dependency_libs"
+ finalize_command="$finalize_command $dir/$old_library$dependency_libs"
+ continue
+ fi
+
+ # This library was specified with -dlopen.
+ if test "$prev" = dlfiles; then
+ dlfiles="$dlfiles $arg"
+ if test -z "$dlname" || test "$dlopen" != yes || test "$build_libtool_libs" = no; then
+ # If there is no dlname, no dlopen support or we're linking statically,
+ # we need to preload.
+ prev=dlprefiles
+ else
+ # We should not create a dependency on this library, but we
+ # may need any libraries it requires.
+ compile_command="$compile_command$dependency_libs"
+ finalize_command="$finalize_command$dependency_libs"
+ prev=
+ continue
+ fi
+ fi
+
+ # The library was specified with -dlpreopen.
+ if test "$prev" = dlprefiles; then
+ # Prefer using a static library (so that no silly _DYNAMIC symbols
+ # are required to link).
+ if test -n "$old_library"; then
+ dlprefiles="$dlprefiles $dir/$old_library"
+ else
+ dlprefiles="$dlprefiles $dir/$linklib"
+ fi
+ prev=
+ fi
+
+ if test -n "$library_names" &&
+ { test "$prefer_static_libs" = no || test -z "$old_library"; }; then
+ link_against_libtool_libs="$link_against_libtool_libs $arg"
+ if test -n "$shlibpath_var"; then
+ # Make sure the rpath contains only unique directories.
+ case "$temp_rpath " in
+ *" $dir "*) ;;
+ *) temp_rpath="$temp_rpath $dir" ;;
+ esac
+ fi
+
+ # We need an absolute path.
+ case "$dir" in
+ [\\/] | [A-Za-z]:[\\/]*) absdir="$dir" ;;
+ *)
+ absdir=`cd "$dir" && pwd`
+ if test -z "$absdir"; then
+ $echo "$modename: warning: cannot determine absolute directory name of \`$dir'" 1>&2
+ $echo "$modename: passing it literally to the linker, although it might fail" 1>&2
+ absdir="$dir"
+ fi
+ ;;
+ esac
+
+ # This is the magic to use -rpath.
+ # Skip directories that are in the system default run-time
+ # search path, unless they have been requested with -R.
+ case " $sys_lib_dlsearch_path " in
+ *" $absdir "*) ;;
+ *)
+ case "$compile_rpath " in
+ *" $absdir "*) ;;
+ *) compile_rpath="$compile_rpath $absdir"
+ esac
+ ;;
+ esac
+
+ case " $sys_lib_dlsearch_path " in
+ *" $libdir "*) ;;
+ *)
+ case "$finalize_rpath " in
+ *" $libdir "*) ;;
+ *) finalize_rpath="$finalize_rpath $libdir"
+ esac
+ ;;
+ esac
+
+ lib_linked=yes
+ case "$hardcode_action" in
+ immediate | unsupported)
+ if test "$hardcode_direct" = no; then
+ compile_command="$compile_command $dir/$linklib"
+ deplibs="$deplibs $dir/$linklib"
+ case "$host" in
+ *-*-cygwin* | *-*-mingw* | *-*-os2*)
+ dllsearchdir=`cd "$dir" && pwd || echo "$dir"`
+ if test -n "$dllsearchpath"; then
+ dllsearchpath="$dllsearchpath:$dllsearchdir"
+ else
+ dllsearchpath="$dllsearchdir"
+ fi
+ ;;
+ esac
+ elif test "$hardcode_minus_L" = no; then
+ case "$host" in
+ *-*-sunos*)
+ compile_shlibpath="$compile_shlibpath$dir:"
+ ;;
+ esac
+ case "$compile_command " in
+ *" -L$dir "*) ;;
+ *) compile_command="$compile_command -L$dir";;
+ esac
+ compile_command="$compile_command -l$name"
+ deplibs="$deplibs -L$dir -l$name"
+ elif test "$hardcode_shlibpath_var" = no; then
+ case ":$compile_shlibpath:" in
+ *":$dir:"*) ;;
+ *) compile_shlibpath="$compile_shlibpath$dir:";;
+ esac
+ compile_command="$compile_command -l$name"
+ deplibs="$deplibs -l$name"
+ else
+ lib_linked=no
+ fi
+ ;;
+
+ relink)
+ if test "$hardcode_direct" = yes; then
+ compile_command="$compile_command $absdir/$linklib"
+ deplibs="$deplibs $absdir/$linklib"
+ elif test "$hardcode_minus_L" = yes; then
+ case "$compile_command " in
+ *" -L$absdir "*) ;;
+ *) compile_command="$compile_command -L$absdir";;
+ esac
+ compile_command="$compile_command -l$name"
+ deplibs="$deplibs -L$absdir -l$name"
+ elif test "$hardcode_shlibpath_var" = yes; then
+ case ":$compile_shlibpath:" in
+ *":$absdir:"*) ;;
+ *) compile_shlibpath="$compile_shlibpath$absdir:";;
+ esac
+ compile_command="$compile_command -l$name"
+ deplibs="$deplibs -l$name"
+ else
+ lib_linked=no
+ fi
+ ;;
+
+ *)
+ lib_linked=no
+ ;;
+ esac
+
+ if test "$lib_linked" != yes; then
+ $echo "$modename: configuration error: unsupported hardcode properties"
+ exit 1
+ fi
+
+ # Finalize command for both is simple: just hardcode it.
+ if test "$hardcode_direct" = yes; then
+ finalize_command="$finalize_command $libdir/$linklib"
+ elif test "$hardcode_minus_L" = yes; then
+ case "$finalize_command " in
+ *" -L$libdir "*) ;;
+ *) finalize_command="$finalize_command -L$libdir";;
+ esac
+ finalize_command="$finalize_command -l$name"
+ elif test "$hardcode_shlibpath_var" = yes; then
+ case ":$finalize_shlibpath:" in
+ *":$libdir:"*) ;;
+ *) finalize_shlibpath="$finalize_shlibpath$libdir:";;
+ esac
+ finalize_command="$finalize_command -l$name"
+ else
+ # We cannot seem to hardcode it, guess we'll fake it.
+ case "$finalize_command " in
+ *" -L$dir "*) ;;
+ *) finalize_command="$finalize_command -L$libdir";;
+ esac
+ finalize_command="$finalize_command -l$name"
+ fi
+ else
+ # Transform directly to old archives if we don't build new libraries.
+ if test -n "$pic_flag" && test -z "$old_library"; then
+ $echo "$modename: cannot find static library for \`$arg'" 1>&2
+ exit 1
+ fi
+
+ # Here we assume that one of hardcode_direct or hardcode_minus_L
+ # is not unsupported. This is valid on all known static and
+ # shared platforms.
+ if test "$hardcode_direct" != unsupported; then
+ test -n "$old_library" && linklib="$old_library"
+ compile_command="$compile_command $dir/$linklib"
+ finalize_command="$finalize_command $dir/$linklib"
+ else
+ case "$compile_command " in
+ *" -L$dir "*) ;;
+ *) compile_command="$compile_command -L$dir";;
+ esac
+ compile_command="$compile_command -l$name"
+ case "$finalize_command " in
+ *" -L$dir "*) ;;
+ *) finalize_command="$finalize_command -L$dir";;
+ esac
+ finalize_command="$finalize_command -l$name"
+ fi
+ fi
+
+ # Add in any libraries that this one depends upon.
+ compile_command="$compile_command$dependency_libs"
+ finalize_command="$finalize_command$dependency_libs"
+ continue
+ ;;
+
+ # Some other compiler argument.
+ *)
+ # Unknown arguments in both finalize_command and compile_command need
+ # to be aesthetically quoted because they are evaled later.
+ arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`
+ case "$arg" in
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*)
+ arg="\"$arg\""
+ ;;
+ esac
+ ;;
+ esac
+
+ # Now actually substitute the argument into the commands.
+ if test -n "$arg"; then
+ compile_command="$compile_command $arg"
+ finalize_command="$finalize_command $arg"
+ fi
+ done
+
+ if test -n "$prev"; then
+ $echo "$modename: the \`$prevarg' option requires an argument" 1>&2
+ $echo "$help" 1>&2
+ exit 1
+ fi
+
+ if test "$export_dynamic" = yes && test -n "$export_dynamic_flag_spec"; then
+ eval arg=\"$export_dynamic_flag_spec\"
+ compile_command="$compile_command $arg"
+ finalize_command="$finalize_command $arg"
+ fi
+
+ oldlibs=
+ # calculate the name of the file, without its directory
+ outputname=`$echo "X$output" | $Xsed -e 's%^.*/%%'`
+ libobjs_save="$libobjs"
+
+ case "$output" in
+ "")
+ $echo "$modename: you must specify an output file" 1>&2
+ $echo "$help" 1>&2
+ exit 1
+ ;;
+
+ *.a | *.lib)
+ if test -n "$link_against_libtool_libs"; then
+ $echo "$modename: error: cannot link libtool libraries into archives" 1>&2
+ exit 1
+ fi
+
+ if test -n "$deplibs"; then
+ $echo "$modename: warning: \`-l' and \`-L' are ignored for archives" 1>&2
+ fi
+
+ if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then
+ $echo "$modename: warning: \`-dlopen' is ignored for archives" 1>&2
+ fi
+
+ if test -n "$rpath"; then
+ $echo "$modename: warning: \`-rpath' is ignored for archives" 1>&2
+ fi
+
+ if test -n "$xrpath"; then
+ $echo "$modename: warning: \`-R' is ignored for archives" 1>&2
+ fi
+
+ if test -n "$vinfo"; then
+ $echo "$modename: warning: \`-version-info' is ignored for archives" 1>&2
+ fi
+
+ if test -n "$release"; then
+ $echo "$modename: warning: \`-release' is ignored for archives" 1>&2
+ fi
+
+ if test -n "$export_symbols" || test -n "$export_symbols_regex"; then
+ $echo "$modename: warning: \`-export-symbols' is ignored for archives" 1>&2
+ fi
+
+ # Now set the variables for building old libraries.
+ build_libtool_libs=no
+ oldlibs="$output"
+ ;;
+
+ *.la)
+ # Make sure we only generate libraries of the form `libNAME.la'.
+ case "$outputname" in
+ lib*)
+ name=`$echo "X$outputname" | $Xsed -e 's/\.la$//' -e 's/^lib//'`
+ eval libname=\"$libname_spec\"
+ ;;
+ *)
+ if test "$module" = no; then
+ $echo "$modename: libtool library \`$output' must begin with \`lib'" 1>&2
+ $echo "$help" 1>&2
+ exit 1
+ fi
+ if test "$need_lib_prefix" != no; then
+ # Add the "lib" prefix for modules if required
+ name=`$echo "X$outputname" | $Xsed -e 's/\.la$//'`
+ eval libname=\"$libname_spec\"
+ else
+ libname=`$echo "X$outputname" | $Xsed -e 's/\.la$//'`
+ fi
+ ;;
+ esac
+
+ output_objdir=`$echo "X$output" | $Xsed -e 's%/[^/]*$%%'`
+ if test "X$output_objdir" = "X$output"; then
+ output_objdir="$objdir"
+ else
+ output_objdir="$output_objdir/$objdir"
+ fi
+
+ if test -n "$objs"; then
+ $echo "$modename: cannot build libtool library \`$output' from non-libtool objects:$objs" 2>&1
+ exit 1
+ fi
+
+ # How the heck are we supposed to write a wrapper for a shared library?
+ if test -n "$link_against_libtool_libs"; then
+ $echo "$modename: error: cannot link shared libraries into libtool libraries" 1>&2
+ exit 1
+ fi
+
+ if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then
+ $echo "$modename: warning: \`-dlopen' is ignored for libtool libraries" 1>&2
+ fi
+
+ set dummy $rpath
+ if test $# -gt 2; then
+ $echo "$modename: warning: ignoring multiple \`-rpath's for a libtool library" 1>&2
+ fi
+ install_libdir="$2"
+
+ oldlibs=
+ if test -z "$rpath"; then
+ if test "$build_libtool_libs" = yes; then
+ # Building a libtool convenience library.
+ libext=al
+ oldlibs="$output_objdir/$libname.$libext $oldlibs"
+ build_libtool_libs=convenience
+ build_old_libs=yes
+ fi
+ dependency_libs="$deplibs"
+
+ if test -n "$vinfo"; then
+ $echo "$modename: warning: \`-version-info' is ignored for convenience libraries" 1>&2
+ fi
+
+ if test -n "$release"; then
+ $echo "$modename: warning: \`-release' is ignored for convenience libraries" 1>&2
+ fi
+ else
+
+ # Parse the version information argument.
+ IFS="${IFS= }"; save_ifs="$IFS"; IFS=':'
+ set dummy $vinfo 0 0 0
+ IFS="$save_ifs"
+
+ if test -n "$8"; then
+ $echo "$modename: too many parameters to \`-version-info'" 1>&2
+ $echo "$help" 1>&2
+ exit 1
+ fi
+
+ current="$2"
+ revision="$3"
+ age="$4"
+
+ # Check that each of the things are valid numbers.
+ case "$current" in
+ 0 | [1-9] | [1-9][0-9]*) ;;
+ *)
+ $echo "$modename: CURRENT \`$current' is not a nonnegative integer" 1>&2
+ $echo "$modename: \`$vinfo' is not valid version information" 1>&2
+ exit 1
+ ;;
+ esac
+
+ case "$revision" in
+ 0 | [1-9] | [1-9][0-9]*) ;;
+ *)
+ $echo "$modename: REVISION \`$revision' is not a nonnegative integer" 1>&2
+ $echo "$modename: \`$vinfo' is not valid version information" 1>&2
+ exit 1
+ ;;
+ esac
+
+ case "$age" in
+ 0 | [1-9] | [1-9][0-9]*) ;;
+ *)
+ $echo "$modename: AGE \`$age' is not a nonnegative integer" 1>&2
+ $echo "$modename: \`$vinfo' is not valid version information" 1>&2
+ exit 1
+ ;;
+ esac
+
+ if test $age -gt $current; then
+ $echo "$modename: AGE \`$age' is greater than the current interface number \`$current'" 1>&2
+ $echo "$modename: \`$vinfo' is not valid version information" 1>&2
+ exit 1
+ fi
+
+ # Calculate the version variables.
+ major=
+ versuffix=
+ verstring=
+ case "$version_type" in
+ none) ;;
+
+ irix)
+ major=`expr $current - $age + 1`
+ versuffix="$major.$revision"
+ verstring="sgi$major.$revision"
+
+ # Add in all the interfaces that we are compatible with.
+ loop=$revision
+ while test $loop != 0; do
+ iface=`expr $revision - $loop`
+ loop=`expr $loop - 1`
+ verstring="sgi$major.$iface:$verstring"
+ done
+ ;;
+
+ linux)
+ major=.`expr $current - $age`
+ versuffix="$major.$age.$revision"
+ ;;
+
+ osf)
+ major=`expr $current - $age`
+ versuffix=".$current.$age.$revision"
+ verstring="$current.$age.$revision"
+
+ # Add in all the interfaces that we are compatible with.
+ loop=$age
+ while test $loop != 0; do
+ iface=`expr $current - $loop`
+ loop=`expr $loop - 1`
+ verstring="$verstring:${iface}.0"
+ done
+
+ # Make executables depend on our current version.
+ verstring="$verstring:${current}.0"
+ ;;
+
+ sunos)
+ major=".$current"
+ versuffix=".$current.$revision"
+ ;;
+
+ freebsd-aout)
+ major=".$current"
+ versuffix=".$current.$revision";
+ ;;
+
+ freebsd-elf)
+ major=".$current"
+ versuffix=".$current";
+ ;;
+
+ windows)
+ # Like Linux, but with '-' rather than '.', since we only
+ # want one extension on Windows 95.
+ major=`expr $current - $age`
+ versuffix="-$major-$age-$revision"
+ ;;
+
+ *)
+ $echo "$modename: unknown library version type \`$version_type'" 1>&2
+ echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2
+ exit 1
+ ;;
+ esac
+
+ # Clear the version info if we defaulted, and they specified a release.
+ if test -z "$vinfo" && test -n "$release"; then
+ major=
+ verstring="0.0"
+ if test "$need_version" = no; then
+ versuffix=
+ else
+ versuffix=".0.0"
+ fi
+ fi
+
+ # Remove version info from name if versioning should be avoided
+ if test "$avoid_version" = yes && test "$need_version" = no; then
+ major=
+ versuffix=
+ verstring=""
+ fi
+
+ # Check to see if the archive will have undefined symbols.
+ if test "$allow_undefined" = yes; then
+ if test "$allow_undefined_flag" = unsupported; then
+ $echo "$modename: warning: undefined symbols not allowed in $host shared libraries" 1>&2
+ build_libtool_libs=no
+ build_old_libs=yes
+ fi
+ else
+ # Don't allow undefined symbols.
+ allow_undefined_flag="$no_undefined_flag"
+ fi
+
+ dependency_libs="$deplibs"
+ case "$host" in
+ *-*-cygwin* | *-*-mingw* | *-*-os2* | *-*-beos*)
+ # these systems don't actually have a c library (as such)!
+ ;;
+ *)
+ # Add libc to deplibs on all other systems.
+ deplibs="$deplibs -lc"
+ ;;
+ esac
+ fi
+
+ # Create the output directory, or remove our outputs if we need to.
+ if test -d $output_objdir; then
+ $show "${rm}r $output_objdir/$outputname $output_objdir/$libname.* $output_objdir/${libname}${release}.*"
+ $run ${rm}r $output_objdir/$outputname $output_objdir/$libname.* $output_objdir/${libname}${release}.*
+ else
+ $show "$mkdir $output_objdir"
+ $run $mkdir $output_objdir
+ status=$?
+ if test $status -ne 0 && test ! -d $output_objdir; then
+ exit $status
+ fi
+ fi
+
+ # Now set the variables for building old libraries.
+ if test "$build_old_libs" = yes && test "$build_libtool_libs" != convenience ; then
+ oldlibs="$oldlibs $output_objdir/$libname.$libext"
+
+ # Transform .lo files to .o files.
+ oldobjs="$objs "`$echo "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}'$/d' -e "$lo2o" | $NL2SP`
+ fi
+
+ if test "$build_libtool_libs" = yes; then
+ # Transform deplibs into only deplibs that can be linked in shared.
+ name_save=$name
+ libname_save=$libname
+ release_save=$release
+ versuffix_save=$versuffix
+ major_save=$major
+ # I'm not sure if I'm treating the release correctly. I think
+ # release should show up in the -l (ie -lgmp5) so we don't want to
+ # add it in twice. Is that correct?
+ release=""
+ versuffix=""
+ major=""
+ newdeplibs=
+ droppeddeps=no
+ case "$deplibs_check_method" in
+ pass_all)
+ # Don't check for shared/static. Everything works.
+ # This might be a little naive. We might want to check
+ # whether the library exists or not. But this is on
+ # osf3 & osf4 and I'm not really sure... Just
+ # implementing what was already the behaviour.
+ newdeplibs=$deplibs
+ ;;
+ test_compile)
+ # This code stresses the "libraries are programs" paradigm to its
+ # limits. Maybe even breaks it. We compile a program, linking it
+ # against the deplibs as a proxy for the library. Then we can check
+ # whether they linked in statically or dynamically with ldd.
+ $rm conftest.c
+ cat > conftest.c <<EOF
+ int main() { return 0; }
+EOF
+ $rm conftest
+ $C_compiler -o conftest conftest.c $deplibs
+ if test $? -eq 0 ; then
+ ldd_output=`ldd conftest`
+ for i in $deplibs; do
+ name="`expr $i : '-l\(.*\)'`"
+ # If $name is empty we are operating on a -L argument.
+ if test "$name" != "" ; then
+ libname=`eval \\$echo \"$libname_spec\"`
+ deplib_matches=`eval \\$echo \"$library_names_spec\"`
+ set dummy $deplib_matches
+ deplib_match=$2
+ if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0 ; then
+ newdeplibs="$newdeplibs $i"
+ else
+ droppeddeps=yes
+ echo
+ echo "*** Warning: This library needs some functionality provided by $i."
+ echo "*** I have the capability to make that library automatically link in when"
+ echo "*** you link to this library. But I can only do this if you have a"
+ echo "*** shared version of the library, which you do not appear to have."
+ fi
+ else
+ newdeplibs="$newdeplibs $i"
+ fi
+ done
+ else
+ # Error occured in the first compile. Let's try to salvage the situation:
+ # Compile a seperate program for each library.
+ for i in $deplibs; do
+ name="`expr $i : '-l\(.*\)'`"
+ # If $name is empty we are operating on a -L argument.
+ if test "$name" != "" ; then
+ $rm conftest
+ $C_compiler -o conftest conftest.c $i
+ # Did it work?
+ if test $? -eq 0 ; then
+ ldd_output=`ldd conftest`
+ libname=`eval \\$echo \"$libname_spec\"`
+ deplib_matches=`eval \\$echo \"$library_names_spec\"`
+ set dummy $deplib_matches
+ deplib_match=$2
+ if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0 ; then
+ newdeplibs="$newdeplibs $i"
+ else
+ droppeddeps=yes
+ echo
+ echo "*** Warning: This library needs some functionality provided by $i."
+ echo "*** I have the capability to make that library automatically link in when"
+ echo "*** you link to this library. But I can only do this if you have a"
+ echo "*** shared version of the library, which you do not appear to have."
+ fi
+ else
+ droppeddeps=yes
+ echo
+ echo "*** Warning! Library $i is needed by this library but I was not able to"
+ echo "*** make it link in! You will probably need to install it or some"
+ echo "*** library that it depends on before this library will be fully"
+ echo "*** functional. Installing it before continuing would be even better."
+ fi
+ else
+ newdeplibs="$newdeplibs $i"
+ fi
+ done
+ fi
+ ;;
+ file_magic*)
+ set dummy $deplibs_check_method
+ file_magic_regex="`expr \"$deplibs_check_method\" : \"$2 \(.*\)\"`"
+ for a_deplib in $deplibs; do
+ name="`expr $a_deplib : '-l\(.*\)'`"
+ # If $name is empty we are operating on a -L argument.
+ if test "$name" != "" ; then
+ libname=`eval \\$echo \"$libname_spec\"`
+ for i in $lib_search_path; do
+ potential_libs=`ls $i/$libname[.-]* 2>/dev/null`
+ for potent_lib in $potential_libs; do
+ # Follow soft links.
+ if ls -lLd "$potent_lib" 2>/dev/null \
+ | grep " -> " >/dev/null; then
+ continue
+ fi
+ # The statement above tries to avoid entering an
+ # endless loop below, in case of cyclic links.
+ # We might still enter an endless loop, since a link
+ # loop can be closed while we follow links,
+ # but so what?
+ potlib="$potent_lib"
+ while test -h "$potlib" 2>/dev/null; do
+ potliblink=`ls -ld $potlib | sed 's/.* -> //'`
+ case "$potliblink" in
+ [\\/]* | [A-Za-z]:[\\/]*) potlib="$potliblink";;
+ *) potlib=`$echo "X$potlib" | $Xsed -e 's,[^/]*$,,'`"$potliblink";;
+ esac
+ done
+ if eval $file_magic_cmd \"\$potlib\" 2>/dev/null \
+ | sed 10q \
+ | egrep "$file_magic_regex" > /dev/null; then
+ newdeplibs="$newdeplibs $a_deplib"
+ a_deplib=""
+ break 2
+ fi
+ done
+ done
+ if test -n "$a_deplib" ; then
+ droppeddeps=yes
+ echo
+ echo "*** Warning: This library needs some functionality provided by $a_deplib."
+ echo "*** I have the capability to make that library automatically link in when"
+ echo "*** you link to this library. But I can only do this if you have a"
+ echo "*** shared version of the library, which you do not appear to have."
+ fi
+ else
+ # Add a -L argument.
+ newdeplibs="$newdeplibs $a_deplib"
+ fi
+ done # Gone through all deplibs.
+ ;;
+ none | unknown | *)
+ newdeplibs=""
+ if $echo "X $deplibs" | $Xsed -e 's/ -lc$//' \
+ -e 's/ -[LR][^ ]*//g' -e 's/[ ]//g' |
+ grep . >/dev/null; then
+ echo
+ if test "X$deplibs_check_method" = "Xnone"; then
+ echo "*** Warning: inter-library dependencies are not supported in this platform."
+ else
+ echo "*** Warning: inter-library dependencies are not known to be supported."
+ fi
+ echo "*** All declared inter-library dependencies are being dropped."
+ droppeddeps=yes
+ fi
+ ;;
+ esac
+ versuffix=$versuffix_save
+ major=$major_save
+ release=$release_save
+ libname=$libname_save
+ name=$name_save
+
+ if test "$droppeddeps" = yes; then
+ if test "$module" = yes; then
+ echo
+ echo "*** Warning: libtool could not satisfy all declared inter-library"
+ echo "*** dependencies of module $libname. Therefore, libtool will create"
+ echo "*** a static module, that should work as long as the dlopening"
+ echo "*** application is linked with the -dlopen flag."
+ if test -z "$global_symbol_pipe"; then
+ echo
+ echo "*** However, this would only work if libtool was able to extract symbol"
+ echo "*** lists from a program, using \`nm' or equivalent, but libtool could"
+ echo "*** not find such a program. So, this module is probably useless."
+ echo "*** \`nm' from GNU binutils and a full rebuild may help."
+ fi
+ if test "$build_old_libs" = no; then
+ oldlibs="$output_objdir/$libname.$libext"
+ build_libtool_libs=module
+ build_old_libs=yes
+ else
+ build_libtool_libs=no
+ fi
+ else
+ echo "*** The inter-library dependencies that have been dropped here will be"
+ echo "*** automatically added whenever a program is linked with this library"
+ echo "*** or is declared to -dlopen it."
+ fi
+ fi
+ # Done checking deplibs!
+ deplibs=$newdeplibs
+ fi
+
+ # All the library-specific variables (install_libdir is set above).
+ library_names=
+ old_library=
+ dlname=
+
+ # Test again, we may have decided not to build it any more
+ if test "$build_libtool_libs" = yes; then
+ # Get the real and link names of the library.
+ eval library_names=\"$library_names_spec\"
+ set dummy $library_names
+ realname="$2"
+ shift; shift
+
+ if test -n "$soname_spec"; then
+ eval soname=\"$soname_spec\"
+ else
+ soname="$realname"
+ fi
+
+ lib="$output_objdir/$realname"
+ for link
+ do
+ linknames="$linknames $link"
+ done
+
+ # Ensure that we have .o objects for linkers which dislike .lo
+ # (e.g. aix) incase we are running --disable-static
+ for obj in $libobjs; do
+ oldobj=`$echo "X$obj" | $Xsed -e "$lo2o"`
+ if test ! -f $oldobj; then
+ $show "${LN_S} $obj $oldobj"
+ $run ${LN_S} $obj $oldobj || exit $?
+ fi
+ done
+
+ # Use standard objects if they are pic
+ test -z "$pic_flag" && libobjs=`$echo "X$libobjs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP`
+
+ # Prepare the list of exported symbols
+ if test -z "$export_symbols"; then
+ if test "$always_export_symbols" = yes || test -n "$export_symbols_regex"; then
+ $show "generating symbol list for \`$libname.la'"
+ export_symbols="$output_objdir/$libname.exp"
+ $run $rm $export_symbols
+ eval cmds=\"$export_symbols_cmds\"
+ IFS="${IFS= }"; save_ifs="$IFS"; IFS='~'
+ for cmd in $cmds; do
+ IFS="$save_ifs"
+ $show "$cmd"
+ $run eval "$cmd" || exit $?
+ done
+ IFS="$save_ifs"
+ if test -n "$export_symbols_regex"; then
+ $show "egrep -e \"$export_symbols_regex\" \"$export_symbols\" > \"${export_symbols}T\""
+ $run eval 'egrep -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"'
+ $show "$mv \"${export_symbols}T\" \"$export_symbols\""
+ $run eval '$mv "${export_symbols}T" "$export_symbols"'
+ fi
+ fi
+ fi
+
+ if test -n "$export_symbols" && test -n "$include_expsyms"; then
+ $run eval '$echo "X$include_expsyms" | $SP2NL >> "$export_symbols"'
+ fi
+
+ if test -n "$convenience"; then
+ if test -n "$whole_archive_flag_spec"; then
+ eval libobjs=\"\$libobjs $whole_archive_flag_spec\"
+ else
+ gentop="$output_objdir/${outputname}x"
+ $show "${rm}r $gentop"
+ $run ${rm}r "$gentop"
+ $show "mkdir $gentop"
+ $run mkdir "$gentop"
+ status=$?
+ if test $status -ne 0 && test ! -d "$gentop"; then
+ exit $status
+ fi
+ generated="$generated $gentop"
+
+ for xlib in $convenience; do
+ # Extract the objects.
+ case "$xlib" in
+ [\\/]* | [A-Za-z]:[\\/]*) xabs="$xlib" ;;
+ *) xabs=`pwd`"/$xlib" ;;
+ esac
+ xlib=`$echo "X$xlib" | $Xsed -e 's%^.*/%%'`
+ xdir="$gentop/$xlib"
+
+ $show "${rm}r $xdir"
+ $run ${rm}r "$xdir"
+ $show "mkdir $xdir"
+ $run mkdir "$xdir"
+ status=$?
+ if test $status -ne 0 && test ! -d "$xdir"; then
+ exit $status
+ fi
+ $show "(cd $xdir && $AR x $xabs)"
+ $run eval "(cd \$xdir && $AR x \$xabs)" || exit $?
+
+ libobjs="$libobjs "`find $xdir -name \*.o -print -o -name \*.lo -print | $NL2SP`
+ done
+ fi
+ fi
+
+ if test "$thread_safe" = yes && test -n "$thread_safe_flag_spec"; then
+ eval flag=\"$thread_safe_flag_spec\"
+ linkopts="$linkopts $flag"
+ fi
+
+ # Do each of the archive commands.
+ if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then
+ eval cmds=\"$archive_expsym_cmds\"
+ else
+ eval cmds=\"$archive_cmds\"
+ fi
+ IFS="${IFS= }"; save_ifs="$IFS"; IFS='~'
+ for cmd in $cmds; do
+ IFS="$save_ifs"
+ $show "$cmd"
+ $run eval "$cmd" || exit $?
+ done
+ IFS="$save_ifs"
+
+ # Create links to the real library.
+ for linkname in $linknames; do
+ if test "$realname" != "$linkname"; then
+ $show "(cd $output_objdir && $rm $linkname && $LN_S $realname $linkname)"
+ $run eval '(cd $output_objdir && $rm $linkname && $LN_S $realname $linkname)' || exit $?
+ fi
+ done
+
+ # If -module or -export-dynamic was specified, set the dlname.
+ if test "$module" = yes || test "$export_dynamic" = yes; then
+ # On all known operating systems, these are identical.
+ dlname="$soname"
+ fi
+ fi
+ ;;
+
+ *.lo | *.o | *.obj)
+ if test -n "$link_against_libtool_libs"; then
+ $echo "$modename: error: cannot link libtool libraries into objects" 1>&2
+ exit 1
+ fi
+
+ if test -n "$deplibs"; then
+ $echo "$modename: warning: \`-l' and \`-L' are ignored for objects" 1>&2
+ fi
+
+ if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then
+ $echo "$modename: warning: \`-dlopen' is ignored for objects" 1>&2
+ fi
+
+ if test -n "$rpath"; then
+ $echo "$modename: warning: \`-rpath' is ignored for objects" 1>&2
+ fi
+
+ if test -n "$xrpath"; then
+ $echo "$modename: warning: \`-R' is ignored for objects" 1>&2
+ fi
+
+ if test -n "$vinfo"; then
+ $echo "$modename: warning: \`-version-info' is ignored for objects" 1>&2
+ fi
+
+ if test -n "$release"; then
+ $echo "$modename: warning: \`-release' is ignored for objects" 1>&2
+ fi
+
+ case "$output" in
+ *.lo)
+ if test -n "$objs"; then
+ $echo "$modename: cannot build library object \`$output' from non-libtool objects" 1>&2
+ exit 1
+ fi
+ libobj="$output"
+ obj=`$echo "X$output" | $Xsed -e "$lo2o"`
+ ;;
+ *)
+ libobj=
+ obj="$output"
+ ;;
+ esac
+
+ # Delete the old objects.
+ $run $rm $obj $libobj
+
+ # Objects from convenience libraries. This assumes
+ # single-version convenience libraries. Whenever we create
+ # different ones for PIC/non-PIC, this we'll have to duplicate
+ # the extraction.
+ reload_conv_objs=
+ gentop=
+ # reload_cmds runs $LD directly, so let us get rid of
+ # -Wl from whole_archive_flag_spec
+ wl=
+
+ if test -n "$convenience"; then
+ if test -n "$whole_archive_flag_spec"; then
+ eval reload_conv_objs=\"\$reload_objs $whole_archive_flag_spec\"
+ else
+ gentop="$output_objdir/${obj}x"
+ $show "${rm}r $gentop"
+ $run ${rm}r "$gentop"
+ $show "mkdir $gentop"
+ $run mkdir "$gentop"
+ status=$?
+ if test $status -ne 0 && test ! -d "$gentop"; then
+ exit $status
+ fi
+ generated="$generated $gentop"
+
+ for xlib in $convenience; do
+ # Extract the objects.
+ case "$xlib" in
+ [\\/]* | [A-Za-z]:[\\/]*) xabs="$xlib" ;;
+ *) xabs=`pwd`"/$xlib" ;;
+ esac
+ xlib=`$echo "X$xlib" | $Xsed -e 's%^.*/%%'`
+ xdir="$gentop/$xlib"
+
+ $show "${rm}r $xdir"
+ $run ${rm}r "$xdir"
+ $show "mkdir $xdir"
+ $run mkdir "$xdir"
+ status=$?
+ if test $status -ne 0 && test ! -d "$xdir"; then
+ exit $status
+ fi
+ $show "(cd $xdir && $AR x $xabs)"
+ $run eval "(cd \$xdir && $AR x \$xabs)" || exit $?
+
+ reload_conv_objs="$reload_objs "`find $xdir -name \*.o -print -o -name \*.lo -print | $NL2SP`
+ done
+ fi
+ fi
+
+ # Create the old-style object.
+ reload_objs="$objs "`$echo "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}$'/d' -e '/\.lib$/d' -e "$lo2o" | $NL2SP`" $reload_conv_objs"
+
+ output="$obj"
+ eval cmds=\"$reload_cmds\"
+ IFS="${IFS= }"; save_ifs="$IFS"; IFS='~'
+ for cmd in $cmds; do
+ IFS="$save_ifs"
+ $show "$cmd"
+ $run eval "$cmd" || exit $?
+ done
+ IFS="$save_ifs"
+
+ # Exit if we aren't doing a library object file.
+ if test -z "$libobj"; then
+ if test -n "$gentop"; then
+ $show "${rm}r $gentop"
+ $run ${rm}r $gentop
+ fi
+
+ exit 0
+ fi
+
+ if test "$build_libtool_libs" != yes; then
+ if test -n "$gentop"; then
+ $show "${rm}r $gentop"
+ $run ${rm}r $gentop
+ fi
+
+ # Create an invalid libtool object if no PIC, so that we don't
+ # accidentally link it into a program.
+ $show "echo timestamp > $libobj"
+ $run eval "echo timestamp > $libobj" || exit $?
+ exit 0
+ fi
+
+ if test -n "$pic_flag"; then
+ # Only do commands if we really have different PIC objects.
+ reload_objs="$libobjs $reload_conv_objs"
+ output="$libobj"
+ eval cmds=\"$reload_cmds\"
+ IFS="${IFS= }"; save_ifs="$IFS"; IFS='~'
+ for cmd in $cmds; do
+ IFS="$save_ifs"
+ $show "$cmd"
+ $run eval "$cmd" || exit $?
+ done
+ IFS="$save_ifs"
+ else
+ # Just create a symlink.
+ $show $rm $libobj
+ $run $rm $libobj
+ $show "$LN_S $obj $libobj"
+ $run $LN_S $obj $libobj || exit $?
+ fi
+
+ if test -n "$gentop"; then
+ $show "${rm}r $gentop"
+ $run ${rm}r $gentop
+ fi
+
+ exit 0
+ ;;
+
+ # Anything else should be a program.
+ *)
+ if test -n "$vinfo"; then
+ $echo "$modename: warning: \`-version-info' is ignored for programs" 1>&2
+ fi
+
+ if test -n "$release"; then
+ $echo "$modename: warning: \`-release' is ignored for programs" 1>&2
+ fi
+
+ if test "$preload" = yes; then
+ if test "$dlopen" = unknown && test "$dlopen_self" = unknown &&
+ test "$dlopen_self_static" = unknown; then
+ $echo "$modename: warning: \`AC_LIBTOOL_DLOPEN' not used. Assuming no dlopen support."
+ fi
+ fi
+
+ if test -n "$rpath$xrpath"; then
+ # If the user specified any rpath flags, then add them.
+ for libdir in $rpath $xrpath; do
+ # This is the magic to use -rpath.
+ case "$compile_rpath " in
+ *" $libdir "*) ;;
+ *) compile_rpath="$compile_rpath $libdir" ;;
+ esac
+ case "$finalize_rpath " in
+ *" $libdir "*) ;;
+ *) finalize_rpath="$finalize_rpath $libdir" ;;
+ esac
+ done
+ fi
+
+ # Now hardcode the library paths
+ rpath=
+ hardcode_libdirs=
+ for libdir in $compile_rpath $finalize_rpath; do
+ if test -n "$hardcode_libdir_flag_spec"; then
+ if test -n "$hardcode_libdir_separator"; then
+ if test -z "$hardcode_libdirs"; then
+ hardcode_libdirs="$libdir"
+ else
+ # Just accumulate the unique libdirs.
+ case "$hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator" in
+ *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
+ ;;
+ *)
+ hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir"
+ ;;
+ esac
+ fi
+ else
+ eval flag=\"$hardcode_libdir_flag_spec\"
+ rpath="$rpath $flag"
+ fi
+ elif test -n "$runpath_var"; then
+ case "$perm_rpath " in
+ *" $libdir "*) ;;
+ *) perm_rpath="$perm_rpath $libdir" ;;
+ esac
+ fi
+ done
+ # Substitute the hardcoded libdirs into the rpath.
+ if test -n "$hardcode_libdir_separator" &&
+ test -n "$hardcode_libdirs"; then
+ libdir="$hardcode_libdirs"
+ eval rpath=\" $hardcode_libdir_flag_spec\"
+ fi
+ compile_rpath="$rpath"
+
+ rpath=
+ hardcode_libdirs=
+ for libdir in $finalize_rpath; do
+ if test -n "$hardcode_libdir_flag_spec"; then
+ if test -n "$hardcode_libdir_separator"; then
+ if test -z "$hardcode_libdirs"; then
+ hardcode_libdirs="$libdir"
+ else
+ # Just accumulate the unique libdirs.
+ case "$hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator" in
+ *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
+ ;;
+ *)
+ hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir"
+ ;;
+ esac
+ fi
+ else
+ eval flag=\"$hardcode_libdir_flag_spec\"
+ rpath="$rpath $flag"
+ fi
+ elif test -n "$runpath_var"; then
+ case "$finalize_perm_rpath " in
+ *" $libdir "*) ;;
+ *) finalize_perm_rpath="$finalize_perm_rpath $libdir" ;;
+ esac
+ fi
+ done
+ # Substitute the hardcoded libdirs into the rpath.
+ if test -n "$hardcode_libdir_separator" &&
+ test -n "$hardcode_libdirs"; then
+ libdir="$hardcode_libdirs"
+ eval rpath=\" $hardcode_libdir_flag_spec\"
+ fi
+ finalize_rpath="$rpath"
+
+ output_objdir=`$echo "X$output" | $Xsed -e 's%/[^/]*$%%'`
+ if test "X$output_objdir" = "X$output"; then
+ output_objdir="$objdir"
+ else
+ output_objdir="$output_objdir/$objdir"
+ fi
+
+ # Create the binary in the object directory, then wrap it.
+ if test ! -d $output_objdir; then
+ $show "$mkdir $output_objdir"
+ $run $mkdir $output_objdir
+ status=$?
+ if test $status -ne 0 && test ! -d $output_objdir; then
+ exit $status
+ fi
+ fi
+
+ if test -n "$libobjs" && test "$build_old_libs" = yes; then
+ # Transform all the library objects into standard objects.
+ compile_command=`$echo "X$compile_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP`
+ finalize_command=`$echo "X$finalize_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP`
+ fi
+
+ dlsyms=
+ if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then
+ if test -n "$NM" && test -n "$global_symbol_pipe"; then
+ dlsyms="${outputname}S.c"
+ else
+ $echo "$modename: not configured to extract global symbols from dlpreopened files" 1>&2
+ fi
+ fi
+
+ if test -n "$dlsyms"; then
+ case "$dlsyms" in
+ "") ;;
+ *.c)
+ # Discover the nlist of each of the dlfiles.
+ nlist="$output_objdir/${outputname}.nm"
+
+ $show "$rm $nlist ${nlist}S ${nlist}T"
+ $run $rm "$nlist" "${nlist}S" "${nlist}T"
+
+ # Parse the name list into a source file.
+ $show "creating $output_objdir/$dlsyms"
+
+ test -z "$run" && $echo > "$output_objdir/$dlsyms" "\
+/* $dlsyms - symbol resolution table for \`$outputname' dlsym emulation. */
+/* Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP */
+
+#ifdef __cplusplus
+extern \"C\" {
+#endif
+
+/* Prevent the only kind of declaration conflicts we can make. */
+#define lt_preloaded_symbols some_other_symbol
+
+/* External symbol declarations for the compiler. */\
+"
+
+ if test "$dlself" = yes; then
+ $show "generating symbol list for \`$output'"
+
+ test -z "$run" && $echo ': @PROGRAM@ ' > "$nlist"
+
+ # Add our own program objects to the symbol list.
+ progfiles=`$echo "X$objs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP`
+ for arg in $progfiles; do
+ $show "extracting global C symbols from \`$arg'"
+ $run eval "$NM $arg | $global_symbol_pipe >> '$nlist'"
+ done
+
+ if test -n "$exclude_expsyms"; then
+ $run eval 'egrep -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T'
+ $run eval '$mv "$nlist"T "$nlist"'
+ fi
+
+ if test -n "$export_symbols_regex"; then
+ $run eval 'egrep -e "$export_symbols_regex" "$nlist" > "$nlist"T'
+ $run eval '$mv "$nlist"T "$nlist"'
+ fi
+
+ # Prepare the list of exported symbols
+ if test -z "$export_symbols"; then
+ export_symbols="$output_objdir/$output.exp"
+ $run $rm $export_symbols
+ $run eval "sed -n -e '/^: @PROGRAM@$/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"'
+ else
+ $run eval "sed -e 's/\([][.*^$]\)/\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$output.exp"'
+ $run eval 'grep -f "$output_objdir/$output.exp" < "$nlist" > "$nlist"T'
+ $run eval 'mv "$nlist"T "$nlist"'
+ fi
+ fi
+
+ for arg in $dlprefiles; do
+ $show "extracting global C symbols from \`$arg'"
+ name=`echo "$arg" | sed -e 's%^.*/%%'`
+ $run eval 'echo ": $name " >> "$nlist"'
+ $run eval "$NM $arg | $global_symbol_pipe >> '$nlist'"
+ done
+
+ if test -z "$run"; then
+ # Make sure we have at least an empty file.
+ test -f "$nlist" || : > "$nlist"
+
+ if test -n "$exclude_expsyms"; then
+ egrep -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T
+ $mv "$nlist"T "$nlist"
+ fi
+
+ # Try sorting and uniquifying the output.
+ if grep -v "^: " < "$nlist" | sort +2 | uniq > "$nlist"S; then
+ :
+ else
+ grep -v "^: " < "$nlist" > "$nlist"S
+ fi
+
+ if test -f "$nlist"S; then
+ eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$dlsyms"'
+ else
+ echo '/* NONE */' >> "$output_objdir/$dlsyms"
+ fi
+
+ $echo >> "$output_objdir/$dlsyms" "\
+
+#undef lt_preloaded_symbols
+
+#if defined (__STDC__) && __STDC__
+# define lt_ptr_t void *
+#else
+# define lt_ptr_t char *
+# define const
+#endif
+
+/* The mapping between symbol names and symbols. */
+const struct {
+ const char *name;
+ lt_ptr_t address;
+}
+lt_preloaded_symbols[] =
+{\
+"
+
+ sed -n -e 's/^: \([^ ]*\) $/ {\"\1\", (lt_ptr_t) 0},/p' \
+ -e 's/^. \([^ ]*\) \([^ ]*\)$/ {"\2", (lt_ptr_t) \&\2},/p' \
+ < "$nlist" >> "$output_objdir/$dlsyms"
+
+ $echo >> "$output_objdir/$dlsyms" "\
+ {0, (lt_ptr_t) 0}
+};
+
+/* This works around a problem in FreeBSD linker */
+#ifdef FREEBSD_WORKAROUND
+static const void *lt_preloaded_setup() {
+ return lt_preloaded_symbols;
+}
+#endif
+
+#ifdef __cplusplus
+}
+#endif\
+"
+ fi
+
+ pic_flag_for_symtable=
+ case "$host" in
+ # compiling the symbol table file with pic_flag works around
+ # a FreeBSD bug that causes programs to crash when -lm is
+ # linked before any other PIC object. But we must not use
+ # pic_flag when linking with -static. The problem exists in
+ # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1.
+ *-*-freebsd2*|*-*-freebsd3.0*)
+ case "$compile_command " in
+ *" -static "*) ;;
+ *) pic_flag_for_symtable=" $pic_flag -DPIC -DFREEBSD_WORKAROUND";;
+ esac
+ esac
+
+ # Now compile the dynamic symbol file.
+ $show "(cd $output_objdir && $C_compiler -c$no_builtin_flag$pic_flag_for_symtable \"$dlsyms\")"
+ $run eval '(cd $output_objdir && $C_compiler -c$no_builtin_flag$pic_flag_for_symtable "$dlsyms")' || exit $?
+
+ # Clean up the generated files.
+ $show "$rm $output_objdir/$dlsyms $nlist ${nlist}S ${nlist}T"
+ $run $rm "$output_objdir/$dlsyms" "$nlist" "${nlist}S" "${nlist}T"
+
+ # Transform the symbol file into the correct name.
+ compile_command=`$echo "X$compile_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%"`
+ finalize_command=`$echo "X$finalize_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%"`
+ ;;
+ *)
+ $echo "$modename: unknown suffix for \`$dlsyms'" 1>&2
+ exit 1
+ ;;
+ esac
+ else
+ # We keep going just in case the user didn't refer to
+ # lt_preloaded_symbols. The linker will fail if global_symbol_pipe
+ # really was required.
+
+ # Nullify the symbol file.
+ compile_command=`$echo "X$compile_command" | $Xsed -e "s% @SYMFILE@%%"`
+ finalize_command=`$echo "X$finalize_command" | $Xsed -e "s% @SYMFILE@%%"`
+ fi
+
+ if test -z "$link_against_libtool_libs" || test "$build_libtool_libs" != yes; then
+ # Replace the output file specification.
+ compile_command=`$echo "X$compile_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'`
+ link_command="$compile_command$compile_rpath"
+
+ # We have no uninstalled library dependencies, so finalize right now.
+ $show "$link_command"
+ $run eval "$link_command"
+ status=$?
+
+ # Delete the generated files.
+ if test -n "$dlsyms"; then
+ $show "$rm $output_objdir/${outputname}S.${objext}"
+ $run $rm "$output_objdir/${outputname}S.${objext}"
+ fi
+
+ exit $status
+ fi
+
+ if test -n "$shlibpath_var"; then
+ # We should set the shlibpath_var
+ rpath=
+ for dir in $temp_rpath; do
+ case "$dir" in
+ [\\/]* | [A-Za-z]:[\\/]*)
+ # Absolute path.
+ rpath="$rpath$dir:"
+ ;;
+ *)
+ # Relative path: add a thisdir entry.
+ rpath="$rpath\$thisdir/$dir:"
+ ;;
+ esac
+ done
+ temp_rpath="$rpath"
+ fi
+
+ if test -n "$compile_shlibpath$finalize_shlibpath"; then
+ compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command"
+ fi
+ if test -n "$finalize_shlibpath"; then
+ finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command"
+ fi
+
+ compile_var=
+ finalize_var=
+ if test -n "$runpath_var"; then
+ if test -n "$perm_rpath"; then
+ # We should set the runpath_var.
+ rpath=
+ for dir in $perm_rpath; do
+ rpath="$rpath$dir:"
+ done
+ compile_var="$runpath_var=\"$rpath\$$runpath_var\" "
+ fi
+ if test -n "$finalize_perm_rpath"; then
+ # We should set the runpath_var.
+ rpath=
+ for dir in $finalize_perm_rpath; do
+ rpath="$rpath$dir:"
+ done
+ finalize_var="$runpath_var=\"$rpath\$$runpath_var\" "
+ fi
+ fi
+
+ if test "$hardcode_action" = relink; then
+ # Fast installation is not supported
+ link_command="$compile_var$compile_command$compile_rpath"
+ relink_command="$finalize_var$finalize_command$finalize_rpath"
+
+ $echo "$modename: warning: this platform does not like uninstalled shared libraries" 1>&2
+ $echo "$modename: \`$output' will be relinked during installation" 1>&2
+ else
+ if test "$fast_install" != no; then
+ link_command="$finalize_var$compile_command$finalize_rpath"
+ if test "$fast_install" = yes; then
+ relink_command=`$echo "X$compile_var$compile_command$compile_rpath" | $Xsed -e 's%@OUTPUT@%\$progdir/\$file%g'`
+ else
+ # fast_install is set to needless
+ relink_command=
+ fi
+ else
+ link_command="$compile_var$compile_command$compile_rpath"
+ relink_command="$finalize_var$finalize_command$finalize_rpath"
+ fi
+ fi
+
+ # Replace the output file specification.
+ link_command=`$echo "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'`
+
+ # Delete the old output files.
+ $run $rm $output $output_objdir/$outputname $output_objdir/lt-$outputname
+
+ $show "$link_command"
+ $run eval "$link_command" || exit $?
+
+ # Now create the wrapper script.
+ $show "creating $output"
+
+ # Quote the relink command for shipping.
+ if test -n "$relink_command"; then
+ relink_command=`$echo "X$relink_command" | $Xsed -e "$sed_quote_subst"`
+ fi
+
+ # Quote $echo for shipping.
+ if test "X$echo" = "X$SHELL $0 --fallback-echo"; then
+ case "$0" in
+ [\\/]* | [A-Za-z]:[\\/]*) qecho="$SHELL $0 --fallback-echo";;
+ *) qecho="$SHELL `pwd`/$0 --fallback-echo";;
+ esac
+ qecho=`$echo "X$qecho" | $Xsed -e "$sed_quote_subst"`
+ else
+ qecho=`$echo "X$echo" | $Xsed -e "$sed_quote_subst"`
+ fi
+
+ # Only actually do things if our run command is non-null.
+ if test -z "$run"; then
+ # win32 will think the script is a binary if it has
+ # a .exe suffix, so we strip it off here.
+ case $output in
+ *.exe) output=`echo $output|sed 's,.exe$,,'` ;;
+ esac
+ $rm $output
+ trap "$rm $output; exit 1" 1 2 15
+
+ $echo > $output "\
+#! $SHELL
+
+# $output - temporary wrapper script for $objdir/$outputname
+# Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP
+#
+# The $output program cannot be directly executed until all the libtool
+# libraries that it depends on are installed.
+#
+# This wrapper script should never be moved out of the build directory.
+# If it is, it will not operate correctly.
+
+# Sed substitution that helps us do robust quoting. It backslashifies
+# metacharacters that are still active within double-quoted strings.
+Xsed='sed -e 1s/^X//'
+sed_quote_subst='$sed_quote_subst'
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+if test \"\${CDPATH+set}\" = set; then CDPATH=; export CDPATH; fi
+
+relink_command=\"$relink_command\"
+
+# This environment variable determines our operation mode.
+if test \"\$libtool_install_magic\" = \"$magic\"; then
+ # install mode needs the following variable:
+ link_against_libtool_libs='$link_against_libtool_libs'
+else
+ # When we are sourced in execute mode, \$file and \$echo are already set.
+ if test \"\$libtool_execute_magic\" != \"$magic\"; then
+ echo=\"$qecho\"
+ file=\"\$0\"
+ # Make sure echo works.
+ if test \"X\$1\" = X--no-reexec; then
+ # Discard the --no-reexec flag, and continue.
+ shift
+ elif test \"X\`(\$echo '\t') 2>/dev/null\`\" = 'X\t'; then
+ # Yippee, \$echo works!
+ :
+ else
+ # Restart under the correct shell, and then maybe \$echo will work.
+ exec $SHELL \"\$0\" --no-reexec \${1+\"\$@\"}
+ fi
+ fi\
+"
+ $echo >> $output "\
+
+ # Find the directory that this script lives in.
+ thisdir=\`\$echo \"X\$file\" | \$Xsed -e 's%/[^/]*$%%'\`
+ test \"x\$thisdir\" = \"x\$file\" && thisdir=.
+
+ # Follow symbolic links until we get to the real thisdir.
+ file=\`ls -ld \"\$file\" | sed -n 's/.*-> //p'\`
+ while test -n \"\$file\"; do
+ destdir=\`\$echo \"X\$file\" | \$Xsed -e 's%/[^/]*\$%%'\`
+
+ # If there was a directory component, then change thisdir.
+ if test \"x\$destdir\" != \"x\$file\"; then
+ case \"\$destdir\" in
+ [\\/]* | [A-Za-z]:[\\/]*) thisdir=\"\$destdir\" ;;
+ *) thisdir=\"\$thisdir/\$destdir\" ;;
+ esac
+ fi
+
+ file=\`\$echo \"X\$file\" | \$Xsed -e 's%^.*/%%'\`
+ file=\`ls -ld \"\$thisdir/\$file\" | sed -n 's/.*-> //p'\`
+ done
+
+ # Try to get the absolute directory name.
+ absdir=\`cd \"\$thisdir\" && pwd\`
+ test -n \"\$absdir\" && thisdir=\"\$absdir\"
+"
+
+ if test "$fast_install" = yes; then
+ echo >> $output "\
+ program=lt-'$outputname'
+ progdir=\"\$thisdir/$objdir\"
+
+ if test ! -f \"\$progdir/\$program\" || \\
+ { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | sed 1q\`; \\
+ test \"X\$file\" != \"X\$progdir/\$program\"; }; then
+
+ file=\"\$\$-\$program\"
+
+ if test ! -d \"\$progdir\"; then
+ $mkdir \"\$progdir\"
+ else
+ $rm \"\$progdir/\$file\"
+ fi"
+
+ echo >> $output "\
+
+ # relink executable if necessary
+ if test -n \"\$relink_command\"; then
+ if (cd \"\$thisdir\" && eval \$relink_command); then :
+ else
+ $rm \"\$progdir/\$file\"
+ exit 1
+ fi
+ fi
+
+ $mv \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null ||
+ { $rm \"\$progdir/\$program\";
+ $mv \"\$progdir/\$file\" \"\$progdir/\$program\"; }
+ $rm \"\$progdir/\$file\"
+ fi"
+ else
+ echo >> $output "\
+ program='$outputname$exeext'
+ progdir=\"\$thisdir/$objdir\"
+"
+ fi
+
+ echo >> $output "\
+
+ if test -f \"\$progdir/\$program\"; then"
+
+ # Export our shlibpath_var if we have one.
+ if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then
+ $echo >> $output "\
+ # Add our own library path to $shlibpath_var
+ $shlibpath_var=\"$temp_rpath\$$shlibpath_var\"
+
+ # Some systems cannot cope with colon-terminated $shlibpath_var
+ # The second colon is a workaround for a bug in BeOS R4 sed
+ $shlibpath_var=\`\$echo \"X\$$shlibpath_var\" | \$Xsed -e 's/::*\$//'\`
+
+ export $shlibpath_var
+"
+ fi
+
+ # fixup the dll searchpath if we need to.
+ if test -n "$dllsearchpath"; then
+ $echo >> $output "\
+ # Add the dll search path components to the executable PATH
+ PATH=$dllsearchpath:\$PATH
+"
+ fi
+
+ $echo >> $output "\
+ if test \"\$libtool_execute_magic\" != \"$magic\"; then
+ # Run the actual program with our arguments.
+"
+ case $host in
+ *-*-cygwin* | *-*-mingw | *-*-os2*)
+ # win32 systems need to use the prog path for dll
+ # lookup to work
+ $echo >> $output "\
+ exec \$progdir\\\\\$program \${1+\"\$@\"}
+"
+ ;;
+ *)
+ $echo >> $output "\
+ # Export the path to the program.
+ PATH=\"\$progdir:\$PATH\"
+ export PATH
+
+ exec \$program \${1+\"\$@\"}
+"
+ ;;
+ esac
+ $echo >> $output "\
+ \$echo \"\$0: cannot exec \$program \${1+\"\$@\"}\"
+ exit 1
+ fi
+ else
+ # The program doesn't exist.
+ \$echo \"\$0: error: \$progdir/\$program does not exist\" 1>&2
+ \$echo \"This script is just a wrapper for \$program.\" 1>&2
+ echo \"See the $PACKAGE documentation for more information.\" 1>&2
+ exit 1
+ fi
+fi\
+"
+ chmod +x $output
+ fi
+ exit 0
+ ;;
+ esac
+
+ # See if we need to build an old-fashioned archive.
+ for oldlib in $oldlibs; do
+
+ if test "$build_libtool_libs" = convenience; then
+ oldobjs="$libobjs_save"
+ addlibs="$convenience"
+ build_libtool_libs=no
+ else
+ if test "$build_libtool_libs" = module; then
+ oldobjs="$libobjs_save"
+ build_libtool_libs=no
+ else
+ oldobjs="$objs "`$echo "X$libobjs_save" | $SP2NL | $Xsed -e '/\.'${libext}'$/d' -e '/\.lib$/d' -e "$lo2o" | $NL2SP`
+ fi
+ addlibs="$old_convenience"
+ fi
+
+ if test -n "$addlibs"; then
+ gentop="$output_objdir/${outputname}x"
+ $show "${rm}r $gentop"
+ $run ${rm}r "$gentop"
+ $show "mkdir $gentop"
+ $run mkdir "$gentop"
+ status=$?
+ if test $status -ne 0 && test ! -d "$gentop"; then
+ exit $status
+ fi
+ generated="$generated $gentop"
+
+ # Add in members from convenience archives.
+ for xlib in $addlibs; do
+ # Extract the objects.
+ case "$xlib" in
+ [\\/]* | [A-Za-z]:[\\/]*) xabs="$xlib" ;;
+ *) xabs=`pwd`"/$xlib" ;;
+ esac
+ xlib=`$echo "X$xlib" | $Xsed -e 's%^.*/%%'`
+ xdir="$gentop/$xlib"
+
+ $show "${rm}r $xdir"
+ $run ${rm}r "$xdir"
+ $show "mkdir $xdir"
+ $run mkdir "$xdir"
+ status=$?
+ if test $status -ne 0 && test ! -d "$xdir"; then
+ exit $status
+ fi
+ $show "(cd $xdir && $AR x $xabs)"
+ $run eval "(cd \$xdir && $AR x \$xabs)" || exit $?
+
+ oldobjs="$oldobjs "`find $xdir -name \*.${objext} -print -o -name \*.lo -print | $NL2SP`
+ done
+ fi
+
+ # Do each command in the archive commands.
+ if test -n "$old_archive_from_new_cmds" && test "$build_libtool_libs" = yes; then
+ eval cmds=\"$old_archive_from_new_cmds\"
+ else
+ # Ensure that we have .o objects in place incase we decided
+ # not to build a shared library, and have fallen back to building
+ # static libs even though --disable-static was passed!
+ for oldobj in $oldobjs; do
+ if test ! -f $oldobj; then
+ obj=`$echo "X$oldobj" | $Xsed -e "$o2lo"`
+ $show "${LN_S} $obj $oldobj"
+ $run ${LN_S} $obj $oldobj || exit $?
+ fi
+ done
+
+ eval cmds=\"$old_archive_cmds\"
+ fi
+ IFS="${IFS= }"; save_ifs="$IFS"; IFS='~'
+ for cmd in $cmds; do
+ IFS="$save_ifs"
+ $show "$cmd"
+ $run eval "$cmd" || exit $?
+ done
+ IFS="$save_ifs"
+ done
+
+ if test -n "$generated"; then
+ $show "${rm}r$generated"
+ $run ${rm}r$generated
+ fi
+
+ # Now create the libtool archive.
+ case "$output" in
+ *.la)
+ old_library=
+ test "$build_old_libs" = yes && old_library="$libname.$libext"
+ $show "creating $output"
+
+ if test -n "$xrpath"; then
+ temp_xrpath=
+ for libdir in $xrpath; do
+ temp_xrpath="$temp_xrpath -R$libdir"
+ done
+ dependency_libs="$temp_xrpath $dependency_libs"
+ fi
+
+ # Only create the output if not a dry run.
+ if test -z "$run"; then
+ for installed in no yes; do
+ if test "$installed" = yes; then
+ if test -z "$install_libdir"; then
+ break
+ fi
+ output="$output_objdir/$outputname"i
+ fi
+ $rm $output
+ $echo > $output "\
+# $outputname - a libtool library file
+# Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP
+#
+# Please DO NOT delete this file!
+# It is necessary for linking the library.
+
+# The name that we can dlopen(3).
+dlname='$dlname'
+
+# Names of this library.
+library_names='$library_names'
+
+# The name of the static archive.
+old_library='$old_library'
+
+# Libraries that this one depends upon.
+dependency_libs='$dependency_libs'
+
+# Version information for $libname.
+current=$current
+age=$age
+revision=$revision
+
+# Is this an already installed library?
+installed=$installed
+
+# Directory that this library needs to be installed in:
+libdir='$install_libdir'\
+"
+ done
+ fi
+
+ # Do a symbolic link so that the libtool archive can be found in
+ # LD_LIBRARY_PATH before the program is installed.
+ $show "(cd $output_objdir && $rm $outputname && $LN_S ../$outputname $outputname)"
+ $run eval "(cd $output_objdir && $rm $outputname && $LN_S ../$outputname $outputname)" || exit $?
+ ;;
+ esac
+ exit 0
+ ;;
+
+ # libtool install mode
+ install)
+ modename="$modename: install"
+
+ # There may be an optional sh(1) argument at the beginning of
+ # install_prog (especially on Windows NT).
+ if test "$nonopt" = "$SHELL" || test "$nonopt" = /bin/sh; then
+ # Aesthetically quote it.
+ arg=`$echo "X$nonopt" | $Xsed -e "$sed_quote_subst"`
+ case "$arg" in
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*)
+ arg="\"$arg\""
+ ;;
+ esac
+ install_prog="$arg "
+ arg="$1"
+ shift
+ else
+ install_prog=
+ arg="$nonopt"
+ fi
+
+ # The real first argument should be the name of the installation program.
+ # Aesthetically quote it.
+ arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`
+ case "$arg" in
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*)
+ arg="\"$arg\""
+ ;;
+ esac
+ install_prog="$install_prog$arg"
+
+ # We need to accept at least all the BSD install flags.
+ dest=
+ files=
+ opts=
+ prev=
+ install_type=
+ isdir=no
+ stripme=
+ for arg
+ do
+ if test -n "$dest"; then
+ files="$files $dest"
+ dest="$arg"
+ continue
+ fi
+
+ case "$arg" in
+ -d) isdir=yes ;;
+ -f) prev="-f" ;;
+ -g) prev="-g" ;;
+ -m) prev="-m" ;;
+ -o) prev="-o" ;;
+ -s)
+ stripme=" -s"
+ continue
+ ;;
+ -*) ;;
+
+ *)
+ # If the previous option needed an argument, then skip it.
+ if test -n "$prev"; then
+ prev=
+ else
+ dest="$arg"
+ continue
+ fi
+ ;;
+ esac
+
+ # Aesthetically quote the argument.
+ arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`
+ case "$arg" in
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*)
+ arg="\"$arg\""
+ ;;
+ esac
+ install_prog="$install_prog $arg"
+ done
+
+ if test -z "$install_prog"; then
+ $echo "$modename: you must specify an install program" 1>&2
+ $echo "$help" 1>&2
+ exit 1
+ fi
+
+ if test -n "$prev"; then
+ $echo "$modename: the \`$prev' option requires an argument" 1>&2
+ $echo "$help" 1>&2
+ exit 1
+ fi
+
+ if test -z "$files"; then
+ if test -z "$dest"; then
+ $echo "$modename: no file or destination specified" 1>&2
+ else
+ $echo "$modename: you must specify a destination" 1>&2
+ fi
+ $echo "$help" 1>&2
+ exit 1
+ fi
+
+ # Strip any trailing slash from the destination.
+ dest=`$echo "X$dest" | $Xsed -e 's%/$%%'`
+
+ # Check to see that the destination is a directory.
+ test -d "$dest" && isdir=yes
+ if test "$isdir" = yes; then
+ destdir="$dest"
+ destname=
+ else
+ destdir=`$echo "X$dest" | $Xsed -e 's%/[^/]*$%%'`
+ test "X$destdir" = "X$dest" && destdir=.
+ destname=`$echo "X$dest" | $Xsed -e 's%^.*/%%'`
+
+ # Not a directory, so check to see that there is only one file specified.
+ set dummy $files
+ if test $# -gt 2; then
+ $echo "$modename: \`$dest' is not a directory" 1>&2
+ $echo "$help" 1>&2
+ exit 1
+ fi
+ fi
+ case "$destdir" in
+ [\\/]* | [A-Za-z]:[\\/]*) ;;
+ *)
+ for file in $files; do
+ case "$file" in
+ *.lo) ;;
+ *)
+ $echo "$modename: \`$destdir' must be an absolute directory name" 1>&2
+ $echo "$help" 1>&2
+ exit 1
+ ;;
+ esac
+ done
+ ;;
+ esac
+
+ # This variable tells wrapper scripts just to set variables rather
+ # than running their programs.
+ libtool_install_magic="$magic"
+
+ staticlibs=
+ future_libdirs=
+ current_libdirs=
+ for file in $files; do
+
+ # Do each installation.
+ case "$file" in
+ *.a | *.lib)
+ # Do the static libraries later.
+ staticlibs="$staticlibs $file"
+ ;;
+
+ *.la)
+ # Check to see that this really is a libtool archive.
+ if (sed -e '2q' $file | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then :
+ else
+ $echo "$modename: \`$file' is not a valid libtool archive" 1>&2
+ $echo "$help" 1>&2
+ exit 1
+ fi
+
+ library_names=
+ old_library=
+ # If there is no directory component, then add one.
+ case "$file" in
+ */* | *\\*) . $file ;;
+ *) . ./$file ;;
+ esac
+
+ # Add the libdir to current_libdirs if it is the destination.
+ if test "X$destdir" = "X$libdir"; then
+ case "$current_libdirs " in
+ *" $libdir "*) ;;
+ *) current_libdirs="$current_libdirs $libdir" ;;
+ esac
+ else
+ # Note the libdir as a future libdir.
+ case "$future_libdirs " in
+ *" $libdir "*) ;;
+ *) future_libdirs="$future_libdirs $libdir" ;;
+ esac
+ fi
+
+ dir="`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'`/"
+ test "X$dir" = "X$file/" && dir=
+ dir="$dir$objdir"
+
+ # See the names of the shared library.
+ set dummy $library_names
+ if test -n "$2"; then
+ realname="$2"
+ shift
+ shift
+
+ # Install the shared library and build the symlinks.
+ $show "$install_prog $dir/$realname $destdir/$realname"
+ $run eval "$install_prog $dir/$realname $destdir/$realname" || exit $?
+
+ if test $# -gt 0; then
+ # Delete the old symlinks, and create new ones.
+ for linkname
+ do
+ if test "$linkname" != "$realname"; then
+ $show "(cd $destdir && $rm $linkname && $LN_S $realname $linkname)"
+ $run eval "(cd $destdir && $rm $linkname && $LN_S $realname $linkname)"
+ fi
+ done
+ fi
+
+ # Do each command in the postinstall commands.
+ lib="$destdir/$realname"
+ eval cmds=\"$postinstall_cmds\"
+ IFS="${IFS= }"; save_ifs="$IFS"; IFS='~'
+ for cmd in $cmds; do
+ IFS="$save_ifs"
+ $show "$cmd"
+ $run eval "$cmd" || exit $?
+ done
+ IFS="$save_ifs"
+ fi
+
+ # Install the pseudo-library for information purposes.
+ name=`$echo "X$file" | $Xsed -e 's%^.*/%%'`
+ instname="$dir/$name"i
+ $show "$install_prog $instname $destdir/$name"
+ $run eval "$install_prog $instname $destdir/$name" || exit $?
+
+ # Maybe install the static library, too.
+ test -n "$old_library" && staticlibs="$staticlibs $dir/$old_library"
+ ;;
+
+ *.lo)
+ # Install (i.e. copy) a libtool object.
+
+ # Figure out destination file name, if it wasn't already specified.
+ if test -n "$destname"; then
+ destfile="$destdir/$destname"
+ else
+ destfile=`$echo "X$file" | $Xsed -e 's%^.*/%%'`
+ destfile="$destdir/$destfile"
+ fi
+
+ # Deduce the name of the destination old-style object file.
+ case "$destfile" in
+ *.lo)
+ staticdest=`$echo "X$destfile" | $Xsed -e "$lo2o"`
+ ;;
+ *.o | *.obj)
+ staticdest="$destfile"
+ destfile=
+ ;;
+ *)
+ $echo "$modename: cannot copy a libtool object to \`$destfile'" 1>&2
+ $echo "$help" 1>&2
+ exit 1
+ ;;
+ esac
+
+ # Install the libtool object if requested.
+ if test -n "$destfile"; then
+ $show "$install_prog $file $destfile"
+ $run eval "$install_prog $file $destfile" || exit $?
+ fi
+
+ # Install the old object if enabled.
+ if test "$build_old_libs" = yes; then
+ # Deduce the name of the old-style object file.
+ staticobj=`$echo "X$file" | $Xsed -e "$lo2o"`
+
+ $show "$install_prog $staticobj $staticdest"
+ $run eval "$install_prog \$staticobj \$staticdest" || exit $?
+ fi
+ exit 0
+ ;;
+
+ *)
+ # Figure out destination file name, if it wasn't already specified.
+ if test -n "$destname"; then
+ destfile="$destdir/$destname"
+ else
+ destfile=`$echo "X$file" | $Xsed -e 's%^.*/%%'`
+ destfile="$destdir/$destfile"
+ fi
+
+ # Do a test to see if this is really a libtool program.
+ if (sed -e '4q' $file | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then
+ link_against_libtool_libs=
+ relink_command=
+
+ # If there is no directory component, then add one.
+ case "$file" in
+ */* | *\\*) . $file ;;
+ *) . ./$file ;;
+ esac
+
+ # Check the variables that should have been set.
+ if test -z "$link_against_libtool_libs"; then
+ $echo "$modename: invalid libtool wrapper script \`$file'" 1>&2
+ exit 1
+ fi
+
+ finalize=yes
+ for lib in $link_against_libtool_libs; do
+ # Check to see that each library is installed.
+ libdir=
+ if test -f "$lib"; then
+ # If there is no directory component, then add one.
+ case "$lib" in
+ */* | *\\*) . $lib ;;
+ *) . ./$lib ;;
+ esac
+ fi
+ libfile="$libdir/`$echo "X$lib" | $Xsed -e 's%^.*/%%g'`"
+ if test -n "$libdir" && test ! -f "$libfile"; then
+ $echo "$modename: warning: \`$lib' has not been installed in \`$libdir'" 1>&2
+ finalize=no
+ fi
+ done
+
+ outputname=
+ if test "$fast_install" = no && test -n "$relink_command"; then
+ if test "$finalize" = yes && test -z "$run"; then
+ tmpdir="/tmp"
+ test -n "$TMPDIR" && tmpdir="$TMPDIR"
+ tmpdir="$tmpdir/libtool-$$"
+ if $mkdir -p "$tmpdir" && chmod 700 "$tmpdir"; then :
+ else
+ $echo "$modename: error: cannot create temporary directory \`$tmpdir'" 1>&2
+ continue
+ fi
+ outputname="$tmpdir/$file"
+ # Replace the output file specification.
+ relink_command=`$echo "X$relink_command" | $Xsed -e 's%@OUTPUT@%'"$outputname"'%g'`
+
+ $show "$relink_command"
+ if $run eval "$relink_command"; then :
+ else
+ $echo "$modename: error: relink \`$file' with the above command before installing it" 1>&2
+ ${rm}r "$tmpdir"
+ continue
+ fi
+ file="$outputname"
+ else
+ $echo "$modename: warning: cannot relink \`$file'" 1>&2
+ fi
+ else
+ # Install the binary that we compiled earlier.
+ file=`$echo "X$file" | $Xsed -e "s%\([^/]*\)$%$objdir/\1%"`
+ fi
+ fi
+
+ $show "$install_prog$stripme $file $destfile"
+ $run eval "$install_prog\$stripme \$file \$destfile" || exit $?
+ test -n "$outputname" && ${rm}r "$tmpdir"
+ ;;
+ esac
+ done
+
+ for file in $staticlibs; do
+ name=`$echo "X$file" | $Xsed -e 's%^.*/%%'`
+
+ # Set up the ranlib parameters.
+ oldlib="$destdir/$name"
+
+ $show "$install_prog $file $oldlib"
+ $run eval "$install_prog \$file \$oldlib" || exit $?
+
+ # Do each command in the postinstall commands.
+ eval cmds=\"$old_postinstall_cmds\"
+ IFS="${IFS= }"; save_ifs="$IFS"; IFS='~'
+ for cmd in $cmds; do
+ IFS="$save_ifs"
+ $show "$cmd"
+ $run eval "$cmd" || exit $?
+ done
+ IFS="$save_ifs"
+ done
+
+ if test -n "$future_libdirs"; then
+ $echo "$modename: warning: remember to run \`$progname --finish$future_libdirs'" 1>&2
+ fi
+
+ if test -n "$current_libdirs"; then
+ # Maybe just do a dry run.
+ test -n "$run" && current_libdirs=" -n$current_libdirs"
+ exec $SHELL $0 --finish$current_libdirs
+ exit 1
+ fi
+
+ exit 0
+ ;;
+
+ # libtool finish mode
+ finish)
+ modename="$modename: finish"
+ libdirs="$nonopt"
+ admincmds=
+
+ if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then
+ for dir
+ do
+ libdirs="$libdirs $dir"
+ done
+
+ for libdir in $libdirs; do
+ if test -n "$finish_cmds"; then
+ # Do each command in the finish commands.
+ eval cmds=\"$finish_cmds\"
+ IFS="${IFS= }"; save_ifs="$IFS"; IFS='~'
+ for cmd in $cmds; do
+ IFS="$save_ifs"
+ $show "$cmd"
+ $run eval "$cmd" || admincmds="$admincmds
+ $cmd"
+ done
+ IFS="$save_ifs"
+ fi
+ if test -n "$finish_eval"; then
+ # Do the single finish_eval.
+ eval cmds=\"$finish_eval\"
+ $run eval "$cmds" || admincmds="$admincmds
+ $cmds"
+ fi
+ done
+ fi
+
+ # Exit here if they wanted silent mode.
+ test "$show" = : && exit 0
+
+ echo "----------------------------------------------------------------------"
+ echo "Libraries have been installed in:"
+ for libdir in $libdirs; do
+ echo " $libdir"
+ done
+ echo
+ echo "If you ever happen to want to link against installed libraries"
+ echo "in a given directory, LIBDIR, you must either use libtool, and"
+ echo "specify the full pathname of the library, or use \`-LLIBDIR'"
+ echo "flag during linking and do at least one of the following:"
+ if test -n "$shlibpath_var"; then
+ echo " - add LIBDIR to the \`$shlibpath_var' environment variable"
+ echo " during execution"
+ fi
+ if test -n "$runpath_var"; then
+ echo " - add LIBDIR to the \`$runpath_var' environment variable"
+ echo " during linking"
+ fi
+ if test -n "$hardcode_libdir_flag_spec"; then
+ libdir=LIBDIR
+ eval flag=\"$hardcode_libdir_flag_spec\"
+
+ echo " - use the \`$flag' linker flag"
+ fi
+ if test -n "$admincmds"; then
+ echo " - have your system administrator run these commands:$admincmds"
+ fi
+ if test -f /etc/ld.so.conf; then
+ echo " - have your system administrator add LIBDIR to \`/etc/ld.so.conf'"
+ fi
+ echo
+ echo "See any operating system documentation about shared libraries for"
+ echo "more information, such as the ld(1) and ld.so(8) manual pages."
+ echo "----------------------------------------------------------------------"
+ exit 0
+ ;;
+
+ # libtool execute mode
+ execute)
+ modename="$modename: execute"
+
+ # The first argument is the command name.
+ cmd="$nonopt"
+ if test -z "$cmd"; then
+ $echo "$modename: you must specify a COMMAND" 1>&2
+ $echo "$help"
+ exit 1
+ fi
+
+ # Handle -dlopen flags immediately.
+ for file in $execute_dlfiles; do
+ if test ! -f "$file"; then
+ $echo "$modename: \`$file' is not a file" 1>&2
+ $echo "$help" 1>&2
+ exit 1
+ fi
+
+ dir=
+ case "$file" in
+ *.la)
+ # Check to see that this really is a libtool archive.
+ if (sed -e '2q' $file | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then :
+ else
+ $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2
+ $echo "$help" 1>&2
+ exit 1
+ fi
+
+ # Read the libtool library.
+ dlname=
+ library_names=
+
+ # If there is no directory component, then add one.
+ case "$file" in
+ */* | *\\*) . $file ;;
+ *) . ./$file ;;
+ esac
+
+ # Skip this library if it cannot be dlopened.
+ if test -z "$dlname"; then
+ # Warn if it was a shared library.
+ test -n "$library_names" && $echo "$modename: warning: \`$file' was not linked with \`-export-dynamic'"
+ continue
+ fi
+
+ dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'`
+ test "X$dir" = "X$file" && dir=.
+
+ if test -f "$dir/$objdir/$dlname"; then
+ dir="$dir/$objdir"
+ else
+ $echo "$modename: cannot find \`$dlname' in \`$dir' or \`$dir/$objdir'" 1>&2
+ exit 1
+ fi
+ ;;
+
+ *.lo)
+ # Just add the directory containing the .lo file.
+ dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'`
+ test "X$dir" = "X$file" && dir=.
+ ;;
+
+ *)
+ $echo "$modename: warning \`-dlopen' is ignored for non-libtool libraries and objects" 1>&2
+ continue
+ ;;
+ esac
+
+ # Get the absolute pathname.
+ absdir=`cd "$dir" && pwd`
+ test -n "$absdir" && dir="$absdir"
+
+ # Now add the directory to shlibpath_var.
+ if eval "test -z \"\$$shlibpath_var\""; then
+ eval "$shlibpath_var=\"\$dir\""
+ else
+ eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\""
+ fi
+ done
+
+ # This variable tells wrapper scripts just to set shlibpath_var
+ # rather than running their programs.
+ libtool_execute_magic="$magic"
+
+ # Check if any of the arguments is a wrapper script.
+ args=
+ for file
+ do
+ case "$file" in
+ -*) ;;
+ *)
+ # Do a test to see if this is really a libtool program.
+ if (sed -e '4q' $file | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then
+ # If there is no directory component, then add one.
+ case "$file" in
+ */* | *\\*) . $file ;;
+ *) . ./$file ;;
+ esac
+
+ # Transform arg to wrapped name.
+ file="$progdir/$program"
+ fi
+ ;;
+ esac
+ # Quote arguments (to preserve shell metacharacters).
+ file=`$echo "X$file" | $Xsed -e "$sed_quote_subst"`
+ args="$args \"$file\""
+ done
+
+ if test -z "$run"; then
+ # Export the shlibpath_var.
+ eval "export $shlibpath_var"
+
+ # Restore saved enviroment variables
+ if test "${save_LC_ALL+set}" = set; then
+ LC_ALL="$save_LC_ALL"; export LC_ALL
+ fi
+ if test "${save_LANG+set}" = set; then
+ LANG="$save_LANG"; export LANG
+ fi
+
+ # Now actually exec the command.
+ eval "exec \$cmd$args"
+
+ $echo "$modename: cannot exec \$cmd$args"
+ exit 1
+ else
+ # Display what would be done.
+ eval "\$echo \"\$shlibpath_var=\$$shlibpath_var\""
+ $echo "export $shlibpath_var"
+ $echo "$cmd$args"
+ exit 0
+ fi
+ ;;
+
+ # libtool uninstall mode
+ uninstall)
+ modename="$modename: uninstall"
+ rm="$nonopt"
+ files=
+
+ for arg
+ do
+ case "$arg" in
+ -*) rm="$rm $arg" ;;
+ *) files="$files $arg" ;;
+ esac
+ done
+
+ if test -z "$rm"; then
+ $echo "$modename: you must specify an RM program" 1>&2
+ $echo "$help" 1>&2
+ exit 1
+ fi
+
+ for file in $files; do
+ dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'`
+ test "X$dir" = "X$file" && dir=.
+ name=`$echo "X$file" | $Xsed -e 's%^.*/%%'`
+
+ rmfiles="$file"
+
+ case "$name" in
+ *.la)
+ # Possibly a libtool archive, so verify it.
+ if (sed -e '2q' $file | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then
+ . $dir/$name
+
+ # Delete the libtool libraries and symlinks.
+ for n in $library_names; do
+ rmfiles="$rmfiles $dir/$n"
+ done
+ test -n "$old_library" && rmfiles="$rmfiles $dir/$old_library"
+
+ $show "$rm $rmfiles"
+ $run $rm $rmfiles
+
+ if test -n "$library_names"; then
+ # Do each command in the postuninstall commands.
+ eval cmds=\"$postuninstall_cmds\"
+ IFS="${IFS= }"; save_ifs="$IFS"; IFS='~'
+ for cmd in $cmds; do
+ IFS="$save_ifs"
+ $show "$cmd"
+ $run eval "$cmd"
+ done
+ IFS="$save_ifs"
+ fi
+
+ if test -n "$old_library"; then
+ # Do each command in the old_postuninstall commands.
+ eval cmds=\"$old_postuninstall_cmds\"
+ IFS="${IFS= }"; save_ifs="$IFS"; IFS='~'
+ for cmd in $cmds; do
+ IFS="$save_ifs"
+ $show "$cmd"
+ $run eval "$cmd"
+ done
+ IFS="$save_ifs"
+ fi
+
+ # FIXME: should reinstall the best remaining shared library.
+ fi
+ ;;
+
+ *.lo)
+ if test "$build_old_libs" = yes; then
+ oldobj=`$echo "X$name" | $Xsed -e "$lo2o"`
+ rmfiles="$rmfiles $dir/$oldobj"
+ fi
+ $show "$rm $rmfiles"
+ $run $rm $rmfiles
+ ;;
+
+ *)
+ $show "$rm $rmfiles"
+ $run $rm $rmfiles
+ ;;
+ esac
+ done
+ exit 0
+ ;;
+
+ "")
+ $echo "$modename: you must specify a MODE" 1>&2
+ $echo "$generic_help" 1>&2
+ exit 1
+ ;;
+ esac
+
+ $echo "$modename: invalid operation mode \`$mode'" 1>&2
+ $echo "$generic_help" 1>&2
+ exit 1
+fi # test -z "$show_help"
+
+# We need to display help for each of the modes.
+case "$mode" in
+"") $echo \
+"Usage: $modename [OPTION]... [MODE-ARG]...
+
+Provide generalized library-building support services.
+
+ --config show all configuration variables
+ --debug enable verbose shell tracing
+-n, --dry-run display commands without modifying any files
+ --features display basic configuration information and exit
+ --finish same as \`--mode=finish'
+ --help display this help message and exit
+ --mode=MODE use operation mode MODE [default=inferred from MODE-ARGS]
+ --quiet same as \`--silent'
+ --silent don't print informational messages
+ --version print version information
+
+MODE must be one of the following:
+
+ compile compile a source file into a libtool object
+ execute automatically set library path, then run a program
+ finish complete the installation of libtool libraries
+ install install libraries or executables
+ link create a library or an executable
+ uninstall remove libraries from an installed directory
+
+MODE-ARGS vary depending on the MODE. Try \`$modename --help --mode=MODE' for
+a more detailed description of MODE."
+ exit 0
+ ;;
+
+compile)
+ $echo \
+"Usage: $modename [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE
+
+Compile a source file into a libtool library object.
+
+This mode accepts the following additional options:
+
+ -o OUTPUT-FILE set the output file name to OUTPUT-FILE
+ -static always build a \`.o' file suitable for static linking
+
+COMPILE-COMMAND is a command to be used in creating a \`standard' object file
+from the given SOURCEFILE.
+
+The output file name is determined by removing the directory component from
+SOURCEFILE, then substituting the C source code suffix \`.c' with the
+library object suffix, \`.lo'."
+ ;;
+
+execute)
+ $echo \
+"Usage: $modename [OPTION]... --mode=execute COMMAND [ARGS]...
+
+Automatically set library path, then run a program.
+
+This mode accepts the following additional options:
+
+ -dlopen FILE add the directory containing FILE to the library path
+
+This mode sets the library path environment variable according to \`-dlopen'
+flags.
+
+If any of the ARGS are libtool executable wrappers, then they are translated
+into their corresponding uninstalled binary, and any of their required library
+directories are added to the library path.
+
+Then, COMMAND is executed, with ARGS as arguments."
+ ;;
+
+finish)
+ $echo \
+"Usage: $modename [OPTION]... --mode=finish [LIBDIR]...
+
+Complete the installation of libtool libraries.
+
+Each LIBDIR is a directory that contains libtool libraries.
+
+The commands that this mode executes may require superuser privileges. Use
+the \`--dry-run' option if you just want to see what would be executed."
+ ;;
+
+install)
+ $echo \
+"Usage: $modename [OPTION]... --mode=install INSTALL-COMMAND...
+
+Install executables or libraries.
+
+INSTALL-COMMAND is the installation command. The first component should be
+either the \`install' or \`cp' program.
+
+The rest of the components are interpreted as arguments to that command (only
+BSD-compatible install options are recognized)."
+ ;;
+
+link)
+ $echo \
+"Usage: $modename [OPTION]... --mode=link LINK-COMMAND...
+
+Link object files or libraries together to form another library, or to
+create an executable program.
+
+LINK-COMMAND is a command using the C compiler that you would use to create
+a program from several object files.
+
+The following components of LINK-COMMAND are treated specially:
+
+ -all-static do not do any dynamic linking at all
+ -avoid-version do not add a version suffix if possible
+ -dlopen FILE \`-dlpreopen' FILE if it cannot be dlopened at runtime
+ -dlpreopen FILE link in FILE and add its symbols to lt_preloaded_symbols
+ -export-dynamic allow symbols from OUTPUT-FILE to be resolved with dlsym(3)
+ -export-symbols SYMFILE
+ try to export only the symbols listed in SYMFILE
+ -export-symbols-regex REGEX
+ try to export only the symbols matching REGEX
+ -LLIBDIR search LIBDIR for required installed libraries
+ -lNAME OUTPUT-FILE requires the installed library libNAME
+ -module build a library that can dlopened
+ -no-undefined declare that a library does not refer to external symbols
+ -o OUTPUT-FILE create OUTPUT-FILE from the specified objects
+ -release RELEASE specify package release information
+ -rpath LIBDIR the created library will eventually be installed in LIBDIR
+ -R[ ]LIBDIR add LIBDIR to the runtime path of programs and libraries
+ -static do not do any dynamic linking of libtool libraries
+ -version-info CURRENT[:REVISION[:AGE]]
+ specify library version info [each variable defaults to 0]
+
+All other options (arguments beginning with \`-') are ignored.
+
+Every other argument is treated as a filename. Files ending in \`.la' are
+treated as uninstalled libtool libraries, other files are standard or library
+object files.
+
+If the OUTPUT-FILE ends in \`.la', then a libtool library is created,
+only library objects (\`.lo' files) may be specified, and \`-rpath' is
+required, except when creating a convenience library.
+
+If OUTPUT-FILE ends in \`.a' or \`.lib', then a standard library is created
+using \`ar' and \`ranlib', or on Windows using \`lib'.
+
+If OUTPUT-FILE ends in \`.lo' or \`.${objext}', then a reloadable object file
+is created, otherwise an executable program is created."
+ ;;
+
+uninstall)
+ $echo \
+"Usage: $modename [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE...
+
+Remove libraries from an installation directory.
+
+RM is the name of the program to use to delete files associated with each FILE
+(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed
+to RM.
+
+If FILE is a libtool library, all the files associated with it are deleted.
+Otherwise, only FILE itself is deleted using RM."
+ ;;
+
+*)
+ $echo "$modename: invalid operation mode \`$mode'" 1>&2
+ $echo "$help" 1>&2
+ exit 1
+ ;;
+esac
+
+echo
+$echo "Try \`$modename --help' for more information about other modes."
+
+exit 0
+
+# Local Variables:
+# mode:shell-script
+# sh-indentation:2
+# End:
diff --git a/man/.cvsignore b/man/.cvsignore
new file mode 100644
index 00000000000..282522db034
--- /dev/null
+++ b/man/.cvsignore
@@ -0,0 +1,2 @@
+Makefile
+Makefile.in
diff --git a/man/Makefile.am b/man/Makefile.am
new file mode 100644
index 00000000000..9e5c4f707ef
--- /dev/null
+++ b/man/Makefile.am
@@ -0,0 +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,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Library General Public License for more details.
+#
+# You should 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
+
+man_MANS = mysql.1
+
+EXTRA_DIST = $(man_MANS)
diff --git a/man/mysql.1 b/man/mysql.1
new file mode 100644
index 00000000000..e0b77363a82
--- /dev/null
+++ b/man/mysql.1
@@ -0,0 +1,143 @@
+.TH MYSQL 1 "13 June 1997"
+.SH NAME
+mysql \- text-based client for mysqld, a SQL-based relational database daemon
+.SH SYNOPSIS
+.B mysql
+.RB [ \-B | \-\-batch ]
+.RB [ \-# | \-\-debug=
+.IR logfile ]
+.RB [ \-T | \-\-debug-info ]
+.RB [ \-e | \-\-exec=
+.IR command ]
+.RB [ \-f | \-\-force ]
+.RB [ \-? | \-\-help ]
+.RB [ \-h | \-\-host=
+.IR hostname ]
+.RB [ \-n | \-\-unbuffered ]
+.RB [ \-p[pwd] ]
+.RI [ \-\-password=[pwd] ]
+.RB [ \-P | \-\-port=
+.IR pnum ]
+.RB [ \-q | \-\-quick ]
+.RB [ \-r | \-\-raw ]
+.RB [ \-s | \-\-silent ]
+.RB [ \-S | \-\-socket=
+.IR snum ]
+.RB [ \-u | \-\-user=
+.IR uname ]
+.RB [ \-v | \-\-verbose ]
+.RB [ \-V | \-\-version ]
+.RB [ \-w | \-\-wait ]
+.SH DESCRIPTION
+The
+.IR mysql
+program provides a curses-based interface to the SQL-based database
+server daemon,
+.IR mysqld (1).
+Full fuller documentation, refer to the HTML documents installed with
+the package.
+.SH OPTIONS
+.TP
+.BR \-B | \-\-batch
+Print results with a tab as separator,
+each row on a new line.
+.TP
+\fB\-#\fP|\fB\-\-debug=\fP\fIlogfile\fP
+Employ the specified debug log.
+.TP
+.BR \-T | \-\-debug-info
+Print debug information upon exiting.
+.TP
+\fB\-e | \-\-exec=\fP\fPcommand\fP
+Execute the specified command and quit
+.BR ( \-\-batch
+is implicit).
+.TP
+.BR \-f | \-\-force
+Continue even if the face of a SQL error.
+.TP
+.BR \-? | \-\-help
+Display a help message and exit.
+.TP
+\fB\-h\fP|\fP\-\-host=\fP\fIhostname\fP
+Connect to the specified host.
+.TP
+.BR \-n | \-\-unbuffered
+Flush the buffer after each query.
+.TP
+\fB\-p\fP|\fB\-\-password\fP[\fB=\fP\fIpwd\fP]
+Employ the specified password when connecting to the database server.
+If a password is not supplied, it will be requested interactively.
+.TP
+\fB\-P\fR|\fB\-\-port=\fP\fIpnum\fP
+Employ the specified port number for connecting to the database server.
+.TP
+.BR \-q | \-\-quick
+Do not cache the result; print it row by row.
+This may slow down the server if the output is suspended.
+.TP
+.BR \-r | \-\-raw
+Write fields without conversion.
+(used with
+.BR \-\-batch ).
+.TP
+.BR \-s | \-\-silent
+Silent mode: reduce the amount of output.
+.TP
+\fB\-S\fP|\fB\-\-socket=\fP\fIsnum\fP
+Employ the specified socket file for connecting to the database server.
+.TP
+\fB\-u\fP|\fB\-\-user=\fP\fIuname\fP
+Employ the specified user name for logging in to the server.
+.TP
+.BR \-v | \-\-verbose
+Verbose mode: write more
+Specifying this option
+.I twice
+produces a tabular output format.
+.TP
+.BR \-V | \-\-version
+Print the
+.I mysql
+version number and exit.
+.TP
+.BR \-w | \-\-wait
+Wait and retry if the database server connection is down.
+.SH FILES
+.TP 2.2i
+.I /depot/bin/mysql
+executable
+.TP
+.I /depot/bin/mysqld
+executable
+.TP
+.I /depot/bin/safe_mysqld
+executable shell script for starting mysqld safely
+.TP
+.I /site/var/mysql/data
+location of database files
+.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),
+.SH AUTHOR
+Ver 6.3, distribution 3.20.20
+Michael (Monty) Widenius (monty@tcx.se),
+TCX Datakonsult AB (http://www.tcx.se).
+This software comes with no warranty.
+Manual page by R. P. C. Rodgers,
+Lister Hill National Center for Biomedical Communication,
+U.S. National Library of Medicine
+(rodgers@nlm.nih.gov).
+.\" end of man page
diff --git a/merge/.cvsignore b/merge/.cvsignore
new file mode 100644
index 00000000000..e9955884756
--- /dev/null
+++ b/merge/.cvsignore
@@ -0,0 +1,3 @@
+.deps
+Makefile
+Makefile.in
diff --git a/merge/Makefile.am b/merge/Makefile.am
new file mode 100644
index 00000000000..84e23f7cdb0
--- /dev/null
+++ b/merge/Makefile.am
@@ -0,0 +1,31 @@
+# Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+INCLUDES = @MT_INCLUDES@ -I$(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
+
+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
diff --git a/merge/_locking.c b/merge/_locking.c
new file mode 100644
index 00000000000..f90b41e2375
--- /dev/null
+++ b/merge/_locking.c
@@ -0,0 +1,35 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/*
+ Lock databases against read or write.
+*/
+
+#include "mrgdef.h"
+
+int mrg_lock_database(info,lock_type)
+MRG_INFO *info;
+int lock_type;
+{
+ int error,new_error;
+ MRG_TABLE *file;
+
+ error=0;
+ for (file=info->open_tables ; file != info->end_table ; file++)
+ if ((new_error=nisam_lock_database(file->table,lock_type)))
+ error=new_error;
+ return(error);
+}
diff --git a/merge/close.c b/merge/close.c
new file mode 100644
index 00000000000..45aa889ef0c
--- /dev/null
+++ b/merge/close.c
@@ -0,0 +1,41 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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"
+
+int mrg_close(info)
+register MRG_INFO *info;
+{
+ int error=0,new_error;
+ MRG_TABLE *file;
+ DBUG_ENTER("mrg_close");
+
+ for (file=info->open_tables ; file != info->end_table ; file++)
+ if ((new_error=nisam_close(file->table)))
+ error=new_error;
+ pthread_mutex_lock(&THR_LOCK_open);
+ mrg_open_list=list_delete(mrg_open_list,&info->open_list);
+ pthread_mutex_unlock(&THR_LOCK_open);
+ my_free((gptr) info,MYF(0));
+ if (error)
+ {
+ my_errno=error;
+ DBUG_RETURN(-1);
+ }
+ DBUG_RETURN(0);
+}
diff --git a/merge/create.c b/merge/create.c
new file mode 100644
index 00000000000..e7086210237
--- /dev/null
+++ b/merge/create.c
@@ -0,0 +1,62 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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"
+
+ /* create file named 'name' and save filenames in it
+ table_names should be NULL or a vector of string-pointers with
+ a NULL-pointer last
+ */
+
+int mrg_create(name,table_names)
+const char *name,**table_names;
+{
+ int save_errno;
+ uint errpos;
+ File file;
+ char buff[FN_REFLEN],*end;
+ DBUG_ENTER("mrg_create");
+
+ errpos=0;
+ if ((file = my_create(fn_format(buff,name,"",MRG_NAME_EXT,4),0,
+ O_RDWR | O_TRUNC,MYF(MY_WME))) < 0)
+ goto err;
+ errpos=1;
+ if (table_names)
+ for ( ; *table_names ; table_names++)
+ {
+ strmov(buff,*table_names);
+ fn_same(buff,name,4);
+ *(end=strend(buff))='\n';
+ if (my_write(file,*table_names,(uint) (end-buff+1),
+ MYF(MY_WME | MY_NABP)))
+ goto err;
+ }
+ if (my_close(file,MYF(0)))
+ goto err;
+ DBUG_RETURN(0);
+
+err:
+ save_errno=my_errno;
+ switch (errpos) {
+ case 1:
+ VOID(my_close(file,MYF(0)));
+ }
+ my_errno=save_errno; /* Return right errocode */
+ DBUG_RETURN(-1);
+} /* mrg_create */
diff --git a/merge/delete.c b/merge/delete.c
new file mode 100644
index 00000000000..a4ee46eedc2
--- /dev/null
+++ b/merge/delete.c
@@ -0,0 +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 */
+
+/* Delete last read record */
+
+#include "mrgdef.h"
+
+int mrg_delete(MRG_INFO *info,const byte *record)
+{
+ if (!info->current_table)
+ {
+ my_errno=HA_ERR_NO_ACTIVE_RECORD;
+ return(-1);
+ }
+ return nisam_delete(info->current_table->table,record);
+}
diff --git a/merge/extra.c b/merge/extra.c
new file mode 100644
index 00000000000..c20241228a2
--- /dev/null
+++ b/merge/extra.c
@@ -0,0 +1,46 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/*
+ Extra functions we want to do with a database
+ - All flags, exept record-cache-flags, are set in all used databases
+ record-cache-flags are set in mrg_rrnd when we are changing database.
+*/
+
+#include "mrgdef.h"
+
+int mrg_extra(info,function)
+MRG_INFO *info;
+enum ha_extra_function function;
+{
+ MRG_TABLE *file;
+
+ if (function == HA_EXTRA_CACHE)
+ info->cache_in_use=1;
+ else
+ {
+ if (function == HA_EXTRA_NO_CACHE)
+ info->cache_in_use=0;
+ if (function == HA_EXTRA_RESET)
+ {
+ info->current_table=0;
+ info->last_used_table=info->open_tables;
+ }
+ for (file=info->open_tables ; file != info->end_table ; file++)
+ nisam_extra(file->table,function);
+ }
+ return 0;
+}
diff --git a/merge/info.c b/merge/info.c
new file mode 100644
index 00000000000..d44ada8e6e6
--- /dev/null
+++ b/merge/info.c
@@ -0,0 +1,60 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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"
+
+ulong mrg_position(MRG_INFO *info)
+{
+ MRG_TABLE *current_table;
+
+ if (!(current_table = info->current_table) &&
+ info->open_tables != info->end_table)
+ current_table = info->open_tables;
+ return (current_table ?
+ (ulong) (current_table->table->lastpos +
+ current_table->file_offset) :
+ ~(ulong) 0);
+}
+
+ /* If flag != 0 one only gets pos of last record */
+
+int mrg_info(MRG_INFO *info,register MERGE_INFO *x,int flag)
+{
+ MRG_TABLE *current_table;
+ DBUG_ENTER("mrg_info");
+
+ if (!(current_table = info->current_table) &&
+ info->open_tables != info->end_table)
+ current_table = info->open_tables;
+ x->recpos = info->current_table ?
+ info->current_table->table->lastpos + info->current_table->file_offset :
+ (ulong) -1L;
+ if (flag != HA_STATUS_POS)
+ {
+ x->records = info->records;
+ x->deleted = info->del;
+ x->data_file_length = info->data_file_length;
+ x->reclength = info->reclength;
+ if (current_table)
+ x->errkey = current_table->table->errkey;
+ else
+ { /* No tables in MRG */
+ x->errkey=0;
+ }
+ x->options = info->options;
+ }
+ DBUG_RETURN(0);
+}
diff --git a/merge/make-ccc b/merge/make-ccc
new file mode 100755
index 00000000000..3f37c33638f
--- /dev/null
+++ b/merge/make-ccc
@@ -0,0 +1,3 @@
+ccc -I./../include -I../include -DDBUG_OFF -fast -O3 -c _locking.c close.c create.c delete.c extra.c info.c open.c panic.c rrnd.c rsame.c static.c update.c
+rm libmerge.a
+ar -cr libmerge.a _locking.o
diff --git a/merge/mrgdef.h b/merge/mrgdef.h
new file mode 100644
index 00000000000..3f22c83589a
--- /dev/null
+++ b/merge/mrgdef.h
@@ -0,0 +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 */
+
+/* Denna fil includeras i alla merge-filer */
+
+#ifndef N_MAXKEY
+#include "../isam/isamdef.h"
+#endif
+
+#include "merge.h"
+
+extern LIST *mrg_open_list;
+
+#ifdef THREAD
+extern pthread_mutex_t THR_LOCK_open;
+#endif
diff --git a/merge/open.c b/merge/open.c
new file mode 100644
index 00000000000..18d3b53fa84
--- /dev/null
+++ b/merge/open.c
@@ -0,0 +1,138 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 <stddef.h>
+#include <errno.h>
+#ifdef VMS
+#include "static.c"
+#endif
+
+/* open a MERGE-database.
+
+ if handle_locking is 0 then exit with error if some database is locked
+ if handle_locking is 1 then wait if database is locked
+*/
+
+
+MRG_INFO *mrg_open(name,mode,handle_locking)
+const char *name;
+int mode;
+int handle_locking;
+{
+ int save_errno,i,errpos;
+ uint files,dir_length;
+ ulonglong file_offset;
+ char name_buff[FN_REFLEN*2],buff[FN_REFLEN],*end;
+ MRG_INFO info,*m_info;
+ FILE *file;
+ N_INFO *isam,*last_isam;
+ DBUG_ENTER("mrg_open");
+
+ LINT_INIT(last_isam);
+ isam=0;
+ errpos=files=0;
+ bzero((gptr) &info,sizeof(info));
+ if (!(file=my_fopen(fn_format(name_buff,name,"",MRG_NAME_EXT,4),
+ O_RDONLY | O_SHARE,MYF(0))))
+ goto err;
+ errpos=1;
+ dir_length=dirname_part(name_buff,name);
+ info.reclength=0;
+ while (fgets(buff,FN_REFLEN-1,file))
+ {
+ if ((end=strend(buff))[-1] == '\n')
+ end[-1]='\0';
+ if (buff[0]) /* Skipp empty lines */
+ {
+ last_isam=isam;
+ if (!test_if_hard_path(buff))
+ {
+ VOID(strmake(name_buff+dir_length,buff,
+ sizeof(name_buff)-1-dir_length));
+ VOID(cleanup_dirname(buff,name_buff));
+ }
+ if (!(isam=nisam_open(buff,mode,test(handle_locking))))
+ goto err;
+ files++;
+ }
+ last_isam=isam;
+ if (info.reclength && info.reclength != isam->s->base.reclength)
+ {
+ my_errno=HA_ERR_WRONG_IN_RECORD;
+ goto err;
+ }
+ info.reclength=isam->s->base.reclength;
+ }
+ if (!(m_info= (MRG_INFO*) my_malloc(sizeof(MRG_INFO)+files*sizeof(MRG_TABLE),
+ MYF(MY_WME))))
+ goto err;
+ *m_info=info;
+ m_info->open_tables=(MRG_TABLE *) (m_info+1);
+ m_info->tables=files;
+
+ for (i=files ; i-- > 0 ; )
+ {
+ m_info->open_tables[i].table=isam;
+ m_info->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);
+ }
+ /* Fix fileinfo for easyer debugging (actually set by rrnd) */
+ file_offset=0;
+ for (i=0 ; (uint) i < files ; i++)
+ {
+ m_info->open_tables[i].file_offset=(my_off_t) file_offset;
+ file_offset+=m_info->open_tables[i].table->s->state.data_file_length;
+ }
+ if (sizeof(my_off_t) == 4 && file_offset > (ulonglong) (ulong) ~0L)
+ {
+ my_errno=HA_ERR_RECORD_FILE_FULL;
+ my_free((char*) m_info,MYF(0));
+ goto err;
+ }
+
+ m_info->end_table=m_info->open_tables+files;
+ m_info->last_used_table=m_info->open_tables;
+
+ VOID(my_fclose(file,MYF(0)));
+ m_info->open_list.data=(void*) m_info;
+ pthread_mutex_lock(&THR_LOCK_open);
+ mrg_open_list=list_add(mrg_open_list,&m_info->open_list);
+ pthread_mutex_unlock(&THR_LOCK_open);
+ DBUG_RETURN(m_info);
+
+err:
+ save_errno=my_errno;
+ switch (errpos) {
+ case 1:
+ VOID(my_fclose(file,MYF(0)));
+ for (i=files ; i-- > 0 ; )
+ {
+ isam=last_isam;
+ if (i)
+ last_isam=(N_INFO*) (isam->open_list.next->data);
+ nisam_close(isam);
+ }
+ }
+ my_errno=save_errno;
+ DBUG_RETURN (NULL);
+}
diff --git a/merge/panic.c b/merge/panic.c
new file mode 100644
index 00000000000..c3820fe468d
--- /dev/null
+++ b/merge/panic.c
@@ -0,0 +1,47 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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"
+
+ /* if flag == HA_PANIC_CLOSE then all misam files are closed */
+ /* if flag == HA_PANIC_WRITE then all misam files are unlocked and
+ all changed data in single user misam is written to file */
+ /* if flag == HA_PANIC_READ then all misam files that was locked when
+ nisam_panic(HA_PANIC_WRITE) was done is locked. A ni_readinfo() is
+ done for all single user files to get changes in database */
+
+
+int mrg_panic(flag)
+enum ha_panic_function flag;
+{
+ int error=0;
+ LIST *list_element,*next_open;
+ MRG_INFO *info;
+ DBUG_ENTER("mrg_panic");
+
+ for (list_element=mrg_open_list ; list_element ; list_element=next_open)
+ {
+ next_open=list_element->next; /* Save if close */
+ info=(MRG_INFO*) list_element->data;
+ if (flag == HA_PANIC_CLOSE && mrg_close(info))
+ error=my_errno;
+ }
+ if (mrg_open_list && flag != HA_PANIC_CLOSE)
+ DBUG_RETURN(nisam_panic(flag));
+ if (!error) DBUG_RETURN(0);
+ my_errno=error;
+ DBUG_RETURN(-1);
+}
diff --git a/merge/rrnd.c b/merge/rrnd.c
new file mode 100644
index 00000000000..15a50c0b89f
--- /dev/null
+++ b/merge/rrnd.c
@@ -0,0 +1,110 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/*
+ Read a record with random-access. The position to the record must
+ get by mrg_info(). The next record can be read with pos= -1 */
+
+
+#include "mrgdef.h"
+
+static MRG_TABLE *find_table(MRG_TABLE *start,MRG_TABLE *end,mrg_off_t pos);
+
+/*
+ If filepos == -1, read next
+ Returns same as nisam_rrnd:
+ 0 = Ok.
+ 1 = Record deleted.
+ -1 = EOF (or something, errno should be HA_ERR_END_OF_FILE)
+*/
+
+int mrg_rrnd(MRG_INFO *info,byte *buf,mrg_off_t filepos)
+{
+ int error;
+ N_INFO *isam_info;
+
+ if (filepos == ~(mrg_off_t) 0) /* Can't use HA_POS_ERROR */
+ {
+ if (!info->current_table)
+ {
+ if (info->open_tables == info->end_table)
+ { /* No tables */
+ my_errno=HA_ERR_END_OF_FILE;
+ return -1;
+ }
+ isam_info=(info->current_table=info->open_tables)->table;
+ if (info->cache_in_use)
+ nisam_extra(isam_info,HA_EXTRA_CACHE);
+ filepos=isam_info->s->pack.header_length;
+ isam_info->lastinx= (uint) -1; /* Can't forward or backward */
+ }
+ else
+ {
+ isam_info=info->current_table->table;
+ filepos= isam_info->nextpos;
+ }
+
+ for (;;)
+ {
+ isam_info->update&= HA_STATE_CHANGED;
+ if ((error=(*isam_info->s->read_rnd)(isam_info,(byte*) buf,
+ filepos,1)) >= 0 ||
+ my_errno != HA_ERR_END_OF_FILE)
+ return (error);
+ if (info->cache_in_use)
+ nisam_extra(info->current_table->table,HA_EXTRA_NO_CACHE);
+ if (info->current_table+1 == info->end_table)
+ return(-1);
+ info->current_table++;
+ info->last_used_table=info->current_table;
+ if (info->cache_in_use)
+ nisam_extra(info->current_table->table,HA_EXTRA_CACHE);
+ info->current_table->file_offset=
+ info->current_table[-1].file_offset+
+ info->current_table[-1].table->s->state.data_file_length;
+
+ isam_info=info->current_table->table;
+ filepos=isam_info->s->pack.header_length;
+ isam_info->lastinx= (uint) -1;
+ }
+ }
+ info->current_table=find_table(info->open_tables,
+ info->last_used_table,filepos);
+ isam_info=info->current_table->table;
+ isam_info->update&= HA_STATE_CHANGED;
+ return ((*isam_info->s->read_rnd)(isam_info,(byte*) buf,
+ (ulong) (filepos -
+ info->current_table->file_offset),
+ 0));
+}
+
+
+ /* Find which table to use according to file-pos */
+
+static MRG_TABLE *find_table(MRG_TABLE *start,MRG_TABLE *end,mrg_off_t pos)
+{
+ MRG_TABLE *mid;
+
+ while (start != end)
+ {
+ mid=start+((uint) (end-start)+1)/2;
+ if (mid->file_offset > pos)
+ end=mid-1;
+ else
+ start=mid;
+ }
+ return start;
+}
diff --git a/merge/rsame.c b/merge/rsame.c
new file mode 100644
index 00000000000..a18f1771c37
--- /dev/null
+++ b/merge/rsame.c
@@ -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 */
+
+#include "mrgdef.h"
+
+
+int mrg_rsame(info,record,inx)
+MRG_INFO *info;
+byte *record;
+int inx; /* not used, should be 0 */
+{
+ if (inx)
+ {
+ my_errno=HA_ERR_WRONG_INDEX;
+ return(-1);
+ }
+ if (!info->current_table)
+ {
+ my_errno=HA_ERR_NO_ACTIVE_RECORD;
+ return(-1);
+ }
+ return nisam_rsame(info->current_table->table,record,inx);
+}
diff --git a/merge/static.c b/merge/static.c
new file mode 100644
index 00000000000..e5f95ef195a
--- /dev/null
+++ b/merge/static.c
@@ -0,0 +1,26 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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
+ a shared library
+*/
+
+#ifndef stdin
+#include "mrgdef.h"
+#endif
+
+LIST *mrg_open_list=0;
diff --git a/merge/update.c b/merge/update.c
new file mode 100644
index 00000000000..64900b82116
--- /dev/null
+++ b/merge/update.c
@@ -0,0 +1,31 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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"
+
+int mrg_update(info,oldrec,newrec)
+register MRG_INFO *info;
+const byte *oldrec,*newrec;
+{
+ if (!info->current_table)
+ {
+ my_errno=HA_ERR_NO_ACTIVE_RECORD;
+ return(-1);
+ }
+ return nisam_update(info->current_table->table,oldrec,newrec);
+}
diff --git a/missing b/missing
new file mode 100755
index 00000000000..7789652e877
--- /dev/null
+++ b/missing
@@ -0,0 +1,190 @@
+#! /bin/sh
+# Common stub for a few missing GNU programs while installing.
+# Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+# Franc,ois Pinard <pinard@iro.umontreal.ca>, 1996.
+
+# This program is free software; you can redistribute 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 test $# -eq 0; then
+ echo 1>&2 "Try \`$0 --help' for more information"
+ exit 1
+fi
+
+case "$1" in
+
+ -h|--h|--he|--hel|--help)
+ echo "\
+$0 [OPTION]... PROGRAM [ARGUMENT]...
+
+Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an
+error status if there is no known handling for PROGRAM.
+
+Options:
+ -h, --help display this help and exit
+ -v, --version output version information and exit
+
+Supported PROGRAM values:
+ aclocal touch file \`aclocal.m4'
+ autoconf touch file \`configure'
+ autoheader touch file \`config.h.in'
+ automake touch all \`Makefile.in' files
+ bison create \`y.tab.[ch]', if possible, from existing .[ch]
+ flex create \`lex.yy.c', if possible, from existing .c
+ lex create \`lex.yy.c', if possible, from existing .c
+ makeinfo touch the output file
+ yacc create \`y.tab.[ch]', if possible, from existing .[ch]"
+ ;;
+
+ -v|--v|--ve|--ver|--vers|--versi|--versio|--version)
+ echo "missing - GNU libit 0.0"
+ ;;
+
+ -*)
+ echo 1>&2 "$0: Unknown \`$1' option"
+ echo 1>&2 "Try \`$0 --help' for more information"
+ exit 1
+ ;;
+
+ aclocal)
+ echo 1>&2 "\
+WARNING: \`$1' is missing on your system. You should only need it if
+ you modified \`acinclude.m4' or \`configure.in'. You might want
+ to install the \`Automake' and \`Perl' packages. Grab them from
+ any GNU archive site."
+ touch aclocal.m4
+ ;;
+
+ autoconf)
+ echo 1>&2 "\
+WARNING: \`$1' is missing on your system. You should only need it if
+ you modified \`configure.in'. You might want to install the
+ \`Autoconf' and \`GNU m4' packages. Grab them from any GNU
+ archive site."
+ touch configure
+ ;;
+
+ autoheader)
+ echo 1>&2 "\
+WARNING: \`$1' is missing on your system. You should only need it if
+ you modified \`acconfig.h' or \`configure.in'. You might want
+ to install the \`Autoconf' and \`GNU m4' packages. Grab them
+ from any GNU archive site."
+ files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' configure.in`
+ test -z "$files" && files="config.h"
+ touch_files=
+ for f in $files; do
+ case "$f" in
+ *:*) touch_files="$touch_files "`echo "$f" |
+ sed -e 's/^[^:]*://' -e 's/:.*//'`;;
+ *) touch_files="$touch_files $f.in";;
+ esac
+ done
+ touch $touch_files
+ ;;
+
+ automake)
+ echo 1>&2 "\
+WARNING: \`$1' is missing on your system. You should only need it if
+ you modified \`Makefile.am', \`acinclude.m4' or \`configure.in'.
+ You might want to install the \`Automake' and \`Perl' packages.
+ Grab them from any GNU archive site."
+ find . -type f -name Makefile.am -print |
+ sed 's/\.am$/.in/' |
+ while read f; do touch "$f"; done
+ ;;
+
+ bison|yacc)
+ echo 1>&2 "\
+WARNING: \`$1' is missing on your system. You should only need it if
+ you modified a \`.y' file. You may need the \`Bison' package
+ in order for those modifications to take effect. You can get
+ \`Bison' from any GNU archive site."
+ rm -f y.tab.c y.tab.h
+ if [ $# -ne 1 ]; then
+ eval LASTARG="\${$#}"
+ case "$LASTARG" in
+ *.y)
+ SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'`
+ if [ -f "$SRCFILE" ]; then
+ cp "$SRCFILE" y.tab.c
+ fi
+ SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'`
+ if [ -f "$SRCFILE" ]; then
+ cp "$SRCFILE" y.tab.h
+ fi
+ ;;
+ esac
+ fi
+ if [ ! -f y.tab.h ]; then
+ echo >y.tab.h
+ fi
+ if [ ! -f y.tab.c ]; then
+ echo 'main() { return 0; }' >y.tab.c
+ fi
+ ;;
+
+ lex|flex)
+ echo 1>&2 "\
+WARNING: \`$1' is missing on your system. You should only need it if
+ you modified a \`.l' file. You may need the \`Flex' package
+ in order for those modifications to take effect. You can get
+ \`Flex' from any GNU archive site."
+ rm -f lex.yy.c
+ if [ $# -ne 1 ]; then
+ eval LASTARG="\${$#}"
+ case "$LASTARG" in
+ *.l)
+ SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'`
+ if [ -f "$SRCFILE" ]; then
+ cp "$SRCFILE" lex.yy.c
+ fi
+ ;;
+ esac
+ fi
+ if [ ! -f lex.yy.c ]; then
+ echo 'main() { return 0; }' >lex.yy.c
+ fi
+ ;;
+
+ makeinfo)
+ echo 1>&2 "\
+WARNING: \`$1' is missing on your system. You should only need it if
+ you modified a \`.texi' or \`.texinfo' file, or any other file
+ indirectly affecting the aspect of the manual. The spurious
+ call might also be the consequence of using a buggy \`make' (AIX,
+ DU, IRIX). You might want to install the \`Texinfo' package or
+ the \`GNU make' package. Grab either from any GNU archive site."
+ file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'`
+ if test -z "$file"; then
+ file=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'`
+ file=`sed -n '/^@setfilename/ { s/.* \([^ ]*\) *$/\1/; p; q; }' $file`
+ fi
+ touch $file
+ ;;
+
+ *)
+ echo 1>&2 "\
+WARNING: \`$1' is needed, and you do not seem to have it handy on your
+ system. You might have modified some files without having the
+ proper tools for further handling them. Check the \`README' file,
+ it often tells you about the needed prerequirements for installing
+ this package. You may also peek at any GNU archive site, in case
+ some other package would contain this missing \`$1' program."
+ exit 1
+ ;;
+esac
+
+exit 0
diff --git a/mit-pthreads/.cvsignore b/mit-pthreads/.cvsignore
new file mode 100644
index 00000000000..6b051949557
--- /dev/null
+++ b/mit-pthreads/.cvsignore
@@ -0,0 +1,6 @@
+Makefile
+config.cache
+config.h
+config.log
+config.status
+obj
diff --git a/mit-pthreads/COPYRIGHT b/mit-pthreads/COPYRIGHT
new file mode 100644
index 00000000000..1b727cd8dac
--- /dev/null
+++ b/mit-pthreads/COPYRIGHT
@@ -0,0 +1,31 @@
+Copyright (c) 1993, 1994, 1995, 1996 by Chris Provenzano and contributors,
+proven@mit.edu All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+3. All advertising materials mentioning features or use of this software
+ must display the following acknowledgement:
+ This product includes software developed by Chris Provenzano,
+ the University of California, Berkeley, and contributors.
+4. Neither the name of Chris Provenzano, the University, nor the names of
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO AND CONTRIBUTORS ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO, THE REGENTS OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
diff --git a/mit-pthreads/Changes-mysql b/mit-pthreads/Changes-mysql
new file mode 100644
index 00000000000..8895144206d
--- /dev/null
+++ b/mit-pthreads/Changes-mysql
@@ -0,0 +1,194 @@
+Changes done to this distrubtion (pthreads-1_60_beta6) by Monty (monty@tcx.se)
+
+93.04.01
+- socket() didn't return NOTOK (-1) on error.
+- bind() didn't set error code on failure
+
+93.03.27
+- Added patch by D. Richard Hipp <drh@vnet.net> to make strtod and
+ printf (of floats/doubles) thread safe. Patch provided by mevans@cti-ltd.com
+- Added patch I got from lucid@secret.org to fix lock in fork().
+
+93.03.26
+- Fixed some include files for BSD 2.0.
+- Changed the prototype of ioctl() for BSD.
+- Fixed new bug in fd_kernel.c; _fd_kern_read returned sometimes wrong errno.
+
+93.03.22
+- Change sys/cdefs.h to get it through Sun cc.
+- Added patches by Mark Evans
+ 1. Crashes and hangs.
+ 2. Missing functionality (namely flock())
+ 3. Use of POSIX reentrant safe routines.
+
+93.03.21
+- Add patches by Larry V. Streepy to fix pthread_cancel.
+ Fixed bug in Streepy's patch that checked return values of read,write..
+ in fd.c (Already done in fd_sys.c)
+
+1. Added a declaration of &#34;signal&#34; to include/signal.h
+2. Modified PANIC macro to operate like assert and call a new function
+ panic_kernel. Added new file pthreads/panic.c.
+3. Added support for fstatfs syscall for linux (mod to
+ syscall-i386-linux-1.0.S).
+4. Added missing function declarations to machdep/linux-1.0/socket.h:
+ getsockopt
+ setsockopt
+ getsockname
+ getpeername
+ send
+ recv
+ sendto
+ recvfrom
+ sendmsg
+ recvmsg
+ shutdown
+5. Added ifdef to avoid type conflict in machdep/linux-1.0/timers.h
+6. Fix bug in getprotoent (bogus semi-colon after if stmt).
+7. Change function name in proto_internal.c from _proto_init to
+ _proto_buf.
+8. Fix bug in res_internal.c where buffer pointer was improperly
+ maintained.
+9. Fix return value handling for POSIX function implementations.
+10. Fix bug in select handling where a thread could be incorrectly
+ resumed with no sockets ready. Also added proper handling of
+ selecting for exceptions (this was not implemented at all).
+11. Added deadlock detection to pthread_join (it can now return an
+ EDEADLK error).
+12. Added support for pthread_cancel, changes to lots of files for this.
+13. Add new function __pthread_is_valid that searches the pthread list
+ for a specified pthread_t value.
+
+93.03.22
+- Fixed some if the tests according to the below changes.
+
+93.03.21 by "Mati Sauks" <mati@psti.com>
+- Fixed bug if priority queue was empty or (*current)->next is empty.
+
+96.03.20 by Josip Gracin
+- Fixed gethostbyname to handle alias
+
+97.02.07
+- Removed CVS directories.
+- Commented make install in GNUmakefile.in.
+
+97.01.26 by David (david@detron.se)
+- Fixed a dist target in the GNUmakefile
+- Added #undef PTHREAD_STACK_MIN to avoid warning on solaris 2.5
+
+97.01.21 by Monty (monty@tcx.se)
+
+- Added file mysql-TODO and the patches directory.
+- Added patch p153 and p155 by Tim Hinderliter and Chris Colohan
+ check the patches directory for more info.
+- Changed pthread_cond_timedwait to return ETIME instead of ETIMEDOUT
+ (Required by Posix)
+- Changed the include file pthread.h to add prototypes for the following
+ functions: pthread_sigmask, sigwait and sigsetwait
+- Added shutdown() and getpeername() prototypes to 'machdep/sunos-5.3/socket.h'
+- Changed __FD_NONBLOCK to (O_NONBLOCK | O_NDELAY) in
+ ./machdep/engine-sparc-sunos-5.3.h
+- Added rint() prototype to math.h
+- Added new slot sighandled to 'struct pthread' for easy check if somebody
+ interrupts a system call.
+- pthread_kill can now interrupt the following system calls:
+ select(), read(), write(), send(), sendto(), sendmsg(), recv_timedwait(),
+ recvfrom_timedwait(), readev(), writeev() and some socket functions.
+- Fixed bug in pthread_kill() which count up 'sigcount' wrongly.
+ Two pthread_kill() in a row bugged the thread.
+- Merged fd_kern_wait and fd_kern_poll to 1 function and removed a
+ a bug when polling select.
+- Implemented getpeername().
+- Some small optimizations.
+- Some re-indentation to make the code readable by me (Sorry about that).
+
+97.08.15 by Monty (monty@tcx.se)
+
+- Added patch by "Chris G. Demetriou" <cgd@pa.dec.com> for NetBSD/alpha.
+
+97.08.18 by Monty (monty@tcx.se)
+
+- Added new machdep definitions for HPUX-10.20,
+ by JOERG_HENNE@Non-HP-Germany-om88.om.hp.com
+
+97.09.25 by Monty (monty@tcx.se)
+
+- Added some definitions for i386-SCO from the site:
+ http://www.sco.com/skunkware/osr5/libraries/
+
+97.10.12 by Monty (monty@tcx.se)
+
+- Changed prototype macro __P to __P_ to avoid warnings on Solaris.
+- Fixed interruption of select() with pthread_kill() when signal handler
+ used read or write.
+
+97.10.16 by Monty (monty@tcx.se)
+
+- Fixed that blocked signals doesn't interrupt threads.
+
+97.10.20 by Monty (monty@tcx.se)
+
+- Fixed broken ftruncate system call for FreeBSD 2.0
+ The old one destroyed the orignal file by truncation too much.
+- Fixed prototypes for des_setkey,encrypt and setkey (according to Solaris 2.5)
+
+97.11.26 by Monty (monty@tcx.se)
+
+- Small patch to avoid compile errors on alpha-OSF1 3.2
+
+97.12.18 by Monty (monty@tcx.se)
+
+- Added fix for Irix 5.3 in __unistd.h
+
+98.01.13 by Monty (monty@tcx.se)
+- Added fd_check_entry to dup2 and table sizecheck to fd_check_entry()
+ patch by Martin Fuchs <Martin@igdv.fh-darmstadt.de>
+
+98.01.18 by Monty (monty@tcx.se)
+- Added prototype for gettimeofday() for Solars 2.3
+- Added some small fixes for configure and Solaris 2.6
+
+98.01.23 by Monty (monty@tcx.se)
+- Ported to openbsd.
+- Renamed nanosleep() to pthread_nanosleep() to avoid name conflict on
+ openbsd.
+- Fixed link problem with variable __sglue for Irix 5.3
+ by Vladislav Malyshkin <malyshki@cs.wmich.edu>.
+
+98.03.02 by Monty (monty@tcx.se)
+- Applied patches from Curt Sampson <cjs@portal.ca>; NetBSD 1.3/i386 port.
+
+98.03.09 by Monty (monty@tcx.se)
+- Applied patches from Curt Sampson <cjs@portal.ca>; NetBSD 1.3/Alpha port.
+
+98.05.12
+- Added unixware to config.guess
+
+98.06.07
+- Added patch by Scott Dybiec <sdybiec@humanfactor.com>:
+ Fixed select() returning incorrect number of active file descriptors.
+
+99.06.07 by Monty (monty@mysql.com)
+- Added patches from the NETBSD site. Should fix the following platforms:
+ alpha-netbsd-1.3, sparc-netbsd-1.3, i386-netbsd, arm32-netbsd
+
+99.09.09 by Monty (monty@mysql.com)
+- Added patches from Christoph Badura <bad@oreilly.de> for NetBSD
+
+99.09.13 by Monty (monty@mysql.com)
+- Added patches from Dirk Froemberg <dirk@FreeBSD.org> for FreeBSD
+
+99.10.18 by Monty (monty@mysql.com)
+- Added patch for machdep_sys_lseek() for netbsd.
+
+99.12.30 by Monty (monty@mysql.com)
+- Added patch by Christoph Badura <bad@oreilly.de> to update mit-pthreads
+ to the same version as in the NetBSD pkgsrc.
+
+00.02.24 by Monty (monty@mysql.com)
+- Added configure files to make mit-pthreads to compile and link during
+ newer linux systems (needed because of the MySQL configure system).
+ The resulting library has however not been verified under Linux.
+
+00.03.30 by Monty (monty@mysql.com)
+- Added chroot() and gethostname().
diff --git a/mit-pthreads/FAQ b/mit-pthreads/FAQ
new file mode 100644
index 00000000000..e4fd3cfc6d8
--- /dev/null
+++ b/mit-pthreads/FAQ
@@ -0,0 +1,122 @@
+
+ Answers to frequently asked questions
+ for my implementation of POSIX threads
+
+-------------------------------------------------------------------------------
+1. Pthreads
+
+(1.0) What is Pthreads?
+(1.1) Where can I get info on Pthreads?
+
+2. Getting, Building, Installing and Using proven's Pthreads
+
+(2.0) Where can I get the latest version of proven's Pthreads?
+(2.1) What platforms does proven's Pthreads run on?
+(2.2) What do I need to build proven's Pthreads?
+(2.3) How do I install proven's Pthreads?
+
+3. Known Problems
+
+(3.0) Tests
+(3.1) Installation
+(3.2) Missing functionality
+(3.3) Signals
+
+-------------------------------------------------------------------------------
+1. Pthreads
+
+(1.0) What is Pthreads?
+
+Pthreads stands for POSIX threads and is based on the POSIX 1003.1c 1995
+thread standard. This standard passed international Standards Organization
+(ISO) Committee Document (CD) balloting in February 1995 and got the
+IEEE Standards Board approval in June 1995.
+
+
+(1.1) Where can I get info on Pthreads?
+
+You can call IEEE (908) 562-3800 which is the organization which POSIX
+belongs, and ask for POSIX 1003.1c (not 1003.4a) draft 10 (the standard
+won't be out until sometime in 1996). The draft costs $30.00 plus shipping
+which for me was $4.00. The IEEE doesn't make any of the standards available
+online.
+
+I have made documentation for some of the functions available online.
+To reference these use http://www.mit.edu:8001/people/proven/pthreads.html
+
+-------------------------------------------------------------------------------
+2. Getting, Building, Installing and Using proven's Pthreads
+
+(2.0) Where can I get the latest version of proven's Pthreads?
+
+The latest version is pthreads-1_60_beta6 was release on November 16, 1996
+and is available from sipb.mit.edu:/pub/pthreads.
+
+
+(2.1) What platforms does proven's Pthreads run on?
+
+Lot's! It should run on the following platforms; the i386 processor
+running NetBSD-1.x, FreeBSD-2.x, BSDOS-2.0, Linux-1.2 and Linux-1.3;
+the r2000 (DECstation) running Ultrix-4.2; the Sparc running NetBSD-1.x,
+SunOS-4.1.3, Solaris-2.3, and Solaris-2.4; the alpha running OSF-2.3 and
+OSF-3.x; the SGI running IRIX-5.2; and the HPPA running HP/UX-9.x.
+
+Because it runs on so many platforms I don't get to compile and test every
+platform for every release. If you have a problem send mail to
+pthreads-bugs@mit.edu with the processor, OS, and version number along with
+a description of the bug.
+
+
+(2.2) What do I need to build proven's Pthreads?
+
+You will need gcc and gmake to build for all but NetBSD, FreeBSD and BSDOS.
+For those you may use either gmake or pmake (the native make).
+
+
+(2.3) How do I install proven's Pthreads?
+
+Installing pthreads is real easy. At the top level of pthreads do
+
+configure
+make
+make install
+
+It will be installed into the directory /usr/local/pthreads. If you don't
+like the location add a --prefix=<dir> option to configure. That's it.
+
+
+-------------------------------------------------------------------------------
+3. Known problems.
+
+(3.0) Tests
+
+Under SunOS-4.1.x there is a bug in the kernel that prevents test_sock_1
+from passing. This bug has to do with a process tring to connect to itself.
+In respose I wrote test_sock_2 to test the socket code for SunOS which
+does work. You should have no problems using the socket code in SunOS
+so long as you don't write a program that need to connect to itself.
+
+
+(3.1) Installation
+
+The only know problem is on the SGI. You will need to use GNU tar instead
+of the native supplied one or edit the config.flags file and remove the -h
+option to tar. Aparently the -h option on IRIX 5.3 version of tar does the
+exact opposite of all the other versions of tar I've used and instead of
+following symbolic links and getting the file it archives the link.
+
+
+(3.2) Missing functionality
+
+The current release is missing cancelation, priority mutexes and others.
+I'm continuing to develope pthreads and I plan to put cancelation and
+priority mutexes and as much other stuff as I can into the 1_70 release
+
+
+(3.3) Signals
+
+Currently to intermix signals with pthreads you need to rename all calls
+to signal() and sigaction() to pthread_signal() and pthread_sigaction().
+I plan to write real wrapper routines for signal() and sigaction() for
+the 1_70 release.
+
diff --git a/mit-pthreads/GNUmakefile b/mit-pthreads/GNUmakefile
new file mode 100644
index 00000000000..a36f425c7a7
--- /dev/null
+++ b/mit-pthreads/GNUmakefile
@@ -0,0 +1,129 @@
+# === GNUmakefile =============================================================
+# Copyright (c) 1991, 1992, 1993 Chris Provenzano, proven@athena.mit.edu
+#
+# Description: This file is for creating libpthread.a
+#
+# 1.00 93/11/17 proven
+# -Put all the .o files into one file libpthread.a
+# -Initial cut for pthreads.
+#
+
+INSTALL_PATH = $(exec_prefix)
+
+ BINDIR = $(INSTALL_PATH)/bin
+ LIBDIR = $(INSTALL_PATH)/lib
+ MANDIR = $(INSTALL_PATH)/man
+ INCDIR = $(INSTALL_PATH)/include
+ SUBINCDIR = $(INCDIR)/pthread
+
+ AR = ar
+ AS = gas
+ CFLAGS = -I. -Iinclude -I$(srcdir)/include -DPTHREAD_KERNEL \
+ -O6 -DDBUG_OFF -Werror
+ CXXFLAGS = -I. -Iinclude -I$(srcdir)/include -DPTHREAD_KERNEL \
+ -g -O2
+ LD = gld
+
+ CSRC =
+
+ PTHREAD_DIR = pthreads stdlib stdio gen
+ DIRS = $(PTHREAD_DIR)
+
+ HEADERS =
+
+ LIBRARIES = libpthread.a
+
+ .CURDIR = .
+
+# force correct default target
+all:
+
+###############################################################################
+#
+# Read in any special flags that config knows about
+include config.flags
+
+# What the heck. Convert srcdir to absolute form so it looks prettier.
+srcdir := $(shell cd $(srcfoo) && pwd)
+
+################################################################################
+#
+# Here starts the nitty grity part of the Makefile.
+
+all-lib : libpthread.a
+
+include ${srcdir}/pthreads/GNUmakefile.inc
+include ${srcdir}/stdlib/GNUmakefile.inc
+include ${srcdir}/stdio/GNUmakefile.inc
+include ${srcdir}/string/GNUmakefile.inc
+include ${srcdir}/gen/GNUmakefile.inc
+include ${srcdir}/net/GNUmakefile.inc
+include ${srcdir}/scripts/GNUmakefile.inc
+
+REGULAR_OBJS= $(subst .cc,.o,$(SRCS))
+REGULAR_OBJS:= $(subst .c,.o,$(REGULAR_OBJS))
+REGULAR_OBJS:= $(subst .S,.o,$(REGULAR_OBJS))
+OBJS= $(REGULAR_OBJS) $(EXTRA_OBJS)
+REALOBJS = $(addprefix obj/, $(OBJS))
+
+$(REALOBJS) : $(config) $(types) $(paths)
+
+# Since we do not have a list of the relevant files we do a make clean
+# before copying everyting to the distribution directory.
+distdir:
+ $(MAKE) clean
+ cp -a . $(distdir)
+ # Remove symlinks that the distribution should not have.
+ rm -f $(distdir)/config.cache \
+ $(distdir)/include/pthread/machdep.h \
+ $(distdir)/include/pthread/posix.h \
+ $(distdir)/include/sys \
+ $(distdir)/machdep.c \
+ $(distdir)/syscall.S \
+ $(distdir)/syscall-template.S
+
+clean:
+ rm -f a.out core maketmp makeout $(LIBRARIES) $(BINARIES) libpthread.*
+ rm -rf obj
+ cd tests && $(MAKE) clean && cd ..
+
+install-lib: $(LIBRARIES) install-dirs
+ for x in $(LIBRARIES); \
+ do install $$x $(DESTDIR)$(LIBDIR); \
+ done
+
+# Removed make install since mysql uses this in place.
+# install-lib install-include install-bin
+install:
+
+libpthread.a: obj/libpthread.a
+ rm -f libpthread.a
+ ln -s obj/libpthread.a .
+
+obj/libpthread.a: ${REALOBJS}
+ rm -f libpthread.a obj/new.a obj/libpthread.a
+ cd obj && \
+ ar r new.a ${OBJS} && \
+ $(RANLIB) new.a && \
+ mv -f new.a libpthread.a && \
+ cd ..
+
+# For examining a combined symbol table, sizes, &c.
+libpthread.o: ${REALOBJS}
+ cd obj && ld -r -o ../libpthread.o ${OBJS} && cd ..
+
+obj/x:
+ if [ -d obj ]; then true; else mkdir obj; fi
+ cp /dev/null obj/x
+
+GNUmakefile: config.status ${srcdir}/config/GNUmakefile.in
+ $(SHELL) config.status
+
+obj/%.o: %.c obj/x
+ $(CC) $(CFLAGS) -c $< -o $@
+
+obj/%.o: %.cc obj/x
+ $(CXX) $(CXXFLAGS) $(CFLAGS) -c $< -o $@
+
+obj/%.o: %.S obj/x
+ $(CC) $(CFLAGS) -c $< -o $@
diff --git a/mit-pthreads/NOTES b/mit-pthreads/NOTES
new file mode 100644
index 00000000000..cebdc6a396c
--- /dev/null
+++ b/mit-pthreads/NOTES
@@ -0,0 +1,59 @@
+
+Here are some notes on the internals of the implementation.
+
+LIBC routines.
+
+ Unfortuanately many of the libc routine return a pointer to static data.
+There are two methods to deal with this. One write a new routine where the
+arguments are different, and have one argument be a pointer to some space
+to store the data, or two use thread specific data and warn the user that
+data isn't valid if the calling thread is terminated.
+
+INTERNAL LOCKING
+To prevent deadlocks the following rules were used for locks.
+
+1. Local locks for mutex queues and other like things are only locked
+ by running threads, at NO time will a local lock be held by
+ a thread in a non running state.
+2. Only threads that are in a run state can attempt to lock another thread,
+ this way, we can assume that the lock will be released shortly, and don't
+ have to unlock the local lock.
+3. The only time a thread will have a pthread->lock and is not in a run
+ state is when it is in the reschedule routine.
+4. The reschedule routine assumes all local locks have been released,
+ there is a lock on the currently running thread (pthread_run),
+ and that this thread is being rescheduled to a non running state.
+ It is safe to unlock the currently running threads lock after it
+ has been rescheduled.
+5. The reschedule routine locks the kernel, sets the state of the currently
+ running thread, unlocks the currently running thread, calls the
+ context switch routines.
+6 the kernel lock is used only ...
+
+
+7. The order of locking is ...
+
+1 local locks
+2 pthread->lock /* Assumes it will get it soon */
+3 pthread_run->lock /* Assumes it will get it soon, but must release 2 */
+4 kernel lock /* Currently assumes it will ALWAYS get it. */
+
+8. The kernel lock will be changed to a spin lock for systems that
+already support kernel threads, this way we can mutiplex threads onto
+kernel threads.
+9. There are points where the kernel is locked and it needs to get
+either a local lock or a pthread lock, if at these points the code
+fails to get the lock the kernel gives up and sets a flag which will
+be checked at a later point.
+10. Interrupts are dissabled while the kernel is locked, the interrupt
+mask must be checked afterwards or cleared in some way, after interrputs
+have been reenabled, this allows back to back interrupts, but should always
+avoid missing one.
+
+------------------------------------------------------------------------------
+Copyright (c) 1994 Chris Provenzano. All rights reserved.
+This product includes software developed by the Univeristy of California,
+Berkeley and its contributors.
+
+For further licencing and distribution restrictions see the file COPYRIGHT
+included in this directory.
diff --git a/mit-pthreads/NOTES_OSR5_BUILD_SKUNKWARE97 b/mit-pthreads/NOTES_OSR5_BUILD_SKUNKWARE97
new file mode 100644
index 00000000000..fd2e00c9860
--- /dev/null
+++ b/mit-pthreads/NOTES_OSR5_BUILD_SKUNKWARE97
@@ -0,0 +1,45 @@
+This port to Osr5 was donated by
+ ARTURO MONTES mitosys@colomsat.net.co
+Its a snapshot of the 1.60 Beta 5 version
+
+It passes all the tests except test_fork (this seems to be a problem
+with the MIT source)
+and I suspect there may also to be problems with
+the floating point initialisation and perhaps the netdb access as well
+
+
+Regarding the networking API's mind the following (ARTURO):
+
+- Always we are searching host address in /etc/hosts by default, if you
+want other behaviour let me to know.
+
+- If you haven't an entry in /etc/hosts, please create it and after test
+with DNS service.
+
+regarding floating point initialisation (ARTURO)
+
+...mit-pthreads/pthreads/tests> ./test_preemption_float
+test_preemption_float INDETERMINATE
+
+I inhibit the pthread float code, but they are a minor changes in machdep.c.
+
+> What did you do/needs to be done here ??
+
+Look into machdep.c machdep_save_float_state() and
+machdep_restore_float_state() routine. I think the initialization float
+code can have problems with pthread initialization code.
+
+----------------
+
+
+If you wish to rebuild from source you'll need the gnus devsys
+(gmake and gcc) and don't use configure to reconfigure the makefiles, etc
+ ( I don't know why this is but it doesn't work)
+
+If Arturo keeps me updated with buildable snapshots I'll endeavour to keep
+the skunkware Website updated with them.
+
+
+Best of luck
+
+hops 01-Aug-97
diff --git a/mit-pthreads/README b/mit-pthreads/README
new file mode 100644
index 00000000000..0a55bcd94bb
--- /dev/null
+++ b/mit-pthreads/README
@@ -0,0 +1,40 @@
+This pthread package is/will be based on the POSIX1003.1c Draft 10 pthread
+standard, and Frank Muellers paper on signal handeling presented at the
+Winter 93 USENIX conference.
+
+It is currently being designed and written by me, Chris Provenzano.
+All bug, comments, and questions can be sent me at proven@mit.edu,
+or pthreads@mit.edu.
+
+PLEASE, don't send questions, bugs or patches to any of the *BSD*, Linux
+or GNU mailing lists.
+
+Thanks goes to Ken Raeburn for his help on the Sparc port, the configurator,
+and his many suggestions, Greg Hudson for the thread safe net routines and
+all the testing he's done.
+
+More thanks to Mark Eichin and all the others for the testing they have done.
+
+PORTING
+One of the goals of this user space implementation of pthreads is that it
+be portable. I have minimized the ammount of assembler code necessary,
+but some is.
+
+If you want to port it to another platform here are a few basic hints.
+
+You will need to create a machdep.h, machdep.c and syscall.S for the
+new architecture. The first two are necessary to get the context switch
+section of the pthread package running, the third is for all the syscalls.
+
+INCLUDE FILES AND PORTING
+In addition to the above three files you need to create a slew of .h files.
+Take a look at an existing port to determine what is in each, and then
+take a look at your system header files to determine what to put in them.
+
+------------------------------------------------------------------------------
+Copyright (c) 1993, 1994, 1995, 1996 Chris Provenzano. All rights reserved.
+This product includes software developed by the Univeristy of California,
+Berkeley and its contributors.
+
+For further licencing and distribution restrictions see the file COPYRIGHT
+included in this directory.
diff --git a/mit-pthreads/TODO-mysql b/mit-pthreads/TODO-mysql
new file mode 100644
index 00000000000..a19b1bd51d6
--- /dev/null
+++ b/mit-pthreads/TODO-mysql
@@ -0,0 +1,4 @@
+This what should be done to get more functionally for mysqld.
+
+- open should be interruptable.
+- fcntl lock should be interruptable.
diff --git a/mit-pthreads/Whats_New b/mit-pthreads/Whats_New
new file mode 100644
index 00000000000..556d9f63268
--- /dev/null
+++ b/mit-pthreads/Whats_New
@@ -0,0 +1,198 @@
+For patches made to this release, check the file Changes-mysql
+
+For the 96/11/11 release version 1_60_beta6
+
+ Ports
+ Alpha running NetBSD-1.1 by Chris G Demetriou <cgd+@cs.cmu.edu>
+ i386 running BSDi-2.1 by David J MacKenzie <djm@va.pubnix.com>
+
+ Bug Fixes
+ Test for struct timespec under linux and DTRT.
+ include/unistd.h : #define SEEK_SET, SEEK_CUR, and SEEK_END.
+ Bug reported by Stephen Tether <tether@MITLNS.MIT.EDU>
+ stdlib/system.c : Uses the POSIX signal systemcalls.
+ Bug reported by Matthew Newhook <matthew@thor.udc.neweast.ca>.
+ net/gethostbyname.c: #include <string.h> and fix dereference problem.
+ Bug reported by Chris G Demetriou <cgd+@cs.cmu.edu>
+ pthreads/fd.c: Fix bug in close() reported by
+ Bug reported by "William S. Lear" <rael@dejanews.com>
+ tests/p_bench_pthread_create.c : Only try and create 10000 threads.
+ include/pthread/sleep.h : No need to prototype machdep_gettimeofday()
+ since it is declared here.
+ Bug reported by Stewart Gebbie <stewart@global.co.za>
+ stdio/fwrite.c: Fixed bug where if total bytes written = 0 then a divid
+ by 0 occurs. Thanks to CTLarsen@lbl.gov for finding is and to
+ Jin Guojun <jin@george.lbl.gov> for submitting a patch for it.
+ stdio/refill.c (__swalk_lflush()): Second pass of flush should call
+ flockfile() not ftrylockfile(). Just like in __swalk_sflush()
+ net/res_internal.c (_res_parse_answer()): It looks like if
+ iquery is true and type == T_PTR then the result->h_name
+ will be over written because the bp isn't incrementd
+ appropriately. Thanks to David Halls <David.Halls@cl.cam.ac.uk>
+ for finding it.
+ net/serv_internal.c (_serv_buf()) : Allocate more than four bytes
+ of buffer space. Reported by drh@@tobit.vnet.net.
+ pthreads/fd_kern.c: Make sure exception fds are included in
+ machdep_sys_select() for support of select(). Thanks to
+ Larry V. Streepy, Jr. <streepy@healthcare.com> for the patches.
+ pthreads/fd_kern.c: Fix more I/O routines to report NOTOK on error
+ instead of the old -error number. Hopefully this is the last of
+ them. Thanks to Larry V. Streepy, Jr. <streepy@healthcare.com> for
+ the patches.
+ machdep/engine-i386-linux-1.0.c: Remove unneeded machdep_sys_readv()
+ and machdep_sys_writev() routines. Reported by
+ pthreads/process.c : Fix execl() and execle() to work on sparc systems.
+ pthreads/fd_sysv.c : Fix accept() to work under Solaris 2.4
+
+
+For the 96/03/09 release version 1_60_beta5
+
+ Ports
+ Sparc running NetBSD-1.1
+
+ Additions
+ New reentrant netdb similar to Solaris API (ghudson)
+
+ Bug Fixes
+ Make default signal handlers work.
+ Deadlock scheduling bug reported by Cathy Abbott <cabbot@cs.utk.edu>
+ See pthreads-bugs transaction 31
+ pthread/queue.c (pthread_queue_remove()): Don't set thread->queue and
+ thread->next to NULL unless the thread is removed from the queue.
+ pthreads/fd.c (setsockopt(), getsockopt(), getsockname(),
+ getpeername()) : Call fd_lock() with appropriate paramaters.
+ pthreads/fd_kern.c (sendmsg_timedwait()): Call fd_unlock() with
+ FD_WRITE instead of FD_READ paramater.
+ machdep/*/timers.h net/res_send.c, pthreads/cond.c, pthreads/select.c
+ pthreads/sleep.c, tests/test_pthread_cond_timedwait.c:
+ Change timespec to be POSIX compliant.
+ include/unistd.h : Change u_int to unsigned [int] in prototypes.
+ pthreads/fd.c : Use FD_SETSIZE instead of 1024 for a limit on fds.
+
+
+For the 95/09/xx release version 1_60_beta4
+
+ Ports
+ SGI running IRIX-5.3
+
+ Additions
+ Added pthread_sigprocmask().
+ Added CV attributes
+
+ strtok() and strtok_r() (Greg Hudson)
+ getsockname() (Sean Levy)
+
+ Bug Fixes
+ stdio/fwalk.c, stdio/refill.c : Use flockfile() instead of
+ ftrylockfile()/pthread_yield(), for traversing FILE list.
+ pthreads/sig.c : Remove enum pthread_sig_flags and just use the vector.
+ Added pthread_sigprocmask().
+ pthreads/signal.c : Protect calls to pthread_sig_process().
+ configure : Create the obj directory.
+ tests/test_preemption_float.c : Rewritten to actually work.
+ machdep/engine-i386-linux-1.0.c : Added __strtol_internal()
+ tests/test_stdio_1.c : Don't use base_name or dir_name as variables.
+ gen/getcwd.c : fstat => machdep_sys_fstat, since kernel fd's are
+ used in the DIR data structure
+ gen/isatty.c : Fixed call to fd_lock() to pass the right # args.
+ pthreads/pthread_init.c : Fixed uninitialized members of
+ pthread_initial.
+
+
+
+For the 95/06/xx release version 1_60_beta3
+
+ Additions
+ Add exec variants execl, execlp, execv, execvp (Ken Raeburn)
+ pthreads/fd_sysv.c : Added routines setsockopt() and getsockname().
+ Added include/endian.h : For machine dependent endian junk. (YUCK)
+ Added socketpair()
+ Added ttyname_r()
+
+ Bug Fixes
+ config/Makefile.in : Need $$ to reference shell variables in make.
+ config/configure, config/configure.in : Redo freebsd2.* machine.
+ machdep/sunos-4.1.3/__stdlib.h : typedef pthread_size_t size_t
+ pthreads/fd.c : Fix bug with fd_free(), dup(), dup2(), and close()
+ where a fd gets lost after a dup() then close().
+ pthreads/fd_kern.c : The fd_table[fd]->flags of the fd that accept()
+ returns should be the same as those of the fd passed to accept().
+ stdio/fclose.c : Don't call funlockfile(fp) after fp->_file has been
+ closed.
+ pthreads/select.c : Move pthread_sched_prevent() inside the statement.
+ if (machdep_sys_select(...) == OK)
+ pthreads/machdep/linux-1.0/cdefs.h : moved the include_next outside
+ of the ifdef so that it would eventually find the system cdefs.h
+ pthreads/signal.c : Check sig_to_process before and after fd_kern_wait()
+ . It is possible for sig_handler_fake() to registered one.
+ pthreads/signal.c : Unset pthread_run temporarily around the call to
+ sig_handler(0). places where this causes core dumps should check
+ pthread_run.
+ include/stdlib.h : Fix prototype for bsearch().
+ machdep/syscall-i386-freebsd-2.0.S syscall-template-i386-freebsd2.0.S:
+ Fix macro expansion problems for FreeBSD-2.0
+ machdep/engine-sparc-sunos-5.3.c : Fix machdep_sys_select() to return
+ machdep_sys_poll() errors and not the number of entries found.
+ gen/getcwd.c : Use strlen(dp->d_name) not dp->d_namlen because there
+ may be extra data associated with dp->d_namelen.
+ machdep/freebsd-2.0/__unistd.h: Change #define _POSIX_VDISABLE to 0xff
+ include/pthread.h : Added prototypes pthread_kill(), pthread_signal()
+ machdep/linux-1.0/__signal.h : Added #define __sigmask() and
+ #define sigmask, and fixed other SIG macros to use __sigmask.
+ machdep/linux-1.0/dirent.h : #include <sys/types.h>
+ machdep/linux-1.0/wait.h : Fix #define WIFSTOPPED(x) to use __WSTATUS(x)
+ machdep/syscall-i386-linux-1.0.S : Added elf support. (NOT TESTED)
+ pthreads/stat.c : Added to separate linux stat calls.
+ (SGI will need this too)
+ pthreads/signal.c : Whereever #ifdef (SA_RESETHAND) is used then
+ #ifdef (SA_RESTART) also
+ gen/isatty.c : isatty_basic() is called with the KFD not UFD.
+ machdep/sunos-4.1.3/__stdlib.h : #include <sys/stdtypes.h>
+ config/sun4os4.mk : Added pipe to SYSCALL_EXCEPTIONS
+ machdep/syscall-sparc-sunos-4.1.3.S : Add machdep_sys_pipe().
+ include/stdio.h : Remove __getc() and __putc(), because they really
+ shouldn't be inlined.
+ machdep/sunos-4.1.3/stat.h : Added __BEGIN_DECLS and __END_DECLS.
+ machdep/alpha-osf1/cdefs.h, machdep/hpux-9.03/cdefs.h
+ machdep/linux-1.0/cdefs.h, machdep/sunos-4.1.3/cdefs.h
+ machdep/sunos-5.3/cdefs.h, machdep/ultrix-4.2/cdefs.h :
+ #define __INLINE static inline and don't #define
+ __CAN_DO_EXTERN_INLINE if __cplusplus and __GCC__ is defined.
+ pthreads/fd_sysv.c : Fix so that only systems without socket systemcalls
+ compile this file.
+ machdep/engine-i386-linux-1.0.c : Fix linux machdep_sys_getdirentries()
+ pthreads/gen : Nuke the signal-blocking code in pclose(). It doesn't do
+ any good in a threaded program; some other thread would just get
+ the signal.
+
+
+For the 94/11/xx release version 1_60
+
+ Additions
+ Added recvfrom_timedwait(), and similar calls
+ Added thread safe time routines: ctime(), localtime(), ...
+ Added thread safe rand routines: rand(), random(), ...
+ Added priorities and releated routines: pthread_attr_getschedparam(),
+ Added signals and releated routines:pthread_kill(), sigwait(), ...
+ Added mutex attribues and releated routines: pthread_mutexattr_init(), .
+ Added abort
+
+ Added counting (recursive) mutexes.
+ Added debugging mutexes.
+ Added some more tests
+
+ Redid entire thread kernel because of priorities, and signals.
+ Test and set instructions no longer necessary for versions
+ that don't support kernel threads.
+
+ More debugging by Greg Hudson along with the network lookup routines
+ An Alpha port from Ken Raeburn and Sean Levy
+ A solaris port from me.
+ select() implementations from Sean Levy and Peter Hofmann
+ configure from Ken Raeburn
+ pthread_init() no longer necessary for systems with G++ from Ken Raeburn
+ net code from Greg Hudson including: gethostbyname(), ...
+
+ Bug fixes:
+ honor _POSIX_THREAD_DESTRUCTOR_ITERATIONS
+ pthread_key_destroy() is really pthread_key_delete()
diff --git a/mit-pthreads/bin/.cvsignore b/mit-pthreads/bin/.cvsignore
new file mode 100644
index 00000000000..f3c7a7c5da6
--- /dev/null
+++ b/mit-pthreads/bin/.cvsignore
@@ -0,0 +1 @@
+Makefile
diff --git a/mit-pthreads/bin/Makefile.in b/mit-pthreads/bin/Makefile.in
new file mode 100644
index 00000000000..979ad2db2ea
--- /dev/null
+++ b/mit-pthreads/bin/Makefile.in
@@ -0,0 +1,48 @@
+# === GNUmakefile ============================================================
+# Copyright (c) 1993 Chris Provenzano, proven@athena.mit.edu
+#
+# Description: This file is for creating the test programs for libpthread.a
+#
+# 1.00 93/08/03 proven
+# -Initial cut for pthreads.
+#
+
+CC = ../pgcc -notinstalled
+srctop = @srctop@
+srcdir = @srctop@/lib
+VPATH = @srctop@/lib
+CDEBUGFLAGS = @CFLAGS@
+
+CFLAGS = $(CDEBUGFLAGS) $(INCLUDES) $(ADDL_CFLAGS) -DSRCDIR=\"$(srcdir)\"
+
+#
+DIRS = finger
+
+################################################################################
+#
+all:
+ (for i in $(DIRS); do cd $$i; $(MAKE) all; cd ..; done)
+
+clean:
+ (for i in $(DIRS); do cd $$i; $(MAKE) clean; cd ..; done)
+ rm -f *.o $(TESTS) $(BENCHMARKS) a.out core maketmp makeout
+
+depend:
+ (for i in $(DIRS); do cd $$i; $(MAKE) depend; cd ..; done)
+ sed '/\#\#\# Dependencies/q' < Makefile > maketmp
+ (for i in $(CSRC);do $(CPP) -M $$i;done) >> maketmp
+ cp maketmp Makefile
+
+install:
+ (for i in $(DIRS); do cd $$i; $(MAKE) install; cd ..; done)
+
+realclean: clean
+ (for i in $(DIRS); do cd $$i; $(MAKE) realclean; cd ..; done)
+ rm -f Makefile
+
+Makefile: Makefile.in
+ (cd .. ; sh config.status)
+
+################################################################################
+### Do not remove the following line. It is for depend #########################
+### Dependencies:
diff --git a/mit-pthreads/bin/finger/.cvsignore b/mit-pthreads/bin/finger/.cvsignore
new file mode 100644
index 00000000000..f3c7a7c5da6
--- /dev/null
+++ b/mit-pthreads/bin/finger/.cvsignore
@@ -0,0 +1 @@
+Makefile
diff --git a/mit-pthreads/bin/finger/Makefile.in b/mit-pthreads/bin/finger/Makefile.in
new file mode 100755
index 00000000000..ee20f47443d
--- /dev/null
+++ b/mit-pthreads/bin/finger/Makefile.in
@@ -0,0 +1,60 @@
+# === makefile ============================================================
+# Copyright (c) 1993 Chris Provenzano, proven@athena.mit.edu
+#
+# Description: This file is for creating the test programs for libpthread.a
+#
+# 1.00 93/08/03 proven
+# -Initial cut for pthreads.
+#
+
+srctop = @srctop@
+srcdir = @srctop@/bin/finger
+VPATH = @srctop@/bin/finger
+prefix= @prefix@
+exec_prefix= @exec_prefix@
+
+INSTALL_PATH = @exec_prefix@
+ BINDIR = $(INSTALL_PATH)/bin
+ LIBDIR = $(INSTALL_PATH)/lib
+ MANDIR = $(INSTALL_PATH)/man
+ INCDIR = $(INSTALL_PATH)/include
+
+ CC = ../../pgcc -notinstalled
+ CDEBUGFLAGS = @CFLAGS@
+ INCLUDES = -I@srctop@/lib/libpthreadutil/ -L../../lib/libpthreadutil/
+ CFLAGS = $(CDEBUGFLAGS) $(INCLUDES) $(ADDL_CFLAGS) -DSRCDIR=\"$(srcdir)\"
+ RANLIB = @RANLIB@
+
+ OBJS = finger.o net.o
+ BINARY = finger
+
+################################################################################
+#
+all : $(BINARY)
+
+clean:
+ rm -f *.o $(TESTS) $(BENCHMARKS) a.out core maketmp makeout
+
+depend:
+ sed '/\#\#\# Dependencies/q' < Makefile > maketmp
+ (for i in $(CSRC);do $(CPP) -M $$i;done) >> maketmp
+ cp maketmp Makefile
+
+install: $(BINARY)
+ install $(BINARY) $(BINDIR)
+
+realclean: clean
+ rm -f Makefile
+
+Makefile: Makefile.in
+ (cd ../.. ; sh config.status)
+
+.c.o:
+ $(CC) $(CFLAGS) -c $<
+
+$(BINARY) : ${OBJS}
+ $(CC) $(CFLAGS) -o $(BINARY) ${OBJS} -lpthreadutil
+
+################################################################################
+### Do not remove the following line. It is for depend #########################
+### Dependencies:
diff --git a/mit-pthreads/bin/finger/finger.c b/mit-pthreads/bin/finger/finger.c
new file mode 100755
index 00000000000..33b3011e8bb
--- /dev/null
+++ b/mit-pthreads/bin/finger/finger.c
@@ -0,0 +1,231 @@
+/* ==== finger.c ============================================================
+ * Copyright (c) 1993 by Chris Provenzano, proven@athena.mit.edu
+ *
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Tony Nardo of the Johns Hopkins University/Applied Physics Lab.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano,
+ * the University of California, Berkeley and its contributors.
+ * 4. Neither the name of Chris Provenzano, the University nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO, THE REGENTS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * 1.00 93/08/26 proven
+ * -Pthread redesign of this file.
+ *
+ * 1.10 95/02/11 proven
+ * -Now that gethostbyname works ....
+ */
+
+#ifndef lint
+char copyright[] =
+"@(#) Copyright (c) 1989 The Regents of the University of California.\n\
+ @(#) Copyright (c) 1993, 1995 Chris Provenzano.\n\
+ @(#) Copyright (c) 1995 Greg Stark.\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+#include <pthreadutil.h>
+#include <sys/param.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+void *netfinger();
+
+void usage(int eval)
+{
+ fprintf(stderr,
+ "usage: finger [-lps] [-c <net_count>] [-t|T <timeout>] [-f <filename>] [login ...]\n");
+ exit(eval);
+}
+
+/*
+ * These globals are set initialy and then are only read.
+ * They do not need mutexes.
+ */
+int thread_time = 0, program_timeout = 0, lflag = 0;
+pthread_tad_t parse_file_tad;
+pthread_tad_t netfinger_tad;
+
+void * timeout_thread(void * arg)
+{
+ sleep(program_timeout);
+ exit(0);
+}
+
+void * signal_thread(void * arg)
+{
+ int sig;
+ sigset_t program_signals;
+ sigemptyset(&program_signals);
+ sigaddset(&program_signals, SIGINT);
+ sigwait(&program_signals, &sig);
+ exit(0);
+}
+
+#ifndef MAXHOSTNAMELEN
+#define MAXHOSTNAMELEN 64
+#endif
+
+void * parse_file(void * arg)
+{
+ char hostname[MAXHOSTNAMELEN];
+ char * filename = arg;
+ pthread_atexit_t atexit_id;
+ pthread_attr_t attr;
+ pthread_t thread_id;
+ char * thread_arg;
+ FILE * fp;
+ int len;
+
+ netsetupwait();
+
+ /* Parse the file and create a thread per connection */
+ if ((fp = fopen(filename, "r")) == NULL) {
+ fprintf(stderr, "Can't open file %s\n", filename);
+ pthread_exit(NULL);
+ }
+ pthread_atexit_add(&atexit_id, fclose_nrv, fp);
+
+ if (pthread_attr_init(&attr)) {
+ fprintf(stderr, "Error: Can't initialize thread attributes\n");
+ exit(2);
+ }
+ pthread_atexit_add(&atexit_id, pthread_attr_destroy_nrv, &attr);
+
+ while (fgets(hostname, MAXHOSTNAMELEN, fp)) {
+ if ((thread_arg = (char *)malloc(len = strlen(hostname))) == NULL) {
+ fprintf(stderr, "Error: out of memory\n");
+ exit(2);
+ }
+
+ hostname[len - 1] = '\0';
+ strcpy(thread_arg, hostname);
+ pthread_attr_setcleanup(&attr, free, thread_arg);
+ if (pthread_tad_create(&netfinger_tad, &thread_id, NULL,
+ netfinger, thread_arg)) {
+ fprintf(stderr, "Error: pthread_tad_create() netfinger_tad.\n");
+ exit(2);
+ }
+ }
+ pthread_exit(NULL);
+}
+
+main(int argc, char **argv)
+{
+ pthread_atexit_t atexit_id;
+ pthread_t thread_id;
+ int max_count = 0;
+ char ch;
+
+ /* getopt variables */
+ extern char *optarg;
+ extern int optind;
+
+ /* Setup tad for parse_file() threads */
+ if (pthread_tad_init(&parse_file_tad, max_count)) {
+ fprintf(stderr,"Error: couldn't create parse_file() TAD.\n");
+ exit(1);
+ }
+
+ while ((ch = getopt(argc, argv, "c:f:t:T:ls")) != (char)EOF)
+ switch(ch) {
+ case 't': /* Time to let each thread run */
+ if ((thread_time = atoi(optarg)) <= 0) {
+ usage(1);
+ }
+ break;
+ case 'T': /* Time to let entire program run */
+ if ((program_timeout = atoi(optarg)) <= 0) {
+ usage(1);
+ }
+ break;
+ case 'f': /* Parse file for list of places to finger */
+ if (pthread_tad_create(&parse_file_tad, &thread_id, NULL,
+ parse_file, optarg)) {
+ fprintf(stderr,"Error: pthread_tad_create() parse_file_tad.\n");
+ exit(1);
+ }
+ break;
+ case 'c':
+ max_count = atoi(optarg);
+ break;
+ case 'l': /* long format */
+ lflag = 1;
+ break;
+ case 's': /* short format */
+ lflag = 0;
+ break;
+ case '?':
+ usage(0);
+ default:
+ usage(1);
+ }
+
+ /* The rest of the argumants are hosts */
+ argc -= optind;
+ argv += optind;
+
+ /* Setup timeout thread, if there is one */
+ if (program_timeout) {
+ if (pthread_create(&thread_id, NULL, timeout_thread, NULL)) {
+ fprintf(stderr,"Error: couldn't create program_timeout() thread\n");
+ exit(1);
+ }
+ }
+
+ /* Setup cleanup thread for signals */
+ if (pthread_create(&thread_id, NULL, signal_thread, NULL)) {
+ fprintf(stderr,"Error: couldn't create signal_timeout() thread\n");
+ exit(1);
+ }
+
+ /* Setup tad for netfinger() threads */
+ if (pthread_tad_init(&netfinger_tad, max_count)) {
+ fprintf(stderr,"Error: couldn't create netfinger() TAD.\n");
+ exit(1);
+ }
+
+ /* Setup the net and let everyone run */
+ netsetup();
+
+ while (*argv) {
+ if (pthread_tad_create(&netfinger_tad, &thread_id, NULL,
+ netfinger, *argv)) {
+ fprintf(stderr, "Error: pthread_tad_create() netfinger_tad.\n");
+ exit(2);
+ }
+ argv++;
+ }
+ pthread_tad_wait(&parse_file_tad, 0);
+ pthread_tad_wait(&netfinger_tad, 0);
+ exit(0);
+}
+
diff --git a/mit-pthreads/bin/finger/net.c b/mit-pthreads/bin/finger/net.c
new file mode 100755
index 00000000000..77ccd92ee8c
--- /dev/null
+++ b/mit-pthreads/bin/finger/net.c
@@ -0,0 +1,189 @@
+/* ==== net.c ============================================================
+ * Copyright (c) 1993, 1995 by Chris Provenzano, proven@athena.mit.edu
+ *
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Tony Nardo of the Johns Hopkins University/Applied Physics Lab.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * 1.00 93/08/26 proven
+ * -Pthread redesign of this file.
+ */
+
+#include <pthreadutil.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/param.h>
+#include <netinet/in.h>
+#include <stdlib.h>
+#include <string.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <ctype.h>
+
+#ifndef MAXHOSTNAMELEN
+#define MAXHOSTNAMELEN 64
+#endif
+/*
+ * These globals are set initialy and then are only read.
+ * They do not need mutexes.
+ */
+extern int lflag;
+char myhostname[MAXHOSTNAMELEN];
+
+/*
+ * These globals change and therefor do need mutexes
+ */
+pthread_mutex_t spmutex = PTHREAD_MUTEX_INITIALIZER;
+pthread_cond_t spcond = PTHREAD_COND_INITIALIZER;
+struct servent *sp = NULL;
+
+void netsetup(void)
+{
+ pthread_mutex_lock(&spmutex);
+ if (sp) {
+ fprintf(stderr, "finger: service pointer already initialized.\n");
+ exit(2);
+ }
+ if ((sp = (struct servent *)malloc(sizeof(struct servent) + 4096)) == NULL){
+ fprintf(stderr, "finger: Couldn't allocate service pointer.\n");
+ exit(2);
+ }
+ if (getservbyname_r("finger", "tcp", sp, (char *)sp + sizeof(struct servent), 4096) == NULL) {
+ fprintf(stderr, "finger: tcp/finger: unknown service\n");
+ exit(2);
+ }
+ if (gethostname(myhostname, MAXHOSTNAMELEN)) {
+ fprintf(stderr, "finger: couldn't get my hostname.\n");
+ exit(2);
+ }
+ pthread_cond_broadcast(&spcond);
+ pthread_mutex_unlock(&spmutex);
+}
+
+void netsetupwait(void)
+{
+ pthread_mutex_lock(&spmutex);
+ while(sp == NULL) {
+ pthread_cond_wait(&spcond, &spmutex);
+ }
+ pthread_mutex_unlock(&spmutex);
+}
+
+void *netfinger(char *name)
+{
+ pthread_atexit_t atexit_id;
+ register int c, lastc;
+ struct in_addr defaddr;
+ struct hostent *hp;
+ struct sockaddr_in sin;
+ int s, i, readbuflen;
+ char readbuf[1024];
+ char *host;
+
+ netsetupwait();
+ pthread_atexit_add(&atexit_id, fflush_nrv, NULL);
+
+ if (!(host = strrchr(name, '@'))) {
+ host = myhostname;
+ } else {
+ *host++ = '\0';
+ }
+ if (!(hp = gethostbyname(host))) {
+ if ((defaddr.s_addr = inet_addr(host)) < 0) {
+ fprintf(stderr, "[%s] gethostbyname: Unknown host\n", host);
+ return;
+ }
+ }
+ sin.sin_family = hp->h_addrtype;
+ memcpy((char *)&sin.sin_addr, hp->h_addr, hp->h_length);
+ sin.sin_port = sp->s_port;
+
+ if ((s = socket(sin.sin_family, SOCK_STREAM, 0)) < 0) {
+ sprintf(readbuf, "[%s]: socket", hp->h_name);
+ perror(readbuf);
+ return;
+ }
+
+ /* have network connection; identify the host connected with */
+ if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
+ sprintf(readbuf, "[%s]: connect", hp->h_name);
+ perror(readbuf);
+ close(s);
+ return;
+ }
+
+ /* -l flag for remote fingerd */
+ if (lflag)
+ write(s, "/W ", 3);
+ /* send the name followed by <CR><LF> */
+ write(s, name, strlen(name));
+ write(s, "\r\n", 2);
+
+ /*
+ * Read from the remote system; once we're connected, we assume some
+ * data. If none arrives, we hang until the user interrupts, or
+ * until the thread timeout expires.
+ *
+ * If we see a <CR> or a <CR> with the high bit set, treat it as
+ * a newline; if followed by a newline character, only output one
+ * newline.
+ *
+ * Otherwise, all high bits are stripped; if it isn't printable and
+ * it isn't a space, we can simply set the 7th bit. Every ASCII
+ * character with bit 7 set is printable.
+ */
+ for (readbuflen = read(s, readbuf, 1024), flockfile(stdout), lastc = '\n',
+ printf("[%s]\n", hp->h_name); readbuflen > 0;
+ readbuflen = read(s, readbuf, 1024)) {
+ for (i = 0; i < readbuflen; i++) {
+ c = readbuf[i] & 0x7f;
+ if (c == 0x0d) {
+ c = '\n';
+ lastc = '\r';
+ } else {
+ if (!isprint(c) && !isspace(c))
+ c |= 0x40;
+ if (lastc != '\r' || c != '\n')
+ lastc = c;
+ else {
+ lastc = '\n';
+ continue;
+ }
+ }
+ putchar_unlocked(c);
+ }
+ }
+ if (lastc != '\n')
+ putchar_unlocked('\n');
+ funlockfile(stdout);
+}
diff --git a/mit-pthreads/config/COPYING.GNU b/mit-pthreads/config/COPYING.GNU
new file mode 100755
index 00000000000..a43ea2126fb
--- /dev/null
+++ b/mit-pthreads/config/COPYING.GNU
@@ -0,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ 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.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. 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.
+
+ 1. 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.
+
+ 2. 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:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) 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.
+
+ c) 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.)
+
+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.
+
+ 3. 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:
+
+ a) 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,
+
+ b) 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,
+
+ c) 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.)
+
+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.
+
+ 4. 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.
+
+ 5. 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.
+
+ 6. 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.
+
+ 7. 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.
+
+ 8. 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.
+
+ 9. 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.
+
+ 10. 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.
+
+ NO WARRANTY
+
+ 11. 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.
+
+ 12. 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 OF TERMS AND CONDITIONS
+
+ Appendix: 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.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+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:
+
+ Gnomovision version 69, Copyright (C) 19yy 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.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `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:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+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.
diff --git a/mit-pthreads/config/COPYRIGHT b/mit-pthreads/config/COPYRIGHT
new file mode 100755
index 00000000000..ba3ac43c589
--- /dev/null
+++ b/mit-pthreads/config/COPYRIGHT
@@ -0,0 +1,4 @@
+The files config.guess and config.sub in this directory come from the GNU
+autoconf distribution, and are covered by the GNU Public License, which may
+be found in the file COPYING.GNU. They are the only files covered by the
+GPL.
diff --git a/mit-pthreads/config/GNUmakefile.in b/mit-pthreads/config/GNUmakefile.in
new file mode 100755
index 00000000000..7c06ee367e6
--- /dev/null
+++ b/mit-pthreads/config/GNUmakefile.in
@@ -0,0 +1,129 @@
+# === GNUmakefile =============================================================
+# Copyright (c) 1991, 1992, 1993 Chris Provenzano, proven@athena.mit.edu
+#
+# Description: This file is for creating libpthread.a
+#
+# 1.00 93/11/17 proven
+# -Put all the .o files into one file libpthread.a
+# -Initial cut for pthreads.
+#
+
+INSTALL_PATH = $(exec_prefix)
+
+ BINDIR = $(INSTALL_PATH)/bin
+ LIBDIR = $(INSTALL_PATH)/lib
+ MANDIR = $(INSTALL_PATH)/man
+ INCDIR = $(INSTALL_PATH)/include
+ SUBINCDIR = $(INCDIR)/pthread
+
+ AR = ar
+ AS = gas
+ CFLAGS = -I. -Iinclude -I$(srcdir)/include -DPTHREAD_KERNEL \
+ @CFLAGS@
+ CXXFLAGS = -I. -Iinclude -I$(srcdir)/include -DPTHREAD_KERNEL \
+ @CXXFLAGS@
+ LD = gld
+
+ CSRC =
+
+ PTHREAD_DIR = pthreads stdlib stdio gen
+ DIRS = $(PTHREAD_DIR)
+
+ HEADERS =
+
+ LIBRARIES = libpthread.a
+
+ .CURDIR = .
+
+# force correct default target
+all:
+
+###############################################################################
+#
+# Read in any special flags that config knows about
+include config.flags
+
+# What the heck. Convert srcdir to absolute form so it looks prettier.
+srcdir := $(shell cd $(srcfoo) && pwd)
+
+################################################################################
+#
+# Here starts the nitty grity part of the Makefile.
+
+all-lib : libpthread.a
+
+include ${srcdir}/pthreads/GNUmakefile.inc
+include ${srcdir}/stdlib/GNUmakefile.inc
+include ${srcdir}/stdio/GNUmakefile.inc
+include ${srcdir}/string/GNUmakefile.inc
+include ${srcdir}/gen/GNUmakefile.inc
+include ${srcdir}/net/GNUmakefile.inc
+include ${srcdir}/scripts/GNUmakefile.inc
+
+REGULAR_OBJS= $(subst .cc,.o,$(SRCS))
+REGULAR_OBJS:= $(subst .c,.o,$(REGULAR_OBJS))
+REGULAR_OBJS:= $(subst .S,.o,$(REGULAR_OBJS))
+OBJS= $(REGULAR_OBJS) $(EXTRA_OBJS)
+REALOBJS = $(addprefix obj/, $(OBJS))
+
+$(REALOBJS) : $(config) $(types) $(paths)
+
+# Since we do not have a list of the relevant files we do a make clean
+# before copying everyting to the distribution directory.
+distdir:
+ $(MAKE) clean
+ cp -a . $(distdir)
+ # Remove symlinks that the distribution should not have.
+ rm -f $(distdir)/config.cache \
+ $(distdir)/include/pthread/machdep.h \
+ $(distdir)/include/pthread/posix.h \
+ $(distdir)/include/sys \
+ $(distdir)/machdep.c \
+ $(distdir)/syscall.S \
+ $(distdir)/syscall-template.S
+
+clean:
+ rm -f a.out core maketmp makeout $(LIBRARIES) $(BINARIES) libpthread.*
+ rm -rf obj
+ cd tests && $(MAKE) clean && cd ..
+
+install-lib: $(LIBRARIES) install-dirs
+ for x in $(LIBRARIES); \
+ do install $$x $(DESTDIR)$(LIBDIR); \
+ done
+
+# Removed make install since mysql uses this in place.
+# install-lib install-include install-bin
+install:
+
+libpthread.a: obj/libpthread.a
+ rm -f libpthread.a
+ ln -s obj/libpthread.a .
+
+obj/libpthread.a: ${REALOBJS}
+ rm -f libpthread.a obj/new.a obj/libpthread.a
+ cd obj && \
+ ar r new.a ${OBJS} && \
+ $(RANLIB) new.a && \
+ mv -f new.a libpthread.a && \
+ cd ..
+
+# For examining a combined symbol table, sizes, &c.
+libpthread.o: ${REALOBJS}
+ cd obj && ld -r -o ../libpthread.o ${OBJS} && cd ..
+
+obj/x:
+ if [ -d obj ]; then true; else mkdir obj; fi
+ cp /dev/null obj/x
+
+GNUmakefile: config.status ${srcdir}/config/GNUmakefile.in
+ $(SHELL) config.status
+
+obj/%.o: %.c obj/x
+ $(CC) $(CFLAGS) -c $< -o $@
+
+obj/%.o: %.cc obj/x
+ $(CXX) $(CXXFLAGS) $(CFLAGS) -c $< -o $@
+
+obj/%.o: %.S obj/x
+ $(CC) $(CFLAGS) -c $< -o $@
diff --git a/mit-pthreads/config/Makefile.in b/mit-pthreads/config/Makefile.in
new file mode 100644
index 00000000000..3fa388d740b
--- /dev/null
+++ b/mit-pthreads/config/Makefile.in
@@ -0,0 +1,56 @@
+# @(#)Makefile 5.2 (Berkeley) 3/5/91
+#
+
+LIB=pthread
+NOPIC=1
+NOPROFILE=1
+NOLINT=1
+MKPIC=no
+MKPROFILE=no
+MKLINT=no
+CPPFLAGS+= -I${.CURDIR} -I${.CURDIR}/include -I${srcdir}/include -DPTHREAD_KERNEL
+CDEBUGFLAGS= @CFLAGS@
+CFLAGS+= ${CDEBUGFLAGS}
+# CFLAGS+= ${CPPFLAGS} <- done by bsd.lib.mk
+CFLAGS+= ${CPPFLAGS}
+LIBDIR= $(exec_prefix)/lib
+BINDIR= $(exec_prefix)/bin
+INCDIR= $(exec_prefix)/include
+MANDIR= $(exec_prefix)/man
+
+.OBJDIR != if test -d ${.CURDIR}/obj ; then true ; else mkdir ${.CURDIR}/obj || exit 1 ; fi ; echo ${.CURDIR}/obj
+
+# Standard bsd install rules look for the "install" program, rather than
+# using some variable. So, hack things so that that install rule works.
+BINGRP != echo " " `groups` " " | sed 's/ [0-9][0-9]* / /g' | awk '{print $$1}'
+BINOWN != echo $${USER}
+LIBMODE = 644 # so ranlib can run!
+
+.include "config.flags"
+
+# %!$@ pmake seems to automagically cd into the obj directory, so relative
+# srcdir references are completely botched. Try to figure out an absolute
+# pathname for srcdir here, and live with it.
+srcdir = $(srctop)
+
+beforeinstall: install-dirs
+
+.include "${srcdir}/pthreads/Makefile.inc"
+.include "${srcdir}/stdlib/Makefile.inc"
+.include "${srcdir}/stdio/Makefile.inc"
+.include "${srcdir}/string/Makefile.inc"
+.include "${srcdir}/gen/Makefile.inc"
+.include "${srcdir}/net/Makefile.inc"
+.include "${srcdir}/scripts/Makefile.inc"
+
+$(OBJS) : $(config) $(types) $(paths)
+
+Makefile: ${srcdir}/config/Makefile.in
+ cd ${.CURDIR} && sh config.status
+
+all-lib : libpthread.a
+# Removed make install since mysql uses this in place.
+#install : install-bin install-include
+install:
+
+.include <bsd.lib.mk>
diff --git a/mit-pthreads/config/acconfig.h b/mit-pthreads/config/acconfig.h
new file mode 100644
index 00000000000..14552b0d851
--- /dev/null
+++ b/mit-pthreads/config/acconfig.h
@@ -0,0 +1,73 @@
+/* Does the OS already support struct timespec */
+#undef _OS_HAS_TIMESPEC
+
+/* For networking code: an integral type the size of an IP address (4
+ octets). Determined by examining return values from certain
+ functions. */
+#undef pthread_ipaddr_type
+
+/* For networking code: an integral type the size of an IP port number
+ (2 octets). Determined by examining return values from certain
+ functions. */
+#undef pthread_ipport_type
+
+/* type of clock_t, from system header files */
+#undef pthread_clock_t
+
+/* Specially named so grep processing will find it and put it into the
+ generated ac-types.h. */
+#undef pthread_have_va_list_h
+
+/* type of size_t, from system header files */
+#undef pthread_size_t
+
+/* type of ssize_t, from system header files */
+#undef pthread_ssize_t
+
+/* type of time_t, from system header files */
+#undef pthread_time_t
+
+/* type of fpos_t, from system header files */
+#undef pthread_fpos_t
+
+/* type of off_t, from system header files */
+#undef pthread_off_t
+
+/* type of va_list, from system header files */
+#undef pthread_va_list
+
+/* type of sigset_t, from system header files */
+#undef pthread_sigset_t
+
+/* I don't know why the native compiler definitions aren't sufficient
+ for this. */
+#undef sunos4
+
+/* define if the linker hauls in certain static data from libc even when
+ you don't want it to. yes, this description is bogus, but chris added
+ the need for this, without describing the problem. */
+#undef LD_LINKS_STATIC_DATA
+
+/* define if the system reissues the SIGCHLD if the handler reinstalls
+ * itself before calling wait()
+ */
+#undef BROKEN_SIGNALS
+
+/* where are terminal devices to be found? */
+#undef _PATH_PTY
+
+/* what directory holds the time zone info on this system? */
+#undef _PATH_TZDIR
+
+/* what file indicates the local time zone? */
+#undef _PATH_TZFILE
+
+/* Paths for various networking support files. */
+#undef _PATH_RESCONF
+#undef _PATH_HOSTS
+#undef _PATH_NETWORKS
+#undef _PATH_PROTOCOLS
+#undef _PATH_SERVICES
+
+/* Path for Bourne shell. */
+#undef _PATH_BSHELL
diff --git a/mit-pthreads/config/aclocal.m4 b/mit-pthreads/config/aclocal.m4
new file mode 100755
index 00000000000..2a5cd3e9cbf
--- /dev/null
+++ b/mit-pthreads/config/aclocal.m4
@@ -0,0 +1,94 @@
+dnl Autoconf extensions for pthreads package.
+dnl
+ifelse(regexp(AC_DEFINE(xxxxx),.*@@@.*),-1,,[define(IS_AUTOHEADER)])])dnl
+dnl
+dnl Now, the real stuff needed by the pthreads package.
+dnl
+AC_DEFUN([PTHREADS_CHECK_ONE_SYSCALL],
+[AC_MSG_CHECKING(for syscall $1)
+AC_CACHE_VAL(pthreads_cv_syscall_$1,
+AC_TRY_LINK([
+/* FIXME: This list should be generated from info in configure.in. */
+#ifdef HAVE_SYSCALL_H
+#include <syscall.h>
+#else
+#ifdef HAVE_SYS_SYSCALL_H
+#include <sys/syscall.h>
+#else
+where is your syscall header file??
+#endif
+#endif
+],[
+int x;
+x = SYS_$1 ;
+],
+eval pthreads_cv_syscall_$1=yes,
+eval pthreads_cv_syscall_$1=no))
+if eval test \$pthreads_cv_syscall_$1 = yes ; then
+ pthreads_syscall_present=yes
+ available_syscalls="$available_syscalls $1"
+dnl Can't just do the obvious substitution here or autoheader gets
+dnl sorta confused. (Sigh.) Getting the requoting of the brackets right
+dnl would be a pain too.
+ macroname=HAVE_SYSCALL_`echo $1 | tr '[[[a-z]]]' '[[[A-Z]]]'`
+ AC_DEFINE_UNQUOTED($macroname)
+else
+ pthreads_syscall_present=no
+ missing_syscalls="$missing_syscalls $1"
+fi
+AC_MSG_RESULT($pthreads_syscall_present)
+])dnl
+dnl
+AC_DEFUN(PTHREADS_CHECK_SYSCALLS,dnl
+ifdef([IS_AUTOHEADER],[#
+dnl Need to fake out autoheader, since there's no way to add a new class
+dnl of features to generate config.h.in entries for.
+@@@syscalls="$1"@@@
+@@@funcs="$funcs syscall_`echo $syscalls | sed 's/ / syscall_/g'`"@@@
+],
+[pthreads_syscall_list="$1"
+for pthreads_syscallname in $pthreads_syscall_list ; do
+ PTHREADS_CHECK_ONE_SYSCALL([$]pthreads_syscallname)
+done
+]))dnl
+dnl
+dnl Requote each argument.
+define([requote], [ifelse($#, 0, , $#, 1, "$1",
+ "$1" [requote(builtin(shift,$@))])])dnl
+dnl
+dnl Determine proper typedef value for a typedef name, and define a
+dnl C macro to expand to that type. (A shell variable with that value
+dnl is also created.) If none of the specified types to try match, the
+dnl macro is left undefined, and the shell variable empty. If the
+dnl typedef name cannot be found in the specified header files, this
+dnl test errors out; perhaps it should be changed to simply leave the
+dnl macro undefined...
+dnl
+dnl PTHREADS_FIND_TYPE(typedefname,varname,includes,possible values...)
+dnl
+AC_DEFUN(PTHREADS_FIND_TYPE,
+ifdef([IS_AUTOHEADER],[#
+@@@syms="$syms $2"@@@
+],[dnl
+AC_MSG_CHECKING(type of $1)
+AC_CACHE_VAL(pthreads_cv_type_$1,
+[AC_TRY_COMPILE([$3],[ extern $1 foo; ],
+[ for try_type in [requote(builtin(shift,builtin(shift,builtin(shift,$@))))] ; do
+ AC_TRY_COMPILE([$3],[ extern $1 foo; extern $try_type foo; ],
+ [ pthreads_cv_type_$1="$try_type" ; break ])
+ done],
+ AC_MSG_ERROR(Can't find system typedef for $1.))])
+if test -n "$pthreads_cv_type_$1" ; then
+ AC_DEFINE_UNQUOTED($2,$pthreads_cv_type_$1)
+fi
+$2=$pthreads_cv_type_$1
+AC_MSG_RESULT($pthreads_cv_type_$1)]))dnl
+dnl
+dnl
+dnl Like above, but the list of types to try is pre-specified.
+dnl
+AC_DEFUN(PTHREADS_FIND_INTEGRAL_TYPE,[
+PTHREADS_FIND_TYPE([$1], [$2], [$3],
+ int, unsigned int, long, unsigned long,
+ short, unsigned short, char, unsigned char,
+ long long, unsigned long long)])dnl
diff --git a/mit-pthreads/config/config.flags.in b/mit-pthreads/config/config.flags.in
new file mode 100755
index 00000000000..3d16423a045
--- /dev/null
+++ b/mit-pthreads/config/config.flags.in
@@ -0,0 +1,80 @@
+# Since the real configure script runs from the config subdirectory,
+# compensate here...
+srctop= @srctop@
+srcfoo= $(srctop)
+
+prefix= @prefix@
+exec_prefix= @exec_prefix@
+
+cpu = @target_cpu@
+os = @target_os@
+
+MISSING_SYSCALLS = @missing_syscalls@
+AVAILABLE_SYSCALLS = @available_syscalls@
+SYSCALL_EXCEPTIONS = @SYSCALL_EXCEPTIONS@
+HAVE_SYSCALL_TEMPLATE = @HAVE_SYSCALL_TEMPLATE@
+
+CC = @CC@
+CXX = @CXX@
+CPP = @CPP@
+SHELL = /bin/sh
+RANLIB = @RANLIB@
+# Should use autoconf to find these. Currently our makefiles are inconsistent.
+#AR = ar
+#AS = gas
+#LD = gld
+
+install-dirs:
+ for d in $(INSTALL_PATH) $(BINDIR) $(LIBDIR) $(INCDIR) ; do \
+ test -d $(DESTDIR)$$d || mkdir $(DESTDIR)$$d || exit 1 ; \
+ done
+
+config.status: @srcdir@/configure
+ cd ${.CURDIR} && $(SHELL) config.status --recheck
+config.flags: config.status @srcdir@/config.flags.in
+ cd ${.CURDIR} && $(SHELL) config.status
+
+realclean: clean
+ cd tests && $(MAKE) realclean && cd ..
+ rm -f $(LINKS) config.status config.flags config.cache \
+ Makefile GNUmakefile
+
+types=$(.CURDIR)/include/pthread/ac-types.h
+$(types) : config.h
+ echo '#ifndef pthread_size_t' > $(types).new
+ egrep '^#define pthread_' $(.CURDIR)/config.h >> $(types).new
+ echo '#endif' >> $(types).new
+ mv -f $(types).new $(types)
+
+config=$(.CURDIR)/include/pthread/config.h
+$(config) : config.h
+ echo '#ifndef _SYS___CONFIG_H_' > $(config).new
+ echo '#define _SYS___CONFIG_H_' >> $(config).new
+ -egrep '^#define _OS_HAS' $(.CURDIR)/config.h >> $(config).new
+ echo '#endif' >> $(config).new
+ mv -f $(config).new $(config)
+
+paths=$(.CURDIR)/include/pthread/paths.h
+$(paths) : config.h
+ echo '#ifndef _SYS___PATHS_H_' > $(paths).new
+ echo '#define _SYS___PATHS_H_' >> $(paths).new
+ egrep '^#define _PATH' $(.CURDIR)/config.h >> $(paths).new
+ echo '#endif' >> $(paths).new
+ mv -f $(paths).new $(paths)
+
+all-tests: all-lib
+ cd ${.CURDIR}/tests && $(MAKE) all
+check: all-lib
+ cd ${.CURDIR}/tests && $(MAKE) check
+all : all-lib all-bin
+
+install-bin: all-bin install-dirs
+ for x in $(SCRIPTS) ; do \
+ install $$x $(DESTDIR)$(BINDIR); \
+ done
+
+install-include: install-dirs
+ (cd ${srcdir}/include && tar chf - .)|(cd $(DESTDIR)$(INCDIR) && tar xf -)
+ if [ -d config ]; then true; else \
+ (cd ${.CURDIR}/include && tar chf - .)|(cd $(DESTDIR)$(INCDIR) && tar xf -); fi
+ (cd $(DESTDIR)$(INCDIR) && find . \( -name CVS -o -name \*~ \) -print | xargs rm -rf)
diff --git a/mit-pthreads/config/config.guess b/mit-pthreads/config/config.guess
new file mode 100755
index 00000000000..36fb26d3998
--- /dev/null
+++ b/mit-pthreads/config/config.guess
@@ -0,0 +1,504 @@
+#!/bin/sh
+# Attempt to guess a canonical system name.
+# Copyright (C) 1992, 1993, 1994 Free Software Foundation, Inc.
+#
+# 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Written by Per Bothner <bothner@cygnus.com>.
+# The master version of this file is at the FSF in /home/gd/gnu/lib.
+#
+# This script attempts to guess a canonical system name similar to
+# config.sub. If it succeeds, it prints the system name on stdout, and
+# exits with 0. Otherwise, it exits with 1.
+#
+# The plan is that this can be called by configure scripts if you
+# don't specify an explicit system type (host/target name).
+#
+# Only a few systems have been added to this list; please add others
+# (but try to keep the structure clean).
+#
+
+# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
+# (ghazi@noc.rutgers.edu 8/24/94.)
+if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
+ PATH=$PATH:/.attbin ; export PATH
+fi
+
+UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
+UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
+UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown
+UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
+
+trap 'rm -f dummy.c dummy.o dummy; exit 1' 1 2 15
+
+# Note: order is significant - the case branches are not exclusive.
+
+case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
+ alpha:OSF1:V*:*)
+ # After 1.2, OSF1 uses "V1.3" for uname -r.
+ echo alpha-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^V//'`
+ exit 0 ;;
+ alpha:OSF1:*:*)
+ # 1.2 uses "1.2" for uname -r.
+ echo alpha-dec-osf${UNAME_RELEASE}
+ exit 0 ;;
+ arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
+ echo arm-acorn-riscix${UNAME_RELEASE}
+ exit 0;;
+ Pyramid*:OSx*:*:*)
+ if test "`(/bin/universe) 2>/dev/null`" = att ; then
+ echo pyramid-pyramid-sysv3
+ else
+ echo pyramid-pyramid-bsd
+ fi
+ exit 0 ;;
+ sun4*:SunOS:5.*:*)
+ echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit 0 ;;
+ sun4*:SunOS:6*:*)
+ # According to config.sub, this is the proper way to canonicalize
+ # SunOS6. Hard to guess exactly what SunOS6 will be like, but
+ # it's likely to be more like Solaris than SunOS4.
+ echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit 0 ;;
+ sun4*:SunOS:*:*)
+ # Japanese Language versions have a version number like `4.1.3-JL'.
+ echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
+ exit 0 ;;
+ sun3*:SunOS:*:*)
+ echo m68k-sun-sunos${UNAME_RELEASE}
+ exit 0 ;;
+ RISC*:ULTRIX:*:*)
+ echo mips-dec-ultrix${UNAME_RELEASE}
+ exit 0 ;;
+ VAX*:ULTRIX*:*:*)
+ echo vax-dec-ultrix${UNAME_RELEASE}
+ exit 0 ;;
+ mips:*:5*:RISCos)
+ echo mips-mips-riscos${UNAME_RELEASE}
+ exit 0 ;;
+ m88k:CX/UX:7*:*)
+ echo m88k-harris-cxux7
+ exit 0 ;;
+ m88k:*:4*:R4*)
+ echo m88k-motorola-sysv4
+ exit 0 ;;
+ m88k:*:3*:R3*)
+ echo m88k-motorola-sysv3
+ exit 0 ;;
+ AViiON:dgux:*:*)
+ if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx \
+ -o ${TARGET_BINARY_INTERFACE}x = x ] ; then
+ echo m88k-dg-dgux${UNAME_RELEASE}
+ else
+ echo m88k-dg-dguxbcs${UNAME_RELEASE}
+ fi
+ exit 0 ;;
+ M88*:DolphinOS:*:*) # DolphinOS (SVR3)
+ echo m88k-dolphin-sysv3
+ exit 0 ;;
+ M88*:*:R3*:*)
+ # Delta 88k system running SVR3
+ echo m88k-motorola-sysv3
+ exit 0 ;;
+ XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
+ echo m88k-tektronix-sysv3
+ exit 0 ;;
+ Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
+ echo m68k-tektronix-bsd
+ exit 0 ;;
+ *:IRIX:*:*)
+ echo mips-sgi-irix${UNAME_RELEASE}
+ exit 0 ;;
+ i[34]86:AIX:*:*)
+ echo i386-ibm-aix
+ exit 0 ;;
+ *:AIX:2:3)
+ if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
+ sed 's/^ //' << EOF >dummy.c
+ #include <sys/systemcfg.h>
+
+ main()
+ {
+ if (!__power_pc())
+ exit(1);
+ puts("powerpc-ibm-aix3.2.5");
+ exit(0);
+ }
+EOF
+ ${CC-cc} dummy.c -o dummy && ./dummy && rm dummy.c dummy && exit 0
+ rm -f dummy.c dummy
+ echo rs6000-ibm-aix3.2.5
+ elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
+ echo rs6000-ibm-aix3.2.4
+ else
+ echo rs6000-ibm-aix3.2
+ fi
+ exit 0 ;;
+ *:AIX:*:4)
+ if /usr/sbin/lsattr -EHl proc0 | grep POWER >/dev/null 2>&1; then
+ IBM_ARCH=rs6000
+ else
+ IBM_ARCH=powerpc
+ fi
+ if grep bos410 /usr/include/stdio.h >/dev/null 2>&1; then
+ IBM_REV=4.1
+ elif grep bos411 /usr/include/stdio.h >/dev/null 2>&1; then
+ IBM_REV=4.1.1
+ else
+ IBM_REV=4.${UNAME_RELEASE}
+ fi
+ echo ${IBM_ARCH}-ibm-aix${IBM_REV}
+ exit 0 ;;
+ *:AIX:*:*)
+ echo rs6000-ibm-aix
+ exit 0 ;;
+ *:BOSX:*:*)
+ echo rs6000-bull-bosx
+ exit 0 ;;
+ DPX/2?00:B.O.S.:*:*)
+ echo m68k-bull-sysv3
+ exit 0 ;;
+ 9000/[34]??:4.3bsd:1.*:*)
+ echo m68k-hp-bsd
+ exit 0 ;;
+ hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
+ echo m68k-hp-bsd4.4
+ exit 0 ;;
+ 9000/[3478]??:HP-UX:*:*)
+ case "${UNAME_MACHINE}" in
+ 9000/31? ) HP_ARCH=m68000 ;;
+ 9000/[34]?? ) HP_ARCH=m68k ;;
+ 9000/7?? | 9000/8?7 ) HP_ARCH=hppa1.1 ;;
+ 9000/8?? ) HP_ARCH=hppa1.0 ;;
+ esac
+ HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+ echo ${HP_ARCH}-hp-hpux${HPUX_REV}
+ exit 0 ;;
+ 3050*:HI-UX:*:*)
+ sed 's/^ //' << EOF >dummy.c
+ #include <unistd.h>
+ int
+ main ()
+ {
+ long cpu = sysconf (_SC_CPU_VERSION);
+ /* The order matters, because CPU_IS_HP_MC68K erroneously returns
+ true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct
+ results, however. */
+ if (CPU_IS_PA_RISC (cpu))
+ {
+ switch (cpu)
+ {
+ case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
+ case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
+ case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
+ default: puts ("hppa-hitachi-hiuxwe2"); break;
+ }
+ }
+ else if (CPU_IS_HP_MC68K (cpu))
+ puts ("m68k-hitachi-hiuxwe2");
+ else puts ("unknown-hitachi-hiuxwe2");
+ exit (0);
+ }
+EOF
+ ${CC-cc} dummy.c -o dummy && ./dummy && rm dummy.c dummy && exit 0
+ rm -f dummy.c dummy
+ echo unknown-hitachi-hiuxwe2
+ exit 0 ;;
+ 9000/7??:4.3bsd:*:* | 9000/8?7:4.3bsd:*:* )
+ echo hppa1.1-hp-bsd
+ exit 0 ;;
+ 9000/8??:4.3bsd:*:*)
+ echo hppa1.0-hp-bsd
+ exit 0 ;;
+ hp7??:OSF1:*:* | hp8?7:OSF1:*:* )
+ echo hppa1.1-hp-osf
+ exit 0 ;;
+ hp8??:OSF1:*:*)
+ echo hppa1.0-hp-osf
+ exit 0 ;;
+ C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
+ echo c1-convex-bsd
+ exit 0 ;;
+ C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
+ if getsysinfo -f scalar_acc
+ then echo c32-convex-bsd
+ else echo c2-convex-bsd
+ fi
+ exit 0 ;;
+ C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
+ echo c34-convex-bsd
+ exit 0 ;;
+ C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
+ echo c38-convex-bsd
+ exit 0 ;;
+ C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
+ echo c4-convex-bsd
+ exit 0 ;;
+ CRAY*X-MP:UNICOS:*:*)
+ echo xmp-cray-unicos
+ exit 0 ;;
+ CRAY*Y-MP:UNICOS:*:*)
+ echo ymp-cray-unicos
+ exit 0 ;;
+ CRAY-2:UNICOS:*:*)
+ echo cray2-cray-unicos
+ exit 0 ;;
+ amiga:NetBSD:*:*)
+ echo m68k-amiga-netbsd${UNAME_RELEASE}
+ exit 0 ;;
+ atari:NetBSD:*:*)
+ echo m68k-atari-netbsd${UNAME_RELEASE}
+ exit 0 ;;
+ hp3[0-9][05]:NetBSD:*:*)
+ echo m68k-hp-netbsd${UNAME_RELEASE}
+ exit 0 ;;
+ mac68k:NetBSD:*:*)
+ echo m68k-apple-netbsd${UNAME_RELEASE}
+ exit 0 ;;
+ mvme68:NetBSD:*:*)
+ echo m68k-motorola-netbsd${UNAME_RELEASE}
+ exit 0 ;;
+ next68k:NetBSD:*:*)
+ echo m68k-next-netbsd${UNAME_RELEASE}
+ exit 0 ;;
+ news68k:NetBSD:*:*)
+ echo m68k-sony-netbsd${UNAME_RELEASE}
+ exit 0 ;;
+ sun3:NetBSD:*:*)
+ echo m68k-sun-netbsd${UNAME_RELEASE}
+ exit 0 ;;
+ x68k:NetBSD:*:*)
+ echo m68k-sharp-netbsd${UNAME_RELEASE}
+ exit 0 ;;
+ i[34]86:BSD/386:*:* | *:BSD/OS:*:*)
+ echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
+ exit 0 ;;
+ *:FreeBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
+ exit 0 ;;
+ *:NetBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-netbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+ exit 0 ;;
+ *:OpenBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-openbsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
+ exit 0 ;;
+ *:GNU:*:*)
+ echo `echo ${UNAME_MACHINE}|sed -e 's,/.*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
+ exit 0 ;;
+ *:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux
+ exit 0 ;;
+# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. earlier versions
+# are messed up and put the nodename in both sysname and nodename.
+ i[34]86:DYNIX/ptx:4*:*)
+ echo i386-sequent-sysv4
+ exit 0 ;;
+ i[34]86:*:4.*:* | i[34]86:SYSTEM_V:4.*:*)
+ if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
+ echo ${UNAME_MACHINE}-univel-sysv${UNAME_RELEASE}
+ else
+ echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}
+ fi
+ exit 0 ;;
+ i[34]86:*:3.2:*)
+ if /bin/uname -X 2>/dev/null >/dev/null ; then
+ UNAME_REL=`(/bin/uname -X|egrep Release|sed -e 's/.*= //')`
+ (/bin/uname -X|egrep i80486 >/dev/null) && UNAME_MACHINE=i486
+ echo ${UNAME_MACHINE}-unknown-sco$UNAME_REL
+ elif test -f /usr/options/cb.name; then
+ UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
+ echo ${UNAME_MACHINE}-unknown-isc$UNAME_REL
+ else
+ echo ${UNAME_MACHINE}-unknown-sysv32
+ fi
+ exit 0 ;;
+ i?86:*:5:7)
+ UNAME_REL=`(/bin/uname -X|egrep Release|sed -e 's/.*= //')`
+ (/bin/uname -X|egrep i80486 >/dev/null) && UNAME_MACHINE=i486
+ (/bin/uname -X|egrep '^Machine.*Pentium' >/dev/null) \
+ && UNAME_MACHINE=i586
+ echo ${UNAME_MACHINE}-${UNAME_SYSTEM}${UNAME_VERSION}-sysv${UNAME_RELEASE}
+ exit 0 ;;
+ Intel:Mach:3*:*)
+ echo i386-unknown-mach3
+ exit 0 ;;
+ i860:*:4.*:*) # i860-SVR4
+ if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
+ echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
+ else # Add other i860-SVR4 vendors below as they are discovered.
+ echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4
+ fi
+ exit 0 ;;
+ mini*:CTIX:SYS*5:*)
+ # "miniframe"
+ echo m68010-convergent-sysv
+ exit 0 ;;
+ M680[234]0:*:R3V[567]*:*)
+ test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;;
+ 3[34]??:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0)
+ uname -p 2>/dev/null | grep 86 >/dev/null \
+ && echo i486-ncr-sysv4.3 && exit 0 ;;
+ 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
+ uname -p 2>/dev/null | grep 86 >/dev/null \
+ && echo i486-ncr-sysv4 && exit 0 ;;
+ m680[234]0:LynxOS:2.2*:*)
+ echo m68k-lynx-lynxos${UNAME_RELEASE}
+ exit 0 ;;
+ mc68030:UNIX_System_V:4.*:*)
+ echo m68k-atari-sysv4
+ exit 0 ;;
+ i[34]86:LynxOS:2.2*:*)
+ echo i386-lynx-lynxos${UNAME_RELEASE}
+ exit 0 ;;
+ TSUNAMI:LynxOS:2.2*:*)
+ echo sparc-lynx-lynxos${UNAME_RELEASE}
+ exit 0 ;;
+ rs6000:LynxOS:2.2*:*)
+ echo rs6000-lynx-lynxos${UNAME_RELEASE}
+ exit 0 ;;
+ RM*:SINIX-*:*:*)
+ echo mips-sni-sysv4
+ exit 0 ;;
+ *:SINIX-*:*:*)
+ if uname -p 2>/dev/null >/dev/null ; then
+ UNAME_MACHINE=`(uname -p) 2>/dev/null`
+ echo ${UNAME_MACHINE}-sni-sysv4
+ else
+ echo ns32k-sni-sysv
+ fi
+ exit 0 ;;
+esac
+
+#echo '(No uname command or uname output not recognized.)' 1>&2
+#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2
+
+cat >dummy.c <<EOF
+main ()
+{
+#if defined (sony)
+#if defined (MIPSEB)
+ /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed,
+ I don't know.... */
+ printf ("mips-sony-bsd\n"); exit (0);
+#else
+ printf ("m68k-sony-newsos\n"); exit (0);
+#endif
+#endif
+
+#if defined (__arm) && defined (__acorn) && defined (__unix)
+ printf ("arm-acorn-riscix"); exit (0);
+#endif
+
+#if defined (hp300) && !defined (hpux)
+ printf ("m68k-hp-bsd\n"); exit (0);
+#endif
+
+#if defined (NeXT)
+#if !defined (__ARCHITECTURE__)
+#define __ARCHITECTURE__ "m68k"
+#endif
+ int version;
+ version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
+ printf ("%s-next-nextstep%s\n", __ARCHITECTURE__, version==2 ? "2" : "3");
+ exit (0);
+#endif
+
+#if defined (MULTIMAX) || defined (n16)
+#if defined (UMAXV)
+ printf ("ns32k-encore-sysv\n"); exit (0);
+#else
+#if defined (CMU)
+ printf ("ns32k-encore-mach\n"); exit (0);
+#else
+ printf ("ns32k-encore-bsd\n"); exit (0);
+#endif
+#endif
+#endif
+
+#if defined (__386BSD__)
+ printf ("i386-unknown-bsd\n"); exit (0);
+#endif
+
+#if defined (sequent)
+#if defined (i386)
+ printf ("i386-sequent-dynix\n"); exit (0);
+#endif
+#if defined (ns32000)
+ printf ("ns32k-sequent-dynix\n"); exit (0);
+#endif
+#endif
+
+#if defined (_SEQUENT_)
+ printf ("i386-sequent-ptx\n"); exit (0);
+#endif
+
+#if defined (vax)
+#if !defined (ultrix)
+ printf ("vax-dec-bsd\n"); exit (0);
+#else
+ printf ("vax-dec-ultrix\n"); exit (0);
+#endif
+#endif
+
+#if defined (alliant) && defined (i860)
+ printf ("i860-alliant-bsd\n"); exit (0);
+#endif
+
+ exit (1);
+}
+EOF
+
+${CC-cc} dummy.c -o dummy 2>/dev/null && ./dummy && rm dummy.c dummy && exit 0
+rm -f dummy.c dummy
+
+# Apollos put the system type in the environment.
+
+test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit 0; }
+
+# Convex versions that predate uname can use getsysinfo(1)
+
+if [ -x /usr/convex/getsysinfo ]
+then
+ case `getsysinfo -f cpu_type` in
+ c1*)
+ echo c1-convex-bsd
+ exit 0 ;;
+ c2*)
+ if getsysinfo -f scalar_acc
+ then echo c32-convex-bsd
+ else echo c2-convex-bsd
+ fi
+ exit 0 ;;
+ c34*)
+ echo c34-convex-bsd
+ exit 0 ;;
+ c38*)
+ echo c38-convex-bsd
+ exit 0 ;;
+ c4*)
+ echo c4-convex-bsd
+ exit 0 ;;
+ esac
+fi
+
+#echo '(Unable to guess system type)' 1>&2
+
+exit 1
diff --git a/mit-pthreads/config/config.h.in b/mit-pthreads/config/config.h.in
new file mode 100755
index 00000000000..b5e25404a67
--- /dev/null
+++ b/mit-pthreads/config/config.h.in
@@ -0,0 +1,324 @@
+/* config.h.in. Generated automatically from configure.in by autoheader. */
+
+/* Define to `long' if <sys/types.h> doesn't define. */
+#undef off_t
+
+/* Define as the return type of signal handlers (int or void). */
+#undef RETSIGTYPE
+
+/* Define to `unsigned' if <sys/types.h> doesn't define. */
+#undef size_t
+
+/* Define if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Define if you can safely include both <sys/time.h> and <time.h>. */
+#undef TIME_WITH_SYS_TIME
+
+/* Does the OS already support struct timespec */
+#undef _OS_HAS_TIMESPEC
+
+/* Does the OS need socklen_t for the socket syscalls? */
+#undef _OS_HAS_SOCKLEN_T
+
+/* For networking code: an integral type the size of an IP address (4
+ octets). Determined by examining return values from certain
+ functions. */
+#undef pthread_ipaddr_type
+
+/* For networking code: an integral type the size of an IP port number
+ (2 octets). Determined by examining return values from certain
+ functions. */
+#undef pthread_ipport_type
+
+/* type of clock_t, from system header files */
+#undef pthread_clock_t
+
+/* Specially named so grep processing will find it and put it into the
+ generated ac-types.h. */
+#undef pthread_have_va_list_h
+
+/* type of size_t, from system header files */
+#undef pthread_size_t
+
+/* type of ssize_t, from system header files */
+#undef pthread_ssize_t
+
+/* type of time_t, from system header files */
+#undef pthread_time_t
+
+/* type of fpos_t, from system header files */
+#undef pthread_fpos_t
+
+/* type of off_t, from system header files */
+#undef pthread_off_t
+
+/* type of va_list, from system header files */
+#undef pthread_va_list
+
+/* I don't know why the native compiler definitions aren't sufficient
+ for this. */
+#undef sunos4
+
+/* define if the linker hauls in certain static data from libc even when
+ you don't want it to. yes, this description is bogus, but chris added
+ the need for this, without describing the problem. */
+#undef LD_LINKS_STATIC_DATA
+
+/* define if the system reissues the SIGCHLD if the handler reinstalls
+ * itself before calling wait()
+ */
+#undef BROKEN_SIGNALS
+
+/* where are terminal devices to be found? */
+#undef _PATH_PTY
+
+/* what directory holds the time zone info on this system? */
+#undef _PATH_TZDIR
+
+/* what file indicates the local time zone? */
+#undef _PATH_TZFILE
+
+/* Paths for various networking support files. */
+#undef _PATH_RESCONF
+#undef _PATH_HOSTS
+#undef _PATH_NETWORKS
+#undef _PATH_PROTOCOLS
+#undef _PATH_SERVICES
+
+/* Path for Bourne shell. */
+#undef _PATH_BSHELL
+
+/* Define if you have the syscall_accept function. */
+#undef HAVE_SYSCALL_ACCEPT
+
+/* Define if you have the syscall_bind function. */
+#undef HAVE_SYSCALL_BIND
+
+/* Define if you have the syscall_chdir function. */
+#undef HAVE_SYSCALL_CHDIR
+
+/* Define if you have the syscall_chmod function. */
+#undef HAVE_SYSCALL_CHMOD
+
+/* Define if you have the syscall_chown function. */
+#undef HAVE_SYSCALL_CHOWN
+
+/* Define if you have the syscall_chroot function. */
+#undef HAVE_SYSCALL_CHROOT
+
+/* Define if you have the syscall_close function. */
+#undef HAVE_SYSCALL_CLOSE
+
+/* Define if you have the syscall_connect function. */
+#undef HAVE_SYSCALL_CONNECT
+
+/* Define if you have the syscall_creat function. */
+#undef HAVE_SYSCALL_CREAT
+
+/* Define if you have the syscall_dup function. */
+#undef HAVE_SYSCALL_DUP
+
+/* Define if you have the syscall_dup2 function. */
+#undef HAVE_SYSCALL_DUP2
+
+/* Define if you have the syscall_execve function. */
+#undef HAVE_SYSCALL_EXECVE
+
+/* Define if you have the syscall_exit function. */
+#undef HAVE_SYSCALL_EXIT
+
+/* Define if you have the syscall_fchmod function. */
+#undef HAVE_SYSCALL_FCHMOD
+
+/* Define if you have the syscall_fchown function. */
+#undef HAVE_SYSCALL_FCHOWN
+
+/* Define if you have the syscall_fcntl function. */
+#undef HAVE_SYSCALL_FCNTL
+
+/* Define if you have the syscall_flock function. */
+#undef HAVE_SYSCALL_FLOCK
+
+/* Define if you have the syscall_fork function. */
+#undef HAVE_SYSCALL_FORK
+
+/* Define if you have the syscall_fstat function. */
+#undef HAVE_SYSCALL_FSTAT
+
+/* Define if you have the syscall_fstatfs function. */
+#undef HAVE_SYSCALL_FSTATFS
+
+/* Define if you have the syscall_ftruncate function. */
+#undef HAVE_SYSCALL_FTRUNCATE
+
+/* Define if you have the syscall_getdents function. */
+#undef HAVE_SYSCALL_GETDENTS
+
+/* Define if you have the syscall_getdirentries function. */
+#undef HAVE_SYSCALL_GETDIRENTRIES
+
+/* Define if you have the syscall_getdtablesize function. */
+#undef HAVE_SYSCALL_GETDTABLESIZE
+
+/* Define if you have the syscall_getmsg function. */
+#undef HAVE_SYSCALL_GETMSG
+
+/* Define if you have the syscall_getpeername function. */
+#undef HAVE_SYSCALL_GETPEERNAME
+
+/* Define if you have the syscall_getpgrp function. */
+#undef HAVE_SYSCALL_GETPGRP
+
+/* Define if you have the syscall_getsockname function. */
+#undef HAVE_SYSCALL_GETSOCKNAME
+
+/* Define if you have the syscall_getsockopt function. */
+#undef HAVE_SYSCALL_GETSOCKOPT
+
+/* Define if you have the syscall_ioctl function. */
+#undef HAVE_SYSCALL_IOCTL
+
+/* Define if you have the syscall_ksigaction function. */
+#undef HAVE_SYSCALL_KSIGACTION
+
+/* Define if you have the syscall_link function. */
+#undef HAVE_SYSCALL_LINK
+
+/* Define if you have the syscall_listen function. */
+#undef HAVE_SYSCALL_LISTEN
+
+/* Define if you have the syscall_lseek function. */
+#undef HAVE_SYSCALL_LSEEK
+
+/* Define if you have the syscall_lstat function. */
+#undef HAVE_SYSCALL_LSTAT
+
+/* Define if you have the syscall_open function. */
+#undef HAVE_SYSCALL_OPEN
+
+/* Define if you have the syscall_pgrpsys function. */
+#undef HAVE_SYSCALL_PGRPSYS
+
+/* Define if you have the syscall_pipe function. */
+#undef HAVE_SYSCALL_PIPE
+
+/* Define if you have the syscall_poll function. */
+#undef HAVE_SYSCALL_POLL
+
+/* Define if you have the syscall_putmsg function. */
+#undef HAVE_SYSCALL_PUTMSG
+
+/* Define if you have the syscall_read function. */
+#undef HAVE_SYSCALL_READ
+
+/* Define if you have the syscall_readdir function. */
+#undef HAVE_SYSCALL_READDIR
+
+/* Define if you have the syscall_readv function. */
+#undef HAVE_SYSCALL_READV
+
+/* Define if you have the syscall_recv function. */
+#undef HAVE_SYSCALL_RECV
+
+/* Define if you have the syscall_recvfrom function. */
+#undef HAVE_SYSCALL_RECVFROM
+
+/* Define if you have the syscall_recvmsg function. */
+#undef HAVE_SYSCALL_RECVMSG
+
+/* Define if you have the syscall_rename function. */
+#undef HAVE_SYSCALL_RENAME
+
+/* Define if you have the syscall_select function. */
+#undef HAVE_SYSCALL_SELECT
+
+/* Define if you have the syscall_send function. */
+#undef HAVE_SYSCALL_SEND
+
+/* Define if you have the syscall_sendmsg function. */
+#undef HAVE_SYSCALL_SENDMSG
+
+/* Define if you have the syscall_sendto function. */
+#undef HAVE_SYSCALL_SENDTO
+
+/* Define if you have the syscall_setsockopt function. */
+#undef HAVE_SYSCALL_SETSOCKOPT
+
+/* Define if you have the syscall_shutdown function. */
+#undef HAVE_SYSCALL_SHUTDOWN
+
+/* Define if you have the syscall_sigaction function. */
+#undef HAVE_SYSCALL_SIGACTION
+
+/* Define if you have the syscall_sigpause function. */
+#undef HAVE_SYSCALL_SIGPAUSE
+
+/* Define if you have the syscall_sigprocmask function. */
+#undef HAVE_SYSCALL_SIGPROCMASK
+
+/* Define if you have the syscall_sigsuspend function. */
+#undef HAVE_SYSCALL_SIGSUSPEND
+
+/* Define if you have the syscall_socket function. */
+#undef HAVE_SYSCALL_SOCKET
+
+/* Define if you have the syscall_socketcall function. */
+#undef HAVE_SYSCALL_SOCKETCALL
+
+/* Define if you have the syscall_socketpair function. */
+#undef HAVE_SYSCALL_SOCKETPAIR
+
+/* Define if you have the syscall_stat function. */
+#undef HAVE_SYSCALL_STAT
+
+/* Define if you have the syscall_uname function. */
+#undef HAVE_SYSCALL_UNAME
+
+/* Define if you have the syscall_unlink function. */
+#undef HAVE_SYSCALL_UNLINK
+
+/* Define if you have the syscall_wait3 function. */
+#undef HAVE_SYSCALL_WAIT3
+
+/* Define if you have the syscall_wait4 function. */
+#undef HAVE_SYSCALL_WAIT4
+
+/* Define if you have the syscall_waitpid function. */
+#undef HAVE_SYSCALL_WAITPID
+
+/* Define if you have the syscall_waitsys function. */
+#undef HAVE_SYSCALL_WAITSYS
+
+/* Define if you have the syscall_write function. */
+#undef HAVE_SYSCALL_WRITE
+
+/* Define if you have the syscall_writev function. */
+#undef HAVE_SYSCALL_WRITEV
+
+/* Define if you have the vfork function. */
+#undef HAVE_VFORK
+
+/* Define if you have the <alloc.h> header file. */
+#undef HAVE_ALLOC_H
+
+/* Define if you have the <sys/filio.h> header file. */
+#undef HAVE_SYS_FILIO_H
+
+/* Define if you have the <sys/syscall.h> header file. */
+#undef HAVE_SYS_SYSCALL_H
+
+/* Define if you have the <sys/termio.h> header file. */
+#undef HAVE_SYS_TERMIO_H
+
+/* Define if you have the <sys/time.h> header file. */
+#undef HAVE_SYS_TIME_H
+
+/* Define if you have the <syscall.h> header file. */
+#undef HAVE_SYSCALL_H
+
+/* Define if you have the <termio.h> header file. */
+#undef HAVE_TERMIO_H
+
+/* Define if you have the <termios.h> header file. */
+#undef HAVE_TERMIOS_H
diff --git a/mit-pthreads/config/config.sub b/mit-pthreads/config/config.sub
new file mode 100755
index 00000000000..7a0c7855a2a
--- /dev/null
+++ b/mit-pthreads/config/config.sub
@@ -0,0 +1,794 @@
+#!/bin/sh
+# Configuration validation subroutine script, version 1.1.
+# Copyright (C) 1991, 1992, 1993, 1994 Free Software Foundation, Inc.
+# This file is (in principle) common to ALL GNU software.
+# The presence of a machine in this file suggests that SOME GNU software
+# can handle that machine. It does not imply ALL GNU software can.
+#
+# 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Configuration subroutine to validate and canonicalize a configuration type.
+# Supply the specified configuration type as an argument.
+# If it is invalid, we print an error message on stderr and exit with code 1.
+# Otherwise, we print the canonical config type on stdout and succeed.
+
+# This file is supposed to be the same for all GNU packages
+# and recognize all the CPU types, system types and aliases
+# that are meaningful with *any* GNU software.
+# Each package is responsible for reporting which valid configurations
+# it does not support. The user should be able to distinguish
+# a failure to support a valid configuration from a meaningless
+# configuration.
+
+# The goal of this file is to map all the various variations of a given
+# machine specification into a single specification in the form:
+# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
+# It is wrong to echo any other type of specification.
+
+# First pass through any local machine types.
+case $1 in
+ *local*)
+ echo $1
+ exit 0
+ ;;
+ *)
+ ;;
+esac
+
+# Separate what the user gave into CPU-COMPANY and OS (if any).
+basic_machine=`echo $1 | sed 's/-[^-]*$//'`
+if [ $basic_machine != $1 ]
+then os=`echo $1 | sed 's/.*-/-/'`
+else os=; fi
+
+### Let's recognize common machines as not being operating systems so
+### that things like config.sub decstation-3100 work. We also
+### recognize some manufacturers as not being operating systems, so we
+### can provide default operating systems below.
+case $os in
+ -sun*os*)
+ # Prevent following clause from handling this invalid input.
+ ;;
+ -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \
+ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \
+ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
+ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
+ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
+ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp )
+ os=
+ basic_machine=$1
+ ;;
+ -hiux*)
+ os=-hiuxwe2
+ ;;
+ -sco4)
+ os=-sco3.2v4
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-unknown/'`
+ ;;
+ -sco3.2.[4-9]*)
+ os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-unknown/'`
+ ;;
+ -sco3.2v[4-9]*)
+ # Don't forget version if it is 3.2v4 or newer.
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-unknown/'`
+ ;;
+ -sco*)
+ os=-sco3.2v2
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-unknown/'`
+ ;;
+ -isc)
+ os=-isc2.2
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-unknown/'`
+ ;;
+ -clix*)
+ basic_machine=clipper-intergraph
+ ;;
+ -isc*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-unknown/'`
+ ;;
+ -lynx)
+ os=-lynxos
+ ;;
+ -ptx*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'`
+ ;;
+ -windowsnt*)
+ os=`echo $os | sed -e 's/windowsnt/winnt/'`
+ ;;
+esac
+
+# Decode aliases for certain CPU-COMPANY combinations.
+case $basic_machine in
+ # Recognize the basic CPU types without company name.
+ # Some are omitted here because they have special meanings below.
+ tahoe | i[3456]86 | i860 | m68k | m68000 | m88k | ns32k | arm | arm32 | pyramid \
+ | tron | a29k | 580 | i960 | h8300 | hppa1.0 | hppa1.1 \
+ | alpha | we32k | ns16k | clipper | sparclite | i370 | sh \
+ | powerpc | sparc64 | 1750a | dsp16xx | mips64 | mipsel \
+ | pdp11 | mips64el | mips64orion | mips64orionel )
+ basic_machine=$basic_machine-unknown
+ ;;
+ # Object if more than one company name word.
+ *-*-*)
+ echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+ exit 1
+ ;;
+ # Recognize the basic CPU types with company name.
+ vax-* | tahoe-* | i[3456]86-* | i860-* | m68k-* | m68000-* | m88k-* \
+ | sparc-* | ns32k-* | fx80-* | arm-* | arm32-* | c[123]* \
+ | mips-* | pyramid-* | tron-* | a29k-* | romp-* | rs6000-* \
+ | none-* | 580-* | cray2-* | h8300-* | i960-* | xmp-* | ymp-* \
+ | hppa1.0-* | hppa1.1-* | alpha-* | we32k-* | cydra-* | ns16k-* \
+ | pn-* | np1-* | xps100-* | clipper-* | orion-* | sparclite-* \
+ | pdp11-* | sh-* | powerpc-* | sparc64-* | mips64-* | mipsel-* \
+ | mips64el-* | mips64orion-* | mips64orionel-* )
+ ;;
+ # Recognize the various machine names and aliases which stand
+ # for a CPU type and a company and sometimes even an OS.
+ 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
+ basic_machine=m68000-att
+ ;;
+ 3b*)
+ basic_machine=we32k-att
+ ;;
+ alliant | fx80)
+ basic_machine=fx80-alliant
+ ;;
+ altos | altos3068)
+ basic_machine=m68k-altos
+ ;;
+ am29k)
+ basic_machine=a29k-none
+ os=-bsd
+ ;;
+ amdahl)
+ basic_machine=580-amdahl
+ os=-sysv
+ ;;
+ amiga | amiga-*)
+ basic_machine=m68k-cbm
+ ;;
+ amigados)
+ basic_machine=m68k-cbm
+ os=-amigados
+ ;;
+ amigaunix | amix)
+ basic_machine=m68k-cbm
+ os=-sysv4
+ ;;
+ apollo68)
+ basic_machine=m68k-apollo
+ os=-sysv
+ ;;
+ balance)
+ basic_machine=ns32k-sequent
+ os=-dynix
+ ;;
+ convex-c1)
+ basic_machine=c1-convex
+ os=-bsd
+ ;;
+ convex-c2)
+ basic_machine=c2-convex
+ os=-bsd
+ ;;
+ convex-c32)
+ basic_machine=c32-convex
+ os=-bsd
+ ;;
+ convex-c34)
+ basic_machine=c34-convex
+ os=-bsd
+ ;;
+ convex-c38)
+ basic_machine=c38-convex
+ os=-bsd
+ ;;
+ cray | ymp)
+ basic_machine=ymp-cray
+ os=-unicos
+ ;;
+ cray2)
+ basic_machine=cray2-cray
+ os=-unicos
+ ;;
+ crds | unos)
+ basic_machine=m68k-crds
+ ;;
+ da30 | da30-*)
+ basic_machine=m68k-da30
+ ;;
+ decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
+ basic_machine=mips-dec
+ ;;
+ delta | 3300 | motorola-3300 | motorola-delta \
+ | 3300-motorola | delta-motorola)
+ basic_machine=m68k-motorola
+ ;;
+ delta88)
+ basic_machine=m88k-motorola
+ os=-sysv3
+ ;;
+ dpx20 | dpx20-*)
+ basic_machine=rs6000-bull
+ os=-bosx
+ ;;
+ dpx2* | dpx2*-bull)
+ basic_machine=m68k-bull
+ os=-sysv3
+ ;;
+ ebmon29k)
+ basic_machine=a29k-amd
+ os=-ebmon
+ ;;
+ elxsi)
+ basic_machine=elxsi-elxsi
+ os=-bsd
+ ;;
+ encore | umax | mmax)
+ basic_machine=ns32k-encore
+ ;;
+ fx2800)
+ basic_machine=i860-alliant
+ ;;
+ genix)
+ basic_machine=ns32k-ns
+ ;;
+ gmicro)
+ basic_machine=tron-gmicro
+ os=-sysv
+ ;;
+ h3050r* | hiux*)
+ basic_machine=hppa1.1-hitachi
+ os=-hiuxwe2
+ ;;
+ h8300hms)
+ basic_machine=h8300-hitachi
+ os=-hms
+ ;;
+ harris)
+ basic_machine=m88k-harris
+ os=-sysv3
+ ;;
+ hp300-*)
+ basic_machine=m68k-hp
+ ;;
+ hp300bsd)
+ basic_machine=m68k-hp
+ os=-bsd
+ ;;
+ hp300hpux)
+ basic_machine=m68k-hp
+ os=-hpux
+ ;;
+ hp9k2[0-9][0-9] | hp9k31[0-9])
+ basic_machine=m68000-hp
+ ;;
+ hp9k3[2-9][0-9])
+ basic_machine=m68k-hp
+ ;;
+ hp9k7[0-9][0-9] | hp7[0-9][0-9] | hp9k8[0-9]7 | hp8[0-9]7)
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[0-9][0-9] | hp8[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ i370-ibm* | ibm*)
+ basic_machine=i370-ibm
+ os=-mvs
+ ;;
+# I'm not sure what "Sysv32" means. Should this be sysv3.2?
+ i[3456]86v32)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-unknown/'`
+ os=-sysv32
+ ;;
+ i[3456]86v4*)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-unknown/'`
+ os=-sysv4
+ ;;
+ i[3456]86v)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-unknown/'`
+ os=-sysv
+ ;;
+ i[3456]86sol2)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-unknown/'`
+ os=-solaris2
+ ;;
+ iris | iris4d)
+ basic_machine=mips-sgi
+ case $os in
+ -irix*)
+ ;;
+ *)
+ os=-irix4
+ ;;
+ esac
+ ;;
+ isi68 | isi)
+ basic_machine=m68k-isi
+ os=-sysv
+ ;;
+ m88k-omron*)
+ basic_machine=m88k-omron
+ ;;
+ magnum | m3230)
+ basic_machine=mips-mips
+ os=-sysv
+ ;;
+ merlin)
+ basic_machine=ns32k-utek
+ os=-sysv
+ ;;
+ miniframe)
+ basic_machine=m68000-convergent
+ ;;
+ mips3*-*)
+ basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
+ ;;
+ mips3*)
+ basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
+ ;;
+ ncr3000)
+ basic_machine=i486-ncr
+ os=-sysv4
+ ;;
+ news | news700 | news800 | news900)
+ basic_machine=m68k-sony
+ os=-newsos
+ ;;
+ news1000)
+ basic_machine=m68030-sony
+ os=-newsos
+ ;;
+ news-3600 | risc-news)
+ basic_machine=mips-sony
+ os=-newsos
+ ;;
+ next | m*-next )
+ basic_machine=m68k-next
+ case $os in
+ -nextstep* )
+ ;;
+ -ns2*)
+ os=-nextstep2
+ ;;
+ *)
+ os=-nextstep3
+ ;;
+ esac
+ ;;
+ nh3000)
+ basic_machine=m68k-harris
+ os=-cxux
+ ;;
+ nh[45]000)
+ basic_machine=m88k-harris
+ os=-cxux
+ ;;
+ nindy960)
+ basic_machine=i960-intel
+ os=-nindy
+ ;;
+ np1)
+ basic_machine=np1-gould
+ ;;
+ pa-hitachi)
+ basic_machine=hppa1.1-hitachi
+ os=-hiuxwe2
+ ;;
+ paragon)
+ basic_machine=i860-intel
+ os=-osf
+ ;;
+ pbd)
+ basic_machine=sparc-tti
+ ;;
+ pbb)
+ basic_machine=m68k-tti
+ ;;
+ pc532 | pc532-*)
+ basic_machine=ns32k-pc532
+ ;;
+ pentium-*)
+ # We will change tis to say i586 once there has been
+ # time for various packages to start to recognize that.
+ basic_machine=i486-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pn)
+ basic_machine=pn-gould
+ ;;
+ ps2)
+ basic_machine=i386-ibm
+ ;;
+ rtpc | rtpc-*)
+ basic_machine=romp-ibm
+ ;;
+ sequent)
+ basic_machine=i386-sequent
+ ;;
+ sh)
+ basic_machine=sh-hitachi
+ os=-hms
+ ;;
+ sps7)
+ basic_machine=m68k-bull
+ os=-sysv2
+ ;;
+ spur)
+ basic_machine=spur-unknown
+ ;;
+ sun2)
+ basic_machine=m68000-sun
+ ;;
+ sun2os3)
+ basic_machine=m68000-sun
+ os=-sunos3
+ ;;
+ sun2os4)
+ basic_machine=m68000-sun
+ os=-sunos4
+ ;;
+ sun3os3)
+ basic_machine=m68k-sun
+ os=-sunos3
+ ;;
+ sun3os4)
+ basic_machine=m68k-sun
+ os=-sunos4
+ ;;
+ sun4os3)
+ basic_machine=sparc-sun
+ os=-sunos3
+ ;;
+ sun4os4)
+ basic_machine=sparc-sun
+ os=-sunos4
+ ;;
+ sun3 | sun3-*)
+ basic_machine=m68k-sun
+ ;;
+ sun4)
+ basic_machine=sparc-sun
+ ;;
+ sun386 | sun386i | roadrunner)
+ basic_machine=i386-sun
+ ;;
+ symmetry)
+ basic_machine=i386-sequent
+ os=-dynix
+ ;;
+ tower | tower-32)
+ basic_machine=m68k-ncr
+ ;;
+ ultra3)
+ basic_machine=a29k-nyu
+ os=-sym1
+ ;;
+ vaxv)
+ basic_machine=vax-dec
+ os=-sysv
+ ;;
+ vms)
+ basic_machine=vax-dec
+ os=-vms
+ ;;
+ vxworks960)
+ basic_machine=i960-wrs
+ os=-vxworks
+ ;;
+ vxworks68)
+ basic_machine=m68k-wrs
+ os=-vxworks
+ ;;
+ xmp)
+ basic_machine=xmp-cray
+ os=-unicos
+ ;;
+ xps | xps100)
+ basic_machine=xps100-honeywell
+ ;;
+ none)
+ basic_machine=none-none
+ os=-none
+ ;;
+
+# Here we handle the default manufacturer of certain CPU types. It is in
+# some cases the only manufacturer, in others, it is the most popular.
+ mips)
+ basic_machine=mips-mips
+ ;;
+ romp)
+ basic_machine=romp-ibm
+ ;;
+ rs6000)
+ basic_machine=rs6000-ibm
+ ;;
+ vax)
+ basic_machine=vax-dec
+ ;;
+ pdp11)
+ basic_machine=pdp11-dec
+ ;;
+ we32k)
+ basic_machine=we32k-att
+ ;;
+ sparc)
+ basic_machine=sparc-sun
+ ;;
+ cydra)
+ basic_machine=cydra-cydrome
+ ;;
+ orion)
+ basic_machine=orion-highlevel
+ ;;
+ orion105)
+ basic_machine=clipper-highlevel
+ ;;
+ *)
+ echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+ exit 1
+ ;;
+esac
+
+# Here we canonicalize certain aliases for manufacturers.
+case $basic_machine in
+ *-digital*)
+ basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'`
+ ;;
+ *-commodore*)
+ basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'`
+ ;;
+ *)
+ ;;
+esac
+
+# Decode manufacturer-specific aliases for certain operating systems.
+
+if [ x"$os" != x"" ]
+then
+case $os in
+ # -solaris* is a basic system type, with this one exception.
+ -solaris1 | -solaris1.*)
+ os=`echo $os | sed -e 's|solaris1|sunos4|'`
+ ;;
+ -solaris)
+ os=-solaris2
+ ;;
+ -gnu/linux*)
+ os=`echo $os | sed -e 's|gnu/linux|linux|'`
+ ;;
+ # First accept the basic system types.
+ # The portable systems comes first.
+ # Each alternative must end in a *, to match a version number.
+ # -sysv* is not here because it comes later, after sysvr4.
+ -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
+ | -vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[3456]* \
+ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \
+ | -amigados* | -msdos* | -newsos* | -unicos* | -aos* \
+ | -nindy* | -vxworks* | -ebmon* | -hms* | -mvs* | -clix* \
+ | -riscos* | -linux* | -uniplus* | -iris* | -rtu* | -xenix* \
+ | -hiux* | -386bsd* | -netbsd* | -freebsd* | -openbsd* \
+ |-riscix* \
+ | -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* \
+ | -ptx* | -coff* | -winnt*)
+ ;;
+ -sunos5*)
+ os=`echo $os | sed -e 's|sunos5|solaris2|'`
+ ;;
+ -sunos6*)
+ os=`echo $os | sed -e 's|sunos6|solaris3|'`
+ ;;
+ -osfrose*)
+ os=-osfrose
+ ;;
+ -osf*)
+ os=-osf
+ ;;
+ -utek*)
+ os=-bsd
+ ;;
+ -dynix*)
+ os=-bsd
+ ;;
+ -acis*)
+ os=-aos
+ ;;
+ -ctix* | -uts*)
+ os=-sysv
+ ;;
+ -triton*)
+ os=-sysv3
+ ;;
+ -oss*)
+ os=-sysv3
+ ;;
+ -svr4)
+ os=-sysv4
+ ;;
+ -svr3)
+ os=-sysv3
+ ;;
+ -sysvr4)
+ os=-sysv4
+ ;;
+ # This must come after -sysvr4.
+ -sysv*)
+ ;;
+ -xenix)
+ os=-xenix
+ ;;
+ -none)
+ ;;
+ *)
+ # Get rid of the `-' at the beginning of $os.
+ os=`echo $os | sed 's/[^-]*-//'`
+ echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2
+ exit 1
+ ;;
+esac
+else
+
+# Here we handle the default operating systems that come with various machines.
+# The value should be what the vendor currently ships out the door with their
+# machine or put another way, the most popular os provided with the machine.
+
+# Note that if you're going to try to match "-MANUFACTURER" here (say,
+# "-sun"), then you have to tell the case statement up towards the top
+# that MANUFACTURER isn't an operating system. Otherwise, code above
+# will signal an error saying that MANUFACTURER isn't an operating
+# system, and we'll never get to this point.
+
+case $basic_machine in
+ *-acorn)
+ os=-riscix1.2
+ ;;
+ pdp11-*)
+ os=-none
+ ;;
+ *-dec | vax-*)
+ os=-ultrix4.2
+ ;;
+ i386-sun)
+ os=-sunos4.0.2
+ ;;
+ m68000-sun)
+ os=-sunos3
+ # This also exists in the configure program, but was not the
+ # default.
+ # os=-sunos4
+ ;;
+ *-tti) # must be before sparc entry or we get the wrong os.
+ os=-sysv3
+ ;;
+ sparc-* | *-sun)
+ os=-sunos4.1.1
+ ;;
+ *-ibm)
+ os=-aix
+ ;;
+ *-hp)
+ os=-hpux
+ ;;
+ *-hitachi)
+ os=-hiux
+ ;;
+ i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
+ os=-sysv
+ ;;
+ *-cbm)
+ os=-amigados
+ ;;
+ *-dg)
+ os=-dgux
+ ;;
+ *-dolphin)
+ os=-sysv3
+ ;;
+ m68k-ccur)
+ os=-rtu
+ ;;
+ m88k-omron*)
+ os=-luna
+ ;;
+ *-sequent)
+ os=-ptx
+ ;;
+ *-crds)
+ os=-unos
+ ;;
+ *-ns)
+ os=-genix
+ ;;
+ i370-*)
+ os=-mvs
+ ;;
+ *-next)
+ os=-nextstep3
+ ;;
+ *-gould)
+ os=-sysv
+ ;;
+ *-highlevel)
+ os=-bsd
+ ;;
+ *-encore)
+ os=-bsd
+ ;;
+ *-sgi)
+ os=-irix
+ ;;
+ *-masscomp)
+ os=-rtu
+ ;;
+ *)
+ os=-none
+ ;;
+esac
+fi
+
+# Here we handle the case where we know the os, and the CPU type, but not the
+# manufacturer. We pick the logical manufacturer.
+vendor=unknown
+case $basic_machine in
+ *-unknown)
+ case $os in
+ -riscix*)
+ vendor=acorn
+ ;;
+ -sunos*)
+ vendor=sun
+ ;;
+ -lynxos*)
+ vendor=lynx
+ ;;
+ -aix*)
+ vendor=ibm
+ ;;
+ -hpux*)
+ vendor=hp
+ ;;
+ -hiux*)
+ vendor=hitachi
+ ;;
+ -unos*)
+ vendor=crds
+ ;;
+ -dgux*)
+ vendor=dg
+ ;;
+ -luna*)
+ vendor=omron
+ ;;
+ -genix*)
+ vendor=ns
+ ;;
+ -mvs*)
+ vendor=ibm
+ ;;
+ -ptx*)
+ vendor=sequent
+ ;;
+ esac
+ basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
+ ;;
+esac
+
+echo $basic_machine$os
diff --git a/mit-pthreads/config/configure b/mit-pthreads/config/configure
new file mode 100755
index 00000000000..ab781193cae
--- /dev/null
+++ b/mit-pthreads/config/configure
@@ -0,0 +1,3330 @@
+#! /bin/sh
+
+# Guess values for system-dependent variables and create Makefiles.
+# Generated automatically using autoconf version 2.13
+# Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc.
+#
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+
+# Defaults:
+ac_help=
+ac_default_prefix=/usr/local
+# Any additions from configure.in:
+ac_help="$ac_help
+--enable-dce-compat DCE compatibility"
+ac_default_prefix=/usr/local/pthreads
+
+# Initialize some variables set by options.
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+build=NONE
+cache_file=./config.cache
+exec_prefix=NONE
+host=NONE
+no_create=
+nonopt=NONE
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+target=NONE
+verbose=
+x_includes=NONE
+x_libraries=NONE
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datadir='${prefix}/share'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+libdir='${exec_prefix}/lib'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+infodir='${prefix}/info'
+mandir='${prefix}/man'
+
+# Initialize some other variables.
+subdirs=
+MFLAGS= MAKEFLAGS=
+SHELL=${CONFIG_SHELL-/bin/sh}
+# Maximum number of lines to put in a shell here document.
+ac_max_here_lines=12
+
+ac_prev=
+for ac_option
+do
+
+ # If the previous option needs an argument, assign it.
+ if test -n "$ac_prev"; then
+ eval "$ac_prev=\$ac_option"
+ ac_prev=
+ continue
+ fi
+
+ case "$ac_option" in
+ -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
+ *) ac_optarg= ;;
+ esac
+
+ # Accept the important Cygnus configure options, so we can diagnose typos.
+
+ case "$ac_option" in
+
+ -bindir | --bindir | --bindi | --bind | --bin | --bi)
+ ac_prev=bindir ;;
+ -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+ bindir="$ac_optarg" ;;
+
+ -build | --build | --buil | --bui | --bu)
+ ac_prev=build ;;
+ -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+ build="$ac_optarg" ;;
+
+ -cache-file | --cache-file | --cache-fil | --cache-fi \
+ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+ ac_prev=cache_file ;;
+ -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+ cache_file="$ac_optarg" ;;
+
+ -datadir | --datadir | --datadi | --datad | --data | --dat | --da)
+ ac_prev=datadir ;;
+ -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \
+ | --da=*)
+ datadir="$ac_optarg" ;;
+
+ -disable-* | --disable-*)
+ ac_feature=`echo $ac_option|sed -e 's/-*disable-//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then
+ { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+ fi
+ ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+ eval "enable_${ac_feature}=no" ;;
+
+ -enable-* | --enable-*)
+ ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then
+ { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+ fi
+ ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+ case "$ac_option" in
+ *=*) ;;
+ *) ac_optarg=yes ;;
+ esac
+ eval "enable_${ac_feature}='$ac_optarg'" ;;
+
+ -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+ | --exec | --exe | --ex)
+ ac_prev=exec_prefix ;;
+ -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+ | --exec=* | --exe=* | --ex=*)
+ exec_prefix="$ac_optarg" ;;
+
+ -gas | --gas | --ga | --g)
+ # Obsolete; use --with-gas.
+ with_gas=yes ;;
+
+ -help | --help | --hel | --he)
+ # Omit some internal or obsolete options to make the list less imposing.
+ # This message is too long to be a string in the A/UX 3.1 sh.
+ cat << EOF
+Usage: configure [options] [host]
+Options: [defaults in brackets after descriptions]
+Configuration:
+ --cache-file=FILE cache test results in FILE
+ --help print this message
+ --no-create do not create output files
+ --quiet, --silent do not print \`checking...' messages
+ --version print the version of autoconf that created configure
+Directory and file names:
+ --prefix=PREFIX install architecture-independent files in PREFIX
+ [$ac_default_prefix]
+ --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
+ [same as prefix]
+ --bindir=DIR user executables in DIR [EPREFIX/bin]
+ --sbindir=DIR system admin executables in DIR [EPREFIX/sbin]
+ --libexecdir=DIR program executables in DIR [EPREFIX/libexec]
+ --datadir=DIR read-only architecture-independent data in DIR
+ [PREFIX/share]
+ --sysconfdir=DIR read-only single-machine data in DIR [PREFIX/etc]
+ --sharedstatedir=DIR modifiable architecture-independent data in DIR
+ [PREFIX/com]
+ --localstatedir=DIR modifiable single-machine data in DIR [PREFIX/var]
+ --libdir=DIR object code libraries in DIR [EPREFIX/lib]
+ --includedir=DIR C header files in DIR [PREFIX/include]
+ --oldincludedir=DIR C header files for non-gcc in DIR [/usr/include]
+ --infodir=DIR info documentation in DIR [PREFIX/info]
+ --mandir=DIR man documentation in DIR [PREFIX/man]
+ --srcdir=DIR find the sources in DIR [configure dir or ..]
+ --program-prefix=PREFIX prepend PREFIX to installed program names
+ --program-suffix=SUFFIX append SUFFIX to installed program names
+ --program-transform-name=PROGRAM
+ run sed PROGRAM on installed program names
+EOF
+ cat << EOF
+Host type:
+ --build=BUILD configure for building on BUILD [BUILD=HOST]
+ --host=HOST configure for HOST [guessed]
+ --target=TARGET configure for TARGET [TARGET=HOST]
+Features and packages:
+ --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no)
+ --enable-FEATURE[=ARG] include FEATURE [ARG=yes]
+ --with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
+ --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
+ --x-includes=DIR X include files are in DIR
+ --x-libraries=DIR X library files are in DIR
+EOF
+ if test -n "$ac_help"; then
+ echo "--enable and --with options recognized:$ac_help"
+ fi
+ exit 0 ;;
+
+ -host | --host | --hos | --ho)
+ ac_prev=host ;;
+ -host=* | --host=* | --hos=* | --ho=*)
+ host="$ac_optarg" ;;
+
+ -includedir | --includedir | --includedi | --included | --include \
+ | --includ | --inclu | --incl | --inc)
+ ac_prev=includedir ;;
+ -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+ | --includ=* | --inclu=* | --incl=* | --inc=*)
+ includedir="$ac_optarg" ;;
+
+ -infodir | --infodir | --infodi | --infod | --info | --inf)
+ ac_prev=infodir ;;
+ -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+ infodir="$ac_optarg" ;;
+
+ -libdir | --libdir | --libdi | --libd)
+ ac_prev=libdir ;;
+ -libdir=* | --libdir=* | --libdi=* | --libd=*)
+ libdir="$ac_optarg" ;;
+
+ -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+ | --libexe | --libex | --libe)
+ ac_prev=libexecdir ;;
+ -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+ | --libexe=* | --libex=* | --libe=*)
+ libexecdir="$ac_optarg" ;;
+
+ -localstatedir | --localstatedir | --localstatedi | --localstated \
+ | --localstate | --localstat | --localsta | --localst \
+ | --locals | --local | --loca | --loc | --lo)
+ ac_prev=localstatedir ;;
+ -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+ | --localstate=* | --localstat=* | --localsta=* | --localst=* \
+ | --locals=* | --local=* | --loca=* | --loc=* | --lo=*)
+ localstatedir="$ac_optarg" ;;
+
+ -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+ ac_prev=mandir ;;
+ -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+ mandir="$ac_optarg" ;;
+
+ -nfp | --nfp | --nf)
+ # Obsolete; use --without-fp.
+ with_fp=no ;;
+
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c)
+ no_create=yes ;;
+
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+ no_recursion=yes ;;
+
+ -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+ | --oldin | --oldi | --old | --ol | --o)
+ ac_prev=oldincludedir ;;
+ -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+ oldincludedir="$ac_optarg" ;;
+
+ -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+ ac_prev=prefix ;;
+ -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+ prefix="$ac_optarg" ;;
+
+ -program-prefix | --program-prefix | --program-prefi | --program-pref \
+ | --program-pre | --program-pr | --program-p)
+ ac_prev=program_prefix ;;
+ -program-prefix=* | --program-prefix=* | --program-prefi=* \
+ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+ program_prefix="$ac_optarg" ;;
+
+ -program-suffix | --program-suffix | --program-suffi | --program-suff \
+ | --program-suf | --program-su | --program-s)
+ ac_prev=program_suffix ;;
+ -program-suffix=* | --program-suffix=* | --program-suffi=* \
+ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+ program_suffix="$ac_optarg" ;;
+
+ -program-transform-name | --program-transform-name \
+ | --program-transform-nam | --program-transform-na \
+ | --program-transform-n | --program-transform- \
+ | --program-transform | --program-transfor \
+ | --program-transfo | --program-transf \
+ | --program-trans | --program-tran \
+ | --progr-tra | --program-tr | --program-t)
+ ac_prev=program_transform_name ;;
+ -program-transform-name=* | --program-transform-name=* \
+ | --program-transform-nam=* | --program-transform-na=* \
+ | --program-transform-n=* | --program-transform-=* \
+ | --program-transform=* | --program-transfor=* \
+ | --program-transfo=* | --program-transf=* \
+ | --program-trans=* | --program-tran=* \
+ | --progr-tra=* | --program-tr=* | --program-t=*)
+ program_transform_name="$ac_optarg" ;;
+
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ silent=yes ;;
+
+ -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+ ac_prev=sbindir ;;
+ -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+ | --sbi=* | --sb=*)
+ sbindir="$ac_optarg" ;;
+
+ -sharedstatedir | --sharedstatedir | --sharedstatedi \
+ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+ | --sharedst | --shareds | --shared | --share | --shar \
+ | --sha | --sh)
+ ac_prev=sharedstatedir ;;
+ -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+ | --sha=* | --sh=*)
+ sharedstatedir="$ac_optarg" ;;
+
+ -site | --site | --sit)
+ ac_prev=site ;;
+ -site=* | --site=* | --sit=*)
+ site="$ac_optarg" ;;
+
+ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+ ac_prev=srcdir ;;
+ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+ srcdir="$ac_optarg" ;;
+
+ -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+ | --syscon | --sysco | --sysc | --sys | --sy)
+ ac_prev=sysconfdir ;;
+ -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+ sysconfdir="$ac_optarg" ;;
+
+ -target | --target | --targe | --targ | --tar | --ta | --t)
+ ac_prev=target ;;
+ -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+ target="$ac_optarg" ;;
+
+ -v | -verbose | --verbose | --verbos | --verbo | --verb)
+ verbose=yes ;;
+
+ -version | --version | --versio | --versi | --vers)
+ echo "configure generated by autoconf version 2.13"
+ exit 0 ;;
+
+ -with-* | --with-*)
+ ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then
+ { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+ fi
+ ac_package=`echo $ac_package| sed 's/-/_/g'`
+ case "$ac_option" in
+ *=*) ;;
+ *) ac_optarg=yes ;;
+ esac
+ eval "with_${ac_package}='$ac_optarg'" ;;
+
+ -without-* | --without-*)
+ ac_package=`echo $ac_option|sed -e 's/-*without-//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then
+ { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+ fi
+ ac_package=`echo $ac_package| sed 's/-/_/g'`
+ eval "with_${ac_package}=no" ;;
+
+ --x)
+ # Obsolete; use --with-x.
+ with_x=yes ;;
+
+ -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+ | --x-incl | --x-inc | --x-in | --x-i)
+ ac_prev=x_includes ;;
+ -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+ x_includes="$ac_optarg" ;;
+
+ -x-libraries | --x-libraries | --x-librarie | --x-librari \
+ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+ ac_prev=x_libraries ;;
+ -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+ x_libraries="$ac_optarg" ;;
+
+ -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; }
+ ;;
+
+ *)
+ if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then
+ echo "configure: warning: $ac_option: invalid host type" 1>&2
+ fi
+ if test "x$nonopt" != xNONE; then
+ { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; }
+ fi
+ nonopt="$ac_option"
+ ;;
+
+ esac
+done
+
+if test -n "$ac_prev"; then
+ { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; }
+fi
+
+trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
+
+# File descriptor usage:
+# 0 standard input
+# 1 file creation
+# 2 errors and warnings
+# 3 some systems may open it to /dev/tty
+# 4 used on the Kubota Titan
+# 6 checking for... messages and results
+# 5 compiler messages saved in config.log
+if test "$silent" = yes; then
+ exec 6>/dev/null
+else
+ exec 6>&1
+fi
+exec 5>./config.log
+
+echo "\
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+" 1>&5
+
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Also quote any args containing shell metacharacters.
+ac_configure_args=
+for ac_arg
+do
+ case "$ac_arg" in
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c) ;;
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;;
+ *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*)
+ ac_configure_args="$ac_configure_args '$ac_arg'" ;;
+ *) ac_configure_args="$ac_configure_args $ac_arg" ;;
+ esac
+done
+
+# NLS nuisances.
+# Only set these to C if already set. These must not be set unconditionally
+# because not all systems understand e.g. LANG=C (notably SCO).
+# Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'!
+# Non-C LC_CTYPE values break the ctype check.
+if test "${LANG+set}" = set; then LANG=C; export LANG; fi
+if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi
+if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi
+if test "${LC_CTYPE+set}" = set; then LC_CTYPE=C; export LC_CTYPE; fi
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -rf conftest* confdefs.h
+# AIX cpp loses on an empty file, so make sure it contains at least a newline.
+echo > confdefs.h
+
+# A filename unique to this package, relative to the directory that
+# configure is in, which we can look for to find out if srcdir is correct.
+ac_unique_file=config.flags.in
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+ ac_srcdir_defaulted=yes
+ # Try the directory containing this script, then its parent.
+ ac_prog=$0
+ ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'`
+ test "x$ac_confdir" = "x$ac_prog" && ac_confdir=.
+ srcdir=$ac_confdir
+ if test ! -r $srcdir/$ac_unique_file; then
+ srcdir=..
+ fi
+else
+ ac_srcdir_defaulted=no
+fi
+if test ! -r $srcdir/$ac_unique_file; then
+ if test "$ac_srcdir_defaulted" = yes; then
+ { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; }
+ else
+ { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; }
+ fi
+fi
+srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'`
+
+# Prefer explicitly selected file to automatically selected ones.
+if test -z "$CONFIG_SITE"; then
+ if test "x$prefix" != xNONE; then
+ CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site"
+ else
+ CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site"
+ fi
+fi
+for ac_site_file in $CONFIG_SITE; do
+ if test -r "$ac_site_file"; then
+ echo "loading site script $ac_site_file"
+ . "$ac_site_file"
+ fi
+done
+
+if test -r "$cache_file"; then
+ echo "loading cache $cache_file"
+ . $cache_file
+else
+ echo "creating cache $cache_file"
+ > $cache_file
+fi
+
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+ac_exeext=
+ac_objext=o
+if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then
+ # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu.
+ if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then
+ ac_n= ac_c='
+' ac_t=' '
+ else
+ ac_n=-n ac_c= ac_t=
+ fi
+else
+ ac_n= ac_c='\c' ac_t=
+fi
+
+
+# Check whether --enable-dce-compat or --disable-dce-compat was given.
+if test "${enable_dce_compat+set}" = set; then
+ enableval="$enable_dce_compat"
+ { echo "configure: error: Actually, DCE compatibility doesn't work yet..." 1>&2; exit 1; }
+
+else
+ true
+
+fi
+
+
+# Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:542: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_dummy="$PATH"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_prog_CC="gcc"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+ echo "$ac_t""$CC" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+if test -z "$CC"; then
+ # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:572: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_prog_rejected=no
+ ac_dummy="$PATH"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then
+ ac_prog_rejected=yes
+ continue
+ fi
+ ac_cv_prog_CC="cc"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+if test $ac_prog_rejected = yes; then
+ # We found a bogon in the path, so make sure we never use it.
+ set dummy $ac_cv_prog_CC
+ shift
+ if test $# -gt 0; then
+ # We chose a different compiler from the bogus one.
+ # However, it has the same basename, so the bogon will be chosen
+ # first if we set CC to just the basename; use the full file name.
+ shift
+ set dummy "$ac_dir/$ac_word" "$@"
+ shift
+ ac_cv_prog_CC="$@"
+ fi
+fi
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+ echo "$ac_t""$CC" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+ if test -z "$CC"; then
+ case "`uname -s`" in
+ *win32* | *WIN32*)
+ # Extract the first word of "cl", so it can be a program name with args.
+set dummy cl; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:623: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_dummy="$PATH"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_prog_CC="cl"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+ echo "$ac_t""$CC" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+ ;;
+ esac
+ fi
+ test -z "$CC" && { echo "configure: error: no acceptable cc found in \$PATH" 1>&2; exit 1; }
+fi
+
+echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6
+echo "configure:655: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5
+
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+cat > conftest.$ac_ext << EOF
+
+#line 666 "configure"
+#include "confdefs.h"
+
+main(){return(0);}
+EOF
+if { (eval echo configure:671: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ ac_cv_prog_cc_works=yes
+ # If we can't run a trivial program, we are probably using a cross compiler.
+ if (./conftest; exit) 2>/dev/null; then
+ ac_cv_prog_cc_cross=no
+ else
+ ac_cv_prog_cc_cross=yes
+ fi
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ ac_cv_prog_cc_works=no
+fi
+rm -fr conftest*
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+echo "$ac_t""$ac_cv_prog_cc_works" 1>&6
+if test $ac_cv_prog_cc_works = no; then
+ { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; }
+fi
+echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6
+echo "configure:697: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5
+echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6
+cross_compiling=$ac_cv_prog_cc_cross
+
+echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6
+echo "configure:702: checking whether we are using GNU C" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.c <<EOF
+#ifdef __GNUC__
+ yes;
+#endif
+EOF
+if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:711: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
+ ac_cv_prog_gcc=yes
+else
+ ac_cv_prog_gcc=no
+fi
+fi
+
+echo "$ac_t""$ac_cv_prog_gcc" 1>&6
+
+if test $ac_cv_prog_gcc = yes; then
+ GCC=yes
+else
+ GCC=
+fi
+
+ac_test_CFLAGS="${CFLAGS+set}"
+ac_save_CFLAGS="$CFLAGS"
+CFLAGS=
+echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6
+echo "configure:730: checking whether ${CC-cc} accepts -g" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ echo 'void f(){}' > conftest.c
+if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then
+ ac_cv_prog_cc_g=yes
+else
+ ac_cv_prog_cc_g=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_prog_cc_g" 1>&6
+if test "$ac_test_CFLAGS" = set; then
+ CFLAGS="$ac_save_CFLAGS"
+elif test $ac_cv_prog_cc_g = yes; then
+ if test "$GCC" = yes; then
+ CFLAGS="-g -O2"
+ else
+ CFLAGS="-g"
+ fi
+else
+ if test "$GCC" = yes; then
+ CFLAGS="-O2"
+ else
+ CFLAGS=
+ fi
+fi
+
+for ac_prog in $CCC c++ g++ gcc CC cxx cc++ cl
+do
+# Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:766: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CXX'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$CXX"; then
+ ac_cv_prog_CXX="$CXX" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_dummy="$PATH"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_prog_CXX="$ac_prog"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+fi
+fi
+CXX="$ac_cv_prog_CXX"
+if test -n "$CXX"; then
+ echo "$ac_t""$CXX" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+test -n "$CXX" && break
+done
+test -n "$CXX" || CXX="gcc"
+
+
+echo $ac_n "checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) works""... $ac_c" 1>&6
+echo "configure:798: checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) works" >&5
+
+ac_ext=C
+# CXXFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='${CXX-g++} -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CXX-g++} -o conftest${ac_exeext} $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cxx_cross
+
+cat > conftest.$ac_ext << EOF
+
+#line 809 "configure"
+#include "confdefs.h"
+
+int main(){return(0);}
+EOF
+if { (eval echo configure:814: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ ac_cv_prog_cxx_works=yes
+ # If we can't run a trivial program, we are probably using a cross compiler.
+ if (./conftest; exit) 2>/dev/null; then
+ ac_cv_prog_cxx_cross=no
+ else
+ ac_cv_prog_cxx_cross=yes
+ fi
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ ac_cv_prog_cxx_works=no
+fi
+rm -fr conftest*
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+echo "$ac_t""$ac_cv_prog_cxx_works" 1>&6
+if test $ac_cv_prog_cxx_works = no; then
+ { echo "configure: error: installation or configuration problem: C++ compiler cannot create executables." 1>&2; exit 1; }
+fi
+echo $ac_n "checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6
+echo "configure:840: checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) is a cross-compiler" >&5
+echo "$ac_t""$ac_cv_prog_cxx_cross" 1>&6
+cross_compiling=$ac_cv_prog_cxx_cross
+
+echo $ac_n "checking whether we are using GNU C++""... $ac_c" 1>&6
+echo "configure:845: checking whether we are using GNU C++" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_gxx'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.C <<EOF
+#ifdef __GNUC__
+ yes;
+#endif
+EOF
+if { ac_try='${CXX-g++} -E conftest.C'; { (eval echo configure:854: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
+ ac_cv_prog_gxx=yes
+else
+ ac_cv_prog_gxx=no
+fi
+fi
+
+echo "$ac_t""$ac_cv_prog_gxx" 1>&6
+
+if test $ac_cv_prog_gxx = yes; then
+ GXX=yes
+else
+ GXX=
+fi
+
+ac_test_CXXFLAGS="${CXXFLAGS+set}"
+ac_save_CXXFLAGS="$CXXFLAGS"
+CXXFLAGS=
+echo $ac_n "checking whether ${CXX-g++} accepts -g""... $ac_c" 1>&6
+echo "configure:873: checking whether ${CXX-g++} accepts -g" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_cxx_g'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ echo 'void f(){}' > conftest.cc
+if test -z "`${CXX-g++} -g -c conftest.cc 2>&1`"; then
+ ac_cv_prog_cxx_g=yes
+else
+ ac_cv_prog_cxx_g=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_prog_cxx_g" 1>&6
+if test "$ac_test_CXXFLAGS" = set; then
+ CXXFLAGS="$ac_save_CXXFLAGS"
+elif test $ac_cv_prog_cxx_g = yes; then
+ if test "$GXX" = yes; then
+ CXXFLAGS="-g -O2"
+ else
+ CXXFLAGS="-g"
+ fi
+else
+ if test "$GXX" = yes; then
+ CXXFLAGS="-O2"
+ else
+ CXXFLAGS=
+ fi
+fi
+
+echo $ac_n "checking compiler availability and simple error detection""... $ac_c" 1>&6
+echo "configure:905: checking compiler availability and simple error detection" >&5
+cat > conftest.$ac_ext <<EOF
+#line 907 "configure"
+#include "confdefs.h"
+
+int main() {
+ exit(0);
+; return 0; }
+EOF
+if { (eval echo configure:914: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+
+ cat > conftest.$ac_ext <<EOF
+#line 918 "configure"
+#include "confdefs.h"
+
+int main() {
+ syntax errors galore!
+; return 0; }
+EOF
+if { (eval echo configure:925: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ { echo "configure: error: Can't detect syntax errors! Is CC set right?" 1>&2; exit 1; }
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ true
+fi
+rm -f conftest*
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ { echo "configure: error: Can't compile test program! Is CC set right?" 1>&2; exit 1; }
+fi
+rm -f conftest*
+
+cat > conftest.$ac_ext <<EOF
+#line 944 "configure"
+#include "confdefs.h"
+
+int main() {
+
+ typedef int Integer;
+ extern int i;
+ extern Integer i;
+
+; return 0; }
+EOF
+if { (eval echo configure:955: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ :
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ { echo "configure: error: Can't redeclare variables with this compiler??" 1>&2; exit 1; }
+fi
+rm -f conftest*
+cat > conftest.$ac_ext <<EOF
+#line 965 "configure"
+#include "confdefs.h"
+
+int main() {
+
+ typedef long Long;
+ extern int i;
+ extern Long i;
+
+; return 0; }
+EOF
+if { (eval echo configure:976: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ { echo "configure: error: Compiler doesn't detect conflicting declarations." 1>&2; exit 1; }
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+fi
+rm -f conftest*
+echo "$ac_t""ok" 1>&6
+
+if test $ac_cv_prog_gcc = yes ; then
+ CFLAGS="$CFLAGS -Werror"
+fi
+
+echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6
+echo "configure:991: checking how to run the C preprocessor" >&5
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+ CPP=
+fi
+if test -z "$CPP"; then
+if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ # This must be in double quotes, not single quotes, because CPP may get
+ # substituted into the Makefile and "${CC-cc}" will confuse make.
+ CPP="${CC-cc} -E"
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp.
+ cat > conftest.$ac_ext <<EOF
+#line 1006 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1012: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ :
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ CPP="${CC-cc} -E -traditional-cpp"
+ cat > conftest.$ac_ext <<EOF
+#line 1023 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1029: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ :
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ CPP="${CC-cc} -nologo -E"
+ cat > conftest.$ac_ext <<EOF
+#line 1040 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1046: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ :
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ CPP=/lib/cpp
+fi
+rm -f conftest*
+fi
+rm -f conftest*
+fi
+rm -f conftest*
+ ac_cv_prog_CPP="$CPP"
+fi
+ CPP="$ac_cv_prog_CPP"
+else
+ ac_cv_prog_CPP="$CPP"
+fi
+echo "$ac_t""$CPP" 1>&6
+
+
+# Extract the first word of "ranlib", so it can be a program name with args.
+set dummy ranlib; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:1074: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$RANLIB"; then
+ ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_dummy="$PATH"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_prog_RANLIB="ranlib"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+ test -z "$ac_cv_prog_RANLIB" && ac_cv_prog_RANLIB=":"
+fi
+fi
+RANLIB="$ac_cv_prog_RANLIB"
+if test -n "$RANLIB"; then
+ echo "$ac_t""$RANLIB" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+
+
+
+ac_aux_dir=
+for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do
+ if test -f $ac_dir/install-sh; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install-sh -c"
+ break
+ elif test -f $ac_dir/install.sh; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install.sh -c"
+ break
+ fi
+done
+if test -z "$ac_aux_dir"; then
+ { echo "configure: error: can not find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." 1>&2; exit 1; }
+fi
+ac_config_guess=$ac_aux_dir/config.guess
+ac_config_sub=$ac_aux_dir/config.sub
+ac_configure=$ac_aux_dir/configure # This should be Cygnus configure.
+
+
+# Do some error checking and defaulting for the host and target type.
+# The inputs are:
+# configure --host=HOST --target=TARGET --build=BUILD NONOPT
+#
+# The rules are:
+# 1. You are not allowed to specify --host, --target, and nonopt at the
+# same time.
+# 2. Host defaults to nonopt.
+# 3. If nonopt is not specified, then host defaults to the current host,
+# as determined by config.guess.
+# 4. Target and build default to nonopt.
+# 5. If nonopt is not specified, then target and build default to host.
+
+# The aliases save the names the user supplied, while $host etc.
+# will get canonicalized.
+case $host---$target---$nonopt in
+NONE---*---* | *---NONE---* | *---*---NONE) ;;
+*) { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; } ;;
+esac
+
+
+# Make sure we can run config.sub.
+if ${CONFIG_SHELL-/bin/sh} $ac_config_sub sun4 >/dev/null 2>&1; then :
+else { echo "configure: error: can not run $ac_config_sub" 1>&2; exit 1; }
+fi
+
+echo $ac_n "checking host system type""... $ac_c" 1>&6
+echo "configure:1151: checking host system type" >&5
+
+host_alias=$host
+case "$host_alias" in
+NONE)
+ case $nonopt in
+ NONE)
+ if host_alias=`${CONFIG_SHELL-/bin/sh} $ac_config_guess`; then :
+ else { echo "configure: error: can not guess host type; you must specify one" 1>&2; exit 1; }
+ fi ;;
+ *) host_alias=$nonopt ;;
+ esac ;;
+esac
+
+host=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $host_alias`
+host_cpu=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
+host_vendor=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
+host_os=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
+echo "$ac_t""$host" 1>&6
+
+echo $ac_n "checking target system type""... $ac_c" 1>&6
+echo "configure:1172: checking target system type" >&5
+
+target_alias=$target
+case "$target_alias" in
+NONE)
+ case $nonopt in
+ NONE) target_alias=$host_alias ;;
+ *) target_alias=$nonopt ;;
+ esac ;;
+esac
+
+target=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $target_alias`
+target_cpu=`echo $target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
+target_vendor=`echo $target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
+target_os=`echo $target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
+echo "$ac_t""$target" 1>&6
+
+echo $ac_n "checking build system type""... $ac_c" 1>&6
+echo "configure:1190: checking build system type" >&5
+
+build_alias=$build
+case "$build_alias" in
+NONE)
+ case $nonopt in
+ NONE) build_alias=$host_alias ;;
+ *) build_alias=$nonopt ;;
+ esac ;;
+esac
+
+build=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $build_alias`
+build_cpu=`echo $build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
+build_vendor=`echo $build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
+build_os=`echo $build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
+echo "$ac_t""$build" 1>&6
+
+test "$host_alias" != "$target_alias" &&
+ test "$program_prefix$program_suffix$program_transform_name" = \
+ NONENONEs,x,x, &&
+ program_prefix=${target_alias}-
+
+
+syscall=NONE
+sysincludes=NONE
+extraincludes=NONE
+
+# Treat all x86 machines the same.
+# (Yet below, we pretend we can distinguish between the MIPS r2000 and r4000?)
+# (What about 680x0 machines?)
+case $host in
+ i[456]86-*)
+ host=`echo $host | sed 's/^i[456]86/i386/'`
+ host_cpu=i386
+ ;;
+esac
+
+# Here, you should set the following variables:
+# name
+# The "name" of this configuration. Used for "engine-*.c" file name,
+# default for syscall file names. Chris seems to have a thing for
+# putting "-" between OS and version number, but the configure script
+# will already have $host_cpu and $host_os available for you to use
+# in constructing a name.
+# sysincludes
+# Name of machdep directory with "sys" include file
+# replacements, if any. This directory is optional;
+# if you don't provide it, don't set this variable.
+# except
+# Names of any syscalls that shouldn't be generated
+# from the template, if any.
+# syscall
+# Base name of the syscall template files, if not the
+# same as <name>. If they're the same, omit this.
+#
+# Also, you may define random symbols and update CFLAGS if
+# necessary. However, for ease of porting to new machines,
+# it's best if you can create portable autoconf tests for
+# whatever you're trying to do, rather than hard-coding it
+# here based on the OS name. So please, try to keep this
+# section as minimal as possible.
+
+except=""
+name=$host_cpu-$host_os
+
+case $host in
+ alpha-*-netbsd1.3[H-Z]|alpha-*-netbsd1.4*)
+ name=alpha-netbsd-1.3
+ sysincludes=netbsd-1.1
+ except="fork lseek pipe fstat"
+ available_syscalls="sigsuspend sigprocmask"
+ ;;
+ alpha-*-netbsd1.3*)
+ name=alpha-netbsd-1.3
+ sysincludes=netbsd-1.1
+ except="fork lseek pipe sigsuspend sigprocmask fstat"
+ ;;
+ alpha-*-netbsd1.1* | alpha-*-netbsd1.2*)
+ name=alpha-netbsd-1.1
+ sysincludes=netbsd-1.1
+ except="fork lseek pipe sigsuspend sigprocmask"
+ ;;
+ alpha-*-osf*)
+ name=alpha-osf1
+ sysincludes=alpha-osf1
+ except="fork sigsuspend"
+ if test $ac_cv_prog_gcc = no ; then
+ CFLAGS="$CFLAGS -std"
+ fi
+ ;;
+ arm32-*-netbsd1.3[H-Z]|arm32-*-netbsd1.4*)
+ name=arm32-netbsd-1.3
+ sysincludes=netbsd-1.1
+ except="fork pipe lseek ftruncate fstat"
+ available_syscalls="sigsuspend sigprocmask"
+ ;;
+ arm32-*-netbsd1.3*)
+ name=arm32-netbsd-1.3
+ sysincludes=netbsd-1.1
+ except="fork pipe lseek ftruncate sigsuspend sigprocmask fstat"
+ ;;
+ hppa1.0-*-hpux10.20 | hppa1.1-*-hpux10.20)
+ name=hppa-hpux-10.20
+ sysincludes=hpux-10.20
+ except="fork"
+ ;;
+ hppa1.1-*-hpux*9.*)
+ name=hppa-hpux-9.03
+ sysincludes=hpux-9.03
+ # hpux-9.03.mk seems to be missing; what should this be?
+ except="fork"
+ ;;
+ sparc-*-sunos4.1.3* | sparc-*-sunos4.1.4*)
+ name=sparc-sunos-4.1.3
+ sysincludes=sunos-4.1.3
+ syscall=sparc-sunos4
+ except="fork pipe getpgrp getdirentries"
+ cat >> confdefs.h <<\EOF
+#define sunos4 1
+EOF
+ # is this really needed??
+ ;;
+ sparc-*-solaris2.3* | sparc-*-solaris2.4*)
+ name=sparc-sunos-5.3
+ sysincludes=sunos-5.3
+ except="fork sigaction"
+ # Should really come up with a test for this...
+ cat >> confdefs.h <<\EOF
+#define LD_LINKS_STATIC_DATA 1
+EOF
+
+ cat >> confdefs.h <<\EOF
+#define BROKEN_SIGNALS 1
+EOF
+
+ ;;
+ sparc-*-solaris2*)
+ name=sparc-sunos-5.3
+ sysincludes=sunos-5.5
+ except="fork sigaction"
+ # Should really come up with a test for this...
+ cat >> confdefs.h <<\EOF
+#define LD_LINKS_STATIC_DATA 1
+EOF
+
+ cat >> confdefs.h <<\EOF
+#define BROKEN_SIGNALS 1
+EOF
+
+ ;;
+ sparc-*-netbsd1.3[H-Z]|sparc-*-netbsd1.4*)
+ name=sparc-netbsd-1.3
+ sysincludes=netbsd-1.1
+ except="pipe fork lseek ftruncate fstat"
+ available_syscalls="sigprocmask sigsuspend"
+ ;;
+ sparc-*-netbsd1.3*)
+ name=sparc-netbsd-1.3
+ sysincludes=netbsd-1.1
+ except="pipe fork lseek ftruncate sigprocmask sigsuspend fstat"
+ ;;
+ sparc-*-netbsd1.0A | sparc-*-netbsd1.1* | sparc-*-netbsd1.2*)
+ name=sparc-sunos-4.1.3
+ sysincludes=netbsd-1.0
+ syscall=sparc-netbsd-1.1
+ except="pipe fork sigprocmask sigsuspend"
+ ;;
+ i386-*-openbsd2.*)
+ name=i386-openbsd-2.0
+ sysincludes=openbsd-2.0
+ except="fork lseek ftruncate sigsuspend sigprocmask"
+ ;;
+ i386-*-linux*)
+ #name=i386-linux-1.0
+ #sysincludes=linux-1.0
+ name=i386-linux-2.0
+ sysincludes=linux-2.0
+ extraincludes="bits"
+ ;;
+ i386-*-bsdi1.1)
+ name=i386-bsdi-1.1
+ sysincludes=bsdi-1.1
+ ;;
+ i386-*-bsdi2.0* | i386-*-bsdi2.1*)
+ name=i386-bsdi-2.0
+ sysincludes=bsdi-2.0
+ syscall=i386-bsdi-2.0
+ except="fork lseek ftruncate sigsuspend"
+ ;;
+ i386-*-netbsd1.3[H-Z]|i386-*-netbsd1.4*)
+ name=i386-netbsd-1.3
+ sysincludes=netbsd-1.1
+ except="fork lseek ftruncate pipe fstat"
+ available_syscalls="sigsuspend sigprocmask"
+ ;;
+ i386-*-netbsd1.3*)
+ name=i386-netbsd-1.3
+ sysincludes=netbsd-1.1
+ except="fork lseek ftruncate pipe sigsuspend sigprocmask fstat"
+ ;;
+ i386-*-netbsd1.1* | i386-*-netbsd1.2*)
+ name=i386-netbsd-1.0
+ sysincludes=netbsd-1.1
+ syscall=i386-netbsd-1.1
+ except="fork lseek ftruncate pipe sigsuspend sigprocmask"
+ ;;
+ i386-*-netbsd1.0*)
+ name=i386-netbsd-1.0
+ sysincludes=netbsd-1.0
+ except="fork lseek ftruncate sigsuspend"
+ ;;
+ i386-*-netbsd0.9*)
+ name=i386-netbsd-0.9
+ sysincludes=netbsd-0.9
+ ;;
+ m68*-*-netbsd*)
+ name=m68000-netbsd
+ sysincludes=netbsd-1.1
+ except="lseek ftruncate pipe fstat"
+ available_syscalls="sigsuspend sigprocmask"
+ ;;
+ i386-*-freebsd*)
+ name=i386-freebsd-2.0
+ sysincludes=freebsd-2.0
+ except="fork lseek ftruncate sigsuspend sigprocmask"
+ ;;
+ romp-*-bsd*)
+ name=romp-bsd
+ ;;
+ mips-dec-ultrix*)
+ name=r2000-ultrix-4.2
+ sysincludes=ultrix-4.2
+ except="fork pipe"
+ ;;
+ mips-sgi-irix*)
+ name=ip22-irix-5.2
+ sysincludes=irix-5.2
+ except="fstat stat"
+ cat >> confdefs.h <<\EOF
+#define BROKEN_SIGNALS 1
+EOF
+
+ ;;
+ i386-*-sco3.2v5*)
+ name=i386-sco3.2.5
+ sysincludes=i386-sco3.2.5
+ syscall=i386-sco3.2.5
+ except="select socketcall accept bind connect getpeername getsockname getsockopt setsockopt listen recv recvfrom recvmsg send sendmsg sendto shutdown socket socketpair fork fcntl dup2 fstat fchmod fchown ftruncate pipe getdirentries sigaction sigpause wait3 waitpid getdtablesize"
+ ;;
+ *)
+ { echo "configure: error: System type $host not recognized or not supported.
+See $srcdir/configure.in for supported systems." 1>&2; exit 1; }
+ exit 1
+ ;;
+esac
+
+SYSCALL_EXCEPTIONS=$except
+
+
+for ac_hdr in sys/termio.h termios.h termio.h alloc.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:1453: checking for $ac_hdr" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1458 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1463: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=yes"
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+
+ac_safe=`echo "va_list.h" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for va_list.h""... $ac_c" 1>&6
+echo "configure:1492: checking for va_list.h" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1497 "configure"
+#include "confdefs.h"
+#include <va_list.h>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1502: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=yes"
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ cat >> confdefs.h <<\EOF
+#define pthread_have_va_list_h 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+
+for ac_hdr in syscall.h sys/syscall.h sys/filio.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:1531: checking for $ac_hdr" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1536 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1541: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=yes"
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+
+pthreads_syscall_list="open write read creat close fcntl lseek dup2 dup pipe
+ fchmod fchown execve fstat lstat link unlink chdir chown chmod stat
+ rename select getdtablesize ioctl ftruncate flock fstatfs chroot uname
+ sigsuspend sigaction sigpause sigprocmask ksigaction
+ getdents readdir getdirentries
+ wait4 wait3 waitpid waitsys
+ socket bind connect accept listen getsockopt setsockopt socketpair
+ poll putmsg getmsg
+ socketcall
+
+ pgrpsys
+
+ exit
+ readv writev send sendto sendmsg recv recvfrom recvmsg
+ getpeername getsockname
+ shutdown
+ getpgrp fork"
+for pthreads_syscallname in $pthreads_syscall_list ; do
+ echo $ac_n "checking for syscall $pthreads_syscallname""... $ac_c" 1>&6
+echo "configure:1587: checking for syscall $pthreads_syscallname" >&5
+if eval "test \"`echo '$''{'pthreads_cv_syscall_$pthreads_syscallname'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1592 "configure"
+#include "confdefs.h"
+
+/* FIXME: This list should be generated from info in configure.in. */
+#ifdef HAVE_SYSCALL_H
+#include <syscall.h>
+#else
+#ifdef HAVE_SYS_SYSCALL_H
+#include <sys/syscall.h>
+#else
+where is your syscall header file??
+#endif
+#endif
+
+int main() {
+
+int x;
+x = SYS_$pthreads_syscallname ;
+
+; return 0; }
+EOF
+if { (eval echo configure:1613: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval pthreads_cv_syscall_$pthreads_syscallname=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval pthreads_cv_syscall_$pthreads_syscallname=no
+fi
+rm -f conftest*
+fi
+
+if eval test \$pthreads_cv_syscall_$pthreads_syscallname = yes ; then
+ pthreads_syscall_present=yes
+ available_syscalls="$available_syscalls $pthreads_syscallname"
+ macroname=HAVE_SYSCALL_`echo $pthreads_syscallname | tr '[a-z]' '[A-Z]'`
+ cat >> confdefs.h <<EOF
+#define $macroname 1
+EOF
+
+else
+ pthreads_syscall_present=no
+ missing_syscalls="$missing_syscalls $pthreads_syscallname"
+fi
+echo "$ac_t""$pthreads_syscall_present" 1>&6
+
+done
+
+
+
+
+
+
+## Determine some typedef values from the system header files.
+echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6
+echo "configure:1648: checking for ANSI C header files" >&5
+if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1653 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1661: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ ac_cv_header_stdc=yes
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+if test $ac_cv_header_stdc = yes; then
+ # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+cat > conftest.$ac_ext <<EOF
+#line 1678 "configure"
+#include "confdefs.h"
+#include <string.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "memchr" >/dev/null 2>&1; then
+ :
+else
+ rm -rf conftest*
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+cat > conftest.$ac_ext <<EOF
+#line 1696 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "free" >/dev/null 2>&1; then
+ :
+else
+ rm -rf conftest*
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+if test "$cross_compiling" = yes; then
+ :
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1717 "configure"
+#include "confdefs.h"
+#include <ctype.h>
+#define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+#define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int main () { int i; for (i = 0; i < 256; i++)
+if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2);
+exit (0); }
+
+EOF
+if { (eval echo configure:1728: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ :
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ ac_cv_header_stdc=no
+fi
+rm -fr conftest*
+fi
+
+fi
+fi
+
+echo "$ac_t""$ac_cv_header_stdc" 1>&6
+if test $ac_cv_header_stdc = yes; then
+ cat >> confdefs.h <<\EOF
+#define STDC_HEADERS 1
+EOF
+
+fi
+
+echo $ac_n "checking for off_t""... $ac_c" 1>&6
+echo "configure:1752: checking for off_t" >&5
+if eval "test \"`echo '$''{'ac_cv_type_off_t'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1757 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "(^|[^a-zA-Z_0-9])off_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then
+ rm -rf conftest*
+ ac_cv_type_off_t=yes
+else
+ rm -rf conftest*
+ ac_cv_type_off_t=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_type_off_t" 1>&6
+if test $ac_cv_type_off_t = no; then
+ cat >> confdefs.h <<\EOF
+#define off_t long
+EOF
+
+fi
+
+echo $ac_n "checking for size_t""... $ac_c" 1>&6
+echo "configure:1785: checking for size_t" >&5
+if eval "test \"`echo '$''{'ac_cv_type_size_t'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1790 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "(^|[^a-zA-Z_0-9])size_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then
+ rm -rf conftest*
+ ac_cv_type_size_t=yes
+else
+ rm -rf conftest*
+ ac_cv_type_size_t=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_type_size_t" 1>&6
+if test $ac_cv_type_size_t = no; then
+ cat >> confdefs.h <<\EOF
+#define size_t unsigned
+EOF
+
+fi
+
+echo $ac_n "checking return type of signal handlers""... $ac_c" 1>&6
+echo "configure:1818: checking return type of signal handlers" >&5
+if eval "test \"`echo '$''{'ac_cv_type_signal'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1823 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <signal.h>
+#ifdef signal
+#undef signal
+#endif
+#ifdef __cplusplus
+extern "C" void (*signal (int, void (*)(int)))(int);
+#else
+void (*signal ()) ();
+#endif
+
+int main() {
+int i;
+; return 0; }
+EOF
+if { (eval echo configure:1840: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ac_cv_type_signal=void
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ac_cv_type_signal=int
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_type_signal" 1>&6
+cat >> confdefs.h <<EOF
+#define RETSIGTYPE $ac_cv_type_signal
+EOF
+
+
+echo $ac_n "checking for ssize_t""... $ac_c" 1>&6
+echo "configure:1859: checking for ssize_t" >&5
+if eval "test \"`echo '$''{'ac_cv_type_ssize_t'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1864 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "(^|[^a-zA-Z_0-9])ssize_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then
+ rm -rf conftest*
+ ac_cv_type_ssize_t=yes
+else
+ rm -rf conftest*
+ ac_cv_type_ssize_t=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_type_ssize_t" 1>&6
+if test $ac_cv_type_ssize_t = no; then
+ cat >> confdefs.h <<\EOF
+#define ssize_t int
+EOF
+
+fi
+
+echo $ac_n "checking for time_t""... $ac_c" 1>&6
+echo "configure:1892: checking for time_t" >&5
+if eval "test \"`echo '$''{'ac_cv_type_time_t'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1897 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "(^|[^a-zA-Z_0-9])time_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then
+ rm -rf conftest*
+ ac_cv_type_time_t=yes
+else
+ rm -rf conftest*
+ ac_cv_type_time_t=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_type_time_t" 1>&6
+if test $ac_cv_type_time_t = no; then
+ cat >> confdefs.h <<\EOF
+#define time_t long
+EOF
+
+fi
+
+for ac_hdr in sys/time.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:1928: checking for $ac_hdr" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1933 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1938: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=yes"
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+echo $ac_n "checking whether time.h and sys/time.h may both be included""... $ac_c" 1>&6
+echo "configure:1965: checking whether time.h and sys/time.h may both be included" >&5
+if eval "test \"`echo '$''{'ac_cv_header_time'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1970 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <sys/time.h>
+#include <time.h>
+int main() {
+struct tm *tp;
+; return 0; }
+EOF
+if { (eval echo configure:1979: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ac_cv_header_time=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ac_cv_header_time=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_header_time" 1>&6
+if test $ac_cv_header_time = yes; then
+ cat >> confdefs.h <<\EOF
+#define TIME_WITH_SYS_TIME 1
+EOF
+
+fi
+
+
+echo $ac_n "checking for struct timespec in sys/time.h""... $ac_c" 1>&6
+echo "configure:2001: checking for struct timespec in sys/time.h" >&5
+if eval "test \"`echo '$''{'pthreads_cv_timespec_in_time'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2006 "configure"
+#include "confdefs.h"
+#include <sys/time.h>
+int main() {
+struct timespec foo;
+; return 0; }
+EOF
+if { (eval echo configure:2013: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ pthreads_cv_timespec_in_time=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ pthreads_cv_timespec_in_time=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$pthreads_cv_timespec_in_time" 1>&6
+if test $pthreads_cv_timespec_in_time = yes ; then
+ cat >> confdefs.h <<\EOF
+#define _OS_HAS_TIMESPEC 1
+EOF
+
+fi
+
+if eval "test \"`echo '$''{'pthreads_cv_socklen_t'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2037 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <sys/socket.h>
+int main() {
+socklen_t foo;
+; return 0; }
+EOF
+if { (eval echo configure:2045: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ pthreads_cv_socklen_t=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ pthreads_cv_socklen_t=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$pthreads_cv_socklen_t" 1>&6
+if test $pthreads_cv_socklen_t = yes ; then
+ cat >> confdefs.h <<\EOF
+#define _OS_HAS_SOCKLEN_T 1
+EOF
+
+fi
+
+
+
+echo $ac_n "checking type of size_t""... $ac_c" 1>&6
+echo "configure:2068: checking type of size_t" >&5
+if eval "test \"`echo '$''{'pthreads_cv_type_size_t'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2073 "configure"
+#include "confdefs.h"
+
+#include <stddef.h>
+#include <sys/types.h>
+#ifdef STDC_HEADERS
+#include <stdlib.h>
+#endif
+
+int main() {
+ extern size_t foo;
+; return 0; }
+EOF
+if { (eval echo configure:2086: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ for try_type in "int" "unsigned int" "long" "unsigned long" "short" "unsigned short" "char" "unsigned char" "long long" "unsigned long long" ; do
+ cat > conftest.$ac_ext <<EOF
+#line 2090 "configure"
+#include "confdefs.h"
+
+#include <stddef.h>
+#include <sys/types.h>
+#ifdef STDC_HEADERS
+#include <stdlib.h>
+#endif
+
+int main() {
+ extern size_t foo; extern $try_type foo;
+; return 0; }
+EOF
+if { (eval echo configure:2103: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ pthreads_cv_type_size_t="$try_type" ; break
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+fi
+rm -f conftest*
+ done
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ { echo "configure: error: Can't find system typedef for size_t." 1>&2; exit 1; }
+fi
+rm -f conftest*
+fi
+
+if test -n "$pthreads_cv_type_size_t" ; then
+ cat >> confdefs.h <<EOF
+#define pthread_size_t $pthreads_cv_type_size_t
+EOF
+
+fi
+pthread_size_t=$pthreads_cv_type_size_t
+echo "$ac_t""$pthreads_cv_type_size_t" 1>&6
+
+echo $ac_n "checking type of ssize_t""... $ac_c" 1>&6
+echo "configure:2131: checking type of ssize_t" >&5
+if eval "test \"`echo '$''{'pthreads_cv_type_ssize_t'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2136 "configure"
+#include "confdefs.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+int main() {
+ extern ssize_t foo;
+; return 0; }
+EOF
+if { (eval echo configure:2147: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ for try_type in "int" "unsigned int" "long" "unsigned long" "short" "unsigned short" "char" "unsigned char" "long long" "unsigned long long" ; do
+ cat > conftest.$ac_ext <<EOF
+#line 2151 "configure"
+#include "confdefs.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+int main() {
+ extern ssize_t foo; extern $try_type foo;
+; return 0; }
+EOF
+if { (eval echo configure:2162: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ pthreads_cv_type_ssize_t="$try_type" ; break
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+fi
+rm -f conftest*
+ done
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ { echo "configure: error: Can't find system typedef for ssize_t." 1>&2; exit 1; }
+fi
+rm -f conftest*
+fi
+
+if test -n "$pthreads_cv_type_ssize_t" ; then
+ cat >> confdefs.h <<EOF
+#define pthread_ssize_t $pthreads_cv_type_ssize_t
+EOF
+
+fi
+pthread_ssize_t=$pthreads_cv_type_ssize_t
+echo "$ac_t""$pthreads_cv_type_ssize_t" 1>&6
+
+echo $ac_n "checking type of clock_t""... $ac_c" 1>&6
+echo "configure:2190: checking type of clock_t" >&5
+if eval "test \"`echo '$''{'pthreads_cv_type_clock_t'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2195 "configure"
+#include "confdefs.h"
+
+#include <stddef.h>
+#if TIME_WITH_SYS_TIME
+# include <time.h>
+# include <sys/time.h>
+#else
+# if HAVE_SYS_TIME_H
+# include <sys/time.h>
+# else
+# include <time.h>
+# endif
+#endif
+
+int main() {
+ extern clock_t foo;
+; return 0; }
+EOF
+if { (eval echo configure:2214: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ for try_type in "int" "unsigned int" "long" "unsigned long" "short" "unsigned short" "char" "unsigned char" "long long" "unsigned long long" ; do
+ cat > conftest.$ac_ext <<EOF
+#line 2218 "configure"
+#include "confdefs.h"
+
+#include <stddef.h>
+#if TIME_WITH_SYS_TIME
+# include <time.h>
+# include <sys/time.h>
+#else
+# if HAVE_SYS_TIME_H
+# include <sys/time.h>
+# else
+# include <time.h>
+# endif
+#endif
+
+int main() {
+ extern clock_t foo; extern $try_type foo;
+; return 0; }
+EOF
+if { (eval echo configure:2237: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ pthreads_cv_type_clock_t="$try_type" ; break
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+fi
+rm -f conftest*
+ done
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ { echo "configure: error: Can't find system typedef for clock_t." 1>&2; exit 1; }
+fi
+rm -f conftest*
+fi
+
+if test -n "$pthreads_cv_type_clock_t" ; then
+ cat >> confdefs.h <<EOF
+#define pthread_clock_t $pthreads_cv_type_clock_t
+EOF
+
+fi
+pthread_clock_t=$pthreads_cv_type_clock_t
+echo "$ac_t""$pthreads_cv_type_clock_t" 1>&6
+
+echo $ac_n "checking type of time_t""... $ac_c" 1>&6
+echo "configure:2265: checking type of time_t" >&5
+if eval "test \"`echo '$''{'pthreads_cv_type_time_t'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2270 "configure"
+#include "confdefs.h"
+
+#include <stddef.h>
+#if TIME_WITH_SYS_TIME
+# include <time.h>
+# include <sys/time.h>
+#else
+# if HAVE_SYS_TIME_H
+# include <sys/time.h>
+# else
+# include <time.h>
+# endif
+#endif
+
+int main() {
+ extern time_t foo;
+; return 0; }
+EOF
+if { (eval echo configure:2289: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ for try_type in "int" "unsigned int" "long" "unsigned long" "short" "unsigned short" "char" "unsigned char" "long long" "unsigned long long" ; do
+ cat > conftest.$ac_ext <<EOF
+#line 2293 "configure"
+#include "confdefs.h"
+
+#include <stddef.h>
+#if TIME_WITH_SYS_TIME
+# include <time.h>
+# include <sys/time.h>
+#else
+# if HAVE_SYS_TIME_H
+# include <sys/time.h>
+# else
+# include <time.h>
+# endif
+#endif
+
+int main() {
+ extern time_t foo; extern $try_type foo;
+; return 0; }
+EOF
+if { (eval echo configure:2312: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ pthreads_cv_type_time_t="$try_type" ; break
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+fi
+rm -f conftest*
+ done
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ { echo "configure: error: Can't find system typedef for time_t." 1>&2; exit 1; }
+fi
+rm -f conftest*
+fi
+
+if test -n "$pthreads_cv_type_time_t" ; then
+ cat >> confdefs.h <<EOF
+#define pthread_time_t $pthreads_cv_type_time_t
+EOF
+
+fi
+pthread_time_t=$pthreads_cv_type_time_t
+echo "$ac_t""$pthreads_cv_type_time_t" 1>&6
+echo $ac_n "checking for fpos_t in stdio.h""... $ac_c" 1>&6
+echo "configure:2339: checking for fpos_t in stdio.h" >&5
+if eval "test \"`echo '$''{'pthreads_cv_fpos_t_in_stdio'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2344 "configure"
+#include "confdefs.h"
+#include <stdio.h>
+int main() {
+fpos_t position;
+; return 0; }
+EOF
+if { (eval echo configure:2351: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ pthreads_cv_fpos_t_in_stdio=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ pthreads_cv_fpos_t_in_stdio=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$pthreads_cv_fpos_t_in_stdio" 1>&6
+if test $pthreads_cv_fpos_t_in_stdio = yes ; then
+
+echo $ac_n "checking type of fpos_t""... $ac_c" 1>&6
+echo "configure:2367: checking type of fpos_t" >&5
+if eval "test \"`echo '$''{'pthreads_cv_type_fpos_t'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2372 "configure"
+#include "confdefs.h"
+
+#include <stdio.h>
+#include <sys/types.h>
+#ifdef STDC_HEADERS
+#include <stdlib.h>
+#endif
+
+int main() {
+ extern fpos_t foo;
+; return 0; }
+EOF
+if { (eval echo configure:2385: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ for try_type in "int" "unsigned int" "long" "unsigned long" "short" "unsigned short" "char" "unsigned char" "long long" "unsigned long long" ; do
+ cat > conftest.$ac_ext <<EOF
+#line 2389 "configure"
+#include "confdefs.h"
+
+#include <stdio.h>
+#include <sys/types.h>
+#ifdef STDC_HEADERS
+#include <stdlib.h>
+#endif
+
+int main() {
+ extern fpos_t foo; extern $try_type foo;
+; return 0; }
+EOF
+if { (eval echo configure:2402: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ pthreads_cv_type_fpos_t="$try_type" ; break
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+fi
+rm -f conftest*
+ done
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ { echo "configure: error: Can't find system typedef for fpos_t." 1>&2; exit 1; }
+fi
+rm -f conftest*
+fi
+
+if test -n "$pthreads_cv_type_fpos_t" ; then
+ cat >> confdefs.h <<EOF
+#define pthread_fpos_t $pthreads_cv_type_fpos_t
+EOF
+
+fi
+pthread_fpos_t=$pthreads_cv_type_fpos_t
+echo "$ac_t""$pthreads_cv_type_fpos_t" 1>&6
+else
+ cat >> confdefs.h <<\EOF
+#define fpos_t off_t
+EOF
+
+ cat >> confdefs.h <<\EOF
+#define pthread_fpos_t pthread_off_t
+EOF
+
+fi
+
+echo $ac_n "checking type of off_t""... $ac_c" 1>&6
+echo "configure:2440: checking type of off_t" >&5
+if eval "test \"`echo '$''{'pthreads_cv_type_off_t'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2445 "configure"
+#include "confdefs.h"
+
+#include <stdio.h>
+#include <sys/types.h>
+#ifdef STDC_HEADERS
+#include <stdlib.h>
+#endif
+
+int main() {
+ extern off_t foo;
+; return 0; }
+EOF
+if { (eval echo configure:2458: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ for try_type in "int" "unsigned int" "long" "unsigned long" "short" "unsigned short" "char" "unsigned char" "long long" "unsigned long long" ; do
+ cat > conftest.$ac_ext <<EOF
+#line 2462 "configure"
+#include "confdefs.h"
+
+#include <stdio.h>
+#include <sys/types.h>
+#ifdef STDC_HEADERS
+#include <stdlib.h>
+#endif
+
+int main() {
+ extern off_t foo; extern $try_type foo;
+; return 0; }
+EOF
+if { (eval echo configure:2475: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ pthreads_cv_type_off_t="$try_type" ; break
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+fi
+rm -f conftest*
+ done
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ { echo "configure: error: Can't find system typedef for off_t." 1>&2; exit 1; }
+fi
+rm -f conftest*
+fi
+
+if test -n "$pthreads_cv_type_off_t" ; then
+ cat >> confdefs.h <<EOF
+#define pthread_off_t $pthreads_cv_type_off_t
+EOF
+
+fi
+pthread_off_t=$pthreads_cv_type_off_t
+echo "$ac_t""$pthreads_cv_type_off_t" 1>&6
+echo $ac_n "checking type of va_list""... $ac_c" 1>&6
+echo "configure:2502: checking type of va_list" >&5
+if eval "test \"`echo '$''{'pthreads_cv_type_va_list'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2507 "configure"
+#include "confdefs.h"
+#include <stdarg.h>
+int main() {
+ extern va_list foo;
+; return 0; }
+EOF
+if { (eval echo configure:2514: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ for try_type in "char *" "char **" "void *" "void **" "int *" "long *" ; do
+ cat > conftest.$ac_ext <<EOF
+#line 2518 "configure"
+#include "confdefs.h"
+#include <stdarg.h>
+int main() {
+ extern va_list foo; extern $try_type foo;
+; return 0; }
+EOF
+if { (eval echo configure:2525: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ pthreads_cv_type_va_list="$try_type" ; break
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+fi
+rm -f conftest*
+ done
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ { echo "configure: error: Can't find system typedef for va_list." 1>&2; exit 1; }
+fi
+rm -f conftest*
+fi
+
+if test -n "$pthreads_cv_type_va_list" ; then
+ cat >> confdefs.h <<EOF
+#define pthread_va_list $pthreads_cv_type_va_list
+EOF
+
+fi
+pthread_va_list=$pthreads_cv_type_va_list
+echo "$ac_t""$pthreads_cv_type_va_list" 1>&6
+
+arpa_headers="#include <sys/types.h>
+#include <arpa/nameser.h>"
+
+echo $ac_n "checking IP address type""... $ac_c" 1>&6
+echo "configure:2556: checking IP address type" >&5
+if eval "test \"`echo '$''{'pthread_cv_type_ipaddr'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2561 "configure"
+#include "confdefs.h"
+$arpa_headers
+int main() {
+ &_getlong;
+; return 0; }
+EOF
+if { (eval echo configure:2568: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+
+ for type in "unsigned long" "unsigned int" ; do
+ cat > conftest.$ac_ext <<EOF
+#line 2573 "configure"
+#include "confdefs.h"
+$arpa_headers
+int main() {
+extern $type _getlong ();
+; return 0; }
+EOF
+if { (eval echo configure:2580: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+
+ pthread_cv_type_ipaddr="$type"
+ break
+
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+fi
+rm -f conftest*
+ done
+
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ echo "configure: warning: Can't compile _getlong reference." 1>&2
+fi
+rm -f conftest*
+ if test "$pthread_cv_type_ipaddr" = "" ; then
+ echo "configure: warning: Can't determine _getlong return type." 1>&2
+ echo "configure: warning: Defaulting to unsigned long." 1>&2
+ pthread_cv_type_ipaddr="unsigned long"
+ fi
+
+fi
+
+echo "$ac_t""$pthread_cv_type_ipaddr" 1>&6
+cat >> confdefs.h <<EOF
+#define pthread_ipaddr_type $pthread_cv_type_ipaddr
+EOF
+
+
+echo $ac_n "checking IP port type""... $ac_c" 1>&6
+echo "configure:2615: checking IP port type" >&5
+if eval "test \"`echo '$''{'pthread_cv_type_ipport'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2620 "configure"
+#include "confdefs.h"
+$arpa_headers
+int main() {
+ &_getshort;
+; return 0; }
+EOF
+if { (eval echo configure:2627: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+
+ for type in "unsigned short" "unsigned int" ; do
+ cat > conftest.$ac_ext <<EOF
+#line 2632 "configure"
+#include "confdefs.h"
+$arpa_headers
+int main() {
+extern $type _getshort ();
+; return 0; }
+EOF
+if { (eval echo configure:2639: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+
+ pthread_cv_type_ipport="$type"
+ break
+
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+fi
+rm -f conftest*
+ done
+
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ echo "configure: warning: Can't compile _getshort reference." 1>&2
+fi
+rm -f conftest*
+ if test "$pthread_cv_type_ipport" = "" ; then
+ echo "configure: warning: Can't determine _getshort return type." 1>&2
+ echo "configure: warning: Defaulting to unsigned short." 1>&2
+ pthread_cv_type_ipport="unsigned short"
+ fi
+
+fi
+
+echo "$ac_t""$pthread_cv_type_ipport" 1>&6
+cat >> confdefs.h <<EOF
+#define pthread_ipport_type $pthread_cv_type_ipport
+EOF
+
+
+echo $ac_n "checking pathname for terminal devices directory""... $ac_c" 1>&6
+echo "configure:2674: checking pathname for terminal devices directory" >&5
+if eval "test \"`echo '$''{'pthread_cv_pty_path'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -d /devices/pseudo ; then
+ pty_path=/devices/pseudo/
+ else
+ pty_path=/dev/
+ fi
+ pthread_cv_pty_path=$pty_path
+
+fi
+
+cat >> confdefs.h <<EOF
+#define _PATH_PTY "$pthread_cv_pty_path"
+EOF
+
+echo "$ac_t""$pthread_cv_pty_path" 1>&6
+
+echo $ac_n "checking directory name for time zone info""... $ac_c" 1>&6
+echo "configure:2694: checking directory name for time zone info" >&5
+tzdir=NONE
+for f in /usr/lib/zoneinfo /usr/share/zoneinfo /usr/share/lib/zoneinfo /etc/zoneinfo /usr/local/lib/zoneinfo
+do
+ if test -d $f ; then
+ tzdir=$f
+ break
+ fi
+done
+case $tzdir in
+NONE)
+ echo "configure: warning: Can't find zoneinfo directory." 1>&2
+ echo "configure: warning: Defaulting zoneinfo directory to NULL." 1>&2
+ tzdir=NULL
+ ;;
+esac
+cat >> confdefs.h <<EOF
+#define _PATH_TZDIR "$tzdir"
+EOF
+
+echo "$ac_t""$tzdir" 1>&6
+
+echo $ac_n "checking filename for local time zone""... $ac_c" 1>&6
+echo "configure:2717: checking filename for local time zone" >&5
+tzfile=NONE
+for f in $tzdir/localtime /etc/localtime
+do
+ if test -f $f ; then
+ tzfile=$f
+ break
+ fi
+done
+case $tzfile in
+NONE) # Should this default to tzdir/localtime?
+ echo "configure: warning: Can't find local time zone file." 1>&2
+ if test tzdir = NULL ; then
+ echo "configure: warning: Defaulting local time zone file to NULL" 1>&2
+ tzfile=NULL
+ else
+ echo "configure: warning: Defaulting local time zone file to $tzdir/localtime." 1>&2
+ tzfile=$tzdir/localtime
+ fi
+ ;;
+esac
+cat >> confdefs.h <<EOF
+#define _PATH_TZFILE "$tzfile"
+EOF
+
+echo "$ac_t""$tzfile" 1>&6
+
+cat >> confdefs.h <<\EOF
+#define _PATH_RESCONF "/etc/resolv.conf"
+EOF
+
+cat >> confdefs.h <<\EOF
+#define _PATH_HOSTS "/etc/hosts"
+EOF
+
+cat >> confdefs.h <<\EOF
+#define _PATH_NETWORKS "/etc/networks"
+EOF
+
+cat >> confdefs.h <<\EOF
+#define _PATH_PROTOCOLS "/etc/protocols"
+EOF
+
+cat >> confdefs.h <<\EOF
+#define _PATH_SERVICES "/etc/services"
+EOF
+
+
+cat >> confdefs.h <<\EOF
+#define _PATH_BSHELL "/bin/sh"
+EOF
+
+
+for ac_func in vfork
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:2773: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2778 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:2801: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+
+srctop=`cd ${srcdir}/..;pwd`
+
+
+# Now we deal with symlinks &c.
+
+test -d include || mkdir include || \
+ { echo "configure: error: Can't create include directory." 1>&2; exit 1; }
+
+test -d include/pthread || mkdir include/pthread || \
+ { echo "configure: error: Can't create include/pthread directory." 1>&2; exit 1; }
+
+test -d lib || mkdir lib || \
+ { echo "configure: error: Can't create lib directory." 1>&2; exit 1; }
+
+test -d lib/libpthreadutil || mkdir lib/libpthreadutil || \
+ { echo "configure: error: Can't create lib/libpthreadutil directory." 1>&2; exit 1; }
+
+test -d bin || mkdir bin || \
+ { echo "configure: error: Can't create bin directory." 1>&2; exit 1; }
+
+test -d bin/finger || mkdir bin/finger || \
+ { echo "configure: error: Can't create bin directory." 1>&2; exit 1; }
+
+test -d tests || mkdir tests || \
+ { echo "configure: error: Can't create tests directory." 1>&2; exit 1; }
+
+if test x$syscall = xNONE ; then
+ syscall=$name
+fi
+
+links="include/pthread/machdep.h include/pthread/posix.h \
+ machdep.c syscall.S"
+targets="../machdep/engine-$name.h ../machdep/posix-$sysincludes.h \
+ ../machdep/engine-$name.c ../machdep/syscall-$syscall.S"
+
+# Both these targets are optional. (Autoconf-generated configure scripts
+# will require the existence of link targets, so check before adding them
+# to the list.)
+if test x$sysincludes != xNONE ; then
+ links="$links include/sys"
+ targets="$targets ../machdep/$sysincludes"
+fi
+
+if test x$extraincludes != xNONE ; then
+ for tmp in $extraincludes
+ do
+ links="$links include/$tmp"
+ targets="$targets ../machdep/$sysincludes/extra/$tmp"
+ done
+fi
+
+syscall_file=../machdep/syscall-template-$syscall.S
+if test -r $srcdir/$syscall_file ; then
+ links="$links syscall-template.S"
+ targets="$targets $syscall_file"
+ HAVE_SYSCALL_TEMPLATE=yes
+else
+ # This really isn't a fatal problem. In fact, it's expected, initially,
+ # for some targets. This is just to persuade people to fix the targets
+ # they deal with to provide some sort of template.
+ #
+ # Eventually this file probably will be required...
+ echo "configure: warning: No syscall template file syscall-template-$syscall.S found." 1>&2
+ HAVE_SYSCALL_TEMPLATE=no
+fi
+
+
+
+
+if test x$makefile_frag != x ; then
+ makefile_frag=${srcdir}/$makefile_frag
+else
+ makefile_frag=/dev/null
+fi
+
+
+
+
+
+trap '' 1 2 15
+cat > confcache <<\EOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs. It is not useful on other systems.
+# If it contains results you don't want to keep, you may remove or edit it.
+#
+# By default, configure uses ./config.cache as the cache file,
+# creating it if it does not exist already. You can give configure
+# the --cache-file=FILE option to use a different cache file; that is
+# what configure does when it calls configure scripts in
+# subdirectories, so they share the cache.
+# Giving --cache-file=/dev/null disables caching, for debugging configure.
+# config.status only pays attention to the cache file if you give it the
+# --recheck option to rerun configure.
+#
+EOF
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, don't put newlines in cache variables' values.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(set) 2>&1 |
+ case `(ac_space=' '; set | grep ac_space) 2>&1` in
+ *ac_space=\ *)
+ # `set' does not quote correctly, so add quotes (double-quote substitution
+ # turns \\\\ into \\, and sed turns \\ into \).
+ sed -n \
+ -e "s/'/'\\\\''/g" \
+ -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p"
+ ;;
+ *)
+ # `set' quotes correctly as required by POSIX, so do not add quotes.
+ sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p'
+ ;;
+ esac >> confcache
+if cmp -s $cache_file confcache; then
+ :
+else
+ if test -w $cache_file; then
+ echo "updating cache $cache_file"
+ cat confcache > $cache_file
+ else
+ echo "not updating unwritable cache $cache_file"
+ fi
+fi
+rm -f confcache
+
+trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+# Any assignment to VPATH causes Sun make to only execute
+# the first set of double-colon rules, so remove it if not needed.
+# If there is a colon in the path, we need to keep it.
+if test "x$srcdir" = x.; then
+ ac_vpsub='/^[ ]*VPATH[ ]*=[^:]*$/d'
+fi
+
+trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15
+
+DEFS=-DHAVE_CONFIG_H
+
+# Without the "./", some shells look in PATH for config.status.
+: ${CONFIG_STATUS=./config.status}
+
+echo creating $CONFIG_STATUS
+rm -f $CONFIG_STATUS
+cat > $CONFIG_STATUS <<EOF
+#! /bin/sh
+# Generated automatically by configure.
+# Run this file to recreate the current configuration.
+# This directory was configured as follows,
+# on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+#
+# $0 $ac_configure_args
+#
+# Compiler output produced by configure, useful for debugging
+# configure, is in ./config.log if it exists.
+
+ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]"
+for ac_option
+do
+ case "\$ac_option" in
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion"
+ exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;;
+ -version | --version | --versio | --versi | --vers | --ver | --ve | --v)
+ echo "$CONFIG_STATUS generated by autoconf version 2.13"
+ exit 0 ;;
+ -help | --help | --hel | --he | --h)
+ echo "\$ac_cs_usage"; exit 0 ;;
+ *) echo "\$ac_cs_usage"; exit 1 ;;
+ esac
+done
+
+ac_given_srcdir=$srcdir
+
+trap 'rm -fr `echo "config.flags GNUmakefile Makefile \
+ lib/Makefile:../lib/Makefile.in \
+ lib/libpthreadutil/Makefile:../lib/libpthreadutil/Makefile.in \
+ bin/Makefile:../bin/Makefile.in \
+ bin/finger/Makefile:../bin/finger/Makefile.in \
+ tests/Makefile:../tests/Makefile.in config.h" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15
+EOF
+cat >> $CONFIG_STATUS <<EOF
+
+# Protect against being on the right side of a sed subst in config.status.
+sed 's/%@/@@/; s/@%/@@/; s/%g\$/@g/; /@g\$/s/[\\\\&%]/\\\\&/g;
+ s/@@/%@/; s/@@/@%/; s/@g\$/%g/' > conftest.subs <<\\CEOF
+$ac_vpsub
+$extrasub
+s%@SHELL@%$SHELL%g
+s%@CFLAGS@%$CFLAGS%g
+s%@CPPFLAGS@%$CPPFLAGS%g
+s%@CXXFLAGS@%$CXXFLAGS%g
+s%@FFLAGS@%$FFLAGS%g
+s%@DEFS@%$DEFS%g
+s%@LDFLAGS@%$LDFLAGS%g
+s%@LIBS@%$LIBS%g
+s%@exec_prefix@%$exec_prefix%g
+s%@prefix@%$prefix%g
+s%@program_transform_name@%$program_transform_name%g
+s%@bindir@%$bindir%g
+s%@sbindir@%$sbindir%g
+s%@libexecdir@%$libexecdir%g
+s%@datadir@%$datadir%g
+s%@sysconfdir@%$sysconfdir%g
+s%@sharedstatedir@%$sharedstatedir%g
+s%@localstatedir@%$localstatedir%g
+s%@libdir@%$libdir%g
+s%@includedir@%$includedir%g
+s%@oldincludedir@%$oldincludedir%g
+s%@infodir@%$infodir%g
+s%@mandir@%$mandir%g
+s%@CC@%$CC%g
+s%@CXX@%$CXX%g
+s%@CPP@%$CPP%g
+s%@RANLIB@%$RANLIB%g
+s%@host@%$host%g
+s%@host_alias@%$host_alias%g
+s%@host_cpu@%$host_cpu%g
+s%@host_vendor@%$host_vendor%g
+s%@host_os@%$host_os%g
+s%@target@%$target%g
+s%@target_alias@%$target_alias%g
+s%@target_cpu@%$target_cpu%g
+s%@target_vendor@%$target_vendor%g
+s%@target_os@%$target_os%g
+s%@build@%$build%g
+s%@build_alias@%$build_alias%g
+s%@build_cpu@%$build_cpu%g
+s%@build_vendor@%$build_vendor%g
+s%@build_os@%$build_os%g
+s%@SYSCALL_EXCEPTIONS@%$SYSCALL_EXCEPTIONS%g
+s%@available_syscalls@%$available_syscalls%g
+s%@missing_syscalls@%$missing_syscalls%g
+s%@srctop@%$srctop%g
+s%@HAVE_SYSCALL_TEMPLATE@%$HAVE_SYSCALL_TEMPLATE%g
+/@makefile_frag@/r $makefile_frag
+s%@makefile_frag@%%g
+
+CEOF
+EOF
+
+cat >> $CONFIG_STATUS <<\EOF
+
+# Split the substitutions into bite-sized pieces for seds with
+# small command number limits, like on Digital OSF/1 and HP-UX.
+ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script.
+ac_file=1 # Number of current file.
+ac_beg=1 # First line for current file.
+ac_end=$ac_max_sed_cmds # Line after last line for current file.
+ac_more_lines=:
+ac_sed_cmds=""
+while $ac_more_lines; do
+ if test $ac_beg -gt 1; then
+ sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file
+ else
+ sed "${ac_end}q" conftest.subs > conftest.s$ac_file
+ fi
+ if test ! -s conftest.s$ac_file; then
+ ac_more_lines=false
+ rm -f conftest.s$ac_file
+ else
+ if test -z "$ac_sed_cmds"; then
+ ac_sed_cmds="sed -f conftest.s$ac_file"
+ else
+ ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file"
+ fi
+ ac_file=`expr $ac_file + 1`
+ ac_beg=$ac_end
+ ac_end=`expr $ac_end + $ac_max_sed_cmds`
+ fi
+done
+if test -z "$ac_sed_cmds"; then
+ ac_sed_cmds=cat
+fi
+EOF
+
+cat >> $CONFIG_STATUS <<EOF
+
+CONFIG_FILES=\${CONFIG_FILES-"config.flags GNUmakefile Makefile \
+ lib/Makefile:../lib/Makefile.in \
+ lib/libpthreadutil/Makefile:../lib/libpthreadutil/Makefile.in \
+ bin/Makefile:../bin/Makefile.in \
+ bin/finger/Makefile:../bin/finger/Makefile.in \
+ tests/Makefile:../tests/Makefile.in"}
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then
+ # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+ case "$ac_file" in
+ *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'`
+ ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
+ *) ac_file_in="${ac_file}.in" ;;
+ esac
+
+ # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories.
+
+ # Remove last slash and all that follows it. Not all systems have dirname.
+ ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
+ if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
+ # The file is in a subdirectory.
+ test ! -d "$ac_dir" && mkdir "$ac_dir"
+ ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`"
+ # A "../" for each directory in $ac_dir_suffix.
+ ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'`
+ else
+ ac_dir_suffix= ac_dots=
+ fi
+
+ case "$ac_given_srcdir" in
+ .) srcdir=.
+ if test -z "$ac_dots"; then top_srcdir=.
+ else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;;
+ /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;;
+ *) # Relative path.
+ srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix"
+ top_srcdir="$ac_dots$ac_given_srcdir" ;;
+ esac
+
+
+ echo creating "$ac_file"
+ rm -f "$ac_file"
+ configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure."
+ case "$ac_file" in
+ *Makefile*) ac_comsub="1i\\
+# $configure_input" ;;
+ *) ac_comsub= ;;
+ esac
+
+ ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"`
+ sed -e "$ac_comsub
+s%@configure_input@%$configure_input%g
+s%@srcdir@%$srcdir%g
+s%@top_srcdir@%$top_srcdir%g
+" $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file
+fi; done
+rm -f conftest.s*
+
+# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where
+# NAME is the cpp macro being defined and VALUE is the value it is being given.
+#
+# ac_d sets the value in "#define NAME VALUE" lines.
+ac_dA='s%^\([ ]*\)#\([ ]*define[ ][ ]*\)'
+ac_dB='\([ ][ ]*\)[^ ]*%\1#\2'
+ac_dC='\3'
+ac_dD='%g'
+# ac_u turns "#undef NAME" with trailing blanks into "#define NAME VALUE".
+ac_uA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)'
+ac_uB='\([ ]\)%\1#\2define\3'
+ac_uC=' '
+ac_uD='\4%g'
+# ac_e turns "#undef NAME" without trailing blanks into "#define NAME VALUE".
+ac_eA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)'
+ac_eB='$%\1#\2define\3'
+ac_eC=' '
+ac_eD='%g'
+
+if test "${CONFIG_HEADERS+set}" != set; then
+EOF
+cat >> $CONFIG_STATUS <<EOF
+ CONFIG_HEADERS="config.h"
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+fi
+for ac_file in .. $CONFIG_HEADERS; do if test "x$ac_file" != x..; then
+ # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+ case "$ac_file" in
+ *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'`
+ ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
+ *) ac_file_in="${ac_file}.in" ;;
+ esac
+
+ echo creating $ac_file
+
+ rm -f conftest.frag conftest.in conftest.out
+ ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"`
+ cat $ac_file_inputs > conftest.in
+
+EOF
+
+# Transform confdefs.h into a sed script conftest.vals that substitutes
+# the proper values into config.h.in to produce config.h. And first:
+# Protect against being on the right side of a sed subst in config.status.
+# Protect against being in an unquoted here document in config.status.
+rm -f conftest.vals
+cat > conftest.hdr <<\EOF
+s/[\\&%]/\\&/g
+s%[\\$`]%\\&%g
+s%#define \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD}%gp
+s%ac_d%ac_u%gp
+s%ac_u%ac_e%gp
+EOF
+sed -n -f conftest.hdr confdefs.h > conftest.vals
+rm -f conftest.hdr
+
+# This sed command replaces #undef with comments. This is necessary, for
+# example, in the case of _POSIX_SOURCE, which is predefined and required
+# on some systems where configure will not decide to define it.
+cat >> conftest.vals <<\EOF
+s%^[ ]*#[ ]*undef[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*%/* & */%
+EOF
+
+# Break up conftest.vals because some shells have a limit on
+# the size of here documents, and old seds have small limits too.
+
+rm -f conftest.tail
+while :
+do
+ ac_lines=`grep -c . conftest.vals`
+ # grep -c gives empty output for an empty file on some AIX systems.
+ if test -z "$ac_lines" || test "$ac_lines" -eq 0; then break; fi
+ # Write a limited-size here document to conftest.frag.
+ echo ' cat > conftest.frag <<CEOF' >> $CONFIG_STATUS
+ sed ${ac_max_here_lines}q conftest.vals >> $CONFIG_STATUS
+ echo 'CEOF
+ sed -f conftest.frag conftest.in > conftest.out
+ rm -f conftest.in
+ mv conftest.out conftest.in
+' >> $CONFIG_STATUS
+ sed 1,${ac_max_here_lines}d conftest.vals > conftest.tail
+ rm -f conftest.vals
+ mv conftest.tail conftest.vals
+done
+rm -f conftest.vals
+
+cat >> $CONFIG_STATUS <<\EOF
+ rm -f conftest.frag conftest.h
+ echo "/* $ac_file. Generated automatically by configure. */" > conftest.h
+ cat conftest.in >> conftest.h
+ rm -f conftest.in
+ if cmp -s $ac_file conftest.h 2>/dev/null; then
+ echo "$ac_file is unchanged"
+ rm -f conftest.h
+ else
+ # Remove last slash and all that follows it. Not all systems have dirname.
+ ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
+ if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
+ # The file is in a subdirectory.
+ test ! -d "$ac_dir" && mkdir "$ac_dir"
+ fi
+ rm -f $ac_file
+ mv conftest.h $ac_file
+ fi
+fi; done
+
+EOF
+
+cat >> $CONFIG_STATUS <<EOF
+ac_sources="$targets"
+ac_dests="$links"
+EOF
+
+cat >> $CONFIG_STATUS <<\EOF
+srcdir=$ac_given_srcdir
+while test -n "$ac_sources"; do
+ set $ac_dests; ac_dest=$1; shift; ac_dests=$*
+ set $ac_sources; ac_source=$1; shift; ac_sources=$*
+
+ echo "linking $srcdir/$ac_source to $ac_dest"
+
+ if test ! -r $srcdir/$ac_source; then
+ { echo "configure: error: $srcdir/$ac_source: File not found" 1>&2; exit 1; }
+ fi
+ rm -f $ac_dest
+
+ # Make relative symlinks.
+ # Remove last slash and all that follows it. Not all systems have dirname.
+ ac_dest_dir=`echo $ac_dest|sed 's%/[^/][^/]*$%%'`
+ if test "$ac_dest_dir" != "$ac_dest" && test "$ac_dest_dir" != .; then
+ # The dest file is in a subdirectory.
+ test ! -d "$ac_dest_dir" && mkdir "$ac_dest_dir"
+ ac_dest_dir_suffix="/`echo $ac_dest_dir|sed 's%^\./%%'`"
+ # A "../" for each directory in $ac_dest_dir_suffix.
+ ac_dots=`echo $ac_dest_dir_suffix|sed 's%/[^/]*%../%g'`
+ else
+ ac_dest_dir_suffix= ac_dots=
+ fi
+
+ case "$srcdir" in
+ [/$]*) ac_rel_source="$srcdir/$ac_source" ;;
+ *) ac_rel_source="$ac_dots$srcdir/$ac_source" ;;
+ esac
+
+ # Make a symlink if possible; otherwise try a hard link.
+ if ln -s $ac_rel_source $ac_dest 2>/dev/null ||
+ ln $srcdir/$ac_source $ac_dest; then :
+ else
+ { echo "configure: error: can not link $ac_dest to $srcdir/$ac_source" 1>&2; exit 1; }
+ fi
+done
+EOF
+cat >> $CONFIG_STATUS <<EOF
+
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+
+exit 0
+EOF
+chmod +x $CONFIG_STATUS
+rm -fr confdefs* $ac_clean_files
+test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1
+
diff --git a/mit-pthreads/config/configure.in b/mit-pthreads/config/configure.in
new file mode 100755
index 00000000000..c623ddc4343
--- /dev/null
+++ b/mit-pthreads/config/configure.in
@@ -0,0 +1,739 @@
+dnl Some reminders:
+dnl "dnl" is a "delete to newline" command for m4 - the remainder of the
+dnl line it's on, including the newline, will be discarded
+dnl "#" comments will usually be copied through
+dnl "[]" are quoting characters; use changequote around code that really
+dnl needs to use them, but try not to invoke autoconf macros
+dnl within such code
+dnl
+dnl When you change this file, re-run "autoreconf" -- that'll automatically
+dnl re-run both autoconf and autoheader.
+dnl
+dnl
+dnl To do:
+dnl CLOCKS_PER_SEC (default 100, Ultrix differs)
+dnl CLK_TCK (default 100, Ultrix differs)
+dnl clockid_t (not on all systems)
+dnl timer_t (not on all systems)
+dnl
+dnl
+dnl Now, the real stuff.
+dnl
+dnl This must be first.
+AC_INIT(config.flags.in)
+dnl
+dnl This file does require autoconf 2.0 or better...
+dnl
+AC_PREREQ(2.0)dnl
+dnl
+dnl Hook for the "--enable-dce-compat" option, when Chris actually
+dnl implements it.
+dnl
+AC_ARG_ENABLE(dce-compat,
+ --enable-dce-compat DCE compatibility,
+[dnl "true" action
+ AC_MSG_ERROR([Actually, DCE compatibility doesn't work yet...])
+],
+[dnl "false" action
+ true
+])
+
+dnl What C compiler?
+AC_PROG_CC
+AC_PROG_CXX
+dnl Apparently autoconf doesn't test to see if the C compiler it locates
+dnl actually works... oops!
+AC_MSG_CHECKING(compiler availability and simple error detection)
+AC_TRY_COMPILE(,[ exit(0); ],[
+ dnl true
+ AC_TRY_COMPILE(,[ syntax errors galore! ],
+ dnl true
+ AC_MSG_ERROR(Can't detect syntax errors! Is CC set right?),
+ dnl false
+ true)],
+ dnl false
+ AC_MSG_ERROR(Can't compile test program! Is CC set right?))
+
+AC_TRY_COMPILE(,[
+ typedef int Integer;
+ extern int i;
+ extern Integer i;
+], , AC_MSG_ERROR(Can't redeclare variables with this compiler??))
+AC_TRY_COMPILE(,[
+ typedef long Long;
+ extern int i;
+ extern Long i;
+], AC_MSG_ERROR(Compiler doesn't detect conflicting declarations.))
+AC_MSG_RESULT(ok)
+
+if test $ac_cv_prog_gcc = yes ; then
+ CFLAGS="$CFLAGS -Werror"
+fi
+
+AC_PROG_CPP
+
+AC_PROG_RANLIB
+
+dnl Default value of prefix should be /usr/local/pthreads, not /usr/local.
+AC_PREFIX_DEFAULT(/usr/local/pthreads)
+
+dnl Determine $host, by guessing if necessary.
+AC_CANONICAL_SYSTEM
+
+syscall=NONE
+sysincludes=NONE
+extraincludes=NONE
+
+# Treat all x86 machines the same.
+# (Yet below, we pretend we can distinguish between the MIPS r2000 and r4000?)
+# (What about 680x0 machines?)
+changequote(,)dnl
+case $host in
+ i[456]86-*)
+ host=`echo $host | sed 's/^i[456]86/i386/'`
+ host_cpu=i386
+ ;;
+esac
+changequote([,])dnl
+
+# Here, you should set the following variables:
+# name
+# The "name" of this configuration. Used for "engine-*.c" file name,
+# default for syscall file names. Chris seems to have a thing for
+# putting "-" between OS and version number, but the configure script
+# will already have $host_cpu and $host_os available for you to use
+# in constructing a name.
+# sysincludes
+# Name of machdep directory with "sys" include file
+# replacements, if any. This directory is optional;
+# if you don't provide it, don't set this variable.
+# except
+# Names of any syscalls that shouldn't be generated
+# from the template, if any.
+# syscall
+# Base name of the syscall template files, if not the
+# same as <name>. If they're the same, omit this.
+#
+# Also, you may define random symbols and update CFLAGS if
+# necessary. However, for ease of porting to new machines,
+# it's best if you can create portable autoconf tests for
+# whatever you're trying to do, rather than hard-coding it
+# here based on the OS name. So please, try to keep this
+# section as minimal as possible.
+
+except=""
+name=$host_cpu-$host_os
+
+case $host in
+changequote(,)dnl
+ alpha-*-netbsd1.3[H-Z]|alpha-*-netbsd1.4*)
+ name=alpha-netbsd-1.3
+ sysincludes=netbsd-1.1
+ except="fork lseek pipe fstat"
+ available_syscalls="sigsuspend sigprocmask"
+ ;;
+changequote([,])dnl
+ alpha-*-netbsd1.3*)
+ name=alpha-netbsd-1.3
+ sysincludes=netbsd-1.1
+ except="fork lseek pipe sigsuspend sigprocmask fstat"
+ ;;
+ alpha-*-netbsd1.1* | alpha-*-netbsd1.2*)
+ name=alpha-netbsd-1.1
+ sysincludes=netbsd-1.1
+ except="fork lseek pipe sigsuspend sigprocmask"
+ ;;
+ alpha-*-osf*)
+ name=alpha-osf1
+ sysincludes=alpha-osf1
+ except="fork sigsuspend"
+ if test $ac_cv_prog_gcc = no ; then
+ CFLAGS="$CFLAGS -std"
+ fi
+ ;;
+changequote(,)dnl
+ arm32-*-netbsd1.3[H-Z]|arm32-*-netbsd1.4*)
+ name=arm32-netbsd-1.3
+ sysincludes=netbsd-1.1
+ except="fork pipe lseek ftruncate fstat"
+ available_syscalls="sigsuspend sigprocmask"
+ ;;
+changequote([,])dnl
+ arm32-*-netbsd1.3*)
+ name=arm32-netbsd-1.3
+ sysincludes=netbsd-1.1
+ except="fork pipe lseek ftruncate sigsuspend sigprocmask fstat"
+ ;;
+ hppa1.0-*-hpux10.20 | hppa1.1-*-hpux10.20)
+ name=hppa-hpux-10.20
+ sysincludes=hpux-10.20
+ except="fork"
+ ;;
+ hppa1.1-*-hpux*9.*)
+ name=hppa-hpux-9.03
+ sysincludes=hpux-9.03
+ # hpux-9.03.mk seems to be missing; what should this be?
+ except="fork"
+ ;;
+ sparc-*-sunos4.1.3* | sparc-*-sunos4.1.4*)
+ name=sparc-sunos-4.1.3
+ sysincludes=sunos-4.1.3
+ syscall=sparc-sunos4
+ except="fork pipe getpgrp getdirentries"
+ AC_DEFINE(sunos4) # is this really needed??
+ ;;
+ sparc-*-solaris2.3* | sparc-*-solaris2.4*)
+ name=sparc-sunos-5.3
+ sysincludes=sunos-5.3
+ except="fork sigaction"
+ # Should really come up with a test for this...
+ AC_DEFINE(LD_LINKS_STATIC_DATA)
+ AC_DEFINE(BROKEN_SIGNALS)
+ ;;
+ sparc-*-solaris2*)
+ name=sparc-sunos-5.3
+ sysincludes=sunos-5.5
+ except="fork sigaction"
+ # Should really come up with a test for this...
+ AC_DEFINE(LD_LINKS_STATIC_DATA)
+ AC_DEFINE(BROKEN_SIGNALS)
+ ;;
+changequote(,)dnl
+ sparc-*-netbsd1.3[H-Z]|sparc-*-netbsd1.4*)
+ name=sparc-netbsd-1.3
+ sysincludes=netbsd-1.1
+ except="pipe fork lseek ftruncate fstat"
+ available_syscalls="sigprocmask sigsuspend"
+ ;;
+changequote([,])dnl
+ sparc-*-netbsd1.3*)
+ name=sparc-netbsd-1.3
+ sysincludes=netbsd-1.1
+ except="pipe fork lseek ftruncate sigprocmask sigsuspend fstat"
+ ;;
+ sparc-*-netbsd1.0A | sparc-*-netbsd1.1* | sparc-*-netbsd1.2*)
+ name=sparc-sunos-4.1.3
+ sysincludes=netbsd-1.0
+ syscall=sparc-netbsd-1.1
+ except="pipe fork sigprocmask sigsuspend"
+ ;;
+ i386-*-openbsd2.*)
+ name=i386-openbsd-2.0
+ sysincludes=openbsd-2.0
+ except="fork lseek ftruncate sigsuspend sigprocmask"
+ ;;
+ i386-*-linux*)
+ #name=i386-linux-1.0
+ #sysincludes=linux-1.0
+ name=i386-linux-2.0
+ sysincludes=linux-2.0
+ extraincludes="bits"
+ ;;
+ i386-*-bsdi1.1)
+ name=i386-bsdi-1.1
+ sysincludes=bsdi-1.1
+ ;;
+ i386-*-bsdi2.0* | i386-*-bsdi2.1*)
+ name=i386-bsdi-2.0
+ sysincludes=bsdi-2.0
+ syscall=i386-bsdi-2.0
+ except="fork lseek ftruncate sigsuspend"
+ ;;
+changequote(,)dnl
+ i386-*-netbsd1.3[H-Z]|i386-*-netbsd1.4*)
+ name=i386-netbsd-1.3
+ sysincludes=netbsd-1.1
+ except="fork lseek ftruncate pipe fstat"
+ available_syscalls="sigsuspend sigprocmask"
+ ;;
+changequote([,])dnl
+ i386-*-netbsd1.3*)
+ name=i386-netbsd-1.3
+ sysincludes=netbsd-1.1
+ except="fork lseek ftruncate pipe sigsuspend sigprocmask fstat"
+ ;;
+ i386-*-netbsd1.1* | i386-*-netbsd1.2*)
+ name=i386-netbsd-1.0
+ sysincludes=netbsd-1.1
+ syscall=i386-netbsd-1.1
+ except="fork lseek ftruncate pipe sigsuspend sigprocmask"
+ ;;
+ i386-*-netbsd1.0*)
+ name=i386-netbsd-1.0
+ sysincludes=netbsd-1.0
+ except="fork lseek ftruncate sigsuspend"
+ ;;
+ i386-*-netbsd0.9*)
+ name=i386-netbsd-0.9
+ sysincludes=netbsd-0.9
+ ;;
+ m68*-*-netbsd*)
+ name=m68000-netbsd
+ sysincludes=netbsd-1.1
+ except="lseek ftruncate pipe fstat"
+ available_syscalls="sigsuspend sigprocmask"
+ ;;
+ i386-*-freebsd*)
+ name=i386-freebsd-2.0
+ sysincludes=freebsd-2.0
+ except="fork lseek ftruncate sigsuspend sigprocmask"
+ ;;
+ romp-*-bsd*)
+ name=romp-bsd
+ ;;
+ mips-dec-ultrix*)
+ name=r2000-ultrix-4.2
+ sysincludes=ultrix-4.2
+ except="fork pipe"
+ ;;
+ mips-sgi-irix*)
+ name=ip22-irix-5.2
+ sysincludes=irix-5.2
+ except="fstat stat"
+ AC_DEFINE(BROKEN_SIGNALS)
+ ;;
+ i386-*-sco3.2v5*)
+ name=i386-sco3.2.5
+ sysincludes=i386-sco3.2.5
+ syscall=i386-sco3.2.5
+ except="select socketcall accept bind connect getpeername getsockname getsockopt setsockopt listen recv recvfrom recvmsg send sendmsg sendto shutdown socket socketpair fork fcntl dup2 fstat fchmod fchown ftruncate pipe getdirentries sigaction sigpause wait3 waitpid getdtablesize"
+ ;;
+ *)
+ AC_MSG_ERROR(System type $host not recognized or not supported.
+See $srcdir/configure.in for supported systems.)
+ exit 1
+ ;;
+esac
+
+SYSCALL_EXCEPTIONS=$except
+AC_SUBST(SYSCALL_EXCEPTIONS)
+
+AC_CHECK_HEADERS(sys/termio.h termios.h termio.h alloc.h)
+
+dnl Don't use AC_CHECK_HEADERS for this one, we want to define a special
+dnl symbol name starting with pthread_ if it's found.
+AC_CHECK_HEADER(va_list.h, AC_DEFINE(pthread_have_va_list_h))
+
+dnl Generate a list of system calls that we could generate. We later use
+dnl a syscall template .S file to produce a .o file for each syscall. This
+dnl is a bit better for porting and development purposes than having every
+dnl syscall listed for every target system; this way we only need the
+dnl template, and special hanlding for only those syscalls that can't be
+dnl handled by the templates.
+AC_CHECK_HEADERS(syscall.h sys/syscall.h sys/filio.h)
+
+PTHREADS_CHECK_SYSCALLS(open write read creat close fcntl lseek dup2 dup pipe
+ fchmod fchown execve fstat lstat link unlink chdir chown chmod stat
+ rename select getdtablesize ioctl ftruncate flock fstatfs chroot uname
+ dnl - signals
+ sigsuspend sigaction sigpause sigprocmask ksigaction
+ dnl - directory reading
+ getdents readdir getdirentries
+ dnl - variants of `wait' syscalls
+ wait4 wait3 waitpid waitsys
+ dnl - BSD socket calls
+ socket bind connect accept listen getsockopt setsockopt socketpair
+ dnl - SYSV stream calls
+ poll putmsg getmsg
+ dnl - Linux version uses one syscall
+ socketcall
+
+ dnl - Process info
+ pgrpsys
+
+ exit
+ readv writev send sendto sendmsg recv recvfrom recvmsg
+ getpeername getsockname
+ shutdown
+ getpgrp fork)
+
+AC_SUBST(available_syscalls)
+AC_SUBST(missing_syscalls)
+
+dnl Disabled for now -- generates warnings from autoconf.
+dnl ## Check some type sizes.
+dnl AC_CHECK_SIZEOF(int)
+dnl AC_CHECK_SIZEOF(long)
+dnl AC_CHECK_SIZEOF(char *)
+
+## Determine some typedef values from the system header files.
+dnl
+dnl Autoconf provides these automatically. They provide reasonable
+dnl fallbacks if the standard header files don't define the typedef names.
+dnl
+dnl AC_TYPE_MODE_T
+AC_TYPE_OFF_T
+dnl AC_TYPE_PID_T
+AC_TYPE_SIZE_T
+dnl AC_TYPE_UID_T
+AC_TYPE_SIGNAL
+dnl
+dnl Default these types if their definitions can't be found.
+dnl
+AC_CHECK_TYPE(ssize_t,int)
+AC_CHECK_TYPE(time_t,long)
+dnl
+AC_CHECK_HEADERS(sys/time.h)
+AC_HEADER_TIME
+
+dnl
+dnl Check for the existence of these types
+dnl
+dnl struct timespec
+dnl
+AC_MSG_CHECKING(for struct timespec in sys/time.h)
+AC_CACHE_VAL(pthreads_cv_timespec_in_time,
+ AC_TRY_COMPILE([#include <sys/time.h>], [struct timespec foo;],
+ pthreads_cv_timespec_in_time=yes, pthreads_cv_timespec_in_time=no))
+AC_MSG_RESULT($pthreads_cv_timespec_in_time)
+if test $pthreads_cv_timespec_in_time = yes ; then
+ AC_DEFINE(_OS_HAS_TIMESPEC)
+fi
+
+dnl socklen_t
+AC_CACHE_VAL(pthreads_cv_socklen_t,
+ AC_TRY_COMPILE([#include <sys/types.h>
+#include <sys/socket.h>], [socklen_t foo;],
+ pthreads_cv_socklen_t=yes, pthreads_cv_socklen_t=no))
+AC_MSG_RESULT($pthreads_cv_socklen_t)
+if test $pthreads_cv_socklen_t = yes ; then
+ AC_DEFINE(_OS_HAS_SOCKLEN_T)
+fi
+
+
+dnl
+dnl Usage: PTHREADS_FIND_TYPE(system-typedef-name, new-macro-name,
+dnl list-of-includes-in-square-brackets,
+dnl comma-separated-list-of-types-to-try)
+dnl
+dnl PTHREADS_FIND_INTEGRAL_TYPE automatically provides a set of integral
+dnl types, and does not permit specification of additional types.
+dnl
+dnl The specified types must all be able to work as prefixes -- i.e., no
+dnl direct specification of array or function types. If you need such
+dnl types, add typedefs for them to include/pthread/xtypes.h, and include
+dnl that in the set of header files. For simple struct types, you can
+dnl try including the definition directly here, but it had better not
+dnl contain any commas or square brackets.
+dnl
+dnl If necessary, you can include other preprocessing commands and such
+dnl in the `includes' portion.
+dnl
+dnl Note: For now, each of these needs a corresponding entry
+dnl in acconfig.h.
+dnl
+dnl size_t
+dnl
+PTHREADS_FIND_INTEGRAL_TYPE(size_t, pthread_size_t, [
+#include <stddef.h>
+#include <sys/types.h>
+#ifdef STDC_HEADERS
+#include <stdlib.h>
+#endif
+])
+dnl
+dnl ssize_t
+dnl
+PTHREADS_FIND_INTEGRAL_TYPE(ssize_t, pthread_ssize_t, [
+#include <stddef.h>
+#include <stdlib.h>
+#include <unistd.h>
+])
+dnl
+dnl clock_t ---FIXME I don't know if this is the right set of header files. KR
+dnl
+PTHREADS_FIND_INTEGRAL_TYPE(clock_t, pthread_clock_t, [
+#include <stddef.h>
+#if TIME_WITH_SYS_TIME
+# include <time.h>
+# include <sys/time.h>
+#else
+# if HAVE_SYS_TIME_H
+# include <sys/time.h>
+# else
+# include <time.h>
+# endif
+#endif
+])
+dnl
+dnl time_t
+dnl
+PTHREADS_FIND_INTEGRAL_TYPE(time_t, pthread_time_t, [
+#include <stddef.h>
+#if TIME_WITH_SYS_TIME
+# include <time.h>
+# include <sys/time.h>
+#else
+# if HAVE_SYS_TIME_H
+# include <sys/time.h>
+# else
+# include <time.h>
+# endif
+#endif
+])
+dnl
+dnl fpos_t
+dnl
+dnl If fpos_t isn't defined in stdio.h, define it to be off_t. It
+dnl looks like AC_CHECK_TYPE won't work for this, because it doesn't
+dnl include stdio.h.
+dnl
+AC_MSG_CHECKING(for fpos_t in stdio.h)
+AC_CACHE_VAL(pthreads_cv_fpos_t_in_stdio,
+ AC_TRY_COMPILE([#include <stdio.h>], [fpos_t position;],
+ pthreads_cv_fpos_t_in_stdio=yes, pthreads_cv_fpos_t_in_stdio=no))
+AC_MSG_RESULT($pthreads_cv_fpos_t_in_stdio)
+if test $pthreads_cv_fpos_t_in_stdio = yes ; then
+ PTHREADS_FIND_INTEGRAL_TYPE(fpos_t, pthread_fpos_t, [
+#include <stdio.h>
+#include <sys/types.h>
+#ifdef STDC_HEADERS
+#include <stdlib.h>
+#endif
+])
+else
+ AC_DEFINE(fpos_t,off_t)
+ AC_DEFINE(pthread_fpos_t,pthread_off_t)
+fi
+dnl
+dnl off_t
+dnl
+PTHREADS_FIND_INTEGRAL_TYPE(off_t, pthread_off_t, [
+#include <stdio.h>
+#include <sys/types.h>
+#ifdef STDC_HEADERS
+#include <stdlib.h>
+#endif
+])
+dnl
+dnl va_list -- This one could be tricky. Fortunately, on some systems,
+dnl we can just include the gcc stdarg.h header file if we can't determine
+dnl the type here. Won't work for non-gcc configurations though.
+dnl
+PTHREADS_FIND_TYPE(va_list, pthread_va_list, [#include <stdarg.h>],
+ char *, char **, void *, void **, int *, long *)
+dnl
+dnl
+
+arpa_headers="#include <sys/types.h>
+#include <arpa/nameser.h>"
+
+dnl
+dnl Type for network (IP) addresses, 32 bits.
+dnl For now, I'm assuming that the return type from _getlong is it.
+dnl
+AC_MSG_CHECKING(IP address type)
+AC_CACHE_VAL(pthread_cv_type_ipaddr,
+ AC_TRY_COMPILE($arpa_headers,[ &_getlong; ],[
+ for type in "unsigned long" "unsigned int" ; do
+ AC_TRY_COMPILE($arpa_headers, extern $type _getlong ();,[
+ pthread_cv_type_ipaddr="$type"
+ break
+ ])
+ done
+ ],[ AC_MSG_WARN(Can't compile _getlong reference.) ])
+ if test "$pthread_cv_type_ipaddr" = "" ; then
+ AC_MSG_WARN(Can't determine _getlong return type.)
+ AC_MSG_WARN(Defaulting to unsigned long.)
+ pthread_cv_type_ipaddr="unsigned long"
+ fi
+)
+AC_MSG_RESULT($pthread_cv_type_ipaddr)
+AC_DEFINE_UNQUOTED(pthread_ipaddr_type,$pthread_cv_type_ipaddr)
+
+dnl
+dnl Type for network (IP) ports, 16 bits.
+dnl For now, I'm assuming that the return type from _getshort is it.
+dnl
+AC_MSG_CHECKING(IP port type)
+AC_CACHE_VAL(pthread_cv_type_ipport,
+ AC_TRY_COMPILE($arpa_headers,[ &_getshort; ],[
+ for type in "unsigned short" "unsigned int" ; do
+ AC_TRY_COMPILE($arpa_headers, extern $type _getshort ();,[
+ pthread_cv_type_ipport="$type"
+ break
+ ])
+ done
+ ],[ AC_MSG_WARN(Can't compile _getshort reference.) ])
+ if test "$pthread_cv_type_ipport" = "" ; then
+ AC_MSG_WARN(Can't determine _getshort return type.)
+ AC_MSG_WARN(Defaulting to unsigned short.)
+ pthread_cv_type_ipport="unsigned short"
+ fi
+)
+AC_MSG_RESULT($pthread_cv_type_ipport)
+AC_DEFINE_UNQUOTED(pthread_ipport_type,$pthread_cv_type_ipport)
+
+dnl
+dnl Guess where terminal devices are stored. This is for use in the
+dnl ttyname() implementation provided here.
+dnl
+AC_MSG_CHECKING(pathname for terminal devices directory)
+AC_CACHE_VAL(pthread_cv_pty_path,
+ if test -d /devices/pseudo ; then
+ pty_path=/devices/pseudo/
+ else
+ pty_path=/dev/
+ fi
+ pthread_cv_pty_path=$pty_path
+)
+AC_DEFINE_UNQUOTED(_PATH_PTY,"$pthread_cv_pty_path")
+AC_MSG_RESULT($pthread_cv_pty_path)
+
+dnl
+dnl Look for timezone info, for use in ctime.
+dnl
+AC_MSG_CHECKING(directory name for time zone info)
+tzdir=NONE
+for f in /usr/lib/zoneinfo /usr/share/zoneinfo /usr/share/lib/zoneinfo /etc/zoneinfo /usr/local/lib/zoneinfo
+do
+ if test -d $f ; then
+ tzdir=$f
+ break
+ fi
+done
+case $tzdir in
+NONE)
+ AC_MSG_WARN(Can't find zoneinfo directory.)
+ AC_MSG_WARN(Defaulting zoneinfo directory to NULL.)
+ tzdir=NULL
+ ;;
+esac
+AC_DEFINE_UNQUOTED(_PATH_TZDIR,"$tzdir")
+AC_MSG_RESULT($tzdir)
+
+AC_MSG_CHECKING(filename for local time zone)
+tzfile=NONE
+for f in $tzdir/localtime /etc/localtime
+do
+ if test -f $f ; then
+ tzfile=$f
+ break
+ fi
+done
+case $tzfile in
+NONE) # Should this default to tzdir/localtime?
+ AC_MSG_WARN(Can't find local time zone file.)
+ if test tzdir = NULL ; then
+ AC_MSG_WARN(Defaulting local time zone file to NULL)
+ tzfile=NULL
+ else
+ AC_MSG_WARN(Defaulting local time zone file to $tzdir/localtime.)
+ tzfile=$tzdir/localtime
+ fi
+ ;;
+esac
+AC_DEFINE_UNQUOTED(_PATH_TZFILE,"$tzfile")
+AC_MSG_RESULT($tzfile)
+
+dnl
+dnl Network stuff. At the moment, I don't think there are any other
+dnl values we should expect. If we find a system that does store these
+dnl files elsewhere -- or doesn't have them all -- then run some tests.
+dnl
+AC_DEFINE(_PATH_RESCONF, "/etc/resolv.conf")
+AC_DEFINE(_PATH_HOSTS, "/etc/hosts")
+AC_DEFINE(_PATH_NETWORKS, "/etc/networks")
+AC_DEFINE(_PATH_PROTOCOLS, "/etc/protocols")
+AC_DEFINE(_PATH_SERVICES, "/etc/services")
+
+dnl
+dnl Other stuff
+dnl
+AC_DEFINE(_PATH_BSHELL, "/bin/sh")
+
+dnl If the system provides vfork, autoconf scripts will detect it.
+dnl So we should hide it.
+AC_CHECK_FUNCS(vfork)
+
+srctop=`cd ${srcdir}/..;pwd`
+AC_SUBST(srctop)
+
+# Now we deal with symlinks &c.
+
+test -d include || mkdir include || \
+ AC_MSG_ERROR(Can't create include directory.)
+
+test -d include/pthread || mkdir include/pthread || \
+ AC_MSG_ERROR(Can't create include/pthread directory.)
+
+test -d lib || mkdir lib || \
+ AC_MSG_ERROR(Can't create lib directory.)
+
+test -d lib/libpthreadutil || mkdir lib/libpthreadutil || \
+ AC_MSG_ERROR(Can't create lib/libpthreadutil directory.)
+
+test -d bin || mkdir bin || \
+ AC_MSG_ERROR(Can't create bin directory.)
+
+test -d bin/finger || mkdir bin/finger || \
+ AC_MSG_ERROR(Can't create bin directory.)
+
+test -d tests || mkdir tests || \
+ AC_MSG_ERROR(Can't create tests directory.)
+
+if test x$syscall = xNONE ; then
+ syscall=$name
+fi
+
+links="include/pthread/machdep.h include/pthread/posix.h \
+ machdep.c syscall.S"
+targets="../machdep/engine-$name.h ../machdep/posix-$sysincludes.h \
+ ../machdep/engine-$name.c ../machdep/syscall-$syscall.S"
+
+# Both these targets are optional. (Autoconf-generated configure scripts
+# will require the existence of link targets, so check before adding them
+# to the list.)
+if test x$sysincludes != xNONE ; then
+ links="$links include/sys"
+ targets="$targets ../machdep/$sysincludes"
+fi
+
+if test x$extraincludes != xNONE ; then
+ for tmp in $extraincludes
+ do
+ links="$links include/$tmp"
+ targets="$targets ../machdep/$sysincludes/extra/$tmp"
+ done
+fi
+
+syscall_file=../machdep/syscall-template-$syscall.S
+if test -r $srcdir/$syscall_file ; then
+ links="$links syscall-template.S"
+ targets="$targets $syscall_file"
+ HAVE_SYSCALL_TEMPLATE=yes
+else
+ # This really isn't a fatal problem. In fact, it's expected, initially,
+ # for some targets. This is just to persuade people to fix the targets
+ # they deal with to provide some sort of template.
+ #
+ # Eventually this file probably will be required...
+ AC_MSG_WARN(No syscall template file syscall-template-$syscall.S found.)
+ HAVE_SYSCALL_TEMPLATE=no
+fi
+AC_SUBST(HAVE_SYSCALL_TEMPLATE)
+
+dnl Now tell it to make the links.
+dnl (The links are actually made by config.status.)
+AC_LINK_FILES($targets, $links)
+
+if test x$makefile_frag != x ; then
+ makefile_frag=${srcdir}/$makefile_frag
+else
+ makefile_frag=/dev/null
+fi
+dnl Drop in file indicated by $makefile_frag on *the line after* the
+dnl magic @makefile_frag@ sequence.
+AC_SUBST_FILE(makefile_frag)
+
+
+dnl Generate output files...
+AC_CONFIG_HEADER(config.h)
+
+dnl This must be last.
+AC_OUTPUT(config.flags GNUmakefile Makefile \
+ lib/Makefile:../lib/Makefile.in \
+ lib/libpthreadutil/Makefile:../lib/libpthreadutil/Makefile.in \
+ bin/Makefile:../bin/Makefile.in \
+ bin/finger/Makefile:../bin/finger/Makefile.in \
+ tests/Makefile:../tests/Makefile.in)
diff --git a/mit-pthreads/config/configure.org b/mit-pthreads/config/configure.org
new file mode 100755
index 00000000000..f8526844a24
--- /dev/null
+++ b/mit-pthreads/config/configure.org
@@ -0,0 +1,2874 @@
+#! /bin/sh
+
+# Guess values for system-dependent variables and create Makefiles.
+# Generated automatically using autoconf version 2.10
+# Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc.
+#
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+
+# Defaults:
+ac_help=
+ac_default_prefix=/usr/local
+# Any additions from configure.in:
+ac_help="$ac_help
+--enable-dce-compat DCE compatibility"
+ac_default_prefix=/usr/local/pthreads
+
+# Initialize some variables set by options.
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+build=NONE
+cache_file=./config.cache
+exec_prefix=NONE
+host=NONE
+no_create=
+nonopt=NONE
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+target=NONE
+verbose=
+x_includes=NONE
+x_libraries=NONE
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datadir='${prefix}/share'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+libdir='${exec_prefix}/lib'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+infodir='${prefix}/info'
+mandir='${prefix}/man'
+
+# Initialize some other variables.
+subdirs=
+MFLAGS= MAKEFLAGS=
+
+ac_prev=
+for ac_option
+do
+
+ # If the previous option needs an argument, assign it.
+ if test -n "$ac_prev"; then
+ eval "$ac_prev=\$ac_option"
+ ac_prev=
+ continue
+ fi
+
+ case "$ac_option" in
+ -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
+ *) ac_optarg= ;;
+ esac
+
+ # Accept the important Cygnus configure options, so we can diagnose typos.
+
+ case "$ac_option" in
+
+ -bindir | --bindir | --bindi | --bind | --bin | --bi)
+ ac_prev=bindir ;;
+ -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+ bindir="$ac_optarg" ;;
+
+ -build | --build | --buil | --bui | --bu)
+ ac_prev=build ;;
+ -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+ build="$ac_optarg" ;;
+
+ -cache-file | --cache-file | --cache-fil | --cache-fi \
+ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+ ac_prev=cache_file ;;
+ -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+ cache_file="$ac_optarg" ;;
+
+ -datadir | --datadir | --datadi | --datad | --data | --dat | --da)
+ ac_prev=datadir ;;
+ -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \
+ | --da=*)
+ datadir="$ac_optarg" ;;
+
+ -disable-* | --disable-*)
+ ac_feature=`echo $ac_option|sed -e 's/-*disable-//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then
+ { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+ fi
+ ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+ eval "enable_${ac_feature}=no" ;;
+
+ -enable-* | --enable-*)
+ ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then
+ { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+ fi
+ ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+ case "$ac_option" in
+ *=*) ;;
+ *) ac_optarg=yes ;;
+ esac
+ eval "enable_${ac_feature}='$ac_optarg'" ;;
+
+ -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+ | --exec | --exe | --ex)
+ ac_prev=exec_prefix ;;
+ -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+ | --exec=* | --exe=* | --ex=*)
+ exec_prefix="$ac_optarg" ;;
+
+ -gas | --gas | --ga | --g)
+ # Obsolete; use --with-gas.
+ with_gas=yes ;;
+
+ -help | --help | --hel | --he)
+ # Omit some internal or obsolete options to make the list less imposing.
+ # This message is too long to be a string in the A/UX 3.1 sh.
+ cat << EOF
+Usage: configure [options] [host]
+Options: [defaults in brackets after descriptions]
+Configuration:
+ --cache-file=FILE cache test results in FILE
+ --help print this message
+ --no-create do not create output files
+ --quiet, --silent do not print \`checking...' messages
+ --version print the version of autoconf that created configure
+Directory and file names:
+ --prefix=PREFIX install architecture-independent files in PREFIX
+ [$ac_default_prefix]
+ --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
+ [same as prefix]
+ --bindir=DIR user executables in DIR [EPREFIX/bin]
+ --sbindir=DIR system admin executables in DIR [EPREFIX/sbin]
+ --libexecdir=DIR program executables in DIR [EPREFIX/libexec]
+ --datadir=DIR read-only architecture-independent data in DIR
+ [PREFIX/share]
+ --sysconfdir=DIR read-only single-machine data in DIR [PREFIX/etc]
+ --sharedstatedir=DIR modifiable architecture-independent data in DIR
+ [PREFIX/com]
+ --localstatedir=DIR modifiable single-machine data in DIR [PREFIX/var]
+ --libdir=DIR object code libraries in DIR [EPREFIX/lib]
+ --includedir=DIR C header files in DIR [PREFIX/include]
+ --oldincludedir=DIR C header files for non-gcc in DIR [/usr/include]
+ --infodir=DIR info documentation in DIR [PREFIX/info]
+ --mandir=DIR man documentation in DIR [PREFIX/man]
+ --srcdir=DIR find the sources in DIR [configure dir or ..]
+ --program-prefix=PREFIX prepend PREFIX to installed program names
+ --program-suffix=SUFFIX append SUFFIX to installed program names
+ --program-transform-name=PROGRAM
+ run sed PROGRAM on installed program names
+EOF
+ cat << EOF
+Host type:
+ --build=BUILD configure for building on BUILD [BUILD=HOST]
+ --host=HOST configure for HOST [guessed]
+ --target=TARGET configure for TARGET [TARGET=HOST]
+Features and packages:
+ --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no)
+ --enable-FEATURE[=ARG] include FEATURE [ARG=yes]
+ --with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
+ --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
+ --x-includes=DIR X include files are in DIR
+ --x-libraries=DIR X library files are in DIR
+EOF
+ if test -n "$ac_help"; then
+ echo "--enable and --with options recognized:$ac_help"
+ fi
+ exit 0 ;;
+
+ -host | --host | --hos | --ho)
+ ac_prev=host ;;
+ -host=* | --host=* | --hos=* | --ho=*)
+ host="$ac_optarg" ;;
+
+ -includedir | --includedir | --includedi | --included | --include \
+ | --includ | --inclu | --incl | --inc)
+ ac_prev=includedir ;;
+ -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+ | --includ=* | --inclu=* | --incl=* | --inc=*)
+ includedir="$ac_optarg" ;;
+
+ -infodir | --infodir | --infodi | --infod | --info | --inf)
+ ac_prev=infodir ;;
+ -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+ infodir="$ac_optarg" ;;
+
+ -libdir | --libdir | --libdi | --libd)
+ ac_prev=libdir ;;
+ -libdir=* | --libdir=* | --libdi=* | --libd=*)
+ libdir="$ac_optarg" ;;
+
+ -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+ | --libexe | --libex | --libe)
+ ac_prev=libexecdir ;;
+ -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+ | --libexe=* | --libex=* | --libe=*)
+ libexecdir="$ac_optarg" ;;
+
+ -localstatedir | --localstatedir | --localstatedi | --localstated \
+ | --localstate | --localstat | --localsta | --localst \
+ | --locals | --local | --loca | --loc | --lo)
+ ac_prev=localstatedir ;;
+ -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+ | --localstate=* | --localstat=* | --localsta=* | --localst=* \
+ | --locals=* | --local=* | --loca=* | --loc=* | --lo=*)
+ localstatedir="$ac_optarg" ;;
+
+ -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+ ac_prev=mandir ;;
+ -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+ mandir="$ac_optarg" ;;
+
+ -nfp | --nfp | --nf)
+ # Obsolete; use --without-fp.
+ with_fp=no ;;
+
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c)
+ no_create=yes ;;
+
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+ no_recursion=yes ;;
+
+ -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+ | --oldin | --oldi | --old | --ol | --o)
+ ac_prev=oldincludedir ;;
+ -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+ oldincludedir="$ac_optarg" ;;
+
+ -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+ ac_prev=prefix ;;
+ -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+ prefix="$ac_optarg" ;;
+
+ -program-prefix | --program-prefix | --program-prefi | --program-pref \
+ | --program-pre | --program-pr | --program-p)
+ ac_prev=program_prefix ;;
+ -program-prefix=* | --program-prefix=* | --program-prefi=* \
+ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+ program_prefix="$ac_optarg" ;;
+
+ -program-suffix | --program-suffix | --program-suffi | --program-suff \
+ | --program-suf | --program-su | --program-s)
+ ac_prev=program_suffix ;;
+ -program-suffix=* | --program-suffix=* | --program-suffi=* \
+ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+ program_suffix="$ac_optarg" ;;
+
+ -program-transform-name | --program-transform-name \
+ | --program-transform-nam | --program-transform-na \
+ | --program-transform-n | --program-transform- \
+ | --program-transform | --program-transfor \
+ | --program-transfo | --program-transf \
+ | --program-trans | --program-tran \
+ | --progr-tra | --program-tr | --program-t)
+ ac_prev=program_transform_name ;;
+ -program-transform-name=* | --program-transform-name=* \
+ | --program-transform-nam=* | --program-transform-na=* \
+ | --program-transform-n=* | --program-transform-=* \
+ | --program-transform=* | --program-transfor=* \
+ | --program-transfo=* | --program-transf=* \
+ | --program-trans=* | --program-tran=* \
+ | --progr-tra=* | --program-tr=* | --program-t=*)
+ program_transform_name="$ac_optarg" ;;
+
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ silent=yes ;;
+
+ -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+ ac_prev=sbindir ;;
+ -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+ | --sbi=* | --sb=*)
+ sbindir="$ac_optarg" ;;
+
+ -sharedstatedir | --sharedstatedir | --sharedstatedi \
+ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+ | --sharedst | --shareds | --shared | --share | --shar \
+ | --sha | --sh)
+ ac_prev=sharedstatedir ;;
+ -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+ | --sha=* | --sh=*)
+ sharedstatedir="$ac_optarg" ;;
+
+ -site | --site | --sit)
+ ac_prev=site ;;
+ -site=* | --site=* | --sit=*)
+ site="$ac_optarg" ;;
+
+ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+ ac_prev=srcdir ;;
+ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+ srcdir="$ac_optarg" ;;
+
+ -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+ | --syscon | --sysco | --sysc | --sys | --sy)
+ ac_prev=sysconfdir ;;
+ -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+ sysconfdir="$ac_optarg" ;;
+
+ -target | --target | --targe | --targ | --tar | --ta | --t)
+ ac_prev=target ;;
+ -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+ target="$ac_optarg" ;;
+
+ -v | -verbose | --verbose | --verbos | --verbo | --verb)
+ verbose=yes ;;
+
+ -version | --version | --versio | --versi | --vers)
+ echo "configure generated by autoconf version 2.10"
+ exit 0 ;;
+
+ -with-* | --with-*)
+ ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then
+ { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+ fi
+ ac_package=`echo $ac_package| sed 's/-/_/g'`
+ case "$ac_option" in
+ *=*) ;;
+ *) ac_optarg=yes ;;
+ esac
+ eval "with_${ac_package}='$ac_optarg'" ;;
+
+ -without-* | --without-*)
+ ac_package=`echo $ac_option|sed -e 's/-*without-//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then
+ { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+ fi
+ ac_package=`echo $ac_package| sed 's/-/_/g'`
+ eval "with_${ac_package}=no" ;;
+
+ --x)
+ # Obsolete; use --with-x.
+ with_x=yes ;;
+
+ -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+ | --x-incl | --x-inc | --x-in | --x-i)
+ ac_prev=x_includes ;;
+ -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+ x_includes="$ac_optarg" ;;
+
+ -x-libraries | --x-libraries | --x-librarie | --x-librari \
+ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+ ac_prev=x_libraries ;;
+ -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+ x_libraries="$ac_optarg" ;;
+
+ -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; }
+ ;;
+
+ *)
+ if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then
+ echo "configure: warning: $ac_option: invalid host type" 1>&2
+ fi
+ if test "x$nonopt" != xNONE; then
+ { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; }
+ fi
+ nonopt="$ac_option"
+ ;;
+
+ esac
+done
+
+if test -n "$ac_prev"; then
+ { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; }
+fi
+
+trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
+
+# File descriptor usage:
+# 0 standard input
+# 1 file creation
+# 2 errors and warnings
+# 3 some systems may open it to /dev/tty
+# 4 used on the Kubota Titan
+# 6 checking for... messages and results
+# 5 compiler messages saved in config.log
+if test "$silent" = yes; then
+ exec 6>/dev/null
+else
+ exec 6>&1
+fi
+exec 5>./config.log
+
+echo "\
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+" 1>&5
+
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Also quote any args containing shell metacharacters.
+ac_configure_args=
+for ac_arg
+do
+ case "$ac_arg" in
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c) ;;
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;;
+ *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*)
+ ac_configure_args="$ac_configure_args '$ac_arg'" ;;
+ *) ac_configure_args="$ac_configure_args $ac_arg" ;;
+ esac
+done
+
+# NLS nuisances.
+# Only set LANG and LC_ALL to C if already set.
+# These must not be set unconditionally because not all systems understand
+# e.g. LANG=C (notably SCO).
+if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi
+if test "${LANG+set}" = set; then LANG=C; export LANG; fi
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -rf conftest* confdefs.h
+# AIX cpp loses on an empty file, so make sure it contains at least a newline.
+echo > confdefs.h
+
+# A filename unique to this package, relative to the directory that
+# configure is in, which we can look for to find out if srcdir is correct.
+ac_unique_file=config.flags.in
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+ ac_srcdir_defaulted=yes
+ # Try the directory containing this script, then its parent.
+ ac_prog=$0
+ ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'`
+ test "x$ac_confdir" = "x$ac_prog" && ac_confdir=.
+ srcdir=$ac_confdir
+ if test ! -r $srcdir/$ac_unique_file; then
+ srcdir=..
+ fi
+else
+ ac_srcdir_defaulted=no
+fi
+if test ! -r $srcdir/$ac_unique_file; then
+ if test "$ac_srcdir_defaulted" = yes; then
+ { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; }
+ else
+ { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; }
+ fi
+fi
+srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'`
+
+# Prefer explicitly selected file to automatically selected ones.
+if test -z "$CONFIG_SITE"; then
+ if test "x$prefix" != xNONE; then
+ CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site"
+ else
+ CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site"
+ fi
+fi
+for ac_site_file in $CONFIG_SITE; do
+ if test -r "$ac_site_file"; then
+ echo "loading site script $ac_site_file"
+ . "$ac_site_file"
+ fi
+done
+
+if test -r "$cache_file"; then
+ echo "loading cache $cache_file"
+ . $cache_file
+else
+ echo "creating cache $cache_file"
+ > $cache_file
+fi
+
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+
+if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then
+ # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu.
+ if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then
+ ac_n= ac_c='
+' ac_t=' '
+ else
+ ac_n=-n ac_c= ac_t=
+ fi
+else
+ ac_n= ac_c='\c' ac_t=
+fi
+
+
+# Check whether --enable-dce-compat or --disable-dce-compat was given.
+if test "${enable_dce_compat+set}" = set; then
+ enableval="$enable_dce_compat"
+ { echo "configure: error: Actually, DCE compatibility doesn't work yet..." 1>&2; exit 1; }
+
+else
+ true
+
+fi
+
+
+# Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+ for ac_dir in $PATH; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_prog_CC="gcc"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+ echo "$ac_t""$CC" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+if test -z "$CC"; then
+ # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+ ac_prog_rejected=no
+ for ac_dir in $PATH; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then
+ ac_prog_rejected=yes
+ continue
+ fi
+ ac_cv_prog_CC="cc"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+if test $ac_prog_rejected = yes; then
+ # We found a bogon in the path, so make sure we never use it.
+ set dummy $ac_cv_prog_CC
+ shift
+ if test $# -gt 0; then
+ # We chose a different compiler from the bogus one.
+ # However, it has the same basename, so the bogon will be chosen
+ # first if we set CC to just the basename; use the full file name.
+ shift
+ set dummy "$ac_dir/$ac_word" "$@"
+ shift
+ ac_cv_prog_CC="$@"
+ fi
+fi
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+ echo "$ac_t""$CC" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+ test -z "$CC" && { echo "configure: error: no acceptable cc found in \$PATH" 1>&2; exit 1; }
+fi
+
+echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6
+if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.c <<EOF
+#ifdef __GNUC__
+ yes;
+#endif
+EOF
+if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:616: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
+ ac_cv_prog_gcc=yes
+else
+ ac_cv_prog_gcc=no
+fi
+fi
+
+echo "$ac_t""$ac_cv_prog_gcc" 1>&6
+if test $ac_cv_prog_gcc = yes; then
+ GCC=yes
+ if test "${CFLAGS+set}" != set; then
+ echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6
+if eval "test \"`echo '$''{'ac_cv_prog_gcc_g'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ echo 'void f(){}' > conftest.c
+if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then
+ ac_cv_prog_gcc_g=yes
+else
+ ac_cv_prog_gcc_g=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_prog_gcc_g" 1>&6
+ if test $ac_cv_prog_gcc_g = yes; then
+ CFLAGS="-g -O"
+ else
+ CFLAGS="-O"
+ fi
+ fi
+else
+ GCC=
+ test "${CFLAGS+set}" = set || CFLAGS="-g"
+fi
+
+for ac_prog in $CCC c++ g++ gcc CC cxx
+do
+# Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+if eval "test \"`echo '$''{'ac_cv_prog_CXX'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$CXX"; then
+ ac_cv_prog_CXX="$CXX" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+ for ac_dir in $PATH; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_prog_CXX="$ac_prog"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+fi
+fi
+CXX="$ac_cv_prog_CXX"
+if test -n "$CXX"; then
+ echo "$ac_t""$CXX" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+test -n "$CXX" && break
+done
+test -n "$CXX" || CXX="gcc"
+
+
+echo $ac_n "checking whether we are using GNU C++""... $ac_c" 1>&6
+if eval "test \"`echo '$''{'ac_cv_prog_gxx'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.C <<EOF
+#ifdef __GNUC__
+ yes;
+#endif
+EOF
+if { ac_try='${CXX-g++} -E conftest.C'; { (eval echo configure:696: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
+ ac_cv_prog_gxx=yes
+else
+ ac_cv_prog_gxx=no
+fi
+fi
+
+echo "$ac_t""$ac_cv_prog_gxx" 1>&6
+if test $ac_cv_prog_gxx = yes; then
+ GXX=yes
+ if test "${CXXFLAGS+set}" != set; then
+ echo $ac_n "checking whether ${CXX-g++} accepts -g""... $ac_c" 1>&6
+if eval "test \"`echo '$''{'ac_cv_prog_gxx_g'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ echo 'void f(){}' > conftest.cc
+if test -z "`${CXX-g++} -g -c conftest.cc 2>&1`"; then
+ ac_cv_prog_gxx_g=yes
+else
+ ac_cv_prog_gxx_g=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_prog_gxx_g" 1>&6
+ if test $ac_cv_prog_gxx_g = yes; then
+ CXXFLAGS="-g -O"
+ else
+ CXXFLAGS="-O"
+ fi
+ fi
+else
+ GXX=
+ test "${CXXFLAGS+set}" = set || CXXFLAGS="-g"
+fi
+
+echo $ac_n "checking compiler availability and simple error detection""... $ac_c" 1>&6
+cat > conftest.$ac_ext <<EOF
+#line 735 "configure"
+#include "confdefs.h"
+
+int main() { return 0; }
+int t() {
+ exit(0);
+; return 0; }
+EOF
+if { (eval echo configure:743: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+
+ cat > conftest.$ac_ext <<EOF
+#line 747 "configure"
+#include "confdefs.h"
+
+int main() { return 0; }
+int t() {
+ syntax errors galore!
+; return 0; }
+EOF
+if { (eval echo configure:755: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ { echo "configure: error: Can't detect syntax errors! Is CC set right?" 1>&2; exit 1; }
+else
+ rm -rf conftest*
+ true
+fi
+rm -f conftest*
+
+else
+ rm -rf conftest*
+ { echo "configure: error: Can't compile test program! Is CC set right?" 1>&2; exit 1; }
+fi
+rm -f conftest*
+
+
+cat > conftest.$ac_ext <<EOF
+#line 772 "configure"
+#include "confdefs.h"
+
+int main() { return 0; }
+int t() {
+
+ typedef int Integer;
+ extern int i;
+ extern Integer i;
+
+; return 0; }
+EOF
+if { (eval echo configure:784: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ :
+else
+ rm -rf conftest*
+ { echo "configure: error: Can't redeclare variables with this compiler??" 1>&2; exit 1; }
+fi
+rm -f conftest*
+
+cat > conftest.$ac_ext <<EOF
+#line 793 "configure"
+#include "confdefs.h"
+
+int main() { return 0; }
+int t() {
+
+ typedef long Long;
+ extern int i;
+ extern Long i;
+
+; return 0; }
+EOF
+if { (eval echo configure:805: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ { echo "configure: error: Compiler doesn't detect conflicting declarations." 1>&2; exit 1; }
+fi
+rm -f conftest*
+
+echo "$ac_t""ok" 1>&6
+
+if test $ac_cv_prog_gcc = yes ; then
+ CFLAGS="$CFLAGS -Werror"
+fi
+
+echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+ CPP=
+fi
+if test -z "$CPP"; then
+if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ # This must be in double quotes, not single quotes, because CPP may get
+ # substituted into the Makefile and "${CC-cc}" will confuse make.
+ CPP="${CC-cc} -E"
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp.
+ cat > conftest.$ac_ext <<EOF
+#line 832 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:838: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out`
+if test -z "$ac_err"; then
+ :
+else
+ echo "$ac_err" >&5
+ rm -rf conftest*
+ CPP="${CC-cc} -E -traditional-cpp"
+ cat > conftest.$ac_ext <<EOF
+#line 847 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:853: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out`
+if test -z "$ac_err"; then
+ :
+else
+ echo "$ac_err" >&5
+ rm -rf conftest*
+ CPP=/lib/cpp
+fi
+rm -f conftest*
+fi
+rm -f conftest*
+ ac_cv_prog_CPP="$CPP"
+fi
+ CPP="$ac_cv_prog_CPP"
+else
+ ac_cv_prog_CPP="$CPP"
+fi
+echo "$ac_t""$CPP" 1>&6
+
+
+# Extract the first word of "ranlib", so it can be a program name with args.
+set dummy ranlib; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$RANLIB"; then
+ ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+ for ac_dir in $PATH; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_prog_RANLIB="ranlib"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+ test -z "$ac_cv_prog_RANLIB" && ac_cv_prog_RANLIB=":"
+fi
+fi
+RANLIB="$ac_cv_prog_RANLIB"
+if test -n "$RANLIB"; then
+ echo "$ac_t""$RANLIB" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+
+
+
+ac_aux_dir=
+for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do
+ if test -f $ac_dir/install-sh; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install-sh -c"
+ break
+ elif test -f $ac_dir/install.sh; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install.sh -c"
+ break
+ fi
+done
+if test -z "$ac_aux_dir"; then
+ { echo "configure: error: can not find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." 1>&2; exit 1; }
+fi
+ac_config_guess=$ac_aux_dir/config.guess
+ac_config_sub=$ac_aux_dir/config.sub
+ac_configure=$ac_aux_dir/configure # This should be Cygnus configure.
+
+
+# Do some error checking and defaulting for the host and target type.
+# The inputs are:
+# configure --host=HOST --target=TARGET --build=BUILD NONOPT
+#
+# The rules are:
+# 1. You are not allowed to specify --host, --target, and nonopt at the
+# same time.
+# 2. Host defaults to nonopt.
+# 3. If nonopt is not specified, then host defaults to the current host,
+# as determined by config.guess.
+# 4. Target and build default to nonopt.
+# 5. If nonopt is not specified, then target and build default to host.
+
+# The aliases save the names the user supplied, while $host etc.
+# will get canonicalized.
+case $host---$target---$nonopt in
+NONE---*---* | *---NONE---* | *---*---NONE) ;;
+*) { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; } ;;
+esac
+
+
+# Make sure we can run config.sub.
+if $ac_config_sub sun4 >/dev/null 2>&1; then :
+else { echo "configure: error: can not run $ac_config_sub" 1>&2; exit 1; }
+fi
+
+echo $ac_n "checking host system type""... $ac_c" 1>&6
+
+host_alias=$host
+case "$host_alias" in
+NONE)
+ case $nonopt in
+ NONE)
+ if host_alias=`$ac_config_guess`; then :
+ else { echo "configure: error: can not guess host type; you must specify one" 1>&2; exit 1; }
+ fi ;;
+ *) host_alias=$nonopt ;;
+ esac ;;
+esac
+
+host=`$ac_config_sub $host_alias`
+host_cpu=`echo $host | sed 's/^\(.*\)-\(.*\)-\(.*\)$/\1/'`
+host_vendor=`echo $host | sed 's/^\(.*\)-\(.*\)-\(.*\)$/\2/'`
+host_os=`echo $host | sed 's/^\(.*\)-\(.*\)-\(.*\)$/\3/'`
+echo "$ac_t""$host" 1>&6
+
+echo $ac_n "checking target system type""... $ac_c" 1>&6
+
+target_alias=$target
+case "$target_alias" in
+NONE)
+ case $nonopt in
+ NONE) target_alias=$host_alias ;;
+ *) target_alias=$nonopt ;;
+ esac ;;
+esac
+
+target=`$ac_config_sub $target_alias`
+target_cpu=`echo $target | sed 's/^\(.*\)-\(.*\)-\(.*\)$/\1/'`
+target_vendor=`echo $target | sed 's/^\(.*\)-\(.*\)-\(.*\)$/\2/'`
+target_os=`echo $target | sed 's/^\(.*\)-\(.*\)-\(.*\)$/\3/'`
+echo "$ac_t""$target" 1>&6
+
+echo $ac_n "checking build system type""... $ac_c" 1>&6
+
+build_alias=$build
+case "$build_alias" in
+NONE)
+ case $nonopt in
+ NONE) build_alias=$host_alias ;;
+ *) build_alias=$nonopt ;;
+ esac ;;
+esac
+
+build=`$ac_config_sub $build_alias`
+build_cpu=`echo $build | sed 's/^\(.*\)-\(.*\)-\(.*\)$/\1/'`
+build_vendor=`echo $build | sed 's/^\(.*\)-\(.*\)-\(.*\)$/\2/'`
+build_os=`echo $build | sed 's/^\(.*\)-\(.*\)-\(.*\)$/\3/'`
+echo "$ac_t""$build" 1>&6
+
+test "$host_alias" != "$target_alias" &&
+ test "$program_prefix$program_suffix$program_transform_name" = \
+ NONENONEs,x,x, &&
+ program_prefix=${target_alias}-
+
+
+syscall=NONE
+sysincludes=NONE
+
+# Treat all x86 machines the same.
+# (Yet below, we pretend we can distinguish between the MIPS r2000 and r4000?)
+# (What about 680x0 machines?)
+case $host in
+ i[456]86-*)
+ host=`echo $host | sed 's/^i[456]86/i386/'`
+ host_cpu=i386
+ ;;
+esac
+
+# Here, you should set the following variables:
+# name
+# The "name" of this configuration. Used for "engine-*.c" file name,
+# default for syscall file names. Chris seems to have a thing for
+# putting "-" between OS and version number, but the configure script
+# will already have $host_cpu and $host_os available for you to use
+# in constructing a name.
+# sysincludes
+# Name of machdep directory with "sys" include file
+# replacements, if any. This directory is optional;
+# if you don't provide it, don't set this variable.
+# except
+# Names of any syscalls that shouldn't be generated
+# from the template, if any.
+# syscall
+# Base name of the syscall template files, if not the
+# same as <name>. If they're the same, omit this.
+#
+# Also, you may define random symbols and update CFLAGS if
+# necessary. However, for ease of porting to new machines,
+# it's best if you can create portable autoconf tests for
+# whatever you're trying to do, rather than hard-coding it
+# here based on the OS name. So please, try to keep this
+# section as minimal as possible.
+
+except=""
+name=$host_cpu-$host_os
+
+case $host in
+ alpha-*-netbsd1.1* | alpha-*-netbsd1.2*)
+ name=alpha-netbsd-1.1
+ sysincludes=netbsd-1.1
+ except="fork lseek pipe sigsuspend sigprocmask"
+ ;;
+ alpha-*-osf*)
+ name=alpha-osf1
+ sysincludes=alpha-osf1
+ except="fork sigsuspend"
+ if test $ac_cv_prog_gcc = no ; then
+ CFLAGS="$CFLAGS -std"
+ fi
+ ;;
+ hppa1.1-*-hpux*)
+ name=hppa-hpux-9.03
+ sysincludes=hpux-9.03
+ # hpux-9.03.mk seems to be missing; what should this be?
+ except="fork"
+ ;;
+ sparc-*-sunos4.1.3* | sparc-*-sunos4.1.4*)
+ name=sparc-sunos-4.1.3
+ sysincludes=sunos-4.1.3
+ syscall=sparc-sunos4
+ except="fork pipe getpgrp getdirentries"
+ cat >> confdefs.h <<\EOF
+#define sunos4 1
+EOF
+ # is this really needed??
+ ;;
+ sparc-*-solaris2*)
+ name=sparc-sunos-5.3
+ sysincludes=sunos-5.3
+ except="fork sigaction"
+ # Should really come up with a test for this...
+ cat >> confdefs.h <<\EOF
+#define LD_LINKS_STATIC_DATA 1
+EOF
+
+ cat >> confdefs.h <<\EOF
+#define BROKEN_SIGNALS 1
+EOF
+
+ ;;
+ sparc-*-netbsd1.0A | sparc-*-netbsd1.1* | sparc-*-netbsd1.2*)
+ name=sparc-sunos-4.1.3
+ sysincludes=netbsd-1.0
+ syscall=sparc-netbsd-1.1
+ except="pipe fork sigprocmask sigsuspend"
+ ;;
+ i386-*-linux*)
+ name=i386-linux-1.0
+ sysincludes=linux-1.0
+ ;;
+ i386-*-bsdi1.1)
+ name=i386-bsdi-1.1
+ sysincludes=bsdi-1.1
+ ;;
+ i386-*-bsdi2.0* | i386-*-bsdi2.1*)
+ name=i386-bsdi-2.0
+ sysincludes=bsdi-2.0
+ syscall=i386-bsdi-2.0
+ except="fork lseek sigsuspend"
+ ;;
+ i386-*-netbsd1.1* | i386-*-netbsd1.2*)
+ name=i386-netbsd-1.0
+ sysincludes=netbsd-1.1
+ syscall=i386-netbsd-1.1
+ except="fork lseek pipe sigsuspend sigprocmask"
+ ;;
+ i386-*-netbsd1.0*)
+ name=i386-netbsd-1.0
+ sysincludes=netbsd-1.0
+ except="fork lseek sigsuspend"
+ ;;
+ i386-*-netbsd0.9*)
+ name=i386-netbsd-0.9
+ sysincludes=netbsd-0.9
+ ;;
+ m68*-*-netbsd*)
+ name=m68000-netbsd
+ ;;
+ i386-*-freebsd2.*)
+ name=i386-freebsd-2.0
+ sysincludes=freebsd-2.0
+ except="fork lseek sigsuspend sigprocmask"
+ ;;
+ romp-*-bsd*)
+ name=romp-bsd
+ ;;
+ mips-dec-ultrix*)
+ name=r2000-ultrix-4.2
+ sysincludes=ultrix-4.2
+ except="fork pipe"
+ ;;
+ mips-sgi-irix*)
+ name=ip22-irix-5.2
+ sysincludes=irix-5.2
+ except="fstat stat"
+ cat >> confdefs.h <<\EOF
+#define BROKEN_SIGNALS 1
+EOF
+
+ ;;
+ *)
+ { echo "configure: error: System type $host not recognized or not supported.
+See $srcdir/configure.in for supported systems." 1>&2; exit 1; }
+ exit 1
+ ;;
+esac
+
+SYSCALL_EXCEPTIONS=$except
+
+
+for ac_hdr in sys/termio.h termios.h termio.h
+do
+ac_safe=`echo "$ac_hdr" | tr './\055' '___'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1174 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1179: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=yes"
+else
+ echo "$ac_err" >&5
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_hdr=HAVE_`echo $ac_hdr | tr 'abcdefghijklmnopqrstuvwxyz./\055' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ___'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+
+ac_safe=`echo "va_list.h" | tr './\055' '___'`
+echo $ac_n "checking for va_list.h""... $ac_c" 1>&6
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1210 "configure"
+#include "confdefs.h"
+#include <va_list.h>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1215: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=yes"
+else
+ echo "$ac_err" >&5
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ cat >> confdefs.h <<\EOF
+#define pthread_have_va_list_h 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+
+for ac_hdr in syscall.h sys/syscall.h
+do
+ac_safe=`echo "$ac_hdr" | tr './\055' '___'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1246 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1251: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=yes"
+else
+ echo "$ac_err" >&5
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_hdr=HAVE_`echo $ac_hdr | tr 'abcdefghijklmnopqrstuvwxyz./\055' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ___'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+
+pthreads_syscall_list="open write read creat close fcntl lseek dup2 dup pipe
+ fchmod fchown execve fstat lstat link unlink chdir chown chmod stat
+ rename select getdtablesize ioctl ftruncate
+ sigsuspend sigaction sigpause sigprocmask ksigaction
+ getdents readdir getdirentries
+ wait4 wait3 waitpid waitsys
+ socket bind connect accept listen getsockopt setsockopt socketpair
+ poll putmsg getmsg
+ socketcall
+
+ pgrpsys
+
+ exit
+ readv writev send sendto sendmsg recv recvfrom recvmsg
+ getpeername getsockname
+ shutdown
+ getpgrp fork"
+for pthreads_syscallname in $pthreads_syscall_list ; do
+ echo $ac_n "checking for syscall $pthreads_syscallname""... $ac_c" 1>&6
+if eval "test \"`echo '$''{'pthreads_cv_syscall_$pthreads_syscallname'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1299 "configure"
+#include "confdefs.h"
+
+/* FIXME: This list should be generated from info in configure.in. */
+#ifdef HAVE_SYSCALL_H
+#include <syscall.h>
+#else
+#ifdef HAVE_SYS_SYSCALL_H
+#include <sys/syscall.h>
+#else
+where is your syscall header file??
+#endif
+#endif
+
+int main() { return 0; }
+int t() {
+
+int x;
+x = SYS_$pthreads_syscallname ;
+
+; return 0; }
+EOF
+if { (eval echo configure:1321: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; }; then
+ rm -rf conftest*
+ eval pthreads_cv_syscall_$pthreads_syscallname=yes
+else
+ rm -rf conftest*
+ eval pthreads_cv_syscall_$pthreads_syscallname=no
+fi
+rm -f conftest*
+
+fi
+
+if eval test \$pthreads_cv_syscall_$pthreads_syscallname = yes ; then
+ pthreads_syscall_present=yes
+ available_syscalls="$available_syscalls $pthreads_syscallname"
+ macroname=HAVE_SYSCALL_`echo $pthreads_syscallname | tr '[a-z]' '[A-Z]'`
+ cat >> confdefs.h <<EOF
+#define $macroname 1
+EOF
+
+else
+ pthreads_syscall_present=no
+ missing_syscalls="$missing_syscalls $pthreads_syscallname"
+fi
+echo "$ac_t""$pthreads_syscall_present" 1>&6
+
+done
+
+
+
+
+
+
+## Determine some typedef values from the system header files.
+# If we cannot run a trivial program, we must be cross compiling.
+echo $ac_n "checking whether cross-compiling""... $ac_c" 1>&6
+if eval "test \"`echo '$''{'ac_cv_c_cross'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test "$cross_compiling" = yes; then
+ ac_cv_c_cross=yes
+else
+cat > conftest.$ac_ext <<EOF
+#line 1363 "configure"
+#include "confdefs.h"
+main(){return(0);}
+EOF
+{ (eval echo configure:1367: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; }
+if test -s conftest && (./conftest; exit) 2>/dev/null; then
+ ac_cv_c_cross=no
+else
+ ac_cv_c_cross=yes
+fi
+fi
+rm -fr conftest*
+fi
+
+echo "$ac_t""$ac_cv_c_cross" 1>&6
+cross_compiling=$ac_cv_c_cross
+
+echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6
+if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1385 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1393: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ ac_cv_header_stdc=yes
+else
+ echo "$ac_err" >&5
+ rm -rf conftest*
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+if test $ac_cv_header_stdc = yes; then
+ # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+cat > conftest.$ac_ext <<EOF
+#line 1408 "configure"
+#include "confdefs.h"
+#include <string.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "memchr" >/dev/null 2>&1; then
+ :
+else
+ rm -rf conftest*
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+cat > conftest.$ac_ext <<EOF
+#line 1426 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "free" >/dev/null 2>&1; then
+ :
+else
+ rm -rf conftest*
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+if test "$cross_compiling" = yes; then
+ :
+else
+cat > conftest.$ac_ext <<EOF
+#line 1447 "configure"
+#include "confdefs.h"
+#include <ctype.h>
+#define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+#define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int main () { int i; for (i = 0; i < 256; i++)
+if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2);
+exit (0); }
+
+EOF
+{ (eval echo configure:1458: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; }
+if test -s conftest && (./conftest; exit) 2>/dev/null; then
+ :
+else
+ ac_cv_header_stdc=no
+fi
+fi
+rm -fr conftest*
+fi
+fi
+
+echo "$ac_t""$ac_cv_header_stdc" 1>&6
+if test $ac_cv_header_stdc = yes; then
+ cat >> confdefs.h <<\EOF
+#define STDC_HEADERS 1
+EOF
+
+fi
+
+echo $ac_n "checking for off_t""... $ac_c" 1>&6
+if eval "test \"`echo '$''{'ac_cv_type_off_t'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1482 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#endif
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "off_t" >/dev/null 2>&1; then
+ rm -rf conftest*
+ ac_cv_type_off_t=yes
+else
+ rm -rf conftest*
+ ac_cv_type_off_t=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_type_off_t" 1>&6
+if test $ac_cv_type_off_t = no; then
+ cat >> confdefs.h <<\EOF
+#define off_t long
+EOF
+
+fi
+
+echo $ac_n "checking for size_t""... $ac_c" 1>&6
+if eval "test \"`echo '$''{'ac_cv_type_size_t'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1513 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#endif
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "size_t" >/dev/null 2>&1; then
+ rm -rf conftest*
+ ac_cv_type_size_t=yes
+else
+ rm -rf conftest*
+ ac_cv_type_size_t=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_type_size_t" 1>&6
+if test $ac_cv_type_size_t = no; then
+ cat >> confdefs.h <<\EOF
+#define size_t unsigned
+EOF
+
+fi
+
+echo $ac_n "checking for ssize_t""... $ac_c" 1>&6
+if eval "test \"`echo '$''{'ac_cv_type_ssize_t'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1544 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#endif
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "ssize_t" >/dev/null 2>&1; then
+ rm -rf conftest*
+ ac_cv_type_ssize_t=yes
+else
+ rm -rf conftest*
+ ac_cv_type_ssize_t=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_type_ssize_t" 1>&6
+if test $ac_cv_type_ssize_t = no; then
+ cat >> confdefs.h <<\EOF
+#define ssize_t int
+EOF
+
+fi
+
+echo $ac_n "checking for time_t""... $ac_c" 1>&6
+if eval "test \"`echo '$''{'ac_cv_type_time_t'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1575 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#endif
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "time_t" >/dev/null 2>&1; then
+ rm -rf conftest*
+ ac_cv_type_time_t=yes
+else
+ rm -rf conftest*
+ ac_cv_type_time_t=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_type_time_t" 1>&6
+if test $ac_cv_type_time_t = no; then
+ cat >> confdefs.h <<\EOF
+#define time_t long
+EOF
+
+fi
+
+for ac_hdr in sys/time.h
+do
+ac_safe=`echo "$ac_hdr" | tr './\055' '___'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1609 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1614: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=yes"
+else
+ echo "$ac_err" >&5
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_hdr=HAVE_`echo $ac_hdr | tr 'abcdefghijklmnopqrstuvwxyz./\055' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ___'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+echo $ac_n "checking whether time.h and sys/time.h may both be included""... $ac_c" 1>&6
+if eval "test \"`echo '$''{'ac_cv_header_time'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1643 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <sys/time.h>
+#include <time.h>
+int main() { return 0; }
+int t() {
+struct tm *tp;
+; return 0; }
+EOF
+if { (eval echo configure:1653: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ac_cv_header_time=yes
+else
+ rm -rf conftest*
+ ac_cv_header_time=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_header_time" 1>&6
+if test $ac_cv_header_time = yes; then
+ cat >> confdefs.h <<\EOF
+#define TIME_WITH_SYS_TIME 1
+EOF
+
+fi
+
+
+echo $ac_n "checking for struct timespec in sys/time.h""... $ac_c" 1>&6
+if eval "test \"`echo '$''{'pthreads_cv_timespec_in_time'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1678 "configure"
+#include "confdefs.h"
+#include <sys/time.h>
+int main() { return 0; }
+int t() {
+struct timespec foo;
+; return 0; }
+EOF
+if { (eval echo configure:1686: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ pthreads_cv_timespec_in_time=yes
+else
+ rm -rf conftest*
+ pthreads_cv_timespec_in_time=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$pthreads_cv_timespec_in_time" 1>&6
+if test $pthreads_cv_timespec_in_time = yes ; then
+ cat >> confdefs.h <<\EOF
+#define _OS_HAS_TIMESPEC 1
+EOF
+
+fi
+
+
+
+echo $ac_n "checking type of size_t""... $ac_c" 1>&6
+if eval "test \"`echo '$''{'pthreads_cv_type_size_t'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1712 "configure"
+#include "confdefs.h"
+
+#include <stddef.h>
+#include <sys/types.h>
+#ifdef STDC_HEADERS
+#include <stdlib.h>
+#endif
+
+int main() { return 0; }
+int t() {
+ extern size_t foo;
+; return 0; }
+EOF
+if { (eval echo configure:1726: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ for try_type in "int" "unsigned int" "long" "unsigned long" "short" "unsigned short" "char" "unsigned char" "long long" "unsigned long long" ; do
+ cat > conftest.$ac_ext <<EOF
+#line 1730 "configure"
+#include "confdefs.h"
+
+#include <stddef.h>
+#include <sys/types.h>
+#ifdef STDC_HEADERS
+#include <stdlib.h>
+#endif
+
+int main() { return 0; }
+int t() {
+ extern size_t foo; extern $try_type foo;
+; return 0; }
+EOF
+if { (eval echo configure:1744: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ pthreads_cv_type_size_t="$try_type" ; break
+fi
+rm -f conftest*
+
+ done
+else
+ rm -rf conftest*
+ { echo "configure: error: Can't find system typedef for size_t." 1>&2; exit 1; }
+fi
+rm -f conftest*
+
+fi
+
+if test -n "$pthreads_cv_type_size_t" ; then
+ cat >> confdefs.h <<EOF
+#define pthread_size_t $pthreads_cv_type_size_t
+EOF
+
+fi
+pthread_size_t=$pthreads_cv_type_size_t
+echo "$ac_t""$pthreads_cv_type_size_t" 1>&6
+
+echo $ac_n "checking type of ssize_t""... $ac_c" 1>&6
+if eval "test \"`echo '$''{'pthreads_cv_type_ssize_t'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1773 "configure"
+#include "confdefs.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+int main() { return 0; }
+int t() {
+ extern ssize_t foo;
+; return 0; }
+EOF
+if { (eval echo configure:1785: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ for try_type in "int" "unsigned int" "long" "unsigned long" "short" "unsigned short" "char" "unsigned char" "long long" "unsigned long long" ; do
+ cat > conftest.$ac_ext <<EOF
+#line 1789 "configure"
+#include "confdefs.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+int main() { return 0; }
+int t() {
+ extern ssize_t foo; extern $try_type foo;
+; return 0; }
+EOF
+if { (eval echo configure:1801: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ pthreads_cv_type_ssize_t="$try_type" ; break
+fi
+rm -f conftest*
+
+ done
+else
+ rm -rf conftest*
+ { echo "configure: error: Can't find system typedef for ssize_t." 1>&2; exit 1; }
+fi
+rm -f conftest*
+
+fi
+
+if test -n "$pthreads_cv_type_ssize_t" ; then
+ cat >> confdefs.h <<EOF
+#define pthread_ssize_t $pthreads_cv_type_ssize_t
+EOF
+
+fi
+pthread_ssize_t=$pthreads_cv_type_ssize_t
+echo "$ac_t""$pthreads_cv_type_ssize_t" 1>&6
+
+echo $ac_n "checking type of clock_t""... $ac_c" 1>&6
+if eval "test \"`echo '$''{'pthreads_cv_type_clock_t'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1830 "configure"
+#include "confdefs.h"
+
+#include <stddef.h>
+#if TIME_WITH_SYS_TIME
+# include <time.h>
+# include <sys/time.h>
+#else
+# if HAVE_SYS_TIME_H
+# include <sys/time.h>
+# else
+# include <time.h>
+# endif
+#endif
+
+int main() { return 0; }
+int t() {
+ extern clock_t foo;
+; return 0; }
+EOF
+if { (eval echo configure:1850: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ for try_type in "int" "unsigned int" "long" "unsigned long" "short" "unsigned short" "char" "unsigned char" "long long" "unsigned long long" ; do
+ cat > conftest.$ac_ext <<EOF
+#line 1854 "configure"
+#include "confdefs.h"
+
+#include <stddef.h>
+#if TIME_WITH_SYS_TIME
+# include <time.h>
+# include <sys/time.h>
+#else
+# if HAVE_SYS_TIME_H
+# include <sys/time.h>
+# else
+# include <time.h>
+# endif
+#endif
+
+int main() { return 0; }
+int t() {
+ extern clock_t foo; extern $try_type foo;
+; return 0; }
+EOF
+if { (eval echo configure:1874: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ pthreads_cv_type_clock_t="$try_type" ; break
+fi
+rm -f conftest*
+
+ done
+else
+ rm -rf conftest*
+ { echo "configure: error: Can't find system typedef for clock_t." 1>&2; exit 1; }
+fi
+rm -f conftest*
+
+fi
+
+if test -n "$pthreads_cv_type_clock_t" ; then
+ cat >> confdefs.h <<EOF
+#define pthread_clock_t $pthreads_cv_type_clock_t
+EOF
+
+fi
+pthread_clock_t=$pthreads_cv_type_clock_t
+echo "$ac_t""$pthreads_cv_type_clock_t" 1>&6
+
+echo $ac_n "checking type of time_t""... $ac_c" 1>&6
+if eval "test \"`echo '$''{'pthreads_cv_type_time_t'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1903 "configure"
+#include "confdefs.h"
+
+#include <stddef.h>
+#if TIME_WITH_SYS_TIME
+# include <time.h>
+# include <sys/time.h>
+#else
+# if HAVE_SYS_TIME_H
+# include <sys/time.h>
+# else
+# include <time.h>
+# endif
+#endif
+
+int main() { return 0; }
+int t() {
+ extern time_t foo;
+; return 0; }
+EOF
+if { (eval echo configure:1923: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ for try_type in "int" "unsigned int" "long" "unsigned long" "short" "unsigned short" "char" "unsigned char" "long long" "unsigned long long" ; do
+ cat > conftest.$ac_ext <<EOF
+#line 1927 "configure"
+#include "confdefs.h"
+
+#include <stddef.h>
+#if TIME_WITH_SYS_TIME
+# include <time.h>
+# include <sys/time.h>
+#else
+# if HAVE_SYS_TIME_H
+# include <sys/time.h>
+# else
+# include <time.h>
+# endif
+#endif
+
+int main() { return 0; }
+int t() {
+ extern time_t foo; extern $try_type foo;
+; return 0; }
+EOF
+if { (eval echo configure:1947: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ pthreads_cv_type_time_t="$try_type" ; break
+fi
+rm -f conftest*
+
+ done
+else
+ rm -rf conftest*
+ { echo "configure: error: Can't find system typedef for time_t." 1>&2; exit 1; }
+fi
+rm -f conftest*
+
+fi
+
+if test -n "$pthreads_cv_type_time_t" ; then
+ cat >> confdefs.h <<EOF
+#define pthread_time_t $pthreads_cv_type_time_t
+EOF
+
+fi
+pthread_time_t=$pthreads_cv_type_time_t
+echo "$ac_t""$pthreads_cv_type_time_t" 1>&6
+echo $ac_n "checking for fpos_t in stdio.h""... $ac_c" 1>&6
+if eval "test \"`echo '$''{'pthreads_cv_fpos_t_in_stdio'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1975 "configure"
+#include "confdefs.h"
+#include <stdio.h>
+int main() { return 0; }
+int t() {
+fpos_t position;
+; return 0; }
+EOF
+if { (eval echo configure:1983: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ pthreads_cv_fpos_t_in_stdio=yes
+else
+ rm -rf conftest*
+ pthreads_cv_fpos_t_in_stdio=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$pthreads_cv_fpos_t_in_stdio" 1>&6
+if test $pthreads_cv_fpos_t_in_stdio = yes ; then
+
+echo $ac_n "checking type of fpos_t""... $ac_c" 1>&6
+if eval "test \"`echo '$''{'pthreads_cv_type_fpos_t'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2002 "configure"
+#include "confdefs.h"
+
+#include <stdio.h>
+#include <sys/types.h>
+#ifdef STDC_HEADERS
+#include <stdlib.h>
+#endif
+
+int main() { return 0; }
+int t() {
+ extern fpos_t foo;
+; return 0; }
+EOF
+if { (eval echo configure:2016: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ for try_type in "int" "unsigned int" "long" "unsigned long" "short" "unsigned short" "char" "unsigned char" "long long" "unsigned long long" ; do
+ cat > conftest.$ac_ext <<EOF
+#line 2020 "configure"
+#include "confdefs.h"
+
+#include <stdio.h>
+#include <sys/types.h>
+#ifdef STDC_HEADERS
+#include <stdlib.h>
+#endif
+
+int main() { return 0; }
+int t() {
+ extern fpos_t foo; extern $try_type foo;
+; return 0; }
+EOF
+if { (eval echo configure:2034: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ pthreads_cv_type_fpos_t="$try_type" ; break
+fi
+rm -f conftest*
+
+ done
+else
+ rm -rf conftest*
+ { echo "configure: error: Can't find system typedef for fpos_t." 1>&2; exit 1; }
+fi
+rm -f conftest*
+
+fi
+
+if test -n "$pthreads_cv_type_fpos_t" ; then
+ cat >> confdefs.h <<EOF
+#define pthread_fpos_t $pthreads_cv_type_fpos_t
+EOF
+
+fi
+pthread_fpos_t=$pthreads_cv_type_fpos_t
+echo "$ac_t""$pthreads_cv_type_fpos_t" 1>&6
+else
+ cat >> confdefs.h <<\EOF
+#define fpos_t off_t
+EOF
+
+ cat >> confdefs.h <<\EOF
+#define pthread_fpos_t pthread_off_t
+EOF
+
+fi
+
+echo $ac_n "checking type of off_t""... $ac_c" 1>&6
+if eval "test \"`echo '$''{'pthreads_cv_type_off_t'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2073 "configure"
+#include "confdefs.h"
+
+#include <stdio.h>
+#include <sys/types.h>
+#ifdef STDC_HEADERS
+#include <stdlib.h>
+#endif
+
+int main() { return 0; }
+int t() {
+ extern off_t foo;
+; return 0; }
+EOF
+if { (eval echo configure:2087: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ for try_type in "int" "unsigned int" "long" "unsigned long" "short" "unsigned short" "char" "unsigned char" "long long" "unsigned long long" ; do
+ cat > conftest.$ac_ext <<EOF
+#line 2091 "configure"
+#include "confdefs.h"
+
+#include <stdio.h>
+#include <sys/types.h>
+#ifdef STDC_HEADERS
+#include <stdlib.h>
+#endif
+
+int main() { return 0; }
+int t() {
+ extern off_t foo; extern $try_type foo;
+; return 0; }
+EOF
+if { (eval echo configure:2105: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ pthreads_cv_type_off_t="$try_type" ; break
+fi
+rm -f conftest*
+
+ done
+else
+ rm -rf conftest*
+ { echo "configure: error: Can't find system typedef for off_t." 1>&2; exit 1; }
+fi
+rm -f conftest*
+
+fi
+
+if test -n "$pthreads_cv_type_off_t" ; then
+ cat >> confdefs.h <<EOF
+#define pthread_off_t $pthreads_cv_type_off_t
+EOF
+
+fi
+pthread_off_t=$pthreads_cv_type_off_t
+echo "$ac_t""$pthreads_cv_type_off_t" 1>&6
+echo $ac_n "checking type of va_list""... $ac_c" 1>&6
+if eval "test \"`echo '$''{'pthreads_cv_type_va_list'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2133 "configure"
+#include "confdefs.h"
+#include <stdarg.h>
+int main() { return 0; }
+int t() {
+ extern va_list foo;
+; return 0; }
+EOF
+if { (eval echo configure:2141: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ for try_type in "char *" "char **" "void *" "void **" "int *" "long *" ; do
+ cat > conftest.$ac_ext <<EOF
+#line 2145 "configure"
+#include "confdefs.h"
+#include <stdarg.h>
+int main() { return 0; }
+int t() {
+ extern va_list foo; extern $try_type foo;
+; return 0; }
+EOF
+if { (eval echo configure:2153: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ pthreads_cv_type_va_list="$try_type" ; break
+fi
+rm -f conftest*
+
+ done
+else
+ rm -rf conftest*
+ { echo "configure: error: Can't find system typedef for va_list." 1>&2; exit 1; }
+fi
+rm -f conftest*
+
+fi
+
+if test -n "$pthreads_cv_type_va_list" ; then
+ cat >> confdefs.h <<EOF
+#define pthread_va_list $pthreads_cv_type_va_list
+EOF
+
+fi
+pthread_va_list=$pthreads_cv_type_va_list
+echo "$ac_t""$pthreads_cv_type_va_list" 1>&6
+
+arpa_headers="#include <sys/types.h>
+#include <arpa/nameser.h>"
+
+echo $ac_n "checking IP address type""... $ac_c" 1>&6
+if eval "test \"`echo '$''{'pthread_cv_type_ipaddr'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2185 "configure"
+#include "confdefs.h"
+$arpa_headers
+int main() { return 0; }
+int t() {
+ &_getlong;
+; return 0; }
+EOF
+if { (eval echo configure:2193: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+
+ for type in "unsigned long" "unsigned int" ; do
+ cat > conftest.$ac_ext <<EOF
+#line 2198 "configure"
+#include "confdefs.h"
+$arpa_headers
+int main() { return 0; }
+int t() {
+extern $type _getlong ();
+; return 0; }
+EOF
+if { (eval echo configure:2206: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+
+ pthread_cv_type_ipaddr="$type"
+ break
+
+fi
+rm -f conftest*
+
+ done
+
+else
+ rm -rf conftest*
+ echo "configure: warning: Can't compile _getlong reference." 1>&2
+fi
+rm -f conftest*
+
+ if test "$pthread_cv_type_ipaddr" = "" ; then
+ echo "configure: warning: Can't determine _getlong return type." 1>&2
+ echo "configure: warning: Defaulting to unsigned long." 1>&2
+ pthread_cv_type_ipaddr="unsigned long"
+ fi
+
+fi
+
+echo "$ac_t""$pthread_cv_type_ipaddr" 1>&6
+cat >> confdefs.h <<EOF
+#define pthread_ipaddr_type $pthread_cv_type_ipaddr
+EOF
+
+
+echo $ac_n "checking IP port type""... $ac_c" 1>&6
+if eval "test \"`echo '$''{'pthread_cv_type_ipport'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2242 "configure"
+#include "confdefs.h"
+$arpa_headers
+int main() { return 0; }
+int t() {
+ &_getshort;
+; return 0; }
+EOF
+if { (eval echo configure:2250: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+
+ for type in "unsigned short" "unsigned int" ; do
+ cat > conftest.$ac_ext <<EOF
+#line 2255 "configure"
+#include "confdefs.h"
+$arpa_headers
+int main() { return 0; }
+int t() {
+extern $type _getshort ();
+; return 0; }
+EOF
+if { (eval echo configure:2263: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+
+ pthread_cv_type_ipport="$type"
+ break
+
+fi
+rm -f conftest*
+
+ done
+
+else
+ rm -rf conftest*
+ echo "configure: warning: Can't compile _getshort reference." 1>&2
+fi
+rm -f conftest*
+
+ if test "$pthread_cv_type_ipport" = "" ; then
+ echo "configure: warning: Can't determine _getshort return type." 1>&2
+ echo "configure: warning: Defaulting to unsigned short." 1>&2
+ pthread_cv_type_ipport="unsigned short"
+ fi
+
+fi
+
+echo "$ac_t""$pthread_cv_type_ipport" 1>&6
+cat >> confdefs.h <<EOF
+#define pthread_ipport_type $pthread_cv_type_ipport
+EOF
+
+
+echo $ac_n "checking pathname for terminal devices directory""... $ac_c" 1>&6
+if eval "test \"`echo '$''{'pthread_cv_pty_path'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -d /devices/pseudo ; then
+ pty_path=/devices/pseudo/
+ else
+ pty_path=/dev/
+ fi
+ pthread_cv_pty_path=$pty_path
+
+fi
+
+cat >> confdefs.h <<EOF
+#define _PATH_PTY "$pthread_cv_pty_path"
+EOF
+
+echo "$ac_t""$pthread_cv_pty_path" 1>&6
+
+echo $ac_n "checking directory name for time zone info""... $ac_c" 1>&6
+tzdir=NONE
+for f in /usr/lib/zoneinfo /usr/share/zoneinfo /usr/share/lib/zoneinfo /etc/zoneinfo /usr/local/lib/zoneinfo
+do
+ if test -d $f ; then
+ tzdir=$f
+ break
+ fi
+done
+case $tzdir in
+NONE)
+ echo "configure: warning: Can't find zoneinfo directory." 1>&2
+ echo "configure: warning: Defaulting zoneinfo directory to NULL." 1>&2
+ tzdir=NULL
+ ;;
+esac
+cat >> confdefs.h <<EOF
+#define _PATH_TZDIR "$tzdir"
+EOF
+
+echo "$ac_t""$tzdir" 1>&6
+
+echo $ac_n "checking filename for local time zone""... $ac_c" 1>&6
+tzfile=NONE
+for f in $tzdir/localtime /etc/localtime
+do
+ if test -f $f ; then
+ tzfile=$f
+ break
+ fi
+done
+case $tzfile in
+NONE) # Should this default to tzdir/localtime?
+ echo "configure: warning: Can't find local time zone file." 1>&2
+ if test tzdir = NULL ; then
+ echo "configure: warning: Defaulting local time zone file to NULL" 1>&2
+ tzfile=NULL
+ else
+ echo "configure: warning: Defaulting local time zone file to $tzdir/localtime." 1>&2
+ tzfile=$tzdir/localtime
+ fi
+ ;;
+esac
+cat >> confdefs.h <<EOF
+#define _PATH_TZFILE "$tzfile"
+EOF
+
+echo "$ac_t""$tzfile" 1>&6
+
+cat >> confdefs.h <<\EOF
+#define _PATH_RESCONF "/etc/resolv.conf"
+EOF
+
+cat >> confdefs.h <<\EOF
+#define _PATH_HOSTS "/etc/hosts"
+EOF
+
+cat >> confdefs.h <<\EOF
+#define _PATH_NETWORKS "/etc/networks"
+EOF
+
+cat >> confdefs.h <<\EOF
+#define _PATH_PROTOCOLS "/etc/protocols"
+EOF
+
+cat >> confdefs.h <<\EOF
+#define _PATH_SERVICES "/etc/services"
+EOF
+
+
+cat >> confdefs.h <<\EOF
+#define _PATH_BSHELL "/bin/sh"
+EOF
+
+
+for ac_func in vfork
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2395 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func();
+
+int main() { return 0; }
+int t() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:2419: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; }; then
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=yes"
+else
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+
+fi
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+
+srctop=`cd ${srcdir}/..;pwd`
+
+
+# Now we deal with symlinks &c.
+
+test -d include || mkdir include || \
+ { echo "configure: error: Can't create include directory." 1>&2; exit 1; }
+
+test -d include/pthread || mkdir include/pthread || \
+ { echo "configure: error: Can't create include/pthread directory." 1>&2; exit 1; }
+
+test -d lib || mkdir lib || \
+ { echo "configure: error: Can't create lib directory." 1>&2; exit 1; }
+
+test -d lib/libpthreadutil || mkdir lib/libpthreadutil || \
+ { echo "configure: error: Can't create lib/libpthreadutil directory." 1>&2; exit 1; }
+
+test -d bin || mkdir bin || \
+ { echo "configure: error: Can't create bin directory." 1>&2; exit 1; }
+
+test -d bin/finger || mkdir bin/finger || \
+ { echo "configure: error: Can't create bin directory." 1>&2; exit 1; }
+
+test -d tests || mkdir tests || \
+ { echo "configure: error: Can't create tests directory." 1>&2; exit 1; }
+
+if test x$syscall = xNONE ; then
+ syscall=$name
+fi
+
+links="include/pthread/machdep.h include/pthread/posix.h \
+ machdep.c syscall.S"
+targets="../machdep/engine-$name.h ../machdep/posix-$sysincludes.h \
+ ../machdep/engine-$name.c ../machdep/syscall-$syscall.S"
+
+# Both these targets are optional. (Autoconf-generated configure scripts
+# will require the existence of link targets, so check before adding them
+# to the list.)
+if test x$sysincludes != xNONE ; then
+ links="$links include/sys"
+ targets="$targets ../machdep/$sysincludes"
+fi
+
+syscall_file=../machdep/syscall-template-$syscall.S
+if test -r $srcdir/$syscall_file ; then
+ links="$links syscall-template.S"
+ targets="$targets $syscall_file"
+ HAVE_SYSCALL_TEMPLATE=yes
+else
+ # This really isn't a fatal problem. In fact, it's expected, initially,
+ # for some targets. This is just to persuade people to fix the targets
+ # they deal with to provide some sort of template.
+ #
+ # Eventually this file probably will be required...
+ echo "configure: warning: No syscall template file syscall-template-$syscall.S found." 1>&2
+ HAVE_SYSCALL_TEMPLATE=no
+fi
+
+
+
+
+if test x$makefile_frag != x ; then
+ makefile_frag=${srcdir}/$makefile_frag
+else
+ makefile_frag=/dev/null
+fi
+
+
+
+
+
+trap '' 1 2 15
+cat > confcache <<\EOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs. It is not useful on other systems.
+# If it contains results you don't want to keep, you may remove or edit it.
+#
+# By default, configure uses ./config.cache as the cache file,
+# creating it if it does not exist already. You can give configure
+# the --cache-file=FILE option to use a different cache file; that is
+# what configure does when it calls configure scripts in
+# subdirectories, so they share the cache.
+# Giving --cache-file=/dev/null disables caching, for debugging configure.
+# config.status only pays attention to the cache file if you give it the
+# --recheck option to rerun configure.
+#
+EOF
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(set) 2>&1 |
+ sed -n "s/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=\${\1='\2'}/p" \
+ >> confcache
+if cmp -s $cache_file confcache; then
+ :
+else
+ if test -w $cache_file; then
+ echo "updating cache $cache_file"
+ cat confcache > $cache_file
+ else
+ echo "not updating unwritable cache $cache_file"
+ fi
+fi
+rm -f confcache
+
+trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+# Any assignment to VPATH causes Sun make to only execute
+# the first set of double-colon rules, so remove it if not needed.
+# If there is a colon in the path, we need to keep it.
+if test "x$srcdir" = x.; then
+ ac_vpsub='/^[ ]*VPATH[ ]*=[^:]*$/d'
+fi
+
+trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15
+
+DEFS=-DHAVE_CONFIG_H
+
+# Without the "./", some shells look in PATH for config.status.
+: ${CONFIG_STATUS=./config.status}
+
+echo creating $CONFIG_STATUS
+rm -f $CONFIG_STATUS
+cat > $CONFIG_STATUS <<EOF
+#! /bin/sh
+# Generated automatically by configure.
+# Run this file to recreate the current configuration.
+# This directory was configured as follows,
+# on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+#
+# $0 $ac_configure_args
+#
+# Compiler output produced by configure, useful for debugging
+# configure, is in ./config.log if it exists.
+
+ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]"
+for ac_option
+do
+ case "\$ac_option" in
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion"
+ exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;;
+ -version | --version | --versio | --versi | --vers | --ver | --ve | --v)
+ echo "$CONFIG_STATUS generated by autoconf version 2.10"
+ exit 0 ;;
+ -help | --help | --hel | --he | --h)
+ echo "\$ac_cs_usage"; exit 0 ;;
+ *) echo "\$ac_cs_usage"; exit 1 ;;
+ esac
+done
+
+ac_given_srcdir=$srcdir
+
+trap 'rm -fr `echo "config.flags GNUmakefile Makefile \
+ lib/Makefile:../lib/Makefile.in \
+ lib/libpthreadutil/Makefile:../lib/libpthreadutil/Makefile.in \
+ bin/Makefile:../bin/Makefile.in \
+ bin/finger/Makefile:../bin/finger/Makefile.in \
+ tests/Makefile:../tests/Makefile.in config.h" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15
+EOF
+cat >> $CONFIG_STATUS <<EOF
+
+# Protect against being on the right side of a sed subst in config.status.
+sed 's/%@/@@/; s/@%/@@/; s/%g\$/@g/; /@g\$/s/[\\\\&%]/\\\\&/g;
+ s/@@/%@/; s/@@/@%/; s/@g\$/%g/' > conftest.subs <<\\CEOF
+$ac_vpsub
+$extrasub
+s%@CFLAGS@%$CFLAGS%g
+s%@CPPFLAGS@%$CPPFLAGS%g
+s%@CXXFLAGS@%$CXXFLAGS%g
+s%@DEFS@%$DEFS%g
+s%@LDFLAGS@%$LDFLAGS%g
+s%@LIBS@%$LIBS%g
+s%@exec_prefix@%$exec_prefix%g
+s%@prefix@%$prefix%g
+s%@program_transform_name@%$program_transform_name%g
+s%@bindir@%$bindir%g
+s%@sbindir@%$sbindir%g
+s%@libexecdir@%$libexecdir%g
+s%@datadir@%$datadir%g
+s%@sysconfdir@%$sysconfdir%g
+s%@sharedstatedir@%$sharedstatedir%g
+s%@localstatedir@%$localstatedir%g
+s%@libdir@%$libdir%g
+s%@includedir@%$includedir%g
+s%@oldincludedir@%$oldincludedir%g
+s%@infodir@%$infodir%g
+s%@mandir@%$mandir%g
+s%@CC@%$CC%g
+s%@CXX@%$CXX%g
+s%@CPP@%$CPP%g
+s%@RANLIB@%$RANLIB%g
+s%@host@%$host%g
+s%@host_alias@%$host_alias%g
+s%@host_cpu@%$host_cpu%g
+s%@host_vendor@%$host_vendor%g
+s%@host_os@%$host_os%g
+s%@target@%$target%g
+s%@target_alias@%$target_alias%g
+s%@target_cpu@%$target_cpu%g
+s%@target_vendor@%$target_vendor%g
+s%@target_os@%$target_os%g
+s%@build@%$build%g
+s%@build_alias@%$build_alias%g
+s%@build_cpu@%$build_cpu%g
+s%@build_vendor@%$build_vendor%g
+s%@build_os@%$build_os%g
+s%@SYSCALL_EXCEPTIONS@%$SYSCALL_EXCEPTIONS%g
+s%@available_syscalls@%$available_syscalls%g
+s%@missing_syscalls@%$missing_syscalls%g
+s%@srctop@%$srctop%g
+s%@HAVE_SYSCALL_TEMPLATE@%$HAVE_SYSCALL_TEMPLATE%g
+/@makefile_frag@/r $makefile_frag
+s%@makefile_frag@%%g
+
+CEOF
+EOF
+cat >> $CONFIG_STATUS <<EOF
+
+CONFIG_FILES=\${CONFIG_FILES-"config.flags GNUmakefile Makefile \
+ lib/Makefile:../lib/Makefile.in \
+ lib/libpthreadutil/Makefile:../lib/libpthreadutil/Makefile.in \
+ bin/Makefile:../bin/Makefile.in \
+ bin/finger/Makefile:../bin/finger/Makefile.in \
+ tests/Makefile:../tests/Makefile.in"}
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then
+ # Support "outfile[:infile]", defaulting infile="outfile.in".
+ case "$ac_file" in
+ *:*) ac_file_in=`echo "$ac_file"|sed 's%.*:%%'`
+ ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
+ *) ac_file_in="${ac_file}.in" ;;
+ esac
+
+ # Adjust relative srcdir, etc. for subdirectories.
+
+ # Remove last slash and all that follows it. Not all systems have dirname.
+ ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
+ if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
+ # The file is in a subdirectory.
+ test ! -d "$ac_dir" && mkdir "$ac_dir"
+ ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`"
+ # A "../" for each directory in $ac_dir_suffix.
+ ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'`
+ else
+ ac_dir_suffix= ac_dots=
+ fi
+
+ case "$ac_given_srcdir" in
+ .) srcdir=.
+ if test -z "$ac_dots"; then top_srcdir=.
+ else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;;
+ /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;;
+ *) # Relative path.
+ srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix"
+ top_srcdir="$ac_dots$ac_given_srcdir" ;;
+ esac
+
+ echo creating "$ac_file"
+ rm -f "$ac_file"
+ configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure."
+ case "$ac_file" in
+ *Makefile*) ac_comsub="1i\\
+# $configure_input" ;;
+ *) ac_comsub= ;;
+ esac
+ sed -e "$ac_comsub
+s%@configure_input@%$configure_input%g
+s%@srcdir@%$srcdir%g
+s%@top_srcdir@%$top_srcdir%g
+" -f conftest.subs $ac_given_srcdir/$ac_file_in > $ac_file
+fi; done
+rm -f conftest.subs
+
+# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where
+# NAME is the cpp macro being defined and VALUE is the value it is being given.
+#
+# ac_d sets the value in "#define NAME VALUE" lines.
+ac_dA='s%^\([ ]*\)#\([ ]*define[ ][ ]*\)'
+ac_dB='\([ ][ ]*\)[^ ]*%\1#\2'
+ac_dC='\3'
+ac_dD='%g'
+# ac_u turns "#undef NAME" with trailing blanks into "#define NAME VALUE".
+ac_uA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)'
+ac_uB='\([ ]\)%\1#\2define\3'
+ac_uC=' '
+ac_uD='\4%g'
+# ac_e turns "#undef NAME" without trailing blanks into "#define NAME VALUE".
+ac_eA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)'
+ac_eB='$%\1#\2define\3'
+ac_eC=' '
+ac_eD='%g'
+
+CONFIG_HEADERS=${CONFIG_HEADERS-"config.h"}
+for ac_file in .. $CONFIG_HEADERS; do if test "x$ac_file" != x..; then
+ # Support "outfile[:infile]", defaulting infile="outfile.in".
+ case "$ac_file" in
+ *:*) ac_file_in=`echo "$ac_file"|sed 's%.*:%%'`
+ ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
+ *) ac_file_in="${ac_file}.in" ;;
+ esac
+
+ echo creating $ac_file
+
+ rm -f conftest.frag conftest.in conftest.out
+ cp $ac_given_srcdir/$ac_file_in conftest.in
+
+EOF
+
+# Transform confdefs.h into a sed script conftest.vals that substitutes
+# the proper values into config.h.in to produce config.h. And first:
+# Protect against being on the right side of a sed subst in config.status.
+# Protect against being in an unquoted here document in config.status.
+rm -f conftest.vals
+cat > conftest.hdr <<\EOF
+s/[\\&%]/\\&/g
+s%[\\$`]%\\&%g
+s%#define \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD}%gp
+s%ac_d%ac_u%gp
+s%ac_u%ac_e%gp
+EOF
+sed -n -f conftest.hdr confdefs.h > conftest.vals
+rm -f conftest.hdr
+
+# This sed command replaces #undef with comments. This is necessary, for
+# example, in the case of _POSIX_SOURCE, which is predefined and required
+# on some systems where configure will not decide to define it.
+cat >> conftest.vals <<\EOF
+s%^[ ]*#[ ]*undef[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*%/* & */%
+EOF
+
+# Break up conftest.vals because some shells have a limit on
+# the size of here documents, and old seds have small limits too.
+# Maximum number of lines to put in a single here document.
+ac_max_here_lines=12
+
+rm -f conftest.tail
+while :
+do
+ ac_lines=`grep -c . conftest.vals`
+ # grep -c gives empty output for an empty file on some AIX systems.
+ if test -z "$ac_lines" || test "$ac_lines" -eq 0; then break; fi
+ # Write a limited-size here document to conftest.frag.
+ echo ' cat > conftest.frag <<CEOF' >> $CONFIG_STATUS
+ sed ${ac_max_here_lines}q conftest.vals >> $CONFIG_STATUS
+ echo 'CEOF
+ sed -f conftest.frag conftest.in > conftest.out
+ rm -f conftest.in
+ mv conftest.out conftest.in
+' >> $CONFIG_STATUS
+ sed 1,${ac_max_here_lines}d conftest.vals > conftest.tail
+ rm -f conftest.vals
+ mv conftest.tail conftest.vals
+done
+rm -f conftest.vals
+
+cat >> $CONFIG_STATUS <<\EOF
+ rm -f conftest.frag conftest.h
+ echo "/* $ac_file. Generated automatically by configure. */" > conftest.h
+ cat conftest.in >> conftest.h
+ rm -f conftest.in
+ if cmp -s $ac_file conftest.h 2>/dev/null; then
+ echo "$ac_file is unchanged"
+ rm -f conftest.h
+ else
+ # Remove last slash and all that follows it. Not all systems have dirname.
+ ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
+ if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
+ # The file is in a subdirectory.
+ test ! -d "$ac_dir" && mkdir "$ac_dir"
+ fi
+ rm -f $ac_file
+ mv conftest.h $ac_file
+ fi
+fi; done
+
+EOF
+
+cat >> $CONFIG_STATUS <<EOF
+ac_sources="$targets"
+ac_dests="$links"
+EOF
+
+cat >> $CONFIG_STATUS <<\EOF
+srcdir=$ac_given_srcdir
+while test -n "$ac_sources"; do
+ set $ac_dests; ac_dest=$1; shift; ac_dests=$*
+ set $ac_sources; ac_source=$1; shift; ac_sources=$*
+
+ echo "linking $srcdir/$ac_source to $ac_dest"
+
+ if test ! -r $srcdir/$ac_source; then
+ { echo "configure: error: $srcdir/$ac_source: File not found" 1>&2; exit 1; }
+ fi
+ rm -f $ac_dest
+
+ # Make relative symlinks.
+ # Remove last slash and all that follows it. Not all systems have dirname.
+ ac_dest_dir=`echo $ac_dest|sed 's%/[^/][^/]*$%%'`
+ if test "$ac_dest_dir" != "$ac_dest" && test "$ac_dest_dir" != .; then
+ # The dest file is in a subdirectory.
+ test ! -d "$ac_dest_dir" && mkdir "$ac_dest_dir"
+ ac_dest_dir_suffix="/`echo $ac_dest_dir|sed 's%^\./%%'`"
+ # A "../" for each directory in $ac_dest_dir_suffix.
+ ac_dots=`echo $ac_dest_dir_suffix|sed 's%/[^/]*%../%g'`
+ else
+ ac_dest_dir_suffix= ac_dots=
+ fi
+
+ case "$srcdir" in
+ [/$]*) ac_rel_source="$srcdir/$ac_source" ;;
+ *) ac_rel_source="$ac_dots$srcdir/$ac_source" ;;
+ esac
+
+ # Make a symlink if possible; otherwise try a hard link.
+ if ln -s $ac_rel_source $ac_dest 2>/dev/null ||
+ ln $srcdir/$ac_source $ac_dest; then :
+ else
+ { echo "configure: error: can not link $ac_dest to $srcdir/$ac_source" 1>&2; exit 1; }
+ fi
+done
+
+
+exit 0
+EOF
+chmod +x $CONFIG_STATUS
+rm -fr confdefs* $ac_clean_files
+test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1
+
diff --git a/mit-pthreads/config/install-sh b/mit-pthreads/config/install-sh
new file mode 100755
index 00000000000..ab74c882e92
--- /dev/null
+++ b/mit-pthreads/config/install-sh
@@ -0,0 +1,238 @@
+#!/bin/sh
+#
+# install - install a program, script, or datafile
+# This comes from X11R5.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# `make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch.
+#
+
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit="${DOITPROG-}"
+
+
+# put in absolute paths if you don't have them in your path; or use env. vars.
+
+mvprog="${MVPROG-mv}"
+cpprog="${CPPROG-cp}"
+chmodprog="${CHMODPROG-chmod}"
+chownprog="${CHOWNPROG-chown}"
+chgrpprog="${CHGRPPROG-chgrp}"
+stripprog="${STRIPPROG-strip}"
+rmprog="${RMPROG-rm}"
+mkdirprog="${MKDIRPROG-mkdir}"
+
+tranformbasename=""
+transform_arg=""
+instcmd="$mvprog"
+chmodcmd="$chmodprog 0755"
+chowncmd=""
+chgrpcmd=""
+stripcmd=""
+rmcmd="$rmprog -f"
+mvcmd="$mvprog"
+src=""
+dst=""
+dir_arg=""
+
+while [ x"$1" != x ]; do
+ case $1 in
+ -c) instcmd="$cpprog"
+ shift
+ continue;;
+
+ -d) dir_arg=true
+ shift
+ continue;;
+
+ -m) chmodcmd="$chmodprog $2"
+ shift
+ shift
+ continue;;
+
+ -o) chowncmd="$chownprog $2"
+ shift
+ shift
+ continue;;
+
+ -g) chgrpcmd="$chgrpprog $2"
+ shift
+ shift
+ continue;;
+
+ -s) stripcmd="$stripprog"
+ shift
+ continue;;
+
+ -t=*) transformarg=`echo $1 | sed 's/-t=//'`
+ shift
+ continue;;
+
+ -b=*) transformbasename=`echo $1 | sed 's/-b=//'`
+ shift
+ continue;;
+
+ *) if [ x"$src" = x ]
+ then
+ src=$1
+ else
+ # this colon is to work around a 386BSD /bin/sh bug
+ :
+ dst=$1
+ fi
+ shift
+ continue;;
+ esac
+done
+
+if [ x"$src" = x ]
+then
+ echo "install: no input file specified"
+ exit 1
+else
+ true
+fi
+
+if [ x"$dir_arg" != x ]; then
+ dst=$src
+ src=""
+
+ if [ -d $dst ]; then
+ instcmd=:
+ else
+ instcmd=mkdir
+ fi
+else
+
+# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
+# might cause directories to be created, which would be especially bad
+# if $src (and thus $dsttmp) contains '*'.
+
+ if [ -f $src -o -d $src ]
+ then
+ true
+ else
+ echo "install: $src does not exist"
+ exit 1
+ fi
+
+ if [ x"$dst" = x ]
+ then
+ echo "install: no destination specified"
+ exit 1
+ else
+ true
+ fi
+
+# If destination is a directory, append the input filename; if your system
+# does not like double slashes in filenames, you may need to add some logic
+
+ if [ -d $dst ]
+ then
+ dst="$dst"/`basename $src`
+ else
+ true
+ fi
+fi
+
+## this sed command emulates the dirname command
+dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
+
+# Make sure that the destination directory exists.
+# this part is taken from Noah Friedman's mkinstalldirs script
+
+# Skip lots of stat calls in the usual case.
+if [ ! -d "$dstdir" ]; then
+defaultIFS='
+'
+IFS="${IFS-${defaultIFS}}"
+
+oIFS="${IFS}"
+# Some sh's can't handle IFS=/ for some reason.
+IFS='%'
+set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
+IFS="${oIFS}"
+
+pathcomp=''
+
+while [ $# -ne 0 ] ; do
+ pathcomp="${pathcomp}${1}"
+ shift
+
+ if [ ! -d "${pathcomp}" ] ;
+ then
+ $mkdirprog "${pathcomp}"
+ else
+ true
+ fi
+
+ pathcomp="${pathcomp}/"
+done
+fi
+
+if [ x"$dir_arg" != x ]
+then
+ $doit $instcmd $dst &&
+
+ if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
+ if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
+ if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
+ if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
+else
+
+# If we're going to rename the final executable, determine the name now.
+
+ if [ x"$transformarg" = x ]
+ then
+ dstfile=`basename $dst`
+ else
+ dstfile=`basename $dst $transformbasename |
+ sed $transformarg`$transformbasename
+ fi
+
+# don't allow the sed command to completely eliminate the filename
+
+ if [ x"$dstfile" = x ]
+ then
+ dstfile=`basename $dst`
+ else
+ true
+ fi
+
+# Make a temp file name in the proper directory.
+
+ dsttmp=$dstdir/#inst.$$#
+
+# Move or copy the file name to the temp name
+
+ $doit $instcmd $src $dsttmp &&
+
+ trap "rm -f ${dsttmp}" 0 &&
+
+# and set any options; do chmod last to preserve setuid bits
+
+# If any of these fail, we abort the whole thing. If we want to
+# ignore errors from any of these, just make sure not to ignore
+# errors from the above "$doit $instcmd $src $dsttmp" command.
+
+ if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
+ if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
+ if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
+ if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
+
+# Now rename the file to the real destination.
+
+ $doit $rmcmd -f $dstdir/$dstfile &&
+ $doit $mvcmd $dsttmp $dstdir/$dstfile
+
+fi &&
+
+
+exit 0
diff --git a/mit-pthreads/configure b/mit-pthreads/configure
new file mode 100755
index 00000000000..9411483a31d
--- /dev/null
+++ b/mit-pthreads/configure
@@ -0,0 +1,19 @@
+#!/bin/sh
+
+# This silliness is because Chris wants the autoconf-related files
+# and makefiles not to appear in the top-level directory. Fine by
+# me, I don't much care. This script just needs to invoke the real
+# configure script...
+
+config=`echo $0 | sed -e 's,configure$,config/configure,'`
+
+if test ! -d obj ; then
+ mkdir obj
+fi
+
+if test -n "$1" ; then
+ exec $config "$@"
+else
+ exec $config
+fi
+
diff --git a/mit-pthreads/gen/GNUmakefile.inc b/mit-pthreads/gen/GNUmakefile.inc
new file mode 100755
index 00000000000..a5025860b85
--- /dev/null
+++ b/mit-pthreads/gen/GNUmakefile.inc
@@ -0,0 +1,9 @@
+# from: @(#)Makefile.inc 5.21 (Berkeley) 5/24/91
+# $Id$
+
+# gen sources
+VPATH:= ${VPATH}:${srcdir}/gen
+
+SRCS:= ttyname.c directory.c popen.c time.c ctime.c difftime.c syslog.c \
+ eprintf.c getpwent.c getpwnamuid.c pwd_internal.c \
+ getcwd.c getwd.c isatty.c $(SRCS)
diff --git a/mit-pthreads/gen/Makefile.inc b/mit-pthreads/gen/Makefile.inc
new file mode 100644
index 00000000000..6e2c3d44f43
--- /dev/null
+++ b/mit-pthreads/gen/Makefile.inc
@@ -0,0 +1,24 @@
+# from: @(#)Makefile.inc 5.21 (Berkeley) 5/24/91
+# $Id$
+
+# gen sources
+.PATH: ${srcdir}/gen
+
+SRCS+= ttyname.c isatty.c directory.c popen.c time.c ctime.c difftime.c \
+ syslog.c eprintf.c getpwent.c getpwnamuid.c pwd_internal.c
+
+#SRCS+= alarm.c assert.c clock.c crypt.c ctermid.c ctype_.c \
+# disklabel.c err.c errlst.c exec.c fnmatch.c frexp.c \
+# fstab.c fts.c getcap.c getcwd.c getgrent.c getlogin.c getmntinfo.c \
+# getpass.c getpwent.c getsubopt.c getttyent.c getusershell.c glob.c \
+# infinity.c initgroups.c isatty.c isctype.c isinf.c mktemp.c nice.c \
+# nlist.c pause.c psignal.c raise.c \
+# scandir.c setjmperr.c \
+# setmode.c setrgid.c setruid.c siginterrupt.c \
+# siglist.c signal.c sigsetops.c syslog.c \
+# termios.c time.c times.c timezone.c ttyslot.c \
+# ualarm.c unvis.c utime.c valloc.c vis.c
+#
+# gen/regexp sources
+#SRCS+= regerror.c regexp.c regsub.c
+
diff --git a/mit-pthreads/gen/ctime.c b/mit-pthreads/gen/ctime.c
new file mode 100644
index 00000000000..e7980296e50
--- /dev/null
+++ b/mit-pthreads/gen/ctime.c
@@ -0,0 +1,1315 @@
+/*
+ * Copyright (c) 1987, 1989 Regents of the University of California.
+ * Copyright (c) 1994 Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Arthur David Olson of the National Cancer Institute.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)ctime.c 5.26 (Berkeley) 2/23/91";
+#endif /* LIBC_SCCS and not lint */
+
+/*
+** Leap second handling from Bradley White (bww@k.gp.cs.cmu.edu).
+** POSIX-style TZ environment variable handling from Guy Harris
+** (guy@auspex.com).
+*/
+
+/*LINTLIBRARY*/
+#include "config.h"
+#include <pthread.h>
+#include <sys/param.h>
+#include <fcntl.h>
+#include <time.h>
+#include <tzfile.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#ifndef WILDABBR
+/*
+** Someone might make incorrect use of a time zone abbreviation:
+** 1. They might reference tzname[0] before calling tzset (explicitly
+** or implicitly).
+** 2. They might reference tzname[1] before calling tzset (explicitly
+** or implicitly).
+** 3. They might reference tzname[1] after setting to a time zone
+** in which Daylight Saving Time is never observed.
+** 4. They might reference tzname[0] after setting to a time zone
+** in which Standard Time is never observed.
+** 5. They might reference tm.TM_ZONE after calling offtime.
+** What's best to do in the above cases is open to debate;
+** for now, we just set things up so that in any of the five cases
+** WILDABBR is used. Another possibility: initialize tzname[0] to the
+** string "tzname[0] used before set", and similarly for the other cases.
+** And another: initialize tzname[0] to "ERA", with an explanation in the
+** manual page of what this "time zone abbreviation" means (doing this so
+** that tzname[0] has the "normal" length of three characters).
+*/
+#define WILDABBR " "
+#endif /* !defined WILDABBR */
+
+#ifndef TRUE
+#define TRUE 1
+#define FALSE 0
+#endif /* !defined TRUE */
+
+static const char GMT[] = "GMT";
+
+struct ttinfo { /* time type information */
+ long tt_gmtoff; /* GMT offset in seconds */
+ int tt_isdst; /* used to set tm_isdst */
+ int tt_abbrind; /* abbreviation list index */
+ int tt_ttisstd; /* TRUE if transition is std time */
+};
+
+struct lsinfo { /* leap second information */
+ time_t ls_trans; /* transition time */
+ long ls_corr; /* correction to apply */
+};
+
+struct state {
+ int leapcnt;
+ int timecnt;
+ int typecnt;
+ int charcnt;
+ time_t ats[TZ_MAX_TIMES];
+ unsigned char types[TZ_MAX_TIMES];
+ struct ttinfo ttis[TZ_MAX_TYPES];
+ char chars[(TZ_MAX_CHARS + 1 > sizeof GMT) ?
+ TZ_MAX_CHARS + 1 : sizeof GMT];
+ struct lsinfo lsis[TZ_MAX_LEAPS];
+};
+
+struct rule {
+ int r_type; /* type of rule--see below */
+ int r_day; /* day number of rule */
+ int r_week; /* week number of rule */
+ int r_mon; /* month number of rule */
+ long r_time; /* transition time of rule */
+};
+
+#define JULIAN_DAY 0 /* Jn - Julian day */
+#define DAY_OF_YEAR 1 /* n - day of year */
+#define MONTH_NTH_DAY_OF_WEEK 2 /* Mm.n.d - month, week, day of week */
+
+/*
+** Prototypes for static functions.
+*/
+
+static long detzcode __P_((const char *));
+static const char * getnum __P_((const char *, int *, int, int));
+static const char * getsecs __P_((const char *, long *));
+static const char * getoffset __P_((const char *, long *));
+static const char * getrule __P_((const char *, struct rule *));
+static const char * getzname __P_((const char *));
+static void gmtload __P_((struct state *));
+static void gmtsub __P_((const time_t *, long, struct tm *));
+static void localsub __P_((const time_t *, long, struct tm *));
+static void normalize __P_((int *, int *, int));
+static void settzname __P_((struct state *));
+static time_t time1 __P_((struct tm *, long));
+static time_t time2 __P_((struct tm *, long, int *));
+static void timesub __P_((const time_t *, long, const struct state *,
+ struct tm *));
+static int tmcomp __P_((const struct tm *, const struct tm *));
+static time_t transtime __P_((time_t, int, const struct rule *, long));
+static int tzload __P_((const char *, struct state *));
+static int tzparse __P_((const char *, struct state *, int));
+static void tzset_basic __P_((void));
+static void tzsetwall_basic __P_((void));
+
+static pthread_mutex_t lcl_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t gmt_mutex = PTHREAD_MUTEX_INITIALIZER;
+static int lcl_is_set = FALSE;
+static int gmt_is_set = FALSE;
+static struct state lclmem;
+static struct state gmtmem;
+
+#define lclptr (&lclmem)
+#define gmtptr (&gmtmem)
+
+char * tzname[2] = {
+ WILDABBR,
+ WILDABBR
+};
+
+#ifdef USG_COMPAT
+time_t timezone = 0;
+int daylight = 0;
+#endif /* defined USG_COMPAT */
+
+#ifdef ALTZONE
+time_t altzone = 0;
+#endif /* defined ALTZONE */
+
+static long detzcode(const char * codep)
+{
+ long result;
+ int i;
+
+ result = 0;
+ for (i = 0; i < 4; ++i)
+ result = (result << 8) | (codep[i] & 0xff);
+ return result;
+}
+
+static void settzname(struct state * sp)
+{
+ register int i;
+
+ tzname[0] = WILDABBR;
+ tzname[1] = WILDABBR;
+#ifdef USG_COMPAT
+ daylight = 0;
+ timezone = 0;
+#endif /* defined USG_COMPAT */
+#ifdef ALTZONE
+ altzone = 0;
+#endif /* defined ALTZONE */
+ for (i = 0; i < sp->typecnt; ++i) {
+ register const struct ttinfo * const ttisp = &sp->ttis[i];
+
+ tzname[ttisp->tt_isdst] =
+ (char *) &sp->chars[ttisp->tt_abbrind];
+#ifdef USG_COMPAT
+ if (ttisp->tt_isdst)
+ daylight = 1;
+ if (i == 0 || !ttisp->tt_isdst)
+ timezone = -(ttisp->tt_gmtoff);
+#endif /* defined USG_COMPAT */
+#ifdef ALTZONE
+ if (i == 0 || ttisp->tt_isdst)
+ altzone = -(ttisp->tt_gmtoff);
+#endif /* defined ALTZONE */
+ }
+ /*
+ ** And to get the latest zone names into tzname. . .
+ */
+ for (i = 0; i < sp->timecnt; ++i) {
+ register const struct ttinfo * const ttisp =
+ &sp->ttis[sp->types[i]];
+
+ tzname[ttisp->tt_isdst] =
+ (char *) &sp->chars[ttisp->tt_abbrind];
+ }
+}
+
+static int tzload(const char * name, struct state * sp)
+{
+ register const char * p;
+ register int i;
+ register int fid;
+
+ if (name == NULL && (name = TZDEFAULT) == NULL)
+ return -1;
+ {
+ char fullname[FILENAME_MAX + 1];
+
+ if (name[0] == ':')
+ ++name;
+ if (name[0] != '/') {
+ if ((p = TZDIR) == NULL)
+ return -1;
+ if ((strlen(p) + strlen(name) + 1) >= sizeof fullname)
+ return -1;
+ (void) strcpy(fullname, p);
+ (void) strcat(fullname, "/");
+ (void) strcat(fullname, name);
+ name = fullname;
+ }
+ if ((fid = open(name, O_RDONLY)) == -1)
+ return -1;
+ }
+ {
+ register const struct tzhead * tzhp;
+ char buf[sizeof *sp + sizeof *tzhp];
+ int ttisstdcnt;
+
+ i = read(fid, buf, sizeof buf);
+ if (close(fid) != 0 || i < sizeof *tzhp)
+ return -1;
+ tzhp = (struct tzhead *) buf;
+ ttisstdcnt = (int) detzcode(tzhp->tzh_ttisstdcnt);
+ sp->leapcnt = (int) detzcode(tzhp->tzh_leapcnt);
+ sp->timecnt = (int) detzcode(tzhp->tzh_timecnt);
+ sp->typecnt = (int) detzcode(tzhp->tzh_typecnt);
+ sp->charcnt = (int) detzcode(tzhp->tzh_charcnt);
+ if (sp->leapcnt < 0 || sp->leapcnt > TZ_MAX_LEAPS ||
+ sp->typecnt <= 0 || sp->typecnt > TZ_MAX_TYPES ||
+ sp->timecnt < 0 || sp->timecnt > TZ_MAX_TIMES ||
+ sp->charcnt < 0 || sp->charcnt > TZ_MAX_CHARS ||
+ (ttisstdcnt != sp->typecnt && ttisstdcnt != 0))
+ return -1;
+ if (i < sizeof *tzhp +
+ sp->timecnt * (4 + sizeof (char)) +
+ sp->typecnt * (4 + 2 * sizeof (char)) +
+ sp->charcnt * sizeof (char) +
+ sp->leapcnt * 2 * 4 +
+ ttisstdcnt * sizeof (char))
+ return -1;
+ p = buf + sizeof *tzhp;
+ for (i = 0; i < sp->timecnt; ++i) {
+ sp->ats[i] = detzcode(p);
+ p += 4;
+ }
+ for (i = 0; i < sp->timecnt; ++i) {
+ sp->types[i] = (unsigned char) *p++;
+ if (sp->types[i] >= sp->typecnt)
+ return -1;
+ }
+ for (i = 0; i < sp->typecnt; ++i) {
+ register struct ttinfo * ttisp;
+
+ ttisp = &sp->ttis[i];
+ ttisp->tt_gmtoff = detzcode(p);
+ p += 4;
+ ttisp->tt_isdst = (unsigned char) *p++;
+ if (ttisp->tt_isdst != 0 && ttisp->tt_isdst != 1)
+ return -1;
+ ttisp->tt_abbrind = (unsigned char) *p++;
+ if (ttisp->tt_abbrind < 0 ||
+ ttisp->tt_abbrind > sp->charcnt)
+ return -1;
+ }
+ for (i = 0; i < sp->charcnt; ++i)
+ sp->chars[i] = *p++;
+ sp->chars[i] = '\0'; /* ensure '\0' at end */
+ for (i = 0; i < sp->leapcnt; ++i) {
+ register struct lsinfo * lsisp;
+
+ lsisp = &sp->lsis[i];
+ lsisp->ls_trans = detzcode(p);
+ p += 4;
+ lsisp->ls_corr = detzcode(p);
+ p += 4;
+ }
+ for (i = 0; i < sp->typecnt; ++i) {
+ register struct ttinfo * ttisp;
+
+ ttisp = &sp->ttis[i];
+ if (ttisstdcnt == 0)
+ ttisp->tt_ttisstd = FALSE;
+ else {
+ ttisp->tt_ttisstd = *p++;
+ if (ttisp->tt_ttisstd != TRUE &&
+ ttisp->tt_ttisstd != FALSE)
+ return -1;
+ }
+ }
+ }
+ return 0;
+}
+
+static const int mon_lengths[2][MONSPERYEAR] = {
+ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31,
+ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
+};
+
+static const int year_lengths[2] = {
+ DAYSPERNYEAR, DAYSPERLYEAR
+};
+
+/*
+** Given a pointer into a time zone string, scan until a character that is not
+** a valid character in a zone name is found. Return a pointer to that
+** character.
+*/
+static const char * getzname(const char * strp)
+{
+ register char c;
+
+ while ((c = *strp) != '\0' && !isdigit(c) && c != ',' && c != '-' &&
+ c != '+')
+ ++strp;
+ return strp;
+}
+
+/*
+** Given a pointer into a time zone string, extract a number from that string.
+** Check that the number is within a specified range; if it is not, return
+** NULL.
+** Otherwise, return a pointer to the first character not part of the number.
+*/
+
+static const char *getnum(const char * strp, int * nump, int min, int max)
+{
+ char c;
+ int num;
+
+ if (strp == NULL || !isdigit(*strp))
+ return NULL;
+ num = 0;
+ while ((c = *strp) != '\0' && isdigit(c)) {
+ num = num * 10 + (c - '0');
+ if (num > max)
+ return NULL; /* illegal value */
+ ++strp;
+ }
+ if (num < min)
+ return NULL; /* illegal value */
+ *nump = num;
+ return strp;
+}
+
+/*
+** Given a pointer into a time zone string, extract a number of seconds,
+** in hh[:mm[:ss]] form, from the string.
+** If any error occurs, return NULL.
+** Otherwise, return a pointer to the first character not part of the number
+** of seconds.
+*/
+static const char * getsecs(const char * strp, long * secsp)
+{
+ int num;
+
+ strp = getnum(strp, &num, 0, HOURSPERDAY);
+ if (strp == NULL)
+ return NULL;
+ *secsp = num * SECSPERHOUR;
+ if (*strp == ':') {
+ ++strp;
+ strp = getnum(strp, &num, 0, MINSPERHOUR - 1);
+ if (strp == NULL)
+ return NULL;
+ *secsp += num * SECSPERMIN;
+ if (*strp == ':') {
+ ++strp;
+ strp = getnum(strp, &num, 0, SECSPERMIN - 1);
+ if (strp == NULL)
+ return NULL;
+ *secsp += num;
+ }
+ }
+ return strp;
+}
+
+/*
+** Given a pointer into a time zone string, extract an offset, in
+** [+-]hh[:mm[:ss]] form, from the string.
+** If any error occurs, return NULL.
+** Otherwise, return a pointer to the first character not part of the time.
+*/
+static const char * getoffset(const char * strp, long * offsetp)
+{
+ int neg;
+
+ if (*strp == '-') {
+ neg = 1;
+ ++strp;
+ } else if (isdigit(*strp) || *strp++ == '+')
+ neg = 0;
+ else return NULL; /* illegal offset */
+ strp = getsecs(strp, offsetp);
+ if (strp == NULL)
+ return NULL; /* illegal time */
+ if (neg)
+ *offsetp = -*offsetp;
+ return strp;
+}
+
+/*
+** Given a pointer into a time zone string, extract a rule in the form
+** date[/time]. See POSIX section 8 for the format of "date" and "time".
+** If a valid rule is not found, return NULL.
+** Otherwise, return a pointer to the first character not part of the rule.
+*/
+static const char * getrule(const char * strp, struct rule * rulep)
+{
+ if (*strp == 'J') {
+ /*
+ ** Julian day.
+ */
+ rulep->r_type = JULIAN_DAY;
+ ++strp;
+ strp = getnum(strp, &rulep->r_day, 1, DAYSPERNYEAR);
+ } else if (*strp == 'M') {
+ /*
+ ** Month, week, day.
+ */
+ rulep->r_type = MONTH_NTH_DAY_OF_WEEK;
+ ++strp;
+ strp = getnum(strp, &rulep->r_mon, 1, MONSPERYEAR);
+ if (strp == NULL)
+ return NULL;
+ if (*strp++ != '.')
+ return NULL;
+ strp = getnum(strp, &rulep->r_week, 1, 5);
+ if (strp == NULL)
+ return NULL;
+ if (*strp++ != '.')
+ return NULL;
+ strp = getnum(strp, &rulep->r_day, 0, DAYSPERWEEK - 1);
+ } else if (isdigit(*strp)) {
+ /*
+ ** Day of year.
+ */
+ rulep->r_type = DAY_OF_YEAR;
+ strp = getnum(strp, &rulep->r_day, 0, DAYSPERLYEAR - 1);
+ } else return NULL; /* invalid format */
+ if (strp == NULL)
+ return NULL;
+ if (*strp == '/') {
+ /*
+ ** Time specified.
+ */
+ ++strp;
+ strp = getsecs(strp, &rulep->r_time);
+ } else rulep->r_time = 2 * SECSPERHOUR; /* default = 2:00:00 */
+ return strp;
+}
+
+/*
+** Given the Epoch-relative time of January 1, 00:00:00 GMT, in a year, the
+** year, a rule, and the offset from GMT at the time that rule takes effect,
+** calculate the Epoch-relative time that rule takes effect.
+*/
+static time_t transtime(time_t janfirst, int year,
+ const struct rule * rulep, long offset)
+{
+ register int leapyear;
+ register time_t value;
+ register int i;
+ int d, m1, yy0, yy1, yy2, dow;
+
+ leapyear = isleap(year);
+ switch (rulep->r_type) {
+
+ case JULIAN_DAY:
+ /*
+ ** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap
+ ** years.
+ ** In non-leap years, or if the day number is 59 or less, just
+ ** add SECSPERDAY times the day number-1 to the time of
+ ** January 1, midnight, to get the day.
+ */
+ value = janfirst + (rulep->r_day - 1) * SECSPERDAY;
+ if (leapyear && rulep->r_day >= 60)
+ value += SECSPERDAY;
+ break;
+
+ case DAY_OF_YEAR:
+ /*
+ ** n - day of year.
+ ** Just add SECSPERDAY times the day number to the time of
+ ** January 1, midnight, to get the day.
+ */
+ value = janfirst + rulep->r_day * SECSPERDAY;
+ break;
+
+ case MONTH_NTH_DAY_OF_WEEK:
+ /*
+ ** Mm.n.d - nth "dth day" of month m.
+ */
+ value = janfirst;
+ for (i = 0; i < rulep->r_mon - 1; ++i)
+ value += mon_lengths[leapyear][i] * SECSPERDAY;
+
+ /*
+ ** Use Zeller's Congruence to get day-of-week of first day of
+ ** month.
+ */
+ m1 = (rulep->r_mon + 9) % 12 + 1;
+ yy0 = (rulep->r_mon <= 2) ? (year - 1) : year;
+ yy1 = yy0 / 100;
+ yy2 = yy0 % 100;
+ dow = ((26 * m1 - 2) / 10 +
+ 1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7;
+ if (dow < 0)
+ dow += DAYSPERWEEK;
+
+ /*
+ ** "dow" is the day-of-week of the first day of the month. Get
+ ** the day-of-month (zero-origin) of the first "dow" day of the
+ ** month.
+ */
+ d = rulep->r_day - dow;
+ if (d < 0)
+ d += DAYSPERWEEK;
+ for (i = 1; i < rulep->r_week; ++i) {
+ if (d + DAYSPERWEEK >=
+ mon_lengths[leapyear][rulep->r_mon - 1])
+ break;
+ d += DAYSPERWEEK;
+ }
+
+ /*
+ ** "d" is the day-of-month (zero-origin) of the day we want.
+ */
+ value += d * SECSPERDAY;
+ break;
+ }
+
+ /*
+ ** "value" is the Epoch-relative time of 00:00:00 GMT on the day in
+ ** question. To get the Epoch-relative time of the specified local
+ ** time on that day, add the transition time and the current offset
+ ** from GMT.
+ */
+ return value + rulep->r_time + offset;
+}
+
+/*
+** Given a POSIX section 8-style TZ string, fill in the rule tables as
+** appropriate.
+*/
+static int tzparse(const char * name, struct state * sp, int lastditch)
+{
+ const char * stdname;
+ const char * dstname;
+ int stdlen;
+ int dstlen;
+ long stdoffset;
+ long dstoffset;
+ register time_t * atp;
+ register unsigned char * typep;
+ register char * cp;
+ register int load_result;
+
+ stdname = name;
+ if (lastditch) {
+ stdlen = strlen(name); /* length of standard zone name */
+ name += stdlen;
+ if (stdlen >= sizeof sp->chars)
+ stdlen = (sizeof sp->chars) - 1;
+ } else {
+ name = getzname(name);
+ stdlen = name - stdname;
+ if (stdlen < 3)
+ return -1;
+ }
+ if (*name == '\0')
+ return -1;
+ else {
+ name = getoffset(name, &stdoffset);
+ if (name == NULL)
+ return -1;
+ }
+ load_result = tzload(TZDEFRULES, sp);
+ if (load_result != 0)
+ sp->leapcnt = 0; /* so, we're off a little */
+ if (*name != '\0') {
+ dstname = name;
+ name = getzname(name);
+ dstlen = name - dstname; /* length of DST zone name */
+ if (dstlen < 3)
+ return -1;
+ if (*name != '\0' && *name != ',' && *name != ';') {
+ name = getoffset(name, &dstoffset);
+ if (name == NULL)
+ return -1;
+ } else dstoffset = stdoffset - SECSPERHOUR;
+ if (*name == ',' || *name == ';') {
+ struct rule start;
+ struct rule end;
+ register int year;
+ register time_t janfirst;
+ time_t starttime;
+ time_t endtime;
+
+ ++name;
+ if ((name = getrule(name, &start)) == NULL)
+ return -1;
+ if (*name++ != ',')
+ return -1;
+ if ((name = getrule(name, &end)) == NULL)
+ return -1;
+ if (*name != '\0')
+ return -1;
+ sp->typecnt = 2; /* standard time and DST */
+ /*
+ ** Two transitions per year, from EPOCH_YEAR to 2037.
+ */
+ sp->timecnt = 2 * (2037 - EPOCH_YEAR + 1);
+ if (sp->timecnt > TZ_MAX_TIMES)
+ return -1;
+ sp->ttis[0].tt_gmtoff = -dstoffset;
+ sp->ttis[0].tt_isdst = 1;
+ sp->ttis[0].tt_abbrind = stdlen + 1;
+ sp->ttis[1].tt_gmtoff = -stdoffset;
+ sp->ttis[1].tt_isdst = 0;
+ sp->ttis[1].tt_abbrind = 0;
+ atp = sp->ats;
+ typep = sp->types;
+ janfirst = 0;
+ for (year = EPOCH_YEAR; year <= 2037; ++year) {
+ starttime = transtime(janfirst, year, &start,
+ stdoffset);
+ endtime = transtime(janfirst, year, &end,
+ dstoffset);
+ if (starttime > endtime) {
+ *atp++ = endtime;
+ *typep++ = 1; /* DST ends */
+ *atp++ = starttime;
+ *typep++ = 0; /* DST begins */
+ } else {
+ *atp++ = starttime;
+ *typep++ = 0; /* DST begins */
+ *atp++ = endtime;
+ *typep++ = 1; /* DST ends */
+ }
+ janfirst +=
+ year_lengths[isleap(year)] * SECSPERDAY;
+ }
+ } else {
+ int sawstd;
+ int sawdst;
+ long stdfix;
+ long dstfix;
+ long oldfix;
+ int isdst;
+ register int i;
+
+ if (*name != '\0')
+ return -1;
+ if (load_result != 0)
+ return -1;
+ /*
+ ** Compute the difference between the real and
+ ** prototype standard and summer time offsets
+ ** from GMT, and put the real standard and summer
+ ** time offsets into the rules in place of the
+ ** prototype offsets.
+ */
+ sawstd = FALSE;
+ sawdst = FALSE;
+ stdfix = 0;
+ dstfix = 0;
+ for (i = 0; i < sp->typecnt; ++i) {
+ if (sp->ttis[i].tt_isdst) {
+ oldfix = dstfix;
+ dstfix =
+ sp->ttis[i].tt_gmtoff + dstoffset;
+ if (sawdst && (oldfix != dstfix))
+ return -1;
+ sp->ttis[i].tt_gmtoff = -dstoffset;
+ sp->ttis[i].tt_abbrind = stdlen + 1;
+ sawdst = TRUE;
+ } else {
+ oldfix = stdfix;
+ stdfix =
+ sp->ttis[i].tt_gmtoff + stdoffset;
+ if (sawstd && (oldfix != stdfix))
+ return -1;
+ sp->ttis[i].tt_gmtoff = -stdoffset;
+ sp->ttis[i].tt_abbrind = 0;
+ sawstd = TRUE;
+ }
+ }
+ /*
+ ** Make sure we have both standard and summer time.
+ */
+ if (!sawdst || !sawstd)
+ return -1;
+ /*
+ ** Now correct the transition times by shifting
+ ** them by the difference between the real and
+ ** prototype offsets. Note that this difference
+ ** can be different in standard and summer time;
+ ** the prototype probably has a 1-hour difference
+ ** between standard and summer time, but a different
+ ** difference can be specified in TZ.
+ */
+ isdst = FALSE; /* we start in standard time */
+ for (i = 0; i < sp->timecnt; ++i) {
+ register const struct ttinfo * ttisp;
+
+ /*
+ ** If summer time is in effect, and the
+ ** transition time was not specified as
+ ** standard time, add the summer time
+ ** offset to the transition time;
+ ** otherwise, add the standard time offset
+ ** to the transition time.
+ */
+ ttisp = &sp->ttis[sp->types[i]];
+ sp->ats[i] +=
+ (isdst && !ttisp->tt_ttisstd) ?
+ dstfix : stdfix;
+ isdst = ttisp->tt_isdst;
+ }
+ }
+ } else {
+ dstlen = 0;
+ sp->typecnt = 1; /* only standard time */
+ sp->timecnt = 0;
+ sp->ttis[0].tt_gmtoff = -stdoffset;
+ sp->ttis[0].tt_isdst = 0;
+ sp->ttis[0].tt_abbrind = 0;
+ }
+ sp->charcnt = stdlen + 1;
+ if (dstlen != 0)
+ sp->charcnt += dstlen + 1;
+ if (sp->charcnt > sizeof sp->chars)
+ return -1;
+ cp = sp->chars;
+ (void) strncpy(cp, stdname, stdlen);
+ cp += stdlen;
+ *cp++ = '\0';
+ if (dstlen != 0) {
+ (void) strncpy(cp, dstname, dstlen);
+ *(cp + dstlen) = '\0';
+ }
+ return 0;
+}
+
+static void gmtload(struct state * sp)
+{
+ if (tzload(GMT, sp) != 0)
+ (void) tzparse(GMT, sp, TRUE);
+}
+
+static void tzset_basic()
+{
+ const char * name;
+ if ((name = getenv("TZ")) == NULL) {
+ tzsetwall_basic();
+ return;
+ }
+
+ if (*name == '\0') {
+ /*
+ ** User wants it fast rather than right.
+ */
+ lclptr->leapcnt = 0; /* so, we're off a little */
+ lclptr->timecnt = 0;
+ lclptr->ttis[0].tt_gmtoff = 0;
+ lclptr->ttis[0].tt_abbrind = 0;
+ (void) strcpy(lclptr->chars, GMT);
+ } else {
+ if (tzload(name, lclptr) != 0)
+ if (name[0] == ':' || tzparse(name, lclptr, FALSE) != 0)
+ (void) gmtload(lclptr);
+ }
+ lcl_is_set = TRUE;
+ settzname(lclptr);
+}
+
+void tzset()
+{
+ pthread_mutex_lock(&lcl_mutex);
+ tzset_basic();
+ pthread_mutex_unlock(&lcl_mutex);
+}
+
+static void tzsetwall_basic()
+{
+ if (tzload((char *) NULL, lclptr) != 0)
+ gmtload(lclptr);
+ settzname(lclptr);
+ lcl_is_set = TRUE;
+}
+
+void tzsetwall()
+{
+ pthread_mutex_lock(&lcl_mutex);
+ tzsetwall_basic();
+ pthread_mutex_unlock(&lcl_mutex);
+}
+
+/*
+** The easy way to behave "as if no library function calls" localtime
+** is to not call it--so we drop its guts into "localsub", which can be
+** freely called. (And no, the PANS doesn't require the above behavior--
+** but it *is* desirable.)
+**
+** The unused offset argument is for the benefit of mktime variants.
+*/
+
+static void localsub(const time_t * timep, long offset, struct tm * tmp)
+{
+ const struct ttinfo * ttisp;
+ const time_t t = *timep;
+ struct state * sp;
+ int i;
+
+ if (!lcl_is_set)
+ tzset_basic();
+ sp = lclptr;
+ if (sp->timecnt == 0 || t < sp->ats[0]) {
+ i = 0;
+ while (sp->ttis[i].tt_isdst)
+ if (++i >= sp->typecnt) {
+ i = 0;
+ break;
+ }
+ } else {
+ for (i = 1; i < sp->timecnt; ++i)
+ if (t < sp->ats[i])
+ break;
+ i = sp->types[i - 1];
+ }
+ ttisp = &sp->ttis[i];
+ /*
+ ** To get (wrong) behavior that's compatible with System V Release 2.0
+ ** you'd replace the statement below with
+ ** t += ttisp->tt_gmtoff;
+ ** timesub(&t, 0L, sp, tmp);
+ */
+ timesub(&t, ttisp->tt_gmtoff, sp, tmp);
+ tzname[tmp->tm_isdst] = (char *) &sp->chars[ttisp->tt_abbrind];
+#ifdef BSD_TM
+ tmp->tm_zone = &sp->chars[ttisp->tt_abbrind];
+#endif
+ tmp->tm_isdst = ttisp->tt_isdst;
+
+ pthread_mutex_unlock(&lcl_mutex);
+}
+
+struct tm * localtime_r(const time_t * timep, struct tm * tm)
+{
+ pthread_mutex_lock(&lcl_mutex);
+ localsub(timep, 0L, tm);
+ pthread_mutex_unlock(&lcl_mutex);
+ return(tm);
+}
+
+struct tm * localtime(const time_t * timep)
+{
+ static pthread_mutex_t localtime_mutex = PTHREAD_MUTEX_INITIALIZER;
+ static pthread_key_t localtime_key = -1;
+ struct tm * tm;
+
+ pthread_mutex_lock(&localtime_mutex);
+ if (localtime_key < 0) {
+ if (pthread_key_create(&localtime_key, free) < 0) {
+ pthread_mutex_unlock(&localtime_mutex);
+ return(NULL);
+ }
+ }
+ pthread_mutex_unlock(&localtime_mutex);
+ if ((tm = pthread_getspecific(localtime_key)) == NULL) {
+ if ((tm = (struct tm *)malloc(sizeof(struct tm))) == NULL) {
+ return(NULL);
+ }
+ pthread_setspecific(localtime_key, tm);
+ }
+
+ pthread_mutex_lock(&lcl_mutex);
+ localsub(timep, 0L, tm);
+ pthread_mutex_unlock(&lcl_mutex);
+ return tm;
+}
+
+
+/*
+ * gmtsub is to gmtime as localsub is to localtime.
+ *
+ * Once set there is no need to lock the gmt_mutex to view gmtptr
+ */
+static void gmtsub(const time_t * timep, long offset, struct tm * tmp)
+{
+ pthread_mutex_lock(&gmt_mutex);
+ if (gmt_is_set == FALSE) {
+ gmt_is_set = TRUE;
+ gmtload(gmtptr);
+ }
+ pthread_mutex_unlock(&gmt_mutex);
+
+ timesub(timep, offset, gmtptr, tmp);
+ /*
+ ** Could get fancy here and deliver something such as
+ ** "GMT+xxxx" or "GMT-xxxx" if offset is non-zero,
+ ** but this is no time for a treasure hunt.
+ */
+#ifdef BSD_TM
+ if (offset != 0) {
+ tmp->tm_zone = WILDABBR;
+ } else {
+ tmp->tm_zone = gmtptr->chars;
+ }
+#endif
+}
+
+struct tm * gmtime_r(const time_t * timep, struct tm * tm)
+{
+ gmtsub(timep, 0L, tm);
+ return(tm);
+}
+
+struct tm * gmtime(const time_t * timep)
+{
+ static pthread_mutex_t gmtime_mutex = PTHREAD_MUTEX_INITIALIZER;
+ static pthread_key_t gmtime_key = -1;
+ struct tm * tm;
+
+ pthread_mutex_lock(&gmtime_mutex);
+ if (gmtime_key < 0) {
+ if (pthread_key_create(&gmtime_key, free) < 0) {
+ pthread_mutex_unlock(&gmtime_mutex);
+ return(NULL);
+ }
+ }
+ pthread_mutex_unlock(&gmtime_mutex);
+ if ((tm = pthread_getspecific(gmtime_key)) == NULL) {
+ if ((tm = (struct tm *)malloc(sizeof(struct tm))) == NULL) {
+ return(NULL);
+ }
+ pthread_setspecific(gmtime_key, tm);
+ }
+
+ gmtsub(timep, 0L, tm);
+ return(tm);
+}
+
+static void timesub(const time_t * timep, long offset,
+ const struct state * sp, struct tm * tmp)
+{
+ register const struct lsinfo * lp;
+ register long days;
+ register long rem;
+ register int y;
+ register int yleap;
+ register const int * ip;
+ register long corr;
+ register int hit;
+ register int i;
+
+ corr = 0;
+ hit = FALSE;
+ i = sp->leapcnt;
+ while (--i >= 0) {
+ lp = &sp->lsis[i];
+ if (*timep >= lp->ls_trans) {
+ if (*timep == lp->ls_trans)
+ hit = ((i == 0 && lp->ls_corr > 0) ||
+ lp->ls_corr > sp->lsis[i - 1].ls_corr);
+ corr = lp->ls_corr;
+ break;
+ }
+ }
+ days = *timep / SECSPERDAY;
+ rem = *timep % SECSPERDAY;
+#ifdef mc68k
+ if (*timep == 0x80000000) {
+ /*
+ ** A 3B1 muffs the division on the most negative number.
+ */
+ days = -24855;
+ rem = -11648;
+ }
+#endif /* mc68k */
+ rem += (offset - corr);
+ while (rem < 0) {
+ rem += SECSPERDAY;
+ --days;
+ }
+ while (rem >= SECSPERDAY) {
+ rem -= SECSPERDAY;
+ ++days;
+ }
+ tmp->tm_hour = (int) (rem / SECSPERHOUR);
+ rem = rem % SECSPERHOUR;
+ tmp->tm_min = (int) (rem / SECSPERMIN);
+ tmp->tm_sec = (int) (rem % SECSPERMIN);
+ if (hit)
+ /*
+ ** A positive leap second requires a special
+ ** representation. This uses "... ??:59:60".
+ */
+ ++(tmp->tm_sec);
+ tmp->tm_wday = (int) ((EPOCH_WDAY + days) % DAYSPERWEEK);
+ if (tmp->tm_wday < 0)
+ tmp->tm_wday += DAYSPERWEEK;
+ y = EPOCH_YEAR;
+ if (days >= 0)
+ for ( ; ; ) {
+ yleap = isleap(y);
+ if (days < (long) year_lengths[yleap])
+ break;
+ ++y;
+ days = days - (long) year_lengths[yleap];
+ }
+ else do {
+ --y;
+ yleap = isleap(y);
+ days = days + (long) year_lengths[yleap];
+ } while (days < 0);
+ tmp->tm_year = y - TM_YEAR_BASE;
+ tmp->tm_yday = (int) days;
+ ip = mon_lengths[yleap];
+ for (tmp->tm_mon = 0; days >= (long) ip[tmp->tm_mon]; ++(tmp->tm_mon))
+ days = days - (long) ip[tmp->tm_mon];
+ tmp->tm_mday = (int) (days + 1);
+ tmp->tm_isdst = 0;
+#ifdef BSD_TM
+ tmp->tm_gmtoff = offset;
+#endif
+}
+
+/*
+ * A la X3J11
+ *
+ * Made thread safe by using thread specific data
+ */
+char * asctime_r(const struct tm * timeptr, char * result)
+{
+ static const char wday_name[DAYSPERWEEK][3] = {
+ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
+ };
+ static const char mon_name[MONSPERYEAR][3] = {
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+ };
+ (void) sprintf(result, "%.3s %.3s%3d %02.2d:%02.2d:%02.2d %d\n",
+ wday_name[timeptr->tm_wday],
+ mon_name[timeptr->tm_mon],
+ timeptr->tm_mday, timeptr->tm_hour,
+ timeptr->tm_min, timeptr->tm_sec,
+ TM_YEAR_BASE + timeptr->tm_year);
+ return(result);
+}
+
+char * asctime(const struct tm * timeptr)
+{
+ static pthread_mutex_t asctime_mutex = PTHREAD_MUTEX_INITIALIZER;
+ static pthread_key_t asctime_key = -1;
+ char * result;
+
+ pthread_mutex_lock(&asctime_mutex);
+ if (asctime_key < 0) {
+ if (pthread_key_create(&asctime_key, free) < 0) {
+ pthread_mutex_unlock(&asctime_mutex);
+ return(NULL);
+ }
+ }
+ pthread_mutex_unlock(&asctime_mutex);
+ if ((result = pthread_getspecific(asctime_key)) == NULL) {
+ if ((result = malloc(26)) == NULL) {
+ return(NULL);
+ }
+ pthread_setspecific(asctime_key, result);
+ }
+
+ return(asctime_r(timeptr, result));
+}
+
+char * ctime_r(const time_t * timep, char * buf)
+{
+ struct tm tm;
+ return asctime_r(localtime_r(timep, &tm), buf);
+}
+
+char * ctime(const time_t * timep)
+{
+ struct tm tm;
+ return asctime(localtime_r(timep, &tm));
+}
+
+/*
+** Adapted from code provided by Robert Elz, who writes:
+** The "best" way to do mktime I think is based on an idea of Bob
+** Kridle's (so its said...) from a long time ago. (mtxinu!kridle now).
+** It does a binary search of the time_t space. Since time_t's are
+** just 32 bits, its a max of 32 iterations (even at 64 bits it
+** would still be very reasonable).
+*/
+static void normalize(int * tensptr,int * unitsptr, int base)
+{
+ if (*unitsptr >= base) {
+ *tensptr += *unitsptr / base;
+ *unitsptr %= base;
+ } else if (*unitsptr < 0) {
+ --*tensptr;
+ *unitsptr += base;
+ if (*unitsptr < 0) {
+ *tensptr -= 1 + (-*unitsptr) / base;
+ *unitsptr = base - (-*unitsptr) % base;
+ }
+ }
+}
+
+static int tmcomp(const struct tm * atmp, const struct tm * btmp)
+{
+ register int result;
+
+ if ((result = (atmp->tm_year - btmp->tm_year)) == 0 &&
+ (result = (atmp->tm_mon - btmp->tm_mon)) == 0 &&
+ (result = (atmp->tm_mday - btmp->tm_mday)) == 0 &&
+ (result = (atmp->tm_hour - btmp->tm_hour)) == 0 &&
+ (result = (atmp->tm_min - btmp->tm_min)) == 0)
+ result = atmp->tm_sec - btmp->tm_sec;
+ return result;
+}
+
+static time_t time2(struct tm * tmp, long offset, int * okayp)
+{
+ register const struct state * sp;
+ register int dir;
+ register int bits;
+ register int i, j ;
+ register int saved_seconds;
+ time_t newt;
+ time_t t;
+ struct tm yourtm, mytm;
+
+ *okayp = FALSE;
+ yourtm = *tmp;
+ if (yourtm.tm_sec >= SECSPERMIN + 2 || yourtm.tm_sec < 0)
+ normalize(&yourtm.tm_min, &yourtm.tm_sec, SECSPERMIN);
+ normalize(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR);
+ normalize(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY);
+ normalize(&yourtm.tm_year, &yourtm.tm_mon, MONSPERYEAR);
+ while (yourtm.tm_mday <= 0) {
+ --yourtm.tm_year;
+ yourtm.tm_mday +=
+ year_lengths[isleap(yourtm.tm_year + TM_YEAR_BASE)];
+ }
+ for ( ; ; ) {
+ i = mon_lengths[isleap(yourtm.tm_year +
+ TM_YEAR_BASE)][yourtm.tm_mon];
+ if (yourtm.tm_mday <= i)
+ break;
+ yourtm.tm_mday -= i;
+ if (++yourtm.tm_mon >= MONSPERYEAR) {
+ yourtm.tm_mon = 0;
+ ++yourtm.tm_year;
+ }
+ }
+ saved_seconds = yourtm.tm_sec;
+ yourtm.tm_sec = 0;
+ /*
+ ** Calculate the number of magnitude bits in a time_t
+ ** (this works regardless of whether time_t is
+ ** signed or unsigned, though lint complains if unsigned).
+ */
+ for (bits = 0, t = 1; t > 0; ++bits, t <<= 1)
+ ;
+ /*
+ ** If time_t is signed, then 0 is the median value,
+ ** if time_t is unsigned, then 1 << bits is median.
+ */
+ t = (t < 0) ? 0 : ((time_t) 1 << bits);
+ for ( ; ; ) {
+ localsub(&t, offset, &mytm);
+ dir = tmcomp(&mytm, &yourtm);
+ if (dir != 0) {
+ if (bits-- < 0)
+ return NOTOK;
+ if (bits < 0)
+ --t;
+ else if (dir > 0)
+ t -= (time_t) 1 << bits;
+ else t += (time_t) 1 << bits;
+ continue;
+ }
+ if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst)
+ break;
+ /*
+ ** Right time, wrong type.
+ ** Hunt for right time, right type.
+ ** It's okay to guess wrong since the guess
+ ** gets checked.
+ */
+ sp = lclptr;
+ for (i = 0; i < sp->typecnt; ++i) {
+ if (sp->ttis[i].tt_isdst != yourtm.tm_isdst)
+ continue;
+ for (j = 0; j < sp->typecnt; ++j) {
+ if (sp->ttis[j].tt_isdst == yourtm.tm_isdst)
+ continue;
+ newt = t + sp->ttis[j].tt_gmtoff -
+ sp->ttis[i].tt_gmtoff;
+ localsub(&newt, offset, &mytm);
+ if (tmcomp(&mytm, &yourtm) != 0)
+ continue;
+ if (mytm.tm_isdst != yourtm.tm_isdst)
+ continue;
+ /*
+ ** We have a match.
+ */
+ t = newt;
+ goto label;
+ }
+ }
+ return NOTOK;
+ }
+label:
+ t += saved_seconds;
+ localsub(&t, offset, tmp);
+ *okayp = TRUE;
+ return t;
+}
+
+static time_t time1(struct tm * tmp, long offset)
+{
+ const struct state * sp;
+ int samei, otheri, okay;
+ time_t t;
+
+ if (tmp->tm_isdst > 1)
+ tmp->tm_isdst = 1;
+ t = time2(tmp, offset, &okay);
+ if (okay || tmp->tm_isdst < 0)
+ return t;
+ /*
+ ** We're supposed to assume that somebody took a time of one type
+ ** and did some math on it that yielded a "struct tm" that's bad.
+ ** We try to divine the type they started from and adjust to the
+ ** type they need.
+ */
+ sp = lclptr;
+ for (samei = 0; samei < sp->typecnt; ++samei) {
+ if (sp->ttis[samei].tt_isdst != tmp->tm_isdst)
+ continue;
+ for (otheri = 0; otheri < sp->typecnt; ++otheri) {
+ if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst)
+ continue;
+ tmp->tm_sec += sp->ttis[otheri].tt_gmtoff -
+ sp->ttis[samei].tt_gmtoff;
+ tmp->tm_isdst = !tmp->tm_isdst;
+ t = time2(tmp, offset, &okay);
+ if (okay)
+ return t;
+ tmp->tm_sec -= sp->ttis[otheri].tt_gmtoff -
+ sp->ttis[samei].tt_gmtoff;
+ tmp->tm_isdst = !tmp->tm_isdst;
+ }
+ }
+ return NOTOK;
+}
+
+time_t mktime(struct tm * tmp)
+{
+ time_t mktime_return_value;
+
+ pthread_mutex_lock(&lcl_mutex);
+ if (lcl_is_set == FALSE) {
+ tzset_basic();
+ }
+ mktime_return_value = time1(tmp, 0L);
+ pthread_mutex_unlock(&lcl_mutex);
+ return(mktime_return_value);
+}
diff --git a/mit-pthreads/gen/difftime.c b/mit-pthreads/gen/difftime.c
new file mode 100644
index 00000000000..cddd896e04a
--- /dev/null
+++ b/mit-pthreads/gen/difftime.c
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)difftime.c 5.2 (Berkeley) 6/1/90";
+#endif /* LIBC_SCCS and not lint */
+
+#include <pthread.h>
+#include <sys/types.h>
+
+double
+difftime(time1, time0)
+ time_t time1, time0;
+{
+ return(time1 - time0);
+}
diff --git a/mit-pthreads/gen/directory.c b/mit-pthreads/gen/directory.c
new file mode 100644
index 00000000000..d189280fc1f
--- /dev/null
+++ b/mit-pthreads/gen/directory.c
@@ -0,0 +1,322 @@
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)closedir.c 5.9 (Berkeley) 2/23/91";
+#endif /* LIBC_SCCS and not lint */
+
+/*
+ * One of these structures is malloced to describe the current directory
+ * position each time telldir is called. It records the current magic
+ * cookie returned by getdirentries and the offset within the buffer
+ * associated with that return value.
+ */
+struct ddloc {
+ struct ddloc *loc_next;/* next structure in list */
+ long loc_index; /* key associated with structure */
+ long loc_seek; /* magic cookie returned by getdirentries */
+ long loc_loc; /* offset of entry in buffer */
+};
+
+static long dd_loccnt = 0; /* Index of entry for sequential telldir's */
+
+#include <errno.h>
+#include <pthread.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <dirent.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+
+
+/*
+ * close a directory.
+ */
+int closedir(DIR * dirp)
+{
+ void *ptr, *nextptr;
+ int fd;
+
+ pthread_mutex_lock (dirp->dd_lock);
+ fd = dirp->dd_fd;
+ dirp->dd_fd = -1;
+ dirp->dd_loc = 0;
+ for (ptr = (void *)dirp->dd_ddloc; ptr; ptr = nextptr) {
+ nextptr = (void *)(((struct ddloc *)ptr)->loc_next);
+ free(ptr);
+ }
+ for (ptr = (void *)dirp->dd_dp; ptr; ptr = nextptr) {
+ nextptr = (void *)(((struct __dirent *)ptr)->next);
+ free(ptr);
+ }
+ free((void *)dirp->dd_buf);
+ free (dirp->dd_lock);
+ free((void *)dirp);
+ return(machdep_sys_close(fd));
+}
+
+/*
+ * open a directory.
+ */
+DIR * opendir(const char * name)
+{
+ DIR *dirp;
+ int fd;
+
+ if ((fd = machdep_sys_open(name, 0)) < 0)
+ return NULL;
+ if (machdep_sys_fcntl(fd, F_SETFD, 1) < 0 ||
+ (dirp = (DIR *)malloc(sizeof(DIR))) == NULL) {
+ machdep_sys_close (fd);
+ return NULL;
+ }
+ dirp->dd_lock = (pthread_mutex_t*) malloc (sizeof (pthread_mutex_t));
+ pthread_mutex_init (dirp->dd_lock, 0);
+ /*
+ * If CLSIZE is an exact multiple of DIRBLKSIZ, use a CLSIZE
+ * buffer that it cluster boundary aligned.
+ * Hopefully this can be a big win someday by allowing page trades
+ * to user space to be done by getdirentries()
+ */
+#ifndef CLSIZE
+#define CLSIZE 1
+#endif
+ if ((CLSIZE % DIRBLKSIZ) == 0) {
+ dirp->dd_buf = malloc(CLSIZE);
+ dirp->dd_len = CLSIZE;
+ } else {
+ dirp->dd_buf = malloc(DIRBLKSIZ);
+ dirp->dd_len = DIRBLKSIZ;
+ }
+ if (dirp->dd_buf == NULL) {
+ machdep_sys_close (fd);
+ free((void *)dirp);
+ return NULL;
+ }
+
+ dirp->dd_ddloc = NULL;
+ dirp->dd_dp = NULL;
+ dirp->dd_seek = 0;
+ dirp->dd_loc = 0;
+ dirp->dd_fd = fd;
+ return(dirp);
+}
+
+/*
+ * The real work in gettint the next entry in a directory.
+ * Return
+ * NULL on End of directory
+ * &ERR on Error
+ * dp on valid directory;
+ */
+static struct dirent ERR;
+static struct dirent * readdir_basic(DIR * dirp)
+{
+ register struct dirent *dp;
+
+ for (;;) {
+ if (dirp->dd_loc == 0) {
+ dirp->dd_size = machdep_sys_getdirentries(dirp->dd_fd,
+ dirp->dd_buf, dirp->dd_len, &dirp->dd_seek);
+ if (dirp->dd_size < 0)
+ return(&ERR);
+ if (dirp->dd_size == 0)
+ return(NULL);
+ }
+ if (dirp->dd_loc >= dirp->dd_size) {
+ dirp->dd_loc = 0;
+ continue;
+ }
+ dp = (struct dirent *)(dirp->dd_buf + dirp->dd_loc);
+ if ((long)dp & 03) /* bogus pointer check */
+ return(&ERR);
+ if (dp->d_reclen <= 0 ||
+ dp->d_reclen > dirp->dd_len + 1 - dirp->dd_loc)
+ return(&ERR);
+ dirp->dd_loc += dp->d_reclen;
+ if (dp->d_ino == 0)
+ continue;
+ return(dp);
+ }
+}
+
+/*
+ * POSIX.1 version of getting the next entry in a directory.
+ */
+struct dirent * readdir(DIR * dirp)
+{
+ register struct dirent * rp;
+ struct __dirent * my__dp;
+ pthread_t self;
+
+ pthread_mutex_lock (dirp->dd_lock);
+
+ self = pthread_self();
+ /* Allocate space and return */
+ for (my__dp = dirp->dd_dp; my__dp; my__dp = my__dp->next) {
+ if (pthread_equal(my__dp->owner, self)) {
+ break;
+ }
+ }
+ if (my__dp == NULL) {
+ if (my__dp = (struct __dirent *)(malloc(sizeof(struct __dirent)))) {
+ my__dp->next = dirp->dd_dp;
+ dirp->dd_dp = my__dp;
+ my__dp->owner = self;
+ } else {
+ pthread_mutex_unlock (dirp->dd_lock);
+ return(NULL);
+ }
+ }
+ if (rp = readdir_basic(dirp)) {
+ if (rp != &ERR) {
+ memcpy(& (my__dp->data), rp, sizeof(struct dirent));
+ rp = & (my__dp->data);
+ } else {
+ rp = NULL;
+ }
+ }
+ pthread_mutex_unlock (dirp->dd_lock);
+ return(rp);
+}
+
+/*
+ * POSIX.4a version of getting the next entry in a directory.
+ */
+int readdir_r(DIR * dirp, struct dirent * entry, struct dirent ** result)
+{
+ register struct dirent * rp;
+ int ret;
+
+ pthread_mutex_lock (dirp->dd_lock);
+ rp = readdir_basic(dirp);
+ if (rp != &ERR) {
+ if (rp) {
+ memcpy(entry, rp, sizeof(struct dirent));
+ *result = entry;
+ ret = 0;
+ } else {
+ *result = NULL;
+ ret = 0;
+ }
+ } else {
+ /* Should get it from errno */
+ ret = EBADF;
+ }
+ pthread_mutex_unlock (dirp->dd_lock);
+ return(ret);
+}
+
+void rewinddir(DIR * dirp)
+{
+ pthread_mutex_lock (dirp->dd_lock);
+ (void)machdep_sys_lseek(dirp->dd_fd, 0, 0);
+ dirp->dd_seek = 0;
+ dirp->dd_loc = 0;
+ pthread_mutex_unlock (dirp->dd_lock);
+}
+
+/*
+ * Seek to an entry in a directory.
+ * _seekdir is in telldir.c so that it can share opaque data structures.
+ *
+ * Use the POSIX reentrant safe readdir_r to simplify varifying POSIX
+ * thread-safe compliance.
+ */
+void seekdir(DIR * dirp, long loc)
+{
+ register struct ddloc ** prevlp;
+ register struct ddloc * lp;
+ struct dirent * dp;
+ struct dirent de;
+
+ pthread_mutex_lock (dirp->dd_lock);
+ prevlp = (struct ddloc **)&(dirp->dd_ddloc);
+ lp = *prevlp;
+ while (lp != NULL) {
+ if (lp->loc_index == loc)
+ break;
+ prevlp = &lp->loc_next;
+ lp = lp->loc_next;
+ }
+ if (lp) {
+ if (lp->loc_seek != dirp->dd_seek) {
+ if (machdep_sys_lseek(dirp->dd_fd, lp->loc_seek, 0) < 0) {
+ *prevlp = lp->loc_next;
+ pthread_mutex_unlock (dirp->dd_lock);
+ return;
+ }
+ dirp->dd_seek = lp->loc_seek;
+ dirp->dd_loc = 0;
+ while (dirp->dd_loc < lp->loc_loc) {
+ if (readdir_r(dirp, &de, &dp)) {
+ *prevlp = lp->loc_next;
+ break;
+ }
+ }
+ }
+ }
+ pthread_mutex_unlock (dirp->dd_lock);
+}
+
+/*
+ * return a pointer into a directory
+ */
+long telldir(DIR *dirp)
+{
+ struct ddloc *lp, **fakeout;
+ int ret;
+
+ pthread_mutex_lock (dirp->dd_lock);
+ if (lp = (struct ddloc *)malloc(sizeof(struct ddloc))) {
+ lp->loc_index = dd_loccnt++;
+ lp->loc_seek = dirp->dd_seek;
+ lp->loc_loc = dirp->dd_loc;
+ lp->loc_next = dirp->dd_ddloc;
+
+ /* Compiler won't let us change anything pointed to by db directly */
+ /* So we fake to the left and do it anyway */
+ /* Wonder if the compile optomizes it to the correct solution */
+ fakeout = (struct ddloc **)&(dirp->dd_ddloc);
+ *fakeout = lp;
+
+ ret = lp->loc_index;
+ } else {
+ ret = -1;
+ }
+ pthread_mutex_unlock (dirp->dd_lock);
+ return(ret);
+}
+
diff --git a/mit-pthreads/gen/eprintf.c b/mit-pthreads/gen/eprintf.c
new file mode 100644
index 00000000000..bcc65757bd4
--- /dev/null
+++ b/mit-pthreads/gen/eprintf.c
@@ -0,0 +1,18 @@
+/* This function is a replacement for the version in libgcc.a. This
+ is needed because typically libgcc.a won't have been compiled
+ against the threads library, so its references to "stderr" will
+ come out wrong. */
+
+#include <stdio.h>
+
+void __eprintf (const char *fmt, const char *expr, int line, const char *file)
+{
+ /* Considering the very special circumstances where this function
+ would be called, perhaps we might want to disable the thread
+ scheduler and break any existing locks on stderr? Well, maybe if
+ we could be sure that stderr was in a useable state... */
+ fprintf (stderr, fmt, expr, line, file);
+ fflush (stderr);
+
+ abort ();
+}
diff --git a/mit-pthreads/gen/getcwd.c b/mit-pthreads/gen/getcwd.c
new file mode 100644
index 00000000000..9c1b089f26e
--- /dev/null
+++ b/mit-pthreads/gen/getcwd.c
@@ -0,0 +1,248 @@
+/*
+ * Copyright (c) 1989, 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)getcwd.c 5.11 (Berkeley) 2/24/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <pthread.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <dirent.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define ISDOT(dp) \
+ (dp->d_name[0] == '.' && (dp->d_name[1] == '\0' || \
+ dp->d_name[1] == '.' && dp->d_name[2] == '\0'))
+
+
+/* Only use reentrant safe routines to simplify varifying POSIX thread-safe
+ * compliance. (mevans).
+ */
+
+char *
+getcwd(pt, size)
+ char *pt;
+ size_t size;
+{
+ register DIR *dir;
+ register dev_t dev;
+ register ino_t ino;
+ register int first;
+ register char *bpt, *bup;
+ struct stat s;
+ struct dirent *dp;
+ struct dirent de;
+ dev_t root_dev;
+ ino_t root_ino;
+ size_t ptsize, upsize;
+ int save_errno;
+ char *ept, *eup, *up;
+ int namelen;
+
+ /*
+ * If no buffer specified by the user, allocate one as necessary.
+ * If a buffer is specified, the size has to be non-zero. The path
+ * is built from the end of the buffer backwards.
+ */
+ if (pt) {
+ ptsize = 0;
+ if (!size) {
+ errno = EINVAL;
+ return((char *)NULL);
+ }
+ ept = pt + size;
+ } else {
+ if (!(pt = (char *)malloc(ptsize = 1024 - 4)))
+ return((char *)NULL);
+ ept = pt + ptsize;
+ }
+ bpt = ept - 1;
+ *bpt = '\0';
+
+ /*
+ * Allocate bytes (1024 - malloc space) for the string of "../"'s.
+ * Should always be enough (it's 340 levels). If it's not, allocate
+ * as necessary. Special * case the first stat, it's ".", not "..".
+ */
+ if (!(up = (char *)malloc(upsize = 1024 - 4)))
+ goto err;
+ eup = up + MAXPATHLEN;
+ bup = up;
+ up[0] = '.';
+ up[1] = '\0';
+
+ /* Save root values, so know when to stop. */
+ if (stat("/", &s))
+ goto err;
+ root_dev = s.st_dev;
+ root_ino = s.st_ino;
+
+ SET_ERRNO(0);
+
+ for (first = 1;; first = 0) {
+ /* Stat the current level. */
+ if (lstat(up, &s))
+ goto err;
+
+ /* Save current node values. */
+ ino = s.st_ino;
+ dev = s.st_dev;
+
+ /* Check for reaching root. */
+ if (root_dev == dev && root_ino == ino) {
+ *--bpt = '/';
+ /*
+ * It's unclear that it's a requirement to copy the
+ * path to the beginning of the buffer, but it's always
+ * been that way and stuff would probably break.
+ */
+ /* XXX was bcopy */
+ (void)memcpy(pt, bpt, ept - bpt);
+ free(up);
+ return(pt);
+ }
+
+ /*
+ * Build pointer to the parent directory, allocating memory
+ * as necessary. Max length is 3 for "../", the largest
+ * possible component name, plus a trailing NULL.
+ */
+ if (bup + 3 + MAXNAMLEN + 1 >= eup) {
+ if (!(up = (char *)realloc(up, upsize *= 2)))
+ goto err;
+ eup = up + upsize;
+ }
+ *bup++ = '.';
+ *bup++ = '.';
+ *bup = '\0';
+
+ /* Open and stat parent directory. */
+ /* XXX opendir() returns kernel fd's instead of
+ pthread fd's for some odd reason, so we must
+ break the abstraction boundry here as well or
+ fix everything in opendir et al. SNL */
+ if (!(dir = opendir(up)) ||
+ machdep_sys_fstat(dirfd(dir), &s))
+ goto err;
+
+ /* Add trailing slash for next directory. */
+ *bup++ = '/';
+
+ /*
+ * If it's a mount point, have to stat each element because
+ * the inode number in the directory is for the entry in the
+ * parent directory, not the inode number of the mounted file.
+ */
+ save_errno = 0;
+ if (s.st_dev == dev) {
+ for (;;) {
+ if (readdir_r(dir, &de, &dp))
+ goto notfound;
+ if (dp->d_fileno == ino)
+ break;
+ }
+ } else
+ for (;;) {
+ if (readdir_r(dir, &de, &dp))
+ goto notfound;
+ if (ISDOT(dp))
+ continue;
+ memcpy(bup, dp->d_name, strlen(dp->d_name) + 1);
+
+ /* Save the first error for later. */
+ if (lstat(up, &s)) {
+ if (!save_errno)
+ save_errno = errno;
+ SET_ERRNO(0);
+ continue;
+ }
+ if (s.st_dev == dev && s.st_ino == ino)
+ break;
+ }
+
+ /*
+ * Check for length of the current name, preceding slash,
+ * leading slash.
+ */
+ namelen = strlen(dp->d_name);
+ if (bpt - pt <= namelen + (first ? 1 : 2)) {
+ size_t len, off;
+
+ if (!ptsize) {
+ SET_ERRNO(ERANGE);
+ goto err;
+ }
+ off = bpt - pt;
+ len = ept - bpt;
+ if (!(pt = (char *)realloc(pt, ptsize *= 2)))
+ goto err;
+ bpt = pt + off;
+ ept = pt + ptsize;
+ /* XXX was bcopy */
+ (void)memcpy(ept - len, bpt, len);
+ bpt = ept - len;
+ }
+ if (!first)
+ *--bpt = '/';
+ bpt -= namelen;
+ memcpy(bpt, dp->d_name, namelen);
+ (void)closedir(dir);
+
+ /* Truncate any file name. */
+ *bup = '\0';
+ }
+
+notfound:
+ /*
+ * If readdir set errno, use it, not any saved error; otherwise,
+ * didn't find the current directory in its parent directory, set
+ * errno to ENOENT.
+ */
+ if (!errno) {
+ if (!save_errno)
+ save_errno = ENOENT;
+ SET_ERRNO(save_errno);
+ }
+ /* FALLTHROUGH */
+err:
+ if (ptsize)
+ free(pt);
+ free(up);
+ return((char *)NULL);
+}
diff --git a/mit-pthreads/gen/getpwent.c b/mit-pthreads/gen/getpwent.c
new file mode 100644
index 00000000000..7bcb2cbd610
--- /dev/null
+++ b/mit-pthreads/gen/getpwent.c
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 1984 Regents of the University of California.
+ * All rights reserved. The Berkeley software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)getpwent.c 5.2 (Berkeley) 3/9/86";
+#endif
+
+#include <pthread.h>
+#include <stdio.h>
+#include <pwd.h>
+#include "pwd_internal.h"
+
+void
+setpwent()
+{
+ pwf_context_t *_data;
+
+ _data = _pw_get_data();
+
+ if (_data) {
+ if (_data->pwf == NULL)
+ _data->pwf = fopen(_data->pw_file, "r");
+ else
+ rewind(_data->pwf);
+ }
+}
+
+void
+endpwent()
+{
+ pwf_context_t *_data;
+
+ _data = _pw_get_data();
+
+ if (_data) {
+ if (_data->pwf != NULL) {
+ fclose(_data->pwf);
+ _data->pwf = NULL;
+ }
+#ifdef DBM_PWD_SUPPORT
+ if (_data->pw_db != (DBM *)0) {
+ dbm_close(_data->pw_db);
+ _data->pw_db = (DBM *)0;
+ _data->pw_stayopen = 0;
+ }
+#endif /* DBM_PWD_SUPPORT */
+ }
+}
+
+static char *
+pwskip(p)
+ char *p;
+{
+ while (*p && *p != ':' && *p != '\n')
+ ++p;
+ if (*p)
+ *p++ = 0;
+ return(p);
+}
+
+struct passwd *
+getpwent()
+{
+ pwf_context_t *_data;
+ char *p;
+
+ _data = _pw_get_data();
+ if (!_data)
+ return 0;
+
+ if (_data->pwf == NULL) {
+ if ((_data->pwf = fopen(_data->pw_file, "r" )) == NULL)
+ return(0);
+ }
+ p = fgets(_data->line, BUFSIZ, _data->pwf);
+ if (p == NULL)
+ return(0);
+ _data->passwd.pw_name = p;
+ p = pwskip(p);
+ _data->passwd.pw_passwd = p;
+ p = pwskip(p);
+ _data->passwd.pw_uid = atoi(p);
+ p = pwskip(p);
+ _data->passwd.pw_gid = atoi(p);
+ p = pwskip(p);
+ _data->passwd.pw_gecos = p;
+ p = pwskip(p);
+ _data->passwd.pw_dir = p;
+ p = pwskip(p);
+ _data->passwd.pw_shell = p;
+ while (*p && *p != '\n')
+ p++;
+ *p = '\0';
+ return(&_data->passwd);
+}
+
+void
+setpwfile(file)
+ char *file;
+{
+ pwf_context_t *_data;
+
+ _data = _pw_get_data();
+ if (_data)
+ _data->pw_file = file;
+}
diff --git a/mit-pthreads/gen/getpwnamuid.c b/mit-pthreads/gen/getpwnamuid.c
new file mode 100644
index 00000000000..0e87081b7a9
--- /dev/null
+++ b/mit-pthreads/gen/getpwnamuid.c
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved. The Berkeley software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)getpwnamuid.c 5.3 (Berkeley) 12/21/87";
+#endif
+
+#include <stdio.h>
+#include <pwd.h>
+#include <sys/file.h>
+#include "pwd_internal.h"
+
+/*
+ * The following are shared with getpwent.c
+ */
+
+#ifdef DBM_PWD_SUPPORT
+static struct passwd *
+fetchpw(key)
+ datum key;
+{
+ char *cp, *tp;
+ pwf_context_t *_data;
+
+ _data = _pw_get_data();
+ if (!_data)
+ return 0;
+ if (key.dptr == 0)
+ return ((struct passwd *)NULL);
+ key = dbm_fetch(_data->pw_db, key);
+ if (key.dptr == 0)
+ return ((struct passwd *)NULL);
+ cp = key.dptr;
+ tp = _data->line;
+
+#define EXPAND(e) _data->passwd.e = tp; while (*tp++ = *cp++);
+ EXPAND(pw_name);
+ EXPAND(pw_passwd);
+ memcpy((char *)&_data->passwd.pw_uid, cp, sizeof (int));
+ cp += sizeof (int);
+ memcpy((char *)&_data->passwd.pw_gid, cp, sizeof (int));
+ cp += sizeof (int);
+ EXPAND(pw_gecos);
+ EXPAND(pw_dir);
+ EXPAND(pw_shell);
+ return (&_data->passwd);
+}
+#endif /* DBM_PWD_SUPPORT */
+
+struct passwd *
+getpwnam(nam)
+ const char *nam;
+{
+#ifdef DBM_PWD_SUPPORT
+ datum key;
+#endif
+ struct passwd *pw, *getpwent();
+ pwf_context_t *_data;
+
+ _data = _pw_get_data();
+ if (!_data)
+ return 0;
+
+#ifdef DBM_PWD_SUPPORT
+ if (_data->pw_db == (DBM *)0 &&
+ (_data->pw_db = dbm_open(_data->pw_file, O_RDONLY)) == (DBM *)0) {
+ oldcode:
+#endif
+ setpwent();
+ while ((pw = getpwent()) && strcmp(nam, pw->pw_name))
+ ;
+ if (!_data->pw_stayopen)
+ endpwent();
+ return (pw);
+#ifdef DBM_PWD_SUPPORT
+ }
+ if (flock(dbm_dirfno(_data->pw_db), LOCK_SH) < 0) {
+ dbm_close(_data->pw_db);
+ _data->pw_db = (DBM *)0;
+ goto oldcode;
+ }
+ key.dptr = nam;
+ key.dsize = strlen(nam);
+ pw = fetchpw(key);
+ (void) flock(dbm_dirfno(_data->pw_db), LOCK_UN);
+ if (!_data->pw_stayopen) {
+ dbm_close(_data->pw_db);
+ _data->pw_db = (DBM *)0;
+ }
+ return (pw);
+#endif
+}
+
+struct passwd *
+getpwuid(uid)
+ uid_t uid;
+{
+#ifdef DBM_PWD_SUPPORT
+ datum key;
+#endif
+ struct passwd *pw, *getpwent();
+ pwf_context_t *_data;
+
+ _data = _pw_get_data();
+ if (!_data)
+ return 0;
+#ifdef DBM_PWD_SUPPORT
+ if (_data->pw_db == (DBM *)0 &&
+ (_data->pw_db = dbm_open(_data->pw_file, O_RDONLY)) == (DBM *)0) {
+ oldcode:
+#endif
+ setpwent();
+ while ((pw = getpwent()) && pw->pw_uid != uid)
+ ;
+ if (!_data->pw_stayopen)
+ endpwent();
+ return (pw);
+#ifdef DBM_PWD_SUPPORT
+ }
+ if (flock(dbm_dirfno(_data->pw_db), LOCK_SH) < 0) {
+ dbm_close(_data->pw_db);
+ _data->pw_db = (DBM *)0;
+ goto oldcode;
+ }
+ key.dptr = (char *) &uid;
+ key.dsize = sizeof uid;
+ pw = fetchpw(key);
+ (void) flock(dbm_dirfno(_data->pw_db), LOCK_UN);
+ if (!_data->pw_stayopen) {
+ dbm_close(_data->pw_db);
+ _data->pw_db = (DBM *)0;
+ }
+ return (pw);
+#endif
+}
diff --git a/mit-pthreads/gen/getwd.c b/mit-pthreads/gen/getwd.c
new file mode 100644
index 00000000000..7fdceda0f45
--- /dev/null
+++ b/mit-pthreads/gen/getwd.c
@@ -0,0 +1,57 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)getwd.c 5.1 (Berkeley) 2/20/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <pthread.h>
+#include <sys/param.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+char *
+getwd(buf)
+ char *buf;
+{
+ char *p;
+ char *strerror();
+
+ if (p = getcwd(buf, MAXPATHLEN))
+ return(p);
+ (void)strcpy(buf, strerror(errno));
+ return((char *)NULL);
+}
diff --git a/mit-pthreads/gen/isatty.c b/mit-pthreads/gen/isatty.c
new file mode 100644
index 00000000000..a22f13015d9
--- /dev/null
+++ b/mit-pthreads/gen/isatty.c
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 1988 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)isatty.c 5.6 (Berkeley) 2/23/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <pthread.h>
+#ifdef sunos4
+#include <sys/termio.h>
+#else
+#include <termios.h>
+#endif
+#include <unistd.h>
+
+/*
+ * If TIOCGETA is not defined try TCGETATTR
+ * If TCGETATTR is not defined try TCGETA
+ * If that doesn't work try getting it from termio.h
+ */
+#ifndef TIOCGETA
+#ifdef TCGETATTR
+#define TIOCGETA TCGETATTR
+#else
+#ifndef TCGETA
+#include <termio.h>
+#endif
+#ifndef TIOCGETA
+#define TIOCGETA TCGETA
+#endif
+#endif
+#endif
+
+/* fd is the real fd to pass to the kernel */
+int isatty_basic(int fd)
+{
+#ifdef sunos4
+ struct termio t;
+#else /* !sunos4 */
+ struct termios t;
+#endif /* sunos4 */
+ return (machdep_sys_ioctl(fd,
+#ifdef sunos4
+ TCGETA,
+#else /* !sunos4 */
+ TIOCGETA,
+#endif /* sunos4 */
+ &t) ? 0 : 1);
+}
+
+int isatty(int fd)
+{
+ int ret;
+
+ if ((ret = fd_lock(fd, FD_READ, NULL)) == OK) {
+ ret = isatty_basic(fd_table[fd]->fd.i);
+ fd_unlock(fd, FD_READ);
+ } else {
+ /* Return 0 or 1 */
+ ret = 0;
+ }
+ return(ret);
+}
+
diff --git a/mit-pthreads/gen/popen.c b/mit-pthreads/gen/popen.c
new file mode 100644
index 00000000000..c15fbdce1fe
--- /dev/null
+++ b/mit-pthreads/gen/popen.c
@@ -0,0 +1,117 @@
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+static pid_t *pids = NULL;
+static int pids_size = 0;
+static int pids_top = 0;
+static pthread_mutex_t pids_lock = PTHREAD_MUTEX_INITIALIZER;
+
+FILE *popen(const char *cmd, const char *mode)
+{
+ int fds[2], parent_fd, child_fd, child_target, new_size, i;
+ pid_t pid, *new_pids;
+
+ /* Verify the mode. */
+ if ((*mode != 'r' && *mode != 'w') || mode[1] != 0)
+ return NULL;
+
+ /* Generate fds, and choose the parent and child fds. */
+ if (pipe(fds) < 0)
+ return NULL;
+ parent_fd = (*mode == 'r') ? fds[0] : fds[1];
+ child_fd = (*mode == 'r') ? fds[1] : fds[0];
+
+ /* Ensure that there is space in the pid table. */
+ pthread_mutex_lock(&pids_lock);
+ if (pids_size <= parent_fd) {
+ new_size = parent_fd + 1;
+ if ((new_pids = malloc(new_size * sizeof(pid_t))) == NULL) {
+ pthread_mutex_unlock(&pids_lock);
+ close(parent_fd);
+ close(child_fd);
+ return NULL;
+ }
+ if (pids) {
+ memcpy(new_pids, pids, pids_size * sizeof(pid_t));
+ free(pids);
+ }
+ while (pids_size < new_size)
+ new_pids[pids_size++] = -1;
+ pids = new_pids;
+ }
+ pthread_mutex_unlock(&pids_lock);
+
+ /* Fork off a child process. */
+ switch (pid = fork()) {
+ case -1: /* Failed to fork. */
+ close(parent_fd);
+ close(child_fd);
+ return NULL;
+ break;
+ case 0: /* Child */
+ /*
+ * Set the child fd to stdout or stdin as appropriate,
+ * and close the parent fd.
+ */
+ child_target = (*mode == 'r') ? STDOUT_FILENO : STDIN_FILENO;
+ if (child_fd != child_target) {
+ dup2(child_fd, child_target);
+ close(child_fd);
+ }
+ close(parent_fd);
+
+ /* Close all parent fds from previous popens(). */
+ for (i = 0; i < pids_top; i++) {
+ if (pids[i] != -1)
+ close(i);
+ }
+
+ execl("/bin/sh", "sh", "-c", cmd, NULL);
+ exit(1);
+ default:
+ break;
+ }
+
+ /* Record the parent fd in the pids table. */
+ pthread_mutex_lock(&pids_lock);
+ pids[parent_fd] = pid;
+ if (pids_top < parent_fd + 1)
+ pids_top = parent_fd + 1;
+ pthread_mutex_unlock(&pids_lock);
+
+ /* Close the child fd and return a stdio buffer for the parent fd. */
+ close(child_fd);
+ return fdopen(parent_fd, mode);
+}
+
+int pclose(fp)
+ FILE *fp;
+{
+ pid_t pid, result;
+ int fd, pstat;
+
+ fd = fileno(fp);
+ pthread_mutex_lock(&pids_lock);
+ /* Make sure this is a popened file. */
+ if ((pids_top <= fd) || ((pid = pids[fd]) == -1)) {
+ pthread_mutex_unlock(&pids_lock);
+ return -1;
+ }
+ pids[fd] = -1;
+ while (pids_top > 0 && pids[pids_top - 1] == -1)
+ pids_top--;
+ pthread_mutex_unlock(&pids_lock);
+
+ fclose(fp);
+
+ /* Wait for the subprocess to quit. */
+ return (((result = waitpid(pid, &pstat, 0)) == -1) ? -1 : pstat);
+}
+
diff --git a/mit-pthreads/gen/pwd_internal.c b/mit-pthreads/gen/pwd_internal.c
new file mode 100644
index 00000000000..b0ebc27b5c6
--- /dev/null
+++ b/mit-pthreads/gen/pwd_internal.c
@@ -0,0 +1,97 @@
+/* ==== pwd_internal.c ============================================================
+ * Copyright (c) 1993, 1994 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Description : Thread-safe password hacking functions.
+ *
+ * 1.00 95/02/08 snl
+ * -Started coding this file.
+ */
+
+#include <pthread.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <pwd.h>
+#include <unistd.h>
+#include "pwd_internal.h"
+
+static pthread_once_t __pw_init = PTHREAD_ONCE_INIT;
+static pthread_key_t __pw_key;
+
+void
+_pw_null_cleanup(void *junkola)
+{
+ pwf_context_t *x = (pwf_context_t *)junkola;
+
+ if (x) {
+ if (x->pwf) {
+ fclose(x->pwf);
+ x->pwf = 0;
+ }
+#ifdef DBM_PWD_SUPPORT
+ if (x->pw_db) {
+ dbm_close(x->pw_db);
+ x->pw_db = 0;
+ }
+#endif /* DBM_PWD_SUPPORT */
+ free((void *)x);
+ }
+}
+
+void
+_pw_create_key()
+{
+ if (pthread_key_create(&__pw_key, _pw_null_cleanup)) {
+ PANIC();
+ }
+}
+
+pwf_context_t *
+_pw_get_data()
+{
+ pwf_context_t *_data;
+
+ pthread_once(&__pw_init, _pw_create_key);
+ _data = (pwf_context_t *)pthread_getspecific(__pw_key);
+ if (!_data) {
+ _data = (pwf_context_t *)malloc(sizeof(pwf_context_t));
+ if (_data) {
+ _data->pwf = 0;
+ _data->line[0] = '\0';
+ _data->pw_stayopen = 0;
+ _data->pw_file = "/etc/passwd";
+#ifdef DBM_PWD_SUPPORT
+ _data->pw_db = 0;
+#endif /* DBM_PWD_SUPPORT */
+ pthread_setspecific(__pw_key, (void *)_data);
+ }
+ }
+ return _data;
+}
diff --git a/mit-pthreads/gen/pwd_internal.h b/mit-pthreads/gen/pwd_internal.h
new file mode 100644
index 00000000000..10fdab6cc4e
--- /dev/null
+++ b/mit-pthreads/gen/pwd_internal.h
@@ -0,0 +1,29 @@
+#ifndef _PWD_INTERNAL_H_
+#define _PWD_INTERNAL_H_
+
+#if 0 /* Turn this off for now until we suck in ndbm or use gdbm -- SNL */
+#ifndef DBM_PWD_SUPPORT
+#if !defined(__alpha) && !defined(linux) && !defined(hpux)
+#define DBM_PWD_SUPPORT 1
+#endif /* !alpha && !linux && !hpux */
+#endif /* !DBM_PWD_SUPPORT */
+#endif
+
+#ifdef DBM_PWD_SUPPORT
+#include <ndbm.h>
+#endif /* DBM_PWD_SUPPORT */
+
+typedef struct pwf_context {
+ FILE *pwf;
+ char line[BUFSIZ+1];
+ struct passwd passwd;
+ int pw_stayopen;
+ char *pw_file;
+#ifdef DBM_PWD_SUPPORT
+ DBM *pw_db;
+#endif /* DBM_PWD_SUPPORT */
+} pwf_context_t;
+
+pwf_context_t *_pw_get_data __P_((void));
+
+#endif /* _PWD_INTERNAL_H_ */
diff --git a/mit-pthreads/gen/syslog.c b/mit-pthreads/gen/syslog.c
new file mode 100644
index 00000000000..e49795ecb69
--- /dev/null
+++ b/mit-pthreads/gen/syslog.c
@@ -0,0 +1,216 @@
+/*
+ * Copyright (c) 1983, 1988 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of California at Berkeley. The name of the University
+ * may not be used to endorse or promote products derived from this
+ * software without specific prior written permission. This software
+ * is provided ``as is'' without express or implied warranty.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)syslog.c 5.14 (Berkeley) 5/20/88";
+#endif /* LIBC_SCCS and not lint */
+
+
+/*
+ * SYSLOG -- print message on log file
+ *
+ * This routine looks a lot like printf, except that it
+ * outputs to the log file instead of the standard output.
+ * Also:
+ * adds a timestamp,
+ * prints the module name in front of the message,
+ * has some other formatting types (or will sometime),
+ * adds a newline on the end of the message.
+ *
+ * The output of this routine is intended to be read by /etc/syslogd.
+ *
+ * Author: Eric Allman
+ * Modified to use UNIX domain IPC by Ralph Campbell
+ * Modified for pthreads and made more POSIX-compliant by Greg Hudson
+ */
+
+#include <pthread.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <fcntl.h>
+#include <netdb.h>
+#include <unistd.h>
+#include <errno.h>
+#include <syslog.h>
+
+int socket();
+char *strerror(int); /* For systems that don't prototype it */
+
+#define MAXLINE 1024 /* max message size */
+
+#define PRIFAC(p) (((p) & LOG_FACMASK) >> 3)
+ /* XXX should be in <syslog.h> */
+#define IMPORTANT LOG_ERR
+
+static void basic_init(void);
+
+static char _log_name[] = "/dev/log";
+static char ctty[] = "/dev/console";
+
+static int LogFile = -1; /* fd for log */
+static int LogStat = 0; /* status bits, set by openlog() */
+static char *LogTag = "syslog"; /* string to tag the entry with */
+static int LogMask = 0xff; /* mask of priorities to be logged */
+static int LogFacility = LOG_USER; /* default facility code */
+
+static pthread_mutex_t basic_init_lock = PTHREAD_MUTEX_INITIALIZER;
+
+static struct sockaddr SyslogAddr; /* AF_UNIX address of local logger */
+
+static void basic_init()
+{
+ pthread_mutex_lock(&basic_init_lock);
+ if (LogFile < 0)
+ openlog(LogTag, LogStat | LOG_NDELAY, 0);
+ pthread_mutex_unlock(&basic_init_lock);
+}
+
+void syslog(int pri, char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ vsyslog(pri, fmt, args);
+ va_end(args);
+}
+
+void vsyslog(int pri, char *fmt, va_list args)
+{
+ char buf[MAXLINE + 1], outline[MAXLINE + 1];
+ register char *b, *f, *o;
+ register int c;
+ time_t now;
+ int olderrno = errno, fd;
+
+ /* Do a basic initialization if user didn't call openlog(). */
+ if (LogFile < 0)
+ basic_init();
+
+ /* see if we should just throw out this message */
+ if ((unsigned) PRIFAC(pri) >= LOG_NFACILITIES ||
+ (LOG_MASK(pri & LOG_PRIMASK) & LogMask) == 0 ||
+ (pri &~ (LOG_PRIMASK|LOG_FACMASK)) != 0)
+ return;
+
+ /* set default facility if none specified */
+ if ((pri & LOG_FACMASK) == 0)
+ pri |= LogFacility;
+
+ /* build the message */
+ o = outline;
+ (void)sprintf(o, "<%d>", pri);
+ o += strlen(o);
+ time(&now);
+ (void)sprintf(o, "%.15s ", ctime(&now) + 4);
+ o += strlen(o);
+ if (LogTag) {
+ strcpy(o, LogTag);
+ o += strlen(o);
+ }
+ if (LogStat & LOG_PID) {
+ (void)sprintf(o, "[%d]", getpid());
+ o += strlen(o);
+ }
+ if (LogTag) {
+ strcpy(o, ": ");
+ o += 2;
+ }
+
+ b = buf;
+ f = fmt;
+ while ((c = *f++) != '\0' && c != '\n' && b < &buf[MAXLINE]) {
+ char *strerror();
+
+ if (c != '%') {
+ *b++ = c;
+ continue;
+ }
+ if ((c = *f++) != 'm') {
+ *b++ = '%';
+ *b++ = c;
+ continue;
+ }
+ strcpy(b, strerror(olderrno));
+ b += strlen(b);
+ }
+ *b++ = '\n';
+ *b = '\0';
+ vsprintf(o, buf, args);
+ c = strlen(outline);
+ if (c > MAXLINE)
+ c = MAXLINE;
+
+ /* output the message to the local logger */
+ if (sendto(LogFile, outline, c, 0, &SyslogAddr, sizeof SyslogAddr) >= 0)
+ return;
+ if (!(LogStat & LOG_CONS))
+ return;
+
+ /* output the message to the console */
+ fd = open(ctty, O_WRONLY);
+ alarm(0);
+ strcat(o, "\r");
+ o = strchr(outline, '>') + 1;
+ write(fd, o, c + 1 - (o - outline));
+ close(fd);
+}
+
+/*
+ * OPENLOG -- open system log
+ */
+
+void openlog(char *ident, int logstat, int logfac)
+{
+ int flags;
+
+ if (ident != NULL)
+ LogTag = ident;
+ LogStat = logstat;
+ if (logfac != 0 && (logfac &~ LOG_FACMASK) == 0)
+ LogFacility = logfac;
+ if (LogFile >= 0)
+ return;
+ SyslogAddr.sa_family = AF_UNIX;
+ strncpy(SyslogAddr.sa_data, _log_name, sizeof SyslogAddr.sa_data);
+ if (LogStat & LOG_NDELAY) {
+ LogFile = socket(AF_UNIX, SOCK_DGRAM, 0);
+ flags = fcntl(LogFile, F_GETFD);
+ fcntl(LogFile, F_SETFD, flags & O_NONBLOCK);
+ }
+}
+
+/*
+ * CLOSELOG -- close the system log
+ */
+
+void closelog()
+{
+ (void) close(LogFile);
+ LogFile = -1;
+}
+
+/*
+ * SETLOGMASK -- set the log mask level
+ */
+int setlogmask(int pmask)
+{
+ int omask;
+
+ omask = LogMask;
+ if (pmask != 0)
+ LogMask = pmask;
+ return (omask);
+}
diff --git a/mit-pthreads/gen/time.c b/mit-pthreads/gen/time.c
new file mode 100644
index 00000000000..82eec7edc1e
--- /dev/null
+++ b/mit-pthreads/gen/time.c
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)time.c 5.6 (Berkeley) 6/1/90";
+#endif /* LIBC_SCCS and not lint */
+
+#include <pthread.h>
+#include <sys/types.h>
+#include <sys/time.h>
+
+time_t time(time_t * t)
+{
+ struct timeval tt;
+
+ if (gettimeofday(&tt, (struct timezone *)0) < 0)
+ return(-1);
+ if (t)
+ *t = tt.tv_sec;
+ return(tt.tv_sec);
+}
diff --git a/mit-pthreads/gen/ttyname.c b/mit-pthreads/gen/ttyname.c
new file mode 100644
index 00000000000..b7a04485f79
--- /dev/null
+++ b/mit-pthreads/gen/ttyname.c
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 1988 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)ttyname.c 5.10 (Berkeley) 5/6/91";
+#endif /* LIBC_SCCS and not lint */
+
+#include "config.h"
+#include <pthread.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+
+static pthread_mutex_t ttyname_lock = PTHREAD_MUTEX_INITIALIZER;
+static pthread_key_t ttyname_key;
+static int ttyname_init = 0;
+extern void free();
+
+char * __ttyname_r_basic(int fd, char * buf, size_t len)
+{
+ register struct dirent *dirp;
+ register DIR *dp;
+ struct stat dsb;
+ struct stat sb;
+ char * rval;
+ int minlen;
+
+ rval = NULL;
+
+ /* Must be a terminal. */
+ if (! isatty_basic(fd))
+ return(rval);
+ /* Must be a character device. */
+ if (machdep_sys_fstat(fd, &sb) || !S_ISCHR(sb.st_mode))
+ return(rval);
+ /* Must have enough room */
+ if (len <= sizeof(_PATH_PTY))
+ return(rval);
+
+ if ((dp = opendir(_PATH_PTY)) != NULL) {
+ memcpy(buf, _PATH_PTY, sizeof(_PATH_PTY));
+ for (rval = NULL; dirp = readdir(dp);) {
+ if (dirp->d_fileno != sb.st_ino)
+ continue;
+ minlen = (len - (sizeof(_PATH_PTY) - 1)) < (dirp->d_namlen + 1) ?
+ (len - (sizeof(_PATH_PTY) - 1)) : (dirp->d_namlen + 1);
+ memcpy (buf + sizeof(_PATH_PTY) - 1, dirp->d_name, minlen);
+ if (stat(buf, &dsb) || sb.st_dev != dsb.st_dev ||
+ sb.st_ino != dsb.st_ino)
+ continue;
+ rval = buf;
+ break;
+ }
+ (void)closedir(dp);
+ }
+ return(rval);
+}
+
+char * __ttyname_basic(int fd)
+{
+ char *buf;
+
+ pthread_mutex_lock (&ttyname_lock);
+ if (ttyname_init == 0) {
+ if (pthread_key_create(&ttyname_key, free)) {
+ pthread_mutex_unlock (&ttyname_lock);
+ return(NULL);
+ }
+ ttyname_init = 1;
+ }
+ pthread_mutex_unlock (&ttyname_lock);
+
+ /* Must have thread specific data field to put data */
+ if ((buf = pthread_getspecific(ttyname_key)) == NULL) {
+ if (buf = malloc(sizeof(_PATH_PTY) + MAXNAMLEN)) {
+ if (pthread_setspecific(ttyname_key, buf) != OK) {
+ free(buf);
+ return(NULL);
+ }
+ } else {
+ return(NULL);
+ }
+ }
+ return(__ttyname_r_basic(fd, buf, sizeof(_PATH_PTY) + MAXNAMLEN));
+}
+
+char * ttyname_r(int fd, char * buf, size_t len)
+{
+ char * ret;
+
+ if (fd_lock(fd, FD_READ) == OK) {
+ ret = __ttyname_r_basic(fd_table[fd]->fd.i, buf, len);
+ fd_unlock(fd, FD_READ);
+ } else {
+ ret = NULL;
+ }
+ return(ret);
+}
+
+char * ttyname(int fd)
+{
+ char * ret;
+
+ if (fd_lock(fd, FD_READ) == OK) {
+ ret = __ttyname_basic(fd_table[fd]->fd.i);
+ fd_unlock(fd, FD_READ);
+ } else {
+ ret = NULL;
+ }
+ return(ret);
+}
+
+
diff --git a/mit-pthreads/include/Makefile.inc b/mit-pthreads/include/Makefile.inc
new file mode 100644
index 00000000000..b7fe59d5f0d
--- /dev/null
+++ b/mit-pthreads/include/Makefile.inc
@@ -0,0 +1,30 @@
+# from: @(#)Makefile 5.45.1.1 (Berkeley) 5/6/91
+
+# Doing a make install builds /usr/include/pthread
+#
+# The ``rm -rf''s used below are safe because rm doesn't follow symbolic
+# links.
+
+
+FILES= cond.h copyright.h fd.h fd_pipe.h kernel.h mutex.h posix.h \
+ pthread.h pthread_attr.h queue.h util.h
+
+# Machine dependent header file
+MFILE= ${.CURDIR}/arch/${MACHINE}/machdep.h
+
+realinstall:
+ if [ ! -d ${DESTDIR}/usr/include/pthread ]; then \
+ mkdir ${DESTDIR}/usr/include/pthread; \
+ fi
+ @echo installing ${FILES}
+ @-for i in ${FILES}; do \
+ cmp -s $$i ${DESTDIR}/usr/include/pthread/$$i || \
+ install -c -m 644 $$i ${DESTDIR}/usr/include/$$i; \
+ done
+ cmp -s ${MFILE} ${DESTDIR}/usr/include/pthread/machdep.h || \
+ install -c -m 644 ${MFILE} ${DESTDIR}/usr/include/pthread/machdep.h
+ rm -rf ${DESTDIR}/usr/include/pthread.h
+ ln -s /usr/include/pthread/pthread.h ${DESTDIR}/usr/include/pthread.h
+ @chown -R ${BINOWN}:${BINGRP} ${DESTDIR}/usr/include/pthread
+ @chmod -R a-w ${DESTDIR}/usr/include/pthread
+
diff --git a/mit-pthreads/include/arpa/inet.h b/mit-pthreads/include/arpa/inet.h
new file mode 100755
index 00000000000..d6ad76f4eb5
--- /dev/null
+++ b/mit-pthreads/include/arpa/inet.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)inet.h 5.7 (Berkeley) 4/3/91
+ * $Id$
+ */
+
+#ifndef _INET_H_
+#define _INET_H_
+
+/* External definitions for functions in inet(3) */
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+#include <pthread/types.h>
+
+__BEGIN_DECLS
+
+pthread_ipaddr_type inet_addr __P_((const char *));
+int inet_aton __P_((const char *, struct in_addr *));
+pthread_ipaddr_type inet_lnaof __P_((struct in_addr));
+struct in_addr inet_makeaddr __P_((pthread_ipaddr_type,
+ pthread_ipaddr_type));
+pthread_ipaddr_type inet_netof __P_((struct in_addr));
+pthread_ipaddr_type inet_network __P_((const char *));
+char * inet_ntoa __P_((struct in_addr));
+char * inet_ntoa_r __P_((struct in_addr in, char *buf,
+ int bufsize));
+
+__END_DECLS
+
+#endif /* !_INET_H_ */
diff --git a/mit-pthreads/include/arpa/nameser.h b/mit-pthreads/include/arpa/nameser.h
new file mode 100755
index 00000000000..350d67538bd
--- /dev/null
+++ b/mit-pthreads/include/arpa/nameser.h
@@ -0,0 +1,279 @@
+/*
+ * Copyright (c) 1983, 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)nameser.h 8.2 (Berkeley) 2/16/94
+ * -
+ * Portions Copyright (c) 1993 by Digital Equipment Corporation.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies, and that
+ * the name of Digital Equipment Corporation not be used in advertising or
+ * publicity pertaining to distribution of the document or software without
+ * specific, written prior permission.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
+ * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ * -
+ * --Copyright--
+ */
+
+#ifndef _NAMESER_H_
+#define _NAMESER_H_
+
+#include <endian.h>
+#include <sys/types.h>
+#include <pthread/types.h>
+
+/*
+ * Define constants based on rfc883
+ */
+#define PACKETSZ 512 /* maximum packet size */
+#define MAXDNAME 256 /* maximum domain name */
+#define MAXCDNAME 255 /* maximum compressed domain name */
+#define MAXLABEL 63 /* maximum length of domain label */
+ /* Number of bytes of fixed size data in query structure */
+#define QFIXEDSZ 4
+ /* number of bytes of fixed size data in resource record */
+#define RRFIXEDSZ 10
+
+/*
+ * Internet nameserver port number
+ */
+#define NAMESERVER_PORT 53
+
+/*
+ * Currently defined opcodes
+ */
+#define QUERY 0x0 /* standard query */
+#define IQUERY 0x1 /* inverse query */
+#define STATUS 0x2 /* nameserver status query */
+/*#define xxx 0x3*/ /* 0x3 reserved */
+ /* non standard - supports ALLOW_UPDATES stuff from Mike Schwartz */
+#define UPDATEA 0x9 /* add resource record */
+#define UPDATED 0xa /* delete a specific resource record */
+#define UPDATEDA 0xb /* delete all named resource record */
+#define UPDATEM 0xc /* modify a specific resource record */
+#define UPDATEMA 0xd /* modify all named resource record */
+
+#define ZONEINIT 0xe /* initial zone transfer */
+#define ZONEREF 0xf /* incremental zone referesh */
+
+/*
+ * Currently defined response codes
+ */
+#define NOERROR 0 /* no error */
+#define FORMERR 1 /* format error */
+#define SERVFAIL 2 /* server failure */
+#define NXDOMAIN 3 /* non existent domain */
+#define NOTIMP 4 /* not implemented */
+#define REFUSED 5 /* query refused */
+ /* non standard */
+#define NOCHANGE 0xf /* update failed to change db */
+
+/*
+ * Type values for resources and queries
+ */
+#define T_A 1 /* host address */
+#define T_NS 2 /* authoritative server */
+#define T_MD 3 /* mail destination */
+#define T_MF 4 /* mail forwarder */
+#define T_CNAME 5 /* connonical name */
+#define T_SOA 6 /* start of authority zone */
+#define T_MB 7 /* mailbox domain name */
+#define T_MG 8 /* mail group member */
+#define T_MR 9 /* mail rename name */
+#define T_NULL 10 /* null resource record */
+#define T_WKS 11 /* well known service */
+#define T_PTR 12 /* domain name pointer */
+#define T_HINFO 13 /* host information */
+#define T_MINFO 14 /* mailbox information */
+#define T_MX 15 /* mail routing information */
+#define T_TXT 16 /* text strings */
+#define T_RP 17 /* responsible person */
+#define T_AFSDB 18 /* AFS cell database */
+#define T_NSAP 22 /* NSAP address */
+#define T_NSAP_PTR 23 /* reverse lookup for NSAP */
+ /* non standard */
+#define T_UINFO 100 /* user (finger) information */
+#define T_UID 101 /* user ID */
+#define T_GID 102 /* group ID */
+#define T_UNSPEC 103 /* Unspecified format (binary data) */
+ /* Query type values which do not appear in resource records */
+#define T_AXFR 252 /* transfer zone of authority */
+#define T_MAILB 253 /* transfer mailbox records */
+#define T_MAILA 254 /* transfer mail agent records */
+#define T_ANY 255 /* wildcard match */
+
+/*
+ * Values for class field
+ */
+
+#define C_IN 1 /* the arpa internet */
+#define C_CHAOS 3 /* for chaos net (MIT) */
+#define C_HS 4 /* for Hesiod name server (MIT) (XXX) */
+ /* Query class values which do not appear in resource records */
+#define C_ANY 255 /* wildcard match */
+
+/*
+ * Status return codes for T_UNSPEC conversion routines
+ */
+#define CONV_SUCCESS 0
+#define CONV_OVERFLOW -1
+#define CONV_BADFMT -2
+#define CONV_BADCKSUM -3
+#define CONV_BADBUFLEN -4
+
+#if !defined(BYTE_ORDER) || (BYTE_ORDER != BIG_ENDIAN \
+ && BYTE_ORDER != LITTLE_ENDIAN && BYTE_ORDER != PDP_ENDIAN)
+ /* you must determine what the correct bit order is for
+ * your compiler - the next line is an intentional error
+ * which will force your compiles to bomb until you fix
+ * the above macros.
+ */
+ #error "Undefined or invalid BYTE_ORDER";
+#endif
+
+/*
+ * Structure for query header. The order of the fields is machine- and
+ * compiler-dependent, depending on the byte/bit order and the layout
+ * of bit fields. We use bit fields only in int variables, as this
+ * is all ANSI requires. This requires a somewhat confusing rearrangement.
+ */
+
+typedef struct {
+ pthread_ipport_type id; /* query identification number */
+#if BYTE_ORDER == BIG_ENDIAN
+ /* fields in third byte */
+ u_int qr:1; /* response flag */
+ u_int opcode:4; /* purpose of message */
+ u_int aa:1; /* authoritive answer */
+ u_int tc:1; /* truncated message */
+ u_int rd:1; /* recursion desired */
+ /* fields in fourth byte */
+ u_int ra:1; /* recursion available */
+ u_int pr:1; /* primary server required (non standard) */
+ u_int unused:2; /* unused bits */
+ u_int rcode:4; /* response code */
+#endif
+#if BYTE_ORDER == LITTLE_ENDIAN || BYTE_ORDER == PDP_ENDIAN
+ /* fields in third byte */
+ u_int rd:1; /* recursion desired */
+ u_int tc:1; /* truncated message */
+ u_int aa:1; /* authoritive answer */
+ u_int opcode:4; /* purpose of message */
+ u_int qr:1; /* response flag */
+ /* fields in fourth byte */
+ u_int rcode:4; /* response code */
+ u_int unused:2; /* unused bits */
+ u_int pr:1; /* primary server required (non standard) */
+ u_int ra:1; /* recursion available */
+#endif
+ /* remaining bytes */
+ pthread_ipport_type qdcount; /* number of question entries */
+ pthread_ipport_type ancount; /* number of answer entries */
+ pthread_ipport_type nscount; /* number of authority entries */
+ pthread_ipport_type arcount; /* number of resource entries */
+} HEADER;
+
+/*
+ * Defines for handling compressed domain names
+ */
+#define INDIR_MASK 0xc0
+
+/*
+ * Structure for passing resource records around.
+ */
+struct rrec {
+ pthread_ipport_type r_zone; /* zone number */
+ pthread_ipport_type r_class; /* class number */
+ pthread_ipport_type r_type; /* type number */
+ pthread_ipaddr_type r_ttl; /* time to live */
+ int r_size; /* size of data area */
+ char * r_data; /* pointer to data */
+};
+
+extern pthread_ipport_type _getshort();
+extern pthread_ipaddr_type _getlong();
+
+/*
+ * Inline versions of get/put short/long. Pointer is advanced.
+ * We also assume that a "pthread_ipport_type" holds 2 "chars"
+ * and that a "pthread_ipaddr_type" holds 4 "chars".
+ *
+ * These macros demonstrate the property of C whereby it can be
+ * portable or it can be elegant but never both.
+ */
+#define GETSHORT(s, cp) { \
+ register u_char *t_cp = (u_char *)(cp); \
+ (s) = ((pthread_ipport_type)t_cp[0] << 8) | (pthread_ipport_type)t_cp[1]; \
+ (cp) += 2; \
+}
+
+#define GETLONG(l, cp) { \
+ register u_char *t_cp = (u_char *)(cp); \
+ (l) = (((pthread_ipaddr_type)t_cp[0]) << 24) \
+ | (((pthread_ipaddr_type)t_cp[1]) << 16) \
+ | (((pthread_ipaddr_type)t_cp[2]) << 8) \
+ | (((pthread_ipaddr_type)t_cp[3])); \
+ (cp) += 4; \
+}
+
+#define PUTSHORT(s, cp) { \
+ register pthread_ipport_type t_s = (pthread_ipport_type)(s); \
+ register u_char *t_cp = (u_char *)(cp); \
+ *t_cp++ = t_s >> 8; \
+ *t_cp = t_s; \
+ (cp) += 2; \
+}
+
+/*
+ * Warning: PUTLONG --no-longer-- destroys its first argument. if you
+ * were depending on this "feature", you will lose.
+ */
+#define PUTLONG(l, cp) { \
+ register pthread_ipaddr_type t_l = (pthread_ipaddr_type)(l); \
+ register u_char *t_cp = (u_char *)(cp); \
+ *t_cp++ = t_l >> 24; \
+ *t_cp++ = t_l >> 16; \
+ *t_cp++ = t_l >> 8; \
+ *t_cp = t_l; \
+ (cp) += 4; \
+}
+
+#endif /* !_NAMESER_H_ */
diff --git a/mit-pthreads/include/dirent.h b/mit-pthreads/include/dirent.h
new file mode 100644
index 00000000000..c3e86cb9da1
--- /dev/null
+++ b/mit-pthreads/include/dirent.h
@@ -0,0 +1,97 @@
+/*-
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)dirent.h 5.18 (Berkeley) 2/23/91
+ */
+
+#ifndef _DIRENT_H_
+#define _DIRENT_H_
+
+#include <sys/dirent.h>
+#include <pthread.h>
+
+struct __dirent {
+ struct __dirent * next;
+ struct dirent data;
+ pthread_t owner;
+};
+
+/* definitions for library routines operating on directories. */
+#define DIRBLKSIZ 1024
+
+/* structure describing an open directory. */
+typedef struct _dirdesc {
+ struct __dirent * dd_dp; /* Linked list of struct __dirent pointer */
+ int dd_fd; /* file descriptor associated with directory */
+ long dd_loc; /* offset in current buffer */
+ long dd_size; /* amount of data returned by getdirentries */
+ char * dd_buf; /* data buffer */
+ int dd_len; /* size of data buffer */
+ long dd_seek; /* magic cookie returned by getdirentries */
+ void * dd_ddloc; /* Linked list of ddloc structs for telldir/seekdir */
+ pthread_mutex_t *dd_lock; /* Lock for open directory structure */
+} DIR;
+
+#define dirfd(dirp) ((dirp)->dd_fd)
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#ifndef KERNEL
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+DIR * opendir __P_((const char *));
+struct dirent * readdir __P_((DIR *));
+int readdir_r __P_((DIR *, struct dirent *, struct dirent **));
+void rewinddir __P_((DIR *));
+int closedir __P_((DIR *));
+#ifndef _POSIX_SOURCE
+long telldir __P_((DIR *));
+void seekdir __P_((DIR *, long));
+
+/*
+int scandir __P_((const char *, struct dirent ***,
+ int (*)(struct dirent *),
+ int (*)(const void *, const void *)));
+int alphasort __P_((const void *, const void *));
+int getdirentries __P_((int, char *, int, long *));
+*/
+#endif /* not POSIX */
+
+__END_DECLS
+
+#endif /* !KERNEL */
+
+#endif /* !_DIRENT_H_ */
diff --git a/mit-pthreads/include/endian.h b/mit-pthreads/include/endian.h
new file mode 100644
index 00000000000..8fb947dbd33
--- /dev/null
+++ b/mit-pthreads/include/endian.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 1983, 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)nameser.h 8.2 (Berkeley) 2/16/94
+ * -
+ * Portions Copyright (c) 1993 by Digital Equipment Corporation.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies, and that
+ * the name of Digital Equipment Corporation not be used in advertising or
+ * publicity pertaining to distribution of the document or software without
+ * specific, written prior permission.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
+ * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ * -
+ * --Copyright--
+ */
+
+#ifndef _ENDIAN_H_
+#define _ENDIAN_H_
+
+#ifndef BYTE_ORDER
+#define LITTLE_ENDIAN 1234 /* least-significant byte first (vax, pc) */
+#define __LITTLE_ENDIAN 1234
+#define BIG_ENDIAN 4321 /* most-significant byte first (IBM, net) */
+#define __BIG_ENDIAN 4321
+#define PDP_ENDIAN 3412 /* LSB first in word, MSW first in long (pdp)*/
+#define __PDP_ENDIAN 3412
+
+#if defined(vax) || defined(ns32000) || defined(sun386) || defined(i386) || \
+ defined(MIPSEL) || defined(_MIPSEL) || defined(BIT_ZERO_ON_RIGHT) || \
+ defined(__alpha__) || defined(__alpha)
+#define BYTE_ORDER LITTLE_ENDIAN
+#define __BYTE_ORDER LITTLE_ENDIAN
+#endif
+
+#if defined(sel) || defined(pyr) || defined(mc68000) || defined(sparc) || \
+ defined(is68k) || defined(tahoe) || defined(ibm032) || defined(ibm370) || \
+ defined(MIPSEB) || defined(_MIPSEB) || defined(_IBMR2) || \
+ defined(apollo) || defined(hp9000) || defined(hp9000s300) || \
+ defined(hp9000s800) || \
+ defined (BIT_ZERO_ON_LEFT)
+#define BYTE_ORDER BIG_ENDIAN
+#define __BYTE_ORDER BIG_ENDIAN
+#endif
+#endif /* BYTE_ORDER */
+
+#if !defined(BYTE_ORDER) || (BYTE_ORDER != BIG_ENDIAN \
+ && BYTE_ORDER != LITTLE_ENDIAN && BYTE_ORDER != PDP_ENDIAN)
+ /* you must determine what the correct bit order is for
+ * your compiler - the next line is an intentional error
+ * which will force your compiles to bomb until you fix
+ * the above macros.
+ */
+ #error "Undefined or invalid BYTE_ORDER";
+#endif
+
+#endif /* !_ENDIAN_H */
diff --git a/mit-pthreads/include/errno.h b/mit-pthreads/include/errno.h
new file mode 100644
index 00000000000..24b005e9369
--- /dev/null
+++ b/mit-pthreads/include/errno.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)errno.h 7.13 (Berkeley) 2/19/91
+ * errno.h,v 1.3 1993/05/20 16:22:09 cgd Exp
+ */
+
+#ifndef _ERRNO_H_
+#define _ERRNO_H_
+
+#include <sys/cdefs.h>
+#include <sys/errno.h>
+
+__BEGIN_DECLS
+
+extern int * __error();
+
+__END_DECLS
+
+#define errno (* __error())
+#define pthread_errno(x) pthread_run->error_p = x
+
+#endif /* _ERRNO_H_ */
diff --git a/mit-pthreads/include/math.h b/mit-pthreads/include/math.h
new file mode 100644
index 00000000000..d5963ce6023
--- /dev/null
+++ b/mit-pthreads/include/math.h
@@ -0,0 +1,85 @@
+#ifndef _MATH_H_
+#define _MATH_H_
+
+/* Needed for HUGE_VAL */
+#include <sys/__math.h>
+
+/* XOPEN/SVID */
+
+#if !defined(_ANSI_SOURCE) && !defined(_POSIX_SOURCE)
+#define M_E 2.7182818284590452354 /* e */
+#define M_LOG2E 1.4426950408889634074 /* log 2e */
+#define M_LOG10E 0.43429448190325182765 /* log 10e */
+#define M_LN2 0.69314718055994530942 /* log e2 */
+#define M_LN10 2.30258509299404568402 /* log e10 */
+#define M_PI 3.14159265358979323846 /* pi */
+#define M_PI_2 1.57079632679489661923 /* pi/2 */
+#define M_PI_4 0.78539816339744830962 /* pi/4 */
+#define M_1_PI 0.31830988618379067154 /* 1/pi */
+#define M_2_PI 0.63661977236758134308 /* 2/pi */
+#define M_2_SQRTPI 1.12837916709551257390 /* 2/sqrt(pi) */
+#define M_SQRT2 1.41421356237309504880 /* sqrt(2) */
+#define M_SQRT1_2 0.70710678118654752440 /* 1/sqrt(2) */
+
+#define MAXFLOAT ((float)3.40282346638528860e+38)
+
+#if !defined(_XOPEN_SOURCE)
+
+struct exception {
+ int type;
+ char *name;
+ double arg1;
+ double arg2;
+ double retval;
+};
+
+#define HUGE MAXFLOAT
+
+#define DOMAIN 1
+#define SING 2
+#define OVERFLOW 3
+#define UNDERFLOW 4
+#define TLOSS 5
+#define PLOSS 6
+
+#endif /* !_XOPEN_SOURCE */
+#endif /* !_ANSI_SOURCE && !_POSIX_SOURCE */
+
+#include <sys/cdefs.h>
+
+/* ANSI/POSIX */
+
+__BEGIN_DECLS
+
+double hypot __P_((double, double));
+double acos __P_((double));
+double asin __P_((double));
+double atan __P_((double));
+double atan2 __P_((double, double));
+double cos __P_((double));
+double sin __P_((double));
+double tan __P_((double));
+
+double cosh __P_((double));
+double sinh __P_((double));
+double tanh __P_((double));
+
+double exp __P_((double));
+double frexp __P_((double, int *));
+double ldexp __P_((double, int));
+double log __P_((double));
+double log10 __P_((double));
+double modf __P_((double, double *));
+
+double pow __P_((double, double));
+double sqrt __P_((double));
+
+double ceil __P_((double));
+double fabs __P_((double));
+double floor __P_((double));
+double fmod __P_((double, double));
+double rint __P_((double)); /* XOPEN; Added by Monty */
+int finite __P_((double dsrc)); /* math.h; added by Monty */
+__END_DECLS
+
+#endif /* _MATH_H_ */
diff --git a/mit-pthreads/include/netdb.h b/mit-pthreads/include/netdb.h
new file mode 100644
index 00000000000..54d85e5a3ed
--- /dev/null
+++ b/mit-pthreads/include/netdb.h
@@ -0,0 +1,146 @@
+/*-
+ * Copyright (c) 1980, 1983, 1988 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)netdb.h 5.15 (Berkeley) 4/3/91
+ * $Id$
+ */
+
+#ifndef _NETDB_H_
+#define _NETDB_H_
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+
+#define _PATH_HEQUIV "/etc/hosts.equiv"
+#define _PATH_HOSTS "/etc/hosts"
+#define _PATH_NETWORKS "/etc/networks"
+#define _PATH_PROTOCOLS "/etc/protocols"
+#define _PATH_SERVICES "/etc/services"
+#define __NETDB_MAXALIASES 35
+#define __NETDB_MAXADDRS 35
+
+/*
+ * Structures returned by network data base library. All addresses are
+ * supplied in host order, and returned in network order (suitable for
+ * use in system calls).
+ */
+struct hostent {
+ char *h_name; /* official name of host */
+ char **h_aliases; /* alias list */
+ int h_addrtype; /* host address type */
+ int 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 compatiblity */
+};
+
+/*
+ * Assumption here is that a network number
+ * fits in 32 bits -- probably a poor one.
+ */
+struct netent {
+ char *n_name; /* official name of net */
+ char **n_aliases; /* alias list */
+ int n_addrtype; /* net address type */
+ unsigned long n_net; /* network # */
+};
+
+struct servent {
+ char *s_name; /* official service name */
+ char **s_aliases; /* alias list */
+ int s_port; /* port # */
+ char *s_proto; /* protocol to use */
+};
+
+struct protoent {
+ char *p_name; /* official protocol name */
+ char **p_aliases; /* alias list */
+ int p_proto; /* protocol # */
+};
+
+/*
+ * Error return codes from gethostbyname() and gethostbyaddr()
+ * (left in extern int h_errno).
+ */
+
+#define HOST_NOT_FOUND 1 /* Authoritative Answer Host not found */
+#define TRY_AGAIN 2 /* Non-Authoritive Host not found, or SERVERFAIL */
+#define NO_RECOVERY 3 /* Non recoverable errors, FORMERR, REFUSED, NOTIMP */
+#define NO_DATA 4 /* Valid name, no data record of requested type */
+#define NO_ADDRESS NO_DATA /* no address, look for MX record */
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+void endhostent __P_((void));
+void endnetent __P_((void));
+void endprotoent __P_((void));
+void endservent __P_((void));
+struct hostent *gethostbyaddr __P_((const char *, int, int));
+struct hostent *gethostbyname __P_((const char *));
+struct hostent *gethostent __P_((void));
+struct netent *getnetbyaddr __P_((long, int)); /* u_long? */
+struct netent *getnetbyname __P_((const char *));
+struct netent *getnetent __P_((void));
+struct protoent *getprotobyname __P_((const char *));
+struct protoent *getprotobynumber __P_((int));
+struct protoent *getprotoent __P_((void));
+struct servent *getservbyname __P_((const char *, const char *));
+struct servent *getservbyport __P_((int, const char *));
+struct servent *getservent __P_((void));
+void herror __P_((const char *));
+char *hstrerror __P_((int));
+void sethostent __P_((int));
+void setnetent __P_((int));
+void setprotoent __P_((int));
+void setservent __P_((int));
+struct hostent *gethostbyaddr_r __P_((const char *, int, int,
+ struct hostent *, char *, int, int *));
+struct hostent *gethostbyname_r __P_((const char *, struct hostent *, char *,
+ int, int *));
+struct hostent *gethostent_r __P_((struct hostent *, char *, int, int *));
+struct netent *getnetbyaddr_r __P_((long, int, struct netent *, char *, int));
+struct netent *getnetbyname_r __P_((const char *, struct netent *, char *,
+ int));
+struct netent *getnetent_r __P_((struct netent *, char *, int));
+struct protoent *getprotobyname_r __P_((const char *, struct protoent *, char *,
+ int));
+struct protoent *getprotobynumber_r __P_((int, struct protoent *, char *, int));
+struct protoent *getprotoent_r __P_((struct protoent *, char *, int));
+struct servent *getservbyname_r __P_((const char *, const char *,
+ struct servent *, char *, int));
+struct servent *getservbyport_r __P_((int, const char *, struct servent *,
+ char *, int));
+struct servent *getservent_r __P_((struct servent *, char *, int));
+__END_DECLS
+
+#endif /* !_NETDB_H_ */
diff --git a/mit-pthreads/include/pthread.h b/mit-pthreads/include/pthread.h
new file mode 100644
index 00000000000..e8a44050215
--- /dev/null
+++ b/mit-pthreads/include/pthread.h
@@ -0,0 +1,371 @@
+/* ==== pthread.h ============================================================
+ * Copyright (c) 1993, 1994 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ *
+ * Description : Basic pthread header.
+ *
+ * 1.00 93/07/20 proven
+ * -Started coding this file.
+ *
+ * 93/9/28 streepy - Added support for pthread cancel
+ *
+ */
+
+#ifndef _PTHREAD_H_
+#define _PTHREAD_H_
+
+#include <pthread/types.h>
+
+#include <pthread/version.h>
+#include <pthread/machdep.h>
+#include <pthread/cleanup.h>
+#include <pthread/kernel.h>
+#include <pthread/prio_queue.h>
+#include <pthread/queue.h>
+#include <pthread/sleep.h>
+#include <pthread/mutex.h>
+#include <pthread/cond.h>
+#include <pthread/fd.h>
+#include <pthread/debug_out.h>
+
+/* Requires mutex.h */
+#include <pthread/specific.h>
+
+#include <pthread/util.h>
+
+/* More includes */
+#include <pthread/pthread_once.h>
+
+/* More includes, that need size_t */
+#include <pthread/pthread_attr.h>
+
+#include <signal.h> /* for sigset_t */ /* Moved by monty */
+
+/* Constants for use with pthread_setcancelstate and pthread_setcanceltype */
+#define PTHREAD_CANCEL_DISABLE 0
+#define PTHREAD_CANCEL_ENABLE 1
+#define PTHREAD_CANCEL_DEFERRED 0
+#define PTHREAD_CANCEL_ASYNCHRONOUS 1
+
+#define PTHREAD_CANCELLED (void *)1 /* Exit status of a cancelled thread */
+
+
+#ifdef PTHREAD_KERNEL
+
+enum pthread_state {
+#define __pthread_defstate(S,NAME) S,
+#include "pthread/state.def"
+#undef __pthread_defstate
+
+ /* enum lists aren't supposed to end with a comma, sigh */
+ PS_STATE_MAX
+};
+
+/* Put PANIC inside an expression that evaluates to non-void type, to
+ make it easier to combine it in expressions. */
+#define DO_PANIC() (PANIC (), 0)
+#define PANICIF(x) ((x) ? DO_PANIC () : 0)
+
+/* In the thread flag field, we use a series of bit flags. Flags can
+ * organized into "groups" of mutually exclusive flags. Other flags
+ * are unrelated and can be set and cleared with a single bit operation.
+ */
+
+#define PF_WAIT_EVENT 0x01
+#define PF_DONE_EVENT 0x02
+#define PF_EVENT_GROUP 0x03 /* All event bits */
+
+#define PF_CANCEL_STATE 0x04 /* cancellability state */
+#define PF_CANCEL_TYPE 0x08 /* cancellability type */
+#define PF_THREAD_CANCELLED 0x10 /* thread has been cancelled */
+#define PF_RUNNING_TO_CANCEL 0x20 /* Thread is running so it can cancel*/
+#define PF_AT_CANCEL_POINT 0x40 /* Thread is at a cancel point */
+
+/* Flag operations */
+
+#define SET_PF_FLAG(x,f) ( (x)->flags |= (f) )
+#define TEST_PF_FLAG(x,f) ( (x)->flags & (f) )
+#define CLEAR_PF_FLAG(x,f) ( (x)->flags &= ~(f) )
+#define CLEAR_PF_GROUP(x,g) ( (x)->flags &= ~(g) )
+#define SET_PF_FLAG_IN_GROUP(x,g,f) ( CLEAR_PF_GROUP(x,g),SET_PF_FLAG(x,f))
+#define TEST_PF_GROUP(x,g) ( (x)->flags & (g) )
+
+#define SET_PF_DONE_EVENT(x) \
+( !TEST_PF_FLAG(x,PF_DONE_EVENT) \
+ ? ( TEST_PF_FLAG(x,PF_WAIT_EVENT) \
+ ? (SET_PF_FLAG_IN_GROUP(x,PF_EVENT_GROUP,PF_DONE_EVENT), OK) \
+ : DO_PANIC ()) \
+ : NOTOK )
+
+#define SET_PF_WAIT_EVENT(x) \
+( PANICIF (TEST_PF_GROUP(x,PF_EVENT_GROUP) ), \
+ SET_PF_FLAG_IN_GROUP(x,PF_EVENT_GROUP,PF_WAIT_EVENT), 0)
+
+#define CLEAR_PF_DONE_EVENT(x) \
+( PANICIF (!TEST_PF_FLAG(x,PF_DONE_EVENT)), \
+ CLEAR_PF_GROUP(x,PF_EVENT_GROUP) )
+
+#define SET_PF_CANCELLED(x) ( SET_PF_FLAG(x,PF_THREAD_CANCELLED) )
+#define TEST_PF_CANCELLED(x) ( TEST_PF_FLAG(x,PF_THREAD_CANCELLED) )
+
+#define SET_PF_RUNNING_TO_CANCEL(x) ( SET_PF_FLAG(x,PF_RUNNING_TO_CANCEL) )
+#define CLEAR_PF_RUNNING_TO_CANCEL(x)( CLEAR_PF_FLAG(x,PF_RUNNING_TO_CANCEL) )
+#define TEST_PF_RUNNING_TO_CANCEL(x)( TEST_PF_FLAG(x,PF_RUNNING_TO_CANCEL) )
+
+#define SET_PF_AT_CANCEL_POINT(x) ( SET_PF_FLAG(x,PF_AT_CANCEL_POINT) )
+#define CLEAR_PF_AT_CANCEL_POINT(x) ( CLEAR_PF_FLAG(x,PF_AT_CANCEL_POINT) )
+#define TEST_PF_AT_CANCEL_POINT(x) ( TEST_PF_FLAG(x,PF_AT_CANCEL_POINT) )
+
+#define SET_PF_CANCEL_STATE(x,f) \
+ ( (f) ? SET_PF_FLAG(x,PF_CANCEL_STATE) : CLEAR_PF_FLAG(x,PF_CANCEL_STATE) )
+#define TEST_PF_CANCEL_STATE(x) \
+ ( (TEST_PF_FLAG(x,PF_CANCEL_STATE)) ? PTHREAD_CANCEL_ENABLE \
+ : PTHREAD_CANCEL_DISABLE )
+
+#define SET_PF_CANCEL_TYPE(x,f) \
+ ( (f) ? SET_PF_FLAG(x,PF_CANCEL_TYPE) : CLEAR_PF_FLAG(x,PF_CANCEL_TYPE) )
+#define TEST_PF_CANCEL_TYPE(x) \
+ ( (TEST_PF_FLAG(x,PF_CANCEL_TYPE)) ? PTHREAD_CANCEL_ASYNCHRONOUS \
+ : PTHREAD_CANCEL_DEFERRED )
+
+/* See if a thread is in a state that it can be cancelled */
+#define TEST_PTHREAD_IS_CANCELLABLE(x) \
+( (TEST_PF_CANCEL_STATE(x) == PTHREAD_CANCEL_ENABLE && TEST_PF_CANCELLED(x)) \
+ ? ((TEST_PF_CANCEL_TYPE(x) == PTHREAD_CANCEL_ASYNCHRONOUS) \
+ ? 1 \
+ : TEST_PF_AT_CANCEL_POINT(x)) \
+ : 0 )
+
+
+struct pthread_select_data {
+ int nfds;
+ fd_set readfds;
+ fd_set writefds;
+ fd_set exceptfds;
+};
+
+union pthread_wait_data {
+ pthread_mutex_t * mutex;
+ pthread_cond_t * cond;
+ const sigset_t * sigwait; /* Waiting on a signal in sigwait */
+ struct {
+ short fd; /* Used when thread waiting on fd */
+ short branch; /* line number, for debugging */
+ } fd;
+ struct pthread_select_data * select_data;
+};
+
+#define PTT_USER_THREAD 0x0001
+
+struct pthread {
+ int thread_type;
+ struct machdep_pthread machdep_data;
+ pthread_attr_t attr;
+
+ /* Signal interface */
+ sigset_t sigmask;
+ sigset_t sigpending;
+ int sigcount; /* Number of signals pending */
+ int sighandled; /* Set when signal has been handled */
+ /* Timeout time */
+ struct timespec wakeup_time;
+
+ /* Join queue for waiting threads */
+ struct pthread_queue join_queue;
+
+ /*
+ * Thread implementations are just multiple queue type implemenations,
+ * Below are the various link lists currently necessary
+ * It is possible for a thread to be on multiple, or even all the
+ * queues at once, much care must be taken during queue manipulation.
+ *
+ * The pthread structure must be locked before you can even look at
+ * the link lists.
+ */
+
+ /*
+ * ALL threads, in any state.
+ * Must lock kernel lock before manipulating.
+ */
+ struct pthread * pll;
+
+ /*
+ * Standard link list for running threads, mutexes, etc ...
+ * It can't be on both a running link list and a wait queue.
+ * Must lock kernel lock before manipulating.
+ */
+ struct pthread * next;
+ union pthread_wait_data data;
+
+ /*
+ * Actual queue state and priority of thread.
+ * (Note: "priority" is a reserved word in Concurrent C, please
+ * don't use it. --KR)
+ */
+ struct pthread_queue * queue;
+ enum pthread_state state;
+ enum pthread_state old_state; /* Used when cancelled */
+ char flags;
+ char pthread_priority;
+
+ /*
+ * Sleep queue, this is different from the standard link list
+ * because it is possible to be on both (pthread_cond_timedwait();
+ * Must lock sleep mutex before manipulating
+ */
+ struct pthread *sll; /* For sleeping threads */
+
+ /*
+ * Data that doesn't need to be locked
+ * Mostly because only the thread owning the data can manipulate it
+ */
+ void * ret;
+ int error;
+ int * error_p;
+ const void ** specific_data;
+ int specific_data_count;
+
+ /* Cleanup handlers Link List */
+ struct pthread_cleanup *cleanup;
+};
+
+#else /* not PTHREAD_KERNEL */
+
+struct pthread;
+
+#endif
+
+typedef struct pthread *pthread_t;
+
+/*
+ * Globals
+ */
+#ifdef PTHREAD_KERNEL
+
+extern struct pthread * pthread_run;
+extern struct pthread * pthread_initial;
+extern struct pthread * pthread_link_list;
+extern struct pthread_queue pthread_dead_queue;
+extern struct pthread_queue pthread_alloc_queue;
+
+extern pthread_attr_t pthread_attr_default;
+extern volatile int fork_lock;
+extern pthread_size_t pthread_pagesize;
+
+extern sigset_t * uthread_sigmask;
+
+/* Kernel global functions */
+extern void pthread_sched_prevent(void);
+extern void pthread_sched_resume(void);
+extern int __pthread_is_valid( pthread_t );
+extern void pthread_cancel_internal( int freelocks );
+
+#endif
+
+/*
+ * New functions
+ */
+
+__BEGIN_DECLS
+
+#if defined(DCE_COMPAT)
+
+typedef void * (*pthread_startroutine_t)(void *);
+typedef void * pthread_addr_t;
+
+int pthread_create __P_((pthread_t *, pthread_attr_t,
+ pthread_startroutine_t,
+ pthread_addr_t));
+void pthread_exit __P_((pthread_addr_t));
+int pthread_join __P_((pthread_t, pthread_addr_t *));
+
+#else
+
+void pthread_init __P_((void));
+int pthread_create __P_((pthread_t *,
+ const pthread_attr_t *,
+ void * (*start_routine)(void *),
+ void *));
+void pthread_exit __P_((void *));
+pthread_t pthread_self __P_((void));
+int pthread_equal __P_((pthread_t, pthread_t));
+int pthread_join __P_((pthread_t, void **));
+int pthread_detach __P_((pthread_t));
+void pthread_yield __P_((void));
+int pthread_setschedparam __P_((pthread_t pthread, int policy,
+ struct sched_param * param));
+int pthread_getschedparam __P_((pthread_t pthread, int * policy,
+ struct sched_param * param));
+int pthread_kill __P_((struct pthread *, int));
+void (*pthread_signal __P_((int, void (*)(int))))();
+int pthread_cancel __P_(( pthread_t pthread ));
+int pthread_setcancelstate __P_(( int state, int *oldstate ));
+int pthread_setcanceltype __P_(( int type, int *oldtype ));
+void pthread_testcancel __P_(( void ));
+
+int pthread_sigmask __P_((int how, const sigset_t *set,
+ sigset_t * oset)); /* added by Monty */
+int sigwait __P_((const sigset_t * set, int * sig));
+int sigsetwait __P_((const sigset_t * set, int * sig));
+#endif
+
+#if defined(PTHREAD_KERNEL)
+
+/* Not valid, but I can't spell so this will be caught at compile time */
+#define pthread_yeild(notvalid)
+
+#endif
+
+__END_DECLS
+
+/*
+ * Static constructors
+ */
+#ifdef __cplusplus
+
+extern struct pthread * pthread_initial;
+
+class __pthread_init_t {
+/* struct __pthread_init_t { */
+ public:
+ __pthread_init_t() {
+ if (pthread_initial == NULL) {
+ pthread_init();
+ }
+ }
+};
+
+static __pthread_init_t __pthread_init_this_file;
+
+#endif /* __cplusplus */
+
+#endif
diff --git a/mit-pthreads/include/pthread/ac-types.h b/mit-pthreads/include/pthread/ac-types.h
new file mode 100644
index 00000000000..c9dc938f6e8
--- /dev/null
+++ b/mit-pthreads/include/pthread/ac-types.h
@@ -0,0 +1,11 @@
+#ifndef pthread_size_t
+#define pthread_ipaddr_type unsigned int
+#define pthread_ipport_type unsigned short
+#define pthread_clock_t long
+#define pthread_size_t unsigned int
+#define pthread_ssize_t int
+#define pthread_time_t long
+#define pthread_fpos_t long long
+#define pthread_off_t long long
+#define pthread_va_list void *
+#endif
diff --git a/mit-pthreads/include/pthread/cleanup.h b/mit-pthreads/include/pthread/cleanup.h
new file mode 100755
index 00000000000..cd995ceddcf
--- /dev/null
+++ b/mit-pthreads/include/pthread/cleanup.h
@@ -0,0 +1,59 @@
+/* ==== cleanup.h ============================================================
+ * Copyright (c) 1994 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ *
+ * Description : cleanup header.
+ *
+ * 1.20 94/02/13 proven
+ * -Started coding this file.
+ */
+
+/*
+ * New cleanup structures
+ */
+struct pthread_cleanup {
+ struct pthread_cleanup *next;
+ void (*routine)();
+ void *routine_arg;
+};
+
+/*
+ * New functions
+ */
+
+__BEGIN_DECLS
+
+int pthread_cleanup_push __P_((void (*routine)(void *), void *routine_arg));
+void pthread_cleanup_pop __P_((int execute));
+
+__END_DECLS
+
diff --git a/mit-pthreads/include/pthread/cond.h b/mit-pthreads/include/pthread/cond.h
new file mode 100755
index 00000000000..ec9f7cf0016
--- /dev/null
+++ b/mit-pthreads/include/pthread/cond.h
@@ -0,0 +1,102 @@
+/* ==== cond.h ============================================================
+ * Copyright (c) 1993 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ *
+ * Description : Condition variable header.
+ *
+ * 1.00 93/10/30 proven
+ * -Started coding this file.
+ */
+
+#include <timers.h>
+
+/*
+ * New cond structures
+ */
+enum pthread_condtype {
+ COND_TYPE_FAST,
+ COND_TYPE_STATIC_FAST,
+ COND_TYPE_COUNTING_FAST, /* Used with MUTEX_TYPE_COUNTING_FAST */
+ COND_TYPE_METERED,
+ COND_TYPE_DEBUG, /* Debug conds will have lots of options */
+ COND_TYPE_MAX
+};
+
+#define PTHREAD_CONDTYPE_FAST 1
+#define PTHREAD_CONDTYPE_DEBUG 4
+#define PTHREAD_CONDTYPE_RECURSIVE 2
+
+typedef struct pthread_cond {
+ enum pthread_condtype c_type;
+ struct pthread_queue c_queue;
+ semaphore c_lock;
+ void * c_data;
+ long c_flags;
+} pthread_cond_t;
+
+typedef struct pthread_condattr {
+ enum pthread_condtype c_type;
+ long c_flags;
+} pthread_condattr_t;
+
+/*
+ * Flags for conds.
+ */
+#define COND_FLAGS_PRIVATE 0x01
+#define COND_FLAGS_INITED 0x02
+#define COND_FLAGS_BUSY 0x04
+
+/*
+ * Static cond initialization values.
+ */
+#define PTHREAD_COND_INITIALIZER \
+{ COND_TYPE_STATIC_FAST, PTHREAD_QUEUE_INITIALIZER, \
+ SEMAPHORE_CLEAR, NULL, COND_FLAGS_INITED }
+
+/*
+ * New functions
+ */
+
+__BEGIN_DECLS
+
+struct timespec;
+
+int pthread_cond_init __P_((pthread_cond_t *, const pthread_condattr_t *));
+int pthread_cond_timedwait __P_((pthread_cond_t *, pthread_mutex_t *,
+ const struct timespec * abstime));
+int pthread_cond_wait __P_((pthread_cond_t *, pthread_mutex_t *));
+int pthread_cond_signal __P_((pthread_cond_t *));
+int pthread_cond_broadcast __P_((pthread_cond_t *));
+int pthread_cond_destroy __P_((pthread_cond_t *));
+
+__END_DECLS
+
diff --git a/mit-pthreads/include/pthread/config.h b/mit-pthreads/include/pthread/config.h
new file mode 100644
index 00000000000..251948c3874
--- /dev/null
+++ b/mit-pthreads/include/pthread/config.h
@@ -0,0 +1,5 @@
+#ifndef _SYS___CONFIG_H_
+#define _SYS___CONFIG_H_
+#define _OS_HAS_TIMESPEC 1
+#define _OS_HAS_SOCKLEN_T 1
+#endif
diff --git a/mit-pthreads/include/pthread/debug_out.h b/mit-pthreads/include/pthread/debug_out.h
new file mode 100755
index 00000000000..6968c5ea90e
--- /dev/null
+++ b/mit-pthreads/include/pthread/debug_out.h
@@ -0,0 +1,44 @@
+/* debug_out.h - macros to use for debugging prints in places where calls
+ to printf() and gang are ill-advised. */
+
+#ifdef PTHREAD_DEBUGGING
+#define PTHREAD_DEBUG_WriteStr(S) (void)machdep_sys_write(2,S,strlen(S))
+#define PTHREAD_DEBUG_WriteInt32Hex(X) \
+ { char _xbuf[8]; int _temp = (int)(X), _temp2; \
+ _temp2 = ((_temp>>28)&0xf); \
+ _xbuf[0] = (_temp2<10)? (_temp2+'0'): ((_temp2-10)+'a'); \
+ _temp2 = ((_temp>>24)&0xf); \
+ _xbuf[1] = (_temp2<10)? (_temp2+'0'): ((_temp2-10)+'a'); \
+ _temp2 = ((_temp>>20)&0xf); \
+ _xbuf[2] = (_temp2<10)? (_temp2+'0'): ((_temp2-10)+'a'); \
+ _temp2 = ((_temp>>16)&0xf); \
+ _xbuf[3] = (_temp2<10)? (_temp2+'0'): ((_temp2-10)+'a'); \
+ _temp2 = ((_temp>>12)&0xf); \
+ _xbuf[4] = (_temp2<10)? (_temp2+'0'): ((_temp2-10)+'a'); \
+ _temp2 = ((_temp>>8)&0xf); \
+ _xbuf[5] = (_temp2<10)? (_temp2+'0'): ((_temp2-10)+'a'); \
+ _temp2 = ((_temp>>4)&0xf); \
+ _xbuf[6] = (_temp2<10)? (_temp2+'0'): ((_temp2-10)+'a'); \
+ _temp2 = (_temp&0xf); \
+ _xbuf[7] = (_temp2<10)? (_temp2+'0'): ((_temp2-10)+'a'); \
+ (void)machdep_sys_write(2,_xbuf,8); \
+ }
+#ifdef __alpha
+#define PTHREAD_DEBUG_WriteInt64Hex(X) \
+ { long _tempX = (long)(X),_tempY; \
+ _tempY=((_tempX>>32)&0xffffffff); \
+ PTHREAD_DEBUG_WriteInt32Hex(_tempY); \
+ _tempY=(_tempX&0xffffffff); \
+ PTHREAD_DEBUG_WriteInt32Hex(_tempY); \
+ }
+#define PTHREAD_DEBUG_WritePointer(X) PTHREAD_DEBUG_WriteInt64Hex(X)
+#else
+#define PTHREAD_DEBUG_WriteInt64Hex(X) PTHREAD_DEBUG_WriteInt32Hex(X)
+#define PTHREAD_DEBUG_WritePointer(X) PTHREAD_DEBUG_WriteInt32Hex(X)
+#endif /* __alpha */
+#else /* ! PTHREAD_DEBUGGING */
+#define PTHREAD_DEBUG_WriteStr(S)
+#define PTHREAD_DEBUG_WriteInt32Hex(X)
+#define PTHREAD_DEBUG_WriteInt64HeX(X)
+#define PTHREAD_DEBUG_WritePointer(X)
+#endif /* PTHREAD_DEBUGGING */
diff --git a/mit-pthreads/include/pthread/fd.h b/mit-pthreads/include/pthread/fd.h
new file mode 100755
index 00000000000..d27a5066936
--- /dev/null
+++ b/mit-pthreads/include/pthread/fd.h
@@ -0,0 +1,122 @@
+/* ==== fd.h ============================================================
+ * Copyright (c) 1993, 1994 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ *
+ * Description : Basic fd header.
+ *
+ * 1.00 93/08/14 proven
+ * -Started coding this file.
+ *
+ * 1.01 93/11/13 proven
+ * -The functions readv() and writev() added
+ */
+
+/*
+ * New pthread types.
+ */
+enum fd_type {
+ FD_NT, /* Not tested */
+ FD_NIU, /* Known to be not in use */
+ FD_HALF_DUPLEX, /* Files, and seeking devices */
+ FD_FULL_DUPLEX, /* pipes, sockets, drivers, ... */
+ FD_TEST_HALF_DUPLEX, /* Redo machdep_sys_fcntl */
+ FD_TEST_FULL_DUPLEX /* Redo machdep_sys_fcntl */
+};
+
+
+#define FD_READ 0x1
+#define FD_WRITE 0x2
+#define FD_RDWR (FD_READ | FD_WRITE)
+
+union fd_data {
+ void *ptr;
+ int i;
+};
+
+struct timespec;
+struct iovec;
+struct fd_ops {
+ pthread_ssize_t (*write) __P_((union fd_data, int, const void *,
+ size_t, struct timespec *));
+ pthread_ssize_t (*read) __P_((union fd_data, int, void *, size_t,
+ struct timespec *));
+ int (*close)();
+ int (*fcntl)();
+ int (*writev) __P_((union fd_data, int,
+ const struct iovec *,
+ int, struct timespec *));
+ int (*readv) __P_((union fd_data, int,
+ const struct iovec *,
+ int, struct timespec *));
+ off_t (*seek)();
+ int use_kfds;
+};
+
+struct fd_table_entry {
+ struct pthread_queue r_queue;
+ struct pthread_queue w_queue;
+ struct pthread *r_owner;
+ struct pthread *w_owner;
+ pthread_mutex_t mutex;
+ struct fd_table_entry *next;
+ struct fd_ops *ops;
+ enum fd_type type;
+ int r_lockcount; /* Count for FILE read locks */
+ int w_lockcount; /* Count for FILE write locks */
+ int count;
+
+ /* data that needs to be passed to the type dependent fd */
+ int flags;
+ union fd_data fd;
+};
+
+/*
+ * Globals
+ */
+#if defined(PTHREAD_KERNEL)
+
+extern struct fd_table_entry **fd_table;
+extern int dtablesize;
+
+#endif
+
+/*
+ * New functions
+ */
+
+__BEGIN_DECLS
+
+#if defined(PTHREAD_KERNEL)
+
+#endif
+
+__END_DECLS
diff --git a/mit-pthreads/include/pthread/fd_pipe.h b/mit-pthreads/include/pthread/fd_pipe.h
new file mode 100755
index 00000000000..cc5670dbb7d
--- /dev/null
+++ b/mit-pthreads/include/pthread/fd_pipe.h
@@ -0,0 +1,54 @@
+/* ==== fd_pipe.h ============================================================
+ * Copyright (c) 1993 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ *
+ * Description : The new fast ITC pipe header.
+ *
+ * 1.00 93/08/14 proven
+ * -Started coding this file.
+ */
+
+struct __pipe {
+ semaphore lock;
+ char * buf;
+ int size;
+ int flags;
+ int count;
+ int offset;
+ struct pthread * wait;
+ char * wait_buf;
+ size_t wait_size;
+};
+
+#define RD_CLOSED 0x01
+#define WR_CLOSED 0x02
+
diff --git a/mit-pthreads/include/pthread/kernel.h b/mit-pthreads/include/pthread/kernel.h
new file mode 100755
index 00000000000..c474d789681
--- /dev/null
+++ b/mit-pthreads/include/pthread/kernel.h
@@ -0,0 +1,71 @@
+/* ==== kernel.h ============================================================
+ * Copyright (c) 1993 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ *
+ * Description : mutex header.
+ *
+ * 1.00 93/07/22 proven
+ * -Started coding this file.
+ */
+
+/*
+ * Defines only for the pthread user kernel.
+ */
+#if defined(PTHREAD_KERNEL)
+
+#ifdef __GNUC__
+#include <assert.h>
+#endif
+#ifdef __ASSERT_FUNCTION
+#define PANIC() panic_kernel( __FILE__, __LINE__, __ASSERT_FUNCTION )
+#else
+#define PANIC() panic_kernel( __FILE__, __LINE__, (const char *)0 )
+#endif
+
+
+/* Time each rr thread gets */
+#define PTHREAD_RR_TIMEOUT 100000000
+
+/* Set the errno value */
+#define SET_ERRNO(x) \
+{ \
+ if (!pthread_run->error_p) { \
+ pthread_run->error_p = &pthread_run->error; \
+ } \
+ (*(pthread_run->error_p)) = x; \
+}
+
+/* Globals only the internals should see */
+extern struct pthread_prio_queue * pthread_current_prio_queue;
+extern volatile int pthread_kernel_lock;
+
+#endif
diff --git a/mit-pthreads/include/pthread/kthread.h b/mit-pthreads/include/pthread/kthread.h
new file mode 100755
index 00000000000..a2e73361d8c
--- /dev/null
+++ b/mit-pthreads/include/pthread/kthread.h
@@ -0,0 +1,67 @@
+/* ==== kthread.h ============================================================
+ * Copyright (c) 1993, 1994 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ *
+ * Description : Basic pthread header.
+ *
+ * 1.00 93/07/20 proven
+ * -Started coding this file.
+ *
+ * 1.32 94/05/25 proven
+ * -Started adding kernel thread support
+ */
+
+#ifndef _KTHREAD_H_
+#define _KTHREAD_H_
+
+enum kthread_state {
+ KS_RUNNING,
+ KS_DEAD,
+};
+
+struct kthread {
+ enum kthread_state state;
+
+ struct pthread_queue pthread_current_queue;
+ struct pthread * pthread_link_list;
+ struct pthread * pthread_run;
+
+ semaphore lock;
+
+};
+
+/*
+ * Globals
+ */
+extern struct kthread * kthread_link_list;
+
+#endif
diff --git a/mit-pthreads/include/pthread/mutex.h b/mit-pthreads/include/pthread/mutex.h
new file mode 100755
index 00000000000..e6f1fe58c0f
--- /dev/null
+++ b/mit-pthreads/include/pthread/mutex.h
@@ -0,0 +1,102 @@
+/* ==== mutex.h ============================================================
+ * Copyright (c) 1993 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ *
+ * Description : mutex header.
+ *
+ * 1.00 93/07/20 proven
+ * -Started coding this file.
+ */
+
+/*
+ * New mutex structures
+ */
+enum pthread_mutextype {
+ MUTEX_TYPE_STATIC_FAST = 0,
+ MUTEX_TYPE_FAST = 1,
+ MUTEX_TYPE_COUNTING_FAST = 2, /* Recursive */
+ MUTEX_TYPE_METERED = 3,
+ MUTEX_TYPE_DEBUG = 4, /* This will have lots of options */
+ MUTEX_TYPE_MAX
+};
+
+#define PTHREAD_MUTEXTYPE_FAST 1
+#define PTHREAD_MUTEXTYPE_DEBUG 4
+#define PTHREAD_MUTEXTYPE_RECURSIVE 2
+
+union pthread_mutex_data {
+ void * m_ptr;
+ int m_count;
+};
+
+typedef struct pthread_mutex {
+ enum pthread_mutextype m_type;
+ struct pthread_queue m_queue;
+ struct pthread * m_owner;
+ semaphore m_lock;
+ union pthread_mutex_data m_data;
+ long m_flags;
+} pthread_mutex_t;
+
+typedef struct pthread_mutexattr {
+ enum pthread_mutextype m_type;
+ long m_flags;
+} pthread_mutexattr_t;
+
+/*
+ * Flags for mutexes.
+ */
+#define MUTEX_FLAGS_PRIVATE 0x01
+#define MUTEX_FLAGS_INITED 0x02
+#define MUTEX_FLAGS_BUSY 0x04
+
+/*
+ * Static mutex initialization values.
+ */
+#define PTHREAD_MUTEX_INITIALIZER \
+{ MUTEX_TYPE_STATIC_FAST, PTHREAD_QUEUE_INITIALIZER, \
+ NULL, SEMAPHORE_CLEAR, { NULL }, MUTEX_FLAGS_INITED }
+
+/*
+ * New functions
+ */
+
+__BEGIN_DECLS
+
+int pthread_mutex_init __P_((pthread_mutex_t *, const pthread_mutexattr_t *));
+int pthread_mutex_lock __P_((pthread_mutex_t *));
+int pthread_mutex_unlock __P_((pthread_mutex_t *));
+int pthread_mutex_trylock __P_((pthread_mutex_t *));
+int pthread_mutex_destroy __P_((pthread_mutex_t *));
+
+__END_DECLS
+
diff --git a/mit-pthreads/include/pthread/paths.h b/mit-pthreads/include/pthread/paths.h
new file mode 100644
index 00000000000..8af9233a67c
--- /dev/null
+++ b/mit-pthreads/include/pthread/paths.h
@@ -0,0 +1,12 @@
+#ifndef _SYS___PATHS_H_
+#define _SYS___PATHS_H_
+#define _PATH_PTY "/dev/"
+#define _PATH_TZDIR "/usr/share/zoneinfo"
+#define _PATH_TZFILE "/etc/localtime"
+#define _PATH_RESCONF "/etc/resolv.conf"
+#define _PATH_HOSTS "/etc/hosts"
+#define _PATH_NETWORKS "/etc/networks"
+#define _PATH_PROTOCOLS "/etc/protocols"
+#define _PATH_SERVICES "/etc/services"
+#define _PATH_BSHELL "/bin/sh"
+#endif
diff --git a/mit-pthreads/include/pthread/prio_queue.h b/mit-pthreads/include/pthread/prio_queue.h
new file mode 100755
index 00000000000..e29a0170548
--- /dev/null
+++ b/mit-pthreads/include/pthread/prio_queue.h
@@ -0,0 +1,78 @@
+/* ==== priority.h ==========================================================
+ * Copyright (c) 1994 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ *
+ * Description : Priority functions.
+ *
+ * 1.00 94/09/19 proven
+ * -Started coding this file.
+ */
+
+#ifndef _PTHREAD_PRIO_QUEUE_H_
+#define _PTHREAD_PRIO_QUEUE_H_
+
+/*
+ * Static queue initialization values.
+ */
+#define PTHREAD_DEFAULT_PRIORITY 64
+#define PTHREAD_MAX_PRIORITY 126
+#define PTHREAD_MIN_PRIORITY 0
+
+/*
+ * New prio_queue structures
+ */
+struct pthread_prio_level {
+ struct pthread * first;
+ struct pthread * last;
+};
+
+struct pthread_prio_queue {
+ void * data;
+ struct pthread * next;
+ struct pthread_prio_level level[PTHREAD_MAX_PRIORITY + 1];
+};
+
+/*
+ * New functions
+ */
+
+__BEGIN_DECLS
+
+void pthread_prio_queue_init __P_((struct pthread_prio_queue *));
+void pthread_prio_queue_enq __P_((struct pthread_prio_queue *,
+ struct pthread *));
+struct pthread *pthread_prio_queue_deq
+ __P_((struct pthread_prio_queue *));
+
+__END_DECLS
+
+#endif
diff --git a/mit-pthreads/include/pthread/pthread_attr.h b/mit-pthreads/include/pthread/pthread_attr.h
new file mode 100755
index 00000000000..8cad262bad2
--- /dev/null
+++ b/mit-pthreads/include/pthread/pthread_attr.h
@@ -0,0 +1,122 @@
+/* ==== pthread_attr.h ========================================================
+ * Copyright (c) 1993 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ *
+ * Description : Basic pthread attributes header.
+ *
+ * 1.00 93/11/03 proven
+ * -Started coding this file.
+ */
+
+#define _POSIX_THREAD_ATTR_STACKSIZE
+
+#define PTHREAD_STACK_DEFAULT 65536
+
+/* flags */
+#define PTHREAD_DETACHED 0x1
+#define PTHREAD_SCOPE_SYSTEM 0x2
+#define PTHREAD_INHERIT_SCHED 0x4
+#define PTHREAD_NOFLOAT 0x8
+
+#define PTHREAD_CREATE_DETACHED PTHREAD_DETACHED
+#define PTHREAD_CREATE_JOINABLE 0
+#define PTHREAD_SCOPE_PROCESS 0
+#define PTHREAD_EXPLICIT_SCHED 0
+
+/*
+ * New pthread attribute types.
+ */
+enum schedparam_policy {
+ SCHED_RR,
+ SCHED_IO,
+ SCHED_FIFO,
+ SCHED_OTHER
+};
+
+struct pthread_attr {
+ enum schedparam_policy schedparam_policy;
+ int sched_priority;
+
+ int flags;
+ void * arg_attr;
+ void (*cleanup_attr)();
+ void * stackaddr_attr;
+ size_t stacksize_attr;
+};
+
+struct sched_param {
+ int sched_priority;
+ void * no_data;
+};
+
+/*
+ * New functions
+ */
+
+__BEGIN_DECLS
+
+#if defined(DCE_COMPAT)
+
+typedef struct pthread_attr * pthread_attr_t;
+
+int pthread_attr_create __P_((pthread_attr_t *));
+int pthread_attr_delete __P_((pthread_attr_t *));
+
+#else
+
+typedef struct pthread_attr pthread_attr_t;
+
+int pthread_attr_init __P_((pthread_attr_t *));
+int pthread_attr_destroy __P_((pthread_attr_t *));
+int pthread_attr_setstacksize __P_((pthread_attr_t *, size_t));
+int pthread_attr_getstacksize __P_((pthread_attr_t *, size_t *));
+int pthread_attr_setstackaddr __P_((pthread_attr_t *, void *));
+int pthread_attr_getstackaddr __P_((pthread_attr_t *, void **));
+int pthread_attr_setdetachstate __P_((pthread_attr_t *, int ));
+int pthread_attr_getdetachstate __P_((pthread_attr_t *, int *));
+int pthread_attr_setscope __P_((pthread_attr_t *, int ));
+int pthread_attr_getscope __P_((pthread_attr_t *, int *));
+int pthread_attr_setinheritsched __P_((pthread_attr_t *, int ));
+int pthread_attr_getinheritsched __P_((pthread_attr_t *, int *));
+int pthread_attr_setschedpolicy __P_((pthread_attr_t *, int ));
+int pthread_attr_getschedpolicy __P_((pthread_attr_t *, int *));
+int pthread_attr_setschedparam __P_((pthread_attr_t *, struct sched_param *));
+int pthread_attr_getschedparam __P_((pthread_attr_t *, struct sched_param *));
+
+int pthread_attr_setfloatstate __P_((pthread_attr_t *, int ));
+int pthread_attr_getfloatstate __P_((pthread_attr_t *, int *));
+int pthread_attr_setcleanup __P_((pthread_attr_t *, void (*routine)(void *),
+ void *));
+
+#endif
+
+__END_DECLS
diff --git a/mit-pthreads/include/pthread/pthread_once.h b/mit-pthreads/include/pthread/pthread_once.h
new file mode 100755
index 00000000000..ac53d5f9b2c
--- /dev/null
+++ b/mit-pthreads/include/pthread/pthread_once.h
@@ -0,0 +1,58 @@
+/* ==== pthread_once.h ========================================================
+ * Copyright (c) 1993 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ *
+ * Description : mutex header.
+ *
+ * 1.00 93/12/12 proven
+ * -Started coding this file.
+ */
+
+/* New pthread_once structures */
+typedef struct pthread_once {
+ int state;
+ pthread_mutex_t mutex;
+} pthread_once_t;
+
+/* Static pthread_once_t initialization value. */
+#define PTHREAD_NEEDS_INIT 0
+#define PTHREAD_DONE_INIT 1
+#define PTHREAD_ONCE_INIT { PTHREAD_NEEDS_INIT, PTHREAD_MUTEX_INITIALIZER }
+
+/* New functions */
+
+__BEGIN_DECLS
+
+int pthread_once __P_((pthread_once_t *, void (*init_routine)(void)));
+
+__END_DECLS
+
diff --git a/mit-pthreads/include/pthread/queue.h b/mit-pthreads/include/pthread/queue.h
new file mode 100755
index 00000000000..eca7699e95a
--- /dev/null
+++ b/mit-pthreads/include/pthread/queue.h
@@ -0,0 +1,67 @@
+/* ==== queue.h ============================================================
+ * Copyright (c) 1993 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ *
+ * Description : mutex header.
+ *
+ * 1.00 93/07/20 proven
+ * -Started coding this file.
+ */
+
+/*
+ * New queue structures
+ */
+struct pthread_queue {
+ struct pthread *q_next;
+ struct pthread *q_last;
+ void *q_data;
+};
+
+/*
+ * Static queue initialization values.
+ */
+#define PTHREAD_QUEUE_INITIALIZER { NULL, NULL, NULL }
+
+/*
+ * New functions
+ * Should make pthread_queue_get a macro
+ */
+
+__BEGIN_DECLS
+
+void pthread_queue_init __P_((struct pthread_queue *));
+void pthread_queue_enq __P_((struct pthread_queue *, struct pthread *));
+int pthread_queue_remove __P_((struct pthread_queue *, struct pthread *));
+struct pthread *pthread_queue_get __P_((struct pthread_queue *));
+struct pthread *pthread_queue_deq __P_((struct pthread_queue *));
+
+__END_DECLS
diff --git a/mit-pthreads/include/pthread/sleep.h b/mit-pthreads/include/pthread/sleep.h
new file mode 100755
index 00000000000..8bf471a24aa
--- /dev/null
+++ b/mit-pthreads/include/pthread/sleep.h
@@ -0,0 +1,63 @@
+/* ==== sleep.h ============================================================
+ * Copyright (c) 1994 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ *
+ * Description : sleep header.
+ *
+ * 1.00 94/06/04 proven
+ * -Started coding this file.
+ */
+
+#if defined(PTHREAD_KERNEL)
+
+#include <timers.h>
+
+/*
+ * New functions
+ */
+static inline int machdep_gettimeofday(struct timespec * current_time)
+{
+ struct timeval current_real_time;
+ int ret;
+
+ ret = gettimeofday(&current_real_time, NULL);
+ TIMEVAL_TO_TIMESPEC((&current_real_time), current_time);
+ return(ret);
+}
+
+__BEGIN_DECLS
+
+void sleep_schedule __P_((struct timespec *, struct timespec *));
+
+__END_DECLS
+
+#endif
diff --git a/mit-pthreads/include/pthread/specific.h b/mit-pthreads/include/pthread/specific.h
new file mode 100755
index 00000000000..9c66a695556
--- /dev/null
+++ b/mit-pthreads/include/pthread/specific.h
@@ -0,0 +1,66 @@
+/* ==== specific.h ========================================================
+ * Copyright (c) 1994 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ *
+ * Description : Thread specific data management header.
+ *
+ * 1.20 94/03/30 proven
+ * -Started coding this file.
+ */
+
+#define PTHREAD_DATAKEYS_MAX 256
+#define _POSIX_THREAD_DESTRUTOR_ITERATIONS 4
+
+/*
+ * New thread specific key type.
+ */
+struct pthread_key {
+ pthread_mutex_t mutex;
+ long count;
+ void (*destructor)();
+};
+
+typedef int pthread_key_t;
+
+/*
+ * New functions
+ */
+
+__BEGIN_DECLS
+
+int pthread_key_create __P_((pthread_key_t *, void (*routine)(void *)));
+int pthread_setspecific __P_((pthread_key_t, const void *));
+void *pthread_getspecific __P_((pthread_key_t));
+int pthread_key_delete __P_((pthread_key_t));
+
+__END_DECLS
+
diff --git a/mit-pthreads/include/pthread/state.def b/mit-pthreads/include/pthread/state.def
new file mode 100755
index 00000000000..c62d102a9f0
--- /dev/null
+++ b/mit-pthreads/include/pthread/state.def
@@ -0,0 +1,64 @@
+/* This file defines the states that a given thread can be in.
+
+ The funky macro use here is so that this one header file can also
+ define the corresponding state names, so that the two lists can't
+ get inconsistent within a given source tree. */
+
+/* The thread is runnable. */
+__pthread_defstate (PS_RUNNING, "running")
+
+/*
+ * The rest of the states are where the thread is waiting on some event.
+ * Someday maybe the "data" field will point to the object being waited for.
+ */
+
+/* Waiting for a mutex (pthread_mutex_lock()). */
+__pthread_defstate (PS_MUTEX_WAIT, "mutex")
+
+/* Waiting on a condition variable
+ (pthread_cond_wait(), or pthread_cond_timedwait()). */
+__pthread_defstate (PS_COND_WAIT, "cond")
+
+/*
+ * File descriptor stuff.
+ *
+ * File descriptors have a special lock. If it is a FULL_DUPLEX fd such as
+ * a socket or fifo then it has two mutexes, one for reads and one for writes.
+ * Some routines will even try to get both. It will always try to get the
+ * read lock first before tring to get the write. All other fds only have
+ * one mutex which all calls will get. It is displayed as if it is a read lock.
+ */
+/* Waiting on a fd read lock (fd_lock()) */
+__pthread_defstate (PS_FDLR_WAIT, "fdlr")
+
+/* Waiting on a fd write lock (fd_lock()) */
+__pthread_defstate (PS_FDLW_WAIT, "fdlw")
+
+/* Waiting for the kernel fd to have data to read,
+ (read(), readv(), recv(), recvfrom(), and recvmsg()). */
+__pthread_defstate (PS_FDR_WAIT, "fdr") /* Waiting on a kernel read */
+
+/* Waiting for the kernel fd to allow a write
+ (write(), writev(), send(), sendto(), sendmsg()) */
+__pthread_defstate (PS_FDW_WAIT, "fdw")
+
+/* Waiting for several fds in a select() */
+__pthread_defstate (PS_SELECT_WAIT, "select")
+
+/* Waiting on a sleep (sleep(), usleep() or nanosleep()). */
+__pthread_defstate (PS_SLEEP_WAIT, "sleep")
+
+/* Waiting for a child to die (wait(), waitpid(), wait3(), or wait4()). */
+__pthread_defstate (PS_WAIT_WAIT, "wait")
+
+/* Waiting on some set of signals (sigwait()) */
+__pthread_defstate (PS_SIGWAIT, "sig")
+
+/* Waiting for a thread to die (pthread_join()) */
+__pthread_defstate (PS_JOIN, "join")
+
+/* Waiting for some thread to join with me or detach me */
+__pthread_defstate (PS_DEAD, "dead")
+
+/* Waiting for some thread to create me */
+__pthread_defstate (PS_UNALLOCED, "unallocated")
diff --git a/mit-pthreads/include/pthread/types.h b/mit-pthreads/include/pthread/types.h
new file mode 100755
index 00000000000..7fdf001a0bc
--- /dev/null
+++ b/mit-pthreads/include/pthread/types.h
@@ -0,0 +1,46 @@
+#ifndef pthread_types_h
+#define pthread_types_h
+
+#include <pthread/xtypes.h>
+#include <pthread/ac-types.h>
+
+#if !defined (pthread_va_list) && defined (__NetBSD__)
+#include <stdarg.h>
+#define pthread_va_list _BSD_VA_LIST_
+#endif
+
+#if !defined (pthread_va_list) && defined (__GNUC__)
+#define __need_va_list
+#include <stdarg.h>
+#define pthread_va_list __gnuc_va_list
+#endif /* pthread_va_list, __GNUC__ */
+
+/* OSF/1 does it this way. */
+#if !defined (pthread_va_list) && defined (pthread_have_va_list_h)
+#ifndef _VA_LIST
+#define _HIDDEN_VA_LIST
+#include <va_list.h>
+#define pthread_va_list __va_list
+#else
+/* va_list has already been defined */
+#define pthread_va_list va_list
+#endif
+#endif
+
+/* If all else fails... */
+#ifndef pthread_va_list
+#include <stdarg.h>
+#define pthread_va_list va_list
+#endif
+
+#if defined(__STDC__) || defined(__GNUC__)
+#ifndef __P_
+#define __P_(protos) protos
+#endif
+#else
+#ifndef __P_
+#define __P_(protos)
+#endif
+#endif
+
+#endif /* pthread_types_h */
diff --git a/mit-pthreads/include/pthread/unistd.h b/mit-pthreads/include/pthread/unistd.h
new file mode 100755
index 00000000000..3cb07533114
--- /dev/null
+++ b/mit-pthreads/include/pthread/unistd.h
@@ -0,0 +1,159 @@
+/*-
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)unistd.h 5.13 (Berkeley) 6/17/91
+ */
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+void _exit __P_((int));
+int access __P_((const char *, int));
+int chdir __P_((const char *));
+int chown __P_((const char *, uid_t, gid_t));
+int close __P_((int));
+int dup __P_((int));
+int dup2 __P_((int, int));
+int execve __P_((const char *, char * const *, char * const *));
+pid_t fork __P_((void));
+int isatty __P_((int));
+int link __P_((const char *, const char *));
+off_t lseek __P_((int, off_t, int));
+int pipe __P_((int *));
+ssize_t read __P_((int, void *, size_t));
+u_int sleep __P_((u_int));
+char *ttyname __P_((int));
+int unlink __P_((const char *));
+ssize_t write __P_((int, const void *, size_t));
+
+/* Not implemented for threads yet */
+u_int alarm __P_((u_int));
+char *cuserid __P_((char *));
+int execl __P_((const char *, const char *, ...));
+int execle __P_((const char *, const char *, ...));
+int execlp __P_((const char *, const char *, ...));
+int execv __P_((const char *, char * const *));
+int execvp __P_((const char *, char * const *));
+long fpathconf __P_((int, int)); /* not yet */
+char *getcwd __P_((char *, size_t));
+gid_t getegid __P_((void));
+uid_t geteuid __P_((void));
+gid_t getgid __P_((void));
+int getgroups __P_((int, int *)); /* XXX (gid_t *) */
+char *getlogin __P_((void));
+pid_t getpgrp __P_((void));
+pid_t getpid __P_((void));
+pid_t getppid __P_((void));
+uid_t getuid __P_((void));
+long pathconf __P_((const char *, int)); /* not yet */
+int pause __P_((void));
+int rmdir __P_((const char *));
+int setgid __P_((gid_t));
+int setpgid __P_((pid_t, pid_t));
+pid_t setsid __P_((void));
+int setuid __P_((uid_t));
+long sysconf __P_((int)); /* not yet */
+pid_t tcgetpgrp __P_((int));
+int tcsetpgrp __P_((int, pid_t));
+
+#ifndef _POSIX_SOURCE
+
+int acct __P_((const char *));
+int async_daemon __P_((void));
+char *brk __P_((const char *));
+int chflags __P_((const char *, long));
+int chroot __P_((const char *));
+char *crypt __P_((const char *, const char *));
+int des_cipher __P_((const char *, char *, long, int));
+int des_setkey __P_((const char *key));
+int encrypt __P_((char *, int));
+void endusershell __P_((void));
+int exect __P_((const char *, char * const *, char * const *));
+int fchdir __P_((int));
+int fchflags __P_((int, long));
+int fchown __P_((int, uid_t, gid_t));
+int fsync __P_((int));
+int ftruncate __P_((int, off_t));
+int getdtablesize __P_((void));
+long gethostid __P_((void));
+int gethostname __P_((char *, int));
+mode_t getmode __P_((const void *, mode_t));
+int getpagesize __P_((void));
+char *getpass __P_((const char *));
+char *getusershell __P_((void));
+char *getwd __P_((char *)); /* obsoleted by getcwd() */
+int initgroups __P_((const char *, int));
+int mknod __P_((const char *, mode_t, dev_t));
+int mkstemp __P_((char *));
+char *mktemp __P_((char *));
+int nfssvc __P_((int));
+int nice __P_((int));
+void psignal __P_((u_int, const char *));
+extern char *sys_siglist[];
+int profil __P_((char *, int, int, int));
+int rcmd __P_((char **, int, const char *,
+ const char *, const char *, int *));
+char *re_comp __P_((const char *));
+int re_exec __P_((const char *));
+int readlink __P_((const char *, char *, int));
+int reboot __P_((int));
+int revoke __P_((const char *));
+int rresvport __P_((int *));
+int ruserok __P_((const char *, int, const char *, const char *));
+char *sbrk __P_((int));
+int setegid __P_((gid_t));
+int seteuid __P_((uid_t));
+int setgroups __P_((int, const int *));
+void sethostid __P_((long));
+int sethostname __P_((const char *, int));
+int setkey __P_((const char *));
+int setlogin __P_((const char *));
+void *setmode __P_((const char *));
+int setpgrp __P_((pid_t pid, pid_t pgrp)); /* obsoleted by setpgid() */
+int setregid __P_((int, int));
+int setreuid __P_((int, int));
+int setrgid __P_((gid_t));
+int setruid __P_((uid_t));
+void setusershell __P_((void));
+int swapon __P_((const char *));
+int symlink __P_((const char *, const char *));
+void sync __P_((void));
+int syscall __P_((int, ...));
+int truncate __P_((const char *, off_t));
+int ttyslot __P_((void));
+u_int ualarm __P_((u_int, u_int));
+void usleep __P_((u_int));
+int vfork __P_((void));
+
+#endif /* !_POSIX_SOURCE */
+__END_DECLS
+
diff --git a/mit-pthreads/include/pthread/util.h b/mit-pthreads/include/pthread/util.h
new file mode 100755
index 00000000000..aaa33a6318d
--- /dev/null
+++ b/mit-pthreads/include/pthread/util.h
@@ -0,0 +1,89 @@
+/* ==== util.h ============================================================
+ * Copyright (c) 1991, 1992, 1993 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ *
+ * Description : Header file for generic utility functions.
+ *
+ * 91/08/31 proven - Added exchange.
+ * Exchange any two objects of any size in any table.
+ *
+ * 91/10/06 proven - Cleaned out all the old junk.
+ *
+ * 91/03/06 proven - Added getint.
+ */
+
+#ifndef _PTHREAD_UTIL_H
+#define _PTHREAD_UTIL_H
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+/* Stuff only pthread internals really uses */
+#if defined(PTHREAD_KERNEL)
+
+#undef FALSE
+#undef TRUE
+
+typedef enum Boolean {
+ FALSE,
+ TRUE
+} Boolean;
+
+#define OK 0
+#define NUL '\0'
+#define NOTOK -1
+
+#if ! defined(min)
+#define min(a,b) (((a)<(b))?(a):(b))
+#define max(a,b) (((a)>(b))?(a):(b))
+#endif
+
+/* Alingn the size to the next multiple of 4 bytes */
+#define ALIGN4(size) ((size + 3) & ~3)
+#define ALIGN8(size) ((size + 7) & ~7)
+
+#ifdef DEBUG
+#define DEBUG0(s) printf(s)
+#define DEBUG1(s,a) printf(s,a)
+#define DEBUG2(s,a,b) printf(s,a,b)
+#define DEBUG3(s,a,b,c) printf(s,a,b,c)
+#else
+#define DEBUG0(s)
+#define DEBUG1(s)
+#define DEBUG2(s)
+#define DEBUG3(s)
+#endif
+
+#endif
+
+#endif
diff --git a/mit-pthreads/include/pthread/version.h b/mit-pthreads/include/pthread/version.h
new file mode 100755
index 00000000000..fda3af284d0
--- /dev/null
+++ b/mit-pthreads/include/pthread/version.h
@@ -0,0 +1,43 @@
+/* ==== version.h ============================================================
+ * Copyright (c) 1994 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ *
+ * Description : Header file for programs that what to KNOW the version.
+ *
+ * 94/08/24 proven - Added this file for pthreads.
+ */
+
+#ifndef _PTHREAD_VERSION_H
+#define _PTHREAD_VERSION_H 1
+#define _PTHREAD_VERSION_M 60
+#define _PTHREAD_VERSION_P 0
+#endif
diff --git a/mit-pthreads/include/pthread/xtypes.h b/mit-pthreads/include/pthread/xtypes.h
new file mode 100755
index 00000000000..4dcc4f04f8c
--- /dev/null
+++ b/mit-pthreads/include/pthread/xtypes.h
@@ -0,0 +1,13 @@
+/* If you need any special typedefs for function pointers &c to try
+ testing for in configure.in, define them here. */
+
+/* According to ANSI, two struct types in the same module are not
+ compatible types. So there's no way to define a type for
+ pthread_sigset_t that's compatible with sigset_t when they're
+ structure types, if we assume we can't pull in a __sigset_t or
+ something by itself from system header files.
+
+ Since that was my main reason for creating this file, there isn't
+ anything here now. If after working on this code a bit longer we
+ don't find anything else to put here, this file should just go
+ away. */
diff --git a/mit-pthreads/include/pwd.h b/mit-pthreads/include/pwd.h
new file mode 100644
index 00000000000..af945a2b8db
--- /dev/null
+++ b/mit-pthreads/include/pwd.h
@@ -0,0 +1,93 @@
+/*-
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ * (c) UNIX System Laboratories, Inc.
+ * All or some portions of this file are derived from material licensed
+ * to the University of California by American Telephone and Telegraph
+ * Co. or Unix System Laboratories, Inc. and are reproduced herein with
+ * the permission of UNIX System Laboratories, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)pwd.h 8.2 (Berkeley) 1/21/94
+ * $Id$
+ */
+
+#ifndef _PWD_H_
+#define _PWD_H_
+
+#include <sys/types.h>
+
+#ifndef _POSIX_SOURCE
+#define _PATH_PASSWD "/etc/passwd"
+#define _PATH_MASTERPASSWD "/etc/master.passwd"
+
+#define _PATH_MP_DB "/etc/pwd.db"
+#define _PATH_SMP_DB "/etc/spwd.db"
+
+#define _PATH_PWD_MKDB "/usr/sbin/pwd_mkdb"
+
+#define _PW_KEYBYNAME '1' /* stored by name */
+#define _PW_KEYBYNUM '2' /* stored by entry in the "file" */
+#define _PW_KEYBYUID '3' /* stored by uid */
+
+#define _PASSWORD_EFMT1 '_' /* extended encryption format */
+
+#define _PASSWORD_LEN 128 /* max length, not counting NULL */
+#endif
+
+struct passwd {
+ char *pw_name; /* user name */
+ char *pw_passwd; /* encrypted password */
+ int pw_uid; /* user uid */
+ int pw_gid; /* user gid */
+ time_t pw_change; /* password change time */
+ char *pw_class; /* user access class */
+ char *pw_gecos; /* Honeywell login info */
+ char *pw_dir; /* home directory */
+ char *pw_shell; /* default shell */
+ time_t pw_expire; /* account expiration */
+};
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+struct passwd *getpwuid __P_((uid_t));
+struct passwd *getpwnam __P_((const char *));
+#ifndef _POSIX_SOURCE
+struct passwd *getpwent __P_((void));
+#ifndef _XOPEN_SOURCE
+int setpassent __P_((int));
+#endif
+void setpwent __P_((void));
+void endpwent __P_((void));
+#endif
+__END_DECLS
+
+#endif /* !_PWD_H_ */
diff --git a/mit-pthreads/include/resolv.h b/mit-pthreads/include/resolv.h
new file mode 100644
index 00000000000..f6313a7229e
--- /dev/null
+++ b/mit-pthreads/include/resolv.h
@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) 1983, 1987, 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)resolv.h 5.15 (Berkeley) 4/3/91
+ * $Id$
+ */
+
+#ifndef _RESOLV_H_
+#define _RESOLV_H_
+
+#include <netinet/in.h>
+/*
+ * This is specificly for Solaris which defines NOERROR in the streams
+ * header files and defines it differently than in arpa/nameser.h
+ */
+#ifdef NOERROR
+#undef NOERROR
+#endif
+#include <arpa/nameser.h>
+
+/*
+ * revision information. this is the release date in YYYYMMDD format.
+ * it can change every day so the right thing to do with it is use it
+ * in preprocessor commands such as "#if (__RES > 19931104)". do not
+ * compare for equality; rather, use it to determine whether your resolver
+ * is new enough to contain a certain feature.
+ */
+
+#define __RES 19940703
+
+/*
+ * Resolver configuration file.
+ * Normally not present, but may contain the address of the
+ * inital name server(s) to query and the domain search list.
+ */
+
+#ifndef _PATH_RESCONF
+#define _PATH_RESCONF "/etc/resolv.conf"
+#endif
+
+/*
+ * Global defines and variables for resolver stub.
+ */
+#define MAXNS 3 /* max # name servers we'll track */
+#define MAXDFLSRCH 3 /* # default domain levels to try */
+#define MAXDNSRCH 6 /* max # domains in search path */
+#define LOCALDOMAINPARTS 2 /* min levels in name that is "local" */
+#define MAXDNSLUS 4 /* max # of host lookup types */
+
+#define RES_TIMEOUT 5 /* min. seconds between retries */
+#define MAXRESOLVSORT 10 /* number of net to sort on */
+#define RES_MAXNDOTS 15 /* should reflect bit field size */
+
+struct __res_state {
+ int retrans; /* retransmition time interval */
+ int retry; /* number of times to retransmit */
+ long options; /* option flags - see below. */
+ int nscount; /* number of name servers */
+ struct sockaddr_in nsaddr_list[MAXNS]; /* address of name server */
+#define nsaddr nsaddr_list[0] /* for backward compatibility */
+ u_short id; /* current packet id */
+ char *dnsrch[MAXDNSRCH+1]; /* components of domain to search */
+ char defdname[MAXDNAME]; /* default domain */
+ long pfcode; /* RES_PRF_ flags - see below. */
+ u_char ndots:4; /* threshold for initial abs. query */
+ u_char nsort:4; /* number of elements in sort_list[] */
+ char unused[3];
+ struct {
+ struct in_addr addr;
+ u_long mask;
+ } sort_list[MAXRESOLVSORT];
+ char lookups[MAXDNSLUS];
+};
+
+/*
+ * Resolver options
+ */
+#define RES_INIT 0x0001 /* address initialized */
+#define RES_DEBUG 0x0002 /* print debug messages */
+#define RES_AAONLY 0x0004 /* authoritative answers only */
+#define RES_USEVC 0x0008 /* use virtual circuit */
+#define RES_PRIMARY 0x0010 /* query primary server only */
+#define RES_IGNTC 0x0020 /* ignore trucation errors */
+#define RES_RECURSE 0x0040 /* recursion desired */
+#define RES_DEFNAMES 0x0080 /* use default domain name */
+#define RES_STAYOPEN 0x0100 /* Keep TCP socket open */
+#define RES_DNSRCH 0x0200 /* search up local domain tree */
+
+#define RES_DEFAULT (RES_RECURSE | RES_DEFNAMES | RES_DNSRCH)
+
+/*
+ * Resolver "pfcode" values. Used by dig.
+ */
+#define RES_PRF_STATS 0x0001
+/* 0x0002 */
+#define RES_PRF_CLASS 0x0004
+#define RES_PRF_CMD 0x0008
+#define RES_PRF_QUES 0x0010
+#define RES_PRF_ANS 0x0020
+#define RES_PRF_AUTH 0x0040
+#define RES_PRF_ADD 0x0080
+#define RES_PRF_HEAD1 0x0100
+#define RES_PRF_HEAD2 0x0200
+#define RES_PRF_TTLID 0x0400
+#define RES_PRF_HEADX 0x0800
+#define RES_PRF_QUERY 0x1000
+#define RES_PRF_REPLY 0x2000
+#define RES_PRF_INIT 0x4000
+/* 0x8000 */
+
+#define _res (*_res_status())
+#define h_errno (_res_get_error())
+
+#include <sys/cdefs.h>
+#include <stdio.h>
+
+/* Private routines shared between libc/net, named, nslookup and others. */
+#define dn_skipname __dn_skipname
+#define fp_query __fp_query
+#define hostalias __hostalias
+#define putlong __putlong
+#define putshort __putshort
+#define p_class __p_class
+#define p_time __p_time
+#define p_type __p_type
+__BEGIN_DECLS
+struct __res_state *_res_status __P_((void));
+int _res_get_error __P_((void));
+
+int __dn_skipname __P_((const u_char *, const u_char *));
+void __fp_query __P_((char *, FILE *));
+char *__hostalias __P_((const char *));
+void __putlong __P_((pthread_ipaddr_type, unsigned char *));
+void __putshort __P_((pthread_ipport_type, unsigned char *));
+char *__p_class __P_((int));
+char *__p_time __P_((unsigned long));
+char *__p_type __P_((int));
+
+int dn_comp __P_((const unsigned char *, unsigned char *, int,
+ unsigned char **, unsigned char **));
+int dn_expand __P_((const unsigned char *, const unsigned char *,
+ const unsigned char *, unsigned char *, int));
+int res_init __P_((void));
+int res_mkquery __P_((int, const char *, int, int, const char *, int,
+ const char *, char *, int));
+int res_send __P_((const char *, int, char *, int));
+__END_DECLS
+
+#endif /* !_RESOLV_H_ */
+
diff --git a/mit-pthreads/include/sched.h b/mit-pthreads/include/sched.h
new file mode 100644
index 00000000000..dcd9d4e3600
--- /dev/null
+++ b/mit-pthreads/include/sched.h
@@ -0,0 +1,57 @@
+/* ==== pthread.h ============================================================
+ * Copyright (c) 1995 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ *
+ * Description : Basic pthread header.
+ *
+ * 1.00 93/08/29 proven
+ * -Started coding this file.
+ */
+
+#ifndef _SCHED_H_
+#define _SCHED_H_
+
+#include <pthread/prio_queue.h>
+
+/*
+ * New functions
+ */
+
+__BEGIN_DECLS
+
+int sched_yield __P_((void));
+int sched_get_priority_max __P_((int));
+int sched_get_priority_min __P_((int));
+
+__END_DECLS
+
+#endif
diff --git a/mit-pthreads/include/signal.h b/mit-pthreads/include/signal.h
new file mode 100644
index 00000000000..9fb1ec6e2c8
--- /dev/null
+++ b/mit-pthreads/include/signal.h
@@ -0,0 +1,81 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)signal.h 8.3 (Berkeley) 3/30/94
+ */
+
+#ifndef _SIGNAL_H
+#define _SIGNAL_H
+
+#include <sys/types.h>
+#include <sys/cdefs.h>
+#include <sys/__signal.h>
+
+__BEGIN_DECLS
+
+int raise __P_((int));
+/* RETSIGTYPE signal __P_((int __sig, RETSIGTYPE)); */
+
+#ifndef _ANSI_SOURCE
+
+int sigfillset __P_((sigset_t *));
+int sigemptyset __P_((sigset_t *));
+int sigaddset __P_((sigset_t *, int));
+int sigdelset __P_((sigset_t *, int));
+int sigismember __P_((const sigset_t *, int));
+int sigsuspend __P_((const sigset_t *));
+int sigprocmask __P_((int, const sigset_t *, sigset_t *));
+
+/* Still need work */
+int kill __P_((pid_t, int));
+int sigaction __P_((int, const struct sigaction *, struct sigaction *));
+int sigpending __P_((sigset_t *));
+
+#ifndef _POSIX_SOURCE
+
+int killpg __P_((pid_t, int));
+int siginterrupt __P_((int, int));
+void psignal __P_((unsigned int, const char *));
+
+/* int sigpause __P_((int)); */
+/* int sigsetmask __P_((int)); */
+/* int sigblock __P_((int)); */
+/* int sigreturn __P_((struct sigcontext *)); */
+/* int sigvec __P_((int, struct sigvec *, struct sigvec *)); */
+/* int sigstack __P_((const struct sigstack *, struct sigstack *)); */
+
+#endif /* !_POSIX_SOURCE */
+#endif /* !_ANSI_SOURCE */
+
+__END_DECLS
+
+#endif /* !_USER_SIGNAL_H */
diff --git a/mit-pthreads/include/stdio.h b/mit-pthreads/include/stdio.h
new file mode 100644
index 00000000000..538d4685f3f
--- /dev/null
+++ b/mit-pthreads/include/stdio.h
@@ -0,0 +1,371 @@
+/* ==== stdio.h ============================================================
+ * Copyright (c) 1990 The Regents of the University of California.
+ * Copyright (c) 1993 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)stdio.h 5.17 (Berkeley) 6/3/91
+ * $Id$
+ */
+
+#ifndef _STDIO_H_
+#define _STDIO_H_
+
+#include <sys/cdefs.h>
+#include <pthread/types.h>
+#include <pthread/posix.h>
+#include <sys/__stdio.h>
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#define _FSTDIO /* Define for new stdio with functions. */
+
+/*
+ * NB: to fit things in six character monocase externals, the stdio
+ * code uses the prefix `__s' for stdio objects, typically followed
+ * by a three-character attempt at a mnemonic.
+ */
+
+/* stdio buffers */
+struct __sbuf {
+ unsigned char *_base;
+ int _size;
+};
+
+/*
+ * stdio state variables.
+ *
+ * The following always hold:
+ *
+ * if (_flags&(__SLBF|__SWR)) == (__SLBF|__SWR),
+ * _lbfsize is -_bf._size, else _lbfsize is 0
+ * if _flags&__SRD, _w is 0
+ * if _flags&__SWR, _r is 0
+ *
+ * This ensures that the getc and putc macros (or inline functions) never
+ * try to write or read from a file that is in `read' or `write' mode.
+ * (Moreover, they can, and do, automatically switch from read mode to
+ * write mode, and back, on "r+" and "w+" files.)
+ *
+ * _lbfsize is used only to make the inline line-buffered output stream
+ * code as compact as possible.
+ *
+ * _ub, _up, and _ur are used when ungetc() pushes back more characters
+ * than fit in the current _bf, or when ungetc() pushes back a character
+ * that does not match the previous one in _bf. When this happens,
+ * _ub._base becomes non-nil (i.e., a stream has ungetc() data iff
+ * _ub._base!=NULL) and _up and _ur save the current values of _p and _r.
+ */
+typedef struct __sFILE {
+ unsigned char *_p; /* current position in (some) buffer */
+ int _r; /* read space left for getc() */
+ int _w; /* write space left for putc() */
+ short _flags; /* flags, below; this FILE is free if 0 */
+ short _file; /* fileno, if Unix descriptor, else -1 */
+ struct __sbuf _bf; /* the buffer (at least 1 byte, if !NULL) */
+ int _lbfsize; /* 0 or -_bf._size, for inline putc */
+
+ /* separate buffer for long sequences of ungetc() */
+ struct __sbuf _ub; /* ungetc buffer */
+ unsigned char *_up; /* saved _p when _p is doing ungetc data */
+ int _ur; /* saved _r when _r is counting ungetc data */
+
+ /* tricks to meet minimum requirements even when malloc() fails */
+ unsigned char _ubuf[3]; /* guarantee an ungetc() buffer */
+ unsigned char _nbuf[1]; /* guarantee a getc() buffer */
+
+ /* separate buffer for fgetline() when line crosses buffer boundary */
+ struct __sbuf _lb; /* buffer for fgetline() */
+
+ /* Unix stdio files get aligned to block boundaries on fseek() */
+ int _blksize; /* stat.st_blksize (may be != _bf._size) */
+ int _offset; /* current lseek offset */
+} FILE;
+
+__BEGIN_DECLS
+extern FILE __sF[];
+__END_DECLS
+
+#define __SLBF 0x0001 /* line buffered */
+#define __SNBF 0x0002 /* unbuffered */
+#define __SRD 0x0004 /* OK to read */
+#define __SWR 0x0008 /* OK to write */
+ /* RD and WR are never simultaneously asserted */
+#define __SRW 0x0010 /* open for reading & writing */
+#define __SEOF 0x0020 /* found EOF */
+#define __SERR 0x0040 /* found error */
+#define __SMBF 0x0080 /* _buf is from malloc */
+#define __SAPP 0x0100 /* fdopen()ed in append mode */
+#define __SSTR 0x0200 /* this is an sprintf/snprintf string */
+#define __SOPT 0x0400 /* do fseek() optimisation */
+#define __SNPT 0x0800 /* do not do fseek() optimisation */
+#define __SOFF 0x1000 /* set iff _offset is in fact correct */
+#define __SMOD 0x2000 /* true => fgetline modified _p text */
+
+/*
+ * The following three definitions are for ANSI C, which took them
+ * from System V, which brilliantly took internal interface macros and
+ * made them official arguments to setvbuf(), without renaming them.
+ * Hence, these ugly _IOxxx names are *supposed* to appear in user code.
+ *
+ * Although numbered as their counterparts above, the implementation
+ * does not rely on this.
+ */
+#define _IOFBF 0 /* setvbuf should set fully buffered */
+#define _IOLBF 1 /* setvbuf should set line buffered */
+#define _IONBF 2 /* setvbuf should set unbuffered */
+
+#define BUFSIZ 1024 /* size of buffer used by setbuf */
+#define EOF (-1)
+
+/*
+ * FOPEN_MAX is a minimum maximum, and should be the number of descriptors
+ * that the kernel can provide without allocation of a resource that can
+ * fail without the process sleeping. Do not use this for anything.
+ */
+#define FOPEN_MAX 20 /* must be <= OPEN_MAX <sys/syslimits.h> */
+#define FILENAME_MAX 1024 /* must be <= PATH_MAX <sys/syslimits.h> */
+
+/* System V/ANSI C; this is the wrong way to do this, do *not* use these. */
+#ifndef _ANSI_SOURCE
+#define P_tmpdir "/var/tmp/"
+#endif
+#define L_tmpnam 1024 /* XXX must be == PATH_MAX */
+#ifndef TMP_MAX
+#define TMP_MAX 308915776
+#endif
+
+#ifndef SEEK_SET
+#define SEEK_SET 0 /* set file offset to offset */
+#endif
+#ifndef SEEK_CUR
+#define SEEK_CUR 1 /* set file offset to current plus offset */
+#endif
+#ifndef SEEK_END
+#define SEEK_END 2 /* set file offset to EOF plus offset */
+#endif
+
+#define stdin (&__sF[0])
+#define stdout (&__sF[1])
+#define stderr (&__sF[2])
+
+/*
+ * Functions defined in ANSI C standard.
+ */
+__BEGIN_DECLS
+void clearerr __P_((FILE *));
+int fclose __P_((FILE *));
+int feof __P_((FILE *));
+int ferror __P_((FILE *));
+int fflush __P_((FILE *));
+int fgetc __P_((FILE *));
+int fgetpos __P_((FILE *, fpos_t *));
+char * fgets __P_((char *, size_t, FILE *));
+FILE * fopen __P_((const char *, const char *));
+int fprintf __P_((FILE *, const char *, ...));
+int fputc __P_((int, FILE *));
+int fputs __P_((const char *, FILE *));
+size_t fread __P_((void *, size_t, size_t, FILE *));
+FILE * freopen __P_((const char *, const char *, FILE *));
+int fscanf __P_((FILE *, const char *, ...));
+int fseek __P_((FILE *, long, int));
+int fsetpos __P_((FILE *, const fpos_t *));
+long ftell __P_((const FILE *));
+size_t fwrite __P_((const void *, size_t, size_t, FILE *));
+int getc __P_((FILE *));
+int getchar __P_((void));
+char * gets __P_((char *));
+
+#if !defined(_ANSI_SOURCE) && !defined(_POSIX_SOURCE)
+extern int sys_nerr; /* perror(3) external variables */
+/* Under NetBSD and BSD 4.4, at least, this is expected to be a const
+ array of pointers to const. If you take `const' back out of this
+ declaration, please make it conditional on __NetBSD__ and bsd4_4. */
+#ifdef HAVE_SYS_ERRLIST_WITHOUT_CONST
+extern char *sys_errlist[];
+#else
+extern const char *const sys_errlist[];
+#endif
+#endif
+
+void perror __P_((const char *));
+int printf __P_((const char *, ...));
+int putc __P_((int, FILE *));
+int putchar __P_((int));
+int puts __P_((const char *));
+int remove __P_((const char *));
+int rename __P_((const char *, const char *));
+void rewind __P_((FILE *));
+int scanf __P_((const char *, ...));
+void setbuf __P_((FILE *, char *));
+int setvbuf __P_((FILE *, char *, int, size_t));
+int sprintf __P_((char *, const char *, ...));
+int sscanf __P_((const char *, const char *, ...));
+FILE * tmpfile __P_((void));
+char * tmpnam __P_((char *));
+int ungetc __P_((int, FILE *));
+int vfprintf __P_((FILE *, const char *, pthread_va_list));
+int vprintf __P_((const char *, pthread_va_list));
+int vsprintf __P_((char *, const char *, pthread_va_list));
+char *mprintf __P_((const char *, ...));
+char *vmprintf __P_((const char *, pthread_va_list));
+__END_DECLS
+
+/*
+ * Functions defined in POSIX 1003.1.
+ */
+#ifndef _ANSI_SOURCE
+#define L_ctermid 1024 /* size for ctermid(); PATH_MAX */
+#define L_cuserid 9 /* size for cuserid(); UT_NAMESIZE + 1 */
+
+__BEGIN_DECLS
+char * ctermid __P_((char *));
+char * cuserid __P_((char *));
+FILE * fdopen __P_((int, const char *));
+int fileno __P_((FILE *));
+__END_DECLS
+#endif /* not ANSI */
+
+/*
+ * Functions defined in POSIX 1003.4a. (1c)
+ */
+#ifndef _ANSI_SOURCE
+__BEGIN_DECLS
+void flockfile __P_((FILE *));
+void funlockfile __P_((FILE *));
+int ftrylockfile __P_((FILE *));
+__END_DECLS
+#endif /* not ANSI */
+
+/*
+ * Routines that are purely local.
+ */
+#if !defined (_ANSI_SOURCE) && !defined(_POSIX_SOURCE)
+__BEGIN_DECLS
+char *fgetline __P_((FILE *, size_t *));
+int fpurge __P_((FILE *));
+int getw __P_((FILE *));
+int pclose __P_((FILE *));
+FILE *popen __P_((const char *, const char *));
+int putw __P_((int, FILE *));
+void setbuffer __P_((FILE *, char *, int));
+int setlinebuf __P_((FILE *));
+char *tempnam __P_((const char *, const char *));
+int snprintf __P_((char *, size_t, const char *, ...));
+int vsnprintf __P_((char *, size_t, const char *, pthread_va_list));
+int vscanf __P_((const char *, pthread_va_list));
+int vsscanf __P_((const char *, const char *, pthread_va_list));
+__END_DECLS
+
+/*
+ * This is a #define because the function is used internally and
+ * (unlike vfscanf) the name __svfscanf is guaranteed not to collide
+ * with a user function when _ANSI_SOURCE or _POSIX_SOURCE is defined.
+ */
+#define vfscanf __svfscanf
+
+/*
+ * Stdio function-access interface.
+ */
+__BEGIN_DECLS
+FILE *funopen __P_((const void *,
+ int (*)(void *, char *, int),
+ int (*)(void *, const char *, int),
+ fpos_t (*)(void *, fpos_t, int),
+ int (*)(void *)));
+__END_DECLS
+#define fropen(cookie, fn) funopen(cookie, fn, 0, 0, 0)
+#define fwopen(cookie, fn) funopen(cookie, 0, fn, 0, 0)
+#endif /* !_ANSI_SOURCE && !_POSIX_SOURCE */
+
+/*
+ * Functions internal to the implementation.
+ */
+__BEGIN_DECLS
+int __srget __P_((FILE *));
+int __svfscanf __P_((FILE *, const char *, pthread_va_list));
+int __swbuf __P_((int, FILE *));
+__END_DECLS
+
+/*
+ * The __sfoo macros are here so that we can
+ * define function versions in the C library.
+ */
+#define __sgetc(p) (--(p)->_r < 0 ? __srget(p) : (int)(*(p)->_p++))
+
+__BEGIN_DECLS
+int __getc __P_((FILE *));
+__END_DECLS
+
+#define getc(fp) __getc(fp)
+#define getchar() getc(stdin)
+#define getc_unlocked(fp) __sgetc(fp)
+#define getchar_unlocked() getc_unlocked(stdin)
+
+#ifdef __CAN_DO_EXTERN_INLINE
+__INLINE int __sputc(int _c, FILE *_p)
+{
+ if (--_p->_w >= 0 || (_p->_w >= _p->_lbfsize && (char)_c != '\n'))
+ return (*_p->_p++ = _c);
+ else
+ return (__swbuf(_c, _p));
+}
+#else
+__BEGIN_DECLS
+int __sputc __P_((int, FILE *));
+__END_DECLS
+#endif
+
+__BEGIN_DECLS
+int __putc __P_((int, FILE *));
+__END_DECLS
+
+#define putc(x, fp) __putc(x, fp)
+#define putchar(x) putc(x, stdout)
+#define putc_unlocked(x, fp) __sputc(x, fp)
+#define putchar_unlocked(x) putc_unlocked(x, stdout)
+
+#define __sfeof(p) (((p)->_flags & __SEOF) != 0)
+#define __sferror(p) (((p)->_flags & __SERR) != 0)
+#define __sfileno(p) ((p)->_file)
+
+#define feof(p) __sfeof(p)
+#define ferror(p) __sferror(p)
+
+#ifndef _ANSI_SOURCE
+#define fileno(p) __sfileno(p)
+#endif
+
+#endif
diff --git a/mit-pthreads/include/stdlib.h b/mit-pthreads/include/stdlib.h
new file mode 100644
index 00000000000..77f84ffa0bb
--- /dev/null
+++ b/mit-pthreads/include/stdlib.h
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * (c) UNIX System Laboratories, Inc.
+ * All or some portions of this file are derived from material licensed
+ * to the University of California by American Telephone and Telegraph
+ * Co. or Unix System Laboratories, Inc. and are reproduced herein with
+ * the permission of UNIX System Laboratories, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)time.h 5.12 (Berkeley) 3/9/91
+ * $Id$
+ */
+
+#ifndef _STDLIB_H_
+#define _STDLIB_H_
+
+#include <sys/__stdlib.h>
+
+/* Returned by `div'. */
+typedef struct
+ {
+ int quot; /* Quotient. */
+ int rem; /* Remainder. */
+ } div_t;
+
+/* Returned by `ldiv'. */
+typedef struct
+ {
+ long quot; /* Quotient. */
+ long rem; /* Remainder. */
+ } ldiv_t;
+
+#ifndef RAND_MAX
+#define RAND_MAX 2147483647
+#endif
+
+#define EXIT_FAILURE 1 /* Failing exit status. */
+#define EXIT_SUCCESS 0 /* Successful exit status. */
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+double atof __P_((const char *));
+int atoi __P_((const char *));
+long atol __P_((const char *));
+double strtod __P_((const char *, char **));
+long strtol __P_((const char *, char **, int));
+unsigned long strtoul __P_((const char *, char **, int));
+
+int rand __P_((void));
+void srand __P_((unsigned int));
+
+long random __P_((void));
+void srandom __P_((unsigned int));
+char * initstate __P_((unsigned int, char *, int));
+char * setstate __P_((char *));
+
+void * malloc __P_((size_t));
+void * realloc __P_((void *, size_t));
+void * calloc __P_((size_t, size_t));
+void free __P_((void *));
+
+__NORETURN void abort __P_((void));
+int atexit __P_((void (* __func)() ));
+__NORETURN void exit __P_((int));
+int system __P_((const char *));
+
+extern char ** environ;
+
+char * getenv __P_((const char *));
+int putenv __P_((const char *));
+int setenv __P_((const char *, const char *, int));
+void unsetenv __P_((const char *));
+
+void * bsearch __P_((const void *, const void *, size_t, size_t,
+ int (* __func)__P_((const void *, const void *)) ));
+void qsort __P_((void *, size_t, size_t,
+ int (* __func)__P_((const void *, const void *)) ));
+
+int abs __P_((int));
+long labs __P_((long));
+div_t div __P_((int, int));
+ldiv_t ldiv __P_((long, long));
+
+void * memchr __P_((const void *, int, size_t));
+
+/* Stuff to do */
+int mblen __P_((const char *, size_t));
+int mbtowc __P_((wchar_t *, const char *, size_t));
+int wctomb __P_((char *, wchar_t));
+size_t mbstowcs __P_((wchar_t *, const char *, size_t));
+size_t wcstombs __P_((char *, const wchar_t *, size_t));
+
+
+__END_DECLS
+
+#endif /* !_STDLIB_H_ */
diff --git a/mit-pthreads/include/string.h b/mit-pthreads/include/string.h
new file mode 100644
index 00000000000..4143a1cfec7
--- /dev/null
+++ b/mit-pthreads/include/string.h
@@ -0,0 +1,85 @@
+/* $NetBSD: string.h,v 1.6 1994/10/26 00:56:30 cgd Exp $ */
+
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)string.h 5.10 (Berkeley) 3/9/91
+ */
+
+#ifndef _STRING_H_
+#define _STRING_H_
+#include <sys/cdefs.h>
+#include <pthread/types.h>
+#include <pthread/posix.h>
+#include <sys/__string.h>
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+__BEGIN_DECLS
+void *memchr __P_((const void *, int, size_t));
+int memcmp __P_((const void *, const void *, size_t));
+void *memcpy __P_((void *, const void *, size_t));
+void *memmove __P_((void *, const void *, size_t));
+void *memset __P_((void *, int, size_t));
+char *strcat __P_((char *, const char *));
+char *strchr __P_((const char *, int));
+int strcmp __P_((const char *, const char *));
+int strcoll __P_((const char *, const char *));
+char *strcpy __P_((char *, const char *));
+size_t strcspn __P_((const char *, const char *));
+char *strerror __P_((int));
+size_t strlen __P_((const char *));
+char *strncat __P_((char *, const char *, size_t));
+int strncmp __P_((const char *, const char *, size_t));
+char *strncpy __P_((char *, const char *, size_t));
+char *strpbrk __P_((const char *, const char *));
+char *strrchr __P_((const char *, int));
+size_t strspn __P_((const char *, const char *));
+char *strstr __P_((const char *, const char *));
+char *strtok __P_((char *, const char *));
+char *strtok_r __P_((char *, const char *, char **));
+size_t strxfrm __P_((char *, const char *, size_t));
+
+/* Nonstandard routines common to all pthreads supported platforms */
+#if !defined(_ANSI_SOURCE) && !defined(_POSIX_SOURCE)
+int ffs __P_((int));
+void *memccpy __P_((void *, const void *, int, size_t));
+int strcasecmp __P_((const char *, const char *));
+int strncasecmp __P_((const char *, const char *, size_t));
+char *strsignal __P_((int));
+void swab __P_((const void *, void *, size_t));
+#endif
+__END_DECLS
+
+#endif /* _STRING_H_ */
diff --git a/mit-pthreads/include/syslog.h b/mit-pthreads/include/syslog.h
new file mode 100644
index 00000000000..31b42285fc1
--- /dev/null
+++ b/mit-pthreads/include/syslog.h
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 1982, 1986 Regents of the University of California.
+ * All rights reserved. The Berkeley software License Agreement
+ * specifies the terms and conditions for redistribution.
+ *
+ * @(#)syslog.h 7.8 (Berkeley) 5/26/88
+ */
+
+#ifndef SYSLOG_H
+#define SYSLOG_H
+
+/* Added __[BEGIN/END]_DECLS so this file would work with C++. (mevans) */
+#include <sys/cdefs.h>
+#include <stdarg.h>
+
+/* Discipline: openlog(), closelog(), and setlogmask() are not thread-safe
+ * and should only be called when other threads will not be calling syslog
+ * functions. syslog() and vsyslog() are thread-safe and may be called
+ * asynchronously, even if openlog() has not been called. */
+
+/*
+ * Facility codes
+ */
+
+#define LOG_KERN (0<<3) /* kernel messages */
+#define LOG_USER (1<<3) /* random user-level messages */
+#define LOG_MAIL (2<<3) /* mail system */
+#define LOG_DAEMON (3<<3) /* system daemons */
+#define LOG_AUTH (4<<3) /* security/authorization messages */
+#define LOG_SYSLOG (5<<3) /* messages generated internally by syslogd */
+#define LOG_LPR (6<<3) /* line printer subsystem */
+#define LOG_NEWS (7<<3) /* network news subsystem */
+#define LOG_UUCP (8<<3) /* UUCP subsystem */
+ /* other codes through 15 reserved for system use */
+#define LOG_LOCAL0 (16<<3) /* reserved for local use */
+#define LOG_LOCAL1 (17<<3) /* reserved for local use */
+#define LOG_LOCAL2 (18<<3) /* reserved for local use */
+#define LOG_LOCAL3 (19<<3) /* reserved for local use */
+#define LOG_LOCAL4 (20<<3) /* reserved for local use */
+#define LOG_LOCAL5 (21<<3) /* reserved for local use */
+#define LOG_LOCAL6 (22<<3) /* reserved for local use */
+#define LOG_LOCAL7 (23<<3) /* reserved for local use */
+
+#define LOG_NFACILITIES 24 /* maximum number of facilities */
+#define LOG_FACMASK 0x03f8 /* mask to extract facility part */
+
+#define LOG_FAC(p) (((p) & LOG_FACMASK) >> 3) /* facility of pri */
+
+/*
+ * Priorities (these are ordered)
+ */
+
+#define LOG_EMERG 0 /* system is unusable */
+#define LOG_ALERT 1 /* action must be taken immediately */
+#define LOG_CRIT 2 /* critical conditions */
+#define LOG_ERR 3 /* error conditions */
+#define LOG_WARNING 4 /* warning conditions */
+#define LOG_NOTICE 5 /* normal but signification condition */
+#define LOG_INFO 6 /* informational */
+#define LOG_DEBUG 7 /* debug-level messages */
+
+#define LOG_PRIMASK 0x0007 /* mask to extract priority part (internal) */
+#define LOG_PRI(p) ((p) & LOG_PRIMASK) /* extract priority */
+
+#define LOG_MAKEPRI(fac, pri) (((fac) << 3) | (pri))
+
+#ifdef KERNEL
+#define LOG_PRINTF -1 /* pseudo-priority to indicate use of printf */
+#endif
+
+/*
+ * arguments to setlogmask.
+ */
+#define LOG_MASK(pri) (1 << (pri)) /* mask for one priority */
+#define LOG_UPTO(pri) ((1 << ((pri)+1)) - 1) /* all priorities through pri */
+
+/*
+ * Option flags for openlog.
+ *
+ * LOG_ODELAY no longer does anything; LOG_NDELAY is the
+ * inverse of what it used to be.
+ */
+#define LOG_PID 0x01 /* log the pid with each message */
+#define LOG_CONS 0x02 /* log on the console if errors in sending */
+#define LOG_ODELAY 0x04 /* delay open until first syslog() (default) */
+#define LOG_NDELAY 0x08 /* don't delay open */
+#define LOG_NOWAIT 0x10 /* if forking to log on console, don't wait() */
+
+__BEGIN_DECLS
+
+/* Syslogging functions. */
+void syslog(int pri, char *fmt, ...);
+void vsyslog(int pri, char *fmt, va_list args);
+void openlog(char *ident, int logstat, int logfac);
+void closelog(void);
+int setlogmask(int pmask);
+
+__END_DECLS
+
+#endif
+
diff --git a/mit-pthreads/include/time.h b/mit-pthreads/include/time.h
new file mode 100644
index 00000000000..614bbeb2a59
--- /dev/null
+++ b/mit-pthreads/include/time.h
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * (c) UNIX System Laboratories, Inc.
+ * All or some portions of this file are derived from material licensed
+ * to the University of California by American Telephone and Telegraph
+ * Co. or Unix System Laboratories, Inc. and are reproduced herein with
+ * the permission of UNIX System Laboratories, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)time.h 5.12 (Berkeley) 3/9/91
+ * $Id$
+ */
+
+#ifndef _TIME_H_
+#define _TIME_H_
+
+#include <sys/__time.h>
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#ifndef __hpux__
+struct tm {
+ int tm_sec; /* seconds after the minute [0-60] */
+ int tm_min; /* minutes after the hour [0-59] */
+ int tm_hour; /* hours since midnight [0-23] */
+ int tm_mday; /* day of the month [1-31] */
+ int tm_mon; /* months since January [0-11] */
+ int tm_year; /* years since 1900 */
+ int tm_wday; /* days since Sunday [0-6] */
+ int tm_yday; /* days since January 1 [0-365] */
+ int tm_isdst; /* Daylight Savings Time flag */
+ long tm_gmtoff; /* offset from CUT in seconds */
+ char *tm_zone; /* timezone abbreviation */
+};
+#endif /* __hpux__ */
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+/* clock_t clock __P_((void)); */
+
+char * asctime __P_((const struct tm *));
+double difftime __P_((time_t, time_t));
+char * ctime __P_((const time_t *));
+struct tm * gmtime __P_((const time_t *));
+struct tm * localtime __P_((const time_t *));
+
+char * asctime_r __P_((const struct tm *, char *));
+char * ctime_r __P_((const time_t *, char *));
+struct tm * gmtime_r __P_((const time_t *, struct tm *));
+struct tm * localtime_r __P_((const time_t *, struct tm *));
+
+time_t mktime __P_((struct tm *));
+
+/* size_t strftime __P_((char *, size_t, const char *, const struct tm *)); */
+time_t time __P_((time_t *));
+
+#if !defined(_ANSI_SOURCE)
+/* #define CLK_TCK 100 */
+extern char *tzname[2];
+void tzset __P_((void));
+#endif /* not ANSI */
+
+#if !defined(_ANSI_SOURCE) && !defined(_POSIX_SOURCE)
+/* char *timezone __P_((int, int)); */
+void tzsetwall __P_((void));
+#endif /* neither ANSI nor POSIX */
+
+__END_DECLS
+
+#endif /* !_TIME_H_ */
diff --git a/mit-pthreads/include/timers.h b/mit-pthreads/include/timers.h
new file mode 100644
index 00000000000..9a0196a3631
--- /dev/null
+++ b/mit-pthreads/include/timers.h
@@ -0,0 +1,45 @@
+/* ==== timers.h ============================================================
+ * Copyright (c) 1994 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ *
+ * Description : Basic timers header.
+ *
+ * 1.00 94/06/13 proven
+ * -Started coding this file.
+ */
+
+#ifndef _TIMERS_H_
+#define _TIMERS_H_
+
+#include <sys/timers.h>
+
+#endif
diff --git a/mit-pthreads/include/tzfile.h b/mit-pthreads/include/tzfile.h
new file mode 100644
index 00000000000..7a486302e10
--- /dev/null
+++ b/mit-pthreads/include/tzfile.h
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 1988 Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Arthur David Olson of the National Cancer Institute.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)tzfile.h 5.10 (Berkeley) 4/3/91
+ * $Id$
+ */
+
+#ifndef _TZFILE_H_
+#define _TZFILE_H_
+
+#include <pthread/paths.h>
+
+/*
+ * Information about time zone files.
+ */
+#define TZDIR _PATH_TZDIR
+#define TZDEFAULT _PATH_TZFILE
+#define TZDEFRULES "posixrules"
+
+/*
+** Each file begins with. . .
+*/
+
+struct tzhead {
+ char tzh_reserved[24]; /* reserved for future use */
+ char tzh_ttisstdcnt[4]; /* coded number of trans. time flags */
+ char tzh_leapcnt[4]; /* coded number of leap seconds */
+ char tzh_timecnt[4]; /* coded number of transition times */
+ char tzh_typecnt[4]; /* coded number of local time types */
+ char tzh_charcnt[4]; /* coded number of abbr. chars */
+};
+
+/*
+** . . .followed by. . .
+**
+** tzh_timecnt (char [4])s coded transition times a la time(2)
+** tzh_timecnt (unsigned char)s types of local time starting at above
+** tzh_typecnt repetitions of
+** one (char [4]) coded GMT offset in seconds
+** one (unsigned char) used to set tm_isdst
+** one (unsigned char) that's an abbreviation list index
+** tzh_charcnt (char)s '\0'-terminated zone abbreviations
+** tzh_leapcnt repetitions of
+** one (char [4]) coded leap second transition times
+** one (char [4]) total correction after above
+** tzh_ttisstdcnt (char)s indexed by type; if TRUE, transition
+** time is standard time, if FALSE,
+** transition time is wall clock time
+** if absent, transition times are
+** assumed to be wall clock time
+*/
+
+/*
+** In the current implementation, "tzset()" refuses to deal with files that
+** exceed any of the limits below.
+*/
+
+/*
+** The TZ_MAX_TIMES value below is enough to handle a bit more than a
+** year's worth of solar time (corrected daily to the nearest second) or
+** 138 years of Pacific Presidential Election time
+** (where there are three time zone transitions every fourth year).
+*/
+#define TZ_MAX_TIMES 370
+
+#define NOSOLAR /* 4BSD doesn't currently handle solar time */
+
+#ifndef NOSOLAR
+#define TZ_MAX_TYPES 256 /* Limited by what (unsigned char)'s can hold */
+#else
+#define TZ_MAX_TYPES 10 /* Maximum number of local time types */
+#endif
+
+#define TZ_MAX_CHARS 50 /* Maximum number of abbreviation characters */
+
+#define TZ_MAX_LEAPS 50 /* Maximum number of leap second corrections */
+
+#define SECSPERMIN 60
+#define MINSPERHOUR 60
+#define HOURSPERDAY 24
+#define DAYSPERWEEK 7
+#define DAYSPERNYEAR 365
+#define DAYSPERLYEAR 366
+#define SECSPERHOUR (SECSPERMIN * MINSPERHOUR)
+#define SECSPERDAY ((long) SECSPERHOUR * HOURSPERDAY)
+#define MONSPERYEAR 12
+
+#define TM_SUNDAY 0
+#define TM_MONDAY 1
+#define TM_TUESDAY 2
+#define TM_WEDNESDAY 3
+#define TM_THURSDAY 4
+#define TM_FRIDAY 5
+#define TM_SATURDAY 6
+
+#define TM_JANUARY 0
+#define TM_FEBRUARY 1
+#define TM_MARCH 2
+#define TM_APRIL 3
+#define TM_MAY 4
+#define TM_JUNE 5
+#define TM_JULY 6
+#define TM_AUGUST 7
+#define TM_SEPTEMBER 8
+#define TM_OCTOBER 9
+#define TM_NOVEMBER 10
+#define TM_DECEMBER 11
+
+#define TM_YEAR_BASE 1900
+
+#define EPOCH_YEAR 1970
+#define EPOCH_WDAY TM_THURSDAY
+
+/*
+** Accurate only for the past couple of centuries;
+** that will probably do.
+*/
+
+#define isleap(y) (((y) % 4) == 0 && ((y) % 100) != 0 || ((y) % 400) == 0)
+
+#endif /* !_TZFILE_H_ */
+
diff --git a/mit-pthreads/include/unistd.h b/mit-pthreads/include/unistd.h
new file mode 100644
index 00000000000..213aa983172
--- /dev/null
+++ b/mit-pthreads/include/unistd.h
@@ -0,0 +1,183 @@
+/*-
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)unistd.h 5.13 (Berkeley) 6/17/91
+ */
+
+#ifndef _UNISTD_H_
+#define _UNISTD_H_
+
+#include <sys/cdefs.h>
+#include <sys/__unistd.h>
+
+#define R_OK 4
+#define W_OK 2
+#define X_OK 1
+#define F_OK 0
+
+#ifndef SEEK_SET
+#define SEEK_SET 0 /* set file offset to offset */
+#endif
+#ifndef SEEK_CUR
+#define SEEK_CUR 1 /* set file offset to current plus offset */
+#endif
+#ifndef SEEK_END
+#define SEEK_END 2 /* set file offset to EOF plus offset */
+#endif
+
+#define STDIN_FILENO 0 /* standard input file descriptor */
+#define STDOUT_FILENO 1 /* standard output file descriptor */
+#define STDERR_FILENO 2 /* standard error file descriptor */
+
+__BEGIN_DECLS
+void _exit __P_((int));
+int access __P_((const char *, int));
+int chdir __P_((const char *));
+int chown __P_((const char *, uid_t, gid_t));
+int close __P_((int));
+int dup __P_((int));
+int dup2 __P_((int, int));
+int execve __P_((const char *, char * const *, char * const *));
+pid_t fork __P_((void));
+int isatty __P_((int));
+int link __P_((const char *, const char *));
+off_t lseek __P_((int, off_t, int));
+int pipe __P_((int *));
+ssize_t read __P_((int, void *, size_t));
+unsigned sleep __P_((unsigned));
+char *ttyname __P_((int));
+int unlink __P_((const char *));
+ssize_t write __P_((int, const void *, size_t));
+
+/* Not implemented for threads yet */
+unsigned alarm __P_((unsigned));
+char *cuserid __P_((char *));
+int execl __P_((const char *, const char *, ...));
+int execle __P_((const char *, const char *, ...));
+int execlp __P_((const char *, const char *, ...));
+int execv __P_((const char *, char * const *));
+int execvp __P_((const char *, char * const *));
+long fpathconf __P_((int, int)); /* not yet */
+char *getcwd __P_((char *, size_t));
+gid_t getegid __P_((void));
+uid_t geteuid __P_((void));
+gid_t getgid __P_((void));
+int getgroups __P_((int, gid_t *)); /* XXX (gid_t *) */
+char *getlogin __P_((void));
+pid_t getpgrp __P_((void));
+pid_t getpid __P_((void));
+pid_t getppid __P_((void));
+uid_t getuid __P_((void));
+long pathconf __P_((const char *, int)); /* not yet */
+int pause __P_((void));
+int rmdir __P_((const char *));
+int setgid __P_((gid_t));
+int setpgid __P_((pid_t, pid_t));
+pid_t setsid __P_((void));
+int setuid __P_((uid_t));
+long sysconf __P_((int)); /* not yet */
+pid_t tcgetpgrp __P_((int));
+int tcsetpgrp __P_((int, pid_t));
+
+#ifndef _POSIX_SOURCE
+
+int acct __P_((const char *));
+int async_daemon __P_((void));
+char *brk __P_((const char *));
+/* int chflags __P_((const char *, long)); */
+int chroot __P_((const char *));
+char *crypt __P_((const char *, const char *));
+int des_cipher __P_((const char *, char *, long, int));
+void des_setkey __P_((const char *key));
+void encrypt __P_((char *, int));
+void endusershell __P_((void));
+int exect __P_((const char *, char * const *, char * const *));
+int fchdir __P_((int));
+/* int fchflags __P_((int, long)); */
+int fchown __P_((int, uid_t, gid_t));
+int fsync __P_((int));
+int ftruncate __P_((int, off_t));
+int getdtablesize __P_((void));
+long gethostid __P_((void));
+int gethostname __P_((char *, int));
+mode_t getmode __P_((const void *, mode_t));
+int getpagesize __P_((void));
+char *getpass __P_((const char *));
+char *getusershell __P_((void));
+char *getwd __P_((char *)); /* obsoleted by getcwd() */
+int initgroups __P_((const char *, gid_t));
+int mknod __P_((const char *, mode_t, dev_t));
+int mkstemp __P_((char *));
+char *mktemp __P_((char *));
+int nfssvc __P_((int));
+int nice __P_((int));
+void psignal __P_((unsigned, const char *));
+/* extern char *sys_siglist[]; */
+int profil __P_((char *, int, int, int));
+int rcmd __P_((char **, int, const char *,
+ const char *, const char *, int *));
+char *re_comp __P_((const char *));
+int re_exec __P_((const char *));
+int readlink __P_((const char *, char *, int));
+int reboot __P_((int));
+int revoke __P_((const char *));
+int rresvport __P_((int *));
+int ruserok __P_((const char *, int, const char *, const char *));
+char *sbrk __P_((int));
+int setegid __P_((gid_t));
+int seteuid __P_((uid_t));
+int setgroups __P_((int, const gid_t *));
+void sethostid __P_((long));
+int sethostname __P_((const char *, int));
+void setkey __P_((const char *));
+int setlogin __P_((const char *));
+void *setmode __P_((const char *));
+int setpgrp __P_((pid_t pid, pid_t pgrp)); /* obsoleted by setpgid() */
+int setregid __P_((int, int));
+int setreuid __P_((int, int));
+int setrgid __P_((gid_t));
+int setruid __P_((uid_t));
+void setusershell __P_((void));
+int swapon __P_((const char *));
+int symlink __P_((const char *, const char *));
+void sync __P_((void));
+int syscall __P_((int, ...));
+int truncate __P_((const char *, off_t));
+int ttyslot __P_((void));
+unsigned ualarm __P_((unsigned, unsigned));
+void usleep __P_((unsigned));
+int vfork __P_((void));
+
+#endif /* !_POSIX_SOURCE */
+__END_DECLS
+
+#endif
diff --git a/mit-pthreads/lib/.cvsignore b/mit-pthreads/lib/.cvsignore
new file mode 100644
index 00000000000..f3c7a7c5da6
--- /dev/null
+++ b/mit-pthreads/lib/.cvsignore
@@ -0,0 +1 @@
+Makefile
diff --git a/mit-pthreads/lib/Makefile.in b/mit-pthreads/lib/Makefile.in
new file mode 100644
index 00000000000..821d293d896
--- /dev/null
+++ b/mit-pthreads/lib/Makefile.in
@@ -0,0 +1,48 @@
+# === GNUmakefile ============================================================
+# Copyright (c) 1993 Chris Provenzano, proven@athena.mit.edu
+#
+# Description: This file is for creating the test programs for libpthread.a
+#
+# 1.00 93/08/03 proven
+# -Initial cut for pthreads.
+#
+
+CC = ../pgcc -notinstalled
+srctop = @srctop@
+srcdir = @srctop@/lib
+VPATH = @srctop@/lib
+CDEBUGFLAGS = @CFLAGS@
+
+CFLAGS = $(CDEBUGFLAGS) $(INCLUDES) $(ADDL_CFLAGS) -DSRCDIR=\"$(srcdir)\"
+
+#
+DIRS = libpthreadutil
+
+################################################################################
+#
+all:
+ (for i in $(DIRS); do cd $$i; $(MAKE) all; cd ..; done)
+
+clean:
+ (for i in $(DIRS); do cd $$i; $(MAKE) clean; cd ..; done)
+ rm -f *.o $(TESTS) $(BENCHMARKS) a.out core maketmp makeout
+
+depend:
+ (for i in $(DIRS); do cd $$i; $(MAKE) depend; cd ..; done)
+ sed '/\#\#\# Dependencies/q' < Makefile > maketmp
+ (for i in $(CSRC);do $(CPP) -M $$i;done) >> maketmp
+ cp maketmp Makefile
+
+install:
+ (for i in $(DIRS); do cd $$i; $(MAKE) install; cd ..; done)
+
+realclean: clean
+ (for i in $(DIRS); do cd $$i; $(MAKE) realclean; cd ..; done)
+ rm -f Makefile
+
+Makefile: Makefile.in
+ (cd .. ; sh config.status)
+
+################################################################################
+### Do not remove the following line. It is for depend #########################
+### Dependencies:
diff --git a/mit-pthreads/lib/libpthreadutil/.cvsignore b/mit-pthreads/lib/libpthreadutil/.cvsignore
new file mode 100644
index 00000000000..f3c7a7c5da6
--- /dev/null
+++ b/mit-pthreads/lib/libpthreadutil/.cvsignore
@@ -0,0 +1 @@
+Makefile
diff --git a/mit-pthreads/lib/libpthreadutil/Makefile.in b/mit-pthreads/lib/libpthreadutil/Makefile.in
new file mode 100755
index 00000000000..94034f426b3
--- /dev/null
+++ b/mit-pthreads/lib/libpthreadutil/Makefile.in
@@ -0,0 +1,65 @@
+# === makefile ============================================================
+# Copyright (c) 1993 Chris Provenzano, proven@athena.mit.edu
+#
+# Description: This file is for creating the test programs for libpthread.a
+#
+# 1.00 93/08/03 proven
+# -Initial cut for pthreads.
+#
+
+srctop = @srctop@
+srcdir = @srctop@/lib/libpthreadutil
+VPATH = @srctop@/lib/libpthreadutil
+prefix= @prefix@
+exec_prefix= @exec_prefix@
+
+INSTALL_PATH = @exec_prefix@
+ BINDIR = $(INSTALL_PATH)/bin
+ LIBDIR = $(INSTALL_PATH)/lib
+ MANDIR = $(INSTALL_PATH)/man
+ INCDIR = $(INSTALL_PATH)/include
+
+ CC = ../../pgcc -notinstalled
+ CDEBUGFLAGS = @CFLAGS@
+ CFLAGS = $(CDEBUGFLAGS) $(INCLUDES) $(ADDL_CFLAGS) -DSRCDIR=\"$(srcdir)\"
+ RANLIB = @RANLIB@
+
+ OBJS = pthread_tad.o pthread_atexit.o
+ LIBRARY = libpthreadutil.a
+ HEADERS = pthreadutil.h
+
+################################################################################
+#
+all : $(LIBRARY)
+
+clean:
+ rm -f *.o $(TESTS) $(BENCHMARKS) a.out core maketmp makeout
+
+depend:
+ sed '/\#\#\# Dependencies/q' < Makefile > maketmp
+ (for i in $(CSRC);do $(CPP) -M $$i;done) >> maketmp
+ cp maketmp Makefile
+
+install: $(LIBRARY)
+ install $(LIBRARY) $(LIBDIR)
+ for x in $(HEADERS); \
+ do cp $(srcdir)/$$x $(INCDIR); \
+ done
+
+realclean: clean
+ rm -f Makefile
+
+Makefile: Makefile.in
+ (cd ../.. ; sh config.status)
+
+.c.o:
+ $(CC) $(CFLAGS) -c $<
+
+$(LIBRARY) : ${OBJS}
+ ar r new.a ${OBJS} && \
+ $(RANLIB) new.a && \
+ mv -f new.a $(LIBRARY)
+
+################################################################################
+### Do not remove the following line. It is for depend #########################
+### Dependencies:
diff --git a/mit-pthreads/lib/libpthreadutil/pthread_atexit.c b/mit-pthreads/lib/libpthreadutil/pthread_atexit.c
new file mode 100755
index 00000000000..f244fbfb0c8
--- /dev/null
+++ b/mit-pthreads/lib/libpthreadutil/pthread_atexit.c
@@ -0,0 +1,135 @@
+/* ==== pthread_atexit.c =====================================================
+ * Copyright (c) 1994 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Description : Pthread attribute functions.
+ *
+ * 1.20 94/02/13 proven
+ * -Started coding this file.
+ */
+
+#ifndef lint
+static const char rcsid[] = "$Id$";
+#endif
+
+#define PTHREAD_KERNEL
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "pthreadutil.h"
+
+static int pthread_atexit_inited = 0;
+static pthread_key_t pthread_atexit_key;
+static pthread_mutex_t pthread_atexit_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+/* ==========================================================================
+ * pthread_atexit_done()
+ */
+static void pthread_atexit_done(void * arg)
+{
+ pthread_atexit_t id, id_next;
+
+ for (id = arg; id; id = id_next) {
+ id_next = id->next;
+ id->rtn(id->arg);
+ free(id);
+ }
+}
+
+/* ==========================================================================
+ * pthread_atexit_add()
+ */
+int pthread_atexit_add(pthread_atexit_t *id, void (*rtn)(void *), void * arg)
+{
+ int ret;
+
+ if (ret = pthread_mutex_lock(&pthread_atexit_mutex)) {
+ return(ret);
+ }
+ if (!pthread_atexit_inited) {
+ if (ret = pthread_key_create(&pthread_atexit_key, pthread_atexit_done)){
+ pthread_mutex_unlock(&pthread_atexit_mutex);
+ return(ret);
+ }
+ pthread_atexit_inited++;
+ }
+ pthread_mutex_unlock(&pthread_atexit_mutex);
+
+ if ((*id) = (pthread_atexit_t)malloc(sizeof(struct pthread_atexit))) {
+ if ((*id)->next = pthread_getspecific(pthread_atexit_key)) {
+ (*id)->next->prev = (*id);
+ }
+ pthread_setspecific(pthread_atexit_key, (void *)*id);
+ (*id)->prev = NULL;
+ (*id)->rtn = rtn;
+ (*id)->arg = arg;
+ return(OK);
+ }
+ return(ENOMEM);
+}
+
+/* ==========================================================================
+ * pthread_atexit_remove()
+ */
+int pthread_atexit_remove(pthread_atexit_t * id, int execute)
+{
+ pthread_atexit_t old;
+
+ if (old = pthread_getspecific(pthread_atexit_key)) {
+ if (old == *id) {
+ old = old->next;
+ old->prev = NULL;
+ pthread_setspecific(pthread_atexit_key, old);
+ } else {
+ if ((*id)->next) {
+ (*id)->next->prev = (*id)->prev;
+ }
+ (*id)->prev->next = (*id)->next;
+ }
+ if (execute) {
+ (*id)->rtn((*id)->arg);
+ }
+ free((*id));
+ return(OK);
+ }
+ return(EINVAL);
+}
+
+/* ==========================================================================
+ * A few non void functions that are often used as void functions
+ */
+void fflush_nrv(void * fp) { fflush((FILE *)fp); }
+void fclose_nrv(void * fp) { fclose((FILE *)fp); }
+
+void pthread_attr_destroy_nrv(void * attr)
+{
+ pthread_attr_destroy((pthread_attr_t *)attr);
+}
diff --git a/mit-pthreads/lib/libpthreadutil/pthread_tad.c b/mit-pthreads/lib/libpthreadutil/pthread_tad.c
new file mode 100755
index 00000000000..a59fd9b87bf
--- /dev/null
+++ b/mit-pthreads/lib/libpthreadutil/pthread_tad.c
@@ -0,0 +1,170 @@
+/* ==== pthread_tad.c =========================================================
+ * Copyright (c) 1995 by Chris Provenzano, proven@athena.mit.edu
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano,
+ * and its contributors.
+ * 4. Neither the name of Chris Provenzano, nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO, AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef lint
+static char copyright[] =
+ "@(#) Copyright (c) 1995 Chris Provenzano.\nAll rights reserved.\n";
+#endif /* not lint */
+
+/* tad = thread allocation domain */
+#define PTHREAD_KERNEL
+
+#include "pthreadutil.h"
+#include <stdio.h>
+#include <errno.h>
+
+int pthread_tad_count(pthread_tad_t * tad)
+{
+ int ret;
+
+ pthread_mutex_lock(&tad->mutex);
+ ret = tad->count_current;
+ pthread_mutex_unlock(&tad->mutex);
+ return(ret);
+}
+
+static void pthread_tad_done(void * arg)
+{
+ pthread_tad_t * tad = arg;
+ pthread_mutex_lock(&tad->mutex);
+ --tad->count_current;
+/* if (--tad->count_current < tad->count_max) */
+ pthread_cond_broadcast(&tad->cond);
+ pthread_mutex_unlock(&tad->mutex);
+}
+
+#ifndef PTHREAD_KERNEL
+struct tad_start {
+ pthread_tad_t * tad;
+ void * (*routine)();
+ void * arg;
+};
+
+static void * pthread_tad_start(struct tad_start * tad_start)
+{
+ void * (*routine)() = tad_start->routine;
+ void * arg = tad_start->arg;
+
+ pthread_mutex_lock(&tad_start->tad->mutex);
+ pthread_cleanup_push(pthread_tad_done, tad_start->tad);
+ pthread_mutex_unlock(&tad_start->tad->mutex);
+ free(tad_start);
+ return(routine(arg));
+}
+#else
+static void * pthread_tad_start(void * tad_start_arg)
+{
+ pthread_tad_t * tad = tad_start_arg;
+ void * (*routine)() = tad->routine;
+ void * arg = tad->arg;
+
+ tad->count_current++;
+ pthread_cleanup_push(pthread_tad_done, tad);
+ pthread_mutex_unlock(&tad->mutex);
+ return(routine(arg));
+}
+#endif
+
+int pthread_tad_create(pthread_tad_t * tad, pthread_t *thread_id,
+ pthread_attr_t *attr, void * (*routine)(), void * arg)
+{
+#ifndef PTHREAD_KERNEL
+ struct tad_start tad;
+#endif
+ int ret;
+
+ pthread_mutex_lock(&tad->mutex);
+ while (tad->count_max && (tad->count_current > tad->count_max))
+ pthread_cond_wait(&tad->cond, &tad->mutex);
+
+#ifndef PTHREAD_KERNEL
+ if ((tad_start = malloc(sizeof(struct tad_start))) == NULL) {
+ pthread_mutex_unlock(&tad->mutex);
+ return(ENOMEM);
+ }
+ tad_start->routine = routine;
+ tad_start->arg = arg;
+ tad_start->tad = tad;
+ if ((ret = pthread_create(thread_id, attr,
+ pthread_tad_start, tad_start)) == OK)
+ tad->count_current++;
+ pthread_mutex_unlock(&tad->mutex);
+#else
+ tad->routine = routine;
+ tad->arg = arg;
+ if (ret = pthread_create(thread_id, attr, pthread_tad_start, tad))
+ pthread_mutex_unlock(&tad->mutex);
+#endif
+ return(ret);
+}
+
+int pthread_tad_wait(pthread_tad_t * tad, unsigned int count)
+{
+ if ((tad->count_max) && (tad->count_max < count)) {
+ return(EINVAL);
+ }
+ pthread_mutex_lock(&tad->mutex);
+ while (tad->count_current > count)
+ pthread_cond_wait(&tad->cond, &tad->mutex);
+ pthread_mutex_unlock(&tad->mutex);
+ return(OK);
+}
+
+int pthread_tad_init(pthread_tad_t * tad, unsigned int max_count)
+{
+ int ret;
+
+ if ((ret = pthread_mutex_init(&tad->mutex, NULL)) == OK) {
+ if (ret = pthread_cond_init(&tad->cond, NULL)) {
+ pthread_mutex_destroy(&tad->mutex);
+ } else {
+ tad->count_max = max_count;
+ tad->count_current = 0;
+ }
+ }
+ return(ret);
+}
+
+/* User is responsible to make sure their are no threads running */
+int pthread_tad_destroy(pthread_tad_t * tad)
+{
+ int ret;
+
+ if ((ret = pthread_mutex_destroy(&tad->mutex)) == OK) {
+ ret = pthread_cond_destroy(&tad->cond);
+ } else {
+ pthread_cond_destroy(&tad->cond);
+ }
+ tad->count_max = NOTOK;
+ return(ret);
+}
diff --git a/mit-pthreads/lib/libpthreadutil/pthreadutil.h b/mit-pthreads/lib/libpthreadutil/pthreadutil.h
new file mode 100755
index 00000000000..0d8e6a6ef5f
--- /dev/null
+++ b/mit-pthreads/lib/libpthreadutil/pthreadutil.h
@@ -0,0 +1,75 @@
+/* ==== pthread_tad.h ========================================================
+ * Copyright (c) 1995 by Chris Provenzano, proven@athena.mit.edu
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano,
+ * and its contributors.
+ * 4. Neither the name of Chris Provenzano, nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO, AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <pthread.h>
+#include <sys/cdefs.h>
+
+typedef struct pthread_tad_t {
+ pthread_mutex_t mutex;
+ pthread_cond_t cond;
+ unsigned int count_current;
+ unsigned int count_max;
+ void * arg;
+ void * (*routine)();
+} pthread_tad_t;
+
+typedef struct pthread_atexit {
+ struct pthread_atexit * next;
+ struct pthread_atexit * prev;
+ void (*rtn)(void *);
+ void * arg;
+} * pthread_atexit_t;
+
+/*
+ * New functions
+ */
+
+__BEGIN_DECLS
+
+int pthread_tad_count __P_((pthread_tad_t *));
+int pthread_tad_create __P_((pthread_tad_t *, pthread_t *, pthread_attr_t *,
+ void *(*routine)(), void *));
+int pthread_tad_wait __P_((pthread_tad_t *, unsigned int));
+int pthread_tad_init __P_((pthread_tad_t *, unsigned int));
+int pthread_tad_destroy __P_((pthread_tad_t *));
+
+int pthread_atexit_add __P_((pthread_atexit_t *, void (*)(void *), void *));
+int pthread_atexit_remove __P_((pthread_atexit_t *, int));
+
+
+void fclose_nrv __P_((void *));
+void fflush_nrv __P_((void *));
+void pthread_attr_destroy_nrv __P_((void *));
+
+__END_DECLS
+
diff --git a/mit-pthreads/machdep/alpha-osf1/__math.h b/mit-pthreads/machdep/alpha-osf1/__math.h
new file mode 100755
index 00000000000..12fdc85678c
--- /dev/null
+++ b/mit-pthreads/machdep/alpha-osf1/__math.h
@@ -0,0 +1,16 @@
+/*
+ * ANSI required entries in math.h
+ *
+ */
+#ifdef _ANSI_C_SOURCE
+
+#if defined(_IEEE_FP)
+# define HUGE_VAL 1.8e308
+#else
+# define HUGE_VAL 1.797693134862315708e308
+#endif
+
+#endif /*_ANSI_C_SOURCE */
+
+
+
diff --git a/mit-pthreads/machdep/alpha-osf1/__signal.h b/mit-pthreads/machdep/alpha-osf1/__signal.h
new file mode 100755
index 00000000000..2bb13380314
--- /dev/null
+++ b/mit-pthreads/machdep/alpha-osf1/__signal.h
@@ -0,0 +1,106 @@
+#include <standards.h>
+
+typedef int sig_atomic_t; /* accessable as an atomic entity (ANSI) */
+
+/*
+ * valid signal values: all undefined values are reserved for future use
+ * note: POSIX requires a value of 0 to be used as the null signal in kill()
+ */
+#define SIGHUP 1 /* hangup, generated when terminal disconnects */
+#define SIGINT 2 /* interrupt, generated from terminal special char */
+#define SIGQUIT 3 /* (*) quit, generated from terminal special char */
+#define SIGILL 4 /* (*) illegal instruction (not reset when caught)*/
+#define SIGTRAP 5 /* (*) trace trap (not reset when caught) */
+#define SIGABRT 6 /* (*) abort process */
+#define SIGEMT 7 /* EMT instruction */
+#define SIGFPE 8 /* (*) floating point exception */
+#define SIGKILL 9 /* kill (cannot be caught or ignored) */
+#define SIGBUS 10 /* (*) bus error (specification exception) */
+#define SIGSEGV 11 /* (*) segmentation violation */
+#define SIGSYS 12 /* (*) bad argument to system call */
+#define SIGPIPE 13 /* write on a pipe with no one to read it */
+#define SIGALRM 14 /* alarm clock timeout */
+#define SIGTERM 15 /* software termination signal */
+#define SIGURG 16 /* (+) urgent contition on I/O channel */
+#define SIGSTOP 17 /* (@) stop (cannot be caught or ignored) */
+#define SIGTSTP 18 /* (@) interactive stop */
+#define SIGCONT 19 /* (!) continue (cannot be caught or ignored) */
+#define SIGCHLD 20 /* (+) sent to parent on child stop or exit */
+#define SIGTTIN 21 /* (@) background read attempted from control terminal*/
+#define SIGTTOU 22 /* (@) background write attempted to control terminal */
+#define SIGIO 23 /* (+) I/O possible, or completed */
+#define SIGXCPU 24 /* cpu time limit exceeded (see setrlimit()) */
+#define SIGXFSZ 25 /* file size limit exceeded (see setrlimit()) */
+#define SIGVTALRM 26 /* virtual time alarm (see setitimer) */
+#define SIGPROF 27 /* profiling time alarm (see setitimer) */
+#define SIGWINCH 28 /* (+) window size changed */
+#define SIGINFO 29 /* information request */
+#define SIGUSR1 30 /* user defined signal 1 */
+#define SIGUSR2 31 /* user defined signal 2 */
+#define SIGMAX 31
+#define NSIG 31
+
+/*
+ * additional signal names supplied for compatibility, only
+ */
+#define SIGIOINT SIGURG /* printer to backend error signal */
+#define SIGAIO SIGIO /* base lan i/o */
+#define SIGPTY SIGIO /* pty i/o */
+#define SIGPOLL SIGIO /* STREAMS version of this signal */
+#define SIGIOT SIGABRT /* abort (terminate) process */
+#define SIGLOST SIGIOT /* old BSD signal ?? */
+#define SIGPWR SIGINFO /* Power Fail/Restart -- SVID3/SVR4 */
+#define SIGCLD SIGCHLD
+
+/*
+ * valid signal action values; other values => pointer to handler function
+ */
+#define SIG_DFL (void (*)())0
+#define SIG_IGN (void (*)())1
+
+/*
+ * values of "how" argument to sigprocmask() call
+ */
+#define SIG_BLOCK 1
+#define SIG_UNBLOCK 2
+#define SIG_SETMASK 3
+
+/*
+ * sigaction structure used in sigaction() system call
+ * The order of the fields in this structure must match those in
+ * the sigvec structure (below).
+ */
+struct sigaction {
+ void (*sa_handler)(); /* signal handler, or action value */
+ sigset_t sa_mask; /* signals to block while in handler */
+ int sa_flags; /* signal action flags */
+};
+
+#define __SIGEMPTYSET 0
+#define __SIGFILLSET 0xffffffff
+#define __SIGADDSET(s, n) ( *(s) |= 1L << ((n) - 1), 0)
+#define __SIGDELSET(s, n) ( *(s) &= ~(1L << ((n) - 1)), 0)
+#define __SIGISMEMBER(s, n) ( (*(s) & (1L << ((n) - 1))) != (sigset_t)0)
+
+
+#define SIGSTKSZ (16384)
+#define MINSIGSTKSZ (4096)
+
+/*
+ * valid flags define for sa_flag field of sigaction structure
+ */
+#define SA_ONSTACK 0x00000001 /* run on special signal stack */
+#define SA_RESTART 0x00000002 /* restart system calls on sigs */
+#define SA_NOCLDSTOP 0x00000004 /* do not set SIGCHLD for child stops*/
+#define SA_NODEFER 0x00000008 /* don't block while handling */
+#define SA_RESETHAND 0x00000010 /* old sys5 style behavior */
+#define SA_NOCLDWAIT 0x00000020 /* no zombies */
+#define SA_SIGINFO 0x00000040 /* deliver siginfo to handler */
+
+/* This is for sys/time.h */
+/* Removed for OSF1 V3.2
+typedef union sigval {
+ int sival_int;
+ void *sival_ptr;
+} sigval_t;
+*/
diff --git a/mit-pthreads/machdep/alpha-osf1/__stdio.h b/mit-pthreads/machdep/alpha-osf1/__stdio.h
new file mode 100755
index 00000000000..39801b125c8
--- /dev/null
+++ b/mit-pthreads/machdep/alpha-osf1/__stdio.h
@@ -0,0 +1,13 @@
+
+#ifndef _FPOS_T
+#define _FPOS_T
+typedef pthread_fpos_t fpos_t; /* Must match off_t <sys/types.h> */
+#endif
+
+#ifndef _SIZE_T
+#define _SIZE_T
+typedef pthread_size_t size_t;
+#endif
+
+#define HAVE_SYS_ERRLIST_WITHOUT_CONST
+
diff --git a/mit-pthreads/machdep/alpha-osf1/__stdlib.h b/mit-pthreads/machdep/alpha-osf1/__stdlib.h
new file mode 100755
index 00000000000..79ca737e0c8
--- /dev/null
+++ b/mit-pthreads/machdep/alpha-osf1/__stdlib.h
@@ -0,0 +1,3 @@
+/* bleah */
+
+#include <stddef.h>
diff --git a/mit-pthreads/machdep/alpha-osf1/__string.h b/mit-pthreads/machdep/alpha-osf1/__string.h
new file mode 100755
index 00000000000..6558102a282
--- /dev/null
+++ b/mit-pthreads/machdep/alpha-osf1/__string.h
@@ -0,0 +1,19 @@
+
+#ifndef _SIZE_T
+#define _SIZE_T
+typedef pthread_size_t size_t;
+#endif
+
+__BEGIN_DECLS
+
+/*
+void * memchr __P_((const void *, int , size_t ));
+void * memcpy __P_((void *, const void *, size_t ));
+void * memset __P_((void *, int , size_t ));
+size_t strcspn __P_((const char *, const char *));
+size_t strlen __P_((const char *));
+size_t strspn __P_((const char *, const char *));
+*/
+
+__END_DECLS
+
diff --git a/mit-pthreads/machdep/alpha-osf1/__time.h b/mit-pthreads/machdep/alpha-osf1/__time.h
new file mode 100755
index 00000000000..b4ce1ead2bf
--- /dev/null
+++ b/mit-pthreads/machdep/alpha-osf1/__time.h
@@ -0,0 +1,21 @@
+#include <pthread/types.h>
+#include <machine/machtime.h> /* CLOCKS_PER_SEC is defined here */
+
+#ifndef _SIZE_T
+#define _SIZE_T
+typedef pthread_size_t size_t;
+#endif
+
+#ifndef _CLOCK_T
+#define _CLOCK_T
+typedef pthread_clock_t clock_t;
+#endif
+
+#ifndef _TIME_T
+#define _TIME_T
+typedef pthread_time_t time_t;
+#endif
+
+#ifndef CLK_TCK
+#define CLK_TCK 60
+#endif
diff --git a/mit-pthreads/machdep/alpha-osf1/__unistd.h b/mit-pthreads/machdep/alpha-osf1/__unistd.h
new file mode 100755
index 00000000000..2a7fbe9389b
--- /dev/null
+++ b/mit-pthreads/machdep/alpha-osf1/__unistd.h
@@ -0,0 +1,6 @@
+#include <sys/types.h>
+
+#ifndef _SSIZE_T
+#define _SSIZE_T
+typedef long ssize_t; /* Added by monty */
+#endif
diff --git a/mit-pthreads/machdep/alpha-osf1/cdefs.h b/mit-pthreads/machdep/alpha-osf1/cdefs.h
new file mode 100755
index 00000000000..c9b54f033ec
--- /dev/null
+++ b/mit-pthreads/machdep/alpha-osf1/cdefs.h
@@ -0,0 +1,62 @@
+/* ==== cdefs.h ============================================================
+ * Copyright (c) 1994 by Chris Provenzano, proven@athena.mit.edu
+ *
+ * Description : Similar to the BSD cdefs.h file.
+ *
+ * 1.00 94/01/26 proven
+ * -Started coding this file.
+ */
+
+#ifndef _PTHREAD_SYS_CDEFS_H_
+#define _PTHREAD_SYS_CDEFS_H_
+
+/* Stuff for compiling */
+#if defined(__GNUC__)
+#if defined(__cplusplus)
+#define __INLINE static inline
+#define __BEGIN_DECLS extern "C" {
+#define __END_DECLS };
+#else
+#define __INLINE extern inline
+#define __CAN_DO_EXTERN_INLINE
+#define __BEGIN_DECLS
+#define __END_DECLS
+#if !defined(__STDC__)
+#define const __const
+#define inline __inline
+#define signed __signed
+#define volatile __volatile
+#endif
+#endif
+#else /* !__GNUC__ */
+#define __BEGIN_DECLS
+#define __END_DECLS
+#define __INLINE static
+#define inline
+#endif
+
+#ifndef __NORETURN
+#define __NORETURN
+#endif /* __NORETURN not defined. */
+
+#ifndef _U_INT32_T_
+#define _U_INT32_T_
+typedef unsigned int u_int32_t;
+#endif
+
+#ifndef _U_INT16_T_
+#define _U_INT16_T_
+typedef unsigned short u_int16_t;
+#endif
+
+#ifndef _INT32_T_
+#define _INT32_T_
+typedef int int32_t;
+#endif
+
+#ifndef _INT16_T_
+#define _INT16_T_
+typedef short int16_t;
+#endif
+
+#endif
diff --git a/mit-pthreads/machdep/alpha-osf1/compat.h b/mit-pthreads/machdep/alpha-osf1/compat.h
new file mode 100755
index 00000000000..4c2801e05de
--- /dev/null
+++ b/mit-pthreads/machdep/alpha-osf1/compat.h
@@ -0,0 +1 @@
+#define omsghdr msghdr
diff --git a/mit-pthreads/machdep/alpha-osf1/dirent.h b/mit-pthreads/machdep/alpha-osf1/dirent.h
new file mode 100755
index 00000000000..697ef7b8a8c
--- /dev/null
+++ b/mit-pthreads/machdep/alpha-osf1/dirent.h
@@ -0,0 +1,7 @@
+struct dirent {
+ ino_t d_ino;
+ ushort_t d_reclen, d_namlen;
+ char d_name[256];
+};
+#define d_fileno d_ino
+#define MAXNAMLEN 256
diff --git a/mit-pthreads/machdep/alpha-osf1/signal.h b/mit-pthreads/machdep/alpha-osf1/signal.h
new file mode 100755
index 00000000000..c387f9f31ad
--- /dev/null
+++ b/mit-pthreads/machdep/alpha-osf1/signal.h
@@ -0,0 +1,3 @@
+
+
+#include <signal.h>
diff --git a/mit-pthreads/machdep/alpha-osf1/socket.h b/mit-pthreads/machdep/alpha-osf1/socket.h
new file mode 100755
index 00000000000..28e17ca463d
--- /dev/null
+++ b/mit-pthreads/machdep/alpha-osf1/socket.h
@@ -0,0 +1,296 @@
+/*
+ * Copyright (c) 1982,1985,1986,1988 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)socket.h 7.13 (Berkeley) 4/20/91
+ */
+
+#ifndef _SOCKET_H_
+#define _SOCKET_H_
+
+/*
+ * Definitions related to sockets: types, address families, options.
+ */
+
+/*
+ * Types
+ */
+#define SOCK_STREAM 1 /* stream socket */
+#define SOCK_DGRAM 2 /* datagram socket */
+#define SOCK_RAW 4 /* raw-protocol interface */
+#define SOCK_RDM 5 /* reliably-delivered message */
+#define SOCK_SEQPACKET 6 /* sequenced packet stream */
+
+/*
+ * Option flags per-socket.
+ */
+#define SO_DEBUG 0x0001 /* turn on debugging info recording */
+#define SO_ACCEPTCONN 0x0002 /* socket has had listen() */
+#define SO_REUSEADDR 0x0004 /* allow local address reuse */
+#define SO_KEEPALIVE 0x0008 /* keep connections alive */
+#define SO_DONTROUTE 0x0010 /* just use interface addresses */
+#define SO_BROADCAST 0x0020 /* permit sending of broadcast msgs */
+#define SO_USELOOPBACK 0x0040 /* bypass hardware when possible */
+#define SO_LINGER 0x0080 /* linger on close if data present */
+#define SO_OOBINLINE 0x0100 /* leave received OOB data in line */
+
+/*
+ * Additional options, not kept in so_options.
+ */
+#define SO_SNDBUF 0x1001 /* send buffer size */
+#define SO_RCVBUF 0x1002 /* receive buffer size */
+#define SO_SNDLOWAT 0x1003 /* send low-water mark */
+#define SO_RCVLOWAT 0x1004 /* receive low-water mark */
+#define SO_SNDTIMEO 0x1005 /* send timeout */
+#define SO_RCVTIMEO 0x1006 /* receive timeout */
+#define SO_ERROR 0x1007 /* get error status and clear */
+#define SO_TYPE 0x1008 /* get socket type */
+#define SO_PROTOTYPE 0x1009 /* get/set protocol type */
+
+/*
+ * Structure used for manipulating linger option.
+ */
+struct linger {
+ int l_onoff; /* option on/off */
+ int l_linger; /* linger time */
+};
+
+/*
+ * Level number for (get/set)sockopt() to apply to socket itself.
+ */
+#define SOL_SOCKET 0xffff /* options for socket level */
+
+/*
+ * Address families.
+ */
+#define AF_UNSPEC 0 /* unspecified */
+#define AF_UNIX 1 /* local to host (pipes, portals) */
+#define AF_INET 2 /* internetwork: UDP, TCP, etc. */
+#define AF_IMPLINK 3 /* arpanet imp addresses */
+#define AF_PUP 4 /* pup protocols: e.g. BSP */
+#define AF_CHAOS 5 /* mit CHAOS protocols */
+#define AF_NS 6 /* XEROX NS protocols */
+#define AF_NBS 7 /* nbs protocols */
+#define AF_ECMA 8 /* european computer manufacturers */
+#define AF_DATAKIT 9 /* datakit protocols */
+#define AF_CCITT 10 /* CCITT protocols, X.25 etc */
+#define AF_SNA 11 /* IBM SNA */
+#define AF_DECnet 12 /* DECnet */
+#define AF_DLI 13 /* DEC Direct data link interface */
+#define AF_LAT 14 /* LAT */
+#define AF_HYLINK 15 /* NSC Hyperchannel */
+#define AF_APPLETALK 16 /* Apple Talk */
+#define AF_NIT 17 /* Network Interface Tap */
+#define AF_802 18 /* IEEE 802.2, also ISO 8802 */
+#define AF_ISO 19 /* ISO protocols */
+#define AF_OSI AF_ISO
+#define AF_X25 20 /* CCITT X.25 in particular */
+#define AF_OSINET 21
+#define AF_GOSIP 22
+#define AF_MAX 22
+
+/* Not supported by solaris */
+/* #define AF_ROUTE 17 /* Internal Routing Protocol */
+/* #define AF_LINK 18 /* Link layer interface */
+/* #define pseudo_AF_XTP 19 /* eXpress Transfer Protocol (no AF) */
+
+
+/*
+ * Structure used by kernel to store most
+ * addresses.
+ */
+struct sockaddr {
+ u_short sa_family; /* address family */
+ char sa_data[14]; /* actually longer; address value */
+};
+
+/*
+ * Structure used by kernel to pass protocol
+ * information in raw sockets.
+ */
+struct sockproto {
+ u_short sp_family; /* address family */
+ u_short sp_protocol; /* protocol */
+};
+
+/*
+ * Protocol families, same as address families for now.
+ */
+#define PF_UNSPEC AF_UNSPEC
+#define PF_UNIX AF_UNIX
+#define PF_INET AF_INET
+#define PF_IMPLINK AF_IMPLINK
+#define PF_PUP AF_PUP
+#define PF_CHAOS AF_CHAOS
+#define PF_NS AF_NS
+#define PF_NBS AF_NBS
+#define PF_ECMA AF_ECMA
+#define PF_DATAKIT AF_DATAKIT
+#define PF_CCITT AF_CCITT
+#define PF_SNA AF_SNA
+#define PF_DECnet AF_DECnet
+#define PF_DLI AF_DLI
+#define PF_LAT AF_LAT
+#define PF_HYLINK AF_HYLINK
+#define PF_APPLETALK AF_APPLETALK
+#define PF_NIT AF_NIT
+#define PF_802 AF_802
+#define PF_ISO AF_ISO
+#define PF_OSI AF_ISO
+#define PF_X25 AF_X25
+#define PF_OSINET AF_OSINET
+#define PF_GOSIP AF_GOSIP
+#define PF_MAX AF_MAX
+
+/* #define PF_ROUTE AF_ROUTE */
+/* #define PF_LINK AF_LINK */
+/* #define PF_XTP pseudo_AF_XTP /* really just proto family, no AF */
+
+/*
+ * Maximum queue length specifiable by listen.
+ */
+#define SOMAXCONN 5
+
+/*
+ * Message header for recvmsg and sendmsg calls.
+ * Used value-result for recvmsg, value only for sendmsg.
+ */
+struct msghdr {
+ caddr_t msg_name; /* optional address */
+ u_int msg_namelen; /* size of address */
+ struct iovec *msg_iov; /* scatter/gather array */
+ u_int msg_iovlen; /* # elements in msg_iov */
+ caddr_t msg_accrights; /* access rights sent/received */
+ int msg_accrightslen;
+};
+
+#define MSG_MAXIOVLEN 16
+
+#define MSG_OOB 0x1 /* process out-of-band data */
+#define MSG_PEEK 0x2 /* peek at incoming message */
+#define MSG_DONTROUTE 0x4 /* send without using routing tables */
+
+/* #define MSG_EOR 0x8 data completes record */
+/* #define MSG_TRUNC 0x10 data discarded before delivery */
+/* #define MSG_CTRUNC 0x20 control data lost before delivery */
+/* #define MSG_WAITALL 0x40 wait for full request or error */
+
+/*
+ * Header for ancillary data objects in msg_control buffer.
+ * Used for additional information with/about a datagram
+ * not expressible by flags. The format is a sequence
+ * of message elements headed by cmsghdr structures.
+ */
+struct cmsghdr {
+ u_int cmsg_len; /* data byte count, including hdr */
+ int cmsg_level; /* originating protocol */
+ int cmsg_type; /* protocol-specific type */
+/* followed by u_char cmsg_data[]; */
+};
+
+/* given pointer to struct adatahdr, return pointer to data */
+#define CMSG_DATA(cmsg) ((u_char *)((cmsg) + 1))
+
+/* given pointer to struct adatahdr, return pointer to next adatahdr */
+#define CMSG_NXTHDR(mhdr, cmsg) \
+ (((caddr_t)(cmsg) + (cmsg)->cmsg_len + sizeof(struct cmsghdr) > \
+ (mhdr)->msg_control + (mhdr)->msg_controllen) ? \
+ (struct cmsghdr *)NULL : \
+ (struct cmsghdr *)((caddr_t)(cmsg) + ALIGN((cmsg)->cmsg_len)))
+
+#define CMSG_FIRSTHDR(mhdr) ((struct cmsghdr *)(mhdr)->msg_control)
+
+/* "Socket"-level control message types: */
+#define SCM_RIGHTS 0x01 /* access rights (array of int) */
+
+/*
+ * 4.3 compat sockaddr, move to compat file later
+ */
+struct osockaddr {
+ u_short sa_family; /* address family */
+ char sa_data[14]; /* up to 14 bytes of direct address */
+};
+
+#define SYS_socketcall 83
+
+#define SO_ACCEPT 1
+#define SO_BIND 2
+#define SO_CONNECT 3
+#define SO_GETPEERNAME 4
+#define SO_GETSOCKNAME 5
+#define SO_GETSOCKOPT 6
+#define SO_LISTEN 7
+#define SO_RECV 8
+#define SO_RECVFROM 9
+#define SO_SEND 10
+#define SO_SENDTO 11
+#define SO_SETSOCKOPT 12
+#define SO_SHUTDOWN 13
+#define SO_SOCKET 14
+#define SO_SOCKPOLL 15
+#define SO_GETIPDOMAIN 16
+#define SO_SETIPDOMAIN 17
+#define SO_ADJTIME 18
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+int accept __P_((int, struct sockaddr *, int *));
+int bind __P_((int, const struct sockaddr *, int));
+int connect __P_((int, const struct sockaddr *, int));
+int getpeername __P_((int, struct sockaddr *, int *));
+int getsockname __P_((int, struct sockaddr *, int *));
+int getsockopt __P_((int, int, int, void *, int *));
+int listen __P_((int, int));
+/* original definitions
+int recv __P_((int, void *, int, int));
+int recvfrom __P_((int, void *, int, int,
+ struct sockaddr *, int *));
+int recvmsg __P_((int, struct msghdr *, int));
+int send __P_((int, const void *, int, int));
+int sendto __P_((int, const void *, int, int, const struct sockaddr *, int));
+int sendmsg __P_((int, const struct msghdr *, int));
+*/
+ssize_t recv __P_((int, void *, size_t, int));
+ssize_t recvfrom __P_((int, void *, size_t, int,
+ struct sockaddr *, int *));
+ssize_t recvmsg __P_((int, struct msghdr *, int));
+ssize_t send __P_((int, const void *, size_t, int));
+ssize_t sendto __P_((int, const void *, size_t, int,
+ const struct sockaddr *, int));
+ssize_t sendmsg __P_((int, const struct msghdr *, int));
+int setsockopt __P_((int, int, int, const void *, int));
+int shutdown __P_((int, int));
+int socket __P_((int, int, int));
+int socketpair __P_((int, int, int, int *));
+__END_DECLS
+
+#endif /* !_SOCKET_H_ */
diff --git a/mit-pthreads/machdep/alpha-osf1/timers.h b/mit-pthreads/machdep/alpha-osf1/timers.h
new file mode 100755
index 00000000000..36317d083f0
--- /dev/null
+++ b/mit-pthreads/machdep/alpha-osf1/timers.h
@@ -0,0 +1,60 @@
+/* ==== timers.h ============================================================
+ * Copyright (c) 1994 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ *
+ * Description : Basic timers header.
+ *
+ * 1.00 94/06/13 proven
+ * -Started coding this file.
+ */
+
+#ifndef _SYS_TIMERS_H_
+#define _SYS_TIMERS_H_
+
+#include <sys/types.h>
+#include <time.h>
+
+struct timespec {
+ time_t tv_sec;
+ long tv_nsec;
+};
+
+#define TIMEVAL_TO_TIMESPEC(tv, ts) { \
+ (ts)->tv_sec = (tv)->tv_sec; \
+ (ts)->tv_nsec = (tv)->tv_usec * 1000; \
+}
+#define TIMESPEC_TO_TIMEVAL(tv, ts) { \
+ (tv)->tv_sec = (ts)->tv_sec; \
+ (tv)->tv_usec = (ts)->tv_nsec / 1000; \
+}
+
+#endif
diff --git a/mit-pthreads/machdep/alpha-osf1/uio.h b/mit-pthreads/machdep/alpha-osf1/uio.h
new file mode 100755
index 00000000000..8d494672ee4
--- /dev/null
+++ b/mit-pthreads/machdep/alpha-osf1/uio.h
@@ -0,0 +1,12 @@
+/* N.B.: The Alpha, under OSF/1, does *not* use size_t for the length,
+ or for the returned values from readv and writev. */
+
+struct iovec {
+ void *iov_base;
+ int iov_len;
+};
+
+/* I'm assuming the iovec structures are const. I haven't verified
+ it. */
+extern ssize_t readv (int, const struct iovec *, int);
+extern ssize_t writev (int, const struct iovec *, int);
diff --git a/mit-pthreads/machdep/bsdi-1.1/compat.h b/mit-pthreads/machdep/bsdi-1.1/compat.h
new file mode 100755
index 00000000000..e6f60c372c7
--- /dev/null
+++ b/mit-pthreads/machdep/bsdi-1.1/compat.h
@@ -0,0 +1,43 @@
+/* ==== compat.h ============================================================
+ * Copyright (c) 1994 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ *
+ * Description : COmpat header to make socket code compile.
+ *
+ * 1.00 94/08/01 proven
+ * -Started coding this file.
+ */
+
+#ifndef _SYS_COMPAT_H_
+#define _SYS_COMPAT_H_
+
+#endif
diff --git a/mit-pthreads/machdep/bsdi-1.1/dirent.h b/mit-pthreads/machdep/bsdi-1.1/dirent.h
new file mode 100755
index 00000000000..d0272a4ee38
--- /dev/null
+++ b/mit-pthreads/machdep/bsdi-1.1/dirent.h
@@ -0,0 +1,73 @@
+/* BSDI $Id$ */
+
+/*-
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)dirent.h 5.18 (Berkeley) 2/23/91
+ */
+
+#ifndef _SYS_DIRENT_H_
+#define _SYS_DIRENT_H_
+
+/*
+ * A directory entry has a struct dirent at the front of it, containing its
+ * inode number, the length of the entry, and the length of the name
+ * contained in the entry. These are followed by the name padded to a 4
+ * byte boundary with null bytes. All names are guaranteed null terminated.
+ * The maximum length of a name in a directory is MAXNAMLEN.
+ */
+
+struct dirent {
+ unsigned long
+ d_fileno; /* file number of entry */
+ unsigned short
+ d_reclen; /* length of this record */
+ unsigned short
+ d_namlen; /* length of string in d_name */
+#ifdef _POSIX_SOURCE
+ char d_name[255 + 1]; /* name must be no longer than this */
+#else
+#define MAXNAMLEN 255
+ char d_name[MAXNAMLEN + 1]; /* name must be no longer than this */
+#endif
+};
+
+/*
+ * There should probably be no need for this. In the BSDI sources,
+ * it is excluded if _POSIX_SOURCE is defined, and pthreads are supposed
+ * to be posix. Sources that use d_ino should really be using d_fileno.
+ * mbd
+ */
+#define d_ino d_fileno /* backward compatibility */
+
+#endif /* !_SYS_DIRENT_H_ */
+
diff --git a/mit-pthreads/machdep/bsdi-1.1/errno.h b/mit-pthreads/machdep/bsdi-1.1/errno.h
new file mode 100755
index 00000000000..3da61d692a3
--- /dev/null
+++ b/mit-pthreads/machdep/bsdi-1.1/errno.h
@@ -0,0 +1,160 @@
+/* $NetBSD: errno.h,v 1.8 1994/06/29 06:44:02 cgd Exp $ */
+
+/*
+ * Copyright (c) 1982, 1986, 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ * (c) UNIX System Laboratories, Inc.
+ * All or some portions of this file are derived from material licensed
+ * to the University of California by American Telephone and Telegraph
+ * Co. or Unix System Laboratories, Inc. and are reproduced herein with
+ * the permission of UNIX System Laboratories, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)errno.h 8.5 (Berkeley) 1/21/94
+ */
+
+#ifndef _SYS_ERRNO_H_
+#define _SYS_ERRNO_H_
+
+#define EPERM 1 /* Operation not permitted */
+#define ENOENT 2 /* No such file or directory */
+#define ESRCH 3 /* No such process */
+#define EINTR 4 /* Interrupted system call */
+#define EIO 5 /* Input/output error */
+#define ENXIO 6 /* Device not configured */
+#define E2BIG 7 /* Argument list too long */
+#define ENOEXEC 8 /* Exec format error */
+#define EBADF 9 /* Bad file descriptor */
+#define ECHILD 10 /* No child processes */
+#define EDEADLK 11 /* Resource deadlock avoided */
+ /* 11 was EAGAIN */
+#define ENOMEM 12 /* Cannot allocate memory */
+#define EACCES 13 /* Permission denied */
+#define EFAULT 14 /* Bad address */
+#ifndef _POSIX_SOURCE
+#define ENOTBLK 15 /* Block device required */
+#endif
+#define EBUSY 16 /* Device busy */
+#define EEXIST 17 /* File exists */
+#define EXDEV 18 /* Cross-device link */
+#define ENODEV 19 /* Operation not supported by device */
+#define ENOTDIR 20 /* Not a directory */
+#define EISDIR 21 /* Is a directory */
+#define EINVAL 22 /* Invalid argument */
+#define ENFILE 23 /* Too many open files in system */
+#define EMFILE 24 /* Too many open files */
+#define ENOTTY 25 /* Inappropriate ioctl for device */
+#ifndef _POSIX_SOURCE
+#define ETXTBSY 26 /* Text file busy */
+#endif
+#define EFBIG 27 /* File too large */
+#define ENOSPC 28 /* No space left on device */
+#define ESPIPE 29 /* Illegal seek */
+#define EROFS 30 /* Read-only file system */
+#define EMLINK 31 /* Too many links */
+#define EPIPE 32 /* Broken pipe */
+
+/* math software */
+#define EDOM 33 /* Numerical argument out of domain */
+#define ERANGE 34 /* Result too large */
+
+/* non-blocking and interrupt i/o */
+#define EAGAIN 35 /* Resource temporarily unavailable */
+#ifndef _POSIX_SOURCE
+#define EWOULDBLOCK EAGAIN /* Operation would block */
+#define EINPROGRESS 36 /* Operation now in progress */
+#define EALREADY 37 /* Operation already in progress */
+
+/* ipc/network software -- argument errors */
+#define ENOTSOCK 38 /* Socket operation on non-socket */
+#define EDESTADDRREQ 39 /* Destination address required */
+#define EMSGSIZE 40 /* Message too long */
+#define EPROTOTYPE 41 /* Protocol wrong type for socket */
+#define ENOPROTOOPT 42 /* Protocol not available */
+#define EPROTONOSUPPORT 43 /* Protocol not supported */
+#define ESOCKTNOSUPPORT 44 /* Socket type not supported */
+#define EOPNOTSUPP 45 /* Operation not supported */
+#define EPFNOSUPPORT 46 /* Protocol family not supported */
+#define EAFNOSUPPORT 47 /* Address family not supported by protocol family */
+#define EADDRINUSE 48 /* Address already in use */
+#define EADDRNOTAVAIL 49 /* Can't assign requested address */
+
+/* ipc/network software -- operational errors */
+#define ENETDOWN 50 /* Network is down */
+#define ENETUNREACH 51 /* Network is unreachable */
+#define ENETRESET 52 /* Network dropped connection on reset */
+#define ECONNABORTED 53 /* Software caused connection abort */
+#define ECONNRESET 54 /* Connection reset by peer */
+#define ENOBUFS 55 /* No buffer space available */
+#define EISCONN 56 /* Socket is already connected */
+#define ENOTCONN 57 /* Socket is not connected */
+#define ESHUTDOWN 58 /* Can't send after socket shutdown */
+#define ETOOMANYREFS 59 /* Too many references: can't splice */
+#define ETIMEDOUT 60 /* Operation timed out */
+#define ECONNREFUSED 61 /* Connection refused */
+
+#define ELOOP 62 /* Too many levels of symbolic links */
+#endif /* _POSIX_SOURCE */
+#define ENAMETOOLONG 63 /* File name too long */
+
+/* should be rearranged */
+#ifndef _POSIX_SOURCE
+#define EHOSTDOWN 64 /* Host is down */
+#define EHOSTUNREACH 65 /* No route to host */
+#endif /* _POSIX_SOURCE */
+#define ENOTEMPTY 66 /* Directory not empty */
+
+/* quotas & mush */
+#ifndef _POSIX_SOURCE
+#define EPROCLIM 67 /* Too many processes */
+#define EUSERS 68 /* Too many users */
+#define EDQUOT 69 /* Disc quota exceeded */
+
+/* Network File System */
+#define ESTALE 70 /* Stale NFS file handle */
+#define EREMOTE 71 /* Too many levels of remote in path */
+#define EBADRPC 72 /* RPC struct is bad */
+#define ERPCMISMATCH 73 /* RPC version wrong */
+#define EPROGUNAVAIL 74 /* RPC prog. not avail */
+#define EPROGMISMATCH 75 /* Program version wrong */
+#define EPROCUNAVAIL 76 /* Bad procedure for program */
+#endif /* _POSIX_SOURCE */
+
+#define ENOLCK 77 /* No locks available */
+#define ENOSYS 78 /* Function not implemented */
+
+#ifndef _POSIX_SOURCE
+#define EFTYPE 79 /* Inappropriate file type or format */
+#define EAUTH 80 /* Authentication error */
+#define ENEEDAUTH 81 /* Need authenticator */
+#define ELAST 81 /* Must be equal largest errno */
+#endif /* _POSIX_SOURCE */
+
+#endif
diff --git a/mit-pthreads/machdep/bsdi-1.1/socket.h b/mit-pthreads/machdep/bsdi-1.1/socket.h
new file mode 100755
index 00000000000..39d7c1cce26
--- /dev/null
+++ b/mit-pthreads/machdep/bsdi-1.1/socket.h
@@ -0,0 +1,277 @@
+/* BSDI $Id$ */
+
+/*
+ * Copyright (c) 1982,1985,1986,1988 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)socket.h 7.13 (Berkeley) 4/20/91
+ */
+
+#ifndef _SOCKET_H_
+#define _SOCKET_H_
+
+/*
+ * Definitions related to sockets: types, address families, options.
+ */
+
+/*
+ * Types
+ */
+#define SOCK_STREAM 1 /* stream socket */
+#define SOCK_DGRAM 2 /* datagram socket */
+#define SOCK_RAW 3 /* raw-protocol interface */
+#define SOCK_RDM 4 /* reliably-delivered message */
+#define SOCK_SEQPACKET 5 /* sequenced packet stream */
+
+/*
+ * Option flags per-socket.
+ */
+#define SO_DEBUG 0x0001 /* turn on debugging info recording */
+#define SO_ACCEPTCONN 0x0002 /* socket has had listen() */
+#define SO_REUSEADDR 0x0004 /* allow local address reuse */
+#define SO_KEEPALIVE 0x0008 /* keep connections alive */
+#define SO_DONTROUTE 0x0010 /* just use interface addresses */
+#define SO_BROADCAST 0x0020 /* permit sending of broadcast msgs */
+#define SO_USELOOPBACK 0x0040 /* bypass hardware when possible */
+#define SO_LINGER 0x0080 /* linger on close if data present */
+#define SO_OOBINLINE 0x0100 /* leave received OOB data in line */
+
+/*
+ * Additional options, not kept in so_options.
+ */
+#define SO_SNDBUF 0x1001 /* send buffer size */
+#define SO_RCVBUF 0x1002 /* receive buffer size */
+#define SO_SNDLOWAT 0x1003 /* send low-water mark */
+#define SO_RCVLOWAT 0x1004 /* receive low-water mark */
+#define SO_SNDTIMEO 0x1005 /* send timeout */
+#define SO_RCVTIMEO 0x1006 /* receive timeout */
+#define SO_ERROR 0x1007 /* get error status and clear */
+#define SO_TYPE 0x1008 /* get socket type */
+
+/*
+ * Structure used for manipulating linger option.
+ */
+struct linger {
+ int l_onoff; /* option on/off */
+ int l_linger; /* linger time */
+};
+
+/*
+ * Level number for (get/set)sockopt() to apply to socket itself.
+ */
+#define SOL_SOCKET 0xffff /* options for socket level */
+
+/*
+ * Address families.
+ */
+#define AF_UNSPEC 0 /* unspecified */
+#define AF_UNIX 1 /* local to host (pipes, portals) */
+#define AF_INET 2 /* internetwork: UDP, TCP, etc. */
+#define AF_IMPLINK 3 /* arpanet imp addresses */
+#define AF_PUP 4 /* pup protocols: e.g. BSP */
+#define AF_CHAOS 5 /* mit CHAOS protocols */
+#define AF_NS 6 /* XEROX NS protocols */
+#define AF_ISO 7 /* ISO protocols */
+#define AF_OSI AF_ISO
+#define AF_ECMA 8 /* european computer manufacturers */
+#define AF_DATAKIT 9 /* datakit protocols */
+#define AF_CCITT 10 /* CCITT protocols, X.25 etc */
+#define AF_SNA 11 /* IBM SNA */
+#define AF_DECnet 12 /* DECnet */
+#define AF_DLI 13 /* DEC Direct data link interface */
+#define AF_LAT 14 /* LAT */
+#define AF_HYLINK 15 /* NSC Hyperchannel */
+#define AF_APPLETALK 16 /* Apple Talk */
+#define AF_ROUTE 17 /* Internal Routing Protocol */
+#define AF_LINK 18 /* Link layer interface */
+#define pseudo_AF_XTP 19 /* eXpress Transfer Protocol (no AF) */
+
+#define AF_MAX 20
+
+/*
+ * Structure used by kernel to store most
+ * addresses.
+ */
+struct sockaddr {
+ u_char sa_len; /* total length */
+ u_char sa_family; /* address family */
+ char sa_data[14]; /* actually longer; address value */
+};
+
+/*
+ * Structure used by kernel to pass protocol
+ * information in raw sockets.
+ */
+struct sockproto {
+ u_short sp_family; /* address family */
+ u_short sp_protocol; /* protocol */
+};
+
+/*
+ * Protocol families, same as address families for now.
+ */
+#define PF_UNSPEC AF_UNSPEC
+#define PF_UNIX AF_UNIX
+#define PF_INET AF_INET
+#define PF_IMPLINK AF_IMPLINK
+#define PF_PUP AF_PUP
+#define PF_CHAOS AF_CHAOS
+#define PF_NS AF_NS
+#define PF_ISO AF_ISO
+#define PF_OSI AF_ISO
+#define PF_ECMA AF_ECMA
+#define PF_DATAKIT AF_DATAKIT
+#define PF_CCITT AF_CCITT
+#define PF_SNA AF_SNA
+#define PF_DECnet AF_DECnet
+#define PF_DLI AF_DLI
+#define PF_LAT AF_LAT
+#define PF_HYLINK AF_HYLINK
+#define PF_APPLETALK AF_APPLETALK
+#define PF_ROUTE AF_ROUTE
+#define PF_LINK AF_LINK
+#define PF_XTP pseudo_AF_XTP /* really just proto family, no AF */
+
+#define PF_MAX AF_MAX
+
+/*
+ * Maximum queue length specifiable by listen.
+ */
+#define SOMAXCONN 5
+
+/*
+ * Message header for recvmsg and sendmsg calls.
+ * Used value-result for recvmsg, value only for sendmsg.
+ */
+struct msghdr {
+ caddr_t msg_name; /* optional address */
+ u_int msg_namelen; /* size of address */
+ struct iovec *msg_iov; /* scatter/gather array */
+ u_int msg_iovlen; /* # elements in msg_iov */
+ caddr_t msg_control; /* ancillary data, see below */
+ u_int msg_controllen; /* ancillary data buffer len */
+ int msg_flags; /* flags on received message */
+};
+
+#define MSG_OOB 0x1 /* process out-of-band data */
+#define MSG_PEEK 0x2 /* peek at incoming message */
+#define MSG_DONTROUTE 0x4 /* send without using routing tables */
+#define MSG_EOR 0x8 /* data completes record */
+#define MSG_TRUNC 0x10 /* data discarded before delivery */
+#define MSG_CTRUNC 0x20 /* control data lost before delivery */
+#define MSG_WAITALL 0x40 /* wait for full request or error */
+
+/*
+ * Header for ancillary data objects in msg_control buffer.
+ * Used for additional information with/about a datagram
+ * not expressible by flags. The format is a sequence
+ * of message elements headed by cmsghdr structures.
+ */
+struct cmsghdr {
+ u_int cmsg_len; /* data byte count, including hdr */
+ int cmsg_level; /* originating protocol */
+ int cmsg_type; /* protocol-specific type */
+/* followed by u_char cmsg_data[]; */
+};
+
+/* given pointer to struct adatahdr, return pointer to data */
+#define CMSG_DATA(cmsg) ((u_char *)((cmsg) + 1))
+
+/* given pointer to struct adatahdr, return pointer to next adatahdr */
+#define CMSG_NXTHDR(mhdr, cmsg) \
+ (((caddr_t)(cmsg) + (cmsg)->cmsg_len + sizeof(struct cmsghdr) > \
+ (mhdr)->msg_control + (mhdr)->msg_controllen) ? \
+ (struct cmsghdr *)NULL : \
+ (struct cmsghdr *)((caddr_t)(cmsg) + ALIGN((cmsg)->cmsg_len)))
+
+#define CMSG_FIRSTHDR(mhdr) ((struct cmsghdr *)(mhdr)->msg_control)
+
+/* "Socket"-level control message types: */
+#define SCM_RIGHTS 0x01 /* access rights (array of int) */
+
+/*
+ * 4.3 compat sockaddr, move to compat file later
+ */
+struct osockaddr {
+ u_short sa_family; /* address family */
+ char sa_data[14]; /* up to 14 bytes of direct address */
+};
+
+/*
+ * 4.3-compat message header (move to compat file later).
+ */
+struct omsghdr {
+ caddr_t msg_name; /* optional address */
+ int msg_namelen; /* size of address */
+ struct iovec *msg_iov; /* scatter/gather array */
+ int msg_iovlen; /* # elements in msg_iov */
+ caddr_t msg_accrights; /* access rights sent/received */
+ int msg_accrightslen;
+};
+
+#ifndef KERNEL
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+int accept __P_((int, struct sockaddr *, int *));
+int bind __P_((int, const struct sockaddr *, int));
+int connect __P_((int, const struct sockaddr *, int));
+int getpeername __P_((int, struct sockaddr *, int *));
+int getsockname __P_((int, struct sockaddr *, int *));
+int getsockopt __P_((int, int, int, void *, int *));
+int listen __P_((int, int));
+/* original definitions
+int recv __P_((int, void *, int, int));
+int recvfrom __P_((int, void *, int, int,
+ struct sockaddr *, int *));
+int recvmsg __P_((int, struct msghdr *, int));
+int send __P_((int, const void *, int, int));
+int sendto __P_((int, const void *, int, int, const struct sockaddr *, int));
+int sendmsg __P_((int, const struct msghdr *, int));
+*/
+ssize_t recv __P_((int, void *, size_t, int));
+ssize_t recvfrom __P_((int, void *, size_t, int,
+ struct sockaddr *, int *));
+ssize_t recvmsg __P_((int, struct msghdr *, int));
+ssize_t send __P_((int, const void *, size_t, int));
+ssize_t sendto __P_((int, const void *, size_t, int,
+ const struct sockaddr *, int));
+ssize_t sendmsg __P_((int, const struct msghdr *, int));
+int setsockopt __P_((int, int, int, const void *, int));
+int shutdown __P_((int, int));
+int socket __P_((int, int, int));
+int socketpair __P_((int, int, int, int *));
+__END_DECLS
+
+#endif /* !KERNEL */
+
+#endif /* !_SOCKET_H_ */
diff --git a/mit-pthreads/machdep/bsdi-1.1/timers.h b/mit-pthreads/machdep/bsdi-1.1/timers.h
new file mode 100755
index 00000000000..7101ab99106
--- /dev/null
+++ b/mit-pthreads/machdep/bsdi-1.1/timers.h
@@ -0,0 +1,59 @@
+/* ==== timers.h ============================================================
+ * Copyright (c) 1994 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ *
+ * Description : Basic timers header.
+ *
+ * 1.00 94/06/13 proven
+ * -Started coding this file.
+ */
+
+#ifndef _SYS_TIMERS_H_
+#define _SYS_TIMERS_H_
+
+#include <sys/time.h>
+
+struct timespec {
+ time_t tv_sec;
+ long tv_nsec;
+};
+
+#define TIMEVAL_TO_TIMESPEC(tv, ts) { \
+ (ts)->tv_sec = (tv)->tv_sec; \
+ (ts)->tv_nsec = (tv)->tv_usec * 1000; \
+}
+#define TIMESPEC_TO_TIMEVAL(tv, ts) { \
+ (tv)->tv_sec = (ts)->tv_sec; \
+ (tv)->tv_usec = (ts)->tv_nsec / 1000; \
+}
+
+#endif
diff --git a/mit-pthreads/machdep/bsdi-2.0/__math.h b/mit-pthreads/machdep/bsdi-2.0/__math.h
new file mode 100755
index 00000000000..2c919472f33
--- /dev/null
+++ b/mit-pthreads/machdep/bsdi-2.0/__math.h
@@ -0,0 +1,6 @@
+/*
+ * ANSI/POSIX
+ */
+/* Generate an overflow to create +Inf; the multiply shuts up gcc 1 */
+#define HUGE_VAL (1e250*1e250) /* IEEE: positive infinity */
+
diff --git a/mit-pthreads/machdep/bsdi-2.0/__path.h b/mit-pthreads/machdep/bsdi-2.0/__path.h
new file mode 100755
index 00000000000..9c347016f5f
--- /dev/null
+++ b/mit-pthreads/machdep/bsdi-2.0/__path.h
@@ -0,0 +1,13 @@
+/*
+ * from: @(#)time.h 5.12 (Berkeley) 3/9/91
+ * __path.h,v 1.1 1995/01/03 12:53:32 proven Exp
+ */
+
+#ifndef _SYS__PATH_H_
+#define _SYS__PATH_H_
+
+#define _PATH_PTY "/dev/"
+#define _PATH_TZDIR "/usr/share/zoneinfo"
+#define _PATH_TZFILE "/etc/localtime"
+
+#endif /* !_SYS__PATH_H_ */
diff --git a/mit-pthreads/machdep/bsdi-2.0/__signal.h b/mit-pthreads/machdep/bsdi-2.0/__signal.h
new file mode 100755
index 00000000000..d3deecf15e2
--- /dev/null
+++ b/mit-pthreads/machdep/bsdi-2.0/__signal.h
@@ -0,0 +1,7 @@
+#include <sys/signal.h>
+
+#define __SIGEMPTYSET 0
+#define __SIGFILLSET 0xffffffff
+#define __SIGADDSET(s, n) (*(s) |= 1 << ((n) - 1), 0)
+#define __SIGDELSET(s, n) (*(s) &= ~(1 << ((n) - 1)), 0)
+#define __SIGISMEMBER(s, n) ((*(s) & (1 << ((n) - 1))) != 0)
diff --git a/mit-pthreads/machdep/bsdi-2.0/__stdio.h b/mit-pthreads/machdep/bsdi-2.0/__stdio.h
new file mode 100755
index 00000000000..d4d37c2017c
--- /dev/null
+++ b/mit-pthreads/machdep/bsdi-2.0/__stdio.h
@@ -0,0 +1,7 @@
+#include <machine/ansi.h>
+#ifdef _BSD_SIZE_T_
+typedef _BSD_SIZE_T_ size_t;
+#undef _BSD_SIZE_T_
+#endif
+
+typedef pthread_fpos_t fpos_t; /* Must match off_t <sys/types.h> */
diff --git a/mit-pthreads/machdep/bsdi-2.0/__stdlib.h b/mit-pthreads/machdep/bsdi-2.0/__stdlib.h
new file mode 100755
index 00000000000..189bb5e8799
--- /dev/null
+++ b/mit-pthreads/machdep/bsdi-2.0/__stdlib.h
@@ -0,0 +1,60 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)stdlib.h 5.13 (Berkeley) 6/4/91
+ * __stdlib.h,v 1.1 1995/01/03 12:53:34 proven Exp
+ */
+
+#ifndef _SYS___STDLIB_H_
+#define _SYS___STDLIB_H_
+
+#include <machine/ansi.h>
+
+#ifdef _BSD_SIZE_T_
+typedef _BSD_SIZE_T_ size_t;
+#undef _BSD_SIZE_T_
+#endif
+
+#ifdef _BSD_WCHAR_T_
+typedef _BSD_WCHAR_T_ wchar_t;
+#undef _BSD_WCHAR_T_
+#endif
+
+#ifndef __NORETURN
+#define __NORETURN
+#endif
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#endif /* _STDLIB_H_ */
diff --git a/mit-pthreads/machdep/bsdi-2.0/__string.h b/mit-pthreads/machdep/bsdi-2.0/__string.h
new file mode 100755
index 00000000000..275032946ea
--- /dev/null
+++ b/mit-pthreads/machdep/bsdi-2.0/__string.h
@@ -0,0 +1,19 @@
+#include <machine/ansi.h>
+#ifdef _BSD_SIZE_T_
+typedef _BSD_SIZE_T_ size_t;
+#undef _BSD_SIZE_T_
+#endif
+
+/* Non-standard NetBSD string routines. */
+#if !defined(_ANSI_SOURCE) && !defined(_POSIX_SOURCE)
+__BEGIN_DECLS
+int bcmp __P_((const void *, const void *, size_t));
+void bcopy __P_((const void *, void *, size_t));
+void bzero __P_((void *, size_t));
+char *index __P_((const char *, int));
+char *rindex __P_((const char *, int));
+char *strdup __P_((const char *));
+void strmode __P_((int, char *));
+char *strsep __P_((char **, const char *));
+__END_DECLS
+#endif
diff --git a/mit-pthreads/machdep/bsdi-2.0/__time.h b/mit-pthreads/machdep/bsdi-2.0/__time.h
new file mode 100755
index 00000000000..bc4d956486d
--- /dev/null
+++ b/mit-pthreads/machdep/bsdi-2.0/__time.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * (c) UNIX System Laboratories, Inc.
+ * All or some portions of this file are derived from material licensed
+ * to the University of California by American Telephone and Telegraph
+ * Co. or Unix System Laboratories, Inc. and are reproduced herein with
+ * the permission of UNIX System Laboratories, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)time.h 5.12 (Berkeley) 3/9/91
+ * __time.h,v 1.1 1994/12/13 07:18:55 proven Exp
+ */
+
+#ifndef _SYS__TIME_H_
+#define _SYS__TIME_H_
+
+#include <machine/ansi.h>
+
+#ifdef _BSD_CLOCK_T_
+typedef _BSD_CLOCK_T_ clock_t;
+#undef _BSD_CLOCK_T_
+#endif
+
+#ifdef _BSD_TIME_T_
+typedef _BSD_TIME_T_ time_t;
+#undef _BSD_TIME_T_
+#endif
+
+#ifdef _BSD_SIZE_T_
+typedef _BSD_SIZE_T_ size_t;
+#undef _BSD_SIZE_T_
+#endif
+
+#endif /* !_SYS__TIME_H_ */
diff --git a/mit-pthreads/machdep/bsdi-2.0/__unistd.h b/mit-pthreads/machdep/bsdi-2.0/__unistd.h
new file mode 100755
index 00000000000..4a5ee6a245e
--- /dev/null
+++ b/mit-pthreads/machdep/bsdi-2.0/__unistd.h
@@ -0,0 +1,109 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)stdlib.h 5.13 (Berkeley) 6/4/91
+ * __unistd.h,v 1.1 1995/01/03 12:53:35 proven Exp
+ */
+
+#ifndef _SYS___UNISTD_H_
+#define _SYS___UNISTD_H_
+
+#include <sys/types.h>
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#define ioctl_request_type unsigned long /* For fd.c */
+
+/* compile-time symbolic constants */
+#define _POSIX_JOB_CONTROL /* implementation supports job control */
+
+#ifdef _NOT_AVAILABLE
+#define _POSIX_SAVED_IDS /* saved set-user-ID and set-group-ID */
+#endif
+
+#define _POSIX_VERSION 198808L
+#define _POSIX2_VERSION 199212L
+
+/* execution-time symbolic constants */
+ /* chown requires appropriate privileges */
+#define _POSIX_CHOWN_RESTRICTED 1
+ /* too-long path components generate errors */
+#define _POSIX_NO_TRUNC 1
+ /* may disable terminal special characters */
+#define _POSIX_VDISABLE ((unsigned char)'\377')
+
+/* configurable pathname variables */
+#define _PC_LINK_MAX 1
+#define _PC_MAX_CANON 2
+#define _PC_MAX_INPUT 3
+#define _PC_NAME_MAX 4
+#define _PC_PATH_MAX 5
+#define _PC_PIPE_BUF 6
+#define _PC_CHOWN_RESTRICTED 7
+#define _PC_NO_TRUNC 8
+#define _PC_VDISABLE 9
+
+/* configurable system variables */
+#define _SC_ARG_MAX 1
+#define _SC_CHILD_MAX 2
+#define _SC_CLK_TCK 3
+#define _SC_NGROUPS_MAX 4
+#define _SC_OPEN_MAX 5
+#define _SC_JOB_CONTROL 6
+#define _SC_SAVED_IDS 7
+#define _SC_VERSION 8
+#define _SC_BC_BASE_MAX 9
+#define _SC_BC_DIM_MAX 10
+#define _SC_BC_SCALE_MAX 11
+#define _SC_BC_STRING_MAX 12
+#define _SC_COLL_WEIGHTS_MAX 13
+#define _SC_EXPR_NEST_MAX 14
+#define _SC_LINE_MAX 15
+#define _SC_RE_DUP_MAX 16
+#define _SC_2_VERSION 17
+#define _SC_2_C_BIND 18
+#define _SC_2_C_DEV 19
+#define _SC_2_CHAR_TERM 20
+#define _SC_2_FORT_DEV 21
+#define _SC_2_FORT_RUN 22
+#define _SC_2_LOCALEDEF 23
+#define _SC_2_SW_DEV 24
+#define _SC_2_UPE 25
+#define _SC_STREAM_MAX 26
+#define _SC_TZNAME_MAX 27
+
+/* configurable system strings */
+#define _CS_PATH 1
+
+#endif
diff --git a/mit-pthreads/machdep/bsdi-2.0/compat.h b/mit-pthreads/machdep/bsdi-2.0/compat.h
new file mode 100755
index 00000000000..0dfdc27f9e8
--- /dev/null
+++ b/mit-pthreads/machdep/bsdi-2.0/compat.h
@@ -0,0 +1,65 @@
+/*-
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)dirent.h 5.18 (Berkeley) 2/23/91
+ */
+
+#ifndef _SYS_DIRENT_H_
+#define _SYS_DIRENT_H_
+
+/*
+ * A directory entry has a struct dirent at the front of it, containing its
+ * inode number, the length of the entry, and the length of the name
+ * contained in the entry. These are followed by the name padded to a 4
+ * byte boundary with null bytes. All names are guaranteed null terminated.
+ * The maximum length of a name in a directory is MAXNAMLEN.
+ */
+
+struct dirent {
+ u_long d_fileno; /* file number of entry */
+ u_short d_reclen; /* length of this record */
+ u_short d_namlen; /* length of string in d_name */
+#ifdef _POSIX_SOURCE
+ char d_name[255 + 1]; /* name must be no longer than this */
+#else
+#define MAXNAMLEN 255
+ char d_name[MAXNAMLEN + 1]; /* name must be no longer than this */
+#endif
+};
+
+#define d_ino d_fileno /* backward compatibility */
+
+/* definitions for library routines operating on directories. */
+#define DIRBLKSIZ 1024
+
+#endif /* !_DIRENT_H_ */
+
diff --git a/mit-pthreads/machdep/bsdi-2.0/dirent.h b/mit-pthreads/machdep/bsdi-2.0/dirent.h
new file mode 100755
index 00000000000..0dfdc27f9e8
--- /dev/null
+++ b/mit-pthreads/machdep/bsdi-2.0/dirent.h
@@ -0,0 +1,65 @@
+/*-
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)dirent.h 5.18 (Berkeley) 2/23/91
+ */
+
+#ifndef _SYS_DIRENT_H_
+#define _SYS_DIRENT_H_
+
+/*
+ * A directory entry has a struct dirent at the front of it, containing its
+ * inode number, the length of the entry, and the length of the name
+ * contained in the entry. These are followed by the name padded to a 4
+ * byte boundary with null bytes. All names are guaranteed null terminated.
+ * The maximum length of a name in a directory is MAXNAMLEN.
+ */
+
+struct dirent {
+ u_long d_fileno; /* file number of entry */
+ u_short d_reclen; /* length of this record */
+ u_short d_namlen; /* length of string in d_name */
+#ifdef _POSIX_SOURCE
+ char d_name[255 + 1]; /* name must be no longer than this */
+#else
+#define MAXNAMLEN 255
+ char d_name[MAXNAMLEN + 1]; /* name must be no longer than this */
+#endif
+};
+
+#define d_ino d_fileno /* backward compatibility */
+
+/* definitions for library routines operating on directories. */
+#define DIRBLKSIZ 1024
+
+#endif /* !_DIRENT_H_ */
+
diff --git a/mit-pthreads/machdep/bsdi-2.0/errno.h b/mit-pthreads/machdep/bsdi-2.0/errno.h
new file mode 100755
index 00000000000..1a3c37d0147
--- /dev/null
+++ b/mit-pthreads/machdep/bsdi-2.0/errno.h
@@ -0,0 +1,162 @@
+
+/* $NetBSD: errno.h,v 1.8 1994/06/29 06:44:02 cgd Exp $ */
+
+/*
+ * Copyright (c) 1982, 1986, 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ * (c) UNIX System Laboratories, Inc.
+ * All or some portions of this file are derived from material licensed
+ * to the University of California by American Telephone and Telegraph
+ * Co. or Unix System Laboratories, Inc. and are reproduced herein with
+ * the permission of UNIX System Laboratories, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)errno.h 8.5 (Berkeley) 1/21/94
+ */
+
+#ifndef _SYS_ERRNO_H_
+#define _SYS_ERRNO_H_
+
+#define EPERM 1 /* Operation not permitted */
+#define ENOENT 2 /* No such file or directory */
+#define ESRCH 3 /* No such process */
+#define EINTR 4 /* Interrupted system call */
+#define EIO 5 /* Input/output error */
+#define ENXIO 6 /* Device not configured */
+#define E2BIG 7 /* Argument list too long */
+#define ENOEXEC 8 /* Exec format error */
+#define EBADF 9 /* Bad file descriptor */
+#define ECHILD 10 /* No child processes */
+#define EDEADLK 11 /* Resource deadlock avoided */
+ /* 11 was EAGAIN */
+#define ENOMEM 12 /* Cannot allocate memory */
+#define EACCES 13 /* Permission denied */
+#define EFAULT 14 /* Bad address */
+#ifndef _POSIX_SOURCE
+#define ENOTBLK 15 /* Block device required */
+#endif
+#define EBUSY 16 /* Device busy */
+#define EEXIST 17 /* File exists */
+#define EXDEV 18 /* Cross-device link */
+#define ENODEV 19 /* Operation not supported by device */
+#define ENOTDIR 20 /* Not a directory */
+#define EISDIR 21 /* Is a directory */
+#define EINVAL 22 /* Invalid argument */
+#define ENFILE 23 /* Too many open files in system */
+#define EMFILE 24 /* Too many open files */
+#define ENOTTY 25 /* Inappropriate ioctl for device */
+#ifndef _POSIX_SOURCE
+#define ETXTBSY 26 /* Text file busy */
+#endif
+#define EFBIG 27 /* File too large */
+#define ENOSPC 28 /* No space left on device */
+#define ESPIPE 29 /* Illegal seek */
+#define EROFS 30 /* Read-only file system */
+#define EMLINK 31 /* Too many links */
+#define EPIPE 32 /* Broken pipe */
+
+/* math software */
+#define EDOM 33 /* Numerical argument out of domain */
+#define ERANGE 34 /* Result too large */
+
+/* non-blocking and interrupt i/o */
+#define EAGAIN 35 /* Resource temporarily unavailable */
+#ifndef _POSIX_SOURCE
+#define EWOULDBLOCK EAGAIN /* Operation would block */
+#define EINPROGRESS 36 /* Operation now in progress */
+#define EALREADY 37 /* Operation already in progress */
+
+/* ipc/network software -- argument errors */
+#define ENOTSOCK 38 /* Socket operation on non-socket */
+#define EDESTADDRREQ 39 /* Destination address required */
+#define EMSGSIZE 40 /* Message too long */
+#define EPROTOTYPE 41 /* Protocol wrong type for socket */
+#define ENOPROTOOPT 42 /* Protocol not available */
+#define EPROTONOSUPPORT 43 /* Protocol not supported */
+#define ESOCKTNOSUPPORT 44 /* Socket type not supported */
+#define EOPNOTSUPP 45 /* Operation not supported */
+#define EPFNOSUPPORT 46 /* Protocol family not supported */
+#define EAFNOSUPPORT 47 /* Address family not supported by protocol family */
+#define EADDRINUSE 48 /* Address already in use */
+#define EADDRNOTAVAIL 49 /* Can't assign requested address */
+
+/* ipc/network software -- operational errors */
+#define ENETDOWN 50 /* Network is down */
+#define ENETUNREACH 51 /* Network is unreachable */
+#define ENETRESET 52 /* Network dropped connection on reset */
+#define ECONNABORTED 53 /* Software caused connection abort */
+#define ECONNRESET 54 /* Connection reset by peer */
+#define ENOBUFS 55 /* No buffer space available */
+#define EISCONN 56 /* Socket is already connected */
+#define ENOTCONN 57 /* Socket is not connected */
+#define ESHUTDOWN 58 /* Can't send after socket shutdown */
+#define ETOOMANYREFS 59 /* Too many references: can't splice */
+#define ETIMEDOUT 60 /* Operation timed out */
+#define ECONNREFUSED 61 /* Connection refused */
+
+#define ELOOP 62 /* Too many levels of symbolic links */
+#endif /* _POSIX_SOURCE */
+#define ENAMETOOLONG 63 /* File name too long */
+
+/* should be rearranged */
+#ifndef _POSIX_SOURCE
+#define EHOSTDOWN 64 /* Host is down */
+#define EHOSTUNREACH 65 /* No route to host */
+#endif /* _POSIX_SOURCE */
+#define ENOTEMPTY 66 /* Directory not empty */
+
+/* quotas & mush */
+#ifndef _POSIX_SOURCE
+#define EPROCLIM 67 /* Too many processes */
+#define EUSERS 68 /* Too many users */
+#define EDQUOT 69 /* Disc quota exceeded */
+
+/* Network File System */
+#define ESTALE 70 /* Stale NFS file handle */
+#define EREMOTE 71 /* Too many levels of remote in path */
+#define EBADRPC 72 /* RPC struct is bad */
+#define ERPCMISMATCH 73 /* RPC version wrong */
+#define EPROGUNAVAIL 74 /* RPC prog. not avail */
+#define EPROGMISMATCH 75 /* Program version wrong */
+#define EPROCUNAVAIL 76 /* Bad procedure for program */
+#endif /* _POSIX_SOURCE */
+
+#define ENOLCK 77 /* No locks available */
+#define ENOSYS 78 /* Function not implemented */
+
+#ifndef _POSIX_SOURCE
+#define EFTYPE 79 /* Inappropriate file type or format */
+#define EAUTH 80 /* Authentication error */
+#define ENEEDAUTH 81 /* Need authenticator */
+#define ELAST 81 /* Must be equal largest errno */
+#endif /* _POSIX_SOURCE */
+
+#endif
+
diff --git a/mit-pthreads/machdep/bsdi-2.0/time.h b/mit-pthreads/machdep/bsdi-2.0/time.h
new file mode 100755
index 00000000000..a8bf0ff8f82
--- /dev/null
+++ b/mit-pthreads/machdep/bsdi-2.0/time.h
@@ -0,0 +1,6 @@
+#ifndef ts_sec
+#define ts_sec tv_sec
+#define ts_nsec tv_nsec
+#endif
+#include "/usr/include/sys/time.h"
+
diff --git a/mit-pthreads/machdep/bsdi-2.0/timers.h b/mit-pthreads/machdep/bsdi-2.0/timers.h
new file mode 100755
index 00000000000..b603b78e6b2
--- /dev/null
+++ b/mit-pthreads/machdep/bsdi-2.0/timers.h
@@ -0,0 +1,45 @@
+/* ==== timers.h ============================================================
+ * Copyright (c) 1994 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * timers.h,v 1.50 1994/08/08 03:44:09 proven Exp
+ *
+ * Description : Basic timers header.
+ *
+ * 1.00 94/06/13 proven
+ * -Started coding this file.
+ */
+
+#ifndef _SYS_TIMERS_H_
+#define _SYS_TIMERS_H_
+
+#include <sys/time.h>
+
+#endif
diff --git a/mit-pthreads/machdep/bsdi-2.0/wait.h b/mit-pthreads/machdep/bsdi-2.0/wait.h
new file mode 100755
index 00000000000..5f7635a73a7
--- /dev/null
+++ b/mit-pthreads/machdep/bsdi-2.0/wait.h
@@ -0,0 +1,159 @@
+/* $NetBSD: wait.h,v 1.7 1994/06/29 06:46:23 cgd Exp $ */
+
+/*
+ * Copyright (c) 1982, 1986, 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)wait.h 8.1 (Berkeley) 6/2/93
+ */
+
+/*
+ * This file holds definitions relevent to the wait4 system call
+ * and the alternate interfaces that use it (wait, wait3, waitpid).
+ */
+
+/*
+ * Macros to test the exit status returned by wait
+ * and extract the relevant values.
+ */
+#ifdef _POSIX_SOURCE
+#define _W_INT(i) (i)
+#else
+#define _W_INT(w) (*(int *)&(w)) /* convert union wait to int */
+#define WCOREFLAG 0200
+#endif
+
+#define _WSTATUS(x) (_W_INT(x) & 0177)
+#define _WSTOPPED 0177 /* _WSTATUS if process is stopped */
+#define WIFSTOPPED(x) (_WSTATUS(x) == _WSTOPPED)
+#define WSTOPSIG(x) (_W_INT(x) >> 8)
+#define WIFSIGNALED(x) (_WSTATUS(x) != _WSTOPPED && _WSTATUS(x) != 0)
+#define WTERMSIG(x) (_WSTATUS(x))
+#define WIFEXITED(x) (_WSTATUS(x) == 0)
+#define WEXITSTATUS(x) (_W_INT(x) >> 8)
+#ifndef _POSIX_SOURCE
+#define WCOREDUMP(x) (_W_INT(x) & WCOREFLAG)
+
+#define W_EXITCODE(ret, sig) ((ret) << 8 | (sig))
+#define W_STOPCODE(sig) ((sig) << 8 | _WSTOPPED)
+#endif
+
+/*
+ * Option bits for the third argument of wait4. WNOHANG causes the
+ * wait to not hang if there are no stopped or terminated processes, rather
+ * returning an error indication in this case (pid==0). WUNTRACED
+ * indicates that the caller should receive status about untraced children
+ * which stop due to signals. If children are stopped and a wait without
+ * this option is done, it is as though they were still running... nothing
+ * about them is returned.
+ */
+#define WNOHANG 1 /* dont hang in wait */
+#define WUNTRACED 2 /* tell about stopped, untraced children */
+
+#ifndef _POSIX_SOURCE
+/* POSIX extensions and 4.2/4.3 compatability: */
+
+/*
+ * Tokens for special values of the "pid" parameter to wait4.
+ */
+#define WAIT_ANY (-1) /* any process */
+#define WAIT_MYPGRP 0 /* any process in my process group */
+
+#include <machine/endian.h>
+
+/*
+ * Deprecated:
+ * Structure of the information in the status word returned by wait4.
+ * If w_stopval==WSTOPPED, then the second structure describes
+ * the information returned, else the first.
+ */
+union wait {
+ int w_status; /* used in syscall */
+ /*
+ * Terminated process status.
+ */
+ struct {
+#if BYTE_ORDER == LITTLE_ENDIAN
+ unsigned int w_Termsig:7, /* termination signal */
+ w_Coredump:1, /* core dump indicator */
+ w_Retcode:8, /* exit code if w_termsig==0 */
+ w_Filler:16; /* upper bits filler */
+#endif
+#if BYTE_ORDER == BIG_ENDIAN
+ unsigned int w_Filler:16, /* upper bits filler */
+ w_Retcode:8, /* exit code if w_termsig==0 */
+ w_Coredump:1, /* core dump indicator */
+ w_Termsig:7; /* termination signal */
+#endif
+ } w_T;
+ /*
+ * Stopped process status. Returned
+ * only for traced children unless requested
+ * with the WUNTRACED option bit.
+ */
+ struct {
+#if BYTE_ORDER == LITTLE_ENDIAN
+ unsigned int w_Stopval:8, /* == W_STOPPED if stopped */
+ w_Stopsig:8, /* signal that stopped us */
+ w_Filler:16; /* upper bits filler */
+#endif
+#if BYTE_ORDER == BIG_ENDIAN
+ unsigned int w_Filler:16, /* upper bits filler */
+ w_Stopsig:8, /* signal that stopped us */
+ w_Stopval:8; /* == W_STOPPED if stopped */
+#endif
+ } w_S;
+};
+#define w_termsig w_T.w_Termsig
+#define w_coredump w_T.w_Coredump
+#define w_retcode w_T.w_Retcode
+#define w_stopval w_S.w_Stopval
+#define w_stopsig w_S.w_Stopsig
+
+#define WSTOPPED _WSTOPPED
+#endif /* _POSIX_SOURCE */
+
+#ifndef KERNEL
+#include <sys/types.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+struct rusage; /* forward declaration */
+
+pid_t wait __P_((int *));
+pid_t waitpid __P_((pid_t, int *, int));
+#ifndef _POSIX_SOURCE
+pid_t wait3 __P_((int *, int, void *));
+pid_t wait4 __P_((pid_t, int *, int, void *));
+#endif
+__END_DECLS
+#endif
+
diff --git a/mit-pthreads/machdep/engine-alpha-netbsd-1.1.c b/mit-pthreads/machdep/engine-alpha-netbsd-1.1.c
new file mode 100644
index 00000000000..c1ff04db16d
--- /dev/null
+++ b/mit-pthreads/machdep/engine-alpha-netbsd-1.1.c
@@ -0,0 +1,196 @@
+/* ==== machdep.c ============================================================
+ * Copyright (c) 1993, 1994 Chris Provenzano, proven@athena.mit.edu
+ *
+ * Description : Machine dependent functions for NetBSD/Alpha 1.1(+)
+ *
+ * 1.00 93/08/04 proven
+ * -Started coding this file.
+ *
+ * 95/04/22 cgd
+ * -Modified to make it go with NetBSD/Alpha
+ */
+
+#ifndef lint
+static const char rcsid[] = "engine-alpha-osf1.c,v 1.4.4.1 1995/12/13 05:41:37 proven Exp";
+#endif
+
+#include <pthread.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/syscall.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <stdio.h>
+
+/* ==========================================================================
+ * machdep_save_state()
+ */
+int machdep_save_state(void)
+{
+ return __machdep_save_int_state(pthread_run->machdep_data.machdep_istate);
+}
+
+void machdep_restore_state(void)
+{
+ __machdep_restore_int_state(pthread_run->machdep_data.machdep_istate);
+}
+
+void machdep_save_float_state (void)
+{
+ __machdep_save_fp_state(pthread_run->machdep_data.machdep_fstate);
+}
+
+void machdep_restore_float_state (void)
+{
+ __machdep_restore_fp_state(pthread_run->machdep_data.machdep_fstate);
+}
+
+/* ==========================================================================
+ * machdep_set_thread_timer()
+ */
+void machdep_set_thread_timer(struct machdep_pthread *machdep_pthread)
+{
+ if (setitimer(ITIMER_VIRTUAL, &(machdep_pthread->machdep_timer), NULL)) {
+ PANIC();
+ }
+}
+
+/* ==========================================================================
+ * machdep_unset_thread_timer()
+ */
+void machdep_unset_thread_timer(struct machdep_pthread *machdep_pthread)
+{
+ struct itimerval zeroval = { { 0, 0 }, { 0, 0} };
+
+ if (setitimer(ITIMER_VIRTUAL, &zeroval, NULL)) {
+ PANIC();
+ }
+}
+
+/* ==========================================================================
+ * machdep_pthread_cleanup()
+ */
+void *machdep_pthread_cleanup(struct machdep_pthread *machdep_pthread)
+{
+ return(machdep_pthread->machdep_stack);
+}
+
+/* ==========================================================================
+ * machdep_pthread_start()
+ */
+void machdep_pthread_start(void)
+{
+ context_switch_done();
+ pthread_sched_resume ();
+
+ /* Run current threads start routine with argument */
+ pthread_exit(pthread_run->machdep_data.start_routine
+ (pthread_run->machdep_data.start_argument));
+
+ /* should never reach here */
+ PANIC();
+}
+
+/* ==========================================================================
+ * __machdep_stack_free()
+ */
+void __machdep_stack_free(void * stack)
+{
+ free(stack);
+}
+
+/* ==========================================================================
+ * __machdep_stack_alloc()
+ */
+void * __machdep_stack_alloc(size_t size)
+{
+ void * stack;
+
+ return(malloc(size));
+}
+
+/* ==========================================================================
+ * __machdep_pthread_create()
+ */
+void __machdep_pthread_create(struct machdep_pthread *machdep_pthread,
+ void *(* start_routine)(), void *start_argument,
+ long stack_size, long nsec, long flags)
+{
+ machdep_pthread->start_routine = start_routine;
+ machdep_pthread->start_argument = start_argument;
+
+ machdep_pthread->machdep_timer.it_value.tv_sec = 0;
+ machdep_pthread->machdep_timer.it_interval.tv_sec = 0;
+ machdep_pthread->machdep_timer.it_interval.tv_usec = 0;
+ machdep_pthread->machdep_timer.it_value.tv_usec = nsec / 1000;
+
+ /* Set up new stack frame so that it looks like it returned from a
+ longjmp() to the beginning of machdep_pthread_start(). */
+ machdep_pthread->machdep_istate[8/*ISTATE_RA*/] = 0;
+ machdep_pthread->machdep_istate[0/*ISTATE_PC*/] = (long)machdep_pthread_start;
+ machdep_pthread->machdep_istate[10/*ISTATE_PV*/] = (long)machdep_pthread_start;
+
+ /* Alpha stack starts high and builds down. */
+ {
+ long stk_addr = (long) machdep_pthread->machdep_stack;
+ stk_addr += stack_size - 1024;
+ stk_addr &= ~15;
+ machdep_pthread->machdep_istate[9/*ISTATE_SP*/] = stk_addr;
+ }
+}
+
+int safe_store (loc, new)
+ int *loc;
+ int new;
+{
+ int locked, old;
+ asm ("mb" : : : "memory");
+ do {
+ asm ("ldl_l %0,%1" : "=r" (old) : "m" (*loc));
+ asm ("stl_c %0,%1" : "=r" (locked), "=m" (*loc) : "0" (new));
+ } while (!locked);
+ asm ("mb" : : : "memory");
+ return old;
+}
+
+/* ==========================================================================
+ * machdep_sys_creat()
+ */
+machdep_sys_creat(char * path, int mode)
+{
+ return(machdep_sys_open(path, O_WRONLY | O_CREAT | O_TRUNC, mode));
+}
+
+/* ==========================================================================
+ * machdep_sys_wait3()
+ */
+machdep_sys_wait3(int * b, int c, int * d)
+{
+ return(machdep_sys_wait4(0, b, c, d));
+}
+
+/* ==========================================================================
+ * machdep_sys_waitpid()
+ */
+machdep_sys_waitpid(int a, int * b, int c)
+{
+ return(machdep_sys_wait4(a, b, c, NULL));
+}
+
+/* ==========================================================================
+ * machdep_sys_getdtablesize()
+ */
+machdep_sys_getdtablesize()
+{
+ return(sysconf(_SC_OPEN_MAX));
+}
+
+/* ==========================================================================
+ * machdep_sys_lseek()
+ */
+off_t machdep_sys_lseek(int fd, off_t offset, int whence)
+{
+ extern off_t __syscall();
+
+ return(__syscall((quad_t)SYS_lseek, fd, 0, offset, whence));
+}
diff --git a/mit-pthreads/machdep/engine-alpha-netbsd-1.1.h b/mit-pthreads/machdep/engine-alpha-netbsd-1.1.h
new file mode 100644
index 00000000000..50c872da7b6
--- /dev/null
+++ b/mit-pthreads/machdep/engine-alpha-netbsd-1.1.h
@@ -0,0 +1,111 @@
+/* ==== machdep.h ============================================================
+ * Copyright (c) 1994 Chris Provenzano (proven@athena.mit.edu) and
+ * Ken Raeburn (raeburn@mit.edu).
+ *
+ * engine-alpha-osf1.h,v 1.4.4.1 1995/12/13 05:41:42 proven Exp
+ *
+ */
+
+#include <unistd.h>
+#include <setjmp.h>
+#include <sys/time.h>
+#include <sys/cdefs.h>
+
+/* The first machine dependent functions are the SEMAPHORES needing
+ the test and set instruction.
+
+ On the Alpha, the actual values here are irrelevant; they just have
+ to be different. */
+#define SEMAPHORE_CLEAR 0
+#define SEMAPHORE_SET 1
+
+#if 0
+#define SEMAPHORE_TEST_AND_SET(lock) \
+({ int *_sem_lock = (lock), locked, old; \
+ asm ("mb" : : : "memory"); \
+ do { asm ("ldl_l %0,%1" : "=r" (old) : "m" (*_sem_lock)); \
+ /* ?? if (old != SEMAPHORE_CLEAR) break; */ \
+ asm ("stl_c %0,%1" : "=r" (locked), "=m" (*_sem_lock) \
+ : "0" (SEMAPHORE_SET)); \
+ } while (!locked); \
+ asm ("mb" : : : "memory"); \
+ old == SEMAPHORE_CLEAR; })
+
+#define SEMAPHORE_RESET(lock) \
+({ int *_sem_lock = (lock); \
+ *_sem_lock = SEMAPHORE_CLEAR; \
+ asm ("mb" : : : "memory"); })
+#endif
+
+/*
+ * New types
+ */
+typedef int semaphore;
+
+/*
+ * sigset_t macros
+ */
+#define SIG_ANY(sig) (sig)
+#define SIGMAX 31
+
+/*
+ * New Strutures
+ */
+struct machdep_pthread {
+ void *(*start_routine)(void *);
+ void *start_argument;
+ void *machdep_stack;
+ struct itimerval machdep_timer;
+ unsigned long machdep_istate[11];
+ unsigned long machdep_fstate[9];
+};
+
+/*
+ * Static machdep_pthread initialization values.
+ * For initial thread only.
+ */
+#define MACHDEP_PTHREAD_INIT \
+ { NULL, NULL, NULL, { { 0, 0 }, { 0, 100000 } }, 0 }
+
+/*
+ * Minimum stack size
+ */
+#define PTHREAD_STACK_MIN 2048
+
+/*
+ * Some fd flag defines that are necessary to distinguish between posix
+ * behavior and bsd4.3 behavior.
+ */
+#define __FD_NONBLOCK O_NONBLOCK
+
+/*
+ * New functions
+ */
+
+__BEGIN_DECLS
+
+#if defined(PTHREAD_KERNEL)
+
+#define __machdep_stack_get(x) (x)->machdep_stack
+#define __machdep_stack_set(x, y) (x)->machdep_stack = y
+#define __machdep_stack_repl(x, y) \
+{ \
+ if (stack = __machdep_stack_get(x)) { \
+ __machdep_stack_free(stack); \
+ } \
+ __machdep_stack_set(x, y); \
+}
+
+void * __machdep_stack_alloc __P_((size_t));
+void __machdep_stack_free __P_((void *));
+
+int machdep_save_state __P_((void));
+
+int __machdep_save_int_state __P_((unsigned long *));
+void __machdep_restore_int_state __P_((unsigned long *));
+void __machdep_save_fp_state __P_((unsigned long *));
+void __machdep_restore_fp_state __P_((unsigned long *));
+
+#endif
+
+__END_DECLS
diff --git a/mit-pthreads/machdep/engine-alpha-netbsd-1.3.c b/mit-pthreads/machdep/engine-alpha-netbsd-1.3.c
new file mode 100644
index 00000000000..0932c421ea2
--- /dev/null
+++ b/mit-pthreads/machdep/engine-alpha-netbsd-1.3.c
@@ -0,0 +1,204 @@
+/* ==== machdep.c ============================================================
+ * Copyright (c) 1993, 1994 Chris Provenzano, proven@athena.mit.edu
+ *
+ * Description : Machine dependent functions for NetBSD/Alpha 1.1(+)
+ *
+ * 1.00 93/08/04 proven
+ * -Started coding this file.
+ *
+ * 95/04/22 cgd
+ * -Modified to make it go with NetBSD/Alpha
+ */
+
+#ifndef lint
+static const char rcsid[] = "engine-alpha-osf1.c,v 1.4.4.1 1995/12/13 05:41:37 proven Exp";
+#endif
+
+#include <pthread.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/syscall.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <stdio.h>
+
+/* ==========================================================================
+ * machdep_save_state()
+ */
+int machdep_save_state(void)
+{
+ return __machdep_save_int_state(pthread_run->machdep_data.machdep_istate);
+}
+
+void machdep_restore_state(void)
+{
+ __machdep_restore_int_state(pthread_run->machdep_data.machdep_istate);
+}
+
+void machdep_save_float_state (void)
+{
+ __machdep_save_fp_state(pthread_run->machdep_data.machdep_fstate);
+}
+
+void machdep_restore_float_state (void)
+{
+ __machdep_restore_fp_state(pthread_run->machdep_data.machdep_fstate);
+}
+
+/* ==========================================================================
+ * machdep_set_thread_timer()
+ */
+void machdep_set_thread_timer(struct machdep_pthread *machdep_pthread)
+{
+ if (setitimer(ITIMER_VIRTUAL, &(machdep_pthread->machdep_timer), NULL)) {
+ PANIC();
+ }
+}
+
+/* ==========================================================================
+ * machdep_unset_thread_timer()
+ */
+void machdep_unset_thread_timer(struct machdep_pthread *machdep_pthread)
+{
+ struct itimerval zeroval = { { 0, 0 }, { 0, 0} };
+
+ if (setitimer(ITIMER_VIRTUAL, &zeroval, NULL)) {
+ PANIC();
+ }
+}
+
+/* ==========================================================================
+ * machdep_pthread_cleanup()
+ */
+void *machdep_pthread_cleanup(struct machdep_pthread *machdep_pthread)
+{
+ return(machdep_pthread->machdep_stack);
+}
+
+/* ==========================================================================
+ * machdep_pthread_start()
+ */
+void machdep_pthread_start(void)
+{
+ context_switch_done();
+ pthread_sched_resume ();
+
+ /* Run current threads start routine with argument */
+ pthread_exit(pthread_run->machdep_data.start_routine
+ (pthread_run->machdep_data.start_argument));
+
+ /* should never reach here */
+ PANIC();
+}
+
+/* ==========================================================================
+ * __machdep_stack_free()
+ */
+void __machdep_stack_free(void * stack)
+{
+ free(stack);
+}
+
+/* ==========================================================================
+ * __machdep_stack_alloc()
+ */
+void * __machdep_stack_alloc(size_t size)
+{
+ void * stack;
+
+ return(malloc(size));
+}
+
+/* ==========================================================================
+ * __machdep_pthread_create()
+ */
+void __machdep_pthread_create(struct machdep_pthread *machdep_pthread,
+ void *(* start_routine)(), void *start_argument,
+ long stack_size, long nsec, long flags)
+{
+ machdep_pthread->start_routine = start_routine;
+ machdep_pthread->start_argument = start_argument;
+
+ machdep_pthread->machdep_timer.it_value.tv_sec = 0;
+ machdep_pthread->machdep_timer.it_interval.tv_sec = 0;
+ machdep_pthread->machdep_timer.it_interval.tv_usec = 0;
+ machdep_pthread->machdep_timer.it_value.tv_usec = nsec / 1000;
+
+ /* Set up new stack frame so that it looks like it returned from a
+ longjmp() to the beginning of machdep_pthread_start(). */
+ machdep_pthread->machdep_istate[8/*ISTATE_RA*/] = 0;
+ machdep_pthread->machdep_istate[0/*ISTATE_PC*/] = (long)machdep_pthread_start;
+ machdep_pthread->machdep_istate[10/*ISTATE_PV*/] = (long)machdep_pthread_start;
+
+ /* Alpha stack starts high and builds down. */
+ {
+ long stk_addr = (long) machdep_pthread->machdep_stack;
+ stk_addr += stack_size - 1024;
+ stk_addr &= ~15;
+ machdep_pthread->machdep_istate[9/*ISTATE_SP*/] = stk_addr;
+ }
+}
+
+int safe_store (loc, new)
+ int *loc;
+ int new;
+{
+ int locked, old;
+ asm ("mb" : : : "memory");
+ do {
+ asm ("ldl_l %0,%1" : "=r" (old) : "m" (*loc));
+ asm ("stl_c %0,%1" : "=r" (locked), "=m" (*loc) : "0" (new));
+ } while (!locked);
+ asm ("mb" : : : "memory");
+ return old;
+}
+
+/* ==========================================================================
+ * machdep_sys_creat()
+ */
+machdep_sys_creat(char * path, int mode)
+{
+ return(machdep_sys_open(path, O_WRONLY | O_CREAT | O_TRUNC, mode));
+}
+
+/* ==========================================================================
+ * machdep_sys_wait3()
+ */
+machdep_sys_wait3(int * b, int c, int * d)
+{
+ return(machdep_sys_wait4(0, b, c, d));
+}
+
+/* ==========================================================================
+ * machdep_sys_waitpid()
+ */
+machdep_sys_waitpid(int a, int * b, int c)
+{
+ return(machdep_sys_wait4(a, b, c, NULL));
+}
+
+/* ==========================================================================
+ * machdep_sys_getdtablesize()
+ */
+machdep_sys_getdtablesize()
+{
+ return(sysconf(_SC_OPEN_MAX));
+}
+
+/* ==========================================================================
+ * machdep_sys_lseek()
+ */
+off_t machdep_sys_lseek(int fd, off_t offset, int whence)
+{
+ extern off_t __syscall();
+
+ return(__syscall((quad_t)SYS_lseek, fd, 0, offset, whence));
+}
+
+/* ==========================================================================
+ * machdep_sys_getdirentries()
+ */
+machdep_sys_getdirentries(int fd, char * buf, int len, int * seek)
+{
+ return(machdep_sys_getdents(fd, buf, len));
+}
diff --git a/mit-pthreads/machdep/engine-alpha-netbsd-1.3.h b/mit-pthreads/machdep/engine-alpha-netbsd-1.3.h
new file mode 100644
index 00000000000..bc4178d3c41
--- /dev/null
+++ b/mit-pthreads/machdep/engine-alpha-netbsd-1.3.h
@@ -0,0 +1,114 @@
+/* ==== machdep.h ============================================================
+ * Copyright (c) 1994 Chris Provenzano (proven@athena.mit.edu) and
+ * Ken Raeburn (raeburn@mit.edu).
+ *
+ * engine-alpha-osf1.h,v 1.4.4.1 1995/12/13 05:41:42 proven Exp
+ *
+ */
+
+#include <unistd.h>
+#include <setjmp.h>
+#include <sys/time.h>
+#include <sys/cdefs.h>
+#include <sys/signal.h> /* for _NSIG */
+
+/* The first machine dependent functions are the SEMAPHORES needing
+ the test and set instruction.
+
+ On the Alpha, the actual values here are irrelevant; they just have
+ to be different. */
+#define SEMAPHORE_CLEAR 0
+#define SEMAPHORE_SET 1
+
+#if 0
+#define SEMAPHORE_TEST_AND_SET(lock) \
+({ int *_sem_lock = (lock), locked, old; \
+ asm ("mb" : : : "memory"); \
+ do { asm ("ldl_l %0,%1" : "=r" (old) : "m" (*_sem_lock)); \
+ /* ?? if (old != SEMAPHORE_CLEAR) break; */ \
+ asm ("stl_c %0,%1" : "=r" (locked), "=m" (*_sem_lock) \
+ : "0" (SEMAPHORE_SET)); \
+ } while (!locked); \
+ asm ("mb" : : : "memory"); \
+ old == SEMAPHORE_CLEAR; })
+
+#define SEMAPHORE_RESET(lock) \
+({ int *_sem_lock = (lock); \
+ *_sem_lock = SEMAPHORE_CLEAR; \
+ asm ("mb" : : : "memory"); })
+#endif
+
+/*
+ * New types
+ */
+typedef int semaphore;
+
+/*
+ * sigset_t macros
+ */
+#define SIG_ANY(sig) (sig)
+#define SIGMAX (_NSIG-1)
+
+/*
+ * New Strutures
+ */
+struct machdep_pthread {
+ void *(*start_routine)(void *);
+ void *start_argument;
+ void *machdep_stack;
+ struct itimerval machdep_timer;
+ unsigned long machdep_istate[11];
+ unsigned long machdep_fstate[9];
+};
+
+/*
+ * Static machdep_pthread initialization values.
+ * For initial thread only.
+ */
+#define MACHDEP_PTHREAD_INIT \
+ { NULL, NULL, NULL, { { 0, 0 }, { 0, 100000 } }, 0 }
+
+/*
+ * Minimum stack size
+ */
+#define PTHREAD_STACK_MIN 2048
+
+/*
+ * Some fd flag defines that are necessary to distinguish between posix
+ * behavior and bsd4.3 behavior.
+ */
+#define __FD_NONBLOCK O_NONBLOCK
+
+/*
+ * New functions
+ */
+
+__BEGIN_DECLS
+
+#if defined(PTHREAD_KERNEL)
+
+#define __machdep_stack_get(x) (x)->machdep_stack
+#define __machdep_stack_set(x, y) (x)->machdep_stack = y
+#define __machdep_stack_repl(x, y) \
+{ \
+ if (stack = __machdep_stack_get(x)) { \
+ __machdep_stack_free(stack); \
+ } \
+ __machdep_stack_set(x, y); \
+}
+
+void * __machdep_stack_alloc __P_((size_t));
+void __machdep_stack_free __P_((void *));
+
+int machdep_save_state __P_((void));
+
+int __machdep_save_int_state __P_((unsigned long *));
+void __machdep_restore_int_state __P_((unsigned long *));
+void __machdep_save_fp_state __P_((unsigned long *));
+void __machdep_restore_fp_state __P_((unsigned long *));
+
+extern off_t machdep_sys_lseek(int, off_t, int);
+
+#endif
+
+__END_DECLS
diff --git a/mit-pthreads/machdep/engine-alpha-osf1.c b/mit-pthreads/machdep/engine-alpha-osf1.c
new file mode 100644
index 00000000000..9b563a56c28
--- /dev/null
+++ b/mit-pthreads/machdep/engine-alpha-osf1.c
@@ -0,0 +1,207 @@
+/* ==== machdep.c ============================================================
+ * Copyright (c) 1993, 1994 Chris Provenzano, proven@athena.mit.edu
+ *
+ * Description : Machine dependent functions for SunOS-4.1.3 on sparc
+ *
+ * 1.00 93/08/04 proven
+ * -Started coding this file.
+ */
+
+#ifndef lint
+static const char rcsid[] = "$Id$";
+#endif
+
+#include <pthread.h>
+#include <stdlib.h>
+
+/* These would be defined in setjmp.h, if _POSIX_SOURCE and _XOPEN_SOURCE
+ were both undefined. But we've already included it, and lost the
+ opportunity. */
+#define JB_PC 2
+#define JB_RA 30
+#define JB_PV 31
+#define JB_SP 34
+
+/* ==========================================================================
+ * machdep_save_state()
+ */
+int machdep_save_state(void)
+{
+ return setjmp (pthread_run->machdep_data.machdep_state);
+}
+
+/* ==========================================================================
+ * machdep_restore_state()
+ */
+extern void machdep_restore_from_setjmp (jmp_buf, long);
+void machdep_restore_state(void)
+{
+ machdep_restore_from_setjmp (pthread_run->machdep_data.machdep_state, 1);
+}
+
+void machdep_save_float_state (void) { }
+void machdep_restore_float_state (void) { }
+
+/* ==========================================================================
+ * machdep_set_thread_timer()
+ */
+void machdep_set_thread_timer(struct machdep_pthread *machdep_pthread)
+{
+ if (setitimer(ITIMER_VIRTUAL, &(machdep_pthread->machdep_timer), NULL)) {
+ PANIC();
+ }
+}
+
+/* ==========================================================================
+ * machdep_unset_thread_timer()
+ */
+void machdep_unset_thread_timer(struct machdep_pthread *machdep_pthread)
+{
+ struct itimerval zeroval = { { 0, 0 }, { 0, 0} };
+
+ if (setitimer(ITIMER_VIRTUAL, &zeroval, NULL)) {
+ PANIC();
+ }
+}
+
+/* ==========================================================================
+ * machdep_pthread_cleanup()
+ */
+void *machdep_pthread_cleanup(struct machdep_pthread *machdep_pthread)
+{
+ return(machdep_pthread->machdep_stack);
+}
+
+/* ==========================================================================
+ * machdep_pthread_start()
+ */
+void machdep_pthread_start(void)
+{
+ context_switch_done();
+ pthread_sched_resume ();
+
+ /* Run current threads start routine with argument */
+ pthread_exit(pthread_run->machdep_data.start_routine
+ (pthread_run->machdep_data.start_argument));
+
+ /* should never reach here */
+ PANIC();
+}
+
+/* ==========================================================================
+ * __machdep_stack_free()
+ */
+void __machdep_stack_free(void * stack)
+{
+ free(stack);
+}
+
+/* ==========================================================================
+ * __machdep_stack_alloc()
+ */
+void * __machdep_stack_alloc(size_t size)
+{
+ void * stack;
+
+ return(malloc(size));
+}
+
+/* ==========================================================================
+ * __machdep_pthread_create()
+ */
+void __machdep_pthread_create(struct machdep_pthread *machdep_pthread,
+ void *(* start_routine)(), void *start_argument,
+ long stack_size, long nsec, long flags)
+{
+ machdep_pthread->start_routine = start_routine;
+ machdep_pthread->start_argument = start_argument;
+
+ machdep_pthread->machdep_timer.it_value.tv_sec = 0;
+ machdep_pthread->machdep_timer.it_interval.tv_sec = 0;
+ machdep_pthread->machdep_timer.it_interval.tv_usec = 0;
+ machdep_pthread->machdep_timer.it_value.tv_usec = nsec / 1000;
+
+ setjmp(machdep_pthread->machdep_state);
+
+ /* Set up new stack frame so that it looks like it returned from a
+ longjmp() to the beginning of machdep_pthread_start(). */
+ machdep_pthread->machdep_state[JB_RA] = 0;
+ machdep_pthread->machdep_state[JB_PC] = (long)machdep_pthread_start;
+ machdep_pthread->machdep_state[JB_PV] = (long)machdep_pthread_start;
+
+ /* Alpha stack starts high and builds down. */
+ {
+ long stk_addr = (long) machdep_pthread->machdep_stack;
+ stk_addr += stack_size - 1024;
+ stk_addr &= ~15;
+ machdep_pthread->machdep_state[JB_SP] = stk_addr;
+ }
+}
+
+/* ==========================================================================
+ * machdep_sys_wait3()
+ */
+machdep_sys_wait3(int * b, int c, int * d)
+{
+ return(machdep_sys_wait4(0, b, c, d));
+}
+
+/* ==========================================================================
+ * machdep_sys_waitpid()
+ */
+machdep_sys_waitpid(int pid, int * statusp, int options)
+{
+ return machdep_sys_wait4 (pid, statusp, options, NULL);
+}
+
+/* These are found in flsbuf.o in the Alpha libc. I don't know what
+ they're for, precisely. */
+static xxx;
+_bufsync (p)
+ char *p;
+{
+ long a1 = *(long *)(p+48);
+ long t0 = *(long *)(p+8);
+ long v0 = a1 - t0;
+ long t1, t2;
+
+ abort ();
+
+ v0 += xxx;
+ if (v0 < 0)
+ {
+ *(char**)(p + 8) = p;
+ return v0;
+ }
+ t1 = *(int*)p;
+ t2 = v0 - t1;
+ if (t2 < 0)
+ *(int*)p = (int) v0;
+ return v0;
+}
+
+_findbuf () { abort (); }
+_wrtchk () { abort (); }
+_xflsbuf () { abort (); }
+_flsbuf () { abort (); }
+
+void __xxx_never_called () {
+ /* Force other stuff to get dragged in. */
+ _cleanup ();
+ fflush (NULL);
+ fclose (NULL);
+}
+
+int safe_store (loc, new)
+ int *loc;
+ int new;
+{
+ int locked, old;
+ asm ("mb" : : : "memory");
+ do {
+ asm ("ldl_l %0,%1" : "=r" (old) : "m" (*loc));
+ asm ("stl_c %0,%1" : "=r" (locked), "=m" (*loc) : "0" (new));
+ } while (!locked);
+ asm ("mb" : : : "memory");
+ return old;
+}
diff --git a/mit-pthreads/machdep/engine-alpha-osf1.h b/mit-pthreads/machdep/engine-alpha-osf1.h
new file mode 100644
index 00000000000..fdf374ccc44
--- /dev/null
+++ b/mit-pthreads/machdep/engine-alpha-osf1.h
@@ -0,0 +1,110 @@
+/* ==== machdep.h ============================================================
+ * Copyright (c) 1994 Chris Provenzano (proven@athena.mit.edu) and
+ * Ken Raeburn (raeburn@mit.edu).
+ *
+ * $Id$
+ *
+ */
+
+#ifndef sigwait
+#define sigwait __bogus_osf1_sigwait
+#endif
+
+#include <unistd.h>
+#include <setjmp.h>
+#include <sys/time.h>
+#include <sys/cdefs.h>
+
+#undef sigwait
+
+/* The first machine dependent functions are the SEMAPHORES needing
+ the test and set instruction.
+
+ On the Alpha, the actual values here are irrelevant; they just have
+ to be different. */
+#define SEMAPHORE_CLEAR 0
+#define SEMAPHORE_SET 1
+
+#if 0
+#define SEMAPHORE_TEST_AND_SET(lock) \
+({ int *_sem_lock = (lock), locked, old; \
+ asm ("mb" : : : "memory"); \
+ do { asm ("ldl_l %0,%1" : "=r" (old) : "m" (*_sem_lock)); \
+ /* ?? if (old != SEMAPHORE_CLEAR) break; */ \
+ asm ("stl_c %0,%1" : "=r" (locked), "=m" (*_sem_lock) \
+ : "0" (SEMAPHORE_SET)); \
+ } while (!locked); \
+ asm ("mb" : : : "memory"); \
+ old == SEMAPHORE_CLEAR; })
+
+#define SEMAPHORE_RESET(lock) \
+({ int *_sem_lock = (lock); \
+ *_sem_lock = SEMAPHORE_CLEAR; \
+ asm ("mb" : : : "memory"); })
+#endif
+
+/*
+ * New types
+ */
+typedef int semaphore;
+
+/*
+ * sigset_t macros
+ */
+#define SIG_ANY(sig) (sig)
+
+/*
+ * New Strutures
+ */
+struct machdep_pthread {
+ void *(*start_routine)(void *);
+ void *start_argument;
+ void *machdep_stack;
+ struct itimerval machdep_timer;
+ jmp_buf machdep_state;
+};
+
+/*
+ * Static machdep_pthread initialization values.
+ * For initial thread only.
+ */
+#define MACHDEP_PTHREAD_INIT \
+ { NULL, NULL, NULL, { { 0, 0 }, { 0, 100000 } }, 0 }
+
+/*
+ * Minimum stack size
+ */
+#define PTHREAD_STACK_MIN 2048
+
+/*
+ * Some fd flag defines that are necessary to distinguish between posix
+ * behavior and bsd4.3 behavior.
+ */
+#define __FD_NONBLOCK O_NONBLOCK
+
+/*
+ * New functions
+ */
+
+__BEGIN_DECLS
+
+#if defined(PTHREAD_KERNEL)
+
+#define __machdep_stack_get(x) (x)->machdep_stack
+#define __machdep_stack_set(x, y) (x)->machdep_stack = y
+#define __machdep_stack_repl(x, y) \
+{ \
+ if (stack = __machdep_stack_get(x)) { \
+ __machdep_stack_free(stack); \
+ } \
+ __machdep_stack_set(x, y); \
+}
+
+void * __machdep_stack_alloc __P_((size_t));
+void __machdep_stack_free __P_((void *));
+
+int machdep_save_state __P_((void));
+
+#endif
+
+__END_DECLS
diff --git a/mit-pthreads/machdep/engine-arm32-netbsd-1.3.c b/mit-pthreads/machdep/engine-arm32-netbsd-1.3.c
new file mode 100644
index 00000000000..510b35fdb0e
--- /dev/null
+++ b/mit-pthreads/machdep/engine-arm32-netbsd-1.3.c
@@ -0,0 +1,203 @@
+/* ==== machdep.c ============================================================
+ * Copyright (c) 1993, 1994 Chris Provenzano, proven@athena.mit.edu
+ *
+ * Description : Machine dependent functions for NetBSD on arm32
+ *
+ * 1.00 93/08/04 proven
+ * -Started coding this file.
+ *
+ * 98/10/22 bad
+ * -adapt from i386 version
+ */
+
+#ifndef lint
+static const char rcsid[] = "$Id$";
+#endif
+
+#include <pthread.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/syscall.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <stdio.h>
+
+#if defined(_JB_REG_R13)
+#define REG_LR _JB_REG_R14
+#define REG_SP _JB_REG_R13
+#else
+#define REG_LR JMPBUF_REG_R14
+#define REG_SP JMPBUF_REG_R13
+#endif
+
+/* ==========================================================================
+ * machdep_save_state()
+ */
+int machdep_save_state(void)
+{
+ return(_setjmp(pthread_run->machdep_data.machdep_state));
+}
+
+/* ==========================================================================
+ * machdep_save_state()
+ */
+int machdep_save_float_state(struct pthread * pthread)
+{
+ return;
+}
+
+/* ==========================================================================
+ * machdep_restore_state()
+ */
+void machdep_restore_state(void)
+{
+ _longjmp(pthread_run->machdep_data.machdep_state, 1);
+}
+
+/* ==========================================================================
+ * machdep_restore_float_state()
+ */
+int machdep_restore_float_state(void)
+{
+ return;
+}
+
+/* ==========================================================================
+ * machdep_set_thread_timer()
+ */
+void machdep_set_thread_timer(struct machdep_pthread *machdep_pthread)
+{
+ if (setitimer(ITIMER_VIRTUAL, &(machdep_pthread->machdep_timer), NULL)) {
+ PANIC();
+ }
+}
+
+/* ==========================================================================
+ * machdep_unset_thread_timer()
+ */
+void machdep_unset_thread_timer(struct machdep_pthread *machdep_pthread)
+{
+ struct itimerval zeroval = { { 0, 0 }, { 0, 0 } };
+ int ret;
+
+ if (machdep_pthread) {
+ ret = setitimer(ITIMER_VIRTUAL, &zeroval,
+ &(machdep_pthread->machdep_timer));
+ } else {
+ ret = setitimer(ITIMER_VIRTUAL, &zeroval, NULL);
+ }
+
+ if (ret) {
+ PANIC();
+ }
+}
+
+/* ==========================================================================
+ * machdep_pthread_cleanup()
+ */
+void *machdep_pthread_cleanup(struct machdep_pthread *machdep_pthread)
+{
+ return(machdep_pthread->machdep_stack);
+}
+
+/* ==========================================================================
+ * machdep_pthread_start()
+ */
+void machdep_pthread_start(void)
+{
+ context_switch_done();
+ pthread_sched_resume();
+
+ /* Run current threads start routine with argument */
+ pthread_exit(pthread_run->machdep_data.start_routine
+ (pthread_run->machdep_data.start_argument));
+
+ /* should never reach here */
+ PANIC();
+}
+
+/* ==========================================================================
+ * __machdep_stack_free()
+ */
+void __machdep_stack_free(void * stack)
+{
+ free(stack);
+}
+
+/* ==========================================================================
+ * __machdep_stack_alloc()
+ */
+void * __machdep_stack_alloc(size_t size)
+{
+ void * stack;
+
+ return(malloc(size));
+}
+
+/* ==========================================================================
+ * __machdep_pthread_create()
+ */
+void __machdep_pthread_create(struct machdep_pthread *machdep_pthread,
+ void *(* start_routine)(), void *start_argument,
+ long stack_size, long nsec, long flags)
+{
+ machdep_pthread->start_routine = start_routine;
+ machdep_pthread->start_argument = start_argument;
+
+ machdep_pthread->machdep_timer.it_value.tv_sec = 0;
+ machdep_pthread->machdep_timer.it_interval.tv_sec = 0;
+ machdep_pthread->machdep_timer.it_interval.tv_usec = 0;
+ machdep_pthread->machdep_timer.it_value.tv_usec = nsec / 1000;
+
+ _setjmp(machdep_pthread->machdep_state);
+ /*
+ * Set up new stact frame so that it looks like it
+ * returned from a longjmp() to the beginning of
+ * machdep_pthread_start().
+ */
+ machdep_pthread->machdep_state[REG_LR] = (int)machdep_pthread_start;
+
+ /* Stack starts high and builds down. */
+ machdep_pthread->machdep_state[REG_SP] =
+ (int)machdep_pthread->machdep_stack + stack_size;
+}
+
+/* ==========================================================================
+ * machdep_sys_creat()
+ */
+machdep_sys_creat(char * path, int mode)
+{
+ return(machdep_sys_open(path, O_WRONLY | O_CREAT | O_TRUNC, mode));
+}
+
+/* ==========================================================================
+ * machdep_sys_wait3()
+ */
+machdep_sys_wait3(int * b, int c, int * d)
+{
+ return(machdep_sys_wait4(0, b, c, d));
+}
+
+/* ==========================================================================
+ * machdep_sys_waitpid()
+ */
+machdep_sys_waitpid(int a, int * b, int c)
+{
+ return(machdep_sys_wait4(a, b, c, NULL));
+}
+
+/* ==========================================================================
+ * machdep_sys_getdtablesize()
+ */
+machdep_sys_getdtablesize()
+{
+ return(sysconf(_SC_OPEN_MAX));
+}
+
+/* ==========================================================================
+ * machdep_sys_getdirentries()
+ */
+machdep_sys_getdirentries(int fd, char * buf, int len, int * seek)
+{
+ return(machdep_sys_getdents(fd, buf, len));
+}
diff --git a/mit-pthreads/machdep/engine-arm32-netbsd-1.3.h b/mit-pthreads/machdep/engine-arm32-netbsd-1.3.h
new file mode 100644
index 00000000000..c8a4e79386a
--- /dev/null
+++ b/mit-pthreads/machdep/engine-arm32-netbsd-1.3.h
@@ -0,0 +1,102 @@
+/* ==== machdep.h ============================================================
+ * Copyright (c) 1993 Chris Provenzano, proven@athena.mit.edu
+ *
+ * Id: engine-i386-netbsd-1.3.h,v 1.1 1998/02/28 04:53:15 cjs Exp
+ *
+ */
+
+#include <unistd.h>
+#include <setjmp.h>
+#include <sys/time.h>
+#include <sys/signal.h> /* for _NSIG */
+
+/*
+ * The first machine dependent functions are the SEMAPHORES
+ * needing the test and set instruction.
+ */
+#define SEMAPHORE_CLEAR 0
+#define SEMAPHORE_SET 1
+
+#if 0
+#define SEMAPHORE_TEST_AND_SET(lock) \
+({ \
+long temp = SEMAPHORE_SET; \
+ \
+__asm__ volatile ("xchgl %0,(%2)" \
+ :"=r" (temp) \
+ :"0" (temp),"r" (lock)); \
+temp; \
+})
+
+#define SEMAPHORE_RESET(lock) *lock = SEMAPHORE_CLEAR
+#endif
+
+/*
+ * New types
+ */
+typedef long semaphore;
+
+/*
+ * sigset_t macros
+ */
+#define SIG_ANY(sig) (sig)
+#define SIGMAX (_NSIG-1)
+
+/*
+ * New Strutures
+ */
+struct machdep_pthread {
+ void *(*start_routine)(void *);
+ void *start_argument;
+ void *machdep_stack;
+ struct itimerval machdep_timer;
+ jmp_buf machdep_state;
+#if 0
+ char machdep_float_state[108];
+#endif
+};
+
+/*
+ * Static machdep_pthread initialization values.
+ * For initial thread only.
+ */
+#define MACHDEP_PTHREAD_INIT \
+{ NULL, NULL, NULL, { { 0, 0 }, { 0, 100000 } }, 0 }
+
+/*
+ * Minimum stack size
+ */
+#define PTHREAD_STACK_MIN 1024
+
+/*
+ * Some fd flag defines that are necessary to distinguish between posix
+ * behavior and bsd4.3 behavior.
+ */
+#define __FD_NONBLOCK O_NONBLOCK
+
+/*
+ * New functions
+ */
+
+__BEGIN_DECLS
+
+#if defined(PTHREAD_KERNEL)
+
+#define __machdep_stack_get(x) (x)->machdep_stack
+#define __machdep_stack_set(x, y) (x)->machdep_stack = y
+#define __machdep_stack_repl(x, y) \
+{ \
+ if (stack = __machdep_stack_get(x)) { \
+ __machdep_stack_free(stack); \
+ } \
+ __machdep_stack_set(x, y); \
+}
+
+void * __machdep_stack_alloc __P_((size_t));
+void __machdep_stack_free __P_((void *));
+
+int machdep_save_state __P_((void));
+
+#endif
+
+__END_DECLS
diff --git a/mit-pthreads/machdep/engine-hppa-hpux-10.20.c b/mit-pthreads/machdep/engine-hppa-hpux-10.20.c
new file mode 100644
index 00000000000..f6f0b2e0f1d
--- /dev/null
+++ b/mit-pthreads/machdep/engine-hppa-hpux-10.20.c
@@ -0,0 +1,169 @@
+/* ==== machdep.c ============================================================
+ * Copyright (c) 1993 Chris Provenzano, proven@athena.mit.edu
+ *
+ * Description : Machine dependent functions for HP-UX 9.03 on hppa
+ *
+ * 1.00 93/12/14 proven
+ * -Started coding this file.
+ */
+
+#include <pthread.h>
+#include <setjmp.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+volatile int setupStack = 0;
+
+/* ==========================================================================
+ * machdep_save_state()
+ */
+int machdep_save_state(void)
+{
+ return(setjmp(pthread_run->machdep_data.machdep_state));
+}
+
+/* ==========================================================================
+ * machdep_restore_state()
+ */
+void machdep_restore_state(void)
+{
+ longjmp(pthread_run->machdep_data.machdep_state, 1);
+}
+
+/* ==========================================================================
+ * machdep_save_float_state()
+ */
+void machdep_save_float_state(struct pthread * pthread)
+{
+ return;
+}
+
+/* ==========================================================================
+ * machdep_restore_float_state()
+ */
+void machdep_restore_float_state()
+{
+ return;
+}
+
+/* ==========================================================================
+ * machdep_set_thread_timer()
+ */
+void machdep_set_thread_timer(struct machdep_pthread *machdep_pthread)
+{
+ if (setitimer(ITIMER_VIRTUAL, &(machdep_pthread->machdep_timer), NULL)) {
+ PANIC();
+ }
+}
+
+/* ==========================================================================
+ * machdep_unset_thread_timer()
+ */
+void machdep_unset_thread_timer(struct machdep_pthread *machdep_pthread)
+{
+ struct itimerval zeroval = { { 0, 0 }, { 0, 0} };
+
+ if (setitimer(ITIMER_VIRTUAL, &zeroval, NULL)) {
+ PANIC();
+ }
+}
+
+/* ==========================================================================
+ * machdep_pthread_cleanup()
+ */
+void *machdep_pthread_cleanup(struct machdep_pthread *machdep_pthread)
+{
+ return(machdep_pthread->machdep_stack);
+}
+
+/* ==========================================================================
+ * machdep_pthread_start()
+ */
+void machdep_pthread_start(jmp_buf j)
+{
+ setjmp(j);
+ if( setupStack )
+ return;
+
+ context_switch_done();
+ pthread_sched_resume();
+
+ /* Run current threads start routine with argument */
+ pthread_exit(pthread_run->machdep_data.start_routine
+ (pthread_run->machdep_data.start_argument));
+
+ /* should never reach here */
+ PANIC();
+}
+
+/* ==========================================================================
+ * __machdep_stack_free()
+ */
+void __machdep_stack_free(void * stack)
+{
+ free(stack);
+}
+
+/* ==========================================================================
+ * __machdep_stack_alloc()
+ */
+void * __machdep_stack_alloc(size_t size)
+{
+ void * stack;
+
+ return(malloc(size));
+}
+
+/* ==========================================================================
+ * __machdep_pthread_create()
+ */
+void __machdep_pthread_create(struct machdep_pthread *machdep_pthread,
+ void *(* start_routine)(), void *start_argument,
+ long stack_size, long nsec, long flags)
+{
+ jmp_buf tmp_jmp_buf;
+
+ machdep_pthread->start_routine = start_routine;
+ machdep_pthread->start_argument = start_argument;
+
+ machdep_pthread->machdep_timer.it_value.tv_sec = 0;
+ machdep_pthread->machdep_timer.it_interval.tv_sec = 0;
+ machdep_pthread->machdep_timer.it_interval.tv_usec = 0;
+ machdep_pthread->machdep_timer.it_value.tv_usec = nsec / 1000;
+
+ /*
+ * Set up new stack frame so that it looks like it
+ * returned from a longjmp() to the beginning of
+ * machdep_pthread_start().
+ */
+ setjmp(machdep_pthread->machdep_state);
+
+ /* get the stack frame from the real machdep_pthread_start */
+ setupStack = 1;
+/* machdep_pthread_start(machdep_pthread->machdep_state); */
+ machdep_pthread_start(tmp_jmp_buf);
+ setupStack = 0;
+
+ /* copy over the interesting part of the frame */
+ ((int *)machdep_pthread->machdep_state)[44] = ((int *)tmp_jmp_buf)[44];
+
+ /* Stack starts low and builds up, but needs two start frames */
+ ((int *)machdep_pthread->machdep_state)[1] =
+ (int)machdep_pthread->machdep_stack + (64 * 2);
+}
+
+int machdep_sys_getdtablesize()
+{
+ return sysconf(_SC_OPEN_MAX);
+}
+
+void sig_check_and_resume()
+{
+ return;
+}
+
+void ___exit(int status)
+{
+ exit(status);
+ PANIC();
+}
diff --git a/mit-pthreads/machdep/engine-hppa-hpux-10.20.h b/mit-pthreads/machdep/engine-hppa-hpux-10.20.h
new file mode 100644
index 00000000000..9cbe3349a3d
--- /dev/null
+++ b/mit-pthreads/machdep/engine-hppa-hpux-10.20.h
@@ -0,0 +1,143 @@
+/* ==== machdep.h ============================================================
+ * Copyright (c) 1993 Chris Provenzano, proven@athena.mit.edu
+ *
+ */
+
+#include <unistd.h>
+#include <setjmp.h>
+#include <sys/time.h>
+
+/*
+ * Stuff for compiling
+ */
+#if defined(__GNUC__)
+#if defined(__cplusplus)
+#define __BEGIN_DECLS extern "C" {
+#define __END_DECLS };
+#else
+#define __BEGIN_DECLS
+#define __END_DECLS
+#if !defined(__STDC__)
+#define const __const
+#define inline __inline
+#define signed __signed
+#define volatile __volatile
+#endif
+#endif
+#else /* !__GNUC__ */
+#define __BEGIN_DECLS
+#define __END_DECLS
+#if !defined(__STDC__)
+#define const
+#endif
+#define inline
+#define signed
+#define volatile
+#endif
+
+/*
+ * The first machine dependent functions are the SEMAPHORES
+ * needing the test and set instruction.
+ *
+ * Note: The set and clear defines are backwards.
+ */
+#define SEMAPHORE_CLEAR { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }
+#define SEMAPHORE_SET 0
+
+#define SEMAPHORE_TEST_AND_SET(lock) \
+({ \
+long real_addr; \
+long temp; \
+ \
+real_addr = ((long)((*lock) + 15) & ~15); \
+ \
+__asm__ volatile("ldcwx %%r0(%2),%0" \
+ :"=r" (temp) \
+ :"0" (temp),"r" (real_addr)); \
+temp ? 0 : 1; \
+})
+
+#define SEMAPHORE_RESET(lock) \
+({ \
+char *real_addr; \
+ \
+real_addr = (char*)((long)((*lock) + 15) & ~15); \
+*real_addr = 0xff; \
+})
+
+/*
+ * New types
+ * The semaphore is really 16 bytes but must be aligened on a 16 byte
+ * boundary. By specifing 31 bytes the macros can frob it correctly.
+ */
+typedef char semaphore[31];
+
+/*
+ * Macros for sigset_t
+ */
+#define SIGMAX 30
+/* see hpux-9.03/__signal.h for SIG_ANY */
+
+/*
+ * New Strutures
+ */
+struct machdep_pthread {
+ void *(*start_routine)(void *);
+ void *start_argument;
+ void *machdep_stack;
+ struct itimerval machdep_timer;
+ jmp_buf machdep_state;
+ /* long machdep_state[_JBLEN]; */
+};
+
+/*
+ * Static machdep_pthread initialization values.
+ * For initial thread only.
+ */
+#define MACHDEP_PTHREAD_INIT \
+{ NULL, NULL, NULL, { { 0, 0 }, { 0, 100000 } }, 0 }
+
+/*
+ * Minimum stack size
+ */
+#define PTHREAD_STACK_MIN 4096
+
+/*
+ * Some fd flag defines that are necessary to distinguish between posix
+ * behavior and bsd4.3 behavior.
+ */
+#define __FD_NONBLOCK O_NONBLOCK
+
+/*
+ * page size
+ */
+#define getpagesize() 4096
+
+/*
+ * New functions
+ */
+
+__BEGIN_DECLS
+
+#if defined(PTHREAD_KERNEL)
+
+#define __machdep_stack_get(x) (x)->machdep_stack
+#define __machdep_stack_set(x, y) (x)->machdep_stack = y
+#define __machdep_stack_repl(x, y) \
+{ \
+ if (stack = __machdep_stack_get(x)) { \
+ __machdep_stack_free(stack); \
+ } \
+ __machdep_stack_set(x, y); \
+}
+
+void * __machdep_stack_alloc __P_((size_t));
+void __machdep_stack_free __P_((void *));
+
+int machdep_save_state __P_((void));
+
+#endif
+
+__END_DECLS
diff --git a/mit-pthreads/machdep/engine-hppa-hpux-9.03.c b/mit-pthreads/machdep/engine-hppa-hpux-9.03.c
new file mode 100644
index 00000000000..3770a2e106a
--- /dev/null
+++ b/mit-pthreads/machdep/engine-hppa-hpux-9.03.c
@@ -0,0 +1,153 @@
+/* ==== machdep.c ============================================================
+ * Copyright (c) 1993 Chris Provenzano, proven@athena.mit.edu
+ *
+ * Description : Machine dependent functions for HP-UX 9.03 on hppa
+ *
+ * 1.00 93/12/14 proven
+ * -Started coding this file.
+ */
+
+#include <pthread.h>
+#include <setjmp.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+/* ==========================================================================
+ * machdep_save_state()
+ */
+int machdep_save_state(void)
+{
+ return(setjmp(pthread_run->machdep_data.machdep_state));
+}
+
+/* ==========================================================================
+ * machdep_restore_state()
+ */
+void machdep_restore_state(void)
+{
+ longjmp(pthread_run->machdep_data.machdep_state, 1);
+}
+
+/* ==========================================================================
+ * machdep_save_float_state()
+ */
+void machdep_save_float_state(struct pthread * pthread)
+{
+ return;
+}
+
+/* ==========================================================================
+ * machdep_restore_float_state()
+ */
+void machdep_restore_float_state()
+{
+ return;
+}
+
+/* ==========================================================================
+ * machdep_set_thread_timer()
+ */
+void machdep_set_thread_timer(struct machdep_pthread *machdep_pthread)
+{
+ if (setitimer(ITIMER_VIRTUAL, &(machdep_pthread->machdep_timer), NULL)) {
+ PANIC();
+ }
+}
+
+/* ==========================================================================
+ * machdep_unset_thread_timer()
+ */
+void machdep_unset_thread_timer(struct machdep_pthread *machdep_pthread)
+{
+ struct itimerval zeroval = { { 0, 0 }, { 0, 0} };
+
+ if (setitimer(ITIMER_VIRTUAL, &zeroval, NULL)) {
+ PANIC();
+ }
+}
+
+/* ==========================================================================
+ * machdep_pthread_cleanup()
+ */
+void *machdep_pthread_cleanup(struct machdep_pthread *machdep_pthread)
+{
+ return(machdep_pthread->machdep_stack);
+}
+
+/* ==========================================================================
+ * machdep_pthread_start()
+ */
+void machdep_pthread_start(void)
+{
+ context_switch_done();
+ pthread_sched_resume();
+
+ /* Run current threads start routine with argument */
+ pthread_exit(pthread_run->machdep_data.start_routine
+ (pthread_run->machdep_data.start_argument));
+
+ /* should never reach here */
+ PANIC();
+}
+
+/* ==========================================================================
+ * __machdep_stack_free()
+ */
+void __machdep_stack_free(void * stack)
+{
+ free(stack);
+}
+
+/* ==========================================================================
+ * __machdep_stack_alloc()
+ */
+void * __machdep_stack_alloc(size_t size)
+{
+ void * stack;
+
+ return(malloc(size));
+}
+
+/* ==========================================================================
+ * __machdep_pthread_create()
+ */
+void __machdep_pthread_create(struct machdep_pthread *machdep_pthread,
+ void *(* start_routine)(), void *start_argument,
+ long stack_size, long nsec, long flags)
+{
+ machdep_pthread->start_routine = start_routine;
+ machdep_pthread->start_argument = start_argument;
+
+ machdep_pthread->machdep_timer.it_value.tv_sec = 0;
+ machdep_pthread->machdep_timer.it_interval.tv_sec = 0;
+ machdep_pthread->machdep_timer.it_interval.tv_usec = 0;
+ machdep_pthread->machdep_timer.it_value.tv_usec = nsec / 1000;
+
+ setjmp(machdep_pthread->machdep_state);
+ /*
+ * Set up new stact frame so that it looks like it
+ * returned from a longjmp() to the beginning of
+ * machdep_pthread_start().
+ */
+ ((int *)machdep_pthread->machdep_state)[0] = (int)machdep_pthread_start;
+
+ /* Stack starts low and builds up, but needs two start frames */
+ ((int *)machdep_pthread->machdep_state)[1] =
+ (int)machdep_pthread->machdep_stack + (64 * 2);
+}
+
+int machdep_sys_getdtablesize()
+{
+ return sysconf(_SC_OPEN_MAX);
+}
+
+void sig_check_and_resume()
+{
+ return;
+}
+
+void ___exit(int status)
+{
+ exit(status);
+ PANIC();
+}
diff --git a/mit-pthreads/machdep/engine-hppa-hpux-9.03.h b/mit-pthreads/machdep/engine-hppa-hpux-9.03.h
new file mode 100644
index 00000000000..7c599400e3e
--- /dev/null
+++ b/mit-pthreads/machdep/engine-hppa-hpux-9.03.h
@@ -0,0 +1,141 @@
+/* ==== machdep.h ============================================================
+ * Copyright (c) 1993 Chris Provenzano, proven@athena.mit.edu
+ *
+ */
+
+#include <unistd.h>
+#include <setjmp.h>
+#include <sys/time.h>
+
+/*
+ * Stuff for compiling
+ */
+#if defined(__GNUC__)
+#if defined(__cplusplus)
+#define __BEGIN_DECLS extern "C" {
+#define __END_DECLS };
+#else
+#define __BEGIN_DECLS
+#define __END_DECLS
+#if !defined(__STDC__)
+#define const __const
+#define inline __inline
+#define signed __signed
+#define volatile __volatile
+#endif
+#endif
+#else /* !__GNUC__ */
+#define __BEGIN_DECLS
+#define __END_DECLS
+#define const
+#define inline
+#define signed
+#define volatile
+#endif
+
+/*
+ * The first machine dependent functions are the SEMAPHORES
+ * needing the test and set instruction.
+ *
+ * Note: The set and clear defines are backwards.
+ */
+#define SEMAPHORE_CLEAR { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }
+#define SEMAPHORE_SET 0
+
+#define SEMAPHORE_TEST_AND_SET(lock) \
+({ \
+long real_addr; \
+long temp; \
+ \
+real_addr = ((long)((*lock) + 15) & ~15); \
+ \
+__asm__ volatile("ldcwx %%r0(%2),%0" \
+ :"=r" (temp) \
+ :"0" (temp),"r" (real_addr)); \
+temp ? 0 : 1; \
+})
+
+#define SEMAPHORE_RESET(lock) \
+({ \
+char *real_addr; \
+ \
+real_addr = (char*)((long)((*lock) + 15) & ~15); \
+*real_addr = 0xff; \
+})
+
+/*
+ * New types
+ * The semaphore is really 16 bytes but must be aligened on a 16 byte
+ * boundary. By specifing 31 bytes the macros can frob it correctly.
+ */
+typedef char semaphore[31];
+
+/*
+ * Macros for sigset_t
+ */
+#define SIGMAX 30
+/* see hpux-9.03/__signal.h for SIG_ANY */
+
+/*
+ * New Strutures
+ */
+struct machdep_pthread {
+ void *(*start_routine)(void *);
+ void *start_argument;
+ void *machdep_stack;
+ struct itimerval machdep_timer;
+ jmp_buf machdep_state;
+ /* long machdep_state[_JBLEN]; */
+};
+
+/*
+ * Static machdep_pthread initialization values.
+ * For initial thread only.
+ */
+#define MACHDEP_PTHREAD_INIT \
+{ NULL, NULL, NULL, { { 0, 0 }, { 0, 100000 } }, 0 }
+
+/*
+ * Minimum stack size
+ */
+#define PTHREAD_STACK_MIN 4096
+
+/*
+ * Some fd flag defines that are necessary to distinguish between posix
+ * behavior and bsd4.3 behavior.
+ */
+#define __FD_NONBLOCK O_NONBLOCK
+
+/*
+ * page size
+ */
+#define getpagesize() 4096
+
+/*
+ * New functions
+ */
+
+__BEGIN_DECLS
+
+#if defined(PTHREAD_KERNEL)
+
+#define __machdep_stack_get(x) (x)->machdep_stack
+#define __machdep_stack_set(x, y) (x)->machdep_stack = y
+#define __machdep_stack_repl(x, y) \
+{ \
+ if (stack = __machdep_stack_get(x)) { \
+ __machdep_stack_free(stack); \
+ } \
+ __machdep_stack_set(x, y); \
+}
+
+void * __machdep_stack_alloc __P_((size_t));
+void __machdep_stack_free __P_((void *));
+
+int machdep_save_state __P_((void));
+
+#endif
+
+__END_DECLS
diff --git a/mit-pthreads/machdep/engine-i386-bsdi-1.1.c b/mit-pthreads/machdep/engine-i386-bsdi-1.1.c
new file mode 100644
index 00000000000..da78bef393e
--- /dev/null
+++ b/mit-pthreads/machdep/engine-i386-bsdi-1.1.c
@@ -0,0 +1,180 @@
+/* ==== machdep.c ============================================================
+ * Copyright (c) 1993, 1994 Chris Provenzano, proven@athena.mit.edu
+ *
+ * Copyright (c) 1993 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Description : Machine dependent functions for NetBSD on i386
+ *
+ * 1.00 93/08/04 proven
+ * -Started coding this file.
+ */
+
+#ifndef lint
+static const char rcsid[] = "$Id$";
+#endif
+
+#include <pthread.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <fcntl.h>
+#include <stdio.h>
+
+/* ==========================================================================
+ * machdep_save_state()
+ */
+int machdep_save_state(void)
+{
+ return(_setjmp(pthread_run->machdep_data.machdep_state));
+}
+
+/* ==========================================================================
+ * machdep_restore_state()
+ */
+void machdep_restore_state(void)
+{
+ _longjmp(pthread_run->machdep_data.machdep_state, 1);
+}
+
+/* ==========================================================================
+ * machdep_set_thread_timer()
+ */
+void machdep_set_thread_timer(struct machdep_pthread *machdep_pthread)
+{
+ if (setitimer(ITIMER_VIRTUAL, &(machdep_pthread->machdep_timer), NULL)) {
+ PANIC();
+ }
+}
+
+/* ==========================================================================
+ * machdep_unset_thread_timer()
+ */
+void machdep_unset_thread_timer(struct machdep_pthread *machdep_pthread)
+{
+ struct itimerval zeroval = { { 0, 0 }, { 0, 0} };
+
+ if (setitimer(ITIMER_VIRTUAL, &zeroval, NULL)) {
+ PANIC();
+ }
+}
+
+/* ==========================================================================
+ * machdep_pthread_cleanup()
+ */
+void *machdep_pthread_cleanup(struct machdep_pthread *machdep_pthread)
+{
+ return(machdep_pthread->machdep_stack);
+}
+
+/* ==========================================================================
+ * machdep_pthread_start()
+ */
+void machdep_pthread_start(void)
+{
+ context_switch_done();
+ sig_check_and_resume();
+
+ /* Run current threads start routine with argument */
+ pthread_exit(pthread_run->machdep_data.start_routine
+ (pthread_run->machdep_data.start_argument));
+
+ /* should never reach here */
+ PANIC();
+}
+
+/* ==========================================================================
+ * machdep_pthread_create()
+ */
+void machdep_pthread_create(struct machdep_pthread *machdep_pthread,
+ void *(* start_routine)(), void *start_argument, long stack_size,
+ void *stack_start, long nsec)
+{
+ machdep_pthread->machdep_stack = stack_start;
+
+ machdep_pthread->start_routine = start_routine;
+ machdep_pthread->start_argument = start_argument;
+
+ machdep_pthread->machdep_timer.it_value.tv_sec = 0;
+ machdep_pthread->machdep_timer.it_interval.tv_sec = 0;
+ machdep_pthread->machdep_timer.it_interval.tv_usec = 0;
+ machdep_pthread->machdep_timer.it_value.tv_usec = nsec / 1000;
+
+ _setjmp(machdep_pthread->machdep_state);
+ /*
+ * Set up new stact frame so that it looks like it
+ * returned from a longjmp() to the beginning of
+ * machdep_pthread_start().
+ */
+ machdep_pthread->machdep_state[0] = (int)machdep_pthread_start;
+
+ /* Stack starts high and builds down. */
+ machdep_pthread->machdep_state[2] =
+ (int)machdep_pthread->machdep_stack + stack_size;
+}
+
+/* ==========================================================================
+ * machdep_sys_creat()
+ */
+machdep_sys_creat(char * path, int mode)
+{
+ return(machdep_sys_open(path, O_WRONLY | O_CREAT | O_TRUNC, mode));
+}
+
+/* ==========================================================================
+ * machdep_sys_wait3()
+ */
+machdep_sys_wait3(int * b, int c, int * d)
+{
+ return(machdep_sys_wait4(0, b, c, d));
+}
+
+/* ==========================================================================
+ * machdep_sys_waitpid()
+ */
+machdep_sys_waitpid(int a, int * b, int c)
+{
+ return(machdep_sys_wait4(a, b, c, NULL));
+}
+
+/* ==========================================================================
+ * machdep_sys_send()
+ */
+machdep_sys_send(int s, const void *buf, int len, int flags)
+{
+ return(machdep_sys_sendto(s, buf, len, flags, (struct sockaddr*)NULL, 0));
+}
+
+/* ==========================================================================
+ * machdep_sys_recv()
+ */
+machdep_sys_recv(int s, void *buf, int len, int flags)
+{
+ return(machdep_sys_recvfrom(s, buf, len, flags, (struct sockaddr*)NULL, 0));
+}
diff --git a/mit-pthreads/machdep/engine-i386-bsdi-1.1.h b/mit-pthreads/machdep/engine-i386-bsdi-1.1.h
new file mode 100644
index 00000000000..7f7b8a62d06
--- /dev/null
+++ b/mit-pthreads/machdep/engine-i386-bsdi-1.1.h
@@ -0,0 +1,84 @@
+/* ==== machdep.h ============================================================
+ * Copyright (c) 1993 Chris Provenzano, proven@athena.mit.edu
+ *
+ * $Id$
+ *
+ */
+
+#include <unistd.h>
+#include <setjmp.h>
+#include <sys/time.h>
+
+/*
+ * The first machine dependent functions are the SEMAPHORES
+ * needing the test and set instruction.
+ */
+#define SEMAPHORE_CLEAR 0
+#define SEMAPHORE_SET 1
+
+#define SEMAPHORE_TEST_AND_SET(lock) \
+({ \
+long temp = SEMAPHORE_SET; \
+ \
+__asm__ volatile ("xchgl %0,(%2)" \
+ :"=r" (temp) \
+ :"0" (temp),"r" (lock)); \
+temp; \
+})
+
+#define SEMAPHORE_RESET(lock) *lock = SEMAPHORE_CLEAR
+
+/*
+ * New types
+ */
+typedef long semaphore;
+
+/*
+ * sigset_t macros
+ */
+#define SIG_ANY(sig) (sig)
+#define SIGMAX 31
+
+/*
+ * New Strutures
+ */
+struct machdep_pthread {
+ void *(*start_routine)(void *);
+ void *start_argument;
+ void *machdep_stack;
+ struct itimerval machdep_timer;
+ jmp_buf machdep_state;
+};
+
+/*
+ * Static machdep_pthread initialization values.
+ * For initial thread only.
+ */
+#define MACHDEP_PTHREAD_INIT \
+{ NULL, NULL, NULL, { { 0, 0 }, { 0, 100000 } }, 0 }
+
+/*
+ * Minimum stack size
+ */
+#define PTHREAD_STACK_MIN 1024
+
+/*
+ * Some fd flag defines that are necessary to distinguish between posix
+ * behavior and bsd4.3 behavior.
+ */
+#define __FD_NONBLOCK O_NONBLOCK
+
+/*
+ * New functions
+ */
+
+__BEGIN_DECLS
+
+#if defined(PTHREAD_KERNEL)
+
+int machdep_save_state __P_((void));
+
+#endif
+
+__END_DECLS
+
diff --git a/mit-pthreads/machdep/engine-i386-bsdi-2.0.c b/mit-pthreads/machdep/engine-i386-bsdi-2.0.c
new file mode 100644
index 00000000000..63a6de1b092
--- /dev/null
+++ b/mit-pthreads/machdep/engine-i386-bsdi-2.0.c
@@ -0,0 +1,210 @@
+/* ==== machdep.c ============================================================
+ * Copyright (c) 1993, 1994 Chris Provenzano, proven@athena.mit.edu
+ *
+ * Copyright (c) 1993 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Description : Machine dependent functions for NetBSD on i386
+ *
+ * 1.00 93/08/04 proven
+ * -Started coding this file.
+ */
+
+#ifndef lint
+static const char rcsid[] = "$Id$";
+#endif
+
+#include <pthread.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <stdio.h>
+
+/* ==========================================================================
+ * machdep_save_state()
+ */
+int machdep_save_state(void)
+{
+ return(_setjmp(pthread_run->machdep_data.machdep_state));
+}
+
+/* ==========================================================================
+ * machdep_save_state()
+ */
+int machdep_save_float_state(struct pthread * pthread)
+{
+ char * fdata = (char *)pthread->machdep_data.machdep_float_state;
+
+ __asm__ ("fsave %0"::"m" (*fdata));
+}
+
+/* ==========================================================================
+ * machdep_restore_state()
+ */
+void machdep_restore_state(void)
+{
+ _longjmp(pthread_run->machdep_data.machdep_state, 1);
+}
+
+/* ==========================================================================
+ * machdep_restore_float_state()
+ */
+int machdep_restore_float_state(void)
+{
+ char * fdata = (char *)pthread_run->machdep_data.machdep_float_state;
+
+ __asm__ ("frstor %0"::"m" (*fdata));
+}
+
+/* ==========================================================================
+ * machdep_set_thread_timer()
+ */
+void machdep_set_thread_timer(struct machdep_pthread *machdep_pthread)
+{
+ if (setitimer(ITIMER_VIRTUAL, &(machdep_pthread->machdep_timer), NULL)) {
+ PANIC();
+ }
+}
+
+/* ==========================================================================
+ * machdep_unset_thread_timer()
+ */
+void machdep_unset_thread_timer(struct machdep_pthread *machdep_pthread)
+{
+ struct itimerval zeroval = { { 0, 0 }, { 0, 0 } };
+ int ret;
+
+ if (machdep_pthread) {
+ ret = setitimer(ITIMER_VIRTUAL, &zeroval,
+ &(machdep_pthread->machdep_timer));
+ } else {
+ ret = setitimer(ITIMER_VIRTUAL, &zeroval, NULL);
+ }
+
+ if (ret) {
+ PANIC();
+ }
+}
+
+/* ==========================================================================
+ * machdep_pthread_cleanup()
+ */
+void *machdep_pthread_cleanup(struct machdep_pthread *machdep_pthread)
+{
+ return(machdep_pthread->machdep_stack);
+}
+
+/* ==========================================================================
+ * machdep_pthread_start()
+ */
+void machdep_pthread_start(void)
+{
+ context_switch_done();
+ pthread_sched_resume();
+
+ /* Run current threads start routine with argument */
+ pthread_exit(pthread_run->machdep_data.start_routine
+ (pthread_run->machdep_data.start_argument));
+
+ /* should never reach here */
+ PANIC();
+}
+
+/* ==========================================================================
+ * __machdep_stack_free()
+ */
+void __machdep_stack_free(void * stack)
+{
+ free(stack);
+}
+
+/* ==========================================================================
+ * __machdep_stack_alloc()
+ */
+void * __machdep_stack_alloc(size_t size)
+{
+ void * stack;
+
+ return(malloc(size));
+}
+
+/* ==========================================================================
+ * __machdep_pthread_create()
+ */
+void __machdep_pthread_create(struct machdep_pthread *machdep_pthread,
+ void *(* start_routine)(), void *start_argument,
+ long stack_size, long nsec, long flags)
+{
+ machdep_pthread->start_routine = start_routine;
+ machdep_pthread->start_argument = start_argument;
+
+ machdep_pthread->machdep_timer.it_value.tv_sec = 0;
+ machdep_pthread->machdep_timer.it_interval.tv_sec = 0;
+ machdep_pthread->machdep_timer.it_interval.tv_usec = 0;
+ machdep_pthread->machdep_timer.it_value.tv_usec = nsec / 1000;
+
+ _setjmp(machdep_pthread->machdep_state);
+ /*
+ * Set up new stact frame so that it looks like it
+ * returned from a longjmp() to the beginning of
+ * machdep_pthread_start().
+ */
+ machdep_pthread->machdep_state[0] = (int)machdep_pthread_start;
+
+ /* Stack starts high and builds down. */
+ machdep_pthread->machdep_state[2] =
+ (int)machdep_pthread->machdep_stack + stack_size;
+}
+
+/* ==========================================================================
+ * machdep_sys_creat()
+ */
+machdep_sys_creat(char * path, int mode)
+{
+ return(machdep_sys_open(path, O_WRONLY | O_CREAT | O_TRUNC, mode));
+}
+
+/* ==========================================================================
+ * machdep_sys_wait3()
+ */
+machdep_sys_wait3(int * b, int c, int * d)
+{
+ return(machdep_sys_wait4(0, b, c, d));
+}
+
+/* ==========================================================================
+ * machdep_sys_waitpid()
+ */
+machdep_sys_waitpid(int a, int * b, int c)
+{
+ return(machdep_sys_wait4(a, b, c, NULL));
+}
+
diff --git a/mit-pthreads/machdep/engine-i386-bsdi-2.0.h b/mit-pthreads/machdep/engine-i386-bsdi-2.0.h
new file mode 100644
index 00000000000..3be254b4090
--- /dev/null
+++ b/mit-pthreads/machdep/engine-i386-bsdi-2.0.h
@@ -0,0 +1,98 @@
+/* ==== machdep.h ============================================================
+ * Copyright (c) 1993 Chris Provenzano, proven@athena.mit.edu
+ *
+ * engine-i386-netbsd-1.0.h,v 1.53 1994/12/13 07:17:23 proven Exp
+ *
+ */
+
+#include <unistd.h>
+#include <setjmp.h>
+#include <sys/time.h>
+
+/*
+ * The first machine dependent functions are the SEMAPHORES
+ * needing the test and set instruction.
+ */
+#define SEMAPHORE_CLEAR 0
+#define SEMAPHORE_SET 1
+
+#define SEMAPHORE_TEST_AND_SET(lock) \
+({ \
+long temp = SEMAPHORE_SET; \
+ \
+__asm__ volatile ("xchgl %0,(%2)" \
+ :"=r" (temp) \
+ :"0" (temp),"r" (lock)); \
+temp; \
+})
+
+#define SEMAPHORE_RESET(lock) *lock = SEMAPHORE_CLEAR
+
+/*
+ * New types
+ */
+typedef long semaphore;
+
+/*
+ * sigset_t macros
+ */
+#define SIG_ANY(sig) (sig)
+#define SIGMAX 31
+
+/*
+ * New Strutures
+ */
+struct machdep_pthread {
+ void *(*start_routine)(void *);
+ void *start_argument;
+ void *machdep_stack;
+ struct itimerval machdep_timer;
+ jmp_buf machdep_state;
+ char machdep_float_state[108];
+};
+
+/*
+ * Static machdep_pthread initialization values.
+ * For initial thread only.
+ */
+#define MACHDEP_PTHREAD_INIT \
+{ NULL, NULL, NULL, { { 0, 0 }, { 0, 100000 } }, 0 }
+
+/*
+ * Minimum stack size
+ */
+#define PTHREAD_STACK_MIN 1024
+
+/*
+ * Some fd flag defines that are necessary to distinguish between posix
+ * behavior and bsd4.3 behavior.
+ */
+#define __FD_NONBLOCK (O_NONBLOCK|O_NDELAY)
+
+/*
+ * New functions
+ */
+
+__BEGIN_DECLS
+
+#if defined(PTHREAD_KERNEL)
+
+#define __machdep_stack_get(x) (x)->machdep_stack
+#define __machdep_stack_set(x, y) (x)->machdep_stack = y
+#define __machdep_stack_repl(x, y) \
+{ \
+ if (stack = __machdep_stack_get(x)) { \
+ __machdep_stack_free(stack); \
+ } \
+ __machdep_stack_set(x, y); \
+}
+
+void * __machdep_stack_alloc __P_((size_t));
+void __machdep_stack_free __P_((void *));
+
+int machdep_save_state __P_((void));
+
+#endif
+
+__END_DECLS
+
diff --git a/mit-pthreads/machdep/engine-i386-freebsd-1.1.c b/mit-pthreads/machdep/engine-i386-freebsd-1.1.c
new file mode 100644
index 00000000000..422193e77e3
--- /dev/null
+++ b/mit-pthreads/machdep/engine-i386-freebsd-1.1.c
@@ -0,0 +1,179 @@
+/* ==== machdep.c ============================================================
+ * Copyright (c) 1993, 1994 Chris Provenzano, proven@athena.mit.edu
+ *
+ * Copyright (c) 1993 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Description : Machine dependent functions for NetBSD on i386
+ *
+ * 1.00 93/08/04 proven
+ * -Started coding this file.
+ */
+
+#ifndef lint
+static const char rcsid[] = "$Id$";
+#endif
+
+#include <pthread.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <stdio.h>
+
+/* ==========================================================================
+ * machdep_save_state()
+ */
+int machdep_save_state(void)
+{
+ return(_setjmp(pthread_run->machdep_data.machdep_state));
+}
+
+/* ==========================================================================
+ * machdep_restore_state()
+ */
+void machdep_restore_state(void)
+{
+ _longjmp(pthread_run->machdep_data.machdep_state, 1);
+}
+
+/* ==========================================================================
+ * machdep_set_thread_timer()
+ */
+void machdep_set_thread_timer(struct machdep_pthread *machdep_pthread)
+{
+ if (setitimer(ITIMER_VIRTUAL, &(machdep_pthread->machdep_timer), NULL)) {
+ PANIC();
+ }
+}
+
+/* ==========================================================================
+ * machdep_unset_thread_timer()
+ */
+void machdep_unset_thread_timer(struct machdep_pthread *machdep_pthread)
+{
+ struct itimerval zeroval = { { 0, 0 }, { 0, 0} };
+
+ if (setitimer(ITIMER_VIRTUAL, &zeroval, NULL)) {
+ PANIC();
+ }
+}
+
+/* ==========================================================================
+ * machdep_pthread_cleanup()
+ */
+void *machdep_pthread_cleanup(struct machdep_pthread *machdep_pthread)
+{
+ return(machdep_pthread->machdep_stack);
+}
+
+/* ==========================================================================
+ * machdep_pthread_start()
+ */
+void machdep_pthread_start(void)
+{
+ context_switch_done();
+ sig_check_and_resume();
+
+ /* Run current threads start routine with argument */
+ pthread_exit(pthread_run->machdep_data.start_routine
+ (pthread_run->machdep_data.start_argument));
+
+ /* should never reach here */
+ PANIC();
+}
+
+/* ==========================================================================
+ * machdep_pthread_create()
+ */
+void machdep_pthread_create(struct machdep_pthread *machdep_pthread,
+ void *(* start_routine)(), void *start_argument, long stack_size,
+ void *stack_start, long nsec)
+{
+ machdep_pthread->machdep_stack = stack_start;
+
+ machdep_pthread->start_routine = start_routine;
+ machdep_pthread->start_argument = start_argument;
+
+ machdep_pthread->machdep_timer.it_value.tv_sec = 0;
+ machdep_pthread->machdep_timer.it_interval.tv_sec = 0;
+ machdep_pthread->machdep_timer.it_interval.tv_usec = 0;
+ machdep_pthread->machdep_timer.it_value.tv_usec = nsec / 1000;
+
+ _setjmp(machdep_pthread->machdep_state);
+ /*
+ * Set up new stact frame so that it looks like it
+ * returned from a longjmp() to the beginning of
+ * machdep_pthread_start().
+ */
+ machdep_pthread->machdep_state[0] = (int)machdep_pthread_start;
+
+ /* Stack starts high and builds down. */
+ machdep_pthread->machdep_state[2] =
+ (int)machdep_pthread->machdep_stack + stack_size;
+}
+
+/* ==========================================================================
+ * machdep_sys_creat()
+ */
+machdep_sys_creat(char * path, int mode)
+{
+ return(machdep_sys_open(path, O_WRONLY | O_CREAT | O_TRUNC, mode));
+}
+
+/* ==========================================================================
+ * machdep_sys_wait3()
+ */
+machdep_sys_wait3(int * b, int c, int * d)
+{
+ return(machdep_sys_wait4(0, b, c, d));
+}
+
+/* ==========================================================================
+ * machdep_sys_waitpid()
+ */
+machdep_sys_waitpid(int a, int * b, int c)
+{
+ return(machdep_sys_wait4(a, b, c, NULL));
+}
+
+/* ==========================================================================
+ * machdep_sys_send()
+ */
+machdep_sys_send(int s, const void *buf, int len, int flags)
+{
+ return(machdep_sys_sendto(s, buf, len, flags, NULL, 0));
+}
+
+/* ==========================================================================
+ * machdep_sys_recv()
+ */
+machdep_sys_recv(int s, void *buf, int len, int flags)
+{
+ return(machdep_sys_recvfrom(s, buf, len, flags, NULL, 0));
+}
diff --git a/mit-pthreads/machdep/engine-i386-freebsd-1.1.h b/mit-pthreads/machdep/engine-i386-freebsd-1.1.h
new file mode 100644
index 00000000000..0e8e93bdbfb
--- /dev/null
+++ b/mit-pthreads/machdep/engine-i386-freebsd-1.1.h
@@ -0,0 +1,83 @@
+/* ==== machdep.h ============================================================
+ * Copyright (c) 1993 Chris Provenzano, proven@athena.mit.edu
+ *
+ * $Id$
+ *
+ */
+
+#include <unistd.h>
+#include <setjmp.h>
+#include <sys/time.h>
+
+/*
+ * The first machine dependent functions are the SEMAPHORES
+ * needing the test and set instruction.
+ */
+#define SEMAPHORE_CLEAR 0
+#define SEMAPHORE_SET 1
+
+#define SEMAPHORE_TEST_AND_SET(lock) \
+({ \
+long temp = SEMAPHORE_SET; \
+ \
+__asm__ volatile ("xchgl %0,(%2)" \
+ :"=r" (temp) \
+ :"0" (temp),"r" (lock)); \
+temp; \
+})
+
+#define SEMAPHORE_RESET(lock) *lock = SEMAPHORE_CLEAR
+
+/*
+ * New types
+ */
+typedef long semaphore;
+
+/*
+ * sigset_t macros
+ */
+#define SIG_ANY(sig) (sig)
+#define SIGMAX 31
+
+/*
+ * New Strutures
+ */
+struct machdep_pthread {
+ void *(*start_routine)(void *);
+ void *start_argument;
+ void *machdep_stack;
+ struct itimerval machdep_timer;
+ jmp_buf machdep_state;
+};
+
+/*
+ * Static machdep_pthread initialization values.
+ * For initial thread only.
+ */
+#define MACHDEP_PTHREAD_INIT \
+{ NULL, NULL, NULL, { { 0, 0 }, { 0, 100000 } }, 0 }
+
+/*
+ * Minimum stack size
+ */
+#define PTHREAD_STACK_MIN 1024
+
+/*
+ * Some fd flag defines that are necessary to distinguish between posix
+ * behavior and bsd4.3 behavior.
+ */
+#define __FD_NONBLOCK O_NONBLOCK
+
+/*
+ * New functions
+ */
+
+__BEGIN_DECLS
+
+#if defined(PTHREAD_KERNEL)
+
+int machdep_save_state __P_((void));
+
+#endif
+
+__END_DECLS
diff --git a/mit-pthreads/machdep/engine-i386-freebsd-2.0.c b/mit-pthreads/machdep/engine-i386-freebsd-2.0.c
new file mode 100644
index 00000000000..3b6b8f31ae0
--- /dev/null
+++ b/mit-pthreads/machdep/engine-i386-freebsd-2.0.c
@@ -0,0 +1,208 @@
+/* ==== machdep.c ============================================================
+ * Copyright (c) 1995 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Description : Machine dependent functions for NetBSD on i386
+ *
+ * 1.00 93/08/04 proven
+ * -Started coding this file.
+ */
+
+#ifndef lint
+static const char rcsid[] = "engine-i386-freebsd-2.0.c,v 1.1 1995/03/01 01:21:20 proven Exp";
+#endif
+
+#include <pthread.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <stdio.h>
+
+/* ==========================================================================
+ * machdep_save_state()
+ */
+int machdep_save_state(void)
+{
+ return(machdep_sys_setjmp(pthread_run->machdep_data.machdep_state));
+}
+
+/* ==========================================================================
+ * machdep_save_state()
+ */
+int machdep_save_float_state(struct pthread * pthread)
+{
+ char * fdata = (char *)pthread->machdep_data.machdep_float_state;
+
+ __asm__ ("fsave %0"::"m" (*fdata));
+}
+
+/* ==========================================================================
+ * machdep_restore_state()
+ */
+void machdep_restore_state(void)
+{
+ machdep_sys_longjmp(pthread_run->machdep_data.machdep_state, 1);
+}
+
+/* ==========================================================================
+ * machdep_restore_float_state()
+ */
+int machdep_restore_float_state(void)
+{
+ char * fdata = (char *)pthread_run->machdep_data.machdep_float_state;
+
+ __asm__ ("frstor %0"::"m" (*fdata));
+}
+
+/* ==========================================================================
+ * machdep_set_thread_timer()
+ */
+void machdep_set_thread_timer(struct machdep_pthread *machdep_pthread)
+{
+ if (setitimer(ITIMER_VIRTUAL, &(machdep_pthread->machdep_timer), NULL)) {
+ PANIC();
+ }
+}
+
+/* ==========================================================================
+ * machdep_unset_thread_timer()
+ */
+void machdep_unset_thread_timer(struct machdep_pthread *machdep_pthread)
+{
+ struct itimerval zeroval = { { 0, 0 }, { 0, 0 } };
+ int ret;
+
+ if (machdep_pthread) {
+ ret = setitimer(ITIMER_VIRTUAL, &zeroval,
+ &(machdep_pthread->machdep_timer));
+ } else {
+ ret = setitimer(ITIMER_VIRTUAL, &zeroval, NULL);
+ }
+
+ if (ret) {
+ PANIC();
+ }
+}
+
+/* ==========================================================================
+ * machdep_pthread_cleanup()
+ */
+void *machdep_pthread_cleanup(struct machdep_pthread *machdep_pthread)
+{
+ return(machdep_pthread->machdep_stack);
+}
+
+/* ==========================================================================
+ * machdep_pthread_start()
+ */
+void machdep_pthread_start(void)
+{
+ context_switch_done();
+ pthread_sched_resume();
+
+ /* Run current threads start routine with argument */
+ pthread_exit(pthread_run->machdep_data.start_routine
+ (pthread_run->machdep_data.start_argument));
+
+ /* should never reach here */
+ PANIC();
+}
+
+/* ==========================================================================
+ * __machdep_stack_free()
+ */
+void __machdep_stack_free(void * stack)
+{
+ free(stack);
+}
+
+/* ==========================================================================
+ * __machdep_stack_alloc()
+ */
+void * __machdep_stack_alloc(size_t size)
+{
+ void * stack;
+
+ return(malloc(size));
+}
+
+/* ==========================================================================
+ * __machdep_pthread_create()
+ */
+void __machdep_pthread_create(struct machdep_pthread *machdep_pthread,
+ void *(* start_routine)(), void *start_argument,
+ long stack_size, long nsec, long flags)
+{
+ machdep_pthread->start_routine = start_routine;
+ machdep_pthread->start_argument = start_argument;
+
+ machdep_pthread->machdep_timer.it_value.tv_sec = 0;
+ machdep_pthread->machdep_timer.it_interval.tv_sec = 0;
+ machdep_pthread->machdep_timer.it_interval.tv_usec = 0;
+ machdep_pthread->machdep_timer.it_value.tv_usec = nsec / 1000;
+
+ machdep_sys_setjmp(machdep_pthread->machdep_state);
+ /*
+ * Set up new stact frame so that it looks like it
+ * returned from a longjmp() to the beginning of
+ * machdep_pthread_start().
+ */
+ machdep_pthread->machdep_state->_jb[0] = (int)machdep_pthread_start;
+
+ /* Stack starts high and builds down. */
+ machdep_pthread->machdep_state->_jb[2] =
+ (int)machdep_pthread->machdep_stack + stack_size;
+}
+
+/* ==========================================================================
+ * machdep_sys_creat()
+ */
+machdep_sys_creat(char * path, int mode)
+{
+ return(machdep_sys_open(path, O_WRONLY | O_CREAT | O_TRUNC, mode));
+}
+
+/* ==========================================================================
+ * machdep_sys_wait3()
+ */
+machdep_sys_wait3(int * b, int c, int * d)
+{
+ return(machdep_sys_wait4(0, b, c, d));
+}
+
+/* ==========================================================================
+ * machdep_sys_waitpid()
+ */
+machdep_sys_waitpid(int a, int * b, int c)
+{
+ return(machdep_sys_wait4(a, b, c, NULL));
+}
+
diff --git a/mit-pthreads/machdep/engine-i386-freebsd-2.0.h b/mit-pthreads/machdep/engine-i386-freebsd-2.0.h
new file mode 100644
index 00000000000..87ef21389ce
--- /dev/null
+++ b/mit-pthreads/machdep/engine-i386-freebsd-2.0.h
@@ -0,0 +1,97 @@
+/* ==== machdep.h ============================================================
+ * Copyright (c) 1993 Chris Provenzano, proven@athena.mit.edu
+ *
+ * $Id$
+ *
+ */
+
+#include <unistd.h>
+#include <setjmp.h>
+#include <sys/time.h>
+
+/*
+ * The first machine dependent functions are the SEMAPHORES
+ * needing the test and set instruction.
+ */
+#define SEMAPHORE_CLEAR 0
+#define SEMAPHORE_SET 1
+
+#define SEMAPHORE_TEST_AND_SET(lock) \
+({ \
+long temp = SEMAPHORE_SET; \
+ \
+__asm__ volatile ("xchgl %0,(%2)" \
+ :"=r" (temp) \
+ :"0" (temp),"r" (lock)); \
+temp; \
+})
+
+#define SEMAPHORE_RESET(lock) *lock = SEMAPHORE_CLEAR
+
+/*
+ * New types
+ */
+typedef long semaphore;
+
+/*
+ * sigset_t macros
+ */
+#define SIG_ANY(sig) (sig)
+#define SIGMAX 31
+
+/*
+ * New Strutures
+ */
+struct machdep_pthread {
+ void *(*start_routine)(void *);
+ void *start_argument;
+ void *machdep_stack;
+ struct itimerval machdep_timer;
+ jmp_buf machdep_state;
+ char machdep_float_state[108];
+};
+
+/*
+ * Static machdep_pthread initialization values.
+ * For initial thread only.
+ */
+#define MACHDEP_PTHREAD_INIT \
+{ NULL, NULL, NULL, { { 0, 0 }, { 0, 100000 } }, 0 }
+
+/*
+ * Minimum stack size
+ */
+#define PTHREAD_STACK_MIN 1024
+
+/*
+ * Some fd flag defines that are necessary to distinguish between posix
+ * behavior and bsd4.3 behavior.
+ */
+#define __FD_NONBLOCK O_NONBLOCK
+
+/*
+ * New functions
+ */
+
+__BEGIN_DECLS
+
+#if defined(PTHREAD_KERNEL)
+
+#define __machdep_stack_get(x) (x)->machdep_stack
+#define __machdep_stack_set(x, y) (x)->machdep_stack = y
+#define __machdep_stack_repl(x, y) \
+{ \
+ if (stack = __machdep_stack_get(x)) { \
+ __machdep_stack_free(stack); \
+ } \
+ __machdep_stack_set(x, y); \
+}
+
+void * __machdep_stack_alloc __P_((size_t));
+void __machdep_stack_free __P_((void *));
+
+int machdep_save_state __P_((void));
+
+#endif
+
+__END_DECLS
diff --git a/mit-pthreads/machdep/engine-i386-linux-1.0.c b/mit-pthreads/machdep/engine-i386-linux-1.0.c
new file mode 100644
index 00000000000..fac044fe47c
--- /dev/null
+++ b/mit-pthreads/machdep/engine-i386-linux-1.0.c
@@ -0,0 +1,503 @@
+/* ==== machdep.c ============================================================
+ * Copyright (c) 1993, 1994 Chris Provenzano, proven@athena.mit.edu
+ *
+ * Description : Machine dependent functions for Linux-1.0 on i386
+ *
+ * 1.00 93/08/04 proven
+ * -Started coding this file.
+ */
+
+#ifndef lint
+static const char rcsid[] = "$Id$";
+#endif
+
+#include <pthread.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <sys/uio.h>
+#include <sys/types.h>
+#include <sys/param.h> /* for OPEN_MAX */
+#include <sys/socket.h>
+#include <sys/socketcall.h>
+
+/* ==========================================================================
+ * machdep_save_state()
+ */
+int machdep_save_state(void)
+{
+ return(_setjmp(pthread_run->machdep_data.machdep_state));
+}
+
+/* ==========================================================================
+ * machdep_restore_state()
+ */
+void machdep_restore_state(void)
+{
+ longjmp(pthread_run->machdep_data.machdep_state, 1);
+}
+
+/* ==========================================================================
+ * machdep_save_float_state()
+ */
+int machdep_save_float_state(struct pthread * pthread)
+{
+ char * fdata = (char *)pthread->machdep_data.machdep_float_state;
+
+ __asm__ ("fsave %0"::"m" (*fdata));
+}
+
+/* ==========================================================================
+ * machdep_restore_float_state()
+ */
+int machdep_restore_float_state(void)
+{
+ char * fdata = (char *)pthread_run->machdep_data.machdep_float_state;
+
+ __asm__ ("frstor %0"::"m" (*fdata));
+}
+
+/* ==========================================================================
+ * machdep_set_thread_timer()
+ */
+void machdep_set_thread_timer(struct machdep_pthread *machdep_pthread)
+{
+ if (setitimer(ITIMER_VIRTUAL, &(machdep_pthread->machdep_timer), NULL)) {
+ PANIC();
+ }
+}
+
+/* ==========================================================================
+ * machdep_unset_thread_timer()
+ */
+void machdep_unset_thread_timer(struct machdep_pthread *machdep_pthread)
+{
+ struct itimerval zeroval = { { 0, 0 }, { 0, 0} };
+
+ if (setitimer(ITIMER_VIRTUAL, &zeroval, NULL)) {
+ PANIC();
+ }
+}
+
+/* ==========================================================================
+ * machdep_pthread_cleanup()
+ */
+void *machdep_pthread_cleanup(struct machdep_pthread *machdep_pthread)
+{
+ return(machdep_pthread->machdep_stack);
+}
+
+/* ==========================================================================
+ * machdep_pthread_start()
+ */
+void machdep_pthread_start(void)
+{
+ context_switch_done();
+ pthread_sched_resume();
+
+ /* Run current threads start routine with argument */
+ pthread_exit(pthread_run->machdep_data.start_routine
+ (pthread_run->machdep_data.start_argument));
+
+ /* should never reach here */
+ PANIC();
+}
+
+/* ==========================================================================
+ * __machdep_stack_free()
+ */
+void __machdep_stack_free(void * stack)
+{
+ free(stack);
+}
+
+/* ==========================================================================
+ * __machdep_stack_alloc()
+ */
+void * __machdep_stack_alloc(size_t size)
+{
+ void * stack;
+
+ return(malloc(size));
+}
+
+/* ==========================================================================
+ * __machdep_pthread_create()
+ */
+void __machdep_pthread_create(struct machdep_pthread *machdep_pthread,
+ void *(* start_routine)(), void *start_argument,
+ long stack_size, long nsec, long flag)
+{
+ machdep_pthread->start_routine = start_routine;
+ machdep_pthread->start_argument = start_argument;
+
+ machdep_pthread->machdep_timer.it_value.tv_sec = 0;
+ machdep_pthread->machdep_timer.it_interval.tv_sec = 0;
+ machdep_pthread->machdep_timer.it_interval.tv_usec = 0;
+ machdep_pthread->machdep_timer.it_value.tv_usec = nsec / 1000;
+
+ setjmp(machdep_pthread->machdep_state);
+ /*
+ * Set up new stact frame so that it looks like it
+ * returned from a longjmp() to the beginning of
+ * machdep_pthread_start().
+ */
+ machdep_pthread->machdep_state->__pc = (char *)machdep_pthread_start;
+ machdep_pthread->machdep_state->__bp = (char *)0;/* So the backtrace
+ * is sensible (mevans) *
+
+ /* Stack starts high and builds down. */
+ machdep_pthread->machdep_state->__sp =
+ (char *)machdep_pthread->machdep_stack + stack_size;
+}
+
+
+/* ==========================================================================
+ * Linux Socket calls are a bit different
+ * ==========================================================================
+ * machdep_sys_socket()
+ */
+int machdep_sys_socket(int a, int b, int c)
+{
+ int array[3];
+
+ array[0] = (int)a;
+ array[1] = (int)b;
+ array[2] = (int)c;
+
+ return(machdep_sys_socketcall(SYS_SOCKET, array));
+}
+
+/* ==========================================================================
+ * machdep_sys_accept()
+ */
+int machdep_sys_accept(int a, struct sockaddr * b, int * c)
+{
+ int array[3];
+
+ array[0] = (int)a;
+ array[1] = (int)b;
+ array[2] = (int)c;
+
+ return(machdep_sys_socketcall(SYS_ACCEPT, array));
+}
+
+/* ==========================================================================
+ * machdep_sys_bind()
+ */
+int machdep_sys_bind(int a, const struct sockaddr * b, int c)
+{
+ int array[3];
+
+ array[0] = (int)a;
+ array[1] = (int)b;
+ array[2] = (int)c;
+
+ return(machdep_sys_socketcall(SYS_BIND, array));
+}
+
+/* ==========================================================================
+ * machdep_sys_connect()
+ */
+int machdep_sys_connect(int a, const struct sockaddr * b, int c)
+{
+ int array[3];
+
+ array[0] = (int)a;
+ array[1] = (int)b;
+ array[2] = (int)c;
+
+ return(machdep_sys_socketcall(SYS_CONNECT, array));
+}
+
+/* ==========================================================================
+ * machdep_sys_listen()
+ */
+int machdep_sys_listen(int a, const struct sockaddr * b, int c)
+{
+ int array[3];
+
+ array[0] = (int)a;
+ array[1] = (int)b;
+ array[2] = (int)c;
+
+ return(machdep_sys_socketcall(SYS_LISTEN, array));
+}
+
+/* ==========================================================================
+ * machdep_sys_shutdown()
+ */
+int machdep_sys_shutdown(int a, int b)
+{
+ int array[2];
+
+ array[0] = (int)a;
+ array[1] = (int)b;
+
+ return(machdep_sys_socketcall(SYS_SHUTDOWN, array));
+}
+
+/* ==========================================================================
+ * machdep_sys_getsockopt()
+ */
+int machdep_sys_getsockopt(int a, int b, int c, char *d, int *e)
+{
+ int array[5];
+
+ array[0] = (int)a;
+ array[1] = (int)b;
+ array[2] = (int)c;
+ array[3] = (int)d;
+ array[4] = (int)e;
+
+ return(machdep_sys_socketcall(SYS_GETSOCKOPT, array));
+}
+
+/* ==========================================================================
+ * machdep_sys_setsockopt()
+ */
+int machdep_sys_setsockopt(int a, int b, int c, char *d, int e)
+{
+ int array[5];
+
+ array[0] = (int)a;
+ array[1] = (int)b;
+ array[2] = (int)c;
+ array[3] = (int)d;
+ array[4] = (int)e;
+
+ return(machdep_sys_socketcall(SYS_SETSOCKOPT, array));
+}
+
+/* ==========================================================================
+ * machdep_sys_getpeername()
+ */
+int machdep_sys_getpeername(int a, struct sockaddr *b, int *c)
+{
+ int array[3];
+
+ array[0] = (int)a;
+ array[1] = (int)b;
+ array[2] = (int)c;
+
+ return(machdep_sys_socketcall(SYS_GETPEERNAME, array));
+}
+
+/* ==========================================================================
+ * machdep_sys_send()
+ */
+int machdep_sys_send(int a, char *b, int c, int d)
+{
+ int array[4];
+
+ array[0] = (int)a;
+ array[1] = (int)b;
+ array[2] = (int)c;
+ array[3] = (int)d;
+
+ return(machdep_sys_socketcall(SYS_SEND, array));
+}
+
+/* ==========================================================================
+ * machdep_sys_sendto()
+ */
+int machdep_sys_sendto(int a, char *b, int c, int d,
+ struct sockaddr *e, int f)
+{
+ int array[6];
+
+ array[0] = (int)a;
+ array[1] = (int)b;
+ array[2] = (int)c;
+ array[3] = (int)d;
+ array[4] = (int)e;
+ array[5] = (int)f;
+
+ return(machdep_sys_socketcall(SYS_SENDTO, array));
+}
+
+/* ==========================================================================
+ * machdep_sys_recv()
+ */
+int machdep_sys_recv(int a, char *b, int c, int d)
+{
+ int array[4];
+
+ array[0] = (int)a;
+ array[1] = (int)b;
+ array[2] = (int)c;
+ array[3] = (int)d;
+
+ return(machdep_sys_socketcall(SYS_RECV, array));
+}
+
+/* ==========================================================================
+ * machdep_sys_recvfrom()
+ */
+int machdep_sys_recvfrom(int a, char *b, int c, int d,
+ struct sockaddr *e, int *f)
+{
+ int array[6];
+
+ array[0] = (int)a;
+ array[1] = (int)b;
+ array[2] = (int)c;
+ array[3] = (int)d;
+ array[4] = (int)e;
+ array[5] = (int)f;
+
+ return(machdep_sys_socketcall(SYS_RECVFROM, array));
+}
+
+/* ==========================================================================
+ * machdep_sys_socketpair()
+ */
+int machdep_sys_socketpair(int a, int b, int c, int d[2])
+{
+ int array[4];
+
+ array[0] = (int)a;
+ array[1] = (int)b;
+ array[2] = (int)c;
+ array[3] = (int)d;
+
+ return(machdep_sys_socketcall(SYS_SOCKETPAIR, array));
+}
+
+/* ==========================================================================
+ * machdep_sys_getsockname()
+ */
+int machdep_sys_getsockname(int a, char * b, int * c)
+{
+ int array[3];
+
+ array[0] = (int)a;
+ array[1] = (int)b;
+ array[2] = (int)c;
+
+ return(machdep_sys_socketcall(SYS_GETSOCKNAME, array));
+}
+
+/* ==========================================================================
+ * machdep_sys_sendmsg()
+ */
+int machdep_sys_sendmsg(int a, char * b, int c)
+{
+#ifdef SYS_SENDMSG
+ int array[3];
+
+ array[0] = (int)a;
+ array[1] = (int)b;
+ array[2] = (int)c;
+
+ return(machdep_sys_socketcall(SYS_SENDMSG, array));
+#else
+ return(-ENOSYS);
+#endif
+}
+
+/* ==========================================================================
+ * machdep_sys_recvmsg()
+ */
+int machdep_sys_recvmsg(int a, char * b, int c)
+{
+#ifdef SYS_RECVMSG
+ int array[3];
+
+ array[0] = (int)a;
+ array[1] = (int)b;
+ array[2] = (int)c;
+
+ return(machdep_sys_socketcall(SYS_RECVMSG, array));
+#else
+ return(-ENOSYS);
+#endif
+}
+
+/* ==========================================================================
+ * machdep_sys_getdirentries()
+ */
+int machdep_sys_getdirentries(int fd, char * buf, int len, int * seek)
+{
+ int ret;
+
+ if ((ret = machdep_sys_readdir(fd, buf, 1)) > 0) {
+ return(1);
+ }
+ return(ret);
+}
+
+/* ==========================================================================
+ * machdep_sys_wait3()
+ */
+machdep_sys_wait3(int * b, int c, int * d)
+{
+ return(machdep_sys_wait4(0, b, c, d));
+}
+
+/* ==========================================================================
+ * machdep_sys_waitpid()
+ */
+machdep_sys_waitpid(int a, int * b, int c)
+{
+ return(machdep_sys_wait4(a, b, c, NULL));
+}
+
+/* getdtablesize */
+machdep_sys_getdtablesize ()
+{
+ return OPEN_MAX;
+}
+
+struct stat;
+
+/* ==========================================================================
+ * _fxstat()
+ */
+int _fxstat(int __ver, int fd, struct stat *buf)
+{
+ int ret;
+
+ if ((ret = fd_lock(fd, FD_READ, NULL)) == OK) {
+ ret = machdep_sys_fstat(fd_table[fd]->fd.i, buf);
+ fd_unlock(fd, FD_READ);
+ }
+ return(ret);
+}
+
+/* ==========================================================================
+ * _lxstat()
+ */
+int _lxstat(int __ver, const char * path, struct stat * buf)
+{
+ int ret;
+
+ if ((ret = machdep_sys_lstat(path, buf)) < OK) {
+ SET_ERRNO(-ret);
+ }
+ return(ret);
+
+}
+
+/* ==========================================================================
+ * _xstat()
+ */
+int _xstat(int __ver, const char * path, struct stat * buf)
+{
+ int ret;
+
+ if ((ret = machdep_sys_stat(path, buf)) < OK) {
+ SET_ERRNO(-ret);
+ }
+ return(ret);
+
+}
+
+/* ==========================================================================
+ * strtol()
+ */
+__strtol_internal(char * a, char ** b, int c)
+{
+ return(strtol(a, b, c));
+}
+
+
diff --git a/mit-pthreads/machdep/engine-i386-linux-1.0.h b/mit-pthreads/machdep/engine-i386-linux-1.0.h
new file mode 100644
index 00000000000..721618a6f19
--- /dev/null
+++ b/mit-pthreads/machdep/engine-i386-linux-1.0.h
@@ -0,0 +1,98 @@
+/* ==== machdep.h ============================================================
+ * Copyright (c) 1993 Chris Provenzano, proven@athena.mit.edu
+ *
+ * $Id$
+ */
+
+
+#include <unistd.h>
+#include <setjmp.h>
+#include <sys/time.h>
+
+/*
+ * The first machine dependent functions are the SEMAPHORES
+ * needing the test and set instruction.
+ */
+#define SEMAPHORE_CLEAR 0
+#define SEMAPHORE_SET 1
+
+#define SEMAPHORE_TEST_AND_SET(lock) \
+({ \
+volatile long temp = SEMAPHORE_SET; \
+ \
+__asm__("xchgl %0,(%2)" \
+ :"=r" (temp) \
+ :"0" (temp),"r" (lock)); \
+temp; \
+})
+
+#define SEMAPHORE_RESET(lock) *lock = SEMAPHORE_CLEAR
+
+/*
+ * New types
+ */
+typedef long semaphore;
+
+#define SIGMAX 31
+
+/*
+ * New Strutures
+ */
+struct machdep_pthread {
+ void *(*start_routine)(void *);
+ void *start_argument;
+ void *machdep_stack;
+ struct itimerval machdep_timer;
+ jmp_buf machdep_state;
+ char machdep_float_state[108];
+};
+
+/*
+ * Static machdep_pthread initialization values.
+ * For initial thread only.
+ */
+#define MACHDEP_PTHREAD_INIT \
+{ NULL, NULL, NULL, { { 0, 0 }, { 0, 100000 } }, 0 }
+
+/*
+ * Minimum stack size
+ */
+#define PTHREAD_STACK_MIN 1024
+
+/*
+ * sigset_t macros
+ */
+#define SIG_ANY(sig) (sig)
+
+/*
+ * Some fd flag defines that are necessary to distinguish between posix
+ * behavior and bsd4.3 behavior.
+ */
+#define __FD_NONBLOCK O_NONBLOCK
+
+/*
+ * New functions
+ */
+
+__BEGIN_DECLS
+
+#if defined(PTHREAD_KERNEL)
+
+#define __machdep_stack_get(x) (x)->machdep_stack
+#define __machdep_stack_set(x, y) (x)->machdep_stack = y
+#define __machdep_stack_repl(x, y) \
+{ \
+ if (stack = __machdep_stack_get(x)) { \
+ __machdep_stack_free(stack); \
+ } \
+ __machdep_stack_set(x, y); \
+}
+
+void * __machdep_stack_alloc __P_((size_t));
+void __machdep_stack_free __P_((void *));
+
+int machdep_save_state __P_((void));
+
+#endif
+
+__END_DECLS
diff --git a/mit-pthreads/machdep/engine-i386-linux-2.0.c b/mit-pthreads/machdep/engine-i386-linux-2.0.c
new file mode 100644
index 00000000000..72c757fe08a
--- /dev/null
+++ b/mit-pthreads/machdep/engine-i386-linux-2.0.c
@@ -0,0 +1,504 @@
+/* ==== machdep.c ============================================================
+ * Copyright (c) 1993, 1994 Chris Provenzano, proven@athena.mit.edu
+ *
+ * Description : Machine dependent functions for Linux-1.0 on i386
+ *
+ * 1.00 93/08/04 proven
+ * -Started coding this file.
+ */
+
+#ifndef lint
+static const char rcsid[] = "$Id$";
+#endif
+
+#include <pthread.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <sys/uio.h>
+#include <sys/types.h>
+#include <sys/param.h> /* for OPEN_MAX */
+#include <sys/socket.h>
+#include <sys/socketcall.h>
+#include <linux/net.h>
+
+/* ==========================================================================
+ * machdep_save_state()
+ */
+int machdep_save_state(void)
+{
+ return(_setjmp(pthread_run->machdep_data.machdep_state));
+}
+
+/* ==========================================================================
+ * machdep_restore_state()
+ */
+void machdep_restore_state(void)
+{
+ longjmp(pthread_run->machdep_data.machdep_state, 1);
+}
+
+/* ==========================================================================
+ * machdep_save_float_state()
+ */
+int machdep_save_float_state(struct pthread * pthread)
+{
+ char * fdata = (char *)pthread->machdep_data.machdep_float_state;
+
+ __asm__ ("fsave %0"::"m" (*fdata));
+}
+
+/* ==========================================================================
+ * machdep_restore_float_state()
+ */
+int machdep_restore_float_state(void)
+{
+ char * fdata = (char *)pthread_run->machdep_data.machdep_float_state;
+
+ __asm__ ("frstor %0"::"m" (*fdata));
+}
+
+/* ==========================================================================
+ * machdep_set_thread_timer()
+ */
+void machdep_set_thread_timer(struct machdep_pthread *machdep_pthread)
+{
+ if (setitimer(ITIMER_VIRTUAL, &(machdep_pthread->machdep_timer), NULL)) {
+ PANIC();
+ }
+}
+
+/* ==========================================================================
+ * machdep_unset_thread_timer()
+ */
+void machdep_unset_thread_timer(struct machdep_pthread *machdep_pthread)
+{
+ struct itimerval zeroval = { { 0, 0 }, { 0, 0} };
+
+ if (setitimer(ITIMER_VIRTUAL, &zeroval, NULL)) {
+ PANIC();
+ }
+}
+
+/* ==========================================================================
+ * machdep_pthread_cleanup()
+ */
+void *machdep_pthread_cleanup(struct machdep_pthread *machdep_pthread)
+{
+ return(machdep_pthread->machdep_stack);
+}
+
+/* ==========================================================================
+ * machdep_pthread_start()
+ */
+void machdep_pthread_start(void)
+{
+ context_switch_done();
+ pthread_sched_resume();
+
+ /* Run current threads start routine with argument */
+ pthread_exit(pthread_run->machdep_data.start_routine
+ (pthread_run->machdep_data.start_argument));
+
+ /* should never reach here */
+ PANIC();
+}
+
+/* ==========================================================================
+ * __machdep_stack_free()
+ */
+void __machdep_stack_free(void * stack)
+{
+ free(stack);
+}
+
+/* ==========================================================================
+ * __machdep_stack_alloc()
+ */
+void * __machdep_stack_alloc(size_t size)
+{
+ void * stack;
+
+ return(malloc(size));
+}
+
+/* ==========================================================================
+ * __machdep_pthread_create()
+ */
+void __machdep_pthread_create(struct machdep_pthread *machdep_pthread,
+ void *(* start_routine)(), void *start_argument,
+ long stack_size, long nsec, long flag)
+{
+ machdep_pthread->start_routine = start_routine;
+ machdep_pthread->start_argument = start_argument;
+
+ machdep_pthread->machdep_timer.it_value.tv_sec = 0;
+ machdep_pthread->machdep_timer.it_interval.tv_sec = 0;
+ machdep_pthread->machdep_timer.it_interval.tv_usec = 0;
+ machdep_pthread->machdep_timer.it_value.tv_usec = nsec / 1000;
+
+ setjmp(machdep_pthread->machdep_state);
+ /*
+ * Set up new stact frame so that it looks like it
+ * returned from a longjmp() to the beginning of
+ * machdep_pthread_start().
+ */
+ machdep_pthread->machdep_state->__jmpbuf[JB_PC]= (int) (char *)machdep_pthread_start;
+ /* Fix so that the backtrace * is sensible (mevans) */
+ machdep_pthread->machdep_state->__jmpbuf[JB_BP] = (int) (char *) 0;
+
+ /* Stack starts high and builds down. */
+ machdep_pthread->machdep_state->__jmpbuf[JB_SP]=
+ (int) (char *) machdep_pthread->machdep_stack + stack_size;
+}
+
+
+/* ==========================================================================
+ * Linux Socket calls are a bit different
+ * ==========================================================================
+ * machdep_sys_socket()
+ */
+int machdep_sys_socket(int a, int b, int c)
+{
+ int array[3];
+
+ array[0] = (int)a;
+ array[1] = (int)b;
+ array[2] = (int)c;
+
+ return(machdep_sys_socketcall(SYS_SOCKET, array));
+}
+
+/* ==========================================================================
+ * machdep_sys_accept()
+ */
+int machdep_sys_accept(int a, struct sockaddr * b, int * c)
+{
+ int array[3];
+
+ array[0] = (int)a;
+ array[1] = (int)b;
+ array[2] = (int)c;
+
+ return(machdep_sys_socketcall(SYS_ACCEPT, array));
+}
+
+/* ==========================================================================
+ * machdep_sys_bind()
+ */
+int machdep_sys_bind(int a, const struct sockaddr * b, int c)
+{
+ int array[3];
+
+ array[0] = (int)a;
+ array[1] = (int)b;
+ array[2] = (int)c;
+
+ return(machdep_sys_socketcall(SYS_BIND, array));
+}
+
+/* ==========================================================================
+ * machdep_sys_connect()
+ */
+int machdep_sys_connect(int a, const struct sockaddr * b, int c)
+{
+ int array[3];
+
+ array[0] = (int)a;
+ array[1] = (int)b;
+ array[2] = (int)c;
+
+ return(machdep_sys_socketcall(SYS_CONNECT, array));
+}
+
+/* ==========================================================================
+ * machdep_sys_listen()
+ */
+int machdep_sys_listen(int a, const struct sockaddr * b, int c)
+{
+ int array[3];
+
+ array[0] = (int)a;
+ array[1] = (int)b;
+ array[2] = (int)c;
+
+ return(machdep_sys_socketcall(SYS_LISTEN, array));
+}
+
+/* ==========================================================================
+ * machdep_sys_shutdown()
+ */
+int machdep_sys_shutdown(int a, int b)
+{
+ int array[2];
+
+ array[0] = (int)a;
+ array[1] = (int)b;
+
+ return(machdep_sys_socketcall(SYS_SHUTDOWN, array));
+}
+
+/* ==========================================================================
+ * machdep_sys_getsockopt()
+ */
+int machdep_sys_getsockopt(int a, int b, int c, char *d, int *e)
+{
+ int array[5];
+
+ array[0] = (int)a;
+ array[1] = (int)b;
+ array[2] = (int)c;
+ array[3] = (int)d;
+ array[4] = (int)e;
+
+ return(machdep_sys_socketcall(SYS_GETSOCKOPT, array));
+}
+
+/* ==========================================================================
+ * machdep_sys_setsockopt()
+ */
+int machdep_sys_setsockopt(int a, int b, int c, char *d, int e)
+{
+ int array[5];
+
+ array[0] = (int)a;
+ array[1] = (int)b;
+ array[2] = (int)c;
+ array[3] = (int)d;
+ array[4] = (int)e;
+
+ return(machdep_sys_socketcall(SYS_SETSOCKOPT, array));
+}
+
+/* ==========================================================================
+ * machdep_sys_getpeername()
+ */
+int machdep_sys_getpeername(int a, struct sockaddr *b, int *c)
+{
+ int array[3];
+
+ array[0] = (int)a;
+ array[1] = (int)b;
+ array[2] = (int)c;
+
+ return(machdep_sys_socketcall(SYS_GETPEERNAME, array));
+}
+
+/* ==========================================================================
+ * machdep_sys_send()
+ */
+int machdep_sys_send(int a, char *b, int c, int d)
+{
+ int array[4];
+
+ array[0] = (int)a;
+ array[1] = (int)b;
+ array[2] = (int)c;
+ array[3] = (int)d;
+
+ return(machdep_sys_socketcall(SYS_SEND, array));
+}
+
+/* ==========================================================================
+ * machdep_sys_sendto()
+ */
+int machdep_sys_sendto(int a, char *b, int c, int d,
+ struct sockaddr *e, int f)
+{
+ int array[6];
+
+ array[0] = (int)a;
+ array[1] = (int)b;
+ array[2] = (int)c;
+ array[3] = (int)d;
+ array[4] = (int)e;
+ array[5] = (int)f;
+
+ return(machdep_sys_socketcall(SYS_SENDTO, array));
+}
+
+/* ==========================================================================
+ * machdep_sys_recv()
+ */
+int machdep_sys_recv(int a, char *b, int c, int d)
+{
+ int array[4];
+
+ array[0] = (int)a;
+ array[1] = (int)b;
+ array[2] = (int)c;
+ array[3] = (int)d;
+
+ return(machdep_sys_socketcall(SYS_RECV, array));
+}
+
+/* ==========================================================================
+ * machdep_sys_recvfrom()
+ */
+int machdep_sys_recvfrom(int a, char *b, int c, int d,
+ struct sockaddr *e, int *f)
+{
+ int array[6];
+
+ array[0] = (int)a;
+ array[1] = (int)b;
+ array[2] = (int)c;
+ array[3] = (int)d;
+ array[4] = (int)e;
+ array[5] = (int)f;
+
+ return(machdep_sys_socketcall(SYS_RECVFROM, array));
+}
+
+/* ==========================================================================
+ * machdep_sys_socketpair()
+ */
+int machdep_sys_socketpair(int a, int b, int c, int d[2])
+{
+ int array[4];
+
+ array[0] = (int)a;
+ array[1] = (int)b;
+ array[2] = (int)c;
+ array[3] = (int)d;
+
+ return(machdep_sys_socketcall(SYS_SOCKETPAIR, array));
+}
+
+/* ==========================================================================
+ * machdep_sys_getsockname()
+ */
+int machdep_sys_getsockname(int a, char * b, int * c)
+{
+ int array[3];
+
+ array[0] = (int)a;
+ array[1] = (int)b;
+ array[2] = (int)c;
+
+ return(machdep_sys_socketcall(SYS_GETSOCKNAME, array));
+}
+
+/* ==========================================================================
+ * machdep_sys_sendmsg()
+ */
+int machdep_sys_sendmsg(int a, char * b, int c)
+{
+#ifdef SYS_SENDMSG
+ int array[3];
+
+ array[0] = (int)a;
+ array[1] = (int)b;
+ array[2] = (int)c;
+
+ return(machdep_sys_socketcall(SYS_SENDMSG, array));
+#else
+ return(-ENOSYS);
+#endif
+}
+
+/* ==========================================================================
+ * machdep_sys_recvmsg()
+ */
+int machdep_sys_recvmsg(int a, char * b, int c)
+{
+#ifdef SYS_RECVMSG
+ int array[3];
+
+ array[0] = (int)a;
+ array[1] = (int)b;
+ array[2] = (int)c;
+
+ return(machdep_sys_socketcall(SYS_RECVMSG, array));
+#else
+ return(-ENOSYS);
+#endif
+}
+
+/* ==========================================================================
+ * machdep_sys_getdirentries()
+ */
+int machdep_sys_getdirentries(int fd, char * buf, int len, int * seek)
+{
+ int ret;
+
+ if ((ret = machdep_sys_readdir(fd, buf, 1)) > 0) {
+ return(1);
+ }
+ return(ret);
+}
+
+/* ==========================================================================
+ * machdep_sys_wait3()
+ */
+machdep_sys_wait3(int * b, int c, int * d)
+{
+ return(machdep_sys_wait4(0, b, c, d));
+}
+
+/* ==========================================================================
+ * machdep_sys_waitpid()
+ */
+machdep_sys_waitpid(int a, int * b, int c)
+{
+ return(machdep_sys_wait4(a, b, c, NULL));
+}
+
+/* getdtablesize */
+machdep_sys_getdtablesize ()
+{
+ return OPEN_MAX;
+}
+
+struct stat;
+
+/* ==========================================================================
+ * _fxstat()
+ */
+int _fxstat(int __ver, int fd, struct stat *buf)
+{
+ int ret;
+
+ if ((ret = fd_lock(fd, FD_READ, NULL)) == OK) {
+ ret = machdep_sys_fstat(fd_table[fd]->fd.i, buf);
+ fd_unlock(fd, FD_READ);
+ }
+ return(ret);
+}
+
+/* ==========================================================================
+ * _lxstat()
+ */
+int _lxstat(int __ver, const char * path, struct stat * buf)
+{
+ int ret;
+
+ if ((ret = machdep_sys_lstat(path, buf)) < OK) {
+ SET_ERRNO(-ret);
+ }
+ return(ret);
+
+}
+
+/* ==========================================================================
+ * _xstat()
+ */
+int _xstat(int __ver, const char * path, struct stat * buf)
+{
+ int ret;
+
+ if ((ret = machdep_sys_stat(path, buf)) < OK) {
+ SET_ERRNO(-ret);
+ }
+ return(ret);
+
+}
+
+/* ==========================================================================
+ * strtol()
+ */
+__strtol_internal(char * a, char ** b, int c)
+{
+ return(strtol(a, b, c));
+}
+
+
diff --git a/mit-pthreads/machdep/engine-i386-linux-2.0.h b/mit-pthreads/machdep/engine-i386-linux-2.0.h
new file mode 100644
index 00000000000..721618a6f19
--- /dev/null
+++ b/mit-pthreads/machdep/engine-i386-linux-2.0.h
@@ -0,0 +1,98 @@
+/* ==== machdep.h ============================================================
+ * Copyright (c) 1993 Chris Provenzano, proven@athena.mit.edu
+ *
+ * $Id$
+ */
+
+
+#include <unistd.h>
+#include <setjmp.h>
+#include <sys/time.h>
+
+/*
+ * The first machine dependent functions are the SEMAPHORES
+ * needing the test and set instruction.
+ */
+#define SEMAPHORE_CLEAR 0
+#define SEMAPHORE_SET 1
+
+#define SEMAPHORE_TEST_AND_SET(lock) \
+({ \
+volatile long temp = SEMAPHORE_SET; \
+ \
+__asm__("xchgl %0,(%2)" \
+ :"=r" (temp) \
+ :"0" (temp),"r" (lock)); \
+temp; \
+})
+
+#define SEMAPHORE_RESET(lock) *lock = SEMAPHORE_CLEAR
+
+/*
+ * New types
+ */
+typedef long semaphore;
+
+#define SIGMAX 31
+
+/*
+ * New Strutures
+ */
+struct machdep_pthread {
+ void *(*start_routine)(void *);
+ void *start_argument;
+ void *machdep_stack;
+ struct itimerval machdep_timer;
+ jmp_buf machdep_state;
+ char machdep_float_state[108];
+};
+
+/*
+ * Static machdep_pthread initialization values.
+ * For initial thread only.
+ */
+#define MACHDEP_PTHREAD_INIT \
+{ NULL, NULL, NULL, { { 0, 0 }, { 0, 100000 } }, 0 }
+
+/*
+ * Minimum stack size
+ */
+#define PTHREAD_STACK_MIN 1024
+
+/*
+ * sigset_t macros
+ */
+#define SIG_ANY(sig) (sig)
+
+/*
+ * Some fd flag defines that are necessary to distinguish between posix
+ * behavior and bsd4.3 behavior.
+ */
+#define __FD_NONBLOCK O_NONBLOCK
+
+/*
+ * New functions
+ */
+
+__BEGIN_DECLS
+
+#if defined(PTHREAD_KERNEL)
+
+#define __machdep_stack_get(x) (x)->machdep_stack
+#define __machdep_stack_set(x, y) (x)->machdep_stack = y
+#define __machdep_stack_repl(x, y) \
+{ \
+ if (stack = __machdep_stack_get(x)) { \
+ __machdep_stack_free(stack); \
+ } \
+ __machdep_stack_set(x, y); \
+}
+
+void * __machdep_stack_alloc __P_((size_t));
+void __machdep_stack_free __P_((void *));
+
+int machdep_save_state __P_((void));
+
+#endif
+
+__END_DECLS
diff --git a/mit-pthreads/machdep/engine-i386-netbsd-0.9.c b/mit-pthreads/machdep/engine-i386-netbsd-0.9.c
new file mode 100644
index 00000000000..c42363fdeda
--- /dev/null
+++ b/mit-pthreads/machdep/engine-i386-netbsd-0.9.c
@@ -0,0 +1,155 @@
+/* ==== machdep.c ============================================================
+ * Copyright (c) 1993, 1994 Chris Provenzano, proven@athena.mit.edu
+ *
+ * Copyright (c) 1993 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Description : Machine dependent functions for NetBSD on i386
+ *
+ * 1.00 93/08/04 proven
+ * -Started coding this file.
+ */
+
+#ifndef lint
+static const char rcsid[] = "$Id$";
+#endif
+
+#include <pthread.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <stdio.h>
+
+/* ==========================================================================
+ * machdep_save_state()
+ */
+int machdep_save_state(void)
+{
+ return(_setjmp(pthread_run->machdep_data.machdep_state));
+}
+
+/* ==========================================================================
+ * machdep_restore_state()
+ */
+void machdep_restore_state(void)
+{
+ _longjmp(pthread_run->machdep_data.machdep_state, 1);
+}
+
+/* ==========================================================================
+ * machdep_set_thread_timer()
+ */
+void machdep_set_thread_timer(struct machdep_pthread *machdep_pthread)
+{
+ if (setitimer(ITIMER_VIRTUAL, &(machdep_pthread->machdep_timer), NULL)) {
+ PANIC();
+ }
+}
+
+/* ==========================================================================
+ * machdep_unset_thread_timer()
+ */
+void machdep_unset_thread_timer(struct machdep_pthread *machdep_pthread)
+{
+ struct itimerval zeroval = { { 0, 0 }, { 0, 0} };
+
+ if (setitimer(ITIMER_VIRTUAL, &zeroval, NULL)) {
+ PANIC();
+ }
+}
+
+/* ==========================================================================
+ * machdep_pthread_cleanup()
+ */
+void *machdep_pthread_cleanup(struct machdep_pthread *machdep_pthread)
+{
+ return(machdep_pthread->machdep_stack);
+}
+
+/* ==========================================================================
+ * machdep_pthread_start()
+ */
+void machdep_pthread_start(void)
+{
+ context_switch_done();
+ sig_check_and_resume();
+
+ /* Run current threads start routine with argument */
+ pthread_exit(pthread_run->machdep_data.start_routine
+ (pthread_run->machdep_data.start_argument));
+
+ /* should never reach here */
+ PANIC();
+}
+
+/* ==========================================================================
+ * machdep_pthread_create()
+ */
+void machdep_pthread_create(struct machdep_pthread *machdep_pthread,
+ void *(* start_routine)(), void *start_argument, long stack_size,
+ void *stack_start, long nsec)
+{
+ machdep_pthread->machdep_stack = stack_start;
+
+ machdep_pthread->start_routine = start_routine;
+ machdep_pthread->start_argument = start_argument;
+
+ machdep_pthread->machdep_timer.it_value.tv_sec = 0;
+ machdep_pthread->machdep_timer.it_interval.tv_sec = 0;
+ machdep_pthread->machdep_timer.it_interval.tv_usec = 0;
+ machdep_pthread->machdep_timer.it_value.tv_usec = nsec / 1000;
+
+ _setjmp(machdep_pthread->machdep_state);
+ /*
+ * Set up new stact frame so that it looks like it
+ * returned from a longjmp() to the beginning of
+ * machdep_pthread_start().
+ */
+ machdep_pthread->machdep_state[0] = (int)machdep_pthread_start;
+
+ /* Stack starts high and builds down. */
+ machdep_pthread->machdep_state[2] =
+ (int)machdep_pthread->machdep_stack + stack_size;
+}
+
+/* ==========================================================================
+ * machdep_sys_send()
+ */
+machdep_sys_send(int s, const void *buf, int len, int flags)
+{
+ return(machdep_sys_sendto(s, buf, len, flags, (struct sockaddr*)NULL, 0));
+}
+
+/* ==========================================================================
+ * machdep_sys_recv()
+ */
+machdep_sys_recv(int s, void *buf, int len, int flags)
+{
+ return(machdep_sys_recvfrom(s, buf, len, flags, (struct sockaddr*)NULL, 0));
+}
diff --git a/mit-pthreads/machdep/engine-i386-netbsd-0.9.h b/mit-pthreads/machdep/engine-i386-netbsd-0.9.h
new file mode 100644
index 00000000000..0e8e93bdbfb
--- /dev/null
+++ b/mit-pthreads/machdep/engine-i386-netbsd-0.9.h
@@ -0,0 +1,83 @@
+/* ==== machdep.h ============================================================
+ * Copyright (c) 1993 Chris Provenzano, proven@athena.mit.edu
+ *
+ * $Id$
+ *
+ */
+
+#include <unistd.h>
+#include <setjmp.h>
+#include <sys/time.h>
+
+/*
+ * The first machine dependent functions are the SEMAPHORES
+ * needing the test and set instruction.
+ */
+#define SEMAPHORE_CLEAR 0
+#define SEMAPHORE_SET 1
+
+#define SEMAPHORE_TEST_AND_SET(lock) \
+({ \
+long temp = SEMAPHORE_SET; \
+ \
+__asm__ volatile ("xchgl %0,(%2)" \
+ :"=r" (temp) \
+ :"0" (temp),"r" (lock)); \
+temp; \
+})
+
+#define SEMAPHORE_RESET(lock) *lock = SEMAPHORE_CLEAR
+
+/*
+ * New types
+ */
+typedef long semaphore;
+
+/*
+ * sigset_t macros
+ */
+#define SIG_ANY(sig) (sig)
+#define SIGMAX 31
+
+/*
+ * New Strutures
+ */
+struct machdep_pthread {
+ void *(*start_routine)(void *);
+ void *start_argument;
+ void *machdep_stack;
+ struct itimerval machdep_timer;
+ jmp_buf machdep_state;
+};
+
+/*
+ * Static machdep_pthread initialization values.
+ * For initial thread only.
+ */
+#define MACHDEP_PTHREAD_INIT \
+{ NULL, NULL, NULL, { { 0, 0 }, { 0, 100000 } }, 0 }
+
+/*
+ * Minimum stack size
+ */
+#define PTHREAD_STACK_MIN 1024
+
+/*
+ * Some fd flag defines that are necessary to distinguish between posix
+ * behavior and bsd4.3 behavior.
+ */
+#define __FD_NONBLOCK O_NONBLOCK
+
+/*
+ * New functions
+ */
+
+__BEGIN_DECLS
+
+#if defined(PTHREAD_KERNEL)
+
+int machdep_save_state __P_((void));
+
+#endif
+
+__END_DECLS
diff --git a/mit-pthreads/machdep/engine-i386-netbsd-1.0.c b/mit-pthreads/machdep/engine-i386-netbsd-1.0.c
new file mode 100644
index 00000000000..7f31cb0305d
--- /dev/null
+++ b/mit-pthreads/machdep/engine-i386-netbsd-1.0.c
@@ -0,0 +1,218 @@
+/* ==== machdep.c ============================================================
+ * Copyright (c) 1993, 1994 Chris Provenzano, proven@athena.mit.edu
+ *
+ * Copyright (c) 1993 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Description : Machine dependent functions for NetBSD on i386
+ *
+ * 1.00 93/08/04 proven
+ * -Started coding this file.
+ */
+
+#ifndef lint
+static const char rcsid[] = "$Id$";
+#endif
+
+#include <pthread.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <stdio.h>
+
+/* ==========================================================================
+ * machdep_save_state()
+ */
+int machdep_save_state(void)
+{
+ return(_setjmp(pthread_run->machdep_data.machdep_state));
+}
+
+/* ==========================================================================
+ * machdep_save_state()
+ */
+int machdep_save_float_state(struct pthread * pthread)
+{
+ char * fdata = (char *)pthread->machdep_data.machdep_float_state;
+
+ __asm__ ("fsave %0"::"m" (*fdata));
+}
+
+/* ==========================================================================
+ * machdep_restore_state()
+ */
+void machdep_restore_state(void)
+{
+ _longjmp(pthread_run->machdep_data.machdep_state, 1);
+}
+
+/* ==========================================================================
+ * machdep_restore_float_state()
+ */
+int machdep_restore_float_state(void)
+{
+ char * fdata = (char *)pthread_run->machdep_data.machdep_float_state;
+
+ __asm__ ("frstor %0"::"m" (*fdata));
+}
+
+/* ==========================================================================
+ * machdep_set_thread_timer()
+ */
+void machdep_set_thread_timer(struct machdep_pthread *machdep_pthread)
+{
+ if (setitimer(ITIMER_VIRTUAL, &(machdep_pthread->machdep_timer), NULL)) {
+ PANIC();
+ }
+}
+
+/* ==========================================================================
+ * machdep_unset_thread_timer()
+ */
+void machdep_unset_thread_timer(struct machdep_pthread *machdep_pthread)
+{
+ struct itimerval zeroval = { { 0, 0 }, { 0, 0 } };
+ int ret;
+
+ if (machdep_pthread) {
+ ret = setitimer(ITIMER_VIRTUAL, &zeroval,
+ &(machdep_pthread->machdep_timer));
+ } else {
+ ret = setitimer(ITIMER_VIRTUAL, &zeroval, NULL);
+ }
+
+ if (ret) {
+ PANIC();
+ }
+}
+
+/* ==========================================================================
+ * machdep_pthread_cleanup()
+ */
+void *machdep_pthread_cleanup(struct machdep_pthread *machdep_pthread)
+{
+ return(machdep_pthread->machdep_stack);
+}
+
+/* ==========================================================================
+ * machdep_pthread_start()
+ */
+void machdep_pthread_start(void)
+{
+ context_switch_done();
+ pthread_sched_resume();
+
+ /* Run current threads start routine with argument */
+ pthread_exit(pthread_run->machdep_data.start_routine
+ (pthread_run->machdep_data.start_argument));
+
+ /* should never reach here */
+ PANIC();
+}
+
+/* ==========================================================================
+ * __machdep_stack_free()
+ */
+void __machdep_stack_free(void * stack)
+{
+ free(stack);
+}
+
+/* ==========================================================================
+ * __machdep_stack_alloc()
+ */
+void * __machdep_stack_alloc(size_t size)
+{
+ void * stack;
+
+ return(malloc(size));
+}
+
+/* ==========================================================================
+ * __machdep_pthread_create()
+ */
+void __machdep_pthread_create(struct machdep_pthread *machdep_pthread,
+ void *(* start_routine)(), void *start_argument,
+ long stack_size, long nsec, long flags)
+{
+ machdep_pthread->start_routine = start_routine;
+ machdep_pthread->start_argument = start_argument;
+
+ machdep_pthread->machdep_timer.it_value.tv_sec = 0;
+ machdep_pthread->machdep_timer.it_interval.tv_sec = 0;
+ machdep_pthread->machdep_timer.it_interval.tv_usec = 0;
+ machdep_pthread->machdep_timer.it_value.tv_usec = nsec / 1000;
+
+ _setjmp(machdep_pthread->machdep_state);
+ /*
+ * Set up new stact frame so that it looks like it
+ * returned from a longjmp() to the beginning of
+ * machdep_pthread_start().
+ */
+ machdep_pthread->machdep_state[0] = (int)machdep_pthread_start;
+
+ /* Stack starts high and builds down. */
+ machdep_pthread->machdep_state[2] =
+ (int)machdep_pthread->machdep_stack + stack_size;
+}
+
+/* ==========================================================================
+ * machdep_sys_creat()
+ */
+machdep_sys_creat(char * path, int mode)
+{
+ return(machdep_sys_open(path, O_WRONLY | O_CREAT | O_TRUNC, mode));
+}
+
+/* ==========================================================================
+ * machdep_sys_wait3()
+ */
+machdep_sys_wait3(int * b, int c, int * d)
+{
+ return(machdep_sys_wait4(0, b, c, d));
+}
+
+/* ==========================================================================
+ * machdep_sys_waitpid()
+ */
+machdep_sys_waitpid(int a, int * b, int c)
+{
+ return(machdep_sys_wait4(a, b, c, NULL));
+}
+
+/* ==========================================================================
+ * machdep_sys_getdtablesize()
+ */
+machdep_sys_getdtablesize()
+{
+ return(sysconf(_SC_OPEN_MAX));
+}
+
diff --git a/mit-pthreads/machdep/engine-i386-netbsd-1.0.h b/mit-pthreads/machdep/engine-i386-netbsd-1.0.h
new file mode 100644
index 00000000000..80e17fef368
--- /dev/null
+++ b/mit-pthreads/machdep/engine-i386-netbsd-1.0.h
@@ -0,0 +1,97 @@
+/* ==== machdep.h ============================================================
+ * Copyright (c) 1993 Chris Provenzano, proven@athena.mit.edu
+ *
+ * $Id$
+ *
+ */
+
+#include <unistd.h>
+#include <setjmp.h>
+#include <sys/time.h>
+
+/*
+ * The first machine dependent functions are the SEMAPHORES
+ * needing the test and set instruction.
+ */
+#define SEMAPHORE_CLEAR 0
+#define SEMAPHORE_SET 1
+
+#define SEMAPHORE_TEST_AND_SET(lock) \
+({ \
+long temp = SEMAPHORE_SET; \
+ \
+__asm__ volatile ("xchgl %0,(%2)" \
+ :"=r" (temp) \
+ :"0" (temp),"r" (lock)); \
+temp; \
+})
+
+#define SEMAPHORE_RESET(lock) *lock = SEMAPHORE_CLEAR
+
+/*
+ * New types
+ */
+typedef long semaphore;
+
+/*
+ * sigset_t macros
+ */
+#define SIG_ANY(sig) (sig)
+#define SIGMAX 31
+
+/*
+ * New Strutures
+ */
+struct machdep_pthread {
+ void *(*start_routine)(void *);
+ void *start_argument;
+ void *machdep_stack;
+ struct itimerval machdep_timer;
+ jmp_buf machdep_state;
+ char machdep_float_state[108];
+};
+
+/*
+ * Static machdep_pthread initialization values.
+ * For initial thread only.
+ */
+#define MACHDEP_PTHREAD_INIT \
+{ NULL, NULL, NULL, { { 0, 0 }, { 0, 100000 } }, 0 }
+
+/*
+ * Minimum stack size
+ */
+#define PTHREAD_STACK_MIN 1024
+
+/*
+ * Some fd flag defines that are necessary to distinguish between posix
+ * behavior and bsd4.3 behavior.
+ */
+#define __FD_NONBLOCK O_NONBLOCK
+
+/*
+ * New functions
+ */
+
+__BEGIN_DECLS
+
+#if defined(PTHREAD_KERNEL)
+
+#define __machdep_stack_get(x) (x)->machdep_stack
+#define __machdep_stack_set(x, y) (x)->machdep_stack = y
+#define __machdep_stack_repl(x, y) \
+{ \
+ if (stack = __machdep_stack_get(x)) { \
+ __machdep_stack_free(stack); \
+ } \
+ __machdep_stack_set(x, y); \
+}
+
+void * __machdep_stack_alloc __P_((size_t));
+void __machdep_stack_free __P_((void *));
+
+int machdep_save_state __P_((void));
+
+#endif
+
+__END_DECLS
diff --git a/mit-pthreads/machdep/engine-i386-netbsd-1.3.c b/mit-pthreads/machdep/engine-i386-netbsd-1.3.c
new file mode 100644
index 00000000000..f86a9e5ba56
--- /dev/null
+++ b/mit-pthreads/machdep/engine-i386-netbsd-1.3.c
@@ -0,0 +1,225 @@
+/* ==== machdep.c ============================================================
+ * Copyright (c) 1993, 1994 Chris Provenzano, proven@athena.mit.edu
+ *
+ * Copyright (c) 1993 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Description : Machine dependent functions for NetBSD on i386
+ *
+ * 1.00 93/08/04 proven
+ * -Started coding this file.
+ */
+
+#ifndef lint
+static const char rcsid[] = "$Id$";
+#endif
+
+#include <pthread.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <stdio.h>
+
+/* ==========================================================================
+ * machdep_save_state()
+ */
+int machdep_save_state(void)
+{
+ return(_setjmp(pthread_run->machdep_data.machdep_state));
+}
+
+/* ==========================================================================
+ * machdep_save_state()
+ */
+int machdep_save_float_state(struct pthread * pthread)
+{
+ char * fdata = (char *)pthread->machdep_data.machdep_float_state;
+
+ __asm__ ("fsave %0"::"m" (*fdata));
+}
+
+/* ==========================================================================
+ * machdep_restore_state()
+ */
+void machdep_restore_state(void)
+{
+ _longjmp(pthread_run->machdep_data.machdep_state, 1);
+}
+
+/* ==========================================================================
+ * machdep_restore_float_state()
+ */
+int machdep_restore_float_state(void)
+{
+ char * fdata = (char *)pthread_run->machdep_data.machdep_float_state;
+
+ __asm__ ("frstor %0"::"m" (*fdata));
+}
+
+/* ==========================================================================
+ * machdep_set_thread_timer()
+ */
+void machdep_set_thread_timer(struct machdep_pthread *machdep_pthread)
+{
+ if (setitimer(ITIMER_VIRTUAL, &(machdep_pthread->machdep_timer), NULL)) {
+ PANIC();
+ }
+}
+
+/* ==========================================================================
+ * machdep_unset_thread_timer()
+ */
+void machdep_unset_thread_timer(struct machdep_pthread *machdep_pthread)
+{
+ struct itimerval zeroval = { { 0, 0 }, { 0, 0 } };
+ int ret;
+
+ if (machdep_pthread) {
+ ret = setitimer(ITIMER_VIRTUAL, &zeroval,
+ &(machdep_pthread->machdep_timer));
+ } else {
+ ret = setitimer(ITIMER_VIRTUAL, &zeroval, NULL);
+ }
+
+ if (ret) {
+ PANIC();
+ }
+}
+
+/* ==========================================================================
+ * machdep_pthread_cleanup()
+ */
+void *machdep_pthread_cleanup(struct machdep_pthread *machdep_pthread)
+{
+ return(machdep_pthread->machdep_stack);
+}
+
+/* ==========================================================================
+ * machdep_pthread_start()
+ */
+void machdep_pthread_start(void)
+{
+ context_switch_done();
+ pthread_sched_resume();
+
+ /* Run current threads start routine with argument */
+ pthread_exit(pthread_run->machdep_data.start_routine
+ (pthread_run->machdep_data.start_argument));
+
+ /* should never reach here */
+ PANIC();
+}
+
+/* ==========================================================================
+ * __machdep_stack_free()
+ */
+void __machdep_stack_free(void * stack)
+{
+ free(stack);
+}
+
+/* ==========================================================================
+ * __machdep_stack_alloc()
+ */
+void * __machdep_stack_alloc(size_t size)
+{
+ void * stack;
+
+ return(malloc(size));
+}
+
+/* ==========================================================================
+ * __machdep_pthread_create()
+ */
+void __machdep_pthread_create(struct machdep_pthread *machdep_pthread,
+ void *(* start_routine)(), void *start_argument,
+ long stack_size, long nsec, long flags)
+{
+ machdep_pthread->start_routine = start_routine;
+ machdep_pthread->start_argument = start_argument;
+
+ machdep_pthread->machdep_timer.it_value.tv_sec = 0;
+ machdep_pthread->machdep_timer.it_interval.tv_sec = 0;
+ machdep_pthread->machdep_timer.it_interval.tv_usec = 0;
+ machdep_pthread->machdep_timer.it_value.tv_usec = nsec / 1000;
+
+ _setjmp(machdep_pthread->machdep_state);
+ /*
+ * Set up new stact frame so that it looks like it
+ * returned from a longjmp() to the beginning of
+ * machdep_pthread_start().
+ */
+ machdep_pthread->machdep_state[0] = (int)machdep_pthread_start;
+
+ /* Stack starts high and builds down. */
+ machdep_pthread->machdep_state[2] =
+ (int)machdep_pthread->machdep_stack + stack_size;
+}
+
+/* ==========================================================================
+ * machdep_sys_creat()
+ */
+machdep_sys_creat(char * path, int mode)
+{
+ return(machdep_sys_open(path, O_WRONLY | O_CREAT | O_TRUNC, mode));
+}
+
+/* ==========================================================================
+ * machdep_sys_wait3()
+ */
+machdep_sys_wait3(int * b, int c, int * d)
+{
+ return(machdep_sys_wait4(0, b, c, d));
+}
+
+/* ==========================================================================
+ * machdep_sys_waitpid()
+ */
+machdep_sys_waitpid(int a, int * b, int c)
+{
+ return(machdep_sys_wait4(a, b, c, NULL));
+}
+
+/* ==========================================================================
+ * machdep_sys_getdtablesize()
+ */
+machdep_sys_getdtablesize()
+{
+ return(sysconf(_SC_OPEN_MAX));
+}
+
+/* ==========================================================================
+ * machdep_sys_getdirentries()
+ */
+machdep_sys_getdirentries(int fd, char * buf, int len, int * seek)
+{
+ return(machdep_sys_getdents(fd, buf, len));
+}
diff --git a/mit-pthreads/machdep/engine-i386-netbsd-1.3.h b/mit-pthreads/machdep/engine-i386-netbsd-1.3.h
new file mode 100644
index 00000000000..f399c4b34b6
--- /dev/null
+++ b/mit-pthreads/machdep/engine-i386-netbsd-1.3.h
@@ -0,0 +1,98 @@
+/* ==== machdep.h ============================================================
+ * Copyright (c) 1993 Chris Provenzano, proven@athena.mit.edu
+ *
+ * $Id$
+ *
+ */
+
+#include <unistd.h>
+#include <setjmp.h>
+#include <sys/time.h>
+#include <sys/signal.h> /* for _NSIG */
+
+/*
+ * The first machine dependent functions are the SEMAPHORES
+ * needing the test and set instruction.
+ */
+#define SEMAPHORE_CLEAR 0
+#define SEMAPHORE_SET 1
+
+#define SEMAPHORE_TEST_AND_SET(lock) \
+({ \
+long temp = SEMAPHORE_SET; \
+ \
+__asm__ volatile ("xchgl %0,(%2)" \
+ :"=r" (temp) \
+ :"0" (temp),"r" (lock)); \
+temp; \
+})
+
+#define SEMAPHORE_RESET(lock) *lock = SEMAPHORE_CLEAR
+
+/*
+ * New types
+ */
+typedef long semaphore;
+
+/*
+ * sigset_t macros
+ */
+#define SIG_ANY(sig) (sig)
+#define SIGMAX (_NSIG-1)
+
+/*
+ * New Strutures
+ */
+struct machdep_pthread {
+ void *(*start_routine)(void *);
+ void *start_argument;
+ void *machdep_stack;
+ struct itimerval machdep_timer;
+ jmp_buf machdep_state;
+ char machdep_float_state[108];
+};
+
+/*
+ * Static machdep_pthread initialization values.
+ * For initial thread only.
+ */
+#define MACHDEP_PTHREAD_INIT \
+{ NULL, NULL, NULL, { { 0, 0 }, { 0, 100000 } }, 0 }
+
+/*
+ * Minimum stack size
+ */
+#define PTHREAD_STACK_MIN 1024
+
+/*
+ * Some fd flag defines that are necessary to distinguish between posix
+ * behavior and bsd4.3 behavior.
+ */
+#define __FD_NONBLOCK O_NONBLOCK
+
+/*
+ * New functions
+ */
+
+__BEGIN_DECLS
+
+#if defined(PTHREAD_KERNEL)
+
+#define __machdep_stack_get(x) (x)->machdep_stack
+#define __machdep_stack_set(x, y) (x)->machdep_stack = y
+#define __machdep_stack_repl(x, y) \
+{ \
+ if (stack = __machdep_stack_get(x)) { \
+ __machdep_stack_free(stack); \
+ } \
+ __machdep_stack_set(x, y); \
+}
+
+void * __machdep_stack_alloc __P_((size_t));
+void __machdep_stack_free __P_((void *));
+
+int machdep_save_state __P_((void));
+
+#endif
+
+__END_DECLS
diff --git a/mit-pthreads/machdep/engine-i386-openbsd-2.0.c b/mit-pthreads/machdep/engine-i386-openbsd-2.0.c
new file mode 100644
index 00000000000..09ff0072fdc
--- /dev/null
+++ b/mit-pthreads/machdep/engine-i386-openbsd-2.0.c
@@ -0,0 +1,215 @@
+/* ==== machdep.c ============================================================
+ * Copyright (c) 1995 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Description : Machine dependent functions for NetBSD on i386
+ *
+ * 1.00 93/08/04 proven
+ * -Started coding this file.
+ */
+
+#ifndef lint
+static const char rcsid[] = "engine-i386-freebsd-2.0.c,v 1.1 1995/03/01 01:21:20 proven Exp";
+#endif
+
+#include <pthread.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <stdio.h>
+
+/* ==========================================================================
+ * machdep_save_state()
+ */
+int machdep_save_state(void)
+{
+ return(machdep_sys_setjmp(pthread_run->machdep_data.machdep_state));
+}
+
+/* ==========================================================================
+ * machdep_save_state()
+ */
+int machdep_save_float_state(struct pthread * pthread)
+{
+ char * fdata = (char *)pthread->machdep_data.machdep_float_state;
+
+ __asm__ ("fsave %0"::"m" (*fdata));
+}
+
+/* ==========================================================================
+ * machdep_restore_state()
+ */
+void machdep_restore_state(void)
+{
+ machdep_sys_longjmp(pthread_run->machdep_data.machdep_state, 1);
+}
+
+/* ==========================================================================
+ * machdep_restore_float_state()
+ */
+int machdep_restore_float_state(void)
+{
+ char * fdata = (char *)pthread_run->machdep_data.machdep_float_state;
+
+ __asm__ ("frstor %0"::"m" (*fdata));
+}
+
+/* ==========================================================================
+ * machdep_set_thread_timer()
+ */
+void machdep_set_thread_timer(struct machdep_pthread *machdep_pthread)
+{
+ if (setitimer(ITIMER_VIRTUAL, &(machdep_pthread->machdep_timer), NULL)) {
+ PANIC();
+ }
+}
+
+/* ==========================================================================
+ * machdep_unset_thread_timer()
+ */
+void machdep_unset_thread_timer(struct machdep_pthread *machdep_pthread)
+{
+ struct itimerval zeroval = { { 0, 0 }, { 0, 0 } };
+ int ret;
+
+ if (machdep_pthread) {
+ ret = setitimer(ITIMER_VIRTUAL, &zeroval,
+ &(machdep_pthread->machdep_timer));
+ } else {
+ ret = setitimer(ITIMER_VIRTUAL, &zeroval, NULL);
+ }
+
+ if (ret) {
+ PANIC();
+ }
+}
+
+/* ==========================================================================
+ * machdep_pthread_cleanup()
+ */
+void *machdep_pthread_cleanup(struct machdep_pthread *machdep_pthread)
+{
+ return(machdep_pthread->machdep_stack);
+}
+
+/* ==========================================================================
+ * machdep_pthread_start()
+ */
+void machdep_pthread_start(void)
+{
+ context_switch_done();
+ pthread_sched_resume();
+
+ /* Run current threads start routine with argument */
+ pthread_exit(pthread_run->machdep_data.start_routine
+ (pthread_run->machdep_data.start_argument));
+
+ /* should never reach here */
+ PANIC();
+}
+
+/* ==========================================================================
+ * __machdep_stack_free()
+ */
+void __machdep_stack_free(void * stack)
+{
+ free(stack);
+}
+
+/* ==========================================================================
+ * __machdep_stack_alloc()
+ */
+void * __machdep_stack_alloc(size_t size)
+{
+ void * stack;
+
+ return(malloc(size));
+}
+
+/* ==========================================================================
+ * __machdep_pthread_create()
+ */
+void __machdep_pthread_create(struct machdep_pthread *machdep_pthread,
+ void *(* start_routine)(), void *start_argument,
+ long stack_size, long nsec, long flags)
+{
+ machdep_pthread->start_routine = start_routine;
+ machdep_pthread->start_argument = start_argument;
+
+ machdep_pthread->machdep_timer.it_value.tv_sec = 0;
+ machdep_pthread->machdep_timer.it_interval.tv_sec = 0;
+ machdep_pthread->machdep_timer.it_interval.tv_usec = 0;
+ machdep_pthread->machdep_timer.it_value.tv_usec = nsec / 1000;
+
+ machdep_sys_setjmp(machdep_pthread->machdep_state);
+ /*
+ * Set up new stact frame so that it looks like it
+ * returned from a longjmp() to the beginning of
+ * machdep_pthread_start().
+ */
+ machdep_pthread->machdep_state[0] = (int)machdep_pthread_start;
+
+ /* Stack starts high and builds down. */
+ machdep_pthread->machdep_state[2] =
+ (int)machdep_pthread->machdep_stack + stack_size;
+}
+
+/* ==========================================================================
+ * machdep_sys_creat()
+ */
+machdep_sys_creat(char * path, int mode)
+{
+ return(machdep_sys_open(path, O_WRONLY | O_CREAT | O_TRUNC, mode));
+}
+
+/* ==========================================================================
+ * machdep_sys_wait3()
+ */
+machdep_sys_wait3(int * b, int c, int * d)
+{
+ return(machdep_sys_wait4(0, b, c, d));
+}
+
+/* ==========================================================================
+ * machdep_sys_waitpid()
+ */
+machdep_sys_waitpid(int a, int * b, int c)
+{
+ return(machdep_sys_wait4(a, b, c, NULL));
+}
+
+/* ==========================================================================
+ * machdep_sys_getdtablesize()
+ */
+machdep_sys_getdtablesize()
+{
+ return(sysconf(_SC_OPEN_MAX));
+}
diff --git a/mit-pthreads/machdep/engine-i386-openbsd-2.0.h b/mit-pthreads/machdep/engine-i386-openbsd-2.0.h
new file mode 100644
index 00000000000..87ef21389ce
--- /dev/null
+++ b/mit-pthreads/machdep/engine-i386-openbsd-2.0.h
@@ -0,0 +1,97 @@
+/* ==== machdep.h ============================================================
+ * Copyright (c) 1993 Chris Provenzano, proven@athena.mit.edu
+ *
+ * $Id$
+ *
+ */
+
+#include <unistd.h>
+#include <setjmp.h>
+#include <sys/time.h>
+
+/*
+ * The first machine dependent functions are the SEMAPHORES
+ * needing the test and set instruction.
+ */
+#define SEMAPHORE_CLEAR 0
+#define SEMAPHORE_SET 1
+
+#define SEMAPHORE_TEST_AND_SET(lock) \
+({ \
+long temp = SEMAPHORE_SET; \
+ \
+__asm__ volatile ("xchgl %0,(%2)" \
+ :"=r" (temp) \
+ :"0" (temp),"r" (lock)); \
+temp; \
+})
+
+#define SEMAPHORE_RESET(lock) *lock = SEMAPHORE_CLEAR
+
+/*
+ * New types
+ */
+typedef long semaphore;
+
+/*
+ * sigset_t macros
+ */
+#define SIG_ANY(sig) (sig)
+#define SIGMAX 31
+
+/*
+ * New Strutures
+ */
+struct machdep_pthread {
+ void *(*start_routine)(void *);
+ void *start_argument;
+ void *machdep_stack;
+ struct itimerval machdep_timer;
+ jmp_buf machdep_state;
+ char machdep_float_state[108];
+};
+
+/*
+ * Static machdep_pthread initialization values.
+ * For initial thread only.
+ */
+#define MACHDEP_PTHREAD_INIT \
+{ NULL, NULL, NULL, { { 0, 0 }, { 0, 100000 } }, 0 }
+
+/*
+ * Minimum stack size
+ */
+#define PTHREAD_STACK_MIN 1024
+
+/*
+ * Some fd flag defines that are necessary to distinguish between posix
+ * behavior and bsd4.3 behavior.
+ */
+#define __FD_NONBLOCK O_NONBLOCK
+
+/*
+ * New functions
+ */
+
+__BEGIN_DECLS
+
+#if defined(PTHREAD_KERNEL)
+
+#define __machdep_stack_get(x) (x)->machdep_stack
+#define __machdep_stack_set(x, y) (x)->machdep_stack = y
+#define __machdep_stack_repl(x, y) \
+{ \
+ if (stack = __machdep_stack_get(x)) { \
+ __machdep_stack_free(stack); \
+ } \
+ __machdep_stack_set(x, y); \
+}
+
+void * __machdep_stack_alloc __P_((size_t));
+void __machdep_stack_free __P_((void *));
+
+int machdep_save_state __P_((void));
+
+#endif
+
+__END_DECLS
diff --git a/mit-pthreads/machdep/engine-i386-sco-3.2v5.c b/mit-pthreads/machdep/engine-i386-sco-3.2v5.c
new file mode 100755
index 00000000000..95f0d757585
--- /dev/null
+++ b/mit-pthreads/machdep/engine-i386-sco-3.2v5.c
@@ -0,0 +1,1072 @@
+
+/* ==== machdep.c ============================================================
+ * Copyright (c) 1995 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Description : Machine dependent functions for SCO3.2v5 on i386
+ *
+ * 1.00 96/11/21 proven
+ * -Started coding this file.
+ */
+
+#ifndef lint
+static const char rcsid[] = "engine-i386-freebsd-2.0.c,v 1.1 1995/03/01 01:21:20 proven Exp";
+#endif
+
+#include <pthread.h>
+#include <sys/types.h>
+#include <sys/timeb.h>
+#include <sys/stat.h>
+#include <stropts.h>
+#include <sys/socket.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <errno.h>
+#include <sys/unistd.h>
+#include <sys/utsname.h>
+#include <sys/sysi86.h>
+
+void machdep_sys_abort(char*fname,int lineno)
+
+{
+ char buf[128];
+
+ sprintf(buf,"panic: %s => %d\n", fname, lineno);
+ machdep_sys_write(1, buf, strlen(buf));
+ abort();
+}
+
+#if 0
+int setitimer(int which, struct itimerval* value, struct itimerval* ovalue)
+
+{
+ register int ret;
+ if ((ret = machdep_sys_setitimer(which,value,ovalue))<0) {
+ errno = -ret;
+ return -1;
+ }
+ else {
+ return 0;
+ }
+}
+#endif
+
+/* ==========================================================================
+ * machdep_save_state()
+ */
+int machdep_save_state(void)
+{
+ return(setjmp(pthread_run->machdep_data.machdep_state));
+}
+
+/* ==========================================================================
+ * machdep_save_state()
+ */
+int machdep_save_float_state(struct pthread * pthread)
+{
+ char * fdata = (char *)pthread->machdep_data.machdep_float_state;
+ __asm__ ("fsave %0"::"m" (*fdata));
+}
+
+/* ==========================================================================
+ * machdep_restore_state()
+ */
+void machdep_restore_state(void)
+{
+ longjmp(pthread_run->machdep_data.machdep_state, 1);
+}
+
+/* ==========================================================================
+ * machdep_restore_float_state()
+ */
+int machdep_restore_float_state(void)
+{
+ char * fdata = (char *)pthread_run->machdep_data.machdep_float_state;
+ __asm__ ("frstor %0"::"m" (*fdata));
+}
+
+/* ==========================================================================
+ * machdep_set_thread_timer()
+ */
+void machdep_set_thread_timer(struct machdep_pthread *machdep_pthread)
+{
+ if (machdep_sys_setitimer(ITIMER_VIRTUAL, &(machdep_pthread->machdep_timer), NULL)) {
+ PANIC();
+ }
+}
+
+/* ==========================================================================
+ * machdep_unset_thread_timer()
+ */
+void machdep_unset_thread_timer(struct machdep_pthread *machdep_pthread)
+{
+ struct itimerval zeroval = { { 0, 0 }, { 0, 0 } };
+ int ret;
+
+ if (machdep_pthread) {
+ ret = machdep_sys_setitimer(ITIMER_VIRTUAL, &zeroval,
+ &(machdep_pthread->machdep_timer));
+ } else {
+ ret = machdep_sys_setitimer(ITIMER_VIRTUAL, &zeroval, NULL);
+ }
+
+ if (ret) {
+ PANIC();
+ }
+}
+
+/* ==========================================================================
+ * machdep_pthread_cleanup()
+ */
+void *machdep_pthread_cleanup(struct machdep_pthread *machdep_pthread)
+{
+ return(machdep_pthread->machdep_stack);
+}
+
+/* ==========================================================================
+ * machdep_pthread_start()
+ */
+void machdep_pthread_start(void)
+{
+ context_switch_done();
+ pthread_sched_resume();
+
+ /* Run current threads start routine with argument */
+ pthread_exit(pthread_run->machdep_data.start_routine
+ (pthread_run->machdep_data.start_argument));
+
+ /* should never reach here */
+ PANIC();
+}
+
+/* ==========================================================================
+ * __machdep_stack_free()
+ */
+void __machdep_stack_free(void * stack)
+{
+ free(stack);
+}
+
+/* ==========================================================================
+ * __machdep_stack_alloc()
+ */
+void * __machdep_stack_alloc(size_t size)
+{
+ void * stack;
+
+ return(malloc(size));
+}
+
+/* ==========================================================================
+ * __machdep_pthread_create()
+ */
+void __machdep_pthread_create(struct machdep_pthread *machdep_pthread,
+ void *(* start_routine)(), void *start_argument,
+ long stack_size, long nsec, long flags)
+{
+ machdep_pthread->start_routine = start_routine;
+ machdep_pthread->start_argument = start_argument;
+
+ machdep_pthread->machdep_timer.it_value.tv_sec = 0;
+ machdep_pthread->machdep_timer.it_interval.tv_sec = 0;
+ machdep_pthread->machdep_timer.it_interval.tv_usec = 0;
+ machdep_pthread->machdep_timer.it_value.tv_usec = nsec / 1000;
+
+ setjmp(machdep_pthread->machdep_state);
+ /*
+ * Set up new stact frame so that it looks like it
+ * returned from a longjmp() to the beginning of
+ * machdep_pthread_start().
+ */
+ machdep_pthread->machdep_state[JB_PC] = (int)machdep_pthread_start;
+
+ /* Stack starts high and builds down. */
+ machdep_pthread->machdep_state[JB_SP] =
+ (int)machdep_pthread->machdep_stack + stack_size;
+}
+
+/* ==========================================================================
+ * machdep_sys_wait3()
+ */
+machdep_sys_wait3(int * b, int c, int * d)
+{
+#if 0
+ return(machdep_sys_wait4(0, b, c, d));
+#else
+ return -ENOSYS;
+#endif
+}
+
+/* ==========================================================================
+ * machdep_sys_fstat()
+ */
+machdep_sys_fstat(int f, struct stat* b)
+{
+ return machdep_sys_fxstat(0x33, f, b);
+}
+
+/* ==========================================================================
+ * machdep_sys_dup2()
+ */
+machdep_sys_dup2(int a, int b)
+{
+ machdep_sys_close(b);
+ return machdep_sys_fcntl(a, F_DUPFD, b);
+}
+
+/* ==========================================================================
+ * machdep_sys_getdtablesize()
+ */
+machdep_sys_getdtablesize()
+
+{
+ register int ret;
+ if ((ret = machdep_sys_sysconf(_SC_OPEN_MAX))<0)
+ PANIC();
+ return ret;
+}
+
+/* ==========================================================================
+ * machdep_sys_fchown()
+ */
+machdep_sys_fchown(int fd,uid_t owner,gid_t group)
+
+{
+ return -ENOSYS;
+}
+
+/* ==========================================================================
+ * machdep_sys_fchmod()
+ */
+machdep_sys_fchmod(int fd,mode_t mode)
+
+{
+ return -ENOSYS;
+}
+
+/* ==========================================================================
+ * machdep_sys_getdirentries()
+ */
+int machdep_sys_getdirentries(int fd, char * buf, int len, int * seek)
+{
+ return(machdep_sys_getdents(fd, buf, len));
+}
+
+/* ==========================================================================
+ * SCO Socket calls are a bit different
+ * ==========================================================================
+ * machdep_sys_socket()
+ */
+int machdep_sys_socket(int domain, int type, int protocol)
+{
+ register int s, fd, ret;
+ struct socksysreq req;
+
+ if ((s = machdep_sys_open("/dev/socksys", 0))<0)
+ return s;
+
+ req.args[0] = SO_SOCKET;
+ req.args[1] = (int)domain;
+ req.args[2] = (int)type;
+ req.args[3] = (int)protocol;
+ if ((fd = machdep_sys_ioctl(s, SIOCSOCKSYS, &req))<0) {
+ machdep_sys_close(s);
+ return fd;
+ }
+
+ if ((ret=machdep_sys_dup2(fd, s))<0) {
+ machdep_sys_close(fd);
+ return ret;
+ }
+
+ machdep_sys_close(fd);
+ return s;
+
+}
+
+/* ==========================================================================
+ * machdep_sys_accept()
+ */
+int machdep_sys_accept(int s, struct sockaddr * b, int * c)
+{
+ struct socksysreq req;
+
+ req.args[0] = SO_ACCEPT;
+ req.args[1] = (int)s;
+ req.args[2] = (int)b;
+ req.args[3] = (int)c;
+
+ return(machdep_sys_ioctl(s, SIOCSOCKSYS, &req));
+}
+
+/* ==========================================================================
+ * machdep_sys_bind()
+ */
+int machdep_sys_bind(int s, const struct sockaddr * b, int c)
+{
+ struct socksysreq req;
+
+ req.args[0] = SO_BIND;
+ req.args[1] = (int)s;
+ req.args[2] = (int)b;
+ req.args[3] = (int)c;
+
+ return(machdep_sys_ioctl(s, SIOCSOCKSYS, &req));
+}
+
+/* ==========================================================================
+ * machdep_sys_connect()
+ */
+int machdep_sys_connect(int s, const struct sockaddr * b, int c)
+{
+ struct socksysreq req;
+
+ req.args[0] = SO_CONNECT;
+ req.args[1] = (int)s;
+ req.args[2] = (int)b;
+ req.args[3] = (int)c;
+
+ return(machdep_sys_ioctl(s, SIOCSOCKSYS, &req));
+}
+
+/* ==========================================================================
+ * machdep_sys_listen()
+ */
+int machdep_sys_listen(int s, int backlog)
+{
+ struct socksysreq req;
+
+ req.args[0] = SO_LISTEN;
+ req.args[1] = (int)s;
+ req.args[2] = (int)backlog;
+
+ return(machdep_sys_ioctl(s, SIOCSOCKSYS, &req));
+}
+
+/* ==========================================================================
+ * machdep_sys_shutdown()
+ */
+int machdep_sys_shutdown(int s, int b)
+{
+ struct socksysreq req;
+
+ req.args[0] = SO_SHUTDOWN;
+ req.args[1] = (int)s;
+ req.args[2] = (int)b;
+
+ return(machdep_sys_ioctl(s, SIOCSOCKSYS, &req));
+}
+
+/* ==========================================================================
+ * machdep_sys_getsockopt()
+ */
+int machdep_sys_getsockopt(int s, int b, int c, char *d, int *e)
+{
+ struct socksysreq req;
+
+ req.args[0] = SO_GETSOCKOPT;
+ req.args[1] = (int)s;
+ req.args[2] = (int)b;
+ req.args[3] = (int)c;
+ req.args[4] = (int)d;
+ req.args[5] = (int)e;
+
+ return(machdep_sys_ioctl(s, SIOCSOCKSYS, &req));
+}
+
+/* ==========================================================================
+ * machdep_sys_setsockopt()
+ */
+int machdep_sys_setsockopt(int s, int b, int c, char *d, int e)
+{
+ struct socksysreq req;
+
+ req.args[0] = SO_SETSOCKOPT;
+ req.args[1] = (int)s;
+ req.args[2] = (int)b;
+ req.args[3] = (int)c;
+ req.args[4] = (int)d;
+ req.args[5] = (int)e;
+
+ return(machdep_sys_ioctl(s, SIOCSOCKSYS, &req));
+}
+
+/* ==========================================================================
+ * machdep_sys_getpeername()
+ */
+int machdep_sys_getpeername(int s, struct sockaddr *b, int *c)
+{
+ struct socksysreq req;
+
+ req.args[0] = SO_GETPEERNAME;
+ req.args[1] = (int)s;
+ req.args[2] = (int)b;
+ req.args[3] = (int)c;
+
+ return(machdep_sys_ioctl(s, SIOCSOCKSYS, &req));
+}
+
+/* ==========================================================================
+ * machdep_sys_send()
+ */
+int machdep_sys_send(int s, char *b, int c, int d)
+{
+ struct socksysreq req;
+
+ req.args[0] = SO_SEND;
+ req.args[1] = (int)s;
+ req.args[2] = (int)b;
+ req.args[3] = (int)c;
+ req.args[4] = (int)d;
+
+ return(machdep_sys_ioctl(s, SIOCSOCKSYS, &req));
+}
+
+/* ==========================================================================
+ * machdep_sys_sendto()
+ */
+int machdep_sys_sendto(int s, char *b, int c, int d,
+ struct sockaddr *e, int f)
+{
+ struct socksysreq req;
+
+ req.args[0] = SO_SENDTO;
+ req.args[1] = (int)s;
+ req.args[2] = (int)b;
+ req.args[3] = (int)c;
+ req.args[4] = (int)d;
+ req.args[5] = (int)e;
+ req.args[6] = (int)f;
+
+ return(machdep_sys_ioctl(s, SIOCSOCKSYS, &req));
+}
+
+/* ==========================================================================
+ * machdep_sys_recv()
+ */
+int machdep_sys_recv(int s, char *b, int c, int d)
+{
+ struct socksysreq req;
+
+ req.args[0] = SO_RECV;
+ req.args[1] = (int)s;
+ req.args[2] = (int)b;
+ req.args[3] = (int)c;
+ req.args[4] = (int)d;
+
+ return(machdep_sys_ioctl(s, SIOCSOCKSYS, &req));
+}
+
+/* ==========================================================================
+ * machdep_sys_recvfrom()
+ */
+int machdep_sys_recvfrom(int s, char *buf, int len, int flags,
+ struct sockaddr *from, int *fromlen)
+{
+ struct socksysreq req;
+
+ req.args[0] = SO_RECVFROM;
+ req.args[1] = (int)s;
+ req.args[2] = (int)buf;
+ req.args[3] = (int)len;
+ req.args[4] = (int)flags;
+ req.args[5] = (int)from;
+ req.args[6] = (int)fromlen;
+
+ return(machdep_sys_ioctl(s, SIOCSOCKSYS, &req));
+}
+
+/* ==========================================================================
+ * machdep_sys_socketpair()
+ */
+int machdep_sys_socketpair(int d, int type, int protocol, int sv[2])
+
+{
+ register int s1, s2;
+ register int ret;
+ struct socksysreq req;
+
+ if (d != AF_UNIX)
+ return -EPROTONOSUPPORT;
+ if ((s1=machdep_sys_socket(d,type,protocol))<0) {
+ return s1;
+ }
+ if ((s2=machdep_sys_socket(d,type,protocol))<0) {
+ machdep_sys_close(s1);
+ return s2;
+ }
+ req.args[0] = SO_SOCKPAIR;
+ req.args[1] = s1;
+ req.args[2] = s2;
+ if ((ret=machdep_sys_ioctl(s1,SIOCSOCKSYS,&req))<0) {
+ machdep_sys_close(s1);
+ machdep_sys_close(s2);
+ return ret;
+ }
+ sv[0] = s1;
+ sv[1] = s2;
+ return 0;
+}
+
+/* ==========================================================================
+ * machdep_sys_getsockname()
+ */
+int machdep_sys_getsockname(int s, char * b, int * c)
+{
+ struct socksysreq req;
+
+ req.args[0] = SO_GETSOCKNAME;
+ req.args[1] = (int)s;
+ req.args[2] = (int)b;
+ req.args[3] = (int)c;
+
+ return(machdep_sys_ioctl(s, SIOCSOCKSYS, &req));
+}
+
+int machdep_sys_sendmsg(int s, const struct msghdr *msg, int flags)
+
+{
+ struct socksysreq req;
+
+ req.args[0] = SO_SENDMSG;
+ req.args[1] = (int)s;
+ req.args[2] = (int)msg;
+ req.args[3] = (int)flags;
+
+ return(machdep_sys_ioctl(s, SIOCSOCKSYS, &req));
+}
+
+int machdep_sys_recvmsg(int s, struct msghdr *msg, int flags)
+
+{
+ struct socksysreq req;
+
+ req.args[0] = SO_RECVMSG;
+ req.args[1] = (int)s;
+ req.args[2] = (int)msg;
+ req.args[3] = (int)flags;
+
+ return(machdep_sys_ioctl(s, SIOCSOCKSYS, &req));
+}
+
+u_short ntohs(u_short n)
+
+{
+ union {
+ unsigned char u_nc[4];
+ u_short u_ns;
+ } ns;
+ register unsigned char* p = &ns.u_nc[0];
+
+ ns.u_ns = n;
+ return (p[0]<<8)|p[1];
+}
+
+u_short htons(u_short h)
+
+{
+ union {
+ unsigned char u_nc[2];
+ u_short u_ns;
+ } ns;
+ register unsigned char* p = &ns.u_nc[0];
+ p[0] = (h>>8)&0xFF;
+ p[1] = (h&0xFF);
+ return ns.u_ns;
+}
+
+
+u_long ntohl(u_long n)
+
+{
+ union {
+ unsigned char u_nc[4];
+ u_long u_nl;
+ } nl;
+ register unsigned char* p = &nl.u_nc[0];
+
+ nl.u_nl = n;
+ return (p[0]<<24)|(p[1]<<16)|(p[2]<<8)|p[3];
+}
+
+u_long htonl(u_long h)
+
+{
+ union {
+ unsigned char u_nc[4];
+ u_long u_nl;
+ } nl;
+ register unsigned char* p = &nl.u_nc[0];
+ p[0] = (h>>24)&0xFF;
+ p[1] = (h>>16)&0xFF;
+ p[2] = (h>>8)&0xFF;
+ p[3] = (h&0xFF);
+ return nl.u_nl;
+}
+
+int getdomainname(char* domain,int len)
+
+{
+ /* edi = len */
+ struct socksysreq req;
+ register int ret, fd;
+ if (len>MAXHOSTNAMELEN)
+ len = MAXHOSTNAMELEN;
+
+ if ((fd = machdep_sys_open("/dev/socksys", 0)) < 0)
+ return fd;
+
+ req.args[0] = SO_GETIPDOMAIN;
+ req.args[1] = (int)domain;
+ req.args[2] = (int)len;
+ if((ret=machdep_sys_ioctl(fd, SIOCSOCKSYS, &req))<0) {
+ machdep_sys_close(fd);
+ return ret;
+ }
+
+ machdep_sys_close(fd);
+ domain[len-1] = '\0';
+ return 0;
+}
+
+int gethostname(char* name, int namelen)
+
+{
+ struct utsname uts;
+ register int ret, len;
+ char domain[MAXHOSTNAMELEN+1];
+
+ if (name==NULL)
+ return -EFAULT;
+ if ((ret=machdep_sys_uname(&uts))<0)
+ return ret;
+ if (namelen<(len=strlen(uts.nodename)))
+ return -EFAULT;
+ strncpy(name,uts.nodename,len);
+ if (namelen>len)
+ name[len] = '\0';
+ if ((ret=getdomainname(domain, namelen - len))<0)
+ return ret;
+ if (domain[0]=='\0')
+ return 0;
+ if (len + strlen(domain) + 2 > namelen)
+ return -EFAULT;
+ strcat(name, ".");
+ strcat(name, domain);
+ return 0;
+}
+
+int gettimeofday(struct timeval* tp, struct timezone* tz)
+
+{
+ register int ret;
+ if ((ret = machdep_sys_gettimeofday(tp, NULL))<0) {
+ errno = -ret;
+ return -1;
+ }
+ else {
+ return 0;
+ }
+}
+
+int kill(pid_t pid, int signo)
+
+{
+ register int ret;
+ if ((ret = machdep_sys_kill(pid,signo))<0) {
+ errno = -ret;
+ return -1;
+ }
+ else {
+ return 0;
+ }
+}
+
+typedef void (*signal_t(int signo, void (*func)(int)))(int);
+
+signal_t* _libc_signal = NULL;
+
+void (*signal(int signo, void (*func)(int)))(int)
+
+{
+ int ret;
+ void (*oldfunc)(int);
+ extern void (*machdep_sys_signal(int signo, void (*func)(int),int* r))(int);
+ if (_libc_signal!=NULL)
+ return (*_libc_signal)(signo, func);
+
+ oldfunc = machdep_sys_signal(signo, func, &ret);
+ if (ret!=0) {
+ errno = ret;
+ return SIG_ERR;
+ }
+ else {
+ return oldfunc;
+ }
+}
+
+int (*_libc_sigaction)(int ,const struct sigaction *, struct sigaction *) = NULL;
+int sigaction(int sig,const struct sigaction *act, struct sigaction *oact)
+
+{
+ register int ret;
+ if (_libc_sigaction!=NULL)
+ return (*_libc_sigaction)(sig,act,oact);
+ if ((ret = machdep_sys_sigaction(sig,act,oact))<0) {
+ errno = -ret;
+ return -1;
+ }
+ else {
+ return 0;
+ }
+}
+
+int (*_libc_sigprocmask)(int, const sigset_t *, sigset_t *) = NULL;
+
+int sigprocmask(int how, const sigset_t *set, sigset_t * oset)
+
+{
+ register int ret;
+ if (_libc_sigprocmask!=NULL)
+ return (*_libc_sigprocmask)(how,set,oset);
+ if ((ret = machdep_sys_sigprocmask(how,set,oset))<0) {
+ errno = -ret;
+ return -1;
+ }
+ else {
+ return 0;
+ }
+}
+
+int (*_libc_sigsuspend)(const sigset_t *) = NULL;
+
+int sigsuspend(const sigset_t *set)
+{
+ register int ret;
+ if (_libc_sigsuspend!=NULL)
+ return (*_libc_sigsuspend)(set);
+ if ((ret = machdep_sys_sigsuspend(set))<0) {
+ errno = -ret;
+ return -1;
+ }
+ else {
+ return 0;
+ }
+}
+
+int _sigrelse(sig)
+int sig;
+
+{
+ sigset_t mask;
+ sigemptyset(&mask);
+ sigaddset(&mask, sig);
+ return sigprocmask(SIG_UNBLOCK,&mask,NULL);
+}
+
+int _sighold(sig)
+int sig;
+
+{
+ sigset_t mask;
+ sigemptyset(&mask);
+ sigaddset(&mask, sig);
+ return sigprocmask(SIG_BLOCK,&mask,NULL);
+}
+
+void (*sigset(int sig, void (*func)(int)))(int)
+{
+ return signal(sig, func);
+}
+
+
+int (*_libc_getmsg)(int , struct strbuf *, struct strbuf *, int *) = NULL;
+
+int getmsg(int fd, struct strbuf * ctlptr, struct strbuf * dataptr,
+ int * flags)
+{
+ register int ret;
+ if (_libc_getmsg != NULL)
+ return (*_libc_getmsg)(fd,ctlptr,dataptr,flags);
+ else if ((ret=machdep_sys_getmsg(fd,ctlptr,dataptr,flags))<0) {
+ errno = -ret;
+ return -1;
+ }
+ else
+ return ret;
+}
+
+int (*_libc_putmsg)(int , const struct strbuf *, const struct strbuf *, int) = NULL;
+
+int putmsg(int fd, const struct strbuf * ctlptr, const struct strbuf * dataptr,
+ int flags)
+{
+ register int ret;
+ if (_libc_putmsg != NULL)
+ return (*_libc_putmsg)(fd,ctlptr,dataptr,flags);
+ else if ((ret=machdep_sys_putmsg(fd,ctlptr,dataptr,flags))<0) {
+ errno = -ret;
+ return -1;
+ }
+ else
+ return ret;
+}
+
+int ftime(struct timeb* tp)
+
+{
+ register int ret;
+ if ((ret=machdep_sys_ftime(tp))<0) {
+ errno = -ret;
+ return NOTOK;
+ }
+ return 0;
+}
+
+int getpagesize()
+
+{
+ register int ret;
+#if 0
+ if ((ret = machdep_sys_sysconf(_SC_PAGE_SIZE))<0) {
+ PANIC();
+ SET_ERRNO(-ret);
+ return -1;
+ }
+ else {
+ return 0;
+ }
+#else
+ return PAGESIZE;
+#endif
+}
+
+static pthread_mutex_t machdep_mutex =
+{ MUTEX_TYPE_COUNTING_FAST, PTHREAD_QUEUE_INITIALIZER, \
+ NULL, SEMAPHORE_CLEAR, { NULL }, MUTEX_FLAGS_INITED };
+
+static pthread_mutex_t malloc_mutex =
+{ MUTEX_TYPE_COUNTING_FAST, PTHREAD_QUEUE_INITIALIZER, \
+ NULL, SEMAPHORE_CLEAR, { NULL }, MUTEX_FLAGS_INITED };
+
+struct stdlock {
+ volatile long init;
+ pthread_mutex_t* mutex;
+};
+
+static void machdep_stdinitlock(struct stdlock* lock)
+
+{
+ if (lock==0) PANIC();
+ pthread_mutex_lock(&machdep_mutex);
+ if (!lock->init) {
+ register pthread_mutex_t* mutex;
+ pthread_mutexattr_t attr;
+
+ lock->init = 1;
+ lock->mutex = &machdep_mutex;
+ mutex = (pthread_mutex_t*) malloc(sizeof(pthread_mutex_t));
+ pthread_mutexattr_init (&attr);
+ pthread_mutexattr_settype (&attr, MUTEX_TYPE_COUNTING_FAST);
+ pthread_mutex_init(mutex, &attr);
+ lock->mutex = mutex;
+ }
+ pthread_mutex_unlock(&machdep_mutex);
+}
+
+void machdep_stdlock(struct stdlock* lock)
+
+{
+ if (lock==0) PANIC();
+ if (!lock->init)
+ machdep_stdinitlock(lock);
+ pthread_mutex_lock(lock->mutex);
+}
+
+void machdep_stdunlock(struct stdlock* lock)
+
+{
+ if (lock==0) PANIC();
+ if (!lock->init)
+ machdep_stdinitlock(lock);
+ pthread_mutex_unlock(lock->mutex);
+}
+
+int machdep_stdtrylock(struct stdlock* lock)
+
+{
+ if (lock==0) PANIC();
+ if (!lock->init)
+ machdep_stdinitlock(lock);
+ return pthread_mutex_trylock(lock->mutex);
+}
+
+int machdep_stdtryunlock(struct stdlock* lock)
+
+{
+ if (lock==0) PANIC();
+ if (!lock->init)
+ machdep_stdinitlock(lock);
+ if (pthread_mutex_trylock(lock->mutex))
+ return pthread_mutex_unlock(lock->mutex);
+ return 0;
+}
+
+extern void (*_libc_stdlock)(struct stdlock* lock);
+extern void (*_libc_stdunlock)(struct stdlock* lock);
+extern int (*_libc_stdtrylock)(struct stdlock* lock);
+extern int (*_libc_stdtryunlock)(struct stdlock* lock);
+
+int machdep_sys_init()
+
+{
+ typedef void (*voidfunc_t)();
+ extern voidfunc_t _libc_read;
+ extern voidfunc_t _libc_write;
+ extern voidfunc_t _libc_readv;
+ extern voidfunc_t _libc_writev;
+ extern voidfunc_t _libc_open;
+ extern voidfunc_t _libc_close;
+ extern voidfunc_t _libc_fork;
+ extern voidfunc_t _libc_fcntl;
+ extern voidfunc_t _libc_dup;
+ extern voidfunc_t _libc_pipe;
+ extern voidfunc_t _libc_select;
+ extern voidfunc_t _libc_malloc;
+ extern voidfunc_t _libc_realloc;
+ extern voidfunc_t _libc_free;
+ extern ssize_t pthread_read (int , char*, int );
+ extern ssize_t pthread_write (int , char*, int );
+ extern int pthread_close (int);
+ extern int pthread_dup (int);
+ extern int pthread_fork ();
+ extern int pthread_pipe (int*);
+ extern int pthread_fcntl(int, int, ...);
+ extern int pthread_open(const char *, int, ...);
+ extern ssize_t pthread_readv (int , const struct iovec *, int );
+ extern ssize_t pthread_writev (int , const struct iovec *, int );
+ extern int pthread_select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
+ extern int pthread_getmsg(int , struct strbuf *, struct strbuf *,int*);
+ extern int pthread_putmsg(int , const struct strbuf *, const struct strbuf *,int);
+ extern void (*pthread_signal(int , void (*)(int)))(int);
+ extern int pthread_sigaction(int,const struct sigaction *, struct sigaction *);
+ extern int pthread_sigprocmask(int, const sigset_t *, sigset_t *);
+ extern int pthread_sigsuspend(const sigset_t *);
+
+
+ static struct {
+ voidfunc_t *p;
+ voidfunc_t f;
+ } maptable[] = {
+ {(voidfunc_t*)&_libc_read, (voidfunc_t) pthread_read},
+ {(voidfunc_t*)&_libc_write, (voidfunc_t) pthread_write},
+ {(voidfunc_t*)&_libc_readv, (voidfunc_t) pthread_readv},
+ {(voidfunc_t*)&_libc_writev, (voidfunc_t) pthread_writev},
+ {(voidfunc_t*)&_libc_open, (voidfunc_t) pthread_open},
+ {(voidfunc_t*)&_libc_close, (voidfunc_t) pthread_close},
+ {(voidfunc_t*)&_libc_fork, (voidfunc_t) pthread_fork},
+ {(voidfunc_t*)&_libc_fcntl, (voidfunc_t) pthread_fcntl},
+ {(voidfunc_t*)&_libc_dup, (voidfunc_t) pthread_dup},
+ {(voidfunc_t*)&_libc_pipe, (voidfunc_t) pthread_pipe},
+ {(voidfunc_t*)&_libc_select, (voidfunc_t) pthread_select},
+ {(voidfunc_t*)&_libc_getmsg, (voidfunc_t) pthread_getmsg},
+ {(voidfunc_t*)&_libc_putmsg, (voidfunc_t) pthread_putmsg},
+ {(voidfunc_t*)&_libc_signal, (voidfunc_t) pthread_signal},
+ {(voidfunc_t*)&_libc_sigaction, (voidfunc_t) pthread_sigaction},
+ {(voidfunc_t*)&_libc_sigprocmask, (voidfunc_t) pthread_sigprocmask},
+ {(voidfunc_t*)&_libc_sigsuspend, (voidfunc_t) pthread_sigsuspend},
+ {(voidfunc_t*) 0, (voidfunc_t) 0}
+ };
+ register int i;
+
+ for (i=0; maptable[i].p; i++)
+ *maptable[i].p = maptable[i].f;
+
+ _libc_stdlock = machdep_stdlock;
+ _libc_stdunlock = machdep_stdunlock;
+ _libc_stdtrylock = machdep_stdtrylock;
+ _libc_stdtryunlock = machdep_stdtryunlock;
+ return 0;
+}
+
+#if 0
+extern end;
+char* nd = (char*) &end;
+char* brk(const char* endds)
+
+{
+ register int ret;
+
+ if ((ret = machdep_sys_brk((char*)endds))<0) {
+ SET_ERRNO(-ret);
+ return (char*) -1;
+ }
+ else {
+ nd = (char*) endds;
+ return 0;
+ }
+}
+
+char *sbrk(int incr)
+
+{
+ register char* ret;
+ if (incr!=0 && (ret=brk(nd + incr))!=0)
+ return ret;
+ else
+ return nd - incr;
+}
+#endif
+
+sigset_t sigmask(int sig)
+
+{
+ sigset_t oset;
+ sigemptyset(&oset);
+ sigaddset(&oset, sig);
+ return oset;
+}
+
+sigset_t sigsetmask(sigset_t set)
+
+{
+ sigset_t oset;
+ sigprocmask(SIG_SETMASK,&set,&oset);
+ return oset;
+}
+
+sigset_t sigblock(sigset_t set)
+
+{
+ sigset_t oset;
+ sigprocmask(SIG_BLOCK,&set,&oset);
+ return oset;
+}
diff --git a/mit-pthreads/machdep/engine-i386-sco-3.2v5.h b/mit-pthreads/machdep/engine-i386-sco-3.2v5.h
new file mode 100644
index 00000000000..8b2aa362f06
--- /dev/null
+++ b/mit-pthreads/machdep/engine-i386-sco-3.2v5.h
@@ -0,0 +1,104 @@
+/* ==== machdep.h ============================================================
+ * Copyright (c) 1993 Chris Provenzano, proven@athena.mit.edu
+ *
+ * engine-i386-freebsd-2.0.h,v 1.1.4.1 1995/12/13 05:41:52 proven Exp
+ *
+ */
+
+#include <unistd.h>
+#include <setjmp.h>
+#include <sys/time.h>
+
+#ifndef __NORETURN
+#define __NORETURN
+#endif
+
+/*
+ * The first machine dependent functions are the SEMAPHORES
+ * needing the test and set instruction.
+ */
+#define SEMAPHORE_CLEAR 0
+#define SEMAPHORE_SET 1
+
+#define SEMAPHORE_TEST_AND_SET(lock) \
+({ \
+long temp = SEMAPHORE_SET; \
+ \
+__asm__ volatile ("xchgl %0,(%2)" \
+ :"=r" (temp) \
+ :"0" (temp),"r" (lock)); \
+temp; \
+})
+
+#define SEMAPHORE_RESET(lock) *lock = SEMAPHORE_CLEAR
+
+/*
+ * New types
+ */
+typedef long semaphore;
+
+/*
+ * sigset_t macros
+ */
+#define SIG_ANY(sig) (sig)
+#define SIGMAX 31
+
+/*
+ * New Strutures
+ */
+struct machdep_pthread {
+ void *(*start_routine)(void *);
+ void *start_argument;
+ void *machdep_stack;
+ struct itimerval machdep_timer;
+ jmp_buf machdep_state;
+#define JB_BP 3
+#define JB_SP 4
+#define JB_PC 5
+ char machdep_float_state[108];
+};
+
+/*
+ * Static machdep_pthread initialization values.
+ * For initial thread only.
+ */
+#define MACHDEP_PTHREAD_INIT \
+{ NULL, NULL, NULL, { { 0, 0 }, { 0, 100000 } }, 0 }
+
+/*
+ * Minimum stack size
+ */
+#define PTHREAD_STACK_MIN 2048
+
+/*
+ * Some fd flag defines that are necessary to distinguish between posix
+ * behavior and bsd4.3 behavior.
+ */
+#define __FD_NONBLOCK O_NONBLOCK
+
+/*
+ * New functions
+ */
+
+__BEGIN_DECLS
+
+#if defined(PTHREAD_KERNEL)
+
+#define __machdep_stack_get(x) (x)->machdep_stack
+#define __machdep_stack_set(x, y) (x)->machdep_stack = y
+#define __machdep_stack_repl(x, y) \
+{ \
+ if (stack = __machdep_stack_get(x)) { \
+ __machdep_stack_free(stack); \
+ } \
+ __machdep_stack_set(x, y); \
+}
+
+void * __machdep_stack_alloc __P_((size_t));
+void __machdep_stack_free __P_((void *));
+
+int machdep_save_state __P_((void));
+
+#endif
+
+__END_DECLS
diff --git a/mit-pthreads/machdep/engine-ip22-irix-5.2.c b/mit-pthreads/machdep/engine-ip22-irix-5.2.c
new file mode 100644
index 00000000000..d205d05f316
--- /dev/null
+++ b/mit-pthreads/machdep/engine-ip22-irix-5.2.c
@@ -0,0 +1,225 @@
+/* ==== machdep.c ============================================================
+ * Copyright (c) 1995 Chris Provenzano, proven@athena.mit.edu
+ *
+ * Description : Machine dependent functions for IRIX-5.2 on the IP22
+ *
+ * 1.00 95/04/26 proven
+ * -Started coding this file.
+ */
+
+#ifndef lint
+static const char rcsid[] = "$Id$";
+#endif
+
+#include <pthread.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+/* ==========================================================================
+ * machdep_save_state()
+ */
+int machdep_save_state(void)
+{
+ return(setjmp(pthread_run->machdep_data.machdep_state));
+}
+
+/* ==========================================================================
+ * machdep_restore_state()
+ */
+void machdep_restore_state(void)
+{
+ longjmp(pthread_run->machdep_data.machdep_state, 1);
+}
+
+/* ==========================================================================
+ * machdep_set_thread_timer()
+ */
+void machdep_set_thread_timer(struct machdep_pthread *machdep_pthread)
+{
+ if (setitimer(ITIMER_VIRTUAL, &(machdep_pthread->machdep_timer), NULL)) {
+ PANIC();
+ }
+}
+
+/* ==========================================================================
+ * machdep_unset_thread_timer()
+ */
+void machdep_unset_thread_timer(struct machdep_pthread *machdep_pthread)
+{
+ struct itimerval zeroval = { { 0, 0 }, { 0, 0} };
+
+ if (setitimer(ITIMER_VIRTUAL, &zeroval, NULL)) {
+ PANIC();
+ }
+}
+
+/* ==========================================================================
+ * machdep_pthread_cleanup()
+ */
+void *machdep_pthread_cleanup(struct machdep_pthread *machdep_pthread)
+{
+ return(machdep_pthread->machdep_stack);
+}
+
+/* ==========================================================================
+ * machdep_pthread_start()
+ */
+void machdep_pthread_start(void)
+{
+ context_switch_done();
+ pthread_sched_resume();
+
+ /* Run current threads start routine with argument */
+ pthread_exit(pthread_run->machdep_data.start_routine
+ (pthread_run->machdep_data.start_argument));
+
+ /* should never reach here */
+ PANIC();
+}
+
+/* ==========================================================================
+ * __machdep_stack_free()
+ */
+void __machdep_stack_free(void * stack)
+{
+ free(stack);
+}
+
+/* ==========================================================================
+ * __machdep_stack_alloc()
+ */
+void * __machdep_stack_alloc(size_t size)
+{
+ void * stack;
+
+ return(malloc(size));
+}
+
+/* ==========================================================================
+ * __machdep_pthread_create()
+ */
+void __machdep_pthread_create(struct machdep_pthread *machdep_pthread,
+ void *(* start_routine)(), void *start_argument,
+ long stack_size, long nsec, long flags)
+{
+ int i;
+
+ machdep_pthread->start_routine = start_routine;
+ machdep_pthread->start_argument = start_argument;
+
+ machdep_pthread->machdep_timer.it_value.tv_sec = 0;
+ machdep_pthread->machdep_timer.it_interval.tv_sec = 0;
+ machdep_pthread->machdep_timer.it_interval.tv_usec = 0;
+ machdep_pthread->machdep_timer.it_value.tv_usec = nsec / 1000;
+
+ if (setjmp(machdep_pthread->machdep_state)) {
+ machdep_pthread_start();
+ }
+
+ /*
+ * Set up new stact frame so that it looks like it
+ * returned from a longjmp() to the beginning of
+ * machdep_pthread_start().
+ */
+
+ /* IP22 stack starts high and builds down. */
+ machdep_pthread->machdep_state[JB_SP] =
+ (int)machdep_pthread->machdep_stack + stack_size - 1024;
+ machdep_pthread->machdep_state[JB_SP] &= ~7;
+
+ memcpy((void *)machdep_pthread->machdep_state[JB_SP],
+ (char *)(((int)&i) - 24), 32);
+
+}
+
+/* ==========================================================================
+ * machdep_sys_dup2()
+ */
+machdep_sys_dup2(int a, int b)
+{
+ machdep_sys_close(b);
+ machdep_sys_fcntl(a, F_DUPFD, b);
+}
+
+/* ==========================================================================
+ * machdep_sys_wait3()
+ */
+machdep_sys_wait3(int * b, int c, int * d)
+{
+ return(machdep_sys_waitsys(0, b, c, d));
+}
+
+/* ==========================================================================
+ * machdep_sys_waitpid()
+ */
+machdep_sys_waitpid(int a, int * b, int c)
+{
+ return(machdep_sys_waitsys(a, b, c, NULL));
+}
+
+struct stat;
+
+/* ==========================================================================
+ * _fxstat()
+ */
+int _fxstat(int __ver, int fd, struct stat *buf)
+{
+ int ret;
+
+ if ((ret = fd_lock(fd, FD_READ, NULL)) == OK) {
+ if ((ret = machdep_sys_fstat(fd_table[fd]->fd.i, buf)) < OK) {
+ SET_ERRNO(-ret);
+ }
+ fd_unlock(fd, FD_READ);
+ }
+ return(ret);
+}
+
+/* ==========================================================================
+ * _lxstat()
+ */
+int _lxstat(int __ver, const char * path, struct stat * buf)
+{
+ int ret;
+
+ if ((ret = machdep_sys_lstat(path, buf)) < OK) {
+ SET_ERRNO(-ret);
+ }
+ return(ret);
+
+}
+
+/* ==========================================================================
+ * _xstat()
+ */
+int _xstat(int __ver, const char * path, struct stat * buf)
+{
+ int ret;
+
+ if ((ret = machdep_sys_stat(path, buf)) < OK) {
+ SET_ERRNO(-ret);
+ }
+ return(ret);
+
+}
+
+/* ==========================================================================
+ * getdtablesize()
+ */
+machdep_sys_getdtablesize()
+{
+ return(sysconf(_SC_OPEN_MAX));
+}
+
+/* ==========================================================================
+ * machdep_sys_getdirentries()
+ */
+int machdep_sys_getdirentries(int fd, char * buf, int len, int * seek)
+{
+ int i;
+
+ i = machdep_sys_getdents(fd, buf, len);
+ return i;
+}
diff --git a/mit-pthreads/machdep/engine-ip22-irix-5.2.h b/mit-pthreads/machdep/engine-ip22-irix-5.2.h
new file mode 100644
index 00000000000..94dd386608e
--- /dev/null
+++ b/mit-pthreads/machdep/engine-ip22-irix-5.2.h
@@ -0,0 +1,108 @@
+/* ==== machdep.h ============================================================
+ * Copyright (c) 1994 Chris Provenzano, proven@athena.mit.edu
+ *
+ * $Id$
+ *
+ */
+
+#include <unistd.h>
+#include <setjmp.h>
+#include <sys/time.h>
+#include <sys/cdefs.h>
+
+/*
+ * The first machine dependent functions are the SEMAPHORES
+ * needing the test and set instruction.
+ */
+#define SEMAPHORE_CLEAR 0
+#define SEMAPHORE_SET 0xff
+
+/*
+ * More machine dependent macros
+ */
+#ifdef PTHREAD_KERNEL
+
+#define machdep_save_float_state(x)
+#define machdep_restore_float_state()
+
+#endif
+
+/*
+ * New types
+ */
+typedef char semaphore;
+
+/*
+ * sigset_t macros
+ */
+#define SIGMAX 32
+#define SIG_ANY(sig) \
+({ \
+ sigset_t *sig_addr = (sigset_t *)&sig; \
+ int ret = 0; \
+ int i; \
+ \
+ for (i = 1; i <= SIGMAX; i++) { \
+ if (sigismember(sig_addr, i)) { \
+ ret = 1; \
+ break; \
+ } \
+ } \
+ ret; \
+})
+
+/*
+ * New Strutures
+ */
+struct machdep_pthread {
+ void *(*start_routine)(void *);
+ void *start_argument;
+ void *machdep_stack;
+ struct itimerval machdep_timer;
+ jmp_buf machdep_state;
+};
+
+/*
+ * Static machdep_pthread initialization values.
+ * For initial thread only.
+ */
+#define MACHDEP_PTHREAD_INIT \
+{ NULL, NULL, NULL, { { 0, 0 }, { 0, 100000 } }, 0 }
+
+/*
+ * Minimum stack size
+ */
+#define PTHREAD_STACK_MIN 1024
+
+/*
+ * Some fd flag defines that are necessary to distinguish between posix
+ * behavior and bsd4.3 behavior.
+ */
+#define __FD_NONBLOCK O_NONBLOCK
+
+/*
+ * New functions
+ */
+
+__BEGIN_DECLS
+
+#if defined(PTHREAD_KERNEL)
+
+#define __machdep_stack_get(x) (x)->machdep_stack
+#define __machdep_stack_set(x, y) (x)->machdep_stack = y
+#define __machdep_stack_repl(x, y) \
+{ \
+ if (stack = __machdep_stack_get(x)) { \
+ __machdep_stack_free(stack); \
+ } \
+ __machdep_stack_set(x, y); \
+}
+
+void * __machdep_stack_alloc __P_((size_t));
+void __machdep_stack_free __P_((void *));
+
+int machdep_save_state __P_((void));
+
+#endif
+
+__END_DECLS
diff --git a/mit-pthreads/machdep/engine-m68000-netbsd.c b/mit-pthreads/machdep/engine-m68000-netbsd.c
new file mode 100644
index 00000000000..6346c36ca7c
--- /dev/null
+++ b/mit-pthreads/machdep/engine-m68000-netbsd.c
@@ -0,0 +1,256 @@
+/* ==== machdep.c ============================================================
+ * Copyright (c) 1993, 1994 Chris Provenzano, proven@athena.mit.edu
+ *
+ * Copyright (c) 1993 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Description : Machine dependent functions for NetBSD on i386
+ *
+ * 1.00 93/08/04 proven
+ * -Started coding this file.
+ *
+ * m68k work from David Leonard <david.leonard@it.uq.edu.au>.
+ * updated and NetBSD/m68k work from Andy Finnell <andyf@vei.net>.
+ *
+ */
+
+#ifndef lint
+static const char rcsid[] = "$Id$";
+#endif
+
+#include "pthread.h"
+#include <sys/syscall.h>
+#include <sys/stat.h>
+
+/* ==========================================================================
+ * machdep_save_state()
+ */
+int machdep_save_state(void)
+{
+ return( _setjmp(pthread_run->machdep_data.machdep_state) );
+}
+
+/* ==========================================================================
+ * machdep_restore_state()
+ */
+void machdep_restore_state(void)
+{
+ _longjmp(pthread_run->machdep_data.machdep_state, 1);
+}
+
+/* ==========================================================================
+ * machdep_save_state()
+ */
+void machdep_save_float_state(struct pthread * pthread)
+{
+ char * fdata = pthread->machdep_data.machdep_fstate;
+
+ __asm__ ( "fmovem fp0-fp7,%0"::"m" (*fdata) );
+ __asm__ ( "fmovem fpcr/fpsr/fpi,%0"::"m" (fdata[80]) );
+}
+
+/* ==========================================================================
+ * machdep_restore_float_state()
+ */
+void machdep_restore_float_state(void)
+{
+ char * fdata = pthread_run->machdep_data.machdep_fstate;
+
+ __asm__ ( "fmovem %0,fp0-fp7"::"m" (*fdata) );
+ __asm__ ( "fmovem %0,fpcr/fpsr/fpi"::"m" (fdata[80]) );
+
+}
+
+/* ==========================================================================
+ * machdep_set_thread_timer()
+ */
+void machdep_set_thread_timer(struct machdep_pthread *machdep_pthread)
+{
+ if (setitimer(ITIMER_VIRTUAL, &(machdep_pthread->machdep_timer), NULL)) {
+ PANIC();
+ }
+}
+
+/* ==========================================================================
+ * machdep_unset_thread_timer()
+ */
+void machdep_unset_thread_timer(struct machdep_pthread *machdep_pthread)
+{
+ struct itimerval zeroval = { { 0, 0 }, { 0, 0 } };
+
+ if (setitimer(ITIMER_VIRTUAL, &zeroval, NULL)) {
+ PANIC();
+ }
+}
+
+/* ==========================================================================
+ * __machdep_stack_free()
+ */
+void __machdep_stack_free(void * stack)
+{
+ free(stack);
+}
+
+/* ==========================================================================
+ * __machdep_stack_alloc()
+ */
+void * __machdep_stack_alloc(size_t size)
+{
+ void * stack;
+
+ return((void*)malloc(size));
+}
+
+/* ==========================================================================
+ * machdep_pthread_cleanup()
+ */
+void *machdep_pthread_cleanup(struct machdep_pthread *machdep_pthread)
+{
+ return(machdep_pthread->machdep_stack);
+}
+
+/* ==========================================================================
+ * machdep_pthread_start()
+ */
+void machdep_pthread_start(void)
+{
+ context_switch_done();
+ pthread_sched_resume();
+
+ /* Run current thread's start routine with argument */
+ pthread_exit(
+ pthread_run->machdep_data.start_routine(
+ pthread_run->machdep_data.start_argument
+ )
+ );
+
+ /* should never reach here */
+ PANIC();
+}
+
+/* ==========================================================================
+ * __machdep_pthread_create()
+ */
+void __machdep_pthread_create(struct machdep_pthread *machdep_pthread,
+ void *(* start_routine)(), void *start_argument,
+ long stack_size, long nsec, long flags)
+{
+ machdep_pthread->start_routine = start_routine;
+ machdep_pthread->start_argument = start_argument;
+
+ machdep_pthread->machdep_timer.it_value.tv_sec = 0;
+ machdep_pthread->machdep_timer.it_interval.tv_sec = 0;
+ machdep_pthread->machdep_timer.it_interval.tv_usec = 0;
+ machdep_pthread->machdep_timer.it_value.tv_usec = nsec / 1000;
+
+ _setjmp(machdep_pthread->machdep_state);
+ /*
+ * Set up new stack frame so that it looks like it
+ * returned from a longjmp() to the beginning of
+ * machdep_pthread_start().
+ *
+ * state is the set_jmp structure, which for m68k is:
+ * long onstack_flag; // [0]
+ * long sigmask; // [1]
+ * long sp; // [2]
+ * long fp; // [3]
+ * long ap; // [4]
+ * long pc; // [5]
+ * long ps; // [6]
+ * long regs[10]; // non scratch registers
+ */
+ machdep_pthread->machdep_state[5] = (long)machdep_pthread_start;
+
+ /* Stack starts high and builds down. */
+ machdep_pthread->machdep_state[2] =
+ (int)machdep_pthread->machdep_stack + stack_size;
+}
+
+/* ==========================================================================
+ * machdep_sys_wait3()
+ */
+machdep_sys_wait3(int * b, int c, int * d)
+{
+ return(machdep_sys_wait4(0, b, c, d));
+}
+
+/* ==========================================================================
+ * machdep_sys_waitpid()
+ */
+machdep_sys_waitpid(int a, int * b, int c)
+{
+ return(machdep_sys_wait4(a, b, c, NULL));
+}
+
+/* ==========================================================================
+ * machdep_sys_getdtablesize()
+ */
+machdep_sys_getdtablesize()
+{
+ return(sysconf(_SC_OPEN_MAX));
+}
+
+/* ==========================================================================
+ * machdep_sys_getdirentries()
+ */
+machdep_sys_getdirentries(int fd, char * buf, int len, int * seek)
+{
+ return(machdep_sys_getdents(fd, buf, len));
+}
+
+/* ==========================================================================
+ * machdep_sys_lseek()
+ */
+off_t machdep_sys_lseek(int fd, off_t offset, int whence)
+{
+ extern off_t __syscall();
+
+ return(__syscall((quad_t)SYS_lseek, fd, 0, offset, whence));
+}
+
+int machdep_sys_ftruncate( int fd, off_t length)
+{
+ quad_t q;
+ int rv;
+
+ q = __syscall((quad_t)SYS_ftruncate, fd,0, length);
+ if( /* LINTED constant */ sizeof( quad_t ) == sizeof( register_t ) ||
+ /* LINTED constant */ BYTE_ORDER == LITTLE_ENDIAN )
+ rv = (int)q;
+ else
+ rv = (int)((u_quad_t)q >> 32);
+
+ return rv;
+}
+
+int machdep_sys_fstat( int f, struct stat* st )
+{
+ return __fstat13(f,st);
+}
diff --git a/mit-pthreads/machdep/engine-m68000-netbsd.h b/mit-pthreads/machdep/engine-m68000-netbsd.h
new file mode 100644
index 00000000000..ec3c6a01bce
--- /dev/null
+++ b/mit-pthreads/machdep/engine-m68000-netbsd.h
@@ -0,0 +1,107 @@
+/* ==== machdep.h ============================================================
+ * Copyright (c) 1993 Chris Provenzano, proven@athena.mit.edu
+ *
+ * $Id$
+ *
+ * m68k work by Andy Finnell <andyf@vei.net> based off work by
+ * David Leonard and Chris Provenzano.
+ *
+ */
+
+#include <unistd.h>
+#include <setjmp.h>
+#include <sys/time.h>
+
+/*
+ * The first machine dependent functions are the SEMAPHORES
+ * needing the test and set instruction.
+ */
+#define SEMAPHORE_CLEAR 0
+#define SEMAPHORE_SET 0x80;
+
+#define SEMAPHORE_TEST_AND_SET(lock) \
+({ \
+ volatile long temp = SEMAPHORE_CLEAR; \
+ __asm__ volatile( \
+ "tas %2; bpl 0f; movl #1,%0; 0:" \
+ :"=r" (temp) \
+ :"0" (temp),"m" (*lock)); \
+ temp; \
+})
+
+#define SEMAPHORE_RESET(lock) *lock = SEMAPHORE_CLEAR
+
+/*
+ * New types
+ */
+typedef char semaphore;
+
+/*
+ * sigset_t macros
+ */
+#define SIG_ANY(sig) (sig)
+#define SIGMAX 31
+
+/*
+ * New Strutures
+ */
+struct machdep_pthread {
+ void *(*start_routine)(void *);
+ void *start_argument;
+ void *machdep_stack;
+ struct itimerval machdep_timer;
+ jmp_buf machdep_state;
+ char machdep_fstate[92];
+};
+
+/*
+ * Min pthread stacksize
+ */
+#define PTHREAD_STACK_MIN 1024
+
+/*
+ * Some fd flag defines that are necessary to distinguish between posix
+ * behavior and bsd4.3 behavior.
+ */
+#define __FD_NONBLOCK O_NONBLOCK
+
+/*
+ * Static machdep_pthread initialization values.
+ * For initial thread only.
+ */
+#define MACHDEP_PTHREAD_INIT \
+{ NULL, NULL, NULL, { { 0, 0 }, { 0, 100000 } }, 0 }
+
+/*
+ * New functions
+ */
+
+__BEGIN_DECLS
+
+#if defined(PTHREAD_KERNEL)
+
+
+#ifndef __machdep_stack_get
+#define __machdep_stack_get(x) (x)->machdep_stack
+#endif
+#ifndef __machdep_stack_set
+#define __machdep_stack_set(x, y) (x)->machdep_stack = y
+#endif
+#ifndef __machdep_stack_repl
+#define __machdep_stack_repl(x, y) \
+{ \
+ if (stack = __machdep_stack_get(x)) { \
+ __machdep_stack_free(stack); \
+ } \
+ __machdep_stack_set(x, y); \
+}
+#endif
+
+void * __machdep_stack_alloc __P_((size_t));
+void __machdep_stack_free __P_((void *));
+
+int machdep_save_state __P_((void));
+
+#endif
+
+__END_DECLS
diff --git a/mit-pthreads/machdep/engine-r2000-ultrix-4.2.c b/mit-pthreads/machdep/engine-r2000-ultrix-4.2.c
new file mode 100644
index 00000000000..45c8cc73f24
--- /dev/null
+++ b/mit-pthreads/machdep/engine-r2000-ultrix-4.2.c
@@ -0,0 +1,209 @@
+/* ==== machdep.c ============================================================
+ * Copyright (c) 1993 Chris Provenzano, proven@athena.mit.edu
+ *
+ * Description : Machine dependent functions for decstation with r2000/r3000
+ *
+ * 1.00 93/07/21 proven
+ * -Started coding this file.
+ */
+
+#ifndef lint
+static const char rcsid[] = "$Id$";
+#endif
+
+#include <pthread.h>
+#include <stdlib.h>
+#include <errno.h>
+
+/*
+ * The r2000/r3000 processors do not have a test and set instruction, so
+ * the semaphore TEST_AND_SET macro is linked very closely to the interrupt
+ * handelling of the pthreads package.
+ */
+
+/* ==========================================================================
+ * semaphore_test_and_set()
+ *
+ * SEMAPHORE_TEST_AND_SET prevents interrupts, tests the lock and then
+ * turns interrupts back on, checking to see if any interrupts have occured
+ * between the prevent and resume.
+ */
+int semaphore_test_and_set(semaphore *lock)
+{
+ int rval;
+
+/* None of this should be necessary
+ sig_prevent();
+ if (!(rval = (*lock))) {
+ *lock = SEMAPHORE_SET;
+ }
+ sig_check_and_resume();
+ return(rval);
+*/
+}
+
+/* ==========================================================================
+ * machdep_save_state()
+ */
+int machdep_save_state(void)
+{
+ return(setjmp(pthread_run->machdep_data.machdep_state));
+}
+
+/* ==========================================================================
+ * machdep_save_float_state()
+ */
+void machdep_save_float_state(struct pthread * pthread)
+{
+ return;
+}
+
+/* ==========================================================================
+ * fake_longjmp()
+ */
+void fake_longjmp(jmp_buf env)
+{
+ asm("li $5,1; sw $5, 20($4); li $2,103; syscall");
+}
+
+/* ==========================================================================
+ * machdep_restore_state()
+ *
+ * When I redo machdep_save_state, I'll put the asm in machdep_save_state()
+ * and machdep_restore_state() and I won't have to do an additional function
+ * call.
+ */
+void machdep_restore_state(void)
+{
+ fake_longjmp(pthread_run->machdep_data.machdep_state);
+ /* longjmp(pthread_run->machdep_data.machdep_state, 1); */
+}
+
+/* ==========================================================================
+ * machdep_restore_float_state()
+ */
+void machdep_restore_float_state(void)
+{
+ return;
+}
+
+/* ==========================================================================
+ * machdep_set_thread_timer()
+ */
+void machdep_set_thread_timer(struct machdep_pthread *machdep_pthread)
+{
+ if (setitimer(ITIMER_VIRTUAL, &(machdep_pthread->machdep_timer), NULL)) {
+ PANIC();
+ }
+}
+
+/* ==========================================================================
+ * machdep_unset_thread_timer()
+ */
+void machdep_unset_thread_timer(struct machdep_pthread *machdep_pthread)
+{
+ struct itimerval zeroval = { { 0, 0 }, { 0, 0} };
+
+ if (setitimer(ITIMER_VIRTUAL, &zeroval, NULL)) {
+ PANIC();
+ }
+}
+
+/* ==========================================================================
+ * machdep_pthread_cleanup()
+ */
+void *machdep_pthread_cleanup(struct machdep_pthread *machdep_pthread)
+{
+ return(machdep_pthread->machdep_stack);
+}
+
+/* ==========================================================================
+ * machdep_pthread_start()
+ */
+void machdep_pthread_start(void)
+{
+ context_switch_done();
+ pthread_sched_resume();
+
+ /* Run current threads start routine with argument */
+ pthread_exit(pthread_run->machdep_data.start_routine
+ (pthread_run->machdep_data.start_argument));
+
+ /* should never reach here */
+ PANIC();
+}
+
+/* ==========================================================================
+ * __machdep_stack_free()
+ */
+void __machdep_stack_free(void * stack)
+{
+ free(stack);
+}
+
+/* ==========================================================================
+ * __machdep_stack_alloc()
+ */
+void * __machdep_stack_alloc(size_t size)
+{
+ void * stack;
+
+ return(malloc(size));
+}
+
+/* ==========================================================================
+ * __machdep_pthread_create()
+ */
+void __machdep_pthread_create(struct machdep_pthread *machdep_pthread,
+ void *(* start_routine)(), void *start_argument,
+ long stack_size, long nsec, long flags)
+{
+ machdep_pthread->start_routine = start_routine;
+ machdep_pthread->start_argument = start_argument;
+
+ machdep_pthread->machdep_timer.it_value.tv_sec = 0;
+ machdep_pthread->machdep_timer.it_interval.tv_sec = 0;
+ machdep_pthread->machdep_timer.it_interval.tv_usec = 0;
+ machdep_pthread->machdep_timer.it_value.tv_usec = nsec / 1000;
+
+ setjmp(machdep_pthread->machdep_state);
+ /*
+ * Set up new stact frame so that it looks like it
+ * returned from a longjmp() to the beginning of
+ * machdep_pthread_start().
+ */
+ machdep_pthread->machdep_state[JB_RA] = (int)machdep_pthread_start;
+ machdep_pthread->machdep_state[JB_PC] = (int)machdep_pthread_start;
+
+ /* Stack starts high and builds down. */
+ machdep_pthread->machdep_state[JB_SP] =
+ (int)machdep_pthread->machdep_stack + stack_size;
+
+ /* This is the real global pointer */
+ /* machdep_pthread->machdep_state[JB_GP] = 0; */
+}
+
+/* ==========================================================================
+ * machdep_sys_sigprocmask()
+ * This isn't a real implementation; we can make the assumption that the
+ * pthreads library is not using oset, and that it is always blocking or
+ * unblocking all signals at once.
+ */
+int machdep_sys_sigprocmask(int how, const sigset_t *set, sigset_t *oset)
+{
+ switch(how) {
+ case SIG_BLOCK:
+ sigblock(*set);
+ break;
+ case SIG_UNBLOCK:
+ sigsetmask(~*set);
+ break;
+ case SIG_SETMASK:
+ sigsetmask(*set);
+ break;
+ default:
+ return -EINVAL;
+ }
+ return(OK);
+}
+
diff --git a/mit-pthreads/machdep/engine-r2000-ultrix-4.2.h b/mit-pthreads/machdep/engine-r2000-ultrix-4.2.h
new file mode 100644
index 00000000000..8e2d70f8feb
--- /dev/null
+++ b/mit-pthreads/machdep/engine-r2000-ultrix-4.2.h
@@ -0,0 +1,107 @@
+/* ==== machdep.h ============================================================
+ * Copyright (c) 1993 Chris Provenzano, proven@athena.mit.edu
+ *
+ * $Id$
+ *
+ * Description : Machine dependent header for decstation with r2000/r3000
+ * running Ultrix-4.2
+ *
+ * 1.00 93/07/21 proven
+ * -Started coding this file.
+ */
+
+#include <setjmp.h>
+#include <sys/time.h>
+#include <sys/cdefs.h>
+
+/*
+ * The first machine dependent functions are the SEMAPHORES
+ * needing the test and set instruction.
+ */
+#define SEMAPHORE_CLEAR 0
+#define SEMAPHORE_SET 1
+
+#define SEMAPHORE_TEST_AND_SET(lock) semaphore_test_and_set(lock)
+#define SEMAPHORE_RESET(lock) *lock = SEMAPHORE_CLEAR
+
+/*
+ * New types
+ */
+typedef long semaphore;
+
+#if !defined(_POSIX_SOURCE)
+
+/* typedef int ssize_t; */
+
+#if !defined(__GNUC__)
+
+/*
+ * sigset_t macros
+ */
+typedef int sigset_t;
+#define sigaddset(set, num) ((*set) |= (1 << (num - 1)))
+#define sigemptyset(set) (*set = 0)
+
+#endif
+#endif
+
+#define SIG_ANY(sig) (sig)
+#define SIGMAX 31
+
+/*
+ * New Structures
+ */
+struct machdep_pthread {
+ void *(*start_routine)(void *);
+ void *start_argument;
+ void *machdep_stack;
+ struct itimerval machdep_timer;
+ jmp_buf machdep_state;
+};
+
+/*
+ * Static machdep_pthread initialization values.
+ * For initial thread only.
+ */
+#define MACHDEP_PTHREAD_INIT \
+{ NULL, NULL, NULL, { { 0, 0 }, { 0, 100000 } }, 0 }
+
+
+/*
+ * Min stacksize, arch dependent
+ */
+#define PTHREAD_STACK_MIN 1024
+
+/*
+ * Some fd flag defines that are necessary to distinguish between posix
+ * behavior and bsd4.3 behavior.
+ */
+#define __FD_NONBLOCK (O_NONBLOCK | O_NDELAY)
+
+/*
+ * New functions
+ */
+
+__BEGIN_DECLS
+
+#if defined(PTHREAD_KERNEL)
+
+#define __machdep_stack_get(x) (x)->machdep_stack
+#define __machdep_stack_set(x, y) (x)->machdep_stack = y
+#define __machdep_stack_repl(x, y) \
+{ \
+ if (stack = __machdep_stack_get(x)) { \
+ __machdep_stack_free(stack); \
+ } \
+ __machdep_stack_set(x, y); \
+}
+
+void * __machdep_stack_alloc __P_((size_t));
+void __machdep_stack_free __P_((void *));
+
+int semaphore_test_and_set __P_((semaphore *));
+int machdep_save_state __P_((void));
+
+#endif
+
+__END_DECLS
diff --git a/mit-pthreads/machdep/engine-romp-bsd.c b/mit-pthreads/machdep/engine-romp-bsd.c
new file mode 100644
index 00000000000..dd1a1096ece
--- /dev/null
+++ b/mit-pthreads/machdep/engine-romp-bsd.c
@@ -0,0 +1,99 @@
+/* ==== machdep.c ============================================================
+ * Copyright (c) 1993 Chris Provenzano, proven@athena.mit.edu
+ *
+ * Description : Machine dependent functions for NetBSD on i386
+ *
+ * 1.00 93/08/04 proven
+ * -Started coding this file.
+ */
+
+#ifndef lint
+static const char rcsid[] = "$Id$";
+#endif
+
+#include <pthread.h>
+
+/* ==========================================================================
+ * machdep_save_state()
+ */
+int machdep_save_state(void)
+{
+ return(_pthread_save(pthread_run->machdep_data.machdep_state, 0, 0));
+}
+
+/* ==========================================================================
+ * machdep_restore_state()
+ */
+void machdep_restore_state(void)
+{
+ _pthread_restore(pthread_run->machdep_data.machdep_state);
+}
+
+/* ==========================================================================
+ * machdep_set_thread_timer()
+ */
+void machdep_set_thread_timer(struct machdep_pthread *machdep_pthread)
+{
+ if (setitimer(ITIMER_VIRTUAL, &(machdep_pthread->machdep_timer), NULL)) {
+ PANIC();
+ }
+}
+
+/* ==========================================================================
+ * machdep_unset_thread_timer()
+ */
+void machdep_unset_thread_timer(struct machdep_pthread *machdep_pthread)
+{
+ struct itimerval zeroval = { { 0, 0 }, { 0, 0} };
+
+ if (setitimer(ITIMER_VIRTUAL, &zeroval, NULL)) {
+ PANIC();
+ }
+}
+
+/* ==========================================================================
+ * machdep_pthread_cleanup()
+ */
+void *machdep_pthread_cleanup(struct machdep_pthread *machdep_pthread)
+{
+ return(machdep_pthread->machdep_stack);
+}
+
+/* ==========================================================================
+ * machdep_pthread_start()
+ */
+void machdep_pthread_start(void)
+{
+ context_switch_done();
+ sig_check_and_resume();
+
+ /* Run current threads start routine with argument */
+ pthread_exit(pthread_run->machdep_data.start_routine
+ (pthread_run->machdep_data.start_argument));
+
+ /* should never reach here */
+ PANIC();
+}
+
+/* ==========================================================================
+ * machdep_pthread_create()
+ */
+void machdep_pthread_create(struct machdep_pthread *machdep_pthread,
+ void *(* start_routine)(), void *start_argument, long stack_size,
+ void *stack_start, long nsec)
+{
+ machdep_pthread->machdep_stack = stack_start;
+
+ machdep_pthread->start_routine = start_routine;
+ machdep_pthread->start_argument = start_argument;
+
+ machdep_pthread->machdep_timer.it_value.tv_sec = 0;
+ machdep_pthread->machdep_timer.it_interval.tv_sec = 0;
+ machdep_pthread->machdep_timer.it_interval.tv_usec = 0;
+ machdep_pthread->machdep_timer.it_value.tv_usec = nsec / 1000;
+
+ _pthread_save(machdep_pthread->machdep_state,
+ (void *)((int)machdep_pthread->machdep_stack + stack_size),
+ machdep_pthread_start);
+}
+
diff --git a/mit-pthreads/machdep/engine-romp-bsd.h b/mit-pthreads/machdep/engine-romp-bsd.h
new file mode 100644
index 00000000000..28c59d35e70
--- /dev/null
+++ b/mit-pthreads/machdep/engine-romp-bsd.h
@@ -0,0 +1,100 @@
+/* ==== machdep.h ============================================================
+ * Copyright (c) 1993 John F. Carr, jfc@athena.mit.edu
+ *
+ * Description : Machine dependent header for IBM/RT
+ *
+ * 1.00 93/09/xx jfc
+ * -Coding this file.
+ */
+
+#ifndef lint
+static const char rcsid[] = "$Id$";
+#endif
+
+#include <setjmp.h>
+#include <sys/time.h>
+#include <sys/types.h>
+
+/*
+ * Stuff for compiling
+ */
+#if defined(__GNUC__)
+#if defined(__cplusplus)
+#define __BEGIN_DECLS extern "C" {
+#define __END_DECLS };
+#else
+#define __BEGIN_DECLS
+#define __END_DECLS
+#if !defined(__STDC__)
+#define const __const
+#define inline __inline
+#define signed __signed
+#define volatile __volatile
+#endif
+#endif
+#else /* !__GNUC__ */
+#define __BEGIN_DECLS
+#define __END_DECLS
+#define const
+#define inline
+#define signed
+#define volatile
+#endif
+
+#define SEMAPHORE_CLEAR 0x0000
+#define SEMAPHORE_SET 0xff00
+#define SEMAPHORE_TEST_AND_SET(lock) _tsh(lock)
+#define SEMAPHORE_RESET(lock) *(lock) = SEMAPHORE_CLEAR
+extern unsigned short _tsh(volatile unsigned short *);
+
+typedef unsigned short semaphore;
+
+/*
+ * sigset_t macros
+ */
+#define SIG_ANY(sig) (sig)
+#define SIGMAX 31
+
+
+struct machdep_pthread {
+ void *(*start_routine)(void *);
+ void *start_argument;
+ void *machdep_stack;
+ struct itimerval machdep_timer;
+ jmp_buf machdep_state;
+};
+
+/*
+ * Static machdep_pthread initialization values.
+ * For initial thread only.
+ */
+#define MACHDEP_PTHREAD_INIT \
+{ NULL, NULL, NULL, { { 0, 0 }, { 0, 100000 } }, 0 }
+
+/*
+ * Min pthread stacksize
+ */
+#define PTHREAD_STACK_MIN 1024
+
+/*
+ * Some fd defines that are necessary to distinguish between posix
+ * behavior and bsd4.3 behavior.
+ */
+#define __FD_NONBLOCK O_NONBLOCK
+
+#if defined(PTHREAD_KERNEL)
+
+int machdep_save_state __P_((void));
+
+/* save(jmp_buf, stack pointer, restart proc) */
+extern int _pthread_save(jmp_buf, void *, void (*)());
+extern void _pthread_restore(jmp_buf);
+
+typedef int ssize_t;
+typedef unsigned int sigset_t;
+#define sigemptyset(sp) *(sp) = 0
+#define sigprocmask(op, nssp, ossp) if (ossp) *(int *)ossp = sigsetmask(*nssp); else sigsetmask(*nssp)
+#define sigdelset(sp, i) *(sp) &= ~(1 << (i))
+#define sigaddset(sp, i) *(sp) |= (1 << (i))
+#define sigismember(sp, i) (*(sp) & (1 << (i)))
+#endif
diff --git a/mit-pthreads/machdep/engine-sparc-netbsd-1.3.c b/mit-pthreads/machdep/engine-sparc-netbsd-1.3.c
new file mode 100644
index 00000000000..8e0520cfba5
--- /dev/null
+++ b/mit-pthreads/machdep/engine-sparc-netbsd-1.3.c
@@ -0,0 +1,232 @@
+/* ==== machdep.c ============================================================
+ * Copyright (c) 1993, 1994 Chris Provenzano, proven@athena.mit.edu
+ *
+ * Description : Machine dependent functions for SunOS-4.1.3 on sparc
+ *
+ * 1.00 93/08/04 proven
+ * -Started coding this file.
+ *
+ * 98/10/22 bad
+ * -update for fat sigset_t in NetBSD 1.3H
+ */
+
+#ifndef lint
+static const char rcsid[] = "$Id$";
+#endif
+
+#include "config.h"
+#include <pthread.h>
+#include <stdlib.h>
+#include <errno.h>
+
+/* ==========================================================================
+ * machdep_save_state()
+ */
+int machdep_save_state(void)
+{
+ /* Save register windows onto stackframe */
+ __asm__ ("ta 3");
+
+ return(setjmp(pthread_run->machdep_data.machdep_state));
+}
+
+/* ==========================================================================
+ * machdep_restore_state()
+ */
+void machdep_restore_state(void)
+{
+ longjmp(pthread_run->machdep_data.machdep_state, 1);
+}
+/* ==========================================================================
+ * machdep_save_float_state()
+ */
+void machdep_save_float_state(struct pthread * pthread)
+{
+ return;
+}
+
+/* ==========================================================================
+ * machdep_restore_float_state()
+ */
+void machdep_restore_float_state(void)
+{
+ return;
+}
+
+/* ==========================================================================
+ * machdep_set_thread_timer()
+ */
+void machdep_set_thread_timer(struct machdep_pthread *machdep_pthread)
+{
+ if (setitimer(ITIMER_VIRTUAL, &(machdep_pthread->machdep_timer), NULL)) {
+ PANIC();
+ }
+}
+
+/* ==========================================================================
+ * machdep_unset_thread_timer()
+ */
+void machdep_unset_thread_timer(struct machdep_pthread *machdep_pthread)
+{
+ struct itimerval zeroval = { { 0, 0 }, { 0, 0} };
+
+ if (setitimer(ITIMER_VIRTUAL, &zeroval, NULL)) {
+ PANIC();
+ }
+}
+
+/* ==========================================================================
+ * machdep_pthread_cleanup()
+ */
+void *machdep_pthread_cleanup(struct machdep_pthread *machdep_pthread)
+{
+ return(machdep_pthread->machdep_stack);
+}
+
+/* ==========================================================================
+ * machdep_pthread_start()
+ */
+void machdep_pthread_start(void)
+{
+ context_switch_done();
+ pthread_sched_resume ();
+
+ /* Run current threads start routine with argument */
+ pthread_exit(pthread_run->machdep_data.start_routine
+ (pthread_run->machdep_data.start_argument));
+
+ /* should never reach here */
+ PANIC();
+}
+
+/* ==========================================================================
+ * __machdep_stack_free()
+ */
+void __machdep_stack_free(void * stack)
+{
+ free(stack);
+}
+
+/* ==========================================================================
+ * __machdep_stack_alloc()
+ */
+void * __machdep_stack_alloc(size_t size)
+{
+ void * stack;
+
+ return(malloc(size));
+}
+
+/* ==========================================================================
+ * __machdep_pthread_create()
+ */
+void __machdep_pthread_create(struct machdep_pthread *machdep_pthread,
+ void *(* start_routine)(), void *start_argument,
+ long stack_size, long nsec, long flags)
+{
+ machdep_pthread->start_routine = start_routine;
+ machdep_pthread->start_argument = start_argument;
+
+ machdep_pthread->machdep_timer.it_value.tv_sec = 0;
+ machdep_pthread->machdep_timer.it_interval.tv_sec = 0;
+ machdep_pthread->machdep_timer.it_interval.tv_usec = 0;
+ machdep_pthread->machdep_timer.it_value.tv_usec = nsec / 1000;
+
+ /* Save register windows onto stackframe */
+ __asm__ ("ta 3");
+
+ setjmp(machdep_pthread->machdep_state);
+ /*
+ * Set up new stact frame so that it looks like it
+ * returned from a longjmp() to the beginning of
+ * machdep_pthread_start().
+ */
+ machdep_pthread->machdep_state[3] = (int)machdep_pthread_start;
+ machdep_pthread->machdep_state[4] = (int)machdep_pthread_start;
+
+ /* Sparc stack starts high and builds down. */
+ machdep_pthread->machdep_state[2] =
+ (int)machdep_pthread->machdep_stack + stack_size - 1024;
+ machdep_pthread->machdep_state[2] &= ~7;
+
+}
+
+#if defined(HAVE_SYSCALL_GETDENTS)
+/* ==========================================================================
+ * machdep_sys_getdirentries()
+ *
+ * Always use getdents in place of getdirentries if possible --proven
+ */
+int machdep_sys_getdirentries(int fd, char * buf, int len, int * seek)
+{
+ return(machdep_sys_getdents(fd, buf, len));
+}
+#endif
+
+/* ==========================================================================
+ * machdep_sys_wait3()
+ */
+machdep_sys_wait3(int * b, int c, int * d)
+{
+ return(machdep_sys_wait4(0, b, c, d));
+}
+
+/* ==========================================================================
+ * machdep_sys_waitpid()
+ */
+machdep_sys_waitpid(int pid, int * statusp, int options)
+{
+ if (pid == -1)
+ pid = 0;
+ else if (pid == 0)
+ pid = - getpgrp ();
+ return machdep_sys_wait4 (pid, statusp, options, NULL);
+}
+
+#if !defined(HAVE_SYSCALL_SIGPROCMASK)
+#if 0
+/* ==========================================================================
+ * machdep_sys_sigprocmask()
+ * This isn't a real implementation; we can make the assumption that the
+ * pthreads library is not using oset, and that it is always blocking or
+ * unblocking all signals at once.
+ */
+int machdep_sys_sigprocmask(int how, const sigset_t *set, sigset_t *oset)
+{
+ switch(how) {
+ case SIG_BLOCK:
+ sigblock(*set);
+ break;
+ case SIG_UNBLOCK:
+ sigsetmask(~*set);
+ break;
+ case SIG_SETMASK:
+ sigsetmask(*set);
+ break;
+ default:
+ return -EINVAL;
+ }
+ return(OK);
+}
+
+/* ==========================================================================
+ * sigaction()
+ *
+ * Temporary until I do machdep_sys_sigaction()
+ */
+int sigaction(int sig, const struct sigaction *act, struct sigaction *oldact)
+{
+ return(sigvec(sig, (struct sigvec *)act, (struct sigvec *)oldact));
+}
+#endif
+#endif
+
+#if !defined(HAVE_SYSCALL_GETDTABLESIZE)
+/* ==========================================================================
+ * machdep_sys_getdtablesize()
+ */
+machdep_sys_getdtablesize()
+{
+ return(sysconf(_SC_OPEN_MAX));
+}
+#endif
diff --git a/mit-pthreads/machdep/engine-sparc-netbsd-1.3.h b/mit-pthreads/machdep/engine-sparc-netbsd-1.3.h
new file mode 100644
index 00000000000..a187d3dace8
--- /dev/null
+++ b/mit-pthreads/machdep/engine-sparc-netbsd-1.3.h
@@ -0,0 +1,106 @@
+/* ==== machdep.h ============================================================
+ * Copyright (c) 1994 Chris Provenzano, proven@athena.mit.edu
+ *
+ * engine-sparc-sunos-4.1.3.h,v 1.52.4.1 1995/12/13 05:42:33 proven Exp
+ *
+ */
+
+#include <unistd.h>
+#include <setjmp.h>
+#include <sys/time.h>
+#include <sys/cdefs.h>
+#include <sys/signal.h> /* for _NSIG */
+
+/*
+ * The first machine dependent functions are the SEMAPHORES
+ * needing the test and set instruction.
+ */
+#define SEMAPHORE_CLEAR 0
+#define SEMAPHORE_SET 0xff
+
+#define SEMAPHORE_TEST_AND_SET(lock) \
+({ \
+char *p = lock; \
+long temp; \
+ \
+__asm__ volatile("ldstub %1,%0" \
+ :"=r" (temp) \
+ :"m" (*p) \
+ :"memory"); \
+temp; \
+})
+
+#define SEMAPHORE_RESET(lock) \
+{ \
+__asm__ volatile("stb %1, %0" \
+ :"=m" (*lock) \
+ :"r" (SEMAPHORE_CLEAR) \
+ :"memory"); \
+}
+
+/*
+ * New types
+ */
+typedef char semaphore;
+
+/*
+ * sigset_t macros
+ */
+#define SIG_ANY(sig) (sig)
+#define SIGMAX (_NSIG-1)
+
+/*
+ * New Strutures
+ */
+struct machdep_pthread {
+ void *(*start_routine)(void *);
+ void *start_argument;
+ void *machdep_stack;
+ struct itimerval machdep_timer;
+ jmp_buf machdep_state;
+};
+
+/*
+ * Static machdep_pthread initialization values.
+ * For initial thread only.
+ */
+#define MACHDEP_PTHREAD_INIT \
+{ NULL, NULL, NULL, { { 0, 0 }, { 0, 100000 } }, 0 }
+
+/*
+ * Minimum stack size
+ */
+#define PTHREAD_STACK_MIN 1024
+
+/*
+ * Some fd flag defines that are necessary to distinguish between posix
+ * behavior and bsd4.3 behavior.
+ */
+#define __FD_NONBLOCK (O_NONBLOCK | O_NDELAY)
+
+/*
+ * New functions
+ */
+
+__BEGIN_DECLS
+
+#if defined(PTHREAD_KERNEL)
+
+#define __machdep_stack_get(x) (x)->machdep_stack
+#define __machdep_stack_set(x, y) (x)->machdep_stack = y
+#define __machdep_stack_repl(x, y) \
+{ \
+ if (stack = __machdep_stack_get(x)) { \
+ __machdep_stack_free(stack); \
+ } \
+ __machdep_stack_set(x, y); \
+}
+
+void * __machdep_stack_alloc __P_((size_t));
+void __machdep_stack_free __P_((void *));
+
+int machdep_save_state __P_((void));
+
+#endif
+
+__END_DECLS
diff --git a/mit-pthreads/machdep/engine-sparc-sunos-4.1.3.c b/mit-pthreads/machdep/engine-sparc-sunos-4.1.3.c
new file mode 100644
index 00000000000..6916c3610cd
--- /dev/null
+++ b/mit-pthreads/machdep/engine-sparc-sunos-4.1.3.c
@@ -0,0 +1,227 @@
+/* ==== machdep.c ============================================================
+ * Copyright (c) 1993, 1994 Chris Provenzano, proven@athena.mit.edu
+ *
+ * Description : Machine dependent functions for SunOS-4.1.3 on sparc
+ *
+ * 1.00 93/08/04 proven
+ * -Started coding this file.
+ */
+
+#ifndef lint
+static const char rcsid[] = "$Id$";
+#endif
+
+#include "config.h"
+#include <pthread.h>
+#include <stdlib.h>
+#include <errno.h>
+
+/* ==========================================================================
+ * machdep_save_state()
+ */
+int machdep_save_state(void)
+{
+ /* Save register windows onto stackframe */
+ __asm__ ("ta 3");
+
+ return(setjmp(pthread_run->machdep_data.machdep_state));
+}
+
+/* ==========================================================================
+ * machdep_restore_state()
+ */
+void machdep_restore_state(void)
+{
+ longjmp(pthread_run->machdep_data.machdep_state, 1);
+}
+/* ==========================================================================
+ * machdep_save_float_state()
+ */
+void machdep_save_float_state(struct pthread * pthread)
+{
+ return;
+}
+
+/* ==========================================================================
+ * machdep_restore_float_state()
+ */
+void machdep_restore_float_state(void)
+{
+ return;
+}
+
+/* ==========================================================================
+ * machdep_set_thread_timer()
+ */
+void machdep_set_thread_timer(struct machdep_pthread *machdep_pthread)
+{
+ if (setitimer(ITIMER_VIRTUAL, &(machdep_pthread->machdep_timer), NULL)) {
+ PANIC();
+ }
+}
+
+/* ==========================================================================
+ * machdep_unset_thread_timer()
+ */
+void machdep_unset_thread_timer(struct machdep_pthread *machdep_pthread)
+{
+ struct itimerval zeroval = { { 0, 0 }, { 0, 0} };
+
+ if (setitimer(ITIMER_VIRTUAL, &zeroval, NULL)) {
+ PANIC();
+ }
+}
+
+/* ==========================================================================
+ * machdep_pthread_cleanup()
+ */
+void *machdep_pthread_cleanup(struct machdep_pthread *machdep_pthread)
+{
+ return(machdep_pthread->machdep_stack);
+}
+
+/* ==========================================================================
+ * machdep_pthread_start()
+ */
+void machdep_pthread_start(void)
+{
+ context_switch_done();
+ pthread_sched_resume ();
+
+ /* Run current threads start routine with argument */
+ pthread_exit(pthread_run->machdep_data.start_routine
+ (pthread_run->machdep_data.start_argument));
+
+ /* should never reach here */
+ PANIC();
+}
+
+/* ==========================================================================
+ * __machdep_stack_free()
+ */
+void __machdep_stack_free(void * stack)
+{
+ free(stack);
+}
+
+/* ==========================================================================
+ * __machdep_stack_alloc()
+ */
+void * __machdep_stack_alloc(size_t size)
+{
+ void * stack;
+
+ return(malloc(size));
+}
+
+/* ==========================================================================
+ * __machdep_pthread_create()
+ */
+void __machdep_pthread_create(struct machdep_pthread *machdep_pthread,
+ void *(* start_routine)(), void *start_argument,
+ long stack_size, long nsec, long flags)
+{
+ machdep_pthread->start_routine = start_routine;
+ machdep_pthread->start_argument = start_argument;
+
+ machdep_pthread->machdep_timer.it_value.tv_sec = 0;
+ machdep_pthread->machdep_timer.it_interval.tv_sec = 0;
+ machdep_pthread->machdep_timer.it_interval.tv_usec = 0;
+ machdep_pthread->machdep_timer.it_value.tv_usec = nsec / 1000;
+
+ /* Save register windows onto stackframe */
+ __asm__ ("ta 3");
+
+ setjmp(machdep_pthread->machdep_state);
+ /*
+ * Set up new stact frame so that it looks like it
+ * returned from a longjmp() to the beginning of
+ * machdep_pthread_start().
+ */
+ machdep_pthread->machdep_state[3] = (int)machdep_pthread_start;
+ machdep_pthread->machdep_state[4] = (int)machdep_pthread_start;
+
+ /* Sparc stack starts high and builds down. */
+ machdep_pthread->machdep_state[2] =
+ (int)machdep_pthread->machdep_stack + stack_size - 1024;
+ machdep_pthread->machdep_state[2] &= ~7;
+
+}
+
+#if defined(HAVE_SYSCALL_GETDENTS)
+/* ==========================================================================
+ * machdep_sys_getdirentries()
+ *
+ * Always use getdents in place of getdirentries if possible --proven
+ */
+int machdep_sys_getdirentries(int fd, char * buf, int len, int * seek)
+{
+ return(machdep_sys_getdents(fd, buf, len));
+}
+#endif
+
+/* ==========================================================================
+ * machdep_sys_wait3()
+ */
+machdep_sys_wait3(int * b, int c, int * d)
+{
+ return(machdep_sys_wait4(0, b, c, d));
+}
+
+/* ==========================================================================
+ * machdep_sys_waitpid()
+ */
+machdep_sys_waitpid(int pid, int * statusp, int options)
+{
+ if (pid == -1)
+ pid = 0;
+ else if (pid == 0)
+ pid = - getpgrp ();
+ return machdep_sys_wait4 (pid, statusp, options, NULL);
+}
+
+#if !defined(HAVE_SYSCALL_SIGPROCMASK)
+/* ==========================================================================
+ * machdep_sys_sigprocmask()
+ * This isn't a real implementation; we can make the assumption that the
+ * pthreads library is not using oset, and that it is always blocking or
+ * unblocking all signals at once.
+ */
+int machdep_sys_sigprocmask(int how, const sigset_t *set, sigset_t *oset)
+{
+ switch(how) {
+ case SIG_BLOCK:
+ sigblock(*set);
+ break;
+ case SIG_UNBLOCK:
+ sigsetmask(~*set);
+ break;
+ case SIG_SETMASK:
+ sigsetmask(*set);
+ break;
+ default:
+ return -EINVAL;
+ }
+ return(OK);
+}
+
+/* ==========================================================================
+ * sigaction()
+ *
+ * Temporary until I do machdep_sys_sigaction()
+ */
+int sigaction(int sig, const struct sigaction *act, struct sigaction *oldact)
+{
+ return(sigvec(sig, (struct sigvec *)act, (struct sigvec *)oldact));
+}
+#endif
+
+#if !defined(HAVE_SYSCALL_GETDTABLESIZE)
+/* ==========================================================================
+ * machdep_sys_getdtablesize()
+ */
+machdep_sys_getdtablesize()
+{
+ return(sysconf(_SC_OPEN_MAX));
+}
+#endif
diff --git a/mit-pthreads/machdep/engine-sparc-sunos-4.1.3.h b/mit-pthreads/machdep/engine-sparc-sunos-4.1.3.h
new file mode 100644
index 00000000000..1a4a8768ad0
--- /dev/null
+++ b/mit-pthreads/machdep/engine-sparc-sunos-4.1.3.h
@@ -0,0 +1,105 @@
+/* ==== machdep.h ============================================================
+ * Copyright (c) 1994 Chris Provenzano, proven@athena.mit.edu
+ *
+ * $Id$
+ *
+ */
+
+#include <unistd.h>
+#include <setjmp.h>
+#include <sys/time.h>
+#include <sys/cdefs.h>
+
+/*
+ * The first machine dependent functions are the SEMAPHORES
+ * needing the test and set instruction.
+ */
+#define SEMAPHORE_CLEAR 0
+#define SEMAPHORE_SET 0xff
+
+#define SEMAPHORE_TEST_AND_SET(lock) \
+({ \
+char *p = lock; \
+long temp; \
+ \
+__asm__ volatile("ldstub %1,%0" \
+ :"=r" (temp) \
+ :"m" (*p) \
+ :"memory"); \
+temp; \
+})
+
+#define SEMAPHORE_RESET(lock) \
+{ \
+__asm__ volatile("stb %1, %0" \
+ :"=m" (*lock) \
+ :"r" (SEMAPHORE_CLEAR) \
+ :"memory"); \
+}
+
+/*
+ * New types
+ */
+typedef char semaphore;
+
+/*
+ * sigset_t macros
+ */
+#define SIG_ANY(sig) (sig)
+#define SIGMAX 31
+
+/*
+ * New Strutures
+ */
+struct machdep_pthread {
+ void *(*start_routine)(void *);
+ void *start_argument;
+ void *machdep_stack;
+ struct itimerval machdep_timer;
+ jmp_buf machdep_state;
+};
+
+/*
+ * Static machdep_pthread initialization values.
+ * For initial thread only.
+ */
+#define MACHDEP_PTHREAD_INIT \
+{ NULL, NULL, NULL, { { 0, 0 }, { 0, 100000 } }, 0 }
+
+/*
+ * Minimum stack size
+ */
+#define PTHREAD_STACK_MIN 1024
+
+/*
+ * Some fd flag defines that are necessary to distinguish between posix
+ * behavior and bsd4.3 behavior.
+ */
+#define __FD_NONBLOCK (O_NONBLOCK | O_NDELAY)
+
+/*
+ * New functions
+ */
+
+__BEGIN_DECLS
+
+#if defined(PTHREAD_KERNEL)
+
+#define __machdep_stack_get(x) (x)->machdep_stack
+#define __machdep_stack_set(x, y) (x)->machdep_stack = y
+#define __machdep_stack_repl(x, y) \
+{ \
+ if (stack = __machdep_stack_get(x)) { \
+ __machdep_stack_free(stack); \
+ } \
+ __machdep_stack_set(x, y); \
+}
+
+void * __machdep_stack_alloc __P_((size_t));
+void __machdep_stack_free __P_((void *));
+
+int machdep_save_state __P_((void));
+
+#endif
+
+__END_DECLS
diff --git a/mit-pthreads/machdep/engine-sparc-sunos-5.3.c b/mit-pthreads/machdep/engine-sparc-sunos-5.3.c
new file mode 100644
index 00000000000..a228a408da3
--- /dev/null
+++ b/mit-pthreads/machdep/engine-sparc-sunos-5.3.c
@@ -0,0 +1,308 @@
+/* ==== machdep.c ============================================================
+ * Copyright (c) 1993, 1994 Chris Provenzano, proven@athena.mit.edu
+ *
+ * Description : Machine dependent functions for SunOS-4.1.3 on sparc
+ *
+ * 1.00 93/08/04 proven
+ * -Started coding this file.
+ */
+
+#ifndef lint
+static const char rcsid[] = "$Id$";
+#endif
+
+#include <pthread.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <sys/procset.h>
+#include <sys/systeminfo.h>
+#include <poll.h>
+
+/* ==========================================================================
+ * machdep_save_state()
+ */
+int machdep_save_state(void)
+{
+ /* Save register windows onto stackframe */
+ __asm__ ("ta 3");
+
+ return(setjmp(pthread_run->machdep_data.machdep_state));
+}
+
+/* ==========================================================================
+ * machdep_restore_state()
+ */
+void machdep_restore_state(void)
+{
+ longjmp(pthread_run->machdep_data.machdep_state, 1);
+}
+
+/* ==========================================================================
+ * machdep_set_thread_timer()
+ */
+void machdep_set_thread_timer(struct machdep_pthread *machdep_pthread)
+{
+ if (setitimer(ITIMER_VIRTUAL, &(machdep_pthread->machdep_timer), NULL)) {
+ PANIC();
+ }
+}
+
+/* ==========================================================================
+ * machdep_unset_thread_timer()
+ */
+void machdep_unset_thread_timer(struct machdep_pthread *machdep_pthread)
+{
+ struct itimerval zeroval = { { 0, 0 }, { 0, 0} };
+
+ if (setitimer(ITIMER_VIRTUAL, &zeroval, NULL)) {
+ PANIC();
+ }
+}
+
+/* ==========================================================================
+ * machdep_pthread_cleanup()
+ */
+void *machdep_pthread_cleanup(struct machdep_pthread *machdep_pthread)
+{
+ return(machdep_pthread->machdep_stack);
+}
+
+/* ==========================================================================
+ * machdep_pthread_start()
+ */
+void machdep_pthread_start(void)
+{
+ context_switch_done();
+ pthread_sched_resume();
+
+ /* Run current threads start routine with argument */
+ pthread_exit(pthread_run->machdep_data.start_routine
+ (pthread_run->machdep_data.start_argument));
+
+ /* should never reach here */
+ PANIC();
+}
+
+/* ==========================================================================
+ * __machdep_stack_free()
+ */
+void __machdep_stack_free(void * stack)
+{
+ free(stack);
+}
+
+/* ==========================================================================
+ * __machdep_stack_alloc()
+ */
+void * __machdep_stack_alloc(size_t size)
+{
+ void * stack;
+
+ return(malloc(size));
+}
+
+/* ==========================================================================
+ * machdep_pthread_create()
+ */
+void __machdep_pthread_create(struct machdep_pthread *machdep_pthread,
+ void *(* start_routine)(), void *start_argument,
+ long stack_size, long nsec, long flags)
+{
+ machdep_pthread->start_routine = start_routine;
+ machdep_pthread->start_argument = start_argument;
+
+ machdep_pthread->machdep_timer.it_value.tv_sec = 0;
+ machdep_pthread->machdep_timer.it_interval.tv_sec = 0;
+ machdep_pthread->machdep_timer.it_interval.tv_usec = 0;
+ machdep_pthread->machdep_timer.it_value.tv_usec = nsec / 1000;
+
+ /* Save register windows onto stackframe */
+ __asm__ ("ta 3");
+
+ if (setjmp(machdep_pthread->machdep_state)) {
+ machdep_pthread_start();
+ }
+
+ /*
+ * Set up new stact frame so that it looks like it
+ * returned from a longjmp() to the beginning of
+ * machdep_pthread_start().
+ */
+
+ /* Sparc stack starts high and builds down. */
+ machdep_pthread->machdep_state[1] =
+ (int)machdep_pthread->machdep_stack + stack_size - 1024;
+ machdep_pthread->machdep_state[1] &= ~7;
+
+}
+
+/* ==========================================================================
+ * machdep_sys_getdirentries()
+ */
+int machdep_sys_getdirentries(int fd, char * buf, int len, int * seek)
+{
+ return(machdep_sys_getdents(fd, buf, len));
+}
+
+/* ==========================================================================
+ * machdep_sys_wait3()
+ */
+machdep_sys_wait3(int * b, int c, int * d)
+{
+ return(-ENOSYS);
+ /* return(machdep_sys_wait4(0, b, c, d)); */
+}
+
+/* ==========================================================================
+ * machdep_sys_waitpid()
+ */
+machdep_sys_waitpid(int a, int * b, int c)
+{
+ idtype_t id;
+
+ switch (a) {
+ case -1:
+ id = P_ALL;
+ break;
+ case 0:
+ a = machdep_sys_pgrpsys(0);
+ id = P_PGID;
+ break;
+ default:
+ if (a < 0) {
+ id = P_PGID;
+ a = -a;
+ } else {
+ id = P_PID;
+ }
+ break;
+ }
+
+ return(machdep_sys_waitsys(id, a, b, c));
+}
+
+/* ==========================================================================
+ * machdep_sys_dup2()
+ */
+machdep_sys_dup2(int a, int b)
+{
+ machdep_sys_close(b);
+ machdep_sys_fcntl(a, F_DUPFD, b);
+}
+
+/* ==========================================================================
+ * machdep_sys_ftruncate()
+ */
+machdep_sys_ftruncate(int a, off_t b)
+{
+ flock_t c;
+
+ c.l_len = 0;
+ c.l_start = b;
+ c.l_whence = 0;
+ return(machdep_sys_fcntl(a, F_FREESP, c));
+}
+
+/* ==========================================================================
+ * machdep_sys_select()
+ * Recoded to be quicker by Monty
+ */
+static fd_set bogus_fds; /* Always zero, never changed */
+
+machdep_sys_select(int nfds, fd_set *readfds, fd_set *writefds,
+ fd_set *exceptfds, struct timeval *timeout)
+{
+ struct pollfd fds[64],*ptr;
+ int i, fds_count, time_out, found;
+
+ /* Make sure each arg has a valid pointer */
+ if ((readfds == NULL) || (writefds == NULL) || (exceptfds == NULL)) {
+ if (exceptfds == NULL) {
+ exceptfds = &bogus_fds;
+ }
+ if (writefds == NULL) {
+ writefds = &bogus_fds;
+ }
+ if (readfds == NULL) {
+ readfds = &bogus_fds;
+ }
+ }
+
+ ptr=fds;
+ for (i = 0 ; i < nfds; i++)
+ {
+ if (FD_ISSET(i, readfds))
+ {
+ if (FD_ISSET(i, writefds))
+ ptr->events= POLLIN | POLLOUT;
+ else
+ ptr->events= POLLIN;
+ (ptr++)->fd=i;
+ }
+ else if (FD_ISSET(i, writefds))
+ {
+ ptr->events=POLLOUT;
+ (ptr++)->fd=i;
+ }
+ }
+ FD_ZERO(readfds);
+ FD_ZERO(writefds);
+ FD_ZERO(exceptfds);
+ time_out = timeout->tv_usec / 1000 + timeout->tv_sec * 1000;
+ fds_count=(int) (ptr-fds);
+ while ((found = machdep_sys_poll(fds, fds_count, time_out)) <= 0)
+ {
+ if (found != -ERESTART) /* Try again if restartable */
+ return(found); /* Usually 0 ; Cant read or write */
+ }
+
+ while (ptr-- != fds)
+ {
+ if (ptr->revents & POLLIN)
+ FD_SET(ptr->fd, readfds);
+ if (ptr->revents & POLLOUT)
+ FD_SET(ptr->fd,writefds);
+ }
+ return(found);
+}
+
+/* ==========================================================================
+ * machdep_sys_getdtablesize()
+ */
+machdep_sys_getdtablesize()
+{
+ return(sysconf(_SC_OPEN_MAX));
+}
+
+/* ==========================================================================
+ * getpagesize()
+ */
+getpagesize()
+{
+ return(sysconf(_SC_PAGESIZE));
+}
+
+/* ==========================================================================
+ * gethostname()
+ */
+int gethostname(char * name, int namelen)
+{
+ if (sysinfo(SI_HOSTNAME, name, namelen) == NOTOK) {
+ return(NOTOK);
+ } else {
+ return(OK);
+ }
+}
+
+/* ==========================================================================
+ * machdep_sys_sigaction()
+ *
+ * This is VERY temporary.
+ */
+int machdep_sys_sigaction(int a, void * b, void * c)
+{
+ return(sigaction(a, b, c));
+}
diff --git a/mit-pthreads/machdep/engine-sparc-sunos-5.3.h b/mit-pthreads/machdep/engine-sparc-sunos-5.3.h
new file mode 100644
index 00000000000..365ecd799eb
--- /dev/null
+++ b/mit-pthreads/machdep/engine-sparc-sunos-5.3.h
@@ -0,0 +1,129 @@
+/* ==== machdep.h ============================================================
+ * Copyright (c) 1994 Chris Provenzano, proven@athena.mit.edu
+ *
+ * $Id$
+ *
+ */
+
+#include <unistd.h>
+#include <setjmp.h>
+#include <sys/time.h>
+#include <sys/cdefs.h>
+
+/*
+ * The first machine dependent functions are the SEMAPHORES
+ * needing the test and set instruction.
+ */
+#define SEMAPHORE_CLEAR 0
+#define SEMAPHORE_SET 0xff
+
+#define SEMAPHORE_TEST_AND_SET(lock) \
+({ \
+char *p = lock; \
+long temp; \
+ \
+__asm__ volatile("ldstub %1,%0" \
+ :"=r" (temp) \
+ :"m" (*p) \
+ :"memory"); \
+temp; \
+})
+
+#define SEMAPHORE_RESET(lock) \
+{ \
+__asm__ volatile("stb %1, %0" \
+ :"=m" (*lock) \
+ :"r" (SEMAPHORE_CLEAR) \
+ :"memory"); \
+}
+
+/*
+ * More machine dependent macros
+ */
+#ifdef PTHREAD_KERNEL
+
+#define machdep_save_float_state(x)
+#define machdep_restore_float_state()
+
+#endif
+
+/*
+ * New types
+ */
+typedef char semaphore;
+
+/*
+ * sigset_t macros
+ */
+#define SIGMAX 31
+#define SIG_ANY(sig) \
+({ \
+ sigset_t *sig_addr = (sigset_t *)&sig; \
+ int ret = 0; \
+ int i; \
+ \
+ for (i = 1; i <= SIGMAX; i++) { \
+ if (sigismember(sig_addr, i)) { \
+ ret = 1; \
+ break; \
+ } \
+ } \
+ ret; \
+})
+
+/*
+ * New Strutures
+ */
+struct machdep_pthread {
+ void *(*start_routine)(void *);
+ void *start_argument;
+ void *machdep_stack;
+ struct itimerval machdep_timer;
+ jmp_buf machdep_state;
+};
+
+/*
+ * Static machdep_pthread initialization values.
+ * For initial thread only.
+ */
+#define MACHDEP_PTHREAD_INIT \
+{ NULL, NULL, NULL, { { 0, 0 }, { 0, 100000 } }, 0 }
+
+/*
+ * Minimum stack size
+ */
+#undef PTHREAD_STACK_MIN /* Defined in limits.h */
+#define PTHREAD_STACK_MIN 1024
+
+/*
+ * Some fd flag defines that are necessary to distinguish between posix
+ * behavior and bsd4.3 behavior.
+ */
+#define __FD_NONBLOCK (O_NONBLOCK | O_NDELAY)
+
+/*
+ * New functions
+ */
+
+__BEGIN_DECLS
+
+#if defined(PTHREAD_KERNEL)
+
+#define __machdep_stack_get(x) (x)->machdep_stack
+#define __machdep_stack_set(x, y) (x)->machdep_stack = y
+#define __machdep_stack_repl(x, y) \
+{ \
+ if (stack = __machdep_stack_get(x)) { \
+ __machdep_stack_free(stack); \
+ } \
+ __machdep_stack_set(x, y); \
+}
+
+void * __machdep_stack_alloc __P_((size_t));
+void __machdep_stack_free __P_((void *));
+
+int machdep_save_state __P_((void));
+
+#endif
+
+__END_DECLS
diff --git a/mit-pthreads/machdep/freebsd-1.1/compat.h b/mit-pthreads/machdep/freebsd-1.1/compat.h
new file mode 100755
index 00000000000..e7de318aa88
--- /dev/null
+++ b/mit-pthreads/machdep/freebsd-1.1/compat.h
@@ -0,0 +1,43 @@
+/* ==== compat.h ============================================================
+ * Copyright (c) 1994 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ *
+ * Description : COmpat header to make socket code compile.
+ *
+ * 1.00 94/08/01 proven
+ * -Started coding this file.
+ */
+
+#ifndef _SYS_COMPAT_H_
+#define _SYS_COMPAT_H_
+
+#endif
diff --git a/mit-pthreads/machdep/freebsd-1.1/dirent.h b/mit-pthreads/machdep/freebsd-1.1/dirent.h
new file mode 100755
index 00000000000..5226443f86b
--- /dev/null
+++ b/mit-pthreads/machdep/freebsd-1.1/dirent.h
@@ -0,0 +1,64 @@
+/*-
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)dirent.h 5.18 (Berkeley) 2/23/91
+ */
+
+#ifndef _SYS_DIRENT_H_
+#define _SYS_DIRENT_H_
+
+/*
+ * A directory entry has a struct dirent at the front of it, containing its
+ * inode number, the length of the entry, and the length of the name
+ * contained in the entry. These are followed by the name padded to a 4
+ * byte boundary with null bytes. All names are guaranteed null terminated.
+ * The maximum length of a name in a directory is MAXNAMLEN.
+ */
+
+struct dirent {
+ u_long d_fileno; /* file number of entry */
+ u_short d_reclen; /* length of this record */
+ u_short d_namlen; /* length of string in d_name */
+#ifdef _POSIX_SOURCE
+ char d_name[255 + 1]; /* name must be no longer than this */
+#else
+#define MAXNAMLEN 255
+ char d_name[MAXNAMLEN + 1]; /* name must be no longer than this */
+#endif
+};
+
+#define d_ino d_fileno /* backward compatibility */
+
+/* definitions for library routines operating on directories. */
+#define DIRBLKSIZ 1024
+
+#endif /* !_DIRENT_H_ */
diff --git a/mit-pthreads/machdep/freebsd-1.1/socket.h b/mit-pthreads/machdep/freebsd-1.1/socket.h
new file mode 100755
index 00000000000..f13d01e7fe5
--- /dev/null
+++ b/mit-pthreads/machdep/freebsd-1.1/socket.h
@@ -0,0 +1,267 @@
+/*
+ * Copyright (c) 1982,1985,1986,1988 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)socket.h 7.13 (Berkeley) 4/20/91
+ * $Id$
+ */
+
+#ifndef _SYS_SOCKET_H_
+#define _SYS_SOCKET_H_ 1
+
+/*
+ * Definitions related to sockets: types, address families, options.
+ */
+
+/*
+ * Types
+ */
+#define SOCK_STREAM 1 /* stream socket */
+#define SOCK_DGRAM 2 /* datagram socket */
+#define SOCK_RAW 3 /* raw-protocol interface */
+#define SOCK_RDM 4 /* reliably-delivered message */
+#define SOCK_SEQPACKET 5 /* sequenced packet stream */
+
+/*
+ * Option flags per-socket.
+ */
+#define SO_DEBUG 0x0001 /* turn on debugging info recording */
+#define SO_ACCEPTCONN 0x0002 /* socket has had listen() */
+#define SO_REUSEADDR 0x0004 /* allow local address reuse */
+#define SO_KEEPALIVE 0x0008 /* keep connections alive */
+#define SO_DONTROUTE 0x0010 /* just use interface addresses */
+#define SO_BROADCAST 0x0020 /* permit sending of broadcast msgs */
+#define SO_USELOOPBACK 0x0040 /* bypass hardware when possible */
+#define SO_LINGER 0x0080 /* linger on close if data present */
+#define SO_OOBINLINE 0x0100 /* leave received OOB data in line */
+
+/*
+ * Additional options, not kept in so_options.
+ */
+#define SO_SNDBUF 0x1001 /* send buffer size */
+#define SO_RCVBUF 0x1002 /* receive buffer size */
+#define SO_SNDLOWAT 0x1003 /* send low-water mark */
+#define SO_RCVLOWAT 0x1004 /* receive low-water mark */
+#define SO_SNDTIMEO 0x1005 /* send timeout */
+#define SO_RCVTIMEO 0x1006 /* receive timeout */
+#define SO_ERROR 0x1007 /* get error status and clear */
+#define SO_TYPE 0x1008 /* get socket type */
+
+/*
+ * Structure used for manipulating linger option.
+ */
+struct linger {
+ int l_onoff; /* option on/off */
+ int l_linger; /* linger time */
+};
+
+/*
+ * Level number for (get/set)sockopt() to apply to socket itself.
+ */
+#define SOL_SOCKET 0xffff /* options for socket level */
+
+/*
+ * Address families.
+ */
+#define AF_UNSPEC 0 /* unspecified */
+#define AF_UNIX 1 /* local to host (pipes, portals) */
+#define AF_INET 2 /* internetwork: UDP, TCP, etc. */
+#define AF_IMPLINK 3 /* arpanet imp addresses */
+#define AF_PUP 4 /* pup protocols: e.g. BSP */
+#define AF_CHAOS 5 /* mit CHAOS protocols */
+#define AF_NS 6 /* XEROX NS protocols */
+#define AF_ISO 7 /* ISO protocols */
+#define AF_OSI AF_ISO
+#define AF_ECMA 8 /* european computer manufacturers */
+#define AF_DATAKIT 9 /* datakit protocols */
+#define AF_CCITT 10 /* CCITT protocols, X.25 etc */
+#define AF_SNA 11 /* IBM SNA */
+#define AF_DECnet 12 /* DECnet */
+#define AF_DLI 13 /* DEC Direct data link interface */
+#define AF_LAT 14 /* LAT */
+#define AF_HYLINK 15 /* NSC Hyperchannel */
+#define AF_APPLETALK 16 /* Apple Talk */
+#define AF_ROUTE 17 /* Internal Routing Protocol */
+#define AF_LINK 18 /* Link layer interface */
+#define pseudo_AF_XTP 19 /* eXpress Transfer Protocol (no AF) */
+#define AF_RMP 20 /* HP's Remote Maint Protocol */
+#define AF_MAX 21
+
+/*
+ * Structure used by kernel to store most
+ * addresses.
+ */
+struct sockaddr {
+ u_char sa_len; /* total length */
+ u_char sa_family; /* address family */
+ char sa_data[14]; /* actually longer; address value */
+};
+
+/*
+ * Structure used by kernel to pass protocol
+ * information in raw sockets.
+ */
+struct sockproto {
+ u_short sp_family; /* address family */
+ u_short sp_protocol; /* protocol */
+};
+
+/*
+ * Protocol families, same as address families for now.
+ */
+#define PF_UNSPEC AF_UNSPEC
+#define PF_UNIX AF_UNIX
+#define PF_INET AF_INET
+#define PF_IMPLINK AF_IMPLINK
+#define PF_PUP AF_PUP
+#define PF_CHAOS AF_CHAOS
+#define PF_NS AF_NS
+#define PF_ISO AF_ISO
+#define PF_OSI AF_ISO
+#define PF_ECMA AF_ECMA
+#define PF_DATAKIT AF_DATAKIT
+#define PF_CCITT AF_CCITT
+#define PF_SNA AF_SNA
+#define PF_DECnet AF_DECnet
+#define PF_DLI AF_DLI
+#define PF_LAT AF_LAT
+#define PF_HYLINK AF_HYLINK
+#define PF_APPLETALK AF_APPLETALK
+#define PF_ROUTE AF_ROUTE
+#define PF_LINK AF_LINK
+#define PF_XTP pseudo_AF_XTP /* really just proto family, no AF */
+#define PF_RMP AF_RMP
+
+#define PF_MAX AF_MAX
+
+/*
+ * Maximum queue length specifiable by listen.
+ */
+#define SOMAXCONN 5
+
+/*
+ * Message header for recvmsg and sendmsg calls.
+ * Used value-result for recvmsg, value only for sendmsg.
+ */
+struct msghdr {
+ caddr_t msg_name; /* optional address */
+ u_int msg_namelen; /* size of address */
+ struct iovec *msg_iov; /* scatter/gather array */
+ u_int msg_iovlen; /* # elements in msg_iov */
+ caddr_t msg_control; /* ancillary data, see below */
+ u_int msg_controllen; /* ancillary data buffer len */
+ int msg_flags; /* flags on received message */
+};
+
+#define MSG_OOB 0x1 /* process out-of-band data */
+#define MSG_PEEK 0x2 /* peek at incoming message */
+#define MSG_DONTROUTE 0x4 /* send without using routing tables */
+#define MSG_EOR 0x8 /* data completes record */
+#define MSG_TRUNC 0x10 /* data discarded before delivery */
+#define MSG_CTRUNC 0x20 /* control data lost before delivery */
+#define MSG_WAITALL 0x40 /* wait for full request or error */
+
+/*
+ * Header for ancillary data objects in msg_control buffer.
+ * Used for additional information with/about a datagram
+ * not expressible by flags. The format is a sequence
+ * of message elements headed by cmsghdr structures.
+ */
+struct cmsghdr {
+ u_int cmsg_len; /* data byte count, including hdr */
+ int cmsg_level; /* originating protocol */
+ int cmsg_type; /* protocol-specific type */
+/* followed by u_char cmsg_data[]; */
+};
+
+/* given pointer to struct adatahdr, return pointer to data */
+#define CMSG_DATA(cmsg) ((u_char *)((cmsg) + 1))
+
+/* given pointer to struct adatahdr, return pointer to next adatahdr */
+#define CMSG_NXTHDR(mhdr, cmsg) \
+ (((caddr_t)(cmsg) + (cmsg)->cmsg_len + sizeof(struct cmsghdr) > \
+ (mhdr)->msg_control + (mhdr)->msg_controllen) ? \
+ (struct cmsghdr *)NULL : \
+ (struct cmsghdr *)((caddr_t)(cmsg) + ALIGN((cmsg)->cmsg_len)))
+
+#define CMSG_FIRSTHDR(mhdr) ((struct cmsghdr *)(mhdr)->msg_control)
+
+/* "Socket"-level control message types: */
+#define SCM_RIGHTS 0x01 /* access rights (array of int) */
+
+/*
+ * 4.3 compat sockaddr, move to compat file later
+ */
+struct osockaddr {
+ u_short sa_family; /* address family */
+ char sa_data[14]; /* up to 14 bytes of direct address */
+};
+
+/*
+ * 4.3-compat message header (move to compat file later).
+ */
+struct omsghdr {
+ caddr_t msg_name; /* optional address */
+ int msg_namelen; /* size of address */
+ struct iovec *msg_iov; /* scatter/gather array */
+ int msg_iovlen; /* # elements in msg_iov */
+ caddr_t msg_accrights; /* access rights sent/received */
+ int msg_accrightslen;
+};
+
+#ifndef KERNEL
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+int accept __P_((int, struct sockaddr *, int *));
+int bind __P_((int, const struct sockaddr *, int));
+int connect __P_((int, const struct sockaddr *, int));
+int getpeername __P_((int, struct sockaddr *, int *));
+int getsockname __P_((int, struct sockaddr *, int *));
+int getsockopt __P_((int, int, int, void *, int *));
+int listen __P_((int, int));
+ssize_t recv __P_((int, void *, size_t, int));
+ssize_t recvfrom __P_((int, void *, size_t, int,
+ struct sockaddr *, int *));
+int recvmsg __P_((int, struct msghdr *, int));
+ssize_t send __P_((int, const void *, size_t, int));
+ssize_t sendto __P_((int, const void *, size_t, int,
+ const struct sockaddr *, int));
+int sendmsg __P_((int, const struct msghdr *, int));
+int setsockopt __P_((int, int, int, const void *, int));
+int shutdown __P_((int, int));
+int socket __P_((int, int, int));
+int socketpair __P_((int, int, int, int *));
+__END_DECLS
+
+#endif /* !KERNEL */
+#endif /* _SYS_SOCKET_H_ */
diff --git a/mit-pthreads/machdep/freebsd-1.1/timers.h b/mit-pthreads/machdep/freebsd-1.1/timers.h
new file mode 100755
index 00000000000..3c4d057976a
--- /dev/null
+++ b/mit-pthreads/machdep/freebsd-1.1/timers.h
@@ -0,0 +1,68 @@
+/* ==== timers.h ============================================================
+ * Copyright (c) 1994 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ *
+ * Description : Basic timers header.
+ *
+ * 1.00 94/06/13 proven
+ * -Started coding this file.
+ */
+
+#ifndef _SYS_TIMERS_H_
+#define _SYS_TIMERS_H_
+
+#include <sys/types.h>
+#include <time.h>
+
+struct timespec {
+ time_t tv_sec;
+ long tv_nsec;
+};
+
+#define TIMEVAL_TO_TIMESPEC(tv, ts) { \
+ (ts)->tv_sec = (tv)->tv_sec; \
+ (ts)->tv_nsec = (tv)->tv_usec * 1000; \
+}
+#define TIMESPEC_TO_TIMEVAL(tv, ts) { \
+ (tv)->tv_sec = (ts)->tv_sec; \
+ (tv)->tv_usec = (ts)->tv_nsec / 1000; \
+}
+
+/*
+ * New functions
+ */
+
+__BEGIN_DECLS
+
+__END_DECLS
+
+#endif
diff --git a/mit-pthreads/machdep/freebsd-2.0/__math.h b/mit-pthreads/machdep/freebsd-2.0/__math.h
new file mode 100755
index 00000000000..27ed0f2575d
--- /dev/null
+++ b/mit-pthreads/machdep/freebsd-2.0/__math.h
@@ -0,0 +1,6 @@
+/*
+ * ANSI/POSIX
+ */
+extern char __infinity[];
+#define HUGE_VAL (*(double *) __infinity)
+
diff --git a/mit-pthreads/machdep/freebsd-2.0/__path.h b/mit-pthreads/machdep/freebsd-2.0/__path.h
new file mode 100755
index 00000000000..432494daafa
--- /dev/null
+++ b/mit-pthreads/machdep/freebsd-2.0/__path.h
@@ -0,0 +1,14 @@
+/*
+ * from: @(#)time.h 5.12 (Berkeley) 3/9/91
+ * $Id$
+ */
+
+#ifndef _SYS__PATH_H_
+#define _SYS__PATH_H_
+
+#define _PATH_PTY "/dev/"
+#define _PATH_TZDIR "/usr/share/zoneinfo"
+#define _PATH_TZFILE "/etc/localtime"
+
+#endif /* !_SYS__PATH_H_ */
+
diff --git a/mit-pthreads/machdep/freebsd-2.0/__signal.h b/mit-pthreads/machdep/freebsd-2.0/__signal.h
new file mode 100755
index 00000000000..918955c9948
--- /dev/null
+++ b/mit-pthreads/machdep/freebsd-2.0/__signal.h
@@ -0,0 +1,8 @@
+#include <sys/signal.h>
+
+#define __SIGEMPTYSET 0
+#define __SIGFILLSET 0xffffffff
+#define __SIGADDSET(s, n) (*(s) |= 1 << ((n) - 1), 0)
+#define __SIGDELSET(s, n) (*(s) &= ~(1 << ((n) - 1)), 0)
+#define __SIGISMEMBER(s, n) ((*(s) & (1 << ((n) - 1))) != 0)
+
diff --git a/mit-pthreads/machdep/freebsd-2.0/__stdio.h b/mit-pthreads/machdep/freebsd-2.0/__stdio.h
new file mode 100755
index 00000000000..d60b9df7a54
--- /dev/null
+++ b/mit-pthreads/machdep/freebsd-2.0/__stdio.h
@@ -0,0 +1,8 @@
+
+#include <machine/ansi.h>
+#ifdef _BSD_SIZE_T_
+typedef _BSD_SIZE_T_ size_t;
+#undef _BSD_SIZE_T_
+#endif
+
+typedef pthread_fpos_t fpos_t; /* Must match off_t <sys/types.h> */
diff --git a/mit-pthreads/machdep/freebsd-2.0/__stdlib.h b/mit-pthreads/machdep/freebsd-2.0/__stdlib.h
new file mode 100755
index 00000000000..5ee2b8ed3d9
--- /dev/null
+++ b/mit-pthreads/machdep/freebsd-2.0/__stdlib.h
@@ -0,0 +1,66 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)stdlib.h 5.13 (Berkeley) 6/4/91
+ * $Id$
+ */
+
+#ifndef _SYS___STDLIB_H_
+#define _SYS___STDLIB_H_
+
+#include <machine/ansi.h>
+
+#ifdef _BSD_SIZE_T_
+typedef _BSD_SIZE_T_ size_t;
+#undef _BSD_SIZE_T_
+#endif
+
+#ifdef _BSD_WCHAR_T_
+typedef _BSD_WCHAR_T_ wchar_t;
+#ifdef _BSD_RUNE_T_
+typedef _BSD_RUNE_T_ rune_t;
+#undef _BSD_RUNE_T_
+#else
+typedef _BSD_WCHAR_T_ rune_t;
+#endif
+#undef _BSD_WCHAR_T_
+#endif
+
+#ifndef __NORETURN
+#define __NORETURN
+#endif
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#endif /* _STDLIB_H_ */
diff --git a/mit-pthreads/machdep/freebsd-2.0/__string.h b/mit-pthreads/machdep/freebsd-2.0/__string.h
new file mode 100755
index 00000000000..93d4fcf9dd2
--- /dev/null
+++ b/mit-pthreads/machdep/freebsd-2.0/__string.h
@@ -0,0 +1,21 @@
+
+#include <machine/ansi.h>
+#ifdef _BSD_SIZE_T_
+typedef _BSD_SIZE_T_ size_t;
+#undef _BSD_SIZE_T_
+#endif
+
+/* Non-standard NetBSD string routines. */
+#if !defined(_ANSI_SOURCE) && !defined(_POSIX_SOURCE)
+__BEGIN_DECLS
+int bcmp __P_((const void *, const void *, size_t));
+void bcopy __P_((const void *, void *, size_t));
+void bzero __P_((void *, size_t));
+char *index __P_((const char *, int));
+char *rindex __P_((const char *, int));
+char *strdup __P_((const char *));
+void strmode __P_((int, char *));
+char *strsep __P_((char **, const char *));
+__END_DECLS
+#endif
+
diff --git a/mit-pthreads/machdep/freebsd-2.0/__time.h b/mit-pthreads/machdep/freebsd-2.0/__time.h
new file mode 100755
index 00000000000..5c4b722bc3c
--- /dev/null
+++ b/mit-pthreads/machdep/freebsd-2.0/__time.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * (c) UNIX System Laboratories, Inc.
+ * All or some portions of this file are derived from material licensed
+ * to the University of California by American Telephone and Telegraph
+ * Co. or Unix System Laboratories, Inc. and are reproduced herein with
+ * the permission of UNIX System Laboratories, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)time.h 5.12 (Berkeley) 3/9/91
+ * $Id$
+ */
+
+#ifndef _SYS__TIME_H_
+#define _SYS__TIME_H_
+
+#include <machine/ansi.h>
+#include <machine/limits.h>
+
+#ifdef _BSD_CLOCK_T_
+typedef _BSD_CLOCK_T_ clock_t;
+#undef _BSD_CLOCK_T_
+#endif
+
+#ifdef _BSD_TIME_T_
+typedef _BSD_TIME_T_ time_t;
+#undef _BSD_TIME_T_
+#endif
+
+#ifdef _BSD_SIZE_T_
+typedef _BSD_SIZE_T_ size_t;
+#undef _BSD_SIZE_T_
+#endif
+
+#define CLOCKS_PER_SEC 100
+
+#if !defined(CLK_TCK)
+#define CLK_TCK 100
+#endif /* not CLK_TCK */
+
+#endif /* !_SYS__TIME_H_ */
diff --git a/mit-pthreads/machdep/freebsd-2.0/__unistd.h b/mit-pthreads/machdep/freebsd-2.0/__unistd.h
new file mode 100755
index 00000000000..ed5b0657727
--- /dev/null
+++ b/mit-pthreads/machdep/freebsd-2.0/__unistd.h
@@ -0,0 +1,113 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)stdlib.h 5.13 (Berkeley) 6/4/91
+ * $Id$
+ */
+
+#ifndef _SYS___UNISTD_H_
+#define _SYS___UNISTD_H_
+
+#include <sys/types.h>
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#define ioctl_request_type unsigned long /* For fd.c */
+
+/* compile-time symbolic constants */
+#define _POSIX_JOB_CONTROL /* implementation supports job control */
+
+#ifdef _NOT_AVAILABLE
+#define _POSIX_SAVED_IDS /* saved set-user-ID and set-group-ID */
+#endif
+
+#ifndef _POSIX_VERSION
+#define _POSIX_VERSION 198808L
+#endif
+#ifndef _POSIX2_VERSION
+#define _POSIX2_VERSION 199212L
+#endif
+
+/* execution-time symbolic constants */
+ /* chown requires appropriate privileges */
+#define _POSIX_CHOWN_RESTRICTED 1
+ /* too-long path components generate errors */
+#define _POSIX_NO_TRUNC 1
+ /* may disable terminal special characters */
+#define _POSIX_VDISABLE 0xff
+
+/* configurable pathname variables */
+#define _PC_LINK_MAX 1
+#define _PC_MAX_CANON 2
+#define _PC_MAX_INPUT 3
+#define _PC_NAME_MAX 4
+#define _PC_PATH_MAX 5
+#define _PC_PIPE_BUF 6
+#define _PC_CHOWN_RESTRICTED 7
+#define _PC_NO_TRUNC 8
+#define _PC_VDISABLE 9
+
+/* configurable system variables */
+#define _SC_ARG_MAX 1
+#define _SC_CHILD_MAX 2
+#define _SC_CLK_TCK 3
+#define _SC_NGROUPS_MAX 4
+#define _SC_OPEN_MAX 5
+#define _SC_JOB_CONTROL 6
+#define _SC_SAVED_IDS 7
+#define _SC_VERSION 8
+#define _SC_BC_BASE_MAX 9
+#define _SC_BC_DIM_MAX 10
+#define _SC_BC_SCALE_MAX 11
+#define _SC_BC_STRING_MAX 12
+#define _SC_COLL_WEIGHTS_MAX 13
+#define _SC_EXPR_NEST_MAX 14
+#define _SC_LINE_MAX 15
+#define _SC_RE_DUP_MAX 16
+#define _SC_2_VERSION 17
+#define _SC_2_C_BIND 18
+#define _SC_2_C_DEV 19
+#define _SC_2_CHAR_TERM 20
+#define _SC_2_FORT_DEV 21
+#define _SC_2_FORT_RUN 22
+#define _SC_2_LOCALEDEF 23
+#define _SC_2_SW_DEV 24
+#define _SC_2_UPE 25
+#define _SC_STREAM_MAX 26
+#define _SC_TZNAME_MAX 27
+
+/* configurable system strings */
+#define _CS_PATH 1
+
+#endif
diff --git a/mit-pthreads/machdep/freebsd-2.0/compat.h b/mit-pthreads/machdep/freebsd-2.0/compat.h
new file mode 100755
index 00000000000..e7de318aa88
--- /dev/null
+++ b/mit-pthreads/machdep/freebsd-2.0/compat.h
@@ -0,0 +1,43 @@
+/* ==== compat.h ============================================================
+ * Copyright (c) 1994 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ *
+ * Description : COmpat header to make socket code compile.
+ *
+ * 1.00 94/08/01 proven
+ * -Started coding this file.
+ */
+
+#ifndef _SYS_COMPAT_H_
+#define _SYS_COMPAT_H_
+
+#endif
diff --git a/mit-pthreads/machdep/freebsd-2.0/dirent.h b/mit-pthreads/machdep/freebsd-2.0/dirent.h
new file mode 100755
index 00000000000..5226443f86b
--- /dev/null
+++ b/mit-pthreads/machdep/freebsd-2.0/dirent.h
@@ -0,0 +1,64 @@
+/*-
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)dirent.h 5.18 (Berkeley) 2/23/91
+ */
+
+#ifndef _SYS_DIRENT_H_
+#define _SYS_DIRENT_H_
+
+/*
+ * A directory entry has a struct dirent at the front of it, containing its
+ * inode number, the length of the entry, and the length of the name
+ * contained in the entry. These are followed by the name padded to a 4
+ * byte boundary with null bytes. All names are guaranteed null terminated.
+ * The maximum length of a name in a directory is MAXNAMLEN.
+ */
+
+struct dirent {
+ u_long d_fileno; /* file number of entry */
+ u_short d_reclen; /* length of this record */
+ u_short d_namlen; /* length of string in d_name */
+#ifdef _POSIX_SOURCE
+ char d_name[255 + 1]; /* name must be no longer than this */
+#else
+#define MAXNAMLEN 255
+ char d_name[MAXNAMLEN + 1]; /* name must be no longer than this */
+#endif
+};
+
+#define d_ino d_fileno /* backward compatibility */
+
+/* definitions for library routines operating on directories. */
+#define DIRBLKSIZ 1024
+
+#endif /* !_DIRENT_H_ */
diff --git a/mit-pthreads/machdep/freebsd-2.0/errno.h b/mit-pthreads/machdep/freebsd-2.0/errno.h
new file mode 100755
index 00000000000..3da61d692a3
--- /dev/null
+++ b/mit-pthreads/machdep/freebsd-2.0/errno.h
@@ -0,0 +1,160 @@
+/* $NetBSD: errno.h,v 1.8 1994/06/29 06:44:02 cgd Exp $ */
+
+/*
+ * Copyright (c) 1982, 1986, 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ * (c) UNIX System Laboratories, Inc.
+ * All or some portions of this file are derived from material licensed
+ * to the University of California by American Telephone and Telegraph
+ * Co. or Unix System Laboratories, Inc. and are reproduced herein with
+ * the permission of UNIX System Laboratories, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)errno.h 8.5 (Berkeley) 1/21/94
+ */
+
+#ifndef _SYS_ERRNO_H_
+#define _SYS_ERRNO_H_
+
+#define EPERM 1 /* Operation not permitted */
+#define ENOENT 2 /* No such file or directory */
+#define ESRCH 3 /* No such process */
+#define EINTR 4 /* Interrupted system call */
+#define EIO 5 /* Input/output error */
+#define ENXIO 6 /* Device not configured */
+#define E2BIG 7 /* Argument list too long */
+#define ENOEXEC 8 /* Exec format error */
+#define EBADF 9 /* Bad file descriptor */
+#define ECHILD 10 /* No child processes */
+#define EDEADLK 11 /* Resource deadlock avoided */
+ /* 11 was EAGAIN */
+#define ENOMEM 12 /* Cannot allocate memory */
+#define EACCES 13 /* Permission denied */
+#define EFAULT 14 /* Bad address */
+#ifndef _POSIX_SOURCE
+#define ENOTBLK 15 /* Block device required */
+#endif
+#define EBUSY 16 /* Device busy */
+#define EEXIST 17 /* File exists */
+#define EXDEV 18 /* Cross-device link */
+#define ENODEV 19 /* Operation not supported by device */
+#define ENOTDIR 20 /* Not a directory */
+#define EISDIR 21 /* Is a directory */
+#define EINVAL 22 /* Invalid argument */
+#define ENFILE 23 /* Too many open files in system */
+#define EMFILE 24 /* Too many open files */
+#define ENOTTY 25 /* Inappropriate ioctl for device */
+#ifndef _POSIX_SOURCE
+#define ETXTBSY 26 /* Text file busy */
+#endif
+#define EFBIG 27 /* File too large */
+#define ENOSPC 28 /* No space left on device */
+#define ESPIPE 29 /* Illegal seek */
+#define EROFS 30 /* Read-only file system */
+#define EMLINK 31 /* Too many links */
+#define EPIPE 32 /* Broken pipe */
+
+/* math software */
+#define EDOM 33 /* Numerical argument out of domain */
+#define ERANGE 34 /* Result too large */
+
+/* non-blocking and interrupt i/o */
+#define EAGAIN 35 /* Resource temporarily unavailable */
+#ifndef _POSIX_SOURCE
+#define EWOULDBLOCK EAGAIN /* Operation would block */
+#define EINPROGRESS 36 /* Operation now in progress */
+#define EALREADY 37 /* Operation already in progress */
+
+/* ipc/network software -- argument errors */
+#define ENOTSOCK 38 /* Socket operation on non-socket */
+#define EDESTADDRREQ 39 /* Destination address required */
+#define EMSGSIZE 40 /* Message too long */
+#define EPROTOTYPE 41 /* Protocol wrong type for socket */
+#define ENOPROTOOPT 42 /* Protocol not available */
+#define EPROTONOSUPPORT 43 /* Protocol not supported */
+#define ESOCKTNOSUPPORT 44 /* Socket type not supported */
+#define EOPNOTSUPP 45 /* Operation not supported */
+#define EPFNOSUPPORT 46 /* Protocol family not supported */
+#define EAFNOSUPPORT 47 /* Address family not supported by protocol family */
+#define EADDRINUSE 48 /* Address already in use */
+#define EADDRNOTAVAIL 49 /* Can't assign requested address */
+
+/* ipc/network software -- operational errors */
+#define ENETDOWN 50 /* Network is down */
+#define ENETUNREACH 51 /* Network is unreachable */
+#define ENETRESET 52 /* Network dropped connection on reset */
+#define ECONNABORTED 53 /* Software caused connection abort */
+#define ECONNRESET 54 /* Connection reset by peer */
+#define ENOBUFS 55 /* No buffer space available */
+#define EISCONN 56 /* Socket is already connected */
+#define ENOTCONN 57 /* Socket is not connected */
+#define ESHUTDOWN 58 /* Can't send after socket shutdown */
+#define ETOOMANYREFS 59 /* Too many references: can't splice */
+#define ETIMEDOUT 60 /* Operation timed out */
+#define ECONNREFUSED 61 /* Connection refused */
+
+#define ELOOP 62 /* Too many levels of symbolic links */
+#endif /* _POSIX_SOURCE */
+#define ENAMETOOLONG 63 /* File name too long */
+
+/* should be rearranged */
+#ifndef _POSIX_SOURCE
+#define EHOSTDOWN 64 /* Host is down */
+#define EHOSTUNREACH 65 /* No route to host */
+#endif /* _POSIX_SOURCE */
+#define ENOTEMPTY 66 /* Directory not empty */
+
+/* quotas & mush */
+#ifndef _POSIX_SOURCE
+#define EPROCLIM 67 /* Too many processes */
+#define EUSERS 68 /* Too many users */
+#define EDQUOT 69 /* Disc quota exceeded */
+
+/* Network File System */
+#define ESTALE 70 /* Stale NFS file handle */
+#define EREMOTE 71 /* Too many levels of remote in path */
+#define EBADRPC 72 /* RPC struct is bad */
+#define ERPCMISMATCH 73 /* RPC version wrong */
+#define EPROGUNAVAIL 74 /* RPC prog. not avail */
+#define EPROGMISMATCH 75 /* Program version wrong */
+#define EPROCUNAVAIL 76 /* Bad procedure for program */
+#endif /* _POSIX_SOURCE */
+
+#define ENOLCK 77 /* No locks available */
+#define ENOSYS 78 /* Function not implemented */
+
+#ifndef _POSIX_SOURCE
+#define EFTYPE 79 /* Inappropriate file type or format */
+#define EAUTH 80 /* Authentication error */
+#define ENEEDAUTH 81 /* Need authenticator */
+#define ELAST 81 /* Must be equal largest errno */
+#endif /* _POSIX_SOURCE */
+
+#endif
diff --git a/mit-pthreads/machdep/freebsd-2.0/timers.h b/mit-pthreads/machdep/freebsd-2.0/timers.h
new file mode 100755
index 00000000000..f9768c68c8f
--- /dev/null
+++ b/mit-pthreads/machdep/freebsd-2.0/timers.h
@@ -0,0 +1,45 @@
+/* ==== timers.h ============================================================
+ * Copyright (c) 1994 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ *
+ * Description : Basic timers header.
+ *
+ * 1.00 94/06/13 proven
+ * -Started coding this file.
+ */
+
+#ifndef _SYS_TIMERS_H_
+#define _SYS_TIMERS_H_
+
+#include <sys/time.h>
+
+#endif
diff --git a/mit-pthreads/machdep/freebsd-2.0/wait.h b/mit-pthreads/machdep/freebsd-2.0/wait.h
new file mode 100755
index 00000000000..7861e3fa180
--- /dev/null
+++ b/mit-pthreads/machdep/freebsd-2.0/wait.h
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 1982, 1986, 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)wait.h 8.1 (Berkeley) 6/2/93
+ * $Id$
+ */
+
+#ifndef _SYS_WAIT_H_
+#define _SYS_WAIT_H_
+
+/*
+ * This file holds definitions relevent to the wait4 system call
+ * and the alternate interfaces that use it (wait, wait3, waitpid).
+ */
+
+/*
+ * Macros to test the exit status returned by wait
+ * and extract the relevant values.
+ */
+#ifdef _POSIX_SOURCE
+#define _W_INT(i) (i)
+#else
+#define _W_INT(w) (*(int *)&(w)) /* convert union wait to int */
+#define WCOREFLAG 0200
+#endif
+
+#define _WSTATUS(x) (_W_INT(x) & 0177)
+#define _WSTOPPED 0177 /* _WSTATUS if process is stopped */
+#define WIFSTOPPED(x) (_WSTATUS(x) == _WSTOPPED)
+#define WSTOPSIG(x) (_W_INT(x) >> 8)
+#define WIFSIGNALED(x) (_WSTATUS(x) != _WSTOPPED && _WSTATUS(x) != 0)
+#define WTERMSIG(x) (_WSTATUS(x))
+#define WIFEXITED(x) (_WSTATUS(x) == 0)
+#define WEXITSTATUS(x) (_W_INT(x) >> 8)
+#ifndef _POSIX_SOURCE
+#define WCOREDUMP(x) (_W_INT(x) & WCOREFLAG)
+
+#define W_EXITCODE(ret, sig) ((ret) << 8 | (sig))
+#define W_STOPCODE(sig) ((sig) << 8 | _WSTOPPED)
+#endif
+
+/*
+ * Option bits for the third argument of wait4. WNOHANG causes the
+ * wait to not hang if there are no stopped or terminated processes, rather
+ * returning an error indication in this case (pid==0). WUNTRACED
+ * indicates that the caller should receive status about untraced children
+ * which stop due to signals. If children are stopped and a wait without
+ * this option is done, it is as though they were still running... nothing
+ * about them is returned.
+ */
+#define WNOHANG 1 /* dont hang in wait */
+#define WUNTRACED 2 /* tell about stopped, untraced children */
+
+#ifndef _POSIX_SOURCE
+/* POSIX extensions and 4.2/4.3 compatability: */
+
+/*
+ * Tokens for special values of the "pid" parameter to wait4.
+ */
+#define WAIT_ANY (-1) /* any process */
+#define WAIT_MYPGRP 0 /* any process in my process group */
+
+#include <machine/endian.h>
+
+/*
+ * Deprecated:
+ * Structure of the information in the status word returned by wait4.
+ * If w_stopval==WSTOPPED, then the second structure describes
+ * the information returned, else the first.
+ */
+union wait {
+ int w_status; /* used in syscall */
+ /*
+ * Terminated process status.
+ */
+ struct {
+#if BYTE_ORDER == LITTLE_ENDIAN
+ unsigned int w_Termsig:7, /* termination signal */
+ w_Coredump:1, /* core dump indicator */
+ w_Retcode:8, /* exit code if w_termsig==0 */
+ w_Filler:16; /* upper bits filler */
+#endif
+#if BYTE_ORDER == BIG_ENDIAN
+ unsigned int w_Filler:16, /* upper bits filler */
+ w_Retcode:8, /* exit code if w_termsig==0 */
+ w_Coredump:1, /* core dump indicator */
+ w_Termsig:7; /* termination signal */
+#endif
+ } w_T;
+ /*
+ * Stopped process status. Returned
+ * only for traced children unless requested
+ * with the WUNTRACED option bit.
+ */
+ struct {
+#if BYTE_ORDER == LITTLE_ENDIAN
+ unsigned int w_Stopval:8, /* == W_STOPPED if stopped */
+ w_Stopsig:8, /* signal that stopped us */
+ w_Filler:16; /* upper bits filler */
+#endif
+#if BYTE_ORDER == BIG_ENDIAN
+ unsigned int w_Filler:16, /* upper bits filler */
+ w_Stopsig:8, /* signal that stopped us */
+ w_Stopval:8; /* == W_STOPPED if stopped */
+#endif
+ } w_S;
+};
+#define w_termsig w_T.w_Termsig
+#define w_coredump w_T.w_Coredump
+#define w_retcode w_T.w_Retcode
+#define w_stopval w_S.w_Stopval
+#define w_stopsig w_S.w_Stopsig
+
+#define WSTOPPED _WSTOPPED
+#endif /* _POSIX_SOURCE */
+
+#ifndef KERNEL
+#include <sys/types.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+struct rusage; /* forward declaration */
+
+pid_t wait __P_((int *));
+pid_t waitpid __P_((pid_t, int *, int));
+#ifndef _POSIX_SOURCE
+pid_t wait3 __P_((int *, int, void *));
+pid_t wait4 __P_((pid_t, int *, int, void *));
+#endif
+__END_DECLS
+#endif
+
+#endif
diff --git a/mit-pthreads/machdep/hpux-10.20/__math.h b/mit-pthreads/machdep/hpux-10.20/__math.h
new file mode 100755
index 00000000000..8066bd60713
--- /dev/null
+++ b/mit-pthreads/machdep/hpux-10.20/__math.h
@@ -0,0 +1,3 @@
+#define HUGE_VAL 1.7976931348623157e+308
+
+
diff --git a/mit-pthreads/machdep/hpux-10.20/__signal.h b/mit-pthreads/machdep/hpux-10.20/__signal.h
new file mode 100755
index 00000000000..fbb1d6ce2b1
--- /dev/null
+++ b/mit-pthreads/machdep/hpux-10.20/__signal.h
@@ -0,0 +1,28 @@
+#include <sys/signal.h>
+
+#ifndef SIGCLD
+#define SIGCLD SIGCHLD
+#endif
+
+/* #define sigmask(n) ((unsigned int)1 << (((n) - 1) & (32 - 1))) */
+#define sigword(n) (((unsigned int)((n) - 1))>>5)
+
+#define __SIGEMPTYSET { 0, 0, 0, 0, 0, 0, 0, 0 }
+#define __SIGFILLSET { 0xffffffff,0xffffffff,0xffffffff,0xffffffff,\
+ 0xffffffff,0xffffffff,0xffffffff,0xffffffff}
+#define __SIGADDSET(s, n) ((s)->sigset[sigword(n)] |= sigmask(n))
+#define __SIGDELSET(s, n) ((s)->sigset[sigword(n)] &= ~sigmask(n))
+#define __SIGISMEMBER(s, n) ((s)->sigset[sigword(n)] & sigmask(n))
+
+#define SIGSET_SIZE sizeof(sigset_t)/sizeof(long)
+
+#define SIG_ANY(sig) sig_any(&sig)
+
+static inline int sig_any(sigset_t *sig) {
+ int i;
+ for (i=0; i < SIGSET_SIZE; i++)
+ if (sig->sigset[i] != 0)
+ return 1;
+ return 0;
+}
+
diff --git a/mit-pthreads/machdep/hpux-10.20/__stdio.h b/mit-pthreads/machdep/hpux-10.20/__stdio.h
new file mode 100755
index 00000000000..b8f1a07d9d6
--- /dev/null
+++ b/mit-pthreads/machdep/hpux-10.20/__stdio.h
@@ -0,0 +1,11 @@
+
+#ifndef _SIZE_T
+#define _SIZE_T
+typedef pthread_size_t size_t;
+#endif
+
+#include <sys/types.h>
+/*
+typedef pthread_fpos_t fpos_t;
+*/
+
diff --git a/mit-pthreads/machdep/hpux-10.20/__stdlib.h b/mit-pthreads/machdep/hpux-10.20/__stdlib.h
new file mode 100755
index 00000000000..37a14a960d5
--- /dev/null
+++ b/mit-pthreads/machdep/hpux-10.20/__stdlib.h
@@ -0,0 +1,24 @@
+/* $Id$ */
+
+#ifndef __sys_stdtypes_h
+
+#ifndef _SYS___STDLIB_H_
+#define _SYS___STDLIB_H_
+
+#ifndef _SIZE_T
+#define _SIZE_T
+typedef unsigned int size_t;
+#endif
+
+#ifndef _WCHAR_T
+#define _WCHAR_T
+typedef unsigned int wchar_t;
+#endif
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#endif
+
+#endif
diff --git a/mit-pthreads/machdep/hpux-10.20/__string.h b/mit-pthreads/machdep/hpux-10.20/__string.h
new file mode 100755
index 00000000000..1badf6d660c
--- /dev/null
+++ b/mit-pthreads/machdep/hpux-10.20/__string.h
@@ -0,0 +1,20 @@
+
+#ifndef _SYS_STDSYMS_INCLUDED
+#endif
+
+#ifndef _SIZE_T
+#define _SIZE_T
+typedef pthread_size_t size_t;
+#endif
+
+/* Non-standard SunOS 4.x string routines. */
+#if !defined(_ANSI_SOURCE) && !defined(_POSIX_SOURCE)
+__BEGIN_DECLS
+int bcmp __P_((const void *, const void *, size_t));
+void bcopy __P_((const void *, void *, size_t));
+void bzero __P_((void *, size_t));
+char *index __P_((const char *, int));
+char *rindex __P_((const char *, int));
+char *strdup __P_((const char *));
+__END_DECLS
+#endif
diff --git a/mit-pthreads/machdep/hpux-10.20/__time.h b/mit-pthreads/machdep/hpux-10.20/__time.h
new file mode 100755
index 00000000000..ae958dcc3cf
--- /dev/null
+++ b/mit-pthreads/machdep/hpux-10.20/__time.h
@@ -0,0 +1,31 @@
+/* $Id$ */
+
+#ifndef __sys_stdtypes_h
+
+#ifndef _SYS__TIME_H_
+#define _SYS__TIME_H_
+
+#ifndef _CLOCK_T
+#define _CLOCK_T
+typedef long clock_t;
+#endif
+
+#ifndef _TIME_T
+#define _TIME_T
+typedef long time_t;
+#endif
+
+#ifndef _SIZE_T
+#define _SIZE_T
+typedef unsigned int size_t;
+#endif
+
+#define CLOCKS_PER_SEC 1000000
+
+#if !defined(_ANSI_SOURCE) && !defined(CLK_TCK)
+#define CLK_TCK 60
+#endif /* not ANSI */
+
+#endif
+
+#endif /* !_SYS__TIME_H_ */
diff --git a/mit-pthreads/machdep/hpux-10.20/__unistd.h b/mit-pthreads/machdep/hpux-10.20/__unistd.h
new file mode 100755
index 00000000000..218e13d14ec
--- /dev/null
+++ b/mit-pthreads/machdep/hpux-10.20/__unistd.h
@@ -0,0 +1,68 @@
+/* /afs/sipb.mit.edu/project/pthreads/src/CVS/pthreads/machdep/hpux-9.03/__unist
+d.h,v 1.2 1995/03/10 03:59:53 snl Exp */
+
+#ifndef _SYS___UNISTD_H_
+#define _SYS___UNISTD_H_
+
+#include <sys/stdsyms.h>
+#include <sys/types.h>
+#include <utime.h>
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#ifndef _GID_T
+#define _GID_T
+typedef long gid_t;
+#endif
+
+#ifndef _UID_T
+#define _UID_T
+typedef long uid_t;
+#endif
+
+#ifndef _PID_T
+#define _PID_T
+typedef long pid_t;
+#endif
+
+#ifndef _OFF_T
+#define _OFF_T
+typedef long off_t;
+#endif
+
+#ifndef _SIZE_T
+#define _SIZE_T
+typedef unsigned int size_t;
+#endif
+
+#ifndef _SSIZE_T
+#define _SSIZE_T
+typedef int ssize_t;
+#endif
+
+#define ioctl_request_type int /* For fd.c */
+
+/* Symbolic constants for sysconf() variables defined by POSIX.1-1988: 0-7 */
+
+#define _SC_ARG_MAX 0 /* ARG_MAX: Max length of argument to exec()
+ including environment data */
+#define _SC_CHILD_MAX 1 /* CHILD_MAX: Max of processes per userid */
+#define _SC_CLK_TCK 2 /* Number of clock ticks per second */
+#define _SC_NGROUPS_MAX 3 /* NGROUPS_MAX: Max of simultaneous
+ supplementary group IDs per process */
+#define _SC_OPEN_MAX 4 /* OPEN_MAX: Max of files that one process
+ can have open at any one time */
+#define _SC_JOB_CONTROL 5 /* _POSIX_JOB_CONTROL: 1 iff supported */
+#define _SC_SAVED_IDS 6 /* _POSIX_SAVED_IDS: 1 iff supported */
+#define _SC_1_VERSION_88 7 /* _POSIX_VERSION: Date of POSIX.1-1988 */
+
+/* Symbolic constants for sysconf() variables added by POSIX.1-1990: 100-199 */
+
+#define _SC_STREAM_MAX 100 /* STREAM_MAX: Max of open stdio FILEs */
+#define _SC_TZNAME_MAX 101 /* TZNAME_MAX: Max length of timezone name */
+#define _SC_1_VERSION_90 102 /* _POSIX_VERSION: Date of POSIX.1-1990 */
+
+#endif /* _SYS___UNISTD_H_ */
+
diff --git a/mit-pthreads/machdep/hpux-10.20/cdefs.h b/mit-pthreads/machdep/hpux-10.20/cdefs.h
new file mode 100755
index 00000000000..643089e6df6
--- /dev/null
+++ b/mit-pthreads/machdep/hpux-10.20/cdefs.h
@@ -0,0 +1,67 @@
+/* ==== cdefs.h ============================================================
+ * Copyright (c) 1994 by Chris Provenzano, proven@athena.mit.edu
+ *
+ * Description : Similar to the BSD cdefs.h file.
+ *
+ * 1.00 94/01/26 proven
+ * -Started coding this file.
+ */
+
+#ifndef _PTHREAD_SYS_CDEFS_H_
+#define _PTHREAD_SYS_CDEFS_H_
+
+#include <sys/_inttypes.h>
+
+/* Stuff for compiling */
+#if defined(__GNUC__)
+#if defined(__cplusplus)
+#define __INLINE static inline
+#define __BEGIN_DECLS extern "C" {
+#define __END_DECLS };
+#else
+#define __INLINE extern inline
+#define __CAN_DO_EXTERN_INLINE
+#define __BEGIN_DECLS
+#define __END_DECLS
+#if !defined(__STDC__)
+#define const __const
+#define inline __inline
+#define signed __signed
+#define volatile __volatile
+#endif
+#endif
+#else /* !__GNUC__ */
+#define __INLINE static
+#define __BEGIN_DECLS
+#define __END_DECLS
+#endif
+
+#ifndef __NORETURN
+#define __NORETURN
+#endif /* __NORETURN not defined. */
+
+#ifndef _U_INT32_T_
+#define _U_INT32_T_
+typedef unsigned int u_int32_t;
+#endif
+
+#ifndef _U_INT16_T_
+#define _U_INT16_T_
+typedef unsigned short u_int16_t;
+#endif
+
+#ifndef _INT32_T_
+#define _INT32_T_
+/*
+typedef int int32_t;
+*/
+#endif
+
+#ifndef _INT16_T_
+#define _INT16_T_
+/*
+typedef short int16_t;
+*/
+#endif
+
+#endif
diff --git a/mit-pthreads/machdep/hpux-10.20/compat.h b/mit-pthreads/machdep/hpux-10.20/compat.h
new file mode 100755
index 00000000000..5a59434417c
--- /dev/null
+++ b/mit-pthreads/machdep/hpux-10.20/compat.h
@@ -0,0 +1,45 @@
+/* ==== compat.h ============================================================
+ * Copyright (c) 1994 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ *
+ * Description : Compatibility header for networking code.
+ *
+ * 1.00 94/06/13 proven
+ * -Started coding this file.
+ */
+
+#ifndef _SYS_COMPAT_H_
+#define _SYS_COMPAT_H_
+
+#define omsghdr msghdr
+
+#endif
diff --git a/mit-pthreads/machdep/hpux-10.20/dirent.h b/mit-pthreads/machdep/hpux-10.20/dirent.h
new file mode 100755
index 00000000000..5f17af345db
--- /dev/null
+++ b/mit-pthreads/machdep/hpux-10.20/dirent.h
@@ -0,0 +1,61 @@
+/*-
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)dirent.h 5.18 (Berkeley) 2/23/91
+ */
+
+#ifndef _SYS_DIRENT_H_
+#define _SYS_DIRENT_H_
+
+/*
+ * A directory entry has a struct dirent at the front of it, containing its
+ * inode number, the length of the entry, and the length of the name
+ * contained in the entry. These are followed by the name padded to a 4
+ * byte boundary with null bytes. All names are guaranteed null terminated.
+ * The maximum length of a name in a directory is MAXNAMLEN.
+ */
+
+struct dirent {
+ u_long d_fileno; /* file number of entry */
+ u_short d_reclen; /* length of this record */
+ u_short d_namlen; /* length of string in d_name */
+#ifdef _POSIX_SOURCE
+ char d_name[255 + 1]; /* name must be no longer than this */
+#else
+#define MAXNAMLEN 255
+ char d_name[MAXNAMLEN + 1]; /* name must be no longer than this */
+#endif
+};
+
+#define d_ino d_fileno
+
+#endif /* !_SYS_DIRENT_H_ */
diff --git a/mit-pthreads/machdep/hpux-10.20/socket.h b/mit-pthreads/machdep/hpux-10.20/socket.h
new file mode 100755
index 00000000000..c7a37706940
--- /dev/null
+++ b/mit-pthreads/machdep/hpux-10.20/socket.h
@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 1982, 1985, 1986 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * @(#)socket.h 7.3 (Berkeley) 6/27/88
+ */
+
+/*
+ * Definitions related to sockets: types, address families, options.
+ */
+
+#include <sys/stdsyms.h>
+#include <pthread/posix.h>
+#include <sys/cdefs.h>
+
+/*
+ * Types of sockets
+ */
+#define SOCK_STREAM 1 /* stream socket */
+#define SOCK_DGRAM 2 /* datagram socket */
+#define SOCK_RAW 3 /* raw-protocol interface */
+#define SOCK_RDM 4 /* reliably-delivered message */
+#define SOCK_SEQPACKET 5 /* sequenced packet stream */
+
+/*
+ * Option flags per-socket.
+ */
+#define SO_DEBUG 0x0001 /* turn on debugging info recording */
+#define SO_ACCEPTCONN 0x0002 /* socket has had listen() */
+#define SO_REUSEADDR 0x0004 /* allow local address reuse */
+#define SO_KEEPALIVE 0x0008 /* keep connections alive */
+#define SO_DONTROUTE 0x0010 /* just use interface addresses */
+#define SO_BROADCAST 0x0020 /* permit sending of broadcast msgs */
+#define SO_USELOOPBACK 0x0040 /* bypass hardware when possible */
+#define SO_LINGER 0x0080 /* linger on close if data present */
+#define SO_OOBINLINE 0x0100 /* leave received OOB data in line */
+
+/*
+ * Additional options, not kept in so_options.
+ */
+#define SO_SNDBUF 0x1001 /* send buffer size */
+#define SO_RCVBUF 0x1002 /* receive buffer size */
+#define SO_SNDLOWAT 0x1003 /* send low-water mark */
+#define SO_RCVLOWAT 0x1004 /* receive low-water mark */
+#define SO_SNDTIMEO 0x1005 /* send timeout */
+#define SO_RCVTIMEO 0x1006 /* receive timeout */
+#define SO_ERROR 0x1007 /* get error status and clear */
+#define SO_TYPE 0x1008 /* get socket type */
+#define SO_SND_COPYAVOID 0x1009 /* avoid copy on send*/
+#define SO_RCV_COPYAVOID 0x100a /* avoid copy on rcv */
+
+/*
+ * Level number for (get/set)sockopt() to apply to socket itself.
+ */
+#define SOL_SOCKET 0xffff /* options for socket level */
+
+/*
+ * Address families.
+ */
+#define AF_UNSPEC 0 /* unspecified */
+#define AF_UNIX 1 /* local to host (pipes, portals) */
+#define AF_INET 2 /* internetwork: UDP, TCP, etc. */
+#define AF_IMPLINK 3 /* arpanet imp addresses */
+#define AF_PUP 4 /* pup protocols: e.g. BSP */
+#define AF_CHAOS 5 /* mit CHAOS protocols */
+#define AF_NS 6 /* XEROX NS protocols */
+#define AF_NBS 7 /* nbs protocols */
+#define AF_ECMA 8 /* european computer manufacturers */
+#define AF_DATAKIT 9 /* datakit protocols */
+#define AF_CCITT 10 /* CCITT protocols, X.25 etc */
+#define AF_SNA 11 /* IBM SNA */
+#define AF_DECnet 12 /* DECnet */
+#define AF_DLI 13 /* Direct data link interface */
+#define AF_LAT 14 /* LAT */
+#define AF_HYLINK 15 /* NSC Hyperchannel */
+#define AF_APPLETALK 16 /* Apple Talk */
+#define AF_OTS 17 /* Used for OSI in the ifnets */
+#define AF_NIT 18 /* NIT */
+
+#define AF_MAX 19
+
+/*
+ * Structure used by kernel to store most
+ * addresses.
+ */
+struct sockaddr {
+ unsigned short sa_family; /* address family */
+ char sa_data[14]; /* up to 14 bytes of direct address */
+};
+
+/*
+ * Structure used by kernel to pass protocol
+ * information in raw sockets.
+ */
+struct sockproto {
+ unsigned short sp_family; /* address family */
+ unsigned short sp_protocol; /* protocol */
+};
+
+/*
+ * Protocol families, same as address families for now.
+ */
+#define PF_UNSPEC AF_UNSPEC
+#define PF_UNIX AF_UNIX
+#define PF_INET AF_INET
+#define PF_IMPLINK AF_IMPLINK
+#define PF_PUP AF_PUP
+#define PF_CHAOS AF_CHAOS
+#define PF_NS AF_NS
+#define PF_NBS AF_NBS
+#define PF_ECMA AF_ECMA
+#define PF_DATAKIT AF_DATAKIT
+#define PF_CCITT AF_CCITT
+#define PF_SNA AF_SNA
+#define PF_DECnet AF_DECnet
+#define PF_DLI AF_DLI
+#define PF_LAT AF_LAT
+#define PF_HYLINK AF_HYLINK
+#define PF_APPLETALK AF_APPLETALK
+
+#define PF_MAX AF_MAX
+
+/*
+ * Maximum queue length specifiable by listen.
+ */
+#define SOMAXCONN 20
+
+/*
+ * Message header for recvmsg and sendmsg calls.
+ */
+struct msghdr {
+ caddr_t msg_name; /* optional address */
+ int msg_namelen; /* size of address */
+ struct iovec *msg_iov; /* scatter/gather array */
+ int msg_iovlen; /* # elements in msg_iov */
+ caddr_t msg_accrights; /* access rights sent/received */
+ int msg_accrightslen;
+};
+
+#define MSG_OOB 0x1 /* process out-of-band data */
+#define MSG_PEEK 0x2 /* peek at incoming message */
+#define MSG_DONTROUTE 0x4 /* send without using routing tables */
+
+#define MSG_MAXIOVLEN 16
+
+/*
+ * Functions
+ */
+
+__BEGIN_DECLS
+
+int accept __P_((int, struct sockaddr *, int *));
+int bind __P_((int, const struct sockaddr *, int));
+int connect __P_((int, const struct sockaddr *, int));
+int listen __P_((int, int));
+int socket __P_((int, int, int));
+
+__END_DECLS
+
diff --git a/mit-pthreads/machdep/hpux-10.20/stdtypes.h b/mit-pthreads/machdep/hpux-10.20/stdtypes.h
new file mode 100755
index 00000000000..2b22abbf818
--- /dev/null
+++ b/mit-pthreads/machdep/hpux-10.20/stdtypes.h
@@ -0,0 +1,74 @@
+/* @(#)stdtypes.h 1.6 90/01/04 SMI */
+
+/*
+ * Suppose you have an ANSI C or POSIX thingy that needs a typedef
+ * for thingy_t. Put it here and include this file wherever you
+ * define the thingy. This is used so that we don't have size_t in
+ * N (N > 1) different places and so that we don't have to have
+ * types.h included all the time and so that we can include this in
+ * the lint libs instead of termios.h which conflicts with ioctl.h.
+ */
+#ifndef __sys_stdtypes_h
+#define __sys_stdtypes_h
+
+#ifndef _SIGSET_T_
+#define _SIGSET_T_
+typedef int sigset_t; /* signal mask - may change */
+#endif
+
+#ifndef _SPEED_T_
+#define _SPEED_T_
+typedef unsigned int speed_t; /* tty speeds */
+#endif
+
+#ifndef _TCFLAG_T_
+#define _TCFLAG_T_
+typedef unsigned long tcflag_t; /* tty line disc modes */
+#endif
+
+#ifndef _CC_T_
+#define _CC_T_
+typedef unsigned char cc_t; /* tty control char */
+#endif
+
+#ifndef _PID_T_
+#define _PID_T_
+typedef int pid_t; /* process id */
+#endif
+
+#ifndef _MODE_T_
+#define _MODE_T_
+typedef unsigned short mode_t; /* file mode bits */
+#endif
+
+#ifndef _NLINK_T_
+#define _NLINK_T_
+typedef short nlink_t; /* links to a file */
+#endif
+
+#ifndef _CLOCK_T_
+#define _CLOCK_T_
+typedef long clock_t; /* units=ticks (typically 60/sec) */
+#endif
+
+#ifndef _TIME_T_
+#define _TIME_T_
+typedef long time_t; /* value = secs since epoch */
+#endif
+
+#ifndef _SIZE_T_
+#define _SIZE_T_
+typedef int size_t; /* ??? */
+#endif
+
+#ifndef _PTRDIFF_T_
+#define _PTRDIFF_T_
+typedef int ptrdiff_t; /* result of subtracting two pointers */
+#endif
+
+#ifndef _WCHAR_T_
+#define _WCHAR_T_
+typedef unsigned short wchar_t; /* big enough for biggest char set */
+#endif
+
+#endif /* !__sys_stdtypes_h */
diff --git a/mit-pthreads/machdep/hpux-10.20/time.h b/mit-pthreads/machdep/hpux-10.20/time.h
new file mode 100755
index 00000000000..544905b0749
--- /dev/null
+++ b/mit-pthreads/machdep/hpux-10.20/time.h
@@ -0,0 +1,228 @@
+/* $Header$ */
+
+#ifndef _SYS_TIME_INCLUDED
+#define _SYS_TIME_INCLUDED
+
+/* time.h: Definitions for time handling functions */
+
+#ifdef _KERNEL_BUILD
+#include "../h/stdsyms.h"
+#else /* ! _KERNEL_BUILD */
+#include <sys/stdsyms.h>
+#endif /* _KERNEL_BUILD */
+
+#include <sys/types.h>
+
+/* ANSI C time constants, types, and structures */
+
+#ifdef _INCLUDE__STDC__
+# define CLOCKS_PER_SEC 1000000
+
+# ifndef NULL
+# define NULL 0
+# endif
+
+# ifndef _CLOCK_T
+# define _CLOCK_T
+ typedef unsigned long clock_t;
+# endif /* _CLOCK_T */
+
+# ifndef _TIME_T
+# define _TIME_T
+ typedef long time_t;
+# endif /* _TIME_T */
+
+# ifndef _SIZE_T
+# define _SIZE_T
+ typedef unsigned int size_t;
+# endif /* _SIZE_T */
+
+ /* Structure used with gmtime(), localtime(), mktime(), strftime(). */
+ struct tm {
+ int tm_sec; /* second (0-61, allows for leap seconds) */
+ int tm_min; /* minute (0-59) */
+ int tm_hour; /* hour (0-23) */
+ int tm_mday; /* day of the month (1-31) */
+ int tm_mon; /* month (0-11) */
+ int tm_year; /* years since 1900 */
+ int tm_wday; /* day of the week (0-6) */
+ int tm_yday; /* day of the year (0-365) */
+ int tm_isdst; /* non-0 if daylight savings time is in effect */
+ };
+#endif /* _INCLUDE__STDC__ */
+
+
+/* Additional types needed for HP-UX */
+
+#ifdef _INCLUDE_HPUX_SOURCE
+# ifndef _STRUCT_TIMEVAL
+# define _STRUCT_TIMEVAL
+ /* Structure returned by gettimeofday(2) system call and others */
+ struct timeval {
+ unsigned long tv_sec; /* seconds */
+ long tv_usec; /* and microseconds */
+ };
+# endif /* _STRUCT_TIMEVAL */
+
+ /* Structure used to represent timezones for gettimeofday(2) and others */
+ struct timezone {
+ int tz_minuteswest; /* minutes west of Greenwich */
+ int tz_dsttime; /* type of dst correction */
+ };
+
+ /* Structure defining a timer setting. */
+ struct itimerval {
+ struct timeval it_interval; /* timer interval */
+ struct timeval it_value; /* current value */
+ };
+#endif /* _INCLUDE_HPUX_SOURCE */
+
+
+/* Function prototypes and external variable declarations */
+
+#ifndef _KERNEL
+#ifdef __cplusplus
+ extern "C" {
+#endif /* __cplusplus */
+
+#ifdef _INCLUDE__STDC__
+# ifdef _PROTOTYPES
+ extern double difftime(time_t, time_t);
+ extern time_t mktime(struct tm *);
+ extern time_t time(time_t *);
+ extern char *ctime(const time_t *);
+ extern struct tm *gmtime(const time_t *);
+ extern struct tm *localtime(const time_t *);
+ extern size_t strftime(char *, size_t, const char *, const struct tm *);
+# else /* not _PROTOTYPES */
+ extern double difftime();
+ extern time_t mktime();
+ extern time_t time();
+ extern char *ctime();
+ extern struct tm *gmtime();
+ extern struct tm *localtime();
+ extern size_t strftime();
+# endif /* not _PROTOTYPES */
+
+# ifdef _CLASSIC_ANSI_TYPES
+ extern long clock();
+# else /* not _CLASSIC_ANSI_TYPES */
+# ifdef _PROTOTYPES
+ extern clock_t clock(void);
+# else /* not _PROTOTYPES */
+ extern clock_t clock();
+# endif /* not _PROTOTYPES */
+# endif /* not _CLASSIC_ANSI_TYPES */
+#endif /* _INCLUDE__STDC__ */
+
+#ifdef _INCLUDE_POSIX_SOURCE
+# ifdef _PROTOTYPES
+ extern void tzset(void);
+# else /* not _PROTOTYPES */
+ extern void tzset();
+# endif /* not _PROTOTYPES */
+
+ extern char *tzname[2];
+#endif /* _INCLUDE_POSIX_SOURCE */
+
+
+#ifdef _INCLUDE_XOPEN_SOURCE
+# ifdef _PROTOTYPES
+ extern char *strptime(const char *, const char *, struct tm *);
+# else /* not _PROTOTYPES */
+ extern char *strptime();
+# endif /* not _PROTOTYPES */
+
+ extern long timezone;
+ extern int daylight;
+#endif /* _INCLUDE_XOPEN_SOURCE */
+
+
+#ifdef _INCLUDE_HPUX_SOURCE
+# ifdef _PROTOTYPES
+ extern struct tm *getdate(const char *);
+ extern char *nl_asctime(struct tm *, char *, int);
+ extern char *nl_ctime(long *, char *, int);
+ extern char *nl_ascxtime(struct tm *, char *);
+ extern char *nl_cxtime(long *, char *);
+ extern int getitimer(int, struct itimerval *);
+ extern int setitimer(int, const struct itimerval *, struct itimerval *);
+ extern int gettimeofday(struct timeval *, struct timezone *);
+ extern int settimeofday(const struct timeval *, const struct timezone *);
+ extern int select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
+ extern int stime(const time_t *);
+# else /* not _PROTOTYPES */
+ extern struct tm *getdate();
+ extern char *nl_asctime();
+ extern char *nl_ctime();
+ extern char *nl_ascxtime();
+ extern char *nl_cxtime();
+ extern int getitimer();
+ extern int setitimer();
+ extern int gettimeofday();
+ extern int settimeofday();
+ extern int select();
+ extern int stime();
+# endif /* not _PROTOTYPES */
+ extern int getdate_err;
+#endif /* _INCLUDE_HPUX_SOURCE */
+
+#ifdef __cplusplus
+ }
+#endif /* __cplusplus */
+#endif /* not _KERNEL */
+
+
+/*
+ * CLK_TCK is needed by the kernel, and also in the POSIX namespace.
+ */
+
+#ifdef _INCLUDE_POSIX_SOURCE
+# ifndef CLK_TCK
+# ifdef __hp9000s300
+# define CLK_TCK 50
+# endif /* __hp9000s300 */
+# ifdef __hp9000s800
+# define CLK_TCK 100
+# endif /* __hp9000s800 */
+# endif /* CLK_TCK */
+#endif
+
+
+/* Additional HP-UX structures, macros, and constants */
+
+#ifdef _INCLUDE_HPUX_SOURCE
+
+ /* Kernel instrumentation time value */
+ struct ki_timeval {
+ long tv_sec; /* seconds */
+ long tv_nunit; /* and native units */
+ };
+
+ /* Kinds of daylight savings time */
+# define DST_NONE 0 /* not on dst */
+# define DST_USA 1 /* USA style dst */
+# define DST_AUST 2 /* Australian style dst */
+# define DST_WET 3 /* Western European dst */
+# define DST_MET 4 /* Middle European dst */
+# define DST_EET 5 /* Eastern European dst */
+
+ /*
+ * Operations on timevals.
+ *
+ * NB: timercmp does not work for >= or <=.
+ */
+# define timerisset(tvp) ((tvp)->tv_sec || (tvp)->tv_usec)
+# define timercmp(tvp, uvp, cmp) \
+ ((tvp)->tv_sec cmp (uvp)->tv_sec || \
+ (tvp)->tv_sec == (uvp)->tv_sec && (tvp)->tv_usec cmp (uvp)->tv_usec)
+# define timerclear(tvp) ((tvp)->tv_sec = (tvp)->tv_usec = 0)
+
+ /* Names of the interval timers */
+# define ITIMER_REAL 0
+# define ITIMER_VIRTUAL 1
+# define ITIMER_PROF 2
+
+#endif /* _INCLUDE_HPUX_SOURCE */
+
+#endif /* _SYS_TIME_INCLUDED */
diff --git a/mit-pthreads/machdep/hpux-10.20/timers.h b/mit-pthreads/machdep/hpux-10.20/timers.h
new file mode 100755
index 00000000000..5a76a295400
--- /dev/null
+++ b/mit-pthreads/machdep/hpux-10.20/timers.h
@@ -0,0 +1,71 @@
+/* ==== timers.h ============================================================
+ * Copyright (c) 1994 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ *
+ * Description : Basic timers header.
+ *
+ * 1.00 94/06/13 proven
+ * -Started coding this file.
+ */
+
+#ifndef _SYS_TIMERS_H_
+#define _SYS_TIMERS_H_
+
+#include <sys/signal.h>
+#include <sys/types.h>
+#include <time.h>
+
+/*
+struct timespec {
+ time_t tv_sec;
+ long tv_nsec;
+};
+*/
+
+#define TIMEVAL_TO_TIMESPEC(tv, ts) { \
+ (ts)->tv_sec = (tv)->tv_sec; \
+ (ts)->tv_nsec = (tv)->tv_usec * 1000; \
+}
+#define TIMESPEC_TO_TIMEVAL(tv, ts) { \
+ (tv)->tv_sec = (ts)->tv_sec; \
+ (tv)->tv_usec = (ts)->tv_nsec / 1000; \
+}
+
+/*
+ * New functions
+ */
+
+__BEGIN_DECLS
+
+__END_DECLS
+
+#endif
diff --git a/mit-pthreads/machdep/hpux-10.20/uio.h b/mit-pthreads/machdep/hpux-10.20/uio.h
new file mode 100755
index 00000000000..d1ec4c94f22
--- /dev/null
+++ b/mit-pthreads/machdep/hpux-10.20/uio.h
@@ -0,0 +1,25 @@
+/* ==== uio.h ============================================================
+ * Copyright (c) 1994 by Chris Provenzano, proven@athena.mit.edu
+ *
+ * Description : Correct HP-UX header file.
+ */
+
+#ifndef _PTHREAD_UIO_H_
+#define _PTHREAD_UIO_H_
+
+#include <sys/cdefs.h>
+
+struct iovec {
+ void *iov_base;
+ size_t iov_len;
+};
+
+__BEGIN_DECLS
+
+int readv __P_((int, const struct iovec *, int));
+int writev __P_((int, const struct iovec *, int));
+
+__END_DECLS
+
+#endif
+
diff --git a/mit-pthreads/machdep/hpux-10.20/wait.h b/mit-pthreads/machdep/hpux-10.20/wait.h
new file mode 100755
index 00000000000..bca70d9f1ec
--- /dev/null
+++ b/mit-pthreads/machdep/hpux-10.20/wait.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 1982, 1986, 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)wait.h 8.1 (Berkeley) 6/2/93
+ * $Id$
+ */
+
+#ifndef _SYS_WAIT_H_
+#define _SYS_WAIT_H_
+
+/*
+ * Macros to test the exit status returned by wait
+ * and extract the relevant values.
+ */
+#define _W_INT(i) (i)
+#define WCOREFLAG 0200
+
+#define _WSTATUS(x) (_W_INT(x) & 0177)
+#define _WSTOPPED 0177 /* _WSTATUS if process is stopped */
+#define WIFSTOPPED(x) (_WSTATUS(x) == _WSTOPPED)
+#define WSTOPSIG(x) (_W_INT(x) >> 8)
+#define WIFSIGNALED(x) (_WSTATUS(x) != _WSTOPPED && _WSTATUS(x) != 0)
+#define WTERMSIG(x) (_WSTATUS(x))
+#define WIFEXITED(x) (_WSTATUS(x) == 0)
+#define WEXITSTATUS(x) (_W_INT(x) >> 8)
+#ifndef _POSIX_SOURCE
+#define WCOREDUMP(x) (_W_INT(x) & WCOREFLAG)
+
+#define W_EXITCODE(ret, sig) ((ret) << 8 | (sig))
+#define W_STOPCODE(sig) ((sig) << 8 | _WSTOPPED)
+#endif
+
+#define WNOHANG 1 /* dont hang in wait */
+#define WUNTRACED 2 /* tell about stopped, untraced children */
+
+#ifndef _POSIX_SOURCE
+/* POSIX extensions and 4.2/4.3 compatability: */
+
+/*
+ * Tokens for special values of the "pid" parameter to wait4.
+ */
+#define WAIT_ANY (-1) /* any process */
+#define WAIT_MYPGRP 0 /* any process in my process group */
+
+#define WSTOPPED _WSTOPPED
+#endif /* _POSIX_SOURCE */
+
+#include <sys/types.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+struct rusage; /* forward declaration */
+
+pid_t wait __P_((int *));
+pid_t waitpid __P_((pid_t, int *, int));
+
+#ifndef _POSIX_SOURCE
+pid_t wait3 __P_((int *, int, void *));
+#endif
+
+__END_DECLS
+
+#endif
diff --git a/mit-pthreads/machdep/hpux-9.03/__math.h b/mit-pthreads/machdep/hpux-9.03/__math.h
new file mode 100755
index 00000000000..8066bd60713
--- /dev/null
+++ b/mit-pthreads/machdep/hpux-9.03/__math.h
@@ -0,0 +1,3 @@
+#define HUGE_VAL 1.7976931348623157e+308
+
+
diff --git a/mit-pthreads/machdep/hpux-9.03/__signal.h b/mit-pthreads/machdep/hpux-9.03/__signal.h
new file mode 100755
index 00000000000..fbb1d6ce2b1
--- /dev/null
+++ b/mit-pthreads/machdep/hpux-9.03/__signal.h
@@ -0,0 +1,28 @@
+#include <sys/signal.h>
+
+#ifndef SIGCLD
+#define SIGCLD SIGCHLD
+#endif
+
+/* #define sigmask(n) ((unsigned int)1 << (((n) - 1) & (32 - 1))) */
+#define sigword(n) (((unsigned int)((n) - 1))>>5)
+
+#define __SIGEMPTYSET { 0, 0, 0, 0, 0, 0, 0, 0 }
+#define __SIGFILLSET { 0xffffffff,0xffffffff,0xffffffff,0xffffffff,\
+ 0xffffffff,0xffffffff,0xffffffff,0xffffffff}
+#define __SIGADDSET(s, n) ((s)->sigset[sigword(n)] |= sigmask(n))
+#define __SIGDELSET(s, n) ((s)->sigset[sigword(n)] &= ~sigmask(n))
+#define __SIGISMEMBER(s, n) ((s)->sigset[sigword(n)] & sigmask(n))
+
+#define SIGSET_SIZE sizeof(sigset_t)/sizeof(long)
+
+#define SIG_ANY(sig) sig_any(&sig)
+
+static inline int sig_any(sigset_t *sig) {
+ int i;
+ for (i=0; i < SIGSET_SIZE; i++)
+ if (sig->sigset[i] != 0)
+ return 1;
+ return 0;
+}
+
diff --git a/mit-pthreads/machdep/hpux-9.03/__stdio.h b/mit-pthreads/machdep/hpux-9.03/__stdio.h
new file mode 100755
index 00000000000..091b065a2e9
--- /dev/null
+++ b/mit-pthreads/machdep/hpux-9.03/__stdio.h
@@ -0,0 +1,8 @@
+
+#ifndef _SIZE_T
+#define _SIZE_T
+typedef pthread_size_t size_t;
+#endif
+
+typedef pthread_fpos_t fpos_t;
+
diff --git a/mit-pthreads/machdep/hpux-9.03/__stdlib.h b/mit-pthreads/machdep/hpux-9.03/__stdlib.h
new file mode 100755
index 00000000000..37a14a960d5
--- /dev/null
+++ b/mit-pthreads/machdep/hpux-9.03/__stdlib.h
@@ -0,0 +1,24 @@
+/* $Id$ */
+
+#ifndef __sys_stdtypes_h
+
+#ifndef _SYS___STDLIB_H_
+#define _SYS___STDLIB_H_
+
+#ifndef _SIZE_T
+#define _SIZE_T
+typedef unsigned int size_t;
+#endif
+
+#ifndef _WCHAR_T
+#define _WCHAR_T
+typedef unsigned int wchar_t;
+#endif
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#endif
+
+#endif
diff --git a/mit-pthreads/machdep/hpux-9.03/__string.h b/mit-pthreads/machdep/hpux-9.03/__string.h
new file mode 100755
index 00000000000..1badf6d660c
--- /dev/null
+++ b/mit-pthreads/machdep/hpux-9.03/__string.h
@@ -0,0 +1,20 @@
+
+#ifndef _SYS_STDSYMS_INCLUDED
+#endif
+
+#ifndef _SIZE_T
+#define _SIZE_T
+typedef pthread_size_t size_t;
+#endif
+
+/* Non-standard SunOS 4.x string routines. */
+#if !defined(_ANSI_SOURCE) && !defined(_POSIX_SOURCE)
+__BEGIN_DECLS
+int bcmp __P_((const void *, const void *, size_t));
+void bcopy __P_((const void *, void *, size_t));
+void bzero __P_((void *, size_t));
+char *index __P_((const char *, int));
+char *rindex __P_((const char *, int));
+char *strdup __P_((const char *));
+__END_DECLS
+#endif
diff --git a/mit-pthreads/machdep/hpux-9.03/__time.h b/mit-pthreads/machdep/hpux-9.03/__time.h
new file mode 100755
index 00000000000..ae958dcc3cf
--- /dev/null
+++ b/mit-pthreads/machdep/hpux-9.03/__time.h
@@ -0,0 +1,31 @@
+/* $Id$ */
+
+#ifndef __sys_stdtypes_h
+
+#ifndef _SYS__TIME_H_
+#define _SYS__TIME_H_
+
+#ifndef _CLOCK_T
+#define _CLOCK_T
+typedef long clock_t;
+#endif
+
+#ifndef _TIME_T
+#define _TIME_T
+typedef long time_t;
+#endif
+
+#ifndef _SIZE_T
+#define _SIZE_T
+typedef unsigned int size_t;
+#endif
+
+#define CLOCKS_PER_SEC 1000000
+
+#if !defined(_ANSI_SOURCE) && !defined(CLK_TCK)
+#define CLK_TCK 60
+#endif /* not ANSI */
+
+#endif
+
+#endif /* !_SYS__TIME_H_ */
diff --git a/mit-pthreads/machdep/hpux-9.03/__unistd.h b/mit-pthreads/machdep/hpux-9.03/__unistd.h
new file mode 100755
index 00000000000..0e8515b1f96
--- /dev/null
+++ b/mit-pthreads/machdep/hpux-9.03/__unistd.h
@@ -0,0 +1,66 @@
+/* /afs/sipb.mit.edu/project/pthreads/src/CVS/pthreads/machdep/hpux-9.03/__unist
+d.h,v 1.2 1995/03/10 03:59:53 snl Exp */
+
+#ifndef _SYS___UNISTD_H_
+#define _SYS___UNISTD_H_
+
+#include <sys/stdsyms.h>
+#include <sys/types.h>
+#include <utime.h>
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#ifndef _GID_T
+#define _GID_T
+typedef long gid_t;
+#endif
+
+#ifndef _UID_T
+#define _UID_T
+typedef long uid_t;
+#endif
+
+#ifndef _PID_T
+#define _PID_T
+typedef long pid_t;
+#endif
+
+#ifndef _OFF_T
+#define _OFF_T
+typedef long off_t;
+#endif
+
+#ifndef _SIZE_T
+#define _SIZE_T
+typedef unsigned int size_t;
+#endif
+
+#ifndef _SSIZE_T
+#define _SSIZE_T
+typedef int ssize_t;
+#endif
+
+/* Symbolic constants for sysconf() variables defined by POSIX.1-1988: 0-7 */
+
+#define _SC_ARG_MAX 0 /* ARG_MAX: Max length of argument to exec()
+ including environment data */
+#define _SC_CHILD_MAX 1 /* CHILD_MAX: Max of processes per userid */
+#define _SC_CLK_TCK 2 /* Number of clock ticks per second */
+#define _SC_NGROUPS_MAX 3 /* NGROUPS_MAX: Max of simultaneous
+ supplementary group IDs per process */
+#define _SC_OPEN_MAX 4 /* OPEN_MAX: Max of files that one process
+ can have open at any one time */
+#define _SC_JOB_CONTROL 5 /* _POSIX_JOB_CONTROL: 1 iff supported */
+#define _SC_SAVED_IDS 6 /* _POSIX_SAVED_IDS: 1 iff supported */
+#define _SC_1_VERSION_88 7 /* _POSIX_VERSION: Date of POSIX.1-1988 */
+
+/* Symbolic constants for sysconf() variables added by POSIX.1-1990: 100-199 */
+
+#define _SC_STREAM_MAX 100 /* STREAM_MAX: Max of open stdio FILEs */
+#define _SC_TZNAME_MAX 101 /* TZNAME_MAX: Max length of timezone name */
+#define _SC_1_VERSION_90 102 /* _POSIX_VERSION: Date of POSIX.1-1990 */
+
+#endif /* _SYS___UNISTD_H_ */
+
diff --git a/mit-pthreads/machdep/hpux-9.03/cdefs.h b/mit-pthreads/machdep/hpux-9.03/cdefs.h
new file mode 100755
index 00000000000..041300cbe02
--- /dev/null
+++ b/mit-pthreads/machdep/hpux-9.03/cdefs.h
@@ -0,0 +1,61 @@
+/* ==== cdefs.h ============================================================
+ * Copyright (c) 1994 by Chris Provenzano, proven@athena.mit.edu
+ *
+ * Description : Similar to the BSD cdefs.h file.
+ *
+ * 1.00 94/01/26 proven
+ * -Started coding this file.
+ */
+
+#ifndef _PTHREAD_SYS_CDEFS_H_
+#define _PTHREAD_SYS_CDEFS_H_
+
+/* Stuff for compiling */
+#if defined(__GNUC__)
+#if defined(__cplusplus)
+#define __INLINE static inline
+#define __BEGIN_DECLS extern "C" {
+#define __END_DECLS };
+#else
+#define __INLINE extern inline
+#define __CAN_DO_EXTERN_INLINE
+#define __BEGIN_DECLS
+#define __END_DECLS
+#if !defined(__STDC__)
+#define const __const
+#define inline __inline
+#define signed __signed
+#define volatile __volatile
+#endif
+#endif
+#else /* !__GNUC__ */
+#define __INLINE static
+#define __BEGIN_DECLS
+#define __END_DECLS
+#endif
+
+#ifndef __NORETURN
+#define __NORETURN
+#endif /* __NORETURN not defined. */
+
+#ifndef _U_INT32_T_
+#define _U_INT32_T_
+typedef unsigned int u_int32_t;
+#endif
+
+#ifndef _U_INT16_T_
+#define _U_INT16_T_
+typedef unsigned short u_int16_t;
+#endif
+
+#ifndef _INT32_T_
+#define _INT32_T_
+typedef int int32_t;
+#endif
+
+#ifndef _INT16_T_
+#define _INT16_T_
+typedef short int16_t;
+#endif
+
+#endif
diff --git a/mit-pthreads/machdep/hpux-9.03/compat.h b/mit-pthreads/machdep/hpux-9.03/compat.h
new file mode 100755
index 00000000000..5a59434417c
--- /dev/null
+++ b/mit-pthreads/machdep/hpux-9.03/compat.h
@@ -0,0 +1,45 @@
+/* ==== compat.h ============================================================
+ * Copyright (c) 1994 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ *
+ * Description : Compatibility header for networking code.
+ *
+ * 1.00 94/06/13 proven
+ * -Started coding this file.
+ */
+
+#ifndef _SYS_COMPAT_H_
+#define _SYS_COMPAT_H_
+
+#define omsghdr msghdr
+
+#endif
diff --git a/mit-pthreads/machdep/hpux-9.03/dirent.h b/mit-pthreads/machdep/hpux-9.03/dirent.h
new file mode 100755
index 00000000000..5f17af345db
--- /dev/null
+++ b/mit-pthreads/machdep/hpux-9.03/dirent.h
@@ -0,0 +1,61 @@
+/*-
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)dirent.h 5.18 (Berkeley) 2/23/91
+ */
+
+#ifndef _SYS_DIRENT_H_
+#define _SYS_DIRENT_H_
+
+/*
+ * A directory entry has a struct dirent at the front of it, containing its
+ * inode number, the length of the entry, and the length of the name
+ * contained in the entry. These are followed by the name padded to a 4
+ * byte boundary with null bytes. All names are guaranteed null terminated.
+ * The maximum length of a name in a directory is MAXNAMLEN.
+ */
+
+struct dirent {
+ u_long d_fileno; /* file number of entry */
+ u_short d_reclen; /* length of this record */
+ u_short d_namlen; /* length of string in d_name */
+#ifdef _POSIX_SOURCE
+ char d_name[255 + 1]; /* name must be no longer than this */
+#else
+#define MAXNAMLEN 255
+ char d_name[MAXNAMLEN + 1]; /* name must be no longer than this */
+#endif
+};
+
+#define d_ino d_fileno
+
+#endif /* !_SYS_DIRENT_H_ */
diff --git a/mit-pthreads/machdep/hpux-9.03/socket.h b/mit-pthreads/machdep/hpux-9.03/socket.h
new file mode 100755
index 00000000000..c7a37706940
--- /dev/null
+++ b/mit-pthreads/machdep/hpux-9.03/socket.h
@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 1982, 1985, 1986 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * @(#)socket.h 7.3 (Berkeley) 6/27/88
+ */
+
+/*
+ * Definitions related to sockets: types, address families, options.
+ */
+
+#include <sys/stdsyms.h>
+#include <pthread/posix.h>
+#include <sys/cdefs.h>
+
+/*
+ * Types of sockets
+ */
+#define SOCK_STREAM 1 /* stream socket */
+#define SOCK_DGRAM 2 /* datagram socket */
+#define SOCK_RAW 3 /* raw-protocol interface */
+#define SOCK_RDM 4 /* reliably-delivered message */
+#define SOCK_SEQPACKET 5 /* sequenced packet stream */
+
+/*
+ * Option flags per-socket.
+ */
+#define SO_DEBUG 0x0001 /* turn on debugging info recording */
+#define SO_ACCEPTCONN 0x0002 /* socket has had listen() */
+#define SO_REUSEADDR 0x0004 /* allow local address reuse */
+#define SO_KEEPALIVE 0x0008 /* keep connections alive */
+#define SO_DONTROUTE 0x0010 /* just use interface addresses */
+#define SO_BROADCAST 0x0020 /* permit sending of broadcast msgs */
+#define SO_USELOOPBACK 0x0040 /* bypass hardware when possible */
+#define SO_LINGER 0x0080 /* linger on close if data present */
+#define SO_OOBINLINE 0x0100 /* leave received OOB data in line */
+
+/*
+ * Additional options, not kept in so_options.
+ */
+#define SO_SNDBUF 0x1001 /* send buffer size */
+#define SO_RCVBUF 0x1002 /* receive buffer size */
+#define SO_SNDLOWAT 0x1003 /* send low-water mark */
+#define SO_RCVLOWAT 0x1004 /* receive low-water mark */
+#define SO_SNDTIMEO 0x1005 /* send timeout */
+#define SO_RCVTIMEO 0x1006 /* receive timeout */
+#define SO_ERROR 0x1007 /* get error status and clear */
+#define SO_TYPE 0x1008 /* get socket type */
+#define SO_SND_COPYAVOID 0x1009 /* avoid copy on send*/
+#define SO_RCV_COPYAVOID 0x100a /* avoid copy on rcv */
+
+/*
+ * Level number for (get/set)sockopt() to apply to socket itself.
+ */
+#define SOL_SOCKET 0xffff /* options for socket level */
+
+/*
+ * Address families.
+ */
+#define AF_UNSPEC 0 /* unspecified */
+#define AF_UNIX 1 /* local to host (pipes, portals) */
+#define AF_INET 2 /* internetwork: UDP, TCP, etc. */
+#define AF_IMPLINK 3 /* arpanet imp addresses */
+#define AF_PUP 4 /* pup protocols: e.g. BSP */
+#define AF_CHAOS 5 /* mit CHAOS protocols */
+#define AF_NS 6 /* XEROX NS protocols */
+#define AF_NBS 7 /* nbs protocols */
+#define AF_ECMA 8 /* european computer manufacturers */
+#define AF_DATAKIT 9 /* datakit protocols */
+#define AF_CCITT 10 /* CCITT protocols, X.25 etc */
+#define AF_SNA 11 /* IBM SNA */
+#define AF_DECnet 12 /* DECnet */
+#define AF_DLI 13 /* Direct data link interface */
+#define AF_LAT 14 /* LAT */
+#define AF_HYLINK 15 /* NSC Hyperchannel */
+#define AF_APPLETALK 16 /* Apple Talk */
+#define AF_OTS 17 /* Used for OSI in the ifnets */
+#define AF_NIT 18 /* NIT */
+
+#define AF_MAX 19
+
+/*
+ * Structure used by kernel to store most
+ * addresses.
+ */
+struct sockaddr {
+ unsigned short sa_family; /* address family */
+ char sa_data[14]; /* up to 14 bytes of direct address */
+};
+
+/*
+ * Structure used by kernel to pass protocol
+ * information in raw sockets.
+ */
+struct sockproto {
+ unsigned short sp_family; /* address family */
+ unsigned short sp_protocol; /* protocol */
+};
+
+/*
+ * Protocol families, same as address families for now.
+ */
+#define PF_UNSPEC AF_UNSPEC
+#define PF_UNIX AF_UNIX
+#define PF_INET AF_INET
+#define PF_IMPLINK AF_IMPLINK
+#define PF_PUP AF_PUP
+#define PF_CHAOS AF_CHAOS
+#define PF_NS AF_NS
+#define PF_NBS AF_NBS
+#define PF_ECMA AF_ECMA
+#define PF_DATAKIT AF_DATAKIT
+#define PF_CCITT AF_CCITT
+#define PF_SNA AF_SNA
+#define PF_DECnet AF_DECnet
+#define PF_DLI AF_DLI
+#define PF_LAT AF_LAT
+#define PF_HYLINK AF_HYLINK
+#define PF_APPLETALK AF_APPLETALK
+
+#define PF_MAX AF_MAX
+
+/*
+ * Maximum queue length specifiable by listen.
+ */
+#define SOMAXCONN 20
+
+/*
+ * Message header for recvmsg and sendmsg calls.
+ */
+struct msghdr {
+ caddr_t msg_name; /* optional address */
+ int msg_namelen; /* size of address */
+ struct iovec *msg_iov; /* scatter/gather array */
+ int msg_iovlen; /* # elements in msg_iov */
+ caddr_t msg_accrights; /* access rights sent/received */
+ int msg_accrightslen;
+};
+
+#define MSG_OOB 0x1 /* process out-of-band data */
+#define MSG_PEEK 0x2 /* peek at incoming message */
+#define MSG_DONTROUTE 0x4 /* send without using routing tables */
+
+#define MSG_MAXIOVLEN 16
+
+/*
+ * Functions
+ */
+
+__BEGIN_DECLS
+
+int accept __P_((int, struct sockaddr *, int *));
+int bind __P_((int, const struct sockaddr *, int));
+int connect __P_((int, const struct sockaddr *, int));
+int listen __P_((int, int));
+int socket __P_((int, int, int));
+
+__END_DECLS
+
diff --git a/mit-pthreads/machdep/hpux-9.03/stdtypes.h b/mit-pthreads/machdep/hpux-9.03/stdtypes.h
new file mode 100755
index 00000000000..2b22abbf818
--- /dev/null
+++ b/mit-pthreads/machdep/hpux-9.03/stdtypes.h
@@ -0,0 +1,74 @@
+/* @(#)stdtypes.h 1.6 90/01/04 SMI */
+
+/*
+ * Suppose you have an ANSI C or POSIX thingy that needs a typedef
+ * for thingy_t. Put it here and include this file wherever you
+ * define the thingy. This is used so that we don't have size_t in
+ * N (N > 1) different places and so that we don't have to have
+ * types.h included all the time and so that we can include this in
+ * the lint libs instead of termios.h which conflicts with ioctl.h.
+ */
+#ifndef __sys_stdtypes_h
+#define __sys_stdtypes_h
+
+#ifndef _SIGSET_T_
+#define _SIGSET_T_
+typedef int sigset_t; /* signal mask - may change */
+#endif
+
+#ifndef _SPEED_T_
+#define _SPEED_T_
+typedef unsigned int speed_t; /* tty speeds */
+#endif
+
+#ifndef _TCFLAG_T_
+#define _TCFLAG_T_
+typedef unsigned long tcflag_t; /* tty line disc modes */
+#endif
+
+#ifndef _CC_T_
+#define _CC_T_
+typedef unsigned char cc_t; /* tty control char */
+#endif
+
+#ifndef _PID_T_
+#define _PID_T_
+typedef int pid_t; /* process id */
+#endif
+
+#ifndef _MODE_T_
+#define _MODE_T_
+typedef unsigned short mode_t; /* file mode bits */
+#endif
+
+#ifndef _NLINK_T_
+#define _NLINK_T_
+typedef short nlink_t; /* links to a file */
+#endif
+
+#ifndef _CLOCK_T_
+#define _CLOCK_T_
+typedef long clock_t; /* units=ticks (typically 60/sec) */
+#endif
+
+#ifndef _TIME_T_
+#define _TIME_T_
+typedef long time_t; /* value = secs since epoch */
+#endif
+
+#ifndef _SIZE_T_
+#define _SIZE_T_
+typedef int size_t; /* ??? */
+#endif
+
+#ifndef _PTRDIFF_T_
+#define _PTRDIFF_T_
+typedef int ptrdiff_t; /* result of subtracting two pointers */
+#endif
+
+#ifndef _WCHAR_T_
+#define _WCHAR_T_
+typedef unsigned short wchar_t; /* big enough for biggest char set */
+#endif
+
+#endif /* !__sys_stdtypes_h */
diff --git a/mit-pthreads/machdep/hpux-9.03/time.h b/mit-pthreads/machdep/hpux-9.03/time.h
new file mode 100755
index 00000000000..544905b0749
--- /dev/null
+++ b/mit-pthreads/machdep/hpux-9.03/time.h
@@ -0,0 +1,228 @@
+/* $Header$ */
+
+#ifndef _SYS_TIME_INCLUDED
+#define _SYS_TIME_INCLUDED
+
+/* time.h: Definitions for time handling functions */
+
+#ifdef _KERNEL_BUILD
+#include "../h/stdsyms.h"
+#else /* ! _KERNEL_BUILD */
+#include <sys/stdsyms.h>
+#endif /* _KERNEL_BUILD */
+
+#include <sys/types.h>
+
+/* ANSI C time constants, types, and structures */
+
+#ifdef _INCLUDE__STDC__
+# define CLOCKS_PER_SEC 1000000
+
+# ifndef NULL
+# define NULL 0
+# endif
+
+# ifndef _CLOCK_T
+# define _CLOCK_T
+ typedef unsigned long clock_t;
+# endif /* _CLOCK_T */
+
+# ifndef _TIME_T
+# define _TIME_T
+ typedef long time_t;
+# endif /* _TIME_T */
+
+# ifndef _SIZE_T
+# define _SIZE_T
+ typedef unsigned int size_t;
+# endif /* _SIZE_T */
+
+ /* Structure used with gmtime(), localtime(), mktime(), strftime(). */
+ struct tm {
+ int tm_sec; /* second (0-61, allows for leap seconds) */
+ int tm_min; /* minute (0-59) */
+ int tm_hour; /* hour (0-23) */
+ int tm_mday; /* day of the month (1-31) */
+ int tm_mon; /* month (0-11) */
+ int tm_year; /* years since 1900 */
+ int tm_wday; /* day of the week (0-6) */
+ int tm_yday; /* day of the year (0-365) */
+ int tm_isdst; /* non-0 if daylight savings time is in effect */
+ };
+#endif /* _INCLUDE__STDC__ */
+
+
+/* Additional types needed for HP-UX */
+
+#ifdef _INCLUDE_HPUX_SOURCE
+# ifndef _STRUCT_TIMEVAL
+# define _STRUCT_TIMEVAL
+ /* Structure returned by gettimeofday(2) system call and others */
+ struct timeval {
+ unsigned long tv_sec; /* seconds */
+ long tv_usec; /* and microseconds */
+ };
+# endif /* _STRUCT_TIMEVAL */
+
+ /* Structure used to represent timezones for gettimeofday(2) and others */
+ struct timezone {
+ int tz_minuteswest; /* minutes west of Greenwich */
+ int tz_dsttime; /* type of dst correction */
+ };
+
+ /* Structure defining a timer setting. */
+ struct itimerval {
+ struct timeval it_interval; /* timer interval */
+ struct timeval it_value; /* current value */
+ };
+#endif /* _INCLUDE_HPUX_SOURCE */
+
+
+/* Function prototypes and external variable declarations */
+
+#ifndef _KERNEL
+#ifdef __cplusplus
+ extern "C" {
+#endif /* __cplusplus */
+
+#ifdef _INCLUDE__STDC__
+# ifdef _PROTOTYPES
+ extern double difftime(time_t, time_t);
+ extern time_t mktime(struct tm *);
+ extern time_t time(time_t *);
+ extern char *ctime(const time_t *);
+ extern struct tm *gmtime(const time_t *);
+ extern struct tm *localtime(const time_t *);
+ extern size_t strftime(char *, size_t, const char *, const struct tm *);
+# else /* not _PROTOTYPES */
+ extern double difftime();
+ extern time_t mktime();
+ extern time_t time();
+ extern char *ctime();
+ extern struct tm *gmtime();
+ extern struct tm *localtime();
+ extern size_t strftime();
+# endif /* not _PROTOTYPES */
+
+# ifdef _CLASSIC_ANSI_TYPES
+ extern long clock();
+# else /* not _CLASSIC_ANSI_TYPES */
+# ifdef _PROTOTYPES
+ extern clock_t clock(void);
+# else /* not _PROTOTYPES */
+ extern clock_t clock();
+# endif /* not _PROTOTYPES */
+# endif /* not _CLASSIC_ANSI_TYPES */
+#endif /* _INCLUDE__STDC__ */
+
+#ifdef _INCLUDE_POSIX_SOURCE
+# ifdef _PROTOTYPES
+ extern void tzset(void);
+# else /* not _PROTOTYPES */
+ extern void tzset();
+# endif /* not _PROTOTYPES */
+
+ extern char *tzname[2];
+#endif /* _INCLUDE_POSIX_SOURCE */
+
+
+#ifdef _INCLUDE_XOPEN_SOURCE
+# ifdef _PROTOTYPES
+ extern char *strptime(const char *, const char *, struct tm *);
+# else /* not _PROTOTYPES */
+ extern char *strptime();
+# endif /* not _PROTOTYPES */
+
+ extern long timezone;
+ extern int daylight;
+#endif /* _INCLUDE_XOPEN_SOURCE */
+
+
+#ifdef _INCLUDE_HPUX_SOURCE
+# ifdef _PROTOTYPES
+ extern struct tm *getdate(const char *);
+ extern char *nl_asctime(struct tm *, char *, int);
+ extern char *nl_ctime(long *, char *, int);
+ extern char *nl_ascxtime(struct tm *, char *);
+ extern char *nl_cxtime(long *, char *);
+ extern int getitimer(int, struct itimerval *);
+ extern int setitimer(int, const struct itimerval *, struct itimerval *);
+ extern int gettimeofday(struct timeval *, struct timezone *);
+ extern int settimeofday(const struct timeval *, const struct timezone *);
+ extern int select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
+ extern int stime(const time_t *);
+# else /* not _PROTOTYPES */
+ extern struct tm *getdate();
+ extern char *nl_asctime();
+ extern char *nl_ctime();
+ extern char *nl_ascxtime();
+ extern char *nl_cxtime();
+ extern int getitimer();
+ extern int setitimer();
+ extern int gettimeofday();
+ extern int settimeofday();
+ extern int select();
+ extern int stime();
+# endif /* not _PROTOTYPES */
+ extern int getdate_err;
+#endif /* _INCLUDE_HPUX_SOURCE */
+
+#ifdef __cplusplus
+ }
+#endif /* __cplusplus */
+#endif /* not _KERNEL */
+
+
+/*
+ * CLK_TCK is needed by the kernel, and also in the POSIX namespace.
+ */
+
+#ifdef _INCLUDE_POSIX_SOURCE
+# ifndef CLK_TCK
+# ifdef __hp9000s300
+# define CLK_TCK 50
+# endif /* __hp9000s300 */
+# ifdef __hp9000s800
+# define CLK_TCK 100
+# endif /* __hp9000s800 */
+# endif /* CLK_TCK */
+#endif
+
+
+/* Additional HP-UX structures, macros, and constants */
+
+#ifdef _INCLUDE_HPUX_SOURCE
+
+ /* Kernel instrumentation time value */
+ struct ki_timeval {
+ long tv_sec; /* seconds */
+ long tv_nunit; /* and native units */
+ };
+
+ /* Kinds of daylight savings time */
+# define DST_NONE 0 /* not on dst */
+# define DST_USA 1 /* USA style dst */
+# define DST_AUST 2 /* Australian style dst */
+# define DST_WET 3 /* Western European dst */
+# define DST_MET 4 /* Middle European dst */
+# define DST_EET 5 /* Eastern European dst */
+
+ /*
+ * Operations on timevals.
+ *
+ * NB: timercmp does not work for >= or <=.
+ */
+# define timerisset(tvp) ((tvp)->tv_sec || (tvp)->tv_usec)
+# define timercmp(tvp, uvp, cmp) \
+ ((tvp)->tv_sec cmp (uvp)->tv_sec || \
+ (tvp)->tv_sec == (uvp)->tv_sec && (tvp)->tv_usec cmp (uvp)->tv_usec)
+# define timerclear(tvp) ((tvp)->tv_sec = (tvp)->tv_usec = 0)
+
+ /* Names of the interval timers */
+# define ITIMER_REAL 0
+# define ITIMER_VIRTUAL 1
+# define ITIMER_PROF 2
+
+#endif /* _INCLUDE_HPUX_SOURCE */
+
+#endif /* _SYS_TIME_INCLUDED */
diff --git a/mit-pthreads/machdep/hpux-9.03/timers.h b/mit-pthreads/machdep/hpux-9.03/timers.h
new file mode 100755
index 00000000000..3c4d057976a
--- /dev/null
+++ b/mit-pthreads/machdep/hpux-9.03/timers.h
@@ -0,0 +1,68 @@
+/* ==== timers.h ============================================================
+ * Copyright (c) 1994 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ *
+ * Description : Basic timers header.
+ *
+ * 1.00 94/06/13 proven
+ * -Started coding this file.
+ */
+
+#ifndef _SYS_TIMERS_H_
+#define _SYS_TIMERS_H_
+
+#include <sys/types.h>
+#include <time.h>
+
+struct timespec {
+ time_t tv_sec;
+ long tv_nsec;
+};
+
+#define TIMEVAL_TO_TIMESPEC(tv, ts) { \
+ (ts)->tv_sec = (tv)->tv_sec; \
+ (ts)->tv_nsec = (tv)->tv_usec * 1000; \
+}
+#define TIMESPEC_TO_TIMEVAL(tv, ts) { \
+ (tv)->tv_sec = (ts)->tv_sec; \
+ (tv)->tv_usec = (ts)->tv_nsec / 1000; \
+}
+
+/*
+ * New functions
+ */
+
+__BEGIN_DECLS
+
+__END_DECLS
+
+#endif
diff --git a/mit-pthreads/machdep/hpux-9.03/uio.h b/mit-pthreads/machdep/hpux-9.03/uio.h
new file mode 100755
index 00000000000..d1ec4c94f22
--- /dev/null
+++ b/mit-pthreads/machdep/hpux-9.03/uio.h
@@ -0,0 +1,25 @@
+/* ==== uio.h ============================================================
+ * Copyright (c) 1994 by Chris Provenzano, proven@athena.mit.edu
+ *
+ * Description : Correct HP-UX header file.
+ */
+
+#ifndef _PTHREAD_UIO_H_
+#define _PTHREAD_UIO_H_
+
+#include <sys/cdefs.h>
+
+struct iovec {
+ void *iov_base;
+ size_t iov_len;
+};
+
+__BEGIN_DECLS
+
+int readv __P_((int, const struct iovec *, int));
+int writev __P_((int, const struct iovec *, int));
+
+__END_DECLS
+
+#endif
+
diff --git a/mit-pthreads/machdep/hpux-9.03/wait.h b/mit-pthreads/machdep/hpux-9.03/wait.h
new file mode 100755
index 00000000000..bca70d9f1ec
--- /dev/null
+++ b/mit-pthreads/machdep/hpux-9.03/wait.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 1982, 1986, 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)wait.h 8.1 (Berkeley) 6/2/93
+ * $Id$
+ */
+
+#ifndef _SYS_WAIT_H_
+#define _SYS_WAIT_H_
+
+/*
+ * Macros to test the exit status returned by wait
+ * and extract the relevant values.
+ */
+#define _W_INT(i) (i)
+#define WCOREFLAG 0200
+
+#define _WSTATUS(x) (_W_INT(x) & 0177)
+#define _WSTOPPED 0177 /* _WSTATUS if process is stopped */
+#define WIFSTOPPED(x) (_WSTATUS(x) == _WSTOPPED)
+#define WSTOPSIG(x) (_W_INT(x) >> 8)
+#define WIFSIGNALED(x) (_WSTATUS(x) != _WSTOPPED && _WSTATUS(x) != 0)
+#define WTERMSIG(x) (_WSTATUS(x))
+#define WIFEXITED(x) (_WSTATUS(x) == 0)
+#define WEXITSTATUS(x) (_W_INT(x) >> 8)
+#ifndef _POSIX_SOURCE
+#define WCOREDUMP(x) (_W_INT(x) & WCOREFLAG)
+
+#define W_EXITCODE(ret, sig) ((ret) << 8 | (sig))
+#define W_STOPCODE(sig) ((sig) << 8 | _WSTOPPED)
+#endif
+
+#define WNOHANG 1 /* dont hang in wait */
+#define WUNTRACED 2 /* tell about stopped, untraced children */
+
+#ifndef _POSIX_SOURCE
+/* POSIX extensions and 4.2/4.3 compatability: */
+
+/*
+ * Tokens for special values of the "pid" parameter to wait4.
+ */
+#define WAIT_ANY (-1) /* any process */
+#define WAIT_MYPGRP 0 /* any process in my process group */
+
+#define WSTOPPED _WSTOPPED
+#endif /* _POSIX_SOURCE */
+
+#include <sys/types.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+struct rusage; /* forward declaration */
+
+pid_t wait __P_((int *));
+pid_t waitpid __P_((pid_t, int *, int));
+
+#ifndef _POSIX_SOURCE
+pid_t wait3 __P_((int *, int, void *));
+#endif
+
+__END_DECLS
+
+#endif
diff --git a/mit-pthreads/machdep/i386-sco-3.2v5/__math.h b/mit-pthreads/machdep/i386-sco-3.2v5/__math.h
new file mode 100755
index 00000000000..4852683fcbf
--- /dev/null
+++ b/mit-pthreads/machdep/i386-sco-3.2v5/__math.h
@@ -0,0 +1,219 @@
+/* Copyright 1994-1995 The Santa Cruz Operation, Inc. All Rights Reserved. */
+
+
+#if defined(_NO_PROTOTYPE) /* Old, crufty environment */
+#include <oldstyle/__math.h>
+#elif defined(_XOPEN_SOURCE) || defined(_XPG4_VERS) /* Xpg4 environment */
+#include <xpg4/__math.h>
+#elif defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) /* Posix environment */
+#include <posix/__math.h>
+#elif _STRICT_ANSI /* Pure Ansi/ISO environment */
+#include <ansi/__math.h>
+#elif defined(_SCO_ODS_30) /* Old, Tbird compatible environment */
+#include <ods_30_compat/__math.h>
+#else /* Normal, default environment */
+/*
+ * Portions Copyright (C) 1983-1995 The Santa Cruz Operation, Inc.
+ * All Rights Reserved.
+ *
+ * The information in this file is provided for the exclusive use of
+ * the licensees of The Santa Cruz Operation, Inc. Such users have the
+ * right to use, modify, and incorporate this code into other products
+ * for purposes authorized by the license agreement provided they include
+ * this notice and the associated copyright notice with any such product.
+ * The information in this file is provided "AS IS" without warranty.
+ */
+
+/* Portions Copyright (c) 1990, 1991, 1992, 1993 UNIX System Laboratories, Inc. */
+/* Portions Copyright (c) 1979 - 1990 AT&T */
+/* All Rights Reserved */
+
+/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF */
+/* UNIX System Laboratories, Inc. */
+/* The copyright notice above does not evidence any */
+/* actual or intended publication of such source code. */
+
+#ifndef ___MATH_H
+#define ___MATH_H
+
+#pragma comment(exestr, "xpg4plus @(#) math.h 20.1 94/12/04 ")
+
+#pragma pack(4)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+extern double acos(double);
+extern double asin(double);
+extern double atan(double);
+extern double atan2(double, double);
+extern double cos(double);
+extern double sin(double);
+extern double tan(double);
+
+extern double cosh(double);
+extern double sinh(double);
+extern double tanh(double);
+
+extern double exp(double);
+extern double frexp(double, int *);
+extern double ldexp(double, int);
+extern double log(double);
+extern double log10(double);
+extern double modf(double, double *);
+
+extern double pow(double, double);
+extern double sqrt(double);
+
+extern double ceil(double);
+extern double fabs(double);
+extern double floor(double);
+extern double fmod(double, double);
+
+#ifndef HUGE_VAL
+extern const double __huge_val;
+#define HUGE_VAL (+__huge_val)
+#endif
+
+
+extern double erf(double);
+extern double erfc(double);
+extern double gamma(double);
+extern double hypot(double, double);
+extern double j0(double);
+extern double j1(double);
+extern double jn(int, double);
+extern double y0(double);
+extern double y1(double);
+extern double yn(int, double);
+extern double lgamma(double);
+extern int isnan(double);
+
+#define MAXFLOAT ((float)3.40282346638528860e+38)
+
+
+
+#define HUGE MAXFLOAT
+
+/*
+ * The following are all legal as XPG4 external functions but must only
+ * be declared in the non standards environments as they conflict with
+ * the user name space
+ */
+
+extern long double frexpl(long double, int *);
+extern long double ldexpl(long double, int);
+extern long double modfl(long double, long double *);
+
+extern float acosf(float);
+extern float asinf(float);
+extern float atanf(float);
+extern float atan2f(float, float);
+extern float cosf(float);
+extern float sinf(float);
+extern float tanf(float);
+
+extern float coshf(float);
+extern float sinhf(float);
+extern float tanhf(float);
+
+extern float expf(float);
+extern float logf(float);
+extern float log10f(float);
+
+extern float powf(float, float);
+extern float sqrtf(float);
+
+extern float ceilf(float);
+extern float fabsf(float);
+extern float floorf(float);
+extern float fmodf(float, float);
+extern float modff(float, float *);
+
+/* These are all extensions from XPG4 */
+
+extern double atof(const char *);
+extern double scalb(double, double);
+extern double logb(double);
+extern double log1p(double);
+extern double nextafter(double, double);
+extern double acosh(double);
+extern double asinh(double);
+extern double atanh(double);
+extern double cbrt(double);
+extern double copysign(double, double);
+extern double expm1(double);
+extern int ilogb(double);
+extern double remainder(double, double);
+extern double rint(double);
+extern int unordered(double, double);
+extern int finite(double);
+
+extern long double scalbl(long double, long double);
+extern long double logbl(long double);
+extern long double nextafterl(long double, long double);
+extern int unorderedl(long double, long double);
+extern int finitel(long double);
+
+
+
+
+extern int signgam;
+
+#define M_E 2.7182818284590452354
+#define M_LOG2E 1.4426950408889634074
+#define M_LOG10E 0.43429448190325182765
+#define M_LN2 0.69314718055994530942
+#define M_LN10 2.30258509299404568402
+#define M_PI 3.14159265358979323846
+#define M_PI_2 1.57079632679489661923
+#define M_PI_4 0.78539816339744830962
+#define M_1_PI 0.31830988618379067154
+#define M_2_PI 0.63661977236758134308
+#define M_2_SQRTPI 1.12837916709551257390
+#define M_SQRT2 1.41421356237309504880
+#define M_SQRT1_2 0.70710678118654752440
+
+
+
+#define _ABS(x) ((x) < 0 ? -(x) : (x))
+
+#define _REDUCE(TYPE, X, XN, C1, C2) { \
+ double x1 = (double)(TYPE)X, x2 = X - x1; \
+ X = x1 - (XN) * (C1); X += x2; X -= (XN) * (C2); }
+
+#define DOMAIN 1
+#define SING 2
+#define OVERFLOW 3
+#define UNDERFLOW 4
+#define TLOSS 5
+#define PLOSS 6
+
+#define _POLY1(x, c) ((c)[0] * (x) + (c)[1])
+#define _POLY2(x, c) (_POLY1((x), (c)) * (x) + (c)[2])
+#define _POLY3(x, c) (_POLY2((x), (c)) * (x) + (c)[3])
+#define _POLY4(x, c) (_POLY3((x), (c)) * (x) + (c)[4])
+#define _POLY5(x, c) (_POLY4((x), (c)) * (x) + (c)[5])
+#define _POLY6(x, c) (_POLY5((x), (c)) * (x) + (c)[6])
+#define _POLY7(x, c) (_POLY6((x), (c)) * (x) + (c)[7])
+#define _POLY8(x, c) (_POLY7((x), (c)) * (x) + (c)[8])
+#define _POLY9(x, c) (_POLY8((x), (c)) * (x) + (c)[9])
+
+
+#ifdef __cplusplus
+}
+inline int sqr(int i) {return(i*i);}
+inline double sqr(double i) {return(i*i);}
+
+#endif /* __cplusplus */
+
+#pragma pack()
+
+#if __cplusplus && !defined(PI)
+#define PI M_PI
+#endif /* __cplusplus */
+
+#endif /* _MATH_H */
+#endif
diff --git a/mit-pthreads/machdep/i386-sco-3.2v5/__signal.h b/mit-pthreads/machdep/i386-sco-3.2v5/__signal.h
new file mode 100755
index 00000000000..6a33d37a261
--- /dev/null
+++ b/mit-pthreads/machdep/i386-sco-3.2v5/__signal.h
@@ -0,0 +1,109 @@
+/* Copyright 1994-1995 The Santa Cruz Operation, Inc. All Rights Reserved. */
+
+
+#if defined(_NO_PROTOTYPE) /* Old, crufty environment */
+#include <sys/oldstyle/signal.h>
+#elif defined(_XOPEN_SOURCE) || defined(_XPG4_VERS) /* Xpg4 environment */
+#include <xpg4/signal.h>
+#elif defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) /* Posix environment */
+#include <sys/posix/__signal.h>
+#elif _STRICT_ANSI /* Pure Ansi/ISO environment */
+#include <sys/ansi/signal.h>
+#elif defined(_SCO_ODS_30) /* Old, Tbird compatible environment */
+#include <sys/ods_30_compat/signal.h>
+#else /* Normal, default environment */
+/*
+ * Portions Copyright (C) 1983-1995 The Santa Cruz Operation, Inc.
+ * All Rights Reserved.
+ *
+ * The information in this file is provided for the exclusive use of
+ * the licensees of The Santa Cruz Operation, Inc. Such users have the
+ * right to use, modify, and incorporate this code into other products
+ * for purposes authorized by the license agreement provided they include
+ * this notice and the associated copyright notice with any such product.
+ * The information in this file is provided "AS IS" without warranty.
+ */
+
+/* Portions Copyright (c) 1990, 1991, 1992, 1993 UNIX System Laboratories, Inc. */
+/* Portions Copyright (c) 1979 - 1990 AT&T */
+/* All Rights Reserved */
+
+/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF */
+/* UNIX System Laboratories, Inc. */
+/* The copyright notice above does not evidence any */
+/* actual or intended publication of such source code. */
+
+#ifndef ___SIGNAL_H
+#define ___SIGNAL_H
+
+#pragma comment(exestr, "xpg4plus @(#) signal.h 20.3 94/12/19 ")
+
+#ifndef _SIG_ATOMIC_T
+#define _SIG_ATOMIC_T
+ /* atomic entity for signal handling */
+typedef int sig_atomic_t;
+#endif
+
+extern const char * const _sys_siglist[];
+extern const int _sys_nsig;
+
+#ifndef _SYS_SIGNAL_H
+#include <sys/signal.h>
+#endif
+
+#define SignalBad ((SignalHandler)-1)
+#define SignalDefault ((SignalHandler)0)
+#define SignalIgnore ((SignalHandler)1)
+
+#define __sigmask(sig) (1 << ((sig) - 1))
+#define __SIGEMPTYSET (~SIGALL)
+#define __SIGFILLSET SIGALL
+#define __SIGADDSET(s,n) ((*s) |= (__sigmask(n)))
+#define __SIGDELSET(s,n) ((*s) &= ~(__sigmask(n)))
+#define __SIGISMEMBER(s,n) ((*s) & (__sigmask(n)))
+
+#if !defined(_SYS_TYPES_H)
+#include <sys/types.h>
+#endif
+
+
+#if __cplusplus
+extern "C" {
+#endif
+
+extern void (*signal(int, void(*)(int)))(int);
+extern int raise(int);
+
+extern void (*bsd_signal(int, void(*)(int)))(int);
+extern int ( *ssignal( int, int(*)(int) ) )(int);
+extern void ( *sigset( int, void(*)(int) ) )(int);
+extern int killpg(pid_t, int);
+#ifdef SS_ONSTACK /* Not defined on old versions of the OS */
+extern int sigaltstack(const stack_t *, stack_t *);
+extern int sigstack(struct sigstack *, struct sigstack *);
+#endif
+extern int sighold(int);
+extern int sigignore(int);
+extern int siginterrupt(int, int);
+extern int sigpause(int);
+extern int sigrelse(int);
+
+extern int (sigfillset)(sigset_t *);
+extern int (sigemptyset)(sigset_t *);
+extern int (sigaddset)(sigset_t *, int);
+extern int (sigdelset)(sigset_t *, int);
+extern int (sigismember)(const sigset_t *, int);
+extern int sigpending(sigset_t *);
+extern int sigsuspend(const sigset_t *);
+extern int sigprocmask(int, const sigset_t *, sigset_t *);
+extern int kill(pid_t, int);
+extern int sigaction(int, const struct sigaction *, struct sigaction *);
+
+#if __cplusplus
+};
+#endif
+
+
+#endif /* ___SIGNAL_H */
+
+#endif
diff --git a/mit-pthreads/machdep/i386-sco-3.2v5/__stdio.h b/mit-pthreads/machdep/i386-sco-3.2v5/__stdio.h
new file mode 100755
index 00000000000..f19672980ec
--- /dev/null
+++ b/mit-pthreads/machdep/i386-sco-3.2v5/__stdio.h
@@ -0,0 +1,113 @@
+/* Copyright 1994-1995 The Santa Cruz Operation, Inc. All Rights Reserved. */
+
+
+#if defined(_NO_PROTOTYPE) /* Old, crufty environment */
+#include <oldstyle/__stdio.h>
+#elif defined(_XOPEN_SOURCE) || defined(_XPG4_VERS) /* Xpg4 environment */
+#include <xpg4/__stdio.h>
+#elif defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) /* Posix environment */
+#include <posix/__stdio.h>
+#elif _STRICT_ANSI /* Pure Ansi/ISO environment */
+#include <ansi/__stdio.h>
+#elif defined(_SCO_ODS_30) /* Old, Tbird compatible environment */
+#include <ods_30_compat/__stdio.h>
+#else /* Normal, default environment */
+/*
+ * Portions Copyright (C) 1984-1995 The Santa Cruz Operation, Inc.
+ * All Rights Reserved.
+ *
+ * The information in this file is provided for the exclusive use of
+ * the licensees of The Santa Cruz Operation, Inc. Such users have the
+ * right to use, modify, and incorporate this code into other products
+ * for purposes authorized by the license agreement provided they include
+ * this notice and the associated copyright notice with any such product.
+ * The information in this file is provided "AS IS" without warranty.
+ */
+
+/* Portions Copyright (c) 1990, 1991, 1992, 1993 UNIX System Laboratories, Inc. */
+/* Portions Copyright (c) 1979 - 1990 AT&T */
+/* All Rights Reserved */
+
+/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF */
+/* UNIX System Laboratories, Inc. */
+/* The copyright notice above does not evidence any */
+/* actual or intended publication of such source code. */
+
+#ifndef ___STDIO_H
+#define ___STDIO_H
+
+#pragma comment(exestr, "xpg4plus @(#) stdio.h 20.1 94/12/04 ")
+
+#pragma pack(4)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef _SIZE_T
+#define _SIZE_T
+typedef unsigned int size_t;
+#endif
+
+#ifndef _FPOS_T
+#define _FPOS_T
+typedef long fpos_t;
+#endif
+
+#ifndef _WCHAR_T
+#define _WCHAR_T
+typedef long wchar_t;
+#endif
+
+#ifndef _WINT_T
+#define _WINT_T
+typedef long wint_t;
+#endif
+
+#ifndef NULL
+#define NULL 0
+#endif /* NULL */
+
+#ifndef EOF
+#define EOF (-1)
+#endif
+
+#define SEEK_SET 0
+#define SEEK_CUR 1
+#define SEEK_END 2
+
+#ifndef TMP_MAX
+#define TMP_MAX 17576 /* 26 * 26 * 26 */
+#endif
+
+#define BUFSIZ 1024 /* default buffer size */
+
+
+#define _IOEOF 0020 /* EOF reached on read */
+#define _IOERR 0040 /* I/O error from system */
+
+#define _IOREAD 0001 /* currently reading */
+#define _IOWRT 0002 /* currently writing */
+#define _IORW 0200 /* opened for reading and writing */
+#define _IOMYBUF 0010 /* stdio malloc()'d buffer */
+
+#define _SBFSIZ 8
+
+#define L_cuserid 9
+
+/* Non name space polluting version of above */
+#define _P_tmpdir "/usr/tmp/"
+
+#ifndef _VA_LIST
+#define _VA_LIST char *
+#endif
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#pragma pack()
+
+#endif /* ___STDIO_H */
+#endif
diff --git a/mit-pthreads/machdep/i386-sco-3.2v5/__stdlib.h b/mit-pthreads/machdep/i386-sco-3.2v5/__stdlib.h
new file mode 100755
index 00000000000..db6a8a56151
--- /dev/null
+++ b/mit-pthreads/machdep/i386-sco-3.2v5/__stdlib.h
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 1984-1995 The Santa Cruz Operation, Inc.
+ * All Rights Reserved.
+ *
+ * The information in this file is provided for the exclusive use of
+ * the licensees of The Santa Cruz Operation, Inc. Such users have the
+ * right to use, modify, and incorporate this code into other products
+ * for purposes authorized by the license agreement provided they include
+ * this notice and the associated copyright notice with any such product.
+ * The information in this file is provided "AS IS" without warranty.
+ */
+
+/* Portions Copyright (c) 1990, 1991, 1992, 1993 UNIX System Laboratories, Inc. */
+/* Portions Copyright (c) 1979 - 1990 AT&T */
+/* All Rights Reserved */
+
+/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF */
+/* UNIX System Laboratories, Inc. */
+/* The copyright notice above does not evidence any */
+/* actual or intended publication of such source code. */
+
+#ifndef ___STDLIB_H
+#define ___STDLIB_H
+
+#pragma comment(exestr, "posix @(#) stdlib.h 20.1 94/12/04 ")
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#pragma pack(4)
+
+#ifndef _DIV_T
+#define _DIV_T
+typedef struct
+{
+ int quot;
+ int rem;
+} div_t;
+#endif
+
+#ifndef _LDIV_T
+#define _LDIV_T
+typedef struct
+{
+ long quot;
+ long rem;
+} ldiv_t;
+#endif
+
+#ifndef _SIZE_T
+#define _SIZE_T
+typedef unsigned int size_t;
+#endif
+
+#if !defined(_SSIZE_T)
+#define _SSIZE_T
+typedef int ssize_t;
+#endif
+
+#ifndef _WCHAR_T
+#define _WCHAR_T
+typedef long wchar_t;
+#endif
+
+#ifndef NULL
+#define NULL 0
+#endif /* NULL */
+
+#define EXIT_FAILURE 1
+#define EXIT_SUCCESS 0
+#define RAND_MAX 077777
+
+
+
+extern unsigned char __ctype[];
+
+#define MB_CUR_MAX ((int)__ctype[520])
+
+extern double atof(const char *);
+extern int atoi(const char *);
+extern long atol(const char *);
+extern double strtod(const char *, char **);
+extern float strtof(const char *, char **);
+extern long strtol(const char *, char **, int);
+extern unsigned long strtoul(const char *, char **, int);
+
+extern int rand(void);
+extern void srand(unsigned int);
+
+extern void *calloc(size_t, size_t);
+extern void free(void *);
+extern void *malloc(size_t);
+extern void *realloc(void *, size_t);
+
+extern void abort(void);
+extern void exit(int);
+extern char *getenv(const char *);
+extern int system(const char *);
+
+extern void *bsearch(const void *, const void *, size_t, size_t,
+ int (*)(const void *, const void *));
+extern void qsort(void *, size_t, size_t,
+ int (*)(const void *, const void *));
+
+#ifdef __cplusplus
+#ifndef _ABS_INL
+#define _ABS_INL
+inline int (abs)(int i) {return (i > 0) ? i : -i;}
+#endif
+#else
+extern int (abs)(int); /* Protect from macro definitions */
+#endif
+
+extern div_t div(int, int);
+extern long labs(long);
+extern ldiv_t ldiv(long, long);
+
+extern int mbtowc(wchar_t *, const char *, size_t);
+extern int mblen(const char *, size_t);
+extern int wctomb(char *, wchar_t);
+
+extern size_t mbstowcs(wchar_t *, const char *, size_t);
+extern size_t wcstombs(char *, const wchar_t *, size_t);
+
+
+
+
+#define mblen(s, n) mbtowc((wchar_t *)0, s, n)
+
+#ifdef __cplusplus
+}
+#endif
+
+#pragma pack()
+
+#endif /* ___STDLIB_H */
diff --git a/mit-pthreads/machdep/i386-sco-3.2v5/__string.h b/mit-pthreads/machdep/i386-sco-3.2v5/__string.h
new file mode 100755
index 00000000000..e4bb93afe5a
--- /dev/null
+++ b/mit-pthreads/machdep/i386-sco-3.2v5/__string.h
@@ -0,0 +1,125 @@
+/* Copyright 1994-1995 The Santa Cruz Operation, Inc. All Rights Reserved. */
+
+
+#if defined(_NO_PROTOTYPE) /* Old, crufty environment */
+#include <oldstyle/string.h>
+#elif defined(_XOPEN_SOURCE) || defined(_XPG4_VERS) /* Xpg4 environment */
+#include <xpg4/string.h>
+#elif defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) /* Posix environment */
+#include <posix/string.h>
+#elif _STRICT_ANSI /* Pure Ansi/ISO environment */
+#include <ansi/string.h>
+#elif defined(_SCO_ODS_30) /* Old, Tbird compatible environment */
+#include <ods_30_compat/string.h>
+#else /* Normal, default environment */
+/*
+ * Portions Copyright (C) 1983-1995 The Santa Cruz Operation, Inc.
+ * All Rights Reserved.
+ *
+ * The information in this file is provided for the exclusive use of
+ * the licensees of The Santa Cruz Operation, Inc. Such users have the
+ * right to use, modify, and incorporate this code into other products
+ * for purposes authorized by the license agreement provided they include
+ * this notice and the associated copyright notice with any such product.
+ * The information in this file is provided "AS IS" without warranty.
+ */
+
+/* Portions Copyright (c) 1990, 1991, 1992, 1993 UNIX System Laboratories, Inc. */
+/* Portions Copyright (c) 1979 - 1990 AT&T */
+/* All Rights Reserved */
+
+/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF */
+/* UNIX System Laboratories, Inc. */
+/* The copyright notice above does not evidence any */
+/* actual or intended publication of such source code. */
+
+#ifndef ___STRING_H
+#define ___STRING_H
+
+#pragma comment(exestr, "xpg4plus @(#) string.h 20.1 94/12/04 ")
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef _SIZE_T
+#define _SIZE_T
+typedef unsigned int size_t;
+#endif
+
+#ifndef NULL
+#define NULL 0
+#endif /* NULL */
+
+
+
+extern void *memchr(const void *, int, size_t);
+extern void *memcpy(void *, const void *, size_t);
+extern void *memccpy(void *, const void *, int, size_t);
+extern void *memmove(void *, const void *, size_t);
+extern void *memset(void *, int, size_t);
+
+extern char *strchr(const char *, int);
+extern char *strcpy(char *, const char *);
+extern char *strncpy(char *, const char *, size_t);
+extern char *strcat(char *, const char *);
+extern char *strncat(char *, const char *, size_t);
+extern char *strpbrk(const char *, const char *);
+extern char *strrchr(const char *, int);
+extern char *strstr(const char *, const char *);
+extern char *strtok(char *, const char *);
+extern char *strtok_r(char *, const char *, char **);
+extern char *strerror(int);
+extern char *strlist(char *, const char *, ...);
+
+extern int memcmp(const void *, const void *, size_t);
+extern int strcmp(const char *, const char *);
+extern int strcoll(const char *, const char *);
+extern int strncmp(const char *, const char *, size_t);
+
+extern void perror(const char *);
+extern char *strdup(const char *);
+extern int strncoll(const char *, const char *, int);
+extern size_t strnxfrm(char *, const char *, size_t , int);
+
+extern size_t strxfrm(char *, const char *, size_t);
+extern size_t strcspn(const char *, const char *);
+extern size_t strspn(const char *, const char *);
+extern size_t strlen(const char *);
+
+#ifdef __USLC__
+#pragma int_to_unsigned strcspn
+#pragma int_to_unsigned strspn
+#pragma int_to_unsigned strlen
+#endif
+
+#if !defined(__cplusplus) && defined(__USLC__)
+/* Use intrinsic ??? */
+#ifndef strlen
+#define strlen __std_hdr_strlen
+#endif
+#ifndef strcpy
+#define strcpy __std_hdr_strcpy
+#endif
+#ifndef strncpy
+#define strncpy __std_hdr_strncpy
+#endif
+#endif
+
+
+extern int ffs(int);
+/*
+ * The following two functions were withdrawn in XPG3,
+ * but are provided for backwards compatibility.
+ */
+extern int nl_strcmp(char *, char *);
+extern int nl_strncmp(char *, char *, int n);
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ___STRING_H */
+#endif
diff --git a/mit-pthreads/machdep/i386-sco-3.2v5/__time.h b/mit-pthreads/machdep/i386-sco-3.2v5/__time.h
new file mode 100755
index 00000000000..4aeee737601
--- /dev/null
+++ b/mit-pthreads/machdep/i386-sco-3.2v5/__time.h
@@ -0,0 +1,141 @@
+/* Copyright 1994-1995 The Santa Cruz Operation, Inc. All Rights Reserved. */
+
+
+#if defined(_NO_PROTOTYPE) /* Old, crufty environment */
+#include <oldstyle/time.h>
+#elif defined(_XOPEN_SOURCE) || defined(_XPG4_VERS) /* Xpg4 environment */
+#include <xpg4/time.h>
+#elif defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) /* Posix environment */
+#include <posix/time.h>
+#elif _STRICT_ANSI /* Pure Ansi/ISO environment */
+#include <ansi/time.h>
+#elif defined(_SCO_ODS_30) /* Old, Tbird compatible environment */
+#include <ods_30_compat/time.h>
+#else /* Normal, default environment */
+/*
+ * Portions Copyright (C) 1983-1995 The Santa Cruz Operation, Inc.
+ * All Rights Reserved.
+ *
+ * The information in this file is provided for the exclusive use of
+ * the licensees of The Santa Cruz Operation, Inc. Such users have the
+ * right to use, modify, and incorporate this code into other products
+ * for purposes authorized by the license agreement provided they include
+ * this notice and the associated copyright notice with any such product.
+ * The information in this file is provided "AS IS" without warranty.
+ */
+
+/* Portions Copyright (c) 1990, 1991, 1992, 1993 UNIX System Laboratories, Inc. */
+/* Portions Copyright (c) 1979 - 1990 AT&T */
+/* All Rights Reserved */
+
+/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF */
+/* UNIX System Laboratories, Inc. */
+/* The copyright notice above does not evidence any */
+/* actual or intended publication of such source code. */
+
+#ifndef ___TIME_H
+#define ___TIME_H
+
+#pragma comment(exestr, "xpg4plus @(#) time.h 20.2 95/01/04 ")
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef NULL
+#define NULL 0
+#endif /* NULL */
+
+#ifndef _SIZE_T
+#define _SIZE_T
+typedef unsigned int size_t;
+#endif
+#ifndef _CLOCK_T
+#define _CLOCK_T
+typedef long clock_t;
+#endif
+#ifndef _TIME_T
+#define _TIME_T
+typedef long time_t;
+#endif
+
+#ifdef _POSIXTIMERS
+#include <sys/sudstime.h>
+#endif
+
+#define CLOCKS_PER_SEC 1000000 /* As required by XPG4 and friends */
+
+#pragma pack(4)
+
+#ifndef _STRUCT_TM
+#define _STRUCT_TM
+struct tm
+{
+ int tm_sec;
+ int tm_min;
+ int tm_hour;
+ int tm_mday;
+ int tm_mon;
+ int tm_year;
+ int tm_wday;
+ int tm_yday;
+ int tm_isdst;
+#define LTZNMAX 50
+ long tm_tzadj;
+ char tm_name[LTZNMAX]; /* name of timezone */
+};
+
+#pragma pack()
+#endif /* _STRUCT_TM */
+
+
+extern clock_t clock(void);
+extern double difftime(time_t, time_t);
+extern time_t mktime(struct tm *);
+extern time_t time(time_t *);
+extern char *asctime(const struct tm *);
+extern char *ctime (const time_t *);
+extern struct tm *gmtime(const time_t *);
+extern struct tm *localtime(const time_t *);
+extern size_t strftime(char *, size_t, const char *, const struct tm *);
+
+
+extern void tzset(void);
+extern char *tzname[];
+
+#ifndef CLK_TCK
+#define CLK_TCK _sysconf(2) /* 2 is _SC_CLK_TCK */
+#endif
+
+extern long timezone;
+extern int daylight;
+extern char *strptime(const char *, const char *, struct tm *);
+
+
+
+
+#include <sys/timeb.h>
+extern int ftime ( struct timeb * );
+extern char * nl_cxtime( long *, char * );
+extern char * nl_ascxtime( struct tm *, char * );
+extern int cftime(char *, const char *, const time_t *);
+extern int ascftime(char *, const char *, const struct tm *);
+extern long altzone;
+extern struct tm *getdate(const char *);
+extern int getdate_err;
+extern char *asctime_r(const struct tm *, char *,int);
+extern char *ctime_r(const time_t *, char *,int);
+extern struct tm *localtime_r(const time_t *, struct tm *);
+extern struct tm *gmtime_r(const time_t *, struct tm *);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#ifndef difftime
+#define difftime(t1, t0) ((double)((t1) - (t0)))
+#endif
+
+#endif /* ___TIME_H */
+#endif
diff --git a/mit-pthreads/machdep/i386-sco-3.2v5/__unistd.h b/mit-pthreads/machdep/i386-sco-3.2v5/__unistd.h
new file mode 100755
index 00000000000..408886301f5
--- /dev/null
+++ b/mit-pthreads/machdep/i386-sco-3.2v5/__unistd.h
@@ -0,0 +1,48 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)stdlib.h 5.13 (Berkeley) 6/4/91
+ * __unistd.h,v 1.1 1995/01/03 12:54:54 proven Exp
+ */
+
+#ifndef ___UNISTD_H_
+#define ___UNISTD_H_
+
+#include <sys/types.h>
+#include <stddef.h>
+
+#ifndef MAXPATHLEN
+#define MAXPATHLEN 1024
+#endif
+
+#endif
+
diff --git a/mit-pthreads/machdep/i386-sco-3.2v5/compat.h b/mit-pthreads/machdep/i386-sco-3.2v5/compat.h
new file mode 100755
index 00000000000..3befbffa68d
--- /dev/null
+++ b/mit-pthreads/machdep/i386-sco-3.2v5/compat.h
@@ -0,0 +1,46 @@
+/* ==== compat.h ============================================================
+ * Copyright (c) 1994 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * compat.h,v 1.52 1995/10/20 09:32:56 proven Exp
+ *
+ * Description : Basic timers header.
+ *
+ * 1.00 94/06/13 proven
+ * -Started coding this file.
+ */
+
+#ifndef _SYS_COMPAT_H_
+#define _SYS_COMPAT_H_
+
+#include <sys/types.h>
+
+#define omsghdr msghdr
+#endif
diff --git a/mit-pthreads/machdep/i386-sco-3.2v5/dirent.h b/mit-pthreads/machdep/i386-sco-3.2v5/dirent.h
new file mode 100755
index 00000000000..6f6804590bb
--- /dev/null
+++ b/mit-pthreads/machdep/i386-sco-3.2v5/dirent.h
@@ -0,0 +1,145 @@
+/* Copyright 1994-1995 The Santa Cruz Operation, Inc. All Rights Reserved. */
+
+
+#if defined(_NO_PROTOTYPE) /* Old, crufty environment */
+#include <oldstyle/dirent.h>
+#elif defined(_XOPEN_SOURCE) || defined(_XPG4_VERS) /* Xpg4 environment */
+#include <xpg4/dirent.h>
+#elif defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) /* Posix environment */
+#include <posix/dirent.h>
+#elif defined(_SCO_ODS_30) /* Old, Tbird compatible environment */
+#include <ods_30_compat/dirent.h>
+#else /* Normal, default environment */
+/*
+ * Portions Copyright (C) 1983-1995 The Santa Cruz Operation, Inc.
+ * All Rights Reserved.
+ *
+ * The information in this file is provided for the exclusive use of
+ * the licensees of The Santa Cruz Operation, Inc. Such users have the
+ * right to use, modify, and incorporate this code into other products
+ * for purposes authorized by the license agreement provided they include
+ * this notice and the associated copyright notice with any such product.
+ * The information in this file is provided "AS IS" without warranty.
+ */
+
+/* Portions Copyright (c) 1990, 1991, 1992, 1993 UNIX System Laboratories, Inc. */
+/* Portions Copyright (c) 1979 - 1990 AT&T */
+/* All Rights Reserved */
+
+/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF */
+/* UNIX System Laboratories, Inc. */
+/* The copyright notice above does not evidence any */
+/* actual or intended publication of such source code. */
+
+#ifndef _DIRENT_H
+#define _DIRENT_H
+
+#pragma comment(exestr, "xpg4plus @(#) dirent.h 20.1 94/12/04 ")
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#pragma pack(4)
+
+#define MAXNAMLEN 512 /* maximum filename length */
+#ifndef MAXPATHLEN
+#define MAXPATHLEN 1024
+#endif
+#undef DIRBLKSIZ
+#define DIRBLKSIZ 1048 /* buffer size for fs-indep. dirs */
+
+#ifndef _SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#ifndef _SYS_DIRENT_H
+#define _SYS_DIRENT_H
+#ifdef __STDC__
+#pragma comment(exestr, "@(#) dirent.h 25.8 94/09/22 ")
+#else
+#ident "@(#) dirent.h 25.8 94/09/22 "
+#endif
+/*
+ * Copyright (C) 1988-1994 The Santa Cruz Operation, Inc.
+ * All Rights Reserved.
+ * The information in this file is provided for the exclusive use of
+ * the licensees of The Santa Cruz Operation, Inc. Such users have the
+ * right to use, modify, and incorporate this code into other products
+ * for purposes authorized by the license agreement provided they include
+ * this notice and the associated copyright notice with any such product.
+ * The information in this file is provided "AS IS" without warranty.
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988 AT&T */
+/* All Rights Reserved */
+
+/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T */
+/* The copyright notice above does not evidence any */
+/* actual or intended publication of such source code. */
+
+/* #ident "@)#(head.sys:dirent.h 1.3" */
+
+/*
+ * The following structure defines the file
+ * system independent directory entry.
+ *
+ */
+
+#include <sys/types.h>
+
+#ifdef _M_I386
+#pragma pack(4)
+#else
+#pragma pack(2)
+#endif
+
+#ifdef _INKERNEL
+/*
+ * dirent used by the kernel
+ */
+struct dirent {
+ ino32_t d_ino; /* inode number of entry */
+ off_t d_off; /* offset of disk directory entry */
+ unsigned short d_reclen; /* length of this record */
+ char d_name[MAXNAMLEN+1]; /* name of file */
+};
+
+#else /* !_INKERNEL */
+/*
+ * dirent as used by application code
+ * For now leave the declaration as is. When the new development system
+ * is implemented, ino_t may be ushort or ulong. If ino_t is ulong, there
+ * will be no d_pad field.
+ */
+struct dirent /* data from readdir() */
+ {
+#if defined(_IBCS2)
+ long d_ino;
+#else /* !_IBCS2 */
+ ino_t d_ino; /* inode number of entry */
+#if defined(_INO_16_T)
+ short d_pad; /* because ino_t is ushort */
+#endif /* defined(_INO_16_T) */
+#endif /* defined(_IBCS2) */
+ off_t d_off; /* offset of disk directory entry */
+ unsigned short d_reclen; /* length of this record */
+ char d_name[MAXNAMLEN+1]; /* name of file */
+ };
+#endif /* _INKERNEL */
+
+typedef struct dirent dirent_t;
+
+#pragma pack()
+#endif /* _SYS_DIRENT_H */
+
+#define d_fileno d_ino
+#define d_namlen d_reclen
+
+#ifdef __cplusplus
+}
+#endif
+
+#pragma pack()
+
+#endif /* _DIRENT_H */
+#endif
diff --git a/mit-pthreads/machdep/i386-sco-3.2v5/posix/__signal.h b/mit-pthreads/machdep/i386-sco-3.2v5/posix/__signal.h
new file mode 100755
index 00000000000..5680fc1491a
--- /dev/null
+++ b/mit-pthreads/machdep/i386-sco-3.2v5/posix/__signal.h
@@ -0,0 +1,69 @@
+/*
+ * Portions Copyright (C) 1983-1995 The Santa Cruz Operation, Inc.
+ * All Rights Reserved.
+ *
+ * The information in this file is provided for the exclusive use of
+ * the licensees of The Santa Cruz Operation, Inc. Such users have the
+ * right to use, modify, and incorporate this code into other products
+ * for purposes authorized by the license agreement provided they include
+ * this notice and the associated copyright notice with any such product.
+ * The information in this file is provided "AS IS" without warranty.
+ */
+
+/* Portions Copyright (c) 1990, 1991, 1992, 1993 UNIX System Laboratories, Inc. */
+/* Portions Copyright (c) 1979 - 1990 AT&T */
+/* All Rights Reserved */
+
+/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF */
+/* UNIX System Laboratories, Inc. */
+/* The copyright notice above does not evidence any */
+/* actual or intended publication of such source code. */
+
+#ifndef ___SIGNAL_H
+#define ___SIGNAL_H
+
+#pragma comment(exestr, "posix @(#) signal.h 20.3 94/12/19 ")
+
+#ifndef _SIG_ATOMIC_T
+#define _SIG_ATOMIC_T
+ /* atomic entity for signal handling */
+typedef int sig_atomic_t;
+#endif
+
+
+#ifndef _SYS_SIGNAL_H
+#include <sys/signal.h>
+#endif
+
+#if !defined(_SYS_TYPES_H)
+#include <sys/types.h>
+#endif
+
+
+#if __cplusplus
+extern "C" {
+#endif
+
+extern void (*signal(int, void(*)(int)))(int);
+extern int raise(int);
+
+
+
+extern int (sigfillset)(sigset_t *);
+extern int (sigemptyset)(sigset_t *);
+extern int (sigaddset)(sigset_t *, int);
+extern int (sigdelset)(sigset_t *, int);
+extern int (sigismember)(const sigset_t *, int);
+extern int sigpending(sigset_t *);
+extern int sigsuspend(const sigset_t *);
+extern int sigprocmask(int, const sigset_t *, sigset_t *);
+extern int kill(pid_t, int);
+extern int sigaction(int, const struct sigaction *, struct sigaction *);
+
+#if __cplusplus
+};
+#endif
+
+
+#endif /* ___SIGNAL_H */
+
diff --git a/mit-pthreads/machdep/i386-sco-3.2v5/socket.h b/mit-pthreads/machdep/i386-sco-3.2v5/socket.h
new file mode 100755
index 00000000000..4a53c7176f9
--- /dev/null
+++ b/mit-pthreads/machdep/i386-sco-3.2v5/socket.h
@@ -0,0 +1,490 @@
+/* @(#)socket.h 6.23 7/18/94 - STREAMware TCP/IP source */
+/*
+ * Copyrighted as an unpublished work.
+ * (c) Copyright 1987-1994 Legent Corporation
+ * All rights reserved.
+ *
+ * RESTRICTED RIGHTS
+ *
+ * These programs are supplied under a license. They may be used,
+ * disclosed, and/or copied only as permitted under such license
+ * agreement. Any copy must contain the above copyright notice and
+ * this restricted rights notice. Use, copying, and/or disclosure
+ * of the programs is strictly prohibited unless otherwise provided
+ * in the license agreement.
+ *
+ */
+/* SCCS IDENTIFICATION */
+/*
+ * Copyright (c) 1985 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef __sys_socket_h
+#define __sys_socket_h
+
+#if !defined(FD_SETSIZE)
+/* Pick up select stuff from standard system include */
+#include <sys/types.h>
+#endif
+
+/* socket.h 6.1 83/07/29 */
+
+/*
+ * Definitions related to sockets: types, address families, options.
+ */
+
+/*
+ * Types
+ */
+#define SOCK_STREAM 1 /* stream socket */
+#define SOCK_DGRAM 2 /* datagram socket */
+#define SOCK_RAW 3 /* raw-protocol interface */
+#define SOCK_RDM 4 /* reliably-delivered message */
+#define SOCK_SEQPACKET 5 /* sequenced packet stream */
+
+/*
+ * Option flags per-socket.
+ */
+#define SO_DEBUG 0x0001 /* turn on debugging info recording */
+#define SO_ACCEPTCONN 0x0002 /* socket has had listen() */
+#define SO_REUSEADDR 0x0004 /* allow local address reuse */
+#define SO_KEEPALIVE 0x0008 /* keep connections alive */
+#define SO_DONTROUTE 0x0010 /* just use interface addresses */
+#define SO_BROADCAST 0x0020 /* permit sending of broadcast msgs */
+#define SO_USELOOPBACK 0x0040 /* bypass hardware when possible */
+#define SO_LINGER 0x0080 /* linger on close if data present */
+#define SO_OOBINLINE 0x0100 /* leave received OOB data in line */
+#define SO_ORDREL 0x0200 /* give use orderly release */
+#define SO_IMASOCKET 0x0400 /* use socket semantics (affects bind) */
+#define SO_MGMT 0x0800 /* => it is used for mgmt. purposes */
+#define SO_REUSEPORT 0x1000 /* allow local port reuse */
+
+/*
+ * Additional options, not kept in so_options.
+ */
+#define SO_SNDBUF 0x1001 /* send buffer size */
+#define SO_RCVBUF 0x1002 /* receive buffer size */
+#define SO_SNDLOWAT 0x1003 /* send low-water mark */
+#define SO_RCVLOWAT 0x1004 /* receive low-water mark */
+#define SO_SNDTIMEO 0x1005 /* send timeout */
+#define SO_RCVTIMEO 0x1006 /* receive timeout */
+#define SO_ERROR 0x1007 /* get error status and clear */
+#define SO_TYPE 0x1008 /* get socket type */
+#define SO_PROTOTYPE 0x1009 /* get/set protocol type */
+
+/*
+ * Structure used for manipulating linger option.
+ */
+struct linger {
+ int l_onoff; /* option on/off */
+ int l_linger; /* linger time */
+};
+
+/*
+ * Level number for (get/set)sockopt() to apply to socket itself.
+ */
+#define SOL_SOCKET 0xffff /* options for socket level */
+
+/*
+ * An option specification consists of an opthdr, followed by the value of
+ * the option. An options buffer contains one or more options. The len
+ * field of opthdr specifies the length of the option value in bytes. This
+ * length must be a multiple of sizeof(long) (use OPTLEN macro).
+ */
+
+struct opthdr {
+ long level; /* protocol level affected */
+ long name; /* option to modify */
+ long len; /* length of option value */
+};
+
+#define OPTLEN(x) ((((x) + sizeof(long) - 1) / sizeof(long)) * sizeof(long))
+#define OPTVAL(opt) ((char *)(opt + 1))
+
+#if defined(INKERNEL) || defined(_KERNEL) || defined(_INKERNEL)
+/*
+ * the optdefault structure is used for internal tables of option default
+ * values.
+ */
+struct optdefault {
+ int optname;/* the option */
+ char *val; /* ptr to default value */
+ int len; /* length of value */
+};
+
+/*
+ * the opproc structure is used to build tables of options processing
+ * functions for in_dooptions().
+ */
+struct opproc {
+ int level; /* options level this function handles */
+ int (*func) (); /* the function */
+};
+#endif
+
+/*
+ * Address families.
+ */
+#define AF_UNSPEC 0 /* unspecified */
+#define AF_UNIX 1 /* local to host (pipes, portals) */
+#define AF_INET 2 /* internetwork: UDP, TCP, etc. */
+#define AF_IMPLINK 3 /* arpanet imp addresses */
+#define AF_PUP 4 /* pup protocols: e.g. BSP */
+#define AF_CHAOS 5 /* mit CHAOS protocols */
+#define AF_NS 6 /* XEROX NS protocols */
+#define AF_ISO 7 /* ISO protocols */
+#define AF_OSI AF_ISO
+#define AF_ECMA 8 /* european computer manufacturers */
+#define AF_DATAKIT 9 /* datakit protocols */
+#define AF_CCITT 10 /* CCITT protocols, X.25 etc */
+#define AF_SNA 11 /* IBM SNA */
+#define AF_DECnet 12 /* DECnet */
+#define AF_DLI 13 /* Direct data link interface */
+#define AF_LAT 14 /* LAT */
+#define AF_HYLINK 15 /* NSC Hyperchannel */
+#define AF_APPLETALK 16 /* Apple Talk */
+#define AF_ROUTE 17 /* Internal Routing Protocol */
+#define AF_LINK 18 /* Link layer interface */
+#define pseudo_AF_XTP 19 /* eXpress Transfer Protocol (no AF) */
+
+#define AF_MAX 20
+
+/*
+ * Structure used by kernel to store most addresses.
+ */
+struct sockaddr {
+ u_short sa_family; /* address family */
+ char sa_data[14]; /* up to 14 bytes of direct address */
+};
+
+/*
+ * Structure used by kernel to pass protocol information in raw sockets.
+ */
+struct sockproto {
+ unsigned short sp_family; /* address family */
+ unsigned short sp_protocol; /* protocol */
+};
+
+/*
+ * Protocol families, same as address families for now.
+ */
+#define PF_UNSPEC AF_UNSPEC
+#define PF_UNIX AF_UNIX
+#define PF_INET AF_INET
+#define PF_IMPLINK AF_IMPLINK
+#define PF_PUP AF_PUP
+#define PF_CHAOS AF_CHAOS
+#define PF_NS AF_NS
+#define PF_NBS AF_NBS
+#define PF_ECMA AF_ECMA
+#define PF_DATAKIT AF_DATAKIT
+#define PF_CCITT AF_CCITT
+#define PF_SNA AF_SNA
+#define PF_DECnet AF_DECnet
+#define PF_DLI AF_DLI
+#define PF_LAT AF_LAT
+#define PF_HYLINK AF_HYLINK
+#define PF_APPLETALK AF_APPLETALK
+#define PF_ROUTE AF_ROUTE
+#define PF_LINK AF_LINK
+#define PF_XTP pseudo_AF_XTP /* really just proto family, no AF */
+
+#define PF_MAX AF_MAX
+
+/*
+ * Maximum queue length specifiable by listen.
+ */
+#define SOMAXCONN 5
+
+/*
+ * Message header for recvmsg and sendmsg calls.
+ * Used value-result for recmvsg, value only for sendmsg.
+ */
+struct msghdr {
+ caddr_t msg_name; /* optional address */
+ u_int msg_namelen; /* size of address */
+ struct iovec *msg_iov; /* scatter/gather array */
+ u_int msg_iovlen; /* # elements msg_iov */
+ caddr_t msg_control; /* ancillary data, see below */
+ u_int msg_controllen; /* ancillary data buffer len */
+ int msg_flags; /* flags on received message */
+};
+#define msg_accrights msg_control
+#define msg_accrightslen msg_controllen
+
+#define MSG_OOB 0x1 /* process out-of-band data */
+#define MSG_PEEK 0x2 /* peek at incoming message */
+#define MSG_DONTROUTE 0x4 /* send without using routing tables */
+#define MSG_EOR 0x8 /* data completes record */ /*notused*/
+#define MSG_TRUNC 0x10 /* data discarded before delivery */
+#define MSG_CTRUNC 0x20 /* control data lost before delivery */
+#define MSG_WAITALL 0x40 /* wait for full request or error */ /*notused*/
+
+#define MSG_MAXIOVLEN 16
+
+/*
+ * Header for ancillary data objects in msg_control buffer.
+ * Used for additional information with/about a datagram
+ * not expressible by flags. The format is a sequence
+ * of message elements headed by cmsghdr structures.
+ * In STREAMware, we shuffle the fields around a little from what
+ * they were in net-2, so that they line up the same as an opthdr
+ * which simplifies our socket implementation amazingly.
+ *
+ * Unfortunately, the opthdrs don't include their own length, which the
+ * cmsghdrs do. What this means is that TLI programmers will not be
+ * able to take something returned using these macros and immediately give
+ * it back to the stack. The size of the struct cmsghdr will have to be
+ * subtracted out.
+ * There doesn't seem to be a way to avoid this, since several applications
+ * look into the cmsg_len field and won't work if it doesn't include the size
+ * of the struct cmsghdr.
+ */
+struct cmsghdr {
+ int cmsg_level; /* originating protocol */
+ int cmsg_type; /* protocol-specific type */
+ u_int cmsg_len; /* data byte count, including hdr */
+/* followed by u_char cmsg_data[]; */
+};
+
+/* given pointer to struct adatahdr, return pointer to data */
+#define CMSG_DATA(cmsg) ((u_char *)((cmsg) + 1))
+
+/* given pointer to struct adatahdr, return pointer to next adatahdr */
+#define CMSG_NXTHDR(mhdr, cmsg) \
+ (((caddr_t)(cmsg) + (cmsg)->cmsg_len + sizeof(struct cmsghdr) > \
+ (mhdr)->msg_control + (mhdr)->msg_controllen) ? \
+ (struct cmsghdr *)NULL : \
+ (struct cmsghdr *)((caddr_t)(cmsg) + OPTLEN((cmsg)->cmsg_len)))
+
+#define CMSG_FIRSTHDR(mhdr) ((struct cmsghdr *)(mhdr)->msg_control)
+
+/* "Socket"-level control message types: */
+#define SCM_RIGHTS 0x01 /* access rights (array of int) */
+
+/*
+ * This ioctl code uses BSD style ioctls to avoid copyin/out problems.
+ * Ioctls have the command encoded in the lower word, and the size of any in
+ * or out parameters in the upper word. The high 2 bits of the upper word
+ * are used to encode the in/out status of the parameter; for now we restrict
+ * parameters to at most 128 bytes.
+ */
+#define IOCPARM_MASK 0x7f /* parameters must be < 128 bytes */
+#define IOC_VOID 0x20000000 /* no parameters */
+#define IOC_OUT 0x40000000 /* copy out parameters */
+#define IOC_IN 0x80000000 /* copy in parameters */
+#define IOC_INOUT (IOC_IN|IOC_OUT)
+/* the 0x20000000 is so we can distinguish new ioctls from old */
+#define _IOS(x,y) (IOC_VOID|(x<<8)|y)
+#define _IOSR(x,y,t) (IOC_OUT|((sizeof(t)&IOCPARM_MASK)<<16)|(x<<8)|y)
+#define _IOSW(x,y,t) (IOC_IN|((sizeof(t)&IOCPARM_MASK)<<16)|(x<<8)|y)
+/* this should be _IOSRW, but stdio got there first */
+#define _IOSWR(x,y,t) (IOC_INOUT|((sizeof(t)&IOCPARM_MASK)<<16)|(x<<8)|y)
+
+/*
+ * Socket ioctl commands
+ */
+
+#define SIOCSHIWAT _IOSW('S', 1, int) /* set high watermark */
+#define SIOCGHIWAT _IOSR('S', 2, int) /* get high watermark */
+#define SIOCSLOWAT _IOSW('S', 3, int) /* set low watermark */
+#define SIOCGLOWAT _IOSR('S', 4, int) /* get low watermark */
+#define SIOCATMARK _IOSR('S', 5, int) /* at oob mark? */
+#define SIOCSPGRP _IOSW('S', 6, int) /* set process group */
+#define SIOCGPGRP _IOSR('S', 7, int) /* get process group */
+#define FIONREAD _IOSR('S', 8, int) /* BSD compatibilty */
+#define FIONBIO _IOSW('S', 9, int) /* BSD compatibilty */
+#define FIOASYNC _IOSW('S', 10, int) /* BSD compatibilty */
+#define SIOCPROTO _IOSW('S', 11, struct socknewproto) /* link proto */
+#define SIOCGETNAME _IOSR('S', 12, struct sockaddr) /* getsockname */
+#define SIOCGETPEER _IOSR('S', 13, struct sockaddr) /* getpeername */
+#define IF_UNITSEL _IOSW('S', 14, int) /* set unit number */
+#define SIOCXPROTO _IOS('S', 15) /* empty proto table */
+#define SIOCSHRDTYPE _IOSW('S', 16, int) /* set hardware type */
+
+#define SIOCADDRT _IOSW('R', 9, struct ortentry) /* add route */
+#define SIOCDELRT _IOSW('R', 10, struct ortentry) /* delete route */
+
+#define SIOCSIFADDR _IOSW('I', 11, struct ifreq) /* set ifnet address */
+#define SIOCGIFADDR _IOSWR('I', 12, struct ifreq) /* get ifnet address */
+#define SIOCSIFDSTADDR _IOSW('I', 13, struct ifreq) /* set p-p address */
+#define SIOCGIFDSTADDR _IOSWR('I', 14, struct ifreq) /* get p-p address */
+#define SIOCSIFFLAGS _IOSW('I', 15, struct ifreq) /* set ifnet flags */
+#define SIOCGIFFLAGS _IOSWR('I', 16, struct ifreq) /* get ifnet flags */
+#define SIOCGIFCONF _IOSWR('I', 17, struct ifconf) /* get ifnet list */
+
+#define SIOCSIFMTU _IOSW('I', 21, struct ifreq) /* get if_mtu */
+#define SIOCGIFMTU _IOSWR('I', 22, struct ifreq) /* set if_mtu */
+
+
+#define SIOCGIFBRDADDR _IOSWR('I', 32, struct ifreq) /* get broadcast addr */
+#define SIOCSIFBRDADDR _IOSW('I', 33, struct ifreq) /* set broadcast addr */
+#define SIOCGIFNETMASK _IOSWR('I', 34, struct ifreq) /* get net addr mask */
+#define SIOCSIFNETMASK _IOSW('I', 35, struct ifreq) /* set net addr mask */
+#define SIOCGIFMETRIC _IOSWR('I', 36, struct ifreq) /* get IF metric */
+#define SIOCSIFMETRIC _IOSW('I', 37, struct ifreq) /* set IF metric */
+
+#define SIOCSARP _IOSW('I', 38, struct arpreq) /* set arp entry */
+#define SIOCGARP _IOSWR('I', 39, struct arpreq) /* get arp entry */
+#define SIOCDARP _IOSW('I', 40, struct arpreq) /* delete arp entry */
+
+#define SIOCSIFNAME _IOSW('I', 41, struct ifreq) /* set interface name */
+#define SIOCGIFONEP _IOSWR('I', 42, struct ifreq) /* get one-packet params */
+#define SIOCSIFONEP _IOSW('I', 43, struct ifreq) /* set one-packet params */
+#define SIOCDIFADDR _IOSW('I', 44, struct ifreq) /* delete IF addr */
+#define SIOCAIFADDR _IOSW('I', 45, struct ifaliasreq) /*add/change IF alias*/
+#define SIOCADDMULTI _IOSW('I', 49, struct ifreq) /* add m'cast addr */
+#define SIOCDELMULTI _IOSW('I', 50, struct ifreq) /* del m'cast addr */
+#define SIOCGIFALIAS _IOSWR('I', 51, struct ifaliasreq) /* get IF alias */
+
+
+#define SIOCSOCKSYS _IOSW('I', 66, struct socksysreq) /* Pseudo socket syscall */
+
+/* these use ifr_metric to pass the information */
+#define SIOCSIFDEBUG _IOSW('I', 67, struct ifreq) /* set if debug level */
+#define SIOCGIFDEBUG _IOSWR('I', 68, struct ifreq) /* get if debug level */
+
+#define SIOCSIFTYPE _IOSW('I', 69, struct ifreq) /* set if MIB type */
+#define SIOCGIFTYPE _IOSWR('I', 70, struct ifreq) /* get if MIB type */
+
+#define SIOCGIFNUM _IOSR('I', 71, int) /* get number of ifs */
+/*
+ * This returns the number of ifreqs that SIOCGIFCONF would return, including
+ * aliases. This is the preferred way of sizing a buffer big enough to hold
+ * all interfaces.
+ */
+#define SIOCGIFANUM _IOSR('I', 72, int) /* get number of ifreqs */
+/*
+ * Interface specific performance tuning
+ */
+#define SIOCGIFPERF _IOSR('I', 73, struct ifreq) /* get perf info */
+#define SIOCSIFPERF _IOSR('I', 74, struct ifreq) /* get perf info */
+
+/*
+ * This structure is used to encode pseudo system calls
+ */
+struct socksysreq {
+ /* When porting, make this the widest thing it can be */
+ int args[7];
+};
+
+/*
+ * This structure is used for adding new protocols to the list supported by
+ * sockets.
+ */
+struct socknewproto {
+ int family; /* address family (AF_INET, etc.) */
+ int type; /* protocol type (SOCK_STREAM, etc.) */
+ int proto; /* per family proto number */
+ dev_t dev; /* major/minor to use (must be a clone) */
+ int flags; /* protosw flags */
+};
+
+/*
+ * utility definitions.
+ */
+
+#ifdef MIN
+#undef MIN
+#endif
+#define MIN(x,y) ((x) < (y) ? (x) : (y))
+#ifndef MAX
+#define MAX(x,y) ((x) > (y) ? (x) : (y))
+#endif
+
+#define MAXHOSTNAMELEN 256
+
+#define NBBY 8 /* number of bits in a byte */
+
+
+/* defines for user/kernel interface */
+
+#define MAX_MINOR (makedev(1,0) - 1) /* could be non-portable */
+
+#define SOCKETSYS 140 /* SCO 3.2v5 */
+
+#define SO_ACCEPT 1
+#define SO_BIND 2
+#define SO_CONNECT 3
+#define SO_GETPEERNAME 4
+#define SO_GETSOCKNAME 5
+#define SO_GETSOCKOPT 6
+#define SO_LISTEN 7
+#define SO_RECV 8
+#define SO_RECVFROM 9
+#define SO_SEND 10
+#define SO_SENDTO 11
+#define SO_SETSOCKOPT 12
+#define SO_SHUTDOWN 13
+#define SO_SOCKET 14
+#define SO_SELECT 15
+#define SO_GETIPDOMAIN 16
+#define SO_SETIPDOMAIN 17
+#define SO_ADJTIME 18
+#define SO_SETREUID 19
+#define SO_SETREGID 20
+#define SO_GETTIME 21
+#define SO_SETTIME 22
+#define SO_GETITIMER 23
+#define SO_SETITIMER 24
+#define SO_RECVMSG 25
+#define SO_SENDMSG 26
+#define SO_SOCKPAIR 27
+
+/*
+ * message flags
+ */
+#define M_BCAST 0x80000000
+
+/* Definitions and structures used for extracting */
+/* the size and/or the contents of kernel tables */
+
+/* Copyin/out values */
+#define GIARG 0x1
+#define CONTI 0x2
+#define GITAB 0x4
+
+struct gi_arg {
+ caddr_t gi_where;
+ unsigned gi_size;
+};
+
+#if !defined(_KERNEL) && !defined(INKERNEL) && !defined(_INKERNEL)
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+int accept __P_((int, struct sockaddr *, int *));
+int bind __P_((int, const struct sockaddr *, int));
+int connect __P_((int, const struct sockaddr *, int));
+int getpeername __P_((int, struct sockaddr *, int *));
+int getsockname __P_((int, struct sockaddr *, int *));
+int getsockopt __P_((int, int, int, void *, int *));
+int setsockopt __P_((int, int, int, const void *, int));
+int listen __P_((int, int));
+ssize_t recv __P_((int, void *, size_t, int));
+ssize_t recvfrom __P_((int, void *, size_t, int, struct sockaddr *, int *));
+int recvmsg __P_((int, struct msghdr *, int));
+ssize_t send __P_((int, const void *, size_t, int));
+int sendmsg __P_((int, const struct msghdr *, int));
+ssize_t sendto __P_((int, const void *, size_t, int, const struct sockaddr *, int));
+int shutdown __P_((int, int));
+int socket __P_((int, int, int));
+int socketpair __P_((int, int, int, int[2]));
+__END_DECLS
+
+#endif /* !INKERNEL */
+#endif /* __sys_socket_h */
diff --git a/mit-pthreads/machdep/i386-sco-3.2v5/syscall.h b/mit-pthreads/machdep/i386-sco-3.2v5/syscall.h
new file mode 100755
index 00000000000..f49fba81b6e
--- /dev/null
+++ b/mit-pthreads/machdep/i386-sco-3.2v5/syscall.h
@@ -0,0 +1,175 @@
+/* Copyright 1994-1995 The Santa Cruz Operation, Inc. All Rights Reserved. */
+
+
+#if defined(_NO_PROTOTYPE) /* Old, crufty environment */
+#include <oldstyle/syscall.h>
+#elif defined(_SCO_ODS_30) /* Old, Tbird compatible environment */
+#include <ods_30_compat/syscall.h>
+#else /* Normal, default environment */
+/*
+/ Portions Copyright (C) 1983-1995 The Santa Cruz Operation, Inc.
+ * All Rights Reserved.
+ *
+ * The information in this file is provided for the exclusive use of
+ * the licensees of The Santa Cruz Operation, Inc. Such users have the
+ * right to use, modify, and incorporate this code into other products
+ * for purposes authorized by the license agreement provided they include
+ * this notice and the associated copyright notice with any such product.
+ * The information in this file is provided "AS IS" without warranty.
+ */
+
+/* Portions Copyright (c) 1990, 1991, 1992, 1993 UNIX System Laboratories, Inc. */
+/* Portions Copyright (c) 1979 - 1990 AT&T */
+
+#ident "xpg4plus @(#) sys.i386 20.1 94/12/04 "
+/* #ident "xpg4plus @(#)head:sys.i386 1.2" */
+
+/*
+/* Definitions of Kernel Entry Call Gates
+*/
+
+#ifndef _SYSCALL_H_
+#define _SYSCALL_H_
+
+/*#define SYSCALL $0x7,$0*/
+/*#define SIGCALL $0xF,$0*/
+
+/*
+/* Definitions of System Call Entry Point Numbers
+*/
+
+#define SYS_access 33
+#define SYS_acct 51
+#define SYS_advfs 70
+#define SYS_alarm 27
+#define SYS_break 17
+#define SYS_brk 17
+#define SYS_chdir 12
+#define SYS_chmod 15
+#define SYS_chown 16
+#define SYS_chroot 61
+#define SYS_close 6
+#define SYS_creat 8
+#define SYS_dup 41
+#define SYS_exec 11
+#define SYS_execve 59
+#define SYS_exit 1
+#define SYS_fcntl 62
+#define SYS_fork 2
+#define SYS_fstat 28
+#define SYS_fstatfs 38
+#define SYS_fxstat 125
+#define SYS_getdents 81
+#define SYS_getgid 47
+#define SYS_getmsg 85
+#define SYS_getpid 20
+#define SYS_gettimeofday 171
+#define SYS_getuid 24
+#define SYS_gtty 32
+#define SYS_ioctl 54
+#define SYS_kill 37
+#define SYS_link 9
+#define SYS_lock 45
+#define SYS_lseek 19
+#define SYS_lstat 91
+#define SYS_lxstat 124
+#define SYS_mkdir 80
+#define SYS_mknod 14
+#define SYS_mount 21
+#define SYS_msgsys 49
+#define SYS_nice 34
+#define SYS_open 5
+#define SYS_pause 29
+#define SYS_pipe 42
+#define SYS_plock 45
+#define SYS_poll 87
+#define SYS_prof 44
+#define SYS_ptrace 26
+#define SYS_putmsg 86
+#define SYS_rdebug 76
+#define SYS_read 3
+#define SYS_readlink 92
+#define SYS_readv 121
+#define SYS_rfstart 74
+#define SYS_rfstop 77
+#define SYS_rfsys 78
+#define SYS_rmdir 79
+#define SYS_rmount 72
+#define SYS_rumount 73
+#define SYS_seek 19
+#define SYS_semsys 53
+#define SYS_setgid 46
+#define SYS_setpgrp 39
+#define SYS_settimeofday 172
+#define SYS_setuid 23
+#define SYS_shmsys 52
+#define SYS_signal 48
+#define SYS_stat 18
+#define SYS_statfs 35
+#define SYS_stime 25
+#define SYS_stty 31
+#define SYS_symlink 90
+#define SYS_sync 36
+#define SYS_sys3b 50
+#define SYS_sysi86 50
+#define SYS_sysacct 51
+#define SYS_sysfs 84
+#define SYS_time 13
+#define SYS_times 43
+#define SYS_uadmin 55
+#define SYS_ulimit 63
+#define SYS_umask 60
+#define SYS_umount 22
+#define SYS_unadvfs 71
+#define SYS_unlink 10
+#define SYS_utime 30
+#define SYS_utssys 57
+#define SYS_wait 7
+#define SYS_write 4
+#define SYS_writev 122
+#define SYS_xstat 123
+#define SYS_ftruncate 192
+
+/* cxenix numbers are created by the formula
+ * (table index << 8) + CXENIX
+ */
+
+#define CXENIX 0x28 /* Decimal 40 */
+
+#define XLOCKING 0x0128
+#define CREATSEM 0x0228
+#define OPENSEM 0x0328
+#define SIGSEM 0x0428
+#define WAITSEM 0x0528
+#define NBWAITSEM 0x0628
+#define RDCHK 0x0728
+#define CHSIZE 0x0a28
+#define SYS_ftime 0x0b28
+#define NAP 0x0c28
+#define SDGET 0x0d28
+#define SDFREE 0x0e28
+#define SDENTER 0x0f28
+#define SDLEAVE 0x1028
+#define SDGETV 0x1128
+#define SDWAITV 0x1228
+#define PROCTL 0x2028
+#define EXECSEG 0x2128
+#define UNEXECSEG 0x2228
+#define SYS_select 0x2428
+#define SYS_eaccess 0x2528
+#define SYS_paccess 0x2628
+#define SYS_sigaction 0x2728
+#define SYS_sigprocmask 0x2828
+#define SYS_sigpending 0x2928
+#define SYS_sigsuspend 0x2a28
+#define SYS_getgroups 0x2b28
+#define SYS_setgroups 0x2c28
+#define SYS_sysconf 0x2d28
+#define SYS_pathconf 0x2e28
+#define SYS_fpathconf 0x2f28
+#define SYS_rename 0x3028
+#define SYS_setitimer 0x3828
+
+#define CLOCAL 127
+#endif
+#endif
diff --git a/mit-pthreads/machdep/i386-sco-3.2v5/timers.h b/mit-pthreads/machdep/i386-sco-3.2v5/timers.h
new file mode 100755
index 00000000000..cbc48ccc8d8
--- /dev/null
+++ b/mit-pthreads/machdep/i386-sco-3.2v5/timers.h
@@ -0,0 +1,68 @@
+/* ==== timers.h ============================================================
+ * Copyright (c) 1994 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * timers.h,v 1.50.8.1 1996/03/05 08:28:36 proven Exp
+ *
+ * Description : Basic timers header.
+ *
+ * 1.00 94/06/13 proven
+ * -Started coding this file.
+ */
+
+#ifndef _SYS_TIMERS_H_
+#define _SYS_TIMERS_H_
+
+#include <sys/types.h>
+#include <time.h>
+
+struct timespec {
+ long tv_sec;
+ long tv_nsec;
+};
+
+#define TIMEVAL_TO_TIMESPEC(tv, ts) { \
+ (ts)->tv_sec = (tv)->tv_sec; \
+ (ts)->tv_nsec = (tv)->tv_usec * 1000; \
+}
+#define TIMESPEC_TO_TIMEVAL(tv, ts) { \
+ (tv)->tv_sec = (ts)->tv_sec; \
+ (tv)->tv_usec = (ts)->tv_nsec / 1000; \
+}
+
+/*
+ * New functions
+ */
+
+__BEGIN_DECLS
+
+__END_DECLS
+
+#endif
diff --git a/mit-pthreads/machdep/i386-sco-3.2v5/trash.can b/mit-pthreads/machdep/i386-sco-3.2v5/trash.can
new file mode 100755
index 00000000000..33edf65aab6
--- /dev/null
+++ b/mit-pthreads/machdep/i386-sco-3.2v5/trash.can
@@ -0,0 +1 @@
+make: *** No targets specified and no makefile found. Stop.
diff --git a/mit-pthreads/machdep/irix-5.2/__math.h b/mit-pthreads/machdep/irix-5.2/__math.h
new file mode 100755
index 00000000000..229d5121524
--- /dev/null
+++ b/mit-pthreads/machdep/irix-5.2/__math.h
@@ -0,0 +1,4 @@
+
+extern char __infinity[];
+#define HUGE_VAL (*(double *) __infinity)
+
diff --git a/mit-pthreads/machdep/irix-5.2/__signal.h b/mit-pthreads/machdep/irix-5.2/__signal.h
new file mode 100755
index 00000000000..87797da3198
--- /dev/null
+++ b/mit-pthreads/machdep/irix-5.2/__signal.h
@@ -0,0 +1,15 @@
+#include <sys/signal.h>
+
+typedef int sig_atomic_t;
+
+#ifndef sigmask
+#define sigmask(n) ((unsigned int)1 << (((n) - 1) & (32 - 1)))
+#endif
+#define sigword(n) (((unsigned int)((n) - 1))>>5)
+
+#define __SIGEMPTYSET { 0, 0, 0, 0 };
+#define __SIGFILLSET { 0xffffffff,0xffffffff,0xffffffff,0xffffffff };
+#define __SIGADDSET(s, n) ((s)->sigbits[sigword(n)] |= sigmask(n))
+#define __SIGDELSET(s, n) ((s)->sigbits[sigword(n)] &= ~sigmask(n))
+#define __SIGISMEMBER(s, n) (sigmask(n) & (s)->sigbits[sigword(n)])
+
diff --git a/mit-pthreads/machdep/irix-5.2/__stdio.h b/mit-pthreads/machdep/irix-5.2/__stdio.h
new file mode 100755
index 00000000000..bb4c14b32c6
--- /dev/null
+++ b/mit-pthreads/machdep/irix-5.2/__stdio.h
@@ -0,0 +1,6 @@
+#if !defined(_SIZE_T) && !defined(_SIZE_T_)
+#define _SIZE_T
+typedef pthread_size_t size_t;
+#endif
+
+typedef pthread_fpos_t fpos_t;
diff --git a/mit-pthreads/machdep/irix-5.2/__stdlib.h b/mit-pthreads/machdep/irix-5.2/__stdlib.h
new file mode 100755
index 00000000000..2bec122c5f1
--- /dev/null
+++ b/mit-pthreads/machdep/irix-5.2/__stdlib.h
@@ -0,0 +1,30 @@
+#include <sgidefs.h>
+
+#if !defined(_SIZE_T) && !defined(_SIZE_T_)
+#define _SIZE_T
+#if (_MIPS_SZLONG == 32)
+typedef unsigned int size_t;
+#endif
+#if (_MIPS_SZLONG == 64)
+typedef unsigned long size_t;
+#endif
+#endif
+
+#ifndef _WCHAR_T
+#define _WCHAR_T
+#if (_MIPS_SZLONG == 32)
+typedef long wchar_t;
+#endif
+#if (_MIPS_SZLONG == 64)
+typedef __int32_t wchar_t;
+#endif
+#endif
+
+#ifndef __NORETURN
+#define __NORETURN
+#endif
+
+#ifndef NULL
+#define NULL 0
+#endif
+
diff --git a/mit-pthreads/machdep/irix-5.2/__string.h b/mit-pthreads/machdep/irix-5.2/__string.h
new file mode 100755
index 00000000000..50261e73cfc
--- /dev/null
+++ b/mit-pthreads/machdep/irix-5.2/__string.h
@@ -0,0 +1,5 @@
+#if !defined(_SIZE_T) && !defined(_SIZE_T_)
+#define _SIZE_T
+typedef pthread_size_t size_t;
+#endif
+
diff --git a/mit-pthreads/machdep/irix-5.2/__time.h b/mit-pthreads/machdep/irix-5.2/__time.h
new file mode 100755
index 00000000000..51fb993b38d
--- /dev/null
+++ b/mit-pthreads/machdep/irix-5.2/__time.h
@@ -0,0 +1,21 @@
+#if !defined(_SIZE_T) && !defined(_SIZE_T_)
+#define _SIZE_T
+typedef pthread_size_t size_t;
+#endif
+
+#ifndef _CLOCK_T
+#define _CLOCK_T
+typedef pthread_clock_t clock_t;
+#endif
+
+#ifndef _TIME_T
+#define _TIME_T
+typedef pthread_time_t time_t;
+#endif /* !_TIME_T */
+
+#define CLOCKS_PER_SEC 1000000
+
+#ifndef CLK_TCK
+#define CLK_TCK sysconf(3) /* clock ticks per second */
+ /* 3 is _SC_CLK_TCK */
+#endif
diff --git a/mit-pthreads/machdep/irix-5.2/__unistd.h b/mit-pthreads/machdep/irix-5.2/__unistd.h
new file mode 100755
index 00000000000..0d71d631a5b
--- /dev/null
+++ b/mit-pthreads/machdep/irix-5.2/__unistd.h
@@ -0,0 +1,8 @@
+#include <sys/types.h>
+#include <sys/unistd.h>
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#define ioctl_request_type int /* For fd.c */
diff --git a/mit-pthreads/machdep/irix-5.2/compat.h b/mit-pthreads/machdep/irix-5.2/compat.h
new file mode 100755
index 00000000000..8fd504e504f
--- /dev/null
+++ b/mit-pthreads/machdep/irix-5.2/compat.h
@@ -0,0 +1,45 @@
+/* ==== compat.h ============================================================
+ * Copyright (c) 1994 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ *
+ * Description :
+ *
+ * 1.00 94/06/13 proven
+ * -Started coding this file.
+ */
+
+#ifndef _SYS_COMPAT_H_
+#define _SYS_COMPAT_H_
+
+#define omsghdr msghdr
+
+#endif
diff --git a/mit-pthreads/machdep/irix-5.2/dirent.h b/mit-pthreads/machdep/irix-5.2/dirent.h
new file mode 100755
index 00000000000..79fe486951d
--- /dev/null
+++ b/mit-pthreads/machdep/irix-5.2/dirent.h
@@ -0,0 +1,21 @@
+#ifndef _SYS_DIRENT_H
+#define _SYS_DIRENT_H
+
+#if !defined(_POSIX_SOURCE)
+#define MAXNAMLEN 255 /* maximum filename length */
+#define DIRBUF 4096 /* buffer size for fs-indep. dirs */
+#endif /* !defined(_POSIX_SOURCE) */
+
+#include <sys/types.h>
+
+struct dirent { /* data from readdir() */
+ ino_t d_ino; /* inode number of entry */
+ off_t d_off; /* offset of disk direntory entry */
+ unsigned short d_reclen; /* length of this record */
+ char d_name[MAXNAMLEN+1];/* name of file */
+};
+
+#define d_namlen d_reclen
+#define d_fileno d_ino
+
+#endif /* _SYS_DIRENT_H */
diff --git a/mit-pthreads/machdep/irix-5.2/socket.h b/mit-pthreads/machdep/irix-5.2/socket.h
new file mode 100755
index 00000000000..b08d3939802
--- /dev/null
+++ b/mit-pthreads/machdep/irix-5.2/socket.h
@@ -0,0 +1,304 @@
+#ifndef __SYS_TPI_SOCKET_H__
+#ifndef __SYS_SOCKET_H__
+#define __SYS_SOCKET_H__
+/*
+ * Copyright (c) 1982,1985, 1986 Regents of the University of California.
+ * All rights reserved. The Berkeley software License Agreement
+ * specifies the terms and conditions for redistribution.
+ *
+ * @(#)socket.h 7.1 (Berkeley) 6/4/86
+ */
+#include <sys/cdefs.h>
+#include <sys/bsd_types.h>
+
+/*
+ * Definitions related to sockets: types, address families, options.
+ */
+
+/*
+ * Types
+ */
+#ifdef _STYPES_LATER /* old ABI */
+#define SOCK_STREAM 1 /* stream socket */
+#define SOCK_DGRAM 2 /* datagram socket */
+#define SOCK_RAW 3 /* raw-protocol interface */
+#define SOCK_RDM 4 /* reliably-delivered message */
+#define SOCK_SEQPACKET 5 /* sequenced packet stream */
+#else /* !_STYPES_LATER, new ABI */
+
+#ifndef NC_TPI_CLTS
+#define NC_TPI_CLTS 1 /* must agree with netconfig.h */
+#define NC_TPI_COTS 2 /* must agree with netconfig.h */
+#define NC_TPI_COTS_ORD 3 /* must agree with netconfig.h */
+#define NC_TPI_RAW 4 /* must agree with netconfig.h */
+#endif /* !NC_TPI_CLTS */
+
+#define SOCK_DGRAM NC_TPI_CLTS /* datagram socket */
+#define SOCK_STREAM NC_TPI_COTS /* stream socket */
+#define SOCK_RAW NC_TPI_RAW /* raw-protocol interface */
+#define SOCK_RDM 5 /* reliably-delivered message */
+#define SOCK_SEQPACKET 6 /* sequenced packet stream */
+
+#ifdef _KERNEL
+#define IRIX4_SOCK_STREAM 1 /* stream socket */
+#define IRIX4_SOCK_DGRAM 2 /* datagram socket */
+#define IRIX4_SOCK_RAW 3 /* raw-protocol interface */
+#define IRIX4_SOCK_RDM 4 /* reliably-delivered message */
+#define IRIX4_SOCK_SEQPACKET 5 /* sequenced packet stream */
+#endif /* _KERNEL */
+#endif /* _STYPES_LATER */
+
+/*
+ * Option flags per-socket.
+ */
+#define SO_DEBUG 0x0001 /* turn on debugging info recording */
+#define SO_ACCEPTCONN 0x0002 /* socket has had listen() */
+#define SO_REUSEADDR 0x0004 /* allow local address reuse */
+#define SO_KEEPALIVE 0x0008 /* keep connections alive */
+#define SO_DONTROUTE 0x0010 /* just use interface addresses */
+#define SO_BROADCAST 0x0020 /* permit sending of broadcast msgs */
+#define SO_USELOOPBACK 0x0040 /* bypass hardware when possible */
+#define SO_LINGER 0x0080 /* linger on close if data present */
+#define SO_OOBINLINE 0x0100 /* leave received OOB data in line */
+#define SO_REUSEPORT 0x0200 /* allow local address,port reuse */
+#define SO_ORDREL 0x0200 /* MIPS ABI - unimplemented */
+#define SO_IMASOCKET 0x0400 /* use libsocket (not TLI) semantics */
+#define SO_CHAMELEON 0x1000 /* (cipso) set label to 1st req rcvd */
+
+/*
+ * Additional options, not kept in so_options.
+ */
+#define SO_SNDBUF 0x1001 /* send buffer size */
+#define SO_RCVBUF 0x1002 /* receive buffer size */
+#define SO_SNDLOWAT 0x1003 /* send low-water mark */
+#define SO_RCVLOWAT 0x1004 /* receive low-water mark */
+#define SO_SNDTIMEO 0x1005 /* send timeout */
+#define SO_RCVTIMEO 0x1006 /* receive timeout */
+#define SO_ERROR 0x1007 /* get error status and clear */
+#define SO_TYPE 0x1008 /* get socket type */
+#define SO_PROTOTYPE 0x1009 /* get protocol type (libsocket) */
+
+/*
+ * Structure used for manipulating linger option.
+ */
+struct linger {
+ int l_onoff; /* option on/off */
+ int l_linger; /* linger time */
+};
+
+/*
+ * Level number for (get/set)sockopt() to apply to socket itself.
+ */
+#define SOL_SOCKET 0xffff /* options for socket level */
+
+/*
+ * Address families.
+ * XTP really is not an address family, but is included here to take
+ * up space, because other AF_ entries are numerically equal to their
+ * PF_ counterparts.
+ */
+#define AF_UNSPEC 0 /* unspecified */
+#define AF_UNIX 1 /* local to host (pipes, portals) */
+#define AF_INET 2 /* internetwork: UDP, TCP, etc. */
+#define AF_IMPLINK 3 /* arpanet imp addresses */
+#define AF_PUP 4 /* pup protocols: e.g. BSP */
+#define AF_CHAOS 5 /* mit CHAOS protocols */
+#define AF_NS 6 /* XEROX NS protocols */
+#define AF_ISO 7 /* ISO protocols */
+#define AF_ECMA 8 /* european computer manufacturers */
+#define AF_DATAKIT 9 /* datakit protocols */
+#define AF_CCITT 10 /* CCITT protocols, X.25 etc */
+#define AF_SNA 11 /* IBM SNA */
+#define AF_DECnet 12 /* DECnet */
+#define AF_DLI 13 /* DEC Direct data link interface */
+#define AF_LAT 14 /* LAT */
+#define AF_HYLINK 15 /* NSC Hyperchannel */
+#define AF_APPLETALK 16 /* Apple Talk */
+#define AF_ROUTE 17 /* Internal Routing Protocol */
+#ifdef __sgi
+#define AF_RAW 18 /* Raw link layer interface */
+#else
+#define AF_LINK 18 /* Link layer interface */
+#endif
+#define pseudo_AF_XTP 19 /* eXpress Transfer Protocol (no AF) */
+
+/* MIPS ABI VALUES - unimplemented */
+#define AF_NIT 17 /* Network Interface Tap */
+#define AF_802 18 /* IEEE 802.2, also ISO 8802 */
+#define AF_OSI 19 /* umbrella for all families used */
+#define AF_X25 20 /* CCITT X.25 in particular */
+#define AF_OSINET 21 /* AFI = 47, IDI = 4 */
+#define AF_GOSIP 22 /* U.S. Government OSI */
+
+
+#define AF_SDL 23 /* SGI Data Link for DLPI */
+
+#define AF_MAX (AF_SDL+1)
+
+/*
+ * Structure used by kernel to store most
+ * addresses.
+ */
+struct sockaddr {
+ u_short sa_family; /* address family */
+ char sa_data[14]; /* up to 14 bytes of direct address */
+};
+
+/*
+ * Structure used by kernel to pass protocol
+ * information in raw sockets.
+ */
+struct sockproto {
+ u_short sp_family; /* address family */
+ u_short sp_protocol; /* protocol */
+};
+
+/*
+ * An option specification consists of an opthdr, followed by the value of
+ * the option. An options buffer contains one or more options. The len
+ * field of opthdr specifies the length of the option value in bytes. This
+ * length must be a multiple of sizeof(long) (use OPTLEN macro).
+ */
+
+struct opthdr {
+ long level; /* protocol level affected */
+ long name; /* option to modify */
+ long len; /* length of option value */
+};
+
+#define OPTLEN(x) ((((x) + sizeof(long) - 1) / sizeof(long)) * sizeof(long))
+#define OPTVAL(opt) ((char *)(opt + 1))
+
+/*
+ * the optdefault structure is used for internal tables of option default
+ * values.
+ */
+struct optdefault {
+ int optname; /* the option */
+ char *val; /* ptr to default value */
+ int len; /* length of value */
+};
+
+struct tpisocket;
+struct T_optmgmt_req;
+struct msgb;
+
+/*
+ * the opproc structure is used to build tables of options processing
+ * functions for dooptions().
+ */
+struct opproc {
+ int level; /* options level this function handles */
+ int (*func)(struct tpisocket *, struct T_optmgmt_req *,
+ struct opthdr *, struct msgb *);
+ /* the function */
+};
+
+/*
+ * This structure is used to encode pseudo system calls
+ */
+struct socksysreq {
+ int args[7];
+};
+
+/*
+ * This structure is used for adding new protocols to the list supported by
+ * sockets.
+ */
+
+struct socknewproto {
+ int family; /* address family (AF_INET, etc.) */
+ int type; /* protocol type (SOCK_STREAM, etc.) */
+ int proto; /* per family proto number */
+ dev_t dev; /* major/minor to use (must be a clone) */
+ int flags; /* protosw flags */
+};
+
+/*
+ * Protocol families, same as address families for now.
+ */
+#define PF_UNSPEC AF_UNSPEC
+#define PF_UNIX AF_UNIX
+#define PF_INET AF_INET
+#define PF_IMPLINK AF_IMPLINK
+#define PF_PUP AF_PUP
+#define PF_CHAOS AF_CHAOS
+#define PF_NS AF_NS
+#define PF_ISO AF_ISO
+#define PF_ECMA AF_ECMA
+#define PF_DATAKIT AF_DATAKIT
+#define PF_CCITT AF_CCITT
+#define PF_SNA AF_SNA
+#define PF_DECnet AF_DECnet
+#define PF_DLI AF_DLI
+#define PF_LAT AF_LAT
+#define PF_HYLINK AF_HYLINK
+#define PF_APPLETALK AF_APPLETALK
+#define PF_ROUTE AF_ROUTE
+#define PF_LINK AF_LINK
+#define PF_XTP pseudo_AF_XTP /* really just proto family, no AF */
+#ifdef __sgi
+#define PF_RAW AF_RAW
+#endif
+
+/* MIPS ABI VALUES - unimplemented */
+#define PF_NIT AF_NIT /* Network Interface Tap */
+#define PF_802 AF_802 /* IEEE 802.2, also ISO 8802 */
+#define PF_OSI AF_OSI /* umbrella for all families used */
+#define PF_X25 AF_X25 /* CCITT X.25 in particular */
+#define PF_OSINET AF_OSINET /* AFI = 47, IDI = 4 */
+#define PF_GOSIP AF_GOSIP /* U.S. Government OSI */
+
+#define PF_MAX AF_MAX
+
+/*
+ * Maximum queue length specifiable by listen.
+ */
+#define SOMAXCONN 5
+
+/*
+ * Message header for recvmsg and sendmsg calls.
+ */
+struct msghdr {
+ caddr_t msg_name; /* optional address */
+ int msg_namelen; /* size of address */
+ struct iovec *msg_iov; /* scatter/gather array */
+ int msg_iovlen; /* # elements in msg_iov */
+ caddr_t msg_accrights; /* access rights sent/received */
+ int msg_accrightslen;
+};
+
+#define MSG_OOB 0x1 /* process out-of-band data */
+#define MSG_PEEK 0x2 /* peek at incoming message */
+#define MSG_DONTROUTE 0x4 /* send without using routing tables */
+#define MSG_EOR 0x8 /* data completes record (OSI only) */
+#ifdef XTP
+#define MSG_BTAG 0x40 /* XTP packet with BTAG field */
+#define MSG_ETAG 0x80 /* XTP packet with ETAG field */
+#endif
+
+#define MSG_MAXIOVLEN 16
+
+__BEGIN_DECLS
+int accept __P_((int, struct sockaddr *, int *));
+int bind __P_((int, const struct sockaddr *, int));
+int connect __P_((int, const struct sockaddr *, int));
+int getpeername __P_((int, struct sockaddr *, int *));
+int getsockname __P_((int, struct sockaddr *, int *));
+int getsockopt __P_((int, int, int, void *, int *));
+int listen __P_((int, int));
+ssize_t recv __P_((int, void *, size_t, int));
+ssize_t recvfrom __P_((int, void *, size_t, int, struct sockaddr *, int *));
+int recvmsg __P_((int, struct msghdr *, int));
+ssize_t send __P_((int, const void *, size_t, int));
+ssize_t sendto __P_((int, const void *, size_t, int,
+ const struct sockaddr *, int));
+int sendmsg __P_((int, const struct msghdr *, int));
+int setsockopt __P_((int, int, int, const void *, int));
+int shutdown __P_((int, int));
+int socket __P_((int, int, int));
+int socketpair __P_((int, int, int, int *));
+__END_DECLS
+
+#endif /* !__SYS_SOCKET_H__ */
+#endif /* !__SYS_TPI_SOCKET_H__ */
diff --git a/mit-pthreads/machdep/irix-5.2/timers.h b/mit-pthreads/machdep/irix-5.2/timers.h
new file mode 100755
index 00000000000..ffa24dc9a15
--- /dev/null
+++ b/mit-pthreads/machdep/irix-5.2/timers.h
@@ -0,0 +1,18 @@
+#ifndef __SYS_TIMERS_H__
+#define __SYS_TIMERS_H__
+
+struct timespec {
+ time_t tv_sec;
+ long tv_nsec;
+};
+
+#define TIMEVAL_TO_TIMESPEC(tv, ts) { \
+ (ts)->tv_sec = (tv)->tv_sec; \
+ (ts)->tv_nsec = (tv)->tv_usec * 1000; \
+}
+#define TIMESPEC_TO_TIMEVAL(tv, ts) { \
+ (tv)->tv_sec = (ts)->tv_sec; \
+ (tv)->tv_usec = (ts)->tv_nsec / 1000; \
+}
+
+#endif /* !__SYS_TIMERS_H__ */
diff --git a/mit-pthreads/machdep/irix-5.2/wait.h b/mit-pthreads/machdep/irix-5.2/wait.h
new file mode 100755
index 00000000000..c0a7e7113d8
--- /dev/null
+++ b/mit-pthreads/machdep/irix-5.2/wait.h
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 1982, 1986 Regents of the University of California.
+ * All rights reserved. The Berkeley software License Agreement
+ * specifies the terms and conditions for redistribution.
+ *
+ * @(#)wait.h 7.4 (Berkeley) 1/27/88
+ */
+#ifndef __SYS_WAIT_H__
+#define __SYS_WAIT_H__
+
+#ifdef _POSIX_SOURCE
+#define _W_INT(i) (i)
+#else
+#define _W_INT(w) (*(int *)&(w)) /* convert union wait to int */
+#define WCOREFLAG 0200
+#endif
+
+#define WSTOPFLG 0177
+#define WIFSTOPPED(stat) ((_W_INT(stat)&0377)==_WSTOPPED&&((_W_INT(stat)>>8)&0377)!=0)
+#define WSTOPSIG(stat) ((_W_INT(stat)>>8)&0377)
+#define WIFSIGNALED(stat) ((_W_INT(stat)&0377)>0&&((_W_INT(stat)>>8)&0377)==0)
+#define WTERMSIG(stat) (_W_INT(stat)&0177)
+#define WIFEXITED(stat) ((_W_INT(stat)&0377)==0)
+#define WEXITSTATUS(stat) ((_W_INT(stat)>>8)&0377)
+#define WCOREDUMP(stat) (_W_INT(stat) & WCOREFLAG)
+
+/*
+ * Option bits for the second argument of wait3. WNOHANG causes the
+ * wait to not hang if there are no stopped or terminated processes, rather
+ * returning an error indication in this case (pid==0). WUNTRACED
+ * indicates that the caller should receive status about untraced children
+ * which stop due to signals. If children are stopped and a wait without
+ * this option is done, it is as though they were still running... nothing
+ * about them is returned.
+ */
+#define WNOHANG 0100
+#define WUNTRACED 0004 /* for POSIX */
+
+#if !defined(_POSIX_SOURCE)
+
+/*
+ * Structure of the information in the first word returned by both
+ * wait and wait3. If w_stopval==_WSTOPPED, then the second structure
+ * describes the information returned, else the first. See WUNTRACED below.
+ */
+typedef union wait {
+ int w_status; /* used in syscall */
+ /*
+ * Terminated process status.
+ */
+ struct {
+#ifdef _MIPSEL
+ unsigned int w_Termsig:7, /* termination signal */
+ w_Coredump:1, /* core dump indicator */
+ w_Retcode:8, /* exit code if w_termsig==0 */
+ w_Filler:16; /* upper bits filler */
+#endif
+#ifdef _MIPSEB
+ unsigned int w_Filler:16, /* upper bits filler */
+ w_Retcode:8, /* exit code if w_termsig==0 */
+ w_Coredump:1, /* core dump indicator */
+ w_Termsig:7; /* termination signal */
+#endif
+ } w_T;
+ /*
+ * Stopped process status. Returned
+ * only for traced children unless requested
+ * with the WUNTRACED option bit.
+ */
+ struct {
+#ifdef _MIPSEL
+ unsigned int w_Stopval:8, /* == W_STOPPED if stopped */
+ w_Stopsig:8, /* signal that stopped us */
+ w_Filler:16; /* upper bits filler */
+#endif
+#ifdef _MIPSEB
+ unsigned int w_Filler:16, /* upper bits filler */
+ w_Stopsig:8, /* signal that stopped us */
+ w_Stopval:8; /* == W_STOPPED if stopped */
+#endif
+ } w_S;
+} wait_t;
+#define w_termsig w_T.w_Termsig
+#define w_coredump w_T.w_Coredump
+#define w_retcode w_T.w_Retcode
+#define w_stopval w_S.w_Stopval
+#define w_stopsig w_S.w_Stopsig
+
+
+
+#define WSTOPPED 0004 /* wait for processes stopped by signals */
+#endif /* !defined(_POSIX_SOURCE) */
+
+#include <sys/types.h>
+#include <sys/cdefs.h>
+__BEGIN_DECLS
+pid_t wait __P_((int *));
+pid_t waitpid __P_((pid_t, int *, int));
+#ifndef _POSIX_SOURCE
+pid_t wait3 __P_((int *, int, void *));
+pid_t wait4 __P_((pid_t, int *, int, void *));
+#endif
+
+#endif /* __SYS_WAIT_H__ */
diff --git a/mit-pthreads/machdep/linux-1.0/__math.h b/mit-pthreads/machdep/linux-1.0/__math.h
new file mode 100755
index 00000000000..05c65d58321
--- /dev/null
+++ b/mit-pthreads/machdep/linux-1.0/__math.h
@@ -0,0 +1,4 @@
+#ifndef HUGE_VAL
+#define HUGE_VAL DBL_MAX
+#endif
+
diff --git a/mit-pthreads/machdep/linux-1.0/__path.h b/mit-pthreads/machdep/linux-1.0/__path.h
new file mode 100755
index 00000000000..9caeb7d3016
--- /dev/null
+++ b/mit-pthreads/machdep/linux-1.0/__path.h
@@ -0,0 +1,14 @@
+/*
+ * from: @(#)time.h 5.12 (Berkeley) 3/9/91
+ * $Id$
+ */
+
+#ifndef _SYS__PATH_H_
+#define _SYS__PATH_H_
+
+#define _PATH_PTY "/dev/"
+#define _PATH_TZDIR "/usr/lib/zoneinfo"
+#define _PATH_TZFILE "/usr/lib/zoneinfo/localtime"
+
+#endif /* !_SYS__PATH_H_ */
+
diff --git a/mit-pthreads/machdep/linux-1.0/__signal.h b/mit-pthreads/machdep/linux-1.0/__signal.h
new file mode 100755
index 00000000000..4cd671f155c
--- /dev/null
+++ b/mit-pthreads/machdep/linux-1.0/__signal.h
@@ -0,0 +1,24 @@
+#include <features.h>
+#include <linux/signal.h>
+
+#ifndef SIGCLD
+#define SIGCLD SIGCHLD
+#endif
+
+typedef int sig_atomic_t;
+
+typedef __sighandler_t SignalHandler;
+
+#define SignalBad ((SignalHandler)-1)
+#define SignalDefault ((SignalHandler)0)
+#define SignalIgnore ((SignalHandler)1)
+
+#define __sigmask(sig) (1 << ((sig) - 1))
+#define sigmask __sigmask
+
+#define __SIGFILLSET 0xffffffff
+#define __SIGEMPTYSET 0
+#define __SIGADDSET(s,n) ((*s) |= (__sigmask(n)))
+#define __SIGDELSET(s,n) ((*s) &= ~(__sigmask(n)))
+#define __SIGISMEMBER(s,n) ((*s) & (__sigmask(n)))
+
diff --git a/mit-pthreads/machdep/linux-1.0/__stdio.h b/mit-pthreads/machdep/linux-1.0/__stdio.h
new file mode 100755
index 00000000000..eb7e904c34d
--- /dev/null
+++ b/mit-pthreads/machdep/linux-1.0/__stdio.h
@@ -0,0 +1,7 @@
+
+#ifndef _SIZE_T
+#define _SIZE_T
+typedef pthread_size_t size_t;
+#endif
+
+typedef pthread_fpos_t fpos_t;
diff --git a/mit-pthreads/machdep/linux-1.0/__stdlib.h b/mit-pthreads/machdep/linux-1.0/__stdlib.h
new file mode 100755
index 00000000000..eaa0bb988ee
--- /dev/null
+++ b/mit-pthreads/machdep/linux-1.0/__stdlib.h
@@ -0,0 +1,20 @@
+
+#ifndef _SYS___STDLIB_H_
+#define _SYS___STDLIB_H_
+
+#include <features.h>
+
+/* Get size_t, wchar_t and NULL from <stddef.h>. */
+#define __need_size_t
+#define __need_wchar_t
+#define __need_NULL
+#include <stddef.h>
+
+#define __need_Emath
+#include <errno.h>
+
+/* Get HUGE_VAL (returned by strtod on overflow) from <float.h>. */
+#define __need_HUGE_VAL
+#include <float.h>
+
+#endif
diff --git a/mit-pthreads/machdep/linux-1.0/__string.h b/mit-pthreads/machdep/linux-1.0/__string.h
new file mode 100755
index 00000000000..8a5e09608e0
--- /dev/null
+++ b/mit-pthreads/machdep/linux-1.0/__string.h
@@ -0,0 +1,18 @@
+
+#ifndef _SIZE_T
+#define _SIZE_T
+typedef pthread_size_t size_t;
+#endif
+
+/* Non-standard Linux string routines. */
+#if !defined(_ANSI_SOURCE) && !defined(_POSIX_SOURCE)
+__BEGIN_DECLS
+int bcmp __P_((const void *, const void *, size_t));
+void bcopy __P_((const void *, void *, size_t));
+void bzero __P_((void *, size_t));
+char *index __P_((const char *, int));
+char *rindex __P_((const char *, int));
+char *strdup __P_((const char *));
+char *strsep __P_((char **, const char *));
+__END_DECLS
+#endif
diff --git a/mit-pthreads/machdep/linux-1.0/__time.h b/mit-pthreads/machdep/linux-1.0/__time.h
new file mode 100755
index 00000000000..a088268286e
--- /dev/null
+++ b/mit-pthreads/machdep/linux-1.0/__time.h
@@ -0,0 +1,72 @@
+/* ==== __time.h ============================================================
+ * Copyright (c) 1994 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ *
+ * Description : System specific time header.
+ *
+ * 1.00 94/11/07 proven
+ * -Started coding this file.
+ */
+
+#ifndef _SYS___TIME_H_
+#define _SYS___TIME_H_
+
+#include <features.h>
+
+#ifndef _SIZE_T
+#define _SIZE_T
+typedef unsigned int size_t;
+#endif
+#ifndef _CLOCK_T
+#define _CLOCK_T
+typedef long clock_t;
+#endif
+#ifndef _TIME_T
+#define _TIME_T
+typedef long time_t;
+
+#ifndef NULL
+#ifdef __cplusplus
+#define NULL 0
+#else
+#define NULL ((void *) 0)
+#endif
+#endif
+#endif
+
+#define CLOCKS_PER_SEC 100
+#define CLK_TCK 100
+
+extern long int timezone;
+extern int daylight;
+
+#endif
diff --git a/mit-pthreads/machdep/linux-1.0/__unistd.h b/mit-pthreads/machdep/linux-1.0/__unistd.h
new file mode 100755
index 00000000000..0f15b7c4883
--- /dev/null
+++ b/mit-pthreads/machdep/linux-1.0/__unistd.h
@@ -0,0 +1,56 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)stdlib.h 5.13 (Berkeley) 6/4/91
+ * $Id$
+ */
+
+#ifndef _SYS___UNISTD_H_
+#define _SYS___UNISTD_H_
+
+#include <features.h>
+
+/* POSIX Standard approved as IEEE Std 1003.1 as of August, 1988. */
+#define _POSIX_VERSION 199009L
+#define _POSIX2_C_BIND 1
+#define _POSIX2_C_DEV 1
+#define _POSIX2_SW_DEV 1
+
+#define __need_size_t
+#define ioctl_request_type int /* For fd.c */
+
+#include <posix_opt.h>
+#include <sys/types.h>
+#include <stddef.h>
+
+#endif
+
diff --git a/mit-pthreads/machdep/linux-1.0/cdefs.h b/mit-pthreads/machdep/linux-1.0/cdefs.h
new file mode 100755
index 00000000000..f9d5668cfe6
--- /dev/null
+++ b/mit-pthreads/machdep/linux-1.0/cdefs.h
@@ -0,0 +1,23 @@
+/* This is intended to eventually find /usr/include/sys/cdefs.h
+ * if it's inside the ifdef then it won't work if this file is
+ * found in the include files path more than once.
+ *
+ * include_next is a GNU C extension, we might eventually want
+ * to have our own cdefs in here simply to avoid GNU C dependencies
+ * (though there are already enough in the asm stuff anyways)
+ * [gsstark:19950419.0307EST]
+ */
+#include_next <sys/cdefs.h>
+
+#ifndef _PTHREAD_SYS_CDEFS_H_
+#define _PTHREAD_SYS_CDEFS_H_
+
+#ifndef __NORETURN
+#define __NORETURN
+#endif /* __NORETURN not defined. */
+
+#if !defined(__cplusplus)
+#define __CAN_DO_EXTERN_INLINE
+#endif
+
+#endif /* _PTHREAD_SYS_CDEFS_H_ */
diff --git a/mit-pthreads/machdep/linux-1.0/compat.h b/mit-pthreads/machdep/linux-1.0/compat.h
new file mode 100755
index 00000000000..6edb992ac3d
--- /dev/null
+++ b/mit-pthreads/machdep/linux-1.0/compat.h
@@ -0,0 +1,47 @@
+/* ==== compat.h ============================================================
+ * Copyright (c) 1994 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ *
+ * Description : Basic timers header.
+ *
+ * 1.00 94/06/13 proven
+ * -Started coding this file.
+ */
+
+#ifndef _SYS_COMPAT_H_
+#define _SYS_COMPAT_H_
+
+#include <sys/types.h>
+
+#define omsghdr msghdr
+
+#endif
diff --git a/mit-pthreads/machdep/linux-1.0/dirent.h b/mit-pthreads/machdep/linux-1.0/dirent.h
new file mode 100755
index 00000000000..7f783a198e0
--- /dev/null
+++ b/mit-pthreads/machdep/linux-1.0/dirent.h
@@ -0,0 +1,27 @@
+
+#ifndef _SYS_DIRENT_H
+#define _SYS_DIRENT_H
+
+#include <sys/types.h>
+#include <linux/limits.h>
+
+struct dirent {
+ long d_ino;
+ off_t d_off;
+ unsigned short d_reclen;
+ char d_name[NAME_MAX+1];
+};
+
+#ifndef d_fileno
+#define d_fileno d_ino
+#endif
+
+#ifndef d_namlen
+#define d_namlen d_reclen
+#endif
+
+#ifndef MAXNAMLEN
+#define MAXNAMLEN NAME_MAX
+#endif
+
+#endif
diff --git a/mit-pthreads/machdep/linux-1.0/errno.h b/mit-pthreads/machdep/linux-1.0/errno.h
new file mode 100755
index 00000000000..a94a56b0437
--- /dev/null
+++ b/mit-pthreads/machdep/linux-1.0/errno.h
@@ -0,0 +1,12 @@
+/* ==== errno.h ============================================================
+ * Copyright (c) 1994 by Chris Provenzano, proven@athena.mit.edu
+ *
+ * Description : Errno is already broken up into data/prototyes.
+ */
+
+#ifndef _SYS_ERRNO_H_
+#define _SYS_ERRNO_H_
+
+#include <linux/errno.h>
+
+#endif
diff --git a/mit-pthreads/machdep/linux-1.0/socket.h b/mit-pthreads/machdep/linux-1.0/socket.h
new file mode 100755
index 00000000000..cc4c0fd262e
--- /dev/null
+++ b/mit-pthreads/machdep/linux-1.0/socket.h
@@ -0,0 +1,193 @@
+/* ==== socket.h.h ============================================================
+ * Copyright (c) 1994 by Chris Provenzano, proven@athena.mit.edu
+ *
+ * Description : Correct Linux header file.
+ */
+
+#ifndef _PTHREAD_SOCKET_H_
+#define _PTHREAD_SOCKET_H_
+
+/* #include <linux/socket.h> */
+#ifndef _LINUX_SOCKET_H
+#define _LINUX_SOCKET_H
+
+/* IP options */
+#define IP_TOS 1
+#define IPTOS_LOWDELAY 0x10
+#define IPTOS_THROUGHPUT 0x08
+#define IPTOS_RELIABILITY 0x04
+#define IP_TTL 2
+#ifndef IP_HDRINCL
+#define IP_HDRINCL 3
+#endif
+#ifdef V1_3_WILL_DO_THIS_FUNKY_STUFF
+#define IP_OPTIONS 4
+#endif
+
+#endif
+
+/* #include <asm/socket.h> arch-dependent defines */
+#include <linux/sockios.h> /* the SIOCxxx I/O controls */
+#include <pthread/posix.h>
+
+struct sockaddr {
+ unsigned short sa_family; /* address family, AF_xxx */
+ char sa_data[14]; /* 14 bytes of protocol address */
+};
+
+struct linger {
+ int l_onoff; /* Linger active */
+ int l_linger; /* How long to linger for */
+};
+
+struct msghdr
+{
+ void * msg_name; /* Socket name */
+ int msg_namelen; /* Length of name */
+ struct iovec * msg_iov; /* Data blocks */
+ int msg_iovlen; /* Number of blocks */
+ void * msg_accrights; /* Per protocol magic (eg BSD file descriptor passing) */
+ int msg_accrightslen;/* Length of rights list */
+};
+
+/* Socket types. */
+#define SOCK_STREAM 1 /* stream (connection) socket */
+#define SOCK_DGRAM 2 /* datagram (conn.less) socket */
+#define SOCK_RAW 3 /* raw socket */
+#define SOCK_RDM 4 /* reliably-delivered message */
+#define SOCK_SEQPACKET 5 /* sequential packet socket */
+#define SOCK_PACKET 10 /* linux specific way of */
+ /* getting packets at the dev */
+ /* level. For writing rarp and */
+ /* other similar things on the */
+ /* user level. */
+
+/* Supported address families. */
+#define AF_UNSPEC 0
+#define AF_UNIX 1 /* Unix domain sockets */
+#define AF_INET 2 /* Internet IP Protocol */
+#define AF_AX25 3 /* Amateur Radio AX.25 */
+#define AF_IPX 4 /* Novell IPX */
+#define AF_APPLETALK 5 /* Appletalk DDP */
+#define AF_NETROM 6 /* Amateur radio NetROM */
+#define AF_BRIDGE 7 /* Multiprotocol bridge */
+#define AF_AAL5 8 /* Reserved for Werner's ATM */
+#define AF_X25 9 /* Reserved for X.25 project */
+#define AF_INET6 10 /* IP version 6 */
+#define AF_MAX 12 /* For now.. */
+
+/* Protocol families, same as address families. */
+#define PF_UNSPEC AF_UNSPEC
+#define PF_UNIX AF_UNIX
+#define PF_INET AF_INET
+#define PF_AX25 AF_AX25
+#define PF_IPX AF_IPX
+#define PF_APPLETALK AF_APPLETALK
+#define PF_NETROM AF_NETROM
+#define PF_BRIDGE AF_BRIDGE
+#define PF_AAL5 AF_AAL5
+#define PF_X25 AF_X25
+#define PF_INET6 AF_INET6
+
+#define PF_MAX AF_MAX
+
+/* Maximum queue length specificable by listen. */
+#define SOMAXCONN 128
+
+/* Flags we can use with send/ and recv. */
+#define MSG_OOB 1
+#define MSG_PEEK 2
+#define MSG_DONTROUTE 4
+
+/* Setsockoptions(2) level. Thanks to BSD these must match IPPROTO_xxx */
+#define SOL_SOCKET 1
+#define SOL_IP 0
+#define SOL_IPX 256
+#define SOL_AX25 257
+#define SOL_ATALK 258
+#define SOL_NETROM 259
+#define SOL_TCP 6
+#define SOL_UDP 17
+
+/* For setsockoptions(2) */
+#define SO_DEBUG 1
+#define SO_REUSEADDR 2
+#define SO_TYPE 3
+#define SO_ERROR 4
+#define SO_DONTROUTE 5
+#define SO_BROADCAST 6
+#define SO_SNDBUF 7
+#define SO_RCVBUF 8
+#define SO_KEEPALIVE 9
+#define SO_OOBINLINE 10
+#define SO_NO_CHECK 11
+#define SO_PRIORITY 12
+#define SO_LINGER 13
+/* To add :#define SO_REUSEPORT 14 */
+
+
+#define IP_MULTICAST_IF 32
+#define IP_MULTICAST_TTL 33
+#define IP_MULTICAST_LOOP 34
+#define IP_ADD_MEMBERSHIP 35
+#define IP_DROP_MEMBERSHIP 36
+
+
+/* These need to appear somewhere around here */
+#define IP_DEFAULT_MULTICAST_TTL 1
+#define IP_DEFAULT_MULTICAST_LOOP 1
+#define IP_MAX_MEMBERSHIPS 20
+
+/* IPX options */
+#define IPX_TYPE 1
+
+/* TCP options - this way around because someone left a set in the c library includes */
+#define TCP_NODELAY 1
+#define TCP_MAXSEG 2
+
+/* The various priorities. */
+#define SOPRI_INTERACTIVE 0
+#define SOPRI_NORMAL 1
+#define SOPRI_BACKGROUND 2
+
+/*
+ * Functions
+ */
+
+__BEGIN_DECLS
+
+int accept __P_((int, struct sockaddr *, int *));
+int bind __P_((int, const struct sockaddr *, int));
+int connect __P_((int, const struct sockaddr *, int));
+int listen __P_((int, int));
+int socket __P_((int, int, int));
+
+int getsockopt __P_((int __s, int __level, int __optname,
+ void *__optval, int *__optlen));
+int setsockopt __P_((int __s, int __level, int __optname,
+ __const void *__optval, int optlen));
+int getsockname __P_((int __sockfd, struct sockaddr *__addr,
+ int *__paddrlen));
+int getpeername __P_((int __sockfd, struct sockaddr *__peer,
+ int *__paddrlen));
+ssize_t send __P_((int __sockfd, __const void *__buff, size_t __len, int __flags));
+ssize_t recv __P_((int __sockfd, void *__buff, size_t __len, int __flags));
+ssize_t sendto __P_((int __sockfd, __const void *__buff, size_t __len,
+ int __flags, __const struct sockaddr *__to,
+ int __tolen));
+ssize_t recvfrom __P_((int __sockfd, void *__buff, size_t __len,
+ int __flags, struct sockaddr *__from,
+ int *__fromlen));
+extern ssize_t sendmsg __P_((int __fd, __const struct msghdr *__message,
+ int __flags));
+extern ssize_t recvmsg __P_((int __fd, struct msghdr *__message,
+ int __flags));
+int shutdown __P_((int __sockfd, int __how));
+
+__END_DECLS
+
+#endif
+
+
+
+
diff --git a/mit-pthreads/machdep/linux-1.0/timers.h b/mit-pthreads/machdep/linux-1.0/timers.h
new file mode 100755
index 00000000000..110cb27378c
--- /dev/null
+++ b/mit-pthreads/machdep/linux-1.0/timers.h
@@ -0,0 +1,71 @@
+/* ==== timers.h ============================================================
+ * Copyright (c) 1994 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ *
+ * Description : Basic timers header.
+ *
+ * 1.00 94/06/13 proven
+ * -Started coding this file.
+ */
+
+#ifndef _SYS_TIMERS_H_
+#define _SYS_TIMERS_H_
+
+#include <pthread/config.h>
+#include <sys/types.h>
+#include <time.h>
+
+#ifndef _OS_HAS_TIMESPEC
+struct timespec {
+ time_t tv_sec;
+ long tv_nsec;
+};
+#endif
+
+#define TIMEVAL_TO_TIMESPEC(tv, ts) { \
+ (ts)->tv_sec = (tv)->tv_sec; \
+ (ts)->tv_nsec = (tv)->tv_usec * 1000; \
+}
+#define TIMESPEC_TO_TIMEVAL(tv, ts) { \
+ (tv)->tv_sec = (ts)->tv_sec; \
+ (tv)->tv_usec = (ts)->tv_nsec / 1000; \
+}
+
+/*
+ * New functions
+ */
+
+__BEGIN_DECLS
+
+__END_DECLS
+
+#endif
diff --git a/mit-pthreads/machdep/linux-1.0/uio.h b/mit-pthreads/machdep/linux-1.0/uio.h
new file mode 100755
index 00000000000..67af5bf76e0
--- /dev/null
+++ b/mit-pthreads/machdep/linux-1.0/uio.h
@@ -0,0 +1,15 @@
+/* ==== uio.h ============================================================
+ * Copyright (c) 1994 by Chris Provenzano, proven@athena.mit.edu
+ *
+ * Description : Correct Linux header file.
+ */
+
+#ifndef _PTHREAD_UIO_H_
+#define _PTHREAD_UIO_H_
+
+struct iovec {
+ void *iov_base;
+ size_t iov_len;
+};
+
+#endif
diff --git a/mit-pthreads/machdep/linux-1.0/wait.h b/mit-pthreads/machdep/linux-1.0/wait.h
new file mode 100755
index 00000000000..bcc28c5ef58
--- /dev/null
+++ b/mit-pthreads/machdep/linux-1.0/wait.h
@@ -0,0 +1,98 @@
+/* $NetBSD: wait.h,v 1.7 1994/06/29 06:46:23 cgd Exp $ */
+
+/*
+ * Copyright (c) 1982, 1986, 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)wait.h 8.1 (Berkeley) 6/2/93
+ */
+
+/*
+ * This file holds definitions relevent to the wait4 system call
+ * and the alternate interfaces that use it (wait, wait3, waitpid).
+ */
+
+/*
+ * Macros to test the exit status returned by wait and extract the
+ * relevant values. Union wait is no supported with pthreads.
+ */
+#define __W_INT(i) (i)
+#define __WSTATUS(x) (__W_INT(x) & 0177)
+#define __WSTOPPED 0177 /* __WSTATUS if process is stopped */
+#define WIFSTOPPED(x) (__WSTATUS(x) == __WSTOPPED)
+#define WSTOPSIG(x) (__W_INT(x) >> 8)
+#define WIFSIGNALED(x) (__WSTATUS(x) != __WSTOPPED && __WSTATUS(x) != 0)
+#define WTERMSIG(x) (__WSTATUS(x))
+#define WIFEXITED(x) (__WSTATUS(x) == 0)
+#define WEXITSTATUS(x) (__W_INT(x) >> 8)
+
+#ifndef _POSIX_SOURCE
+#define WCOREDUMP(x) (__W_INT(x) & WCOREFLAG)
+#define W_EXITCODE(ret, sig) ((ret) << 8 | (sig))
+#define W_STOPCODE(sig) ((sig) << 8 | __WSTOPPED)
+#endif
+
+/*
+ * Option bits for the third argument of wait4. WNOHANG causes the
+ * wait to not hang if there are no stopped or terminated processes, rather
+ * returning an error indication in this case (pid==0). WUNTRACED
+ * indicates that the caller should receive status about untraced children
+ * which stop due to signals. If children are stopped and a wait without
+ * this option is done, it is as though they were still running... nothing
+ * about them is returned.
+ */
+#define WNOHANG 1 /* dont hang in wait */
+#define WUNTRACED 2 /* tell about stopped, untraced children */
+
+#ifndef _POSIX_SOURCE
+
+/* Tokens for special values of the "pid" parameter to wait4. */
+#define WAIT_ANY (-1) /* any process */
+#define WAIT_MYPGRP 0 /* any process in my process group */
+
+#define WSTOPPED __WSTOPPED
+#endif /* _POSIX_SOURCE */
+
+#include <sys/types.h>
+#include <sys/cdefs.h>
+
+#ifndef __WAIT_STATUS
+#define __WAIT_STATUS int *
+#endif
+
+__BEGIN_DECLS
+pid_t wait __P_((int *));
+pid_t waitpid __P_((pid_t, int *, int));
+#ifndef _POSIX_SOURCE
+pid_t wait3 __P_((int *, int, void *));
+pid_t wait4 __P_((pid_t, int *, int, void *));
+#endif
+__END_DECLS
diff --git a/mit-pthreads/machdep/linux-2.0/__math.h b/mit-pthreads/machdep/linux-2.0/__math.h
new file mode 100755
index 00000000000..05c65d58321
--- /dev/null
+++ b/mit-pthreads/machdep/linux-2.0/__math.h
@@ -0,0 +1,4 @@
+#ifndef HUGE_VAL
+#define HUGE_VAL DBL_MAX
+#endif
+
diff --git a/mit-pthreads/machdep/linux-2.0/__path.h b/mit-pthreads/machdep/linux-2.0/__path.h
new file mode 100755
index 00000000000..9caeb7d3016
--- /dev/null
+++ b/mit-pthreads/machdep/linux-2.0/__path.h
@@ -0,0 +1,14 @@
+/*
+ * from: @(#)time.h 5.12 (Berkeley) 3/9/91
+ * $Id$
+ */
+
+#ifndef _SYS__PATH_H_
+#define _SYS__PATH_H_
+
+#define _PATH_PTY "/dev/"
+#define _PATH_TZDIR "/usr/lib/zoneinfo"
+#define _PATH_TZFILE "/usr/lib/zoneinfo/localtime"
+
+#endif /* !_SYS__PATH_H_ */
+
diff --git a/mit-pthreads/machdep/linux-2.0/__signal.h b/mit-pthreads/machdep/linux-2.0/__signal.h
new file mode 100755
index 00000000000..4cd671f155c
--- /dev/null
+++ b/mit-pthreads/machdep/linux-2.0/__signal.h
@@ -0,0 +1,24 @@
+#include <features.h>
+#include <linux/signal.h>
+
+#ifndef SIGCLD
+#define SIGCLD SIGCHLD
+#endif
+
+typedef int sig_atomic_t;
+
+typedef __sighandler_t SignalHandler;
+
+#define SignalBad ((SignalHandler)-1)
+#define SignalDefault ((SignalHandler)0)
+#define SignalIgnore ((SignalHandler)1)
+
+#define __sigmask(sig) (1 << ((sig) - 1))
+#define sigmask __sigmask
+
+#define __SIGFILLSET 0xffffffff
+#define __SIGEMPTYSET 0
+#define __SIGADDSET(s,n) ((*s) |= (__sigmask(n)))
+#define __SIGDELSET(s,n) ((*s) &= ~(__sigmask(n)))
+#define __SIGISMEMBER(s,n) ((*s) & (__sigmask(n)))
+
diff --git a/mit-pthreads/machdep/linux-2.0/__stdio.h b/mit-pthreads/machdep/linux-2.0/__stdio.h
new file mode 100755
index 00000000000..eb7e904c34d
--- /dev/null
+++ b/mit-pthreads/machdep/linux-2.0/__stdio.h
@@ -0,0 +1,7 @@
+
+#ifndef _SIZE_T
+#define _SIZE_T
+typedef pthread_size_t size_t;
+#endif
+
+typedef pthread_fpos_t fpos_t;
diff --git a/mit-pthreads/machdep/linux-2.0/__stdlib.h b/mit-pthreads/machdep/linux-2.0/__stdlib.h
new file mode 100755
index 00000000000..eaa0bb988ee
--- /dev/null
+++ b/mit-pthreads/machdep/linux-2.0/__stdlib.h
@@ -0,0 +1,20 @@
+
+#ifndef _SYS___STDLIB_H_
+#define _SYS___STDLIB_H_
+
+#include <features.h>
+
+/* Get size_t, wchar_t and NULL from <stddef.h>. */
+#define __need_size_t
+#define __need_wchar_t
+#define __need_NULL
+#include <stddef.h>
+
+#define __need_Emath
+#include <errno.h>
+
+/* Get HUGE_VAL (returned by strtod on overflow) from <float.h>. */
+#define __need_HUGE_VAL
+#include <float.h>
+
+#endif
diff --git a/mit-pthreads/machdep/linux-2.0/__string.h b/mit-pthreads/machdep/linux-2.0/__string.h
new file mode 100755
index 00000000000..8a5e09608e0
--- /dev/null
+++ b/mit-pthreads/machdep/linux-2.0/__string.h
@@ -0,0 +1,18 @@
+
+#ifndef _SIZE_T
+#define _SIZE_T
+typedef pthread_size_t size_t;
+#endif
+
+/* Non-standard Linux string routines. */
+#if !defined(_ANSI_SOURCE) && !defined(_POSIX_SOURCE)
+__BEGIN_DECLS
+int bcmp __P_((const void *, const void *, size_t));
+void bcopy __P_((const void *, void *, size_t));
+void bzero __P_((void *, size_t));
+char *index __P_((const char *, int));
+char *rindex __P_((const char *, int));
+char *strdup __P_((const char *));
+char *strsep __P_((char **, const char *));
+__END_DECLS
+#endif
diff --git a/mit-pthreads/machdep/linux-2.0/__time.h b/mit-pthreads/machdep/linux-2.0/__time.h
new file mode 100755
index 00000000000..b86c153543a
--- /dev/null
+++ b/mit-pthreads/machdep/linux-2.0/__time.h
@@ -0,0 +1,78 @@
+/* ==== __time.h ============================================================
+ * Copyright (c) 1994 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ *
+ * Description : System specific time header.
+ *
+ * 1.00 94/11/07 proven
+ * -Started coding this file.
+ */
+
+#ifndef _SYS___TIME_H_
+#define _SYS___TIME_H_
+
+#include <features.h>
+
+struct timespec
+ {
+ long int tv_sec; /* Seconds. */
+ long int tv_nsec; /* Nanoseconds. */
+ };
+
+#ifndef _SIZE_T
+#define _SIZE_T
+typedef unsigned int size_t;
+#endif
+#ifndef _CLOCK_T
+#define _CLOCK_T
+typedef long clock_t;
+#endif
+#ifndef _TIME_T
+#define _TIME_T
+typedef long time_t;
+
+#ifndef NULL
+#ifdef __cplusplus
+#define NULL 0
+#else
+#define NULL ((void *) 0)
+#endif
+#endif
+#endif
+
+#define CLOCKS_PER_SEC 100
+#define CLK_TCK 100
+
+extern long int timezone;
+extern int daylight;
+
+#endif
diff --git a/mit-pthreads/machdep/linux-2.0/__unistd.h b/mit-pthreads/machdep/linux-2.0/__unistd.h
new file mode 100755
index 00000000000..444f070659a
--- /dev/null
+++ b/mit-pthreads/machdep/linux-2.0/__unistd.h
@@ -0,0 +1,62 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)stdlib.h 5.13 (Berkeley) 6/4/91
+ * $Id$
+ */
+
+#ifndef _SYS___UNISTD_H_
+#define _SYS___UNISTD_H_
+
+#include <features.h>
+
+/* POSIX Standard approved as IEEE Std 1003.1 as of August, 1988. */
+#define _POSIX_VERSION 199009L
+#define _POSIX2_C_BIND 1
+#define _POSIX2_C_DEV 1
+#define _POSIX2_SW_DEV 1
+
+#define __need_size_t
+
+#include <sys/types.h>
+#include <stddef.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+int chroot(const char *);
+int gethostname(char *, int);
+#ifdef __cplusplus
+}
+#endif
+#endif
+
diff --git a/mit-pthreads/machdep/linux-2.0/cdefs.h b/mit-pthreads/machdep/linux-2.0/cdefs.h
new file mode 100755
index 00000000000..04f93a138c9
--- /dev/null
+++ b/mit-pthreads/machdep/linux-2.0/cdefs.h
@@ -0,0 +1,36 @@
+/* This is intended to eventually find /usr/include/sys/cdefs.h
+ * if it's inside the ifdef then it won't work if this file is
+ * found in the include files path more than once.
+ *
+ * include_next is a GNU C extension, we might eventually want
+ * to have our own cdefs in here simply to avoid GNU C dependencies
+ * (though there are already enough in the asm stuff anyways)
+ * [gsstark:19950419.0307EST]
+ */
+
+/* We are almost always included from features.h. */
+
+#ifndef _FEATURES_H
+#include <features.h>
+#endif
+
+#ifndef __BITS_SOCKET_H
+#define __BITS_SOCKET_H
+#endif
+
+#define __need_timespec
+
+#include_next <sys/cdefs.h>
+
+#ifndef _PTHREAD_SYS_CDEFS_H_
+#define _PTHREAD_SYS_CDEFS_H_
+
+#ifndef __NORETURN
+#define __NORETURN
+#endif /* __NORETURN not defined. */
+
+#if !defined(__cplusplus)
+#define __CAN_DO_EXTERN_INLINE
+#endif
+
+#endif /* _PTHREAD_SYS_CDEFS_H_ */
diff --git a/mit-pthreads/machdep/linux-2.0/compat.h b/mit-pthreads/machdep/linux-2.0/compat.h
new file mode 100755
index 00000000000..6edb992ac3d
--- /dev/null
+++ b/mit-pthreads/machdep/linux-2.0/compat.h
@@ -0,0 +1,47 @@
+/* ==== compat.h ============================================================
+ * Copyright (c) 1994 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ *
+ * Description : Basic timers header.
+ *
+ * 1.00 94/06/13 proven
+ * -Started coding this file.
+ */
+
+#ifndef _SYS_COMPAT_H_
+#define _SYS_COMPAT_H_
+
+#include <sys/types.h>
+
+#define omsghdr msghdr
+
+#endif
diff --git a/mit-pthreads/machdep/linux-2.0/dirent.h b/mit-pthreads/machdep/linux-2.0/dirent.h
new file mode 100755
index 00000000000..7f783a198e0
--- /dev/null
+++ b/mit-pthreads/machdep/linux-2.0/dirent.h
@@ -0,0 +1,27 @@
+
+#ifndef _SYS_DIRENT_H
+#define _SYS_DIRENT_H
+
+#include <sys/types.h>
+#include <linux/limits.h>
+
+struct dirent {
+ long d_ino;
+ off_t d_off;
+ unsigned short d_reclen;
+ char d_name[NAME_MAX+1];
+};
+
+#ifndef d_fileno
+#define d_fileno d_ino
+#endif
+
+#ifndef d_namlen
+#define d_namlen d_reclen
+#endif
+
+#ifndef MAXNAMLEN
+#define MAXNAMLEN NAME_MAX
+#endif
+
+#endif
diff --git a/mit-pthreads/machdep/linux-2.0/errno.h b/mit-pthreads/machdep/linux-2.0/errno.h
new file mode 100755
index 00000000000..a94a56b0437
--- /dev/null
+++ b/mit-pthreads/machdep/linux-2.0/errno.h
@@ -0,0 +1,12 @@
+/* ==== errno.h ============================================================
+ * Copyright (c) 1994 by Chris Provenzano, proven@athena.mit.edu
+ *
+ * Description : Errno is already broken up into data/prototyes.
+ */
+
+#ifndef _SYS_ERRNO_H_
+#define _SYS_ERRNO_H_
+
+#include <linux/errno.h>
+
+#endif
diff --git a/mit-pthreads/machdep/linux-2.0/extra/bits/local_lim.h b/mit-pthreads/machdep/linux-2.0/extra/bits/local_lim.h
new file mode 100644
index 00000000000..1a319ccdfd4
--- /dev/null
+++ b/mit-pthreads/machdep/linux-2.0/extra/bits/local_lim.h
@@ -0,0 +1,15 @@
+/* Minimum guaranteed maximum values for system limits. Linux version.
+
+/* The kernel header pollutes the namespace with the NR_OPEN symbol.
+ Remove this after including the header if necessary. */
+
+#ifndef NR_OPEN
+# define __undef_NR_OPEN
+#endif
+
+#include <linux/limits.h>
+
+#ifdef __undef_NR_OPEN
+# undef NR_OPEN
+# undef __undef_NR_OPEN
+#endif
diff --git a/mit-pthreads/machdep/linux-2.0/extra/bits/socket.h b/mit-pthreads/machdep/linux-2.0/extra/bits/socket.h
new file mode 100755
index 00000000000..cc4c0fd262e
--- /dev/null
+++ b/mit-pthreads/machdep/linux-2.0/extra/bits/socket.h
@@ -0,0 +1,193 @@
+/* ==== socket.h.h ============================================================
+ * Copyright (c) 1994 by Chris Provenzano, proven@athena.mit.edu
+ *
+ * Description : Correct Linux header file.
+ */
+
+#ifndef _PTHREAD_SOCKET_H_
+#define _PTHREAD_SOCKET_H_
+
+/* #include <linux/socket.h> */
+#ifndef _LINUX_SOCKET_H
+#define _LINUX_SOCKET_H
+
+/* IP options */
+#define IP_TOS 1
+#define IPTOS_LOWDELAY 0x10
+#define IPTOS_THROUGHPUT 0x08
+#define IPTOS_RELIABILITY 0x04
+#define IP_TTL 2
+#ifndef IP_HDRINCL
+#define IP_HDRINCL 3
+#endif
+#ifdef V1_3_WILL_DO_THIS_FUNKY_STUFF
+#define IP_OPTIONS 4
+#endif
+
+#endif
+
+/* #include <asm/socket.h> arch-dependent defines */
+#include <linux/sockios.h> /* the SIOCxxx I/O controls */
+#include <pthread/posix.h>
+
+struct sockaddr {
+ unsigned short sa_family; /* address family, AF_xxx */
+ char sa_data[14]; /* 14 bytes of protocol address */
+};
+
+struct linger {
+ int l_onoff; /* Linger active */
+ int l_linger; /* How long to linger for */
+};
+
+struct msghdr
+{
+ void * msg_name; /* Socket name */
+ int msg_namelen; /* Length of name */
+ struct iovec * msg_iov; /* Data blocks */
+ int msg_iovlen; /* Number of blocks */
+ void * msg_accrights; /* Per protocol magic (eg BSD file descriptor passing) */
+ int msg_accrightslen;/* Length of rights list */
+};
+
+/* Socket types. */
+#define SOCK_STREAM 1 /* stream (connection) socket */
+#define SOCK_DGRAM 2 /* datagram (conn.less) socket */
+#define SOCK_RAW 3 /* raw socket */
+#define SOCK_RDM 4 /* reliably-delivered message */
+#define SOCK_SEQPACKET 5 /* sequential packet socket */
+#define SOCK_PACKET 10 /* linux specific way of */
+ /* getting packets at the dev */
+ /* level. For writing rarp and */
+ /* other similar things on the */
+ /* user level. */
+
+/* Supported address families. */
+#define AF_UNSPEC 0
+#define AF_UNIX 1 /* Unix domain sockets */
+#define AF_INET 2 /* Internet IP Protocol */
+#define AF_AX25 3 /* Amateur Radio AX.25 */
+#define AF_IPX 4 /* Novell IPX */
+#define AF_APPLETALK 5 /* Appletalk DDP */
+#define AF_NETROM 6 /* Amateur radio NetROM */
+#define AF_BRIDGE 7 /* Multiprotocol bridge */
+#define AF_AAL5 8 /* Reserved for Werner's ATM */
+#define AF_X25 9 /* Reserved for X.25 project */
+#define AF_INET6 10 /* IP version 6 */
+#define AF_MAX 12 /* For now.. */
+
+/* Protocol families, same as address families. */
+#define PF_UNSPEC AF_UNSPEC
+#define PF_UNIX AF_UNIX
+#define PF_INET AF_INET
+#define PF_AX25 AF_AX25
+#define PF_IPX AF_IPX
+#define PF_APPLETALK AF_APPLETALK
+#define PF_NETROM AF_NETROM
+#define PF_BRIDGE AF_BRIDGE
+#define PF_AAL5 AF_AAL5
+#define PF_X25 AF_X25
+#define PF_INET6 AF_INET6
+
+#define PF_MAX AF_MAX
+
+/* Maximum queue length specificable by listen. */
+#define SOMAXCONN 128
+
+/* Flags we can use with send/ and recv. */
+#define MSG_OOB 1
+#define MSG_PEEK 2
+#define MSG_DONTROUTE 4
+
+/* Setsockoptions(2) level. Thanks to BSD these must match IPPROTO_xxx */
+#define SOL_SOCKET 1
+#define SOL_IP 0
+#define SOL_IPX 256
+#define SOL_AX25 257
+#define SOL_ATALK 258
+#define SOL_NETROM 259
+#define SOL_TCP 6
+#define SOL_UDP 17
+
+/* For setsockoptions(2) */
+#define SO_DEBUG 1
+#define SO_REUSEADDR 2
+#define SO_TYPE 3
+#define SO_ERROR 4
+#define SO_DONTROUTE 5
+#define SO_BROADCAST 6
+#define SO_SNDBUF 7
+#define SO_RCVBUF 8
+#define SO_KEEPALIVE 9
+#define SO_OOBINLINE 10
+#define SO_NO_CHECK 11
+#define SO_PRIORITY 12
+#define SO_LINGER 13
+/* To add :#define SO_REUSEPORT 14 */
+
+
+#define IP_MULTICAST_IF 32
+#define IP_MULTICAST_TTL 33
+#define IP_MULTICAST_LOOP 34
+#define IP_ADD_MEMBERSHIP 35
+#define IP_DROP_MEMBERSHIP 36
+
+
+/* These need to appear somewhere around here */
+#define IP_DEFAULT_MULTICAST_TTL 1
+#define IP_DEFAULT_MULTICAST_LOOP 1
+#define IP_MAX_MEMBERSHIPS 20
+
+/* IPX options */
+#define IPX_TYPE 1
+
+/* TCP options - this way around because someone left a set in the c library includes */
+#define TCP_NODELAY 1
+#define TCP_MAXSEG 2
+
+/* The various priorities. */
+#define SOPRI_INTERACTIVE 0
+#define SOPRI_NORMAL 1
+#define SOPRI_BACKGROUND 2
+
+/*
+ * Functions
+ */
+
+__BEGIN_DECLS
+
+int accept __P_((int, struct sockaddr *, int *));
+int bind __P_((int, const struct sockaddr *, int));
+int connect __P_((int, const struct sockaddr *, int));
+int listen __P_((int, int));
+int socket __P_((int, int, int));
+
+int getsockopt __P_((int __s, int __level, int __optname,
+ void *__optval, int *__optlen));
+int setsockopt __P_((int __s, int __level, int __optname,
+ __const void *__optval, int optlen));
+int getsockname __P_((int __sockfd, struct sockaddr *__addr,
+ int *__paddrlen));
+int getpeername __P_((int __sockfd, struct sockaddr *__peer,
+ int *__paddrlen));
+ssize_t send __P_((int __sockfd, __const void *__buff, size_t __len, int __flags));
+ssize_t recv __P_((int __sockfd, void *__buff, size_t __len, int __flags));
+ssize_t sendto __P_((int __sockfd, __const void *__buff, size_t __len,
+ int __flags, __const struct sockaddr *__to,
+ int __tolen));
+ssize_t recvfrom __P_((int __sockfd, void *__buff, size_t __len,
+ int __flags, struct sockaddr *__from,
+ int *__fromlen));
+extern ssize_t sendmsg __P_((int __fd, __const struct msghdr *__message,
+ int __flags));
+extern ssize_t recvmsg __P_((int __fd, struct msghdr *__message,
+ int __flags));
+int shutdown __P_((int __sockfd, int __how));
+
+__END_DECLS
+
+#endif
+
+
+
+
diff --git a/mit-pthreads/machdep/linux-2.0/socket.h b/mit-pthreads/machdep/linux-2.0/socket.h
new file mode 100755
index 00000000000..fb43c394e10
--- /dev/null
+++ b/mit-pthreads/machdep/linux-2.0/socket.h
@@ -0,0 +1,196 @@
+/* ==== socket.h.h ============================================================
+ * Copyright (c) 1994 by Chris Provenzano, proven@athena.mit.edu
+ *
+ * Description : Correct Linux header file.
+ */
+
+#ifndef _PTHREAD_SOCKET_H_
+#define _PTHREAD_SOCKET_H_
+
+/* #include <linux/socket.h> */
+#ifndef _LINUX_SOCKET_H
+#define _LINUX_SOCKET_H
+
+/* IP options */
+#define IP_TOS 1
+#define IPTOS_LOWDELAY 0x10
+#define IPTOS_THROUGHPUT 0x08
+#define IPTOS_RELIABILITY 0x04
+#define IP_TTL 2
+#ifndef IP_HDRINCL
+#define IP_HDRINCL 3
+#endif
+#ifdef V1_3_WILL_DO_THIS_FUNKY_STUFF
+#define IP_OPTIONS 4
+#endif
+
+#endif
+
+/* Type for length arguments in socket calls. */
+typedef unsigned int socklen_t;
+
+/* #include <asm/socket.h> arch-dependent defines */
+#include <linux/sockios.h> /* the SIOCxxx I/O controls */
+#include <pthread/posix.h>
+
+struct sockaddr {
+ unsigned short sa_family; /* address family, AF_xxx */
+ char sa_data[14]; /* 14 bytes of protocol address */
+};
+
+struct linger {
+ int l_onoff; /* Linger active */
+ int l_linger; /* How long to linger for */
+};
+
+struct msghdr
+{
+ void * msg_name; /* Socket name */
+ int msg_namelen; /* Length of name */
+ struct iovec * msg_iov; /* Data blocks */
+ int msg_iovlen; /* Number of blocks */
+ void * msg_accrights; /* Per protocol magic (eg BSD file descriptor passing) */
+ int msg_accrightslen;/* Length of rights list */
+};
+
+/* Socket types. */
+#define SOCK_STREAM 1 /* stream (connection) socket */
+#define SOCK_DGRAM 2 /* datagram (conn.less) socket */
+#define SOCK_RAW 3 /* raw socket */
+#define SOCK_RDM 4 /* reliably-delivered message */
+#define SOCK_SEQPACKET 5 /* sequential packet socket */
+#define SOCK_PACKET 10 /* linux specific way of */
+ /* getting packets at the dev */
+ /* level. For writing rarp and */
+ /* other similar things on the */
+ /* user level. */
+
+/* Supported address families. */
+#define AF_UNSPEC 0
+#define AF_UNIX 1 /* Unix domain sockets */
+#define AF_INET 2 /* Internet IP Protocol */
+#define AF_AX25 3 /* Amateur Radio AX.25 */
+#define AF_IPX 4 /* Novell IPX */
+#define AF_APPLETALK 5 /* Appletalk DDP */
+#define AF_NETROM 6 /* Amateur radio NetROM */
+#define AF_BRIDGE 7 /* Multiprotocol bridge */
+#define AF_AAL5 8 /* Reserved for Werner's ATM */
+#define AF_X25 9 /* Reserved for X.25 project */
+#define AF_INET6 10 /* IP version 6 */
+#define AF_MAX 12 /* For now.. */
+
+/* Protocol families, same as address families. */
+#define PF_UNSPEC AF_UNSPEC
+#define PF_UNIX AF_UNIX
+#define PF_INET AF_INET
+#define PF_AX25 AF_AX25
+#define PF_IPX AF_IPX
+#define PF_APPLETALK AF_APPLETALK
+#define PF_NETROM AF_NETROM
+#define PF_BRIDGE AF_BRIDGE
+#define PF_AAL5 AF_AAL5
+#define PF_X25 AF_X25
+#define PF_INET6 AF_INET6
+
+#define PF_MAX AF_MAX
+
+/* Maximum queue length specificable by listen. */
+#define SOMAXCONN 128
+
+/* Flags we can use with send/ and recv. */
+#define MSG_OOB 1
+#define MSG_PEEK 2
+#define MSG_DONTROUTE 4
+
+/* Setsockoptions(2) level. Thanks to BSD these must match IPPROTO_xxx */
+#define SOL_SOCKET 1
+#define SOL_IP 0
+#define SOL_IPX 256
+#define SOL_AX25 257
+#define SOL_ATALK 258
+#define SOL_NETROM 259
+#define SOL_TCP 6
+#define SOL_UDP 17
+
+/* For setsockoptions(2) */
+#define SO_DEBUG 1
+#define SO_REUSEADDR 2
+#define SO_TYPE 3
+#define SO_ERROR 4
+#define SO_DONTROUTE 5
+#define SO_BROADCAST 6
+#define SO_SNDBUF 7
+#define SO_RCVBUF 8
+#define SO_KEEPALIVE 9
+#define SO_OOBINLINE 10
+#define SO_NO_CHECK 11
+#define SO_PRIORITY 12
+#define SO_LINGER 13
+/* To add :#define SO_REUSEPORT 14 */
+
+
+#define IP_MULTICAST_IF 32
+#define IP_MULTICAST_TTL 33
+#define IP_MULTICAST_LOOP 34
+#define IP_ADD_MEMBERSHIP 35
+#define IP_DROP_MEMBERSHIP 36
+
+
+/* These need to appear somewhere around here */
+#define IP_DEFAULT_MULTICAST_TTL 1
+#define IP_DEFAULT_MULTICAST_LOOP 1
+#define IP_MAX_MEMBERSHIPS 20
+
+/* IPX options */
+#define IPX_TYPE 1
+
+/* TCP options - this way around because someone left a set in the c library includes */
+#define TCP_NODELAY 1
+#define TCP_MAXSEG 2
+
+/* The various priorities. */
+#define SOPRI_INTERACTIVE 0
+#define SOPRI_NORMAL 1
+#define SOPRI_BACKGROUND 2
+
+/*
+ * Functions
+ */
+
+__BEGIN_DECLS
+
+int accept __P_((int, struct sockaddr *, socklen_t *));
+int bind __P_((int, const struct sockaddr *, socklen_t));
+int connect __P_((int, const struct sockaddr *, socklen_t));
+int listen __P_((int, int));
+int socket __P_((int, int, int));
+
+int getsockopt __P_((int __s, int __level, int __optname,
+ void *__optval, socklen_t *__optlen));
+int setsockopt __P_((int __s, int __level, int __optname,
+ __const void *__optval, socklen_t optlen));
+int getsockname __P_((int __sockfd, struct sockaddr *__addr,
+ socklen_t *__paddrlen));
+int getpeername __P_((int __sockfd, struct sockaddr *__peer,
+ socklen_t *__paddrlen));
+ssize_t send __P_((int __sockfd, __const void *__buff, size_t __len, int __flags));
+ssize_t recv __P_((int __sockfd, void *__buff, size_t __len, int __flags));
+ssize_t sendto __P_((int __sockfd, __const void *__buff, size_t __len,
+ int __flags, __const struct sockaddr *__to,
+ socklen_t __tolen));
+ssize_t recvfrom __P_((int __sockfd, void *__buff, size_t __len,
+ int __flags, struct sockaddr *__from,
+ socklen_t *__fromlen));
+extern ssize_t sendmsg __P_((int __fd, __const struct msghdr *__message,
+ int __flags));
+extern ssize_t recvmsg __P_((int __fd, struct msghdr *__message,
+ int __flags));
+int shutdown __P_((int __sockfd, int __how));
+
+__END_DECLS
+
+#endif
+
+
+
+
diff --git a/mit-pthreads/machdep/linux-2.0/socketcall.h b/mit-pthreads/machdep/linux-2.0/socketcall.h
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/mit-pthreads/machdep/linux-2.0/socketcall.h
diff --git a/mit-pthreads/machdep/linux-2.0/timers.h b/mit-pthreads/machdep/linux-2.0/timers.h
new file mode 100755
index 00000000000..110cb27378c
--- /dev/null
+++ b/mit-pthreads/machdep/linux-2.0/timers.h
@@ -0,0 +1,71 @@
+/* ==== timers.h ============================================================
+ * Copyright (c) 1994 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ *
+ * Description : Basic timers header.
+ *
+ * 1.00 94/06/13 proven
+ * -Started coding this file.
+ */
+
+#ifndef _SYS_TIMERS_H_
+#define _SYS_TIMERS_H_
+
+#include <pthread/config.h>
+#include <sys/types.h>
+#include <time.h>
+
+#ifndef _OS_HAS_TIMESPEC
+struct timespec {
+ time_t tv_sec;
+ long tv_nsec;
+};
+#endif
+
+#define TIMEVAL_TO_TIMESPEC(tv, ts) { \
+ (ts)->tv_sec = (tv)->tv_sec; \
+ (ts)->tv_nsec = (tv)->tv_usec * 1000; \
+}
+#define TIMESPEC_TO_TIMEVAL(tv, ts) { \
+ (tv)->tv_sec = (ts)->tv_sec; \
+ (tv)->tv_usec = (ts)->tv_nsec / 1000; \
+}
+
+/*
+ * New functions
+ */
+
+__BEGIN_DECLS
+
+__END_DECLS
+
+#endif
diff --git a/mit-pthreads/machdep/linux-2.0/uio.h b/mit-pthreads/machdep/linux-2.0/uio.h
new file mode 100755
index 00000000000..67af5bf76e0
--- /dev/null
+++ b/mit-pthreads/machdep/linux-2.0/uio.h
@@ -0,0 +1,15 @@
+/* ==== uio.h ============================================================
+ * Copyright (c) 1994 by Chris Provenzano, proven@athena.mit.edu
+ *
+ * Description : Correct Linux header file.
+ */
+
+#ifndef _PTHREAD_UIO_H_
+#define _PTHREAD_UIO_H_
+
+struct iovec {
+ void *iov_base;
+ size_t iov_len;
+};
+
+#endif
diff --git a/mit-pthreads/machdep/linux-2.0/wait.h b/mit-pthreads/machdep/linux-2.0/wait.h
new file mode 100755
index 00000000000..bcc28c5ef58
--- /dev/null
+++ b/mit-pthreads/machdep/linux-2.0/wait.h
@@ -0,0 +1,98 @@
+/* $NetBSD: wait.h,v 1.7 1994/06/29 06:46:23 cgd Exp $ */
+
+/*
+ * Copyright (c) 1982, 1986, 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)wait.h 8.1 (Berkeley) 6/2/93
+ */
+
+/*
+ * This file holds definitions relevent to the wait4 system call
+ * and the alternate interfaces that use it (wait, wait3, waitpid).
+ */
+
+/*
+ * Macros to test the exit status returned by wait and extract the
+ * relevant values. Union wait is no supported with pthreads.
+ */
+#define __W_INT(i) (i)
+#define __WSTATUS(x) (__W_INT(x) & 0177)
+#define __WSTOPPED 0177 /* __WSTATUS if process is stopped */
+#define WIFSTOPPED(x) (__WSTATUS(x) == __WSTOPPED)
+#define WSTOPSIG(x) (__W_INT(x) >> 8)
+#define WIFSIGNALED(x) (__WSTATUS(x) != __WSTOPPED && __WSTATUS(x) != 0)
+#define WTERMSIG(x) (__WSTATUS(x))
+#define WIFEXITED(x) (__WSTATUS(x) == 0)
+#define WEXITSTATUS(x) (__W_INT(x) >> 8)
+
+#ifndef _POSIX_SOURCE
+#define WCOREDUMP(x) (__W_INT(x) & WCOREFLAG)
+#define W_EXITCODE(ret, sig) ((ret) << 8 | (sig))
+#define W_STOPCODE(sig) ((sig) << 8 | __WSTOPPED)
+#endif
+
+/*
+ * Option bits for the third argument of wait4. WNOHANG causes the
+ * wait to not hang if there are no stopped or terminated processes, rather
+ * returning an error indication in this case (pid==0). WUNTRACED
+ * indicates that the caller should receive status about untraced children
+ * which stop due to signals. If children are stopped and a wait without
+ * this option is done, it is as though they were still running... nothing
+ * about them is returned.
+ */
+#define WNOHANG 1 /* dont hang in wait */
+#define WUNTRACED 2 /* tell about stopped, untraced children */
+
+#ifndef _POSIX_SOURCE
+
+/* Tokens for special values of the "pid" parameter to wait4. */
+#define WAIT_ANY (-1) /* any process */
+#define WAIT_MYPGRP 0 /* any process in my process group */
+
+#define WSTOPPED __WSTOPPED
+#endif /* _POSIX_SOURCE */
+
+#include <sys/types.h>
+#include <sys/cdefs.h>
+
+#ifndef __WAIT_STATUS
+#define __WAIT_STATUS int *
+#endif
+
+__BEGIN_DECLS
+pid_t wait __P_((int *));
+pid_t waitpid __P_((pid_t, int *, int));
+#ifndef _POSIX_SOURCE
+pid_t wait3 __P_((int *, int, void *));
+pid_t wait4 __P_((pid_t, int *, int, void *));
+#endif
+__END_DECLS
diff --git a/mit-pthreads/machdep/netbsd-0.9/dirent.h b/mit-pthreads/machdep/netbsd-0.9/dirent.h
new file mode 100755
index 00000000000..5226443f86b
--- /dev/null
+++ b/mit-pthreads/machdep/netbsd-0.9/dirent.h
@@ -0,0 +1,64 @@
+/*-
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)dirent.h 5.18 (Berkeley) 2/23/91
+ */
+
+#ifndef _SYS_DIRENT_H_
+#define _SYS_DIRENT_H_
+
+/*
+ * A directory entry has a struct dirent at the front of it, containing its
+ * inode number, the length of the entry, and the length of the name
+ * contained in the entry. These are followed by the name padded to a 4
+ * byte boundary with null bytes. All names are guaranteed null terminated.
+ * The maximum length of a name in a directory is MAXNAMLEN.
+ */
+
+struct dirent {
+ u_long d_fileno; /* file number of entry */
+ u_short d_reclen; /* length of this record */
+ u_short d_namlen; /* length of string in d_name */
+#ifdef _POSIX_SOURCE
+ char d_name[255 + 1]; /* name must be no longer than this */
+#else
+#define MAXNAMLEN 255
+ char d_name[MAXNAMLEN + 1]; /* name must be no longer than this */
+#endif
+};
+
+#define d_ino d_fileno /* backward compatibility */
+
+/* definitions for library routines operating on directories. */
+#define DIRBLKSIZ 1024
+
+#endif /* !_DIRENT_H_ */
diff --git a/mit-pthreads/machdep/netbsd-1.0/__math.h b/mit-pthreads/machdep/netbsd-1.0/__math.h
new file mode 100755
index 00000000000..dc009d822f4
--- /dev/null
+++ b/mit-pthreads/machdep/netbsd-1.0/__math.h
@@ -0,0 +1,6 @@
+/*
+ * ANSI/POSIX
+ */
+extern char __infinity[];
+#define HUGE_VAL (*(double *) __infinity)
+
diff --git a/mit-pthreads/machdep/netbsd-1.0/__path.h b/mit-pthreads/machdep/netbsd-1.0/__path.h
new file mode 100755
index 00000000000..432494daafa
--- /dev/null
+++ b/mit-pthreads/machdep/netbsd-1.0/__path.h
@@ -0,0 +1,14 @@
+/*
+ * from: @(#)time.h 5.12 (Berkeley) 3/9/91
+ * $Id$
+ */
+
+#ifndef _SYS__PATH_H_
+#define _SYS__PATH_H_
+
+#define _PATH_PTY "/dev/"
+#define _PATH_TZDIR "/usr/share/zoneinfo"
+#define _PATH_TZFILE "/etc/localtime"
+
+#endif /* !_SYS__PATH_H_ */
+
diff --git a/mit-pthreads/machdep/netbsd-1.0/__signal.h b/mit-pthreads/machdep/netbsd-1.0/__signal.h
new file mode 100755
index 00000000000..918955c9948
--- /dev/null
+++ b/mit-pthreads/machdep/netbsd-1.0/__signal.h
@@ -0,0 +1,8 @@
+#include <sys/signal.h>
+
+#define __SIGEMPTYSET 0
+#define __SIGFILLSET 0xffffffff
+#define __SIGADDSET(s, n) (*(s) |= 1 << ((n) - 1), 0)
+#define __SIGDELSET(s, n) (*(s) &= ~(1 << ((n) - 1)), 0)
+#define __SIGISMEMBER(s, n) ((*(s) & (1 << ((n) - 1))) != 0)
+
diff --git a/mit-pthreads/machdep/netbsd-1.0/__stdio.h b/mit-pthreads/machdep/netbsd-1.0/__stdio.h
new file mode 100755
index 00000000000..d60b9df7a54
--- /dev/null
+++ b/mit-pthreads/machdep/netbsd-1.0/__stdio.h
@@ -0,0 +1,8 @@
+
+#include <machine/ansi.h>
+#ifdef _BSD_SIZE_T_
+typedef _BSD_SIZE_T_ size_t;
+#undef _BSD_SIZE_T_
+#endif
+
+typedef pthread_fpos_t fpos_t; /* Must match off_t <sys/types.h> */
diff --git a/mit-pthreads/machdep/netbsd-1.0/__stdlib.h b/mit-pthreads/machdep/netbsd-1.0/__stdlib.h
new file mode 100755
index 00000000000..7b24491b892
--- /dev/null
+++ b/mit-pthreads/machdep/netbsd-1.0/__stdlib.h
@@ -0,0 +1,60 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)stdlib.h 5.13 (Berkeley) 6/4/91
+ * $Id$
+ */
+
+#ifndef _SYS___STDLIB_H_
+#define _SYS___STDLIB_H_
+
+#include <machine/ansi.h>
+
+#ifdef _BSD_SIZE_T_
+typedef _BSD_SIZE_T_ size_t;
+#undef _BSD_SIZE_T_
+#endif
+
+#ifdef _BSD_WCHAR_T_
+typedef _BSD_WCHAR_T_ wchar_t;
+#undef _BSD_WCHAR_T_
+#endif
+
+#ifndef __NORETURN
+#define __NORETURN
+#endif
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#endif /* _STDLIB_H_ */
diff --git a/mit-pthreads/machdep/netbsd-1.0/__string.h b/mit-pthreads/machdep/netbsd-1.0/__string.h
new file mode 100755
index 00000000000..1ebee28e708
--- /dev/null
+++ b/mit-pthreads/machdep/netbsd-1.0/__string.h
@@ -0,0 +1,20 @@
+
+#include <machine/ansi.h>
+#ifdef _BSD_SIZE_T_
+typedef _BSD_SIZE_T_ size_t;
+#undef _BSD_SIZE_T_
+#endif
+
+/* Non-standard NetBSD string routines. */
+#if !defined(_ANSI_SOURCE) && !defined(_POSIX_SOURCE)
+__BEGIN_DECLS
+int bcmp __P_((const void *, const void *, size_t));
+void bcopy __P_((const void *, void *, size_t));
+void bzero __P_((void *, size_t));
+char *index __P_((const char *, int));
+char *rindex __P_((const char *, int));
+char *strdup __P_((const char *));
+void strmode __P_((int, char *));
+char *strsep __P_((char **, const char *));
+__END_DECLS
+#endif
diff --git a/mit-pthreads/machdep/netbsd-1.0/__time.h b/mit-pthreads/machdep/netbsd-1.0/__time.h
new file mode 100755
index 00000000000..16ea9d1f0dd
--- /dev/null
+++ b/mit-pthreads/machdep/netbsd-1.0/__time.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * (c) UNIX System Laboratories, Inc.
+ * All or some portions of this file are derived from material licensed
+ * to the University of California by American Telephone and Telegraph
+ * Co. or Unix System Laboratories, Inc. and are reproduced herein with
+ * the permission of UNIX System Laboratories, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)time.h 5.12 (Berkeley) 3/9/91
+ * $Id$
+ */
+
+#ifndef _SYS__TIME_H_
+#define _SYS__TIME_H_
+
+#include <machine/ansi.h>
+
+#ifdef _BSD_CLOCK_T_
+typedef _BSD_CLOCK_T_ clock_t;
+#undef _BSD_CLOCK_T_
+#endif
+
+#ifdef _BSD_TIME_T_
+typedef _BSD_TIME_T_ time_t;
+#undef _BSD_TIME_T_
+#endif
+
+#ifdef _BSD_SIZE_T_
+typedef _BSD_SIZE_T_ size_t;
+#undef _BSD_SIZE_T_
+#endif
+
+#define CLOCKS_PER_SEC 100
+
+#if !defined(_ANSI_SOURCE)
+#define CLK_TCK 100
+#endif /* not ANSI */
+
+#endif /* !_SYS__TIME_H_ */
diff --git a/mit-pthreads/machdep/netbsd-1.0/__unistd.h b/mit-pthreads/machdep/netbsd-1.0/__unistd.h
new file mode 100755
index 00000000000..b4741ba6725
--- /dev/null
+++ b/mit-pthreads/machdep/netbsd-1.0/__unistd.h
@@ -0,0 +1,107 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)stdlib.h 5.13 (Berkeley) 6/4/91
+ * $Id$
+ */
+
+#ifndef _SYS___UNISTD_H_
+#define _SYS___UNISTD_H_
+
+#include <sys/types.h>
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+/* compile-time symbolic constants */
+#define _POSIX_JOB_CONTROL /* implementation supports job control */
+
+#ifdef _NOT_AVAILABLE
+#define _POSIX_SAVED_IDS /* saved set-user-ID and set-group-ID */
+#endif
+
+#define _POSIX_VERSION 198808L
+#define _POSIX2_VERSION 199212L
+
+/* execution-time symbolic constants */
+ /* chown requires appropriate privileges */
+#define _POSIX_CHOWN_RESTRICTED 1
+ /* too-long path components generate errors */
+#define _POSIX_NO_TRUNC 1
+ /* may disable terminal special characters */
+#define _POSIX_VDISABLE ((unsigned char)'\377')
+
+/* configurable pathname variables */
+#define _PC_LINK_MAX 1
+#define _PC_MAX_CANON 2
+#define _PC_MAX_INPUT 3
+#define _PC_NAME_MAX 4
+#define _PC_PATH_MAX 5
+#define _PC_PIPE_BUF 6
+#define _PC_CHOWN_RESTRICTED 7
+#define _PC_NO_TRUNC 8
+#define _PC_VDISABLE 9
+
+/* configurable system variables */
+#define _SC_ARG_MAX 1
+#define _SC_CHILD_MAX 2
+#define _SC_CLK_TCK 3
+#define _SC_NGROUPS_MAX 4
+#define _SC_OPEN_MAX 5
+#define _SC_JOB_CONTROL 6
+#define _SC_SAVED_IDS 7
+#define _SC_VERSION 8
+#define _SC_BC_BASE_MAX 9
+#define _SC_BC_DIM_MAX 10
+#define _SC_BC_SCALE_MAX 11
+#define _SC_BC_STRING_MAX 12
+#define _SC_COLL_WEIGHTS_MAX 13
+#define _SC_EXPR_NEST_MAX 14
+#define _SC_LINE_MAX 15
+#define _SC_RE_DUP_MAX 16
+#define _SC_2_VERSION 17
+#define _SC_2_C_BIND 18
+#define _SC_2_C_DEV 19
+#define _SC_2_CHAR_TERM 20
+#define _SC_2_FORT_DEV 21
+#define _SC_2_FORT_RUN 22
+#define _SC_2_LOCALEDEF 23
+#define _SC_2_SW_DEV 24
+#define _SC_2_UPE 25
+#define _SC_STREAM_MAX 26
+#define _SC_TZNAME_MAX 27
+
+/* configurable system strings */
+#define _CS_PATH 1
+
+#endif
diff --git a/mit-pthreads/machdep/netbsd-1.0/compat.h b/mit-pthreads/machdep/netbsd-1.0/compat.h
new file mode 100755
index 00000000000..e7de318aa88
--- /dev/null
+++ b/mit-pthreads/machdep/netbsd-1.0/compat.h
@@ -0,0 +1,43 @@
+/* ==== compat.h ============================================================
+ * Copyright (c) 1994 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ *
+ * Description : COmpat header to make socket code compile.
+ *
+ * 1.00 94/08/01 proven
+ * -Started coding this file.
+ */
+
+#ifndef _SYS_COMPAT_H_
+#define _SYS_COMPAT_H_
+
+#endif
diff --git a/mit-pthreads/machdep/netbsd-1.0/dirent.h b/mit-pthreads/machdep/netbsd-1.0/dirent.h
new file mode 100755
index 00000000000..5226443f86b
--- /dev/null
+++ b/mit-pthreads/machdep/netbsd-1.0/dirent.h
@@ -0,0 +1,64 @@
+/*-
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)dirent.h 5.18 (Berkeley) 2/23/91
+ */
+
+#ifndef _SYS_DIRENT_H_
+#define _SYS_DIRENT_H_
+
+/*
+ * A directory entry has a struct dirent at the front of it, containing its
+ * inode number, the length of the entry, and the length of the name
+ * contained in the entry. These are followed by the name padded to a 4
+ * byte boundary with null bytes. All names are guaranteed null terminated.
+ * The maximum length of a name in a directory is MAXNAMLEN.
+ */
+
+struct dirent {
+ u_long d_fileno; /* file number of entry */
+ u_short d_reclen; /* length of this record */
+ u_short d_namlen; /* length of string in d_name */
+#ifdef _POSIX_SOURCE
+ char d_name[255 + 1]; /* name must be no longer than this */
+#else
+#define MAXNAMLEN 255
+ char d_name[MAXNAMLEN + 1]; /* name must be no longer than this */
+#endif
+};
+
+#define d_ino d_fileno /* backward compatibility */
+
+/* definitions for library routines operating on directories. */
+#define DIRBLKSIZ 1024
+
+#endif /* !_DIRENT_H_ */
diff --git a/mit-pthreads/machdep/netbsd-1.0/errno.h b/mit-pthreads/machdep/netbsd-1.0/errno.h
new file mode 100755
index 00000000000..3da61d692a3
--- /dev/null
+++ b/mit-pthreads/machdep/netbsd-1.0/errno.h
@@ -0,0 +1,160 @@
+/* $NetBSD: errno.h,v 1.8 1994/06/29 06:44:02 cgd Exp $ */
+
+/*
+ * Copyright (c) 1982, 1986, 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ * (c) UNIX System Laboratories, Inc.
+ * All or some portions of this file are derived from material licensed
+ * to the University of California by American Telephone and Telegraph
+ * Co. or Unix System Laboratories, Inc. and are reproduced herein with
+ * the permission of UNIX System Laboratories, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)errno.h 8.5 (Berkeley) 1/21/94
+ */
+
+#ifndef _SYS_ERRNO_H_
+#define _SYS_ERRNO_H_
+
+#define EPERM 1 /* Operation not permitted */
+#define ENOENT 2 /* No such file or directory */
+#define ESRCH 3 /* No such process */
+#define EINTR 4 /* Interrupted system call */
+#define EIO 5 /* Input/output error */
+#define ENXIO 6 /* Device not configured */
+#define E2BIG 7 /* Argument list too long */
+#define ENOEXEC 8 /* Exec format error */
+#define EBADF 9 /* Bad file descriptor */
+#define ECHILD 10 /* No child processes */
+#define EDEADLK 11 /* Resource deadlock avoided */
+ /* 11 was EAGAIN */
+#define ENOMEM 12 /* Cannot allocate memory */
+#define EACCES 13 /* Permission denied */
+#define EFAULT 14 /* Bad address */
+#ifndef _POSIX_SOURCE
+#define ENOTBLK 15 /* Block device required */
+#endif
+#define EBUSY 16 /* Device busy */
+#define EEXIST 17 /* File exists */
+#define EXDEV 18 /* Cross-device link */
+#define ENODEV 19 /* Operation not supported by device */
+#define ENOTDIR 20 /* Not a directory */
+#define EISDIR 21 /* Is a directory */
+#define EINVAL 22 /* Invalid argument */
+#define ENFILE 23 /* Too many open files in system */
+#define EMFILE 24 /* Too many open files */
+#define ENOTTY 25 /* Inappropriate ioctl for device */
+#ifndef _POSIX_SOURCE
+#define ETXTBSY 26 /* Text file busy */
+#endif
+#define EFBIG 27 /* File too large */
+#define ENOSPC 28 /* No space left on device */
+#define ESPIPE 29 /* Illegal seek */
+#define EROFS 30 /* Read-only file system */
+#define EMLINK 31 /* Too many links */
+#define EPIPE 32 /* Broken pipe */
+
+/* math software */
+#define EDOM 33 /* Numerical argument out of domain */
+#define ERANGE 34 /* Result too large */
+
+/* non-blocking and interrupt i/o */
+#define EAGAIN 35 /* Resource temporarily unavailable */
+#ifndef _POSIX_SOURCE
+#define EWOULDBLOCK EAGAIN /* Operation would block */
+#define EINPROGRESS 36 /* Operation now in progress */
+#define EALREADY 37 /* Operation already in progress */
+
+/* ipc/network software -- argument errors */
+#define ENOTSOCK 38 /* Socket operation on non-socket */
+#define EDESTADDRREQ 39 /* Destination address required */
+#define EMSGSIZE 40 /* Message too long */
+#define EPROTOTYPE 41 /* Protocol wrong type for socket */
+#define ENOPROTOOPT 42 /* Protocol not available */
+#define EPROTONOSUPPORT 43 /* Protocol not supported */
+#define ESOCKTNOSUPPORT 44 /* Socket type not supported */
+#define EOPNOTSUPP 45 /* Operation not supported */
+#define EPFNOSUPPORT 46 /* Protocol family not supported */
+#define EAFNOSUPPORT 47 /* Address family not supported by protocol family */
+#define EADDRINUSE 48 /* Address already in use */
+#define EADDRNOTAVAIL 49 /* Can't assign requested address */
+
+/* ipc/network software -- operational errors */
+#define ENETDOWN 50 /* Network is down */
+#define ENETUNREACH 51 /* Network is unreachable */
+#define ENETRESET 52 /* Network dropped connection on reset */
+#define ECONNABORTED 53 /* Software caused connection abort */
+#define ECONNRESET 54 /* Connection reset by peer */
+#define ENOBUFS 55 /* No buffer space available */
+#define EISCONN 56 /* Socket is already connected */
+#define ENOTCONN 57 /* Socket is not connected */
+#define ESHUTDOWN 58 /* Can't send after socket shutdown */
+#define ETOOMANYREFS 59 /* Too many references: can't splice */
+#define ETIMEDOUT 60 /* Operation timed out */
+#define ECONNREFUSED 61 /* Connection refused */
+
+#define ELOOP 62 /* Too many levels of symbolic links */
+#endif /* _POSIX_SOURCE */
+#define ENAMETOOLONG 63 /* File name too long */
+
+/* should be rearranged */
+#ifndef _POSIX_SOURCE
+#define EHOSTDOWN 64 /* Host is down */
+#define EHOSTUNREACH 65 /* No route to host */
+#endif /* _POSIX_SOURCE */
+#define ENOTEMPTY 66 /* Directory not empty */
+
+/* quotas & mush */
+#ifndef _POSIX_SOURCE
+#define EPROCLIM 67 /* Too many processes */
+#define EUSERS 68 /* Too many users */
+#define EDQUOT 69 /* Disc quota exceeded */
+
+/* Network File System */
+#define ESTALE 70 /* Stale NFS file handle */
+#define EREMOTE 71 /* Too many levels of remote in path */
+#define EBADRPC 72 /* RPC struct is bad */
+#define ERPCMISMATCH 73 /* RPC version wrong */
+#define EPROGUNAVAIL 74 /* RPC prog. not avail */
+#define EPROGMISMATCH 75 /* Program version wrong */
+#define EPROCUNAVAIL 76 /* Bad procedure for program */
+#endif /* _POSIX_SOURCE */
+
+#define ENOLCK 77 /* No locks available */
+#define ENOSYS 78 /* Function not implemented */
+
+#ifndef _POSIX_SOURCE
+#define EFTYPE 79 /* Inappropriate file type or format */
+#define EAUTH 80 /* Authentication error */
+#define ENEEDAUTH 81 /* Need authenticator */
+#define ELAST 81 /* Must be equal largest errno */
+#endif /* _POSIX_SOURCE */
+
+#endif
diff --git a/mit-pthreads/machdep/netbsd-1.0/time.h b/mit-pthreads/machdep/netbsd-1.0/time.h
new file mode 100755
index 00000000000..f2cc61f8d75
--- /dev/null
+++ b/mit-pthreads/machdep/netbsd-1.0/time.h
@@ -0,0 +1,125 @@
+/* $NetBSD: time.h,v 1.8 1994/06/29 06:45:44 cgd Exp $ */
+
+/*
+ * Copyright (c) 1982, 1986, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)time.h 8.1 (Berkeley) 6/2/93
+ */
+
+#ifndef _SYS_TIME_H_
+#define _SYS_TIME_H_
+
+/*
+ * Structure returned by gettimeofday(2) system call,
+ * and used in other calls.
+ */
+struct timeval {
+ long tv_sec; /* seconds */
+ long tv_usec; /* and microseconds */
+};
+
+/*
+ * Structure defined by POSIX.4 to be like a timeval.
+ */
+struct timespec {
+ long tv_sec; /* seconds */
+ long tv_nsec; /* and nanoseconds */
+};
+
+#define TIMEVAL_TO_TIMESPEC(tv, ts) { \
+ (ts)->tv_sec = (tv)->tv_sec; \
+ (ts)->tv_nsec = (tv)->tv_usec * 1000; \
+}
+#define TIMESPEC_TO_TIMEVAL(tv, ts) { \
+ (tv)->tv_sec = (ts)->tv_sec; \
+ (tv)->tv_usec = (ts)->tv_nsec / 1000; \
+}
+
+struct timezone {
+ int tz_minuteswest; /* minutes west of Greenwich */
+ int tz_dsttime; /* type of dst correction */
+};
+#define DST_NONE 0 /* not on dst */
+#define DST_USA 1 /* USA style dst */
+#define DST_AUST 2 /* Australian style dst */
+#define DST_WET 3 /* Western European dst */
+#define DST_MET 4 /* Middle European dst */
+#define DST_EET 5 /* Eastern European dst */
+#define DST_CAN 6 /* Canada */
+
+/* Operations on timevals. */
+#define timerclear(tvp) (tvp)->tv_sec = (tvp)->tv_usec = 0
+#define timerisset(tvp) ((tvp)->tv_sec || (tvp)->tv_usec)
+#define timercmp(tvp, uvp, cmp) \
+ (((tvp)->tv_sec == (uvp)->tv_sec) ? \
+ ((tvp)->tv_usec cmp (uvp)->tv_usec) : \
+ ((tvp)->tv_sec cmp (uvp)->tv_sec))
+
+/*
+ * Names of the interval timers, and structure
+ * defining a timer setting.
+ */
+#define ITIMER_REAL 0
+#define ITIMER_VIRTUAL 1
+#define ITIMER_PROF 2
+
+struct itimerval {
+ struct timeval it_interval; /* timer interval */
+ struct timeval it_value; /* current value */
+};
+
+/*
+ * Getkerninfo clock information structure
+ */
+struct clockinfo {
+ int hz; /* clock frequency */
+ int tick; /* micro-seconds per hz tick */
+ int stathz; /* statistics clock frequency */
+ int profhz; /* profiling clock frequency */
+};
+
+#include <time.h>
+
+#ifndef _POSIX_SOURCE
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+int adjtime __P_((const struct timeval *, struct timeval *));
+int getitimer __P_((int, struct itimerval *));
+int gettimeofday __P_((struct timeval *, struct timezone *));
+int setitimer __P_((int, const struct itimerval *, struct itimerval *));
+int settimeofday __P_((const struct timeval *, const struct timezone *));
+int utimes __P_((const char *, const struct timeval *));
+__END_DECLS
+#endif /* !POSIX */
+
+#endif /* !_SYS_TIME_H_ */
diff --git a/mit-pthreads/machdep/netbsd-1.0/timers.h b/mit-pthreads/machdep/netbsd-1.0/timers.h
new file mode 100755
index 00000000000..f9768c68c8f
--- /dev/null
+++ b/mit-pthreads/machdep/netbsd-1.0/timers.h
@@ -0,0 +1,45 @@
+/* ==== timers.h ============================================================
+ * Copyright (c) 1994 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ *
+ * Description : Basic timers header.
+ *
+ * 1.00 94/06/13 proven
+ * -Started coding this file.
+ */
+
+#ifndef _SYS_TIMERS_H_
+#define _SYS_TIMERS_H_
+
+#include <sys/time.h>
+
+#endif
diff --git a/mit-pthreads/machdep/netbsd-1.0/wait.h b/mit-pthreads/machdep/netbsd-1.0/wait.h
new file mode 100755
index 00000000000..c1cd876d052
--- /dev/null
+++ b/mit-pthreads/machdep/netbsd-1.0/wait.h
@@ -0,0 +1,158 @@
+/* $NetBSD: wait.h,v 1.7 1994/06/29 06:46:23 cgd Exp $ */
+
+/*
+ * Copyright (c) 1982, 1986, 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)wait.h 8.1 (Berkeley) 6/2/93
+ */
+
+/*
+ * This file holds definitions relevent to the wait4 system call
+ * and the alternate interfaces that use it (wait, wait3, waitpid).
+ */
+
+/*
+ * Macros to test the exit status returned by wait
+ * and extract the relevant values.
+ */
+#ifdef _POSIX_SOURCE
+#define _W_INT(i) (i)
+#else
+#define _W_INT(w) (*(int *)&(w)) /* convert union wait to int */
+#define WCOREFLAG 0200
+#endif
+
+#define _WSTATUS(x) (_W_INT(x) & 0177)
+#define _WSTOPPED 0177 /* _WSTATUS if process is stopped */
+#define WIFSTOPPED(x) (_WSTATUS(x) == _WSTOPPED)
+#define WSTOPSIG(x) (_W_INT(x) >> 8)
+#define WIFSIGNALED(x) (_WSTATUS(x) != _WSTOPPED && _WSTATUS(x) != 0)
+#define WTERMSIG(x) (_WSTATUS(x))
+#define WIFEXITED(x) (_WSTATUS(x) == 0)
+#define WEXITSTATUS(x) (_W_INT(x) >> 8)
+#ifndef _POSIX_SOURCE
+#define WCOREDUMP(x) (_W_INT(x) & WCOREFLAG)
+
+#define W_EXITCODE(ret, sig) ((ret) << 8 | (sig))
+#define W_STOPCODE(sig) ((sig) << 8 | _WSTOPPED)
+#endif
+
+/*
+ * Option bits for the third argument of wait4. WNOHANG causes the
+ * wait to not hang if there are no stopped or terminated processes, rather
+ * returning an error indication in this case (pid==0). WUNTRACED
+ * indicates that the caller should receive status about untraced children
+ * which stop due to signals. If children are stopped and a wait without
+ * this option is done, it is as though they were still running... nothing
+ * about them is returned.
+ */
+#define WNOHANG 1 /* dont hang in wait */
+#define WUNTRACED 2 /* tell about stopped, untraced children */
+
+#ifndef _POSIX_SOURCE
+/* POSIX extensions and 4.2/4.3 compatability: */
+
+/*
+ * Tokens for special values of the "pid" parameter to wait4.
+ */
+#define WAIT_ANY (-1) /* any process */
+#define WAIT_MYPGRP 0 /* any process in my process group */
+
+#include <machine/endian.h>
+
+/*
+ * Deprecated:
+ * Structure of the information in the status word returned by wait4.
+ * If w_stopval==WSTOPPED, then the second structure describes
+ * the information returned, else the first.
+ */
+union wait {
+ int w_status; /* used in syscall */
+ /*
+ * Terminated process status.
+ */
+ struct {
+#if BYTE_ORDER == LITTLE_ENDIAN
+ unsigned int w_Termsig:7, /* termination signal */
+ w_Coredump:1, /* core dump indicator */
+ w_Retcode:8, /* exit code if w_termsig==0 */
+ w_Filler:16; /* upper bits filler */
+#endif
+#if BYTE_ORDER == BIG_ENDIAN
+ unsigned int w_Filler:16, /* upper bits filler */
+ w_Retcode:8, /* exit code if w_termsig==0 */
+ w_Coredump:1, /* core dump indicator */
+ w_Termsig:7; /* termination signal */
+#endif
+ } w_T;
+ /*
+ * Stopped process status. Returned
+ * only for traced children unless requested
+ * with the WUNTRACED option bit.
+ */
+ struct {
+#if BYTE_ORDER == LITTLE_ENDIAN
+ unsigned int w_Stopval:8, /* == W_STOPPED if stopped */
+ w_Stopsig:8, /* signal that stopped us */
+ w_Filler:16; /* upper bits filler */
+#endif
+#if BYTE_ORDER == BIG_ENDIAN
+ unsigned int w_Filler:16, /* upper bits filler */
+ w_Stopsig:8, /* signal that stopped us */
+ w_Stopval:8; /* == W_STOPPED if stopped */
+#endif
+ } w_S;
+};
+#define w_termsig w_T.w_Termsig
+#define w_coredump w_T.w_Coredump
+#define w_retcode w_T.w_Retcode
+#define w_stopval w_S.w_Stopval
+#define w_stopsig w_S.w_Stopsig
+
+#define WSTOPPED _WSTOPPED
+#endif /* _POSIX_SOURCE */
+
+#ifndef KERNEL
+#include <sys/types.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+struct rusage; /* forward declaration */
+
+pid_t wait __P_((int *));
+pid_t waitpid __P_((pid_t, int *, int));
+#ifndef _POSIX_SOURCE
+pid_t wait3 __P_((int *, int, void *));
+pid_t wait4 __P_((pid_t, int *, int, void *));
+#endif
+__END_DECLS
+#endif
diff --git a/mit-pthreads/machdep/netbsd-1.1/__math.h b/mit-pthreads/machdep/netbsd-1.1/__math.h
new file mode 100755
index 00000000000..dc009d822f4
--- /dev/null
+++ b/mit-pthreads/machdep/netbsd-1.1/__math.h
@@ -0,0 +1,6 @@
+/*
+ * ANSI/POSIX
+ */
+extern char __infinity[];
+#define HUGE_VAL (*(double *) __infinity)
+
diff --git a/mit-pthreads/machdep/netbsd-1.1/__path.h b/mit-pthreads/machdep/netbsd-1.1/__path.h
new file mode 100755
index 00000000000..be7f9f6c658
--- /dev/null
+++ b/mit-pthreads/machdep/netbsd-1.1/__path.h
@@ -0,0 +1,14 @@
+/*
+ * from: @(#)time.h 5.12 (Berkeley) 3/9/91
+ * __path.h,v 1.1 1995/01/03 12:53:32 proven Exp
+ */
+
+#ifndef _SYS__PATH_H_
+#define _SYS__PATH_H_
+
+#define _PATH_PTY "/dev/"
+#define _PATH_TZDIR "/usr/share/zoneinfo"
+#define _PATH_TZFILE "/etc/localtime"
+
+#endif /* !_SYS__PATH_H_ */
+
diff --git a/mit-pthreads/machdep/netbsd-1.1/__signal.h b/mit-pthreads/machdep/netbsd-1.1/__signal.h
new file mode 100755
index 00000000000..e41e9218261
--- /dev/null
+++ b/mit-pthreads/machdep/netbsd-1.1/__signal.h
@@ -0,0 +1,20 @@
+#include <sys/signal.h>
+
+#if NSIG <= 32
+#define __SIGEMPTYSET 0
+#define __SIGFILLSET 0xffffffff
+#define __SIGADDSET(s, n) (*(s) |= 1 << ((n) - 1), 0)
+#define __SIGDELSET(s, n) (*(s) &= ~(1 << ((n) - 1)), 0)
+#define __SIGISMEMBER(s, n) ((*(s) & (1 << ((n) - 1))) != 0)
+
+#else /* XXX Netbsd >= 1.3H */
+#define __SIGEMPTYSET { 0, 0, 0, 0}
+#define __SIGFILLSET { 0xffffffff, 0xffffffff, \
+ 0xffffffff, 0xffffffff }
+#define __SIGMASK(n) (1 << (((n) - 1) & 31))
+#define __SIGWORD(n) (((n) - 1) >> 5)
+#define __SIGADDSET(s, n) ((s)->__bits[__SIGWORD(n)] |= __SIGMASK(n))
+#define __SIGDELSET(s, n) ((s)->__bits[__SIGWORD(n)] &= ~__SIGMASK(n))
+#define __SIGISMEMBER(s, n) (((s)->__bits[__SIGWORD(n)] & __SIGMASK(n)) != 0)
+
+#endif
diff --git a/mit-pthreads/machdep/netbsd-1.1/__stdio.h b/mit-pthreads/machdep/netbsd-1.1/__stdio.h
new file mode 100755
index 00000000000..d60b9df7a54
--- /dev/null
+++ b/mit-pthreads/machdep/netbsd-1.1/__stdio.h
@@ -0,0 +1,8 @@
+
+#include <machine/ansi.h>
+#ifdef _BSD_SIZE_T_
+typedef _BSD_SIZE_T_ size_t;
+#undef _BSD_SIZE_T_
+#endif
+
+typedef pthread_fpos_t fpos_t; /* Must match off_t <sys/types.h> */
diff --git a/mit-pthreads/machdep/netbsd-1.1/__stdlib.h b/mit-pthreads/machdep/netbsd-1.1/__stdlib.h
new file mode 100755
index 00000000000..189bb5e8799
--- /dev/null
+++ b/mit-pthreads/machdep/netbsd-1.1/__stdlib.h
@@ -0,0 +1,60 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)stdlib.h 5.13 (Berkeley) 6/4/91
+ * __stdlib.h,v 1.1 1995/01/03 12:53:34 proven Exp
+ */
+
+#ifndef _SYS___STDLIB_H_
+#define _SYS___STDLIB_H_
+
+#include <machine/ansi.h>
+
+#ifdef _BSD_SIZE_T_
+typedef _BSD_SIZE_T_ size_t;
+#undef _BSD_SIZE_T_
+#endif
+
+#ifdef _BSD_WCHAR_T_
+typedef _BSD_WCHAR_T_ wchar_t;
+#undef _BSD_WCHAR_T_
+#endif
+
+#ifndef __NORETURN
+#define __NORETURN
+#endif
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#endif /* _STDLIB_H_ */
diff --git a/mit-pthreads/machdep/netbsd-1.1/__string.h b/mit-pthreads/machdep/netbsd-1.1/__string.h
new file mode 100755
index 00000000000..1ebee28e708
--- /dev/null
+++ b/mit-pthreads/machdep/netbsd-1.1/__string.h
@@ -0,0 +1,20 @@
+
+#include <machine/ansi.h>
+#ifdef _BSD_SIZE_T_
+typedef _BSD_SIZE_T_ size_t;
+#undef _BSD_SIZE_T_
+#endif
+
+/* Non-standard NetBSD string routines. */
+#if !defined(_ANSI_SOURCE) && !defined(_POSIX_SOURCE)
+__BEGIN_DECLS
+int bcmp __P_((const void *, const void *, size_t));
+void bcopy __P_((const void *, void *, size_t));
+void bzero __P_((void *, size_t));
+char *index __P_((const char *, int));
+char *rindex __P_((const char *, int));
+char *strdup __P_((const char *));
+void strmode __P_((int, char *));
+char *strsep __P_((char **, const char *));
+__END_DECLS
+#endif
diff --git a/mit-pthreads/machdep/netbsd-1.1/__time.h b/mit-pthreads/machdep/netbsd-1.1/__time.h
new file mode 100755
index 00000000000..27ceb815852
--- /dev/null
+++ b/mit-pthreads/machdep/netbsd-1.1/__time.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * (c) UNIX System Laboratories, Inc.
+ * All or some portions of this file are derived from material licensed
+ * to the University of California by American Telephone and Telegraph
+ * Co. or Unix System Laboratories, Inc. and are reproduced herein with
+ * the permission of UNIX System Laboratories, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)time.h 5.12 (Berkeley) 3/9/91
+ * __time.h,v 1.1 1994/12/13 07:18:55 proven Exp
+ */
+
+#ifndef _SYS__TIME_H_
+#define _SYS__TIME_H_
+
+#include <machine/ansi.h>
+
+#ifdef _BSD_CLOCK_T_
+typedef _BSD_CLOCK_T_ clock_t;
+#undef _BSD_CLOCK_T_
+#endif
+
+#ifdef _BSD_TIME_T_
+typedef _BSD_TIME_T_ time_t;
+#undef _BSD_TIME_T_
+#endif
+
+#ifdef _BSD_SIZE_T_
+typedef _BSD_SIZE_T_ size_t;
+#undef _BSD_SIZE_T_
+#endif
+
+#define CLOCKS_PER_SEC 100
+
+#if !defined(_ANSI_SOURCE)
+#define CLK_TCK 100
+#endif /* not ANSI */
+
+#endif /* !_SYS__TIME_H_ */
diff --git a/mit-pthreads/machdep/netbsd-1.1/__unistd.h b/mit-pthreads/machdep/netbsd-1.1/__unistd.h
new file mode 100755
index 00000000000..cea3165c229
--- /dev/null
+++ b/mit-pthreads/machdep/netbsd-1.1/__unistd.h
@@ -0,0 +1,107 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)stdlib.h 5.13 (Berkeley) 6/4/91
+ * __unistd.h,v 1.1 1995/01/03 12:53:35 proven Exp
+ */
+
+#ifndef _SYS___UNISTD_H_
+#define _SYS___UNISTD_H_
+
+#include <sys/types.h>
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+/* compile-time symbolic constants */
+#define _POSIX_JOB_CONTROL /* implementation supports job control */
+
+#ifdef _NOT_AVAILABLE
+#define _POSIX_SAVED_IDS /* saved set-user-ID and set-group-ID */
+#endif
+
+#define _POSIX_VERSION 198808L
+#define _POSIX2_VERSION 199212L
+
+/* execution-time symbolic constants */
+ /* chown requires appropriate privileges */
+#define _POSIX_CHOWN_RESTRICTED 1
+ /* too-long path components generate errors */
+#define _POSIX_NO_TRUNC 1
+ /* may disable terminal special characters */
+#define _POSIX_VDISABLE ((unsigned char)'\377')
+
+/* configurable pathname variables */
+#define _PC_LINK_MAX 1
+#define _PC_MAX_CANON 2
+#define _PC_MAX_INPUT 3
+#define _PC_NAME_MAX 4
+#define _PC_PATH_MAX 5
+#define _PC_PIPE_BUF 6
+#define _PC_CHOWN_RESTRICTED 7
+#define _PC_NO_TRUNC 8
+#define _PC_VDISABLE 9
+
+/* configurable system variables */
+#define _SC_ARG_MAX 1
+#define _SC_CHILD_MAX 2
+#define _SC_CLK_TCK 3
+#define _SC_NGROUPS_MAX 4
+#define _SC_OPEN_MAX 5
+#define _SC_JOB_CONTROL 6
+#define _SC_SAVED_IDS 7
+#define _SC_VERSION 8
+#define _SC_BC_BASE_MAX 9
+#define _SC_BC_DIM_MAX 10
+#define _SC_BC_SCALE_MAX 11
+#define _SC_BC_STRING_MAX 12
+#define _SC_COLL_WEIGHTS_MAX 13
+#define _SC_EXPR_NEST_MAX 14
+#define _SC_LINE_MAX 15
+#define _SC_RE_DUP_MAX 16
+#define _SC_2_VERSION 17
+#define _SC_2_C_BIND 18
+#define _SC_2_C_DEV 19
+#define _SC_2_CHAR_TERM 20
+#define _SC_2_FORT_DEV 21
+#define _SC_2_FORT_RUN 22
+#define _SC_2_LOCALEDEF 23
+#define _SC_2_SW_DEV 24
+#define _SC_2_UPE 25
+#define _SC_STREAM_MAX 26
+#define _SC_TZNAME_MAX 27
+
+/* configurable system strings */
+#define _CS_PATH 1
+
+#endif
diff --git a/mit-pthreads/machdep/netbsd-1.1/compat.h b/mit-pthreads/machdep/netbsd-1.1/compat.h
new file mode 100755
index 00000000000..f843795cc0a
--- /dev/null
+++ b/mit-pthreads/machdep/netbsd-1.1/compat.h
@@ -0,0 +1,43 @@
+/* ==== compat.h ============================================================
+ * Copyright (c) 1994 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * compat.h,v 1.50 1994/08/08 03:44:05 proven Exp
+ *
+ * Description : COmpat header to make socket code compile.
+ *
+ * 1.00 94/08/01 proven
+ * -Started coding this file.
+ */
+
+#ifndef _SYS_COMPAT_H_
+#define _SYS_COMPAT_H_
+
+#endif
diff --git a/mit-pthreads/machdep/netbsd-1.1/dirent.h b/mit-pthreads/machdep/netbsd-1.1/dirent.h
new file mode 100755
index 00000000000..cf004a274d6
--- /dev/null
+++ b/mit-pthreads/machdep/netbsd-1.1/dirent.h
@@ -0,0 +1,95 @@
+/* $NetBSD: dirent.h,v 1.12 1996/04/09 20:55:25 cgd Exp $ */
+
+/*-
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)dirent.h 8.3 (Berkeley) 8/10/94
+ */
+
+/*
+ * The dirent structure defines the format of directory entries returned by
+ * the getdirentries(2) system call.
+ *
+ * A directory entry has a struct dirent at the front of it, containing its
+ * inode number, the length of the entry, and the length of the name
+ * contained in the entry. These are followed by the name padded to a 4
+ * byte boundary with null bytes. All names are guaranteed null terminated.
+ * The maximum length of a name in a directory is MAXNAMLEN.
+ */
+
+struct dirent {
+ u_int32_t d_fileno; /* file number of entry */
+ u_int16_t d_reclen; /* length of this record */
+ u_int8_t d_type; /* file type, see below */
+ u_int8_t d_namlen; /* length of string in d_name */
+#ifdef _POSIX_SOURCE
+ char d_name[255 + 1]; /* name must be no longer than this */
+#else
+#define MAXNAMLEN 255
+ char d_name[MAXNAMLEN + 1]; /* name must be no longer than this */
+#endif
+};
+
+#ifdef PTHREAD_KERNEL
+#define d_ino d_fileno
+#endif
+
+/*
+ * File types
+ */
+#define DT_UNKNOWN 0
+#define DT_FIFO 1
+#define DT_CHR 2
+#define DT_DIR 4
+#define DT_BLK 6
+#define DT_REG 8
+#define DT_LNK 10
+#define DT_SOCK 12
+#define DT_WHT 14
+
+/*
+ * Convert between stat structure types and directory types.
+ */
+#define IFTODT(mode) (((mode) & 0170000) >> 12)
+#define DTTOIF(dirtype) ((dirtype) << 12)
+
+#if defined(_KERNEL)
+/*
+ * The DIRENT_SIZE macro gives the minimum record length which will hold
+ * the directory entry. This requires the amount of space in struct dirent
+ * without the d_name field, plus enough space for the name with a terminating
+ * null byte (dp->d_namlen+1), rounded up to a 4 byte boundary.
+ */
+#define DIRENT_SIZE(dp) \
+ ((sizeof (struct dirent) - (MAXNAMLEN+1)) + (((dp)->d_namlen+1 + 3) &~ 3))
+
+#endif /* !_KERNEL */
diff --git a/mit-pthreads/machdep/netbsd-1.1/errno.h b/mit-pthreads/machdep/netbsd-1.1/errno.h
new file mode 100755
index 00000000000..c313b578c5a
--- /dev/null
+++ b/mit-pthreads/machdep/netbsd-1.1/errno.h
@@ -0,0 +1,170 @@
+/* $NetBSD: errno.h,v 1.10 1996/01/20 01:33:53 jtc Exp $ */
+
+/*
+ * Copyright (c) 1982, 1986, 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ * (c) UNIX System Laboratories, Inc.
+ * All or some portions of this file are derived from material licensed
+ * to the University of California by American Telephone and Telegraph
+ * Co. or Unix System Laboratories, Inc. and are reproduced herein with
+ * the permission of UNIX System Laboratories, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)errno.h 8.5 (Berkeley) 1/21/94
+ */
+
+#ifndef _KERNEL
+extern int errno; /* global error number */
+
+#if !defined(_ANSI_SOURCE) && !defined(_POSIX_SOURCE)
+extern int sys_nerr;
+extern const char *const sys_errlist[];
+#endif
+#endif
+
+#define EPERM 1 /* Operation not permitted */
+#define ENOENT 2 /* No such file or directory */
+#define ESRCH 3 /* No such process */
+#define EINTR 4 /* Interrupted system call */
+#define EIO 5 /* Input/output error */
+#define ENXIO 6 /* Device not configured */
+#define E2BIG 7 /* Argument list too long */
+#define ENOEXEC 8 /* Exec format error */
+#define EBADF 9 /* Bad file descriptor */
+#define ECHILD 10 /* No child processes */
+#define EDEADLK 11 /* Resource deadlock avoided */
+ /* 11 was EAGAIN */
+#define ENOMEM 12 /* Cannot allocate memory */
+#define EACCES 13 /* Permission denied */
+#define EFAULT 14 /* Bad address */
+#ifndef _POSIX_SOURCE
+#define ENOTBLK 15 /* Block device required */
+#endif
+#define EBUSY 16 /* Device busy */
+#define EEXIST 17 /* File exists */
+#define EXDEV 18 /* Cross-device link */
+#define ENODEV 19 /* Operation not supported by device */
+#define ENOTDIR 20 /* Not a directory */
+#define EISDIR 21 /* Is a directory */
+#define EINVAL 22 /* Invalid argument */
+#define ENFILE 23 /* Too many open files in system */
+#define EMFILE 24 /* Too many open files */
+#define ENOTTY 25 /* Inappropriate ioctl for device */
+#ifndef _POSIX_SOURCE
+#define ETXTBSY 26 /* Text file busy */
+#endif
+#define EFBIG 27 /* File too large */
+#define ENOSPC 28 /* No space left on device */
+#define ESPIPE 29 /* Illegal seek */
+#define EROFS 30 /* Read-only file system */
+#define EMLINK 31 /* Too many links */
+#define EPIPE 32 /* Broken pipe */
+
+/* math software */
+#define EDOM 33 /* Numerical argument out of domain */
+#define ERANGE 34 /* Result too large */
+
+/* non-blocking and interrupt i/o */
+#define EAGAIN 35 /* Resource temporarily unavailable */
+#ifndef _POSIX_SOURCE
+#define EWOULDBLOCK EAGAIN /* Operation would block */
+#define EINPROGRESS 36 /* Operation now in progress */
+#define EALREADY 37 /* Operation already in progress */
+
+/* ipc/network software -- argument errors */
+#define ENOTSOCK 38 /* Socket operation on non-socket */
+#define EDESTADDRREQ 39 /* Destination address required */
+#define EMSGSIZE 40 /* Message too long */
+#define EPROTOTYPE 41 /* Protocol wrong type for socket */
+#define ENOPROTOOPT 42 /* Protocol not available */
+#define EPROTONOSUPPORT 43 /* Protocol not supported */
+#define ESOCKTNOSUPPORT 44 /* Socket type not supported */
+#define EOPNOTSUPP 45 /* Operation not supported */
+#define EPFNOSUPPORT 46 /* Protocol family not supported */
+#define EAFNOSUPPORT 47 /* Address family not supported by protocol family */
+#define EADDRINUSE 48 /* Address already in use */
+#define EADDRNOTAVAIL 49 /* Can't assign requested address */
+
+/* ipc/network software -- operational errors */
+#define ENETDOWN 50 /* Network is down */
+#define ENETUNREACH 51 /* Network is unreachable */
+#define ENETRESET 52 /* Network dropped connection on reset */
+#define ECONNABORTED 53 /* Software caused connection abort */
+#define ECONNRESET 54 /* Connection reset by peer */
+#define ENOBUFS 55 /* No buffer space available */
+#define EISCONN 56 /* Socket is already connected */
+#define ENOTCONN 57 /* Socket is not connected */
+#define ESHUTDOWN 58 /* Can't send after socket shutdown */
+#define ETOOMANYREFS 59 /* Too many references: can't splice */
+#define ETIMEDOUT 60 /* Operation timed out */
+#define ECONNREFUSED 61 /* Connection refused */
+
+#define ELOOP 62 /* Too many levels of symbolic links */
+#endif /* _POSIX_SOURCE */
+#define ENAMETOOLONG 63 /* File name too long */
+
+/* should be rearranged */
+#ifndef _POSIX_SOURCE
+#define EHOSTDOWN 64 /* Host is down */
+#define EHOSTUNREACH 65 /* No route to host */
+#endif /* _POSIX_SOURCE */
+#define ENOTEMPTY 66 /* Directory not empty */
+
+/* quotas & mush */
+#ifndef _POSIX_SOURCE
+#define EPROCLIM 67 /* Too many processes */
+#define EUSERS 68 /* Too many users */
+#define EDQUOT 69 /* Disc quota exceeded */
+
+/* Network File System */
+#define ESTALE 70 /* Stale NFS file handle */
+#define EREMOTE 71 /* Too many levels of remote in path */
+#define EBADRPC 72 /* RPC struct is bad */
+#define ERPCMISMATCH 73 /* RPC version wrong */
+#define EPROGUNAVAIL 74 /* RPC prog. not avail */
+#define EPROGMISMATCH 75 /* Program version wrong */
+#define EPROCUNAVAIL 76 /* Bad procedure for program */
+#endif /* _POSIX_SOURCE */
+
+#define ENOLCK 77 /* No locks available */
+#define ENOSYS 78 /* Function not implemented */
+
+#ifndef _POSIX_SOURCE
+#define EFTYPE 79 /* Inappropriate file type or format */
+#define EAUTH 80 /* Authentication error */
+#define ENEEDAUTH 81 /* Need authenticator */
+#define ELAST 81 /* Must be equal largest errno */
+#endif /* _POSIX_SOURCE */
+
+#ifdef _KERNEL
+/* pseudo-errors returned inside kernel to modify return to process */
+#define ERESTART -1 /* restart syscall */
+#define EJUSTRETURN -2 /* don't modify regs, just return */
+#endif
diff --git a/mit-pthreads/machdep/netbsd-1.1/time.h b/mit-pthreads/machdep/netbsd-1.1/time.h
new file mode 100755
index 00000000000..a701db9c62e
--- /dev/null
+++ b/mit-pthreads/machdep/netbsd-1.1/time.h
@@ -0,0 +1,153 @@
+/* $NetBSD: time.h,v 1.17 1996/02/01 00:10:36 jtc Exp $ */
+
+/*
+ * Copyright (c) 1982, 1986, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)time.h 8.2 (Berkeley) 7/10/94
+ */
+
+#ifndef _SYS_TIME_H_
+#define _SYS_TIME_H_
+
+#include <sys/types.h>
+
+/*
+ * Structure returned by gettimeofday(2) system call,
+ * and used in other calls.
+ */
+struct timeval {
+ long tv_sec; /* seconds */
+ long tv_usec; /* and microseconds */
+};
+
+/*
+ * Structure defined by POSIX.1b to be like a timeval.
+ */
+struct timespec {
+ time_t tv_sec; /* seconds */
+ long tv_nsec; /* and nanoseconds */
+};
+
+#define TIMEVAL_TO_TIMESPEC(tv, ts) { \
+ (ts)->tv_sec = (tv)->tv_sec; \
+ (ts)->tv_nsec = (tv)->tv_usec * 1000; \
+}
+#define TIMESPEC_TO_TIMEVAL(tv, ts) { \
+ (tv)->tv_sec = (ts)->tv_sec; \
+ (tv)->tv_usec = (ts)->tv_nsec / 1000; \
+}
+
+struct timezone {
+ int tz_minuteswest; /* minutes west of Greenwich */
+ int tz_dsttime; /* type of dst correction */
+};
+#define DST_NONE 0 /* not on dst */
+#define DST_USA 1 /* USA style dst */
+#define DST_AUST 2 /* Australian style dst */
+#define DST_WET 3 /* Western European dst */
+#define DST_MET 4 /* Middle European dst */
+#define DST_EET 5 /* Eastern European dst */
+#define DST_CAN 6 /* Canada */
+
+/* Operations on timevals. */
+#define timerclear(tvp) (tvp)->tv_sec = (tvp)->tv_usec = 0
+#define timerisset(tvp) ((tvp)->tv_sec || (tvp)->tv_usec)
+#define timercmp(tvp, uvp, cmp) \
+ (((tvp)->tv_sec == (uvp)->tv_sec) ? \
+ ((tvp)->tv_usec cmp (uvp)->tv_usec) : \
+ ((tvp)->tv_sec cmp (uvp)->tv_sec))
+#define timeradd(tvp, uvp, vvp) \
+ do { \
+ (vvp)->tv_sec = (tvp)->tv_sec + (uvp)->tv_sec; \
+ (vvp)->tv_usec = (tvp)->tv_usec + (uvp)->tv_usec; \
+ if ((vvp)->tv_usec >= 1000000) { \
+ (vvp)->tv_sec++; \
+ (vvp)->tv_usec -= 1000000; \
+ } \
+ } while (0)
+#define timersub(tvp, uvp, vvp) \
+ do { \
+ (vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec; \
+ (vvp)->tv_usec = (tvp)->tv_usec - (uvp)->tv_usec; \
+ if ((vvp)->tv_usec < 0) { \
+ (vvp)->tv_sec--; \
+ (vvp)->tv_usec += 1000000; \
+ } \
+ } while (0)
+
+/*
+ * Names of the interval timers, and structure
+ * defining a timer setting.
+ */
+#define ITIMER_REAL 0
+#define ITIMER_VIRTUAL 1
+#define ITIMER_PROF 2
+
+struct itimerval {
+ struct timeval it_interval; /* timer interval */
+ struct timeval it_value; /* current value */
+};
+
+/*
+ * Getkerninfo clock information structure
+ */
+struct clockinfo {
+ int hz; /* clock frequency */
+ int tick; /* micro-seconds per hz tick */
+ int tickadj; /* clock skew rate for adjtime() */
+ int stathz; /* statistics clock frequency */
+ int profhz; /* profiling clock frequency */
+};
+
+#ifdef _KERNEL
+int itimerfix __P_((struct timeval *tv));
+int itimerdecr __P_((struct itimerval *itp, int usec));
+void microtime __P_((struct timeval *tv));
+#else /* !_KERNEL */
+#include <time.h>
+
+#ifndef _POSIX_SOURCE
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+int adjtime __P_((const struct timeval *, struct timeval *));
+int getitimer __P_((int, struct itimerval *));
+int gettimeofday __P_((struct timeval *, struct timezone *));
+int setitimer __P_((int, const struct itimerval *, struct itimerval *));
+int settimeofday __P_((const struct timeval *, const struct timezone *));
+int utimes __P_((const char *, const struct timeval *));
+__END_DECLS
+#endif /* !POSIX */
+
+#endif /* !_KERNEL */
+
+#endif /* !_SYS_TIME_H_ */
diff --git a/mit-pthreads/machdep/netbsd-1.1/timers.h b/mit-pthreads/machdep/netbsd-1.1/timers.h
new file mode 100755
index 00000000000..b603b78e6b2
--- /dev/null
+++ b/mit-pthreads/machdep/netbsd-1.1/timers.h
@@ -0,0 +1,45 @@
+/* ==== timers.h ============================================================
+ * Copyright (c) 1994 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * timers.h,v 1.50 1994/08/08 03:44:09 proven Exp
+ *
+ * Description : Basic timers header.
+ *
+ * 1.00 94/06/13 proven
+ * -Started coding this file.
+ */
+
+#ifndef _SYS_TIMERS_H_
+#define _SYS_TIMERS_H_
+
+#include <sys/time.h>
+
+#endif
diff --git a/mit-pthreads/machdep/netbsd-1.1/wait.h b/mit-pthreads/machdep/netbsd-1.1/wait.h
new file mode 100755
index 00000000000..0a1e9285e56
--- /dev/null
+++ b/mit-pthreads/machdep/netbsd-1.1/wait.h
@@ -0,0 +1,163 @@
+/* $NetBSD: wait.h,v 1.11 1996/04/09 20:55:51 cgd Exp $ */
+
+/*
+ * Copyright (c) 1982, 1986, 1989, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)wait.h 8.2 (Berkeley) 7/10/94
+ */
+
+#ifndef _SYS_WAIT_H_
+#define _SYS_WAIT_H_
+
+/*
+ * This file holds definitions relevent to the wait4 system call
+ * and the alternate interfaces that use it (wait, wait3, waitpid).
+ */
+
+/*
+ * Macros to test the exit status returned by wait
+ * and extract the relevant values.
+ */
+#ifdef _POSIX_SOURCE
+#define _W_INT(i) (i)
+#else
+#define _W_INT(w) (*(int *)&(w)) /* convert union wait to int */
+#define WCOREFLAG 0200
+#endif
+
+#define _WSTATUS(x) (_W_INT(x) & 0177)
+#define _WSTOPPED 0177 /* _WSTATUS if process is stopped */
+#define WIFSTOPPED(x) (_WSTATUS(x) == _WSTOPPED)
+#define WSTOPSIG(x) (_W_INT(x) >> 8)
+#define WIFSIGNALED(x) (_WSTATUS(x) != _WSTOPPED && _WSTATUS(x) != 0)
+#define WTERMSIG(x) (_WSTATUS(x))
+#define WIFEXITED(x) (_WSTATUS(x) == 0)
+#define WEXITSTATUS(x) (_W_INT(x) >> 8)
+#ifndef _POSIX_SOURCE
+#define WCOREDUMP(x) (_W_INT(x) & WCOREFLAG)
+
+#define W_EXITCODE(ret, sig) ((ret) << 8 | (sig))
+#define W_STOPCODE(sig) ((sig) << 8 | _WSTOPPED)
+#endif
+
+/*
+ * Option bits for the third argument of wait4. WNOHANG causes the
+ * wait to not hang if there are no stopped or terminated processes, rather
+ * returning an error indication in this case (pid==0). WUNTRACED
+ * indicates that the caller should receive status about untraced children
+ * which stop due to signals. If children are stopped and a wait without
+ * this option is done, it is as though they were still running... nothing
+ * about them is returned.
+ */
+#define WNOHANG 1 /* don't hang in wait */
+#define WUNTRACED 2 /* tell about stopped, untraced children */
+
+#ifndef _POSIX_SOURCE
+/* POSIX extensions and 4.2/4.3 compatability: */
+
+/*
+ * Tokens for special values of the "pid" parameter to wait4.
+ */
+#define WAIT_ANY (-1) /* any process */
+#define WAIT_MYPGRP 0 /* any process in my process group */
+
+#include <machine/endian.h>
+
+/*
+ * Deprecated:
+ * Structure of the information in the status word returned by wait4.
+ * If w_stopval==WSTOPPED, then the second structure describes
+ * the information returned, else the first.
+ */
+union wait {
+ int w_status; /* used in syscall */
+ /*
+ * Terminated process status.
+ */
+ struct {
+#if BYTE_ORDER == LITTLE_ENDIAN
+ unsigned int w_Termsig:7, /* termination signal */
+ w_Coredump:1, /* core dump indicator */
+ w_Retcode:8, /* exit code if w_termsig==0 */
+ w_Filler:16; /* upper bits filler */
+#endif
+#if BYTE_ORDER == BIG_ENDIAN
+ unsigned int w_Filler:16, /* upper bits filler */
+ w_Retcode:8, /* exit code if w_termsig==0 */
+ w_Coredump:1, /* core dump indicator */
+ w_Termsig:7; /* termination signal */
+#endif
+ } w_T;
+ /*
+ * Stopped process status. Returned
+ * only for traced children unless requested
+ * with the WUNTRACED option bit.
+ */
+ struct {
+#if BYTE_ORDER == LITTLE_ENDIAN
+ unsigned int w_Stopval:8, /* == W_STOPPED if stopped */
+ w_Stopsig:8, /* signal that stopped us */
+ w_Filler:16; /* upper bits filler */
+#endif
+#if BYTE_ORDER == BIG_ENDIAN
+ unsigned int w_Filler:16, /* upper bits filler */
+ w_Stopsig:8, /* signal that stopped us */
+ w_Stopval:8; /* == W_STOPPED if stopped */
+#endif
+ } w_S;
+};
+#define w_termsig w_T.w_Termsig
+#define w_coredump w_T.w_Coredump
+#define w_retcode w_T.w_Retcode
+#define w_stopval w_S.w_Stopval
+#define w_stopsig w_S.w_Stopsig
+
+#define WSTOPPED _WSTOPPED
+#endif /* _POSIX_SOURCE */
+
+#ifndef _KERNEL
+#include <sys/types.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+struct rusage; /* forward declaration */
+
+pid_t wait __P_((int *));
+pid_t waitpid __P_((pid_t, int *, int));
+#ifndef _POSIX_SOURCE
+pid_t wait3 __P_((int *, int, void *));
+pid_t wait4 __P_((pid_t, int *, int, void *));
+#endif
+__END_DECLS
+#endif
+
+#endif /* !_SYS_WAIT_H_ */
diff --git a/mit-pthreads/machdep/openbsd-2.0/__math.h b/mit-pthreads/machdep/openbsd-2.0/__math.h
new file mode 100755
index 00000000000..27ed0f2575d
--- /dev/null
+++ b/mit-pthreads/machdep/openbsd-2.0/__math.h
@@ -0,0 +1,6 @@
+/*
+ * ANSI/POSIX
+ */
+extern char __infinity[];
+#define HUGE_VAL (*(double *) __infinity)
+
diff --git a/mit-pthreads/machdep/openbsd-2.0/__path.h b/mit-pthreads/machdep/openbsd-2.0/__path.h
new file mode 100755
index 00000000000..432494daafa
--- /dev/null
+++ b/mit-pthreads/machdep/openbsd-2.0/__path.h
@@ -0,0 +1,14 @@
+/*
+ * from: @(#)time.h 5.12 (Berkeley) 3/9/91
+ * $Id$
+ */
+
+#ifndef _SYS__PATH_H_
+#define _SYS__PATH_H_
+
+#define _PATH_PTY "/dev/"
+#define _PATH_TZDIR "/usr/share/zoneinfo"
+#define _PATH_TZFILE "/etc/localtime"
+
+#endif /* !_SYS__PATH_H_ */
+
diff --git a/mit-pthreads/machdep/openbsd-2.0/__signal.h b/mit-pthreads/machdep/openbsd-2.0/__signal.h
new file mode 100755
index 00000000000..918955c9948
--- /dev/null
+++ b/mit-pthreads/machdep/openbsd-2.0/__signal.h
@@ -0,0 +1,8 @@
+#include <sys/signal.h>
+
+#define __SIGEMPTYSET 0
+#define __SIGFILLSET 0xffffffff
+#define __SIGADDSET(s, n) (*(s) |= 1 << ((n) - 1), 0)
+#define __SIGDELSET(s, n) (*(s) &= ~(1 << ((n) - 1)), 0)
+#define __SIGISMEMBER(s, n) ((*(s) & (1 << ((n) - 1))) != 0)
+
diff --git a/mit-pthreads/machdep/openbsd-2.0/__stdio.h b/mit-pthreads/machdep/openbsd-2.0/__stdio.h
new file mode 100755
index 00000000000..d60b9df7a54
--- /dev/null
+++ b/mit-pthreads/machdep/openbsd-2.0/__stdio.h
@@ -0,0 +1,8 @@
+
+#include <machine/ansi.h>
+#ifdef _BSD_SIZE_T_
+typedef _BSD_SIZE_T_ size_t;
+#undef _BSD_SIZE_T_
+#endif
+
+typedef pthread_fpos_t fpos_t; /* Must match off_t <sys/types.h> */
diff --git a/mit-pthreads/machdep/openbsd-2.0/__stdlib.h b/mit-pthreads/machdep/openbsd-2.0/__stdlib.h
new file mode 100755
index 00000000000..5ee2b8ed3d9
--- /dev/null
+++ b/mit-pthreads/machdep/openbsd-2.0/__stdlib.h
@@ -0,0 +1,66 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)stdlib.h 5.13 (Berkeley) 6/4/91
+ * $Id$
+ */
+
+#ifndef _SYS___STDLIB_H_
+#define _SYS___STDLIB_H_
+
+#include <machine/ansi.h>
+
+#ifdef _BSD_SIZE_T_
+typedef _BSD_SIZE_T_ size_t;
+#undef _BSD_SIZE_T_
+#endif
+
+#ifdef _BSD_WCHAR_T_
+typedef _BSD_WCHAR_T_ wchar_t;
+#ifdef _BSD_RUNE_T_
+typedef _BSD_RUNE_T_ rune_t;
+#undef _BSD_RUNE_T_
+#else
+typedef _BSD_WCHAR_T_ rune_t;
+#endif
+#undef _BSD_WCHAR_T_
+#endif
+
+#ifndef __NORETURN
+#define __NORETURN
+#endif
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#endif /* _STDLIB_H_ */
diff --git a/mit-pthreads/machdep/openbsd-2.0/__string.h b/mit-pthreads/machdep/openbsd-2.0/__string.h
new file mode 100755
index 00000000000..93d4fcf9dd2
--- /dev/null
+++ b/mit-pthreads/machdep/openbsd-2.0/__string.h
@@ -0,0 +1,21 @@
+
+#include <machine/ansi.h>
+#ifdef _BSD_SIZE_T_
+typedef _BSD_SIZE_T_ size_t;
+#undef _BSD_SIZE_T_
+#endif
+
+/* Non-standard NetBSD string routines. */
+#if !defined(_ANSI_SOURCE) && !defined(_POSIX_SOURCE)
+__BEGIN_DECLS
+int bcmp __P_((const void *, const void *, size_t));
+void bcopy __P_((const void *, void *, size_t));
+void bzero __P_((void *, size_t));
+char *index __P_((const char *, int));
+char *rindex __P_((const char *, int));
+char *strdup __P_((const char *));
+void strmode __P_((int, char *));
+char *strsep __P_((char **, const char *));
+__END_DECLS
+#endif
+
diff --git a/mit-pthreads/machdep/openbsd-2.0/__time.h b/mit-pthreads/machdep/openbsd-2.0/__time.h
new file mode 100755
index 00000000000..5c4b722bc3c
--- /dev/null
+++ b/mit-pthreads/machdep/openbsd-2.0/__time.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * (c) UNIX System Laboratories, Inc.
+ * All or some portions of this file are derived from material licensed
+ * to the University of California by American Telephone and Telegraph
+ * Co. or Unix System Laboratories, Inc. and are reproduced herein with
+ * the permission of UNIX System Laboratories, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)time.h 5.12 (Berkeley) 3/9/91
+ * $Id$
+ */
+
+#ifndef _SYS__TIME_H_
+#define _SYS__TIME_H_
+
+#include <machine/ansi.h>
+#include <machine/limits.h>
+
+#ifdef _BSD_CLOCK_T_
+typedef _BSD_CLOCK_T_ clock_t;
+#undef _BSD_CLOCK_T_
+#endif
+
+#ifdef _BSD_TIME_T_
+typedef _BSD_TIME_T_ time_t;
+#undef _BSD_TIME_T_
+#endif
+
+#ifdef _BSD_SIZE_T_
+typedef _BSD_SIZE_T_ size_t;
+#undef _BSD_SIZE_T_
+#endif
+
+#define CLOCKS_PER_SEC 100
+
+#if !defined(CLK_TCK)
+#define CLK_TCK 100
+#endif /* not CLK_TCK */
+
+#endif /* !_SYS__TIME_H_ */
diff --git a/mit-pthreads/machdep/openbsd-2.0/__unistd.h b/mit-pthreads/machdep/openbsd-2.0/__unistd.h
new file mode 100755
index 00000000000..41244522461
--- /dev/null
+++ b/mit-pthreads/machdep/openbsd-2.0/__unistd.h
@@ -0,0 +1,109 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)stdlib.h 5.13 (Berkeley) 6/4/91
+ * $Id$
+ */
+
+#ifndef _SYS___UNISTD_H_
+#define _SYS___UNISTD_H_
+
+#include <sys/types.h>
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#define ioctl_request_type unsigned long /* For fd.c */
+
+/* compile-time symbolic constants */
+#define _POSIX_JOB_CONTROL /* implementation supports job control */
+
+#ifdef _NOT_AVAILABLE
+#define _POSIX_SAVED_IDS /* saved set-user-ID and set-group-ID */
+#endif
+
+#define _POSIX_VERSION 198808L
+#define _POSIX2_VERSION 199212L
+
+/* execution-time symbolic constants */
+ /* chown requires appropriate privileges */
+#define _POSIX_CHOWN_RESTRICTED 1
+ /* too-long path components generate errors */
+#define _POSIX_NO_TRUNC 1
+ /* may disable terminal special characters */
+/* #define _POSIX_VDISABLE 0xff */
+
+/* configurable pathname variables */
+#define _PC_LINK_MAX 1
+#define _PC_MAX_CANON 2
+#define _PC_MAX_INPUT 3
+#define _PC_NAME_MAX 4
+#define _PC_PATH_MAX 5
+#define _PC_PIPE_BUF 6
+#define _PC_CHOWN_RESTRICTED 7
+#define _PC_NO_TRUNC 8
+#define _PC_VDISABLE 9
+
+/* configurable system variables */
+#define _SC_ARG_MAX 1
+#define _SC_CHILD_MAX 2
+#define _SC_CLK_TCK 3
+#define _SC_NGROUPS_MAX 4
+#define _SC_OPEN_MAX 5
+#define _SC_JOB_CONTROL 6
+#define _SC_SAVED_IDS 7
+#define _SC_VERSION 8
+#define _SC_BC_BASE_MAX 9
+#define _SC_BC_DIM_MAX 10
+#define _SC_BC_SCALE_MAX 11
+#define _SC_BC_STRING_MAX 12
+#define _SC_COLL_WEIGHTS_MAX 13
+#define _SC_EXPR_NEST_MAX 14
+#define _SC_LINE_MAX 15
+#define _SC_RE_DUP_MAX 16
+#define _SC_2_VERSION 17
+#define _SC_2_C_BIND 18
+#define _SC_2_C_DEV 19
+#define _SC_2_CHAR_TERM 20
+#define _SC_2_FORT_DEV 21
+#define _SC_2_FORT_RUN 22
+#define _SC_2_LOCALEDEF 23
+#define _SC_2_SW_DEV 24
+#define _SC_2_UPE 25
+#define _SC_STREAM_MAX 26
+#define _SC_TZNAME_MAX 27
+
+/* configurable system strings */
+#define _CS_PATH 1
+
+#endif
diff --git a/mit-pthreads/machdep/openbsd-2.0/compat.h b/mit-pthreads/machdep/openbsd-2.0/compat.h
new file mode 100755
index 00000000000..e7de318aa88
--- /dev/null
+++ b/mit-pthreads/machdep/openbsd-2.0/compat.h
@@ -0,0 +1,43 @@
+/* ==== compat.h ============================================================
+ * Copyright (c) 1994 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ *
+ * Description : COmpat header to make socket code compile.
+ *
+ * 1.00 94/08/01 proven
+ * -Started coding this file.
+ */
+
+#ifndef _SYS_COMPAT_H_
+#define _SYS_COMPAT_H_
+
+#endif
diff --git a/mit-pthreads/machdep/openbsd-2.0/dirent.h b/mit-pthreads/machdep/openbsd-2.0/dirent.h
new file mode 100755
index 00000000000..5226443f86b
--- /dev/null
+++ b/mit-pthreads/machdep/openbsd-2.0/dirent.h
@@ -0,0 +1,64 @@
+/*-
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)dirent.h 5.18 (Berkeley) 2/23/91
+ */
+
+#ifndef _SYS_DIRENT_H_
+#define _SYS_DIRENT_H_
+
+/*
+ * A directory entry has a struct dirent at the front of it, containing its
+ * inode number, the length of the entry, and the length of the name
+ * contained in the entry. These are followed by the name padded to a 4
+ * byte boundary with null bytes. All names are guaranteed null terminated.
+ * The maximum length of a name in a directory is MAXNAMLEN.
+ */
+
+struct dirent {
+ u_long d_fileno; /* file number of entry */
+ u_short d_reclen; /* length of this record */
+ u_short d_namlen; /* length of string in d_name */
+#ifdef _POSIX_SOURCE
+ char d_name[255 + 1]; /* name must be no longer than this */
+#else
+#define MAXNAMLEN 255
+ char d_name[MAXNAMLEN + 1]; /* name must be no longer than this */
+#endif
+};
+
+#define d_ino d_fileno /* backward compatibility */
+
+/* definitions for library routines operating on directories. */
+#define DIRBLKSIZ 1024
+
+#endif /* !_DIRENT_H_ */
diff --git a/mit-pthreads/machdep/openbsd-2.0/errno.h b/mit-pthreads/machdep/openbsd-2.0/errno.h
new file mode 100755
index 00000000000..3da61d692a3
--- /dev/null
+++ b/mit-pthreads/machdep/openbsd-2.0/errno.h
@@ -0,0 +1,160 @@
+/* $NetBSD: errno.h,v 1.8 1994/06/29 06:44:02 cgd Exp $ */
+
+/*
+ * Copyright (c) 1982, 1986, 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ * (c) UNIX System Laboratories, Inc.
+ * All or some portions of this file are derived from material licensed
+ * to the University of California by American Telephone and Telegraph
+ * Co. or Unix System Laboratories, Inc. and are reproduced herein with
+ * the permission of UNIX System Laboratories, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)errno.h 8.5 (Berkeley) 1/21/94
+ */
+
+#ifndef _SYS_ERRNO_H_
+#define _SYS_ERRNO_H_
+
+#define EPERM 1 /* Operation not permitted */
+#define ENOENT 2 /* No such file or directory */
+#define ESRCH 3 /* No such process */
+#define EINTR 4 /* Interrupted system call */
+#define EIO 5 /* Input/output error */
+#define ENXIO 6 /* Device not configured */
+#define E2BIG 7 /* Argument list too long */
+#define ENOEXEC 8 /* Exec format error */
+#define EBADF 9 /* Bad file descriptor */
+#define ECHILD 10 /* No child processes */
+#define EDEADLK 11 /* Resource deadlock avoided */
+ /* 11 was EAGAIN */
+#define ENOMEM 12 /* Cannot allocate memory */
+#define EACCES 13 /* Permission denied */
+#define EFAULT 14 /* Bad address */
+#ifndef _POSIX_SOURCE
+#define ENOTBLK 15 /* Block device required */
+#endif
+#define EBUSY 16 /* Device busy */
+#define EEXIST 17 /* File exists */
+#define EXDEV 18 /* Cross-device link */
+#define ENODEV 19 /* Operation not supported by device */
+#define ENOTDIR 20 /* Not a directory */
+#define EISDIR 21 /* Is a directory */
+#define EINVAL 22 /* Invalid argument */
+#define ENFILE 23 /* Too many open files in system */
+#define EMFILE 24 /* Too many open files */
+#define ENOTTY 25 /* Inappropriate ioctl for device */
+#ifndef _POSIX_SOURCE
+#define ETXTBSY 26 /* Text file busy */
+#endif
+#define EFBIG 27 /* File too large */
+#define ENOSPC 28 /* No space left on device */
+#define ESPIPE 29 /* Illegal seek */
+#define EROFS 30 /* Read-only file system */
+#define EMLINK 31 /* Too many links */
+#define EPIPE 32 /* Broken pipe */
+
+/* math software */
+#define EDOM 33 /* Numerical argument out of domain */
+#define ERANGE 34 /* Result too large */
+
+/* non-blocking and interrupt i/o */
+#define EAGAIN 35 /* Resource temporarily unavailable */
+#ifndef _POSIX_SOURCE
+#define EWOULDBLOCK EAGAIN /* Operation would block */
+#define EINPROGRESS 36 /* Operation now in progress */
+#define EALREADY 37 /* Operation already in progress */
+
+/* ipc/network software -- argument errors */
+#define ENOTSOCK 38 /* Socket operation on non-socket */
+#define EDESTADDRREQ 39 /* Destination address required */
+#define EMSGSIZE 40 /* Message too long */
+#define EPROTOTYPE 41 /* Protocol wrong type for socket */
+#define ENOPROTOOPT 42 /* Protocol not available */
+#define EPROTONOSUPPORT 43 /* Protocol not supported */
+#define ESOCKTNOSUPPORT 44 /* Socket type not supported */
+#define EOPNOTSUPP 45 /* Operation not supported */
+#define EPFNOSUPPORT 46 /* Protocol family not supported */
+#define EAFNOSUPPORT 47 /* Address family not supported by protocol family */
+#define EADDRINUSE 48 /* Address already in use */
+#define EADDRNOTAVAIL 49 /* Can't assign requested address */
+
+/* ipc/network software -- operational errors */
+#define ENETDOWN 50 /* Network is down */
+#define ENETUNREACH 51 /* Network is unreachable */
+#define ENETRESET 52 /* Network dropped connection on reset */
+#define ECONNABORTED 53 /* Software caused connection abort */
+#define ECONNRESET 54 /* Connection reset by peer */
+#define ENOBUFS 55 /* No buffer space available */
+#define EISCONN 56 /* Socket is already connected */
+#define ENOTCONN 57 /* Socket is not connected */
+#define ESHUTDOWN 58 /* Can't send after socket shutdown */
+#define ETOOMANYREFS 59 /* Too many references: can't splice */
+#define ETIMEDOUT 60 /* Operation timed out */
+#define ECONNREFUSED 61 /* Connection refused */
+
+#define ELOOP 62 /* Too many levels of symbolic links */
+#endif /* _POSIX_SOURCE */
+#define ENAMETOOLONG 63 /* File name too long */
+
+/* should be rearranged */
+#ifndef _POSIX_SOURCE
+#define EHOSTDOWN 64 /* Host is down */
+#define EHOSTUNREACH 65 /* No route to host */
+#endif /* _POSIX_SOURCE */
+#define ENOTEMPTY 66 /* Directory not empty */
+
+/* quotas & mush */
+#ifndef _POSIX_SOURCE
+#define EPROCLIM 67 /* Too many processes */
+#define EUSERS 68 /* Too many users */
+#define EDQUOT 69 /* Disc quota exceeded */
+
+/* Network File System */
+#define ESTALE 70 /* Stale NFS file handle */
+#define EREMOTE 71 /* Too many levels of remote in path */
+#define EBADRPC 72 /* RPC struct is bad */
+#define ERPCMISMATCH 73 /* RPC version wrong */
+#define EPROGUNAVAIL 74 /* RPC prog. not avail */
+#define EPROGMISMATCH 75 /* Program version wrong */
+#define EPROCUNAVAIL 76 /* Bad procedure for program */
+#endif /* _POSIX_SOURCE */
+
+#define ENOLCK 77 /* No locks available */
+#define ENOSYS 78 /* Function not implemented */
+
+#ifndef _POSIX_SOURCE
+#define EFTYPE 79 /* Inappropriate file type or format */
+#define EAUTH 80 /* Authentication error */
+#define ENEEDAUTH 81 /* Need authenticator */
+#define ELAST 81 /* Must be equal largest errno */
+#endif /* _POSIX_SOURCE */
+
+#endif
diff --git a/mit-pthreads/machdep/openbsd-2.0/timers.h b/mit-pthreads/machdep/openbsd-2.0/timers.h
new file mode 100755
index 00000000000..f9768c68c8f
--- /dev/null
+++ b/mit-pthreads/machdep/openbsd-2.0/timers.h
@@ -0,0 +1,45 @@
+/* ==== timers.h ============================================================
+ * Copyright (c) 1994 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ *
+ * Description : Basic timers header.
+ *
+ * 1.00 94/06/13 proven
+ * -Started coding this file.
+ */
+
+#ifndef _SYS_TIMERS_H_
+#define _SYS_TIMERS_H_
+
+#include <sys/time.h>
+
+#endif
diff --git a/mit-pthreads/machdep/openbsd-2.0/wait.h b/mit-pthreads/machdep/openbsd-2.0/wait.h
new file mode 100755
index 00000000000..7861e3fa180
--- /dev/null
+++ b/mit-pthreads/machdep/openbsd-2.0/wait.h
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 1982, 1986, 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)wait.h 8.1 (Berkeley) 6/2/93
+ * $Id$
+ */
+
+#ifndef _SYS_WAIT_H_
+#define _SYS_WAIT_H_
+
+/*
+ * This file holds definitions relevent to the wait4 system call
+ * and the alternate interfaces that use it (wait, wait3, waitpid).
+ */
+
+/*
+ * Macros to test the exit status returned by wait
+ * and extract the relevant values.
+ */
+#ifdef _POSIX_SOURCE
+#define _W_INT(i) (i)
+#else
+#define _W_INT(w) (*(int *)&(w)) /* convert union wait to int */
+#define WCOREFLAG 0200
+#endif
+
+#define _WSTATUS(x) (_W_INT(x) & 0177)
+#define _WSTOPPED 0177 /* _WSTATUS if process is stopped */
+#define WIFSTOPPED(x) (_WSTATUS(x) == _WSTOPPED)
+#define WSTOPSIG(x) (_W_INT(x) >> 8)
+#define WIFSIGNALED(x) (_WSTATUS(x) != _WSTOPPED && _WSTATUS(x) != 0)
+#define WTERMSIG(x) (_WSTATUS(x))
+#define WIFEXITED(x) (_WSTATUS(x) == 0)
+#define WEXITSTATUS(x) (_W_INT(x) >> 8)
+#ifndef _POSIX_SOURCE
+#define WCOREDUMP(x) (_W_INT(x) & WCOREFLAG)
+
+#define W_EXITCODE(ret, sig) ((ret) << 8 | (sig))
+#define W_STOPCODE(sig) ((sig) << 8 | _WSTOPPED)
+#endif
+
+/*
+ * Option bits for the third argument of wait4. WNOHANG causes the
+ * wait to not hang if there are no stopped or terminated processes, rather
+ * returning an error indication in this case (pid==0). WUNTRACED
+ * indicates that the caller should receive status about untraced children
+ * which stop due to signals. If children are stopped and a wait without
+ * this option is done, it is as though they were still running... nothing
+ * about them is returned.
+ */
+#define WNOHANG 1 /* dont hang in wait */
+#define WUNTRACED 2 /* tell about stopped, untraced children */
+
+#ifndef _POSIX_SOURCE
+/* POSIX extensions and 4.2/4.3 compatability: */
+
+/*
+ * Tokens for special values of the "pid" parameter to wait4.
+ */
+#define WAIT_ANY (-1) /* any process */
+#define WAIT_MYPGRP 0 /* any process in my process group */
+
+#include <machine/endian.h>
+
+/*
+ * Deprecated:
+ * Structure of the information in the status word returned by wait4.
+ * If w_stopval==WSTOPPED, then the second structure describes
+ * the information returned, else the first.
+ */
+union wait {
+ int w_status; /* used in syscall */
+ /*
+ * Terminated process status.
+ */
+ struct {
+#if BYTE_ORDER == LITTLE_ENDIAN
+ unsigned int w_Termsig:7, /* termination signal */
+ w_Coredump:1, /* core dump indicator */
+ w_Retcode:8, /* exit code if w_termsig==0 */
+ w_Filler:16; /* upper bits filler */
+#endif
+#if BYTE_ORDER == BIG_ENDIAN
+ unsigned int w_Filler:16, /* upper bits filler */
+ w_Retcode:8, /* exit code if w_termsig==0 */
+ w_Coredump:1, /* core dump indicator */
+ w_Termsig:7; /* termination signal */
+#endif
+ } w_T;
+ /*
+ * Stopped process status. Returned
+ * only for traced children unless requested
+ * with the WUNTRACED option bit.
+ */
+ struct {
+#if BYTE_ORDER == LITTLE_ENDIAN
+ unsigned int w_Stopval:8, /* == W_STOPPED if stopped */
+ w_Stopsig:8, /* signal that stopped us */
+ w_Filler:16; /* upper bits filler */
+#endif
+#if BYTE_ORDER == BIG_ENDIAN
+ unsigned int w_Filler:16, /* upper bits filler */
+ w_Stopsig:8, /* signal that stopped us */
+ w_Stopval:8; /* == W_STOPPED if stopped */
+#endif
+ } w_S;
+};
+#define w_termsig w_T.w_Termsig
+#define w_coredump w_T.w_Coredump
+#define w_retcode w_T.w_Retcode
+#define w_stopval w_S.w_Stopval
+#define w_stopsig w_S.w_Stopsig
+
+#define WSTOPPED _WSTOPPED
+#endif /* _POSIX_SOURCE */
+
+#ifndef KERNEL
+#include <sys/types.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+struct rusage; /* forward declaration */
+
+pid_t wait __P_((int *));
+pid_t waitpid __P_((pid_t, int *, int));
+#ifndef _POSIX_SOURCE
+pid_t wait3 __P_((int *, int, void *));
+pid_t wait4 __P_((pid_t, int *, int, void *));
+#endif
+__END_DECLS
+#endif
+
+#endif
diff --git a/mit-pthreads/machdep/posix-alpha-osf1.h b/mit-pthreads/machdep/posix-alpha-osf1.h
new file mode 100644
index 00000000000..1d8bb6c5c4b
--- /dev/null
+++ b/mit-pthreads/machdep/posix-alpha-osf1.h
@@ -0,0 +1,7 @@
+#ifndef _PTHREAD_POSIX_H_
+#define _PTHREAD_POSIX_H_
+
+#define __WAIT_STATUS int *
+#include <pthread/types.h>
+
+#endif
diff --git a/mit-pthreads/machdep/posix-bsdi-1.1.h b/mit-pthreads/machdep/posix-bsdi-1.1.h
new file mode 100644
index 00000000000..4c56ea93a3b
--- /dev/null
+++ b/mit-pthreads/machdep/posix-bsdi-1.1.h
@@ -0,0 +1,34 @@
+/* ==== posix.h ============================================================
+ * Copyright (c) 1993 by Chris Provenzano, proven@athena.mit.edu
+ *
+ * Description : Convert an Ultrix-4.2 system to a more or less POSIX system.
+ *
+ * $Id$
+ *
+ * 1.00 93/07/20 proven
+ * -Started coding this file.
+ */
+
+#ifndef _PTHREAD_POSIX_H_
+#define _PTHREAD_POSIX_H_
+
+#include <sys/cdefs.h>
+
+/* More stuff for compiling */
+#if defined(__GNUC__)
+#define __INLINE extern inline
+#else
+#define __INLINE static
+#endif
+
+/* Make sure we have size_t defined */
+#include <pthread/types.h>
+
+#define __NORETURN
+
+#ifndef __WAIT_STATUS
+#define __WAIT_STATUS int *
+#endif
+
+#endif
+
diff --git a/mit-pthreads/machdep/posix-bsdi-2.0.h b/mit-pthreads/machdep/posix-bsdi-2.0.h
new file mode 100644
index 00000000000..4c56ea93a3b
--- /dev/null
+++ b/mit-pthreads/machdep/posix-bsdi-2.0.h
@@ -0,0 +1,34 @@
+/* ==== posix.h ============================================================
+ * Copyright (c) 1993 by Chris Provenzano, proven@athena.mit.edu
+ *
+ * Description : Convert an Ultrix-4.2 system to a more or less POSIX system.
+ *
+ * $Id$
+ *
+ * 1.00 93/07/20 proven
+ * -Started coding this file.
+ */
+
+#ifndef _PTHREAD_POSIX_H_
+#define _PTHREAD_POSIX_H_
+
+#include <sys/cdefs.h>
+
+/* More stuff for compiling */
+#if defined(__GNUC__)
+#define __INLINE extern inline
+#else
+#define __INLINE static
+#endif
+
+/* Make sure we have size_t defined */
+#include <pthread/types.h>
+
+#define __NORETURN
+
+#ifndef __WAIT_STATUS
+#define __WAIT_STATUS int *
+#endif
+
+#endif
+
diff --git a/mit-pthreads/machdep/posix-freebsd-1.1.h b/mit-pthreads/machdep/posix-freebsd-1.1.h
new file mode 100644
index 00000000000..e1a00e9efd1
--- /dev/null
+++ b/mit-pthreads/machdep/posix-freebsd-1.1.h
@@ -0,0 +1,33 @@
+/* ==== posix.h ============================================================
+ * Copyright (c) 1993 by Chris Provenzano, proven@athena.mit.edu
+ *
+ * Description : Convert an Ultrix-4.2 system to a more or less POSIX system.
+ *
+ * $Id$
+ *
+ * 1.00 93/07/20 proven
+ * -Started coding this file.
+ */
+
+#ifndef _PTHREAD_POSIX_H_
+#define _PTHREAD_POSIX_H_
+
+#include <sys/cdefs.h>
+
+/* More stuff for compiling */
+#if defined(__GNUC__)
+#define __INLINE extern inline
+#else
+#define __INLINE static
+#endif
+
+/* Make sure we have size_t defined */
+#include <pthread/types.h>
+
+#define __NORETURN
+
+#ifndef __WAIT_STATUS
+#define __WAIT_STATUS int *
+#endif
+
+#endif
diff --git a/mit-pthreads/machdep/posix-freebsd-2.0.h b/mit-pthreads/machdep/posix-freebsd-2.0.h
new file mode 100644
index 00000000000..7bad77aba02
--- /dev/null
+++ b/mit-pthreads/machdep/posix-freebsd-2.0.h
@@ -0,0 +1,31 @@
+/* ==== posix.h ============================================================
+ * Copyright (c) 1993 by Chris Provenzano, proven@athena.mit.edu
+ *
+ * Description : Convert an Ultrix-4.2 system to a more or less POSIX system.
+ *
+ * $Id$
+ *
+ * 1.00 93/07/20 proven
+ * -Started coding this file.
+ */
+
+#ifndef _PTHREAD_POSIX_H_
+#define _PTHREAD_POSIX_H_
+
+#include <sys/cdefs.h>
+
+/* More stuff for compiling */
+#if defined(__GNUC__)
+#define __INLINE extern inline
+#else
+#define __INLINE static
+#endif
+
+/* Make sure we have size_t defined */
+#include <pthread/types.h>
+
+#ifndef __WAIT_STATUS
+#define __WAIT_STATUS int *
+#endif
+
+#endif
diff --git a/mit-pthreads/machdep/posix-hpux-10.20.h b/mit-pthreads/machdep/posix-hpux-10.20.h
new file mode 100644
index 00000000000..c7ecb429e79
--- /dev/null
+++ b/mit-pthreads/machdep/posix-hpux-10.20.h
@@ -0,0 +1,23 @@
+/* ==== posix.h ============================================================
+ * Copyright (c) 1993 by Chris Provenzano, proven@athena.mit.edu
+ *
+ * $Id$
+ *
+ * Description : Convert an Ultrix-4.2 system to a more or less POSIX system.
+ *
+ * 1.00 93/07/20 proven
+ * -Started coding this file.
+ */
+
+#ifndef _PTHREAD_POSIX_H_
+#define _PTHREAD_POSIX_H_
+
+/* Make sure we have size_t defined */
+#include <pthread/types.h>
+
+#ifndef __WAIT_STATUS
+#define __WAIT_STATUS int *
+#endif
+
+#endif
+
diff --git a/mit-pthreads/machdep/posix-hpux-9.03.h b/mit-pthreads/machdep/posix-hpux-9.03.h
new file mode 100644
index 00000000000..c7ecb429e79
--- /dev/null
+++ b/mit-pthreads/machdep/posix-hpux-9.03.h
@@ -0,0 +1,23 @@
+/* ==== posix.h ============================================================
+ * Copyright (c) 1993 by Chris Provenzano, proven@athena.mit.edu
+ *
+ * $Id$
+ *
+ * Description : Convert an Ultrix-4.2 system to a more or less POSIX system.
+ *
+ * 1.00 93/07/20 proven
+ * -Started coding this file.
+ */
+
+#ifndef _PTHREAD_POSIX_H_
+#define _PTHREAD_POSIX_H_
+
+/* Make sure we have size_t defined */
+#include <pthread/types.h>
+
+#ifndef __WAIT_STATUS
+#define __WAIT_STATUS int *
+#endif
+
+#endif
+
diff --git a/mit-pthreads/machdep/posix-i386-sco-3.2v5.h b/mit-pthreads/machdep/posix-i386-sco-3.2v5.h
new file mode 100644
index 00000000000..ab91311612d
--- /dev/null
+++ b/mit-pthreads/machdep/posix-i386-sco-3.2v5.h
@@ -0,0 +1,35 @@
+/* ==== posix.h ============================================================
+ * Copyright (c) 1993 by Chris Provenzano, proven@athena.mit.edu
+ *
+ * Description : Convert an Ultrix-4.2 system to a more or less POSIX system.
+ *
+ * posix-freebsd-2.0.h,v 1.1 1995/03/01 01:21:30 proven Exp
+ *
+ * 1.00 93/07/20 proven
+ * -Started coding this file.
+ */
+
+#ifndef _PTHREAD_POSIX_H_
+#define _PTHREAD_POSIX_H_
+
+#include <sys/cdefs.h>
+
+/* More stuff for compiling */
+#if defined(__GNUC__)
+#define __INLINE extern inline
+#else
+#define __INLINE static
+#endif
+
+/* Make sure we have size_t defined */
+#include <pthread/types.h>
+
+#ifndef __NORETURN
+#define __NORETURN
+#endif
+
+#ifndef __WAIT_STATUS
+#define __WAIT_STATUS int *
+#endif
+
+#endif
diff --git a/mit-pthreads/machdep/posix-irix-5.2.h b/mit-pthreads/machdep/posix-irix-5.2.h
new file mode 100644
index 00000000000..d387bbbbf69
--- /dev/null
+++ b/mit-pthreads/machdep/posix-irix-5.2.h
@@ -0,0 +1,31 @@
+/* ==== posix.h ============================================================
+ * Copyright (c) 1995 by Chris Provenzano, proven@athena.mit.edu
+ *
+ * Description : Convert an IRIX-5.2 system to a more or less POSIX system.
+ *
+ * $Id$
+ *
+ * 1.00 95/06/01 proven
+ * -Started coding this file.
+ */
+
+#ifndef _PTHREAD_POSIX_H_
+#define _PTHREAD_POSIX_H_
+
+#include <sys/cdefs.h>
+
+/* More stuff for compiling */
+#if defined(__GNUC__)
+#define __INLINE extern inline
+#else
+#define __INLINE static
+#endif
+
+/* Make sure we have size_t defined */
+#include <pthread/types.h>
+
+#ifndef __WAIT_STATUS
+#define __WAIT_STATUS int *
+#endif
+
+#endif
diff --git a/mit-pthreads/machdep/posix-linux-1.0.h b/mit-pthreads/machdep/posix-linux-1.0.h
new file mode 100644
index 00000000000..7f665d6b44a
--- /dev/null
+++ b/mit-pthreads/machdep/posix-linux-1.0.h
@@ -0,0 +1,31 @@
+/* ==== posix.h ============================================================
+ * Copyright (c) 1993, 1994 by Chris Provenzano, proven@athena.mit.edu
+ *
+ * $Id$
+ *
+ * Description : Convert a Linux-1.0 system to a more or less POSIX system.
+ * Mostly POSIX already
+ */
+
+#ifndef _PTHREAD_POSIX_H_
+#define _PTHREAD_POSIX_H_
+
+#include <sys/cdefs.h>
+
+/* Make sure we have size_t defined */
+#include <pthread/types.h>
+
+#define __INLINE extern inline
+/*
+ * OK now do stuff to make the code compile.
+ * Every OS has its own prototypes for each function
+ */
+#ifdef malloc
+#undef malloc
+#endif
+
+#ifdef free
+#undef free
+#endif
+
+#endif
diff --git a/mit-pthreads/machdep/posix-linux-2.0.h b/mit-pthreads/machdep/posix-linux-2.0.h
new file mode 100644
index 00000000000..7f665d6b44a
--- /dev/null
+++ b/mit-pthreads/machdep/posix-linux-2.0.h
@@ -0,0 +1,31 @@
+/* ==== posix.h ============================================================
+ * Copyright (c) 1993, 1994 by Chris Provenzano, proven@athena.mit.edu
+ *
+ * $Id$
+ *
+ * Description : Convert a Linux-1.0 system to a more or less POSIX system.
+ * Mostly POSIX already
+ */
+
+#ifndef _PTHREAD_POSIX_H_
+#define _PTHREAD_POSIX_H_
+
+#include <sys/cdefs.h>
+
+/* Make sure we have size_t defined */
+#include <pthread/types.h>
+
+#define __INLINE extern inline
+/*
+ * OK now do stuff to make the code compile.
+ * Every OS has its own prototypes for each function
+ */
+#ifdef malloc
+#undef malloc
+#endif
+
+#ifdef free
+#undef free
+#endif
+
+#endif
diff --git a/mit-pthreads/machdep/posix-netbsd-0.9.h b/mit-pthreads/machdep/posix-netbsd-0.9.h
new file mode 100644
index 00000000000..00ff2efa327
--- /dev/null
+++ b/mit-pthreads/machdep/posix-netbsd-0.9.h
@@ -0,0 +1,22 @@
+/* ==== posix.h ============================================================
+ * Copyright (c) 1993 by Chris Provenzano, proven@athena.mit.edu
+ *
+ * Description : Convert an Ultrix-4.2 system to a more or less POSIX system.
+ *
+ * $Id$
+ *
+ * 1.00 93/07/20 proven
+ * -Started coding this file.
+ */
+
+#ifndef _PTHREAD_POSIX_H_
+#define _PTHREAD_POSIX_H_
+
+#include <sys/cdefs.h>
+
+/* Make sure we have size_t defined */
+#include <pthread/types.h>
+
+#define __NORETURN
+
+#endif
diff --git a/mit-pthreads/machdep/posix-netbsd-1.0.h b/mit-pthreads/machdep/posix-netbsd-1.0.h
new file mode 100644
index 00000000000..7bad77aba02
--- /dev/null
+++ b/mit-pthreads/machdep/posix-netbsd-1.0.h
@@ -0,0 +1,31 @@
+/* ==== posix.h ============================================================
+ * Copyright (c) 1993 by Chris Provenzano, proven@athena.mit.edu
+ *
+ * Description : Convert an Ultrix-4.2 system to a more or less POSIX system.
+ *
+ * $Id$
+ *
+ * 1.00 93/07/20 proven
+ * -Started coding this file.
+ */
+
+#ifndef _PTHREAD_POSIX_H_
+#define _PTHREAD_POSIX_H_
+
+#include <sys/cdefs.h>
+
+/* More stuff for compiling */
+#if defined(__GNUC__)
+#define __INLINE extern inline
+#else
+#define __INLINE static
+#endif
+
+/* Make sure we have size_t defined */
+#include <pthread/types.h>
+
+#ifndef __WAIT_STATUS
+#define __WAIT_STATUS int *
+#endif
+
+#endif
diff --git a/mit-pthreads/machdep/posix-netbsd-1.1.h b/mit-pthreads/machdep/posix-netbsd-1.1.h
new file mode 100644
index 00000000000..f4ff1dfae05
--- /dev/null
+++ b/mit-pthreads/machdep/posix-netbsd-1.1.h
@@ -0,0 +1,31 @@
+/* ==== posix.h ============================================================
+ * Copyright (c) 1993 by Chris Provenzano, proven@athena.mit.edu
+ *
+ * Description : Convert an Ultrix-4.2 system to a more or less POSIX system.
+ *
+ * posix-netbsd-1.0.h,v 1.53 1995/02/17 03:41:34 proven Exp
+ *
+ * 1.00 93/07/20 proven
+ * -Started coding this file.
+ */
+
+#ifndef _PTHREAD_POSIX_H_
+#define _PTHREAD_POSIX_H_
+
+#include <sys/cdefs.h>
+
+/* More stuff for compiling */
+#if defined(__GNUC__)
+#define __INLINE extern inline
+#else
+#define __INLINE static
+#endif
+
+/* Make sure we have size_t defined */
+#include <pthread/types.h>
+
+#ifndef __WAIT_STATUS
+#define __WAIT_STATUS int *
+#endif
+
+#endif
diff --git a/mit-pthreads/machdep/posix-openbsd-2.0.h b/mit-pthreads/machdep/posix-openbsd-2.0.h
new file mode 100644
index 00000000000..7bad77aba02
--- /dev/null
+++ b/mit-pthreads/machdep/posix-openbsd-2.0.h
@@ -0,0 +1,31 @@
+/* ==== posix.h ============================================================
+ * Copyright (c) 1993 by Chris Provenzano, proven@athena.mit.edu
+ *
+ * Description : Convert an Ultrix-4.2 system to a more or less POSIX system.
+ *
+ * $Id$
+ *
+ * 1.00 93/07/20 proven
+ * -Started coding this file.
+ */
+
+#ifndef _PTHREAD_POSIX_H_
+#define _PTHREAD_POSIX_H_
+
+#include <sys/cdefs.h>
+
+/* More stuff for compiling */
+#if defined(__GNUC__)
+#define __INLINE extern inline
+#else
+#define __INLINE static
+#endif
+
+/* Make sure we have size_t defined */
+#include <pthread/types.h>
+
+#ifndef __WAIT_STATUS
+#define __WAIT_STATUS int *
+#endif
+
+#endif
diff --git a/mit-pthreads/machdep/posix-romp-bsd.h b/mit-pthreads/machdep/posix-romp-bsd.h
new file mode 100644
index 00000000000..7825622b064
--- /dev/null
+++ b/mit-pthreads/machdep/posix-romp-bsd.h
@@ -0,0 +1,33 @@
+/* ==== posix.h ============================================================
+ * Copyright (c) 1993 by Chris Provenzano, proven@athena.mit.edu
+ *
+ * Description : Convert a system to a more or less POSIX system.
+ *
+ * 1.00 93/07/20 proven
+ * -Started coding this file.
+ */
+
+#ifndef lint
+static const char rcsid[] = "$Id$";
+#endif
+
+#ifndef O_NONBLOCK
+#ifdef FNDELAY
+#define O_NONBLOCK FNDELAY
+#endif
+#endif
+
+#ifndef O_ACCMODE
+#define O_ACCMODE (O_RDONLY|O_RDWR|O_WRONLY)
+#endif
+
+#ifndef S_ISREG
+#define S_ISREG(x) ((x & S_IFMT) == S_IFREG)
+#endif
+
+#ifndef ENOSYS
+#define ENOSYS EINVAL
+#endif
+
+/* Make sure we have size_t defined */
+#include <pthread/types.h>
diff --git a/mit-pthreads/machdep/posix-sco-3.2v5.h b/mit-pthreads/machdep/posix-sco-3.2v5.h
new file mode 100644
index 00000000000..ab91311612d
--- /dev/null
+++ b/mit-pthreads/machdep/posix-sco-3.2v5.h
@@ -0,0 +1,35 @@
+/* ==== posix.h ============================================================
+ * Copyright (c) 1993 by Chris Provenzano, proven@athena.mit.edu
+ *
+ * Description : Convert an Ultrix-4.2 system to a more or less POSIX system.
+ *
+ * posix-freebsd-2.0.h,v 1.1 1995/03/01 01:21:30 proven Exp
+ *
+ * 1.00 93/07/20 proven
+ * -Started coding this file.
+ */
+
+#ifndef _PTHREAD_POSIX_H_
+#define _PTHREAD_POSIX_H_
+
+#include <sys/cdefs.h>
+
+/* More stuff for compiling */
+#if defined(__GNUC__)
+#define __INLINE extern inline
+#else
+#define __INLINE static
+#endif
+
+/* Make sure we have size_t defined */
+#include <pthread/types.h>
+
+#ifndef __NORETURN
+#define __NORETURN
+#endif
+
+#ifndef __WAIT_STATUS
+#define __WAIT_STATUS int *
+#endif
+
+#endif
diff --git a/mit-pthreads/machdep/posix-sunos-4.1.3.h b/mit-pthreads/machdep/posix-sunos-4.1.3.h
new file mode 100644
index 00000000000..719386bc558
--- /dev/null
+++ b/mit-pthreads/machdep/posix-sunos-4.1.3.h
@@ -0,0 +1,27 @@
+/* ==== posix.h ============================================================
+ * Copyright (c) 1993 by Chris Provenzano, proven@athena.mit.edu
+ *
+ * $Id$
+ *
+ * Description : Do the right thing for a sunos 4.1.3 system.
+ *
+ * 1.00 93/07/20 proven
+ * -Started coding this file.
+ */
+
+#ifndef _PTHREAD_POSIX_H_
+#ifndef __WAIT_STATUS
+#define __WAIT_STATUS int *
+#endif
+
+#define _PTHREAD_POSIX_H_
+
+#include <sys/cdefs.h>
+
+/* Make sure we have size_t defined */
+#include <pthread/types.h>
+
+extern long strtol();
+extern unsigned long strtoul();
+
+#endif
diff --git a/mit-pthreads/machdep/posix-sunos-5.3.h b/mit-pthreads/machdep/posix-sunos-5.3.h
new file mode 100644
index 00000000000..9fb765d60c3
--- /dev/null
+++ b/mit-pthreads/machdep/posix-sunos-5.3.h
@@ -0,0 +1,22 @@
+/* ==== posix.h ============================================================
+ * Copyright (c) 1993 by Chris Provenzano, proven@athena.mit.edu
+ *
+ * $Id$
+ *
+ * Description : Do the right thing for a sunos 4.1.3 system.
+ *
+ * 1.00 93/07/20 proven
+ * -Started coding this file.
+ */
+
+#ifndef _PTHREAD_POSIX_H_
+#define _PTHREAD_POSIX_H_
+
+/* Make sure we have size_t defined */
+#include <pthread/types.h>
+
+#ifndef __WAIT_STATUS
+#define __WAIT_STATUS int *
+#endif
+
+#endif
diff --git a/mit-pthreads/machdep/posix-sunos-5.5.h b/mit-pthreads/machdep/posix-sunos-5.5.h
new file mode 100644
index 00000000000..9fb765d60c3
--- /dev/null
+++ b/mit-pthreads/machdep/posix-sunos-5.5.h
@@ -0,0 +1,22 @@
+/* ==== posix.h ============================================================
+ * Copyright (c) 1993 by Chris Provenzano, proven@athena.mit.edu
+ *
+ * $Id$
+ *
+ * Description : Do the right thing for a sunos 4.1.3 system.
+ *
+ * 1.00 93/07/20 proven
+ * -Started coding this file.
+ */
+
+#ifndef _PTHREAD_POSIX_H_
+#define _PTHREAD_POSIX_H_
+
+/* Make sure we have size_t defined */
+#include <pthread/types.h>
+
+#ifndef __WAIT_STATUS
+#define __WAIT_STATUS int *
+#endif
+
+#endif
diff --git a/mit-pthreads/machdep/posix-ultrix-4.2.h b/mit-pthreads/machdep/posix-ultrix-4.2.h
new file mode 100644
index 00000000000..f21aec23ea3
--- /dev/null
+++ b/mit-pthreads/machdep/posix-ultrix-4.2.h
@@ -0,0 +1,24 @@
+/* ==== posix.h ============================================================
+ * Copyright (c) 1993 by Chris Provenzano, proven@athena.mit.edu
+ *
+ * $Id$
+ *
+ * Description : Convert an Ultrix-4.2 system to a more or less POSIX system.
+ *
+ * 1.00 93/07/20 proven
+ * -Started coding this file.
+ */
+
+#ifndef _PTHREAD_POSIX_H_
+#define _PTHREAD_POSIX_H_
+
+#include <sys/cdefs.h>
+
+/* Make sure we have size_t defined */
+#include <pthread/types.h>
+
+#ifndef __WAIT_STATUS
+#define __WAIT_STATUS int *
+#endif
+
+#endif
diff --git a/mit-pthreads/machdep/sco-3.2v5/__math.h b/mit-pthreads/machdep/sco-3.2v5/__math.h
new file mode 100755
index 00000000000..4852683fcbf
--- /dev/null
+++ b/mit-pthreads/machdep/sco-3.2v5/__math.h
@@ -0,0 +1,219 @@
+/* Copyright 1994-1995 The Santa Cruz Operation, Inc. All Rights Reserved. */
+
+
+#if defined(_NO_PROTOTYPE) /* Old, crufty environment */
+#include <oldstyle/__math.h>
+#elif defined(_XOPEN_SOURCE) || defined(_XPG4_VERS) /* Xpg4 environment */
+#include <xpg4/__math.h>
+#elif defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) /* Posix environment */
+#include <posix/__math.h>
+#elif _STRICT_ANSI /* Pure Ansi/ISO environment */
+#include <ansi/__math.h>
+#elif defined(_SCO_ODS_30) /* Old, Tbird compatible environment */
+#include <ods_30_compat/__math.h>
+#else /* Normal, default environment */
+/*
+ * Portions Copyright (C) 1983-1995 The Santa Cruz Operation, Inc.
+ * All Rights Reserved.
+ *
+ * The information in this file is provided for the exclusive use of
+ * the licensees of The Santa Cruz Operation, Inc. Such users have the
+ * right to use, modify, and incorporate this code into other products
+ * for purposes authorized by the license agreement provided they include
+ * this notice and the associated copyright notice with any such product.
+ * The information in this file is provided "AS IS" without warranty.
+ */
+
+/* Portions Copyright (c) 1990, 1991, 1992, 1993 UNIX System Laboratories, Inc. */
+/* Portions Copyright (c) 1979 - 1990 AT&T */
+/* All Rights Reserved */
+
+/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF */
+/* UNIX System Laboratories, Inc. */
+/* The copyright notice above does not evidence any */
+/* actual or intended publication of such source code. */
+
+#ifndef ___MATH_H
+#define ___MATH_H
+
+#pragma comment(exestr, "xpg4plus @(#) math.h 20.1 94/12/04 ")
+
+#pragma pack(4)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+extern double acos(double);
+extern double asin(double);
+extern double atan(double);
+extern double atan2(double, double);
+extern double cos(double);
+extern double sin(double);
+extern double tan(double);
+
+extern double cosh(double);
+extern double sinh(double);
+extern double tanh(double);
+
+extern double exp(double);
+extern double frexp(double, int *);
+extern double ldexp(double, int);
+extern double log(double);
+extern double log10(double);
+extern double modf(double, double *);
+
+extern double pow(double, double);
+extern double sqrt(double);
+
+extern double ceil(double);
+extern double fabs(double);
+extern double floor(double);
+extern double fmod(double, double);
+
+#ifndef HUGE_VAL
+extern const double __huge_val;
+#define HUGE_VAL (+__huge_val)
+#endif
+
+
+extern double erf(double);
+extern double erfc(double);
+extern double gamma(double);
+extern double hypot(double, double);
+extern double j0(double);
+extern double j1(double);
+extern double jn(int, double);
+extern double y0(double);
+extern double y1(double);
+extern double yn(int, double);
+extern double lgamma(double);
+extern int isnan(double);
+
+#define MAXFLOAT ((float)3.40282346638528860e+38)
+
+
+
+#define HUGE MAXFLOAT
+
+/*
+ * The following are all legal as XPG4 external functions but must only
+ * be declared in the non standards environments as they conflict with
+ * the user name space
+ */
+
+extern long double frexpl(long double, int *);
+extern long double ldexpl(long double, int);
+extern long double modfl(long double, long double *);
+
+extern float acosf(float);
+extern float asinf(float);
+extern float atanf(float);
+extern float atan2f(float, float);
+extern float cosf(float);
+extern float sinf(float);
+extern float tanf(float);
+
+extern float coshf(float);
+extern float sinhf(float);
+extern float tanhf(float);
+
+extern float expf(float);
+extern float logf(float);
+extern float log10f(float);
+
+extern float powf(float, float);
+extern float sqrtf(float);
+
+extern float ceilf(float);
+extern float fabsf(float);
+extern float floorf(float);
+extern float fmodf(float, float);
+extern float modff(float, float *);
+
+/* These are all extensions from XPG4 */
+
+extern double atof(const char *);
+extern double scalb(double, double);
+extern double logb(double);
+extern double log1p(double);
+extern double nextafter(double, double);
+extern double acosh(double);
+extern double asinh(double);
+extern double atanh(double);
+extern double cbrt(double);
+extern double copysign(double, double);
+extern double expm1(double);
+extern int ilogb(double);
+extern double remainder(double, double);
+extern double rint(double);
+extern int unordered(double, double);
+extern int finite(double);
+
+extern long double scalbl(long double, long double);
+extern long double logbl(long double);
+extern long double nextafterl(long double, long double);
+extern int unorderedl(long double, long double);
+extern int finitel(long double);
+
+
+
+
+extern int signgam;
+
+#define M_E 2.7182818284590452354
+#define M_LOG2E 1.4426950408889634074
+#define M_LOG10E 0.43429448190325182765
+#define M_LN2 0.69314718055994530942
+#define M_LN10 2.30258509299404568402
+#define M_PI 3.14159265358979323846
+#define M_PI_2 1.57079632679489661923
+#define M_PI_4 0.78539816339744830962
+#define M_1_PI 0.31830988618379067154
+#define M_2_PI 0.63661977236758134308
+#define M_2_SQRTPI 1.12837916709551257390
+#define M_SQRT2 1.41421356237309504880
+#define M_SQRT1_2 0.70710678118654752440
+
+
+
+#define _ABS(x) ((x) < 0 ? -(x) : (x))
+
+#define _REDUCE(TYPE, X, XN, C1, C2) { \
+ double x1 = (double)(TYPE)X, x2 = X - x1; \
+ X = x1 - (XN) * (C1); X += x2; X -= (XN) * (C2); }
+
+#define DOMAIN 1
+#define SING 2
+#define OVERFLOW 3
+#define UNDERFLOW 4
+#define TLOSS 5
+#define PLOSS 6
+
+#define _POLY1(x, c) ((c)[0] * (x) + (c)[1])
+#define _POLY2(x, c) (_POLY1((x), (c)) * (x) + (c)[2])
+#define _POLY3(x, c) (_POLY2((x), (c)) * (x) + (c)[3])
+#define _POLY4(x, c) (_POLY3((x), (c)) * (x) + (c)[4])
+#define _POLY5(x, c) (_POLY4((x), (c)) * (x) + (c)[5])
+#define _POLY6(x, c) (_POLY5((x), (c)) * (x) + (c)[6])
+#define _POLY7(x, c) (_POLY6((x), (c)) * (x) + (c)[7])
+#define _POLY8(x, c) (_POLY7((x), (c)) * (x) + (c)[8])
+#define _POLY9(x, c) (_POLY8((x), (c)) * (x) + (c)[9])
+
+
+#ifdef __cplusplus
+}
+inline int sqr(int i) {return(i*i);}
+inline double sqr(double i) {return(i*i);}
+
+#endif /* __cplusplus */
+
+#pragma pack()
+
+#if __cplusplus && !defined(PI)
+#define PI M_PI
+#endif /* __cplusplus */
+
+#endif /* _MATH_H */
+#endif
diff --git a/mit-pthreads/machdep/sco-3.2v5/__signal.h b/mit-pthreads/machdep/sco-3.2v5/__signal.h
new file mode 100755
index 00000000000..6a33d37a261
--- /dev/null
+++ b/mit-pthreads/machdep/sco-3.2v5/__signal.h
@@ -0,0 +1,109 @@
+/* Copyright 1994-1995 The Santa Cruz Operation, Inc. All Rights Reserved. */
+
+
+#if defined(_NO_PROTOTYPE) /* Old, crufty environment */
+#include <sys/oldstyle/signal.h>
+#elif defined(_XOPEN_SOURCE) || defined(_XPG4_VERS) /* Xpg4 environment */
+#include <xpg4/signal.h>
+#elif defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) /* Posix environment */
+#include <sys/posix/__signal.h>
+#elif _STRICT_ANSI /* Pure Ansi/ISO environment */
+#include <sys/ansi/signal.h>
+#elif defined(_SCO_ODS_30) /* Old, Tbird compatible environment */
+#include <sys/ods_30_compat/signal.h>
+#else /* Normal, default environment */
+/*
+ * Portions Copyright (C) 1983-1995 The Santa Cruz Operation, Inc.
+ * All Rights Reserved.
+ *
+ * The information in this file is provided for the exclusive use of
+ * the licensees of The Santa Cruz Operation, Inc. Such users have the
+ * right to use, modify, and incorporate this code into other products
+ * for purposes authorized by the license agreement provided they include
+ * this notice and the associated copyright notice with any such product.
+ * The information in this file is provided "AS IS" without warranty.
+ */
+
+/* Portions Copyright (c) 1990, 1991, 1992, 1993 UNIX System Laboratories, Inc. */
+/* Portions Copyright (c) 1979 - 1990 AT&T */
+/* All Rights Reserved */
+
+/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF */
+/* UNIX System Laboratories, Inc. */
+/* The copyright notice above does not evidence any */
+/* actual or intended publication of such source code. */
+
+#ifndef ___SIGNAL_H
+#define ___SIGNAL_H
+
+#pragma comment(exestr, "xpg4plus @(#) signal.h 20.3 94/12/19 ")
+
+#ifndef _SIG_ATOMIC_T
+#define _SIG_ATOMIC_T
+ /* atomic entity for signal handling */
+typedef int sig_atomic_t;
+#endif
+
+extern const char * const _sys_siglist[];
+extern const int _sys_nsig;
+
+#ifndef _SYS_SIGNAL_H
+#include <sys/signal.h>
+#endif
+
+#define SignalBad ((SignalHandler)-1)
+#define SignalDefault ((SignalHandler)0)
+#define SignalIgnore ((SignalHandler)1)
+
+#define __sigmask(sig) (1 << ((sig) - 1))
+#define __SIGEMPTYSET (~SIGALL)
+#define __SIGFILLSET SIGALL
+#define __SIGADDSET(s,n) ((*s) |= (__sigmask(n)))
+#define __SIGDELSET(s,n) ((*s) &= ~(__sigmask(n)))
+#define __SIGISMEMBER(s,n) ((*s) & (__sigmask(n)))
+
+#if !defined(_SYS_TYPES_H)
+#include <sys/types.h>
+#endif
+
+
+#if __cplusplus
+extern "C" {
+#endif
+
+extern void (*signal(int, void(*)(int)))(int);
+extern int raise(int);
+
+extern void (*bsd_signal(int, void(*)(int)))(int);
+extern int ( *ssignal( int, int(*)(int) ) )(int);
+extern void ( *sigset( int, void(*)(int) ) )(int);
+extern int killpg(pid_t, int);
+#ifdef SS_ONSTACK /* Not defined on old versions of the OS */
+extern int sigaltstack(const stack_t *, stack_t *);
+extern int sigstack(struct sigstack *, struct sigstack *);
+#endif
+extern int sighold(int);
+extern int sigignore(int);
+extern int siginterrupt(int, int);
+extern int sigpause(int);
+extern int sigrelse(int);
+
+extern int (sigfillset)(sigset_t *);
+extern int (sigemptyset)(sigset_t *);
+extern int (sigaddset)(sigset_t *, int);
+extern int (sigdelset)(sigset_t *, int);
+extern int (sigismember)(const sigset_t *, int);
+extern int sigpending(sigset_t *);
+extern int sigsuspend(const sigset_t *);
+extern int sigprocmask(int, const sigset_t *, sigset_t *);
+extern int kill(pid_t, int);
+extern int sigaction(int, const struct sigaction *, struct sigaction *);
+
+#if __cplusplus
+};
+#endif
+
+
+#endif /* ___SIGNAL_H */
+
+#endif
diff --git a/mit-pthreads/machdep/sco-3.2v5/__stdio.h b/mit-pthreads/machdep/sco-3.2v5/__stdio.h
new file mode 100755
index 00000000000..f19672980ec
--- /dev/null
+++ b/mit-pthreads/machdep/sco-3.2v5/__stdio.h
@@ -0,0 +1,113 @@
+/* Copyright 1994-1995 The Santa Cruz Operation, Inc. All Rights Reserved. */
+
+
+#if defined(_NO_PROTOTYPE) /* Old, crufty environment */
+#include <oldstyle/__stdio.h>
+#elif defined(_XOPEN_SOURCE) || defined(_XPG4_VERS) /* Xpg4 environment */
+#include <xpg4/__stdio.h>
+#elif defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) /* Posix environment */
+#include <posix/__stdio.h>
+#elif _STRICT_ANSI /* Pure Ansi/ISO environment */
+#include <ansi/__stdio.h>
+#elif defined(_SCO_ODS_30) /* Old, Tbird compatible environment */
+#include <ods_30_compat/__stdio.h>
+#else /* Normal, default environment */
+/*
+ * Portions Copyright (C) 1984-1995 The Santa Cruz Operation, Inc.
+ * All Rights Reserved.
+ *
+ * The information in this file is provided for the exclusive use of
+ * the licensees of The Santa Cruz Operation, Inc. Such users have the
+ * right to use, modify, and incorporate this code into other products
+ * for purposes authorized by the license agreement provided they include
+ * this notice and the associated copyright notice with any such product.
+ * The information in this file is provided "AS IS" without warranty.
+ */
+
+/* Portions Copyright (c) 1990, 1991, 1992, 1993 UNIX System Laboratories, Inc. */
+/* Portions Copyright (c) 1979 - 1990 AT&T */
+/* All Rights Reserved */
+
+/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF */
+/* UNIX System Laboratories, Inc. */
+/* The copyright notice above does not evidence any */
+/* actual or intended publication of such source code. */
+
+#ifndef ___STDIO_H
+#define ___STDIO_H
+
+#pragma comment(exestr, "xpg4plus @(#) stdio.h 20.1 94/12/04 ")
+
+#pragma pack(4)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef _SIZE_T
+#define _SIZE_T
+typedef unsigned int size_t;
+#endif
+
+#ifndef _FPOS_T
+#define _FPOS_T
+typedef long fpos_t;
+#endif
+
+#ifndef _WCHAR_T
+#define _WCHAR_T
+typedef long wchar_t;
+#endif
+
+#ifndef _WINT_T
+#define _WINT_T
+typedef long wint_t;
+#endif
+
+#ifndef NULL
+#define NULL 0
+#endif /* NULL */
+
+#ifndef EOF
+#define EOF (-1)
+#endif
+
+#define SEEK_SET 0
+#define SEEK_CUR 1
+#define SEEK_END 2
+
+#ifndef TMP_MAX
+#define TMP_MAX 17576 /* 26 * 26 * 26 */
+#endif
+
+#define BUFSIZ 1024 /* default buffer size */
+
+
+#define _IOEOF 0020 /* EOF reached on read */
+#define _IOERR 0040 /* I/O error from system */
+
+#define _IOREAD 0001 /* currently reading */
+#define _IOWRT 0002 /* currently writing */
+#define _IORW 0200 /* opened for reading and writing */
+#define _IOMYBUF 0010 /* stdio malloc()'d buffer */
+
+#define _SBFSIZ 8
+
+#define L_cuserid 9
+
+/* Non name space polluting version of above */
+#define _P_tmpdir "/usr/tmp/"
+
+#ifndef _VA_LIST
+#define _VA_LIST char *
+#endif
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#pragma pack()
+
+#endif /* ___STDIO_H */
+#endif
diff --git a/mit-pthreads/machdep/sco-3.2v5/__stdlib.h b/mit-pthreads/machdep/sco-3.2v5/__stdlib.h
new file mode 100755
index 00000000000..db6a8a56151
--- /dev/null
+++ b/mit-pthreads/machdep/sco-3.2v5/__stdlib.h
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 1984-1995 The Santa Cruz Operation, Inc.
+ * All Rights Reserved.
+ *
+ * The information in this file is provided for the exclusive use of
+ * the licensees of The Santa Cruz Operation, Inc. Such users have the
+ * right to use, modify, and incorporate this code into other products
+ * for purposes authorized by the license agreement provided they include
+ * this notice and the associated copyright notice with any such product.
+ * The information in this file is provided "AS IS" without warranty.
+ */
+
+/* Portions Copyright (c) 1990, 1991, 1992, 1993 UNIX System Laboratories, Inc. */
+/* Portions Copyright (c) 1979 - 1990 AT&T */
+/* All Rights Reserved */
+
+/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF */
+/* UNIX System Laboratories, Inc. */
+/* The copyright notice above does not evidence any */
+/* actual or intended publication of such source code. */
+
+#ifndef ___STDLIB_H
+#define ___STDLIB_H
+
+#pragma comment(exestr, "posix @(#) stdlib.h 20.1 94/12/04 ")
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#pragma pack(4)
+
+#ifndef _DIV_T
+#define _DIV_T
+typedef struct
+{
+ int quot;
+ int rem;
+} div_t;
+#endif
+
+#ifndef _LDIV_T
+#define _LDIV_T
+typedef struct
+{
+ long quot;
+ long rem;
+} ldiv_t;
+#endif
+
+#ifndef _SIZE_T
+#define _SIZE_T
+typedef unsigned int size_t;
+#endif
+
+#if !defined(_SSIZE_T)
+#define _SSIZE_T
+typedef int ssize_t;
+#endif
+
+#ifndef _WCHAR_T
+#define _WCHAR_T
+typedef long wchar_t;
+#endif
+
+#ifndef NULL
+#define NULL 0
+#endif /* NULL */
+
+#define EXIT_FAILURE 1
+#define EXIT_SUCCESS 0
+#define RAND_MAX 077777
+
+
+
+extern unsigned char __ctype[];
+
+#define MB_CUR_MAX ((int)__ctype[520])
+
+extern double atof(const char *);
+extern int atoi(const char *);
+extern long atol(const char *);
+extern double strtod(const char *, char **);
+extern float strtof(const char *, char **);
+extern long strtol(const char *, char **, int);
+extern unsigned long strtoul(const char *, char **, int);
+
+extern int rand(void);
+extern void srand(unsigned int);
+
+extern void *calloc(size_t, size_t);
+extern void free(void *);
+extern void *malloc(size_t);
+extern void *realloc(void *, size_t);
+
+extern void abort(void);
+extern void exit(int);
+extern char *getenv(const char *);
+extern int system(const char *);
+
+extern void *bsearch(const void *, const void *, size_t, size_t,
+ int (*)(const void *, const void *));
+extern void qsort(void *, size_t, size_t,
+ int (*)(const void *, const void *));
+
+#ifdef __cplusplus
+#ifndef _ABS_INL
+#define _ABS_INL
+inline int (abs)(int i) {return (i > 0) ? i : -i;}
+#endif
+#else
+extern int (abs)(int); /* Protect from macro definitions */
+#endif
+
+extern div_t div(int, int);
+extern long labs(long);
+extern ldiv_t ldiv(long, long);
+
+extern int mbtowc(wchar_t *, const char *, size_t);
+extern int mblen(const char *, size_t);
+extern int wctomb(char *, wchar_t);
+
+extern size_t mbstowcs(wchar_t *, const char *, size_t);
+extern size_t wcstombs(char *, const wchar_t *, size_t);
+
+
+
+
+#define mblen(s, n) mbtowc((wchar_t *)0, s, n)
+
+#ifdef __cplusplus
+}
+#endif
+
+#pragma pack()
+
+#endif /* ___STDLIB_H */
diff --git a/mit-pthreads/machdep/sco-3.2v5/__string.h b/mit-pthreads/machdep/sco-3.2v5/__string.h
new file mode 100755
index 00000000000..e4bb93afe5a
--- /dev/null
+++ b/mit-pthreads/machdep/sco-3.2v5/__string.h
@@ -0,0 +1,125 @@
+/* Copyright 1994-1995 The Santa Cruz Operation, Inc. All Rights Reserved. */
+
+
+#if defined(_NO_PROTOTYPE) /* Old, crufty environment */
+#include <oldstyle/string.h>
+#elif defined(_XOPEN_SOURCE) || defined(_XPG4_VERS) /* Xpg4 environment */
+#include <xpg4/string.h>
+#elif defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) /* Posix environment */
+#include <posix/string.h>
+#elif _STRICT_ANSI /* Pure Ansi/ISO environment */
+#include <ansi/string.h>
+#elif defined(_SCO_ODS_30) /* Old, Tbird compatible environment */
+#include <ods_30_compat/string.h>
+#else /* Normal, default environment */
+/*
+ * Portions Copyright (C) 1983-1995 The Santa Cruz Operation, Inc.
+ * All Rights Reserved.
+ *
+ * The information in this file is provided for the exclusive use of
+ * the licensees of The Santa Cruz Operation, Inc. Such users have the
+ * right to use, modify, and incorporate this code into other products
+ * for purposes authorized by the license agreement provided they include
+ * this notice and the associated copyright notice with any such product.
+ * The information in this file is provided "AS IS" without warranty.
+ */
+
+/* Portions Copyright (c) 1990, 1991, 1992, 1993 UNIX System Laboratories, Inc. */
+/* Portions Copyright (c) 1979 - 1990 AT&T */
+/* All Rights Reserved */
+
+/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF */
+/* UNIX System Laboratories, Inc. */
+/* The copyright notice above does not evidence any */
+/* actual or intended publication of such source code. */
+
+#ifndef ___STRING_H
+#define ___STRING_H
+
+#pragma comment(exestr, "xpg4plus @(#) string.h 20.1 94/12/04 ")
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef _SIZE_T
+#define _SIZE_T
+typedef unsigned int size_t;
+#endif
+
+#ifndef NULL
+#define NULL 0
+#endif /* NULL */
+
+
+
+extern void *memchr(const void *, int, size_t);
+extern void *memcpy(void *, const void *, size_t);
+extern void *memccpy(void *, const void *, int, size_t);
+extern void *memmove(void *, const void *, size_t);
+extern void *memset(void *, int, size_t);
+
+extern char *strchr(const char *, int);
+extern char *strcpy(char *, const char *);
+extern char *strncpy(char *, const char *, size_t);
+extern char *strcat(char *, const char *);
+extern char *strncat(char *, const char *, size_t);
+extern char *strpbrk(const char *, const char *);
+extern char *strrchr(const char *, int);
+extern char *strstr(const char *, const char *);
+extern char *strtok(char *, const char *);
+extern char *strtok_r(char *, const char *, char **);
+extern char *strerror(int);
+extern char *strlist(char *, const char *, ...);
+
+extern int memcmp(const void *, const void *, size_t);
+extern int strcmp(const char *, const char *);
+extern int strcoll(const char *, const char *);
+extern int strncmp(const char *, const char *, size_t);
+
+extern void perror(const char *);
+extern char *strdup(const char *);
+extern int strncoll(const char *, const char *, int);
+extern size_t strnxfrm(char *, const char *, size_t , int);
+
+extern size_t strxfrm(char *, const char *, size_t);
+extern size_t strcspn(const char *, const char *);
+extern size_t strspn(const char *, const char *);
+extern size_t strlen(const char *);
+
+#ifdef __USLC__
+#pragma int_to_unsigned strcspn
+#pragma int_to_unsigned strspn
+#pragma int_to_unsigned strlen
+#endif
+
+#if !defined(__cplusplus) && defined(__USLC__)
+/* Use intrinsic ??? */
+#ifndef strlen
+#define strlen __std_hdr_strlen
+#endif
+#ifndef strcpy
+#define strcpy __std_hdr_strcpy
+#endif
+#ifndef strncpy
+#define strncpy __std_hdr_strncpy
+#endif
+#endif
+
+
+extern int ffs(int);
+/*
+ * The following two functions were withdrawn in XPG3,
+ * but are provided for backwards compatibility.
+ */
+extern int nl_strcmp(char *, char *);
+extern int nl_strncmp(char *, char *, int n);
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ___STRING_H */
+#endif
diff --git a/mit-pthreads/machdep/sco-3.2v5/__time.h b/mit-pthreads/machdep/sco-3.2v5/__time.h
new file mode 100755
index 00000000000..4aeee737601
--- /dev/null
+++ b/mit-pthreads/machdep/sco-3.2v5/__time.h
@@ -0,0 +1,141 @@
+/* Copyright 1994-1995 The Santa Cruz Operation, Inc. All Rights Reserved. */
+
+
+#if defined(_NO_PROTOTYPE) /* Old, crufty environment */
+#include <oldstyle/time.h>
+#elif defined(_XOPEN_SOURCE) || defined(_XPG4_VERS) /* Xpg4 environment */
+#include <xpg4/time.h>
+#elif defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) /* Posix environment */
+#include <posix/time.h>
+#elif _STRICT_ANSI /* Pure Ansi/ISO environment */
+#include <ansi/time.h>
+#elif defined(_SCO_ODS_30) /* Old, Tbird compatible environment */
+#include <ods_30_compat/time.h>
+#else /* Normal, default environment */
+/*
+ * Portions Copyright (C) 1983-1995 The Santa Cruz Operation, Inc.
+ * All Rights Reserved.
+ *
+ * The information in this file is provided for the exclusive use of
+ * the licensees of The Santa Cruz Operation, Inc. Such users have the
+ * right to use, modify, and incorporate this code into other products
+ * for purposes authorized by the license agreement provided they include
+ * this notice and the associated copyright notice with any such product.
+ * The information in this file is provided "AS IS" without warranty.
+ */
+
+/* Portions Copyright (c) 1990, 1991, 1992, 1993 UNIX System Laboratories, Inc. */
+/* Portions Copyright (c) 1979 - 1990 AT&T */
+/* All Rights Reserved */
+
+/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF */
+/* UNIX System Laboratories, Inc. */
+/* The copyright notice above does not evidence any */
+/* actual or intended publication of such source code. */
+
+#ifndef ___TIME_H
+#define ___TIME_H
+
+#pragma comment(exestr, "xpg4plus @(#) time.h 20.2 95/01/04 ")
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef NULL
+#define NULL 0
+#endif /* NULL */
+
+#ifndef _SIZE_T
+#define _SIZE_T
+typedef unsigned int size_t;
+#endif
+#ifndef _CLOCK_T
+#define _CLOCK_T
+typedef long clock_t;
+#endif
+#ifndef _TIME_T
+#define _TIME_T
+typedef long time_t;
+#endif
+
+#ifdef _POSIXTIMERS
+#include <sys/sudstime.h>
+#endif
+
+#define CLOCKS_PER_SEC 1000000 /* As required by XPG4 and friends */
+
+#pragma pack(4)
+
+#ifndef _STRUCT_TM
+#define _STRUCT_TM
+struct tm
+{
+ int tm_sec;
+ int tm_min;
+ int tm_hour;
+ int tm_mday;
+ int tm_mon;
+ int tm_year;
+ int tm_wday;
+ int tm_yday;
+ int tm_isdst;
+#define LTZNMAX 50
+ long tm_tzadj;
+ char tm_name[LTZNMAX]; /* name of timezone */
+};
+
+#pragma pack()
+#endif /* _STRUCT_TM */
+
+
+extern clock_t clock(void);
+extern double difftime(time_t, time_t);
+extern time_t mktime(struct tm *);
+extern time_t time(time_t *);
+extern char *asctime(const struct tm *);
+extern char *ctime (const time_t *);
+extern struct tm *gmtime(const time_t *);
+extern struct tm *localtime(const time_t *);
+extern size_t strftime(char *, size_t, const char *, const struct tm *);
+
+
+extern void tzset(void);
+extern char *tzname[];
+
+#ifndef CLK_TCK
+#define CLK_TCK _sysconf(2) /* 2 is _SC_CLK_TCK */
+#endif
+
+extern long timezone;
+extern int daylight;
+extern char *strptime(const char *, const char *, struct tm *);
+
+
+
+
+#include <sys/timeb.h>
+extern int ftime ( struct timeb * );
+extern char * nl_cxtime( long *, char * );
+extern char * nl_ascxtime( struct tm *, char * );
+extern int cftime(char *, const char *, const time_t *);
+extern int ascftime(char *, const char *, const struct tm *);
+extern long altzone;
+extern struct tm *getdate(const char *);
+extern int getdate_err;
+extern char *asctime_r(const struct tm *, char *,int);
+extern char *ctime_r(const time_t *, char *,int);
+extern struct tm *localtime_r(const time_t *, struct tm *);
+extern struct tm *gmtime_r(const time_t *, struct tm *);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#ifndef difftime
+#define difftime(t1, t0) ((double)((t1) - (t0)))
+#endif
+
+#endif /* ___TIME_H */
+#endif
diff --git a/mit-pthreads/machdep/sco-3.2v5/__unistd.h b/mit-pthreads/machdep/sco-3.2v5/__unistd.h
new file mode 100755
index 00000000000..408886301f5
--- /dev/null
+++ b/mit-pthreads/machdep/sco-3.2v5/__unistd.h
@@ -0,0 +1,48 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)stdlib.h 5.13 (Berkeley) 6/4/91
+ * __unistd.h,v 1.1 1995/01/03 12:54:54 proven Exp
+ */
+
+#ifndef ___UNISTD_H_
+#define ___UNISTD_H_
+
+#include <sys/types.h>
+#include <stddef.h>
+
+#ifndef MAXPATHLEN
+#define MAXPATHLEN 1024
+#endif
+
+#endif
+
diff --git a/mit-pthreads/machdep/sco-3.2v5/compat.h b/mit-pthreads/machdep/sco-3.2v5/compat.h
new file mode 100755
index 00000000000..3befbffa68d
--- /dev/null
+++ b/mit-pthreads/machdep/sco-3.2v5/compat.h
@@ -0,0 +1,46 @@
+/* ==== compat.h ============================================================
+ * Copyright (c) 1994 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * compat.h,v 1.52 1995/10/20 09:32:56 proven Exp
+ *
+ * Description : Basic timers header.
+ *
+ * 1.00 94/06/13 proven
+ * -Started coding this file.
+ */
+
+#ifndef _SYS_COMPAT_H_
+#define _SYS_COMPAT_H_
+
+#include <sys/types.h>
+
+#define omsghdr msghdr
+#endif
diff --git a/mit-pthreads/machdep/sco-3.2v5/dirent.h b/mit-pthreads/machdep/sco-3.2v5/dirent.h
new file mode 100755
index 00000000000..6f6804590bb
--- /dev/null
+++ b/mit-pthreads/machdep/sco-3.2v5/dirent.h
@@ -0,0 +1,145 @@
+/* Copyright 1994-1995 The Santa Cruz Operation, Inc. All Rights Reserved. */
+
+
+#if defined(_NO_PROTOTYPE) /* Old, crufty environment */
+#include <oldstyle/dirent.h>
+#elif defined(_XOPEN_SOURCE) || defined(_XPG4_VERS) /* Xpg4 environment */
+#include <xpg4/dirent.h>
+#elif defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) /* Posix environment */
+#include <posix/dirent.h>
+#elif defined(_SCO_ODS_30) /* Old, Tbird compatible environment */
+#include <ods_30_compat/dirent.h>
+#else /* Normal, default environment */
+/*
+ * Portions Copyright (C) 1983-1995 The Santa Cruz Operation, Inc.
+ * All Rights Reserved.
+ *
+ * The information in this file is provided for the exclusive use of
+ * the licensees of The Santa Cruz Operation, Inc. Such users have the
+ * right to use, modify, and incorporate this code into other products
+ * for purposes authorized by the license agreement provided they include
+ * this notice and the associated copyright notice with any such product.
+ * The information in this file is provided "AS IS" without warranty.
+ */
+
+/* Portions Copyright (c) 1990, 1991, 1992, 1993 UNIX System Laboratories, Inc. */
+/* Portions Copyright (c) 1979 - 1990 AT&T */
+/* All Rights Reserved */
+
+/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF */
+/* UNIX System Laboratories, Inc. */
+/* The copyright notice above does not evidence any */
+/* actual or intended publication of such source code. */
+
+#ifndef _DIRENT_H
+#define _DIRENT_H
+
+#pragma comment(exestr, "xpg4plus @(#) dirent.h 20.1 94/12/04 ")
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#pragma pack(4)
+
+#define MAXNAMLEN 512 /* maximum filename length */
+#ifndef MAXPATHLEN
+#define MAXPATHLEN 1024
+#endif
+#undef DIRBLKSIZ
+#define DIRBLKSIZ 1048 /* buffer size for fs-indep. dirs */
+
+#ifndef _SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#ifndef _SYS_DIRENT_H
+#define _SYS_DIRENT_H
+#ifdef __STDC__
+#pragma comment(exestr, "@(#) dirent.h 25.8 94/09/22 ")
+#else
+#ident "@(#) dirent.h 25.8 94/09/22 "
+#endif
+/*
+ * Copyright (C) 1988-1994 The Santa Cruz Operation, Inc.
+ * All Rights Reserved.
+ * The information in this file is provided for the exclusive use of
+ * the licensees of The Santa Cruz Operation, Inc. Such users have the
+ * right to use, modify, and incorporate this code into other products
+ * for purposes authorized by the license agreement provided they include
+ * this notice and the associated copyright notice with any such product.
+ * The information in this file is provided "AS IS" without warranty.
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988 AT&T */
+/* All Rights Reserved */
+
+/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T */
+/* The copyright notice above does not evidence any */
+/* actual or intended publication of such source code. */
+
+/* #ident "@)#(head.sys:dirent.h 1.3" */
+
+/*
+ * The following structure defines the file
+ * system independent directory entry.
+ *
+ */
+
+#include <sys/types.h>
+
+#ifdef _M_I386
+#pragma pack(4)
+#else
+#pragma pack(2)
+#endif
+
+#ifdef _INKERNEL
+/*
+ * dirent used by the kernel
+ */
+struct dirent {
+ ino32_t d_ino; /* inode number of entry */
+ off_t d_off; /* offset of disk directory entry */
+ unsigned short d_reclen; /* length of this record */
+ char d_name[MAXNAMLEN+1]; /* name of file */
+};
+
+#else /* !_INKERNEL */
+/*
+ * dirent as used by application code
+ * For now leave the declaration as is. When the new development system
+ * is implemented, ino_t may be ushort or ulong. If ino_t is ulong, there
+ * will be no d_pad field.
+ */
+struct dirent /* data from readdir() */
+ {
+#if defined(_IBCS2)
+ long d_ino;
+#else /* !_IBCS2 */
+ ino_t d_ino; /* inode number of entry */
+#if defined(_INO_16_T)
+ short d_pad; /* because ino_t is ushort */
+#endif /* defined(_INO_16_T) */
+#endif /* defined(_IBCS2) */
+ off_t d_off; /* offset of disk directory entry */
+ unsigned short d_reclen; /* length of this record */
+ char d_name[MAXNAMLEN+1]; /* name of file */
+ };
+#endif /* _INKERNEL */
+
+typedef struct dirent dirent_t;
+
+#pragma pack()
+#endif /* _SYS_DIRENT_H */
+
+#define d_fileno d_ino
+#define d_namlen d_reclen
+
+#ifdef __cplusplus
+}
+#endif
+
+#pragma pack()
+
+#endif /* _DIRENT_H */
+#endif
diff --git a/mit-pthreads/machdep/sco-3.2v5/posix/__signal.h b/mit-pthreads/machdep/sco-3.2v5/posix/__signal.h
new file mode 100755
index 00000000000..5680fc1491a
--- /dev/null
+++ b/mit-pthreads/machdep/sco-3.2v5/posix/__signal.h
@@ -0,0 +1,69 @@
+/*
+ * Portions Copyright (C) 1983-1995 The Santa Cruz Operation, Inc.
+ * All Rights Reserved.
+ *
+ * The information in this file is provided for the exclusive use of
+ * the licensees of The Santa Cruz Operation, Inc. Such users have the
+ * right to use, modify, and incorporate this code into other products
+ * for purposes authorized by the license agreement provided they include
+ * this notice and the associated copyright notice with any such product.
+ * The information in this file is provided "AS IS" without warranty.
+ */
+
+/* Portions Copyright (c) 1990, 1991, 1992, 1993 UNIX System Laboratories, Inc. */
+/* Portions Copyright (c) 1979 - 1990 AT&T */
+/* All Rights Reserved */
+
+/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF */
+/* UNIX System Laboratories, Inc. */
+/* The copyright notice above does not evidence any */
+/* actual or intended publication of such source code. */
+
+#ifndef ___SIGNAL_H
+#define ___SIGNAL_H
+
+#pragma comment(exestr, "posix @(#) signal.h 20.3 94/12/19 ")
+
+#ifndef _SIG_ATOMIC_T
+#define _SIG_ATOMIC_T
+ /* atomic entity for signal handling */
+typedef int sig_atomic_t;
+#endif
+
+
+#ifndef _SYS_SIGNAL_H
+#include <sys/signal.h>
+#endif
+
+#if !defined(_SYS_TYPES_H)
+#include <sys/types.h>
+#endif
+
+
+#if __cplusplus
+extern "C" {
+#endif
+
+extern void (*signal(int, void(*)(int)))(int);
+extern int raise(int);
+
+
+
+extern int (sigfillset)(sigset_t *);
+extern int (sigemptyset)(sigset_t *);
+extern int (sigaddset)(sigset_t *, int);
+extern int (sigdelset)(sigset_t *, int);
+extern int (sigismember)(const sigset_t *, int);
+extern int sigpending(sigset_t *);
+extern int sigsuspend(const sigset_t *);
+extern int sigprocmask(int, const sigset_t *, sigset_t *);
+extern int kill(pid_t, int);
+extern int sigaction(int, const struct sigaction *, struct sigaction *);
+
+#if __cplusplus
+};
+#endif
+
+
+#endif /* ___SIGNAL_H */
+
diff --git a/mit-pthreads/machdep/sco-3.2v5/socket.h b/mit-pthreads/machdep/sco-3.2v5/socket.h
new file mode 100755
index 00000000000..4a53c7176f9
--- /dev/null
+++ b/mit-pthreads/machdep/sco-3.2v5/socket.h
@@ -0,0 +1,490 @@
+/* @(#)socket.h 6.23 7/18/94 - STREAMware TCP/IP source */
+/*
+ * Copyrighted as an unpublished work.
+ * (c) Copyright 1987-1994 Legent Corporation
+ * All rights reserved.
+ *
+ * RESTRICTED RIGHTS
+ *
+ * These programs are supplied under a license. They may be used,
+ * disclosed, and/or copied only as permitted under such license
+ * agreement. Any copy must contain the above copyright notice and
+ * this restricted rights notice. Use, copying, and/or disclosure
+ * of the programs is strictly prohibited unless otherwise provided
+ * in the license agreement.
+ *
+ */
+/* SCCS IDENTIFICATION */
+/*
+ * Copyright (c) 1985 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef __sys_socket_h
+#define __sys_socket_h
+
+#if !defined(FD_SETSIZE)
+/* Pick up select stuff from standard system include */
+#include <sys/types.h>
+#endif
+
+/* socket.h 6.1 83/07/29 */
+
+/*
+ * Definitions related to sockets: types, address families, options.
+ */
+
+/*
+ * Types
+ */
+#define SOCK_STREAM 1 /* stream socket */
+#define SOCK_DGRAM 2 /* datagram socket */
+#define SOCK_RAW 3 /* raw-protocol interface */
+#define SOCK_RDM 4 /* reliably-delivered message */
+#define SOCK_SEQPACKET 5 /* sequenced packet stream */
+
+/*
+ * Option flags per-socket.
+ */
+#define SO_DEBUG 0x0001 /* turn on debugging info recording */
+#define SO_ACCEPTCONN 0x0002 /* socket has had listen() */
+#define SO_REUSEADDR 0x0004 /* allow local address reuse */
+#define SO_KEEPALIVE 0x0008 /* keep connections alive */
+#define SO_DONTROUTE 0x0010 /* just use interface addresses */
+#define SO_BROADCAST 0x0020 /* permit sending of broadcast msgs */
+#define SO_USELOOPBACK 0x0040 /* bypass hardware when possible */
+#define SO_LINGER 0x0080 /* linger on close if data present */
+#define SO_OOBINLINE 0x0100 /* leave received OOB data in line */
+#define SO_ORDREL 0x0200 /* give use orderly release */
+#define SO_IMASOCKET 0x0400 /* use socket semantics (affects bind) */
+#define SO_MGMT 0x0800 /* => it is used for mgmt. purposes */
+#define SO_REUSEPORT 0x1000 /* allow local port reuse */
+
+/*
+ * Additional options, not kept in so_options.
+ */
+#define SO_SNDBUF 0x1001 /* send buffer size */
+#define SO_RCVBUF 0x1002 /* receive buffer size */
+#define SO_SNDLOWAT 0x1003 /* send low-water mark */
+#define SO_RCVLOWAT 0x1004 /* receive low-water mark */
+#define SO_SNDTIMEO 0x1005 /* send timeout */
+#define SO_RCVTIMEO 0x1006 /* receive timeout */
+#define SO_ERROR 0x1007 /* get error status and clear */
+#define SO_TYPE 0x1008 /* get socket type */
+#define SO_PROTOTYPE 0x1009 /* get/set protocol type */
+
+/*
+ * Structure used for manipulating linger option.
+ */
+struct linger {
+ int l_onoff; /* option on/off */
+ int l_linger; /* linger time */
+};
+
+/*
+ * Level number for (get/set)sockopt() to apply to socket itself.
+ */
+#define SOL_SOCKET 0xffff /* options for socket level */
+
+/*
+ * An option specification consists of an opthdr, followed by the value of
+ * the option. An options buffer contains one or more options. The len
+ * field of opthdr specifies the length of the option value in bytes. This
+ * length must be a multiple of sizeof(long) (use OPTLEN macro).
+ */
+
+struct opthdr {
+ long level; /* protocol level affected */
+ long name; /* option to modify */
+ long len; /* length of option value */
+};
+
+#define OPTLEN(x) ((((x) + sizeof(long) - 1) / sizeof(long)) * sizeof(long))
+#define OPTVAL(opt) ((char *)(opt + 1))
+
+#if defined(INKERNEL) || defined(_KERNEL) || defined(_INKERNEL)
+/*
+ * the optdefault structure is used for internal tables of option default
+ * values.
+ */
+struct optdefault {
+ int optname;/* the option */
+ char *val; /* ptr to default value */
+ int len; /* length of value */
+};
+
+/*
+ * the opproc structure is used to build tables of options processing
+ * functions for in_dooptions().
+ */
+struct opproc {
+ int level; /* options level this function handles */
+ int (*func) (); /* the function */
+};
+#endif
+
+/*
+ * Address families.
+ */
+#define AF_UNSPEC 0 /* unspecified */
+#define AF_UNIX 1 /* local to host (pipes, portals) */
+#define AF_INET 2 /* internetwork: UDP, TCP, etc. */
+#define AF_IMPLINK 3 /* arpanet imp addresses */
+#define AF_PUP 4 /* pup protocols: e.g. BSP */
+#define AF_CHAOS 5 /* mit CHAOS protocols */
+#define AF_NS 6 /* XEROX NS protocols */
+#define AF_ISO 7 /* ISO protocols */
+#define AF_OSI AF_ISO
+#define AF_ECMA 8 /* european computer manufacturers */
+#define AF_DATAKIT 9 /* datakit protocols */
+#define AF_CCITT 10 /* CCITT protocols, X.25 etc */
+#define AF_SNA 11 /* IBM SNA */
+#define AF_DECnet 12 /* DECnet */
+#define AF_DLI 13 /* Direct data link interface */
+#define AF_LAT 14 /* LAT */
+#define AF_HYLINK 15 /* NSC Hyperchannel */
+#define AF_APPLETALK 16 /* Apple Talk */
+#define AF_ROUTE 17 /* Internal Routing Protocol */
+#define AF_LINK 18 /* Link layer interface */
+#define pseudo_AF_XTP 19 /* eXpress Transfer Protocol (no AF) */
+
+#define AF_MAX 20
+
+/*
+ * Structure used by kernel to store most addresses.
+ */
+struct sockaddr {
+ u_short sa_family; /* address family */
+ char sa_data[14]; /* up to 14 bytes of direct address */
+};
+
+/*
+ * Structure used by kernel to pass protocol information in raw sockets.
+ */
+struct sockproto {
+ unsigned short sp_family; /* address family */
+ unsigned short sp_protocol; /* protocol */
+};
+
+/*
+ * Protocol families, same as address families for now.
+ */
+#define PF_UNSPEC AF_UNSPEC
+#define PF_UNIX AF_UNIX
+#define PF_INET AF_INET
+#define PF_IMPLINK AF_IMPLINK
+#define PF_PUP AF_PUP
+#define PF_CHAOS AF_CHAOS
+#define PF_NS AF_NS
+#define PF_NBS AF_NBS
+#define PF_ECMA AF_ECMA
+#define PF_DATAKIT AF_DATAKIT
+#define PF_CCITT AF_CCITT
+#define PF_SNA AF_SNA
+#define PF_DECnet AF_DECnet
+#define PF_DLI AF_DLI
+#define PF_LAT AF_LAT
+#define PF_HYLINK AF_HYLINK
+#define PF_APPLETALK AF_APPLETALK
+#define PF_ROUTE AF_ROUTE
+#define PF_LINK AF_LINK
+#define PF_XTP pseudo_AF_XTP /* really just proto family, no AF */
+
+#define PF_MAX AF_MAX
+
+/*
+ * Maximum queue length specifiable by listen.
+ */
+#define SOMAXCONN 5
+
+/*
+ * Message header for recvmsg and sendmsg calls.
+ * Used value-result for recmvsg, value only for sendmsg.
+ */
+struct msghdr {
+ caddr_t msg_name; /* optional address */
+ u_int msg_namelen; /* size of address */
+ struct iovec *msg_iov; /* scatter/gather array */
+ u_int msg_iovlen; /* # elements msg_iov */
+ caddr_t msg_control; /* ancillary data, see below */
+ u_int msg_controllen; /* ancillary data buffer len */
+ int msg_flags; /* flags on received message */
+};
+#define msg_accrights msg_control
+#define msg_accrightslen msg_controllen
+
+#define MSG_OOB 0x1 /* process out-of-band data */
+#define MSG_PEEK 0x2 /* peek at incoming message */
+#define MSG_DONTROUTE 0x4 /* send without using routing tables */
+#define MSG_EOR 0x8 /* data completes record */ /*notused*/
+#define MSG_TRUNC 0x10 /* data discarded before delivery */
+#define MSG_CTRUNC 0x20 /* control data lost before delivery */
+#define MSG_WAITALL 0x40 /* wait for full request or error */ /*notused*/
+
+#define MSG_MAXIOVLEN 16
+
+/*
+ * Header for ancillary data objects in msg_control buffer.
+ * Used for additional information with/about a datagram
+ * not expressible by flags. The format is a sequence
+ * of message elements headed by cmsghdr structures.
+ * In STREAMware, we shuffle the fields around a little from what
+ * they were in net-2, so that they line up the same as an opthdr
+ * which simplifies our socket implementation amazingly.
+ *
+ * Unfortunately, the opthdrs don't include their own length, which the
+ * cmsghdrs do. What this means is that TLI programmers will not be
+ * able to take something returned using these macros and immediately give
+ * it back to the stack. The size of the struct cmsghdr will have to be
+ * subtracted out.
+ * There doesn't seem to be a way to avoid this, since several applications
+ * look into the cmsg_len field and won't work if it doesn't include the size
+ * of the struct cmsghdr.
+ */
+struct cmsghdr {
+ int cmsg_level; /* originating protocol */
+ int cmsg_type; /* protocol-specific type */
+ u_int cmsg_len; /* data byte count, including hdr */
+/* followed by u_char cmsg_data[]; */
+};
+
+/* given pointer to struct adatahdr, return pointer to data */
+#define CMSG_DATA(cmsg) ((u_char *)((cmsg) + 1))
+
+/* given pointer to struct adatahdr, return pointer to next adatahdr */
+#define CMSG_NXTHDR(mhdr, cmsg) \
+ (((caddr_t)(cmsg) + (cmsg)->cmsg_len + sizeof(struct cmsghdr) > \
+ (mhdr)->msg_control + (mhdr)->msg_controllen) ? \
+ (struct cmsghdr *)NULL : \
+ (struct cmsghdr *)((caddr_t)(cmsg) + OPTLEN((cmsg)->cmsg_len)))
+
+#define CMSG_FIRSTHDR(mhdr) ((struct cmsghdr *)(mhdr)->msg_control)
+
+/* "Socket"-level control message types: */
+#define SCM_RIGHTS 0x01 /* access rights (array of int) */
+
+/*
+ * This ioctl code uses BSD style ioctls to avoid copyin/out problems.
+ * Ioctls have the command encoded in the lower word, and the size of any in
+ * or out parameters in the upper word. The high 2 bits of the upper word
+ * are used to encode the in/out status of the parameter; for now we restrict
+ * parameters to at most 128 bytes.
+ */
+#define IOCPARM_MASK 0x7f /* parameters must be < 128 bytes */
+#define IOC_VOID 0x20000000 /* no parameters */
+#define IOC_OUT 0x40000000 /* copy out parameters */
+#define IOC_IN 0x80000000 /* copy in parameters */
+#define IOC_INOUT (IOC_IN|IOC_OUT)
+/* the 0x20000000 is so we can distinguish new ioctls from old */
+#define _IOS(x,y) (IOC_VOID|(x<<8)|y)
+#define _IOSR(x,y,t) (IOC_OUT|((sizeof(t)&IOCPARM_MASK)<<16)|(x<<8)|y)
+#define _IOSW(x,y,t) (IOC_IN|((sizeof(t)&IOCPARM_MASK)<<16)|(x<<8)|y)
+/* this should be _IOSRW, but stdio got there first */
+#define _IOSWR(x,y,t) (IOC_INOUT|((sizeof(t)&IOCPARM_MASK)<<16)|(x<<8)|y)
+
+/*
+ * Socket ioctl commands
+ */
+
+#define SIOCSHIWAT _IOSW('S', 1, int) /* set high watermark */
+#define SIOCGHIWAT _IOSR('S', 2, int) /* get high watermark */
+#define SIOCSLOWAT _IOSW('S', 3, int) /* set low watermark */
+#define SIOCGLOWAT _IOSR('S', 4, int) /* get low watermark */
+#define SIOCATMARK _IOSR('S', 5, int) /* at oob mark? */
+#define SIOCSPGRP _IOSW('S', 6, int) /* set process group */
+#define SIOCGPGRP _IOSR('S', 7, int) /* get process group */
+#define FIONREAD _IOSR('S', 8, int) /* BSD compatibilty */
+#define FIONBIO _IOSW('S', 9, int) /* BSD compatibilty */
+#define FIOASYNC _IOSW('S', 10, int) /* BSD compatibilty */
+#define SIOCPROTO _IOSW('S', 11, struct socknewproto) /* link proto */
+#define SIOCGETNAME _IOSR('S', 12, struct sockaddr) /* getsockname */
+#define SIOCGETPEER _IOSR('S', 13, struct sockaddr) /* getpeername */
+#define IF_UNITSEL _IOSW('S', 14, int) /* set unit number */
+#define SIOCXPROTO _IOS('S', 15) /* empty proto table */
+#define SIOCSHRDTYPE _IOSW('S', 16, int) /* set hardware type */
+
+#define SIOCADDRT _IOSW('R', 9, struct ortentry) /* add route */
+#define SIOCDELRT _IOSW('R', 10, struct ortentry) /* delete route */
+
+#define SIOCSIFADDR _IOSW('I', 11, struct ifreq) /* set ifnet address */
+#define SIOCGIFADDR _IOSWR('I', 12, struct ifreq) /* get ifnet address */
+#define SIOCSIFDSTADDR _IOSW('I', 13, struct ifreq) /* set p-p address */
+#define SIOCGIFDSTADDR _IOSWR('I', 14, struct ifreq) /* get p-p address */
+#define SIOCSIFFLAGS _IOSW('I', 15, struct ifreq) /* set ifnet flags */
+#define SIOCGIFFLAGS _IOSWR('I', 16, struct ifreq) /* get ifnet flags */
+#define SIOCGIFCONF _IOSWR('I', 17, struct ifconf) /* get ifnet list */
+
+#define SIOCSIFMTU _IOSW('I', 21, struct ifreq) /* get if_mtu */
+#define SIOCGIFMTU _IOSWR('I', 22, struct ifreq) /* set if_mtu */
+
+
+#define SIOCGIFBRDADDR _IOSWR('I', 32, struct ifreq) /* get broadcast addr */
+#define SIOCSIFBRDADDR _IOSW('I', 33, struct ifreq) /* set broadcast addr */
+#define SIOCGIFNETMASK _IOSWR('I', 34, struct ifreq) /* get net addr mask */
+#define SIOCSIFNETMASK _IOSW('I', 35, struct ifreq) /* set net addr mask */
+#define SIOCGIFMETRIC _IOSWR('I', 36, struct ifreq) /* get IF metric */
+#define SIOCSIFMETRIC _IOSW('I', 37, struct ifreq) /* set IF metric */
+
+#define SIOCSARP _IOSW('I', 38, struct arpreq) /* set arp entry */
+#define SIOCGARP _IOSWR('I', 39, struct arpreq) /* get arp entry */
+#define SIOCDARP _IOSW('I', 40, struct arpreq) /* delete arp entry */
+
+#define SIOCSIFNAME _IOSW('I', 41, struct ifreq) /* set interface name */
+#define SIOCGIFONEP _IOSWR('I', 42, struct ifreq) /* get one-packet params */
+#define SIOCSIFONEP _IOSW('I', 43, struct ifreq) /* set one-packet params */
+#define SIOCDIFADDR _IOSW('I', 44, struct ifreq) /* delete IF addr */
+#define SIOCAIFADDR _IOSW('I', 45, struct ifaliasreq) /*add/change IF alias*/
+#define SIOCADDMULTI _IOSW('I', 49, struct ifreq) /* add m'cast addr */
+#define SIOCDELMULTI _IOSW('I', 50, struct ifreq) /* del m'cast addr */
+#define SIOCGIFALIAS _IOSWR('I', 51, struct ifaliasreq) /* get IF alias */
+
+
+#define SIOCSOCKSYS _IOSW('I', 66, struct socksysreq) /* Pseudo socket syscall */
+
+/* these use ifr_metric to pass the information */
+#define SIOCSIFDEBUG _IOSW('I', 67, struct ifreq) /* set if debug level */
+#define SIOCGIFDEBUG _IOSWR('I', 68, struct ifreq) /* get if debug level */
+
+#define SIOCSIFTYPE _IOSW('I', 69, struct ifreq) /* set if MIB type */
+#define SIOCGIFTYPE _IOSWR('I', 70, struct ifreq) /* get if MIB type */
+
+#define SIOCGIFNUM _IOSR('I', 71, int) /* get number of ifs */
+/*
+ * This returns the number of ifreqs that SIOCGIFCONF would return, including
+ * aliases. This is the preferred way of sizing a buffer big enough to hold
+ * all interfaces.
+ */
+#define SIOCGIFANUM _IOSR('I', 72, int) /* get number of ifreqs */
+/*
+ * Interface specific performance tuning
+ */
+#define SIOCGIFPERF _IOSR('I', 73, struct ifreq) /* get perf info */
+#define SIOCSIFPERF _IOSR('I', 74, struct ifreq) /* get perf info */
+
+/*
+ * This structure is used to encode pseudo system calls
+ */
+struct socksysreq {
+ /* When porting, make this the widest thing it can be */
+ int args[7];
+};
+
+/*
+ * This structure is used for adding new protocols to the list supported by
+ * sockets.
+ */
+struct socknewproto {
+ int family; /* address family (AF_INET, etc.) */
+ int type; /* protocol type (SOCK_STREAM, etc.) */
+ int proto; /* per family proto number */
+ dev_t dev; /* major/minor to use (must be a clone) */
+ int flags; /* protosw flags */
+};
+
+/*
+ * utility definitions.
+ */
+
+#ifdef MIN
+#undef MIN
+#endif
+#define MIN(x,y) ((x) < (y) ? (x) : (y))
+#ifndef MAX
+#define MAX(x,y) ((x) > (y) ? (x) : (y))
+#endif
+
+#define MAXHOSTNAMELEN 256
+
+#define NBBY 8 /* number of bits in a byte */
+
+
+/* defines for user/kernel interface */
+
+#define MAX_MINOR (makedev(1,0) - 1) /* could be non-portable */
+
+#define SOCKETSYS 140 /* SCO 3.2v5 */
+
+#define SO_ACCEPT 1
+#define SO_BIND 2
+#define SO_CONNECT 3
+#define SO_GETPEERNAME 4
+#define SO_GETSOCKNAME 5
+#define SO_GETSOCKOPT 6
+#define SO_LISTEN 7
+#define SO_RECV 8
+#define SO_RECVFROM 9
+#define SO_SEND 10
+#define SO_SENDTO 11
+#define SO_SETSOCKOPT 12
+#define SO_SHUTDOWN 13
+#define SO_SOCKET 14
+#define SO_SELECT 15
+#define SO_GETIPDOMAIN 16
+#define SO_SETIPDOMAIN 17
+#define SO_ADJTIME 18
+#define SO_SETREUID 19
+#define SO_SETREGID 20
+#define SO_GETTIME 21
+#define SO_SETTIME 22
+#define SO_GETITIMER 23
+#define SO_SETITIMER 24
+#define SO_RECVMSG 25
+#define SO_SENDMSG 26
+#define SO_SOCKPAIR 27
+
+/*
+ * message flags
+ */
+#define M_BCAST 0x80000000
+
+/* Definitions and structures used for extracting */
+/* the size and/or the contents of kernel tables */
+
+/* Copyin/out values */
+#define GIARG 0x1
+#define CONTI 0x2
+#define GITAB 0x4
+
+struct gi_arg {
+ caddr_t gi_where;
+ unsigned gi_size;
+};
+
+#if !defined(_KERNEL) && !defined(INKERNEL) && !defined(_INKERNEL)
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+int accept __P_((int, struct sockaddr *, int *));
+int bind __P_((int, const struct sockaddr *, int));
+int connect __P_((int, const struct sockaddr *, int));
+int getpeername __P_((int, struct sockaddr *, int *));
+int getsockname __P_((int, struct sockaddr *, int *));
+int getsockopt __P_((int, int, int, void *, int *));
+int setsockopt __P_((int, int, int, const void *, int));
+int listen __P_((int, int));
+ssize_t recv __P_((int, void *, size_t, int));
+ssize_t recvfrom __P_((int, void *, size_t, int, struct sockaddr *, int *));
+int recvmsg __P_((int, struct msghdr *, int));
+ssize_t send __P_((int, const void *, size_t, int));
+int sendmsg __P_((int, const struct msghdr *, int));
+ssize_t sendto __P_((int, const void *, size_t, int, const struct sockaddr *, int));
+int shutdown __P_((int, int));
+int socket __P_((int, int, int));
+int socketpair __P_((int, int, int, int[2]));
+__END_DECLS
+
+#endif /* !INKERNEL */
+#endif /* __sys_socket_h */
diff --git a/mit-pthreads/machdep/sco-3.2v5/syscall.h b/mit-pthreads/machdep/sco-3.2v5/syscall.h
new file mode 100755
index 00000000000..f49fba81b6e
--- /dev/null
+++ b/mit-pthreads/machdep/sco-3.2v5/syscall.h
@@ -0,0 +1,175 @@
+/* Copyright 1994-1995 The Santa Cruz Operation, Inc. All Rights Reserved. */
+
+
+#if defined(_NO_PROTOTYPE) /* Old, crufty environment */
+#include <oldstyle/syscall.h>
+#elif defined(_SCO_ODS_30) /* Old, Tbird compatible environment */
+#include <ods_30_compat/syscall.h>
+#else /* Normal, default environment */
+/*
+/ Portions Copyright (C) 1983-1995 The Santa Cruz Operation, Inc.
+ * All Rights Reserved.
+ *
+ * The information in this file is provided for the exclusive use of
+ * the licensees of The Santa Cruz Operation, Inc. Such users have the
+ * right to use, modify, and incorporate this code into other products
+ * for purposes authorized by the license agreement provided they include
+ * this notice and the associated copyright notice with any such product.
+ * The information in this file is provided "AS IS" without warranty.
+ */
+
+/* Portions Copyright (c) 1990, 1991, 1992, 1993 UNIX System Laboratories, Inc. */
+/* Portions Copyright (c) 1979 - 1990 AT&T */
+
+#ident "xpg4plus @(#) sys.i386 20.1 94/12/04 "
+/* #ident "xpg4plus @(#)head:sys.i386 1.2" */
+
+/*
+/* Definitions of Kernel Entry Call Gates
+*/
+
+#ifndef _SYSCALL_H_
+#define _SYSCALL_H_
+
+/*#define SYSCALL $0x7,$0*/
+/*#define SIGCALL $0xF,$0*/
+
+/*
+/* Definitions of System Call Entry Point Numbers
+*/
+
+#define SYS_access 33
+#define SYS_acct 51
+#define SYS_advfs 70
+#define SYS_alarm 27
+#define SYS_break 17
+#define SYS_brk 17
+#define SYS_chdir 12
+#define SYS_chmod 15
+#define SYS_chown 16
+#define SYS_chroot 61
+#define SYS_close 6
+#define SYS_creat 8
+#define SYS_dup 41
+#define SYS_exec 11
+#define SYS_execve 59
+#define SYS_exit 1
+#define SYS_fcntl 62
+#define SYS_fork 2
+#define SYS_fstat 28
+#define SYS_fstatfs 38
+#define SYS_fxstat 125
+#define SYS_getdents 81
+#define SYS_getgid 47
+#define SYS_getmsg 85
+#define SYS_getpid 20
+#define SYS_gettimeofday 171
+#define SYS_getuid 24
+#define SYS_gtty 32
+#define SYS_ioctl 54
+#define SYS_kill 37
+#define SYS_link 9
+#define SYS_lock 45
+#define SYS_lseek 19
+#define SYS_lstat 91
+#define SYS_lxstat 124
+#define SYS_mkdir 80
+#define SYS_mknod 14
+#define SYS_mount 21
+#define SYS_msgsys 49
+#define SYS_nice 34
+#define SYS_open 5
+#define SYS_pause 29
+#define SYS_pipe 42
+#define SYS_plock 45
+#define SYS_poll 87
+#define SYS_prof 44
+#define SYS_ptrace 26
+#define SYS_putmsg 86
+#define SYS_rdebug 76
+#define SYS_read 3
+#define SYS_readlink 92
+#define SYS_readv 121
+#define SYS_rfstart 74
+#define SYS_rfstop 77
+#define SYS_rfsys 78
+#define SYS_rmdir 79
+#define SYS_rmount 72
+#define SYS_rumount 73
+#define SYS_seek 19
+#define SYS_semsys 53
+#define SYS_setgid 46
+#define SYS_setpgrp 39
+#define SYS_settimeofday 172
+#define SYS_setuid 23
+#define SYS_shmsys 52
+#define SYS_signal 48
+#define SYS_stat 18
+#define SYS_statfs 35
+#define SYS_stime 25
+#define SYS_stty 31
+#define SYS_symlink 90
+#define SYS_sync 36
+#define SYS_sys3b 50
+#define SYS_sysi86 50
+#define SYS_sysacct 51
+#define SYS_sysfs 84
+#define SYS_time 13
+#define SYS_times 43
+#define SYS_uadmin 55
+#define SYS_ulimit 63
+#define SYS_umask 60
+#define SYS_umount 22
+#define SYS_unadvfs 71
+#define SYS_unlink 10
+#define SYS_utime 30
+#define SYS_utssys 57
+#define SYS_wait 7
+#define SYS_write 4
+#define SYS_writev 122
+#define SYS_xstat 123
+#define SYS_ftruncate 192
+
+/* cxenix numbers are created by the formula
+ * (table index << 8) + CXENIX
+ */
+
+#define CXENIX 0x28 /* Decimal 40 */
+
+#define XLOCKING 0x0128
+#define CREATSEM 0x0228
+#define OPENSEM 0x0328
+#define SIGSEM 0x0428
+#define WAITSEM 0x0528
+#define NBWAITSEM 0x0628
+#define RDCHK 0x0728
+#define CHSIZE 0x0a28
+#define SYS_ftime 0x0b28
+#define NAP 0x0c28
+#define SDGET 0x0d28
+#define SDFREE 0x0e28
+#define SDENTER 0x0f28
+#define SDLEAVE 0x1028
+#define SDGETV 0x1128
+#define SDWAITV 0x1228
+#define PROCTL 0x2028
+#define EXECSEG 0x2128
+#define UNEXECSEG 0x2228
+#define SYS_select 0x2428
+#define SYS_eaccess 0x2528
+#define SYS_paccess 0x2628
+#define SYS_sigaction 0x2728
+#define SYS_sigprocmask 0x2828
+#define SYS_sigpending 0x2928
+#define SYS_sigsuspend 0x2a28
+#define SYS_getgroups 0x2b28
+#define SYS_setgroups 0x2c28
+#define SYS_sysconf 0x2d28
+#define SYS_pathconf 0x2e28
+#define SYS_fpathconf 0x2f28
+#define SYS_rename 0x3028
+#define SYS_setitimer 0x3828
+
+#define CLOCAL 127
+#endif
+#endif
diff --git a/mit-pthreads/machdep/sco-3.2v5/timers.h b/mit-pthreads/machdep/sco-3.2v5/timers.h
new file mode 100755
index 00000000000..cbc48ccc8d8
--- /dev/null
+++ b/mit-pthreads/machdep/sco-3.2v5/timers.h
@@ -0,0 +1,68 @@
+/* ==== timers.h ============================================================
+ * Copyright (c) 1994 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * timers.h,v 1.50.8.1 1996/03/05 08:28:36 proven Exp
+ *
+ * Description : Basic timers header.
+ *
+ * 1.00 94/06/13 proven
+ * -Started coding this file.
+ */
+
+#ifndef _SYS_TIMERS_H_
+#define _SYS_TIMERS_H_
+
+#include <sys/types.h>
+#include <time.h>
+
+struct timespec {
+ long tv_sec;
+ long tv_nsec;
+};
+
+#define TIMEVAL_TO_TIMESPEC(tv, ts) { \
+ (ts)->tv_sec = (tv)->tv_sec; \
+ (ts)->tv_nsec = (tv)->tv_usec * 1000; \
+}
+#define TIMESPEC_TO_TIMEVAL(tv, ts) { \
+ (tv)->tv_sec = (ts)->tv_sec; \
+ (tv)->tv_usec = (ts)->tv_nsec / 1000; \
+}
+
+/*
+ * New functions
+ */
+
+__BEGIN_DECLS
+
+__END_DECLS
+
+#endif
diff --git a/mit-pthreads/machdep/sco-3.2v5/trash.can b/mit-pthreads/machdep/sco-3.2v5/trash.can
new file mode 100755
index 00000000000..33edf65aab6
--- /dev/null
+++ b/mit-pthreads/machdep/sco-3.2v5/trash.can
@@ -0,0 +1 @@
+make: *** No targets specified and no makefile found. Stop.
diff --git a/mit-pthreads/machdep/sunos-4.1.3/__math.h b/mit-pthreads/machdep/sunos-4.1.3/__math.h
new file mode 100755
index 00000000000..9de1dc6d4bd
--- /dev/null
+++ b/mit-pthreads/machdep/sunos-4.1.3/__math.h
@@ -0,0 +1,5 @@
+/*
+ * Posix (actually ansi C) section
+ */
+#define HUGE_VAL (__infinity()) /* Produces IEEE Infinity. */
+
diff --git a/mit-pthreads/machdep/sunos-4.1.3/__path.h b/mit-pthreads/machdep/sunos-4.1.3/__path.h
new file mode 100755
index 00000000000..2665b5a0e8a
--- /dev/null
+++ b/mit-pthreads/machdep/sunos-4.1.3/__path.h
@@ -0,0 +1,12 @@
+/*
+ * $Id$
+ */
+
+#ifndef _SYS__PATH_H_
+#define _SYS__PATH_H_
+
+#define _PATH_PTY "/dev/"
+#define _PATH_TZDIR "/usr/share/zoneinfo"
+#define _PATH_TZFILE "localtime"
+
+#endif /* !_SYS__PATH_H_ */
diff --git a/mit-pthreads/machdep/sunos-4.1.3/__signal.h b/mit-pthreads/machdep/sunos-4.1.3/__signal.h
new file mode 100755
index 00000000000..f8b4fb8b6de
--- /dev/null
+++ b/mit-pthreads/machdep/sunos-4.1.3/__signal.h
@@ -0,0 +1,11 @@
+
+#include <sys/signal.h>
+#include <sys/stdtypes.h>
+
+typedef int sig_atomic_t;
+
+#define __SIGFILLSET 0xffffffff
+#define __SIGEMPTYSET 0
+#define __SIGADDSET(s,n) ((*s) |= (1 << ((n) - 1)))
+#define __SIGDELSET(s,n) ((*s) &= ~(1 << ((n) - 1)))
+#define __SIGISMEMBER(s,n) ((*s) & (1 << ((n) - 1)))
diff --git a/mit-pthreads/machdep/sunos-4.1.3/__stdio.h b/mit-pthreads/machdep/sunos-4.1.3/__stdio.h
new file mode 100755
index 00000000000..6ca5e57396d
--- /dev/null
+++ b/mit-pthreads/machdep/sunos-4.1.3/__stdio.h
@@ -0,0 +1,4 @@
+
+typedef pthread_fpos_t fpos_t;
+
+#include <sys/stdtypes.h>
diff --git a/mit-pthreads/machdep/sunos-4.1.3/__stdlib.h b/mit-pthreads/machdep/sunos-4.1.3/__stdlib.h
new file mode 100755
index 00000000000..7bb9093c51c
--- /dev/null
+++ b/mit-pthreads/machdep/sunos-4.1.3/__stdlib.h
@@ -0,0 +1,28 @@
+/* $Id$ */
+
+#ifndef __sys_stdtypes_h
+
+#ifndef _SYS___STDLIB_H_
+#define _SYS___STDLIB_H_
+
+#include <sys/stdtypes.h> /* to get size_t */
+
+#if (! defined _SIZE_T_ ) && (! defined(_GCC_SIZE_T))
+#define _SIZE_T_
+#define _GCC_SIZE_T
+typedef pthread_size_t size_t;
+#endif
+
+#if (! defined _WCHAR_T_ ) && (! defined(_GCC_WCHAR_T))
+#define _WCHAR_T_
+#define _GCC_WCHAR_T
+typedef unsigned int wchar_t;
+#endif
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#endif
+
+#endif
diff --git a/mit-pthreads/machdep/sunos-4.1.3/__string.h b/mit-pthreads/machdep/sunos-4.1.3/__string.h
new file mode 100755
index 00000000000..0859a80cf24
--- /dev/null
+++ b/mit-pthreads/machdep/sunos-4.1.3/__string.h
@@ -0,0 +1,14 @@
+
+#include <sys/stdtypes.h>
+
+/* Non-standard SunOS 4.x string routines. */
+#if !defined(_ANSI_SOURCE) && !defined(_POSIX_SOURCE)
+__BEGIN_DECLS
+int bcmp __P_((const void *, const void *, size_t));
+void bcopy __P_((const void *, void *, size_t));
+void bzero __P_((void *, size_t));
+char *index __P_((const char *, int));
+char *rindex __P_((const char *, int));
+char *strdup __P_((const char *));
+__END_DECLS
+#endif
diff --git a/mit-pthreads/machdep/sunos-4.1.3/__time.h b/mit-pthreads/machdep/sunos-4.1.3/__time.h
new file mode 100755
index 00000000000..1ffa0e47d3f
--- /dev/null
+++ b/mit-pthreads/machdep/sunos-4.1.3/__time.h
@@ -0,0 +1,2 @@
+
+#include <sys/stdtypes.h>
diff --git a/mit-pthreads/machdep/sunos-4.1.3/__unistd.h b/mit-pthreads/machdep/sunos-4.1.3/__unistd.h
new file mode 100755
index 00000000000..3b86527252c
--- /dev/null
+++ b/mit-pthreads/machdep/sunos-4.1.3/__unistd.h
@@ -0,0 +1,73 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)stdlib.h 5.13 (Berkeley) 6/4/91
+ * $Id$
+ */
+
+#ifndef _SYS___UNISTD_H_
+#define _SYS___UNISTD_H_
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+
+#define _SC_ARG_MAX 1 /* space for argv & envp */
+#define _SC_CHILD_MAX 2 /* maximum children per process??? */
+#define _SC_CLK_TCK 3 /* clock ticks/sec */
+#define _SC_NGROUPS_MAX 4 /* number of groups if multple supp. */
+#define _SC_OPEN_MAX 5 /* max open files per process */
+#define _SC_JOB_CONTROL 6 /* do we have job control */
+#define _SC_SAVED_IDS 7 /* do we have saved uid/gids */
+#define _SC_VERSION 8 /* POSIX version supported */
+
+#define _POSIX_JOB_CONTROL 1
+#define _POSIX_SAVED_IDS 1
+#define _POSIX_VERSION 198808
+
+#define _PC_LINK_MAX 1 /* max links to file/dir */
+#define _PC_MAX_CANON 2 /* max line length */
+#define _PC_MAX_INPUT 3 /* max "packet" to a tty device */
+#define _PC_NAME_MAX 4 /* max pathname component length */
+#define _PC_PATH_MAX 5 /* max pathname length */
+#define _PC_PIPE_BUF 6 /* size of a pipe */
+#define _PC_CHOWN_RESTRICTED 7 /* can we give away files */
+#define _PC_NO_TRUNC 8 /* trunc or error on >NAME_MAX */
+#define _PC_VDISABLE 9 /* best char to shut off tty c_cc */
+#define _PC_LAST 9 /* highest value of any _PC_* */
+
+#ifndef NULL
+#define NULL 0 /* null pointer constant */
+#endif
+
+typedef int ssize_t;
+
+#endif
diff --git a/mit-pthreads/machdep/sunos-4.1.3/cdefs.h b/mit-pthreads/machdep/sunos-4.1.3/cdefs.h
new file mode 100755
index 00000000000..a059fa3d3fc
--- /dev/null
+++ b/mit-pthreads/machdep/sunos-4.1.3/cdefs.h
@@ -0,0 +1,61 @@
+/* ==== cdefs.h ============================================================
+ * Copyright (c) 1994 by Chris Provenzano, proven@athena.mit.edu
+ *
+ * Description : Similar to the BSD cdefs.h file.
+ *
+ * 1.00 94/01/26 proven
+ * -Started coding this file.
+ */
+
+#ifndef _PTHREAD_SYS_CDEFS_H_
+#define _PTHREAD_SYS_CDEFS_H_
+
+/* Stuff for compiling */
+#if defined(__GNUC__)
+#if defined(__cplusplus)
+#define __INLINE static inline
+#define __BEGIN_DECLS extern "C" {
+#define __END_DECLS };
+#else
+#define __INLINE extern inline
+#define __CAN_DO_EXTERN_INLINE
+#define __BEGIN_DECLS
+#define __END_DECLS
+#if !defined(__STDC__)
+#define const __const
+#define inline __inline
+#define signed __signed
+#define volatile __volatile
+#endif
+#endif
+#else /* !__GNUC__ */
+#define __BEGIN_DECLS
+#define __END_DECLS
+#define __INLINE static
+#endif
+
+#ifndef __NORETURN
+#define __NORETURN
+#endif /* __NORETURN not defined. */
+
+#ifndef _U_INT32_T_
+#define _U_INT32_T_
+typedef unsigned int u_int32_t;
+#endif
+
+#ifndef _U_INT16_T_
+#define _U_INT16_T_
+typedef unsigned short u_int16_t;
+#endif
+
+#ifndef _INT32_T_
+#define _INT32_T_
+typedef int int32_t;
+#endif
+
+#ifndef _INT16_T_
+#define _INT16_T_
+typedef short int16_t;
+#endif
+
+#endif
diff --git a/mit-pthreads/machdep/sunos-4.1.3/compat.h b/mit-pthreads/machdep/sunos-4.1.3/compat.h
new file mode 100755
index 00000000000..b2a846d00ee
--- /dev/null
+++ b/mit-pthreads/machdep/sunos-4.1.3/compat.h
@@ -0,0 +1,45 @@
+/* ==== compat.h ============================================================
+ * Copyright (c) 1994 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ *
+ * Description : Basic timers header.
+ *
+ * 1.00 94/06/13 proven
+ * -Started coding this file.
+ */
+
+#ifndef _SYS_COMPAT_H_
+#define _SYS_COMPAT_H_
+
+#define omsghdr msghdr
+
+#endif
diff --git a/mit-pthreads/machdep/sunos-4.1.3/dirent.h b/mit-pthreads/machdep/sunos-4.1.3/dirent.h
new file mode 100755
index 00000000000..c2048b1741c
--- /dev/null
+++ b/mit-pthreads/machdep/sunos-4.1.3/dirent.h
@@ -0,0 +1,64 @@
+/*-
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)dirent.h 5.18 (Berkeley) 2/23/91
+ */
+
+#ifndef _SYS_DIRENT_H_
+#define _SYS_DIRENT_H_
+
+/*
+ * A directory entry has a struct dirent at the front of it, containing its
+ * inode number, the length of the entry, and the length of the name
+ * contained in the entry. These are followed by the name padded to a 4
+ * byte boundary with null bytes. All names are guaranteed null terminated.
+ * The maximum length of a name in a directory is MAXNAMLEN.
+ */
+
+struct dirent {
+ off_t d_off; /* offset of next disk dir entry */
+ u_long d_fileno; /* file number of entry */
+ u_short d_reclen; /* length of this record */
+ u_short d_namlen; /* length of string in d_name */
+#ifdef _POSIX_SOURCE
+ char d_name[255 + 1]; /* name must be no longer than this */
+#else
+#define MAXNAMLEN 255
+ char d_name[MAXNAMLEN + 1]; /* name must be no longer than this */
+#endif
+};
+
+#define d_ino d_fileno
+
+#endif /* !_SYS_DIRENT_H_ */
+
+
diff --git a/mit-pthreads/machdep/sunos-4.1.3/fcntlcom.h b/mit-pthreads/machdep/sunos-4.1.3/fcntlcom.h
new file mode 100755
index 00000000000..2b7acce7696
--- /dev/null
+++ b/mit-pthreads/machdep/sunos-4.1.3/fcntlcom.h
@@ -0,0 +1,163 @@
+/* @(#)fcntlcom.h 1.13 91/06/18 SMI; from UCB fcntl.h 5.2 1/8/86 */
+
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved. The Berkeley software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
+
+#ifndef __sys_fcntlcom_h
+#define __sys_fcntlcom_h
+
+#include <sys/cdefs.h>
+
+/*
+ * Rewack the FXXXXX values as _FXXXX so that _POSIX_SOURCE works.
+ */
+#define _FOPEN (-1) /* from sys/file.h, kernel use only */
+#define _FREAD 0x0001 /* read enabled */
+#define _FWRITE 0x0002 /* write enabled */
+#define _FNDELAY 0x0004 /* non blocking I/O (4.2 style) */
+#define _FAPPEND 0x0008 /* append (writes guaranteed at the end) */
+#define _FSETBLK 0x0010 /* use block offsets */
+#define _FASYNC 0x0040 /* signal pgrp when data ready */
+#define _FSHLOCK 0x0080 /* BSD flock() shared lock present */
+#define _FEXLOCK 0x0100 /* BSD flock() exclusive lock present */
+#define _FCREAT 0x0200 /* open with file create */
+#define _FTRUNC 0x0400 /* open with truncation */
+#define _FEXCL 0x0800 /* error on open if file exists */
+#define _FNBIO 0x1000 /* non blocking I/O (sys5 style) */
+#define _FSYNC 0x2000 /* do all writes synchronously */
+#define _FNONBLOCK 0x4000 /* non blocking I/O (POSIX style) */
+#define _FNOCTTY 0x8000 /* don't assign a ctty on this open */
+#define _FMARK 0x10000 /* internal; mark during gc() */
+#define _FDEFER 0x20000 /* internal; defer for next gc pass */
+
+#define O_ACCMODE (O_RDONLY|O_WRONLY|O_RDWR)
+
+/*
+ * Flag values for open(2) and fcntl(2)
+ * The kernel adds 1 to the open modes to turn it into some
+ * combination of FREAD and FWRITE.
+ */
+#define O_RDONLY 0 /* +1 == FREAD */
+#define O_WRONLY 1 /* +1 == FWRITE */
+#define O_RDWR 2 /* +1 == FREAD|FWRITE */
+#define O_APPEND _FAPPEND
+#define O_CREAT _FCREAT
+#define O_TRUNC _FTRUNC
+#define O_EXCL _FEXCL
+/* O_SYNC _FSYNC not posix, defined below */
+/* O_NDELAY _FNDELAY set in include/fcntl.h */
+/* O_NDELAY _FNBIO set in 5include/fcntl.h */
+#define O_NONBLOCK _FNONBLOCK
+#define O_NOCTTY _FNOCTTY
+
+#ifndef _POSIX_SOURCE
+
+#define O_SYNC _FSYNC
+
+/*
+ * Flags that work for fcntl(fd, F_SETFL, FXXXX)
+ */
+#define FAPPEND _FAPPEND
+#define FSYNC _FSYNC
+#define FASYNC _FASYNC
+#define FNBIO _FNBIO
+#define FNONBIO _FNONBLOCK /* XXX fix to be NONBLOCK everywhere */
+#define FNDELAY _FNDELAY
+
+/*
+ * Flags that are disallowed for fcntl's (FCNTLCANT);
+ * used for opens, internal state, or locking.
+ */
+#define FREAD _FREAD
+#define FWRITE _FWRITE
+#define FMARK _FMARK
+#define FDEFER _FDEFER
+#define FSETBLK _FSETBLK
+#define FSHLOCK _FSHLOCK
+#define FEXLOCK _FEXLOCK
+
+/*
+ * The rest of the flags, used only for opens
+ */
+#define FOPEN _FOPEN
+#define FCREAT _FCREAT
+#define FTRUNC _FTRUNC
+#define FEXCL _FEXCL
+#define FNOCTTY _FNOCTTY
+
+#endif !_POSIX_SOURCE
+
+/* XXX close on exec request; must match UF_EXCLOSE in user.h */
+#define FD_CLOEXEC 1 /* posix */
+
+/* fcntl(2) requests */
+#define F_DUPFD 0 /* Duplicate fildes */
+#define F_GETFD 1 /* Get fildes flags (close on exec) */
+#define F_SETFD 2 /* Set fildes flags (close on exec) */
+#define F_GETFL 3 /* Get file flags */
+#define F_SETFL 4 /* Set file flags */
+#ifndef _POSIX_SOURCE
+#define F_GETOWN 5 /* Get owner - for ASYNC */
+#define F_SETOWN 6 /* Set owner - for ASYNC */
+#endif /* !_POSIX_SOURCE */
+#define F_GETLK 7 /* Get record-locking information */
+#define F_SETLK 8 /* Set or Clear a record-lock (Non-Blocking) */
+#define F_SETLKW 9 /* Set or Clear a record-lock (Blocking) */
+#ifndef _POSIX_SOURCE
+#define F_RGETLK 10 /* Test a remote lock to see if it is blocked */
+#define F_RSETLK 11 /* Set or unlock a remote lock */
+#define F_CNVT 12 /* Convert a fhandle to an open fd */
+#define F_RSETLKW 13 /* Set or Clear remote record-lock(Blocking) */
+#endif /* !_POSIX_SOURCE */
+
+/* fcntl(2) flags (l_type field of flock structure) */
+#define F_RDLCK 1 /* read lock */
+#define F_WRLCK 2 /* write lock */
+#define F_UNLCK 3 /* remove lock(s) */
+#ifndef _POSIX_SOURCE
+#define F_UNLKSYS 4 /* remove remote locks for a given system */
+#endif /* !_POSIX_SOURCE */
+
+#include <sys/stdtypes.h>
+
+/* file segment locking set data type - information passed to system by user */
+struct flock {
+ short l_type; /* F_RDLCK, F_WRLCK, or F_UNLCK */
+ short l_whence; /* flag to choose starting offset */
+ long l_start; /* relative offset, in bytes */
+ long l_len; /* length, in bytes; 0 means lock to EOF */
+ short l_pid; /* returned with F_GETLK */
+ short l_xxx; /* reserved for future use */
+};
+
+#ifndef _POSIX_SOURCE
+/* extended file segment locking set data type */
+struct eflock {
+ short l_type; /* F_RDLCK, F_WRLCK, or F_UNLCK */
+ short l_whence; /* flag to choose starting offset */
+ long l_start; /* relative offset, in bytes */
+ long l_len; /* length, in bytes; 0 means lock to EOF */
+ short l_pid; /* returned with F_GETLK */
+ short l_xxx; /* reserved for future use */
+ long l_rpid; /* Remote process id wanting this lock */
+ long l_rsys; /* Remote system id wanting this lock */
+};
+#endif /* !_POSIX_SOURCE */
+
+#ifndef KERNEL
+#include <sys/stat.h> /* sigh. for the mode bits for open/creat */
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+int open __P_((const char *path, int flags, ...));
+int creat __P_((const char *path, mode_t modes));
+int fcntl __P_((int fd, int cmd, ...));
+
+__END_DECLS
+
+#endif /* !KERNEL */
+#endif /* !__sys_fcntlcom_h */
diff --git a/mit-pthreads/machdep/sunos-4.1.3/signal.h b/mit-pthreads/machdep/sunos-4.1.3/signal.h
new file mode 100755
index 00000000000..02a19860922
--- /dev/null
+++ b/mit-pthreads/machdep/sunos-4.1.3/signal.h
@@ -0,0 +1,98 @@
+#ifndef __sys_signal_h
+#define __sys_signal_h
+
+#define NSIG 32
+
+/*
+ * If any signal defines (SIG*) are added, deleted, or changed, the same
+ * changes must be made in /usr/include/signal.h as well.
+ */
+#define SIGHUP 1 /* hangup */
+#define SIGINT 2 /* interrupt */
+#define SIGQUIT 3 /* quit */
+#define SIGILL 4 /* illegal instruction (not reset when caught) */
+#define SIGTRAP 5 /* trace trap (not reset when caught) */
+#define SIGIOT 6 /* IOT instruction */
+#define SIGABRT 6 /* used by abort, replace SIGIOT in the future */
+#define SIGEMT 7 /* EMT instruction */
+#define SIGFPE 8 /* floating point exception */
+#define SIGKILL 9 /* kill (cannot be caught or ignored) */
+#define SIGBUS 10 /* bus error */
+#define SIGSEGV 11 /* segmentation violation */
+#define SIGSYS 12 /* bad argument to system call */
+#define SIGPIPE 13 /* write on a pipe with no one to read it */
+#define SIGALRM 14 /* alarm clock */
+#define SIGTERM 15 /* software termination signal from kill */
+#define SIGURG 16 /* urgent condition on IO channel */
+#define SIGSTOP 17 /* sendable stop signal not from tty */
+#define SIGTSTP 18 /* stop signal from tty */
+#define SIGCONT 19 /* continue a stopped process */
+#define SIGCHLD 20 /* to parent on child stop or exit */
+#define SIGCLD 20 /* System V name for SIGCHLD */
+#define SIGTTIN 21 /* to readers pgrp upon background tty read */
+#define SIGTTOU 22 /* like TTIN for output if (tp->t_local&LTOSTOP) */
+#define SIGIO 23 /* input/output possible signal */
+#define SIGPOLL SIGIO /* System V name for SIGIO */
+#define SIGXCPU 24 /* exceeded CPU time limit */
+#define SIGXFSZ 25 /* exceeded file size limit */
+#define SIGVTALRM 26 /* virtual time alarm */
+#define SIGPROF 27 /* profiling time alarm */
+#define SIGWINCH 28 /* window changed */
+#define SIGLOST 29 /* resource lost (eg, record-lock lost) */
+#define SIGUSR1 30 /* user defined signal 1 */
+#define SIGUSR2 31 /* user defined signal 2 */
+
+struct sigvec {
+ void (*sv_handler)(); /* signal handler */
+ int sv_mask; /* signal mask to apply */
+ int sv_flags; /* see signal options below */
+};
+#define SV_ONSTACK 0x0001 /* take signal on signal stack */
+#define SV_INTERRUPT 0x0002 /* do not restart system on signal return */
+#define SV_RESETHAND 0x0004 /* reset signal handler to SIG_DFL when signal taken */
+/*
+ * If any SA_NOCLDSTOP or SV_NOCLDSTOP is change, the same
+ * changes must be made in /usr/include/signal.h as well.
+ */
+#define SV_NOCLDSTOP 0x0008 /* don't send a SIGCHLD on child stop */
+#define SA_ONSTACK SV_ONSTACK
+#define SA_INTERRUPT SV_INTERRUPT
+#define SA_RESETHAND SV_RESETHAND
+
+#define SA_NOCLDSTOP SV_NOCLDSTOP
+#define sv_onstack sv_flags /* isn't compatibility wonderful! */
+
+/*
+ * If SIG_ERR, SIG_DFL, SIG_IGN, or SIG_HOLD are changed, the same changes
+ * must be made in /usr/include/signal.h as well.
+ */
+#define SIG_ERR (void (*)())-1
+#define SIG_DFL (void (*)())0
+#define SIG_IGN (void (*)())1
+
+/*
+ * Macro for converting signal number to a mask suitable for sigblock().
+ */
+#define sigmask(m) (1 << ((m)-1))
+
+/*
+ * If SIG_BLOCK, SIG_UNBLOCK, or SIG_SETMASK are changed, the same changes
+ * must be made in /usr/include/signal.h as well.
+ */
+#define SIG_BLOCK 0x0001
+#define SIG_UNBLOCK 0x0002
+#define SIG_SETMASK 0x0004
+
+/*
+ * If changes are made to sigset_t or struct sigaction, the same changes
+ * must be made in /usr/include/signal.h as well.
+ */
+#include <sys/stdtypes.h>
+
+struct sigaction {
+ void (*sa_handler)();
+ sigset_t sa_mask;
+ int sa_flags;
+};
+
+#endif /* !__sys_signal_h */
diff --git a/mit-pthreads/machdep/sunos-4.1.3/stat.h b/mit-pthreads/machdep/sunos-4.1.3/stat.h
new file mode 100755
index 00000000000..35e7f760204
--- /dev/null
+++ b/mit-pthreads/machdep/sunos-4.1.3/stat.h
@@ -0,0 +1,94 @@
+/* @(#)stat.h 2.19 90/01/24 SMI; from UCB 4.7 83/05/21 */
+
+/*
+ * NOTE: changes to this file should also be made to xpg2include/sys/stat.h
+ */
+
+#ifndef __sys_stat_h
+#define __sys_stat_h
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+
+struct stat {
+ dev_t st_dev;
+ ino_t st_ino;
+ mode_t st_mode;
+ short st_nlink;
+ uid_t st_uid;
+ gid_t st_gid;
+ dev_t st_rdev;
+ off_t st_size;
+ time_t st_atime;
+ int st_spare1;
+ time_t st_mtime;
+ int st_spare2;
+ time_t st_ctime;
+ int st_spare3;
+ long st_blksize;
+ long st_blocks;
+ long st_spare4[2];
+};
+
+#define _IFMT 0170000 /* type of file */
+#define _IFDIR 0040000 /* directory */
+#define _IFCHR 0020000 /* character special */
+#define _IFBLK 0060000 /* block special */
+#define _IFREG 0100000 /* regular */
+#define _IFLNK 0120000 /* symbolic link */
+#define _IFSOCK 0140000 /* socket */
+#define _IFIFO 0010000 /* fifo */
+
+#define S_ISUID 0004000 /* set user id on execution */
+#define S_ISGID 0002000 /* set group id on execution */
+#ifndef _POSIX_SOURCE
+#define S_ISVTX 0001000 /* save swapped text even after use */
+#define S_IREAD 0000400 /* read permission, owner */
+#define S_IWRITE 0000200 /* write permission, owner */
+#define S_IEXEC 0000100 /* execute/search permission, owner */
+
+#define S_ENFMT 0002000 /* enforcement-mode locking */
+
+#define S_IFMT _IFMT
+#define S_IFDIR _IFDIR
+#define S_IFCHR _IFCHR
+#define S_IFBLK _IFBLK
+#define S_IFREG _IFREG
+#define S_IFLNK _IFLNK
+#define S_IFSOCK _IFSOCK
+#define S_IFIFO _IFIFO
+#endif !_POSIX_SOURCE
+
+#define S_IRWXU 0000700 /* rwx, owner */
+#define S_IRUSR 0000400 /* read permission, owner */
+#define S_IWUSR 0000200 /* write permission, owner */
+#define S_IXUSR 0000100 /* execute/search permission, owner */
+#define S_IRWXG 0000070 /* rwx, group */
+#define S_IRGRP 0000040 /* read permission, group */
+#define S_IWGRP 0000020 /* write permission, grougroup */
+#define S_IXGRP 0000010 /* execute/search permission, group */
+#define S_IRWXO 0000007 /* rwx, other */
+#define S_IROTH 0000004 /* read permission, other */
+#define S_IWOTH 0000002 /* write permission, other */
+#define S_IXOTH 0000001 /* execute/search permission, other */
+
+#define S_ISBLK(m) (((m)&_IFMT) == _IFBLK)
+#define S_ISCHR(m) (((m)&_IFMT) == _IFCHR)
+#define S_ISDIR(m) (((m)&_IFMT) == _IFDIR)
+#define S_ISFIFO(m) (((m)&_IFMT) == _IFIFO)
+#define S_ISREG(m) (((m)&_IFMT) == _IFREG)
+#ifndef _POSIX_SOURCE
+#define S_ISLNK(m) (((m)&_IFMT) == _IFLNK)
+#define S_ISSOCK(m) (((m)&_IFMT) == _IFSOCK)
+#endif
+
+__BEGIN_DECLS
+int chmod __P_((const char *path, mode_t mode));
+int fstat __P_((int fd, struct stat *sbuf));
+int mkdir __P_((char *path, mode_t mode));
+int mkfifo __P_((char *path, mode_t mode));
+int stat __P_((const char *path, struct stat *sbuf));
+mode_t umask __P_((mode_t mask));
+__END_DECLS
+
+#endif /* !__sys_stat_h */
diff --git a/mit-pthreads/machdep/sunos-4.1.3/time.h b/mit-pthreads/machdep/sunos-4.1.3/time.h
new file mode 100755
index 00000000000..20bb085e4d8
--- /dev/null
+++ b/mit-pthreads/machdep/sunos-4.1.3/time.h
@@ -0,0 +1,69 @@
+/* @(#)time.h 2.12 91/05/22 SMI; from UCB 7.1 6/4/86 */
+
+/*
+ * Copyright (c) 1982, 1986 Regents of the University of California.
+ * All rights reserved. The Berkeley software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
+
+#ifndef _SYS_TIME_H_
+#define _SYS_TIME_H_
+
+#include <sys/cdefs.h>
+/*
+ * Structure returned by gettimeofday(2) system call,
+ * and used in other calls.
+ */
+
+struct timeval {
+ long tv_sec; /* seconds */
+ long tv_usec; /* and microseconds */
+};
+
+struct timezone {
+ int tz_minuteswest; /* minutes west of Greenwich */
+ int tz_dsttime; /* type of dst correction */
+};
+
+#define DST_NONE 0 /* not on dst */
+#define DST_USA 1 /* USA style dst */
+#define DST_AUST 2 /* Australian style dst */
+#define DST_WET 3 /* Western European dst */
+#define DST_MET 4 /* Middle European dst */
+#define DST_EET 5 /* Eastern European dst */
+#define DST_CAN 6 /* Canada */
+#define DST_GB 7 /* Great Britain and Eire */
+#define DST_RUM 8 /* Rumania */
+#define DST_TUR 9 /* Turkey */
+#define DST_AUSTALT 10 /* Australian style with shift in 1986 */
+
+/*
+ * Operations on timevals.
+ *
+ * NB: timercmp does not work for >= or <=.
+ */
+#define timerisset(tvp) ((tvp)->tv_sec || (tvp)->tv_usec)
+#define timercmp(tvp, uvp, cmp) \
+ ((tvp)->tv_sec cmp (uvp)->tv_sec || \
+ (tvp)->tv_sec == (uvp)->tv_sec && (tvp)->tv_usec cmp (uvp)->tv_usec)
+#define timerclear(tvp) (tvp)->tv_sec = (tvp)->tv_usec = 0
+
+/*
+ * Names of the interval timers, and structure
+ * defining a timer setting.
+ */
+#define ITIMER_REAL 0
+#define ITIMER_VIRTUAL 1
+#define ITIMER_PROF 2
+
+struct itimerval {
+ struct timeval it_interval; /* timer interval */
+ struct timeval it_value; /* current value */
+};
+
+__BEGIN_DECLS
+int gettimeofday __P_((struct timeval *, struct timezone *));
+__END_DECLS
+
+
+#endif
diff --git a/mit-pthreads/machdep/sunos-4.1.3/timers.h b/mit-pthreads/machdep/sunos-4.1.3/timers.h
new file mode 100755
index 00000000000..3c4d057976a
--- /dev/null
+++ b/mit-pthreads/machdep/sunos-4.1.3/timers.h
@@ -0,0 +1,68 @@
+/* ==== timers.h ============================================================
+ * Copyright (c) 1994 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ *
+ * Description : Basic timers header.
+ *
+ * 1.00 94/06/13 proven
+ * -Started coding this file.
+ */
+
+#ifndef _SYS_TIMERS_H_
+#define _SYS_TIMERS_H_
+
+#include <sys/types.h>
+#include <time.h>
+
+struct timespec {
+ time_t tv_sec;
+ long tv_nsec;
+};
+
+#define TIMEVAL_TO_TIMESPEC(tv, ts) { \
+ (ts)->tv_sec = (tv)->tv_sec; \
+ (ts)->tv_nsec = (tv)->tv_usec * 1000; \
+}
+#define TIMESPEC_TO_TIMEVAL(tv, ts) { \
+ (tv)->tv_sec = (ts)->tv_sec; \
+ (tv)->tv_usec = (ts)->tv_nsec / 1000; \
+}
+
+/*
+ * New functions
+ */
+
+__BEGIN_DECLS
+
+__END_DECLS
+
+#endif
diff --git a/mit-pthreads/machdep/sunos-4.1.3/wait.h b/mit-pthreads/machdep/sunos-4.1.3/wait.h
new file mode 100755
index 00000000000..97f5fb261f7
--- /dev/null
+++ b/mit-pthreads/machdep/sunos-4.1.3/wait.h
@@ -0,0 +1,22 @@
+#ifndef _SYS_WAIT_H_
+#define _SYS_WAIT_H_
+
+#define WNOHANG 1 /* dont hang in wait */
+#define WUNTRACED 2 /* tell about stopped, untraced children */
+
+pid_t wait __P_((int *));
+pid_t waitpid __P_((pid_t, int *, int));
+
+#define _W_INT(i) (i)
+#define WCOREFLAG 0200
+
+#define _WSTATUS(x) (_W_INT(x) & 0177)
+#define _WSTOPPED 0177 /* _WSTATUS if process is stopped */
+#define WIFSTOPPED(x) (_WSTATUS(x) == _WSTOPPED)
+#define WSTOPSIG(x) (_W_INT(x) >> 8)
+#define WIFSIGNALED(x) (_WSTATUS(x) != _WSTOPPED && _WSTATUS(x) != 0)
+#define WTERMSIG(x) (_WSTATUS(x))
+#define WIFEXITED(x) (_WSTATUS(x) == 0)
+#define WEXITSTATUS(x) (_W_INT(x) >> 8)
+
+#endif /* _SYS_WAIT_H_ */
diff --git a/mit-pthreads/machdep/sunos-5.3/__math.h b/mit-pthreads/machdep/sunos-5.3/__math.h
new file mode 100755
index 00000000000..5404b52c661
--- /dev/null
+++ b/mit-pthreads/machdep/sunos-5.3/__math.h
@@ -0,0 +1,16 @@
+/*
+ * ANSI/POSIX
+ */
+typedef union _h_val {
+ unsigned long _i[2];
+ double _d;
+} _h_val;
+
+#ifdef __STDC__
+extern const _h_val __huge_val;
+#else
+extern _h_val __huge_val;
+#endif
+
+#define HUGE_VAL __huge_val._d
+
diff --git a/mit-pthreads/machdep/sunos-5.3/__signal.h b/mit-pthreads/machdep/sunos-5.3/__signal.h
new file mode 100755
index 00000000000..638c1ca7331
--- /dev/null
+++ b/mit-pthreads/machdep/sunos-5.3/__signal.h
@@ -0,0 +1,19 @@
+#include <sys/feature_tests.h>
+#include <sys/signal.h>
+
+/*
+typedef struct {
+ unsigned long __sigbits[4];
+} sigset_t;
+*/
+
+typedef int sig_atomic_t;
+
+#define sigmask(n) ((unsigned int)1 << (((n) - 1) & (32 - 1)))
+#define sigword(n) (((unsigned int)((n) - 1))>>5)
+
+#define __SIGEMPTYSET { 0, 0, 0, 0 };
+#define __SIGFILLSET { 0xffffffff,0xffffffff,0xffffffff,0xffffffff };
+#define __SIGADDSET(s, n) ((s)->__sigbits[sigword(n)] |= sigmask(n))
+#define __SIGDELSET(s, n) ((s)->__sigbits[sigword(n)] &= ~sigmask(n))
+#define __SIGISMEMBER(s, n) (sigmask(n) & (s)->__sigbits[sigword(n)])
diff --git a/mit-pthreads/machdep/sunos-5.3/__stdio.h b/mit-pthreads/machdep/sunos-5.3/__stdio.h
new file mode 100755
index 00000000000..4dd4becdbe9
--- /dev/null
+++ b/mit-pthreads/machdep/sunos-5.3/__stdio.h
@@ -0,0 +1,6 @@
+typedef pthread_fpos_t fpos_t;
+
+#ifndef _SIZE_T
+#define _SIZE_T
+typedef pthread_size_t size_t;
+#endif
diff --git a/mit-pthreads/machdep/sunos-5.3/__stdlib.h b/mit-pthreads/machdep/sunos-5.3/__stdlib.h
new file mode 100755
index 00000000000..a0717ce3c2b
--- /dev/null
+++ b/mit-pthreads/machdep/sunos-5.3/__stdlib.h
@@ -0,0 +1,27 @@
+
+#ifndef _SYS___STDLIB_H_
+#define _SYS___STDLIB_H_
+
+#include <sys/feature_tests.h>
+
+#ifndef _SIZE_T
+#define _SIZE_T
+typedef unsigned int size_t;
+#endif
+
+#ifndef _UID_T
+#define _UID_T
+typedef long uid_t;
+#endif
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#ifndef _WCHAR_T
+#define _WCHAR_T
+typedef long wchar_t;
+#endif
+
+
+#endif
diff --git a/mit-pthreads/machdep/sunos-5.3/__string.h b/mit-pthreads/machdep/sunos-5.3/__string.h
new file mode 100755
index 00000000000..9cb12a07bb7
--- /dev/null
+++ b/mit-pthreads/machdep/sunos-5.3/__string.h
@@ -0,0 +1,12 @@
+
+#ifndef _SIZE_T
+#define _SIZE_T
+typedef pthread_size_t size_t;
+#endif
+
+/* Non-standard NetBSD string routines. */
+#if !defined(_ANSI_SOURCE) && !defined(_POSIX_SOURCE)
+__BEGIN_DECLS
+char *strdup __P_((const char *));
+__END_DECLS
+#endif
diff --git a/mit-pthreads/machdep/sunos-5.3/__time.h b/mit-pthreads/machdep/sunos-5.3/__time.h
new file mode 100755
index 00000000000..231e997acfa
--- /dev/null
+++ b/mit-pthreads/machdep/sunos-5.3/__time.h
@@ -0,0 +1,69 @@
+/* ==== timers.h ============================================================
+ * Copyright (c) 1994 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ *
+ * Description : System specific time header.
+ *
+ * 1.00 94/11/07 proven
+ * -Started coding this file.
+ */
+
+#ifndef _SYS___TIME_H_
+#define _SYS___TIME_H_
+
+#include <sys/feature_tests.h>
+
+#ifndef _SIZE_T
+#define _SIZE_T
+typedef unsigned size_t;
+#endif
+#ifndef _CLOCK_T
+#define _CLOCK_T
+typedef long clock_t;
+#endif
+#ifndef _TIME_T
+#define _TIME_T
+typedef long time_t;
+#endif
+#ifndef _CLOCKID_T
+#define _CLOCKID_T
+typedef int clockid_t;
+#endif
+#ifndef _TIMER_T
+#define _TIMER_T
+typedef int timer_t;
+#endif
+
+#include <sys/time.h>
+#include <sys/siginfo.h>
+
+#endif
diff --git a/mit-pthreads/machdep/sunos-5.3/__unistd.h b/mit-pthreads/machdep/sunos-5.3/__unistd.h
new file mode 100755
index 00000000000..4e83a863735
--- /dev/null
+++ b/mit-pthreads/machdep/sunos-5.3/__unistd.h
@@ -0,0 +1,47 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)stdlib.h 5.13 (Berkeley) 6/4/91
+ * $Id$
+ */
+
+#ifndef _SYS___UNISTD_H_
+#define _SYS___UNISTD_H_
+
+#include <sys/types.h>
+#include <sys/unistd.h>
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#endif
diff --git a/mit-pthreads/machdep/sunos-5.3/cdefs.h b/mit-pthreads/machdep/sunos-5.3/cdefs.h
new file mode 100755
index 00000000000..f95f7b36958
--- /dev/null
+++ b/mit-pthreads/machdep/sunos-5.3/cdefs.h
@@ -0,0 +1,59 @@
+/* ==== cdefs.h ============================================================
+ * Copyright (c) 1994 by Chris Provenzano, proven@athena.mit.edu
+ *
+ * Description : Similar to the BSD cdefs.h file.
+ *
+ * 1.00 94/01/26 proven
+ * -Started coding this file.
+ */
+
+#ifndef _PTHREAD_SYS_CDEFS_H_
+#define _PTHREAD_SYS_CDEFS_H_
+
+/* Stuff for compiling */
+#if defined(__GNUC__)
+#if defined(__cplusplus)
+#define __INLINE static inline
+#define __BEGIN_DECLS extern "C" {
+#define __END_DECLS };
+#else
+#define __INLINE extern inline
+#define __CAN_DO_EXTERN_INLINE
+#define __BEGIN_DECLS
+#define __END_DECLS
+#define const __const
+#define inline __inline
+#define signed __signed
+#define volatile __volatile
+#endif
+#else /* !__GNUC__ */
+#define __BEGIN_DECLS
+#define __END_DECLS
+#define __INLINE static
+#endif
+
+#ifndef __NORETURN
+#define __NORETURN
+#endif /* __NORETURN not defined. */
+
+#ifndef _U_INT32_T_
+#define _U_INT32_T_
+typedef unsigned int u_int32_t;
+#endif
+
+#ifndef _U_INT16_T_
+#define _U_INT16_T_
+typedef unsigned short u_int16_t;
+#endif
+
+#ifndef _INT32_T_
+#define _INT32_T_
+typedef int int32_t;
+#endif
+
+#ifndef _INT16_T_
+#define _INT16_T_
+typedef short int16_t;
+#endif
+
+#endif
diff --git a/mit-pthreads/machdep/sunos-5.3/compat.h b/mit-pthreads/machdep/sunos-5.3/compat.h
new file mode 100755
index 00000000000..b2a846d00ee
--- /dev/null
+++ b/mit-pthreads/machdep/sunos-5.3/compat.h
@@ -0,0 +1,45 @@
+/* ==== compat.h ============================================================
+ * Copyright (c) 1994 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ *
+ * Description : Basic timers header.
+ *
+ * 1.00 94/06/13 proven
+ * -Started coding this file.
+ */
+
+#ifndef _SYS_COMPAT_H_
+#define _SYS_COMPAT_H_
+
+#define omsghdr msghdr
+
+#endif
diff --git a/mit-pthreads/machdep/sunos-5.3/dirent.h b/mit-pthreads/machdep/sunos-5.3/dirent.h
new file mode 100755
index 00000000000..303d3d7df2b
--- /dev/null
+++ b/mit-pthreads/machdep/sunos-5.3/dirent.h
@@ -0,0 +1,64 @@
+/*-
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)dirent.h 5.18 (Berkeley) 2/23/91
+ */
+
+#ifndef _SYS_DIRENT_H_
+#define _SYS_DIRENT_H_
+
+/*
+ * A directory entry has a struct dirent at the front of it, containing its
+ * inode number, the length of the entry, and the length of the name
+ * contained in the entry. These are followed by the name padded to a 4
+ * byte boundary with null bytes. All names are guaranteed null terminated.
+ * The maximum length of a name in a directory is MAXNAMLEN.
+ */
+
+struct dirent {
+ u_long d_fileno; /* file number of entry */
+ off_t d_off; /* offset of next disk dir entry */
+ u_short d_reclen; /* length of this record */
+#ifdef _POSIX_SOURCE
+ char d_name[255 + 1]; /* name must be no longer than this */
+#else
+#define MAXNAMLEN 255
+ char d_name[MAXNAMLEN + 1]; /* name must be no longer than this */
+#endif
+};
+
+#define d_namlen d_reclen
+#define d_ino d_fileno
+
+#endif /* !_SYS_DIRENT_H_ */
+
+
diff --git a/mit-pthreads/machdep/sunos-5.3/socket.h b/mit-pthreads/machdep/sunos-5.3/socket.h
new file mode 100755
index 00000000000..0b075622fed
--- /dev/null
+++ b/mit-pthreads/machdep/sunos-5.3/socket.h
@@ -0,0 +1,180 @@
+/*
+ * Copyright (c) 1982, 1985, 1986 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * @(#)socket.h 7.3 (Berkeley) 6/27/88
+ */
+
+#ifndef _SYS_SOCKET_H
+#define _SYS_SOCKET_H
+
+/*
+ * Types of sockets
+ */
+#define SOCK_STREAM 2 /* stream socket */
+#define SOCK_DGRAM 1 /* datagram socket */
+#define SOCK_RAW 4 /* raw-protocol interface */
+#define SOCK_RDM 5 /* reliably-delivered message */
+#define SOCK_SEQPACKET 6 /* sequenced packet stream */
+
+/*
+ * Option flags per-socket.
+ */
+#define SO_DEBUG 0x0001 /* turn on debugging info recording */
+#define SO_ACCEPTCONN 0x0002 /* socket has had listen() */
+#define SO_REUSEADDR 0x0004 /* allow local address reuse */
+#define SO_KEEPALIVE 0x0008 /* keep connections alive */
+#define SO_DONTROUTE 0x0010 /* just use interface addresses */
+#define SO_BROADCAST 0x0020 /* permit sending of broadcast msgs */
+#define SO_USELOOPBACK 0x0040 /* bypass hardware when possible */
+#define SO_LINGER 0x0080 /* linger on close if data present */
+#define SO_OOBINLINE 0x0100 /* leave received OOB data in line */
+
+/*
+ * Additional options, not kept in so_options.
+ */
+#define SO_SNDBUF 0x1001 /* send buffer size */
+#define SO_RCVBUF 0x1002 /* receive buffer size */
+#define SO_SNDLOWAT 0x1003 /* send low-water mark */
+#define SO_RCVLOWAT 0x1004 /* receive low-water mark */
+#define SO_SNDTIMEO 0x1005 /* send timeout */
+#define SO_RCVTIMEO 0x1006 /* receive timeout */
+#define SO_ERROR 0x1007 /* get error status and clear */
+#define SO_TYPE 0x1008 /* get socket type */
+#define SO_PROTOTYPE 0x1009 /* get/set protocol type */
+
+/*
+ * Level number for (get/set)sockopt() to apply to socket itself.
+ */
+#define SOL_SOCKET 0xffff /* options for socket level */
+
+/*
+ * Address families.
+ */
+#define AF_UNSPEC 0 /* unspecified */
+#define AF_UNIX 1 /* local to host (pipes, portals) */
+#define AF_INET 2 /* internetwork: UDP, TCP, etc. */
+#define AF_IMPLINK 3 /* arpanet imp addresses */
+#define AF_PUP 4 /* pup protocols: e.g. BSP */
+#define AF_CHAOS 5 /* mit CHAOS protocols */
+#define AF_NS 6 /* XEROX NS protocols */
+#define AF_NBS 7 /* nbs protocols */
+#define AF_ECMA 8 /* european computer manufacturers */
+#define AF_DATAKIT 9 /* datakit protocols */
+#define AF_CCITT 10 /* CCITT protocols, X.25 etc */
+#define AF_SNA 11 /* IBM SNA */
+#define AF_DECnet 12 /* DECnet */
+#define AF_DLI 13 /* Direct data link interface */
+#define AF_LAT 14 /* LAT */
+#define AF_HYLINK 15 /* NSC Hyperchannel */
+#define AF_APPLETALK 16 /* Apple Talk */
+#define AF_NIT 17 /* NIT */
+#define AF_802 18 /* IEEE 802.2, also ISO 8802 */
+#define AF_ISO 19 /* ISO protocols */
+#define AF_OSI AF_ISO
+#define AF_X25 20 /* CCITT X.25 in particular */
+#define AF_OSINET 21
+#define AF_GOSIP 22
+#define AF_MAX 22
+
+/*
+ * Structure used by kernel to store most
+ * addresses.
+ */
+struct sockaddr {
+ unsigned short sa_family; /* address family */
+ char sa_data[14]; /* up to 14 bytes of direct address */
+};
+
+/*
+ * Structure used by kernel to pass protocol
+ * information in raw sockets.
+ */
+struct sockproto {
+ unsigned short sp_family; /* address family */
+ unsigned short sp_protocol; /* protocol */
+};
+
+/*
+ * Protocol families, same as address families for now.
+ */
+#define PF_UNSPEC AF_UNSPEC
+#define PF_UNIX AF_UNIX
+#define PF_INET AF_INET
+#define PF_IMPLINK AF_IMPLINK
+#define PF_PUP AF_PUP
+#define PF_CHAOS AF_CHAOS
+#define PF_NS AF_NS
+#define PF_NBS AF_NBS
+#define PF_ECMA AF_ECMA
+#define PF_DATAKIT AF_DATAKIT
+#define PF_CCITT AF_CCITT
+#define PF_SNA AF_SNA
+#define PF_DECnet AF_DECnet
+#define PF_DLI AF_DLI
+#define PF_LAT AF_LAT
+#define PF_HYLINK AF_HYLINK
+#define PF_APPLETALK AF_APPLETALK
+#define PF_NIT AF_NIT
+#define PF_802 AF_802
+#define PF_ISO AF_ISO
+#define PF_OSI AF_ISO
+#define PF_X25 AF_X25
+#define PF_OSINET AF_OSINET
+#define PF_GOSIP AF_GOSIP
+#define PF_MAX AF_MAX
+
+/*
+ * Maximum queue length specifiable by listen.
+ */
+#define SOMAXCONN 5
+
+/*
+ * Message header for recvmsg and sendmsg calls.
+ */
+struct msghdr {
+ caddr_t msg_name; /* optional address */
+ int msg_namelen; /* size of address */
+ struct iovec *msg_iov; /* scatter/gather array */
+ int msg_iovlen; /* # elements in msg_iov */
+ caddr_t msg_accrights; /* access rights sent/received */
+ int msg_accrightslen;
+};
+
+#define MSG_OOB 0x1 /* process out-of-band data */
+#define MSG_PEEK 0x2 /* peek at incoming message */
+#define MSG_DONTROUTE 0x4 /* send without using routing tables */
+
+#define MSG_MAXIOVLEN 16
+
+#include <sys/cdefs.h>
+/*
+ * Functions
+ */
+
+__BEGIN_DECLS
+
+int accept __P_((int, struct sockaddr *, int *));
+int bind __P_((int, const struct sockaddr *, int));
+int connect __P_((int, const struct sockaddr *, int));
+int listen __P_((int, int));
+int socket __P_((int, int, int));
+int setsockopt __P_((int, int, int, const void *, int));
+int getsockname __P_((int, struct sockaddr *, int *));
+int shutdown __P_((int, int));
+int getpeername __P_((int, struct sockaddr *, int *));
+__END_DECLS
+
+#endif /* _SYS_SOCKET_H */
diff --git a/mit-pthreads/machdep/sunos-5.3/timers.h b/mit-pthreads/machdep/sunos-5.3/timers.h
new file mode 100755
index 00000000000..3ee2c78f088
--- /dev/null
+++ b/mit-pthreads/machdep/sunos-5.3/timers.h
@@ -0,0 +1,72 @@
+/* ==== timers.h ============================================================
+ * Copyright (c) 1994 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ *
+ * Description : Basic timers header.
+ *
+ * 1.00 94/06/13 proven
+ * -Started coding this file.
+ */
+
+#ifndef _SYS_TIMERS_H_
+#define _SYS_TIMERS_H_
+
+#include <sys/types.h>
+#include <time.h>
+
+#define tv_sec tv_sec
+#define tv_nsec tv_nsec
+
+#define TIMEVAL_TO_TIMESPEC(tv, ts) { \
+ (ts)->tv_sec = (tv)->tv_sec; \
+ (ts)->tv_nsec = (tv)->tv_usec * 1000; \
+}
+#define TIMESPEC_TO_TIMEVAL(tv, ts) { \
+ (tv)->tv_sec = (ts)->tv_sec; \
+ (tv)->tv_usec = (ts)->tv_nsec / 1000; \
+}
+
+/*
+ * New functions
+ */
+
+#ifndef NOT_USED
+/* for sleep.h */
+/* int gettimeofday __P_((struct timeval *,struct timezone *)); */
+int gettimeofday __P_((struct timeval *,void *));
+#endif
+
+__BEGIN_DECLS
+
+__END_DECLS
+
+#endif
diff --git a/mit-pthreads/machdep/sunos-5.3/uio.h b/mit-pthreads/machdep/sunos-5.3/uio.h
new file mode 100755
index 00000000000..7786142dd87
--- /dev/null
+++ b/mit-pthreads/machdep/sunos-5.3/uio.h
@@ -0,0 +1,40 @@
+/* ==== uio.h ============================================================
+ * Copyright (c) 1994 by Chris Provenzano, proven@athena.mit.edu
+ *
+ * Description : Correct Solaris header file.
+ */
+
+#ifndef _PTHREAD_UIO_H_
+#define _PTHREAD_UIO_H_
+
+#include <sys/cdefs.h>
+
+struct iovec {
+ void *iov_base;
+ size_t iov_len;
+};
+
+typedef struct iovec iovec_t;
+
+struct uio {
+ iovec_t *uio_iov; /* pointer to array of iovecs */
+ int uio_iovcnt; /* number of iovecs */
+ /* These are all bogus */
+ int _uio_offset; /* file offset */
+ int uio_segflg; /* address space (kernel or user) */
+ short uio_fmode; /* file mode flags */
+ int _uio_limit; /* u-limit (maximum "block" offset) */
+ int uio_resid; /* residual count */
+};
+
+typedef struct uio uio_t;
+
+__BEGIN_DECLS
+
+int readv __P_((int, const struct iovec *, int));
+int writev __P_((int, const struct iovec *, int));
+
+__END_DECLS
+
+#endif
+
diff --git a/mit-pthreads/machdep/sunos-5.5/__math.h b/mit-pthreads/machdep/sunos-5.5/__math.h
new file mode 100755
index 00000000000..5404b52c661
--- /dev/null
+++ b/mit-pthreads/machdep/sunos-5.5/__math.h
@@ -0,0 +1,16 @@
+/*
+ * ANSI/POSIX
+ */
+typedef union _h_val {
+ unsigned long _i[2];
+ double _d;
+} _h_val;
+
+#ifdef __STDC__
+extern const _h_val __huge_val;
+#else
+extern _h_val __huge_val;
+#endif
+
+#define HUGE_VAL __huge_val._d
+
diff --git a/mit-pthreads/machdep/sunos-5.5/__signal.h b/mit-pthreads/machdep/sunos-5.5/__signal.h
new file mode 100755
index 00000000000..638c1ca7331
--- /dev/null
+++ b/mit-pthreads/machdep/sunos-5.5/__signal.h
@@ -0,0 +1,19 @@
+#include <sys/feature_tests.h>
+#include <sys/signal.h>
+
+/*
+typedef struct {
+ unsigned long __sigbits[4];
+} sigset_t;
+*/
+
+typedef int sig_atomic_t;
+
+#define sigmask(n) ((unsigned int)1 << (((n) - 1) & (32 - 1)))
+#define sigword(n) (((unsigned int)((n) - 1))>>5)
+
+#define __SIGEMPTYSET { 0, 0, 0, 0 };
+#define __SIGFILLSET { 0xffffffff,0xffffffff,0xffffffff,0xffffffff };
+#define __SIGADDSET(s, n) ((s)->__sigbits[sigword(n)] |= sigmask(n))
+#define __SIGDELSET(s, n) ((s)->__sigbits[sigword(n)] &= ~sigmask(n))
+#define __SIGISMEMBER(s, n) (sigmask(n) & (s)->__sigbits[sigword(n)])
diff --git a/mit-pthreads/machdep/sunos-5.5/__stdio.h b/mit-pthreads/machdep/sunos-5.5/__stdio.h
new file mode 100755
index 00000000000..4dd4becdbe9
--- /dev/null
+++ b/mit-pthreads/machdep/sunos-5.5/__stdio.h
@@ -0,0 +1,6 @@
+typedef pthread_fpos_t fpos_t;
+
+#ifndef _SIZE_T
+#define _SIZE_T
+typedef pthread_size_t size_t;
+#endif
diff --git a/mit-pthreads/machdep/sunos-5.5/__stdlib.h b/mit-pthreads/machdep/sunos-5.5/__stdlib.h
new file mode 100755
index 00000000000..a0717ce3c2b
--- /dev/null
+++ b/mit-pthreads/machdep/sunos-5.5/__stdlib.h
@@ -0,0 +1,27 @@
+
+#ifndef _SYS___STDLIB_H_
+#define _SYS___STDLIB_H_
+
+#include <sys/feature_tests.h>
+
+#ifndef _SIZE_T
+#define _SIZE_T
+typedef unsigned int size_t;
+#endif
+
+#ifndef _UID_T
+#define _UID_T
+typedef long uid_t;
+#endif
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#ifndef _WCHAR_T
+#define _WCHAR_T
+typedef long wchar_t;
+#endif
+
+
+#endif
diff --git a/mit-pthreads/machdep/sunos-5.5/__string.h b/mit-pthreads/machdep/sunos-5.5/__string.h
new file mode 100755
index 00000000000..9cb12a07bb7
--- /dev/null
+++ b/mit-pthreads/machdep/sunos-5.5/__string.h
@@ -0,0 +1,12 @@
+
+#ifndef _SIZE_T
+#define _SIZE_T
+typedef pthread_size_t size_t;
+#endif
+
+/* Non-standard NetBSD string routines. */
+#if !defined(_ANSI_SOURCE) && !defined(_POSIX_SOURCE)
+__BEGIN_DECLS
+char *strdup __P_((const char *));
+__END_DECLS
+#endif
diff --git a/mit-pthreads/machdep/sunos-5.5/__time.h b/mit-pthreads/machdep/sunos-5.5/__time.h
new file mode 100755
index 00000000000..231e997acfa
--- /dev/null
+++ b/mit-pthreads/machdep/sunos-5.5/__time.h
@@ -0,0 +1,69 @@
+/* ==== timers.h ============================================================
+ * Copyright (c) 1994 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ *
+ * Description : System specific time header.
+ *
+ * 1.00 94/11/07 proven
+ * -Started coding this file.
+ */
+
+#ifndef _SYS___TIME_H_
+#define _SYS___TIME_H_
+
+#include <sys/feature_tests.h>
+
+#ifndef _SIZE_T
+#define _SIZE_T
+typedef unsigned size_t;
+#endif
+#ifndef _CLOCK_T
+#define _CLOCK_T
+typedef long clock_t;
+#endif
+#ifndef _TIME_T
+#define _TIME_T
+typedef long time_t;
+#endif
+#ifndef _CLOCKID_T
+#define _CLOCKID_T
+typedef int clockid_t;
+#endif
+#ifndef _TIMER_T
+#define _TIMER_T
+typedef int timer_t;
+#endif
+
+#include <sys/time.h>
+#include <sys/siginfo.h>
+
+#endif
diff --git a/mit-pthreads/machdep/sunos-5.5/__unistd.h b/mit-pthreads/machdep/sunos-5.5/__unistd.h
new file mode 100755
index 00000000000..4e83a863735
--- /dev/null
+++ b/mit-pthreads/machdep/sunos-5.5/__unistd.h
@@ -0,0 +1,47 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)stdlib.h 5.13 (Berkeley) 6/4/91
+ * $Id$
+ */
+
+#ifndef _SYS___UNISTD_H_
+#define _SYS___UNISTD_H_
+
+#include <sys/types.h>
+#include <sys/unistd.h>
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#endif
diff --git a/mit-pthreads/machdep/sunos-5.5/cdefs.h b/mit-pthreads/machdep/sunos-5.5/cdefs.h
new file mode 100755
index 00000000000..f95f7b36958
--- /dev/null
+++ b/mit-pthreads/machdep/sunos-5.5/cdefs.h
@@ -0,0 +1,59 @@
+/* ==== cdefs.h ============================================================
+ * Copyright (c) 1994 by Chris Provenzano, proven@athena.mit.edu
+ *
+ * Description : Similar to the BSD cdefs.h file.
+ *
+ * 1.00 94/01/26 proven
+ * -Started coding this file.
+ */
+
+#ifndef _PTHREAD_SYS_CDEFS_H_
+#define _PTHREAD_SYS_CDEFS_H_
+
+/* Stuff for compiling */
+#if defined(__GNUC__)
+#if defined(__cplusplus)
+#define __INLINE static inline
+#define __BEGIN_DECLS extern "C" {
+#define __END_DECLS };
+#else
+#define __INLINE extern inline
+#define __CAN_DO_EXTERN_INLINE
+#define __BEGIN_DECLS
+#define __END_DECLS
+#define const __const
+#define inline __inline
+#define signed __signed
+#define volatile __volatile
+#endif
+#else /* !__GNUC__ */
+#define __BEGIN_DECLS
+#define __END_DECLS
+#define __INLINE static
+#endif
+
+#ifndef __NORETURN
+#define __NORETURN
+#endif /* __NORETURN not defined. */
+
+#ifndef _U_INT32_T_
+#define _U_INT32_T_
+typedef unsigned int u_int32_t;
+#endif
+
+#ifndef _U_INT16_T_
+#define _U_INT16_T_
+typedef unsigned short u_int16_t;
+#endif
+
+#ifndef _INT32_T_
+#define _INT32_T_
+typedef int int32_t;
+#endif
+
+#ifndef _INT16_T_
+#define _INT16_T_
+typedef short int16_t;
+#endif
+
+#endif
diff --git a/mit-pthreads/machdep/sunos-5.5/compat.h b/mit-pthreads/machdep/sunos-5.5/compat.h
new file mode 100755
index 00000000000..b2a846d00ee
--- /dev/null
+++ b/mit-pthreads/machdep/sunos-5.5/compat.h
@@ -0,0 +1,45 @@
+/* ==== compat.h ============================================================
+ * Copyright (c) 1994 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ *
+ * Description : Basic timers header.
+ *
+ * 1.00 94/06/13 proven
+ * -Started coding this file.
+ */
+
+#ifndef _SYS_COMPAT_H_
+#define _SYS_COMPAT_H_
+
+#define omsghdr msghdr
+
+#endif
diff --git a/mit-pthreads/machdep/sunos-5.5/dirent.h b/mit-pthreads/machdep/sunos-5.5/dirent.h
new file mode 100755
index 00000000000..303d3d7df2b
--- /dev/null
+++ b/mit-pthreads/machdep/sunos-5.5/dirent.h
@@ -0,0 +1,64 @@
+/*-
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)dirent.h 5.18 (Berkeley) 2/23/91
+ */
+
+#ifndef _SYS_DIRENT_H_
+#define _SYS_DIRENT_H_
+
+/*
+ * A directory entry has a struct dirent at the front of it, containing its
+ * inode number, the length of the entry, and the length of the name
+ * contained in the entry. These are followed by the name padded to a 4
+ * byte boundary with null bytes. All names are guaranteed null terminated.
+ * The maximum length of a name in a directory is MAXNAMLEN.
+ */
+
+struct dirent {
+ u_long d_fileno; /* file number of entry */
+ off_t d_off; /* offset of next disk dir entry */
+ u_short d_reclen; /* length of this record */
+#ifdef _POSIX_SOURCE
+ char d_name[255 + 1]; /* name must be no longer than this */
+#else
+#define MAXNAMLEN 255
+ char d_name[MAXNAMLEN + 1]; /* name must be no longer than this */
+#endif
+};
+
+#define d_namlen d_reclen
+#define d_ino d_fileno
+
+#endif /* !_SYS_DIRENT_H_ */
+
+
diff --git a/mit-pthreads/machdep/sunos-5.5/socket.h b/mit-pthreads/machdep/sunos-5.5/socket.h
new file mode 100755
index 00000000000..0b075622fed
--- /dev/null
+++ b/mit-pthreads/machdep/sunos-5.5/socket.h
@@ -0,0 +1,180 @@
+/*
+ * Copyright (c) 1982, 1985, 1986 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * @(#)socket.h 7.3 (Berkeley) 6/27/88
+ */
+
+#ifndef _SYS_SOCKET_H
+#define _SYS_SOCKET_H
+
+/*
+ * Types of sockets
+ */
+#define SOCK_STREAM 2 /* stream socket */
+#define SOCK_DGRAM 1 /* datagram socket */
+#define SOCK_RAW 4 /* raw-protocol interface */
+#define SOCK_RDM 5 /* reliably-delivered message */
+#define SOCK_SEQPACKET 6 /* sequenced packet stream */
+
+/*
+ * Option flags per-socket.
+ */
+#define SO_DEBUG 0x0001 /* turn on debugging info recording */
+#define SO_ACCEPTCONN 0x0002 /* socket has had listen() */
+#define SO_REUSEADDR 0x0004 /* allow local address reuse */
+#define SO_KEEPALIVE 0x0008 /* keep connections alive */
+#define SO_DONTROUTE 0x0010 /* just use interface addresses */
+#define SO_BROADCAST 0x0020 /* permit sending of broadcast msgs */
+#define SO_USELOOPBACK 0x0040 /* bypass hardware when possible */
+#define SO_LINGER 0x0080 /* linger on close if data present */
+#define SO_OOBINLINE 0x0100 /* leave received OOB data in line */
+
+/*
+ * Additional options, not kept in so_options.
+ */
+#define SO_SNDBUF 0x1001 /* send buffer size */
+#define SO_RCVBUF 0x1002 /* receive buffer size */
+#define SO_SNDLOWAT 0x1003 /* send low-water mark */
+#define SO_RCVLOWAT 0x1004 /* receive low-water mark */
+#define SO_SNDTIMEO 0x1005 /* send timeout */
+#define SO_RCVTIMEO 0x1006 /* receive timeout */
+#define SO_ERROR 0x1007 /* get error status and clear */
+#define SO_TYPE 0x1008 /* get socket type */
+#define SO_PROTOTYPE 0x1009 /* get/set protocol type */
+
+/*
+ * Level number for (get/set)sockopt() to apply to socket itself.
+ */
+#define SOL_SOCKET 0xffff /* options for socket level */
+
+/*
+ * Address families.
+ */
+#define AF_UNSPEC 0 /* unspecified */
+#define AF_UNIX 1 /* local to host (pipes, portals) */
+#define AF_INET 2 /* internetwork: UDP, TCP, etc. */
+#define AF_IMPLINK 3 /* arpanet imp addresses */
+#define AF_PUP 4 /* pup protocols: e.g. BSP */
+#define AF_CHAOS 5 /* mit CHAOS protocols */
+#define AF_NS 6 /* XEROX NS protocols */
+#define AF_NBS 7 /* nbs protocols */
+#define AF_ECMA 8 /* european computer manufacturers */
+#define AF_DATAKIT 9 /* datakit protocols */
+#define AF_CCITT 10 /* CCITT protocols, X.25 etc */
+#define AF_SNA 11 /* IBM SNA */
+#define AF_DECnet 12 /* DECnet */
+#define AF_DLI 13 /* Direct data link interface */
+#define AF_LAT 14 /* LAT */
+#define AF_HYLINK 15 /* NSC Hyperchannel */
+#define AF_APPLETALK 16 /* Apple Talk */
+#define AF_NIT 17 /* NIT */
+#define AF_802 18 /* IEEE 802.2, also ISO 8802 */
+#define AF_ISO 19 /* ISO protocols */
+#define AF_OSI AF_ISO
+#define AF_X25 20 /* CCITT X.25 in particular */
+#define AF_OSINET 21
+#define AF_GOSIP 22
+#define AF_MAX 22
+
+/*
+ * Structure used by kernel to store most
+ * addresses.
+ */
+struct sockaddr {
+ unsigned short sa_family; /* address family */
+ char sa_data[14]; /* up to 14 bytes of direct address */
+};
+
+/*
+ * Structure used by kernel to pass protocol
+ * information in raw sockets.
+ */
+struct sockproto {
+ unsigned short sp_family; /* address family */
+ unsigned short sp_protocol; /* protocol */
+};
+
+/*
+ * Protocol families, same as address families for now.
+ */
+#define PF_UNSPEC AF_UNSPEC
+#define PF_UNIX AF_UNIX
+#define PF_INET AF_INET
+#define PF_IMPLINK AF_IMPLINK
+#define PF_PUP AF_PUP
+#define PF_CHAOS AF_CHAOS
+#define PF_NS AF_NS
+#define PF_NBS AF_NBS
+#define PF_ECMA AF_ECMA
+#define PF_DATAKIT AF_DATAKIT
+#define PF_CCITT AF_CCITT
+#define PF_SNA AF_SNA
+#define PF_DECnet AF_DECnet
+#define PF_DLI AF_DLI
+#define PF_LAT AF_LAT
+#define PF_HYLINK AF_HYLINK
+#define PF_APPLETALK AF_APPLETALK
+#define PF_NIT AF_NIT
+#define PF_802 AF_802
+#define PF_ISO AF_ISO
+#define PF_OSI AF_ISO
+#define PF_X25 AF_X25
+#define PF_OSINET AF_OSINET
+#define PF_GOSIP AF_GOSIP
+#define PF_MAX AF_MAX
+
+/*
+ * Maximum queue length specifiable by listen.
+ */
+#define SOMAXCONN 5
+
+/*
+ * Message header for recvmsg and sendmsg calls.
+ */
+struct msghdr {
+ caddr_t msg_name; /* optional address */
+ int msg_namelen; /* size of address */
+ struct iovec *msg_iov; /* scatter/gather array */
+ int msg_iovlen; /* # elements in msg_iov */
+ caddr_t msg_accrights; /* access rights sent/received */
+ int msg_accrightslen;
+};
+
+#define MSG_OOB 0x1 /* process out-of-band data */
+#define MSG_PEEK 0x2 /* peek at incoming message */
+#define MSG_DONTROUTE 0x4 /* send without using routing tables */
+
+#define MSG_MAXIOVLEN 16
+
+#include <sys/cdefs.h>
+/*
+ * Functions
+ */
+
+__BEGIN_DECLS
+
+int accept __P_((int, struct sockaddr *, int *));
+int bind __P_((int, const struct sockaddr *, int));
+int connect __P_((int, const struct sockaddr *, int));
+int listen __P_((int, int));
+int socket __P_((int, int, int));
+int setsockopt __P_((int, int, int, const void *, int));
+int getsockname __P_((int, struct sockaddr *, int *));
+int shutdown __P_((int, int));
+int getpeername __P_((int, struct sockaddr *, int *));
+__END_DECLS
+
+#endif /* _SYS_SOCKET_H */
diff --git a/mit-pthreads/machdep/sunos-5.5/timers.h b/mit-pthreads/machdep/sunos-5.5/timers.h
new file mode 100755
index 00000000000..3aad5f80065
--- /dev/null
+++ b/mit-pthreads/machdep/sunos-5.5/timers.h
@@ -0,0 +1,70 @@
+/* ==== timers.h ============================================================
+ * Copyright (c) 1994 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ *
+ * Description : Basic timers header.
+ *
+ * 1.00 94/06/13 proven
+ * -Started coding this file.
+ */
+
+#ifndef _SYS_TIMERS_H_
+#define _SYS_TIMERS_H_
+
+#include <sys/types.h>
+#include <time.h>
+
+#define tv_sec tv_sec
+#define tv_nsec tv_nsec
+
+#define TIMEVAL_TO_TIMESPEC(tv, ts) { \
+ (ts)->tv_sec = (tv)->tv_sec; \
+ (ts)->tv_nsec = (tv)->tv_usec * 1000; \
+}
+#define TIMESPEC_TO_TIMEVAL(tv, ts) { \
+ (tv)->tv_sec = (ts)->tv_sec; \
+ (tv)->tv_usec = (ts)->tv_nsec / 1000; \
+}
+
+/*
+ * New functions
+ */
+
+#ifdef NOT_USED
+int gettimeofday __P_((struct timeval *,struct timezone *)); /* for sleep.h */
+#endif
+
+__BEGIN_DECLS
+
+__END_DECLS
+
+#endif
diff --git a/mit-pthreads/machdep/sunos-5.5/uio.h b/mit-pthreads/machdep/sunos-5.5/uio.h
new file mode 100755
index 00000000000..7786142dd87
--- /dev/null
+++ b/mit-pthreads/machdep/sunos-5.5/uio.h
@@ -0,0 +1,40 @@
+/* ==== uio.h ============================================================
+ * Copyright (c) 1994 by Chris Provenzano, proven@athena.mit.edu
+ *
+ * Description : Correct Solaris header file.
+ */
+
+#ifndef _PTHREAD_UIO_H_
+#define _PTHREAD_UIO_H_
+
+#include <sys/cdefs.h>
+
+struct iovec {
+ void *iov_base;
+ size_t iov_len;
+};
+
+typedef struct iovec iovec_t;
+
+struct uio {
+ iovec_t *uio_iov; /* pointer to array of iovecs */
+ int uio_iovcnt; /* number of iovecs */
+ /* These are all bogus */
+ int _uio_offset; /* file offset */
+ int uio_segflg; /* address space (kernel or user) */
+ short uio_fmode; /* file mode flags */
+ int _uio_limit; /* u-limit (maximum "block" offset) */
+ int uio_resid; /* residual count */
+};
+
+typedef struct uio uio_t;
+
+__BEGIN_DECLS
+
+int readv __P_((int, const struct iovec *, int));
+int writev __P_((int, const struct iovec *, int));
+
+__END_DECLS
+
+#endif
+
diff --git a/mit-pthreads/machdep/syscall-alpha-netbsd-1.1.S b/mit-pthreads/machdep/syscall-alpha-netbsd-1.1.S
new file mode 100644
index 00000000000..5b7dd017426
--- /dev/null
+++ b/mit-pthreads/machdep/syscall-alpha-netbsd-1.1.S
@@ -0,0 +1,206 @@
+#include <machine/asm.h>
+#define CHMK() call_pal 0x83
+#define COMPAT_43
+#include <sys/syscall.h>
+#ifndef __CONCAT
+#include <sys/cdefs.h>
+#endif
+#define CONCAT __CONCAT
+
+#undef SYSCALL
+
+/* Kernel syscall interface:
+ Input:
+ v0 - system call number
+ a* - arguments, as in C
+ Output:
+ a3 - zero iff successful
+ v0 - errno value on failure, else result
+
+ This macro is similar to SYSCALL in asm.h, but not completely.
+ There's room for optimization, if we assume this will continue to
+ be assembled as one file.
+
+ This macro expansions does not include the return instruction.
+ If there's no other work to be done, use something like:
+ SYSCALL(foo) ; ret
+ If there is other work to do (in fork, maybe?), do it after the
+ SYSCALL invocation. */
+
+#define SYSCALL(x) \
+ .align 4 ;\
+ .globl CONCAT(machdep_sys_,x) ;\
+ .ent CONCAT(machdep_sys_,x), 0 ;\
+CONCAT(machdep_sys_,x): ;\
+ .frame sp,0,ra ;\
+ ldiq v0, CONCAT(SYS_,x) ;\
+ CHMK() ;\
+ beq a3, CONCAT(Lsys_noerr_,x) ;\
+ br gp, CONCAT(Lsys_err_,x) ;\
+CONCAT(Lsys_err_,x): ;\
+ /* Load gp so we can find cerror to jump to. */;\
+ ldgp gp, 0(gp) ;\
+ jmp zero, machdep_cerror ;\
+CONCAT(Lsys_noerr_,x):
+
+#define XSYSCALL(x) SYSCALL(x) ; RET ; .end CONCAT(machdep_sys_,x)
+
+ .globl machdep_cerror
+machdep_cerror:
+ br t0, Lmachdep_cerror_setgp
+Lmachdep_cerror_setgp:
+ ldgp gp, 0(t0)
+ stl v0, errno
+#if 0
+ ldiq v0, -1
+#else
+ subq zero, v0, v0
+#endif
+ RET
+
+/* The fork system call is special... */
+SYSCALL(fork)
+ cmovne a4, 0, v0
+ RET
+ .end machdep_sys_fork
+
+/* The pipe system call is special... */
+SYSCALL(pipe)
+ stl v0, 0(a0)
+ stl a4, 4(a0)
+ mov zero, v0
+ RET
+ .end machdep_sys_pipe
+
+/* The sigsuspend system call is special... */
+ .align 4
+ .globl machdep_sys_sigsuspend
+ .ent machdep_sys_sigsuspend, 0
+machdep_sys_sigsuspend:
+ ldl a0, 0(a0) /* pass *mask instead of mask */
+ ldiq v0, SYS_sigsuspend
+ CHMK()
+ mov zero, v0 /* shouldn't need; just in case... */
+ RET
+ .end machdep_sys_sigsuspend
+
+/* The sigprocmask system call is special... */
+ .align 4
+ .globl machdep_sys_sigprocmask
+ .ent machdep_sys_sigprocmask, 0
+machdep_sys_sigprocmask:
+ mov a2, a5 /* safe */
+ cmoveq a1, 1, a0 /* if set == NULL, how = SIG_BLOCK */
+ beq a1, Ldoit /* and set = 0, and do it. */
+ ldl a1, 0(a1) /* load the set from *set */
+Ldoit: ldiq v0, SYS_sigprocmask
+ CHMK()
+ beq a5, Lret /* if they don't want old mask, done */
+ stl v0, 0(a5) /* otherwise, give it to them. */
+Lret: mov zero, v0
+ RET
+ .end machdep_sys_sigprocmask
+
+/* More stuff ... */
+ .align 4
+ .global __machdep_save_int_state
+ .ent __machdep_save_int_state, 0
+__machdep_save_int_state:
+ .frame sp, 16, ra
+ ldgp gp, 0(t12)
+ lda sp, -16(sp)
+ stq ra, 0(sp)
+
+ /* save integer registers */
+ stq ra, ( 0 * 8)(a0) /* return address */
+ stq s0, ( 1 * 8)(a0) /* callee-saved registers */
+ stq s1, ( 2 * 8)(a0)
+ stq s2, ( 3 * 8)(a0)
+ stq s3, ( 4 * 8)(a0)
+ stq s4, ( 5 * 8)(a0)
+ stq s5, ( 6 * 8)(a0)
+ stq s6, ( 7 * 8)(a0)
+ stq sp, ( 9 * 8)(a0)
+ stq ra, ( 8 * 8)(a0) /* RA on return */
+ stq pv, (10 * 8)(a0) /* and PV; we restore it */
+
+ mov zero, v0
+ lda sp, 16(sp)
+ RET
+ .end __machdep_save_int_state
+
+ .align 4
+ .global __machdep_restore_int_state
+ .ent __machdep_restore_int_state, 0
+__machdep_restore_int_state:
+ .frame sp, 16, ra
+ ldgp gp, 0(t12)
+ lda sp, -16(sp)
+ stq ra, 0(sp)
+
+ /* restore integer registers */
+ ldq t0, ( 0 * 8)(a0) /* return address */
+ ldq s0, ( 1 * 8)(a0) /* callee-saved registers */
+ ldq s1, ( 2 * 8)(a0)
+ ldq s2, ( 3 * 8)(a0)
+ ldq s3, ( 4 * 8)(a0)
+ ldq s4, ( 5 * 8)(a0)
+ ldq s5, ( 6 * 8)(a0)
+ ldq s6, ( 7 * 8)(a0)
+ ldq ra, ( 8 * 8)(a0) /* RA after return */
+ ldq sp, ( 9 * 8)(a0)
+ ldq pv, (10 * 8)(a0) /* and PV; we restore it */
+
+ ldiq v0, 1
+ ret zero,(t0),1
+ .end __machdep_restore_int_state
+
+ .align 4
+ .global __machdep_save_fp_state
+ .ent __machdep_save_fp_state, 0
+__machdep_save_fp_state:
+ .frame sp, 16, ra
+ ldgp gp, 0(t12)
+ lda sp, -16(sp)
+ stq ra, 0(sp)
+
+ /* save FP registers */
+ stt fs0, (0 * 8)(a0) /* callee-saved registers */
+ stt fs1, (1 * 8)(a0)
+ stt fs2, (2 * 8)(a0)
+ stt fs3, (3 * 8)(a0)
+ stt fs4, (4 * 8)(a0)
+ stt fs5, (5 * 8)(a0)
+ stt fs6, (6 * 8)(a0)
+ stt fs7, (7 * 8)(a0)
+ mf_fpcr ft0 /* and FP control reg */
+ stt ft0, (8 * 8)(a0)
+
+ lda sp, 16(sp)
+ RET
+ .end __machdep_save_fp_state
+
+ .align 4
+ .global __machdep_restore_fp_state
+ .ent __machdep_restore_fp_state, 0
+__machdep_restore_fp_state:
+ .frame sp, 16, ra
+ ldgp gp, 0(t12)
+ lda sp, -16(sp)
+ stq ra, 0(sp)
+
+ /* restore FP registers */
+ ldt fs0, (0 * 8)(a0) /* callee-saved registers */
+ ldt fs1, (1 * 8)(a0)
+ ldt fs2, (2 * 8)(a0)
+ ldt fs3, (3 * 8)(a0)
+ ldt fs4, (4 * 8)(a0)
+ ldt fs5, (5 * 8)(a0)
+ ldt fs6, (6 * 8)(a0)
+ ldt fs7, (7 * 8)(a0)
+ ldt ft0, (8 * 8)(a0)
+ mt_fpcr ft0 /* and FP control reg */
+
+ lda sp, 16(sp)
+ RET
+ .end __machdep_restore_fp_state
diff --git a/mit-pthreads/machdep/syscall-alpha-netbsd-1.3.S b/mit-pthreads/machdep/syscall-alpha-netbsd-1.3.S
new file mode 100644
index 00000000000..61435a729d7
--- /dev/null
+++ b/mit-pthreads/machdep/syscall-alpha-netbsd-1.3.S
@@ -0,0 +1,228 @@
+#include <machine/asm.h>
+#define CHMK() call_pal 0x83
+#define COMPAT_43
+#include <sys/syscall.h>
+#ifndef __CONCAT
+#include <sys/cdefs.h>
+#endif
+#define CONCAT __CONCAT
+
+#undef SYSCALL
+
+/* Kernel syscall interface:
+ Input:
+ v0 - system call number
+ a* - arguments, as in C
+ Output:
+ a3 - zero iff successful
+ v0 - errno value on failure, else result
+
+ This macro is similar to SYSCALL in asm.h, but not completely.
+ There's room for optimization, if we assume this will continue to
+ be assembled as one file.
+
+ This macro expansions does not include the return instruction.
+ If there's no other work to be done, use something like:
+ SYSCALL(foo) ; ret
+ If there is other work to do (in fork, maybe?), do it after the
+ SYSCALL invocation. */
+
+#define SYSCALL(x) \
+ .align 4 ;\
+ .globl CONCAT(machdep_sys_,x) ;\
+ .ent CONCAT(machdep_sys_,x), 0 ;\
+CONCAT(machdep_sys_,x): ;\
+ .frame sp,0,ra ;\
+ ldiq v0, CONCAT(SYS_,x) ;\
+ CHMK() ;\
+ beq a3, CONCAT(Lsys_noerr_,x) ;\
+ br gp, CONCAT(Lsys_err_,x) ;\
+CONCAT(Lsys_err_,x): ;\
+ /* Load gp so we can find cerror to jump to. */;\
+ ldgp gp, 0(gp) ;\
+ jmp zero, machdep_cerror ;\
+CONCAT(Lsys_noerr_,x):
+
+#define XSYSCALL(x) SYSCALL(x) ; RET ; .end CONCAT(machdep_sys_,x)
+
+ .globl machdep_cerror
+machdep_cerror:
+ br t0, Lmachdep_cerror_setgp
+Lmachdep_cerror_setgp:
+ ldgp gp, 0(t0)
+ stl v0, errno
+#if 0
+ ldiq v0, -1
+#else
+ subq zero, v0, v0
+#endif
+ RET
+
+/* The fork system call is special... */
+SYSCALL(fork)
+ cmovne a4, 0, v0
+ RET
+ .end machdep_sys_fork
+
+/* The pipe system call is special... */
+SYSCALL(pipe)
+ stl v0, 0(a0)
+ stl a4, 4(a0)
+ mov zero, v0
+ RET
+ .end machdep_sys_pipe
+
+#ifndef SYS___sigsuspend14
+/* The sigsuspend system call is special... */
+ .align 4
+ .globl machdep_sys_sigsuspend
+ .ent machdep_sys_sigsuspend, 0
+machdep_sys_sigsuspend:
+ ldl a0, 0(a0) /* pass *mask instead of mask */
+ ldiq v0, SYS_sigsuspend
+ CHMK()
+ mov zero, v0 /* shouldn't need; just in case... */
+ RET
+ .end machdep_sys_sigsuspend
+#endif /* SYS_sigsuspend14 */
+
+#ifndef SYS___sigprocmask14
+/* The sigprocmask system call is special... */
+ .align 4
+ .globl machdep_sys_sigprocmask
+ .ent machdep_sys_sigprocmask, 0
+machdep_sys_sigprocmask:
+ mov a2, a5 /* safe */
+ cmoveq a1, 1, a0 /* if set == NULL, how = SIG_BLOCK */
+ beq a1, Ldoit /* and set = 0, and do it. */
+ ldl a1, 0(a1) /* load the set from *set */
+Ldoit: ldiq v0, SYS_sigprocmask
+ CHMK()
+ beq a5, Lret /* if they don't want old mask, done */
+ stl v0, 0(a5) /* otherwise, give it to them. */
+Lret: mov zero, v0
+ RET
+ .end machdep_sys_sigprocmask
+#endif /* SYS_sigprocmask14 */
+
+/* More stuff ... */
+ .align 4
+ .global __machdep_save_int_state
+ .ent __machdep_save_int_state, 0
+__machdep_save_int_state:
+ .frame sp, 16, ra
+ ldgp gp, 0(t12)
+ lda sp, -16(sp)
+ stq ra, 0(sp)
+
+ /* save integer registers */
+ stq ra, ( 0 * 8)(a0) /* return address */
+ stq s0, ( 1 * 8)(a0) /* callee-saved registers */
+ stq s1, ( 2 * 8)(a0)
+ stq s2, ( 3 * 8)(a0)
+ stq s3, ( 4 * 8)(a0)
+ stq s4, ( 5 * 8)(a0)
+ stq s5, ( 6 * 8)(a0)
+ stq s6, ( 7 * 8)(a0)
+ stq sp, ( 9 * 8)(a0)
+ stq ra, ( 8 * 8)(a0) /* RA on return */
+ stq pv, (10 * 8)(a0) /* and PV; we restore it */
+
+ mov zero, v0
+ lda sp, 16(sp)
+ RET
+ .end __machdep_save_int_state
+
+ .align 4
+ .global __machdep_restore_int_state
+ .ent __machdep_restore_int_state, 0
+__machdep_restore_int_state:
+ .frame sp, 16, ra
+ ldgp gp, 0(t12)
+ lda sp, -16(sp)
+ stq ra, 0(sp)
+
+ /* restore integer registers */
+ ldq t0, ( 0 * 8)(a0) /* return address */
+ ldq s0, ( 1 * 8)(a0) /* callee-saved registers */
+ ldq s1, ( 2 * 8)(a0)
+ ldq s2, ( 3 * 8)(a0)
+ ldq s3, ( 4 * 8)(a0)
+ ldq s4, ( 5 * 8)(a0)
+ ldq s5, ( 6 * 8)(a0)
+ ldq s6, ( 7 * 8)(a0)
+ ldq ra, ( 8 * 8)(a0) /* RA after return */
+ ldq sp, ( 9 * 8)(a0)
+ ldq pv, (10 * 8)(a0) /* and PV; we restore it */
+
+ ldiq v0, 1
+ ret zero,(t0),1
+ .end __machdep_restore_int_state
+
+ .align 4
+ .global __machdep_save_fp_state
+ .ent __machdep_save_fp_state, 0
+__machdep_save_fp_state:
+ .frame sp, 16, ra
+ ldgp gp, 0(t12)
+ lda sp, -16(sp)
+ stq ra, 0(sp)
+
+ /* save FP registers */
+ stt fs0, (0 * 8)(a0) /* callee-saved registers */
+ stt fs1, (1 * 8)(a0)
+ stt fs2, (2 * 8)(a0)
+ stt fs3, (3 * 8)(a0)
+ stt fs4, (4 * 8)(a0)
+ stt fs5, (5 * 8)(a0)
+ stt fs6, (6 * 8)(a0)
+ stt fs7, (7 * 8)(a0)
+ mf_fpcr ft0 /* and FP control reg */
+ stt ft0, (8 * 8)(a0)
+
+ lda sp, 16(sp)
+ RET
+ .end __machdep_save_fp_state
+
+ .align 4
+ .global __machdep_restore_fp_state
+ .ent __machdep_restore_fp_state, 0
+__machdep_restore_fp_state:
+ .frame sp, 16, ra
+ ldgp gp, 0(t12)
+ lda sp, -16(sp)
+ stq ra, 0(sp)
+
+ /* restore FP registers */
+ ldt fs0, (0 * 8)(a0) /* callee-saved registers */
+ ldt fs1, (1 * 8)(a0)
+ ldt fs2, (2 * 8)(a0)
+ ldt fs3, (3 * 8)(a0)
+ ldt fs4, (4 * 8)(a0)
+ ldt fs5, (5 * 8)(a0)
+ ldt fs6, (6 * 8)(a0)
+ ldt fs7, (7 * 8)(a0)
+ ldt ft0, (8 * 8)(a0)
+ mt_fpcr ft0 /* and FP control reg */
+
+ lda sp, 16(sp)
+ RET
+ .end __machdep_restore_fp_state
+
+/* For fstat() we actually syscall fstat13. */
+ .align 4
+ .globl machdep_sys_fstat
+ .ent machdep_sys_fstat, 0
+machdep_sys_fstat:
+ .frame sp,0,ra
+ ldiq v0, SYS___fstat13
+ CHMK()
+ beq a3, Lsys_noerr_fstat
+ br gp, Lsys_err_fstat
+Lsys_err_fstat:
+ /* Load gp so we can find cerror to jump to. */
+ ldgp gp, 0(gp)
+ jmp zero, machdep_cerror
+Lsys_noerr_fstat:
+ RET
+ .end machdep_sys_fstat
diff --git a/mit-pthreads/machdep/syscall-alpha-osf1.S b/mit-pthreads/machdep/syscall-alpha-osf1.S
new file mode 100644
index 00000000000..fad823a7352
--- /dev/null
+++ b/mit-pthreads/machdep/syscall-alpha-osf1.S
@@ -0,0 +1,97 @@
+#include <asm.h>
+#include <regdef.h>
+#define COMPAT_43
+#include <syscall.h>
+
+#undef SYSCALL
+
+/* Kernel syscall interface:
+ Input:
+ v0 - system call number
+ a* - arguments, as in C
+ Output:
+ a3 - zero iff successful
+ v0 - errno value on failure, else result
+
+ This macro is similar to SYSCALL in asm.h, but not completely.
+ There's room for optimization, if we assume this will continue to
+ be assembled as one file.
+
+ This macro expansions does not include the return instruction.
+ If there's no other work to be done, use something like:
+ SYSCALL(foo) ; ret
+ If there is other work to do (in fork, maybe?), do it after the
+ SYSCALL invocation. */
+
+#define SYSCALL(x) \
+ .align 4 ;\
+ .globl machdep_sys_##x ;\
+ .ent machdep_sys_##x, 0 ;\
+machdep_sys_##x: ;\
+ .frame sp,0,ra ;\
+ ldiq v0, SYS_##x ;\
+ CHMK() ;\
+ beq a3, 2f ;\
+ br gp, 1f ;\
+1: ;\
+ /* Load gp so we can find cerror to jump to. */;\
+ ldgp gp, 0(gp) ;\
+ jmp zero, machdep_cerror ;\
+2:
+
+#define XSYSCALL(x) SYSCALL(x) ; ret ; .end machdep_sys_##x
+
+ .globl machdep_cerror
+machdep_cerror:
+ br t0, 1f
+1:
+ ldgp gp, 0(t0)
+ stl v0, errno
+#if 0
+ ldiq v0, -1
+#else
+ subq zero, v0, v0
+#endif
+ ret
+
+/* The fork system call is special... */
+SYSCALL(fork)
+ cmovne a4, 0, v0
+ ret
+ .end machdep_sys_fork
+
+/* So is the sigsuspend system call */
+ .align 4
+ .globl machdep_sys_sigsuspend
+ .ent machdep_sys_sigsuspend, 0
+machdep_sys_sigsuspend:
+ .frame sp,0,ra
+
+ bis a0, a0, a1
+ ldq a0, 0(a1)
+ ldiq v0, SYS_sigsuspend
+ CHMK()
+ ret
+ .end machdep_sys_sigsuspend
+
+/* More stuff ... */
+ .align 4
+ .globl machdep_restore_from_setjmp
+ .ent machdep_restore_from_setjmp, 0
+machdep_restore_from_setjmp:
+ .frame sp, 16, ra
+ ldgp gp, 0(t12)
+ lda sp, -16(sp)
+ stq ra, 0(sp)
+ ldq v0, 280(a0)
+ subq v0, 0x00000000acedbade, t0
+ bne t0, botch
+ cmoveq a1, 0x1, a1
+ stq a1, 32(a0)
+ ldiq v0, 0x67
+ call_pal 0x83
+botch:
+ /* This should cause the program to crash. Eventually, fix it
+ up to print a message first. */
+ jsr abort
+ .end machdep_restore_from_setjmp
diff --git a/mit-pthreads/machdep/syscall-arm32-netbsd-1.3.S b/mit-pthreads/machdep/syscall-arm32-netbsd-1.3.S
new file mode 100644
index 00000000000..5914674b508
--- /dev/null
+++ b/mit-pthreads/machdep/syscall-arm32-netbsd-1.3.S
@@ -0,0 +1,193 @@
+/* ==== syscall.S ============================================================
+ * Copyright (c) 1990 The Regents of the University of California.
+ * Copyright (c) 1993 Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Description : Machine dependent syscalls for i386/i486/i586
+ *
+ * 1.00 93/08/26 proven
+ * -Started coding this file.
+ *
+ * 1.01 93/11/13 proven
+ * -The functions readv() and writev() added.
+ */
+
+#ifndef lint
+ .text
+ .asciz "$Id$";
+#endif
+
+#if defined(SYSLIBC_SCCS) && !defined(lint)
+ .asciz "@(#)syscall.s 5.1 (Berkeley) 4/23/90"
+#endif /* SYSLIBC_SCCS and not lint */
+
+#include <machine/asm.h>
+#include <sys/syscall.h>
+
+/*
+ * Initial asm stuff for all functions.
+ */
+ .text
+ .align 0
+
+
+/* ==========================================================================
+ * machdep_sys_fork()
+ */
+ .globl _C_LABEL(machdep_sys_fork);
+
+_C_LABEL(machdep_sys_fork):;
+
+ swi SYS_fork
+ bcs 1f
+ sub r1, r1, #0x00000001
+ and r0, r0, r1
+ mov r15, r14
+
+
+
+/* ==========================================================================
+ * machdep_sys_fstat()
+ */
+ .globl _C_LABEL(machdep_sys_fstat);
+
+_C_LABEL(machdep_sys_fstat):;
+
+ swi SYS___fstat13
+ bcs 1f
+ mov r15, r14
+
+/* ==========================================================================
+ * machdep_sys___syscall()
+ */
+
+_machdep_sys___syscall:;
+
+ swi SYS___syscall
+ bcs 1f
+ mov r15, r14
+
+
+#ifndef SYS___sigsuspend14
+/* ==========================================================================
+ * machdep_sys_sigsuspend()
+ */
+ .globl _C_LABEL(machdep_sys_sigsuspend);
+
+_C_LABEL(machdep_sys_sigsuspend):;
+
+ ldr r0, [r0]
+ swi SYS_sigsuspend
+ bcs 1f
+ mov r0, #0x00000000
+ mov r15, r14
+
+#endif
+
+#ifndef SYS___sigprocmask14
+/* ==========================================================================
+ * machdep_sys_sigprocmask()
+ */
+ .globl _C_LABEL(machdep_sys_sigprocmask);
+
+_C_LABEL(machdep_sys_sigprocmask):;
+
+ teq r1, #0x00000000
+ moveq r0, #0x00000001
+ moveq r1, #0x00000000
+ ldrne r1, [r1]
+ swi SYS_sigprocmask
+ bcs 1f
+ teq r2, #0x00000000
+ strne r0, [r2]
+ mov r0, #0x00000000
+ mov r15, r14
+#endif
+
+/* ==========================================================================
+ * machdep_sys_ftruncate()
+ */
+ .global _C_LABEL(machdep_sys_ftruncate)
+_C_LABEL(machdep_sys_ftruncate):
+ mov r12, r13
+ stmfd r13!, {r11, r12, r14, r15}
+ sub r13, r13, #8
+ stmia r13, {r1-r2}
+ mov r3, #0
+ sub r11, r12, #4
+ mov r2, r0
+ mov r1, #0
+ mov r0, #201
+ bl _machdep_sys___syscall
+ ldmea r11, {r11, r13, r15}
+
+/* ==========================================================================
+ * machdep_sys_lseek()
+ */
+ .global _C_LABEL(machdep_sys_lseek)
+
+_C_LABEL(machdep_sys_lseek):
+ mov r12, r13
+ stmfd r13!, {r11, r12, r14, r15}
+ str r3, [r13, #-4]!
+ sub r13, r13, #8
+ stmia r13, {r1-r2}
+ sub r11, r12, #4
+ mov r3, #0
+ mov r2, r0
+ mov r1, #0
+ mov r0, #SYS_lseek
+ bl _machdep_sys___syscall
+ ldmea r11, {r11, r13, r15}
+
+/* ==========================================================================
+ * machdep_sys_pipe()
+ */
+ .globl _C_LABEL(machdep_sys_pipe);
+
+_C_LABEL(machdep_sys_pipe):;
+
+ mov r2, r0
+ swi SYS_pipe
+ bcs 1f
+ str r0, [r2, #0x0000]
+ str r1, [r2, #0x0004]
+ mov r0, #0x00000000
+ mov r15, r14
+
+
+1:
+ rsb r0, r0, #0x00000000
+ mvn r1, #0x00000000
+ mov r15, r14
diff --git a/mit-pthreads/machdep/syscall-hppa-hpux-10.20.S b/mit-pthreads/machdep/syscall-hppa-hpux-10.20.S
new file mode 100644
index 00000000000..c63d845bae5
--- /dev/null
+++ b/mit-pthreads/machdep/syscall-hppa-hpux-10.20.S
@@ -0,0 +1,23 @@
+ .CODE
+
+machdep_error
+ sub %r0,%r28,%r28
+ bv,n %r0(%r2)
+
+machdep_sys_fork
+
+ .PROC
+ .CALLINFO NO_CALLS,FRAME=0
+
+ ldil -0x80000,%r1
+ ble 4(%sr7,%r1)
+ ldi 2 ,%r22
+ or,= %r0,%r22,%r0
+ b,n machdep_error
+ or,= %r29,%r0,%r0
+ copy %r0,%r28
+ bv,n %r0(%r2)
+
+ .PROCEND
+ .EXPORT machdep_sys_fork,ENTRY
+
diff --git a/mit-pthreads/machdep/syscall-hppa-hpux-9.03.S b/mit-pthreads/machdep/syscall-hppa-hpux-9.03.S
new file mode 100644
index 00000000000..c63d845bae5
--- /dev/null
+++ b/mit-pthreads/machdep/syscall-hppa-hpux-9.03.S
@@ -0,0 +1,23 @@
+ .CODE
+
+machdep_error
+ sub %r0,%r28,%r28
+ bv,n %r0(%r2)
+
+machdep_sys_fork
+
+ .PROC
+ .CALLINFO NO_CALLS,FRAME=0
+
+ ldil -0x80000,%r1
+ ble 4(%sr7,%r1)
+ ldi 2 ,%r22
+ or,= %r0,%r22,%r0
+ b,n machdep_error
+ or,= %r29,%r0,%r0
+ copy %r0,%r28
+ bv,n %r0(%r2)
+
+ .PROCEND
+ .EXPORT machdep_sys_fork,ENTRY
+
diff --git a/mit-pthreads/machdep/syscall-i386-bsdi-1.1.S b/mit-pthreads/machdep/syscall-i386-bsdi-1.1.S
new file mode 100644
index 00000000000..e54cd0d0773
--- /dev/null
+++ b/mit-pthreads/machdep/syscall-i386-bsdi-1.1.S
@@ -0,0 +1,288 @@
+/* ==== syscall.S ============================================================
+ * Copyright (c) 1990 The Regents of the University of California.
+ * Copyright (c) 1993 Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Description : Machine dependent syscalls for i386/i486/i586
+ *
+ * 1.00 93/08/26 proven
+ * -Started coding this file.
+ *
+ * 1.01 93/11/13 proven
+ * -The functions readv() and writev() added.
+ */
+
+#ifndef lint
+ .text
+ .asciz "$Id$";
+#endif
+
+#if defined(SYSLIBC_SCCS) && !defined(lint)
+ .asciz "@(#)syscall.s 5.1 (Berkeley) 4/23/90"
+#endif /* SYSLIBC_SCCS and not lint */
+
+#include <sys/syscall.h>
+
+#define SYSCALL(x) \
+ .globl _machdep_sys_/**/x; \
+ \
+_machdep_sys_/**/x:; \
+ \
+ movl $(SYS_/**/x), %eax; \
+ .byte 0x9a; .long 0; .word 7; \
+ jb 1b; \
+ ret;
+
+/*
+ * Initial asm stuff for all functions.
+ */
+ .text
+ .align 2
+
+
+/* ==========================================================================
+ * error code for all syscalls. The error value is returned as the negative
+ * of the errno value.
+ */
+
+1:
+ neg %eax
+ ret
+
+/* ==========================================================================
+ * machdep_sys_write()
+ */
+SYSCALL(write)
+
+/* ==========================================================================
+ * machdep_sys_read()
+ */
+SYSCALL(read)
+
+/* ==========================================================================
+ * machdep_sys_open()
+ */
+SYSCALL(open)
+
+/* ==========================================================================
+ * machdep_sys_close()
+ */
+SYSCALL(close)
+
+/* ==========================================================================
+ * machdep_sys_fcntl()
+ */
+SYSCALL(fcntl)
+
+/* ==========================================================================
+ * machdep_sys_lseek()
+ */
+SYSCALL(lseek)
+
+/* ==========================================================================
+ * machdep_sys_pipe()
+ */
+SYSCALL(pipe)
+
+/* ==========================================================================
+ * machdep_sys_dup()
+ */
+SYSCALL(dup)
+
+/* ==========================================================================
+ * machdep_sys_dup2()
+ */
+SYSCALL(dup2)
+
+/* ==========================================================================
+ * machdep_sys_fork()
+ */
+ .globl _machdep_sys_fork;
+
+_machdep_sys_fork:;
+
+ movl $(SYS_fork), %eax;
+ .byte 0x9a; .long 0; .word 7;
+ cmpl $0, %edx
+ je 2f
+ movl $0, %eax
+2:
+ ret;
+
+/* ==========================================================================
+ * machdep_sys_execve()
+ */
+SYSCALL(execve)
+
+/* ==========================================================================
+ * machdep_sys_fstat()
+ */
+SYSCALL(fstat)
+
+/* ==========================================================================
+ * machdep_sys_fchown()
+ */
+SYSCALL(fchown)
+
+/* ==========================================================================
+ * machdep_sys_fchmod()
+ */
+SYSCALL(fchmod)
+
+/* ==========================================================================
+ * machdep_sys_chown()
+ */
+SYSCALL(chown)
+
+/* ==========================================================================
+ * machdep_sys_chmod()
+ */
+SYSCALL(chmod)
+
+/* ==========================================================================
+ * machdep_sys_chdir()
+ */
+SYSCALL(chdir)
+
+/* ==========================================================================
+ * machdep_sys_chdir()
+ */
+SYSCALL(link)
+
+/* ==========================================================================
+ * machdep_sys_chdir()
+ */
+SYSCALL(unlink)
+
+/* ==========================================================================
+ * machdep_sys_chdir()
+ */
+SYSCALL(rename)
+
+/* ==========================================================================
+ * Nonstandard calls used to make the system work
+ *
+ * ==========================================================================
+ * machdep_sys_select()
+ */
+SYSCALL(select)
+
+/* ==========================================================================
+ * machdep_sys_getdirentries()
+ */
+SYSCALL(getdirentries)
+
+/* ==========================================================================
+ * machdep_sys_wait4()
+ */
+SYSCALL(wait4)
+
+/* ==========================================================================
+ * Berkeley socket stuff
+ *
+ * ==========================================================================
+ * machdep_sys_socket()
+ */
+SYSCALL(socket)
+
+/* ==========================================================================
+ * machdep_sys_bind()
+ */
+SYSCALL(bind)
+
+/* ==========================================================================
+ * machdep_sys_connect()
+ */
+SYSCALL(connect)
+
+/* ==========================================================================
+ * machdep_sys_accept()
+ */
+SYSCALL(accept)
+
+/* ==========================================================================
+ * machdep_sys_listen()
+ */
+SYSCALL(listen)
+
+/* ==========================================================================
+ * machdep_sys_getsockopt()
+ */
+SYSCALL(getsockopt)
+
+/* ==========================================================================
+ * machdep_sys_readv()
+ */
+SYSCALL(readv)
+
+/* ==========================================================================
+ * machdep_sys_writev()
+ */
+SYSCALL(writev)
+
+/* ==========================================================================
+ * machdep_sys_getpeername()
+ */
+SYSCALL(getpeername)
+
+/* ==========================================================================
+ * machdep_sys_getsockname()
+ */
+SYSCALL(getsockname)
+
+/* ==========================================================================
+ * machdep_sys_sendto()
+ */
+SYSCALL(sendto)
+
+/* ==========================================================================
+ * machdep_sys_recvfrom()
+ */
+SYSCALL(recvfrom)
+
+/* ==========================================================================
+ * machdep_sys_sendmsg()
+ */
+SYSCALL(sendmsg)
+
+/* ==========================================================================
+ * machdep_sys_recvmsg()
+ */
+SYSCALL(recvmsg)
+
+/* ==========================================================================
+ * machdep_sys_shutdown() - Is this correct?
+ */
+SYSCALL(shutdown)
+
diff --git a/mit-pthreads/machdep/syscall-i386-bsdi-2.0.S b/mit-pthreads/machdep/syscall-i386-bsdi-2.0.S
new file mode 100644
index 00000000000..8a56717da31
--- /dev/null
+++ b/mit-pthreads/machdep/syscall-i386-bsdi-2.0.S
@@ -0,0 +1,294 @@
+/* ==== syscall.S ============================================================
+ * Copyright (c) 1990 The Regents of the University of California.
+ * Copyright (c) 1993 Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Description : Machine dependent syscalls for i386/i486/i586
+ *
+ * 1.00 93/08/26 proven
+ * -Started coding this file.
+ *
+ * 1.01 93/11/13 proven
+ * -The functions readv() and writev() added.
+ */
+
+#ifndef lint
+ .text
+ .asciz "syscall-i386-netbsd-1.0.S,v 1.56 1995/09/26 21:04:05 raeburn Exp";
+#endif
+
+#if defined(SYSLIBC_SCCS) && !defined(lint)
+ .asciz "@(#)syscall.s 5.1 (Berkeley) 4/23/90"
+#endif /* SYSLIBC_SCCS and not lint */
+
+#include <sys/syscall.h>
+
+/*
+ * Initial asm stuff for all functions.
+ */
+ .text
+ .align 2
+
+
+/* ==========================================================================
+ * error code for all syscalls. The error value is returned as the negative
+ * of the errno value.
+ */
+
+1:
+ neg %eax
+ ret
+
+/* ==========================================================================
+ * machdep_sys_fork()
+ */
+ .globl _machdep_sys_fork;
+
+_machdep_sys_fork:;
+
+ movl $(SYS_fork), %eax;
+ .byte 0x9a; .long 0; .word 7;
+ cmpl $0, %edx
+ je 2f
+ movl $0, %eax
+2:
+ ret;
+
+/* ==========================================================================
+ * machdep_sys___syscall()
+ */
+
+_machdep_sys___syscall:;
+
+ movl $(SYS___syscall), %eax;
+ .byte 0x9a; .long 0; .word 7;
+ jb 3f;
+ ret
+
+/* ==========================================================================
+ * machdep_sys_sigsuspend()
+ */
+ .globl _machdep_sys_sigsuspend;
+
+_machdep_sys_sigsuspend:;
+
+ movl 4(%esp),%eax # fetch mask arg
+ movl (%eax),%eax # indirect to mask arg
+ movl %eax,4(%esp)
+ movl $(SYS_sigsuspend), %eax;
+ .byte 0x9a; .long 0; .word 7;
+ jb 3f;
+ ret
+
+3:
+
+ neg %eax
+ movl $0xffffffff,%edx
+ ret
+
+/* ==========================================================================
+ * machdep_sys_lseek()
+ */
+ .globl _machdep_sys_lseek;
+
+_machdep_sys_lseek:;
+
+ pushl %ebp;
+ movl %esp,%ebp;
+ pushl 0x14(%ebp);
+ pushl 0x10(%ebp);
+ pushl 0xc(%ebp);
+ pushl $0x0;
+ pushl 0x8(%ebp);
+ pushl $0x0;
+ pushl $(SYS_lseek);
+ call _machdep_sys___syscall;
+ leave
+ ret
+
+/* ==========================================================================
+ * machdep_sys_ftruncate() ; Added by Monty
+ */
+ .globl _machdep_sys_ftruncate;
+
+_machdep_sys_ftruncate:;
+
+ pushl %ebp;
+ movl %esp,%ebp;
+ pushl 0x10(%ebp);
+ pushl 0xc(%ebp);
+ pushl $0x0; # Why this?
+ pushl 0x8(%ebp);
+ pushl $0x0; # And this?
+ pushl $(SYS_ftruncate);
+ call _machdep_sys___syscall;
+ leave
+ ret
+
+
+/* BSDI DEFS.h,v 2.1 1995/02/03 06:28:24 polk Exp */
+
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)DEFS.h 8.1 (Berkeley) 6/4/93
+ */
+
+#ifdef PROF
+#define ENTRY(x) .globl _/**/x; .align 2; _/**/x: \
+ .data; 1:; .long 0; .text; \
+ pushl %ebp; movl %esp,%ebp; \
+ leal 1b,%eax; call mcount; leave
+#define ASENTRY(x) .globl x; .align 2; x: \
+ .data; 1:; .long 0; .text; \
+ pushl %ebp; movl %esp,%ebp; \
+ leal 1b,%eax; call mcount; leave
+#else
+#define ENTRY(x) .globl _/**/x; .align 2; _/**/x:
+#define ASENTRY(x) .globl x; .align 2; x:
+#endif
+
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+ .asciz "@(#)_setjmp.s 8.1 (Berkeley) 6/4/93"
+#endif /* LIBC_SCCS and not lint */
+
+/*
+ * C library -- _setjmp, _longjmp
+ *
+ * _longjmp(a,v)
+ * will generate a "return(v)" from the last call to
+ * _setjmp(a)
+ * by restoring registers from the stack.
+ * The previous signal state is NOT restored.
+ */
+
+
+.globl __setjmp; /* Patch by Jan Legenhausen (monty) */
+.align 2;
+__setjmp:
+ movl 4(%esp),%eax
+ movl 0(%esp),%edx
+ movl %edx, 0(%eax) /* rta */
+ movl %ebx, 4(%eax)
+ movl %esp, 8(%eax)
+ movl %ebp,12(%eax)
+ movl %esi,16(%eax)
+ movl %edi,20(%eax)
+ movl $0,%eax
+ ret
+
+.globl __longjmp; /* Patch by Jan Legenhausen ? (monty) */
+.align 2;
+__longjmp:
+ movl 4(%esp),%edx
+ movl 8(%esp),%eax
+ movl 0(%edx),%ecx
+ movl 4(%edx),%ebx
+ movl 8(%edx),%esp
+ movl 12(%edx),%ebp
+ movl 16(%edx),%esi
+ movl 20(%edx),%edi
+ cmpl $0,%eax
+ jne 1f
+ movl $1,%eax
+1: movl %ecx,0(%esp)
+ ret
diff --git a/mit-pthreads/machdep/syscall-i386-freebsd-1.1.S b/mit-pthreads/machdep/syscall-i386-freebsd-1.1.S
new file mode 100644
index 00000000000..5777cc5e06d
--- /dev/null
+++ b/mit-pthreads/machdep/syscall-i386-freebsd-1.1.S
@@ -0,0 +1,293 @@
+/* ==== syscall.S ============================================================
+ * Copyright (c) 1990 The Regents of the University of California.
+ * Copyright (c) 1993 Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Description : Machine dependent syscalls for i386/i486/i586
+ *
+ * 1.00 93/08/26 proven
+ * -Started coding this file.
+ *
+ * 1.01 93/11/13 proven
+ * -The functions readv() and writev() added.
+ */
+
+#ifndef lint
+ .text
+ .asciz "$Id$";
+#endif
+
+#if defined(SYSLIBC_SCCS) && !defined(lint)
+ .asciz "@(#)syscall.s 5.1 (Berkeley) 4/23/90"
+#endif /* SYSLIBC_SCCS and not lint */
+
+#include <sys/syscall.h>
+
+#define SYSCALL(x) \
+ .globl _machdep_sys_/**/x; \
+ \
+_machdep_sys_/**/x:; \
+ \
+ movl $(SYS_/**/x), %eax; \
+ .byte 0x9a; .long 0; .word 7; \
+ jb 1b; \
+ ret;
+
+/*
+ * Initial asm stuff for all functions.
+ */
+ .text
+ .align 2
+
+
+/* ==========================================================================
+ * error code for all syscalls. The error value is returned as the negative
+ * of the errno value.
+ */
+
+1:
+ neg %eax
+ ret
+
+/* ==========================================================================
+ * machdep_sys_write()
+ */
+SYSCALL(write)
+
+/* ==========================================================================
+ * machdep_sys_read()
+ */
+SYSCALL(read)
+
+/* ==========================================================================
+ * machdep_sys_open()
+ */
+SYSCALL(open)
+
+/* ==========================================================================
+ * machdep_sys_close()
+ */
+SYSCALL(close)
+
+/* ==========================================================================
+ * machdep_sys_fcntl()
+ */
+SYSCALL(fcntl)
+
+/* ==========================================================================
+ * machdep_sys_lseek()
+ */
+SYSCALL(lseek)
+
+/* ==========================================================================
+ * machdep_sys_stat()
+ */
+SYSCALL(stat)
+
+/* ==========================================================================
+ * machdep_sys_pipe()
+ */
+SYSCALL(pipe)
+
+/* ==========================================================================
+ * machdep_sys_dup()
+ */
+SYSCALL(dup)
+
+/* ==========================================================================
+ * machdep_sys_dup2()
+ */
+SYSCALL(dup2)
+
+/* ==========================================================================
+ * machdep_sys_fork()
+ */
+ .globl _machdep_sys_fork;
+
+_machdep_sys_fork:;
+
+ movl $(SYS_fork), %eax;
+ .byte 0x9a; .long 0; .word 7;
+ cmpl $0, %edx
+ je 2f
+ movl $0, %eax
+2:
+ ret;
+
+/* ==========================================================================
+ * machdep_sys_execve()
+ */
+SYSCALL(execve)
+
+/* ==========================================================================
+ * machdep_sys_fstat()
+ */
+SYSCALL(fstat)
+
+/* ==========================================================================
+ * machdep_sys_fchown()
+ */
+SYSCALL(fchown)
+
+/* ==========================================================================
+ * machdep_sys_fchmod()
+ */
+SYSCALL(fchmod)
+
+/* ==========================================================================
+ * machdep_sys_chown()
+ */
+SYSCALL(chown)
+
+/* ==========================================================================
+ * machdep_sys_chmod()
+ */
+SYSCALL(chmod)
+
+/* ==========================================================================
+ * machdep_sys_chdir()
+ */
+SYSCALL(chdir)
+
+/* ==========================================================================
+ * machdep_sys_chdir()
+ */
+SYSCALL(link)
+
+/* ==========================================================================
+ * machdep_sys_chdir()
+ */
+SYSCALL(unlink)
+
+/* ==========================================================================
+ * machdep_sys_chdir()
+ */
+SYSCALL(rename)
+
+/* ==========================================================================
+ * Nonstandard calls used to make the system work
+ *
+ * ==========================================================================
+ * machdep_sys_select()
+ */
+SYSCALL(select)
+
+/* ==========================================================================
+ * machdep_sys_getdirentries()
+ */
+SYSCALL(getdirentries)
+
+/* ==========================================================================
+ * machdep_sys_wait4()
+ */
+SYSCALL(wait4)
+
+/* ==========================================================================
+ * Berkeley socket stuff
+ *
+ * ==========================================================================
+ * machdep_sys_socket()
+ */
+SYSCALL(socket)
+
+/* ==========================================================================
+ * machdep_sys_bind()
+ */
+SYSCALL(bind)
+
+/* ==========================================================================
+ * machdep_sys_connect()
+ */
+SYSCALL(connect)
+
+/* ==========================================================================
+ * machdep_sys_accept()
+ */
+SYSCALL(accept)
+
+/* ==========================================================================
+ * machdep_sys_listen()
+ */
+SYSCALL(listen)
+
+/* ==========================================================================
+ * machdep_sys_getsockopt()
+ */
+SYSCALL(getsockopt)
+
+/* ==========================================================================
+ * machdep_sys_readv()
+ */
+SYSCALL(readv)
+
+/* ==========================================================================
+ * machdep_sys_writev()
+ */
+SYSCALL(writev)
+
+/* ==========================================================================
+ * machdep_sys_getpeername()
+ */
+SYSCALL(getpeername)
+
+/* ==========================================================================
+ * machdep_sys_getsockname()
+ */
+SYSCALL(getsockname)
+
+/* ==========================================================================
+ * machdep_sys_sendto()
+ */
+SYSCALL(sendto)
+
+/* ==========================================================================
+ * machdep_sys_recvfrom()
+ */
+SYSCALL(recvfrom)
+
+/* ==========================================================================
+ * machdep_sys_sendmsg()
+ */
+SYSCALL(sendmsg)
+
+/* ==========================================================================
+ * machdep_sys_recvmsg()
+ */
+SYSCALL(recvmsg)
+
+/* ==========================================================================
+ * machdep_sys_shutdown()
+ */
+SYSCALL(shutdown)
+
diff --git a/mit-pthreads/machdep/syscall-i386-freebsd-2.0.S b/mit-pthreads/machdep/syscall-i386-freebsd-2.0.S
new file mode 100644
index 00000000000..b713bcac344
--- /dev/null
+++ b/mit-pthreads/machdep/syscall-i386-freebsd-2.0.S
@@ -0,0 +1,240 @@
+/* ==== syscall.S ============================================================
+ * Copyright (c) 1990 The Regents of the University of California.
+ * Copyright (c) 1995 Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Description : Machine dependent syscalls for i386/i486/i586
+ *
+ */
+
+#ifndef lint
+ .text
+ .asciz "syscall-i386-freebsd-2.0.S,v 1.2 1995/05/26 07:44:29 proven Exp";
+#endif
+
+#if defined(SYSLIBC_SCCS) && !defined(lint)
+ .asciz "@(#)syscall.s 5.1 (Berkeley) 4/23/90"
+#endif /* SYSLIBC_SCCS and not lint */
+
+#include <sys/syscall.h>
+
+#ifdef __STDC__
+
+#ifdef __ELF__
+#define NAME(X) machdep_sys_##X
+#else
+#define NAME(X) _machdep_sys_##X
+#endif
+
+#else
+
+#ifdef __ELF__
+#define NAME(X) machdep_sys_/**/X
+#else
+#define NAME(X) _machdep_sys_/**/X
+#endif
+
+#endif
+
+#ifdef __ELF__
+#define END(X) 5: ; .type NAME(X),@function ; .size NAME(X),5b - NAME(X)
+#define KERNCALL int $0x80
+#else
+#define END(X)
+#define KERNCALL .byte 0x9a; .long 0; .word 7;
+#endif
+
+/*
+ * Initial asm stuff for all functions.
+ */
+ .text
+ .align 2
+
+
+/* ==========================================================================
+ * error code for all syscalls. The error value is returned as the negative
+ * of the errno value.
+ */
+
+1:
+ neg %eax
+ ret
+
+/* ==========================================================================
+ * machdep_sys_fork()
+ */
+ .globl NAME(fork);
+
+NAME(fork):;
+
+ movl $(SYS_fork), %eax;
+ KERNCALL;
+ cmpl $0, %edx
+ je 2f
+ movl $0, %eax
+2:
+ ret;
+ END(fork)
+
+/* ==========================================================================
+ * machdep_sys___syscall()
+ */
+
+_machdep_sys___syscall:;
+
+ movl $(SYS___syscall), %eax;
+ KERNCALL;
+ jb 3f;
+ ret
+
+/* ==========================================================================
+ * machdep_sys_sigsuspend()
+ */
+ .globl NAME(sigsuspend);
+
+NAME(sigsuspend):;
+
+ movl 4(%esp),%eax # fetch mask arg
+ movl (%eax),%eax # indirect to mask arg
+ movl %eax,4(%esp)
+ movl $(SYS_sigsuspend), %eax;
+ KERNCALL;
+ jb 3f;
+ ret
+3:
+ neg %eax
+ movl $0xffffffff,%edx
+ ret
+ END(sigsuspend)
+
+/* ==========================================================================
+ * machdep_sys_sigprocmask()
+ */
+ .globl NAME(sigprocmask);
+
+NAME(sigprocmask):;
+
+ movl 8(%esp),%ecx
+ movl (%ecx),%ecx
+ movl %ecx,8(%esp)
+ movl $ SYS_sigprocmask , %eax
+ KERNCALL;
+ jb 4f;
+ ret
+4:
+ neg %eax
+ movl $0xffffffff,%edx
+ ret
+ END(sigprocmask)
+
+/* ==========================================================================
+ * machdep_sys_lseek()
+ */
+ .globl NAME(lseek);
+
+NAME(lseek):;
+
+ pushl %ebp;
+ movl %esp,%ebp;
+ pushl 0x14(%ebp);
+ pushl 0x10(%ebp);
+ pushl 0xc(%ebp);
+ pushl $0x0;
+ pushl 0x8(%ebp);
+ pushl $0x0;
+ pushl $(SYS_lseek);
+ call _machdep_sys___syscall;
+ leave
+ ret
+ END(lseek)
+
+/* ==========================================================================
+ * machdep_sys_ftruncate() ; Added by Monty
+ */
+ .globl NAME(ftruncate);
+
+NAME(ftruncate):;
+
+ pushl %ebp;
+ movl %esp,%ebp;
+ pushl 0x10(%ebp);
+ pushl 0xc(%ebp);
+ pushl $0x0; # Why this?
+ pushl 0x8(%ebp);
+ pushl $0x0; # And this?
+ pushl $(SYS_ftruncate);
+ call _machdep_sys___syscall;
+ leave
+ ret
+ END(ftruncate)
+
+/* ==========================================================================
+ * machdep_sys_setjmp()
+ */
+ .globl NAME(setjmp);
+
+NAME(setjmp):;
+ movl 4(%esp),%eax
+ movl 0(%esp),%edx
+ movl %edx, 0(%eax) /* rta */
+ movl %ebx, 4(%eax)
+ movl %esp, 8(%eax)
+ movl %ebp,12(%eax)
+ movl %esi,16(%eax)
+ movl %edi,20(%eax)
+ xorl %eax,%eax
+ ret
+ END(setjmp)
+
+/* ==========================================================================
+ * machdep_sys_longjmp()
+ */
+ .globl NAME(longjmp);
+
+NAME(longjmp):;
+ movl 4(%esp),%edx
+ movl 8(%esp),%eax
+ movl 0(%edx),%ecx
+ movl 4(%edx),%ebx
+ movl 8(%edx),%esp
+ movl 12(%edx),%ebp
+ movl 16(%edx),%esi
+ movl 20(%edx),%edi
+ testl %eax,%eax
+ jnz 1f
+ incl %eax
+1:
+ movl %ecx,0(%esp)
+ ret
+ END(longjmp)
diff --git a/mit-pthreads/machdep/syscall-i386-linux-1.0.S b/mit-pthreads/machdep/syscall-i386-linux-1.0.S
new file mode 100644
index 00000000000..1399c812e2f
--- /dev/null
+++ b/mit-pthreads/machdep/syscall-i386-linux-1.0.S
@@ -0,0 +1,406 @@
+/* ==== syscall.S ============================================================
+ * Copyright (c) 1994 Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Description : Machine dependent syscalls for i386/i486/i586
+ *
+ * 1.00 93/08/26 proven
+ * -Started coding this file.
+ *
+ * 1.01 93/11/13 proven
+ * -The functions readv() and writev() added.
+ *
+ * 1.16 94/01/30 proven
+ * -This file now requires gas version 2.0 or greater.
+ */
+
+#ifndef lint
+ .text
+ .asciz "$Id$";
+#endif
+
+#include <sys/syscall.h>
+#include <config.h>
+
+#ifdef __ELF__
+
+#define NAME(X) machdep_sys_##X
+#define END(X) 1: ; .type NAME(X),@function ; .size NAME(X),1b - NAME(X)
+
+#else
+
+#define NAME(X) _machdep_sys_##X
+#define END(X)
+
+#endif
+
+#define SYSCALL0(x) \
+ .globl NAME(x) ; \
+ \
+NAME(x): \
+ \
+ push %ebx; \
+ lea SYS_##x, %eax; \
+ int $0x80; \
+ pop %ebx; \
+ ret; \
+ \
+ END(x)
+
+#define SYSCALL1(x) \
+ .globl NAME(x) ; \
+ \
+NAME(x): \
+ \
+ push %ebx; \
+ mov 8(%esp), %ebx; \
+ lea SYS_##x, %eax; \
+ int $0x80; \
+ pop %ebx; \
+ ret; \
+ \
+ END(x)
+
+#define SYSCALL2(x) \
+ .globl NAME(x) ; \
+ \
+NAME(x): \
+ \
+ push %ebx; \
+ mov 8(%esp), %ebx; \
+ mov 12(%esp), %ecx; \
+ lea SYS_##x, %eax; \
+ int $0x80; \
+ pop %ebx; \
+ ret; \
+ \
+ END(x)
+
+#define STATCALL2(x) \
+ .globl NAME(x) ; \
+ \
+NAME(x): \
+ \
+ push %ebx; \
+ mov 8(%esp), %ebx; \
+ mov 12(%esp), %ecx; \
+ lea SYS_prev_##x, %eax; \
+ int $0x80; \
+ pop %ebx; \
+ ret; \
+ END(x)
+
+#define SYSCALL3(x) \
+ .globl NAME(x) ; \
+ \
+NAME(x): \
+ \
+ push %ebx; \
+ mov 8(%esp), %ebx; \
+ mov 12(%esp), %ecx; \
+ mov 16(%esp), %edx; \
+ lea SYS_##x, %eax; \
+ int $0x80; \
+ pop %ebx; \
+ ret; \
+ END(x)
+
+
+#define SYSCALL4(x) \
+ .globl NAME(x) ; \
+ \
+NAME(x): \
+ \
+ push %ebx; \
+ push %esi; \
+ mov 12(%esp), %ebx; \
+ mov 16(%esp), %ecx; \
+ mov 20(%esp), %edx; \
+ mov 24(%esp), %esi; \
+ lea SYS_##x, %eax; \
+ int $0x80; \
+ pop %esi; \
+ pop %ebx; \
+ ret; \
+ END(x)
+
+#define SYSCALL5(x) \
+ .globl NAME(x) ; \
+ \
+NAME(x): \
+ \
+ push %ebx; \
+ push %esi; \
+ push %edi; \
+ mov 16(%esp), %ebx; \
+ mov 20(%esp), %ecx; \
+ mov 24(%esp), %edx; \
+ mov 28(%esp), %esi; \
+ mov 32(%esp), %edi; \
+ lea SYS_##x, %eax; \
+ int $0x80; \
+ pop %edi; \
+ pop %esi; \
+ pop %ebx; \
+ ret; \
+ END(x)
+
+/* =========================================================================
+ * exit 1 select 82
+ * fork 2 fstatfs 100
+ * read 3 socketcall 102
+ * write 4 flock 143
+ * open 5 readv 145
+ * creat 8 writev 146
+ * link 9
+ * unlink 10
+ * execve 11
+ * chdir 12
+ * chmod 15
+ * chown 16
+ * lseek 19
+ * rename 38
+ * dup 41
+ * pipe 42
+ * ioctl 54
+ * fcntl 55
+ * dup2 63
+ * readdir 89
+ * ftruncate 93
+ * fchmod 94
+ * fchown 95
+ */
+
+/*
+ * Initial asm stuff for all functions.
+ */
+ .text
+ .align 2
+
+
+/* ==========================================================================
+ * machdep_sys_read()
+ */
+SYSCALL3(read)
+
+/* ==========================================================================
+ * machdep_sys_write()
+ */
+SYSCALL3(write)
+
+/* ==========================================================================
+ * machdep_sys_open()
+ */
+SYSCALL3(open)
+
+/* ==========================================================================
+ * machdep_sys_close()
+ */
+SYSCALL1(close)
+
+/* ==========================================================================
+ * machdep_sys_creat()
+ */
+SYSCALL2(creat)
+
+/* ==========================================================================
+ * machdep_sys_dup2()
+ */
+SYSCALL2(dup2)
+
+/* ==========================================================================
+ * machdep_sys_fcntl()
+ */
+SYSCALL3(fcntl)
+
+/* ==========================================================================
+ * machdep_sys_fchown()
+ */
+SYSCALL3(fchown)
+
+/* ==========================================================================
+ * machdep_sys_fchmod()
+ */
+SYSCALL2(fchmod)
+
+/* ==========================================================================
+ * machdep_sys_ioctl()
+ */
+SYSCALL3(ioctl)
+
+/* ==========================================================================
+ * machdep_sys_chown()
+ */
+SYSCALL3(chown)
+
+/* ==========================================================================
+ * machdep_sys_chmod()
+ */
+SYSCALL2(chmod)
+
+/* ==========================================================================
+ * machdep_sys_chdir()
+ */
+SYSCALL1(chdir)
+
+/* ==========================================================================
+ * machdep_sys_unlink()
+ */
+SYSCALL1(unlink)
+
+/* ==========================================================================
+ * machdep_sys_link()
+ */
+SYSCALL2(link)
+
+/* ==========================================================================
+ * machdep_sys_rename()
+ */
+SYSCALL2(rename)
+
+/* ==========================================================================
+ * machdep_sys_lseek()
+ */
+SYSCALL3(lseek)
+
+/* ==========================================================================
+ * machdep_sys_pipe()
+ */
+SYSCALL1(pipe)
+
+/* ==========================================================================
+ * machdep_sys_dup()
+ */
+SYSCALL1(dup)
+
+/* ==========================================================================
+ * machdep_sys_fork()
+ */
+SYSCALL0(fork)
+
+/* ==========================================================================
+ * machdep_sys_execve()
+ */
+SYSCALL3(execve)
+
+/* ==========================================================================
+ * machdep_sys_stat()
+ */
+#ifdef __ELF__
+STATCALL2(stat)
+#else
+SYSCALL2(stat)
+#endif
+
+/* ==========================================================================
+ * machdep_sys_fstat()
+ */
+#ifdef __ELF__
+STATCALL2(fstat)
+#else
+SYSCALL2(fstat)
+#endif
+
+/* ==========================================================================
+ * machdep_sys_lstat()
+ */
+#ifdef __ELF__
+STATCALL2(lstat)
+#else
+SYSCALL2(lstat)
+#endif
+
+/* ==========================================================================
+ * machdep_sys_fstatfs()
+ */
+SYSCALL2(fstatfs)
+
+
+/* ==========================================================================
+ * machdep_sys_ftruncate()
+ */
+SYSCALL2(ftruncate)
+
+/* ==========================================================================
+ * Nonstandard calls used to make the system work
+ *
+ * ==========================================================================
+ * machdep_sys_select()
+ */
+
+ .globl NAME(select)
+
+NAME(select):
+
+ push %ebx
+ lea 8(%esp), %ebx
+ lea SYS_select, %eax
+ int $0x80
+ pop %ebx
+ ret
+ END(select)
+
+/* ==========================================================================
+ * machdep_sys_wait4()
+ */
+SYSCALL4(wait4)
+
+/* ==========================================================================
+ * machdep_sys_readdir()
+ */
+SYSCALL3(readdir)
+
+/* ==========================================================================
+ * machdep_sys_socketcall()
+ */
+SYSCALL2(socketcall)
+
+
+SYSCALL1(exit)
+SYSCALL3(sigprocmask)
+
+/* ==========================================================================
+ * machdep_sys_sigsuspend()
+ */
+
+ .globl NAME(sigsuspend)
+
+NAME(sigsuspend):
+
+ push %ebp
+ mov %esp,%ebp
+ push %edi
+ push %esi
+ push %ebx
+ mov 8(%ebp), %edx
+ mov (%edx), %edx
+ lea SYS_sigsuspend, %eax
+ int $0x80
+ pop %ebx
+ pop %esi
+ pop %edi
+ mov %ebp,%esp
+ pop %ebp
+ ret
+ END(sigsuspend)
+
+/* ==========================================================================
+ * machdep_sys_readv()
+ */
+#ifdef HAVE_SYSCALL_READV
+SYSCALL3(readv)
+#endif
+
+/* ==========================================================================
+ * machdep_sys_writev()
+ */
+#ifdef HAVE_SYSCALL_WRITEV
+SYSCALL3(writev)
+#endif
+
+/* ==========================================================================
+ * machdep_sys_flock()
+ */
+#ifdef HAVE_SYSCALL_FLOCK
+SYSCALL2(flock)
+#endif
diff --git a/mit-pthreads/machdep/syscall-i386-linux-2.0.S b/mit-pthreads/machdep/syscall-i386-linux-2.0.S
new file mode 100644
index 00000000000..d5807b2d9b4
--- /dev/null
+++ b/mit-pthreads/machdep/syscall-i386-linux-2.0.S
@@ -0,0 +1,389 @@
+/* ==== syscall.S ============================================================
+ * Copyright (c) 1994 Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Description : Machine dependent syscalls for i386/i486/i586
+ *
+ * 1.00 93/08/26 proven
+ * -Started coding this file.
+ *
+ * 1.01 93/11/13 proven
+ * -The functions readv() and writev() added.
+ *
+ * 1.16 94/01/30 proven
+ * -This file now requires gas version 2.0 or greater.
+ */
+
+#ifndef lint
+ .text
+ .asciz "$Id$";
+#endif
+
+#include <sys/syscall.h>
+#include <config.h>
+
+#ifdef __ELF__
+
+#define NAME(X) machdep_sys_##X
+#define END(X) 1: ; .type NAME(X),@function ; .size NAME(X),1b - NAME(X)
+
+#else
+
+#define NAME(X) _machdep_sys_##X
+#define END(X)
+
+#endif
+
+#define SYSCALL0(x) \
+ .globl NAME(x) ; \
+ \
+NAME(x): \
+ \
+ push %ebx; \
+ lea SYS_##x, %eax; \
+ int $0x80; \
+ pop %ebx; \
+ ret; \
+ \
+ END(x)
+
+#define SYSCALL1(x) \
+ .globl NAME(x) ; \
+ \
+NAME(x): \
+ \
+ push %ebx; \
+ mov 8(%esp), %ebx; \
+ lea SYS_##x, %eax; \
+ int $0x80; \
+ pop %ebx; \
+ ret; \
+ \
+ END(x)
+
+#define SYSCALL2(x) \
+ .globl NAME(x) ; \
+ \
+NAME(x): \
+ \
+ push %ebx; \
+ mov 8(%esp), %ebx; \
+ mov 12(%esp), %ecx; \
+ lea SYS_##x, %eax; \
+ int $0x80; \
+ pop %ebx; \
+ ret; \
+ \
+ END(x)
+
+#define SYSCALL3(x) \
+ .globl NAME(x) ; \
+ \
+NAME(x): \
+ \
+ push %ebx; \
+ mov 8(%esp), %ebx; \
+ mov 12(%esp), %ecx; \
+ mov 16(%esp), %edx; \
+ lea SYS_##x, %eax; \
+ int $0x80; \
+ pop %ebx; \
+ ret; \
+ END(x)
+
+
+#define SYSCALL4(x) \
+ .globl NAME(x) ; \
+ \
+NAME(x): \
+ \
+ push %ebx; \
+ push %esi; \
+ mov 12(%esp), %ebx; \
+ mov 16(%esp), %ecx; \
+ mov 20(%esp), %edx; \
+ mov 24(%esp), %esi; \
+ lea SYS_##x, %eax; \
+ int $0x80; \
+ pop %esi; \
+ pop %ebx; \
+ ret; \
+ END(x)
+
+#define SYSCALL5(x) \
+ .globl NAME(x) ; \
+ \
+NAME(x): \
+ \
+ push %ebx; \
+ push %esi; \
+ push %edi; \
+ mov 16(%esp), %ebx; \
+ mov 20(%esp), %ecx; \
+ mov 24(%esp), %edx; \
+ mov 28(%esp), %esi; \
+ mov 32(%esp), %edi; \
+ lea SYS_##x, %eax; \
+ int $0x80; \
+ pop %edi; \
+ pop %esi; \
+ pop %ebx; \
+ ret; \
+ END(x)
+
+/* =========================================================================
+ * exit 1 select 82
+ * fork 2 fstatfs 100
+ * read 3 socketcall 102
+ * write 4 flock 143
+ * open 5 readv 145
+ * creat 8 writev 146
+ * link 9
+ * unlink 10
+ * execve 11
+ * chdir 12
+ * chmod 15
+ * chown 16
+ * lseek 19
+ * rename 38
+ * dup 41
+ * pipe 42
+ * ioctl 54
+ * fcntl 55
+ * dup2 63
+ * readdir 89
+ * ftruncate 93
+ * fchmod 94
+ * fchown 95
+ */
+
+/*
+ * Initial asm stuff for all functions.
+ */
+ .text
+ .align 2
+
+
+/* ==========================================================================
+ * machdep_sys_read()
+ */
+SYSCALL3(read)
+
+/* ==========================================================================
+ * machdep_sys_write()
+ */
+SYSCALL3(write)
+
+/* ==========================================================================
+ * machdep_sys_open()
+ */
+SYSCALL3(open)
+
+/* ==========================================================================
+ * machdep_sys_close()
+ */
+SYSCALL1(close)
+
+/* ==========================================================================
+ * machdep_sys_creat()
+ */
+SYSCALL2(creat)
+
+/* ==========================================================================
+ * machdep_sys_dup2()
+ */
+SYSCALL2(dup2)
+
+/* ==========================================================================
+ * machdep_sys_fcntl()
+ */
+SYSCALL3(fcntl)
+
+/* ==========================================================================
+ * machdep_sys_fchown()
+ */
+SYSCALL3(fchown)
+
+/* ==========================================================================
+ * machdep_sys_fchmod()
+ */
+SYSCALL2(fchmod)
+
+/* ==========================================================================
+ * machdep_sys_ioctl()
+ */
+SYSCALL3(ioctl)
+
+/* ==========================================================================
+ * machdep_sys_chown()
+ */
+SYSCALL3(chown)
+
+/* ==========================================================================
+ * machdep_sys_chmod()
+ */
+SYSCALL2(chmod)
+
+/* ==========================================================================
+ * machdep_sys_chdir()
+ */
+SYSCALL1(chdir)
+
+/* ==========================================================================
+ * machdep_sys_unlink()
+ */
+SYSCALL1(unlink)
+
+/* ==========================================================================
+ * machdep_sys_link()
+ */
+SYSCALL2(link)
+
+/* ==========================================================================
+ * machdep_sys_rename()
+ */
+SYSCALL2(rename)
+
+/* ==========================================================================
+ * machdep_sys_lseek()
+ */
+SYSCALL3(lseek)
+
+/* ==========================================================================
+ * machdep_sys_pipe()
+ */
+SYSCALL1(pipe)
+
+/* ==========================================================================
+ * machdep_sys_dup()
+ */
+SYSCALL1(dup)
+
+/* ==========================================================================
+ * machdep_sys_fork()
+ */
+SYSCALL0(fork)
+
+/* ==========================================================================
+ * machdep_sys_execve()
+ */
+SYSCALL3(execve)
+
+/* ==========================================================================
+ * machdep_sys_stat()
+ */
+SYSCALL2(stat)
+
+/* ==========================================================================
+ * machdep_sys_fstat()
+ */
+SYSCALL2(fstat)
+
+/* ==========================================================================
+ * machdep_sys_lstat()
+ */
+SYSCALL2(lstat)
+
+/* ==========================================================================
+ * machdep_sys_fstatfs()
+ */
+SYSCALL2(fstatfs)
+
+/* ==========================================================================
+ * machdep_sys_ftruncate()
+ */
+SYSCALL2(ftruncate)
+
+/* ==========================================================================
+ * machdep_sys_chroot()
+ */
+SYSCALL1(chroot)
+
+/* ==========================================================================
+ * machdep_sys_uname()
+ */
+SYSCALL1(uname)
+
+/* ==========================================================================
+ * Nonstandard calls used to make the system work
+ *
+ * ==========================================================================
+ * machdep_sys_select()
+ */
+
+ .globl NAME(select)
+
+NAME(select):
+
+ push %ebx
+ lea 8(%esp), %ebx
+ lea SYS_select, %eax
+ int $0x80
+ pop %ebx
+ ret
+ END(select)
+
+/* ==========================================================================
+ * machdep_sys_wait4()
+ */
+SYSCALL4(wait4)
+
+/* ==========================================================================
+ * machdep_sys_readdir()
+ */
+SYSCALL3(readdir)
+
+/* ==========================================================================
+ * machdep_sys_socketcall()
+ */
+SYSCALL2(socketcall)
+
+
+SYSCALL1(exit)
+SYSCALL3(sigprocmask)
+
+/* ==========================================================================
+ * machdep_sys_sigsuspend()
+ */
+
+ .globl NAME(sigsuspend)
+
+NAME(sigsuspend):
+
+ push %ebp
+ mov %esp,%ebp
+ push %edi
+ push %esi
+ push %ebx
+ mov 8(%ebp), %edx
+ mov (%edx), %edx
+ lea SYS_sigsuspend, %eax
+ int $0x80
+ pop %ebx
+ pop %esi
+ pop %edi
+ mov %ebp,%esp
+ pop %ebp
+ ret
+ END(sigsuspend)
+
+/* ==========================================================================
+ * machdep_sys_readv()
+ */
+#ifdef HAVE_SYSCALL_READV
+SYSCALL3(readv)
+#endif
+
+/* ==========================================================================
+ * machdep_sys_writev()
+ */
+#ifdef HAVE_SYSCALL_WRITEV
+SYSCALL3(writev)
+#endif
+
+/* ==========================================================================
+ * machdep_sys_flock()
+ */
+#ifdef HAVE_SYSCALL_FLOCK
+SYSCALL2(flock)
+#endif
diff --git a/mit-pthreads/machdep/syscall-i386-netbsd-0.9.S b/mit-pthreads/machdep/syscall-i386-netbsd-0.9.S
new file mode 100644
index 00000000000..8d768a673d3
--- /dev/null
+++ b/mit-pthreads/machdep/syscall-i386-netbsd-0.9.S
@@ -0,0 +1,229 @@
+/* ==== syscall.S ============================================================
+ * Copyright (c) 1990 The Regents of the University of California.
+ * Copyright (c) 1993 Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Description : Machine dependent syscalls for i386/i486/i586
+ *
+ * 1.00 93/08/26 proven
+ * -Started coding this file.
+ *
+ * 1.01 93/11/13 proven
+ * -The functions readv() and writev() added.
+ */
+
+#ifndef lint
+ .text
+ .asciz "$Id$";
+#endif
+
+#if defined(SYSLIBC_SCCS) && !defined(lint)
+ .asciz "@(#)syscall.s 5.1 (Berkeley) 4/23/90"
+#endif /* SYSLIBC_SCCS and not lint */
+
+#include <machine/asm.h>
+#include <sys/syscall.h>
+
+#define SYSCALL(x) \
+ .globl _machdep_sys_/**/x; \
+ \
+_machdep_sys_/**/x:; \
+ \
+ movl $(SYS_/**/x), %eax; \
+ .byte 0x9a; .long 0; .word 7; \
+ jb 1b; \
+ ret;
+
+/*
+ * Initial asm stuff for all functions.
+ */
+ .text
+ .align 2
+
+
+/* ==========================================================================
+ * error code for all syscalls. The error value is returned as the negative
+ * of the errno value.
+ */
+
+1:
+ neg %eax
+ ret
+
+/* ==========================================================================
+ * machdep_sys_write()
+ */
+SYSCALL(write)
+
+/* ==========================================================================
+ * machdep_sys_read()
+ */
+SYSCALL(read)
+
+/* ==========================================================================
+ * machdep_sys_open()
+ */
+SYSCALL(open)
+
+/* ==========================================================================
+ * machdep_sys_close()
+ */
+SYSCALL(close)
+
+/* ==========================================================================
+ * machdep_sys_fcntl()
+ */
+SYSCALL(fcntl)
+
+/* ==========================================================================
+ * machdep_sys_lseek()
+ */
+SYSCALL(lseek)
+
+/* ==========================================================================
+ * machdep_sys_pipe()
+ */
+SYSCALL(pipe)
+
+/* ==========================================================================
+ * machdep_sys_dup()
+ */
+SYSCALL(dup)
+
+/* ==========================================================================
+ * machdep_sys_dup2()
+ */
+SYSCALL(dup2)
+
+/* ==========================================================================
+ * machdep_sys_fork()
+ */
+ .globl _machdep_sys_fork;
+
+_machdep_sys_fork:;
+
+ movl $(SYS_fork), %eax;
+ .byte 0x9a; .long 0; .word 7;
+ cmpl $0, %edx
+ je 2f
+ movl $0, %eax
+2:
+ ret;
+
+/* ==========================================================================
+ * machdep_sys_execve()
+ */
+SYSCALL(execve)
+
+/* ==========================================================================
+ * machdep_sys_fstat()
+ */
+SYSCALL(fstat)
+
+/* ==========================================================================
+ * Nonstandard calls used to make the system work
+ *
+ * ==========================================================================
+ * machdep_sys_select()
+ */
+SYSCALL(select)
+
+/* ==========================================================================
+ * machdep_sys_getdirentries()
+ */
+SYSCALL(getdirentries)
+
+/* ==========================================================================
+ * Berkeley socket stuff
+ *
+ * ==========================================================================
+ * machdep_sys_socket()
+ */
+SYSCALL(socket)
+
+/* ==========================================================================
+ * machdep_sys_bind()
+ */
+SYSCALL(bind)
+
+/* ==========================================================================
+ * machdep_sys_connect()
+ */
+SYSCALL(connect)
+
+/* ==========================================================================
+ * machdep_sys_accept()
+ */
+SYSCALL(accept)
+
+/* ==========================================================================
+ * machdep_sys_listen()
+ */
+SYSCALL(listen)
+
+/* ==========================================================================
+ * machdep_sys_getsockopt()
+ */
+SYSCALL(getsockopt)
+
+/* ==========================================================================
+ * machdep_sys_readv()
+ */
+SYSCALL(readv)
+
+/* ==========================================================================
+ * machdep_sys_writev()
+ */
+SYSCALL(writev)
+
+/* ==========================================================================
+ * machdep_sys_getpeername()
+ */
+SYSCALL(getpeername)
+
+/* ==========================================================================
+ * machdep_sys_getsockname()
+ */
+SYSCALL(getsockname)
+
+/* ==========================================================================
+ * machdep_sys_sendto()
+ */
+SYSCALL(sendto)
+
+/* ==========================================================================
+ * machdep_sys_recvfrom()
+ */
+SYSCALL(recvfrom)
+
diff --git a/mit-pthreads/machdep/syscall-i386-netbsd-1.0.S b/mit-pthreads/machdep/syscall-i386-netbsd-1.0.S
new file mode 100644
index 00000000000..da535dd2f80
--- /dev/null
+++ b/mit-pthreads/machdep/syscall-i386-netbsd-1.0.S
@@ -0,0 +1,158 @@
+/* ==== syscall.S ============================================================
+ * Copyright (c) 1990 The Regents of the University of California.
+ * Copyright (c) 1993 Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Description : Machine dependent syscalls for i386/i486/i586
+ *
+ * 1.00 93/08/26 proven
+ * -Started coding this file.
+ *
+ * 1.01 93/11/13 proven
+ * -The functions readv() and writev() added.
+ */
+
+#ifndef lint
+ .text
+ .asciz "$Id$";
+#endif
+
+#if defined(SYSLIBC_SCCS) && !defined(lint)
+ .asciz "@(#)syscall.s 5.1 (Berkeley) 4/23/90"
+#endif /* SYSLIBC_SCCS and not lint */
+
+#include <machine/asm.h>
+#include <sys/syscall.h>
+
+/*
+ * Initial asm stuff for all functions.
+ */
+ .text
+ .align 2
+
+
+/* ==========================================================================
+ * error code for all syscalls. The error value is returned as the negative
+ * of the errno value.
+ */
+
+1:
+ neg %eax
+ ret
+
+/* ==========================================================================
+ * machdep_sys_fork()
+ */
+ .globl _machdep_sys_fork;
+
+_machdep_sys_fork:;
+
+ movl $(SYS_fork), %eax;
+ .byte 0x9a; .long 0; .word 7;
+ cmpl $0, %edx
+ je 2f
+ movl $0, %eax
+2:
+ ret;
+
+/* ==========================================================================
+ * machdep_sys___syscall()
+ */
+
+_machdep_sys___syscall:;
+
+ movl $(SYS___syscall), %eax;
+ .byte 0x9a; .long 0; .word 7;
+ jb 3f;
+ ret
+
+/* ==========================================================================
+ * machdep_sys_sigsuspend()
+ */
+ .globl _machdep_sys_sigsuspend;
+
+_machdep_sys_sigsuspend:;
+
+ movl 4(%esp),%eax # fetch mask arg
+ movl (%eax),%eax # indirect to mask arg
+ movl %eax,4(%esp)
+ movl $(SYS_sigsuspend), %eax;
+ .byte 0x9a; .long 0; .word 7;
+ jb 3f;
+ ret
+
+3:
+
+ neg %eax
+ movl $0xffffffff,%edx
+ ret
+
+/* ==========================================================================
+ * machdep_sys_lseek()
+ */
+ .globl _machdep_sys_lseek;
+
+_machdep_sys_lseek:;
+
+ pushl %ebp;
+ movl %esp,%ebp;
+ pushl 0x14(%ebp);
+ pushl 0x10(%ebp);
+ pushl 0xc(%ebp);
+ pushl $0x0;
+ pushl 0x8(%ebp);
+ pushl $0x0;
+ pushl $(SYS_lseek);
+ call _machdep_sys___syscall;
+ leave
+ ret
+
+/* ==========================================================================
+ * machdep_sys_ftruncate() ; Added by Monty
+ */
+ .globl _machdep_sys_ftruncate;
+
+_machdep_sys_ftruncate:;
+
+ pushl %ebp;
+ movl %esp,%ebp;
+ pushl 0x10(%ebp);
+ pushl 0xc(%ebp);
+ pushl $0x0; # Why this?
+ pushl 0x8(%ebp);
+ pushl $0x0; # And this?
+ pushl $(SYS_ftruncate);
+ call _machdep_sys___syscall;
+ leave
+ ret
diff --git a/mit-pthreads/machdep/syscall-i386-netbsd-1.1.S b/mit-pthreads/machdep/syscall-i386-netbsd-1.1.S
new file mode 100644
index 00000000000..a74d2ac1af6
--- /dev/null
+++ b/mit-pthreads/machdep/syscall-i386-netbsd-1.1.S
@@ -0,0 +1,181 @@
+/* ==== syscall.S ============================================================
+ * Copyright (c) 1990 The Regents of the University of California.
+ * Copyright (c) 1993 Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Description : Machine dependent syscalls for i386/i486/i586
+ *
+ * 1.00 93/08/26 proven
+ * -Started coding this file.
+ *
+ * 1.01 93/11/13 proven
+ * -The functions readv() and writev() added.
+ */
+
+#ifndef lint
+ .text
+ .asciz "$Id$";
+#endif
+
+#if defined(SYSLIBC_SCCS) && !defined(lint)
+ .asciz "@(#)syscall.s 5.1 (Berkeley) 4/23/90"
+#endif /* SYSLIBC_SCCS and not lint */
+
+#include <machine/asm.h>
+#include <sys/syscall.h>
+
+/*
+ * Initial asm stuff for all functions.
+ */
+ .text
+ .align 2
+
+
+/* ==========================================================================
+ * machdep_sys_fork()
+ */
+ .globl _machdep_sys_fork;
+
+_machdep_sys_fork:;
+
+ movl $(SYS_fork), %eax;
+ .byte 0x9a; .long 0; .word 7;
+ cmpl $0, %edx
+ je 2f
+ movl $0, %eax
+2:
+ ret;
+
+/* ==========================================================================
+ * machdep_sys___syscall()
+ */
+
+_machdep_sys___syscall:;
+
+ movl $(SYS___syscall), %eax;
+ int $0x80;
+ jb 3f;
+ ret
+
+/* ==========================================================================
+ * machdep_sys_sigsuspend()
+ */
+ .globl _machdep_sys_sigsuspend;
+
+_machdep_sys_sigsuspend:;
+
+ movl 4(%esp),%eax # fetch mask arg
+ movl (%eax),%eax # indirect to mask arg
+ movl %eax,4(%esp)
+ movl $(SYS_sigsuspend), %eax;
+ int $0x80;
+ jb 3f;
+ ret
+
+3:
+
+ neg %eax
+ movl $0xffffffff,%edx
+ ret
+
+/* ==========================================================================
+ * machdep_sys_lseek()
+ */
+ .globl _machdep_sys_lseek;
+
+_machdep_sys_lseek:;
+
+ pushl %ebp;
+ movl %esp,%ebp;
+ pushl 0x14(%ebp);
+ pushl 0x10(%ebp);
+ pushl 0xc(%ebp);
+ pushl $0x0;
+ pushl 0x8(%ebp);
+ pushl $0x0;
+ pushl $(SYS_lseek);
+ call _machdep_sys___syscall;
+ leave
+ ret
+
+/* ==========================================================================
+ * machdep_sys_ftruncate() ; Added by Monty
+ */
+ .globl _machdep_sys_ftruncate;
+
+_machdep_sys_ftruncate:;
+
+ pushl %ebp;
+ movl %esp,%ebp;
+ pushl 0x10(%ebp);
+ pushl 0xc(%ebp);
+ pushl $0x0; # Why this?
+ pushl 0x8(%ebp);
+ pushl $0x0; # And this?
+ pushl $(SYS_ftruncate);
+ call _machdep_sys___syscall;
+ leave
+ ret
+
+/* ==========================================================================
+ * machdep_sys_sigprocmask()
+ */
+ .globl _machdep_sys_sigprocmask;
+
+_machdep_sys_sigprocmask:;
+
+ movl 8(%esp),%ecx
+ movl (%ecx),%ecx
+ movl %ecx,8(%esp)
+ movl $(SYS_sigprocmask), %eax;
+ int $0x80;
+ jb 3b;
+ ret
+
+/* ==========================================================================
+ * machdep_sys_pipe()
+ */
+ .globl _machdep_sys_pipe;
+
+_machdep_sys_pipe:;
+
+ movl $(SYS_pipe), %eax;
+ int $0x80;
+ jb 3b;
+ movl 4(%esp),%ecx
+ movl %eax,(%ecx)
+ movl %edx,4(%ecx)
+ xorl %eax,%eax
+ ret
+
diff --git a/mit-pthreads/machdep/syscall-i386-netbsd-1.3.S b/mit-pthreads/machdep/syscall-i386-netbsd-1.3.S
new file mode 100644
index 00000000000..85dc6b3e5bc
--- /dev/null
+++ b/mit-pthreads/machdep/syscall-i386-netbsd-1.3.S
@@ -0,0 +1,200 @@
+/* ==== syscall.S ============================================================
+ * Copyright (c) 1990 The Regents of the University of California.
+ * Copyright (c) 1993 Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Description : Machine dependent syscalls for i386/i486/i586
+ *
+ * 1.00 93/08/26 proven
+ * -Started coding this file.
+ *
+ * 1.01 93/11/13 proven
+ * -The functions readv() and writev() added.
+ */
+
+#ifndef lint
+ .text
+ .asciz "$Id$";
+#endif
+
+#if defined(SYSLIBC_SCCS) && !defined(lint)
+ .asciz "@(#)syscall.s 5.1 (Berkeley) 4/23/90"
+#endif /* SYSLIBC_SCCS and not lint */
+
+#include <machine/asm.h>
+#include <sys/syscall.h>
+
+/*
+ * Initial asm stuff for all functions.
+ */
+ .text
+ .align 2
+
+
+/* ==========================================================================
+ * machdep_sys_fork()
+ */
+ .globl _C_LABEL(machdep_sys_fork);
+
+_C_LABEL(machdep_sys_fork):;
+
+ movl $(SYS_fork), %eax;
+ .byte 0x9a; .long 0; .word 7;
+ cmpl $0, %edx
+ je 2f
+ movl $0, %eax
+2:
+ ret;
+
+/* ==========================================================================
+ * machdep_sys___syscall()
+ */
+
+_machdep_sys___syscall:;
+
+ movl $(SYS___syscall), %eax;
+ int $0x80;
+ jb 3f;
+ ret
+
+#ifndef SYS___sigsuspend14
+/* ==========================================================================
+ * machdep_sys_sigsuspend()
+ */
+ .globl _C_LABEL(machdep_sys_sigsuspend);
+
+_C_LABEL(machdep_sys_sigsuspend):;
+
+ movl 4(%esp),%eax # fetch mask arg
+ movl (%eax),%eax # indirect to mask arg
+ movl %eax,4(%esp)
+ movl $(SYS_sigsuspend), %eax;
+ int $0x80;
+ jb 3f;
+ ret
+#endif
+
+3:
+
+ neg %eax
+ movl $0xffffffff,%edx
+ ret
+
+/* ==========================================================================
+ * machdep_sys_lseek()
+ */
+ .globl _C_LABEL(machdep_sys_lseek);
+
+_C_LABEL(machdep_sys_lseek):;
+
+ pushl %ebp;
+ movl %esp,%ebp;
+ pushl 0x14(%ebp);
+ pushl 0x10(%ebp);
+ pushl 0xc(%ebp);
+ pushl $0x0;
+ pushl 0x8(%ebp);
+ pushl $0x0;
+ pushl $(SYS_lseek);
+ call _machdep_sys___syscall;
+ leave
+ ret
+
+/* ==========================================================================
+ * machdep_sys_ftruncate() ; Added by Monty
+ */
+ .globl _C_LABEL(machdep_sys_ftruncate);
+
+_C_LABEL(machdep_sys_ftruncate):;
+
+ pushl %ebp;
+ movl %esp,%ebp;
+ pushl 0x10(%ebp);
+ pushl 0xc(%ebp);
+ pushl $0x0; # Why this?
+ pushl 0x8(%ebp);
+ pushl $0x0; # And this?
+ pushl $(SYS_ftruncate);
+ call _machdep_sys___syscall;
+ leave
+ ret
+
+#ifndef SYS___sigprocmask14
+/* ==========================================================================
+ * machdep_sys_sigprocmask()
+ */
+ .globl _C_LABEL(machdep_sys_sigprocmask);
+
+_C_LABEL(machdep_sys_sigprocmask):;
+
+ movl 8(%esp),%ecx
+ movl (%ecx),%ecx
+ movl %ecx,8(%esp)
+ movl $(SYS_sigprocmask), %eax;
+ int $0x80;
+ jb 3b;
+ ret
+#endif
+
+/* ==========================================================================
+ * machdep_sys_pipe()
+ */
+ .globl _C_LABEL(machdep_sys_pipe);
+
+_C_LABEL(machdep_sys_pipe):;
+
+ movl $(SYS_pipe), %eax;
+ int $0x80;
+ jb 3b;
+ movl 4(%esp),%ecx
+ movl %eax,(%ecx)
+ movl %edx,4(%ecx)
+ xorl %eax,%eax
+ ret
+
+/* ==========================================================================
+ * machdep_sys_fstat()
+ */
+ .globl _C_LABEL(machdep_sys_fstat);
+
+_C_LABEL(machdep_sys_fstat):;
+ movl $(SYS___fstat13), %eax;
+ int $0x80;
+ jb 4f;
+ ret
+4:
+ neg %eax
+ movl $0xffffffff,%edx
+ ret
+
diff --git a/mit-pthreads/machdep/syscall-i386-openbsd-2.0.S b/mit-pthreads/machdep/syscall-i386-openbsd-2.0.S
new file mode 100644
index 00000000000..cfdbbc77f73
--- /dev/null
+++ b/mit-pthreads/machdep/syscall-i386-openbsd-2.0.S
@@ -0,0 +1,237 @@
+/* ==== syscall.S ============================================================
+ * Copyright (c) 1990 The Regents of the University of California.
+ * Copyright (c) 1995 Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Description : Machine dependent syscalls for i386/i486/i586
+ *
+ */
+
+#ifndef lint
+ .text
+ .asciz "syscall-i386-freebsd-2.0.S,v 1.2 1995/05/26 07:44:29 proven Exp";
+#endif
+
+#if defined(SYSLIBC_SCCS) && !defined(lint)
+ .asciz "@(#)syscall.s 5.1 (Berkeley) 4/23/90"
+#endif /* SYSLIBC_SCCS and not lint */
+
+#include <sys/syscall.h>
+
+#ifdef __STDC__
+
+#define SYSCALL(x) \
+ .globl _machdep_sys_##x##; \
+ \
+_machdep_sys_##x##:; \
+ \
+ movl $(SYS_##x##), %eax; \
+ .byte 0x9a; .long 0; .word 7; \
+ jb 1b; \
+ ret;
+
+#else
+
+#define SYSCALL(x) \
+ .globl _machdep_sys_/**/x; \
+ \
+_machdep_sys_/**/x:; \
+ \
+ movl $(SYS_/**/x), %eax; \
+ .byte 0x9a; .long 0; .word 7; \
+ jb 1b; \
+ ret;
+
+#endif
+
+
+/*
+ * Initial asm stuff for all functions.
+ */
+ .text
+ .align 2
+
+
+/* ==========================================================================
+ * error code for all syscalls. The error value is returned as the negative
+ * of the errno value.
+ */
+
+1:
+ neg %eax
+ ret
+
+/* ==========================================================================
+ * machdep_sys_fork()
+ */
+ .globl _machdep_sys_fork;
+
+_machdep_sys_fork:;
+
+ movl $(SYS_fork), %eax;
+ .byte 0x9a; .long 0; .word 7;
+ cmpl $0, %edx
+ je 2f
+ movl $0, %eax
+2:
+ ret;
+
+/* ==========================================================================
+ * machdep_sys___syscall()
+ */
+
+_machdep_sys___syscall:;
+
+ movl $(SYS___syscall), %eax;
+ .byte 0x9a; .long 0; .word 7;
+ jb 3f;
+ ret
+
+/* ==========================================================================
+ * machdep_sys_sigsuspend()
+ */
+ .globl _machdep_sys_sigsuspend;
+
+_machdep_sys_sigsuspend:;
+
+ movl 4(%esp),%eax # fetch mask arg
+ movl (%eax),%eax # indirect to mask arg
+ movl %eax,4(%esp)
+ movl $(SYS_sigsuspend), %eax;
+ .byte 0x9a; .long 0; .word 7;
+ jb 3f;
+ ret
+
+3:
+
+ neg %eax
+ movl $0xffffffff,%edx
+ ret
+
+/* ==========================================================================
+ * machdep_sys_sigprocmask()
+ */
+ .globl _machdep_sys_sigprocmask;
+
+_machdep_sys_sigprocmask:;
+
+ movl 8(%esp),%ecx
+ movl (%ecx),%ecx
+ movl %ecx,8(%esp)
+ movl $ SYS_sigprocmask , %eax
+ .byte 0x9a; .long 0; .word 7;
+ jb 4f;
+ ret
+
+4:
+ neg %eax
+ movl $0xffffffff,%edx
+ ret
+
+/* ==========================================================================
+ * machdep_sys_lseek()
+ */
+ .globl _machdep_sys_lseek;
+
+_machdep_sys_lseek:;
+
+ pushl %ebp;
+ movl %esp,%ebp;
+ pushl 0x14(%ebp);
+ pushl 0x10(%ebp);
+ pushl 0xc(%ebp);
+ pushl $0x0;
+ pushl 0x8(%ebp);
+ pushl $0x0;
+ pushl $(SYS_lseek);
+ call _machdep_sys___syscall;
+ leave
+ ret
+
+/* ==========================================================================
+ * machdep_sys_ftruncate() ; Added by Monty
+ */
+ .globl _machdep_sys_ftruncate;
+
+_machdep_sys_ftruncate:;
+
+ pushl %ebp;
+ movl %esp,%ebp;
+ pushl 0x10(%ebp);
+ pushl 0xc(%ebp);
+ pushl $0x0; # Why this?
+ pushl 0x8(%ebp);
+ pushl $0x0; # And this?
+ pushl $(SYS_ftruncate);
+ call _machdep_sys___syscall;
+ leave
+ ret
+
+/* ==========================================================================
+ * machdep_sys_setjmp()
+ */
+ .globl _machdep_sys_setjmp;
+
+_machdep_sys_setjmp:;
+ movl 4(%esp),%eax
+ movl 0(%esp),%edx
+ movl %edx, 0(%eax) /* rta */
+ movl %ebx, 4(%eax)
+ movl %esp, 8(%eax)
+ movl %ebp,12(%eax)
+ movl %esi,16(%eax)
+ movl %edi,20(%eax)
+ xorl %eax,%eax
+ ret
+
+/* ==========================================================================
+ * machdep_sys_longjmp()
+ */
+ .globl _machdep_sys_longjmp;
+
+_machdep_sys_longjmp:;
+ movl 4(%esp),%edx
+ movl 8(%esp),%eax
+ movl 0(%edx),%ecx
+ movl 4(%edx),%ebx
+ movl 8(%edx),%esp
+ movl 12(%edx),%ebp
+ movl 16(%edx),%esi
+ movl 20(%edx),%edi
+ testl %eax,%eax
+ jnz 1f
+ incl %eax
+1: movl %ecx,0(%esp)
+ ret
+
diff --git a/mit-pthreads/machdep/syscall-i386-sco-3.2v5.S b/mit-pthreads/machdep/syscall-i386-sco-3.2v5.S
new file mode 100644
index 00000000000..0a60dcdd866
--- /dev/null
+++ b/mit-pthreads/machdep/syscall-i386-sco-3.2v5.S
@@ -0,0 +1,442 @@
+/* ==== syscall.S ============================================================
+ * Copyright (c) 1990 The Regents of the University of California.
+ * Copyright (c) 1995 Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Description : Machine dependent syscalls for i386/i486/i586
+ *
+ */
+
+#ifndef lint
+ .text
+ .asciz "syscall-i386-sco-3.2v5.S,v 1.2 1995/05/26 07:44:29 proven Exp";
+#endif
+
+#if defined(SYSLIBC_SCCS) && !defined(lint)
+ .asciz "@(#)syscall.s 5.1 (Berkeley) 4/23/90"
+#endif /* SYSLIBC_SCCS and not lint */
+
+#include <sys/errno.h>
+#include <sys/syscall.h>
+
+#ifdef _SCO_ELF
+
+#define NAME(X) machdep_sys_##X
+#define GETADDR(X) \
+ call 1f; \
+1: \
+ popl %ebx; \
+ addl $NAME(X)+[.-1b], %ebx
+
+#define END(X) 1: ; .type NAME(X),@function ; .size NAME(X),1b - NAME(X)
+
+#else
+
+#define NAME(X) _machdep_sys_##X
+#define END(X)
+
+#endif
+
+#ifdef __STDC__
+
+#define SYSCALL(x) \
+ .globl NAME(x); \
+ \
+NAME(x): \
+ movl $(SYS_##x##), %eax; \
+ lcall $7, $0; \
+ jae 1f; \
+ cmp $(ERESTART), %eax; \
+ je NAME(x); \
+ neg %eax; \
+1: \
+ ret; \
+\
+ END(x)
+
+
+#else
+
+#define SYSCALL(x) \
+ .globl NAME(x); \
+ \
+NAME(x): \
+ \
+ movl $(SYS_/**/x), %eax; \
+ lcall $7, $0; \
+ jb 1b; \
+ ret; \
+ END(x)
+
+#endif
+
+
+/*
+ * Initial asm stuff for all functions.
+ */
+ .text
+ .align 2
+
+/* ==========================================================================
+ * machdep_sys_fork()
+ */
+ .globl NAME(fork);
+
+NAME(fork):;
+ movl $(SYS_fork), %eax
+ lcall $7, $0
+ jae 1f
+ neg %eax
+ ret
+1:
+ test %edx, %edx
+ je 2f
+ xor %eax, %eax
+2:
+ ret;
+ END(fork)
+
+/* ==========================================================================
+ * NAME(getdents)
+ */
+ .globl NAME(getdents);
+
+NAME(getdents):
+ movl $(SYS_getdents), %eax;
+ lcall $7, $0
+ jae 1f
+ neg %eax
+1:
+ ret;
+ END(getdents)
+
+/* ==========================================================================
+ * NAME(fxstat)
+ */
+ .globl NAME(fxstat);
+
+NAME(fxstat):;
+ movl $(SYS_fxstat), %eax;
+ lcall $7, $0
+ jae 1f
+ neg %eax;
+ ret;
+1:
+ xor %eax, %eax;
+ ret;
+ END(fxstat)
+
+/* ==========================================================================
+ * NAME(signal)
+ */
+ .globl NAME(signal);
+
+NAME(signal):;
+ movl 4(%esp), %ecx
+ movl $(SYS_signal),%eax
+#if 0
+ call .L1
+.L1:
+ popl %edx
+ addl $(NAME(sigreturn)+[.-.L1]), %edx
+#else
+ movl $NAME(sigreturn), %edx
+#endif
+ lcall $7,$0
+ jae 1f
+# movl %eax, 12(%esp)
+ neg %eax
+ ret
+1:
+# xor %eax, %eax
+# movl %eax, 12(%esp)
+ ret
+ END(signal)
+
+/* ==========================================================================
+ * NAME(sigaction)
+ */
+ .globl NAME(sigaction);
+
+NAME(sigaction):
+ movl $(SYS_sigaction),%eax
+#if 0
+ call .L2
+.L2:
+ popl %edx
+ addl $(NAME(sigreturn)+[.-.L2]), %edx
+#else
+ movl $NAME(sigreturn), %edx
+#endif
+ lcall $7, $0
+ jb 1f
+ xor %eax, %eax
+ ret
+1:
+ neg %eax
+ ret
+ END(sigaction)
+
+ .globl NAME(sigreturn)
+NAME(sigreturn):
+ addl $4,%esp
+ lcall $0xf, $0
+ nop
+ nop
+ END(sigreturn)
+
+/* ==========================================================================
+ * NAME(waitpid)
+ */
+ .globl NAME(waitpid);
+
+NAME(waitpid):
+ .byte 0x9c
+ popl %eax
+ orl $0x8c4, %eax
+ pushl %eax
+ .byte 0x9d
+ movl $(SYS_wait), %eax
+ lcall $7, $0
+ jae 2f
+ cmpl $(ERESTART), %al
+ je NAME(waitpid)
+ neg %eax
+3:
+ ret
+2:
+ movl 8(%esp), %ecx
+ test %ecx,%ecx
+ je 3b
+ mov %edx, (%ecx)
+ ret
+ END(waitpid)
+
+/* ==========================================================================
+ * NAME(uname)
+ */
+ .globl NAME(uname);
+
+NAME(uname):
+ pushl $0
+ pushl $0
+ pushl 12(%esp)
+ subl $4, %esp
+ movl $(SYS_utssys), %eax
+ .byte 0x9a; .long 0; .word 7;
+ jb 1f
+ addl $16, %esp
+ ret
+1:
+ addl $16, %esp
+ neg %eax
+ ret
+ END(uname)
+
+
+/* ==========================================================================
+ * machdep_sys_ftruncate
+ */
+
+SYSCALL(ftruncate)
+
+/* ==========================================================================
+ * machdep_sys_ftime
+ */
+
+SYSCALL(ftime)
+
+/* ==========================================================================
+ * machdep_sys_gettimeofday()
+ */
+
+SYSCALL(gettimeofday)
+
+/* ==========================================================================
+ * machdep_sys_kill()
+ */
+
+SYSCALL(kill)
+
+/* ==========================================================================
+ * pthread_sys_setitimer
+ */
+ .globl NAME(setitimer);
+
+NAME(setitimer):;
+ movl $(SYS_setitimer), %eax;
+ lcall $7, $0
+ jae 1f
+ neg %eax
+ ret
+1:
+ xor %eax, %eax
+ ret;
+ END(setitimer)
+
+/* ==========================================================================
+ * pthread_sys_sysconf
+ */
+ .globl NAME(sysconf);
+
+NAME(sysconf):;
+ movl $(SYS_sysconf), %eax;
+ lcall $7, $0
+ jae 1f
+ neg %eax
+1:
+ ret;
+ END(sysconf)
+
+/* ==========================================================================
+ * pthread_sys_sysi86()
+ */
+ .globl NAME(sysi86);
+
+NAME(sysi86):;
+ movl $(SYS_sysi86), %eax
+ lcall $7, $0
+ jae 1f
+ neg %eax
+1:
+ ret;
+ END(sysi86)
+
+
+/* ==========================================================================
+ * machdep_sys_brk()
+ */
+ .globl NAME(brk);
+
+NAME(brk):;
+ movl $(SYS_break), %eax
+ lcall $7, $0
+ jae 1f
+ neg %eax
+ ret
+1:
+ xor %eax, %eax
+ ret;
+ END(brk)
+
+/* ==========================================================================
+ * machdep_sys_pipe()
+ */
+ .globl NAME(pipe);
+
+NAME(pipe):;
+ movl $(SYS_pipe), %eax;
+ lcall $7, $0
+ jae 1f
+ neg %eax
+ ret
+1:
+ movl 4(%esp), %ecx
+ movl %eax, (%ecx)
+ movl %edx, 4(%ecx)
+ xor %eax, %eax
+ ret;
+ END(brk)
+
+/* ==========================================================================
+ * machdep_sys_fcntl()
+ */
+ .globl NAME(fcntl);
+
+NAME(fcntl):;
+ movl $(SYS_fcntl), %eax
+ lcall $7, $0
+ jae 1f
+ neg %eax
+1:
+ ret
+ END(fcntl)
+
+
+/* ==========================================================================
+ * machdep_sys_select()
+ */
+ .globl NAME(select);
+
+NAME(select):;
+ movl $(SYS_select), %eax
+ lcall $7, $0
+ jae 1f
+ cmp $(ERESTART), %eax
+ jne 2f
+ movl $(EINTR), %eax
+2:
+ neg %eax
+1:
+ ret
+ END(select)
+
+
+/* ==========================================================================
+ * setjmp()
+ */
+ .globl setjmp;
+
+setjmp:
+ movl 4(%esp),%eax
+ movl %ebx,(%eax)
+ movl %esi,4(%eax)
+ movl %edi,8(%eax)
+ movl %ebp,12(%eax)
+ popl %edx
+ movl %esp,16(%eax)
+ movl %edx,20(%eax)
+ subl %eax,%eax
+ jmp *%edx
+1: ; .type setjmp,@function ; .size setjmp,1b - setjmp
+
+/* ==========================================================================
+ * longjmp()
+ */
+ .globl longjmp;
+
+longjmp:
+ movl 4(%esp),%edx
+ movl 8(%esp),%eax
+ movl 0(%edx),%ebx
+ movl 4(%edx),%esi
+ movl 8(%edx),%edi
+ movl 12(%edx),%ebp
+ movl 16(%edx),%esp
+ test %eax,%eax
+ jne 1f
+ inc %eax
+1:
+ jmp *20(%edx)
+1: ; .type longjmp,@function ; .size longjmp,1b - longjmp
diff --git a/mit-pthreads/machdep/syscall-ip22-irix-5.2.S b/mit-pthreads/machdep/syscall-ip22-irix-5.2.S
new file mode 100644
index 00000000000..ded0fc55e38
--- /dev/null
+++ b/mit-pthreads/machdep/syscall-ip22-irix-5.2.S
@@ -0,0 +1,106 @@
+#include <sys.s>
+#include <sys/regdef.h>
+
+/*
+ Kernel syscall interface:
+ Input:
+ v0 syscall number
+ Output:
+
+ This macro is similar to SYSCALL in sys/syscall.h, but not completely.
+ There's room for optimization, if we assume this will continue to
+ be assembled as one file.
+
+ Compile with -DPIC for pic code.
+*/
+
+#ifdef PIC
+#define PICOPT .option pic2
+#else
+#define PICOPT
+#endif
+
+
+#define YSYSCALL(x) \
+ PICOPT; \
+ .globl machdep_sys_##x; \
+ .ent machdep_sys_##x, 0; \
+machdep_sys_##x:; \
+ .frame sp,0,ra; \
+ .set noreorder; \
+ li v0, SYS_##x; \
+ syscall; \
+ bne a3, zero, 1b; \
+ nop; \
+ j ra; \
+ nop; \
+ .end machdep_sys_##x
+
+/* ==========================================================================
+ * error code for all syscalls. The error value is returned as the negative
+ * of the errno value.
+ */
+
+1:
+ subu v0,zero,v0;
+ j ra;
+
+/* ==========================================================================
+ * lstat
+ */
+ PICOPT;
+ .globl machdep_sys_lstat;
+ .ent machdep_sys_lstat, 0;
+machdep_sys_lstat:;
+ .frame sp,0,ra;
+ .set noreorder;
+ move a2, a1
+ move a1, a0
+ li a0, 2
+ li v0, SYS_lxstat;
+ syscall;
+ bne a3, zero, 1b;
+ nop;
+ j ra;
+ nop;
+ .end machdep_sys_lstat
+
+/* ==========================================================================
+ * fstat
+ */
+ PICOPT;
+ .globl machdep_sys_fstat;
+ .ent machdep_sys_fstat, 0;
+machdep_sys_fstat:;
+ .frame sp,0,ra;
+ .set noreorder;
+ move a2, a1
+ move a1, a0
+ li a0, 2
+ li v0, SYS_fxstat;
+ syscall;
+ bne a3, zero, 1b;
+ nop;
+ j ra;
+ nop;
+ .end machdep_sys_fstat
+
+/* ==========================================================================
+ * stat
+ */
+ PICOPT;
+ .globl machdep_sys_stat;
+ .ent machdep_sys_stat, 0;
+machdep_sys_stat:;
+ .frame sp,0,ra;
+ .set noreorder;
+ move a2, a1
+ move a1, a0
+ li a0, 2
+ li v0, SYS_xstat;
+ syscall;
+ bne a3, zero, 1b;
+ nop;
+ j ra;
+ nop;
+ .end machdep_sys_stat
diff --git a/mit-pthreads/machdep/syscall-m68000-netbsd.S b/mit-pthreads/machdep/syscall-m68000-netbsd.S
new file mode 100644
index 00000000000..f36286770a2
--- /dev/null
+++ b/mit-pthreads/machdep/syscall-m68000-netbsd.S
@@ -0,0 +1,83 @@
+
+#ifndef lint
+ .text
+ .asciz "$Id$";
+#endif
+
+#include <machine/asm.h>
+#include <sys/syscall.h>
+
+#ifdef __STDC__
+#define IMM #
+#define SYSCALL(x) .even; ENTRY(machdep_sys_ ## x); \
+ movl IMM SYS_ ## x,d0; trap IMM 0; jcs err; rts
+#else /* !__STDC__ */
+#define SYSCALL(x) .even; ENTRY(machdep_sys_/**/x); \
+ movl #SYS_/**/x,d0; trap #0; jcs err; rts
+#endif /* !__STDC__ */
+
+/*
+ * Initial asm stuff for all functions.
+ */
+ .text
+ .even
+
+
+/* ==========================================================================
+ * error code for all syscalls. The error value is returned as the negative
+ * of the errno value.
+ */
+
+err:
+ negl d0
+ rts
+
+/* ==========================================================================
+ * machdep_sys_pipe
+ */
+ .even
+ENTRY(machdep_sys_pipe);
+ movl #SYS_pipe,d0
+ trap #0
+ jcs err
+ movl sp@(4),a0
+ movl d0,a0@+
+ movl d1,a0@
+ clrl d0
+ rts
+
+#ifndef SYS___sigsuspend14
+ .even
+ENTRY(machdep_sys_sigsuspend)
+ movl sp@(4),a0
+ movl a0@,sp@(4)
+ movl #SYS_compat_13_sigsuspend13,d0
+ trap #0
+ jcs err
+ clrl d0
+ rts
+#endif
+
+#ifndef SYS___sigprocmask14
+ .even
+ENTRY(machdep_sys_sigprocmask)
+ tstl sp@(8)
+ jne gotptr
+/* movl #0,sp@(8) /* null mask pointer; block empty set */
+ movl #1,sp@(4)
+ jra doit
+gotptr:
+ movl sp@(8),a0
+ movl a0@,sp@(8)
+doit:
+ movl #SYS_compat_13_sigprocmask13,d0
+ trap #0
+ jcs err
+ tstl sp@(12)
+ jeq out
+ movl sp@(12),a0
+ movl d0,a0@
+out:
+ clrl d0
+ rts
+#endif
diff --git a/mit-pthreads/machdep/syscall-r2000-ultrix-4.2.S b/mit-pthreads/machdep/syscall-r2000-ultrix-4.2.S
new file mode 100644
index 00000000000..dc891dc37bd
--- /dev/null
+++ b/mit-pthreads/machdep/syscall-r2000-ultrix-4.2.S
@@ -0,0 +1,166 @@
+/* ==== syscall.S ============================================================
+ * Copyright (c) 1993 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Description : Machine dependent syscalls for decstation with r2000/r3000
+ *
+ * 1.00 93/08/14 proven
+ * -Started coding this file.
+ */
+
+ .text
+ .ascii "$Id$";
+
+#include <syscall.h>
+#include <machine/regdef.h>
+
+/*
+ * Initial asm stuff for all functions.
+ */
+ .text
+ .align 2
+
+/* ==========================================================================
+ * error code for all syscalls. The error value is returned as the negative
+ * of the errno value. Eventually I want to load the errno value directly
+ * into pthread_run->error but until then ...
+ */
+machdep_error:
+ negu v0, v0 /* Return negative of errno value. */
+ j ra
+
+/* ==========================================================================
+ * Syscalls already done,
+ * Standard Other important BSD sockets
+ * fork = 2 select = 93 socket = 97
+ * read = 3 readv = 120 connect = 98
+ * write = 4 writev = 121 accept = 99
+ * open = 5 getdirentries = send = 101
+ * close = 6 recv = 102
+ * creat = 8 bind = 104
+ * link = 9 listen = 106
+ * unlink = 10 recvmsg = 113
+ * chdir = 12 sendmsg = 114
+ * chmod = 15 getsockopt = 118
+ * chown = 16 recvfrom = 125
+ * lseek = 19 sendto = 133
+ * stat = 38 shutdown = 134
+ * dup = 41 getpeername = 141
+ * pipe = 42
+ * execve = 59
+ * fstat = 62
+ * wait3 = 84
+ * dup2 = 90
+ * fcntl = 92
+ * fchown = 123
+ * fchmod = 124
+ * rename = 128
+ * waitpid = 189
+ * ======================================================================= */
+
+/* ==========================================================================
+ * machdep_sys_fork()
+ */
+ .globl machdep_sys_fork
+ .ent machdep_sys_fork
+
+machdep_sys_fork:
+
+ .frame sp,0,ra /* No frame, return address in ra */
+
+ li v0,SYS_fork /* Load fork syscall # into v0 */
+ syscall
+ bne a3,zero,machdep_error /* Error if a3 != 0 */
+ beqz v1,__fork_parent /* Second return value = 0, if parent */
+ li v0,0
+__fork_parent:
+ j ra
+
+ .end machdep_sys_fork
+
+/* ==========================================================================
+ * machdep_sys_pipe()
+ */
+ .globl machdep_sys_pipe
+ .ent machdep_sys_pipe
+
+machdep_sys_pipe:
+
+ .frame sp,0,ra /* No frame, return address in ra */
+
+ li v0,SYS_pipe /* Load pipe syscall # into v0 */
+ syscall
+ bne a3,zero,machdep_error /* Error if a3 != 0 */
+ sw v0, 0(a0)
+ sw v1, 4(a0)
+ li v0, 0
+ j ra
+
+ .end machdep_sys_pipe
+
+/* ==========================================================================
+ * Other important asm routines.
+ * ======================================================================= */
+/* ==========================================================================
+ * fake_setjmp()
+ */
+ .globl fake_setjmp
+ .ent fake_setjmp
+
+fake_setjmp:
+
+ .frame sp,0,ra /* No frame, return address in ra */
+
+ /* Save all the important registers */
+ sw ra,8(a0)
+ sw gp,124(a0)
+ sw sp,128(a0)
+ sw s0,76(a0)
+ /* More registers needed. */
+ j ra
+
+ .end fake_longjmp
+
+/* ==========================================================================
+ * machdep_sys_longjmp()
+ */
+ .globl machdep_sys_longjmp
+ .ent machdep_sys_longjmp
+
+machdep_sys_longjmp:
+
+ .frame sp,0,ra /* No frame, return address in ra */
+ li a1,1 /* Load 1 into reg a1 */
+ sw a1, 20(a0); /* Load a1 into address a0 + 20 */
+ li v0,SYS_sigreturn /* Load sigreturn syscall # into v0 */
+ syscall /* Do syscall to do longjmp */
+ j ra
+
+ .end machdep_sys_longjmp
diff --git a/mit-pthreads/machdep/syscall-romp-bsd.S b/mit-pthreads/machdep/syscall-romp-bsd.S
new file mode 100644
index 00000000000..233f0b9430b
--- /dev/null
+++ b/mit-pthreads/machdep/syscall-romp-bsd.S
@@ -0,0 +1,327 @@
+/* ==== syscall.S ============================================================
+ * Copyright (c) 1993 by John F. Carr, jfc@mit.edu
+ *
+ * 1.00 93/09/xx proven
+ * -Started coding this file.
+ */
+
+#ifndef lint
+static const char rcsid[] = "$Id$";
+#endif
+
+/* DO NOT USE COLONS IN THIS FILE, GCC CAN'T HANDLE THEM */
+/* #include <copyright.h> */
+
+ .globl .oVncs
+ .text
+ .align 2
+
+/* ==========================================================================
+ * machdep_sys_write()
+ */
+ .globl _machdep_sys_write
+ .globl _.machdep_sys_write
+
+ .text 2
+_machdep_sys_write:
+ .long _.machdep_sys_write
+
+ .text
+_.machdep_sys_write:
+ lcs r0,0(r3)
+ svc 4(r0)
+ bntbr r15
+ store r2,_errno,r5
+ brx r15
+ cal r2,-1(r0)
+
+
+/* ==========================================================================
+ * machdep_sys_read()
+ */
+ .globl _machdep_sys_read
+ .globl _.machdep_sys_read
+
+ .text 2
+_machdep_sys_read:
+ .long _.machdep_sys_read
+
+ .text
+_.machdep_sys_read:
+ lcs r0,0(r3)
+ svc 3(r0)
+ bntbr r15
+ store r2,_errno,r5
+ brx r15
+ cal r2,-1(r0)
+
+
+/* ==========================================================================
+ * machdep_sys_open()
+ */
+ .globl _machdep_sys_open
+ .globl _.machdep_sys_open
+
+ .text 2
+_machdep_sys_open:
+ .long _.machdep_sys_open
+
+ .text
+_.machdep_sys_open:
+ lcs r0,0(r2)
+ svc 5(r0)
+ bntbr r15
+ store r2,_errno,r5
+ brx r15
+ cal r2,-1(r0)
+
+
+/* ==========================================================================
+ * machdep_sys_bind()
+ */
+ .globl _machdep_sys_bind
+ .globl _.machdep_sys_bind
+
+ .text 2
+_machdep_sys_bind:
+ .long _.machdep_sys_bind
+
+ .text
+_.machdep_sys_bind:
+ ls r0,0(r3)
+ svc 104(r0)
+ bntbr r15
+ store r2,_errno,r5
+ brx r15
+ cal r2,-1(r0)
+
+
+/* ==========================================================================
+ * machdep_sys_socket()
+ */
+ .globl _machdep_sys_socket
+ .globl _.machdep_sys_socket
+
+ .text 2
+_machdep_sys_socket:
+ .long _.machdep_sys_socket
+
+ .text
+ .align 2
+_.machdep_sys_socket:
+ svc 97(r0)
+ bntbr r15
+ store r2,_errno,r5
+ brx r15
+ cal r2,-1(r0)
+
+
+/* ==========================================================================
+ * machdep_sys_close()
+ */
+ .globl _machdep_sys_close
+ .globl _.machdep_sys_close
+
+ .text 2
+_machdep_sys_close:
+ .long _.machdep_sys_close
+
+ .text
+ .align 2
+_.machdep_sys_close:
+ svc 6(r0)
+ bntbr r15
+ store r2,_errno,r5
+ brx r15
+ cal r2,-1(r0)
+
+
+/* ==========================================================================
+ * machdep_sys_connect()
+ */
+ .globl _machdep_sys_connect
+ .globl _.machdep_sys_connect
+
+ .text 2
+_machdep_sys_connect:
+ .long _.machdep_sys_connect
+
+ .text
+_.machdep_sys_connect:
+ lcs r0,0(r3)
+ svc 98(r0)
+ bntbr r15
+ store r2,_errno,r5
+ brx r15
+ cal r2,-1(r0)
+
+/* ==========================================================================
+ * machdep_sys_accept()
+ */
+ .globl _machdep_sys_accept
+ .globl _.machdep_sys_accept
+
+ .text 2
+_machdep_sys_accept:
+ .long _.machdep_sys_accept
+
+ .text
+_.machdep_sys_accept:
+ lcs r0,0(r3)
+ svc 99(r0)
+ bntbr r15
+ store r2,_errno,r5
+ cal r2,-1(r0)
+
+/* ==========================================================================
+ * machdep_sys_listen()
+ */
+ .globl _machdep_sys_listen
+ .globl _.machdep_sys_listen
+
+ .text 2
+ .align 2
+_machdep_sys_listen:
+ .long _.machdep_sys_listen
+
+ .text
+ .align 2
+_.machdep_sys_listen:
+ svc 106(r0)
+ bntbr r15
+ brx r15
+ twoc r2,r2
+
+/* ==========================================================================
+ * machdep_sys_fcntl()
+ */
+ .globl _.machdep_sys_fcntl
+ .globl _machdep_sys_fcntl
+
+ .text 2
+_machdep_sys_fcntl:
+ .long _.machdep_sys_fcntl
+ .text
+_.machdep_sys_fcntl:
+ lcs r0,0(sp)
+ svc 92(r0)
+ bntbr r15
+ store r2,_errno,r5
+ brx r15
+ cal r2,-1(r0)
+
+/* ==========================================================================
+ * machdep_sys_getpeername()
+ */
+ .globl _machdep_sys_getpeername
+ .globl _.machdep_sys_getpeername
+
+ .text 2
+_machdep_sys_getpeername:
+ .long _.machdep_sys_getpeername
+
+ .text
+_.machdep_sys_getpeername:
+ ls r0,0(sp)
+ svc 141(r0)
+ bntbr r15
+ brx r15
+ twoc r2,r2
+
+
+/* ==========================================================================
+ * machdep_sys_getsockopt()
+ */
+ .globl _machdep_sys_getsockopt
+ .globl _.machdep_sys_getsockopt
+
+ .text 2
+_machdep_sys_getsockopt:
+ .long _.machdep_sys_getsockopt
+
+ .text
+_.machdep_sys_getsockopt:
+ ls r0,0(sp)
+ svc 118(r0)
+ bntbr r15
+ brx r15
+ twoc r2,r2
+
+
+/* ==========================================================================
+ * machdep_sys_select()
+ */
+
+ .globl _.machdep_sys_select
+ .globl _machdep_sys_select
+
+ .text 2
+_machdep_sys_select:
+ .long _.machdep_sys_select
+ .text
+_.machdep_sys_select:
+ svc 93(r0)
+ bntbr r15
+ brx r15
+ twoc r2,r2
+
+/* ==========================================================================
+ * __tsh()
+ */
+ .globl _._tsh
+ .globl __tsh
+ .text 2
+__tsh: .long _._tsh
+ .text
+ .align 2
+_._tsh:
+ brx r15
+ tsh r2,0(r2)
+
+
+/* ==========================================================================
+ * __pthread_save()
+ */
+ .globl __pthread_save
+ .globl _._pthread_save
+ .text 2
+__pthread_save:
+ .long _._pthread_save
+ .text
+ .align 2
+_._pthread_save:
+ ail r5,r4,0
+ jne 1f
+ mr r4,sp
+ lis r5,0
+ stm r4,0(r2)
+ brx r15
+ lis r2,0
+1:
+ mr r0,r15 # save old return address
+ ls r15,0(r4) # new return address
+ mr r5,r4 # r0 to restore
+ mr r4,r3 # sp to restore
+ stm r4,0(r2)
+ brx r0
+ lis r2,0
+
+
+/* ==========================================================================
+ * __pthread_restore()
+ */
+ .globl __pthread_restore
+ .globl _._pthread_restore
+ .text 2
+__pthread_restore:
+ .long _._pthread_restore
+ .text
+ .align 2
+_._pthread_restore:
+ lm r4,0(r2)
+ mr r0,r5
+ lis r2,1
+ brx r15
+ mr sp,r4
+
+
diff --git a/mit-pthreads/machdep/syscall-sparc-netbsd-1.1.S b/mit-pthreads/machdep/syscall-sparc-netbsd-1.1.S
new file mode 100644
index 00000000000..9c4da4b1325
--- /dev/null
+++ b/mit-pthreads/machdep/syscall-sparc-netbsd-1.1.S
@@ -0,0 +1,102 @@
+/* ==== syscall.S ============================================================
+ * Copyright (c) 1994 Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ */
+
+#ifndef lint
+ .text
+ .asciz "$Id$";
+#endif
+
+#include <sys/syscall.h>
+
+#define SYSCALL(x) \
+ .globl _machdep_sys_##x; \
+ \
+_machdep_sys_##x:; \
+ \
+ mov SYS_##x, %g1; \
+ ta 0; \
+ bcs,a 2b; \
+ sub %r0,%o0,%o0; \
+ retl
+
+
+/*
+ * Initial asm stuff for all functions.
+ */
+ .text
+ .align 4
+
+/* ==========================================================================
+ * error code for all syscalls. The error value is returned as the negative
+ * of the errno value.
+ */
+
+1:
+ sub %r0, %o0, %o0
+2:
+ retl
+ nop
+
+/* ==========================================================================
+ * machdep_sys_pipe()
+ */
+ .globl _machdep_sys_pipe
+
+_machdep_sys_pipe:
+ mov %o0, %o2
+ mov SYS_pipe, %g1
+ ta 0
+ bcs 1b
+ nop
+ st %o0, [ %o2 ]
+ st %o1, [ %o2 + 4 ]
+ retl
+ mov %g0, %o0
+
+/* ==========================================================================
+ * machdep_sys_fork()
+ */
+ .globl _machdep_sys_fork;
+
+_machdep_sys_fork:;
+
+ mov SYS_fork, %g1;
+ ta 0;
+ bcs 1b;
+ nop;
+ dec %o1;
+ retl;
+ and %o0, %o1, %o0; ! return 0 in child, pid in parent
+
+/* ==========================================================================
+ * machdep_sys_sigprocmask()
+ */
+ .globl _machdep_sys_sigprocmask;
+
+_machdep_sys_sigprocmask:;
+
+ ld [%o1], %o1;
+ mov SYS_sigprocmask, %g1;
+ ta 0;
+ bcs 1b;
+ nop;
+ retl
+ nop
+
+/* ==========================================================================
+ * machdep_sys_sigsuspend()
+ */
+ .globl _machdep_sys_sigsuspend;
+
+_machdep_sys_sigsuspend:;
+
+ ld [%o0], %o0;
+ mov SYS_sigsuspend, %g1;
+ ta 0;
+ bcs 1b;
+ nop;
+ retl
+ nop
diff --git a/mit-pthreads/machdep/syscall-sparc-netbsd-1.3.S b/mit-pthreads/machdep/syscall-sparc-netbsd-1.3.S
new file mode 100644
index 00000000000..74a51e756b7
--- /dev/null
+++ b/mit-pthreads/machdep/syscall-sparc-netbsd-1.3.S
@@ -0,0 +1,172 @@
+/* ==== syscall.S ============================================================
+ * Copyright (c) 1994 Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ */
+
+#ifndef lint
+ .text
+ .asciz "$Id$";
+#endif
+
+#include <machine/asm.h>
+#include <sys/syscall.h>
+
+#define SYSCALL(x) \
+ .globl _C_LABEL(machdep_sys_##x); \
+ \
+_C_LABEL(machdep_sys_##x):; \
+ \
+ mov SYS_##x, %g1; \
+ ta 0; \
+ bcs,a 2b; \
+ sub %r0,%o0,%o0; \
+ retl
+
+
+/*
+ * Initial asm stuff for all functions.
+ */
+ .text
+ .align 4
+
+/* ==========================================================================
+ * error code for all syscalls. The error value is returned as the negative
+ * of the errno value.
+ */
+
+1:
+ sub %r0, %o0, %o0
+2:
+ retl
+ nop
+
+/* ==========================================================================
+ * machdep_sys_pipe()
+ */
+ .globl _C_LABEL(machdep_sys_pipe)
+
+_C_LABEL(machdep_sys_pipe):
+ mov %o0, %o2
+ mov SYS_pipe, %g1
+ ta 0
+ bcs 1b
+ nop
+ st %o0, [ %o2 ]
+ st %o1, [ %o2 + 4 ]
+ retl
+ mov %g0, %o0
+
+/* ==========================================================================
+ * machdep_sys_fork()
+ */
+ .globl _C_LABEL(machdep_sys_fork);
+
+_C_LABEL(machdep_sys_fork):;
+
+ mov SYS_fork, %g1;
+ ta 0;
+ bcs 1b;
+ nop;
+ dec %o1;
+ retl;
+ and %o0, %o1, %o0; ! return 0 in child, pid in parent
+
+#ifndef SYS___sigprocmask14
+/* ==========================================================================
+ * machdep_sys_sigprocmask()
+ */
+ .globl _C_LABEL(machdep_sys_sigprocmask);
+
+_C_LABEL(machdep_sys_sigprocmask):;
+
+ ld [%o1], %o1;
+ mov SYS_sigprocmask, %g1;
+ ta 0;
+ bcs 1b;
+ nop;
+ retl
+ nop
+#endif
+
+#ifndef SYS___sigsuspend14
+/* ==========================================================================
+ * machdep_sys_sigsuspend()
+ */
+ .globl _C_LABEL(machdep_sys_sigsuspend);
+
+_C_LABEL(machdep_sys_sigsuspend):;
+
+ ld [%o0], %o0;
+ mov SYS_sigsuspend, %g1;
+ ta 0;
+ bcs 1b;
+ nop;
+ retl
+ nop
+#endif
+
+/* ==========================================================================
+ * machdep_sys_fstat()
+ */
+ .globl _C_LABEL(machdep_sys_fstat);
+
+_C_LABEL(machdep_sys_fstat):;
+
+ mov SYS___fstat13, %g1;
+ ta 0;
+ bcs 1b;
+ nop;
+ retl
+ nop
+
+/* ==========================================================================
+ * machdep_sys___syscall()
+ */
+_machdep_sys___syscall:;
+
+ mov SYS___syscall, %g1;
+ ta 0;
+ bcs 1b;
+ nop;
+ retl
+ nop
+
+/* ==========================================================================
+ * machdep_sys_lseek()
+ */
+ .global _C_LABEL(machdep_sys_lseek)
+
+_C_LABEL(machdep_sys_lseek):
+ save %sp,-112,%sp
+ mov %i1,%o4
+ mov %i2,%o5
+ st %i3,[%sp+92]
+ mov 0,%o0
+ mov SYS_lseek,%o1
+ mov %i0,%o2
+ call _machdep_sys___syscall,0
+ mov 0,%o3
+ mov %o0,%i0
+ mov %o1,%i1
+ ret
+ restore
+
+/* ==========================================================================
+ * machdep_sys_ftruncate()
+ */
+ .global _C_LABEL(machdep_sys_ftruncate)
+
+_C_LABEL(machdep_sys_ftruncate):
+ save %sp,-104,%sp
+ mov %i1,%o4
+ mov %i2,%o5
+ mov 0,%o0
+ mov SYS_ftruncate,%o1
+ mov %i0,%o2
+ call _machdep_sys___syscall,0
+ mov 0,%o3
+ mov %o0,%o1
+ sra %o0,31,%o0
+ ret
+ restore %g0,%o1,%o0
diff --git a/mit-pthreads/machdep/syscall-sparc-sunos-4.1.3.S b/mit-pthreads/machdep/syscall-sparc-sunos-4.1.3.S
new file mode 100644
index 00000000000..ec293b0ca3f
--- /dev/null
+++ b/mit-pthreads/machdep/syscall-sparc-sunos-4.1.3.S
@@ -0,0 +1,113 @@
+/* ==== syscall.S ============================================================
+ * Copyright (c) 1994 Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ */
+
+#ifndef lint
+ .text
+ .asciz "$Id$";
+#endif
+
+#include <sys/syscall.h>
+
+#define SYSCALL(x) \
+ .globl _machdep_sys_##x; \
+ \
+_machdep_sys_##x:; \
+ \
+ mov SYS_##x, %g1; \
+ ta 0; \
+ bcs,a 2b; \
+ sub %r0,%o0,%o0; \
+ retl
+
+
+/*
+ * Initial asm stuff for all functions.
+ */
+ .text
+ .align 4
+
+/* ==========================================================================
+ * error code for all syscalls. The error value is returned as the negative
+ * of the errno value.
+ */
+
+1:
+ sub %r0, %o0, %o0
+2:
+ retl
+ nop
+
+/* ==========================================================================
+ * machdep_sys_pipe()
+ */
+ .globl _machdep_sys_pipe
+
+_machdep_sys_pipe:
+ mov %o0, %o2
+ mov SYS_pipe, %g1
+ ta 0
+ bcs 1b
+ nop
+ st %o0, [ %o2 ]
+ st %o1, [ %o2 + 4 ]
+ retl
+ mov %g0, %o0
+
+/* ==========================================================================
+ * machdep_sys_fork()
+ */
+ .globl _machdep_sys_fork;
+
+_machdep_sys_fork:;
+
+ mov SYS_fork, %g1;
+ ta 0;
+ bcs 1b;
+ nop;
+ tst %o1
+ bne,a __fork_parent
+ mov %g0, %o0
+__fork_parent:;
+ retl
+
+/* POSIX-compliant getpgrp() takes no arguments. The SunOS syscall wants
+ one, and gives the POSIXy result if that argument is zero. */
+ .globl _getpgrp
+_getpgrp:
+ mov SYS_getpgrp, %g1
+ mov 0, %i0
+ ta 0
+ bcs 1b
+ nop
+ retl
+ nop
+
+#if 0
+/* I think this bit of magic will do the right thing for other syscalls.
+ We get here with the new `errno' code in %o0. It should get stored in
+ *__error(), and -1 returned to the caller. */
+ .globl cerror
+cerror:
+ save %sp,-104,%sp
+ /* Now value is in %i0. Store it in *__error(). */
+ call ___error
+ nop
+ st %i0,[%o0]
+
+ /* Now also store a copy in global variable errno, for routines
+ like isatty that want to examine it and which haven't been
+ converted yet. */
+ sethi %hi(_errno), %o0
+ st %i0,[%o0+%lo(_errno)]
+
+#if 0 /* use this if you want -errno returned */
+ sub %r0,%i0,%i0
+#else /* return -1 */
+ mov -1,%i0
+#endif
+ retl
+ restore
+#endif
diff --git a/mit-pthreads/machdep/syscall-sparc-sunos-5.3.S b/mit-pthreads/machdep/syscall-sparc-sunos-5.3.S
new file mode 100644
index 00000000000..822055ad04e
--- /dev/null
+++ b/mit-pthreads/machdep/syscall-sparc-sunos-5.3.S
@@ -0,0 +1,65 @@
+/* ==== syscall.S ============================================================
+ * Copyright (c) 1994 Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ */
+
+#ifndef lint
+ .text
+ .asciz "$Id$";
+#endif
+
+#define _ASM
+#include <sys/syscall.h>
+
+/*
+ * Initial asm stuff for all functions.
+ */
+ .text
+ .align 4
+
+/* ==========================================================================
+ * error code for all syscalls. The error value is returned as the negative
+ * of the errno value.
+ */
+
+1:
+ sub %r0, %o0, %o0
+2:
+ retl
+ nop
+
+/* ==========================================================================
+ * machdep_sys_fork()
+ */
+ .globl machdep_sys_fork;
+
+machdep_sys_fork:;
+
+ mov SYS_fork, %g1;
+ ta 0;
+ bcs 1b;
+ nop;
+ tst %o1
+ bne,a __fork_parent
+ mov %g0, %o0
+__fork_parent:;
+ retl
+ nop; /* Added by monty to keep sparc assembler happy */
+
+/* ==========================================================================
+ * Berkeley socket stuff
+ *
+ * ==========================================================================
+ * machdep_sys_socketcall()
+ */
+ .globl machdep_sys_socketcall;
+
+machdep_sys_socketcall:;
+
+ mov 83, %g1;
+ ta 0;
+ bcs,a 2b;
+ sub %r0,%o0,%o0;
+ retl
+ nop; /* Added by monty to keep sparc assembler happy */
diff --git a/mit-pthreads/machdep/syscall-sparc-sunos4.S b/mit-pthreads/machdep/syscall-sparc-sunos4.S
new file mode 100644
index 00000000000..ec293b0ca3f
--- /dev/null
+++ b/mit-pthreads/machdep/syscall-sparc-sunos4.S
@@ -0,0 +1,113 @@
+/* ==== syscall.S ============================================================
+ * Copyright (c) 1994 Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ */
+
+#ifndef lint
+ .text
+ .asciz "$Id$";
+#endif
+
+#include <sys/syscall.h>
+
+#define SYSCALL(x) \
+ .globl _machdep_sys_##x; \
+ \
+_machdep_sys_##x:; \
+ \
+ mov SYS_##x, %g1; \
+ ta 0; \
+ bcs,a 2b; \
+ sub %r0,%o0,%o0; \
+ retl
+
+
+/*
+ * Initial asm stuff for all functions.
+ */
+ .text
+ .align 4
+
+/* ==========================================================================
+ * error code for all syscalls. The error value is returned as the negative
+ * of the errno value.
+ */
+
+1:
+ sub %r0, %o0, %o0
+2:
+ retl
+ nop
+
+/* ==========================================================================
+ * machdep_sys_pipe()
+ */
+ .globl _machdep_sys_pipe
+
+_machdep_sys_pipe:
+ mov %o0, %o2
+ mov SYS_pipe, %g1
+ ta 0
+ bcs 1b
+ nop
+ st %o0, [ %o2 ]
+ st %o1, [ %o2 + 4 ]
+ retl
+ mov %g0, %o0
+
+/* ==========================================================================
+ * machdep_sys_fork()
+ */
+ .globl _machdep_sys_fork;
+
+_machdep_sys_fork:;
+
+ mov SYS_fork, %g1;
+ ta 0;
+ bcs 1b;
+ nop;
+ tst %o1
+ bne,a __fork_parent
+ mov %g0, %o0
+__fork_parent:;
+ retl
+
+/* POSIX-compliant getpgrp() takes no arguments. The SunOS syscall wants
+ one, and gives the POSIXy result if that argument is zero. */
+ .globl _getpgrp
+_getpgrp:
+ mov SYS_getpgrp, %g1
+ mov 0, %i0
+ ta 0
+ bcs 1b
+ nop
+ retl
+ nop
+
+#if 0
+/* I think this bit of magic will do the right thing for other syscalls.
+ We get here with the new `errno' code in %o0. It should get stored in
+ *__error(), and -1 returned to the caller. */
+ .globl cerror
+cerror:
+ save %sp,-104,%sp
+ /* Now value is in %i0. Store it in *__error(). */
+ call ___error
+ nop
+ st %i0,[%o0]
+
+ /* Now also store a copy in global variable errno, for routines
+ like isatty that want to examine it and which haven't been
+ converted yet. */
+ sethi %hi(_errno), %o0
+ st %i0,[%o0+%lo(_errno)]
+
+#if 0 /* use this if you want -errno returned */
+ sub %r0,%i0,%i0
+#else /* return -1 */
+ mov -1,%i0
+#endif
+ retl
+ restore
+#endif
diff --git a/mit-pthreads/machdep/syscall-template-alpha-netbsd-1.1.S b/mit-pthreads/machdep/syscall-template-alpha-netbsd-1.1.S
new file mode 100644
index 00000000000..a2941ece7c9
--- /dev/null
+++ b/mit-pthreads/machdep/syscall-template-alpha-netbsd-1.1.S
@@ -0,0 +1,46 @@
+#include <machine/asm.h>
+#define COMPAT_43
+#include <sys/syscall.h>
+#define CHMK() call_pal 0x83
+
+#undef SYSCALL
+
+/* Kernel syscall interface:
+ Input:
+ v0 - system call number
+ a* - arguments, as in C
+ Output:
+ a3 - zero iff successful
+ v0 - errno value on failure, else result
+
+ This macro is similar to SYSCALL in asm.h, but not completely.
+ There's room for optimization, if we assume this will continue to
+ be assembled as one file.
+
+ This macro expansions does not include the return instruction.
+ If there's no other work to be done, use something like:
+ SYSCALL(foo) ; ret
+ If there is other work to do (in fork, maybe?), do it after the
+ SYSCALL invocation. */
+
+#define SYSCALL(x) \
+ .align 4 ;\
+ .globl machdep_sys_##x ;\
+ .ent machdep_sys_##x, 0 ;\
+machdep_sys_##x: ;\
+ .frame sp,0,ra ;\
+ ldiq v0, SYS_##x ;\
+ CHMK() ;\
+ beq a3, Lsys_noerr_##x ;\
+ br gp, Lsys_err_##x ;\
+Lsys_err_##x: ;\
+ /* Load gp so we can find cerror to jump to. */;\
+ ldgp gp, 0(gp) ;\
+ jmp zero, machdep_cerror ;\
+Lsys_noerr_##x:
+
+#define SIMPLE_SYSCALL(x) SYSCALL(x) ; ret ; .end machdep_sys_##x
+
+#define XSYSCALL(x) SIMPLE_SYSCALL(x)
+
+XSYSCALL(SYSCALL_NAME)
diff --git a/mit-pthreads/machdep/syscall-template-alpha-netbsd-1.3.S b/mit-pthreads/machdep/syscall-template-alpha-netbsd-1.3.S
new file mode 100644
index 00000000000..12595feabc1
--- /dev/null
+++ b/mit-pthreads/machdep/syscall-template-alpha-netbsd-1.3.S
@@ -0,0 +1,53 @@
+#include <machine/asm.h>
+#define COMPAT_43
+#include <sys/syscall.h>
+#define CHMK() call_pal 0x83
+
+#ifdef SYS___sigsuspend14
+#define SYS_sigsuspend SYS___sigsuspend14
+#endif
+#ifdef SYS___sigprocmask14
+#define SYS_sigprocmask SYS___sigprocmask14
+#endif
+
+#undef SYSCALL
+
+/* Kernel syscall interface:
+ Input:
+ v0 - system call number
+ a* - arguments, as in C
+ Output:
+ a3 - zero iff successful
+ v0 - errno value on failure, else result
+
+ This macro is similar to SYSCALL in asm.h, but not completely.
+ There's room for optimization, if we assume this will continue to
+ be assembled as one file.
+
+ This macro expansions does not include the return instruction.
+ If there's no other work to be done, use something like:
+ SYSCALL(foo) ; ret
+ If there is other work to do (in fork, maybe?), do it after the
+ SYSCALL invocation. */
+
+#define SYSCALL(x) \
+ .align 4 ;\
+ .globl machdep_sys_##x ;\
+ .ent machdep_sys_##x, 0 ;\
+machdep_sys_##x: ;\
+ .frame sp,0,ra ;\
+ ldiq v0, SYS_##x ;\
+ CHMK() ;\
+ beq a3, Lsys_noerr_##x ;\
+ br gp, Lsys_err_##x ;\
+Lsys_err_##x: ;\
+ /* Load gp so we can find cerror to jump to. */;\
+ ldgp gp, 0(gp) ;\
+ jmp zero, machdep_cerror ;\
+Lsys_noerr_##x:
+
+#define SIMPLE_SYSCALL(x) SYSCALL(x) ; ret ; .end machdep_sys_##x
+
+#define XSYSCALL(x) SIMPLE_SYSCALL(x)
+
+XSYSCALL(SYSCALL_NAME)
diff --git a/mit-pthreads/machdep/syscall-template-alpha-osf1.S b/mit-pthreads/machdep/syscall-template-alpha-osf1.S
new file mode 100644
index 00000000000..bc4653b5f9e
--- /dev/null
+++ b/mit-pthreads/machdep/syscall-template-alpha-osf1.S
@@ -0,0 +1,46 @@
+#include <asm.h>
+#include <regdef.h>
+#define COMPAT_43
+#include <syscall.h>
+
+#undef SYSCALL
+
+/* Kernel syscall interface:
+ Input:
+ v0 - system call number
+ a* - arguments, as in C
+ Output:
+ a3 - zero iff successful
+ v0 - errno value on failure, else result
+
+ This macro is similar to SYSCALL in asm.h, but not completely.
+ There's room for optimization, if we assume this will continue to
+ be assembled as one file.
+
+ This macro expansions does not include the return instruction.
+ If there's no other work to be done, use something like:
+ SYSCALL(foo) ; ret
+ If there is other work to do (in fork, maybe?), do it after the
+ SYSCALL invocation. */
+
+#define SYSCALL(x) \
+ .align 4 ;\
+ .globl machdep_sys_##x ;\
+ .ent machdep_sys_##x, 0 ;\
+machdep_sys_##x: ;\
+ .frame sp,0,ra ;\
+ ldiq v0, SYS_##x ;\
+ CHMK() ;\
+ beq a3, 2f ;\
+ br gp, 1f ;\
+1: ;\
+ /* Load gp so we can find cerror to jump to. */;\
+ ldgp gp, 0(gp) ;\
+ jmp zero, machdep_cerror ;\
+2:
+
+#define SIMPLE_SYSCALL(x) SYSCALL(x) ; ret ; .end machdep_sys_##x
+
+#define XSYSCALL(x) SIMPLE_SYSCALL(x)
+
+XSYSCALL(SYSCALL_NAME)
diff --git a/mit-pthreads/machdep/syscall-template-arm32-netbsd-1.3.S b/mit-pthreads/machdep/syscall-template-arm32-netbsd-1.3.S
new file mode 100644
index 00000000000..923d2c03a75
--- /dev/null
+++ b/mit-pthreads/machdep/syscall-template-arm32-netbsd-1.3.S
@@ -0,0 +1,55 @@
+#include <machine/asm.h>
+#include <sys/syscall.h>
+
+#ifdef SYS___sigsuspend14
+#define SYS_sigsuspend SYS___sigsuspend14
+#endif
+#ifdef SYS___sigprocmask14
+#define SYS_sigprocmask SYS___sigprocmask14
+#endif
+
+#ifdef __STDC__
+
+#define SYSCALL(x) \
+ .globl _C_LABEL(machdep_sys_##x); \
+ \
+_C_LABEL(machdep_sys_##x):; \
+ \
+ swi SYS_##x; \
+ bcs 1b; \
+ mov r15, r14;
+
+#else
+
+#define SYSCALL(x) \
+ .globl _C_LABEL(_machdep_sys_/**/x); \
+ \
+_C_LABEL(machdep_sys_/**/x):; \
+ \
+ swi SYS_/**/x; \
+ bcs 1b; \
+ mov r15, r14;
+
+#endif
+
+
+/*
+ * Initial asm stuff for all functions.
+ */
+ .text
+ .align 0
+
+
+/* ==========================================================================
+ * error code for all syscalls. The error value is returned as the negative
+ * of the errno value.
+ */
+
+1:
+ rsb r0, r0, #0x00000000
+ mvn r1, #0x00000000
+ mov r15, r14
+
+#define XSYSCALL(NAME) SYSCALL(NAME)
+
+XSYSCALL(SYSCALL_NAME)
diff --git a/mit-pthreads/machdep/syscall-template-hppa-hpux-10.20.S b/mit-pthreads/machdep/syscall-template-hppa-hpux-10.20.S
new file mode 100644
index 00000000000..0123b1deee7
--- /dev/null
+++ b/mit-pthreads/machdep/syscall-template-hppa-hpux-10.20.S
@@ -0,0 +1,27 @@
+/* ==== syscall.S ============================================================
+ * Written 1996 by Stefan Grefen, grefen@convex.com
+ */
+
+#include <sys/syscall.h>
+
+#define _CAT(a,b)a##b
+#define CAT(a,b)_CAT(a,b)
+
+#define MKNAME(a)CAT(a,SYSCALL_NAME)
+
+ .CODE
+machdep_error
+ sub %r0,%r28,%r28
+ bv,n %r0(%r2)
+
+ .label MKNAME(machdep_sys_)
+ .PROC
+ .CALLINFO NO_CALLS,FRAME=0
+ ldil -0x80000,%r1
+ ble 4(%sr7,%r1)
+ ldi MKNAME(SYS_),%r22
+ or,= %r0,%r22,%r0
+ b,n machdep_error
+ bv,n %r0(%r2)
+ .PROCEND
+ .EXPORT MKNAME(machdep_sys_)
diff --git a/mit-pthreads/machdep/syscall-template-hppa-hpux-9.03.S b/mit-pthreads/machdep/syscall-template-hppa-hpux-9.03.S
new file mode 100644
index 00000000000..0123b1deee7
--- /dev/null
+++ b/mit-pthreads/machdep/syscall-template-hppa-hpux-9.03.S
@@ -0,0 +1,27 @@
+/* ==== syscall.S ============================================================
+ * Written 1996 by Stefan Grefen, grefen@convex.com
+ */
+
+#include <sys/syscall.h>
+
+#define _CAT(a,b)a##b
+#define CAT(a,b)_CAT(a,b)
+
+#define MKNAME(a)CAT(a,SYSCALL_NAME)
+
+ .CODE
+machdep_error
+ sub %r0,%r28,%r28
+ bv,n %r0(%r2)
+
+ .label MKNAME(machdep_sys_)
+ .PROC
+ .CALLINFO NO_CALLS,FRAME=0
+ ldil -0x80000,%r1
+ ble 4(%sr7,%r1)
+ ldi MKNAME(SYS_),%r22
+ or,= %r0,%r22,%r0
+ b,n machdep_error
+ bv,n %r0(%r2)
+ .PROCEND
+ .EXPORT MKNAME(machdep_sys_)
diff --git a/mit-pthreads/machdep/syscall-template-i386-bsdi-2.0.S b/mit-pthreads/machdep/syscall-template-i386-bsdi-2.0.S
new file mode 100644
index 00000000000..3299f49195f
--- /dev/null
+++ b/mit-pthreads/machdep/syscall-template-i386-bsdi-2.0.S
@@ -0,0 +1,48 @@
+#include <sys/syscall.h>
+
+#ifdef __STDC__
+
+#define SYSCALL(x) \
+ .globl _machdep_sys_##x##; \
+ \
+_machdep_sys_##x##:; \
+ \
+ movl $(SYS_##x##), %eax; \
+ .byte 0x9a; .long 0; .word 7; \
+ jb 1b; \
+ ret;
+
+#else
+
+#define SYSCALL(x) \
+ .globl _machdep_sys_/**/x/**/; \
+ \
+_machdep_sys_/**/x/**/:; \
+ \
+ movl $(SYS_/**/x/**/), %eax; \
+ .byte 0x9a; .long 0; .word 7; \
+ jb 1b; \
+ ret;
+
+#endif
+
+
+/*
+ * Initial asm stuff for all functions.
+ */
+ .text
+ .align 2
+
+
+/* ==========================================================================
+ * error code for all syscalls. The error value is returned as the negative
+ * of the errno value.
+ */
+
+1:
+ neg %eax
+ ret
+
+#define XSYSCALL(NAME) SYSCALL(NAME)
+
+XSYSCALL(SYSCALL_NAME)
diff --git a/mit-pthreads/machdep/syscall-template-i386-freebsd-2.0.S b/mit-pthreads/machdep/syscall-template-i386-freebsd-2.0.S
new file mode 100644
index 00000000000..1906a949c8b
--- /dev/null
+++ b/mit-pthreads/machdep/syscall-template-i386-freebsd-2.0.S
@@ -0,0 +1,59 @@
+#include <sys/syscall.h>
+
+#ifdef __STDC__
+
+#define SYS(X) SYS_##X
+#ifdef __ELF__
+#define NAME(X) machdep_sys_##X
+#else
+#define NAME(X) _machdep_sys_##X
+#endif
+
+#else
+
+#define SYS(X) SYS_/**/X
+#ifdef __ELF__
+#define NAME(X) machdep_sys_/**/X
+#else
+#define NAME(X) _machdep_sys_/**/X
+#endif
+
+#endif
+
+#ifdef __ELF__
+#define END(X) 5: ; .type NAME(X),@function ; .size NAME(X),5b - NAME(X)
+#define KERNCALL int $0x80
+#else
+#define END(X)
+#define KERNCALL .byte 0x9a; .long 0; .word 7;
+#endif
+
+#define SYSCALL(x) \
+ .globl NAME(x); \
+ \
+NAME(x):; \
+ movl $(SYS(x)), %eax; \
+ KERNCALL; \
+ jb 1b; \
+ ret; \
+ END(x)
+
+/*
+ * Initial asm stuff for all functions.
+ */
+ .text
+ .align 2
+
+
+/* ==========================================================================
+ * error code for all syscalls. The error value is returned as the negative
+ * of the errno value.
+ */
+
+1:
+ neg %eax
+ ret
+
+#define XSYSCALL(NAME) SYSCALL(NAME)
+
+XSYSCALL(SYSCALL_NAME)
diff --git a/mit-pthreads/machdep/syscall-template-i386-netbsd-1.1.S b/mit-pthreads/machdep/syscall-template-i386-netbsd-1.1.S
new file mode 100644
index 00000000000..c5e76bb4538
--- /dev/null
+++ b/mit-pthreads/machdep/syscall-template-i386-netbsd-1.1.S
@@ -0,0 +1,49 @@
+#include <machine/asm.h>
+#include <sys/syscall.h>
+
+#ifdef __STDC__
+
+#define SYSCALL(x) \
+ .globl _machdep_sys_##x; \
+ \
+_machdep_sys_##x:; \
+ \
+ movl $(SYS_##x), %eax; \
+ int $0x80; \
+ jb 1b; \
+ ret;
+
+#else
+
+#define SYSCALL(x) \
+ .globl _machdep_sys_/**/x; \
+ \
+_machdep_sys_/**/x:; \
+ \
+ movl $(SYS_/**/x), %eax; \
+ int $0x80; \
+ jb 1b; \
+ ret;
+
+#endif
+
+
+/*
+ * Initial asm stuff for all functions.
+ */
+ .text
+ .align 2
+
+
+/* ==========================================================================
+ * error code for all syscalls. The error value is returned as the negative
+ * of the errno value.
+ */
+
+1:
+ neg %eax
+ ret
+
+#define XSYSCALL(NAME) SYSCALL(NAME)
+
+XSYSCALL(SYSCALL_NAME)
diff --git a/mit-pthreads/machdep/syscall-template-i386-netbsd-1.3.S b/mit-pthreads/machdep/syscall-template-i386-netbsd-1.3.S
new file mode 100644
index 00000000000..d6dffc35132
--- /dev/null
+++ b/mit-pthreads/machdep/syscall-template-i386-netbsd-1.3.S
@@ -0,0 +1,56 @@
+#include <machine/asm.h>
+#include <sys/syscall.h>
+
+#ifdef SYS___sigsuspend14
+#define SYS_sigsuspend SYS___sigsuspend14
+#endif
+#ifdef SYS___sigprocmask14
+#define SYS_sigprocmask SYS___sigprocmask14
+#endif
+
+#ifdef __STDC__
+
+#define SYSCALL(x) \
+ .globl _C_LABEL(machdep_sys_##x); \
+ \
+_C_LABEL(machdep_sys_##x):; \
+ \
+ movl $(SYS_##x), %eax; \
+ int $0x80; \
+ jb 1b; \
+ ret;
+
+#else
+
+#define _SYSCALL(x) \
+ .globl _C_LABEL(machdep_sys_/**/x); \
+ \
+_C_LABEL(machdep_sys_/**/x):; \
+ \
+ movl $(SYS_/**/x), %eax; \
+ int $0x80; \
+ jb 1b; \
+ ret;
+
+#endif
+
+
+/*
+ * Initial asm stuff for all functions.
+ */
+ .text
+ .align 2
+
+
+/* ==========================================================================
+ * error code for all syscalls. The error value is returned as the negative
+ * of the errno value.
+ */
+
+1:
+ neg %eax
+ ret
+
+#define XSYSCALL(NAME) SYSCALL(NAME)
+
+XSYSCALL(SYSCALL_NAME)
diff --git a/mit-pthreads/machdep/syscall-template-i386-netbsd1.0.S b/mit-pthreads/machdep/syscall-template-i386-netbsd1.0.S
new file mode 100644
index 00000000000..83a2405ed51
--- /dev/null
+++ b/mit-pthreads/machdep/syscall-template-i386-netbsd1.0.S
@@ -0,0 +1,49 @@
+#include <machine/asm.h>
+#include <sys/syscall.h>
+
+#ifdef __STDC__
+
+#define SYSCALL(x) \
+ .globl _machdep_sys_##x; \
+ \
+_machdep_sys_##x:; \
+ \
+ movl $(SYS_##x), %eax; \
+ .byte 0x9a; .long 0; .word 7; \
+ jb 1b; \
+ ret;
+
+#else
+
+#define SYSCALL(x) \
+ .globl _machdep_sys_/**/x; \
+ \
+_machdep_sys_/**/x:; \
+ \
+ movl $(SYS_/**/x), %eax; \
+ .byte 0x9a; .long 0; .word 7; \
+ jb 1b; \
+ ret;
+
+#endif
+
+
+/*
+ * Initial asm stuff for all functions.
+ */
+ .text
+ .align 2
+
+
+/* ==========================================================================
+ * error code for all syscalls. The error value is returned as the negative
+ * of the errno value.
+ */
+
+1:
+ neg %eax
+ ret
+
+#define XSYSCALL(NAME) SYSCALL(NAME)
+
+XSYSCALL(SYSCALL_NAME)
diff --git a/mit-pthreads/machdep/syscall-template-i386-openbsd-2.0.S b/mit-pthreads/machdep/syscall-template-i386-openbsd-2.0.S
new file mode 100644
index 00000000000..34fb5caaa43
--- /dev/null
+++ b/mit-pthreads/machdep/syscall-template-i386-openbsd-2.0.S
@@ -0,0 +1,48 @@
+#include <sys/syscall.h>
+
+#ifdef __STDC__
+
+#define SYSCALL(x) \
+ .globl _machdep_sys_##x##; \
+ \
+_machdep_sys_##x:##; \
+ \
+ movl $(SYS_##x##), %eax; \
+ .byte 0x9a; .long 0; .word 7; \
+ jb 1b; \
+ ret;
+
+#else
+
+#define SYSCALL(x) \
+ .globl _machdep_sys_/**/x; \
+ \
+_machdep_sys_/**/x:; \
+ \
+ movl $(SYS_/**/x), %eax; \
+ .byte 0x9a; .long 0; .word 7; \
+ jb 1b; \
+ ret;
+
+#endif
+
+
+/*
+ * Initial asm stuff for all functions.
+ */
+ .text
+ .align 2
+
+
+/* ==========================================================================
+ * error code for all syscalls. The error value is returned as the negative
+ * of the errno value.
+ */
+
+1:
+ neg %eax
+ ret
+
+#define XSYSCALL(NAME) SYSCALL(NAME)
+
+XSYSCALL(SYSCALL_NAME)
diff --git a/mit-pthreads/machdep/syscall-template-i386-sco-3.2v5.S b/mit-pthreads/machdep/syscall-template-i386-sco-3.2v5.S
new file mode 100644
index 00000000000..753475b5c3d
--- /dev/null
+++ b/mit-pthreads/machdep/syscall-template-i386-sco-3.2v5.S
@@ -0,0 +1,67 @@
+#include <sys/errno.h>
+#include <sys/syscall.h>
+
+#ifdef _SCO_ELF
+
+#define NAME(X) machdep_sys_##X
+#define END(X) 1: ; .type NAME(X),@function ; .size NAME(X),1b - NAME(X)
+#define GETBX(X) \
+ push %ebx; \
+ call 1f; \
+1: \
+ popl %ebx;
+#else
+
+#define NAME(X) _machdep_sys_##X
+#define END(X)
+
+#endif
+
+#ifdef __STDC__
+
+#define SYSCALL(x) \
+ .globl NAME(x); \
+ \
+NAME(x):; \
+ movl $(SYS_##x##), %eax; \
+ .byte 0x9a; .long 0; .word 7; \
+ jae 1f; \
+ cmp $(ERESTART), %eax; \
+ je NAME(x); \
+ neg %eax; \
+1: \
+ ret; \
+ END(x)
+
+#else
+
+#define SYSCALL(x) \
+ .globl _machdep_sys_/**/x; \
+ \
+machdep_sys_/**/x:; \
+ \
+ movl $(SYS_/**/x), %eax; \
+ .byte 0x9a; .long 0; .word 7; \
+ jae 1f; \
+ neg %eax;
+1: \
+ ret;
+
+#endif
+
+
+/*
+ * Initial asm stuff for all functions.
+ */
+ .text
+ .align 2
+
+
+/* ==========================================================================
+ * error code for all syscalls. The error value is returned as the negative
+ * of the errno value.
+ */
+
+#define XSYSCALL(NAME) SYSCALL(NAME)
+
+XSYSCALL(SYSCALL_NAME)
diff --git a/mit-pthreads/machdep/syscall-template-ip22-irix-5.2.S b/mit-pthreads/machdep/syscall-template-ip22-irix-5.2.S
new file mode 100644
index 00000000000..722b001671b
--- /dev/null
+++ b/mit-pthreads/machdep/syscall-template-ip22-irix-5.2.S
@@ -0,0 +1,51 @@
+#include <sys.s>
+#include <sys/regdef.h>
+/* #include <sys/asm.h> */
+
+/*
+ Kernel syscall interface:
+ Input:
+ v0 syscall number
+ Output:
+
+ This macro is similar to SYSCALL in sys/syscall.h, but not completely.
+ There's room for optimization, if we assume this will continue to
+ be assembled as one file.
+
+ Compile with -DPIC for pic code.
+*/
+
+#ifdef PIC
+#define PICOPT .option pic2
+#else
+#define PICOPT
+#endif
+
+
+#define YSYSCALL(x) \
+ PICOPT; \
+ .globl machdep_sys_##x; \
+ .ent machdep_sys_##x, 0; \
+machdep_sys_##x:; \
+ .frame sp,0,ra; \
+ .set noreorder; \
+ li v0, SYS_##x; \
+ syscall; \
+ bne a3, zero, 1b; \
+ nop; \
+ j ra; \
+ nop; \
+ .end machdep_sys_##x
+
+/* ==========================================================================
+ * error code for all syscalls. The error value is returned as the negative
+ * of the errno value.
+ */
+
+1:
+ subu v0,zero,v0;
+ j ra;
+
+#define XSYSCALL(x) YSYSCALL(x)
+
+XSYSCALL(SYSCALL_NAME)
diff --git a/mit-pthreads/machdep/syscall-template-m68000-netbsd.S b/mit-pthreads/machdep/syscall-template-m68000-netbsd.S
new file mode 100644
index 00000000000..ce16bb5523c
--- /dev/null
+++ b/mit-pthreads/machdep/syscall-template-m68000-netbsd.S
@@ -0,0 +1,43 @@
+#include <machine/asm.h>
+#include <sys/syscall.h>
+
+#ifdef SYS___sigsuspend14
+#define SYS_sigsuspend SYS___sigsuspend14
+#endif
+#ifdef SYS___sigprocmask14
+#define SYS_sigprocmask SYS___sigprocmask14
+#endif
+
+
+#ifdef __STDC__
+#define IMM #
+#define SYSCALL(x) .even; \
+ ENTRY(machdep_sys_ ## x); \
+ movl IMM SYS_ ## x,d0; \
+ trap IMM 0; \
+ jcs err; \
+ rts
+#else /* !__STDC__ */
+#define SYSCALL(x) .even; ENTRY(machdep_sys_/**/x); \
+ movl #SYS_/**/x,d0; trap #0; jcs err; rts
+#endif /* !__STDC__ */
+
+/*
+ * Initial asm stuff for all functions.
+ */
+ .text
+ .even
+
+
+/* ==========================================================================
+ * error code for all syscalls. The error value is returned as the negative
+ * of the errno value.
+ */
+
+err:
+ negl d0
+ rts
+
+#define XSYSCALL(NAME) SYSCALL(NAME)
+
+XSYSCALL(SYSCALL_NAME)
diff --git a/mit-pthreads/machdep/syscall-template-r2000-ultrix-4.2.S b/mit-pthreads/machdep/syscall-template-r2000-ultrix-4.2.S
new file mode 100644
index 00000000000..575fe3c3d74
--- /dev/null
+++ b/mit-pthreads/machdep/syscall-template-r2000-ultrix-4.2.S
@@ -0,0 +1,77 @@
+/* ==== syscall.S ============================================================
+ * Copyright (c) 1993 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Description : Machine dependent syscalls for decstation with r2000/r3000
+ *
+ * 1.00 93/08/14 proven
+ * -Started coding this file.
+ */
+
+ .text
+ .ascii "$Id$";
+
+#include <syscall.h>
+#include <machine/regdef.h>
+
+#define SYSCALL(x) \
+ \
+ .globl machdep_sys_##x; \
+ .ent machdep_sys_##x; \
+ \
+machdep_sys_##x:; \
+ \
+ .frame sp,0,ra; /* No frame, return address in ra */ \
+ \
+ li v0,SYS_##x; /* Load syscall # into v0 */ \
+ syscall; \
+ bne a3,zero,machdep_error; /* Error if a3 != 0 */ \
+ j ra; \
+ \
+ .end machdep_sys_##x
+
+/*
+ * Initial asm stuff for all functions.
+ */
+ .text
+ .align 2
+
+/* ==========================================================================
+ * error code for all syscalls. The error value is returned as the negative
+ * of the errno value. Eventually I want to load the errno value directly
+ * into pthread_run->error but until then ...
+ */
+machdep_error:
+ negu v0, v0 /* Return negative of errno value. */
+ j ra
+
+#define XSYSCALL(NAME) SYSCALL(NAME)
+
+XSYSCALL(SYSCALL_NAME)
diff --git a/mit-pthreads/machdep/syscall-template-sparc-netbsd-1.1.S b/mit-pthreads/machdep/syscall-template-sparc-netbsd-1.1.S
new file mode 100644
index 00000000000..2d07892a315
--- /dev/null
+++ b/mit-pthreads/machdep/syscall-template-sparc-netbsd-1.1.S
@@ -0,0 +1,40 @@
+/* ==== syscall.S ============================================================
+ * Copyright (c) 1994 Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ */
+
+#include <sys/syscall.h>
+
+#define SYSCALL(x) \
+ .globl _machdep_sys_##x; \
+ \
+_machdep_sys_##x:; \
+ \
+ mov SYS_##x, %g1; \
+ ta 0; \
+ bcs,a 2b; \
+ sub %r0,%o0,%o0; \
+ retl; \
+ nop
+
+/*
+ * Initial asm stuff for all functions.
+ */
+ .text
+ .align 4
+
+/* ==========================================================================
+ * error code for all syscalls. The error value is returned as the negative
+ * of the errno value.
+ */
+
+1:
+ sub %r0, %o0, %o0
+2:
+ retl
+ nop
+
+#define XSYSCALL(NAME) SYSCALL(NAME)
+
+XSYSCALL(SYSCALL_NAME)
diff --git a/mit-pthreads/machdep/syscall-template-sparc-netbsd-1.3.S b/mit-pthreads/machdep/syscall-template-sparc-netbsd-1.3.S
new file mode 100644
index 00000000000..2caad5c3437
--- /dev/null
+++ b/mit-pthreads/machdep/syscall-template-sparc-netbsd-1.3.S
@@ -0,0 +1,48 @@
+/* ==== syscall.S ============================================================
+ * Copyright (c) 1994 Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ */
+
+#include <machine/asm.h>
+#include <sys/syscall.h>
+
+#ifdef SYS___sigsuspend14
+#define SYS_sigsuspend SYS___sigsuspend14
+#endif
+#ifdef SYS___sigprocmask14
+#define SYS_sigprocmask SYS___sigprocmask14
+#endif
+
+#define SYSCALL(x) \
+ .globl _C_LABEL(machdep_sys_##x); \
+ \
+_C_LABEL(machdep_sys_##x):; \
+ \
+ mov SYS_##x, %g1; \
+ ta 0; \
+ bcs,a 2b; \
+ sub %r0,%o0,%o0; \
+ retl; \
+ nop
+
+/*
+ * Initial asm stuff for all functions.
+ */
+ .text
+ .align 4
+
+/* ==========================================================================
+ * error code for all syscalls. The error value is returned as the negative
+ * of the errno value.
+ */
+
+1:
+ sub %r0, %o0, %o0
+2:
+ retl
+ nop
+
+#define XSYSCALL(NAME) SYSCALL(NAME)
+
+XSYSCALL(SYSCALL_NAME)
diff --git a/mit-pthreads/machdep/syscall-template-sparc-sunos-5.3.S b/mit-pthreads/machdep/syscall-template-sparc-sunos-5.3.S
new file mode 100644
index 00000000000..65a796a057d
--- /dev/null
+++ b/mit-pthreads/machdep/syscall-template-sparc-sunos-5.3.S
@@ -0,0 +1,45 @@
+/* ==== syscall.S ============================================================
+ * Copyright (c) 1994 Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ */
+
+#ifndef lint
+ .text
+ .asciz "$Id$";
+#endif
+
+#define _ASM
+#include <sys/syscall.h>
+
+/*
+ * Initial asm stuff for all functions.
+ */
+ .text
+ .align 4
+
+/* ==========================================================================
+ * error code for all syscalls. The error value is returned as the negative
+ * of the errno value.
+ */
+
+1:
+ sub %r0, %o0, %o0
+2:
+ retl
+ nop
+
+#define concat2(a,b) a ## b
+#define concat(a,b) concat2(a,b)
+#define SYSval concat(SYS_,SYSCALL_NAME)
+#define procname concat(machdep_sys_,SYSCALL_NAME)
+
+ .globl procname
+
+procname:
+ mov SYSval, %g1
+ ta 0
+ bcs,a 2b
+ sub %r0,%o0,%o0
+ retl
+ nop
diff --git a/mit-pthreads/machdep/syscall-template-sparc-sunos4.S b/mit-pthreads/machdep/syscall-template-sparc-sunos4.S
new file mode 100644
index 00000000000..2d07892a315
--- /dev/null
+++ b/mit-pthreads/machdep/syscall-template-sparc-sunos4.S
@@ -0,0 +1,40 @@
+/* ==== syscall.S ============================================================
+ * Copyright (c) 1994 Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ */
+
+#include <sys/syscall.h>
+
+#define SYSCALL(x) \
+ .globl _machdep_sys_##x; \
+ \
+_machdep_sys_##x:; \
+ \
+ mov SYS_##x, %g1; \
+ ta 0; \
+ bcs,a 2b; \
+ sub %r0,%o0,%o0; \
+ retl; \
+ nop
+
+/*
+ * Initial asm stuff for all functions.
+ */
+ .text
+ .align 4
+
+/* ==========================================================================
+ * error code for all syscalls. The error value is returned as the negative
+ * of the errno value.
+ */
+
+1:
+ sub %r0, %o0, %o0
+2:
+ retl
+ nop
+
+#define XSYSCALL(NAME) SYSCALL(NAME)
+
+XSYSCALL(SYSCALL_NAME)
diff --git a/mit-pthreads/machdep/ultrix-4.2/__math.h b/mit-pthreads/machdep/ultrix-4.2/__math.h
new file mode 100755
index 00000000000..6249d720039
--- /dev/null
+++ b/mit-pthreads/machdep/ultrix-4.2/__math.h
@@ -0,0 +1,2 @@
+#define HUGE_VAL 1.8e+308
+
diff --git a/mit-pthreads/machdep/ultrix-4.2/__signal.h b/mit-pthreads/machdep/ultrix-4.2/__signal.h
new file mode 100755
index 00000000000..68364772a6a
--- /dev/null
+++ b/mit-pthreads/machdep/ultrix-4.2/__signal.h
@@ -0,0 +1,66 @@
+#include <ansi_compat.h>
+
+#define NSIG 32
+
+#define SIGHUP 1 /* hangup */
+#define SIGINT 2 /* interrupt */
+#define SIGQUIT 3 /* quit */
+#define SIGILL 4 /* illegal instruction (not reset when caught) */
+#define SIGTRAP 5 /* trace trap (not reset when caught) */
+#define SIGIOT 6 /* IOT instruction */
+#define SIGEMT 7 /* EMT instruction */
+#define SIGFPE 8 /* floating point exception */
+#define SIGKILL 9 /* kill (cannot be caught or ignored) */
+#define SIGBUS 10 /* bus error */
+#define SIGSEGV 11 /* segmentation violation */
+#define SIGSYS 12 /* bad argument to system call */
+#define SIGPIPE 13 /* write on a pipe with no one to read it */
+#define SIGALRM 14 /* alarm clock */
+#define SIGTERM 15 /* software termination signal from kill */
+#define SIGURG 16 /* urgent condition on IO channel */
+#define SIGSTOP 17 /* sendable stop signal not from tty */
+#define SIGTSTP 18 /* stop signal from tty */
+#define SIGCONT 19 /* continue a stopped process */
+#define SIGCHLD 20 /* to parent on child stop or exit */
+#define SIGTTIN 21 /* to readers pgrp upon background tty read */
+#define SIGTTOU 22 /* like TTIN for output if (tp->t_local&LTOSTOP) */
+#define SIGIO 23 /* input/output possible signal */
+#define SIGXCPU 24 /* exceeded CPU time limit */
+#define SIGXFSZ 25 /* exceeded file size limit */
+#define SIGVTALRM 26 /* virtual time alarm */
+#define SIGPROF 27 /* profiling time alarm */
+#define SIGWINCH 28 /* window size changes */
+#define SIGLOST 29 /* Sys-V rec lock: notify user upon server crash */
+#define SIGUSR1 30 /* User signal 1 (from SysV) */
+#define SIGUSR2 31 /* User signal 2 (from SysV) */
+
+/* Add System V signal definitions (DLB001) */
+#define SIGCLD SIGCHLD /* System V name for SIGCHLD */
+#define SIGABRT SIGIOT
+
+typedef long sig_atomic_t;
+typedef unsigned int sigset_t;
+
+struct sigaction {
+ void (*sa_handler)(); /* signal handler */
+ sigset_t sa_mask; /* signal mask to apply */
+ int sa_flags; /* see signal options below */
+};
+
+/* Defines for sigprocmask() call. POSIX.
+ */
+#define SIG_BLOCK 1 /* Add these signals to block mask */
+#define SIG_UNBLOCK 2 /* Remove these signals from block mask */
+#define SIG_SETMASK 3 /* Set block mask to this mask */
+
+#define SIG_ERR ((void (*)())(-1))
+#define SIG_DFL ((void (*)())( 0))
+#define SIG_IGN ((void (*)())( 1))
+
+
+#define __SIGFILLSET 0xffffffff
+#define __SIGEMPTYSET 0
+#define __SIGADDSET(s,n) ((*s) |= (1 << ((n) - 1)))
+#define __SIGDELSET(s,n) ((*s) &= ~(1 << ((n) - 1)))
+#define __SIGISMEMBER(s,n) ((*s) & (1 << ((n) - 1)))
+
diff --git a/mit-pthreads/machdep/ultrix-4.2/__stdio.h b/mit-pthreads/machdep/ultrix-4.2/__stdio.h
new file mode 100755
index 00000000000..3f6aee47de3
--- /dev/null
+++ b/mit-pthreads/machdep/ultrix-4.2/__stdio.h
@@ -0,0 +1,7 @@
+
+#if ! defined(_SIZE_T_)
+#define _SIZE_T_
+typedef pthread_size_t size_t;
+#endif
+
+typedef pthread_fpos_t fpos_t;
diff --git a/mit-pthreads/machdep/ultrix-4.2/__stdlib.h b/mit-pthreads/machdep/ultrix-4.2/__stdlib.h
new file mode 100755
index 00000000000..e2e52cc41c9
--- /dev/null
+++ b/mit-pthreads/machdep/ultrix-4.2/__stdlib.h
@@ -0,0 +1,21 @@
+
+#ifndef _SYS___STDLIB_H_
+#define _SYS___STDLIB_H_
+
+#include <ansi_compat.h>
+
+#ifndef _SIZE_T_
+#define _SIZE_T_
+typedef unsigned int size_t;
+#endif
+
+#ifndef _WCHAR_T_
+#define _WCHAR_T_
+typedef unsigned int wchar_t;
+#endif
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#endif
diff --git a/mit-pthreads/machdep/ultrix-4.2/__string.h b/mit-pthreads/machdep/ultrix-4.2/__string.h
new file mode 100755
index 00000000000..03039b5cf73
--- /dev/null
+++ b/mit-pthreads/machdep/ultrix-4.2/__string.h
@@ -0,0 +1,17 @@
+
+#if ! defined(_SIZE_T_)
+#define _SIZE_T_
+typedef pthread_size_t size_t;
+#endif
+
+/* Non-standard Ultrix string routines. */
+#if !defined(_ANSI_SOURCE) && !defined(_POSIX_SOURCE)
+__BEGIN_DECLS
+int bcmp __P_((const void *, const void *, size_t));
+void bcopy __P_((const void *, void *, size_t));
+void bzero __P_((void *, size_t));
+char *index __P_((const char *, int));
+char *rindex __P_((const char *, int));
+__END_DECLS
+#endif
+
diff --git a/mit-pthreads/machdep/ultrix-4.2/__time.h b/mit-pthreads/machdep/ultrix-4.2/__time.h
new file mode 100755
index 00000000000..dddc54430bc
--- /dev/null
+++ b/mit-pthreads/machdep/ultrix-4.2/__time.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * (c) UNIX System Laboratories, Inc.
+ * All or some portions of this file are derived from material licensed
+ * to the University of California by American Telephone and Telegraph
+ * Co. or Unix System Laboratories, Inc. and are reproduced herein with
+ * the permission of UNIX System Laboratories, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)time.h 5.12 (Berkeley) 3/9/91
+ * $Id$
+ */
+
+#ifndef _SYS__TIME_H_
+#define _SYS__TIME_H_
+
+#include <ansi_compat.h>
+
+#ifndef _CLOCK_T_
+#define _CLOCK_T_
+typedef int clock_t;
+#endif
+
+#ifndef _TIME_T_
+#define _TIME_T_
+typedef int time_t;
+#endif
+
+#ifndef _SIZE_T_
+#define _SIZE_T_
+typedef unsigned int size_t;
+#endif
+
+#define CLOCKS_PER_SEC 1000000
+
+#if !defined(_ANSI_SOURCE)
+#define CLK_TCK 60
+#endif /* not ANSI */
+
+#endif /* !_SYS__TIME_H_ */
diff --git a/mit-pthreads/machdep/ultrix-4.2/__unistd.h b/mit-pthreads/machdep/ultrix-4.2/__unistd.h
new file mode 100755
index 00000000000..f570242ef0d
--- /dev/null
+++ b/mit-pthreads/machdep/ultrix-4.2/__unistd.h
@@ -0,0 +1,51 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)stdlib.h 5.13 (Berkeley) 6/4/91
+ * $Id$
+ */
+
+#ifndef _SYS___UNISTD_H_
+#define _SYS___UNISTD_H_
+
+#include <sys/types.h>
+
+#ifndef _SSIZE_T_
+#define _SSIZE_T_
+typedef int ssize_t;
+#endif
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#endif
diff --git a/mit-pthreads/machdep/ultrix-4.2/cdefs.h b/mit-pthreads/machdep/ultrix-4.2/cdefs.h
new file mode 100755
index 00000000000..4e1dc1c280d
--- /dev/null
+++ b/mit-pthreads/machdep/ultrix-4.2/cdefs.h
@@ -0,0 +1,66 @@
+/* ==== cdefs.h ============================================================
+ * Copyright (c) 1994 by Chris Provenzano, proven@athena.mit.edu
+ *
+ * Description : Similar to the BSD cdefs.h file.
+ *
+ * 1.00 94/01/26 proven
+ * -Started coding this file.
+ */
+
+#ifndef _PTHREAD_SYS_CDEFS_H_
+#define _PTHREAD_SYS_CDEFS_H_
+
+/* Stuff for compiling */
+#if defined(__GNUC__)
+#if defined(__cplusplus)
+#define __INLINE static inline
+#define __BEGIN_DECLS extern "C" {
+#define __END_DECLS };
+#else
+#define __INLINE extern inline
+#define __CAN_DO_EXTERN_INLINE
+#define __BEGIN_DECLS
+#define __END_DECLS
+#if !defined(__STDC__)
+#define const __const
+#define inline __inline
+#define signed __signed
+#define volatile __volatile
+#endif
+#endif
+#else /* !__GNUC__ */
+#define __INLINE static
+#define __BEGIN_DECLS
+#define __END_DECLS
+#endif
+
+#ifndef __NORETURN
+#define __NORETURN
+#endif /* __NORETURN not defined. */
+
+#ifndef _U_INT32_T_
+#define _U_INT32_T_
+typedef unsigned int u_int32_t;
+#endif
+
+#ifndef _U_INT16_T_
+#define _U_INT16_T_
+typedef unsigned short u_int16_t;
+#endif
+
+#ifndef _INT32_T_
+#define _INT32_T_
+typedef int int32_t;
+#endif
+
+#ifndef _INT16_T_
+#define _INT16_T_
+typedef short int16_t;
+#endif
+
+#ifndef _SSIZE_T_
+#define _SSIZE_T_
+typedef int ssize_t;
+#endif
+
+#endif
diff --git a/mit-pthreads/machdep/ultrix-4.2/compat.h b/mit-pthreads/machdep/ultrix-4.2/compat.h
new file mode 100755
index 00000000000..b2a846d00ee
--- /dev/null
+++ b/mit-pthreads/machdep/ultrix-4.2/compat.h
@@ -0,0 +1,45 @@
+/* ==== compat.h ============================================================
+ * Copyright (c) 1994 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ *
+ * Description : Basic timers header.
+ *
+ * 1.00 94/06/13 proven
+ * -Started coding this file.
+ */
+
+#ifndef _SYS_COMPAT_H_
+#define _SYS_COMPAT_H_
+
+#define omsghdr msghdr
+
+#endif
diff --git a/mit-pthreads/machdep/ultrix-4.2/dirent.h b/mit-pthreads/machdep/ultrix-4.2/dirent.h
new file mode 100755
index 00000000000..5f17af345db
--- /dev/null
+++ b/mit-pthreads/machdep/ultrix-4.2/dirent.h
@@ -0,0 +1,61 @@
+/*-
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)dirent.h 5.18 (Berkeley) 2/23/91
+ */
+
+#ifndef _SYS_DIRENT_H_
+#define _SYS_DIRENT_H_
+
+/*
+ * A directory entry has a struct dirent at the front of it, containing its
+ * inode number, the length of the entry, and the length of the name
+ * contained in the entry. These are followed by the name padded to a 4
+ * byte boundary with null bytes. All names are guaranteed null terminated.
+ * The maximum length of a name in a directory is MAXNAMLEN.
+ */
+
+struct dirent {
+ u_long d_fileno; /* file number of entry */
+ u_short d_reclen; /* length of this record */
+ u_short d_namlen; /* length of string in d_name */
+#ifdef _POSIX_SOURCE
+ char d_name[255 + 1]; /* name must be no longer than this */
+#else
+#define MAXNAMLEN 255
+ char d_name[MAXNAMLEN + 1]; /* name must be no longer than this */
+#endif
+};
+
+#define d_ino d_fileno
+
+#endif /* !_SYS_DIRENT_H_ */
diff --git a/mit-pthreads/machdep/ultrix-4.2/errno.h b/mit-pthreads/machdep/ultrix-4.2/errno.h
new file mode 100755
index 00000000000..b47633a9456
--- /dev/null
+++ b/mit-pthreads/machdep/ultrix-4.2/errno.h
@@ -0,0 +1,180 @@
+/*
+ * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)errno.h 7.13 (Berkeley) 2/19/91
+ * errno.h,v 1.3 1993/05/20 16:22:09 cgd Exp
+ */
+
+#ifndef _SYS_ERRNO_H_
+#define _SYS_ERRNO_H_
+
+#define EPERM 1 /* Operation not permitted */
+#define ENOENT 2 /* No such file or directory */
+#define ESRCH 3 /* No such process */
+#define EINTR 4 /* Interrupted system call */
+#define EIO 5 /* Input/output error */
+#define ENXIO 6 /* Device not configured */
+#define E2BIG 7 /* Argument list too long */
+#define ENOEXEC 8 /* Exec format error */
+#define EBADF 9 /* Bad file descriptor */
+#define ECHILD 10 /* No child processes */
+#define EAGAIN 11 /* No more processes */
+#define ENOMEM 12 /* Cannot allocate memory */
+#define EACCES 13 /* Permission denied */
+#define EFAULT 14 /* Bad address */
+/* 15 Non POSIX */
+/* 16 Non POSIX */
+#define EEXIST 17 /* File exists */
+#define EXDEV 18 /* Cross-device link */
+#define ENODEV 19 /* Operation not supported by device */
+#define ENOTDIR 20 /* Not a directory */
+#define EISDIR 21 /* Is a directory */
+#define EINVAL 22 /* Invalid argument */
+#define ENFILE 23 /* Too many open files in system */
+#define EMFILE 24 /* Too many open files */
+#define ENOTTY 25 /* Inappropriate ioctl for device */
+/* 26 Non POSIX */
+#define EFBIG 27 /* File too large */
+#define ENOSPC 28 /* No space left on device */
+#define ESPIPE 29 /* Illegal seek */
+#define EROFS 30 /* Read-only file system */
+#define EMLINK 31 /* Too many links */
+#define EPIPE 32 /* Broken pipe */
+
+/* math software */
+#define EDOM 33 /* Numerical argument out of domain */
+#define ERANGE 34 /* Result too large */
+/* 35 Non POSIX */
+/* 36 Non POSIX */
+/* 37 Non POSIX */
+/* 38 Non POSIX */
+/* 39 Non POSIX */
+/* 40 Non POSIX */
+/* 41 Non POSIX */
+/* 42 Non POSIX */
+/* 43 Non POSIX */
+/* 44 Non POSIX */
+/* 45 Non POSIX */
+/* 46 Non POSIX */
+/* 47 Non POSIX */
+/* 48 Non POSIX */
+/* 49 Non POSIX */
+/* 50 Non POSIX */
+/* 51 Non POSIX */
+/* 52 Non POSIX */
+/* 53 Non POSIX */
+/* 54 Non POSIX */
+/* 55 Non POSIX */
+/* 56 Non POSIX */
+/* 57 Non POSIX */
+/* 58 Non POSIX */
+/* 59 Non POSIX */
+/* 60 Non POSIX */
+/* 61 Non POSIX */
+/* 62 Non POSIX */
+#define ENAMETOOLONG 63 /* File name too long */
+/* 64 Non POSIX */
+/* 65 Non POSIX */
+#define ENOTEMPTY 66 /* Directory not empty */
+/* 67 Non POSIX */
+/* 68 Non POSIX */
+/* 69 Non POSIX */
+/* 70 Non POSIX */
+/* 71 Non POSIX */
+/* 72 Non POSIX */
+/* 73 Non POSIX */
+/* 74 Non POSIX */
+#define ENOLCK 75 /* No locks available */
+#define ENOSYS 76 /* Function not implemented */
+
+#ifndef _POSIX_SOURCE
+#define ENOTBLK 15 /* Block device required */
+#define EBUSY 16 /* Device busy */
+#define ETXTBSY 26 /* Text file busy */
+
+/* non-blocking and interrupt i/o */
+#define EWOULDBLOCK 35 /* Operation would block */
+#define EDEADLK EWOULDBLOCK /* Resource deadlock avoided */
+#define EINPROGRESS 36 /* Operation now in progress */
+#define EALREADY 37 /* Operation already in progress */
+
+/* ipc/network software -- argument errors */
+#define ENOTSOCK 38 /* Socket operation on non-socket */
+#define EDESTADDRREQ 39 /* Destination address required */
+#define EMSGSIZE 40 /* Message too long */
+#define EPROTOTYPE 41 /* Protocol wrong type for socket */
+#define ENOPROTOOPT 42 /* Protocol not available */
+#define EPROTONOSUPPORT 43 /* Protocol not supported */
+#define ESOCKTNOSUPPORT 44 /* Socket type not supported */
+#define EOPNOTSUPP 45 /* Operation not supported on socket */
+#define EPFNOSUPPORT 46 /* Protocol family not supported */
+#define EAFNOSUPPORT 47 /* Address family not supported by protocol family */
+#define EADDRINUSE 48 /* Address already in use */
+#define EADDRNOTAVAIL 49 /* Can't assign requested address */
+
+/* ipc/network software -- operational errors */
+#define ENETDOWN 50 /* Network is down */
+#define ENETUNREACH 51 /* Network is unreachable */
+#define ENETRESET 52 /* Network dropped connection on reset */
+#define ECONNABORTED 53 /* Software caused connection abort */
+#define ECONNRESET 54 /* Connection reset by peer */
+#define ENOBUFS 55 /* No buffer space available */
+#define EISCONN 56 /* Socket is already connected */
+#define ENOTCONN 57 /* Socket is not connected */
+#define ESHUTDOWN 58 /* Can't send after socket shutdown */
+#define ETOOMANYREFS 59 /* Too many references: can't splice */
+#define ETIMEDOUT 60 /* Connection timed out */
+#define ECONNREFUSED 61 /* Connection refused */
+
+#define ELOOP 62 /* Too many levels of symbolic links */
+
+#define EHOSTDOWN 64 /* Host is down */
+#define EHOSTUNREACH 65 /* No route to host */
+
+/* quotas & mush */
+#define EPROCLIM 67 /* Too many processes */
+#define EUSERS 68 /* Too many users */
+#define EDQUOT 69 /* Disc quota exceeded */
+
+/* Network File System */
+#define ESTALE 70 /* Stale NFS file handle */
+#define EREMOTE 71 /* Too many levels of remote in path */
+
+/* IPC errors */
+#define ENOMSG 72 /* RPC struct is bad */
+#define EIDRM 73 /* RPC version wrong */
+
+/* Alignment error of some type (i.e., cluster, page, block ...) */
+#define EALIGN 74 /* RPC prog. not avail */
+#endif /* _POSIX_SOURCE */
+
+#endif /* _SYS_ERRNO_H_ */
diff --git a/mit-pthreads/machdep/ultrix-4.2/time.h b/mit-pthreads/machdep/ultrix-4.2/time.h
new file mode 100755
index 00000000000..1dbb32b67a4
--- /dev/null
+++ b/mit-pthreads/machdep/ultrix-4.2/time.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * (c) UNIX System Laboratories, Inc.
+ * All or some portions of this file are derived from material licensed
+ * to the University of California by American Telephone and Telegraph
+ * Co. or Unix System Laboratories, Inc. and are reproduced herein with
+ * the permission of UNIX System Laboratories, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)time.h 5.12 (Berkeley) 3/9/91
+ * $Id$
+ */
+
+#ifndef _SYS_TIME_H_
+#define _SYS_TIME_H_
+
+#include <time.h>
+#include <sys/cdefs.h>
+
+struct timeval {
+ long tv_sec; /* seconds */
+ long tv_usec; /* microseconds */
+};
+
+struct timezone {
+ int tz_minuteswest; /* minutes west of Greenwich */
+ int tz_dsttime; /* dst correction */
+};
+#define DST_NONE 0 /* not on dst */
+#define DST_USA 1 /* USA style dst */
+#define DST_AUST 2 /* Australian style dst */
+#define DST_WET 3 /* Western European dst */
+#define DST_MET 4 /* Middle European dst */
+#define DST_EET 5 /* Eastern European dst */
+
+
+struct itimerval {
+ struct timeval it_interval; /* timer interval */
+ struct timeval it_value; /* current value */
+};
+#define ITIMER_REAL 0
+#define ITIMER_VIRTUAL 1
+#define ITIMER_PROF 2
+
+/*
+ * Functions
+ */
+__BEGIN_DECLS
+
+int gettimeofday __P_((struct timeval *, struct timezone *));
+
+__END_DECLS
+
+#endif
diff --git a/mit-pthreads/machdep/ultrix-4.2/timers.h b/mit-pthreads/machdep/ultrix-4.2/timers.h
new file mode 100755
index 00000000000..3c4d057976a
--- /dev/null
+++ b/mit-pthreads/machdep/ultrix-4.2/timers.h
@@ -0,0 +1,68 @@
+/* ==== timers.h ============================================================
+ * Copyright (c) 1994 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ *
+ * Description : Basic timers header.
+ *
+ * 1.00 94/06/13 proven
+ * -Started coding this file.
+ */
+
+#ifndef _SYS_TIMERS_H_
+#define _SYS_TIMERS_H_
+
+#include <sys/types.h>
+#include <time.h>
+
+struct timespec {
+ time_t tv_sec;
+ long tv_nsec;
+};
+
+#define TIMEVAL_TO_TIMESPEC(tv, ts) { \
+ (ts)->tv_sec = (tv)->tv_sec; \
+ (ts)->tv_nsec = (tv)->tv_usec * 1000; \
+}
+#define TIMESPEC_TO_TIMEVAL(tv, ts) { \
+ (tv)->tv_sec = (ts)->tv_sec; \
+ (tv)->tv_usec = (ts)->tv_nsec / 1000; \
+}
+
+/*
+ * New functions
+ */
+
+__BEGIN_DECLS
+
+__END_DECLS
+
+#endif
diff --git a/mit-pthreads/machdep/ultrix-4.2/wait.h b/mit-pthreads/machdep/ultrix-4.2/wait.h
new file mode 100755
index 00000000000..8114f7e461d
--- /dev/null
+++ b/mit-pthreads/machdep/ultrix-4.2/wait.h
@@ -0,0 +1,121 @@
+
+#ifndef _SYS_WAIT_H_
+#define _SYS_WAIT_H_
+
+#include <ansi_compat.h>
+#include <sys/cdefs.h>
+
+#if !defined(_POSIX_SOURCE)
+union wait {
+#else
+union __wait {
+#endif /* !defined(_POSIX_SOURCE) */
+#ifdef __vax
+ int w_status; /* used in syscall */
+#endif /* __vax */
+#ifdef __mips__
+ unsigned int w_status; /* used in syscall */
+#endif /* __mips */
+ /*
+ * Terminated process status.
+ */
+ struct {
+#ifdef __vax
+ unsigned short w_Termsig:7; /* termination signal */
+ unsigned short w_Coredump:1; /* core dump indicator */
+ unsigned short w_Retcode:8; /* exit code if w_termsig==0 */
+#endif /* __vax */
+#ifdef __mips__
+#ifdef __MIPSEL__
+ unsigned int w_Termsig:7; /* termination signal */
+ unsigned int w_Coredump:1; /* core dump indicator */
+ unsigned int w_Retcode:8; /* exit code if w_termsig==0 */
+ unsigned int w_Filler:16; /* pad to word boundary */
+#endif /* __MIPSEL */
+#ifdef __MIPSEB__
+ unsigned int w_Filler:16; /* pad to word boundary */
+ unsigned int w_Retcode:8; /* exit code if w_termsig==0 */
+ unsigned int w_Coredump:1; /* core dump indicator */
+ unsigned int w_Termsig:7; /* termination signal */
+#endif /* __MIPSEB */
+#endif /* __mips */
+ } w_T;
+ /*
+ * Stopped process status. Returned
+ * only for traced children unless requested
+ * with the WUNTRACED option bit.
+ */
+ struct {
+#ifdef __vax
+ unsigned short w_Stopval:8; /* == W_STOPPED if stopped */
+ unsigned short w_Stopsig:8; /* signal that stopped us */
+#endif /* __vax */
+#ifdef __mips__
+#ifdef __MIPSEL__
+ unsigned int w_Stopval:8; /* == W_STOPPED if stopped */
+ unsigned int w_Stopsig:8; /* signal that stopped us */
+ unsigned int w_Filler:16; /* pad to word boundary */
+#endif /* __MIPSEL */
+#ifdef __MIPSEB__
+ unsigned int w_Filler:16; /* pad to word boundary */
+ unsigned int w_Stopsig:8; /* signal that stopped us */
+ unsigned int w_Stopval:8; /* == W_STOPPED if stopped */
+#endif /* __MIPSEB */
+#endif /* __mips */
+ } w_S;
+};
+
+#if !defined(_POSIX_SOURCE)
+#define w_termsig w_T.w_Termsig
+#define w_coredump w_T.w_Coredump
+#define w_retcode w_T.w_Retcode
+#define w_stopval w_S.w_Stopval
+#define w_stopsig w_S.w_Stopsig
+#define WSTOPPED 0177 /* value of s.stopval if process is stopped */
+#endif /* !defined(_POSIX_SOURCE) */
+
+#ifdef WSTOPPED
+#define _WSTOPPED WSTOPPED
+#else
+#define _WSTOPPED 0177
+#endif
+
+/*
+ * Option bits for the second argument of wait3. WNOHANG causes the
+ * wait to not hang if there are no stopped or terminated processes, rather
+ * returning an error indication in this case (pid==0). WUNTRACED
+ * indicates that the caller should receive status about untraced children
+ * which stop due to signals. If children are stopped and a wait without
+ * this option is done, it is as though they were still running... nothing
+ * about them is returned.
+ */
+#define WNOHANG 1 /* dont hang in wait */
+#define WUNTRACED 2 /* tell about stopped, untraced children */
+
+/*
+ * Must cast as union wait * because POSIX defines the input to these macros
+ * as int.
+ */
+
+#ifdef _POSIX_SOURCE
+#define WIFSTOPPED(x) (((union __wait *)&(x))->w_S.w_Stopval == _WSTOPPED)
+#define WIFSIGNALED(x) (((union __wait *)&(x))->w_S.w_Stopval != _WSTOPPED && ((union __wait *)&(x))->w_T.w_Termsig != 0)
+#define WIFEXITED(x) (((union __wait *)&(x))->w_S.w_Stopval != _WSTOPPED && ((union __wait *)&(x))->w_T.w_Termsig == 0)
+#define WEXITSTATUS(x) (((union __wait *)&(x))->w_T.w_Retcode)
+#define WTERMSIG(x) (((union __wait *)&(x))->w_T.w_Termsig)
+#define WSTOPSIG(x) (((union __wait *)&(x))->w_S.w_Stopsig)
+#endif /* _POSIX_SOURCE */
+
+#if !defined(_POSIX_SOURCE)
+#define WIFSTOPPED(x) (((union wait *)&(x))->w_stopval == WSTOPPED)
+#define WIFSIGNALED(x) (((union wait *)&(x))->w_stopval != WSTOPPED && ((union wait *)&(x))->w_termsig != 0)
+#define WIFEXITED(x) (((union wait *)&(x))->w_stopval != WSTOPPED && ((union wait *)&(x))->w_termsig == 0)
+#define WEXITSTATUS(x) (((union wait *)&(x))->w_retcode)
+#define WTERMSIG(x) (((union wait *)&(x))->w_termsig)
+#define WSTOPSIG(x) (((union wait *)&(x))->w_stopsig)
+#endif /* !defined(_POSIX_SOURCE) */
+
+pid_t wait __P_((int *));
+pid_t waitpid __P_((pid_t, int *, int));
+
+#endif /* _SYS_WAIT_H_ */
diff --git a/mit-pthreads/machdep/unistd-i386-freebsd-1.1.h b/mit-pthreads/machdep/unistd-i386-freebsd-1.1.h
new file mode 100644
index 00000000000..033e70de5e5
--- /dev/null
+++ b/mit-pthreads/machdep/unistd-i386-freebsd-1.1.h
@@ -0,0 +1,178 @@
+/*-
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)unistd.h 5.13 (Berkeley) 6/17/91
+ */
+
+#ifndef _UNISTD_H_
+#define _UNISTD_H_
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+#include <sys/unistd.h>
+
+#define STDIN_FILENO 0 /* standard input file descriptor */
+#define STDOUT_FILENO 1 /* standard output file descriptor */
+#define STDERR_FILENO 2 /* standard error file descriptor */
+
+#ifndef NULL
+#define NULL 0 /* null pointer constant */
+#endif
+
+typedef int ssize_t; /* count of bytes or error indication */
+
+__BEGIN_DECLS
+void _exit __P_((int));
+int access __P_((const char *, int));
+u_int alarm __P_((u_int));
+int chdir __P_((const char *));
+int chown __P_((const char *, uid_t, gid_t));
+int close __P_((int));
+char *cuserid __P_((char *));
+int dup __P_((int));
+int dup2 __P_((int, int));
+int execl __P_((const char *, const char *, ...));
+int execle __P_((const char *, const char *, ...));
+int execlp __P_((const char *, const char *, ...));
+int execv __P_((const char *, char * const *));
+int execve __P_((const char *, char * const *, char * const *));
+int execvp __P_((const char *, char * const *));
+pid_t fork __P_((void));
+long fpathconf __P_((int, int)); /* not yet */
+char *getcwd __P_((char *, size_t));
+gid_t getegid __P_((void));
+uid_t geteuid __P_((void));
+gid_t getgid __P_((void));
+int getgroups __P_((int, int *)); /* XXX (gid_t *) */
+char *getlogin __P_((void));
+pid_t getpgrp __P_((void));
+pid_t getpid __P_((void));
+pid_t getppid __P_((void));
+uid_t getuid __P_((void));
+int isatty __P_((int));
+int link __P_((const char *, const char *));
+off_t lseek __P_((int, off_t, int));
+long pathconf __P_((const char *, int)); /* not yet */
+int pause __P_((void));
+int pipe __P_((int *));
+ssize_t read __P_((int, void *, size_t));
+int rmdir __P_((const char *));
+int setgid __P_((gid_t));
+int setpgid __P_((pid_t, pid_t));
+pid_t setsid __P_((void));
+int setuid __P_((uid_t));
+u_int sleep __P_((u_int));
+long sysconf __P_((int)); /* not yet */
+pid_t tcgetpgrp __P_((int));
+int tcsetpgrp __P_((int, pid_t));
+char *ttyname __P_((int));
+int unlink __P_((const char *));
+ssize_t write __P_((int, const void *, size_t));
+
+#ifndef _POSIX_SOURCE
+
+/* structure timeval required for select() */
+#include <sys/time.h>
+
+int acct __P_((const char *));
+int async_daemon __P_((void));
+char *brk __P_((const char *));
+int chflags __P_((const char *, long));
+int chroot __P_((const char *));
+char *crypt __P_((const char *, const char *));
+int des_cipher __P_((const char *, char *, long, int));
+int des_setkey __P_((const char *key));
+int encrypt __P_((char *, int));
+void endusershell __P_((void));
+int exect __P_((const char *, char * const *, char * const *));
+int fchdir __P_((int));
+int fchflags __P_((int, long));
+int fchown __P_((int, uid_t, gid_t));
+int fsync __P_((int));
+int ftruncate __P_((int, off_t));
+int getdtablesize __P_((void));
+long gethostid __P_((void));
+int gethostname __P_((char *, int));
+mode_t getmode __P_((const void *, mode_t));
+int getpagesize __P_((void));
+char *getpass __P_((const char *));
+char *getusershell __P_((void));
+char *getwd __P_((char *)); /* obsoleted by getcwd() */
+int initgroups __P_((const char *, int));
+int mknod __P_((const char *, mode_t, dev_t));
+int mkstemp __P_((char *));
+char *mktemp __P_((char *));
+int nfssvc __P_((int));
+int nice __P_((int));
+void psignal __P_((u_int, const char *));
+extern char *sys_siglist[];
+int profil __P_((char *, int, int, int));
+int rcmd __P_((char **, int, const char *,
+ const char *, const char *, int *));
+char *re_comp __P_((const char *));
+int re_exec __P_((const char *));
+int readlink __P_((const char *, char *, int));
+int reboot __P_((int));
+int revoke __P_((const char *));
+int rresvport __P_((int *));
+int ruserok __P_((const char *, int, const char *, const char *));
+char *sbrk __P_((int));
+int select __P_((int, fd_set *, fd_set *, fd_set *, struct timeval *));
+int setegid __P_((gid_t));
+int seteuid __P_((uid_t));
+int setgroups __P_((int, const int *));
+void sethostid __P_((long));
+int sethostname __P_((const char *, int));
+int setkey __P_((const char *));
+int setlogin __P_((const char *));
+void *setmode __P_((const char *));
+int setpgrp __P_((pid_t pid, pid_t pgrp)); /* obsoleted by setpgid() */
+int setregid __P_((int, int));
+int setreuid __P_((int, int));
+int setrgid __P_((gid_t));
+int setruid __P_((uid_t));
+void setusershell __P_((void));
+int swapon __P_((const char *));
+int symlink __P_((const char *, const char *));
+void sync __P_((void));
+int syscall __P_((int, ...));
+int truncate __P_((const char *, off_t));
+int ttyslot __P_((void));
+u_int ualarm __P_((u_int, u_int));
+void usleep __P_((u_int));
+void *valloc __P_((size_t)); /* obsoleted by malloc() */
+int vfork __P_((void));
+
+#endif /* !_POSIX_SOURCE */
+__END_DECLS
+
+#endif /* !_UNISTD_H_ */
diff --git a/mit-pthreads/machdep/unistd-i386-linux-1.0.h b/mit-pthreads/machdep/unistd-i386-linux-1.0.h
new file mode 100644
index 00000000000..e7a3c5de1e4
--- /dev/null
+++ b/mit-pthreads/machdep/unistd-i386-linux-1.0.h
@@ -0,0 +1,59 @@
+/*-
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)unistd.h 5.13 (Berkeley) 6/17/91
+ */
+
+#ifndef _UNISTD_H_
+#define _UNISTD_H_
+
+#include <features.h>
+
+/* POSIX Standard approved as IEEE Std 1003.1 as of August, 1988. */
+#define _POSIX_VERSION 199009L
+#define _POSIX2_C_BIND 1
+#define _POSIX2_C_DEV 1
+#define _POSIX2_SW_DEV 1
+
+#define __need_size_t
+
+#include <posix_opt.h>
+#include <sys/types.h>
+#include <stddef.h>
+
+#define STDIN_FILENO 0 /* standard input file descriptor */
+#define STDOUT_FILENO 1 /* standard output file descriptor */
+#define STDERR_FILENO 2 /* standard error file descriptor */
+
+#include <pthread/unistd.h>
+
+#endif /* !_UNISTD_H_ */
diff --git a/mit-pthreads/machdep/unistd-i386-linux-2.0.h b/mit-pthreads/machdep/unistd-i386-linux-2.0.h
new file mode 100644
index 00000000000..e7a3c5de1e4
--- /dev/null
+++ b/mit-pthreads/machdep/unistd-i386-linux-2.0.h
@@ -0,0 +1,59 @@
+/*-
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)unistd.h 5.13 (Berkeley) 6/17/91
+ */
+
+#ifndef _UNISTD_H_
+#define _UNISTD_H_
+
+#include <features.h>
+
+/* POSIX Standard approved as IEEE Std 1003.1 as of August, 1988. */
+#define _POSIX_VERSION 199009L
+#define _POSIX2_C_BIND 1
+#define _POSIX2_C_DEV 1
+#define _POSIX2_SW_DEV 1
+
+#define __need_size_t
+
+#include <posix_opt.h>
+#include <sys/types.h>
+#include <stddef.h>
+
+#define STDIN_FILENO 0 /* standard input file descriptor */
+#define STDOUT_FILENO 1 /* standard output file descriptor */
+#define STDERR_FILENO 2 /* standard error file descriptor */
+
+#include <pthread/unistd.h>
+
+#endif /* !_UNISTD_H_ */
diff --git a/mit-pthreads/machdep/unistd-sparc-sunos-4.1.3.h b/mit-pthreads/machdep/unistd-sparc-sunos-4.1.3.h
new file mode 100644
index 00000000000..4d2161b628f
--- /dev/null
+++ b/mit-pthreads/machdep/unistd-sparc-sunos-4.1.3.h
@@ -0,0 +1,215 @@
+/*-
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)unistd.h 5.13 (Berkeley) 6/17/91
+ * $Id$
+ */
+
+#ifndef _UNISTD_H_
+#define _UNISTD_H_
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+
+#define _NO_STDIO_SIZE_T
+
+#define _SC_ARG_MAX 1 /* space for argv & envp */
+#define _SC_CHILD_MAX 2 /* maximum children per process??? */
+#define _SC_CLK_TCK 3 /* clock ticks/sec */
+#define _SC_NGROUPS_MAX 4 /* number of groups if multple supp. */
+#define _SC_OPEN_MAX 5 /* max open files per process */
+#define _SC_JOB_CONTROL 6 /* do we have job control */
+#define _SC_SAVED_IDS 7 /* do we have saved uid/gids */
+#define _SC_VERSION 8 /* POSIX version supported */
+
+#define _POSIX_JOB_CONTROL 1
+#define _POSIX_SAVED_IDS 1
+#define _POSIX_VERSION 198808
+
+#define _PC_LINK_MAX 1 /* max links to file/dir */
+#define _PC_MAX_CANON 2 /* max line length */
+#define _PC_MAX_INPUT 3 /* max "packet" to a tty device */
+#define _PC_NAME_MAX 4 /* max pathname component length */
+#define _PC_PATH_MAX 5 /* max pathname length */
+#define _PC_PIPE_BUF 6 /* size of a pipe */
+#define _PC_CHOWN_RESTRICTED 7 /* can we give away files */
+#define _PC_NO_TRUNC 8 /* trunc or error on >NAME_MAX */
+#define _PC_VDISABLE 9 /* best char to shut off tty c_cc */
+#define _PC_LAST 9 /* highest value of any _PC_* */
+
+
+#define STDIN_FILENO 0 /* standard input file descriptor */
+#define STDOUT_FILENO 1 /* standard output file descriptor */
+#define STDERR_FILENO 2 /* standard error file descriptor */
+
+#ifndef NULL
+#define NULL 0 /* null pointer constant */
+#endif
+
+typedef int ssize_t;
+
+__BEGIN_DECLS
+void _exit __P_((int));
+int access __P_((const char *, int));
+unsigned alarm __P_((unsigned));
+int chdir __P_((const char *));
+int chown __P_((const char *, uid_t, gid_t));
+int close __P_((int));
+size_t confstr __P_((int, char *, size_t));
+char *cuserid __P_((char *));
+int dup __P_((int));
+int dup2 __P_((int, int));
+int execl __P_((const char *, const char *, ...));
+int execle __P_((const char *, const char *, ...));
+int execlp __P_((const char *, const char *, ...));
+int execv __P_((const char *, char * const *));
+int execve __P_((const char *, char * const *, char * const *));
+int execvp __P_((const char *, char * const *));
+pid_t fork __P_((void));
+long fpathconf __P_((int, int)); /* not yet */
+char *getcwd __P_((char *, size_t));
+gid_t getegid __P_((void));
+uid_t geteuid __P_((void));
+gid_t getgid __P_((void));
+int getgroups __P_((int, int *)); /* XXX (gid_t *) */
+char *getlogin __P_((void));
+pid_t getpgrp __P_((void));
+pid_t getpid __P_((void));
+pid_t getppid __P_((void));
+uid_t getuid __P_((void));
+int isatty __P_((int));
+int link __P_((const char *, const char *));
+off_t lseek __P_((int, off_t, int));
+long pathconf __P_((const char *, int)); /* not yet */
+int pause __P_((void));
+int pipe __P_((int *));
+ssize_t read __P_((int, void *, size_t));
+int rmdir __P_((const char *));
+int setgid __P_((gid_t));
+int setpgid __P_((pid_t, pid_t));
+pid_t setsid __P_((void));
+int setuid __P_((uid_t));
+unsigned sleep __P_((unsigned));
+long sysconf __P_((int)); /* not yet */
+pid_t tcgetpgrp __P_((int));
+int tcsetpgrp __P_((int, pid_t));
+char *ttyname __P_((int));
+int unlink __P_((const char *));
+ssize_t write __P_((int, const void *, size_t));
+
+#ifndef _POSIX_SOURCE
+
+/* structure timeval required for select() */
+#include <sys/time.h>
+
+int acct __P_((const char *));
+int async_daemon __P_((void));
+char *brk __P_((const char *));
+int chflags __P_((const char *, long));
+int chroot __P_((const char *));
+char *crypt __P_((const char *, const char *));
+int des_cipher __P_((const char *, char *, long, int));
+int des_setkey __P_((const char *key));
+int encrypt __P_((char *, int));
+void endusershell __P_((void));
+int exect __P_((const char *, char * const *, char * const *));
+int fchdir __P_((int));
+int fchflags __P_((int, long));
+int fchown __P_((int, uid_t, gid_t));
+int fsync __P_((int));
+int ftruncate __P_((int, off_t));
+int getdomainname __P_((char *, int));
+int getdtablesize __P_((void));
+long gethostid __P_((void));
+int gethostname __P_((char *, int));
+mode_t getmode __P_((const void *, mode_t));
+int getpagesize __P_((void));
+char *getpass __P_((const char *));
+char *getusershell __P_((void));
+char *getwd __P_((char *)); /* obsoleted by getcwd() */
+int initgroups __P_((const char *, int));
+int mknod __P_((const char *, mode_t, dev_t));
+int mkstemp __P_((char *));
+char *mktemp __P_((char *));
+int nfssvc __P_((int));
+int nice __P_((int));
+void psignal __P_((u_int, const char *));
+extern const char *const sys_siglist[];
+int profil __P_((char *, int, int, int));
+int rcmd __P_((char **, int, const char *,
+ const char *, const char *, int *));
+char *re_comp __P_((const char *));
+int re_exec __P_((const char *));
+int readlink __P_((const char *, char *, int));
+int reboot __P_((int));
+int revoke __P_((const char *));
+int rresvport __P_((int *));
+int ruserok __P_((const char *, int, const char *, const char *));
+char *sbrk __P_((int));
+int select __P_((int, fd_set *, fd_set *, fd_set *, struct timeval *));
+int setdomainname __P_((const char *, int));
+int setegid __P_((gid_t));
+int seteuid __P_((uid_t));
+int setgroups __P_((int, const int *));
+void sethostid __P_((long));
+int sethostname __P_((const char *, int));
+int setkey __P_((const char *));
+int setlogin __P_((const char *));
+void *setmode __P_((const char *));
+int setpgrp __P_((pid_t pid, pid_t pgrp)); /* obsoleted by setpgid() */
+int setregid __P_((int, int));
+int setreuid __P_((int, int));
+int setrgid __P_((gid_t));
+int setruid __P_((uid_t));
+void setusershell __P_((void));
+int swapon __P_((const char *));
+int symlink __P_((const char *, const char *));
+void sync __P_((void));
+int syscall __P_((int, ...));
+int truncate __P_((const char *, off_t));
+int ttyslot __P_((void));
+u_int ualarm __P_((u_int, u_int));
+void usleep __P_((u_int));
+void *valloc __P_((size_t)); /* obsoleted by malloc() */
+pid_t vfork __P_((void));
+
+int getopt __P_((int, char * const *, const char *));
+extern char *optarg; /* getopt(3) external variables */
+extern int opterr;
+extern int optind;
+extern int optopt;
+int getsubopt __P_((char **, char * const *, char **));
+extern char *suboptarg; /* getsubopt(3) external variable */
+#endif /* !_POSIX_SOURCE */
+__END_DECLS
+
+#endif /* !_UNISTD_H_ */
diff --git a/mit-pthreads/net/GNUmakefile.inc b/mit-pthreads/net/GNUmakefile.inc
new file mode 100644
index 00000000000..6b89617f63b
--- /dev/null
+++ b/mit-pthreads/net/GNUmakefile.inc
@@ -0,0 +1,14 @@
+# from: @(#)Makefile.inc 5.21 (Berkeley) 5/24/91
+# $Id$
+
+# gen sources
+VPATH:= ${VPATH}:${srcdir}/net
+
+SRCS:= gethostbyaddr.c gethostbyname.c gethostent.c getnetbyaddr.c \
+ getnetbyname.c getnetent.c getproto.c getprotoent.c getprotoname.c \
+ getservbyname.c getservbyport.c getservent.c herror.c inet_addr.c \
+ inet_lnaof.c inet_makeaddr.c inet_netof.c inet_network.c inet_ntoa.c \
+ net_internal.c proto_internal.c res_comp.c res_init.c res_internal.c \
+ res_mkquery.c res_query.c res_querydomain.c res_search.c res_send.c \
+ res_debug.c serv_internal.c $(SRCS)
+
diff --git a/mit-pthreads/net/Makefile.inc b/mit-pthreads/net/Makefile.inc
new file mode 100644
index 00000000000..08be88c808f
--- /dev/null
+++ b/mit-pthreads/net/Makefile.inc
@@ -0,0 +1,13 @@
+# from: @(#)Makefile.inc 5.21 (Berkeley) 5/24/91
+# $Id$
+
+# gen sources
+.PATH: ${srcdir}/net
+
+SRCS+= gethostbyaddr.c gethostbyname.c gethostent.c getnetbyaddr.c \
+ getnetbyname.c getnetent.c getproto.c getprotoent.c getprotoname.c \
+ getservbyname.c getservbyport.c getservent.c herror.c inet_addr.c \
+ inet_lnaof.c inet_makeaddr.c inet_netof.c inet_network.c inet_ntoa.c \
+ net_internal.c proto_internal.c res_comp.c res_init.c res_internal.c \
+ res_mkquery.c res_query.c res_querydomain.c res_search.c res_send.c \
+ serv_internal.c gethostname.c
diff --git a/mit-pthreads/net/gethostbyaddr.c b/mit-pthreads/net/gethostbyaddr.c
new file mode 100644
index 00000000000..f80e47ffd99
--- /dev/null
+++ b/mit-pthreads/net/gethostbyaddr.c
@@ -0,0 +1,161 @@
+/*
+ * Copyright (c) 1985, 1988 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)gethostbyaddr.c 6.45 (Berkeley) 2/24/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+
+#include <pthread.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <resolv.h>
+#include <netinet/in.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include "res_internal.h"
+
+static struct hostent *file_find_addr(const char *addr, int len, int type,
+ struct hostent *result, char *buf,
+ int bufsize, int *errval);
+
+struct hostent *gethostbyaddr(const char *addr, int len, int type)
+{
+ struct res_data *data = _res_init();
+
+ if (!data)
+ return NULL;
+ if (!data->buf) {
+ data->buf = malloc(sizeof(struct hostent) + HOST_BUFSIZE);
+ if (!data->buf) {
+ errno = 0;
+ data->errval = NO_RECOVERY;
+ return NULL;
+ }
+ }
+ return gethostbyaddr_r(addr, len, type, (struct hostent *) data->buf,
+ data->buf + sizeof(struct hostent), HOST_BUFSIZE,
+ &data->errval);
+}
+
+struct hostent *gethostbyaddr_r(const char *addr, int len, int type,
+ struct hostent *result, char *buf, int bufsize,
+ int *errval)
+{
+ struct res_data *data;
+ querybuf qbuf;
+ char lookups[MAXDNSLUS], addrbuf[MAXDNAME], *abuf;
+ struct hostent *hp;
+ int n, i;
+
+ /* Default failure condition is not a range error and not recoverable. */
+ errno = 0;
+ *errval = NO_RECOVERY;
+
+ data = _res_init();
+ if (!data)
+ return NULL;
+
+ if (type != AF_INET)
+ return NULL;
+ sprintf(addrbuf, "%u.%u.%u.%u.in-addr.arpa",
+ (unsigned)addr[3] & 0xff, (unsigned)addr[2] & 0xff,
+ (unsigned)addr[1] & 0xff, (unsigned)addr[0] & 0xff);
+
+ memcpy(lookups, data->state.lookups, sizeof(lookups));
+ if (*lookups == 0)
+ strncpy(lookups, "bf", sizeof(lookups));
+
+ hp = NULL;
+ for (i = 0; i < MAXDNSLUS && hp == NULL && lookups[i]; i++) {
+ switch (lookups[i]) {
+ case 'b':
+
+ /* Allocate space for a one-item list of addresses. */
+ abuf = SP(SP(buf, char *, 2), struct in_addr, 1);
+ if (abuf > buf + bufsize) {
+ errno = ERANGE;
+ return NULL;
+ }
+
+ /* Perform and parse the query. */
+ n = res_query(addrbuf, C_IN, T_PTR, (char *)&qbuf, sizeof(qbuf));
+ if (n < 0)
+ break;
+ hp = _res_parse_answer(&qbuf, n, 1, result, abuf,
+ bufsize - (abuf - buf), errval);
+ if (hp == NULL)
+ break;
+
+ /* Fill in our own address list. */
+ result->h_addrtype = type;
+ result->h_length = len;
+ result->h_addr_list = (char **) ALIGN(buf, char *);
+ result->h_addr_list[0] = ALIGN(&result->h_addr_list[2],
+ struct in_addr);
+ result->h_addr_list[1] = NULL;
+ break;
+
+ case 'f':
+ hp = file_find_addr(addr, len, type, result, buf, bufsize, errval);
+ break;
+ }
+ }
+
+ return hp;
+}
+
+static struct hostent *file_find_addr(const char *addr, int len, int type,
+ struct hostent *result, char *buf,
+ int bufsize, int *errval)
+{
+ FILE *fp = NULL;
+
+ pthread_mutex_lock(&host_iterate_lock);
+ sethostent(0);
+ while ((result = gethostent_r(result, buf, bufsize, errval)) != NULL) {
+ /* Check the entry against the given address. */
+ if (result->h_addrtype == type &&
+ memcmp(result->h_addr, addr, len) == 0)
+ break;
+ }
+ pthread_mutex_unlock(&host_iterate_lock);
+ if (!result && errno != ERANGE)
+ *errval = HOST_NOT_FOUND;
+ return result;
+}
+
diff --git a/mit-pthreads/net/gethostbyname.c b/mit-pthreads/net/gethostbyname.c
new file mode 100644
index 00000000000..aaaaf79b31b
--- /dev/null
+++ b/mit-pthreads/net/gethostbyname.c
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 1985, 1988 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)gethostbyname.c 6.45 (Berkeley) 2/24/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <resolv.h>
+#include "res_internal.h"
+
+static struct hostent *fake_hostent(const char *hostname, struct in_addr addr,
+ struct hostent *result, char *buf,
+ int bufsize, int *errval);
+static struct hostent *file_find_name(const char *name, struct hostent *result,
+ char *buf, int bufsize, int *errval);
+
+struct hostent *gethostbyname(const char *hostname)
+{
+ struct res_data *data = _res_init();
+
+ if (!data)
+ return NULL;
+ if (!data->buf) {
+ data->buf = malloc(sizeof(struct hostent) + HOST_BUFSIZE);
+ if (!data->buf) {
+ errno = 0;
+ data->errval = NO_RECOVERY;
+ return NULL;
+ }
+ }
+ return gethostbyname_r(hostname, (struct hostent *) data->buf,
+ data->buf + sizeof(struct hostent), HOST_BUFSIZE,
+ &data->errval);
+}
+
+struct hostent *gethostbyname_r(const char *hostname, struct hostent *result,
+ char *buf, int bufsize, int *errval)
+{
+ struct in_addr addr;
+ querybuf qbuf;
+ const char *p;
+ int n;
+
+ /* Default failure condition is not a range error and not recoverable. */
+ errno = 0;
+ *errval = NO_RECOVERY;
+
+ /* Check for all-numeric hostname with no trailing dot. */
+ if (isdigit(hostname[0])) {
+ p = hostname;
+ while (*p && (isdigit(*p) || *p == '.'))
+ p++;
+ if (!*p && p[-1] != '.') {
+ /* Looks like an IP address; convert it. */
+ if (inet_aton(hostname, &addr) == -1) {
+ *errval = HOST_NOT_FOUND;
+ return NULL;
+ }
+ return fake_hostent(hostname, addr, result, buf, bufsize, errval);
+ }
+ }
+
+ /* Do the search. */
+ n = res_search(hostname, C_IN, T_A, qbuf.buf, sizeof(qbuf));
+ if (n >= 0)
+ return _res_parse_answer(&qbuf, n, 0, result, buf, bufsize, errval);
+ else if (errno == ECONNREFUSED)
+ return file_find_name(hostname, result, buf, bufsize, errval);
+ else
+ return NULL;
+}
+
+static struct hostent *fake_hostent(const char *hostname, struct in_addr addr,
+ struct hostent *result, char *buf,
+ int bufsize, int *errval)
+{
+ int len = strlen(hostname);
+ char *name, *addr_ptr;
+
+ if (SP(SP(SP(buf, char, len + 1), addr, 1), char *, 3) > buf + bufsize) {
+ errno = ERANGE;
+ return NULL;
+ }
+
+ /* Copy faked name and address into buffer. */
+ strcpy(buf, hostname);
+ name = buf;
+ buf = ALIGN(buf + len + 1, addr);
+ *((struct in_addr *) buf) = addr;
+ addr_ptr = buf;
+ buf = ALIGN(buf + sizeof(addr), char *);
+ ((char **) buf)[0] = addr_ptr;
+ ((char **) buf)[1] = NULL;
+ ((char **) buf)[2] = NULL;
+
+ result->h_name = name;
+ result->h_aliases = ((char **) buf) + 2;
+ result->h_addrtype = AF_INET;
+ result->h_length = sizeof(addr);
+ result->h_addr_list = (char **) buf;
+
+ return result;
+}
+
+static struct hostent *file_find_name(const char *name, struct hostent *result,
+ char *buf, int bufsize, int *errval)
+{
+ char **alias;
+ FILE *fp = NULL;
+
+ pthread_mutex_lock(&host_iterate_lock);
+ sethostent(0);
+ while ((result = gethostent_r(result, buf, bufsize, errval)) != NULL) {
+ /* Check the entry's name and aliases against the given name. */
+ if (strcasecmp(result->h_name, name) == 0)
+ break;
+ for (alias = result->h_aliases; *alias; alias++) {
+ if (strcasecmp(*alias, name) == 0)
+ goto end; /* Josip Gracin */
+ }
+ }
+end:
+ pthread_mutex_unlock(&host_iterate_lock);
+ if (!result && errno != ERANGE)
+ *errval = HOST_NOT_FOUND;
+ return result;
+}
+
diff --git a/mit-pthreads/net/gethostent.c b/mit-pthreads/net/gethostent.c
new file mode 100644
index 00000000000..d6feb7aa164
--- /dev/null
+++ b/mit-pthreads/net/gethostent.c
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)gethostent.c 5.8 (Berkeley) 2/24/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <pthread.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include "res_internal.h"
+
+static pthread_mutex_t res_file_lock = PTHREAD_MUTEX_INITIALIZER;
+static int res_file_stayopen;
+static FILE *res_file;
+
+void sethostent(int stayopen)
+{
+ pthread_mutex_lock(&res_file_lock);
+ res_file_stayopen |= stayopen;
+ if (res_file)
+ rewind(res_file);
+ else
+ res_file = fopen(_PATH_HOSTS, "r");
+ pthread_mutex_unlock(&res_file_lock);
+}
+
+void endhostent()
+{
+ pthread_mutex_lock(&res_file_lock);
+ if (res_file)
+ fclose(res_file);
+ pthread_mutex_unlock(&res_file_lock);
+}
+
+struct hostent *gethostent()
+{
+ struct res_data *data = _res_init();
+
+ if (!data)
+ return NULL;
+ if (!data->buf) {
+ data->buf = malloc(sizeof(struct hostent) + HOST_BUFSIZE);
+ if (!data->buf) {
+ data->errval = NO_RECOVERY;
+ return NULL;
+ }
+ }
+ return gethostent_r((struct hostent *) data->buf,
+ data->buf + sizeof(struct hostent), HOST_BUFSIZE,
+ &data->errval);
+}
+
+struct hostent *gethostent_r(struct hostent *result, char *buf, int bufsize,
+ int *errval)
+{
+ char *p, **alias;
+ struct in_addr *addr;
+ int l;
+
+ errno = 0;
+ pthread_mutex_lock(&res_file_lock);
+ if (res_file == NULL && (res_file = fopen(_PATH_HOSTS, "r")) == NULL) {
+ pthread_mutex_unlock(&res_file_lock);
+ return NULL;
+ }
+ while (fgets(buf, bufsize, res_file)) {
+ if (*buf == '#')
+ continue;
+ p = strpbrk(buf, "#\n");
+ if (p == NULL)
+ continue;
+ l = strlen(buf) + 1;
+ *p = '\0';
+ p = strpbrk(buf, " \t");
+ if (p == NULL)
+ continue;
+ *p++ = '\0';
+
+ /* THIS STUFF IS INTERNET SPECIFIC */
+ if (SP(SP(SP(buf, char, l), *addr, 1), char *, 3) > buf + bufsize) {
+ errno = ERANGE;
+ break;
+ }
+ addr = (struct in_addr *) ALIGN(buf + l, struct in_addr);
+ if (inet_aton(buf, addr) == 0)
+ continue;
+ result->h_length = sizeof(*addr);
+ result->h_addrtype = AF_INET;
+ result->h_addr_list = (char **) ALIGN(addr + sizeof(*addr), char *);
+ result->h_addr_list[0] = (char *) addr;
+ result->h_addr_list[1] = NULL;
+ result->h_aliases = result->h_addr_list + 2;
+ while (*p == ' ' || *p == '\t')
+ p++;
+ result->h_name = p;
+ alias = result->h_aliases;
+ p = strpbrk(p, " \t");
+ if (p != NULL)
+ *p++ = '\0';
+ while (p && *p) {
+ if (*p == ' ' || *p == '\t') {
+ p++;
+ continue;
+ }
+ if ((char *) &alias[2] > buf + bufsize) {
+ errno = ERANGE;
+ break;
+ }
+ *alias++ = p;
+ p = strpbrk(p, " \t");
+ if (p != NULL)
+ *p++ = '\0';
+ }
+ if (p && *p)
+ break;
+ *alias = NULL;
+ pthread_mutex_unlock(&res_file_lock);
+ return result;
+ }
+
+ pthread_mutex_unlock(&res_file_lock);
+ *errval = (errno == ERANGE) ? NO_RECOVERY : 0;
+ return NULL;
+}
+
diff --git a/mit-pthreads/net/gethostname.c b/mit-pthreads/net/gethostname.c
new file mode 100644
index 00000000000..8bec0793296
--- /dev/null
+++ b/mit-pthreads/net/gethostname.c
@@ -0,0 +1,22 @@
+/* Copyright Abandoned 2000 TCX DataKonsult AB & Monty Program KB & Detron HB
+ This file is public domain and comes with NO WARRANTY of any kind */
+
+#include "config.h"
+#include <pthread.h>
+#include <sys/utsname.h>
+
+#ifdef HAVE_SYSCALL_UNAME
+int gethostname(char *name, int len)
+{
+ int ret;
+ struct utsname buf;
+
+ if ((ret = machdep_sys_chroot(&buf)) < OK)
+ {
+ SET_ERRNO(-ret);
+ }
+ else
+ strncpy(name,uname->sysname, len);
+ return(ret);
+}
+#endif
diff --git a/mit-pthreads/net/getnetbyaddr.c b/mit-pthreads/net/getnetbyaddr.c
new file mode 100644
index 00000000000..6fba661c92e
--- /dev/null
+++ b/mit-pthreads/net/getnetbyaddr.c
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)getnetbyaddr.c 5.7 (Berkeley) 6/1/90";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <stdio.h>
+#include <netdb.h>
+#include "net_internal.h"
+
+struct netent *getnetbyaddr(long net, int type)
+{
+ char *buf = _net_buf();
+
+ if (!buf)
+ return NULL;
+ return getnetbyaddr_r(net, type, (struct netent *) buf,
+ buf + sizeof(struct netent), NET_BUFSIZE);
+}
+
+struct netent *getnetbyaddr_r(long net, int type, struct netent *result,
+ char *buf, int bufsize)
+{
+ pthread_mutex_lock(&net_iterate_lock);
+ setnetent(0);
+ while ((result = getnetent_r(result, buf, bufsize)) != NULL) {
+ if (result->n_addrtype == type && result->n_net == net)
+ break;
+ }
+ pthread_mutex_unlock(&net_iterate_lock);
+ return result;
+}
+
diff --git a/mit-pthreads/net/getnetbyname.c b/mit-pthreads/net/getnetbyname.c
new file mode 100644
index 00000000000..5b044ceb7a7
--- /dev/null
+++ b/mit-pthreads/net/getnetbyname.c
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)getnetbyname.c 5.7 (Berkeley) 2/24/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <netdb.h>
+#include <string.h>
+#include "net_internal.h"
+
+struct netent *getnetbyname(const char *name)
+{
+ char *buf = _net_buf();
+
+ if (!buf)
+ return NULL;
+ return getnetbyname_r(name, (struct netent *) buf,
+ buf + sizeof(struct netent), NET_BUFSIZE);
+}
+
+struct netent *getnetbyname_r(const char *name, struct netent *result,
+ char *buf, int bufsize)
+{
+ char **alias;
+
+ pthread_mutex_lock(&net_iterate_lock);
+ setnetent(0);
+ while ((result = getnetent_r(result, buf, bufsize)) != NULL) {
+ /* Check the entry's name and aliases against the given name. */
+ if (strcmp(result->n_name, name) == 0)
+ break;
+ for (alias = result->n_aliases; *alias != 0; alias++) {
+ if (strcmp(*alias, name) == 0)
+ break;
+ }
+ }
+ pthread_mutex_unlock(&net_iterate_lock);
+ return result;
+}
+
diff --git a/mit-pthreads/net/getnetent.c b/mit-pthreads/net/getnetent.c
new file mode 100644
index 00000000000..05af0b09159
--- /dev/null
+++ b/mit-pthreads/net/getnetent.c
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)getnetent.c 5.8 (Berkeley) 2/24/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <pthread.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include "net_internal.h"
+
+static pthread_mutex_t net_file_lock = PTHREAD_MUTEX_INITIALIZER;
+static int net_file_stayopen;
+static FILE *net_file;
+
+void setnetent(int stayopen)
+{
+ pthread_mutex_lock(&net_file_lock);
+ net_file_stayopen |= stayopen;
+ if (net_file)
+ rewind(net_file);
+ else
+ net_file = fopen(_PATH_NETWORKS, "r");
+ pthread_mutex_unlock(&net_file_lock);
+}
+
+void endnetent()
+{
+ pthread_mutex_lock(&net_file_lock);
+ if (net_file)
+ fclose(net_file);
+ pthread_mutex_unlock(&net_file_lock);
+}
+
+struct netent *getnetent()
+{
+ char *buf = _net_buf();
+
+ return getnetent_r((struct netent *) buf, buf + sizeof(struct netent),
+ NET_BUFSIZE);
+}
+
+struct netent *getnetent_r(struct netent *result, char *buf, int bufsize)
+{
+ char *p, *q, **alias;
+ int l;
+
+ errno = 0;
+ pthread_mutex_lock(&net_file_lock);
+ if (net_file == NULL && (net_file = fopen(_PATH_NETWORKS, "r")) == NULL) {
+ pthread_mutex_unlock(&net_file_lock);
+ return NULL;
+ }
+ while (fgets(buf, bufsize, net_file)) {
+ if (*buf == '#')
+ continue;
+ p = strpbrk(buf, "#\n");
+ if (p == NULL)
+ continue;
+ *p = '\0';
+ l = strlen(buf) + 1;
+ result->n_name = buf;
+ p = strpbrk(buf, " \t");
+ if (p == NULL)
+ continue;
+ *p++ = '\0';
+ while (*p == ' ' || *p == '\t')
+ p++;
+ q = strpbrk(p, " \t");
+ if (q != NULL)
+ *q++ = '\0';
+ if (SP(SP(buf, char, l), char *, 1) > buf + bufsize) {
+ errno = ERANGE;
+ break;
+ }
+ result->n_net = inet_network(p);
+ result->n_addrtype = AF_INET;
+ result->n_aliases = (char **) ALIGN(buf + l, char *);
+ alias = result->n_aliases;
+ if (q != NULL) {
+ p = q;
+ while (p && *p) {
+ if (*p == ' ' || *p == '\t') {
+ p++;
+ continue;
+ }
+ if ((char *) &alias[2] > buf + bufsize) {
+ errno = ERANGE;
+ break;
+ }
+ *alias++ = p;
+ p = strpbrk(p, " \t");
+ if (p != NULL)
+ *p++ = '\0';
+ }
+ if (p && *p)
+ break;
+ }
+ *alias = NULL;
+ pthread_mutex_unlock(&net_file_lock);
+ return result;
+ }
+
+ pthread_mutex_unlock(&net_file_lock);
+ return NULL;
+}
+
diff --git a/mit-pthreads/net/getproto.c b/mit-pthreads/net/getproto.c
new file mode 100644
index 00000000000..f6313bf1510
--- /dev/null
+++ b/mit-pthreads/net/getproto.c
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)getproto.c 5.6 (Berkeley) 6/1/90";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <stdio.h>
+#include <netdb.h>
+#include "proto_internal.h"
+
+struct protoent *getprotobynumber(int proto)
+{
+ char *buf = _proto_buf();
+
+ if (!buf)
+ return NULL;
+ return getprotobynumber_r(proto, (struct protoent *) buf,
+ buf + sizeof(struct protoent), PROTO_BUFSIZE);
+}
+
+struct protoent *getprotobynumber_r(int proto, struct protoent *result,
+ char *buf, int bufsize)
+{
+ pthread_mutex_lock(&proto_iterate_lock);
+ setprotoent(0);
+ while ((result = getprotoent_r(result, buf, bufsize)) != NULL) {
+ if (result->p_proto == proto)
+ break;
+ }
+ pthread_mutex_unlock(&proto_iterate_lock);
+ return result;
+}
+
diff --git a/mit-pthreads/net/getprotoent.c b/mit-pthreads/net/getprotoent.c
new file mode 100644
index 00000000000..8bd8d95ec14
--- /dev/null
+++ b/mit-pthreads/net/getprotoent.c
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)getprotoent.c 5.8 (Berkeley) 2/24/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <pthread.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include "proto_internal.h"
+
+static pthread_mutex_t proto_file_lock = PTHREAD_MUTEX_INITIALIZER;
+static int proto_file_stayopen;
+static FILE *proto_file;
+
+void setprotoent(int stayopen)
+{
+ pthread_mutex_lock(&proto_file_lock);
+ proto_file_stayopen |= stayopen;
+ if (proto_file)
+ rewind(proto_file);
+ else
+ proto_file = fopen(_PATH_PROTOCOLS, "r");
+ pthread_mutex_unlock(&proto_file_lock);
+}
+
+void endprotoent()
+{
+ pthread_mutex_lock(&proto_file_lock);
+ if (proto_file)
+ fclose(proto_file);
+ pthread_mutex_unlock(&proto_file_lock);
+}
+
+struct protoent *getprotoent()
+{
+ char *buf = _proto_buf();
+
+ return getprotoent_r((struct protoent *) buf,
+ buf + sizeof(struct protoent), PROTO_BUFSIZE);
+}
+
+struct protoent *getprotoent_r(struct protoent *result, char *buf, int bufsize)
+{
+ char *p, *q, **alias;
+ int l;
+
+ errno = 0;
+ pthread_mutex_lock(&proto_file_lock);
+ if (proto_file == NULL && !(proto_file = fopen(_PATH_PROTOCOLS, "r"))) {
+ pthread_mutex_unlock(&proto_file_lock);
+ return NULL;
+ }
+ while (fgets(buf, bufsize, proto_file)) {
+ if (*buf == '#')
+ continue;
+ p = strpbrk(buf, "#\n");
+ if (p == NULL)
+ continue;
+ *p = '\0';
+ l = strlen(buf) + 1;
+ result->p_name = buf;
+ p = strpbrk(buf, " \t");
+ if (p == NULL)
+ continue;
+ *p++ = '\0';
+ while (*p == ' ' || *p == '\t')
+ p++;
+ q = strpbrk(p, " \t");
+ if (q != NULL)
+ *q++ = '\0';
+ if (SP(SP(buf, char, l), char *, 1) > buf + bufsize) {
+ errno = ERANGE;
+ break;
+ }
+ result->p_proto = atoi(p);
+ result->p_aliases = (char **) ALIGN(buf + l, char *);
+ alias = result->p_aliases;
+ if (q != NULL) {
+ p = q;
+ while (p && *p) {
+ if (*p == ' ' || *p == '\t') {
+ p++;
+ continue;
+ }
+ if ((char *) &alias[2] > buf + bufsize) {
+ errno = ERANGE;
+ break;
+ }
+ *alias++ = p;
+ p = strpbrk(p, " \t");
+ if (p != NULL)
+ *p++ = '\0';
+ }
+ if (p && *p)
+ break;
+ }
+ *alias = NULL;
+ pthread_mutex_unlock(&proto_file_lock);
+ return result;
+ }
+
+ pthread_mutex_unlock(&proto_file_lock);
+ return NULL;
+}
+
diff --git a/mit-pthreads/net/getprotoname.c b/mit-pthreads/net/getprotoname.c
new file mode 100644
index 00000000000..7bd7b925091
--- /dev/null
+++ b/mit-pthreads/net/getprotoname.c
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)getprotoname.c 5.7 (Berkeley) 2/24/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <pthread.h>
+#include <netdb.h>
+#include <string.h>
+#include "proto_internal.h"
+
+struct protoent *getprotobyname(const char *name)
+{
+ char *buf = _proto_buf();
+
+ if (!buf)
+ return NULL;
+ return getprotobyname_r(name, (struct protoent *) buf,
+ buf + sizeof(struct protoent), PROTO_BUFSIZE);
+}
+
+struct protoent *getprotobyname_r(const char *name, struct protoent *result,
+ char *buf, int bufsize)
+{
+ char **alias;
+
+ pthread_mutex_lock(&proto_iterate_lock);
+ setprotoent(0);
+ while ((result = getprotoent_r(result, buf, bufsize)) != NULL) {
+ /* Check the entry's name and aliases against the given name. */
+ if (strcmp(result->p_name, name) == 0)
+ break;
+ for (alias = result->p_aliases; *alias != 0; alias++) {
+ if (strcmp(*alias, name) == 0)
+ break;
+ }
+ }
+ pthread_mutex_unlock(&proto_iterate_lock);
+ return result;
+}
+
diff --git a/mit-pthreads/net/getservbyname.c b/mit-pthreads/net/getservbyname.c
new file mode 100644
index 00000000000..f482b544fd0
--- /dev/null
+++ b/mit-pthreads/net/getservbyname.c
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)getservbyname.c 5.7 (Berkeley) 2/24/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <netdb.h>
+#include <string.h>
+#include "serv_internal.h"
+
+struct servent *getservbyname(const char *name, const char *proto)
+{
+ char *buf = _serv_buf();
+
+ if (!buf)
+ return NULL;
+ return getservbyname_r(name, proto, (struct servent *) buf,
+ buf + sizeof(struct servent), SERV_BUFSIZE);
+}
+
+struct servent *getservbyname_r(const char *name, const char *proto,
+ struct servent *result, char *buf, int bufsize)
+{
+ char **alias;
+
+ pthread_mutex_lock(&serv_iterate_lock);
+ setservent(0);
+ while ((result = getservent_r(result, buf, bufsize)) != NULL) {
+ /* Check the entry's name and aliases against the given name. */
+ if (strcmp(result->s_name, name) != 0) {
+ for (alias = result->s_aliases; *alias != NULL; alias++) {
+ if (strcmp(*alias, name) == 0)
+ break;
+ }
+ if (*alias == NULL)
+ continue;
+ }
+ if (proto == NULL || strcmp(result->s_proto, proto) == 0)
+ break;
+ }
+ pthread_mutex_unlock(&serv_iterate_lock);
+ return result;
+}
+
diff --git a/mit-pthreads/net/getservbyport.c b/mit-pthreads/net/getservbyport.c
new file mode 100644
index 00000000000..e3418212c0b
--- /dev/null
+++ b/mit-pthreads/net/getservbyport.c
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)getservbyport.c 5.7 (Berkeley) 2/24/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <stdio.h>
+#include <netdb.h>
+#include <string.h>
+#include "serv_internal.h"
+
+struct servent *getservbyport(int port, const char *proto)
+{
+ char *buf = _serv_buf();
+
+ if (!buf)
+ return NULL;
+ return getservbyport_r(port, proto, (struct servent *) buf,
+ buf + sizeof(struct servent), SERV_BUFSIZE);
+}
+
+struct servent *getservbyport_r(int port, const char *proto,
+ struct servent *result, char *buf, int bufsize)
+{
+ pthread_mutex_lock(&serv_iterate_lock);
+ setservent(0);
+ while ((result = getservent_r(result, buf, bufsize)) != NULL) {
+ if (result->s_port != port)
+ continue;
+ if (proto == NULL || strcmp(result->s_proto, proto) == 0)
+ break;
+ }
+ pthread_mutex_unlock(&serv_iterate_lock);
+ return result;
+}
+
diff --git a/mit-pthreads/net/getservent.c b/mit-pthreads/net/getservent.c
new file mode 100644
index 00000000000..b0a7e039f69
--- /dev/null
+++ b/mit-pthreads/net/getservent.c
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)getservent.c 5.9 (Berkeley) 2/24/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <pthread.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include "serv_internal.h"
+
+static pthread_mutex_t serv_file_lock = PTHREAD_MUTEX_INITIALIZER;
+static int serv_file_stayopen=0;
+static FILE *serv_file=NULL;
+
+void setservent(int stayopen)
+{
+ pthread_mutex_lock(&serv_file_lock);
+ serv_file_stayopen |= stayopen;
+ if (serv_file)
+ rewind(serv_file);
+ else
+ serv_file = fopen(_PATH_SERVICES, "r");
+ pthread_mutex_unlock(&serv_file_lock);
+}
+
+void endservent()
+{
+ pthread_mutex_lock(&serv_file_lock);
+ if (serv_file)
+ {
+ fclose(serv_file);
+ serv_file=NULL;
+ }
+ pthread_mutex_unlock(&serv_file_lock);
+}
+
+struct servent *getservent()
+{
+ char *buf = _serv_buf();
+
+ return getservent_r((struct servent *) buf, buf + sizeof(struct servent),
+ SERV_BUFSIZE);
+}
+
+struct servent *getservent_r(struct servent *result, char *buf, int bufsize)
+{
+ char *p, *q, **alias;
+ int l;
+
+ errno = 0;
+ pthread_mutex_lock(&serv_file_lock);
+ if (serv_file == NULL && !(serv_file = fopen(_PATH_SERVICES, "r"))) {
+ pthread_mutex_unlock(&serv_file_lock);
+ return NULL;
+ }
+ while (fgets(buf, bufsize, serv_file)) {
+ if (*buf == '#')
+ continue;
+ p = strpbrk(buf, "#\n");
+ if (p == NULL)
+ continue;
+ *p = '\0';
+ l = strlen(buf) + 1;
+ result->s_name = buf;
+ q = strpbrk(buf, " \t");
+ if (q == NULL)
+ continue;
+ *q++ = '\0';
+ while (*q == ' ' || *q == '\t')
+ q++;
+ p = strpbrk(q, ",/");
+ if (p == NULL)
+ continue;
+ *p++ = '\0';
+ if (SP(SP(buf, char, l), char *, 1) > buf + bufsize) {
+ errno = ERANGE;
+ break;
+ }
+ result->s_port = htons((u_short)atoi(q));
+ result->s_proto = p;
+ result->s_aliases = (char **) ALIGN(buf + l, char *);
+ alias = result->s_aliases;
+ p = strpbrk(p, " \t");
+ if (p != NULL)
+ *p++ = '\0';
+ while (p && *p) {
+ if (*p == ' ' || *p == '\t') {
+ p++;
+ continue;
+ }
+ if ((char *) &alias[2] > buf + bufsize) {
+ errno = ERANGE;
+ break;
+ }
+ *alias++ = p;
+ p = strpbrk(p, " \t");
+ if (p != NULL)
+ *p++ = '\0';
+ }
+ *alias = NULL;
+ pthread_mutex_unlock(&serv_file_lock);
+ return result;
+ }
+
+ pthread_mutex_unlock(&serv_file_lock);
+ return NULL;
+}
+
diff --git a/mit-pthreads/net/herror.c b/mit-pthreads/net/herror.c
new file mode 100644
index 00000000000..935c8e7ea38
--- /dev/null
+++ b/mit-pthreads/net/herror.c
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 1987 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)herror.c 6.6 (Berkeley) 2/24/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <netdb.h>
+#include <unistd.h>
+#include <string.h>
+#include <resolv.h>
+
+char *h_errlist[] = {
+ "Error 0",
+ "Unknown host", /* 1 HOST_NOT_FOUND */
+ "Host name lookup failure", /* 2 TRY_AGAIN */
+ "Unknown server error", /* 3 NO_RECOVERY */
+ "No address associated with name", /* 4 NO_ADDRESS */
+};
+int h_nerr = { sizeof(h_errlist)/sizeof(h_errlist[0]) };
+
+/*
+ * herror --
+ * print the error indicated by the h_errno value.
+ */
+void
+herror(s)
+ const char *s;
+{
+ struct iovec iov[4];
+ register struct iovec *v = iov;
+ int error = h_errno;
+
+ if (s && *s) {
+ v->iov_base = (char *)s;
+ v->iov_len = strlen(s);
+ v++;
+ v->iov_base = ": ";
+ v->iov_len = 2;
+ v++;
+ }
+ v->iov_base = ((unsigned int)(error) < h_nerr) ?
+ h_errlist[error] : "Unknown error";
+ v->iov_len = strlen(v->iov_base);
+ v++;
+ v->iov_base = "\n";
+ v->iov_len = 1;
+ writev(STDERR_FILENO, iov, (v - iov) + 1);
+}
+
+char *
+hstrerror(err)
+ int err;
+{
+ return ((unsigned int)(err) < h_nerr) ? h_errlist[err]
+ : "Unknown resolver error";
+}
+
diff --git a/mit-pthreads/net/inet_addr.c b/mit-pthreads/net/inet_addr.c
new file mode 100644
index 00000000000..75ca154d4c2
--- /dev/null
+++ b/mit-pthreads/net/inet_addr.c
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 1983, 1990 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)inet_addr.c 5.10 (Berkeley) 2/24/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <pthread.h>
+#include <sys/param.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <ctype.h>
+
+#ifndef INADDR_NONE
+#define INADDR_NONE 0xffffffff
+#endif
+/*
+ * Ascii internet address interpretation routine.
+ * The value returned is in network order.
+ */
+pthread_ipaddr_type
+inet_addr(cp)
+ register const char *cp;
+{
+ struct in_addr val;
+
+ if (inet_aton(cp, &val))
+ return (val.s_addr);
+ return (INADDR_NONE);
+}
+
+/*
+ * Check whether "cp" is a valid ascii representation
+ * of an Internet address and convert to a binary address.
+ * Returns 1 if the address is valid, 0 if not.
+ * This replaces inet_addr, the return value from which
+ * cannot distinguish between failure and a local broadcast address.
+ */
+
+inet_aton(cp, addr)
+ const register char *cp;
+ struct in_addr *addr;
+{
+ pthread_ipaddr_type parts[4], *pp = parts;
+ pthread_ipaddr_type val, base, n;
+ register char c;
+
+ for (;;) {
+ /*
+ * Collect number up to ``.''.
+ * Values are specified as for C:
+ * 0x=hex, 0=octal, other=decimal.
+ */
+ val = 0; base = 10;
+ if (*cp == '0') {
+ if (*++cp == 'x' || *cp == 'X')
+ base = 16, cp++;
+ else
+ base = 8;
+ }
+ while ((c = *cp) != '\0') {
+ if (isascii(c) && isdigit(c)) {
+ val = (val * base) + (c - '0');
+ cp++;
+ continue;
+ }
+ if (base == 16 && isascii(c) && isxdigit(c)) {
+ val = (val << 4) +
+ (c + 10 - (islower(c) ? 'a' : 'A'));
+ cp++;
+ continue;
+ }
+ break;
+ }
+ if (*cp == '.') {
+ /*
+ * Internet format:
+ * a.b.c.d
+ * a.b.c (with c treated as 16-bits)
+ * a.b (with b treated as 24 bits)
+ */
+ if (pp >= parts + 3 || val > 0xff)
+ return (0);
+ *pp++ = val, cp++;
+ } else
+ break;
+ }
+ /*
+ * Check for trailing characters.
+ */
+ if (*cp && (!isascii(*cp) || !isspace(*cp)))
+ return (0);
+ /*
+ * Concoct the address according to
+ * the number of parts specified.
+ */
+ n = pp - parts + 1;
+ switch (n) {
+
+ case 1: /* a -- 32 bits */
+ break;
+
+ case 2: /* a.b -- 8.24 bits */
+ if (val > 0xffffff)
+ return (0);
+ val |= parts[0] << 24;
+ break;
+
+ case 3: /* a.b.c -- 8.8.16 bits */
+ if (val > 0xffff)
+ return (0);
+ val |= (parts[0] << 24) | (parts[1] << 16);
+ break;
+
+ case 4: /* a.b.c.d -- 8.8.8.8 bits */
+ if (val > 0xff)
+ return (0);
+ val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8);
+ break;
+ }
+ if (addr)
+ addr->s_addr = htonl(val);
+ return (1);
+}
+
diff --git a/mit-pthreads/net/inet_lnaof.c b/mit-pthreads/net/inet_lnaof.c
new file mode 100644
index 00000000000..752a5f03f79
--- /dev/null
+++ b/mit-pthreads/net/inet_lnaof.c
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)inet_lnaof.c 5.7 (Berkeley) 2/24/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <pthread.h>
+#include <sys/param.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+/*
+ * Return the local network address portion of an
+ * internet address; handles class a/b/c network
+ * number formats.
+ */
+pthread_ipaddr_type
+inet_lnaof(in)
+ struct in_addr in;
+{
+ register pthread_ipaddr_type i = ntohl(in.s_addr);
+
+ if (IN_CLASSA(i))
+ return ((i)&IN_CLASSA_HOST);
+ else if (IN_CLASSB(i))
+ return ((i)&IN_CLASSB_HOST);
+ else
+ return ((i)&IN_CLASSC_HOST);
+}
diff --git a/mit-pthreads/net/inet_makeaddr.c b/mit-pthreads/net/inet_makeaddr.c
new file mode 100644
index 00000000000..a4995e2b4c4
--- /dev/null
+++ b/mit-pthreads/net/inet_makeaddr.c
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)inet_makeaddr.c 5.6 (Berkeley) 2/24/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <pthread.h>
+#include <sys/param.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+/*
+ * Formulate an Internet address from network + host. Used in
+ * building addresses stored in the ifnet structure.
+ */
+struct in_addr
+inet_makeaddr(net, host)
+ pthread_ipaddr_type net, host;
+{
+ pthread_ipaddr_type addr;
+
+ if (net < 128)
+ addr = (net << IN_CLASSA_NSHIFT) | (host & IN_CLASSA_HOST);
+ else if (net < 65536)
+ addr = (net << IN_CLASSB_NSHIFT) | (host & IN_CLASSB_HOST);
+ else if (net < 16777216L)
+ addr = (net << IN_CLASSC_NSHIFT) | (host & IN_CLASSC_HOST);
+ else
+ addr = net | host;
+ addr = htonl(addr);
+ return (*(struct in_addr *)&addr);
+}
diff --git a/mit-pthreads/net/inet_netof.c b/mit-pthreads/net/inet_netof.c
new file mode 100644
index 00000000000..40d3f4c3385
--- /dev/null
+++ b/mit-pthreads/net/inet_netof.c
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)inet_netof.c 5.7 (Berkeley) 2/24/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <pthread.h>
+#include <sys/param.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+/*
+ * Return the network number from an internet
+ * address; handles class a/b/c network #'s.
+ */
+pthread_ipaddr_type
+inet_netof(in)
+ struct in_addr in;
+{
+ register pthread_ipaddr_type i = ntohl(in.s_addr);
+
+ if (IN_CLASSA(i))
+ return (((i)&IN_CLASSA_NET) >> IN_CLASSA_NSHIFT);
+ else if (IN_CLASSB(i))
+ return (((i)&IN_CLASSB_NET) >> IN_CLASSB_NSHIFT);
+ else
+ return (((i)&IN_CLASSC_NET) >> IN_CLASSC_NSHIFT);
+}
diff --git a/mit-pthreads/net/inet_network.c b/mit-pthreads/net/inet_network.c
new file mode 100644
index 00000000000..cc0f1b4e603
--- /dev/null
+++ b/mit-pthreads/net/inet_network.c
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)inet_network.c 5.8 (Berkeley) 2/24/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <pthread.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <ctype.h>
+
+#ifndef INADDR_NONE
+#define INADDR_NONE 0xffffffff
+#endif
+/*
+ * Internet network address interpretation routine.
+ * The library routines call this routine to interpret
+ * network numbers.
+ */
+pthread_ipaddr_type
+inet_network(cp)
+ register const char *cp;
+{
+ pthread_ipaddr_type parts[4], *pp = parts;
+ pthread_ipaddr_type val, base, n;
+ register char c;
+ register int i;
+
+again:
+ val = 0; base = 10;
+ if (*cp == '0')
+ base = 8, cp++;
+ if (*cp == 'x' || *cp == 'X')
+ base = 16, cp++;
+ while (c = *cp) {
+ if (isdigit(c)) {
+ val = (val * base) + (c - '0');
+ cp++;
+ continue;
+ }
+ if (base == 16 && isxdigit(c)) {
+ val = (val << 4) + (c + 10 - (islower(c) ? 'a' : 'A'));
+ cp++;
+ continue;
+ }
+ break;
+ }
+ if (*cp == '.') {
+ if (pp >= parts + 4)
+ return (INADDR_NONE);
+ *pp++ = val, cp++;
+ goto again;
+ }
+ if (*cp && !isspace(*cp))
+ return (INADDR_NONE);
+ *pp++ = val;
+ n = pp - parts;
+ if (n > 4)
+ return (INADDR_NONE);
+ for (val = 0, i = 0; i < n; i++) {
+ val <<= 8;
+ val |= parts[i] & 0xff;
+ }
+ return (val);
+}
diff --git a/mit-pthreads/net/inet_ntoa.c b/mit-pthreads/net/inet_ntoa.c
new file mode 100644
index 00000000000..cd206afcf2a
--- /dev/null
+++ b/mit-pthreads/net/inet_ntoa.c
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)inet_ntoa.c 5.6 (Berkeley) 2/24/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+/*
+ * Convert network-format internet address
+ * to base 256 d.d.d.d representation.
+ */
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+char *inet_ntoa(struct in_addr in)
+{
+ static pthread_mutex_t inet_ntoa_mutex = PTHREAD_MUTEX_INITIALIZER;
+ static pthread_key_t inet_ntoa_key = -1;
+ char *buf, *inet_ntoa_r();
+
+ if (inet_ntoa_key < 0) {
+ pthread_mutex_lock(&inet_ntoa_mutex);
+ if (inet_ntoa_key < 0) {
+ if (pthread_key_create(&inet_ntoa_key, free) < 0) {
+ pthread_mutex_unlock(&inet_ntoa_mutex);
+ return(NULL);
+ }
+ }
+ pthread_mutex_unlock(&inet_ntoa_mutex);
+ }
+ if ((buf = pthread_getspecific(inet_ntoa_key)) == NULL) {
+ if ((buf = (char *) malloc(18)) == NULL) {
+ return(NULL);
+ }
+ pthread_setspecific(inet_ntoa_key, buf);
+ }
+ return inet_ntoa_r(in, buf, 18);
+}
+
+char *inet_ntoa_r(struct in_addr in, char *buf, int bufsize)
+{
+ register char *p;
+
+ p = (char *)&in;
+#define UC(b) (((int)b)&0xff)
+ (void)snprintf(buf, bufsize,
+ "%d.%d.%d.%d", UC(p[0]), UC(p[1]), UC(p[2]), UC(p[3]));
+ return (buf);
+}
+
diff --git a/mit-pthreads/net/net_internal.c b/mit-pthreads/net/net_internal.c
new file mode 100644
index 00000000000..2c25ff76693
--- /dev/null
+++ b/mit-pthreads/net/net_internal.c
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 1985 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)net_internal.c 6.22 (Berkeley) 3/19/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "net_internal.h"
+
+static void _net_init_global(void);
+
+pthread_mutex_t net_iterate_lock = PTHREAD_MUTEX_INITIALIZER;
+static pthread_once_t init_once = PTHREAD_ONCE_INIT;
+static pthread_key_t key;
+static int init_status;
+
+/* Performs global initialization. */
+char *_net_buf()
+{
+ char *buf;
+
+ /* Make sure the global initializations have been done. */
+ pthread_once(&init_once, _net_init_global);
+
+ /* Initialize thread-specific data for this thread if it hasn't
+ * been done already. */
+ buf = (char *) pthread_getspecific(key);
+ if (!buf) {
+ buf = (char *) malloc(NET_BUFSIZE);
+ if (buf == NULL)
+ return NULL;
+ if (pthread_setspecific(key, buf) < 0) {
+ free(buf);
+ return NULL;
+ }
+ }
+ return buf;
+}
+
+static void _net_init_global()
+{
+ init_status = pthread_key_create(&key, free);
+}
+
diff --git a/mit-pthreads/net/net_internal.h b/mit-pthreads/net/net_internal.h
new file mode 100644
index 00000000000..10ece181a94
--- /dev/null
+++ b/mit-pthreads/net/net_internal.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 1985 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)net_internal.h 6.22 (Berkeley) 3/19/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#ifndef _NET_INTERNAL_H
+#define _NET_INTERNAL_H
+
+#include <pthread.h>
+#include <netdb.h>
+#include <resolv.h>
+
+#define NET_BUFSIZE 4096
+#define ALIGN(p, t) ((char *)(((((long)(p) - 1) / sizeof(t)) + 1) * sizeof(t)))
+#define SP(p, t, n) (ALIGN(p, t) + (n) * sizeof(t))
+
+extern pthread_mutex_t net_iterate_lock;
+
+__BEGIN_DECLS
+char *_net_buf(void);
+__END_DECLS
+
+#endif
+
diff --git a/mit-pthreads/net/proto_internal.c b/mit-pthreads/net/proto_internal.c
new file mode 100644
index 00000000000..db3ab04ec77
--- /dev/null
+++ b/mit-pthreads/net/proto_internal.c
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 1985 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)proto_internal.c 6.22 (Berkeley) 3/19/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "proto_internal.h"
+
+static void _proto_init_global(void);
+
+pthread_mutex_t proto_iterate_lock = PTHREAD_MUTEX_INITIALIZER;
+static pthread_once_t init_once = PTHREAD_ONCE_INIT;
+static pthread_key_t key;
+static int init_status;
+
+/* Performs global initialization. */
+char *_proto_buf()
+{
+ char *buf;
+
+ /* Make sure the global initializations have been done. */
+ pthread_once(&init_once, _proto_init_global);
+
+ /* Initialize thread-specific data for this thread if it hasn't
+ * been done already. */
+ buf = (char *) pthread_getspecific(key);
+ if (!buf) {
+ buf = (char *) malloc(PROTO_BUFSIZE);
+ if (buf == NULL)
+ return NULL;
+ if (pthread_setspecific(key, buf) < 0) {
+ free(buf);
+ return NULL;
+ }
+ }
+ return buf;
+}
+
+static void _proto_init_global()
+{
+ init_status = pthread_key_create(&key, free);
+}
+
diff --git a/mit-pthreads/net/proto_internal.h b/mit-pthreads/net/proto_internal.h
new file mode 100644
index 00000000000..d40f77b519e
--- /dev/null
+++ b/mit-pthreads/net/proto_internal.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 1985 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)proto_internal.h 6.22 (Berkeley) 3/19/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#ifndef _PROTO_INTERNAL_H
+#define _PROTO_INTERNAL_H
+
+#include <pthread.h>
+#include <netdb.h>
+#include <resolv.h>
+
+#define PROTO_BUFSIZE 4096
+#define ALIGN(p, t) ((char *)(((((long)(p) - 1) / sizeof(t)) + 1) * sizeof(t)))
+#define SP(p, t, n) (ALIGN(p, t) + (n) * sizeof(t))
+
+extern pthread_mutex_t proto_iterate_lock;
+
+__BEGIN_DECLS
+char *_proto_buf(void);
+__END_DECLS
+
+#endif
+
diff --git a/mit-pthreads/net/res_comp.c b/mit-pthreads/net/res_comp.c
new file mode 100644
index 00000000000..45a4bcafed2
--- /dev/null
+++ b/mit-pthreads/net/res_comp.c
@@ -0,0 +1,340 @@
+/*
+ * Copyright (c) 1985 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)res_comp.c 6.22 (Berkeley) 3/19/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <pthread.h>
+#include <sys/param.h>
+#include <sys/cdefs.h>
+#include <netinet/in.h>
+#include <resolv.h>
+#include <stdio.h>
+
+static dn_find();
+
+/*
+ * Expand compressed domain name 'comp_dn' to full domain name.
+ * 'msg' is a pointer to the begining of the message,
+ * 'eomorig' points to the first location after the message,
+ * 'exp_dn' is a pointer to a buffer of size 'length' for the result.
+ * Return size of compressed name or -1 if there was an error.
+ */
+dn_expand(msg, eomorig, comp_dn, exp_dn, length)
+ const u_char *msg, *eomorig, *comp_dn;
+ u_char *exp_dn;
+ int length;
+{
+ register u_char *cp, *dn;
+ register int n, c;
+ u_char *eom;
+ int len = -1, checked = 0;
+
+ dn = exp_dn;
+ cp = (u_char *)comp_dn;
+ eom = exp_dn + length;
+ /*
+ * fetch next label in domain name
+ */
+ while (n = *cp++) {
+ /*
+ * Check for indirection
+ */
+ switch (n & INDIR_MASK) {
+ case 0:
+ if (dn != exp_dn) {
+ if (dn >= eom)
+ return (-1);
+ *dn++ = '.';
+ }
+ if (dn+n >= eom)
+ return (-1);
+ checked += n + 1;
+ while (--n >= 0) {
+ if ((c = *cp++) == '.') {
+ if (dn + n + 2 >= eom)
+ return (-1);
+ *dn++ = '\\';
+ }
+ *dn++ = c;
+ if (cp >= eomorig) /* out of range */
+ return(-1);
+ }
+ break;
+
+ case INDIR_MASK:
+ if (len < 0)
+ len = cp - comp_dn + 1;
+ cp = (u_char *)msg + (((n & 0x3f) << 8) | (*cp & 0xff));
+ if (cp < msg || cp >= eomorig) /* out of range */
+ return(-1);
+ checked += 2;
+ /*
+ * Check for loops in the compressed name;
+ * if we've looked at the whole message,
+ * there must be a loop.
+ */
+ if (checked >= eomorig - msg)
+ return (-1);
+ break;
+
+ default:
+ return (-1); /* flag error */
+ }
+ }
+ *dn = '\0';
+ if (len < 0)
+ len = cp - comp_dn;
+ return (len);
+}
+
+/*
+ * Compress domain name 'exp_dn' into 'comp_dn'.
+ * Return the size of the compressed name or -1.
+ * 'length' is the size of the array pointed to by 'comp_dn'.
+ * 'dnptrs' is a list of pointers to previous compressed names. dnptrs[0]
+ * is a pointer to the beginning of the message. The list ends with NULL.
+ * 'lastdnptr' is a pointer to the end of the arrary pointed to
+ * by 'dnptrs'. Side effect is to update the list of pointers for
+ * labels inserted into the message as we compress the name.
+ * If 'dnptr' is NULL, we don't try to compress names. If 'lastdnptr'
+ * is NULL, we don't update the list.
+ */
+dn_comp(exp_dn, comp_dn, length, dnptrs, lastdnptr)
+ const u_char *exp_dn;
+ u_char *comp_dn, **dnptrs, **lastdnptr;
+ int length;
+{
+ register u_char *cp, *dn;
+ register int c, l;
+ u_char **cpp, **lpp, *sp, *eob;
+ u_char *msg;
+
+ dn = (u_char *)exp_dn;
+ cp = comp_dn;
+ eob = cp + length;
+ if (dnptrs != NULL) {
+ if ((msg = *dnptrs++) != NULL) {
+ for (cpp = dnptrs; *cpp != NULL; cpp++)
+ ;
+ lpp = cpp; /* end of list to search */
+ }
+ } else
+ msg = NULL;
+ for (c = *dn++; c != '\0'; ) {
+ /* look to see if we can use pointers */
+ if (msg != NULL) {
+ if ((l = dn_find(dn-1, msg, dnptrs, lpp)) >= 0) {
+ if (cp+1 >= eob)
+ return (-1);
+ *cp++ = (l >> 8) | INDIR_MASK;
+ *cp++ = l % 256;
+ return (cp - comp_dn);
+ }
+ /* not found, save it */
+ if (lastdnptr != NULL && cpp < lastdnptr-1) {
+ *cpp++ = cp;
+ *cpp = NULL;
+ }
+ }
+ sp = cp++; /* save ptr to length byte */
+ do {
+ if (c == '.') {
+ c = *dn++;
+ break;
+ }
+ if (c == '\\') {
+ if ((c = *dn++) == '\0')
+ break;
+ }
+ if (cp >= eob) {
+ if (msg != NULL)
+ *lpp = NULL;
+ return (-1);
+ }
+ *cp++ = c;
+ } while ((c = *dn++) != '\0');
+ /* catch trailing '.'s but not '..' */
+ if ((l = cp - sp - 1) == 0 && c == '\0') {
+ cp--;
+ break;
+ }
+ if (l <= 0 || l > MAXLABEL) {
+ if (msg != NULL)
+ *lpp = NULL;
+ return (-1);
+ }
+ *sp = l;
+ }
+ if (cp >= eob) {
+ if (msg != NULL)
+ *lpp = NULL;
+ return (-1);
+ }
+ *cp++ = '\0';
+ return (cp - comp_dn);
+}
+
+/*
+ * Skip over a compressed domain name. Return the size or -1.
+ */
+__dn_skipname(comp_dn, eom)
+ const u_char *comp_dn, *eom;
+{
+ register u_char *cp;
+ register int n;
+
+ cp = (u_char *)comp_dn;
+ while (cp < eom && (n = *cp++)) {
+ /*
+ * check for indirection
+ */
+ switch (n & INDIR_MASK) {
+ case 0: /* normal case, n == len */
+ cp += n;
+ continue;
+ case INDIR_MASK: /* indirection */
+ cp++;
+ break;
+ default: /* illegal type */
+ return (-1);
+ }
+ break;
+ }
+ if (cp > eom)
+ return -1;
+ return (cp - comp_dn);
+}
+
+/*
+ * Search for expanded name from a list of previously compressed names.
+ * Return the offset from msg if found or -1.
+ * dnptrs is the pointer to the first name on the list,
+ * not the pointer to the start of the message.
+ */
+static int
+dn_find(exp_dn, msg, dnptrs, lastdnptr)
+ u_char *exp_dn, *msg;
+ u_char **dnptrs, **lastdnptr;
+{
+ register u_char *dn, *cp, **cpp;
+ register int n;
+ u_char *sp;
+
+ for (cpp = dnptrs; cpp < lastdnptr; cpp++) {
+ dn = exp_dn;
+ sp = cp = *cpp;
+ while (n = *cp++) {
+ /*
+ * check for indirection
+ */
+ switch (n & INDIR_MASK) {
+ case 0: /* normal case, n == len */
+ while (--n >= 0) {
+ if (*dn == '.')
+ goto next;
+ if (*dn == '\\')
+ dn++;
+ if (*dn++ != *cp++)
+ goto next;
+ }
+ if ((n = *dn++) == '\0' && *cp == '\0')
+ return (sp - msg);
+ if (n == '.')
+ continue;
+ goto next;
+
+ default: /* illegal type */
+ return (-1);
+
+ case INDIR_MASK: /* indirection */
+ cp = msg + (((n & 0x3f) << 8) | *cp);
+ }
+ }
+ if (*dn == '\0')
+ return (sp - msg);
+ next: ;
+ }
+ return (-1);
+}
+
+/*
+ * Routines to insert/extract short/long's. Must account for byte
+ * order and non-alignment problems. This code at least has the
+ * advantage of being portable.
+ *
+ * used by sendmail.
+ */
+
+u_short
+_getshort(msgp)
+ register const u_char *msgp;
+{
+ register u_short u;
+
+ GETSHORT(u, msgp);
+ return (u);
+}
+
+pthread_ipaddr_type
+_getlong(msgp)
+ const u_char *msgp;
+{
+ pthread_ipaddr_type u;
+
+ GETLONG(u, msgp);
+ return (u);
+}
+
+void
+#ifdef __STDC__
+__putshort(register u_short s, register u_char *msgp)
+#else
+ __putshort(s, msgp)
+ register u_short s;
+ register u_char *msgp;
+#endif
+{
+ PUTSHORT(s, msgp);
+}
+
+void
+__putlong(l, msgp)
+ register pthread_ipaddr_type l;
+ register u_char *msgp;
+{
+ PUTLONG(l, msgp);
+}
+
diff --git a/mit-pthreads/net/res_debug.c b/mit-pthreads/net/res_debug.c
new file mode 100644
index 00000000000..3e2084fccf8
--- /dev/null
+++ b/mit-pthreads/net/res_debug.c
@@ -0,0 +1,749 @@
+/*
+ * Copyright (c) 1985, 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Portions Copyright (c) 1993 by Digital Equipment Corporation.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies, and that
+ * the name of Digital Equipment Corporation not be used in advertising or
+ * publicity pertaining to distribution of the document or software without
+ * specific, written prior permission.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
+ * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)res_debug.c 8.1 (Berkeley) 6/4/93";
+static char rcsid[] = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <pthread.h>
+#include <sys/param.h>
+#include <stdio.h>
+#include <string.h>
+#include <resolv.h>
+#include <arpa/inet.h>
+
+void __fp_query();
+char *__p_class(), *__p_time(), *__p_type();
+char *p_cdname(), *p_fqname(), *p_rr();
+static char *p_option __P_((u_long));
+
+char *_res_opcodes[] = {
+ "QUERY",
+ "IQUERY",
+ "CQUERYM",
+ "CQUERYU",
+ "4",
+ "5",
+ "6",
+ "7",
+ "8",
+ "UPDATEA",
+ "UPDATED",
+ "UPDATEDA",
+ "UPDATEM",
+ "UPDATEMA",
+ "ZONEINIT",
+ "ZONEREF",
+};
+
+char *_res_resultcodes[] = {
+ "NOERROR",
+ "FORMERR",
+ "SERVFAIL",
+ "NXDOMAIN",
+ "NOTIMP",
+ "REFUSED",
+ "6",
+ "7",
+ "8",
+ "9",
+ "10",
+ "11",
+ "12",
+ "13",
+ "14",
+ "NOCHANGE",
+};
+
+static char retbuf[16];
+
+static char *
+dewks(wks)
+ int wks;
+{
+ switch (wks) {
+ case 5: return("rje");
+ case 7: return("echo");
+ case 9: return("discard");
+ case 11: return("systat");
+ case 13: return("daytime");
+ case 15: return("netstat");
+ case 17: return("qotd");
+ case 19: return("chargen");
+ case 20: return("ftp-data");
+ case 21: return("ftp");
+ case 23: return("telnet");
+ case 25: return("smtp");
+ case 37: return("time");
+ case 39: return("rlp");
+ case 42: return("name");
+ case 43: return("whois");
+ case 53: return("domain");
+ case 57: return("apts");
+ case 59: return("apfs");
+ case 67: return("bootps");
+ case 68: return("bootpc");
+ case 69: return("tftp");
+ case 77: return("rje");
+ case 79: return("finger");
+ case 87: return("link");
+ case 95: return("supdup");
+ case 100: return("newacct");
+ case 101: return("hostnames");
+ case 102: return("iso-tsap");
+ case 103: return("x400");
+ case 104: return("x400-snd");
+ case 105: return("csnet-ns");
+ case 109: return("pop-2");
+ case 111: return("sunrpc");
+ case 113: return("auth");
+ case 115: return("sftp");
+ case 117: return("uucp-path");
+ case 119: return("nntp");
+ case 121: return("erpc");
+ case 123: return("ntp");
+ case 133: return("statsrv");
+ case 136: return("profile");
+ case 144: return("NeWS");
+ case 161: return("snmp");
+ case 162: return("snmp-trap");
+ case 170: return("print-srv");
+ default: (void) sprintf(retbuf, "%d", wks); return(retbuf);
+ }
+}
+
+static char *
+deproto(protonum)
+ int protonum;
+{
+ switch (protonum) {
+ case 1: return("icmp");
+ case 2: return("igmp");
+ case 3: return("ggp");
+ case 5: return("st");
+ case 6: return("tcp");
+ case 7: return("ucl");
+ case 8: return("egp");
+ case 9: return("igp");
+ case 11: return("nvp-II");
+ case 12: return("pup");
+ case 16: return("chaos");
+ case 17: return("udp");
+ default: (void) sprintf(retbuf, "%d", protonum); return(retbuf);
+ }
+}
+
+static char *
+do_rrset(msg, cp, cnt, pflag, file, hs)
+ int cnt, pflag;
+ char *cp,*msg, *hs;
+ FILE *file;
+{
+ int n;
+ int sflag;
+ /*
+ * Print answer records
+ */
+ sflag = (_res.pfcode & pflag);
+ if (n = ntohs(cnt)) {
+ if ((!_res.pfcode) || ((sflag) && (_res.pfcode & RES_PRF_HEAD1)))
+ fprintf(file, hs);
+ while (--n >= 0) {
+ cp = p_rr(cp, msg, file);
+ if ((cp-msg) > PACKETSZ)
+ return (NULL);
+ }
+ if ((!_res.pfcode) || ((sflag) && (_res.pfcode & RES_PRF_HEAD1)))
+ putc('\n', file);
+ }
+ return(cp);
+}
+
+__p_query(msg)
+ char *msg;
+{
+ __fp_query(msg, stdout);
+}
+
+/*
+ * Print the current options.
+ * This is intended to be primarily a debugging routine.
+ */
+void
+__fp_resstat(statp, file)
+ struct __res_state *statp;
+ FILE *file;
+{
+ int bit;
+
+ fprintf(file, ";; res options:");
+ if (!statp)
+ statp = &_res;
+ for (bit = 0; bit < 32; bit++) { /* XXX 32 - bad assumption! */
+ if (statp->options & (1<<bit))
+ fprintf(file, " %s", p_option(1<<bit));
+ }
+ putc('\n', file);
+}
+
+/*
+ * Print the contents of a query.
+ * This is intended to be primarily a debugging routine.
+ */
+void
+__fp_query(msg,file)
+ char *msg;
+ FILE *file;
+{
+ register char *cp;
+ register HEADER *hp;
+ register int n;
+
+ /*
+ * Print header fields.
+ */
+ hp = (HEADER *)msg;
+ cp = msg + sizeof(HEADER);
+ if ((!_res.pfcode) || (_res.pfcode & RES_PRF_HEADX) || hp->rcode) {
+ fprintf(file,";; ->>HEADER<<- opcode: %s, status: %s, id: %d",
+ _res_opcodes[hp->opcode],
+ _res_resultcodes[hp->rcode],
+ ntohs(hp->id));
+ putc('\n', file);
+ }
+ putc(';', file);
+ if ((!_res.pfcode) || (_res.pfcode & RES_PRF_HEAD2)) {
+ fprintf(file,"; flags:");
+ if (hp->qr)
+ fprintf(file," qr");
+ if (hp->aa)
+ fprintf(file," aa");
+ if (hp->tc)
+ fprintf(file," tc");
+ if (hp->rd)
+ fprintf(file," rd");
+ if (hp->ra)
+ fprintf(file," ra");
+ if (hp->pr)
+ fprintf(file," pr");
+ }
+ if ((!_res.pfcode) || (_res.pfcode & RES_PRF_HEAD1)) {
+ fprintf(file,"; Ques: %d", ntohs(hp->qdcount));
+ fprintf(file,", Ans: %d", ntohs(hp->ancount));
+ fprintf(file,", Auth: %d", ntohs(hp->nscount));
+ fprintf(file,", Addit: %d", ntohs(hp->arcount));
+ }
+#if 1
+ if ((!_res.pfcode) || (_res.pfcode &
+ (RES_PRF_HEADX | RES_PRF_HEAD2 | RES_PRF_HEAD1))) {
+ putc('\n',file);
+ }
+#endif
+ /*
+ * Print question records.
+ */
+ if (n = ntohs(hp->qdcount)) {
+ if ((!_res.pfcode) || (_res.pfcode & RES_PRF_QUES))
+ fprintf(file,";; QUESTIONS:\n");
+ while (--n >= 0) {
+ fprintf(file,";;\t");
+ cp = p_cdname(cp, msg, file);
+ if (cp == NULL)
+ return;
+ if ((!_res.pfcode) || (_res.pfcode & RES_PRF_QUES))
+ fprintf(file, ", type = %s",
+ __p_type(_getshort(cp)));
+ cp += sizeof(u_short);
+ if ((!_res.pfcode) || (_res.pfcode & RES_PRF_QUES))
+ fprintf(file, ", class = %s\n",
+ __p_class(_getshort(cp)));
+ cp += sizeof(u_short);
+ putc('\n', file);
+ }
+ }
+ /*
+ * Print authoritative answer records
+ */
+ cp = do_rrset(msg, cp, hp->ancount, RES_PRF_ANS, file,
+ ";; ANSWERS:\n");
+ if (cp == NULL)
+ return;
+
+ /*
+ * print name server records
+ */
+ cp = do_rrset(msg, cp, hp->nscount, RES_PRF_AUTH, file,
+ ";; AUTHORITY RECORDS:\n");
+ if (!cp)
+ return;
+
+ /*
+ * print additional records
+ */
+ cp = do_rrset(msg, cp, hp->arcount, RES_PRF_ADD, file,
+ ";; ADDITIONAL RECORDS:\n");
+ if (!cp)
+ return;
+}
+
+char *
+p_cdname(cp, msg, file)
+ char *cp, *msg;
+ FILE *file;
+{
+ char name[MAXDNAME];
+ int n;
+
+ if ((n = dn_expand((u_char *)msg, (u_char *)cp + MAXCDNAME,
+ (u_char *)cp, (u_char *)name, sizeof(name))) < 0)
+ return (NULL);
+ if (name[0] == '\0')
+ putc('.', file);
+ else
+ fputs(name, file);
+ return (cp + n);
+}
+
+char *
+p_fqname(cp, msg, file)
+ char *cp, *msg;
+ FILE *file;
+{
+ char name[MAXDNAME];
+ int n, len;
+
+ if ((n = dn_expand((u_char *)msg, (u_char *)cp + MAXCDNAME,
+ (u_char *)cp, (u_char *)name, sizeof(name))) < 0)
+ return (NULL);
+ if (name[0] == '\0') {
+ putc('.', file);
+ } else {
+ fputs(name, file);
+ if (name[strlen(name) - 1] != '.')
+ putc('.', file);
+ }
+ return (cp + n);
+}
+
+/*
+ * Print resource record fields in human readable form.
+ *
+ * Removed calls to non-reentrant routines to simplify varifying
+ * POSIX thread-safe implementations. (mevans).
+ */
+char *
+p_rr(cp, msg, file)
+ char *cp, *msg;
+ FILE *file;
+{
+ int type, class, dlen, n, c;
+ struct in_addr inaddr;
+ char *cp1, *cp2;
+ u_long tmpttl, t;
+ int lcnt;
+ char buf[32];
+
+ if ((cp = p_fqname(cp, msg, file)) == NULL)
+ return (NULL); /* compression error */
+ type = _getshort(cp);
+ cp += sizeof(u_short);
+ class = _getshort(cp);
+ cp += sizeof(u_short);
+ tmpttl = _getlong(cp);
+ cp += sizeof(u_long);
+ dlen = _getshort(cp);
+ cp += sizeof(u_short);
+ cp1 = cp;
+ if ((!_res.pfcode) || (_res.pfcode & RES_PRF_TTLID))
+ fprintf(file, "\t%lu", tmpttl);
+ if ((!_res.pfcode) || (_res.pfcode & RES_PRF_CLASS))
+ fprintf(file, "\t%s", __p_class(class));
+ fprintf(file, "\t%s", __p_type(type));
+ /*
+ * Print type specific data, if appropriate
+ */
+ switch (type) {
+ case T_A:
+ switch (class) {
+ case C_IN:
+ case C_HS:
+ bcopy(cp, (char *)&inaddr, sizeof(inaddr));
+ if (dlen == 4) {
+ fprintf(file,"\t%s",
+ inet_ntoa_r(inaddr, buf, sizeof(buf)));
+ cp += dlen;
+ } else if (dlen == 7) {
+ char *address;
+ u_char protocol;
+ u_short port;
+
+ address = inet_ntoa_r(inaddr,
+ buf, sizeof(buf));
+ cp += sizeof(inaddr);
+ protocol = *(u_char*)cp;
+ cp += sizeof(u_char);
+ port = _getshort(cp);
+ cp += sizeof(u_short);
+ fprintf(file, "\t%s\t; proto %d, port %d",
+ address, protocol, port);
+ }
+ break;
+ default:
+ cp += dlen;
+ }
+ break;
+ case T_CNAME:
+ case T_MB:
+ case T_MG:
+ case T_MR:
+ case T_NS:
+ case T_PTR:
+ putc('\t', file);
+ cp = p_fqname(cp, msg, file);
+ break;
+
+ case T_HINFO:
+ if (n = *cp++) {
+ fprintf(file,"\t%.*s", n, cp);
+ cp += n;
+ }
+ if (n = *cp++) {
+ fprintf(file,"\t%.*s", n, cp);
+ cp += n;
+ }
+ break;
+
+ case T_SOA:
+ putc('\t', file);
+ cp = p_fqname(cp, msg, file); /* origin */
+ putc(' ', file);
+ cp = p_fqname(cp, msg, file); /* mail addr */
+ fputs(" (\n", file);
+ t = _getlong(cp); cp += sizeof(u_long);
+ fprintf(file,"\t\t\t%lu\t; serial\n", t);
+ t = _getlong(cp); cp += sizeof(u_long);
+ fprintf(file,"\t\t\t%lu\t; refresh (%s)\n", t, __p_time(t));
+ t = _getlong(cp); cp += sizeof(u_long);
+ fprintf(file,"\t\t\t%lu\t; retry (%s)\n", t, __p_time(t));
+ t = _getlong(cp); cp += sizeof(u_long);
+ fprintf(file,"\t\t\t%lu\t; expire (%s)\n", t, __p_time(t));
+ t = _getlong(cp); cp += sizeof(u_long);
+ fprintf(file,"\t\t\t%lu )\t; minimum (%s)", t, __p_time(t));
+ break;
+
+ case T_MX:
+ case T_AFSDB:
+ fprintf(file,"\t%d ", _getshort(cp));
+ cp += sizeof(u_short);
+ cp = p_fqname(cp, msg, file);
+ break;
+
+ case T_TXT:
+ (void) fputs("\t\"", file);
+ cp2 = cp1 + dlen;
+ while (cp < cp2) {
+ if (n = (unsigned char) *cp++) {
+ for (c = n; c > 0 && cp < cp2; c--)
+ if (*cp == '\n') {
+ (void) putc('\\', file);
+ (void) putc(*cp++, file);
+ } else
+ (void) putc(*cp++, file);
+ }
+ }
+ putc('"', file);
+ break;
+
+ case T_MINFO:
+ case T_RP:
+ putc('\t', file);
+ cp = p_fqname(cp, msg, file);
+ putc(' ', file);
+ cp = p_fqname(cp, msg, file);
+ break;
+
+ case T_UINFO:
+ putc('\t', file);
+ fputs(cp, file);
+ cp += dlen;
+ break;
+
+ case T_UID:
+ case T_GID:
+ if (dlen == 4) {
+ fprintf(file,"\t%u", _getlong(cp));
+ cp += sizeof(long);
+ }
+ break;
+
+ case T_WKS:
+ if (dlen < sizeof(u_long) + 1)
+ break;
+ bcopy(cp, (char *)&inaddr, sizeof(inaddr));
+ cp += sizeof(u_long);
+ fprintf(file, "\t%s %s ( ",
+ inet_ntoa_r(inaddr, buf, sizeof(buf)),
+ deproto((int) *cp));
+ cp += sizeof(u_char);
+ n = 0;
+ lcnt = 0;
+ while (cp < cp1 + dlen) {
+ c = *cp++;
+ do {
+ if (c & 0200) {
+ if (lcnt == 0) {
+ fputs("\n\t\t\t", file);
+ lcnt = 5;
+ }
+ fputs(dewks(n), file);
+ putc(' ', file);
+ lcnt--;
+ }
+ c <<= 1;
+ } while (++n & 07);
+ }
+ putc(')', file);
+ break;
+
+#ifdef ALLOW_T_UNSPEC
+ case T_UNSPEC:
+ {
+ int NumBytes = 8;
+ char *DataPtr;
+ int i;
+
+ if (dlen < NumBytes) NumBytes = dlen;
+ fprintf(file, "\tFirst %d bytes of hex data:",
+ NumBytes);
+ for (i = 0, DataPtr = cp; i < NumBytes; i++, DataPtr++)
+ fprintf(file, " %x", *DataPtr);
+ cp += dlen;
+ }
+ break;
+#endif /* ALLOW_T_UNSPEC */
+
+ default:
+ fprintf(file,"\t?%d?", type);
+ cp += dlen;
+ }
+#if 0
+ fprintf(file, "\t; dlen=%d, ttl %s\n", dlen, __p_time(tmpttl));
+#else
+ putc('\n', file);
+#endif
+ if (cp - cp1 != dlen) {
+ fprintf(file,";; packet size error (found %d, dlen was %d)\n",
+ cp - cp1, dlen);
+ cp = NULL;
+ }
+ return (cp);
+}
+
+static char nbuf[40];
+
+/*
+ * Return a string for the type
+ */
+char *
+__p_type(type)
+ int type;
+{
+ switch (type) {
+ case T_A:
+ return("A");
+ case T_NS: /* authoritative server */
+ return("NS");
+ case T_CNAME: /* canonical name */
+ return("CNAME");
+ case T_SOA: /* start of authority zone */
+ return("SOA");
+ case T_MB: /* mailbox domain name */
+ return("MB");
+ case T_MG: /* mail group member */
+ return("MG");
+ case T_MR: /* mail rename name */
+ return("MR");
+ case T_NULL: /* null resource record */
+ return("NULL");
+ case T_WKS: /* well known service */
+ return("WKS");
+ case T_PTR: /* domain name pointer */
+ return("PTR");
+ case T_HINFO: /* host information */
+ return("HINFO");
+ case T_MINFO: /* mailbox information */
+ return("MINFO");
+ case T_MX: /* mail routing info */
+ return("MX");
+ case T_TXT: /* text */
+ return("TXT");
+ case T_RP: /* responsible person */
+ return("RP");
+ case T_AFSDB: /* AFS cell database */
+ return("AFSDB");
+ case T_AXFR: /* zone transfer */
+ return("AXFR");
+ case T_MAILB: /* mail box */
+ return("MAILB");
+ case T_MAILA: /* mail address */
+ return("MAILA");
+ case T_ANY: /* matches any type */
+ return("ANY");
+ case T_UINFO:
+ return("UINFO");
+ case T_UID:
+ return("UID");
+ case T_GID:
+ return("GID");
+#ifdef ALLOW_T_UNSPEC
+ case T_UNSPEC:
+ return("UNSPEC");
+#endif /* ALLOW_T_UNSPEC */
+
+ default:
+ (void)sprintf(nbuf, "%d", type);
+ return(nbuf);
+ }
+}
+
+/*
+ * Return a mnemonic for class
+ */
+char *
+__p_class(class)
+ int class;
+{
+
+ switch (class) {
+ case C_IN: /* internet class */
+ return("IN");
+ case C_HS: /* hesiod class */
+ return("HS");
+ case C_ANY: /* matches any class */
+ return("ANY");
+ default:
+ (void)sprintf(nbuf, "%d", class);
+ return(nbuf);
+ }
+}
+
+/*
+ * Return a mnemonic for an option
+ */
+static char *
+p_option(option)
+ u_long option;
+{
+ switch (option) {
+ case RES_INIT: return "init";
+ case RES_DEBUG: return "debug";
+ case RES_AAONLY: return "aaonly";
+ case RES_USEVC: return "usevc";
+ case RES_PRIMARY: return "primry";
+ case RES_IGNTC: return "igntc";
+ case RES_RECURSE: return "recurs";
+ case RES_DEFNAMES: return "defnam";
+ case RES_STAYOPEN: return "styopn";
+ case RES_DNSRCH: return "dnsrch";
+ default: sprintf(nbuf, "?0x%x?", option); return nbuf;
+ }
+}
+
+/*
+ * Return a mnemonic for a time to live
+ */
+char *
+__p_time(value)
+ u_long value;
+{
+ int secs, mins, hours, days;
+ register char *p;
+
+ if (value == 0) {
+ strcpy(nbuf, "0 secs");
+ return(nbuf);
+ }
+
+ secs = value % 60;
+ value /= 60;
+ mins = value % 60;
+ value /= 60;
+ hours = value % 24;
+ value /= 24;
+ days = value;
+ value = 0;
+
+#define PLURALIZE(x) x, (x == 1) ? "" : "s"
+ p = nbuf;
+ if (days) {
+ (void)sprintf(p, "%d day%s", PLURALIZE(days));
+ while (*++p);
+ }
+ if (hours) {
+ if (days)
+ *p++ = ' ';
+ (void)sprintf(p, "%d hour%s", PLURALIZE(hours));
+ while (*++p);
+ }
+ if (mins) {
+ if (days || hours)
+ *p++ = ' ';
+ (void)sprintf(p, "%d min%s", PLURALIZE(mins));
+ while (*++p);
+ }
+ if (secs || ! (days || hours || mins)) {
+ if (days || hours || mins)
+ *p++ = ' ';
+ (void)sprintf(p, "%d sec%s", PLURALIZE(secs));
+ }
+ return(nbuf);
+}
diff --git a/mit-pthreads/net/res_init.c b/mit-pthreads/net/res_init.c
new file mode 100644
index 00000000000..0a5c944c974
--- /dev/null
+++ b/mit-pthreads/net/res_init.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 1985 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)res_init.c 6.22 (Berkeley) 3/19/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <pthread.h>
+#include <resolv.h>
+#include <netdb.h>
+#include "res_internal.h"
+
+int res_init()
+{
+ if (_res_init()) {
+ return 0;
+ } else {
+ /* Due to clever tricks in _res_init(), a check for h_errno will
+ * return NO_RECOVERY even if the next try at initialization
+ * succeeds, so it's okay that we can't set an error value here. */
+ return -1;
+ }
+}
+
diff --git a/mit-pthreads/net/res_internal.c b/mit-pthreads/net/res_internal.c
new file mode 100644
index 00000000000..4eab65bf5aa
--- /dev/null
+++ b/mit-pthreads/net/res_internal.c
@@ -0,0 +1,576 @@
+/*
+ * Copyright (c) 1985 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)res_internal.c 6.22 (Berkeley) 3/19/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <resolv.h>
+#include <netdb.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <string.h>
+#include <errno.h>
+#include "res_internal.h"
+
+#define DEFAULT_RETRIES 4
+
+pthread_mutex_t host_iterate_lock = PTHREAD_MUTEX_INITIALIZER;
+static pthread_once_t init_once = PTHREAD_ONCE_INIT;
+static pthread_key_t key;
+static int init_status;
+
+static void _res_init_global(void);
+static void set_options(const char *options, const char *source);
+static pthread_ipaddr_type net_mask(struct in_addr in);
+static int qcomp(const void *arg1, const void *arg2);
+
+static struct __res_state start;
+/* We want to define _res for partial binary compatibility with libraries. */
+#undef _res
+struct __res_state _res = {
+ RES_TIMEOUT, /* retransmition time interval */
+ 4, /* number of times to retransmit */
+ RES_DEFAULT, /* options flags */
+ 1, /* number of name servers */
+};
+
+struct hostent *_res_parse_answer(querybuf *answer, int anslen, int iquery,
+ struct hostent *result, char *buf,
+ int bufsize, int *errval)
+{
+ struct res_data *data = _res_init();
+ register HEADER *hp;
+ register u_char *cp;
+ register int n;
+ u_char *eom;
+ char *aliases[__NETDB_MAXALIASES], *addrs[__NETDB_MAXADDRS];
+ char *bp = buf, **ap = aliases, **hap = addrs;
+ int type, class, ancount, qdcount, getclass = C_ANY, iquery_done = 0;
+
+ eom = answer->buf + anslen;
+ /*
+ * find first satisfactory answer
+ */
+ hp = &answer->hdr;
+ ancount = ntohs(hp->ancount);
+ qdcount = ntohs(hp->qdcount);
+ bp = buf;
+ cp = answer->buf + sizeof(HEADER);
+
+ /* Read in the hostname if this is an address lookup. */
+ if (qdcount) {
+ if (iquery) {
+ if ((n = dn_expand((u_char *) answer->buf,
+ (u_char *) eom, (u_char *) cp, (u_char *) bp,
+ bufsize - (bp - buf))) < 0) {
+ *errval = NO_RECOVERY;
+ return ((struct hostent *) NULL);
+ }
+ cp += n + QFIXEDSZ;
+ result->h_name = bp;
+ bp += strlen(bp) + 1;
+ } else {
+ cp += __dn_skipname(cp, eom) + QFIXEDSZ;
+ }
+ while (--qdcount > 0)
+ cp += __dn_skipname(cp, eom) + QFIXEDSZ;
+ } else if (iquery) {
+ *errval = (hp->aa) ? HOST_NOT_FOUND : TRY_AGAIN;
+ return ((struct hostent *) NULL);
+ }
+
+ /* Read in the answers. */
+ *ap = NULL;
+ *hap = NULL;
+ while (--ancount >= 0 && cp < eom) {
+ if ((n = dn_expand((u_char *) answer->buf, (u_char *) eom,
+ (u_char *) cp, (u_char *) bp,
+ bufsize - (bp - buf))) < 0)
+ break;
+ cp += n;
+ type = _getshort(cp);
+ cp += sizeof(u_short);
+ class = _getshort(cp);
+ cp += sizeof(u_short) + sizeof(pthread_ipaddr_type);
+ n = _getshort(cp);
+ cp += sizeof(u_short);
+ if (type == T_CNAME) {
+ cp += n;
+ if (ap >= aliases + __NETDB_MAXALIASES - 1)
+ continue;
+ *ap++ = bp;
+ bp += strlen(bp) + 1;
+ continue;
+ }
+ if (iquery && type == T_PTR) {
+ if ((n = dn_expand((u_char *) answer->buf, (u_char *) eom,
+ (u_char *) cp, (u_char *) bp,
+ bufsize - (bp - buf))) < 0)
+ break;
+ cp += n;
+ result->h_name = bp;
+ bp += strlen(bp) + 1;
+ iquery_done = 1;
+ break;
+ }
+ if (iquery || type != T_A) {
+#ifdef DEBUG_RESOLVER
+ if (data->state.options & RES_DEBUG)
+ printf("unexpected answer type %d, size %d\n",
+ type, n);
+#endif
+ cp += n;
+ continue;
+ }
+ if (hap > addrs) {
+ if (n != result->h_length) {
+ cp += n;
+ continue;
+ }
+ if (class != getclass) {
+ cp += n;
+ continue;
+ }
+ } else {
+ result->h_length = n;
+ getclass = class;
+ result->h_addrtype = (class == C_IN) ? AF_INET : AF_UNSPEC;
+ if (!iquery) {
+ result->h_name = bp;
+ bp += strlen(bp) + 1;
+ }
+ }
+ bp = ALIGN(bp, pthread_ipaddr_type);
+ if (bp + n >= buf + bufsize) {
+ errno = ERANGE;
+ return NULL;
+ }
+ memcpy(bp, cp, n);
+ cp += n;
+ if (hap >= addrs + __NETDB_MAXADDRS - 1)
+ continue;
+ *hap++ = bp;
+ bp += n;
+ cp += n;
+ }
+
+ if (hap > addrs || iquery_done) {
+ *ap++ = NULL;
+ *hap++ = NULL;
+ if (data->state.nsort)
+ qsort(addrs, hap - addrs, sizeof(struct in_addr), qcomp);
+ if (SP(bp, char *, (hap - addrs) + (ap - aliases)) > buf + bufsize) {
+ errno = ERANGE;
+ return NULL;
+ }
+ result->h_addr_list = (char **) ALIGN(bp, char *);
+ memcpy(result->h_addr_list, addrs, (hap - addrs) * sizeof(char *));
+ result->h_aliases = result->h_addr_list + (hap - addrs);
+ memcpy(result->h_aliases, aliases, (ap - aliases) * sizeof(char *));
+ return result;
+ } else {
+ *errval = TRY_AGAIN;
+ return NULL;
+ }
+}
+
+/* Performs global initialization. */
+struct res_data *_res_init()
+{
+ struct res_data *data;
+
+ /* Make sure the global initializations have been done. */
+ pthread_once(&init_once, _res_init_global);
+ if (init_status < 0)
+ return NULL;
+
+ /* Initialize thread-specific data for this thread if it hasn't
+ * been done already. */
+ data = (struct res_data *) pthread_getspecific(key);
+ if (!data) {
+ data = (struct res_data *) malloc(sizeof(struct res_data));
+ if (data == NULL)
+ return NULL;
+ if (pthread_setspecific(key, data) < 0) {
+ free(data);
+ return NULL;
+ }
+ data->buf = NULL;
+ data->state = start;
+ data->errval = NO_RECOVERY;
+ data->sock = -1;
+ }
+ return data;
+}
+
+static void _res_init_global()
+{
+ int result;
+ char line[BUFSIZ], buf[BUFSIZ], *domain, *p, *net;
+ int i, localdomain_set = 0, num_servers = 0, num_sorts = 0;
+ FILE *fp;
+ struct in_addr addr;
+
+ /* Assume an error state until we finish. */
+ init_status = -1;
+
+ /* Initialize the key for thread-specific data. */
+ result = pthread_key_create(&key, free);
+ if (result < 0)
+ return;
+
+ /* Initialize starting state. */
+ start.retrans = RES_TIMEOUT;
+ start.retry = DEFAULT_RETRIES;
+ start.options = RES_DEFAULT;
+ start.id = 0;
+ start.nscount = 1;
+ start.nsaddr.sin_addr.s_addr = INADDR_ANY;
+ start.nsaddr.sin_family = AF_INET;
+ start.nsaddr.sin_port = htons(NAMESERVER_PORT);
+ start.nscount = 1;
+ start.ndots = 1;
+ start.pfcode = 0;
+ strncpy(start.lookups, "f", sizeof(start.lookups));
+
+ /* Look for a LOCALDOMAIN definition. */
+ domain = getenv("LOCALDOMAIN");
+ if (domain != NULL) {
+ strncpy(start.defdname, domain, sizeof(start.defdname));
+ domain = start.defdname;
+ localdomain_set = 1;
+
+ /* Construct a search path from the LOCALDOMAIN value, which is
+ * a space-separated list of strings. For backwards-compatibility,
+ * a newline terminates the list. */
+ i = 0;
+ while (*domain && i < MAXDNSRCH) {
+ start.dnsrch[i] = domain;
+ while (*domain && !isspace(*domain))
+ domain++;
+ if (!*domain || *domain == '\n') {
+ *domain = 0;
+ break;
+ }
+ *domain++ = 0;
+ while (isspace(*domain))
+ domain++;
+ i++;
+ }
+ }
+
+ /* Look for a config file and read it in. */
+ fp = fopen(_PATH_RESCONF, "r");
+ if (fp != NULL) {
+ strncpy(start.lookups, "bf", sizeof(start.lookups));
+
+ /* Read in the configuration file. */
+ while (fgets(line, sizeof(line), fp)) {
+
+ /* Ignore blank lines and comments. */
+ if (*line == ';' || *line == '#' || !*line)
+ continue;
+
+ if (strncmp(line, "domain", 6) == 0) {
+
+ /* Read in the default domain, and initialize a one-
+ * element search path. Skip the domain line if we
+ * already got one from the LOCALDOMAIN environment
+ * variable. */
+ if (localdomain_set)
+ continue;
+
+ /* Look for the next word in the line. */
+ p = line + 6;
+ while (*p == ' ' || *p == '\t')
+ p++;
+ if (!*p || *p == '\n')
+ continue;
+
+ /* Copy in the domain, and null-terminate it at the
+ * first tab or newline. */
+ strncpy(start.defdname, p, sizeof(start.defdname) - 1);
+ p = strpbrk(start.defdname, "\t\n");
+ if (p)
+ *p = 0;
+
+ start.dnsrch[0] = start.defdname;
+ start.dnsrch[1] = NULL;
+
+ } else if (strncmp(line, "lookup", 6) == 0) {
+
+ /* Get a list of lookup types. */
+ memset(start.lookups, 0, sizeof(start.lookups));
+
+ /* Find the next word in the line. */
+ p = line + 6;
+ while (isspace(*p))
+ p++;
+
+ i = 0;
+ while (*p && i < MAXDNSLUS) {
+ /* Add a lookup type. */
+ if (*p == 'y' || *p == 'b' || *p == 'f')
+ start.lookups[i++] = *p;
+
+ /* Find the next word. */
+ while (*p && !isspace(*p))
+ p++;
+ while (isspace(*p))
+ p++;
+ }
+
+ } else if (strncmp(line, "search", 6) == 0) {
+
+ /* Read in a space-separated list of domains to search
+ * when a name is not fully-qualified. Skip this line
+ * if the LOCALDOMAIN environment variable was set. */
+ if (localdomain_set)
+ continue;
+
+ /* Look for the next word on the line. */
+ p = line + 6;
+ while (*p == ' ' || *p == '\t')
+ p++;
+ if (!*p || *p == '\n')
+ continue;
+
+ /* Copy the rest of the line into start.defdname. */
+ strncpy(start.defdname, p, sizeof(start.defdname) - 1);
+ domain = start.defdname;
+ p = strchr(domain, '\n');
+ if (*p)
+ *p = 0;
+
+ /* Construct a search path from the line, which is a
+ * space-separated list of strings. */
+ i = 0;
+ while (*domain && i < MAXDNSRCH) {
+ start.dnsrch[i] = domain;
+ while (*domain && !isspace(*domain))
+ domain++;
+ if (!*domain || *domain == '\n') {
+ *domain = 0;
+ break;
+ }
+ *domain++ = 0;
+ while (isspace(*domain))
+ domain++;
+ i++;
+ }
+
+ } else if (strncmp(line, "nameserver", 10) == 0) {
+
+ /* Add an address to the list of name servers we can
+ * connect to. */
+
+ /* Look for the next word in the line. */
+ p = line + 10;
+ while (*p == ' ' || *p == '\t')
+ p++;
+ if (*p && *p != '\n' && inet_aton(p, &addr)) {
+ start.nsaddr_list[num_servers].sin_addr = addr;
+ start.nsaddr_list[num_servers].sin_family = AF_INET;
+ start.nsaddr_list[num_servers].sin_port =
+ htons(NAMESERVER_PORT);
+ if (++num_servers >= MAXNS)
+ break;
+ }
+
+ } else if (strncmp(line, "sortlist", 8) == 0) {
+
+ p = line + 8;
+ while (num_sorts < MAXRESOLVSORT) {
+
+ /* Find the next word in the line. */
+ p = line + 8;
+ while (*p == ' ' || *p == '\t')
+ p++;
+
+ /* Read in an IP address and netmask. */
+ if (sscanf(p, "%[0-9./]s", buf) != 1)
+ break;
+ net = strchr(buf, '/');
+ if (net)
+ *net = 0;
+
+ /* Translate the address into an IP address
+ * and netmask. */
+ if (inet_aton(buf, &addr)) {
+ start.sort_list[num_sorts].addr = addr;
+ if (net && inet_aton(net + 1, &addr)) {
+ start.sort_list[num_sorts].mask = addr.s_addr;
+ } else {
+ start.sort_list[num_sorts].mask =
+ net_mask(start.sort_list[num_sorts].addr);
+ }
+ num_sorts++;
+ }
+
+ /* Skip past this word. */
+ if (net)
+ *net = '/';
+ p += strlen(buf);
+ }
+
+ }
+ }
+ fclose(fp);
+ }
+
+ /* If we don't have a default domain, strip off the first
+ * component of this machine's domain name, and make a one-
+ * element search path consisting of the default domain. */
+ if (*start.defdname == 0) {
+ if (gethostname(buf, sizeof(start.defdname) - 1) == 0) {
+ p = strchr(buf, '.');
+ if (p)
+ strcpy(start.defdname, p + 1);
+ }
+ start.dnsrch[0] = start.defdname;
+ start.dnsrch[1] = NULL;
+ }
+
+ p = getenv("RES_OPTIONS");
+ if (p)
+ set_options(p, "env");
+
+ start.options |= RES_INIT;
+ _res = start;
+ init_status = 0;
+}
+
+static void set_options(const char *options, const char *source)
+{
+ const char *p = options;
+ int i;
+
+ while (*p) {
+
+ /* Skip leading and inner runs of spaces. */
+ while (*p == ' ' || *p == '\t')
+ p++;
+
+ /* Search for and process individual options. */
+ if (strncmp(p, "ndots:", 6) == 0) {
+ i = atoi(p + 6);
+ start.ndots = (i <= RES_MAXNDOTS) ? i : RES_MAXNDOTS;
+ } else if (!strncmp(p, "debug", 5))
+ start.options |= RES_DEBUG;
+ else if (!strncmp(p, "usevc", 5))
+ start.options |= RES_USEVC;
+ else if (!strncmp(p, "stayopen", 8))
+ start.options |= RES_STAYOPEN;
+
+ /* Skip to next run of spaces */
+ while (*p && *p != ' ' && *p != '\t')
+ p++;
+ }
+}
+
+static pthread_ipaddr_type net_mask(struct in_addr in)
+{
+ pthread_ipaddr_type i = ntohl(in.s_addr);
+
+ if (IN_CLASSA(i))
+ return htonl(IN_CLASSA_NET);
+ if (IN_CLASSB(i))
+ return htonl(IN_CLASSB_NET);
+ return htonl(IN_CLASSC_NET);
+}
+
+/* Get the error value for this thread, or NO_RECOVERY if none has been
+ * successfully set. The screw case to worry about here is if
+ * __res_init() fails for a resolver routine because it can't allocate
+ * or set the thread-specific data, and then __res_init() succeeds here.
+ * Because __res_init() sets errval to NO_RECOVERY after a successful
+ * initialization, we return NO_RECOVERY in that case, which is correct. */
+int _res_get_error()
+{
+ struct res_data *data;
+
+ data = _res_init();
+ return (data) ? data->errval : NO_RECOVERY;
+}
+
+struct __res_state *_res_status()
+{
+ struct res_data *data;
+
+ data = _res_init();
+ return (data) ? &data->state : NULL;
+}
+
+static int qcomp(const void *arg1, const void *arg2)
+{
+ const struct in_addr **a1 = (const struct in_addr **) arg1;
+ const struct in_addr **a2 = (const struct in_addr **) arg2;
+ struct __res_state *state = _res_status();
+
+ int pos1, pos2;
+
+ for (pos1 = 0; pos1 < state->nsort; pos1++) {
+ if (state->sort_list[pos1].addr.s_addr ==
+ ((*a1)->s_addr & state->sort_list[pos1].mask))
+ break;
+ }
+ for (pos2 = 0; pos2 < state->nsort; pos2++) {
+ if (state->sort_list[pos2].addr.s_addr ==
+ ((*a2)->s_addr & state->sort_list[pos2].mask))
+ break;
+ }
+ return pos1 - pos2;
+}
+
+/*
+ * This routine is for closing the socket if a virtual circuit is used and
+ * the program wants to close it. We don't use this routine, but libc
+ * might reference it.
+ *
+ * This routine is not expected to be user visible.
+ */
+void _res_close()
+{
+ struct res_data *data;
+
+ data = _res_init();
+ if (data && data->sock != -1) {
+ (void) close(data->sock);
+ data->sock = -1;
+ }
+}
diff --git a/mit-pthreads/net/res_internal.h b/mit-pthreads/net/res_internal.h
new file mode 100644
index 00000000000..4a4691bab84
--- /dev/null
+++ b/mit-pthreads/net/res_internal.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 1985 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)res_internal.h 6.22 (Berkeley) 3/19/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#ifndef _RES_INTERNAL_H
+#define _RES_INTERNAL_H
+
+#include <pthread.h>
+#include <netdb.h>
+#include <resolv.h>
+
+#define HOST_BUFSIZE 4096
+#define ALIGN(p, t) ((char *)(((((long)(p) - 1) / sizeof(t)) + 1) * sizeof(t)))
+#define SP(p, t, n) (ALIGN(p, t) + (n) * sizeof(t))
+
+struct res_data {
+ char *buf;
+ struct __res_state state;
+ int errval;
+ int sock;
+};
+
+#if PACKETSZ > 1024
+#define MAXPACKET PACKETSZ
+#else
+#define MAXPACKET 1024
+#endif
+
+typedef union {
+ HEADER hdr;
+ unsigned char buf[MAXPACKET];
+} querybuf;
+
+typedef union {
+ long al;
+ char ac;
+} align;
+
+extern pthread_mutex_t host_iterate_lock;
+
+__BEGIN_DECLS
+struct hostent *_res_parse_answer(querybuf *answer, int anslen, int iquery,
+ struct hostent *result, char *buf,
+ int buflen, int *errval);
+void _res_set_error(int val);
+struct res_data *_res_init(void);
+__END_DECLS
+
+#endif
+
diff --git a/mit-pthreads/net/res_mkquery.c b/mit-pthreads/net/res_mkquery.c
new file mode 100644
index 00000000000..42f27318368
--- /dev/null
+++ b/mit-pthreads/net/res_mkquery.c
@@ -0,0 +1,212 @@
+/*
+ * Copyright (c) 1985 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)res_mkquery.c 6.16 (Berkeley) 3/6/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <pthread.h>
+#include <sys/param.h>
+#include <sys/cdefs.h>
+#include <netinet/in.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <string.h>
+
+/*
+ * Form all types of queries.
+ * Returns the size of the result or -1.
+ */
+res_mkquery(op, dname, class, type, data, datalen, newrr_in, buf, buflen)
+ int op; /* opcode of query */
+ const char *dname; /* domain name */
+ int class, type; /* class and type of query */
+ const char *data; /* resource record data */
+ int datalen; /* length of data */
+ const char *newrr_in; /* new rr for modify or append */
+ char *buf; /* buffer to put query */
+ int buflen; /* size of buffer */
+{
+ register HEADER *hp;
+ register char *cp;
+ register int n;
+ struct rrec *newrr = (struct rrec *) newrr_in;
+ char *dnptrs[10], **dpp, **lastdnptr;
+ struct __res_state *_rs;
+
+ /*
+ * Initialize header fields.
+ */
+
+ _rs = _res_status();
+ if (!_rs)
+ return -1;
+ if ((buf == NULL) || (buflen < sizeof(HEADER)))
+ return(-1);
+ memset(buf, 0, sizeof(HEADER));
+ hp = (HEADER *) buf;
+ hp->id = htons(++_rs->id);
+ hp->opcode = op;
+ hp->pr = (_rs->options & RES_PRIMARY) != 0;
+ hp->rd = (_rs->options & RES_RECURSE) != 0;
+ hp->rcode = NOERROR;
+ cp = buf + sizeof(HEADER);
+ buflen -= sizeof(HEADER);
+ dpp = dnptrs;
+ *dpp++ = buf;
+ *dpp++ = NULL;
+ lastdnptr = dnptrs + sizeof(dnptrs)/sizeof(dnptrs[0]);
+ /*
+ * perform opcode specific processing
+ */
+ switch (op) {
+ case QUERY:
+ if ((buflen -= QFIXEDSZ) < 0)
+ return(-1);
+ if ((n = dn_comp((u_char *)dname, (u_char *)cp, buflen,
+ (u_char **)dnptrs, (u_char **)lastdnptr)) < 0)
+ return (-1);
+ cp += n;
+ buflen -= n;
+ __putshort(type, (u_char *)cp);
+ cp += sizeof(u_short);
+ __putshort(class, (u_char *)cp);
+ cp += sizeof(u_short);
+ hp->qdcount = htons(1);
+ if (op == QUERY || data == NULL)
+ break;
+ /*
+ * Make an additional record for completion domain.
+ */
+ buflen -= RRFIXEDSZ;
+ if ((n = dn_comp((u_char *)data, (u_char *)cp, buflen,
+ (u_char **)dnptrs, (u_char **)lastdnptr)) < 0)
+ return (-1);
+ cp += n;
+ buflen -= n;
+ __putshort(T_NULL, (u_char *)cp);
+ cp += sizeof(u_short);
+ __putshort(class, (u_char *)cp);
+ cp += sizeof(u_short);
+ __putlong(0, (u_char *)cp);
+ cp += sizeof(pthread_ipaddr_type);
+ __putshort(0, (u_char *)cp);
+ cp += sizeof(u_short);
+ hp->arcount = htons(1);
+ break;
+
+ case IQUERY:
+ /*
+ * Initialize answer section
+ */
+ if (buflen < 1 + RRFIXEDSZ + datalen)
+ return (-1);
+ *cp++ = '\0'; /* no domain name */
+ __putshort(type, (u_char *)cp);
+ cp += sizeof(u_short);
+ __putshort(class, (u_char *)cp);
+ cp += sizeof(u_short);
+ __putlong(0, (u_char *)cp);
+ cp += sizeof(pthread_ipaddr_type);
+ __putshort(datalen, (u_char *)cp);
+ cp += sizeof(u_short);
+ if (datalen) {
+ memcpy(cp, data, datalen);
+ cp += datalen;
+ }
+ hp->ancount = htons(1);
+ break;
+
+#ifdef ALLOW_UPDATES
+ /*
+ * For UPDATEM/UPDATEMA, do UPDATED/UPDATEDA followed by UPDATEA
+ * (Record to be modified is followed by its replacement in msg.)
+ */
+ case UPDATEM:
+ case UPDATEMA:
+
+ case UPDATED:
+ /*
+ * The res code for UPDATED and UPDATEDA is the same; user
+ * calls them differently: specifies data for UPDATED; server
+ * ignores data if specified for UPDATEDA.
+ */
+ case UPDATEDA:
+ buflen -= RRFIXEDSZ + datalen;
+ if ((n = dn_comp(dname, cp, buflen, dnptrs, lastdnptr)) < 0)
+ return (-1);
+ cp += n;
+ __putshort(type, cp);
+ cp += sizeof(u_short);
+ __putshort(class, cp);
+ cp += sizeof(u_short);
+ __putlong(0, cp);
+ cp += sizeof(pthread_ipaddr_type);
+ __putshort(datalen, cp);
+ cp += sizeof(u_short);
+ if (datalen) {
+ memcpy(cp, data, datalen);
+ cp += datalen;
+ }
+ if ( (op == UPDATED) || (op == UPDATEDA) ) {
+ hp->ancount = htons(0);
+ break;
+ }
+ /* Else UPDATEM/UPDATEMA, so drop into code for UPDATEA */
+
+ case UPDATEA: /* Add new resource record */
+ buflen -= RRFIXEDSZ + datalen;
+ if ((n = dn_comp(dname, cp, buflen, dnptrs, lastdnptr)) < 0)
+ return (-1);
+ cp += n;
+ __putshort(newrr->r_type, cp);
+ cp += sizeof(u_short);
+ __putshort(newrr->r_class, cp);
+ cp += sizeof(u_short);
+ __putlong(0, cp);
+ cp += sizeof(pthread_ipaddr_type);
+ __putshort(newrr->r_size, cp);
+ cp += sizeof(u_short);
+ if (newrr->r_size) {
+ memcpy(cp, newrr->r_data, newrr->r_size);
+ cp += newrr->r_size;
+ }
+ hp->ancount = htons(0);
+ break;
+
+#endif /* ALLOW_UPDATES */
+ }
+ return (cp - buf);
+}
+
diff --git a/mit-pthreads/net/res_query.c b/mit-pthreads/net/res_query.c
new file mode 100644
index 00000000000..1727e6d1179
--- /dev/null
+++ b/mit-pthreads/net/res_query.c
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 1985 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)res_query.c 6.22 (Berkeley) 3/19/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <pthread.h>
+#include <resolv.h>
+#include <netdb.h>
+#include "res_internal.h"
+
+#if PACKETSZ > 1024
+#define MAXPACKET PACKETSZ
+#else
+#define MAXPACKET 1024
+#endif
+
+int res_query(char *name, int class, int type, unsigned char *answer,
+ int anslen)
+{
+ struct res_data *data;
+ char buf[MAXPACKET];
+ int result;
+ HEADER *hp;
+
+ data = _res_init();
+ if (!data)
+ return -1;
+
+ /* Make the query. */
+ result = res_mkquery(QUERY, name, class, type, NULL, 0, NULL, buf,
+ sizeof(buf));
+ if (result <= 0) {
+ data->errval = NO_RECOVERY;
+ return result;
+ }
+
+ result = res_send(buf, result, (char *) answer, anslen);
+ if (result < 0) {
+ data->errval = TRY_AGAIN;
+ return result;
+ }
+
+ hp = (HEADER *) answer;
+ if (hp->rcode == NOERROR && ntohs(hp->ancount) != 0)
+ return result;
+
+ /* Translate the error code and return. */
+ switch(hp->rcode) {
+ case NOERROR:
+ data->errval = NO_DATA;
+ break;
+ case SERVFAIL:
+ data->errval = TRY_AGAIN;
+ break;
+ case NXDOMAIN:
+ data->errval = HOST_NOT_FOUND;
+ break;
+ default:
+ data->errval = NO_RECOVERY;
+ break;
+ }
+ return -1;
+}
+
diff --git a/mit-pthreads/net/res_querydomain.c b/mit-pthreads/net/res_querydomain.c
new file mode 100644
index 00000000000..31beeb7a62c
--- /dev/null
+++ b/mit-pthreads/net/res_querydomain.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 1985 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)res_querydomain.c 6.22 (Berkeley) 3/19/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <pthread.h>
+#include <resolv.h>
+#include <string.h>
+
+/* For backwards compatibility. */
+int res_querydomain(char *name, char *domain, int class, int type,
+ unsigned char *answer, int anslen)
+{
+ char buf[2 * MAXDNAME + 2];
+ char *longname = buf;
+ int len;
+
+ if (domain == NULL) {
+ /* Check for trailing '.'; copy without '.' if present. */
+ len = strlen(name);
+ if (len > 0 && name[len - 1] == '.' && len < sizeof(buf)) {
+ memcpy(buf, name, len - 1);
+ buf[len - 1] = '\0';
+ } else {
+ longname = name;
+ }
+ } else {
+ sprintf(buf, "%.*s.%.*s", MAXDNAME, name, MAXDNAME, domain);
+ }
+
+ return (res_query(longname, class, type, answer, anslen));
+}
+
diff --git a/mit-pthreads/net/res_search.c b/mit-pthreads/net/res_search.c
new file mode 100644
index 00000000000..2c84f0d68f3
--- /dev/null
+++ b/mit-pthreads/net/res_search.c
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 1985, 1988 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)res_search.c 6.45 (Berkeley) 2/24/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <pthread.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <resolv.h>
+#include <netdb.h>
+#include "res_internal.h"
+
+static char *search_aliases(const char *name, char *buf, int bufsize);
+
+int res_search(const char *name, int class, int type, unsigned char *answer,
+ int anslen)
+{
+ struct res_data *data;
+ const char *p;
+ int num_dots, len, result, no_data = 0, error;
+ char buf[2 * MAXDNAME + 2], *domain, **dptr, *alias;
+
+ data = _res_init();
+ if (!data)
+ return -1;
+
+ /* Count the dots in name, and get a pointer to the end of name. */
+ num_dots = 0;
+ for (p = name; *p; p++) {
+ if (*p == '.')
+ num_dots++;
+ }
+ len = p - name;
+
+ /* If there aren't any dots, check to see if name is an alias for
+ * another host. If so, try the resolved alias as a fully-qualified
+ * name. */
+ alias = search_aliases(name, buf, sizeof(buf));
+ if (alias != NULL)
+ return res_query(alias, class, type, answer, anslen);
+
+ /* If there's a trailing dot, try to strip it off and query the name. */
+ if (len > 0 && p[-1] == '.') {
+ if (len > sizeof(buf)) {
+ /* It's too long; just query the original name. */
+ return res_query(name, class, type, answer, anslen);
+ } else {
+ /* Copy the name without the trailing dot and query. */
+ memcpy(buf, name, len - 1);
+ buf[len] = 0;
+ return res_query(buf, class, type, answer, anslen);
+ }
+ }
+
+ if (data->state.options & RES_DNSRCH) {
+ /* If RES_DNSRCH is set, query all the domains until we get a
+ * definitive answer. */
+ for (dptr = data->state.dnsrch; *dptr; dptr++) {
+ domain = *dptr;
+ sprintf(buf, "%.*s.%.*s", MAXDNAME, name, MAXDNAME, domain);
+ result = res_query(buf, class, type, answer, anslen);
+ if (result > 0)
+ return result;
+ if (data->errval == NO_DATA)
+ no_data = 1;
+ else if (data->errval != HOST_NOT_FOUND)
+ break;
+ }
+ } else if (num_dots == 0 && data->state.options & RES_DEFNAMES) {
+ /* If RES_DEFNAMES is set and there is no dot, query the default
+ * domain. */
+ domain = data->state.defdname;
+ sprintf(buf, "%.*s.%.%s", MAXDNAME, name, MAXDNAME, domain);
+ result = res_query(buf, class, type, answer, anslen);
+ if (result > 0)
+ return result;
+ if (data->errval == NO_DATA)
+ no_data = 1;
+ }
+
+ /* If all the domain queries failed, try the name as fully-qualified.
+ * Only do this if there is at least one dot in the name. */
+ if (num_dots > 0) {
+ result = res_query(name, class, type, answer, anslen);
+ if (result > 0)
+ return result;
+ }
+
+ if (no_data)
+ data->errval = NO_DATA;
+
+ return -1;
+}
+
+static char *search_aliases(const char *name, char *buf, int bufsize)
+{
+ FILE *fp;
+ char *filename, *p;
+ int len;
+
+ filename = getenv("HOSTALIASES");
+ if (filename == NULL)
+ return NULL;
+
+ fp = fopen(filename, "r");
+ if (fp == NULL)
+ return NULL;
+
+ len = strlen(name);
+ while (fgets(buf, bufsize, fp)) {
+
+ /* Get the first word from the buffer. */
+ p = buf;
+ while (*p && !isspace(*p))
+ p++;
+ if (!*p)
+ break;
+
+ /* Null-terminate the first word and compare it with the name. */
+ *p = 0;
+ if (strcasecmp(buf, name) != 0)
+ continue;
+
+ p++;
+ while (isspace(*p))
+ p++;
+ fclose(fp);
+ return (*p) ? p : NULL;
+ }
+
+ fclose(fp);
+ return NULL;
+}
+
diff --git a/mit-pthreads/net/res_send.c b/mit-pthreads/net/res_send.c
new file mode 100644
index 00000000000..84162e8e387
--- /dev/null
+++ b/mit-pthreads/net/res_send.c
@@ -0,0 +1,313 @@
+/*
+ * Copyright (c) 1985, 1988 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)res_send.c 6.45 (Berkeley) 2/24/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <pthread.h>
+#include <stdio.h>
+#include <errno.h>
+#include <resolv.h>
+#include <netdb.h>
+#include <time.h>
+#include <sys/timers.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+#include <netinet/in.h>
+#include "res_internal.h"
+
+enum { SEND_GIVE_UP = -1, SEND_TRY_NEXT = -2, SEND_TRY_SAME = -3,
+ SEND_TIMEOUT = -4, SEND_TRUNCATED = -5 };
+
+static int send_datagram(int server, int sock, const char *buf, int buflen,
+ char *answer, int anslen, int try,
+ struct res_data *data);
+static int send_circuit(int server, const char *buf, int buflen, char *answer,
+ int anslen, struct res_data *data);
+static int close_save_errno(int sock);
+
+int res_send(const char *buf, int buflen, char *answer, int anslen)
+{
+ struct res_data *data;
+ struct sockaddr_in local;
+ int use_virtual_circuit, result, udp_sock, have_seen_same, terrno = 0;
+ int try, server;
+
+ data = _res_init();
+ if (!data)
+ return -1;
+
+ try = 0;
+ server = 0;
+
+ /* Try doing connectionless queries if appropriate. */
+ if (!(data->state.options & RES_USEVC) && buflen <= PACKETSZ) {
+ /* Create and bind a local UDP socket. */
+ udp_sock = socket(AF_INET, SOCK_DGRAM, 0);
+ if (udp_sock < 0)
+ return -1;
+ local.sin_family = AF_INET;
+ local.sin_addr.s_addr = htonl(INADDR_ANY);
+ local.sin_port = htons(0);
+ if (bind(udp_sock, (struct sockaddr *) &local, sizeof(local)) < 0) {
+ close(udp_sock);
+ return -1;
+ }
+
+ /* Cycle through the retries and servers, sending off queries and
+ * waiting for responses. */
+ for (; try < data->state.retry; try++) {
+ for (; server < data->state.nscount; server++) {
+ result = send_datagram(server, udp_sock, buf, buflen, answer,
+ anslen, try, data);
+ if (result == SEND_TIMEOUT)
+ terrno = ETIMEDOUT;
+ else if (result != SEND_TRY_NEXT)
+ break;
+ }
+ if (server < data->state.nscount)
+ break;
+ }
+
+ close(udp_sock);
+ if (result < 0)
+ errno = (terrno == ETIMEDOUT) ? ETIMEDOUT : ECONNREFUSED;
+ else
+ errno = 0;
+ if (result != SEND_TRUNCATED)
+ return (result >= 0) ? result : -1;
+ }
+
+ /* Either we have to use the virtual circuit, or the server couldn't
+ * fit its response in a UDP packet. Cycle through the retries and
+ * servers, sending off queries and waiting for responses. Allow a
+ * response of SEND_TRY_SAME to cause an extra retry once. */
+ for (; try < data->state.retry; try++) {
+ for (; server < data->state.nscount; server++) {
+ result = send_circuit(server, buf, buflen, answer, anslen, data);
+ terrno = errno;
+ if (result == SEND_TRY_SAME) {
+ if (!have_seen_same)
+ server--;
+ have_seen_same = 1;
+ } else if (result != SEND_TRY_NEXT) {
+ break;
+ }
+ }
+ }
+
+ errno = terrno;
+ return (result >= 0) ? result : -1;
+}
+
+static int send_datagram(int server, int sock, const char *buf, int buflen,
+ char *answer, int anslen, int try,
+ struct res_data *data)
+{
+ int count, interval;
+ struct sockaddr_in local_addr;
+ HEADER *request = (HEADER *) buf, *response = (HEADER *) answer;
+ struct timespec timeout;
+ struct timeval current;
+ struct timezone zone;
+
+#ifdef DEBUG_RESOLVER
+ if (_res.options & RES_DEBUG) {
+ printf("res_send: request:\n");
+ __p_query(buf);
+ }
+#endif /* DEBUG_RESOLVER */
+ /* Send a packet to the server. */
+ count = sendto(sock, buf, buflen, 0,
+ (struct sockaddr *) &data->state.nsaddr_list[server],
+ sizeof(struct sockaddr_in));
+
+ if (count != buflen) {
+#ifdef DEBUG_RESOLVER
+ if (count < 0){
+ if (_res.options & RES_DEBUG)
+ perror("send_datagram:sendto");
+ }
+#endif /* DEBUG_RESOLVER */
+ return SEND_TRY_NEXT;
+ }
+
+ /* Await a reply with the correct ID. */
+ while (1) {
+ struct sockaddr_in from;
+ int from_len;
+
+ from_len = sizeof(from);
+ interval = data->state.retrans << try;
+ if (try > 0)
+ interval /= data->state.nscount;
+ gettimeofday(&current, &zone);
+ current.tv_sec += interval;
+ TIMEVAL_TO_TIMESPEC(&current, &timeout);
+ count = recvfrom_timedwait(sock, answer, anslen, 0,
+ &from, &from_len, &timeout);
+ if (count < 0)
+ return SEND_TRY_NEXT;
+ /* If the ID is wrong, it's from an old query; ignore it. */
+ if (response->id == request->id)
+ break;
+#ifdef DEBUG_RESOLVER
+ if (_res.options & RES_DEBUG) {
+ printf("res_sendto: count=%d, response:\n", count);
+ __p_query(answer);
+ }
+#endif /* DEBUG_RESOLVER */
+ }
+
+ /* Report a truncated response unless RES_IGNTC is set. This will
+ * cause the res_send() loop to fall back to TCP. */
+ if (response->tc && !(data->state.options & RES_IGNTC))
+ return SEND_TRUNCATED;
+
+ return count;
+}
+
+static int send_circuit(int server, const char *buf, int buflen, char *answer,
+ int anslen, struct res_data *data)
+{
+ HEADER *response = (HEADER *) answer;
+ int sock = -1, result, n, response_len, count;
+ unsigned short len;
+ struct iovec iov[2];
+ char *p, junk[512];
+
+ /* If data->sock is valid, then it's an open connection to the
+ * first server. Grab it if it's appropriate; close it if not. */
+ if (data->sock) {
+ if (server == 0)
+ sock = data->sock;
+ else
+ close(data->sock);
+ data->sock = -1;
+ }
+
+ /* Initialize our socket if we didn't grab it from data. */
+ if (sock == -1) {
+ sock = socket(AF_INET, SOCK_STREAM, 0);
+ if (sock < 0)
+ return SEND_GIVE_UP;
+ result = connect(sock,
+ (struct sockaddr *) &data->state.nsaddr_list[server],
+ sizeof(struct sockaddr_in));
+ if (result < 0) {
+ close_save_errno(sock);
+ return SEND_TRY_NEXT;
+ }
+ }
+
+ /* Send length and message. */
+ len = htons((unsigned short) buflen);
+ iov[0].iov_base = (caddr_t) &len;
+ iov[0].iov_len = sizeof(len);
+ iov[1].iov_base = (char *) buf;
+ iov[1].iov_len = buflen;
+ if (writev(sock, iov, 2) != sizeof(len) + buflen) {
+ close_save_errno(sock);
+ return SEND_TRY_NEXT;
+ }
+
+ /* Receive length. */
+ p = (char *) &len;
+ n = sizeof(len);
+ while (n) {
+ count = read(sock, p, n);
+ if (count <= 0) {
+ /* If we got ECONNRESET, the remote server may have restarted,
+ * and we report SEND_TRY_SAME. (The main loop will only
+ * allow one of these, so we don't have to worry about looping
+ * indefinitely.) */
+ close_save_errno(sock);
+ return (errno == ECONNRESET) ? SEND_TRY_SAME : SEND_TRY_NEXT;
+ }
+ p += count;
+ n -= count;
+ }
+ len = ntohs(len);
+ response_len = (len > anslen) ? anslen : len;
+ len -= response_len;
+
+ /* Receive message. */
+ p = answer;
+ n = response_len;
+ while (n) {
+ count = read(sock, p, n);
+ if (count <= 0) {
+ close_save_errno(sock);
+ return SEND_TRY_NEXT;
+ }
+ p += count;
+ n -= count;
+ }
+
+ /* If the reply is longer than our answer buffer, set the truncated
+ * bit and flush the rest of the reply, to keep the connection in
+ * sync. */
+ if (len) {
+ response->tc = 1;
+ while (len) {
+ n = (len > sizeof(junk)) ? sizeof(junk) : len;
+ count = read(sock, junk, n);
+ if (count <= 0) {
+ close_save_errno(sock);
+ return response_len;
+ }
+ len -= count;
+ }
+ }
+
+ /* If this is the first server, and RES_USEVC and RES_STAYOPEN are
+ * both set, save the connection. Otherwise, close it. */
+ if (server == 0 && (data->state.options & RES_USEVC &&
+ data->state.options & RES_STAYOPEN))
+ data->sock = sock;
+ else
+ close_save_errno(sock);
+
+ return response_len;
+}
+
+static int close_save_errno(int sock)
+{
+ int terrno;
+
+ terrno = errno;
+ close(sock);
+ errno = terrno;
+}
diff --git a/mit-pthreads/net/serv_internal.c b/mit-pthreads/net/serv_internal.c
new file mode 100644
index 00000000000..f4acc8697ae
--- /dev/null
+++ b/mit-pthreads/net/serv_internal.c
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 1985 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)serv_internal.c 6.22 (Berkeley) 3/19/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "serv_internal.h"
+
+#define DEFAULT_RETRIES 4
+
+static void _serv_init_global();
+
+pthread_mutex_t serv_iterate_lock = PTHREAD_MUTEX_INITIALIZER;
+static pthread_once_t init_once = PTHREAD_ONCE_INIT;
+static pthread_key_t key;
+static int init_status;
+
+/* Performs global initialization. */
+char *_serv_buf()
+{
+ char *buf;
+
+ /* Make sure the global initializations have been done. */
+ pthread_once(&init_once, _serv_init_global);
+
+ /* Initialize thread-specific data for this thread if it hasn't
+ * been done already. */
+ buf = (char *) pthread_getspecific(key);
+ if (!buf) {
+ buf = (char *) malloc(sizeof(struct servent) + SERV_BUFSIZE);
+ if (buf == NULL)
+ return NULL;
+ if (pthread_setspecific(key, buf) < 0) {
+ free(buf);
+ return NULL;
+ }
+ }
+ return buf;
+}
+
+static void _serv_init_global()
+{
+ init_status = pthread_key_create(&key, free);
+}
+
diff --git a/mit-pthreads/net/serv_internal.h b/mit-pthreads/net/serv_internal.h
new file mode 100644
index 00000000000..1d933826083
--- /dev/null
+++ b/mit-pthreads/net/serv_internal.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 1985 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)serv_internal.h 6.22 (Berkeley) 3/19/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#ifndef _SERV_INTERNAL_H
+#define _SERV_INTERNAL_H
+
+#include <pthread.h>
+#include <netdb.h>
+#include <resolv.h>
+
+#define SERV_BUFSIZE 4096
+#define ALIGN(p, t) ((char *)(((((long)(p) - 1) / sizeof(t)) + 1) * sizeof(t)))
+#define SP(p, t, n) (ALIGN(p, t) + (n) * sizeof(t))
+
+extern pthread_mutex_t serv_iterate_lock;
+
+__BEGIN_DECLS
+char *_serv_buf(void);
+__END_DECLS
+
+#endif
+
diff --git a/mit-pthreads/patches/Streepy.html b/mit-pthreads/patches/Streepy.html
new file mode 100755
index 00000000000..a3b4faa815f
--- /dev/null
+++ b/mit-pthreads/patches/Streepy.html
@@ -0,0 +1,2873 @@
+diff -c -r1.1.1.1 pthread.h
+*** pthread.h 1996/03/13 04:30:57 1.1.1.1
+--- pthread.h 1996/10/02 17:52:47
+***************
+*** 35,40 ****
+--- 35,43 ----
+ *
+ * 1.00 93/07/20 proven
+ * -Started coding this file.
++ *
++ * 93/9/28 streepy - Added support for pthread cancel
++ *
+ */
+
+ #ifndef _PTHREAD_H_
+***************
+*** 65,70 ****
+--- 68,82 ----
+ /* More includes, that need size_t */
+ #include <pthread/pthread_attr.h>
+
++ /* Constants for use with pthread_setcancelstate and pthread_setcanceltype */
++ #define PTHREAD_CANCEL_DISABLE 0
++ #define PTHREAD_CANCEL_ENABLE 1
++ #define PTHREAD_CANCEL_DEFERRED 0
++ #define PTHREAD_CANCEL_ASYNCHRONOUS 1
++
++ #define PTHREAD_CANCELLED (void *)1 /* Exit status of a cancelled thread */
++
++
+ #ifdef PTHREAD_KERNEL
+
+ #include <signal.h> /* for sigset_t */
+***************
+*** 78,120 ****
+ PS_STATE_MAX
+ };
+
+- #define PF_WAIT_EVENT 0x01
+- #define PF_DONE_EVENT 0x02
+-
+ /* Put PANIC inside an expression that evaluates to non-void type, to
+ make it easier to combine it in expressions. */
+! #define DO_PANIC() (PANIC (), 0)
+! #define PANICIF(x) ((x) ? DO_PANIC () : 0)
+
+! #define SET_PF_DONE_EVENT(x) \
+! ( !(x->flags & PF_DONE_EVENT) \
+! ? ( (x->flags & PF_WAIT_EVENT) \
+! ? (x->flags = PF_DONE_EVENT, OK) \
+! : DO_PANIC ()) \
+ : NOTOK )
+
+! #define SET_PF_WAIT_EVENT(x) \
+! ( PANICIF (x->flags & (PF_WAIT_EVENT | PF_DONE_EVENT)), \
+! (x->flags = PF_WAIT_EVENT), 0)
+!
+! #define CLEAR_PF_DONE_EVENT(x) \
+! ( PANICIF (!(x->flags & PF_DONE_EVENT)), \
+! x->flags = 0 )
+
+ struct pthread_select_data {
+! int nfds;
+! fd_set readfds;
+! fd_set writefds;
+! fd_set exceptfds;
+ };
+
+ union pthread_wait_data {
+! pthread_mutex_t * mutex;
+! pthread_cond_t * cond;
+! const sigset_t * sigwait; /* Waiting on a signal in sigwait */
+ struct {
+! short fd; /* Used when thread waiting on fd */
+! short branch; /* line number, for debugging */
+ } fd;
+ struct pthread_select_data * select_data;
+ };
+--- 90,185 ----
+ PS_STATE_MAX
+ };
+
+ /* Put PANIC inside an expression that evaluates to non-void type, to
+ make it easier to combine it in expressions. */
+! #define DO_PANIC() (PANIC (), 0)
+! #define PANICIF(x) ((x) ? DO_PANIC () : 0)
+!
+! /* In the thread flag field, we use a series of bit flags. Flags can
+! * organized into "groups" of mutually exclusive flags. Other flags
+! * are unrelated and can be set and cleared with a single bit operation.
+! */
+
+! #define PF_WAIT_EVENT 0x01
+! #define PF_DONE_EVENT 0x02
+! #define PF_EVENT_GROUP 0x03 /* All event bits */
+!
+! #define PF_CANCEL_STATE 0x04 /* cancellability state */
+! #define PF_CANCEL_TYPE 0x08 /* cancellability type */
+! #define PF_THREAD_CANCELLED 0x10 /* thread has been cancelled */
+! #define PF_RUNNING_TO_CANCEL 0x20 /* Thread is running so it can cancel*/
+! #define PF_AT_CANCEL_POINT 0x40 /* Thread is at a cancel point */
+!
+! /* Flag operations */
+!
+! #define SET_PF_FLAG(x,f) ( (x)->flags |= (f) )
+! #define TEST_PF_FLAG(x,f) ( (x)->flags & (f) )
+! #define CLEAR_PF_FLAG(x,f) ( (x)->flags &= ~(f) )
+! #define CLEAR_PF_GROUP(x,g) ( (x)->flags &= ~(g) )
+! #define SET_PF_FLAG_IN_GROUP(x,g,f) ( CLEAR_PF_GROUP(x,g),SET_PF_FLAG(x,f))
+! #define TEST_PF_GROUP(x,g) ( (x)->flags & (g) )
+!
+! #define SET_PF_DONE_EVENT(x) \
+! ( !TEST_PF_FLAG(x,PF_DONE_EVENT) \
+! ? ( TEST_PF_FLAG(x,PF_WAIT_EVENT) \
+! ? (SET_PF_FLAG_IN_GROUP(x,PF_EVENT_GROUP,PF_DONE_EVENT), OK) \
+! : DO_PANIC ()) \
+ : NOTOK )
+
+! #define SET_PF_WAIT_EVENT(x) \
+! ( PANICIF (TEST_PF_GROUP(x,PF_EVENT_GROUP) ), \
+! SET_PF_FLAG_IN_GROUP(x,PF_EVENT_GROUP,PF_WAIT_EVENT), 0)
+!
+! #define CLEAR_PF_DONE_EVENT(x) \
+! ( PANICIF (!TEST_PF_FLAG(x,PF_DONE_EVENT)), \
+! CLEAR_PF_GROUP(x,PF_EVENT_GROUP) )
+!
+! #define SET_PF_CANCELLED(x) ( SET_PF_FLAG(x,PF_THREAD_CANCELLED) )
+! #define TEST_PF_CANCELLED(x) ( TEST_PF_FLAG(x,PF_THREAD_CANCELLED) )
+!
+! #define SET_PF_RUNNING_TO_CANCEL(x) ( SET_PF_FLAG(x,PF_RUNNING_TO_CANCEL) )
+! #define CLEAR_PF_RUNNING_TO_CANCEL(x)( CLEAR_PF_FLAG(x,PF_RUNNING_TO_CANCEL) )
+! #define TEST_PF_RUNNING_TO_CANCEL(x)( TEST_PF_FLAG(x,PF_RUNNING_TO_CANCEL) )
+!
+! #define SET_PF_AT_CANCEL_POINT(x) ( SET_PF_FLAG(x,PF_AT_CANCEL_POINT) )
+! #define CLEAR_PF_AT_CANCEL_POINT(x) ( CLEAR_PF_FLAG(x,PF_AT_CANCEL_POINT) )
+! #define TEST_PF_AT_CANCEL_POINT(x) ( TEST_PF_FLAG(x,PF_AT_CANCEL_POINT) )
+!
+! #define SET_PF_CANCEL_STATE(x,f) \
+! ( (f) ? SET_PF_FLAG(x,PF_CANCEL_STATE) : CLEAR_PF_FLAG(x,PF_CANCEL_STATE) )
+! #define TEST_PF_CANCEL_STATE(x) \
+! ( (TEST_PF_FLAG(x,PF_CANCEL_STATE)) ? PTHREAD_CANCEL_ENABLE \
+! : PTHREAD_CANCEL_DISABLE )
+!
+! #define SET_PF_CANCEL_TYPE(x,f) \
+! ( (f) ? SET_PF_FLAG(x,PF_CANCEL_TYPE) : CLEAR_PF_FLAG(x,PF_CANCEL_TYPE) )
+! #define TEST_PF_CANCEL_TYPE(x) \
+! ( (TEST_PF_FLAG(x,PF_CANCEL_TYPE)) ? PTHREAD_CANCEL_ASYNCHRONOUS \
+! : PTHREAD_CANCEL_DEFERRED )
+!
+! /* See if a thread is in a state that it can be cancelled */
+! #define TEST_PTHREAD_IS_CANCELLABLE(x) \
+! ( (TEST_PF_CANCEL_STATE(x) == PTHREAD_CANCEL_ENABLE && TEST_PF_CANCELLED(x)) \
+! ? ((TEST_PF_CANCEL_TYPE(x) == PTHREAD_CANCEL_ASYNCHRONOUS) \
+! ? 1 \
+! : TEST_PF_AT_CANCEL_POINT(x)) \
+! : 0 )
+!
+
+ struct pthread_select_data {
+! int nfds;
+! fd_set readfds;
+! fd_set writefds;
+! fd_set exceptfds;
+ };
+
+ union pthread_wait_data {
+! pthread_mutex_t * mutex;
+! pthread_cond_t * cond;
+! const sigset_t * sigwait; /* Waiting on a signal in sigwait */
+ struct {
+! short fd; /* Used when thread waiting on fd */
+! short branch; /* line number, for debugging */
+ } fd;
+ struct pthread_select_data * select_data;
+ };
+***************
+*** 122,143 ****
+ #define PTT_USER_THREAD 0x0001
+
+ struct pthread {
+! int thread_type;
+ struct machdep_pthread machdep_data;
+! pthread_attr_t attr;
+
+ /* Signal interface */
+! sigset_t sigmask;
+! sigset_t sigpending;
+! int sigcount; /* Number of signals pending */
+
+ /* Timeout time */
+! struct timespec wakeup_time;
+
+ /* Join queue for waiting threads */
+ struct pthread_queue join_queue;
+
+-
+ /*
+ * Thread implementations are just multiple queue type implemenations,
+ * Below are the various link lists currently necessary
+--- 187,207 ----
+ #define PTT_USER_THREAD 0x0001
+
+ struct pthread {
+! int thread_type;
+ struct machdep_pthread machdep_data;
+! pthread_attr_t attr;
+
+ /* Signal interface */
+! sigset_t sigmask;
+! sigset_t sigpending;
+! int sigcount; /* Number of signals pending */
+
+ /* Timeout time */
+! struct timespec wakeup_time;
+
+ /* Join queue for waiting threads */
+ struct pthread_queue join_queue;
+
+ /*
+ * Thread implementations are just multiple queue type implemenations,
+ * Below are the various link lists currently necessary
+***************
+*** 152,165 ****
+ * ALL threads, in any state.
+ * Must lock kernel lock before manipulating.
+ */
+! struct pthread * pll;
+
+ /*
+ * Standard link list for running threads, mutexes, etc ...
+ * It can't be on both a running link list and a wait queue.
+ * Must lock kernel lock before manipulating.
+ */
+! struct pthread * next;
+ union pthread_wait_data data;
+
+ /*
+--- 216,229 ----
+ * ALL threads, in any state.
+ * Must lock kernel lock before manipulating.
+ */
+! struct pthread * pll;
+
+ /*
+ * Standard link list for running threads, mutexes, etc ...
+ * It can't be on both a running link list and a wait queue.
+ * Must lock kernel lock before manipulating.
+ */
+! struct pthread * next;
+ union pthread_wait_data data;
+
+ /*
+***************
+*** 167,197 ****
+ * (Note: "priority" is a reserved word in Concurrent C, please
+ * don't use it. --KR)
+ */
+! struct pthread_queue * queue;
+! enum pthread_state state;
+! char flags;
+! char pthread_priority;
+
+ /*
+ * Sleep queue, this is different from the standard link list
+ * because it is possible to be on both (pthread_cond_timedwait();
+ * Must lock sleep mutex before manipulating
+ */
+! struct pthread *sll; /* For sleeping threads */
+
+ /*
+ * Data that doesn't need to be locked
+! * Mostly it's because only the thread owning the data can manipulate it
+ */
+! void * ret;
+! int error;
+! int * error_p;
+! const void ** specific_data;
+! int specific_data_count;
+
+ /* Cleanup handlers Link List */
+ struct pthread_cleanup *cleanup;
+-
+ };
+
+ #else /* not PTHREAD_KERNEL */
+--- 231,261 ----
+ * (Note: "priority" is a reserved word in Concurrent C, please
+ * don't use it. --KR)
+ */
+! struct pthread_queue * queue;
+! enum pthread_state state;
+! enum pthread_state old_state; /* Used when cancelled */
+! char flags;
+! char pthread_priority;
+
+ /*
+ * Sleep queue, this is different from the standard link list
+ * because it is possible to be on both (pthread_cond_timedwait();
+ * Must lock sleep mutex before manipulating
+ */
+! struct pthread *sll; /* For sleeping threads */
+
+ /*
+ * Data that doesn't need to be locked
+! * Mostly because only the thread owning the data can manipulate it
+ */
+! void * ret;
+! int error;
+! int * error_p;
+! const void ** specific_data;
+! int specific_data_count;
+
+ /* Cleanup handlers Link List */
+ struct pthread_cleanup *cleanup;
+ };
+
+ #else /* not PTHREAD_KERNEL */
+***************
+*** 200,223 ****
+
+ #endif
+
+! typedef struct pthread * pthread_t;
+
+ /*
+ * Globals
+ */
+ #ifdef PTHREAD_KERNEL
+
+! extern struct pthread * pthread_run;
+! extern struct pthread * pthread_initial;
+! extern struct pthread * pthread_link_list;
+ extern struct pthread_queue pthread_dead_queue;
+ extern struct pthread_queue pthread_alloc_queue;
+
+! extern pthread_attr_t pthread_attr_default;
+! extern volatile int fork_lock;
+! extern pthread_size_t pthread_pagesize;
+!
+! extern sigset_t * uthread_sigmask;
+
+ #endif
+
+--- 264,293 ----
+
+ #endif
+
+! typedef struct pthread *pthread_t;
+
+ /*
+ * Globals
+ */
+ #ifdef PTHREAD_KERNEL
+
+! extern struct pthread * pthread_run;
+! extern struct pthread * pthread_initial;
+! extern struct pthread * pthread_link_list;
+ extern struct pthread_queue pthread_dead_queue;
+ extern struct pthread_queue pthread_alloc_queue;
+
+! extern pthread_attr_t pthread_attr_default;
+! extern volatile int fork_lock;
+! extern pthread_size_t pthread_pagesize;
+!
+! extern sigset_t * uthread_sigmask;
+!
+! /* Kernel global functions */
+! extern void pthread_sched_prevent(void);
+! extern void pthread_sched_resume(void);
+! extern int __pthread_is_valid( pthread_t );
+! extern void pthread_cancel_internal( int freelocks );
+
+ #endif
+
+***************
+*** 229,271 ****
+
+ #if defined(DCE_COMPAT)
+
+! typedef void * (*pthread_startroutine_t)(void *)
+! typedef void * pthread_addr_t
+
+! int pthread_create __P((pthread_t *, pthread_attr_t,
+! pthread_startroutine_t,
+! pthread_addr_t));
+! void pthread_exit __P((pthread_addr_t));
+! int pthread_join __P((pthread_t, pthread_addr_t *));
+
+ #else
+
+! void pthread_init __P((void));
+! int pthread_create __P((pthread_t *,
+! const pthread_attr_t *,
+! void * (*start_routine)(void *),
+! void *));
+! void pthread_exit __P((void *));
+! pthread_t pthread_self __P((void));
+! int pthread_equal __P((pthread_t, pthread_t));
+! int pthread_join __P((pthread_t, void **));
+! int pthread_detach __P((pthread_t));
+! void pthread_yield __P((void));
+!
+! int pthread_setschedparam __P((pthread_t pthread, int policy,
+! struct sched_param * param));
+! int pthread_getschedparam __P((pthread_t pthread, int * policy,
+! struct sched_param * param));
+!
+! int pthread_kill __P((struct pthread *, int));
+! int pthread_signal __P((int, void (*)(int)));
+
+ #endif
+
+ #if defined(PTHREAD_KERNEL)
+
+ /* Not valid, but I can't spell so this will be caught at compile time */
+! #define pthread_yeild(notvalid)
+
+ #endif
+
+--- 299,343 ----
+
+ #if defined(DCE_COMPAT)
+
+! typedef void * (*pthread_startroutine_t)(void *);
+! typedef void * pthread_addr_t;
+
+! int pthread_create __P((pthread_t *, pthread_attr_t,
+! pthread_startroutine_t, pthread_addr_t));
+! void pthread_exit __P((pthread_addr_t));
+! int pthread_join __P((pthread_t, pthread_addr_t *));
+
+ #else
+
+! void pthread_init __P((void));
+! int pthread_create __P((pthread_t *, const pthread_attr_t *,
+! void * (*start_routine)(void *), void *));
+! void pthread_exit __P((void *));
+! pthread_t pthread_self __P((void));
+! int pthread_equal __P((pthread_t, pthread_t));
+! int pthread_join __P((pthread_t, void **));
+! int pthread_detach __P((pthread_t));
+! void pthread_yield __P((void));
+!
+! int pthread_setschedparam __P((pthread_t pthread, int policy,
+! struct sched_param * param));
+! int pthread_getschedparam __P((pthread_t pthread, int * policy,
+! struct sched_param * param));
+!
+! int pthread_kill __P((struct pthread *, int));
+! int pthread_signal __P((int, void (*)(int)));
+!
+! int pthread_cancel __P(( pthread_t pthread ));
+! int pthread_setcancelstate __P(( int state, int *oldstate ));
+! int pthread_setcanceltype __P(( int type, int *oldtype ));
+! void pthread_testcancel __P(( void ));
+
+ #endif
+
+ #if defined(PTHREAD_KERNEL)
+
+ /* Not valid, but I can't spell so this will be caught at compile time */
+! #define pthread_yeild(notvalid)
+
+ #endif
+
+=================================================================== RCS file: /usr/cvssrc/pthreads-1_60_beta5/include/signal.h,v retrieving revision 1.1.1.1
+diff -c -r1.1.1.1 signal.h
+*** signal.h 1995/12/25 03:03:09 1.1.1.1
+--- signal.h 1996/09/26 21:46:04
+***************
+*** 43,48 ****
+--- 43,49 ----
+ __BEGIN_DECLS
+
+ int raise __P((int));
++ __sighandler_t signal __P((int __sig, __sighandler_t));
+
+ #ifndef _ANSI_SOURCE
+
+=================================================================== RCS file: /usr/cvssrc/pthreads-1_60_beta5/include/pthread/kernel.h,v retrieving revision 1.1.1.1
+diff -c -r1.1.1.1 kernel.h
+*** kernel.h 1994/12/13 07:09:01 1.1.1.1
+--- kernel.h 1996/10/02 19:08:41
+***************
+*** 42,48 ****
+ */
+ #if defined(PTHREAD_KERNEL)
+
+! #define PANIC() abort()
+
+ /* Time each rr thread gets */
+ #define PTHREAD_RR_TIMEOUT 100000000
+--- 42,54 ----
+ */
+ #if defined(PTHREAD_KERNEL)
+
+! #ifdef __GNUC__
+! #include <assert.h>
+! #define PANIC() panic_kernel( __FILE__, __LINE__, __ASSERT_FUNCTION )
+! #else
+! #define PANIC() panic_kernel( __FILE__, __LINE__, (const char *)0 )
+! #endif
+!
+
+ /* Time each rr thread gets */
+ #define PTHREAD_RR_TIMEOUT 100000000
+=================================================================== RCS file: /usr/cvssrc/pthreads-1_60_beta5/machdep/syscall-i386-linux-1.0.S,v retrieving revision 1.1.1.1
+diff -c -r1.1.1.1 syscall-i386-linux-1.0.S
+*** syscall-i386-linux-1.0.S 1995/09/27 04:38:55 1.1.1.1
+--- syscall-i386-linux-1.0.S 1996/06/04 19:20:17
+***************
+*** 147,154 ****
+
+ /* =========================================================================
+ * exit 1 select 82
+! * fork 2 socketcall 102
+! * read 3
+ * write 4
+ * open 5
+ * creat 8
+--- 147,154 ----
+
+ /* =========================================================================
+ * exit 1 select 82
+! * fork 2 fstatfs 100
+! * read 3 socketcall 102
+ * write 4
+ * open 5
+ * creat 8
+***************
+*** 160,166 ****
+ * chown 16
+ * lseek 19
+ * rename 38
+! * dup 41
+ * pipe 42
+ * ioctl 54
+ * fcntl 55
+--- 160,166 ----
+ * chown 16
+ * lseek 19
+ * rename 38
+! * dup 41
+ * pipe 42
+ * ioctl 54
+ * fcntl 55
+***************
+*** 302,314 ****
+ #endif
+
+ /* ==========================================================================
+! * machdep_sys_fstat()
+ */
+ #ifdef __ELF__
+ STATCALL2(lstat)
+ #else
+ SYSCALL2(lstat)
+ #endif
+
+ /* ==========================================================================
+ * machdep_sys_ftruncate()
+--- 302,320 ----
+ #endif
+
+ /* ==========================================================================
+! * machdep_sys_lstat()
+ */
+ #ifdef __ELF__
+ STATCALL2(lstat)
+ #else
+ SYSCALL2(lstat)
+ #endif
++
++ /* ==========================================================================
++ * machdep_sys_fstatfs()
++ */
++ SYSCALL2(fstatfs)
++
+
+ /* ==========================================================================
+ * machdep_sys_ftruncate()
+=================================================================== RCS file: /usr/cvssrc/pthreads-1_60_beta5/machdep/linux-1.0/socket.h,v retrieving revision 1.1.1.1
+diff -c -r1.1.1.1 socket.h
+*** socket.h 1995/12/26 02:28:03 1.1.1.1
+--- socket.h 1996/09/27 18:12:45
+***************
+*** 26,32 ****
+
+ #endif
+
+! /* #include <asm/socket.h> /* arch-dependent defines */
+ #include <linux/sockios.h> /* the SIOCxxx I/O controls */
+ #include <pthread/posix.h>
+
+--- 26,32 ----
+
+ #endif
+
+! /* #include <asm/socket.h> arch-dependent defines */
+ #include <linux/sockios.h> /* the SIOCxxx I/O controls */
+ #include <pthread/posix.h>
+
+***************
+*** 161,166 ****
+--- 161,188 ----
+ int connect __P((int, const struct sockaddr *, int));
+ int listen __P((int, int));
+ int socket __P((int, int, int));
++
++ int getsockopt __P ((int __s, int __level, int __optname,
++ void *__optval, int *__optlen));
++ int setsockopt __P ((int __s, int __level, int __optname,
++ __const void *__optval, int optlen));
++ int getsockname __P ((int __sockfd, struct sockaddr *__addr,
++ int *__paddrlen));
++ int getpeername __P ((int __sockfd, struct sockaddr *__peer,
++ int *__paddrlen));
++ ssize_t send __P ((int __sockfd, __const void *__buff, size_t __len, int __flags));
++ ssize_t recv __P ((int __sockfd, void *__buff, size_t __len, int __flags));
++ ssize_t sendto __P ((int __sockfd, __const void *__buff, size_t __len,
++ int __flags, __const struct sockaddr *__to,
++ int __tolen));
++ ssize_t recvfrom __P ((int __sockfd, void *__buff, size_t __len,
++ int __flags, struct sockaddr *__from,
++ int *__fromlen));
++ extern ssize_t sendmsg __P ((int __fd, __const struct msghdr *__message,
++ int __flags));
++ extern ssize_t recvmsg __P ((int __fd, struct msghdr *__message,
++ int __flags));
++ int shutdown __P ((int __sockfd, int __how));
+
+ __END_DECLS
+
+=================================================================== RCS file: /usr/cvssrc/pthreads-1_60_beta5/machdep/linux-1.0/timers.h,v retrieving revision 1.1.1.1
+diff -c -r1.1.1.1 timers.h
+*** timers.h 1996/03/05 08:28:36 1.1.1.1
+--- timers.h 1996/05/25 21:30:08
+***************
+*** 43,52 ****
+--- 43,54 ----
+ #include <sys/types.h>
+ #include <time.h>
+
++ #ifndef _LINUX_TIME_H
+ struct timespec {
+ time_t tv_sec;
+ long tv_nsec;
+ };
++ #endif /* _LINUX_TIME_H */
+
+ #define TIMEVAL_TO_TIMESPEC(tv, ts) { \
+ (ts)->tv_sec = (tv)->tv_sec; \
+=================================================================== RCS file: /usr/cvssrc/pthreads-1_60_beta5/net/getprotoent.c,v retrieving revision 1.1.1.1
+diff -c -r1.1.1.1 getprotoent.c
+*** getprotoent.c 1996/02/09 05:39:41 1.1.1.1
+--- getprotoent.c 1996/05/27 01:11:27
+***************
+*** 128,135 ****
+ if (p != NULL)
+ *p++ = '\0';
+ }
+! if (p && *p);
+! break;
+ }
+ *alias = NULL;
+ pthread_mutex_unlock(&proto_file_lock);
+--- 128,135 ----
+ if (p != NULL)
+ *p++ = '\0';
+ }
+! if (p && *p)
+! break;
+ }
+ *alias = NULL;
+ pthread_mutex_unlock(&proto_file_lock);
+=================================================================== RCS file: /usr/cvssrc/pthreads-1_60_beta5/net/proto_internal.c,v retrieving revision 1.1.1.1
+diff -c -r1.1.1.1 proto_internal.c
+*** proto_internal.c 1996/02/09 05:39:49 1.1.1.1
+--- proto_internal.c 1996/06/04 16:25:57
+***************
+*** 49,55 ****
+ static int init_status;
+
+ /* Performs global initialization. */
+! char *_proto_init()
+ {
+ char *buf;
+
+--- 49,55 ----
+ static int init_status;
+
+ /* Performs global initialization. */
+! char *_proto_buf()
+ {
+ char *buf;
+
+***************
+*** 75,78 ****
+ {
+ init_status = pthread_key_create(&key, free);
+ }
+-
+--- 75,77 ----
+=================================================================== RCS file: /usr/cvssrc/pthreads-1_60_beta5/net/res_internal.c,v retrieving revision 1.1.1.1
+diff -c -r1.1.1.1 res_internal.c
+*** res_internal.c 1996/02/09 05:39:53 1.1.1.1
+--- res_internal.c 1996/09/25 23:31:11
+***************
+*** 144,149 ****
+--- 144,150 ----
+ break;
+ cp += n;
+ result->h_name = bp;
++ bp += strlen(bp) + 1;
+ iquery_done = 1;
+ break;
+ }
+=================================================================== RCS file: /usr/cvssrc/pthreads-1_60_beta5/pthreads/GNUmakefile.inc,v retrieving revision 1.1.1.1
+diff -c -r1.1.1.1 GNUmakefile.inc
+*** GNUmakefile.inc 1995/08/30 22:27:04 1.1.1.1
+--- GNUmakefile.inc 1996/10/02 19:04:29
+***************
+*** 8,14 ****
+ syscall.S pthread_join.c pthread_detach.c pthread_once.c sleep.c \
+ specific.c process.c wait.c errno.c schedparam.c _exit.c prio_queue.c \
+ pthread_init.c init.cc sig.c info.c mutexattr.c select.c wrapper.c \
+! dump_state.c pthread_kill.c stat.c readv.c writev.c condattr.c $(SRCS)
+
+ ifeq ($(HAVE_SYSCALL_TEMPLATE),yes)
+ SYSCALL_FILTER_RULE= for s in $(AVAILABLE_SYSCALLS) ; do \
+--- 8,15 ----
+ syscall.S pthread_join.c pthread_detach.c pthread_once.c sleep.c \
+ specific.c process.c wait.c errno.c schedparam.c _exit.c prio_queue.c \
+ pthread_init.c init.cc sig.c info.c mutexattr.c select.c wrapper.c \
+! dump_state.c pthread_kill.c stat.c readv.c writev.c condattr.c \
+! pthread_cancel.c panic.c $(SRCS)
+
+ ifeq ($(HAVE_SYSCALL_TEMPLATE),yes)
+ SYSCALL_FILTER_RULE= for s in $(AVAILABLE_SYSCALLS) ; do \
+=================================================================== RCS file: /usr/cvssrc/pthreads-1_60_beta5/pthreads/Makefile.inc,v retrieving revision 1.1.1.1
+diff -c -r1.1.1.1 Makefile.inc
+*** Makefile.inc 1995/08/22 22:09:07 1.1.1.1
+--- Makefile.inc 1996/10/02 19:04:38
+***************
+*** 8,14 ****
+ pthread_join.c pthread_detach.c pthread_once.c sleep.c specific.c \
+ process.c wait.c errno.c schedparam.c _exit.c prio_queue.c \
+ pthread_init.c init.cc sig.c info.c mutexattr.c select.c wrapper.c \
+! dump_state.c pthread_kill.c condattr.c
+
+ .if $(HAVE_SYSCALL_TEMPLATE) == yes
+ OBJS+= syscalls.o
+--- 8,14 ----
+ pthread_join.c pthread_detach.c pthread_once.c sleep.c specific.c \
+ process.c wait.c errno.c schedparam.c _exit.c prio_queue.c \
+ pthread_init.c init.cc sig.c info.c mutexattr.c select.c wrapper.c \
+! dump_state.c pthread_kill.c condattr.c pthread_cancel.c panic.c
+
+ .if $(HAVE_SYSCALL_TEMPLATE) == yes
+ OBJS+= syscalls.o
+=================================================================== RCS file: /usr/cvssrc/pthreads-1_60_beta5/pthreads/cond.c,v retrieving revision 1.1.1.1
+diff -c -r1.1.1.1 cond.c
+*** cond.c 1996/03/05 08:29:12 1.1.1.1
+--- cond.c 1996/10/03 18:19:04
+***************
+*** 188,197 ****
+--- 188,204 ----
+ pthread_queue_enq(&cond->c_queue, pthread_run);
+ pthread_mutex_unlock(mutex);
+
++ pthread_run->data.mutex = mutex;
++
+ SET_PF_WAIT_EVENT(pthread_run);
++ SET_PF_AT_CANCEL_POINT(pthread_run); /* This is a cancel point */
+ /* Reschedule will unlock pthread_run */
+ pthread_resched_resume(PS_COND_WAIT);
++ CLEAR_PF_AT_CANCEL_POINT(pthread_run); /* No longer at cancel point */
+ CLEAR_PF_DONE_EVENT(pthread_run);
++
++ pthread_run->data.mutex = NULL;
++
+ rval = pthread_mutex_lock(mutex);
+ return(rval);
+ break;
+***************
+*** 203,212 ****
+--- 210,226 ----
+ pthread_mutex_unlock(mutex);
+ mutex->m_data.m_count = 1;
+
++ pthread_run->data.mutex = mutex;
++
+ SET_PF_WAIT_EVENT(pthread_run);
++ SET_PF_AT_CANCEL_POINT(pthread_run); /* This is a cancel point */
+ /* Reschedule will unlock pthread_run */
+ pthread_resched_resume(PS_COND_WAIT);
++ CLEAR_PF_AT_CANCEL_POINT(pthread_run); /* No longer at cancel point */
+ CLEAR_PF_DONE_EVENT(pthread_run);
++
++ pthread_run->data.mutex = NULL;
++
+ rval = pthread_mutex_lock(mutex);
+ mutex->m_data.m_count = count;
+ return(rval);
+***************
+*** 258,265 ****
+--- 272,285 ----
+ SET_PF_WAIT_EVENT(pthread_run);
+ pthread_mutex_unlock(mutex);
+
++ pthread_run->data.mutex = mutex;
++
++ SET_PF_AT_CANCEL_POINT(pthread_run); /* This is a cancel point */
+ /* Reschedule will unlock pthread_run */
+ pthread_resched_resume(PS_COND_WAIT);
++ CLEAR_PF_AT_CANCEL_POINT(pthread_run); /* No longer at cancel point */
++
++ pthread_run->data.mutex = NULL;
+
+ /* Remove ourselves from sleep queue. If we fail then we timedout */
+ if (sleep_cancel(pthread_run) == NOTOK) {
+***************
+*** 285,292 ****
+--- 305,318 ----
+ SET_PF_WAIT_EVENT(pthread_run);
+ pthread_mutex_unlock(mutex);
+
++ pthread_run->data.mutex = mutex;
++
++ SET_PF_AT_CANCEL_POINT(pthread_run); /* This is a cancel point */
+ /* Reschedule will unlock pthread_run */
+ pthread_resched_resume(PS_COND_WAIT);
++ CLEAR_PF_AT_CANCEL_POINT(pthread_run); /* No longer at cancel point */
++
++ pthread_run->data.mutex = NULL;
+
+ /* Remove ourselves from sleep queue. If we fail then we timedout */
+ if (sleep_cancel(pthread_run) == NOTOK) {
+=================================================================== RCS file: /usr/cvssrc/pthreads-1_60_beta5/pthreads/fd.c,v retrieving revision 1.1.1.1
+diff -c -r1.1.1.1 fd.c
+*** fd.c 1996/02/09 02:54:19 1.1.1.1
+--- fd.c 1996/10/03 01:33:03
+***************
+*** 48,54 ****
+--- 48,59 ----
+ #include <sys/types.h>
+ #include <sys/stat.h>
+ #include <sys/uio.h>
++ #include <sys/ioctl.h>
++ #if __STDC__
+ #include <stdarg.h>
++ #else
++ #include <varargs.h>
++ #endif
+ #include <fcntl.h>
+ #include <errno.h>
+ #include <pthread/posix.h>
+***************
+*** 62,67 ****
+--- 67,74 ----
+ static const int dtablecount = 4096/sizeof(struct fd_table_entry);
+ int dtablesize;
+
++ static int fd_get_pthread_fd_from_kernel_fd( int );
++
+ /* ==========================================================================
+ * Allocate dtablecount entries at once and populate the fd_table.
+ *
+***************
+*** 199,204 ****
+--- 206,244 ----
+ return(NOTOK);
+ }
+
++ /*----------------------------------------------------------------------
++ * Function: fd_get_pthread_fd_from_kernel_fd
++ * Purpose: get the fd_table index of a kernel fd
++ * Args: fd = kernel fd to convert
++ * Returns: fd_table index, -1 if not found
++ * Notes:
++ *----------------------------------------------------------------------*/
++ static int
++ fd_get_pthread_fd_from_kernel_fd( int kfd )
++ {
++ int j;
++
++ /* This is *SICK*, but unless there is a faster way to
++ * turn a kernel fd into an fd_table index, this has to do.
++ */
++ for( j=0; j < dtablesize; j++ ) {
++ if( fd_table[j] &&
++ fd_table[j]->type != FD_NT &&
++ fd_table[j]->type != FD_NIU &&
++ fd_table[j]->fd.i == kfd ) {
++ return j;
++ }
++ }
++
++ /* Not listed byfd, Check for kernel fd == pthread fd */
++ if( fd_table[kfd] == NULL || fd_table[kfd]->type == FD_NT ) {
++ /* Assume that the kernel fd is the same */
++ return kfd;
++ }
++
++ return NOTOK; /* Not found */
++ }
++
+ /* ==========================================================================
+ * fd_basic_basic_unlock()
+ *
+***************
+*** 288,293 ****
+--- 328,334 ----
+ switch (fd_table[fd]->type) {
+ case FD_NIU:
+ /* If not in use return EBADF error */
++ SET_ERRNO(EBADF);
+ return(NOTOK);
+ break;
+ case FD_NT:
+***************
+*** 297,302 ****
+--- 338,344 ----
+ */
+ fd_kern_init(fd);
+ if (fd_table[fd]->type == FD_NIU) {
++ SET_ERRNO(EBADF);
+ return(NOTOK);
+ }
+ break;
+***************
+*** 409,414 ****
+--- 451,545 ----
+ return(OK);
+ }
+
++ /*----------------------------------------------------------------------
++ * Function: fd_unlock_for_cancel
++ * Purpose: Unlock all fd locks held prior to being cancelled
++ * Args: void
++ * Returns:
++ * OK or NOTOK
++ * Notes:
++ * Assumes the kernel is locked on entry
++ *----------------------------------------------------------------------*/
++ int
++ fd_unlock_for_cancel( void )
++ {
++ int i, fd;
++ struct pthread_select_data *data;
++ int rdlk, wrlk, lktype;
++ int found;
++
++ /* What we do depends on the previous state of the thread */
++ switch( pthread_run->old_state ) {
++ case PS_RUNNING:
++ case PS_JOIN:
++ case PS_SLEEP_WAIT:
++ case PS_WAIT_WAIT:
++ case PS_SIGWAIT:
++ case PS_FDLR_WAIT:
++ case PS_FDLW_WAIT:
++ case PS_DEAD:
++ case PS_UNALLOCED:
++ break; /* Nothing to do */
++
++ case PS_COND_WAIT:
++ CLEAR_PF_GROUP( pthread_run, PF_EVENT_GROUP );
++ /* Must reaquire the mutex according to the standard */
++ if( pthread_run->data.mutex == NULL ) {
++ PANIC();
++ }
++ pthread_mutex_lock( pthread_run->data.mutex );
++ break;
++
++ case PS_FDR_WAIT:
++ CLEAR_PF_GROUP( pthread_run, PF_EVENT_GROUP);
++ /* Free the lock on the fd being used */
++ fd = fd_get_pthread_fd_from_kernel_fd( pthread_run->data.fd.fd );
++ if( fd == NOTOK ) {
++ PANIC(); /* Can't find fd */
++ }
++ fd_unlock( fd, FD_READ );
++ break;
++
++ case PS_FDW_WAIT: /* Waiting on i/o */
++ CLEAR_PF_GROUP( pthread_run, PF_EVENT_GROUP);
++ /* Free the lock on the fd being used */
++ fd = fd_get_pthread_fd_from_kernel_fd( pthread_run->data.fd.fd );
++ if( fd == NOTOK ) {
++ PANIC(); /* Can't find fd */
++ }
++ fd_unlock( fd, FD_WRITE );
++ break;
++
++ case PS_SELECT_WAIT:
++ data = pthread_run->data.select_data;
++
++ CLEAR_PF_GROUP( pthread_run, PF_EVENT_GROUP);
++
++ for( i = 0; i < data->nfds; i++) {
++ rdlk =(FD_ISSET(i,&data->readfds)
++ || FD_ISSET(i,&data->exceptfds));
++ wrlk = FD_ISSET(i, &data->writefds);
++ lktype = rdlk ? (wrlk ? FD_RDWR : FD_READ) : FD_WRITE;
++
++ if( ! (rdlk || wrlk) )
++ continue; /* No locks, no unlock */
++
++ if( (fd = fd_get_pthread_fd_from_kernel_fd( i )) == NOTOK ) {
++ PANIC(); /* Can't find fd */
++ }
++
++ fd_unlock( fd, lktype );
++ }
++ break;
++
++ case PS_MUTEX_WAIT:
++ PANIC(); /* Should never cancel a mutex wait */
++
++ default:
++ PANIC(); /* Unknown thread status */
++ }
++ }
++
+ /* ==========================================================================
+ * fd_lock()
+ */
+***************
+*** 476,481 ****
+--- 607,616 ----
+ ret = fd_table[fd]->ops->read(fd_table[fd]->fd,
+ fd_table[fd]->flags, buf, nbytes, timeout);
+ fd_unlock(fd, FD_READ);
++ if( ret < 0 ) {
++ SET_ERRNO(-ret);
++ ret = NOTOK;
++ }
+ }
+ return(ret);
+ }
+***************
+*** 500,505 ****
+--- 635,644 ----
+ ret = fd_table[fd]->ops->readv(fd_table[fd]->fd,
+ fd_table[fd]->flags, iov, iovcnt, timeout);
+ fd_unlock(fd, FD_READ);
++ if( ret < 0 ) {
++ SET_ERRNO(-ret);
++ ret = NOTOK;
++ }
+ }
+ return(ret);
+ }
+***************
+*** 524,529 ****
+--- 663,672 ----
+ ret = fd_table[fd]->ops->write(fd_table[fd]->fd,
+ fd_table[fd]->flags, buf, nbytes, timeout);
+ fd_unlock(fd, FD_WRITE);
++ if( ret < 0 ) {
++ SET_ERRNO(-ret);
++ ret = NOTOK;
++ }
+ }
+ return(ret);
+ }
+***************
+*** 548,553 ****
+--- 691,700 ----
+ ret = fd_table[fd]->ops->writev(fd_table[fd]->fd,
+ fd_table[fd]->flags, iov, iovcnt, timeout);
+ fd_unlock(fd, FD_WRITE);
++ if( ret < 0 ) {
++ SET_ERRNO(-ret);
++ ret = NOTOK;
++ }
+ }
+ return(ret);
+ }
+***************
+*** 599,677 ****
+ union fd_data realfd;
+ int ret, flags;
+
+ /* Need to lock the newfd by hand */
+! if (fd < dtablesize) {
+! pthread_mutex_lock(&fd_table_mutex);
+! if (fd_table[fd]) {
+! pthread_mutex_unlock(&fd_table_mutex);
+! mutex = &(fd_table[fd]->mutex);
+! pthread_mutex_lock(mutex);
+
+! /*
+! * XXX Gross hack ... because of fork(), any fd closed by the
+! * parent should not change the fd of the child, unless it owns it.
+ */
+! switch(fd_table[fd]->type) {
+! case FD_NIU:
+! pthread_mutex_unlock(mutex);
+! ret = -EINVAL;
+! break;
+! case FD_NT:
+! /*
+! * If it's not tested then the only valid possibility is it's
+! * kernel fd.
+! */
+! ret = machdep_sys_close(fd);
+! fd_table[fd]->type = FD_NIU;
+! pthread_mutex_unlock(mutex);
+! break;
+! case FD_TEST_FULL_DUPLEX:
+! case FD_TEST_HALF_DUPLEX:
+ realfd = fd_table[fd]->fd;
+ flags = fd_table[fd]->flags;
+ if ((entry = fd_free(fd)) == NULL) {
+! ret = fd_table[fd]->ops->close(realfd, flags);
+ } else {
+! /* There can't be any others waiting for fd. */
+ pthread_mutex_unlock(&entry->mutex);
+ /* Note: entry->mutex = mutex */
+- mutex = &(fd_table[fd]->mutex);
+ }
+ pthread_mutex_unlock(mutex);
+- break;
+- default:
+- ret = fd_basic_lock(fd, FD_RDWR, mutex, NULL);
+- if (ret == OK) {
+- realfd = fd_table[fd]->fd;
+- flags = fd_table[fd]->flags;
+- pthread_mutex_unlock(mutex);
+- if ((entry = fd_free(fd)) == NULL) {
+- ret = fd_table[fd]->ops->close(realfd, flags);
+- } else {
+- fd_basic_basic_unlock(entry, FD_RDWR);
+- pthread_mutex_unlock(&entry->mutex);
+- /* Note: entry->mutex = mutex */
+- }
+- fd_unlock(fd, FD_RDWR);
+- } else {
+- pthread_mutex_unlock(mutex);
+- }
+- break;
+ }
+! } else {
+! /* Don't bother creating a table entry */
+! pthread_mutex_unlock(&fd_table_mutex);
+! ret = machdep_sys_close(fd);
+ }
+! return(ret);
+ }
+! return(-EINVAL);
+ }
+
+ /* ==========================================================================
+ * fd_basic_dup()
+ *
+ * Might need to do more than just what's below.
+ */
+ static inline void fd_basic_dup(int fd, int newfd)
+ {
+--- 746,836 ----
+ union fd_data realfd;
+ int ret, flags;
+
++ if( fd < 0 || fd >= dtablesize ) {
++ SET_ERRNO(EBADF);
++ return -1;
++ }
++
+ /* Need to lock the newfd by hand */
+! pthread_mutex_lock(&fd_table_mutex);
+! if (fd_table[fd]) {
+! pthread_mutex_unlock(&fd_table_mutex);
+! mutex = &(fd_table[fd]->mutex);
+! pthread_mutex_lock(mutex);
+
+! /*
+! * XXX Gross hack ... because of fork(), any fd closed by the
+! * parent should not change the fd of the child, unless it owns it.
+! */
+! switch(fd_table[fd]->type) {
+! case FD_NIU:
+! pthread_mutex_unlock(mutex);
+! ret = -EBADF;
+! break;
+! case FD_NT:
+! /*
+! * If it's not tested then the only valid possibility is it's
+! * kernel fd.
+ */
+! ret = machdep_sys_close(fd);
+! fd_table[fd]->type = FD_NIU;
+! pthread_mutex_unlock(mutex);
+! break;
+! case FD_TEST_FULL_DUPLEX:
+! case FD_TEST_HALF_DUPLEX:
+! realfd = fd_table[fd]->fd;
+! flags = fd_table[fd]->flags;
+! if ((entry = fd_free(fd)) == NULL) {
+! ret = fd_table[fd]->ops->close(realfd, flags);
+! } else {
+! /* There can't be any others waiting for fd. */
+! pthread_mutex_unlock(&entry->mutex);
+! /* Note: entry->mutex = mutex */
+! mutex = &(fd_table[fd]->mutex);
+! }
+! pthread_mutex_unlock(mutex);
+! break;
+! default:
+! ret = fd_basic_lock(fd, FD_RDWR, mutex, NULL);
+! if (ret == OK) {
+ realfd = fd_table[fd]->fd;
+ flags = fd_table[fd]->flags;
++ pthread_mutex_unlock(mutex);
+ if ((entry = fd_free(fd)) == NULL) {
+! ret = fd_table[fd]->ops->close(realfd, flags);
+ } else {
+! fd_basic_basic_unlock(entry, FD_RDWR);
+ pthread_mutex_unlock(&entry->mutex);
+ /* Note: entry->mutex = mutex */
+ }
++ fd_unlock(fd, FD_RDWR);
++ } else {
+ pthread_mutex_unlock(mutex);
+ }
+! break;
+ }
+! } else {
+! /* Don't bother creating a table entry */
+! pthread_mutex_unlock(&fd_table_mutex);
+! ret = machdep_sys_close(fd);
+! }
+!
+! if( ret < 0 ) {
+! SET_ERRNO(-ret);
+! ret = -1;
+ }
+!
+! return ret;
+ }
+
+ /* ==========================================================================
+ * fd_basic_dup()
+ *
+ * Might need to do more than just what's below.
++ *
++ * This is a MAJOR guess!! I don't know if the mutext unlock is valid
++ * in the BIG picture. But it seems to be needed to avoid deadlocking
++ * with ourselves when we try to close the duped file descriptor.
+ */
+ static inline void fd_basic_dup(int fd, int newfd)
+ {
+***************
+*** 679,684 ****
+--- 838,845 ----
+ fd_table[fd]->next = fd_table[newfd];
+ fd_table[newfd] = fd_table[fd];
+ fd_table[fd]->count++;
++ pthread_mutex_unlock(&fd_table[newfd]->next->mutex);
++
+ }
+
+ /* ==========================================================================
+***************
+*** 896,904 ****
+ * ala select()... --SNL
+ */
+ int
+! ioctl(int fd, unsigned long request, caddr_t arg)
+ {
+ int ret;
+
+ if (fd < 0 || fd >= dtablesize)
+ ret = NOTOK;
+--- 1057,1071 ----
+ * ala select()... --SNL
+ */
+ int
+! ioctl(int fd, int request, ...)
+ {
+ int ret;
++ pthread_va_list ap;
++ caddr_t arg;
++
++ va_start( ap, request ); /* Get the arg */
++ arg = va_arg(ap,caddr_t);
++ va_end( ap );
+
+ if (fd < 0 || fd >= dtablesize)
+ ret = NOTOK;
+***************
+*** 906,911 ****
+--- 1073,1086 ----
+ ret = machdep_sys_ioctl(fd, request, arg);
+ else if ((ret = fd_lock(fd, FD_RDWR, NULL)) == OK) {
+ ret = machdep_sys_ioctl(fd_table[fd]->fd.i, request, arg);
++ if( ret == 0 && request == FIONBIO ) {
++ /* Properly set NONBLOCK flag */
++ int v = *(int *)arg;
++ if( v )
++ fd_table[fd]->flags |= __FD_NONBLOCK;
++ else
++ fd_table[fd]->flags &= ~__FD_NONBLOCK;
++ }
+ fd_unlock(fd, FD_RDWR);
+ }
+ return ret;
+=================================================================== RCS file: /usr/cvssrc/pthreads-1_60_beta5/pthreads/fd_kern.c,v retrieving revision 1.1.1.1
+diff -c -r1.1.1.1 fd_kern.c
+*** fd_kern.c 1996/02/12 00:58:30 1.1.1.1
+--- fd_kern.c 1996/10/03 01:54:15
+***************
+*** 128,134 ****
+
+
+ if ((count = machdep_sys_select(dtablesize, &fd_set_read,
+! &fd_set_write, NULL, &__fd_kern_poll_timeout)) < OK) {
+ if (count == -EINTR) {
+ return;
+ }
+--- 128,134 ----
+
+
+ if ((count = machdep_sys_select(dtablesize, &fd_set_read,
+! &fd_set_write, &fd_set_except, &__fd_kern_poll_timeout)) < OK) {
+ if (count == -EINTR) {
+ return;
+ }
+***************
+*** 167,200 ****
+
+ for (pthread = fd_wait_select.q_next; count && pthread; ) {
+ int found_one = 0;
+
+ for (i = 0; i < pthread->data.select_data->nfds; i++) {
+ int count_dec = 0;
+
+! if ((FD_ISSET(i, &pthread->data.select_data->exceptfds) &&
+! ! FD_ISSET(i, &fd_set_except))) {
+! FD_CLR(i, &pthread->data.select_data->exceptfds);
+! } else {
+! count_dec++;
+ }
+! if ((FD_ISSET(i, &pthread->data.select_data->writefds) &&
+! ! FD_ISSET(i, &fd_set_write))) {
+! FD_CLR(i, &pthread->data.select_data->writefds);
+! } else {
+! count_dec++;
+ }
+! if ((FD_ISSET(i, &pthread->data.select_data->readfds) &&
+! ! FD_ISSET(i, &fd_set_read))) {
+! FD_CLR(i, &pthread->data.select_data->readfds);
+! } else {
+! count_dec++;
+ }
+ if (count_dec) {
+ found_one++;
+ count--;
+ }
+ }
+ if (found_one) {
+ deq = pthread;
+ pthread = pthread->next;
+ pthread_queue_remove(&fd_wait_select, deq);
+--- 167,223 ----
+
+ for (pthread = fd_wait_select.q_next; count && pthread; ) {
+ int found_one = 0;
++ fd_set tmp_readfds, tmp_writefds, tmp_exceptfds;
++
++ memcpy(&tmp_readfds, &pthread->data.select_data->readfds,
++ sizeof(fd_set));
++ memcpy(&tmp_writefds, &pthread->data.select_data->writefds,
++ sizeof(fd_set));
++ memcpy(&tmp_exceptfds, &pthread->data.select_data->exceptfds,
++ sizeof(fd_set));
+
+ for (i = 0; i < pthread->data.select_data->nfds; i++) {
+ int count_dec = 0;
+
+! if( (FD_ISSET(i, &tmp_exceptfds)) ) {
+! if( FD_ISSET(i, &fd_set_except) ) {
+! count_dec++; /* got a hit */
+! } else {
+! FD_CLR(i, &tmp_exceptfds);
+! }
+ }
+!
+! if( (FD_ISSET(i, &tmp_writefds)) ) {
+! if( FD_ISSET(i, &fd_set_write) ) {
+! count_dec++; /* got a hit */
+! } else {
+! FD_CLR(i, &tmp_writefds);
+! }
+ }
+!
+! if( (FD_ISSET(i, &tmp_readfds)) ) {
+! if( FD_ISSET(i, &fd_set_read) ) {
+! count_dec++; /* got a hit */
+! } else {
+! FD_CLR(i, &tmp_readfds);
+! }
+ }
++
+ if (count_dec) {
+ found_one++;
+ count--;
+ }
+ }
++
+ if (found_one) {
++ /* Update the threads saved select data fd sets */
++ memcpy(&pthread->data.select_data->readfds, &tmp_readfds,
++ sizeof(fd_set));
++ memcpy(&pthread->data.select_data->writefds, &tmp_writefds,
++ sizeof(fd_set));
++ memcpy(&pthread->data.select_data->exceptfds, &tmp_exceptfds,
++ sizeof(fd_set));
++
+ deq = pthread;
+ pthread = pthread->next;
+ pthread_queue_remove(&fd_wait_select, deq);
+***************
+*** 266,272 ****
+ */
+
+ while ((count = machdep_sys_select(dtablesize, &fd_set_read,
+! &fd_set_write, NULL, &__fd_kern_wait_timeout)) < OK) {
+ if (count == -EINTR) {
+ return;
+ }
+--- 289,295 ----
+ */
+
+ while ((count = machdep_sys_select(dtablesize, &fd_set_read,
+! &fd_set_write, &fd_set_except, &__fd_kern_wait_timeout)) < OK) {
+ if (count == -EINTR) {
+ return;
+ }
+***************
+*** 305,338 ****
+
+ for (pthread = fd_wait_select.q_next; count && pthread; ) {
+ int found_one = 0;
+
+ for (i = 0; i < pthread->data.select_data->nfds; i++) {
+ int count_dec = 0;
+
+! if ((FD_ISSET(i, &pthread->data.select_data->exceptfds) &&
+! ! FD_ISSET(i, &fd_set_except))) {
+! FD_CLR(i, &pthread->data.select_data->exceptfds);
+! } else {
+! count_dec++;
+ }
+! if ((FD_ISSET(i, &pthread->data.select_data->writefds) &&
+! ! FD_ISSET(i, &fd_set_write))) {
+! FD_CLR(i, &pthread->data.select_data->writefds);
+! } else {
+! count_dec++;
+ }
+! if ((FD_ISSET(i, &pthread->data.select_data->readfds) &&
+! ! FD_ISSET(i, &fd_set_read))) {
+! FD_CLR(i, &pthread->data.select_data->readfds);
+! } else {
+! count_dec++;
+ }
+ if (count_dec) {
+ found_one++;
+ count--;
+ }
+ }
+ if (found_one) {
+ deq = pthread;
+ pthread = pthread->next;
+ pthread_queue_remove(&fd_wait_select, deq);
+--- 328,383 ----
+
+ for (pthread = fd_wait_select.q_next; count && pthread; ) {
+ int found_one = 0;
++ fd_set tmp_readfds, tmp_writefds, tmp_exceptfds;
++
++ memcpy(&tmp_readfds, &pthread->data.select_data->readfds,
++ sizeof(fd_set));
++ memcpy(&tmp_writefds, &pthread->data.select_data->writefds,
++ sizeof(fd_set));
++ memcpy(&tmp_exceptfds, &pthread->data.select_data->exceptfds,
++ sizeof(fd_set));
+
+ for (i = 0; i < pthread->data.select_data->nfds; i++) {
+ int count_dec = 0;
+
+! if( (FD_ISSET(i, &tmp_exceptfds)) ) {
+! if( FD_ISSET(i, &fd_set_except) ) {
+! count_dec++; /* got a hit */
+! } else {
+! FD_CLR(i, &tmp_exceptfds);
+! }
+ }
+!
+! if( (FD_ISSET(i, &tmp_writefds)) ) {
+! if( FD_ISSET(i, &fd_set_write) ) {
+! count_dec++; /* got a hit */
+! } else {
+! FD_CLR(i, &tmp_writefds);
+! }
+ }
+!
+! if( (FD_ISSET(i, &tmp_readfds)) ) {
+! if( FD_ISSET(i, &fd_set_read) ) {
+! count_dec++; /* got a hit */
+! } else {
+! FD_CLR(i, &tmp_readfds);
+! }
+ }
++
+ if (count_dec) {
+ found_one++;
+ count--;
+ }
+ }
+ if (found_one) {
++ /* Update the threads saved select data fd sets */
++ memcpy(&pthread->data.select_data->readfds, &tmp_readfds,
++ sizeof(fd_set));
++ memcpy(&pthread->data.select_data->writefds, &tmp_writefds,
++ sizeof(fd_set));
++ memcpy(&pthread->data.select_data->exceptfds, &tmp_exceptfds,
++ sizeof(fd_set));
++
+ deq = pthread;
+ pthread = pthread->next;
+ pthread_queue_remove(&fd_wait_select, deq);
+***************
+*** 380,404 ****
+ machdep_gettimeofday(&current_time);
+ sleep_schedule(&current_time, timeout);
+
+ pthread_resched_resume(PS_FDR_WAIT);
+
+ /* We're awake */
+ pthread_sched_prevent();
+ if (sleep_cancel(pthread_run) == NOTOK) {
+ CLEAR_PF_DONE_EVENT(pthread_run);
+ pthread_sched_resume();
+- SET_ERRNO(ETIMEDOUT);
+ ret = -ETIMEDOUT;
+ break;
+ }
+ pthread_sched_resume();
+ } else {
+ pthread_resched_resume(PS_FDR_WAIT);
+ }
+ CLEAR_PF_DONE_EVENT(pthread_run);
+ } else {
+- SET_ERRNO(-ret);
+- ret = NOTOK;
+ break;
+ }
+ }
+--- 425,450 ----
+ machdep_gettimeofday(&current_time);
+ sleep_schedule(&current_time, timeout);
+
++ SET_PF_AT_CANCEL_POINT(pthread_run);
+ pthread_resched_resume(PS_FDR_WAIT);
++ CLEAR_PF_AT_CANCEL_POINT(pthread_run);
+
+ /* We're awake */
+ pthread_sched_prevent();
+ if (sleep_cancel(pthread_run) == NOTOK) {
+ CLEAR_PF_DONE_EVENT(pthread_run);
+ pthread_sched_resume();
+ ret = -ETIMEDOUT;
+ break;
+ }
+ pthread_sched_resume();
+ } else {
++ SET_PF_AT_CANCEL_POINT(pthread_run);
+ pthread_resched_resume(PS_FDR_WAIT);
++ CLEAR_PF_AT_CANCEL_POINT(pthread_run);
+ }
+ CLEAR_PF_DONE_EVENT(pthread_run);
+ } else {
+ break;
+ }
+ }
+***************
+*** 437,443 ****
+ if (sleep_cancel(pthread_run) == NOTOK) {
+ CLEAR_PF_DONE_EVENT(pthread_run);
+ pthread_sched_resume();
+- SET_ERRNO(ETIMEDOUT);
+ ret = -ETIMEDOUT;
+ break;
+ }
+--- 483,488 ----
+***************
+*** 447,454 ****
+ }
+ CLEAR_PF_DONE_EVENT(pthread_run);
+ } else {
+- SET_ERRNO(-ret);
+- ret = NOTOK;
+ break;
+ }
+ }
+--- 492,497 ----
+***************
+*** 480,504 ****
+ machdep_gettimeofday(&current_time);
+ sleep_schedule(&current_time, timeout);
+
+ pthread_resched_resume(PS_FDW_WAIT);
+
+ /* We're awake */
+ pthread_sched_prevent();
+ if (sleep_cancel(pthread_run) == NOTOK) {
+ CLEAR_PF_DONE_EVENT(pthread_run);
+ pthread_sched_resume();
+- SET_ERRNO(ETIMEDOUT);
+ ret = -ETIMEDOUT;
+ break;
+ }
+ pthread_sched_resume();
+ } else {
+ pthread_resched_resume(PS_FDW_WAIT);
+ }
+ CLEAR_PF_DONE_EVENT(pthread_run);
+ } else {
+- SET_ERRNO(-ret);
+- ret = NOTOK;
+ break;
+ }
+ }
+--- 523,548 ----
+ machdep_gettimeofday(&current_time);
+ sleep_schedule(&current_time, timeout);
+
++ SET_PF_AT_CANCEL_POINT(pthread_run);
+ pthread_resched_resume(PS_FDW_WAIT);
++ CLEAR_PF_AT_CANCEL_POINT(pthread_run);
+
+ /* We're awake */
+ pthread_sched_prevent();
+ if (sleep_cancel(pthread_run) == NOTOK) {
+ CLEAR_PF_DONE_EVENT(pthread_run);
+ pthread_sched_resume();
+ ret = -ETIMEDOUT;
+ break;
+ }
+ pthread_sched_resume();
+ } else {
++ SET_PF_AT_CANCEL_POINT(pthread_run);
+ pthread_resched_resume(PS_FDW_WAIT);
++ CLEAR_PF_AT_CANCEL_POINT(pthread_run);
+ }
+ CLEAR_PF_DONE_EVENT(pthread_run);
+ } else {
+ break;
+ }
+ }
+***************
+*** 537,543 ****
+ if (sleep_cancel(pthread_run) == NOTOK) {
+ CLEAR_PF_DONE_EVENT(pthread_run);
+ pthread_sched_resume();
+- SET_ERRNO(ETIMEDOUT);
+ ret = -ETIMEDOUT;
+ break;
+ }
+--- 581,586 ----
+***************
+*** 547,554 ****
+ }
+ CLEAR_PF_DONE_EVENT(pthread_run);
+ } else {
+- SET_ERRNO(-ret);
+- ret = NOTOK;
+ break;
+ }
+ }
+--- 590,595 ----
+***************
+*** 662,668 ****
+ */
+ int create(const char *path, mode_t mode)
+ {
+! return creat (path, mode);
+ }
+
+ /* ==========================================================================
+--- 703,709 ----
+ */
+ int create(const char *path, mode_t mode)
+ {
+! return creat (path, mode);
+ }
+
+ /* ==========================================================================
+***************
+*** 672,678 ****
+
+ int creat(const char *path, mode_t mode)
+ {
+! return open (path, O_CREAT | O_TRUNC | O_WRONLY, mode);
+ }
+
+ /* ==========================================================================
+--- 713,719 ----
+
+ int creat(const char *path, mode_t mode)
+ {
+! return open (path, O_CREAT | O_TRUNC | O_WRONLY, mode);
+ }
+
+ /* ==========================================================================
+***************
+*** 1079,1090 ****
+ int bind(int fd, const struct sockaddr *name, int namelen)
+ {
+ /* Not much to do in bind */
+- semaphore *plock;
+ int ret;
+
+ if ((ret = fd_lock(fd, FD_RDWR, NULL)) == OK) {
+ if ((ret = machdep_sys_bind(fd_table[fd]->fd.i, name, namelen)) < OK) {
+ SET_ERRNO(-ret);
+ }
+ fd_unlock(fd, FD_RDWR);
+ }
+--- 1120,1131 ----
+ int bind(int fd, const struct sockaddr *name, int namelen)
+ {
+ /* Not much to do in bind */
+ int ret;
+
+ if ((ret = fd_lock(fd, FD_RDWR, NULL)) == OK) {
+ if ((ret = machdep_sys_bind(fd_table[fd]->fd.i, name, namelen)) < OK) {
+ SET_ERRNO(-ret);
++ ret = NOTOK;
+ }
+ fd_unlock(fd, FD_RDWR);
+ }
+***************
+*** 1100,1113 ****
+ */
+ int connect(int fd, const struct sockaddr *name, int namelen)
+ {
+! struct sockaddr tmpname;
+! int ret, tmpnamelen;
+
+! if ((ret = fd_lock(fd, FD_RDWR, NULL)) == OK) {
+ if ((ret = machdep_sys_connect(fd_table[fd]->fd.i, name, namelen)) < OK) {
+ if (!(fd_table[fd]->flags & __FD_NONBLOCK) &&
+! ((ret == -EWOULDBLOCK) || (ret == -EINPROGRESS) ||
+! (ret == -EALREADY) || (ret == -EAGAIN))) {
+ pthread_sched_prevent();
+
+ /* queue pthread for a FDW_WAIT */
+--- 1141,1154 ----
+ */
+ int connect(int fd, const struct sockaddr *name, int namelen)
+ {
+! struct sockaddr tmpname;
+! int ret, tmpnamelen;
+
+! if ((ret = fd_lock(fd, FD_RDWR, NULL)) == OK) {
+ if ((ret = machdep_sys_connect(fd_table[fd]->fd.i, name, namelen)) < OK) {
+ if (!(fd_table[fd]->flags & __FD_NONBLOCK) &&
+! ((ret == -EWOULDBLOCK) || (ret == -EINPROGRESS) ||
+! (ret == -EALREADY) || (ret == -EAGAIN))) {
+ pthread_sched_prevent();
+
+ /* queue pthread for a FDW_WAIT */
+***************
+*** 1121,1131 ****
+ tmpnamelen = sizeof(tmpname);
+ /* OK now lets see if it really worked */
+ if (((ret = machdep_sys_getpeername(fd_table[fd]->fd.i,
+! &tmpname, &tmpnamelen)) < OK) && (ret == -ENOTCONN)) {
+
+ /* Get the error, this function should not fail */
+ machdep_sys_getsockopt(fd_table[fd]->fd.i, SOL_SOCKET,
+! SO_ERROR, &pthread_run->error, &tmpnamelen);
+ }
+ } else {
+ SET_ERRNO(-ret);
+--- 1162,1180 ----
+ tmpnamelen = sizeof(tmpname);
+ /* OK now lets see if it really worked */
+ if (((ret = machdep_sys_getpeername(fd_table[fd]->fd.i,
+! &tmpname, &tmpnamelen)) < OK)
+! && (ret == -ENOTCONN)) {
+
+ /* Get the error, this function should not fail */
+ machdep_sys_getsockopt(fd_table[fd]->fd.i, SOL_SOCKET,
+! SO_ERROR, &ret, &tmpnamelen);
+! SET_ERRNO(-ret);
+! ret = NOTOK;
+! } else {
+! if( ret < 0 ) {
+! SET_ERRNO(-ret);
+! ret = NOTOK;
+! }
+ }
+ } else {
+ SET_ERRNO(-ret);
+***************
+*** 1133,1140 ****
+ }
+ }
+ fd_unlock(fd, FD_RDWR);
+! }
+! return(ret);
+ }
+
+ #endif
+--- 1182,1189 ----
+ }
+ }
+ fd_unlock(fd, FD_RDWR);
+! }
+! return(ret);
+ }
+
+ #endif
+***************
+*** 1164,1170 ****
+ } else {
+ fd_unlock(fd, FD_RDWR);
+ SET_ERRNO(-fd_kern);
+! return(fd_kern);
+ }
+ }
+ fd_unlock(fd, FD_RDWR);
+--- 1213,1219 ----
+ } else {
+ fd_unlock(fd, FD_RDWR);
+ SET_ERRNO(-fd_kern);
+! return(NOTOK);
+ }
+ }
+ fd_unlock(fd, FD_RDWR);
+***************
+*** 1198,1205 ****
+ int ret;
+
+ if ((ret = fd_lock(fd, FD_RDWR, NULL)) == OK) {
+! ret = machdep_sys_listen(fd_table[fd]->fd.i, backlog);
+! if ((ret = machdep_sys_listen(fd_table[fd]->fd.i, backlog)) < OK) {
+ SET_ERRNO(-ret);
+ ret = NOTOK;
+ }
+--- 1247,1253 ----
+ int ret;
+
+ if ((ret = fd_lock(fd, FD_RDWR, NULL)) == OK) {
+! if ((ret = machdep_sys_listen(fd_table[fd]->fd.i, backlog)) < OK) {
+ SET_ERRNO(-ret);
+ ret = NOTOK;
+ }
+***************
+*** 1246,1252 ****
+ CLEAR_PF_DONE_EVENT(pthread_run);
+ pthread_sched_resume();
+ SET_ERRNO(ETIMEDOUT);
+! ret = -ETIMEDOUT;
+ break;
+ }
+ pthread_sched_resume();
+--- 1294,1300 ----
+ CLEAR_PF_DONE_EVENT(pthread_run);
+ pthread_sched_resume();
+ SET_ERRNO(ETIMEDOUT);
+! ret = NOTOK;
+ break;
+ }
+ pthread_sched_resume();
+***************
+*** 1311,1317 ****
+ CLEAR_PF_DONE_EVENT(pthread_run);
+ pthread_sched_resume();
+ SET_ERRNO(ETIMEDOUT);
+! ret = -ETIMEDOUT;
+ break;
+ }
+ pthread_sched_resume();
+--- 1359,1365 ----
+ CLEAR_PF_DONE_EVENT(pthread_run);
+ pthread_sched_resume();
+ SET_ERRNO(ETIMEDOUT);
+! ret = NOTOK;
+ break;
+ }
+ pthread_sched_resume();
+***************
+*** 1405,1411 ****
+ CLEAR_PF_DONE_EVENT(pthread_run);
+ pthread_sched_resume();
+ SET_ERRNO(ETIMEDOUT);
+! ret = -ETIMEDOUT;
+ break;
+ }
+ pthread_sched_resume();
+--- 1453,1459 ----
+ CLEAR_PF_DONE_EVENT(pthread_run);
+ pthread_sched_resume();
+ SET_ERRNO(ETIMEDOUT);
+! ret = NOTOK;
+ break;
+ }
+ pthread_sched_resume();
+***************
+*** 1471,1477 ****
+ CLEAR_PF_DONE_EVENT(pthread_run);
+ pthread_sched_resume();
+ SET_ERRNO(ETIMEDOUT);
+! ret = -ETIMEDOUT;
+ break;
+ }
+ pthread_sched_resume();
+--- 1519,1525 ----
+ CLEAR_PF_DONE_EVENT(pthread_run);
+ pthread_sched_resume();
+ SET_ERRNO(ETIMEDOUT);
+! ret = NOTOK;
+ break;
+ }
+ pthread_sched_resume();
+***************
+*** 1536,1542 ****
+ CLEAR_PF_DONE_EVENT(pthread_run);
+ pthread_sched_resume();
+ SET_ERRNO(ETIMEDOUT);
+! ret = -ETIMEDOUT;
+ break;
+ }
+ pthread_sched_resume();
+--- 1584,1590 ----
+ CLEAR_PF_DONE_EVENT(pthread_run);
+ pthread_sched_resume();
+ SET_ERRNO(ETIMEDOUT);
+! ret = NOTOK;
+ break;
+ }
+ pthread_sched_resume();
+***************
+*** 1603,1609 ****
+ CLEAR_PF_DONE_EVENT(pthread_run);
+ pthread_sched_resume();
+ SET_ERRNO(ETIMEDOUT);
+! ret = -ETIMEDOUT;
+ break;
+ }
+ pthread_sched_resume();
+--- 1651,1657 ----
+ CLEAR_PF_DONE_EVENT(pthread_run);
+ pthread_sched_resume();
+ SET_ERRNO(ETIMEDOUT);
+! ret = NOTOK;
+ break;
+ }
+ pthread_sched_resume();
+***************
+*** 1734,1744 ****
+ */
+ int getsockopt(int fd, int level, int optname, void * optval, int * optlen)
+ {
+! int ret;
+
+! if ((ret = fd_lock(fd, FD_READ, NULL)) == OK) {
+ if ((ret = machdep_sys_getsockopt(fd_table[fd]->fd.i, level,
+! optname, optval, optlen)) < OK) {
+ SET_ERRNO(-ret);
+ ret = NOTOK;
+ }
+--- 1782,1792 ----
+ */
+ int getsockopt(int fd, int level, int optname, void * optval, int * optlen)
+ {
+! int ret;
+
+! if ((ret = fd_lock(fd, FD_READ, NULL)) == OK) {
+ if ((ret = machdep_sys_getsockopt(fd_table[fd]->fd.i, level,
+! optname, optval, optlen)) < OK) {
+ SET_ERRNO(-ret);
+ ret = NOTOK;
+ }
+***************
+*** 1756,1772 ****
+ */
+ int getsockname(int fd, struct sockaddr * name, int * naddrlen)
+ {
+! int ret;
+
+! if ((ret = fd_lock(fd, FD_READ, NULL)) == OK) {
+! if ((ret = machdep_sys_getsockname(fd_table[fd]->fd.i,
+! name, naddrlen)) < OK) {
+! SET_ERRNO(-ret);
+! ret = NOTOK;
+! }
+! fd_unlock(fd, FD_RDWR);
+! }
+! return ret;
+ }
+
+ #endif
+--- 1804,1820 ----
+ */
+ int getsockname(int fd, struct sockaddr * name, int * naddrlen)
+ {
+! int ret;
+
+! if ((ret = fd_lock(fd, FD_READ, NULL)) == OK) {
+! if ((ret = machdep_sys_getsockname(fd_table[fd]->fd.i,
+! name, naddrlen)) < OK) {
+! SET_ERRNO(-ret);
+! ret = NOTOK;
+! }
+! fd_unlock(fd, FD_RDWR);
+! }
+! return ret;
+ }
+
+ #endif
+***************
+*** 1778,1793 ****
+ */
+ int getpeername(int fd, struct sockaddr * peer, int * paddrlen)
+ {
+! int ret;
+
+! if ((ret = fd_lock(fd, FD_READ, NULL)) == OK) {
+! if ((ret = machdep_sys_getpeername(fd_table[fd]->fd.i,
+! peer, paddrlen)) < OK) {
+ SET_ERRNO(-ret);
+ ret = NOTOK;
+! }
+! fd_unlock(fd, FD_READ);
+! }
+ return ret;
+ }
+
+--- 1826,1841 ----
+ */
+ int getpeername(int fd, struct sockaddr * peer, int * paddrlen)
+ {
+! int ret;
+
+! if ((ret = fd_lock(fd, FD_READ, NULL)) == OK) {
+! if ((ret = machdep_sys_getpeername(fd_table[fd]->fd.i,
+! peer, paddrlen)) < OK) {
+ SET_ERRNO(-ret);
+ ret = NOTOK;
+! }
+! fd_unlock(fd, FD_READ);
+! }
+ return ret;
+ }
+
+=================================================================== RCS file: /usr/cvssrc/pthreads-1_60_beta5/pthreads/pthread.c,v retrieving revision 1.1.1.1
+diff -c -r1.1.1.1 pthread.c
+*** pthread.c 1995/12/13 05:53:01 1.1.1.1
+--- pthread.c 1996/10/01 21:42:01
+***************
+*** 129,134 ****
+--- 129,160 ----
+
+ }
+
++ /*----------------------------------------------------------------------
++ * Function: __pthread_is_valid
++ * Purpose: Scan the list of threads to see if a specified thread exists
++ * Args:
++ * pthread = The thread to scan for
++ * Returns:
++ * int = 1 if found, 0 if not
++ * Notes:
++ * The kernel is assumed to be locked
++ *----------------------------------------------------------------------*/
++ int
++ __pthread_is_valid( pthread_t pthread )
++ {
++ int rtn = 0; /* Assume not found */
++ pthread_t t;
++
++ for( t = pthread_link_list; t; t = t->pll ) {
++ if( t == pthread ) {
++ rtn = 1; /* Found it */
++ break;
++ }
++ }
++
++ return rtn;
++ }
++
+ /* ==========================================================================
+ * __pthread_free()
+ */
+***************
+*** 242,247 ****
+--- 268,277 ----
+ new_thread->next = NULL;
+ new_thread->flags = 0;
+
++ /* PTHREADS spec says we start with cancellability on and deferred */
++ SET_PF_CANCEL_STATE(new_thread, PTHREAD_CANCEL_ENABLE);
++ SET_PF_CANCEL_TYPE(new_thread, PTHREAD_CANCEL_DEFERRED);
++
+ new_thread->error_p = NULL;
+ new_thread->sll = NULL;
+
+***************
+*** 261,269 ****
+ }
+ return(retval);
+ }
+-
+- /* ==========================================================================
+- * pthread_cancel()
+- *
+- * This routine will also require a sig_prevent/sig_check_and_resume()
+- */
+--- 291,293 ----
+=================================================================== RCS file: /usr/cvssrc/pthreads-1_60_beta5/pthreads/pthread_init.c,v retrieving revision 1.1.1.1
+diff -c -r1.1.1.1 pthread_init.c
+*** pthread_init.c 1996/03/13 04:33:10 1.1.1.1
+--- pthread_init.c 1996/10/01 21:43:59
+***************
+*** 92,99 ****
+ pthread_initial->next = NULL;
+ pthread_initial->flags = 0;
+ pthread_initial->pll = NULL;
+- pthread_initial->flags = 0;
+ pthread_initial->sll = NULL;
+
+ /* Ugly errno hack */
+ pthread_initial->error_p = &errno;
+--- 92,103 ----
+ pthread_initial->next = NULL;
+ pthread_initial->flags = 0;
+ pthread_initial->pll = NULL;
+ pthread_initial->sll = NULL;
++
++ /* PTHREADS spec says we start with cancellability on and deferred */
++ SET_PF_CANCEL_STATE(pthread_initial, PTHREAD_CANCEL_ENABLE);
++ SET_PF_CANCEL_TYPE(pthread_initial, PTHREAD_CANCEL_DEFERRED);
++
+
+ /* Ugly errno hack */
+ pthread_initial->error_p = &errno;
+=================================================================== RCS file: /usr/cvssrc/pthreads-1_60_beta5/pthreads/pthread_join.c,v retrieving revision 1.1.1.1
+diff -c -r1.1.1.1 pthread_join.c
+*** pthread_join.c 1995/12/13 05:53:07 1.1.1.1
+--- pthread_join.c 1996/10/02 16:54:36
+***************
+*** 42,47 ****
+--- 42,49 ----
+ #include <pthread.h>
+ #include <errno.h>
+
++ static int testDeadlock( struct pthread_queue *queue, pthread_t target );
++
+ /* ==========================================================================
+ * pthread_join()
+ */
+***************
+*** 51,56 ****
+--- 53,64 ----
+
+ pthread_sched_prevent();
+
++ /* Ensure they gave us a legal pthread pointer */
++ if( ! __pthread_is_valid( pthread ) ) {
++ pthread_sched_resume();
++ return(EINVAL);
++ }
++
+ /* Check that thread isn't detached already */
+ if (pthread->attr.flags & PTHREAD_DETACHED) {
+ pthread_sched_resume();
+***************
+*** 62,81 ****
+ * Note: This must happen after checking detached state.
+ */
+ if (pthread_queue_remove(&pthread_dead_queue, pthread) != OK) {
+! pthread_queue_enq(&(pthread->join_queue), pthread_run);
+! pthread_resched_resume(PS_JOIN);
+! pthread_sched_prevent();
+!
+! if (pthread_queue_remove(&pthread_dead_queue, pthread) == OK) {
+! pthread_queue_enq(&pthread_alloc_queue, pthread);
+! pthread->attr.flags |= PTHREAD_DETACHED;
+! pthread->state = PS_UNALLOCED;
+! if (thread_return) {
+! *thread_return = pthread->ret;
+! }
+! ret = OK;
+ } else {
+! ret = ESRCH;
+ }
+ } else {
+ /* Just get the return value and detach the thread */
+--- 70,98 ----
+ * Note: This must happen after checking detached state.
+ */
+ if (pthread_queue_remove(&pthread_dead_queue, pthread) != OK) {
+!
+! /* Before we pend on the join, ensure there is no dead lock */
+!
+! if( testDeadlock( &pthread_run->join_queue, pthread ) == NOTOK ) {
+! ret = EDEADLK;
+ } else {
+! pthread_queue_enq(&(pthread->join_queue), pthread_run);
+! SET_PF_AT_CANCEL_POINT(pthread_run); /* This is a cancel point */
+! pthread_resched_resume(PS_JOIN);
+! CLEAR_PF_AT_CANCEL_POINT(pthread_run); /* No longer at cancel point */
+! pthread_sched_prevent();
+!
+! if (pthread_queue_remove(&pthread_dead_queue, pthread) == OK) {
+! pthread_queue_enq(&pthread_alloc_queue, pthread);
+! pthread->attr.flags |= PTHREAD_DETACHED;
+! pthread->state = PS_UNALLOCED;
+! if (thread_return) {
+! *thread_return = pthread->ret;
+! }
+! ret = OK;
+! } else {
+! ret = ESRCH;
+! }
+ }
+ } else {
+ /* Just get the return value and detach the thread */
+***************
+*** 89,92 ****
+--- 106,139 ----
+ }
+ pthread_sched_resume();
+ return(ret);
++ }
++
++ /*----------------------------------------------------------------------
++ * Function: testDeadlock
++ * Purpose: recursive queue walk to check for deadlocks
++ * Args:
++ * queue = the queue to walk
++ * pthread = target to scan for
++ * Returns:
++ * OK = no deadlock, NOTOK = deadlock
++ * Notes:
++ *----------------------------------------------------------------------*/
++ static int
++ testDeadlock( struct pthread_queue *queue, pthread_t target )
++ {
++ pthread_t t;
++
++ if( queue == NULL )
++ return OK; /* Empty queue, obviously ok */
++
++ for( t = queue->q_next; t; t = t->next ) {
++ if( t == target )
++ return NOTOK; /* bang, your dead */
++
++ if( testDeadlock( &t->join_queue, target ) == NOTOK ) {
++ return NOTOK;
++ }
++ }
++
++ return OK; /* No deadlock */
+ }
+=================================================================== RCS file: /usr/cvssrc/pthreads-1_60_beta5/pthreads/select.c,v retrieving revision 1.1.1.1
+diff -c -r1.1.1.1 select.c
+*** select.c 1996/03/05 08:29:14 1.1.1.1
+--- select.c 1996/10/02 16:56:27
+***************
+*** 56,220 ****
+ int select(int numfds, fd_set *readfds, fd_set *writefds,
+ fd_set *exceptfds, struct timeval *timeout)
+ {
+! fd_set real_exceptfds, real_readfds, real_writefds; /* mapped fd_sets */
+! fd_set * real_readfds_p, * real_writefds_p, * real_exceptfds_p;
+! fd_set read_locks, write_locks, rdwr_locks;
+! struct timespec timeout_time, current_time;
+! struct timeval zero_timeout = { 0, 0 };
+! int i, j, ret = 0, got_all_locks = 1;
+! struct pthread_select_data data;
+!
+! if (numfds > dtablesize) {
+! numfds = dtablesize;
+! }
+!
+! data.nfds = 0;
+! FD_ZERO(&data.readfds);
+! FD_ZERO(&data.writefds);
+! FD_ZERO(&data.exceptfds);
+
+! /* Do this first */
+! if (timeout) {
+ machdep_gettimeofday(&current_time);
+! timeout_time.tv_sec = current_time.tv_sec + timeout->tv_sec;
+! if ((timeout_time.tv_nsec = current_time.tv_nsec +
+! (timeout->tv_usec * 1000)) > 1000000000) {
+! timeout_time.tv_nsec -= 1000000000;
+! timeout_time.tv_sec++;
+! }
+! }
+!
+! FD_ZERO(&read_locks);
+! FD_ZERO(&write_locks);
+! FD_ZERO(&rdwr_locks);
+! FD_ZERO(&real_readfds);
+! FD_ZERO(&real_writefds);
+! FD_ZERO(&real_exceptfds);
+!
+! /* lock readfds */
+! if (readfds || writefds || exceptfds) {
+! for (i = 0; i < numfds; i++) {
+! if ((readfds && (FD_ISSET(i, readfds))) ||
+! (exceptfds && FD_ISSET(i, exceptfds))) {
+! if (writefds && FD_ISSET(i ,writefds)) {
+! if ((ret = fd_lock(i, FD_RDWR, NULL)) != OK) {
+! got_all_locks = 0;
+! break;
+! }
+! FD_SET(i, &rdwr_locks);
+! FD_SET(fd_table[i]->fd.i,&real_writefds);
+! } else {
+! if ((ret = fd_lock(i, FD_READ, NULL)) != OK) {
+! got_all_locks = 0;
+! break;
+! }
+! FD_SET(i, &read_locks);
+! }
+! if (readfds && FD_ISSET(i,readfds)) {
+! FD_SET(fd_table[i]->fd.i, &real_readfds);
+! }
+! if (exceptfds && FD_ISSET(i,exceptfds)) {
+! FD_SET(fd_table[i]->fd.i, &real_exceptfds);
+! }
+! if (fd_table[i]->fd.i >= data.nfds) {
+! data.nfds = fd_table[i]->fd.i + 1;
+! }
+! } else {
+! if (writefds && FD_ISSET(i, writefds)) {
+! if ((ret = fd_lock(i, FD_WRITE, NULL)) != OK) {
+! got_all_locks = 0;
+! break;
+! }
+! FD_SET(i, &write_locks);
+! FD_SET(fd_table[i]->fd.i,&real_writefds);
+! }
+! if (fd_table[i]->fd.i >= data.nfds) {
+! data.nfds = fd_table[i]->fd.i + 1;
+! }
+! }
+! }
+! }
+!
+! if (got_all_locks) {
+!
+! memcpy(&data.readfds,&real_readfds,sizeof(fd_set));
+! memcpy(&data.writefds,&real_writefds,sizeof(fd_set));
+! memcpy(&data.exceptfds,&real_exceptfds,sizeof(fd_set));
+!
+! real_readfds_p = (readfds == NULL) ? NULL : &real_readfds;
+! real_writefds_p = (writefds == NULL) ? NULL : &real_writefds;
+! real_exceptfds_p = (exceptfds == NULL) ? NULL : &real_exceptfds;
+!
+! if ((ret = machdep_sys_select(data.nfds, real_readfds_p,
+! real_writefds_p, real_exceptfds_p, &zero_timeout)) == OK) {
+!
+! pthread_sched_prevent();
+!
+! real_exceptfds_p = (exceptfds == NULL) ? NULL : &data.exceptfds;
+! real_writefds_p = (writefds == NULL) ? NULL : &data.writefds;
+! real_readfds_p = (readfds == NULL) ? NULL : &data.readfds;
+!
+! pthread_queue_enq(&fd_wait_select, pthread_run);
+! pthread_run->data.select_data = &data;
+! SET_PF_WAIT_EVENT(pthread_run);
+!
+! if (timeout) {
+! machdep_gettimeofday(&current_time);
+! sleep_schedule(&current_time, &timeout_time);
+!
+! pthread_resched_resume(PS_SELECT_WAIT);
+!
+! /* We're awake */
+! CLEAR_PF_DONE_EVENT(pthread_run);
+! if (sleep_cancel(pthread_run) == NOTOK) {
+! ret = OK;
+! } else {
+! ret = data.nfds;
+! }
+! } else {
+! pthread_resched_resume(PS_SELECT_WAIT);
+! CLEAR_PF_DONE_EVENT(pthread_run);
+! ret = data.nfds; /* XXX ??? snl */
+! }
+! } else if (ret < 0) {
+! SET_ERRNO(-ret);
+! ret = NOTOK;
+! }
+! }
+!
+! /* clean up the locks */
+! for (i = 0; i < numfds; i++)
+! if (FD_ISSET(i,&read_locks)) fd_unlock(i,FD_READ);
+! for (i = 0; i < numfds; i++)
+! if (FD_ISSET(i,&rdwr_locks)) fd_unlock(i,FD_RDWR);
+! for (i = 0; i < numfds; i++)
+! if (FD_ISSET(i,&write_locks)) fd_unlock(i,FD_WRITE);
+!
+! if (ret > 0) {
+! if (readfds != NULL) {
+! for (i = 0; i < numfds; i++) {
+! if (! (FD_ISSET(i,readfds) &&
+! FD_ISSET(fd_table[i]->fd.i,real_readfds_p)))
+! FD_CLR(i,readfds);
+! }
+! }
+! if (writefds != NULL) {
+! for (i = 0; i < numfds; i++)
+! if (! (FD_ISSET(i,writefds) &&
+! FD_ISSET(fd_table[i]->fd.i,real_writefds_p)))
+! FD_CLR(i,writefds);
+! }
+! if (exceptfds != NULL) {
+! for (i = 0; i < numfds; i++)
+! if (! (FD_ISSET(i,exceptfds) &&
+! FD_ISSET(fd_table[i]->fd.i,real_exceptfds_p)))
+! FD_CLR(i,exceptfds);
+! }
+! } else {
+! if (exceptfds != NULL) FD_ZERO(exceptfds);
+! if (writefds != NULL) FD_ZERO(writefds);
+! if (readfds != NULL) FD_ZERO(readfds);
+ }
+
+! return(ret);
+ }
+--- 56,223 ----
+ int select(int numfds, fd_set *readfds, fd_set *writefds,
+ fd_set *exceptfds, struct timeval *timeout)
+ {
+! fd_set real_exceptfds, real_readfds, real_writefds; /* mapped fd_sets */
+! fd_set * real_readfds_p, * real_writefds_p, * real_exceptfds_p;
+! fd_set read_locks, write_locks, rdwr_locks;
+! struct timespec timeout_time, current_time;
+! struct timeval zero_timeout = { 0, 0 };
+! int i, j, ret = 0, got_all_locks = 1;
+! struct pthread_select_data data;
+!
+! if (numfds > dtablesize) {
+! numfds = dtablesize;
+! }
+!
+! data.nfds = 0;
+! FD_ZERO(&data.readfds);
+! FD_ZERO(&data.writefds);
+! FD_ZERO(&data.exceptfds);
+!
+! /* Do this first */
+! if (timeout) {
+! machdep_gettimeofday(&current_time);
+! timeout_time.tv_sec = current_time.tv_sec + timeout->tv_sec;
+! if ((timeout_time.tv_nsec = current_time.tv_nsec +
+! (timeout->tv_usec * 1000)) > 1000000000) {
+! timeout_time.tv_nsec -= 1000000000;
+! timeout_time.tv_sec++;
+! }
+! }
+!
+! FD_ZERO(&read_locks);
+! FD_ZERO(&write_locks);
+! FD_ZERO(&rdwr_locks);
+! FD_ZERO(&real_readfds);
+! FD_ZERO(&real_writefds);
+! FD_ZERO(&real_exceptfds);
+!
+! /* lock readfds */
+! if (readfds || writefds || exceptfds) {
+! for (i = 0; i < numfds; i++) {
+! if ((readfds && (FD_ISSET(i, readfds))) ||
+! (exceptfds && FD_ISSET(i, exceptfds))) {
+! if (writefds && FD_ISSET(i ,writefds)) {
+! if ((ret = fd_lock(i, FD_RDWR, NULL)) != OK) {
+! got_all_locks = 0;
+! break;
+! }
+! FD_SET(i, &rdwr_locks);
+! FD_SET(fd_table[i]->fd.i,&real_writefds);
+! } else {
+! if ((ret = fd_lock(i, FD_READ, NULL)) != OK) {
+! got_all_locks = 0;
+! break;
+! }
+! FD_SET(i, &read_locks);
+! }
+! if (readfds && FD_ISSET(i,readfds)) {
+! FD_SET(fd_table[i]->fd.i, &real_readfds);
+! }
+! if (exceptfds && FD_ISSET(i,exceptfds)) {
+! FD_SET(fd_table[i]->fd.i, &real_exceptfds);
+! }
+! if (fd_table[i]->fd.i >= data.nfds) {
+! data.nfds = fd_table[i]->fd.i + 1;
+! }
+! } else {
+! if (writefds && FD_ISSET(i, writefds)) {
+! if ((ret = fd_lock(i, FD_WRITE, NULL)) != OK) {
+! got_all_locks = 0;
+! break;
+! }
+! FD_SET(i, &write_locks);
+! FD_SET(fd_table[i]->fd.i,&real_writefds);
+! if (fd_table[i]->fd.i >= data.nfds) {
+! data.nfds = fd_table[i]->fd.i + 1;
+! }
+! }
+! }
+! }
+! }
+!
+! if (got_all_locks) {
+! memcpy(&data.readfds,&real_readfds,sizeof(fd_set));
+! memcpy(&data.writefds,&real_writefds,sizeof(fd_set));
+! memcpy(&data.exceptfds,&real_exceptfds,sizeof(fd_set));
+!
+! real_readfds_p = (readfds == NULL) ? NULL : &real_readfds;
+! real_writefds_p = (writefds == NULL) ? NULL : &real_writefds;
+! real_exceptfds_p = (exceptfds == NULL) ? NULL : &real_exceptfds;
+!
+! if ((ret = machdep_sys_select(data.nfds, real_readfds_p,
+! real_writefds_p, real_exceptfds_p,
+! &zero_timeout)) == OK) {
+! pthread_sched_prevent();
+!
+! real_exceptfds_p = (exceptfds == NULL) ? NULL : &data.exceptfds;
+! real_writefds_p = (writefds == NULL) ? NULL : &data.writefds;
+! real_readfds_p = (readfds == NULL) ? NULL : &data.readfds;
+!
+! pthread_queue_enq(&fd_wait_select, pthread_run);
+! pthread_run->data.select_data = &data;
+! SET_PF_WAIT_EVENT(pthread_run);
+
+! if (timeout) {
+ machdep_gettimeofday(&current_time);
+! sleep_schedule(&current_time, &timeout_time);
+!
+! SET_PF_AT_CANCEL_POINT(pthread_run);
+! pthread_resched_resume(PS_SELECT_WAIT);
+! CLEAR_PF_AT_CANCEL_POINT(pthread_run);
+!
+! /* We're awake */
+! CLEAR_PF_DONE_EVENT(pthread_run);
+! if (sleep_cancel(pthread_run) == NOTOK) {
+! ret = OK;
+! } else {
+! ret = data.nfds;
+! }
+! } else {
+! SET_PF_AT_CANCEL_POINT(pthread_run);
+! pthread_resched_resume(PS_SELECT_WAIT);
+! CLEAR_PF_AT_CANCEL_POINT(pthread_run);
+! CLEAR_PF_DONE_EVENT(pthread_run);
+! ret = data.nfds; /* XXX ??? snl */
+! }
+! } else if (ret < 0) {
+! SET_ERRNO(-ret);
+! ret = NOTOK;
+! }
+! }
+!
+! /* clean up the locks */
+! for (i = 0; i < numfds; i++)
+! if (FD_ISSET(i,&read_locks)) fd_unlock(i,FD_READ);
+! for (i = 0; i < numfds; i++)
+! if (FD_ISSET(i,&rdwr_locks)) fd_unlock(i,FD_RDWR);
+! for (i = 0; i < numfds; i++)
+! if (FD_ISSET(i,&write_locks)) fd_unlock(i,FD_WRITE);
+!
+! if (ret > 0) {
+! if (readfds != NULL) {
+! for (i = 0; i < numfds; i++) {
+! if (! (FD_ISSET(i,readfds) &&
+! FD_ISSET(fd_table[i]->fd.i,real_readfds_p)))
+! FD_CLR(i,readfds);
+! }
+! }
+! if (writefds != NULL) {
+! for (i = 0; i < numfds; i++)
+! if (! (FD_ISSET(i,writefds) &&
+! FD_ISSET(fd_table[i]->fd.i,real_writefds_p)))
+! FD_CLR(i,writefds);
+! }
+! if (exceptfds != NULL) {
+! for (i = 0; i < numfds; i++)
+! if (! (FD_ISSET(i,exceptfds) &&
+! FD_ISSET(fd_table[i]->fd.i,real_exceptfds_p)))
+! FD_CLR(i,exceptfds);
+ }
++ } else {
++ if (exceptfds != NULL) FD_ZERO(exceptfds);
++ if (writefds != NULL) FD_ZERO(writefds);
++ if (readfds != NULL) FD_ZERO(readfds);
++ }
+
+! return(ret);
+ }
+=================================================================== RCS file: /usr/cvssrc/pthreads-1_60_beta5/pthreads/sig.c,v retrieving revision 1.1.1.1
+diff -c -r1.1.1.1 sig.c
+*** sig.c 1996/03/13 04:33:13 1.1.1.1
+--- sig.c 1996/10/03 01:07:54
+***************
+*** 301,307 ****
+--- 301,310 ----
+ pthread_run->data.sigwait = set;
+ pthread_run->ret = sig;
+
++ SET_PF_AT_CANCEL_POINT(pthread_run); /* This is a cancel point */
+ pthread_resched_resume(PS_SIGWAIT);
++ CLEAR_PF_AT_CANCEL_POINT(pthread_run); /* No longer at cancel point */
++
+ return(OK);
+ }
+
+=================================================================== RCS file: /usr/cvssrc/pthreads-1_60_beta5/pthreads/signal.c,v retrieving revision 1.1.1.1
+diff -c -r1.1.1.1 signal.c
+*** signal.c 1996/03/13 04:33:17 1.1.1.1
+--- signal.c 1996/10/03 17:30:16
+***************
+*** 72,77 ****
+--- 72,78 ----
+
+ static void sig_handler(int signal);
+ static void set_thread_timer();
++ static void __cleanup_after_resume( void );
+ void sig_prevent(void);
+ void sig_resume(void);
+
+***************
+*** 482,502 ****
+ }
+ }
+
+! /* Only bother if we are truly unlocking the kernel */
+! while (!(--pthread_kernel_lock)) {
+! if (sig_to_process) {
+! /* if (SIG_ANY(sig_to_process)) { */
+! pthread_kernel_lock++;
+! sig_handler(0);
+! continue;
+! }
+! if (pthread_run && pthread_run->sigcount) {
+! pthread_kernel_lock++;
+! pthread_sig_process();
+! continue;
+! }
+! break;
+! }
+ }
+
+ /* ==========================================================================
+--- 483,489 ----
+ }
+ }
+
+! __cleanup_after_resume();
+ }
+
+ /* ==========================================================================
+***************
+*** 508,530 ****
+ void pthread_resched_resume(enum pthread_state state)
+ {
+ pthread_run->state = state;
+- sig_handler(SIGVTALRM);
+
+! /* Only bother if we are truely unlocking the kernel */
+! while (!(--pthread_kernel_lock)) {
+! if (sig_to_process) {
+! /* if (SIG_ANY(sig_to_process)) { */
+! pthread_kernel_lock++;
+! sig_handler(0);
+! continue;
+! }
+! if (pthread_run && pthread_run->sigcount) {
+! pthread_kernel_lock++;
+! pthread_sig_process();
+! continue;
+! }
+! break;
+ }
+ }
+
+ /* ==========================================================================
+--- 495,523 ----
+ void pthread_resched_resume(enum pthread_state state)
+ {
+ pthread_run->state = state;
+
+! /* Since we are about to block this thread, lets see if we are
+! * at a cancel point and if we've been cancelled.
+! * Avoid cancelling dead or unalloced threads.
+! */
+! if( ! TEST_PF_RUNNING_TO_CANCEL(pthread_run) &&
+! TEST_PTHREAD_IS_CANCELLABLE(pthread_run) &&
+! state != PS_DEAD && state != PS_UNALLOCED ) {
+!
+! /* Set this flag to avoid recursively calling pthread_exit */
+! /* We have to set this flag here because we will unlock the
+! * kernel prior to calling pthread_cancel_internal.
+! */
+! SET_PF_RUNNING_TO_CANCEL(pthread_run);
+!
+! pthread_run->old_state = state; /* unlock needs this data */
+! pthread_sched_resume(); /* Unlock kernel before cancel */
+! pthread_cancel_internal( 1 ); /* free locks and exit */
+ }
++
++ sig_handler(SIGVTALRM);
++
++ __cleanup_after_resume();
+ }
+
+ /* ==========================================================================
+***************
+*** 532,537 ****
+--- 525,543 ----
+ */
+ void pthread_sched_resume()
+ {
++ __cleanup_after_resume();
++ }
++
++ /*----------------------------------------------------------------------
++ * Function: __cleanup_after_resume
++ * Purpose: cleanup kernel locks after a resume
++ * Args: void
++ * Returns: void
++ * Notes:
++ *----------------------------------------------------------------------*/
++ static void
++ __cleanup_after_resume( void )
++ {
+ /* Only bother if we are truely unlocking the kernel */
+ while (!(--pthread_kernel_lock)) {
+ /* if (SIG_ANY(sig_to_process)) { */
+***************
+*** 546,551 ****
+--- 552,568 ----
+ continue;
+ }
+ break;
++ }
++
++ if( pthread_run == NULL )
++ return; /* Must be during init processing */
++
++ /* Test for cancel that should be handled now */
++
++ if( ! TEST_PF_RUNNING_TO_CANCEL(pthread_run) &&
++ TEST_PTHREAD_IS_CANCELLABLE(pthread_run) ) {
++ /* Kernel is already unlocked */
++ pthread_cancel_internal( 1 ); /* free locks and exit */
+ }
+ }
+
+=================================================================== RCS file: /usr/cvssrc/pthreads-1_60_beta5/pthreads/sleep.c,v retrieving revision 1.1.1.1
+diff -c -r1.1.1.1 sleep.c
+*** sleep.c 1996/03/11 08:33:32 1.1.1.1
+--- sleep.c 1996/10/03 01:14:58
+***************
+*** 249,255 ****
+--- 249,257 ----
+
+ /* Reschedule thread */
+ SET_PF_WAIT_EVENT(pthread_run);
++ SET_PF_AT_CANCEL_POINT(pthread_run); /* This is a cancel point */
+ pthread_resched_resume(PS_SLEEP_WAIT);
++ CLEAR_PF_AT_CANCEL_POINT(pthread_run); /* No longer at cancel point */
+ CLEAR_PF_DONE_EVENT(pthread_run);
+
+ /* Return actual time slept */
+***************
+*** 332,338 ****
+ current_time.tv_sec++;
+ }
+ machdep_start_timer(&(current_time),
+! &(pthread_sleep->wakeup_time));
+ }
+ } else {
+ for (pthread_last = pthread_sleep; pthread_last;
+--- 334,340 ----
+ current_time.tv_sec++;
+ }
+ machdep_start_timer(&(current_time),
+! &(pthread_sleep->wakeup_time));
+ }
+ } else {
+ for (pthread_last = pthread_sleep; pthread_last;
+=================================================================== RCS file: /usr/cvssrc/pthreads-1_60_beta5/pthreads/stat.c,v retrieving revision 1.1.1.1
+diff -c -r1.1.1.1 stat.c
+*** stat.c 1995/09/21 02:36:05 1.1.1.1
+--- stat.c 1996/06/04 19:17:33
+***************
+*** 43,48 ****
+--- 43,49 ----
+ #include <errno.h>
+
+ struct stat;
++ struct statfs;
+
+ /* ==========================================================================
+ * fstat()
+***************
+*** 91,95 ****
+--- 92,115 ----
+ }
+ return(ret);
+
++ }
++
++ /* ==========================================================================
++ * fstatfs()
++ *
++ * Might want to indirect this.
++ */
++ int fstatfs(int fd, struct statfs *buf)
++ {
++ int ret;
++
++ if ((ret = fd_lock(fd, FD_READ, NULL)) == OK) {
++ if ((ret = machdep_sys_fstatfs(fd_table[fd]->fd.i, buf)) < OK) {
++ SET_ERRNO(-ret);
++ ret = NOTOK;
++ }
++ fd_unlock(fd, FD_READ);
++ }
++ return(ret);
+ }
+
+=================================================================== RCS file: /usr/cvssrc/pthreads-1_60_beta5/pthreads/wait.c,v retrieving revision 1.1.1.1
+diff -c -r1.1.1.1 wait.c
+*** wait.c 1995/02/21 08:07:24 1.1.1.1
+--- wait.c 1996/10/03 01:20:02
+***************
+*** 103,109 ****
+--- 103,111 ----
+ pthread_queue_enq(&wait_queue, pthread_run);
+
+ /* reschedule unlocks scheduler */
++ SET_PF_AT_CANCEL_POINT(pthread_run); /* This is a cancel point */
+ pthread_resched_resume(PS_WAIT_WAIT);
++ CLEAR_PF_AT_CANCEL_POINT(pthread_run); /* No longer at cancel point */
+
+ pthread_sched_prevent();
+ }
+***************
+*** 126,132 ****
+--- 128,136 ----
+ pthread_queue_enq(&wait_queue, pthread_run);
+
+ /* reschedule unlocks scheduler */
++ SET_PF_AT_CANCEL_POINT(pthread_run); /* This is a cancel point */
+ pthread_resched_resume(PS_WAIT_WAIT);
++ CLEAR_PF_AT_CANCEL_POINT(pthread_run); /* No longer at cancel point */
+
+ pthread_sched_prevent();
+ }
+<pre><font size=-1>
diff --git a/mit-pthreads/patches/Streepy2.html b/mit-pthreads/patches/Streepy2.html
new file mode 100755
index 00000000000..80d44d6440c
--- /dev/null
+++ b/mit-pthreads/patches/Streepy2.html
@@ -0,0 +1,93 @@
+<html>
+<head>
+ <title>Diffs on diffs :-) by Larry V. Streepy, Jr.</title>
+ <base target=_top>
+ <meta name="GENERATOR" content="FindMail Communications">
+ <meta name="Date" content="Monday, October 07, 1996 02:03 PM PST">
+ <meta name="Author" content="Larry V. Streepy, Jr.">
+</head>
+<body background="/gifs/betafm.gif" bgcolor="#ffffff" text="#000000" link="#0000ee" vlink="#ff0000" alink="#000099">
+<h3>Diffs on diffs :-)</h3>
+Larry V. Streepy, Jr. (<a href="mailto.html?mid=2079859748&num=398" target="_top">@healthcare.com</a>)<br>Monday, October 07, 1996 02:03 PM PST<br>
+<p>
+This is a multi-part message in MIME format.<p>
+--------------65BE18E23639BCDD7BE55F7F <br>
+Content-Type: text/plain; charset=us-ascii <br>
+Content-Transfer-Encoding: 7bit<p>
+Unfortunately, there are a couple of bugs in my pthread_cancel support (no, say it isn't so :-)<p>
+Oh well, I cam across a couple of cases that I missed in my testing last week. Here are the bugs:<p>
+1. If a thread calls pthread_testcancel during it's cleanup processing after being cancelled, the pthread kernel would hang.<p>
+2. I didn't realize that threads in PS_SLEEP_WAIT state are *NOT* on any queue, they are handled using a linked list. So, when cancelling a thread that was sleeping, a PANIC() I put in possiblymakeRunnable would go off.<p>
+Both of these are fixed. The diffs are attached.<br>
+-- <br>
+Larry V. Streepy, Jr. <br>
+Chief Technical Officer, Healthcare Communications, Inc. mailto:<a href="mailto.html?mid=2079859748&num=398" target="_top">@healthcare.com</a> <br>
+(214) 851-7033 (Dallas Main #) <br>
+(970) 626-5028 (My office #) (970) 626-4425 (Fax)<p>
+--------------65BE18E23639BCDD7BE55F7F <br>
+Content-Type: text/plain; charset=us-ascii; name=&#34;cancel.diffs&#34; Content-Transfer-Encoding: 7bit <br>
+Content-Disposition: inline; filename=&#34;cancel.diffs&#34;<p>
+Index: pthread_cancel.c<br>
+=================================================================== RCS file: /usr/cvssrc/pthreads-1_60_beta5/pthreads/pthread_cancel.c,v retrieving revision 1.1 <br>
+diff -c -r1.1 pthread_cancel.c<br>
+*** pthread_cancel.c 1996/10/06 00:31:27 1.1<br>
+--- pthread_cancel.c 1996/10/07 18:33:27<br>
+***************<br>
+*** 187,192 ****<br>
+--- 187,197 ----<br>
+ return; /* Can't be cancelled */<br>
+ }<br>
+ <br>
++ /* Ensure that we aren't in the process of exiting already */<br>
++ if( TEST_PF_RUNNING_TO_CANCEL(pthread_run) ) {<br>
++ return;<br>
++ }<br>
++ <br>
+ /* See if we have been cancelled */<br>
+ if( TEST_PF_CANCELLED(pthread_run) ) {<br>
+ /* Set this flag to avoid recursively calling pthread_exit */<br>
+***************<br>
+*** 266,277 ****<br>
+ if( pthread-&gt;state == PS_RUNNING )<br>
+ return; /* will happen at context switch */<br>
+ <br>
+! /* Otherwise, we need to take it off the queue and make it runnable */<br>
+! if( pthread-&gt;queue == NULL ) {<br>
+! PANIC(); /* Must be on a queue */<br>
+! }<br>
+ <br>
+- pthread_queue_remove(pthread-&gt;queue, pthread);<br>
+ pthread_prio_queue_enq(pthread_current_prio_queue, pthread);<br>
+ pthread-&gt;old_state = pthread-&gt;state;<br>
+ pthread-&gt;state = PS_RUNNING;<br>
+--- 271,291 ----<br>
+ if( pthread-&gt;state == PS_RUNNING )<br>
+ return; /* will happen at context switch */<br>
+ <br>
+! /* If the thread is sleeping, the it isn't on a queue. */<br>
+! if( pthread-&gt;state == PS_SLEEP_WAIT ) {<br>
+! sleep_cancel( pthread ); /* Remove from sleep list */<br>
+! } else {<br>
+! /* Otherwise, we need to take it off the queue and make it runnable */<br>
+! <br>
+! if( pthread-&gt;queue == NULL ) {<br>
+! PANIC(); /* Must be on a queue */<br>
+! }<br>
+! <br>
+! pthread_queue_remove(pthread-&gt;queue, pthread);<br>
+! }<br>
+! <br>
+! /* And make it runnable */<br>
+ <br>
+ pthread_prio_queue_enq(pthread_current_prio_queue, pthread);<br>
+ pthread-&gt;old_state = pthread-&gt;state;<br>
+ pthread-&gt;state = PS_RUNNING;<p>
+<pre><font size=-1>
+--------------65BE18E23639BCDD7BE55F7F--
+
+</pre><p></pre>
+<hr>
+<a href="http://www.findmail.com/" target="_top"><font size=-1>Powered by FindMail Communications</font><br></a>
+<br>Please email comments and suggestions to:<a href="/cgi-bin/comments.py" target="_top">comments@findmail.com</a>
+<br><font size=-3 color="#ffffff">xmlarchive</font>
+</body></html> \ No newline at end of file
diff --git a/mit-pthreads/patches/bill_lear b/mit-pthreads/patches/bill_lear
new file mode 100755
index 00000000000..f49b79c4272
--- /dev/null
+++ b/mit-pthreads/patches/bill_lear
@@ -0,0 +1,70 @@
+From rael@dejanews.com Wed Jan 29 06:06:14 1997
+X-VM-v5-Data: ([nil nil nil t nil nil nil nil nil]
+ ["1497" "Tue" "28" "January" "1997" "21:52:57" "-0600" "William S. Lear" "rael@dejanews.com" "<199701290352.VAA08678@homer.dejanews.com>" "53" "Patches for linux2.0" "^From:" nil nil "1" "1997012903:52:57" "Patches for linux2.0" nil nil]
+ nil)
+Received: from MIT.EDU (PACIFIC-CARRIER-ANNEX.MIT.EDU [18.69.0.28])
+ by analytik.analytikerna.se (8.8.4/8.8.4) with SMTP
+ id GAA23245 for <monty@analytikerna.se>; Wed, 29 Jan 1997 06:06:12 +0100 (MET)
+Received: from host-205-238-143-2.dejanews.com by MIT.EDU with SMTP
+ id AA25254; Tue, 28 Jan 97 22:53:08 EST
+Received: (from rael@localhost) by homer.dejanews.com (8.7.6/8.6.12) id VAA08678 for pthreads@mit.edu; Tue, 28 Jan 1997 21:52:57 -0600 (CST)
+Message-Id: <199701290352.VAA08678@homer.dejanews.com>
+Content-Length: 1496
+From: "William S. Lear" <rael@dejanews.com>
+To: pthreads@MIT.EDU
+Subject: Patches for linux2.0
+Date: Tue, 28 Jan 1997 21:52:57 -0600 (CST)
+
+
+The following are some patches I found necessary to run smoothly
+under linux2.0. The PTEST directory below refers to the original
+pthreads 1.60 beta 6 release. Of course, the '-O2' "fix" is not strictly
+needed.
+
+#============================================================
+# < pthreads-1_60beta6/config/configure
+# > PTEST/pthreads-1_60beta6/config/configure
+#------------------------------------------------------------
+642c642
+< CFLAGS="-g -O2"
+---
+> CFLAGS="-g -O"
+1104,1106d1103
+< cat >> confdefs.h <<EOF
+< #define BSD_TM 1
+< EOF
+
+# Diff for:
+#============================================================
+# < pthreads-1_60beta6/config/config.h.in
+# > PTEST/pthreads-1_60beta6/config/config.h.in
+#------------------------------------------------------------
+3,8d2
+< /* Does the OS have tm needing bsd'ish initialization? */
+< #undef BSD_TM
+<
+< /* Does the OS already support struct timespec */
+< #undef _OS_HAS_TIMESPEC
+<
+
+# Diff for:
+#============================================================
+# < pthreads-1_60beta6/gen/ctime.c
+# > PTEST/pthreads-1_60beta6/gen/ctime.c
+#------------------------------------------------------------
+49c49
+< #include "config.h"
+---
+>
+
+# Diff for:
+#============================================================
+# < pthreads-1_60beta6/include/math.h
+# > PTEST/pthreads-1_60beta6/include/math.h
+#------------------------------------------------------------
+54d53
+< double hypot __P((double, double));
+
+
+Bill Lear (rael@dejanews.com)
+
diff --git a/mit-pthreads/patches/chris_demetriou b/mit-pthreads/patches/chris_demetriou
new file mode 100755
index 00000000000..283d6c1999c
--- /dev/null
+++ b/mit-pthreads/patches/chris_demetriou
@@ -0,0 +1,149 @@
+From cgd@pa.dec.com Fri Aug 15 04:22:21 1997
+X-VM-v5-Data: ([nil nil nil nil nil nil nil nil nil]
+ ["3982" "Thu" "14" "August" "1997" "18:57:55" "-0700" "Chris G. Demetriou" "cgd@pa.dec.com" "<15218.871610275@dnaunix.pa.dec.com>" "126" "patches to get 1.60 beta6 to build on ELF NetBSD/alpha systems" "^From:" nil nil "8" "1997081501:57:55" "patches to get 1.60 beta6 to build on ELF NetBSD/alpha systems" nil nil]
+ nil)
+Received: from MIT.EDU (PACIFIC-CARRIER-ANNEX.MIT.EDU [18.69.0.28])
+ by analytik.analytikerna.se (8.8.4/8.8.4) with SMTP
+ id EAA10207 for <monty@analytikerna.se>; Fri, 15 Aug 1997 04:22:19 +0200 (MET DST)
+Received: from mail2.digital.com by MIT.EDU with SMTP
+ id AA13470; Thu, 14 Aug 97 22:01:37 EDT
+Received: from dnaunix.pa.dec.com (dnaunix.pa.dec.com [16.4.208.21])
+ by mail2.digital.com (8.7.5/UNX 1.5/1.0/WV) with SMTP id SAA15366;
+ Thu, 14 Aug 1997 18:58:16 -0700 (PDT)
+Received: by dnaunix.pa.dec.com; id AA15044; Thu, 14 Aug 1997 18:57:56 -0700
+Message-Id: <15218.871610275@dnaunix.pa.dec.com>
+X-Mts: smtp
+Content-Length: 3981
+From: "Chris G. Demetriou" <cgd@pa.dec.com>
+Sender: cgd@pa.dec.com
+To: pthreads-bugs@MIT.EDU
+Cc: "Chris G. Demetriou" <cgd@pa.dec.com>, pthreads@MIT.EDU
+Subject: patches to get 1.60 beta6 to build on ELF NetBSD/alpha systems
+Date: Thu, 14 Aug 97 18:57:55 -0700
+
+Enclosed below are patches to pthreads 1.60 beta6 to build on
+current NetBSD/alpha systems (which use ELF). With these patches,
+pthreads passes 'make check.'
+
+As an aside, the test_switch test generates _340k_ of output ("a"
+for a while, then "ab" for a while) when run one the machine I was
+testing on. In my opinion, that's a ... bit excessive, especially
+since 'make check' has to be run interactively!
+
+
+
+chris
+============================================================================
+diff -rc pthreads-1_60_beta6.orig/config/Makefile.in pthreads-1_60_beta6/config/Makefile.in
+*** pthreads-1_60_beta6.orig/config/Makefile.in Thu Mar 21 20:29:54 1996
+--- pthreads-1_60_beta6/config/Makefile.in Thu Aug 14 17:56:55 1997
+***************
+*** 29,35 ****
+ # pathname for srcdir here, and live with it.
+ srcdir = $(srctop)
+
+! beforeinstall:: install-dirs
+
+ .include "${srcdir}/pthreads/Makefile.inc"
+ .include "${srcdir}/stdlib/Makefile.inc"
+--- 29,35 ----
+ # pathname for srcdir here, and live with it.
+ srcdir = $(srctop)
+
+! beforeinstall: install-dirs
+
+ .include "${srcdir}/pthreads/Makefile.inc"
+ .include "${srcdir}/stdlib/Makefile.inc"
+diff -rc pthreads-1_60_beta6.orig/machdep/syscall-alpha-netbsd-1.1.S pthreads-1_60_beta6/machdep/syscall-alpha-netbsd-1.1.S
+*** pthreads-1_60_beta6.orig/machdep/syscall-alpha-netbsd-1.1.S Wed Nov 13 13:03:28 1996
+--- pthreads-1_60_beta6/machdep/syscall-alpha-netbsd-1.1.S Thu Aug 14 18:03:27 1997
+***************
+*** 35,54 ****
+ .frame sp,0,ra ;\
+ ldiq v0, CONCAT(SYS_,x) ;\
+ CHMK() ;\
+! beq a3, 2f ;\
+! br gp, 1f ;\
+! 1: ;\
+ /* Load gp so we can find cerror to jump to. */;\
+ ldgp gp, 0(gp) ;\
+! jmp zero, machdep_cerror ;\
+! 2:
+
+ #define XSYSCALL(x) SYSCALL(x) ; RET ; .end CONCAT(machdep_sys_,x)
+
+ .globl machdep_cerror
+ machdep_cerror:
+! br t0, 1f
+! 1:
+ ldgp gp, 0(t0)
+ stl v0, errno
+ #if 0
+--- 35,54 ----
+ .frame sp,0,ra ;\
+ ldiq v0, CONCAT(SYS_,x) ;\
+ CHMK() ;\
+! beq a3, CONCAT(Lsys_noerr_,x) ;\
+! br gp, CONCAT(Lsys_err_,x) ;\
+! CONCAT(Lsys_err_,x): ;\
+ /* Load gp so we can find cerror to jump to. */;\
+ ldgp gp, 0(gp) ;\
+! jmp zero, machdep_cerror ;\
+! CONCAT(Lsys_noerr_,x):
+
+ #define XSYSCALL(x) SYSCALL(x) ; RET ; .end CONCAT(machdep_sys_,x)
+
+ .globl machdep_cerror
+ machdep_cerror:
+! br t0, Lmachdep_cerror_setgp
+! Lmachdep_cerror_setgp:
+ ldgp gp, 0(t0)
+ stl v0, errno
+ #if 0
+diff -rc pthreads-1_60_beta6.orig/machdep/syscall-template-alpha-netbsd-1.1.S pthreads-1_60_beta6/machdep/syscall-template-alpha-netbsd-1.1.S
+*** pthreads-1_60_beta6.orig/machdep/syscall-template-alpha-netbsd-1.1.S Mon Apr 22 23:15:42 1996
+--- pthreads-1_60_beta6/machdep/syscall-template-alpha-netbsd-1.1.S Thu Aug 14 17:58:14 1997
+***************
+*** 31,43 ****
+ .frame sp,0,ra ;\
+ ldiq v0, SYS_##x ;\
+ CHMK() ;\
+! beq a3, 2f ;\
+! br gp, 1f ;\
+! 1: ;\
+ /* Load gp so we can find cerror to jump to. */;\
+ ldgp gp, 0(gp) ;\
+! jmp zero, machdep_cerror ;\
+! 2:
+
+ #define SIMPLE_SYSCALL(x) SYSCALL(x) ; ret ; .end machdep_sys_##x
+
+--- 31,43 ----
+ .frame sp,0,ra ;\
+ ldiq v0, SYS_##x ;\
+ CHMK() ;\
+! beq a3, Lsys_noerr_##x ;\
+! br gp, Lsys_err_##x ;\
+! Lsys_err_##x: ;\
+ /* Load gp so we can find cerror to jump to. */;\
+ ldgp gp, 0(gp) ;\
+! jmp zero, machdep_cerror ;\
+! Lsys_noerr_##x:
+
+ #define SIMPLE_SYSCALL(x) SYSCALL(x) ; ret ; .end machdep_sys_##x
+
+diff -rc pthreads-1_60_beta6.orig/pthreads/process.c pthreads-1_60_beta6/pthreads/process.c
+*** pthreads-1_60_beta6.orig/pthreads/process.c Tue Nov 12 05:45:16 1996
+--- pthreads-1_60_beta6/pthreads/process.c Thu Aug 14 18:12:49 1997
+***************
+*** 40,45 ****
+--- 40,47 ----
+ #include <stdarg.h>
+ #include <unistd.h>
+
++ extern void *alloca();
++
+ #ifndef lint
+ static const char rcsid[] = "$Id$";
+ #endif
+
diff --git a/mit-pthreads/patches/mevans b/mit-pthreads/patches/mevans
new file mode 100755
index 00000000000..d5ff2f27610
--- /dev/null
+++ b/mit-pthreads/patches/mevans
@@ -0,0 +1,642 @@
+=A0
+Attached are several patches for pthreads-1_60_beta6. The patches fall
+into 3 catagories:
+
+ 1. Crashes and hangs.
+ 2. Missing functionality (namely flock())
+ 3. Use of POSIX reentrant safe routines.
+
+Most of the patches contain a comment as to why the change was made.
+The one major exception is to fd_kern.c at line 257 (unpatched). The
+change to that line is to fix a "hang" that prevents threads for
+scheduling for an hour if there is no external I/O event.
+
+I also include patches that modify several functions to use POSIX
+reentrant safe routines. I know that MIT pthreads implements routine
+like gethostbyname in a thread safe manner, but we're pretty, um, anal
+about trying to keep our code as portable as possible. By excluding
+using routines that are not reentrant safe according to the PTHREAD
+safe, it's easy for us to stub out the unsafe routines and catch
+non-compliant code. I almost left these patches out, but I'm hoping
+they'll be adopted. :-)
+
+WARNING: None of the MIT pthreads routines that convert floats/doubles
+between their native forms and strings are thread safe! (i.e printf,
+sprintf, fprintf, atod, strtod, etc) I have replacements, but I need to
+check with the author of the replacements and my employer.
+
+Mark Evans
+
+------------69CDAAF52A3566916F8ED01A0
+Content-Disposition: inline; filename="pthreads-1_60_beta6.patch"
+Content-Type: text/plain; charset=us-ascii; name="pthreads-1_60_beta6.patch"
+Content-Transfer-Encoding: 7bit
+
+diff -c -b -r -d -I .*$Id:.* pthreads-1_60_beta6/config/config.h.in pthreads-1_60_beta6+/config/config.h.in
+*** pthreads-1_60_beta6/config/config.h.in Thu Mar 21 21:30:04 1996
+--- pthreads-1_60_beta6+/config/config.h.in Sat Mar 15 14:08:55 1997
+***************
+*** 137,142 ****
+--- 137,145 ----
+ /* Define if you have the syscall_ftruncate function. */
+ #undef HAVE_SYSCALL_FTRUNCATE
+
++ /* Define if you have the syscall_flock function. */
++ #undef HAVE_SYSCALL_FLOCK
++
+ /* Define if you have the syscall_getdents function. */
+ #undef HAVE_SYSCALL_GETDENTS
+
+diff -c -b -r -d -I .*$Id:.* pthreads-1_60_beta6/config/configure.in pthreads-1_60_beta6+/config/configure.in
+*** pthreads-1_60_beta6/config/configure.in Wed Nov 13 14:03:08 1996
+--- pthreads-1_60_beta6+/config/configure.in Sat Mar 15 14:08:55 1997
+***************
+*** 241,247 ****
+
+ PTHREADS_CHECK_SYSCALLS(open write read creat close fcntl lseek dup2 dup pipe
+ fchmod fchown execve fstat lstat link unlink chdir chown chmod stat
+! rename select getdtablesize ioctl ftruncate
+ dnl - signals
+ sigsuspend sigaction sigpause sigprocmask ksigaction
+ dnl - directory reading
+--- 241,247 ----
+
+ PTHREADS_CHECK_SYSCALLS(open write read creat close fcntl lseek dup2 dup pipe
+ fchmod fchown execve fstat lstat link unlink chdir chown chmod stat
+! rename select getdtablesize ioctl ftruncate flock
+ dnl - signals
+ sigsuspend sigaction sigpause sigprocmask ksigaction
+ dnl - directory reading
+diff -c -b -r -d -I .*$Id:.* pthreads-1_60_beta6/gen/directory.c pthreads-1_60_beta6+/gen/directory.c
+*** pthreads-1_60_beta6/gen/directory.c Sat May 20 10:55:34 1995
+--- pthreads-1_60_beta6+/gen/directory.c Sat Mar 15 14:08:55 1997
+***************
+*** 251,262 ****
+--- 251,266 ----
+ /*
+ * Seek to an entry in a directory.
+ * _seekdir is in telldir.c so that it can share opaque data structures.
++ *
++ * Use the POSIX reentrant safe readdir_r to simplify varifying POSIX
++ * thread-safe compliance.
+ */
+ void seekdir(DIR * dirp, long loc)
+ {
+ register struct ddloc ** prevlp;
+ register struct ddloc * lp;
+ struct dirent * dp;
++ struct dirent de;
+
+ pthread_mutex_lock (dirp->dd_lock);
+ prevlp = (struct ddloc **)&(dirp->dd_ddloc);
+***************
+*** 277,283 ****
+ dirp->dd_seek = lp->loc_seek;
+ dirp->dd_loc = 0;
+ while (dirp->dd_loc < lp->loc_loc) {
+! if (!(dp = readdir(dirp))) {
+ *prevlp = lp->loc_next;
+ break;
+ }
+--- 281,287 ----
+ dirp->dd_seek = lp->loc_seek;
+ dirp->dd_loc = 0;
+ while (dirp->dd_loc < lp->loc_loc) {
+! if (readdir_r(dirp, &de, &dp)) {
+ *prevlp = lp->loc_next;
+ break;
+ }
+diff -c -b -r -d -I .*$Id:.* pthreads-1_60_beta6/gen/getcwd.c pthreads-1_60_beta6+/gen/getcwd.c
+*** pthreads-1_60_beta6/gen/getcwd.c Sat Sep 2 17:39:30 1995
+--- pthreads-1_60_beta6+/gen/getcwd.c Sat Mar 15 14:08:55 1997
+***************
+*** 50,67 ****
+ (dp->d_name[0] == '.' && (dp->d_name[1] == '\0' || \
+ dp->d_name[1] == '.' && dp->d_name[2] == '\0'))
+
+ char *
+ getcwd(pt, size)
+ char *pt;
+ size_t size;
+ {
+- register struct dirent *dp;
+ register DIR *dir;
+ register dev_t dev;
+ register ino_t ino;
+ register int first;
+ register char *bpt, *bup;
+ struct stat s;
+ dev_t root_dev;
+ ino_t root_ino;
+ size_t ptsize, upsize;
+--- 50,71 ----
+ (dp->d_name[0] == '.' && (dp->d_name[1] == '\0' || \
+ dp->d_name[1] == '.' && dp->d_name[2] == '\0'))
+
++ /* Only use reentrant safe routines to simplify varifying POSIX thread-safe
++ * compliance. (mevans).
++ */
+ char *
+ getcwd(pt, size)
+ char *pt;
+ size_t size;
+ {
+ register DIR *dir;
+ register dev_t dev;
+ register ino_t ino;
+ register int first;
+ register char *bpt, *bup;
+ struct stat s;
++ struct dirent *dp;
++ struct dirent de;
+ dev_t root_dev;
+ ino_t root_ino;
+ size_t ptsize, upsize;
+***************
+*** 166,179 ****
+ save_errno = 0;
+ if (s.st_dev == dev) {
+ for (;;) {
+! if (!(dp = readdir(dir)))
+ goto notfound;
+ if (dp->d_fileno == ino)
+ break;
+ }
+ } else
+ for (;;) {
+! if (!(dp = readdir(dir)))
+ goto notfound;
+ if (ISDOT(dp))
+ continue;
+--- 170,183 ----
+ save_errno = 0;
+ if (s.st_dev == dev) {
+ for (;;) {
+! if (readdir_r(dir, &de, &dp))
+ goto notfound;
+ if (dp->d_fileno == ino)
+ break;
+ }
+ } else
+ for (;;) {
+! if (readdir_r(dir, &de, &dp))
+ goto notfound;
+ if (ISDOT(dp))
+ continue;
+diff -c -b -r -d -I .*$Id:.* pthreads-1_60_beta6/include/syslog.h pthreads-1_60_beta6+/include/syslog.h
+*** pthreads-1_60_beta6/include/syslog.h Mon Sep 26 21:26:29 1994
+--- pthreads-1_60_beta6+/include/syslog.h Sat Mar 15 14:08:56 1997
+***************
+*** 9,14 ****
+--- 9,16 ----
+ #ifndef SYSLOG_H
+ #define SYSLOG_H
+
++ /* Added __[BEGIN/END]_DECLS so this file would work with C++. (mevans) */
++ #include <sys/cdefs.h>
+ #include <stdarg.h>
+
+ /* Discipline: openlog(), closelog(), and setlogmask() are not thread-safe
+***************
+*** 84,95 ****
+--- 86,101 ----
+ #define LOG_NDELAY 0x08 /* don't delay open */
+ #define LOG_NOWAIT 0x10 /* if forking to log on console, don't wait() */
+
++ __BEGIN_DECLS
++
+ /* Syslogging functions. */
+ void syslog(int pri, char *fmt, ...);
+ void vsyslog(int pri, char *fmt, va_list args);
+ void openlog(char *ident, int logstat, int logfac);
+ void closelog(void);
+ int setlogmask(int pmask);
++
++ __END_DECLS
+
+ #endif
+
+diff -c -b -r -d -I .*$Id:.* pthreads-1_60_beta6/machdep/engine-i386-linux-1.0.c pthreads-1_60_beta6+/machdep/engine-i386-linux-1.0.c
+*** pthreads-1_60_beta6/machdep/engine-i386-linux-1.0.c Mon Oct 21 20:39:13 1996
+--- pthreads-1_60_beta6+/machdep/engine-i386-linux-1.0.c Sat Mar 15 14:08:56 1997
+***************
+*** 142,147 ****
+--- 142,149 ----
+ * machdep_pthread_start().
+ */
+ machdep_pthread->machdep_state->__pc = (char *)machdep_pthread_start;
++ machdep_pthread->machdep_state->__bp = (char *)0;/* So the backtrace
++ * is sensible (mevans) */
+
+ /* Stack starts high and builds down. */
+ machdep_pthread->machdep_state->__sp =
+diff -c -b -r -d -I .*$Id:.* pthreads-1_60_beta6/machdep/syscall-i386-linux-1.0.S pthreads-1_60_beta6+/machdep/syscall-i386-linux-1.0.S
+*** pthreads-1_60_beta6/machdep/syscall-i386-linux-1.0.S Mon Oct 21 22:17:32 1996
+--- pthreads-1_60_beta6+/machdep/syscall-i386-linux-1.0.S Sat Mar 15 14:08:56 1997
+***************
+*** 148,156 ****
+ /* =========================================================================
+ * exit 1 select 82
+ * fork 2 socketcall 102
+! * read 3 readv 145
+! * write 4 writev 146
+! * open 5
+ * creat 8
+ * link 9
+ * unlink 10
+--- 148,156 ----
+ /* =========================================================================
+ * exit 1 select 82
+ * fork 2 socketcall 102
+! * read 3 flock 143
+! * write 4 readv 145
+! * open 5 writev 146
+ * creat 8
+ * link 9
+ * unlink 10
+***************
+*** 390,394 ****
+--- 390,401 ----
+ */
+ #ifdef HAVE_SYSCALL_WRITEV
+ SYSCALL3(writev)
++ #endif
++
++ /* ==========================================================================
++ * machdep_sys_flock()
++ */
++ #ifdef HAVE_SYSCALL_FLOCK
++ SYSCALL2(flock)
+ #endif
+
+diff -c -b -r -d -I .*$Id:.* pthreads-1_60_beta6/net/gethostbyname.c pthreads-1_60_beta6+/net/gethostbyname.c
+*** pthreads-1_60_beta6/net/gethostbyname.c Mon Apr 22 22:41:21 1996
+--- pthreads-1_60_beta6+/net/gethostbyname.c Sat Mar 15 14:08:58 1997
+***************
+*** 146,161 ****
+ {
+ char **alias;
+ FILE *fp = NULL;
+
+ pthread_mutex_lock(&host_iterate_lock);
+ sethostent(0);
+! while ((result = gethostent_r(result, buf, bufsize, errval)) != NULL) {
+ /* Check the entry's name and aliases against the given name. */
+ if (strcasecmp(result->h_name, name) == 0)
+ break;
+ for (alias = result->h_aliases; *alias; alias++) {
+! if (strcasecmp(*alias, name) == 0)
+ break;
+ }
+ }
+ pthread_mutex_unlock(&host_iterate_lock);
+--- 146,166 ----
+ {
+ char **alias;
+ FILE *fp = NULL;
++ int fFound = FALSE;
+
+ pthread_mutex_lock(&host_iterate_lock);
+ sethostent(0);
+! while (!fFound && (result = gethostent_r(result, buf, bufsize, errval))
+! != NULL) {
+ /* Check the entry's name and aliases against the given name. */
+ if (strcasecmp(result->h_name, name) == 0)
+ break;
+ for (alias = result->h_aliases; *alias; alias++) {
+! if (strcasecmp(*alias, name) == 0) {
+! /* fFound will exit while loop. (mevans). */
+! fFound = TRUE;
+ break;
++ }
+ }
+ }
+ pthread_mutex_unlock(&host_iterate_lock);
+diff -c -b -r -d -I .*$Id:.* pthreads-1_60_beta6/net/res_debug.c pthreads-1_60_beta6+/net/res_debug.c
+*** pthreads-1_60_beta6/net/res_debug.c Thu Feb 23 22:42:35 1995
+--- pthreads-1_60_beta6+/net/res_debug.c Sat Mar 15 14:08:58 1997
+***************
+*** 375,380 ****
+--- 375,383 ----
+
+ /*
+ * Print resource record fields in human readable form.
++ *
++ * Removed calls to non-reentrant routines to simplify varifying
++ * POSIX thread-safe implementations. (mevans).
+ */
+ char *
+ p_rr(cp, msg, file)
+***************
+*** 386,391 ****
+--- 389,395 ----
+ char *cp1, *cp2;
+ u_long tmpttl, t;
+ int lcnt;
++ char buf[32];
+
+ if ((cp = p_fqname(cp, msg, file)) == NULL)
+ return (NULL); /* compression error */
+***************
+*** 413,426 ****
+ case C_HS:
+ bcopy(cp, (char *)&inaddr, sizeof(inaddr));
+ if (dlen == 4) {
+! fprintf(file,"\t%s", inet_ntoa(inaddr));
+ cp += dlen;
+ } else if (dlen == 7) {
+ char *address;
+ u_char protocol;
+ u_short port;
+
+! address = inet_ntoa(inaddr);
+ cp += sizeof(inaddr);
+ protocol = *(u_char*)cp;
+ cp += sizeof(u_char);
+--- 417,432 ----
+ case C_HS:
+ bcopy(cp, (char *)&inaddr, sizeof(inaddr));
+ if (dlen == 4) {
+! fprintf(file,"\t%s",
+! inet_ntoa_r(inaddr, buf, sizeof(buf)));
+ cp += dlen;
+ } else if (dlen == 7) {
+ char *address;
+ u_char protocol;
+ u_short port;
+
+! address = inet_ntoa_r(inaddr,
+! buf, sizeof(buf));
+ cp += sizeof(inaddr);
+ protocol = *(u_char*)cp;
+ cp += sizeof(u_char);
+***************
+*** 524,530 ****
+ bcopy(cp, (char *)&inaddr, sizeof(inaddr));
+ cp += sizeof(u_long);
+ fprintf(file, "\t%s %s ( ",
+! inet_ntoa(inaddr),
+ deproto((int) *cp));
+ cp += sizeof(u_char);
+ n = 0;
+--- 530,536 ----
+ bcopy(cp, (char *)&inaddr, sizeof(inaddr));
+ cp += sizeof(u_long);
+ fprintf(file, "\t%s %s ( ",
+! inet_ntoa_r(inaddr, buf, sizeof(buf)),
+ deproto((int) *cp));
+ cp += sizeof(u_char);
+ n = 0;
+diff -c -b -r -d -I .*$Id:.* pthreads-1_60_beta6/pthreads/fd_kern.c pthreads-1_60_beta6+/pthreads/fd_kern.c
+*** pthreads-1_60_beta6/pthreads/fd_kern.c Tue Oct 1 12:26:48 1996
+--- pthreads-1_60_beta6+/pthreads/fd_kern.c Sat Mar 15 14:09:00 1997
+***************
+*** 215,221 ****
+ * Called when there is no active thread to run.
+ */
+ extern struct timeval __fd_kern_wait_timeout;
+!
+ void fd_kern_wait()
+ {
+ fd_set fd_set_read, fd_set_write, fd_set_except;
+--- 215,221 ----
+ * Called when there is no active thread to run.
+ */
+ extern struct timeval __fd_kern_wait_timeout;
+! extern volatile sig_atomic_t sig_to_process;
+ void fd_kern_wait()
+ {
+ fd_set fd_set_read, fd_set_write, fd_set_except;
+***************
+*** 254,260 ****
+
+ machdep_unset_thread_timer(NULL);
+ __fd_kern_wait_timeout.tv_usec = 0;
+! __fd_kern_wait_timeout.tv_sec = 3600;
+
+ machdep_sys_sigprocmask(SIG_UNBLOCK, &sig_to_block, &oset);
+
+--- 254,260 ----
+
+ machdep_unset_thread_timer(NULL);
+ __fd_kern_wait_timeout.tv_usec = 0;
+! __fd_kern_wait_timeout.tv_sec = (sig_to_process) ? 0 : 3600;
+
+ machdep_sys_sigprocmask(SIG_UNBLOCK, &sig_to_block, &oset);
+
+***************
+*** 726,731 ****
+--- 726,753 ----
+ return(ret);
+ }
+
++ #if defined (HAVE_SYSCALL_FLOCK)
++ /* ==========================================================================
++ * flock()
++ *
++ * Added (mevans)
++ */
++ int flock(int fd, int operation)
++ {
++ int ret;
++
++ if ((ret = fd_lock(fd, FD_RDWR, NULL)) == OK) {
++ if ((ret = machdep_sys_flock(fd_table[fd]->fd.i,
++ operation)) < OK) {
++ SET_ERRNO(-ret);
++ ret = NOTOK;
++ }
++ fd_unlock(fd, FD_RDWR);
++ }
++ return(ret);
++ }
++ #endif
++
+ /* ==========================================================================
+ * pipe()
+ */
+***************
+*** 1126,1132 ****
+ /* Get the error, this function should not fail */
+ machdep_sys_getsockopt(fd_table[fd]->fd.i, SOL_SOCKET,
+ SO_ERROR, &ret, &tmpnamelen);
+! SET_ERRNO(-ret);
+ ret = NOTOK;
+ }
+ } else {
+--- 1148,1155 ----
+ /* Get the error, this function should not fail */
+ machdep_sys_getsockopt(fd_table[fd]->fd.i, SOL_SOCKET,
+ SO_ERROR, &ret, &tmpnamelen);
+! /* ret is already positive (mevans) */
+! SET_ERRNO(ret);
+ ret = NOTOK;
+ }
+ } else {
+diff -c -b -r -d -I .*$Id:.* pthreads-1_60_beta6/pthreads/malloc.c pthreads-1_60_beta6+/pthreads/malloc.c
+*** pthreads-1_60_beta6/pthreads/malloc.c Thu Mar 9 21:06:43 1995
+--- pthreads-1_60_beta6+/pthreads/malloc.c Sat Mar 15 14:09:00 1997
+***************
+*** 196,204 ****
+ else
+ n = n - x;
+ if (n) {
+! if (sbrk(n) == (char *)-1)
+ return (NULL);
+ }
+ bucket = 0;
+ amt = 8;
+ while (pagesz > amt) {
+--- 196,207 ----
+ else
+ n = n - x;
+ if (n) {
+! if (sbrk(n) == (char *)-1) {
+! /* Unlock before returning (mevans) */
+! pthread_mutex_unlock(mutex);
+ return (NULL);
+ }
++ }
+ bucket = 0;
+ amt = 8;
+ while (pagesz > amt) {
+***************
+*** 363,366 ****
+--- 366,382 ----
+ free(cp);
+
+ return (res);
++ }
++ /* ==========================================================================
++ * calloc()
++ *
++ * Added to ensure pthread's allocation is used (mevans).
++ */
++ void *calloc(size_t nmemb, size_t size)
++ {
++ void *p;
++ size *= nmemb;
++ p = malloc(size);
++ if (p) memset(p, 0, size);
++ return (p);
+ }
+diff -c -b -r -d -I .*$Id:.* pthreads-1_60_beta6/pthreads/select.c pthreads-1_60_beta6+/pthreads/select.c
+*** pthreads-1_60_beta6/pthreads/select.c Sat Jul 6 21:58:55 1996
+--- pthreads-1_60_beta6+/pthreads/select.c Sat Mar 15 14:09:00 1997
+***************
+*** 165,176 ****
+ pthread_resched_resume(PS_SELECT_WAIT);
+
+ /* We're awake */
+- CLEAR_PF_DONE_EVENT(pthread_run);
+ if (sleep_cancel(pthread_run) == NOTOK) {
+ ret = OK;
+ } else {
+ ret = data.nfds;
+ }
+ } else {
+ pthread_resched_resume(PS_SELECT_WAIT);
+ CLEAR_PF_DONE_EVENT(pthread_run);
+--- 165,180 ----
+ pthread_resched_resume(PS_SELECT_WAIT);
+
+ /* We're awake */
+ if (sleep_cancel(pthread_run) == NOTOK) {
+ ret = OK;
+ } else {
+ ret = data.nfds;
+ }
++ /* Moving this after the sleep_cancel() seemed
++ * to fix intermittent crashes during heavy
++ * socket use. (mevans)
++ */
++ CLEAR_PF_DONE_EVENT(pthread_run);
+ } else {
+ pthread_resched_resume(PS_SELECT_WAIT);
+ CLEAR_PF_DONE_EVENT(pthread_run);
+diff -c -b -r -d -I .*$Id:.* pthreads-1_60_beta6/pthreads/signal.c pthreads-1_60_beta6+/pthreads/signal.c
+*** pthreads-1_60_beta6/pthreads/signal.c Tue Mar 12 21:33:17 1996
+--- pthreads-1_60_beta6+/pthreads/signal.c Sat Mar 15 14:09:00 1997
+***************
+*** 65,71 ****
+ */
+
+ static sig_atomic_t signum_to_process[SIGMAX + 1] = { 0, };
+! static sig_atomic_t sig_to_process = 0;
+
+ /* static volatile sigset_t sig_to_process; */
+ static volatile int sig_count = 0;
+--- 65,71 ----
+ */
+
+ static sig_atomic_t signum_to_process[SIGMAX + 1] = { 0, };
+! volatile sig_atomic_t sig_to_process = 0;
+
+ /* static volatile sigset_t sig_to_process; */
+ static volatile int sig_count = 0;
+***************
+*** 303,309 ****
+ break;
+ case NOTOK:
+ /* Do the registered action, no threads were sleeping */
+! sigdefault(sig);
+ break;
+ }
+ break;
+--- 303,317 ----
+ break;
+ case NOTOK:
+ /* Do the registered action, no threads were sleeping */
+! /* There is a timing window that gets
+! * here when no threads are on the
+! * sleep queue. This is a quick fix.
+! * The real problem is possibly related
+! * to heavy use of condition variables
+! * with time outs.
+! * (mevans)
+! *sigdefault(sig);
+! */
+ break;
+ }
+ break;
+diff -c -b -r -d -I .*$Id:.* pthreads-1_60_beta6/stdio/setvbuf.c pthreads-1_60_beta6+/stdio/setvbuf.c
+*** pthreads-1_60_beta6/stdio/setvbuf.c Sat Sep 3 20:58:36 1994
+--- pthreads-1_60_beta6+/stdio/setvbuf.c Sat Mar 15 14:09:00 1997
+***************
+*** 142,148 ****
+ flags |= __SLBF;
+ if (flags & __SRW)
+ flags &= ~(__SRD | __SWR);
+! fp->_w = 0;
+ fp->_flags = flags;
+ fp->_bf._base = fp->_p = (unsigned char *)buf;
+ fp->_bf._size = size;
+--- 142,148 ----
+ flags |= __SLBF;
+ if (flags & __SRW)
+ flags &= ~(__SRD | __SWR);
+! fp->_w = size; /* Was 0 (mevans) */
+ fp->_flags = flags;
+ fp->_bf._base = fp->_p = (unsigned char *)buf;
+ fp->_bf._size = size;
+diff -c -b -r -d -I .*$Id:.* pthreads-1_60_beta6/stdlib/system.c pthreads-1_60_beta6+/stdlib/system.c
+*** pthreads-1_60_beta6/stdlib/system.c Wed Apr 24 21:18:56 1996
+--- pthreads-1_60_beta6+/stdlib/system.c Sat Mar 15 14:09:01 1997
+***************
+*** 62,68 ****
+ argp[2] = (char *) command;
+ sigemptyset(&tmp_mask);
+ sigaddset(&tmp_mask, SIGCHLD);
+! pthread_sigmask(SIG_BLOCK, tmp_mask, &old_mask);
+ switch(pid = fork()) {
+ case -1: /* error */
+ (void)pthread_sigmask(SIG_SETMASK, &old_mask, NULL);
+--- 62,69 ----
+ argp[2] = (char *) command;
+ sigemptyset(&tmp_mask);
+ sigaddset(&tmp_mask, SIGCHLD);
+! /* Pass the address of tmp_mask to avoid a sigfault. (mevans). */
+! pthread_sigmask(SIG_BLOCK, &tmp_mask, &old_mask);
+ switch(pid = fork()) {
+ case -1: /* error */
+ (void)pthread_sigmask(SIG_SETMASK, &old_mask, NULL);
diff --git a/mit-pthreads/patches/p153 b/mit-pthreads/patches/p153
new file mode 100755
index 00000000000..4e374e29a10
--- /dev/null
+++ b/mit-pthreads/patches/p153
@@ -0,0 +1,90 @@
+<HEAD><TITLE>discuss@charon.mit.edu: [153] in "Pthreads Bugs"</TITLE>
+<H1>[153] in Pthreads Bugs</H1></HEAD>
+<A HREF="/"><IMG SRC="/i-d.gif" ALT="root"></A>
+<A HREF="?153"><IMG SRC="/i-back.gif" ALT="meeting"></A>
+<A HREF="/help.html"><IMG SRC="/i-help.gif" ALT="help"></A>
+<A HREF="1"><IMG SRC="/i-first.gif" ALT="first"></A>
+<A HREF="151"><IMG SRC="/i-fref.gif" ALT="first in chain"></A>
+<A HREF="152"><IMG SRC="/i-pref.gif" ALT="previous in chain"></A>
+<A HREF="152"><IMG SRC="/i-prev.gif" ALT="previous"></A>
+<A HREF="154"><IMG SRC="/i-next.gif" ALT="next"></A>
+<IMG SRC="/n-nref.gif" ALT="">
+<IMG SRC="/n-lref.gif" ALT="">
+<A HREF="161"><IMG SRC="/i-last.gif" ALT="last"></A>
+<HR><H2>Re: sleep / SIGALRM problem in 1_60_beta6</H2>
+<H3>daemon@ATHENA.MIT.EDU (Mon Dec 9 19:32:22 1996
+)</H3>
+<PRE>
+Date: Mon, 09 Dec 1996 17:22:50 -0700
+From: "Mark M. Evans" &lt;mevans@cti-ltd.com&gt;
+To: Tim Hinderliter &lt;kyd@internap.com&gt;
+Cc: pthreads-bugs@MIT.EDU
+
+I think I found what caused fd_kern_wait() to block for the entire
+hour (instead of waking up due to the SIGALRM). Basically, the
+SIGALRM that would move the sleeping thread to the run queue occurs
+while pthread_kernel_lock is set, but *before* the critical section in
+fd_kern_wait() that sets __fd_kern_wait_timeout.tv_sec to 3600. So,
+sig_handler_real() clears __fd_kern_wait_timeout.tv_sec "too soon."
+
+I've worked around this by checking sig_to_process in the critical
+section to determine if we are truly idle. To do this I had to make
+sig_to_process publicly available.
+
+Here are the diffs (relative to the pthreads/pthreads directory):
+
+diff -c -r1.2 -r1.3
+*** signal.c 1996/11/20 05:09:50 1.2
+--- signal.c 1996/12/09 23:14:52 1.3
+***************
+*** 65,71 ****
+ */
+
+ static sig_atomic_t signum_to_process[SIGMAX + 1] = { 0, };
+! static sig_atomic_t sig_to_process = 0;
+
+ /* static volatile sigset_t sig_to_process; */
+ static volatile int sig_count = 0;
+--- 65,71 ----
+ */
+
+ static sig_atomic_t signum_to_process[SIGMAX + 1] = { 0, };
+! sig_atomic_t sig_to_process = 0;
+
+ /* static volatile sigset_t sig_to_process; */
+ static volatile int sig_count = 0;
+*** fd_kern.c 1996/12/03 04:14:59 1.6
+--- fd_kern.c 1996/12/09 23:14:51 1.7
+***************
+*** 215,221 ****
+ * Called when there is no active thread to run.
+ */
+ extern struct timeval __fd_kern_wait_timeout;
+!
+ void fd_kern_wait()
+ {
+ fd_set fd_set_read, fd_set_write, fd_set_except;
+--- 215,221 ----
+ * Called when there is no active thread to run.
+ */
+ extern struct timeval __fd_kern_wait_timeout;
+! extern volatile sig_atomic_t sig_to_process;
+ void fd_kern_wait()
+ {
+ fd_set fd_set_read, fd_set_write, fd_set_except;
+***************
+*** 254,260 ****
+
+ machdep_unset_thread_timer(NULL);
+ __fd_kern_wait_timeout.tv_usec = 0;
+! __fd_kern_wait_timeout.tv_sec = 3600;
+
+ machdep_sys_sigprocmask(SIG_UNBLOCK, &amp;sig_to_block, &amp;oset);
+
+--- 254,260 ----
+
+ machdep_unset_thread_timer(NULL);
+ __fd_kern_wait_timeout.tv_usec = 0;
+! __fd_kern_wait_timeout.tv_sec = (sig_to_process) ? 0 : 3600;
+
+ machdep_sys_sigprocmask(SIG_UNBLOCK, &amp;sig_to_block, &amp;oset);
diff --git a/mit-pthreads/patches/p155 b/mit-pthreads/patches/p155
new file mode 100755
index 00000000000..dbdfa7de899
--- /dev/null
+++ b/mit-pthreads/patches/p155
@@ -0,0 +1,96 @@
+<HEAD><TITLE>discuss@charon.mit.edu: [155] in "Pthreads Bugs"</TITLE>
+<H1>[155] in Pthreads Bugs</H1></HEAD>
+<A HREF="/"><IMG SRC="/i-d.gif" ALT="root"></A>
+<A HREF="?155"><IMG SRC="/i-back.gif" ALT="meeting"></A>
+<A HREF="/help.html"><IMG SRC="/i-help.gif" ALT="help"></A>
+<A HREF="1"><IMG SRC="/i-first.gif" ALT="first"></A>
+<IMG SRC="/n-fref.gif" ALT="">
+<IMG SRC="/n-pref.gif" ALT="">
+<A HREF="154"><IMG SRC="/i-prev.gif" ALT="previous"></A>
+<A HREF="156"><IMG SRC="/i-next.gif" ALT="next"></A>
+<IMG SRC="/n-nref.gif" ALT="">
+<IMG SRC="/n-lref.gif" ALT="">
+<A HREF="161"><IMG SRC="/i-last.gif" ALT="last"></A>
+<HR><H2>pthread_kill() Bug</H2>
+<H3>daemon@ATHENA.MIT.EDU (Thu Dec 26 20:34:45 1996
+)</H3>
+<PRE>
+From: Chris Colohan &lt;colohan@eecg.toronto.edu&gt;
+To: pthreads-bugs@MIT.EDU, proven@MIT.EDU
+Date: Thu, 26 Dec 1996 20:33:48 -0500
+
+pthread_kill() has a problem in PThreads 1.60beta6. It checks to see
+if the target thread is in the state PS_SIGWAIT, and if it is it
+reschedules it. But it does not check if there is more than one
+thread in the PS_SIGWAIT state, and hence mangles the pthread_sigwait
+linked list, potentially resulting in threads getting blocked forever,
+and signals never being delivered. I have a *very* contrived test
+case that demonstrates this problem if you would like it. Please let
+me know...
+
+Chris
+===
+
+Diffs created with diff -c:
+
+*** /home/colohan/thesis/t/pthreads-1_60_beta6/pthreads/pthread_kill.c Tue Feb 21 03:07:18 1995
+--- pthread_kill.c Thu Dec 26 19:50:22 1996
+***************
+*** 41,51 ****
+--- 41,58 ----
+
+ #include &lt;pthread.h&gt;
+
++ /* Defined in sig.c, a linked list of threads currently
++ * blocked in sigwait(): */
++ extern struct pthread * pthread_sigwait;
++
++
+ /* ==========================================================================
+ * pthread_kill()
+ */
+ int pthread_kill(struct pthread * pthread, int sig)
+ {
++ struct pthread ** pthread_ptr;
++
+ pthread_sched_prevent();
+
+ /* Check who is the current owner of pthread */
+***************
+*** 53,62 ****
+ if (0) {
+ } else {
+ if (pthread-&gt;state == PS_SIGWAIT) {
+! if (sigismember(pthread-&gt;data.sigwait, sig)) {
+! *(int *)(pthread-&gt;ret) = sig;
+! pthread_sched_other_resume(pthread);
+! return(OK);
+ }
+ }
+ sigaddset(&amp;(pthread-&gt;sigpending), sig);
+--- 60,84 ----
+ if (0) {
+ } else {
+ if (pthread-&gt;state == PS_SIGWAIT) {
+! if(sigismember(pthread-&gt;data.sigwait, sig)) {
+! for (pthread_ptr = &amp;pthread_sigwait;
+! (*pthread_ptr);
+! pthread_ptr = &amp;((*pthread_ptr)-&gt;next)) {
+! if ((*pthread_ptr) == pthread) {
+!
+! /* Take the thread out of the
+! * pthread_sigwait linked list: */
+! *pthread_ptr=(*pthread_ptr)-&gt;next;
+!
+! *(int *)(pthread-&gt;ret) = sig;
+! pthread_sched_other_resume(pthread);
+! return(OK);
+! }
+! }
+! /* A thread should not be in the state PS_SIGWAIT
+! * without being in the pthread_sigwait linked
+! * list: */
+! PANIC();
+ }
+ }
+ sigaddset(&amp;(pthread-&gt;sigpending), sig);
diff --git a/mit-pthreads/pg++ b/mit-pthreads/pg++
new file mode 100755
index 00000000000..0d5f78929ae
--- /dev/null
+++ b/mit-pthreads/pg++
@@ -0,0 +1,32 @@
+#!/bin/sh
+
+pthreads_root=/usr/local/pthreads
+build_root=/dr1/my/masters/mysql/mit-pthreads
+src_root=/dr1/my/masters/mysql/mit-pthreads
+
+include_dir='-I$pthreads_root/include'
+lib_dir='-L$pthreads_root/lib'
+libs='-lpthread -lm -lgcc -lpthread'
+
+# Might be a good idea to also provide a way to override pthreads_root
+# so that we can use this script in the build tree, before installation.
+if arg="$1" ; then
+ case $arg in
+ -notinstalled)
+ include_dir='-I$build_root/include -I$src_root/include'
+ lib_dir='-L$build_root/obj'
+ shift
+ ;;
+ esac
+fi
+
+for arg in "$@" ; do
+ case $arg in
+ -nostdinc) include_dir= ;;
+ -nostdlib | -c) libs= ;;
+ esac
+done
+
+# Include the -L option in any case, just in case the user provided the
+# names of some libraries we've built threaded versions of.
+eval exec g++ '"$@"' $include_dir $lib_dir $libs
diff --git a/mit-pthreads/pgcc b/mit-pthreads/pgcc
new file mode 100755
index 00000000000..6eed8a2d0f0
--- /dev/null
+++ b/mit-pthreads/pgcc
@@ -0,0 +1,32 @@
+#!/bin/sh
+
+pthreads_root=/usr/local/pthreads
+build_root=/dr1/my/masters/mysql/mit-pthreads
+src_root=/dr1/my/masters/mysql/mit-pthreads
+
+include_dir='-I$pthreads_root/include'
+lib_dir='-L$pthreads_root/lib'
+libs='-lpthread -lm -lgcc -lpthread'
+
+# Might be a good idea to also provide a way to override pthreads_root
+# so that we can use this script in the build tree, before installation.
+if arg="$1" ; then
+ case $arg in
+ -notinstalled)
+ include_dir='-I$build_root/include -I$src_root/include'
+ lib_dir='-L$build_root/obj'
+ shift
+ ;;
+ esac
+fi
+
+for arg in "$@" ; do
+ case $arg in
+ -nostdinc) include_dir= ;;
+ -nostdlib | -c) libs= ;;
+ esac
+done
+
+# Include the -L option in any case, just in case the user provided the
+# names of some libraries we've built threaded versions of.
+eval exec gcc '"$@"' $include_dir $lib_dir $libs
diff --git a/mit-pthreads/pthreads/GNUmakefile.inc b/mit-pthreads/pthreads/GNUmakefile.inc
new file mode 100644
index 00000000000..c8621495bac
--- /dev/null
+++ b/mit-pthreads/pthreads/GNUmakefile.inc
@@ -0,0 +1,46 @@
+# from: @(#)Makefile.inc 5.6 (Berkeley) 6/4/91
+
+# pthread sources
+VPATH := $(VPATH):${srcdir}/pthreads
+
+SRCS:= cleanup.c cond.c fd.c fd_kern.c fd_pipe.c fd_sysv.c file.c globals.c \
+ malloc.c mutex.c pthread.c pthread_attr.c queue.c signal.c machdep.c \
+ syscall.S pthread_join.c pthread_detach.c pthread_once.c sleep.c \
+ specific.c process.c wait.c errno.c schedparam.c _exit.c prio_queue.c \
+ pthread_init.c init.cc sig.c info.c mutexattr.c select.c wrapper.c \
+ dump_state.c pthread_kill.c stat.c readv.c writev.c condattr.c \
+ pthread_cancel.c panic.c $(SRCS)
+
+ifeq ($(HAVE_SYSCALL_TEMPLATE),yes)
+SYSCALL_FILTER_RULE= for s in $(AVAILABLE_SYSCALLS) ; do \
+ case " $(SYSCALL_EXCEPTIONS) " in \
+ *" "$$s" "*) ;; \
+ *) echo $$s ;; \
+ esac ; \
+ done
+STD_SYSCALLS:=$(shell $(SYSCALL_FILTER_RULE))
+STD_SYSCALL_FILES:= $(addprefix S,$(addsuffix .o,$(STD_SYSCALLS)))
+EXTRA_OBJS := $(EXTRA_OBJS) syscalls.o
+# EXTRA_OBJS := $(EXTRA_OBJS) $(STD_SYSCALL_FILES)
+
+ifndef SYSCALL_PIC_COMPILE
+SYSCALL_PIC_COMPILE=true
+endif
+
+obj/syscalls.o: syscall-template.S
+ -rm -rf obj/syscalls
+ mkdir obj/syscalls
+ for syscall in $(STD_SYSCALLS) ; do \
+ echo $$syscall ; \
+ $(CC) $(CFLAGS) -DSYSCALL_NAME=$$syscall -c syscall-template.S -o obj/syscalls/S$$syscall.o ; \
+ $(SYSCALL_PIC_COMPILE) ; \
+ done
+ x=`pwd` && cd obj/syscalls && ld -r -o ../syscalls.o S*.o && cd $$x
+ rm -r obj/syscalls
+endif
+
+syscall.o: ${.CURDIR}/pthreads/syscall.S
+ cpp ${CPPFLAGS} ${.CURDIR}/pthreads/syscall.S > syscall.i
+ as syscall.i
+ rm syscall.i
+ mv a.out syscall.o
diff --git a/mit-pthreads/pthreads/Makefile.inc b/mit-pthreads/pthreads/Makefile.inc
new file mode 100644
index 00000000000..3939d57de6e
--- /dev/null
+++ b/mit-pthreads/pthreads/Makefile.inc
@@ -0,0 +1,75 @@
+# from: @(#)Makefile.inc 5.6 (Berkeley) 6/4/91
+
+# pthread sources
+.PATH: ${srcdir}/pthreads
+
+SRCS+= cleanup.c cond.c fd.c fd_kern.c fd_pipe.c file.c globals.c malloc.c \
+ mutex.c pthread.c pthread_attr.c queue.c signal.c machdep.c syscall.S \
+ pthread_join.c pthread_detach.c pthread_once.c sleep.c specific.c \
+ process.c wait.c errno.c schedparam.c _exit.c prio_queue.c \
+ pthread_init.c init.cc sig.c info.c mutexattr.c select.c wrapper.c \
+ dump_state.c pthread_kill.c condattr.c pthread_cancel.c panic.c
+
+.if $(HAVE_SYSCALL_TEMPLATE) == yes
+OBJS+= syscalls.o
+.if !defined(NOPIC)
+SOBJS+= syscalls.so
+SYSCALL_PIC_COMPILE= $(CC) $(CFLAGS) -DSYSCALL_NAME=$$syscall -DPIC -c ${.CURDIR}/syscall-template.S -o ${.OBJDIR}/syscalls/S$$syscall.so
+.else
+SYSCALL_PIC_COMPILE= true
+.endif
+.if !defined(NOPROFILE)
+POBJS+= syscalls.po
+SYSCALL_PROF_COMPILE= $(CC) $(CFLAGS) -DSYSCALL_NAME=$$syscall -pg -c ${.CURDIR}/syscall-template.S -o ${.OBJDIR}/syscalls/S$$syscall.po
+.else
+SYSCALL_PROF_COMPILE= true
+.endif
+
+OPSYS!= uname -s
+
+syscalls.o syscalls.so syscalls.po : syscall-template.S
+ -rm -rf ${.OBJDIR}/syscalls
+ mkdir ${.OBJDIR}/syscalls
+ for syscall in $(AVAILABLE_SYSCALLS) ; do \
+ case " $(SYSCALL_EXCEPTIONS) " in \
+ *" "$$syscall" "*) ;; \
+ *) echo $$syscall ; \
+ $(CC) $(CFLAGS) -DSYSCALL_NAME=$$syscall -c ${.CURDIR}/syscall-template.S -o ${.OBJDIR}/syscalls/S$$syscall.o ; \
+ $(SYSCALL_PIC_COMPILE) ; \
+ $(SYSCALL_PROF_COMPILE) ;; \
+ esac ; \
+ done
+ x=`pwd` && cd ${.OBJDIR}/syscalls && ld -r -o ../syscalls.o *.o && cd $$x
+.if !defined(NOPIC)
+ x=`pwd` && cd ${.OBJDIR}/syscalls && ld -r -o ../syscalls.so *.so && cd $$x
+.endif
+.if !defined(NOPROFILE)
+ x=`pwd` && cd ${.OBJDIR}/syscalls && ld -r -o ../syscalls.po *.po && cd $$x
+.endif
+ rm -r ${.OBJDIR}/syscalls
+.endif
+
+syscall.o: syscall.S
+.if (${OPSYS} == "FreeBSD")
+ $(CC) -c -x assembler-with-cpp -o syscall.o ${.CURDIR}/syscall.S
+.else
+ cpp ${CPPFLAGS} ${.CURDIR}/syscall.S > syscall.i
+ as syscall.i
+ rm syscall.i
+ mv a.out syscall.o
+.endif
+
+syscall.po: syscall.S
+.if (${OPSYS} == "FreeBSD")
+ $(CC) -c -x assembler-with-cpp -o syscall.po ${.CURDIR}/syscall.S
+.else
+ cpp ${CPPFLAGS} ${.CURDIR}/syscall.S > syscall.i
+ as syscall.i
+ rm syscall.i
+ mv a.out syscall.po
+.endif
+
+MAN2+=
+
+MAN3+=
+
diff --git a/mit-pthreads/pthreads/_exit.c b/mit-pthreads/pthreads/_exit.c
new file mode 100644
index 00000000000..fde795011ce
--- /dev/null
+++ b/mit-pthreads/pthreads/_exit.c
@@ -0,0 +1,80 @@
+/* ==== _exit.c ============================================================
+ * Copyright (c) 1994 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Description : The locking functions for stdio.
+ *
+ * 1.00 94/09/04 proven
+ * -Started coding this file.
+ */
+
+#ifndef lint
+static const char rcsid[] = "$Id$";
+#endif
+
+#include <pthread.h>
+#include <fcntl.h>
+
+/* ==========================================================================
+ * _exit()
+ *
+ * Change all file descriptors back to their original state,
+ * before exiting for good.
+ */
+void _exit(int status)
+{
+ int fd;
+
+ pthread_sched_prevent();
+
+ for (fd = 0; fd < dtablesize; fd++) {
+ if (fd_table[fd] == NULL) {
+ continue;
+ }
+ /* Is it a kernel fd ? */
+ if ((!fd_table[fd]->ops) || (fd_table[fd]->ops->use_kfds != 1)) {
+ continue;
+ }
+ switch (fd_table[fd]->type) {
+ case FD_HALF_DUPLEX:
+ machdep_sys_fcntl(fd_table[fd]->fd.i, F_SETFL, fd_table[fd]->flags);
+ fd_table[fd]->type = FD_TEST_HALF_DUPLEX;
+ break;
+ case FD_FULL_DUPLEX:
+ machdep_sys_fcntl(fd_table[fd]->fd.i, F_SETFL, fd_table[fd]->flags);
+ fd_table[fd]->type = FD_TEST_FULL_DUPLEX;
+ break;
+ default:
+ break;
+ }
+ }
+ machdep_sys_exit(status);
+}
+
diff --git a/mit-pthreads/pthreads/cleanup.c b/mit-pthreads/pthreads/cleanup.c
new file mode 100644
index 00000000000..3eb096b8337
--- /dev/null
+++ b/mit-pthreads/pthreads/cleanup.c
@@ -0,0 +1,84 @@
+/* ==== cleanup.c =======================================================
+ * Copyright (c) 1994 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Description : Pthread attribute functions.
+ *
+ * 1.20 94/02/13 proven
+ * -Started coding this file.
+ */
+
+#ifndef lint
+static const char rcsid[] = "$Id$";
+#endif
+
+#include <pthread.h>
+#include <errno.h>
+#include <stdlib.h>
+
+/* ==========================================================================
+ * pthread_cleanup_push()
+ */
+int pthread_cleanup_push(void (*routine)(void *), void *routine_arg)
+{
+ struct pthread_cleanup *new;
+ int ret;
+
+ if ((new = (struct pthread_cleanup*)malloc(sizeof(struct pthread_cleanup))))
+ {
+ new->routine = routine;
+ new->routine_arg = routine_arg;
+ new->next = pthread_run->cleanup;
+
+ pthread_run->cleanup = new;
+ ret = OK;
+ } else {
+ ret = ENOMEM;
+ }
+ return(ret);
+}
+
+/* ==========================================================================
+ * pthread_cleanup_pop()
+ */
+void pthread_cleanup_pop(int execute)
+{
+ struct pthread_cleanup *old;
+
+ if ((old = pthread_run->cleanup))
+ {
+ pthread_run->cleanup = old->next;
+ if (execute) {
+ old->routine(old->routine_arg);
+ }
+ free(old);
+ }
+}
+
diff --git a/mit-pthreads/pthreads/cond.c b/mit-pthreads/pthreads/cond.c
new file mode 100644
index 00000000000..8dacd0397ce
--- /dev/null
+++ b/mit-pthreads/pthreads/cond.c
@@ -0,0 +1,437 @@
+/* ==== cond.c ============================================================
+ * Copyright (c) 1993, 1994 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Description : Condition variable functions.
+ *
+ * 1.00 93/10/28 proven
+ * -Started coding this file.
+ */
+
+#ifndef lint
+static const char rcsid[] = "$Id$";
+#endif
+
+#include <pthread.h>
+#include <sys/time.h>
+#include <stdlib.h>
+#include <timers.h>
+#include <errno.h>
+
+#ifndef ETIME
+#define ETIME ETIMEDOUT
+#endif
+
+/* ==========================================================================
+ * pthread_cond_is_debug()
+ *
+ * Check that cond is a debug cond and if so returns entry number into
+ * array of debug condes.
+ */
+static int pthread_cond_debug_count = 0;
+static pthread_cond_t ** pthread_cond_debug_ptrs = NULL;
+static pthread_mutex_t pthread_cond_debug_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+static inline int pthread_cond_is_debug(pthread_cond_t * cond)
+{
+ int i;
+
+ for (i = 0; i < pthread_cond_debug_count; i++) {
+ if (pthread_cond_debug_ptrs[i] == cond) {
+ return(i);
+ }
+ }
+ return(NOTOK);
+}
+/* ==========================================================================
+ * pthread_cond_init()
+ *
+ * In this implementation I don't need to allocate memory.
+ * ENOMEM, EAGAIN should never be returned. Arch that have
+ * weird constraints may need special coding.
+ */
+int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *cond_attr)
+{
+ enum pthread_condtype type;
+
+ /* Only check if attr specifies some mutex type other than fast */
+ if ((cond_attr) && (cond_attr->c_type != COND_TYPE_FAST)) {
+ if (cond_attr->c_type >= COND_TYPE_MAX) {
+ return(EINVAL);
+ }
+ type = cond_attr->c_type;
+ } else {
+ type = COND_TYPE_FAST;
+ }
+
+ switch (type) {
+ case COND_TYPE_FAST:
+ case COND_TYPE_COUNTING_FAST:
+ break;
+ case COND_TYPE_DEBUG:
+ pthread_mutex_lock(&pthread_cond_debug_mutex);
+ if (pthread_cond_is_debug(cond) == NOTOK) {
+ pthread_cond_t ** new;
+
+ if ((new = (pthread_cond_t **)realloc(pthread_cond_debug_ptrs,
+ (pthread_cond_debug_count + 1) * (sizeof(void *)))) == NULL) {
+ pthread_mutex_unlock(&pthread_cond_debug_mutex);
+ return(ENOMEM);
+ }
+ pthread_cond_debug_ptrs = new;
+ pthread_cond_debug_ptrs[pthread_cond_debug_count++] = cond;
+ } else {
+ pthread_mutex_unlock(&pthread_cond_debug_mutex);
+ return(EBUSY);
+ }
+ pthread_mutex_unlock(&pthread_cond_debug_mutex);
+ break;
+ case COND_TYPE_STATIC_FAST:
+ defualt:
+ return(EINVAL);
+ break;
+ }
+
+ /* Set all other paramaters */
+ pthread_queue_init(&cond->c_queue);
+ cond->c_flags |= COND_FLAGS_INITED;
+ cond->c_type = type;
+ return(OK);
+}
+
+/* ==========================================================================
+ * pthread_cond_destroy()
+ */
+int pthread_cond_destroy(pthread_cond_t *cond)
+{
+ int i;
+
+ /* Only check if cond is of type other than fast */
+ switch(cond->c_type) {
+ case COND_TYPE_FAST:
+ case COND_TYPE_COUNTING_FAST:
+ break;
+ case COND_TYPE_DEBUG:
+ if (pthread_queue_get(&(cond->c_queue))) {
+ return(EBUSY);
+ }
+ pthread_mutex_lock(&pthread_cond_debug_mutex);
+ if ((i = pthread_cond_is_debug(cond)) == NOTOK) {
+ pthread_mutex_unlock(&pthread_cond_debug_mutex);
+ return(EINVAL);
+ }
+
+ /* Remove the cond from the list of debug condition variables */
+ pthread_cond_debug_ptrs[i] =
+ pthread_cond_debug_ptrs[--pthread_cond_debug_count];
+ pthread_cond_debug_ptrs[pthread_cond_debug_count] = NULL;
+ pthread_mutex_unlock(&pthread_cond_debug_mutex);
+ break;
+ case COND_TYPE_STATIC_FAST:
+ default:
+ return(EINVAL);
+ break;
+ }
+
+ /* Cleanup cond, others might want to use it. */
+ pthread_queue_init(&cond->c_queue);
+ cond->c_flags = 0;
+ return(OK);
+}
+
+/* ==========================================================================
+ * pthread_cond_wait()
+ */
+int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
+{
+ int rval;
+
+ pthread_sched_prevent();
+ switch (cond->c_type) {
+ case COND_TYPE_DEBUG:
+ pthread_mutex_lock(&pthread_cond_debug_mutex);
+ if (pthread_cond_is_debug(cond) == NOTOK) {
+ pthread_mutex_unlock(&pthread_cond_debug_mutex);
+ pthread_sched_resume();
+ return(EINVAL);
+ }
+ pthread_mutex_unlock(&pthread_cond_debug_mutex);
+
+ /*
+ * Fast condition variables do not check for any error conditions.
+ */
+ case COND_TYPE_FAST:
+ case COND_TYPE_STATIC_FAST:
+ pthread_queue_enq(&cond->c_queue, pthread_run);
+ pthread_mutex_unlock(mutex);
+
+ pthread_run->data.mutex = mutex;
+
+ SET_PF_WAIT_EVENT(pthread_run);
+ SET_PF_AT_CANCEL_POINT(pthread_run); /* This is a cancel point */
+ /* Reschedule will unlock pthread_run */
+ pthread_resched_resume(PS_COND_WAIT);
+ CLEAR_PF_AT_CANCEL_POINT(pthread_run); /* No longer at cancel point */
+ CLEAR_PF_DONE_EVENT(pthread_run);
+
+ pthread_run->data.mutex = NULL;
+
+ rval = pthread_mutex_lock(mutex);
+ return(rval);
+ break;
+ case COND_TYPE_COUNTING_FAST:
+ {
+ int count = mutex->m_data.m_count;
+
+ pthread_queue_enq(&cond->c_queue, pthread_run);
+ pthread_mutex_unlock(mutex);
+ mutex->m_data.m_count = 1;
+
+ pthread_run->data.mutex = mutex;
+
+ SET_PF_WAIT_EVENT(pthread_run);
+ SET_PF_AT_CANCEL_POINT(pthread_run); /* This is a cancel point */
+ /* Reschedule will unlock pthread_run */
+ pthread_resched_resume(PS_COND_WAIT);
+ CLEAR_PF_AT_CANCEL_POINT(pthread_run); /* No longer at cancel point */
+ CLEAR_PF_DONE_EVENT(pthread_run);
+
+ pthread_run->data.mutex = NULL;
+
+ rval = pthread_mutex_lock(mutex);
+ mutex->m_data.m_count = count;
+ return(rval);
+ break;
+ }
+ default:
+ rval = EINVAL;
+ break;
+ }
+ pthread_sched_resume();
+ return(rval);
+}
+
+/* ==========================================================================
+ * pthread_cond_timedwait()
+ */
+int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
+ const struct timespec * abstime)
+{
+ struct timespec current_time, new_time;
+ int rval = OK;
+
+ pthread_sched_prevent();
+ machdep_gettimeofday(& current_time);
+
+ switch (cond->c_type) {
+ case COND_TYPE_DEBUG:
+ pthread_mutex_lock(&pthread_cond_debug_mutex);
+ if (pthread_cond_is_debug(cond) == NOTOK) {
+ pthread_mutex_unlock(&pthread_cond_debug_mutex);
+ pthread_sched_resume();
+ return(EINVAL);
+ }
+ pthread_mutex_unlock(&pthread_cond_debug_mutex);
+
+ /*
+ * Fast condition variables do not check for any error conditions.
+ */
+ case COND_TYPE_FAST:
+ case COND_TYPE_STATIC_FAST:
+
+ /* Set pthread wakeup time*/
+ pthread_run->wakeup_time = *abstime;
+
+ /* Install us on the sleep queue */
+ sleep_schedule (&current_time, &(pthread_run->wakeup_time));
+
+ pthread_queue_enq(&cond->c_queue, pthread_run);
+ SET_PF_WAIT_EVENT(pthread_run);
+ pthread_mutex_unlock(mutex);
+
+ pthread_run->data.mutex = mutex;
+
+ SET_PF_AT_CANCEL_POINT(pthread_run); /* This is a cancel point */
+ /* Reschedule will unlock pthread_run */
+ pthread_resched_resume(PS_COND_WAIT);
+ CLEAR_PF_AT_CANCEL_POINT(pthread_run); /* No longer at cancel point */
+
+ pthread_run->data.mutex = NULL;
+
+ /* Remove ourselves from sleep queue. If we fail then we timedout */
+ if (sleep_cancel(pthread_run) == NOTOK) {
+ SET_ERRNO(ETIME);
+ rval = ETIME;
+ }
+
+ CLEAR_PF_DONE_EVENT(pthread_run);
+ pthread_mutex_lock(mutex);
+ return(rval);
+ break;
+ case COND_TYPE_COUNTING_FAST:
+ {
+ int count = mutex->m_data.m_count;
+
+ /* Set pthread wakeup time*/
+ pthread_run->wakeup_time = *abstime;
+
+ /* Install us on the sleep queue */
+ sleep_schedule (&current_time, &(pthread_run->wakeup_time));
+
+ pthread_queue_enq(&cond->c_queue, pthread_run);
+ SET_PF_WAIT_EVENT(pthread_run);
+ pthread_mutex_unlock(mutex);
+
+ pthread_run->data.mutex = mutex;
+
+ SET_PF_AT_CANCEL_POINT(pthread_run); /* This is a cancel point */
+ /* Reschedule will unlock pthread_run */
+ pthread_resched_resume(PS_COND_WAIT);
+ CLEAR_PF_AT_CANCEL_POINT(pthread_run); /* No longer at cancel point */
+
+ pthread_run->data.mutex = NULL;
+
+ /* Remove ourselves from sleep queue. If we fail then we timedout */
+ if (sleep_cancel(pthread_run) == NOTOK) {
+ SET_ERRNO(ETIME);
+ rval = ETIME;
+ }
+
+ CLEAR_PF_DONE_EVENT(pthread_run);
+ pthread_mutex_lock(mutex);
+ mutex->m_data.m_count = count;
+ return(rval);
+ break;
+ }
+ default:
+ rval = EINVAL;
+ break;
+ }
+ pthread_sched_resume();
+ return(rval);
+}
+
+/* ==========================================================================
+ * pthread_cond_signal()
+ */
+int pthread_cond_signal(pthread_cond_t *cond)
+{
+ struct pthread *pthread;
+ int rval;
+
+ pthread_sched_prevent();
+ switch (cond->c_type) {
+ case COND_TYPE_DEBUG:
+ pthread_mutex_lock(&pthread_cond_debug_mutex);
+ if (pthread_cond_is_debug(cond) == NOTOK) {
+ pthread_mutex_unlock(&pthread_cond_debug_mutex);
+ pthread_sched_resume();
+ return(EINVAL);
+ }
+ pthread_mutex_unlock(&pthread_cond_debug_mutex);
+
+ case COND_TYPE_FAST:
+ case COND_TYPE_STATIC_FAST:
+ if (pthread = pthread_queue_deq(&cond->c_queue)) {
+ if ((SET_PF_DONE_EVENT(pthread)) == OK) {
+ pthread_sched_other_resume(pthread);
+ } else {
+ pthread_sched_resume();
+ }
+ return(OK);
+ }
+ rval = OK;
+ break;
+ default:
+ rval = EINVAL;
+ break;
+ }
+ pthread_sched_resume();
+ return(rval);
+}
+
+/* ==========================================================================
+ * pthread_cond_broadcast()
+ *
+ * Not much different then the above routine.
+ */
+int pthread_cond_broadcast(pthread_cond_t *cond)
+{
+ struct pthread * pthread, * high_pthread, * low_pthread;
+ int rval;
+
+ pthread_sched_prevent();
+ switch (cond->c_type) {
+ case COND_TYPE_DEBUG:
+ pthread_mutex_lock(&pthread_cond_debug_mutex);
+ if (pthread_cond_is_debug(cond) == NOTOK) {
+ pthread_mutex_unlock(&pthread_cond_debug_mutex);
+ pthread_sched_resume();
+ return(EINVAL);
+ }
+ pthread_mutex_unlock(&pthread_cond_debug_mutex);
+
+ case COND_TYPE_FAST:
+ case COND_TYPE_STATIC_FAST:
+ if (pthread = pthread_queue_deq(&cond->c_queue)) {
+ pthread->state = PS_RUNNING;
+ high_pthread = pthread;
+
+ while (pthread = pthread_queue_deq(&cond->c_queue)) {
+ if (pthread->pthread_priority >
+ high_pthread->pthread_priority) {
+ low_pthread = high_pthread;
+ high_pthread = pthread;
+ } else {
+ low_pthread = pthread;
+ }
+ if ((SET_PF_DONE_EVENT(low_pthread)) == OK) {
+ pthread_prio_queue_enq(pthread_current_prio_queue,
+ low_pthread);
+ low_pthread->state = PS_RUNNING;
+ }
+ }
+ if ((SET_PF_DONE_EVENT(high_pthread)) == OK) {
+ pthread_sched_other_resume(high_pthread);
+ } else {
+ pthread_sched_resume();
+ }
+ return(OK);
+ }
+ rval = OK;
+ break;
+ default:
+ rval = EINVAL;
+ break;
+ }
+ pthread_sched_resume();
+ return(rval);
+}
+
diff --git a/mit-pthreads/pthreads/condattr.c b/mit-pthreads/pthreads/condattr.c
new file mode 100644
index 00000000000..ac010bdf4b1
--- /dev/null
+++ b/mit-pthreads/pthreads/condattr.c
@@ -0,0 +1,90 @@
+/* ==== condattr.c ===========================================================
+ * Copyright (c) 1995 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Description : Mutex functions.
+ *
+ * 1.00 95/08/22 proven
+ * -Started coding this file.
+ */
+
+#ifndef lint
+static const char rcsid[] = "$Id$";
+#endif
+
+#include <pthread.h>
+#include <errno.h>
+
+/* ==========================================================================
+ * pthread_condattr_init()
+ */
+int pthread_condattr_init(pthread_condattr_t *attr)
+{
+ attr->c_type = COND_TYPE_FAST;
+ return(OK);
+}
+
+/* ==========================================================================
+ * pthread_condattr_destroy()
+ */
+int pthread_condattr_destroy(pthread_condattr_t *attr)
+{
+ return(OK);
+}
+
+/* ==========================================================================
+ * pthread_condattr_settype()
+ */
+int pthread_condattr_settype(pthread_condattr_t *attr, unsigned int type)
+{
+ switch(type) {
+ case PTHREAD_CONDTYPE_FAST:
+ attr->c_type = COND_TYPE_FAST;
+ break;
+ case PTHREAD_CONDTYPE_RECURSIVE:
+ attr->c_type = COND_TYPE_COUNTING_FAST;
+ break;
+ case PTHREAD_CONDTYPE_DEBUG:
+ attr->c_type = COND_TYPE_DEBUG;
+ break;
+ default:
+ return(EINVAL);
+ }
+ return(OK);
+}
+
+/* ==========================================================================
+ * pthread_condattr_gettype()
+ */
+int pthread_condattr_gettype(pthread_condattr_t *attr, unsigned int * type)
+{
+ *type = (unsigned int)attr->c_type;
+ return(OK);
+}
diff --git a/mit-pthreads/pthreads/dump_state.c b/mit-pthreads/pthreads/dump_state.c
new file mode 100644
index 00000000000..3d9840bad64
--- /dev/null
+++ b/mit-pthreads/pthreads/dump_state.c
@@ -0,0 +1,88 @@
+/* ==== dump_state.c ============================================================
+ * Copyright (c) 1993, 1994 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ *
+ * Description : Bogus debugging output routines.
+ *
+ * 1.00 95/02/08 snl
+ * -Started coding this file.
+ */
+
+#include <pthread.h>
+#include <stdio.h>
+
+/* ==========================================================================
+ * pthread_dump_state()
+ *
+ * Totally, totally bogus routine to dump the state of pthreads.
+ */
+
+void
+pthread_dump_state()
+{
+ pthread_t thread;
+
+ for (thread = pthread_link_list; thread; thread = thread->pll) {
+ printf("Thread %lx", thread);
+ if (thread == pthread_initial)
+ printf("*");
+ if (thread == pthread_run)
+ printf("^");
+ printf(" ");
+ switch (thread->state) {
+ case PS_RUNNING: printf("RUNNING "); break;
+ case PS_MUTEX_WAIT: printf("MUTEX_WAIT "); break;
+ case PS_COND_WAIT: printf("COND_WAIT "); break;
+ case PS_FDLR_WAIT: printf("FDLR_WAIT "); break;
+ case PS_FDLW_WAIT: printf("FDLW_WAIT "); break;
+ case PS_FDR_WAIT: printf("FDR_WAIT "); break;
+ case PS_FDW_WAIT: printf("FDW_WAIT "); break;
+ case PS_SELECT_WAIT: printf("SELECT "); break;
+ case PS_SLEEP_WAIT: printf("SLEEP_WAIT "); break;
+ case PS_WAIT_WAIT: printf("WAIT_WAIT "); break;
+ case PS_SIGWAIT: printf("SIGWAIT "); break;
+ case PS_JOIN: printf("JOIN "); break;
+ case PS_DEAD: printf("DEAD "); break;
+ default: printf("*UNKNOWN %d* ", thread->state);
+ break;
+ }
+ switch (thread->attr.schedparam_policy) {
+ case SCHED_RR: printf("RR "); break;
+ case SCHED_IO: printf("IO "); break;
+ case SCHED_FIFO: printf("FIFO "); break;
+ case SCHED_OTHER: printf("OTHER "); break;
+ default: printf("*UNKNOWN %d* ",
+ thread->attr.schedparam_policy);
+ break;
+ }
+ }
+}
diff --git a/mit-pthreads/pthreads/errno.c b/mit-pthreads/pthreads/errno.c
new file mode 100644
index 00000000000..bc680235424
--- /dev/null
+++ b/mit-pthreads/pthreads/errno.c
@@ -0,0 +1,53 @@
+/* ==== errno.c ============================================================
+ * Copyright (c) 1994 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Description : Return the pointer to the threads errno address.
+ *
+ * 1.32 94/05/25 proven
+ * -Started coding this file.
+ */
+
+#ifndef lint
+static const char rcsid[] = "$Id$";
+#endif
+
+#include <pthread.h>
+
+/* ==========================================================================
+ * __error()
+ */
+int * __error()
+{
+ if (!pthread_run->error_p) {
+ pthread_run->error_p = &pthread_run->error;
+ }
+ return(pthread_run->error_p);
+}
diff --git a/mit-pthreads/pthreads/fd.c b/mit-pthreads/pthreads/fd.c
new file mode 100644
index 00000000000..3eb59c11bd1
--- /dev/null
+++ b/mit-pthreads/pthreads/fd.c
@@ -0,0 +1,1083 @@
+/* ==== fd.c ============================================================
+ * Copyright (c) 1993, 1994 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Description : All the syscalls dealing with fds.
+ *
+ * 1.00 93/08/14 proven
+ * -Started coding this file.
+ *
+ * 1.01 93/11/13 proven
+ * -The functions readv() and writev() added.
+ */
+
+#ifndef lint
+static const char rcsid[] = "$Id$";
+#endif
+
+#include "config.h"
+#include <pthread.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/uio.h>
+#include <sys/ioctl.h>
+#ifdef HAVE_SYS_FILIO_H
+#include <sys/filio.h> /* For ioctl */
+#endif
+#if __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+#include <fcntl.h>
+#include <errno.h>
+#include <pthread/posix.h>
+
+/*
+ * These first functions really should not be called by the user.
+ *
+ * I really should dynamically figure out what the table size is.
+ */
+static pthread_mutex_t fd_table_mutex = PTHREAD_MUTEX_INITIALIZER;
+static const int dtablecount = 4096/sizeof(struct fd_table_entry);
+int dtablesize;
+
+static int fd_get_pthread_fd_from_kernel_fd( int );
+
+/* ==========================================================================
+ * Allocate dtablecount entries at once and populate the fd_table.
+ *
+ * fd_init_entry()
+ */
+int fd_init_entry(int entry)
+{
+ struct fd_table_entry *fd_entry;
+ int i, round;
+
+ if (fd_table[entry] == NULL) {
+ round = entry - entry % dtablecount;
+
+ if ((fd_entry = (struct fd_table_entry *)malloc(
+ sizeof(struct fd_table_entry) * dtablecount)) == NULL) {
+ return(NOTOK);
+ }
+
+ for (i = 0; i < dtablecount && round+i < dtablesize; i++) {
+ fd_table[round + i] = &fd_entry[i];
+
+ fd_table[round + i]->ops = NULL;
+ fd_table[round + i]->type = FD_NT;
+ fd_table[round + i]->fd.i = NOTOK;
+ fd_table[round + i]->flags = 0;
+ fd_table[round + i]->count = 0;
+
+ pthread_mutex_init(&(fd_table[round + i]->mutex), NULL);
+ pthread_queue_init(&(fd_table[round + i]->r_queue));
+ pthread_queue_init(&(fd_table[round + i]->w_queue));
+ fd_table[round + i]->r_owner = NULL;
+ fd_table[round + i]->w_owner = NULL;
+ fd_table[round + i]->r_lockcount= 0;
+ fd_table[round + i]->w_lockcount= 0;
+
+ fd_table[round + i]->next = NULL;
+ }
+ }
+ return(OK);
+}
+
+/* ==========================================================================
+ * fd_check_entry()
+ */
+int fd_check_entry(unsigned int entry)
+{
+ int ret = OK;
+
+ pthread_mutex_lock(&fd_table_mutex);
+
+ if (entry < dtablesize) {
+ if (fd_table[entry] == NULL) {
+ if (fd_init_entry(entry)) {
+ SET_ERRNO(EBADF);
+ ret = -EBADF;
+ }
+ }
+ } else {
+ SET_ERRNO(EBADF);
+ ret = -EBADF;
+ }
+
+ pthread_mutex_unlock(&fd_table_mutex);
+ return(ret);
+}
+
+/* ==========================================================================
+ * fd_init()
+ */
+void fd_init(void)
+{
+ int i;
+
+ if ((dtablesize = machdep_sys_getdtablesize()) < 0) {
+ /* Can't figure out the table size. */
+ PANIC();
+ }
+
+ /* select() can only handle FD_SETSIZE descriptors, so our inner loop will
+ * break if dtablesize is higher than that. This should be removed if and
+ * when the inner loop is rewritten to use poll(). */
+ if (dtablesize > FD_SETSIZE) {
+ dtablesize = FD_SETSIZE;
+ }
+
+ if (fd_table = (struct fd_table_entry **)malloc(
+ sizeof(struct fd_table_entry) * dtablesize)) {
+ memset(fd_table, 0, sizeof(struct fd_table_entry) * dtablesize);
+ if (fd_check_entry(0) == OK) {
+ return;
+ }
+ }
+
+ /*
+ * There isn't enough memory to allocate a fd table at init time.
+ * This is a problem.
+ */
+ PANIC();
+
+}
+
+/* ==========================================================================
+ * fd_allocate()
+ */
+int fd_allocate()
+{
+ pthread_mutex_t * mutex;
+ int i;
+
+ for (i = 0; i < dtablesize; i++) {
+ if (fd_check_entry(i) == OK) {
+ mutex = &(fd_table[i]->mutex);
+ if (pthread_mutex_trylock(mutex)) {
+ continue;
+ }
+ if (fd_table[i]->count || fd_table[i]->r_owner
+ || fd_table[i]->w_owner) {
+ pthread_mutex_unlock(mutex);
+ continue;
+ }
+ if (fd_table[i]->type == FD_NT) {
+ /* Test to see if the kernel version is in use */
+ if ((machdep_sys_fcntl(i, F_GETFL, NULL)) >= OK) {
+ /* If so continue; */
+ pthread_mutex_unlock(mutex);
+ continue;
+ }
+ }
+ fd_table[i]->count++;
+ pthread_mutex_unlock(mutex);
+ return(i);
+ }
+ }
+ SET_ERRNO(ENFILE);
+ return(NOTOK);
+}
+
+/*----------------------------------------------------------------------
+ * Function: fd_get_pthread_fd_from_kernel_fd
+ * Purpose: get the fd_table index of a kernel fd
+ * Args: fd = kernel fd to convert
+ * Returns: fd_table index, -1 if not found
+ * Notes:
+ *----------------------------------------------------------------------*/
+static int
+fd_get_pthread_fd_from_kernel_fd( int kfd )
+{
+ int j;
+
+ /* This is *SICK*, but unless there is a faster way to
+ * turn a kernel fd into an fd_table index, this has to do.
+ */
+ for( j=0; j < dtablesize; j++ ) {
+ if( fd_table[j] &&
+ fd_table[j]->type != FD_NT &&
+ fd_table[j]->type != FD_NIU &&
+ fd_table[j]->fd.i == kfd ) {
+ return j;
+ }
+ }
+
+ /* Not listed byfd, Check for kernel fd == pthread fd */
+ if( fd_table[kfd] == NULL || fd_table[kfd]->type == FD_NT ) {
+ /* Assume that the kernel fd is the same */
+ return kfd;
+ }
+
+ return NOTOK; /* Not found */
+}
+
+/* ==========================================================================
+ * fd_basic_basic_unlock()
+ *
+ * The real work of unlock without the locking of fd_table[fd].lock.
+ */
+void fd_basic_basic_unlock(struct fd_table_entry * entry, int lock_type)
+{
+ struct pthread *pthread;
+
+ if (entry->r_owner == pthread_run) {
+ if ((entry->type == FD_HALF_DUPLEX) ||
+ (entry->type == FD_TEST_HALF_DUPLEX) ||
+ (lock_type == FD_READ) || (lock_type == FD_RDWR)) {
+ if (entry->r_lockcount == 0) {
+ if (pthread = pthread_queue_deq(&entry->r_queue)) {
+ pthread_sched_prevent();
+ entry->r_owner = pthread;
+ if ((SET_PF_DONE_EVENT(pthread)) == OK) {
+ pthread_sched_other_resume(pthread);
+ } else {
+ pthread_sched_resume();
+ }
+ } else {
+ entry->r_owner = NULL;
+ }
+ } else {
+ entry->r_lockcount--;
+ }
+ }
+ }
+
+ if (entry->w_owner == pthread_run) {
+ if ((entry->type != FD_HALF_DUPLEX) &&
+ (entry->type != FD_TEST_HALF_DUPLEX) &&
+ ((lock_type == FD_WRITE) || (lock_type == FD_RDWR))) {
+ if (entry->w_lockcount == 0) {
+ if (pthread = pthread_queue_deq(&entry->w_queue)) {
+ pthread_sched_prevent();
+ entry->w_owner = pthread;
+ if ((SET_PF_DONE_EVENT(pthread)) == OK) {
+ pthread_sched_other_resume(pthread);
+ } else {
+ pthread_sched_resume();
+ }
+ } else {
+ entry->w_owner = NULL;
+ }
+ } else {
+ entry->w_lockcount--;
+ }
+ }
+ }
+}
+
+/* ==========================================================================
+ * fd_basic_unlock()
+ */
+void fd_basic_unlock(int fd, int lock_type)
+{
+ fd_basic_basic_unlock(fd_table[fd], lock_type);
+}
+
+/* ==========================================================================
+ * fd_unlock()
+ */
+void fd_unlock(int fd, int lock_type)
+{
+ pthread_mutex_t *mutex;
+
+ mutex = &(fd_table[fd]->mutex);
+ pthread_mutex_lock(mutex);
+ fd_basic_basic_unlock(fd_table[fd], lock_type);
+ pthread_mutex_unlock(mutex);
+}
+
+/* ==========================================================================
+ * fd_basic_lock()
+ *
+ * The real work of lock without the locking of fd_table[fd].lock.
+ * Be sure to leave the lock the same way you found it. i.e. locked.
+ */
+int fd_basic_lock(unsigned int fd, int lock_type, pthread_mutex_t * mutex,
+ struct timespec * timeout)
+{
+ semaphore *plock;
+
+ switch (fd_table[fd]->type) {
+ case FD_NIU:
+ /* If not in use return EBADF error */
+ SET_ERRNO(EBADF);
+ return(NOTOK);
+ break;
+ case FD_NT:
+ /*
+ * If not tested, test it and see if it is valid
+ * If not ok return EBADF error
+ */
+ fd_kern_init(fd);
+ if (fd_table[fd]->type == FD_NIU) {
+ SET_ERRNO(EBADF);
+ return(NOTOK);
+ }
+ break;
+ case FD_TEST_HALF_DUPLEX:
+ case FD_TEST_FULL_DUPLEX:
+ /* If a parent process reset the fd to its proper state */
+ if (!fork_lock) {
+ /* It had better be a kernel fd */
+ fd_kern_reset(fd);
+ }
+ break;
+ default:
+ break;
+ }
+
+ if ((fd_table[fd]->type == FD_HALF_DUPLEX) ||
+ (fd_table[fd]->type == FD_TEST_HALF_DUPLEX) ||
+ (lock_type == FD_READ) || (lock_type == FD_RDWR)) {
+ if (fd_table[fd]->r_owner) {
+ if (fd_table[fd]->r_owner != pthread_run) {
+ pthread_sched_prevent();
+ pthread_queue_enq(&fd_table[fd]->r_queue, pthread_run);
+ SET_PF_WAIT_EVENT(pthread_run);
+ pthread_mutex_unlock(mutex);
+
+ if (timeout) {
+ /* get current time */
+ struct timespec current_time;
+ machdep_gettimeofday(&current_time);
+ sleep_schedule(&current_time, timeout);
+
+ /* Reschedule will unlock pthread_run */
+ pthread_run->data.fd.fd = fd;
+ pthread_run->data.fd.branch = __LINE__;
+ pthread_resched_resume(PS_FDLR_WAIT);
+ pthread_mutex_lock(mutex);
+
+ /* If we're the owner then we have to cancel the sleep */
+ if (fd_table[fd]->r_owner != pthread_run) {
+ CLEAR_PF_DONE_EVENT(pthread_run);
+ SET_ERRNO(ETIMEDOUT);
+ return(NOTOK);
+ }
+ sleep_cancel(pthread_run);
+ } else {
+ /* Reschedule will unlock pthread_run */
+ pthread_run->data.fd.fd = fd;
+ pthread_run->data.fd.branch = __LINE__;
+ pthread_resched_resume(PS_FDLR_WAIT);
+ pthread_mutex_lock(mutex);
+ }
+ CLEAR_PF_DONE_EVENT(pthread_run);
+ } else {
+ fd_table[fd]->r_lockcount++;
+ }
+ }
+ fd_table[fd]->r_owner = pthread_run;
+ }
+ if ((fd_table[fd]->type != FD_HALF_DUPLEX) &&
+ (fd_table[fd]->type != FD_TEST_HALF_DUPLEX) &&
+ ((lock_type == FD_WRITE) || (lock_type == FD_RDWR))) {
+ if (fd_table[fd]->w_owner) {
+ if (fd_table[fd]->w_owner != pthread_run) {
+ pthread_sched_prevent();
+ pthread_queue_enq(&fd_table[fd]->w_queue, pthread_run);
+ SET_PF_WAIT_EVENT(pthread_run);
+ pthread_mutex_unlock(mutex);
+
+ if (timeout) {
+ /* get current time */
+ struct timespec current_time;
+ machdep_gettimeofday(&current_time);
+ sleep_schedule(&current_time, timeout);
+
+ /* Reschedule will unlock pthread_run */
+ pthread_run->data.fd.fd = fd;
+ pthread_run->data.fd.branch = __LINE__;
+ pthread_resched_resume(PS_FDLR_WAIT);
+ pthread_mutex_lock(mutex);
+
+ /* If we're the owner then we have to cancel the sleep */
+ if (fd_table[fd]->w_owner != pthread_run) {
+ if (lock_type == FD_RDWR) {
+ /* Unlock current thread */
+ fd_basic_unlock(fd, FD_READ);
+ }
+ CLEAR_PF_DONE_EVENT(pthread_run);
+ SET_ERRNO(ETIMEDOUT);
+ return(NOTOK);
+ }
+ sleep_cancel(pthread_run);
+ } else {
+ /* Reschedule will unlock pthread_run */
+ pthread_run->data.fd.fd = fd;
+ pthread_run->data.fd.branch = __LINE__;
+ pthread_resched_resume(PS_FDLR_WAIT);
+ pthread_mutex_lock(mutex);
+ }
+ CLEAR_PF_DONE_EVENT(pthread_run);
+ } else {
+ fd_table[fd]->w_lockcount++;
+ }
+ }
+ fd_table[fd]->w_owner = pthread_run;
+ }
+ if (!fd_table[fd]->count) {
+ fd_basic_unlock(fd, lock_type);
+ return(NOTOK);
+ }
+ return(OK);
+}
+
+/*----------------------------------------------------------------------
+ * Function: fd_unlock_for_cancel
+ * Purpose: Unlock all fd locks held prior to being cancelled
+ * Args: void
+ * Returns:
+ * OK or NOTOK
+ * Notes:
+ * Assumes the kernel is locked on entry
+ *----------------------------------------------------------------------*/
+int
+fd_unlock_for_cancel( void )
+{
+ int i, fd;
+ struct pthread_select_data *data;
+ int rdlk, wrlk, lktype;
+ int found;
+
+ /* What we do depends on the previous state of the thread */
+ switch( pthread_run->old_state ) {
+ case PS_RUNNING:
+ case PS_JOIN:
+ case PS_SLEEP_WAIT:
+ case PS_WAIT_WAIT:
+ case PS_SIGWAIT:
+ case PS_FDLR_WAIT:
+ case PS_FDLW_WAIT:
+ case PS_DEAD:
+ case PS_UNALLOCED:
+ break; /* Nothing to do */
+
+ case PS_COND_WAIT:
+ CLEAR_PF_GROUP( pthread_run, PF_EVENT_GROUP );
+ /* Must reaquire the mutex according to the standard */
+ if( pthread_run->data.mutex == NULL ) {
+ PANIC();
+ }
+ pthread_mutex_lock( pthread_run->data.mutex );
+ break;
+
+ case PS_FDR_WAIT:
+ CLEAR_PF_GROUP( pthread_run, PF_EVENT_GROUP);
+ /* Free the lock on the fd being used */
+ fd = fd_get_pthread_fd_from_kernel_fd( pthread_run->data.fd.fd );
+ if( fd == NOTOK ) {
+ PANIC(); /* Can't find fd */
+ }
+ fd_unlock( fd, FD_READ );
+ break;
+
+ case PS_FDW_WAIT: /* Waiting on i/o */
+ CLEAR_PF_GROUP( pthread_run, PF_EVENT_GROUP);
+ /* Free the lock on the fd being used */
+ fd = fd_get_pthread_fd_from_kernel_fd( pthread_run->data.fd.fd );
+ if( fd == NOTOK ) {
+ PANIC(); /* Can't find fd */
+ }
+ fd_unlock( fd, FD_WRITE );
+ break;
+
+ case PS_SELECT_WAIT:
+ data = pthread_run->data.select_data;
+
+ CLEAR_PF_GROUP( pthread_run, PF_EVENT_GROUP);
+
+ for( i = 0; i < data->nfds; i++) {
+ rdlk =(FD_ISSET(i,&data->readfds)
+ || FD_ISSET(i,&data->exceptfds));
+ wrlk = FD_ISSET(i, &data->writefds);
+ lktype = rdlk ? (wrlk ? FD_RDWR : FD_READ) : FD_WRITE;
+
+ if( ! (rdlk || wrlk) )
+ continue; /* No locks, no unlock */
+
+ if( (fd = fd_get_pthread_fd_from_kernel_fd( i )) == NOTOK ) {
+ PANIC(); /* Can't find fd */
+ }
+
+ fd_unlock( fd, lktype );
+ }
+ break;
+
+ case PS_MUTEX_WAIT:
+ PANIC(); /* Should never cancel a mutex wait */
+
+ default:
+ PANIC(); /* Unknown thread status */
+ }
+}
+
+/* ==========================================================================
+ * fd_lock()
+ */
+#define pthread_mutex_lock_timedwait(a, b) pthread_mutex_lock(a)
+
+int fd_lock(unsigned int fd, int lock_type, struct timespec * timeout)
+{
+ struct timespec current_time;
+ pthread_mutex_t *mutex;
+ int error;
+
+ if ((error = fd_check_entry(fd)) == OK) {
+ mutex = &(fd_table[fd]->mutex);
+ if (pthread_mutex_lock_timedwait(mutex, timeout)) {
+ SET_ERRNO(ETIMEDOUT);
+ return(-ETIMEDOUT);
+ }
+ error = fd_basic_lock(fd, lock_type, mutex, timeout);
+ pthread_mutex_unlock(mutex);
+ }
+ return(error);
+}
+
+/* ==========================================================================
+ * fd_free()
+ *
+ * Assumes fd is locked and owner by pthread_run
+ * Don't clear the queues, fd_unlock will do that.
+ */
+struct fd_table_entry * fd_free(int fd)
+{
+ struct fd_table_entry *fd_valid;
+
+ fd_valid = NULL;
+ fd_table[fd]->r_lockcount = 0;
+ fd_table[fd]->w_lockcount = 0;
+ if (--fd_table[fd]->count) {
+ fd_valid = fd_table[fd];
+ fd_table[fd] = fd_table[fd]->next;
+ fd_valid->next = fd_table[fd]->next;
+ /* Don't touch queues of fd_valid */
+ }
+
+ fd_table[fd]->type = FD_NIU;
+ fd_table[fd]->fd.i = NOTOK;
+ fd_table[fd]->next = NULL;
+ fd_table[fd]->flags = 0;
+ fd_table[fd]->count = 0;
+ return(fd_valid);
+}
+
+
+/* ==========================================================================
+ * ======================================================================= */
+
+/* ==========================================================================
+ * read_timedwait()
+ */
+ssize_t read_timedwait(int fd, void *buf, size_t nbytes,
+ struct timespec * timeout)
+{
+ int ret;
+
+ if ((ret = fd_lock(fd, FD_READ, NULL)) == OK) {
+ ret = fd_table[fd]->ops->read(fd_table[fd]->fd,
+ fd_table[fd]->flags, buf, nbytes, timeout);
+ fd_unlock(fd, FD_READ);
+ }
+ return(ret);
+}
+
+/* ==========================================================================
+ * read()
+ */
+ssize_t read(int fd, void *buf, size_t nbytes)
+{
+ return(read_timedwait(fd, buf, nbytes, NULL));
+}
+
+/* ==========================================================================
+ * readv_timedwait()
+ */
+int readv_timedwait(int fd, const struct iovec *iov, int iovcnt,
+ struct timespec * timeout)
+{
+ int ret;
+
+ if ((ret = fd_lock(fd, FD_READ, NULL)) == OK) {
+ ret = fd_table[fd]->ops->readv(fd_table[fd]->fd,
+ fd_table[fd]->flags, iov, iovcnt, timeout);
+ fd_unlock(fd, FD_READ);
+ }
+ return(ret);
+}
+
+/* ==========================================================================
+ * readv()
+ */
+ssize_t readv(int fd, const struct iovec *iov, int iovcnt)
+{
+ return(readv_timedwait(fd, iov, iovcnt, NULL));
+}
+
+/* ==========================================================================
+ * write()
+ */
+ssize_t write_timedwait(int fd, const void *buf, size_t nbytes,
+ struct timespec * timeout)
+{
+ int ret;
+
+ if ((ret = fd_lock(fd, FD_WRITE, NULL)) == OK)
+ {
+ ret = fd_table[fd]->ops->write(fd_table[fd]->fd,
+ fd_table[fd]->flags, buf, nbytes,
+ timeout);
+ fd_unlock(fd, FD_WRITE);
+ }
+ return(ret);
+}
+
+/* ==========================================================================
+ * write()
+ */
+ssize_t write(int fd, const void * buf, size_t nbytes)
+{
+ return(write_timedwait(fd, buf, nbytes, NULL));
+}
+
+/* ==========================================================================
+ * writev_timedwait()
+ */
+int writev_timedwait(int fd, const struct iovec *iov, int iovcnt,
+ struct timespec * timeout)
+{
+ int ret;
+
+ if ((ret = fd_lock(fd, FD_WRITE, NULL)) == OK) {
+ ret = fd_table[fd]->ops->writev(fd_table[fd]->fd,
+ fd_table[fd]->flags, iov, iovcnt, timeout);
+ fd_unlock(fd, FD_WRITE);
+ }
+ return(ret);
+}
+
+/* ==========================================================================
+ * writev()
+ */
+ssize_t writev(int fd, const struct iovec *iov, int iovcnt)
+{
+ return(writev_timedwait(fd, iov, iovcnt, NULL));
+}
+
+/* ==========================================================================
+ * lseek()
+ */
+off_t lseek(int fd, off_t offset, int whence)
+{
+ off_t ret;
+
+ if ((ret = fd_lock(fd, FD_RDWR, NULL)) == OK) {
+ ret = fd_table[fd]->ops->seek(fd_table[fd]->fd,
+ fd_table[fd]->flags, offset, whence);
+ fd_unlock(fd, FD_RDWR);
+ }
+ return(ret);
+}
+
+/* ==========================================================================
+ * close()
+ *
+ * The whole close procedure is a bit odd and needs a bit of a rethink.
+ * For now close() locks the fd, calls fd_free() which checks to see if
+ * there are any other fd values poinging to the same real fd. If so
+ * It breaks the wait queue into two sections those that are waiting on fd
+ * and those waiting on other fd's. Those that are waiting on fd are connected
+ * to the fd_table[fd] queue, and the count is set to zero, (BUT THE LOCK IS NOT
+ * RELEASED). close() then calls fd_unlock which give the fd to the next queued
+ * element which determins that the fd is closed and then calls fd_unlock etc...
+ *
+ * XXX close() is even uglier now. You may assume that the kernel fd is the
+ * same as fd if fd_table[fd] == NULL or if fd_table[fd]->type == FD_NT.
+ * This is true because before any fd_table[fd] is allocated the corresponding
+ * kernel fd must be checks to see if it's valid.
+ */
+int close(int fd)
+{
+ struct fd_table_entry * entry;
+ pthread_mutex_t *mutex;
+ union fd_data realfd;
+ int ret, flags;
+
+ if(fd < 0 || fd >= dtablesize)
+ {
+ SET_ERRNO(EBADF);
+ return -1;
+ }
+ /* Need to lock the newfd by hand */
+ pthread_mutex_lock(&fd_table_mutex);
+ if (fd_table[fd]) {
+ pthread_mutex_unlock(&fd_table_mutex);
+ mutex = &(fd_table[fd]->mutex);
+ pthread_mutex_lock(mutex);
+
+ /*
+ * XXX Gross hack ... because of fork(), any fd closed by the
+ * parent should not change the fd of the child, unless it owns it.
+ */
+ switch(fd_table[fd]->type) {
+ case FD_NIU:
+ pthread_mutex_unlock(mutex);
+ ret = -EBADF;
+ break;
+ case FD_NT:
+ /*
+ * If it's not tested then the only valid possibility is it's
+ * kernel fd.
+ */
+ ret = machdep_sys_close(fd);
+ fd_table[fd]->type = FD_NIU;
+ pthread_mutex_unlock(mutex);
+ break;
+ case FD_TEST_FULL_DUPLEX:
+ case FD_TEST_HALF_DUPLEX:
+ realfd = fd_table[fd]->fd;
+ flags = fd_table[fd]->flags;
+ if ((entry = fd_free(fd)) == NULL) {
+ ret = fd_table[fd]->ops->close(realfd, flags);
+ } else {
+ /* There can't be any others waiting for fd. */
+ pthread_mutex_unlock(&entry->mutex);
+ /* Note: entry->mutex = mutex */
+ mutex = &(fd_table[fd]->mutex);
+ }
+ pthread_mutex_unlock(mutex);
+ break;
+ default:
+ ret = fd_basic_lock(fd, FD_RDWR, mutex, NULL);
+ if (ret == OK) {
+ realfd = fd_table[fd]->fd;
+ flags = fd_table[fd]->flags;
+ pthread_mutex_unlock(mutex);
+ if ((entry = fd_free(fd)) == NULL) {
+ ret = fd_table[fd]->ops->close(realfd, flags);
+ } else {
+ fd_basic_basic_unlock(entry, FD_RDWR);
+ pthread_mutex_unlock(&entry->mutex);
+ /* Note: entry->mutex = mutex */
+ }
+ fd_unlock(fd, FD_RDWR);
+ } else {
+ pthread_mutex_unlock(mutex);
+ }
+ break;
+ }
+ } else {
+ /* Don't bother creating a table entry */
+ pthread_mutex_unlock(&fd_table_mutex);
+ ret = machdep_sys_close(fd);
+ }
+ if( ret < 0) {
+ SET_ERRNO(-ret);
+ ret = -1;
+ }
+ return(ret);
+}
+
+/* ==========================================================================
+ * fd_basic_dup()
+ *
+ *
+ * This is a MAJOR guess!! I don't know if the mutext unlock is valid
+ * in the BIG picture. But it seems to be needed to avoid deadlocking
+ * with ourselves when we try to close the duped file descriptor.
+ */
+static inline void fd_basic_dup(int fd, int newfd)
+{
+ fd_table[newfd]->next = fd_table[fd]->next;
+ fd_table[fd]->next = fd_table[newfd];
+ fd_table[newfd] = fd_table[fd];
+ fd_table[fd]->count++;
+ pthread_mutex_unlock(&fd_table[newfd]->next->mutex);
+
+}
+
+/* ==========================================================================
+ * dup2()
+ *
+ * Note: Always lock the lower number fd first to avoid deadlocks.
+ * Note: Leave the newfd locked. It will be unlocked at close() time.
+ * Note: newfd must be locked by hand so it can be closed if it is open,
+ * or it won't be opened while dup is in progress.
+ */
+int dup2(fd, newfd)
+{
+ struct fd_table_entry * entry;
+ pthread_mutex_t *mutex;
+ union fd_data realfd;
+ int ret, flags;
+
+ if ((ret = fd_check_entry(newfd)) != OK)
+ return ret;
+
+ if (newfd < dtablesize) {
+ if (fd < newfd) {
+ if ((ret = fd_lock(fd, FD_RDWR, NULL)) == OK) {
+ /* Need to lock the newfd by hand */
+ mutex = &(fd_table[newfd]->mutex);
+ pthread_mutex_lock(mutex);
+
+ /* Is it inuse */
+ if (fd_basic_lock(newfd, FD_RDWR, mutex, NULL) == OK) {
+ realfd = fd_table[newfd]->fd;
+ flags = fd_table[newfd]->flags;
+ /* free it and check close status */
+ if ((entry = fd_free(newfd)) == NULL) {
+ entry = fd_table[newfd];
+ entry->ops->close(realfd, flags);
+ if (entry->r_queue.q_next) {
+ if (fd_table[fd]->next) {
+ fd_table[fd]->r_queue.q_last->next =
+ entry->r_queue.q_next;
+ } else {
+ fd_table[fd]->r_queue.q_next =
+ entry->r_queue.q_next;
+ }
+ fd_table[fd]->r_queue.q_last =
+ entry->r_queue.q_last;
+ }
+ if (entry->w_queue.q_next) {
+ if (fd_table[fd]->next) {
+ fd_table[fd]->w_queue.q_last->next =
+ entry->w_queue.q_next;
+ } else {
+ fd_table[fd]->w_queue.q_next =
+ entry->w_queue.q_next;
+ }
+ fd_table[fd]->w_queue.q_last =
+ entry->w_queue.q_last;
+ }
+ entry->r_queue.q_next = NULL;
+ entry->w_queue.q_next = NULL;
+ entry->r_queue.q_last = NULL;
+ entry->w_queue.q_last = NULL;
+ entry->r_owner = NULL;
+ entry->w_owner = NULL;
+ ret = OK;
+ } else {
+ fd_basic_basic_unlock(entry, FD_RDWR);
+ pthread_mutex_unlock(&entry->mutex);
+ /* Note: entry->mutex = mutex */
+ }
+ }
+ fd_basic_dup(fd, newfd);
+ }
+ fd_unlock(fd, FD_RDWR);
+ } else {
+ /* Need to lock the newfd by hand */
+ mutex = &(fd_table[newfd]->mutex);
+ pthread_mutex_lock(mutex);
+
+ if ((ret = fd_lock(fd, FD_RDWR, NULL)) == OK) {
+ /* Is newfd inuse */
+ if ((ret = fd_basic_lock(newfd, FD_RDWR, mutex, NULL)) == OK) {
+ realfd = fd_table[newfd]->fd;
+ flags = fd_table[newfd]->flags;
+ /* free it and check close status */
+ if ((entry = fd_free(newfd)) == NULL) {
+ entry = fd_table[newfd];
+ entry->ops->close(realfd, flags);
+ if (entry->r_queue.q_next) {
+ if (fd_table[fd]->next) {
+ fd_table[fd]->r_queue.q_last->next =
+ entry->r_queue.q_next;
+ } else {
+ fd_table[fd]->r_queue.q_next =
+ entry->r_queue.q_next;
+ }
+ fd_table[fd]->r_queue.q_last =
+ entry->r_queue.q_last;
+ }
+ if (entry->w_queue.q_next) {
+ if (fd_table[fd]->next) {
+ fd_table[fd]->w_queue.q_last->next =
+ entry->w_queue.q_next;
+ } else {
+ fd_table[fd]->w_queue.q_next =
+ entry->w_queue.q_next;
+ }
+ fd_table[fd]->w_queue.q_last =
+ entry->w_queue.q_last;
+ }
+ entry->r_queue.q_next = NULL;
+ entry->w_queue.q_next = NULL;
+ entry->r_queue.q_last = NULL;
+ entry->w_queue.q_last = NULL;
+ entry->r_owner = NULL;
+ entry->w_owner = NULL;
+ ret = OK;
+ } else {
+ fd_basic_basic_unlock(entry, FD_RDWR);
+ pthread_mutex_unlock(&entry->mutex);
+ /* Note: entry->mutex = mutex */
+ }
+ fd_basic_dup(fd, newfd);
+ }
+ fd_unlock(fd, FD_RDWR);
+ }
+ }
+ } else {
+ ret = NOTOK;
+ }
+ return(ret);
+
+}
+
+/* ==========================================================================
+ * dup()
+ */
+int dup(int fd)
+{
+ int ret;
+
+ if ((ret = fd_lock(fd, FD_RDWR, NULL)) == OK) {
+ ret = fd_allocate();
+ fd_basic_dup(fd, ret);
+ fd_unlock(fd, FD_RDWR);
+ }
+ return(ret);
+}
+
+/* ==========================================================================
+ * fcntl()
+ */
+int fcntl(int fd, int cmd, ...)
+{
+ int ret, realfd, flags;
+ struct flock *flock;
+ semaphore *plock;
+ va_list ap;
+
+ flags = 0;
+ if ((ret = fd_lock(fd, FD_RDWR, NULL)) == OK) {
+ va_start(ap, cmd);
+ switch(cmd) {
+ case F_DUPFD:
+ ret = fd_allocate();
+ fd_basic_dup(va_arg(ap, int), ret);
+ break;
+ case F_SETFD:
+ break;
+ case F_GETFD:
+ break;
+ case F_GETFL:
+ ret = fd_table[fd]->flags;
+ break;
+ case F_SETFL:
+ flags = va_arg(ap, int);
+ if ((ret = fd_table[fd]->ops->fcntl(fd_table[fd]->fd,
+ fd_table[fd]->flags, cmd, flags | __FD_NONBLOCK)) == OK) {
+ fd_table[fd]->flags = flags;
+ }
+ break;
+/* case F_SETLKW: */
+ /*
+ * Do the same as SETLK but if it fails with EACCES or EAGAIN
+ * block the thread and try again later, not implemented yet
+ */
+/* case F_SETLK: */
+/* case F_GETLK:
+ flock = va_arg(ap, struct flock*);
+ ret = fd_table[fd]->ops->fcntl(fd_table[fd]->fd,
+ fd_table[fd]->flags, cmd, flock);
+ break; */
+ default:
+ /* Might want to make va_arg use a union */
+ ret = fd_table[fd]->ops->fcntl(fd_table[fd]->fd,
+ fd_table[fd]->flags, cmd, va_arg(ap, void*));
+ break;
+ }
+ va_end(ap);
+ fd_unlock(fd, FD_RDWR);
+ }
+ return(ret);
+}
+
+/* ==========================================================================
+ * getdtablesize()
+ */
+int getdtablesize()
+{
+ return dtablesize;
+}
+
+/* ==========================================================================
+ * ioctl()
+ *
+ * Really want to do a real implementation of this that parses the args ala
+ * fcntl(), above, but it will have to be a totally platform-specific,
+ * nightmare-on-elm-st-style sort of thing. Might even deserve its own file
+ * ala select()... --SNL
+ */
+#ifndef ioctl_request_type
+#define ioctl_request_type unsigned long /* Dummy patch by Monty */
+#endif
+
+int
+ioctl(int fd, ioctl_request_type request, ...)
+{
+ int ret;
+ pthread_va_list ap;
+ caddr_t arg;
+
+ va_start( ap, request ); /* Get the arg */
+ arg = va_arg(ap,caddr_t);
+ va_end( ap );
+
+ if (fd < 0 || fd >= dtablesize)
+ ret = NOTOK;
+ else if (fd_table[fd]->fd.i == NOTOK)
+ ret = machdep_sys_ioctl(fd, request, arg);
+ else if ((ret = fd_lock(fd, FD_RDWR, NULL)) == OK) {
+ ret = machdep_sys_ioctl(fd_table[fd]->fd.i, request, arg);
+ if( ret == 0 && request == FIONBIO ) {
+ /* Properly set NONBLOCK flag */
+ int v = *(int *)arg;
+ if( v )
+ fd_table[fd]->flags |= __FD_NONBLOCK;
+ else
+ fd_table[fd]->flags &= ~__FD_NONBLOCK;
+ }
+ fd_unlock(fd, FD_RDWR);
+ }
+ return ret;
+}
+
diff --git a/mit-pthreads/pthreads/fd_kern.c b/mit-pthreads/pthreads/fd_kern.c
new file mode 100644
index 00000000000..f4ada4e4fd4
--- /dev/null
+++ b/mit-pthreads/pthreads/fd_kern.c
@@ -0,0 +1,1950 @@
+/* ==== fd_kern.c ============================================================
+ * Copyright (c) 1993, 1994 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Description : Deals with the valid kernel fds.
+ *
+ * 1.00 93/09/27 proven
+ * -Started coding this file.
+ *
+ * 1.01 93/11/13 proven
+ * -The functions readv() and writev() added.
+ */
+
+#ifndef lint
+static const char rcsid[] = "$Id$";
+#endif
+
+#include "config.h"
+#include <pthread.h>
+#include <unistd.h>
+#include <sys/compat.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/uio.h>
+#include <stdarg.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <pthread/posix.h>
+#include <string.h>
+
+#if defined (HAVE_SYSCALL_SENDTO) && !defined (HAVE_SYSCALL_SEND)
+
+pthread_ssize_t machdep_sys_send (int fd, const void *msg, size_t len,
+ int flags)
+{
+ return machdep_sys_sendto (fd, msg, len, flags,
+ (const struct sockaddr *) 0, 0);
+}
+
+#endif
+
+#if defined (HAVE_SYSCALL_RECVFROM) && !defined (HAVE_SYSCALL_RECV)
+
+pthread_ssize_t machdep_sys_recv (int fd, void *buf, size_t len, int flags)
+{
+ return machdep_sys_recvfrom (fd, buf, len, flags,
+ (struct sockaddr *) 0, (int *) 0);
+}
+
+#endif
+
+/* ==========================================================================
+ * Check if there is any signal with must be handled. Added by Monty
+ * This could be somewhat system dependent but it should work.
+ */
+
+static int fd_check_if_pending_signal(struct pthread *pthread)
+{
+ int i;
+ unsigned long *pending,*mask;
+ if (!pthread->sigcount)
+ return 0;
+ pending= (unsigned long*) &pthread->sigpending;
+ mask= (unsigned long*) &pthread->sigmask;
+
+ for (i=0 ; i < sizeof(pthread->sigpending)/sizeof(unsigned long); i++)
+ {
+ if (*pending && (*mask ^ (unsigned) ~0L))
+ return 1;
+ pending++;
+ mask++;
+ }
+ return 0;
+}
+
+/* ==========================================================================
+ * Variables used by both fd_kern_poll and fd_kern_wait
+ */
+struct pthread_queue fd_wait_read = PTHREAD_QUEUE_INITIALIZER;
+struct pthread_queue fd_wait_write = PTHREAD_QUEUE_INITIALIZER;
+struct pthread_queue fd_wait_select = PTHREAD_QUEUE_INITIALIZER;
+
+static struct timeval __fd_kern_poll_timeout = { 0, 0 }; /* Moved by monty */
+extern struct timeval __fd_kern_wait_timeout;
+extern volatile sig_atomic_t sig_to_process;
+
+/*
+ * ==========================================================================
+ * Do a select if there is someting to wait for.
+ * This is to a combination of the old fd_kern_poll() and fd_kern_wait()
+ * Return 1 if nothing to do.
+ */
+
+static int fd_kern_select(struct timeval *timeout)
+{
+ fd_set fd_set_read, fd_set_write, fd_set_except;
+ struct pthread *pthread, *deq;
+ int count, i;
+
+ if (!fd_wait_read.q_next && !fd_wait_write.q_next && !fd_wait_select.q_next)
+ return 1; /* Nothing to do */
+
+ FD_ZERO(&fd_set_read);
+ FD_ZERO(&fd_set_write);
+ FD_ZERO(&fd_set_except);
+ for (pthread = fd_wait_read.q_next; pthread; pthread = pthread->next)
+ FD_SET(pthread->data.fd.fd, &fd_set_read);
+ for (pthread = fd_wait_write.q_next; pthread; pthread = pthread->next)
+ FD_SET(pthread->data.fd.fd, &fd_set_write);
+ for (pthread = fd_wait_select.q_next; pthread; pthread = pthread->next)
+ {
+ for (i = 0; i < pthread->data.select_data->nfds; i++) {
+ if (FD_ISSET(i, &pthread->data.select_data->exceptfds))
+ FD_SET(i, &fd_set_except);
+ if (FD_ISSET(i, &pthread->data.select_data->writefds))
+ FD_SET(i, &fd_set_write);
+ if (FD_ISSET(i, &pthread->data.select_data->readfds))
+ FD_SET(i, &fd_set_read);
+ }
+ }
+
+ /* Turn off interrupts for real while we set the timer. */
+
+ if (timeout == &__fd_kern_wait_timeout)
+ { /* from fd_kern_wait() */
+ sigset_t sig_to_block, oset;
+ sigfillset(&sig_to_block);
+ machdep_sys_sigprocmask(SIG_BLOCK, &sig_to_block, &oset);
+
+ machdep_unset_thread_timer(NULL);
+ __fd_kern_wait_timeout.tv_usec = 0;
+ __fd_kern_wait_timeout.tv_sec = (sig_to_process) ? 0 : 3600;
+
+ machdep_sys_sigprocmask(SIG_UNBLOCK, &sig_to_block, &oset);
+ }
+ /*
+ * There is a small but finite chance that an interrupt will
+ * occure between the unblock and the select. Because of this
+ * sig_handler_real() sets the value of __fd_kern_wait_timeout
+ * to zero causing the select to do a poll instead of a wait.
+ */
+
+ while ((count = machdep_sys_select(dtablesize, &fd_set_read,
+ &fd_set_write, &fd_set_except,
+ timeout)) < OK)
+ {
+ if (count == -EINTR)
+ return 0;
+ PANIC();
+ }
+
+ for (pthread = fd_wait_read.q_next; pthread; ) {
+ if (count && FD_ISSET(pthread->data.fd.fd, &fd_set_read) ||
+ fd_check_if_pending_signal(pthread))
+ {
+ if (FD_ISSET(pthread->data.fd.fd, &fd_set_read))
+ count--;
+ deq = pthread;
+ pthread = pthread->next;
+ pthread_queue_remove(&fd_wait_read, deq);
+ if (SET_PF_DONE_EVENT(deq) == OK) {
+ pthread_prio_queue_enq(pthread_current_prio_queue, deq);
+ deq->state = PS_RUNNING;
+ }
+ continue;
+ }
+ pthread = pthread->next;
+ }
+
+ for (pthread = fd_wait_write.q_next; pthread; ) {
+ if (count && FD_ISSET(pthread->data.fd.fd, &fd_set_write) ||
+ fd_check_if_pending_signal(pthread))
+ {
+ if (FD_ISSET(pthread->data.fd.fd, &fd_set_read))
+ count--;
+ deq = pthread;
+ pthread = pthread->next;
+ pthread_queue_remove(&fd_wait_write, deq);
+ if (SET_PF_DONE_EVENT(deq) == OK) {
+ pthread_prio_queue_enq(pthread_current_prio_queue, deq);
+ deq->state = PS_RUNNING;
+ }
+ continue;
+ }
+ pthread = pthread->next;
+ }
+
+ for (pthread = fd_wait_select.q_next; pthread; )
+ {
+ int found_one=0; /* Loop fixed by monty */
+ if (count)
+ {
+ fd_set tmp_readfds, tmp_writefds, tmp_exceptfds;
+ memcpy(&tmp_readfds, &pthread->data.select_data->readfds,
+ sizeof(fd_set));
+ memcpy(&tmp_writefds, &pthread->data.select_data->writefds,
+ sizeof(fd_set));
+ memcpy(&tmp_exceptfds, &pthread->data.select_data->exceptfds,
+ sizeof(fd_set));
+
+ for (i = 0; i < pthread->data.select_data->nfds; i++) {
+ if (FD_ISSET(i, &tmp_exceptfds))
+ {
+ if (! FD_ISSET(i, &fd_set_except))
+ FD_CLR(i, &tmp_exceptfds);
+ else
+ found_one=1;
+ }
+ if (FD_ISSET(i, &tmp_writefds))
+ {
+ if (! FD_ISSET(i, &fd_set_write))
+ FD_CLR(i, &tmp_writefds);
+ else
+ found_one=1;
+ }
+ if (FD_ISSET(i, &tmp_readfds))
+ {
+ if (! FD_ISSET(i, &fd_set_read))
+ FD_CLR(i, &tmp_readfds);
+ else
+ found_one=1;
+ }
+ }
+ if (found_one)
+ {
+ memcpy(&pthread->data.select_data->readfds, &tmp_readfds,
+ sizeof(fd_set));
+ memcpy(&pthread->data.select_data->writefds, &tmp_writefds,
+ sizeof(fd_set));
+ memcpy(&pthread->data.select_data->exceptfds, &tmp_exceptfds,
+ sizeof(fd_set));
+ }
+ }
+ if (found_one || fd_check_if_pending_signal(pthread))
+ {
+ deq = pthread;
+ pthread = pthread->next;
+ pthread_queue_remove(&fd_wait_select, deq);
+ if (SET_PF_DONE_EVENT(deq) == OK) {
+ pthread_prio_queue_enq(pthread_current_prio_queue, deq);
+ deq->state = PS_RUNNING;
+ }
+ } else {
+ pthread = pthread->next;
+ }
+ }
+ return 0;
+}
+
+
+/* ==========================================================================
+ * fd_kern_poll()
+ *
+ * Called only from context_switch(). The kernel must be locked.
+ *
+ * This function uses a linked list of waiting pthreads, NOT a queue.
+ */
+
+void fd_kern_poll()
+{
+ fd_kern_select(&__fd_kern_poll_timeout);
+}
+
+
+/* ==========================================================================
+ * fd_kern_wait()
+ *
+ * Called when there is no active thread to run.
+ */
+
+void fd_kern_wait()
+{
+ if (fd_kern_select(&__fd_kern_wait_timeout))
+ /* No threads, waiting on I/O, do a sigsuspend */
+ sig_handler_pause();
+}
+
+
+/* ==========================================================================
+ * Special Note: All operations return the errno as a negative of the errno
+ * listed in errno.h
+ * ======================================================================= */
+
+/* ==========================================================================
+ * read()
+ */
+pthread_ssize_t __fd_kern_read(union fd_data fd_data, int flags, void *buf,
+ size_t nbytes, struct timespec * timeout)
+{
+ int fd = fd_data.i;
+ int ret;
+
+ pthread_run->sighandled=0; /* Added by monty */
+ while ((ret = machdep_sys_read(fd, buf, nbytes)) < OK) {
+ if (!(flags & __FD_NONBLOCK) &&
+ ((ret == -EWOULDBLOCK) || (ret == -EAGAIN))) {
+ pthread_sched_prevent();
+
+ /* queue pthread for a FDR_WAIT */
+ SET_PF_WAIT_EVENT(pthread_run);
+ pthread_run->data.fd.fd = fd;
+ pthread_queue_enq(&fd_wait_read, pthread_run);
+
+ if (timeout) {
+ /* get current time */
+ struct timespec current_time;
+ machdep_gettimeofday(&current_time);
+ sleep_schedule(&current_time, timeout);
+
+ SET_PF_AT_CANCEL_POINT(pthread_run);
+ pthread_resched_resume(PS_FDR_WAIT);
+ CLEAR_PF_AT_CANCEL_POINT(pthread_run);
+
+ /* We're awake */
+ pthread_sched_prevent();
+ if (sleep_cancel(pthread_run) == NOTOK) {
+ CLEAR_PF_DONE_EVENT(pthread_run);
+ pthread_sched_resume();
+ SET_ERRNO(ETIMEDOUT);
+ ret= NOTOK;
+ break;
+ }
+ pthread_sched_resume();
+ } else {
+ SET_PF_AT_CANCEL_POINT(pthread_run);
+ pthread_resched_resume(PS_FDR_WAIT);
+ CLEAR_PF_AT_CANCEL_POINT(pthread_run);
+ }
+ CLEAR_PF_DONE_EVENT(pthread_run);
+ if (pthread_run->sighandled) /* Added by monty */
+ { /* We where aborted */
+ SET_ERRNO(EINTR);
+ ret= NOTOK;
+ break;
+ }
+ } else {
+ SET_ERRNO(-ret);
+ ret = NOTOK;
+ break;
+ }
+ }
+ return(ret);
+}
+
+/* ==========================================================================
+ * readv()
+ */
+int __fd_kern_readv(union fd_data fd_data, int flags, const struct iovec *iov,
+ int iovcnt, struct timespec * timeout)
+{
+ int fd = fd_data.i;
+ int ret;
+
+ pthread_run->sighandled=0; /* Added by monty */
+ while ((ret = machdep_sys_readv(fd, iov, iovcnt)) < OK) {
+ if (!(flags & __FD_NONBLOCK) &&
+ ((ret == -EWOULDBLOCK) || (ret == -EAGAIN))) {
+ pthread_sched_prevent();
+
+ /* queue pthread for a FDR_WAIT */
+ pthread_run->data.fd.fd = fd;
+ SET_PF_WAIT_EVENT(pthread_run);
+ pthread_queue_enq(&fd_wait_read, pthread_run);
+
+ if (timeout) {
+ /* get current time */
+ struct timespec current_time;
+ machdep_gettimeofday(&current_time);
+ sleep_schedule(&current_time, timeout);
+
+ SET_PF_AT_CANCEL_POINT(pthread_run);
+ pthread_resched_resume(PS_FDW_WAIT);
+ CLEAR_PF_AT_CANCEL_POINT(pthread_run);
+
+ /* We're awake */
+ pthread_sched_prevent();
+ if (sleep_cancel(pthread_run) == NOTOK) {
+ CLEAR_PF_DONE_EVENT(pthread_run);
+ pthread_sched_resume();
+ SET_ERRNO(ETIMEDOUT);
+ ret = NOTOK;
+ break;
+ }
+ pthread_sched_resume();
+ } else {
+ SET_PF_AT_CANCEL_POINT(pthread_run);
+ pthread_resched_resume(PS_FDW_WAIT);
+ CLEAR_PF_AT_CANCEL_POINT(pthread_run);
+ }
+ CLEAR_PF_DONE_EVENT(pthread_run);
+ if (pthread_run->sighandled) /* Added by monty */
+ { /* We where aborted */
+ SET_ERRNO(EINTR);
+ ret= NOTOK;
+ break;
+ }
+ } else {
+ SET_ERRNO(-ret);
+ ret = NOTOK;
+ break;
+ }
+ }
+ return(ret);
+}
+
+/* ==========================================================================
+ * write()
+ */
+pthread_ssize_t __fd_kern_write(union fd_data fd_data, int flags,
+ const void *buf, size_t nbytes, struct timespec * timeout)
+{
+ int fd = fd_data.i;
+ int ret;
+
+ pthread_run->sighandled=0; /* Added by monty */
+ while ((ret = machdep_sys_write(fd, buf, nbytes)) < OK) {
+ if (!(flags & __FD_NONBLOCK) &&
+ ((ret == -EWOULDBLOCK) || (ret == -EAGAIN))) {
+ pthread_sched_prevent();
+
+ /* queue pthread for a FDW_WAIT */
+ pthread_run->data.fd.fd = fd;
+ SET_PF_WAIT_EVENT(pthread_run);
+ pthread_queue_enq(&fd_wait_write, pthread_run);
+
+ if (timeout) {
+ /* get current time */
+ struct timespec current_time;
+ machdep_gettimeofday(&current_time);
+ sleep_schedule(&current_time, timeout);
+
+ pthread_resched_resume(PS_FDW_WAIT);
+
+ /* We're awake */
+ pthread_sched_prevent();
+ if (sleep_cancel(pthread_run) == NOTOK) {
+ CLEAR_PF_DONE_EVENT(pthread_run);
+ pthread_sched_resume();
+ SET_ERRNO(ETIMEDOUT);
+ ret = NOTOK;
+ break;
+ }
+ pthread_sched_resume();
+ } else {
+ pthread_resched_resume(PS_FDW_WAIT);
+ }
+ CLEAR_PF_DONE_EVENT(pthread_run);
+ if (pthread_run->sighandled) /* Added by monty */
+ { /* We where aborted */
+ SET_ERRNO(EINTR);
+ ret= NOTOK;
+ break;
+ }
+ } else {
+ SET_ERRNO(-ret);
+ ret = NOTOK;
+ break;
+ }
+ }
+ return(ret);
+}
+
+/* ==========================================================================
+ * writev()
+ */
+int __fd_kern_writev(union fd_data fd_data, int flags, const struct iovec *iov,
+ int iovcnt, struct timespec * timeout)
+{
+ int fd = fd_data.i;
+ int ret;
+
+ pthread_run->sighandled=0; /* Added by monty */
+ while ((ret = machdep_sys_writev(fd, iov, iovcnt)) < OK) {
+ if (!(flags & __FD_NONBLOCK) &&
+ ((ret == -EWOULDBLOCK) || (ret == -EAGAIN))) {
+ pthread_sched_prevent();
+
+ /* queue pthread for a FDW_WAIT */
+ pthread_run->data.fd.fd = fd;
+ SET_PF_WAIT_EVENT(pthread_run);
+ pthread_queue_enq(&fd_wait_write, pthread_run);
+
+ if (timeout) {
+ /* get current time */
+ struct timespec current_time;
+ machdep_gettimeofday(&current_time);
+ sleep_schedule(&current_time, timeout);
+
+ pthread_resched_resume(PS_FDW_WAIT);
+
+ /* We're awake */
+ pthread_sched_prevent();
+ if (sleep_cancel(pthread_run) == NOTOK) {
+ CLEAR_PF_DONE_EVENT(pthread_run);
+ pthread_sched_resume();
+ SET_ERRNO(ETIMEDOUT);
+ ret = NOTOK;
+ break;
+ }
+ pthread_sched_resume();
+ } else {
+ pthread_resched_resume(PS_FDW_WAIT);
+ }
+ CLEAR_PF_DONE_EVENT(pthread_run);
+ if (pthread_run->sighandled) /* Added by monty */
+ { /* We where aborted */
+ SET_ERRNO(EINTR);
+ ret= NOTOK;
+ break;
+ }
+ } else {
+ break;
+ }
+ }
+ return(ret);
+}
+
+/* ==========================================================================
+ * For blocking version we really should set an interrupt
+ * fcntl()
+ */
+int __fd_kern_fcntl(union fd_data fd_data, int flags, int cmd, int arg)
+{
+ int fd = fd_data.i;
+
+ return(machdep_sys_fcntl(fd, cmd, arg));
+}
+
+/* ==========================================================================
+ * close()
+ */
+int __fd_kern_close(union fd_data fd_data, int flags)
+{
+ int fd = fd_data.i;
+
+ return(machdep_sys_close(fd));
+}
+
+/* ==========================================================================
+ * lseek()
+ * Assume that error number is in the range 0- 255 to get bigger
+ * range of seek. ; Monty
+ */
+off_t __fd_kern_lseek(union fd_data fd_data, int f, off_t offset, int whence)
+{
+ int fd = fd_data.i;
+ extern off_t machdep_sys_lseek(int, off_t, int);
+ off_t ret=machdep_sys_lseek(fd, offset, whence);
+ if ((long) ret < 0L && (long) ret >= -255L)
+ {
+ SET_ERRNO(ret);
+ ret= NOTOK;
+ }
+ return ret;
+}
+
+/*
+ * File descriptor operations
+ */
+extern machdep_sys_close();
+
+/* Normal file operations */
+static struct fd_ops __fd_kern_ops = {
+ __fd_kern_write, __fd_kern_read, __fd_kern_close, __fd_kern_fcntl,
+ __fd_kern_writev, __fd_kern_readv, __fd_kern_lseek, 1
+};
+
+/* NFS file opperations */
+
+/* FIFO file opperations */
+
+/* Device operations */
+
+/* ==========================================================================
+ * open()
+ *
+ * Because open could potentially block opening a file from a remote
+ * system, we want to make sure the call will timeout. We then try and open
+ * the file, and stat the file to determine what operations we should
+ * associate with the fd.
+ *
+ * This is not done yet
+ *
+ * A regular file on the local system needs no special treatment.
+ */
+int open(const char *path, int flags, ...)
+{
+ int fd, mode, fd_kern;
+ struct stat stat_buf;
+ va_list ap;
+
+ /* If pthread scheduling == FIFO set a virtual timer */
+ if (flags & O_CREAT) {
+ va_start(ap, flags);
+ mode = va_arg(ap, int);
+ va_end(ap);
+ } else {
+ mode = 0;
+ }
+
+ if (!((fd = fd_allocate()) < OK)) {
+ fd_table[fd]->flags = flags;
+ flags |= __FD_NONBLOCK;
+
+ if (!((fd_kern = machdep_sys_open(path, flags, mode)) < OK)) {
+
+ /* fstat the file to determine what type it is */
+ if (machdep_sys_fstat(fd_kern, &stat_buf)) {
+ PANIC();
+ }
+ if (S_ISREG(stat_buf.st_mode)) {
+ fd_table[fd]->ops = &(__fd_kern_ops);
+ fd_table[fd]->type = FD_HALF_DUPLEX;
+ } else {
+ fd_table[fd]->ops = &(__fd_kern_ops);
+ fd_table[fd]->type = FD_FULL_DUPLEX;
+ }
+ fd_table[fd]->fd.i = fd_kern;
+ return(fd);
+ }
+
+ fd_table[fd]->count = 0;
+ SET_ERRNO(-fd_kern);
+ }
+ return(NOTOK);
+}
+
+/* ==========================================================================
+ * create()
+ */
+int create(const char *path, mode_t mode)
+{
+ return creat (path, mode);
+}
+
+/* ==========================================================================
+ * creat()
+ */
+#undef creat
+
+int creat(const char *path, mode_t mode)
+{
+ return open (path, O_CREAT | O_TRUNC | O_WRONLY, mode);
+}
+
+/* ==========================================================================
+ * fchown()
+ */
+int fchown(int fd, uid_t owner, gid_t group)
+{
+ int ret;
+
+ if ((ret = fd_lock(fd, FD_WRITE, NULL)) == OK) {
+ if ((ret = machdep_sys_fchown(fd_table[fd]->fd.i, owner, group)) < OK) {
+ SET_ERRNO(-ret);
+ ret = NOTOK;
+ }
+ fd_unlock(fd, FD_WRITE);
+ }
+ return(ret);
+}
+
+/* ==========================================================================
+ * fchmod()
+ */
+int fchmod(int fd, mode_t mode)
+{
+ int ret;
+
+ if ((ret = fd_lock(fd, FD_WRITE, NULL)) == OK) {
+ if ((ret = machdep_sys_fchmod(fd_table[fd]->fd.i, mode)) < OK) {
+ SET_ERRNO(-ret);
+ ret = NOTOK;
+ }
+ fd_unlock(fd, FD_WRITE);
+ }
+ return(ret);
+}
+
+/* ==========================================================================
+ * ftruncate()
+ */
+int ftruncate(int fd, off_t length)
+{
+ int ret;
+
+ if ((ret = fd_lock(fd, FD_WRITE, NULL)) == OK) {
+ if ((ret = machdep_sys_ftruncate(fd_table[fd]->fd.i, length)) < OK) {
+ SET_ERRNO(-ret);
+ ret = NOTOK;
+ }
+ fd_unlock(fd, FD_WRITE);
+ }
+ return(ret);
+}
+
+#if defined (HAVE_SYSCALL_FLOCK)
+/* ==========================================================================
+ * flock()
+ *
+ * Added (mevans)
+ */
+int flock(int fd, int operation)
+{
+ int ret;
+
+ if ((ret = fd_lock(fd, FD_RDWR, NULL)) == OK) {
+ if ((ret = machdep_sys_flock(fd_table[fd]->fd.i,
+ operation)) < OK) {
+ SET_ERRNO(-ret);
+ ret = NOTOK;
+ }
+ fd_unlock(fd, FD_RDWR);
+ }
+ return(ret);
+}
+#endif
+
+/* ==========================================================================
+ * pipe()
+ */
+int pipe(int fds[2])
+{
+ int kfds[2];
+ int ret;
+
+ if ((fds[0] = fd_allocate()) >= OK) {
+ if ((fds[1] = fd_allocate()) >= OK) {
+ if ((ret = machdep_sys_pipe(kfds)) >= OK) {
+ fd_table[fds[0]]->flags = machdep_sys_fcntl(kfds[0], F_GETFL, NULL);
+ machdep_sys_fcntl(kfds[0], F_SETFL, fd_table[fds[0]]->flags | __FD_NONBLOCK);
+ fd_table[fds[1]]->flags = machdep_sys_fcntl(kfds[1], F_GETFL, NULL);
+ machdep_sys_fcntl(kfds[1], F_SETFL, fd_table[fds[1]]->flags | __FD_NONBLOCK);
+
+ fd_table[fds[0]]->ops = &(__fd_kern_ops);
+ fd_table[fds[1]]->ops = &(__fd_kern_ops);
+
+ /* Not really full duplex but ... */
+ fd_table[fds[0]]->type = FD_FULL_DUPLEX;
+ fd_table[fds[1]]->type = FD_FULL_DUPLEX;
+
+ fd_table[fds[0]]->fd.i = kfds[0];
+ fd_table[fds[1]]->fd.i = kfds[1];
+
+ return(OK);
+ } else {
+ SET_ERRNO(-ret);
+ }
+ fd_table[fds[1]]->count = 0;
+ }
+ fd_table[fds[0]]->count = 0;
+ }
+ return(NOTOK);
+}
+
+/* ==========================================================================
+ * fd_kern_reset()
+ * Change the fcntl blocking flag back to NONBLOCKING. This should only
+ * be called after a fork.
+ */
+void fd_kern_reset(int fd)
+{
+ switch (fd_table[fd]->type) {
+ case FD_TEST_HALF_DUPLEX:
+ machdep_sys_fcntl(fd_table[fd]->fd.i, F_SETFL,
+ fd_table[fd]->flags | __FD_NONBLOCK);
+ fd_table[fd]->type = FD_HALF_DUPLEX;
+ break;
+ case FD_TEST_FULL_DUPLEX:
+ machdep_sys_fcntl(fd_table[fd]->fd.i, F_SETFL,
+ fd_table[fd]->flags | __FD_NONBLOCK);
+ fd_table[fd]->type = FD_FULL_DUPLEX;
+ break;
+ default:
+ break;
+ }
+}
+
+/* ==========================================================================
+ * fd_kern_init()
+ *
+ * Assume the entry is locked before routine is invoked
+ *
+ * This may change. The problem is setting the fd to nonblocking changes
+ * the parents fd too, which may not be the desired result.
+ *
+ * New added feature: If the fd in question is a tty then we open it again
+ * and close the original, this way we don't have to worry about the
+ * fd being NONBLOCKING to the outside world.
+ */
+void fd_kern_init(int fd)
+{
+ if ((fd_table[fd]->flags = machdep_sys_fcntl(fd, F_GETFL, NULL)) >= OK) {
+ if (isatty_basic(fd)) {
+ int new_fd;
+
+ if ((new_fd = machdep_sys_open(__ttyname_basic(fd), O_RDWR)) >= OK){
+ if (machdep_sys_dup2(new_fd, fd) == OK) {
+ /* Should print a warning */
+
+ /* Should also set the flags to that of opened outside of
+ process */
+ }
+ machdep_sys_close(new_fd);
+ }
+ }
+ /* We do these things regaurdless of the above results */
+ machdep_sys_fcntl(fd, F_SETFL, fd_table[fd]->flags | __FD_NONBLOCK);
+ fd_table[fd]->ops = &(__fd_kern_ops);
+ fd_table[fd]->type = FD_HALF_DUPLEX;
+ fd_table[fd]->fd.i = fd;
+ fd_table[fd]->count = 1;
+
+ }
+}
+
+/* ==========================================================================
+ * fd_kern_gettableentry()
+ *
+ * Remember only return a a file descriptor that I will modify later.
+ * Don't return file descriptors that aren't owned by the child, or don't
+ * have kernel operations.
+ */
+static int fd_kern_gettableentry(const int child, int fd)
+{
+ int i;
+
+ for (i = 0; i < dtablesize; i++) {
+ if (fd_table[i]) {
+ if (fd_table[i]->fd.i == fd) {
+ if (child) {
+ if ((fd_table[i]->type != FD_TEST_HALF_DUPLEX) &&
+ (fd_table[i]->type != FD_TEST_FULL_DUPLEX)) {
+ continue;
+ }
+ } else {
+ if ((fd_table[i]->type == FD_NT) ||
+ (fd_table[i]->type == FD_NIU)) {
+ continue;
+ }
+ }
+ /* Is it a kernel fd ? */
+ if ((!fd_table[i]->ops) ||
+ (fd_table[i]->ops->use_kfds != 1)) {
+ continue;
+ }
+ return(i);
+ }
+ }
+ }
+ return(NOTOK);
+}
+
+/* ==========================================================================
+ * fd_kern_exec()
+ *
+ * Fixup the fd_table such that (fd == fd_table[fd]->fd.i) this way
+ * the new immage will be OK.
+ *
+ * Only touch those that won't be used by the parent if we're in a child
+ * otherwise fixup all.
+ *
+ * Returns:
+ * 0 no fixup necessary
+ * 1 fixup without problems
+ * 2 failed fixup on some descriptors, and clobbered them.
+ */
+int fd_kern_exec(const int child)
+{
+ int ret = 0;
+ int fd, i;
+
+ for (fd = 0; fd < dtablesize; fd++) {
+ if (fd_table[fd] == NULL) {
+ continue;
+ }
+ /* Is the fd already in use ? */
+ if (child) {
+ if ((fd_table[fd]->type != FD_TEST_HALF_DUPLEX) &&
+ (fd_table[fd]->type != FD_TEST_FULL_DUPLEX)) {
+ continue;
+ }
+ } else {
+ if ((fd_table[fd]->type == FD_NT) ||
+ (fd_table[fd]->type == FD_NIU)) {
+ continue;
+ }
+ }
+ /* Is it a kernel fd ? */
+ if ((!fd_table[fd]->ops) ||
+ (fd_table[fd]->ops->use_kfds != 1)) {
+ continue;
+ }
+ /* Does it match ? */
+ if (fd_table[fd]->fd.i == fd) {
+ continue;
+ }
+ /* OK, fixup entry: Read comments before changing. This isn't obvious */
+
+ /* i is the real file descriptor fd currently represents */
+ if (((i = fd_table[fd]->fd.i) >= dtablesize) || (i < 0)) {
+ /* This should never happen */
+ PANIC();
+ }
+
+ /*
+ * if the real file descriptor with the same number as the fake file
+ * descriptor number fd is actually in use by the program, we have
+ * to move it out of the way
+ */
+ if ((machdep_sys_fcntl(fd, F_GETFL, NULL)) >= OK) {
+ /* fd is busy */
+ int j;
+
+ /*
+ * j is the fake file descriptor that represents the real file
+ * descriptor that we want to move. This way the fake file
+ * descriptor fd can move its real file descriptor i such that
+ * fd == i.
+ */
+ if ((j = fd_kern_gettableentry(child, fd)) >= OK) {
+
+ /*
+ * Since j represents a fake file descriptor and fd represents
+ * a fake file descriptor. If j < fd then a previous pass
+ * should have set fd_table[j]->fd.i == j.
+ */
+ if (fd < j) {
+ if ((fd_table[j]->fd.i = machdep_sys_dup(fd)) < OK) {
+ /* Close j, there is nothing else we can do */
+ fd_table[j]->type = FD_NIU;
+ ret = 2;
+ }
+ } else {
+ /* This implies fd_table[j]->fd.i != j */
+ PANIC();
+ }
+ }
+ }
+
+ /*
+ * Here the real file descriptor i is set to equel the fake file
+ * descriptor fd
+ */
+ machdep_sys_dup2(i, fd);
+
+ /*
+ * Now comes the really complicated part: UNDERSTAND before changing
+ *
+ * Here are the things this routine wants to do ...
+ *
+ * Case 1. The real file descriptor has only one fake file descriptor
+ * representing it.
+ * fd -> i, fd != i ===> fd -> fd, close(i)
+ * Example fd = 4, i = 2: then close(2), set fd -> i = 4
+ *
+ * Case 2. The real file descriptor has more than one fake file
+ * descriptor representing it, and this is the first fake file
+ * descriptor representing the real file descriptor
+ * fd -> i, fd' -> i, fd != i ===> fd -> fd, fd' -> fd, close(i)
+ *
+ * The problem is achiving the above is very messy and difficult,
+ * but I should be able to take a short cut. If fd > i then there
+ * will be no need to ever move i, this is because the fake file
+ * descriptor foo that we would have wanted to represent the real
+ * file descriptor i has already been processed. If fd < i then by
+ * moving i to fd all subsequent fake file descriptors fd' should fall
+ * into the previous case and won't need aditional adjusting.
+ *
+ * Does this break the above fd < j check .... It shouldn't because j
+ * is a fake file descriptor and if j < fd then j has already moved
+ * its real file descriptor foo such that foo <= j therefore foo < fd
+ * and not foo == fd therefor j cannot represent the real
+ * filedescriptor that fd want to move to and be less than fd
+ */
+ if (fd < i) {
+ fd_table[fd]->fd.i = fd;
+ machdep_sys_close(i);
+ }
+ if (ret < 1) {
+ ret = 1;
+ }
+ }
+}
+
+/* ==========================================================================
+ * fd_kern_fork()
+ */
+void fd_kern_fork()
+{
+ pthread_mutex_t *mutex;
+ int fd;
+
+ for (fd = 0; fd < dtablesize; fd++) {
+ if (fd_table[fd] == NULL) {
+ continue;
+ }
+ mutex = & (fd_table[fd]->mutex);
+ if (pthread_mutex_trylock(mutex)) {
+ continue;
+ }
+ if ((fd_table[fd]->r_owner) || (fd_table[fd]->w_owner)) {
+ pthread_mutex_unlock(mutex);
+ continue;
+ }
+ /* Is it a kernel fd ? */
+ if ((!fd_table[fd]->ops) || (fd_table[fd]->ops->use_kfds != 1)) {
+ pthread_mutex_unlock(mutex);
+ continue;
+ }
+ switch (fd_table[fd]->type) {
+ case FD_HALF_DUPLEX:
+ machdep_sys_fcntl(fd_table[fd]->fd.i, F_SETFL, fd_table[fd]->flags);
+ fd_table[fd]->type = FD_TEST_HALF_DUPLEX;
+ break;
+ case FD_FULL_DUPLEX:
+ machdep_sys_fcntl(fd_table[fd]->fd.i, F_SETFL, fd_table[fd]->flags);
+ fd_table[fd]->type = FD_TEST_FULL_DUPLEX;
+ break;
+ default:
+ break;
+ }
+ pthread_mutex_unlock(mutex);
+ }
+}
+
+/* ==========================================================================
+ * Here are the berkeley socket functions. These are not POSIX.
+ * ======================================================================= */
+
+#if defined (HAVE_SYSCALL_SOCKET) || defined (HAVE_SYSCALL_SOCKETCALL)
+
+/* ==========================================================================
+ * socket()
+ */
+int socket(int af, int type, int protocol)
+{
+ int fd, fd_kern;
+
+ if (!((fd = fd_allocate()) < OK)) {
+
+ if (!((fd_kern = machdep_sys_socket(af, type, protocol)) < OK)) {
+ int tmp_flags;
+
+ tmp_flags = machdep_sys_fcntl(fd_kern, F_GETFL, 0);
+ machdep_sys_fcntl(fd_kern, F_SETFL, tmp_flags | __FD_NONBLOCK);
+
+ /* Should fstat the file to determine what type it is */
+ fd_table[fd]->ops = & __fd_kern_ops;
+ fd_table[fd]->type = FD_FULL_DUPLEX;
+ fd_table[fd]->fd.i = fd_kern;
+ fd_table[fd]->flags = tmp_flags;
+ return(fd);
+ }
+
+ fd_table[fd]->count = 0;
+ SET_ERRNO(-fd_kern);
+ }
+ return(NOTOK);
+}
+
+#endif
+
+#if defined (HAVE_SYSCALL_BIND) || defined (HAVE_SYSCALL_SOCKETCALL)
+
+/* ==========================================================================
+ * bind()
+ */
+#ifdef _OS_HAS_SOCKLEN_T
+int bind(int fd, const struct sockaddr *name, socklen_t namelen)
+#else
+int bind(int fd, const struct sockaddr *name, int namelen)
+#endif
+{
+ /* Not much to do in bind */
+ int ret;
+
+ if ((ret = fd_lock(fd, FD_RDWR, NULL)) == OK) {
+ if ((ret = machdep_sys_bind(fd_table[fd]->fd.i, name, namelen)) < OK) {
+ SET_ERRNO(-ret);
+ ret = NOTOK;
+ }
+ fd_unlock(fd, FD_RDWR);
+ }
+ return(ret);
+}
+
+#endif
+
+#if defined (HAVE_SYSCALL_CONNECT) || defined (HAVE_SYSCALL_SOCKETCALL)
+
+/* ==========================================================================
+ * connect()
+ */
+#ifdef _OS_HAS_SOCKLEN_T
+int connect(int fd, const struct sockaddr *name, socklen_t namelen)
+#else
+int connect(int fd, const struct sockaddr *name, int namelen)
+#endif
+{
+ struct sockaddr tmpname;
+ int ret, tmpnamelen;
+
+ if ((ret = fd_lock(fd, FD_RDWR, NULL)) == OK) {
+ if ((ret = machdep_sys_connect(fd_table[fd]->fd.i, name, namelen)) < OK) {
+ if (!(fd_table[fd]->flags & __FD_NONBLOCK) &&
+ ((ret == -EWOULDBLOCK) || (ret == -EINPROGRESS) ||
+ (ret == -EALREADY) || (ret == -EAGAIN))) {
+ pthread_sched_prevent();
+
+ /* queue pthread for a FDW_WAIT */
+ SET_PF_WAIT_EVENT(pthread_run);
+ pthread_run->data.fd.fd = fd_table[fd]->fd.i;
+ pthread_queue_enq(&fd_wait_write, pthread_run);
+
+ pthread_resched_resume(PS_FDW_WAIT);
+ CLEAR_PF_DONE_EVENT(pthread_run);
+
+ tmpnamelen = sizeof(tmpname);
+ /* OK now lets see if it really worked */
+ if (((ret = machdep_sys_getpeername(fd_table[fd]->fd.i,
+ &tmpname, &tmpnamelen)) < OK) &&
+ (ret == -ENOTCONN))
+ {
+ /* Get the error, this function should not fail */
+ machdep_sys_getsockopt(fd_table[fd]->fd.i, SOL_SOCKET,
+ SO_ERROR, &ret, &tmpnamelen);
+ SET_ERRNO(ret); /* ret is already positive (mevans) */
+ ret = NOTOK;
+ }
+ } else {
+ if (ret < 0)
+ {
+ SET_ERRNO(-ret);
+ ret = NOTOK;
+ }
+ }
+ }
+ fd_unlock(fd, FD_RDWR);
+ }
+ return(ret);
+}
+
+#endif
+
+#if defined (HAVE_SYSCALL_ACCEPT) || defined (HAVE_SYSCALL_SOCKETCALL)
+
+/* ==========================================================================
+ * accept()
+ */
+#ifdef _OS_HAS_SOCKLEN_T
+int accept(int fd, struct sockaddr *name, socklen_t *namelen)
+#else
+int accept(int fd, struct sockaddr *name, int *namelen)
+#endif
+{
+ int ret, fd_kern;
+
+ if ((ret = fd_lock(fd, FD_RDWR, NULL)) == OK) {
+ while ((fd_kern = machdep_sys_accept(fd_table[fd]->fd.i, name, namelen)) < OK) {
+ if (!(fd_table[fd]->flags & __FD_NONBLOCK) &&
+ ((fd_kern == -EWOULDBLOCK) || (fd_kern == -EAGAIN))) {
+ pthread_sched_prevent();
+
+ /* queue pthread for a FDR_WAIT */
+ SET_PF_WAIT_EVENT(pthread_run);
+ pthread_run->data.fd.fd = fd_table[fd]->fd.i;
+ pthread_queue_enq(&fd_wait_read, pthread_run);
+
+ pthread_resched_resume(PS_FDR_WAIT);
+ CLEAR_PF_DONE_EVENT(pthread_run);
+ } else {
+ fd_unlock(fd, FD_RDWR);
+ SET_ERRNO(-fd_kern);
+ return(NOTOK);
+ }
+ }
+ fd_unlock(fd, FD_RDWR);
+
+ if (!((ret = fd_allocate()) < OK)) {
+
+ /* This may be unnecessary */
+ machdep_sys_fcntl(fd_kern, F_SETFL, __FD_NONBLOCK);
+
+ /* Should fstat the file to determine what type it is */
+ fd_table[ret]->ops = & __fd_kern_ops;
+ fd_table[ret]->type = FD_FULL_DUPLEX;
+ fd_table[ret]->fd.i = fd_kern;
+
+ /* XXX Flags should be the same as those on the listening fd */
+ fd_table[ret]->flags = fd_table[fd]->flags;
+ }
+ }
+ return(ret);
+}
+
+#endif
+
+#if defined (HAVE_SYSCALL_LISTEN) || defined (HAVE_SYSCALL_SOCKETCALL)
+
+/* ==========================================================================
+ * listen()
+ */
+int listen(int fd, int backlog)
+{
+ int ret;
+
+ if ((ret = fd_lock(fd, FD_RDWR, NULL)) == OK) {
+ if ((ret = machdep_sys_listen(fd_table[fd]->fd.i, backlog)) < OK) {
+ SET_ERRNO(-ret);
+ ret = NOTOK;
+ }
+ fd_unlock(fd, FD_RDWR);
+ }
+ return(ret);
+}
+
+#endif
+
+#if defined (HAVE_SYSCALL_SEND) || defined (HAVE_SYSCALL_SOCKETCALL)
+
+/* ==========================================================================
+ * send_timedwait()
+ */
+ssize_t send_timedwait(int fd, const void * msg, size_t len, int flags,
+ struct timespec * timeout)
+{
+ int ret;
+
+ pthread_run->sighandled=0; /* Added by monty */
+ if ((ret = fd_lock(fd, FD_WRITE, timeout)) == OK) {
+ while ((ret = machdep_sys_send(fd_table[fd]->fd.i,
+ msg, len, flags)) < OK)
+ {
+ if (!(fd_table[fd]->flags & __FD_NONBLOCK) &&
+ ((ret == -EWOULDBLOCK) || (ret == -EAGAIN)))
+ {
+ pthread_sched_prevent();
+
+ /* queue pthread for a FDW_WAIT */
+ SET_PF_WAIT_EVENT(pthread_run);
+ pthread_run->data.fd.fd = fd_table[fd]->fd.i;
+ pthread_queue_enq(&fd_wait_write, pthread_run);
+
+ if (timeout) {
+ /* get current time */
+ struct timespec current_time;
+ machdep_gettimeofday(&current_time);
+ sleep_schedule(&current_time, timeout);
+
+ pthread_resched_resume(PS_FDW_WAIT);
+
+ /* We're awake */
+ pthread_sched_prevent();
+ if (sleep_cancel(pthread_run) == NOTOK) {
+ CLEAR_PF_DONE_EVENT(pthread_run);
+ pthread_sched_resume();
+ ret = -ETIMEDOUT;
+ break;
+ }
+ pthread_sched_resume();
+ } else {
+ pthread_resched_resume(PS_FDW_WAIT);
+ }
+ CLEAR_PF_DONE_EVENT(pthread_run);
+ if (pthread_run->sighandled) /* Added by monty */
+ { /* We where aborted */
+ ret= -EINTR;
+ break;
+ }
+ } else {
+ break;
+ }
+ }
+ fd_unlock(fd, FD_WRITE);
+ }
+ if (ret < 0)
+ {
+ SET_ERRNO(-ret);
+ return(NOTOK);
+ }
+ return ret;
+}
+
+/* ==========================================================================
+ * send()
+ */
+ssize_t send(int fd, const void * msg, size_t len, int flags)
+{
+ return(send_timedwait(fd, msg, len, flags, NULL));
+}
+
+#endif
+
+#if defined (HAVE_SYSCALL_SENDTO) || defined (HAVE_SYSCALL_SOCKETCALL)
+
+/* ==========================================================================
+ * sendto_timedwait()
+ */
+ssize_t sendto_timedwait(int fd, const void * msg, size_t len,
+ int flags, const struct sockaddr *to, int to_len,
+ struct timespec * timeout)
+{
+ int ret;
+
+ pthread_run->sighandled=0; /* Added by monty */
+ if ((ret = fd_lock(fd, FD_WRITE, timeout)) == OK) {
+ while ((ret = machdep_sys_sendto(fd_table[fd]->fd.i,
+ msg, len, flags, to, to_len)) < OK) {
+ if (!(fd_table[fd]->flags & __FD_NONBLOCK) &&
+ ((ret == -EWOULDBLOCK) || (ret == -EAGAIN))) {
+ pthread_sched_prevent();
+
+ /* queue pthread for a FDW_WAIT */
+ SET_PF_WAIT_EVENT(pthread_run);
+ pthread_run->data.fd.fd = fd_table[fd]->fd.i;
+ pthread_queue_enq(&fd_wait_write, pthread_run);
+
+ if (timeout) {
+ /* get current time */
+ struct timespec current_time;
+ machdep_gettimeofday(&current_time);
+ sleep_schedule(&current_time, timeout);
+
+ pthread_resched_resume(PS_FDW_WAIT);
+
+ /* We're awake */
+ pthread_sched_prevent();
+ if (sleep_cancel(pthread_run) == NOTOK) {
+ CLEAR_PF_DONE_EVENT(pthread_run);
+ pthread_sched_resume();
+ ret= -ETIMEDOUT;
+ break;
+ }
+ pthread_sched_resume();
+ } else {
+ pthread_resched_resume(PS_FDW_WAIT);
+ }
+ CLEAR_PF_DONE_EVENT(pthread_run);
+ if (pthread_run->sighandled) /* Added by monty */
+ { /* We where aborted */
+ ret= -EINTR;
+ break;
+ }
+ }
+ else
+ break; /* ret contains the errorcode */
+ }
+ fd_unlock(fd, FD_WRITE);
+ }
+ if (ret < 0)
+ {
+ SET_ERRNO(-ret);
+ return(NOTOK);
+ }
+ return(ret);
+}
+
+/* ==========================================================================
+ * sendto()
+ */
+#ifdef _OS_HAS_SOCKLEN_T
+ssize_t sendto(int fd, const void * msg, size_t len, int flags,
+ const struct sockaddr *to, socklen_t to_len)
+#else
+ssize_t sendto(int fd, const void * msg, size_t len, int flags,
+ const struct sockaddr *to, int to_len)
+#endif
+{
+ return(sendto_timedwait(fd, msg, len, flags, to, to_len, NULL));
+}
+
+#endif
+
+#if defined (HAVE_SYSCALL_SENDMSG) || defined (HAVE_SYSCALL_SOCKETCALL)
+
+/* ==========================================================================
+ * sendmsg_timedwait()
+ */
+ssize_t sendmsg_timedwait(int fd, const struct msghdr *msg, int flags,
+ struct timespec * timeout)
+{
+ int passed_fd, ret, i;
+
+ /* Handle getting the real file descriptor */
+ for(i = 0; i < (((struct omsghdr *)msg)->msg_accrightslen/sizeof(i)); i++) {
+ passed_fd = *(((int *)((struct omsghdr *)msg)->msg_accrights) + i);
+ if ((ret = fd_lock(passed_fd, FD_RDWR, NULL)) == OK) {
+ *(((int *)((struct omsghdr *)msg)->msg_accrights) + i)
+ = fd_table[passed_fd]->fd.i;
+ machdep_sys_fcntl(fd_table[passed_fd]->fd.i, F_SETFL,
+ fd_table[passed_fd]->flags);
+ switch(fd_table[passed_fd]->type) {
+ case FD_TEST_FULL_DUPLEX:
+ case FD_TEST_HALF_DUPLEX:
+ break;
+ case FD_FULL_DUPLEX:
+ fd_table[passed_fd]->type = FD_TEST_FULL_DUPLEX;
+ break;
+ case FD_HALF_DUPLEX:
+ fd_table[passed_fd]->type = FD_TEST_HALF_DUPLEX;
+ break;
+ default:
+ PANIC();
+ }
+ } else {
+ fd_unlock(fd, FD_RDWR);
+ SET_ERRNO(EBADF);
+ return(NOTOK);
+ }
+ fd_unlock(fd, FD_RDWR);
+ }
+
+ pthread_run->sighandled=0; /* Added by monty */
+ if ((ret = fd_lock(fd, FD_WRITE, timeout)) == OK) {
+ while((ret = machdep_sys_sendmsg(fd_table[fd]->fd.i, msg, flags)) < OK){
+ if (!(fd_table[fd]->flags & __FD_NONBLOCK) &&
+ ((ret == -EWOULDBLOCK) || (ret == -EAGAIN))) {
+ pthread_sched_prevent();
+
+ /* queue pthread for a FDW_WAIT */
+ SET_PF_WAIT_EVENT(pthread_run);
+ pthread_run->data.fd.fd = fd_table[fd]->fd.i;
+ pthread_queue_enq(&fd_wait_write, pthread_run);
+
+ if (timeout) {
+ /* get current time */
+ struct timespec current_time;
+ machdep_gettimeofday(&current_time);
+ sleep_schedule(&current_time, timeout);
+
+ pthread_resched_resume(PS_FDW_WAIT);
+
+ /* We're awake */
+ pthread_sched_prevent();
+ if (sleep_cancel(pthread_run) == NOTOK) {
+ CLEAR_PF_DONE_EVENT(pthread_run);
+ pthread_sched_resume();
+ SET_ERRNO(ETIMEDOUT);
+ ret = NOTOK;
+ break;
+ }
+ pthread_sched_resume();
+
+ } else {
+ pthread_resched_resume(PS_FDW_WAIT);
+ }
+ CLEAR_PF_DONE_EVENT(pthread_run);
+ if (pthread_run->sighandled) /* Added by monty */
+ { /* We where aborted */
+ SET_ERRNO(EINTR);
+ ret= NOTOK;
+ break;
+ }
+
+ } else {
+ SET_ERRNO(-ret);
+ ret = NOTOK;
+ break;
+ }
+ }
+ fd_unlock(fd, FD_WRITE);
+ }
+ return(ret);
+}
+
+/* ==========================================================================
+ * sendmsg()
+ */
+ssize_t sendmsg(int fd, const struct msghdr *msg, int flags)
+{
+ return(sendmsg_timedwait(fd, msg, flags, NULL));
+}
+
+#endif
+
+#if defined (HAVE_SYSCALL_RECV) || defined (HAVE_SYSCALL_SOCKETCALL)
+
+/* ==========================================================================
+ * recv_timedwait()
+ */
+ssize_t recv_timedwait(int fd, void * buf, size_t len, int flags,
+ struct timespec * timeout)
+{
+ int ret;
+
+ pthread_run->sighandled=0; /* Added by monty */
+ if ((ret = fd_lock(fd, FD_READ, timeout)) == OK) {
+ while ((ret = machdep_sys_recv(fd_table[fd]->fd.i,
+ buf, len, flags)) < OK) {
+ if (!(fd_table[fd]->flags & __FD_NONBLOCK) &&
+ ((ret == -EWOULDBLOCK) || (ret == -EAGAIN))) {
+ pthread_sched_prevent();
+
+ /* queue pthread for a FDR_WAIT */
+ SET_PF_WAIT_EVENT(pthread_run);
+ pthread_run->data.fd.fd = fd_table[fd]->fd.i;
+ pthread_queue_enq(&fd_wait_read, pthread_run);
+
+ if (timeout) {
+ /* get current time */
+ struct timespec current_time;
+ machdep_gettimeofday(&current_time);
+ sleep_schedule(&current_time, timeout);
+
+ pthread_resched_resume(PS_FDR_WAIT);
+
+ /* We're awake */
+ pthread_sched_prevent();
+ if (sleep_cancel(pthread_run) == NOTOK) {
+ CLEAR_PF_DONE_EVENT(pthread_run);
+ pthread_sched_resume();
+ ret = -ETIMEDOUT;
+ break;
+ }
+ pthread_sched_resume();
+ } else {
+ pthread_resched_resume(PS_FDR_WAIT);
+ }
+ CLEAR_PF_DONE_EVENT(pthread_run);
+ if (pthread_run->sighandled) /* Added by monty */
+ { /* We where aborted */
+ ret= -EINTR;
+ break;
+ }
+
+ } else {
+ break;
+ }
+ }
+ fd_unlock(fd, FD_READ);
+ }
+ if (ret < 0)
+ {
+ SET_ERRNO(-ret);
+ return(NOTOK);
+ }
+ return(ret);
+}
+
+/* ==========================================================================
+ * recv()
+ */
+ssize_t recv(int fd, void * buf, size_t len, int flags)
+{
+ return(recv_timedwait(fd, buf, len, flags, NULL));
+}
+
+#endif
+
+#if defined (HAVE_SYSCALL_RECVFROM) || defined (HAVE_SYSCALL_SOCKETCALL)
+
+/* ==========================================================================
+ * recvfrom_timedwait()
+ */
+ssize_t recvfrom_timedwait(int fd, void * buf, size_t len, int flags,
+ struct sockaddr * from, int * from_len,
+ struct timespec * timeout)
+{
+ int ret;
+
+ pthread_run->sighandled=0; /* Added by monty */
+ if ((ret = fd_lock(fd, FD_READ, timeout)) == OK) {
+ while ((ret = machdep_sys_recvfrom(fd_table[fd]->fd.i,
+ buf, len, flags, from, from_len)) < OK) {
+ if (!(fd_table[fd]->flags & __FD_NONBLOCK) &&
+ ((ret == -EWOULDBLOCK) || (ret == -EAGAIN))) {
+ pthread_sched_prevent();
+
+ /* queue pthread for a FDR_WAIT */
+ SET_PF_WAIT_EVENT(pthread_run);
+ pthread_run->data.fd.fd = fd_table[fd]->fd.i;
+ pthread_queue_enq(&fd_wait_read, pthread_run);
+
+ if (timeout) {
+ /* get current time */
+ struct timespec current_time;
+ machdep_gettimeofday(&current_time);
+ sleep_schedule(&current_time, timeout);
+
+ pthread_resched_resume(PS_FDR_WAIT);
+
+ /* We're awake */
+ pthread_sched_prevent();
+ if (sleep_cancel(pthread_run) == NOTOK) {
+ CLEAR_PF_DONE_EVENT(pthread_run);
+ pthread_sched_resume();
+ ret= -ETIMEDOUT;
+ break;
+ }
+ pthread_sched_resume();
+
+ } else {
+ pthread_resched_resume(PS_FDR_WAIT);
+ }
+ CLEAR_PF_DONE_EVENT(pthread_run);
+ if (pthread_run->sighandled) /* Added by monty */
+ { /* We where aborted */
+ ret= -EINTR;
+ break;
+ }
+ } else {
+ break;
+ }
+ }
+ fd_unlock(fd, FD_READ);
+ }
+ if (ret < 0)
+ {
+ SET_ERRNO(-ret);
+ return(NOTOK);
+ }
+ return(ret);
+}
+
+/* ==========================================================================
+ * recvfrom()
+ */
+#ifdef _OS_HAS_SOCKLEN_T
+ssize_t recvfrom(int fd, void * buf, size_t len, int flags,
+ struct sockaddr * from, socklen_t * from_len)
+#else
+ssize_t recvfrom(int fd, void * buf, size_t len, int flags,
+ struct sockaddr * from, int * from_len)
+#endif
+{
+ return(recvfrom_timedwait(fd, buf, len, flags, from, from_len, NULL));
+}
+
+#endif
+
+#if defined (HAVE_SYSCALL_RECVMSG) || defined (HAVE_SYSCALL_SOCKETCALL)
+
+/* ==========================================================================
+ * recvmsg_timedwait()
+ */
+ssize_t recvmsg_timedwait(int fd, struct msghdr *msg, int flags,
+ struct timespec * timeout)
+{
+ struct stat stat_buf;
+ int passed_fd, ret, i;
+
+ pthread_run->sighandled=0; /* Added by monty */
+ if ((ret = fd_lock(fd, FD_READ, timeout)) == OK) {
+ while ((ret = machdep_sys_recvmsg(fd_table[fd]->fd.i, msg, flags)) < OK) {
+ if (!(fd_table[fd]->flags & __FD_NONBLOCK) &&
+ ((ret == -EWOULDBLOCK) || (ret == -EAGAIN))) {
+ pthread_sched_prevent();
+
+ /* queue pthread for a FDR_WAIT */
+ SET_PF_WAIT_EVENT(pthread_run);
+ pthread_run->data.fd.fd = fd_table[fd]->fd.i;
+ pthread_queue_enq(&fd_wait_read, pthread_run);
+
+ if (timeout) {
+ /* get current time */
+ struct timespec current_time;
+ machdep_gettimeofday(&current_time);
+ sleep_schedule(&current_time, timeout);
+
+ pthread_resched_resume(PS_FDR_WAIT);
+
+ /* We're awake */
+ pthread_sched_prevent();
+ if (sleep_cancel(pthread_run) == NOTOK) {
+ CLEAR_PF_DONE_EVENT(pthread_run);
+ pthread_sched_resume();
+ SET_ERRNO(ETIMEDOUT);
+ ret = NOTOK;
+ break;
+ }
+ pthread_sched_resume();
+
+ } else {
+ pthread_resched_resume(PS_FDR_WAIT);
+ }
+ CLEAR_PF_DONE_EVENT(pthread_run);
+ if (pthread_run->sighandled) /* Added by monty */
+ { /* We where aborted */
+ SET_ERRNO(EINTR);
+ ret= NOTOK;
+ break;
+ }
+ } else {
+ SET_ERRNO(-ret);
+ ret = NOTOK;
+ break;
+ }
+ }
+ fd_unlock(fd, FD_READ);
+
+ /* Handle getting the real file descriptor */
+ for (i = 0; i < (((struct omsghdr *)msg)->msg_accrightslen / sizeof(i));
+ i++) {
+ passed_fd = *(((int *)((struct omsghdr *)msg)->msg_accrights) + i);
+ if (!((fd = fd_allocate()) < OK)) {
+ fd_table[fd]->flags = machdep_sys_fcntl(passed_fd, F_GETFL);
+
+ if (!( fd_table[fd]->flags & __FD_NONBLOCK)) {
+ machdep_sys_fcntl(passed_fd, F_SETFL,
+ fd_table[fd]->flags | __FD_NONBLOCK);
+ }
+
+ /* fstat the file to determine what type it is */
+ machdep_sys_fstat(passed_fd, &stat_buf);
+ if (S_ISREG(stat_buf.st_mode)) {
+ fd_table[fd]->type = FD_HALF_DUPLEX;
+ } else {
+ fd_table[fd]->type = FD_FULL_DUPLEX;
+ }
+ *(((int *)((struct omsghdr *)msg)->msg_accrights) + i) = fd;
+ fd_table[fd]->ops = &(__fd_kern_ops);
+ fd_table[fd]->fd.i = passed_fd;
+ } else {
+ SET_ERRNO(EBADF);
+ return(NOTOK);
+ break;
+ }
+ }
+ }
+ return(ret);
+}
+
+/* ==========================================================================
+ * recvmsg()
+ */
+ssize_t recvmsg(int fd, struct msghdr *msg, int flags)
+{
+ return(recvmsg_timedwait(fd, msg, flags, NULL));
+}
+
+#endif
+
+#if defined (HAVE_SYSCALL_SHUTDOWN) || defined (HAVE_SYSCALL_SOCKETCALL)
+
+/* ==========================================================================
+ * shutdown()
+ */
+int shutdown(int fd, int how)
+{
+ int ret;
+
+ switch(how) {
+ case 0: /* Read */
+ if ((ret = fd_lock(fd, FD_READ, NULL)) == OK) {
+ if ((ret = machdep_sys_shutdown(fd_table[fd]->fd.i, how)) < OK) {
+ SET_ERRNO(-ret);
+ ret = NOTOK;
+ }
+ fd_unlock(fd, FD_READ);
+ }
+ case 1: /* Write */
+ if ((ret = fd_lock(fd, FD_WRITE, NULL)) == OK) {
+ if ((ret = machdep_sys_shutdown(fd_table[fd]->fd.i, how)) < OK) {
+ SET_ERRNO(-ret);
+ ret = NOTOK;
+ }
+ fd_unlock(fd, FD_WRITE);
+ }
+ case 2: /* Read-Write */
+ if ((ret = fd_lock(fd, FD_RDWR, NULL)) == OK) {
+ if ((ret = machdep_sys_shutdown(fd_table[fd]->fd.i, how)) < OK) {
+ SET_ERRNO(-ret);
+ ret = NOTOK;
+ }
+ fd_unlock(fd, FD_RDWR);
+ }
+ default:
+ SET_ERRNO(EBADF);
+ ret = NOTOK;
+ break;
+ }
+ return(ret);
+}
+
+#endif
+
+#if defined (HAVE_SYSCALL_SETSOCKOPT) || defined (HAVE_SYSCALL_SOCKETCALL)
+
+/* ==========================================================================
+ * setsockopt()
+ */
+#ifdef _OS_HAS_SOCKLEN_T
+int setsockopt(int fd, int level, int optname, const void * optval, socklen_t optlen)
+#else
+int setsockopt(int fd, int level, int optname, const void * optval, int optlen)
+#endif
+{
+ int ret;
+
+ if ((ret = fd_lock(fd, FD_RDWR, NULL)) == OK) {
+ if ((ret = machdep_sys_setsockopt(fd_table[fd]->fd.i, level,
+ optname, optval, optlen)) < OK) {
+ SET_ERRNO(-ret);
+ ret = NOTOK;
+ }
+ fd_unlock(fd, FD_RDWR);
+ }
+ return ret;
+}
+
+#endif
+
+#if defined (HAVE_SYSCALL_GETSOCKOPT) || defined (HAVE_SYSCALL_SOCKETCALL)
+
+/* ==========================================================================
+ * getsockopt()
+ */
+#ifdef _OS_HAS_SOCKLEN_T
+int getsockopt(int fd, int level, int optname, void * optval, socklen_t * optlen)
+#else
+int getsockopt(int fd, int level, int optname, void * optval, int * optlen)
+#endif
+{
+ int ret;
+
+ if ((ret = fd_lock(fd, FD_READ, NULL)) == OK) {
+ if ((ret = machdep_sys_getsockopt(fd_table[fd]->fd.i, level,
+ optname, optval, optlen)) < OK) {
+ SET_ERRNO(-ret);
+ ret = NOTOK;
+ }
+ fd_unlock(fd, FD_RDWR);
+ }
+ return ret;
+}
+
+#endif
+
+#if defined (HAVE_SYSCALL_GETSOCKOPT) || defined (HAVE_SYSCALL_SOCKETCALL)
+
+/* ==========================================================================
+ * getsockname()
+ */
+#ifdef _OS_HAS_SOCKLEN_T
+int getsockname(int fd, struct sockaddr * name, socklen_t * naddrlen)
+#else
+int getsockname(int fd, struct sockaddr * name, int * naddrlen)
+#endif
+{
+ int ret;
+
+ if ((ret = fd_lock(fd, FD_READ, NULL)) == OK) {
+ if ((ret = machdep_sys_getsockname(fd_table[fd]->fd.i,
+ name, naddrlen)) < OK) {
+ SET_ERRNO(-ret);
+ ret = NOTOK;
+ }
+ fd_unlock(fd, FD_RDWR);
+ }
+ return ret;
+}
+
+#endif
+
+#if defined (HAVE_SYSCALL_GETPEERNAME) || defined (HAVE_SYSCALL_SOCKETCALL)
+
+/* ==========================================================================
+ * getpeername()
+ */
+#ifdef _OS_HAS_SOCKLEN_T
+int getpeername(int fd, struct sockaddr * peer, socklen_t * paddrlen)
+#else
+int getpeername(int fd, struct sockaddr * peer, int * paddrlen)
+#endif
+{
+ int ret;
+
+ if ((ret = fd_lock(fd, FD_READ, NULL)) == OK) {
+ if ((ret = machdep_sys_getpeername(fd_table[fd]->fd.i,
+ peer, paddrlen)) < OK) {
+ SET_ERRNO(-ret);
+ ret = NOTOK;
+ }
+ fd_unlock(fd, FD_READ);
+ }
+ return ret;
+}
+
+#endif
+
+#if defined (HAVE_SYSCALL_SOCKETPAIR) || defined (HAVE_SYSCALL_SOCKETCALL)
+
+/* ==========================================================================
+ * socketpair()
+ */
+int socketpair(int af, int type, int protocol, int pair[2])
+{
+ int ret, fd[2];
+
+ if (!((pair[0] = fd_allocate()) < OK)) {
+ if (!((pair[1] = fd_allocate()) < OK)) {
+ if (!((ret = machdep_sys_socketpair(af, type, protocol, fd)) < OK)){
+ int tmp_flags;
+
+ tmp_flags = machdep_sys_fcntl(fd[0], F_GETFL, 0);
+ machdep_sys_fcntl(fd[0], F_SETFL, tmp_flags | __FD_NONBLOCK);
+ fd_table[pair[0]]->ops = & __fd_kern_ops;
+ fd_table[pair[0]]->type = FD_FULL_DUPLEX;
+ fd_table[pair[0]]->flags = tmp_flags;
+ fd_table[pair[0]]->fd.i = fd[0];
+
+ tmp_flags = machdep_sys_fcntl(fd[1], F_GETFL, 0);
+ machdep_sys_fcntl(fd[1], F_SETFL, tmp_flags | __FD_NONBLOCK);
+ fd_table[pair[1]]->ops = & __fd_kern_ops;
+ fd_table[pair[1]]->type = FD_FULL_DUPLEX;
+ fd_table[pair[1]]->flags = tmp_flags;
+ fd_table[pair[1]]->fd.i = fd[1];
+
+ return(ret);
+ }
+ fd_table[pair[1]]->count = 0;
+ }
+ fd_table[pair[0]]->count = 0;
+ SET_ERRNO(-ret);
+ }
+ return(NOTOK);
+}
+
+#endif
diff --git a/mit-pthreads/pthreads/fd_pipe.c b/mit-pthreads/pthreads/fd_pipe.c
new file mode 100644
index 00000000000..e8bc20857ed
--- /dev/null
+++ b/mit-pthreads/pthreads/fd_pipe.c
@@ -0,0 +1,257 @@
+/* ==== fd_pipe.c ============================================================
+ * Copyright (c) 1993, 1994 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Description : The new fast ITC pipe routines.
+ *
+ * 1.00 93/08/14 proven
+ * -Started coding this file.
+ *
+ * 1.01 93/11/13 proven
+ * -The functions readv() and writev() added.
+ */
+
+#ifndef lint
+static const char rcsid[] = "$Id$";
+#endif
+
+#include <pthread.h>
+#include <pthread/fd_pipe.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <pthread/posix.h>
+#include <string.h>
+#include <stdlib.h>
+
+#ifndef MIN
+#define MIN(a,b) ((a)<(b)?(a):(b))
+#endif
+
+/* ==========================================================================
+ * The pipe lock is never unlocked until all pthreads waiting are done with it
+ * read()
+ */
+pthread_ssize_t __pipe_read(union fd_data fd_data, int flags, void *buf,
+ size_t nbytes, struct timespec * timeout)
+{
+ struct __pipe *fd = (struct __pipe *)fd_data.ptr;
+ struct pthread * pthread;
+ int ret = 0;
+
+ if (flags & O_ACCMODE) { return(NOTOK); }
+
+ /* If there is nothing to read, go to sleep */
+ if (fd->count == 0) {
+ if (flags == WR_CLOSED) {
+ return(0);
+ }
+
+ pthread_sched_prevent();
+
+ /* queue pthread for a FDR_WAIT */
+ pthread_run->next = NULL;
+ fd->wait = pthread_run;
+
+ pthread_resched_resume(PS_FDR_WAIT);
+ ret = fd->size;
+ } else {
+ ret = MIN(nbytes, fd->count);
+ memcpy(buf, fd->buf + fd->offset, ret);
+ if (!(fd->count -= ret)) {
+ fd->offset = 0;
+ }
+
+ if (pthread = fd->wait) {
+ fd->wait = NULL;
+ pthread_sched_prevent();
+ pthread_sched_other_resume(pthread);
+ }
+ }
+ return(ret);
+}
+
+/* ==========================================================================
+ * __pipe_write()
+ *
+ * First check to see if the read side is still open, then
+ * check to see if there is a thread in a read wait for this pipe, if so
+ * copy as much data as possible directly into the read waiting threads
+ * buffer. The write thread(whether or not there was a read thread)
+ * copies as much data as it can into the pipe buffer and it there
+ * is still data it goes to sleep.
+ */
+pthread_ssize_t __pipe_write(union fd_data fd_data, int flags, const void *buf,
+ size_t nbytes, struct timespec * timeout) {
+ struct __pipe *fd = (struct __pipe *)fd_data.ptr;
+ struct pthread * pthread;
+ int ret, count;
+
+ if (!(flags & O_ACCMODE)) { return(NOTOK); }
+
+ while (fd->flags != RD_CLOSED) {
+ if (pthread = fd->wait) {
+
+ pthread_sched_prevent();
+
+ /* Copy data directly into waiting pthreads buf */
+ fd->wait_size = MIN(nbytes, fd->wait_size);
+ memcpy(fd->wait_buf, buf, fd->wait_size);
+ buf = (const char *)buf + fd->wait_size;
+ nbytes -= fd->wait_size;
+ ret = fd->wait_size;
+ fd->wait = NULL;
+
+ /* Wake up waiting pthread */
+ pthread_sched_other_resume(pthread);
+ }
+
+ if (count = MIN(nbytes, fd->size - (fd->offset + fd->count))) {
+ memcpy(fd->buf + (fd->offset + fd->count), buf, count);
+ buf = (const char *)buf + count;
+ nbytes -= count;
+ ret += count;
+ }
+ if (nbytes) {
+ pthread_sched_prevent();
+ fd->wait = pthread_run;
+ pthread_resched_resume(PS_FDW_WAIT);
+ } else {
+ return(ret);
+ }
+ }
+ return(NOTOK);
+}
+
+/* ==========================================================================
+ * __pipe_close()
+ *
+ * The whole close procedure is a bit odd and needs a bit of a rethink.
+ * For now close() locks the fd, calls fd_free() which checks to see if
+ * there are any other fd values poinging to the same real fd. If so
+ * It breaks the wait queue into two sections those that are waiting on fd
+ * and those waiting on other fd's. Those that are waiting on fd are connected
+ * to the fd_table[fd] queue, and the count is set to zero, (BUT THE LOCK IS NOT
+ * RELEASED). close() then calls fd_unlock which give the fd to the next queued
+ * element which determins that the fd is closed and then calls fd_unlock etc...
+ */
+int __pipe_close(struct __pipe *fd, int flags)
+{
+ struct pthread * pthread;
+
+ if (!(fd->flags)) {
+ if (pthread = fd->wait) {
+ if (flags & O_ACCMODE) {
+ fd->count = 0;
+ fd->wait = NULL;
+ fd->flags |= WR_CLOSED;
+ pthread_sched_prevent();
+ pthread_resched_resume(pthread);
+ } else {
+ /* Should send a signal */
+ fd->flags |= RD_CLOSED;
+ }
+ }
+ } else {
+ free(fd);
+ return(OK);
+ }
+}
+
+/* ==========================================================================
+ * For fcntl() which isn't implemented yet
+ * __pipe_enosys()
+ */
+static int __pipe_enosys()
+{
+ SET_ERRNO(ENOSYS);
+ return(NOTOK);
+}
+
+/* ==========================================================================
+ * For writev() and readv() which aren't implemented yet
+ * __pipe_enosys_v()
+ */
+static int __pipe_enosys_v(union fd_data fd, int flags,
+ const struct iovec *vec, int nvec,
+ struct timespec *timeout)
+{
+ SET_ERRNO(ENOSYS);
+ return(NOTOK);
+}
+
+/* ==========================================================================
+ * For lseek() which isn't implemented yet
+ * __pipe_enosys_o()
+ */
+static off_t __pipe_enosys_o()
+{
+ SET_ERRNO(ENOSYS);
+ return(NOTOK);
+}
+
+/*
+ * File descriptor operations
+ */
+struct fd_ops fd_ops[] = {
+{ __pipe_write, __pipe_read, __pipe_close, __pipe_enosys,
+ __pipe_enosys_v, __pipe_enosys_v, __pipe_enosys_o, 0 },
+};
+
+/* ==========================================================================
+ * open()
+ */
+/* int __pipe_open(const char *path, int flags, ...) */
+int newpipe(int fd[2])
+{
+ struct __pipe *fd_data;
+
+ if ((!((fd[0] = fd_allocate()) < OK)) && (!((fd[1] = fd_allocate()) < OK))) {
+ fd_data = malloc(sizeof(struct __pipe));
+ fd_data->buf = malloc(4096);
+ fd_data->size = 4096;
+ fd_data->count = 0;
+ fd_data->offset = 0;
+
+ fd_data->wait = NULL;
+ fd_data->flags = 0;
+
+ fd_table[fd[0]]->fd.ptr = fd_data;
+ fd_table[fd[0]]->flags = O_RDONLY;
+ fd_table[fd[1]]->fd.ptr = fd_data;
+ fd_table[fd[1]]->flags = O_WRONLY;
+
+ return(OK);
+ }
+ return(NOTOK);
+}
+
diff --git a/mit-pthreads/pthreads/fd_sysv.c b/mit-pthreads/pthreads/fd_sysv.c
new file mode 100644
index 00000000000..6dc01a49aa4
--- /dev/null
+++ b/mit-pthreads/pthreads/fd_sysv.c
@@ -0,0 +1,897 @@
+/* ==== fd_sysv.c ============================================================
+ * Copyright (c) 1994 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Description : Transforms BSD socket calls to SYSV streams.
+ *
+ * 1.00 94/11/19 proven
+ * -Started coding this file.
+ */
+
+#ifndef lint
+static const char rcsid[] = "$Id$";
+#endif
+
+#include <config.h>
+#include <pthread.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#if defined (HAVE_SYSCALL_PUTMSG) && defined (HAVE_SYSCALL_GETMSG) && !defined(HAVE_SYSCALL_SOCKETCALL) && !defined(HAVE_SYSCALL_SOCKET)
+#define HAVE_STREAMS 1
+
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/socket.h>
+#include <sys/stream.h>
+#include <sys/stropts.h>
+#include <tiuser.h>
+#include <sys/tihdr.h>
+#include <netinet/in.h>
+#include <sys/timod.h>
+
+#define STREAM_BUF_SIZE sizeof(union T_primitives) + sizeof(struct sockaddr)
+
+extern struct pthread_queue fd_wait_read, fd_wait_write;
+
+/* ==========================================================================
+ * putmsg_timedwait_basic()
+ */
+static int putmsg_timedwait_basic(int fd, struct strbuf * ctlptr,
+ struct strbuf * dataptr, int flags, struct timespec * timeout)
+{
+
+ int ret;
+
+ pthread_run->sighandled=0; /* Added by monty */
+ while ((ret = machdep_sys_putmsg(fd_table[fd]->fd.i,
+ ctlptr, dataptr, flags)) < OK) {
+ if (!(fd_table[fd]->flags & __FD_NONBLOCK) &&
+ ((ret == -EWOULDBLOCK) || (ret == -EAGAIN))) {
+ pthread_sched_prevent();
+
+ /* queue pthread for a FDW_WAIT */
+ SET_PF_WAIT_EVENT(pthread_run);
+ pthread_run->data.fd.fd = fd_table[fd]->fd.i;
+ pthread_queue_enq(&fd_wait_write, pthread_run);
+
+ if (timeout) {
+ /* get current time */
+ struct timespec current_time;
+ machdep_gettimeofday(&current_time);
+ sleep_schedule(& current_time, timeout);
+
+ pthread_resched_resume(PS_FDW_WAIT);
+
+ /* We're awake */
+ pthread_sched_prevent();
+ if (sleep_cancel(pthread_run) == NOTOK) {
+ CLEAR_PF_DONE_EVENT(pthread_run);
+ pthread_sched_resume();
+ SET_ERRNO(ETIMEDOUT);
+ ret = -ETIMEDOUT;
+ break;
+ }
+ pthread_sched_resume();
+ } else {
+ pthread_resched_resume(PS_FDW_WAIT);
+ }
+ CLEAR_PF_DONE_EVENT(pthread_run);
+ if (pthread_run->sighandled) /* Added by monty */
+ { /* We where aborted */
+ SET_ERRNO(EINTR);
+ ret= -EINTR;
+ break;
+ }
+ } else {
+ SET_ERRNO(-ret);
+ break;
+ }
+ }
+ return(ret);
+}
+
+/* ==========================================================================
+ * putmsg_timedwait()
+ */
+int putmsg_timedwait(int fd, struct strbuf * ctlptr, struct strbuf * dataptr,
+ int flags, struct timespec * timeout)
+{
+ int ret;
+
+ if ((ret = fd_lock(fd, FD_WRITE, timeout)) == OK) {
+ ret = putmsg_timedwait_basic(fd, ctlptr, dataptr, flags, timeout);
+ fd_unlock(fd, FD_WRITE);
+ }
+ return(ret);
+}
+
+/* ==========================================================================
+ * putmsg()
+ */
+int putmsg(int fd, struct strbuf * ctlptr, struct strbuf * dataptr,
+ int flags)
+{
+ return(putmsg_timedwait(fd, ctlptr, dataptr, flags, NULL));
+}
+
+/* ==========================================================================
+ * getmsg_timedwait_basic()
+ */
+int getmsg_timedwait_basic(int fd, struct strbuf * ctlptr,
+ struct strbuf * dataptr, int * flags, struct timespec * timeout)
+{
+ int ret;
+
+ pthread_run->sighandled=0; /* Added by monty */
+ while ((ret = machdep_sys_getmsg(fd_table[fd]->fd.i,
+ ctlptr, dataptr, flags)) < OK) {
+ if (!(fd_table[fd]->flags & __FD_NONBLOCK) &&
+ ((ret == -EWOULDBLOCK) || (ret == -EAGAIN))) {
+ pthread_sched_prevent();
+
+ /* queue pthread for a FDR_WAIT */
+ SET_PF_WAIT_EVENT(pthread_run);
+ pthread_run->data.fd.fd = fd_table[fd]->fd.i;
+ pthread_queue_enq(&fd_wait_read, pthread_run);
+
+ if (timeout) {
+ /* get current time */
+ struct timespec current_time;
+ machdep_gettimeofday(&current_time);
+ sleep_schedule(& current_time, timeout);
+
+ pthread_resched_resume(PS_FDR_WAIT);
+
+ /* We're awake */
+ pthread_sched_prevent();
+ if (sleep_cancel(pthread_run) == NOTOK) {
+ CLEAR_PF_DONE_EVENT(pthread_run);
+ pthread_sched_resume();
+ SET_ERRNO(ETIMEDOUT);
+ ret = -ETIMEDOUT;
+ break;
+ }
+ pthread_sched_resume();
+ } else {
+ pthread_resched_resume(PS_FDR_WAIT);
+ }
+ CLEAR_PF_DONE_EVENT(pthread_run);
+ if (pthread_run->sighandled) /* Added by monty */
+ { /* We where aborted */
+ SET_ERRNO(EINTR);
+ ret= -EINTR;
+ break;
+ }
+
+ } else {
+ SET_ERRNO(-ret);
+ break;
+ }
+ }
+ return(ret);
+}
+
+/* ==========================================================================
+ * getmsg_timedwait()
+ */
+int getmsg_timedwait(int fd, struct strbuf * ctlptr, struct strbuf * dataptr,
+ int * flags, struct timespec * timeout)
+{
+ int ret;
+
+ if ((ret = fd_lock(fd, FD_READ, timeout)) == OK) {
+ ret = getmsg_timedwait_basic(fd, ctlptr, dataptr, flags, timeout);
+ fd_unlock(fd, FD_READ);
+ }
+ return (ret);
+}
+
+/* ==========================================================================
+ * getmsg()
+ */
+int getmsg(int fd, struct strbuf * ctlptr, struct strbuf * dataptr,
+ int * flags)
+{
+ return(getmsg_timedwait(fd, ctlptr, dataptr, flags, NULL));
+}
+
+#endif
+
+/* ==========================================================================
+ * Here are the berkeley socket functions implemented with stream calls.
+ * These are not POSIX.
+ * ======================================================================= */
+
+#if (!defined (HAVE_SYSCALL_BIND)) && defined(HAVE_STREAMS)
+
+/* ==========================================================================
+ * bind()
+ */
+int bind(int fd, const struct sockaddr *name, int namelen)
+{
+ char buf[STREAM_BUF_SIZE];
+ union T_primitives * res;
+ struct T_bind_req * req;
+ struct T_bind_ack * ack;
+ struct strbuf strbuf;
+ int flags, ret;
+
+ if ((ret = fd_lock(fd, FD_RDWR, NULL)) == OK)
+ {
+ req = (struct T_bind_req *)buf;
+ req->PRIM_type = T_BIND_REQ;
+ req->ADDR_length = namelen;
+ req->ADDR_offset = sizeof(struct T_bind_req);
+ req->CONIND_number = 4;
+ memcpy(buf + sizeof(struct T_bind_req), name, namelen);
+
+ strbuf.len = sizeof(struct T_bind_req) + namelen;
+ strbuf.maxlen = STREAM_BUF_SIZE;
+ strbuf.buf = buf;
+
+ if ((ret=putmsg_timedwait_basic(fd, &strbuf, NULL, 0, NULL)) == OK)
+ {
+ memset(buf, 0, STREAM_BUF_SIZE);
+
+ strbuf.len = sizeof(struct T_bind_ack) + namelen;
+ strbuf.maxlen = STREAM_BUF_SIZE;
+ strbuf.buf = buf;
+ flags = 0;
+
+ if ((ret = getmsg_timedwait_basic(fd, &strbuf, NULL,
+ &flags, NULL)) >= OK)
+ {
+ res = (union T_primitives *)buf;
+
+ switch(res->type) {
+ case T_BIND_ACK:
+ ret = OK;
+ break;
+ default:
+ SET_ERRNO(EPROTO); /* What should this be? */
+ ret = NOTOK;
+ break;
+ }
+ }
+ else
+ {
+ SET_ERRNO(-ret);
+ ret = NOTOK;
+ }
+ }
+ else
+ {
+ SET_ERRNO(-ret);
+ ret = NOTOK;
+ }
+ fd_unlock(fd, FD_RDWR);
+ }
+ return(ret);
+}
+
+#endif
+
+#if (!defined (HAVE_SYSCALL_CONNECT)) && defined(HAVE_STREAMS)
+
+/* ==========================================================================
+ * connect()
+ */
+int connect(int fd, const struct sockaddr *name, int namelen)
+{
+ char buf[STREAM_BUF_SIZE];
+ union T_primitives * res;
+ struct T_conn_req * req;
+ struct T_conn_con * con;
+ struct T_ok_ack * ok;
+ struct strbuf strbuf;
+ int flags, ret;
+
+ if ((ret = fd_lock(fd, FD_RDWR, NULL)) == OK)
+ {
+ req = (struct T_conn_req *)buf;
+ req->PRIM_type = T_CONN_REQ;
+ req->DEST_length = namelen;
+ req->DEST_offset = sizeof(struct T_conn_req);
+ req->OPT_length = 0;
+ req->OPT_offset = 0;
+ memcpy(buf + sizeof(struct T_conn_req), name, namelen);
+
+ strbuf.len = sizeof(struct T_conn_req) + namelen;
+ strbuf.maxlen = STREAM_BUF_SIZE;
+ strbuf.buf = buf;
+
+ if ((ret=putmsg_timedwait_basic(fd, &strbuf, NULL, 0, NULL)) != OK)
+ goto err;
+
+ memset(buf, 0, STREAM_BUF_SIZE);
+ ok = (struct T_ok_ack *)buf;
+
+ strbuf.maxlen = STREAM_BUF_SIZE;
+ strbuf.len = STREAM_BUF_SIZE;
+ strbuf.buf = buf;
+ flags = 0;
+
+ if ((ret=getmsg_timedwait_basic(fd, &strbuf, NULL, &flags, NULL)) < OK)
+ goto err; /* Fixed by monty */
+ if (ok->PRIM_type != T_OK_ACK)
+ {
+ ret= -EPROTO; /* What should this be? */
+ goto err;
+ }
+
+ memset(buf, 0, STREAM_BUF_SIZE);
+ strbuf.maxlen = STREAM_BUF_SIZE;
+ strbuf.len = STREAM_BUF_SIZE;
+ strbuf.buf = buf;
+ flags = 0;
+
+ if ((ret=getmsg_timedwait_basic(fd, &strbuf, NULL, &flags, NULL) < OK))
+ goto err;
+
+ res = (union T_primitives *) buf;
+ switch(res->type) {
+ case T_CONN_CON:
+ ret = OK;
+ break;
+ case T_DISCON_IND:
+ ret= -ECONNREFUSED;
+ goto err;
+ default:
+ ret= -EPROTO; /* What should this be? */
+ goto err;
+ }
+ fd_unlock(fd, FD_RDWR);
+ }
+ return(ret);
+
+ err:
+ fd_unlock(fd, FD_RDWR);
+ SET_ERRNO(-ret); /* Proably not needed... */
+ return NOTOK;
+}
+
+#endif
+
+#if (!defined (HAVE_SYSCALL_LISTEN)) && defined(HAVE_STREAMS)
+
+/* ==========================================================================
+ * listen()
+ */
+int listen(int fd, int backlog)
+{
+ return(OK);
+}
+
+#endif
+
+#if (!defined (HAVE_SYSCALL_SOCKET)) && defined(HAVE_STREAMS)
+
+extern ssize_t __fd_kern_write();
+static pthread_ssize_t __fd_sysv_read();
+extern int __fd_kern_close();
+extern int __fd_kern_fcntl();
+extern int __fd_kern_writev();
+extern int __fd_kern_readv();
+extern off_t __fd_kern_lseek();
+
+/* Normal file operations */
+static struct fd_ops __fd_sysv_ops = {
+ __fd_kern_write, __fd_sysv_read, __fd_kern_close, __fd_kern_fcntl,
+ __fd_kern_writev, __fd_kern_readv, __fd_kern_lseek, 1
+};
+
+/* ==========================================================================
+ * read()
+ */
+static pthread_ssize_t __fd_sysv_read(union fd_data fd_data, int flags,
+ void *buf, size_t nbytes, struct timespec * timeout)
+{
+ struct strbuf dataptr;
+ int fd = fd_data.i;
+ int getmsg_flags;
+ int ret;
+
+ getmsg_flags = 0;
+ dataptr.len = 0;
+ dataptr.buf = buf;
+ dataptr.maxlen = nbytes;
+
+ pthread_run->sighandled=0; /* Added by monty */
+ while ((ret = machdep_sys_getmsg(fd, NULL, &dataptr, &getmsg_flags)) < OK) {
+ if (!(fd_table[fd]->flags & __FD_NONBLOCK) &&
+ ((ret == -EWOULDBLOCK) || (ret == -EAGAIN))) {
+ pthread_sched_prevent();
+
+ /* queue pthread for a FDR_WAIT */
+ pthread_run->data.fd.fd = fd;
+ SET_PF_WAIT_EVENT(pthread_run);
+ pthread_queue_enq(&fd_wait_read, pthread_run);
+
+ if (timeout) {
+ /* get current time */
+ struct timespec current_time;
+ machdep_gettimeofday(&current_time);
+ sleep_schedule(& current_time, timeout);
+
+ pthread_resched_resume(PS_FDR_WAIT);
+
+ /* We're awake */
+ pthread_sched_prevent();
+ if (sleep_cancel(pthread_run) == NOTOK) {
+ CLEAR_PF_DONE_EVENT(pthread_run);
+ pthread_sched_resume();
+ SET_ERRNO(ETIMEDOUT);
+ ret = -ETIMEDOUT;
+ break;
+ }
+ pthread_sched_resume();
+ } else {
+ pthread_resched_resume(PS_FDR_WAIT);
+ }
+ CLEAR_PF_DONE_EVENT(pthread_run);
+ if (pthread_run->sighandled) /* Added by monty */
+ { /* We where aborted */
+ SET_ERRNO(EINTR);
+ return(NOTOK);
+ }
+ } else {
+ SET_ERRNO(-ret);
+ return(NOTOK);
+ break;
+ }
+ }
+ return(dataptr.len);
+}
+
+/* ==========================================================================
+ * socket_tcp()
+ */
+static int socket_tcp(int fd)
+{
+ int ret;
+
+ if ((ret = machdep_sys_open("/dev/tcp", O_RDWR | O_NONBLOCK, 0)) >= OK) {
+ /* Should fstat the file to determine what type it is */
+ fd_table[fd]->ops = & __fd_sysv_ops;
+ fd_table[fd]->type = FD_FULL_DUPLEX;
+ fd_table[fd]->fd.i = ret;
+ fd_table[fd]->flags = 0;
+ }
+ return(ret);
+}
+
+/* ==========================================================================
+ * socket()
+ */
+int socket(int af, int type, int protocol)
+{
+ int fd, fd_kern;
+
+ if ((fd = fd_allocate()) < OK)
+ return (fd);
+
+ switch(af) {
+ case AF_INET:
+ switch(type) {
+ case SOCK_STREAM:
+ if ((fd_kern = socket_tcp(fd)) >= OK)
+ return(fd);
+ SET_ERRNO(-fd_kern);
+ break;
+ case SOCK_DGRAM:
+ if ((fd_kern = machdep_sys_open("/dev/udp",
+ O_RDWR | O_NONBLOCK, 0)) >= OK) {
+ /* Should fstat the file to determine what type it is */
+ fd_table[fd]->ops = & __fd_sysv_ops;
+ fd_table[fd]->type = FD_FULL_DUPLEX;
+ fd_table[fd]->fd.i = fd_kern;
+ fd_table[fd]->flags = 0;
+ return(fd);
+ }
+ SET_ERRNO(-fd_kern);
+ break;
+ default:
+ SET_ERRNO(EPROTONOSUPPORT);
+ break;
+ }
+ break;
+ case AF_UNIX:
+ case AF_ISO:
+ case AF_NS:
+ default:
+ SET_ERRNO(EPROTONOSUPPORT);
+ break;
+ }
+ fd_table[fd]->count = 0;
+ return(NOTOK); /* Fixed by monty */
+}
+
+#endif
+
+#if (!defined (HAVE_SYSCALL_ACCEPT)) && defined(HAVE_STREAMS)
+
+/* ==========================================================================
+ * accept_fd()
+ */
+static int accept_fd(int fd, struct sockaddr *name, int *namelen, char * buf,
+ int SEQ_number)
+{
+ struct T_conn_res * res;
+ struct strbuf strbuf;
+ int fd_new, fd_kern;
+
+ /* Get a new table entry */
+ if ((fd_new = fd_allocate()) < OK)
+ return(NOTOK);
+
+ /* Get the new kernel entry */
+ if (!((fd_kern = socket_tcp(fd_new)) < OK)) {
+ res = (struct T_conn_res *)buf;
+ res->PRIM_type = T_CONN_RES;
+ /* res->QUEUE_ptr = (queue_t *)&fd_kern; */
+ res->OPT_length = 0;
+ res->OPT_offset = 0;
+ res->SEQ_number = SEQ_number;
+
+ strbuf.maxlen = sizeof(union T_primitives) +sizeof(struct sockaddr);
+ strbuf.len = sizeof(struct T_conn_ind) + (*namelen);
+ strbuf.buf = buf;
+
+ {
+ struct strfdinsert insert;
+
+ insert.ctlbuf.maxlen = (sizeof(union T_primitives) +
+ sizeof(struct sockaddr));
+ insert.ctlbuf.len = sizeof(struct T_conn_ind);
+ insert.ctlbuf.buf = buf;
+ insert.databuf.maxlen = 0;
+ insert.databuf.len = 0;
+ insert.databuf.buf = NULL;
+ insert.flags = 0;
+ insert.fildes = fd_kern;
+ insert.offset = 4;
+ /* Should the following be checked ? */
+ machdep_sys_ioctl(fd_table[fd]->fd.i, I_FDINSERT, &insert);
+ }
+
+ /* if (putmsg_timedwait_basic(fd, &strbuf, NULL, 0, NULL) == OK) {
+ /* return(fd_new); */
+ {
+ int flags = 0;
+ int ret;
+
+ /* Should the following be checked ? */
+ ret = getmsg_timedwait_basic(fd, &strbuf, NULL, &flags, NULL);
+ return(fd_new);
+
+ }
+ machdep_sys_close(fd_kern);
+ }
+ fd_table[fd_new]->count = 0;
+ return(NOTOK);
+}
+
+
+/* ==========================================================================
+ * accept()
+ */
+int accept(int fd, struct sockaddr *name, int *namelen)
+{
+ char buf[sizeof(union T_primitives) + sizeof(struct sockaddr)];
+ struct T_conn_ind * ind;
+ struct strbuf strbuf;
+ int flags, ret;
+
+ if ((ret = fd_lock(fd, FD_RDWR, NULL)) == OK)
+ {
+ ind = (struct T_conn_ind *)buf;
+ ind->PRIM_type = T_CONN_IND;
+ ind->SRC_length = (*namelen);
+ ind->SRC_offset = sizeof(struct T_conn_ind);
+ ind->OPT_length = 0;
+ ind->OPT_offset = 0;
+ ind->SEQ_number = 0;
+
+ strbuf.maxlen = sizeof(union T_primitives) + sizeof(struct sockaddr);
+ strbuf.len = sizeof(struct T_conn_ind) + (*namelen);
+ strbuf.buf = buf;
+ flags = 0;
+
+ if ((ret=getmsg_timedwait_basic(fd, &strbuf, NULL, &flags, NULL)) < OK)
+ {
+ SET_ERRNO(-ret);
+ ret= NOTOK;
+ }
+ else
+ ret = accept_fd(fd, name, namelen, buf, ind->SEQ_number);
+ fd_unlock(fd, FD_RDWR);
+ }
+ return(ret);
+}
+
+#endif /* HAVE_SYSCALL_ACCEPT */
+
+#if (!defined (HAVE_SYSCALL_SENDTO)) && defined (HAVE_STREAMS)
+
+/* ==========================================================================
+ * sendto_timedwait()
+ */
+ssize_t sendto_timedwait(int fd, const void * msg, size_t len, int flags,
+ const struct sockaddr *name, int namelen, struct timespec * timeout)
+{
+ char buf[STREAM_BUF_SIZE];
+ struct T_unitdata_req * req;
+ struct strbuf dataptr;
+ struct strbuf ctlptr;
+ ssize_t ret, prio;
+
+ req = (struct T_unitdata_req *)buf;
+ req->PRIM_type = T_UNITDATA_REQ;
+ req->DEST_length = namelen;
+ req->DEST_offset = sizeof(struct T_unitdata_req);
+ req->OPT_length = 0;
+ req->OPT_offset = 0;
+ memcpy(buf + sizeof(struct T_unitdata_req), name, namelen);
+
+ ctlptr.len = sizeof(struct T_unitdata_req) + namelen;
+ ctlptr.maxlen = STREAM_BUF_SIZE;
+ ctlptr.buf = buf;
+
+ dataptr.len = len;
+ dataptr.maxlen = len;
+ dataptr.buf = (void *)msg;
+
+ if ((ret = putmsg_timedwait(fd, &ctlptr, &dataptr, 0, timeout)) == OK) {
+ ret = len;
+ }
+ return(ret);
+}
+
+/* ==========================================================================
+ * sendto()
+ */
+ssize_t sendto(int fd, const void * msg, size_t len, int flags,
+ const struct sockaddr *to, int to_len)
+{
+ return(sendto_timedwait(fd, msg, len, flags, to, to_len, NULL));
+}
+
+#endif
+
+#if (!defined (HAVE_SYSCALL_SEND)) && defined (HAVE_STREAMS)
+
+/* ==========================================================================
+ * send_timedwait()
+ */
+ssize_t send_timedwait(int fd, const void * msg, size_t len, int flags,
+ struct timespec * timeout)
+{
+ char buf[STREAM_BUF_SIZE];
+ struct T_unitdata_req * req;
+ struct strbuf dataptr;
+ struct strbuf ctlptr;
+ ssize_t ret, prio;
+
+ req = (struct T_unitdata_req *)buf;
+ req->PRIM_type = T_UNITDATA_REQ;
+ req->DEST_length = 0;
+ req->DEST_offset = 0;
+ req->OPT_length = 0;
+ req->OPT_offset = 0;
+
+ ctlptr.len = sizeof(struct T_unitdata_req);
+ ctlptr.maxlen = STREAM_BUF_SIZE;
+ ctlptr.buf = buf;
+
+ dataptr.len = len;
+ dataptr.maxlen = len;
+ dataptr.buf = (void *)msg;
+
+ if ((ret = putmsg_timedwait(fd, &ctlptr, &dataptr, 0, timeout)) == OK) {
+ ret = len;
+ }
+ return(ret);
+}
+
+/* ==========================================================================
+ * send()
+ */
+ssize_t send(int fd, const void * msg, size_t len, int flags)
+{
+ return(send_timedwait(fd, msg, len, flags, NULL));
+}
+
+#endif
+
+#if (!defined (HAVE_SYSCALL_RECVFROM)) && defined(HAVE_STREAMS)
+
+/* ==========================================================================
+ * recvfrom_timedwait()
+ */
+ssize_t recvfrom_timedwait(int fd, void * msg, size_t len, int flags,
+ struct sockaddr * name, int * namelen, struct timespec * timeout)
+{
+ char buf[STREAM_BUF_SIZE];
+ struct T_unitdata_ind * ind;
+ struct strbuf dataptr;
+ struct strbuf ctlptr;
+ int ret, prio;
+
+ ctlptr.len = 0;
+ ctlptr.maxlen = STREAM_BUF_SIZE;
+ ctlptr.buf = buf;
+
+ dataptr.maxlen = len;
+ dataptr.len = 0;
+ dataptr.buf = msg;
+
+ prio = 0;
+
+ ret = getmsg_timedwait(fd, &ctlptr, &dataptr, &prio, timeout);
+ if (ret >= OK) {
+ if (name != NULL) {
+ ind = (struct T_unitdata_ind *)buf;
+
+ if (*namelen > ind->SRC_length)
+ *namelen = ind->SRC_length;
+ memcpy(name, buf + ind->SRC_offset, *namelen);
+ }
+ ret = dataptr.len;
+ }
+
+ return(ret);
+}
+
+/* ==========================================================================
+ * recvfrom()
+ */
+ssize_t recvfrom(int fd, void * buf, size_t len, int flags,
+ struct sockaddr * from, int * from_len)
+{
+ return(recvfrom_timedwait(fd, buf, len, flags, from, from_len, NULL));
+}
+
+#endif
+
+#if (!defined (HAVE_SYSCALL_RECV)) && defined(HAVE_STREAMS)
+
+/* ==========================================================================
+ * recv_timedwait()
+ */
+ssize_t recv_timedwait(int fd, void * msg, size_t len, int flags,
+ struct timespec * timeout)
+{
+ char buf[STREAM_BUF_SIZE];
+ struct T_unitdata_ind * ind;
+ struct strbuf dataptr;
+ struct strbuf ctlptr;
+ int ret, prio;
+
+ ctlptr.len = 0;
+ ctlptr.maxlen = STREAM_BUF_SIZE;
+ ctlptr.buf = buf;
+
+ dataptr.maxlen = len;
+ dataptr.len = 0;
+ dataptr.buf = msg;
+
+ prio = 0;
+
+ ret = getmsg_timedwait(fd, &ctlptr, &dataptr, &prio, timeout);
+ if (ret >= OK)
+ ret = dataptr.len;
+
+ return(ret);
+}
+
+/* ==========================================================================
+ * recv()
+ */
+ssize_t recv(int fd, void * buf, size_t len, int flags,
+ struct sockaddr * from, int * from_len)
+{
+ return(recv_timedwait(fd, buf, len, flags, NULL));
+}
+
+#endif
+
+#if (!defined (HAVE_SYSCALL_SETSOCKOPT)) && defined(HAVE_STREAMS)
+/* ==========================================================================
+ * setsockopt()
+ */
+int setsockopt(int s, int level, int optname, const void *optval, int optlen)
+{
+ return(0);
+}
+#endif
+
+struct foo { /* Used by getsockname and getpeername */
+ long a;
+ int b;
+ struct sockaddr *name;
+};
+
+#if (!defined (HAVE_SYSCALL_GETSOCKNAME)) && defined(HAVE_STREAMS)
+/* ==========================================================================
+ * getsockname()
+ */
+
+
+int getsockname(int s, struct sockaddr *name, int *namelen)
+{
+ struct foo foo;
+ int i;
+ if (*namelen < sizeof(struct sockaddr)) {
+ SET_ERRNO(ENOMEM);
+ return(-1);
+ }
+ foo.a = 0x84;
+ foo.b = 0;
+ foo.name = name;
+ i = ioctl(s, TI_GETMYNAME, &foo);
+ *namelen = foo.b;
+ return(i);
+}
+#endif
+
+#if (!defined (HAVE_SYSCALL_GETPEERNAME)) && defined(HAVE_STREAMS)
+/* ==========================================================================
+ * getpeername() ; Added by Monty
+ */
+
+int getpeername(int s, struct sockaddr *name, int *namelen)
+{
+ struct foo foo;
+ int i;
+ if (*namelen < sizeof(struct sockaddr)) {
+ SET_ERRNO(ENOMEM);
+ return(-1);
+ }
+ foo.a = 0x84; /* Max length ? */
+ foo.b = 0; /* Return length */
+ foo.name = name; /* Return buffer */
+ i = ioctl(s, TI_GETPEERNAME, &foo);
+ *namelen = foo.b;
+ return(i);
+}
+#endif
+
+
+#if (!defined (HAVE_SYSCALL_SHUTDOWN)) && defined(HAVE_STREAMS)
+/* ==========================================================================
+ * shutdown()
+ */
+
+int shutdown(int s, int how)
+{
+ return(0);
+}
+#endif
diff --git a/mit-pthreads/pthreads/file.c b/mit-pthreads/pthreads/file.c
new file mode 100644
index 00000000000..4b8a8aad6db
--- /dev/null
+++ b/mit-pthreads/pthreads/file.c
@@ -0,0 +1,129 @@
+/* ==== file.c ============================================================
+ * Copyright (c) 1993, 1994 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Description : The locking functions for stdio.
+ *
+ * 1.00 93/09/04 proven
+ * -Started coding this file.
+ */
+
+#ifndef lint
+static const char rcsid[] = "$Id$";
+#endif
+
+#include <pthread.h>
+#include <stdio.h>
+
+/* ==========================================================================
+ * flockfile()
+ */
+void flockfile(FILE *fp)
+{
+ pthread_mutex_t *mutex;
+ int fd, flags;
+
+ if ((fd = fileno(fp)) >= 0) {
+ pthread_mutex_lock(mutex = &(fd_table[fd]->mutex));
+
+ if (fp->_flags & __SRW) {
+ flags = FD_READ | FD_WRITE;
+ } else {
+ if (fp->_flags & __SWR) {
+ flags = FD_WRITE;
+ } else {
+ flags = FD_READ;
+ }
+ }
+
+ /* This might fail but POSIX doesn't give a damn. */
+ fd_basic_lock(fd, flags, mutex, NULL);
+ pthread_mutex_unlock(mutex);
+ }
+}
+
+/* ==========================================================================
+ * ftrylockfile()
+ */
+int ftrylockfile(FILE *fp)
+{
+ pthread_mutex_t *mutex;
+ int fd, flags;
+
+ if ((fd = fileno(fp)) >= 0) {
+ pthread_mutex_lock(mutex = &(fd_table[fd]->mutex));
+
+ if (fp->_flags & __SRW) {
+ flags = FD_READ | FD_WRITE;
+ } else {
+ if (fp->_flags & __SWR) {
+ flags = FD_WRITE;
+ } else {
+ flags = FD_READ;
+ }
+ }
+ if (!(fd_table[fd]->r_owner && fd_table[fd]->w_owner)) {
+ fd_basic_lock(fd, flags, mutex, NULL);
+ fd = OK;
+ } else {
+ fd = NOTOK;
+ }
+ pthread_mutex_unlock(mutex);
+ } else {
+ fd = OK;
+ }
+ return(fd);
+}
+
+/* ==========================================================================
+ * funlockfile()
+ */
+void funlockfile(FILE *fp)
+{
+ pthread_mutex_t *mutex;
+ int fd, flags;
+
+ if ((fd = fileno(fp)) >= 0) {
+ pthread_mutex_lock(mutex = &(fd_table[fd]->mutex));
+
+ if (fp->_flags & __SRW) {
+ flags = FD_READ | FD_WRITE;
+ } else {
+ if (fp->_flags & __SWR) {
+ flags = FD_WRITE;
+ } else {
+ flags = FD_READ;
+ }
+ }
+ fd_basic_unlock(fd, flags);
+ pthread_mutex_unlock(mutex);
+ }
+}
+
diff --git a/mit-pthreads/pthreads/globals.c b/mit-pthreads/pthreads/globals.c
new file mode 100644
index 00000000000..921588fb220
--- /dev/null
+++ b/mit-pthreads/pthreads/globals.c
@@ -0,0 +1,85 @@
+/* ==== globals.c ============================================================
+ * Copyright (c) 1993, 1994 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Description : Global variables.
+ *
+ * 1.00 93/07/26 proven
+ * -Started coding this file.
+ */
+
+#ifndef lint
+static const char rcsid[] = "$Id$";
+#endif
+
+#include <pthread.h>
+
+/*
+ * Initial thread, running thread, and top of link list of all threads.
+ */
+struct pthread *pthread_run=NULL;
+struct pthread *pthread_initial=NULL;
+struct pthread *pthread_link_list=NULL;
+
+sigset_t * uthread_sigmask; /* Current process signal mask */
+
+/*
+ * Dead thread queue, and threads elligible to be alloced queue.
+ */
+struct pthread_queue pthread_dead_queue;
+struct pthread_queue pthread_alloc_queue;
+
+/*
+ * Queue for all threads elidgeable to run this scheduling round.
+ */
+struct pthread_prio_queue * pthread_current_prio_queue=NULL;
+
+/*
+ * default thread attributes
+ */
+pthread_attr_t pthread_attr_default = { SCHED_RR, PTHREAD_DEFAULT_PRIORITY,
+ PTHREAD_CREATE_JOINABLE, NULL, NULL, NULL, PTHREAD_STACK_DEFAULT };
+
+/*
+ * File table information
+ */
+struct fd_table_entry **fd_table=NULL;
+
+/*
+ * A we a fork()ed process
+ */
+volatile int fork_lock = 0;
+volatile int pthread_kernel_lock=0;
+
+/*
+ * The page size, as returned by getpagesize()
+ */
+size_t pthread_pagesize=0;
+
diff --git a/mit-pthreads/pthreads/info.c b/mit-pthreads/pthreads/info.c
new file mode 100644
index 00000000000..2b9722ba291
--- /dev/null
+++ b/mit-pthreads/pthreads/info.c
@@ -0,0 +1,77 @@
+/* hello */
+
+#include <stdio.h>
+#include <pthread.h>
+#include <signal.h>
+
+static const char *const state_names[] = {
+#define __pthread_defstate(S,NAME) NAME,
+#include "pthread/state.def"
+#undef __pthread_defstate
+ 0
+};
+
+void (*dump_thread_info_fn) (struct pthread *, FILE *);
+
+static void
+dump_thread_info (thread, file)
+ struct pthread *thread;
+ FILE *file;
+{
+ /* machdep */
+ /* attr */
+ /* signals */
+ /* wakeup_time */
+ /* join */
+ fprintf (file, " thread @%p prio %3d %s", thread,
+ thread->pthread_priority, state_names[(int) thread->state]);
+ switch (thread->state) {
+ case PS_FDLR_WAIT:
+ fprintf (file, " fd %d[%d]", thread->data.fd.fd,
+ thread->data.fd.branch);
+ fprintf (file, " owner %pr/%pw",
+ fd_table[thread->data.fd.fd]->r_owner,
+ fd_table[thread->data.fd.fd]->w_owner);
+ break;
+ }
+ /* show where the signal handler gets run */
+ if (thread == pthread_run)
+ fprintf (file, "\t\t[ME!]");
+ fprintf (file, "\n");
+ if (dump_thread_info_fn)
+ (*dump_thread_info_fn) (thread, file);
+}
+
+static void
+pthread_dump_info_to_file (file)
+ FILE *file;
+{
+ pthread_t t;
+ for (t = pthread_link_list; t; t = t->pll)
+ dump_thread_info (t, file);
+}
+
+void
+pthread_dump_info ()
+{
+ if (ftrylockfile (stderr) != 0)
+ return;
+ fprintf (stderr, "process id %ld:\n", (long) getpid ());
+ pthread_dump_info_to_file (stderr);
+ funlockfile (stderr);
+}
+
+#ifdef SIGINFO
+static void
+sig_handler (sig)
+ int sig;
+{
+ pthread_dump_info ();
+}
+
+void
+pthread_setup_siginfo ()
+{
+ (void) signal (SIGINFO, sig_handler);
+}
+#endif
diff --git a/mit-pthreads/pthreads/init.cc b/mit-pthreads/pthreads/init.cc
new file mode 100644
index 00000000000..24a131a60a5
--- /dev/null
+++ b/mit-pthreads/pthreads/init.cc
@@ -0,0 +1,9 @@
+
+/*
+ * DO not delete this file. The hack here ensures that pthread_init() gets
+ * called before main does. This doesn't fix everything. It is still
+ * possible for a c++ module to reley on constructors that need pthreads.
+ */
+#include <pthread.h>
+
+char __pthread_init_hack = 42;
diff --git a/mit-pthreads/pthreads/malloc.c b/mit-pthreads/pthreads/malloc.c
new file mode 100644
index 00000000000..76fe03824ac
--- /dev/null
+++ b/mit-pthreads/pthreads/malloc.c
@@ -0,0 +1,383 @@
+/* ==== malloc.c ============================================================
+ * Copyright (c) 1983 Regents of the University of California.
+ * Copyright (c) 1993, 1994 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Description : Malloc functions.
+ * This is a very fast storage allocator. It allocates blocks of a small
+ * number of different sizes, and keeps free lists of each size. Blocks that
+ * don't exactly fit are passed up to the next larger size. In this
+ * implementation, the available sizes are 2^n-4 (or 2^n-10) bytes long.
+ * This is designed for use in a virtual memory environment.
+ *
+ * 0.00 82/02/21 Chris Kingsley kingsley@cit-20
+ *
+ * 1.00 93/11/06 proven
+ * -Modified BSD libc malloc to be threadsafe.
+ *
+ */
+
+#ifndef lint
+static const char rcsid[] = "$Id$";
+#endif
+
+#include <pthread.h>
+#include <sys/types.h>
+#include <string.h>
+#include <pthread/posix.h>
+
+/*
+ * The overhead on a block is at least 4 bytes. When free, this space
+ * contains a pointer to the next free block, and the bottom two bits must
+ * be zero. When in use, the first byte is set to MAGIC, and the second
+ * byte is the size index. The remaining bytes are for alignment.
+ * If range checking is enabled then a second word holds the size of the
+ * requested block, less 1, rounded up to a multiple of sizeof(RMAGIC).
+ * The order of elements is critical: ov_magic must overlay the low order
+ * bits of ov_next, and ov_magic can not be a valid ov_next bit pattern.
+ */
+#ifdef __alpha
+#define _MOST_RESTRICTIVE_ALIGNMENT_TYPE char*
+#else
+#define _MOST_RESTRICTIVE_ALIGNMENT_TYPE double
+#endif /* __alpha */
+union overhead {
+ _MOST_RESTRICTIVE_ALIGNMENT_TYPE __alignment_pad0;
+ union overhead *ov_next; /* when free */
+ struct {
+ u_char ovu_magic; /* magic number */
+ u_char ovu_index; /* bucket # */
+#ifdef RCHECK
+ u_short ovu_rmagic; /* range magic number */
+ size_t ovu_size; /* actual block size */
+#endif
+ } ovu;
+#define ov_magic ovu.ovu_magic
+#define ov_index ovu.ovu_index
+#define ov_rmagic ovu.ovu_rmagic
+#define ov_size ovu.ovu_size
+};
+
+#define MAGIC 0xef /* magic # on accounting info */
+#define RMAGIC 0x5555 /* magic # on range info */
+
+#ifdef RCHECK
+#define RSLOP sizeof (u_short)
+#else
+#define RSLOP 0
+#endif
+
+/*
+ * nextf[i] is the pointer to the next free block of size 2^(i+3). The
+ * smallest allocatable block is 8 bytes. The overhead information
+ * precedes the data area returned to the user.
+ */
+#define NBUCKETS 30
+static union overhead *nextf[NBUCKETS];
+#ifndef hpux
+extern char *sbrk();
+#endif
+
+static size_t pagesz; /* page size */
+static int pagebucket; /* page size bucket */
+static pthread_mutex_t malloc_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+#if defined(DEBUG) || defined(RCHECK)
+#define ASSERT(p) if (!(p)) botch("p")
+#include <stdio.h>
+static
+botch(s)
+ char *s;
+{
+ fprintf(stderr, "\r\nassertion botched: %s\r\n", s);
+ (void) fflush(stderr); /* just in case user buffered it */
+ abort();
+}
+#else
+#define ASSERT(p)
+#endif
+
+/* ==========================================================================
+ * morecore()
+ *
+ * Allocate more memory to the indicated bucket
+ */
+static inline void morecore(int bucket)
+{
+ register union overhead *op;
+ register size_t sz; /* size of desired block */
+ size_t amt; /* amount to allocate */
+ size_t nblks; /* how many blocks we get */
+
+ /*
+ * sbrk_size <= 0 only for big, FLUFFY, requests (about
+ * 2^30 bytes on a VAX, I think) or for a negative arg.
+ */
+ sz = 1L << (bucket + 3);
+#ifdef DEBUG
+ ASSERT(sz > 0);
+#else
+ if (sz <= 0)
+ return;
+#endif
+ if (sz < pagesz) {
+ amt = pagesz;
+ nblks = amt / sz;
+ } else {
+ amt = sz + pagesz;
+ nblks = 1;
+ }
+ op = (union overhead *)sbrk(amt);
+ /* no more room! */
+ if (op == (union overhead *) -1)
+ return;
+ /*
+ * Add new memory allocated to that on
+ * free list for this hash bucket.
+ */
+ nextf[bucket] = op;
+ while (--nblks > 0) {
+ op->ov_next = (union overhead *)((caddr_t)op + sz);
+ op = (union overhead *)((caddr_t)op + sz);
+ }
+}
+
+/* ==========================================================================
+ * malloc()
+ */
+void *malloc(size_t nbytes)
+{
+ pthread_mutex_t *mutex;
+ union overhead *op;
+ size_t amt;
+ size_t bucket, n;
+
+ mutex = &malloc_mutex;
+ pthread_mutex_lock(mutex);
+ /*
+ * First time malloc is called, setup page size and
+ * align break pointer so all data will be page aligned.
+ */
+ if (pagesz == 0) {
+ size_t x;
+ pagesz = n = getpagesize();
+ op = (union overhead *)sbrk(0);
+ x = sizeof (*op) - ((long)op & (n - 1));
+ if (n < x)
+ n = n + pagesz - x;
+ else
+ n = n - x;
+ if (n) {
+ if (sbrk(n) == (char *)-1) {
+ /* Unlock before returning (mevans) */
+ pthread_mutex_unlock(mutex);
+ return (NULL);
+ }
+ }
+ bucket = 0;
+ amt = 8;
+ while (pagesz > amt) {
+ amt <<= 1;
+ bucket++;
+ }
+ pagebucket = bucket;
+ }
+ /*
+ * Convert amount of memory requested into closest block size
+ * stored in hash buckets which satisfies request.
+ * Account for space used per block for accounting.
+ */
+ if (nbytes <= (n = pagesz - sizeof (*op) - RSLOP)) {
+#ifndef RCHECK
+ amt = 8; /* size of first bucket */
+ bucket = 0;
+#else
+ amt = 16; /* size of first bucket */
+ bucket = 1;
+#endif
+ n = -(sizeof (*op) + RSLOP);
+ } else {
+ amt = pagesz;
+ bucket = pagebucket;
+ }
+ while (nbytes > amt + n) {
+ amt <<= 1;
+ if (amt == 0) {
+ pthread_mutex_unlock(mutex);
+ return (NULL);
+ }
+ bucket++;
+ }
+ ASSERT (bucket < NBUCKETS);
+ /*
+ * If nothing in hash bucket right now,
+ * request more memory from the system.
+ */
+ if ((op = nextf[bucket]) == NULL) {
+ morecore(bucket);
+ if ((op = nextf[bucket]) == NULL) {
+ pthread_mutex_unlock(mutex);
+ return (NULL);
+ }
+ }
+ /* remove from linked list */
+ nextf[bucket] = op->ov_next;
+ op->ov_magic = MAGIC;
+ op->ov_index = bucket;
+#ifdef RCHECK
+ /*
+ * Record allocated size of block and
+ * bound space with magic numbers.
+ */
+ op->ov_size = (nbytes + RSLOP - 1) & ~(RSLOP - 1);
+ op->ov_rmagic = RMAGIC;
+ *(u_short *)((caddr_t)(op + 1) + op->ov_size) = RMAGIC;
+#endif
+ pthread_mutex_unlock(mutex);
+ return ((char *)(op + 1));
+}
+
+/* ==========================================================================
+ * free()
+ */
+void free(void *cp)
+{
+ pthread_mutex_t *mutex;
+ union overhead *op;
+ int size;
+
+ mutex = &malloc_mutex;
+ pthread_mutex_lock(mutex);
+ if (cp == NULL) {
+ pthread_mutex_unlock(mutex);
+ return;
+ }
+ op = (union overhead *)((caddr_t)cp - sizeof (union overhead));
+#ifdef DEBUG
+ ASSERT(op->ov_magic == MAGIC); /* make sure it was in use */
+#else
+ if (op->ov_magic != MAGIC) {
+ pthread_mutex_unlock(mutex);
+ return; /* sanity */
+ }
+#endif
+#ifdef RCHECK
+ ASSERT(op->ov_rmagic == RMAGIC);
+ ASSERT(*(u_short *)((caddr_t)(op + 1) + op->ov_size) == RMAGIC);
+#endif
+ size = op->ov_index;
+ ASSERT(size < NBUCKETS);
+ op->ov_next = nextf[size]; /* also clobbers ov_magic */
+ nextf[size] = op;
+
+ pthread_mutex_unlock(mutex);
+}
+
+/* ==========================================================================
+ * realloc()
+ *
+ * Storage compaction is no longer supported, fix program and try again.
+ */
+void *realloc(void *cp, size_t nbytes)
+{
+ pthread_mutex_t *mutex;
+ size_t onb;
+ size_t i;
+ union overhead *op;
+ char *res;
+
+ if (cp == NULL)
+ return (malloc(nbytes));
+ op = (union overhead *)((caddr_t)cp - sizeof (union overhead));
+
+ if (op->ov_magic == MAGIC) {
+ i = op->ov_index;
+ } else {
+ /*
+ * This will cause old programs using storage compaction feature of
+ * realloc to break in a pseudo resonable way that is easy to debug.
+ * Returning a malloced buffer without the copy may cause
+ * indeterministic behavior.
+ */
+ return(NULL);
+ }
+
+ mutex = &malloc_mutex;
+ pthread_mutex_lock(mutex);
+ onb = 1L << (i + 3);
+ if (onb < pagesz)
+ onb -= sizeof (*op) + RSLOP;
+ else
+ onb += pagesz - sizeof (*op) - RSLOP;
+
+ /* avoid the copy if same size block */
+ if (i) {
+ i = 1L << (i + 2);
+ if (i < pagesz)
+ i -= sizeof (*op) + RSLOP;
+ else
+ i += pagesz - sizeof (*op) - RSLOP;
+ }
+
+ if (nbytes <= onb && nbytes > i) {
+#ifdef RCHECK
+ op->ov_size = (nbytes + RSLOP - 1) & ~(RSLOP - 1);
+ *(u_short *)((caddr_t)(op + 1) + op->ov_size) = RMAGIC;
+#endif
+ pthread_mutex_unlock(mutex);
+ return(cp);
+ }
+ pthread_mutex_unlock(mutex);
+
+ if ((res = malloc(nbytes)) == NULL) {
+ free(cp);
+ return (NULL);
+ }
+
+ memcpy(res, cp, (nbytes < onb) ? nbytes : onb);
+ free(cp);
+
+ return (res);
+}
+
+/* ==========================================================================
+ * calloc()
+ *
+ * Added to ensure pthread's allocation is used (mevans).
+ */
+void *calloc(size_t nmemb, size_t size)
+{
+ void *p;
+ size *= nmemb;
+ p = malloc(size);
+ if (p) memset(p, 0, size);
+ return (p);
+}
diff --git a/mit-pthreads/pthreads/mutex.c b/mit-pthreads/pthreads/mutex.c
new file mode 100644
index 00000000000..1a2ca6fa1c1
--- /dev/null
+++ b/mit-pthreads/pthreads/mutex.c
@@ -0,0 +1,371 @@
+/* ==== mutex.c ==============================================================
+ * Copyright (c) 1993, 1994 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Description : Mutex functions.
+ *
+ * 1.00 93/07/19 proven
+ * -Started coding this file.
+ */
+
+#ifndef lint
+static const char rcsid[] = "$Id$";
+#endif
+
+#include <pthread.h>
+#include <stdlib.h>
+#include <errno.h>
+
+/* ==========================================================================
+ * pthread_mutex_is_debug()
+ *
+ * Check that mutex is a debug mutex and if so returns entry number into
+ * array of debug mutexes.
+ */
+static int pthread_mutex_debug_count = 0;
+static pthread_mutex_t ** pthread_mutex_debug_ptrs = NULL;
+
+static inline int pthread_mutex_is_debug(pthread_mutex_t * mutex)
+{
+ int i;
+
+ for (i = 0; i < pthread_mutex_debug_count; i++) {
+ if (pthread_mutex_debug_ptrs[i] == mutex) {
+ return(i);
+ }
+ }
+ return(NOTOK);
+}
+
+/* ==========================================================================
+ * pthread_mutex_init()
+ *
+ * In this implementation I don't need to allocate memory.
+ * ENOMEM, EAGAIN should never be returned. Arch that have
+ * weird constraints may need special coding.
+ */
+int pthread_mutex_init(pthread_mutex_t *mutex,
+ const pthread_mutexattr_t *mutex_attr)
+{
+ enum pthread_mutextype type;
+
+ /* Only check if attr specifies some mutex type other than fast */
+ if ((mutex_attr) && (mutex_attr->m_type != MUTEX_TYPE_FAST)) {
+ if (mutex_attr->m_type >= MUTEX_TYPE_MAX) {
+ return(EINVAL);
+ }
+ type = mutex_attr->m_type;
+ } else {
+ type = MUTEX_TYPE_FAST;
+ }
+ mutex->m_flags = 0;
+
+ pthread_sched_prevent();
+
+ switch(type) {
+ case MUTEX_TYPE_FAST:
+ break;
+ case MUTEX_TYPE_STATIC_FAST:
+ pthread_sched_resume();
+ return(EINVAL);
+ break;
+ case MUTEX_TYPE_COUNTING_FAST:
+ mutex->m_data.m_count = 0;
+ break;
+ case MUTEX_TYPE_DEBUG:
+ if (pthread_mutex_is_debug(mutex) == NOTOK) {
+ pthread_mutex_t ** new;
+
+ if ((new = (pthread_mutex_t **)realloc(pthread_mutex_debug_ptrs,
+ (pthread_mutex_debug_count + 1) * (sizeof(void *)))) == NULL) {
+ pthread_sched_resume();
+ return(ENOMEM);
+ }
+ pthread_mutex_debug_ptrs = new;
+ pthread_mutex_debug_ptrs[pthread_mutex_debug_count++] = mutex;
+ } else {
+ pthread_sched_resume();
+ return(EBUSY);
+ }
+ break;
+ default:
+ pthread_sched_resume();
+ return(EINVAL);
+ break;
+ }
+ /* Set all other paramaters */
+ pthread_queue_init(&mutex->m_queue);
+ mutex->m_flags |= MUTEX_FLAGS_INITED;
+ mutex->m_owner = NULL;
+ mutex->m_type = type;
+
+ pthread_sched_resume();
+ return(OK);
+}
+
+/* ==========================================================================
+ * pthread_mutex_destroy()
+ */
+int pthread_mutex_destroy(pthread_mutex_t *mutex)
+{
+ int i;
+
+ pthread_sched_prevent();
+
+ /* Only check if mutex is of type other than fast */
+ switch(mutex->m_type) {
+ case MUTEX_TYPE_FAST:
+ break;
+ case MUTEX_TYPE_STATIC_FAST:
+ pthread_sched_resume();
+ return(EINVAL);
+ break;
+ case MUTEX_TYPE_COUNTING_FAST:
+ mutex->m_data.m_count = 0;
+ break;
+ case MUTEX_TYPE_DEBUG:
+ if ((i = pthread_mutex_is_debug(mutex)) == NOTOK) {
+ pthread_sched_resume();
+ return(EINVAL);
+ }
+ if (mutex->m_owner) {
+ pthread_sched_resume();
+ return(EBUSY);
+ }
+
+ /* Remove the mutex from the list of debug mutexes */
+ pthread_mutex_debug_ptrs[i] =
+ pthread_mutex_debug_ptrs[--pthread_mutex_debug_count];
+ pthread_mutex_debug_ptrs[pthread_mutex_debug_count] = NULL;
+ break;
+ default:
+ pthread_sched_resume();
+ return(EINVAL);
+ break;
+ }
+
+ /* Cleanup mutex, others might want to use it. */
+ pthread_queue_init(&mutex->m_queue);
+ mutex->m_owner = NULL;
+ mutex->m_flags = 0;
+
+ pthread_sched_resume();
+ return(OK);
+}
+
+/* ==========================================================================
+ * pthread_mutex_trylock()
+ */
+int pthread_mutex_trylock(pthread_mutex_t *mutex)
+{
+ int rval;
+
+ pthread_sched_prevent();
+ switch (mutex->m_type) {
+ /*
+ * Fast mutexes do not check for any error conditions.
+ */
+ case MUTEX_TYPE_FAST:
+ case MUTEX_TYPE_STATIC_FAST:
+ if (!mutex->m_owner) {
+ mutex->m_owner = pthread_run;
+ rval = OK;
+ } else {
+ rval = EBUSY;
+ }
+ break;
+ case MUTEX_TYPE_COUNTING_FAST:
+ if (mutex->m_owner) {
+ if (mutex->m_owner == pthread_run) {
+ mutex->m_data.m_count++;
+ rval = OK;
+ } else {
+ rval = EBUSY;
+ }
+ } else {
+ mutex->m_owner = pthread_run;
+ rval = OK;
+ }
+ break;
+ case MUTEX_TYPE_DEBUG:
+ if (pthread_mutex_is_debug(mutex) != NOTOK) {
+ if (!mutex->m_owner) {
+ mutex->m_owner = pthread_run;
+ rval = OK;
+ } else {
+ rval = EBUSY;
+ }
+ } else {
+ rval = EINVAL;
+ }
+ break;
+ default:
+ rval = EINVAL;
+ break;
+ }
+
+ pthread_sched_resume();
+ return(rval);
+}
+
+/* ==========================================================================
+ * pthread_mutex_lock()
+ */
+int pthread_mutex_lock(pthread_mutex_t *mutex)
+{
+ int rval;
+
+ pthread_sched_prevent();
+ switch (mutex->m_type) {
+ /*
+ * Fast mutexes do not check for any error conditions.
+ */
+ case MUTEX_TYPE_FAST:
+ case MUTEX_TYPE_STATIC_FAST:
+ if (mutex->m_owner) {
+ pthread_queue_enq(&mutex->m_queue, pthread_run);
+
+ /* Reschedule will unlock scheduler */
+ pthread_resched_resume(PS_MUTEX_WAIT);
+ return(OK);
+ }
+ mutex->m_owner = pthread_run;
+ rval = OK;
+ break;
+ case MUTEX_TYPE_COUNTING_FAST:
+ if (mutex->m_owner) {
+ if (mutex->m_owner != pthread_run) {
+ pthread_queue_enq(&mutex->m_queue, pthread_run);
+
+ /* Reschedule will unlock scheduler */
+ pthread_resched_resume(PS_MUTEX_WAIT);
+ return(OK);
+ } else {
+ mutex->m_data.m_count++;
+ }
+ } else {
+ mutex->m_owner = pthread_run;
+ }
+ rval = OK;
+ break;
+ case MUTEX_TYPE_DEBUG:
+ if (pthread_mutex_is_debug(mutex) != NOTOK) {
+ if (mutex->m_owner) {
+ if (mutex->m_owner != pthread_run) {
+ pthread_queue_enq(&mutex->m_queue, pthread_run);
+
+ /* Reschedule will unlock pthread_run */
+ pthread_resched_resume(PS_MUTEX_WAIT);
+
+ if (mutex->m_owner != pthread_run) {
+ PANIC();
+ }
+ return(OK);
+ }
+ rval = EDEADLK;
+ break;
+ }
+ mutex->m_owner = pthread_run;
+ rval = OK;
+ break;
+ }
+ rval = EINVAL;
+ break;
+ default:
+ rval = EINVAL;
+ break;
+ }
+
+ pthread_sched_resume();
+ return(rval);
+}
+
+/* ==========================================================================
+ * pthread_mutex_unlock()
+ */
+int pthread_mutex_unlock(pthread_mutex_t *mutex)
+{
+ struct pthread *pthread;
+ int rval;
+
+ pthread_sched_prevent();
+
+ switch (mutex->m_type) {
+ /*
+ * Fast mutexes do not check for any error conditions.
+ */
+ case MUTEX_TYPE_FAST:
+ case MUTEX_TYPE_STATIC_FAST:
+ if (mutex->m_owner = pthread_queue_deq(&mutex->m_queue)) {
+
+ /* Reschedule will unlock scheduler */
+ pthread_sched_other_resume(mutex->m_owner);
+ return(OK);
+ }
+ rval = OK;
+ break;
+ case MUTEX_TYPE_COUNTING_FAST:
+ if (mutex->m_data.m_count) {
+ mutex->m_data.m_count--;
+ rval = OK;
+ break;
+ }
+ if (mutex->m_owner = pthread_queue_deq(&mutex->m_queue)) {
+
+ /* Reschedule will unlock scheduler */
+ pthread_sched_other_resume(mutex->m_owner);
+ return(OK);
+ }
+ rval = OK;
+ break;
+ case MUTEX_TYPE_DEBUG:
+ if (pthread_mutex_is_debug(mutex) != NOTOK) {
+ if (mutex->m_owner == pthread_run) {
+ if (mutex->m_owner = pthread_queue_deq(&mutex->m_queue)) {
+
+ /* Reschedule will unlock scheduler */
+ pthread_sched_other_resume(mutex->m_owner);
+ return(OK);
+ }
+ rval = OK;
+ } else {
+ rval = EPERM;
+ }
+ } else {
+ rval = EINVAL;
+ }
+ break;
+ default:
+ rval = EINVAL;
+ break;
+ }
+ pthread_sched_resume();
+ return(rval);
+}
diff --git a/mit-pthreads/pthreads/mutexattr.c b/mit-pthreads/pthreads/mutexattr.c
new file mode 100644
index 00000000000..d045b5041a0
--- /dev/null
+++ b/mit-pthreads/pthreads/mutexattr.c
@@ -0,0 +1,90 @@
+/* ==== mutexattr.c ===========================================================
+ * Copyright (c) 1993, 1994 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Description : Mutex functions.
+ *
+ * 1.00 93/07/19 proven
+ * -Started coding this file.
+ */
+
+#ifndef lint
+static const char rcsid[] = "$Id$";
+#endif
+
+#include <pthread.h>
+#include <errno.h>
+
+/* ==========================================================================
+ * pthread_mutexattr_init()
+ */
+int pthread_mutexattr_init(pthread_mutexattr_t *attr)
+{
+ attr->m_type = MUTEX_TYPE_FAST;
+ return(OK);
+}
+
+/* ==========================================================================
+ * pthread_mutexattr_destroy()
+ */
+int pthread_mutexattr_destroy(pthread_mutexattr_t *attr)
+{
+ return(OK);
+}
+
+/* ==========================================================================
+ * pthread_mutexattr_settype()
+ */
+int pthread_mutexattr_settype(pthread_mutexattr_t *attr, unsigned int type)
+{
+ switch(type) {
+ case PTHREAD_MUTEXTYPE_FAST:
+ attr->m_type = MUTEX_TYPE_FAST;
+ break;
+ case PTHREAD_MUTEXTYPE_RECURSIVE:
+ attr->m_type = MUTEX_TYPE_COUNTING_FAST;
+ break;
+ case PTHREAD_MUTEXTYPE_DEBUG:
+ attr->m_type = MUTEX_TYPE_DEBUG;
+ break;
+ default:
+ return(EINVAL);
+ }
+ return(OK);
+}
+
+/* ==========================================================================
+ * pthread_mutexattr_gettype()
+ */
+int pthread_mutexattr_gettype(pthread_mutexattr_t *attr, unsigned int * type)
+{
+ *type = (unsigned int)attr->m_type;
+ return(OK);
+}
diff --git a/mit-pthreads/pthreads/panic.c b/mit-pthreads/pthreads/panic.c
new file mode 100644
index 00000000000..6b963acd651
--- /dev/null
+++ b/mit-pthreads/pthreads/panic.c
@@ -0,0 +1,58 @@
+/* ==== panic.c =======================================================
+ * Copyright (c) 1996 by Larry V. Streepy, Jr.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Larry V. Streepy, Jr.
+ * 4. The name of Larry V. Streepy, Jr. may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Larry V. Streepy, Jr. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL Larry V. Streepy, Jr. BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Description : pthread kernel panic
+ *
+ * 02 Oct 1996 - Larry V. Streepy, Jr.
+ * - Initial coding
+ */
+
+#include <pthread.h>
+#include <stdio.h>
+/*----------------------------------------------------------------------
+ * Function: panic_kernel
+ * Purpose: print a message and panic the pthreads kernel
+ * Args: file name, line number, and function
+ * Returns: doesn't
+ * Notes:
+ *----------------------------------------------------------------------*/ void
+panic_kernel( const char *file, unsigned int line, const char *func )
+{
+#ifdef __GNUC__
+ (void) fprintf( stderr, "%s:%u: %s%sPhtreads kernel panic.\n",
+ file, line, func ? func : "", func ? ": " : "" );
+ (void) fflush (stderr);
+#else
+ (void) fprintf( stderr, "%s:%u: Phtreads kernel panic.\n", file, line );
+ (void) fflush (stderr);
+#endif
+ abort();
+}
diff --git a/mit-pthreads/pthreads/prio_queue.c b/mit-pthreads/pthreads/prio_queue.c
new file mode 100644
index 00000000000..d976f9cd68f
--- /dev/null
+++ b/mit-pthreads/pthreads/prio_queue.c
@@ -0,0 +1,176 @@
+/* ==== prio_queue.c ==========================================================
+ * Copyright (c) 1994 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Description : Priority Queue functions.
+ *
+ * 1.00 94/09/19 proven
+ * -Started coding this file.
+ */
+
+#ifndef lint
+static const char rcsid[] = "$Id$";
+#endif
+
+#include <pthread.h>
+
+/* A thread when it becomes eligeble to run is placed on the run queue.
+ This requires locking the kernel lock
+*/
+
+/* ==========================================================================
+ * pthread_prio_queue_init()
+ */
+void pthread_prio_queue_init(struct pthread_prio_queue * queue)
+{
+ int i;
+
+ for (i = 0; i <= PTHREAD_MAX_PRIORITY; i++) {
+ queue->level[i].first = NULL;
+ queue->level[i].last = NULL;
+ }
+ queue->next = NULL;
+ queue->data = NULL;
+}
+
+/* ==========================================================================
+ * pthread_priority_enq()
+ */
+void pthread_prio_queue_enq(struct pthread_prio_queue * queue,
+ struct pthread * pthread)
+{
+ int priority = pthread->pthread_priority;
+
+ if (queue->next) {
+ if (queue->level[priority].first) {
+ pthread->next = (queue->level[priority].last)->next;
+ (queue->level[priority].last)->next = pthread;
+ queue->level[priority].last = pthread;
+ return;
+ }
+ if (priority != PTHREAD_MAX_PRIORITY) {
+ int prev_priority;
+ /* Find first higher priority thread queued on queue */
+ for (prev_priority = priority + 1; prev_priority <=
+ PTHREAD_MAX_PRIORITY; prev_priority++) {
+ if (queue->level[prev_priority].first) {
+ pthread->next = (queue->level[prev_priority].last)->next;
+ (queue->level[prev_priority].last)->next = pthread;
+ queue->level[priority].first = pthread;
+ queue->level[priority].last = pthread;
+ return;
+ }
+ }
+ }
+ }
+ queue->level[priority].first = pthread;
+ queue->level[priority].last = pthread;
+ pthread->next = queue->next;
+ queue->next = pthread;
+}
+
+/* ==========================================================================
+ * pthread_prio_queue_deq()
+ */
+struct pthread * pthread_prio_queue_deq(struct pthread_prio_queue * queue)
+{
+ struct pthread * pthread;
+ int priority;
+
+ if (pthread = queue->next) {
+ priority = queue->next->pthread_priority;
+ if (queue->level[priority].first == queue->level[priority].last) {
+ queue->level[priority].first = NULL;
+ queue->level[priority].last = NULL;
+ } else {
+ queue->level[priority].first = pthread->next;
+ }
+ queue->next = pthread->next;
+ pthread->next = NULL;
+ }
+ return(pthread);
+}
+
+/* ==========================================================================
+ * pthread_prio_queue_remove()
+ */
+int pthread_prio_queue_remove(struct pthread_prio_queue *queue,
+ struct pthread *thread)
+{
+ /* XXX This is slow, should start with thread priority */
+ int priority = thread->pthread_priority;
+ struct pthread **current = &(queue->level[priority].first);
+ struct pthread *prev = NULL;
+
+ if (thread==*current) {
+ int current_priority=priority+1;
+
+ if (*current == queue->next){
+ pthread_prio_queue_deq(queue);
+ thread->next = NULL;
+ return(OK);
+ }
+ for (current_priority; current_priority <= PTHREAD_MAX_PRIORITY;
+ current_priority++) {
+ if (queue->level[current_priority].last) {
+ queue->level[current_priority].last->next = (*current)->next;
+ if ((*current)->next &&
+ (*current)->next->pthread_priority == priority)
+ queue->level[priority].first = (*current)->next;
+ else {
+ queue->level[priority].first = NULL;
+ queue->level[priority].last = NULL;
+ }
+ thread->next = NULL;
+ return(OK);
+ }
+ }
+ }
+
+ if (*current == NULL) /* Mati Sauks */
+ {
+ return (NOTOK);
+ }
+ for (prev=*current,current=&((*current)->next);
+ *current && ((*current)->pthread_priority == priority);
+ prev=*current,current=&((*current)->next)) {
+ if (*current == thread) {
+ if (*current == queue->level[priority].last) {
+ queue->level[priority].last = prev;
+ }
+
+ *current = (*current)->next;
+ thread->next=NULL;
+ return(OK);
+ }
+ }
+ return(NOTOK);
+}
+
diff --git a/mit-pthreads/pthreads/process.c b/mit-pthreads/pthreads/process.c
new file mode 100644
index 00000000000..9b3abb3384b
--- /dev/null
+++ b/mit-pthreads/pthreads/process.c
@@ -0,0 +1,208 @@
+/* ==== process.c ============================================================
+ * Copyright (c) 1994 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Description : Process functions (fork, exec, ...).
+ *
+ * 1.23 94/04/18 proven
+ * -Started coding this file.
+ */
+
+#include <pthread.h>
+#include <sys/types.h>
+#include <pthread.h>
+#include <stdarg.h>
+#include <unistd.h>
+#ifdef HAVE_ALLOC_H
+#include <alloc.h>
+#endif
+
+extern void *alloca();
+
+#ifndef lint
+static const char rcsid[] = "$Id$";
+#endif
+
+/* ==========================================================================
+ * fork()
+ *
+ * This function requires a sig_prevent()/sig_check_and_resume() for the
+ * parent. The child never unlocks.
+ */
+pid_t fork()
+{
+ pid_t ret;
+
+ pthread_sched_prevent();
+
+ fd_kern_fork();
+ if (ret = machdep_sys_fork()) { /* Parent or error */
+ pthread_sched_resume();
+ } else { /* Child */
+ machdep_unset_thread_timer(NULL);
+ machdep_stop_timer(NULL);
+ fork_lock++;
+ pthread_kernel_lock--;
+ }
+ return(ret);
+}
+
+#ifdef HAVE_VFORK
+/* The semantics of vfork probably won't mix well with the pthread
+ library code. Don't even try. */
+pid_t vfork ()
+{
+ return fork ();
+}
+#endif
+
+/* ==========================================================================
+ * execve()
+ *
+ * This function requires a sig_prevent()/sig_check_and_resume() if one
+ * hasn't been done in the fork routine. Normally machdep_sys_execve()
+ * should never return.
+ */
+int execve(const char *name, char * const *argv, char * const *envp)
+{
+ int ret;
+
+ if (!fork_lock) {
+ pthread_sched_prevent();
+ fd_kern_exec(0);
+ ret = machdep_sys_execve(name, argv, envp);
+ pthread_sched_resume();
+ } else {
+ fd_kern_exec(1);
+ ret = machdep_sys_execve(name, argv, envp);
+ }
+ return(ret);
+}
+
+/* Variants of execve. Define them here so that the system versions
+ don't get used and drag in the system version of execve. */
+#include <sys/stat.h>
+#include <string.h>
+#include <sys/param.h>
+extern char **environ;
+
+static const char *find (const char *name, char *buf)
+{
+ char *p1, *p2;
+ extern char *getenv ();
+ struct stat sb;
+
+ if (strchr (name, '/'))
+ return name;
+ p1 = getenv ("PATH");
+ if (p1 == 0)
+ p1 = "/bin:/usr/bin:";
+ while (*p1) {
+ memset (buf, 0, MAXPATHLEN);
+ p2 = strchr (p1, ':');
+ if (p2 == 0)
+ p2 = p1 + strlen (p1);
+ strncpy (buf, p1, p2 - p1);
+ buf[p2 - p1] = 0;
+ strcat (buf, "/");
+ strcat (buf, name);
+ if (lstat (buf, &sb) == 0)
+ return buf;
+
+ if (*p2 == ':')
+ p2++;
+ p1 = p2;
+ }
+ return name;
+}
+
+int execl (const char *path, const char *arg, ...)
+{
+#ifdef SCO_3_5
+ return execve (path, (char *const *) &arg, environ);
+#else
+ char ** argv;
+ va_list ap;
+ int i;
+
+ va_start(ap, arg);
+ for (i = 1; va_arg(ap, char *) != NULL; i++);
+ va_end(ap);
+
+ argv = alloca (i * sizeof (char *));
+
+ va_start(ap, arg);
+ argv[0] = (char *) arg;
+ for (i = 1; (argv[i] = (char *) va_arg(ap, char *)) != NULL; i++);
+ va_end(ap);
+
+ return execve (path, argv, environ);
+#endif
+}
+
+int execlp (const char *name, const char *arg, ...)
+{
+#ifdef SCO_3_5
+ char buf[MAXPATHLEN];
+ return execve (find (name, buf), (char *const *) &arg, environ);
+#else
+ char buf[MAXPATHLEN];
+ char ** argv;
+ va_list ap;
+ int i;
+
+ va_start(ap, arg);
+ for (i = 1; va_arg(ap, char *) != NULL; i++);
+ va_end(ap);
+
+ argv = alloca (i * sizeof (char *));
+
+ va_start(ap, arg);
+ argv[0] = (char *) arg;
+ for (i = 1; (argv[i] = (char *) va_arg(ap, char *)) != NULL; i++);
+ va_end(ap);
+
+ return execve (find (name, buf), argv, environ);
+#endif
+}
+
+int execle (const char *name, const char *arg, ... /* , char *const envp[] */);
+
+/* This one turns on ptrace-style tracing? */
+int exect (const char *path, char *const argv[], char *const envp[]);
+
+int execv (const char *path, char *const argv[]) {
+ return execve (path, argv, environ);
+}
+
+int execvp (const char *name, char *const argv[]) {
+ char buf[MAXPATHLEN];
+ return execve (find (name, buf), argv, environ);
+}
diff --git a/mit-pthreads/pthreads/pthread.c b/mit-pthreads/pthreads/pthread.c
new file mode 100644
index 00000000000..6f7e2d53980
--- /dev/null
+++ b/mit-pthreads/pthreads/pthread.c
@@ -0,0 +1,293 @@
+/* ==== pthread.c ============================================================
+ * Copyright (c) 1993, 1994 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Description : Pthread functions.
+ *
+ * 1.00 93/07/26 proven
+ * -Started coding this file.
+ */
+
+#ifndef lint
+static const char rcsid[] = "$Id$";
+#endif
+
+#include <pthread.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <errno.h>
+#include <string.h>
+#include <sched.h>
+
+/* ==========================================================================
+ * sched_yield()
+ */
+int sched_yield()
+{
+ sig_handler_fake(SIGVTALRM);
+ return(OK);
+}
+
+/* ==========================================================================
+ * pthread_yield()
+ */
+void pthread_yield()
+{
+ sig_handler_fake(SIGVTALRM);
+}
+
+/* ==========================================================================
+ * pthread_self()
+ */
+pthread_t pthread_self()
+{
+ return(pthread_run);
+}
+
+/* ==========================================================================
+ * pthread_equal()
+ */
+int pthread_equal(pthread_t t1, pthread_t t2)
+{
+ return(t1 == t2);
+}
+
+/* ==========================================================================
+ * pthread_exit()
+ */
+extern void pthread_cleanupspecific(void);
+
+void pthread_exit(void *status)
+{
+ pthread_t pthread;
+
+ /* Save return value */
+ pthread_run->ret = status;
+
+ /* First execute all cleanup handlers */
+ while (pthread_run->cleanup) {
+ pthread_cleanup_pop(1);
+ }
+
+ /* Don't forget the cleanup attr */
+ if (pthread_run->attr.cleanup_attr) {
+ pthread_run->attr.cleanup_attr(pthread_run->attr.arg_attr);
+ }
+
+ /* Next run thread-specific data desctructors */
+ if (pthread_run->specific_data) {
+ pthread_cleanupspecific();
+ }
+
+ pthread_sched_prevent();
+
+ if (!(pthread_run->attr.flags & PTHREAD_DETACHED)) {
+ /*
+ * Are there any threads joined to this one,
+ * if so wake them and let them detach this thread.
+ */
+ while (pthread = pthread_queue_deq(&(pthread_run->join_queue))) {
+ pthread_prio_queue_enq(pthread_current_prio_queue, pthread);
+ pthread->state = PS_RUNNING;
+ }
+ pthread_queue_enq(&pthread_dead_queue, pthread_run);
+ pthread_resched_resume(PS_DEAD);
+ } else {
+ pthread_queue_enq(&pthread_alloc_queue, pthread_run);
+ pthread_resched_resume(PS_UNALLOCED);
+ }
+
+ /* This thread will never run again */
+ PANIC();
+
+}
+
+/*----------------------------------------------------------------------
+ * Function: __pthread_is_valid
+ * Purpose: Scan the list of threads to see if a specified thread exists
+ * Args:
+ * pthread = The thread to scan for
+ * Returns:
+ * int = 1 if found, 0 if not
+ * Notes:
+ * The kernel is assumed to be locked
+ *----------------------------------------------------------------------*/
+int
+__pthread_is_valid( pthread_t pthread )
+{
+ int rtn = 0; /* Assume not found */
+ pthread_t t;
+
+ for( t = pthread_link_list; t; t = t->pll ) {
+ if( t == pthread ) {
+ rtn = 1; /* Found it */
+ break;
+ }
+ }
+
+ return rtn;
+}
+
+/* ==========================================================================
+ * __pthread_free()
+ */
+static inline void __pthread_free(pthread_t new_thread)
+{
+ pthread_sched_prevent();
+ new_thread->state = PS_UNALLOCED;
+ new_thread->attr.stacksize_attr = 0;
+ new_thread->attr.stackaddr_attr = NULL;
+ pthread_queue_enq(&pthread_alloc_queue, new_thread);
+ pthread_sched_resume();
+}
+/* ==========================================================================
+ * __pthread_alloc()
+ */
+/* static inline pthread_t __pthread_alloc(const pthread_attr_t *attr) */
+static pthread_t __pthread_alloc(const pthread_attr_t *attr)
+{
+ pthread_t thread;
+ void * stack;
+ void * old;
+
+ pthread_sched_prevent();
+ thread = pthread_queue_deq(&pthread_alloc_queue);
+ pthread_sched_resume();
+
+ if (thread) {
+ if (stack = attr->stackaddr_attr) {
+ __machdep_stack_repl(&(thread->machdep_data), stack);
+ } else {
+ if ((__machdep_stack_get(&(thread->machdep_data)) == NULL)
+ || (attr->stacksize_attr > thread->attr.stacksize_attr)) {
+ if (stack = __machdep_stack_alloc(attr->stacksize_attr)) {
+ __machdep_stack_repl(&(thread->machdep_data), stack);
+ } else {
+ __pthread_free(thread);
+ thread = NULL;
+ }
+ }
+ }
+ } else {
+ /* We should probable allocate several for efficiency */
+ if (thread = (pthread_t)malloc(sizeof(struct pthread))) {
+ /* Link new thread into list of all threads */
+
+ pthread_sched_prevent();
+ thread->state = PS_UNALLOCED;
+ thread->pll = pthread_link_list;
+ pthread_link_list = thread;
+ pthread_sched_resume();
+
+ if ((stack = attr->stackaddr_attr) ||
+ (stack = __machdep_stack_alloc(attr->stacksize_attr))) {
+ __machdep_stack_set(&(thread->machdep_data), stack);
+ } else {
+ __machdep_stack_set(&(thread->machdep_data), NULL);
+ __pthread_free(thread);
+ thread = NULL;
+ }
+ }
+ }
+ return(thread);
+}
+
+/* ==========================================================================
+ * pthread_create()
+ *
+ * After the new thread structure is allocated and set up, it is added to
+ * pthread_run_next_queue, which requires a sig_prevent(),
+ * sig_check_and_resume()
+ */
+int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
+ void * (*start_routine)(void *), void *arg)
+{
+ pthread_t new_thread;
+ int nsec = 100000000;
+ int retval = OK;
+
+ if (! attr)
+ attr = &pthread_attr_default;
+
+ if (new_thread = __pthread_alloc(attr)) {
+
+ __machdep_pthread_create(&(new_thread->machdep_data),
+ start_routine, arg, attr->stacksize_attr, nsec, 0);
+
+ memcpy(&new_thread->attr, attr, sizeof(pthread_attr_t));
+ if (new_thread->attr.flags & PTHREAD_INHERIT_SCHED) {
+ new_thread->pthread_priority = pthread_run->pthread_priority;
+ new_thread->attr.sched_priority = pthread_run->pthread_priority;
+ new_thread->attr.schedparam_policy =
+ pthread_run->attr.schedparam_policy;
+ } else {
+ new_thread->pthread_priority = new_thread->attr.sched_priority;
+ }
+
+ if (!(new_thread->attr.flags & PTHREAD_NOFLOAT)) {
+ machdep_save_float_state(new_thread);
+ }
+
+ /* Initialize signalmask */
+ new_thread->sigmask = pthread_run->sigmask;
+ sigemptyset(&(new_thread->sigpending));
+ new_thread->sigcount = 0;
+
+ pthread_queue_init(&(new_thread->join_queue));
+ new_thread->specific_data = NULL;
+ new_thread->specific_data_count = 0;
+ new_thread->cleanup = NULL;
+ new_thread->queue = NULL;
+ new_thread->next = NULL;
+ new_thread->flags = 0;
+
+ /* PTHREADS spec says we start with cancellability on and deferred */
+ SET_PF_CANCEL_STATE(new_thread, PTHREAD_CANCEL_ENABLE);
+ SET_PF_CANCEL_TYPE(new_thread, PTHREAD_CANCEL_DEFERRED);
+
+ new_thread->error_p = NULL;
+ new_thread->sll = NULL;
+
+ pthread_sched_prevent();
+
+
+ pthread_sched_other_resume(new_thread);
+ /*
+ * Assignment must be outside of the locked pthread kernel incase
+ * thread is a bogus address resulting in a seg-fault. We want the
+ * original thread to be capable of handling the resulting signal.
+ * --proven
+ */
+ (*thread) = new_thread;
+ } else {
+ retval = EAGAIN;
+ }
+ return(retval);
+}
diff --git a/mit-pthreads/pthreads/pthread_attr.c b/mit-pthreads/pthreads/pthread_attr.c
new file mode 100644
index 00000000000..5e1c0302227
--- /dev/null
+++ b/mit-pthreads/pthreads/pthread_attr.c
@@ -0,0 +1,255 @@
+/* ==== pthread_attr.c =======================================================
+ * Copyright (c) 1993, 1994 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Description : Pthread attribute functions.
+ *
+ * 1.00 93/11/04 proven
+ * -Started coding this file.
+ */
+
+#ifndef lint
+static const char rcsid[] = "$Id$";
+#endif
+
+#include <pthread.h>
+#include <errno.h>
+#include <string.h>
+
+/* Currently we do no locking, should we just to be safe? CAP */
+/* ==========================================================================
+ * pthread_attr_init()
+ */
+int pthread_attr_init(pthread_attr_t *attr)
+{
+ memcpy(attr, &pthread_attr_default, sizeof(pthread_attr_t));
+ return(OK);
+}
+
+/* ==========================================================================
+ * pthread_attr_destroy()
+ */
+int pthread_attr_destroy(pthread_attr_t *attr)
+{
+ return(OK);
+}
+
+/* ==========================================================================
+ * pthread_attr_getstacksize()
+ */
+int pthread_attr_getstacksize(pthread_attr_t *attr, size_t * stacksize)
+{
+ *stacksize = attr->stacksize_attr;
+ return(OK);
+}
+
+/* ==========================================================================
+ * pthread_attr_setstacksize()
+ */
+int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize)
+{
+ if (stacksize >= PTHREAD_STACK_MIN) {
+ attr->stacksize_attr = stacksize;
+ return(OK);
+ }
+ return(EINVAL);
+}
+
+/* ==========================================================================
+ * pthread_attr_getstackaddr()
+ */
+int pthread_attr_getstackaddr(pthread_attr_t *attr, void ** stackaddr)
+{
+ *stackaddr = attr->stackaddr_attr;
+ return(OK);
+}
+
+/* ==========================================================================
+ * pthread_attr_setstackaddr()
+ */
+int pthread_attr_setstackaddr(pthread_attr_t *attr, void * stackaddr)
+{
+ attr->stackaddr_attr = stackaddr;
+ return(OK);
+}
+
+/* ==========================================================================
+ * pthread_attr_setcleanup()
+ */
+int pthread_attr_setcleanup(pthread_attr_t *attr, void (*routine)(void *),
+ void * arg)
+{
+ attr->cleanup_attr = routine;
+ attr->arg_attr = arg;
+ return(OK);
+}
+
+/* ==========================================================================
+ * pthread_attr_getdetachstate()
+ */
+int pthread_attr_getdetachstate(pthread_attr_t *attr, int * detachstate)
+{
+ *detachstate = attr->flags & PTHREAD_DETACHED;
+ return(OK);
+}
+
+/* ==========================================================================
+ * pthread_attr_setdetachstate()
+ */
+int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate)
+{
+ attr->flags = (attr->flags & ~(PTHREAD_DETACHED)) |
+ (detachstate & PTHREAD_DETACHED);
+ return(OK);
+}
+
+/* ==========================================================================
+ * pthread_attr_getfloatstate()
+ */
+int pthread_attr_getfloatstate(pthread_attr_t *attr, int * floatstate)
+{
+ *floatstate = attr->flags & PTHREAD_NOFLOAT;
+ return(OK);
+}
+
+/* ==========================================================================
+ * pthread_attr_setfloatstate()
+ */
+int pthread_attr_setfloatstate(pthread_attr_t *attr, int floatstate)
+{
+ attr->flags = (attr->flags & ~(PTHREAD_NOFLOAT)) |
+ (floatstate & PTHREAD_NOFLOAT);
+ return(OK);
+}
+
+/* ==========================================================================
+ * pthread_attr_getscope()
+ */
+int pthread_attr_getscope(pthread_attr_t *attr, int * contentionscope)
+{
+ *contentionscope = attr->flags & PTHREAD_SCOPE_SYSTEM;
+ return(OK);
+}
+
+/* ==========================================================================
+ * pthread_attr_setscope()
+ */
+int pthread_attr_setscope(pthread_attr_t *attr, int contentionscope)
+{
+ int ret;
+
+ switch (contentionscope) {
+ case PTHREAD_SCOPE_PROCESS:
+ attr->flags = (attr->flags & ~(PTHREAD_SCOPE_PROCESS))
+ | PTHREAD_SCOPE_PROCESS;
+ ret = OK;
+ break;
+ case PTHREAD_SCOPE_SYSTEM:
+ ret = ENOSYS;
+ break;
+ default:
+ ret = EINVAL;
+ break;
+ }
+
+ return(ret);
+}
+
+/* ==========================================================================
+ * pthread_attr_getinheritsched()
+ */
+int pthread_attr_getinheritsched(pthread_attr_t *attr, int * inheritsched)
+{
+ *inheritsched = attr->flags & PTHREAD_INHERIT_SCHED;
+ return(OK);
+}
+
+/* ==========================================================================
+ * pthread_attr_setinheritsched()
+ */
+int pthread_attr_setinheritsched(pthread_attr_t *attr, int inheritsched)
+{
+ attr->flags = (attr->flags & ~(PTHREAD_INHERIT_SCHED)) |
+ (inheritsched & PTHREAD_INHERIT_SCHED);
+ return(OK);
+}
+
+/* ==========================================================================
+ * pthread_attr_getschedpolicy()
+ */
+int pthread_attr_getschedpolicy(pthread_attr_t *attr, int * schedpolicy)
+{
+ *schedpolicy = (int)attr->schedparam_policy;
+ return(OK);
+}
+
+/* ==========================================================================
+ * pthread_attr_setschedpolicy()
+ */
+int pthread_attr_setschedpolicy(pthread_attr_t *attr, int schedpolicy)
+{
+ int ret;
+
+ switch(schedpolicy) {
+ case SCHED_FIFO:
+ case SCHED_IO:
+ case SCHED_RR:
+ attr->schedparam_policy = schedpolicy;
+ ret = OK;
+ break;
+ default:
+ ret = EINVAL;
+ break;
+ }
+ return(ret);
+}
+
+/* ==========================================================================
+ * pthread_attr_getschedparam()
+ */
+int pthread_attr_getschedparam(pthread_attr_t *attr, struct sched_param * param)
+{
+ param->sched_priority = attr->sched_priority;
+ return(OK);
+}
+
+/* ==========================================================================
+ * pthread_attr_setschedparam()
+ */
+int pthread_attr_setschedparam(pthread_attr_t *attr, struct sched_param * param)
+{
+ if ((param->sched_priority >= PTHREAD_MIN_PRIORITY) &&
+ (param->sched_priority <= PTHREAD_MAX_PRIORITY)) {
+ attr->sched_priority = param->sched_priority;
+ return(OK);
+ }
+ return(EINVAL);
+}
+
diff --git a/mit-pthreads/pthreads/pthread_cancel.c b/mit-pthreads/pthreads/pthread_cancel.c
new file mode 100644
index 00000000000..4191a269027
--- /dev/null
+++ b/mit-pthreads/pthreads/pthread_cancel.c
@@ -0,0 +1,258 @@
+/* ==== pthread_cancel.c ====================================================
+ * Copyright (c) 1996 by Larry V. Streepy, Jr.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Larry V. Streepy, Jr.
+ * 4. The name of Larry V. Streepy, Jr. may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Larry V. Streepy, Jr. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL Larry V. Streepy, Jr. BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Description : pthread_cancel operations
+ *
+ * 27 Sep 1996 - Larry V. Streepy, Jr.
+ * - Initial coding
+ */
+#ifndef lint
+static const char rcsid[] = "$Id:";
+#endif
+#include <pthread.h>
+#include <errno.h>
+static void possiblyMakeRunnable( pthread_t pthread );
+
+/*----------------------------------------------------------------------
+ * Function: pthread_cancel
+ * Purpose: Allows a thread to request that it or another thread
+ * terminate execution
+ * Args:
+ * thread = thread to mark as cancelled
+ * Returns:
+ * int 0 = ok, -1 = some error (see errno)
+ * Notes:
+ * The thread is simply marked as CANCELLED, it is up to the cancelled
+ * thread to decide how to handle it.
+ *----------------------------------------------------------------------*/ int
+pthread_cancel( pthread_t pthread )
+{
+ int rtn = 0; /* Assume all ok */
+ pthread_sched_prevent();
+ /* Ensure they gave us a legal pthread pointer */
+ if( ! __pthread_is_valid( pthread ) ) {
+ rtn = ESRCH; /* No such thread */
+ } else if( pthread->state == PS_UNALLOCED || pthread->state == PS_DEAD ) {
+ /* The standard doesn't call these out as errors, so return 0 */
+ rtn = 0;
+ } else {
+ SET_PF_CANCELLED(pthread); /* Set the flag */
+ /* If the thread is in the right state, then stick it on the
+ * run queue so it will get a chance to process the cancel.
+ */
+ if( pthread != pthread_run ) {
+ possiblyMakeRunnable( pthread );
+ }
+ }
+ pthread_sched_resume();
+ if( rtn == 0 )
+ pthread_testcancel(); /* See if we cancelled ourself */
+ return rtn;
+}
+
+/*----------------------------------------------------------------------
+ * Function: pthread_setcancelstate
+ * Purpose: Set the current thread's cancellability state
+ * Args:
+ * state = PTHREAD_CANCEL_DISABLE or PTHREAD_CANCEL_ENABLE
+ * oldstate= pointer to holder for old state or NULL (*MODIFIED*)
+ * Returns:
+ * int 0 = ok
+ * EINVAL = state is neither of the legal states
+ * Notes:
+ * This has to be async-cancel safe, so we prevent scheduling in
+ * here
+ *----------------------------------------------------------------------*/
+
+int
+pthread_setcancelstate( int newstate, int *oldstate )
+{
+ int ostate = TEST_PF_CANCEL_STATE(pthread_run);
+ int rtn = 0;
+ pthread_sched_prevent();
+ if( newstate == PTHREAD_CANCEL_ENABLE ||
+ newstate == PTHREAD_CANCEL_DISABLE ) {
+ SET_PF_CANCEL_STATE(pthread_run, newstate);
+ if( oldstate != NULL )
+ *oldstate = ostate;
+ } else { /* Invalid new state */
+ rtn = EINVAL;
+ }
+ pthread_sched_resume();
+ if( rtn == 0 ) {
+ /* Test to see if we have a pending cancel to handle */
+ pthread_testcancel();
+ }
+ return rtn;
+}
+
+/*----------------------------------------------------------------------
+ * Function: pthread_setcanceltype
+ * Purpose: Set the current thread's cancellability type
+ * Args:
+ * type = PTHREAD_CANCEL_DEFERRED or PTHREAD_CANCEL_ASYNCHRONOUS
+ * oldtype = pointer to holder for old type or NULL (*MODIFIED*)
+ * Returns:
+ * int 0 = ok
+ * EINVAL = type is neither of the legal states
+ * Notes:
+ * This has to be async-cancel safe, so we prevent scheduling in
+ * here
+ *----------------------------------------------------------------------*/
+
+int
+pthread_setcanceltype( int newtype, int *oldtype )
+{
+ int otype = TEST_PF_CANCEL_TYPE(pthread_run);
+ int rtn = 0;
+ pthread_sched_prevent();
+ if( newtype == PTHREAD_CANCEL_DEFERRED ||
+ newtype == PTHREAD_CANCEL_ASYNCHRONOUS) {
+ SET_PF_CANCEL_TYPE(pthread_run, newtype);
+ if( oldtype != NULL )
+ *oldtype = otype;
+ } else { /* Invalid new type */
+ rtn = EINVAL;
+ }
+ pthread_sched_resume();
+ if( rtn == 0 ) {
+ /* Test to see if we have a pending cancel to handle */
+ pthread_testcancel();
+ }
+ return rtn;
+}
+
+/*----------------------------------------------------------------------
+ * Function: pthread_testcancel
+ * Purpose: Requests delivery of a pending cancel to the current thread
+ * Args: void
+ * Returns: void
+ * Notes:
+ * If the current thread has been cancelled, this function will not
+ * return and the threads exit processing will be initiated.
+ *----------------------------------------------------------------------*/
+
+void
+pthread_testcancel( void )
+{
+ if( TEST_PF_CANCEL_STATE(pthread_run) == PTHREAD_CANCEL_DISABLE ) {
+ return; /* Can't be cancelled */
+ }
+ /* Ensure that we aren't in the process of exiting already */
+ if( TEST_PF_RUNNING_TO_CANCEL(pthread_run) )
+ return;
+
+ /* See if we have been cancelled */
+ if( TEST_PF_CANCELLED(pthread_run) ) {
+ /* Set this flag to avoid recursively calling pthread_exit */
+ SET_PF_RUNNING_TO_CANCEL(pthread_run);
+ pthread_exit( PTHREAD_CANCELLED ); /* Easy - just call pthread_exit */
+ }
+ return; /* Not cancelled */
+}
+
+/*----------------------------------------------------------------------
+ * Function: pthread_cancel_internal
+ * Purpose: An internal routine to begin the cancel processing
+ * Args: freelocks = do we need to free locks before exiting
+ * Returns: void
+ * Notes:
+ * This routine is called from pthread_resched_resume
+ * prior to a context switch, and after a thread has resumed.
+ *
+ * The kernel must *NOT* be locked on entry here
+ *----------------------------------------------------------------------*/
+
+void
+pthread_cancel_internal( int freelocks )
+{
+ pthread_sched_prevent(); /* gotta stay focused */
+ /* Since we can be called from pthread_resched_resume(), our
+ * state is currently not PS_RUNNING. Since we side stepped
+ * the actually blocking, we need to be removed from the queue
+ * and marked as running.
+ */
+ if( pthread_run->state != PS_RUNNING ) {
+ if( pthread_run->queue == NULL ) {
+ PANIC(); /* Must be on a queue */
+ }
+ /* We MUST NOT put the thread on the prio_queue here. It
+ * is already running (although it's state has changed) and if we
+ * put it on the run queue, it will get resumed after it is dead
+ * and we end up with a nice panic.
+ */
+ pthread_queue_remove(pthread_run->queue, pthread_run);
+ pthread_run->state = PS_RUNNING; /* we are running */
+ }
+ /* Set this flag to avoid recursively calling pthread_exit */
+ SET_PF_RUNNING_TO_CANCEL(pthread_run);
+ /* Free up any locks we hold if told to. */
+ if( freelocks ) {
+ fd_unlock_for_cancel();
+ }
+ pthread_sched_resume();
+ pthread_exit( PTHREAD_CANCELLED ); /* Easy - just call pthread_exit */
+}
+
+/*----------------------------------------------------------------------
+ * Function: possiblyMakeRunnable
+ * Purpose: Make a thread runnable so it can be cancelled if state allows
+ * Args:
+ * pthread = thread to process
+ * Returns:
+ * Notes:
+ *----------------------------------------------------------------------*/
+
+static void
+possiblyMakeRunnable( pthread_t pthread )
+{
+ if( ! TEST_PTHREAD_IS_CANCELLABLE(pthread) )
+ return; /* Not currently cancellable */
+ /* If the thread is currently runnable, then we just let things
+ * take their course when it is next resumed.
+ */
+ if( pthread->state == PS_RUNNING )
+ return; /* will happen at context switch */
+ /* If the thread is sleeping, the it isn't on a queue. */
+ if( pthread->state == PS_SLEEP_WAIT ) {
+ sleep_cancel( pthread ); /* Remove from sleep list */
+ } else {
+ /* Otherwise, we need to take it off the queue and make it runnable */
+ if( pthread->queue == NULL ) {
+ PANIC(); /* Must be on a queue */
+ }
+ pthread_queue_remove(pthread->queue, pthread);
+ }
+ /* And make it runnable */
+ pthread_prio_queue_enq(pthread_current_prio_queue, pthread);
+ pthread->old_state = pthread->state;
+ pthread->state = PS_RUNNING;
+}
diff --git a/mit-pthreads/pthreads/pthread_detach.c b/mit-pthreads/pthreads/pthread_detach.c
new file mode 100644
index 00000000000..d3ae8c03bb3
--- /dev/null
+++ b/mit-pthreads/pthreads/pthread_detach.c
@@ -0,0 +1,92 @@
+/* ==== pthread_detach.c =======================================================
+ * Copyright (c) 1994 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Description : pthread_join function.
+ *
+ * 1.00 94/01/15 proven
+ * -Started coding this file.
+ */
+
+#ifndef lint
+static const char rcsid[] = "$Id$";
+#endif
+
+#include <errno.h>
+#include <pthread.h>
+
+/* ==========================================================================
+ * pthread_detach()
+ */
+int pthread_detach(pthread_t pthread)
+{
+ struct pthread * next_thread, * high_thread, * low_thread;
+ int ret;
+
+ pthread_sched_prevent();
+
+ /* Check that thread isn't detached already */
+ if (!(pthread->attr.flags & PTHREAD_DETACHED)) {
+
+ pthread->attr.flags |= PTHREAD_DETACHED;
+
+ /* Wakeup all threads waiting on a join */
+ if (next_thread = pthread_queue_deq(&(pthread->join_queue))) {
+ high_thread = next_thread;
+
+ while (next_thread = pthread_queue_deq(&(pthread->join_queue))) {
+ if (high_thread->pthread_priority < next_thread->pthread_priority) {
+ low_thread = high_thread;
+ high_thread = next_thread;
+ } else {
+ low_thread = next_thread;
+ }
+ pthread_prio_queue_enq(pthread_current_prio_queue, low_thread);
+ low_thread->state = PS_RUNNING;
+ }
+ /* If the thread is dead then move it to the alloc queue */
+ if (pthread_queue_remove(&pthread_dead_queue, pthread) == OK) {
+ pthread_queue_enq(&pthread_alloc_queue, pthread);
+ }
+ pthread_sched_other_resume(high_thread);
+ return(OK);
+ }
+ /* If the thread is dead then move it to the alloc queue */
+ if (pthread_queue_remove(&pthread_dead_queue, pthread) == OK) {
+ pthread_queue_enq(&pthread_alloc_queue, pthread);
+ pthread->state = PS_UNALLOCED;
+ }
+ ret = OK;
+ } else {
+ ret = ESRCH;
+ }
+ pthread_sched_resume();
+ return(ret);
+}
diff --git a/mit-pthreads/pthreads/pthread_init.c b/mit-pthreads/pthreads/pthread_init.c
new file mode 100644
index 00000000000..83e19fe0229
--- /dev/null
+++ b/mit-pthreads/pthreads/pthread_init.c
@@ -0,0 +1,135 @@
+/* ==== pthread_init.c ========================================================
+ * Copyright (c) 1993, 1994 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Description : Pthread_init routine.
+ *
+ * 1.00 94/09/20 proven
+ * -Started coding this file.
+ */
+
+#ifndef lint
+static const char rcsid[] = "$Id$";
+#endif
+
+#include <pthread.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * errno is declared here to prevent the linker from pulling in errno
+ * from the C library (and whatever else is in that file). I also use
+ * errno as the default location for error numbers for the initial thread
+ * giving some backwards compatibility.
+ */
+#ifdef errno
+#undef errno
+#endif
+
+#if !defined(M_UNIX)
+int errno;
+#else
+extern int errno;
+#endif
+
+/* ==========================================================================
+ * pthread_init()
+ *
+ * We use features of the C++ linker to make sure this function is called
+ * before anything else is done in the program. See init.cc.
+ */
+void pthread_init(void)
+{
+ struct machdep_pthread machdep_data = MACHDEP_PTHREAD_INIT;
+
+ /* Only call this once */
+ if (pthread_initial) {
+ return;
+ }
+
+ pthread_pagesize = getpagesize();
+
+ /* Initialize the first thread */
+ if ((pthread_initial = (pthread_t)malloc(sizeof(struct pthread))) &&
+ (pthread_current_prio_queue = (struct pthread_prio_queue *)
+ malloc(sizeof(struct pthread_prio_queue)))) {
+ memcpy(&(pthread_initial->machdep_data), &machdep_data,
+ sizeof(machdep_data));
+ memcpy(&pthread_initial->attr, &pthread_attr_default,
+ sizeof(pthread_attr_t));
+
+ pthread_initial->pthread_priority = PTHREAD_DEFAULT_PRIORITY;
+ pthread_initial->state = PS_RUNNING;
+
+ pthread_queue_init(&(pthread_initial->join_queue));
+ pthread_initial->specific_data = NULL;
+ pthread_initial->specific_data_count = 0;
+ pthread_initial->cleanup = NULL;
+ pthread_initial->queue = NULL;
+ pthread_initial->next = NULL;
+ pthread_initial->flags = 0;
+ pthread_initial->pll = NULL;
+ pthread_initial->sll = NULL;
+
+ /* PTHREADS spec says we start with cancellability on and deferred */
+ SET_PF_CANCEL_STATE(pthread_initial, PTHREAD_CANCEL_ENABLE);
+ SET_PF_CANCEL_TYPE(pthread_initial, PTHREAD_CANCEL_DEFERRED);
+
+
+ /* Ugly errno hack */
+ pthread_initial->error_p = &errno;
+ pthread_initial->error = 0;
+
+ pthread_prio_queue_init(pthread_current_prio_queue);
+ pthread_link_list = pthread_initial;
+ pthread_run = pthread_initial;
+
+ uthread_sigmask = &(pthread_run->sigmask);
+
+ /* XXX can I assume the mask and pending siganl sets are empty. */
+ sigemptyset(&(pthread_initial->sigpending));
+ sigemptyset(&(pthread_initial->sigmask));
+ pthread_initial->sigcount = 0;
+
+ /* Initialize the signal handler. */
+ sig_init();
+
+ /* Initialize the fd table. */
+ fd_init();
+
+ /* Start the scheduler */
+ machdep_set_thread_timer(&(pthread_run->machdep_data));
+#ifdef M_UNIX
+ machdep_sys_init();
+#endif
+ return;
+ }
+ PANIC();
+}
diff --git a/mit-pthreads/pthreads/pthread_join.c b/mit-pthreads/pthreads/pthread_join.c
new file mode 100644
index 00000000000..879250020a1
--- /dev/null
+++ b/mit-pthreads/pthreads/pthread_join.c
@@ -0,0 +1,139 @@
+/* ==== pthread_join.c =======================================================
+ * Copyright (c) 1994 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Description : pthread_join function.
+ *
+ * 1.00 94/01/15 proven
+ * -Started coding this file.
+ */
+
+#ifndef lint
+static const char rcsid[] = "$Id$";
+#endif
+
+#include <pthread.h>
+#include <errno.h>
+
+static int testDeadlock( struct pthread_queue *queue, pthread_t target );
+
+/* ==========================================================================
+ * pthread_join()
+ */
+int pthread_join(pthread_t pthread, void **thread_return)
+{
+ int ret;
+
+ pthread_sched_prevent();
+
+ /* Ensure they gave us a legal pthread pointer */
+ if( ! __pthread_is_valid( pthread ) ) {
+ pthread_sched_resume();
+ return(EINVAL);
+ }
+
+ /* Check that thread isn't detached already */
+ if (pthread->attr.flags & PTHREAD_DETACHED) {
+ pthread_sched_resume();
+ return(ESRCH);
+ }
+
+ /*
+ * Now check if other thread has exited
+ * Note: This must happen after checking detached state.
+ */
+ if (pthread_queue_remove(&pthread_dead_queue, pthread) != OK) {
+
+ /* Before we pend on the join, ensure there is no dead lock */
+
+ if( testDeadlock( &pthread_run->join_queue, pthread ) == NOTOK ) {
+ ret = EDEADLK;
+ } else {
+ pthread_queue_enq(&(pthread->join_queue), pthread_run);
+ SET_PF_AT_CANCEL_POINT(pthread_run); /* This is a cancel point */
+ pthread_resched_resume(PS_JOIN);
+ CLEAR_PF_AT_CANCEL_POINT(pthread_run); /* No longer at cancel point */
+ pthread_sched_prevent();
+
+ if (pthread_queue_remove(&pthread_dead_queue, pthread) == OK) {
+ pthread_queue_enq(&pthread_alloc_queue, pthread);
+ pthread->attr.flags |= PTHREAD_DETACHED;
+ pthread->state = PS_UNALLOCED;
+ if (thread_return) {
+ *thread_return = pthread->ret;
+ }
+ ret = OK;
+ } else {
+ ret = ESRCH;
+ }
+ }
+ } else {
+ /* Just get the return value and detach the thread */
+ pthread_queue_enq(&pthread_alloc_queue, pthread);
+ pthread->attr.flags |= PTHREAD_DETACHED;
+ pthread->state = PS_UNALLOCED;
+ if (thread_return) {
+ *thread_return = pthread->ret;
+ }
+ ret = OK;
+ }
+ pthread_sched_resume();
+ return(ret);
+}
+
+/*----------------------------------------------------------------------
+ * Function: testDeadlock
+ * Purpose: recursive queue walk to check for deadlocks
+ * Args:
+ * queue = the queue to walk
+ * pthread = target to scan for
+ * Returns:
+ * OK = no deadlock, NOTOK = deadlock
+ * Notes:
+ *----------------------------------------------------------------------*/
+static int
+testDeadlock( struct pthread_queue *queue, pthread_t target )
+{
+ pthread_t t;
+
+ if( queue == NULL )
+ return OK; /* Empty queue, obviously ok */
+
+ for( t = queue->q_next; t; t = t->next ) {
+ if( t == target )
+ return NOTOK; /* bang, your dead */
+
+ if( testDeadlock( &t->join_queue, target ) == NOTOK ) {
+ return NOTOK;
+ }
+ }
+
+ return OK; /* No deadlock */
+}
diff --git a/mit-pthreads/pthreads/pthread_kill.c b/mit-pthreads/pthreads/pthread_kill.c
new file mode 100644
index 00000000000..9e3e61488a3
--- /dev/null
+++ b/mit-pthreads/pthreads/pthread_kill.c
@@ -0,0 +1,93 @@
+/* ==== pthread_kill.c =======================================================
+ * Copyright (c) 1994 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Description : pthread_kill function.
+ *
+ * 1.32 94/06/12 proven
+ * -Started coding this file.
+ */
+
+#ifndef lint
+static const char rcsid[] = "$Id$";
+#endif
+
+#include <pthread.h>
+
+/* Defined in sig.c, a linked list of threads currently
+ * blocked in sigwait(): */
+extern struct pthread * pthread_sigwait;
+
+
+/* ==========================================================================
+ * pthread_kill()
+ */
+int pthread_kill(struct pthread * pthread, int sig)
+{
+ struct pthread ** pthread_ptr;
+
+ pthread_sched_prevent();
+
+ /* Check who is the current owner of pthread */
+/* if (pthread->kthread != pthread_run->kthread) { */
+ if (0) {
+ } else {
+ if (pthread->state == PS_SIGWAIT) {
+ if(sigismember(pthread->data.sigwait, sig)) {
+ for (pthread_ptr = &pthread_sigwait;
+ (*pthread_ptr);
+ pthread_ptr = &((*pthread_ptr)->next)) {
+ if ((*pthread_ptr) == pthread) {
+
+ /* Take the thread out of the
+ * pthread_sigwait linked list: */
+ *pthread_ptr=(*pthread_ptr)->next;
+
+ *(int *)(pthread->ret) = sig;
+ pthread_sched_other_resume(pthread);
+ return(OK);
+ }
+ }
+ /* A thread should not be in the state PS_SIGWAIT
+ * without being in the pthread_sigwait linked
+ * list: */
+ PANIC();
+ }
+ }
+ if (!sigismember(&pthread->sigpending,sig)) /* Added by monty */
+ {
+ sigaddset(&(pthread->sigpending), sig);
+ pthread->sigcount++;
+ }
+ }
+
+ pthread_sched_resume();
+ return(OK);
+}
diff --git a/mit-pthreads/pthreads/pthread_once.c b/mit-pthreads/pthreads/pthread_once.c
new file mode 100644
index 00000000000..0a3dcd23fae
--- /dev/null
+++ b/mit-pthreads/pthreads/pthread_once.c
@@ -0,0 +1,59 @@
+/* ==== pthread_once.c =======================================================
+ * Copyright (c) 1993, 1994 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Description : pthread_once function.
+ *
+ * 1.00 93/12/12 proven
+ * -Started coding this file.
+ */
+
+#ifndef lint
+static const char rcsid[] = "$Id$";
+#endif
+
+#include <pthread.h>
+
+/* ==========================================================================
+ * pthread_once()
+ */
+int pthread_once(pthread_once_t *once_control, void (*init_routine)(void))
+{
+ /* Check first for speed */
+ if (once_control->state == PTHREAD_NEEDS_INIT) {
+ pthread_mutex_lock(&(once_control->mutex));
+ if (once_control->state == PTHREAD_NEEDS_INIT) {
+ init_routine();
+ once_control->state = PTHREAD_DONE_INIT;
+ }
+ pthread_mutex_unlock(&(once_control->mutex));
+ }
+ return(OK);
+}
diff --git a/mit-pthreads/pthreads/queue.c b/mit-pthreads/pthreads/queue.c
new file mode 100644
index 00000000000..c33774bf4dd
--- /dev/null
+++ b/mit-pthreads/pthreads/queue.c
@@ -0,0 +1,143 @@
+/* ==== queue.c ============================================================
+ * Copyright (c) 1993, 1994 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Description : Queue functions.
+ *
+ * 1.00 93/07/15 proven
+ * -Started coding this file.
+ */
+
+#ifndef lint
+static const char rcsid[] = "$Id$";
+#endif
+
+#include <pthread.h>
+
+/*
+ * All routines in this file assume that the queue has been appropriatly
+ * locked.
+ */
+
+/* ==========================================================================
+ * pthread_queue_init()
+ */
+void pthread_queue_init(struct pthread_queue *queue)
+{
+ queue->q_next = NULL;
+ queue->q_last = NULL;
+ queue->q_data = NULL;
+}
+
+/* ==========================================================================
+ * pthread_queue_enq()
+ */
+void pthread_queue_enq(struct pthread_queue *queue, struct pthread *thread)
+{
+ if (queue->q_last) {
+ queue->q_last->next = thread;
+ } else {
+ queue->q_next = thread;
+ }
+ queue->q_last = thread;
+ thread->queue = queue;
+ thread->next = NULL;
+
+}
+
+/* ==========================================================================
+ * pthread_queue_get()
+ */
+struct pthread *pthread_queue_get(struct pthread_queue *queue)
+{
+ return(queue->q_next);
+}
+
+/* ==========================================================================
+ * pthread_queue_deq()
+ */
+struct pthread *pthread_queue_deq(struct pthread_queue *queue)
+{
+ struct pthread *thread = NULL;
+
+ if (queue->q_next) {
+ thread = queue->q_next;
+ if (!(queue->q_next = queue->q_next->next)) {
+ queue->q_last = NULL;
+ }
+ thread->queue = NULL;
+ thread->next = NULL;
+ }
+ return(thread);
+}
+
+/* ==========================================================================
+ * pthread_queue_remove()
+ */
+int pthread_queue_remove(struct pthread_queue *queue, struct pthread *thread)
+{
+ struct pthread **current = &(queue->q_next);
+ struct pthread *prev = NULL;
+ int ret = NOTOK;
+
+ while (*current) {
+ if (*current == thread) {
+ if ((*current)->next) {
+ *current = (*current)->next;
+ } else {
+ queue->q_last = prev;
+ *current = NULL;
+ }
+ thread->queue = NULL;
+ thread->next = NULL;
+ ret = OK;
+ break;
+ }
+ prev = *current;
+ current = &((*current)->next);
+ }
+ return(ret);
+}
+
+/* ==========================================================================
+ * pthread_llist_remove()
+ */
+int pthread_llist_remove(struct pthread **llist, struct pthread *thread)
+{
+ while (*llist) {
+ if (*llist == thread) {
+ *llist = thread->next;
+ return(OK);
+ }
+ llist = &(*llist)->next;
+ }
+ return(NOTOK);
+}
+
diff --git a/mit-pthreads/pthreads/readv.c b/mit-pthreads/pthreads/readv.c
new file mode 100644
index 00000000000..fd63d31cf94
--- /dev/null
+++ b/mit-pthreads/pthreads/readv.c
@@ -0,0 +1,85 @@
+/* ==== readv.c ============================================================
+ * Copyright (c) 1995 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Description : Implementation of readv().
+ *
+ * 1.00 95/06/19 proven
+ * -Started coding this file.
+ */
+
+#ifndef lint
+static const char rcsid[] = "$Id$";
+#endif
+
+#include "config.h"
+
+#ifndef HAVE_SYSCALL_READV
+
+#include <errno.h>
+#include <unistd.h>
+#include <sys/uio.h>
+#include <sys/types.h>
+
+/* ==========================================================================
+ * machdep_sys_readv()
+ */
+int machdep_sys_readv(int fd, struct iovec * vector, int count)
+{
+ size_t bytes, i;
+ char *buffer;
+ int ret = 0;
+
+ /* Find the total number of bytes to be read. */
+ for (bytes = 0, i = 0; i < count; ++i)
+ bytes += vector[i].iov_len;
+
+ if (bytes) {
+ /*
+ * Allocate a temporary buffer to hold the data.
+ * Don't use alloca because threads tend to have smaller stacks.
+ */
+ if ((buffer = (char *)malloc(bytes)) == NULL) {
+ return(-ENOMEM);
+ }
+ ret = (int)machdep_sys_read(fd, buffer, bytes);
+
+ /* Copy the data from memory specified by VECTOR to BUFFER */
+ for (i = 0, bytes = 0; ret > 0; ret -= vector[i].iov_len) {
+ memcpy(vector[i].iov_base, buffer + bytes,
+ ret > vector[i].iov_len ? vector[i].iov_len : ret);
+ bytes += vector[i].iov_len;
+ }
+ free(buffer);
+ }
+ return(ret);
+}
+
+#endif
diff --git a/mit-pthreads/pthreads/schedparam.c b/mit-pthreads/pthreads/schedparam.c
new file mode 100644
index 00000000000..b4b28577022
--- /dev/null
+++ b/mit-pthreads/pthreads/schedparam.c
@@ -0,0 +1,170 @@
+/* ==== schedparam.c =======================================================
+ * Copyright (c) 1994 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Description : Pthread schedparam functions.
+ *
+ * 1.38 94/06/15 proven
+ * -Started coding this file.
+ */
+
+#ifndef lint
+static const char rcsid[] = "$Id$";
+#endif
+
+#include <pthread.h>
+#include <sched.h>
+#include <errno.h>
+
+/* ==========================================================================
+ * sched_get_priority_max
+ */
+int sched_get_priority_max(int policy)
+{
+ return PTHREAD_MAX_PRIORITY;
+}
+
+/* ==========================================================================
+ * sched_get_priority_min
+ */
+int sched_get_priority_min(int policy)
+{
+ return PTHREAD_MIN_PRIORITY;
+}
+
+/* Currently only policy is supported */
+/* ==========================================================================
+ * pthread_setschedparam()
+ */
+int pthread_setschedparam(pthread_t pthread, int policy,
+ struct sched_param * param)
+{
+ enum schedparam_policy new_policy, old_policy;
+ int ret = OK;
+ int prio;
+
+ new_policy = policy;
+ pthread_sched_prevent();
+ old_policy = pthread->attr.schedparam_policy;
+
+ if (param) {
+ if ((param->sched_priority < PTHREAD_MIN_PRIORITY) ||
+ (param->sched_priority > PTHREAD_MAX_PRIORITY)) {
+ pthread_sched_resume();
+ return(EINVAL);
+ }
+ prio = param->sched_priority;
+ } else {
+ prio = pthread->pthread_priority;
+ }
+
+ if (pthread == pthread_run) {
+ switch(new_policy) {
+ case SCHED_RR:
+ pthread->attr.schedparam_policy = new_policy;
+ switch (old_policy) {
+ case SCHED_FIFO:
+ machdep_unset_thread_timer(NULL);
+ default:
+ pthread->pthread_priority = prio;
+ break;
+ }
+ break;
+ case SCHED_FIFO:
+ pthread->attr.schedparam_policy = new_policy;
+ switch (old_policy) {
+ case SCHED_IO:
+ case SCHED_RR:
+ if (pthread->pthread_priority < prio) {
+ pthread->pthread_priority = prio;
+ pthread_sched_resume();
+ pthread_yield();
+ return(OK);
+ }
+ default:
+ pthread->pthread_priority = prio;
+ break;
+ }
+ break;
+ case SCHED_IO:
+ pthread->attr.schedparam_policy = new_policy;
+ switch (old_policy) {
+ case SCHED_FIFO:
+ machdep_unset_thread_timer(NULL);
+ default:
+ pthread->pthread_priority = prio;
+ break;
+ }
+ break;
+ default:
+ SET_ERRNO(EINVAL);
+ ret = EINVAL;
+ break;
+ }
+ } else {
+ switch(new_policy) {
+ case SCHED_FIFO:
+ case SCHED_IO:
+ case SCHED_RR:
+ if(pthread_prio_queue_remove(pthread_current_prio_queue,pthread) == OK) {
+ pthread->attr.schedparam_policy = new_policy;
+ pthread->pthread_priority = prio;
+ pthread_sched_other_resume(pthread);
+ } else {
+ pthread->attr.schedparam_policy = new_policy;
+ pthread->pthread_priority = prio;
+ pthread_sched_resume();
+ }
+ return(OK);
+ break;
+ default:
+ SET_ERRNO(EINVAL);
+ ret = EINVAL;
+ break;
+ }
+ }
+
+ pthread_sched_resume();
+ return(ret);
+}
+
+/* ==========================================================================
+ * pthread_getschedparam()
+ */
+int pthread_getschedparam(pthread_t pthread, int * policy,
+ struct sched_param * param)
+{
+ *policy = pthread->attr.schedparam_policy;
+ if (param) {
+ param->sched_priority = pthread->pthread_priority;
+ }
+ return(OK);
+}
+
diff --git a/mit-pthreads/pthreads/select.c b/mit-pthreads/pthreads/select.c
new file mode 100644
index 00000000000..eaafce31f19
--- /dev/null
+++ b/mit-pthreads/pthreads/select.c
@@ -0,0 +1,255 @@
+/* ==== select.c ============================================================
+ * Copyright (c) 1994 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * This code based on code contributed by
+ * Peter Hofmann <peterh@prz.tu-berlin.d400.de>
+ *
+ * Description : Select.
+ *
+ * 1.23 94/04/26 proven
+ * -Started coding this file.
+ */
+
+#ifndef lint
+static const char rcsid[] = "$Id$";
+#endif
+
+#include <string.h>
+#include <errno.h>
+#include <pthread.h>
+#include <sys/types.h>
+#include <sys/time.h>
+
+extern struct pthread_queue fd_wait_select;
+static struct timeval zero_timeout = { 0, 0 }; /* Moved by monty */
+
+/* ==========================================================================
+ * select()
+ */
+int select(int numfds, fd_set *readfds, fd_set *writefds,
+ fd_set *exceptfds, struct timeval *timeout)
+{
+ fd_set real_exceptfds, real_readfds, real_writefds; /* mapped fd_sets */
+ fd_set * real_readfds_p, * real_writefds_p, * real_exceptfds_p;
+ fd_set read_locks, write_locks, rdwr_locks;
+ struct timespec timeout_time, current_time;
+ int i, j, ret = 0, got_all_locks = 1;
+ struct pthread_select_data data;
+
+ if (numfds > dtablesize) {
+ numfds = dtablesize;
+ }
+
+ data.nfds = 0;
+ FD_ZERO(&data.readfds);
+ FD_ZERO(&data.writefds);
+ FD_ZERO(&data.exceptfds);
+
+ /* Do this first */
+ if (timeout) {
+ machdep_gettimeofday(&current_time);
+ timeout_time.tv_sec = current_time.tv_sec + timeout->tv_sec;
+ if ((timeout_time.tv_nsec = current_time.tv_nsec +
+ (timeout->tv_usec * 1000)) > 1000000000) {
+ timeout_time.tv_nsec -= 1000000000;
+ timeout_time.tv_sec++;
+ }
+ }
+
+ FD_ZERO(&read_locks);
+ FD_ZERO(&write_locks);
+ FD_ZERO(&rdwr_locks);
+ FD_ZERO(&real_readfds);
+ FD_ZERO(&real_writefds);
+ FD_ZERO(&real_exceptfds);
+
+ /* lock readfds */
+ if (readfds || writefds || exceptfds) {
+ for (i = 0; i < numfds; i++) {
+ if ((readfds && (FD_ISSET(i, readfds))) ||
+ (exceptfds && FD_ISSET(i, exceptfds))) {
+ if (writefds && FD_ISSET(i ,writefds)) {
+ if ((ret = fd_lock(i, FD_RDWR, NULL)) != OK) {
+ got_all_locks = 0;
+ break;
+ }
+ FD_SET(i, &rdwr_locks);
+ FD_SET(fd_table[i]->fd.i,&real_writefds);
+ } else {
+ if ((ret = fd_lock(i, FD_READ, NULL)) != OK) {
+ got_all_locks = 0;
+ break;
+ }
+ FD_SET(i, &read_locks);
+ }
+ if (readfds && FD_ISSET(i,readfds)) {
+ FD_SET(fd_table[i]->fd.i, &real_readfds);
+ }
+ if (exceptfds && FD_ISSET(i,exceptfds)) {
+ FD_SET(fd_table[i]->fd.i, &real_exceptfds);
+ }
+ if (fd_table[i]->fd.i >= data.nfds) {
+ data.nfds = fd_table[i]->fd.i + 1;
+ }
+ } else {
+ if (writefds && FD_ISSET(i, writefds)) {
+ if ((ret = fd_lock(i, FD_WRITE, NULL)) != OK) {
+ got_all_locks = 0;
+ break;
+ }
+ FD_SET(i, &write_locks);
+ FD_SET(fd_table[i]->fd.i,&real_writefds);
+ if (fd_table[i]->fd.i >= data.nfds) {
+ data.nfds = fd_table[i]->fd.i + 1;
+ }
+ }
+ }
+ }
+ }
+
+ if (got_all_locks)
+ {
+ memcpy(&data.readfds,&real_readfds,sizeof(fd_set));
+ memcpy(&data.writefds,&real_writefds,sizeof(fd_set));
+ memcpy(&data.exceptfds,&real_exceptfds,sizeof(fd_set));
+
+ real_readfds_p = (readfds == NULL) ? NULL : &real_readfds;
+ real_writefds_p = (writefds == NULL) ? NULL : &real_writefds;
+ real_exceptfds_p = (exceptfds == NULL) ? NULL : &real_exceptfds;
+
+ pthread_run->sighandled=0;
+ if ((ret = machdep_sys_select(data.nfds, real_readfds_p,
+ real_writefds_p, real_exceptfds_p,
+ &zero_timeout)) == OK) {
+ pthread_sched_prevent();
+
+ real_exceptfds_p = (exceptfds == NULL) ? NULL : &data.exceptfds;
+ real_writefds_p = (writefds == NULL) ? NULL : &data.writefds;
+ real_readfds_p = (readfds == NULL) ? NULL : &data.readfds;
+
+ pthread_queue_enq(&fd_wait_select, pthread_run);
+ pthread_run->data.select_data = &data;
+ SET_PF_WAIT_EVENT(pthread_run);
+
+ if (timeout) {
+ machdep_gettimeofday(&current_time);
+ sleep_schedule(&current_time, &timeout_time);
+
+ SET_PF_AT_CANCEL_POINT(pthread_run);
+ pthread_resched_resume(PS_SELECT_WAIT);
+ CLEAR_PF_AT_CANCEL_POINT(pthread_run);
+
+ /* We're awake */
+ if (sleep_cancel(pthread_run) == NOTOK) {
+ ret = OK;
+ }
+ else
+ {
+ int count = 0;
+ for (i = 0; i < numfds; i++)
+ {
+ if (real_readfds_p && (FD_ISSET(i, real_readfds_p)))
+ count++;
+ if (real_writefds_p && (FD_ISSET(i, real_writefds_p)))
+ count++;
+ if (real_exceptfds_p && (FD_ISSET(i, real_exceptfds_p)))
+ count++;
+ }
+ ret = count;
+ }
+ /* Moving this after the sleep_cancel() seemed
+ * to fix intermittent crashes during heavy
+ * socket use. (mevans)
+ */
+ CLEAR_PF_DONE_EVENT(pthread_run);
+ } else {
+ int count = 0;
+ SET_PF_AT_CANCEL_POINT(pthread_run);
+ pthread_resched_resume(PS_SELECT_WAIT);
+ CLEAR_PF_AT_CANCEL_POINT(pthread_run);
+ CLEAR_PF_DONE_EVENT(pthread_run);
+ for (i = 0; i < numfds; i++)
+ {
+ if (real_readfds_p && (FD_ISSET(i, real_readfds_p)))
+ count++;
+ if (real_writefds_p && (FD_ISSET(i, real_writefds_p)))
+ count++;
+ if (real_exceptfds_p && (FD_ISSET(i, real_exceptfds_p)))
+ count++;
+ }
+ ret = count;
+ }
+ if (pthread_run->sighandled) /* Added by monty */
+ { /* We where aborted */
+ ret= NOTOK;
+ SET_ERRNO(EINTR);
+ }
+ } else if (ret < 0) {
+ SET_ERRNO(-ret);
+ ret = NOTOK;
+ }
+ }
+
+ /* clean up the locks */
+ for (i = 0; i < numfds; i++)
+ { /* Changed by monty */
+ if (FD_ISSET(i,&read_locks)) fd_unlock(i,FD_READ);
+ if (FD_ISSET(i,&rdwr_locks)) fd_unlock(i,FD_RDWR);
+ if (FD_ISSET(i,&write_locks)) fd_unlock(i,FD_WRITE);
+ }
+ if (ret > 0) {
+ if (readfds != NULL) {
+ for (i = 0; i < numfds; i++) {
+ if (! (FD_ISSET(i,readfds) &&
+ FD_ISSET(fd_table[i]->fd.i,real_readfds_p)))
+ FD_CLR(i,readfds);
+ }
+ }
+ if (writefds != NULL) {
+ for (i = 0; i < numfds; i++)
+ if (! (FD_ISSET(i,writefds) &&
+ FD_ISSET(fd_table[i]->fd.i,real_writefds_p)))
+ FD_CLR(i,writefds);
+ }
+ if (exceptfds != NULL) {
+ for (i = 0; i < numfds; i++)
+ if (! (FD_ISSET(i,exceptfds) &&
+ FD_ISSET(fd_table[i]->fd.i,real_exceptfds_p)))
+ FD_CLR(i,exceptfds);
+ }
+ } else {
+ if (exceptfds != NULL) FD_ZERO(exceptfds);
+ if (writefds != NULL) FD_ZERO(writefds);
+ if (readfds != NULL) FD_ZERO(readfds);
+ }
+
+ return(ret);
+}
diff --git a/mit-pthreads/pthreads/sig.c b/mit-pthreads/pthreads/sig.c
new file mode 100644
index 00000000000..85d4465bf1c
--- /dev/null
+++ b/mit-pthreads/pthreads/sig.c
@@ -0,0 +1,452 @@
+/* ==== sig.c =======================================================
+ * Copyright (c) 1994 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Description : All the thread signal functions.
+ *
+ * 1.32 94/06/12 proven
+ * -Started coding this file.
+ */
+
+#ifndef lint
+static const char rcsid[] = "$Id$";
+#endif
+
+#include <errno.h>
+#include <pthread.h>
+#include <signal.h>
+#include <string.h>
+
+#if defined(M_UNIX)
+#define signal(A,B) machdep_sys_signal((A),(B))
+#endif
+
+extern void sig_handler_real();
+
+struct pthread * pthread_sigwait;
+static sigset_t pending_signals;
+
+struct pthread_sigvec {
+ void (*vector)();
+ sigset_t mask;
+ int flags;
+} pthread_sigvec[SIGMAX];
+
+/* ==========================================================================
+ * pthread_sig_register()
+ *
+ * Assumes the kernel is locked.
+ */
+int pthread_sig_register(int sig)
+{
+ struct pthread ** pthread_ptr, * pthread;
+ int ret;
+
+ /*
+ * If we have a siginfo structure and the signal is synchronous then
+ * only deliver the signal to the current thread.
+ */
+
+ /* Check waiting threads for delivery */
+ for (pthread_ptr = &pthread_sigwait; (*pthread_ptr);
+ pthread_ptr = &((*pthread_ptr)->next)) {
+ if (sigismember((*pthread_ptr)->data.sigwait, sig)) {
+ pthread=*pthread_ptr;
+ *pthread_ptr=(*pthread_ptr)->next;
+
+ pthread_prio_queue_enq(pthread_current_prio_queue, pthread);
+ ret = pthread->pthread_priority;
+ *(int *)(pthread->ret) = sig;
+ pthread->state = PS_RUNNING;
+
+ return(ret);
+ }
+ }
+
+ /* Check current running thread */
+ if (pthread_run) {
+ if (!sigismember(&pthread_run->sigmask, sig)) {
+ sigaddset(&pthread_run->sigpending, sig);
+ pthread_run->sigcount++;
+ return(0);
+ }
+ }
+
+ /* Check any running thread */
+ for (pthread = pthread_current_prio_queue->next;
+ pthread; pthread = pthread->next) {
+ if (!sigismember(&pthread->sigmask, sig)) {
+ sigaddset(&pthread->sigpending, sig);
+ pthread->sigcount++;
+ return(0);
+ }
+ }
+
+ /* Check any thread */
+ for (pthread = pthread_link_list; pthread; pthread = pthread->pll) {
+ if (!sigismember(&pthread->sigmask, sig)) {
+ sigaddset(&pthread->sigpending, sig);
+ pthread->sigcount++;
+ return(0);
+ }
+ }
+
+ sigaddset(&pending_signals, sig);
+ return(0);
+}
+
+/* ==========================================================================
+ * pthread_sig_default()
+ */
+void pthread_sig_default(int sig)
+{
+ sigset_t mask, omask;
+
+ if (pthread_sigvec[sig].vector == SIG_DFL) {
+ /* Set the signal handler to default before issueing the kill */
+ signal(sig, SIG_DFL);
+ kill(getpid(), sig);
+ sigemptyset(&mask);
+ sigaddset(&mask, sig);
+ machdep_sys_sigprocmask(SIG_UNBLOCK, &mask, &omask);
+ signal(sig, sig_handler_real);
+ }
+}
+
+/* ==========================================================================
+ * pthread_sig_process()
+ *
+ * Assumes the kernel is locked.
+ */
+void pthread_sig_process()
+{
+ void (*vector)();
+ int i, j;
+
+ for (i = 1; i < SIGMAX; i++) {
+ if (sigismember(&(pthread_run->sigpending), i)) {
+ if (! sigismember(&(pthread_run->sigmask), i)) {
+ sigdelset(&(pthread_run->sigpending), i);
+ pthread_run->sigcount--;
+
+ if (pthread_sigvec[i].vector == SIG_IGN) {
+ continue;
+ }
+ if (pthread_sigvec[i].vector == SIG_DFL) {
+ pthread_sig_default(i);
+ continue;
+ }
+
+ {
+ sigset_t omask;
+
+ sigemptyset(&omask);
+ /* Save old mask */
+ for (j = 1; j < SIGMAX; j++) {
+ if (sigismember(&(pthread_run->sigmask), j)) {
+ if (sigismember(&(pthread_sigvec[i].mask), j))
+ sigaddset(&(pthread_run->sigmask), j);
+ sigaddset(&omask, j);
+ }
+ }
+ /* The signal is masked while handling the signal */
+ sigaddset(&(pthread_run->sigmask), i);
+
+ /*
+ * Allow interrupts during a signal,
+ * but not a change in the vector
+ */
+ vector = pthread_sigvec[i].vector;
+ if (--pthread_kernel_lock) {
+ PANIC();
+ }
+ vector(i);
+ pthread_run->sighandled=1; /* Mark for select; Monty */
+ pthread_kernel_lock++;
+
+ memcpy(&(pthread_run->sigmask), &omask, sizeof(omask));
+ }
+ }
+ }
+ }
+}
+
+/* ==========================================================================
+ * pthread_sigmask()
+ *
+ * It is unclear wheather this call should be implemented as an atomic
+ * operation. The resulting mask could be wrong if in the signal
+ * handler the thread calls sigprocmask for any signal other than the
+ * signal the handler is dealing with.
+ */
+int pthread_sigmask(int how, const sigset_t *set, sigset_t * oset)
+{
+ int i;
+
+ if (oset) {
+ sigemptyset(oset);
+ for (i = 1; i < SIGMAX; i++) {
+ if (sigismember(&(pthread_run->sigmask), i)) {
+ sigaddset(oset, i);
+ }
+ }
+ }
+
+ if (set) {
+ switch(how) {
+ case SIG_BLOCK:
+ for (i = 1; i < SIGMAX; i++) {
+ if (sigismember(set, i)) {
+ sigaddset(&(pthread_run->sigmask), i);
+ }
+ }
+ break;
+ case SIG_UNBLOCK:
+ pthread_sched_prevent();
+ for (i = 1; i < SIGMAX; i++) {
+ if (sigismember(set, i)) {
+ sigdelset(&(pthread_run->sigmask), i);
+ if (sigismember(&pending_signals, i)) {
+ sigaddset(&(pthread_run->sigpending), i);
+ sigdelset(&pending_signals, i);
+ pthread_run->sigcount++;
+ }
+ }
+ }
+ pthread_sched_resume();
+ break;
+ case SIG_SETMASK:
+ sigfillset(&(pthread_run->sigmask));
+ pthread_sched_prevent();
+ for (i = 1; i < SIGMAX; i++) {
+ if (! sigismember(set, i)) {
+ sigdelset(&(pthread_run->sigmask), i);
+ if (sigismember(&pending_signals, i)) {
+ sigaddset(&(pthread_run->sigpending), i);
+ sigdelset(&pending_signals, i);
+ pthread_run->sigcount++;
+ }
+ }
+ }
+ pthread_sched_resume();
+ break;
+ default:
+ SET_ERRNO(EINVAL);
+ return(NOTOK);
+ }
+ }
+ return(OK);
+}
+
+int sigprocmask(int how, const sigset_t *set, sigset_t * oset)
+{
+ return(pthread_sigmask(how, set, oset));
+}
+
+/* ==========================================================================
+ * sigwait()
+ */
+int sigwait(const sigset_t * set, int * sig)
+{
+ int i;
+
+ /* Check that sig is valid */
+ *sig = 0;
+
+ pthread_sched_prevent();
+ for (i = 1; i < SIGMAX; i++) {
+ if (sigismember(set, i)) {
+ /* Check personal signals */
+ if (sigismember(&(pthread_run->sigpending), i)) {
+ sigdelset(&(pthread_run->sigpending), i);
+ pthread_sched_resume();
+ *sig = i;
+ return(OK);
+ }
+ /* Check kernel signals */
+ if (sigismember(&pending_signals, i)) {
+ sigdelset(&pending_signals, i);
+ pthread_sched_resume();
+ *sig = i;
+ return(OK);
+ }
+ }
+ }
+
+ /* No pending signals, wait for one */
+ pthread_run->next = pthread_sigwait;
+ pthread_sigwait = pthread_run;
+ pthread_run->data.sigwait = set;
+ pthread_run->ret = sig;
+
+ SET_PF_AT_CANCEL_POINT(pthread_run); /* This is a cancel point */
+ pthread_resched_resume(PS_SIGWAIT);
+ CLEAR_PF_AT_CANCEL_POINT(pthread_run); /* No longer at cancel point */
+
+ return(OK);
+}
+
+/* ==========================================================================
+ * raise()
+ */
+int raise(int sig)
+{
+ return(pthread_kill(pthread_self(), sig));
+}
+
+/* ==========================================================================
+ * sigsuspend()
+ */
+int sigsuspend(const sigset_t * mask)
+{
+ int ret_sig, ret;
+ sigset_t nm, om;
+
+ sigfillset(&nm);
+ for(ret_sig = 1; ret_sig < SIGMAX; ret_sig++) {
+ if (sigismember(mask, ret_sig)) {
+ sigdelset(&nm, ret_sig);
+ }
+ }
+ pthread_sigmask(SIG_BLOCK, &nm, &om);
+ if ((ret = sigwait(&nm, &ret_sig)) == OK) {
+ sigemptyset(&nm);
+ sigaddset(&nm, ret_sig);
+ pthread_kill(pthread_self(), ret_sig);
+ pthread_sigmask(SIG_UNBLOCK, &nm, NULL);
+ /* There is a race condition here, it's not worth worring about */
+ pthread_sigmask(SIG_BLOCK, &nm, NULL);
+ SET_ERRNO(EINTR);
+ ret = NOTOK;
+ }
+ pthread_sigmask(SIG_SETMASK, &om, NULL);
+ return(ret);
+}
+
+/* ==========================================================================
+ * pthread_signal()
+ */
+void (*pthread_signal(int sig, void (*dispatch)(int)))()
+{
+ void (*odispatch)(int);
+
+ odispatch = pthread_sigvec[sig].vector;
+ if ((sig > 0) && (sig < SIGMAX)) {
+ pthread_sigvec[sig].vector = dispatch;
+ sigemptyset(&(pthread_sigvec[sig].mask));
+ pthread_sigvec[sig].flags = 0;
+ }
+ return(odispatch);
+}
+
+/* ==========================================================================
+ * pthread_sigprocmask()
+ */
+int pthread_sigaction(int sig, const struct sigaction * act,
+ struct sigaction * oact)
+{
+ if ((sig > 0) && (sig < SIGMAX)) {
+ if (oact) {
+ memcpy(&(oact->sa_mask), &(pthread_sigvec[sig].mask),
+ sizeof(sigset_t));
+ oact->sa_handler = pthread_sigvec[sig].vector;
+ oact->sa_flags = pthread_sigvec[sig].flags;
+ }
+ if (act) {
+ memcpy(&(pthread_sigvec[sig].mask), &(act->sa_mask),
+ sizeof(sigset_t));
+ pthread_sigvec[sig].vector = act->sa_handler;
+ pthread_sigvec[sig].flags = act->sa_flags;
+ }
+ return(OK);
+ }
+ SET_ERRNO(EINVAL);
+ return(NOTOK);
+}
+
+/*
+ * The following here are stolen from BSD because I get mutiply defined
+ * symbols between sig.o and posix_sig.o in Sun's libc.a under Sunos 4.1.3.
+ * The problem is that sigprocmask() is defined in posix_sig.o, in the same
+ * module that a lot of other sigset-primitives are defined, and we have
+ * our definition of sigprocmask() here, but use those other primitives.
+ */
+
+#undef sigemptyset
+#undef sigfillset
+#undef sigaddset
+#undef sigdelset
+#undef sigismember
+
+static const sigset_t __sigemptyset = __SIGEMPTYSET;
+int sigemptyset(sigset_t *set)
+{
+ *set = __sigemptyset;
+ return (0);
+}
+
+static const sigset_t __sigfillset = __SIGFILLSET;
+int sigfillset(sigset_t * set)
+{
+ *set = __sigfillset;
+ return (0);
+}
+
+#define _MAXIMUM_SIG NSIG
+
+int sigaddset(sigset_t *set, int signo)
+{
+ if (signo <= 0 || signo >= _MAXIMUM_SIG) {
+ errno = EINVAL;
+ return -1;
+ }
+ __SIGADDSET(set, signo);
+ return (0);
+}
+
+int sigdelset(sigset_t *set, int signo)
+{
+ if (signo <= 0 || signo >= _MAXIMUM_SIG) {
+ errno = EINVAL;
+ return -1;
+ }
+ __SIGDELSET(set, signo);
+ return (0);
+}
+
+int sigismember(const sigset_t *set, int signo)
+{
+ if (signo <= 0 || signo >= _MAXIMUM_SIG) {
+ errno = EINVAL;
+ return -1;
+ }
+ return(__SIGISMEMBER(set, signo));
+}
+
diff --git a/mit-pthreads/pthreads/signal.c b/mit-pthreads/pthreads/signal.c
new file mode 100644
index 00000000000..7da4183c1cb
--- /dev/null
+++ b/mit-pthreads/pthreads/signal.c
@@ -0,0 +1,653 @@
+/* ==== signal.c ============================================================
+ * Copyright (c) 1993, 1994 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Description : Queue functions.
+ *
+ * 1.00 93/07/21 proven
+ * -Started coding this file.
+ */
+
+#ifndef lint
+static const char rcsid[] = "$Id$";
+#endif
+
+#include <config.h>
+#include <pthread.h>
+#include <signal.h>
+
+/* This will force init.o to get dragged in; if you've got support for
+ C++ initialization, that'll cause pthread_init to be called at
+ program startup automatically, so the application won't need to
+ call it explicitly. */
+
+extern char __pthread_init_hack;
+char *__pthread_init_hack_2 = &__pthread_init_hack;
+
+/*
+ * Time which select in fd_kern_wait() will sleep.
+ * If there are no threads to run we sleep for an hour or until
+ * we get an interrupt or an fd thats awakens. To make sure we
+ * don't miss an interrupt this variable gets reset too zero in
+ * sig_handler_real().
+ */
+struct timeval __fd_kern_wait_timeout = { 0, 0 };
+
+/*
+ * Global for user-kernel lock, and blocked signals
+ */
+
+static sig_atomic_t signum_to_process[SIGMAX + 1] = { 0, };
+volatile sig_atomic_t sig_to_process = 0;
+
+/* static volatile sigset_t sig_to_process; */
+static volatile int sig_count = 0;
+
+static void sig_handler(int signal);
+static void set_thread_timer();
+static void __cleanup_after_resume( void );
+void sig_prevent(void);
+void sig_resume(void);
+
+/* ==========================================================================
+ * context_switch()
+ *
+ * This routine saves the current state of the running thread gets
+ * the next thread to run and restores it's state. To allow different
+ * processors to work with this routine, I allow the machdep_restore_state()
+ * to either return or have it return from machdep_save_state with a value
+ * other than 0, this is for implementations which use setjmp/longjmp.
+ */
+static void context_switch()
+{
+ struct pthread **current, *next, *last, **dead;
+
+ if (pthread_run->state == PS_RUNNING) {
+ /* Put current thread back on the queue */
+ pthread_prio_queue_enq(pthread_current_prio_queue, pthread_run);
+ }
+
+ /* save floating point registers if necessary */
+ if (!(pthread_run->attr.flags & PTHREAD_NOFLOAT)) {
+ machdep_save_float_state(pthread_run);
+ }
+ /* save state of current thread */
+ if (machdep_save_state()) {
+ return;
+ }
+
+ last = pthread_run;
+
+ /* Poll all fds */
+ fd_kern_poll();
+
+context_switch_reschedule:;
+ /* Are there any threads to run */
+ if (pthread_run = pthread_prio_queue_deq(pthread_current_prio_queue)) {
+ /* restore floating point registers if necessary */
+ if (!(pthread_run->attr.flags & PTHREAD_NOFLOAT)) {
+ machdep_restore_float_state();
+ }
+ uthread_sigmask = &(pthread_run->sigmask);
+ /* restore state of new current thread */
+ machdep_restore_state();
+ return;
+ }
+
+ /* Are there any threads at all */
+ for (next = pthread_link_list; next; next = next->pll) {
+ if ((next->state != PS_UNALLOCED) && (next->state != PS_DEAD)) {
+ sigset_t sig_to_block, oset;
+
+ sigfillset(&sig_to_block);
+
+ /*
+ * Check sig_to_process before calling fd_kern_wait, to handle
+ * things like zero timeouts to select() which would register
+ * a signal with the sig_handler_fake() call.
+ *
+ * This case should ignore SIGVTALRM
+ */
+ machdep_sys_sigprocmask(SIG_BLOCK, &sig_to_block, &oset);
+ signum_to_process[SIGVTALRM] = 0;
+ if (sig_to_process) {
+ /* Process interrupts */
+ /*
+ * XXX pthread_run should not be set!
+ * Places where it dumps core should be fixed to
+ * check for the existance of pthread_run --proven
+ */
+ sig_handler(0);
+ } else {
+ machdep_sys_sigprocmask(SIG_UNBLOCK, &sig_to_block, &oset);
+ /*
+ * Do a wait, timeout is set to a hour unless we get an
+ * intr. before the select in wich case it polls.
+ */
+ fd_kern_wait();
+ machdep_sys_sigprocmask(SIG_BLOCK, &sig_to_block, &oset);
+ /* Check for interrupts, but ignore SIGVTALR */
+ signum_to_process[SIGVTALRM] = 0;
+ if (sig_to_process) {
+ /* Process interrupts */
+ sig_handler(0);
+ }
+ }
+ machdep_sys_sigprocmask(SIG_UNBLOCK, &sig_to_block, &oset);
+ goto context_switch_reschedule;
+ }
+ }
+
+ /* There are no threads alive. */
+ pthread_run = last;
+ exit(0);
+}
+
+#if !defined(HAVE_SYSCALL_SIGSUSPEND) && defined(HAVE_SYSCALL_SIGPAUSE)
+
+/* ==========================================================================
+ * machdep_sys_sigsuspend()
+ */
+int machdep_sys_sigsuspend(sigset_t * set)
+{
+ return(machdep_sys_sigpause(* set));
+}
+
+#endif
+
+/* ==========================================================================
+ * sig_handler_pause()
+ *
+ * Wait until a signal is sent to the process.
+ */
+void sig_handler_pause()
+{
+ sigset_t sig_to_block, sig_to_pause, oset;
+
+ sigfillset(&sig_to_block);
+ sigemptyset(&sig_to_pause);
+ machdep_sys_sigprocmask(SIG_BLOCK, &sig_to_block, &oset);
+/* if (!(SIG_ANY(sig_to_process))) { */
+ if (!sig_to_process) {
+ machdep_sys_sigsuspend(&sig_to_pause);
+ }
+ machdep_sys_sigprocmask(SIG_UNBLOCK, &sig_to_block, &oset);
+}
+
+/* ==========================================================================
+ * context_switch_done()
+ *
+ * This routine does all the things that are necessary after a context_switch()
+ * calls the machdep_restore_state(). DO NOT put this in the context_switch()
+ * routine because sometimes the machdep_restore_state() doesn't return
+ * to context_switch() but instead ends up in machdep_thread_start() or
+ * some such routine, which will need to call this routine and
+ * sig_check_and_resume().
+ */
+void context_switch_done()
+{
+ /* sigdelset((sigset_t *)&sig_to_process, SIGVTALRM); */
+ signum_to_process[SIGVTALRM] = 0;
+ set_thread_timer();
+}
+
+/* ==========================================================================
+ * set_thread_timer()
+ *
+ * Assums kernel is locked.
+ */
+static void set_thread_timer()
+{
+ static int last_sched_attr = SCHED_RR;
+
+ switch (pthread_run->attr.schedparam_policy) {
+ case SCHED_RR:
+ machdep_set_thread_timer(&(pthread_run->machdep_data));
+ break;
+ case SCHED_FIFO:
+ if (last_sched_attr != SCHED_FIFO) {
+ machdep_unset_thread_timer(NULL);
+ }
+ break;
+ case SCHED_IO:
+ if ((last_sched_attr != SCHED_IO) && (!sig_count)) {
+ machdep_set_thread_timer(&(pthread_run->machdep_data));
+ }
+ break;
+ default:
+ machdep_set_thread_timer(&(pthread_run->machdep_data));
+ break;
+ }
+ last_sched_attr = pthread_run->attr.schedparam_policy;
+}
+
+/* ==========================================================================
+ * sigvtalrm()
+ */
+static inline void sigvtalrm()
+{
+ if (sig_count) {
+ sigset_t sigall, oset;
+
+ sig_count = 0;
+
+ /* Unblock all signals */
+ sigemptyset(&sigall);
+ machdep_sys_sigprocmask(SIG_SETMASK, &sigall, &oset);
+ }
+ context_switch();
+ context_switch_done();
+}
+
+/* ==========================================================================
+ * sigdefault()
+ */
+static inline void sigdefault(int sig)
+{
+ int ret;
+
+ ret = pthread_sig_register(sig);
+ if (pthread_run && (ret > pthread_run->pthread_priority)) {
+ sigvtalrm();
+ }
+}
+
+/* ==========================================================================
+ * sig_handler_switch()
+ */
+static inline void sig_handler_switch(int sig)
+{
+ int ret;
+
+ switch(sig) {
+ case 0:
+ break;
+ case SIGVTALRM:
+ sigvtalrm();
+ break;
+ case SIGALRM:
+/* sigdelset((sigset_t *)&sig_to_process, SIGALRM); */
+ signum_to_process[SIGALRM] = 0;
+ switch (ret = sleep_wakeup()) {
+ default:
+ if (pthread_run && (ret > pthread_run->pthread_priority)) {
+ sigvtalrm();
+ }
+ case 0:
+ break;
+ case NOTOK:
+ /* Do the registered action, no threads were sleeping */
+ /* There is a timing window that gets
+ * here when no threads are on the
+ * sleep queue. This is a quick fix.
+ * The real problem is possibly related
+ * to heavy use of condition variables
+ * with time outs.
+ * (mevans)
+ *sigdefault(sig);
+ */
+ break;
+ }
+ break;
+ case SIGCHLD:
+/* sigdelset((sigset_t *)&sig_to_process, SIGCHLD); */
+ signum_to_process[SIGCHLD] = 0;
+ switch (ret = wait_wakeup()) {
+ default:
+ if (pthread_run && (ret > pthread_run->pthread_priority)) {
+ sigvtalrm();
+ }
+ case 0:
+ break;
+ case NOTOK:
+ /* Do the registered action, no threads were waiting */
+ sigdefault(sig);
+ break;
+ }
+ break;
+
+#ifdef SIGINFO
+ case SIGINFO:
+ pthread_dump_info ();
+ /* Then fall through, invoking the application's
+ signal handler after printing our info out.
+
+ I'm not convinced that this is right, but I'm not
+ 100% convinced that it is wrong, and this is how
+ Chris wants it done... */
+#endif
+
+ default:
+ /* Do the registered action */
+ if (!sigismember(uthread_sigmask, sig)) {
+ /*
+ * If the signal isn't masked by the last running thread and
+ * the signal behavior is default or ignore then we can
+ * execute it immediatly. --proven
+ */
+ pthread_sig_default(sig);
+ }
+ signum_to_process[sig] = 0;
+ sigdefault(sig);
+ break;
+ }
+
+}
+
+/* ==========================================================================
+ * sig_handler()
+ *
+ * Process signal that just came in, plus any pending on the signal mask.
+ * All of these must be resolved.
+ *
+ * Assumes the kernel is locked.
+ */
+static void sig_handler(int sig)
+{
+ if (pthread_kernel_lock != 1) {
+ PANIC();
+ }
+
+ if (sig) {
+ sig_handler_switch(sig);
+ }
+
+ while (sig_to_process) {
+ for (sig_to_process = 0, sig = 1; sig <= SIGMAX; sig++) {
+ if (signum_to_process[sig]) {
+ sig_handler_switch(sig);
+ }
+ }
+ }
+
+
+/*
+ if (SIG_ANY(sig_to_process)) {
+ for (sig = 1; sig <= SIGMAX; sig++) {
+ if (sigismember((sigset_t *)&sig_to_process, sig)) {
+ goto sig_handler_top;
+ }
+ }
+ }
+*/
+}
+
+/* ==========================================================================
+ * sig_handler_real()
+ *
+ * On a multi-processor this would need to use the test and set instruction
+ * otherwise the following will work.
+ */
+void sig_handler_real(int sig)
+{
+ /*
+ * Get around systems with BROKEN signal handlers.
+ *
+ * Some systems will reissue SIGCHLD if the handler explicitly
+ * clear the signal pending by either doing a wait() or
+ * ignoring the signal.
+ */
+#if defined BROKEN_SIGNALS
+ if (sig == SIGCHLD) {
+ sigignore(SIGCHLD);
+ signal(SIGCHLD, sig_handler_real);
+ }
+#endif
+
+ if (pthread_kernel_lock) {
+ /* sigaddset((sigset_t *)&sig_to_process, sig); */
+ __fd_kern_wait_timeout.tv_sec = 0;
+ signum_to_process[sig] = 1;
+ sig_to_process = 1;
+ return;
+ }
+ pthread_kernel_lock++;
+
+ sig_count++;
+ sig_handler(sig);
+
+ /* Handle any signals the current thread might have just gotten */
+ if (pthread_run && pthread_run->sigcount) {
+ pthread_sig_process();
+ }
+ pthread_kernel_lock--;
+}
+
+/* ==========================================================================
+ * sig_handler_fake()
+ */
+void sig_handler_fake(int sig)
+{
+ if (pthread_kernel_lock) {
+ /* sigaddset((sigset_t *)&sig_to_process, sig); */
+ signum_to_process[sig] = 1;
+ sig_to_process = 1;
+ return;
+ }
+ pthread_kernel_lock++;
+ sig_handler(sig);
+ while (!(--pthread_kernel_lock)) {
+ if (sig_to_process) {
+ /* if (SIG_ANY(sig_to_process)) { */
+ pthread_kernel_lock++;
+ sig_handler(0);
+ } else {
+ break;
+ }
+ }
+}
+
+/* ==========================================================================
+ * __pthread_signal_delete(int sig)
+ *
+ * Assumes the kernel is locked.
+ */
+void __pthread_signal_delete(int sig)
+{
+ signum_to_process[sig] = 0;
+}
+
+/* ==========================================================================
+ * pthread_sched_other_resume()
+ *
+ * Check if thread to be resumed is of higher priority and if so
+ * stop current thread and start new thread.
+ */
+pthread_sched_other_resume(struct pthread * pthread)
+{
+ pthread->state = PS_RUNNING;
+ pthread_prio_queue_enq(pthread_current_prio_queue, pthread);
+
+ if (pthread->pthread_priority > pthread_run->pthread_priority) {
+ if (pthread_kernel_lock == 1) {
+ sig_handler(SIGVTALRM);
+ }
+ }
+
+ __cleanup_after_resume();
+}
+
+/* ==========================================================================
+ * pthread_resched_resume()
+ *
+ * This routine assumes that the caller is the current pthread, pthread_run
+ * and that it has a lock the kernel thread and it wants to reschedule itself.
+ */
+void pthread_resched_resume(enum pthread_state state)
+{
+ pthread_run->state = state;
+
+ /* Since we are about to block this thread, lets see if we are
+ * at a cancel point and if we've been cancelled.
+ * Avoid cancelling dead or unalloced threads.
+ */
+ if( ! TEST_PF_RUNNING_TO_CANCEL(pthread_run) &&
+ TEST_PTHREAD_IS_CANCELLABLE(pthread_run) &&
+ state != PS_DEAD && state != PS_UNALLOCED ) {
+
+ /* Set this flag to avoid recursively calling pthread_exit */
+ /* We have to set this flag here because we will unlock the
+ * kernel prior to calling pthread_cancel_internal.
+ */
+ SET_PF_RUNNING_TO_CANCEL(pthread_run);
+
+ pthread_run->old_state = state; /* unlock needs this data */
+ pthread_sched_resume(); /* Unlock kernel before cancel */
+ pthread_cancel_internal( 1 ); /* free locks and exit */
+ }
+
+ sig_handler(SIGVTALRM);
+
+ __cleanup_after_resume();
+}
+
+/* ==========================================================================
+ * pthread_sched_resume()
+ */
+void pthread_sched_resume()
+{
+ __cleanup_after_resume();
+}
+
+/*----------------------------------------------------------------------
+ * Function: __cleanup_after_resume
+ * Purpose: cleanup kernel locks after a resume
+ * Args: void
+ * Returns: void
+ * Notes:
+ *----------------------------------------------------------------------*/
+static void
+__cleanup_after_resume( void )
+{
+ /* Only bother if we are truely unlocking the kernel */
+ while (!(--pthread_kernel_lock)) {
+ /* if (SIG_ANY(sig_to_process)) { */
+ if (sig_to_process) {
+ pthread_kernel_lock++;
+ sig_handler(0);
+ continue;
+ }
+ if (pthread_run && pthread_run->sigcount) {
+ pthread_kernel_lock++;
+ pthread_sig_process();
+ continue;
+ }
+ break;
+ }
+
+ if( pthread_run == NULL )
+ return; /* Must be during init processing */
+
+ /* Test for cancel that should be handled now */
+
+ if( ! TEST_PF_RUNNING_TO_CANCEL(pthread_run) &&
+ TEST_PTHREAD_IS_CANCELLABLE(pthread_run) ) {
+ /* Kernel is already unlocked */
+ pthread_cancel_internal( 1 ); /* free locks and exit */
+ }
+}
+
+/* ==========================================================================
+ * pthread_sched_prevent()
+ */
+void pthread_sched_prevent(void)
+{
+ pthread_kernel_lock++;
+}
+
+/* ==========================================================================
+ * sig_init()
+ *
+ * SIGVTALRM (NOT POSIX) needed for thread timeslice timeouts.
+ * Since it's not POSIX I will replace it with a
+ * virtual timer for threads.
+ * SIGALRM (IS POSIX) so some special handling will be
+ * necessary to fake SIGALRM signals
+ */
+#ifndef SIGINFO
+#define SIGINFO 0
+#endif
+void sig_init(void)
+{
+ static const int signum_to_initialize[] =
+ { SIGCHLD, SIGALRM, SIGVTALRM, SIGINFO, 0 };
+ static const int signum_to_ignore[] = { SIGKILL, SIGSTOP, 0 };
+ int i, j;
+
+#if defined(HAVE_SYSCALL_SIGACTION) || defined(HAVE_SYSCALL_KSIGACTION)
+ struct sigaction act;
+
+ act.sa_handler = sig_handler_real;
+ sigemptyset(&(act.sa_mask));
+ act.sa_flags = 0;
+#endif
+
+ /* Initialize the important signals */
+ for (i = 0; signum_to_initialize[i]; i++) {
+
+#if defined(HAVE_SYSCALL_SIGACTION) || defined(HAVE_SYSCALL_KSIGACTION)
+ if (sigaction(signum_to_initialize[i], &act, NULL)) {
+#else
+ if (signal(signum_to_initialize[i], sig_handler_real)) {
+#endif
+ PANIC();
+ }
+ }
+
+ /* Initialize the rest of the signals */
+ for (j = 1; j < SIGMAX; j++) {
+ for (i = 0; signum_to_initialize[i]; i++) {
+ if (signum_to_initialize[i] == j) {
+ goto sig_next;
+ }
+ }
+ /* Because Solaris 2.4 can't deal -- proven */
+ for (i = 0; signum_to_ignore[i]; i++) {
+ if (signum_to_ignore[i] == j) {
+ goto sig_next;
+ }
+ }
+ pthread_signal(j, SIG_DFL);
+
+#if defined(HAVE_SYSCALL_SIGACTION) || defined(HAVE_SYSCALL_KSIGACTION)
+ sigaction(j, &act, NULL);
+#else
+ signal(j, sig_handler_real);
+#endif
+
+ sig_next:;
+ }
+
+#if defined BROKEN_SIGNALS
+ signal(SIGCHLD, sig_handler_real);
+#endif
+
+}
+
diff --git a/mit-pthreads/pthreads/sleep.c b/mit-pthreads/pthreads/sleep.c
new file mode 100644
index 00000000000..1c13dd2eb1d
--- /dev/null
+++ b/mit-pthreads/pthreads/sleep.c
@@ -0,0 +1,367 @@
+/* ==== sleep.c ============================================================
+ * Copyright (c) 1993, 1994 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Description : All the appropriate sleep routines.
+ *
+ * 1.00 93/12/28 proven
+ * -Started coding this file.
+ *
+ * 1.36 94/06/04 proven
+ * -Use new timer structure pthread_timer, that uses seconds
+ * -nano seconds. Rewrite all routines completely.
+ *
+ * 1.38 94/06/13 proven
+ * -switch pthread_timer to timespec
+ */
+
+#ifndef lint
+static const char rcsid[] = "$Id$";
+#endif
+
+#include <pthread.h>
+#include <stdio.h>
+#include <errno.h>
+#include <sys/time.h>
+#include <signal.h>
+#include <unistd.h>
+#include <sys/compat.h>
+
+struct pthread * pthread_sleep = NULL;
+
+/* ==========================================================================
+ * sleep_compare_time()
+ */
+/* static inline int sleep_compare_time(struct timespec * time1,
+ struct timespec * time2) */
+static int sleep_compare_time(struct timespec * time1, struct timespec * time2)
+{
+ if ((time1->tv_sec < time2->tv_sec) ||
+ ((time1->tv_sec == time2->tv_sec) && (time1->tv_nsec < time2->tv_nsec))) {
+ return(-1);
+ }
+ if ((time1->tv_sec == time2->tv_sec) && (time1->tv_nsec == time2->tv_nsec)){
+ return(0);
+ }
+ return(1);
+}
+
+/* ==========================================================================
+ * machdep_stop_timer()
+ *
+ * Returns the time left on the timer.
+ */
+static struct itimerval timestop = { { 0, 0 }, { 0, 0 } };
+
+void machdep_stop_timer(struct timespec *current)
+{
+ struct itimerval timenow;
+
+ setitimer(ITIMER_REAL, & timestop, & timenow);
+ __pthread_signal_delete(SIGALRM);
+ if (current) {
+ current->tv_nsec = timenow.it_value.tv_usec * 1000;
+ current->tv_sec = timenow.it_value.tv_sec;
+ }
+}
+
+/* ==========================================================================
+ * machdep_start_timer()
+ */
+int machdep_start_timer(struct timespec *current, struct timespec *wakeup)
+{
+ struct itimerval timeout;
+
+ timeout.it_value.tv_usec = (wakeup->tv_nsec - current->tv_nsec) / 1000;
+ timeout.it_value.tv_sec = wakeup->tv_sec - current->tv_sec;
+ timeout.it_interval.tv_usec = 0;
+ timeout.it_interval.tv_sec = 0;
+ if (timeout.it_value.tv_usec < 0) {
+ timeout.it_value.tv_usec += 1000000;
+ timeout.it_value.tv_sec--;
+ }
+
+ if (((long) timeout.it_value.tv_sec >= 0) &&
+ ((timeout.it_value.tv_usec) || (timeout.it_value.tv_sec))) {
+ if (setitimer(ITIMER_REAL, & timeout, NULL) < 0)
+ {
+ fprintf(stderr,"Got error %d from setitimer with:\n\
+ wakeup: tv_sec: %ld tv_nsec: %ld\n\
+ current: tv_sec: %ld tv_nsec: %ld\n\
+ argument: tv_sec: %ld tv_usec: %ld\n",
+ errno,
+ wakeup->tv_sec, wakeup->tv_nsec,
+ current->tv_sec, current->tv_nsec,
+ timeout.it_value.tv_sec, timeout.it_value.tv_usec);
+ PANIC();
+ }
+ } else {
+ /*
+ * There is no time on the timer.
+ * This shouldn't happen,
+ * but isn't fatal.
+ */
+ sig_handler_fake(SIGALRM);
+ }
+ return(OK);
+}
+
+/* ==========================================================================
+ * sleep_schedule()
+ *
+ * Assumes that the current thread is the thread to be scheduled
+ * and that the kthread is already locked.
+ */
+void sleep_schedule(struct timespec *current_time, struct timespec *new_time)
+{
+ struct pthread * pthread_sleep_current, * pthread_sleep_prev;
+
+ /* Record the new time as the current thread's wakeup time. */
+ pthread_run->wakeup_time = *new_time;
+
+ /* any threads? */
+ if (pthread_sleep_current = pthread_sleep) {
+ if (sleep_compare_time(&(pthread_sleep_current->wakeup_time),
+ new_time) <= 0) {
+ /* Don't need to restart timer */
+ while (pthread_sleep_current->sll) {
+
+ pthread_sleep_prev = pthread_sleep_current;
+ pthread_sleep_current = pthread_sleep_current->sll;
+
+ if (sleep_compare_time(&(pthread_sleep_current->wakeup_time),
+ new_time) > 0) {
+ pthread_run->sll = pthread_sleep_current;
+ pthread_sleep_prev->sll = pthread_run;
+ return;
+ }
+ }
+
+ /* No more threads in queue, attach pthread_run to end of list */
+ pthread_sleep_current->sll = pthread_run;
+ pthread_run->sll = NULL;
+
+ } else {
+ /* Start timer and enqueue thread */
+ machdep_start_timer(current_time, new_time);
+ pthread_run->sll = pthread_sleep_current;
+ pthread_sleep = pthread_run;
+ }
+ } else {
+ /* Start timer and enqueue thread */
+ machdep_start_timer(current_time, new_time);
+ pthread_sleep = pthread_run;
+ pthread_run->sll = NULL;
+ }
+}
+
+/* ==========================================================================
+ * sleep_wakeup()
+ *
+ * This routine is called by the interrupt handler, which has already
+ * locked the current kthread. Since all threads on this list are owned
+ * by the current kthread, rescheduling won't be a problem.
+ */
+int sleep_spurious_wakeup = 0;
+int sleep_wakeup()
+{
+ struct pthread *pthread_sleep_next;
+ struct timespec current_time;
+ int ret = 0;
+
+ if (pthread_sleep == NULL) {
+ return(NOTOK);
+ }
+
+ machdep_gettimeofday(&current_time);
+ if (sleep_compare_time(&(pthread_sleep->wakeup_time), &current_time) > 0) {
+ machdep_start_timer(&current_time, &(pthread_sleep->wakeup_time));
+ sleep_spurious_wakeup++;
+ return(OK);
+ }
+
+ do {
+ if (pthread_sleep->pthread_priority > ret) {
+ ret = pthread_sleep->pthread_priority;
+ }
+
+ /*
+ * Clean up removed thread and start it running again.
+ *
+ * Note: It is VERY important to remove the thread form the
+ * current queue before putting it on the run queue.
+ * Both queues use pthread_sleep->next, and the thread that points
+ * to pthread_sleep should point to pthread_sleep->next then
+ * pthread_sleep should be put on the run queue.
+ */
+ if ((SET_PF_DONE_EVENT(pthread_sleep)) == OK) {
+ if (pthread_sleep->queue)
+ pthread_queue_remove(pthread_sleep->queue, pthread_sleep);
+ pthread_prio_queue_enq(pthread_current_prio_queue, pthread_sleep);
+ pthread_sleep->state = PS_RUNNING;
+ }
+
+ pthread_sleep_next = pthread_sleep->sll;
+ pthread_sleep->sll = NULL;
+
+ if ((pthread_sleep = pthread_sleep_next) == NULL) {
+ /* No more threads on sleep queue */
+ return(ret);
+ }
+ } while (sleep_compare_time(&(pthread_sleep->wakeup_time), &(current_time)) <= 0);
+
+ /* Start timer for next time interval */
+ machdep_start_timer(&current_time, &(pthread_sleep->wakeup_time));
+ return(ret);
+}
+
+
+/* ==========================================================================
+ * __sleep()
+ */
+void __sleep(struct timespec * time_to_sleep)
+{
+ struct pthread *pthread_sleep_prev;
+ struct timespec current_time, wakeup_time;
+
+ pthread_sched_prevent();
+
+ /* Get real time */
+ machdep_gettimeofday(&current_time);
+ wakeup_time.tv_sec = current_time.tv_sec + time_to_sleep->tv_sec;
+ wakeup_time.tv_nsec = current_time.tv_nsec + time_to_sleep->tv_nsec;
+
+ sleep_schedule(&current_time, &wakeup_time);
+
+ /* Reschedule thread */
+ SET_PF_WAIT_EVENT(pthread_run);
+ SET_PF_AT_CANCEL_POINT(pthread_run); /* This is a cancel point */
+ pthread_resched_resume(PS_SLEEP_WAIT);
+ CLEAR_PF_AT_CANCEL_POINT(pthread_run); /* No longer at cancel point */
+ CLEAR_PF_DONE_EVENT(pthread_run);
+
+ /* Return actual time slept */
+ time_to_sleep->tv_sec = pthread_run->wakeup_time.tv_sec;
+ time_to_sleep->tv_nsec = pthread_run->wakeup_time.tv_nsec;
+}
+
+/* ==========================================================================
+ * pthread_nanosleep()
+ */
+unsigned int pthread_nanosleep(unsigned int nseconds)
+{
+ struct timespec time_to_sleep;
+
+ if (nseconds) {
+ time_to_sleep.tv_nsec = nseconds;
+ time_to_sleep.tv_sec = 0;
+ __sleep(&time_to_sleep);
+ nseconds = time_to_sleep.tv_nsec;
+ }
+ return(nseconds);
+}
+
+/* ==========================================================================
+ * usleep()
+ */
+void usleep(unsigned int useconds)
+{
+ struct timespec time_to_sleep;
+
+ if (useconds) {
+ time_to_sleep.tv_nsec = (useconds % 1000000) * 1000;
+ time_to_sleep.tv_sec = useconds / 1000000;
+ __sleep(&time_to_sleep);
+ }
+}
+
+/* ==========================================================================
+ * sleep()
+ */
+unsigned int sleep(unsigned int seconds)
+{
+ struct timespec time_to_sleep;
+
+ if (seconds) {
+ time_to_sleep.tv_sec = seconds;
+ time_to_sleep.tv_nsec = 0;
+ __sleep(&time_to_sleep);
+ seconds = time_to_sleep.tv_sec;
+ }
+ return(seconds);
+}
+
+/* ==========================================================================
+ * sleep_cancel()
+ *
+ * Cannot be called while kernel is locked.
+ * Does not wake sleeping thread up, just remove it from the sleep queue.
+ */
+int sleep_cancel(struct pthread * pthread)
+{
+ struct timespec current_time, delta_time;
+ struct pthread * pthread_last;
+ int rval = NOTOK;
+
+ /* Lock sleep queue, Note this may be on a different kthread queue */
+ pthread_sched_prevent();
+
+ if (pthread_sleep) {
+ if (pthread == pthread_sleep) {
+ rval = OK;
+ machdep_stop_timer(&delta_time);
+ if (pthread_sleep = pthread_sleep->sll) {
+ current_time.tv_sec = delta_time.tv_sec;
+ current_time.tv_nsec = delta_time.tv_nsec;
+ current_time.tv_sec += pthread_sleep->wakeup_time.tv_sec;
+ current_time.tv_nsec += pthread_sleep->wakeup_time.tv_nsec;
+ while (current_time.tv_nsec > 1000000000) {
+ current_time.tv_nsec -= 1000000000;
+ current_time.tv_sec++;
+ }
+ machdep_start_timer(&(current_time),
+ &(pthread_sleep->wakeup_time));
+ }
+ } else {
+ for (pthread_last = pthread_sleep; pthread_last;
+ pthread_last = pthread_last->sll) {
+ if (pthread_last->sll == pthread) {
+ pthread_last->sll = pthread->sll;
+ rval = OK;
+ break;
+ }
+ }
+ }
+ }
+
+ pthread_sched_resume();
+ pthread->sll = NULL;
+ return(rval);
+}
diff --git a/mit-pthreads/pthreads/specific.c b/mit-pthreads/pthreads/specific.c
new file mode 100644
index 00000000000..898f9b0cd1b
--- /dev/null
+++ b/mit-pthreads/pthreads/specific.c
@@ -0,0 +1,198 @@
+/* ==== specific.c =======================================================
+ * Copyright (c) 1994 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Description : Pthread thread specific data management.
+ *
+ * 1.20 94/03/30 proven
+ * -Started coding this file.
+ */
+
+#ifndef lint
+static const char rcsid[] = "$Id$";
+#endif
+
+#include <errno.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <string.h>
+
+static struct pthread_key key_table[PTHREAD_DATAKEYS_MAX];
+static pthread_mutex_t key_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+/* ==========================================================================
+ * pthread_key_create()
+ */
+int pthread_key_create(pthread_key_t *key, void (*destructor)(void *))
+{
+ pthread_mutex_lock(&key_mutex);
+ for ((*key) = 0; (*key) < PTHREAD_DATAKEYS_MAX; (*key)++) {
+ if (key_table[(*key)].count == 0) {
+ key_table[(*key)].count++;
+ key_table[(*key)].destructor = destructor;
+ pthread_mutex_init(&(key_table[(*key)].mutex), NULL);
+ pthread_mutex_unlock(&key_mutex);
+ return(OK);
+ }
+ }
+ pthread_mutex_unlock(&key_mutex);
+ return(EAGAIN);
+}
+
+/* ==========================================================================
+ * pthread_key_delete()
+ */
+int pthread_key_delete(pthread_key_t key)
+{
+ int ret;
+
+ if (key < PTHREAD_DATAKEYS_MAX) {
+ pthread_mutex_lock(&(key_table[key].mutex));
+ switch (key_table[key].count) {
+ case 1:
+ pthread_mutex_destroy(&(key_table[key].mutex));
+ key_table[key].destructor = NULL;
+ key_table[key].count = 0;
+ case 0:
+ ret = OK;
+ break;
+ default:
+ ret = EBUSY;
+ }
+ pthread_mutex_unlock(&(key_table[key].mutex));
+ } else {
+ ret = EINVAL;
+ }
+ return(ret);
+}
+
+/* ==========================================================================
+ * pthread_cleanupspecific()
+ */
+void pthread_cleanupspecific(void)
+{
+ void * data;
+ int key;
+ int itr;
+
+ pthread_mutex_lock(&key_mutex);
+ for (itr = 0; itr < _POSIX_THREAD_DESTRUTOR_ITERATIONS; itr++) {
+ for (key = 0; key < PTHREAD_DATAKEYS_MAX; key++) {
+ if (pthread_run->specific_data_count) {
+ if (pthread_run->specific_data[key]) {
+ data = (void *)pthread_run->specific_data[key];
+ pthread_run->specific_data[key] = NULL;
+ pthread_run->specific_data_count--;
+ if (key_table[key].destructor) {
+ pthread_mutex_unlock(&key_mutex);
+ key_table[key].destructor(data);
+ pthread_mutex_lock(&key_mutex);
+ }
+ key_table[key].count--;
+ }
+ } else {
+ free(pthread_run->specific_data);
+ pthread_mutex_unlock(&key_mutex);
+ return;
+ }
+ }
+ }
+ free(pthread_run->specific_data);
+ pthread_mutex_unlock(&key_mutex);
+}
+
+static inline const void ** pthread_key_allocate_data(void)
+{
+ const void ** new_data;
+ if(new_data = (const void**)malloc(sizeof(void *) * PTHREAD_DATAKEYS_MAX)) {
+ memset((void *)new_data, 0, sizeof(void *) * PTHREAD_DATAKEYS_MAX);
+ }
+ return(new_data);
+}
+
+/* ==========================================================================
+ * pthread_setspecific()
+ */
+int pthread_setspecific(pthread_key_t key, const void * value)
+{
+ int ret;
+
+ if ((pthread_run->specific_data) ||
+ (pthread_run->specific_data = pthread_key_allocate_data())) {
+ if ((key < PTHREAD_DATAKEYS_MAX) && (key_table)) {
+ pthread_mutex_lock(&(key_table[key].mutex));
+ if (key_table[key].count) {
+ if (pthread_run->specific_data[key] == NULL) {
+ if (value != NULL) {
+ pthread_run->specific_data_count++;
+ key_table[key].count++;
+ }
+ } else {
+ if (value == NULL) {
+ pthread_run->specific_data_count--;
+ key_table[key].count--;
+ }
+ }
+ pthread_run->specific_data[key] = value;
+ ret = OK;
+ } else {
+ ret = EINVAL;
+ }
+ pthread_mutex_unlock(&(key_table[key].mutex));
+ } else {
+ ret = EINVAL;
+ }
+ } else {
+ ret = ENOMEM;
+ }
+ return(ret);
+}
+
+/* ==========================================================================
+ * pthread_getspecific()
+ */
+void * pthread_getspecific(pthread_key_t key)
+{
+ void *ret;
+
+ if ((pthread_run->specific_data) && (key < PTHREAD_DATAKEYS_MAX)
+ && (key_table)) {
+ pthread_mutex_lock(&(key_table[key].mutex));
+ if (key_table[key].count) {
+ ret = (void *)pthread_run->specific_data[key];
+ } else {
+ ret = NULL;
+ }
+ pthread_mutex_unlock(&(key_table[key].mutex));
+ } else {
+ ret = NULL;
+ }
+ return(ret);
+}
diff --git a/mit-pthreads/pthreads/stat.c b/mit-pthreads/pthreads/stat.c
new file mode 100644
index 00000000000..f18b7c6bd24
--- /dev/null
+++ b/mit-pthreads/pthreads/stat.c
@@ -0,0 +1,116 @@
+/* ==== stat.c ============================================================
+ * Copyright (c) 1995 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Description : All the syscalls dealing with fds.
+ *
+ * 1.00 93/05/27 proven
+ * -Started coding this file.
+ */
+
+#ifndef lint
+static const char rcsid[] = "$Id$";
+#endif
+
+#include <pthread.h>
+#include <errno.h>
+
+struct stat;
+struct statfs;
+
+/* ==========================================================================
+ * fstat()
+ *
+ * Might want to indirect this.
+ */
+int fstat(int fd, struct stat *buf)
+{
+ int ret;
+
+ if ((ret = fd_lock(fd, FD_READ, NULL)) == OK) {
+ if ((ret = machdep_sys_fstat(fd_table[fd]->fd.i, buf)) < OK) {
+ SET_ERRNO(-ret);
+ ret = NOTOK;
+ }
+ fd_unlock(fd, FD_READ);
+ }
+ return(ret);
+}
+
+/* ==========================================================================
+ * stat()
+ */
+int stat(const char * path, struct stat * buf)
+{
+ int ret;
+
+ if ((ret = machdep_sys_stat(path, buf)) < OK) {
+ SET_ERRNO(-ret);
+ ret = NOTOK;
+ }
+ return(ret);
+
+}
+
+/* ==========================================================================
+ * lstat()
+ */
+int lstat(const char * path, struct stat * buf)
+{
+ int ret;
+
+ if ((ret = machdep_sys_lstat(path, buf)) < OK) {
+ SET_ERRNO(-ret);
+ ret = NOTOK;
+ }
+ return(ret);
+
+}
+
+#ifdef HAVE_SYSCALL_FSTATFS
+/* ==========================================================================
+ * fstatfs()
+ *
+ * Might want to indirect this.
+ */
+int fstatfs(int fd, struct statfs *buf)
+{
+ int ret;
+
+ if ((ret = fd_lock(fd, FD_READ, NULL)) == OK) {
+ if ((ret = machdep_sys_fstatfs(fd_table[fd]->fd.i, buf)) < OK) {
+ SET_ERRNO(-ret);
+ ret = NOTOK;
+ }
+ fd_unlock(fd, FD_READ);
+ }
+ return(ret);
+}
+#endif
diff --git a/mit-pthreads/pthreads/wait.c b/mit-pthreads/pthreads/wait.c
new file mode 100644
index 00000000000..9f0418ca8a1
--- /dev/null
+++ b/mit-pthreads/pthreads/wait.c
@@ -0,0 +1,159 @@
+/* ==== wait.c ============================================================
+ * Copyright (c) 1994 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Description : All the appropriate wait routines.
+ *
+ * 1.38 94/06/13 proven
+ * -Started coding this file.
+ *
+ */
+
+#ifndef lint
+static const char rcsid[] = "$Id$";
+#endif
+
+#include <pthread.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <pthread/posix.h>
+#include <sys/compat.h>
+#include <sys/wait.h>
+
+/* This is an UGLY hack to get wait to compile, something better is needed. */
+/* #define _POSIX_SOURCE
+#undef _POSIX_SOURCE
+*/
+
+struct pthread_queue wait_queue = { NULL, NULL, NULL };
+extern void sig_handler_real();
+
+/* ==========================================================================
+ * wait_wakeup()
+ *
+ * This routine is called by the interrupt handler which has locked
+ * the current kthread semaphore. Since only threads owned by the
+ * current kthread can be queue here, no additional locks are necessary.
+ */
+int wait_wakeup()
+{
+ struct pthread *pthread;
+ int ret = 0;
+
+ if (pthread = pthread_queue_deq(& wait_queue)) {
+ /* Wakeup all threads, and enqueue them on the run queue */
+ do {
+ pthread->state = PS_RUNNING;
+ if (pthread->pthread_priority > ret) {
+ ret = pthread->pthread_priority;
+ }
+ pthread_prio_queue_enq(pthread_current_prio_queue, pthread);
+ } while (pthread = pthread_queue_deq(&wait_queue));
+ return(ret);
+ }
+ return(NOTOK);
+}
+
+/* ==========================================================================
+ * For the wait calls, it is important that the current kthread is locked
+ * before the apropriate wait syscall is preformed. This way we ensure
+ * that there is never a case where a thread is waiting for a child but
+ * missed the interrupt for that child.
+ * Patched by William S. Lear 1997-02-02
+ */
+
+/* ==========================================================================
+ * waitpid()
+ */
+pid_t waitpid(pid_t pid, int *status, int options)
+{
+ pid_t ret;
+
+ pthread_sched_prevent();
+ ret = machdep_sys_waitpid(pid, status, options | WNOHANG);
+ /* If we are not doing nohang, try again, else return immediately */
+ if (!(options & WNOHANG)) {
+ while (ret == OK) {
+ /* Enqueue thread on wait queue */
+ pthread_queue_enq(&wait_queue, pthread_run);
+
+ /* reschedule unlocks scheduler */
+ SET_PF_AT_CANCEL_POINT(pthread_run); /* This is a cancel point */
+ pthread_resched_resume(PS_WAIT_WAIT);
+ CLEAR_PF_AT_CANCEL_POINT(pthread_run); /* No longer at cancel point */
+
+ pthread_sched_prevent();
+
+ ret = machdep_sys_waitpid(pid, status, options | WNOHANG);
+ }
+ }
+ pthread_sched_resume();
+ return(ret);
+}
+
+/* ==========================================================================
+ * wait3()
+ * Patched by Monty 1997-02-02
+ */
+pid_t wait3(__WAIT_STATUS status, int options, void * rusage)
+{
+ semaphore * lock;
+ pid_t ret;
+
+ pthread_sched_prevent();
+ ret = machdep_sys_wait3(status, options | WNOHANG, rusage);
+ /* If we are not doing nohang, try again, else return immediately */
+ if (!(options & WNOHANG)) {
+ while (ret == OK) {
+ /* Enqueue thread on wait queue */
+ pthread_queue_enq(&wait_queue, pthread_run);
+
+ /* reschedule unlocks scheduler */
+ SET_PF_AT_CANCEL_POINT(pthread_run); /* This is a cancel point */
+ pthread_resched_resume(PS_WAIT_WAIT);
+ CLEAR_PF_AT_CANCEL_POINT(pthread_run); /* No longer at cancel point */
+
+ pthread_sched_prevent();
+
+ machdep_sys_wait3(status, options | WNOHANG, rusage);
+ }
+ }
+ pthread_sched_resume();
+ return(ret);
+}
+
+/* ==========================================================================
+ * wait()
+ */
+pid_t wait(__WAIT_STATUS status)
+{
+ return(waitpid((pid_t)-1, (int *)status, 0));
+}
diff --git a/mit-pthreads/pthreads/wrapper.c b/mit-pthreads/pthreads/wrapper.c
new file mode 100644
index 00000000000..6e3f4478fcf
--- /dev/null
+++ b/mit-pthreads/pthreads/wrapper.c
@@ -0,0 +1,149 @@
+/* ==== wrapper.c ============================================================
+ * Copyright (c) 1994 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Description : Wrapper functions for syscalls that only need errno redirected
+ *
+ * 1.4x 94/07/23 proven
+ * -Started coding this file.
+ */
+
+#ifndef lint
+static const char rcsid[] = "$Id$";
+#endif
+
+#include "config.h"
+#include <pthread.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <pthread/posix.h>
+
+/* ==========================================================================
+ * link()
+ */
+int link(const char * name1, const char * name2)
+{
+ int ret;
+
+ if ((ret = machdep_sys_link(name1, name2)) < OK) {
+ SET_ERRNO(-ret);
+ }
+ return(ret);
+
+}
+
+/* ==========================================================================
+ * unlink()
+ */
+int unlink(const char * path)
+{
+ int ret;
+
+ if ((ret = machdep_sys_unlink(path)) < OK) {
+ SET_ERRNO(-ret);
+ }
+ return(ret);
+
+}
+
+/* ==========================================================================
+ * chdir()
+ */
+int chdir(const char * path)
+{
+ int ret;
+
+ if ((ret = machdep_sys_chdir(path)) < OK) {
+ SET_ERRNO(-ret);
+ }
+ return(ret);
+
+}
+
+/* ==========================================================================
+ * chmod()
+ */
+int chmod(const char * path, mode_t mode)
+{
+ int ret;
+
+ if ((ret = machdep_sys_chmod(path, mode)) < OK) {
+ SET_ERRNO(-ret);
+ }
+ return(ret);
+
+}
+
+/* ==========================================================================
+ * chown()
+ */
+int chown(const char * path, uid_t owner, gid_t group)
+{
+ int ret;
+
+ if ((ret = machdep_sys_chown(path, owner, group)) < OK) {
+ SET_ERRNO(-ret);
+ }
+ return(ret);
+
+}
+
+/* ==========================================================================
+ * rename()
+ */
+int rename(const char * name1, const char * name2)
+{
+ int ret;
+
+ if ((ret = machdep_sys_rename(name1, name2)) < OK) {
+ SET_ERRNO(-ret);
+ }
+ return(ret);
+
+}
+
+
+/* ==========================================================================
+ * chroot()
+ */
+
+#ifdef HAVE_SYSCALL_CHROOT
+int chroot(const char * name)
+{
+ int ret;
+
+ if ((ret = machdep_sys_chroot(name)) < OK) {
+ SET_ERRNO(-ret);
+ }
+ return(ret);
+
+}
+#endif
diff --git a/mit-pthreads/pthreads/writev.c b/mit-pthreads/pthreads/writev.c
new file mode 100644
index 00000000000..9823d5ad201
--- /dev/null
+++ b/mit-pthreads/pthreads/writev.c
@@ -0,0 +1,89 @@
+/* ==== writev.c ============================================================
+ * Copyright (c) 1995 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Description : Implementation of writev().
+ *
+ * 1.00 95/06/19 proven
+ * -Started coding this file.
+ */
+
+#ifndef lint
+static const char rcsid[] = "$Id$";
+#endif
+
+#include "config.h"
+
+#ifndef HAVE_SYSCALL_WRITEV
+
+#include <errno.h>
+#include <unistd.h>
+#include <sys/uio.h>
+#include <sys/types.h>
+
+/* ==========================================================================
+ * machdep_sys_writev()
+ *
+ * modified from the GNU C Library posix/writev.c
+ */
+int machdep_sys_writev(int fd, struct iovec * vector, int count)
+{
+ size_t bytes, i;
+ char *buffer;
+ int ret;
+
+ /* Find the total number of bytes to be written. */
+ for (bytes = 0, i = 0; i < count; ++i)
+ bytes += vector[i].iov_len;
+
+ if (bytes) {
+ /*
+ * Allocate a temporary buffer to hold the data.
+ * Don't use alloca because threads tend to have smaller stacks.
+ */
+ if ((buffer = (char *)malloc(bytes)) == NULL) {
+ return(-ENOMEM);
+ }
+ /* Copy the data from memory specified by VECTOR to BUFFER */
+ for (ret = 0, i = 0; i < count; ++i) {
+ memcpy(buffer + ret, vector[i].iov_base, vector[i].iov_len);
+ ret += vector[i].iov_len;
+ }
+ } else {
+ buffer = NULL;
+ }
+
+ ret = (int)machdep_sys_write(fd, buffer, bytes);
+ if (buffer)
+ free(buffer);
+ return(ret);
+}
+
+#endif
diff --git a/mit-pthreads/scripts/GNUmakefile.inc b/mit-pthreads/scripts/GNUmakefile.inc
new file mode 100755
index 00000000000..6309f28ca55
--- /dev/null
+++ b/mit-pthreads/scripts/GNUmakefile.inc
@@ -0,0 +1,24 @@
+VPATH := $(VPATH):${srcdir}/scripts
+SCRIPTS= pgcc pg++
+
+abspath := $(shell pwd)
+
+all-bin: $(SCRIPTS)
+
+pgcc: pgcc.sh
+ sed -e 's!EXEC_PREFIX!$(exec_prefix)!g' \
+ -e 's!BUILD_PREFIX!$(abspath)!g' \
+ -e 's!SRC_PREFIX!$(srcdir)!g' \
+ -e 's!COMPILER!gcc!g' \
+ < $(srcdir)/scripts/pgcc.sh > pgcc.new
+ chmod a+x pgcc.new
+ mv -f pgcc.new pgcc
+
+pg++: pgcc.sh
+ sed -e 's!EXEC_PREFIX!$(exec_prefix)!g' \
+ -e 's!BUILD_PREFIX!$(abspath)!g' \
+ -e 's!SRC_PREFIX!$(srcdir)!g' \
+ -e 's!COMPILER!g++!g' \
+ < $(srcdir)/scripts/pgcc.sh > pg++.new
+ chmod a+x pg++.new
+ mv -f pg++.new pg++
diff --git a/mit-pthreads/scripts/Makefile.inc b/mit-pthreads/scripts/Makefile.inc
new file mode 100644
index 00000000000..441f6b51d29
--- /dev/null
+++ b/mit-pthreads/scripts/Makefile.inc
@@ -0,0 +1,30 @@
+.PATH : ${srcdir}/scripts
+SCRIPTS= pgcc pg++
+
+abspath != pwd
+
+all-bin: $(SCRIPTS)
+
+#
+# Objects go in the obj directory for both BSD and GNU make but these
+# scripts get put in the obj dir for BSD and the root dir for GNU.
+#
+pgcc: pgcc.sh
+ sed -e 's!EXEC_PREFIX!$(exec_prefix)!g' \
+ -e 's!BUILD_PREFIX!$(.CURDIR)!g' \
+ -e 's!SRC_PREFIX!$(srcdir)!g' \
+ -e 's!COMPILER!gcc!g' \
+ < $(srcdir)/scripts/pgcc.sh > pgcc.new
+ chmod a+x pgcc.new
+ mv -f pgcc.new pgcc
+ ln -fs obj/pgcc ../pgcc
+
+pg++: pgcc.sh
+ sed -e 's!EXEC_PREFIX!$(exec_prefix)!g' \
+ -e 's!BUILD_PREFIX!$(.CURDIR)!g' \
+ -e 's!SRC_PREFIX!$(srcdir)!g' \
+ -e 's!COMPILER!g++!g' \
+ < $(srcdir)/scripts/pgcc.sh > pg++.new
+ chmod a+x pg++.new
+ mv -f pg++.new pg++
+ ln -fs obj/pg++ ../pg++
diff --git a/mit-pthreads/scripts/pgcc.sh b/mit-pthreads/scripts/pgcc.sh
new file mode 100755
index 00000000000..6bd6cbeccdb
--- /dev/null
+++ b/mit-pthreads/scripts/pgcc.sh
@@ -0,0 +1,32 @@
+#!/bin/sh
+
+pthreads_root=EXEC_PREFIX
+build_root=BUILD_PREFIX
+src_root=SRC_PREFIX
+
+include_dir='-I$pthreads_root/include'
+lib_dir='-L$pthreads_root/lib'
+libs='-lpthread -lm -lgcc -lpthread'
+
+# Might be a good idea to also provide a way to override pthreads_root
+# so that we can use this script in the build tree, before installation.
+if arg="$1" ; then
+ case $arg in
+ -notinstalled)
+ include_dir='-I$build_root/include -I$src_root/include'
+ lib_dir='-L$build_root/obj'
+ shift
+ ;;
+ esac
+fi
+
+for arg in "$@" ; do
+ case $arg in
+ -nostdinc) include_dir= ;;
+ -nostdlib | -c) libs= ;;
+ esac
+done
+
+# Include the -L option in any case, just in case the user provided the
+# names of some libraries we've built threaded versions of.
+eval exec COMPILER '"$@"' $include_dir $lib_dir $libs
diff --git a/mit-pthreads/stdio/GNUmakefile.inc b/mit-pthreads/stdio/GNUmakefile.inc
new file mode 100755
index 00000000000..7cb1371661d
--- /dev/null
+++ b/mit-pthreads/stdio/GNUmakefile.inc
@@ -0,0 +1,26 @@
+
+# from: @(#)Makefile.inc 5.7 (Berkeley) 6/27/91
+# $Id$
+
+# Thread safe stdio sources
+VPATH:= ${VPATH}:${srcdir}/stdio
+
+SRCS:= clrerr.c fclose.c fdopen.c feof.c ferror.c fflush.c fgetc.c \
+ fgetline.c fgetpos.c fgets.c fileno.c findfp.c flags.c fopen.c \
+ fpurge.c fputc.c fputs.c fread.c freopen.c fscanf.c \
+ fseek.c fsetpos.c ftell.c funopen.c fvwrite.c fwalk.c fwrite.c \
+ getc.c getchar.c gets.c getw.c makebuf.c perror.c putc.c \
+ putchar.c puts.c putw.c refill.c remove.c rewind.c rget.c scanf.c \
+ setbuf.c setbuffer.c setvbuf.c sscanf.c \
+ stdio.c ungetc.c \
+ vfscanf.c vscanf.c vsscanf.c \
+ wsetup.c putc_unlocked.c putchar_unlocked.c getc_unlocked.c \
+ getchar_unlocked.c strerror.c wbuf.c xprintf.c $(SRCS)
+
+# tempnam.c tmpnam.c tmpfile.c
+#
+# SRCS:= sys_errlist.c $(SRCS)
+# sys_errlist.c: make_errlist
+# (FOO=`pwd`; cd ${srcdir}/stdio/make_errlist; \
+# $(MAKE) CC=$(CC) srcdir=${srcdir} objdir=$${FOO})
+# `pwd`/make_errlist;
diff --git a/mit-pthreads/stdio/Makefile.inc b/mit-pthreads/stdio/Makefile.inc
new file mode 100644
index 00000000000..10c598c328f
--- /dev/null
+++ b/mit-pthreads/stdio/Makefile.inc
@@ -0,0 +1,20 @@
+
+# from: @(#)Makefile.inc 5.7 (Berkeley) 6/27/91
+# $Id$
+
+# Thread safe stdio sources
+.PATH: ${srcdir}/stdio
+
+# SRCS+= tempnam.c tmpfile.c tmpnam.c
+
+SRCS+= clrerr.c fclose.c fdopen.c feof.c ferror.c fflush.c fgetc.c \
+ fgetline.c fgetpos.c fgets.c fileno.c findfp.c flags.c fopen.c \
+ fpurge.c fputc.c fputs.c fread.c freopen.c fscanf.c \
+ fseek.c fsetpos.c ftell.c funopen.c fvwrite.c fwalk.c fwrite.c \
+ getc.c getchar.c gets.c getw.c makebuf.c perror.c putc.c \
+ putchar.c puts.c putw.c refill.c remove.c rewind.c rget.c scanf.c \
+ setbuf.c setbuffer.c setvbuf.c sscanf.c \
+ stdio.c ungetc.c \
+ vfscanf.c vscanf.c vsscanf.c \
+ wsetup.c putc_unlocked.c putchar_unlocked.c getc_unlocked.c \
+ getchar_unlocked.c strerror.c wbuf.c xprintf.c
diff --git a/mit-pthreads/stdio/README b/mit-pthreads/stdio/README
new file mode 100755
index 00000000000..8e4c07909e9
--- /dev/null
+++ b/mit-pthreads/stdio/README
@@ -0,0 +1,41 @@
+Copyright (c) 1993, 1994 Chris Provenzano. All rights reserved.
+
+This is a threadsafe stdio based on the BSD stdio written by Chris Torek.
+This product includes software developed by the Univeristy of California,
+Berkeley and its contributors.
+
+INCLUDE FILES AND PORTING
+To continue to make this package portable, some basic rules on includes
+files must be followed.
+
+pthread.h should be included first (if it is to be included).
+stdio.h should be included.
+
+INTERNAL LOCKING
+1. All functions that can be called by the user must have flockfile() at the
+ begining and a funlockfile() at the end. The routine flockfile() is a
+ counting mutex, The thread that owns the lock can call flockfile() as
+ many times as it wants, but must call an equal number of funlockfile()
+ before the lock will be released.
+2. All functions starting with __ shouldn't need addtional locking.
+3. Anything that writes the variable __sglue should lock __sfp_mutex,
+ check __sfp_state, and do a condion wait if it is set.
+4. Anything that checks fp->_flag for valididity should also lock
+ __sfp_mutex.
+5. Anything that reads the variable __sglue should lock __sfp_mutex, increment
+ __sfp_state, and then unlock the mutex. At function return it should
+ lock the mutex again decrement __sfp_state and check if zero. If so
+ do a cond_signal, and unlock the mutex.
+6. The functions fopen, fdopen, and freopen are the only functions that
+ will change a fp->_file
+7. fdopen and fopen both allocate the next fp by locking __sfp_mutex
+ checking fp->_flags and then setting it if free.
+8. freopen tries to preserve fp->_file. It sets __sfp_mutex, then it
+ tries to lock fp->_file and close it.
+9. __sinit is done with a pthread_once routine.
+
+
+
+Things to do.
+
+Fix printf so it uses the ininf function.
diff --git a/mit-pthreads/stdio/clrerr.c b/mit-pthreads/stdio/clrerr.c
new file mode 100644
index 00000000000..e809cfb8efd
--- /dev/null
+++ b/mit-pthreads/stdio/clrerr.c
@@ -0,0 +1,51 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * Copyright (c) 1993, 1994 Chris Provenzano.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)clrerr.c 5.3 (Berkeley) 1/20/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <pthread.h>
+#include <stdio.h>
+
+void clearerr(FILE *fp)
+{
+ flockfile(fp);
+ fp->_flags &= ~(__SERR|__SEOF);
+ funlockfile(fp);
+}
diff --git a/mit-pthreads/stdio/fclose.c b/mit-pthreads/stdio/fclose.c
new file mode 100644
index 00000000000..c5db0808f6a
--- /dev/null
+++ b/mit-pthreads/stdio/fclose.c
@@ -0,0 +1,73 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * Copyright (c) 1993, 1994 Chris Provenzano.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)fclose.c 5.2 (Berkeley) 2/1/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <pthread.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "local.h"
+
+/* Do not reset the fd */
+fclose(fp)
+ register FILE *fp;
+{
+ register int r;
+
+ if (fp->_flags) {
+ flockfile(fp);
+ r = fp->_flags & __SWR ? __sflush(fp) : 0;
+ if (fp->_flags & __SMBF)
+ free((char *)fp->_bf._base);
+ if (HASUB(fp))
+ FREEUB(fp);
+ if (HASLB(fp))
+ FREELB(fp);
+ if (__sclose(fp) < 0)
+ r = EOF;
+/* funlockfile(fp); Don't unlock. The close() already has. */
+ fp->_file = -1;
+ fp->_flags = 0; /* release this FILE for reuse, DO THIS LAST */
+ return(r);
+ }
+ errno = EBADF;
+ return(EOF);
+}
diff --git a/mit-pthreads/stdio/fdopen.c b/mit-pthreads/stdio/fdopen.c
new file mode 100644
index 00000000000..4c006f24c7c
--- /dev/null
+++ b/mit-pthreads/stdio/fdopen.c
@@ -0,0 +1,93 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * Copyright (c) 1993, 1994 Chris Provenzano.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)fdopen.c 5.6 (Berkeley) 2/24/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <pthread.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+#include "local.h"
+
+extern pthread_mutex_t __sfp_mutex;
+extern pthread_cond_t __sfp_cond;
+extern int __sfp_state;
+
+FILE *fdopen(int fd, const char *mode)
+{
+ register FILE *fp;
+ int flags, oflags, fdflags, tmp;
+
+ if ((flags = __sflags(mode, &oflags)) == 0)
+ return (NULL);
+
+ /* Make sure the mode the user wants is a subset of the actual mode. */
+ if ((fdflags = fcntl(fd, F_GETFL, 0)) < 0)
+ return (NULL);
+ tmp = fdflags & O_ACCMODE;
+ if (tmp != O_RDWR && (tmp != (oflags & O_ACCMODE))) {
+ errno = EINVAL;
+ return (NULL);
+ }
+
+ __sinit ();
+ pthread_mutex_lock(&__sfp_mutex);
+ while (__sfp_state) {
+ pthread_cond_wait(&__sfp_cond, &__sfp_mutex);
+ }
+
+ if (fp = __sfp()) {
+ fp->_flags = flags;
+
+ /*
+ * If opened for appending, but underlying descriptor does not have
+ * O_APPEND bit set, assert __SAPP so that __swrite() will lseek to
+ * end before each write.
+ */
+ if ((oflags & O_APPEND) && !(fdflags & O_APPEND))
+ fp->_flags |= __SAPP;
+ fp->_file = fd;
+
+ }
+ pthread_mutex_unlock(&__sfp_mutex);
+ return (fp);
+}
diff --git a/mit-pthreads/stdio/feof.c b/mit-pthreads/stdio/feof.c
new file mode 100644
index 00000000000..10946fee581
--- /dev/null
+++ b/mit-pthreads/stdio/feof.c
@@ -0,0 +1,55 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * Copyright (c) 1993, 1994 Chris Provenzano.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)feof.c 5.1 (Berkeley) 1/20/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <pthread.h>
+#include <stdio.h>
+
+/*
+ * A subroutine version of the macro feof.
+ */
+#undef feof
+
+feof(fp)
+ FILE *fp;
+{
+ return (__sfeof(fp));
+}
diff --git a/mit-pthreads/stdio/ferror.c b/mit-pthreads/stdio/ferror.c
new file mode 100644
index 00000000000..b80ddab037e
--- /dev/null
+++ b/mit-pthreads/stdio/ferror.c
@@ -0,0 +1,55 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * Copyright (c) 1993, 1994 Chris Provenzano.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)ferror.c 5.1 (Berkeley) 1/20/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <pthread.h>
+#include <stdio.h>
+
+/*
+ * A subroutine version of the macro ferror.
+ */
+#undef ferror
+
+ferror(fp)
+ FILE *fp;
+{
+ return (__sferror(fp));
+}
diff --git a/mit-pthreads/stdio/fflush.c b/mit-pthreads/stdio/fflush.c
new file mode 100644
index 00000000000..766691045b5
--- /dev/null
+++ b/mit-pthreads/stdio/fflush.c
@@ -0,0 +1,98 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * Copyright (c) 1993, 1994 Chris Provenzano.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)fflush.c 5.1 (Berkeley) 1/20/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <pthread.h>
+#include <errno.h>
+#include <stdio.h>
+#include "local.h"
+
+/* Flush a single file, or (if fp is NULL) all files. */
+fflush(fp)
+ register FILE *fp;
+{
+ int retval;
+
+ if (fp == NULL)
+ return (__swalk_sflush());
+ flockfile(fp);
+
+ if ((fp->_flags & (__SWR | __SRW)) == 0) {
+ errno = EBADF;
+ retval = EOF;
+ } else {
+ retval = __sflush(fp);
+ }
+ funlockfile(fp);
+ return(retval);
+}
+
+__sflush(fp)
+ register FILE *fp;
+{
+ register unsigned char *p;
+ register int n, t;
+
+ t = fp->_flags;
+ if ((t & __SWR) == 0)
+ return (0);
+
+ if ((p = fp->_bf._base) == NULL)
+ return (0);
+
+ n = fp->_p - p; /* write this much */
+
+ /*
+ * Set these immediately to avoid problems with longjmp and to allow
+ * exchange buffering (via setvbuf) in user write function.
+ */
+ fp->_p = p;
+ fp->_w = t & (__SLBF|__SNBF) ? 0 : fp->_bf._size;
+
+ for (; n > 0; n -= t, p += t) {
+ t = __swrite(fp, (char *)p, n);
+ if (t <= 0) {
+ fp->_flags |= __SERR;
+ return (EOF);
+ }
+ }
+ return (0);
+}
diff --git a/mit-pthreads/stdio/fgetc.c b/mit-pthreads/stdio/fgetc.c
new file mode 100644
index 00000000000..c5eb2ee5986
--- /dev/null
+++ b/mit-pthreads/stdio/fgetc.c
@@ -0,0 +1,65 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * Copyright (c) 1993, 1994 Chris Provenzano.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)fgetc.c 5.3 (Berkeley) 1/20/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <pthread.h>
+#include <stdio.h>
+
+fgetc(fp)
+ FILE *fp;
+{
+ int ret;
+
+ flockfile(fp);
+ ret = __sgetc(fp);
+ funlockfile(fp);
+ return(ret);
+}
+
+int __getc(FILE *_p)
+{
+ int ret;
+ flockfile(_p);
+ ret = __sgetc(_p);
+ funlockfile(_p);
+ return(ret);
+}
+
diff --git a/mit-pthreads/stdio/fgetline.c b/mit-pthreads/stdio/fgetline.c
new file mode 100644
index 00000000000..219660612f1
--- /dev/null
+++ b/mit-pthreads/stdio/fgetline.c
@@ -0,0 +1,170 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * Copyright (c) 1993, 1994 Chris Provenzano.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)fgetline.c 5.2 (Berkeley) 5/4/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "local.h"
+
+/*
+ * Expand the line buffer. Return -1 on error.
+ * The `new size' does not account for a terminating '\0',
+ * so we add 1 here.
+ */
+__slbexpand(fp, newsize)
+ FILE *fp;
+ size_t newsize;
+{
+ void *p;
+
+ if (fp->_lb._size >= ++newsize)
+ return (0);
+ if ((p = realloc(fp->_lb._base, newsize)) == NULL)
+ return (-1);
+ fp->_lb._base = p;
+ fp->_lb._size = newsize;
+ return (0);
+}
+
+/*
+ * Get an input line. The returned pointer often (but not always)
+ * points into a stdio buffer. Fgetline smashes the newline (if any)
+ * in the stdio buffer; callers must not use it on streams that
+ * have `magic' setvbuf() games happening.
+ */
+char *
+fgetline(fp, lenp)
+ register FILE *fp;
+ size_t *lenp;
+{
+ register unsigned char *p;
+ register size_t len;
+ size_t off;
+
+ flockfile(fp);
+
+ /* make sure there is input */
+ if (fp->_r <= 0 && __srefill(fp)) {
+ if (lenp != NULL)
+ *lenp = 0;
+ funlockfile(fp);
+ return (NULL);
+ }
+
+ /* look for a newline in the input */
+ if ((p = memchr((void *)fp->_p, '\n', fp->_r)) != NULL) {
+ register char *ret;
+
+ /*
+ * Found one. Flag buffer as modified to keep
+ * fseek from `optimising' a backward seek, since
+ * the newline is about to be trashed. (We should
+ * be able to get away with doing this only if
+ * p is not pointing into an ungetc buffer, since
+ * fseek discards ungetc data, but this is the
+ * usual case anyway.)
+ */
+ ret = (char *)fp->_p;
+ len = p - fp->_p;
+ fp->_flags |= __SMOD;
+ *p = 0;
+ fp->_r -= len + 1;
+ fp->_p = p + 1;
+ if (lenp != NULL)
+ *lenp = len;
+ funlockfile(fp);
+ return (ret);
+ }
+
+ /*
+ * We have to copy the current buffered data to the line buffer.
+ *
+ * OPTIMISTIC is length that we (optimistically)
+ * expect will accomodate the `rest' of the string,
+ * on each trip through the loop below.
+ */
+#define OPTIMISTIC 80
+
+ for (len = fp->_r, off = 0;; len += fp->_r) {
+ register size_t diff;
+
+ /*
+ * Make sure there is room for more bytes.
+ * Copy data from file buffer to line buffer,
+ * refill file and look for newline. The
+ * loop stops only when we find a newline.
+ */
+ if (__slbexpand(fp, len + OPTIMISTIC))
+ goto error;
+ (void) memcpy((void *)(fp->_lb._base + off), (void *)fp->_p,
+ len - off);
+ off = len;
+ if (__srefill(fp))
+ break; /* EOF or error: return partial line */
+ if ((p = memchr((void *)fp->_p, '\n', fp->_r)) == NULL)
+ continue;
+
+ /* got it: finish up the line (like code above) */
+ fp->_flags |= __SMOD; /* soon */
+ diff = p - fp->_p;
+ len += diff;
+ if (__slbexpand(fp, len))
+ goto error;
+ (void) memcpy((void *)(fp->_lb._base + off), (void *)fp->_p, diff);
+ fp->_r -= diff + 1;
+ fp->_p = p + 1;
+ break;
+ }
+ if (lenp != NULL)
+ *lenp = len;
+ fp->_lb._base[len] = 0;
+
+ funlockfile(fp);
+ return ((char *)fp->_lb._base);
+
+error:
+ if (lenp != NULL)
+ *lenp = 0; /* ??? */
+ funlockfile(fp);
+ return (NULL); /* ??? */
+}
diff --git a/mit-pthreads/stdio/fgetpos.c b/mit-pthreads/stdio/fgetpos.c
new file mode 100644
index 00000000000..c81b48e3cc8
--- /dev/null
+++ b/mit-pthreads/stdio/fgetpos.c
@@ -0,0 +1,85 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * Copyright (c) 1993, 1994 Chris Provenzano.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)fgetpos.c 5.1 (Berkeley) 1/20/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <pthread.h>
+#include <unistd.h>
+#include <stdio.h>
+#include "local.h"
+
+fgetpos(fp, pos)
+ FILE *fp;
+ fpos_t *pos;
+{
+ flockfile(fp);
+
+ /*
+ * Find offset of underlying I/O object, then
+ * adjust for buffered bytes.
+ */
+ if (fp->_flags & __SOFF) {
+ *pos = fp->_offset;
+ } else {
+ *pos = __sseek(fp, (off_t)0, SEEK_CUR);
+ }
+
+ if (*pos != (fpos_t)-1) {
+ if (fp->_flags & __SRD) {
+ /*
+ * Reading. Any unread characters (including
+ * those from ungetc) cause the position to be
+ * smaller than that in the underlying object.
+ */
+ *pos -= fp->_r;
+ if (HASUB(fp))
+ *pos -= fp->_ur;
+ } else if (fp->_flags & __SWR && fp->_p != NULL) {
+ /*
+ * Writing. Any buffered characters cause the
+ * position to be greater than that in the
+ * underlying object.
+ */
+ *pos += fp->_p - fp->_bf._base;
+ }
+ }
+ funlockfile(fp);
+ return ((*pos) == (fpos_t)-1);
+}
diff --git a/mit-pthreads/stdio/fgets.c b/mit-pthreads/stdio/fgets.c
new file mode 100644
index 00000000000..5ee5c4d6608
--- /dev/null
+++ b/mit-pthreads/stdio/fgets.c
@@ -0,0 +1,110 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * Copyright (c) 1993, 1994 Chris Provenzano.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)fgets.c 5.4 (Berkeley) 5/4/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * Read at most n-1 characters from the given file.
+ * Stop when a newline has been read, or the count runs out.
+ * Return first argument, or NULL if no characters were read.
+ */
+char *
+fgets(buf, n, fp)
+ char *buf;
+ register size_t n;
+ register FILE *fp;
+{
+ register size_t len;
+ register char *s;
+ register unsigned char *p, *t;
+
+ if (n < 2) /* sanity check */
+ return (NULL);
+
+ flockfile(fp);
+ s = buf;
+ n--; /* leave space for NUL */
+ do {
+ /*
+ * If the buffer is empty, refill it.
+ */
+ if ((len = fp->_r) <= 0) {
+ if (__srefill(fp)) {
+ /* EOF/error: stop with partial or no line */
+ if (s == buf)
+ buf = NULL;
+ break;
+ }
+ len = fp->_r;
+ }
+ p = fp->_p;
+
+ /*
+ * Scan through at most n bytes of the current buffer,
+ * looking for '\n'. If found, copy up to and including
+ * newline, and stop. Otherwise, copy entire chunk
+ * and loop.
+ */
+ if (len > n)
+ len = n;
+ t = memchr((void *)p, '\n', len);
+ if (t != NULL) {
+ len = ++t - p;
+ fp->_r -= len;
+ fp->_p = t;
+ (void) memcpy((void *)s, (void *)p, len);
+ s += len;
+ break;
+ }
+ fp->_r -= len;
+ fp->_p += len;
+ (void) memcpy((void *)s, (void *)p, len);
+ s += len;
+ } while ((n -= len) != 0);
+
+ *s = 0;
+ funlockfile(fp);
+ return (buf);
+}
diff --git a/mit-pthreads/stdio/fileno.c b/mit-pthreads/stdio/fileno.c
new file mode 100644
index 00000000000..475bd509993
--- /dev/null
+++ b/mit-pthreads/stdio/fileno.c
@@ -0,0 +1,55 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * Copyright (c) 1993, 1994 Chris Provenzano.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)fileno.c 5.1 (Berkeley) 1/20/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <pthread.h>
+#include <stdio.h>
+
+/*
+ * A subroutine version of the macro fileno.
+ */
+#undef fileno
+
+fileno(fp)
+ FILE *fp;
+{
+ return (__sfileno(fp));
+}
diff --git a/mit-pthreads/stdio/findfp.c b/mit-pthreads/stdio/findfp.c
new file mode 100644
index 00000000000..35817eb6a5f
--- /dev/null
+++ b/mit-pthreads/stdio/findfp.c
@@ -0,0 +1,161 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * Copyright (c) 1993, 1994 Chris Provenzano.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)findfp.c 5.10 (Berkeley) 2/24/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <pthread.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include "local.h"
+#include "glue.h"
+
+
+#define NSTATIC 20 /* stdin + stdout + stderr + the usual */
+#define NDYNAMIC 10 /* add ten more whenever necessary */
+
+#define std(flags, file) \
+ {0,0,0,flags,file,{0},0 }
+/* p r w flags file _bf z */
+
+static FILE usual[NSTATIC - 3]; /* the usual */
+static struct glue uglue = { 0, NSTATIC - 3, usual };
+
+FILE __sF[3] = {
+ std(__SRD, 0), /* stdin */
+ std(__SWR, 1), /* stdout */
+ std(__SWR|__SNBF, 2) /* stderr */
+};
+struct glue __sglue = { &uglue, 3, __sF };
+FILE *__iob = __sF;
+FILE *_iob = __sF;
+
+pthread_mutex_t __sfp_mutex = PTHREAD_MUTEX_INITIALIZER;
+pthread_cond_t __sfp_cond = PTHREAD_COND_INITIALIZER;
+/*
+ * __sfp_state = 0, when free, > 0 when in _fwalk
+ * This allows multiple readers in _fwalk, but only one writer __sfp,
+ * or freopen() at a time.
+ */
+int __sfp_state = 0;
+
+static struct glue *moreglue(register int n)
+{
+ register struct glue *g;
+ register FILE *p;
+ static FILE empty;
+
+ g = (struct glue *)malloc(sizeof(struct glue) + n * sizeof(FILE));
+ if (g == NULL)
+ return (NULL);
+ p = (FILE *)(g + 1);
+ g->next = NULL;
+ g->niobs = n;
+ g->iobs = p;
+ while (--n >= 0)
+ *p++ = empty;
+ return (g);
+}
+
+/*
+ * Find a free FILE for fopen et al.
+ */
+FILE *__sfp()
+{
+ register FILE *fp;
+ register int n;
+ register struct glue *g;
+
+ for (g = &__sglue;; g = g->next) {
+ for (fp = g->iobs, n = g->niobs; --n >= 0; fp++)
+ if (fp->_flags == 0) {
+ fp->_flags = 1; /* reserve this slot; caller sets real flags */
+ fp->_p = NULL; /* no current pointer */
+ fp->_w = 0; /* nothing to read or write */
+ fp->_r = 0;
+ fp->_bf._base = NULL; /* no buffer */
+ fp->_bf._size = 0;
+ fp->_lbfsize = 0; /* not line buffered */
+ fp->_file = -1; /* no file */
+ fp->_ub._base = NULL; /* no ungetc buffer */
+ fp->_ub._size = 0;
+ fp->_lb._base = NULL; /* no line buffer */
+ fp->_lb._size = 0;
+ goto __sfp_done;
+ }
+ if (g->next == NULL && (g->next = moreglue(NDYNAMIC)) == NULL) {
+ fp = NULL;
+ break;
+ }
+ }
+__sfp_done:;
+ return (fp);
+}
+
+/*
+ * exit() calls _cleanup() through *__cleanup, set whenever we
+ * open or buffer a file. This chicanery is done so that programs
+ * that do not use stdio need not link it all in.
+ *
+ * The name `_cleanup' is, alas, fairly well known outside stdio.
+ */
+void _cleanup()
+{
+ (void) __swalk_sflush();
+}
+
+/*
+ * __sinit() is called whenever stdio's internal variables must be set up.
+ * Do the pthread_once stuff here to keep pthread_once_t out of the
+ * header files. No reason sprintf.c &c should need to include pthread.h...
+ */
+static void __s_real_init ()
+{
+ /* make sure we clean up on exit */
+ __cleanup = _cleanup;
+}
+
+static pthread_once_t sdidinit = PTHREAD_ONCE_INIT;
+
+void __sinit ()
+{
+ pthread_once (&sdidinit, __s_real_init);
+}
diff --git a/mit-pthreads/stdio/flags.c b/mit-pthreads/stdio/flags.c
new file mode 100644
index 00000000000..c0971003312
--- /dev/null
+++ b/mit-pthreads/stdio/flags.c
@@ -0,0 +1,93 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * Copyright (c) 1993, 1994 Chris Provenzano.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)flags.c 5.1 (Berkeley) 1/20/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <pthread.h>
+#include <sys/types.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+
+/*
+ * Return the (stdio) flags for a given mode. Store the flags
+ * to be passed to an open() syscall through *optr.
+ * Return 0 on error.
+ */
+__sflags(mode, optr)
+ register char *mode;
+ int *optr;
+{
+ register int ret, m, o;
+
+ switch (*mode++) {
+
+ case 'r': /* open for reading */
+ ret = __SRD;
+ m = O_RDONLY;
+ o = 0;
+ break;
+
+ case 'w': /* open for writing */
+ ret = __SWR;
+ m = O_WRONLY;
+ o = O_CREAT | O_TRUNC;
+ break;
+
+ case 'a': /* open for appending */
+ ret = __SWR;
+ m = O_WRONLY;
+ o = O_CREAT | O_APPEND;
+ break;
+
+ default: /* illegal mode */
+ errno = EINVAL;
+ return (0);
+ }
+
+ /* [rwa]\+ or [rwa]b\+ means read and write */
+ if (*mode == '+' || (*mode == 'b' && mode[1] == '+')) {
+ ret = __SRW;
+ m = O_RDWR;
+ }
+ *optr = m | o;
+ return (ret);
+}
diff --git a/mit-pthreads/stdio/floatio.h b/mit-pthreads/stdio/floatio.h
new file mode 100644
index 00000000000..cf3821488ae
--- /dev/null
+++ b/mit-pthreads/stdio/floatio.h
@@ -0,0 +1,47 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)floatio.h 5.1 (Berkeley) 1/20/91
+ * $Id$
+ */
+
+/*
+ * Floating point scanf/printf (input/output) definitions.
+ */
+
+/* 11-bit exponent (VAX G floating point) is 308 decimal digits */
+#define MAXEXP 308
+/* 128 bit fraction takes up 39 decimal digits; max reasonable precision */
+#define MAXFRACT 39
diff --git a/mit-pthreads/stdio/fopen.c b/mit-pthreads/stdio/fopen.c
new file mode 100644
index 00000000000..d44c17b633f
--- /dev/null
+++ b/mit-pthreads/stdio/fopen.c
@@ -0,0 +1,90 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * Copyright (c) 1993, 1994 Chris Provenzano.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)fopen.c 5.5 (Berkeley) 2/5/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <pthread.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <errno.h>
+#include "local.h"
+
+extern pthread_mutex_t __sfp_mutex;
+extern pthread_cond_t __sfp_cond;
+extern int __sfp_state;
+
+FILE *fopen(const char *file, const char *mode)
+{
+ register FILE *fp;
+ register int f;
+ int flags, oflags;
+
+ if ((flags = __sflags(mode, &oflags)) == 0)
+ return (NULL);
+ if ((f = open(file, oflags, 0666)) < 0) {
+ return (NULL);
+ }
+
+ __sinit ();
+ pthread_mutex_lock(&__sfp_mutex);
+ while (__sfp_state) {
+ pthread_cond_wait(&__sfp_cond, &__sfp_mutex);
+ }
+
+ if (fp = __sfp()) {
+ fp->_file = f;
+ fp->_flags = flags;
+
+ /*
+ * When opening in append mode, even though we use O_APPEND,
+ * we need to seek to the end so that ftell() gets the right
+ * answer. If the user then alters the seek pointer, or
+ * the file extends, this will fail, but there is not much
+ * we can do about this. (We could set __SAPP and check in
+ * fseek and ftell.)
+ */
+ if (oflags & O_APPEND)
+ (void) __sseek((void *)fp, (off_t)0, SEEK_END);
+ }
+ pthread_mutex_unlock(&__sfp_mutex);
+ return (fp);
+}
diff --git a/mit-pthreads/stdio/fprintf.c b/mit-pthreads/stdio/fprintf.c
new file mode 100644
index 00000000000..bdeb49c054d
--- /dev/null
+++ b/mit-pthreads/stdio/fprintf.c
@@ -0,0 +1,71 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * Copyright (c) 1993, 1994 Chris Provenzano.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)fprintf.c 5.6 (Berkeley) 1/20/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <pthread.h>
+#include <stdio.h>
+#if __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+#if __STDC__
+fprintf(FILE *fp, const char *fmt, ...)
+#else
+fprintf(fp, fmt, va_alist)
+ FILE *fp;
+ char *fmt;
+ va_dcl
+#endif
+{
+ int ret;
+ va_list ap;
+
+#if __STDC__
+ va_start(ap, fmt);
+#else
+ va_start(ap);
+#endif
+ ret = vfprintf(fp, fmt, ap);
+ va_end(ap);
+ return (ret);
+}
diff --git a/mit-pthreads/stdio/fpurge.c b/mit-pthreads/stdio/fpurge.c
new file mode 100644
index 00000000000..7edbb0b30cd
--- /dev/null
+++ b/mit-pthreads/stdio/fpurge.c
@@ -0,0 +1,73 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * Copyright (c) 1993, 1994 Chris Provenzano.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)fpurge.c 5.2 (Berkeley) 2/24/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <pthread.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "local.h"
+
+/*
+ * fpurge: like fflush, but without writing anything: leave the
+ * given FILE's buffer empty.
+ */
+int
+fpurge(fp)
+ register FILE *fp;
+{
+ int ret;
+
+ flockfile(fp);
+ if (fp->_flags) {
+ if (HASUB(fp))
+ FREEUB(fp);
+ fp->_p = fp->_bf._base;
+ fp->_r = 0;
+ fp->_w = fp->_flags & (__SLBF|__SNBF) ? 0 : fp->_bf._size;
+ ret = 0;
+ } else {
+ errno = EBADF;
+ ret = EOF;
+ }
+ funlockfile(fp);
+ return (ret);
+}
diff --git a/mit-pthreads/stdio/fputc.c b/mit-pthreads/stdio/fputc.c
new file mode 100644
index 00000000000..e6dd752f81b
--- /dev/null
+++ b/mit-pthreads/stdio/fputc.c
@@ -0,0 +1,73 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * Copyright (c) 1993, 1994 Chris Provenzano.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)fputc.c 5.3 (Berkeley) 1/20/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <pthread.h>
+#include <stdio.h>
+
+fputc(c, fp)
+ int c;
+ register FILE *fp;
+{
+ int ret;
+ flockfile(fp);
+ ret = __sputc(c, fp);
+ funlockfile(fp);
+ return(ret);
+}
+
+int __putc(int _c, FILE *_p)
+{
+ int ret;
+ flockfile(_p);
+ ret = __sputc(_c, _p);
+ funlockfile(_p);
+ return(ret);
+}
+
+int __sputc(int _c, FILE *_p)
+{
+ if (--_p->_w >= 0 || (_p->_w >= _p->_lbfsize && (char)_c != '\n'))
+ return (*_p->_p++ = _c);
+ else
+ return (__swbuf(_c, _p));
+}
+
diff --git a/mit-pthreads/stdio/fputs.c b/mit-pthreads/stdio/fputs.c
new file mode 100644
index 00000000000..882b828409e
--- /dev/null
+++ b/mit-pthreads/stdio/fputs.c
@@ -0,0 +1,67 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * Copyright (c) 1993, 1994 Chris Provenzano.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)fputs.c 5.6 (Berkeley) 2/24/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <pthread.h>
+#include <stdio.h>
+#include <string.h>
+#include "fvwrite.h"
+
+/*
+ * Write the given string to the given file.
+ */
+fputs(s, fp)
+ const char *s;
+ FILE *fp;
+{
+ struct __suio uio;
+ struct __siov iov;
+ int ret;
+
+ iov.iov_base = (void *)s;
+ iov.iov_len = uio.uio_resid = strlen(s);
+ uio.uio_iov = &iov;
+ uio.uio_iovcnt = 1;
+ flockfile(fp);
+ ret = __sfvwrite(fp, &uio);
+ funlockfile(fp);
+ return(ret);
+}
diff --git a/mit-pthreads/stdio/fread.c b/mit-pthreads/stdio/fread.c
new file mode 100644
index 00000000000..0d8ec6186c7
--- /dev/null
+++ b/mit-pthreads/stdio/fread.c
@@ -0,0 +1,84 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * Copyright (c) 1993, 1994 Chris Provenzano.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)fread.c 5.4 (Berkeley) 5/4/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <pthread.h>
+#include <stdio.h>
+#include <string.h>
+
+size_t
+fread(buf, size, count, fp)
+ void *buf;
+ size_t size, count;
+ register FILE *fp;
+{
+ register size_t resid;
+ register char *p;
+ register int r;
+ size_t total;
+
+ if ((resid = count * size) == 0)
+ return (count);
+
+ flockfile(fp);
+ if (fp->_r < 0)
+ fp->_r = 0;
+ total = resid;
+ p = buf;
+ while (resid > (r = fp->_r)) {
+ (void) memcpy((void *)p, (void *)fp->_p, (size_t)r);
+ fp->_p += r;
+ /* fp->_r = 0 ... done in __srefill */
+ p += r;
+ resid -= r;
+ if (__srefill(fp)) {
+ /* no more input: return partial result */
+ count = (total - resid) / size;
+ goto done_fread;
+ }
+ }
+ (void) memcpy((void *)p, (void *)fp->_p, resid);
+ fp->_r -= resid;
+ fp->_p += resid;
+done_fread:;
+ funlockfile(fp);
+ return (count);
+}
diff --git a/mit-pthreads/stdio/freopen.c b/mit-pthreads/stdio/freopen.c
new file mode 100644
index 00000000000..f45571c8ea0
--- /dev/null
+++ b/mit-pthreads/stdio/freopen.c
@@ -0,0 +1,149 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * Copyright (c) 1993, 1994 Chris Provenzano.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)freopen.c 5.6 (Berkeley) 2/24/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <pthread.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "local.h"
+
+extern pthread_mutex_t __sfp_mutex;
+extern pthread_cond_t __sfp_cond;
+extern int __sfp_state;
+
+/*
+ * Re-direct an existing, open (probably) file to some other file.
+ * ANSI is written such that the original file gets closed if at
+ * all possible, no matter what.
+ */
+FILE *
+freopen(file, mode, fp)
+ const char *file, *mode;
+ register FILE *fp;
+{
+ int f, flags, oflags;
+ FILE *ret;
+
+ if ((flags = __sflags(mode, &oflags)) == 0) {
+ (void) fclose(fp);
+ return (NULL);
+ }
+
+ __sinit ();
+
+ /*
+ * There are actually programs that depend on being able to "freopen"
+ * descriptors that weren't originally open. Keep this from breaking.
+ * Remember whether the stream was open to begin with, and which file
+ * descriptor (if any) was associated with it. If it was attached to
+ * a descriptor, defer closing it; freopen("/dev/stdin", "r", stdin)
+ * should work. This is unnecessary if it was not a Unix file.
+ */
+ /* while lock __sfp_mutex, to block out fopen, and other freopen calls */
+ while (pthread_mutex_lock(&__sfp_mutex) == OK) {
+ if (ftrylockfile(fp) == OK) {
+ if (fp->_flags) {
+ /* flush the stream; ANSI doesn't require this. */
+ if (fp->_flags & __SWR)
+ (void) __sflush(fp);
+ __sclose(fp);
+ /*
+ * Finish closing fp. We cannot keep fp->_base:
+ * it may be the wrong size. This loses the effect
+ * of any setbuffer calls, but stdio has always done
+ * this before.
+ * NOTE: We do this even if __ftrylockfilr failed with
+ * an error to avoid memory leaks.
+ */
+ if (fp->_flags & __SMBF)
+ free((char *)fp->_bf._base);
+ fp->_w = 0;
+ fp->_r = 0;
+ fp->_p = NULL;
+ fp->_bf._base = NULL;
+ fp->_bf._size = 0;
+ fp->_lbfsize = 0;
+ if (HASUB(fp))
+ FREEUB(fp);
+ fp->_ub._size = 0;
+ if (HASLB(fp))
+ FREELB(fp);
+ fp->_lb._size = 0;
+ }
+ /* Get a new descriptor to refer to the new file. */
+ if ((f = open(file, oflags, 0666)) < OK)
+ ret = NULL;
+ /*
+ * If reopening something that was open before on a real file, try
+ * to maintain the descriptor. Various C library routines (perror)
+ * assume stderr is always fd STDERR_FILENO, even if being
+ * freopen'd.
+ */
+ /* Testing f == fp->_file may no longer be necessary */
+ if (fp->_file >= 0 && f != fp->_file) {
+ if (dup2(f, fp->_file) >= OK) {
+ (void)close(f);
+ f = fp->_file;
+ }
+ }
+ fp->_flags = flags;
+ fp->_file = f;
+ ret = fp;
+ } else {
+ /* unlock __sfp_mutex, and try again later */
+ pthread_mutex_unlock(&__sfp_mutex);
+ pthread_yield();
+ continue;
+ }
+ /* @@ Yo, Chris! Between the "break" and "continue" statements
+ above, the program will never get here. What gives? */
+ pthread_mutex_unlock(&__sfp_mutex);
+ funlockfile(fp);
+ return(ret);
+ }
+ (void)fclose(fp);
+ return(NULL);
+}
diff --git a/mit-pthreads/stdio/fscanf.c b/mit-pthreads/stdio/fscanf.c
new file mode 100644
index 00000000000..8fbbac5d102
--- /dev/null
+++ b/mit-pthreads/stdio/fscanf.c
@@ -0,0 +1,73 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * Copyright (c) 1993, 1994 Chris Provenzano.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)fscanf.c 5.1 (Berkeley) 1/20/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <pthread.h>
+#include <stdio.h>
+#if __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+#if __STDC__
+fscanf(FILE *fp, char const *fmt, ...) {
+ int r;
+ va_list ap;
+
+ va_start(ap, fmt);
+#else
+fscanf(fp, fmt, va_alist)
+ FILE *fp;
+ char *fmt;
+ va_dcl
+{
+ int r;
+ va_list ap;
+
+ va_start(ap);
+#endif
+ flockfile(fp);
+ r = __svfscanf(fp, fmt, ap);
+ funlockfile(fp);
+ va_end(ap);
+ return(r);
+}
diff --git a/mit-pthreads/stdio/fseek.c b/mit-pthreads/stdio/fseek.c
new file mode 100644
index 00000000000..5c7feda638f
--- /dev/null
+++ b/mit-pthreads/stdio/fseek.c
@@ -0,0 +1,248 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * Copyright (c) 1993, 1994 Chris Provenzano.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)fseek.c 5.7 (Berkeley) 2/24/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <pthread.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include "local.h"
+
+#define POS_ERR (-(fpos_t)1)
+
+/*
+ * Seek the given file to the given offset.
+ * `Whence' must be one of the three SEEK_* macros.
+ */
+fseek(fp, offset, whence)
+ register FILE *fp;
+ long offset;
+ int whence;
+{
+#if __STDC__
+ register fpos_t (*seekfn)(void *, fpos_t, int);
+#else
+ register fpos_t (*seekfn)();
+#endif
+ fpos_t target, curoff;
+ size_t n;
+ struct stat st;
+ int havepos;
+
+ /* make sure stdio is set up */
+ __sinit ();
+
+ flockfile(fp);
+
+ /*
+ * Change any SEEK_CUR to SEEK_SET, and check `whence' argument.
+ * After this, whence is either SEEK_SET or SEEK_END.
+ */
+ switch (whence) {
+ case SEEK_CUR:
+ /*
+ * In order to seek relative to the current stream offset,
+ * we have to first find the current stream offset a la
+ * ftell (see ftell for details).
+ */
+ if (fp->_flags & __SOFF)
+ curoff = fp->_offset;
+ else {
+ curoff = __sseek(fp, (off_t)0, SEEK_CUR);
+ if (curoff == -1L) {
+ funlockfile(fp);
+ return (EOF);
+ }
+ }
+ if (fp->_flags & __SRD) {
+ curoff -= fp->_r;
+ if (HASUB(fp))
+ curoff -= fp->_ur;
+ } else if (fp->_flags & __SWR && fp->_p != NULL)
+ curoff += fp->_p - fp->_bf._base;
+
+ offset += curoff;
+ whence = SEEK_SET;
+ havepos = 1;
+ break;
+
+ case SEEK_SET:
+ case SEEK_END:
+ curoff = 0; /* XXX just to keep gcc quiet */
+ havepos = 0;
+ break;
+
+ default:
+ errno = EINVAL;
+ funlockfile(fp);
+ return (EOF);
+ }
+
+ /*
+ * Can only optimise if:
+ * reading (and not reading-and-writing);
+ * not unbuffered; and
+ * this is a `regular' Unix file (and hence seekfn==__sseek).
+ * We must check __NBF first, because it is possible to have __NBF
+ * and __SOPT both set.
+ */
+ if (fp->_bf._base == NULL)
+ __smakebuf(fp);
+ if (fp->_flags & (__SWR | __SRW | __SNBF | __SNPT))
+ goto dumb;
+ if ((fp->_flags & __SOPT) == 0) {
+ if (fp->_file < 0 || fstat(fp->_file, &st) ||
+ (st.st_mode & S_IFMT) != S_IFREG) {
+ fp->_flags |= __SNPT;
+ goto dumb;
+ }
+ fp->_blksize = st.st_blksize;
+ fp->_flags |= __SOPT;
+ }
+
+ /*
+ * We are reading; we can try to optimise.
+ * Figure out where we are going and where we are now.
+ */
+ if (whence == SEEK_SET)
+ target = offset;
+ else {
+ if (fstat(fp->_file, &st))
+ goto dumb;
+ target = st.st_size + offset;
+ }
+
+ if (!havepos) {
+ if (fp->_flags & __SOFF)
+ curoff = fp->_offset;
+ else {
+ curoff = __sseek(fp, (off_t)0, SEEK_CUR);
+ if (curoff == POS_ERR)
+ goto dumb;
+ }
+ curoff -= fp->_r;
+ if (HASUB(fp))
+ curoff -= fp->_ur;
+ }
+
+ /*
+ * Compute the number of bytes in the input buffer (pretending
+ * that any ungetc() input has been discarded). Adjust current
+ * offset backwards by this count so that it represents the
+ * file offset for the first byte in the current input buffer.
+ */
+ if (HASUB(fp)) {
+ n = fp->_up - fp->_bf._base;
+ curoff -= n;
+ n += fp->_ur;
+ } else {
+ n = fp->_p - fp->_bf._base;
+ curoff -= n;
+ n += fp->_r;
+ }
+
+ /*
+ * If the target offset is within the current buffer,
+ * simply adjust the pointers, clear EOF, undo ungetc(),
+ * and return. (If the buffer was modified, we have to
+ * skip this; see fgetline.c.)
+ */
+ if ((fp->_flags & __SMOD) == 0 &&
+ target >= curoff && target < curoff + n) {
+ register int o = target - curoff;
+
+ fp->_p = fp->_bf._base + o;
+ fp->_r = n - o;
+ if (HASUB(fp))
+ FREEUB(fp);
+ fp->_flags &= ~__SEOF;
+ funlockfile(fp);
+ return (0);
+ }
+
+ /*
+ * The place we want to get to is not within the current buffer,
+ * but we can still be kind to the kernel copyout mechanism.
+ * By aligning the file offset to a block boundary, we can let
+ * the kernel use the VM hardware to map pages instead of
+ * copying bytes laboriously. Using a block boundary also
+ * ensures that we only read one block, rather than two.
+ */
+ curoff = target & ~(fp->_blksize - 1);
+ if (__sseek(fp, (off_t)curoff, SEEK_SET) != POS_ERR) {
+ fp->_r = 0;
+ fp->_p = fp->_bf._base;
+ if (HASUB(fp))
+ FREEUB(fp);
+ fp->_flags &= ~__SEOF;
+ n = target - curoff;
+ if (n) {
+ if (__srefill(fp) || fp->_r < n)
+ goto dumb;
+ fp->_p += n;
+ fp->_r -= n;
+ }
+ funlockfile(fp);
+ return (0);
+ }
+
+ /*
+ * We get here if we cannot optimise the seek ... just
+ * do it. Allow the seek function to change fp->_bf._base.
+ */
+dumb:
+ if (__sflush(fp) || __sseek(fp, (off_t)offset, whence) == POS_ERR) {
+ funlockfile(fp);
+ return (EOF);
+ }
+ /* success: clear EOF indicator and discard ungetc() data */
+ if (HASUB(fp))
+ FREEUB(fp);
+ fp->_p = fp->_bf._base;
+ fp->_r = 0;
+ /* fp->_w = 0; */ /* unnecessary (I think...) */
+ fp->_flags &= ~__SEOF;
+ funlockfile(fp);
+ return (0);
+}
diff --git a/mit-pthreads/stdio/fsetpos.c b/mit-pthreads/stdio/fsetpos.c
new file mode 100644
index 00000000000..a421d405f51
--- /dev/null
+++ b/mit-pthreads/stdio/fsetpos.c
@@ -0,0 +1,54 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * Copyright (c) 1993, 1994 Chris Provenzano.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)fsetpos.c 5.2 (Berkeley) 2/5/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <stdio.h>
+
+/*
+ * fsetpos: like fseek.
+ * Don't bother locking, fseek does it.
+ */
+fsetpos(iop, pos)
+ FILE *iop;
+ const fpos_t *pos;
+{
+ return (fseek(iop, (long)*pos, SEEK_SET));
+}
diff --git a/mit-pthreads/stdio/ftell.c b/mit-pthreads/stdio/ftell.c
new file mode 100644
index 00000000000..e5961fa50b6
--- /dev/null
+++ b/mit-pthreads/stdio/ftell.c
@@ -0,0 +1,90 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * Copyright (c) 1993, 1994 Chris Provenzano.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)ftell.c 5.4 (Berkeley) 2/5/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <pthread.h>
+#include <stdio.h>
+#include <errno.h>
+#include "local.h"
+
+/*
+ * ftell: return current offset.
+ */
+long
+ftell(fp)
+ register const FILE *fp;
+{
+ long pos;
+
+ flockfile((FILE *)fp);
+
+ /*
+ * Find offset of underlying I/O object, then
+ * adjust for buffered bytes.
+ */
+ if (fp->_flags & __SOFF) {
+ pos = fp->_offset;
+ } else {
+ pos = (long)__sseek((FILE *)fp, (off_t)0, SEEK_CUR);
+ }
+
+ if (pos != -1L) {
+ if (fp->_flags & __SRD) {
+ /*
+ * Reading. Any unread characters (including
+ * those from ungetc) cause the position to be
+ * smaller than that in the underlying object.
+ */
+ pos -= fp->_r;
+ if (HASUB(fp))
+ pos -= fp->_ur;
+ } else if (fp->_flags & __SWR && fp->_p != NULL) {
+ /*
+ * Writing. Any buffered characters cause the
+ * position to be greater than that in the
+ * underlying object.
+ */
+ pos += fp->_p - fp->_bf._base;
+ }
+ }
+ funlockfile((FILE *)fp);
+ return (pos);
+}
diff --git a/mit-pthreads/stdio/funopen.c b/mit-pthreads/stdio/funopen.c
new file mode 100644
index 00000000000..f8b37ed0ae4
--- /dev/null
+++ b/mit-pthreads/stdio/funopen.c
@@ -0,0 +1,105 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * Copyright (c) 1993, 1994 Chris Provenzano.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)funopen.c 5.2 (Berkeley) 2/5/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <pthread.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <errno.h>
+#include "local.h"
+
+FILE *
+funopen(cookie, readfn, writefn, seekfn, closefn)
+ const void *cookie;
+ int (*readfn)(), (*writefn)();
+#if __STDC__
+ fpos_t (*seekfn)(void *cookie, fpos_t off, int whence);
+#else
+ fpos_t (*seekfn)();
+#endif
+ int (*closefn)();
+{
+ struct fd_ops *fd_ops;
+ char *flags;
+ FILE *fp;
+ int fd;
+
+ if (readfn == NULL) {
+ if (writefn == NULL) { /* illegal */
+ errno = EINVAL;
+ return (NULL);
+ } else
+ flags = "w"; /* write only */
+ } else {
+ if (writefn == NULL)
+ flags = "r"; /* read only */
+ else
+ flags = "r+"; /* read-write */
+ }
+
+ if (fd_ops = (struct fd_ops*)malloc(sizeof(struct fd_ops))) {
+ if ((fd = fd_allocate()) >= OK) {
+
+ /* Set functions */
+ fd_ops->seek = (off_t(*)())seekfn;
+ fd_ops->read = (pthread_ssize_t(*)())readfn;
+ fd_ops->write = (pthread_ssize_t(*)())writefn;
+ fd_ops->close = closefn;
+ fd_ops->use_kfds = 2;
+
+ /* Alloc space for funtion pointer table */
+ fd_table[fd]->type = FD_HALF_DUPLEX;
+ fd_table[fd]->ops = fd_ops;
+ fd_table[fd]->flags = O_RDWR;
+
+ /* Save the cookie, it's important */
+ fd_table[fd]->fd.ptr = (void *)cookie;
+
+ if (fp = fdopen(fd, flags))
+ return(fp);
+
+ fd_free(fd);
+ }
+ free(fd_ops);
+ }
+ return(NULL);
+}
diff --git a/mit-pthreads/stdio/fvwrite.c b/mit-pthreads/stdio/fvwrite.c
new file mode 100644
index 00000000000..5ed25b4e7b4
--- /dev/null
+++ b/mit-pthreads/stdio/fvwrite.c
@@ -0,0 +1,190 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * Copyright (c) 1993, 1994 Chris Provenzano.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)fvwrite.c 5.3 (Berkeley) 5/4/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "local.h"
+#include "fvwrite.h"
+
+/*
+ * Write some memory regions. Return zero on success, EOF on error.
+ *
+ * This routine is large and unsightly, but most of the ugliness due
+ * to the three different kinds of output buffering is handled here.
+ */
+__sfvwrite(fp, uio)
+ register FILE *fp;
+ register struct __suio *uio;
+{
+ register size_t len;
+ register char *p;
+ register struct __siov *iov;
+ register int w, s;
+ char *nl;
+ int nlknown, nldist;
+
+ if ((len = uio->uio_resid) == 0)
+ return (0);
+ /* make sure we can write */
+ if (cantwrite(fp))
+ return (EOF);
+
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+#define COPY(n) (void) memcpy((void *)fp->_p, (void *)p, (size_t)(n));
+
+ iov = uio->uio_iov;
+ p = iov->iov_base;
+ len = iov->iov_len;
+ iov++;
+#define GETIOV(extra_work) \
+ while (len == 0) { \
+ extra_work; \
+ p = iov->iov_base; \
+ len = iov->iov_len; \
+ iov++; \
+ }
+ if (fp->_flags & __SNBF) {
+ /*
+ * Unbuffered: write up to BUFSIZ bytes at a time.
+ */
+ do {
+ GETIOV(;);
+ w = __swrite(fp, p, MIN(len, BUFSIZ));
+ if (w <= 0)
+ goto err;
+ p += w;
+ len -= w;
+ } while ((uio->uio_resid -= w) != 0);
+ } else if ((fp->_flags & __SLBF) == 0) {
+ /*
+ * Fully buffered: fill partially full buffer, if any,
+ * and then flush. If there is no partial buffer, write
+ * one _bf._size byte chunk directly (without copying).
+ *
+ * String output is a special case: write as many bytes
+ * as fit, but pretend we wrote everything. This makes
+ * snprintf() return the number of bytes needed, rather
+ * than the number used, and avoids its write function
+ * (so that the write function can be invalid).
+ */
+ do {
+ GETIOV(;);
+ w = fp->_w;
+ if (fp->_flags & __SSTR) {
+ if (len < w)
+ w = len;
+ COPY(w); /* copy MIN(fp->_w,len), */
+ fp->_w -= w;
+ fp->_p += w;
+ w = len; /* but pretend copied all */
+ } else if (fp->_p > fp->_bf._base && len > w) {
+ /* fill and flush */
+ COPY(w);
+ /* fp->_w -= w; */ /* unneeded */
+ fp->_p += w;
+ if (fflush(fp))
+ goto err;
+ } else if (len >= (w = fp->_bf._size)) {
+ if ((w = __swrite(fp, p, w)) <= 0)
+ goto err;
+ } else {
+ /* fill and done */
+ w = len;
+ COPY(w);
+ fp->_w -= w;
+ fp->_p += w;
+ }
+ p += w;
+ len -= w;
+ } while ((uio->uio_resid -= w) != 0);
+ } else {
+ /*
+ * Line buffered: like fully buffered, but we
+ * must check for newlines. Compute the distance
+ * to the first newline (including the newline),
+ * or `infinity' if there is none, then pretend
+ * that the amount to write is MIN(len,nldist).
+ */
+ nlknown = 0;
+ nldist = 0; /* XXX just to keep gcc happy */
+ do {
+ GETIOV(nlknown = 0);
+ if (!nlknown) {
+ nl = memchr((void *)p, '\n', len);
+ nldist = nl ? nl + 1 - p : len + 1;
+ nlknown = 1;
+ }
+ s = MIN(len, nldist);
+ w = fp->_w + fp->_bf._size;
+ if (fp->_p > fp->_bf._base && s > w) {
+ COPY(w);
+ /* fp->_w -= w; */
+ fp->_p += w;
+ if (fflush(fp))
+ goto err;
+ } else if (s >= (w = fp->_bf._size)) {
+ if ((w = __swrite(fp, p, w)) <= 0)
+ goto err;
+ } else {
+ w = s;
+ COPY(w);
+ fp->_w -= w;
+ fp->_p += w;
+ }
+ if ((nldist -= w) == 0) {
+ /* copied the newline: flush and forget */
+ if (fflush(fp))
+ goto err;
+ nlknown = 0;
+ }
+ p += w;
+ len -= w;
+ } while ((uio->uio_resid -= w) != 0);
+ }
+ return (0);
+
+err:
+ fp->_flags |= __SERR;
+ return (EOF);
+}
diff --git a/mit-pthreads/stdio/fvwrite.h b/mit-pthreads/stdio/fvwrite.h
new file mode 100644
index 00000000000..b3474563a4e
--- /dev/null
+++ b/mit-pthreads/stdio/fvwrite.h
@@ -0,0 +1,54 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)fvwrite.h 5.1 (Berkeley) 1/20/91
+ * $Id$
+ */
+
+/*
+ * I/O descriptors for __sfvwrite().
+ */
+struct __siov {
+ void *iov_base;
+ size_t iov_len;
+};
+
+struct __suio {
+ struct __siov *uio_iov;
+ int uio_iovcnt;
+ int uio_resid;
+};
+
+extern int __sfvwrite __P_(( FILE *, struct __suio *));
diff --git a/mit-pthreads/stdio/fwalk.c b/mit-pthreads/stdio/fwalk.c
new file mode 100644
index 00000000000..58a199e0707
--- /dev/null
+++ b/mit-pthreads/stdio/fwalk.c
@@ -0,0 +1,132 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * Copyright (c) 1993, 1994 Chris Provenzano.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)fwalk.c 5.2 (Berkeley) 2/24/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <pthread.h>
+#include <errno.h>
+#include <stdio.h>
+#include "local.h"
+#include "glue.h"
+
+extern pthread_mutex_t __sfp_mutex;
+extern pthread_cond_t __sfp_cond;
+extern int __sfp_state;
+
+/*
+ * fwalk now can only be used for flushing the buffers.
+ * This is all it was originally used for.
+ * The function has also become much more complicated.
+ * The first time through we flush everything we can.
+ * If this fails to flush everything because we couldn't get a lock
+ * we wait on the locksfor the second pass. Why this works ...
+ *
+ * This function must allow for multiple threads to flush everything.
+ * This function cannot flush buffers locked by another thread.
+ * So we flush everything we can the first pass. This includes all
+ * buffers locked by this thread, and wait on buffers that are locked.
+ * Eventually other threads willl unlock there buffers or flush them themselves
+ * at which point this thread will notice that it's empty or be able to
+ * flush the buffer. This is fine so long as no other thread tries to flush
+ * all buffers. Here is the possible deadlock condition, but since this thread
+ * has flushed all buffers it can, there are NO buffers locked by this thread
+ * that need flushing so any other thread flushing won't block waiting on this
+ * thread thereby eliminating the deadlock condition.
+ */
+
+int __swalk_sflush()
+{
+ register FILE *fp, *savefp;
+ register int n, ret, saven;
+ register struct glue *g, *saveg;
+
+ /* Only allow other threads to read __sglue */
+ pthread_mutex_lock(&__sfp_mutex);
+ __sfp_state++;
+ pthread_mutex_unlock(&__sfp_mutex);
+
+ ret = 0;
+ saven = 0;
+ saveg = NULL;
+ savefp = NULL;
+ for (g = &__sglue; g != NULL; g = g->next) {
+ for (fp = g->iobs, n = g->niobs; --n >= 0; fp++) {
+ if (fp->_flags != 0) {
+ /* Is there anything to flush? */
+ if (fp->_bf._base && (fp->_bf._base - fp->_p)) {
+ if (ftrylockfile(fp)) { /* Can we flush it */
+ if (!saven) { /* No, save first fp we can't flush */
+ saven = n;
+ saveg = g;
+ savefp = fp;
+ continue;
+ }
+ } else {
+ ret |= __sflush(fp);
+ funlockfile(fp);
+ }
+ }
+ }
+ }
+ }
+ if (savefp) {
+ for (g = saveg; g != NULL; g = g->next) {
+ for (fp = savefp, n = saven + 1; --n >= 0; fp++) {
+ if (fp->_flags != 0) {
+ /* Anything to flush */
+ while (fp->_bf._base && (fp->_bf._base - fp->_p)) {
+ flockfile(fp);
+ ret |= __sflush(fp);
+ funlockfile(fp);
+ }
+ }
+ }
+ }
+ }
+
+ /* If no other readers wakeup a thread waiting to do __sfp */
+ pthread_mutex_lock(&__sfp_mutex);
+ if (! (--__sfp_state)) {
+ pthread_cond_signal(&__sfp_cond);
+ }
+ pthread_mutex_unlock(&__sfp_mutex);
+ return (ret);
+}
+
diff --git a/mit-pthreads/stdio/fwrite.c b/mit-pthreads/stdio/fwrite.c
new file mode 100644
index 00000000000..5eada4ee84b
--- /dev/null
+++ b/mit-pthreads/stdio/fwrite.c
@@ -0,0 +1,80 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * Copyright (c) 1993, 1994 Chris Provenzano.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)fwrite.c 5.5 (Berkeley) 2/24/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <pthread.h>
+#include <stdio.h>
+#include "local.h"
+#include "fvwrite.h"
+
+/*
+ * Write `count' objects (each size `size') from memory to the given file.
+ * Return the number of whole objects written.
+ */
+size_t
+fwrite(buf, size, count, fp)
+ const void *buf;
+ size_t size, count;
+ FILE *fp;
+{
+ struct __suio uio;
+ struct __siov iov;
+ size_t n;
+
+ iov.iov_base = (void *)buf;
+ uio.uio_resid = iov.iov_len = n = count * size;
+ uio.uio_iov = &iov;
+ uio.uio_iovcnt = 1;
+ if (! n)
+ return(0);
+
+ flockfile(fp);
+
+ /*
+ * The usual case is success (__sfvwrite returns 0);
+ * skip the divide if this happens, since divides are
+ * generally slow and since this occurs whenever size==0.
+ */
+ if (__sfvwrite(fp, &uio) == 0)
+ count = (n - uio.uio_resid) / size;
+ funlockfile(fp);
+ return(count);
+}
diff --git a/mit-pthreads/stdio/getc.c b/mit-pthreads/stdio/getc.c
new file mode 100644
index 00000000000..6896e78bc7e
--- /dev/null
+++ b/mit-pthreads/stdio/getc.c
@@ -0,0 +1,58 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * Copyright (c) 1993, 1994 Chris Provenzano.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)getc.c 5.1 (Berkeley) 1/20/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <stdio.h>
+
+/*
+ * A subroutine version of the macro getc.
+ */
+#undef getc
+
+getc(fp)
+ register FILE *fp;
+{
+ int ret;
+ flockfile(fp);
+ ret = __sgetc(fp);
+ funlockfile(fp);
+ return(ret);
+}
diff --git a/mit-pthreads/stdio/getc_unlocked.c b/mit-pthreads/stdio/getc_unlocked.c
new file mode 100644
index 00000000000..01db3bcea2a
--- /dev/null
+++ b/mit-pthreads/stdio/getc_unlocked.c
@@ -0,0 +1,55 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * Copyright (c) 1993, 1994 Chris Provenzano.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)getc.c 5.1 (Berkeley) 1/20/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <pthread.h>
+#include <stdio.h>
+
+/*
+ * A subroutine version of the macro getc.
+ */
+#undef getc_unlocked
+
+getc_unlocked(fp)
+ register FILE *fp;
+{
+ return (__sgetc(fp));
+}
diff --git a/mit-pthreads/stdio/getchar.c b/mit-pthreads/stdio/getchar.c
new file mode 100644
index 00000000000..6e631c6c1b1
--- /dev/null
+++ b/mit-pthreads/stdio/getchar.c
@@ -0,0 +1,58 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * Copyright (c) 1993, 1994 Chris Provenzano.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)getchar.c 5.3 (Berkeley) 1/20/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+/*
+ * A subroutine version of the macro getchar.
+ */
+#include <pthread.h>
+#include <stdio.h>
+
+#undef getchar
+
+getchar()
+{
+ int ret;
+ flockfile(stdin);
+ ret = getc(stdin);
+ funlockfile(stdin);
+ return(ret);
+}
diff --git a/mit-pthreads/stdio/getchar_unlocked.c b/mit-pthreads/stdio/getchar_unlocked.c
new file mode 100644
index 00000000000..40945c5dd57
--- /dev/null
+++ b/mit-pthreads/stdio/getchar_unlocked.c
@@ -0,0 +1,54 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * Copyright (c) 1993, 1994 Chris Provenzano.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)getchar.c 5.3 (Berkeley) 1/20/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+/*
+ * A subroutine version of the macro getchar.
+ */
+#include <pthread.h>
+#include <stdio.h>
+
+#undef getchar_unlocked
+
+getchar_unlocked()
+{
+ return (getc(stdin));
+}
diff --git a/mit-pthreads/stdio/gets.c b/mit-pthreads/stdio/gets.c
new file mode 100644
index 00000000000..0e7967ae3fe
--- /dev/null
+++ b/mit-pthreads/stdio/gets.c
@@ -0,0 +1,71 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * Copyright (c) 1993, 1994 Chris Provenzano.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)gets.c 5.3 (Berkeley) 1/20/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <pthread.h>
+#include <unistd.h>
+#include <stdio.h>
+
+char *
+gets(buf)
+ char *buf;
+{
+ register int c;
+ register char *s;
+ static int warned;
+ static char w[] =
+ "warning: this program uses gets(), which is unsafe.\r\n";
+
+ if (!warned) {
+ (void) write(STDERR_FILENO, w, sizeof(w) - 1);
+ warned = 1;
+ }
+ for (s = buf; (c = getchar()) != '\n';)
+ if (c == EOF)
+ if (s == buf)
+ return (NULL);
+ else
+ break;
+ else
+ *s++ = c;
+ *s = 0;
+ return (buf);
+}
diff --git a/mit-pthreads/stdio/getw.c b/mit-pthreads/stdio/getw.c
new file mode 100644
index 00000000000..623ba6258a1
--- /dev/null
+++ b/mit-pthreads/stdio/getw.c
@@ -0,0 +1,51 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * Copyright (c) 1993, 1994 Chris Provenzano.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)getw.c 5.3 (Berkeley) 1/20/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <stdio.h>
+
+getw(fp)
+ FILE *fp;
+{
+ int x;
+
+ return (fread((void *)&x, sizeof(x), 1, fp) == 1 ? x : EOF);
+}
diff --git a/mit-pthreads/stdio/glue.h b/mit-pthreads/stdio/glue.h
new file mode 100644
index 00000000000..e5103bbb0b3
--- /dev/null
+++ b/mit-pthreads/stdio/glue.h
@@ -0,0 +1,49 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)glue.h 5.1 (Berkeley) 1/20/91
+ * $Id$
+ */
+
+/*
+ * The first few FILEs are statically allocated; others are dynamically
+ * allocated and linked in via this glue structure.
+ */
+typedef struct glue {
+ struct glue *next;
+ int niobs;
+ FILE *iobs;
+} __sglue_type;
+extern struct glue __sglue;
diff --git a/mit-pthreads/stdio/local.h b/mit-pthreads/stdio/local.h
new file mode 100644
index 00000000000..068754fad38
--- /dev/null
+++ b/mit-pthreads/stdio/local.h
@@ -0,0 +1,90 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)local.h 5.3 (Berkeley) 5/6/93
+ * $Id$
+ */
+
+/*
+ * Information local to this implementation of stdio,
+ * in particular, macros and private variables.
+ */
+
+#include <sys/types.h>
+#include <stddef.h>
+
+extern FILE *__sfp __P_((void));
+extern int __sflush __P_((FILE *));
+extern int __srefill __P_((FILE *));
+extern int __swrite __P_((FILE *, const char *, int));
+extern int __sread __P_((FILE *, char *, int));
+extern fpos_t __sseek __P_((FILE *, off_t, int));
+extern int __sclose __P_((FILE *));
+extern void __sinit __P_((void));
+extern void _cleanup __P_((void));
+extern void __smakebuf __P_((FILE *));
+extern int __swhatbuf __P_((FILE *, size_t *, int *));
+extern int __swalk_sflush __P_(());
+extern int __swsetup __P_((FILE *));
+extern int __sflags __P_((const char *, int *));
+
+extern void (*__cleanup) __P_((void));
+
+/*
+ * Return true iff the given FILE cannot be written now.
+ */
+#define cantwrite(fp) \
+ ((((fp)->_flags & __SWR) == 0 || (fp)->_bf._base == NULL) && \
+ __swsetup(fp))
+
+/*
+ * Test whether the given stdio file has an active ungetc buffer;
+ * release such a buffer, without restoring ordinary unread data.
+ */
+#define HASUB(fp) ((fp)->_ub._base != NULL)
+#define FREEUB(fp) { \
+ if ((fp)->_ub._base != (fp)->_ubuf) \
+ free((char *)(fp)->_ub._base); \
+ (fp)->_ub._base = NULL; \
+}
+
+/*
+ * test for an fgetline() buffer.
+ */
+#define HASLB(fp) ((fp)->_lb._base != NULL)
+#define FREELB(fp) { \
+ free((char *)(fp)->_lb._base); \
+ (fp)->_lb._base = NULL; \
+}
diff --git a/mit-pthreads/stdio/makebuf.c b/mit-pthreads/stdio/makebuf.c
new file mode 100644
index 00000000000..316abe054b6
--- /dev/null
+++ b/mit-pthreads/stdio/makebuf.c
@@ -0,0 +1,122 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * Copyright (c) 1993, 1994 Chris Provenzano.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)makebuf.c 5.3 (Berkeley) 5/6/93";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <pthread.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "local.h"
+
+void (*__cleanup) __P_((void));
+
+/*
+ * Allocate a file buffer, or switch to unbuffered I/O.
+ * Per the ANSI C standard, ALL tty devices default to line buffered.
+ *
+ * As a side effect, we set __SOPT or __SNPT (en/dis-able fseek
+ * optimisation) right after the fstat() that finds the buffer size.
+ */
+void
+__smakebuf(fp)
+ register FILE *fp;
+{
+ register void *p;
+ register int flags;
+ size_t size;
+ int couldbetty;
+
+ if (fp->_flags & __SNBF) {
+ fp->_bf._base = fp->_p = fp->_nbuf;
+ fp->_bf._size = 1;
+ return;
+ }
+ flags = __swhatbuf(fp, &size, &couldbetty);
+ if ((p = malloc(size)) == NULL) {
+ fp->_flags |= __SNBF;
+ fp->_bf._base = fp->_p = fp->_nbuf;
+ fp->_bf._size = 1;
+ return;
+ }
+ __cleanup = _cleanup;
+ flags |= __SMBF;
+ fp->_bf._base = fp->_p = p;
+ fp->_bf._size = size;
+ if (couldbetty && isatty(fp->_file))
+ flags |= __SLBF;
+ fp->_flags |= flags;
+}
+
+/*
+ * Internal routine to determine `proper' buffering for a file.
+ */
+int
+__swhatbuf(fp, bufsize, couldbetty)
+ register FILE *fp;
+ size_t *bufsize;
+ int *couldbetty;
+{
+ struct stat st;
+
+ if (fp->_file < 0 || fstat(fp->_file, &st) < 0) {
+ *couldbetty = 0;
+ *bufsize = BUFSIZ;
+ return (__SNPT);
+ }
+
+ /* could be a tty iff it is a character device */
+ *couldbetty = (st.st_mode & S_IFMT) == S_IFCHR;
+ if (st.st_blksize <= 0) {
+ *bufsize = BUFSIZ;
+ return (__SNPT);
+ }
+
+ /*
+ * Optimise fseek() only if it is a regular file. (The test for
+ * __sseek is mainly paranoia.) It is safe to set _blksize
+ * unconditionally; it will only be used if __SOPT is also set.
+ */
+ *bufsize = st.st_blksize;
+ fp->_blksize = st.st_blksize;
+ return ((st.st_mode & S_IFMT) == S_IFREG ? __SOPT : __SNPT);
+}
diff --git a/mit-pthreads/stdio/mktemp.c b/mit-pthreads/stdio/mktemp.c
new file mode 100644
index 00000000000..7fdc631ad0b
--- /dev/null
+++ b/mit-pthreads/stdio/mktemp.c
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 1987 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)mktemp.c 5.10 (Berkeley) 2/24/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+
+static int _gettemp();
+
+mkstemp(path)
+ char *path;
+{
+ int fd;
+
+ return (_gettemp(path, &fd) ? fd : -1);
+}
+
+char *
+mktemp(path)
+ char *path;
+{
+ return(_gettemp(path, (int *)NULL) ? path : (char *)NULL);
+}
+
+static
+_gettemp(path, doopen)
+ char *path;
+ register int *doopen;
+{
+ extern int errno;
+ register char *start, *trv;
+ struct stat sbuf;
+ u_int pid;
+
+ pid = getpid();
+ for (trv = path; *trv; ++trv); /* extra X's get set to 0's */
+ while (*--trv == 'X') {
+ *trv = (pid % 10) + '0';
+ pid /= 10;
+ }
+
+ /*
+ * check the target directory; if you have six X's and it
+ * doesn't exist this runs for a *very* long time.
+ */
+ for (start = trv + 1;; --trv) {
+ if (trv <= path)
+ break;
+ if (*trv == '/') {
+ *trv = '\0';
+ if (stat(path, &sbuf))
+ return(0);
+ if (!S_ISDIR(sbuf.st_mode)) {
+ errno = ENOTDIR;
+ return(0);
+ }
+ *trv = '/';
+ break;
+ }
+ }
+
+ for (;;) {
+ if (doopen) {
+ if ((*doopen =
+ open(path, O_CREAT|O_EXCL|O_RDWR, 0600)) >= 0)
+ return(1);
+ if (errno != EEXIST)
+ return(0);
+ }
+ else if (stat(path, &sbuf))
+ return(errno == ENOENT ? 1 : 0);
+
+ /* tricky little algorithm for backward compatibility */
+ for (trv = start;;) {
+ if (!*trv)
+ return(0);
+ if (*trv == 'z')
+ *trv++ = 'a';
+ else {
+ if (isdigit(*trv))
+ *trv = 'a';
+ else
+ ++*trv;
+ break;
+ }
+ }
+ }
+ /*NOTREACHED*/
+}
diff --git a/mit-pthreads/stdio/perror.c b/mit-pthreads/stdio/perror.c
new file mode 100644
index 00000000000..19fe52f5010
--- /dev/null
+++ b/mit-pthreads/stdio/perror.c
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 1988 Regents of the University of California.
+ * Copyright (c) 1993, 1994 Chris Provenzano proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)perror.c 5.11 (Berkeley) 2/24/91";
+#endif /* LIBC_SCCS and not lint */
+
+#include <pthread.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+char *strerror(int); /* For systems that don't prototype it in string.h */
+
+void
+perror(s)
+ const char *s;
+{
+ char * e;
+
+ if (fd_lock(STDERR_FILENO, FD_WRITE, NULL) == OK) {
+ if (s && *s) {
+ fd_table[STDERR_FILENO]->ops->write(fd_table[STDERR_FILENO]->fd,
+ fd_table[STDERR_FILENO]->flags, s, strlen(s), NULL);
+ fd_table[STDERR_FILENO]->ops->write(fd_table[STDERR_FILENO]->fd,
+ fd_table[STDERR_FILENO]->flags, ": ", 2, NULL);
+ }
+ e = strerror(errno);
+ fd_table[STDERR_FILENO]->ops->write(fd_table[STDERR_FILENO]->fd,
+ fd_table[STDERR_FILENO]->flags, e, strlen(e), NULL);
+ fd_table[STDERR_FILENO]->ops->write(fd_table[STDERR_FILENO]->fd,
+ fd_table[STDERR_FILENO]->flags, "\n", 1, NULL);
+ fd_unlock(STDERR_FILENO, FD_WRITE);
+ }
+}
diff --git a/mit-pthreads/stdio/printf.c b/mit-pthreads/stdio/printf.c
new file mode 100644
index 00000000000..a298509d341
--- /dev/null
+++ b/mit-pthreads/stdio/printf.c
@@ -0,0 +1,56 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * Copyright (c) 1993, 1994 Chris Provenzano.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)printf.c 5.6 (Berkeley) 1/20/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <stdarg.h>
+#include <pthread.h>
+#include <stdio.h>
+
+printf(char const *fmt, ...)
+{
+ int ret;
+ va_list ap;
+
+ va_start(ap, fmt);
+ ret = vfprintf(stdout, fmt, ap);
+ va_end(ap);
+ return (ret);
+}
diff --git a/mit-pthreads/stdio/putc.c b/mit-pthreads/stdio/putc.c
new file mode 100644
index 00000000000..ac71e35ff25
--- /dev/null
+++ b/mit-pthreads/stdio/putc.c
@@ -0,0 +1,60 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * Copyright (c) 1993, 1994 Chris Provenzano.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)putc.c 5.1 (Berkeley) 1/20/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <pthread.h>
+#include <stdio.h>
+
+/*
+ * A subroutine version of the macro putc.
+ */
+#undef putc
+
+putc(c, fp)
+ int c;
+ register FILE *fp;
+{
+ int ret;
+ flockfile(fp);
+ ret = __sputc(c, fp);
+ funlockfile(fp);
+ return(ret);
+}
diff --git a/mit-pthreads/stdio/putc_unlocked.c b/mit-pthreads/stdio/putc_unlocked.c
new file mode 100644
index 00000000000..7c9c78ff1e8
--- /dev/null
+++ b/mit-pthreads/stdio/putc_unlocked.c
@@ -0,0 +1,56 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * Copyright (c) 1993, 1994 Chris Provenzano.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)putc.c 5.1 (Berkeley) 1/20/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <pthread.h>
+#include <stdio.h>
+
+/*
+ * A subroutine version of the macro putc.
+ */
+#undef putc_unlocked
+
+putc_unlocked(c, fp)
+ int c;
+ register FILE *fp;
+{
+ return (__sputc(c, fp));
+}
diff --git a/mit-pthreads/stdio/putchar.c b/mit-pthreads/stdio/putchar.c
new file mode 100644
index 00000000000..c22a11ea25d
--- /dev/null
+++ b/mit-pthreads/stdio/putchar.c
@@ -0,0 +1,60 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * Copyright (c) 1993, 1994 Chris Provenzano.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)putchar.c 5.3 (Berkeley) 1/20/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <stdio.h>
+
+#undef putchar
+
+/*
+ * A subroutine version of the macro putchar
+ */
+putchar(c)
+ int c;
+{
+ register FILE *so = stdout;
+ int ret;
+
+ flockfile(so);
+ ret = __sputc(c, so);
+ funlockfile(so);
+ return(ret);
+}
diff --git a/mit-pthreads/stdio/putchar_unlocked.c b/mit-pthreads/stdio/putchar_unlocked.c
new file mode 100644
index 00000000000..df27a501211
--- /dev/null
+++ b/mit-pthreads/stdio/putchar_unlocked.c
@@ -0,0 +1,56 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * Copyright (c) 1993, 1994 Chris Provenzano.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)putchar.c 5.3 (Berkeley) 1/20/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <pthread.h>
+#include <stdio.h>
+
+#undef putchar_unlocked
+/*
+ * A subroutine version of the macro putchar
+ */
+putchar_unlocked(c)
+ int c;
+{
+ register FILE *so = stdout;
+
+ return (__sputc(c, so));
+}
diff --git a/mit-pthreads/stdio/puts.c b/mit-pthreads/stdio/puts.c
new file mode 100644
index 00000000000..97f8b3599f2
--- /dev/null
+++ b/mit-pthreads/stdio/puts.c
@@ -0,0 +1,71 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * Copyright (c) 1993, 1994 Chris Provenzano.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)puts.c 5.6 (Berkeley) 2/24/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <pthread.h>
+#include <stdio.h>
+#include <string.h>
+#include "fvwrite.h"
+
+/*
+ * Write the given string to stdout, appending a newline.
+ */
+puts(s)
+ char const *s;
+{
+ size_t c = strlen(s);
+ struct __suio uio;
+ struct __siov iov[2];
+ int r;
+
+ iov[0].iov_base = (void *)s;
+ iov[0].iov_len = c;
+ iov[1].iov_base = "\n";
+ iov[1].iov_len = 1;
+ uio.uio_resid = c + 1;
+ uio.uio_iov = &iov[0];
+ uio.uio_iovcnt = 2;
+
+ flockfile(stdout);
+ r = (__sfvwrite(stdout, &uio) ? EOF : '\n');
+ funlockfile(stdout);
+ return(r);
+}
diff --git a/mit-pthreads/stdio/putw.c b/mit-pthreads/stdio/putw.c
new file mode 100644
index 00000000000..79473f0e243
--- /dev/null
+++ b/mit-pthreads/stdio/putw.c
@@ -0,0 +1,64 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * Copyright (c) 1993, 1994 Chris Provenzano.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)putw.c 5.3 (Berkeley) 1/20/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <pthread.h>
+#include <stdio.h>
+#include "fvwrite.h"
+
+putw(w, fp)
+ int w;
+ FILE *fp;
+{
+ struct __suio uio;
+ struct __siov iov;
+ int r;
+
+ iov.iov_base = &w;
+ iov.iov_len = uio.uio_resid = sizeof(w);
+ uio.uio_iov = &iov;
+ uio.uio_iovcnt = 1;
+
+ flockfile(fp);
+ r = (__sfvwrite(fp, &uio));
+ funlockfile(fp);
+ return(r);
+}
diff --git a/mit-pthreads/stdio/refill.c b/mit-pthreads/stdio/refill.c
new file mode 100644
index 00000000000..396895e56ff
--- /dev/null
+++ b/mit-pthreads/stdio/refill.c
@@ -0,0 +1,189 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * Copyright (c) 1993, 1994 Chris Provenzano.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)refill.c 5.3 (Berkeley) 2/24/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <pthread.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "local.h"
+#include "glue.h"
+
+extern pthread_mutex_t __sfp_mutex;
+extern pthread_cond_t __sfp_cond;
+extern struct glue __sglue;
+extern int __sfp_state;
+
+/* This function is very similar to __swalk_sflush */
+static void __swalk_lflush()
+{
+ register FILE *fp, *savefp;
+ register int n, saven;
+ register struct glue *g, *saveg;
+
+ /* Only allow other threads to read __sglue */
+ pthread_mutex_lock(&__sfp_mutex);
+ __sfp_state++;
+ pthread_mutex_unlock(&__sfp_mutex);
+
+ saven = 0;
+ saveg = NULL;
+ savefp = NULL;
+ for (g = &__sglue; g != NULL; g = g->next) {
+ for (fp = g->iobs, n = g->niobs; --n >= 0; fp++) {
+ if ((fp->_flags & (__SLBF|__SWR)) == (__SLBF|__SWR)) {
+ /* Is there anything to flush? */
+ if (fp->_bf._base && (fp->_bf._base - fp->_p)) {
+ if (ftrylockfile(fp)) { /* Can we flush it */
+ if (!saven) { /* No, save first fp we can't flush */
+ saven = n;
+ saveg = g;
+ savefp = fp;
+ continue;
+ }
+ } else {
+ (void) __sflush(fp);
+ funlockfile(fp);
+ }
+ }
+ }
+ }
+ }
+ if (savefp) {
+ for (g = saveg; g != NULL; g = g->next) {
+ for (fp = savefp, n = saven + 1; --n >= 0; fp++) {
+ if ((fp->_flags & (__SLBF|__SWR)) == (__SLBF|__SWR)) {
+ /* Anything to flush */
+ while (fp->_bf._base && (fp->_bf._base - fp->_p)) {
+ flockfile(fp);
+ (void) __sflush(fp);
+ funlockfile(fp);
+ }
+ }
+ }
+ }
+ }
+
+ /* If no other readers wakeup a thread waiting to do __sfp */
+ pthread_mutex_lock(&__sfp_mutex);
+ if (! (--__sfp_state)) {
+ pthread_cond_signal(&__sfp_cond);
+ }
+ pthread_mutex_unlock(&__sfp_mutex);
+}
+
+/*
+ * Refill a stdio buffer.
+ * Return EOF on eof or error, 0 otherwise.
+ */
+__srefill(fp)
+ register FILE *fp;
+{
+
+ /* make sure stdio is set up */
+ __sinit ();
+
+ fp->_r = 0; /* largely a convenience for callers */
+
+ /* SysV does not make this test; take it out for compatibility */
+ if (fp->_flags & __SEOF)
+ return (EOF);
+
+ /* if not already reading, have to be reading and writing */
+ if ((fp->_flags & __SRD) == 0) {
+ if ((fp->_flags & __SRW) == 0) {
+ errno = EBADF;
+ return (EOF);
+ }
+ /* switch to reading */
+ if (fp->_flags & __SWR) {
+ if (__sflush(fp))
+ return (EOF);
+ fp->_flags &= ~__SWR;
+ fp->_w = 0;
+ fp->_lbfsize = 0;
+ }
+ fp->_flags |= __SRD;
+ } else {
+ /*
+ * We were reading. If there is an ungetc buffer,
+ * we must have been reading from that. Drop it,
+ * restoring the previous buffer (if any). If there
+ * is anything in that buffer, return.
+ */
+ if (HASUB(fp)) {
+ FREEUB(fp);
+ if ((fp->_r = fp->_ur) != 0) {
+ fp->_p = fp->_up;
+ return (0);
+ }
+ }
+ }
+
+ if (fp->_file == -1) {
+ fp->_flags |= __SEOF;
+ return(EOF);
+ }
+
+ if (fp->_bf._base == NULL)
+ __smakebuf(fp);
+
+ /*
+ * Before reading from a line buffered or unbuffered file,
+ * flush all line buffered output files, per the ANSI C
+ * standard.
+ */
+ if (fp->_flags & (__SLBF|__SNBF))
+ __swalk_lflush();
+ fp->_p = fp->_bf._base;
+ fp->_r = __sread(fp, (char *)fp->_p, fp->_bf._size);
+ fp->_flags &= ~__SMOD; /* buffer contents are again pristine */
+ if (fp->_r <= 0) {
+ if (fp->_r == 0)
+ fp->_flags |= __SEOF;
+ else {
+ fp->_r = 0;
+ fp->_flags |= __SERR;
+ }
+ return (EOF);
+ }
+ return (0);
+}
diff --git a/mit-pthreads/stdio/remove.c b/mit-pthreads/stdio/remove.c
new file mode 100644
index 00000000000..116537e3a0f
--- /dev/null
+++ b/mit-pthreads/stdio/remove.c
@@ -0,0 +1,50 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * Copyright (c) 1993, 1994 Chris Provenzano.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)remove.c 5.3 (Berkeley) 2/24/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <pthread.h>
+#include <unistd.h>
+
+remove(file)
+ const char *file;
+{
+ return (unlink(file));
+}
diff --git a/mit-pthreads/stdio/rewind.c b/mit-pthreads/stdio/rewind.c
new file mode 100644
index 00000000000..17d4418db39
--- /dev/null
+++ b/mit-pthreads/stdio/rewind.c
@@ -0,0 +1,55 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * Copyright (c) 1993, 1994 Chris Provenzano.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)rewind.c 5.6 (Berkeley) 1/20/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <errno.h>
+#include <stdio.h>
+
+void
+rewind(fp)
+ register FILE *fp;
+{
+ flockfile(fp);
+ (void) fseek(fp, 0L, SEEK_SET);
+ fp->_flags &= ~(__SERR|__SEOF); /* clearerr */
+ funlockfile(fp);
+ errno = 0; /* not required, but seems reasonable */
+}
diff --git a/mit-pthreads/stdio/rget.c b/mit-pthreads/stdio/rget.c
new file mode 100644
index 00000000000..a2b19afb130
--- /dev/null
+++ b/mit-pthreads/stdio/rget.c
@@ -0,0 +1,58 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * Copyright (c) 1993, 1994 Chris Provenzano.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)rget.c 5.1 (Berkeley) 1/20/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <stdio.h>
+
+/*
+ * Handle getc() when the buffer ran out:
+ * Refill, then return the first character
+ * in the newly-filled buffer.
+ */
+__srget(fp)
+ register FILE *fp;
+{
+ if (__srefill(fp) == 0) {
+ fp->_r--;
+ return (*fp->_p++);
+ }
+ return (EOF);
+}
diff --git a/mit-pthreads/stdio/scanf.c b/mit-pthreads/stdio/scanf.c
new file mode 100644
index 00000000000..9f9f5a6665e
--- /dev/null
+++ b/mit-pthreads/stdio/scanf.c
@@ -0,0 +1,72 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * Copyright (c) 1993, 1994 Chris Provenzano.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)scanf.c 5.3 (Berkeley) 1/20/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <pthread.h>
+#include <stdio.h>
+#if __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+#if __STDC__
+scanf(char const *fmt, ...)
+#else
+scanf(fmt, va_alist)
+ char *fmt;
+ va_dcl
+#endif
+{
+ int ret;
+ va_list ap;
+
+#if __STDC__
+ va_start(ap, fmt);
+#else
+ va_start(ap);
+#endif
+ flockfile(stdin);
+ ret = __svfscanf(stdin, fmt, ap);
+ funlockfile(stdin);
+ va_end(ap);
+ return (ret);
+}
diff --git a/mit-pthreads/stdio/setbuf.c b/mit-pthreads/stdio/setbuf.c
new file mode 100644
index 00000000000..af8d088089d
--- /dev/null
+++ b/mit-pthreads/stdio/setbuf.c
@@ -0,0 +1,52 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * Copyright (c) 1993, 1994 Chris Provenzano.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)setbuf.c 5.3 (Berkeley) 1/20/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <stdio.h>
+#include "local.h"
+
+void
+setbuf(fp, buf)
+ FILE *fp;
+ char *buf;
+{
+ (void) setvbuf(fp, buf, buf ? _IOFBF : _IONBF, BUFSIZ);
+}
diff --git a/mit-pthreads/stdio/setbuffer.c b/mit-pthreads/stdio/setbuffer.c
new file mode 100644
index 00000000000..0c79e55fd93
--- /dev/null
+++ b/mit-pthreads/stdio/setbuffer.c
@@ -0,0 +1,64 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * Copyright (c) 1993, 1994 Chris Provenzano.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)setbuffer.c 5.5 (Berkeley) 3/18/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <stdio.h>
+
+void
+setbuffer(fp, buf, size)
+ register FILE *fp;
+ char *buf;
+ int size;
+{
+
+ (void) setvbuf(fp, buf, buf ? _IOFBF : _IONBF, size);
+}
+
+/*
+ * set line buffering
+ */
+setlinebuf(fp)
+ FILE *fp;
+{
+
+ (void) setvbuf(fp, (char *)NULL, _IOLBF, (size_t)0);
+ return (0); /* ??? */
+}
diff --git a/mit-pthreads/stdio/setvbuf.c b/mit-pthreads/stdio/setvbuf.c
new file mode 100644
index 00000000000..288d8c32db0
--- /dev/null
+++ b/mit-pthreads/stdio/setvbuf.c
@@ -0,0 +1,154 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * Copyright (c) 1993, 1994 Chris Provenzano.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)setvbuf.c 5.5 (Berkeley) 5/6/93";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "local.h"
+
+/*
+ * Set one of the three kinds of buffering, optionally including
+ * a buffer.
+ */
+setvbuf(fp, buf, mode, size)
+ register FILE *fp;
+ char *buf;
+ register int mode;
+ register size_t size;
+{
+ register int ret, flags;
+ size_t iosize;
+ int ttyflag;
+
+ /*
+ * Verify arguments. The `int' limit on `size' is due to this
+ * particular implementation. Note, buf and size are ignored
+ * when setting _IONBF.
+ */
+ if (mode != _IONBF)
+ if ((mode != _IOFBF && mode != _IOLBF) || (int)size < 0)
+ return (EOF);
+
+ flockfile(fp);
+ /*
+ * Write current buffer, if any. Discard unread input, cancel
+ * line buffering, and free old buffer if malloc()ed.
+ */
+ ret = 0;
+ (void)__sflush(fp);
+ fp->_r = fp->_lbfsize = 0;
+ flags = fp->_flags;
+ if (flags & __SMBF)
+ free((void *)fp->_bf._base);
+ flags &= ~(__SLBF | __SNBF | __SMBF | __SOPT | __SNPT);
+
+ /* If setting unbuffered mode, skip all the hard work. */
+ if (mode == _IONBF)
+ goto nbf;
+
+ /*
+ * Find optimal I/O size for seek optimization. This also returns
+ * a `tty flag' to suggest that we check isatty(fd), but we do not
+ * care since our caller told us how to buffer.
+ */
+ flags |= __swhatbuf(fp, &iosize, &ttyflag);
+ if (size == 0) {
+ buf = NULL; /* force local allocation */
+ size = iosize;
+ }
+
+ /* Allocate buffer if needed. */
+ if (buf == NULL) {
+ if ((buf = malloc(size)) == NULL) {
+ /*
+ * Unable to honor user's request. We will return
+ * failure, but try again with file system size.
+ */
+ ret = EOF;
+ if (size != iosize) {
+ size = iosize;
+ buf = malloc(size);
+ }
+ }
+ if (buf == NULL) {
+ /* No luck; switch to unbuffered I/O. */
+nbf:
+ fp->_flags = flags | __SNBF;
+ fp->_w = 0;
+ fp->_bf._base = fp->_p = fp->_nbuf;
+ fp->_bf._size = 1;
+ funlockfile(fp);
+ return (ret);
+ }
+ flags |= __SMBF;
+ }
+
+ /*
+ * Kill any seek optimization if the buffer is not the
+ * right size.
+ *
+ * SHOULD WE ALLOW MULTIPLES HERE (i.e., ok iff (size % iosize) == 0)?
+ */
+ if (size != iosize)
+ flags |= __SNPT;
+
+ /*
+ * Fix up the FILE fields, and set __cleanup for output flush on
+ * exit (since we are buffered in some way). If in r/w mode, go
+ * to the intermediate state, so that everyone has to call
+ * __srefill or __swsetup on the first operation -- it is more
+ * trouble than it is worth to set things up correctly here.
+ */
+ if (mode == _IOLBF)
+ flags |= __SLBF;
+ if (flags & __SRW)
+ flags &= ~(__SRD | __SWR);
+ fp->_w = size; /* Was 0 (mevans) */
+ fp->_flags = flags;
+ fp->_bf._base = fp->_p = (unsigned char *)buf;
+ fp->_bf._size = size;
+ fp->_lbfsize = 0;
+ __cleanup = _cleanup;
+
+ funlockfile(fp);
+ return (ret);
+}
diff --git a/mit-pthreads/stdio/snprintf.c b/mit-pthreads/stdio/snprintf.c
new file mode 100644
index 00000000000..dd9bca24f73
--- /dev/null
+++ b/mit-pthreads/stdio/snprintf.c
@@ -0,0 +1,79 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * Copyright (c) 1993, 1994 Chris Provenzano.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)snprintf.c 5.1 (Berkeley) 1/20/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <stdio.h>
+#if __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+#if __STDC__
+snprintf(char *str, size_t n, char const *fmt, ...)
+#else
+snprintf(str, n, fmt, va_alist)
+ char *str;
+ size_t n;
+ char *fmt;
+ va_dcl
+#endif
+{
+ int ret;
+ va_list ap;
+ FILE f;
+
+ if ((int)n < 1)
+ return (EOF);
+#if __STDC__
+ va_start(ap, fmt);
+#else
+ va_start(ap);
+#endif
+ f._file = -1;
+ f._flags = __SWR | __SSTR;
+ f._bf._base = f._p = (unsigned char *)str;
+ f._bf._size = f._w = n - 1;
+ ret = vfprintf(&f, fmt, ap);
+ *f._p = 0;
+ va_end(ap);
+ return (ret);
+}
diff --git a/mit-pthreads/stdio/sprintf.c b/mit-pthreads/stdio/sprintf.c
new file mode 100644
index 00000000000..a500e8d4afa
--- /dev/null
+++ b/mit-pthreads/stdio/sprintf.c
@@ -0,0 +1,78 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * Copyright (c) 1993, 1994 Chris Provenzano.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)sprintf.c 5.7 (Berkeley) 1/20/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <limits.h>
+#include <stdio.h>
+#if __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+#include "local.h"
+
+#if __STDC__
+sprintf(char *str, char const *fmt, ...)
+#else
+sprintf(str, fmt, va_alist)
+ char *str;
+ char *fmt;
+ va_dcl
+#endif
+{
+ int ret;
+ va_list ap;
+ FILE f;
+
+ f._file = -1;
+ f._flags = __SWR | __SSTR;
+ f._bf._base = f._p = (unsigned char *)str;
+ f._bf._size = f._w = INT_MAX;
+#if __STDC__
+ va_start(ap, fmt);
+#else
+ va_start(ap);
+#endif
+ ret = vfprintf(&f, fmt, ap);
+ va_end(ap);
+ *f._p = 0;
+ return (ret);
+}
diff --git a/mit-pthreads/stdio/sscanf.c b/mit-pthreads/stdio/sscanf.c
new file mode 100644
index 00000000000..50148192b9c
--- /dev/null
+++ b/mit-pthreads/stdio/sscanf.c
@@ -0,0 +1,79 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * Copyright (c) 1993, 1994 Chris Provenzano.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)sscanf.c 5.1 (Berkeley) 1/20/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <stdio.h>
+#include <string.h>
+#if __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+#include "local.h"
+
+#if __STDC__
+sscanf(const char *str, char const *fmt, ...)
+#else
+sscanf(str, fmt, va_alist)
+ const char *str;
+ char *fmt;
+ va_dcl
+#endif
+{
+ int ret;
+ va_list ap;
+ FILE f;
+
+ f._flags = __SRD;
+ f._file = -1;
+ f._bf._base = f._p = (unsigned char *)str;
+ f._bf._size = f._r = strlen(str);
+ f._ub._base = NULL;
+ f._lb._base = NULL;
+#if __STDC__
+ va_start(ap, fmt);
+#else
+ va_start(ap);
+#endif
+ ret = __svfscanf(&f, fmt, ap);
+ va_end(ap);
+ return (ret);
+}
diff --git a/mit-pthreads/stdio/stdio.c b/mit-pthreads/stdio/stdio.c
new file mode 100644
index 00000000000..0b676eeb09b
--- /dev/null
+++ b/mit-pthreads/stdio/stdio.c
@@ -0,0 +1,104 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * Copyright (c) 1993, 1994 Chris Provenzano.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)stdio.c 5.3 (Berkeley) 2/24/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <pthread.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdio.h>
+#include "local.h"
+
+/*
+ * Small standard I/O/seek/close functions.
+ * These maintain the `known seek offset' for seek optimisation.
+ */
+int __sread(FILE *fp, char *buf, int n)
+{
+ register int ret;
+
+ /* if the read succeeded, update the current offset */
+ if (fd_table[fp->_file]->ops->use_kfds < 2) {
+ ret = fd_table[fp->_file]->ops->read(fd_table[fp->_file]->fd,
+ fd_table[fp->_file]->flags, buf, n, NULL);
+ } else {
+ pthread_ssize_t (*readfn)() = fd_table[fp->_file]->ops->read;
+ ret = readfn(fd_table[fp->_file]->fd, buf, n);
+ }
+ if (ret >= 0) {
+ fp->_offset += ret;
+ } else {
+ fp->_flags &= ~__SOFF; /* paranoia */
+ }
+ return (ret);
+}
+
+int __swrite(FILE *fp, const char *buf, int n)
+{
+ if (fp->_flags & __SAPP)
+ (void) lseek(fp->_file, (off_t)0, SEEK_END);
+ fp->_flags &= ~__SOFF; /* in case FAPPEND mode is set */
+ if (fd_table[fp->_file]->ops->use_kfds < 2) {
+ return(fd_table[fp->_file]->ops->write(fd_table[fp->_file]->fd,
+ fd_table[fp->_file]->flags, buf, n, NULL));
+ } else {
+ pthread_ssize_t (*writefn)() = fd_table[fp->_file]->ops->write;
+ return(writefn(fd_table[fp->_file]->fd,buf,n));
+ }
+}
+
+fpos_t __sseek(FILE *fp, off_t offset, int whence)
+{
+ register fpos_t ret;
+
+ ret = (fpos_t)lseek(fp->_file, offset, whence);
+ if (ret == -1L)
+ fp->_flags &= ~__SOFF;
+ else {
+ fp->_flags |= __SOFF;
+ fp->_offset = ret;
+ }
+ return (ret);
+}
+
+int __sclose(FILE *fp)
+{
+ return (close(fp->_file));
+}
diff --git a/mit-pthreads/stdio/strerror.c b/mit-pthreads/stdio/strerror.c
new file mode 100644
index 00000000000..5aea7e7a4fc
--- /dev/null
+++ b/mit-pthreads/stdio/strerror.c
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 1988 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)strerror.c 5.6 (Berkeley) 5/4/91";
+#endif /* LIBC_SCCS and not lint */
+
+#include <string.h>
+
+char *
+strerror(num)
+ int num;
+{
+ extern int sys_nerr;
+ extern char *sys_errlist[];
+#define UPREFIX "Unknown error: "
+ static char ebuf[40] = UPREFIX; /* 64-bit number + slop */
+ register unsigned int errnum;
+ register char *p, *t;
+ char tmp[40];
+
+ errnum = num; /* convert to unsigned */
+ if (errnum < sys_nerr)
+ return(sys_errlist[errnum]);
+
+ /* Do this by hand, so we don't include stdio(3). */
+ t = tmp;
+ do {
+ *t++ = "0123456789"[errnum % 10];
+ } while (errnum /= 10);
+ for (p = ebuf + sizeof(UPREFIX) - 1;;) {
+ *p++ = *--t;
+ if (t <= tmp)
+ break;
+ }
+ return(ebuf);
+}
diff --git a/mit-pthreads/stdio/tempnam.c b/mit-pthreads/stdio/tempnam.c
new file mode 100644
index 00000000000..88150a18019
--- /dev/null
+++ b/mit-pthreads/stdio/tempnam.c
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 1988 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)tempnam.c 5.1 (Berkeley) 2/22/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/param.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+/* #include <paths.h> */
+
+char *
+tempnam(dir, pfx)
+ const char *dir, *pfx;
+{
+ int sverrno;
+ char *f, *name;
+
+ if (!(name = malloc(MAXPATHLEN)))
+ return(NULL);
+
+ if (!pfx)
+ pfx = "tmp.";
+
+ if (f = getenv("TMPDIR")) {
+ (void)snprintf(name, MAXPATHLEN, "%s%s%sXXXXXX", f,
+ *(f + strlen(f) - 1) == '/'? "": "/", pfx);
+ if (f = mktemp(name))
+ return(f);
+ }
+
+ if (f = (char *)dir) {
+ (void)snprintf(name, MAXPATHLEN, "%s%s%sXXXXXX", f,
+ *(f + strlen(f) - 1) == '/'? "": "/", pfx);
+ if (f = mktemp(name))
+ return(f);
+ }
+
+ f = P_tmpdir;
+ (void)snprintf(name, MAXPATHLEN, "%s%sXXXXXX", f, pfx);
+ if (f = mktemp(name))
+ return(f);
+
+ f = _PATH_TMP;
+ (void)snprintf(name, MAXPATHLEN, "%s%sXXXXXX", f, pfx);
+ if (f = mktemp(name))
+ return(f);
+
+ sverrno = errno;
+ free(name);
+ errno = sverrno;
+ return(NULL);
+}
diff --git a/mit-pthreads/stdio/tmpfile.c b/mit-pthreads/stdio/tmpfile.c
new file mode 100644
index 00000000000..471bed33716
--- /dev/null
+++ b/mit-pthreads/stdio/tmpfile.c
@@ -0,0 +1,80 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)tmpfile.c 5.4 (Berkeley) 5/27/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/types.h>
+#include <signal.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdio.h>
+#include <paths.h>
+
+FILE *
+tmpfile()
+{
+ sigset_t set, oset;
+ FILE *fp;
+ int fd, sverrno;
+#define TRAILER "tmp.XXXXXX"
+ char buf[sizeof(_PATH_TMP) + sizeof(TRAILER)];
+
+ memcpy(buf, _PATH_TMP, sizeof(_PATH_TMP) - 1);
+ memcpy( buf + sizeof(_PATH_TMP) - 1, TRAILER, sizeof(TRAILER));
+
+ sigfillset(&set);
+ (void)sigprocmask(SIG_BLOCK, &set, &oset);
+
+ fd = mkstemp(buf);
+ if (fd != -1)
+ (void)unlink(buf);
+
+ (void)sigprocmask(SIG_SETMASK, &oset, NULL);
+
+ if (fd == -1)
+ return (NULL);
+
+ if (!(fp = fdopen(fd, "w+"))) {
+ sverrno = errno;
+ (void)close(fd);
+ errno = sverrno;
+ return (NULL);
+ }
+ return (fp);
+}
diff --git a/mit-pthreads/stdio/tmpnam.c b/mit-pthreads/stdio/tmpnam.c
new file mode 100644
index 00000000000..8d65b21b037
--- /dev/null
+++ b/mit-pthreads/stdio/tmpnam.c
@@ -0,0 +1,55 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)tmpnam.c 5.3 (Berkeley) 2/24/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <unistd.h>
+#include <stdio.h>
+
+char *
+tmpnam(s)
+ char *s;
+{
+ static char buf[L_tmpnam];
+
+ if (s == NULL)
+ s = buf;
+ (void)snprintf(s, L_tmpnam, "%stmp.XXXXXX", P_tmpdir);
+ return(mktemp(s));
+}
diff --git a/mit-pthreads/stdio/ungetc.c b/mit-pthreads/stdio/ungetc.c
new file mode 100644
index 00000000000..e035f93d5f2
--- /dev/null
+++ b/mit-pthreads/stdio/ungetc.c
@@ -0,0 +1,155 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * Copyright (c) 1993, 1994 Chris Provenzano.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)ungetc.c 5.6 (Berkeley) 5/4/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "local.h"
+
+/*
+ * Expand the ungetc buffer `in place'. That is, adjust fp->_p when
+ * the buffer moves, so that it points the same distance from the end,
+ * and move the bytes in the buffer around as necessary so that they
+ * are all at the end (stack-style).
+ */
+static
+__submore(fp)
+ register FILE *fp;
+{
+ register int i;
+ register unsigned char *p;
+
+ if (fp->_ub._base == fp->_ubuf) {
+ /*
+ * Get a new buffer (rather than expanding the old one).
+ */
+ if ((p = malloc((size_t)BUFSIZ)) == NULL)
+ return (EOF);
+ fp->_ub._base = p;
+ fp->_ub._size = BUFSIZ;
+ p += BUFSIZ - sizeof(fp->_ubuf);
+ for (i = sizeof(fp->_ubuf); --i >= 0;)
+ p[i] = fp->_ubuf[i];
+ fp->_p = p;
+ return (0);
+ }
+ i = fp->_ub._size;
+ p = realloc(fp->_ub._base, i << 1);
+ if (p == NULL)
+ return (EOF);
+ (void) memcpy((void *)(p + i), (void *)p, (size_t)i);
+ fp->_p = p + i;
+ fp->_ub._base = p;
+ fp->_ub._size = i << 1;
+ return (0);
+}
+
+ungetc(c, fp)
+ int c;
+ register FILE *fp;
+{
+ if (c == EOF)
+ return (EOF);
+ __sinit ();
+
+ flockfile(fp);
+ if ((fp->_flags & __SRD) == 0) {
+ /*
+ * Not already reading: no good unless reading-and-writing.
+ * Otherwise, flush any current write stuff.
+ */
+ if ((fp->_flags & __SRW) == 0)
+ c = EOF;
+ goto ungetc_end;
+ if (fp->_flags & __SWR) {
+ if (__sflush(fp))
+ c = EOF;
+ goto ungetc_end;
+ fp->_flags &= ~__SWR;
+ fp->_w = 0;
+ fp->_lbfsize = 0;
+ }
+ fp->_flags |= __SRD;
+ }
+ c = (unsigned char)c;
+
+ /*
+ * If we are in the middle of ungetc'ing, just continue.
+ * This may require expanding the current ungetc buffer.
+ */
+ if (HASUB(fp)) {
+ if (fp->_r >= fp->_ub._size && __submore(fp))
+ return (EOF);
+ *--fp->_p = c;
+ fp->_r++;
+ goto ungetc_end;
+ }
+
+ /*
+ * If we can handle this by simply backing up, do so,
+ * but never replace the original character.
+ * (This makes sscanf() work when scanning `const' data.)
+ */
+ if (fp->_bf._base != NULL && fp->_p > fp->_bf._base &&
+ fp->_p[-1] == c) {
+ fp->_p--;
+ fp->_r++;
+ goto ungetc_end;
+ }
+
+ /*
+ * Create an ungetc buffer.
+ * Initially, we will use the `reserve' buffer.
+ */
+ fp->_ur = fp->_r;
+ fp->_up = fp->_p;
+ fp->_ub._base = fp->_ubuf;
+ fp->_ub._size = sizeof(fp->_ubuf);
+ fp->_ubuf[sizeof(fp->_ubuf) - 1] = c;
+ fp->_p = &fp->_ubuf[sizeof(fp->_ubuf) - 1];
+ fp->_r = 1;
+
+ungetc_end:;
+ funlockfile(fp);
+ return (c);
+}
diff --git a/mit-pthreads/stdio/vfprintf.c b/mit-pthreads/stdio/vfprintf.c
new file mode 100644
index 00000000000..fd990bb1889
--- /dev/null
+++ b/mit-pthreads/stdio/vfprintf.c
@@ -0,0 +1,788 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * Copyright (c) 1993, 1994 Chris Provenzano.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)vfprintf.c 5.50 (Berkeley) 12/16/92";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+/*
+ * Actual printf innards.
+ *
+ * This code is large and complicated...
+ */
+
+#include <pthread.h>
+#include <sys/types.h>
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "local.h"
+#include "fvwrite.h"
+
+/* Define FLOATING_POINT to get floating point. */
+#define FLOATING_POINT
+
+/*
+ * Flush out all the vectors defined by the given uio,
+ * then reset it so that it can be reused.
+ */
+static int
+__sprint(fp, uio)
+ register FILE* fp;
+ register struct __suio *uio;
+{
+ register int err;
+
+ if (uio->uio_resid == 0) {
+ uio->uio_iovcnt = 0;
+ return (0);
+ }
+ err = __sfvwrite(fp, uio);
+ uio->uio_resid = 0;
+ uio->uio_iovcnt = 0;
+ return (err);
+}
+
+/*
+ * Helper function for `fprintf to unbuffered unix file': creates a
+ * temporary buffer. We only work on write-only files; this avoids
+ * worries about ungetc buffers and so forth.
+ */
+static int
+__sbprintf(fp, fmt, ap)
+ FILE *fp;
+ const char *fmt;
+ pthread_va_list ap;
+{
+ unsigned char buf[BUFSIZ];
+ FILE fake;
+ int ret;
+
+ /* copy the important variables */
+ fake._flags = fp->_flags & ~__SNBF;
+ fake._file = fp->_file;
+
+ /* set up the buffer */
+ fake._bf._base = fake._p = buf;
+ fake._bf._size = fake._w = sizeof(buf);
+ fake._lbfsize = 0; /* not actually used, but Just In Case */
+
+ /* do the work, then copy any error status */
+ ret = vfprintf(&fake, fmt, ap);
+ if (ret >= 0 && fflush(&fake))
+ ret = EOF;
+ if (fake._flags & __SERR)
+ fp->_flags |= __SERR;
+ return (ret);
+}
+
+
+#ifdef FLOATING_POINT
+#include <locale.h>
+#include <math.h>
+#include "floatio.h"
+
+#define BUF (MAXEXP+MAXFRACT+1) /* + decimal point */
+#define DEFPREC 6
+
+static char *cvt __P_((double, int, int, char *, int *, int, int *));
+static int exponent __P_((char *, int, int));
+
+#else /* no FLOATING_POINT */
+
+#define BUF 40
+
+#endif /* FLOATING_POINT */
+
+
+/*
+ * Macros for converting digits to letters and vice versa
+ */
+#define to_digit(c) ((c) - '0')
+#define is_digit(c) ((unsigned)to_digit(c) <= 9)
+#define to_char(n) ((n) + '0')
+
+/*
+ * Flags used during conversion.
+ */
+#define ALT 0x001 /* alternate form */
+#define HEXPREFIX 0x002 /* add 0x or 0X prefix */
+#define LADJUST 0x004 /* left adjustment */
+#define LONGDBL 0x008 /* long double; unimplemented */
+#define LONGINT 0x010 /* long integer */
+#define QUADINT 0x020 /* quad integer */
+#define SHORTINT 0x040 /* short integer */
+#define ZEROPAD 0x080 /* zero (as opposed to blank) pad */
+#define FPT 0x100 /* Floating point number */
+int
+vfprintf(fp, fmt0, ap)
+ FILE *fp;
+ const char *fmt0;
+ pthread_va_list ap;
+{
+ register char *fmt; /* format string */
+ register int ch; /* character from fmt */
+ register int n; /* handy integer (short term usage) */
+ register char *cp; /* handy char pointer (short term usage) */
+ register struct __siov *iovp;/* for PRINT macro */
+ register int flags; /* flags as above */
+ int ret; /* return value accumulator */
+ int width; /* width from format (%8d), or 0 */
+ int prec; /* precision from format (%.3d), or -1 */
+ char sign; /* sign prefix (' ', '+', '-', or \0) */
+#ifdef FLOATING_POINT
+ char softsign; /* temporary negative sign for floats */
+ double _double; /* double precision arguments %[eEfgG] */
+ int expt; /* integer value of exponent */
+ int expsize; /* character count for expstr */
+ int ndig; /* actual number of digits returned by cvt */
+ char expstr[7]; /* buffer for exponent string */
+#endif
+
+#if defined (__alpha) && !defined(_GNUC_)
+#define quad_t long
+#define u_quad_t unsigned long
+#else /* gcc has builtin quad type (long long) SOS */
+#define quad_t long long
+#define u_quad_t unsigned long long
+#endif
+
+ u_quad_t _uquad; /* integer arguments %[diouxX] */
+ enum { OCT, DEC, HEX } base;/* base for [diouxX] conversion */
+ int dprec; /* a copy of prec if [diouxX], 0 otherwise */
+ int fieldsz; /* field size expanded by sign, etc */
+ int realsz; /* field size expanded by dprec */
+ int size; /* size of converted field or string */
+ char *xdigs; /* digits for [xX] conversion */
+#define NIOV 8
+ struct __suio uio; /* output information: summary */
+ struct __siov iov[NIOV];/* ... and individual io vectors */
+ char buf[BUF]; /* space for %c, %[diouxX], %[eEfgG] */
+ char ox[2]; /* space for 0x hex-prefix */
+
+ /*
+ * Choose PADSIZE to trade efficiency vs. size. If larger printf
+ * fields occur frequently, increase PADSIZE and make the initialisers
+ * below longer.
+ */
+#define PADSIZE 16 /* pad chunk size */
+ static char blanks[PADSIZE] =
+ {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
+ static char zeroes[PADSIZE] =
+ {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};
+
+ /*
+ * BEWARE, these `goto error' on error, and PAD uses `n'.
+ */
+#define PRINT(ptr, len) { \
+ iovp->iov_base = (ptr); \
+ iovp->iov_len = (len); \
+ uio.uio_resid += (len); \
+ iovp++; \
+ if (++uio.uio_iovcnt >= NIOV) { \
+ if (__sprint(fp, &uio)) \
+ goto error; \
+ iovp = iov; \
+ } \
+}
+#define PAD(howmany, with) { \
+ if ((n = (howmany)) > 0) { \
+ while (n > PADSIZE) { \
+ PRINT(with, PADSIZE); \
+ n -= PADSIZE; \
+ } \
+ PRINT(with, n); \
+ } \
+}
+#define FLUSH() { \
+ if (uio.uio_resid && __sprint(fp, &uio)) \
+ goto error; \
+ uio.uio_iovcnt = 0; \
+ iovp = iov; \
+}
+
+ /*
+ * To extend shorts properly, we need both signed and unsigned
+ * argument extraction methods.
+ */
+#define SARG() \
+ (flags&QUADINT ? va_arg(ap, quad_t) : \
+ flags&LONGINT ? va_arg(ap, long) : \
+ flags&SHORTINT ? (long)(short)va_arg(ap, int) : \
+ (long)va_arg(ap, int))
+#define UARG() \
+ (flags&QUADINT ? va_arg(ap, u_quad_t) : \
+ flags&LONGINT ? va_arg(ap, u_long) : \
+ flags&SHORTINT ? (u_long)(u_short)va_arg(ap, int) : \
+ (u_long)va_arg(ap, u_int))
+
+ flockfile(fp);
+
+ /* sorry, fprintf(read_only_file, "") returns EOF, not 0 */
+ if (cantwrite(fp))
+ return (EOF);
+
+ /* optimise fprintf(stderr) (and other unbuffered Unix files) */
+ if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) &&
+ fp->_file >= 0) {
+ ret = (__sbprintf(fp, fmt0, ap));
+ funlockfile(fp);
+ return(ret);
+ }
+
+ fmt = (char *)fmt0;
+ uio.uio_iov = iovp = iov;
+ uio.uio_resid = 0;
+ uio.uio_iovcnt = 0;
+ ret = 0;
+
+ /*
+ * Scan the format for conversions (`%' character).
+ */
+ for (;;) {
+ for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++)
+ /* void */;
+ if ((n = fmt - cp) != 0) {
+ PRINT(cp, n);
+ ret += n;
+ }
+ if (ch == '\0')
+ goto done;
+ fmt++; /* skip over '%' */
+
+ flags = 0;
+ dprec = 0;
+ width = 0;
+ prec = -1;
+ sign = '\0';
+
+rflag: ch = *fmt++;
+reswitch: switch (ch) {
+ case ' ':
+ /*
+ * ``If the space and + flags both appear, the space
+ * flag will be ignored.''
+ * -- ANSI X3J11
+ */
+ if (!sign)
+ sign = ' ';
+ goto rflag;
+ case '#':
+ flags |= ALT;
+ goto rflag;
+ case '*':
+ /*
+ * ``A negative field width argument is taken as a
+ * - flag followed by a positive field width.''
+ * -- ANSI X3J11
+ * They don't exclude field widths read from args.
+ */
+ if ((width = va_arg(ap, int)) >= 0)
+ goto rflag;
+ width = -width;
+ /* FALLTHROUGH */
+ case '-':
+ flags |= LADJUST;
+ goto rflag;
+ case '+':
+ sign = '+';
+ goto rflag;
+ case '.':
+ if ((ch = *fmt++) == '*') {
+ n = va_arg(ap, int);
+ prec = n < 0 ? -1 : n;
+ goto rflag;
+ }
+ n = 0;
+ while (is_digit(ch)) {
+ n = 10 * n + to_digit(ch);
+ ch = *fmt++;
+ }
+ prec = n < 0 ? -1 : n;
+ goto reswitch;
+ case '0':
+ /*
+ * ``Note that 0 is taken as a flag, not as the
+ * beginning of a field width.''
+ * -- ANSI X3J11
+ */
+ flags |= ZEROPAD;
+ goto rflag;
+ case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ n = 0;
+ do {
+ n = 10 * n + to_digit(ch);
+ ch = *fmt++;
+ } while (is_digit(ch));
+ width = n;
+ goto reswitch;
+#ifdef FLOATING_POINT
+ case 'L':
+ flags |= LONGDBL;
+ goto rflag;
+#endif
+ case 'h':
+ flags |= SHORTINT;
+ goto rflag;
+ case 'l':
+ flags |= LONGINT;
+ goto rflag;
+ case 'q':
+ flags |= QUADINT;
+ goto rflag;
+ case 'c':
+ *(cp = buf) = va_arg(ap, int);
+ size = 1;
+ sign = '\0';
+ break;
+ case 'D':
+ flags |= LONGINT;
+ /*FALLTHROUGH*/
+ case 'd':
+ case 'i':
+ _uquad = SARG();
+ if ((quad_t)_uquad < 0) {
+ _uquad = -_uquad;
+ sign = '-';
+ }
+ base = DEC;
+ goto number;
+#ifdef FLOATING_POINT
+ case 'e':
+ case 'E':
+ case 'f':
+ case 'g':
+ case 'G':
+ if (prec == -1) {
+ prec = DEFPREC;
+ } else if ((ch == 'g' || ch == 'G') && prec == 0) {
+ prec = 1;
+ }
+
+ if (flags & LONGDBL) {
+ _double = (double) va_arg(ap, long double);
+ } else {
+ _double = va_arg(ap, double);
+ }
+
+ /* do this before tricky precision changes */
+ /* if (isinf(_double)) {
+ if (_double < 0)
+ sign = '-';
+ cp = "Inf";
+ size = 3;
+ break;
+ } */
+/* if (isnan(_double)) {
+ cp = "NaN";
+ size = 3;
+ break;
+ } */
+
+ flags |= FPT;
+ cp = cvt(_double, prec, flags, &softsign,
+ &expt, ch, &ndig);
+ if (ch == 'g' || ch == 'G') {
+ if (expt <= -4 || expt > prec)
+ ch = (ch == 'g') ? 'e' : 'E';
+ else
+ ch = 'g';
+ }
+ if (ch <= 'e') { /* 'e' or 'E' fmt */
+ --expt;
+ expsize = exponent(expstr, expt, ch);
+ size = expsize + ndig;
+ if (ndig > 1 || flags & ALT)
+ ++size;
+ } else if (ch == 'f') { /* f fmt */
+ if (expt > 0) {
+ size = expt;
+ if (prec || flags & ALT)
+ size += prec + 1;
+ } else /* "0.X" */
+ size = prec + 2;
+ } else if (expt >= ndig) { /* fixed g fmt */
+ size = expt;
+ if (flags & ALT)
+ ++size;
+ } else
+ size = ndig + (expt > 0 ?
+ 1 : 2 - expt);
+
+ if (softsign)
+ sign = '-';
+ break;
+#endif /* FLOATING_POINT */
+ case 'n':
+ if (flags & QUADINT)
+ *va_arg(ap, quad_t *) = ret;
+ else if (flags & LONGINT)
+ *va_arg(ap, long *) = ret;
+ else if (flags & SHORTINT)
+ *va_arg(ap, short *) = ret;
+ else
+ *va_arg(ap, int *) = ret;
+ continue; /* no output */
+ case 'O':
+ flags |= LONGINT;
+ /*FALLTHROUGH*/
+ case 'o':
+ _uquad = UARG();
+ base = OCT;
+ goto nosign;
+ case 'p':
+ /*
+ * ``The argument shall be a pointer to void. The
+ * value of the pointer is converted to a sequence
+ * of printable characters, in an implementation-
+ * defined manner.''
+ * -- ANSI X3J11
+ */
+ /* NOSTRICT */
+ _uquad = (u_quad_t)(size_t)va_arg(ap, void *);
+ base = HEX;
+ xdigs = "0123456789abcdef";
+ flags |= HEXPREFIX;
+ ch = 'x';
+ goto nosign;
+ case 's':
+ if ((cp = va_arg(ap, char *)) == NULL)
+ cp = "(null)";
+ if (prec >= 0) {
+ /*
+ * can't use strlen; can only look for the
+ * NUL in the first `prec' characters, and
+ * strlen() will go further.
+ */
+ char *p = memchr(cp, 0, prec);
+
+ if (p != NULL) {
+ size = p - cp;
+ if (size > prec)
+ size = prec;
+ } else
+ size = prec;
+ } else
+ size = strlen(cp);
+ sign = '\0';
+ break;
+ case 'U':
+ flags |= LONGINT;
+ /*FALLTHROUGH*/
+ case 'u':
+ _uquad = UARG();
+ base = DEC;
+ goto nosign;
+ case 'X':
+ xdigs = "0123456789ABCDEF";
+ goto hex;
+ case 'x':
+ xdigs = "0123456789abcdef";
+hex: _uquad = UARG();
+ base = HEX;
+ /* leading 0x/X only if non-zero */
+ if (flags & ALT && _uquad != 0)
+ flags |= HEXPREFIX;
+
+ /* unsigned conversions */
+nosign: sign = '\0';
+ /*
+ * ``... diouXx conversions ... if a precision is
+ * specified, the 0 flag will be ignored.''
+ * -- ANSI X3J11
+ */
+number: if ((dprec = prec) >= 0)
+ flags &= ~ZEROPAD;
+
+ /*
+ * ``The result of converting a zero value with an
+ * explicit precision of zero is no characters.''
+ * -- ANSI X3J11
+ */
+ cp = buf + BUF;
+ if (_uquad != 0 || prec != 0) {
+ /*
+ * Unsigned mod is hard, and unsigned mod
+ * by a constant is easier than that by
+ * a variable; hence this switch.
+ */
+ switch (base) {
+ case OCT:
+ do {
+ *--cp = to_char(_uquad & 7);
+ _uquad >>= 3;
+ } while (_uquad);
+ /* handle octal leading 0 */
+ if (flags & ALT && *cp != '0')
+ *--cp = '0';
+ break;
+
+ case DEC:
+ /* many numbers are 1 digit */
+ while (_uquad >= 10) {
+ *--cp = to_char(_uquad % 10);
+ _uquad /= 10;
+ }
+ *--cp = to_char(_uquad);
+ break;
+
+ case HEX:
+ do {
+ *--cp = xdigs[_uquad & 15];
+ _uquad >>= 4;
+ } while (_uquad);
+ break;
+
+ default:
+ cp = "bug in vfprintf: bad base";
+ size = strlen(cp);
+ goto skipsize;
+ }
+ }
+ size = buf + BUF - cp;
+ skipsize:
+ break;
+ default: /* "%?" prints ?, unless ? is NUL */
+ if (ch == '\0')
+ goto done;
+ /* pretend it was %c with argument ch */
+ cp = buf;
+ *cp = ch;
+ size = 1;
+ sign = '\0';
+ break;
+ }
+
+ /*
+ * All reasonable formats wind up here. At this point, `cp'
+ * points to a string which (if not flags&LADJUST) should be
+ * padded out to `width' places. If flags&ZEROPAD, it should
+ * first be prefixed by any sign or other prefix; otherwise,
+ * it should be blank padded before the prefix is emitted.
+ * After any left-hand padding and prefixing, emit zeroes
+ * required by a decimal [diouxX] precision, then print the
+ * string proper, then emit zeroes required by any leftover
+ * floating precision; finally, if LADJUST, pad with blanks.
+ *
+ * Compute actual size, so we know how much to pad.
+ * fieldsz excludes decimal prec; realsz includes it.
+ */
+ fieldsz = size;
+ if (sign)
+ fieldsz++;
+ else if (flags & HEXPREFIX)
+ fieldsz += 2;
+ realsz = dprec > fieldsz ? dprec : fieldsz;
+
+ /* right-adjusting blank padding */
+ if ((flags & (LADJUST|ZEROPAD)) == 0)
+ PAD(width - realsz, blanks);
+
+ /* prefix */
+ if (sign) {
+ PRINT(&sign, 1);
+ } else if (flags & HEXPREFIX) {
+ ox[0] = '0';
+ ox[1] = ch;
+ PRINT(ox, 2);
+ }
+
+ /* right-adjusting zero padding */
+ if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
+ PAD(width - realsz, zeroes);
+
+ /* leading zeroes from decimal precision */
+ PAD(dprec - fieldsz, zeroes);
+
+ /* the string or number proper */
+#ifdef FLOATING_POINT
+ if ((flags & FPT) == 0) {
+ PRINT(cp, size);
+ } else { /* glue together f_p fragments */
+ if (ch >= 'f') { /* 'f' or 'g' */
+ if (_double == 0) {
+ /* kludge for __dtoa irregularity */
+ if (expt >= ndig && (flags & ALT) == 0) {
+ PRINT("0", 1);
+ } else {
+ PRINT("0.", 2);
+ PAD(ndig - 1, zeroes);
+ }
+ } else if (expt <= 0) {
+ PRINT("0.", 2);
+ PAD(-expt, zeroes);
+ PRINT(cp, ndig);
+ } else if (expt >= ndig) {
+ PRINT(cp, ndig);
+ PAD(expt - ndig, zeroes);
+ if (flags & ALT)
+ PRINT(".", 1);
+ } else {
+ PRINT(cp, expt);
+ cp += expt;
+ PRINT(".", 1);
+ PRINT(cp, ndig-expt);
+ }
+ } else { /* 'e' or 'E' */
+ if (ndig > 1 || flags & ALT) {
+ ox[0] = *cp++;
+ ox[1] = '.';
+ PRINT(ox, 2);
+ if (_double || flags & ALT == 0) {
+ PRINT(cp, ndig-1);
+ } else /* 0.[0..] */
+ /* __dtoa irregularity */
+ PAD(ndig - 1, zeroes);
+ } else /* XeYYY */
+ PRINT(cp, 1);
+ PRINT(expstr, expsize);
+ }
+ }
+#else
+ PRINT(cp, size);
+#endif
+ /* left-adjusting padding (always blank) */
+ if (flags & LADJUST)
+ PAD(width - realsz, blanks);
+
+ /* finally, adjust ret */
+ ret += width > realsz ? width : realsz;
+
+ FLUSH(); /* copy out the I/O vectors */
+ }
+done:
+ FLUSH();
+error:
+ if (__sferror(fp))
+ ret = EOF;
+ funlockfile(fp);
+ return (ret);
+}
+
+#ifdef FLOATING_POINT
+
+extern char *__dtoa __P_((double, int, int, int *, int *, char **));
+
+static char *
+cvt(value, ndigits, flags, sign, decpt, ch, length)
+ double value;
+ int ndigits, flags, *decpt, ch, *length;
+ char *sign;
+{
+ int mode, dsgn;
+ char *digits, *bp, *rve;
+
+ if (ch == 'f') {
+ mode = 3; /* ndigits after the decimal point */
+ } else {
+ /* To obtain ndigits after the decimal point for the 'e'
+ * and 'E' formats, round to ndigits + 1 significant
+ * figures.
+ */
+ if (ch == 'e' || ch == 'E') {
+ ndigits++;
+ }
+ mode = 2; /* ndigits significant digits */
+ }
+
+ if (value < 0) {
+ value = -value;
+ *sign = '-';
+ } else
+ *sign = '\000';
+/* #if !defined(__alpha__) && !defined(hpux) */
+#ifndef THIS_IS_NEVER_DEFINED
+ digits = __dtoa(value, mode, ndigits, decpt, &dsgn, &rve);
+#else
+ { char *ecvt(double,int,int*,int*);
+
+ digits = ecvt(value, ndigits, decpt, &dsgn);
+ rve = (digits + (int)strlen(digits));
+ }
+#endif
+ if ((ch != 'g' && ch != 'G') || flags & ALT) { /* Print trailing zeros */
+ bp = digits + ndigits;
+ if (ch == 'f') {
+ if (*digits == '0' && value)
+ *decpt = -ndigits + 1;
+ bp += *decpt;
+ }
+ if (value == 0) /* kludge for __dtoa irregularity */
+ rve = bp;
+ while (rve < bp)
+ *rve++ = '0';
+ }
+ *length = rve - digits;
+ return (digits);
+}
+
+static int
+exponent(p0, exp, fmtch)
+ char *p0;
+ int exp, fmtch;
+{
+ register char *p, *t;
+ char expbuf[MAXEXP];
+
+ p = p0;
+ *p++ = fmtch;
+ if (exp < 0) {
+ exp = -exp;
+ *p++ = '-';
+ }
+ else
+ *p++ = '+';
+ t = expbuf + MAXEXP;
+ if (exp > 9) {
+ do {
+ *--t = to_char(exp % 10);
+ } while ((exp /= 10) > 9);
+ *--t = to_char(exp);
+ for (; t < expbuf + MAXEXP; *p++ = *t++);
+ }
+ else {
+ *p++ = '0';
+ *p++ = to_char(exp);
+ }
+ return (p - p0);
+}
+#endif /* FLOATING_POINT */
diff --git a/mit-pthreads/stdio/vfscanf.c b/mit-pthreads/stdio/vfscanf.c
new file mode 100644
index 00000000000..f6d0a40aa51
--- /dev/null
+++ b/mit-pthreads/stdio/vfscanf.c
@@ -0,0 +1,750 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * Copyright (c) 1993, 1994 Chris Provenzano.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)vfscanf.c 5.7 (Berkeley) 12/14/92";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#if __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+#include "local.h"
+
+#define FLOATING_POINT
+
+#include "floatio.h"
+#define BUF 513 /* Maximum length of numeric string. */
+
+/*
+ * Flags used during conversion.
+ */
+#define LONG 0x01 /* l: long or double */
+#define LONGDBL 0x02 /* L: long double; unimplemented */
+#define SHORT 0x04 /* h: short */
+#define SUPPRESS 0x08 /* suppress assignment */
+#define POINTER 0x10 /* weird %p pointer (`fake hex') */
+#define NOSKIP 0x20 /* do not skip blanks */
+
+/*
+ * The following are used in numeric conversions only:
+ * SIGNOK, NDIGITS, DPTOK, and EXPOK are for floating point;
+ * SIGNOK, NDIGITS, PFXOK, and NZDIGITS are for integral.
+ */
+#define SIGNOK 0x40 /* +/- is (still) legal */
+#define NDIGITS 0x80 /* no digits detected */
+
+#define DPTOK 0x100 /* (float) decimal point is still legal */
+#define EXPOK 0x200 /* (float) exponent (e+3, etc) still legal */
+
+#define PFXOK 0x100 /* 0x prefix is (still) legal */
+#define NZDIGITS 0x200 /* no zero digits detected */
+
+/*
+ * Conversion types.
+ */
+#define CT_CHAR 0 /* %c conversion */
+#define CT_CCL 1 /* %[...] conversion */
+#define CT_STRING 2 /* %s conversion */
+#define CT_INT 3 /* integer, i.e., strtol or strtoul */
+#define CT_FLOAT 4 /* floating, i.e., strtod */
+
+#define u_char unsigned char
+#define u_long unsigned long
+
+static u_char *__sccl();
+
+/*
+ * vfscanf
+ */
+__svfscanf(fp, fmt0, ap)
+ register FILE *fp;
+ char const *fmt0;
+ pthread_va_list ap;
+{
+ register u_char *fmt = (u_char *)fmt0;
+ register int c; /* character from format, or conversion */
+ register size_t width; /* field width, or 0 */
+ register char *p; /* points into all kinds of strings */
+ register int n; /* handy integer */
+ register int flags; /* flags as defined above */
+ register char *p0; /* saves original value of p when necessary */
+ int nassigned; /* number of fields assigned */
+ int nread; /* number of characters consumed from fp */
+ int base; /* base argument to strtol/strtoul */
+ u_long (*ccfn)(); /* conversion function (strtol/strtoul) */
+ char ccltab[256]; /* character class table for %[...] */
+ char buf[BUF]; /* buffer for numeric conversions */
+
+ /* `basefix' is used to avoid `if' tests in the integer scanner */
+ static short basefix[17] =
+ { 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
+
+ nassigned = 0;
+ nread = 0;
+ base = 0; /* XXX just to keep gcc happy */
+ ccfn = NULL; /* XXX just to keep gcc happy */
+ for (;;) {
+ c = *fmt++;
+ if (c == 0)
+ return (nassigned);
+ if (isspace(c)) {
+ for (;;) {
+ if (fp->_r <= 0 && __srefill(fp))
+ return (nassigned);
+ if (!isspace(*fp->_p))
+ break;
+ nread++, fp->_r--, fp->_p++;
+ }
+ continue;
+ }
+ if (c != '%')
+ goto literal;
+ width = 0;
+ flags = 0;
+ /*
+ * switch on the format. continue if done;
+ * break once format type is derived.
+ */
+again: c = *fmt++;
+ switch (c) {
+ case '%':
+literal:
+ if (fp->_r <= 0 && __srefill(fp))
+ goto input_failure;
+ if (*fp->_p != c)
+ goto match_failure;
+ fp->_r--, fp->_p++;
+ nread++;
+ continue;
+
+ case '*':
+ flags |= SUPPRESS;
+ goto again;
+ case 'l':
+ flags |= LONG;
+ goto again;
+ case 'L':
+ flags |= LONGDBL;
+ goto again;
+ case 'h':
+ flags |= SHORT;
+ goto again;
+
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ width = width * 10 + c - '0';
+ goto again;
+
+ /*
+ * Conversions.
+ * Those marked `compat' are for 4.[123]BSD compatibility.
+ *
+ * (According to ANSI, E and X formats are supposed
+ * to the same as e and x. Sorry about that.)
+ */
+ case 'D': /* compat */
+ flags |= LONG;
+ /* FALLTHROUGH */
+ case 'd':
+ c = CT_INT;
+ ccfn = (u_long (*)())strtol;
+ base = 10;
+ break;
+
+ case 'i':
+ c = CT_INT;
+ ccfn = (u_long (*)())strtol;
+ base = 0;
+ break;
+
+ case 'O': /* compat */
+ flags |= LONG;
+ /* FALLTHROUGH */
+ case 'o':
+ c = CT_INT;
+ ccfn = strtoul;
+ base = 8;
+ break;
+
+ case 'u':
+ c = CT_INT;
+ ccfn = strtoul;
+ base = 10;
+ break;
+
+ case 'X': /* compat XXX */
+ flags |= LONG;
+ /* FALLTHROUGH */
+ case 'x':
+ flags |= PFXOK; /* enable 0x prefixing */
+ c = CT_INT;
+ ccfn = strtoul;
+ base = 16;
+ break;
+
+#ifdef FLOATING_POINT
+ case 'E': /* compat XXX */
+ case 'F': /* compat */
+ flags |= LONG;
+ /* FALLTHROUGH */
+ case 'e': case 'f': case 'g':
+ c = CT_FLOAT;
+ break;
+#endif
+
+ case 's':
+ c = CT_STRING;
+ break;
+
+ case '[':
+ fmt = __sccl(ccltab, fmt);
+ flags |= NOSKIP;
+ c = CT_CCL;
+ break;
+
+ case 'c':
+ flags |= NOSKIP;
+ c = CT_CHAR;
+ break;
+
+ case 'p': /* pointer format is like hex */
+ flags |= POINTER | PFXOK;
+ c = CT_INT;
+ ccfn = strtoul;
+ base = 16;
+ break;
+
+ case 'n':
+ if (flags & SUPPRESS) /* ??? */
+ continue;
+ if (flags & SHORT)
+ *va_arg(ap, short *) = nread;
+ else if (flags & LONG)
+ *va_arg(ap, long *) = nread;
+ else
+ *va_arg(ap, int *) = nread;
+ continue;
+
+ /*
+ * Disgusting backwards compatibility hacks. XXX
+ */
+ case '\0': /* compat */
+ return (EOF);
+
+ default: /* compat */
+ if (isupper(c))
+ flags |= LONG;
+ c = CT_INT;
+ ccfn = (u_long (*)())strtol;
+ base = 10;
+ break;
+ }
+
+ /*
+ * We have a conversion that requires input.
+ */
+ if (fp->_r <= 0 && __srefill(fp))
+ goto input_failure;
+
+ /*
+ * Consume leading white space, except for formats
+ * that suppress this.
+ */
+ if ((flags & NOSKIP) == 0) {
+ while (isspace(*fp->_p)) {
+ nread++;
+ if (--fp->_r > 0)
+ fp->_p++;
+ else if (__srefill(fp))
+ goto input_failure;
+ }
+ /*
+ * Note that there is at least one character in
+ * the buffer, so conversions that do not set NOSKIP
+ * ca no longer result in an input failure.
+ */
+ }
+
+ /*
+ * Do the conversion.
+ */
+ switch (c) {
+
+ case CT_CHAR:
+ /* scan arbitrary characters (sets NOSKIP) */
+ if (width == 0)
+ width = 1;
+ if (flags & SUPPRESS) {
+ size_t sum = 0;
+ for (;;) {
+ if ((n = fp->_r) < width) {
+ sum += n;
+ width -= n;
+ fp->_p += n;
+ if (__srefill(fp)) {
+ if (sum == 0)
+ goto input_failure;
+ break;
+ }
+ } else {
+ sum += width;
+ fp->_r -= width;
+ fp->_p += width;
+ break;
+ }
+ }
+ nread += sum;
+ } else {
+ size_t r = fread((void *)va_arg(ap, char *), 1,
+ width, fp);
+
+ if (r == 0)
+ goto input_failure;
+ nread += r;
+ nassigned++;
+ }
+ break;
+
+ case CT_CCL:
+ /* scan a (nonempty) character class (sets NOSKIP) */
+ if (width == 0)
+ width = ~0; /* `infinity' */
+ /* take only those things in the class */
+ if (flags & SUPPRESS) {
+ n = 0;
+ while (ccltab[*fp->_p]) {
+ n++, fp->_r--, fp->_p++;
+ if (--width == 0)
+ break;
+ if (fp->_r <= 0 && __srefill(fp)) {
+ if (n == 0)
+ goto input_failure;
+ break;
+ }
+ }
+ if (n == 0)
+ goto match_failure;
+ } else {
+ p0 = p = va_arg(ap, char *);
+ while (ccltab[*fp->_p]) {
+ fp->_r--;
+ *p++ = *fp->_p++;
+ if (--width == 0)
+ break;
+ if (fp->_r <= 0 && __srefill(fp)) {
+ if (p == p0)
+ goto input_failure;
+ break;
+ }
+ }
+ n = p - p0;
+ if (n == 0)
+ goto match_failure;
+ *p = 0;
+ nassigned++;
+ }
+ nread += n;
+ break;
+
+ case CT_STRING:
+ /* like CCL, but zero-length string OK, & no NOSKIP */
+ if (width == 0)
+ width = ~0;
+ if (flags & SUPPRESS) {
+ n = 0;
+ while (!isspace(*fp->_p)) {
+ n++, fp->_r--, fp->_p++;
+ if (--width == 0)
+ break;
+ if (fp->_r <= 0 && __srefill(fp))
+ break;
+ }
+ nread += n;
+ } else {
+ p0 = p = va_arg(ap, char *);
+ while (!isspace(*fp->_p)) {
+ fp->_r--;
+ *p++ = *fp->_p++;
+ if (--width == 0)
+ break;
+ if (fp->_r <= 0 && __srefill(fp))
+ break;
+ }
+ *p = 0;
+ nread += p - p0;
+ nassigned++;
+ }
+ continue;
+
+ case CT_INT:
+ /* scan an integer as if by strtol/strtoul */
+#ifdef hardway
+ if (width == 0 || width > sizeof(buf) - 1)
+ width = sizeof(buf) - 1;
+#else
+ /* size_t is unsigned, hence this optimisation */
+ if (--width > sizeof(buf) - 2)
+ width = sizeof(buf) - 2;
+ width++;
+#endif
+ flags |= SIGNOK | NDIGITS | NZDIGITS;
+ for (p = buf; width; width--) {
+ c = *fp->_p;
+ /*
+ * Switch on the character; `goto ok'
+ * if we accept it as a part of number.
+ */
+ switch (c) {
+
+ /*
+ * The digit 0 is always legal, but is
+ * special. For %i conversions, if no
+ * digits (zero or nonzero) have been
+ * scanned (only signs), we will have
+ * base==0. In that case, we should set
+ * it to 8 and enable 0x prefixing.
+ * Also, if we have not scanned zero digits
+ * before this, do not turn off prefixing
+ * (someone else will turn it off if we
+ * have scanned any nonzero digits).
+ */
+ case '0':
+ if (base == 0) {
+ base = 8;
+ flags |= PFXOK;
+ }
+ if (flags & NZDIGITS)
+ flags &= ~(SIGNOK|NZDIGITS|NDIGITS);
+ else
+ flags &= ~(SIGNOK|PFXOK|NDIGITS);
+ goto ok;
+
+ /* 1 through 7 always legal */
+ case '1': case '2': case '3':
+ case '4': case '5': case '6': case '7':
+ base = basefix[base];
+ flags &= ~(SIGNOK | PFXOK | NDIGITS);
+ goto ok;
+
+ /* digits 8 and 9 ok iff decimal or hex */
+ case '8': case '9':
+ base = basefix[base];
+ if (base <= 8)
+ break; /* not legal here */
+ flags &= ~(SIGNOK | PFXOK | NDIGITS);
+ goto ok;
+
+ /* letters ok iff hex */
+ case 'A': case 'B': case 'C':
+ case 'D': case 'E': case 'F':
+ case 'a': case 'b': case 'c':
+ case 'd': case 'e': case 'f':
+ /* no need to fix base here */
+ if (base <= 10)
+ break; /* not legal here */
+ flags &= ~(SIGNOK | PFXOK | NDIGITS);
+ goto ok;
+
+ /* sign ok only as first character */
+ case '+': case '-':
+ if (flags & SIGNOK) {
+ flags &= ~SIGNOK;
+ goto ok;
+ }
+ break;
+
+ /* x ok iff flag still set & 2nd char */
+ case 'x': case 'X':
+ if (flags & PFXOK && p == buf + 1) {
+ base = 16; /* if %i */
+ flags &= ~PFXOK;
+ goto ok;
+ }
+ break;
+ }
+
+ /*
+ * If we got here, c is not a legal character
+ * for a number. Stop accumulating digits.
+ */
+ break;
+ ok:
+ /*
+ * c is legal: store it and look at the next.
+ */
+ *p++ = c;
+ if (--fp->_r > 0)
+ fp->_p++;
+ else if (__srefill(fp))
+ break; /* EOF */
+ }
+ /*
+ * If we had only a sign, it is no good; push
+ * back the sign. If the number ends in `x',
+ * it was [sign] '0' 'x', so push back the x
+ * and treat it as [sign] '0'.
+ */
+ if (flags & NDIGITS) {
+ if (p > buf)
+ (void) ungetc(*(u_char *)--p, fp);
+ goto match_failure;
+ }
+ c = ((u_char *)p)[-1];
+ if (c == 'x' || c == 'X') {
+ --p;
+ (void) ungetc(c, fp);
+ }
+ if ((flags & SUPPRESS) == 0) {
+ u_long res;
+
+ *p = 0;
+ res = (*ccfn)(buf, (char **)NULL, base);
+ if (flags & POINTER)
+ *va_arg(ap, void **) = (void *)res;
+ else if (flags & SHORT)
+ *va_arg(ap, short *) = res;
+ else if (flags & LONG)
+ *va_arg(ap, long *) = res;
+ else
+ *va_arg(ap, int *) = res;
+ nassigned++;
+ }
+ nread += p - buf;
+ break;
+
+#ifdef FLOATING_POINT
+ case CT_FLOAT:
+ /* scan a floating point number as if by strtod */
+#ifdef hardway
+ if (width == 0 || width > sizeof(buf) - 1)
+ width = sizeof(buf) - 1;
+#else
+ /* size_t is unsigned, hence this optimisation */
+ if (--width > sizeof(buf) - 2)
+ width = sizeof(buf) - 2;
+ width++;
+#endif
+ flags |= SIGNOK | NDIGITS | DPTOK | EXPOK;
+ for (p = buf; width; width--) {
+ c = *fp->_p;
+ /*
+ * This code mimicks the integer conversion
+ * code, but is much simpler.
+ */
+ switch (c) {
+
+ case '0': case '1': case '2': case '3':
+ case '4': case '5': case '6': case '7':
+ case '8': case '9':
+ flags &= ~(SIGNOK | NDIGITS);
+ goto fok;
+
+ case '+': case '-':
+ if (flags & SIGNOK) {
+ flags &= ~SIGNOK;
+ goto fok;
+ }
+ break;
+ case '.':
+ if (flags & DPTOK) {
+ flags &= ~(SIGNOK | DPTOK);
+ goto fok;
+ }
+ break;
+ case 'e': case 'E':
+ /* no exponent without some digits */
+ if ((flags&(NDIGITS|EXPOK)) == EXPOK) {
+ flags =
+ (flags & ~(EXPOK|DPTOK)) |
+ SIGNOK | NDIGITS;
+ goto fok;
+ }
+ break;
+ }
+ break;
+ fok:
+ *p++ = c;
+ if (--fp->_r > 0)
+ fp->_p++;
+ else if (__srefill(fp))
+ break; /* EOF */
+ }
+ /*
+ * If no digits, might be missing exponent digits
+ * (just give back the exponent) or might be missing
+ * regular digits, but had sign and/or decimal point.
+ */
+ if (flags & NDIGITS) {
+ if (flags & EXPOK) {
+ /* no digits at all */
+ while (p > buf)
+ ungetc(*(u_char *)--p, fp);
+ goto match_failure;
+ }
+ /* just a bad exponent (e and maybe sign) */
+ c = *(u_char *)--p;
+ if (c != 'e' && c != 'E') {
+ (void) ungetc(c, fp);/* sign */
+ c = *(u_char *)--p;
+ }
+ (void) ungetc(c, fp);
+ }
+ if ((flags & SUPPRESS) == 0) {
+ double res;
+
+ *p = 0;
+ res = strtod(buf, (char **) NULL);
+ if (flags & LONG)
+ *va_arg(ap, double *) = res;
+ else
+ *va_arg(ap, float *) = res;
+ nassigned++;
+ }
+ nread += p - buf;
+ break;
+#endif /* FLOATING_POINT */
+ }
+ }
+input_failure:
+ return (nassigned ? nassigned : -1);
+match_failure:
+ return (nassigned);
+}
+
+/*
+ * Fill in the given table from the scanset at the given format
+ * (just after `['). Return a pointer to the character past the
+ * closing `]'. The table has a 1 wherever characters should be
+ * considered part of the scanset.
+ */
+static u_char *
+__sccl(tab, fmt)
+ register char *tab;
+ register u_char *fmt;
+{
+ register int c, n, v;
+
+ /* first `clear' the whole table */
+ c = *fmt++; /* first char hat => negated scanset */
+ if (c == '^') {
+ v = 1; /* default => accept */
+ c = *fmt++; /* get new first char */
+ } else
+ v = 0; /* default => reject */
+ /* should probably use memset here */
+ for (n = 0; n < 256; n++)
+ tab[n] = v;
+ if (c == 0)
+ return (fmt - 1);/* format ended before closing ] */
+
+ /*
+ * Now set the entries corresponding to the actual scanset
+ * to the opposite of the above.
+ *
+ * The first character may be ']' (or '-') without being special;
+ * the last character may be '-'.
+ */
+ v = 1 - v;
+ for (;;) {
+ tab[c] = v; /* take character c */
+doswitch:
+ n = *fmt++; /* and examine the next */
+ switch (n) {
+
+ case 0: /* format ended too soon */
+ return (fmt - 1);
+
+ case '-':
+ /*
+ * A scanset of the form
+ * [01+-]
+ * is defined as `the digit 0, the digit 1,
+ * the character +, the character -', but
+ * the effect of a scanset such as
+ * [a-zA-Z0-9]
+ * is implementation defined. The V7 Unix
+ * scanf treats `a-z' as `the letters a through
+ * z', but treats `a-a' as `the letter a, the
+ * character -, and the letter a'.
+ *
+ * For compatibility, the `-' is not considerd
+ * to define a range if the character following
+ * it is either a close bracket (required by ANSI)
+ * or is not numerically greater than the character
+ * we just stored in the table (c).
+ */
+ n = *fmt;
+ if (n == ']' || n < c) {
+ c = '-';
+ break; /* resume the for(;;) */
+ }
+ fmt++;
+ do { /* fill in the range */
+ tab[++c] = v;
+ } while (c < n);
+#if 1 /* XXX another disgusting compatibility hack */
+ /*
+ * Alas, the V7 Unix scanf also treats formats
+ * such as [a-c-e] as `the letters a through e'.
+ * This too is permitted by the standard....
+ */
+ goto doswitch;
+#else
+ c = *fmt++;
+ if (c == 0)
+ return (fmt - 1);
+ if (c == ']')
+ return (fmt);
+#endif
+ break;
+
+ case ']': /* end of scanset */
+ return (fmt);
+
+ default: /* just another character */
+ c = n;
+ break;
+ }
+ }
+ /* NOTREACHED */
+}
diff --git a/mit-pthreads/stdio/vprintf.c b/mit-pthreads/stdio/vprintf.c
new file mode 100644
index 00000000000..4999c4fb239
--- /dev/null
+++ b/mit-pthreads/stdio/vprintf.c
@@ -0,0 +1,51 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * Copyright (c) 1993, 1994 Chris Provenzano.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)vprintf.c 5.6 (Berkeley) 2/24/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <stdarg.h>
+#include <stdio.h>
+
+vprintf(fmt, ap)
+ char const *fmt;
+ pthread_va_list ap;
+{
+ return (vfprintf(stdout, fmt, ap));
+}
diff --git a/mit-pthreads/stdio/vscanf.c b/mit-pthreads/stdio/vscanf.c
new file mode 100644
index 00000000000..5a562f89528
--- /dev/null
+++ b/mit-pthreads/stdio/vscanf.c
@@ -0,0 +1,55 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * Copyright (c) 1993, 1994 Chris Provenzano.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Donn Seeley at UUNET Technologies, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)vscanf.c 5.1 (Berkeley) 4/15/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <stdarg.h>
+#include <stdio.h>
+
+vscanf(fmt, ap)
+ const char *fmt;
+ pthread_va_list ap;
+{
+ int r;
+ flockfile(stdin);
+ r = __svfscanf(stdin, fmt, ap);
+ funlockfile(stdin);
+ return(r);
+}
diff --git a/mit-pthreads/stdio/vsnprintf.c b/mit-pthreads/stdio/vsnprintf.c
new file mode 100644
index 00000000000..8fd1e6d8613
--- /dev/null
+++ b/mit-pthreads/stdio/vsnprintf.c
@@ -0,0 +1,65 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * Copyright (c) 1993, 1994 Chris Provenzano.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)vsnprintf.c 5.2 (Berkeley) 2/5/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdio.h>
+
+vsnprintf(str, n, fmt, ap)
+ char *str;
+ size_t n;
+ const char *fmt;
+ pthread_va_list ap;
+{
+ int ret;
+ FILE f;
+
+ if ((int)n < 1)
+ return (EOF);
+ f._file = -1;
+ f._flags = __SWR | __SSTR;
+ f._bf._base = f._p = (unsigned char *)str;
+ f._bf._size = f._w = n - 1;
+ ret = vfprintf(&f, fmt, ap);
+ *f._p = 0;
+ return (ret);
+}
diff --git a/mit-pthreads/stdio/vsprintf.c b/mit-pthreads/stdio/vsprintf.c
new file mode 100644
index 00000000000..c6cdb708be3
--- /dev/null
+++ b/mit-pthreads/stdio/vsprintf.c
@@ -0,0 +1,62 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * Copyright (c) 1993, 1994 Chris Provenzano.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)vsprintf.c 5.5 (Berkeley) 2/5/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <stdarg.h>
+#include <limits.h>
+#include <stdio.h>
+
+vsprintf(str, fmt, ap)
+ char *str;
+ const char *fmt;
+ pthread_va_list ap;
+{
+ int ret;
+ FILE f;
+
+ f._file = -1;
+ f._flags = __SWR | __SSTR;
+ f._bf._base = f._p = (unsigned char *)str;
+ f._bf._size = f._w = INT_MAX;
+ ret = vfprintf(&f, fmt, ap);
+ *f._p = 0;
+ return (ret);
+}
diff --git a/mit-pthreads/stdio/vsscanf.c b/mit-pthreads/stdio/vsscanf.c
new file mode 100644
index 00000000000..9d9cdcffeeb
--- /dev/null
+++ b/mit-pthreads/stdio/vsscanf.c
@@ -0,0 +1,62 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * Copyright (c) 1993, 1994 Chris Provenzano.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Donn Seeley at UUNET Technologies, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)vsscanf.c 5.1 (Berkeley) 4/15/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+
+vsscanf(str, fmt, ap)
+ const char *str;
+ const char *fmt;
+ pthread_va_list ap;
+{
+ int ret;
+ FILE f;
+
+ f._flags = __SRD;
+ f._file = -1; /* This will do the right thing */
+ f._bf._base = f._p = (unsigned char *)str;
+ f._bf._size = f._r = strlen(str);
+ f._ub._base = NULL;
+ f._lb._base = NULL;
+ return (__svfscanf(&f, fmt, ap));
+}
diff --git a/mit-pthreads/stdio/wbuf.c b/mit-pthreads/stdio/wbuf.c
new file mode 100644
index 00000000000..58cb9ad058e
--- /dev/null
+++ b/mit-pthreads/stdio/wbuf.c
@@ -0,0 +1,89 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * Copyright (c) 1993, 1994 Chris Provenzano.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)wbuf.c 5.6 (Berkeley) 1/20/91";
+#endif /* LIBC_SCCS and not lint */
+
+#include <stdio.h>
+#include "local.h"
+
+/*
+ * Write the given character into the (probably full) buffer for
+ * the given file. Flush the buffer out if it is or becomes full,
+ * or if c=='\n' and the file is line buffered.
+ */
+__swbuf(c, fp)
+ register int c;
+ register FILE *fp;
+{
+ register int n;
+
+ /*
+ * In case we cannot write, or longjmp takes us out early,
+ * make sure _w is 0 (if fully- or un-buffered) or -_bf._size
+ * (if line buffered) so that we will get called again.
+ * If we did not do this, a sufficient number of putc()
+ * calls might wrap _w from negative to positive.
+ */
+ fp->_w = fp->_lbfsize;
+ if (cantwrite(fp))
+ return (EOF);
+ c = (unsigned char)c;
+
+ /*
+ * If it is completely full, flush it out. Then, in any case,
+ * stuff c into the buffer. If this causes the buffer to fill
+ * completely, or if c is '\n' and the file is line buffered,
+ * flush it (perhaps a second time). The second flush will always
+ * happen on unbuffered streams, where _bf._size==1; fflush()
+ * guarantees that putc() will always call wbuf() by setting _w
+ * to 0, so we need not do anything else.
+ */
+ n = fp->_p - fp->_bf._base;
+ if (n >= fp->_bf._size) {
+ if (fflush(fp))
+ return (EOF);
+ n = 0;
+ }
+ fp->_w--;
+ *fp->_p++ = c;
+ if (++n == fp->_bf._size || (fp->_flags & __SLBF && c == '\n'))
+ if (fflush(fp))
+ return (EOF);
+ return (c);
+}
diff --git a/mit-pthreads/stdio/wsetup.c b/mit-pthreads/stdio/wsetup.c
new file mode 100644
index 00000000000..1c86f45a973
--- /dev/null
+++ b/mit-pthreads/stdio/wsetup.c
@@ -0,0 +1,91 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * Copyright (c) 1993, 1994 Chris Provenzano.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)wsetup.c 5.2 (Berkeley) 2/24/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "local.h"
+
+/*
+ * Various output routines call wsetup to be sure it is safe to write,
+ * because either _flags does not include __SWR, or _buf is NULL.
+ * _wsetup returns 0 if OK to write, nonzero otherwise.
+ */
+__swsetup(fp)
+ register FILE *fp;
+{
+ /* make sure stdio is set up */
+ __sinit ();
+
+ /*
+ * If we are not writing, we had better be reading and writing.
+ */
+ if ((fp->_flags & __SWR) == 0) {
+ if ((fp->_flags & __SRW) == 0)
+ return (EOF);
+ if (fp->_flags & __SRD) {
+ /* clobber any ungetc data */
+ if (HASUB(fp))
+ FREEUB(fp);
+ fp->_flags &= ~(__SRD|__SEOF);
+ fp->_r = 0;
+ fp->_p = fp->_bf._base;
+ }
+ fp->_flags |= __SWR;
+ }
+
+ /*
+ * Make a buffer if necessary, then set _w.
+ */
+ if (fp->_bf._base == NULL)
+ __smakebuf(fp);
+ if (fp->_flags & __SLBF) {
+ /*
+ * It is line buffered, so make _lbfsize be -_bufsize
+ * for the putc() macro. We will change _lbfsize back
+ * to 0 whenever we turn off __SWR.
+ */
+ fp->_w = 0;
+ fp->_lbfsize = -fp->_bf._size;
+ } else
+ fp->_w = fp->_flags & __SNBF ? 0 : fp->_bf._size;
+ return (0);
+}
diff --git a/mit-pthreads/stdio/xprintf.c b/mit-pthreads/stdio/xprintf.c
new file mode 100644
index 00000000000..668e8bc0605
--- /dev/null
+++ b/mit-pthreads/stdio/xprintf.c
@@ -0,0 +1,883 @@
+/*
+** It turns out that the printf functions in the stock MIT pthread library
+** is busted. It isn't thread safe. If two threads try to do a printf
+** of a floating point value at the same time, a core-dump might result.
+** So this code is substituted.
+*/
+/*
+** NAME: $Source$
+** VERSION: $Revision$
+** DATE: $Date$
+**
+** ONELINER: A replacement for formatted printing programs.
+**
+** COPYRIGHT:
+** Copyright (c) 1990 by D. Richard Hipp. This code is an original
+** work and has been prepared without reference to any prior
+** implementations of similar functions. No part of this code is
+** subject to licensing restrictions of any telephone company or
+** university.
+**
+** This copyright was released and the code placed in the public domain
+** by the author, D. Richard Hipp, on October 3, 1996.
+**
+** DESCRIPTION:
+** This program is an enhanced replacement for the "printf" programs
+** found in the standard library. The following enhancements are
+** supported:
+**
+** + Additional functions. The standard set of "printf" functions
+** includes printf, fprintf, sprintf, vprintf, vfprintf, and
+** vsprintf. This module adds the following:
+**
+** * snprintf -- Works like sprintf, but has an extra argument
+** which is the size of the buffer written to.
+**
+** * mprintf -- Similar to sprintf. Writes output to memory
+** obtained from mem_alloc.
+**
+** * xprintf -- Calls a function to dispose of output.
+**
+** * nprintf -- No output, but returns the number of characters
+** that would have been output by printf.
+**
+** * A v- version (ex: vsnprintf) of every function is also
+** supplied.
+**
+** + A few extensions to the formatting notation are supported:
+**
+** * The "=" flag (similar to "-") causes the output to be
+** be centered in the appropriately sized field.
+**
+** * The %b field outputs an integer in binary notation.
+**
+** * The %c field now accepts a precision. The character output
+** is repeated by the number of times the precision specifies.
+**
+** * The %' field works like %c, but takes as its character the
+** next character of the format string, instead of the next
+** argument. For example, printf("%.78'-") prints 78 minus
+** signs, the same as printf("%.78c",'-').
+**
+** + When compiled using GCC on a SPARC, this version of printf is
+** faster than the library printf for SUN OS 4.1.
+**
+** + All functions are fully reentrant.
+**
+*/
+/*
+** Undefine COMPATIBILITY to make some slight changes in the way things
+** work. I think the changes are an improvement, but they are not
+** backwards compatible.
+*/
+/* #define COMPATIBILITY / * Compatible with SUN OS 4.1 */
+#include <stdio.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+/*
+** The maximum number of digits of accuracy in a floating-point conversion.
+*/
+#define MAXDIG 20
+
+/*
+** Conversion types fall into various categories as defined by the
+** following enumeration.
+*/
+enum e_type { /* The type of the format field */
+ RADIX, /* Integer types. %d, %x, %o, and so forth */
+ FLOAT, /* Floating point. %f */
+ EXP, /* Exponentional notation. %e and %E */
+ GENERIC, /* Floating or exponential, depending on exponent. %g */
+ SIZE, /* Return number of characters processed so far. %n */
+ STRING, /* Strings. %s */
+ PERCENT, /* Percent symbol. %% */
+ CHAR, /* Characters. %c */
+ ERROR, /* Used to indicate no such conversion type */
+/* The rest are extensions, not normally found in printf() */
+ CHARLIT, /* Literal characters. %' */
+ SEEIT, /* Strings with visible control characters. %S */
+ MEM_STRING, /* A string which should be deleted after use. %z */
+ ORDINAL, /* 1st, 2nd, 3rd and so forth */
+};
+
+/*
+** Each builtin conversion character (ex: the 'd' in "%d") is described
+** by an instance of the following structure
+*/
+typedef struct s_info { /* Information about each format field */
+ int fmttype; /* The format field code letter */
+ int base; /* The base for radix conversion */
+ char *charset; /* The character set for conversion */
+ int flag_signed; /* Is the quantity signed? */
+ char *prefix; /* Prefix on non-zero values in alt format */
+ enum e_type type; /* Conversion paradigm */
+} info;
+
+/*
+** The following table is searched linearly, so it is good to put the
+** most frequently used conversion types first.
+*/
+static info fmtinfo[] = {
+ { 'd', 10, "0123456789", 1, 0, RADIX, },
+ { 's', 0, 0, 0, 0, STRING, },
+ { 'S', 0, 0, 0, 0, SEEIT, },
+ { 'z', 0, 0, 0, 0, MEM_STRING, },
+ { 'c', 0, 0, 0, 0, CHAR, },
+ { 'o', 8, "01234567", 0, "0", RADIX, },
+ { 'u', 10, "0123456789", 0, 0, RADIX, },
+ { 'x', 16, "0123456789abcdef", 0, "x0", RADIX, },
+ { 'X', 16, "0123456789ABCDEF", 0, "X0", RADIX, },
+ { 'r', 10, "0123456789", 0, 0, ORDINAL, },
+ { 'f', 0, 0, 1, 0, FLOAT, },
+ { 'e', 0, "e", 1, 0, EXP, },
+ { 'E', 0, "E", 1, 0, EXP, },
+ { 'g', 0, "e", 1, 0, GENERIC, },
+ { 'G', 0, "E", 1, 0, GENERIC, },
+ { 'i', 10, "0123456789", 1, 0, RADIX, },
+ { 'n', 0, 0, 0, 0, SIZE, },
+ { 'S', 0, 0, 0, 0, SEEIT, },
+ { '%', 0, 0, 0, 0, PERCENT, },
+ { 'b', 2, "01", 0, "b0", RADIX, }, /* Binary notation */
+ { 'p', 10, "0123456789", 0, 0, RADIX, }, /* Pointers */
+ { '\'', 0, 0, 0, 0, CHARLIT, }, /* Literal char */
+};
+#define NINFO (sizeof(fmtinfo)/sizeof(info)) /* Size of the fmtinfo table */
+
+/*
+** If NOFLOATINGPOINT is defined, then none of the floating point
+** conversions will work.
+*/
+#ifndef NOFLOATINGPOINT
+/*
+** "*val" is a double such that 0.1 <= *val < 10.0
+** Return the ascii code for the leading digit of *val, then
+** multiply "*val" by 10.0 to renormalize.
+**
+** Example:
+** input: *val = 3.14159
+** output: *val = 1.4159 function return = '3'
+**
+** The counter *cnt is incremented each time. After counter exceeds
+** 16 (the number of significant digits in a 64-bit float) '0' is
+** always returned.
+*/
+static int getdigit(long double *val, int *cnt){
+ int digit;
+ long double d;
+ if( (*cnt)++ >= MAXDIG ) return '0';
+ digit = (int)*val;
+ d = digit;
+ digit += '0';
+ *val = (*val - d)*10.0;
+ return digit;
+}
+#endif
+
+/*
+** Setting the size of the BUFFER involves trade-offs. No %d or %f
+** conversion can have more than BUFSIZE characters. If the field
+** width is larger than BUFSIZE, it is silently shortened. On the
+** other hand, this routine consumes more stack space with larger
+** BUFSIZEs. If you have some threads for which you want to minimize
+** stack space, you should keep BUFSIZE small.
+*/
+#define BUFSIZE 100 /* Size of the output buffer */
+
+/*
+** The root program. All variations call this core.
+**
+** INPUTS:
+** func This is a pointer to a function taking three arguments
+** 1. A pointer to the list of characters to be output
+** (Note, this list is NOT null terminated.)
+** 2. An integer number of characters to be output.
+** (Note: This number might be zero.)
+** 3. A pointer to anything. Same as the "arg" parameter.
+**
+** arg This is the pointer to anything which will be passed as the
+** third argument to "func". Use it for whatever you like.
+**
+** fmt This is the format string, as in the usual print.
+**
+** ap This is a pointer to a list of arguments. Same as in
+** vfprint.
+**
+** OUTPUTS:
+** The return value is the total number of characters sent to
+** the function "func". Returns -1 on a error.
+**
+** Note that the order in which automatic variables are declared below
+** seems to make a big difference in determining how fast this beast
+** will run.
+*/
+static int vxprintf(func,arg,format,ap)
+ void (*func)(char*,int,void*);
+ void *arg;
+ const char *format;
+ va_list ap;
+{
+ register const char *fmt; /* The format string. */
+ register int c; /* Next character in the format string */
+ register char *bufpt; /* Pointer to the conversion buffer */
+ register int precision; /* Precision of the current field */
+ register int length; /* Length of the field */
+ register int idx; /* A general purpose loop counter */
+ int count; /* Total number of characters output */
+ int width; /* Width of the current field */
+ int flag_leftjustify; /* True if "-" flag is present */
+ int flag_plussign; /* True if "+" flag is present */
+ int flag_blanksign; /* True if " " flag is present */
+ int flag_alternateform; /* True if "#" flag is present */
+ int flag_zeropad; /* True if field width constant starts with zero */
+ int flag_long; /* True if "l" flag is present */
+ int flag_center; /* True if "=" flag is present */
+ unsigned long longvalue; /* Value for integer types */
+ long double realvalue; /* Value for real types */
+ info *infop; /* Pointer to the appropriate info structure */
+ char buf[BUFSIZE]; /* Conversion buffer */
+ char prefix; /* Prefix character. "+" or "-" or " " or '\0'. */
+ int errorflag = 0; /* True if an error is encountered */
+ enum e_type xtype; /* Conversion paradigm */
+ char *zMem; /* String to be freed */
+ static char spaces[] =
+ " ";
+#define SPACESIZE (sizeof(spaces)-1)
+#ifndef NOFLOATINGPOINT
+ int exp; /* exponent of real numbers */
+ long double rounder; /* Used for rounding floating point values */
+ int flag_dp; /* True if decimal point should be shown */
+ int flag_rtz; /* True if trailing zeros should be removed */
+ int flag_exp; /* True to force display of the exponent */
+ int nsd; /* Number of significant digits returned */
+#endif
+
+ fmt = format; /* Put in a register for speed */
+ count = length = 0;
+ bufpt = 0;
+ for(; (c=(*fmt))!=0; ++fmt){
+ if( c!='%' ){
+ register int amt;
+ bufpt = (char *)fmt;
+ amt = 1;
+ while( (c=(*++fmt))!='%' && c!=0 ) amt++;
+ (*func)(bufpt,amt,arg);
+ count += amt;
+ if( c==0 ) break;
+ }
+ if( (c=(*++fmt))==0 ){
+ errorflag = 1;
+ (*func)("%",1,arg);
+ count++;
+ break;
+ }
+ /* Find out what flags are present */
+ flag_leftjustify = flag_plussign = flag_blanksign =
+ flag_alternateform = flag_zeropad = flag_center = 0;
+ do{
+ switch( c ){
+ case '-': flag_leftjustify = 1; c = 0; break;
+ case '+': flag_plussign = 1; c = 0; break;
+ case ' ': flag_blanksign = 1; c = 0; break;
+ case '#': flag_alternateform = 1; c = 0; break;
+ case '0': flag_zeropad = 1; c = 0; break;
+ case '=': flag_center = 1; c = 0; break;
+ default: break;
+ }
+ }while( c==0 && (c=(*++fmt))!=0 );
+ if( flag_center ) flag_leftjustify = 0;
+ /* Get the field width */
+ width = 0;
+ if( c=='*' ){
+ width = va_arg(ap,int);
+ if( width<0 ){
+ flag_leftjustify = 1;
+ width = -width;
+ }
+ c = *++fmt;
+ }else{
+ while( isdigit(c) ){
+ width = width*10 + c - '0';
+ c = *++fmt;
+ }
+ }
+ if( width > BUFSIZE-10 ){
+ width = BUFSIZE-10;
+ }
+ /* Get the precision */
+ if( c=='.' ){
+ precision = 0;
+ c = *++fmt;
+ if( c=='*' ){
+ precision = va_arg(ap,int);
+#ifndef COMPATIBILITY
+ /* This is sensible, but SUN OS 4.1 doesn't do it. */
+ if( precision<0 ) precision = -precision;
+#endif
+ c = *++fmt;
+ }else{
+ while( isdigit(c) ){
+ precision = precision*10 + c - '0';
+ c = *++fmt;
+ }
+ }
+ /* Limit the precision to prevent overflowing buf[] during conversion */
+ if( precision>BUFSIZE-40 ) precision = BUFSIZE-40;
+ }else{
+ precision = -1;
+ }
+ /* Get the conversion type modifier */
+ if( c=='l' ){
+ flag_long = 1;
+ c = *++fmt;
+ }else{
+ flag_long = 0;
+ }
+ /* Fetch the info entry for the field */
+ infop = 0;
+ for(idx=0; idx<NINFO; idx++){
+ if( c==fmtinfo[idx].fmttype ){
+ infop = &fmtinfo[idx];
+ break;
+ }
+ }
+ /* No info entry found. It must be an error. */
+ if( infop==0 ){
+ xtype = ERROR;
+ }else{
+ xtype = infop->type;
+ }
+
+ /*
+ ** At this point, variables are initialized as follows:
+ **
+ ** flag_alternateform TRUE if a '#' is present.
+ ** flag_plussign TRUE if a '+' is present.
+ ** flag_leftjustify TRUE if a '-' is present or if the
+ ** field width was negative.
+ ** flag_zeropad TRUE if the width began with 0.
+ ** flag_long TRUE if the letter 'l' (ell) prefixed
+ ** the conversion character.
+ ** flag_blanksign TRUE if a ' ' is present.
+ ** width The specified field width. This is
+ ** always non-negative. Zero is the default.
+ ** precision The specified precision. The default
+ ** is -1.
+ ** xtype The class of the conversion.
+ ** infop Pointer to the appropriate info struct.
+ */
+ switch( xtype ){
+ case ORDINAL:
+ case RADIX:
+ if( flag_long ) longvalue = va_arg(ap,long);
+ else longvalue = va_arg(ap,int);
+#ifdef COMPATIBILITY
+ /* For the format %#x, the value zero is printed "0" not "0x0".
+ ** I think this is stupid. */
+ if( longvalue==0 ) flag_alternateform = 0;
+#else
+ /* More sensible: turn off the prefix for octal (to prevent "00"),
+ ** but leave the prefix for hex. */
+ if( longvalue==0 && infop->base==8 ) flag_alternateform = 0;
+#endif
+ if( infop->flag_signed ){
+ if( *(long*)&longvalue<0 ){
+ longvalue = -*(long*)&longvalue;
+ prefix = '-';
+ }else if( flag_plussign ) prefix = '+';
+ else if( flag_blanksign ) prefix = ' ';
+ else prefix = 0;
+ }else prefix = 0;
+ if( flag_zeropad && precision<width-(prefix!=0) ){
+ precision = width-(prefix!=0);
+ }
+ bufpt = &buf[BUFSIZE];
+ if( xtype==ORDINAL ){
+ long a,b;
+ a = longvalue%10;
+ b = longvalue%100;
+ bufpt -= 2;
+ if( a==0 || a>3 || (b>10 && b<14) ){
+ bufpt[0] = 't';
+ bufpt[1] = 'h';
+ }else if( a==1 ){
+ bufpt[0] = 's';
+ bufpt[1] = 't';
+ }else if( a==2 ){
+ bufpt[0] = 'n';
+ bufpt[1] = 'd';
+ }else if( a==3 ){
+ bufpt[0] = 'r';
+ bufpt[1] = 'd';
+ }
+ }
+ {
+ register char *cset; /* Use registers for speed */
+ register int base;
+ cset = infop->charset;
+ base = infop->base;
+ do{ /* Convert to ascii */
+ *(--bufpt) = cset[longvalue%base];
+ longvalue = longvalue/base;
+ }while( longvalue>0 );
+ }
+ length = (int)(&buf[BUFSIZE]-bufpt);
+ for(idx=precision-length; idx>0; idx--){
+ *(--bufpt) = '0'; /* Zero pad */
+ }
+ if( prefix ) *(--bufpt) = prefix; /* Add sign */
+ if( flag_alternateform && infop->prefix ){ /* Add "0" or "0x" */
+ char *pre, x;
+ pre = infop->prefix;
+ if( *bufpt!=pre[0] ){
+ for(pre=infop->prefix; (x=(*pre))!=0; pre++) *(--bufpt) = x;
+ }
+ }
+ length = (int)(&buf[BUFSIZE]-bufpt);
+ break;
+ case FLOAT:
+ case EXP:
+ case GENERIC:
+ realvalue = va_arg(ap,double);
+#ifndef NOFLOATINGPOINT
+ if( precision<0 ) precision = 6; /* Set default precision */
+ if( precision>BUFSIZE-10 ) precision = BUFSIZE-10;
+ if( realvalue<0.0 ){
+ realvalue = -realvalue;
+ prefix = '-';
+ }else{
+ if( flag_plussign ) prefix = '+';
+ else if( flag_blanksign ) prefix = ' ';
+ else prefix = 0;
+ }
+ if( infop->type==GENERIC && precision>0 ) precision--;
+ rounder = 0.0;
+#ifdef COMPATIBILITY
+ /* Rounding works like BSD when the constant 0.4999 is used. Wierd! */
+ for(idx=precision, rounder=0.4999; idx>0; idx--, rounder*=0.1);
+#else
+ /* It makes more sense to use 0.5 */
+ if( precision>MAXDIG-1 ) idx = MAXDIG-1;
+ else idx = precision;
+ for(rounder=0.5; idx>0; idx--, rounder*=0.1);
+#endif
+ if( infop->type==FLOAT ) realvalue += rounder;
+ /* Normalize realvalue to within 10.0 > realvalue >= 1.0 */
+ exp = 0;
+ if( realvalue>0.0 ){
+ int k = 0;
+ while( realvalue>=1e8 && k++<100 ){ realvalue *= 1e-8; exp+=8; }
+ while( realvalue>=10.0 && k++<100 ){ realvalue *= 0.1; exp++; }
+ while( realvalue<1e-8 && k++<100 ){ realvalue *= 1e8; exp-=8; }
+ while( realvalue<1.0 && k++<100 ){ realvalue *= 10.0; exp--; }
+ if( k>=100 ){
+ bufpt = "NaN";
+ length = 3;
+ break;
+ }
+ }
+ bufpt = buf;
+ /*
+ ** If the field type is GENERIC, then convert to either EXP
+ ** or FLOAT, as appropriate.
+ */
+ flag_exp = xtype==EXP;
+ if( xtype!=FLOAT ){
+ realvalue += rounder;
+ if( realvalue>=10.0 ){ realvalue *= 0.1; exp++; }
+ }
+ if( xtype==GENERIC ){
+ flag_rtz = !flag_alternateform;
+ if( exp<-4 || exp>precision ){
+ xtype = EXP;
+ }else{
+ precision = precision - exp;
+ xtype = FLOAT;
+ }
+ }else{
+ flag_rtz = 0;
+ }
+ /*
+ ** The "exp+precision" test causes output to be of type EXP if
+ ** the precision is too large to fit in buf[].
+ */
+ nsd = 0;
+ if( xtype==FLOAT && exp+precision<BUFSIZE-30 ){
+ flag_dp = (precision>0 || flag_alternateform);
+ if( prefix ) *(bufpt++) = prefix; /* Sign */
+ if( exp<0 ) *(bufpt++) = '0'; /* Digits before "." */
+ else for(; exp>=0; exp--) *(bufpt++) = getdigit(&realvalue,&nsd);
+ if( flag_dp ) *(bufpt++) = '.'; /* The decimal point */
+ for(exp++; exp<0 && precision>0; precision--, exp++){
+ *(bufpt++) = '0';
+ }
+ while( (precision--)>0 ) *(bufpt++) = getdigit(&realvalue,&nsd);
+ *(bufpt--) = 0; /* Null terminate */
+ if( flag_rtz && flag_dp ){ /* Remove trailing zeros and "." */
+ while( bufpt>=buf && *bufpt=='0' ) *(bufpt--) = 0;
+ if( bufpt>=buf && *bufpt=='.' ) *(bufpt--) = 0;
+ }
+ bufpt++; /* point to next free slot */
+ }else{ /* EXP or GENERIC */
+ flag_dp = (precision>0 || flag_alternateform);
+ if( prefix ) *(bufpt++) = prefix; /* Sign */
+ *(bufpt++) = getdigit(&realvalue,&nsd); /* First digit */
+ if( flag_dp ) *(bufpt++) = '.'; /* Decimal point */
+ while( (precision--)>0 ) *(bufpt++) = getdigit(&realvalue,&nsd);
+ bufpt--; /* point to last digit */
+ if( flag_rtz && flag_dp ){ /* Remove tail zeros */
+ while( bufpt>=buf && *bufpt=='0' ) *(bufpt--) = 0;
+ if( bufpt>=buf && *bufpt=='.' ) *(bufpt--) = 0;
+ }
+ bufpt++; /* point to next free slot */
+ if( exp || flag_exp ){
+ *(bufpt++) = infop->charset[0];
+ if( exp<0 ){ *(bufpt++) = '-'; exp = -exp; } /* sign of exp */
+ else { *(bufpt++) = '+'; }
+ if( exp>=100 ){
+ *(bufpt++) = (exp/100)+'0'; /* 100's digit */
+ exp %= 100;
+ }
+ *(bufpt++) = exp/10+'0'; /* 10's digit */
+ *(bufpt++) = exp%10+'0'; /* 1's digit */
+ }
+ }
+ /* The converted number is in buf[] and zero terminated. Output it.
+ ** Note that the number is in the usual order, not reversed as with
+ ** integer conversions. */
+ length = (int)(bufpt-buf);
+ bufpt = buf;
+
+ /* Special case: Add leading zeros if the flag_zeropad flag is
+ ** set and we are not left justified */
+ if( flag_zeropad && !flag_leftjustify && length < width){
+ int i;
+ int nPad = width - length;
+ for(i=width; i>=nPad; i--){
+ bufpt[i] = bufpt[i-nPad];
+ }
+ i = prefix!=0;
+ while( nPad-- ) bufpt[i++] = '0';
+ length = width;
+ }
+#endif
+ break;
+ case SIZE:
+ *(va_arg(ap,int*)) = count;
+ length = width = 0;
+ break;
+ case PERCENT:
+ buf[0] = '%';
+ bufpt = buf;
+ length = 1;
+ break;
+ case CHARLIT:
+ case CHAR:
+ c = buf[0] = (xtype==CHAR ? va_arg(ap,int) : *++fmt);
+ if( precision>=0 ){
+ for(idx=1; idx<precision; idx++) buf[idx] = c;
+ length = precision;
+ }else{
+ length =1;
+ }
+ bufpt = buf;
+ break;
+ case STRING:
+ case MEM_STRING:
+ zMem = bufpt = va_arg(ap,char*);
+ if( bufpt==0 ) bufpt = "(null)";
+ length = strlen(bufpt);
+ if( precision>=0 && precision<length ) length = precision;
+ break;
+ case SEEIT:
+ {
+ int i;
+ int c;
+ char *arg = va_arg(ap,char*);
+ for(i=0; i<BUFSIZE-1 && (c = *arg++)!=0; i++){
+ if( c<0x20 || c>=0x7f ){
+ buf[i++] = '^';
+ buf[i] = (c&0x1f)+0x40;
+ }else{
+ buf[i] = c;
+ }
+ }
+ bufpt = buf;
+ length = i;
+ if( precision>=0 && precision<length ) length = precision;
+ }
+ break;
+ case ERROR:
+ buf[0] = '%';
+ buf[1] = c;
+ errorflag = 0;
+ idx = 1+(c!=0);
+ (*func)("%",idx,arg);
+ count += idx;
+ if( c==0 ) fmt--;
+ break;
+ }/* End switch over the format type */
+ /*
+ ** The text of the conversion is pointed to by "bufpt" and is
+ ** "length" characters long. The field width is "width". Do
+ ** the output.
+ */
+ if( !flag_leftjustify ){
+ register int nspace;
+ nspace = width-length;
+ if( nspace>0 ){
+ if( flag_center ){
+ nspace = nspace/2;
+ width -= nspace;
+ flag_leftjustify = 1;
+ }
+ count += nspace;
+ while( nspace>=SPACESIZE ){
+ (*func)(spaces,SPACESIZE,arg);
+ nspace -= SPACESIZE;
+ }
+ if( nspace>0 ) (*func)(spaces,nspace,arg);
+ }
+ }
+ if( length>0 ){
+ (*func)(bufpt,length,arg);
+ count += length;
+ }
+ if( xtype==MEM_STRING && zMem ){
+ free(zMem);
+ }
+ if( flag_leftjustify ){
+ register int nspace;
+ nspace = width-length;
+ if( nspace>0 ){
+ count += nspace;
+ while( nspace>=SPACESIZE ){
+ (*func)(spaces,SPACESIZE,arg);
+ nspace -= SPACESIZE;
+ }
+ if( nspace>0 ) (*func)(spaces,nspace,arg);
+ }
+ }
+ }/* End for loop over the format string */
+ return errorflag ? -1 : count;
+} /* End of function */
+
+/*
+** This non-standard function is still occasionally useful....
+*/
+int xprintf(
+ void (*func)(char*,int,void*),
+ void *arg,
+ const char *format,
+ ...
+){
+ va_list ap;
+ va_start(ap,format);
+ return vxprintf(func,arg,format,ap);
+}
+
+/*
+** Now for string-print, also as found in any standard library.
+** Add to this the snprint function which stops added characters
+** to the string at a given length.
+**
+** Note that snprint returns the length of the string as it would
+** be if there were no limit on the output.
+*/
+struct s_strargument { /* Describes the string being written to */
+ char *next; /* Next free slot in the string */
+ char *last; /* Last available slot in the string */
+};
+
+static void sout(txt,amt,arg)
+ char *txt;
+ int amt;
+ void *arg;
+{
+ register char *head;
+ register const char *t;
+ register int a;
+ register char *tail;
+ a = amt;
+ t = txt;
+ head = ((struct s_strargument*)arg)->next;
+ tail = ((struct s_strargument*)arg)->last;
+ if( tail ){
+ while( a-- >0 && head<tail ) *(head++) = *(t++);
+ }else{
+ while( a-- >0 ) *(head++) = *(t++);
+ }
+ *head = 0;
+ ((struct s_strargument*)arg)->next = head;
+}
+
+int sprintf(char *buf, const char *fmt, ...){
+ int rc;
+ va_list ap;
+ struct s_strargument arg;
+
+ va_start(ap,fmt);
+ arg.next = buf;
+ arg.last = 0;
+ *arg.next = 0;
+ rc = vxprintf(sout,&arg,fmt,ap);
+ va_end(ap);
+}
+int vsprintf(char *buf,const char *fmt,va_list ap){
+ struct s_strargument arg;
+ arg.next = buf;
+ arg.last = 0;
+ *buf = 0;
+ return vxprintf(sout,&arg,fmt,ap);
+}
+int snprintf(char *buf, size_t n, const char *fmt, ...){
+ int rc;
+ va_list ap;
+ struct s_strargument arg;
+
+ va_start(ap,fmt);
+ arg.next = buf;
+ arg.last = &arg.next[n-1];
+ *arg.next = 0;
+ rc = vxprintf(sout,&arg,fmt,ap);
+ va_end(ap);
+}
+int vsnprintf(char *buf, size_t n, const char *fmt, va_list ap){
+ struct s_strargument arg;
+ arg.next = buf;
+ arg.last = &buf[n-1];
+ *buf = 0;
+ return vxprintf(sout,&arg,fmt,ap);
+}
+
+/*
+** The following section of code handles the mprintf routine, that
+** writes to memory obtained from malloc().
+*/
+
+/* This structure is used to store state information about the
+** write in progress
+*/
+struct sgMprintf {
+ char *zBase; /* A base allocation */
+ char *zText; /* The string collected so far */
+ int nChar; /* Length of the string so far */
+ int nAlloc; /* Amount of space allocated in zText */
+};
+
+/* The xprintf callback function. */
+static void mout(zNewText,nNewChar,arg)
+ char *zNewText;
+ int nNewChar;
+ void *arg;
+{
+ struct sgMprintf *pM = (struct sgMprintf*)arg;
+ if( pM->nChar + nNewChar + 1 > pM->nAlloc ){
+ pM->nAlloc = pM->nChar + nNewChar*2 + 1;
+ if( pM->zText==pM->zBase ){
+ pM->zText = malloc(pM->nAlloc);
+ if( pM->zText && pM->nChar ) memcpy(pM->zText,pM->zBase,pM->nChar);
+ }else{
+ pM->zText = realloc(pM->zText, pM->nAlloc);
+ }
+ }
+ if( pM->zText ){
+ memcpy(&pM->zText[pM->nChar], zNewText, nNewChar);
+ pM->nChar += nNewChar;
+ pM->zText[pM->nChar] = 0;
+ }
+}
+
+/*
+** mprintf() works like printf(), but allocations memory to hold the
+** resulting string and returns a pointer to the allocated memory.
+**
+** We changed the name to TclMPrint() to conform with the Tcl private
+** routine naming conventions.
+*/
+char *mprintf(const char *zFormat, ...){
+ va_list ap;
+ struct sgMprintf sMprintf;
+ char *zNew;
+ char zBuf[200];
+
+ va_start(ap,zFormat);
+ sMprintf.nChar = 0;
+ sMprintf.nAlloc = sizeof(zBuf);
+ sMprintf.zText = zBuf;
+ sMprintf.zBase = zBuf;
+ vxprintf(mout,&sMprintf,zFormat,ap);
+ va_end(ap);
+ if( sMprintf.zText==sMprintf.zBase ){
+ zNew = malloc( sMprintf.nChar+1 );
+ if( zNew ) strcpy(zNew,zBuf);
+ }else{
+ zNew = realloc(sMprintf.zText,sMprintf.nChar+1);
+ }
+
+ return zNew;
+}
+
+/* This is the varargs version of mprintf.
+**
+** The name is changed to TclVMPrintf() to conform with Tcl naming
+** conventions.
+*/
+char *vmprintf(const char *zFormat,va_list ap){
+ struct sgMprintf sMprintf;
+ char zBuf[200];
+ sMprintf.nChar = 0;
+ sMprintf.zText = zBuf;
+ sMprintf.nAlloc = sizeof(zBuf);
+ sMprintf.zBase = zBuf;
+ vxprintf(mout,&sMprintf,zFormat,ap);
+ if( sMprintf.zText==sMprintf.zBase ){
+ sMprintf.zText = malloc( strlen(zBuf)+1 );
+ if( sMprintf.zText ) strcpy(sMprintf.zText,zBuf);
+ }else{
+ sMprintf.zText = realloc(sMprintf.zText,sMprintf.nChar+1);
+ }
+ return sMprintf.zText;
+}
+
+/*
+** The following section of code handles the standard fprintf routines
+** for pthreads.
+*/
+
+/* The xprintf callback function. */
+static void fout(zNewText,nNewChar,arg)
+ char *zNewText;
+ int nNewChar;
+ void *arg;
+{
+ fwrite(zNewText,1,nNewChar,(FILE*)arg);
+}
+
+/* The public interface routines */
+int fprintf(FILE *pOut, const char *zFormat, ...){
+ va_list ap;
+ int retc;
+
+ va_start(ap,zFormat);
+ retc = vxprintf(fout,pOut,zFormat,ap);
+ va_end(ap);
+ return retc;
+}
+int vfprintf(FILE *pOut, const char *zFormat, va_list ap){
+ return vxprintf(fout,pOut,zFormat,ap);
+}
+int printf(const char *zFormat, ...){
+ va_list ap;
+ int retc;
+
+ va_start(ap,zFormat);
+ retc = vxprintf(fout,stdout,zFormat,ap);
+ va_end(ap);
+ return retc;
+}
+int vprintf(const char *zFormat, va_list ap){
+ return vxprintf(fout,stdout,zFormat,ap);
+}
diff --git a/mit-pthreads/stdlib/GNUmakefile.inc b/mit-pthreads/stdlib/GNUmakefile.inc
new file mode 100755
index 00000000000..2f55ce8b217
--- /dev/null
+++ b/mit-pthreads/stdlib/GNUmakefile.inc
@@ -0,0 +1,7 @@
+# @(#)Makefile.inc 5.6 (Berkeley) 6/4/91
+
+# stdlib sources
+VPATH:= ${VPATH}:${srcdir}/stdlib
+
+SRCS:= abort.c exit.c strtod.c getopt.c rand.c random.c strtol.c strtoul.c \
+ system.c $(SRCS)
diff --git a/mit-pthreads/stdlib/Makefile.inc b/mit-pthreads/stdlib/Makefile.inc
new file mode 100644
index 00000000000..cc323d1d0e1
--- /dev/null
+++ b/mit-pthreads/stdlib/Makefile.inc
@@ -0,0 +1,10 @@
+# @(#)Makefile.inc 5.6 (Berkeley) 6/4/91
+
+# stdlib sources
+.PATH: ${srcdir}/${MACHINE}/stdlib ${srcdir}/stdlib
+
+SRCS+= exit.c strtod.c getopt.c rand.c random.c strtol.c strtoul.c
+
+# SRCS+=abort.c atexit.c atoi.c atof.c atol.c bsearch.c calloc.c div.c \
+# getenv.c heapsort.c labs.c ldiv.c malloc.c multibyte.c \
+# putenv.c qsort.c radixsort.c setenv.c system.c
diff --git a/mit-pthreads/stdlib/abort.c b/mit-pthreads/stdlib/abort.c
new file mode 100644
index 00000000000..474c35f6107
--- /dev/null
+++ b/mit-pthreads/stdlib/abort.c
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 1985 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)abort.c 5.11 (Berkeley) 2/23/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <pthread.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <unistd.h>
+
+void
+abort()
+{
+ sigset_t mask;
+
+ sigfillset(&mask);
+ /*
+ * don't block SIGABRT to give any handler a chance; we ignore
+ * any errors -- X3J11 doesn't allow abort to return anyway.
+ */
+ sigdelset(&mask, SIGABRT);
+ pthread_sigmask(SIG_SETMASK, &mask, NULL);
+ kill(getpid(), SIGABRT);
+
+ /*
+ * if SIGABRT ignored, or caught and the handler returns, do
+ * it again, only harder.
+ */
+ pthread_signal(SIGABRT, SIG_DFL);
+ pthread_sigmask(SIG_SETMASK, &mask, NULL);
+ kill(getpid(), SIGABRT);
+ exit(1);
+}
diff --git a/mit-pthreads/stdlib/atexit.h b/mit-pthreads/stdlib/atexit.h
new file mode 100644
index 00000000000..d13dc588781
--- /dev/null
+++ b/mit-pthreads/stdlib/atexit.h
@@ -0,0 +1,46 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)atexit.h 5.1 (Berkeley) 5/15/90
+ * $Id$
+ */
+
+/* must be at least 32 to guarantee ANSI conformance */
+#define ATEXIT_SIZE 32
+
+struct atexit {
+ struct atexit *next; /* next in list */
+ int ind; /* next index in this table */
+ void (*fns[ATEXIT_SIZE])(); /* the table itself */
+};
+
+struct atexit *__atexit; /* points to head of LIFO stack */
diff --git a/mit-pthreads/stdlib/exit.c b/mit-pthreads/stdlib/exit.c
new file mode 100644
index 00000000000..159a066d797
--- /dev/null
+++ b/mit-pthreads/stdlib/exit.c
@@ -0,0 +1,89 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)exit.c 5.4 (Berkeley) 2/23/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <pthread.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/cdefs.h>
+#include <pthread/posix.h>
+#include "atexit.h"
+
+void (*__cleanup)();
+
+/*
+ * Exit, flushing stdio buffers if necessary.
+ */
+void __NORETURN exit(int status)
+{
+ register struct atexit *p;
+ register int n;
+
+ for (p = __atexit; p; p = p->next)
+ for (n = p->ind; --n >= 0;)
+ (*p->fns[n])();
+ if (__cleanup)
+ (*__cleanup)();
+ _exit(status);
+
+ /* This is to shut up gcc, which complains about this function
+ * returning even if _exit() is declared noreturn. */
+ while (1);
+}
+
+
+/*
+ * Register a function to be performed at exit.
+ */
+int atexit(void (*fn)())
+{
+ static struct atexit __atexit0; /* one guaranteed table */
+ register struct atexit *p;
+
+ if ((p = __atexit) == NULL)
+ __atexit = p = &__atexit0;
+ else if (p->ind >= ATEXIT_SIZE) {
+ if ((p = malloc(sizeof(*p))) == NULL)
+ return (-1);
+ p->ind = 0;
+ p->next = __atexit;
+ __atexit = p;
+ }
+ p->fns[p->ind++] = fn;
+ return (0);
+}
diff --git a/mit-pthreads/stdlib/getopt.c b/mit-pthreads/stdlib/getopt.c
new file mode 100644
index 00000000000..71fafd49490
--- /dev/null
+++ b/mit-pthreads/stdlib/getopt.c
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 1987 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)getopt.c 4.13 (Berkeley) 2/23/91";
+#endif /* LIBC_SCCS and not lint */
+
+#include <config.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * get option letter from argument vector
+ */
+
+#ifndef LD_LINKS_STATIC_DATA
+/*
+ * Under the Solaris ld, some data sections are linked in regaurdless of
+ * whether or not the name has been resolved.
+ */
+int opterr = 1, /* if error message should be printed */
+ optind = 1, /* index into parent argv vector */
+ optopt = 0; /* character checked for validity */
+char * optarg = NULL; /* argument associated with option */
+
+#else
+
+extern int opterr, optind, optopt;
+extern char *optarg;
+
+#endif
+
+#define BADCH (int)'?'
+#define EMSG ""
+
+int
+getopt(nargc, nargv, ostr)
+ int nargc;
+ char * const *nargv;
+ const char *ostr;
+{
+ static char *place = EMSG; /* option letter processing */
+ register char *oli; /* option letter list index */
+ char *p;
+
+ if (!*place) { /* update scanning pointer */
+ if (optind >= nargc || *(place = nargv[optind]) != '-') {
+ place = EMSG;
+ return(EOF);
+ }
+ if (place[1] && *++place == '-') { /* found "--" */
+ ++optind;
+ place = EMSG;
+ return(EOF);
+ }
+ } /* option letter okay? */
+ if ((optopt = (int)*place++) == (int)':' ||
+ !(oli = strchr(ostr, optopt))) {
+ /*
+ * if the user didn't specify '-' as an option,
+ * assume it means EOF.
+ */
+ if (optopt == (int)'-')
+ return(EOF);
+ if (!*place)
+ ++optind;
+ if (opterr) {
+ if (!(p = strrchr(*nargv, '/')))
+ p = *nargv;
+ else
+ ++p;
+ (void)fprintf(stderr, "%s: illegal option -- %c\n",
+ p, optopt);
+ }
+ return(BADCH);
+ }
+ if (*++oli != ':') { /* don't need argument */
+ optarg = NULL;
+ if (!*place)
+ ++optind;
+ }
+ else { /* need an argument */
+ if (*place) /* no white space */
+ optarg = place;
+ else if (nargc <= ++optind) { /* no arg */
+ place = EMSG;
+ if (!(p = strrchr(*nargv, '/')))
+ p = *nargv;
+ else
+ ++p;
+ if (opterr)
+ (void)fprintf(stderr,
+ "%s: option requires an argument -- %c\n",
+ p, optopt);
+ return(BADCH);
+ }
+ else /* white space */
+ optarg = nargv[optind];
+ place = EMSG;
+ ++optind;
+ }
+ return(optopt); /* dump back option letter */
+}
diff --git a/mit-pthreads/stdlib/rand.c b/mit-pthreads/stdlib/rand.c
new file mode 100644
index 00000000000..9367dceed25
--- /dev/null
+++ b/mit-pthreads/stdlib/rand.c
@@ -0,0 +1,64 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * Copyright (c) 1994 Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)rand.c 5.6 (Berkeley) 6/24/91";
+#endif /* LIBC_SCCS and not lint */
+
+#include <pthread.h>
+#include <sys/types.h>
+#include <stdlib.h>
+
+static u_long next = 1;
+
+int rand_r(u_int * next_r)
+{
+ int ret;
+
+ (*next_r) = (*next_r) * 1103515245 + 12345;
+ ret = (*next_r) & RAND_MAX;
+ return(ret);
+}
+
+#undef rand
+int rand(void)
+{
+ return ((next = next * 1103515245 + 12345) & RAND_MAX);
+}
+
+#undef srand
+void srand(unsigned int seed)
+{
+ next = seed;
+}
diff --git a/mit-pthreads/stdlib/random.c b/mit-pthreads/stdlib/random.c
new file mode 100644
index 00000000000..8cba96e7534
--- /dev/null
+++ b/mit-pthreads/stdlib/random.c
@@ -0,0 +1,389 @@
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * Copyright (c) 1994 Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)random.c 5.9 (Berkeley) 2/23/91";
+#endif /* LIBC_SCCS and not lint */
+
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+/*
+ * random.c:
+ *
+ * An improved random number generation package. In addition to the standard
+ * rand()/srand() like interface, this package also has a special state info
+ * interface. The initstate() routine is called with a seed, an array of
+ * bytes, and a count of how many bytes are being passed in; this array is
+ * then initialized to contain information for random number generation with
+ * that much state information. Good sizes for the amount of state
+ * information are 32, 64, 128, and 256 bytes. The state can be switched by
+ * calling the setstate() routine with the same array as was initiallized
+ * with initstate(). By default, the package runs with 128 bytes of state
+ * information and generates far better random numbers than a linear
+ * congruential generator. If the amount of state information is less than
+ * 32 bytes, a simple linear congruential R.N.G. is used.
+ *
+ * Internally, the state information is treated as an array of longs; the
+ * zeroeth element of the array is the type of R.N.G. being used (small
+ * integer); the remainder of the array is the state information for the
+ * R.N.G. Thus, 32 bytes of state information will give 7 longs worth of
+ * state information, which will allow a degree seven polynomial. (Note:
+ * the zeroeth word of state information also has some other information
+ * stored in it -- see setstate() for details).
+ *
+ * The random number generation technique is a linear feedback shift register
+ * approach, employing trinomials (since there are fewer terms to sum up that
+ * way). In this approach, the least significant bit of all the numbers in
+ * the state table will act as a linear feedback shift register, and will
+ * have period 2^deg - 1 (where deg is the degree of the polynomial being
+ * used, assuming that the polynomial is irreducible and primitive). The
+ * higher order bits will have longer periods, since their values are also
+ * influenced by pseudo-random carries out of the lower bits. The total
+ * period of the generator is approximately deg*(2**deg - 1); thus doubling
+ * the amount of state information has a vast influence on the period of the
+ * generator. Note: the deg*(2**deg - 1) is an approximation only good for
+ * large deg, when the period of the shift register is the dominant factor.
+ * With deg equal to seven, the period is actually much longer than the
+ * 7*(2**7 - 1) predicted by this formula.
+ */
+
+/*
+ * For each of the currently supported random number generators, we have a
+ * break value on the amount of state information (you need at least this
+ * many bytes of state info to support this random number generator), a degree
+ * for the polynomial (actually a trinomial) that the R.N.G. is based on, and
+ * the separation between the two lower order coefficients of the trinomial.
+ */
+#define TYPE_0 0 /* linear congruential */
+#define BREAK_0 8
+#define DEG_0 0
+#define SEP_0 0
+
+#define TYPE_1 1 /* x**7 + x**3 + 1 */
+#define BREAK_1 32
+#define DEG_1 7
+#define SEP_1 3
+
+#define TYPE_2 2 /* x**15 + x + 1 */
+#define BREAK_2 64
+#define DEG_2 15
+#define SEP_2 1
+
+#define TYPE_3 3 /* x**31 + x**3 + 1 */
+#define BREAK_3 128
+#define DEG_3 31
+#define SEP_3 3
+
+#define TYPE_4 4 /* x**63 + x + 1 */
+#define BREAK_4 256
+#define DEG_4 63
+#define SEP_4 1
+
+/*
+ * Array versions of the above information to make code run faster --
+ * relies on fact that TYPE_i == i.
+ */
+#define MAX_TYPES 5 /* max number of types above */
+
+static int degrees[MAX_TYPES] = { DEG_0, DEG_1, DEG_2, DEG_3, DEG_4 };
+static int seps [MAX_TYPES] = { SEP_0, SEP_1, SEP_2, SEP_3, SEP_4 };
+
+/*
+ * Initially, everything is set up as if from:
+ *
+ * initstate(1, &randtbl, 128);
+ *
+ * Note that this initialization takes advantage of the fact that srandom()
+ * advances the front and rear pointers 10*rand_deg times, and hence the
+ * rear pointer which starts at 0 will also end up at zero; thus the zeroeth
+ * element of the state information, which contains info about the current
+ * position of the rear pointer is just
+ *
+ * MAX_TYPES * (rptr - state) + TYPE_3 == TYPE_3.
+ */
+
+static long randtbl[DEG_3 + 1] = {
+ TYPE_3,
+ 0x9a319039, 0x32d9c024, 0x9b663182, 0x5da1f342, 0xde3b81e0, 0xdf0a6fb5,
+ 0xf103bc02, 0x48f340fb, 0x7449e56b, 0xbeb1dbb0, 0xab5c5918, 0x946554fd,
+ 0x8c2e680f, 0xeb3d799f, 0xb11ee0b7, 0x2d436b86, 0xda672e2a, 0x1588ca88,
+ 0xe369735d, 0x904f35f7, 0xd7158fd6, 0x6fa6f051, 0x616e6b96, 0xac94efdc,
+ 0x36413f93, 0xc622c298, 0xf5a42ab8, 0x8a88d77b, 0xf5ad9d0e, 0x8999220b,
+ 0x27fb47b9,
+};
+
+/*
+ * fptr and rptr are two pointers into the state info, a front and a rear
+ * pointer. These two pointers are always rand_sep places aparts, as they
+ * cycle cyclically through the state information. (Yes, this does mean we
+ * could get away with just one pointer, but the code for random() is more
+ * efficient this way). The pointers are left positioned as they would be
+ * from the call
+ *
+ * initstate(1, randtbl, 128);
+ *
+ * (The position of the rear pointer, rptr, is really 0 (as explained above
+ * in the initialization of randtbl) because the state table pointer is set
+ * to point to randtbl[1] (as explained below).
+ */
+static long *fptr = &randtbl[SEP_3 + 1];
+static long *rptr = &randtbl[1];
+
+/*
+ * The following things are the pointer to the state information table, the
+ * type of the current generator, the degree of the current polynomial being
+ * used, and the separation between the two pointers. Note that for efficiency
+ * of random(), we remember the first location of the state information, not
+ * the zeroeth. Hence it is valid to access state[-1], which is used to
+ * store the type of the R.N.G. Also, we remember the last location, since
+ * this is more efficient than indexing every time to find the address of
+ * the last element to see if the front and rear pointers have wrapped.
+ */
+static long *state = &randtbl[1];
+static int rand_type = TYPE_3;
+static int rand_deg = DEG_3;
+static int rand_sep = SEP_3;
+static long *end_ptr = &randtbl[DEG_3 + 1];
+
+/*
+ * State info won't be corrupted by multiple simultaneous calls,
+ * but srandom(), initstate(), and setstate() affect all threads
+ */
+static pthread_mutex_t random_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+/*
+ * random:
+ *
+ * If we are using the trivial TYPE_0 R.N.G., just do the old linear
+ * congruential bit. Otherwise, we do our fancy trinomial stuff, which is
+ * the same in all the other cases due to all the global variables that have
+ * been set up. The basic operation is to add the number at the rear pointer
+ * into the one at the front pointer. Then both pointers are advanced to
+ * the next location cyclically in the table. The value returned is the sum
+ * generated, reduced to 31 bits by throwing away the "least random" low bit.
+ *
+ * Note: the code takes advantage of the fact that both the front and
+ * rear pointers can't wrap on the same call by not testing the rear
+ * pointer if the front one has wrapped.
+ *
+ * Returns a 31-bit random number.
+ */
+static long random_basic()
+{
+ long i;
+
+ if (rand_type == TYPE_0)
+ i = state[0] = (state[0] * 1103515245 + 12345) & 0x7fffffff;
+ else {
+ *fptr += *rptr;
+ i = (*fptr >> 1) & 0x7fffffff; /* chucking least random bit */
+ if (++fptr >= end_ptr) {
+ fptr = state;
+ ++rptr;
+ } else if (++rptr >= end_ptr)
+ rptr = state;
+ }
+ return(i);
+}
+
+long random()
+{
+ long ret;
+
+ pthread_mutex_lock(&random_mutex);
+ ret = random_basic();
+ pthread_mutex_unlock(&random_mutex);
+ return(ret);
+}
+/*
+ * srandom:
+ *
+ * Initialize the random number generator based on the given seed. If the
+ * type is the trivial no-state-information type, just remember the seed.
+ * Otherwise, initializes state[] based on the given "seed" via a linear
+ * congruential generator. Then, the pointers are set to known locations
+ * that are exactly rand_sep places apart. Lastly, it cycles the state
+ * information a given number of times to get rid of any initial dependencies
+ * introduced by the L.C.R.N.G. Note that the initialization of randtbl[]
+ * for default usage relies on values produced by this routine.
+ */
+static void srandom_basic(u_int x)
+{
+ int i;
+
+ state[0] = x;
+ for (i = 1; i < rand_deg; i++)
+ state[i] = 1103515245 * state[i - 1] + 12345;
+ fptr = &state[rand_sep];
+ rptr = &state[0];
+
+ for (i = 0; i < 10 * rand_deg; i++)
+ (void)random_basic();
+}
+
+void srandom(u_int x)
+{
+ pthread_mutex_lock(&random_mutex);
+ srandom_basic(x);
+ pthread_mutex_unlock(&random_mutex);
+}
+
+/*
+ * initstate:
+ *
+ * Initialize the state information in the given array of n bytes for future
+ * random number generation. Based on the number of bytes we are given, and
+ * the break values for the different R.N.G.'s, we choose the best (largest)
+ * one we can and set things up for it. srandom() is then called to
+ * initialize the state information.
+ *
+ * Note that on return from srandom(), we set state[-1] to be the type
+ * multiplexed with the current value of the rear pointer; this is so
+ * successive calls to initstate() won't lose this information and will be
+ * able to restart with setstate().
+ *
+ * Note: the first thing we do is save the current state, if any, just like
+ * setstate() so that it doesn't matter when initstate is called.
+ *
+ * Returns a pointer to the old state.
+ */
+#ifdef initstate
+#undef initstate
+#endif
+char * initstate(u_int seed, char * arg_state, int n)
+{
+ register char *ostate = (char *)(&state[-1]);
+
+ pthread_mutex_lock(&random_mutex);
+
+ if (rand_type == TYPE_0)
+ state[-1] = rand_type;
+ else
+ state[-1] = MAX_TYPES * (rptr - state) + rand_type;
+ if (n < BREAK_0) {
+ (void)fprintf(stderr,
+ "random: not enough state (%d bytes); ignored.\n", n);
+ pthread_mutex_unlock(&random_mutex);
+ return(0);
+ }
+ if (n < BREAK_1) {
+ rand_type = TYPE_0;
+ rand_deg = DEG_0;
+ rand_sep = SEP_0;
+ } else if (n < BREAK_2) {
+ rand_type = TYPE_1;
+ rand_deg = DEG_1;
+ rand_sep = SEP_1;
+ } else if (n < BREAK_3) {
+ rand_type = TYPE_2;
+ rand_deg = DEG_2;
+ rand_sep = SEP_2;
+ } else if (n < BREAK_4) {
+ rand_type = TYPE_3;
+ rand_deg = DEG_3;
+ rand_sep = SEP_3;
+ } else {
+ rand_type = TYPE_4;
+ rand_deg = DEG_4;
+ rand_sep = SEP_4;
+ }
+ state = &(((long *)arg_state)[1]); /* first location */
+ end_ptr = &state[rand_deg]; /* must set end_ptr before srandom */
+ srandom_basic(seed);
+ if (rand_type == TYPE_0)
+ state[-1] = rand_type;
+ else
+ state[-1] = MAX_TYPES*(rptr - state) + rand_type;
+ pthread_mutex_unlock(&random_mutex);
+ return(ostate);
+}
+
+/*
+ * setstate:
+ *
+ * Restore the state from the given state array.
+ *
+ * Note: it is important that we also remember the locations of the pointers
+ * in the current state information, and restore the locations of the pointers
+ * from the old state information. This is done by multiplexing the pointer
+ * location into the zeroeth word of the state information.
+ *
+ * Note that due to the order in which things are done, it is OK to call
+ * setstate() with the same state as the current state.
+ *
+ * Returns a pointer to the old state information.
+ */
+#ifdef setstate
+#undef setstate
+#endif
+char * setstate(char * arg_state)
+{
+ register long *new_state = (long *)arg_state;
+ register int type = new_state[0] % MAX_TYPES;
+ register int rear = new_state[0] / MAX_TYPES;
+ char *ostate = (char *)(&state[-1]);
+
+ pthread_mutex_lock(&random_mutex);
+
+ if (rand_type == TYPE_0)
+ state[-1] = rand_type;
+ else
+ state[-1] = MAX_TYPES * (rptr - state) + rand_type;
+ switch(type) {
+ case TYPE_0:
+ case TYPE_1:
+ case TYPE_2:
+ case TYPE_3:
+ case TYPE_4:
+ rand_type = type;
+ rand_deg = degrees[type];
+ rand_sep = seps[type];
+ break;
+ default:
+ (void)fprintf(stderr,
+ "random: state info corrupted; not changed.\n");
+ }
+ state = &new_state[1];
+ if (rand_type != TYPE_0) {
+ rptr = &state[rear];
+ fptr = &state[(rear + rand_sep) % rand_deg];
+ }
+ end_ptr = &state[rand_deg]; /* set end_ptr too */
+
+ pthread_mutex_unlock(&random_mutex);
+ return(ostate);
+}
+
diff --git a/mit-pthreads/stdlib/strtod.c b/mit-pthreads/stdlib/strtod.c
new file mode 100644
index 00000000000..173ca1e4bdf
--- /dev/null
+++ b/mit-pthreads/stdlib/strtod.c
@@ -0,0 +1,178 @@
+/*
+** An alternative implemtation of "strtod()" that is both
+** simplier, and thread-safe.
+*/
+#include <pthread.h>
+#include <ctype.h>
+#include <math.h>
+
+#ifdef TEST
+# define strtod NewStrtod
+#include <stdio.h>
+#endif
+
+static double scaler10[] = {
+ 1.0, 1e10, 1e20, 1e30, 1e40, 1e50, 1e60, 1e70, 1e80, 1e90
+};
+static double scaler1[] = {
+ 1.0, 10.0, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9
+};
+static double pastpoint[] = {
+ 1e-1, 1e-2, 1e-3, 1e-4, 1e-5, 1e-6, 1e-7, 1e-8, 1e-9,
+ 1e-10, 1e-11, 1e-12, 1e-13, 1e-14, 1e-15, 1e-16, 1e-17, 1e-18, 1e-19,
+ 1e-20, 1e-21, 1e-22, 1e-23, 1e-24, 1e-25, 1e-26, 1e-27, 1e-28, 1e-29,
+ 1e-30, 1e-31, 1e-32, 1e-33, 1e-34, 1e-35, 1e-36, 1e-37, 1e-38, 1e-39,
+ 1e-40, 1e-41, 1e-42, 1e-43, 1e-44, 1e-45, 1e-46, 1e-47, 1e-48, 1e-49,
+ 1e-50, 1e-51, 1e-52, 1e-53, 1e-54, 1e-55, 1e-56, 1e-57, 1e-58, 1e-59,
+};
+
+#ifndef DBL_MAX
+#define DBL_MAX 1.7976931348623157e+308
+#endif
+
+double strtod(const char *zNum, char **pzEnd){
+ double rResult = 0.0;
+ int isNegative = 0;
+
+ while( isspace(*zNum) ){
+ zNum++;
+ }
+ if( *zNum=='-' ){
+ zNum++;
+ isNegative = 1;
+ }else if( *zNum=='+' ){
+ zNum++;
+ }
+ while( isdigit(*zNum) ){
+ rResult = rResult*10.0 + (*zNum - '0');
+ zNum++;
+ }
+ if( *zNum=='.' ){
+ int n = 0;
+ zNum++;
+ while( isdigit(*zNum) ){
+ if( n<sizeof(pastpoint)/sizeof(pastpoint[0]) ){
+ rResult += pastpoint[n] * (*zNum - '0');
+ n++;
+ }
+ zNum++;
+ }
+ }
+ if( *zNum=='e' || *zNum=='E' ){
+ int expVal = 0;
+ int isNegExp = 0;
+ const char *zExpStart = zNum;
+ zNum++;
+ if( *zNum=='-' ){
+ isNegExp = 1;
+ zNum++;
+ }else if( *zNum=='+' ){
+ zNum++;
+ }
+ if( !isdigit(*zNum) ){
+ zNum = zExpStart;
+ }else{
+ double scaler = 1.0;
+ while( isdigit(*zNum) ){
+ expVal = expVal*10 + *zNum - '0';
+ zNum++;
+ }
+ if( expVal >= 1000 ){
+ if( isNegExp ){
+ rResult = 0.0;
+ }else{
+ rResult = DBL_MAX;
+ }
+ goto done;
+ }
+ while( expVal >= 100 ){
+ scaler *= 1.0e100;
+ expVal -= 100;
+ }
+ scaler *= scaler10[expVal/10]*scaler1[expVal%10];
+ if( isNegExp ){
+ scaler = 1.0/scaler;
+ }
+ rResult *= scaler;
+ }
+
+ }
+
+done:
+ if( pzEnd ){
+ *pzEnd = (char *)zNum;
+ }
+ if( isNegative && rResult!=0.0 ){
+ rResult = -rResult;
+ }
+ return rResult;
+}
+
+double atof(const char *nptr)
+{
+ return (strtod(nptr, 0));
+}
+
+#ifdef TEST
+#undef strtod
+
+double strtod(const char*,char**);
+double NewStrtod(const char*,char**);
+
+int main(int argc, char **argv){
+ int nTest = 0;
+ int nFail = 0;
+ int nBigFail = 0;
+ char zBuf[1000];
+
+ while( fgets(zBuf,sizeof(zBuf),stdin) ){
+ double old, new;
+ char *zTailOld, *zTailNew;
+ int i;
+
+ for(i=0; zBuf[i] && zBuf[i]!='\n'; i++){}
+ zBuf[i] = 0;
+
+#if TEST==1
+ printf("Input line: [%s]\n",zBuf);
+ old = strtod(zBuf,&zTailOld);
+ printf("value=%g\n",old);
+ printf("Old: 0x%08x%08x tail=[%s]\n",
+ ((int*)&old)[1], ((int*)&old)[0], zTailOld);
+ new = NewStrtod(zBuf,&zTailNew);
+ printf("value=%g\n",new);
+ printf("New: 0x%08x%08x tail=[%s]\n\n",
+ ((int*)&new)[1], ((int*)&new)[0], zTailNew);
+#else
+ old = strtod(zBuf,&zTailOld);
+ new = NewStrtod(zBuf,&zTailNew);
+ nTest++;
+ if( strcmp(zTailOld,zTailNew)
+ || ((int*)&old)[0]!=((int*)&new)[0]
+ || ((int*)&old)[1]!=((int*)&new)[1]
+ ){
+ int olda, oldb, newa, newb;
+
+ nFail++;
+ olda = ((int*)&old)[1];
+ oldb = ((int*)&old)[0];
+ newa = ((int*)&new)[1];
+ newb = ((int*)&new)[0];
+
+ if( olda!=newa || abs(oldb-newb)>2 ){
+ nBigFail++;
+ printf("******* Big failure \n");
+ }
+ printf("Input = [%s]\n",zBuf);
+ printf("old: val=%g 0x%08x%08x tail=[%s]\n",
+ old, olda, oldb, zTailOld);
+ printf("new: val=%g 0x%08x%08x tail=[%s]\n\n",
+ new, newa, newb, zTailNew);
+ }
+#endif
+ }
+
+ printf("Out of %d tests, %d failures and %d big failurs\n",
+ nTest,nFail, nBigFail);
+}
+#endif
diff --git a/mit-pthreads/stdlib/strtol.c b/mit-pthreads/stdlib/strtol.c
new file mode 100644
index 00000000000..91be90cc94c
--- /dev/null
+++ b/mit-pthreads/stdlib/strtol.c
@@ -0,0 +1,131 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)strtol.c 5.4 (Berkeley) 2/23/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <pthread.h>
+#include <limits.h>
+#include <ctype.h>
+#include <errno.h>
+#include <stdlib.h>
+
+
+/*
+ * Convert a string to a long integer.
+ *
+ * Ignores `locale' stuff. Assumes that the upper and lower case
+ * alphabets and digits are each contiguous.
+ */
+long
+strtol(nptr, endptr, base)
+ const char *nptr;
+ char **endptr;
+ register int base;
+{
+ register const char *s = nptr;
+ register unsigned long acc;
+ register int c;
+ register unsigned long cutoff;
+ register int neg = 0, any, cutlim;
+
+ /*
+ * Skip white space and pick up leading +/- sign if any.
+ * If base is 0, allow 0x for hex and 0 for octal, else
+ * assume decimal; if base is already 16, allow 0x.
+ */
+ do {
+ c = *s++;
+ } while (isspace(c));
+ if (c == '-') {
+ neg = 1;
+ c = *s++;
+ } else if (c == '+')
+ c = *s++;
+ if ((base == 0 || base == 16) &&
+ c == '0' && (*s == 'x' || *s == 'X')) {
+ c = s[1];
+ s += 2;
+ base = 16;
+ }
+ if (base == 0)
+ base = c == '0' ? 8 : 10;
+
+ /*
+ * Compute the cutoff value between legal numbers and illegal
+ * numbers. That is the largest legal value, divided by the
+ * base. An input number that is greater than this value, if
+ * followed by a legal input character, is too big. One that
+ * is equal to this value may be valid or not; the limit
+ * between valid and invalid numbers is then based on the last
+ * digit. For instance, if the range for longs is
+ * [-2147483648..2147483647] and the input base is 10,
+ * cutoff will be set to 214748364 and cutlim to either
+ * 7 (neg==0) or 8 (neg==1), meaning that if we have accumulated
+ * a value > 214748364, or equal but the next digit is > 7 (or 8),
+ * the number is too big, and we will return a range error.
+ *
+ * Set any if any `digits' consumed; make it negative to indicate
+ * overflow.
+ */
+ cutoff = neg ? -(unsigned long)LONG_MIN : LONG_MAX;
+ cutlim = cutoff % (unsigned long)base;
+ cutoff /= (unsigned long)base;
+ for (acc = 0, any = 0;; c = *s++) {
+ if (isdigit(c))
+ c -= '0';
+ else if (isalpha(c))
+ c -= isupper(c) ? 'A' - 10 : 'a' - 10;
+ else
+ break;
+ if (c >= base)
+ break;
+ if (any < 0 || acc > cutoff || acc == cutoff && c > cutlim)
+ any = -1;
+ else {
+ any = 1;
+ acc *= base;
+ acc += c;
+ }
+ }
+ if (any < 0) {
+ acc = neg ? LONG_MIN : LONG_MAX;
+ errno = ERANGE;
+ } else if (neg)
+ acc = -acc;
+ if (endptr != 0)
+ *endptr = (char *) (any ? s - 1 : nptr);
+ return (acc);
+}
diff --git a/mit-pthreads/stdlib/strtoul.c b/mit-pthreads/stdlib/strtoul.c
new file mode 100644
index 00000000000..c6b6b01a0f2
--- /dev/null
+++ b/mit-pthreads/stdlib/strtoul.c
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 1990 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)strtoul.c 5.3 (Berkeley) 2/23/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <pthread.h>
+#include <limits.h>
+#include <ctype.h>
+#include <errno.h>
+#include <stdlib.h>
+
+/*
+ * Convert a string to an unsigned long integer.
+ *
+ * Ignores `locale' stuff. Assumes that the upper and lower case
+ * alphabets and digits are each contiguous.
+ */
+unsigned long
+strtoul(nptr, endptr, base)
+ const char *nptr;
+ char **endptr;
+ register int base;
+{
+ register const char *s = nptr;
+ register unsigned long acc;
+ register int c;
+ register unsigned long cutoff;
+ register int neg = 0, any, cutlim;
+
+ /*
+ * See strtol for comments as to the logic used.
+ */
+ do {
+ c = *s++;
+ } while (isspace(c));
+ if (c == '-') {
+ neg = 1;
+ c = *s++;
+ } else if (c == '+')
+ c = *s++;
+ if ((base == 0 || base == 16) &&
+ c == '0' && (*s == 'x' || *s == 'X')) {
+ c = s[1];
+ s += 2;
+ base = 16;
+ }
+ if (base == 0)
+ base = c == '0' ? 8 : 10;
+ cutoff = (unsigned long)ULONG_MAX / (unsigned long)base;
+ cutlim = (unsigned long)ULONG_MAX % (unsigned long)base;
+ for (acc = 0, any = 0;; c = *s++) {
+ if (isdigit(c))
+ c -= '0';
+ else if (isalpha(c))
+ c -= isupper(c) ? 'A' - 10 : 'a' - 10;
+ else
+ break;
+ if (c >= base)
+ break;
+ if (any < 0 || acc > cutoff || acc == cutoff && c > cutlim)
+ any = -1;
+ else {
+ any = 1;
+ acc *= base;
+ acc += c;
+ }
+ }
+ if (any < 0) {
+ acc = ULONG_MAX;
+ errno = ERANGE;
+ } else if (neg)
+ acc = -acc;
+ if (endptr != 0)
+ *endptr = (char *) (any ? s - 1 : nptr);
+ return (acc);
+}
diff --git a/mit-pthreads/stdlib/system.c b/mit-pthreads/stdlib/system.c
new file mode 100644
index 00000000000..e7cc164fbc7
--- /dev/null
+++ b/mit-pthreads/stdlib/system.c
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 1988 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)system.c 5.10 (Berkeley) 2/23/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <pthread.h>
+#include <pthread/paths.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <unistd.h>
+
+extern char **environ;
+
+system(command)
+ const char *command;
+{
+ char *argp[] = {"sh", "-c", "*to be filled in*", NULL};
+ void (*intsave)(), (*quitsave)(), (*signal())();
+ sigset_t tmp_mask, old_mask;
+ int pstat;
+ pid_t pid;
+
+ if (!command) /* just checking... */
+ return(1);
+
+ argp[2] = (char *) command;
+ sigemptyset(&tmp_mask);
+ sigaddset(&tmp_mask, SIGCHLD);
+ pthread_sigmask(SIG_BLOCK, &tmp_mask, &old_mask);
+ switch(pid = fork()) {
+ case -1: /* error */
+ (void)pthread_sigmask(SIG_SETMASK, &old_mask, NULL);
+ return(-1);
+ case 0: /* child */
+ (void)pthread_sigmask(SIG_SETMASK, &old_mask, NULL);
+ execve(_PATH_BSHELL, argp, environ);
+ _exit(127);
+ }
+
+ intsave = pthread_signal(SIGINT, SIG_IGN);
+ quitsave = pthread_signal(SIGQUIT, SIG_IGN);
+ pid = waitpid(pid, (int *)&pstat, 0);
+ (void)pthread_sigmask(SIG_SETMASK, &old_mask, NULL);
+ (void)pthread_signal(SIGQUIT, quitsave);
+ (void)pthread_signal(SIGINT, intsave);
+ return(pid == -1 ? -1 : pstat);
+}
diff --git a/mit-pthreads/string/GNUmakefile.inc b/mit-pthreads/string/GNUmakefile.inc
new file mode 100755
index 00000000000..f3994d31479
--- /dev/null
+++ b/mit-pthreads/string/GNUmakefile.inc
@@ -0,0 +1,7 @@
+# from: @(#)Makefile.inc 5.21 (Berkeley) 5/24/91
+# $Id$
+
+# gen sources
+VPATH:= ${VPATH}:${srcdir}/string
+
+SRCS:= strtok.c $(SRCS)
diff --git a/mit-pthreads/string/Makefile.inc b/mit-pthreads/string/Makefile.inc
new file mode 100644
index 00000000000..4a5536bac4a
--- /dev/null
+++ b/mit-pthreads/string/Makefile.inc
@@ -0,0 +1,8 @@
+# from: @(#)Makefile.inc 5.21 (Berkeley) 5/24/91
+# $Id$
+
+# string sources
+.PATH: ${srcdir}/string
+
+SRCS+= strtok.c
+
diff --git a/mit-pthreads/string/strtok.c b/mit-pthreads/string/strtok.c
new file mode 100644
index 00000000000..4c08dcc4d37
--- /dev/null
+++ b/mit-pthreads/string/strtok.c
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 1988 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)strtok.c 5.8 (Berkeley) 2/24/91";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <pthread.h>
+#include <string.h>
+#include <stdlib.h>
+
+char *
+strtok(s, delim)
+ register char *s;
+ register const char *delim;
+{
+ static pthread_mutex_t strtok_mutex = PTHREAD_MUTEX_INITIALIZER;
+ static pthread_key_t strtok_key = -1;
+ char **lasts;
+
+ pthread_mutex_lock(&strtok_mutex);
+ if (strtok_key < 0) {
+ if (pthread_key_create(&strtok_key, free) < 0) {
+ pthread_mutex_unlock(&strtok_mutex);
+ return(NULL);
+ }
+ }
+ pthread_mutex_unlock(&strtok_mutex);
+ if ((lasts = pthread_getspecific(strtok_key)) == NULL) {
+ if ((lasts = (char **)malloc(sizeof(char *))) == NULL) {
+ return(NULL);
+ }
+ pthread_setspecific(strtok_key, lasts);
+ }
+
+ return(strtok_r(s, delim, lasts));
+}
+
+char *
+strtok_r(s, delim, lasts)
+ register char *s;
+ register const char *delim;
+ register char **lasts;
+{
+ register char *spanp;
+ register int c, sc;
+ char *tok;
+
+
+ if (s == NULL && (s = *lasts) == NULL)
+ return (NULL);
+
+ /*
+ * Skip (span) leading delimiters (s += strspn(s, delim), sort of).
+ */
+cont:
+ c = *s++;
+ for (spanp = (char *)delim; (sc = *spanp++) != 0;) {
+ if (c == sc)
+ goto cont;
+ }
+
+ if (c == 0) { /* no non-delimiter characters */
+ *lasts = NULL;
+ return (NULL);
+ }
+ tok = s - 1;
+
+ /*
+ * Scan token (scan for delimiters: s += strcspn(s, delim), sort of).
+ * Note that delim must have one NUL; we stop if we see that, too.
+ */
+ for (;;) {
+ c = *s++;
+ spanp = (char *)delim;
+ do {
+ if ((sc = *spanp++) == c) {
+ if (c == 0)
+ s = NULL;
+ else
+ s[-1] = 0;
+ *lasts = s;
+ return (tok);
+ }
+ } while (sc != 0);
+ }
+ /* NOTREACHED */
+}
diff --git a/mit-pthreads/tests/.cvsignore b/mit-pthreads/tests/.cvsignore
new file mode 100644
index 00000000000..f3c7a7c5da6
--- /dev/null
+++ b/mit-pthreads/tests/.cvsignore
@@ -0,0 +1 @@
+Makefile
diff --git a/mit-pthreads/tests/Makefile.in b/mit-pthreads/tests/Makefile.in
new file mode 100644
index 00000000000..6e01b6bffc3
--- /dev/null
+++ b/mit-pthreads/tests/Makefile.in
@@ -0,0 +1,164 @@
+# === GNUmakefile ============================================================
+# Copyright (c) 1993 Chris Provenzano, proven@athena.mit.edu
+#
+# Description: This file is for creating the test programs for libpthread.a
+#
+# 1.00 93/08/03 proven
+# -Initial cut for pthreads.
+#
+
+CC = ../pgcc -notinstalled
+CPP = @CPP@
+srctop = @srctop@
+srcdir = @srctop@/tests
+VPATH = @srctop@/tests
+CDEBUGFLAGS = @CFLAGS@
+
+INCLUDES= -I../include -I.. -I$(srctop)/include
+CFLAGS = $(CDEBUGFLAGS) $(INCLUDES) $(ADDL_CFLAGS) -DSRCDIR=\"$(srcdir)\"
+LIBS = -lm -lgcc -L../obj/ -lpthread
+#LIBS = -static
+
+# This list used to include test_select, but that test doesn't terminate.
+TESTS = test_create test_pthread_join test_switch test_sleep test_readdir \
+ test_fork test_execve test_preemption test_preemption_float \
+ test_sock_1 test_sock_2 test_stdio_1 test_pthread_mutex \
+ test_pthread_cond_timedwait test_netdb test_pw test_cwd
+# This list used to include p_bench_semaphore, but the semaphore support isn't
+# defined for all targets (or used for any).
+BENCHMARKS = p_bench_read p_bench_mutex p_bench_yield \
+ p_bench_getpid p_bench_pthread_create
+
+all : $(TESTS) $(BENCHMARKS)
+
+check : $(TESTS)
+ set -e ; \
+ for i in $(TESTS) ; do \
+ echo Running test $$i ... ; \
+ ./$$i ; \
+ done
+
+# More flags
+ADDITIONALFLAGS = -DPTHREAD_INITIAL_PORT
+################################################################################
+#
+
+clean:
+ rm -f *.o $(TESTS) $(BENCHMARKS) a.out core maketmp makeout
+
+depend:
+ sed '/\#\#\# Dependencies/q' < Makefile > maketmp
+ (for i in $(CSRC);do $(CPP) -M $$i;done) >> maketmp
+ cp maketmp Makefile
+
+install:
+
+realclean: clean
+ rm -f Makefile
+
+.c.o:
+ $(CC) $(CFLAGS) -c $<
+
+Makefile: Makefile.in
+ (cd .. ; sh config.status)
+
+test_create : test_create.o ../libpthread.a
+ $(CC) $(CFLAGS) -o test_create test_create.o $(LIBS)
+
+test_pthread_join : test_pthread_join.o ../libpthread.a
+ $(CC) $(CFLAGS) -o test_pthread_join test_pthread_join.o $(LIBS)
+
+test_switch : test_switch.o ../libpthread.a
+ $(CC) $(CFLAGS) -o test_switch test_switch.o $(LIBS)
+
+test_sleep : test_sleep.o ../libpthread.a
+ $(CC) $(CFLAGS) -o test_sleep test_sleep.o $(LIBS)
+
+test_readdir : test_readdir.o ../libpthread.a
+ $(CC) $(CFLAGS) -o test_readdir test_readdir.o $(LIBS)
+
+test_fork : test_fork.o ../libpthread.a
+ $(CC) $(CFLAGS) -o test_fork test_fork.o $(LIBS)
+
+test_execve : test_execve.o ../libpthread.a
+ $(CC) $(CFLAGS) -o test_execve test_execve.o $(LIBS)
+
+test_preemption : test_preemption.o ../libpthread.a
+ $(CC) $(CFLAGS) -o test_preemption test_preemption.o $(LIBS)
+
+test_preemption_float : test_preemption_float.o ../libpthread.a
+ $(CC) $(CFLAGS) -o test_preemption_float test_preemption_float.o $(LIBS)
+
+test_stdio_1 : test_stdio_1.o ../libpthread.a
+ $(CC) $(CFLAGS) -o test_stdio_1 test_stdio_1.o $(LIBS)
+
+test_sock_1 : test_sock_1.o ../libpthread.a
+ $(CC) $(CFLAGS) -o test_sock_1 test_sock_1.o $(LIBS)
+
+test_sock_2 : test_sock_2a test_sock_2.o ../libpthread.a
+ $(CC) $(CFLAGS) -o test_sock_2 test_sock_2.o $(LIBS)
+
+test_sock_2a : test_sock_2a.o ../libpthread.a
+ $(CC) $(CFLAGS) -o test_sock_2a test_sock_2a.o $(LIBS)
+
+test_pthread_mutex : test_pthread_mutex.o ../libpthread.a
+ $(CC) $(CFLAGS) -o test_pthread_mutex test_pthread_mutex.o $(LIBS)
+
+test_pthread_cond_timedwait : test_pthread_cond_timedwait.o ../libpthread.a
+ $(CC) $(CFLAGS) -o test_pthread_cond_timedwait test_pthread_cond_timedwait.o $(LIBS)
+
+test_netdb : test_netdb.o ../libpthread.a
+ $(CC) $(CFLAGS) -o test_netdb test_netdb.o $(LIBS)
+
+test_select : test_select.o ../obj/libpthread.a
+ $(CC) $(CFLAGS) -o test_select test_select.o $(LIBS)
+
+test_pw : test_pw.o ../obj/libpthread.a
+ $(CC) $(CFLAGS) -o test_pw test_pw.o $(LIBS)
+
+test_cwd : test_cwd.o ../obj/libpthread.a
+ $(CC) $(CFLAGS) -o test_cwd test_cwd.o $(LIBS)
+
+p_bench_read : p_bench_read.o ../libpthread.a
+ $(CC) $(CFLAGS) -o p_bench_read p_bench_read.o $(LIBS)
+
+p_bench_semaphore : p_bench_semaphore.o ../libpthread.a
+ $(CC) $(CFLAGS) -o p_bench_semaphore p_bench_semaphore.o $(LIBS)
+
+p_bench_mutex : p_bench_mutex.o ../libpthread.a
+ $(CC) $(CFLAGS) -o p_bench_mutex p_bench_mutex.o $(LIBS)
+
+p_bench_yield : p_bench_yield.o ../libpthread.a
+ $(CC) $(CFLAGS) -o p_bench_yield p_bench_yield.o $(LIBS)
+
+p_bench_getpid : p_bench_getpid.o ../libpthread.a
+ $(CC) $(CFLAGS) -o p_bench_getpid p_bench_getpid.o $(LIBS)
+
+p_bench_pthread_create : p_bench_pthread_create.o ../libpthread.a
+ $(CC) $(CFLAGS) -o p_bench_pthread_create p_bench_pthread_create.o $(LIBS)
+
+test_create.o : test_create.c
+test_pthread_join.o : test_pthread_join.c
+test_switch.o : test_switch.c
+test_sleep.o : test_sleep.c
+test_readdir.o : test_readdir.c
+test_fork.o : test_fork.c
+test_execve.o : test_execve.c
+test_preemption.o : test_preemption.c
+test_preemption_float.o : test_preemption_float.c
+test_sock_1.o : test_sock_1.c
+test_sock_2.o : test_sock_2.c
+test_sock_3.o : test_sock_3.c
+test_stdio_1.o : test_stdio_1.c
+test_pthread_mutex.o : test_pthread_mutex.c
+test_pthread_cond_timedwait.o : test_pthread_cond_timedwait.c
+p_bench_read.o : p_bench_read.c
+p_bench_semaphore.o : p_bench_semaphore.c
+p_bench_mutex.o : p_bench_mutex.c
+p_bench_yield.o : p_bench_yield.c
+p_bench_getpid.o : p_bench_getpid.c
+p_bench_pthread_create.o : p_bench_pthread_create.c
+
+################################################################################
+### Do not remove the following line. It is for depend #########################
+### Dependencies:
diff --git a/mit-pthreads/tests/README b/mit-pthreads/tests/README
new file mode 100755
index 00000000000..bb4a3e7ce01
--- /dev/null
+++ b/mit-pthreads/tests/README
@@ -0,0 +1,26 @@
+This directory contains a few test and benchmark programs that I've
+developed to help me test the consistancy of the libpthread.a.
+
+TEST
+----------------------
+test_create Tests the pthread_create() routine. The stack addresses
+ should be very different (ie the upper values of the
+ address should be different) and the arg should be
+ 0xdeadbeaf.
+
+test_switch A nondeterministic test. It should show context switching,
+ by displaying different letters.
+
+test_sleep Timing this test should result in a time of about 20 seconds.
+ It should sleep for 10 seconds and then print ba 10 times
+ at the rate of about once a second.
+
+p_bench_* Benchmarks for various routines.
+
+------------------------------------------------------------------------------
+Copyright (c) 1994 Chris Provenzano. All rights reserved.
+This product includes software developed by the Univeristy of California,
+Berkeley and its contributors.
+
+For further licencing and distribution restrictions see the file COPYRIGHT
+included in the parent directory.
diff --git a/mit-pthreads/tests/bench_fcntl.c b/mit-pthreads/tests/bench_fcntl.c
new file mode 100644
index 00000000000..046046adda4
--- /dev/null
+++ b/mit-pthreads/tests/bench_fcntl.c
@@ -0,0 +1,82 @@
+/* ==== bench_read.c ============================================================
+ * Copyright (c) 1993 by Chris Provenzano, proven@athena.mit.edu
+ *
+ * Description : Benchmark reads of /dev/null. Gives a good aprox. of
+ * syscall times.
+ *
+ * 1.00 93/08/01 proven
+ * -Started coding this file.
+ */
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#define OK 0
+#define NOTOK -1
+/* ==========================================================================
+ * usage();
+ */
+void usage(void)
+{
+ printf("getopt [-d?] [-c count]\n");
+ errno = 0;
+}
+
+main(int argc, char **argv)
+{
+ struct timeval starttime, endtime;
+ int count = 1000000;
+ int debug = 0;
+ int flags;
+ int fd;
+ int i;
+
+ char word[8192];
+
+ /* Getopt variables. */
+ extern int optind, opterr;
+ extern char *optarg;
+
+ while ((word[0] = getopt(argc, argv, "c:d?")) != (char)EOF) {
+ switch (word[0]) {
+ case 'd':
+ debug++;
+ break;
+ case 'c':
+ count = atoi(optarg);
+ break;
+ case '?':
+ usage();
+ return(OK);
+ default:
+ usage();
+ return(NOTOK);
+ }
+ }
+
+ if ((fd = open("/dev/zero", O_RDONLY)) < OK) {
+ printf("Error: open\n");
+ exit(0);
+ }
+
+ if (gettimeofday(&starttime, NULL)) {
+ printf("Error: gettimeofday\n");
+ exit(0);
+ }
+ for (i = 0; i < count; i++) {
+ if ((flags = fcntl(0, F_GETFL)) < 0) {
+ perror("fcntl 1st GETFL");
+ }
+ }
+ if (gettimeofday(&endtime, NULL)) {
+ printf("Error: gettimeofday\n");
+ exit(0);
+ }
+
+ printf("%d fcntls of /dev/null took %d usecs.\n", count,
+ (endtime.tv_sec - starttime.tv_sec) * 1000000 +
+ (endtime.tv_usec - starttime.tv_usec));
+}
diff --git a/mit-pthreads/tests/bench_pipe.c b/mit-pthreads/tests/bench_pipe.c
new file mode 100644
index 00000000000..8555cf37f67
--- /dev/null
+++ b/mit-pthreads/tests/bench_pipe.c
@@ -0,0 +1,115 @@
+/* ==== bench_pipe.c ============================================================
+ * Copyright (c) 1993 by Chris Provenzano, proven@athena.mit.edu
+ *
+ * Description : Benchmark reads of /dev/null. Gives a good aprox. of
+ * syscall times.
+ *
+ * 1.00 93/08/01 proven
+ * -Started coding this file.
+ */
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#define OK 0
+#define NOTOK -1
+
+/* ==========================================================================
+ * usage();
+ */
+void usage(void)
+{
+ printf("bench_pipe [-d?] [-c count]\n");
+ errno = 0;
+}
+
+main(int argc, char **argv)
+{
+ struct timeval starttime, endtime;
+ char buf[1];
+ int count = 1000;
+ int debug = 0;
+ int fd0[2];
+ int fd1[2];
+ int i;
+
+ char word[256];
+
+ /* Getopt variables. */
+ extern int optind, opterr;
+ extern char *optarg;
+
+ while ((word[0] = getopt(argc, argv, "c:d?")) != (char)EOF) {
+ switch (word[0]) {
+ case 'd':
+ debug++;
+ break;
+ case 'c':
+ count = atoi(optarg);
+ break;
+ case '?':
+ usage();
+ return(OK);
+ default:
+ usage();
+ return(NOTOK);
+ }
+ }
+
+ if ((pipe(fd0) < OK) || (pipe(fd1) < OK)) {
+ printf("Error: pipe\n");
+ exit(0);
+ }
+
+ switch (fork()) {
+ case NOTOK:
+ printf("Error: fork\n");
+ exit(0);
+ case OK: /* Child */
+ for (i = 0; i < count; i++) {
+ if (read(fd1[0], buf, 1) < OK) {
+ printf("Error: child read\n");
+ exit(0);
+ }
+ if (write(fd0[1], buf, 1) < OK) {
+ printf("Error: child write\n");
+ exit(0);
+ }
+ }
+ exit(0);
+ break;
+ default:
+ break;
+ }
+
+ if (gettimeofday(&starttime, NULL)) {
+ printf("Error: gettimeofday\n");
+ exit(0);
+ }
+ count --;
+ if (write(fd1[1], buf, 1) < OK) {
+ perror("first parent write");
+ exit(0);
+ }
+ for (i = 0; i < count; i++) {
+ if (read(fd0[0], buf, 1) < OK) {
+ printf("Error: parent read\n");
+ exit(0);
+ }
+ if (write(fd1[1], buf, 1) < OK) {
+ printf("Error: parent write\n");
+ exit(0);
+ }
+ }
+ if (gettimeofday(&endtime, NULL)) {
+ printf("Error: gettimeofday\n");
+ exit(0);
+ }
+
+ printf("%d ping pong tests took %d usecs.\n", count,
+ (endtime.tv_sec - starttime.tv_sec) * 1000000 +
+ (endtime.tv_usec - starttime.tv_usec));
+}
diff --git a/mit-pthreads/tests/bench_read.c b/mit-pthreads/tests/bench_read.c
new file mode 100644
index 00000000000..28c8469e270
--- /dev/null
+++ b/mit-pthreads/tests/bench_read.c
@@ -0,0 +1,88 @@
+/* ==== bench_read.c ============================================================
+ * Copyright (c) 1993 by Chris Provenzano, proven@athena.mit.edu
+ *
+ * Description : Benchmark reads of /dev/null. Gives a good aprox. of
+ * syscall times.
+ *
+ * 1.00 93/08/01 proven
+ * -Started coding this file.
+ */
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#define OK 0
+#define NOTOK -1
+/* ==========================================================================
+ * usage();
+ */
+void usage(void)
+{
+ printf("getopt [-d?] [-c count] [-s size]\n");
+ errno = 0;
+}
+
+main(int argc, char **argv)
+{
+ struct timeval starttime, endtime;
+ int count = 1000000;
+ int debug = 0;
+ int size = 1;
+ int fd;
+ int i;
+
+ char word[8192];
+
+ /* Getopt variables. */
+ extern int optind, opterr;
+ extern char *optarg;
+
+ while ((word[0] = getopt(argc, argv, "s:c:d?")) != (char)EOF) {
+ switch (word[0]) {
+ case 'd':
+ debug++;
+ break;
+ case 'c':
+ count = atoi(optarg);
+ break;
+ case 's':
+ if ((size = atoi(optarg)) > 8192) {
+ size = 8192;
+ }
+ break;
+ case '?':
+ usage();
+ return(OK);
+ default:
+ usage();
+ return(NOTOK);
+ }
+ }
+
+ if ((fd = open("/netbsd", O_RDONLY)) < OK) {
+ printf("Error: open\n");
+ exit(0);
+ }
+
+ if (gettimeofday(&starttime, NULL)) {
+ printf("Error: gettimeofday\n");
+ exit(0);
+ }
+ for (i = 0; i < count; i++) {
+ if (read(fd, word, size) < OK) {
+ printf("Error: read\n");
+ exit(0);
+ }
+ }
+ if (gettimeofday(&endtime, NULL)) {
+ printf("Error: gettimeofday\n");
+ exit(0);
+ }
+
+ printf("%d reads of /netbsd took %d usecs.\n", count,
+ (endtime.tv_sec - starttime.tv_sec) * 1000000 +
+ (endtime.tv_usec - starttime.tv_usec));
+}
diff --git a/mit-pthreads/tests/p_bench_getpid.c b/mit-pthreads/tests/p_bench_getpid.c
new file mode 100644
index 00000000000..d972d075c1d
--- /dev/null
+++ b/mit-pthreads/tests/p_bench_getpid.c
@@ -0,0 +1,78 @@
+/* ==== p_bench_getpid.c =================================================
+ * Copyright (c) 1993 by Chris Provenzano, proven@athena.mit.edu
+ *
+ * Description : Benchmark mutex lock and unlock times
+ *
+ * 1.00 93/11/08 proven
+ * -Started coding this file.
+ */
+
+#include <errno.h>
+#include <pthread.h>
+#include <unistd.h>
+#include <stdio.h>
+
+#define OK 0
+#define NOTOK -1
+
+/* ==========================================================================
+ * usage();
+ */
+void usage(void)
+{
+ printf("p_bench_getpid [-d?] [-c count]\n");
+ errno = 0;
+}
+
+main(int argc, char **argv)
+{
+ struct timeval starttime, endtime;
+ pthread_mutex_t lock;
+ pid_t process_id;
+ int count = 1000000;
+ int debug = 0;
+ int i;
+
+ char word[256];
+
+ /* Getopt variables. */
+ extern int optind, opterr;
+ extern char *optarg;
+
+ pthread_init();
+
+ while ((word[0] = getopt(argc, argv, "c:d?")) != (char)EOF) {
+ switch (word[0]) {
+ case 'd':
+ debug++;
+ break;
+ case 'c':
+ count = atoi(optarg);
+ break;
+ case '?':
+ usage();
+ return(OK);
+ default:
+ usage();
+ return(NOTOK);
+ }
+ }
+
+ if (gettimeofday(&starttime, NULL)) {
+ perror ("gettimeofday");
+ return 1;
+ }
+ for (i = 0; i < count; i++) {
+ process_id = getpid();
+ }
+ if (gettimeofday(&endtime, NULL)) {
+ perror ("gettimeofday");
+ return 1;
+ }
+
+ printf("%d getpid calls took %d usecs.\n", count,
+ (endtime.tv_sec - starttime.tv_sec) * 1000000 +
+ (endtime.tv_usec - starttime.tv_usec));
+
+ return 0;
+}
diff --git a/mit-pthreads/tests/p_bench_mutex.c b/mit-pthreads/tests/p_bench_mutex.c
new file mode 100644
index 00000000000..e3179f08072
--- /dev/null
+++ b/mit-pthreads/tests/p_bench_mutex.c
@@ -0,0 +1,78 @@
+/* ==== p_bench_mutex.c =================================================
+ * Copyright (c) 1993 by Chris Provenzano, proven@athena.mit.edu
+ *
+ * Description : Benchmark mutex lock and unlock times
+ *
+ * 1.00 93/11/08 proven
+ * -Started coding this file.
+ */
+
+#include <errno.h>
+#include <pthread.h>
+#include <stdio.h>
+
+#define OK 0
+#define NOTOK -1
+
+/* ==========================================================================
+ * usage();
+ */
+void usage(void)
+{
+ printf("getopt [-d?] [-c count]\n");
+ errno = 0;
+}
+
+main(int argc, char **argv)
+{
+ struct timeval starttime, endtime;
+ pthread_mutex_t lock;
+ int count = 1000000;
+ int debug = 0;
+ int i;
+
+ char word[256];
+
+ /* Getopt variables. */
+ extern int optind, opterr;
+ extern char *optarg;
+
+ pthread_init();
+
+ while ((word[0] = getopt(argc, argv, "c:d?")) != (char)EOF) {
+ switch (word[0]) {
+ case 'd':
+ debug++;
+ break;
+ case 'c':
+ count = atoi(optarg);
+ break;
+ case '?':
+ usage();
+ return(OK);
+ default:
+ usage();
+ return(NOTOK);
+ }
+ }
+
+ pthread_mutex_init(&lock, NULL);
+ if (gettimeofday(&starttime, NULL)) {
+ perror ("gettimeofday");
+ return 1;
+ }
+ for (i = 0; i < count; i++) {
+ pthread_mutex_lock(&lock);
+ pthread_mutex_unlock(&lock);
+ }
+ if (gettimeofday(&endtime, NULL)) {
+ perror ("gettimeofday");
+ return 1;
+ }
+
+ printf("%d mutex locks/unlocks no contention took %d usecs.\n", count,
+ (endtime.tv_sec - starttime.tv_sec) * 1000000 +
+ (endtime.tv_usec - starttime.tv_usec));
+
+ return 0;
+}
diff --git a/mit-pthreads/tests/p_bench_pthread_create.c b/mit-pthreads/tests/p_bench_pthread_create.c
new file mode 100644
index 00000000000..b31b680c665
--- /dev/null
+++ b/mit-pthreads/tests/p_bench_pthread_create.c
@@ -0,0 +1,92 @@
+/* ==== p_bench_pthread_create.c =============================================
+ * Copyright (c) 1993 by Chris Provenzano, proven@athena.mit.edu
+ *
+ * Description : Benchmark mutex lock and unlock times
+ *
+ * 1.00 93/11/08 proven
+ * -Started coding this file.
+ */
+
+#define PTHREAD_KERNEL
+
+#include <errno.h>
+#include <pthread.h>
+#include <stdio.h>
+
+extern pthread_attr_t pthread_attr_default;
+
+/* ==========================================================================
+ * new_thread();
+ */
+void * new_thread(void * arg)
+{
+ PANIC();
+}
+
+/* ==========================================================================
+ * usage();
+ */
+void usage(void)
+{
+ printf("p_bench_getpid [-d?] [-c count]\n");
+ errno = 0;
+}
+
+main(int argc, char **argv)
+{
+ struct timeval starttime, endtime;
+ pthread_mutex_t lock;
+ pthread_t thread_id;
+ int count = 10000;
+ int debug = 0;
+ int i;
+
+ char word[256];
+
+ /* Getopt variables. */
+ extern int optind, opterr;
+ extern char *optarg;
+
+ pthread_init();
+ /* Shut timer off */
+ machdep_unset_thread_timer(NULL);
+ pthread_attr_default.stackaddr_attr = &word;
+
+ while ((word[0] = getopt(argc, argv, "c:d?")) != (char)EOF) {
+ switch (word[0]) {
+ case 'd':
+ debug++;
+ break;
+ case 'c':
+ count = atoi(optarg);
+ break;
+ case '?':
+ usage();
+ return(OK);
+ default:
+ usage();
+ return(NOTOK);
+ }
+ }
+
+ if (gettimeofday(&starttime, NULL)) {
+ perror ("gettimeofday");
+ return 1;
+ }
+ for (i = 0; i < count; i++) {
+ if (pthread_create(&thread_id, & pthread_attr_default, new_thread, NULL)) {
+ printf("Bad pthread create routine\n");
+ exit(1);
+ }
+ }
+ if (gettimeofday(&endtime, NULL)) {
+ perror ("gettimeofday");
+ return 1;
+ }
+
+ printf("%d getpid calls took %d usecs.\n", count,
+ (endtime.tv_sec - starttime.tv_sec) * 1000000 +
+ (endtime.tv_usec - starttime.tv_usec));
+
+ return 0;
+}
diff --git a/mit-pthreads/tests/p_bench_read.c b/mit-pthreads/tests/p_bench_read.c
new file mode 100644
index 00000000000..52a6aca7706
--- /dev/null
+++ b/mit-pthreads/tests/p_bench_read.c
@@ -0,0 +1,103 @@
+/* ==== p_bench_read.c ============================================================
+ * Copyright (c) 1993 by Chris Provenzano, proven@athena.mit.edu
+ *
+ * Description : Benchmark reads of /dev/null. Gives a good aprox. of
+ * syscall times.
+ *
+ * 1.00 93/08/01 proven
+ * -Started coding this file.
+ */
+
+#include <pthread.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#define OK 0
+#define NOTOK -1
+
+/* ==========================================================================
+ * usage();
+ */
+void usage(void)
+{
+ printf("p_bench_read [-d?] [-c count] [-s size] [-f file]\n");
+ errno = 0;
+}
+
+main(int argc, char **argv)
+{
+ struct timeval starttime, endtime;
+ char *infile = "/dev/null";
+ int count = 1000000;
+ int debug = 0;
+ int size = 1;
+ int fd;
+ int i;
+
+ char word[16384], *word_ptr;
+
+ /* Getopt variables. */
+ extern int optind, opterr;
+ extern char *optarg;
+
+ pthread_init();
+
+ while ((word[0] = getopt(argc, argv, "c:df:s:?")) != (char)EOF) {
+ switch (word[0]) {
+ case 'c':
+ count = atoi(optarg);
+ break;
+ case 'd':
+ debug++;
+ break;
+ case 'f':
+ infile = optarg;
+ break;
+ case 's':
+ if ((size = atoi(optarg)) > 8192) {
+ size = 8192;
+ }
+ break;
+ case '?':
+ usage();
+ return(OK);
+ default:
+ usage();
+ return(NOTOK);
+ }
+ }
+
+ /* Align buffer boundary to a page boundary */
+ word_ptr = (char *)(((size_t) word + 4095) & ~4095);
+
+ if ((fd = open(infile, O_RDONLY)) < OK) {
+ perror ("open");
+ return 1;
+ }
+
+ if (gettimeofday(&starttime, NULL)) {
+ perror ("gettimeofday");
+ return 1;
+ }
+
+ for (i = 0; i < count; i++) {
+ if (read(fd, word_ptr, size) < OK) {
+ printf("Error: read\n");
+ exit(0);
+ }
+ }
+
+ if (gettimeofday(&endtime, NULL)) {
+ perror ("gettimeofday");
+ return 1;
+ }
+
+ printf("%d reads of %s took %d usecs.\n", count, infile,
+ (endtime.tv_sec - starttime.tv_sec) * 1000000 +
+ (endtime.tv_usec - starttime.tv_usec));
+
+ return 0;
+}
diff --git a/mit-pthreads/tests/p_bench_semaphore.c b/mit-pthreads/tests/p_bench_semaphore.c
new file mode 100644
index 00000000000..b3bce340b95
--- /dev/null
+++ b/mit-pthreads/tests/p_bench_semaphore.c
@@ -0,0 +1,82 @@
+/* ==== p_bench_semaphore.c =================================================
+ * Copyright (c) 1993 by Chris Provenzano, proven@athena.mit.edu
+ *
+ * Description : Benchmark semaphore Test and Set/ CLear times
+ *
+ * 1.00 93/11/08 proven
+ * -Started coding this file.
+ */
+
+#include <errno.h>
+#include <pthread.h>
+#include <stdio.h>
+
+#define OK 0
+#define NOTOK -1
+
+/* ==========================================================================
+ * usage();
+ */
+void usage(void)
+{
+ printf("getopt [-d?] [-c count]\n");
+ errno = 0;
+}
+
+main(int argc, char **argv)
+{
+ struct timeval starttime, endtime;
+ semaphore lock = SEMAPHORE_CLEAR;
+ semaphore *lock_addr;
+ int count = 1000000;
+ int debug = 0;
+ int i;
+
+ char word[256];
+
+ /* Getopt variables. */
+ extern int optind, opterr;
+ extern char *optarg;
+
+ pthread_init();
+
+ while ((word[0] = getopt(argc, argv, "c:d?")) != (char)EOF) {
+ switch (word[0]) {
+ case 'd':
+ debug++;
+ break;
+ case 'c':
+ count = atoi(optarg);
+ break;
+ case '?':
+ usage();
+ return(OK);
+ default:
+ usage();
+ return(NOTOK);
+ }
+ }
+
+ lock_addr = &lock;
+ if (gettimeofday(&starttime, NULL)) {
+ perror ("gettimeofday");
+ return 1;
+ }
+ for (i = 0; i < count; i++) {
+ if (SEMAPHORE_TEST_AND_SET(lock_addr)) {
+ printf("Semaphore already locked error\n");
+ return 1;
+ }
+ SEMAPHORE_RESET(lock_addr);
+ }
+ if (gettimeofday(&endtime, NULL)) {
+ perror ("gettimeofday");
+ return 1;
+ }
+
+ printf("%d locks/unlocks of a semaphore took %d usecs.\n", count,
+ (endtime.tv_sec - starttime.tv_sec) * 1000000 +
+ (endtime.tv_usec - starttime.tv_usec));
+
+ return 0;
+}
diff --git a/mit-pthreads/tests/p_bench_yield.c b/mit-pthreads/tests/p_bench_yield.c
new file mode 100644
index 00000000000..bb6d86be09e
--- /dev/null
+++ b/mit-pthreads/tests/p_bench_yield.c
@@ -0,0 +1,123 @@
+/* ==== p_bench_mutex.c =================================================
+ * Copyright (c) 1993-1995 by Chris Provenzano, proven@athena.mit.edu
+ *
+ * Description : Benchmark mutex lock and unlock times
+ *
+ * 1.00 93/11/08 proven
+ * -Started coding this file.
+ */
+
+#include <errno.h>
+#include <pthread.h>
+#include <stdio.h>
+
+#define OK 0
+#define NOTOK -1
+
+/* ==========================================================================
+ * usage();
+ */
+void usage(void)
+{
+ printf("p_bench_yield [-d?] \\\n");
+ printf("\t[-c count] \\\n");
+ printf("\t[-C thread count] \\\n");
+ printf("\t[-O optimization level]\n");
+ errno = 0;
+}
+
+void *yield(void * arg)
+{
+ int i, * count;
+
+ count = (int *)arg;
+ for (i = 0; i < *count; i++) {
+ pthread_yield();
+ }
+ return(NULL);
+}
+
+main(int argc, char **argv)
+{
+ struct timeval starttime, endtime;
+ pthread_mutex_t lock;
+ pthread_attr_t attr;
+ pthread_t thread_id;
+ int thread_count = 1;
+ int optimization = 0;
+ int count = 1000000;
+ int i, debug = 0;
+
+ char word[256];
+
+ /* Getopt variables. */
+ extern int optind, opterr;
+ extern char *optarg;
+
+ pthread_init();
+
+ while ((word[0] = getopt(argc, argv, "C:O:c:d?")) != (char)EOF) {
+ switch (word[0]) {
+ case 'C':
+ thread_count = atoi(optarg);
+ break;
+ case 'O':
+ optimization = atoi(optarg);
+ break;
+ case 'c':
+ count = atoi(optarg);
+ break;
+ case 'd':
+ debug++;
+ break;
+ case '?':
+ usage();
+ return(OK);
+ default:
+ usage();
+ return(NOTOK);
+ }
+ }
+
+ pthread_attr_init(&attr);
+ if (optimization > 0) {
+ pthread_attr_setschedpolicy(&attr, SCHED_FIFO);
+ }
+ if (optimization > 1) {
+ pthread_attr_setfloatstate(&attr, PTHREAD_NOFLOAT);
+ }
+
+ pthread_mutex_init(&lock, NULL);
+ if (gettimeofday(&starttime, NULL)) {
+ perror ("gettimeofday");
+ return 1;
+ }
+ for (i = 1; i < thread_count; i++) {
+ if (pthread_create(&thread_id, &attr, yield, &count)) {
+ perror ("pthread_create");
+ return 1;
+ }
+ if (pthread_detach(thread_id)) {
+ perror ("pthread_detach");
+ return 1;
+ }
+ }
+ if (pthread_create(&thread_id, &attr, yield, &count)) {
+ perror ("pthread_create");
+ return 1;
+ }
+ if (pthread_join(thread_id, NULL)) {
+ perror ("pthread_join");
+ return 1;
+ }
+ if (gettimeofday(&endtime, NULL)) {
+ perror ("gettimeofday");
+ return 1;
+ }
+
+ printf("%d pthread_yields took %d usecs.\n", count,
+ (endtime.tv_sec - starttime.tv_sec) * 1000000 +
+ (endtime.tv_usec - starttime.tv_usec));
+
+ return 0;
+}
diff --git a/mit-pthreads/tests/test_create.c b/mit-pthreads/tests/test_create.c
new file mode 100644
index 00000000000..2d82db07c5f
--- /dev/null
+++ b/mit-pthreads/tests/test_create.c
@@ -0,0 +1,35 @@
+/* ==== test_create.c ============================================================
+ * Copyright (c) 1993 by Chris Provenzano, proven@athena.mit.edu
+ *
+ * Description : Test pthread_create() and pthread_exit() calls.
+ *
+ * 1.00 93/08/03 proven
+ * -Started coding this file.
+ */
+
+#define PTHREAD_KERNEL
+#include <pthread.h>
+#include <stdio.h>
+
+void* new_thread(void* arg)
+{
+ int i;
+
+ printf("New thread was passed arg address %x\n", arg);
+ printf("New thread stack at %x\n", &i);
+ return(NULL);
+ PANIC();
+}
+
+main()
+{
+ pthread_t thread;
+ int i;
+
+ printf("Original thread stack at %x\n", &i);
+ if (pthread_create(&thread, NULL, new_thread, (void *)0xdeadbeef)) {
+ printf("Error: creating new thread\n");
+ }
+ pthread_exit(NULL);
+ PANIC();
+}
diff --git a/mit-pthreads/tests/test_cwd.c b/mit-pthreads/tests/test_cwd.c
new file mode 100644
index 00000000000..979c173d5fc
--- /dev/null
+++ b/mit-pthreads/tests/test_cwd.c
@@ -0,0 +1,11 @@
+#include <stdio.h>
+
+main(int argc, char **argv)
+{
+ char wd[1024], *getcwd(), *getwd();
+
+ pthread_init();
+ printf("getcwd => %s\n", getcwd(wd, 1024));
+ printf("getwd => %s\n", getwd(wd));
+ exit(0);
+}
diff --git a/mit-pthreads/tests/test_execve.c b/mit-pthreads/tests/test_execve.c
new file mode 100644
index 00000000000..f7988457df9
--- /dev/null
+++ b/mit-pthreads/tests/test_execve.c
@@ -0,0 +1,57 @@
+/* ==== test_execve.c ============================================================
+ * Copyright (c) 1994 by Chris Provenzano, proven@athena.mit.edu
+ *
+ * Description : Test execve() and dup2() calls.
+ *
+ * 1.00 94/04/29 proven
+ * -Started coding this file.
+ */
+
+#define PTHREAD_KERNEL
+#include <pthread.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdio.h>
+
+extern char **environ;
+char *argv[] = {
+ "/bin/echo",
+ "This message should be displayed after the execve system call",
+ NULL
+};
+
+char * should_succeed = "This line should be displayed\n";
+char * should_fail = "Error: This line should NOT be displayed\n";
+
+main()
+{
+ pthread_t thread;
+ int fd;
+
+ pthread_init();
+
+ printf("This is the first message\n");
+ if (isatty(1)) {
+ if ((fd = open(ttyname(1), O_RDWR)) < OK) {
+ printf("Error: opening tty\n");
+ exit(1);
+ }
+ } else {
+ printf("Error: stdout not a tty\n");
+ exit(1);
+ }
+
+ printf("This output is necessary to set the stdout fd to NONBLOCKING\n");
+
+ /* do a dup2 */
+ dup2(fd, 1);
+ write(1, should_succeed, (size_t)strlen(should_succeed));
+ machdep_sys_write(1, should_fail, strlen(should_fail));
+
+ if (execve(argv[0], argv, environ) < OK) {
+ printf("Error: execve\n");
+ exit(1);
+ }
+ PANIC();
+}
diff --git a/mit-pthreads/tests/test_fcntl.c b/mit-pthreads/tests/test_fcntl.c
new file mode 100644
index 00000000000..60bc77ce464
--- /dev/null
+++ b/mit-pthreads/tests/test_fcntl.c
@@ -0,0 +1,32 @@
+#include <stdio.h>
+#include <fcntl.h>
+
+main()
+{
+ int flags, child;
+
+ if ((flags = fcntl(0, F_GETFL)) < 0) {
+ perror("fcntl 1st GETFL");
+ }
+ printf ("flags = %x\n", flags);
+
+ switch(child = fork()) {
+ case -1:
+ printf("error during fork\n");
+ break;
+ case 0: /* child */
+ execlp("test_create", "test_create", NULL);
+ break;
+ default: /* parent */
+ wait(NULL);
+ break;
+ }
+
+ while(1){
+ if ((flags = fcntl(0, F_GETFL)) < 0) {
+ perror("fcntl parent GETFL");
+ }
+ printf ("parent %d flags = %x\n", child, flags);
+ sleep(1);
+ }
+}
diff --git a/mit-pthreads/tests/test_fork.c b/mit-pthreads/tests/test_fork.c
new file mode 100644
index 00000000000..4c2125e678a
--- /dev/null
+++ b/mit-pthreads/tests/test_fork.c
@@ -0,0 +1,60 @@
+/* ==== test_fork.c ============================================================
+ * Copyright (c) 1994 by Chris Provenzano, proven@athena.mit.edu
+ *
+ * Description : Test fork() and dup2() calls.
+ *
+ * 1.00 94/04/29 proven
+ * -Started coding this file.
+ */
+
+#define PTHREAD_KERNEL
+#include <pthread.h>
+#include <stdio.h>
+#include <fcntl.h>
+
+main()
+{
+ pthread_t thread;
+ int flags, pid;
+
+ pthread_init();
+
+ if (((flags = machdep_sys_fcntl(1, F_GETFL, NULL)) >= OK) &&
+ (flags & __FD_NONBLOCK | O_NDELAY)) {
+ machdep_sys_fcntl(1, F_SETFL, flags & (~__FD_NONBLOCK | O_NDELAY));
+ }
+ printf("parent process %d\n", getpid());
+
+ switch(pid = fork()) {
+ case OK:
+ exit(OK);
+ break;
+ case NOTOK:
+ printf("fork() FAILED\n");
+ exit(2);
+ break;
+ default:
+ if ((flags = machdep_sys_fcntl(1, F_GETFL, NULL)) >= OK) {
+ if (flags & (__FD_NONBLOCK | O_NDELAY)) {
+ printf("fd flags not set to BLOCKING ERROR\n");
+ printf("test_fork FAILED\n");
+ exit(1);
+ break;
+ }
+ printf("The stdout fd was set to BLOCKING\n");
+ printf("child process %d\n", pid);
+ flags = machdep_sys_fcntl(1, F_GETFL, NULL);
+ if (flags & (__FD_NONBLOCK | O_NDELAY)) {
+ printf("The stdout fd was reset to O_NDELAY\n");
+ } else {
+ printf("Error: the stdout fd was not reset\n");
+ printf("test_fork FAILED\n");
+ exit(1);
+ }
+ }
+ break;
+ }
+
+ printf("test_fork PASSED\n");
+ pthread_exit(NULL);
+}
diff --git a/mit-pthreads/tests/test_netdb.c b/mit-pthreads/tests/test_netdb.c
new file mode 100644
index 00000000000..a944579237f
--- /dev/null
+++ b/mit-pthreads/tests/test_netdb.c
@@ -0,0 +1,110 @@
+/* ==== test_netdb.c =========================================================
+ * Copyright (c) 1995 by Greg Hudson, ghudson@.mit.edu
+ *
+ * Description : Test netdb calls.
+ *
+ * 1.00 95/01/05 ghudson
+ * -Started coding this file.
+ */
+
+#define PTHREAD_KERNEL /* Needed for OK and NOTOK defines */
+#include <pthread.h>
+#include <string.h>
+#include <stdio.h>
+#include <netdb.h>
+#include <errno.h>
+
+int debug = 0;
+
+static int test_serv()
+{
+ struct servent *serv;
+ char answer[1024];
+
+ if (serv = getservbyname("telnet", "tcp"))
+ printf("getservbyname -> port %d\n", ntohs(serv->s_port));
+ else
+ printf("getservbyname -> NULL (bad)\n");
+
+ if (serv = getservbyname_r("telnet", "tcp", serv, answer, 1024))
+ printf("getservbyname_r -> port %d\n", ntohs(serv->s_port));
+ else
+ printf("getservbyname_r -> NULL (bad)\n");
+ return(OK);
+}
+
+static int test_host()
+{
+ struct hostent *host;
+ struct in_addr addr;
+ char answer[1024];
+ int error;
+
+ if (host = gethostbyname("maze.mit.edu")) {
+ memcpy(&addr, host->h_addr, sizeof(addr));
+ printf("gethostbyname -> %s\n", inet_ntoa(addr));
+ } else {
+ printf("gethostbyname -> NULL (bad)\n");
+ host = (struct hostent *)answer;
+ }
+
+ if (host = gethostbyname_r("maze.mit.edu", host, answer, 1024, &error)) {
+ memcpy(&addr, host->h_addr, sizeof(addr));
+ printf("gethostbyname_r -> %s\n", inet_ntoa(addr));
+ } else {
+ printf("gethostbyname_r -> NULL (bad)\n");
+ }
+ return(OK);
+}
+
+static int test_localhost()
+{
+ struct hostent *host;
+
+ if (host = gethostbyname("127.0.0.1")) {
+ return(OK);
+ }
+ return(NOTOK);
+}
+
+/* ==========================================================================
+ * usage();
+ */
+void usage(void)
+{
+ printf("test_netdb [-d?]\n");
+ errno = 0;
+}
+
+main(int argc, char **argv)
+{
+
+ /* Getopt variables. */
+ extern int optind, opterr;
+ extern char *optarg;
+ char ch;
+
+ while ((ch = getopt(argc, argv, "d?")) != (char)EOF) {
+ switch (ch) {
+ case 'd':
+ debug++;
+ break;
+ case '?':
+ usage();
+ return(OK);
+ default:
+ usage();
+ return(NOTOK);
+ }
+ }
+
+ printf("test_netdb START\n");
+
+ if (test_serv() || test_localhost() || test_host()) {
+ printf("test_netdb FAILED\n");
+ exit(1);
+ }
+
+ printf("test_netdb PASSED\n");
+ exit(0);
+}
diff --git a/mit-pthreads/tests/test_pause.c b/mit-pthreads/tests/test_pause.c
new file mode 100644
index 00000000000..46c5080e43e
--- /dev/null
+++ b/mit-pthreads/tests/test_pause.c
@@ -0,0 +1,19 @@
+#include <stdio.h>
+#include <signal.h>
+
+foo(int sig)
+{
+ return;
+}
+
+main()
+{
+ sigset_t all;
+
+ signal (1, foo);
+ sigfillset(&all);
+ sigprocmask(SIG_BLOCK, &all, NULL);
+ printf("Begin pause\n");
+ pause();
+ printf("Done pause\n");
+}
diff --git a/mit-pthreads/tests/test_preemption.c b/mit-pthreads/tests/test_preemption.c
new file mode 100644
index 00000000000..9181c127fe4
--- /dev/null
+++ b/mit-pthreads/tests/test_preemption.c
@@ -0,0 +1,38 @@
+/* ==== test_pthread_cond.c =========================================
+ * Copyright (c) 1993 by Chris Provenzano, proven@athena.mit.edu
+ *
+ * Description : Test pthread_cond(). Run this after test_create()
+ *
+ * 1.23 94/05/04 proven
+ * -Started coding this file.
+ */
+
+#include <pthread.h>
+#include <stdio.h>
+
+void* new_thread(void * new_buf)
+{
+ int i;
+
+ for (i = 0; i < 10; i++) {
+ pthread_yield();
+ }
+ printf("test_preemption PASSED\n");
+ exit(0);
+}
+
+main()
+{
+ pthread_t thread;
+ int error;
+
+ printf("test_preemption START\n");
+
+ if (pthread_create(&thread, NULL, new_thread, NULL)) {
+ printf("pthread_create failed\n");
+ exit(2);
+ }
+
+ while(1);
+ exit(1);
+}
diff --git a/mit-pthreads/tests/test_preemption_float.c b/mit-pthreads/tests/test_preemption_float.c
new file mode 100644
index 00000000000..e12192044c6
--- /dev/null
+++ b/mit-pthreads/tests/test_preemption_float.c
@@ -0,0 +1,98 @@
+/* Test to see if floating point state is being properly maintained
+ for each thread. Different threads doing floating point operations
+ simultaneously should not interfere with one another. This
+ includes operations that might change some FPU flags, such as
+ rounding modes, at least implicitly. */
+
+#include <pthread.h>
+#include <math.h>
+#include <stdio.h>
+
+int limit = 2;
+int float_passed = 0;
+int float_failed = 1;
+
+void *log_loop (void *x) {
+ int i;
+ double d, d1, d2;
+ /* sleep (1); */
+ for (i = 0; i < limit; i++) {
+ d = 42.0;
+ d = log (exp (d));
+ d = (d + 39.0) / d;
+ if (i == 0)
+ d1 = d;
+ else {
+ d2 = d;
+ d = sin(d);
+ /* if (d2 != d1) { */
+ if (memcmp (&d2, &d1, 8)) {
+ pthread_exit(&float_failed);
+ }
+ }
+ }
+ pthread_exit(&float_passed);
+}
+
+void *trig_loop (void *x) {
+ int i;
+ double d, d1, d2;
+ /* sleep (1); */
+ for (i = 0; i < limit; i++) {
+ d = 35.0;
+ d *= M_PI;
+ d /= M_LN2;
+ d = sin (d);
+ d = cos (1 / d);
+ if (i == 0)
+ d1 = d;
+ else {
+ d2 = d;
+ d = sin(d);
+ /* if (d2 != d1) { */
+ if (memcmp (&d2, &d1, 8)) {
+ pthread_exit(&float_failed);
+ }
+ }
+ }
+ pthread_exit(&float_passed);
+}
+
+#define N 10
+int main () {
+ int i;
+ pthread_t thread[2];
+ pthread_attr_t attr;
+ int *x, *y;
+
+ pthread_init ();
+ pthread_attr_init(&attr);
+ pthread_attr_setfloatstate(&attr, PTHREAD_NOFLOAT);
+
+ while(limit < 100000) {
+ pthread_create (&thread[0], &attr, trig_loop, 0);
+ pthread_create (&thread[1], &attr, log_loop, 0);
+ pthread_join(thread[0], (void **) &x);
+ pthread_join(thread[1], (void **) &y);
+ if ((*x == float_failed) || (*y == float_failed)) {
+ limit *= 4;
+ break;
+ }
+ limit *= 4;
+ }
+ if ((*x == float_passed) && (*y == float_passed)) {
+ printf("test_preemption_float INDETERMINATE\n");
+ return(0);
+ }
+ pthread_create (&thread[0], NULL, trig_loop, 0);
+ pthread_create (&thread[1], NULL, log_loop, 0);
+ pthread_join(thread[0], (void **) &x);
+ pthread_join(thread[1], (void **) &y);
+
+ if ((*x == float_failed) || (*y == float_failed)) {
+ printf("test_preemption_float FAILED\n");
+ return(1);
+ }
+ printf("test_preemption_float PASSED\n");
+ return(0);
+}
diff --git a/mit-pthreads/tests/test_pthread_cond_timedwait.c b/mit-pthreads/tests/test_pthread_cond_timedwait.c
new file mode 100644
index 00000000000..fe21408f11e
--- /dev/null
+++ b/mit-pthreads/tests/test_pthread_cond_timedwait.c
@@ -0,0 +1,93 @@
+/* ==== test_pthread_cond.c =========================================
+ * Copyright (c) 1993 by Chris Provenzano, proven@athena.mit.edu
+ *
+ * Description : Test pthread_cond(). Run this after test_create()
+ *
+ * 1.23 94/05/04 proven
+ * -Started coding this file.
+ */
+
+#include <pthread.h>
+#include <stdio.h>
+#include <errno.h>
+
+#ifndef ETIME
+#define ETIME ETIMEDOUT
+#endif
+
+pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
+
+void* thread_1(void * new_buf)
+{
+ pthread_mutex_lock(&mutex);
+ pthread_cond_signal(&cond);
+ pthread_mutex_unlock(&mutex);
+ pthread_exit(NULL);
+}
+
+void* thread_2(void * new_buf)
+{
+ sleep(1);
+ pthread_mutex_lock(&mutex);
+ pthread_cond_signal(&cond);
+ pthread_mutex_unlock(&mutex);
+ pthread_exit(NULL);
+}
+
+main()
+{
+ struct timespec abstime = { 0, 0 };
+ struct timeval curtime;
+ pthread_t thread;
+ int error;
+
+ pthread_init();
+ printf("pthread_cond_timedwait START\n");
+
+ pthread_mutex_lock(&mutex);
+ gettimeofday(&curtime, NULL);
+ abstime.tv_sec = curtime.tv_sec + 5;
+
+ /* Test a condition timeout */
+ if (pthread_cond_timedwait(&cond, &mutex, &abstime) != ETIME) {
+ printf("pthread_cond_timedwait failed to timeout\n");
+ printf("pthread_cond_timedwait FAILED\n");
+ pthread_mutex_unlock(&mutex);
+ exit(1);
+ }
+ printf("Got first timeout ok\n"); /* Added by monty */
+ /* Test a normal condition signal */
+ if (pthread_create(&thread, NULL, thread_1, NULL)) {
+ printf("pthread_create failed\n");
+ exit(2);
+ }
+
+ abstime.tv_sec = curtime.tv_sec + 10;
+ if (pthread_cond_timedwait(&cond, &mutex, &abstime)) {
+ printf("pthread_cond_timedwait #1 timedout\n");
+ printf("pthread_cond_timedwait FAILED\n");
+ pthread_mutex_unlock(&mutex);
+ exit(1);
+ }
+
+ /* Test a normal condition signal after a sleep */
+ if (pthread_create(&thread, NULL, thread_2, NULL)) {
+ printf("pthread_create failed\n");
+ exit(2);
+ }
+
+ pthread_yield();
+
+ abstime.tv_sec = curtime.tv_sec + 10;
+ if (pthread_cond_timedwait(&cond, &mutex, &abstime)) {
+ printf("pthread_cond_timedwait #2 timedout\n");
+ printf("pthread_cond_timedwait FAILED\n");
+ pthread_mutex_unlock(&mutex);
+ exit(1);
+ }
+
+ printf("pthread_cond_timedwait PASSED\n");
+ pthread_mutex_unlock(&mutex);
+ exit(0);
+}
diff --git a/mit-pthreads/tests/test_pthread_join.c b/mit-pthreads/tests/test_pthread_join.c
new file mode 100644
index 00000000000..fd2ec6a78b2
--- /dev/null
+++ b/mit-pthreads/tests/test_pthread_join.c
@@ -0,0 +1,78 @@
+/* ==== test_pthread_join.c =================================================
+ * Copyright (c) 1993 by Chris Provenzano, proven@athena.mit.edu
+ *
+ * Description : Test pthread_join(). Run this after test_create()
+ *
+ * 1.23 94/05/04 proven
+ * -Started coding this file.
+ */
+
+#define PTHREAD_KERNEL
+#include <pthread.h>
+#include <stdio.h>
+
+/* This thread yields so the creator has a live thread to wait on */
+void* new_thread_1(void * new_buf)
+{
+ int i;
+
+ sprintf((char *)new_buf, "New thread %%d stack at %x\n", &i);
+ pthread_yield();
+ return(new_buf);
+ PANIC();
+}
+
+/* This thread doesn't yield so the creator has a dead thread to wait on */
+void* new_thread_2(void * new_buf)
+{
+ int i;
+
+ sprintf((char *)new_buf, "New thread %%d stack at %x\n", &i);
+ return(new_buf);
+ PANIC();
+}
+
+main()
+{
+ char buf[256], *status;
+ pthread_t thread;
+ int debug = 1;
+ int i = 0;
+
+ pthread_init();
+
+ printf("Original thread stack at %x\n", &i);
+ if (pthread_create(&thread, NULL, new_thread_1, (void *)buf) == OK) {
+ if (pthread_join(thread, (void **)(&status)) == OK) {
+ if (debug) { printf(status, ++i); }
+ } else {
+ printf("ERROR: Joining with new thread #1.\n");
+ printf("FAILED: test_pthread_join\n");
+ exit(1);
+ }
+ } else {
+ printf("ERROR: Creating new thread #1\n");
+ printf("FAILED: test_pthread_join\n");
+ exit(2);
+ }
+
+
+ /* Now have the created thread finishing before the join. */
+ if (pthread_create(&thread, NULL, new_thread_2, (void *)buf) == OK){
+ pthread_yield();
+ if (pthread_join(thread, (void **)(&status)) == OK) {
+ if (debug) { printf(status, ++i); }
+ } else {
+ printf("ERROR: Joining with new thread #2.\n");
+ printf("FAILED: test_pthread_join\n");
+ exit(1);
+ }
+ } else {
+ printf("ERROR: Creating new thread #2\n");
+ printf("FAILED: test_pthread_join\n");
+ exit(2);
+ }
+ printf("test_pthread_join PASSED\n");
+ pthread_exit(NULL);
+}
+
diff --git a/mit-pthreads/tests/test_pthread_mutex.c b/mit-pthreads/tests/test_pthread_mutex.c
new file mode 100644
index 00000000000..2fb0574f5cb
--- /dev/null
+++ b/mit-pthreads/tests/test_pthread_mutex.c
@@ -0,0 +1,221 @@
+/* ==== test_pthread_cond.c =========================================
+ * Copyright (c) 1993 by Chris Provenzano, proven@athena.mit.edu
+ *
+ * Description : Test pthread_cond(). Run this after test_create()
+ *
+ * 1.23 94/05/04 proven
+ * -Started coding this file.
+ */
+
+#include <errno.h>
+#include <pthread.h>
+#include <stdio.h>
+
+#define OK 0
+#define NOTOK -1
+
+int contention_variable;
+
+void * thread_contention(void * arg)
+{
+ pthread_mutex_t * mutex = arg;
+
+ if (pthread_mutex_lock(mutex)) {
+ printf("pthread_mutex_lock() ERROR\n");
+ pthread_exit(NULL);
+ }
+
+ if (contention_variable != 1) {
+ printf("contention_variable != 1 ERROR\n");
+ pthread_exit(NULL);
+ }
+ contention_variable = 2;
+
+ if (pthread_mutex_unlock(mutex)) {
+ printf("pthread_mutex_unlock() ERROR\n");
+ pthread_exit(NULL);
+ }
+ pthread_exit(NULL);
+}
+
+int test_contention_lock(pthread_mutex_t * mutex)
+{
+ pthread_t thread;
+
+ printf("test_contention_lock()\n");
+
+ if (pthread_mutex_lock(mutex)) {
+ printf("pthread_mutex_lock() ERROR\n");
+ return(NOTOK);
+ }
+ contention_variable = 0;
+
+ if (pthread_create(&thread, NULL, thread_contention, mutex)) {
+ printf("pthread_create() FAILED\n");
+ exit(2);
+ }
+
+ pthread_yield();
+
+ contention_variable = 1;
+
+ if (pthread_mutex_unlock(mutex)) {
+ printf("pthread_mutex_unlock() ERROR\n");
+ return(NOTOK);
+ }
+
+ if (pthread_mutex_lock(mutex)) {
+ printf("pthread_mutex_lock() ERROR\n");
+ return(NOTOK);
+ }
+
+ if (contention_variable != 2) {
+ printf("contention_variable != 2 ERROR\n");
+ return(NOTOK);
+ }
+
+ if (pthread_mutex_unlock(mutex)) {
+ printf("pthread_mutex_unlock() ERROR\n");
+ return(NOTOK);
+ }
+
+ return(OK);
+}
+
+int test_nocontention_lock(pthread_mutex_t * mutex)
+{
+ printf("test_nocontention_lock()\n");
+ if (pthread_mutex_lock(mutex)) {
+ printf("pthread_mutex_lock() ERROR\n");
+ return(NOTOK);
+ }
+ if (pthread_mutex_unlock(mutex)) {
+ printf("pthread_mutex_unlock() ERROR\n");
+ return(NOTOK);
+ }
+ return(OK);
+}
+
+int test_debug_double_lock(pthread_mutex_t * mutex)
+{
+ printf("test_debug_double_lock()\n");
+ if (pthread_mutex_lock(mutex)) {
+ printf("pthread_mutex_lock() ERROR\n");
+ return(NOTOK);
+ }
+ if (pthread_mutex_lock(mutex) != EDEADLK) {
+ printf("double lock error not detected ERROR\n");
+ return(NOTOK);
+ }
+ if (pthread_mutex_unlock(mutex)) {
+ printf("pthread_mutex_unlock() ERROR\n");
+ return(NOTOK);
+ }
+ return(OK);
+}
+
+int test_debug_double_unlock(pthread_mutex_t * mutex)
+{
+ printf("test_debug_double_unlock()\n");
+ if (pthread_mutex_lock(mutex)) {
+ printf("pthread_mutex_lock() ERROR\n");
+ return(NOTOK);
+ }
+ if (pthread_mutex_unlock(mutex)) {
+ printf("pthread_mutex_unlock() ERROR\n");
+ return(NOTOK);
+ }
+ if (pthread_mutex_unlock(mutex) != EPERM) {
+ printf("double unlock error not detected ERROR\n");
+ return(NOTOK);
+ }
+ return(OK);
+}
+
+int test_nocontention_trylock(pthread_mutex_t * mutex)
+{
+ printf("test_nocontention_trylock()\n");
+ if (pthread_mutex_trylock(mutex)) {
+ printf("pthread_mutex_trylock() ERROR\n");
+ return(NOTOK);
+ }
+ if (pthread_mutex_unlock(mutex)) {
+ printf("pthread_mutex_unlock() ERROR\n");
+ return(NOTOK);
+ }
+ return(OK);
+}
+
+int test_mutex_static(void)
+{
+ pthread_mutex_t mutex_static = PTHREAD_MUTEX_INITIALIZER;
+
+ printf("test_mutex_static()\n");
+ if (test_nocontention_lock(&mutex_static) ||
+ test_contention_lock(&mutex_static)) {
+ return(NOTOK);
+ }
+ return(OK);
+}
+
+int test_mutex_fast(void)
+{
+ pthread_mutex_t mutex_fast;
+
+ printf("test_mutex_fast()\n");
+ if (pthread_mutex_init(&mutex_fast, NULL)) {
+ printf("pthread_mutex_init() ERROR\n");
+ return(NOTOK);
+ }
+ if (test_nocontention_lock(&mutex_fast) ||
+ test_contention_lock(&mutex_fast)) {
+ return(NOTOK);
+ }
+ if (pthread_mutex_destroy(&mutex_fast)) {
+ printf("pthread_mutex_destroy() ERROR\n");
+ return(NOTOK);
+ }
+ return(OK);
+}
+
+int test_mutex_debug()
+{
+ pthread_mutexattr_t mutex_debug_attr;
+ pthread_mutex_t mutex_debug;
+
+ printf("test_mutex_debug()\n");
+ pthread_mutexattr_init(&mutex_debug_attr);
+ pthread_mutexattr_settype(&mutex_debug_attr, PTHREAD_MUTEXTYPE_DEBUG);
+
+ if (pthread_mutex_init(&mutex_debug, &mutex_debug_attr)) {
+ printf("pthread_mutex_init() ERROR\n");
+ return(NOTOK);
+ }
+ if (test_nocontention_lock(&mutex_debug) ||
+ test_contention_lock(&mutex_debug) ||
+ test_debug_double_lock(&mutex_debug) ||
+ test_debug_double_unlock(&mutex_debug)) {
+ return(NOTOK);
+ }
+ if (pthread_mutex_destroy(&mutex_debug)) {
+ printf("pthread_mutex_destroy() ERROR\n");
+ return(NOTOK);
+ }
+ return(OK);
+}
+
+main()
+{
+ pthread_init();
+
+ printf("test_pthread_mutex START\n");
+
+ if (test_mutex_static() || test_mutex_fast() || test_mutex_debug()) {
+ printf("test_pthread_mutex FAILED\n");
+ exit(1);
+ }
+
+ printf("test_pthread_mutex PASSED\n");
+ exit(0);
+}
+
diff --git a/mit-pthreads/tests/test_pw.c b/mit-pthreads/tests/test_pw.c
new file mode 100644
index 00000000000..0ef6d428180
--- /dev/null
+++ b/mit-pthreads/tests/test_pw.c
@@ -0,0 +1,20 @@
+#include <stdio.h>
+#include <sys/types.h>
+#include <pwd.h>
+
+main()
+{
+ struct passwd *pw;
+
+ pthread_init();
+ pw = getpwuid(getuid());
+ if (!pw) {
+ printf("getpwuid(%d) died!\n", getuid());
+ exit(1);
+ }
+ printf("getpwuid(%d) => %lx\n", getuid(), pw);
+ printf(" you are: %s\n uid: %d\n gid: %d\n class: %s\n gecos: %s\n dir: %s\n shell: %s\n",
+ pw->pw_name, pw->pw_uid, pw->pw_gid, pw->pw_class, pw->pw_gecos, pw->pw_dir,
+ pw->pw_shell);
+ exit(0);
+}
diff --git a/mit-pthreads/tests/test_readdir.c b/mit-pthreads/tests/test_readdir.c
new file mode 100644
index 00000000000..6de1841bdbc
--- /dev/null
+++ b/mit-pthreads/tests/test_readdir.c
@@ -0,0 +1,42 @@
+/* ==== test_readdir.c ========================================================
+ * Copyright (c) 1993, 1994 by Chris Provenzano, proven@athena.mit.edu
+ *
+ * Description : Test pthread_create() and pthread_exit() calls.
+ *
+ * 1.00 94/05/19 proven
+ * -Started coding this file.
+ */
+
+#include <pthread.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <stdio.h>
+
+main()
+{
+ struct dirent * file;
+ DIR * dot_dir;
+ int i, found = 0;
+
+ pthread_init();
+
+ if (dot_dir = opendir(".")) {
+ while (file = readdir(dot_dir)) {
+ if (!strcmp("test_readdir", file->d_name)) {
+ found = 1;
+ }
+ }
+ closedir(dot_dir);
+ if (found) {
+ printf("test_readdir PASSED\n");
+ exit(0);
+ } else {
+ printf("Couldn't find file test_readdir ERROR\n");
+ }
+ } else {
+ printf("opendir() ERROR\n");
+ }
+ printf("test_readdir FAILED\n");
+ exit(1);
+}
+
diff --git a/mit-pthreads/tests/test_select.c b/mit-pthreads/tests/test_select.c
new file mode 100644
index 00000000000..0401d77a666
--- /dev/null
+++ b/mit-pthreads/tests/test_select.c
@@ -0,0 +1,115 @@
+#include <pthread.h>
+#include <stdio.h>
+#ifndef ultrix
+#include <sys/fcntl.h>
+#else /* ultrix */
+#include <fcntl.h>
+#endif /* !ultrix */
+#include <sys/types.h>
+#include <sys/time.h>
+#ifdef hpux
+#include <sys/file.h>
+#endif /* hpux */
+#include <errno.h>
+#define NLOOPS 1000
+
+int ntouts = 0;
+
+void *
+bg_routine(void *arg)
+{
+ write(1,"bg routine running\n",19);
+ /*pthread_dump_state();*/
+ while (1) {
+ int n;
+ char dot;
+
+ dot = '.';
+ pthread_yield();
+ write(1,&dot,1);
+ pthread_yield();
+ n = NLOOPS;
+ while (n-- > 0)
+ pthread_yield();
+ }
+}
+
+void *
+fg_routine(void *arg)
+{
+ int flags, stat, nonblock_flag;
+ static struct timeval tout = { 0, 500000 };
+
+#if 0
+#if defined(hpux) || defined(__alpha)
+ nonblock_flag = O_NONBLOCK;
+#else
+ nonblock_flag = FNDELAY;
+#endif
+ printf("fg_routine running\n");
+ flags = fcntl(0, F_GETFL, 0);
+ printf("stdin flags b4 anything = %x\n", flags);
+ stat = fcntl(0, F_SETFL, flags | nonblock_flag);
+ if (stat < 0) {
+ printf("fcntl(%x) => %d\n", nonblock_flag, errno);
+ printf("could not set nonblocking i/o on stdin [oldf %x, stat %d]\n",
+ flags, stat);
+ exit(1);
+ }
+ printf("stdin flags = 0x%x after turning on %x\n", flags, nonblock_flag);
+#endif
+ while (1) {
+ int n;
+ fd_set r;
+
+ FD_ZERO(&r);
+ FD_SET(0,&r);
+ printf("select>");
+ n = select(1, &r, (fd_set*)0, (fd_set*)0, (struct timeval *)0);
+ if (n < 0) {
+ perror ("select");
+ exit(1);
+ } else if (n > 0) {
+ int nb;
+ char buf[128];
+
+ printf("=> select returned: %d\n", n);
+ while ((nb = read(0, buf, sizeof(buf)-1)) >= 0) {
+ buf[nb] = '\0';
+ printf("read %d: |%s|\n", nb, buf);
+ }
+ printf("=> out of read loop: %d / %d\n", nb, errno);
+ if (nb < 0) {
+ if (errno != EWOULDBLOCK && errno != EAGAIN) {
+ perror ("read");
+ exit(1);
+ }
+ }
+ } else
+ ntouts++;
+ }
+}
+
+main(int argc, char **argv)
+{
+ pthread_t bg_thread, fg_thread;
+ int junk;
+
+ pthread_init();
+ setbuf(stdout,NULL);
+ setbuf(stderr,NULL);
+ if (argc > 1) {
+ if (pthread_create(&bg_thread, NULL, bg_routine, 0) < 0) {
+ printf("error: could not create bg thread\n");
+ exit(1);
+ }
+ }
+ if (pthread_create(&fg_thread, NULL, fg_routine, 0) < 0) {
+ printf("error: could not create fg thread\n");
+ exit(1);
+ }
+ printf("threads forked: bg=%lx fg=%lx\n", bg_thread, fg_thread);
+ /*pthread_dump_state();*/
+ printf("initial thread %lx joining fg...\n", pthread_self());
+ pthread_join(fg_thread, (void **)&junk);
+}
diff --git a/mit-pthreads/tests/test_setjmp.c b/mit-pthreads/tests/test_setjmp.c
new file mode 100644
index 00000000000..ea24ecd63bc
--- /dev/null
+++ b/mit-pthreads/tests/test_setjmp.c
@@ -0,0 +1,13 @@
+#include <setjmp.h>
+
+main()
+{
+jmp_buf foo;
+
+if (setjmp(foo)) {
+ exit(0);
+}
+printf("Hi mom\n");
+longjmp(foo, 1);
+printf("Should never reach here\n");
+}
diff --git a/mit-pthreads/tests/test_sleep.c b/mit-pthreads/tests/test_sleep.c
new file mode 100644
index 00000000000..f228d08a2ca
--- /dev/null
+++ b/mit-pthreads/tests/test_sleep.c
@@ -0,0 +1,46 @@
+/* ==== test_switch.c ============================================================
+ * Copyright (c) 1993 by Chris Provenzano, proven@athena.mit.edu
+ *
+ * Description : Test context switch functionality.
+ *
+ * 1.00 93/08/04 proven
+ * -Started coding this file.
+ */
+
+#include <pthread.h>
+#include <stdio.h>
+
+const char buf[] = "abcdefghijklimnopqrstuvwxyz";
+int fd = 1;
+
+void* new_thread(void* arg)
+{
+ int i;
+
+ for (i = 0; i < 10; i++) {
+ write(fd, buf + (long) arg, 1);
+ sleep(1);
+ }
+}
+
+main()
+{
+ pthread_t thread;
+ int count = 2;
+ long i;
+
+ pthread_init();
+
+ printf("Going to sleep\n");
+ sleep(10);
+ printf("Done sleeping\n");
+
+ for(i = 0; i < count; i++) {
+ if (pthread_create(&thread, NULL, new_thread, (void *) i)) {
+ printf("error creating new thread %d\n", i);
+ }
+ }
+ pthread_exit(NULL);
+ fprintf(stderr, "pthread_exit returned\n");
+ exit(1);
+}
diff --git a/mit-pthreads/tests/test_sock_1.c b/mit-pthreads/tests/test_sock_1.c
new file mode 100644
index 00000000000..e23755a67dc
--- /dev/null
+++ b/mit-pthreads/tests/test_sock_1.c
@@ -0,0 +1,204 @@
+/* ==== test_sock_1.c =========================================================
+ * Copyright (c) 1993 by Chris Provenzano, proven@athena.mit.edu
+ *
+ * Description : Test pthread_create() and pthread_exit() calls.
+ *
+ * 1.00 93/08/03 proven
+ * -Started coding this file.
+ */
+
+#include <pthread.h>
+#include <errno.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+struct sockaddr_in a_sout;
+pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+pthread_attr_t attr;
+
+#define MESSAGE5 "This should be message #5"
+#define MESSAGE6 "This should be message #6"
+
+void * sock_connect(void* arg)
+{
+ char buf[1024];
+ int fd, tmp;
+
+ /* Ensure sock_read runs first */
+ if (pthread_mutex_lock(&mutex)) {
+ printf("Error: sock_connect:pthread_mutex_lock()\n");
+ exit(1);
+ }
+
+ a_sout.sin_addr.s_addr = htonl(0x7f000001); /* loopback */
+
+ if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+ printf("Error: sock_connect:socket()\n");
+ exit(1);
+ }
+
+ printf("This should be message #2\n");
+ if (connect(fd, (struct sockaddr *) &a_sout, sizeof(a_sout)) < 0) {
+ printf("Error: sock_connect:connect()\n");
+ exit(1);
+ }
+ close(fd);
+
+ if (pthread_mutex_unlock(&mutex)) {
+ printf("Error: sock_connect:pthread_mutex_lock()\n");
+ exit(1);
+ }
+
+ if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+ printf("Error: sock_connect:socket()\n");
+ exit(1);
+ }
+
+ printf("This should be message #3\n");
+
+ if (connect(fd, (struct sockaddr *) &a_sout, sizeof(a_sout)) < 0) {
+ printf("Error: sock_connect:connect()\n");
+ exit(1);
+ }
+
+ /* Ensure sock_read runs again */
+ pthread_yield();
+ pthread_yield();
+ pthread_yield();
+ pthread_yield();
+ if (pthread_mutex_lock(&mutex)) {
+ printf("Error: sock_connect:pthread_mutex_lock()\n");
+ exit(1);
+ }
+
+ if ((tmp = read(fd, buf, 1024)) <= 0) {
+ printf("Error: sock_connect:read() == %d\n", tmp);
+ exit(1);
+ }
+ write(fd, MESSAGE6, sizeof(MESSAGE6));
+ printf("%s\n", buf);
+ close(fd);
+}
+
+extern struct fd_table_entry ** fd_table;
+void * sock_write(void* arg)
+{
+ int fd = *(int *)arg;
+
+ write(fd, MESSAGE5, sizeof(MESSAGE5));
+ return(NULL);
+}
+
+void * sock_accept(void* arg)
+{
+ pthread_t thread;
+ struct sockaddr a_sin;
+ int a_sin_size, a_fd, fd, tmp;
+ short port;
+ char buf[1024];
+
+ if (pthread_mutex_unlock(&mutex)) {
+ printf("Error: sock_accept:pthread_mutex_lock()\n");
+ exit(1);
+ }
+
+ port = 3276;
+ a_sout.sin_family = AF_INET;
+ a_sout.sin_port = htons(port);
+ a_sout.sin_addr.s_addr = INADDR_ANY;
+
+ if ((a_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+ printf("Error: sock_accept:socket()\n");
+ exit(1);
+ }
+
+ while (bind(a_fd, (struct sockaddr *) &a_sout, sizeof(a_sout)) < 0) {
+ if (errno == EADDRINUSE) {
+ a_sout.sin_port = htons((++port));
+ continue;
+ }
+ printf("Error: sock_accept:bind()\n");
+ exit(1);
+ }
+
+ if (listen(a_fd, 2)) {
+ printf("Error: sock_accept:listen()\n");
+ exit(1);
+ }
+
+ a_sin_size = sizeof(a_sin);
+ printf("This should be message #1\n");
+ if ((fd = accept(a_fd, &a_sin, &a_sin_size)) < 0) {
+ printf("Error: sock_accept:accept()\n");
+ exit(1);
+ }
+
+ if (pthread_mutex_lock(&mutex)) {
+ printf("Error: sock_accept:pthread_mutex_lock()\n");
+ exit(1);
+ }
+ close(fd);
+
+ a_sin_size = sizeof(a_sin);
+ printf("This should be message #4\n");
+ if ((fd = accept(a_fd, &a_sin, &a_sin_size)) < 0) {
+ printf("Error: sock_accept:accept()\n");
+ exit(1);
+ }
+
+ if (pthread_mutex_unlock(&mutex)) {
+ printf("Error: sock_accept:pthread_mutex_lock()\n");
+ exit(1);
+ }
+
+ /* Setup a write thread */
+ if (pthread_create(&thread, &attr, sock_write, &fd)) {
+ printf("Error: sock_accept:pthread_create(sock_write)\n");
+ exit(1);
+ }
+ if ((tmp = read(fd, buf, 1024)) <= 0) {
+ printf("Error: sock_accept:read() == %d\n", tmp);
+ exit(1);
+ }
+ printf("%s\n", buf);
+ close(fd);
+}
+
+main()
+{
+ pthread_t thread;
+ int i;
+
+ pthread_init();
+ setbuf(stdout, NULL);
+ setbuf(stderr, NULL);
+
+ /* Ensure sock_read runs first */
+ if (pthread_mutex_lock(&mutex)) {
+ printf("Error: main:pthread_mutex_lock()\n");
+ exit(1);
+ }
+
+ if (pthread_attr_init(&attr)) {
+ printf("Error: main:pthread_attr_init()\n");
+ exit(1);
+ }
+ if (pthread_attr_setschedpolicy(&attr, SCHED_FIFO)) {
+ printf("Error: main:pthread_attr_setschedpolicy()\n");
+ exit(1);
+ }
+ if (pthread_create(&thread, &attr, sock_accept, (void *)0xdeadbeaf)) {
+ printf("Error: main:pthread_create(sock_accept)\n");
+ exit(1);
+ }
+ if (pthread_create(&thread, &attr, sock_connect, (void *)0xdeadbeaf)) {
+ printf("Error: main:pthread_create(sock_connect)\n");
+ exit(1);
+ }
+ printf("initial thread %lx going to sleep\n", pthread_self());
+ sleep(10);
+ printf("done sleeping\n");
+ return 0;
+}
diff --git a/mit-pthreads/tests/test_sock_2.c b/mit-pthreads/tests/test_sock_2.c
new file mode 100644
index 00000000000..5ec82fd7499
--- /dev/null
+++ b/mit-pthreads/tests/test_sock_2.c
@@ -0,0 +1,116 @@
+/* ==== test_sock_1.c =========================================================
+ * Copyright (c) 1993 by Chris Provenzano, proven@athena.mit.edu
+ *
+ * Description : Test pthread_create() and pthread_exit() calls.
+ *
+ * 1.00 93/08/03 proven
+ * -Started coding this file.
+ */
+
+#include <pthread.h>
+#include <errno.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+struct sockaddr_in a_sout;
+
+#define MESSAGE5 "This should be message #5"
+#define MESSAGE6 "This should be message #6"
+
+void * sock_write(void* arg)
+{
+ int fd = *(int *)arg;
+
+ write(fd, MESSAGE5, sizeof(MESSAGE5));
+ return(NULL);
+}
+
+void * sock_accept(void* arg)
+{
+ pthread_t thread;
+ struct sockaddr a_sin;
+ int a_sin_size, a_fd, fd, tmp;
+ short port;
+ char buf[1024];
+
+ port = 3276;
+ a_sout.sin_family = AF_INET;
+ a_sout.sin_port = htons(port);
+ a_sout.sin_addr.s_addr = INADDR_ANY;
+
+ if ((a_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+ printf("Error: sock_accept:socket()\n");
+ exit(1);
+ }
+
+ while (bind(a_fd, (struct sockaddr *) &a_sout, sizeof(a_sout)) < 0) {
+ if (errno == EADDRINUSE) {
+ a_sout.sin_port = htons((++port));
+ continue;
+ }
+ printf("Error: sock_accept:bind()\n");
+ exit(1);
+ }
+
+ if (listen(a_fd, 2)) {
+ printf("Error: sock_accept:listen()\n");
+ exit(1);
+ }
+
+ a_sin_size = sizeof(a_sin);
+ printf("This should be message #1\n");
+ if ((fd = accept(a_fd, &a_sin, &a_sin_size)) < 0) {
+ printf("Error: sock_accept:accept()\n");
+ exit(1);
+ }
+ close(fd);
+ sleep(1);
+
+ a_sin_size = sizeof(a_sin);
+ memset(&a_sin, 0, sizeof(a_sin));
+ printf("This should be message #4\n");
+ if ((fd = accept(a_fd, &a_sin, &a_sin_size)) < 0) {
+ printf("Error: sock_accept:accept()\n");
+ exit(1);
+ }
+
+ /* Setup a write thread */
+ if (pthread_create(&thread, NULL, sock_write, &fd)) {
+ printf("Error: sock_accept:pthread_create(sock_write)\n");
+ exit(1);
+ }
+ if ((tmp = read(fd, buf, 1024)) <= 0) {
+ tmp = read(fd, buf, 1024);
+ printf("Error: sock_accept:read() == %d\n", tmp);
+ exit(1);
+ }
+ printf("%s\n", buf);
+ close(fd);
+}
+
+main()
+{
+ pthread_t thread;
+ int i;
+
+ switch(fork()) {
+ case -1:
+ printf("Error: main:fork()\n");
+ break;
+ case 0:
+ execl("test_sock_2a", "test_sock_2a", "fork okay", NULL);
+ default:
+ break;
+ }
+
+ setbuf(stdout, NULL);
+ setbuf(stderr, NULL);
+
+ if (pthread_create(&thread, NULL, sock_accept, (void *)0xdeadbeaf)) {
+ printf("Error: main:pthread_create(sock_accept)\n");
+ exit(1);
+ }
+ pthread_exit(NULL);
+}
diff --git a/mit-pthreads/tests/test_sock_2a.c b/mit-pthreads/tests/test_sock_2a.c
new file mode 100644
index 00000000000..9f767b7c675
--- /dev/null
+++ b/mit-pthreads/tests/test_sock_2a.c
@@ -0,0 +1,87 @@
+/* ==== test_sock_1.c =========================================================
+ * Copyright (c) 1993 by Chris Provenzano, proven@athena.mit.edu
+ *
+ * Description : Test pthread_create() and pthread_exit() calls.
+ *
+ * 1.00 93/08/03 proven
+ * -Started coding this file.
+ */
+
+#include <pthread.h>
+#include <errno.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+struct sockaddr_in a_sout;
+
+#define MESSAGE5 "This should be message #5"
+#define MESSAGE6 "This should be message #6"
+
+void * sock_connect(void* arg)
+{
+ char buf[1024];
+ int fd, tmp;
+ short port;
+
+ port = 3276;
+ a_sout.sin_family = AF_INET;
+ a_sout.sin_port = htons(port);
+ a_sout.sin_addr.s_addr = htonl(0x7f000001); /* loopback */
+
+ if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+ printf("Error: sock_connect:socket()\n");
+ exit(1);
+ }
+
+ printf("This should be message #2\n");
+ if (connect(fd, (struct sockaddr *) &a_sout, sizeof(a_sout)) < 0) {
+ printf("Error: sock_connect:connect()\n");
+ exit(1);
+ }
+ close(fd);
+
+ if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+ printf("Error: sock_connect:socket()\n");
+ exit(1);
+ }
+
+ printf("This should be message #3\n");
+
+ if (connect(fd, (struct sockaddr *) &a_sout, sizeof(a_sout)) < 0) {
+ printf("Error: sock_connect:connect()\n");
+ exit(1);
+ }
+
+ /* Ensure sock_read runs again */
+
+ if ((tmp = read(fd, buf, 1024)) <= 0) {
+ printf("Error: sock_connect:read() == %d\n", tmp);
+ exit(1);
+ }
+ write(fd, MESSAGE6, sizeof(MESSAGE6));
+ printf("%s\n", buf);
+ close(fd);
+}
+
+main(int argc, char **argv)
+{
+ pthread_t thread;
+ int i;
+
+ if (argv[1] && (!strcmp(argv[1], "fork okay"))) {
+ sleep(1);
+ setbuf(stdout, NULL);
+ setbuf(stderr, NULL);
+
+ if (pthread_create(&thread, NULL, sock_connect, (void *)0xdeadbeaf)) {
+ printf("Error: main:pthread_create(sock_connect)\n");
+ exit(1);
+ }
+ pthread_exit(NULL);
+ }
+ printf("test_sock_2a needs to be execed from test_sock_2.\n");
+ printf("It is not a stand alone test.\n");
+ exit(1);
+}
diff --git a/mit-pthreads/tests/test_stdio_1.c b/mit-pthreads/tests/test_stdio_1.c
new file mode 100644
index 00000000000..648343a2c9d
--- /dev/null
+++ b/mit-pthreads/tests/test_stdio_1.c
@@ -0,0 +1,124 @@
+#include <pthread.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+char * base_name = "test_stdio_1.c";
+char * dir_name = SRCDIR;
+char * fullname;
+
+#define OK 0
+#define NOTOK -1
+
+/* Test fopen()/ftell()/getc() */
+int test_1(void)
+{
+ struct stat statbuf;
+ FILE * fp;
+ int i;
+
+ if (stat(fullname, &statbuf) < OK) {
+ printf("ERROR: Couldn't stat %s\n", fullname);
+ return(NOTOK);
+ }
+
+ if ((fp = fopen(fullname, "r")) == NULL) {
+ printf("ERROR: Couldn't open %s\n", fullname);
+ return(NOTOK);
+ }
+
+ /* Get the entire file */
+ while ((i = getc(fp)) != EOF);
+
+ if (ftell(fp) != statbuf.st_size) {
+ printf("ERROR: ftell() and stat() don't agree.");
+ return(NOTOK);
+ }
+
+ if (fclose(fp) < OK) {
+ printf("ERROR: fclose() failed.");
+ return(NOTOK);
+ }
+ return(OK);
+}
+
+/* Test fopen()/fclose() */
+int test_2(void)
+{
+ FILE *fp1, *fp2;
+
+ if ((fp1 = fopen(fullname, "r")) == NULL) {
+ printf("ERROR: Couldn't fopen %s\n", fullname);
+ return(NOTOK);
+ }
+
+ if (fclose(fp1) < OK) {
+ printf("ERROR: fclose() failed.");
+ return(NOTOK);
+ }
+
+ if ((fp2 = fopen(fullname, "r")) == NULL) {
+ printf("ERROR: Couldn't fopen %s\n", fullname);
+ return(NOTOK);
+ }
+
+ if (fclose(fp2) < OK) {
+ printf("ERROR: fclose() failed.");
+ return(NOTOK);
+ }
+
+ if (fp1 != fp2) {
+ printf("ERROR: FILE table leak.\n");
+ return(NOTOK);
+ }
+
+ return(OK);
+}
+
+/* Test sscanf()/sprintf() */
+int test_3(void)
+{
+ char * str = "10 4.53";
+ char buf[64];
+ double d;
+ int i;
+
+ if (sscanf(str, "%d %lf", &i, &d) != 2) {
+ printf("ERROR: sscanf didn't parse input string correctly\n");
+ return(NOTOK);
+ }
+
+ /* Should have a check */
+ sprintf(buf, "%d %2.2lf", i, d);
+
+ if (strcmp(buf, str)) {
+ printf("ERROR: sscanf()/sprintf() didn't parse unparse correctly\n");
+ return(NOTOK);
+ }
+ return(OK);
+}
+
+main()
+{
+
+ printf("test_stdio_1 START\n");
+
+ if (fullname = malloc (strlen (dir_name) + strlen (base_name) + 2)) {
+ sprintf (fullname, "%s/%s", dir_name, base_name);
+ } else {
+ perror ("malloc");
+ exit(1);
+ }
+
+ if (test_1() || test_2() || test_3()) {
+ printf("test_stdio_1 FAILED\n");
+ exit(1);
+ }
+
+ printf("test_stdio_1 PASSED\n");
+ exit(0);
+}
+
+
diff --git a/mit-pthreads/tests/test_switch.c b/mit-pthreads/tests/test_switch.c
new file mode 100644
index 00000000000..4c184158fb8
--- /dev/null
+++ b/mit-pthreads/tests/test_switch.c
@@ -0,0 +1,97 @@
+/* ==== test_switch.c ============================================================
+ * Copyright (c) 1993 by Chris Provenzano, proven@athena.mit.edu
+ *
+ * Description : Test context switch functionality.
+ *
+ * 1.00 93/08/04 proven
+ * -Started coding this file.
+ */
+
+#include <pthread.h>
+#include <stdio.h>
+#include <errno.h>
+
+#define OK 0
+#define NOTOK -1
+
+const char buf[] = "abcdefghijklmnopqrstuvwxyz";
+char x[sizeof(buf)];
+int fd = 1;
+
+/* ==========================================================================
+ * usage();
+ */
+void usage(void)
+{
+ printf("test_switch [-d?] [-c count]\n");
+ printf("count must be between 2 and 26\n");
+ errno = 0;
+}
+
+void* new_thread(void* arg)
+{
+ while(1) {
+ write (fd, (char *) arg, 1);
+ x[(char *)arg - buf] = 1;
+ }
+ fprintf(stderr, "Compiler error\n");
+ exit(1);
+}
+
+main(int argc, char **argv)
+{
+ pthread_t thread;
+ int count = 2;
+ int debug = 0;
+ int eof = 0;
+ long i;
+
+ /* Getopt variables. */
+ extern int optind, opterr;
+ extern char *optarg;
+
+ while (!eof)
+ switch (getopt (argc, argv, "c:d?"))
+ {
+ case EOF:
+ eof = 1;
+ break;
+ case 'd':
+ debug++;
+ break;
+ case 'c':
+ count = atoi(optarg);
+ if ((count > 26) || (count < 2)) {
+ count = 2;
+ }
+ break;
+ case '?':
+ usage();
+ return(OK);
+ default:
+ usage();
+ return(NOTOK);
+ }
+
+ for (i = 0; i < count; i++) {
+ if (pthread_create(&thread, NULL, new_thread, (void*)(buf+i))) {
+ fprintf (stderr, "error creating new thread %d\n", i);
+ exit (1);
+ }
+ }
+#if 0 /* This would cause the program to loop forever, and "make
+ check" would never complete. */
+ pthread_exit (NULL);
+ fprintf(stderr, "pthread_exit returned\n");
+ exit(1);
+#else
+ sleep (10);
+ for (i = 0; i < count; i++)
+ if (x[i] == 0) {
+ fprintf (stderr, "thread %d never ran\n", i);
+ return 1;
+ }
+ printf ("\n%s PASSED\n", argv[0]);
+ return 0;
+#endif
+}
diff --git a/mkinstalldirs b/mkinstalldirs
new file mode 100755
index 00000000000..f945dbf2bce
--- /dev/null
+++ b/mkinstalldirs
@@ -0,0 +1,38 @@
+#! /bin/sh
+# mkinstalldirs --- make directory hierarchy
+# Author: Noah Friedman <friedman@prep.ai.mit.edu>
+# Created: 1993-05-16
+# Public domain
+
+errstatus=0
+
+for file
+do
+ set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'`
+ shift
+
+ pathcomp=
+ for d
+ do
+ pathcomp="$pathcomp$d"
+ case "$pathcomp" in
+ -* ) pathcomp=./$pathcomp ;;
+ esac
+
+ if test ! -d "$pathcomp"; then
+ echo "mkdir $pathcomp" 1>&2
+
+ mkdir "$pathcomp" || lasterr=$?
+
+ if test ! -d "$pathcomp"; then
+ errstatus=$lasterr
+ fi
+ fi
+
+ pathcomp="$pathcomp/"
+ done
+done
+
+exit $errstatus
+
+# mkinstalldirs ends here
diff --git a/myisam/.cvsignore b/myisam/.cvsignore
new file mode 100644
index 00000000000..d9adcedd308
--- /dev/null
+++ b/myisam/.cvsignore
@@ -0,0 +1,12 @@
+.deps
+.libs
+Makefile
+Makefile.in
+ft_eval
+ft_test1
+mi_test1
+mi_test2
+mi_test3
+myisamchk
+myisamlog
+myisampack
diff --git a/myisam/Attic/ft_global.h b/myisam/Attic/ft_global.h
new file mode 100644
index 00000000000..c8d0734fed3
--- /dev/null
+++ b/myisam/Attic/ft_global.h
@@ -0,0 +1,52 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 */
+
+/* some definitions for full-text indices */
+
+/* #include "myisam.h" */
+
+#ifndef _ft_global_h
+#define _ft_global_h
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define FT_QUERY_MAXLEN 1024
+
+typedef struct ft_doc_rec {
+ my_off_t dpos;
+ double weight;
+} FT_DOC;
+
+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;
+
+int ft_init_stopwords(const char **);
+
+FT_DOCLIST * ft_init_search(MI_INFO *, uint, byte *, uint, bool);
+double ft_read_next(FT_DOCLIST *, char *);
+#define ft_close_search(handler) my_free(((gptr)(handler)),MYF(0))
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/myisam/ChangeLog b/myisam/ChangeLog
new file mode 100644
index 00000000000..a2cd00a8c50
--- /dev/null
+++ b/myisam/ChangeLog
@@ -0,0 +1,137 @@
+2000-07-02 Michael Widenius <monty@mysql.com>
+
+* Added safety margin to guard against full index file.
+
+2000-05-22 Michael Widenius <monty@mysql.com>
+
+* Fixed that --join works with myisampack.
+
+2000-05-14 Michael Widenius <monty@mysql.com>
+
+* Don't lock datafile during myisamchk (only indexfile is locked; This is good
+ enough for all MyISAM functions); This made it possible to close datafile
+ in rep_by_sort().
+
+2000-05-04 Michael Widenius <monty@mysql.com>
+
+* Fixed bug in code that scanned after rows in a crashed table.
+ This could cause an infinite loop when repairing tables.
+
+2000-04-26 Michael Widenius <monty@mysql.com>
+
+* Fixed bug when doing read_next after a delete/insert which balanced key
+ pages (In this case one internal buffer was wrongly reused)
+
+2000-04-21 Michael Widenius <monty@tik.pp.sci.fi>
+
+* Changed mi_find_halfpos() to return key, key_length and pos after key.
+* Don't join or split key buffers in the middle when inserting a key
+ that is bigger than all other keys; This will improve inserts when
+ doing these in sorted order.
+
+2000-04-04 Michael Widenius <monty@mysql.com>
+
+* Added support for different languages on key part level.
+
+2000-02-23 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Fixed that myisamchk works properly with RAID.
+
+2000-02-07 Michael Widenius <monty@tik.pp.sci.fi>
+
+* Added delete and rename of tables (works with RAID tables)
+
+2000-01-29 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Fixed the sorting of index works with prefix-packed keys.
+
+1999-11-24 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Fixed that DECIMAL() keys are sorted correct for negative numbers.
+
+1999-11-22 Michael Widenius <monty@monty.pp.sci.fi>
+
+* removed 'NO_LOCKING' macros.
+* Added function mi_rnext_same
+* Added support for concurrent reads.
+
+1999-11-05 Michael Widenius <monty@tik.pp.sci.fi>
+
+* Added function mi_scan().
+* Changed all functions to return error number in case of errors.
+
+1999-08-17 Michael Widenius <monty@tik.pp.sci.fi>
+
+* Added option DELAY_KEY_WRITE to tables and mi_open()
+
+1999-08-10 Michael Widenius <monty@tik.pp.sci.fi>
+
+* Added support of HA_READ_PREFIX_LAST to mi_rkey(). This finds the last
+ row with the given prefix.
+
+Mon Aug 2 13:54:35 1999 Michael Widenius <monty@bitch.pp.sci.fi>
+
+* Added data- and key-file-length to myisamchk.
+* Fixed some problems with null and space packed keys.
+
+1999-07-15 Michael Widenius <monty@tik.pp.sci.fi>
+
+* The following options are for COUNT(DISTINCT ..)
+* Added option HA_EXTRA_NO_ROWS; In this case only the index tree is updated
+* Added mi_delete_all_rows()
+
+1999-07-13 Michael Widenius <monty@tik.pp.sci.fi>
+
+* Added special handling of tempoary tables
+
+1999-06-12 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Added optional checksum for file and for each dynamic-length row
+* Added unique constraint checking
+
+1999-05-06 Michael Widenius <monty@tik.pp.sci.fi>
+
+* All index blocks of the same size now share the same key block delete link
+
+1999-03-17 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Different key packing code depending on if the first key part
+ is a variable length column (space packed, BLOB or VARCHAR)
+* The create interface allows one to specify a key segment to start and
+ end one a specific bit. (The bit handling isn't yet implemented)
+* Added more tests to 'test1'
+
+1999-03-16 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Added option -m to myisamchk as an alternative to -e (-m is faster but
+ not as quite as safe as -e).
+* Added option --fast to not check not changed tables.
+* The first update will set a bit that the table has been changed.
+* The first update to a table increments a 'open_count' field. This will
+ be reset on close. This will allow myisamchk to find tables that hasn't
+ been properly closed!
+* Support for true VARCHAR columns
+
+1999-03-01 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Dynamic length blocks are double linked to allow easy reallocation
+ of block lengths. This will help that the dynamic length data will not be
+ as fragmented as with ISAM.
+* Extended mypack_isam to compress BLOB/TEXT columns.
+* Allow keys on BLOB.
+
+1999-02-06 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Keys, key pointers and all varibles in the index file are stored in
+ high-endian-order to get better compression.
+* Allow NULL on keys
+
+1998-10-29 Michael Widenius <monty@monty.pp.sci.fi>
+
+* All data is stored in low-endian order
+ (This means that the files will be architecture and OS independent)
+* All record numbers are now of type 'ha_rows' and file pointer are now of type
+ my_off_t. One can use files with 32-64 bit pointers with a 32bit or 64bit
+ record handling.
+ Currently the code is limited to 5 bytes pointers, but this is real easy
+ to change.
diff --git a/myisam/Makefile.am b/myisam/Makefile.am
new file mode 100644
index 00000000000..4a26fbae479
--- /dev/null
+++ b/myisam/Makefile.am
@@ -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
+
+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
+LDADD = @CLIENT_EXTRA_LDFLAGS@ libmyisam.a ../mysys/libmysys.a \
+ ../dbug/libdbug.a ../strings/libmystrings.a
+pkglib_LIBRARIES = libmyisam.a
+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_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)
+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 \
+ mi_rrnd.c mi_scan.c mi_cache.c \
+ mi_statrec.c mi_packrec.c mi_dynrec.c \
+ mi_update.c mi_write.c mi_unique.c \
+ mi_delete.c \
+ mi_rprev.c mi_rfirst.c mi_rlast.c mi_rsame.c \
+ mi_rsamepos.c mi_panic.c mi_close.c mi_create.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
+CLEANFILES = test?.IS? isam.log mi_test_all
+DEFS = -DMAP_TO_USE_RAID
+# Omit dependency for ../mit-pthreads/include/sys that only exits if
+# mit-pthreads are used
+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 \
+ wait.h
+
+# Move to automake rules ?
+prolint:; plparse -b -u -hF1 "-width(0,0)" "-format=%f:%l:\s%t:%n\s%m" \
+ "-elib(????)" "+elib(?3??)" my.lnt $(nisam_SOURCES)
+
+SUFFIXES = .sh
+
+.sh:
+ @RM@ -f $@ $@-t
+ @SED@ \
+ -e 's!@''bindir''@!$(bindir)!g' \
+ -e 's!@''scriptdir''@!$(bindir)!g' \
+ -e 's!@''prefix''@!$(prefix)!g' \
+ -e 's!@''datadir''@!$(datadir)!g' \
+ -e 's!@''localstatedir''@!$(localstatedir)!g' \
+ -e 's!@''libexecdir''@!$(libexecdir)!g' \
+ -e 's!@''CC''@!@CC@!'\
+ -e 's!@''CXX''@!@CXX@!'\
+ -e 's!@''GXX''@!@GXX@!'\
+ -e 's!@''PERL''@!@PERL@!' \
+ -e 's!@''CFLAGS''@!@SAVE_CFLAGS@!'\
+ -e 's!@''CXXFLAGS''@!@SAVE_CXXFLAGS@!'\
+ -e 's!@''LDFLAGS''@!@SAVE_LDFLAGS@!'\
+ -e 's!@''VERSION''@!@VERSION@!' \
+ -e 's!@''COMPILATION_COMMENT''@!@COMPILATION_COMMENT@!' \
+ -e 's!@''MACHINE_TYPE''@!@MACHINE_TYPE@!' \
+ -e 's!@''HOSTNAME''@!@HOSTNAME@!' \
+ -e 's!@''SYSTEM_TYPE''@!@SYSTEM_TYPE@!' \
+ -e 's!@''CHECK_PID''@!@CHECK_PID@!' \
+ -e 's!@''FIND_PROC''@!@FIND_PROC@!' \
+ -e 's!@''MYSQLD_DEFAULT_SWITCHES''@!@MYSQLD_DEFAULT_SWITCHES@!' \
+ -e 's!@''MYSQL_UNIX_ADDR''@!@MYSQL_UNIX_ADDR@!' \
+ -e 's!@''IS_LINUX''@!@IS_LINUX@!' \
+ -e "s!@""CONF_COMMAND""@!@CONF_COMMAND@!" \
+ -e 's!@''MYSQLD_USER''@!@MYSQLD_USER@!' \
+ -e 's!@''sysconfdir''@!@sysconfdir@!' \
+ -e 's!@''SHORT_MYSQL_INTRO''@!@SHORT_MYSQL_INTRO@!' \
+ -e 's!@''SHARED_LIB_VERSION''@!@SHARED_LIB_VERSION@!' \
+ -e 's!@''MYSQL_BASE_VERSION''@!@MYSQL_BASE_VERSION@!' \
+ -e 's!@''MYSQL_NO_DASH_VERSION''@!@MYSQL_NO_DASH_VERSION@!' \
+ -e 's!@''MYSQL_TCP_PORT''@!@MYSQL_TCP_PORT@!' \
+ -e 's!@''PERL_DBI_VERSION''@!@PERL_DBI_VERSION@!' \
+ -e 's!@''PERL_DBD_VERSION''@!@PERL_DBD_VERSION@!' \
+ -e 's!@''PERL_DATA_DUMPER''@!@PERL_DATA_DUMPER@!' \
+ $< > $@-t
+ @MV@ $@-t $@
diff --git a/myisam/NEWS b/myisam/NEWS
new file mode 100644
index 00000000000..bb1f141610b
--- /dev/null
+++ b/myisam/NEWS
@@ -0,0 +1,66 @@
+New features compared to NISAM:
+
+- All file positions have type my_off_t; This enables one to use big
+ files (2^63 byte) by defining my_off_t to be longlong on OS that supports
+ big files.
+- When creating a table, one can now specify the maximum data file length.
+ This will be used to calculate the length of row pointers.
+- All key segments have their own language definition.
+- Some changes to support more types:
+ The biggest change is that the interface allows MY_ISAM will support
+ variable length integer types. (Only the interface is implemented)
+- All data is stored with low byte first; This makes the data machine
+ independent.
+- All number keys are stored with high byte first to give better packing.
+- Support for a true VARCHAR type; A VARCHAR column starts with a length
+ stored on 2 bytes.
+- Tables with VARCHAR may have fixed or dynamic record length.
+- There are now 2 different ways to pack keys:
+ - If the first key part is a space stripped CHAR, a VARCHAR or a BLOB the
+ 'packed' method is used. This only prefix-compresses the first
+ key part.
+ - In other cases prefix packing is used (This also includes the record
+ pointer into the prefix packing). A key may in the best case be
+ packed on 2 bytes.
+- VARCHAR and CHAR may be up to 65K
+- Index on BLOB and VARCHAR.
+- One can now have NULL in an index. This takes 0-1 bytes / key.
+- MYISAM will allow one to specify one AUTO_INCREMENT column; MYISAM will
+ automaticly update this on INSERT/UPDATE. The AUTO_INCREMENT value can be
+ reset with myisamchk.
+- Max key length will be 500 by default; In cases of longer keys than 250,
+ a bigger key block size than the default of 1024 byes is used for this key.
+- Max number of keys enlarged to 32 as default. This can be enlarged to 64
+ without having to recompile myisamchk.
+- There is a flag in the MYISAM header that tells if the index file (.MYI)
+ was closed correctly.
+- myisamchk will now mark tables as checked. 'myisamchk --fast' will only
+ check those tables that doesn't have this mark.
+- 'myisamchk -a' stores statistic for key parts (and not only for whole keys
+ as in NISAM).
+- Dynamic size rows will now be much less fragmented when mixing deletes with
+ update and insert. This is done by automaticly combine adjacent deleted
+ blocks and by extending blocks if the next block is deleted.
+- For dynamic size rows, the delete link contains a pointer to itself
+ (to make repairs easier).
+- myisampack (called pack_isam in NISAM) can pack BLOB and VARCHAR
+ columns.
+- One can now disable any key from update; In NISAM one could only disable
+ the last x keys.
+- One can have a UNIQUE constraint on anything (including BLOBS).
+ This is implemented by a key that contains a hashed number of the whole
+ record and before inserting a new record, MyISAM will check all records
+ with the same hash for dupplicates.
+- When creating the table, one can define that MyISAM should maintain
+ a CRC for the whole table (to make isamchk even better). In the case of
+ dynamic size rows, one will in this case get 1 byte checksum for each row.
+ (This is a great help for debugging, but it can also be used to keep
+ MyISAM table 'extra' safe.
+- Temporary tables will not write not flushed keys to file on close and
+ not wait on 'disk full' conditions.
+
+Interface changes compared to NISAM:
+
+- mi_create()
+ - keyinfo->seg must be allocated explicitely.
+ - One must put number of key segments in keyinfo
diff --git a/myisam/TODO b/myisam/TODO
new file mode 100644
index 00000000000..cad9486e1bb
--- /dev/null
+++ b/myisam/TODO
@@ -0,0 +1,7 @@
+TODO:
+
+- Let packisam find the optimal way to store keys.
+- kill when using 'myisamchk' should remove all temporary files.
+- Text search index
+ (Sergei A. Golub is working on this)
+- Add '%' packed to myisamchk for compressed tables with blobs.
diff --git a/myisam/ft_eval.c b/myisam/ft_eval.c
new file mode 100644
index 00000000000..b8628724642
--- /dev/null
+++ b/myisam/ft_eval.c
@@ -0,0 +1,208 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "ft_eval.h"
+#include <stdarg.h>
+#include <getopt.h>
+
+static void print_error(int exit_code, const char *fmt,...);
+
+int main(int argc,char *argv[])
+{
+ MI_INFO *file;
+ int i,j;
+
+ MY_INIT(argv[0]);
+ get_options(argc,argv);
+ bzero((char*)recinfo,sizeof(recinfo));
+
+ /* First define 2 columns */
+ recinfo[0].type=FIELD_SKIPP_ENDSPACE;
+ recinfo[0].length=docid_length;
+ recinfo[1].type=FIELD_BLOB;
+ recinfo[1].length= 4+mi_portable_sizeof_char_ptr;
+
+ /* Define a key over the first column */
+ keyinfo[0].seg=keyseg;
+ keyinfo[0].keysegs=1;
+ keyinfo[0].seg[0].type= HA_KEYTYPE_TEXT;
+ keyinfo[0].seg[0].flag= HA_BLOB_PART;
+ keyinfo[0].seg[0].start=recinfo[0].length;
+ keyinfo[0].seg[0].length=key_length;
+ keyinfo[0].seg[0].null_bit=0;
+ keyinfo[0].seg[0].null_pos=0;
+ keyinfo[0].seg[0].bit_start=4;
+ keyinfo[0].seg[0].language=MY_CHARSET_CURRENT;
+ keyinfo[0].flag = HA_FULLTEXT;
+
+ if (!silent)
+ printf("- Creating isam-file\n");
+ if (mi_create(filename,1,keyinfo,2,recinfo,0,NULL,(MI_CREATE_INFO*) 0,0))
+ goto err;
+ if (!(file=mi_open(filename,2,0)))
+ goto err;
+ if (!silent)
+ printf("Initializing stopwords\n");
+ ft_init_stopwords(stopwordlist);
+
+ if (!silent)
+ printf("- Writing key:s\n");
+
+ my_errno=0;
+ i=0;
+ while(create_record(record,df))
+ {
+ error=mi_write(file,record);
+ if (error)
+ printf("I= %2d mi_write: %d errno: %d\n",i,error,my_errno);
+ i++;
+ }
+ fclose(df);
+
+ if (mi_close(file)) goto err;
+ if (!silent)
+ printf("- Reopening file\n");
+ if (!(file=mi_open(filename,2,0))) goto err;
+ if (!silent)
+ printf("- Reading rows with key\n");
+ for(i=1;create_record(record,qf);i++) {
+ FT_DOCLIST *result; double w; int t;
+
+ result=ft_init_search(file,0,blob_record,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;(w=ft_read_next(result, read_record))>0;j++) {
+ t=uint2korr(read_record);
+ printf("%d %.*s %f\n",i,t,read_record+2,w);
+ }
+ if(w<0) {
+ printf("ft_read_next %d failed with errno %3d\n",j,my_errno);
+ goto err;
+ }
+ ft_close_search(result);
+ }
+
+ if (mi_close(file)) goto err;
+ my_end(MY_CHECK_ERROR);
+
+ return (0);
+err:
+ printf("got error: %3d when using myisam-database\n",my_errno);
+ return 1; /* skipp warning */
+
+}
+
+void get_options(int argc,char *argv[])
+{
+ int c;
+ char *options=(char*) "Vh#:qSs:";
+
+ while ((c=getopt(argc,argv,options)) != -1)
+ {
+ switch(c) {
+ case 's':
+ if(stopwordlist && stopwordlist!=ft_precompiled_stopwords) break;
+ {
+ FILE *f; char s[HA_FT_MAXLEN]; int i=0,n=SWL_INIT;
+
+ if(!(stopwordlist=malloc(n*sizeof(char *))))
+ print_error(1,"malloc(%d)",n*sizeof(char *));
+ if(!(f=fopen(optarg,"r")))
+ print_error(1,"fopen(%s)",optarg);
+ while(!feof(f)) {
+ if(!(fgets(s,HA_FT_MAXLEN,f)))
+ print_error(1,"fgets(s,%d,%s)",HA_FT_MAXLEN,optarg);
+ if(!(stopwordlist[i++]=strdup(s)))
+ print_error(1,"strdup(%s)",s);
+ if(i>=n) {
+ n+=SWL_PLUS;
+ if(!(stopwordlist=(const char**) realloc((char*) stopwordlist,n*sizeof(char *))))
+ print_error(1,"realloc(%d)",n*sizeof(char *));
+ }
+ }
+ fclose(f);
+ stopwordlist[i]=NULL;
+ break;
+ }
+ case 'q': silent=1; break;
+ case 'S': if(stopwordlist==ft_precompiled_stopwords) stopwordlist=NULL; break;
+ case '#':
+ DEBUGGER_ON;
+ DBUG_PUSH (optarg);
+ break;
+ case 'V':
+ case '?':
+ case 'h':
+ default:
+ printf("%s -[%s] <d_file> <q_file>\n", argv[0], options);
+ exit(0);
+ }
+ }
+ if(!(d_file=argv[optind])) print_error(1,"No d_file");
+ if(!(df=fopen(d_file,"r")))
+ print_error(1,"fopen(%s)",d_file);
+ if(!(q_file=argv[optind+1])) print_error(1,"No q_file");
+ if(!(qf=fopen(q_file,"r")))
+ print_error(1,"fopen(%s)",q_file);
+ return;
+} /* get options */
+
+int create_record(char *pos, FILE *file)
+{ uint tmp; char *ptr;
+
+ bzero((char *)pos,MAX_REC_LENGTH);
+
+ /* column 1 - VARCHAR */
+ if(!(fgets(pos+2,MAX_REC_LENGTH-32,file)))
+ {
+ if(feof(file)) return 0; else print_error(1,"fgets(docid) - 1");
+ }
+ tmp=strlen(pos+2)-1;
+ int2store(pos,tmp);
+ pos+=recinfo[0].length;
+
+ /* column 2 - BLOB */
+
+ if(!(fgets(blob_record,MAX_BLOB_LENGTH,file)))
+ print_error(1,"fgets(docid) - 2");
+ tmp=strlen(blob_record);
+ int4store(pos,tmp);
+ ptr=blob_record;
+ memcpy_fixed(pos+4,&ptr,sizeof(char*));
+ return 1;
+}
+
+/* VARARGS */
+
+static void print_error(int exit_code, const char *fmt,...)
+{
+ va_list args;
+
+ va_start(args,fmt);
+ fprintf(stderr,"%s: error: ",my_progname);
+ VOID(vfprintf(stderr, fmt, args));
+ VOID(fputc('\n',stderr));
+ fflush(stderr);
+ va_end(args);
+ exit(exit_code);
+}
diff --git a/myisam/ft_eval.h b/myisam/ft_eval.h
new file mode 100644
index 00000000000..5d7f41ab04d
--- /dev/null
+++ b/myisam/ft_eval.h
@@ -0,0 +1,46 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 */
+
+const char **stopwordlist=ft_precompiled_stopwords;
+
+#define MAX_REC_LENGTH 128
+#define MAX_BLOB_LENGTH 60000
+char record[MAX_REC_LENGTH], read_record[MAX_REC_LENGTH+MAX_BLOB_LENGTH];
+char blob_record[MAX_BLOB_LENGTH+20*20];
+
+char *filename= (char*) "EVAL";
+
+int silent=0, error=0;
+
+uint key_length=MAX_BLOB_LENGTH,docid_length=32;
+char *d_file, *q_file;
+FILE *df,*qf;
+
+MI_COLUMNDEF recinfo[3];
+MI_KEYDEF keyinfo[2];
+MI_KEYSEG keyseg[10];
+
+void get_options(int argc,char *argv[]);
+int create_record(char *, FILE *);
+
+#define SWL_INIT 500
+#define SWL_PLUS 50
+
+#define MAX_LINE_LENGTH 128
+char line[MAX_LINE_LENGTH];
+
diff --git a/myisam/ft_parser.c b/myisam/ft_parser.c
new file mode 100644
index 00000000000..e2fcd2b00a1
--- /dev/null
+++ b/myisam/ft_parser.c
@@ -0,0 +1,152 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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"
+
+#ifdef EVAL_RUN
+#ifdef PIVOT_STAT
+ulong collstat=0;
+#endif
+#endif /* EVAL_RUN */
+
+typedef struct st_ft_docstat {
+ FT_WORD *list;
+ uint uniq;
+ double sum;
+#ifdef EVAL_RUN
+ uint words, totlen;
+ 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)
+{
+ return _mi_compare_text(default_charset_info,
+ (uchar*) w1->pos,w1->len,
+ (uchar*) w2->pos, w2->len,0);
+}
+
+static int walk_and_copy(FT_WORD *word,uint32 count,FT_DOCSTAT *docstat)
+{
+ if(is_stopword(word->pos, word->len))
+ return 0;
+
+ word->weight=LWS_IN_USE;
+
+#ifdef EVAL_RUN
+ word->cnt= (uchar) count;
+ if(docstat->max < word->weight) docstat->max=word->weight;
+ docstat->words+=count;
+ docstat->totlen+=word->len;
+#endif /* EVAL_RUN */
+ docstat->sum+=word->weight;
+
+ memcpy_fixed((docstat->list)++,word,sizeof(FT_WORD));
+ return 0;
+}
+
+/* transforms tree of words into the array, applying normalization */
+
+FT_WORD * ft_linearize(MI_INFO *info, uint keynr, byte *keybuf, TREE *wtree)
+{
+ FT_WORD *wlist,*p;
+ FT_DOCSTAT docstat;
+
+ 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
+ docstat.nsum=docstat.nsum2=docstat.max=docstat.words=docstat.totlen=
+#endif /* EVAL_RUN */
+ docstat.sum=0;
+ tree_walk(wtree,(tree_walk_action)&walk_and_copy,&docstat,left_root_right);
+ }
+ delete_tree(wtree);
+ free(wtree);
+ if(wlist==NULL)
+ return NULL;
+
+ docstat.list->pos=NULL;
+
+ for(p=wlist;p->pos;p++)
+ {
+ p->weight=PRENORM_IN_USE;
+#ifdef EVAL_RUN
+ docstat.nsum+=p->weight;
+ docstat.nsum2+=p->weight*p->weight;
+#endif /* EVAL_RUN */
+ }
+
+#ifdef EVAL_RUN
+#ifdef PIVOT_STAT
+ collstat+=PIVOT_STAT;
+#endif
+#endif /* EVAL_RUN */
+
+ for(p=wlist;p->pos;p++)
+ {
+ p->weight/=NORM_IN_USE;
+ }
+
+ return wlist;
+}
+
+#ifdef HYPHEN_IS_DELIM
+#define word_char(X) (isalnum(X) || (X)=='_' || (X)=='\'')
+#else
+#define word_char(X) (isalnum(X) || (X)=='_' || (X)=='\'' || (X)=='-')
+#endif
+
+/* this is rather dumb first version of the parser */
+TREE * ft_parse(TREE *wtree, byte *doc, int doclen)
+{
+ byte *end=doc+doclen;
+ FT_WORD w;
+
+ if(!wtree)
+ {
+ 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);
+ }
+
+ 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=doc-w.pos) < MIN_WORD_LEN) continue;
+ if(!tree_insert(wtree, &w, 0))
+ {
+ delete_tree(wtree);
+ free(wtree);
+ return NULL;
+ }
+ }
+ return wtree;
+}
diff --git a/myisam/ft_search.c b/myisam/ft_search.c
new file mode 100644
index 00000000000..db3afd3057b
--- /dev/null
+++ b/myisam/ft_search.c
@@ -0,0 +1,223 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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"
+
+/* queries isam and returns list of documents matched */
+
+typedef struct st_all_in_one {
+ MI_INFO *info;
+ uint keynr;
+ uchar *keybuff;
+ MI_KEYDEF *keyinfo;
+ my_off_t key_root;
+ TREE dtree;
+} ALL_IN_ONE;
+
+typedef struct st_ft_superdoc {
+ FT_DOC doc;
+ FT_WORD *word_ptr;
+ double tmp_weight;
+} FT_SUPERDOC;
+
+static int FT_SUPERDOC_cmp(FT_SUPERDOC *p1, FT_SUPERDOC *p2)
+{
+ if (p1->doc.dpos < p2->doc.dpos)
+ return -1;
+ if (p1->doc.dpos == p2->doc.dpos)
+ return 0;
+ return 1;
+}
+
+static int walk_and_match(FT_WORD *word, uint32 count, ALL_IN_ONE *aio)
+{
+ uint keylen, r, doc_cnt;
+#ifdef EVAL_RUN
+ uint cnt;
+ double sum, sum2, suml;
+#endif /* EVAL_RUN */
+ FT_SUPERDOC sdoc, *sptr;
+ TREE_ELEMENT *selem;
+#if HA_FT_WTYPE == HA_KEYTYPE_FLOAT
+ float tmp_weight;
+#else
+#error
+#endif
+
+ word->weight=LWS_FOR_QUERY;
+
+ keylen=_ft_make_key(aio->info,aio->keynr,(char*) aio->keybuff,word,0);
+#ifdef EVAL_RUN
+ keylen-=1+HA_FT_WLEN;
+#else /* EVAL_RUN */
+ keylen-=HA_FT_WLEN;
+#endif /* EVAL_RUN */
+
+#ifdef EVAL_RUN
+ sum=sum2=suml=
+#endif /* EVAL_RUN */
+ doc_cnt=0;
+
+ r=_mi_search(aio->info, aio->keyinfo, aio->keybuff, keylen,
+ SEARCH_FIND | SEARCH_PREFIX, aio->key_root);
+
+ while(!r)
+ {
+ if (_mi_compare_text(default_charset_info,
+ aio->info->lastkey,keylen,
+ aio->keybuff,keylen,0)) break;
+
+#if HA_FT_WTYPE == HA_KEYTYPE_FLOAT
+#ifdef EVAL_RUN
+ mi_float4get(tmp_weight,aio->info->lastkey+keylen+1);
+#else /* EVAL_RUN */
+ mi_float4get(tmp_weight,aio->info->lastkey+keylen);
+#endif /* EVAL_RUN */
+#else
+#error
+#endif
+ if(tmp_weight==0) return doc_cnt; /* stopword, doc_cnt should be 0 */
+
+#ifdef EVAL_RUN
+ cnt=*(byte *)(aio->info->lastkey+keylen);
+#endif /* EVAL_RUN */
+
+ sdoc.doc.dpos=aio->info->lastpos;
+
+ /* saving document matched into dtree */
+ if(!(selem=tree_insert(&aio->dtree, &sdoc, 0))) return 1;
+
+ sptr=(FT_SUPERDOC *)ELEMENT_KEY((&aio->dtree), selem);
+
+ if(selem->count==1) /* document's first match */
+ sptr->doc.weight=0;
+ else
+ sptr->doc.weight+=sptr->tmp_weight*sptr->word_ptr->weight;
+
+ sptr->word_ptr=word;
+ sptr->tmp_weight=tmp_weight;
+
+ doc_cnt++;
+#ifdef EVAL_RUN
+ sum +=cnt;
+ sum2+=cnt*cnt;
+ suml+=cnt*log(cnt);
+#endif /* EVAL_RUN */
+
+ if (_mi_test_if_changed(aio->info) == 0)
+ r=_mi_search_next(aio->info, aio->keyinfo, aio->info->lastkey,
+ aio->info->lastkey_length, SEARCH_BIGGER,
+ aio->key_root);
+ else
+ r=_mi_search(aio->info, aio->keyinfo, aio->info->lastkey,
+ aio->info->lastkey_length, SEARCH_BIGGER,
+ aio->key_root);
+ }
+ if(doc_cnt) {
+ word->weight*=GWS_IN_USE;
+ if(word->weight < 0) word->weight=0;
+ }
+
+ return 0;
+}
+
+static int walk_and_copy(FT_SUPERDOC *from,
+ uint32 count __attribute__((unused)), FT_DOC **to)
+{
+ from->doc.weight+=from->tmp_weight*from->word_ptr->weight;
+ (*to)->dpos=from->doc.dpos;
+ (*to)->weight=from->doc.weight;
+ (*to)++;
+ return 0;
+}
+
+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)
+{
+ TREE *wtree;
+ ALL_IN_ONE aio;
+ FT_DOCLIST *dlist;
+ FT_DOC *dptr;
+
+/* black magic ON */
+ if ((int) (keynr = _mi_check_index((MI_INFO *)info,keynr)) < 0)
+ return NULL;
+ if (_mi_readinfo((MI_INFO *)info,F_RDLCK,1))
+ return NULL;
+/* black magic OFF */
+
+ dlist=NULL;
+ aio.info=(MI_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];
+
+ if(!(wtree=ft_parse(NULL,key,key_len))) return NULL;
+
+ init_tree(&aio.dtree,0,sizeof(FT_SUPERDOC),(qsort_cmp)&FT_SUPERDOC_cmp,0,
+ NULL);
+
+ if(tree_walk(wtree, (tree_walk_action)&walk_and_match, &aio,
+ left_root_right))
+ 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;
+
+ dlist->ndocs=aio.dtree.elements_in_tree;
+ dlist->curdoc=0;
+ dlist->info=aio.info;
+ dptr=dlist->doc;
+
+ tree_walk(&aio.dtree, (tree_walk_action)&walk_and_copy, &dptr, left_root_right);
+
+ if(presort)
+ {
+ qsort(dlist->doc, dlist->ndocs, sizeof(FT_DOC), (qsort_cmp)&FT_DOC_cmp);
+ }
+
+err:
+ delete_tree(&aio.dtree);
+ delete_tree(wtree);
+ free(wtree);
+ return dlist;
+}
+
+double ft_read_next(FT_DOCLIST *handler, char *record)
+{
+ MI_INFO *info=handler->info;
+
+ if (handler->curdoc >= handler->ndocs)
+ return 0;
+
+ info->update&= (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
+
+ if (!(*info->read_record)(info,handler->doc[handler->curdoc].dpos,record))
+ {
+ info->update|= HA_STATE_AKTIV; /* Record is read */
+ return handler->doc[handler->curdoc++].weight;
+ }
+ return -my_errno;
+}
diff --git a/myisam/ft_static.c b/myisam/ft_static.c
new file mode 100644
index 00000000000..5cbcff85b54
--- /dev/null
+++ b/myisam/ft_static.c
@@ -0,0 +1,627 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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"
+
+const MI_KEYSEG ft_keysegs[FT_SEGS]={
+ {
+ HA_KEYTYPE_VARTEXT, // type
+ 7, // language
+ 0, 0, 0, // null_bit, bit_start, bit_end
+ HA_VAR_LENGTH | HA_PACK_KEY, // flag
+ HA_FT_MAXLEN, // length
+#ifdef EVAL_RUN
+ HA_FT_WLEN+1, // start
+#else /* EVAL_RUN */
+ HA_FT_WLEN, // start
+#endif /* EVAL_RUN */
+ 0, // null_pos
+ NULL // sort_order
+ },
+#ifdef EVAL_RUN
+ {
+ HA_KEYTYPE_INT8, 7, 0, 0, 0, 0, 1, HA_FT_WLEN, 0, NULL
+ },
+#endif /* EVAL_RUN */
+ {
+ HA_FT_WTYPE, 7, 0, 0, 0, 0, HA_FT_WLEN, 0, 0, NULL
+ }
+};
+
+const char *ft_precompiled_stopwords[] = {
+
+#ifdef COMPILE_STOPWORDS_IN
+
+/* This particular stopword list was taken from SMART distribution
+ ftp://ftp.cs.cornell.edu/pub/smart/smart.11.0.tar.Z
+ it was slightly modified to my taste, though
+ */
+
+ "a",
+ "a's",
+ "able",
+ "about",
+ "above",
+ "according",
+ "accordingly",
+ "across",
+ "actually",
+ "after",
+ "afterwards",
+ "again",
+ "against",
+ "ain't",
+ "all",
+ "allow",
+ "allows",
+ "almost",
+ "alone",
+ "along",
+ "already",
+ "also",
+ "although",
+ "always",
+ "am",
+ "among",
+ "amongst",
+ "an",
+ "and",
+ "another",
+ "any",
+ "anybody",
+ "anyhow",
+ "anyone",
+ "anything",
+ "anyway",
+ "anyways",
+ "anywhere",
+ "apart",
+ "appear",
+ "appreciate",
+ "appropriate",
+ "are",
+ "aren't",
+ "around",
+ "as",
+ "aside",
+ "ask",
+ "asking",
+ "associated",
+ "at",
+ "available",
+ "away",
+ "awfully",
+ "b",
+ "be",
+ "became",
+ "because",
+ "become",
+ "becomes",
+ "becoming",
+ "been",
+ "before",
+ "beforehand",
+ "behind",
+ "being",
+ "believe",
+ "below",
+ "beside",
+ "besides",
+ "best",
+ "better",
+ "between",
+ "beyond",
+ "both",
+ "brief",
+ "but",
+ "by",
+ "c",
+ "c'mon",
+ "c's",
+ "came",
+ "can",
+ "can't",
+ "cannot",
+ "cant",
+ "cause",
+ "causes",
+ "certain",
+ "certainly",
+ "changes",
+ "clearly",
+ "co",
+ "com",
+ "come",
+ "comes",
+ "concerning",
+ "consequently",
+ "consider",
+ "considering",
+ "contain",
+ "containing",
+ "contains",
+ "corresponding",
+ "could",
+ "couldn't",
+ "course",
+ "currently",
+ "d",
+ "definitely",
+ "described",
+ "despite",
+ "did",
+ "didn't",
+ "different",
+ "do",
+ "does",
+ "doesn't",
+ "doing",
+ "don't",
+ "done",
+ "down",
+ "downwards",
+ "during",
+ "e",
+ "each",
+ "edu",
+ "eg",
+ "eight",
+ "either",
+ "else",
+ "elsewhere",
+ "enough",
+ "entirely",
+ "especially",
+ "et",
+ "etc",
+ "even",
+ "ever",
+ "every",
+ "everybody",
+ "everyone",
+ "everything",
+ "everywhere",
+ "ex",
+ "exactly",
+ "example",
+ "except",
+ "f",
+ "far",
+ "few",
+ "fifth",
+ "first",
+ "five",
+ "followed",
+ "following",
+ "follows",
+ "for",
+ "former",
+ "formerly",
+ "forth",
+ "four",
+ "from",
+ "further",
+ "furthermore",
+ "g",
+ "get",
+ "gets",
+ "getting",
+ "given",
+ "gives",
+ "go",
+ "goes",
+ "going",
+ "gone",
+ "got",
+ "gotten",
+ "greetings",
+ "h",
+ "had",
+ "hadn't",
+ "happens",
+ "hardly",
+ "has",
+ "hasn't",
+ "have",
+ "haven't",
+ "having",
+ "he",
+ "he's",
+ "hello",
+ "help",
+ "hence",
+ "her",
+ "here",
+ "here's",
+ "hereafter",
+ "hereby",
+ "herein",
+ "hereupon",
+ "hers",
+ "herself",
+ "hi",
+ "him",
+ "himself",
+ "his",
+ "hither",
+ "hopefully",
+ "how",
+ "howbeit",
+ "however",
+ "i",
+ "i'd",
+ "i'll",
+ "i'm",
+ "i've",
+ "ie",
+ "if",
+ "ignored",
+ "immediate",
+ "in",
+ "inasmuch",
+ "inc",
+ "indeed",
+ "indicate",
+ "indicated",
+ "indicates",
+ "inner",
+ "insofar",
+ "instead",
+ "into",
+ "inward",
+ "is",
+ "isn't",
+ "it",
+ "it'd",
+ "it'll",
+ "it's",
+ "its",
+ "itself",
+ "j",
+ "just",
+ "k",
+ "keep",
+ "keeps",
+ "kept",
+ "know",
+ "knows",
+ "known",
+ "l",
+ "last",
+ "lately",
+ "later",
+ "latter",
+ "latterly",
+ "least",
+ "less",
+ "lest",
+ "let",
+ "let's",
+ "like",
+ "liked",
+ "likely",
+ "little",
+ "look",
+ "looking",
+ "looks",
+ "ltd",
+ "m",
+ "mainly",
+ "many",
+ "may",
+ "maybe",
+ "me",
+ "mean",
+ "meanwhile",
+ "merely",
+ "might",
+ "more",
+ "moreover",
+ "most",
+ "mostly",
+ "much",
+ "must",
+ "my",
+ "myself",
+ "n",
+ "name",
+ "namely",
+ "nd",
+ "near",
+ "nearly",
+ "necessary",
+ "need",
+ "needs",
+ "neither",
+ "never",
+ "nevertheless",
+ "new",
+ "next",
+ "nine",
+ "no",
+ "nobody",
+ "non",
+ "none",
+ "noone",
+ "nor",
+ "normally",
+ "not",
+ "nothing",
+ "novel",
+ "now",
+ "nowhere",
+ "o",
+ "obviously",
+ "of",
+ "off",
+ "often",
+ "oh",
+ "ok",
+ "okay",
+ "old",
+ "on",
+ "once",
+ "one",
+ "ones",
+ "only",
+ "onto",
+ "or",
+ "other",
+ "others",
+ "otherwise",
+ "ought",
+ "our",
+ "ours",
+ "ourselves",
+ "out",
+ "outside",
+ "over",
+ "overall",
+ "own",
+ "p",
+ "particular",
+ "particularly",
+ "per",
+ "perhaps",
+ "placed",
+ "please",
+ "plus",
+ "possible",
+ "presumably",
+ "probably",
+ "provides",
+ "q",
+ "que",
+ "quite",
+ "qv",
+ "r",
+ "rather",
+ "rd",
+ "re",
+ "really",
+ "reasonably",
+ "regarding",
+ "regardless",
+ "regards",
+ "relatively",
+ "respectively",
+ "right",
+ "s",
+ "said",
+ "same",
+ "saw",
+ "say",
+ "saying",
+ "says",
+ "second",
+ "secondly",
+ "see",
+ "seeing",
+ "seem",
+ "seemed",
+ "seeming",
+ "seems",
+ "seen",
+ "self",
+ "selves",
+ "sensible",
+ "sent",
+ "serious",
+ "seriously",
+ "seven",
+ "several",
+ "shall",
+ "she",
+ "should",
+ "shouldn't",
+ "since",
+ "six",
+ "so",
+ "some",
+ "somebody",
+ "somehow",
+ "someone",
+ "something",
+ "sometime",
+ "sometimes",
+ "somewhat",
+ "somewhere",
+ "soon",
+ "sorry",
+ "specified",
+ "specify",
+ "specifying",
+ "still",
+ "sub",
+ "such",
+ "sup",
+ "sure",
+ "t",
+ "t's",
+ "take",
+ "taken",
+ "tell",
+ "tends",
+ "th",
+ "than",
+ "thank",
+ "thanks",
+ "thanx",
+ "that",
+ "that's",
+ "thats",
+ "the",
+ "their",
+ "theirs",
+ "them",
+ "themselves",
+ "then",
+ "thence",
+ "there",
+ "there's",
+ "thereafter",
+ "thereby",
+ "therefore",
+ "therein",
+ "theres",
+ "thereupon",
+ "these",
+ "they",
+ "they'd",
+ "they'll",
+ "they're",
+ "they've",
+ "think",
+ "third",
+ "this",
+ "thorough",
+ "thoroughly",
+ "those",
+ "though",
+ "three",
+ "through",
+ "throughout",
+ "thru",
+ "thus",
+ "to",
+ "together",
+ "too",
+ "took",
+ "toward",
+ "towards",
+ "tried",
+ "tries",
+ "truly",
+ "try",
+ "trying",
+ "twice",
+ "two",
+ "u",
+ "un",
+ "under",
+ "unfortunately",
+ "unless",
+ "unlikely",
+ "until",
+ "unto",
+ "up",
+ "upon",
+ "us",
+ "use",
+ "used",
+ "useful",
+ "uses",
+ "using",
+ "usually",
+ "v",
+ "value",
+ "various",
+ "very",
+ "via",
+ "viz",
+ "vs",
+ "w",
+ "want",
+ "wants",
+ "was",
+ "wasn't",
+ "way",
+ "we",
+ "we'd",
+ "we'll",
+ "we're",
+ "we've",
+ "welcome",
+ "well",
+ "went",
+ "were",
+ "weren't",
+ "what",
+ "what's",
+ "whatever",
+ "when",
+ "whence",
+ "whenever",
+ "where",
+ "where's",
+ "whereafter",
+ "whereas",
+ "whereby",
+ "wherein",
+ "whereupon",
+ "wherever",
+ "whether",
+ "which",
+ "while",
+ "whither",
+ "who",
+ "who's",
+ "whoever",
+ "whole",
+ "whom",
+ "whose",
+ "why",
+ "will",
+ "willing",
+ "wish",
+ "with",
+ "within",
+ "without",
+ "won't",
+ "wonder",
+ "would",
+ "would",
+ "wouldn't",
+ "x",
+ "y",
+ "yes",
+ "yet",
+ "you",
+ "you'd",
+ "you'll",
+ "you're",
+ "you've",
+ "your",
+ "yours",
+ "yourself",
+ "yourselves",
+ "z",
+ "zero",
+#endif
+
+ NULL };
diff --git a/myisam/ft_stem.c b/myisam/ft_stem.c
new file mode 100644
index 00000000000..bdfc73b774b
--- /dev/null
+++ b/myisam/ft_stem.c
@@ -0,0 +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 */
+
+/* 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
new file mode 100644
index 00000000000..f8fddc9d4bb
--- /dev/null
+++ b/myisam/ft_stopwords.c
@@ -0,0 +1,68 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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"
+
+typedef struct st_ft_stopwords {
+ const char * pos;
+ uint len;
+} FT_STOPWORD;
+
+static TREE *stopwords3=NULL;
+
+static int FT_STOPWORD_cmp(FT_STOPWORD *w1, FT_STOPWORD *w2)
+{
+ return _mi_compare_text(default_charset_info,
+ (uchar *)w1->pos,w1->len,
+ (uchar *)w2->pos,w2->len,0);
+}
+
+int ft_init_stopwords(const char **sws)
+{
+ FT_STOPWORD sw;
+
+
+ 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);
+ }
+
+ if(!sws) return 0;
+
+ for(;*sws;sws++)
+ {
+ if( (sw.len=strlen(sw.pos=*sws)) < MIN_WORD_LEN) continue;
+ if(!tree_insert(stopwords3, &sw, 0))
+ {
+ delete_tree(stopwords3);
+ return -1;
+ }
+ }
+ return 0;
+}
+
+int is_stopword(char *word, uint len)
+{
+ FT_STOPWORD sw;
+ sw.pos=word;
+ sw.len=len;
+ return tree_search(stopwords3,&sw) != NULL;
+}
+
diff --git a/myisam/ft_test1.c b/myisam/ft_test1.c
new file mode 100644
index 00000000000..377fa808d52
--- /dev/null
+++ b/myisam/ft_test1.c
@@ -0,0 +1,265 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "ft_test1.h"
+#include <getopt.h>
+
+static int key_field=FIELD_VARCHAR,extra_field=FIELD_SKIPP_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,
+ no_keys=0,no_stopwords=0,no_search=0,no_fulltext=0;
+static int create_flag=0,error=0;
+
+#define MAX_REC_LENGTH 300
+static char record[MAX_REC_LENGTH],read_record[MAX_REC_LENGTH];
+
+void get_options(int argc,char *argv[]);
+static int run_test(const char *filename);
+
+int main(int argc,char *argv[])
+{
+ MY_INIT(argv[0]);
+
+ get_options(argc,argv);
+
+ exit(run_test("FT1"));
+}
+
+static MI_COLUMNDEF recinfo[3];
+static MI_KEYDEF keyinfo[2];
+static MI_KEYSEG keyseg[10];
+
+void create_record(char *, int);
+
+static int run_test(const char *filename)
+{
+ MI_INFO *file;
+ int i,j;
+ my_off_t pos;
+
+ bzero((char*) recinfo,sizeof(recinfo));
+
+ /* First define 2 columns */
+ recinfo[0].type=extra_field;
+ recinfo[0].length= (extra_field == FIELD_BLOB ? 4 + mi_portable_sizeof_char_ptr :
+ extra_length);
+ if (extra_field == FIELD_VARCHAR)
+ recinfo[0].length+=2;
+ recinfo[1].type=key_field;
+ recinfo[1].length= (key_field == FIELD_BLOB ? 4+mi_portable_sizeof_char_ptr :
+ key_length);
+ if (key_field == FIELD_VARCHAR)
+ recinfo[1].length+=2;
+
+ /* Define a key over the first column */
+ keyinfo[0].seg=keyseg;
+ keyinfo[0].keysegs=1;
+ keyinfo[0].seg[0].type= key_type;
+ keyinfo[0].seg[0].flag= (key_field == FIELD_BLOB)?HA_BLOB_PART:
+ (key_field == FIELD_VARCHAR)?HA_VAR_LENGTH:0;
+ keyinfo[0].seg[0].start=recinfo[0].length;
+ keyinfo[0].seg[0].length=key_length;
+ keyinfo[0].seg[0].null_bit= 0;
+ keyinfo[0].seg[0].null_pos=0;
+ keyinfo[0].seg[0].language=MY_CHARSET_CURRENT;
+ keyinfo[0].flag = (no_fulltext?HA_PACK_KEY:HA_FULLTEXT);
+
+ if (!silent)
+ printf("- Creating isam-file\n");
+ if (mi_create(filename,(no_keys?0:1),keyinfo,2,recinfo,0,NULL,
+ (MI_CREATE_INFO*) 0, create_flag))
+ goto err;
+ if (!(file=mi_open(filename,2,0)))
+ goto err;
+
+ if (!silent)
+ printf("- %s stopwords\n",no_stopwords?"Skipping":"Initializing");
+ ft_init_stopwords(no_stopwords?NULL:ft_precompiled_stopwords);
+
+ if (!silent)
+ printf("- Writing key:s\n");
+
+ my_errno=0;
+ for (i=NUPD ; i<NDATAS; i++ )
+ {
+ create_record(record,i);
+ error=mi_write(file,record);
+ if (verbose || error)
+ printf("I= %2d mi_write: %d errno: %d, record: %s\n",
+ i,error,my_errno,data[i].f0);
+ }
+
+ if (!skip_update)
+ {
+ if (!silent)
+ printf("- Updating rows\n");
+
+ /* Read through all rows and update them */
+ pos=(ha_rows) 0;
+ i=0;
+ while ((error=mi_rrnd(file,read_record,pos)) == 0)
+ {
+ create_record(record,NUPD-i-1);
+ if (mi_update(file,read_record,record))
+ {
+ printf("Can't update row: %.*s, error: %d\n",
+ keyinfo[0].seg[0].length,record,my_errno);
+ }
+ if(++i == NUPD) break;
+ pos=HA_OFFSET_ERROR;
+ }
+ if (i != NUPD)
+ printf("Found %d of %d rows\n", i,NUPD);
+ }
+
+ if (mi_close(file)) goto err;
+ if(no_search) return 0;
+ if (!silent)
+ printf("- Reopening file\n");
+ if (!(file=mi_open(filename,2,0))) goto err;
+ if (!silent)
+ 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);
+ if(!result) {
+ printf("Query %d: `%s' failed with errno %3d\n",i,query[i],my_errno);
+ continue;
+ }
+ printf("Query %d: `%s'. Found: %d. Top five documents:\n",
+ i,query[i],result->ndocs);
+ for(j=0;j<5;j++) { double w;
+ w=ft_read_next(result, read_record);
+ if(w<0) {
+ printf("ft_read_next %d failed with errno %3d\n",j,my_errno);
+ break;
+ } else if (w==0) {
+ printf("No more matches!\n");
+ break;
+ }
+ if(key_field == FIELD_VARCHAR) {
+ uint l;
+ char *p;
+ p=recinfo[0].length+read_record;
+ l=uint2korr(p);
+ printf("%10.7f: %.*s\n",w,(int) l,p+2);
+ } else
+ printf("%10.7f: %.*s\n",w,recinfo[1].length,
+ recinfo[0].length+read_record);
+ }
+ ft_close_search(result);
+ }
+
+ if (mi_close(file)) goto err;
+ my_end(MY_CHECK_ERROR);
+
+ return (0);
+err:
+ printf("got error: %3d when using myisam-database\n",my_errno);
+ return 1; /* skipp warning */
+}
+
+static char blob_key[MAX_REC_LENGTH];
+/* static char blob_record[MAX_REC_LENGTH+20*20]; */
+
+void create_record(char *pos, int n)
+{
+ bzero((char*) pos,MAX_REC_LENGTH);
+ if (recinfo[0].type == FIELD_BLOB)
+ {
+ uint tmp;
+ char *ptr;
+ strncpy(blob_key,data[n].f0,keyinfo[0].seg[0].length);
+ tmp=strlen(blob_key);
+ int4store(pos,tmp);
+ ptr=blob_key;
+ memcpy_fixed(pos+4,&ptr,sizeof(char*));
+ pos+=recinfo[0].length;
+ }
+ else if (recinfo[0].type == FIELD_VARCHAR)
+ {
+ uint tmp;
+ strncpy(pos+2,data[n].f0,keyinfo[0].seg[0].length);
+ tmp=strlen(pos+2);
+ int2store(pos,tmp);
+ pos+=recinfo[0].length;
+ }
+ else
+ {
+ strncpy(pos,data[n].f0,keyinfo[0].seg[0].length);
+ pos+=recinfo[0].length;
+ }
+ if (recinfo[1].type == FIELD_BLOB)
+ {
+ uint tmp;
+ char *ptr;
+ strncpy(blob_key,data[n].f2,keyinfo[0].seg[0].length);
+ tmp=strlen(blob_key);
+ int4store(pos,tmp);
+ ptr=blob_key;
+ memcpy_fixed(pos+4,&ptr,sizeof(char*));
+ pos+=recinfo[1].length;
+ }
+ else if (recinfo[1].type == FIELD_VARCHAR)
+ {
+ uint tmp;
+ strncpy(pos+2,data[n].f2,keyinfo[0].seg[0].length);
+ tmp=strlen(pos+2);
+ int2store(pos,tmp);
+ pos+=recinfo[1].length;
+ }
+ else
+ {
+ strncpy(pos,data[n].f2,keyinfo[0].seg[0].length);
+ pos+=recinfo[1].length;
+ }
+}
+
+/* Read options */
+
+void get_options(int argc,char *argv[])
+{
+ int c;
+ const char *options="hVvsNSKFU#:";
+
+ while ((c=getopt(argc,argv,options)) != -1)
+ {
+ switch(c) {
+ case 'v': verbose=1; break;
+ case 's': silent=1; break;
+ case 'F': no_fulltext=1; no_search=1;
+ case 'U': skip_update=1; break;
+ case 'K': no_keys=no_search=1; break;
+ case 'N': no_search=1; break;
+ case 'S': no_stopwords=1; break;
+ case '#':
+ DEBUGGER_ON;
+ DBUG_PUSH (optarg);
+ break;
+ case 'V':
+ case '?':
+ case 'h':
+ default:
+ printf("%s -[%s]\n", argv[0], options);
+ exit(0);
+ }
+ }
+ return;
+} /* get options */
diff --git a/myisam/ft_test1.h b/myisam/ft_test1.h
new file mode 100644
index 00000000000..17b0cae66b7
--- /dev/null
+++ b/myisam/ft_test1.h
@@ -0,0 +1,422 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 */
+
+#define NUPD 20
+#define NDATAS 389
+struct { const char *f0, *f2; } data[NDATAS] = {
+ {"1", "General Information about MySQL"},
+ {"1.1", "What is MySQL?"},
+ {"1.2", "About this manual"},
+ {"1.3", "History of MySQL"},
+ {"1.4", "The main features of MySQL"},
+ {"1.5", "General SQL information and tutorials"},
+ {"1.6", "Useful MySQL-related links"},
+ {"1.7", "What are stored procedures and triggers and so on?"},
+ {"2", "MySQL mailing lists and how to ask questions/give error (bug) reports"},
+ {"2.1", "Subscribing to/un-subscribing from the MySQL mailing list"},
+ {"2.2", "Asking questions or reporting bugs"},
+ {"2.3", "I think I have found a bug. What information do you need to help me?"},
+ {"2.3.1", "MySQL keeps crashing"},
+ {"2.4", "Guidelines for answering questions on the mailing list"},
+ {"3", "Licensing or When do I have/want to pay for MySQL?"},
+ {"3.1", "How much does MySQL cost?"},
+ {"3.2", "How do I get commercial support?"},
+ {"3.2.1", "Types of commercial support"},
+ {"3.2.1.1", "Basic email support"},
+ {"3.2.1.2", "Extended email support"},
+/*------------------------------- NUPD=20 -------------------------------*/
+ {"3.2.1.3", "Asking: Login support"},
+ {"3.2.1.4", "Extended login support"},
+ {"3.3", "How do I pay for licenses/support?"},
+ {"3.4", "Who do I contact when I want more information about licensing/support?"},
+ {"3.5", "What Copyright does MySQL use?"},
+ {"3.6", "When may I distribute MySQL commercially without a fee?"},
+ {"3.7", "I want to sell a product that can be configured to use MySQL"},
+ {"3.8", "I am running a commercial web server using MySQL"},
+ {"3.9", "Do I need a license to sell commercial Perl/tcl/PHP/Web+ etc applications?"},
+ {"3.10", "Possible future changes in the licensing"},
+ {"4", "Compiling and installing MySQL"},
+ {"4.1", "How do I get MySQL?"},
+ {"4.2", "Which MySQL version should I use?"},
+ {"4.3", "How/when will you release updates?"},
+ {"4.4", "What operating systems does MySQL support?"},
+ {"4.5", "Compiling MySQL from source code"},
+ {"4.5.1", "Quick installation overview"},
+ {"4.5.2", "Usual configure switches"},
+ {"4.5.3", "Applying a patch"},
+ {"4.6", "Problems compiling?"},
+ {"4.7", "General compilation notes"},
+ {"4.8", "MIT-pthreads notes (FreeBSD)"},
+ {"4.9", "Perl installation comments"},
+ {"4.10", "Special things to consider for some machine/OS combinations"},
+ {"4.10.1", "Solaris notes"},
+ {"4.10.2", "SunOS 4 notes"},
+ {"4.10.3", "Linux notes for all versions"},
+ {"4.10.3.1", "Linux-x86 notes"},
+ {"4.10.3.2", "RedHat 5.0"},
+ {"4.10.3.3", "RedHat 5.1"},
+ {"4.10.3.4", "Linux-Sparc notes"},
+ {"4.10.3.5", "Linux-Alpha notes"},
+ {"4.10.3.6", "MkLinux notes"},
+ {"4.10.4", "Alpha-DEC-Unix notes"},
+ {"4.10.5", "Alpha-DEC-OSF1 notes"},
+ {"4.10.6", "SGI-IRIX notes"},
+ {"4.10.7", "FreeBSD notes"},
+ {"4.10.7.1", "FreeBSD-3.0 notes"},
+ {"4.10.8", "BSD/OS 2.# notes"},
+ {"4.10.8.1", "BSD/OS 3.# notes"},
+ {"4.10.9", "SCO notes"},
+ {"4.10.10", "SCO Unixware 7.0 notes"},
+ {"4.10.11", "IBM-AIX notes"},
+ {"4.10.12", "HP-UX notes"},
+ {"4.11", "TcX binaries"},
+ {"4.12", "Win32 notes"},
+ {"4.13", "Installation instructions for MySQL binary releases"},
+ {"4.13.1", "How to get MySQL Perl support working"},
+ {"4.13.2", "Linux notes"},
+ {"4.13.3", "HP-UX notes"},
+ {"4.13.4", "Linking client libraries"},
+ {"4.14", "Problems running mysql_install_db"},
+ {"4.15", "Problems starting MySQL"},
+ {"4.16", "Automatic start/stop of MySQL"},
+ {"4.17", "Option files"},
+ {"5", "How standards-compatible is MySQL?"},
+ {"5.1", "What extensions has MySQL to ANSI SQL92?"},
+ {"5.2", "What functionality is missing in MySQL?"},
+ {"5.2.1", "Sub-selects"},
+ {"5.2.2", "SELECT INTO TABLE"},
+ {"5.2.3", "Transactions"},
+ {"5.2.4", "Triggers"},
+ {"5.2.5", "Foreign Keys"},
+ {"5.2.5.1", "Some reasons NOT to use FOREIGN KEYS"},
+ {"5.2.6", "Views"},
+ {"5.2.7", "-- as start of a comment"},
+ {"5.3", "What standards does MySQL follow?"},
+ {"5.4", "What functions exist only for compatibility?"},
+ {"5.5", "Limitations of BLOB and TEXT types"},
+ {"5.6", "How to cope without COMMIT-ROLLBACK"},
+ {"6", "The MySQL access privilege system"},
+ {"6.1", "What the privilege system does"},
+ {"6.2", "Connecting to the MySQL server"},
+ {"6.2.1", "Keeping your password secure"},
+ {"6.3", "Privileges provided by MySQL"},
+ {"6.4", "How the privilege system works"},
+ {"6.5", "The privilege tables"},
+ {"6.6", "Setting up the initial MySQL privileges"},
+ {"6.7", "Adding new user privileges to MySQL"},
+ {"6.8", "An example permission setup"},
+ {"6.9", "Causes of Access denied errors"},
+ {"6.10", "How to make MySQL secure against crackers"},
+ {"7", "MySQL language reference"},
+ {"7.1", "Literals: how to write strings and numbers"},
+ {"7.1.1", "Strings"},
+ {"7.1.2", "Numbers"},
+ {"7.1.3", "NULL values"},
+ {"7.1.4", "Database, table, index, column and alias names"},
+ {"7.1.4.1", "Case sensitivity in names"},
+ {"7.2", "Column types"},
+ {"7.2.1", "Column type storage requirements"},
+ {"7.2.5", "Numeric types"},
+ {"7.2.6", "Date and time types"},
+ {"7.2.6.1", "The DATE type"},
+ {"7.2.6.2", "The TIME type"},
+ {"7.2.6.3", "The DATETIME type"},
+ {"7.2.6.4", "The TIMESTAMP type"},
+ {"7.2.6.5", "The YEAR type"},
+ {"7.2.6.6", "Miscellaneous date and time properties"},
+ {"7.2.7", "String types"},
+ {"7.2.7.1", "The CHAR and VARCHAR types"},
+ {"7.2.7.2", "The BLOB and TEXT types"},
+ {"7.2.7.3", "The ENUM type"},
+ {"7.2.7.4", "The SET type"},
+ {"7.2.8", "Choosing the right type for a column"},
+ {"7.2.9", "Column indexes"},
+ {"7.2.10", "Multiple-column indexes"},
+ {"7.2.11", "Using column types from other database engines"},
+ {"7.3", "Functions for use in SELECT and WHERE clauses"},
+ {"7.3.1", "Grouping functions"},
+ {"7.3.2", "Normal arithmetic operations"},
+ {"7.3.3", "Bit functions"},
+ {"7.3.4", "Logical operations"},
+ {"7.3.5", "Comparison operators"},
+ {"7.3.6", "String comparison functions"},
+ {"7.3.7", "Control flow functions"},
+ {"7.3.8", "Mathematical functions"},
+ {"7.3.9", "String functions"},
+ {"7.3.10", "Date and time functions"},
+ {"7.3.11", "Miscellaneous functions"},
+ {"7.3.12", "Functions for use with GROUP BY clauses"},
+ {"7.4", "CREATE DATABASE syntax"},
+ {"7.5", "DROP DATABASE syntax"},
+ {"7.6", "CREATE TABLE syntax"},
+ {"7.7", "ALTER TABLE syntax"},
+ {"7.8", "OPTIMIZE TABLE syntax"},
+ {"7.9", "DROP TABLE syntax"},
+ {"7.10", "DELETE syntax"},
+ {"7.11", "SELECT syntax"},
+ {"7.12", "JOIN syntax"},
+ {"7.13", "INSERT syntax"},
+ {"7.14", "REPLACE syntax"},
+ {"7.15", "LOAD DATA INFILE syntax"},
+ {"7.16", "UPDATE syntax"},
+ {"7.17", "USE syntax"},
+ {"7.18", "SHOW syntax (Get information about tables, columns...)"},
+ {"7.19", "EXPLAIN syntax (Get information about a SELECT)"},
+ {"7.20", "DESCRIBE syntax (Get information about columns)"},
+ {"7.21", "LOCK TABLES/UNLOCK TABLES syntax"},
+ {"7.22", "SET OPTION syntax"},
+ {"7.23", "GRANT syntax (Compatibility function)"},
+ {"7.24", "CREATE INDEX syntax (Compatibility function)"},
+ {"7.25", "DROP INDEX syntax (Compatibility function)"},
+ {"7.26", "Comment syntax"},
+ {"7.27", "CREATE FUNCTION/DROP FUNCTION syntax"},
+ {"7.28", "Is MySQL picky about reserved words?"},
+ {"8", "Example SQL queries"},
+ {"8.1", "Queries from twin project"},
+ {"8.1.1", "Find all non-distributed twins"},
+ {"8.1.2", "Show a table on twin pair status"},
+ {"9", "How safe/stable is MySQL?"},
+ {"9.1", "How stable is MySQL?"},
+ {"9.2", "Why are there is so many releases of MySQL?"},
+ {"9.3", "Checking a table for errors"},
+ {"9.4", "How to repair tables"},
+ {"9.5", "Is there anything special to do when upgrading/downgrading MySQL?"},
+ {"9.5.1", "Upgrading from a 3.21 version to 3.22"},
+ {"9.5.2", "Upgrading from a 3.20 version to 3.21"},
+ {"9.5.3", "Upgrading to another architecture"},
+ {"9.6", "Year 2000 compliance"},
+ {"10", "MySQL Server functions"},
+ {"10.1", "What languages are supported by MySQL?"},
+ {"10.1.1", "Character set used for data &#38; sorting"},
+ {"10.2", "The update log"},
+ {"10.3", "How big can MySQL tables be?"},
+ {"11", "Getting maximum performance from MySQL"},
+ {"11.1", "How does one change the size of MySQL buffers?"},
+ {"11.2", "How compiling and linking affects the speed of MySQL"},
+ {"11.3", "How does MySQL use memory?"},
+ {"11.4", "How does MySQL use indexes?"},
+ {"11.5", "What optimizations are done on WHERE clauses?"},
+ {"11.6", "How does MySQL open &#38; close tables?"},
+ {"11.6.0.1", "What are the drawbacks of creating possibly thousands of tables in a database?"},
+ {"11.7", "How does MySQL lock tables?"},
+ {"11.8", "How should I arrange my table to be as fast/small as possible?"},
+ {"11.9", "What affects the speed of INSERT statements?"},
+ {"11.10", "What affects the speed DELETE statements?"},
+ {"11.11", "How do I get MySQL to run at full speed?"},
+ {"11.12", "What are the different row formats? Or, when should VARCHAR/CHAR be used?"},
+ {"11.13", "Why so many open tables?"},
+ {"12", "MySQL benchmark suite"},
+ {"13", "MySQL Utilites"},
+ {"13.1", "Overview of the different MySQL programs"},
+ {"13.2", "The MySQL table check, optimize and repair program"},
+ {"13.2.1", "isamchk memory use"},
+ {"13.2.2", "Getting low-level table information"},
+ {"13.3", "The MySQL compressed read-only table generator"},
+ {"14", "Adding new functions to MySQL"},
+ {"15", "MySQL ODBC Support"},
+ {"15.1", "Operating systems supported by MyODBC"},
+ {"15.2", "How to report problems with MyODBC"},
+ {"15.3", "Programs known to work with MyODBC"},
+ {"15.4", "How to fill in the various fields in the ODBC administrator program"},
+ {"15.5", "How to get the value of an AUTO_INCREMENT column in ODBC"},
+ {"16", "Problems and common errors"},
+ {"16.1", "Some common errors when using MySQL"},
+ {"16.1.1", "MySQL server has gone away error"},
+ {"16.1.2", "Can't connect to local MySQL server error"},
+ {"16.1.3", "Out of memory error"},
+ {"16.1.4", "Packet too large error"},
+ {"16.1.5", "The table is full error"},
+ {"16.1.6", "Commands out of sync error in client"},
+ {"16.1.7", "Removing user error"},
+ {"16.2", "How MySQL handles a full disk"},
+ {"16.3", "How to run SQL commands from a text file"},
+ {"16.4", "Where MySQL stores temporary files"},
+ {"16.5", "Access denied error"},
+ {"16.6", "How to run MySQL as a normal user"},
+ {"16.7", "Problems with file permissions"},
+ {"16.8", "File not found"},
+ {"16.9", "Problems using DATE columns"},
+ {"16.10", "Case sensitivity in searches"},
+ {"16.11", "Problems with NULL values"},
+ {"17", "Solving some common problems with MySQL"},
+ {"17.1", "Database replication"},
+ {"17.2", "Database backups"},
+ {"18", "MySQL client tools and API's"},
+ {"18.1", "MySQL C API"},
+ {"18.2", "C API datatypes"},
+ {"18.3", "C API function overview"},
+ {"18.4", "C API function descriptions"},
+ {"18.4.1", "mysql_affected_rows()"},
+ {"18.4.2", "mysql_close()"},
+ {"18.4.3", "mysql_connect()"},
+ {"18.4.4", "mysql_create_db()"},
+ {"18.4.5", "mysql_data_seek()"},
+ {"18.4.6", "mysql_debug()"},
+ {"18.4.7", "mysql_drop_db()"},
+ {"18.4.8", "mysql_dump_debug_info()"},
+ {"18.4.9", "mysql_eof()"},
+ {"18.4.10", "mysql_errno()"},
+ {"18.4.11", "mysql_error()"},
+ {"18.4.12", "mysql_escape_string()"},
+ {"18.4.13", "mysql_fetch_field()"},
+ {"18.4.14", "mysql_fetch_fields()"},
+ {"18.4.15", "mysql_fetch_field_direct()"},
+ {"18.4.16", "mysql_fetch_lengths()"},
+ {"18.4.17", "mysql_fetch_row()"},
+ {"18.4.18", "mysql_field_seek()"},
+ {"18.4.19", "mysql_field_tell()"},
+ {"18.4.20", "mysql_free_result()"},
+ {"18.4.21", "mysql_get_client_info()"},
+ {"18.4.22", "mysql_get_host_info()"},
+ {"18.4.23", "mysql_get_proto_info()"},
+ {"18.4.24", "mysql_get_server_info()"},
+ {"18.4.25", "mysql_info()"},
+ {"18.4.26", "mysql_init()"},
+ {"18.4.27", "mysql_insert_id()"},
+ {"18.4.28", "mysql_kill()"},
+ {"18.4.29", "mysql_list_dbs()"},
+ {"18.4.30", "mysql_list_fields()"},
+ {"18.4.31", "mysql_list_processes()"},
+ {"18.4.32", "mysql_list_tables()"},
+ {"18.4.33", "mysql_num_fields()"},
+ {"18.4.34", "mysql_num_rows()"},
+ {"18.4.35", "mysql_query()"},
+ {"18.4.36", "mysql_real_connect()"},
+ {"18.4.37", "mysql_real_query()"},
+ {"18.4.38", "mysql_reload()"},
+ {"18.4.39", "mysql_row_tell()"},
+ {"18.4.40", "mysql_select_db()"},
+ {"18.4.41", "mysql_shutdown()"},
+ {"18.4.42", "mysql_stat()"},
+ {"18.4.43", "mysql_store_result()"},
+ {"18.4.44", "mysql_thread_id()"},
+ {"18.4.45", "mysql_use_result()"},
+ {"18.4.46", "Why is it that after mysql_query() returns success, mysql_store_result() sometimes returns NULL?"},
+ {"18.4.47", "What results can I get from a query?"},
+ {"18.4.48", "How can I get the unique ID for the last inserted row?"},
+ {"18.4.49", "Problems linking with the C API"},
+ {"18.4.50", "How to make a thread-safe client"},
+ {"18.5", "MySQL Perl API's"},
+ {"18.5.1", "DBI with DBD::mysql"},
+ {"18.5.1.1", "The DBI interface"},
+ {"18.5.1.2", "More DBI/DBD information"},
+ {"18.6", "MySQL Java connectivity (JDBC)"},
+ {"18.7", "MySQL PHP API's"},
+ {"18.8", "MySQL C++ API's"},
+ {"18.9", "MySQL Python API's"},
+ {"18.10", "MySQL TCL API's"},
+ {"19", "How MySQL compares to other databases"},
+ {"19.1", "How MySQL compares to mSQL"},
+ {"19.1.1", "How to convert mSQL tools for MySQL"},
+ {"19.1.2", "How mSQL and MySQL client/server communications protocols differ"},
+ {"19.1.3", "How mSQL 2.0 SQL syntax differs from MySQL"},
+ {"19.2", "How MySQL compares to PostgreSQL"},
+ {"A", "Some users of MySQL"},
+ {"B", "Contributed programs"},
+ {"C", "Contributors to MySQL"},
+ {"D", "MySQL change history"},
+ {"19.3", "Changes in release 3.22.x (Alpha version)"},
+ {"19.3.1", "Changes in release 3.22.7"},
+ {"19.3.2", "Changes in release 3.22.6"},
+ {"19.3.3", "Changes in release 3.22.5"},
+ {"19.3.4", "Changes in release 3.22.4"},
+ {"19.3.5", "Changes in release 3.22.3"},
+ {"19.3.6", "Changes in release 3.22.2"},
+ {"19.3.7", "Changes in release 3.22.1"},
+ {"19.3.8", "Changes in release 3.22.0"},
+ {"19.4", "Changes in release 3.21.x"},
+ {"19.4.1", "Changes in release 3.21.33"},
+ {"19.4.2", "Changes in release 3.21.32"},
+ {"19.4.3", "Changes in release 3.21.31"},
+ {"19.4.4", "Changes in release 3.21.30"},
+ {"19.4.5", "Changes in release 3.21.29"},
+ {"19.4.6", "Changes in release 3.21.28"},
+ {"19.4.7", "Changes in release 3.21.27"},
+ {"19.4.8", "Changes in release 3.21.26"},
+ {"19.4.9", "Changes in release 3.21.25"},
+ {"19.4.10", "Changes in release 3.21.24"},
+ {"19.4.11", "Changes in release 3.21.23"},
+ {"19.4.12", "Changes in release 3.21.22"},
+ {"19.4.13", "Changes in release 3.21.21a"},
+ {"19.4.14", "Changes in release 3.21.21"},
+ {"19.4.15", "Changes in release 3.21.20"},
+ {"19.4.16", "Changes in release 3.21.19"},
+ {"19.4.17", "Changes in release 3.21.18"},
+ {"19.4.18", "Changes in release 3.21.17"},
+ {"19.4.19", "Changes in release 3.21.16"},
+ {"19.4.20", "Changes in release 3.21.15"},
+ {"19.4.21", "Changes in release 3.21.14b"},
+ {"19.4.22", "Changes in release 3.21.14a"},
+ {"19.4.23", "Changes in release 3.21.13"},
+ {"19.4.24", "Changes in release 3.21.12"},
+ {"19.4.25", "Changes in release 3.21.11"},
+ {"19.4.26", "Changes in release 3.21.10"},
+ {"19.4.27", "Changes in release 3.21.9"},
+ {"19.4.28", "Changes in release 3.21.8"},
+ {"19.4.29", "Changes in release 3.21.7"},
+ {"19.4.30", "Changes in release 3.21.6"},
+ {"19.4.31", "Changes in release 3.21.5"},
+ {"19.4.32", "Changes in release 3.21.4"},
+ {"19.4.33", "Changes in release 3.21.3"},
+ {"19.4.34", "Changes in release 3.21.2"},
+ {"19.4.35", "Changes in release 3.21.0"},
+ {"19.5", "Changes in release 3.20.x"},
+ {"19.5.1", "Changes in release 3.20.18"},
+ {"19.5.2", "Changes in release 3.20.17"},
+ {"19.5.3", "Changes in release 3.20.16"},
+ {"19.5.4", "Changes in release 3.20.15"},
+ {"19.5.5", "Changes in release 3.20.14"},
+ {"19.5.6", "Changes in release 3.20.13"},
+ {"19.5.7", "Changes in release 3.20.11"},
+ {"19.5.8", "Changes in release 3.20.10"},
+ {"19.5.9", "Changes in release 3.20.9"},
+ {"19.5.10", "Changes in release 3.20.8"},
+ {"19.5.11", "Changes in release 3.20.7"},
+ {"19.5.12", "Changes in release 3.20.6"},
+ {"19.5.13", "Changes in release 3.20.3"},
+ {"19.5.14", "Changes in release 3.20.0"},
+ {"19.6", "Changes in release 3.19.x"},
+ {"19.6.1", "Changes in release 3.19.5"},
+ {"19.6.2", "Changes in release 3.19.4"},
+ {"19.6.3", "Changes in release 3.19.3"},
+ {"E", "Known errors and design deficiencies in MySQL"},
+ {"F", "List of things we want to add to MySQL in the future (The TODO)"},
+ {"19.7", "Things that must done in the real near future"},
+ {"19.8", "Things that have to be done sometime"},
+ {"19.9", "Some things we don't have any plans to do"},
+ {"G", "Comments on porting to other systems"},
+ {"19.10", "Debugging MySQL"},
+ {"19.11", "Comments about RTS threads"},
+ {"19.12", "What is the difference between different thread packages?"},
+ {"H", "Description of MySQL regular expression syntax"},
+ {"I", "What is Unireg?"},
+ {"J", "The MySQL server license"},
+ {"K", "The MySQL license for Microsoft operating systems"},
+ {"*", "SQL command, type and function index"},
+ {"*", "Concept Index"}
+};
+
+#define NQUERIES 5
+const char *query[NQUERIES]={
+ "mysql information and manual",
+ "upgrading from previous version",
+ "column indexes",
+ "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
new file mode 100644
index 00000000000..cff5cb36baa
--- /dev/null
+++ b/myisam/ft_update.c
@@ -0,0 +1,189 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 */
+
+/* functions to work with full-text indices */
+
+#include "ftdefs.h"
+
+/**************************************************************
+ This is to make ft-code to ignore keyseg.length at all *
+ and to index the whole VARCHAR/BLOB instead... */
+#undef set_if_smaller
+#define set_if_smaller(A,B) /* no op */
+/**************************************************************/
+
+
+/* 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)
+{
+ TREE *parsed=NULL;
+ MI_KEYSEG *keyseg;
+ byte *pos;
+ uint i;
+
+ i=info->s->keyinfo[keynr].keysegs-FT_SEGS;
+ keyseg=info->s->keyinfo[keynr].seg;
+ while(i--)
+ {
+ uint len;
+
+ 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;
+
+ parsed=ft_parse(parsed, pos, len);
+ if(parsed==NULL) return NULL;
+ }
+ return ft_linearize(info, keynr, keybuf, parsed);
+}
+
+static int _mi_ft_store(MI_INFO *info, uint keynr, byte *keybuf,
+ FT_WORD *wlist, my_off_t filepos)
+{
+ uint key_length;
+
+ while(wlist->pos)
+ {
+ key_length=_ft_make_key(info,keynr,keybuf,wlist,filepos);
+ if (_mi_ck_write(info,keynr,(uchar*) keybuf,key_length))
+ return 1;
+ wlist++;
+ }
+ return 0;
+}
+
+static int _mi_ft_erase(MI_INFO *info, uint keynr, byte *keybuf, FT_WORD *wlist, my_off_t filepos)
+{
+ uint key_length, err=0;
+
+ while(wlist->pos)
+ {
+ key_length=_ft_make_key(info,keynr,keybuf,wlist,filepos);
+ if (_mi_ck_delete(info,keynr,(uchar*) keybuf,key_length))
+ err=1;
+ wlist++;
+ }
+ return err;
+}
+
+/* compares an appropriate parts of two WORD_KEY keys directly out of records */
+/* returns 1 if they are different */
+
+#define THOSE_TWO_DAMN_KEYS_ARE_REALLY_DIFFERENT 1
+#define GEE_THEY_ARE_ABSOLUTELY_IDENTICAL 0
+
+int _mi_ft_cmp(MI_INFO *info, uint keynr, const byte *rec1, const byte *rec2)
+{
+ MI_KEYSEG *keyseg;
+ byte *pos1, *pos2;
+ uint i;
+
+ i=info->s->keyinfo[keynr].keysegs-FT_SEGS;
+ keyseg=info->s->keyinfo[keynr].seg;
+ while(i--)
+ {
+ 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)
+ {
+ 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);
+ }
+ if ((len1 != len2) || memcmp(pos1, pos2, len1))
+ return THOSE_TWO_DAMN_KEYS_ARE_REALLY_DIFFERENT;
+ }
+ return GEE_THEY_ARE_ABSOLUTELY_IDENTICAL;
+}
+
+/* adds a document to the collection */
+int _mi_ft_add(MI_INFO *info, uint keynr, byte *keybuf, const byte *record, my_off_t pos)
+{
+ FT_WORD *wlist;
+
+ if(!(wlist=_mi_ft_parserecord(info, keynr, keybuf, record))) return -1;
+ return _mi_ft_store(info,keynr,keybuf,wlist,pos);
+}
+
+/* removes a document from the collection */
+int _mi_ft_del(MI_INFO *info, uint keynr, byte *keybuf, const byte *record, my_off_t pos)
+{
+ FT_WORD *wlist;
+ if(!(wlist=_mi_ft_parserecord(info, keynr, keybuf, record))) return -1;
+ return _mi_ft_erase(info,keynr,keybuf,wlist,pos);
+}
+
+uint _ft_make_key(MI_INFO *info, uint keynr, byte *keybuf, FT_WORD *wptr, my_off_t filepos)
+{
+ byte buf[HA_FT_MAXLEN+16];
+
+#if HA_FT_WTYPE == HA_KEYTYPE_FLOAT
+ float weight=(float) ((filepos==HA_OFFSET_ERROR) ? 0 : wptr->weight);
+ mi_float4store(buf,weight);
+#else
+#error
+#endif
+
+#ifdef EVAL_RUN
+ *(buf+HA_FT_WLEN)=wptr->cnt;
+ int2store(buf+HA_FT_WLEN+1,wptr->len);
+ memcpy(buf+HA_FT_WLEN+3,wptr->pos,wptr->len);
+#else /* EVAL_RUN */
+ int2store(buf+HA_FT_WLEN,wptr->len);
+ memcpy(buf+HA_FT_WLEN+2,wptr->pos,wptr->len);
+#endif /* EVAL_RUN */
+ return _mi_make_key(info,keynr,(uchar*) keybuf,buf,filepos);
+}
diff --git a/myisam/ftdefs.h b/myisam/ftdefs.h
new file mode 100644
index 00000000000..ebf99e84d5a
--- /dev/null
+++ b/myisam/ftdefs.h
@@ -0,0 +1,99 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 */
+
+/* some definitions for full-text indices */
+
+#include "fulltext.h"
+#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
+ NORM_PIVOT was taken from the article
+ A.Singhal, C.Buckley, M.Mitra, "Pivoted Document Length Normalization",
+ ACM SIGIR'96, 21-29, 1996
+ */
+
+#define LWS_FOR_QUERY LWS_TF
+#define LWS_IN_USE LWS_LOG
+#define PRENORM_IN_USE PRENORM_AVG
+#define NORM_IN_USE NORM_PIVOT
+#define GWS_IN_USE GWS_PROB
+/*==============================================================*/
+#define LWS_TF (count)
+#define LWS_BINARY (count>0)
+#define LWS_SQUARE (count*count)
+#define LWS_LOG (count?(log(count)+1):0)
+/*--------------------------------------------------------------*/
+#define PRENORM_NONE (p->weight)
+#define PRENORM_MAX (p->weight/docstat.max)
+#define PRENORM_AUG (0.4+0.6*p->weight/docstat.max)
+#define PRENORM_AVG (p->weight/docstat.sum*docstat.uniq)
+#define PRENORM_AVGLOG ((1+log(p->weight))/(1+log(docstat.sum/docstat.uniq)))
+/*--------------------------------------------------------------*/
+#define NORM_NONE (1)
+#define NORM_SUM (docstat.nsum)
+#define NORM_COS (sqrt(docstat.nsum2))
+
+#ifdef EVAL_RUN
+/*
+extern ulong collstat;
+#define PIVOT_STAT (docstat.uniq)
+#define PIVOT_SLOPE (0.69)
+#define PIVOT_PIVOT ((double)collstat/(info->state->records+1))
+#define NORM_PIVOT ((1-PIVOT_SLOPE)*PIVOT_PIVOT+PIVOT_SLOPE*docstat.uniq)
+*/
+#endif /* EVAL_RUN */
+
+#define PIVOT_VAL (0.0115)
+#define NORM_PIVOT (1+PIVOT_VAL*docstat.uniq)
+/*---------------------------------------------------------------*/
+#define GWS_NORM (1/sqrt(sum2))
+#define GWS_GFIDF (sum/doc_cnt)
+/* Mysterious, but w/o (double) GWS_IDF performs better :-o */
+#define GWS_IDF log(aio->info->state->records/doc_cnt)
+#define GWS_IDF1 log((double)aio->info->state->records/doc_cnt)
+#define GWS_PROB log(((double)(aio->info->state->records-doc_cnt))/doc_cnt)
+#define GWS_FREQ (1.0/doc_cnt)
+#define GWS_SQUARED pow(log((double)aio->info->state->records/doc_cnt),2)
+#define GWS_CUBIC pow(log((double)aio->info->state->records/doc_cnt),3)
+#define GWS_ENTROPY (1-(suml/sum-log(sum))/log(aio->info->state->records))
+/*=================================================================*/
+
+typedef struct st_ft_word {
+ byte * pos;
+ uint len;
+ double weight;
+#ifdef EVAL_RUN
+ byte cnt;
+#endif /* EVAL_RUN */
+} FT_WORD;
+
+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 *);
diff --git a/myisam/fulltext.h b/myisam/fulltext.h
new file mode 100644
index 00000000000..3555abe1a1c
--- /dev/null
+++ b/myisam/fulltext.h
@@ -0,0 +1,42 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 */
+
+/* some definitions for full-text indices */
+
+#include "myisamdef.h"
+#include "ft_global.h"
+
+/* 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
+#define FT_SEGS 3
+#else /* EVAL_RUN */
+#define FT_SEGS 2
+#endif /* EVAL_RUN */
+
+extern const MI_KEYSEG ft_keysegs[FT_SEGS];
+
+extern const char *ft_precompiled_stopwords[];
+
+int _mi_ft_cmp(MI_INFO *, uint, const byte *, const byte *);
+int _mi_ft_add(MI_INFO *, uint, byte *, const byte *, my_off_t);
+int _mi_ft_del(MI_INFO *, uint, byte *, const byte *, my_off_t);
diff --git a/myisam/make-ccc b/myisam/make-ccc
new file mode 100755
index 00000000000..6d1303729db
--- /dev/null
+++ b/myisam/make-ccc
@@ -0,0 +1,5 @@
+rm -f .deps/*.P
+ccc -DMAP_TO_USE_RAID -I./../include -I../include -DDBUG_OFF -fast -O3 -c mi_cache.c mi_changed.c mi_checksum.c mi_close.c mi_create.c mi_dbug.c mi_delete.c mi_delete_all.c mi_delete_table.c mi_dynrec.c mi_extra.c mi_info.c mi_key.c mi_locking.c mi_log.c mi_open.c mi_packrec.c mi_page.c mi_panic.c mi_range.c mi_rename.c mi_rfirst.c mi_rkey.c mi_rlast.c mi_rnext.c mi_rnext_same.c mi_rprev.c mi_rrnd.c mi_rsame.c mi_rsamepos.c mi_scan.c mi_search.c mi_static.c mi_statrec.c mi_unique.c mi_update.c mi_write.c ft_update.c ft_search.o ft_stem.o ft_stopwords.c ft_parser.c
+make sort.o mi_check.o
+rm libmyisam.a
+ar -cr libmyisam.a mi_cache.o sort.o mi_check.o
diff --git a/myisam/mi_cache.c b/myisam/mi_cache.c
new file mode 100644
index 00000000000..f2f7af8eac3
--- /dev/null
+++ b/myisam/mi_cache.c
@@ -0,0 +1,101 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* Functions for read record cacheing with myisam */
+/* Used instead of my_b_read() to allow for no-cacheed seeks */
+
+#include "myisamdef.h"
+#define READING_NEXT 1
+#define READING_HEADER 2
+
+ /* Copy block from cache if it`s in it. If re_read_if_possibly is */
+ /* set read to cache (if after current file-position) else read to */
+ /* buff */
+
+int _mi_read_cache(IO_CACHE *info, byte *buff, my_off_t pos, uint length,
+ int flag)
+{
+ uint read_length,in_buff_length;
+ my_off_t offset;
+ char *in_buff_pos;
+ DBUG_ENTER("_mi_read_cache");
+
+ if (pos < info->pos_in_file)
+ {
+ read_length=length;
+ if ((my_off_t) read_length > (my_off_t) (info->pos_in_file-pos))
+ read_length=(uint) (info->pos_in_file-pos);
+ info->seek_not_done=1;
+ VOID(my_seek(info->file,pos,MY_SEEK_SET,MYF(0)));
+ if (my_read(info->file,buff,read_length,MYF(MY_NABP)))
+ DBUG_RETURN(1);
+ if (!(length-=read_length))
+ DBUG_RETURN(0);
+ pos+=read_length;
+ buff+=read_length;
+ }
+ if ((offset= (my_off_t) (pos - info->pos_in_file)) <
+ (my_off_t) (info->rc_end - info->rc_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);
+ if (!(length-=in_buff_length))
+ DBUG_RETURN(0);
+ pos+=in_buff_length;
+ buff+=in_buff_length;
+ }
+ else
+ in_buff_length=0;
+ if (flag & READING_NEXT)
+ {
+ if (pos != ((info)->pos_in_file +
+ (uint) ((info)->rc_end - (info)->rc_request_pos)))
+ {
+ info->pos_in_file=pos; /* Force start here */
+ info->rc_pos=info->rc_end=info->rc_request_pos; /* Everything used */
+ info->seek_not_done=1;
+ }
+ else
+ info->rc_pos=info->rc_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)
+ {
+ if (!my_errno)
+ my_errno=HA_ERR_WRONG_IN_RECORD;
+ DBUG_RETURN(1);
+ }
+ bzero(buff+info->error,MI_BLOCK_INFO_HEADER_LENGTH - in_buff_length -
+ (uint) info->error);
+ DBUG_RETURN(0);
+ }
+ info->seek_not_done=1;
+ VOID(my_seek(info->file,pos,MY_SEEK_SET,MYF(0)));
+ if ((read_length=my_read(info->file,buff,length,MYF(0))) == length)
+ DBUG_RETURN(0);
+ if (!(flag & READING_HEADER) || (int) read_length == -1 ||
+ read_length+in_buff_length < 3)
+ {
+ if (!my_errno)
+ my_errno=HA_ERR_WRONG_IN_RECORD;
+ DBUG_RETURN(1);
+ }
+ bzero(buff+read_length,MI_BLOCK_INFO_HEADER_LENGTH - in_buff_length -
+ read_length);
+ DBUG_RETURN(0);
+} /* _mi_read_cache */
diff --git a/myisam/mi_changed.c b/myisam/mi_changed.c
new file mode 100644
index 00000000000..bd6b14b0c6c
--- /dev/null
+++ b/myisam/mi_changed.c
@@ -0,0 +1,34 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* Check if somebody has changed table since last check. */
+
+#include "myisamdef.h"
+
+ /* Return 0 if table isn't changed */
+
+int mi_is_changed(MI_INFO *info)
+{
+ int result;
+ DBUG_ENTER("mi_is_changed");
+ if (_mi_readinfo(info,F_RDLCK,1))
+ DBUG_RETURN(-1);
+ VOID(_mi_writeinfo(info,0));
+ result=(int) info->data_changed;
+ info->data_changed=0;
+ DBUG_PRINT("exit",("result: %d",result));
+ DBUG_RETURN(result);
+}
diff --git a/myisam/mi_check.c b/myisam/mi_check.c
new file mode 100644
index 00000000000..5b5583b136e
--- /dev/null
+++ b/myisam/mi_check.c
@@ -0,0 +1,2886 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* Descript, check and repair of ISAM tables */
+
+#include "myisamdef.h"
+
+#include <m_ctype.h>
+#include <stdarg.h>
+#include <getopt.h>
+#include <assert.h>
+#ifdef HAVE_SYS_VADVICE_H
+#include <sys/vadvise.h>
+#endif
+#ifdef HAVE_SYS_MMAN_H
+#include <sys/mman.h>
+#endif
+
+#ifndef USE_RAID
+#define my_raid_create(A,B,C,D,E,F,G) my_create(A,B,C,G)
+#define my_raid_delete(A,B,C) my_delete(A,B)
+#endif
+
+ /* Functions defined in this file */
+
+static int check_k_link(MI_CHECK *param, MI_INFO *info,uint nr);
+static int chk_index(MI_CHECK *param, MI_INFO *info, MI_KEYDEF *keyinfo,
+ my_off_t page, uchar *buff, ha_rows *keys,
+ ha_checksum *key_checksum, uint level);
+static uint isam_key_length(MI_INFO *info,MI_KEYDEF *keyinfo);
+static ha_checksum calc_checksum(ha_rows count);
+static int writekeys(MI_INFO *info,byte *buff,my_off_t filepos);
+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_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);
+static my_off_t get_record_for_key(MI_INFO *info,MI_KEYDEF *keyinfo,
+ uchar *key);
+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 SORT_KEY_BLOCKS *alloc_key_blocks(MI_CHECK *param, uint blocks,
+ uint buffer_length);
+static void update_key_parts(MI_KEYDEF *keyinfo,
+ ulong *rec_per_key_part,
+ ulonglong *unique,
+ ulonglong records);
+static ha_checksum mi_byte_checksum(const byte *buf, uint length);
+
+
+#ifdef __WIN__
+static double ulonglong2double(ulonglong value)
+{
+ longlong nr=(longlong) value;
+ if (nr >= 0)
+ return (double) nr;
+ return (18446744073709551616.0 + (double) nr);
+}
+
+#if SIZEOF_OFF_T > 4
+#define my_off_t2double(A) ulonglong2double(A)
+#else
+#define my_off_t2double(A) ((double) (A))
+#endif /* SIZEOF_OFF_T > 4 */
+#endif
+
+void myisamchk_init(MI_CHECK *param)
+{
+ bzero((gptr) param,sizeof(*param));
+ param->opt_follow_links=1;
+ param->keys_in_use= ~(ulonglong) 0;
+ param->search_after_block=HA_OFFSET_ERROR;
+ param->auto_increment_value= 0;
+ param->use_buffers=USE_BUFFER_INIT;
+ param->read_buffer_length=READ_BUFFER_INIT;
+ param->write_buffer_length=READ_BUFFER_INIT;
+ param->sort_buffer_length=SORT_BUFFER_INIT;
+ param->sort_key_blocks=BUFFERS_WHEN_SORTING;
+ param->tmpfile_createflag=O_RDWR | O_TRUNC | O_EXCL;
+ param->myf_rw=MYF(MY_NABP | MY_WME | MY_WAIT_IF_FULL);
+ param->sort_info.param=param;
+}
+
+ /* Check delete links */
+
+int chk_del(MI_CHECK *param, register MI_INFO *info, uint test_flag)
+{
+ reg2 ha_rows i;
+ uint j,delete_link_length;
+ my_off_t empty,next_link,old_link;
+ char buff[22],buff2[22];
+ DBUG_ENTER("chk_del");
+
+ if (!(test_flag & T_SILENT))
+ puts("- check key delete-chain");
+
+ LINT_INIT(old_link);
+ param->record_checksum=0;
+ param->key_file_blocks=info->s->base.keystart;
+ for (j=0 ; j < info->s->state.header.max_block_size ; j++)
+ if (check_k_link(param,info,j))
+ goto wrong;
+ delete_link_length=((info->s->options & HA_OPTION_PACK_RECORD) ? 20 :
+ info->s->rec_reflength+1);
+
+ if (!(test_flag & T_SILENT))
+ puts("- check record delete-chain");
+
+ next_link=info->s->state.dellink;
+ if (info->state->del == 0)
+ {
+ if (test_flag & T_VERBOSE)
+ {
+ puts("No recordlinks");
+ }
+ }
+ else
+ {
+ if (test_flag & T_VERBOSE)
+ printf("Recordlinks: ");
+ empty=0;
+ for (i= info->state->del ; i > 0L && next_link != HA_OFFSET_ERROR ; i--)
+ {
+ if (test_flag & T_VERBOSE)
+ printf(" %9s",llstr(next_link,buff));
+ if (next_link >= info->state->data_file_length)
+ goto wrong;
+ if (my_pread(info->dfile,(char*) buff,delete_link_length,
+ next_link,MYF(MY_NABP)))
+ {
+ if (test_flag & T_VERBOSE) puts("");
+ mi_check_print_error(param,"Can't read delete-link at filepos: %s",
+ llstr(next_link,buff));
+ DBUG_RETURN(1);
+ }
+ if (*buff != '\0')
+ {
+ if (test_flag & T_VERBOSE) puts("");
+ mi_check_print_error(param,"Record at pos: %s is not remove-marked",
+ llstr(next_link,buff));
+ goto wrong;
+ }
+ if (info->s->options & HA_OPTION_PACK_RECORD)
+ {
+ my_off_t prev_link=mi_sizekorr(buff+12);
+ if (empty && prev_link != old_link)
+ {
+ if (test_flag & T_VERBOSE) puts("");
+ mi_check_print_error(param,"Deleted block at %s doesn't point back at previous delete link",llstr(next_link,buff2));
+ goto wrong;
+ }
+ old_link=next_link;
+ next_link=mi_sizekorr(buff+4);
+ empty+=mi_uint3korr(buff+1);
+ }
+ else
+ {
+ param->record_checksum+=(ha_checksum) next_link;
+ next_link=_mi_rec_pos(info->s,(uchar*) buff+1);
+ empty+=info->s->base.pack_reclength;
+ }
+ }
+ if (empty != info->state->empty)
+ {
+ if (test_flag & T_VERBOSE) puts("");
+ mi_check_print_warning(param,
+ "Not used space is supposed to be: %s but is: %s",
+ llstr(info->state->empty,buff),
+ llstr(empty,buff2));
+ info->state->empty=empty;
+ }
+ if (i != 0 || next_link != HA_OFFSET_ERROR)
+ goto wrong;
+
+ if (test_flag & T_VERBOSE) puts("\n");
+ }
+ DBUG_RETURN(0);
+wrong:
+ if (test_flag & T_VERBOSE) puts("");
+ mi_check_print_error(param,"record delete-link-chain corrupted");
+ DBUG_RETURN(1);
+} /* chk_del */
+
+
+ /* Check delete links in index file */
+
+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;
+ ha_rows records;
+ char llbuff[21],*buff;
+ DBUG_ENTER("check_k_link");
+
+ if (param->testflag & T_VERBOSE)
+ printf("block_size %4d:",block_size);
+
+ next_link=info->s->state.key_del[nr];
+ records= (ha_rows) (info->state->key_file_length / block_size);
+ while (next_link != HA_OFFSET_ERROR && records > 0)
+ {
+ if (param->testflag & T_VERBOSE)
+ printf("%16s",llstr(next_link,llbuff));
+ if (next_link > info->state->key_file_length ||
+ next_link & (info->s->blocksize-1))
+ DBUG_RETURN(1);
+ if (!(buff=key_cache_read(info->s->kfile, next_link, info->buff,
+ myisam_block_size, block_size, 1)))
+ DBUG_RETURN(1);
+ next_link=mi_sizekorr(buff);
+ records--;
+ param->key_file_blocks+=block_size;
+ }
+ if (param->testflag & T_VERBOSE)
+ {
+ if (next_link != HA_OFFSET_ERROR)
+ printf("%16s\n",llstr(next_link,llbuff));
+ else
+ puts("");
+ }
+ DBUG_RETURN (next_link != HA_OFFSET_ERROR);
+} /* check_k_link */
+
+
+ /* Kontrollerar storleken p} filerna */
+
+int chk_size(MI_CHECK *param, register MI_INFO *info)
+{
+ int error=0;
+ register my_off_t skr,size;
+ char buff[22],buff2[22];
+ DBUG_ENTER("chk_size");
+
+ if (!(param->testflag & T_SILENT)) puts("- check file-size");
+
+ flush_key_blocks(info->s->kfile, FLUSH_FORCE_WRITE); /* If called externally */
+
+ size=my_seek(info->s->kfile,0L,MY_SEEK_END,MYF(0));
+ if ((skr=(my_off_t) info->state->key_file_length) != size)
+ {
+ if (skr > size)
+ {
+ error=1;
+ mi_check_print_error(param,
+ "Size of indexfile is: %-8s Should be: %s",
+ llstr(size,buff), llstr(skr,buff2));
+ }
+ else
+ mi_check_print_warning(param,
+ "Size of indexfile is: %-8s Should be: %s",
+ llstr(size,buff), llstr(skr,buff2));
+ }
+ if (!(param->testflag & T_VERY_SILENT) &&
+ ! (info->s->options & HA_OPTION_COMPRESS_RECORD) &&
+ ulonglong2double(info->state->key_file_length) >
+ ulonglong2double(info->s->base.margin_key_file_length)*0.9)
+ mi_check_print_warning(param,"Keyfile is almost full, %10s of %10s used",
+ llstr(info->state->key_file_length,buff),
+ llstr(info->s->base.max_key_file_length-1,buff));
+
+ size=my_seek(info->dfile,0L,MY_SEEK_END,MYF(0));
+ skr=(my_off_t) info->state->data_file_length;
+ if (info->s->options & HA_OPTION_COMPRESS_RECORD)
+ skr+= MEMMAP_EXTRA_MARGIN;
+#ifdef USE_RELOC
+ if (info->data_file_type == STATIC_RECORD &&
+ skr < (my_off_t) info->s->base.reloc*info->s->base.min_pack_length)
+ skr=(my_off_t) info->s->base.reloc*info->s->base.min_pack_length;
+#endif
+ if (skr != size)
+ {
+ info->state->data_file_length=size; /* Skipp other errors */
+ if (skr > size && skr != size + MEMMAP_EXTRA_MARGIN)
+ {
+ error=1;
+ mi_check_print_error(param,"Size of datafile is: %-8s Should be: %s",
+ llstr(size,buff), llstr(skr,buff2));
+ }
+ else
+ {
+ mi_check_print_warning(param,
+ "Size of datafile is: %-8s Should be: %s",
+ llstr(size,buff), llstr(skr,buff2));
+ }
+ }
+ if (!(param->testflag & T_VERY_SILENT) &&
+ !(info->s->options & HA_OPTION_COMPRESS_RECORD) &&
+ ulonglong2double(info->state->data_file_length) >
+ (ulonglong2double(info->s->base.max_data_file_length)*0.9))
+ mi_check_print_warning(param, "Datafile is almost full, %10s of %10s used",
+ llstr(info->state->data_file_length,buff),
+ llstr(info->s->base.max_data_file_length-1,buff2));
+ DBUG_RETURN(error);
+} /* chk_size */
+
+
+ /* Check keys */
+
+int chk_key(MI_CHECK *param, register MI_INFO *info)
+{
+ uint key,found_keys=0,full_text_keys=0;
+ ha_rows keys;
+ ha_checksum old_record_checksum,init_checksum;
+ my_off_t all_keydata,all_totaldata,key_totlength,length;
+ ulong *rec_per_key_part;
+ MYISAM_SHARE *share=info->s;
+ MI_KEYDEF *keyinfo;
+ char buff[22],buff2[22];
+ DBUG_ENTER("chk_key");
+
+ if (!(param->testflag & T_SILENT)) puts("- check index reference");
+
+ all_keydata=all_totaldata=key_totlength=0;
+ old_record_checksum=0;
+ init_checksum=param->record_checksum;
+ if (!(share->options &
+ (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)))
+ old_record_checksum=calc_checksum(info->state->records+info->state->del-1)*
+ share->base.pack_reclength;
+ rec_per_key_part= param->rec_per_key_part;
+ for (key= 0,keyinfo= &share->keyinfo[0]; key < share->base.keys ;
+ rec_per_key_part+=keyinfo->keysegs, key++, keyinfo++)
+ {
+ param->key_crc[key]=0;
+ if (!(((ulonglong) 1 << key) & share->state.key_map))
+ continue;
+ found_keys++;
+
+ param->record_checksum=init_checksum;
+ bzero((char*) &param->unique_count,sizeof(param->unique_count));
+ if ((!(param->testflag & T_SILENT)))
+ printf ("- check data record references index: %d\n",key+1);
+ if (share->state.key_root[key] == HA_OFFSET_ERROR &&
+ info->state->records == 0)
+ continue;
+ if (!_mi_fetch_keypage(info,keyinfo,share->state.key_root[key],info->buff,
+ 0))
+ {
+ mi_check_print_error(param,"Can't read indexpage from filepos: %s",
+ llstr(share->state.key_root[key],buff));
+ DBUG_RETURN(-1);
+ }
+ param->key_file_blocks+=keyinfo->block_length;
+ keys=0;
+ param->keydata=param->totaldata=0;
+ param->key_blocks=0;
+ param->max_level=0;
+ if (chk_index(param,info,keyinfo,share->state.key_root[key],info->buff,
+ &keys, param->key_crc+key,1))
+ DBUG_RETURN(-1);
+ if(!(keyinfo->flag & HA_FULLTEXT))
+ {
+ if (keys != info->state->records)
+ {
+ mi_check_print_error(param,"Found %s keys of %s",llstr(keys,buff),
+ llstr(info->state->records,buff2));
+ DBUG_RETURN(-1);
+ }
+ if (found_keys - full_text_keys == 1 &&
+ ((share->options &
+ (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)) ||
+ (param->testflag & T_DONT_CHECK_CHECKSUM)))
+ old_record_checksum=param->record_checksum;
+ else if (old_record_checksum != param->record_checksum)
+ {
+ if (key)
+ mi_check_print_error(param,"Key %u doesn't point at same records that key 1",
+ key+1);
+ else
+ mi_check_print_error(param,"Key 1 doesn't point at all records");
+ DBUG_RETURN(-1);
+ }
+ }
+ else
+ full_text_keys++;
+ /* Check that auto_increment key is bigger than max key value */
+ if ((uint) share->base.auto_key -1 == key)
+ {
+ ulonglong save_auto_value=info->s->state.auto_increment;
+ info->s->state.auto_increment=0;
+ info->lastinx=key;
+ _mi_read_key_record(info, 0L, info->rec_buff);
+ update_auto_increment(info, info->rec_buff);
+ if (info->s->state.auto_increment > save_auto_value)
+ {
+ mi_check_print_warning(param,
+ "Auto-increment value: %s is smaller than max used value: %s",
+ llstr(save_auto_value,buff2),
+ llstr(info->s->state.auto_increment, buff));
+ }
+ if (param->testflag & T_AUTO_INC)
+ {
+ set_if_bigger(info->s->state.auto_increment,
+ param->auto_increment_value);
+ }
+ else
+ info->s->state.auto_increment=save_auto_value;
+ }
+
+ length=(my_off_t) isam_key_length(info,keyinfo)*keys + param->key_blocks*2;
+ if (param->testflag & T_INFO && param->totaldata != 0L && keys != 0L)
+ printf("Key: %2d: Keyblocks used: %3d%% Packed: %4d%% Max levels: %2d\n",
+ key+1,
+ (int) (my_off_t2double(param->keydata)*100.0/my_off_t2double(param->totaldata)),
+ (int) ((my_off_t2double(length) - my_off_t2double(param->keydata))*100.0/
+ my_off_t2double(length)),
+ param->max_level);
+ all_keydata+=param->keydata; all_totaldata+=param->totaldata; key_totlength+=length;
+
+ if (param->testflag & T_STATISTICS)
+ update_key_parts(keyinfo, rec_per_key_part, param->unique_count,
+ (ulonglong) info->state->records);
+ }
+ if (param->testflag & T_INFO)
+ {
+ if (all_totaldata != 0L && found_keys > 0)
+ printf("Total: Keyblocks used: %3d%% Packed: %4d%%\n\n",
+ (int) (my_off_t2double(all_keydata)*100.0/
+ my_off_t2double(all_totaldata)),
+ (int) ((my_off_t2double(key_totlength) -
+ my_off_t2double(all_keydata))*100.0/
+ my_off_t2double(key_totlength)));
+ else if (all_totaldata != 0L && share->state.key_map)
+ puts("");
+ }
+ if (param->key_file_blocks != info->state->key_file_length &&
+ param->keys_in_use != ~(ulonglong) 0)
+ mi_check_print_warning(param, "Some data are unreferenced in keyfile");
+ if (found_keys != full_text_keys)
+ param->record_checksum=old_record_checksum-init_checksum; /* Remove delete links */
+ else
+ param->record_checksum=0;
+ DBUG_RETURN(0);
+} /* chk_key */
+
+
+ /* Check if index is ok */
+
+static int chk_index(MI_CHECK *param, MI_INFO *info, MI_KEYDEF *keyinfo,
+ my_off_t page, uchar *buff, ha_rows *keys,
+ ha_checksum *key_checksum, uint level)
+{
+ int flag;
+ uint used_length,comp_flag,nod_flag,key_length,not_used;
+ uchar key[MI_MAX_POSSIBLE_KEY_BUFF],*temp_buff,*keypos,*old_keypos,*endpos;
+ my_off_t next_page,record;
+ char llbuff[22],llbuff2[22];
+ DBUG_ENTER("chk_index");
+ DBUG_DUMP("buff",(byte*) buff,mi_getint(buff));
+
+ if (!(temp_buff=(uchar*) my_alloca((uint) keyinfo->block_length)))
+ {
+ mi_check_print_error(param,"Not Enough memory");
+ DBUG_RETURN(-1);
+ }
+
+ if (keyinfo->flag & HA_NOSAME)
+ comp_flag=SEARCH_FIND | SEARCH_UPDATE; /* Not real duplicates */
+ else
+ comp_flag=SEARCH_SAME; /* Keys in positionorder */
+ nod_flag=mi_test_if_nod(buff);
+ used_length=mi_getint(buff);
+ keypos=buff+2+nod_flag;
+ endpos=buff+used_length;
+
+ param->keydata+=used_length; param->totaldata+=keyinfo->block_length; /* INFO */
+ param->key_blocks++;
+ if (level > param->max_level)
+ param->max_level=level;
+
+ if (used_length > keyinfo->block_length)
+ {
+ mi_check_print_error(param,"Wrong pageinfo at page: %s", llstr(page,llbuff));
+ goto err;
+ }
+ for ( ;; )
+ {
+ if (nod_flag)
+ {
+ next_page=_mi_kpos(nod_flag,keypos);
+ if (next_page > info->state->key_file_length ||
+ (nod_flag && (next_page & (info->s->blocksize -1))))
+ {
+ my_off_t max_length=my_seek(info->s->kfile,0L,MY_SEEK_END,MYF(0));
+ mi_check_print_error(param,"Wrong pagepointer: %s at page: %s",
+ llstr(next_page,llbuff),llstr(page,llbuff2));
+
+ if (next_page+info->s->blocksize > max_length)
+ goto err;
+ info->state->key_file_length=(max_length &
+ ~ (my_off_t) (info->s->blocksize-1));
+ }
+ if (!_mi_fetch_keypage(info,keyinfo,next_page,temp_buff,0))
+ {
+ mi_check_print_error(param,"Can't read key from filepos: %s",llstr(next_page,llbuff));
+ goto err;
+ }
+ param->key_file_blocks+=keyinfo->block_length;
+ if (chk_index(param,info,keyinfo,next_page,temp_buff,keys,key_checksum,
+ level+1))
+ goto err;
+ }
+ old_keypos=keypos;
+ if (keypos >= endpos ||
+ (key_length=(*keyinfo->get_key)(keyinfo,nod_flag,&keypos,key)) == 0)
+ break;
+ if (keypos > endpos)
+ {
+ mi_check_print_error(param,"Wrong key block length at page: %s",llstr(page,llbuff));
+ goto err;
+ }
+ if ((*keys)++ &&
+ (flag=_mi_key_cmp(keyinfo->seg,info->lastkey,key,key_length,
+ comp_flag, &not_used)) >=0)
+ {
+ DBUG_DUMP("old",(byte*) info->lastkey, info->lastkey_length);
+ DBUG_DUMP("new",(byte*) key, key_length);
+ DBUG_DUMP("new_in_page",(char*) old_keypos,(uint) (keypos-old_keypos));
+
+ if (comp_flag & SEARCH_FIND && flag == 0)
+ mi_check_print_error(param,"Found duplicated key at page %s",llstr(page,llbuff));
+ else
+ mi_check_print_error(param,"Key in wrong position at page %s",llstr(page,llbuff));
+ goto err;
+ }
+ if (param->testflag & T_STATISTICS)
+ {
+ if (*keys == 1L) /* first_key */
+ param->unique_count[keyinfo->keysegs]++;
+ else
+ {
+ uint diff;
+ _mi_key_cmp(keyinfo->seg,info->lastkey,key,USE_WHOLE_KEY,SEARCH_FIND,
+ &diff);
+ param->unique_count[diff-1]++;
+ }
+ }
+ (*key_checksum)+= mi_byte_checksum((byte*) key,
+ key_length- info->s->rec_reflength);
+ memcpy((char*) info->lastkey,(char*) key,key_length);
+ info->lastkey_length=key_length;
+ record= _mi_dpos(info,0,key+key_length);
+ if (record >= info->state->data_file_length)
+ {
+#ifndef DBUG_OFF
+ char llbuff3[22];
+#endif
+ mi_check_print_error(param,"Found key at page %s that points to record outside datafile",llstr(page,llbuff));
+ DBUG_PRINT("test",("page: %s record: %s filelength: %s",
+ llstr(page,llbuff),llstr(record,llbuff2),
+ llstr(info->state->data_file_length,llbuff3)));
+ DBUG_DUMP("key",(byte*) info->lastkey,key_length);
+ DBUG_DUMP("new_in_page",(char*) old_keypos,(uint) (keypos-old_keypos));
+ goto err;
+ }
+ param->record_checksum+=(ha_checksum) record;
+ }
+ if (keypos != endpos)
+ {
+ mi_check_print_error(param,"Keyblock size at page %s is not correct. Block length: %d key length: %d",
+ llstr(page,llbuff), used_length, (keypos - buff));
+ goto err;
+ }
+ my_afree((byte*) temp_buff);
+ DBUG_RETURN(0);
+ err:
+ my_afree((byte*) temp_buff);
+ DBUG_RETURN(1);
+} /* chk_index */
+
+
+ /* Calculate a checksum of 1+2+3+4...N = N*(N+1)/2 without overflow */
+
+static ha_checksum calc_checksum(ha_rows count)
+{
+ ulonglong sum,a,b;
+ DBUG_ENTER("calc_checksum");
+
+ sum=0;
+ a=count; b=count+1;
+ if (a & 1)
+ b>>=1;
+ else
+ a>>=1;
+ while (b)
+ {
+ if (b & 1)
+ sum+=a;
+ a<<=1; b>>=1;
+ }
+ DBUG_PRINT("exit",("sum: %lx",(ulong) sum));
+ DBUG_RETURN((ha_checksum) sum);
+} /* calc_checksum */
+
+
+ /* Calc length of key in normal isam */
+
+static uint isam_key_length(MI_INFO *info, register MI_KEYDEF *keyinfo)
+{
+ uint length;
+ MI_KEYSEG *keyseg;
+ DBUG_ENTER("isam_key_length");
+
+ length= info->s->rec_reflength;
+ for (keyseg=keyinfo->seg ; keyseg->type ; keyseg++)
+ length+= keyseg->length;
+
+ DBUG_PRINT("exit",("length: %d",length));
+ DBUG_RETURN(length);
+} /* key_length */
+
+
+ /* Check that record-link is ok */
+
+int chk_data_link(MI_CHECK *param, MI_INFO *info,int extend)
+{
+ int error,got_error,flag;
+ uint key,left_length,b_type,field;
+ ha_rows records,del_blocks;
+ my_off_t used,empty,pos,splits,start_recpos,
+ del_length,link_used,start_block;
+ byte *record,*to;
+ char llbuff[22],llbuff2[22],llbuff3[22];
+ ha_checksum intern_record_checksum;
+ ha_checksum key_checksum[MI_MAX_POSSIBLE_KEY];
+ my_bool static_row_size;
+ MI_KEYDEF *keyinfo;
+ MI_BLOCK_INFO block_info;
+ DBUG_ENTER("chk_data_link");
+
+ if (!(param->testflag & T_SILENT))
+ {
+ if (extend)
+ puts("- check records and index references");
+ else
+ puts("- check record links");
+ }
+
+ if (!(record= (byte*) my_alloca(info->s->base.pack_reclength)))
+ {
+ mi_check_print_error(param,"Not Enough memory");
+ DBUG_RETURN(-1);
+ }
+ records=del_blocks=0;
+ used=link_used=splits=del_length=0;
+ intern_record_checksum=param->glob_crc=0;
+ LINT_INIT(left_length); LINT_INIT(start_recpos); LINT_INIT(to);
+ got_error=error=0;
+ empty=pos=info->s->pack.header_length;
+
+ /* Check how to calculate checksum of rows */
+ static_row_size=1;
+ if (info->s->data_file_type == COMPRESSED_RECORD)
+ {
+ for (field=0 ; field < info->s->base.fields ; field++)
+ {
+ if (info->s->rec[field].base_type == FIELD_BLOB ||
+ info->s->rec[field].base_type == FIELD_VARCHAR)
+ {
+ static_row_size=0;
+ break;
+ }
+ }
+ }
+
+ bzero((char*) key_checksum, info->s->base.keys * sizeof(key_checksum[0]));
+ while (pos < info->state->data_file_length)
+ {
+ switch (info->s->data_file_type) {
+ case STATIC_RECORD:
+ if (my_b_read(&param->read_cache,(byte*) record,
+ info->s->base.pack_reclength))
+ goto err;
+ start_recpos=pos;
+ pos+=info->s->base.pack_reclength;
+ splits++;
+ if (*record == '\0')
+ {
+ del_blocks++;
+ del_length+=info->s->base.pack_reclength;
+ continue; /* Record removed */
+ }
+ param->glob_crc+= mi_static_checksum(info,record);
+ used+=info->s->base.pack_reclength;
+ break;
+ case DYNAMIC_RECORD:
+ flag=block_info.second_read=0;
+ block_info.next_filepos=pos;
+ do
+ {
+ if (_mi_read_cache(&param->read_cache,(byte*) block_info.header,
+ (start_block=block_info.next_filepos),
+ sizeof(block_info.header),test(! flag) | 2))
+ goto err;
+ if (start_block & (MI_DYN_ALIGN_SIZE-1))
+ {
+ mi_check_print_error(param,"Wrong aligned block at %s",llstr(start_block,llbuff));
+ goto err2;
+ }
+ b_type=_mi_get_block_info(&block_info,-1,start_block);
+ if (b_type & (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR |
+ BLOCK_FATAL_ERROR))
+ {
+ if (b_type & BLOCK_SYNC_ERROR)
+ {
+ if (flag)
+ {
+ mi_check_print_error(param,"Unexpected byte: %d at link: %s",
+ (int) block_info.header[0],
+ llstr(start_block,llbuff));
+ goto err2;
+ }
+ pos=block_info.filepos+block_info.block_len;
+ goto next;
+ }
+ if (b_type & BLOCK_DELETED)
+ {
+ if (block_info.block_len < info->s->base.min_block_length)
+ {
+ mi_check_print_error(param,"Deleted block with impossible length %lu at %s",
+ block_info.block_len,llstr(pos,llbuff));
+ goto err2;
+ }
+ if ((block_info.next_filepos != HA_OFFSET_ERROR &&
+ block_info.next_filepos >= info->state->data_file_length) ||
+ (block_info.prev_filepos != HA_OFFSET_ERROR &&
+ block_info.prev_filepos >= info->state->data_file_length))
+ {
+ mi_check_print_error(param,"Delete link points outside datafile at %s",
+ llstr(pos,llbuff));
+ goto err2;
+ }
+ del_blocks++;
+ del_length+=block_info.block_len;
+ pos=block_info.filepos+block_info.block_len;
+ splits++;
+ goto next;
+ }
+ mi_check_print_error(param,"Wrong bytesec: %d-%d-%d at linkstart: %s",
+ block_info.header[0],block_info.header[1],
+ block_info.header[2],
+ llstr(start_block,llbuff));
+ goto err2;
+ }
+ if (info->state->data_file_length < block_info.filepos+
+ block_info.block_len)
+ {
+ mi_check_print_error(param,"Recordlink that points outside datafile at %s",
+ llstr(pos,llbuff));
+ got_error=1;
+ break;
+ }
+ splits++;
+ if (!flag++) /* First block */
+ {
+ start_recpos=pos;
+ pos=block_info.filepos+block_info.block_len;
+ if (block_info.rec_len > (uint) info->s->base.max_pack_length)
+ {
+ mi_check_print_error(param,"Found too long record (%d) at %s",
+ block_info.rec_len,
+ llstr(start_recpos,llbuff));
+ got_error=1;
+ break;
+ }
+ if (info->s->base.blobs)
+ {
+ if (!(to=mi_fix_rec_buff_for_blob(info,block_info.rec_len)))
+ {
+ mi_check_print_error(param,"Not enough memory for blob at %s",
+ llstr(start_recpos,llbuff));
+ got_error=1;
+ break;
+ }
+ }
+ else
+ to= info->rec_buff;
+ left_length=block_info.rec_len;
+ }
+ if (left_length < block_info.data_len)
+ {
+ mi_check_print_error(param,"Found too long record at %s",
+ llstr(start_recpos,llbuff));
+ got_error=1; break;
+ }
+ if (_mi_read_cache(&param->read_cache,(byte*) to,block_info.filepos,
+ (uint) block_info.data_len, test(flag == 1)))
+ goto err;
+ to+=block_info.data_len;
+ link_used+= block_info.filepos-start_block;
+ used+= block_info.filepos - start_block + block_info.data_len;
+ empty+=block_info.block_len-block_info.data_len;
+ left_length-=block_info.data_len;
+ if (left_length)
+ {
+ if (b_type & BLOCK_LAST)
+ {
+ mi_check_print_error(param,"Record link to short for record at %s",
+ llstr(start_recpos,llbuff));
+ got_error=1;
+ break;
+ }
+ if (info->state->data_file_length < block_info.next_filepos)
+ {
+ mi_check_print_error(param,"Found next-recordlink that points outside datafile at %s",
+ llstr(block_info.filepos,llbuff));
+ got_error=1;
+ break;
+ }
+ }
+ } while (left_length);
+ if (! got_error)
+ {
+ if (_mi_rec_unpack(info,record,info->rec_buff,block_info.rec_len) ==
+ MY_FILE_ERROR)
+ {
+ mi_check_print_error(param,"Found wrong record at %s", llstr(start_recpos,llbuff));
+ got_error=1;
+ }
+ else
+ {
+ info->checksum=mi_checksum(info,record);
+ if (param->testflag & (T_EXTEND | T_MEDIUM | T_VERBOSE))
+ {
+ if (_mi_rec_check(info,record))
+ {
+ mi_check_print_error(param,"Found wrong packed record at %s",
+ llstr(start_recpos,llbuff));
+ got_error=1;
+ }
+ }
+ if (!got_error)
+ param->glob_crc+= info->checksum;
+ }
+ }
+ else if (!flag)
+ pos=block_info.filepos+block_info.block_len;
+ break;
+ case COMPRESSED_RECORD:
+ if (_mi_read_cache(&param->read_cache,(byte*) block_info.header, pos,
+ info->s->pack.ref_length, 1))
+ goto err;
+ start_recpos=pos;
+ splits++;
+ VOID(_mi_pack_get_block_info(info,&block_info, -1, start_recpos, NullS));
+ pos=block_info.filepos+block_info.rec_len;
+ if (block_info.rec_len < (uint) info->s->min_pack_length ||
+ block_info.rec_len > (uint) info->s->max_pack_length)
+ {
+ mi_check_print_error(param,"Found block with wrong recordlength: %d at %s",
+ block_info.rec_len, llstr(start_recpos,llbuff));
+ got_error=1;
+ break;
+ }
+ if (_mi_read_cache(&param->read_cache,(byte*) info->rec_buff,
+ block_info.filepos, block_info.rec_len,1))
+ goto err;
+ if (_mi_pack_rec_unpack(info,record,info->rec_buff,block_info.rec_len))
+ {
+ mi_check_print_error(param,"Found wrong record at %s", llstr(start_recpos,llbuff));
+ got_error=1;
+ }
+ if (static_row_size)
+ param->glob_crc+= mi_static_checksum(info,record);
+ else
+ param->glob_crc+= mi_checksum(info,record);
+ link_used+= (block_info.filepos - start_recpos);
+ used+= (pos-start_recpos);
+ } /* switch */
+ if (! got_error)
+ {
+ intern_record_checksum+=(ha_checksum) start_recpos;
+ records++;
+ if (param->testflag & T_WRITE_LOOP && records % WRITE_COUNT == 0)
+ {
+ printf("%s\r", llstr(records,llbuff)); VOID(fflush(stdout));
+ }
+
+ /* Check if keys match the record */
+
+ for (key=0,keyinfo= info->s->keyinfo; key < info->s->base.keys;
+ key++,keyinfo++)
+ {
+ if ((((ulonglong) 1 << key) & info->s->state.key_map))
+ {
+ if(!(keyinfo->flag & HA_FULLTEXT))
+ {
+ uint key_length=_mi_make_key(info,key,info->lastkey,record,
+ start_recpos);
+ if (extend)
+ {
+ /* We don't need to lock the key tree here as we don't allow
+ concurrent threads when running myisamchk
+ */
+ if (_mi_search(info,keyinfo,info->lastkey,key_length,
+ SEARCH_SAME, info->s->state.key_root[key]))
+ {
+ mi_check_print_error(param,"Record at: %10s Can't find key for index: %2d",
+ llstr(start_recpos,llbuff),key+1);
+ if (error++ > MAXERR || !(param->testflag & T_VERBOSE))
+ goto err2;
+ }
+ }
+ else
+ key_checksum[key]+=mi_byte_checksum((byte*) info->lastkey,
+ key_length);
+ }
+ }
+ }
+ }
+ else
+ {
+ got_error=0;
+ if (error++ > MAXERR || !(param->testflag & T_VERBOSE))
+ goto err2;
+ }
+ next:; /* Next record */
+ }
+ if (param->testflag & T_WRITE_LOOP)
+ {
+ VOID(fputs(" \r",stdout)); VOID(fflush(stdout));
+ }
+ if (records != info->state->records)
+ {
+ mi_check_print_error(param,"Record-count is not ok; is %-10s Should be: %s",
+ llstr(records,llbuff), llstr(info->state->records,llbuff2));
+ error=1;
+ }
+ else if (param->record_checksum &&
+ param->record_checksum != intern_record_checksum)
+ {
+ mi_check_print_error(param,
+ "Keypointers and record positions doesn't match");
+ error=1;
+ }
+ else if (param->glob_crc != info->s->state.checksum &&
+ (info->s->options &
+ (HA_OPTION_CHECKSUM | HA_OPTION_COMPRESS_RECORD)))
+ {
+ mi_check_print_warning(param,
+ "Record checksum is not the same as checksum stored in the index file\n");
+ error=1;
+ }
+ else if (!extend)
+ {
+ for (key=0 ; key < info->s->base.keys; key++)
+ {
+ if (key_checksum[key] != param->key_crc[key] &&
+ !(info->s->keyinfo[key].flag & HA_FULLTEXT))
+ {
+ mi_check_print_error(param,"Checksum for key: %2d doesn't match checksum for records",
+ key+1);
+ error=1;
+ }
+ }
+ }
+
+ if (used+empty+del_length != info->state->data_file_length)
+ {
+ mi_check_print_warning(param,
+ "Found %s record-data and %s unused data and %s deleted-data",
+ llstr(used,llbuff),llstr(empty,llbuff2),
+ llstr(del_length,llbuff3));
+ mi_check_print_warning(param,
+ "Total %s, Should be: %s",
+ llstr((used+empty+del_length),llbuff),
+ llstr(info->state->data_file_length,llbuff2));
+ }
+ if (del_blocks != info->state->del)
+ {
+ mi_check_print_warning(param,
+ "Found %10s deleted blocks Should be: %s",
+ llstr(del_blocks,llbuff),
+ llstr(info->state->del,llbuff2));
+ }
+ if (splits != info->s->state.split)
+ {
+ mi_check_print_warning(param,
+ "Found %10s parts Should be: %s parts",
+ llstr(splits,llbuff),
+ llstr(info->s->state.split,llbuff2));
+ }
+ if (param->testflag & T_INFO)
+ {
+ if (param->warning_printed || param->error_printed)
+ puts("");
+ if (used != 0 && ! param->error_printed)
+ {
+ printf("Records:%18s M.recordlength:%9lu Packed:%14.0f%%\n",
+ llstr(records,llbuff), (long)((used-link_used)/records),
+ (info->s->base.blobs ? 0.0 :
+ (ulonglong2double((ulonglong) info->s->base.reclength*records)-
+ my_off_t2double(used))/
+ ulonglong2double((ulonglong) info->s->base.reclength*records)*100.0));
+ printf("Recordspace used:%9.0f%% Empty space:%12d%% Blocks/Record: %6.2f\n",
+ (ulonglong2double(used-link_used)/ulonglong2double(used-link_used+empty)*100.0),
+ (!records ? 100 : (int) (ulonglong2double(del_length+empty)/
+ my_off_t2double(used)*100.0)),
+ ulonglong2double(splits - del_blocks) / records);
+ }
+ printf("Record blocks:%12s Delete blocks:%10s\n",
+ llstr(splits-del_blocks,llbuff),llstr(del_blocks,llbuff2));
+ printf("Record data: %12s Deleted data: %10s\n",
+ llstr(used-link_used,llbuff),llstr(del_length,llbuff2));
+ printf("Lost space: %12s Linkdata: %10s\n",
+ llstr(empty,llbuff),llstr(link_used,llbuff2));
+ }
+ my_afree((gptr) record);
+ DBUG_RETURN (error);
+ err:
+ mi_check_print_error(param,"got error: %d when reading datafile",my_errno);
+ err2:
+ my_afree((gptr) record);
+ DBUG_RETURN(1);
+} /* chk_data_link */
+
+
+ /* Recover old table by reading each record and writing all keys */
+ /* Save new datafile-name in temp_filename */
+
+int mi_repair(MI_CHECK *param, register MI_INFO *info,
+ my_string name, int rep_quick)
+{
+ int error,got_error;
+ uint i;
+ ha_rows start_records,new_header_length;
+ my_off_t del;
+ File new_file;
+ MYISAM_SHARE *share=info->s;
+ char llbuff[22],llbuff2[22];
+ SORT_INFO *sort_info= &param->sort_info;
+ DBUG_ENTER("mi_repair");
+
+ start_records=info->state->records;
+ new_header_length=(param->testflag & T_UNPACK) ? 0L : share->pack.header_length;
+ got_error=1;
+ new_file= -1;
+ if (!(param->testflag & T_SILENT))
+ {
+ printf("- recovering MyISAM-table '%s'\n",name);
+ printf("Data records: %s\n", llstr(info->state->records,llbuff));
+ }
+
+ if (!param->using_global_keycache)
+ VOID(init_key_cache(param->use_buffers,NEAD_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)))
+ goto err;
+ if (!rep_quick)
+ if (init_io_cache(&info->rec_cache,-1,(uint) param->write_buffer_length,
+ WRITE_CACHE, new_header_length, 1,
+ MYF(MY_WME | MY_WAIT_IF_FULL)))
+ goto err;
+ info->opt_flag|=WRITE_CACHE_USED;
+ sort_info->start_recpos=0;
+ sort_info->buff=0; sort_info->buff_length=0;
+ if (!(sort_info->record=(byte*) my_malloc((uint) share->base.pack_reclength,
+ MYF(0))))
+ {
+ mi_check_print_error(param,"Not Enough memory for extra record");
+ goto err;
+ }
+
+ if (!rep_quick)
+ {
+ if ((new_file=my_raid_create(fn_format(param->temp_filename,name,"",
+ DATA_TMP_EXT,
+ 2+4),
+ 0,param->tmpfile_createflag,
+ share->base.raid_type,
+ share->base.raid_chunks,
+ share->base.raid_chunksize,
+ MYF(0))) < 0)
+ {
+ mi_check_print_error(param,"Can't create new tempfile: '%s'",
+ param->temp_filename);
+ goto err;
+ }
+ if (filecopy(param,new_file,info->dfile,0L,new_header_length,
+ "datafile-header"))
+ goto err;
+ info->s->state.dellink= HA_OFFSET_ERROR;
+ info->rec_cache.file=new_file;
+ if (param->testflag & T_UNPACK)
+ {
+ share->options&= ~HA_OPTION_COMPRESS_RECORD;
+ mi_int2store(share->state.header.options,share->options);
+ }
+ }
+ sort_info->info=info;
+ sort_info->pos=sort_info->max_pos=share->pack.header_length;
+ sort_info->filepos=new_header_length;
+ param->read_cache.end_of_file=sort_info->filelength=
+ my_seek(info->dfile,0L,MY_SEEK_END,MYF(0));
+ sort_info->dupp=0;
+ sort_info->fix_datafile= (my_bool) (! rep_quick);
+ sort_info->max_records= ~(ha_rows) 0;
+ if ((sort_info->new_data_file_type=share->data_file_type) ==
+ COMPRESSED_RECORD && param->testflag & T_UNPACK)
+ {
+ if (share->options & HA_OPTION_PACK_RECORD)
+ sort_info->new_data_file_type = DYNAMIC_RECORD;
+ else
+ sort_info->new_data_file_type = STATIC_RECORD;
+ }
+
+ del=info->state->del;
+ info->state->records=info->state->del=share->state.split=0;
+ info->state->empty=0;
+ if (sort_info->new_data_file_type != COMPRESSED_RECORD && !rep_quick)
+ share->state.checksum=0;
+ info->update= (short) (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
+ for (i=0 ; i < info->s->base.keys ; i++)
+ share->state.key_root[i]= HA_OFFSET_ERROR;
+ for (i=0 ; i < share->state.header.max_block_size ; i++)
+ share->state.key_del[i]= HA_OFFSET_ERROR;
+
+ info->state->key_file_length=share->base.keystart;
+
+ lock_memory(param); /* Everything is alloced */
+ while (!(error=sort_get_next_record(sort_info)))
+ {
+ if (writekeys(info,(byte*) sort_info->record,sort_info->filepos))
+ {
+ if (my_errno != HA_ERR_FOUND_DUPP_KEY) goto err;
+ DBUG_DUMP("record",(byte*) sort_info->record,share->base.pack_reclength);
+ mi_check_print_info(param,"Duplicate key %2d for record at %10s against new record at %10s",
+ info->errkey+1,
+ llstr(sort_info->start_recpos,llbuff),
+ llstr(info->lastpos,llbuff2));
+ if (param->testflag & T_VERBOSE)
+ {
+ VOID(_mi_make_key(info,(uint) info->errkey,info->lastkey,
+ sort_info->record,0L));
+ _mi_print_key(stdout,share->keyinfo[info->errkey].seg,info->lastkey,
+ USE_WHOLE_KEY);
+ }
+ sort_info->dupp++;
+ if (rep_quick == 1)
+ {
+ param->error_printed=1;
+ goto err;
+ }
+ continue;
+ }
+ if (sort_write_record(sort_info))
+ goto err;
+ }
+ if (error > 0 || write_data_suffix(param,info) ||
+ flush_io_cache(&info->rec_cache) || param->read_cache.error < 0)
+ goto err;
+
+ if (param->testflag & T_WRITE_LOOP)
+ {
+ VOID(fputs(" \r",stdout)); VOID(fflush(stdout));
+ }
+ if (my_chsize(share->kfile,info->state->key_file_length,MYF(0)))
+ {
+ mi_check_print_warning(param,
+ "Can't change size of indexfile, error: %d",
+ my_errno);
+ goto err;
+ }
+
+ if (rep_quick && del+sort_info->dupp != info->state->del)
+ {
+ 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;
+ goto err;
+ }
+
+ if (!rep_quick)
+ {
+ 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;
+ param->out_flag|=O_NEW_DATA; /* Data in new file */
+ share->state.version=(ulong) time((time_t*) 0); /* Force reopen */
+ }
+ else
+ info->state->data_file_length=sort_info->max_pos;
+
+ if (!(param->testflag & T_SILENT))
+ {
+ if (start_records != info->state->records)
+ printf("Data records: %s\n", llstr(info->state->records,llbuff));
+ if (sort_info->dupp)
+ mi_check_print_warning(param,
+ "%s records have been removed",
+ llstr(sort_info->dupp,llbuff));
+ }
+
+ got_error=0;
+ /* If invoked by external program that uses thr_lock */
+ if (&share->state.state != info->state)
+ memcpy( &share->state.state, info->state, sizeof(*info->state));
+
+err:
+ if (got_error)
+ {
+ if (! param->error_printed)
+ mi_check_print_error(param,"%d for record at pos %s",my_errno,
+ llstr(sort_info->start_recpos,llbuff));
+ if (new_file >= 0)
+ {
+ VOID(my_close(new_file,MYF(0)));
+ VOID(my_raid_delete(param->temp_filename,info->s->base.raid_chunks,
+ MYF(MY_WME)));
+ }
+ }
+ if (sort_info->record)
+ my_free(sort_info->record,MYF(0));
+
+ my_free(sort_info->buff,MYF(MY_ALLOW_ZERO_PTR));
+ VOID(end_io_cache(&param->read_cache));
+ info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
+ VOID(end_io_cache(&info->rec_cache));
+ got_error|=flush_blocks(param,share->kfile);
+ if (!got_error && param->testflag & T_UNPACK)
+ {
+ share->state.header.options[0]&= (uchar) ~HA_OPTION_COMPRESS_RECORD;
+ share->pack.header_length=0;
+ share->data_file_type=sort_info->new_data_file_type;
+ }
+ DBUG_RETURN(got_error);
+} /* rep */
+
+
+/* Uppate keyfile when doing repair */
+
+static int writekeys(register MI_INFO *info,byte *buff,my_off_t filepos)
+{
+ register uint i;
+ uchar *key;
+ DBUG_ENTER("writekeys");
+
+ key=info->lastkey+info->s->base.max_key_length;
+ for (i=0 ; i < info->s->base.keys ; i++)
+ {
+ if (((ulonglong) 1 << i) & info->s->state.key_map)
+ {
+ uint key_length=_mi_make_key(info,i,key,buff,filepos);
+ if (_mi_ck_write(info,i,key,key_length)) goto err;
+ }
+ }
+ DBUG_RETURN(0);
+
+ err:
+ if (my_errno == HA_ERR_FOUND_DUPP_KEY)
+ {
+ info->errkey=(int) i; /* This key was found */
+ while ( i-- > 0 )
+ {
+ if (((ulonglong) 1 << i) & info->s->state.key_map)
+ {
+ uint key_length=_mi_make_key(info,i,key,buff,filepos);
+ if (_mi_ck_delete(info,i,key,key_length)) break;
+ }
+ }
+ }
+ DBUG_PRINT("error",("errno: %d",my_errno));
+ DBUG_RETURN(-1);
+} /* writekeys */
+
+
+ /* Change all key-pointers that points to a records */
+
+int movepoint(register MI_INFO *info, byte *record, my_off_t oldpos,
+ my_off_t newpos, uint prot_key)
+{
+ register uint i;
+ uchar *key;
+ uint key_length;
+ DBUG_ENTER("movepoint");
+
+ key=info->lastkey+info->s->base.max_key_length;
+ for (i=0 ; i < info->s->base.keys; i++)
+ {
+ if (i != prot_key && (((ulonglong) 1 << i) & info->s->state.key_map))
+ {
+ key_length=_mi_make_key(info,i,key,record,oldpos);
+ if (info->s->keyinfo[i].flag & HA_NOSAME)
+ { /* Change pointer direct */
+ uint nod_flag;
+ MI_KEYDEF *keyinfo;
+ keyinfo=info->s->keyinfo+i;
+ if (_mi_search(info,keyinfo,key,USE_WHOLE_KEY,
+ (uint) (SEARCH_SAME | SEARCH_SAVE_BUFF),
+ info->s->state.key_root[i]))
+ DBUG_RETURN(-1);
+ nod_flag=mi_test_if_nod(info->buff);
+ _mi_dpointer(info,info->int_keypos-nod_flag-
+ info->s->rec_reflength,newpos);
+ if (_mi_write_keypage(info,keyinfo,info->last_keypage,info->buff))
+ DBUG_RETURN(-1);
+ }
+ else
+ { /* Change old key to new */
+ if (_mi_ck_delete(info,i,key,key_length))
+ DBUG_RETURN(-1);
+ key_length=_mi_make_key(info,i,key,record,newpos);
+ if (_mi_ck_write(info,i,key,key_length))
+ DBUG_RETURN(-1);
+ }
+ }
+ }
+ DBUG_RETURN(0);
+} /* movepoint */
+
+
+ /* Tell system that we want all memory for our cache */
+
+void lock_memory(MI_CHECK *param __attribute__((unused)))
+{
+#ifdef SUN_OS /* Key-cacheing thrases on sun 4.1 */
+ if (param->opt_lock_memory)
+ {
+ int success = mlockall(MCL_CURRENT); /* or plock(DATLOCK); */
+ if (geteuid() == 0 && success != 0)
+ mi_check_print_warning(param,
+ "Failed to lock memory. errno %d",my_errno);
+ }
+#endif
+} /* lock_memory */
+
+
+ /* Flush all changed blocks to disk */
+
+int flush_blocks(MI_CHECK *param, File file)
+{
+ if (flush_key_blocks(file,FLUSH_RELEASE))
+ {
+ mi_check_print_error(param,"%d when trying to write bufferts",my_errno);
+ return(1);
+ }
+ if (!param->using_global_keycache)
+ end_key_cache();
+ return 0;
+} /* flush_blocks */
+
+
+ /* Sort index for more efficent reads */
+
+int mi_sort_index(MI_CHECK *param, register MI_INFO *info, my_string name)
+{
+ reg2 uint key;
+ reg1 MI_KEYDEF *keyinfo;
+ File new_file;
+ my_off_t index_pos[MI_MAX_POSSIBLE_KEY];
+ DBUG_ENTER("sort_index");
+
+ 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),
+ 0,param->tmpfile_createflag,MYF(0))) <= 0)
+ {
+ mi_check_print_error(param,"Can't create new tempfile: '%s'",
+ param->temp_filename);
+ DBUG_RETURN(-1);
+ }
+ if (filecopy(param, new_file,info->s->kfile,0L,
+ (ulong) info->s->base.keystart, "headerblock"))
+ goto err;
+
+ param->new_file_pos=info->s->base.keystart;
+ for (key= 0,keyinfo= &info->s->keyinfo[0]; key < info->s->base.keys ;
+ key++,keyinfo++)
+ {
+ if (!(((ulonglong) 1 << key) & info->s->state.key_map))
+ continue;
+
+ if (info->s->state.key_root[key] != HA_OFFSET_ERROR)
+ {
+ index_pos[key]=param->new_file_pos; /* Write first block here */
+ if (sort_one_index(param,info,keyinfo,info->s->state.key_root[key],
+ new_file))
+ goto err;
+ }
+ else
+ index_pos[key]= HA_OFFSET_ERROR; /* No blocks */
+ }
+
+ /* Flush key cache for this file if we are calling this outside myisamchk */
+ flush_key_blocks(info->s->kfile, FLUSH_IGNORE_CHANGED);
+
+ /* Put same locks as old file */
+ if (lock_file(param,new_file,0L,F_WRLCK,"tempfile",param->temp_filename))
+ goto err;
+ info->s->state.version=(ulong) time((time_t*) 0);
+ VOID(_mi_writeinfo(info,WRITEINFO_UPDATE_KEYFILE));
+ VOID(my_close(info->s->kfile,MYF(MY_WME)));
+ param->out_flag|=O_NEW_INDEX; /* Data in new file */
+
+ info->s->kfile=new_file;
+ info->state->key_file_length=param->new_file_pos;
+ info->update= (short) (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
+ for (key=0 ; key < info->s->base.keys ; key++)
+ info->s->state.key_root[key]=index_pos[key];
+ for (key=0 ; key < info->s->state.header.max_block_size ; key++)
+ info->s->state.key_del[key]= HA_OFFSET_ERROR;
+
+ DBUG_RETURN(0);
+
+err:
+ VOID(my_close(new_file,MYF(MY_WME)));
+ VOID(my_delete(param->temp_filename,MYF(MY_WME)));
+ DBUG_RETURN(-1);
+} /* sort_index */
+
+
+ /* Sort records recursive using one index */
+
+static int sort_one_index(MI_CHECK *param, MI_INFO *info, MI_KEYDEF *keyinfo,
+ my_off_t pagepos, File new_file)
+{
+ uint length,nod_flag,used_length;
+ uchar *buff,*keypos,*endpos;
+ uchar key[MI_MAX_POSSIBLE_KEY_BUFF];
+ my_off_t new_page_pos,next_page;
+ char llbuff[22];
+ DBUG_ENTER("sort_one_index");
+
+ new_page_pos=param->new_file_pos;
+ param->new_file_pos+=keyinfo->block_length;
+
+ if (!(buff=(uchar*) my_alloca((uint) keyinfo->block_length)))
+ {
+ mi_check_print_error(param,"Not Enough memory");
+ DBUG_RETURN(-1);
+ }
+ if (!_mi_fetch_keypage(info,keyinfo,pagepos,buff,0))
+ {
+ mi_check_print_error(param,"Can't read key block from filepos: %s",
+ llstr(pagepos,llbuff));
+ goto err;
+ }
+ if ((nod_flag=mi_test_if_nod(buff)))
+ {
+ used_length=mi_getint(buff);
+ keypos=buff+2+nod_flag;
+ endpos=buff+used_length;
+ for ( ;; )
+ {
+ if (nod_flag)
+ {
+ next_page=_mi_kpos(nod_flag,keypos);
+ _mi_kpointer(info,keypos-nod_flag,param->new_file_pos); /* Save new pos */
+ if (sort_one_index(param,info,keyinfo,next_page, new_file))
+ {
+ DBUG_PRINT("error",("From page: %ld, keyoffset: %d used_length: %d",
+ (ulong) pagepos, (int) (keypos - buff),
+ (int) used_length));
+ DBUG_DUMP("buff",(byte*) buff,used_length);
+ goto err;
+ }
+ }
+ if (keypos >= endpos ||
+ ((*keyinfo->get_key)(keyinfo,nod_flag,&keypos,key)) == 0)
+ break;
+#ifdef EXTRA_DEBUG
+ assert(keypos <= endpos);
+#endif
+ }
+ }
+
+ /* Fill block with zero and write it to the new index file */
+ length=mi_getint(buff);
+ bzero((byte*) buff+length,keyinfo->block_length-length);
+ if (my_pwrite(new_file,(byte*) buff,(uint) keyinfo->block_length,
+ new_page_pos,MYF(MY_NABP | MY_WAIT_IF_FULL)))
+ {
+ mi_check_print_error(param,"Can't write indexblock, error: %d",my_errno);
+ goto err;
+ }
+ my_afree((gptr) buff);
+ DBUG_RETURN(0);
+err:
+ my_afree((gptr) buff);
+ DBUG_RETURN(1);
+} /* sort_one_index */
+
+
+ /* Change to use new file */
+ /* Copy stats from old file to new file, deletes orginal and */
+ /* changes new file name to old file name */
+
+int change_to_newfile(const char * filename, const char * old_ext,
+ const char * new_ext,
+ uint raid_chunks __attribute__((unused)))
+{
+ char old_filename[FN_REFLEN],new_filename[FN_REFLEN];
+#ifdef USE_RAID
+ if (raid_chunks)
+ return my_raid_redel(fn_format(old_filename,filename,"",old_ext,2+4),
+ fn_format(new_filename,filename,"",new_ext,2+4),
+ raid_chunks,
+ MYF(MY_WME+MY_LINK_WARNING));
+#endif
+ return my_redel(fn_format(old_filename,filename,"",old_ext,2+4),
+ fn_format(new_filename,filename,"",new_ext,2+4),
+ MYF(MY_WME+MY_LINK_WARNING));
+} /* change_to_newfile */
+
+
+ /* Locks a whole file */
+ /* Gives an error-message if file can't be locked */
+
+int lock_file(MI_CHECK *param, File file, my_off_t start, int lock_type,
+ const char *filetype, const char *filename)
+{
+ if (my_lock(file,lock_type,start,F_TO_EOF,
+ param->testflag & T_WAIT_FOREVER ? MYF(MY_SEEK_NOT_DONE) :
+ MYF(MY_SEEK_NOT_DONE | MY_DONT_WAIT)))
+ {
+ mi_check_print_error(param," %d when locking %s '%s'",my_errno,filetype,filename);
+ param->error_printed=2; /* Don't give that data is crashed */
+ return 1;
+ }
+ return 0;
+} /* lock_file */
+
+
+ /* Copy a block between two files */
+
+int filecopy(MI_CHECK *param, File to,File from,my_off_t start,
+ my_off_t length, const char *type)
+{
+ char tmp_buff[IO_SIZE],*buff;
+ ulong buff_length;
+ DBUG_ENTER("filecopy");
+
+ buff_length=(ulong) min(param->write_buffer_length,length);
+ if (!(buff=my_malloc(buff_length,MYF(0))))
+ {
+ buff=tmp_buff; buff_length=IO_SIZE;
+ }
+
+ VOID(my_seek(from,start,MY_SEEK_SET,MYF(0)));
+ while (length > buff_length)
+ {
+ if (my_read(from,(byte*) buff,buff_length,MYF(MY_NABP)) ||
+ my_write(to,(byte*) buff,buff_length,param->myf_rw))
+ goto err;
+ length-= buff_length;
+ }
+ if (my_read(from,(byte*) buff,(uint) length,MYF(MY_NABP)) ||
+ my_write(to,(byte*) buff,(uint) length,param->myf_rw))
+ goto err;
+ if (buff != tmp_buff)
+ my_free(buff,MYF(0));
+ DBUG_RETURN(0);
+err:
+ if (buff != tmp_buff)
+ my_free(buff,MYF(0));
+ mi_check_print_error(param,"Can't copy %s to tempfile, error %d",
+ type,my_errno);
+ DBUG_RETURN(1);
+}
+
+ /* Fix table using sorting */
+ /* saves new table in temp_filename */
+
+int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info,
+ const char * name, int rep_quick)
+{
+ int got_error;
+ uint i;
+ ulong length;
+ ha_rows start_records;
+ my_off_t new_header_length,del;
+ File new_file;
+ MI_SORT_PARAM sort_param;
+ MYISAM_SHARE *share=info->s;
+ ulong *rec_per_key_part;
+ char llbuff[22];
+ SORT_INFO *sort_info= &param->sort_info;
+ DBUG_ENTER("rep_by_sort");
+
+ start_records=info->state->records;
+ got_error=1;
+ new_file= -1;
+ new_header_length=(param->testflag & T_UNPACK) ? 0 :
+ share->pack.header_length;
+ if (!(param->testflag & T_SILENT))
+ {
+ printf("- recovering MyISAM-table '%s'\n",name);
+ printf("Data records: %s\n", llstr(start_records,llbuff));
+ }
+ bzero((char*) sort_info,sizeof(*sort_info));
+ if (!(sort_info->key_block=
+ alloc_key_blocks(param,
+ (uint) param->sort_key_blocks,
+ share->base.max_key_block_length))
+ || init_io_cache(&param->read_cache,info->dfile,
+ (uint) param->read_buffer_length,
+ READ_CACHE,share->pack.header_length,1,MYF(MY_WME)) ||
+ (! rep_quick &&
+ init_io_cache(&info->rec_cache,info->dfile,
+ (uint) param->write_buffer_length,
+ WRITE_CACHE,new_header_length,1,
+ MYF(MY_WME | MY_WAIT_IF_FULL))))
+ goto err;
+ sort_info->key_block_end=sort_info->key_block+param->sort_key_blocks;
+ info->opt_flag|=WRITE_CACHE_USED;
+ info->rec_cache.file=info->dfile; /* for sort_delete_record */
+
+ /* Flush key cache for this file if we are calling this outside myisamchk */
+ flush_key_blocks(share->kfile, FLUSH_IGNORE_CHANGED);
+
+ if (!(sort_info->record=(byte*) my_malloc((uint) share->base.pack_reclength,
+ MYF(0))))
+ {
+ mi_check_print_error(param,"Not enough memory for extra record");
+ goto err;
+ }
+ if (!rep_quick)
+ {
+ if ((new_file=my_raid_create(fn_format(param->temp_filename,name,"",
+ DATA_TMP_EXT,
+ 2+4),
+ 0,param->tmpfile_createflag,
+ share->base.raid_type,
+ share->base.raid_chunks,
+ share->base.raid_chunksize,
+ MYF(0))) < 0)
+ {
+ mi_check_print_error(param,"Can't create new tempfile: '%s'",
+ param->temp_filename);
+ goto err;
+ }
+ if (filecopy(param, new_file,info->dfile,0L,new_header_length,
+ "datafile-header"))
+ goto err;
+ if (param->testflag & T_UNPACK)
+ {
+ share->options&= ~HA_OPTION_COMPRESS_RECORD;
+ mi_int2store(share->state.header.options,share->options);
+ }
+ share->state.dellink= HA_OFFSET_ERROR;
+ info->rec_cache.file=new_file;
+ }
+
+ info->update= (short) (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
+ for (i=0 ; i < share->base.keys ; i++)
+ share->state.key_root[i]= HA_OFFSET_ERROR;
+ for (i=0 ; i < share->state.header.max_block_size ; i++)
+ share->state.key_del[i]= HA_OFFSET_ERROR;
+
+ info->state->key_file_length=share->base.keystart;
+
+ sort_info->info=info;
+ sort_info->param = param;
+
+ if ((sort_info->new_data_file_type=share->data_file_type) ==
+ COMPRESSED_RECORD && param->testflag & T_UNPACK)
+ {
+ if (share->options & HA_OPTION_PACK_RECORD)
+ sort_info->new_data_file_type = DYNAMIC_RECORD;
+ else
+ sort_info->new_data_file_type = STATIC_RECORD;
+ }
+
+ sort_info->filepos=new_header_length;
+ sort_info->dupp=0;
+ sort_info->buff=0;
+ param->read_cache.end_of_file=sort_info->filelength=
+ my_seek(param->read_cache.file,0L,MY_SEEK_END,MYF(0));
+
+ if (share->data_file_type == DYNAMIC_RECORD)
+ length=max(share->base.min_pack_length+1,share->base.min_block_length);
+ else if (share->data_file_type == COMPRESSED_RECORD)
+ length=share->base.min_block_length;
+ else
+ length=share->base.pack_reclength;
+ sort_param.max_records=sort_info->max_records=
+ (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.sort_info=sort_info;
+
+ del=info->state->del;
+ if (sort_info->new_data_file_type != COMPRESSED_RECORD &&
+ ! rep_quick)
+ share->state.checksum=0;
+
+ rec_per_key_part= param->rec_per_key_part;
+ for (sort_info->key=0 ; sort_info->key < share->base.keys ;
+ rec_per_key_part+=sort_info->keyinfo->keysegs, sort_info->key++)
+ {
+ sort_info->keyinfo=share->keyinfo+sort_info->key;
+ if (!(((ulonglong) 1 << sort_info->key) & share->state.key_map))
+ continue;
+
+ if ((!(param->testflag & T_SILENT)))
+ printf ("- Fixing index %d\n",sort_info->key+1);
+ sort_info->max_pos=sort_info->pos=share->pack.header_length;
+ sort_info->keyseg=sort_info->keyinfo->seg;
+ sort_info->fix_datafile= (my_bool) (sort_info->key == 0 && ! rep_quick);
+ bzero((char*) sort_info->unique,sizeof(sort_info->unique));
+ sort_param.key_length=share->rec_reflength;
+ for (i=0 ; sort_info->keyseg[i].type != HA_KEYTYPE_END; i++)
+ {
+ sort_param.key_length+=sort_info->keyseg[i].length;
+ if (sort_info->keyseg[i].flag & HA_SPACE_PACK)
+ sort_param.key_length+=get_pack_length(sort_info->keyseg[i].length);
+ if (sort_info->keyseg[i].flag & (HA_BLOB_PART | HA_VAR_LENGTH))
+ sort_param.key_length+=2 + test(sort_info->keyseg[i].length >= 127);
+ if (sort_info->keyseg[i].flag & HA_NULL_PART)
+ sort_param.key_length++;
+ }
+ info->state->records=info->state->del=share->state.split=0;
+ info->state->empty=0;
+
+ if (_create_index_by_sort(&sort_param,
+ (my_bool) (!(param->testflag & T_VERBOSE)),
+ (uint) param->sort_buffer_length))
+ goto err;
+
+ /* Set for next loop */
+ sort_param.max_records=sort_info->max_records=
+ (ha_rows) info->state->records;
+
+ if (param->testflag & T_STATISTICS)
+ update_key_parts(sort_info->keyinfo, rec_per_key_part, sort_info->unique,
+ (ulonglong) info->state->records);
+
+ if (sort_info->fix_datafile)
+ {
+ param->read_cache.end_of_file=sort_info->filepos;
+ if (write_data_suffix(param,info) || end_io_cache(&info->rec_cache))
+ goto err;
+ 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);
+ param->out_flag|=O_NEW_DATA; /* Data in new file */
+ my_close(info->dfile,MYF(0));
+ info->dfile=new_file;
+ share->data_file_type=sort_info->new_data_file_type;
+ share->pack.header_length=(ulong) new_header_length;
+ }
+ else
+ info->state->data_file_length=sort_info->max_pos;
+
+ 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,
+ 1);
+ }
+
+ if (param->testflag & T_WRITE_LOOP)
+ {
+ VOID(fputs(" \r",stdout)); VOID(fflush(stdout));
+ }
+
+ if (rep_quick && del+sort_info->dupp != info->state->del)
+ {
+ 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;
+ goto err;
+ }
+
+ if (rep_quick != 1)
+ {
+ my_off_t skr=info->state->data_file_length+
+ (share->options & HA_OPTION_COMPRESS_RECORD ?
+ MEMMAP_EXTRA_MARGIN : 0);
+#ifdef USE_RELOC
+ if (share->data_file_type == STATIC_RECORD &&
+ skr < share->base.reloc*share->base.min_pack_length)
+ skr=share->base.reloc*share->base.min_pack_length;
+#endif
+ if (skr != sort_info->filelength && !info->s->base.raid_type)
+ if (my_chsize(info->dfile,skr,MYF(0)))
+ mi_check_print_warning(param,
+ "Can't change size of datafile, error: %d",
+ my_errno);
+ }
+ if (my_chsize(share->kfile,info->state->key_file_length,MYF(0)))
+ mi_check_print_warning(param,
+ "Can't change size of indexfile, error: %d",
+ my_errno);
+
+ if (!(param->testflag & T_SILENT))
+ {
+ if (start_records != info->state->records)
+ printf("Data records: %s\n", llstr(info->state->records,llbuff));
+ if (sort_info->dupp)
+ mi_check_print_warning(param,
+ "%s records have been removed",
+ llstr(sort_info->dupp,llbuff));
+ }
+ got_error=0;
+
+ if (&share->state.state != info->state)
+ memcpy( &share->state.state, info->state, sizeof(*info->state));
+
+err:
+ if (got_error)
+ {
+ if (! param->error_printed)
+ mi_check_print_error(param,"%d when fixing table",my_errno);
+ if (new_file >= 0)
+ {
+ VOID(end_io_cache(&info->rec_cache));
+ VOID(my_close(new_file,MYF(0)));
+ VOID(my_raid_delete(param->temp_filename,info->s->base.raid_chunks,
+ MYF(MY_WME)));
+ }
+ }
+ my_free((gptr) sort_info->key_block,MYF(MY_ALLOW_ZERO_PTR));
+ my_free(sort_info->record,MYF(MY_ALLOW_ZERO_PTR));
+ my_free(sort_info->buff,MYF(MY_ALLOW_ZERO_PTR));
+ VOID(end_io_cache(&param->read_cache));
+ VOID(end_io_cache(&info->rec_cache));
+ info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
+ if (!got_error && param->testflag & T_UNPACK)
+ {
+ share->state.header.options[0]&= (uchar) ~HA_OPTION_COMPRESS_RECORD;
+ share->pack.header_length=0;
+ }
+ DBUG_RETURN(got_error);
+} /* rep_by_sort */
+
+
+ /* Read next record and return next key */
+
+static int sort_key_read(SORT_INFO *sort_info, void *key)
+{
+ int error;
+ MI_INFO *info;
+ DBUG_ENTER("sort_key_read");
+
+ info=sort_info->info;
+
+ if ((error=sort_get_next_record(sort_info)))
+ DBUG_RETURN(error);
+ if (info->state->records == sort_info->max_records)
+ {
+ mi_check_print_error(sort_info->param,
+ "Found too many records; Can`t continue");
+ DBUG_RETURN(1);
+ }
+ VOID(_mi_make_key(info,sort_info->key,key,sort_info->record,
+ sort_info->filepos));
+ DBUG_RETURN(sort_write_record(sort_info));
+} /* sort_key_read */
+
+
+ /* Read next record from file using parameters in sort_info */
+ /* Return -1 if end of file, 0 if ok and > 0 if error */
+
+static int sort_get_next_record(SORT_INFO *sort_info)
+{
+ int searching;
+ uint found_record,b_type,left_length;
+ my_off_t pos;
+ byte *to;
+ MI_BLOCK_INFO block_info;
+ MI_INFO *info;
+ MYISAM_SHARE *share;
+ MI_CHECK *param=sort_info->param;
+ char llbuff[22],llbuff2[22];
+ DBUG_ENTER("sort_get_next_record");
+
+ info=sort_info->info;
+ share=info->s;
+ switch (share->data_file_type) {
+ case STATIC_RECORD:
+ for (;;)
+ {
+ if (my_b_read(&param->read_cache,sort_info->record,
+ share->base.pack_reclength))
+ DBUG_RETURN(-1);
+ sort_info->start_recpos=sort_info->pos;
+ if (!sort_info->fix_datafile)
+ sort_info->filepos=sort_info->pos;
+ sort_info->max_pos=(sort_info->pos+=share->base.pack_reclength);
+ share->state.split++;
+ if (*sort_info->record)
+ DBUG_RETURN(0);
+ if (!sort_info->fix_datafile)
+ {
+ info->state->del++;
+ info->state->empty+=share->base.pack_reclength;
+ }
+ }
+ case DYNAMIC_RECORD:
+ LINT_INIT(to);
+ pos=sort_info->pos;
+ searching=(sort_info->fix_datafile && (param->testflag & T_EXTEND));
+ for (;;)
+ {
+ found_record=block_info.second_read= 0;
+ left_length=1;
+ if (searching)
+ pos=MY_ALIGN(pos,MI_DYN_ALIGN_SIZE);
+ do
+ {
+ if (pos > sort_info->max_pos)
+ sort_info->max_pos=pos;
+ if (pos & (MI_DYN_ALIGN_SIZE-1))
+ {
+ if ((param->testflag & T_VERBOSE) || searching == 0)
+ {
+ mi_check_print_info(param,"Wrong aligned block at %s",
+ llstr(pos,llbuff));
+ goto try_next;
+ }
+ }
+ if (found_record && pos == param->search_after_block)
+ mi_check_print_info(param,"Block: %s used by record at %s",
+ llstr(param->search_after_block,llbuff),
+ llstr(sort_info->start_recpos,llbuff2));
+ if (_mi_read_cache(&param->read_cache,(byte*) block_info.header,pos,
+ MI_BLOCK_INFO_HEADER_LENGTH,
+ test(! found_record) | 2))
+ {
+ if (found_record)
+ {
+ mi_check_print_info(param,
+ "Can't read whole record at %s (errno: %d)",
+ llstr(sort_info->start_recpos,llbuff),errno);
+ goto try_next;
+ }
+ DBUG_RETURN(-1);
+ }
+ if (searching && ! sort_info->fix_datafile)
+ {
+ param->error_printed=1;
+ DBUG_RETURN(1); /* Something wrong with data */
+ }
+ if (((b_type=_mi_get_block_info(&block_info,-1,pos)) &
+ (BLOCK_ERROR | BLOCK_FATAL_ERROR)) ||
+ ((b_type & BLOCK_FIRST) &&
+ (block_info.rec_len < (uint) share->base.min_pack_length ||
+ block_info.rec_len > (uint) share->base.max_pack_length)))
+ {
+ uint i;
+ if (param->testflag & T_VERBOSE || searching == 0)
+ mi_check_print_info(param,
+ "Wrong bytesec: %3d-%3d-%3d at %10s; Skipped",
+ block_info.header[0],block_info.header[1],
+ block_info.header[2],llstr(pos,llbuff));
+ if (found_record)
+ goto try_next;
+ block_info.second_read=0;
+ searching=1;
+ /* Search after block in read header string */
+ for (i=MI_DYN_ALIGN_SIZE ;
+ i < MI_BLOCK_INFO_HEADER_LENGTH ;
+ i+= MI_DYN_ALIGN_SIZE)
+ if (block_info.header[i] >= 1 &&
+ block_info.header[i] <= MI_MAX_DYN_HEADER_BYTE)
+ break;
+ pos+=(ulong) i;
+ continue;
+ }
+ if (b_type & BLOCK_DELETED)
+ {
+ bool error=0;
+ if (block_info.block_len+ (uint) (block_info.filepos-pos) <
+ share->base.min_block_length)
+ {
+ if (!searching)
+ mi_check_print_info(param,
+ "Deleted block with impossible length %u at %s",
+ block_info.block_len,llstr(pos,llbuff));
+ error=1;
+ }
+ else
+ {
+ if ((block_info.next_filepos != HA_OFFSET_ERROR &&
+ block_info.next_filepos >=
+ info->state->data_file_length) ||
+ (block_info.prev_filepos != HA_OFFSET_ERROR &&
+ block_info.prev_filepos >= info->state->data_file_length))
+ {
+ if (!searching)
+ mi_check_print_info(param,
+ "Delete link points outside datafile at %s",
+ llstr(pos,llbuff));
+ error=1;
+ }
+ }
+ if (error)
+ {
+ if (found_record)
+ goto try_next;
+ searching=1;
+ pos++;
+ block_info.second_read=0;
+ continue;
+ }
+ }
+ else
+ {
+ if (block_info.block_len+ (uint) (block_info.filepos-pos) <
+ share->base.min_block_length ||
+ block_info.block_len > (uint) share->base.max_pack_length+
+ MI_SPLIT_LENGTH)
+ {
+ if (!searching)
+ mi_check_print_info(param,
+ "Found block with impossible length %u at %s; Skipped",
+ block_info.block_len+ (uint) (block_info.filepos-pos),
+ llstr(pos,llbuff));
+ if (found_record)
+ goto try_next;
+ searching=1;
+ pos++;
+ block_info.second_read=0;
+ continue;
+ }
+ }
+ if (b_type & (BLOCK_DELETED | BLOCK_SYNC_ERROR))
+ {
+ if (!sort_info->fix_datafile && (b_type & BLOCK_DELETED))
+ {
+ info->state->empty+=block_info.block_len;
+ info->state->del++;
+ share->state.split++;
+ }
+ if (found_record)
+ goto try_next;
+ if (searching)
+ pos++;
+ else
+ pos=block_info.filepos+block_info.block_len;
+ block_info.second_read=0;
+ continue;
+ }
+
+ share->state.split++;
+ if (! found_record++)
+ {
+ sort_info->find_length=left_length=block_info.rec_len;
+ sort_info->start_recpos=pos;
+ if (!sort_info->fix_datafile)
+ sort_info->filepos=sort_info->start_recpos;
+ if (sort_info->fix_datafile && (param->testflag & T_EXTEND))
+ sort_info->pos=block_info.filepos+1;
+ else
+ sort_info->pos=block_info.filepos+block_info.block_len;
+ if (share->base.blobs)
+ {
+ if (!(to=mi_fix_rec_buff_for_blob(info,block_info.rec_len)))
+ {
+ mi_check_print_error(param,"Not enough memory for blob at %s",
+ llstr(sort_info->start_recpos,llbuff));
+ DBUG_RETURN(-1);
+ }
+ }
+ else
+ to= info->rec_buff;
+ }
+ if (left_length < block_info.data_len || ! block_info.data_len)
+ {
+ mi_check_print_info(param,"Found block with too small length at %s; Skipped",
+ llstr(sort_info->start_recpos,llbuff));
+ goto try_next;
+ }
+ if (block_info.filepos + block_info.data_len >
+ param->read_cache.end_of_file)
+ {
+ mi_check_print_info(param,"Found block that points outside data file at %s",
+ llstr(sort_info->start_recpos,llbuff));
+ goto try_next;
+ }
+ if (_mi_read_cache(&param->read_cache,to,block_info.filepos,
+ block_info.data_len, test(found_record == 1)))
+ {
+ mi_check_print_info(param,"Read error for block at: %s (error: %d); Skipped",
+ llstr(block_info.filepos,llbuff),my_errno);
+ goto try_next;
+ }
+ left_length-=block_info.data_len;
+ to+=block_info.data_len;
+ pos=block_info.next_filepos;
+ if (pos == HA_OFFSET_ERROR && left_length)
+ {
+ mi_check_print_info(param,"Wrong block with wrong total length starting at %s",
+ llstr(sort_info->start_recpos,llbuff));
+ goto try_next;
+ }
+ if (pos + MI_BLOCK_INFO_HEADER_LENGTH > param->read_cache.end_of_file)
+ {
+ mi_check_print_info(param,"Found link that points at %s (outside data file) at %s",
+ llstr(pos,llbuff2), llstr(sort_info->start_recpos,llbuff));
+ goto try_next;
+ }
+ } while (left_length);
+
+ if (_mi_rec_unpack(info,sort_info->record,info->rec_buff,
+ sort_info->find_length) != MY_FILE_ERROR)
+ {
+ if (param->read_cache.error < 0)
+ DBUG_RETURN(1);
+ if ((param->testflag & (T_EXTEND | T_REP)) || searching)
+ {
+ if (info->s->calc_checksum)
+ info->checksum=mi_checksum(info,sort_info->record);
+ if (_mi_rec_check(info, sort_info->record))
+ {
+ mi_check_print_info(param,"Found wrong packed record at %s",
+ llstr(sort_info->start_recpos,llbuff));
+ goto try_next;
+ }
+ }
+ DBUG_RETURN(0);
+ }
+ try_next:
+ pos=(sort_info->start_recpos+=MI_DYN_ALIGN_SIZE);
+ searching=1;
+ }
+ case COMPRESSED_RECORD:
+ for (searching=0 ;; searching=1, sort_info->pos++)
+ {
+ if (_mi_read_cache(&param->read_cache,(byte*) block_info.header,sort_info->pos,
+ share->pack.ref_length,1))
+ DBUG_RETURN(-1);
+ if (searching && ! sort_info->fix_datafile)
+ {
+ param->error_printed=1;
+ DBUG_RETURN(1); /* Something wrong with data */
+ }
+ sort_info->start_recpos=sort_info->pos;
+ if (_mi_pack_get_block_info(info,&block_info,-1,sort_info->pos, NullS))
+ DBUG_RETURN(-1);
+ if (!block_info.rec_len &&
+ sort_info->pos + MEMMAP_EXTRA_MARGIN ==
+ param->read_cache.end_of_file)
+ DBUG_RETURN(-1);
+ if (block_info.rec_len < (uint) share->min_pack_length ||
+ block_info.rec_len > (uint) share->max_pack_length)
+ {
+ if (! searching)
+ mi_check_print_info(param,"Found block with wrong recordlength: %d at %s\n",
+ block_info.rec_len, llstr(sort_info->pos,llbuff));
+ continue;
+ }
+ if (_mi_read_cache(&param->read_cache,(byte*) info->rec_buff,
+ block_info.filepos, block_info.rec_len,1))
+ {
+ if (! searching)
+ mi_check_print_info(param,"Couldn't read hole record from %s",
+ llstr(sort_info->pos,llbuff));
+ continue;
+ }
+ if (_mi_pack_rec_unpack(info,sort_info->record,info->rec_buff,
+ block_info.rec_len))
+ {
+ if (! searching)
+ mi_check_print_info(param,"Found wrong record at %s", llstr(sort_info->pos,llbuff));
+ continue;
+ }
+ if (!sort_info->fix_datafile)
+ sort_info->filepos=sort_info->pos;
+ sort_info->max_pos=(sort_info->pos=block_info.filepos+
+ block_info.rec_len);
+ share->state.split++;
+ info->packed_length=block_info.rec_len;
+ DBUG_RETURN(0);
+ }
+ }
+ DBUG_RETURN(1); /* Impossible */
+}
+
+
+ /* Write record to new file */
+
+int sort_write_record(SORT_INFO *sort_info)
+{
+ int flag;
+ uint length;
+ ulong block_length,reclength;
+ byte *from;
+ byte block_buff[8];
+ MI_INFO *info;
+ MYISAM_SHARE *share;
+ MI_CHECK *param=sort_info->param;
+ DBUG_ENTER("sort_write_record");
+
+ info=sort_info->info;
+ share=info->s;
+ if (sort_info->fix_datafile)
+ {
+ switch (sort_info->new_data_file_type) {
+ case STATIC_RECORD:
+ if (my_b_write(&info->rec_cache,sort_info->record,
+ share->base.pack_reclength))
+ {
+ mi_check_print_error(param,"%d when writing to datafile",my_errno);
+ DBUG_RETURN(1);
+ }
+ sort_info->filepos+=share->base.pack_reclength;
+ info->s->state.checksum+=mi_static_checksum(info, sort_info->record);
+ break;
+ case DYNAMIC_RECORD:
+ if (! info->blobs)
+ from=info->rec_buff;
+ else
+ {
+ /* must be sure that local buffer is big enough */
+ reclength=info->s->base.pack_reclength+
+ _my_calc_total_blob_length(info,sort_info->record)+
+ ALIGN_SIZE(MI_MAX_DYN_BLOCK_HEADER)+MI_SPLIT_LENGTH+
+ MI_DYN_DELETE_BLOCK_HEADER;
+ if (sort_info->buff_length < reclength)
+ {
+ if (!(sort_info->buff=my_realloc(sort_info->buff, (uint) reclength,
+ MYF(MY_FREE_ON_ERROR |
+ MY_ALLOW_ZERO_PTR))))
+ DBUG_RETURN(1);
+ sort_info->buff_length=reclength;
+ }
+ from=sort_info->buff+ALIGN_SIZE(MI_MAX_DYN_BLOCK_HEADER);
+ }
+ info->checksum=mi_checksum(info,sort_info->record);
+ reclength=_mi_rec_pack(info,from,sort_info->record);
+ info->s->state.checksum+=info->checksum;
+ block_length=reclength+ 3 +test(reclength > 65532L);
+ if (block_length < share->base.min_block_length)
+ block_length=share->base.min_block_length;
+ flag=0;
+ info->update|=HA_STATE_WRITE_AT_END;
+ 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))
+ {
+ mi_check_print_error(param,"%d when writing to datafile",my_errno);
+ DBUG_RETURN(1);
+ }
+ sort_info->filepos+=block_length;
+ break;
+ case COMPRESSED_RECORD:
+ reclength=info->packed_length;
+ length=save_pack_length(block_buff,reclength);
+ if (info->s->base.blobs)
+ length+=save_pack_length(block_buff+length,info->blob_length);
+ if (my_b_write(&info->rec_cache,block_buff,length) ||
+ my_b_write(&info->rec_cache,(byte*) info->rec_buff,reclength))
+ {
+ mi_check_print_error(param,"%d when writing to datafile",my_errno);
+ DBUG_RETURN(1);
+ }
+ sort_info->filepos+=reclength+length;
+ break;
+ }
+ }
+ info->state->records++;
+ if ((param->testflag & T_WRITE_LOOP) &&
+ (info->state->records % WRITE_COUNT) == 0)
+ {
+ char llbuff[22];
+ printf("%s\r", llstr(info->state->records,llbuff)); VOID(fflush(stdout));
+ }
+ DBUG_RETURN(0);
+} /* sort_write_record */
+
+
+ /* Compare two keys from _create_index_by_sort */
+
+static int sort_key_cmp(SORT_INFO *sort_info, const void *a, const void *b)
+{
+ uint not_used;
+ return (_mi_key_cmp(sort_info->keyseg,*((uchar**) a),*((uchar**) b),
+ USE_WHOLE_KEY, SEARCH_SAME,&not_used));
+} /* sort_key_cmp */
+
+
+static int sort_key_write(SORT_INFO *sort_info, const void *a)
+{
+ uint diff_pos;
+ char llbuff[22],llbuff2[22];
+ MI_CHECK *param= sort_info->param;
+ int cmp;
+
+ if (sort_info->key_block->inited)
+ {
+ cmp=_mi_key_cmp(sort_info->keyseg,sort_info->key_block->lastkey,(uchar*) a,
+ USE_WHOLE_KEY,SEARCH_FIND | SEARCH_UPDATE ,&diff_pos);
+ }
+ else
+ {
+ cmp= -1; diff_pos=sort_info->keyinfo->keysegs;
+ }
+ if ((sort_info->keyinfo->flag & HA_NOSAME) && cmp == 0)
+ {
+ sort_info->dupp++;
+ sort_info->info->lastpos=get_record_for_key(sort_info->info,
+ sort_info->keyinfo,
+ (uchar*) a);
+ mi_check_print_warning(param,
+ "Duplicate key for record at %10s against record at %10s",
+ llstr(sort_info->info->lastpos,llbuff),
+ llstr(get_record_for_key(sort_info->info,
+ sort_info->keyinfo,
+ sort_info->key_block->
+ lastkey),
+ llbuff2));
+ if (sort_info->param->testflag & T_VERBOSE)
+ _mi_print_key(stdout,sort_info->keyseg,(uchar*) a, USE_WHOLE_KEY);
+ return (sort_delete_record(param));
+ }
+ sort_info->unique[diff_pos-1]++;
+#ifndef DBUG_OFF
+ if (cmp > 0)
+ {
+ mi_check_print_error(param,
+ "Internal error: Keys are not in order from sort");
+ return(1);
+ }
+#endif
+ return (sort_insert_key(param,sort_info->key_block,(uchar*) a,
+ HA_OFFSET_ERROR));
+} /* sort_key_write */
+
+
+ /* get pointer to record from a key */
+
+static my_off_t get_record_for_key(MI_INFO *info, MI_KEYDEF *keyinfo,
+ uchar *key)
+{
+ return _mi_dpos(info,0,key+_mi_keylength(keyinfo,key));
+} /* get_record_for_key */
+
+
+ /* Insert a key in sort-key-blocks */
+
+static int sort_insert_key(MI_CHECK *param,
+ register SORT_KEY_BLOCKS *key_block, uchar *key,
+ my_off_t prev_block)
+{
+ uint a_length,t_length,nod_flag;
+ my_off_t filepos;
+ uchar *anc_buff,*lastkey;
+ MI_KEY_PARAM s_temp;
+ MI_INFO *info;
+ SORT_INFO *sort_info= &param->sort_info;
+ DBUG_ENTER("sort_insert_key");
+
+ anc_buff=key_block->buff;
+ info=sort_info->info;
+ lastkey=key_block->lastkey;
+ nod_flag= (key_block == sort_info->key_block ? 0 :
+ sort_info->info->s->base.key_reflength);
+
+ if (!key_block->inited)
+ {
+ key_block->inited=1;
+ if (key_block == sort_info->key_block_end)
+ {
+ mi_check_print_error(param,"To many key-block-levels; Try increasing sort_key_blocks");
+ DBUG_RETURN(1);
+ }
+ a_length=2+nod_flag;
+ key_block->end_pos=anc_buff+2;
+ lastkey=0; /* No previous key in block */
+ }
+ else
+ a_length=mi_getint(anc_buff);
+
+ /* Save pointer to previous block */
+ if (nod_flag)
+ _mi_kpointer(info,key_block->end_pos,prev_block);
+
+ t_length=(*sort_info->keyinfo->pack_key)(sort_info->keyinfo,nod_flag,
+ (uchar*) 0,lastkey,lastkey,key,
+ &s_temp);
+ (*sort_info->keyinfo->store_key)(sort_info->keyinfo,
+ key_block->end_pos+nod_flag,&s_temp);
+ a_length+=t_length;
+ mi_putint(anc_buff,a_length,nod_flag);
+ key_block->end_pos+=t_length;
+ if (a_length <= sort_info->keyinfo->block_length)
+ {
+ VOID(_mi_move_key(sort_info->keyinfo,key_block->lastkey,key));
+ key_block->last_length=a_length-t_length;
+ DBUG_RETURN(0);
+ }
+
+ /* Fill block with end-zero and write filled block */
+ mi_putint(anc_buff,key_block->last_length,nod_flag);
+ bzero((byte*) anc_buff+key_block->last_length,
+ sort_info->keyinfo->block_length- key_block->last_length);
+ if ((filepos=_mi_new(info,sort_info->keyinfo)) == HA_OFFSET_ERROR)
+ return 1;
+ if (my_pwrite(info->s->kfile,(byte*) anc_buff,
+ (uint) sort_info->keyinfo->block_length,filepos,
+ param->myf_rw))
+ DBUG_RETURN(1);
+ DBUG_DUMP("buff",(byte*) anc_buff,mi_getint(anc_buff));
+
+ /* Write separator-key to block in next level */
+ if (sort_insert_key(param,key_block+1,key_block->lastkey,filepos))
+ DBUG_RETURN(1);
+
+ /* clear old block and write new key in it */
+ key_block->inited=0;
+ DBUG_RETURN(sort_insert_key(param, key_block,key,prev_block));
+} /* sort_insert_key */
+
+
+ /* Delete record when we found a duplicated key */
+
+static int sort_delete_record(MI_CHECK *param)
+{
+ uint i;
+ int old_file,error;
+ uchar *key;
+ MI_INFO *info;
+ SORT_INFO *sort_info= &param->sort_info;
+ DBUG_ENTER("sort_delete_record");
+
+ if (param->opt_rep_quick == 1)
+ {
+ mi_check_print_error(param,
+ "Quick-recover aborted; Run recovery without switch 'q' or with switch -qq");
+ DBUG_RETURN(1);
+ }
+ info=sort_info->info;
+ if (info->s->options & HA_OPTION_COMPRESS_RECORD)
+ {
+ mi_check_print_error(param,
+ "Recover aborted; Can't run standard recovery on compressed tables with errors in data-file. Use switch 'myisamchk --safe-recover' to fix it\n",stderr);;
+ DBUG_RETURN(1);
+ }
+
+ old_file=info->dfile;
+ info->dfile=info->rec_cache.file;
+ if (sort_info->key)
+ {
+ key=info->lastkey+info->s->base.max_key_length;
+ if ((error=(*info->s->read_rnd)(info,sort_info->record,info->lastpos,0)) &&
+ error != HA_ERR_RECORD_DELETED)
+ {
+ mi_check_print_error(param,"Can't read record to be removed");
+ info->dfile=old_file;
+ DBUG_RETURN(1);
+ }
+
+ for (i=0 ; i < sort_info->key ; i++)
+ {
+ uint key_length=_mi_make_key(info,i,key,sort_info->record,info->lastpos);
+ if (_mi_ck_delete(info,i,key,key_length))
+ {
+ mi_check_print_error(param,"Can't delete key %d from record to be removed",i+1);
+ info->dfile=old_file;
+ DBUG_RETURN(1);
+ }
+ }
+ if (info->s->calc_checksum)
+ info->s->state.checksum-=(*info->s->calc_checksum)(info,
+ sort_info->record);
+ }
+ error=flush_io_cache(&info->rec_cache) || (*info->s->delete_record)(info);
+ info->dfile=old_file; /* restore actual value */
+ info->state->records--;
+ DBUG_RETURN(error);
+} /* sort_delete_record */
+
+
+ /* Fix all pending blocks and flush everything to disk */
+
+static int flush_pending_blocks(MI_CHECK *param)
+{
+ uint nod_flag,length;
+ my_off_t filepos;
+ MI_INFO *info;
+ SORT_KEY_BLOCKS *key_block;
+ SORT_INFO *sort_info= &param->sort_info;
+ DBUG_ENTER("flush_pending_blocks");
+
+ filepos= HA_OFFSET_ERROR; /* if empty file */
+ info=sort_info->info;
+ nod_flag=0;
+ for (key_block=sort_info->key_block ; key_block->inited ; key_block++)
+ {
+ key_block->inited=0;
+ length=mi_getint(key_block->buff);
+ if (nod_flag)
+ _mi_kpointer(info,key_block->end_pos,filepos);
+ if ((filepos=_mi_new(info,sort_info->keyinfo)) == HA_OFFSET_ERROR)
+ DBUG_RETURN(1);
+ bzero((byte*) key_block->buff+length,
+ sort_info->keyinfo->block_length-length);
+ if (my_pwrite(info->s->kfile,(byte*) key_block->buff,
+ (uint) sort_info->keyinfo->block_length,filepos,
+ param->myf_rw))
+ DBUG_RETURN(1);
+ DBUG_DUMP("buff",(byte*) key_block->buff,length);
+ nod_flag=1;
+ }
+ info->s->state.key_root[sort_info->key]=filepos; /* Last is root for tree */
+ DBUG_RETURN(0);
+} /* flush_pending_blocks */
+
+
+ /* alloc space and pointers for key_blocks */
+
+static SORT_KEY_BLOCKS *alloc_key_blocks(MI_CHECK *param, uint blocks,
+ uint buffer_length)
+{
+ reg1 uint i;
+ SORT_KEY_BLOCKS *block;
+ DBUG_ENTER("alloc_key_blocks");
+
+ if (!(block=(SORT_KEY_BLOCKS*) my_malloc((sizeof(SORT_KEY_BLOCKS)+
+ buffer_length+IO_SIZE)*blocks,
+ MYF(0))))
+ {
+ mi_check_print_error(param,"Not Enough memory for sort-key-blocks");
+ return(0);
+ }
+ for (i=0 ; i < blocks ; i++)
+ {
+ block[i].inited=0;
+ block[i].buff=(uchar*) (block+blocks)+(buffer_length+IO_SIZE)*i;
+ }
+ DBUG_RETURN(block);
+} /* alloc_key_blocks */
+
+
+ /* Check if file is almost full */
+
+int test_if_almost_full(MI_INFO *info)
+{
+ if (info->s->options & HA_OPTION_COMPRESS_RECORD)
+ return 0;
+ return (my_seek(info->s->kfile,0L,MY_SEEK_END,MYF(0))/10*9 >
+ (my_off_t) (info->s->base.max_key_file_length) ||
+ my_seek(info->dfile,0L,MY_SEEK_END,MYF(0))/10*9 >
+ (my_off_t) info->s->base.max_data_file_length);
+}
+
+ /* Recreate table with bigger more alloced record-data */
+
+int recreate_table(MI_CHECK *param, MI_INFO **org_info, char *filename)
+{
+ int error;
+ MI_INFO info;
+ MYISAM_SHARE share;
+ MI_KEYDEF *keyinfo,*key,*key_end;
+ MI_KEYSEG *keysegs,*keyseg;
+ MI_COLUMNDEF *recdef,*rec,*end;
+ MI_UNIQUEDEF *uniquedef,*u_ptr,*u_end;
+ 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;
+
+ error=1; /* Default error */
+ info= **org_info;
+ status_info= (*org_info)->state[0];
+ info.state= &status_info;
+ share= *(*org_info)->s;
+ unpack= (share.options & HA_OPTION_COMPRESS_RECORD) &&
+ (param->testflag & T_UNPACK);
+ if (!(keyinfo=(MI_KEYDEF*) my_alloca(sizeof(MI_KEYDEF)*share.base.keys)))
+ return 0;
+ memcpy((byte*) keyinfo,(byte*) share.keyinfo,
+ (size_t) (sizeof(MI_KEYDEF)*share.base.keys));
+
+ key_parts= share.base.all_key_parts;
+ if (!(keysegs=(MI_KEYSEG*) my_alloca(sizeof(MI_KEYSEG)*
+ (key_parts+share.base.keys))))
+ {
+ my_afree((gptr) keyinfo);
+ return 1;
+ }
+ if (!(recdef=(MI_COLUMNDEF*)
+ my_alloca(sizeof(MI_COLUMNDEF)*(share.base.fields+1))))
+ {
+ my_afree((gptr) keyinfo);
+ my_afree((gptr) keysegs);
+ return 1;
+ }
+ if (!(uniquedef=(MI_UNIQUEDEF*)
+ my_alloca(sizeof(MI_UNIQUEDEF)*(share.state.header.uniques+1))))
+ {
+ my_afree((gptr) recdef);
+ my_afree((gptr) keyinfo);
+ my_afree((gptr) keysegs);
+ return 1;
+ }
+
+ /* Copy the column definitions */
+ memcpy((byte*) recdef,(byte*) share.rec,
+ (size_t) (sizeof(MI_COLUMNDEF)*(share.base.fields+1)));
+ for (rec=recdef,end=recdef+share.base.fields; rec != end ; rec++)
+ {
+ if (unpack && !(share.options & HA_OPTION_PACK_RECORD) &&
+ rec->type != FIELD_BLOB &&
+ rec->type != FIELD_VARCHAR &&
+ rec->type != FIELD_CHECK)
+ rec->type=(int) FIELD_NORMAL;
+ }
+
+ /* Change the new key to point at the saved key segments */
+ memcpy((byte*) keysegs,(byte*) share.keyparts,
+ (size_t) (sizeof(MI_KEYSEG)*(key_parts+share.base.keys+
+ share.state.header.uniques)));
+ keyseg=keysegs;
+ for (key=keyinfo,key_end=keyinfo+share.base.keys; key != key_end ; key++)
+ {
+ key->seg=keyseg;
+ for (; keyseg->type ; keyseg++)
+ {
+ if (param->language)
+ keyseg->language=param->language; /* change language */
+ }
+ keyseg++; /* Skipp end pointer */
+ }
+
+ /* Copy the unique definitions and change them to point at the new key
+ segments*/
+ memcpy((byte*) uniquedef,(byte*) share.uniqueinfo,
+ (size_t) (sizeof(MI_UNIQUEDEF)*(share.state.header.uniques)));
+ for (u_ptr=uniquedef,u_end=uniquedef+share.state.header.uniques;
+ u_ptr != u_end ; u_ptr++)
+ {
+ u_ptr->seg=keyseg;
+ keyseg+=u_ptr->keysegs+1;
+ }
+ if (share.options & HA_OPTION_COMPRESS_RECORD)
+ share.base.records=max_records=info.state->records;
+ else if (share.base.min_pack_length)
+ max_records=(ha_rows) (my_seek(info.dfile,0L,MY_SEEK_END,MYF(0)) /
+ (ulong) share.base.min_pack_length);
+ else
+ max_records=0;
+ unpack= (share.options & HA_OPTION_COMPRESS_RECORD) &&
+ (param->testflag & T_UNPACK);
+ share.options&= ~HA_OPTION_TEMP_COMPRESS_RECORD;
+
+ file_length=(ulonglong) my_seek(info.dfile,0L,MY_SEEK_END,MYF(0));
+ tmp_length= file_length+file_length/10;
+ set_if_bigger(file_length,param->max_data_file_length);
+ set_if_bigger(file_length,tmp_length);
+ set_if_bigger(file_length,(ulonglong) share.base.max_data_file_length);
+
+ VOID(mi_close(*org_info));
+ bzero((char*) &create_info,sizeof(create_info));
+ create_info.max_rows=max(max_records,share.base.records);
+ create_info.reloc_rows=share.base.reloc;
+ create_info.old_options=(share.options |
+ (unpack ? HA_OPTION_TEMP_COMPRESS_RECORD : 0));
+
+ create_info.data_file_length=file_length;
+ create_info.auto_increment=share.state.auto_increment;
+ create_info.raid_type= share.base.raid_type;
+ create_info.raid_chunks= share.base.raid_chunks;
+ create_info.raid_chunksize= share.base.raid_chunksize;
+ 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)),
+ share.base.keys - share.state.header.uniques,
+ keyinfo, share.base.fields, recdef,
+ share.state.header.uniques, uniquedef,
+ &create_info,
+ HA_DONT_TOUCH_DATA))
+ {
+ mi_check_print_error(param,"Got error %d when trying to recreate indexfile",my_errno);
+ goto end;
+ }
+ *org_info=mi_open(name,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);
+ if (!*org_info)
+ {
+ mi_check_print_error(param,"Got error %d when trying to open re-created indexfile",
+ my_errno);
+ goto end;
+ }
+ /* We are modifing */
+ (*org_info)->s->options&= ~HA_OPTION_READ_ONLY_DATA;
+ VOID(_mi_readinfo(*org_info,F_WRLCK,0));
+ (*org_info)->state->records=info.state->records;
+ if (share.state.create_time)
+ (*org_info)->s->state.create_time=share.state.create_time;
+ (*org_info)->s->state.unique=(*org_info)->this_unique=
+ share.state.unique;
+ (*org_info)->s->state.checksum=share.state.checksum;
+ (*org_info)->state->del=info.state->del;
+ (*org_info)->s->state.dellink=share.state.dellink;
+ (*org_info)->state->empty=info.state->empty;
+ (*org_info)->state->data_file_length=info.state->data_file_length;
+ if (update_state_info(param,*org_info,UPDATE_TIME | UPDATE_STAT |
+ UPDATE_OPEN_COUNT))
+ goto end;
+ error=0;
+end:
+ my_afree((gptr) uniquedef);
+ my_afree((gptr) keyinfo);
+ my_afree((gptr) recdef);
+ my_afree((gptr) keysegs);
+ return error;
+}
+
+
+ /* write suffix to data file if neaded */
+
+int write_data_suffix(MI_CHECK *param, MI_INFO *info)
+{
+ if (info->s->options & HA_OPTION_COMPRESS_RECORD &&
+ param->sort_info.fix_datafile)
+ {
+ char buff[MEMMAP_EXTRA_MARGIN];
+ bzero(buff,sizeof(buff));
+ if (my_b_write(&info->rec_cache,buff,sizeof(buff)))
+ {
+ mi_check_print_error(param,"%d when writing to datafile",my_errno);
+ return 1;
+ }
+ param->read_cache.end_of_file+=sizeof(buff);
+ }
+ return 0;
+}
+
+
+ /* Update state and myisamchk_time of indexfile */
+
+int update_state_info(MI_CHECK *param, MI_INFO *info,uint update)
+{
+ MYISAM_SHARE *share=info->s;
+
+ if (update & UPDATE_OPEN_COUNT)
+ {
+ share->state.open_count=0;
+ share->global_changed=0;
+ }
+ if (update & UPDATE_STAT)
+ {
+ uint key_parts= mi_uint2korr(share->state.header.key_parts);
+ share->state.rec_per_key_rows=info->state->records;
+ memcpy((char*) share->state.rec_per_key_part,
+ (char*) param->rec_per_key_part,
+ sizeof(*param->rec_per_key_part)*key_parts);
+ }
+ if (update & (UPDATE_STAT | UPDATE_SORT | UPDATE_TIME | UPDATE_AUTO_INC))
+ {
+ if (update & UPDATE_TIME)
+ {
+ share->state.check_time= (long) time((time_t*) 0);
+ if (!share->state.create_time)
+ share->state.create_time=share->state.check_time;
+ }
+ if (mi_state_info_write(share->kfile,&share->state,1+2))
+ goto err;
+ }
+ { /* Force update of status */
+ int error;
+ uint r_locks=share->r_locks,w_locks=share->w_locks;
+ share->r_locks=share->w_locks=0;
+ error=_mi_writeinfo(info,WRITEINFO_NO_UNLOCK);
+ share->r_locks=r_locks; share->w_locks=w_locks;
+ if (!error)
+ return 0;
+ }
+err:
+ mi_check_print_error(param,"%d when updateing keyfile",my_errno);
+ return 1;
+}
+
+ /*
+ Update auto increment value for a table
+ When setting the 'repair_only' flag we only want to change the
+ old auto_increment value if its wrong (smaller than some given key).
+ The reason is that we shouldn't change the auto_increment value
+ for a table without good reason when only doing a repair; If the
+ user have inserted and deleted rows, the auto_increment value
+ may be bigger than the biggest current row and this is ok.
+
+ If repair_only is not set, we will update the flag to the value in
+ param->auto_increment is bigger than the biggest key.
+ */
+
+void update_auto_increment_key(MI_CHECK *param, MI_INFO *info,
+ my_bool repair_only)
+{
+ if (!info->s->base.auto_key ||
+ !(((ulonglong) 1 << (info->s->base.auto_key-1)
+ & info->s->state.key_map)))
+ {
+ mi_check_print_info(param,"Table: %s doesn't have an auto increment key\n",
+ param->isam_file_name);
+ return;
+ }
+ if (!(param->testflag & T_SILENT) &&
+ !(param->testflag & (T_REP | T_REP_BY_SORT)))
+ printf("Updating MyISAM file: %s\n", param->isam_file_name);
+ /* We have to use keyread here as a normal read uses info->rec_buff */
+ mi_extra(info,HA_EXTRA_KEYREAD);
+ if (mi_rlast(info,info->rec_buff, info->s->base.auto_key-1))
+ {
+ if (my_errno != HA_ERR_END_OF_FILE)
+ {
+ mi_extra(info,HA_EXTRA_NO_KEYREAD);
+ mi_check_print_error(param,"%d when reading last record",my_errno);
+ return;
+ }
+ if (!repair_only)
+ info->s->state.auto_increment=param->auto_increment_value;
+ }
+ else
+ {
+ ulonglong auto_increment= (repair_only ? info->s->state.auto_increment :
+ param->auto_increment_value);
+ info->s->state.auto_increment=0;
+ update_auto_increment(info,info->rec_buff);
+ set_if_bigger(info->s->state.auto_increment,auto_increment);
+ }
+ mi_extra(info,HA_EXTRA_NO_KEYREAD);
+ update_state_info(param, info, UPDATE_AUTO_INC);
+ return;
+}
+
+ /* calculate unique keys for each part key */
+
+static void update_key_parts(MI_KEYDEF *keyinfo,
+ ulong *rec_per_key_part,
+ ulonglong *unique,
+ ulonglong records)
+{
+ ulonglong count=0,tmp;
+ uint parts;
+ for (parts=0 ; parts < keyinfo->keysegs ; parts++)
+ {
+ count+=unique[parts];
+ if (count == 0)
+ tmp=records;
+ else
+ tmp= (records+count/2) / count;
+ if (tmp >= (ulonglong) ~(ulong) 0)
+ tmp=(ulonglong) ~(ulong) 0;
+ *rec_per_key_part=(ulong) tmp;
+ rec_per_key_part++;
+ }
+}
+
+
+ha_checksum mi_byte_checksum(const byte *buf, uint length)
+{
+ ha_checksum crc;
+ const byte *end=buf+length;
+ for (crc=0; buf != end; buf++)
+ crc=((crc << 1) + *((uchar*) buf)) +
+ test(crc & (((ha_checksum) 1) << (8*sizeof(ha_checksum)-1)));
+ return crc;
+}
diff --git a/myisam/mi_checksum.c b/myisam/mi_checksum.c
new file mode 100644
index 00000000000..9dabe55e239
--- /dev/null
+++ b/myisam/mi_checksum.c
@@ -0,0 +1,67 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 checksum for a row */
+
+#include "myisamdef.h"
+
+ha_checksum mi_checksum(MI_INFO *info, const byte *buf)
+{
+ uint i;
+ ha_checksum crc=0;
+ MI_COLUMNDEF *rec=info->s->rec;
+
+ for (i=info->s->base.fields ; i-- ; buf+=(rec++)->length)
+ {
+ const byte *pos;
+ const byte *end;
+ switch (rec->type) {
+ case FIELD_BLOB:
+ {
+ ulong length=_mi_calc_blob_length(rec->length-
+ mi_portable_sizeof_char_ptr,
+ buf);
+ memcpy((char*) &pos, buf+rec->length- mi_portable_sizeof_char_ptr,
+ sizeof(char*));
+ end=pos+length;
+ break;
+ }
+ case FIELD_VARCHAR:
+ {
+ uint length;
+ length=uint2korr(buf);
+ pos=buf+2; end=pos+length;
+ break;
+ }
+ default:
+ pos=buf; end=buf+rec->length;
+ break;
+ }
+ for ( ; pos != end ; pos++)
+ crc=((crc << 8) + *((uchar*) pos)) + (crc >> (8*sizeof(ha_checksum)-8));
+ }
+ return crc;
+}
+
+
+ha_checksum mi_static_checksum(MI_INFO *info, const byte *pos)
+{
+ ha_checksum crc;
+ const byte *end=pos+info->s->base.reclength;
+ for (crc=0; pos != end; pos++)
+ crc=((crc << 8) + *((uchar*) pos)) + (crc >> (8*sizeof(ha_checksum)-8));
+ return crc;
+}
diff --git a/myisam/mi_close.c b/myisam/mi_close.c
new file mode 100644
index 00000000000..ebd64aa2349
--- /dev/null
+++ b/myisam/mi_close.c
@@ -0,0 +1,105 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 */
+/*
+ TODO:
+ We need to have a separate mutex on the closed file to allow other threads
+ to open other files during the time we flush the cache and close this file
+*/
+
+#include "myisamdef.h"
+
+int mi_close(register MI_INFO *info)
+{
+ int error=0,flag;
+ MYISAM_SHARE *share=info->s;
+ DBUG_ENTER("mi_close");
+ DBUG_PRINT("enter",("base: %lx reopen: %u locks: %u",
+ info,(uint) share->reopen,
+ (uint) (share->w_locks+share->r_locks)));
+
+ pthread_mutex_lock(&THR_LOCK_myisam);
+ if (info->lock_type == F_EXTRA_LCK)
+ info->lock_type=F_UNLCK; /* HA_EXTRA_NO_USER_CHANGE */
+
+ if (share->reopen == 1)
+ _mi_decrement_open_count(info);
+
+ if (info->lock_type != F_UNLCK)
+ {
+ if (mi_lock_database(info,F_UNLCK))
+ error=my_errno;
+ }
+ pthread_mutex_lock(&share->intern_lock);
+
+ if (share->options & HA_OPTION_READ_ONLY_DATA)
+ share->r_locks--;
+ if (info->opt_flag & (READ_CACHE_USED | WRITE_CACHE_USED))
+ {
+ if (end_io_cache(&info->rec_cache))
+ error=my_errno;
+ info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
+ }
+ flag= !--share->reopen;
+ myisam_open_list=list_delete(myisam_open_list,&info->open_list);
+ pthread_mutex_unlock(&share->intern_lock);
+
+ if (flag)
+ {
+ if (share->kfile >= 0 &&
+ flush_key_blocks(share->kfile,
+ share->temporary ? FLUSH_IGNORE_CHANGED :
+ FLUSH_RELEASE))
+ error=my_errno;
+ if (share->kfile >= 0 && my_close(share->kfile,MYF(0)))
+ error = my_errno;
+#ifdef HAVE_MMAP
+ if (share->file_map)
+ _mi_unmap_file(info);
+#endif
+ if (share->decode_trees)
+ {
+ my_free((gptr) share->decode_trees,MYF(0));
+ my_free((gptr) share->decode_tables,MYF(0));
+ }
+#ifdef THREAD
+ thr_lock_delete(&share->lock);
+ VOID(pthread_mutex_destroy(&share->intern_lock));
+ {
+ int i,keys;
+ keys = share->state.header.keys;
+ for(i=0; i<keys; i++) {
+ VOID(rwlock_destroy(&share->key_root_lock[i]));
+ }
+ }
+#endif
+ my_free((gptr) info->s,MYF(0));
+ }
+ pthread_mutex_unlock(&THR_LOCK_myisam);
+ if (info->dfile >= 0 && my_close(info->dfile,MYF(0)))
+ error = my_errno;
+
+ myisam_log_command(MI_LOG_CLOSE,info,NULL,0,error);
+ my_free((gptr) info->rec_alloc,MYF(MY_ALLOW_ZERO_PTR));
+ my_free((gptr) info,MYF(0));
+
+ if (error)
+ {
+ DBUG_RETURN(my_errno=error);
+ }
+ DBUG_RETURN(0);
+} /* mi_close */
diff --git a/myisam/mi_create.c b/myisam/mi_create.c
new file mode 100644
index 00000000000..27c47c5170b
--- /dev/null
+++ b/myisam/mi_create.c
@@ -0,0 +1,628 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 MyISAM table */
+
+#include "fulltext.h"
+#if defined(MSDOS) || defined(__WIN__)
+#ifdef __WIN__
+#include <fcntl.h>
+#else
+#include <process.h> /* Prototype for getpid */
+#endif
+#endif
+#include <m_ctype.h>
+
+ /*
+ ** Old options is used when recreating database, from isamchk
+ */
+
+int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs,
+ uint columns, MI_COLUMNDEF *recinfo,
+ uint uniques, MI_UNIQUEDEF *uniquedefs,
+ MI_CREATE_INFO *ci,uint flags)
+{
+ register uint i,j;
+ File dfile,file;
+ int errpos,save_errno;
+ 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[max(FN_REFLEN,2048)];
+ ulong pack_reclength;
+ ulonglong tot_length,max_rows;
+ enum en_fieldtype type;
+ MYISAM_SHARE share;
+ MI_KEYDEF *keydef,tmp_keydef;
+ MI_UNIQUEDEF *uniquedef;
+ MI_KEYSEG *keyseg,tmp_keyseg;
+ MI_COLUMNDEF *rec;
+ ulong rec_per_key_part[MI_MAX_POSSIBLE_KEY*MI_MAX_KEY_SEG];
+ my_off_t key_root[MI_MAX_POSSIBLE_KEY],key_del[MI_MAX_KEY_BLOCK_SIZE];
+ MI_CREATE_INFO tmp_create_info;
+ DBUG_ENTER("mi_create");
+
+ if (!ci)
+ {
+ bzero((char*) &tmp_create_info,sizeof(tmp_create_info));
+ ci=&tmp_create_info;
+ }
+
+ if (keys + uniques > MI_MAX_KEY)
+ {
+ DBUG_RETURN(my_errno=HA_WRONG_CREATE_OPTION);
+ }
+ LINT_INIT(dfile);
+ LINT_INIT(file);
+ pthread_mutex_lock(&THR_LOCK_myisam);
+ errpos=0;
+ options=0;
+ bzero((byte*) &share,sizeof(share));
+
+ if (flags & HA_DONT_TOUCH_DATA)
+ {
+ if (!(ci->old_options & HA_OPTION_TEMP_COMPRESS_RECORD))
+ options=ci->old_options &
+ (HA_OPTION_COMPRESS_RECORD | HA_OPTION_PACK_RECORD |
+ HA_OPTION_READ_ONLY_DATA | HA_OPTION_CHECKSUM |
+ HA_OPTION_TMP_TABLE | HA_OPTION_DELAY_KEY_WRITE);
+ else
+ options=ci->old_options &
+ (HA_OPTION_CHECKSUM | HA_OPTION_TMP_TABLE | HA_OPTION_DELAY_KEY_WRITE);
+ }
+
+ if (ci->reloc_rows > ci->max_rows)
+ ci->reloc_rows=ci->max_rows; /* Check if wrong parameter */
+
+ /* Start by checking fields and field-types used */
+
+ reclength=varchar_count=varchar_length=long_varchar_count=packed=
+ min_pack_length=pack_reclength=0;
+ for (rec=recinfo, fields=0 ;
+ fields != columns ;
+ rec++,fields++)
+ {
+ reclength+=rec->length;
+ if ((type=(enum en_fieldtype) rec->type) != FIELD_NORMAL &&
+ type != FIELD_CHECK)
+ {
+ packed++;
+ if (type == FIELD_BLOB)
+ {
+ share.base.blobs++;
+ if (pack_reclength != INT_MAX32)
+ {
+ if (rec->length == 4+mi_portable_sizeof_char_ptr)
+ pack_reclength= INT_MAX32;
+ else
+ pack_reclength+=(1 << ((rec->length-mi_portable_sizeof_char_ptr)*8)); /* Max blob length */
+ }
+ }
+ else if (type == FIELD_SKIPP_PRESPACE ||
+ type == FIELD_SKIPP_ENDSPACE)
+ {
+ if (pack_reclength != INT_MAX32)
+ pack_reclength+= rec->length > 255 ? 2 : 1;
+ min_pack_length++;
+ }
+ else if (type == FIELD_VARCHAR)
+ {
+ varchar_count++;
+ varchar_length+=rec->length-2;
+ packed--;
+ pack_reclength+=1;
+ if (test(rec->length > 257))
+ { /* May be packed on 3 bytes */
+ long_varchar_count++;
+ pack_reclength+=2;
+ }
+ }
+ else if (type != FIELD_SKIPP_ZERO)
+ {
+ min_pack_length+=rec->length;
+ packed--; /* Not a pack record type */
+ }
+ }
+ else /* FIELD_NORMAL */
+ min_pack_length+=rec->length;
+ }
+ if ((packed & 7) == 1)
+ { /* Bad packing, try to remove a zero-field */
+ while (rec != recinfo)
+ {
+ rec--;
+ if (rec->type == (int) FIELD_SKIPP_ZERO && rec->length == 1)
+ {
+ rec->type=(int) FIELD_NORMAL;
+ packed--;
+ min_pack_length++;
+ break;
+ }
+ }
+ }
+
+ if (packed || (flags & HA_PACK_RECORD))
+ options|=HA_OPTION_PACK_RECORD; /* Must use packed records */
+ if (options & (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD))
+ min_pack_length+=varchar_count; /* Min length to pack */
+ else
+ {
+ min_pack_length+=varchar_length+2*varchar_count;
+ }
+ if (flags & HA_CREATE_TMP_TABLE)
+ options|= HA_OPTION_TMP_TABLE;
+ if (flags & HA_CREATE_CHECKSUM || (options & HA_OPTION_CHECKSUM))
+ {
+ options|= HA_OPTION_CHECKSUM;
+ min_pack_length++;
+ }
+ if (flags & HA_CREATE_DELAY_KEY_WRITE)
+ options|= HA_OPTION_DELAY_KEY_WRITE;
+
+ packed=(packed+7)/8;
+ if (pack_reclength != INT_MAX32)
+ pack_reclength+= reclength+packed +
+ test(test_all_bits(options, HA_OPTION_CHECKSUM | HA_PACK_RECORD));
+ min_pack_length+=packed;
+
+ if (!ci->data_file_length)
+ {
+ if (ci->max_rows == 0 || pack_reclength == INT_MAX32)
+ ci->data_file_length= INT_MAX32-1; /* Should be enough */
+ else if ((~(ulonglong) 0)/ci->max_rows < (ulonglong) pack_reclength)
+ ci->data_file_length= ~(ulonglong) 0;
+ else
+ ci->data_file_length=(ulonglong) ci->max_rows*pack_reclength;
+ }
+ else if (!ci->max_rows)
+ ci->max_rows=(ha_rows) (ci->data_file_length/(min_pack_length +
+ ((options & HA_OPTION_PACK_RECORD) ?
+ 3 : 0)));
+
+ if (options & (HA_OPTION_COMPRESS_RECORD | HA_OPTION_PACK_RECORD))
+ pointer=mi_get_pointer_length(ci->data_file_length,4);
+ else
+ pointer=mi_get_pointer_length(ci->max_rows,4);
+ if (!(max_rows=(ulonglong) ci->max_rows))
+ max_rows= ((((ulonglong) 1 << (pointer*8)) -1) / min_pack_length);
+
+
+ real_reclength=reclength;
+ if (!(options & (HA_OPTION_COMPRESS_RECORD | HA_OPTION_PACK_RECORD)))
+ {
+ if (reclength <= pointer)
+ reclength=pointer+1; /* reserve place for delete link */
+ }
+ else
+ reclength+=long_varchar_count; /* We need space for this! */
+
+ max_key_length=0; tot_length=0 ; key_segs=0;
+ max_key_block_length=0;
+ share.state.rec_per_key_part=rec_per_key_part;
+ bzero((char*) rec_per_key_part,sizeof(rec_per_key_part));
+ share.state.key_root=key_root;
+ share.state.key_del=key_del;
+ if (uniques)
+ {
+ max_key_block_length= MI_KEY_BLOCK_LENGTH;
+ max_key_length= MI_UNIQUE_HASH_LENGTH;
+ }
+
+ for (i=0, keydef=keydefs ; i < keys ; i++ , keydef++)
+ {
+ share.state.key_root[i]= HA_OFFSET_ERROR;
+
+ min_key_length_skipp=length=0;
+ key_length=pointer;
+
+ if (keydef->flag & HA_FULLTEXT) /* SerG */
+ {
+ keydef->flag=HA_FULLTEXT | HA_PACK_KEY | HA_VAR_LENGTH_KEY;
+ options|=HA_OPTION_PACK_KEYS; /* Using packed keys */
+
+ if (flags & HA_DONT_TOUCH_DATA)
+ {
+ /* called by myisamchk - i.e. table structure was taken from
+ MYI file and FULLTEXT key *do has* additional FT_SEGS keysegs.
+ We'd better delete them now
+ */
+ keydef->keysegs-=FT_SEGS;
+ }
+
+ for (j=0, keyseg=keydef->seg ; (int) j < keydef->keysegs ;
+ j++, keyseg++)
+ {
+ if (keyseg->type != HA_KEYTYPE_TEXT &&
+ keyseg->type != HA_KEYTYPE_VARTEXT)
+ {
+ my_errno=HA_WRONG_CREATE_OPTION;
+ goto err;
+ }
+ }
+ keydef->keysegs+=FT_SEGS;
+
+ key_length+= HA_FT_MAXLEN+HA_FT_WLEN;
+#ifdef EVAL_RUN
+ key_length++;
+#endif
+
+ length++; /* At least one length byte */
+ min_key_length_skipp+=HA_FT_MAXLEN;
+#if HA_FT_MAXLEN >= 255
+ min_key_length_skipp+=2; /* prefix may be 3 bytes */
+ length+=2;
+#endif
+ }
+ else
+ {
+ /* Test if prefix compression */
+ if (keydef->flag & HA_PACK_KEY)
+ {
+ /* Can't use space_compression on number keys */
+ if ((keydef->seg[0].flag & HA_SPACE_PACK) &&
+ keydef->seg[0].type == (int) HA_KEYTYPE_NUM)
+ keydef->seg[0].flag&= ~HA_SPACE_PACK;
+
+ /* Only use HA_PACK_KEY if the first segment is a variable length key */
+ if (!(keydef->seg[0].flag & (HA_SPACE_PACK | HA_BLOB_PART |
+ HA_VAR_LENGTH)))
+ {
+ /* pack relative to previous key */
+ keydef->flag&= ~HA_PACK_KEY;
+ keydef->flag|= HA_BINARY_PACK_KEY | HA_VAR_LENGTH_KEY;
+ }
+ else
+ {
+ keydef->seg[0].flag|=HA_PACK_KEY; /* for easyer intern test */
+ keydef->flag|=HA_VAR_LENGTH_KEY;
+ options|=HA_OPTION_PACK_KEYS; /* Using packed keys */
+ }
+ }
+ if (keydef->flag & HA_BINARY_PACK_KEY)
+ options|=HA_OPTION_PACK_KEYS; /* Using packed keys */
+
+ if (keydef->flag & HA_AUTO_KEY)
+ share.base.auto_key=i+1;
+ for (j=0, keyseg=keydef->seg ; j < keydef->keysegs ; j++, keyseg++)
+ {
+ /* numbers are stored with high by first to make compression easier */
+ switch (keyseg->type) {
+ case HA_KEYTYPE_SHORT_INT:
+ case HA_KEYTYPE_LONG_INT:
+ case HA_KEYTYPE_FLOAT:
+ case HA_KEYTYPE_DOUBLE:
+ case HA_KEYTYPE_USHORT_INT:
+ case HA_KEYTYPE_ULONG_INT:
+ case HA_KEYTYPE_LONGLONG:
+ case HA_KEYTYPE_ULONGLONG:
+ case HA_KEYTYPE_INT24:
+ case HA_KEYTYPE_UINT24:
+ case HA_KEYTYPE_INT8:
+ keyseg->flag|= HA_SWAP_KEY;
+ /* fall through */
+ default:
+ break;
+ }
+ if (keyseg->flag & HA_SPACE_PACK)
+ {
+ keydef->flag |= HA_SPACE_PACK_USED | HA_VAR_LENGTH_KEY;
+ options|=HA_OPTION_PACK_KEYS; /* Using packed keys */
+ length++; /* At least one length byte */
+ min_key_length_skipp+=keyseg->length;
+ if (keyseg->length >= 255)
+ { /* prefix may be 3 bytes */
+ min_key_length_skipp+=2;
+ length+=2;
+ }
+ }
+ if (keyseg->flag & (HA_VAR_LENGTH | HA_BLOB_PART))
+ {
+ keydef->flag|=HA_VAR_LENGTH_KEY;
+ length++; /* At least one length byte */
+ options|=HA_OPTION_PACK_KEYS; /* Using packed keys */
+ min_key_length_skipp+=keyseg->length;
+ if (keyseg->length >= 255)
+ { /* prefix may be 3 bytes */
+ min_key_length_skipp+=2;
+ length+=2;
+ }
+ }
+ key_length+= keyseg->length;
+ if (keyseg->null_bit)
+ {
+ key_length++;
+ options|=HA_OPTION_PACK_KEYS;
+ keyseg->flag|=HA_NULL_PART;
+ keydef->flag|=HA_VAR_LENGTH_KEY | HA_NULL_PART_KEY;
+ }
+ }
+ } /* if HA_FULLTEXT */
+ key_segs+=keydef->keysegs;
+ if (keydef->keysegs > MI_MAX_KEY_SEG)
+ {
+ my_errno=HA_WRONG_CREATE_OPTION;
+ goto err;
+ }
+ if ((keydef->flag & (HA_NOSAME | HA_NULL_PART_KEY)) == HA_NOSAME)
+ 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)
+ {
+ my_errno=HA_WRONG_CREATE_OPTION;
+ goto err;
+ }
+ set_if_bigger(max_key_block_length,keydef->block_length);
+ keydef->keylength= (uint16) key_length;
+ keydef->minlength= (uint16) (length-min_key_length_skipp);
+ keydef->maxlength= (uint16) length;
+
+ if (length > max_key_length)
+ max_key_length= length;
+ tot_length+= (max_rows/(ulong) (((uint) keydef->block_length-5)/
+ (length*2)))*
+ (ulong) keydef->block_length;
+ }
+ for (i=max_key_block_length/MI_KEY_BLOCK_LENGTH ; i-- ; )
+ key_del[i]=HA_OFFSET_ERROR;
+
+ unique_key_parts=0;
+ offset=reclength-uniques*MI_UNIQUE_HASH_LENGTH;
+ for (i=0, uniquedef=uniquedefs ; i < uniques ; i++ , uniquedef++)
+ {
+ uniquedef->key=keys+i;
+ unique_key_parts+=uniquedef->keysegs;
+ share.state.key_root[keys+i]= HA_OFFSET_ERROR;
+ }
+ keys+=uniques; /* Each unique has 1 key */
+ 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+
+ key_segs*MI_STATE_KEYSEG_SIZE);
+ info_length=base_pos+(uint) (MI_BASE_INFO_SIZE+
+ keys * MI_KEYDEF_SIZE+
+ uniques * MI_UNIQUEDEF_SIZE +
+ (key_segs + unique_key_parts)*MI_KEYSEG_SIZE+
+ columns*MI_COLUMNDEF_SIZE);
+
+ bmove(share.state.header.file_version,(byte*) myisam_file_magic,4);
+ ci->old_options=options| (ci->old_options & HA_OPTION_TEMP_COMPRESS_RECORD ?
+ HA_OPTION_COMPRESS_RECORD |
+ HA_OPTION_TEMP_COMPRESS_RECORD: 0);
+ mi_int2store(share.state.header.options,ci->old_options);
+ mi_int2store(share.state.header.header_length,info_length);
+ mi_int2store(share.state.header.state_info_length,MI_STATE_INFO_SIZE);
+ mi_int2store(share.state.header.base_info_length,MI_BASE_INFO_SIZE);
+ 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.dellink = HA_OFFSET_ERROR;
+ share.state.process= (ulong) getpid();
+ share.state.unique= (ulong) 0;
+ share.state.version= (ulong) time((time_t*) 0);
+ share.state.sortkey= (ushort) ~0;
+ share.state.auto_increment=ci->auto_increment;
+ share.options=options;
+ 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,
+ 3);
+ share.base.keys= share.state.header.keys = keys;
+ share.state.header.uniques= uniques;
+ mi_int2store(share.state.header.key_parts,key_segs);
+ mi_int2store(share.state.header.unique_key_parts,unique_key_parts);
+
+ share.state.key_map = ((ulonglong) 1 << keys)-1;
+ share.base.keystart = share.state.state.key_file_length=
+ MY_ALIGN(info_length, myisam_block_size);
+ share.base.max_key_block_length=max_key_block_length;
+ share.base.max_key_length=ALIGN_SIZE(max_key_length+4);
+ 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.max_pack_length=pack_reclength;
+ share.base.min_pack_length=min_pack_length;
+ share.base.pack_bits=packed;
+ share.base.fields=fields;
+ share.base.pack_fields=packed;
+#ifdef USE_RAID
+ share.base.raid_type=ci->raid_type;
+ share.base.raid_chunks=ci->raid_chunks;
+ share.base.raid_chunksize=ci->raid_chunksize;
+#endif
+
+ /* max_data_file_length and max_key_file_length are recalculated on open */
+ if (options & HA_OPTION_TMP_TABLE)
+ share.base.max_data_file_length=(my_off_t) ci->data_file_length;
+
+ share.base.min_block_length=
+ (share.base.pack_reclength+3 < MI_EXTEND_BLOCK_LENGTH &&
+ ! share.base.blobs) ?
+ max(share.base.pack_reclength,MI_MIN_BLOCK_LENGTH) :
+ MI_EXTEND_BLOCK_LENGTH;
+ 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)
+ 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,
+ share.base.raid_type,
+ share.base.raid_chunks,
+ share.base.raid_chunksize,
+ MYF(MY_WME | MY_RAID))) < 0)
+ goto err;
+ }
+ else
+#endif
+ if ((dfile = my_create(buff,0,O_RDWR | O_TRUNC,MYF(MY_WME))) < 0)
+ goto err;
+
+ errpos=3;
+ }
+
+ if (mi_state_info_write(file, &share.state, 2) ||
+ mi_base_info_write(file, &share.base))
+ goto err;
+#ifndef DBUG_OFF
+ if ((uint) my_tell(file,MYF(0)) != base_pos+ MI_BASE_INFO_SIZE)
+ {
+ uint pos=(uint) my_tell(file,MYF(0));
+ DBUG_PRINT("warning",("base_length: %d != used_length: %d",
+ base_pos+ MI_BASE_INFO_SIZE, pos));
+ }
+#endif
+
+ /* 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 */
+
+ 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 */
+ if (mi_keyseg_write(file, &ft_keysegs[j]))
+ goto err;
+ }
+ /* Create extra keys for unique definitions */
+ offset=reclength-uniques*MI_UNIQUE_HASH_LENGTH;
+ bzero((char*) &tmp_keydef,sizeof(tmp_keydef));
+ bzero((char*) &tmp_keyseg,sizeof(tmp_keyseg));
+ for (i=0; i < uniques ; i++)
+ {
+ tmp_keydef.keysegs=1;
+ tmp_keydef.flag= HA_UNIQUE_CHECK;
+ tmp_keydef.block_length= MI_KEY_BLOCK_LENGTH;
+ tmp_keydef.keylength= MI_UNIQUE_HASH_LENGTH + pointer;
+ tmp_keydef.minlength=tmp_keydef.maxlength=tmp_keydef.keylength;
+ tmp_keyseg.type= MI_UNIQUE_HASH_TYPE;
+ tmp_keyseg.length= MI_UNIQUE_HASH_LENGTH;
+ tmp_keyseg.start= offset;
+ offset+= MI_UNIQUE_HASH_LENGTH;
+ if (mi_keydef_write(file,&tmp_keydef) ||
+ mi_keyseg_write(file,(&tmp_keyseg)))
+ goto err;
+ }
+
+ /* Save unique definition */
+ for (i=0 ; i < share.state.header.uniques ; i++)
+ {
+ if (mi_uniquedef_write(file, &uniquedefs[i]))
+ goto err;
+ for (j=0 ; j < uniquedefs[i].keysegs ; j++)
+ {
+ if (mi_keyseg_write(file, &uniquedefs[i].seg[j]))
+ goto err;
+ }
+ }
+ for (i=0 ; i < share.base.fields ; i++)
+ if (mi_recinfo_write(file, &recinfo[i]))
+ goto err;
+
+#ifndef DBUG_OFF
+ if ((uint) my_tell(file,MYF(0)) != info_length)
+ {
+ uint pos= (uint) my_tell(file,MYF(0));
+ DBUG_PRINT("warning",("info_length: %d != used_length: %d",
+ info_length, pos));
+ }
+#endif
+
+ /* Enlarge files */
+ if (my_chsize(file,(ulong) share.base.keystart,MYF(0)))
+ goto err;
+
+ if (! (flags & HA_DONT_TOUCH_DATA))
+ {
+#ifdef USE_RELOC
+ if (my_chsize(dfile,share.base.min_pack_length*ci->reloc_rows,MYF(0)))
+ goto err;
+#endif
+ errpos=2;
+ if (my_close(dfile,MYF(0)))
+ goto err;
+ }
+ errpos=0;
+ pthread_mutex_unlock(&THR_LOCK_myisam);
+ if (my_close(file,MYF(0)))
+ goto err;
+ DBUG_RETURN(0);
+
+err:
+ pthread_mutex_unlock(&THR_LOCK_myisam);
+ save_errno=my_errno;
+ switch (errpos) {
+ case 3:
+ 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));
+ }
+ /* 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));
+ }
+ }
+ DBUG_RETURN(my_errno=save_errno); /* return the fatal errno */
+}
+
+
+uint mi_get_pointer_length(ulonglong file_length, uint def)
+{
+ if (file_length) /* If not default */
+ {
+ if (file_length >= (longlong) 1 << 56)
+ def=8;
+ if (file_length >= (longlong) 1 << 48)
+ def=7;
+ if (file_length >= (longlong) 1 << 40)
+ def=6;
+ else if (file_length >= (longlong) 1 << 32)
+ def=5;
+ else if (file_length >= (1L << 24))
+ def=4;
+ else if (file_length >= (1L << 16))
+ def=3;
+ else
+ def=2;
+ }
+ return def;
+}
diff --git a/myisam/mi_dbug.c b/myisam/mi_dbug.c
new file mode 100644
index 00000000000..62d6e039059
--- /dev/null
+++ b/myisam/mi_dbug.c
@@ -0,0 +1,149 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* Support rutiner with are using with dbug */
+
+#include "myisamdef.h"
+
+ /* Print a key in user understandable format */
+
+void _mi_print_key(FILE *stream, register MI_KEYSEG *keyseg,
+ const uchar *key, uint length)
+{
+ int flag;
+ short int s_1;
+ long int l_1;
+ float f_1;
+ double d_1;
+ const uchar *end;
+ const uchar *key_end=key+length;
+
+ VOID(fputs("Key: \"",stream));
+ flag=0;
+ for (; keyseg->type && key < key_end ;keyseg++)
+ {
+ if (flag++)
+ VOID(putc('-',stream));
+ end= key+ keyseg->length;
+ if (keyseg->flag & HA_NULL_PART)
+ {
+ if (!*key)
+ {
+ fprintf(stream,"NULL");
+ continue;
+ }
+ key++;
+ }
+
+ switch (keyseg->type) {
+ case HA_KEYTYPE_BINARY:
+ if (!(keyseg->flag & HA_SPACE_PACK) && keyseg->length == 1)
+ { /* packed binary digit */
+ VOID(fprintf(stream,"%d",(uint) *key++));
+ break;
+ }
+ /* fall through */
+ case HA_KEYTYPE_TEXT:
+ case HA_KEYTYPE_NUM:
+ if (keyseg->flag & HA_SPACE_PACK)
+ {
+ VOID(fprintf(stream,"%.*s",(int) *key,key+1));
+ key+= (int) *key+1;
+ }
+ else
+ {
+ VOID(fprintf(stream,"%.*s",(int) keyseg->length,key));
+ key=end;
+ }
+ break;
+ case HA_KEYTYPE_INT8:
+ VOID(fprintf(stream,"%d",(int) *((signed char*) key)));
+ key=end;
+ break;
+ case HA_KEYTYPE_SHORT_INT:
+ s_1= mi_sint2korr(key);
+ VOID(fprintf(stream,"%d",(int) s_1));
+ key=end;
+ break;
+ case HA_KEYTYPE_USHORT_INT:
+ {
+ ushort u_1;
+ u_1= mi_uint2korr(key);
+ VOID(fprintf(stream,"%u",(uint) u_1));
+ key=end;
+ break;
+ }
+ case HA_KEYTYPE_LONG_INT:
+ l_1=mi_sint4korr(key);
+ VOID(fprintf(stream,"%ld",l_1));
+ key=end;
+ break;
+ case HA_KEYTYPE_ULONG_INT:
+ l_1=mi_sint4korr(key);
+ VOID(fprintf(stream,"%lu",(ulong) l_1));
+ key=end;
+ break;
+ case HA_KEYTYPE_INT24:
+ VOID(fprintf(stream,"%ld",(long) mi_sint3korr(key)));
+ key=end;
+ break;
+ case HA_KEYTYPE_UINT24:
+ VOID(fprintf(stream,"%lu",(ulong) mi_uint3korr(key)));
+ key=end;
+ break;
+ case HA_KEYTYPE_FLOAT:
+ mi_float4get(f_1,key);
+ VOID(fprintf(stream,"%g",(double) f_1));
+ key=end;
+ break;
+ case HA_KEYTYPE_DOUBLE:
+ mi_float8get(d_1,key);
+ VOID(fprintf(stream,"%g",d_1));
+ key=end;
+ break;
+#ifdef HAVE_LONG_LONG
+ case HA_KEYTYPE_LONGLONG:
+ {
+ char buff[21];
+ longlong2str(mi_sint8korr(key),buff,-10);
+ VOID(fprintf(stream,"%s",buff));
+ key=end;
+ break;
+ }
+ case HA_KEYTYPE_ULONGLONG:
+ {
+ char buff[21];
+ longlong2str(mi_sint8korr(key),buff,10);
+ VOID(fprintf(stream,"%s",buff));
+ key=end;
+ break;
+ }
+#endif
+ case HA_KEYTYPE_VARTEXT: /* VARCHAR and TEXT */
+ case HA_KEYTYPE_VARBINARY: /* VARBINARY and BLOB */
+ {
+ uint tmp_length;
+ get_key_length(tmp_length,key);
+ VOID(fprintf(stream,"%.*s",(int) tmp_length,key));
+ key+=tmp_length;
+ break;
+ }
+ default: break; /* This never happens */
+ }
+ }
+ VOID(fputs("\"\n",stream));
+ return;
+} /* print_key */
diff --git a/myisam/mi_delete.c b/myisam/mi_delete.c
new file mode 100644
index 00000000000..4c5f3c79e17
--- /dev/null
+++ b/myisam/mi_delete.c
@@ -0,0 +1,780 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 a row from a MyISAM table */
+
+#include "fulltext.h"
+#ifdef __WIN__
+#include <errno.h>
+#endif
+
+static int d_search(MI_INFO *info,MI_KEYDEF *keyinfo,uchar *key,
+ uint key_length, my_off_t page, uchar *anc_buff);
+static int del(MI_INFO *info,MI_KEYDEF *keyinfo,uchar *key,uchar *anc_buff,
+ my_off_t leaf_page,uchar *leaf_buff,uchar *keypos,
+ my_off_t next_block,uchar *ret_key);
+static int underflow(MI_INFO *info,MI_KEYDEF *keyinfo,uchar *anc_buff,
+ my_off_t leaf_page, uchar *leaf_buff,uchar *keypos);
+static uint remove_key(MI_KEYDEF *keyinfo,uint nod_flag,uchar *keypos,
+ uchar *lastkey,uchar *page_end,
+ my_off_t *next_block);
+
+
+int mi_delete(MI_INFO *info,const byte *record)
+{
+ uint i;
+ uchar *old_key;
+ int save_errno;
+ char lastpos[8];
+
+ MYISAM_SHARE *share=info->s;
+ DBUG_ENTER("mi_delete");
+
+ /* Test if record is in datafile */
+
+ if (!(info->update & HA_STATE_AKTIV))
+ {
+ DBUG_RETURN(my_errno=HA_ERR_KEY_NOT_FOUND); /* No database read */
+ }
+ if (share->options & HA_OPTION_READ_ONLY_DATA)
+ {
+ DBUG_RETURN(my_errno=EACCES);
+ }
+ if (_mi_readinfo(info,F_WRLCK,1))
+ DBUG_RETURN(my_errno);
+ if (info->s->calc_checksum)
+ info->checksum=(*info->s->calc_checksum)(info,record);
+ if ((*share->compare_record)(info,record))
+ goto err; /* Error on read-check */
+
+ if (_mi_mark_file_changed(info))
+ goto err;
+
+ /* Remove all keys from the .ISAM file */
+
+ old_key=info->lastkey2;
+ for (i=0 ; i < share->base.keys ; i++ )
+ {
+ if (((ulonglong) 1 << i) & info->s->state.key_map)
+ {
+ info->s->keyinfo[i].version++;
+ /* The following code block is for text searching by SerG */
+ if (info->s->keyinfo[i].flag & HA_FULLTEXT )
+ {
+ if (_mi_ft_del(info,i,(char*) old_key,record,info->lastpos))
+ goto err;
+ }
+ else
+ {
+ uint key_length=_mi_make_key(info,i,old_key,record,info->lastpos);
+ if (_mi_ck_delete(info,i,old_key,key_length))
+ goto err;
+ }
+ }
+ }
+
+ if ((*share->delete_record)(info))
+ goto err; /* Remove record from database */
+ info->s->state.checksum-=info->checksum;
+
+ info->update= HA_STATE_CHANGED+HA_STATE_DELETED+HA_STATE_ROW_CHANGED;
+ info->state->records--;
+
+ mi_sizestore(lastpos,info->lastpos);
+ myisam_log_command(MI_LOG_DELETE,info,(byte*) lastpos,sizeof(lastpos),0);
+ VOID(_mi_writeinfo(info,WRITEINFO_UPDATE_KEYFILE));
+ allow_break(); /* Allow SIGHUP & SIGINT */
+ DBUG_RETURN(0);
+
+err:
+ save_errno=my_errno;
+ mi_sizestore(lastpos,info->lastpos);
+ myisam_log_command(MI_LOG_DELETE,info,(byte*) lastpos, sizeof(lastpos),0);
+ if (save_errno != HA_ERR_RECORD_CHANGED)
+ mi_mark_crashed(info); /* mark table crashed */
+ VOID(_mi_writeinfo(info,WRITEINFO_UPDATE_KEYFILE));
+ info->update|=HA_STATE_WRITTEN; /* Buffer changed */
+ allow_break(); /* Allow SIGHUP & SIGINT */
+ my_errno=save_errno;
+ if (save_errno == HA_ERR_KEY_NOT_FOUND)
+ my_errno=HA_ERR_CRASHED;
+
+ DBUG_RETURN(my_errno);
+} /* mi_delete */
+
+
+ /* Remove a key from the btree index */
+
+int _mi_ck_delete(register MI_INFO *info, uint keynr, uchar *key,
+ uint key_length)
+{
+ int error;
+ uint nod_flag;
+ my_off_t old_root;
+ uchar *root_buff;
+ MI_KEYDEF *keyinfo;
+ DBUG_ENTER("_mi_ck_delete");
+
+ if ((old_root=info->s->state.key_root[keynr]) == HA_OFFSET_ERROR)
+ {
+ DBUG_RETURN(my_errno=HA_ERR_CRASHED);
+ }
+ keyinfo=info->s->keyinfo+keynr;
+ if (!(root_buff= (uchar*) my_alloca((uint) keyinfo->block_length+
+ MI_MAX_KEY_BUFF*2)))
+ {
+ DBUG_PRINT("error",("Couldn't allocate memory"));
+ DBUG_RETURN(my_errno=ENOMEM);
+ }
+ DBUG_PRINT("info",("root_page: %ld",old_root));
+ if (!_mi_fetch_keypage(info,keyinfo,old_root,root_buff,0))
+ {
+ error= -1;
+ goto err;
+ }
+ if ((error=d_search(info,keyinfo,key,key_length,old_root,root_buff)) >0)
+ {
+ if (error == 2)
+ {
+ DBUG_PRINT("test",("Enlarging of root when deleting"));
+ error=_mi_enlarge_root(info,keynr,key);
+ }
+ else /* error == 1 */
+ {
+ if (mi_getint(root_buff) <= (nod_flag=mi_test_if_nod(root_buff))+3)
+ {
+ error=0;
+ if (nod_flag)
+ info->s->state.key_root[keynr]=_mi_kpos(nod_flag,
+ root_buff+2+nod_flag);
+ else
+ info->s->state.key_root[keynr]= HA_OFFSET_ERROR;
+ if (_mi_dispose(info,keyinfo,old_root))
+ error= -1;
+ }
+ else
+ error=_mi_write_keypage(info,keyinfo,old_root,root_buff);
+ }
+ }
+err:
+ my_afree((gptr) root_buff);
+ DBUG_RETURN(error);
+} /* _mi_ck_delete */
+
+
+ /*
+ ** Remove key below key root
+ ** Return values:
+ ** 1 if there are less buffers; In this case anc_buff is not saved
+ ** 2 if there are more buffers
+ ** -1 on errors
+ */
+
+static int d_search(register MI_INFO *info, register MI_KEYDEF *keyinfo,
+ uchar *key, uint key_length, my_off_t page,
+ uchar *anc_buff)
+{
+ int flag,ret_value,save_flag;
+ uint length,nod_flag;
+ my_bool last_key;
+ uchar *leaf_buff,*keypos;
+ my_off_t leaf_page,next_block;
+ uchar lastkey[MI_MAX_KEY_BUFF];
+ 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,
+ &keypos, lastkey, &last_key);
+ if (flag == MI_FOUND_WRONG_KEY)
+ {
+ DBUG_PRINT("error",("Found wrong key"));
+ DBUG_RETURN(-1);
+ }
+ nod_flag=mi_test_if_nod(anc_buff);
+
+ leaf_buff=0;
+ LINT_INIT(leaf_page);
+ if (nod_flag)
+ {
+ leaf_page=_mi_kpos(nod_flag,keypos);
+ if (!(leaf_buff= (uchar*) my_alloca((uint) keyinfo->block_length+
+ MI_MAX_KEY_BUFF*2)))
+ {
+ DBUG_PRINT("error",("Couldn't allocate memory"));
+ my_errno=ENOMEM;
+ DBUG_RETURN(-1);
+ }
+ if (!_mi_fetch_keypage(info,keyinfo,leaf_page,leaf_buff,0))
+ goto err;
+ }
+
+ if (flag != 0)
+ {
+ if (!nod_flag)
+ {
+ DBUG_PRINT("error",("Didn't find key"));
+ my_errno=HA_ERR_CRASHED; /* This should newer happend */
+ goto err;
+ }
+ save_flag=0;
+ ret_value=d_search(info,keyinfo,key,key_length,leaf_page,leaf_buff);
+ }
+ else
+ { /* Found key */
+ uint tmp;
+ length=mi_getint(anc_buff);
+ tmp=remove_key(keyinfo,nod_flag,keypos,lastkey,anc_buff+length,
+ &next_block);
+ if (tmp == 0)
+ DBUG_RETURN(0);
+ length-= tmp;
+
+ mi_putint(anc_buff,length,nod_flag);
+ if (!nod_flag)
+ { /* On leaf page */
+ if (_mi_write_keypage(info,keyinfo,page,anc_buff))
+ DBUG_RETURN(-1);
+ if (length <= (uint) keyinfo->underflow_block_length)
+ DBUG_RETURN(1); /* Page will be update later */
+ DBUG_RETURN(0);
+ }
+ save_flag=1;
+ ret_value=del(info,keyinfo,key,anc_buff,leaf_page,leaf_buff,keypos,
+ next_block,lastkey);
+ }
+ if (ret_value >0)
+ {
+ save_flag=1;
+ if (ret_value == 1)
+ ret_value= underflow(info,keyinfo,anc_buff,leaf_page,leaf_buff,keypos);
+ else
+ { /* This happens only with packed keys */
+ DBUG_PRINT("test",("Enlarging of key when deleting"));
+ if (!_mi_get_last_key(info,keyinfo,anc_buff,lastkey,keypos,&length))
+ {
+ goto err;
+ }
+ ret_value=_mi_insert(info,keyinfo,key,anc_buff,keypos,lastkey,
+ (uchar*) 0,(uchar*) 0,(my_off_t) 0,(my_bool) 0);
+ }
+ }
+ if (ret_value == 0 && mi_getint(anc_buff) > keyinfo->block_length)
+ {
+ save_flag=1;
+ ret_value=_mi_split_page(info,keyinfo,key,anc_buff,lastkey,0) | 2;
+ }
+ if (save_flag && ret_value != 1)
+ ret_value|=_mi_write_keypage(info,keyinfo,page,anc_buff);
+ else
+ {
+ DBUG_DUMP("page",(byte*) anc_buff,mi_getint(anc_buff));
+ }
+ my_afree((byte*) leaf_buff);
+ DBUG_RETURN(ret_value);
+err:
+ my_afree((byte*) leaf_buff);
+ DBUG_PRINT("exit",("Error: %d",my_errno));
+ DBUG_RETURN (-1);
+} /* d_search */
+
+
+ /* Remove a key that has a page-reference */
+
+static int del(register MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *key,
+ uchar *anc_buff, my_off_t leaf_page, uchar *leaf_buff,
+ uchar *keypos, /* Pos to where deleted key was */
+ my_off_t next_block,
+ uchar *ret_key) /* key before keypos in anc_buff */
+{
+ int ret_value,length;
+ uint a_length,nod_flag,tmp;
+ my_off_t next_page;
+ uchar keybuff[MI_MAX_KEY_BUFF],*endpos,*next_buff,*key_start, *prev_key;
+ MYISAM_SHARE *share=info->s;
+ MI_KEY_PARAM s_temp;
+ DBUG_ENTER("del");
+ DBUG_PRINT("enter",("leaf_page: %ld keypos: %lx",leaf_page,keypos));
+ DBUG_DUMP("leaf_buff",(byte*) leaf_buff,mi_getint(leaf_buff));
+
+ endpos=leaf_buff+mi_getint(leaf_buff);
+ if (!(key_start=_mi_get_last_key(info,keyinfo,leaf_buff,keybuff,endpos,
+ &tmp)))
+ DBUG_RETURN(-1);
+
+ if ((nod_flag=mi_test_if_nod(leaf_buff)))
+ {
+ next_page= _mi_kpos(nod_flag,endpos);
+ if (!(next_buff= (uchar*) my_alloca((uint) keyinfo->block_length+
+ MI_MAX_KEY_BUFF*2)))
+ DBUG_RETURN(-1);
+ if (!_mi_fetch_keypage(info,keyinfo,next_page,next_buff,0))
+ ret_value= -1;
+ else
+ {
+ DBUG_DUMP("next_page",(byte*) next_buff,mi_getint(next_buff));
+ if ((ret_value=del(info,keyinfo,key,anc_buff,next_page,next_buff,
+ keypos,next_block,ret_key)) >0)
+ {
+ endpos=leaf_buff+mi_getint(leaf_buff);
+ if (ret_value == 1)
+ {
+ ret_value=underflow(info,keyinfo,leaf_buff,next_page,
+ next_buff,endpos);
+ if (ret_value == 0 && mi_getint(leaf_buff) > keyinfo->block_length)
+ {
+ ret_value=_mi_split_page(info,keyinfo,key,leaf_buff,ret_key,0) | 2;
+ }
+ }
+ else
+ {
+ DBUG_PRINT("test",("Inserting of key when deleting"));
+ if (_mi_get_last_key(info,keyinfo,leaf_buff,keybuff,endpos,
+ &tmp))
+ goto err;
+ ret_value=_mi_insert(info,keyinfo,key,leaf_buff,endpos,keybuff,
+ (uchar*) 0,(uchar*) 0,(my_off_t) 0,0);
+ }
+ }
+ if (_mi_write_keypage(info,keyinfo,leaf_page,leaf_buff))
+ goto err;
+ }
+ my_afree((byte*) next_buff);
+ DBUG_RETURN(ret_value);
+ }
+
+ /* Remove last key from leaf page */
+
+ mi_putint(leaf_buff,key_start-leaf_buff,nod_flag);
+ if (_mi_write_keypage(info,keyinfo,leaf_page,leaf_buff))
+ goto err;
+
+ /* Place last key in ancestor page on deleted key position */
+
+ a_length=mi_getint(anc_buff);
+ endpos=anc_buff+a_length;
+ if (keypos != anc_buff+2+share->base.key_reflength &&
+ !_mi_get_last_key(info,keyinfo,anc_buff,ret_key,keypos,&tmp))
+ goto err;
+ prev_key=(keypos == anc_buff+2+share->base.key_reflength ?
+ 0 : ret_key);
+ length=(*keyinfo->pack_key)(keyinfo,share->base.key_reflength,
+ keypos == endpos ? (uchar*) 0 : keypos,
+ prev_key, prev_key,
+ keybuff,&s_temp);
+ if (length > 0)
+ bmove_upp((byte*) endpos+length,(byte*) endpos,(uint) (endpos-keypos));
+ else
+ bmove(keypos,keypos-length, (int) (endpos-keypos)+length);
+ (*keyinfo->store_key)(keyinfo,keypos,&s_temp);
+ /* Save pointer to next leaf */
+ if (!(*keyinfo->get_key)(keyinfo,share->base.key_reflength,&keypos,ret_key))
+ goto err;
+ _mi_kpointer(info,keypos - share->base.key_reflength,next_block);
+ mi_putint(anc_buff,a_length+length,share->base.key_reflength);
+
+ DBUG_RETURN( mi_getint(leaf_buff) <= (uint) keyinfo->underflow_block_length);
+err:
+ DBUG_RETURN(-1);
+} /* del */
+
+
+ /* Balances adjacent pages if underflow occours */
+
+static int underflow(register MI_INFO *info, register MI_KEYDEF *keyinfo,
+ uchar *anc_buff,
+ my_off_t leaf_page,/* Ancestor page and underflow page */
+ uchar *leaf_buff,
+ uchar *keypos) /* Position to pos after key */
+{
+ int t_length;
+ uint length,anc_length,buff_length,leaf_length,p_length,s_length,nod_flag,
+ key_reflength,key_length;
+ my_off_t next_page;
+ uchar anc_key[MI_MAX_KEY_BUFF],leaf_key[MI_MAX_KEY_BUFF],
+ *buff,*endpos,*next_keypos,*anc_pos,*half_pos,*temp_pos,*prev_key,
+ *after_key;
+ MI_KEY_PARAM s_temp;
+ MYISAM_SHARE *share=info->s;
+ DBUG_ENTER("underflow");
+ DBUG_PRINT("enter",("leaf_page: %ld keypos: %lx",(long) leaf_page,keypos));
+ DBUG_DUMP("anc_buff",(byte*) anc_buff,mi_getint(anc_buff));
+ DBUG_DUMP("leaf_buff",(byte*) leaf_buff,mi_getint(leaf_buff));
+
+ buff=info->buff;
+ info->buff_used=1;
+ next_keypos=keypos;
+ nod_flag=mi_test_if_nod(leaf_buff);
+ p_length=nod_flag+2;
+ anc_length=mi_getint(anc_buff);
+ leaf_length=mi_getint(leaf_buff);
+ key_reflength=share->base.key_reflength;
+ if (info->s->keyinfo+info->lastinx == keyinfo)
+ info->page_changed=1;
+
+ if ((keypos < anc_buff+anc_length && (share->rnd++ & 1)) ||
+ keypos == anc_buff+2+key_reflength)
+ { /* Use page right of anc-page */
+ DBUG_PRINT("test",("use right page"));
+
+ if (keyinfo->flag & HA_BINARY_PACK_KEY)
+ {
+ if (!(next_keypos=_mi_get_key(info, keyinfo,
+ anc_buff, buff, keypos, &length)))
+ goto err;
+ }
+ else
+ {
+ /* Got to end of found key */
+ buff[0]=buff[1]=0; /* Avoid length error check if packed key */
+ if (!(*keyinfo->get_key)(keyinfo,key_reflength,&next_keypos,
+ buff))
+ goto err;
+ }
+ next_page= _mi_kpos(key_reflength,next_keypos);
+ if (!_mi_fetch_keypage(info,keyinfo,next_page,buff,0))
+ goto err;
+ buff_length=mi_getint(buff);
+ DBUG_DUMP("next",(byte*) buff,buff_length);
+
+ /* find keys to make a big key-page */
+ bmove((byte*) next_keypos-key_reflength,(byte*) buff+2,
+ key_reflength);
+ if (!_mi_get_last_key(info,keyinfo,anc_buff,anc_key,next_keypos,&length)
+ || !_mi_get_last_key(info,keyinfo,leaf_buff,leaf_key,
+ leaf_buff+leaf_length,&length))
+ goto err;
+
+ /* merge pages and put parting key from anc_buff between */
+ prev_key=(leaf_length == p_length ? (uchar*) 0 : leaf_key);
+ t_length=(*keyinfo->pack_key)(keyinfo,nod_flag,buff+p_length,
+ prev_key, prev_key,
+ anc_key, &s_temp);
+ length=buff_length-p_length;
+ endpos=buff+length+leaf_length+t_length;
+ /* buff will always be larger than before !*/
+ bmove_upp((byte*) endpos, (byte*) buff+buff_length,length);
+ memcpy((byte*) buff, (byte*) leaf_buff,(size_t) leaf_length);
+ (*keyinfo->store_key)(keyinfo,buff+leaf_length,&s_temp);
+ buff_length=(uint) (endpos-buff);
+ mi_putint(buff,buff_length,nod_flag);
+
+ /* remove key from anc_buff */
+
+ s_length=remove_key(keyinfo,key_reflength,keypos,anc_key,
+ anc_buff+anc_length,(my_off_t *) 0);
+ if (!s_length)
+ goto err;
+ anc_length-=s_length;
+ mi_putint(anc_buff,anc_length,key_reflength);
+
+ if (buff_length <= keyinfo->block_length)
+ { /* Keys in one page */
+ memcpy((byte*) leaf_buff,(byte*) buff,(size_t) buff_length);
+ if (_mi_dispose(info,keyinfo,next_page))
+ goto err;
+ }
+ else
+ { /* Page is full */
+ endpos=anc_buff+anc_length;
+ DBUG_PRINT("test",("anc_buff: %lx endpos: %lx",anc_buff,endpos));
+ if (keypos != anc_buff+2+key_reflength &&
+ !_mi_get_last_key(info,keyinfo,anc_buff,anc_key,keypos,&length))
+ goto err;
+ if (!(half_pos=_mi_find_half_pos(nod_flag, keyinfo, buff, leaf_key,
+ &key_length, &after_key)))
+ goto err;
+ length=(uint) (half_pos-buff);
+ memcpy((byte*) leaf_buff,(byte*) buff,(size_t) length);
+ mi_putint(leaf_buff,length,nod_flag);
+
+ /* Correct new keypointer to leaf_page */
+ half_pos=after_key;
+ _mi_kpointer(info,leaf_key+key_length,next_page);
+ /* Save key in anc_buff */
+ prev_key=(keypos == anc_buff+2+key_reflength ? (uchar*) 0 : anc_key),
+ t_length=(*keyinfo->pack_key)(keyinfo,key_reflength,
+ (keypos == endpos ? (uchar*) 0 :
+ keypos),
+ prev_key, prev_key,
+ leaf_key, &s_temp);
+ if (t_length >= 0)
+ bmove_upp((byte*) endpos+t_length,(byte*) endpos,
+ (uint) (endpos-keypos));
+ else
+ bmove(keypos,keypos-t_length,(uint) (endpos-keypos)+t_length);
+ (*keyinfo->store_key)(keyinfo,keypos,&s_temp);
+ mi_putint(anc_buff,(anc_length+=t_length),key_reflength);
+
+ /* Store key first in new page */
+ if (nod_flag)
+ bmove((byte*) buff+2,(byte*) half_pos-nod_flag,(size_t) nod_flag);
+ if (!(*keyinfo->get_key)(keyinfo,nod_flag,&half_pos,leaf_key))
+ goto err;
+ t_length=(int) (*keyinfo->pack_key)(keyinfo, nod_flag, (uchar*) 0,
+ (uchar*) 0, (uchar *) 0,
+ leaf_key, &s_temp);
+ /* t_length will always be > 0 for a new page !*/
+ length=(buff+mi_getint(buff))-half_pos;
+ bmove((byte*) buff+p_length+t_length,(byte*) half_pos,(size_t) length);
+ (*keyinfo->store_key)(keyinfo,buff+p_length,&s_temp);
+ mi_putint(buff,length+t_length+p_length,nod_flag);
+
+ if (_mi_write_keypage(info,keyinfo,next_page,buff))
+ goto err;
+ }
+ if (_mi_write_keypage(info,keyinfo,leaf_page,leaf_buff))
+ goto err;
+ DBUG_RETURN(anc_length <= (uint) keyinfo->underflow_block_length);
+ }
+
+ DBUG_PRINT("test",("use left page"));
+
+ keypos=_mi_get_last_key(info,keyinfo,anc_buff,anc_key,keypos,&length);
+ if (!keypos)
+ goto err;
+ next_page= _mi_kpos(key_reflength,keypos);
+ if (!_mi_fetch_keypage(info,keyinfo,next_page,buff,0))
+ goto err;
+ buff_length=mi_getint(buff);
+ endpos=buff+buff_length;
+ DBUG_DUMP("prev",(byte*) buff,buff_length);
+
+ /* find keys to make a big key-page */
+ bmove((byte*) next_keypos - key_reflength,(byte*) leaf_buff+2,
+ key_reflength);
+ next_keypos=keypos;
+ if (!(*keyinfo->get_key)(keyinfo,key_reflength,&next_keypos,
+ anc_key))
+ goto err;
+ if (!_mi_get_last_key(info,keyinfo,buff,leaf_key,endpos,&length))
+ goto err;
+
+ /* merge pages and put parting key from anc_buff between */
+ prev_key=(leaf_length == p_length ? (uchar*) 0 : leaf_key);
+ t_length=(*keyinfo->pack_key)(keyinfo,nod_flag,
+ (leaf_length == p_length ?
+ (uchar*) 0 : leaf_buff+p_length),
+ prev_key, prev_key,
+ anc_key, &s_temp);
+ if (t_length >= 0)
+ bmove((byte*) endpos+t_length,(byte*) leaf_buff+p_length,
+ (size_t) (leaf_length-p_length));
+ else /* We gained space */
+ bmove((byte*) endpos,(byte*) leaf_buff+((int) p_length-t_length),
+ (size_t) (leaf_length-p_length+t_length));
+
+ (*keyinfo->store_key)(keyinfo,endpos,&s_temp);
+ buff_length=buff_length+leaf_length-p_length+t_length;
+ mi_putint(buff,buff_length,nod_flag);
+
+ /* remove key from anc_buff */
+ s_length=remove_key(keyinfo,key_reflength,keypos,anc_key,
+ anc_buff+anc_length,(my_off_t *) 0);
+ if (!s_length)
+ goto err;
+ anc_length-=s_length;
+ mi_putint(anc_buff,anc_length,key_reflength);
+
+ if (buff_length <= keyinfo->block_length)
+ { /* Keys in one page */
+ if (_mi_dispose(info,keyinfo,leaf_page))
+ goto err;
+ }
+ else
+ { /* Page is full */
+ if (keypos == anc_buff+2+key_reflength)
+ anc_pos=0; /* First key */
+ else if (!_mi_get_last_key(info,keyinfo,anc_buff,anc_pos=anc_key,keypos,
+ &length))
+ goto err;
+ endpos=_mi_find_half_pos(nod_flag,keyinfo,buff,leaf_key,
+ &key_length, &half_pos);
+ if (!endpos)
+ goto err;
+ _mi_kpointer(info,leaf_key+key_length,leaf_page);
+ /* Save key in anc_buff */
+ DBUG_DUMP("anc_buff",(byte*) anc_buff,anc_length);
+ DBUG_DUMP("key_to_anc",(byte*) leaf_key,key_length);
+
+ temp_pos=anc_buff+anc_length;
+ t_length=(*keyinfo->pack_key)(keyinfo,key_reflength,
+ keypos == temp_pos ? (uchar*) 0
+ : keypos,
+ anc_pos, anc_pos,
+ leaf_key,&s_temp);
+ if (t_length > 0)
+ bmove_upp((byte*) temp_pos+t_length,(byte*) temp_pos,
+ (uint) (temp_pos-keypos));
+ else
+ bmove(keypos,keypos-t_length,(uint) (temp_pos-keypos)+t_length);
+ (*keyinfo->store_key)(keyinfo,keypos,&s_temp);
+ mi_putint(anc_buff,(anc_length+=t_length),key_reflength);
+
+ /* Store first key on new page */
+ if (nod_flag)
+ bmove((byte*) leaf_buff+2,(byte*) half_pos-nod_flag,(size_t) nod_flag);
+ if (!(length=(*keyinfo->get_key)(keyinfo,nod_flag,&half_pos,leaf_key)))
+ goto err;
+ DBUG_DUMP("key_to_leaf",(byte*) leaf_key,length);
+ t_length=(*keyinfo->pack_key)(keyinfo,nod_flag, (uchar*) 0,
+ (uchar*) 0, (uchar*) 0, leaf_key, &s_temp);
+ length=(uint) ((buff+buff_length)-half_pos);
+ DBUG_PRINT("info",("t_length: %d length: %d",t_length,(int) length));
+ bmove((byte*) leaf_buff+p_length+t_length,(byte*) half_pos,
+ (size_t) length);
+ (*keyinfo->store_key)(keyinfo,leaf_buff+p_length,&s_temp);
+ mi_putint(leaf_buff,length+t_length+p_length,nod_flag);
+ if (_mi_write_keypage(info,keyinfo,leaf_page,leaf_buff))
+ goto err;
+ mi_putint(buff,endpos-buff,nod_flag);
+ }
+ if (_mi_write_keypage(info,keyinfo,next_page,buff))
+ goto err;
+ DBUG_RETURN(anc_length <= (uint) keyinfo->block_length/2);
+err:
+ DBUG_RETURN(-1);
+} /* underflow */
+
+
+ /*
+ remove a key from packed buffert
+ The current code doesn't handle the case that the next key may be
+ packed better against the previous key if there is a case difference
+ returns how many chars was removed or 0 on error
+ */
+
+static uint remove_key(MI_KEYDEF *keyinfo, uint nod_flag,
+ uchar *keypos, /* Where key starts */
+ uchar *lastkey, /* key to be removed */
+ uchar *page_end, /* End of page */
+ my_off_t *next_block) /* ptr to next block */
+{
+ int s_length;
+ uchar *start;
+ DBUG_ENTER("remove_key");
+ DBUG_PRINT("enter",("keypos: %lx page_end: %lx",keypos,page_end));
+
+ start=keypos;
+ if (!(keyinfo->flag &
+ (HA_PACK_KEY | HA_SPACE_PACK_USED | HA_VAR_LENGTH_KEY |
+ HA_BINARY_PACK_KEY)))
+ {
+ s_length=(int) (keyinfo->keylength+nod_flag);
+ if (next_block && nod_flag)
+ *next_block= _mi_kpos(nod_flag,keypos+s_length);
+ }
+ else
+ { /* Let keypos point at next key */
+ /* Calculate length of key */
+ if (!(*keyinfo->get_key)(keyinfo,nod_flag,&keypos,lastkey))
+ DBUG_RETURN(0); /* Error */
+ if (next_block && nod_flag)
+ *next_block= _mi_kpos(nod_flag,keypos);
+ s_length=(keypos-start);
+ if (keypos != page_end)
+ {
+ if (keyinfo->flag & HA_BINARY_PACK_KEY)
+ {
+ uchar *old_key=start;
+ uint next_length,prev_length,prev_pack_length;
+ get_key_length(next_length,keypos);
+ get_key_pack_length(prev_length,prev_pack_length,old_key);
+ if (next_length > prev_length)
+ {
+ /* We have to copy data from the current key to the next key */
+ bmove_upp((char*) keypos,(char*) (lastkey+next_length),
+ (next_length-prev_length));
+ keypos-=(next_length-prev_length)+prev_pack_length;
+ store_key_length(keypos,prev_length);
+ s_length=(keypos-start);
+ }
+ }
+ else
+ {
+ /* A variable length first key part */
+ if (*keypos & 128) /* Next key is packed */
+ {
+ uint next_length,prev_length,prev_pack_length,lastkey_length,
+ rest_length;
+ if (keyinfo->seg[0].length >= 127)
+ {
+ if (!(prev_length=mi_uint2korr(start) & 32767))
+ goto end;
+ next_length=mi_uint2korr(keypos) & 32767;
+ keypos+=2;
+ prev_pack_length=2;
+ }
+ else
+ {
+ if (!(prev_length= *start & 127))
+ goto end; /* Same key as previous*/
+ next_length= *keypos & 127;
+ keypos++;
+ prev_pack_length=1;
+ }
+ if (!(*start & 128))
+ prev_length=0; /* prev key not packed */
+ if (keyinfo->seg[0].flag & HA_NULL_PART)
+ lastkey++; /* Skipp null marker */
+ get_key_length(lastkey_length,lastkey);
+ if (!next_length) /* Same key after */
+ {
+ next_length=lastkey_length;
+ rest_length=0;
+ }
+ else
+ get_key_length(rest_length,keypos);
+
+ if (next_length > prev_length)
+ { /* Key after is based on deleted key */
+ uint pack_length,tmp;
+ bmove_upp((char*) keypos,(char*) (lastkey+next_length),
+ tmp=(next_length-prev_length));
+ rest_length+=tmp;
+ pack_length= prev_length ? get_pack_length(rest_length): 0;
+ keypos-=tmp+pack_length+prev_pack_length;
+ s_length=(keypos-start);
+ if (prev_length) /* Pack against prev key */
+ {
+ *keypos++= start[0];
+ if (prev_pack_length == 2)
+ *keypos++= start[1];
+ store_key_length(keypos,rest_length);
+ }
+ else
+ {
+ /* Next key is not packed anymore */
+ if (keyinfo->seg[0].flag & HA_NULL_PART)
+ {
+ rest_length++; /* Mark not null */
+ }
+ if (prev_pack_length == 2)
+ {
+ mi_int2store(keypos,rest_length);
+ }
+ else
+ *keypos= rest_length;
+ }
+ }
+ }
+ }
+ }
+ }
+ end:
+ bmove((byte*) start,(byte*) start+s_length,
+ (uint) (page_end-start-s_length));
+ DBUG_RETURN((uint) s_length);
+} /* remove_key */
diff --git a/myisam/mi_delete_all.c b/myisam/mi_delete_all.c
new file mode 100644
index 00000000000..c3ed9455e12
--- /dev/null
+++ b/myisam/mi_delete_all.c
@@ -0,0 +1,65 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 */
+
+#include "myisamdef.h"
+
+int mi_delete_all_rows(MI_INFO *info)
+{
+ uint i;
+ MYISAM_SHARE *share=info->s;
+ MI_STATE_INFO *state=&share->state;
+ DBUG_ENTER("mi_delete_all_rows");
+
+ if (share->options & HA_OPTION_READ_ONLY_DATA)
+ {
+ DBUG_RETURN(my_errno=EACCES);
+ }
+ if (_mi_readinfo(info,F_WRLCK,1))
+ DBUG_RETURN(my_errno);
+ if (_mi_mark_file_changed(info))
+ goto err;
+
+ info->state->records=info->state->del=state->split=0;
+ state->dellink = HA_OFFSET_ERROR;
+ state->sortkey= (ushort) ~0;
+ info->state->key_file_length=share->base.keystart;
+ info->state->data_file_length=0;
+ info->state->empty=info->state->key_empty=0;
+ state->checksum=0;
+
+ for (i=share->base.max_key_block_length/MI_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));
+ allow_break(); /* Allow SIGHUP & SIGINT */
+ DBUG_RETURN(0);
+
+err:
+ {
+ int save_errno=my_errno;
+ VOID(_mi_writeinfo(info,WRITEINFO_UPDATE_KEYFILE));
+ info->update|=HA_STATE_WRITTEN; /* Buffer changed */
+ allow_break(); /* Allow SIGHUP & SIGINT */
+ DBUG_RETURN(my_errno=save_errno);
+ }
+} /* mi_delete */
+
diff --git a/myisam/mi_delete_table.c b/myisam/mi_delete_table.c
new file mode 100644
index 00000000000..916f5a8fc02
--- /dev/null
+++ b/myisam/mi_delete_table.c
@@ -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 */
+
+/*
+ deletes a table
+*/
+
+#include "fulltext.h"
+#ifdef __WIN__
+#include <errno.h>
+#endif
+
+int mi_delete_table(const char *name)
+{
+ char from[FN_REFLEN];
+#ifdef USE_RAID
+ uint raid_type=0,raid_chunks=0;
+#endif
+ DBUG_ENTER("mi_delete_table");
+#ifdef USE_RAID
+ {
+ MI_INFO *info;
+ if (!(info=mi_open(name, O_RDONLY, 0)))
+ DBUG_RETURN(my_errno);
+ raid_type = info->s->base.raid_type;
+ raid_chunks = info->s->base.raid_chunks;
+ mi_close(info);
+ }
+#endif
+
+ fn_format(from,name,"",MI_NAME_IEXT,4);
+ if (my_delete(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);
+}
diff --git a/myisam/mi_dynrec.c b/myisam/mi_dynrec.c
new file mode 100644
index 00000000000..789831db810
--- /dev/null
+++ b/myisam/mi_dynrec.c
@@ -0,0 +1,1537 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+ /* Functions to handle space-packed-records and blobs */
+
+#include "myisamdef.h"
+
+/* Enough for comparing if number is zero */
+static char zero_string[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
+
+static int write_dynamic_record(MI_INFO *info,const byte *record,
+ ulong reclength);
+static int _mi_find_writepos(MI_INFO *info,ulong reclength,my_off_t *filepos,
+ ulong *length);
+static int update_dynamic_record(MI_INFO *info,my_off_t filepos,byte *record,
+ ulong reclength);
+static int delete_dynamic_record(MI_INFO *info,my_off_t filepos,
+ uint second_read);
+static int _mi_cmp_buffer(File file, const byte *buff, my_off_t filepos,
+ uint length);
+
+#ifdef THREAD
+/* Play it safe; We have a small stack when using threads */
+#undef my_alloca
+#undef my_afree
+#define my_alloca(A) my_malloc((A),MYF(0))
+#define my_afree(A) my_free((A),MYF(0))
+#endif
+
+ /* Interface function from MI_INFO */
+
+int _mi_write_dynamic_record(MI_INFO *info, const byte *record)
+{
+ ulong reclength=_mi_rec_pack(info,info->rec_buff,record);
+ return (write_dynamic_record(info,info->rec_buff,reclength));
+}
+
+int _mi_update_dynamic_record(MI_INFO *info, my_off_t pos, const byte *record)
+{
+ uint length=_mi_rec_pack(info,info->rec_buff,record);
+ return (update_dynamic_record(info,pos,info->rec_buff,length));
+}
+
+int _mi_write_blob_record(MI_INFO *info, const byte *record)
+{
+ byte *rec_buff;
+ int error;
+ ulong reclength,extra;
+
+ extra=ALIGN_SIZE(MI_MAX_DYN_BLOCK_HEADER)+MI_SPLIT_LENGTH+
+ MI_DYN_DELETE_BLOCK_HEADER+1;
+ reclength=info->s->base.pack_reclength+
+ _my_calc_total_blob_length(info,record)+ extra;
+ if (reclength > MI_DYN_MAX_ROW_LENGTH)
+ {
+ my_errno=HA_ERR_TO_BIG_ROW;
+ return -1;
+ }
+ if (!(rec_buff=(byte*) my_alloca(reclength)))
+ {
+ my_errno=ENOMEM;
+ return(-1);
+ }
+ reclength=_mi_rec_pack(info,rec_buff+ALIGN_SIZE(MI_MAX_DYN_BLOCK_HEADER),
+ record);
+ error=write_dynamic_record(info,rec_buff+ALIGN_SIZE(MI_MAX_DYN_BLOCK_HEADER),
+ reclength);
+ my_afree(rec_buff);
+ return(error);
+}
+
+
+int _mi_update_blob_record(MI_INFO *info, my_off_t pos, const byte *record)
+{
+ byte *rec_buff;
+ int error;
+ ulong reclength,extra;
+
+ extra=ALIGN_SIZE(MI_MAX_DYN_BLOCK_HEADER)+MI_SPLIT_LENGTH+
+ MI_DYN_DELETE_BLOCK_HEADER;
+ reclength=info->s->base.pack_reclength+
+ _my_calc_total_blob_length(info,record)+ extra;
+ if (reclength > MI_DYN_MAX_ROW_LENGTH)
+ {
+ my_errno=HA_ERR_TO_BIG_ROW;
+ return -1;
+ }
+ if (!(rec_buff=(byte*) my_alloca(reclength)))
+ {
+ my_errno=ENOMEM;
+ return(-1);
+ }
+ reclength=_mi_rec_pack(info,rec_buff+ALIGN_SIZE(MI_MAX_DYN_BLOCK_HEADER),
+ record);
+ error=update_dynamic_record(info,pos,
+ rec_buff+ALIGN_SIZE(MI_MAX_DYN_BLOCK_HEADER),
+ reclength);
+ my_afree(rec_buff);
+ return(error);
+}
+
+
+int _mi_delete_dynamic_record(MI_INFO *info)
+{
+ return delete_dynamic_record(info,info->lastpos,0);
+}
+
+
+ /* Write record to data-file */
+
+static int write_dynamic_record(MI_INFO *info, const byte *record,
+ ulong reclength)
+{
+ int flag;
+ ulong length;
+ my_off_t filepos;
+ DBUG_ENTER("write_dynamic_record");
+
+ flag=0;
+ while (reclength)
+ {
+ 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;
+ }
+
+ DBUG_RETURN(0);
+ err:
+ DBUG_RETURN(1);
+}
+
+
+ /* Get a block for data ; The given data-area must be used !! */
+
+static int _mi_find_writepos(MI_INFO *info,
+ ulong reclength, /* record length */
+ my_off_t *filepos, /* Return file pos */
+ ulong *length) /* length of block at filepos */
+{
+ MI_BLOCK_INFO block_info;
+ DBUG_ENTER("_mi_find_writepos");
+
+ if (info->s->state.dellink != HA_OFFSET_ERROR)
+ {
+ /* Deleted blocks exists; Get last used block */
+
+ *filepos=info->s->state.dellink;
+ block_info.second_read=0;
+ info->rec_cache.seek_not_done=1;
+ if (!(_mi_get_block_info(&block_info,info->dfile,info->s->state.dellink) &
+ BLOCK_DELETED))
+ {
+ DBUG_PRINT("error",("Delete link crashed"));
+ my_errno=HA_ERR_WRONG_IN_RECORD;
+ DBUG_RETURN(-1);
+ }
+ info->s->state.dellink=block_info.next_filepos;
+ info->state->del--;
+ info->state->empty-= block_info.block_len;
+ *length= block_info.block_len;
+ }
+ else
+ {
+ /* No deleted blocks; Allocate a new block */
+ *filepos=info->state->data_file_length;
+ if ((*length=reclength+3 + test(reclength > 65520)) <
+ info->s->base.min_block_length)
+ *length=info->s->base.min_block_length;
+ else
+ *length= ((*length+MI_DYN_ALIGN_SIZE-1) &
+ (~ (ulong) (MI_DYN_ALIGN_SIZE-1)));
+ if (info->state->data_file_length >
+ (info->s->base.max_data_file_length- *length))
+ {
+ my_errno=HA_ERR_RECORD_FILE_FULL;
+ DBUG_RETURN(-1);
+ }
+ info->state->data_file_length+= *length;
+ info->s->state.split++;
+ info->update|=HA_STATE_WRITE_AT_END;
+ }
+ DBUG_RETURN(0);
+} /* _mi_find_writepos */
+
+
+
+/* Remove a deleted block from the deleted list */
+
+static bool unlink_deleted_block(MI_INFO *info, MI_BLOCK_INFO *block_info)
+{
+ DBUG_ENTER("unlink_deleted_block");
+ if (block_info->filepos == info->s->state.dellink)
+ {
+ /* First deleted block; We can just use this ! */
+ info->s->state.dellink=block_info->next_filepos;
+ }
+ else
+ {
+ MI_BLOCK_INFO tmp;
+ tmp.second_read=0;
+ if (!(_mi_get_block_info(&tmp,info->dfile,block_info->prev_filepos)
+ & BLOCK_DELETED))
+ DBUG_RETURN(1); /* Something is wrong */
+ mi_sizestore(tmp.header+4,block_info->next_filepos);
+ if (my_pwrite(info->dfile,(char*) tmp.header+4,8,
+ block_info->prev_filepos+4, MYF(MY_NABP)))
+ DBUG_RETURN(1);
+ if (block_info->next_filepos != HA_OFFSET_ERROR)
+ {
+ if (!(_mi_get_block_info(&tmp,info->dfile,block_info->next_filepos)
+ & BLOCK_DELETED))
+ DBUG_RETURN(1); /* Something is wrong */
+ mi_sizestore(tmp.header+12,block_info->prev_filepos);
+ if (my_pwrite(info->dfile,(char*) tmp.header+12,8,
+ block_info->next_filepos+12,
+ MYF(MY_NABP)))
+ DBUG_RETURN(1);
+ }
+ }
+ info->state->del--;
+ info->state->empty-= block_info->block_len;
+ info->s->state.split--;
+
+ /* Removing block that we are using through mi_rrnd */
+ if (info->nextpos == block_info->filepos)
+ info->nextpos+=block_info->block_len;
+ DBUG_RETURN(0);
+}
+
+ /* Delete datarecord from database */
+ /* info->rec_cache.seek_not_done is updated in cmp_record */
+
+static int delete_dynamic_record(MI_INFO *info, my_off_t filepos,
+ uint second_read)
+{
+ uint length,b_type;
+ MI_BLOCK_INFO block_info,del_block;
+ int error=0;
+ my_bool remove_next_block;
+ DBUG_ENTER("delete_dynamic_record");
+
+ /* First add a link from the last block to the new one */
+ if (info->s->state.dellink != HA_OFFSET_ERROR)
+ {
+ block_info.second_read=0;
+ if (_mi_get_block_info(&block_info,info->dfile,info->s->state.dellink)
+ & BLOCK_DELETED)
+ {
+ char buff[8];
+ mi_sizestore(buff,filepos);
+ if (my_pwrite(info->dfile,buff,8,info->s->state.dellink+12,
+ MYF(MY_NABP)))
+ error=1; /* Error on write */
+ }
+ else
+ {
+ error=1; /* Wrong delete link */
+ my_errno=HA_ERR_WRONG_IN_RECORD;
+ }
+ }
+
+ block_info.second_read=second_read;
+ do
+ {
+ /* Remove block at 'filepos' */
+ if ((b_type=_mi_get_block_info(&block_info,info->dfile,filepos))
+ & (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR |
+ BLOCK_FATAL_ERROR) ||
+ (length=(uint) (block_info.filepos-filepos) +block_info.block_len) <
+ MI_MIN_BLOCK_LENGTH)
+ {
+ my_errno=HA_ERR_WRONG_IN_RECORD;
+ DBUG_RETURN(1);
+ }
+ /* Check if next block is a delete block */
+ del_block.second_read=0;
+ remove_next_block=0;
+ if (_mi_get_block_info(&del_block,info->dfile,filepos+length) &
+ BLOCK_DELETED && del_block.block_len+length < MI_DYN_MAX_BLOCK_LENGTH)
+ {
+ /* We can't remove this yet as this block may be the head block */
+ remove_next_block=1;
+ length+=del_block.block_len;
+ }
+
+ block_info.header[0]=0;
+ mi_int3store(block_info.header+1,length);
+ mi_sizestore(block_info.header+4,info->s->state.dellink);
+ if (b_type & BLOCK_LAST)
+ bfill(block_info.header+12,8,255);
+ else
+ mi_sizestore(block_info.header+12,block_info.next_filepos);
+ if (my_pwrite(info->dfile,(byte*) block_info.header,20,filepos,
+ MYF(MY_NABP)))
+ DBUG_RETURN(1);
+ info->s->state.dellink = filepos;
+ info->state->del++;
+ info->state->empty+=length;
+ filepos=block_info.next_filepos;
+
+ /* Now it's safe to unlink the block */
+ if (remove_next_block && unlink_deleted_block(info,&del_block))
+ error=1;
+ } while (!(b_type & BLOCK_LAST));
+
+ DBUG_RETURN(error);
+}
+
+
+ /* Write a block to datafile */
+
+int _mi_write_part_record(MI_INFO *info,
+ my_off_t filepos, /* points at empty block */
+ ulong length, /* length of block */
+ my_off_t next_filepos,/* Next empty block */
+ byte **record, /* pointer to record ptr */
+ ulong *reclength, /* length of *record */
+ int *flag) /* *flag == 0 if header */
+{
+ ulong head_length,res_length,extra_length,long_block,del_length;
+ byte *pos,*record_end;
+ my_off_t next_delete_block;
+ uchar temp[MI_SPLIT_LENGTH+MI_DYN_DELETE_BLOCK_HEADER];
+ DBUG_ENTER("_mi_write_part_record");
+
+ next_delete_block=HA_OFFSET_ERROR;
+
+ res_length=extra_length=0;
+ if (length > *reclength + MI_SPLIT_LENGTH)
+ { /* Splitt big block */
+ res_length=MY_ALIGN(length- *reclength - MI_EXTEND_BLOCK_LENGTH,
+ MI_DYN_ALIGN_SIZE);
+ length-= res_length; /* Use this for first part */
+ }
+ long_block= (length < 65520L && *reclength < 65520L) ? 0 : 1;
+ if (length == *reclength+ 3 + long_block)
+ {
+ /* Block is exactly of the right length */
+ temp[0]=(uchar) (1+ *flag)+(uchar) long_block; /* Flag is 0 or 6 */
+ if (long_block)
+ {
+ mi_int3store(temp+1,*reclength);
+ head_length=4;
+ }
+ else
+ {
+ mi_int2store(temp+1,*reclength);
+ head_length=3;
+ }
+ }
+ else if (length-long_block < *reclength+4)
+ { /* To short block */
+ if (next_filepos == HA_OFFSET_ERROR)
+ next_filepos=info->s->state.dellink != HA_OFFSET_ERROR ?
+ 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)
+ {
+ 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
+ {
+ head_length=3+8+long_block;
+ temp[0]=11+(uchar) long_block;
+ if (long_block)
+ {
+ mi_int3store(temp+1,length-head_length);
+ mi_sizestore((byte*) temp+4,next_filepos);
+ }
+ else
+ {
+ mi_int2store(temp+1,length-head_length);
+ mi_sizestore((byte*) temp+3,next_filepos);
+ }
+ }
+ }
+ else
+ { /* Block with empty info last */
+ head_length=4+long_block;
+ extra_length= length- *reclength-head_length;
+ temp[0]= (uchar) (3+ *flag)+(uchar) long_block; /* 3,4 or 9,10 */
+ if (long_block)
+ {
+ mi_int3store(temp+1,*reclength);
+ temp[4]= (uchar) (extra_length);
+ }
+ else
+ {
+ mi_int2store(temp+1,*reclength);
+ temp[3]= (uchar) (extra_length);
+ }
+ length= *reclength+head_length; /* Write only what is needed */
+ }
+ DBUG_DUMP("header",(byte*) temp,head_length);
+
+ /* Make a long block for one write */
+ record_end= *record+length-head_length;
+ del_length=(res_length ? MI_DYN_DELETE_BLOCK_HEADER : 0);
+ bmove((byte*) (*record-head_length),(byte*) temp,head_length);
+ memcpy(temp,record_end,(size_t) (extra_length+del_length));
+ bzero((byte*) record_end,extra_length);
+
+ if (res_length)
+ {
+ /* Check first if we can join this block with the next one */
+ MI_BLOCK_INFO del_block;
+ my_off_t next_block=filepos+length+extra_length+res_length;
+
+ del_block.second_read=0;
+ if (next_block < info->state->data_file_length &&
+ info->s->state.dellink != HA_OFFSET_ERROR)
+ {
+ if ((_mi_get_block_info(&del_block,info->dfile,next_block)
+ & BLOCK_DELETED) &&
+ res_length + del_block.block_len < MI_DYN_MAX_BLOCK_LENGTH)
+ {
+ if (unlink_deleted_block(info,&del_block))
+ goto err;
+ res_length+=del_block.block_len;
+ }
+ }
+
+ /* Create a delete link of the last part of the block */
+ pos=record_end+extra_length;
+ pos[0]= '\0';
+ mi_int3store(pos+1,res_length);
+ mi_sizestore(pos+4,info->s->state.dellink);
+ bfill(pos+12,8,255); /* End link */
+ next_delete_block=info->s->state.dellink;
+ info->s->state.dellink= filepos+length+extra_length;
+ info->state->del++;
+ info->state->empty+=res_length;
+ info->s->state.split++;
+ }
+ if (info->opt_flag & WRITE_CACHE_USED &&
+ info->update & HA_STATE_WRITE_AT_END)
+ {
+ if (info->update & HA_STATE_EXTEND_BLOCK)
+ {
+ info->update&= ~HA_STATE_EXTEND_BLOCK;
+ if (my_block_write(&info->rec_cache,(byte*) *record-head_length,
+ length+extra_length+del_length,filepos))
+ goto err;
+ }
+ else if (my_b_write(&info->rec_cache,(byte*) *record-head_length,
+ length+extra_length+del_length))
+ goto err;
+ }
+ else
+ {
+ info->rec_cache.seek_not_done=1;
+ if (my_pwrite(info->dfile,(byte*) *record-head_length,length+extra_length+
+ del_length,filepos,info->s->write_flag))
+ goto err;
+ }
+ memcpy(record_end,temp,(size_t) (extra_length+del_length));
+ *record=record_end;
+ *reclength-=(length-head_length);
+ *flag=6;
+
+ if (del_length && next_delete_block != HA_OFFSET_ERROR)
+ {
+ /* link the next delete block to this */
+ MI_BLOCK_INFO del_block;
+ del_block.second_read=0;
+ if (!(_mi_get_block_info(&del_block,info->dfile,next_delete_block)
+ & BLOCK_DELETED))
+ {
+ my_errno=HA_ERR_WRONG_IN_RECORD;
+ goto err;
+ }
+ mi_sizestore(del_block.header+12,info->s->state.dellink);
+ if (my_pwrite(info->dfile,(char*) del_block.header+12,8,
+ next_delete_block+12,
+ MYF(MY_NABP)))
+ goto err;
+ }
+
+ DBUG_RETURN(0);
+err:
+ DBUG_PRINT("exit",("errno: %d",my_errno));
+ DBUG_RETURN(1);
+} /*_mi_write_part_record */
+
+
+ /* update record from datafile */
+
+static int update_dynamic_record(MI_INFO *info, my_off_t filepos, byte *record,
+ ulong reclength)
+{
+ int flag;
+ uint error;
+ ulong length;
+ MI_BLOCK_INFO block_info;
+ DBUG_ENTER("update_dynamic_record");
+
+ flag=block_info.second_read=0;
+ while (reclength > 0)
+ {
+ if (filepos != info->s->state.dellink)
+ {
+ block_info.next_filepos= HA_OFFSET_ERROR;
+ if ((error=_mi_get_block_info(&block_info,info->dfile,filepos))
+ & (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR |
+ BLOCK_FATAL_ERROR))
+ {
+ DBUG_PRINT("error",("Got wrong block info"));
+ if (!(error & BLOCK_FATAL_ERROR))
+ my_errno=HA_ERR_WRONG_IN_RECORD;
+ goto err;
+ }
+ length=(ulong) (block_info.filepos-filepos) + block_info.block_len;
+ if (length < reclength)
+ {
+ uint tmp=MY_ALIGN(reclength - length + 3 +
+ test(reclength >= 65520L),MI_DYN_ALIGN_SIZE);
+ /* Check if we can extend this block */
+ if (block_info.filepos + block_info.block_len ==
+ info->state->data_file_length &&
+ info->state->data_file_length <
+ info->s->base.max_data_file_length-tmp)
+ {
+ /* extend file */
+ DBUG_PRINT("info",("Extending file with %d bytes",tmp));
+ if (info->nextpos == info->state->data_file_length)
+ info->nextpos+= tmp;
+ info->state->data_file_length+= tmp;
+ info->update|= HA_STATE_WRITE_AT_END | HA_STATE_EXTEND_BLOCK;
+ length+=tmp;
+ }
+ else
+ {
+ /* Check if next block is a deleted block */
+ MI_BLOCK_INFO del_block;
+ del_block.second_read=0;
+ if (_mi_get_block_info(&del_block,info->dfile,
+ block_info.filepos + block_info.block_len) &
+ BLOCK_DELETED)
+ {
+ /* Use; Unlink it and extend the current block */
+ DBUG_PRINT("info",("Extending current block"));
+ if (unlink_deleted_block(info,&del_block))
+ goto err;
+ length+=del_block.block_len;
+ }
+ }
+ }
+ }
+ else
+ {
+ if (_mi_find_writepos(info,reclength,&filepos,&length))
+ goto err;
+ }
+ if (_mi_write_part_record(info,filepos,length,block_info.next_filepos,
+ &record,&reclength,&flag))
+ goto err;
+ if ((filepos=block_info.next_filepos) == HA_OFFSET_ERROR)
+ filepos=info->s->state.dellink;
+ }
+
+ if (block_info.next_filepos != HA_OFFSET_ERROR)
+ if (delete_dynamic_record(info,block_info.next_filepos,1))
+ goto err;
+ DBUG_RETURN(0);
+err:
+ DBUG_RETURN(1);
+}
+
+
+ /* Pack a record. Return new reclength */
+
+uint _mi_rec_pack(MI_INFO *info, register byte *to, register const byte *from)
+{
+ uint length,new_length,flag,bit,i;
+ char *pos,*end,*startpos,*packpos;
+ enum en_fieldtype type;
+ reg3 MI_COLUMNDEF *rec;
+ MI_BLOB *blob;
+ DBUG_ENTER("_mi_rec_pack");
+
+ flag=0 ; bit=1;
+ startpos=packpos=to; to+= info->s->base.pack_bits; blob=info->blobs;
+ rec=info->s->rec;
+
+ for (i=info->s->base.fields ; i-- > 0; from+= length,rec++)
+ {
+ length=(uint) rec->length;
+ if ((type = (enum en_fieldtype) rec->type) != FIELD_NORMAL)
+ {
+ if (type == FIELD_BLOB)
+ {
+ if (!blob->length)
+ flag|=bit;
+ else
+ {
+ char *temp_pos;
+ size_t tmp_length=length-mi_portable_sizeof_char_ptr;
+ memcpy((byte*) to,from,tmp_length);
+ memcpy_fixed(&temp_pos,from+tmp_length,sizeof(char*));
+ memcpy(to+tmp_length,temp_pos,(size_t) blob->length);
+ to+=tmp_length+blob->length;
+ }
+ blob++;
+ }
+ else if (type == FIELD_SKIPP_ZERO)
+ {
+ if (memcmp((byte*) from,zero_string,length) == 0)
+ flag|=bit;
+ else
+ {
+ memcpy((byte*) to,from,(size_t) length); to+=length;
+ }
+ }
+ else if (type == FIELD_SKIPP_ENDSPACE ||
+ type == FIELD_SKIPP_PRESPACE)
+ {
+ pos= (byte*) from; end= (byte*) from + length;
+ if (type == FIELD_SKIPP_ENDSPACE)
+ { /* Pack trailing spaces */
+ while (end > from && *(end-1) == ' ')
+ end--;
+ }
+ else
+ { /* Pack pref-spaces */
+ while (pos < end && *pos == ' ')
+ pos++;
+ }
+ new_length=(uint) (end-pos);
+ if (new_length +1 + test(rec->length > 255 && new_length > 127)
+ < length)
+ {
+ if (rec->length > 255 && new_length > 127)
+ {
+ to[0]=(char) ((new_length & 127)+128);
+ to[1]=(char) (new_length >> 7);
+ to+=2;
+ }
+ else
+ *to++= (char) new_length;
+ memcpy((byte*) to,pos,(size_t) new_length); to+=new_length;
+ flag|=bit;
+ }
+ else
+ {
+ memcpy(to,from,(size_t) length); to+=length;
+ }
+ }
+ else if (type == FIELD_VARCHAR)
+ {
+ uint tmp_length=uint2korr(from);
+ store_key_length_inc(to,tmp_length);
+ memcpy(to,from+2,tmp_length);
+ to+=tmp_length;
+ continue;
+ }
+ else
+ {
+ memcpy(to,from,(size_t) length); to+=length;
+ continue; /* Normal field */
+ }
+ if ((bit= bit << 1) >= 256)
+ {
+ *packpos++ = (char) (uchar) flag;
+ bit=1; flag=0;
+ }
+ }
+ else
+ {
+ memcpy(to,from,(size_t) length); to+=length;
+ }
+ }
+ if (bit != 1)
+ *packpos= (char) (uchar) flag;
+ if (info->s->calc_checksum)
+ *to++=(char) info->checksum;
+ DBUG_PRINT("exit",("packed length: %d",(int) (to-startpos)));
+ DBUG_RETURN((uint) (to-startpos));
+} /* _mi_rec_pack */
+
+
+
+/*
+** Check if a record was correctly packed. Used only by isamchk
+** Returns 0 if record is ok.
+*/
+
+my_bool _mi_rec_check(MI_INFO *info,const char *record)
+{
+ uint length,new_length,flag,bit,i;
+ char *pos,*end,*packpos,*to;
+ enum en_fieldtype type;
+ reg3 MI_COLUMNDEF *rec;
+ DBUG_ENTER("_mi_rec_check");
+
+ packpos=info->rec_buff; to= info->rec_buff+info->s->base.pack_bits;
+ rec=info->s->rec;
+ flag= *packpos; bit=1;
+
+ for (i=info->s->base.fields ; i-- > 0; record+= length, rec++)
+ {
+ length=(uint) rec->length;
+ if ((type = (enum en_fieldtype) rec->type) != FIELD_NORMAL)
+ {
+ if (type == FIELD_BLOB)
+ {
+ uint blob_length=
+ _mi_calc_blob_length(length-mi_portable_sizeof_char_ptr,record);
+ if (!blob_length && !(flag & bit))
+ goto err;
+ if (blob_length)
+ to+=length - mi_portable_sizeof_char_ptr+ blob_length;
+ }
+ else if (type == FIELD_SKIPP_ZERO)
+ {
+ if (memcmp((byte*) record,zero_string,length) == 0)
+ {
+ if (!(flag & bit))
+ goto err;
+ }
+ else
+ to+=length;
+ }
+ else if (type == FIELD_SKIPP_ENDSPACE ||
+ type == FIELD_SKIPP_PRESPACE)
+ {
+ pos= (byte*) record; end= (byte*) record + length;
+ if (type == FIELD_SKIPP_ENDSPACE)
+ { /* Pack trailing spaces */
+ while (end > record && *(end-1) == ' ')
+ end--;
+ }
+ else
+ { /* Pack pre-spaces */
+ while (pos < end && *pos == ' ')
+ pos++;
+ }
+ new_length=(uint) (end-pos);
+ if (new_length +1 + test(rec->length > 255 && new_length > 127)
+ < length)
+ {
+ if (!(flag & bit))
+ goto err;
+ if (rec->length > 255 && new_length > 127)
+ {
+ if (to[0] != (char) ((new_length & 127)+128) ||
+ to[1] != (char) (new_length >> 7))
+ goto err;
+ to+=2;
+ }
+ else if (*to++ != (char) new_length)
+ goto err;
+ to+=new_length;
+ }
+ else
+ to+=length;
+ }
+ else if (type == FIELD_VARCHAR)
+ {
+ uint tmp_length=uint2korr(record);
+ to+=get_pack_length(tmp_length)+tmp_length;
+ continue;
+ }
+ else
+ {
+ to+=length;
+ continue; /* Normal field */
+ }
+ if ((bit= bit << 1) >= 256)
+ {
+ flag= *++packpos;
+ bit=1;
+ }
+ }
+ else
+ {
+ to+=length;
+ }
+ }
+ if (info->packed_length != (uint) (to - info->rec_buff)
+ + test(info->s->calc_checksum) ||
+ (bit != 1 && (flag & ~(bit - 1))))
+ goto err;
+ if (info->s->calc_checksum)
+ {
+ if ((uchar) info->checksum != (uchar) *to)
+ {
+ DBUG_PRINT("error",("wrong checksum for row"));
+ goto err;
+ }
+ }
+ DBUG_RETURN(0);
+
+ err:
+ DBUG_RETURN(1);
+}
+
+
+
+ /* Unpacks a record */
+ /* Returns -1 and my_errno =HA_ERR_RECORD_DELETED if reclength isn't */
+ /* right. Returns reclength (>0) if ok */
+
+ulong _mi_rec_unpack(register MI_INFO *info, register byte *to, byte *from,
+ ulong found_length)
+{
+ uint flag,bit,length,rec_length,min_pack_length;
+ enum en_fieldtype type;
+ byte *from_end,*to_end,*packpos;
+ reg3 MI_COLUMNDEF *rec,*end_field;
+ DBUG_ENTER("_mi_rec_unpack");
+
+ to_end=to + info->s->base.reclength;
+ from_end=from+found_length;
+ flag= (uchar) *from; bit=1; packpos=from;
+ if (found_length < info->s->base.min_pack_length)
+ goto err;
+ from+= info->s->base.pack_bits;
+ min_pack_length=info->s->base.min_pack_length - info->s->base.pack_bits;
+
+ for (rec=info->s->rec , end_field=rec+info->s->base.fields ;
+ rec < end_field ; to+= rec_length, rec++)
+ {
+ rec_length=rec->length;
+ if ((type = (enum en_fieldtype) rec->type) != FIELD_NORMAL &&
+ (type != FIELD_CHECK))
+ {
+ if (type == FIELD_VARCHAR)
+ {
+ get_key_length(length,from);
+ if (length > rec_length-2)
+ goto err;
+ int2store(to,length);
+ memcpy(to+2,from,length);
+ from+=length;
+ continue;
+ }
+ if (flag & bit)
+ {
+ if (type == FIELD_BLOB || type == FIELD_SKIPP_ZERO)
+ bzero((byte*) to,rec_length);
+ else if (type == FIELD_SKIPP_ENDSPACE ||
+ type == FIELD_SKIPP_PRESPACE)
+ {
+ if (rec->length > 255 && *from & 128)
+ {
+ if (from + 1 >= from_end)
+ goto err;
+ length= (*from & 127)+ ((uint) (uchar) *(from+1) << 7); from+=2;
+ }
+ else
+ {
+ if (from == from_end)
+ goto err;
+ length= (uchar) *from++;
+ }
+ min_pack_length--;
+ if (length >= rec_length ||
+ min_pack_length + length > (uint) (from_end - from))
+ goto err;
+ if (type == FIELD_SKIPP_ENDSPACE)
+ {
+ memcpy(to,(byte*) from,(size_t) length);
+ bfill((byte*) to+length,rec_length-length,' ');
+ }
+ else
+ {
+ bfill((byte*) to,rec_length-length,' ');
+ memcpy(to+rec_length-length,(byte*) from,(size_t) length);
+ }
+ from+=length;
+ }
+ }
+ else if (type == FIELD_BLOB)
+ {
+ uint size_length=rec_length- mi_portable_sizeof_char_ptr;
+ ulong blob_length=_mi_calc_blob_length(size_length,from);
+ if ((ulong) (from_end-from) - size_length < blob_length ||
+ min_pack_length > (uint) (from_end -(from+size_length+blob_length)))
+ goto err;
+ memcpy((byte*) to,(byte*) from,(size_t) size_length);
+ from+=size_length;
+ memcpy_fixed((byte*) to+size_length,(byte*) &from,sizeof(char*));
+ from+=blob_length;
+ }
+ else
+ {
+ if (type == FIELD_SKIPP_ENDSPACE || type == FIELD_SKIPP_PRESPACE)
+ min_pack_length--;
+ if (min_pack_length + rec_length > (uint) (from_end - from))
+ goto err;
+ memcpy(to,(byte*) from,(size_t) rec_length); from+=rec_length;
+ }
+ if ((bit= bit << 1) >= 256)
+ {
+ flag= (uchar) *++packpos; bit=1;
+ }
+ }
+ else
+ {
+ if (min_pack_length > (uint) (from_end - from))
+ goto err;
+ min_pack_length-=rec_length;
+ memcpy(to,(byte*) from,(size_t) rec_length); from+=rec_length;
+ }
+ }
+ if (info->s->calc_checksum)
+ from++;
+ if (to == to_end && from == from_end && (bit == 1 || !(flag & ~(bit-1))))
+ DBUG_RETURN((info->packed_length=found_length));
+ err:
+ my_errno=HA_ERR_RECORD_DELETED;
+ DBUG_PRINT("error",("to_end: %lx -> %lx from_end: %lx -> %lx",
+ to,to_end,from,from_end));
+ DBUG_DUMP("from",(byte*) info->rec_buff,info->s->base.min_pack_length);
+ DBUG_RETURN(MY_FILE_ERROR);
+} /* _mi_rec_unpack */
+
+
+ /* Calc length of blob. Update info in blobs->length */
+
+ulong _my_calc_total_blob_length(MI_INFO *info, const byte *record)
+{
+ ulong length;
+ MI_BLOB *blob,*end;
+
+ for (length=0, blob= info->blobs, end=blob+info->s->base.blobs ;
+ blob != end;
+ blob++)
+ {
+ blob->length=_mi_calc_blob_length(blob->pack_length,record + blob->offset);
+ length+=blob->length;
+ }
+ return length;
+}
+
+
+ulong _mi_calc_blob_length(uint length, const byte *pos)
+{
+ switch (length) {
+ case 1:
+ return (uint) (uchar) *pos;
+ case 2:
+ return (uint) uint2korr(pos);
+ case 3:
+ return uint3korr(pos);
+ case 4:
+ return uint4korr(pos);
+ default:
+ break;
+ }
+ return 0; /* Impossible */
+}
+
+
+void _my_store_blob_length(byte *pos,uint pack_length,uint length)
+{
+ switch (pack_length) {
+ case 1:
+ *pos= (uchar) length;
+ break;
+ case 2:
+ int2store(pos,length);
+ break;
+ case 3:
+ int3store(pos,length);
+ break;
+ case 4:
+ int4store(pos,length);
+ default:
+ break;
+ }
+ return;
+}
+
+
+ /* Read record from datafile */
+ /* Returns 0 if ok, -1 if error */
+
+int _mi_read_dynamic_record(MI_INFO *info, my_off_t filepos, byte *buf)
+{
+ int flag;
+ uint b_type,left_length;
+ byte *to;
+ MI_BLOCK_INFO block_info;
+ File file;
+ DBUG_ENTER("mi_read_dynamic_record");
+
+ if (filepos != HA_OFFSET_ERROR)
+ {
+ LINT_INIT(to);
+ LINT_INIT(left_length);
+ file=info->dfile;
+ block_info.next_filepos=filepos; /* for easyer loop */
+ flag=block_info.second_read=0;
+ do
+ {
+ if (info->opt_flag & WRITE_CACHE_USED &&
+ info->rec_cache.pos_in_file <= block_info.next_filepos &&
+ flush_io_cache(&info->rec_cache))
+ goto err;
+ info->rec_cache.seek_not_done=1;
+ if ((b_type=_mi_get_block_info(&block_info,file,
+ block_info.next_filepos))
+ & (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR |
+ BLOCK_FATAL_ERROR))
+ {
+ if (b_type & (BLOCK_SYNC_ERROR | BLOCK_DELETED))
+ my_errno=HA_ERR_RECORD_DELETED;
+ goto err;
+ }
+ if (flag == 0) /* First block */
+ {
+ flag=1;
+ if (block_info.rec_len > (uint) info->s->base.max_pack_length)
+ goto panic;
+ if (info->s->base.blobs)
+ {
+ if (!(to=mi_fix_rec_buff_for_blob(info,block_info.rec_len)))
+ goto err;
+ }
+ else
+ to= info->rec_buff;
+ left_length=block_info.rec_len;
+ }
+ if (left_length < block_info.data_len || ! block_info.data_len)
+ goto panic; /* Wrong linked record */
+ if (my_pread(file,(byte*) to,block_info.data_len,block_info.filepos,
+ MYF(MY_NABP)))
+ goto panic;
+ left_length-=block_info.data_len;
+ to+=block_info.data_len;
+ } while (left_length);
+
+ info->update|= HA_STATE_AKTIV; /* We have a aktive record */
+ VOID(_mi_writeinfo(info,0));
+ DBUG_RETURN(_mi_rec_unpack(info,buf,info->rec_buff,block_info.rec_len) !=
+ MY_FILE_ERROR ? 0 : -1);
+ }
+ VOID(_mi_writeinfo(info,0));
+ DBUG_RETURN(-1); /* Wrong data to read */
+
+panic:
+ my_errno=HA_ERR_WRONG_IN_RECORD;
+err:
+ VOID(_mi_writeinfo(info,0));
+ DBUG_RETURN(-1);
+}
+
+
+byte *mi_fix_rec_buff_for_blob(MI_INFO *info, ulong length)
+{
+ uint extra;
+ if (! info->rec_buff || length > info->alloced_rec_buff_length)
+ {
+ byte *newptr;
+ extra=ALIGN_SIZE(MI_MAX_DYN_BLOCK_HEADER)+MI_SPLIT_LENGTH+
+ MI_DYN_DELETE_BLOCK_HEADER;
+ if (!(newptr=(byte*) my_realloc((gptr) info->rec_alloc,length+extra,
+ MYF(MY_ALLOW_ZERO_PTR))))
+ return newptr;
+ info->rec_alloc=newptr;
+ info->rec_buff=newptr+ALIGN_SIZE(MI_DYN_DELETE_BLOCK_HEADER);
+ info->alloced_rec_buff_length=length;
+ }
+ return info->rec_buff;
+}
+
+
+ /* compare unique constraint between stored rows */
+
+int _mi_cmp_dynamic_unique(MI_INFO *info, MI_UNIQUEDEF *def,
+ const byte *record, my_off_t pos)
+{
+ byte *rec_buff,*rec_alloc,*old_record;
+ uint alloced_rec_buff_length;
+ int error;
+ DBUG_ENTER("_mi_cmp_dynamic_unique");
+
+ if (!(old_record=my_alloca(info->s->base.reclength)))
+ DBUG_RETURN(1);
+
+ /* Don't let the compare destroy blobs that may be in use */
+ rec_buff=info->rec_buff;
+ rec_alloc=info->rec_alloc;
+ alloced_rec_buff_length=info->alloced_rec_buff_length;
+ if (info->s->base.blobs)
+ {
+ info->rec_buff=0;
+ info->rec_alloc=0;
+ info->alloced_rec_buff_length=0;
+ }
+ error=_mi_read_dynamic_record(info,pos,old_record);
+ if (!error)
+ error=mi_unique_comp(def, record, old_record, def->null_are_equal);
+ if (info->s->base.blobs)
+ {
+ my_free(info->rec_alloc,MYF(MY_ALLOW_ZERO_PTR));
+ info->rec_buff=rec_buff;
+ info->rec_alloc=rec_alloc;
+ info->alloced_rec_buff_length=alloced_rec_buff_length;
+ }
+ my_afree(old_record);
+ DBUG_RETURN(error);
+}
+
+
+ /* Compare of record one disk with packed record in memory */
+
+int _mi_cmp_dynamic_record(register MI_INFO *info, register const byte *record)
+{
+ uint flag,reclength,b_type;
+ my_off_t filepos;
+ byte *buffer;
+ MI_BLOCK_INFO block_info;
+ DBUG_ENTER("_mi_cmp_dynamic_record");
+
+ /* We are going to do changes; dont let anybody disturb */
+ dont_break(); /* Dont allow SIGHUP or SIGINT */
+
+ if (info->opt_flag & WRITE_CACHE_USED)
+ {
+ info->update&= ~(HA_STATE_WRITE_AT_END | HA_STATE_EXTEND_BLOCK);
+ if (flush_io_cache(&info->rec_cache))
+ DBUG_RETURN(-1);
+ }
+ info->rec_cache.seek_not_done=1;
+
+ /* If nobody have touched the database we don't have to test rec */
+
+ buffer=info->rec_buff;
+ if ((info->opt_flag & READ_CHECK_USED))
+ { /* If check isn't disabled */
+ if (info->s->base.blobs)
+ {
+ if (!(buffer=(byte*) my_alloca(info->s->base.pack_reclength+
+ _my_calc_total_blob_length(info,record))))
+ DBUG_RETURN(-1);
+ }
+ reclength=_mi_rec_pack(info,buffer,record);
+ record= buffer;
+
+ filepos=info->lastpos;
+ flag=block_info.second_read=0;
+ block_info.next_filepos=filepos;
+ while (reclength > 0)
+ {
+ if ((b_type=_mi_get_block_info(&block_info,info->dfile,
+ block_info.next_filepos))
+ & (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR |
+ BLOCK_FATAL_ERROR))
+ {
+ if (b_type & (BLOCK_SYNC_ERROR | BLOCK_DELETED))
+ my_errno=HA_ERR_RECORD_CHANGED;
+ goto err;
+ }
+ if (flag == 0) /* First block */
+ {
+ flag=1;
+ if (reclength != block_info.rec_len)
+ {
+ my_errno=HA_ERR_RECORD_CHANGED;
+ goto err;
+ }
+ } else if (reclength < block_info.data_len)
+ {
+ my_errno=HA_ERR_WRONG_IN_RECORD;
+ goto err;
+ }
+ reclength-=block_info.data_len;
+ if (_mi_cmp_buffer(info->dfile,record,block_info.filepos,
+ block_info.data_len))
+ {
+ my_errno=HA_ERR_RECORD_CHANGED;
+ goto err;
+ }
+ flag=1;
+ record+=block_info.data_len;
+ }
+ }
+ my_errno=0;
+ err:
+ if (buffer != info->rec_buff)
+ my_afree((gptr) buffer);
+ DBUG_RETURN(my_errno);
+}
+
+
+ /* Compare file to buffert */
+
+static int _mi_cmp_buffer(File file, const byte *buff, my_off_t filepos,
+ uint length)
+{
+ uint next_length;
+ char temp_buff[IO_SIZE*2];
+ DBUG_ENTER("_mi_cmp_buffer");
+
+ VOID(my_seek(file,filepos,MY_SEEK_SET,MYF(0)));
+ next_length= IO_SIZE*2 - (uint) (filepos & (IO_SIZE-1));
+
+ while (length > IO_SIZE*2)
+ {
+ if (my_read(file,temp_buff,next_length,MYF(MY_NABP)))
+ goto err;
+ if (memcmp((byte*) buff,temp_buff,IO_SIZE))
+ DBUG_RETURN(1);
+ buff+=next_length;
+ length-= next_length;
+ next_length=IO_SIZE*2;
+ }
+ if (my_read(file,temp_buff,length,MYF(MY_NABP)))
+ goto err;
+ DBUG_RETURN(memcmp((byte*) buff,temp_buff,length));
+err:
+ DBUG_RETURN(1);
+}
+
+
+int _mi_read_rnd_dynamic_record(MI_INFO *info, byte *buf,
+ register my_off_t filepos,
+ my_bool skipp_deleted_blocks)
+{
+ int flag,info_read,save_errno;
+ uint left_len,b_type;
+ byte *to;
+ MI_BLOCK_INFO block_info;
+ MYISAM_SHARE *share=info->s;
+ DBUG_ENTER("_mi_read_rnd_dynamic_record");
+
+ info_read=0;
+ LINT_INIT(to);
+
+ if (info->lock_type == F_UNLCK)
+ {
+#ifndef UNSAFE_LOCKING
+ if (share->r_locks == 0 && share->w_locks == 0)
+ {
+ if (my_lock(share->kfile,F_RDLCK,0L,F_TO_EOF,
+ MYF(MY_SEEK_NOT_DONE) | info->lock_wait))
+ DBUG_RETURN(my_errno);
+ }
+#else
+ info->tmp_lock_type=F_RDLCK;
+#endif
+ }
+ else
+ info_read=1; /* memory-keyinfoblock is ok */
+
+ flag=block_info.second_read=0;
+ left_len=1;
+ do
+ {
+ if (filepos >= info->state->data_file_length)
+ {
+ if (!info_read)
+ { /* Check if changed */
+ info_read=1;
+ info->rec_cache.seek_not_done=1;
+ if (mi_state_info_read_dsk(share->kfile,&share->state,1))
+ goto panic;
+ }
+ if (filepos >= info->state->data_file_length)
+ {
+ my_errno= HA_ERR_END_OF_FILE;
+ goto err;
+ }
+ }
+ if (info->opt_flag & READ_CACHE_USED)
+ {
+ if (_mi_read_cache(&info->rec_cache,(byte*) block_info.header,filepos,
+ sizeof(block_info.header),
+ test(!flag && skipp_deleted_blocks) | 2))
+ goto panic;
+ b_type=_mi_get_block_info(&block_info,-1,filepos);
+ }
+ else
+ {
+ if (info->opt_flag & WRITE_CACHE_USED &&
+ info->rec_cache.pos_in_file <= filepos &&
+ flush_io_cache(&info->rec_cache))
+ DBUG_RETURN(my_errno);
+ info->rec_cache.seek_not_done=1;
+ b_type=_mi_get_block_info(&block_info,info->dfile,filepos);
+ }
+
+ if (b_type & (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR |
+ BLOCK_FATAL_ERROR))
+ {
+ if ((b_type & (BLOCK_DELETED | BLOCK_SYNC_ERROR))
+ && skipp_deleted_blocks)
+ {
+ filepos=block_info.filepos+block_info.block_len;
+ block_info.second_read=0;
+ continue; /* Search after next_record */
+ }
+ if (b_type & (BLOCK_DELETED | BLOCK_SYNC_ERROR))
+ {
+ my_errno=HA_ERR_RECORD_DELETED;
+ info->lastpos=block_info.filepos;
+ info->nextpos=block_info.filepos+block_info.block_len;
+ }
+ goto err;
+ }
+ if (flag == 0) /* First block */
+ {
+ if (block_info.rec_len > (uint) share->base.max_pack_length)
+ goto panic;
+ info->lastpos=filepos;
+ if (share->base.blobs)
+ {
+ if (!(to=mi_fix_rec_buff_for_blob(info,block_info.rec_len)))
+ goto err;
+ }
+ else
+ to= info->rec_buff;
+ left_len=block_info.rec_len;
+ }
+ if (left_len < block_info.data_len)
+ goto panic; /* Wrong linked record */
+
+ /* copy information that is already read */
+ {
+ uint offset=(uint) (block_info.filepos - filepos);
+ uint tmp_length= (sizeof(block_info.header) - offset);
+ filepos=block_info.filepos;
+
+ if (tmp_length > block_info.data_len)
+ tmp_length= block_info.data_len;
+ if (tmp_length)
+ {
+ memcpy((byte*) to, block_info.header+offset,tmp_length);
+ block_info.data_len-=tmp_length;
+ left_len-=tmp_length;
+ to+=tmp_length;
+ filepos+=tmp_length;
+ }
+ }
+ /* read rest of record from file */
+ if (block_info.data_len)
+ {
+ if (info->opt_flag & READ_CACHE_USED)
+ {
+ if (_mi_read_cache(&info->rec_cache,(byte*) to,filepos,
+ block_info.data_len,
+ test(!flag && skipp_deleted_blocks)))
+ goto panic;
+ }
+ else
+ {
+ /* VOID(my_seek(info->dfile,filepos,MY_SEEK_SET,MYF(0))); */
+ if (my_read(info->dfile,(byte*) to,block_info.data_len,MYF(MY_NABP)))
+ {
+ if (my_errno == -1)
+ my_errno= HA_ERR_WRONG_IN_RECORD; /* Unexpected end of file */
+ goto err;
+ }
+ }
+ }
+ if (flag++ == 0)
+ {
+ info->nextpos=block_info.filepos+block_info.block_len;
+ skipp_deleted_blocks=0;
+ }
+ left_len-=block_info.data_len;
+ to+=block_info.data_len;
+ filepos=block_info.next_filepos;
+ } while (left_len);
+
+ info->update|= HA_STATE_AKTIV | HA_STATE_KEY_CHANGED;
+ if (share->r_locks == 0 && share->w_locks == 0)
+ VOID(_mi_writeinfo(info,0));
+ if (_mi_rec_unpack(info,buf,info->rec_buff,block_info.rec_len) !=
+ MY_FILE_ERROR)
+ DBUG_RETURN(0);
+ DBUG_RETURN(my_errno); /* Wrong record */
+
+panic:
+ my_errno=HA_ERR_WRONG_IN_RECORD; /* Something is fatal wrong */
+err:
+ save_errno=my_errno;
+ VOID(_mi_writeinfo(info,0));
+ DBUG_RETURN(my_errno=save_errno);
+}
+
+
+ /* Read and process header from a dynamic-record-file */
+
+uint _mi_get_block_info(MI_BLOCK_INFO *info, File file, my_off_t filepos)
+{
+ uint return_val=0;
+ uchar *header=info->header;
+
+ if (file >= 0)
+ {
+ VOID(my_seek(file,filepos,MY_SEEK_SET,MYF(0)));
+ if (my_read(file,(char*) header,sizeof(info->header),MYF(0)) !=
+ sizeof(info->header))
+ {
+ my_errno=HA_ERR_WRONG_IN_RECORD;
+ return BLOCK_FATAL_ERROR;
+ }
+ }
+ DBUG_DUMP("header",(byte*) header,MI_BLOCK_INFO_HEADER_LENGTH);
+ if (info->second_read)
+ {
+ if (info->header[0] <= 6)
+ return_val=BLOCK_SYNC_ERROR;
+ }
+ else
+ {
+ if (info->header[0] > 6)
+ return_val=BLOCK_SYNC_ERROR;
+ }
+ info->next_filepos= HA_OFFSET_ERROR; /* Dummy ifall no next block */
+
+ switch (info->header[0]) {
+ case 0:
+ if ((info->block_len=(uint) mi_uint3korr(header+1)) <
+ MI_MIN_BLOCK_LENGTH ||
+ (info->block_len & (MI_DYN_ALIGN_SIZE -1)))
+ {
+ my_errno=HA_ERR_WRONG_IN_RECORD;
+ return BLOCK_ERROR;
+ }
+ info->filepos=filepos;
+ info->next_filepos=mi_sizekorr(header+4);
+ info->prev_filepos=mi_sizekorr(header+12);
+#if SIZEOF_OFF_T == 4
+ if ((mi_uint4korr(header+4) != 0 &&
+ (mi_uint4korr(header+4) != (ulong) ~0 ||
+ info->next_filepos != (ulong) ~0)) ||
+ (mi_uint4korr(header+12) != 0 &&
+ (mi_uint4korr(header+12) != (ulong) ~0 ||
+ info->prev_filepos != (ulong) ~0)))
+ return BLOCK_FATAL_ERROR;
+#endif
+ return return_val | BLOCK_DELETED; /* Deleted block */
+
+ case 1:
+ info->rec_len=info->data_len=info->block_len=mi_uint2korr(header+1);
+ info->filepos=filepos+3;
+ return return_val | BLOCK_FIRST | BLOCK_LAST;
+ case 2:
+ info->rec_len=info->data_len=info->block_len=mi_uint3korr(header+1);
+ info->filepos=filepos+4;
+ return return_val | BLOCK_FIRST | BLOCK_LAST;
+
+ case 3:
+ info->rec_len=info->data_len=mi_uint2korr(header+1);
+ info->block_len=info->rec_len+ (uint) header[3];
+ info->filepos=filepos+4;
+ return return_val | BLOCK_FIRST | BLOCK_LAST;
+ case 4:
+ info->rec_len=info->data_len=mi_uint3korr(header+1);
+ info->block_len=info->rec_len+ (uint) header[4];
+ info->filepos=filepos+5;
+ return return_val | BLOCK_FIRST | BLOCK_LAST;
+
+ case 5:
+ info->rec_len=mi_uint2korr(header+1);
+ info->block_len=info->data_len=mi_uint2korr(header+3);
+ info->next_filepos=mi_sizekorr(header+5);
+ info->second_read=1;
+ info->filepos=filepos+13;
+ return return_val | BLOCK_FIRST;
+ case 6:
+ info->rec_len=mi_uint3korr(header+1);
+ info->block_len=info->data_len=mi_uint3korr(header+4);
+ info->next_filepos=mi_sizekorr(header+7);
+ info->second_read=1;
+ info->filepos=filepos+15;
+ return return_val | BLOCK_FIRST;
+
+ /* The following blocks are identical to 1-6 without rec_len */
+ case 7:
+ info->data_len=info->block_len=mi_uint2korr(header+1);
+ info->filepos=filepos+3;
+ return return_val | BLOCK_LAST;
+ case 8:
+ info->data_len=info->block_len=mi_uint3korr(header+1);
+ info->filepos=filepos+4;
+ return return_val | BLOCK_LAST;
+
+ case 9:
+ info->data_len=mi_uint2korr(header+1);
+ info->block_len=info->data_len+ (uint) header[3];
+ info->filepos=filepos+4;
+ return return_val | BLOCK_LAST;
+ case 10:
+ info->data_len=mi_uint3korr(header+1);
+ info->block_len=info->data_len+ (uint) header[4];
+ info->filepos=filepos+5;
+ return return_val | BLOCK_LAST;
+
+ case 11:
+ info->data_len=info->block_len=mi_uint2korr(header+1);
+ info->next_filepos=mi_sizekorr(header+3);
+ info->second_read=1;
+ info->filepos=filepos+11;
+ return return_val;
+ case 12:
+ info->data_len=info->block_len=mi_uint3korr(header+1);
+ info->next_filepos=mi_sizekorr(header+4);
+ info->second_read=1;
+ info->filepos=filepos+12;
+ return return_val;
+ default:
+ my_errno=HA_ERR_WRONG_IN_RECORD; /* Garbage */
+ return BLOCK_ERROR;
+ }
+}
diff --git a/myisam/mi_extra.c b/myisam/mi_extra.c
new file mode 100644
index 00000000000..287f1dd34c8
--- /dev/null
+++ b/myisam/mi_extra.c
@@ -0,0 +1,324 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* Extra functions we want to do with a database */
+/* - Set flags for quicker databasehandler */
+/* - Set databasehandler to normal */
+/* - Reset recordpointers as after open database */
+
+#include "myisamdef.h"
+#ifdef HAVE_MMAP
+#include <sys/mman.h>
+#endif
+#ifdef __WIN__
+#include <errno.h>
+#endif
+
+ /* set extra flags for database */
+
+int mi_extra(MI_INFO *info, enum ha_extra_function function)
+{
+ int error=0;
+ MYISAM_SHARE *share=info->s;
+ DBUG_ENTER("mi_extra");
+
+ switch (function) {
+ case HA_EXTRA_RESET:
+ info->lastinx= 0; /* Use first index as def */
+ info->last_search_keypage=info->lastpos= HA_OFFSET_ERROR;
+ info->page_changed=1;
+ /* Next/prev gives first/last */
+ if (info->opt_flag & READ_CACHE_USED)
+ {
+ reinit_io_cache(&info->rec_cache,READ_CACHE,0,
+ (pbool) (info->lock_type != F_UNLCK),
+ (pbool) test(info->update & HA_STATE_ROW_CHANGED)
+ );
+ }
+ info->update= ((info->update & HA_STATE_CHANGED) | HA_STATE_NEXT_FOUND |
+ HA_STATE_PREV_FOUND);
+ break;
+ case HA_EXTRA_CACHE:
+ if (info->lock_type == F_UNLCK &&
+ (share->options & HA_OPTION_PACK_RECORD))
+ {
+ error=1; /* Not possibly if not locked */
+ my_errno=EACCES;
+ break;
+ }
+#if defined(HAVE_MMAP) && defined(HAVE_MADVICE)
+ if ((share->options & HA_OPTION_COMPRESS_RECORD))
+ {
+ pthread_mutex_lock(&share->intern_lock);
+ if (_mi_memmap_file(info))
+ {
+ /* We don't nead MADV_SEQUENTIAL if small file */
+ madvise(share->file_map,share->state.state.data_file_length,
+ share->state.state.data_file_length <= RECORD_CACHE_SIZE*16 ?
+ MADV_RANDOM : MADV_SEQUENTIAL);
+ pthread_mutex_unlock(&share->intern_lock);
+ break;
+ }
+ pthread_mutex_unlock(&share->intern_lock);
+ }
+#endif
+ if (info->opt_flag & WRITE_CACHE_USED)
+ {
+ info->opt_flag&= ~WRITE_CACHE_USED;
+ if ((error=end_io_cache(&info->rec_cache)))
+ break;
+ }
+ if (!(info->opt_flag &
+ (READ_CACHE_USED | WRITE_CACHE_USED | MEMMAP_USED)))
+ {
+ if (!(init_io_cache(&info->rec_cache,info->dfile,
+ (uint) min(info->state->data_file_length+1,
+ my_default_record_cache_size),
+ READ_CACHE,0L,(pbool) (info->lock_type != F_UNLCK),
+ MYF(share->write_flag & MY_WAIT_IF_FULL))))
+ {
+ info->opt_flag|=READ_CACHE_USED;
+ info->update&= ~HA_STATE_ROW_CHANGED;
+ }
+ if (share->concurrent_insert)
+ info->rec_cache.end_of_file=info->state->data_file_length;
+ }
+ break;
+ case HA_EXTRA_REINIT_CACHE:
+ if (info->opt_flag & READ_CACHE_USED)
+ {
+ reinit_io_cache(&info->rec_cache,READ_CACHE,info->nextpos,
+ (pbool) (info->lock_type != F_UNLCK),
+ (pbool) test(info->update & HA_STATE_ROW_CHANGED));
+ info->update&= ~HA_STATE_ROW_CHANGED;
+ if (share->concurrent_insert)
+ info->rec_cache.end_of_file=info->state->data_file_length;
+ }
+ break;
+ case HA_EXTRA_WRITE_CACHE:
+ if (info->lock_type == F_UNLCK)
+ {
+ error=1; /* Not possibly if not locked */
+ break;
+ }
+ if (!(info->opt_flag &
+ (READ_CACHE_USED | WRITE_CACHE_USED | OPT_NO_ROWS)) &&
+ !share->state.header.uniques)
+ if (!(init_io_cache(&info->rec_cache,info->dfile,0,
+ WRITE_CACHE,info->state->data_file_length,
+ (pbool) (info->lock_type != F_UNLCK),
+ MYF(share->write_flag & MY_WAIT_IF_FULL))))
+ {
+ info->opt_flag|=WRITE_CACHE_USED;
+ info->update&= ~(HA_STATE_ROW_CHANGED |
+ HA_STATE_WRITE_AT_END |
+ HA_STATE_EXTEND_BLOCK);
+ }
+ break;
+ case HA_EXTRA_NO_CACHE:
+ if (info->opt_flag & (READ_CACHE_USED | WRITE_CACHE_USED))
+ {
+ info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
+ error=end_io_cache(&info->rec_cache);
+ }
+#if defined(HAVE_MMAP) && defined(HAVE_MADVICE)
+ if (info->opt_flag & MEMMAP_USED)
+ madvise(share->file_map,share->state.state.data_file_length,MADV_RANDOM);
+#endif
+ break;
+ case HA_EXTRA_FLUSH_CACHE:
+ if (info->opt_flag & WRITE_CACHE_USED)
+ {
+ if ((error=flush_io_cache(&info->rec_cache)))
+ mi_mark_crashed(info); /* Fatal error found */
+ }
+ break;
+ case HA_EXTRA_NO_READCHECK:
+ info->opt_flag&= ~READ_CHECK_USED; /* No readcheck */
+ break;
+ case HA_EXTRA_READCHECK:
+ info->opt_flag|= READ_CHECK_USED;
+ break;
+ case HA_EXTRA_KEYREAD: /* Read only keys to record */
+ case HA_EXTRA_REMEMBER_POS:
+ info->opt_flag |= REMEMBER_OLD_POS;
+ bmove((byte*) info->lastkey+share->base.max_key_length*2,
+ (byte*) info->lastkey,info->lastkey_length);
+ info->save_update= info->update;
+ info->save_lastinx= info->lastinx;
+ info->save_lastpos= info->lastpos;
+ info->save_lastkey_length=info->lastkey_length;
+ if (function == HA_EXTRA_REMEMBER_POS)
+ break;
+ /* fall through */
+ case HA_EXTRA_KEYREAD_CHANGE_POS:
+ info->opt_flag |= KEY_READ_USED;
+ info->read_record=_mi_read_key_record;
+ break;
+ case HA_EXTRA_NO_KEYREAD:
+ case HA_EXTRA_RESTORE_POS:
+ if (info->opt_flag & REMEMBER_OLD_POS)
+ {
+ bmove((byte*) info->lastkey,
+ (byte*) info->lastkey+share->base.max_key_length*2,
+ info->save_lastkey_length);
+ info->update= info->save_update | HA_STATE_WRITTEN;
+ info->lastinx= info->save_lastinx;
+ info->lastpos= info->save_lastpos;
+ info->lastkey_length=info->save_lastkey_length;
+ }
+ info->read_record= share->read_record;
+ info->opt_flag&= ~(KEY_READ_USED | REMEMBER_OLD_POS);
+ break;
+ case HA_EXTRA_NO_USER_CHANGE: /* Database is somehow locked agains changes */
+ info->lock_type= F_EXTRA_LCK; /* Simulate as locked */
+ break;
+ case HA_EXTRA_WAIT_LOCK:
+ info->lock_wait=0;
+ break;
+ case HA_EXTRA_NO_WAIT_LOCK:
+ info->lock_wait=MY_DONT_WAIT;
+ break;
+ case HA_EXTRA_NO_KEYS:
+ if (info->lock_type == F_UNLCK)
+ {
+ error=1; /* Not possibly if not lock */
+ break;
+ }
+ if (share->state.key_map)
+ {
+ share->state.key_map=0;
+ info->state->key_file_length=share->state.state.key_file_length=
+ share->base.keystart;
+ if (!share->changed)
+ {
+ share->state.changed|=1;
+ share->changed=1; /* Update on close */
+ if (!share->global_changed)
+ {
+ share->global_changed=1;
+ share->state.open_count++;
+ }
+ }
+ share->state.state= *info->state;
+ error=mi_state_info_write(share->kfile,&share->state,1 | 2);
+ }
+ break;
+ case HA_EXTRA_FORCE_REOPEN:
+ 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))
+ {
+ error=my_errno;
+ share->changed=1;
+ mi_mark_crashed(info); /* Fatal error found */
+ }
+ if (info->opt_flag & (READ_CACHE_USED | WRITE_CACHE_USED))
+ {
+ info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
+ error=end_io_cache(&info->rec_cache);
+ }
+ if (info->lock_type != F_UNLCK && ! info->was_locked)
+ {
+ info->was_locked=info->lock_type;
+ if (mi_lock_database(info,F_UNLCK))
+ error=my_errno;
+ info->lock_type = F_UNLCK;
+ }
+ if (share->kfile >= 0 && my_close(share->kfile,MYF(0)))
+ error=my_errno;
+ {
+ LIST *list_element ;
+ for (list_element=myisam_open_list ;
+ list_element ;
+ list_element=list_element->next)
+ {
+ MI_INFO *tmpinfo=(MI_INFO*) list_element->data;
+ if (tmpinfo->s == info->s)
+ {
+ if (tmpinfo->dfile >= 0 && my_close(tmpinfo->dfile,MYF(0)))
+ error = my_errno;
+ tmpinfo->dfile= -1;
+ }
+ }
+ }
+ share->kfile= -1; /* Files aren't open anymore */
+ pthread_mutex_unlock(&share->intern_lock);
+#endif
+ pthread_mutex_unlock(&THR_LOCK_myisam);
+ break;
+ case HA_EXTRA_FLUSH:
+ if (!share->temporary)
+ flush_key_blocks(share->kfile,FLUSH_KEEP);
+#ifdef HAVE_PWRITE
+ _mi_decrement_open_count(info);
+#endif
+ if (share->not_flushed)
+ {
+ share->not_flushed=0;
+#if defined(__WIN__)
+ if (_commit(share->kfile))
+ error=errno;
+ if (_commit(info->dfile))
+ error=errno;
+#elif defined(HAVE_FDATASYNC)
+ if (fdatasync(share->kfile))
+ error=errno;
+ if (fdatasync(share->dfile))
+ error=errno;
+#elif defined(HAVE_FSYNC)
+ if ( fsync(share->kfile))
+ error=errno;
+ if (fsync(share->dfile))
+ error=errno;
+#endif
+ if (error)
+ {
+ share->changed=1;
+ mi_mark_crashed(info); /* Fatal error found */
+ }
+ }
+ if (share->base.blobs)
+ {
+ my_free(info->rec_alloc,MYF(MY_ALLOW_ZERO_PTR));
+ info->rec_alloc=info->rec_buff=0;
+ }
+ break;
+ case HA_EXTRA_NORMAL: /* Theese isn't in use */
+ info->quick_mode=0;
+ break;
+ case HA_EXTRA_QUICK:
+ info->quick_mode=1;
+ break;
+ case HA_EXTRA_NO_ROWS:
+ if (!share->state.header.uniques)
+ info->opt_flag|= OPT_NO_ROWS;
+ break;
+ case HA_EXTRA_KEY_CACHE:
+ case HA_EXTRA_NO_KEY_CACHE:
+ default:
+ break;
+ }
+ {
+ char tmp[1];
+ tmp[0]=function;
+ myisam_log_command(MI_LOG_EXTRA,info,(byte*) tmp,1,error);
+ }
+ DBUG_RETURN(error);
+} /* mi_extra */
diff --git a/myisam/mi_info.c b/myisam/mi_info.c
new file mode 100644
index 00000000000..958c881158d
--- /dev/null
+++ b/myisam/mi_info.c
@@ -0,0 +1,102 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* Ger tillbaka en struct med information om isam-filen */
+
+#include "myisamdef.h"
+#ifdef __WIN__
+#include <sys/stat.h>
+#endif
+
+ /* Get position to last record */
+
+my_off_t mi_position(MI_INFO *info)
+{
+ return info->lastpos;
+}
+
+
+/* Get information about the table */
+/* if flag == 2 one get current info (no sync from database */
+
+int mi_status(MI_INFO *info, register MI_ISAMINFO *x, uint flag)
+{
+ MY_STAT state;
+ MYISAM_SHARE *share=info->s;
+ DBUG_ENTER("mi_status");
+
+ x->recpos = info->lastpos;
+ if (flag == HA_STATUS_POS)
+ DBUG_RETURN(0); /* Compatible with ISAM */
+ if (!(flag & HA_STATUS_NO_LOCK))
+ {
+ pthread_mutex_lock(&share->intern_lock);
+ VOID(_mi_readinfo(info,F_RDLCK,0));
+ VOID(_mi_writeinfo(info,0));
+ pthread_mutex_unlock(&share->intern_lock);
+ }
+ if (flag & HA_STATUS_VARIABLE)
+ {
+ x->records = info->state->records;
+ x->deleted = info->state->del;
+ x->delete_length = info->state->empty;
+ x->data_file_length =info->state->data_file_length;
+ x->index_file_length=info->state->key_file_length;
+
+ x->keys = share->state.header.keys;
+ x->key_map = share->state.key_map;
+ x->check_time = share->state.check_time;
+ x->mean_reclength = info->state->records ?
+ (ulong) (info->state->data_file_length-info->state->empty)/
+ info->state->records : (ulong) share->min_pack_length;
+ }
+ if (flag & HA_STATUS_ERRKEY)
+ {
+ x->errkey = info->errkey;
+ x->dupp_key_pos= info->dupp_key_pos;
+ }
+ if (flag & HA_STATUS_CONST)
+ {
+ x->reclength = share->base.reclength;
+ x->max_data_file_length=share->base.max_data_file_length;
+ x->max_index_file_length=info->s->base.max_key_file_length;
+ x->filenr = info->dfile;
+ x->options = share->options;
+ x->create_time=share->state.create_time;
+ x->reflength= mi_get_pointer_length(share->base.max_data_file_length,4);
+ x->record_offset= ((share->options &
+ (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)) ?
+ 0L : share->base.pack_reclength);
+ x->sortkey= -1; /* No clustering */
+ /* The following should be included even if we are not compiling with
+ USE_RAID as the client must be able to request it! */
+ x->rec_per_key = share->state.rec_per_key_part;
+ x->raid_type= share->base.raid_type;
+ x->raid_chunks= share->base.raid_chunks;
+ x->raid_chunksize= share->base.raid_chunksize;
+ }
+ if ((flag & HA_STATUS_TIME) && !my_fstat(info->dfile,&state,MYF(0)))
+ x->update_time=state.st_mtime;
+ else
+ x->update_time=0;
+ if (flag & HA_STATUS_AUTO)
+ {
+ x->auto_increment= share->state.auto_increment+1;
+ if (!x->auto_increment) /* This shouldn't happen */
+ x->auto_increment= ~(ulonglong) 0;
+ }
+ DBUG_RETURN(0);
+}
diff --git a/myisam/mi_key.c b/myisam/mi_key.c
new file mode 100644
index 00000000000..f9eb9b77835
--- /dev/null
+++ b/myisam/mi_key.c
@@ -0,0 +1,411 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* Functions to handle keys */
+
+#include "myisamdef.h"
+#include "m_ctype.h"
+
+#define CHECK_KEYS
+
+static int _mi_put_key_in_record(MI_INFO *info,uint keynr,byte *record);
+
+ /*
+ ** Make a intern key from a record
+ ** Ret: Length of key
+ */
+
+uint _mi_make_key(register MI_INFO *info, uint keynr, uchar *key,
+ const byte *record, my_off_t filepos)
+{
+ byte *pos,*end;
+ uchar *start;
+ reg1 MI_KEYSEG *keyseg;
+ DBUG_ENTER("_mi_make_key");
+
+ start=key;
+ for (keyseg=info->s->keyinfo[keynr].seg ; keyseg->type ;keyseg++)
+ {
+ enum ha_base_keytype type=(enum ha_base_keytype) keyseg->type;
+ uint length=keyseg->length;
+
+ if (keyseg->null_bit)
+ {
+ if (record[keyseg->null_pos] & keyseg->null_bit)
+ {
+ *key++= 0; /* NULL in key */
+ continue;
+ }
+ *key++=1; /* Not NULL */
+ }
+
+ pos= (byte*) record+keyseg->start;
+ if (keyseg->flag & HA_SPACE_PACK)
+ {
+ end=pos+length;
+ if (type != HA_KEYTYPE_NUM)
+ {
+ while (end > pos && end[-1] == ' ')
+ end--;
+ }
+ else
+ {
+ while (pos < end && pos[0] == ' ')
+ pos++;
+ }
+ length=(uint) (end-pos);
+ store_key_length_inc(key,length);
+ memcpy((byte*) key,(byte*) pos,(size_t) length);
+ key+=length;
+ continue;
+ }
+ if (keyseg->flag & HA_VAR_LENGTH)
+ {
+ uint tmp_length=uint2korr(pos);
+ pos+=2; /* Skip VARCHAR length */
+ set_if_smaller(length,tmp_length);
+ store_key_length_inc(key,length);
+ }
+ else if (keyseg->flag & HA_BLOB_PART)
+ {
+ uint tmp_length=_mi_calc_blob_length(keyseg->bit_start,pos);
+ memcpy_fixed((byte*) &pos,pos+keyseg->bit_start,sizeof(char*));
+ set_if_smaller(length,tmp_length);
+ store_key_length_inc(key,length);
+ }
+ else if (keyseg->flag & HA_SWAP_KEY)
+ { /* Numerical column */
+#ifdef NAN_TEST
+ float float_nr;
+ double dbl_nr;
+ if (type == HA_KEYTYPE_FLOAT)
+ {
+ float_nr=float4get(pos);
+ if (float_nr == (float) FLT_MAX)
+ {
+ float_nr= (float) FLT_MAX;
+ pos= (byte*) &float_nr;
+ }
+ }
+ else if (type == HA_KEYTYPE_DOUBLE)
+ {
+ dbl_nr=float8get(key);
+ if (dbl_nr == DBL_MAX)
+ {
+ dbl_nr=DBL_MAX;
+ pos=(byte*) &dbl_nr;
+ }
+ }
+#endif
+ pos+=length;
+ while (length--)
+ {
+ *key++ = *--pos;
+ }
+ continue;
+ }
+ memcpy((byte*) key, pos, length);
+ key+= length;
+ }
+ _mi_dpointer(info,key,filepos);
+ DBUG_PRINT("exit",("keynr: %d",keynr));
+ DBUG_DUMP("key",(byte*) start,(uint) (key-start)+keyseg->length);
+ DBUG_EXECUTE("key",
+ _mi_print_key(DBUG_FILE,info->s->keyinfo[keynr].seg,start,
+ (uint) (key-start)););
+ DBUG_RETURN((uint) (key-start)); /* Return keylength */
+} /* _mi_make_key */
+
+
+ /* Pack a key to intern format from given format (c_rkey) */
+ /* returns length of packed key */
+
+uint _mi_pack_key(register MI_INFO *info, uint keynr, uchar *key, uchar *old,
+ uint k_length)
+{
+ uint length;
+ uchar *pos,*end,*start_key=key;
+ reg1 MI_KEYSEG *keyseg;
+ enum ha_base_keytype type;
+ DBUG_ENTER("_mi_pack_key");
+
+ start_key=key;
+ for (keyseg=info->s->keyinfo[keynr].seg ;
+ keyseg->type && (int) k_length > 0;
+ old+=keyseg->length, keyseg++)
+ {
+ length=min((uint) keyseg->length,(uint) k_length);
+ type=(enum ha_base_keytype) keyseg->type;
+ if (keyseg->null_bit)
+ {
+ k_length--;
+ if (!(*key++= (char) 1-*old++)) /* Copy null marker */
+ {
+ k_length-=length;
+ continue; /* Found NULL */
+ }
+ }
+ pos=old;
+ if (keyseg->flag & HA_SPACE_PACK)
+ {
+ end=pos+length;
+ if (type != HA_KEYTYPE_NUM)
+ {
+ while (end > pos && end[-1] == ' ')
+ end--;
+ }
+ else
+ {
+ while (pos < end && pos[0] == ' ')
+ pos++;
+ }
+ k_length-=length;
+ length=(uint) (end-pos);
+ store_key_length_inc(key,length);
+ memcpy((byte*) key,pos,(size_t) length);
+ key+= length;
+ continue;
+ }
+ else if (keyseg->flag & (HA_VAR_LENGTH | HA_BLOB_PART))
+ {
+ uint tmp_length=uint2korr(pos); pos+=2;
+ set_if_smaller(length,tmp_length);
+ store_key_length_inc(key,length);
+ k_length-=2;
+ }
+ else if (keyseg->flag & HA_SWAP_KEY)
+ { /* Numerical column */
+ pos+=length;
+ k_length-=length;
+ while (length--)
+ {
+ *key++ = *--pos;
+ }
+ continue;
+ }
+ memcpy((byte*) key,pos,(size_t) length);
+ key+= length;
+ k_length-=length;
+ }
+
+#ifdef NOT_USED
+ if (keyseg->type)
+ {
+ /* Part-key ; fill with ASCII 0 for easier searching */
+ length= (uint) -k_length; /* unused part of last key */
+ do
+ {
+ if (keyseg->flag & HA_NULL_PART)
+ length++;
+ if (keyseg->flag & HA_SPACE_PACK)
+ length+=2;
+ else
+ length+= keyseg->length;
+ keyseg++;
+ } while (keyseg->type);
+ bzero((byte*) key,length);
+ key+=length;
+ }
+#endif
+ DBUG_RETURN((uint) (key-start_key));
+} /* _mi_pack_key */
+
+
+ /* Put a key in record */
+ /* Used when only-keyread is wanted */
+
+static int _mi_put_key_in_record(register MI_INFO *info, uint keynr,
+ byte *record)
+{
+ reg2 byte *key;
+ byte *pos,*key_end;
+ reg1 MI_KEYSEG *keyseg;
+ byte *blob_ptr;
+ DBUG_ENTER("_mi_put_key_in_record");
+
+ if (info->blobs && info->s->keyinfo[keynr].flag & HA_VAR_LENGTH_KEY)
+ {
+ if (!(blob_ptr=
+ mi_fix_rec_buff_for_blob(info, info->s->keyinfo[keynr].keylength)))
+ goto err;
+ }
+ key=(byte*) info->lastkey;
+ key_end=key+info->lastkey_length;
+ for (keyseg=info->s->keyinfo[keynr].seg ; keyseg->type ;keyseg++)
+ {
+ if (keyseg->null_bit)
+ {
+ if (!*key++)
+ {
+ record[keyseg->null_pos]|= keyseg->null_bit;
+ continue;
+ }
+ record[keyseg->null_pos]&= ~keyseg->null_bit;
+ }
+ if (keyseg->flag & HA_SPACE_PACK)
+ {
+ uint length;
+ get_key_length(length,key);
+#ifdef CHECK_KEYS
+ if (length > keyseg->length || key+length > key_end)
+ goto err;
+#endif
+ pos= record+keyseg->start;
+ if (keyseg->type != (int) HA_KEYTYPE_NUM)
+ {
+ memcpy(pos,key,(size_t) length);
+ bfill(pos+length,keyseg->length-length,' ');
+ }
+ else
+ {
+ bfill(pos,keyseg->length-length,' ');
+ memcpy(pos+keyseg->length-length,key,(size_t) length);
+ }
+ key+=length;
+ continue;
+ }
+
+ if (keyseg->flag & HA_VAR_LENGTH)
+ {
+ uint length;
+ get_key_length(length,key);
+#ifdef CHECK_KEYS
+ if (length >= keyseg->length || key+length > key_end)
+ goto err;
+#endif
+ memcpy(record+keyseg->start,(byte*) key, length);
+ key+= length;
+ }
+ else if (keyseg->flag & HA_BLOB_PART)
+ {
+ uint length;
+ get_key_length(length,key);
+#ifdef CHECK_KEYS
+ if (length >= keyseg->length || key+length > key_end)
+ goto err;
+#endif
+ memcpy(record+keyseg->start+keyseg->bit_start,
+ (char*) &blob_ptr,sizeof(char*));
+ memcpy(blob_ptr,key,length);
+ blob_ptr+=length;
+ _my_store_blob_length(record+keyseg->start,
+ (uint) keyseg->bit_start,length);
+ key+=length;
+ }
+ else if (keyseg->flag & HA_SWAP_KEY)
+ {
+ byte *to= record+keyseg->start+keyseg->length;
+ byte *end= key+keyseg->length;
+#ifdef CHECK_KEYS
+ if (end > key_end)
+ goto err;
+#endif
+ do
+ {
+ *--to= *key++;
+ } while (key != end);
+ continue;
+ }
+ else
+ {
+#ifdef CHECK_KEYS
+ if (key+keyseg->length > key_end)
+ goto err;
+#endif
+ memcpy(record+keyseg->start,(byte*) key,
+ (size_t) keyseg->length);
+ key+= keyseg->length;
+ }
+ }
+ DBUG_RETURN(0);
+
+err:
+ DBUG_RETURN(1); /* Crashed row */
+} /* _mi_put_key_in_record */
+
+
+ /* Here when key reads are used */
+
+int _mi_read_key_record(MI_INFO *info, my_off_t filepos, byte *buf)
+{
+ VOID(_mi_writeinfo(info,0));
+ if (filepos != HA_OFFSET_ERROR)
+ {
+ if (info->lastinx >= 0)
+ { /* Read only key */
+ if (_mi_put_key_in_record(info,(uint) info->lastinx,buf))
+ {
+ my_errno=HA_ERR_CRASHED;
+ return -1;
+ }
+ info->update|= HA_STATE_AKTIV; /* We should find a record */
+ return 0;
+ }
+ my_errno=HA_ERR_WRONG_INDEX;
+ }
+ return(-1); /* Wrong data to read */
+}
+
+
+ /* Update auto_increment info */
+
+void update_auto_increment(MI_INFO *info,const byte *record)
+{
+ ulonglong value;
+ MI_KEYSEG *keyseg=info->s->keyinfo[info->s->base.auto_key-1].seg;
+ const uchar *key=(uchar*) record+keyseg->start;
+
+ switch (keyseg->type) {
+ case HA_KEYTYPE_INT8:
+ case HA_KEYTYPE_BINARY:
+ value=(ulonglong) *(uchar*) key;
+ break;
+ case HA_KEYTYPE_SHORT_INT:
+ case HA_KEYTYPE_USHORT_INT:
+ value=(ulonglong) uint2korr(key);
+ break;
+ case HA_KEYTYPE_LONG_INT:
+ case HA_KEYTYPE_ULONG_INT:
+ value=(ulonglong) uint4korr(key);
+ break;
+ case HA_KEYTYPE_INT24:
+ case HA_KEYTYPE_UINT24:
+ value=(ulonglong) uint3korr(key);
+ break;
+ case HA_KEYTYPE_FLOAT: /* This shouldn't be used */
+ {
+ float f_1;
+ float4get(f_1,key);
+ value = (ulonglong) f_1;
+ break;
+ }
+ case HA_KEYTYPE_DOUBLE: /* This shouldn't be used */
+ {
+ double f_1;
+ float8get(f_1,key);
+ value = (ulonglong) f_1;
+ break;
+ }
+ case HA_KEYTYPE_LONGLONG:
+ case HA_KEYTYPE_ULONGLONG:
+ value= uint8korr(key);
+ break;
+ default:
+ value=0; /* Error */
+ break;
+ }
+ set_if_bigger(info->s->state.auto_increment,value);
+}
diff --git a/myisam/mi_locking.c b/myisam/mi_locking.c
new file mode 100644
index 00000000000..2ef62c23430
--- /dev/null
+++ b/myisam/mi_locking.c
@@ -0,0 +1,456 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/*
+ locking of isam-tables.
+ reads info from a isam-table. Must be first request before doing any furter
+ calls to any isamfunktion. Is used to allow many process use the same
+ isamdatabase.
+ */
+
+#include "myisamdef.h"
+#ifdef __WIN__
+#include <errno.h>
+#endif
+#if !defined(HAVE_PREAD) && defined(THREAD)
+pthread_mutex_t THR_LOCK_keycache;
+#endif
+
+ /* lock table by F_UNLCK, F_RDLCK or F_WRLCK */
+
+int mi_lock_database(MI_INFO *info, int lock_type)
+{
+ int error;
+ uint count;
+ MYISAM_SHARE *share=info->s;
+ uint flag;
+ DBUG_ENTER("mi_lock_database");
+
+ if (share->options & HA_OPTION_READ_ONLY_DATA ||
+ info->lock_type == lock_type)
+ DBUG_RETURN(0);
+ flag=error=0;
+ pthread_mutex_lock(&share->intern_lock);
+ if (share->kfile >= 0) /* May only be false on windows */
+ {
+ switch (lock_type)
+ {
+ case F_UNLCK:
+ if (info->lock_type == F_RDLCK)
+ count= --share->r_locks;
+ else
+ count= --share->w_locks;
+ if (info->lock_type == F_WRLCK && !share->w_locks &&
+ !share->delay_key_write && flush_key_blocks(share->kfile,FLUSH_KEEP))
+ {
+ error=my_errno;
+ mi_mark_crashed(info); /* Mark that table must be checked */
+ }
+ if (info->opt_flag & (READ_CACHE_USED | WRITE_CACHE_USED))
+ {
+ if (end_io_cache(&info->rec_cache))
+ {
+ error=my_errno;
+ mi_mark_crashed(info);
+ }
+ }
+ if (!count)
+ {
+ if (share->changed && !share->w_locks)
+ {
+ share->state.process= share->last_process=share->this_process;
+ share->state.unique= info->last_unique= info->this_unique;
+#ifndef HAVE_PREAD
+ pthread_mutex_lock(&THR_LOCK_keycache); // QQ; Has to be removed!
+#endif
+ if (mi_state_info_write(share->kfile, &share->state, 1))
+ error=my_errno;
+#ifndef HAVE_PREAD
+ pthread_mutex_unlock(&THR_LOCK_keycache);// QQ; Has to be removed!
+#endif
+ share->changed=0;
+ if (myisam_flush)
+ {
+#if defined(__WIN__)
+ if (_commit(share->kfile))
+ error=errno;
+ if (_commit(info->dfile))
+ error=errno;
+#elif defined(HAVE_FDATASYNC)
+ if (fdatasync(share->kfile))
+ error=errno;
+ if (fdatasync(share->dfile))
+ error=errno;
+#elif defined(HAVE_FSYNC)
+ if (fsync(share->kfile))
+ error=errno;
+ if (fsync(share->dfile))
+ error=errno;
+#endif
+ }
+ else
+ share->not_flushed=1;
+ if (error)
+ mi_mark_crashed(info);
+ }
+ if (share->r_locks)
+ { /* Only read locks left */
+ flag=1;
+ if (my_lock(share->kfile,F_RDLCK,0L,F_TO_EOF,
+ MYF(MY_WME | MY_SEEK_NOT_DONE)) && !error)
+ error=my_errno;
+ }
+ else if (!share->w_locks)
+ { /* No more locks */
+ flag=1;
+ if (my_lock(share->kfile,F_UNLCK,0L,F_TO_EOF,
+ MYF(MY_WME | MY_SEEK_NOT_DONE)) && !error)
+ error=my_errno;
+ }
+ }
+ info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
+ info->lock_type= F_UNLCK;
+ break;
+ case F_RDLCK:
+ if (info->lock_type == F_WRLCK)
+ { /* Change RW to READONLY */
+ if (share->w_locks == 1)
+ {
+ flag=1;
+ if (my_lock(share->kfile,lock_type,0L,F_TO_EOF,
+ MYF(MY_SEEK_NOT_DONE)))
+ {
+ error=my_errno;
+ break;
+ }
+ }
+ share->w_locks--;
+ share->r_locks++;
+ info->lock_type=lock_type;
+ break;
+ }
+ if (!share->r_locks && !share->w_locks)
+ {
+ flag=1;
+ if (my_lock(share->kfile,lock_type,0L,F_TO_EOF,
+ info->lock_wait | MY_SEEK_NOT_DONE))
+ {
+ error=my_errno;
+ break;
+ }
+ if (mi_state_info_read_dsk(share->kfile, &share->state, 1))
+ {
+ error=my_errno;
+ VOID(my_lock(share->kfile,F_UNLCK,0L,F_TO_EOF,MYF(MY_SEEK_NOT_DONE)));
+ my_errno=error;
+ break;
+ }
+ }
+ VOID(_mi_test_if_changed(info));
+ share->r_locks++;
+ info->lock_type=lock_type;
+ break;
+ case F_WRLCK:
+ if (info->lock_type == F_RDLCK)
+ { /* Change READONLY to RW */
+ if (share->r_locks == 1)
+ {
+ flag=1;
+ if (my_lock(share->kfile,lock_type,0L,F_TO_EOF,
+ MYF(info->lock_wait | MY_SEEK_NOT_DONE)))
+ {
+ error=my_errno;
+ break;
+ }
+ share->r_locks--;
+ share->w_locks++;
+ info->lock_type=lock_type;
+ break;
+ }
+ }
+ if (!(share->options & HA_OPTION_READ_ONLY_DATA))
+ {
+ if (!share->w_locks)
+ {
+ flag=1;
+ VOID(my_seek(share->kfile,0L,MY_SEEK_SET,MYF(0)));
+ if (my_lock(share->kfile,lock_type,0L,F_TO_EOF,info->lock_wait))
+ {
+ error=my_errno;
+ break;
+ }
+ if (!share->r_locks)
+ {
+ if (mi_state_info_read_dsk(share->kfile, &share->state, 0))
+ {
+ error=my_errno;
+ VOID(my_lock(share->kfile,F_UNLCK,0L,F_TO_EOF,info->lock_wait));
+ my_errno=error;
+ break;
+ }
+ }
+ }
+ }
+ VOID(_mi_test_if_changed(info));
+ info->lock_type=lock_type;
+ share->w_locks++;
+ break;
+ default:
+ break; /* Impossible */
+ }
+ }
+ pthread_mutex_unlock(&share->intern_lock);
+#if defined(FULL_LOG) || defined(_lint)
+ lock_type|=(int) (flag << 8); /* Set bit to set if real lock */
+ myisam_log_command(MI_LOG_LOCK,info,(byte*) &lock_type,sizeof(lock_type),
+ error);
+#endif
+ DBUG_RETURN(error);
+} /* mi_lock_database */
+
+
+/****************************************************************************
+** The following functions are called by thr_lock() in threaded applications
+****************************************************************************/
+
+void mi_get_status(void* param)
+{
+ MI_INFO *info=(MI_INFO*) param;
+ DBUG_ENTER("mi_get_status");
+ DBUG_PRINT("info",("key_file: %ld data_file: %ld",
+ (long) info->s->state.state.key_file_length,
+ (long) info->s->state.state.data_file_length));
+#ifndef DBUG_OFF
+ if (info->state->key_file_length > info->s->state.state.key_file_length ||
+ info->state->data_file_length > info->s->state.state.data_file_length)
+ DBUG_PRINT("warning",("old info: key_file: %ld data_file: %ld",
+ (long) info->state->key_file_length,
+ (long) info->state->data_file_length));
+#endif
+ info->save_state=info->s->state.state;
+ info->state= &info->save_state;
+ DBUG_VOID_RETURN;
+}
+
+void mi_update_status(void* param)
+{
+ MI_INFO *info=(MI_INFO*) param;
+ /*
+ Because someone may have closed the table we point at, we only
+ update the state if its our own state. This isn't a problem as
+ we are always pointing at our own lock or at a read lock.
+ (This is enforced by thr_multi_lock.c)
+ */
+ if (info->state == &info->save_state)
+ {
+#ifndef DBUG_OFF
+ DBUG_PRINT("info",("updating status: key_file: %ld data_file: %ld",
+ (long) info->state->key_file_length,
+ (long) info->state->data_file_length));
+ if (info->state->key_file_length < info->s->state.state.key_file_length ||
+ info->state->data_file_length < info->s->state.state.data_file_length)
+ DBUG_PRINT("warning",("old info: key_file: %ld data_file: %ld",
+ (long) info->s->state.state.key_file_length,
+ (long) info->s->state.state.data_file_length));
+#endif
+ info->s->state.state= *info->state;
+ info->state= &info->s->state.state;
+ }
+
+ /*
+ We have to flush the write cache here as other threads may start
+ reading the table before mi_lock_database() is called
+ */
+ if (info->opt_flag & WRITE_CACHE_USED)
+ {
+ if (end_io_cache(&info->rec_cache))
+ {
+ mi_mark_crashed(info);
+ }
+ info->opt_flag&= ~WRITE_CACHE_USED;
+ }
+}
+
+void mi_copy_status(void* to,void *from)
+{
+ ((MI_INFO*) to)->state= &((MI_INFO*) from)->save_state;
+}
+
+my_bool mi_check_status(void* param)
+{
+ MI_INFO *info=(MI_INFO*) param;
+ return (my_bool) (info->s->state.dellink != HA_OFFSET_ERROR);
+}
+
+
+/****************************************************************************
+ ** functions to read / write the state
+****************************************************************************/
+
+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)
+ {
+ if ((info->tmp_lock_type=lock_type) != F_RDLCK)
+ if (my_lock(share->kfile,lock_type,0L,F_TO_EOF,
+ info->lock_wait | MY_SEEK_NOT_DONE))
+ DBUG_RETURN(1);
+ if (mi_state_info_read_dsk(share->kfile, &share->state, 1))
+ {
+ int error=my_errno ? my_errno : -1;
+ VOID(my_lock(share->kfile,F_UNLCK,0L,F_TO_EOF,
+ MYF(MY_SEEK_NOT_DONE)));
+ my_errno=error;
+ DBUG_RETURN(1);
+ }
+ }
+ if (check_keybuffer)
+ VOID(_mi_test_if_changed(info));
+ }
+ else if (lock_type == F_WRLCK && info->lock_type == F_RDLCK)
+ {
+ my_errno=EACCES; /* Not allowed to change */
+ DBUG_RETURN(-1); /* when have read_lock() */
+ }
+ DBUG_RETURN(0);
+} /* _mi_readinfo */
+
+
+ /* Every isam-function that uppdates the isam-database must! end */
+ /* with this request */
+ /* ARGSUSED */
+
+int _mi_writeinfo(register MI_INFO *info, uint operation)
+{
+ int error,olderror;
+ MYISAM_SHARE *share;
+ DBUG_ENTER("_mi_writeinfo");
+
+ error=0;
+ share=info->s;
+ if (share->r_locks == 0 && share->w_locks == 0)
+ {
+ olderror=my_errno; /* Remember last error */
+ if (operation)
+ { /* Two threads can't be here */
+ share->state.process= share->last_process= share->this_process;
+ share->state.unique= info->last_unique= info->this_unique;
+ if ((error=mi_state_info_write(share->kfile, &share->state, 1)))
+ olderror=my_errno;
+#ifdef __WIN__
+ if (myisam_flush)
+ {
+ _commit(share->kfile);
+ _commit(info->dfile);
+ }
+#endif
+ }
+ if (!(operation & WRITEINFO_NO_UNLOCK) &&
+ my_lock(share->kfile,F_UNLCK,0L,F_TO_EOF,
+ MYF(MY_WME | MY_SEEK_NOT_DONE)) && !error)
+ DBUG_RETURN(1);
+ my_errno=olderror;
+ }
+ else if (operation)
+ {
+ share->changed= 1; /* Mark keyfile changed */
+ }
+ DBUG_RETURN(error);
+} /* _mi_writeinfo */
+
+
+ /* Test if someone has changed the database */
+ /* (Should be called after readinfo) */
+
+int _mi_test_if_changed(register MI_INFO *info)
+{
+ MYISAM_SHARE *share=info->s;
+ if (share->state.process != share->last_process ||
+ share->state.unique != info->last_unique)
+ { /* Keyfile has changed */
+ if (share->state.process != share->this_process)
+ VOID(flush_key_blocks(share->kfile,FLUSH_RELEASE));
+ share->last_process=share->state.process;
+ info->last_unique= share->state.unique;
+ info->update|= HA_STATE_WRITTEN; /* Must use file on next */
+ info->data_changed= 1; /* For mi_is_changed */
+ return 1;
+ }
+ return (!(info->update & HA_STATE_AKTIV) ||
+ (info->update & (HA_STATE_WRITTEN | HA_STATE_DELETED |
+ HA_STATE_KEY_CHANGED)));
+} /* _mi_test_if_changed */
+
+
+/* Put a mark in the .ISM file that someone is updating the table */
+
+int _mi_mark_file_changed(MI_INFO *info)
+{
+ char buff[3];
+ register MYISAM_SHARE *share=info->s;
+ if (!share->state.changed || ! share->global_changed)
+ {
+ share->state.changed|=1;
+ if (!share->global_changed)
+ {
+ 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)));
+ }
+ return 0;
+}
+
+
+/*
+ This is only called by close or by extra(HA_FLUSH) if the OS has the pwrite()
+ call. In these context the following code should be safe!
+ */
+
+int _mi_decrement_open_count(MI_INFO *info)
+{
+ char buff[2];
+ register MYISAM_SHARE *share=info->s;
+ int lock_error=0,write_error=0;
+ if (share->global_changed)
+ {
+ uint old_lock=info->lock_type;
+ share->global_changed=0;
+ lock_error=mi_lock_database(info,F_WRLCK);
+ /* Its not fatal even if we couldn't get the lock ! */
+ if (share->state.open_count > 0)
+ {
+ share->state.open_count--;
+ mi_int2store(buff,share->state.open_count);
+ write_error=my_pwrite(share->kfile,buff,sizeof(buff),
+ sizeof(share->state.header),
+ MYF(MY_NABP));
+ }
+ if (!lock_error)
+ lock_error=mi_lock_database(info,old_lock);
+ }
+ return test(lock_error || write_error);
+}
diff --git a/myisam/mi_log.c b/myisam/mi_log.c
new file mode 100644
index 00000000000..9f08b835d14
--- /dev/null
+++ b/myisam/mi_log.c
@@ -0,0 +1,158 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* Logging of isamcommands and records on logfile */
+
+#include "myisamdef.h"
+#if defined(MSDOS) || defined(__WIN__)
+#include <errno.h>
+#include <fcntl.h>
+#ifndef __WIN__
+#include <process.h>
+#endif
+#endif
+#ifdef VMS
+#include <processes.h>
+#endif
+
+#undef GETPID /* For HPUX */
+#ifdef THREAD
+#define GETPID() (log_type == 1 ? getpid() : (long) my_thread_id());
+#else
+#define GETPID() getpid()
+#endif
+
+ /* Activate logging if flag is 1 and reset logging if flag is 0 */
+
+static int log_type=0;
+
+int mi_log(int activate_log)
+{
+ int error=0;
+ char buff[FN_REFLEN];
+ DBUG_ENTER("mi_log");
+
+ log_type=activate_log;
+ if (activate_log)
+ {
+ if (myisam_log_file < 0)
+ {
+ if ((myisam_log_file = my_create(fn_format(buff,myisam_log_filename,
+ "",".log",4),
+ 0,(O_RDWR | O_BINARY | O_APPEND),MYF(0)))
+ < 0)
+ DBUG_RETURN(my_errno);
+ }
+ }
+ else if (myisam_log_file >= 0)
+ {
+ error=my_close(myisam_log_file,MYF(0)) ? my_errno : 0 ;
+ myisam_log_file= -1;
+ }
+ DBUG_RETURN(error);
+}
+
+
+ /* Logging of records and commands on logfile */
+ /* All logs starts with command(1) dfile(2) process(4) result(2) */
+
+void _myisam_log(enum myisam_log_commands command, MI_INFO *info, const byte *buffert, uint length)
+{
+ char buff[11];
+ int error,old_errno;
+ ulong pid=(ulong) GETPID();
+ old_errno=my_errno;
+ bzero(buff,sizeof(buff));
+ buff[0]=(char) command;
+ mi_int2store(buff+1,info->dfile);
+ mi_int4store(buff+3,pid);
+ mi_int2store(buff+9,length);
+
+ pthread_mutex_lock(&THR_LOCK_myisam);
+ error=my_lock(myisam_log_file,F_WRLCK,0L,F_TO_EOF,MYF(MY_SEEK_NOT_DONE));
+ VOID(my_write(myisam_log_file,buff,sizeof(buff),MYF(0)));
+ VOID(my_write(myisam_log_file,buffert,length,MYF(0)));
+ if (!error)
+ error=my_lock(myisam_log_file,F_UNLCK,0L,F_TO_EOF,MYF(MY_SEEK_NOT_DONE));
+ pthread_mutex_unlock(&THR_LOCK_myisam);
+ my_errno=old_errno;
+}
+
+
+void _myisam_log_command(enum myisam_log_commands command, MI_INFO *info,
+ const byte *buffert, uint length, int result)
+{
+ char buff[9];
+ int error,old_errno;
+ ulong pid=(ulong) GETPID();
+
+ old_errno=my_errno;
+ buff[0]=(char) command;
+ mi_int2store(buff+1,info->dfile);
+ mi_int4store(buff+3,pid);
+ mi_int2store(buff+7,result);
+ pthread_mutex_lock(&THR_LOCK_myisam);
+ error=my_lock(myisam_log_file,F_WRLCK,0L,F_TO_EOF,MYF(MY_SEEK_NOT_DONE));
+ VOID(my_write(myisam_log_file,buff,sizeof(buff),MYF(0)));
+ if (buffert)
+ VOID(my_write(myisam_log_file,buffert,length,MYF(0)));
+ if (!error)
+ error=my_lock(myisam_log_file,F_UNLCK,0L,F_TO_EOF,MYF(MY_SEEK_NOT_DONE));
+ pthread_mutex_unlock(&THR_LOCK_myisam);
+ my_errno=old_errno;
+}
+
+
+void _myisam_log_record(enum myisam_log_commands command, MI_INFO *info,
+ const byte *record, my_off_t filepos, int result)
+{
+ char buff[21],*pos;
+ int error,old_errno;
+ uint length;
+ ulong pid=(ulong) GETPID();
+
+ old_errno=my_errno;
+ if (!info->s->base.blobs)
+ length=info->s->base.reclength;
+ else
+ length=info->s->base.reclength+ _my_calc_total_blob_length(info,record);
+ buff[0]=(char) command;
+ mi_int2store(buff+1,info->dfile);
+ mi_int4store(buff+3,pid);
+ mi_int2store(buff+7,result);
+ mi_sizestore(buff+9,filepos);
+ mi_int4store(buff+17,length);
+ pthread_mutex_lock(&THR_LOCK_myisam);
+ error=my_lock(myisam_log_file,F_WRLCK,0L,F_TO_EOF,MYF(MY_SEEK_NOT_DONE));
+ VOID(my_write(myisam_log_file,buff,sizeof(buff),MYF(0)));
+ VOID(my_write(myisam_log_file,(byte*) record,info->s->base.reclength,MYF(0)));
+ if (info->s->base.blobs)
+ {
+ MI_BLOB *blob,*end;
+
+ for (end=info->blobs+info->s->base.blobs, blob= info->blobs;
+ blob != end ;
+ blob++)
+ {
+ memcpy_fixed(&pos,record+blob->offset+blob->pack_length,sizeof(char*));
+ VOID(my_write(myisam_log_file,pos,blob->length,MYF(0)));
+ }
+ }
+ if (!error)
+ error=my_lock(myisam_log_file,F_UNLCK,0L,F_TO_EOF,MYF(MY_SEEK_NOT_DONE));
+ pthread_mutex_unlock(&THR_LOCK_myisam);
+ my_errno=old_errno;
+}
diff --git a/myisam/mi_open.c b/myisam/mi_open.c
new file mode 100644
index 00000000000..2067e343246
--- /dev/null
+++ b/myisam/mi_open.c
@@ -0,0 +1,994 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* open a isam-database */
+
+#include "fulltext.h"
+#include <m_ctype.h>
+
+#if defined(MSDOS) || defined(__WIN__)
+#ifdef __WIN__
+#include <fcntl.h>
+#else
+#include <process.h> /* Prototype for getpid */
+#endif
+#endif
+#ifdef VMS
+#include "static.c"
+#endif
+
+static void setup_functions(MYISAM_SHARE *info);
+static void setup_key_functions(MI_KEYDEF *keyinfo);
+#define get_next_element(to,pos,size) { memcpy((char*) to,pos,(size_t) size); \
+ pos+=size;}
+
+
+/******************************************************************************
+** Return the shared struct if the table is already open.
+** In MySQL the server will handle version issues.
+******************************************************************************/
+
+static MI_INFO *test_if_reopen(char *filename)
+{
+ LIST *pos;
+
+ for (pos=myisam_open_list ; pos ; pos=pos->next)
+ {
+ MI_INFO *info=(MI_INFO*) pos->data;
+ MYISAM_SHARE *share=info->s;
+ if (!strcmp(share->filename,filename) && share->last_version)
+ return info;
+ }
+ return 0;
+}
+
+
+/******************************************************************************
+ open a isam database.
+ if handle_locking is 0 then exit with error if database is locked
+ if handle_locking is 1 then wait if database is locked
+ if handle_locking is 2 then continue, but count-vars in st_i_info
+ may be wrong. count-vars are automaticly fixed after next isam
+ request.
+******************************************************************************/
+
+
+MI_INFO *mi_open(const char *name, int mode, uint handle_locking)
+{
+ int lock_error,kfile,open_mode,save_errno;
+ uint i,j,len,errpos,head_length,base_pos,offset,info_length,extra,keys,
+ key_parts,unique_key_parts,tmp_length,uniques;
+ char name_buff[FN_REFLEN],*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];
+ my_off_t key_root[MI_MAX_POSSIBLE_KEY],key_del[MI_MAX_KEY_BLOCK_SIZE];
+ ulonglong max_key_file_length, max_data_file_length;
+ DBUG_ENTER("mi_open");
+
+ LINT_INIT(m_info);
+ kfile= -1;
+ lock_error=1;
+ errpos=0;
+ head_length=sizeof(share_buff.state.header);
+ bzero((byte*) &info,sizeof(info));
+
+ VOID(fn_format(name_buff,name,"",MI_NAME_IEXT,4+16+32));
+ pthread_mutex_lock(&THR_LOCK_myisam);
+ if (!(old_info=test_if_reopen(name_buff)))
+ {
+ share= &share_buff;
+ bzero((gptr) &share_buff,sizeof(share_buff));
+ share_buff.state.rec_per_key_part=rec_per_key_part;
+ share_buff.state.key_root=key_root;
+ share_buff.state.key_del=key_del;
+
+ if ((kfile=my_open(name_buff,(open_mode=O_RDWR) | O_SHARE,MYF(0))) < 0)
+ {
+ if ((errno != EROFS && errno != EACCES) ||
+ mode != O_RDONLY ||
+ (kfile=my_open(name_buff,(open_mode=O_RDONLY) | O_SHARE,MYF(0))) < 0)
+ goto err;
+ }
+ errpos=1;
+ if (my_read(kfile,(char*) share->state.header.file_version,head_length,
+ MYF(MY_NABP)))
+ goto err;
+
+ if (memcmp((byte*) share->state.header.file_version,
+ (byte*) myisam_file_magic, 4))
+ {
+ DBUG_PRINT("error",("Wrong header in %s",name_buff));
+ DBUG_DUMP("error_dump",(char*) share->state.header.file_version,
+ head_length);
+ my_errno=HA_ERR_CRASHED;
+ goto err;
+ }
+ share->options= mi_uint2korr(share->state.header.options);
+ if (share->options &
+ ~(HA_OPTION_PACK_RECORD | HA_OPTION_PACK_KEYS |
+ HA_OPTION_COMPRESS_RECORD | HA_OPTION_READ_ONLY_DATA |
+ HA_OPTION_TEMP_COMPRESS_RECORD | HA_OPTION_CHECKSUM |
+ HA_OPTION_TMP_TABLE | HA_OPTION_DELAY_KEY_WRITE))
+ {
+ DBUG_PRINT("error",("wrong options: 0x%lx",
+ share->options));
+ my_errno=HA_ERR_OLD_FILE;
+ goto err;
+ }
+ 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)))
+ {
+ my_errno=ENOMEM;
+ goto err;
+ }
+ errpos=2;
+
+ VOID(my_seek(kfile,0L,MY_SEEK_SET,MYF(0)));
+ if (!(handle_locking & HA_OPEN_TMP_TABLE))
+ {
+ if ((lock_error=my_lock(kfile,F_RDLCK,0L,F_TO_EOF,
+ MYF(handle_locking & HA_OPEN_WAIT_IF_LOCKED ?
+ 0 : MY_DONT_WAIT))) &&
+ !(handle_locking & HA_OPEN_IGNORE_IF_LOCKED))
+ goto err;
+ }
+ errpos=3;
+ if (my_read(kfile,disk_cache,info_length,MYF(MY_NABP)))
+ goto err;
+ len=mi_uint2korr(share->state.header.state_info_length);
+ keys= (uint) share->state.header.keys;
+ uniques= (uint) share->state.header.uniques;
+ key_parts= mi_uint2korr(share->state.header.key_parts);
+ unique_key_parts= mi_uint2korr(share->state.header.unique_key_parts);
+ tmp_length=(MI_STATE_INFO_SIZE + keys * MI_STATE_KEY_SIZE +
+ key_parts*MI_STATE_KEYSEG_SIZE +
+ share->state.header.max_block_size*MI_STATE_KEYBLOCK_SIZE);
+ if (len != MI_STATE_INFO_SIZE)
+ {
+ DBUG_PRINT("warning",
+ ("saved_state_info_length: %d state_info_length: %d",
+ len,MI_STATE_INFO_SIZE));
+ }
+ share->state_diff_length=len-MI_STATE_INFO_SIZE;
+
+ mi_state_info_read(disk_cache, &share->state);
+ len= mi_uint2korr(share->state.header.base_info_length);
+ if (len != MI_BASE_INFO_SIZE)
+ {
+ DBUG_PRINT("warning",("saved_base_info_length: %d base_info_length: %d",
+ len,MI_BASE_INFO_SIZE))
+ }
+ disk_pos=my_n_base_info_read(disk_cache+base_pos, &share->base);
+ share->state.state_length=base_pos;
+
+ /* Correct max_file_length based on length of sizeof_t */
+ max_data_file_length=
+ (share->options & (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)) ?
+ (((ulonglong) 1 << (share->base.rec_reflength*8))-1) :
+ (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,
+ ((ulonglong) 1 << (share->base.key_reflength*8))-1);
+#if SIZEOF_OFF_T == 4
+ set_if_smaller(max_data_file_length, INT_MAX32);
+ set_if_smaller(max_key_file_length, INT_MAX32);
+#endif
+#if USE_RAID && SYSTEM_SIZEOF_OFF_T == 4
+ set_if_smaller(max_key_file_length, INT_MAX32);
+ if (!share->base.raid_type)
+ {
+ set_if_smaller(max_data_file_length, INT_MAX32);
+ }
+ else
+ {
+ set_if_smaller(max_data_file_length,
+ (ulonglong) share->base.raid_chunks << 31);
+ }
+#elif !defined(USE_RAID)
+ if (share->base.raid_type)
+ {
+ my_errno=HA_ERR_UNSUPPORTED;
+ goto err;
+ }
+#endif
+ share->base.max_data_file_length=(my_off_t) max_data_file_length;
+ share->base.max_key_file_length=(my_off_t) max_key_file_length;
+
+ if (share->base.max_key_length > MI_MAX_KEY_BUFF || keys > MI_MAX_KEY ||
+ key_parts >= MI_MAX_KEY * MI_MAX_KEY_SEG)
+ {
+ my_errno=HA_ERR_UNSUPPORTED;
+ goto err;
+ }
+ if (share->options & HA_OPTION_COMPRESS_RECORD)
+ share->base.max_key_length+=2; /* For safety */
+
+ if (!my_multi_malloc(MY_WME,
+ &share,sizeof(*share),
+ &share->state.rec_per_key_part,sizeof(long)*key_parts,
+ &share->keyinfo,keys*sizeof(MI_KEYDEF),
+ &share->uniqueinfo,uniques*sizeof(MI_UNIQUEDEF),
+ &share->keyparts,
+ (key_parts+unique_key_parts+keys+uniques) *
+ sizeof(MI_KEYSEG),
+ &share->rec,
+ (share->base.fields+1)*sizeof(MI_COLUMNDEF),
+ &share->blobs,sizeof(MI_BLOB)*share->base.blobs,
+ &share->filename,strlen(name_buff)+1,
+ &share->state.key_root,keys*sizeof(my_off_t),
+ &share->state.key_del,
+ (share->state.header.max_block_size*sizeof(my_off_t)),
+#ifdef THREAD
+ &share->key_root_lock,sizeof(rw_lock_t)*keys,
+#endif
+ NullS))
+ goto err;
+ errpos=4;
+ *share=share_buff;
+ memcpy((char*) share->state.rec_per_key_part,
+ (char*) rec_per_key_part, sizeof(long)*key_parts);
+ memcpy((char*) share->state.key_root,
+ (char*) key_root, sizeof(my_off_t)*keys);
+ memcpy((char*) share->state.key_del,
+ (char*) key_del, (sizeof(my_off_t) *
+ share->state.header.max_block_size));
+ strmov(share->filename,name_buff);
+
+ share->blocksize=min(IO_SIZE,myisam_block_size);
+ {
+ MI_KEYSEG *pos=share->keyparts;
+ for (i=0 ; i < keys ; i++)
+ {
+ disk_pos=mi_keydef_read(disk_pos, &share->keyinfo[i]);
+ set_if_smaller(share->blocksize,share->keyinfo[i].block_length);
+ share->keyinfo[i].seg=pos;
+ for (j=0 ; j < share->keyinfo[i].keysegs; j++,pos++)
+ {
+ disk_pos=mi_keyseg_read(disk_pos, pos);
+ if (pos->type == HA_KEYTYPE_TEXT || pos->type == HA_KEYTYPE_VARTEXT)
+ {
+ if (!pos->language)
+ pos->charset=default_charset_info;
+ else if (!(pos->charset= get_charset(pos->language, MYF(MY_WME))))
+ {
+ my_errno=HA_ERR_UNKNOWN_CHARSET;
+ goto err;
+ }
+ }
+ }
+ if (share->keyinfo[i].flag & HA_FULLTEXT) /* SerG */
+ share->keyinfo[i].seg=pos-FT_SEGS; /* SerG */
+ share->keyinfo[i].end=pos;
+ pos->type=HA_KEYTYPE_END; /* End */
+ pos->length=share->base.rec_reflength;
+ pos->null_bit=0;
+ pos++;
+ }
+ for (i=0 ; i < uniques ; i++)
+ {
+ disk_pos=mi_uniquedef_read(disk_pos, &share->uniqueinfo[i]);
+ share->uniqueinfo[i].seg=pos;
+ for (j=0 ; j < share->uniqueinfo[i].keysegs; j++,pos++)
+ {
+ disk_pos=mi_keyseg_read(disk_pos, pos);
+ if (pos->type == HA_KEYTYPE_TEXT || pos->type == HA_KEYTYPE_VARTEXT)
+ {
+ if (!pos->language)
+ pos->charset=default_charset_info;
+ else if (!(pos->charset= get_charset(pos->language, MYF(MY_WME))))
+ {
+ my_errno=HA_ERR_UNKNOWN_CHARSET;
+ goto err;
+ }
+ }
+ }
+ share->uniqueinfo[i].end=pos;
+ pos->type=HA_KEYTYPE_END; /* End */
+ pos->null_bit=0;
+ pos++;
+ }
+ }
+ for (i=0 ; i < keys ; i++)
+ setup_key_functions(share->keyinfo+i);
+
+ for (i=j=offset=0 ; i < share->base.fields ; i++)
+ {
+ disk_pos=mi_recinfo_read(disk_pos,&share->rec[i]);
+ share->rec[i].pack_type=0;
+ share->rec[i].huff_tree=0;
+ share->rec[i].offset=offset;
+ if (share->rec[i].type == (int) FIELD_BLOB)
+ {
+ share->blobs[j].pack_length=
+ share->rec[i].length-mi_portable_sizeof_char_ptr;;
+ share->blobs[j].offset=offset;
+ j++;
+ }
+ offset+=share->rec[i].length;
+ }
+ share->rec[i].type=(int) FIELD_LAST; /* End marker */
+
+ if (! lock_error)
+ {
+ VOID(my_lock(kfile,F_UNLCK,0L,F_TO_EOF,MYF(MY_SEEK_NOT_DONE)));
+ lock_error=1; /* Database unlocked */
+ }
+
+#ifdef USE_RAID
+ if (share->base.raid_type)
+ {
+ if ((info.dfile=my_raid_open(fn_format(name_buff,name,"",MI_NAME_DEXT,
+ 2+4),
+ mode | O_SHARE,
+ share->base.raid_type,
+ share->base.raid_chunks,
+ share->base.raid_chunksize,
+ MYF(MY_WME | MY_RAID))) < 0)
+ goto err;
+ }
+ else
+#endif
+ if ((info.dfile=my_open(fn_format(name_buff,name,"",MI_NAME_DEXT,2+4),
+ mode | O_SHARE,
+ MYF(MY_WME))) < 0)
+ goto err;
+ errpos=5;
+
+ share->kfile=kfile;
+ share->mode=open_mode;
+ share->this_process=(ulong) getpid();
+ share->rnd= (int) share->this_process; /* rnd-counter for splits */
+#ifndef DBUG_OFF
+ share->rnd=0; /* To make things repeatable */
+#endif
+ share->last_process= share->state.process;
+ share->base.key_parts=key_parts;
+ share->base.all_key_parts=key_parts+unique_key_parts;
+ if (!(share->last_version=share->state.version))
+ share->last_version=1; /* Safety */
+ share->rec_reflength=share->base.rec_reflength; /* May be changed */
+ share->base.margin_key_file_length=(share->base.max_key_file_length -
+ (keys ? MI_INDEX_BLOCK_MARGIN *
+ share->blocksize * keys : 0));
+ share->blocksize=min(IO_SIZE,myisam_block_size);
+
+ share->data_file_type=STATIC_RECORD;
+ if (share->options & HA_OPTION_COMPRESS_RECORD)
+ {
+ share->data_file_type = COMPRESSED_RECORD;
+ share->options|= HA_OPTION_READ_ONLY_DATA;
+ info.s=share;
+ if (_mi_read_pack_info(&info,
+ (pbool)
+ test(!(share->options &
+ (HA_OPTION_PACK_RECORD |
+ HA_OPTION_TEMP_COMPRESS_RECORD)))))
+ goto err;
+ }
+ else if (share->options & HA_OPTION_PACK_RECORD)
+ share->data_file_type = DYNAMIC_RECORD;
+ my_afree((gptr) disk_cache);
+ setup_functions(share);
+#ifdef THREAD
+ thr_lock_init(&share->lock);
+ VOID(pthread_mutex_init(&share->intern_lock,NULL));
+ for (i=0; i<keys; i++)
+ VOID(my_rwlock_init(&share->key_root_lock[i], NULL));
+ if (!thr_lock_inited)
+ {
+ /* Probably a single threaded program; Don't use concurrent inserts */
+ myisam_concurrent_insert=0;
+ }
+ else if (myisam_concurrent_insert)
+ {
+ share->concurrent_insert=
+ ((share->options & (HA_OPTION_READ_ONLY_DATA | HA_OPTION_TMP_TABLE |
+ HA_OPTION_COMPRESS_RECORD |
+ HA_OPTION_TEMP_COMPRESS_RECORD)) ||
+ (handle_locking & HA_OPEN_TMP_TABLE)) ? 0 : 1;
+ if (share->concurrent_insert)
+ {
+ share->lock.get_status=mi_get_status;
+ share->lock.copy_status=mi_copy_status;
+ share->lock.update_status=mi_update_status;
+ share->lock.check_status=mi_check_status;
+ }
+ }
+#endif
+ }
+ else
+ {
+ share= old_info->s;
+ if (mode == O_RDWR && share->mode == O_RDONLY)
+ {
+ my_errno=EACCES; /* Can't open in write mode */
+ goto err;
+ }
+#ifdef USE_RAID
+ if (share->base.raid_type)
+ {
+ if ((info.dfile=my_raid_open(fn_format(name_buff,old_info->filename,"",
+ MI_NAME_DEXT, 2+4),
+ mode | O_SHARE,
+ share->base.raid_type,
+ share->base.raid_chunks,
+ share->base.raid_chunksize,
+ MYF(MY_WME | MY_RAID))) < 0)
+ goto err;
+ }
+ else
+#endif
+ if ((info.dfile=my_open(fn_format(name_buff,old_info->filename,"",
+ MI_NAME_DEXT,2+4),
+ mode | O_SHARE,MYF(MY_WME))) < 0)
+ {
+ my_errno=errno;
+ goto err;
+ }
+ errpos=5;
+ }
+
+ /* alloc and set up private structure parts */
+ if (!my_multi_malloc(MY_WME,
+ &m_info,sizeof(MI_INFO),
+ &info.blobs,sizeof(MI_BLOB)*share->base.blobs,
+ &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,
+ NullS))
+ goto err;
+ errpos=6;
+
+ strmov(info.filename,name);
+ memcpy(info.blobs,share->blobs,sizeof(MI_BLOB)*share->base.blobs);
+ info.lastkey2=info.lastkey+share->base.max_key_length;
+
+ info.s=share;
+ info.lastpos= HA_OFFSET_ERROR;
+ info.update= (short) (HA_STATE_NEXT_FOUND+HA_STATE_PREV_FOUND);
+ info.opt_flag=READ_CHECK_USED;
+ info.this_unique= (ulong) info.dfile; /* Uniq number in process */
+ if (share->data_file_type == COMPRESSED_RECORD)
+ info.this_unique= share->state.unique;
+ info.this_loop=0; /* Update counter */
+ info.last_unique= share->state.unique;
+ if (mode == O_RDONLY)
+ share->options|=HA_OPTION_READ_ONLY_DATA;
+ info.lock_type=F_UNLCK;
+ info.quick_mode=0;
+ info.errkey= -1;
+ info.page_changed=1;
+ pthread_mutex_lock(&share->intern_lock);
+ info.read_record=share->read_record;
+ share->reopen++;
+ share->write_flag=MYF(MY_NABP | MY_WAIT_IF_FULL);
+ if (share->options & HA_OPTION_READ_ONLY_DATA)
+ {
+ info.lock_type=F_RDLCK;
+ share->r_locks++;
+ }
+ if ((handle_locking & HA_OPEN_TMP_TABLE) ||
+ (share->options & HA_OPTION_TMP_TABLE))
+ {
+ share->temporary=share->delay_key_write=1;
+ share->write_flag=MYF(MY_NABP);
+ share->w_locks++; /* We don't have to update status */
+ info.lock_type=F_WRLCK;
+ }
+ if (((handle_locking & HA_OPEN_DELAY_KEY_WRITE) ||
+ (share->options & HA_OPTION_DELAY_KEY_WRITE)) &&
+ myisam_delay_key_write)
+ share->delay_key_write=1;
+ info.state= &share->state.state; /* Change global values by default */
+ pthread_mutex_unlock(&share->intern_lock);
+
+ /* Allocate buffer for one record */
+
+ extra=0;
+ if (share->options & HA_OPTION_PACK_RECORD)
+ extra=ALIGN_SIZE(MI_MAX_DYN_BLOCK_HEADER)+MI_SPLIT_LENGTH+
+ MI_DYN_DELETE_BLOCK_HEADER;
+
+ tmp_length=max(share->base.pack_reclength,share->base.max_key_length);
+ info.alloced_rec_buff_length=tmp_length;
+ if (!(info.rec_alloc=(byte*) my_malloc(tmp_length+extra+8,
+ MYF(MY_WME | MY_ZEROFILL))))
+ goto err;
+ if (extra)
+ info.rec_buff=info.rec_alloc+ALIGN_SIZE(MI_MAX_DYN_BLOCK_HEADER);
+ else
+ info.rec_buff=info.rec_alloc;
+
+ *m_info=info;
+#ifdef THREAD
+ thr_lock_data_init(&share->lock,&m_info->lock,(void*) m_info);
+#endif
+ m_info->open_list.data=(void*) m_info;
+ myisam_open_list=list_add(myisam_open_list,&m_info->open_list);
+
+ pthread_mutex_unlock(&THR_LOCK_myisam);
+ myisam_log(MI_LOG_OPEN,m_info,share->filename,(uint) strlen(share->filename));
+ DBUG_RETURN(m_info);
+
+err:
+ save_errno=my_errno ? my_errno : HA_ERR_END_OF_FILE;
+ switch (errpos) {
+ case 6:
+ my_free((gptr) m_info,MYF(0));
+ /* fall through */
+ case 5:
+ VOID(my_close(info.dfile,MYF(0)));
+ if (old_info)
+ break; /* Don't remove open table */
+ /* fall through */
+ case 4:
+ my_free((gptr) share,MYF(0));
+ /* fall through */
+ case 3:
+ if (! lock_error)
+ VOID(my_lock(kfile, F_UNLCK, 0L, F_TO_EOF, MYF(MY_SEEK_NOT_DONE)));
+ /* fall through */
+ case 2:
+ my_afree((gptr) disk_cache);
+ /* fall through */
+ case 1:
+ VOID(my_close(kfile,MYF(0)));
+ /* fall through */
+ case 0:
+ default:
+ break;
+ }
+ pthread_mutex_unlock(&THR_LOCK_myisam);
+ my_errno=save_errno;
+ DBUG_RETURN (NULL);
+} /* mi_open */
+
+
+ulonglong mi_safe_mul(ulonglong a, ulonglong b)
+{
+ ulonglong max_val= ~ (ulonglong) 0; /* my_off_t is unsigned */
+
+ if (!a || max_val / a < b)
+ return max_val;
+ return a*b;
+}
+
+ /* Set up functions in structs */
+
+static void setup_functions(register MYISAM_SHARE *share)
+{
+ if (share->options & HA_OPTION_COMPRESS_RECORD)
+ {
+ share->read_record=_mi_read_pack_record;
+ share->read_rnd=_mi_read_rnd_pack_record;
+ if (!(share->options & HA_OPTION_TEMP_COMPRESS_RECORD))
+ share->calc_checksum=0; /* No checksum */
+ else if (share->options & HA_OPTION_PACK_RECORD)
+ share->calc_checksum= mi_checksum;
+ else
+ share->calc_checksum= mi_static_checksum;
+ }
+ else if (share->options & HA_OPTION_PACK_RECORD)
+ {
+ share->read_record=_mi_read_dynamic_record;
+ share->read_rnd=_mi_read_rnd_dynamic_record;
+ share->delete_record=_mi_delete_dynamic_record;
+ share->compare_record=_mi_cmp_dynamic_record;
+ share->compare_unique=_mi_cmp_dynamic_unique;
+ share->calc_checksum= mi_checksum;
+
+ if (share->base.blobs)
+ {
+ share->update_record=_mi_update_blob_record;
+ share->write_record=_mi_write_blob_record;
+ }
+ else
+ {
+ share->write_record=_mi_write_dynamic_record;
+ share->update_record=_mi_update_dynamic_record;
+ }
+ }
+ else
+ {
+ share->read_record=_mi_read_static_record;
+ share->read_rnd=_mi_read_rnd_static_record;
+ share->delete_record=_mi_delete_static_record;
+ share->compare_record=_mi_cmp_static_record;
+ share->update_record=_mi_update_static_record;
+ share->write_record=_mi_write_static_record;
+ share->compare_unique=_mi_cmp_static_unique;
+ share->calc_checksum= mi_static_checksum;
+ }
+ if (!(share->options & HA_OPTION_CHECKSUM))
+ share->calc_checksum=0;
+ return;
+}
+
+
+static void setup_key_functions(register MI_KEYDEF *keyinfo)
+{
+ if (keyinfo->flag & HA_BINARY_PACK_KEY)
+ { /* Simple prefix compression */
+ keyinfo->bin_search=_mi_seq_search;
+ keyinfo->get_key=_mi_get_binary_pack_key;
+ keyinfo->pack_key=_mi_calc_bin_pack_key_length;
+ keyinfo->store_key=_mi_store_bin_pack_key;
+ }
+ 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 */
+ keyinfo->pack_key=_mi_calc_var_pack_key_length;
+ keyinfo->store_key=_mi_store_var_pack_key;
+ }
+ else
+ {
+ keyinfo->pack_key=_mi_calc_var_key_length; /* Variable length key */
+ keyinfo->store_key=_mi_store_static_key;
+ }
+ }
+ else
+ {
+ keyinfo->bin_search=_mi_bin_search;
+ keyinfo->get_key=_mi_get_static_key;
+ keyinfo->pack_key=_mi_calc_static_key_length;
+ keyinfo->store_key=_mi_store_static_key;
+ }
+ return;
+}
+
+
+/***************************************************************************
+** Function to save and store the header in the index file (.MSI)
+***************************************************************************/
+
+uint mi_state_info_write(File file, MI_STATE_INFO *state, uint pWrite)
+{
+ uchar buff[MI_STATE_INFO_SIZE + MI_STATE_EXTRA_SIZE];
+ uchar *ptr=buff;
+ uint i, keys= (uint) state->header.keys,
+ key_blocks=state->header.max_block_size;
+
+ memcpy_fixed(ptr,&state->header,sizeof(state->header));
+ ptr+=sizeof(state->header);
+
+ /* open_count must be first because of _mi_mark_file_changed ! */
+ mi_int2store(ptr,state->open_count); ptr +=2;
+ *ptr++= (uchar)state->changed; *ptr++= state->sortkey;
+ mi_rowstore(ptr,state->state.records); ptr +=8;
+ mi_rowstore(ptr,state->state.del); ptr +=8;
+ mi_rowstore(ptr,state->split); ptr +=8;
+ mi_sizestore(ptr,state->dellink); ptr +=8;
+ mi_sizestore(ptr,state->state.key_file_length); ptr +=8;
+ mi_sizestore(ptr,state->state.data_file_length); ptr +=8;
+ mi_sizestore(ptr,state->state.empty); ptr +=8;
+ mi_sizestore(ptr,state->state.key_empty); ptr +=8;
+ mi_int8store(ptr,state->auto_increment); ptr +=8;
+ mi_int8store(ptr,(ulonglong) state->checksum);ptr +=8;
+ mi_int4store(ptr,state->process); ptr +=4;
+ mi_int4store(ptr,state->unique); ptr +=4;
+ mi_int4store(ptr,state->status); ptr +=4;
+ *ptr++=0; *ptr++=0; *ptr++=0; *ptr++=0; /* extra */
+
+ ptr+=state->state_diff_length;
+
+ for (i=0; i < keys; i++)
+ {
+ mi_sizestore(ptr,state->key_root[i]); ptr +=8;
+ }
+ for (i=0; i < key_blocks; i++)
+ {
+ mi_sizestore(ptr,state->key_del[i]); ptr +=8;
+ }
+ if (pWrite & 2) /* From isamchk */
+ {
+ uint key_parts= mi_uint2korr(state->header.key_parts);
+ mi_int4store(ptr,state->sec_index_changed); ptr +=4;
+ mi_int4store(ptr,state->sec_index_used); ptr +=4;
+ mi_int4store(ptr,state->version); ptr +=4;
+ mi_int8store(ptr,state->key_map); ptr +=8;
+ mi_int8store(ptr,(ulonglong) state->create_time); ptr +=8;
+ mi_int8store(ptr,(ulonglong) state->recover_time); ptr +=8;
+ mi_int8store(ptr,(ulonglong) state->check_time); ptr +=8;
+ mi_sizestore(ptr,state->rec_per_key_rows); ptr+=8;
+ for (i=0 ; i < key_parts ; i++)
+ {
+ mi_int4store(ptr,state->rec_per_key_part[i]); ptr+=4;
+ }
+ }
+
+ if (pWrite & 1)
+ return my_pwrite(file,(char*) buff, (uint) (ptr-buff), 0L,
+ MYF(MY_NABP | MY_THREADSAFE));
+ else
+ return my_write(file, (char*) buff, (uint) (ptr-buff), MYF(MY_NABP));
+}
+
+
+char *mi_state_info_read(char *ptr, MI_STATE_INFO *state)
+{
+ uint i,keys,key_parts,key_blocks;
+ memcpy_fixed(&state->header,ptr, sizeof(state->header));
+ ptr +=sizeof(state->header);
+ keys=(uint) state->header.keys;
+ key_parts=mi_uint2korr(state->header.key_parts);
+ key_blocks=state->header.max_block_size;
+
+ state->open_count = mi_uint2korr(ptr); ptr +=2;
+ state->changed= (bool) *ptr++;
+ state->sortkey = (uint) *ptr++;
+ state->state.records= mi_rowkorr(ptr); ptr +=8;
+ state->state.del = mi_rowkorr(ptr); ptr +=8;
+ state->split = mi_rowkorr(ptr); ptr +=8;
+ state->dellink= mi_sizekorr(ptr); ptr +=8;
+ state->state.key_file_length = mi_sizekorr(ptr); ptr +=8;
+ state->state.data_file_length= mi_sizekorr(ptr); ptr +=8;
+ state->state.empty = mi_sizekorr(ptr); ptr +=8;
+ state->state.key_empty= mi_sizekorr(ptr); ptr +=8;
+ state->auto_increment=mi_uint8korr(ptr); ptr +=8;
+ state->checksum=(ha_checksum) mi_uint8korr(ptr); ptr +=8;
+ state->process= mi_uint4korr(ptr); ptr +=4;
+ state->unique = mi_uint4korr(ptr); ptr +=4;
+ state->status = mi_uint4korr(ptr); ptr +=4;
+ ptr +=4; /* extra */
+ for (i=0; i < keys; i++)
+ {
+ state->key_root[i]= mi_sizekorr(ptr); ptr +=8;
+ }
+ for (i=0; i < key_blocks; i++)
+ {
+ state->key_del[i] = mi_sizekorr(ptr); ptr +=8;
+ }
+ ptr+= state->state_diff_length;
+ state->sec_index_changed = mi_uint4korr(ptr); ptr +=4;
+ state->sec_index_used = mi_uint4korr(ptr); ptr +=4;
+ state->version = mi_uint4korr(ptr); ptr +=4;
+ state->key_map = mi_uint8korr(ptr); ptr +=8;
+ state->create_time = (time_t) mi_sizekorr(ptr); ptr +=8;
+ state->recover_time =(time_t) mi_sizekorr(ptr); ptr +=8;
+ state->check_time = (time_t) mi_sizekorr(ptr); ptr +=8;
+ state->rec_per_key_rows=mi_sizekorr(ptr); ptr +=8;
+ for (i=0 ; i < key_parts ; i++)
+ {
+ state->rec_per_key_part[i]= mi_uint4korr(ptr); ptr+=4;
+ }
+ return ptr;
+}
+
+
+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 (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);
+ return 0;
+}
+
+
+/****************************************************************************
+** store and read of MI_BASE_INFO
+****************************************************************************/
+
+uint mi_base_info_write(File file, MI_BASE_INFO *base)
+{
+ uchar buff[MI_BASE_INFO_SIZE], *ptr=buff;
+
+ mi_sizestore(ptr,base->keystart); ptr +=8;
+ mi_sizestore(ptr,base->max_data_file_length); ptr +=8;
+ mi_sizestore(ptr,base->max_key_file_length); ptr +=8;
+ mi_rowstore(ptr,base->records); ptr +=8;
+ mi_rowstore(ptr,base->reloc); ptr +=8;
+ mi_int4store(ptr,base->mean_row_length); ptr +=4;
+ mi_int4store(ptr,base->reclength); ptr +=4;
+ mi_int4store(ptr,base->pack_reclength); ptr +=4;
+ mi_int4store(ptr,base->min_pack_length); ptr +=4;
+ mi_int4store(ptr,base->max_pack_length); ptr +=4;
+ mi_int4store(ptr,base->min_block_length); ptr +=4;
+ mi_int4store(ptr,base->fields); ptr +=4;
+ mi_int4store(ptr,base->pack_fields); ptr +=4;
+ *ptr++=base->rec_reflength;
+ *ptr++=base->key_reflength;
+ *ptr++=base->keys;
+ *ptr++=base->auto_key;
+ mi_int2store(ptr,base->pack_bits); ptr +=2;
+ mi_int2store(ptr,base->blobs); ptr +=2;
+ mi_int2store(ptr,base->max_key_block_length); ptr +=2;
+ mi_int2store(ptr,base->max_key_length); ptr +=2;
+ mi_int2store(ptr,base->extra_alloc_bytes); ptr +=2;
+ *ptr++= base->extra_alloc_procent;
+ *ptr++= base->raid_type;
+ mi_int2store(ptr,base->raid_chunks); ptr +=2;
+ mi_int4store(ptr,base->raid_chunksize); ptr +=4;
+ bzero(ptr,6); ptr +=6; /* extra */
+ return my_write(file,(char*) buff, (uint) (ptr-buff), MYF(MY_NABP));
+}
+
+
+char *my_n_base_info_read(char *ptr, MI_BASE_INFO *base)
+{
+ base->keystart = mi_sizekorr(ptr); ptr +=8;
+ base->max_data_file_length = mi_sizekorr(ptr); ptr +=8;
+ base->max_key_file_length = mi_sizekorr(ptr); ptr +=8;
+ base->records = (ha_rows) mi_sizekorr(ptr); ptr +=8;
+ base->reloc = (ha_rows) mi_sizekorr(ptr); ptr +=8;
+ base->mean_row_length = mi_uint4korr(ptr); ptr +=4;
+ base->reclength = mi_uint4korr(ptr); ptr +=4;
+ base->pack_reclength = mi_uint4korr(ptr); ptr +=4;
+ base->min_pack_length = mi_uint4korr(ptr); ptr +=4;
+ base->max_pack_length = mi_uint4korr(ptr); ptr +=4;
+ base->min_block_length = mi_uint4korr(ptr); ptr +=4;
+ base->fields = mi_uint4korr(ptr); ptr +=4;
+ base->pack_fields = mi_uint4korr(ptr); ptr +=4;
+
+ base->rec_reflength = *ptr++;
+ base->key_reflength = *ptr++;
+ base->keys= *ptr++;
+ base->auto_key= *ptr++;
+ base->pack_bits = mi_uint2korr(ptr); ptr +=2;
+ base->blobs = mi_uint2korr(ptr); ptr +=2;
+ base->max_key_block_length= mi_uint2korr(ptr); ptr +=2;
+ base->max_key_length = mi_uint2korr(ptr); ptr +=2;
+ base->extra_alloc_bytes = mi_uint2korr(ptr); ptr +=2;
+ base->extra_alloc_procent = *ptr++;
+ base->raid_type= *ptr++;
+ base->raid_chunks= mi_uint2korr(ptr); ptr +=2;
+ base->raid_chunksize= mi_uint4korr(ptr); ptr +=4;
+ /* TO BE REMOVED: Fix for old RAID files */
+ if (base->raid_type == 0)
+ {
+ base->raid_chunks=0;
+ base->raid_chunksize=0;
+ }
+
+ ptr+=6;
+ return ptr;
+}
+
+/*--------------------------------------------------------------------------
+ mi_keydef
+---------------------------------------------------------------------------*/
+
+uint mi_keydef_write(File file, MI_KEYDEF *keydef)
+{
+ uchar buff[MI_KEYDEF_SIZE];
+ uchar *ptr=buff;
+
+ *ptr++ = (uchar) keydef->keysegs;
+ *ptr++ = 0; /* not used */
+ mi_int2store(ptr,keydef->flag); ptr +=2;
+ mi_int2store(ptr,keydef->block_length); ptr +=2;
+ mi_int2store(ptr,keydef->keylength); ptr +=2;
+ mi_int2store(ptr,keydef->minlength); ptr +=2;
+ mi_int2store(ptr,keydef->maxlength); ptr +=2;
+ return my_write(file,(char*) buff, (uint) (ptr-buff), MYF(MY_NABP));
+}
+
+char *mi_keydef_read(char *ptr, MI_KEYDEF *keydef)
+{
+ keydef->keysegs = (uint) *ptr++;
+ ptr++;
+ keydef->flag = mi_uint2korr(ptr); ptr +=2;
+ keydef->block_length = mi_uint2korr(ptr); ptr +=2;
+ 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->underflow_block_length=keydef->block_length/3;
+ keydef->version = 0; /* Not saved */
+ return ptr;
+}
+
+/***************************************************************************
+** mi_keyseg
+***************************************************************************/
+
+int mi_keyseg_write(File file, const MI_KEYSEG *keyseg)
+{
+ uchar buff[MI_KEYSEG_SIZE];
+ uchar *ptr=buff;
+
+ *ptr++ =keyseg->type;
+ *ptr++ =keyseg->language;
+ *ptr++ =keyseg->null_bit;
+ *ptr++ =keyseg->bit_start;
+ *ptr++ =keyseg->bit_end;
+ *ptr++ =0; /* Not used */
+ mi_int2store(ptr,keyseg->flag); ptr+=2;
+ mi_int2store(ptr,keyseg->length); ptr+=2;
+ mi_int4store(ptr,keyseg->start); ptr+=4;
+ mi_int4store(ptr,keyseg->null_pos); ptr+=4;
+
+ return my_write(file,(char*) buff, (uint) (ptr-buff), MYF(MY_NABP));
+}
+
+
+char *mi_keyseg_read(char *ptr, MI_KEYSEG *keyseg)
+{
+ keyseg->type = *ptr++;
+ keyseg->language = *ptr++;
+ keyseg->null_bit = *ptr++;
+ keyseg->bit_start = *ptr++;
+ keyseg->bit_end = *ptr++;
+ ptr++;
+ keyseg->flag = mi_uint2korr(ptr); ptr +=2;
+ keyseg->length = mi_uint2korr(ptr); ptr +=2;
+ keyseg->start = mi_uint4korr(ptr); ptr +=4;
+ keyseg->null_pos = mi_uint4korr(ptr); ptr +=4;
+ keyseg->charset=0; /* Will be filled in later */
+ return ptr;
+}
+
+/*--------------------------------------------------------------------------
+ mi_uniquedef
+---------------------------------------------------------------------------*/
+
+uint mi_uniquedef_write(File file, MI_UNIQUEDEF *def)
+{
+ uchar buff[MI_UNIQUEDEF_SIZE];
+ uchar *ptr=buff;
+
+ mi_int2store(ptr,def->keysegs); ptr+=2;
+ *ptr++= (uchar) def->key;
+ *ptr++ = (uchar) def->null_are_equal;
+
+ return my_write(file,(char*) buff, (uint) (ptr-buff), MYF(MY_NABP));
+}
+
+char *mi_uniquedef_read(char *ptr, MI_UNIQUEDEF *def)
+{
+ def->keysegs = mi_uint2korr(ptr);
+ def->key = ptr[2];
+ def->null_are_equal=ptr[3];
+ return ptr+4; /* 1 extra byte */
+}
+
+/***************************************************************************
+** MI_COLUMNDEF
+***************************************************************************/
+
+uint mi_recinfo_write(File file, MI_COLUMNDEF *recinfo)
+{
+ uchar buff[MI_COLUMNDEF_SIZE];
+ uchar *ptr=buff;
+
+ mi_int2store(ptr,recinfo->type); ptr +=2;
+ mi_int2store(ptr,recinfo->length); ptr +=2;
+ *ptr++ = recinfo->null_bit;
+ mi_int2store(ptr,recinfo->null_pos); ptr+= 2;
+ return my_write(file,(char*) buff, (uint) (ptr-buff), MYF(MY_NABP));
+}
+
+char *mi_recinfo_read(char *ptr, MI_COLUMNDEF *recinfo)
+{
+ recinfo->type= mi_sint2korr(ptr); ptr +=2;
+ recinfo->length=mi_uint2korr(ptr); ptr +=2;
+ recinfo->null_bit= (uint8) *ptr++;
+ recinfo->null_pos=mi_uint2korr(ptr); ptr +=2;
+ return ptr;
+}
diff --git a/myisam/mi_packrec.c b/myisam/mi_packrec.c
new file mode 100644
index 00000000000..b6a9435ee3d
--- /dev/null
+++ b/myisam/mi_packrec.c
@@ -0,0 +1,1312 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+ /* Functions to compressed records */
+
+#include "myisamdef.h"
+
+#define IS_CHAR ((uint) 32768) /* Bit if char (not offset) in tree */
+
+#if INT_MAX > 65536L
+#define BITS_SAVED 32
+#define MAX_QUICK_TABLE_BITS 9 /* Because we may shift in 24 bits */
+#else
+#define BITS_SAVED 16
+#define MAX_QUICK_TABLE_BITS 6
+#endif
+
+#define get_bit(BU) ((BU)->bits ? \
+ (BU)->current_byte & ((mi_bit_type) 1 << --(BU)->bits) :\
+ (fill_buffer(BU), (BU)->bits= BITS_SAVED-1,\
+ (BU)->current_byte & ((mi_bit_type) 1 << (BITS_SAVED-1))))
+#define skipp_to_next_byte(BU) ((BU)->bits&=~7)
+#define get_bits(BU,count) (((BU)->bits >= count) ? (((BU)->current_byte >> ((BU)->bits-=count)) & mask[count]) : fill_and_get_bits(BU,count))
+
+#define decode_bytes_test_bit(bit) \
+ if (low_byte & (1 << (7-bit))) \
+ pos++; \
+ if (*pos & IS_CHAR) \
+ { bits-=(bit+1); break; } \
+ pos+= *pos
+
+
+static void read_huff_table(MI_BIT_BUFF *bit_buff,MI_DECODE_TREE *decode_tree,
+ uint16 **decode_table,byte **intervall_buff,
+ uint16 *tmp_buff);
+static void make_quick_table(uint16 *to_table,uint16 *decode_table,
+ uint *next_free,uint value,uint bits,
+ uint max_bits);
+static void fill_quick_table(uint16 *table,uint bits, uint max_bits,
+ uint value);
+static uint copy_decode_table(uint16 *to_pos,uint offset,
+ uint16 *decode_table);
+static uint find_longest_bitstream(uint16 *table);
+static void (*get_unpack_function(MI_COLUMNDEF *rec))(MI_COLUMNDEF *field,
+ MI_BIT_BUFF *buff,
+ uchar *to,
+ uchar *end);
+static void uf_zerofill_skipp_zero(MI_COLUMNDEF *rec,MI_BIT_BUFF *bit_buff,
+ uchar *to,uchar *end);
+static void uf_skipp_zero(MI_COLUMNDEF *rec,MI_BIT_BUFF *bit_buff,
+ uchar *to,uchar *end);
+static void uf_space_normal(MI_COLUMNDEF *rec,MI_BIT_BUFF *bit_buff,
+ uchar *to,uchar *end);
+static void uf_space_endspace_selected(MI_COLUMNDEF *rec,MI_BIT_BUFF *bit_buff,
+ uchar *to, uchar *end);
+static void uf_endspace_selected(MI_COLUMNDEF *rec,MI_BIT_BUFF *bit_buff,
+ uchar *to,uchar *end);
+static void uf_space_endspace(MI_COLUMNDEF *rec,MI_BIT_BUFF *bit_buff,
+ uchar *to,uchar *end);
+static void uf_endspace(MI_COLUMNDEF *rec,MI_BIT_BUFF *bit_buff,
+ uchar *to,uchar *end);
+static void uf_space_prespace_selected(MI_COLUMNDEF *rec,MI_BIT_BUFF *bit_buff,
+ uchar *to, uchar *end);
+static void uf_prespace_selected(MI_COLUMNDEF *rec,MI_BIT_BUFF *bit_buff,
+ uchar *to,uchar *end);
+static void uf_space_prespace(MI_COLUMNDEF *rec,MI_BIT_BUFF *bit_buff,
+ uchar *to,uchar *end);
+static void uf_prespace(MI_COLUMNDEF *rec,MI_BIT_BUFF *bit_buff,
+ uchar *to,uchar *end);
+static void uf_zerofill_normal(MI_COLUMNDEF *rec,MI_BIT_BUFF *bit_buff,
+ uchar *to,uchar *end);
+static void uf_constant(MI_COLUMNDEF *rec,MI_BIT_BUFF *bit_buff,
+ uchar *to,uchar *end);
+static void uf_intervall(MI_COLUMNDEF *rec,MI_BIT_BUFF *bit_buff,
+ uchar *to,uchar *end);
+static void uf_zero(MI_COLUMNDEF *rec,MI_BIT_BUFF *bit_buff,
+ uchar *to,uchar *end);
+static void uf_blob(MI_COLUMNDEF *rec, MI_BIT_BUFF *bit_buff,
+ uchar *to, uchar *end);
+static void uf_varchar(MI_COLUMNDEF *rec, MI_BIT_BUFF *bit_buff,
+ uchar *to, uchar *end);
+static void decode_bytes(MI_COLUMNDEF *rec,MI_BIT_BUFF *bit_buff,
+ uchar *to,uchar *end);
+static uint decode_pos(MI_BIT_BUFF *bit_buff,MI_DECODE_TREE *decode_tree);
+static void init_bit_buffer(MI_BIT_BUFF *bit_buff,uchar *buffer,uint length);
+static uint fill_and_get_bits(MI_BIT_BUFF *bit_buff,uint count);
+static void fill_buffer(MI_BIT_BUFF *bit_buff);
+static uint max_bit(uint value);
+#ifdef HAVE_MMAP
+static uchar *_mi_mempack_get_block_info(MI_INFO *myisam,MI_BLOCK_INFO *info,
+ uchar *header);
+#endif
+
+static mi_bit_type mask[]=
+{
+ 0x00000000,
+ 0x00000001, 0x00000003, 0x00000007, 0x0000000f,
+ 0x0000001f, 0x0000003f, 0x0000007f, 0x000000ff,
+ 0x000001ff, 0x000003ff, 0x000007ff, 0x00000fff,
+ 0x00001fff, 0x00003fff, 0x00007fff, 0x0000ffff,
+#if BITS_SAVED > 16
+ 0x0001ffff, 0x0003ffff, 0x0007ffff, 0x000fffff,
+ 0x001fffff, 0x003fffff, 0x007fffff, 0x00ffffff,
+ 0x01ffffff, 0x03ffffff, 0x07ffffff, 0x0fffffff,
+ 0x1fffffff, 0x3fffffff, 0x7fffffff, 0xffffffff,
+#endif
+ };
+
+
+ /* Read all packed info, allocate memory and fix field structs */
+
+my_bool _mi_read_pack_info(MI_INFO *info, pbool fix_keys)
+{
+ File file;
+ int diff_length;
+ uint i,trees,huff_tree_bits,rec_reflength,length;
+ uint16 *decode_table,*tmp_buff;
+ ulong elements,intervall_length;
+ char *disk_cache,*intervall_buff;
+ uchar header[32];
+ MYISAM_SHARE *share=info->s;
+ MI_BIT_BUFF bit_buff;
+ DBUG_ENTER("_mi_read_pack_info");
+
+ if (myisam_quick_table_bits < 4)
+ myisam_quick_table_bits=4;
+ else if (myisam_quick_table_bits > MAX_QUICK_TABLE_BITS)
+ myisam_quick_table_bits=MAX_QUICK_TABLE_BITS;
+
+ file=info->dfile;
+ my_errno=0;
+ if (my_read(file,(byte*) header,sizeof(header),MYF(MY_NABP)))
+ {
+ if (!my_errno)
+ my_errno=HA_ERR_END_OF_FILE;
+ DBUG_RETURN(1);
+ }
+ if (memcmp((byte*) header,(byte*) myisam_pack_file_magic,4))
+ {
+ my_errno=HA_ERR_WRONG_IN_RECORD;
+ DBUG_RETURN(1);
+ }
+ share->pack.header_length= uint4korr(header+4);
+ share->min_pack_length=(uint) uint4korr(header+8);
+ share->max_pack_length=(uint) uint4korr(header+12);
+ set_if_bigger(share->base.pack_reclength,share->max_pack_length);
+ elements=uint4korr(header+16);
+ intervall_length=uint4korr(header+20);
+ trees=uint2korr(header+24);
+ share->pack.ref_length=header[26];
+ rec_reflength=header[27];
+ diff_length=(int) rec_reflength - (int) share->base.rec_reflength;
+ if (fix_keys)
+ share->rec_reflength=rec_reflength;
+ share->base.min_block_length=share->min_pack_length+share->pack.ref_length;
+
+ if (!(share->decode_trees=(MI_DECODE_TREE*)
+ my_malloc((uint) (trees*sizeof(MI_DECODE_TREE)+
+ intervall_length*sizeof(byte)),
+ MYF(MY_WME))))
+ DBUG_RETURN(1);
+ intervall_buff=(byte*) (share->decode_trees+trees);
+
+ length=(uint) (elements*2+trees*(1 << myisam_quick_table_bits));
+ if (!(share->decode_tables=(uint16*)
+ my_malloc((length+512)*sizeof(uint16)+
+ (uint) (share->pack.header_length+7),
+ MYF(MY_WME | MY_ZEROFILL))))
+ {
+ my_free((gptr) share->decode_trees,MYF(0));
+ DBUG_RETURN(1);
+ }
+ tmp_buff=share->decode_tables+length;
+ disk_cache=(byte*) (tmp_buff+512);
+
+ if (my_read(file,disk_cache,
+ (uint) (share->pack.header_length-sizeof(header)),
+ MYF(MY_NABP)))
+ {
+ my_free((gptr) share->decode_trees,MYF(0));
+ my_free((gptr) share->decode_tables,MYF(0));
+ DBUG_RETURN(1);
+ }
+
+ huff_tree_bits=max_bit(trees ? trees-1 : 0);
+ init_bit_buffer(&bit_buff, (uchar*) disk_cache,
+ (uint) (share->pack.header_length-sizeof(header)));
+ /* Read new info for each field */
+ for (i=0 ; i < share->base.fields ; i++)
+ {
+ share->rec[i].base_type=(enum en_fieldtype) get_bits(&bit_buff,5);
+ share->rec[i].pack_type=(uint) get_bits(&bit_buff,6);
+ share->rec[i].space_length_bits=get_bits(&bit_buff,5);
+ share->rec[i].huff_tree=share->decode_trees+(uint) get_bits(&bit_buff,
+ huff_tree_bits);
+ share->rec[i].unpack=get_unpack_function(share->rec+i);
+ }
+ skipp_to_next_byte(&bit_buff);
+ decode_table=share->decode_tables;
+ for (i=0 ; i < trees ; i++)
+ read_huff_table(&bit_buff,share->decode_trees+i,&decode_table,
+ &intervall_buff,tmp_buff);
+ decode_table=(uint16*)
+ my_realloc((gptr) share->decode_tables,
+ (uint) ((byte*) decode_table - (byte*) share->decode_tables),
+ MYF(MY_HOLD_ON_ERROR));
+ {
+ long diff=PTR_BYTE_DIFF(decode_table,share->decode_tables);
+ share->decode_tables=decode_table;
+ for (i=0 ; i < trees ; i++)
+ share->decode_trees[i].table=ADD_TO_PTR(share->decode_trees[i].table,
+ diff,
+ uint16*);
+ }
+
+ /* Fix record-ref-length for keys */
+ if (fix_keys)
+ {
+ for (i=0 ; i < share->base.keys ; i++)
+ {
+ share->keyinfo[i].keylength+=(uint16) diff_length;
+ share->keyinfo[i].minlength+=(uint16) diff_length;
+ share->keyinfo[i].maxlength+=(uint16) diff_length;
+ share->keyinfo[i].seg[share->keyinfo[i].keysegs].length=
+ (uint16) rec_reflength;
+ }
+ }
+
+ if (bit_buff.error || bit_buff.pos < bit_buff.end)
+ { /* info_length was wrong */
+ my_errno=HA_ERR_WRONG_IN_RECORD;
+ my_free((gptr) share->decode_trees,MYF(0));
+ my_free((gptr) share->decode_tables,MYF(0));
+ DBUG_RETURN(1);
+ }
+ DBUG_RETURN(0);
+}
+
+
+ /* Read on huff-code-table from datafile */
+
+static void read_huff_table(MI_BIT_BUFF *bit_buff, MI_DECODE_TREE *decode_tree,
+ uint16 **decode_table, byte **intervall_buff,
+ uint16 *tmp_buff)
+{
+ uint min_chr,elements,char_bits,offset_bits,size,intervall_length,table_bits,
+ next_free_offset;
+ uint16 *ptr,*end;
+
+ LINT_INIT(ptr);
+ if (!get_bits(bit_buff,1))
+ {
+ min_chr=get_bits(bit_buff,8);
+ elements=get_bits(bit_buff,9);
+ char_bits=get_bits(bit_buff,5);
+ offset_bits=get_bits(bit_buff,5);
+ intervall_length=0;
+ ptr=tmp_buff;
+ }
+ else
+ {
+ min_chr=0;
+ elements=get_bits(bit_buff,15);
+ intervall_length=get_bits(bit_buff,16);
+ char_bits=get_bits(bit_buff,5);
+ offset_bits=get_bits(bit_buff,5);
+ decode_tree->quick_table_bits=0;
+ ptr= *decode_table;
+ }
+ size=elements*2-2;
+
+ for (end=ptr+size ; ptr < end ; ptr++)
+ {
+ if (get_bit(bit_buff))
+ *ptr= (uint16) get_bits(bit_buff,offset_bits);
+ else
+ *ptr= (uint16) (IS_CHAR + (get_bits(bit_buff,char_bits) + min_chr));
+ }
+ skipp_to_next_byte(bit_buff);
+
+ decode_tree->table= *decode_table;
+ decode_tree->intervalls= *intervall_buff;
+ if (! intervall_length)
+ {
+ table_bits=find_longest_bitstream(tmp_buff);
+ if (table_bits > myisam_quick_table_bits)
+ table_bits=myisam_quick_table_bits;
+ next_free_offset= (1 << table_bits);
+ make_quick_table(*decode_table,tmp_buff,&next_free_offset,0,table_bits,
+ table_bits);
+ (*decode_table)+= next_free_offset;
+ decode_tree->quick_table_bits=table_bits;
+ }
+ else
+ {
+ (*decode_table)=end;
+ bit_buff->pos-= bit_buff->bits/8;
+ memcpy(*intervall_buff,bit_buff->pos,(size_t) intervall_length);
+ (*intervall_buff)+=intervall_length;
+ bit_buff->pos+=intervall_length;
+ bit_buff->bits=0;
+ }
+ return;
+}
+
+
+static void make_quick_table(uint16 *to_table, uint16 *decode_table,
+ uint *next_free_offset, uint value, uint bits,
+ uint max_bits)
+{
+ if (!bits--)
+ {
+ to_table[value]= (uint16) *next_free_offset;
+ *next_free_offset=copy_decode_table(to_table, *next_free_offset,
+ decode_table);
+ return;
+ }
+ if (!(*decode_table & IS_CHAR))
+ {
+ make_quick_table(to_table,decode_table+ *decode_table,
+ next_free_offset,value,bits,max_bits);
+ }
+ else
+ fill_quick_table(to_table+value,bits,max_bits,(uint) *decode_table);
+ decode_table++;
+ value|= (1 << bits);
+ if (!(*decode_table & IS_CHAR))
+ {
+ make_quick_table(to_table,decode_table+ *decode_table,
+ next_free_offset,value,bits,max_bits);
+ }
+ else
+ fill_quick_table(to_table+value,bits,max_bits,(uint) *decode_table);
+ return;
+}
+
+
+static void fill_quick_table(uint16 *table, uint bits, uint max_bits,
+ uint value)
+{
+ uint16 *end;
+ value|=(max_bits-bits) << 8;
+ for (end=table+ (1 << bits) ;
+ table < end ;
+ *table++ = (uint16) value | IS_CHAR) ;
+}
+
+
+static uint copy_decode_table(uint16 *to_pos, uint offset,
+ uint16 *decode_table)
+{
+ uint prev_offset;
+ prev_offset= offset;
+
+ if (!(*decode_table & IS_CHAR))
+ {
+ to_pos[offset]=2;
+ offset=copy_decode_table(to_pos,offset+2,decode_table+ *decode_table);
+ }
+ else
+ {
+ to_pos[offset]= *decode_table;
+ offset+=2;
+ }
+ decode_table++;
+
+ if (!(*decode_table & IS_CHAR))
+ {
+ to_pos[prev_offset+1]=(uint16) (offset-prev_offset-1);
+ offset=copy_decode_table(to_pos,offset,decode_table+ *decode_table);
+ }
+ else
+ to_pos[prev_offset+1]= *decode_table;
+ return offset;
+}
+
+
+static uint find_longest_bitstream(uint16 *table)
+{
+ uint length=1,length2;
+ if (!(*table & IS_CHAR))
+ length=find_longest_bitstream(table+ *table)+1;
+ table++;
+ if (!(*table & IS_CHAR))
+ {
+ length2=find_longest_bitstream(table+ *table)+1;
+ length=max(length,length2);
+ }
+ return length;
+}
+
+
+ /* Read record from datafile */
+ /* Returns length of packed record, -1 if error */
+
+int _mi_read_pack_record(MI_INFO *info, my_off_t filepos, byte *buf)
+{
+ MI_BLOCK_INFO block_info;
+ File file;
+ DBUG_ENTER("mi_read_pack_record");
+
+ if (filepos == HA_OFFSET_ERROR)
+ DBUG_RETURN(-1); /* _search() didn't find record */
+
+ file=info->dfile;
+ if (_mi_pack_get_block_info(info, &block_info, file, filepos,
+ info->rec_buff))
+ goto err;
+ if (my_read(file,(byte*) info->rec_buff + block_info.offset ,
+ block_info.rec_len - block_info.offset, MYF(MY_NABP)))
+ goto panic;
+ info->update|= HA_STATE_AKTIV;
+ DBUG_RETURN(_mi_pack_rec_unpack(info,buf,info->rec_buff,block_info.rec_len));
+panic:
+ my_errno=HA_ERR_WRONG_IN_RECORD;
+err:
+ DBUG_RETURN(-1);
+}
+
+
+
+int _mi_pack_rec_unpack(register MI_INFO *info, register byte *to, byte *from,
+ ulong reclength)
+{
+ byte *end_field;
+ reg3 MI_COLUMNDEF *end;
+ MI_COLUMNDEF *current_field;
+ MYISAM_SHARE *share=info->s;
+ DBUG_ENTER("_mi_pack_rec_unpack");
+
+ init_bit_buffer(&info->bit_buff, (uchar*) from,reclength);
+
+ for (current_field=share->rec, end=current_field+share->base.fields ;
+ current_field < end ;
+ current_field++,to=end_field)
+ {
+ end_field=to+current_field->length;
+ (*current_field->unpack)(current_field,&info->bit_buff,(uchar*) to,
+ (uchar*) end_field);
+ }
+ if (! info->bit_buff.error &&
+ info->bit_buff.pos - info->bit_buff.bits/8 == info->bit_buff.end)
+ DBUG_RETURN(0);
+ info->update&= ~HA_STATE_AKTIV;
+ DBUG_RETURN(my_errno=HA_ERR_WRONG_IN_RECORD);
+} /* _mi_pack_rec_unpack */
+
+
+ /* Return function to unpack field */
+
+static void (*get_unpack_function(MI_COLUMNDEF *rec))
+(MI_COLUMNDEF *, MI_BIT_BUFF *, uchar *, uchar *)
+{
+ switch (rec->base_type) {
+ case FIELD_SKIPP_ZERO:
+ if (rec->pack_type & PACK_TYPE_ZERO_FILL)
+ return &uf_zerofill_skipp_zero;
+ return &uf_skipp_zero;
+ case FIELD_NORMAL:
+ if (rec->pack_type & PACK_TYPE_SPACE_FIELDS)
+ return &uf_space_normal;
+ if (rec->pack_type & PACK_TYPE_ZERO_FILL)
+ return &uf_zerofill_normal;
+ return &decode_bytes;
+ case FIELD_SKIPP_ENDSPACE:
+ if (rec->pack_type & PACK_TYPE_SPACE_FIELDS)
+ {
+ if (rec->pack_type & PACK_TYPE_SELECTED)
+ return &uf_space_endspace_selected;
+ return &uf_space_endspace;
+ }
+ if (rec->pack_type & PACK_TYPE_SELECTED)
+ return &uf_endspace_selected;
+ return &uf_endspace;
+ case FIELD_SKIPP_PRESPACE:
+ if (rec->pack_type & PACK_TYPE_SPACE_FIELDS)
+ {
+ if (rec->pack_type & PACK_TYPE_SELECTED)
+ return &uf_space_prespace_selected;
+ return &uf_space_prespace;
+ }
+ if (rec->pack_type & PACK_TYPE_SELECTED)
+ return &uf_prespace_selected;
+ return &uf_prespace;
+ case FIELD_CONSTANT:
+ return &uf_constant;
+ case FIELD_INTERVALL:
+ return &uf_intervall;
+ case FIELD_ZERO:
+ case FIELD_CHECK:
+ return &uf_zero;
+ case FIELD_BLOB:
+ return &uf_blob;
+ case FIELD_VARCHAR:
+ return &uf_varchar;
+ case FIELD_LAST:
+ default:
+ return 0; /* This should never happend */
+ }
+}
+
+ /* De different functions to unpack a field */
+
+static void uf_zerofill_skipp_zero(MI_COLUMNDEF *rec, MI_BIT_BUFF *bit_buff,
+ uchar *to, uchar *end)
+{
+ if (get_bit(bit_buff))
+ bzero((char*) to,(uint) (end-to));
+ else
+ {
+ end-=rec->space_length_bits;
+ decode_bytes(rec,bit_buff,to,end);
+ bzero((char*) end,rec->space_length_bits);
+ }
+}
+
+static void uf_skipp_zero(MI_COLUMNDEF *rec, MI_BIT_BUFF *bit_buff, uchar *to,
+ uchar *end)
+{
+ if (get_bit(bit_buff))
+ bzero((char*) to,(uint) (end-to));
+ else
+ decode_bytes(rec,bit_buff,to,end);
+}
+
+static void uf_space_normal(MI_COLUMNDEF *rec, MI_BIT_BUFF *bit_buff, uchar *to,
+ uchar *end)
+{
+ if (get_bit(bit_buff))
+ bfill((byte*) to,(end-to),' ');
+ else
+ decode_bytes(rec,bit_buff,to,end);
+}
+
+static void uf_space_endspace_selected(MI_COLUMNDEF *rec, MI_BIT_BUFF *bit_buff,
+ uchar *to, uchar *end)
+{
+ uint spaces;
+ if (get_bit(bit_buff))
+ bfill((byte*) to,(end-to),' ');
+ else
+ {
+ if (get_bit(bit_buff))
+ {
+ if ((spaces=get_bits(bit_buff,rec->space_length_bits))+to > end)
+ {
+ bit_buff->error=1;
+ return;
+ }
+ if (to+spaces != end)
+ decode_bytes(rec,bit_buff,to,end-spaces);
+ bfill((byte*) end-spaces,spaces,' ');
+ }
+ else
+ decode_bytes(rec,bit_buff,to,end);
+ }
+}
+
+static void uf_endspace_selected(MI_COLUMNDEF *rec, MI_BIT_BUFF *bit_buff,
+ uchar *to, uchar *end)
+{
+ uint spaces;
+ if (get_bit(bit_buff))
+ {
+ if ((spaces=get_bits(bit_buff,rec->space_length_bits))+to > end)
+ {
+ bit_buff->error=1;
+ return;
+ }
+ if (to+spaces != end)
+ decode_bytes(rec,bit_buff,to,end-spaces);
+ bfill((byte*) end-spaces,spaces,' ');
+ }
+ else
+ decode_bytes(rec,bit_buff,to,end);
+}
+
+static void uf_space_endspace(MI_COLUMNDEF *rec, MI_BIT_BUFF *bit_buff, uchar *to,
+ uchar *end)
+{
+ uint spaces;
+ if (get_bit(bit_buff))
+ bfill((byte*) to,(end-to),' ');
+ else
+ {
+ if ((spaces=get_bits(bit_buff,rec->space_length_bits))+to > end)
+ {
+ bit_buff->error=1;
+ return;
+ }
+ if (to+spaces != end)
+ decode_bytes(rec,bit_buff,to,end-spaces);
+ bfill((byte*) end-spaces,spaces,' ');
+ }
+}
+
+static void uf_endspace(MI_COLUMNDEF *rec, MI_BIT_BUFF *bit_buff, uchar *to,
+ uchar *end)
+{
+ uint spaces;
+ if ((spaces=get_bits(bit_buff,rec->space_length_bits))+to > end)
+ {
+ bit_buff->error=1;
+ return;
+ }
+ if (to+spaces != end)
+ decode_bytes(rec,bit_buff,to,end-spaces);
+ bfill((byte*) end-spaces,spaces,' ');
+}
+
+static void uf_space_prespace_selected(MI_COLUMNDEF *rec, MI_BIT_BUFF *bit_buff,
+ uchar *to, uchar *end)
+{
+ uint spaces;
+ if (get_bit(bit_buff))
+ bfill((byte*) to,(end-to),' ');
+ else
+ {
+ if (get_bit(bit_buff))
+ {
+ if ((spaces=get_bits(bit_buff,rec->space_length_bits))+to > end)
+ {
+ bit_buff->error=1;
+ return;
+ }
+ bfill((byte*) to,spaces,' ');
+ if (to+spaces != end)
+ decode_bytes(rec,bit_buff,to+spaces,end);
+ }
+ else
+ decode_bytes(rec,bit_buff,to,end);
+ }
+}
+
+
+static void uf_prespace_selected(MI_COLUMNDEF *rec, MI_BIT_BUFF *bit_buff,
+ uchar *to, uchar *end)
+{
+ uint spaces;
+ if (get_bit(bit_buff))
+ {
+ if ((spaces=get_bits(bit_buff,rec->space_length_bits))+to > end)
+ {
+ bit_buff->error=1;
+ return;
+ }
+ bfill((byte*) to,spaces,' ');
+ if (to+spaces != end)
+ decode_bytes(rec,bit_buff,to+spaces,end);
+ }
+ else
+ decode_bytes(rec,bit_buff,to,end);
+}
+
+
+static void uf_space_prespace(MI_COLUMNDEF *rec, MI_BIT_BUFF *bit_buff, uchar *to,
+ uchar *end)
+{
+ uint spaces;
+ if (get_bit(bit_buff))
+ bfill((byte*) to,(end-to),' ');
+ else
+ {
+ if ((spaces=get_bits(bit_buff,rec->space_length_bits))+to > end)
+ {
+ bit_buff->error=1;
+ return;
+ }
+ bfill((byte*) to,spaces,' ');
+ if (to+spaces != end)
+ decode_bytes(rec,bit_buff,to+spaces,end);
+ }
+}
+
+static void uf_prespace(MI_COLUMNDEF *rec, MI_BIT_BUFF *bit_buff, uchar *to,
+ uchar *end)
+{
+ uint spaces;
+ if ((spaces=get_bits(bit_buff,rec->space_length_bits))+to > end)
+ {
+ bit_buff->error=1;
+ return;
+ }
+ bfill((byte*) to,spaces,' ');
+ if (to+spaces != end)
+ decode_bytes(rec,bit_buff,to+spaces,end);
+}
+
+static void uf_zerofill_normal(MI_COLUMNDEF *rec, MI_BIT_BUFF *bit_buff, uchar *to,
+ uchar *end)
+{
+ end-=rec->space_length_bits;
+ decode_bytes(rec,bit_buff,(uchar*) to,end);
+ bzero((char*) end,rec->space_length_bits);
+}
+
+static void uf_constant(MI_COLUMNDEF *rec,
+ MI_BIT_BUFF *bit_buff __attribute__((unused)),
+ uchar *to,
+ uchar *end)
+{
+ memcpy(to,rec->huff_tree->intervalls,(size_t) (end-to));
+}
+
+static void uf_intervall(MI_COLUMNDEF *rec, MI_BIT_BUFF *bit_buff, uchar *to,
+ uchar *end)
+{
+ reg1 uint field_length=(uint) (end-to);
+ memcpy(to,rec->huff_tree->intervalls+field_length*decode_pos(bit_buff,
+ rec->huff_tree),
+ (size_t) field_length);
+}
+
+
+/*ARGSUSED*/
+static void uf_zero(MI_COLUMNDEF *rec __attribute__((unused)),
+ MI_BIT_BUFF *bit_buff __attribute__((unused)),
+ uchar *to, uchar *end)
+{
+ bzero((char*) to,(uint) (end-to));
+}
+
+static void uf_blob(MI_COLUMNDEF *rec, MI_BIT_BUFF *bit_buff,
+ uchar *to, uchar *end)
+{
+ if (get_bit(bit_buff))
+ bzero((byte*) to,(end-to));
+ else
+ {
+ ulong length=get_bits(bit_buff,rec->space_length_bits);
+ uint pack_length=(uint) (end-to)-mi_portable_sizeof_char_ptr;
+ decode_bytes(rec,bit_buff,bit_buff->blob_pos,bit_buff->blob_pos+length);
+ _my_store_blob_length((byte*) to,pack_length,length);
+ memcpy_fixed((char*) to+pack_length,(char*) &bit_buff->blob_pos,
+ sizeof(char*));
+ bit_buff->blob_pos+=length;
+ }
+}
+
+static void uf_varchar(MI_COLUMNDEF *rec, MI_BIT_BUFF *bit_buff,
+ uchar *to, uchar *end __attribute__((unused)))
+{
+ if (get_bit(bit_buff))
+ to[0]=to[1]=0; /* Zero lengths */
+ else
+ {
+ ulong length=get_bits(bit_buff,rec->space_length_bits);
+ int2store(to,length);
+ decode_bytes(rec,bit_buff,to+2,to+2+length);
+ }
+}
+
+ /* Functions to decode of buffer of bits */
+
+#if BITS_SAVED == 64
+
+static void decode_bytes(MI_COLUMNDEF *rec,MI_BIT_BUFF *bit_buff,uchar *to,
+ uchar *end)
+{
+ reg1 uint bits,low_byte;
+ reg3 uint16 *pos;
+ reg4 uint table_bits,table_and;
+ MI_DECODE_TREE *decode_tree;
+
+ decode_tree=rec->decode_tree;
+ bits=bit_buff->bits; /* Save in reg for quicker access */
+ table_bits=decode_tree->quick_table_bits;
+ table_and= (1 << table_bits)-1;
+
+ do
+ {
+ if (bits <= 32)
+ {
+ if (bit_buff->pos > bit_buff->end+4)
+ return; /* Can't be right */
+ bit_buff->current_byte= (bit_buff->current_byte << 32) +
+ ((((uint) bit_buff->pos[3])) +
+ (((uint) bit_buff->pos[2]) << 8) +
+ (((uint) bit_buff->pos[1]) << 16) +
+ (((uint) bit_buff->pos[0]) << 24));
+ bit_buff->pos+=4;
+ bits+=32;
+ }
+ /* First use info in quick_table */
+ low_byte=(uint) (bit_buff->current_byte >> (bits - table_bits)) & table_and;
+ low_byte=decode_tree->table[low_byte];
+ if (low_byte & IS_CHAR)
+ {
+ *to++ = (low_byte & 255); /* Found char in quick table */
+ bits-= ((low_byte >> 8) & 31); /* Remove bits used */
+ }
+ else
+ { /* Map through rest of decode-table */
+ pos=decode_tree->table+low_byte;
+ bits-=table_bits;
+ for (;;)
+ {
+ low_byte=(uint) (bit_buff->current_byte >> (bits-8));
+ decode_bytes_test_bit(0);
+ decode_bytes_test_bit(1);
+ decode_bytes_test_bit(2);
+ decode_bytes_test_bit(3);
+ decode_bytes_test_bit(4);
+ decode_bytes_test_bit(5);
+ decode_bytes_test_bit(6);
+ decode_bytes_test_bit(7);
+ bits-=8;
+ }
+ *to++ = *pos;
+ }
+ } while (to != end);
+
+ bit_buff->bits=bits;
+ return;
+}
+
+#else
+
+static void decode_bytes(MI_COLUMNDEF *rec, MI_BIT_BUFF *bit_buff, uchar *to, uchar *end)
+{
+ reg1 uint bits,low_byte;
+ reg3 uint16 *pos;
+ reg4 uint table_bits,table_and;
+ MI_DECODE_TREE *decode_tree;
+
+ decode_tree=rec->huff_tree;
+ bits=bit_buff->bits; /* Save in reg for quicker access */
+ table_bits=decode_tree->quick_table_bits;
+ table_and= (1 << table_bits)-1;
+
+ do
+ {
+ if (bits < table_bits)
+ {
+ if (bit_buff->pos > bit_buff->end+1)
+ return; /* Can't be right */
+#if BITS_SAVED == 32
+ bit_buff->current_byte= (bit_buff->current_byte << 24) +
+ (((uint) ((uchar) bit_buff->pos[2]))) +
+ (((uint) ((uchar) bit_buff->pos[1])) << 8) +
+ (((uint) ((uchar) bit_buff->pos[0])) << 16);
+ bit_buff->pos+=3;
+ bits+=24;
+#else
+ if (bits) /* We must have at leasts 9 bits */
+ {
+ bit_buff->current_byte= (bit_buff->current_byte << 8) +
+ (uint) ((uchar) bit_buff->pos[0]);
+ bit_buff->pos++;
+ bits+=8;
+ }
+ else
+ {
+ bit_buff->current_byte= ((uint) ((uchar) bit_buff->pos[0]) << 8) +
+ ((uint) ((uchar) bit_buff->pos[1]));
+ bit_buff->pos+=2;
+ bits+=16;
+ }
+#endif
+ }
+ /* First use info in quick_table */
+ low_byte=(bit_buff->current_byte >> (bits - table_bits)) & table_and;
+ low_byte=decode_tree->table[low_byte];
+ if (low_byte & IS_CHAR)
+ {
+ *to++ = (low_byte & 255); /* Found char in quick table */
+ bits-= ((low_byte >> 8) & 31); /* Remove bits used */
+ }
+ else
+ { /* Map through rest of decode-table */
+ pos=decode_tree->table+low_byte;
+ bits-=table_bits;
+ for (;;)
+ {
+ if (bits < 8)
+ { /* We don't need to check end */
+#if BITS_SAVED == 32
+ bit_buff->current_byte= (bit_buff->current_byte << 24) +
+ (((uint) ((uchar) bit_buff->pos[2]))) +
+ (((uint) ((uchar) bit_buff->pos[1])) << 8) +
+ (((uint) ((uchar) bit_buff->pos[0])) << 16);
+ bit_buff->pos+=3;
+ bits+=24;
+#else
+ bit_buff->current_byte= (bit_buff->current_byte << 8) +
+ (uint) ((uchar) bit_buff->pos[0]);
+ bit_buff->pos+=1;
+ bits+=8;
+#endif
+ }
+ low_byte=(uint) (bit_buff->current_byte >> (bits-8));
+ decode_bytes_test_bit(0);
+ decode_bytes_test_bit(1);
+ decode_bytes_test_bit(2);
+ decode_bytes_test_bit(3);
+ decode_bytes_test_bit(4);
+ decode_bytes_test_bit(5);
+ decode_bytes_test_bit(6);
+ decode_bytes_test_bit(7);
+ bits-=8;
+ }
+ *to++ = (uchar) *pos;
+ }
+ } while (to != end);
+
+ bit_buff->bits=bits;
+ return;
+}
+#endif /* BIT_SAVED == 64 */
+
+
+static uint decode_pos(MI_BIT_BUFF *bit_buff, MI_DECODE_TREE *decode_tree)
+{
+ uint16 *pos=decode_tree->table;
+ for (;;)
+ {
+ if (get_bit(bit_buff))
+ pos++;
+ if (*pos & IS_CHAR)
+ return (uint) (*pos & ~IS_CHAR);
+ pos+= *pos;
+ }
+}
+
+
+int _mi_read_rnd_pack_record(MI_INFO *info, byte *buf,
+ register my_off_t filepos,
+ my_bool skip_deleted_blocks)
+{
+ uint b_type;
+ MI_BLOCK_INFO block_info;
+ MYISAM_SHARE *share=info->s;
+ DBUG_ENTER("_mi_read_rnd_pack_record");
+
+ if (filepos >= info->state->data_file_length)
+ {
+ my_errno= HA_ERR_END_OF_FILE;
+ goto err;
+ }
+
+ if (info->opt_flag & READ_CACHE_USED)
+ {
+ if (_mi_read_cache(&info->rec_cache,(byte*) block_info.header,filepos,
+ share->pack.ref_length, skip_deleted_blocks))
+ goto err;
+ b_type=_mi_pack_get_block_info(info,&block_info,-1, filepos, NullS);
+ }
+ else
+ b_type=_mi_pack_get_block_info(info,&block_info,info->dfile,filepos,
+ info->rec_buff);
+ if (b_type)
+ goto err;
+#ifndef DBUG_OFF
+ if (block_info.rec_len > share->max_pack_length)
+ {
+ my_errno=HA_ERR_WRONG_IN_RECORD;
+ goto err;
+ }
+#endif
+
+ if (info->opt_flag & READ_CACHE_USED)
+ {
+ if (_mi_read_cache(&info->rec_cache,(byte*) info->rec_buff,
+ block_info.filepos, block_info.rec_len,
+ skip_deleted_blocks))
+ goto err;
+ }
+ else
+ {
+ if (my_read(info->dfile,(byte*) info->rec_buff + block_info.offset,
+ block_info.rec_len-block_info.offset,
+ MYF(MY_NABP)))
+ goto err;
+ }
+ info->packed_length=block_info.rec_len;
+ info->lastpos=filepos;
+ info->nextpos=block_info.filepos+block_info.rec_len;
+ info->update|= HA_STATE_AKTIV | HA_STATE_KEY_CHANGED;
+
+ DBUG_RETURN (_mi_pack_rec_unpack(info,buf,info->rec_buff,
+ block_info.rec_len));
+ err:
+ DBUG_RETURN(my_errno);
+}
+
+
+ /* Read and process header from a huff-record-file */
+
+uint _mi_pack_get_block_info(MI_INFO *myisam, MI_BLOCK_INFO *info, File file,
+ my_off_t filepos, char *rec_buff)
+{
+ uchar *header=info->header;
+ uint head_length,ref_length;
+ LINT_INIT(ref_length);
+
+ if (file >= 0)
+ {
+ ref_length=myisam->s->pack.ref_length;
+ /*
+ We can't use my_pread() here because mi_rad_pack_record assumes
+ position is ok
+ */
+ VOID(my_seek(file,filepos,MY_SEEK_SET,MYF(0)));
+ if (my_read(file,(char*) header,ref_length,MYF(MY_NABP)))
+ return BLOCK_FATAL_ERROR;
+ DBUG_DUMP("header",(byte*) header,ref_length);
+ }
+ if (header[0] < 254)
+ {
+ info->rec_len=header[0];
+ head_length=1;
+ }
+ else if (header[0] == 254)
+ {
+ info->rec_len=uint2korr(header+1);
+ head_length=3;
+ }
+ else
+ {
+ info->rec_len=uint3korr(header+1);
+ head_length=4;
+ }
+ if (myisam->s->base.blobs)
+ {
+ if (header[head_length] < 254)
+ {
+ info->blob_len=header[head_length];
+ head_length++;
+ }
+ else if (header[head_length] == 254)
+ {
+ info->blob_len=uint2korr(header+head_length+1);
+ head_length+=3;
+ }
+ else
+ {
+ info->blob_len=uint3korr(header+head_length+1);
+ head_length+=4;
+ }
+ if (!(mi_fix_rec_buff_for_blob(myisam,info->rec_len + info->blob_len)))
+ return BLOCK_FATAL_ERROR; /* not enough memory */
+ myisam->bit_buff.blob_pos=(uchar*) myisam->rec_buff+info->rec_len;
+ myisam->blob_length=info->blob_len;
+ }
+ info->filepos=filepos+head_length;
+ if (file > 0)
+ {
+ info->offset=min(info->rec_len, ref_length - head_length);
+ memcpy(rec_buff, header+head_length, info->offset);
+ }
+ return 0;
+}
+
+
+ /* rutines for bit buffer */
+ /* Note buffer must be 6 byte bigger than longest row */
+
+static void init_bit_buffer(MI_BIT_BUFF *bit_buff, uchar *buffer, uint length)
+{
+ bit_buff->pos=buffer;
+ bit_buff->end=buffer+length;
+ bit_buff->bits=bit_buff->error=0;
+ bit_buff->current_byte=0; /* Avoid purify errors */
+}
+
+static uint fill_and_get_bits(MI_BIT_BUFF *bit_buff, uint count)
+{
+ uint tmp;
+ count-=bit_buff->bits;
+ tmp=(bit_buff->current_byte & mask[bit_buff->bits]) << count;
+ fill_buffer(bit_buff);
+ bit_buff->bits=BITS_SAVED - count;
+ return tmp+(bit_buff->current_byte >> (BITS_SAVED - count));
+}
+
+ /* Fill in empty bit_buff->current_byte from buffer */
+ /* Sets bit_buff->error if buffer is exhausted */
+
+static void fill_buffer(MI_BIT_BUFF *bit_buff)
+{
+ if (bit_buff->pos >= bit_buff->end)
+ {
+ bit_buff->error= 1;
+ bit_buff->current_byte=0;
+ return;
+ }
+#if BITS_SAVED == 64
+ bit_buff->current_byte= ((((uint) ((uchar) bit_buff->pos[7]))) +
+ (((uint) ((uchar) bit_buff->pos[6])) << 8) +
+ (((uint) ((uchar) bit_buff->pos[5])) << 16) +
+ (((uint) ((uchar) bit_buff->pos[4])) << 24) +
+ ((ulonglong)
+ ((((uint) ((uchar) bit_buff->pos[3]))) +
+ (((uint) ((uchar) bit_buff->pos[2])) << 8) +
+ (((uint) ((uchar) bit_buff->pos[1])) << 16) +
+ (((uint) ((uchar) bit_buff->pos[0])) << 24)) << 32));
+ bit_buff->pos+=8;
+#else
+#if BITS_SAVED == 32
+ bit_buff->current_byte= (((uint) ((uchar) bit_buff->pos[3])) +
+ (((uint) ((uchar) bit_buff->pos[2])) << 8) +
+ (((uint) ((uchar) bit_buff->pos[1])) << 16) +
+ (((uint) ((uchar) bit_buff->pos[0])) << 24));
+ bit_buff->pos+=4;
+#else
+ bit_buff->current_byte= (uint) (((uint) ((uchar) bit_buff->pos[1]))+
+ (((uint) ((uchar) bit_buff->pos[0])) << 8));
+ bit_buff->pos+=2;
+#endif
+#endif
+}
+
+ /* Get number of bits neaded to represent value */
+
+static uint max_bit(register uint value)
+{
+ reg2 uint power=1;
+
+ while ((value>>=1))
+ power++;
+ return (power);
+}
+
+
+/*****************************************************************************
+ Some redefined functions to handle files when we are using memmap
+*****************************************************************************/
+
+#ifdef HAVE_MMAP
+
+#include <sys/mman.h>
+
+static int _mi_read_mempack_record(MI_INFO *info,my_off_t filepos,byte *buf);
+static int _mi_read_rnd_mempack_record(MI_INFO*, byte *,my_off_t, my_bool);
+
+#ifndef MAP_NORESERVE
+#define MAP_NORESERVE 0 /* For irix */
+#endif
+#ifndef MAP_FAILED
+#define MAP_FAILED -1
+#endif
+
+my_bool _mi_memmap_file(MI_INFO *info)
+{
+ byte *file_map;
+ MYISAM_SHARE *share=info->s;
+ DBUG_ENTER("mi_memmap_file");
+
+ if (!info->s->file_map)
+ {
+ if (my_seek(info->dfile,0L,MY_SEEK_END,MYF(0)) <
+ share->state.state.data_file_length+MEMMAP_EXTRA_MARGIN)
+ {
+ DBUG_PRINT("warning",("File isn't extended for memmap"));
+ DBUG_RETURN(0);
+ }
+ file_map=(byte*)
+ mmap(0,share->state.state.data_file_length+MEMMAP_EXTRA_MARGIN,PROT_READ,
+ MAP_SHARED | MAP_NORESERVE,info->dfile,0L);
+ if (file_map == (byte*) MAP_FAILED)
+ {
+ DBUG_PRINT("warning",("mmap failed: errno: %d",errno));
+ my_errno=errno;
+ DBUG_RETURN(0);
+ }
+ info->s->file_map=file_map;
+ }
+ info->opt_flag|= MEMMAP_USED;
+ info->read_record=share->read_record=_mi_read_mempack_record;
+ share->read_rnd=_mi_read_rnd_mempack_record;
+ DBUG_RETURN(1);
+}
+
+
+void _mi_unmap_file(MI_INFO *info)
+{
+ VOID(munmap((caddr_t) info->s->file_map,
+ (size_t) info->s->state.state.data_file_length+
+ MEMMAP_EXTRA_MARGIN));
+}
+
+
+static uchar *_mi_mempack_get_block_info(MI_INFO *myisam,MI_BLOCK_INFO *info,
+ uchar *header)
+{
+ if (header[0] < 254)
+ info->rec_len= *header++;
+ else if (header[0] == 254)
+ {
+ info->rec_len=uint2korr(header+1);
+ header+=3;
+ }
+ else
+ {
+ info->rec_len=uint3korr(header+1);
+ header+=4;
+ }
+ if (myisam->s->base.blobs)
+ {
+ if (header[0] < 254)
+ {
+ info->blob_len= *header++;
+ }
+ else if (header[0] == 254)
+ {
+ info->blob_len=uint2korr(header+1);
+ header+=3;
+ }
+ else
+ {
+ info->blob_len=uint3korr(header+1);
+ header+=4;
+ }
+ /* mi_fix_rec_buff_for_blob sets my_errno on error */
+ if (!(mi_fix_rec_buff_for_blob(myisam,info->blob_len)))
+ return 0; /* not enough memory */
+ myisam->bit_buff.blob_pos=(uchar*) myisam->rec_buff;
+ }
+ return header;
+}
+
+
+static int _mi_read_mempack_record(MI_INFO *info, my_off_t filepos, byte *buf)
+{
+ MI_BLOCK_INFO block_info;
+ MYISAM_SHARE *share=info->s;
+ byte *pos;
+ DBUG_ENTER("mi_read_mempack_record");
+
+ if (filepos == HA_OFFSET_ERROR)
+ DBUG_RETURN(-1); /* _search() didn't find record */
+
+ if (!(pos= (byte*) _mi_mempack_get_block_info(info,&block_info,
+ (uchar*) share->file_map+
+ filepos)))
+ DBUG_RETURN(-1);
+ DBUG_RETURN(_mi_pack_rec_unpack(info, buf, pos, block_info.rec_len));
+}
+
+
+/*ARGSUSED*/
+static int _mi_read_rnd_mempack_record(MI_INFO *info, byte *buf,
+ register my_off_t filepos,
+ my_bool skip_deleted_blocks
+ __attribute__((unused)))
+{
+ MI_BLOCK_INFO block_info;
+ MYISAM_SHARE *share=info->s;
+ byte *pos,*start;
+ DBUG_ENTER("_mi_read_rnd_mempack_record");
+
+ if (filepos >= share->state.state.data_file_length)
+ {
+ my_errno=HA_ERR_END_OF_FILE;
+ goto err;
+ }
+ if (!(pos= (byte*) _mi_mempack_get_block_info(info,&block_info,
+ (uchar*)
+ (start=share->file_map+
+ filepos))))
+ goto err;
+#ifndef DBUG_OFF
+ if (block_info.rec_len > info->s->max_pack_length)
+ {
+ my_errno=HA_ERR_WRONG_IN_RECORD;
+ goto err;
+ }
+#endif
+ info->packed_length=block_info.rec_len;
+ info->lastpos=filepos;
+ info->nextpos=filepos+(uint) (pos-start)+block_info.rec_len;
+ info->update|= HA_STATE_AKTIV | HA_STATE_KEY_CHANGED;
+
+ DBUG_RETURN (_mi_pack_rec_unpack(info,buf,pos, block_info.rec_len));
+ err:
+ DBUG_RETURN(my_errno);
+}
+
+#endif /* HAVE_MMAP */
+
+ /* Save length of row */
+
+uint save_pack_length(byte *block_buff,ulong length)
+{
+ if (length < 254)
+ {
+ *(uchar*) block_buff= (uchar) length;
+ return 1;
+ }
+ if (length <= 65535)
+ {
+ *(uchar*) block_buff=254;
+ int2store(block_buff+1,(uint) length);
+ return 3;
+ }
+ *(uchar*) block_buff=255;
+ int3store(block_buff+1,(ulong) length);
+ return 4;
+}
diff --git a/myisam/mi_page.c b/myisam/mi_page.c
new file mode 100644
index 00000000000..dd7de9ba8b6
--- /dev/null
+++ b/myisam/mi_page.c
@@ -0,0 +1,144 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 key blocks */
+
+#include "myisamdef.h"
+#ifdef __WIN__
+#include <errno.h>
+#endif
+
+ /* Fetch a key-page in memory */
+
+uchar *_mi_fetch_keypage(register MI_INFO *info, MI_KEYDEF *keyinfo,
+ my_off_t page, uchar *buff, int return_buffer)
+{
+ uchar *tmp;
+ uint page_size;
+ tmp=(uchar*) key_cache_read(info->s->kfile,page,(byte*) buff,
+ (uint) keyinfo->block_length,
+ (uint) keyinfo->block_length,
+ return_buffer);
+ if (tmp == info->buff)
+ info->buff_used=1;
+ else if (!tmp)
+ {
+ DBUG_PRINT("error",("Got errno: %d from key_cache_read",my_errno));
+ info->last_keypage=HA_OFFSET_ERROR;
+ my_errno=HA_ERR_CRASHED;
+ return 0;
+ }
+ info->last_keypage=page;
+ page_size=mi_getint(tmp);
+ if (page_size < 4 || page_size > keyinfo->block_length)
+ {
+ DBUG_PRINT("error",("page %lu had wrong page length: %u",
+ (ulong) page, page_size));
+ info->last_keypage = HA_OFFSET_ERROR;
+ my_errno = HA_ERR_CRASHED;
+ tmp = 0;
+ }
+ return tmp;
+} /* _mi_fetch_keypage */
+
+
+ /* Write a key-page on disk */
+
+int _mi_write_keypage(register MI_INFO *info, register MI_KEYDEF *keyinfo,
+ my_off_t page, uchar *buff)
+{
+ reg3 uint length;
+#ifndef FAST /* Safety check */
+ if (page < info->s->base.keystart ||
+ page+keyinfo->block_length > info->state->key_file_length ||
+ page & (myisam_block_size-1))
+ {
+ DBUG_PRINT("error",("Trying to write outside key region: %lu",
+ (long) page));
+ my_errno=EINVAL;
+ return(-1);
+ }
+ DBUG_PRINT("page",("write page at: %lu",(long) page,buff));
+ DBUG_DUMP("buff",(byte*) buff,mi_getint(buff));
+#endif
+
+ if ((length=keyinfo->block_length) > IO_SIZE*2 &&
+ info->state->key_file_length != page+length)
+ length= ((mi_getint(buff)+IO_SIZE-1) & (uint) ~(IO_SIZE-1));
+#ifdef HAVE_purify
+ {
+ length=mi_getint(buff);
+ bzero((byte*) buff+length,keyinfo->block_length-length);
+ length=keyinfo->block_length;
+ }
+#endif
+ return (key_cache_write(info->s->kfile,page,(byte*) buff,length,
+ (uint) keyinfo->block_length,
+ (int) ((info->lock_type != F_UNLCK) ||
+ info->s->delay_key_write)));
+} /* mi_write_keypage */
+
+
+ /* Remove page from disk */
+
+int _mi_dispose(register MI_INFO *info, MI_KEYDEF *keyinfo, my_off_t pos)
+{
+ my_off_t old_link;
+ char buff[8];
+ DBUG_ENTER("_mi_dispose");
+
+ old_link=info->s->state.key_del[keyinfo->block_size];
+ info->s->state.key_del[keyinfo->block_size]=pos;
+ mi_sizestore(buff,old_link);
+ DBUG_RETURN(key_cache_write(info->s->kfile,pos,buff,
+ sizeof(buff),
+ (uint) keyinfo->block_length,
+ (int) (info->lock_type != F_UNLCK)));
+} /* _mi_dispose */
+
+
+ /* Make new page on disk */
+
+my_off_t _mi_new(register MI_INFO *info, MI_KEYDEF *keyinfo)
+{
+ my_off_t pos;
+ char buff[8];
+ DBUG_ENTER("_mi_new");
+
+ if ((pos=info->s->state.key_del[keyinfo->block_size]) == HA_OFFSET_ERROR)
+ {
+ if (info->state->key_file_length >=
+ info->s->base.max_key_file_length - keyinfo->block_length)
+ {
+ my_errno=HA_ERR_INDEX_FILE_FULL;
+ DBUG_RETURN(HA_OFFSET_ERROR);
+ }
+ pos=info->state->key_file_length;
+ info->state->key_file_length+= keyinfo->block_length;
+ }
+ else
+ {
+ if (!key_cache_read(info->s->kfile,pos,
+ buff,
+ (uint) sizeof(buff),
+ (uint) keyinfo->block_length,0))
+ pos= HA_OFFSET_ERROR;
+ else
+ info->s->state.key_del[keyinfo->block_size]=mi_sizekorr(buff);
+ }
+ DBUG_PRINT("exit",("Pos: %d",pos));
+ DBUG_RETURN(pos);
+} /* _mi_new */
diff --git a/myisam/mi_panic.c b/myisam/mi_panic.c
new file mode 100644
index 00000000000..ae149df3ffe
--- /dev/null
+++ b/myisam/mi_panic.c
@@ -0,0 +1,111 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "myisamdef.h"
+
+ /* if flag == HA_PANIC_CLOSE then all misam files are closed */
+ /* if flag == HA_PANIC_WRITE then all misam files are unlocked and
+ all changed data in single user misam is written to file */
+ /* if flag == HA_PANIC_READ then all misam files that was locked when
+ mi_panic(HA_PANIC_WRITE) was done is locked. A mi_readinfo() is
+ done for all single user files to get changes in database */
+
+
+int mi_panic(enum ha_panic_function flag)
+{
+ int error=0;
+ LIST *list_element,*next_open;
+ MI_INFO *info;
+ DBUG_ENTER("mi_panic");
+
+ pthread_mutex_lock(&THR_LOCK_myisam);
+ for (list_element=myisam_open_list ; list_element ; list_element=next_open)
+ {
+ next_open=list_element->next; /* Save if close */
+ info=(MI_INFO*) list_element->data;
+ switch (flag) {
+ case HA_PANIC_CLOSE:
+ pthread_mutex_unlock(&THR_LOCK_myisam); /* Not exactly right... */
+ if (mi_close(info))
+ error=my_errno;
+ pthread_mutex_lock(&THR_LOCK_myisam);
+ break;
+ case HA_PANIC_WRITE: /* Do this to free databases */
+#ifdef CANT_OPEN_FILES_TWICE
+ if (info->s->options & HA_OPTION_READ_ONLY_DATA)
+ break;
+#endif
+ if (flush_key_blocks(info->s->kfile,FLUSH_RELEASE))
+ error=my_errno;
+ if (info->opt_flag & WRITE_CACHE_USED)
+ if (flush_io_cache(&info->rec_cache))
+ error=my_errno;
+ if (info->opt_flag & READ_CACHE_USED)
+ {
+ if (flush_io_cache(&info->rec_cache))
+ error=my_errno;
+ reinit_io_cache(&info->rec_cache,READ_CACHE,0,
+ (pbool) (info->lock_type != F_UNLCK),1);
+ }
+ if (info->lock_type != F_UNLCK && ! info->was_locked)
+ {
+ info->was_locked=info->lock_type;
+ if (mi_lock_database(info,F_UNLCK))
+ error=my_errno;
+ }
+#ifdef CANT_OPEN_FILES_TWICE
+ if (info->s->kfile >= 0 && my_close(info->s->kfile,MYF(0)))
+ error = my_errno;
+ if (info->dfile >= 0 && my_close(info->dfile,MYF(0)))
+ error = my_errno;
+ info->s->kfile=info->dfile= -1; /* Files aren't open anymore */
+ break;
+#endif
+ case HA_PANIC_READ: /* Restore to before WRITE */
+#ifdef CANT_OPEN_FILES_TWICE
+ { /* Open closed files */
+ char name_buff[FN_REFLEN];
+ if (info->s->kfile < 0)
+ if ((info->s->kfile= my_open(fn_format(name_buff,info->filename,"",
+ N_NAME_IEXT,4),info->mode,
+ MYF(MY_WME))) < 0)
+ error = my_errno;
+ if (info->dfile < 0)
+ {
+ if ((info->dfile= my_open(fn_format(name_buff,info->filename,"",
+ N_NAME_DEXT,4),info->mode,
+ MYF(MY_WME))) < 0)
+ error = my_errno;
+ info->rec_cache.file=info->dfile;
+ }
+ }
+#endif
+ if (info->was_locked)
+ {
+ if (mi_lock_database(info, info->was_locked))
+ error=my_errno;
+ info->was_locked=0;
+ }
+ break;
+ }
+ }
+ if (flag == HA_PANIC_CLOSE)
+ VOID(mi_log(0)); /* Close log if neaded */
+ pthread_mutex_unlock(&THR_LOCK_myisam);
+ if (!error)
+ DBUG_RETURN(0);
+ DBUG_RETURN(my_errno=error);
+} /* mi_panic */
diff --git a/myisam/mi_range.c b/myisam/mi_range.c
new file mode 100644
index 00000000000..038f9abc3a6
--- /dev/null
+++ b/myisam/mi_range.c
@@ -0,0 +1,199 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/*
+ Gives a approximated number of how many records there is between two keys.
+ Used when optimizing querries.
+ */
+
+#include "myisamdef.h"
+
+static ha_rows _mi_record_pos(MI_INFO *info,const byte *key,uint key_len,
+ enum ha_rkey_function search_flag);
+static double _mi_search_pos(MI_INFO *info,MI_KEYDEF *keyinfo,uchar *key,
+ uint key_len,uint nextflag,my_off_t pos);
+static uint _mi_keynr(MI_INFO *info,MI_KEYDEF *keyinfo,uchar *page,
+ uchar *keypos,uint *ret_max_key);
+
+
+ /* If start_key = 0 assume read from start */
+ /* If end_key = 0 assume read to end */
+ /* Returns HA_POS_ERROR on error */
+
+ha_rows mi_records_in_range(MI_INFO *info, int inx, const byte *start_key,
+ uint start_key_len,
+ enum ha_rkey_function start_search_flag,
+ const byte *end_key, uint end_key_len,
+ enum ha_rkey_function end_search_flag)
+{
+ ha_rows start_pos,end_pos;
+ DBUG_ENTER("mi_records_in_range");
+
+ if ((inx = _mi_check_index(info,inx)) < 0)
+ DBUG_RETURN(HA_POS_ERROR);
+
+ if (_mi_readinfo(info,F_RDLCK,1))
+ DBUG_RETURN(HA_POS_ERROR);
+ info->update&= (HA_STATE_CHANGED+HA_STATE_ROW_CHANGED);
+ if (info->s->concurrent_insert)
+ rw_rdlock(&info->s->key_root_lock[inx]);
+ start_pos= (start_key ?
+ _mi_record_pos(info,start_key,start_key_len,start_search_flag) :
+ (ha_rows) 0);
+ end_pos= (end_key ?
+ _mi_record_pos(info,end_key,end_key_len,end_search_flag) :
+ info->state->records+ (ha_rows) 1);
+ if (info->s->concurrent_insert)
+ rw_unlock(&info->s->key_root_lock[inx]);
+ VOID(_mi_writeinfo(info,0));
+ 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)));
+ DBUG_RETURN(end_pos < start_pos ? (ha_rows) 0 :
+ (end_pos == start_pos ? (ha_rows) 1 : end_pos-start_pos));
+}
+
+
+ /* Find relative position (in records) for key in index-tree */
+
+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;
+ MI_KEYDEF *keyinfo=info->s->keyinfo+inx;
+ uchar *key_buff;
+ double pos;
+
+ DBUG_ENTER("_mi_record_pos");
+ DBUG_PRINT("enter",("search_flag: %d",search_flag));
+
+ if (key_len == 0)
+ key_len=USE_WHOLE_KEY;
+ key_buff=info->lastkey+info->s->base.max_key_length;
+ 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););
+ pos=_mi_search_pos(info,keyinfo,key_buff,key_len,
+ myisam_read_vec[search_flag] | SEARCH_SAVE_BUFF,
+ info->s->state.key_root[inx]);
+ if (pos >= 0.0)
+ {
+ DBUG_PRINT("exit",("pos: %ld",(ulong) (pos*info->state->records)));
+ DBUG_RETURN((ulong) (pos*info->state->records+0.5));
+ }
+ DBUG_RETURN(HA_POS_ERROR);
+}
+
+
+ /* This is a modified version of _mi_search */
+ /* Returns offset for key in indextable (decimal 0.0 <= x <= 1.0) */
+
+static double _mi_search_pos(register MI_INFO *info,
+ register MI_KEYDEF *keyinfo,
+ uchar *key, uint key_len, uint nextflag,
+ register my_off_t pos)
+{
+ int flag;
+ uint nod_flag,keynr,max_keynr;
+ my_bool after_key;
+ uchar *keypos,*buff;
+ double offset;
+ DBUG_ENTER("_mi_search_pos");
+
+ if (pos == HA_OFFSET_ERROR)
+ DBUG_RETURN(0.5);
+
+ if (!(buff=_mi_fetch_keypage(info,keyinfo,pos,info->buff,1)))
+ goto err;
+ flag=(*keyinfo->bin_search)(info,keyinfo,buff,key,key_len,nextflag,
+ &keypos,info->lastkey, &after_key);
+ nod_flag=mi_test_if_nod(buff);
+ keynr=_mi_keynr(info,keyinfo,buff,keypos,&max_keynr);
+
+ if (flag)
+ {
+ if (flag == MI_FOUND_WRONG_KEY)
+ DBUG_RETURN(-1); /* error */
+ /*
+ ** Didn't found match. keypos points at next (bigger) key
+ * Try to find a smaller, better matching key.
+ ** Matches keynr + [0-1]
+ */
+ if (flag > 0 && ! nod_flag)
+ offset= 1.0;
+ else if ((offset=_mi_search_pos(info,keyinfo,key,key_len,nextflag,
+ _mi_kpos(nod_flag,keypos))) < 0)
+ DBUG_RETURN(offset);
+ }
+ else
+ {
+ /*
+ ** Found match. Keypos points at the start of the found key
+ ** Matches keynr+1
+ */
+ offset=1.0; /* Matches keynr+1 */
+ if (nextflag & SEARCH_FIND &&
+ ((keyinfo->flag & (HA_NOSAME | HA_NULL_PART)) != HA_NOSAME ||
+ key_len) && nod_flag)
+ {
+ /*
+ ** There may be identical keys in the tree. Try to match on of those.
+ ** Matches keynr + [0-1]
+ */
+ if ((offset=_mi_search_pos(info,keyinfo,key,key_len,SEARCH_FIND,
+ _mi_kpos(nod_flag,keypos))) < 0)
+ DBUG_RETURN(offset); /* Read error */
+ }
+ }
+ DBUG_PRINT("info",("keynr: %d offset: %g max_keynr: %d nod: %d flag: %d",
+ keynr,offset,max_keynr,nod_flag,flag));
+ DBUG_RETURN((keynr+offset)/(max_keynr+1));
+err:
+ DBUG_PRINT("exit",("Error: %d",my_errno));
+ DBUG_RETURN (-1.0);
+}
+
+
+ /* Get keynummer of current key and max number of keys in nod */
+
+static uint _mi_keynr(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page, uchar *keypos, uint *ret_max_key)
+{
+ uint nod_flag,keynr,max_key;
+ uchar t_buff[MI_MAX_KEY_BUFF],*end;
+
+ end= page+mi_getint(page);
+ nod_flag=mi_test_if_nod(page);
+ page+=2+nod_flag;
+
+ if (!(keyinfo->flag & (HA_VAR_LENGTH_KEY| HA_BINARY_PACK_KEY)))
+ {
+ *ret_max_key= (uint) (end-page)/(keyinfo->keylength+nod_flag);
+ return (uint) (keypos-page)/(keyinfo->keylength+nod_flag);
+ }
+
+ max_key=keynr=0;
+ t_buff[0]=0; /* Safety */
+ while (page < end)
+ {
+ if (!(*keyinfo->get_key)(keyinfo,nod_flag,&page,t_buff))
+ return 0; /* Error */
+ max_key++;
+ if (page == keypos)
+ keynr=max_key;
+ }
+ *ret_max_key=max_key;
+ return(keynr);
+}
diff --git a/myisam/mi_rename.c b/myisam/mi_rename.c
new file mode 100644
index 00000000000..6849e1c3d26
--- /dev/null
+++ b/myisam/mi_rename.c
@@ -0,0 +1,56 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/*
+ Rename a table
+*/
+
+#include "fulltext.h"
+#ifdef __WIN__
+#include <errno.h>
+#endif
+
+int mi_rename(const char *old_name, const char *new_name)
+{
+ char from[FN_REFLEN],to[FN_REFLEN];
+#ifdef USE_RAID
+ uint raid_type=0,raid_chunks=0;
+#endif
+ DBUG_ENTER("mi_rename");
+#ifdef USE_RAID
+ {
+ MI_INFO *info;
+ if (!(info=mi_open(old_name, O_RDONLY, 0)))
+ DBUG_RETURN(my_errno);
+ raid_type = info->s->base.raid_type;
+ raid_chunks = info->s->base.raid_chunks;
+ mi_close(info);
+ }
+#endif
+
+ 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)))
+ DBUG_RETURN(my_errno);
+ fn_format(from,old_name,"",MI_NAME_DEXT,4);
+ fn_format(to,new_name,"",MI_NAME_DEXT,4);
+#ifdef USE_RAID
+ if (raid_type)
+ 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);
+}
diff --git a/myisam/mi_rfirst.c b/myisam/mi_rfirst.c
new file mode 100644
index 00000000000..8928c6332c5
--- /dev/null
+++ b/myisam/mi_rfirst.c
@@ -0,0 +1,27 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "myisamdef.h"
+
+ /* Read first row through a specfic key */
+
+int mi_rfirst(MI_INFO *info, byte *buf, int inx)
+{
+ DBUG_ENTER("mi_rfirst");
+ info->lastpos= HA_OFFSET_ERROR;
+ info->update|= HA_STATE_PREV_FOUND;
+ DBUG_RETURN(mi_rnext(info,buf,inx));
+} /* mi_rfirst */
diff --git a/myisam/mi_rkey.c b/myisam/mi_rkey.c
new file mode 100644
index 00000000000..0b88a62e7fc
--- /dev/null
+++ b/myisam/mi_rkey.c
@@ -0,0 +1,89 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* Read record based on a key */
+
+#include "myisamdef.h"
+
+
+ /* Read a record using key */
+ /* Ordinary search_flag is 0 ; Give error if no record with key */
+
+int mi_rkey(MI_INFO *info, byte *buf, int inx, const byte *key, uint key_len,
+ enum ha_rkey_function search_flag)
+{
+ uchar *key_buff;
+ MYISAM_SHARE *share=info->s;
+ uint pack_key_length;
+ DBUG_ENTER("mi_rkey");
+ DBUG_PRINT("enter",("base: %lx inx: %d search_flag: %d",
+ info,inx,search_flag));
+
+ if ((inx = _mi_check_index(info,inx)) < 0)
+ DBUG_RETURN(my_errno);
+
+ info->update&= (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
+ if (key_len == 0)
+ key_len=USE_WHOLE_KEY;
+ key_buff=info->lastkey+info->s->base.max_key_length;
+ pack_key_length=_mi_pack_key(info,(uint) inx,key_buff,(uchar*) key,key_len);
+ info->last_rkey_length=pack_key_length;
+ DBUG_EXECUTE("key",_mi_print_key(DBUG_FILE,share->keyinfo[inx].seg,
+ key_buff,pack_key_length););
+
+ if (_mi_readinfo(info,F_RDLCK,1))
+ 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,
+ myisam_read_vec[search_flag],info->s->state.key_root[inx]))
+ {
+ while (info->lastpos >= info->state->data_file_length)
+ {
+ /*
+ Skip rows that are inserted by other threads since we got a lock
+ Note that this can only happen if we are not searching after an
+ exact key, because the keys are sorted according to position
+ */
+
+ if (_mi_search_next(info,info->s->keyinfo+inx,info->lastkey,
+ info->lastkey_length,
+ myisam_readnext_vec[search_flag],
+ info->s->state.key_root[inx]))
+ break;
+ }
+ }
+ if (share->concurrent_insert)
+ rw_unlock(&share->key_root_lock[inx]);
+
+ if (!(*info->read_record)(info,info->lastpos,buf))
+ {
+ info->update|= HA_STATE_AKTIV; /* Record is read */
+ DBUG_RETURN(0);
+ }
+
+ info->lastpos = HA_OFFSET_ERROR; /* Didn't find key */
+
+ /* Store key for read next */
+ memcpy(info->lastkey,key_buff,pack_key_length);
+ bzero((char*) info->lastkey+pack_key_length,info->s->base.rec_reflength);
+ info->lastkey_length=pack_key_length+info->s->base.rec_reflength;
+
+ if (search_flag == HA_READ_AFTER_KEY)
+ info->update|=HA_STATE_NEXT_FOUND; /* Previous gives last row */
+err:
+ DBUG_RETURN(my_errno);
+} /* mi_rkey */
diff --git a/myisam/mi_rlast.c b/myisam/mi_rlast.c
new file mode 100644
index 00000000000..c08174e9117
--- /dev/null
+++ b/myisam/mi_rlast.c
@@ -0,0 +1,27 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "myisamdef.h"
+
+ /* Read last row with the same key as the previous read. */
+
+int mi_rlast(MI_INFO *info, byte *buf, int inx)
+{
+ DBUG_ENTER("mi_rlast");
+ info->lastpos= HA_OFFSET_ERROR;
+ info->update|= HA_STATE_NEXT_FOUND;
+ DBUG_RETURN(mi_rprev(info,buf,inx));
+} /* mi_rlast */
diff --git a/myisam/mi_rnext.c b/myisam/mi_rnext.c
new file mode 100644
index 00000000000..296aa73793a
--- /dev/null
+++ b/myisam/mi_rnext.c
@@ -0,0 +1,84 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "myisamdef.h"
+
+ /*
+ Read next row with the same key as previous read
+ One may have done a write, update or delete of the previous row.
+ NOTE! Even if one changes the previous row, the next read is done
+ based on the position of the last used key!
+ */
+
+int mi_rnext(MI_INFO *info, byte *buf, int inx)
+{
+ int error;
+ uint flag;
+ DBUG_ENTER("mi_rnext");
+
+ if ((inx = _mi_check_index(info,inx)) < 0)
+ DBUG_RETURN(my_errno);
+ flag=SEARCH_BIGGER; /* Read next */
+ if (info->lastpos == HA_OFFSET_ERROR && info->update & HA_STATE_PREV_FOUND)
+ flag=0; /* Read first */
+
+ if (_mi_readinfo(info,F_RDLCK,1))
+ DBUG_RETURN(my_errno);
+ if (info->s->concurrent_insert)
+ rw_rdlock(&info->s->key_root_lock[inx]);
+ if (!flag)
+ error=_mi_search_first(info,info->s->keyinfo+inx,
+ info->s->state.key_root[inx]);
+ else if (_mi_test_if_changed(info) == 0)
+ error=_mi_search_next(info,info->s->keyinfo+inx,info->lastkey,
+ info->lastkey_length,flag,
+ 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]);
+
+ if (!error)
+ {
+ while (info->lastpos >= info->state->data_file_length)
+ {
+ /* Skip rows that are inserted by other threads since we got a lock */
+ if ((error=_mi_search_next(info,info->s->keyinfo+inx,info->lastkey,
+ info->lastkey_length,
+ flag,
+ info->s->state.key_root[inx])))
+ break;
+ }
+ }
+
+ if (info->s->concurrent_insert)
+ rw_unlock(&info->s->key_root_lock[inx]);
+ /* Don't clear if database-changed */
+ info->update&= (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
+ info->update|= HA_STATE_NEXT_FOUND;
+
+ if (error)
+ {
+ if (my_errno == HA_ERR_KEY_NOT_FOUND)
+ my_errno=HA_ERR_END_OF_FILE;
+ }
+ else if (!(*info->read_record)(info,info->lastpos,buf))
+ {
+ info->update|= HA_STATE_AKTIV; /* Record is read */
+ DBUG_RETURN(0);
+ }
+ DBUG_PRINT("error",("Got error: %d, errno: %d",error, my_errno));
+ DBUG_RETURN(my_errno);
+} /* mi_rnext */
diff --git a/myisam/mi_rnext_same.c b/myisam/mi_rnext_same.c
new file mode 100644
index 00000000000..0e172894cdf
--- /dev/null
+++ b/myisam/mi_rnext_same.c
@@ -0,0 +1,79 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "myisamdef.h"
+
+ /*
+ Read next row with the same key as previous read, but abort if
+ the key changes.
+ One may have done a write, update or delete of the previous row.
+ NOTE! Even if one changes the previous row, the next read is done
+ based on the position of the last used key!
+ */
+
+int mi_rnext_same(MI_INFO *info, byte *buf)
+{
+ int error;
+ uint inx,flag,not_used;
+ MI_KEYDEF *keyinfo;
+ DBUG_ENTER("mi_rnext_same");
+
+ if ((int) (inx=info->lastinx) < 0 || info->lastpos == HA_OFFSET_ERROR)
+ 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))
+ DBUG_RETURN(my_errno);
+
+ memcpy(info->lastkey2,info->lastkey,info->last_rkey_length);
+ if (info->s->concurrent_insert)
+ rw_rdlock(&info->s->key_root_lock[inx]);
+ for (;;)
+ {
+ if ((error=_mi_search_next(info,keyinfo,info->lastkey,
+ info->lastkey_length,flag,
+ info->s->state.key_root[inx])))
+ break;
+ if (_mi_key_cmp(keyinfo->seg,info->lastkey2,info->lastkey,
+ info->last_rkey_length, SEARCH_FIND, &not_used))
+ {
+ error=1;
+ my_errno=HA_ERR_END_OF_FILE;
+ info->lastpos= HA_OFFSET_ERROR;
+ break;
+ }
+ /* Skip rows that are inserted by other threads since we got a lock */
+ if (info->lastpos < info->state->data_file_length)
+ break;
+ }
+ if (info->s->concurrent_insert)
+ rw_unlock(&info->s->key_root_lock[inx]);
+ /* Don't clear if database-changed */
+ info->update&= (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
+ info->update|= HA_STATE_NEXT_FOUND;
+
+ if (error)
+ {
+ if (my_errno == HA_ERR_KEY_NOT_FOUND)
+ my_errno=HA_ERR_END_OF_FILE;
+ }
+ else if (!(*info->read_record)(info,info->lastpos,buf))
+ {
+ info->update|= HA_STATE_AKTIV; /* Record is read */
+ DBUG_RETURN(0);
+ }
+ DBUG_RETURN(my_errno);
+} /* mi_rnext */
diff --git a/myisam/mi_rprev.c b/myisam/mi_rprev.c
new file mode 100644
index 00000000000..f8f89235549
--- /dev/null
+++ b/myisam/mi_rprev.c
@@ -0,0 +1,82 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "myisamdef.h"
+
+ /*
+ Read previous row with the same key as previous read
+ One may have done a write, update or delete of the previous row.
+ NOTE! Even if one changes the previous row, the next read is done
+ based on the position of the last used key!
+ */
+
+int mi_rprev(MI_INFO *info, byte *buf, int inx)
+{
+ int error;
+ register uint flag;
+ MYISAM_SHARE *share=info->s;
+ DBUG_ENTER("mi_rprev");
+
+ if ((inx = _mi_check_index(info,inx)) < 0)
+ DBUG_RETURN(my_errno);
+ flag=SEARCH_SMALLER; /* Read previous */
+ if (info->lastpos == HA_OFFSET_ERROR && info->update & HA_STATE_NEXT_FOUND)
+ flag=0; /* Read last */
+
+ if (_mi_readinfo(info,F_RDLCK,1))
+ DBUG_RETURN(my_errno);
+ if (share->concurrent_insert)
+ rw_rdlock(&share->key_root_lock[inx]);
+ if (!flag)
+ error=_mi_search_last(info, share->keyinfo+inx,
+ share->state.key_root[inx]);
+ else if (_mi_test_if_changed(info) == 0)
+ error=_mi_search_next(info,share->keyinfo+inx,info->lastkey,
+ info->lastkey_length,flag,
+ share->state.key_root[inx]);
+ else
+ error=_mi_search(info,share->keyinfo+inx,info->lastkey,
+ info->lastkey_length, flag, share->state.key_root[inx]);
+
+ if (!error)
+ {
+ while (info->lastpos > info->state->data_file_length)
+ {
+ /* Skip rows that are inserted by other threads since we got a lock */
+ if ((error=_mi_search_next(info,share->keyinfo+inx,info->lastkey,
+ info->lastkey_length,
+ flag,
+ share->state.key_root[inx])))
+ break;
+ }
+ }
+
+ if (share->concurrent_insert)
+ rw_unlock(&share->key_root_lock[inx]);
+ info->update&= (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
+ info->update|= HA_STATE_PREV_FOUND;
+ if (error)
+ {
+ if (my_errno == HA_ERR_KEY_NOT_FOUND)
+ my_errno=HA_ERR_END_OF_FILE;
+ }
+ else if (!(*info->read_record)(info,info->lastpos,buf))
+ {
+ info->update|= HA_STATE_AKTIV; /* Record is read */
+ DBUG_RETURN(0);
+ }
+ DBUG_RETURN(my_errno);
+} /* mi_rprev */
diff --git a/myisam/mi_rrnd.c b/myisam/mi_rrnd.c
new file mode 100644
index 00000000000..11fa2af59bd
--- /dev/null
+++ b/myisam/mi_rrnd.c
@@ -0,0 +1,57 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* Read a record with random-access. The position to the record must
+ get by MI_INFO. The next record can be read with pos= MI_POS_ERROR */
+
+
+#include "myisamdef.h"
+
+/*
+ Read a row based on position.
+ If filepos= HA_OFFSET_ERROR then read next row
+ Return values
+ Returns one of following values:
+ 0 = Ok.
+ HA_ERR_RECORD_DELETED = Record is deleted.
+ HA_ERR_END_OF_FILE = EOF.
+*/
+
+int mi_rrnd(MI_INFO *info, byte *buf, register my_off_t filepos)
+{
+ my_bool skipp_deleted_blocks;
+ DBUG_ENTER("mi_rrnd");
+
+ skipp_deleted_blocks=0;
+
+ if (filepos == HA_OFFSET_ERROR)
+ {
+ skipp_deleted_blocks=1;
+ if (info->lastpos == HA_OFFSET_ERROR) /* First read ? */
+ filepos= info->s->pack.header_length; /* Read first record */
+ else
+ filepos= info->nextpos;
+ }
+
+ info->lastinx= -1; /* Can't forward or backward */
+ /* Init all but update-flag */
+ info->update&= (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
+
+ if (info->opt_flag & WRITE_CACHE_USED && flush_io_cache(&info->rec_cache))
+ DBUG_RETURN(my_errno);
+
+ DBUG_RETURN ((*info->s->read_rnd)(info,buf,filepos,skipp_deleted_blocks));
+}
diff --git a/myisam/mi_rsame.c b/myisam/mi_rsame.c
new file mode 100644
index 00000000000..a4092b53c0b
--- /dev/null
+++ b/myisam/mi_rsame.c
@@ -0,0 +1,65 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 "myisamdef.h"
+
+ /*
+ ** Find current row with read on position or read on key
+ ** If inx >= 0 find record using key
+ ** Return values:
+ ** 0 = Ok.
+ ** HA_ERR_KEY_NOT_FOUND = Row is deleted
+ ** HA_ERR_END_OF_FILE = End of file
+ */
+
+
+int mi_rsame(MI_INFO *info, byte *record, int inx)
+{
+ DBUG_ENTER("mi_rsame");
+
+ if (inx != -1 && ! (((ulonglong) 1 << inx) & info->s->state.key_map))
+ {
+ DBUG_RETURN(my_errno=HA_ERR_WRONG_INDEX);
+ }
+ if (info->lastpos == HA_OFFSET_ERROR || info->update & HA_STATE_DELETED)
+ {
+ DBUG_RETURN(my_errno=HA_ERR_KEY_NOT_FOUND); /* No current record */
+ }
+ info->update&= (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
+
+ /* Read row from data file */
+ if (_mi_readinfo(info,F_RDLCK,1))
+ DBUG_RETURN(my_errno);
+
+ if (inx >= 0)
+ {
+ info->lastinx=inx;
+ info->lastkey_length=_mi_make_key(info,(uint) inx,info->lastkey,record,
+ 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,
+ info->s->state.key_root[inx]));
+ if (info->s->concurrent_insert)
+ rw_unlock(&info->s->key_root_lock[inx]);
+ }
+
+ if (!(*info->read_record)(info,info->lastpos,record))
+ DBUG_RETURN(0);
+ if (my_errno == HA_ERR_RECORD_DELETED)
+ my_errno=HA_ERR_KEY_NOT_FOUND;
+ DBUG_RETURN(my_errno);
+} /* mi_rsame */
diff --git a/myisam/mi_rsamepos.c b/myisam/mi_rsamepos.c
new file mode 100644
index 00000000000..28a5b6783b2
--- /dev/null
+++ b/myisam/mi_rsamepos.c
@@ -0,0 +1,56 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* read record through position and fix key-position */
+/* As mi_rsame but supply a position */
+
+#include "myisamdef.h"
+
+
+ /*
+ ** If inx >= 0 update index pointer
+ ** Returns one of the following values:
+ ** 0 = Ok.
+ ** HA_ERR_KEY_NOT_FOUND = Row is deleted
+ ** HA_ERR_END_OF_FILE = End of file
+ */
+
+int mi_rsame_with_pos(MI_INFO *info, byte *record, int inx, my_off_t filepos)
+{
+ DBUG_ENTER("mi_rsame_with_pos");
+
+ if (inx < -1 || ! (((ulonglong) 1 << inx) & info->s->state.key_map))
+ {
+ DBUG_RETURN(my_errno=HA_ERR_WRONG_INDEX);
+ }
+
+ info->update&= (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
+ if ((*info->s->read_rnd)(info,record,filepos,0))
+ {
+ if (my_errno == HA_ERR_RECORD_DELETED)
+ my_errno=HA_ERR_KEY_NOT_FOUND;
+ DBUG_RETURN(my_errno);
+ }
+ info->lastpos=filepos;
+ info->lastinx=inx;
+ if (inx >= 0)
+ {
+ info->lastkey_length=_mi_make_key(info,(uint) inx,info->lastkey,record,
+ info->lastpos);
+ info->update|=HA_STATE_KEY_CHANGED; /* Don't use indexposition */
+ }
+ DBUG_RETURN(0);
+} /* mi_rsame_pos */
diff --git a/myisam/mi_scan.c b/myisam/mi_scan.c
new file mode 100644
index 00000000000..c06f092ab17
--- /dev/null
+++ b/myisam/mi_scan.c
@@ -0,0 +1,46 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 through all rows sequntially */
+
+#include "myisamdef.h"
+
+int mi_scan_init(register MI_INFO *info)
+{
+ DBUG_ENTER("mi_scan_init");
+ info->nextpos=info->s->pack.header_length; /* Read first record */
+ info->lastinx= -1; /* Can't forward or backward */
+ if (info->opt_flag & WRITE_CACHE_USED && flush_io_cache(&info->rec_cache))
+ DBUG_RETURN(my_errno);
+ DBUG_RETURN(0);
+}
+
+/*
+ Read a row based on position.
+ If filepos= HA_OFFSET_ERROR then read next row
+ Return values
+ Returns one of following values:
+ 0 = Ok.
+ HA_ERR_END_OF_FILE = EOF.
+*/
+
+int mi_scan(MI_INFO *info, byte *buf)
+{
+ DBUG_ENTER("mi_scan");
+ /* Init all but update-flag */
+ info->update&= (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
+ DBUG_RETURN ((*info->s->read_rnd)(info,buf,info->nextpos,1));
+}
diff --git a/myisam/mi_search.c b/myisam/mi_search.c
new file mode 100644
index 00000000000..e7a654c4da8
--- /dev/null
+++ b/myisam/mi_search.c
@@ -0,0 +1,1877 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* key handling functions */
+
+#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);
+
+ /* Check index */
+
+int _mi_check_index(MI_INFO *info, int inx)
+{
+ 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 */
+ {
+ 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);
+ }
+ if (info->opt_flag & WRITE_CACHE_USED && flush_io_cache(&info->rec_cache))
+ return(-1);
+ return(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
+ */
+
+int _mi_search(register MI_INFO *info, register MI_KEYDEF *keyinfo,
+ uchar *key, uint key_len, uint nextflag, register my_off_t pos)
+{
+ my_bool last_key;
+ int error,flag;
+ uint nod_flag;
+ uchar *keypos,*maxpos;
+ uchar lastkey[MI_MAX_KEY_BUFF],*buff;
+ DBUG_ENTER("_mi_search");
+ DBUG_PRINT("enter",("pos: %ld nextflag: %d lastpos: %ld",
+ 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 */
+ 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 */
+ }
+
+ if (!(buff=_mi_fetch_keypage(info,keyinfo,pos,info->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);
+ if (flag == MI_FOUND_WRONG_KEY)
+ DBUG_RETURN(-1);
+ nod_flag=mi_test_if_nod(buff);
+ maxpos=buff+mi_getint(buff)-1;
+
+ if (flag)
+ {
+ if ((error=_mi_search(info,keyinfo,key,key_len,nextflag,
+ _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 */
+ }
+ else if (nextflag & SEARCH_BIGGER && keypos >= maxpos)
+ DBUG_RETURN(1); /* Smaller than key */
+ }
+ else
+ {
+ if (nextflag & SEARCH_FIND && (!(keyinfo->flag & HA_NOSAME)
+ || key_len) && nod_flag)
+ {
+ 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 */
+ }
+ }
+ if (pos != info->last_keypage)
+ {
+ uchar *old_buff=buff;
+ if (!(buff=_mi_fetch_keypage(info,keyinfo,pos,info->buff,
+ test(!(nextflag & SEARCH_SAVE_BUFF)))))
+ goto err;
+ keypos=buff+(keypos-old_buff);
+ maxpos=buff+(maxpos-old_buff);
+ }
+
+ if ((nextflag & (SEARCH_SMALLER | SEARCH_LAST)) && flag != 0)
+ {
+ uint not_used;
+ if (_mi_get_prev_key(info,keyinfo, buff, info->lastkey, keypos,
+ &info->lastkey_length))
+ goto err;
+ if ((nextflag & SEARCH_LAST) &&
+ _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 */
+ goto err;
+ }
+ }
+ else
+ {
+ info->lastkey_length=(*keyinfo->get_key)(keyinfo,nod_flag,&keypos,lastkey);
+ if (!info->lastkey_length)
+ goto err;
+ memcpy(info->lastkey,lastkey,info->lastkey_length);
+ }
+ info->lastpos=_mi_dpos(info,0,info->lastkey+info->lastkey_length);
+ /* Save position for a possible read next / previous */
+ info->int_keypos=info->buff+ (keypos-buff);
+ info->int_maxpos=info->buff+ (maxpos-buff);
+ info->int_nod_flag=nod_flag;
+ 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 */
+
+ DBUG_PRINT("exit",("found key at %ld",info->lastpos));
+ DBUG_RETURN(0);
+err:
+ DBUG_PRINT("exit",("Error: %d",my_errno));
+ info->lastpos= HA_OFFSET_ERROR;
+ info->page_changed=1;
+ DBUG_RETURN (-1);
+} /* _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 */
+
+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)
+{
+ reg4 int start,mid,end,save_end;
+ int flag;
+ uint totlength,nod_flag,not_used;
+ DBUG_ENTER("_mi_bin_search");
+
+ LINT_INIT(flag);
+ totlength=keyinfo->keylength+(nod_flag=mi_test_if_nod(page));
+ start=0; mid=1;
+ save_end=end=(int) ((mi_getint(page)-2-nod_flag)/totlength-1);
+ DBUG_PRINT("test",("mi_getint: %d end: %d",mi_getint(page),end));
+ page+=2+nod_flag;
+
+ while (start != end)
+ {
+ mid= (start+end)/2;
+ if ((flag=_mi_key_cmp(keyinfo->seg,page+(uint) mid*totlength,key,key_len,
+ 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);
+ if (flag < 0)
+ 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));
+ DBUG_RETURN(flag);
+} /* _mi_bin_search */
+
+
+ /* 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)
+{
+ int flag;
+ uint nod_flag,length,not_used;
+ uchar t_buff[MI_MAX_KEY_BUFF],*end;
+ DBUG_ENTER("_mi_seq_search");
+
+ LINT_INIT(flag); LINT_INIT(length);
+ end= page+mi_getint(page);
+ nod_flag=mi_test_if_nod(page);
+ page+=2+nod_flag;
+ *ret_pos=page;
+ t_buff[0]=0; /* Avoid bugs */
+ while (page < end)
+ {
+ length=(*keyinfo->get_key)(keyinfo,nod_flag,&page,t_buff);
+ if (length == 0 || 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 ((flag=_mi_key_cmp(keyinfo->seg,t_buff,key,key_len,comp_flag,
+ &not_used)) >= 0)
+ break;
+#ifdef EXTRA_DEBUG
+ DBUG_PRINT("loop",("page: %lx key: '%s' flag: %d",page,t_buff,flag));
+#endif
+ memcpy(buff,t_buff,length);
+ *ret_pos=page;
+ }
+ if (flag == 0)
+ memcpy(buff,t_buff,length); /* Result is first key */
+ *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 */
+
+my_off_t _mi_kpos(uint nod_flag, uchar *after_key)
+{
+ after_key-=nod_flag;
+ switch (nod_flag) {
+#if SIZEOF_OFF_T > 4
+ case 7:
+ return mi_uint7korr(after_key)*MI_KEY_BLOCK_LENGTH;
+ case 6:
+ return mi_uint6korr(after_key)*MI_KEY_BLOCK_LENGTH;
+ case 5:
+ return mi_uint5korr(after_key)*MI_KEY_BLOCK_LENGTH;
+#else
+ case 7:
+ after_key++;
+ case 6:
+ after_key++;
+ case 5:
+ after_key++;
+#endif
+ case 4:
+ return ((my_off_t) mi_uint4korr(after_key))*MI_KEY_BLOCK_LENGTH;
+ case 3:
+ return ((my_off_t) mi_uint3korr(after_key))*MI_KEY_BLOCK_LENGTH;
+ case 2:
+ return (my_off_t) (mi_uint2korr(after_key)*MI_KEY_BLOCK_LENGTH);
+ case 1:
+ return (uint) (*after_key)*MI_KEY_BLOCK_LENGTH;
+ case 0: /* At leaf page */
+ default: /* Impossible */
+ return(HA_OFFSET_ERROR);
+ }
+} /* _kpos */
+
+
+ /* 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;
+ switch (info->s->base.key_reflength) {
+#if SIZEOF_OFF_T > 4
+ case 7: mi_int7store(buff,pos); break;
+ case 6: mi_int6store(buff,pos); break;
+ case 5: mi_int5store(buff,pos); break;
+#else
+ case 7: *buff++=0;
+ /* fall trough */
+ case 6: *buff++=0;
+ /* fall trough */
+ case 5: *buff++=0;
+ /* fall trough */
+#endif
+ case 4: mi_int4store(buff,pos); break;
+ case 3: mi_int3store(buff,pos); break;
+ case 2: mi_int2store(buff,(uint) pos); break;
+ case 1: buff[0]= (uchar) pos; break;
+ default: abort(); /* impossible */
+ }
+} /* _mi_kpointer */
+
+
+ /* Calc pos to a data-record from a key */
+
+
+my_off_t _mi_dpos(MI_INFO *info, uint nod_flag, uchar *after_key)
+{
+ my_off_t pos;
+ after_key-=(nod_flag + info->s->rec_reflength);
+ switch (info->s->rec_reflength) {
+#if SIZEOF_OFF_T > 4
+ case 8: pos= (my_off_t) mi_uint5korr(after_key); break;
+ case 7: pos= (my_off_t) mi_uint7korr(after_key); break;
+ case 6: pos= (my_off_t) mi_uint6korr(after_key); break;
+ 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;
+#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 */
+ }
+ return (info->s->options &
+ (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)) ? pos :
+ pos*info->s->base.pack_reclength;
+}
+
+
+/* Calc position from a record pointer ( in delete link chain ) */
+
+my_off_t _mi_rec_pos(MYISAM_SHARE *s, uchar *ptr)
+{
+ my_off_t pos;
+ switch (s->rec_reflength) {
+#if SIZEOF_OFF_T > 4
+ case 8:
+ pos= (my_off_t) mi_uint8korr(ptr);
+ if (pos == HA_OFFSET_ERROR)
+ 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 */
+ 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 */
+ 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 */
+ break;
+#else
+ case 8:
+ case 7:
+ case 6:
+ case 5:
+ ptr+= (s->rec_reflength-4);
+ /* fall through */
+#endif
+ case 4:
+ pos= (my_off_t) mi_uint4korr(ptr);
+ if (pos == (my_off_t) (uint32) ~0L)
+ return HA_OFFSET_ERROR;
+ break;
+ case 3:
+ pos= (my_off_t) mi_uint3korr(ptr);
+ if (pos == (my_off_t) (1 << 24) -1)
+ return HA_OFFSET_ERROR;
+ break;
+ case 2:
+ pos= (my_off_t) mi_uint2korr(ptr);
+ if (pos == (my_off_t) (1 << 16) -1)
+ return HA_OFFSET_ERROR;
+ break;
+ default: abort(); /* Impossible */
+ }
+ return ((s->options &
+ (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)) ? pos :
+ pos*s->base.pack_reclength);
+}
+
+
+ /* 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)) &&
+ pos != HA_OFFSET_ERROR)
+ pos/=info->s->base.pack_reclength;
+
+ switch (info->s->rec_reflength) {
+#if SIZEOF_OFF_T > 4
+ case 8: mi_int8store(buff,pos); break;
+ case 7: mi_int7store(buff,pos); break;
+ case 6: mi_int6store(buff,pos); break;
+ case 5: mi_int5store(buff,pos); break;
+#else
+ case 8: *buff++=0;
+ /* fall trough */
+ case 7: *buff++=0;
+ /* fall trough */
+ case 6: *buff++=0;
+ /* fall trough */
+ case 5: *buff++=0;
+ /* fall trough */
+#endif
+ 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 */
+ }
+} /* _mi_dpointer */
+
+
+int _mi_compare_text(CHARSET_INFO *charset_info, uchar *a, uint a_length,
+ 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;
+ }
+ else
+#endif
+ {
+ uchar *sort_order=charset_info->sort_order;
+ while (a < end)
+ if ((flag= (int) sort_order[*a++] - (int) sort_order[*b++]))
+ return flag;
+ }
+ if (part_key && b_length < a_length)
+ return 0;
+ return (int) (a_length-b_length);
+}
+
+
+static int compare_bin(uchar *a, uint a_length, uchar *b, uint b_length,
+ my_bool part_key)
+{
+ uint length= min(a_length,b_length);
+ uchar *end= a+ length;
+ int flag;
+
+ while (a < end)
+ if ((flag= (int) *a++ - (int) *b++))
+ return flag;
+ if (part_key && b_length < a_length)
+ return 0;
+ return (int) (a_length-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
+ */
+
+#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)
+{
+ int flag;
+ int16 s_1,s_2;
+ int32 l_1,l_2;
+ uint32 u_1,u_2;
+ float f_1,f_2;
+ double d_1,d_2;
+ 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;
+ (*diff_pos)++;
+
+ /* Handle NULL part */
+ if (keyseg->null_bit)
+ {
+ key_length--;
+ if (*a != *b)
+ {
+ flag = (int) *a - (int) *b;
+ return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
+ }
+ b++;
+ 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 */
+ }
+ }
+ 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 */
+ 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;
+ }
+ 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;
+ }
+ 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;
+ }
+ 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;
+ }
+ 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;
+ }
+ 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;
+ }
+ 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);
+ a= end;
+ b++;
+ break;
+ }
+ 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);
+ 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;
+ }
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ a= end;
+ b+= 8; /* sizeof(double); */
+ break;
+ 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 */
+ end= a+ (int) (end-b);
+ }
+ if (keyseg->flag & HA_SPACE_PACK)
+ {
+ alength= *a++; blength= *b++;
+ end=a+alength;
+ }
+ else
+ {
+ 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 (*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]);
+
+ if (swap_flag) /* Restore pointers */
+ swap(uchar*,a,b);
+ break;
+ }
+#ifdef HAVE_LONG_LONG
+ case HA_KEYTYPE_LONGLONG:
+ {
+ 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);
+ a= end;
+ b+= 8;
+ break;
+ }
+ case HA_KEYTYPE_ULONGLONG:
+ {
+ 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);
+ a= end;
+ b+= 8;
+ break;
+ }
+#endif
+ case HA_KEYTYPE_END: /* Ready */
+ goto end; /* diff_pos is incremented */
+ }
+ }
+ (*diff_pos)++;
+end:
+ if (!(nextflag & SEARCH_FIND))
+ {
+ uint i;
+ if (nextflag & (SEARCH_NO_FIND | SEARCH_LAST)) /* Find record after key */
+ return (nextflag & (SEARCH_BIGGER | SEARCH_LAST)) ? -1 : 1;
+ flag=0;
+ for (i=keyseg->length ; i-- > 0 ; )
+ {
+ if (*a++ != *b++)
+ {
+ flag= FCMP(a[-1],b[-1]);
+ break;
+ }
+ }
+ if (nextflag & SEARCH_SAME)
+ return (flag); /* read same */
+ if (nextflag & SEARCH_BIGGER)
+ return (flag <= 0 ? -1 : 1); /* read next */
+ return (flag < 0 ? -1 : 1); /* read previous */
+ }
+ return 0;
+} /* _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 */
+
+ /* 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)
+{
+ memcpy((byte*) key,(byte*) *page,
+ (size_t) (keyinfo->keylength+nod_flag));
+ *page+=keyinfo->keylength+nod_flag;
+ return(keyinfo->keylength);
+} /* _mi_get_static_key */
+
+
+
+uint _mi_get_pack_key(register MI_KEYDEF *keyinfo, uint nod_flag,
+ register uchar **page_pos, register uchar *key)
+{
+ reg1 MI_KEYSEG *keyseg;
+ uchar *start_key,*page=*page_pos;
+ uint length;
+
+ start_key=key;
+ for (keyseg=keyinfo->seg ; keyseg->type ;keyseg++)
+ {
+ /* First key part is always packed !*/
+ if (keyseg->flag & HA_PACK_KEY)
+ {
+ /* key with length, packed to previous key */
+ uchar *start=key;
+ uint packed= *page & 128,tot_length,rest_length;
+ if (keyseg->length >= 127)
+ {
+ length=mi_uint2korr(page) & 32767;
+ page+=2;
+ }
+ else
+ length= *page++ & 127;
+
+ if (packed)
+ {
+ if (length > (uint) keyseg->length)
+ {
+ my_errno=HA_ERR_CRASHED;
+ return 0; /* Error */
+ }
+ if (length == 0) /* Same key */
+ {
+ if (keyseg->flag & HA_NULL_PART)
+ *key++=1; /* Can't be NULL */
+ get_key_length(length,key);
+ key+= length; /* Same diff_key as prev */
+ if (length > keyseg->length)
+ {
+ DBUG_PRINT("error",("Found too long null 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;
+ }
+ continue;
+ }
+ if (keyseg->flag & HA_NULL_PART)
+ key++; /* Skipp null marker*/
+
+ get_key_length(rest_length,page);
+ tot_length=rest_length+length;
+
+ /* If the stored length has changed, we must move the key */
+ if (tot_length >= 255 && *start != 255)
+ {
+ /* length prefix changed from a length of one to a length of 3 */
+ bmove_upp((char*) key+length+3,(char*) key+length+1,length);
+ *key=255;
+ mi_int2store(key+1,tot_length);
+ key+=3+length;
+ }
+ else if (tot_length < 255 && *start == 255)
+ {
+ bmove(key+1,key+3,length);
+ *key=tot_length;
+ key+=1+length;
+ }
+ else
+ {
+ store_key_length_inc(key,tot_length);
+ key+=length;
+ }
+ memcpy(key,page,rest_length);
+ page+=rest_length;
+ key+=rest_length;
+ continue;
+ }
+ else
+ {
+ 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 */
+ }
+ store_key_length_inc(key,length);
+ }
+ else
+ {
+ if (keyseg->flag & HA_NULL_PART)
+ {
+ if (!(*key++ = *page++))
+ continue;
+ }
+ if (keyseg->flag &
+ (HA_VAR_LENGTH | HA_BLOB_PART | HA_SPACE_PACK))
+ {
+ uchar *tmp=page;
+ get_key_length(length,tmp);
+ length+=(uint) (tmp-page);
+ }
+ else
+ length=keyseg->length;
+ }
+ memcpy((byte*) key,(byte*) page,(size_t) length);
+ key+=length;
+ page+=length;
+ }
+ length=keyseg->length+nod_flag;
+ bmove((byte*) key,(byte*) page,length);
+ *page_pos= page+length;
+ return ((uint) (key-start_key)+keyseg->length);
+} /* _mi_get_pack_key */
+
+
+
+/* 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)
+{
+ reg1 MI_KEYSEG *keyseg;
+ uchar *start_key,*page=*page_pos,*page_end,*from,*from_end;
+ uint length,tmp;
+
+ page_end=page+MI_MAX_KEY_BUFF+1;
+ start_key=key;
+
+ get_key_length(length,page);
+ if (length)
+ {
+ if (length > keyinfo->maxlength)
+ {
+ DBUG_PRINT("error",("Found too long binary packed key: %d of %d at %lx",
+ length, keyinfo->maxlength, *page_pos));
+ DBUG_DUMP("key",(char*) *page_pos,16);
+ my_errno=HA_ERR_CRASHED;
+ return 0; /* Wrong key */
+ }
+ from=key; from_end=key+length;
+ }
+ else
+ {
+ from=page; from_end=page_end; /* Not packed key */
+ }
+
+ /*
+ The trouble is that key is split in two parts:
+ The first part is in from ...from_end-1.
+ The second part starts at page
+ */
+ for (keyseg=keyinfo->seg ; keyseg->type ;keyseg++)
+ {
+ if (keyseg->flag & HA_NULL_PART)
+ {
+ if (from == from_end) { from=page; from_end=page_end; }
+ if (!(*key++ = *from++))
+ continue; /* Null part */
+ }
+ if (keyseg->flag & (HA_VAR_LENGTH | HA_BLOB_PART | HA_SPACE_PACK))
+ {
+ /* Get length of dynamic length key part */
+ 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++));
+ }
+ }
+ else
+ length=keyseg->length;
+
+ if ((tmp=(uint) (from_end-from)) <= length)
+ {
+ key+=tmp; /* Use old key */
+ length-=tmp;
+ from=page; from_end=page_end;
+ }
+ memcpy((byte*) key,(byte*) from,(size_t) length);
+ key+=length;
+ from+=length;
+ }
+ length=keyseg->length+nod_flag;
+ if ((tmp=(uint) (from_end-from)) <= length)
+ {
+ memcpy(key+tmp,page,length-tmp); /* Get last part of key */
+ *page_pos= page+length-tmp;
+ }
+ else
+ {
+ if (from_end != page_end)
+ {
+ DBUG_PRINT("error",("Error when unpacking key"));
+ my_errno=HA_ERR_CRASHED;
+ return 0; /* Error */
+ }
+ memcpy((byte*) key,(byte*) from,(size_t) length);
+ *page_pos= from+length;
+ }
+ return((uint) (key-start_key)+keyseg->length);
+}
+
+
+ /* 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)
+{
+ uint nod_flag;
+ DBUG_ENTER("_mi_get_key");
+
+ nod_flag=mi_test_if_nod(page);
+ if (! (keyinfo->flag & (HA_VAR_LENGTH_KEY | HA_BINARY_PACK_KEY)))
+ {
+ bmove((byte*) key,(byte*) keypos,keyinfo->keylength+nod_flag);
+ DBUG_RETURN(keypos+keyinfo->keylength+nod_flag);
+ }
+ else
+ {
+ page+=2+nod_flag;
+ 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);
+ }
+ }
+ }
+ DBUG_PRINT("exit",("page: %lx length: %d",page,*return_key_length));
+ DBUG_RETURN(page);
+} /* _mi_get_key */
+
+
+ /* 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)
+{
+ uint nod_flag;
+ DBUG_ENTER("_mi_get_prev_key");
+
+ nod_flag=mi_test_if_nod(page);
+ if (! (keyinfo->flag & (HA_VAR_LENGTH_KEY | HA_BINARY_PACK_KEY)))
+ {
+ *return_key_length=keyinfo->keylength;
+ bmove((byte*) key,(byte*) keypos- *return_key_length-nod_flag,
+ *return_key_length);
+ DBUG_RETURN(0);
+ }
+ else
+ {
+ page+=2+nod_flag;
+ 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);
+ }
+ }
+ }
+ DBUG_RETURN(0);
+} /* _mi_get_key */
+
+
+
+ /* 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)
+{
+ uint nod_flag;
+ uchar *lastpos;
+ DBUG_ENTER("_mi_get_last_key");
+ DBUG_PRINT("enter",("page: %lx endpos: %lx",page,endpos));
+
+ nod_flag=mi_test_if_nod(page);
+ if (! (keyinfo->flag & (HA_VAR_LENGTH_KEY | HA_BINARY_PACK_KEY)))
+ {
+ lastpos=endpos-keyinfo->keylength-nod_flag;
+ *return_key_length=keyinfo->keylength;
+ if (lastpos > page)
+ bmove((byte*) lastkey,(byte*) lastpos,keyinfo->keylength+nod_flag);
+ }
+ else
+ {
+ lastpos=(page+=2+nod_flag);
+ lastkey[0]=0;
+ while (page < endpos)
+ {
+ lastpos=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("exit",("lastpos: %lx length: %d",lastpos,*return_key_length));
+ DBUG_RETURN(lastpos);
+} /* _mi_get_last_key */
+
+
+ /* Calculate length of key */
+
+uint _mi_keylength(MI_KEYDEF *keyinfo, register uchar *key)
+{
+ reg1 MI_KEYSEG *keyseg;
+ uchar *start;
+
+ if (! (keyinfo->flag & (HA_VAR_LENGTH_KEY | HA_BINARY_PACK_KEY)))
+ return (keyinfo->keylength);
+
+ start=key;
+ for (keyseg=keyinfo->seg ; keyseg->type ; keyseg++)
+ {
+ if (keyseg->flag & HA_NULL_PART)
+ if (!*key++)
+ continue;
+ if (keyseg->flag & (HA_SPACE_PACK | HA_BLOB_PART | HA_VAR_LENGTH))
+ {
+ uint length;
+ get_key_length(length,key);
+ key+=length;
+ }
+ else
+ key+= keyseg->length;
+ }
+ return((uint) (key-start)+keyseg->length);
+} /* _mi_keylength */
+
+
+ /* 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)));
+ return to+length;
+}
+
+ /* 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)
+{
+ 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));
+ 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
+ and the key tree has changed since we used it last time */
+
+ if (((nextflag & SEARCH_BIGGER) && info->int_keypos >= info->int_maxpos) ||
+ 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));
+
+ if (info->buff_used)
+ {
+ if (!_mi_fetch_keypage(info,keyinfo,info->last_search_keypage,
+ 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 */
+ {
+ 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 (!(info->lastkey_length=(*keyinfo->get_key)(keyinfo,nod_flag,
+ &info->int_keypos,lastkey)))
+ DBUG_RETURN(-1);
+ }
+ 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);
+ 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(error);
+
+ if (! _mi_get_last_key(info,keyinfo,info->buff,lastkey,
+ info->int_keypos,&info->lastkey_length))
+ DBUG_RETURN(-1);
+ }
+ memcpy(info->lastkey,lastkey,info->lastkey_length);
+ info->lastpos=_mi_dpos(info,0,info->lastkey+info->lastkey_length);
+ DBUG_PRINT("exit",("found key at %d",info->lastpos));
+ DBUG_RETURN(0);
+} /* _mi_search_next */
+
+
+ /* 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)
+{
+ uint nod_flag;
+ uchar *page;
+ DBUG_ENTER("_mi_search_first");
+
+ if (pos == HA_OFFSET_ERROR)
+ {
+ my_errno=HA_ERR_KEY_NOT_FOUND;
+ info->lastpos= HA_OFFSET_ERROR;
+ DBUG_RETURN(-1);
+ }
+
+ do
+ {
+ if (!_mi_fetch_keypage(info,keyinfo,pos,info->buff,0))
+ {
+ info->lastpos= HA_OFFSET_ERROR;
+ DBUG_RETURN(-1);
+ }
+ nod_flag=mi_test_if_nod(info->buff);
+ page=info->buff+2+nod_flag;
+ } while ((pos=_mi_kpos(nod_flag,page)) != HA_OFFSET_ERROR);
+
+ info->lastkey_length=(*keyinfo->get_key)(keyinfo,nod_flag,&page,
+ info->lastkey);
+ 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;
+ info->last_search_keypage=info->last_keypage;
+ info->page_changed=info->buff_used=0;
+ info->lastpos=_mi_dpos(info,0,info->lastkey+info->lastkey_length);
+
+ DBUG_PRINT("exit",("found key at %d",info->lastpos));
+ DBUG_RETURN(0);
+} /* _mi_search_first */
+
+
+ /* 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)
+{
+ uint nod_flag;
+ uchar *buff,*page;
+ DBUG_ENTER("_mi_search_last");
+
+ if (pos == HA_OFFSET_ERROR)
+ {
+ my_errno=HA_ERR_KEY_NOT_FOUND; /* Didn't find key */
+ info->lastpos= HA_OFFSET_ERROR;
+ DBUG_RETURN(-1);
+ }
+
+ buff=info->buff;
+ do
+ {
+ if (!_mi_fetch_keypage(info,keyinfo,pos,buff,0))
+ {
+ info->lastpos= HA_OFFSET_ERROR;
+ DBUG_RETURN(-1);
+ }
+ page= buff+mi_getint(buff);
+ nod_flag=mi_test_if_nod(buff);
+ } while ((pos=_mi_kpos(nod_flag,page)) != HA_OFFSET_ERROR);
+
+ if (!_mi_get_last_key(info,keyinfo,buff,info->lastkey,page,
+ &info->lastkey_length))
+ DBUG_RETURN(-1);
+ info->lastpos=_mi_dpos(info,0,info->lastkey+info->lastkey_length);
+ info->int_keypos=info->int_maxpos=page;
+ info->int_nod_flag=nod_flag;
+ info->int_keytree_version=keyinfo->version;
+ info->last_search_keypage=info->last_keypage;
+ info->page_changed=info->buff_used=0;
+
+ DBUG_PRINT("exit",("found key at %d",info->lastpos));
+ DBUG_RETURN(0);
+} /* _mi_search_last */
+
+
+
+/****************************************************************************
+**
+** 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
+****************************************************************************/
+
+/* 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)
+{
+ s_temp->key=key;
+ return (int) (s_temp->totlength=keyinfo->keylength+nod_flag);
+}
+
+/* Variable length key */
+
+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)
+{
+ s_temp->key=key;
+ return (int) (s_temp->totlength=_mi_keylength(keyinfo,key)+nod_flag);
+}
+
+/*
+ length of key with a variable length first segment which is prefix
+ compressed (myisamchk reports 'packed + stripped')
+
+ Keys are compressed the following way:
+
+ If the max length of first key segment <= 127 characters the prefix is
+ 1 byte else its 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
+
+ If the first segment can have NULL:
+ The length is 0 for NULLS and 1+length for not null columns.
+
+*/
+
+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)
+{
+ reg1 MI_KEYSEG *keyseg;
+ int length;
+ uint key_length,ref_length,org_key_length=0,
+ length_pack,new_key_length,diff_flag,pack_marker;
+ uchar *start,*end,*key_end,*sort_order;
+ bool same_length;
+
+ length_pack=s_temp->ref_length=s_temp->n_ref_length=s_temp->n_length=0;
+ same_length=0; keyseg=keyinfo->seg;
+ key_length=_mi_keylength(keyinfo,key)+nod_flag;
+
+ sort_order=0;
+ if ((keyinfo->flag & HA_FULLTEXT) &&
+ ((keyseg->type == HA_KEYTYPE_TEXT) ||
+ (keyseg->type == HA_KEYTYPE_VARTEXT)) &&
+ !use_strcoll(keyseg->charset))
+ sort_order=keyseg->charset->sort_order;
+
+ /* diff flag contains how many bytes is needed to pack key */
+ if (keyseg->length >= 127)
+ {
+ diff_flag=2;
+ pack_marker=32768;
+ }
+ else
+ {
+ diff_flag= 1;
+ pack_marker=128;
+ }
+ s_temp->pack_marker=pack_marker;
+
+ /* Handle the case that the first part have NULL values */
+ if (keyseg->flag & HA_NULL_PART)
+ {
+ if (!*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 */
+ return (s_temp->totlength);
+ }
+ s_temp->store_not_null=1;
+ key_length--; /* We don't store NULL */
+ if (prev_key && !*prev_key++)
+ org_key=prev_key=0; /* Can't pack against prev */
+ else if (org_key)
+ org_key++; /* Skipp NULL */
+ }
+ else
+ s_temp->store_not_null=0;
+ s_temp->prev_key=org_key;
+
+ /* The key part will start with a packed length */
+
+ get_key_pack_length(new_key_length,length_pack,key);
+ end=key_end= key+ new_key_length;
+ start=key;
+
+ /* Calc how many characters are identical between this and the prev. key */
+ if (prev_key)
+ {
+ get_key_length(org_key_length,prev_key);
+ 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+1;
+
+ if (sort_order) /* SerG */
+ {
+ while (key < end && sort_order[*key] == sort_order[*prev_key])
+ {
+ key++; prev_key++;
+ }
+ }
+ else
+ {
+ while (key < end && *key == *prev_key)
+ {
+ key++; prev_key++;
+ }
+ }
+ }
+
+ s_temp->key=key;
+ s_temp->key_length= (uint) (key_end-key);
+
+ if (same_length && key == key_end)
+ {
+ /* identical variable length key */
+ s_temp->ref_length= pack_marker;
+ 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 */
+ next_key=0;
+ }
+ }
+ else
+ {
+ if (start != key)
+ { /* Starts as prev key */
+ ref_length= (uint) (key-start);
+ s_temp->ref_length= ref_length + pack_marker;
+ length= (int) (key_length - ref_length);
+
+ length-= length_pack;
+ length+= diff_flag;
+ length+= ((new_key_length-ref_length) >= 255) ? 3 : 1;/* Rest_of_key */
+ }
+ else
+ {
+ 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));
+
+ /* 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;
+
+ packed = *next_key & 128;
+ if (diff_flag == 2)
+ {
+ n_length= mi_uint2korr(next_key) & 32767; /* Length of next key */
+ next_key+=2;
+ }
+ else
+ n_length= *next_key++ & 127;
+ if (!packed)
+ n_length-= s_temp->store_not_null;
+
+ 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= (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;
+ }
+ 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 */
+ {
+ 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 */
+ }
+ if (n_length == 0)
+ {
+ 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;
+ }
+ }
+ }
+ return length;
+}
+
+
+/* Length of key which is prefix compressed */
+
+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)
+{
+ 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 */
+ {
+ /* pack key against previous key */
+ /*
+ As keys may be identical when running a sort in myisamchk, we
+ have to guard against the case where keys may be identical
+ */
+ uchar *end;
+ end=key+key_length;
+ for ( ; *key == *prev_key && key < end; key++,prev_key++) ;
+ s_temp->ref_length= ref_length=(uint) (key-s_temp->key);
+ length=key_length - ref_length + get_pack_length(ref_length);
+ }
+ else
+ {
+ /* No previous key */
+ s_temp->ref_length=ref_length=0;
+ length=key_length+1;
+ }
+ if ((s_temp->next_key_pos=next_key)) /* If another key after */
+ {
+ /* pack key against next key */
+ uint next_length,next_length_pack;
+ get_key_pack_length(next_length,next_length_pack,next_key);
+
+ /* If first key and next key is packed (only on delete) */
+ if (!prev_key && org_key && next_length)
+ {
+ uchar *end;
+ for (key= s_temp->key, end=key+next_length ;
+ *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 */
+ 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));
+ }
+ /* Check how many characters are identical to next key */
+ key= s_temp->key+next_length;
+ while (*key++ == *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 */
+ }
+ 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));
+ }
+ return (int) length;
+}
+
+
+/*
+** store a key packed with _mi_calc_xxx_key_length in page-buffert
+*/
+
+/* store key without compression */
+
+void _mi_store_static_key(MI_KEYDEF *keyinfo __attribute__((unused)),
+ register uchar *key_pos,
+ register MI_KEY_PARAM *s_temp)
+{
+ memcpy((byte*) key_pos,(byte*) s_temp->key,(size_t) s_temp->totlength);
+}
+
+
+/* store variable length key with prefix compression */
+
+#define store_pack_length(test,pos,length) { \
+ if (test) { *((pos)++) = (uchar) (length); } else \
+ { *((pos)++) = (uchar) ((length) >> 8); *((pos)++) = (uchar) (length); } }
+
+
+void _mi_store_var_pack_key(MI_KEYDEF *keyinfo __attribute__((unused)),
+ register uchar *key_pos,
+ register MI_KEY_PARAM *s_temp)
+{
+ uint length;
+ uchar *start;
+
+ start=key_pos;
+
+ if (s_temp->ref_length)
+ {
+ /* Packed against previous key */
+ store_pack_length(s_temp->pack_marker == 128,key_pos,s_temp->ref_length);
+ /* If not same key after */
+ if (s_temp->ref_length != s_temp->pack_marker)
+ store_key_length_inc(key_pos,s_temp->key_length);
+ }
+ else
+ {
+ /* Not packed against previous key */
+ 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)));
+
+ if (!s_temp->next_key_pos) /* No following key */
+ return;
+ key_pos+=length;
+
+ if (s_temp->prev_length)
+ {
+ /* Extend next key because new key didn't have same prefix as prev key */
+ if (s_temp->part_of_prev_key)
+ {
+ store_pack_length(s_temp->pack_marker == 128,key_pos,
+ 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);
+ }
+ memcpy(key_pos, s_temp->prev_key, s_temp->prev_length);
+ }
+ else if (s_temp->n_ref_length)
+ {
+ 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 */
+ store_key_length(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);
+ }
+}
+
+
+/* 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)
+{
+ 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);
+
+ 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 */
+ {
+ memcpy(key_pos,s_temp->prev_key,s_temp->prev_length);
+ }
+ }
+}
diff --git a/myisam/mi_static.c b/myisam/mi_static.c
new file mode 100644
index 00000000000..4cc831e3f78
--- /dev/null
+++ b/myisam/mi_static.c
@@ -0,0 +1,56 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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
+ a shared library
+*/
+
+#ifndef _global_h
+#include "myisamdef.h"
+#endif
+
+LIST *myisam_open_list=0;
+uchar NEAR myisam_file_magic[]=
+{ (uchar) 254, (uchar) 254,'\007', '\001', };
+uchar NEAR myisam_pack_file_magic[]=
+{ (uchar) 254, (uchar) 254,'\010', '\001', };
+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;
+#if defined(THREAD) && !defined(DONT_USE_RW_LOCKS) && defined(HAVE_PREAD)
+my_bool myisam_concurrent_insert=1;
+#else
+my_bool myisam_concurrent_insert=0;
+#endif
+
+/* read_vec[] is used for converting between P_READ_KEY.. and SEARCH_ */
+/* Position is , == , >= , <= , > , < */
+
+uint NEAR myisam_read_vec[]=
+{
+ SEARCH_FIND, SEARCH_FIND | SEARCH_BIGGER, SEARCH_FIND | SEARCH_SMALLER,
+ SEARCH_NO_FIND | SEARCH_BIGGER, SEARCH_NO_FIND | SEARCH_SMALLER,
+ SEARCH_FIND | SEARCH_PREFIX, SEARCH_LAST
+};
+
+uint NEAR myisam_readnext_vec[]=
+{
+ SEARCH_BIGGER, SEARCH_BIGGER, SEARCH_SMALLER, SEARCH_BIGGER, SEARCH_SMALLER,
+ SEARCH_BIGGER, SEARCH_SMALLER
+};
diff --git a/myisam/mi_statrec.c b/myisam/mi_statrec.c
new file mode 100644
index 00000000000..05ff40d8921
--- /dev/null
+++ b/myisam/mi_statrec.c
@@ -0,0 +1,302 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+ /* Functions to handle fixed-length-records */
+
+#include "myisamdef.h"
+
+
+int _mi_write_static_record(MI_INFO *info, const byte *record)
+{
+ uchar temp[8]; /* max pointer length */
+
+ if (info->s->state.dellink != HA_OFFSET_ERROR)
+ {
+ 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)))
+ 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)))
+ goto err;
+ }
+ else
+ {
+ if (info->state->data_file_length > info->s->base.max_data_file_length-
+ info->s->base.pack_reclength)
+ {
+ my_errno=HA_ERR_RECORD_FILE_FULL;
+ return(2);
+ }
+ if (info->opt_flag & WRITE_CACHE_USED)
+ { /* Cash in use */
+ if (my_b_write(&info->rec_cache, (byte*) record,
+ info->s->base.reclength))
+ goto err;
+ 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_b_write(&info->rec_cache, (byte*) temp,length))
+ goto err;
+ }
+ }
+ 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))
+ 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))
+ goto err;
+ }
+ }
+ info->state->data_file_length+=info->s->base.pack_reclength;
+ info->s->state.split++;
+ }
+ return 0;
+ err:
+ return 1;
+}
+
+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);
+}
+
+
+int _mi_delete_static_record(MI_INFO *info)
+{
+ uchar temp[9]; /* 1+sizeof(uint32) */
+
+ info->state->del++;
+ info->state->empty+=info->s->base.pack_reclength;
+ temp[0]= '\0'; /* Mark that record is deleted */
+ _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);
+}
+
+
+int _mi_cmp_static_record(register MI_INFO *info, register const byte *old)
+{
+ DBUG_ENTER("_mi_cmp_static_record");
+
+ /* We are going to do changes; dont let anybody disturb */
+ dont_break(); /* Dont allow SIGHUP or SIGINT */
+
+ if (info->opt_flag & WRITE_CACHE_USED)
+ {
+ if (flush_io_cache(&info->rec_cache))
+ {
+ DBUG_RETURN(-1);
+ }
+ info->rec_cache.seek_not_done=1; /* We have done a seek */
+ }
+
+ if ((info->opt_flag & READ_CHECK_USED))
+ { /* If check isn't disabled */
+ info->rec_cache.seek_not_done=1; /* We have done a seek */
+ VOID(my_seek(info->dfile,info->lastpos,MY_SEEK_SET,MYF(0)));
+ if (my_read(info->dfile, (char*) info->rec_buff, info->s->base.reclength,
+ MYF(MY_NABP)))
+ DBUG_RETURN(-1);
+ if (memcmp((byte*) info->rec_buff, (byte*) old,
+ (uint) info->s->base.reclength))
+ {
+ DBUG_DUMP("read",old,info->s->base.reclength);
+ DBUG_DUMP("disk",info->rec_buff,info->s->base.reclength);
+ my_errno=HA_ERR_RECORD_CHANGED; /* Record have changed */
+ DBUG_RETURN(1);
+ }
+ }
+ DBUG_RETURN(0);
+}
+
+
+int _mi_cmp_static_unique(MI_INFO *info, MI_UNIQUEDEF *def,
+ const byte *record, my_off_t pos)
+{
+ 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)))
+ DBUG_RETURN(-1);
+ DBUG_RETURN(mi_unique_comp(def, record, info->rec_buff,
+ def->null_are_equal));
+}
+
+
+ /* Read a fixed-length-record */
+ /* Returns 0 if Ok. */
+ /* 1 if record is deleted */
+ /* MY_FILE_ERROR on read-error or locking-error */
+
+int _mi_read_static_record(register MI_INFO *info, register my_off_t pos,
+ register byte *record)
+{
+ int error;
+
+ if (pos != HA_OFFSET_ERROR)
+ {
+ if (info->opt_flag & WRITE_CACHE_USED &&
+ info->rec_cache.pos_in_file <= pos &&
+ flush_io_cache(&info->rec_cache))
+ return(-1);
+ info->rec_cache.seek_not_done=1; /* We have done a seek */
+
+ error=my_pread(info->dfile,(char*) record,info->s->base.reclength,
+ pos,MYF(MY_NABP)) != 0;
+ if (info->s->r_locks == 0 && info->s->w_locks == 0)
+ VOID(_mi_writeinfo(info,0));
+ if (! error)
+ {
+ if (!*record)
+ {
+ my_errno=HA_ERR_RECORD_DELETED;
+ return(1); /* Record is deleted */
+ }
+ info->update|= HA_STATE_AKTIV; /* Record is read */
+ return(0);
+ }
+ return(-1); /* Error on read */
+ }
+ VOID(_mi_writeinfo(info,0)); /* No such record */
+ return(-1);
+}
+
+
+
+int _mi_read_rnd_static_record(MI_INFO *info, byte *buf,
+ register my_off_t filepos,
+ my_bool skipp_deleted_blocks)
+{
+ int locked,error,cache_read;
+ uint cache_length;
+ MYISAM_SHARE *share=info->s;
+ DBUG_ENTER("_mi_read_rnd_static_record");
+
+ cache_read=0;
+ cache_length=0;
+ if (info->opt_flag & WRITE_CACHE_USED &&
+ (info->rec_cache.pos_in_file <= filepos || skipp_deleted_blocks) &&
+ flush_io_cache(&info->rec_cache))
+ DBUG_RETURN(my_errno);
+ if (info->opt_flag & READ_CACHE_USED)
+ { /* Cache in use */
+ if (filepos == my_b_tell(&info->rec_cache) &&
+ (skipp_deleted_blocks || !filepos))
+ {
+ cache_read=1; /* Read record using cache */
+ cache_length=(uint) (info->rec_cache.rc_end - info->rec_cache.rc_pos);
+ }
+ else
+ info->rec_cache.seek_not_done=1; /* Filepos is changed */
+ }
+ locked=0;
+ if (info->lock_type == F_UNLCK)
+ {
+ if (filepos >= info->state->data_file_length)
+ { /* Test if new records */
+ if (_mi_readinfo(info,F_RDLCK,0))
+ DBUG_RETURN(my_errno);
+ locked=1;
+ }
+ else
+ { /* We don't nead new info */
+#ifndef UNSAFE_LOCKING
+ if ((! cache_read || share->base.reclength > cache_length) &&
+ share->r_locks == 0 && share->w_locks == 0)
+ { /* record not in cache */
+ if (my_lock(share->kfile,F_RDLCK,0L,F_TO_EOF,
+ MYF(MY_SEEK_NOT_DONE) | info->lock_wait))
+ DBUG_RETURN(my_errno);
+ locked=1;
+ }
+#else
+ info->tmp_lock_type=F_RDLCK;
+#endif
+ }
+ }
+ if (filepos >= info->state->data_file_length)
+ {
+ 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));
+ DBUG_RETURN(my_errno=HA_ERR_END_OF_FILE);
+ }
+ info->lastpos= filepos;
+ info->nextpos= filepos+share->base.pack_reclength;
+
+ if (! cache_read) /* No cacheing */
+ {
+ if ((error=_mi_read_static_record(info,filepos,buf)))
+ {
+ if (error > 0)
+ error=my_errno=HA_ERR_RECORD_DELETED;
+ else
+ error=my_errno;
+ }
+ DBUG_RETURN(error);
+ }
+
+ /* Read record with cacheing */
+ error=my_b_read(&info->rec_cache,(byte*) buf,share->base.reclength);
+ if (info->s->base.pack_reclength != info->s->base.reclength && !error)
+ {
+ char tmp[8]; /* Skill fill bytes */
+ error=my_b_read(&info->rec_cache,(byte*) tmp,
+ info->s->base.pack_reclength - info->s->base.reclength);
+ }
+ if (locked)
+ VOID(_mi_writeinfo(info,0)); /* Unlock keyfile */
+ if (!error)
+ {
+ if (!buf[0])
+ { /* Record is removed */
+ DBUG_RETURN(my_errno=HA_ERR_RECORD_DELETED);
+ }
+ /* Found and may be updated */
+ info->update|= HA_STATE_AKTIV | HA_STATE_KEY_CHANGED;
+ DBUG_RETURN(0);
+ }
+ /* my_errno should be set if rec_cache.error == -1 */
+ if (info->rec_cache.error != -1 || my_errno == 0)
+ my_errno=HA_ERR_WRONG_IN_RECORD;
+ DBUG_RETURN(my_errno); /* Something wrong (EOF?) */
+}
diff --git a/myisam/mi_test1.c b/myisam/mi_test1.c
new file mode 100644
index 00000000000..59b9ceb266e
--- /dev/null
+++ b/myisam/mi_test1.c
@@ -0,0 +1,640 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* Testing of the basic functions of a MyISAM table */
+
+#include "myisam.h"
+#include <getopt.h>
+#include <m_ctype.h>
+
+
+#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_type=HA_KEYTYPE_NUM;
+static int create_flag=0;
+
+static uint insert_count= 1000,update_count=1000,remove_count=1000;
+static uint pack_keys=0,pack_seg=0,null_fields=0,key_length=6,skip_update=0;
+static uint unique_key=HA_NOSAME,key_cacheing=0,opt_unique=0;
+static uint silent;
+static MI_COLUMNDEF recinfo[4];
+static MI_KEYDEF keyinfo[10];
+static MI_KEYSEG keyseg[10];
+static MI_KEYSEG uniqueseg[10];
+
+static int run_test(const char *filename);
+static void get_options(int argc, char *argv[]);
+static void create_key(char *key,uint rownr);
+static void create_record(char *record,uint rownr);
+static void update_record(char *record);
+
+int main(int argc,char *argv[])
+{
+ MY_INIT(argv[0]);
+ my_init();
+ if (key_cacheing)
+ init_key_cache(IO_SIZE*16,(uint) IO_SIZE*4*10);
+ get_options(argc,argv);
+
+ exit(run_test("test1"));
+}
+
+
+int run_test(const char *filename)
+{
+ MI_INFO *file;
+ int i,j,error,deleted,rec_length,uniques=0;
+ ha_rows found,row_count;
+ my_off_t pos;
+ char record[MAX_REC_LENGTH],key[MAX_REC_LENGTH],read_record[MAX_REC_LENGTH];
+ MI_UNIQUEDEF uniquedef;
+ MI_CREATE_INFO create_info;
+
+ bzero((char*) recinfo,sizeof(recinfo));
+
+ /* First define 2 columns */
+ recinfo[0].type=FIELD_NORMAL; recinfo[0].length=1; /* For NULL bits */
+ recinfo[1].type=key_field;
+ recinfo[1].length= (key_field == FIELD_BLOB ? 4+mi_portable_sizeof_char_ptr :
+ key_length);
+ if (key_field == FIELD_VARCHAR)
+ recinfo[1].length+=2;
+ recinfo[2].type=extra_field;
+ recinfo[2].length= (extra_field == FIELD_BLOB ? 4 + mi_portable_sizeof_char_ptr : 24);
+ if (extra_field == FIELD_VARCHAR)
+ recinfo[2].length+=2;
+ if (opt_unique)
+ {
+ recinfo[3].type=FIELD_CHECK;
+ recinfo[3].length=MI_UNIQUE_HASH_LENGTH;
+ }
+ rec_length=recinfo[0].length+recinfo[1].length+recinfo[2].length+
+ recinfo[3].length;
+
+
+ /* Define a key over the first column */
+ keyinfo[0].seg=keyseg;
+ keyinfo[0].keysegs=1;
+ keyinfo[0].seg[0].type= key_type;
+ keyinfo[0].seg[0].flag= pack_seg;
+ keyinfo[0].seg[0].start=1;
+ keyinfo[0].seg[0].length=key_length;
+ keyinfo[0].seg[0].null_bit= null_fields ? 2 : 0;
+ keyinfo[0].seg[0].null_pos=0;
+ keyinfo[0].seg[0].language=MY_CHARSET_CURRENT;
+ if (pack_seg & HA_BLOB_PART)
+ {
+ keyinfo[0].seg[0].bit_start=4; /* Length of blob length */
+ }
+ keyinfo[0].flag = (uint8) (pack_keys | unique_key);
+
+ bzero((byte*) flags,sizeof(flags));
+ if (opt_unique)
+ {
+ uint start;
+ uniques=1;
+ bzero((char*) &uniquedef,sizeof(uniquedef));
+ bzero((char*) uniqueseg,sizeof(uniqueseg));
+ uniquedef.seg=uniqueseg;
+ uniquedef.keysegs=2;
+
+ /* Make a unique over all columns (except first NULL fields) */
+ for (i=0, start=1 ; i < 2 ; i++)
+ {
+ uniqueseg[i].start=start;
+ start+=recinfo[i+1].length;
+ uniqueseg[i].length=recinfo[i+1].length;
+ uniqueseg[i].language=MY_CHARSET_CURRENT;
+ }
+ uniqueseg[0].type= key_type;
+ uniqueseg[0].null_bit= null_fields ? 2 : 0;
+ uniqueseg[1].type= HA_KEYTYPE_TEXT;
+ if (extra_field == FIELD_BLOB)
+ {
+ uniqueseg[1].length=0; /* The whole blob */
+ uniqueseg[1].bit_start=4; /* long blob */
+ uniqueseg[1].flag|= HA_BLOB_PART;
+ }
+ else if (extra_field == FIELD_VARCHAR)
+ uniqueseg[1].flag|= HA_VAR_LENGTH;
+ }
+ else
+ uniques=0;
+
+ if (!silent)
+ printf("- Creating isam-file\n");
+ bzero((char*) &create_info,sizeof(create_info));
+ create_info.max_rows=(ulong) (rec_pointer_size ?
+ (1L << (rec_pointer_size*8))/40 :
+ 0);
+ if (mi_create(filename,1,keyinfo,3+opt_unique,recinfo,
+ uniques, &uniquedef, &create_info,
+ create_flag))
+ goto err;
+ if (!(file=mi_open(filename,2,HA_OPEN_ABORT_IF_LOCKED)))
+ goto err;
+ if (!silent)
+ printf("- Writing key:s\n");
+
+ my_errno=0;
+ row_count=deleted=0;
+ for (i=49 ; i>=1 ; i-=2 )
+ {
+ if (insert_count-- == 0) { VOID(mi_close(file)) ; exit(0) ; }
+ j=i%25 +1;
+ create_record(record,j);
+ error=mi_write(file,record);
+ if (!error)
+ row_count++;
+ flags[j]=1;
+ if (verbose || error)
+ printf("J= %2d mi_write: %d errno: %d\n", j,error,my_errno);
+ }
+
+ /* Insert 2 rows with null values */
+ if (null_fields)
+ {
+ create_record(record,0);
+ error=mi_write(file,record);
+ if (!error)
+ row_count++;
+ if (verbose || error)
+ printf("J= NULL mi_write: %d errno: %d\n", error,my_errno);
+ error=mi_write(file,record);
+ if (!error)
+ row_count++;
+ if (verbose || error)
+ printf("J= NULL mi_write: %d errno: %d\n", error,my_errno);
+ flags[0]=2;
+ }
+
+ if (!skip_update)
+ {
+ if (opt_unique)
+ {
+ if (!silent)
+ printf("- Checking unique constraint\n");
+ create_record(record,j);
+ if (!mi_write(file,record) || my_errno != HA_ERR_FOUND_DUPP_UNIQUE)
+ {
+ printf("unique check failed\n");
+ }
+ }
+ if (!silent)
+ printf("- Updating rows\n");
+
+ /* Update first last row to force extend of file */
+ if (mi_rsame(file,read_record,-1))
+ {
+ printf("Can't find last row with mi_rsame\n");
+ }
+ else
+ {
+ memcpy(record,read_record,rec_length);
+ update_record(record);
+ if (mi_update(file,read_record,record))
+ {
+ printf("Can't update last row: %.*s\n",
+ keyinfo[0].seg[0].length,read_record+1);
+ }
+ }
+
+ /* Read through all rows and update them */
+ pos=(my_off_t) 0;
+ found=0;
+ while ((error=mi_rrnd(file,read_record,pos)) == 0)
+ {
+ if (update_count-- == 0) { VOID(mi_close(file)) ; exit(0) ; }
+ memcpy(record,read_record,rec_length);
+ update_record(record);
+ if (mi_update(file,read_record,record))
+ {
+ printf("Can't update row: %.*s, error: %d\n",
+ keyinfo[0].seg[0].length,record+1,my_errno);
+ }
+ found++;
+ pos=HA_OFFSET_ERROR;
+ }
+ if (found != row_count)
+ printf("Found %ld of %ld rows\n", found,row_count);
+ }
+
+ if (!silent)
+ printf("- Reopening file\n");
+ if (mi_close(file)) goto err;
+ if (!(file=mi_open(filename,2,HA_OPEN_ABORT_IF_LOCKED))) goto err;
+ if (!skip_update)
+ {
+ if (!silent)
+ printf("- Removing keys\n");
+
+ for (i=0 ; i <= 10 ; i++)
+ {
+ /* testing */
+ if (remove_count-- == 0) { VOID(mi_close(file)) ; exit(0) ; }
+ j=i*2;
+ if (!flags[j])
+ continue;
+ create_key(key,j);
+ my_errno=0;
+ if ((error = mi_rkey(file,read_record,0,key,0,HA_READ_KEY_EXACT)))
+ {
+ if (verbose || (flags[j] >= 1 ||
+ (error && my_errno != HA_ERR_KEY_NOT_FOUND)))
+ printf("key: '%.*s' mi_rkey: %3d errno: %3d\n",
+ (int) key_length,key+test(null_fields),error,my_errno);
+ }
+ else
+ {
+ error=mi_delete(file,read_record);
+ if (verbose || error)
+ printf("key: '%.*s' mi_delete: %3d errno: %3d\n",
+ (int) key_length, key+test(null_fields), error, my_errno);
+ if (! error)
+ {
+ deleted++;
+ flags[j]--;
+ }
+ }
+ }
+ }
+ if (!silent)
+ printf("- Reading rows with key\n");
+ for (i=0 ; i <= 25 ; i++)
+ {
+ create_key(key,i);
+ my_errno=0;
+ error=mi_rkey(file,read_record,0,key,0,HA_READ_KEY_EXACT);
+ if (verbose ||
+ (error == 0 && flags[i] == 0 && unique_key) ||
+ (error && (flags[i] != 0 || my_errno != HA_ERR_KEY_NOT_FOUND)))
+ {
+ printf("key: '%.*s' mi_rkey: %3d errno: %3d record: %s\n",
+ (int) key_length,key+test(null_fields),error,my_errno,record+1);
+ }
+ }
+
+ if (!silent)
+ printf("- Reading rows with position\n");
+ for (i=1,found=0 ; i <= 30 ; i++)
+ {
+ my_errno=0;
+ if ((error=mi_rrnd(file,read_record,i == 1 ? 0L : HA_OFFSET_ERROR)) == -1)
+ {
+ if (found != row_count-deleted)
+ printf("Found only %ld of %ld rows\n",found,row_count-deleted);
+ break;
+ }
+ if (!error)
+ found++;
+ if (verbose || (error != 0 && error != HA_ERR_RECORD_DELETED &&
+ error != HA_ERR_END_OF_FILE))
+ {
+ printf("pos: %2d mi_rrnd: %3d errno: %3d record: %s\n",
+ i-1,error,my_errno,read_record+1);
+ }
+ }
+ if (mi_close(file)) goto err;
+ my_end(MY_CHECK_ERROR);
+
+ return (0);
+err:
+ printf("got error: %3d when using myisam-database\n",my_errno);
+ return 1; /* skipp warning */
+}
+
+
+static void create_key_part(char *key,uint rownr)
+{
+ if (!unique_key)
+ rownr&=7; /* Some identical keys */
+ if (keyinfo[0].seg[0].type == HA_KEYTYPE_NUM)
+ {
+ sprintf(key,"%*d",keyinfo[0].seg[0].length,rownr);
+ }
+ else if (keyinfo[0].seg[0].type == HA_KEYTYPE_VARTEXT)
+ { /* Alpha record */
+ /* Create a key that may be easily packed */
+ bfill(key,keyinfo[0].seg[0].length,rownr < 10 ? 'A' : 'B');
+ sprintf(key+keyinfo[0].seg[0].length-2,"%-2d",rownr);
+ if ((rownr & 7) == 0)
+ {
+ /* Change the key to force a unpack of the next key */
+ bfill(key+3,keyinfo[0].seg[0].length-4,rownr < 10 ? 'a' : 'b');
+ }
+ }
+ else
+ { /* Alpha record */
+ if (keyinfo[0].seg[0].flag & HA_SPACE_PACK)
+ sprintf(key,"%-*d",keyinfo[0].seg[0].length,rownr);
+ else
+ {
+ /* Create a key that may be easily packed */
+ bfill(key,keyinfo[0].seg[0].length,rownr < 10 ? 'A' : 'B');
+ sprintf(key+keyinfo[0].seg[0].length-2,"%-2d",rownr);
+ if ((rownr & 7) == 0)
+ {
+ /* Change the key to force a unpack of the next key */
+ key[1]= (rownr < 10 ? 'a' : 'b');
+ }
+ }
+ }
+}
+
+
+static void create_key(char *key,uint rownr)
+{
+ if (keyinfo[0].seg[0].null_bit)
+ {
+ if (rownr == 0)
+ {
+ key[0]=1; /* null key */
+ key[1]=0; /* Fore easy print of key */
+ return;
+ }
+ *key++=0;
+ }
+ if (keyinfo[0].seg[0].flag & (HA_BLOB_PART | HA_VAR_LENGTH))
+ {
+ uint tmp;
+ create_key_part(key+2,rownr);
+ tmp=strlen(key+2);
+ int2store(key,tmp);
+ }
+ else
+ create_key_part(key,rownr);
+}
+
+
+static char blob_key[MAX_REC_LENGTH];
+static char blob_record[MAX_REC_LENGTH+20*20];
+
+
+static void create_record(char *record,uint rownr)
+{
+ char *pos;
+ bzero((char*) record,MAX_REC_LENGTH);
+ record[0]=1; /* delete marker */
+ if (rownr == 0 && keyinfo[0].seg[0].null_bit)
+ record[0]|=keyinfo[0].seg[0].null_bit; /* Null key */
+
+ pos=record+1;
+ if (recinfo[1].type == FIELD_BLOB)
+ {
+ uint tmp;
+ char *ptr;
+ create_key_part(blob_key,rownr);
+ tmp=strlen(blob_key);
+ int4store(pos,tmp);
+ ptr=blob_key;
+ memcpy_fixed(pos+4,&ptr,sizeof(char*));
+ pos+=recinfo[1].length;
+ }
+ else if (recinfo[1].type == FIELD_VARCHAR)
+ {
+ uint tmp;
+ create_key_part(pos+2,rownr);
+ tmp=strlen(pos+2);
+ int2store(pos,tmp);
+ pos+=recinfo[1].length;
+ }
+ else
+ {
+ create_key_part(pos,rownr);
+ pos+=recinfo[1].length;
+ }
+ if (recinfo[2].type == FIELD_BLOB)
+ {
+ uint tmp;
+ char *ptr;;
+ sprintf(blob_record,"... row: %d", rownr);
+ strappend(blob_record,max(MAX_REC_LENGTH-rownr,10),' ');
+ tmp=strlen(blob_record);
+ int4store(pos,tmp);
+ ptr=blob_record;
+ memcpy_fixed(pos+4,&ptr,sizeof(char*));
+ }
+ else if (recinfo[2].type == FIELD_VARCHAR)
+ {
+ uint tmp;
+ sprintf(pos+2,"... row: %d", rownr);
+ tmp=strlen(pos+2);
+ int2store(pos,tmp);
+ }
+ else
+ {
+ sprintf(pos,"... row: %d", rownr);
+ strappend(pos,recinfo[2].length,' ');
+ }
+}
+
+/* change row to test re-packing of rows and reallocation of keys */
+
+static void update_record(char *record)
+{
+ char *pos=record+1;
+ if (recinfo[1].type == FIELD_BLOB)
+ {
+ char *column,*ptr;
+ int length;
+ length=uint4korr(pos); /* Long blob */
+ memcpy_fixed(&column,pos+4,sizeof(char*));
+ memcpy(blob_key,column,length); /* Move old key */
+ ptr=blob_key;
+ memcpy_fixed(pos+4,&ptr,sizeof(char*)); /* Store pointer to new key */
+ if (keyinfo[0].seg[0].type != HA_KEYTYPE_NUM)
+ casedn(blob_key,length);
+ pos+=recinfo[1].length;
+ }
+ else if (recinfo[1].type == FIELD_VARCHAR)
+ {
+ uint length=uint2korr(pos);
+ casedn(pos+2,length);
+ pos+=recinfo[1].length;
+ }
+ else
+ {
+ if (keyinfo[0].seg[0].type != HA_KEYTYPE_NUM)
+ casedn(pos,keyinfo[0].seg[0].length);
+ pos+=recinfo[1].length;
+ }
+
+ if (recinfo[2].type == FIELD_BLOB)
+ {
+ char *column;
+ int length;
+ length=uint4korr(pos);
+ memcpy_fixed(&column,pos+4,sizeof(char*));
+ memcpy(blob_record,column,length);
+ bfill(blob_record+length,20,'.'); /* Make it larger */
+ length+=20;
+ int4store(pos,length);
+ column=blob_record;
+ memcpy_fixed(pos+4,&column,sizeof(char*));
+ }
+ else if (recinfo[2].type == FIELD_VARCHAR)
+ {
+ /* Second field is longer than 10 characters */
+ uint length=uint2korr(pos);
+ bfill(pos+2+length,recinfo[2].length-length-2,'.');
+ length=recinfo[2].length-2;
+ int2store(pos,length);
+ }
+ else
+ {
+ bfill(pos+recinfo[2].length-10,10,'.');
+ }
+}
+
+
+static struct option long_options[] =
+{
+ {"checksum", no_argument, 0, 'c'},
+#ifndef DBUG_OFF
+ {"debug", required_argument, 0, '#'},
+#endif
+ {"delete_rows", required_argument, 0, 'd'},
+ {"help", no_argument, 0, '?'},
+ {"insert_rows", required_argument, 0, 'i'},
+ {"key_alpha", no_argument, 0, 'a'},
+ {"key_binary_pack", no_argument, 0, 'B'},
+ {"key_blob", required_argument, 0, 'b'},
+ {"key_cache", no_argument, 0, 'K'},
+ {"key_length", required_argument, 0, 'k'},
+ {"key_multiple", no_argument, 0, 'm'},
+ {"key_prefix_pack", no_argument, 0, 'P'},
+ {"key_space_pack", no_argument, 0, 'p'},
+ {"key_varchar", no_argument, 0, 'w'},
+ {"null_fields", no_argument, 0, 'N'},
+ {"row_fixed_size", no_argument, 0, 'S'},
+ {"row_pointer_size", required_argument, 0, 'R'},
+ {"silent", no_argument, 0, 's'},
+ {"skip_update", no_argument, 0, 'U'},
+ {"unique", no_argument, 0, 'C'},
+ {"update_rows", required_argument, 0, 'u'},
+ {"verbose", no_argument, 0, 'v'},
+ {"version", no_argument, 0, 'V'},
+ {0, 0, 0, 0}
+};
+
+
+/* Read options */
+
+static void get_options(int argc,char *argv[])
+{
+ int c,option_index=0;
+
+ while ((c=getopt_long(argc,argv,"abBcCd:i:k:KmPR:SspNu:UvVw#:",
+ long_options, &option_index)) != EOF)
+ {
+ switch(c) {
+ case 'a':
+ key_type= HA_KEYTYPE_TEXT;
+ break;
+ case 'c':
+ create_flag|= HA_CREATE_CHECKSUM;
+ break;
+ case 'C':
+ opt_unique=1;
+ break;
+ case 'R': /* Length of record pointer */
+ rec_pointer_size=atoi(optarg);
+ if (rec_pointer_size > 3)
+ rec_pointer_size=0;
+ break;
+ case 'P':
+ pack_keys= HA_PACK_KEY; /* Use prefix compression */
+ break;
+ case 'B':
+ pack_keys= HA_BINARY_PACK_KEY; /* Use binary compression */
+ break;
+ case 'S':
+ if (key_field == FIELD_VARCHAR)
+ {
+ create_flag=0; /* Static sized varchar */
+ }
+ else if (key_field != FIELD_BLOB)
+ {
+ key_field=FIELD_NORMAL; /* static-size record */
+ extra_field=FIELD_NORMAL;
+ }
+ break;
+ case 'p':
+ pack_keys=HA_PACK_KEY; /* Use prefix + space packing */
+ pack_seg=HA_SPACE_PACK;
+ key_type=HA_KEYTYPE_TEXT;
+ break;
+ case 'N':
+ null_fields=1; /* First key part may be null */
+ break;
+ case 'v': /* verbose */
+ verbose=1;
+ break;
+ case 'd':
+ remove_count=atoi(optarg);
+ break;
+ case 'i':
+ insert_count=atoi(optarg);
+ break;
+ case 'u':
+ update_count=atoi(optarg);
+ break;
+ case 'U':
+ skip_update=1;
+ break;
+ case 'm':
+ unique_key=0;
+ break;
+ case 'b':
+ key_field=FIELD_BLOB; /* blob key */
+ extra_field= FIELD_BLOB;
+ pack_seg|= HA_BLOB_PART;
+ key_type= HA_KEYTYPE_VARTEXT;
+ break;
+ case 'k':
+ key_length=atoi(optarg);
+ if (key_length < 4 || key_length > MI_MAX_KEY_LENGTH)
+ {
+ fprintf(stderr,"Wrong key length\n");
+ exit(1);
+ }
+ break;
+ case 's':
+ silent=1;
+ break;
+ case 'w':
+ key_field=FIELD_VARCHAR; /* varchar keys */
+ extra_field= FIELD_VARCHAR;
+ key_type= HA_KEYTYPE_VARTEXT;
+ pack_seg|= HA_VAR_LENGTH;
+ create_flag|= HA_PACK_RECORD;
+ break;
+ case 'K': /* Use key cacheing */
+ key_cacheing=1;
+ break;
+ case 'V':
+ printf("test1 Ver 1.0 \n");
+ exit(0);
+ case '#':
+ DEBUGGER_ON;
+ DBUG_PUSH (optarg);
+ break;
+ }
+ }
+ return;
+} /* get options */
diff --git a/myisam/mi_test2.c b/myisam/mi_test2.c
new file mode 100644
index 00000000000..25bc1a4f844
--- /dev/null
+++ b/myisam/mi_test2.c
@@ -0,0 +1,973 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* Test av isam-databas: stor test */
+
+#ifndef USE_MY_FUNC /* We want to be able to dbug this !! */
+#define USE_MY_FUNC
+#endif
+#ifdef DBUG_OFF
+#undef DBUG_OFF
+#endif
+#ifndef SAFEMALLOC
+#define SAFEMALLOC
+#endif
+#include "myisamdef.h"
+#include <m_ctype.h>
+
+#define STANDARD_LENGTH 37
+#define MYISAM_KEYS 6
+#define MAX_PARTS 4
+#if !defined(MSDOS) && !defined(labs)
+#define labs(a) abs(a)
+#endif
+
+static void get_options(int argc, char *argv[]);
+static uint rnd(uint max_value);
+static void fix_length(byte *record,uint length);
+static void put_blob_in_record(char *blob_pos,char **blob_buffer);
+static void copy_key(struct st_myisam_info *info,uint inx,
+ uchar *record,uchar *key);
+
+static int verbose=0,testflag=0,
+ first_key=0,async_io=0,key_cacheing=0,write_cacheing=0,locking=0,
+ rec_pointer_size=0,pack_fields=1,use_log=0,silent=0;
+static int pack_seg=HA_SPACE_PACK,pack_type=HA_PACK_KEY,remove_count=-1,
+ create_flag=0;
+static ulong key_cache_size=IO_SIZE*16;
+
+static uint keys=MYISAM_KEYS,recant=1000;
+static uint use_blob=0;
+static uint16 key1[1001],key3[5000];
+static char record[300],record2[300],key[100],key2[100],
+ read_record[300],read_record2[300],read_record3[300];
+static MI_KEYSEG glob_keyseg[MYISAM_KEYS][MAX_PARTS];
+
+ /* Test program */
+
+int main(int argc, char **argv)
+{
+ uint i;
+ int j,n1,n2,n3,error,k;
+ uint write_count,update,dupp_keys,delete,start,length,blob_pos,
+ reclength,ant,found_parts;
+ my_off_t lastpos;
+ ha_rows range_records,records;
+ MI_INFO *file;
+ MI_KEYDEF keyinfo[10];
+ MI_COLUMNDEF recinfo[10];
+ MI_ISAMINFO info;
+ const char *filename;
+ char *blob_buffer;
+ MI_CREATE_INFO create_info;
+ MY_INIT(argv[0]);
+
+ filename= "test2";
+ get_options(argc,argv);
+ if (! async_io)
+ my_disable_async_io=1;
+
+ reclength=STANDARD_LENGTH+60+(use_blob ? 8 : 0);
+ blob_pos=STANDARD_LENGTH+60;
+ keyinfo[0].seg= &glob_keyseg[0][0];
+ keyinfo[0].seg[0].start=0;
+ keyinfo[0].seg[0].length=6;
+ keyinfo[0].seg[0].type=HA_KEYTYPE_TEXT;
+ keyinfo[0].seg[0].language=MY_CHARSET_CURRENT;
+ keyinfo[0].seg[0].flag=(uint8) pack_seg;
+ keyinfo[0].seg[0].null_bit=0;
+ keyinfo[0].seg[0].null_pos=0;
+ keyinfo[0].keysegs=1;
+ keyinfo[0].flag = pack_type;
+ keyinfo[1].seg= &glob_keyseg[1][0];
+ keyinfo[1].seg[0].start=7;
+ keyinfo[1].seg[0].length=6;
+ keyinfo[1].seg[0].type=HA_KEYTYPE_BINARY;
+ keyinfo[1].seg[0].flag=0;
+ keyinfo[1].seg[0].null_bit=0;
+ keyinfo[1].seg[0].null_pos=0;
+ keyinfo[1].seg[1].start=0; /* two part key */
+ keyinfo[1].seg[1].length=6;
+ keyinfo[1].seg[1].type=HA_KEYTYPE_NUM;
+ keyinfo[1].seg[1].flag=HA_REVERSE_SORT;
+ keyinfo[1].seg[1].null_bit=0;
+ keyinfo[1].seg[1].null_pos=0;
+ keyinfo[1].keysegs=2;
+ keyinfo[1].flag =0;
+ keyinfo[2].seg= &glob_keyseg[2][0];
+ keyinfo[2].seg[0].start=12;
+ keyinfo[2].seg[0].length=8;
+ keyinfo[2].seg[0].type=HA_KEYTYPE_BINARY;
+ keyinfo[2].seg[0].flag=HA_REVERSE_SORT;
+ keyinfo[2].seg[0].null_bit=0;
+ keyinfo[2].seg[0].null_pos=0;
+ keyinfo[2].keysegs=1;
+ keyinfo[2].flag =HA_NOSAME;
+ keyinfo[3].seg= &glob_keyseg[3][0];
+ keyinfo[3].seg[0].start=0;
+ keyinfo[3].seg[0].length=reclength-(use_blob ? 8 : 0);
+ keyinfo[3].seg[0].type=HA_KEYTYPE_TEXT;
+ keyinfo[3].seg[0].language=MY_CHARSET_CURRENT;
+ keyinfo[3].seg[0].flag=(uint8) pack_seg;
+ keyinfo[3].seg[0].null_bit=0;
+ keyinfo[3].seg[0].null_pos=0;
+ keyinfo[3].keysegs=1;
+ keyinfo[3].flag = pack_type;
+ keyinfo[4].seg= &glob_keyseg[4][0];
+ keyinfo[4].seg[0].start=0;
+ keyinfo[4].seg[0].length=5;
+ keyinfo[4].seg[0].type=HA_KEYTYPE_TEXT;
+ keyinfo[4].seg[0].language=MY_CHARSET_CURRENT;
+ keyinfo[4].seg[0].flag=0;
+ keyinfo[4].seg[0].null_bit=0;
+ keyinfo[4].seg[0].null_pos=0;
+ keyinfo[4].keysegs=1;
+ keyinfo[4].flag = pack_type;
+ keyinfo[5].seg= &glob_keyseg[5][0];
+ keyinfo[5].seg[0].start=0;
+ keyinfo[5].seg[0].length=4;
+ keyinfo[5].seg[0].type=HA_KEYTYPE_TEXT;
+ keyinfo[5].seg[0].language=MY_CHARSET_CURRENT;
+ keyinfo[5].seg[0].flag=pack_seg;
+ keyinfo[5].seg[0].null_bit=0;
+ keyinfo[5].seg[0].null_pos=0;
+ keyinfo[5].keysegs=1;
+ keyinfo[5].flag = pack_type;
+
+ recinfo[0].type=pack_fields ? FIELD_SKIPP_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].length=5;
+ recinfo[1].null_bit=0;
+ recinfo[1].null_pos=0;
+ recinfo[2].type=pack_fields ? FIELD_SKIPP_PRESPACE : 0;
+ recinfo[2].length=9;
+ recinfo[2].null_bit=0;
+ recinfo[2].null_pos=0;
+ recinfo[3].type=FIELD_NORMAL;
+ 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].length=4;
+ recinfo[4].null_bit=0;
+ recinfo[4].null_pos=0;
+ recinfo[5].type=pack_fields ? FIELD_SKIPP_ENDSPACE : 0;
+ recinfo[5].length=60;
+ recinfo[5].null_bit=0;
+ recinfo[5].null_pos=0;
+ if (use_blob)
+ {
+ recinfo[6].type=FIELD_BLOB;
+ recinfo[6].length=4+mi_portable_sizeof_char_ptr;
+ recinfo[6].null_bit=0;
+ recinfo[6].null_pos=0;
+ }
+
+ write_count=update=dupp_keys=delete=0;
+ blob_buffer=0;
+
+ for (i=1000 ; i>0 ; i--) key1[i]=0;
+ for (i=4999 ; i>0 ; i--) key3[i]=0;
+
+ if (!silent)
+ printf("- Creating isam-file\n");
+ /* DBUG_PUSH(""); */
+ /* my_delete(filename,MYF(0)); */ /* Remove old locks under gdb */
+ file= 0;
+ bzero((char*) &create_info,sizeof(create_info));
+ create_info.max_rows=(ha_rows) (rec_pointer_size ?
+ (1L << (rec_pointer_size*8))/
+ reclength : 0);
+ create_info.reloc_rows=(ha_rows) 100;
+ if (mi_create(filename,keys,&keyinfo[first_key],
+ use_blob ? 7 : 6, &recinfo[0],
+ 0,(MI_UNIQUEDEF*) 0,
+ &create_info,create_flag))
+ goto err;
+ if (use_log)
+ mi_log(1);
+ if (!(file=mi_open(filename,2,HA_OPEN_ABORT_IF_LOCKED)))
+ goto err;
+ if (!silent)
+ printf("- Writing key:s\n");
+ if (key_cacheing)
+ init_key_cache(key_cache_size,(uint) IO_SIZE*4*10); /* Use a small cache */
+ if (locking)
+ mi_lock_database(file,F_WRLCK);
+ if (write_cacheing)
+ mi_extra(file,HA_EXTRA_WRITE_CACHE);
+
+ for (i=0 ; i < recant ; i++)
+ {
+ n1=rnd(1000); n2=rnd(100); n3=rnd(5000);
+ sprintf(record,"%6d:%4d:%8d:Pos: %4d ",n1,n2,n3,write_count);
+ int4store(record+STANDARD_LENGTH-4,(long) i);
+ fix_length(record,(uint) STANDARD_LENGTH+rnd(60));
+ put_blob_in_record(record+blob_pos,&blob_buffer);
+ DBUG_PRINT("test",("record: %d",i));
+
+ if (mi_write(file,record))
+ {
+ if (my_errno != HA_ERR_FOUND_DUPP_KEY || key3[n3] == 0)
+ {
+ printf("Error: %d in write at record: %d\n",my_errno,i);
+ goto err;
+ }
+ if (verbose) printf(" Double key: %d\n",n3);
+ }
+ else
+ {
+ if (key3[n3] == 1 && first_key <3 && first_key+keys >= 3)
+ {
+ printf("Error: Didn't get error when writing second key: '%8d'\n",n3);
+ goto err;
+ }
+ write_count++; key1[n1]++; key3[n3]=1;
+ }
+
+ /* Check if we can find key without flushing database */
+ if (i == recant/2)
+ {
+ for (j=rnd(1000)+1 ; j>0 && key1[j] == 0 ; j--) ;
+ if (!j)
+ for (j=999 ; j>0 && key1[j] == 0 ; j--) ;
+ sprintf(key,"%6d",j);
+ if (mi_rkey(file,read_record,0,key,0,HA_READ_KEY_EXACT))
+ {
+ printf("Test in loop: Can't find key: \"%s\"\n",key);
+ goto err;
+ }
+ }
+ }
+ if (testflag==1) goto end;
+
+ if (write_cacheing)
+ if (mi_extra(file,HA_EXTRA_NO_CACHE))
+ {
+ puts("got error from mi_extra(HA_EXTRA_NO_CACHE)");
+ goto end;
+ }
+
+ if (!silent)
+ printf("- Delete\n");
+ for (i=0 ; i<recant/10 ; i++)
+ {
+ for (j=rnd(1000)+1 ; j>0 && key1[j] == 0 ; j--) ;
+ if (j != 0)
+ {
+ sprintf(key,"%6d",j);
+ if (mi_rkey(file,read_record,0,key,0,HA_READ_KEY_EXACT))
+ {
+ printf("can't find key1: \"%s\"\n",key);
+ goto err;
+ }
+ if (delete == (uint) remove_count) /* While testing */
+ goto end;
+ if (mi_delete(file,read_record))
+ {
+ printf("error: %d; can't delete record: \"%s\"\n", my_errno,read_record);
+ goto err;
+ }
+ delete++;
+ key1[atoi(read_record+keyinfo[0].seg[0].start)]--;
+ key3[atoi(read_record+keyinfo[2].seg[0].start)]=0;
+ }
+ else
+ puts("Warning: Skipping delete test because no dupplicate keys");
+ }
+ if (testflag==2) goto end;
+
+ if (!silent)
+ printf("- Update\n");
+ for (i=0 ; i<recant/10 ; i++)
+ {
+ n1=rnd(1000); n2=rnd(100); n3=rnd(5000);
+ sprintf(record2,"%6d:%4d:%8d:XXX: %4d ",n1,n2,n3,update);
+ int4store(record2+STANDARD_LENGTH-4,(long) i);
+ fix_length(record2,(uint) STANDARD_LENGTH+rnd(60));
+
+ for (j=rnd(1000)+1 ; j>0 && key1[j] == 0 ; j--) ;
+ if (j != 0)
+ {
+ sprintf(key,"%6d",j);
+ if (mi_rkey(file,read_record,0,key,0,HA_READ_KEY_EXACT))
+ {
+ printf("can't find key1: \"%s\"\n",key);
+ goto err;
+ }
+ if (use_blob)
+ {
+ if (i & 1)
+ put_blob_in_record(record+blob_pos,&blob_buffer);
+ else
+ bmove(record+blob_pos,read_record+blob_pos,8);
+ }
+ if (mi_update(file,read_record,record2))
+ {
+ if (my_errno != HA_ERR_FOUND_DUPP_KEY || key3[n3] == 0)
+ {
+ printf("error: %d; can't uppdate:\nFrom: \"%s\"\nTo: \"%s\"\n",
+ my_errno,read_record,record2);
+ goto err;
+ }
+ if (verbose)
+ printf("Double key when tryed to uppdate:\nFrom: \"%s\"\nTo: \"%s\"\n",record,record2);
+ }
+ else
+ {
+ key1[atoi(read_record+keyinfo[0].seg[0].start)]--;
+ key3[atoi(read_record+keyinfo[2].seg[0].start)]=0;
+ key1[n1]++; key3[n3]=1;
+ update++;
+ }
+ }
+ }
+ 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; }
+ }
+ 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;
+ }
+ {
+ 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;
+ }
+
+ /* 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)
+ printf("- All keys: first - next -> last - prev -> first\n");
+ DBUG_PRINT("progpos",("All keys: first - next -> last - prev -> first"));
+ ant=1;
+ if (mi_rfirst(file,read_record,0))
+ {
+ printf("Can't find first record\n");
+ goto end;
+ }
+ while ((error=mi_rnext(file,read_record3,0)) == 0 && ant < write_count+10)
+ ant++;
+ if (ant != write_count - delete || error != HA_ERR_END_OF_FILE)
+ {
+ printf("next: I found: %d records of %d (error: %d)\n",
+ ant, write_count - delete, error);
+ goto end;
+ }
+ if (mi_rlast(file,read_record2,0) ||
+ bcmp(read_record2,read_record3,reclength))
+ {
+ printf("Can't find last record\n");
+ DBUG_DUMP("record2",(byte*) read_record2,reclength);
+ DBUG_DUMP("record3",(byte*) read_record3,reclength);
+ goto end;
+ }
+ ant=1;
+ while (mi_rprev(file,read_record3,0) == 0 && ant < write_count+10)
+ ant++;
+ if (ant != write_count - delete)
+ {
+ printf("prev: I found: %d records of %d\n",ant,write_count);
+ goto end;
+ }
+ if (bcmp(read_record,read_record3,reclength))
+ {
+ printf("Can't find first record\n");
+ goto end;
+ }
+
+ if (!silent)
+ printf("- Test if: Read first - next - prev - prev - next == first\n");
+ DBUG_PRINT("progpos",("- Read first - next - prev - prev - next == first"));
+ if (mi_rfirst(file,read_record,0) ||
+ mi_rnext(file,read_record3,0) ||
+ mi_rprev(file,read_record3,0) ||
+ mi_rprev(file,read_record3,0) == 0 ||
+ mi_rnext(file,read_record3,0))
+ goto err;
+ if (bcmp(read_record,read_record3,reclength) != 0)
+ printf("Can't find first record\n");
+
+ if (!silent)
+ printf("- Test if: Read last - prev - next - next - prev == last\n");
+ DBUG_PRINT("progpos",("Read last - prev - next - next - prev == last"));
+ if (mi_rlast(file,read_record2,0) ||
+ mi_rprev(file,read_record3,0) ||
+ mi_rnext(file,read_record3,0) ||
+ mi_rnext(file,read_record3,0) == 0 ||
+ mi_rprev(file,read_record3,0))
+ goto err;
+ if (bcmp(read_record2,read_record3,reclength))
+ printf("Can't find last record\n");
+
+ if (!silent)
+ puts("- Test read key-part");
+ strmov(key2,key);
+ for(i=strlen(key2) ; i-- > 1 ;)
+ {
+ key2[i]=0;
+
+ /* The following row is just to catch some bugs in the key code */
+ bzero((char*) file->lastkey,file->s->base.max_key_length*2);
+ if (mi_rkey(file,read_record,0,key2,(uint) i,HA_READ_PREFIX))
+ goto err;
+ if (bcmp(read_record+start,key,(uint) i))
+ {
+ puts("Didn't find right record");
+ goto end;
+ }
+ }
+ if (dupp_keys > 2)
+ {
+ if (!silent)
+ printf("- Read key (first) - next - delete - next -> last\n");
+ DBUG_PRINT("progpos",("first - next - delete - next -> last"));
+ if (mi_rkey(file,read_record,0,key,0,HA_READ_KEY_EXACT)) goto err;
+ if (mi_rnext(file,read_record3,0)) goto err;
+ if (mi_delete(file,read_record3)) goto err;
+ delete++;
+ ant=1;
+ while (mi_rnext(file,read_record3,0) == 0 &&
+ bcmp(read_record3+start,key,length) == 0) ant++;
+ if (ant != dupp_keys-1)
+ {
+ printf("next: I can only find: %d keys of %d\n",ant,dupp_keys-1);
+ goto end;
+ }
+ }
+ if (dupp_keys>4)
+ {
+ if (!silent)
+ printf("- Read last of key - prev - delete - prev -> first\n");
+ DBUG_PRINT("progpos",("last - prev - delete - prev -> first"));
+ if (mi_rprev(file,read_record3,0)) goto err;
+ if (mi_rprev(file,read_record3,0)) goto err;
+ if (mi_delete(file,read_record3)) goto err;
+ delete++;
+ ant=1;
+ while (mi_rprev(file,read_record3,0) == 0 &&
+ bcmp(read_record3+start,key,length) == 0) ant++;
+ if (ant != dupp_keys-2)
+ {
+ printf("next: I can only find: %d keys of %d\n",ant,dupp_keys-2);
+ goto end;
+ }
+ }
+ if (dupp_keys > 6)
+ {
+ if (!silent)
+ printf("- Read first - delete - next -> last\n");
+ DBUG_PRINT("progpos",("first - delete - next -> last"));
+ if (mi_rkey(file,read_record3,0,key,0,HA_READ_KEY_EXACT)) goto err;
+ if (mi_delete(file,read_record3)) goto err;
+ delete++;
+ ant=1;
+ if (mi_rnext(file,read_record,0))
+ goto err; /* Skall finnas poster */
+ while (mi_rnext(file,read_record3,0) == 0 &&
+ bcmp(read_record3+start,key,length) == 0) ant++;
+ if (ant != dupp_keys-3)
+ {
+ printf("next: I can only find: %d keys of %d\n",ant,dupp_keys-3);
+ goto end;
+ }
+
+ if (!silent)
+ printf("- Read last - delete - prev -> first\n");
+ DBUG_PRINT("progpos",("last - delete - prev -> first"));
+ if (mi_rprev(file,read_record3,0)) goto err;
+ if (mi_delete(file,read_record3)) goto err;
+ delete++;
+ ant=0;
+ while (mi_rprev(file,read_record3,0) == 0 &&
+ bcmp(read_record3+start,key,length) == 0) ant++;
+ if (ant != dupp_keys-4)
+ {
+ printf("next: I can only find: %d keys of %d\n",ant,dupp_keys-4);
+ goto end;
+ }
+ }
+
+ if (!silent)
+ puts("- Test if: Read rrnd - same");
+ DBUG_PRINT("progpos",("Read rrnd - same"));
+ for (i=0 ; i < write_count ; i++)
+ {
+ if (mi_rrnd(file,read_record,i == 0 ? 0L : HA_OFFSET_ERROR) == 0)
+ break;
+ }
+ if (i == write_count)
+ goto err;
+
+ bmove(read_record2,read_record,reclength);
+ for (i=min(2,keys) ; i-- > 0 ;)
+ {
+ if (mi_rsame(file,read_record2,(int) i)) goto err;
+ if (bcmp(read_record,read_record2,reclength) != 0)
+ {
+ printf("is_rsame didn't find same record\n");
+ goto end;
+ }
+ }
+ if (!silent)
+ puts("- Test mi_records_in_range");
+ mi_status(file,&info,HA_STATUS_VARIABLE);
+ for (i=0 ; i < info.keys ; i++)
+ {
+ if (mi_rfirst(file,read_record,(int) i) ||
+ mi_rlast(file,read_record2,(int) i))
+ goto err;
+ copy_key(file,(uint) i,(uchar*) read_record,(uchar*) key);
+ copy_key(file,(uint) i,(uchar*) read_record2,(uchar*) key2);
+ range_records=mi_records_in_range(file,(int) i,key,0,HA_READ_KEY_EXACT,
+ key2,0,HA_READ_AFTER_KEY);
+ if (range_records < info.records*8/10 ||
+ range_records > info.records*12/10)
+ {
+ printf("mi_records_range returned %ld; Should be about %ld\n",
+ (long) range_records,(long) info.records);
+ goto end;
+ }
+ if (verbose)
+ {
+ printf("mi_records_range returned %ld; Exact is %ld (diff: %4.2g %%)\n",
+ (long) range_records, (long) info.records,
+ labs((long) range_records - (long) info.records)*100.0/
+ info.records);
+ }
+ }
+ for (i=0 ; i < 5 ; i++)
+ {
+ for (j=rnd(1000)+1 ; j>0 && key1[j] == 0 ; j--) ;
+ for (k=rnd(1000)+1 ; k>0 && key1[k] == 0 ; k--) ;
+ if (j != 0 && k != 0)
+ {
+ if (j > k)
+ swap(int,j,k);
+ sprintf(key,"%6d",j);
+ sprintf(key2,"%6d",k);
+ range_records=mi_records_in_range(file,0,key,0,HA_READ_AFTER_KEY,
+ key2,0,HA_READ_BEFORE_KEY);
+ records=0;
+ for (j++ ; j < k ; j++)
+ records+=key1[j];
+ if ((long) range_records < (long) records*7/10-2 ||
+ (long) range_records > (long) records*14/10+2)
+ {
+ printf("mi_records_range for key: %d returned %ld; Should be about %ld\n",
+ i, range_records, records);
+ goto end;
+ }
+ if (verbose && records)
+ {
+ printf("mi_records_range returned %ld; Exact is %ld (diff: %4.2g %%)\n",
+ range_records,records,
+ labs((long) range_records-(long) records)*100.0/records);
+
+ }
+ }
+ }
+
+ if (!silent)
+ printf("- mi_info\n");
+ mi_status(file,&info,HA_STATUS_VARIABLE | HA_STATUS_CONST);
+ if (info.records != write_count-delete || info.deleted > delete + update
+ || info.keys != keys)
+ {
+ puts("Wrong info from mi_info");
+ printf("Got: records: %ld delete: %ld i_keys: %d\n",
+ info.records,info.deleted,info.keys);
+ }
+ if (verbose)
+ {
+ char buff[80];
+ get_date(buff,3,info.create_time);
+ printf("info: Created %s\n",buff);
+ get_date(buff,3,info.check_time);
+ printf("info: checked %s\n",buff);
+ get_date(buff,3,info.update_time);
+ printf("info: Modified %s\n",buff);
+ }
+
+ mi_panic(HA_PANIC_WRITE);
+ mi_panic(HA_PANIC_READ);
+ if (mi_is_changed(file))
+ puts("Warning: mi_is_changed reported that datafile was changed");
+
+ if (!silent)
+ printf("- mi_extra(CACHE) + mi_rrnd.... + mi_extra(NO_CACHE)\n");
+ if (mi_extra(file,HA_EXTRA_RESET) || mi_extra(file,HA_EXTRA_CACHE))
+ {
+ if (locking || (!use_blob && !pack_fields))
+ {
+ puts("got error from mi_extra(HA_EXTRA_CACHE)");
+ goto end;
+ }
+ }
+ ant=0;
+ while ((error=mi_rrnd(file,record,HA_OFFSET_ERROR)) != HA_ERR_END_OF_FILE &&
+ ant < write_count + 10)
+ ant+= error ? 0 : 1;
+ if (ant != write_count-delete)
+ {
+ printf("rrnd with cache: I can only find: %d records of %d\n",
+ ant,write_count-delete);
+ goto end;
+ }
+ if (mi_extra(file,HA_EXTRA_NO_CACHE))
+ {
+ puts("got error from mi_extra(HA_EXTRA_NO_CACHE)");
+ goto end;
+ }
+
+ ant=0;
+ mi_scan_init(file);
+ while ((error=mi_scan(file,record)) != HA_ERR_END_OF_FILE &&
+ ant < write_count + 10)
+ ant+= error ? 0 : 1;
+ if (ant != write_count-delete)
+ {
+ printf("scan with cache: I can only find: %d records of %d\n",
+ ant,write_count-delete);
+ goto end;
+ }
+
+ if (testflag == 4) goto end;
+
+ if (!silent)
+ printf("- Removing keys\n");
+ DBUG_PRINT("progpos",("Removing keys"));
+ lastpos = HA_OFFSET_ERROR;
+ /* DBUG_POP(); */
+ mi_extra(file,HA_EXTRA_RESET);
+ found_parts=0;
+ while ((error=mi_rrnd(file,read_record,HA_OFFSET_ERROR)) !=
+ HA_ERR_END_OF_FILE)
+ {
+ info.recpos=mi_position(file);
+ if (lastpos >= info.recpos && lastpos != HA_OFFSET_ERROR)
+ {
+ printf("mi_rrnd didn't advance filepointer; old: %ld, new: %ld\n",
+ (long) lastpos, (long) info.recpos);
+ goto err;
+ }
+ lastpos=info.recpos;
+ if (error == 0)
+ {
+ if (delete == (uint) remove_count) /* While testing */
+ goto end;
+ if (mi_rsame(file,read_record,-1))
+ {
+ printf("can't find record %lx\n",(long) info.recpos);
+ goto err;
+ }
+ if (use_blob)
+ {
+ ulong blob_length,pos;
+ uchar *ptr;
+ longget(blob_length,read_record+blob_pos+4);
+ ptr=(uchar*) blob_length;
+ longget(blob_length,read_record+blob_pos);
+ for (pos=0 ; pos < blob_length ; pos++)
+ {
+ if (ptr[pos] != (uchar) (blob_length+pos))
+ {
+ printf("found blob with wrong info at %ld\n",(long) lastpos);
+ use_blob=0;
+ break;
+ }
+ }
+ }
+ if (mi_delete(file,read_record))
+ {
+ printf("can't delete record: %6.6s, delete_count: %d\n",
+ read_record, delete);
+ goto err;
+ }
+ delete++;
+ }
+ else
+ found_parts++;
+ }
+ if (my_errno != HA_ERR_END_OF_FILE && my_errno != HA_ERR_RECORD_DELETED)
+ printf("error: %d from mi_rrnd\n",my_errno);
+ if (write_count != delete)
+ {
+ printf("Deleted only %d of %d records (%d parts)\n",delete,write_count,
+ found_parts);
+ goto err;
+ }
+end:
+ if (mi_close(file))
+ goto err;
+ mi_panic(HA_PANIC_CLOSE); /* Should close log */
+ if (!silent)
+ {
+ 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,delete);
+ if (rec_pointer_size)
+ printf("Record pointer size: %d\n",rec_pointer_size);
+ if (key_cacheing)
+ puts("Key cacheing used");
+ if (write_cacheing)
+ puts("Write cacheing used");
+ if (async_io && locking)
+ puts("Asyncron io with locking used");
+ else if (locking)
+ puts("Locking used");
+ if (use_blob)
+ puts("blobs used");
+ printf("key cache status: \n\
+blocks used:%10lu\n\
+w_requests: %10lu\n\
+writes: %10lu\n\
+r_requests: %10lu\n\
+reads: %10lu\n",
+ _my_blocks_used,_my_cache_w_requests, _my_cache_write,
+ _my_cache_r_requests,_my_cache_read);
+ }
+ end_key_cache();
+ if (blob_buffer)
+ my_free(blob_buffer,MYF(0));
+ my_end(MY_CHECK_ERROR | MY_GIVE_INFO);
+ return(0);
+err:
+ printf("got error: %d when using MyISAM-database\n",my_errno);
+ if (file)
+ VOID(mi_close(file));
+ return(1);
+} /* main */
+
+
+ /* l{ser optioner */
+ /* OBS! intierar endast DEBUG - ingen debuggning h{r ! */
+
+static void get_options(int argc, char **argv)
+{
+ char *pos,*progname;
+ DEBUGGER_OFF;
+
+ progname= argv[0];
+
+ while (--argc >0 && *(pos = *(++argv)) == '-' ) {
+ switch(*++pos) {
+ case 'B':
+ pack_type= HA_BINARY_PACK_KEY;
+ break;
+ case 'b':
+ use_blob=1;
+ break;
+ case 'K': /* Use key cacheing */
+ key_cacheing=1;
+ if (*++pos)
+ key_cache_size=atol(pos);
+ break;
+ case 'W': /* Use write cacheing */
+ write_cacheing=1;
+ if (*++pos)
+ my_default_record_cache_size=atoi(pos);
+ break;
+ case 'd':
+ remove_count= atoi(++pos);
+ break;
+ case 'i':
+ if (*++pos)
+ srand(atoi(pos));
+ break;
+ case 'l':
+ use_log=1;
+ break;
+ case 'L':
+ locking=1;
+ break;
+ case 'A': /* use asyncron io */
+ async_io=1;
+ if (*++pos)
+ my_default_record_cache_size=atoi(pos);
+ break;
+ case 'v': /* verbose */
+ verbose=1;
+ break;
+ case 'm': /* records */
+ recant=atoi(++pos);
+ break;
+ case 'f':
+ if ((first_key=atoi(++pos)) < 0 || first_key >= MYISAM_KEYS)
+ first_key=0;
+ break;
+ case 'k':
+ if ((keys=(uint) atoi(++pos)) < 1 ||
+ keys > (uint) (MYISAM_KEYS-first_key))
+ keys=MYISAM_KEYS-first_key;
+ break;
+ case 'P':
+ pack_type=0; /* Don't use DIFF_LENGTH */
+ pack_seg=0;
+ break;
+ case 'R': /* Length of record pointer */
+ rec_pointer_size=atoi(++pos);
+ if (rec_pointer_size > 7)
+ rec_pointer_size=0;
+ break;
+ case 'S':
+ pack_fields=0; /* Static-length-records */
+ break;
+ case 's':
+ silent=1;
+ break;
+ case 't':
+ testflag=atoi(++pos); /* testmod */
+ break;
+ case 'c':
+ create_flag|= HA_CREATE_CHECKSUM;
+ break;
+ case 'D':
+ create_flag|=HA_CREATE_DELAY_KEY_WRITE;
+ break;
+ case '?':
+ case 'I':
+ case 'V':
+ printf("%s Ver 1.1 for %s at %s\n",progname,SYSTEM_TYPE,MACHINE_TYPE);
+ puts("By Monty, for your professional use\n");
+ printf("Usage: %s [-?AbBcDIKLPRSsVWltv] [-k#] [-f#] [-m#] [-t#]\n",
+ progname);
+ exit(0);
+ case '#':
+ DEBUGGER_ON;
+ DBUG_PUSH (++pos);
+ break;
+ default:
+ printf("Illegal option: '%c'\n",*pos);
+ break;
+ }
+ }
+ return;
+} /* get options */
+
+ /* Get a random value 0 <= x <= n */
+
+static uint rnd(uint max_value)
+{
+ return (uint) ((rand() & 32767)/32767.0*max_value);
+} /* rnd */
+
+
+ /* Create a variable length record */
+
+static void fix_length(byte *rec, uint length)
+{
+ bmove(rec+STANDARD_LENGTH,
+ "0123456789012345678901234567890123456789012345678901234567890",
+ length-STANDARD_LENGTH);
+ strfill(rec+length,STANDARD_LENGTH+60-length,' ');
+} /* fix_length */
+
+
+ /* Put maybe a blob in record */
+
+static void put_blob_in_record(char *blob_pos, char **blob_buffer)
+{
+ ulong i,length;
+ if (use_blob)
+ {
+ if (rnd(10) == 0)
+ {
+ if (! *blob_buffer &&
+ !(*blob_buffer=my_malloc((uint) use_blob,MYF(MY_WME))))
+ {
+ use_blob=0;
+ return;
+ }
+ length=rnd(use_blob);
+ for (i=0 ; i < length ; i++)
+ (*blob_buffer)[i]=(char) (length+i);
+ int4store(blob_pos,length);
+ memcpy_fixed(blob_pos+4,(char*) blob_buffer,sizeof(char*));
+ }
+ else
+ {
+ int4store(blob_pos,0);
+ }
+ }
+ return;
+}
+
+
+static void copy_key(MI_INFO *info,uint inx,uchar *rec,uchar *key_buff)
+{
+ MI_KEYSEG *keyseg;
+
+ for (keyseg=info->s->keyinfo[inx].seg ; keyseg->type ; keyseg++)
+ {
+ memcpy(key_buff,rec+keyseg->start,(size_t) keyseg->length);
+ key_buff+=keyseg->length;
+ }
+ return;
+}
diff --git a/myisam/mi_test3.c b/myisam/mi_test3.c
new file mode 100644
index 00000000000..48325b2dcac
--- /dev/null
+++ b/myisam/mi_test3.c
@@ -0,0 +1,485 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* Test av locking */
+
+#include "myisam.h"
+#include <sys/types.h>
+#ifdef HAVE_SYS_WAIT_H
+# include <sys/wait.h>
+#endif
+#ifndef WEXITSTATUS
+# define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
+#endif
+#ifndef WIFEXITED
+# define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
+#endif
+
+
+#if defined(HAVE_LRAND48)
+#define rnd(X) (lrand48() % X)
+#define rnd_init(X) srand48(X)
+#else
+#define rnd(X) (random() % X)
+#define rnd_init(X) srandom(X)
+#endif
+
+
+const char *filename= "test3.MSI";
+uint tests=10,forks=10,key_cacheing=0,use_log=0;
+
+static void get_options(int argc, char *argv[]);
+void start_test(int id);
+int test_read(MI_INFO *,int),test_write(MI_INFO *,int,int),
+ test_update(MI_INFO *,int,int),test_rrnd(MI_INFO *,int);
+
+struct record {
+ char id[8];
+ char nr[4];
+ char text[10];
+} record;
+
+
+int main(int argc,char **argv)
+{
+ int status,wait_ret;
+ uint i=0;
+ MI_KEYDEF keyinfo[10];
+ MI_COLUMNDEF recinfo[10];
+ MI_KEYSEG keyseg[10][2];
+ MY_INIT(argv[0]);
+ get_options(argc,argv);
+
+ bzero((char*) keyinfo,sizeof(keyinfo));
+ bzero((char*) recinfo,sizeof(recinfo));
+ keyinfo[0].seg= &keyseg[0][0];
+ keyinfo[0].seg[0].start=0;
+ keyinfo[0].seg[0].length=8;
+ keyinfo[0].seg[0].type=HA_KEYTYPE_TEXT;
+ keyinfo[0].seg[0].flag=HA_SPACE_PACK;
+ keyinfo[0].keysegs=1;
+ keyinfo[0].flag = (uint8) HA_PACK_KEY;
+ keyinfo[1].seg= &keyseg[1][0];
+ keyinfo[1].seg[0].start=8;
+ keyinfo[1].seg[0].length=4; /* Long is always 4 in myisam */
+ keyinfo[1].seg[0].type=HA_KEYTYPE_LONG_INT;
+ keyinfo[1].seg[0].flag=0;
+ keyinfo[1].keysegs=1;
+ keyinfo[1].flag =HA_NOSAME;
+
+ recinfo[0].type=0;
+ recinfo[0].length=sizeof(record.id);
+ recinfo[1].type=0;
+ recinfo[1].length=sizeof(record.nr);
+ recinfo[2].type=0;
+ recinfo[2].length=sizeof(record.text);
+
+ puts("- Creating myisam-file");
+ my_delete(filename,MYF(0)); /* Remove old locks under gdb */
+ if (mi_create(filename,2,&keyinfo[0],2,&recinfo[0],0,(MI_UNIQUEDEF*) 0,
+ (MI_CREATE_INFO*) 0,0))
+ exit(1);
+
+ rnd_init(0);
+ printf("- Starting %d processes\n",forks); fflush(stdout);
+ for (i=0 ; i < forks; i++)
+ {
+ if (!fork())
+ {
+ start_test(i+1);
+ sleep(1);
+ return 0;
+ }
+ VOID(rnd(1));
+ }
+
+ for (i=0 ; i < forks ; i++)
+ while ((wait_ret=wait(&status)) && wait_ret == -1);
+ return 0;
+}
+
+
+static void get_options(int argc, char **argv)
+{
+ char *pos,*progname;
+ DEBUGGER_OFF;
+
+ progname= argv[0];
+
+ while (--argc >0 && *(pos = *(++argv)) == '-' ) {
+ switch(*++pos) {
+ case 'l':
+ use_log=1;
+ break;
+ case 'f':
+ forks=atoi(++pos);
+ break;
+ case 't':
+ tests=atoi(++pos);
+ break;
+ case 'K': /* Use key cacheing */
+ key_cacheing=1;
+ break;
+ case 'A': /* All flags */
+ use_log=key_cacheing=1;
+ break;
+ case '?':
+ case 'I':
+ case 'V':
+ printf("%s Ver 1.0 for %s at %s\n",progname,SYSTEM_TYPE,MACHINE_TYPE);
+ puts("By Monty, for your professional use\n");
+ puts("Test av locking with threads\n");
+ printf("Usage: %s [-?lKA] [-f#] [-t#]\n",progname);
+ exit(0);
+ case '#':
+ DEBUGGER_ON;
+ DBUG_PUSH (++pos);
+ break;
+ default:
+ printf("Illegal option: '%c'\n",*pos);
+ break;
+ }
+ }
+ return;
+}
+
+
+void start_test(int id)
+{
+ uint i;
+ int error,lock_type;
+ MI_ISAMINFO isam_info;
+ MI_INFO *file,*file1,*file2=0,*lock;
+
+ if (use_log)
+ mi_log(1);
+ if (!(file1=mi_open(filename,O_RDWR,HA_OPEN_WAIT_IF_LOCKED)) ||
+ !(file2=mi_open(filename,O_RDWR,HA_OPEN_WAIT_IF_LOCKED)))
+ {
+ fprintf(stderr,"Can't open isam-file: %s\n",filename);
+ exit(1);
+ }
+ if (key_cacheing && rnd(2) == 0)
+ init_key_cache(65536L,(uint) IO_SIZE*4*10);
+ printf("Process %d, pid: %d\n",id,getpid()); fflush(stdout);
+
+ for (error=i=0 ; i < tests && !error; i++)
+ {
+ file= (rnd(2) == 1) ? file1 : file2;
+ lock=0 ; lock_type=0;
+ if (rnd(10) == 0)
+ {
+ if (mi_lock_database(lock=(rnd(2) ? file1 : file2),
+ lock_type=(rnd(2) == 0 ? F_RDLCK : F_WRLCK)))
+ {
+ fprintf(stderr,"%2d: start: Can't lock table %d\n",id,my_errno);
+ error=1;
+ break;
+ }
+ }
+ switch (rnd(4)) {
+ case 0: error=test_read(file,id); break;
+ case 1: error=test_rrnd(file,id); break;
+ case 2: error=test_write(file,id,lock_type); break;
+ case 3: error=test_update(file,id,lock_type); break;
+ }
+ if (lock)
+ mi_lock_database(lock,F_UNLCK);
+ }
+ if (!error)
+ {
+ mi_status(file1,&isam_info,HA_STATUS_VARIABLE);
+ printf("%2d: End of test. Records: %ld Deleted: %ld\n",
+ id,isam_info.records,isam_info.deleted);
+ fflush(stdout);
+ }
+
+ mi_close(file1);
+ mi_close(file2);
+ if (use_log)
+ mi_log(0);
+ if (error)
+ {
+ printf("%2d: Aborted\n",id); fflush(stdout);
+ exit(1);
+ }
+}
+
+
+int test_read(MI_INFO *file,int id)
+{
+ uint i,lock,found,next,prev;
+ ulong find;
+
+ lock=0;
+ if (rnd(2) == 0)
+ {
+ lock=1;
+ if (mi_lock_database(file,F_RDLCK))
+ {
+ fprintf(stderr,"%2d: Can't lock table %d\n",id,my_errno);
+ return 1;
+ }
+ }
+
+ found=next=prev=0;
+ for (i=0 ; i < 100 ; i++)
+ {
+ find=rnd(100000);
+ if (!mi_rkey(file,record.id,1,(byte*) &find,
+ sizeof(find),HA_READ_KEY_EXACT))
+ found++;
+ else
+ {
+ if (my_errno != HA_ERR_KEY_NOT_FOUND)
+ {
+ fprintf(stderr,"%2d: Got error %d from read in read\n",id,my_errno);
+ return 1;
+ }
+ else if (!mi_rnext(file,record.id,1))
+ next++;
+ else
+ {
+ if (my_errno != HA_ERR_END_OF_FILE)
+ {
+ fprintf(stderr,"%2d: Got error %d from rnext in read\n",id,my_errno);
+ return 1;
+ }
+ else if (!mi_rprev(file,record.id,1))
+ prev++;
+ else
+ {
+ if (my_errno != HA_ERR_END_OF_FILE)
+ {
+ fprintf(stderr,"%2d: Got error %d from rnext in read\n",
+ id,my_errno);
+ return 1;
+ }
+ }
+ }
+ }
+ }
+ if (lock)
+ {
+ if (mi_lock_database(file,F_UNLCK))
+ {
+ fprintf(stderr,"%2d: Can't unlock table\n",id);
+ return 1;
+ }
+ }
+ printf("%2d: read: found: %5d next: %5d prev: %5d\n",
+ id,found,next,prev);
+ fflush(stdout);
+ return 0;
+}
+
+
+int test_rrnd(MI_INFO *file,int id)
+{
+ uint count,lock;
+
+ lock=0;
+ if (rnd(2) == 0)
+ {
+ lock=1;
+ if (mi_lock_database(file,F_RDLCK))
+ {
+ fprintf(stderr,"%2d: Can't lock table (%d)\n",id,my_errno);
+ mi_close(file);
+ return 1;
+ }
+ if (rnd(2) == 0)
+ mi_extra(file,HA_EXTRA_CACHE);
+ }
+
+ count=0;
+ if (mi_rrnd(file,record.id,0L))
+ {
+ if (my_errno == HA_ERR_END_OF_FILE)
+ goto end;
+ fprintf(stderr,"%2d: Can't read first record (%d)\n",id,my_errno);
+ return 1;
+ }
+ for (count=1 ; !mi_rrnd(file,record.id,HA_OFFSET_ERROR) ;count++) ;
+ if (my_errno != HA_ERR_END_OF_FILE)
+ {
+ fprintf(stderr,"%2d: Got error %d from rrnd\n",id,my_errno);
+ return 1;
+ }
+
+end:
+ if (lock)
+ {
+ mi_extra(file,HA_EXTRA_NO_CACHE);
+ if (mi_lock_database(file,F_UNLCK))
+ {
+ fprintf(stderr,"%2d: Can't unlock table\n",id);
+ exit(0);
+ }
+ }
+ printf("%2d: rrnd: %5d\n",id,count); fflush(stdout);
+ return 0;
+}
+
+
+int test_write(MI_INFO *file,int id,int lock_type)
+{
+ uint i,tries,count,lock;
+
+ lock=0;
+ if (rnd(2) == 0 || lock_type == F_RDLCK)
+ {
+ lock=1;
+ if (mi_lock_database(file,F_WRLCK))
+ {
+ if (lock_type == F_RDLCK && my_errno == EDEADLK)
+ {
+ printf("%2d: write: deadlock\n",id); fflush(stdout);
+ return 0;
+ }
+ fprintf(stderr,"%2d: Can't lock table (%d)\n",id,my_errno);
+ mi_close(file);
+ return 1;
+ }
+ if (rnd(2) == 0)
+ mi_extra(file,HA_EXTRA_WRITE_CACHE);
+ }
+
+ sprintf(record.id,"%7d",getpid());
+ strmov(record.text,"Testing...");
+
+ tries=(uint) rnd(100)+10;
+ for (i=count=0 ; i < tries ; i++)
+ {
+ uint32 tmp=rnd(80000)+20000;
+ int4store(record.nr,tmp);
+ if (!mi_write(file,record.id))
+ count++;
+ else
+ {
+ if (my_errno != HA_ERR_FOUND_DUPP_KEY)
+ {
+ fprintf(stderr,"%2d: Got error %d (errno %d) from write\n",id,my_errno,
+ errno);
+ return 1;
+ }
+ }
+ }
+ if (lock)
+ {
+ mi_extra(file,HA_EXTRA_NO_CACHE);
+ if (mi_lock_database(file,F_UNLCK))
+ {
+ fprintf(stderr,"%2d: Can't unlock table\n",id);
+ exit(0);
+ }
+ }
+ printf("%2d: write: %5d\n",id,count); fflush(stdout);
+ return 0;
+}
+
+
+int test_update(MI_INFO *file,int id,int lock_type)
+{
+ uint i,lock,found,next,prev,update;
+ uint32 tmp;
+ char find[4];
+ struct record new_record;
+
+ lock=0;
+ if (rnd(2) == 0 || lock_type == F_RDLCK)
+ {
+ lock=1;
+ if (mi_lock_database(file,F_WRLCK))
+ {
+ if (lock_type == F_RDLCK && my_errno == EDEADLK)
+ {
+ printf("%2d: write: deadlock\n",id); fflush(stdout);
+ return 0;
+ }
+ fprintf(stderr,"%2d: Can't lock table (%d)\n",id,my_errno);
+ return 1;
+ }
+ }
+ bzero((char*) &new_record,sizeof(new_record));
+ strmov(new_record.text,"Updated");
+
+ found=next=prev=update=0;
+ for (i=0 ; i < 100 ; i++)
+ {
+ tmp=rnd(100000);
+ int4store(find,tmp);
+ if (!mi_rkey(file,record.id,1,(byte*) find,
+ sizeof(find),HA_READ_KEY_EXACT))
+ found++;
+ else
+ {
+ if (my_errno != HA_ERR_KEY_NOT_FOUND)
+ {
+ fprintf(stderr,"%2d: Got error %d from read in update\n",id,my_errno);
+ return 1;
+ }
+ else if (!mi_rnext(file,record.id,1))
+ next++;
+ else
+ {
+ if (my_errno != HA_ERR_END_OF_FILE)
+ {
+ fprintf(stderr,"%2d: Got error %d from rnext in update\n",
+ id,my_errno);
+ return 1;
+ }
+ else if (!mi_rprev(file,record.id,1))
+ prev++;
+ else
+ {
+ if (my_errno != HA_ERR_END_OF_FILE)
+ {
+ fprintf(stderr,"%2d: Got error %d from rnext in update\n",
+ id,my_errno);
+ return 1;
+ }
+ continue;
+ }
+ }
+ }
+ memcpy_fixed(new_record.id,record.id,sizeof(record.id));
+ tmp=rnd(20000)+40000;
+ int4store(new_record.nr,tmp);
+ if (!mi_update(file,record.id,new_record.id))
+ update++;
+ else
+ {
+ if (my_errno != HA_ERR_RECORD_CHANGED &&
+ my_errno != HA_ERR_RECORD_DELETED &&
+ my_errno != HA_ERR_FOUND_DUPP_KEY)
+ {
+ fprintf(stderr,"%2d: Got error %d from update\n",id,my_errno);
+ return 1;
+ }
+ }
+ }
+ if (lock)
+ {
+ if (mi_lock_database(file,F_UNLCK))
+ {
+ fprintf(stderr,"Can't unlock table,id, error%d\n",my_errno);
+ return 1;
+ }
+ }
+ printf("%2d: update: %5d\n",id,update); fflush(stdout);
+ return 0;
+}
diff --git a/myisam/mi_test_all.res b/myisam/mi_test_all.res
new file mode 100644
index 00000000000..d6b4703d702
--- /dev/null
+++ b/myisam/mi_test_all.res
@@ -0,0 +1,48 @@
+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
+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)
+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)
+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
diff --git a/myisam/mi_test_all.sh b/myisam/mi_test_all.sh
new file mode 100755
index 00000000000..dfa2e1d0fdd
--- /dev/null
+++ b/myisam/mi_test_all.sh
@@ -0,0 +1,120 @@
+silent="-s"
+suffix=$MACH
+mi_test1$suffix $silent
+myisamchk$suffix -se test1
+mi_test1$suffix $silent -N -S
+myisamchk$suffix -se test1
+mi_test1$suffix $silent -P --checksum
+myisamchk$suffix -se test1
+mi_test1$suffix $silent -P -N -S
+myisamchk$suffix -se test1
+mi_test1$suffix $silent -B -N -R2
+myisamchk$suffix -sm test1
+mi_test1$suffix $silent -a -k 480 --unique
+myisamchk$suffix -sm test1
+mi_test1$suffix $silent -a -N -S -R1
+myisamchk$suffix -sm test1
+mi_test1$suffix $silent -p -S
+myisamchk$suffix -sm test1
+mi_test1$suffix $silent -p -S -N --unique
+myisamchk$suffix -sm test1
+mi_test1$suffix $silent -p -S -N --key_length=127 --checksum
+myisamchk$suffix -sm test1
+mi_test1$suffix $silent -p -S -N --key_length=128
+myisamchk$suffix -sm test1
+mi_test1$suffix $silent -p -S --key_length=480
+myisamchk$suffix -sm test1
+mi_test1$suffix $silent -a -B
+myisamchk$suffix -sm test1
+mi_test1$suffix $silent -a -B --key_length=64 --unique
+myisamchk$suffix -sm test1
+mi_test1$suffix $silent -a -B -k 480 --checksum
+myisamchk$suffix -sm test1
+mi_test1$suffix $silent -a -B -k 480 -N --unique --checksum
+myisamchk$suffix -sm test1
+mi_test1$suffix $silent -a -m
+myisamchk$suffix -sm test1
+mi_test1$suffix $silent -a -m -P --unique --checksum
+myisamchk$suffix -sm test1
+mi_test1$suffix $silent -a -m -P --key_length=480 --key_cache
+myisamchk$suffix -sm test1
+mi_test1$suffix $silent -m -p
+myisamchk$suffix -sm test1
+mi_test1$suffix $silent -w -S --unique
+myisamchk$suffix -sm test1
+mi_test1$suffix $silent -a -w --key_length=64 --checksum
+myisamchk$suffix -sm test1
+mi_test1$suffix $silent -a -w -N --key_length=480
+myisamchk$suffix -sm test1
+mi_test1$suffix $silent -a -w -S --key_length=480 --checksum
+myisamchk$suffix -sm test1
+mi_test1$suffix $silent -a -b -N
+myisamchk$suffix -sm test1
+mi_test1$suffix $silent -a -b --key_length=480
+myisamchk$suffix -sm test1
+mi_test1$suffix $silent -p -B --key_length=480
+myisamchk$suffix -sm test1
+
+mi_test1$suffix $silent --checksum
+myisamchk$suffix -se test1
+myisamchk$suffix -rs test1
+myisamchk$suffix -se test1
+myisamchk$suffix -rqs test1
+myisamchk$suffix -se test1
+
+# check of myisampack / myisamchk
+myisampack$suffix --force -s test1
+myisamchk$suffix -es test1
+myisamchk$suffix -rqs test1
+myisamchk$suffix -es test1
+myisamchk$suffix -rs test1
+myisamchk$suffix -es test1
+myisamchk$suffix -rus test1
+myisamchk$suffix -es test1
+
+mi_test1$suffix $silent --checksum -S
+myisamchk$suffix -se test1
+myisamchk$suffix -ros test1
+myisamchk$suffix -rqs test1
+myisamchk$suffix -se test1
+
+myisampack$suffix --force -s test1
+myisamchk$suffix -rqs test1
+myisamchk$suffix -es test1
+myisamchk$suffix -rus test1
+myisamchk$suffix -es test1
+
+mi_test1$suffix $silent --checksum --unique
+myisamchk$suffix -se test1
+mi_test1$suffix $silent --unique -S
+myisamchk$suffix -se test1
+
+
+mi_test1$suffix $silent --key_multiple -N -S
+myisamchk$suffix -sm test1
+mi_test1$suffix $silent --key_multiple -a -p --key_length=480
+myisamchk$suffix -sm test1
+mi_test1$suffix $silent --key_multiple -a -B --key_length=480
+myisamchk$suffix -sm test1
+mi_test1$suffix $silent --key_multiple -P -S
+myisamchk$suffix -sm test1
+
+mi_test2$suffix $silent -L -K -W -P
+mi_test2$suffix $silent -L -K -W -P -A
+mi_test2$suffix $silent -L -K -W -P -S -R1 -m500
+echo "mi_test2$suffix $silent -L -K -R1 -m2000 ; Should give error 135"
+mi_test2$suffix $silent -L -K -R1 -m2000
+mi_test2$suffix $silent -L -K -P -S -R3 -m50 -b1000000
+mi_test2$suffix $silent -L -B
+mi_test2$suffix $silent -D -B -c
+mi_test2$suffix $silent -L -K -W -P -m50 -l
+myisamlog$suffix
+mi_test2$suffix $silent -L -K -W -P -m50 -l -b100
+myisamlog$suffix
+time mi_test2$suffix $silent
+time mi_test2$suffix $silent -K -B
+time mi_test2$suffix $silent -L -B
+time mi_test2$suffix $silent -L -K -B
+time mi_test2$suffix $silent -L -K -W -B
+time mi_test2$suffix $silent -L -K -W -S -B
+time mi_test2$suffix $silent -D -K -W -S -B
diff --git a/myisam/mi_unique.c b/myisam/mi_unique.c
new file mode 100644
index 00000000000..e598fbeedb4
--- /dev/null
+++ b/myisam/mi_unique.c
@@ -0,0 +1,188 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 check if a row is unique */
+
+#include "myisamdef.h"
+#include <m_ctype.h>
+
+my_bool mi_check_unique(MI_INFO *info, MI_UNIQUEDEF *def, byte *record,
+ ha_checksum unique_hash, my_off_t disk_pos)
+{
+ my_off_t lastpos=info->lastpos;
+ MI_KEYDEF *key= &info->s->keyinfo[def->key];
+ uchar *key_buff=info->lastkey+info->s->base.max_key_length;
+ DBUG_ENTER("mi_check_unique");
+
+ mi_unique_store(record+key->seg->start, unique_hash);
+ _mi_make_key(info,def->key,key_buff,record,0);
+
+ if (_mi_search(info,info->s->keyinfo+def->key,key_buff,MI_UNIQUE_HASH_LENGTH,
+ SEARCH_FIND,info->s->state.key_root[def->key]))
+ {
+ info->page_changed=1; /* Can't optimize read next */
+ info->lastpos= lastpos;
+ DBUG_RETURN(0); /* No matching rows */
+ }
+
+ for (;;)
+ {
+ if (info->lastpos != disk_pos &&
+ !(*info->s->compare_unique)(info,def,record,info->lastpos))
+ {
+ my_errno=HA_ERR_FOUND_DUPP_UNIQUE;
+ info->errkey= (int) def->key;
+ info->dupp_key_pos= info->lastpos;
+ info->page_changed=1; /* Can't optimize read next */
+ info->lastpos=lastpos;
+ DBUG_PRINT("info",("Found duplicate"));
+ DBUG_RETURN(1); /* Found identical */
+ }
+ if (_mi_search_next(info,info->s->keyinfo+def->key, info->lastkey,
+ MI_UNIQUE_HASH_LENGTH, SEARCH_BIGGER,
+ info->s->state.key_root[def->key]) ||
+ bcmp(info->lastkey, key_buff, MI_UNIQUE_HASH_LENGTH))
+ {
+ info->page_changed=1; /* Can't optimize read next */
+ info->lastpos=lastpos;
+ DBUG_RETURN(0); /* end of tree */
+ }
+ }
+}
+
+
+/* Calculate a hash for a row */
+
+ha_checksum mi_unique_hash(MI_UNIQUEDEF *def, const byte *record)
+{
+ const byte *pos, *end;
+ ha_checksum crc=0;
+ MI_KEYSEG *keyseg;
+
+ for (keyseg=def->seg ; keyseg < def->end ; keyseg++)
+ {
+ enum ha_base_keytype type=(enum ha_base_keytype) keyseg->type;
+ uint length=keyseg->length;
+
+ if (keyseg->null_bit)
+ {
+ if (record[keyseg->null_pos] & keyseg->null_bit)
+ continue;
+ }
+ pos= record+keyseg->start;
+ if (keyseg->flag & HA_VAR_LENGTH)
+ {
+ uint tmp_length=uint2korr(pos);
+ pos+=2; /* Skip VARCHAR length */
+ set_if_smaller(length,tmp_length);
+ }
+ else if (keyseg->flag & HA_BLOB_PART)
+ {
+ uint tmp_length=_mi_calc_blob_length(keyseg->bit_start,pos);
+ memcpy_fixed((byte*) &pos,pos+keyseg->bit_start,sizeof(char*));
+ if (!length || length > tmp_length)
+ length=tmp_length; /* The whole blob */
+ }
+ end= pos+length;
+ if (type == HA_KEYTYPE_TEXT || type == HA_KEYTYPE_VARTEXT)
+ {
+ uchar *sort_order=keyseg->charset->sort_order;
+ while (pos != end)
+ crc=((crc << 8) +
+ (((uchar) sort_order[*(uchar*) pos++]))) +
+ (crc >> (8*sizeof(ha_checksum)-8));
+ }
+ else
+ while (pos != end)
+ crc=((crc << 8) +
+ (((uchar) *(uchar*) pos++))) +
+ (crc >> (8*sizeof(ha_checksum)-8));
+ }
+ return crc;
+}
+
+ /*
+ Returns 0 if both rows have equal unique value
+ */
+
+int mi_unique_comp(MI_UNIQUEDEF *def, const byte *a, const byte *b,
+ my_bool null_are_equal)
+{
+ const byte *pos_a, *pos_b, *end;
+ MI_KEYSEG *keyseg;
+
+ for (keyseg=def->seg ; keyseg < def->end ; keyseg++)
+ {
+ enum ha_base_keytype type=(enum ha_base_keytype) keyseg->type;
+ uint length=keyseg->length;
+
+ /* If part is NULL it's regarded as different */
+ if (keyseg->null_bit)
+ {
+ uint tmp;
+ if ((tmp=(a[keyseg->null_pos] & keyseg->null_bit)) !=
+ (uint) (b[keyseg->null_pos] & keyseg->null_bit))
+ return 1;
+ if (tmp)
+ {
+ if (!null_are_equal)
+ return 1;
+ continue;
+ }
+ }
+ pos_a= a+keyseg->start;
+ pos_b= b+keyseg->start;
+ if (keyseg->flag & HA_VAR_LENGTH)
+ {
+ uint tmp_length=uint2korr(pos_a);
+ if (tmp_length != uint2korr(pos_b))
+ return 1;
+ pos_a+=2; /* Skip VARCHAR length */
+ pos_b+=2;
+ set_if_smaller(length,tmp_length);
+ }
+ else if (keyseg->flag & HA_BLOB_PART)
+ {
+ /* Only compare 'length' characters if length<> 0 */
+ uint a_length= _mi_calc_blob_length(keyseg->bit_start,pos_a);
+ uint b_length= _mi_calc_blob_length(keyseg->bit_start,pos_b);
+ /* Check that a and b are of equal length */
+ if (length && a_length > length)
+ a_length=length;
+ if (!length || length > b_length)
+ length=b_length;
+ if (length != a_length)
+ return 1;
+ /* Both strings are at least 'length' long */
+ memcpy_fixed((byte*) &pos_a,pos_a+keyseg->bit_start,sizeof(char*));
+ memcpy_fixed((byte*) &pos_b,pos_b+keyseg->bit_start,sizeof(char*));
+ }
+ end= pos_a+length;
+ if (type == HA_KEYTYPE_TEXT || type == HA_KEYTYPE_VARTEXT)
+ {
+ uchar *sort_order=keyseg->charset->sort_order;
+ while (pos_a != end)
+ if (sort_order[*(uchar*) pos_a++] !=
+ sort_order[*(uchar*) pos_b++])
+ return 1;
+ }
+ else
+ while (pos_a != end)
+ if (*pos_a++ != *pos_b++)
+ return 1;
+ }
+ return 0;
+}
diff --git a/myisam/mi_update.c b/myisam/mi_update.c
new file mode 100644
index 00000000000..185624f3878
--- /dev/null
+++ b/myisam/mi_update.c
@@ -0,0 +1,184 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 an old row in a MyISAM table */
+
+#include "fulltext.h"
+#ifdef __WIN__
+#include <errno.h>
+#endif
+
+
+int mi_update(register MI_INFO *info, const byte *oldrec, byte *newrec)
+{
+ int flag,key_changed,save_errno;
+ reg3 my_off_t pos;
+ uint i;
+ uchar old_key[MI_MAX_KEY_BUFF],*new_key;
+ bool auto_key_changed=0;
+ ulonglong changed;
+ MYISAM_SHARE *share=info->s;
+ ha_checksum old_checksum;
+ DBUG_ENTER("mi_update");
+ LINT_INIT(new_key);
+ LINT_INIT(changed);
+ LINT_INIT(old_checksum);
+
+ if (!(info->update & HA_STATE_AKTIV))
+ {
+ DBUG_RETURN(my_errno=HA_ERR_KEY_NOT_FOUND);
+ }
+ if (share->options & HA_OPTION_READ_ONLY_DATA)
+ {
+ DBUG_RETURN(my_errno=EACCES);
+ }
+ if (info->state->key_file_length >= share->base.margin_key_file_length)
+ {
+ DBUG_RETURN(my_errno=HA_ERR_INDEX_FILE_FULL);
+ }
+ pos=info->lastpos;
+ if (_mi_readinfo(info,F_WRLCK,1))
+ DBUG_RETURN(my_errno);
+
+ if (share->calc_checksum)
+ old_checksum=info->checksum=(*share->calc_checksum)(info,oldrec);
+ if ((*share->compare_record)(info,oldrec))
+ {
+ save_errno=my_errno;
+ goto err_end; /* Record has changed */
+ }
+
+ /* Calculate and check all unique constraints */
+ key_changed=0;
+ for (i=0 ; i < share->state.header.uniques ; i++)
+ {
+ MI_UNIQUEDEF *def=share->uniqueinfo+i;
+ if (mi_unique_comp(def, newrec, oldrec,1) &&
+ mi_check_unique(info, def, newrec, mi_unique_hash(def, newrec),
+ info->lastpos))
+ {
+ save_errno=my_errno;
+ goto err_end;
+ }
+ }
+ if (_mi_mark_file_changed(info))
+ {
+ save_errno=my_errno;
+ goto err_end;
+ }
+
+ /* Check which keys changed from the original row */
+
+ new_key=info->lastkey2;
+ key_changed=HA_STATE_KEY_CHANGED; /* We changed current database */
+ /* Remove key that didn't change */
+ changed=0;
+ for (i=0 ; i < share->base.keys ; i++)
+ {
+ if (((ulonglong) 1 << i) & share->state.key_map)
+ {
+ /* The following code block is for text searching by SerG */
+ if (share->keyinfo[i].flag & HA_FULLTEXT )
+ {
+ if(_mi_ft_cmp(info,i,oldrec, 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))
+ goto err;
+ }
+ }
+ else
+ {
+ uint new_length=_mi_make_key(info,i,new_key,newrec,pos);
+ uint old_length=_mi_make_key(info,i,old_key,oldrec,pos);
+ if (new_length != old_length ||
+ memcmp((byte*) old_key,(byte*) new_key,new_length))
+ {
+ if ((int) i == info->lastinx)
+ key_changed|=HA_STATE_WRITTEN; /* Mark that keyfile changed */
+ changed|=((ulonglong) 1 << i);
+ share->keyinfo[i].version++;
+ if (_mi_ck_delete(info,i,old_key,old_length)) goto err;
+ if (_mi_ck_write(info,i,new_key,new_length)) goto err;
+ if (share->base.auto_key == i+1)
+ auto_key_changed=1;
+ }
+ }
+ }
+ }
+
+ if (share->calc_checksum)
+ info->checksum=(*share->calc_checksum)(info,newrec);
+ if ((*share->update_record)(info,pos,newrec))
+ goto err;
+ if (auto_key_changed)
+ update_auto_increment(info,newrec);
+ if (share->calc_checksum)
+ share->state.checksum+=(info->checksum - old_checksum);
+
+ info->update= (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED | HA_STATE_AKTIV |
+ key_changed);
+ 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 */
+ DBUG_RETURN(0);
+
+err:
+ DBUG_PRINT("error",("key: %d errno: %d",i,my_errno));
+ save_errno=my_errno;
+ if (my_errno == HA_ERR_FOUND_DUPP_KEY || my_errno == HA_ERR_RECORD_FILE_FULL)
+ {
+ info->errkey= (int) i;
+ flag=0;
+ do
+ {
+ if (((ulonglong) 1 << i) & changed)
+ {
+ /* The following code block is for text searching by SerG */
+ if (share->keyinfo[i].flag & HA_FULLTEXT)
+ {
+ if ((flag++ && _mi_ft_del(info,i,(char*) new_key,newrec,pos)) ||
+ _mi_ft_add(info,i,(char*) old_key,oldrec,pos))
+ break;
+ }
+ else
+ {
+ uint new_length=_mi_make_key(info,i,new_key,newrec,pos);
+ uint old_length= _mi_make_key(info,i,old_key,oldrec,pos);
+ if ((flag++ && _mi_ck_delete(info,i,new_key,new_length)) ||
+ _mi_ck_write(info,i,old_key,old_length))
+ break;
+ }
+ }
+ } while (i-- != 0);
+ }
+ else
+ mi_mark_crashed(info);
+ info->update= (HA_STATE_CHANGED | HA_STATE_AKTIV | HA_STATE_ROW_CHANGED |
+ key_changed);
+
+ err_end:
+ myisam_log_record(MI_LOG_UPDATE,info,newrec,info->lastpos,my_errno);
+ VOID(_mi_writeinfo(info,WRITEINFO_UPDATE_KEYFILE));
+ allow_break(); /* Allow SIGHUP & SIGINT */
+ if (save_errno == HA_ERR_KEY_NOT_FOUND)
+ save_errno=HA_ERR_CRASHED;
+ DBUG_RETURN(my_errno=save_errno);
+} /* mi_update */
diff --git a/myisam/mi_write.c b/myisam/mi_write.c
new file mode 100644
index 00000000000..f31e43e52ab
--- /dev/null
+++ b/myisam/mi_write.c
@@ -0,0 +1,684 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 table */
+
+#include "fulltext.h"
+#ifdef __WIN__
+#include <errno.h>
+#endif
+
+#define MAX_POINTER_LENGTH 8
+
+ /* Functions declared in this file */
+
+static int w_search(MI_INFO *info,MI_KEYDEF *keyinfo,uchar *key,
+ uint key_length, my_off_t pos, uchar *father_buff,
+ uchar *father_keypos, my_off_t father_page,
+ my_bool insert_last);
+static int _mi_balance_page(MI_INFO *info,MI_KEYDEF *keyinfo,uchar *key,
+ uchar *curr_buff,uchar *father_buff,
+ uchar *father_keypos,my_off_t father_page);
+static uchar *_mi_find_last_pos(MI_KEYDEF *keyinfo, uchar *page,
+ uchar *key, uint *return_key_length,
+ uchar **after_key);
+
+
+ /* Write new record to database */
+
+int mi_write(MI_INFO *info, byte *record)
+{
+ uint i;
+ int save_errno;
+ my_off_t filepos;
+ uchar *buff;
+ MYISAM_SHARE *share=info->s;
+ DBUG_ENTER("mi_write");
+ DBUG_PRINT("enter",("isam: %d data: %d",info->s->kfile,info->dfile));
+
+ if (share->options & HA_OPTION_READ_ONLY_DATA)
+ {
+ DBUG_RETURN(my_errno=EACCES);
+ }
+ if (_mi_readinfo(info,F_WRLCK,1))
+ DBUG_RETURN(my_errno);
+ dont_break(); /* Dont allow SIGHUP or SIGINT */
+#if !defined(NO_LOCKING) && defined(USE_RECORD_LOCK)
+ if (!info->locked && my_lock(info->dfile,F_WRLCK,0L,F_TO_EOF,
+ MYF(MY_SEEK_NOT_DONE) | info->lock_wait))
+ goto err;
+#endif
+ filepos= ((share->state.dellink != HA_OFFSET_ERROR) ?
+ share->state.dellink :
+ info->state->data_file_length);
+
+ if (share->base.reloc == (ha_rows) 1 &&
+ share->base.records == (ha_rows) 1 &&
+ info->state->records == (ha_rows) 1)
+ { /* System file */
+ my_errno=HA_ERR_RECORD_FILE_FULL;
+ goto err2;
+ }
+ if (info->state->key_file_length >= share->base.margin_key_file_length)
+ {
+ my_errno=HA_ERR_INDEX_FILE_FULL;
+ goto err2;
+ }
+ if (_mi_mark_file_changed(info))
+ goto err2;
+
+ /* Calculate and check all unique constraints */
+ for (i=0 ; i < share->state.header.uniques ; i++)
+ {
+ if (mi_check_unique(info,share->uniqueinfo+i,record,
+ mi_unique_hash(share->uniqueinfo+i,record),
+ HA_OFFSET_ERROR))
+ goto err2;
+ }
+
+ /* Write all keys to indextree */
+
+ buff=info->lastkey2;
+ for (i=0 ; i < share->base.keys ; i++)
+ {
+ if (((ulonglong) 1 << i) & share->state.key_map)
+ {
+ if (share->concurrent_insert)
+ {
+ 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)
+ 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 */
+ {
+ uint key_length=_mi_make_key(info,i,buff,record,filepos);
+ if (_mi_ck_write(info,i,buff,key_length))
+ {
+ if (share->concurrent_insert)
+ rw_unlock(&share->key_root_lock[i]);
+ DBUG_PRINT("error",("Got error: %d on write",my_errno));
+ goto err;
+ }
+ }
+ if (share->concurrent_insert)
+ rw_unlock(&share->key_root_lock[i]);
+ }
+ }
+ if (share->calc_checksum)
+ info->checksum=(*share->calc_checksum)(info,record);
+ if (!(info->opt_flag & OPT_NO_ROWS))
+ {
+ if ((*share->write_record)(info,record))
+ goto err;
+ share->state.checksum+=info->checksum;
+ }
+ if (share->base.auto_key)
+ update_auto_increment(info,record);
+ info->update= (HA_STATE_CHANGED | HA_STATE_AKTIV | HA_STATE_WRITTEN |
+ HA_STATE_ROW_CHANGED);
+ info->state->records++;
+ info->lastpos=filepos;
+ myisam_log_record(MI_LOG_WRITE,info,record,filepos,0);
+ VOID(_mi_writeinfo(info, WRITEINFO_UPDATE_KEYFILE));
+ allow_break(); /* Allow SIGHUP & SIGINT */
+ DBUG_RETURN(0);
+
+err:
+ save_errno=my_errno;
+ if (my_errno == HA_ERR_FOUND_DUPP_KEY || my_errno == HA_ERR_RECORD_FILE_FULL)
+ {
+ info->errkey= (int) i;
+ while ( i-- > 0)
+ {
+ if (((ulonglong) 1 << i) & share->state.key_map)
+ {
+ if (share->concurrent_insert)
+ 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)
+ rw_unlock(&share->key_root_lock[i]);
+ break;
+ }
+ }
+ else
+ {
+ uint key_length=_mi_make_key(info,i,buff,record,filepos);
+ if (_mi_ck_delete(info,i,buff,key_length))
+ {
+ if (share->concurrent_insert)
+ rw_unlock(&share->key_root_lock[i]);
+ break;
+ }
+ }
+ if (share->concurrent_insert)
+ rw_unlock(&share->key_root_lock[i]);
+ }
+ }
+ }
+ else
+ mi_mark_crashed(info);
+ info->update= (HA_STATE_CHANGED | HA_STATE_WRITTEN | HA_STATE_ROW_CHANGED);
+ my_errno=save_errno;
+err2:
+ save_errno=my_errno;
+ myisam_log_record(MI_LOG_WRITE,info,record,filepos,my_errno);
+ VOID(_mi_writeinfo(info,WRITEINFO_UPDATE_KEYFILE));
+ allow_break(); /* Allow SIGHUP & SIGINT */
+ DBUG_RETURN(my_errno=save_errno);
+} /* mi_write */
+
+
+ /* Write one key to btree */
+
+int _mi_ck_write(register MI_INFO *info, uint keynr, uchar *key,
+ uint key_length)
+{
+ int error;
+ DBUG_ENTER("_mi_ck_write");
+
+ if (info->s->state.key_root[keynr] == HA_OFFSET_ERROR ||
+ (error=w_search(info,info->s->keyinfo+keynr,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 */
+
+
+ /* Make a new root with key as only pointer */
+
+int _mi_enlarge_root(register MI_INFO *info, uint keynr, uchar *key)
+{
+ uint t_length,nod_flag;
+ reg2 MI_KEYDEF *keyinfo;
+ MI_KEY_PARAM s_temp;
+ MYISAM_SHARE *share=info->s;
+ DBUG_ENTER("_mi_enlarge_root");
+
+ nod_flag= (share->state.key_root[keynr] != HA_OFFSET_ERROR) ?
+ share->base.key_reflength : 0;
+ _mi_kpointer(info,info->buff+2,share->state.key_root[keynr]); /* if nod */
+ keyinfo=share->keyinfo+keynr;
+ t_length=(*keyinfo->pack_key)(keyinfo,nod_flag,(uchar*) 0,
+ (uchar*) 0, (uchar*) 0, key,&s_temp);
+ mi_putint(info->buff,t_length+2+nod_flag,nod_flag);
+ (*keyinfo->store_key)(keyinfo,info->buff+2+nod_flag,&s_temp);
+ info->buff_used=info->page_changed=1; /* info->buff is used */
+ if ((share->state.key_root[keynr]= _mi_new(info,keyinfo)) ==
+ HA_OFFSET_ERROR ||
+ _mi_write_keypage(info,keyinfo,share->state.key_root[keynr],info->buff))
+ DBUG_RETURN(-1);
+ DBUG_RETURN(0);
+} /* _mi_enlarge_root */
+
+
+ /*
+ Search after a position for a key and store it there
+ Returns -1 = error
+ 0 = ok
+ 1 = key should be stored in higher tree
+ */
+
+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)
+{
+ int error,flag;
+ uint comp_flag,nod_flag;
+ uchar *temp_buff,*keypos;
+ uchar keybuff[MI_MAX_KEY_BUFF];
+ my_bool was_last_key;
+ my_off_t next_page;
+ 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 */
+
+ 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);
+ nod_flag=mi_test_if_nod(temp_buff);
+ if (flag == 0)
+ {
+ uint tmp_key_length;
+ my_errno=HA_ERR_FOUND_DUPP_KEY;
+ /* get position to record with duplicated key */
+ tmp_key_length=(*keyinfo->get_key)(keyinfo,nod_flag,&keypos,keybuff);
+ if (tmp_key_length)
+ info->dupp_key_pos=_mi_dpos(info,0,keybuff+tmp_key_length);
+ else
+ info->dupp_key_pos= HA_OFFSET_ERROR;
+ my_afree((byte*) temp_buff);
+ DBUG_RETURN(-1);
+ }
+ if (flag == MI_FOUND_WRONG_KEY)
+ DBUG_RETURN(-1);
+ if (!was_last_key)
+ 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,
+ temp_buff, keypos, page, insert_last)) >0)
+ {
+ error=_mi_insert(info,keyinfo,key,temp_buff,keypos,keybuff,father_buff,
+ father_keypos,father_page, insert_last);
+ if (_mi_write_keypage(info,keyinfo,page,temp_buff))
+ goto err;
+ }
+ my_afree((byte*) temp_buff);
+ DBUG_RETURN(error);
+err:
+ my_afree((byte*) temp_buff);
+ DBUG_PRINT("exit",("Error: %d",my_errno));
+ DBUG_RETURN (-1);
+} /* w_search */
+
+
+ /* Insert new key at right of key_pos */
+ /* Returns 2 if key contains key to upper level */
+
+int _mi_insert(register MI_INFO *info, register MI_KEYDEF *keyinfo,
+ uchar *key, uchar *anc_buff, uchar *key_pos, uchar *key_buff,
+ uchar *father_buff, uchar *father_key_pos, my_off_t father_page,
+ my_bool insert_last)
+
+{
+ uint a_length,nod_flag;
+ int t_length;
+ uchar *endpos, *prev_key;
+ MI_KEY_PARAM s_temp;
+ DBUG_ENTER("_mi_insert");
+ DBUG_PRINT("enter",("key_pos: %lx",key_pos));
+ DBUG_EXECUTE("key",_mi_print_key(DBUG_FILE,keyinfo->seg,key,USE_WHOLE_KEY););
+
+ nod_flag=mi_test_if_nod(anc_buff);
+ a_length=mi_getint(anc_buff);
+ endpos= anc_buff+ a_length;
+ prev_key=(key_pos == anc_buff+2+nod_flag ? (uchar*) 0 : key_buff);
+ t_length=(*keyinfo->pack_key)(keyinfo,nod_flag,
+ (key_pos == endpos ? (uchar*) 0 : key_pos),
+ prev_key, prev_key,
+ key,&s_temp);
+#ifndef DBUG_OFF
+ if (key_pos != anc_buff+2+nod_flag && (keyinfo->flag &
+ (HA_BINARY_PACK_KEY | HA_PACK_KEY)))
+ DBUG_DUMP("prev_key",(byte*) key_buff,_mi_keylength(keyinfo,key_buff));
+ if (keyinfo->flag & HA_PACK_KEY)
+ {
+ DBUG_PRINT("test",("t_length: %d ref_len: %d",
+ t_length,s_temp.ref_length));
+ DBUG_PRINT("test",("n_ref_len: %d n_length: %d key: %lx",
+ s_temp.n_ref_length,s_temp.n_length,s_temp.key));
+ }
+#endif
+ if (t_length > 0)
+ {
+ if (t_length >= keyinfo->maxlength*2+MAX_POINTER_LENGTH)
+ {
+ my_errno=HA_ERR_CRASHED;
+ DBUG_RETURN(-1);
+ }
+ bmove_upp((byte*) endpos+t_length,(byte*) endpos,(uint) (endpos-key_pos));
+ }
+ else
+ {
+ if (-t_length >= keyinfo->maxlength*2+MAX_POINTER_LENGTH)
+ {
+ my_errno=HA_ERR_CRASHED;
+ DBUG_RETURN(-1);
+ }
+ bmove(key_pos,key_pos-t_length,(uint) (endpos-key_pos)+t_length);
+ }
+ (*keyinfo->store_key)(keyinfo,key_pos,&s_temp);
+ a_length+=t_length;
+ mi_putint(anc_buff,a_length,nod_flag);
+ if (a_length <= keyinfo->block_length)
+ DBUG_RETURN(0); /* There is room on page */
+
+ /* Page is full */
+ if (nod_flag)
+ insert_last=0;
+ if (!(keyinfo->flag & (HA_VAR_LENGTH_KEY | HA_BINARY_PACK_KEY)) &&
+ father_buff && !insert_last)
+ DBUG_RETURN(_mi_balance_page(info,keyinfo,key,anc_buff,father_buff,
+ father_key_pos,father_page));
+ DBUG_RETURN(_mi_split_page(info,keyinfo,key,anc_buff,key_buff, insert_last));
+} /* _mi_insert */
+
+
+ /* split a full page in two and assign emerging item to key */
+
+int _mi_split_page(register MI_INFO *info, register MI_KEYDEF *keyinfo,
+ uchar *key, uchar *buff, uchar *key_buff,
+ my_bool insert_last_key)
+{
+ uint length,a_length,key_ref_length,t_length,nod_flag,key_length;
+ uchar *key_pos,*pos, *after_key;
+ my_off_t new_pos;
+ MI_KEY_PARAM s_temp;
+ DBUG_ENTER("mi_split_page");
+ DBUG_DUMP("buff",(byte*) buff,mi_getint(buff));
+
+ if (info->s->keyinfo+info->lastinx == keyinfo)
+ info->page_changed=1; /* Info->buff is used */
+ info->buff_used=1;
+ nod_flag=mi_test_if_nod(buff);
+ key_ref_length=2+nod_flag;
+ if (insert_last_key)
+ key_pos=_mi_find_last_pos(keyinfo,buff,key_buff, &key_length, &after_key);
+ else
+ key_pos=_mi_find_half_pos(nod_flag,keyinfo,buff,key_buff, &key_length,
+ &after_key);
+ if (!key_pos)
+ DBUG_RETURN(-1);
+ length=(uint) (key_pos-buff);
+ a_length=mi_getint(buff);
+ mi_putint(buff,length,nod_flag);
+
+ key_pos=after_key;
+ if (nod_flag)
+ {
+ DBUG_PRINT("test",("Splitting nod"));
+ pos=key_pos-nod_flag;
+ memcpy((byte*) info->buff+2,(byte*) pos,(size_t) nod_flag);
+ }
+
+ /* Move middle item to key and pointer to new page */
+ if ((new_pos=_mi_new(info,keyinfo)) == HA_OFFSET_ERROR)
+ DBUG_RETURN(-1);
+ _mi_kpointer(info,_mi_move_key(keyinfo,key,key_buff),new_pos);
+
+ /* Store new page */
+ if (!(*keyinfo->get_key)(keyinfo,nod_flag,&key_pos,key_buff))
+ DBUG_RETURN(-1);
+ t_length=(*keyinfo->pack_key)(keyinfo,nod_flag,(uchar *) 0,
+ (uchar*) 0, (uchar*) 0,
+ key_buff, &s_temp);
+ length=(uint) ((buff+a_length)-key_pos);
+ memcpy((byte*) info->buff+key_ref_length+t_length,(byte*) key_pos,
+ (size_t) length);
+ (*keyinfo->store_key)(keyinfo,info->buff+key_ref_length,&s_temp);
+ mi_putint(info->buff,length+t_length+key_ref_length,nod_flag);
+
+ if (_mi_write_keypage(info,keyinfo,new_pos,info->buff))
+ DBUG_RETURN(-1);
+ DBUG_DUMP("key",(byte*) key,_mi_keylength(keyinfo,key));
+ DBUG_RETURN(2); /* Middle key up */
+} /* _mi_split_page */
+
+
+ /*
+ Calculate how to much to move to split a page in two
+ Returns pointer to start of key.
+ key will contain the key.
+ return_key_length will contain the length of key
+ after_key will contain the position to where the next key starts
+ */
+
+uchar *_mi_find_half_pos(uint nod_flag, MI_KEYDEF *keyinfo, uchar *page,
+ uchar *key, uint *return_key_length,
+ uchar **after_key)
+{
+ uint keys,length,key_ref_length;
+ uchar *end,*lastpos;
+ DBUG_ENTER("_mi_find_half_pos");
+
+ key_ref_length=2+nod_flag;
+ length=mi_getint(page)-key_ref_length;
+ page+=key_ref_length;
+ if (!(keyinfo->flag &
+ (HA_PACK_KEY | HA_SPACE_PACK_USED | HA_VAR_LENGTH_KEY |
+ HA_BINARY_PACK_KEY)))
+ {
+ key_ref_length=keyinfo->keylength+nod_flag;
+ keys=length/(key_ref_length*2);
+ *return_key_length=keyinfo->keylength;
+ end=page+keys*key_ref_length;
+ *after_key=end+key_ref_length;
+ memcpy(key,end,key_ref_length);
+ DBUG_RETURN(end);
+ }
+
+ end=page+length/2-key_ref_length; /* This is aprox. half */
+ *key='\0';
+ do
+ {
+ lastpos=page;
+ if (!(length=(*keyinfo->get_key)(keyinfo,nod_flag,&page,key)))
+ DBUG_RETURN(0);
+ } while (page < end);
+ *return_key_length=length;
+ *after_key=page;
+ DBUG_PRINT("exit",("returns: %lx page: %lx half: %lx",lastpos,page,end));
+ DBUG_RETURN(lastpos);
+} /* _mi_find_half_pos */
+
+
+ /*
+ Split buffer at last key
+ Returns pointer to the start of the key before the last key
+ key will contain the last key
+ */
+
+static uchar *_mi_find_last_pos(MI_KEYDEF *keyinfo, uchar *page,
+ uchar *key, uint *return_key_length,
+ uchar **after_key)
+{
+ uint keys,length,last_length,key_ref_length;
+ uchar *end,*lastpos,*prevpos;
+ uchar key_buff[MI_MAX_KEY_BUFF];
+ DBUG_ENTER("_mi_find_last_pos");
+
+ key_ref_length=2;
+ length=mi_getint(page)-key_ref_length;
+ page+=key_ref_length;
+ if (!(keyinfo->flag &
+ (HA_PACK_KEY | HA_SPACE_PACK_USED | HA_VAR_LENGTH_KEY |
+ HA_BINARY_PACK_KEY)))
+ {
+ keys=length/keyinfo->keylength-2;
+ *return_key_length=length=keyinfo->keylength;
+ end=page+keys*length;
+ *after_key=end+length;
+ memcpy(key,end,length);
+ DBUG_RETURN(end);
+ }
+
+ LINT_INIT(prevpos);
+ LINT_INIT(last_length);
+ end=page+length-key_ref_length;
+ *key='\0';
+ length=0;
+ lastpos=page;
+ while (page < end)
+ {
+ prevpos=lastpos; lastpos=page;
+ last_length=length;
+ memcpy(key, key_buff, length); /* previous key */
+ if (!(length=(*keyinfo->get_key)(keyinfo,0,&page,key_buff)))
+ {
+ my_errno=HA_ERR_CRASHED;
+ DBUG_RETURN(0);
+ }
+ }
+ *return_key_length=last_length;
+ *after_key=lastpos;
+ DBUG_PRINT("exit",("returns: %lx page: %lx end: %lx",prevpos,page,end));
+ DBUG_RETURN(prevpos);
+} /* _mi_find_last_pos */
+
+
+ /* Balance page with not packed keys with page on right/left */
+ /* returns 0 if balance was done */
+
+static int _mi_balance_page(register MI_INFO *info, MI_KEYDEF *keyinfo,
+ uchar *key, uchar *curr_buff, uchar *father_buff,
+ uchar *father_key_pos, my_off_t father_page)
+{
+ my_bool right;
+ uint k_length,father_length,father_keylength,nod_flag,curr_keylength,
+ right_length,left_length,new_right_length,new_left_length,extra_length,
+ length,keys;
+ uchar *pos,*buff,*extra_buff;
+ my_off_t next_page,new_pos;
+ byte tmp_part_key[MI_MAX_KEY_BUFF];
+ DBUG_ENTER("_mi_balance_page");
+
+ k_length=keyinfo->keylength;
+ father_length=mi_getint(father_buff);
+ father_keylength=k_length+info->s->base.key_reflength;
+ nod_flag=mi_test_if_nod(curr_buff);
+ curr_keylength=k_length+nod_flag;
+ info->page_changed=1;
+
+ if ((father_key_pos != father_buff+father_length && (info->s->rnd++ & 1)) ||
+ father_key_pos == father_buff+2+info->s->base.key_reflength)
+ {
+ right=1;
+ next_page= _mi_kpos(info->s->base.key_reflength,
+ father_key_pos+father_keylength);
+ buff=info->buff;
+ DBUG_PRINT("test",("use right page: %lu",next_page));
+ }
+ else
+ {
+ right=0;
+ father_key_pos-=father_keylength;
+ next_page= _mi_kpos(info->s->base.key_reflength,father_key_pos);
+ /* Fix that curr_buff is to left */
+ buff=curr_buff; curr_buff=info->buff;
+ DBUG_PRINT("test",("use left page: %lu",next_page));
+ } /* father_key_pos ptr to parting key */
+
+ if (!_mi_fetch_keypage(info,keyinfo,next_page,info->buff,0))
+ goto err;
+ DBUG_DUMP("next",(byte*) info->buff,mi_getint(info->buff));
+
+ /* Test if there is room to share keys */
+
+ left_length=mi_getint(curr_buff);
+ right_length=mi_getint(buff);
+ keys=(left_length+right_length-4-nod_flag*2)/curr_keylength;
+
+ if ((right ? right_length : left_length) + curr_keylength <=
+ keyinfo->block_length)
+ { /* Merge buffs */
+ new_left_length=2+nod_flag+(keys/2)*curr_keylength;
+ new_right_length=2+nod_flag+((keys+1)/2)*curr_keylength;
+ mi_putint(curr_buff,new_left_length,nod_flag);
+ mi_putint(buff,new_right_length,nod_flag);
+
+ if (left_length < new_left_length)
+ { /* Move keys buff -> leaf */
+ pos=curr_buff+left_length;
+ memcpy((byte*) pos,(byte*) father_key_pos, (size_t) k_length);
+ memcpy((byte*) pos+k_length, (byte*) buff+2,
+ (size_t) (length=new_left_length - left_length - k_length));
+ pos=buff+2+length;
+ memcpy((byte*) father_key_pos,(byte*) pos,(size_t) k_length);
+ bmove((byte*) buff+2,(byte*) pos+k_length,new_right_length);
+ }
+ else
+ { /* Move keys -> buff */
+
+ bmove_upp((byte*) buff+new_right_length,(byte*) buff+right_length,
+ right_length-2);
+ length=new_right_length-right_length-k_length;
+ memcpy((byte*) buff+2+length,father_key_pos,(size_t) k_length);
+ pos=curr_buff+new_left_length;
+ memcpy((byte*) father_key_pos,(byte*) pos,(size_t) k_length);
+ memcpy((byte*) buff+2,(byte*) pos+k_length,(size_t) length);
+ }
+
+ if (_mi_write_keypage(info,keyinfo,next_page,info->buff) ||
+ _mi_write_keypage(info,keyinfo,father_page,father_buff))
+ goto err;
+ DBUG_RETURN(0);
+ }
+
+ /* curr_buff[] and buff[] are full, lets split and make new nod */
+
+ extra_buff=info->buff+info->s->base.max_key_block_length;
+ new_left_length=new_right_length=2+nod_flag+(keys+1)/3*curr_keylength;
+ if (keys == 5) /* Too few keys to balance */
+ new_left_length-=curr_keylength;
+ extra_length=nod_flag+left_length+right_length-
+ new_left_length-new_right_length-curr_keylength;
+ DBUG_PRINT("info",("left_length: %d right_length: %d new_left_length: %d new_right_length: %d extra_length: %d",
+ left_length, right_length,
+ new_left_length, new_right_length,
+ extra_length));
+ mi_putint(curr_buff,new_left_length,nod_flag);
+ mi_putint(buff,new_right_length,nod_flag);
+ mi_putint(extra_buff,extra_length+2,nod_flag);
+
+ /* move first largest keys to new page */
+ pos=buff+right_length-extra_length;
+ memcpy((byte*) extra_buff+2,pos,(size_t) extra_length);
+ /* Save new parting key */
+ memcpy(tmp_part_key, pos-k_length,k_length);
+ /* Make place for new keys */
+ bmove_upp((byte*) buff+new_right_length,(byte*) pos-k_length,
+ right_length-extra_length-k_length-2);
+ /* Copy keys from left page */
+ pos= curr_buff+new_left_length;
+ memcpy((byte*) buff+2,(byte*) pos+k_length,
+ (size_t) (length=left_length-new_left_length-k_length));
+ /* Copy old parting key */
+ memcpy((byte*) buff+2+length,father_key_pos,(size_t) k_length);
+
+ /* Move new parting keys up to caller */
+ memcpy((byte*) (right ? key : father_key_pos),pos,(size_t) k_length);
+ memcpy((byte*) (right ? father_key_pos : key),tmp_part_key, k_length);
+
+ if ((new_pos=_mi_new(info,keyinfo)) == HA_OFFSET_ERROR)
+ goto err;
+ _mi_kpointer(info,key+k_length,new_pos);
+ if (_mi_write_keypage(info,keyinfo,(right ? new_pos : next_page),
+ info->buff) ||
+ _mi_write_keypage(info,keyinfo,(right ? next_page : new_pos),extra_buff))
+ goto err;
+
+ DBUG_RETURN(1); /* Middle key up */
+
+err:
+ DBUG_RETURN(-1);
+} /* _mi_balance_page */
diff --git a/myisam/myisamchk.c b/myisam/myisamchk.c
new file mode 100644
index 00000000000..4f2288322e8
--- /dev/null
+++ b/myisam/myisamchk.c
@@ -0,0 +1,1365 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* Descript, check and repair of ISAM tables */
+
+#include "myisamdef.h"
+
+#include <m_ctype.h>
+#include <stdarg.h>
+#include <getopt.h>
+#include <assert.h>
+#ifdef HAVE_SYS_VADVICE_H
+#include <sys/vadvise.h>
+#endif
+#ifdef HAVE_SYS_MMAN_H
+#include <sys/mman.h>
+#endif
+SET_STACK_SIZE(9000) /* Minimum stack size for program */
+
+#ifndef USE_RAID
+#define my_raid_create(A,B,C,D,E,F,G) my_create(A,B,C,G)
+#define my_raid_delete(A,B,C) my_delete(A,B)
+#endif
+
+static uint decode_bits;
+static char **default_argv;
+static const char *load_default_groups[]= { "myisamchk", 0 };
+static const char *set_charset_name;
+static uint8 set_charset_number;
+static CHARSET_INFO *set_charset;
+
+static const char *type_names[]=
+{ "?","char","binary", "short", "long", "float",
+ "double","number","unsigned short",
+ "unsigned long","longlong","ulonglong","int24",
+ "uint24","int8","varchar", "varbin","?",
+ "?"};
+
+static const char *prefix_packed_txt="packed ",
+ *bin_packed_txt="prefix ",
+ *diff_txt="stripped ",
+ *null_txt="NULL",
+ *blob_txt="BLOB ";
+
+static const char *field_pack[]=
+{"","no endspace", "no prespace",
+ "no zeros", "blob", "constant", "table-lockup",
+ "always zero","varchar","unique-hash","?","?"};
+
+
+static void get_options(int *argc,char * * *argv);
+static void print_version(void);
+static void usage(void);
+static int myisamchk(MI_CHECK *param, char *filename);
+static void descript(MI_CHECK *param, register MI_INFO *info, my_string name);
+static int mi_sort_records(MI_CHECK *param,
+ register MI_INFO *info, my_string name,
+ uint sort_key,
+ my_bool write_info,
+ my_bool update_index);
+static int sort_record_index(MI_CHECK *param,MI_INFO *info,MI_KEYDEF *keyinfo,
+ my_off_t page,uchar *buff,uint sortkey,
+ File new_file, my_bool update_index);
+
+MI_CHECK check_param;
+
+ /* Main program */
+
+int main(int argc, char **argv)
+{
+ int error;
+ MY_INIT(argv[0]);
+
+ myisamchk_init(&check_param);
+ check_param.opt_lock_memory=1; /* Lock memory if possible */
+ check_param.using_global_keycache = 0;
+ get_options(&argc,(char***) &argv);
+ myisam_quick_table_bits=decode_bits;
+ error=0;
+ while (--argc >= 0)
+ {
+ error|= myisamchk(&check_param, *(argv++));
+ VOID(fflush(stdout));
+ VOID(fflush(stderr));
+ if ((check_param.error_printed | check_param.warning_printed) &&
+ (check_param.testflag & T_FORCE_CREATE) &&
+ (!(check_param.testflag & (T_REP | T_REP_BY_SORT | T_SORT_RECORDS |
+ T_SORT_INDEX))))
+ {
+ uint old_testflag=check_param.testflag;
+ check_param.testflag|=T_REP;
+ check_param.testflag&= ~T_EXTEND; /* Don't needed */
+ error|=myisamchk(&check_param, argv[-1]);
+ check_param.testflag= old_testflag;
+ VOID(fflush(stdout));
+ VOID(fflush(stderr));
+ }
+ if (argc && (!(check_param.testflag & T_SILENT) || check_param.testflag & T_INFO))
+ {
+ puts("\n---------\n");
+ VOID(fflush(stdout));
+ }
+ }
+ if (check_param.total_files > 1)
+ { /* Only if descript */
+ char buff[22],buff2[22];
+ if (!(check_param.testflag & T_SILENT) || check_param.testflag & T_INFO)
+ puts("\n---------\n");
+ printf("\nTotal of all %d ISAM-files:\nData records: %9s Deleted blocks: %9s\n",check_param.total_files,llstr(check_param.total_records,buff),
+ llstr(check_param.total_deleted,buff2));
+ }
+ free_defaults(default_argv);
+ my_end(check_param.testflag & T_INFO ? MY_CHECK_ERROR | MY_GIVE_INFO : MY_CHECK_ERROR);
+ exit(error);
+#ifndef _lint
+ return 0; /* No compiler warning */
+#endif
+} /* main */
+
+
+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};
+
+
+static struct option long_options[] =
+{
+ {"analyze", no_argument, 0, 'a'},
+ {"block-search", required_argument, 0, 'b'},
+ {"character-sets-dir",required_argument,0, OPT_CHARSETS_DIR},
+ {"check", no_argument, 0, 'c'},
+ {"check-only-changed",no_argument, 0, 'C'},
+#ifndef DBUG_OFF
+ {"debug", required_argument, 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'},
+ {"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'},
+ {"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}
+};
+
+static void print_version(void)
+{
+ printf("%s Ver 1.28 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");
+ puts("Description, check and repair of ISAM tables.");
+ puts("Used without options all tables on the command will be checked for errors");
+ printf("Usage: %s [OPTIONS] tables[.MYI]\n", my_progname);
+ puts("\nGlobal options:\n\
+ -#, --debug=... Output debug log. Often this is 'd:t:o,filename`\n\
+ -?, --help Display this help and exit.\n\
+ -O, --set-variable var=option\n\
+ Change the value of a variable.\n\
+ -s, --silent Only print errors. One can use two -s to make\n\
+ myisamchk very silent\n\
+ -v, --verbose Print more information. This can be used with\n\
+ --describe and --check. Use many -v for more verbosity!\n\
+ -V, --version Print version and exit.\n\
+ -w, --wait Wait if table is locked.\n");
+
+ puts("Check options (check is the default action for myisamchk):\n\
+ -c, --check Check table for errors\n\
+ -e, --extend-check Check the table VERY throughly. Only use this in\n\
+ extreme cases as myisamchk should normally be able to\n\
+ find out if the table is ok even without this switch\n\
+ -F, --fast Check only tables that hasn't been closed properly\n\
+ -C, --check-changed-tables\n\
+ Check only tables that has changed since last check\n\
+ -f, --force Restart with -r if there are any errors in the table\n\
+ -i, --information Print statistics information about table that is checked\n\
+ -m, --medium-check Faster than extended-check, but only finds 99.99% of\n\
+ all errors. Should however be good enough for most cases\n\
+ -U --update-state Mark tables as crashed if you find any errors\n\
+ -T, --read-only Don't mark table as checked\n");
+
+ puts("Repair options (When using -r or -o) \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\
+ Normally this will also find a lot of garbage rows;\n\
+ Don't use this option if you are not totally desperate.\n\
+ -f, --force Overwrite old temporary files.\n\
+ -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\
+ -o, --safe-recover Uses old recovery method; Slower than '-r' but can\n\
+ handle a couple of cases where '-r' reports that it can't\n\
+ fix the data file.\n\
+ --character-sets-dir=...\n\
+ Directory where character sets are\n\
+ --set-character-set=name\n\
+ Change the character set used by the index\n\
+ -t, --tmpdir=path Path for temporary files\n\
+ -q, --quick Faster repair by not modifying the data file.\n\
+ One can give a second '-q' to force myisamchk to\n\
+ modify the original datafile in case of duplicate keys\n\
+ -u, --unpack Unpack file packed with myisampack.\n\
+");
+
+ puts("Other actions:\n\
+ -a, --analyze Analyze distribution of keys. Will make some joins in\n\
+ MySQL faster. You can check the calculated distribution\n\
+ by using '--describe --verbose table_name'.\n\
+ -d, --description Prints some information about table.\n\
+ -A, --set-auto-increment[=value]\n\
+ Force auto_increment to start at this or higher value\n\
+ If no value is given, then sets the next auto_increment\n\
+ value to the highest used value for the auto key + 1.\n\
+ -S, --sort-index Sort index blocks. This speeds up 'read-next' in\n\
+ applications\n\
+ -R, --sort-records=#\n\
+ Sort records according to an index. This makes your\n\
+ 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);
+}
+
+
+ /* Read options */
+
+static void get_options(register int *argc,register char ***argv)
+{
+ 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,"acCdeif?lqrmosSTuUvVw#:b:D:k:O:R:A::t:",
+ long_options, &option_index)) != EOF)
+ {
+ switch(c) {
+ case 'a':
+ 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 'c':
+ check_param.testflag|= T_CHECK;
+ break;
+ case 'C':
+ 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 */
+ if (check_param.testflag & T_SILENT)
+ check_param.testflag|=T_VERY_SILENT;
+ check_param.testflag|= T_SILENT;
+ check_param.testflag&= ~T_WRITE_LOOP;
+ break;
+ case 'w':
+ check_param.testflag|= T_WAIT_FOREVER;
+ break;
+ case 'd': /* description if isam-file */
+ check_param.testflag|= T_DESCRIPT;
+ break;
+ case 'e': /* extend check */
+ check_param.testflag|= T_EXTEND;
+ break;
+ case 'i':
+ check_param.testflag|= T_INFO;
+ break;
+ case 'f':
+ check_param.tmpfile_createflag= O_RDWR | O_TRUNC;
+ check_param.testflag|=T_FORCE_CREATE;
+ 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':
+ check_param.testflag|= T_MEDIUM; /* Medium check */
+ break;
+ case 'r': /* Repair table */
+ check_param.testflag= (check_param.testflag & ~T_REP) | T_REP_BY_SORT;
+ break;
+ case 'o':
+ check_param.testflag= (check_param.testflag & ~T_REP_BY_SORT) | T_REP;
+ my_disable_async_io=1; /* More safety */
+ break;
+ case 'q':
+ check_param.opt_rep_quick++;
+ break;
+ case 'u':
+ check_param.testflag|= T_UNPACK | T_REP_BY_SORT;
+ break;
+ case 'v': /* Verbose */
+ 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;
+ check_param.testflag|= T_SORT_RECORDS;
+ check_param.opt_sort_key=(uint) atoi(optarg)-1;
+ if (check_param.opt_sort_key >= MI_MAX_KEY)
+ {
+ fprintf(stderr,
+ "The value of the sort key is bigger than max key: %d.\n",
+ MI_MAX_KEY);
+ exit(1);
+ }
+ break;
+ case 'S': /* Sort index */
+ old_testflag=check_param.testflag;
+ check_param.testflag|= T_SORT_INDEX;
+ break;
+ case 't':
+ check_param.tmpdir=optarg;
+ break;
+ case 'T':
+ check_param.testflag|= T_READONLY;
+ break;
+ case 'U':
+ check_param.testflag|= T_UPDATE_STATE;
+ break;
+ case '#':
+ DBUG_PUSH(optarg ? optarg : "d:t:o,/tmp/isamchk");
+ break;
+ case 'V':
+ print_version();
+ exit(0);
+ case OPT_CHARSETS_DIR:
+ charsets_dir = optarg;
+ break;
+ case OPT_SET_CHARSET:
+ set_charset_name=optarg;
+ break;
+ case '?':
+ usage();
+ exit(0);
+ }
+ }
+ (*argc)-=optind;
+ (*argv)+=optind;
+ if (*argc == 0)
+ {
+ usage();
+ exit(-1);
+ }
+ if ((check_param.testflag & T_UNPACK) &&
+ (check_param.opt_rep_quick || (check_param.testflag & T_SORT_RECORDS)))
+ {
+ VOID(fprintf(stderr,
+ "%s: --unpack can't be used with --quick or --sort-records\n",
+ my_progname));
+ exit(1);
+ }
+ if ((check_param.testflag & T_READONLY) &&
+ (check_param.testflag &
+ (T_REP_BY_SORT | T_REP | T_STATISTICS | T_AUTO_INC |
+ T_SORT_RECORDS | T_SORT_INDEX)))
+ {
+ VOID(fprintf(stderr,
+ "%s: Can't use --readonly when repairing or sorting\n",
+ my_progname));
+ exit(1);
+ }
+
+ if (set_charset_name)
+ if (!(set_charset=get_charset_by_name(set_charset_name, MYF(MY_WME))))
+ exit(1);
+
+ return;
+} /* get options */
+
+
+ /* Check table */
+
+static int myisamchk(MI_CHECK *param, my_string filename)
+{
+ int error,lock_type,recreate;
+ int rep_quick= param->opt_rep_quick;
+ uint raid_chunks;
+ MI_INFO *info;
+ File datafile;
+ char fixed_name[FN_REFLEN];
+ char llbuff[22],llbuff2[22];
+ MYISAM_SHARE *share;
+ DBUG_ENTER("myisamchk");
+
+ param->out_flag=error=param->warning_printed=param->error_printed=
+ recreate=0;
+ datafile=0;
+ param->isam_file_name=filename; /* For error messages */
+ if (!(info=mi_open(filename,
+ (param->testflag & (T_DESCRIPT | T_READONLY)) ?
+ O_RDONLY : 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)))
+ {
+ /* Avoid twice printing of isam file name */
+ param->error_printed=1;
+ switch (my_errno) {
+ case HA_ERR_CRASHED:
+ mi_check_print_error(param,"'%s' is not a MyISAM-table",filename);
+ break;
+ case HA_ERR_OLD_FILE:
+ mi_check_print_error(param,"'%s' is a old type of MyISAM-table", filename);
+ break;
+ case HA_ERR_END_OF_FILE:
+ mi_check_print_error(param,"Couldn't read complete header from '%s'", filename);
+ break;
+ case EAGAIN:
+ mi_check_print_error(param,"'%s' is locked. Use -w to wait until unlocked",filename);
+ break;
+ case ENOENT:
+ mi_check_print_error(param,"File '%s' doesn't exist",filename);
+ break;
+ case EACCES:
+ mi_check_print_error(param,"You don't have permission to use '%s'",filename);
+ break;
+ default:
+ mi_check_print_error(param,"%d when opening MyISAM-table '%s'",
+ my_errno,filename);
+ break;
+ }
+ DBUG_RETURN(1);
+ }
+ share=info->s;
+ share->options&= ~HA_OPTION_READ_ONLY_DATA; /* We are modifing it */
+ share->r_locks=0;
+ raid_chunks=share->base.raid_chunks;
+
+
+ /*
+ Skipp the checking of the file if:
+ We are using --fast and the table is closed properly
+ We are using --check-only-changed-tables and the table hasn't changed
+ */
+ if ((param->testflag & T_CHECK_ONLY_CHANGED) && !share->state.changed ||
+ (param->testflag & T_FAST) && share->state.open_count == 0)
+ {
+ if (!(param->testflag & T_SILENT) || param->testflag & T_INFO)
+ printf("MyISAM file: %s is already checked\n",filename);
+ if (mi_close(info))
+ {
+ mi_check_print_error(param,"%d when closing MyISAM-table '%s'",
+ my_errno,filename);
+ DBUG_RETURN(1);
+ }
+ DBUG_RETURN(0);
+ }
+
+ if ((param->testflag & (T_REP_BY_SORT | T_REP | T_STATISTICS |
+ T_SORT_RECORDS | T_SORT_INDEX)) &&
+ (((param->testflag & T_UNPACK) &&
+ share->data_file_type == COMPRESSED_RECORD) ||
+ mi_uint2korr(share->state.header.state_info_length) !=
+ MI_STATE_INFO_SIZE ||
+ mi_uint2korr(share->state.header.base_info_length) !=
+ MI_BASE_INFO_SIZE ||
+ ((param->keys_in_use & ~share->state.key_map) &
+ (((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)))
+ {
+ check_param.language=set_charset_number;
+ if (recreate_table(&check_param, &info,filename))
+ {
+ VOID(fprintf(stderr,
+ "MyISAM-table '%s' is not fixed because of errors\n",
+ filename));
+ return(-1);
+ }
+ recreate=1;
+ if (!(param->testflag & (T_REP | T_REP_BY_SORT)))
+ {
+ 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;
+ }
+ share=info->s;
+ share->r_locks=0;
+ }
+
+ if (param->testflag & T_DESCRIPT)
+ {
+ param->total_files++;
+ param->total_records+=info->state->records;
+ param->total_deleted+=info->state->del;
+ descript(&check_param, info, filename);
+ }
+ else
+ {
+ if (!(param->testflag & T_READONLY))
+ lock_type = F_WRLCK; /* table is changed */
+ else
+ lock_type= F_RDLCK;
+ if (info->lock_type == F_RDLCK)
+ info->lock_type=F_UNLCK; /* Read only table */
+ if (_mi_readinfo(info,lock_type,0))
+ {
+ mi_check_print_error(param,"Can't lock indexfile of '%s', error: %d",
+ filename,my_errno);
+ param->error_printed=0;
+ goto end2;
+ }
+ share->w_locks++; /* Mark for writeinfo */
+ info->lock_type= F_EXTRA_LCK; /* Simulate as locked */
+ info->tmp_lock_type=lock_type;
+ datafile=info->dfile;
+
+ if (param->testflag & (T_REP+T_REP_BY_SORT+T_SORT_RECORDS+T_SORT_INDEX))
+ {
+ if (param->testflag & (T_REP+T_REP_BY_SORT))
+ share->state.key_map= (((ulonglong) 1 << share->base.keys)-1)
+ & param->keys_in_use;
+ 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))
+ {
+ if (param->testflag & T_FORCE_CREATE)
+ {
+ rep_quick=0;
+ mi_check_print_info(param,"Creating new data file\n");
+ }
+ else
+ {
+ error=1;
+ mi_check_print_error(param,
+ "Quick-recover aborted; Run recovery without switch 'q'");
+ }
+ }
+ if (!error)
+ {
+ if (param->testflag & T_REP_BY_SORT &&
+ (share->state.key_map ||
+ (rep_quick && !param->keys_in_use && !recreate)))
+ error=mi_repair_by_sort(&check_param,info,fixed_name,rep_quick);
+ else if (param->testflag & (T_REP | T_REP_BY_SORT))
+ error=mi_repair(&check_param, info,fixed_name,rep_quick);
+ }
+ if (!error && param->testflag & T_SORT_RECORDS)
+ {
+ 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,
+ raid_chunks);
+#ifdef USE_RAID
+ if (share->base.raid_type)
+ {
+ mi_check_print_info(&check_param,"Opening as RAID-ed table\n");
+ info->dfile=my_raid_open(fn_format(param->temp_filename,
+ fixed_name,"",
+ MI_NAME_DEXT, 2+4),
+ O_RDWR | O_SHARE,
+ share->base.raid_type,
+ raid_chunks,
+ share->base.raid_chunksize,
+ MYF(MY_WME | MY_RAID));
+ }
+ else
+#endif
+ info->dfile=my_open(fn_format(param->temp_filename,
+ fixed_name,"",
+ MI_NAME_DEXT,2+4),
+ O_RDWR | O_SHARE,
+ MYF(MY_WME));
+ if (info->dfile < 0)
+ error=1;
+ param->out_flag&= ~O_NEW_DATA; /* We are using new datafile */
+ param->read_cache.file=info->dfile;
+ }
+ if (! error)
+ {
+ uint key;
+ /*
+ We can't update the index in mi_sort_records if we have a
+ prefix compressed index
+ */
+ my_bool update_index=1;
+ for (key=0 ; key < share->base.keys; key++)
+ if (share->keyinfo[key].flag & HA_BINARY_PACK_KEY)
+ update_index=0;
+
+ error=mi_sort_records(param,info,fixed_name,param->opt_sort_key,
+ (my_bool) !(param->testflag & T_REP),
+ update_index);
+ datafile=info->dfile; /* This is now locked */
+ if (!error && !update_index)
+ {
+ 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);
+ }
+ }
+ }
+ if (!error && param->testflag & T_SORT_INDEX)
+ error=mi_sort_index(param,info,fixed_name);
+ if (!error)
+ share->state.changed=0;
+ else
+ mi_mark_crashed(info);
+ }
+ else if ((param->testflag & T_CHECK) || !(param->testflag & T_AUTO_INC))
+ {
+ if (!(param->testflag & T_SILENT) || param->testflag & T_INFO)
+ printf("Checking MyISAM file: %s\n",filename);
+ if (!(param->testflag & T_SILENT))
+ printf("Data records: %7s Deleted blocks: %7s\n",
+ llstr(info->state->records,llbuff),
+ llstr(info->state->del,llbuff2));
+ if (share->state.open_count)
+ {
+ mi_check_print_warning(param,
+ "%d clients is using or hasn't closed the table properly",
+ share->state.open_count);
+ }
+ share->state.key_map &=param->keys_in_use;
+ error =chk_size(param,info);
+ if (!error || !(param->testflag & (T_FAST | T_FORCE_CREATE)))
+ error|=chk_del(param, info,param->testflag);
+ if (!error || !(param->testflag & (T_FAST | T_FORCE_CREATE)))
+ {
+ error|=chk_key(param, info);
+ if (!error && (param->testflag & (T_STATISTICS | T_AUTO_INC)))
+ error=update_state_info(param, info, UPDATE_STAT);
+ }
+ if ((!rep_quick && !error) ||
+ !(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_io_cache(&param->read_cache,datafile,
+ (uint) param->read_buffer_length,
+ READ_CACHE,share->pack.header_length,1,
+ MYF(MY_WME)));
+ lock_memory(param);
+ if ((info->s->options & (HA_OPTION_PACK_RECORD |
+ HA_OPTION_COMPRESS_RECORD)) ||
+ (param->testflag & (T_EXTEND | T_MEDIUM)))
+ error|=chk_data_link(param, info, param->testflag & T_EXTEND);
+ error|=flush_blocks(param,share->kfile);
+ VOID(end_io_cache(&param->read_cache));
+ }
+ if (!error)
+ {
+ if (share->state.changed && (param->testflag & T_UPDATE_STATE))
+ info->update|=HA_STATE_CHANGED | HA_STATE_ROW_CHANGED;
+ share->state.changed=0;
+ }
+ else if (!mi_is_crashed(info) &&
+ (param->testflag & T_UPDATE_STATE))
+ { /* Mark crashed */
+ mi_mark_crashed(info);
+ info->update|=HA_STATE_CHANGED | HA_STATE_ROW_CHANGED;
+ }
+ }
+ }
+ if ((param->testflag & T_AUTO_INC) ||
+ ((param->testflag & (T_REP | T_REP_BY_SORT)) &&
+ info->s->base.auto_key))
+ update_auto_increment_key(param, info,
+ (my_bool) !test(param->testflag & T_AUTO_INC));
+
+ if (!(param->testflag & T_DESCRIPT))
+ {
+ if (info->update & HA_STATE_CHANGED && ! (param->testflag & T_READONLY))
+ error|=update_state_info(param, info,
+ UPDATE_OPEN_COUNT |
+ (((param->testflag & (T_REP | T_REP_BY_SORT)) ?
+ UPDATE_TIME | UPDATE_STAT : 0) |
+ ((param->testflag & T_SORT_RECORDS) ?
+ UPDATE_SORT : 0)));
+ VOID(lock_file(param, share->kfile,0L,F_UNLCK,"indexfile",filename));
+ info->update&= ~HA_STATE_CHANGED;
+ }
+ share->w_locks--;
+end2:
+ if (mi_close(info))
+ {
+ mi_check_print_error(param,"%d when closing MyISAM-table '%s'",my_errno,filename);
+ DBUG_RETURN(1);
+ }
+ if (error == 0)
+ {
+ if (param->out_flag & O_NEW_DATA)
+ error|=change_to_newfile(fixed_name,MI_NAME_DEXT,DATA_TMP_EXT,
+ raid_chunks);
+ if (param->out_flag & O_NEW_INDEX)
+ error|=change_to_newfile(fixed_name,MI_NAME_IEXT,INDEX_TMP_EXT,0);
+ }
+ VOID(fflush(stdout)); VOID(fflush(stderr));
+ if (param->error_printed)
+ {
+ if (param->testflag & (T_REP+T_REP_BY_SORT+T_SORT_RECORDS+T_SORT_INDEX))
+ {
+ VOID(fprintf(stderr,
+ "MyISAM-table '%s' is not fixed because of errors\n",
+ filename));
+ if (check_param.testflag & (T_REP_BY_SORT | T_REP))
+ VOID(fprintf(stderr,
+ "Try fixing it by using the --safe-recover (-o) option\n"));
+ }
+ else if (!(param->error_printed & 2) &&
+ !(param->testflag & T_FORCE_CREATE))
+ VOID(fprintf(stderr,
+ "MyISAM-table '%s' is corrupted\nFix it using switch \"-r\" or \"-o\"\n",
+ filename));
+ }
+ else if (param->warning_printed &&
+ ! (param->testflag & (T_REP+T_REP_BY_SORT+T_SORT_RECORDS+T_SORT_INDEX+
+ T_FORCE_CREATE)))
+ VOID(fprintf(stderr, "MyISAM-table '%s' is usable but should be fixed\n",
+ filename));
+ VOID(fflush(stderr));
+ DBUG_RETURN(error);
+} /* myisamchk */
+
+
+ /* Write info about table */
+
+static void descript(MI_CHECK *param, register MI_INFO *info, my_string name)
+{
+ uint key,keyseg_nr,field,start;
+ reg3 MI_KEYDEF *keyinfo;
+ reg2 MI_KEYSEG *keyseg;
+ reg4 const char *text;
+ char buff[40],length[10],*pos,*end;
+ enum en_fieldtype type;
+ MYISAM_SHARE *share=info->s;
+ char llbuff[22],llbuff2[22];
+ DBUG_ENTER("describe");
+
+ printf("\nMyISAM file: %s\n",name);
+ fputs("Record format: ",stdout);
+ if (share->options & HA_OPTION_COMPRESS_RECORD)
+ puts("Compressed");
+ else if (share->options & HA_OPTION_PACK_RECORD)
+ puts("Packed");
+ else
+ puts("Fixed length");
+ printf("Character set: %s (%d)\n",
+ get_charset_name(share->state.header.language),
+ share->state.header.language);
+
+ if (param->testflag & T_VERBOSE)
+ {
+ printf("File-version: %d\n",
+ (int) share->state.header.file_version[3]);
+ if (share->state.create_time)
+ {
+ get_date(buff,1,share->state.create_time);
+ printf("Creation time: %s\n",buff);
+ }
+ if (share->state.check_time)
+ {
+ get_date(buff,1,share->state.check_time);
+ printf("Recover time: %s\n",buff);
+ }
+ printf("Status: %s\n",
+ share->state.changed & 2 ? "crashed" :
+ share->state.open_count ? "open" :
+ share->state.changed ? "changed" : "checked");
+ if (share->base.auto_key)
+ {
+ printf("Auto increment key: %13d Last value: %13s\n",
+ share->base.auto_key,
+ llstr(share->state.auto_increment,llbuff));
+ }
+ if (share->base.raid_type)
+ {
+ printf("RAID: Type: %u Chunks: %u Chunksize: %lu\n",
+ share->base.raid_type,
+ share->base.raid_chunks,
+ share->base.raid_chunksize);
+ }
+ if (share->options & HA_OPTION_CHECKSUM)
+ printf("Using checksums\n");
+ if (share->options & HA_OPTION_DELAY_KEY_WRITE)
+ printf("Keys are only flushed at close\n");
+
+ }
+ printf("Data records: %13s Deleted blocks: %13s\n",
+ llstr(info->state->records,llbuff),llstr(info->state->del,llbuff2));
+ if (param->testflag & T_SILENT)
+ DBUG_VOID_RETURN; /* This is enough */
+
+ if (param->testflag & T_VERBOSE)
+ {
+#ifdef USE_RELOC
+ printf("Init-relocation: %13s\n",llstr(share->base.reloc,llbuff));
+#endif
+ printf("Datafile parts: %13s Deleted data: %13s\n",
+ llstr(share->state.split,llbuff),
+ llstr(info->state->empty,llbuff2));
+ printf("Datafile pointer (bytes):%9d Keyfile pointer (bytes):%9d\n",
+ share->rec_reflength,share->base.key_reflength);
+ printf("Datafile length: %13s Keyfile length: %13s\n",
+ llstr(info->state->data_file_length,llbuff),
+ llstr(info->state->key_file_length,llbuff2));
+
+ if (info->s->base.reloc == 1L && info->s->base.records == 1L)
+ puts("This is a one-record table");
+ else
+ {
+ if (share->base.max_data_file_length != HA_OFFSET_ERROR ||
+ share->base.max_key_file_length != HA_OFFSET_ERROR)
+ printf("Max datafile length: %13s Max keyfile length: %13s\n",
+ llstr(share->base.max_data_file_length-1,llbuff),
+ llstr(share->base.max_key_file_length-1,llbuff2));
+ }
+ }
+
+ printf("Recordlength: %13d\n",(int) share->base.pack_reclength);
+ if (share->state.key_map != (((ulonglong) 1 << share->base.keys) -1))
+ {
+ longlong2str(share->state.key_map,buff,2);
+ printf("Using only keys '%s' of %d possibly keys\n",
+ buff, share->base.keys);
+ }
+ puts("\ntable description:");
+ printf("Key Start Len Index Type");
+ if (param->testflag & T_VERBOSE)
+ printf(" Rec/key Root Blocksize");
+ VOID(putchar('\n'));
+
+ for (key=keyseg_nr=0, keyinfo= &share->keyinfo[0] ;
+ key < share->base.keys;
+ key++,keyinfo++)
+ {
+ keyseg=keyinfo->seg;
+ if (keyinfo->flag & HA_NOSAME) text="unique ";
+ else text="multip.";
+
+ pos=buff;
+ if (keyseg->flag & HA_REVERSE_SORT)
+ *pos++ = '-';
+ pos=strmov(pos,type_names[keyseg->type]);
+ *pos++ = ' ';
+ *pos=0;
+ if (keyinfo->flag & HA_PACK_KEY)
+ pos=strmov(pos,prefix_packed_txt);
+ if (keyinfo->flag & HA_BINARY_PACK_KEY)
+ pos=strmov(pos,bin_packed_txt);
+ if (keyseg->flag & HA_SPACE_PACK)
+ pos=strmov(pos,diff_txt);
+ if (keyseg->flag & HA_BLOB_PART)
+ pos=strmov(pos,blob_txt);
+ if (keyseg->flag & HA_NULL_PART)
+ pos=strmov(pos,null_txt);
+ *pos=0;
+
+ printf("%-4d%-6ld%-3d %-8s%-21s",
+ key+1,(long) keyseg->start+1,keyseg->length,text,buff);
+ if (share->state.key_root[key] != HA_OFFSET_ERROR)
+ llstr(share->state.key_root[key],buff);
+ else
+ buff[0]=0;
+ if (param->testflag & T_VERBOSE)
+ printf("%11lu %12s %10d",
+ share->state.rec_per_key_part[keyseg_nr++],
+ buff,keyinfo->block_length);
+ VOID(putchar('\n'));
+ while ((++keyseg)->type != HA_KEYTYPE_END)
+ {
+ pos=buff;
+ if (keyseg->flag & HA_REVERSE_SORT)
+ *pos++ = '-';
+ pos=strmov(pos,type_names[keyseg->type]);
+ *pos++= ' ';
+ if (keyseg->flag & HA_SPACE_PACK)
+ pos=strmov(pos,diff_txt);
+ if (keyseg->flag & HA_BLOB_PART)
+ pos=strmov(pos,blob_txt);
+ if (keyseg->flag & HA_NULL_PART)
+ pos=strmov(pos,null_txt);
+ *pos=0;
+ printf(" %-6ld%-3d %-21s",
+ (long) keyseg->start+1,keyseg->length,buff);
+ if (param->testflag & T_VERBOSE)
+ printf("%11lu", share->state.rec_per_key_part[keyseg_nr++]);
+ VOID(putchar('\n'));
+ }
+ keyseg++;
+ }
+ if (share->state.header.uniques)
+ {
+ MI_UNIQUEDEF *uniqueinfo;
+ puts("\nUnique Key Start Len Nullpos Nullbit Type");
+ for (key=0,uniqueinfo= &share->uniqueinfo[0] ;
+ key < share->state.header.uniques; key++, uniqueinfo++)
+ {
+ my_bool new_row=0;
+ char null_bit[8],null_pos[8];
+ printf("%-8d%-5d",key+1,uniqueinfo->key+1);
+ for (keyseg=uniqueinfo->seg ; keyseg->type != HA_KEYTYPE_END ; keyseg++)
+ {
+ if (new_row)
+ fputs(" ",stdout);
+ null_bit[0]=null_pos[0]=0;
+ if (keyseg->null_bit)
+ {
+ sprintf(null_bit,"%d",keyseg->null_bit);
+ sprintf(null_pos,"%ld",(long) keyseg->null_pos+1);
+ }
+ printf("%-7ld%-5d%-9s%-10s%-30s\n",
+ (long) keyseg->start+1,keyseg->length,
+ null_pos,null_bit,
+ type_names[keyseg->type]);
+ new_row=1;
+ }
+ }
+ }
+ if (param->verbose > 1)
+ {
+ char null_bit[8],null_pos[8];
+ printf("\nField Start Length Nullpos Nullbit Type");
+ if (share->options & HA_OPTION_COMPRESS_RECORD)
+ printf(" Huff tree Bits");
+ VOID(putchar('\n'));
+ start=1;
+ for (field=0 ; field < share->base.fields ; field++)
+ {
+ if (share->options & HA_OPTION_COMPRESS_RECORD)
+ type=share->rec[field].base_type;
+ else
+ type=(enum en_fieldtype) share->rec[field].type;
+ end=strmov(buff,field_pack[type]);
+ if (share->options & HA_OPTION_COMPRESS_RECORD)
+ {
+ if (share->rec[field].pack_type & PACK_TYPE_SELECTED)
+ end=strmov(end,", not_always");
+ if (share->rec[field].pack_type & PACK_TYPE_SPACE_FIELDS)
+ end=strmov(end,", no empty");
+ if (share->rec[field].pack_type & PACK_TYPE_ZERO_FILL)
+ {
+ sprintf(end,", zerofill(%d)",share->rec[field].space_length_bits);
+ end=strend(end);
+ }
+ }
+ if (buff[0] == ',')
+ strmov(buff,buff+2);
+ int2str((long) share->rec[field].length,length,10);
+ null_bit[0]=null_pos[0]=0;
+ if (share->rec[field].null_bit)
+ {
+ sprintf(null_bit,"%d",share->rec[field].null_bit);
+ sprintf(null_pos,"%d",share->rec[field].null_pos+1);
+ }
+ printf("%-6d%-6d%-7s%-8s%-8s%-35s",field+1,start,length,
+ null_pos, null_bit, buff);
+ if (share->options & HA_OPTION_COMPRESS_RECORD)
+ {
+ if (share->rec[field].huff_tree)
+ printf("%3d %2d",
+ (uint) (share->rec[field].huff_tree-share->decode_trees)+1,
+ share->rec[field].huff_tree->quick_table_bits);
+ }
+ VOID(putchar('\n'));
+ start+=share->rec[field].length;
+ }
+ }
+ DBUG_VOID_RETURN;
+} /* describe */
+
+
+ /* Sort records according to one key */
+
+static int mi_sort_records(MI_CHECK *param,
+ register MI_INFO *info, my_string name,
+ uint sort_key,
+ my_bool write_info,
+ my_bool update_index)
+{
+ int got_error;
+ uint key;
+ MI_KEYDEF *keyinfo;
+ File new_file;
+ uchar *temp_buff;
+ ha_rows old_record_count;
+ MYISAM_SHARE *share=info->s;
+ char llbuff[22],llbuff2[22];
+ SORT_INFO *sort_info= &param->sort_info;
+ DBUG_ENTER("sort_records");
+
+ bzero((char*) sort_info,sizeof(sort_info));
+ keyinfo= &share->keyinfo[sort_key];
+ got_error=1;
+ temp_buff=0;
+ new_file= -1;
+
+ if (!(((ulonglong) 1 << sort_key) & share->state.key_map))
+ {
+ mi_check_print_error(param,"Can't sort table '%s' on key %d; No such key",
+ name,sort_key+1);
+ param->error_printed=0;
+ DBUG_RETURN(-1);
+ }
+ if (!(param->testflag & T_SILENT))
+ {
+ printf("- Sorting records for MyISAM-table '%s'\n",name);
+ if (write_info)
+ printf("Data records: %9s Deleted: %9s\n",
+ llstr(info->state->records,llbuff),
+ llstr(info->state->del,llbuff2));
+ }
+ if (share->state.key_root[sort_key] == HA_OFFSET_ERROR)
+ DBUG_RETURN(0); /* Nothing to do */
+
+ init_key_cache(param->use_buffers,NEAD_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)))
+ goto err;
+ info->opt_flag|=WRITE_CACHE_USED;
+
+ if (!(temp_buff=(uchar*) my_alloca((uint) keyinfo->block_length)))
+ {
+ mi_check_print_error(param,"Not enough memory for key block");
+ goto err;
+ }
+ if (!(sort_info->record=(byte*) my_malloc((uint) share->base.pack_reclength,
+ MYF(0))))
+ {
+ mi_check_print_error(param,"Not enough memory for record");
+ goto err;
+ }
+ new_file=my_raid_create(fn_format(param->temp_filename,name,"",
+ DATA_TMP_EXT,2+4),
+ 0,param->tmpfile_createflag,
+ share->base.raid_type,
+ share->base.raid_chunks,
+ share->base.raid_chunksize,
+ MYF(0));
+ if (new_file < 0)
+ {
+ mi_check_print_error(param,"Can't create new tempfile: '%s'",
+ param->temp_filename);
+ goto err;
+ }
+ if (filecopy(param,new_file,info->dfile,0L,share->pack.header_length,
+ "datafile-header"))
+ goto err;
+ info->rec_cache.file=new_file; /* Use this file for cacheing*/
+
+ lock_memory(param);
+ for (key=0 ; key < share->base.keys ; key++)
+ share->keyinfo[key].flag|= HA_SORT_ALLOWS_SAME;
+
+ if (my_pread(share->kfile,(byte*) temp_buff,
+ (uint) keyinfo->block_length,
+ share->state.key_root[sort_key],
+ MYF(MY_NABP+MY_WME)))
+ {
+ mi_check_print_error(param,"Can't read indexpage from filepos: %s",
+ (ulong) share->state.key_root[sort_key]);
+ goto err;
+ }
+
+ /* Setup param for sort_write_record */
+ sort_info->info=info;
+ sort_info->new_data_file_type=share->data_file_type;
+ sort_info->fix_datafile=1;
+ sort_info->filepos=share->pack.header_length;
+ old_record_count=info->state->records;
+ info->state->records=0;
+ if (sort_info->new_data_file_type != COMPRESSED_RECORD)
+ share->state.checksum=0;
+
+ if (sort_record_index(param, info,keyinfo,share->state.key_root[sort_key],
+ temp_buff, sort_key,new_file,update_index) ||
+ write_data_suffix(param, info) ||
+ flush_io_cache(&info->rec_cache))
+ goto err;
+
+ if (info->state->records != old_record_count)
+ {
+ mi_check_print_error(param,"found %s of %s records",
+ llstr(info->state->records,llbuff),
+ llstr(old_record_count,llbuff2));
+ goto err;
+ }
+
+ VOID(my_close(info->dfile,MYF(MY_WME)));
+ param->out_flag|=O_NEW_DATA; /* Data in new file */
+ info->dfile=new_file; /* Use new datafile */
+ info->state->del=0;
+ info->state->empty=0;
+ share->state.dellink= HA_OFFSET_ERROR;
+ info->state->data_file_length=sort_info->filepos;
+ share->state.split=info->state->records; /* Only hole records */
+ share->state.version=(ulong) time((time_t*) 0);
+
+ info->update= (short) (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
+
+ if (param->testflag & T_WRITE_LOOP)
+ {
+ VOID(fputs(" \r",stdout)); VOID(fflush(stdout));
+ }
+ got_error=0;
+
+err:
+ if (got_error && new_file >= 0)
+ {
+ VOID(end_io_cache(&info->rec_cache));
+ (void) my_close(new_file,MYF(MY_WME));
+ (void) my_raid_delete(param->temp_filename, share->base.raid_chunksize,
+ MYF(MY_WME));
+ }
+ if (temp_buff)
+ {
+ my_afree((gptr) temp_buff);
+ }
+ my_free(sort_info->record,MYF(MY_ALLOW_ZERO_PTR));
+ info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
+ VOID(end_io_cache(&info->rec_cache));
+ my_free(sort_info->buff,MYF(MY_ALLOW_ZERO_PTR));
+ sort_info->buff=0;
+ share->state.sortkey=sort_key;
+ DBUG_RETURN(flush_blocks(param, share->kfile) | got_error);
+} /* sort_records */
+
+
+ /* Sort records recursive using one index */
+
+static int sort_record_index(MI_CHECK *param,MI_INFO *info, MI_KEYDEF *keyinfo,
+ my_off_t page, uchar *buff, uint sort_key,
+ File new_file,my_bool update_index)
+{
+ uint nod_flag,used_length,key_length;
+ uchar *temp_buff,*keypos,*endpos;
+ my_off_t next_page,rec_pos;
+ uchar lastkey[MI_MAX_KEY_BUFF];
+ char llbuff[22];
+ SORT_INFO *sort_info= &param->sort_info;
+ DBUG_ENTER("sort_record_index");
+
+ nod_flag=mi_test_if_nod(buff);
+ temp_buff=0;
+
+ if (nod_flag)
+ {
+ if (!(temp_buff=(uchar*) my_alloca((uint) keyinfo->block_length)))
+ {
+ mi_check_print_error(param,"Not Enough memory");
+ DBUG_RETURN(-1);
+ }
+ }
+ used_length=mi_getint(buff);
+ keypos=buff+2+nod_flag;
+ endpos=buff+used_length;
+ for ( ;; )
+ {
+ _sanity(__FILE__,__LINE__);
+ if (nod_flag)
+ {
+ next_page=_mi_kpos(nod_flag,keypos);
+ if (my_pread(info->s->kfile,(byte*) temp_buff,
+ (uint) keyinfo->block_length, next_page,
+ MYF(MY_NABP+MY_WME)))
+ {
+ mi_check_print_error(param,"Can't read keys from filepos: %s",
+ llstr(next_page,llbuff));
+ goto err;
+ }
+ if (sort_record_index(param, info,keyinfo,next_page,temp_buff,sort_key,
+ new_file, update_index))
+ goto err;
+ }
+ _sanity(__FILE__,__LINE__);
+ if (keypos >= endpos ||
+ (key_length=(*keyinfo->get_key)(keyinfo,nod_flag,&keypos,lastkey))
+ == 0)
+ break;
+ rec_pos= _mi_dpos(info,0,lastkey+key_length);
+
+ if ((*info->s->read_rnd)(info,sort_info->record,rec_pos,0))
+ {
+ mi_check_print_error(param,"%d when reading datafile",my_errno);
+ goto err;
+ }
+ if (rec_pos != sort_info->filepos && update_index)
+ {
+ _mi_dpointer(info,keypos-nod_flag-info->s->rec_reflength,
+ sort_info->filepos);
+ if (movepoint(info,sort_info->record,rec_pos,sort_info->filepos,
+ sort_key))
+ {
+ mi_check_print_error(param,"%d when updating key-pointers",my_errno);
+ goto err;
+ }
+ }
+ if (sort_write_record(sort_info))
+ goto err;
+ }
+ /* Clear end of block to get better compression if the table is backuped */
+ bzero((byte*) buff+used_length,keyinfo->block_length-used_length);
+ if (my_pwrite(info->s->kfile,(byte*) buff,(uint) keyinfo->block_length,
+ page,param->myf_rw))
+ {
+ mi_check_print_error(param,"%d when updating keyblock",my_errno);
+ goto err;
+ }
+ if (temp_buff)
+ my_afree((gptr) temp_buff);
+ DBUG_RETURN(0);
+err:
+ if (temp_buff)
+ my_afree((gptr) temp_buff);
+ DBUG_RETURN(1);
+} /* sort_record_index */
+
+
+ /* print warnings and errors */
+ /* VARARGS */
+
+void mi_check_print_info(MI_CHECK *param __attribute__((unused)),
+ const char *fmt,...)
+{
+ va_list args;
+
+ va_start(args,fmt);
+ VOID(vfprintf(stdout, fmt, args));
+ VOID(fputc('\n',stdout));
+ va_end(args);
+ return;
+}
+
+/* VARARGS */
+
+void mi_check_print_warning(MI_CHECK *param, const char *fmt,...)
+{
+ va_list args;
+ DBUG_ENTER("mi_check_print_warning");
+
+ fflush(stdout);
+ if (!param->warning_printed && !param->error_printed)
+ {
+ if (param->testflag & T_SILENT)
+ fprintf(stderr,"%s: MyISAM file %s\n",my_progname,
+ param->isam_file_name);
+ }
+ param->warning_printed=1;
+ va_start(args,fmt);
+ fprintf(stderr,"%s: warning: ",my_progname);
+ VOID(vfprintf(stderr, fmt, args));
+ VOID(fputc('\n',stderr));
+ fflush(stderr);
+ va_end(args);
+ DBUG_VOID_RETURN;
+}
+
+/* VARARGS */
+
+void mi_check_print_error(MI_CHECK *param, const char *fmt,...)
+{
+ va_list args;
+ DBUG_ENTER("mi_check_print_error");
+ DBUG_PRINT("enter",("format: %s",fmt));
+
+ fflush(stdout);
+ if (!param->warning_printed && !param->error_printed)
+ {
+ if (param->testflag & T_SILENT)
+ fprintf(stderr,"%s: ISAM file %s\n",my_progname,param->isam_file_name);
+ }
+ param->error_printed|=1;
+ va_start(args,fmt);
+ fprintf(stderr,"%s: error: ",my_progname);
+ VOID(vfprintf(stderr, fmt, args));
+ VOID(fputc('\n',stderr));
+ fflush(stderr);
+ va_end(args);
+ DBUG_VOID_RETURN;
+}
diff --git a/myisam/myisamdef.h b/myisam/myisamdef.h
new file mode 100644
index 00000000000..13bb2e7efad
--- /dev/null
+++ b/myisam/myisamdef.h
@@ -0,0 +1,621 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 included by all internal myisam files */
+
+#define ISAM_LIBRARY
+#include "myisam.h" /* Structs & some defines */
+#include "myisampack.h" /* packing of keys */
+#ifdef THREAD
+#include <my_pthread.h>
+#include <thr_lock.h>
+#else
+#include <my_no_pthread.h>
+#endif
+
+#if defined(my_write) && !defined(MAP_TO_USE_RAID)
+#undef my_write /* undef map from my_nosys; We need test-if-disk full */
+#endif
+
+typedef struct st_mi_status_info
+{
+ ha_rows records; /* Rows in table */
+ ha_rows del; /* Removed rows */
+ my_off_t empty; /* lost space in datafile */
+ my_off_t key_empty; /* lost space in indexfile */
+ my_off_t key_file_length;
+ my_off_t data_file_length;
+} MI_STATUS_INFO;
+
+typedef struct st_mi_state_info
+{
+ struct { /* Fileheader */
+ uchar file_version[4];
+ uchar options[2];
+ uchar header_length[2];
+ uchar state_info_length[2];
+ uchar base_info_length[2];
+ uchar base_pos[2];
+ uchar key_parts[2]; /* Key parts */
+ uchar unique_key_parts[2]; /* Key parts + unique parts */
+ uchar keys; /* number of keys in file */
+ uchar uniques; /* number of UNIQUE definitions */
+ uchar language; /* Language for indexes */
+ uchar max_block_size; /* max keyblock size */
+ uchar not_used[2]; /* To align to 8 */
+ } header;
+
+ MI_STATUS_INFO state;
+ ha_rows split; /* number of split blocks */
+ my_off_t dellink; /* Link to next removed block */
+ ulonglong auto_increment;
+ ulong process; /* process that updated table last */
+ ulong unique; /* Unique number for this process */
+ ulong status;
+ my_off_t *key_root; /* Start of key trees */
+ my_off_t *key_del; /* delete links for trees */
+
+ ulong sec_index_changed; /* Updated when new sec_index */
+ ulong sec_index_used; /* which extra index are in use */
+ ulonglong key_map; /* Which keys are in use */
+ ha_checksum checksum;
+ ulong version; /* timestamp of create */
+ time_t create_time; /* Time when created database */
+ time_t recover_time; /* Time for last recover */
+ time_t check_time; /* Time for last check */
+ uint sortkey; /* sorted by this key (not used) */
+ uint open_count;
+ bool changed; /* Changed since isamchk */
+ 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 */
+ uint state_length; /* Length of state header in file */
+ ulong *key_info;
+} MI_STATE_INFO;
+
+#define MI_STATE_INFO_SIZE (24+14*8+7*4+2*2+8)
+#define MI_STATE_KEY_SIZE 8
+#define MI_STATE_KEYBLOCK_SIZE 8
+#define MI_STATE_KEYSEG_SIZE 4
+#define MI_STATE_EXTRA_SIZE ((MI_MAX_KEY+MI_MAX_KEY_BLOCK_SIZE)*MI_STATE_KEY_SIZE + MI_MAX_KEY*MI_MAX_KEY_SEG*MI_STATE_KEYSEG_SIZE)
+#define MI_KEYDEF_SIZE (2+ 5*2)
+#define MI_UNIQUEDEF_SIZE (2+1+1)
+#define MI_KEYSEG_SIZE (6+ 2*2 + 4*2)
+#define MI_COLUMNDEF_SIZE (2*3+1)
+#define MI_BASE_INFO_SIZE (5*8 + 8*4 + 4 + 4*2 + 16)
+#define MI_INDEX_BLOCK_MARGIN 16 /* Safety margin for .MYI tables */
+
+typedef struct st_mi_base_info
+{
+ my_off_t keystart; /* Start of keys */
+ my_off_t max_data_file_length;
+ my_off_t max_key_file_length;
+ my_off_t margin_key_file_length;
+ ha_rows records,reloc; /* Create information */
+ ulong mean_row_length; /* Create information */
+ ulong reclength; /* length of unpacked record */
+ ulong pack_reclength; /* Length of full packed rec. */
+ ulong min_pack_length;
+ ulong max_pack_length; /* Max possibly length of packed rec.*/
+ ulong min_block_length;
+ ulong fields, /* fields in table */
+ pack_fields; /* packed fields in table */
+ uint rec_reflength; /* = 2-8 */
+ uint key_reflength; /* = 2-8 */
+ uint keys; /* same as in state.header */
+ uint auto_key; /* Which key-1 is a auto key */
+ uint blobs; /* Number of blobs */
+ uint pack_bits; /* Length of packed bits */
+ uint max_key_block_length; /* Max block length */
+ uint max_key_length; /* Max key length */
+ /* Extra allocation when using dynamic record format */
+ uint extra_alloc_bytes;
+ uint extra_alloc_procent;
+ /* Info about raid */
+ uint raid_type,raid_chunks;
+ ulong raid_chunksize;
+ /* The following are from the header */
+ uint key_parts,all_key_parts;
+} MI_BASE_INFO;
+
+
+ /* Structs used intern in database */
+
+typedef struct st_mi_blob /* Info of record */
+{
+ ulong offset; /* Offset to blob in record */
+ uint pack_length; /* Type of packed length */
+ ulong length; /* Calc:ed for each record */
+} MI_BLOB;
+
+
+typedef struct st_mi_isam_pack {
+ ulong header_length;
+ uint ref_length;
+} MI_PACK;
+
+
+typedef struct st_mi_isam_share { /* Shared between opens */
+ MI_STATE_INFO state;
+ MI_BASE_INFO base;
+ MI_KEYDEF *keyinfo; /* Key definitions */
+ MI_UNIQUEDEF *uniqueinfo; /* unique definitions */
+ MI_KEYSEG *keyparts; /* key part info */
+ 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 */
+ byte *file_map; /* mem-map of file if possible */
+ ulong this_process; /* processid */
+ ulong last_process; /* For table-change-check */
+ ulong last_version; /* Version on start */
+ ulong options; /* Options used */
+ uint rec_reflength; /* rec_reflength in use now */
+ int kfile; /* Shared keyfile */
+ int 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 blocksize; /* blocksize of keyfile */
+ ulong min_pack_length; /* Theese are used by packed data */
+ ulong max_pack_length;
+ ulong state_diff_length;
+ my_bool changed, /* If changed since lock */
+ global_changed, /* If changed since open */
+ not_flushed,
+ temporary,delay_key_write,
+ concurrent_insert;
+ 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 */
+ rw_lock_t *key_root_lock;
+#endif
+} MYISAM_SHARE;
+
+
+typedef uint mi_bit_type;
+
+typedef struct st_mi_bit_buff { /* Used for packing of record */
+ mi_bit_type current_byte;
+ uint bits;
+ uchar *pos,*end,*blob_pos;
+ 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 */
+ char *filename; /* parameter to open filename */
+ ulong this_unique; /* uniq filenumber or thread */
+ ulong last_unique; /* last unique number */
+ ulong this_loop; /* counter for this open */
+ ulong last_loop; /* last used counter */
+ my_off_t lastpos, /* Last record position */
+ nextpos; /* Position to next record */
+ my_off_t save_lastpos;
+ my_off_t pos; /* Intern variable */
+ ha_checksum checksum;
+ ulong packed_length,blob_length; /* Length of found, packed record */
+ 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() */
+ uint save_lastkey_length;
+ int errkey; /* Got last error on this key */
+ int lock_type; /* How database was locked */
+ int tmp_lock_type; /* When locked by readinfo */
+ uint data_changed; /* Somebody has changed data */
+ uint save_update; /* When using KEY_READ */
+ int save_lastinx;
+ 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 */
+ 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
+};
+
+
+ /* Some defines used by isam-funktions */
+
+#define USE_WHOLE_KEY MI_MAX_KEY_BUFF*2 /* Use whole key in _mi_search() */
+#define F_EXTRA_LCK -1
+
+ /* bits in opt_flag */
+#define MEMMAP_USED 32
+#define REMEMBER_OLD_POS 64
+
+#define WRITEINFO_UPDATE_KEYFILE 1
+#define WRITEINFO_NO_UNLOCK 2
+
+#define mi_getint(x) ((uint) mi_uint2korr(x) & 32767)
+#define mi_putint(x,y,nod) { uint16 boh=(nod ? (uint16) 32768 : 0) + (uint16) (y);\
+ mi_int2store(x,boh); }
+#define mi_test_if_nod(x) (x[0] & 128 ? info->s->base.key_reflength : 0)
+#define mi_mark_crashed(x) (x)->s->state.changed|=2
+#define mi_is_crashed(x) ((x)->s->state.changed & 2)
+
+/* Functions to store length of space packed keys, VARCHAR or BLOB keys */
+
+#define store_key_length_inc(key,length) \
+{ if ((length) < 255) \
+ { *(key)++=(length); } \
+ else \
+ { *(key)=255; mi_int2store((key)+1,(length)); (key)+=3; } \
+}
+
+#define store_key_length(key,length) \
+{ if ((length) < 255) \
+ { *(key)=(length); } \
+ else \
+ { *(key)=255; mi_int2store((key)+1,(length)); } \
+}
+
+#define get_key_length(length,key) \
+{ if ((uchar) *(key) != 255) \
+ length= (uint) (uchar) *((key)++); \
+ else \
+ { length=mi_uint2korr((key)+1); (key)+=3; } \
+}
+
+#define get_key_full_length(length,key) \
+{ if ((uchar) *(key) != 255) \
+ length= ((uint) (uchar) *((key)++))+1; \
+ else \
+ { length=mi_uint2korr((key)+1)+3; (key)+=3; } \
+}
+
+#define get_key_pack_length(length,length_pack,key) \
+{ if ((uchar) *(key) != 255) \
+ { length= (uint) (uchar) *((key)++); length_pack=1; }\
+ else \
+ { length=mi_uint2korr((key)+1); (key)+=3; length_pack=3; } \
+}
+
+#define get_pack_length(length) ((length) >= 255 ? 3 : 1)
+
+#define MI_MIN_BLOCK_LENGTH 20 /* Because of delete-link */
+#define MI_EXTEND_BLOCK_LENGTH 20 /* Don't use to small record-blocks */
+#define MI_SPLIT_LENGTH ((MI_EXTEND_BLOCK_LENGTH+4)*2)
+#define MI_MAX_DYN_BLOCK_HEADER 20 /* Max prefix of record-block */
+#define MI_BLOCK_INFO_HEADER_LENGTH 20
+#define MI_DYN_DELETE_BLOCK_HEADER 20 /* length of delete-block-header */
+#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 MEMMAP_EXTRA_MARGIN 7 /* Write this as a suffix for file */
+
+#define PACK_TYPE_SELECTED 1 /* Bits in field->pack_type */
+#define PACK_TYPE_SPACE_FIELDS 2
+#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_KEYPTR_SIZE 5 /* For calculating block lengths */
+
+/* The UNIQUE check is done with a hashed long key */
+
+#define MI_UNIQUE_HASH_TYPE HA_KEYTYPE_ULONG_INT
+#define mi_unique_store(A,B) mi_int4store((A),(B))
+
+#ifdef THREAD
+extern pthread_mutex_t THR_LOCK_myisam;
+#endif
+#if !defined(THREAD) || defined(DONT_USE_RW_LOCKS)
+#define rw_wrlock(A) {}
+#define rw_rdlock(A) {}
+#define rw_unlock(A) {}
+#endif
+
+ /* Some extern variables */
+
+extern LIST *myisam_open_list;
+extern uchar NEAR myisam_file_magic[],NEAR myisam_pack_file_magic[];
+extern uint NEAR myisam_read_vec[],NEAR myisam_readnext_vec[];
+extern uint myisam_quick_table_bits;
+extern File myisam_log_file;
+
+ /* This is used by _mi_calc_xxx_key_length och _mi_store_key */
+
+typedef struct st_mi_s_param
+{
+ uint ref_length,key_length,
+ n_ref_length,
+ n_length,
+ totlength,
+ part_of_prev_key,prev_length,pack_marker;
+ uchar *key, *prev_key,*next_key_pos;
+ bool store_not_null;
+} MI_KEY_PARAM;
+
+ /* Prototypes for intern functions */
+
+extern int _mi_read_dynamic_record(MI_INFO *info,my_off_t filepos,byte *buf);
+extern int _mi_write_dynamic_record(MI_INFO*, const byte*);
+extern int _mi_update_dynamic_record(MI_INFO*, my_off_t, const byte*);
+extern int _mi_delete_dynamic_record(MI_INFO *info);
+extern int _mi_cmp_dynamic_record(MI_INFO *info,const byte *record);
+extern int _mi_read_rnd_dynamic_record(MI_INFO *, byte *,my_off_t, my_bool);
+extern int _mi_write_blob_record(MI_INFO*, const byte*);
+extern int _mi_update_blob_record(MI_INFO*, my_off_t, const byte*);
+extern int _mi_read_static_record(MI_INFO *info, my_off_t filepos,byte *buf);
+extern int _mi_write_static_record(MI_INFO*, const byte*);
+extern int _mi_update_static_record(MI_INFO*, my_off_t, const byte*);
+extern int _mi_delete_static_record(MI_INFO *info);
+extern int _mi_cmp_static_record(MI_INFO *info,const byte *record);
+extern int _mi_read_rnd_static_record(MI_INFO*, byte *,my_off_t, my_bool);
+extern int _mi_ck_write(MI_INFO *info,uint keynr,uchar *key,uint length);
+extern int _mi_enlarge_root(MI_INFO *info,uint keynr,uchar *key);
+extern int _mi_insert(MI_INFO *info,MI_KEYDEF *keyinfo,uchar *key,
+ uchar *anc_buff,uchar *key_pos,uchar *key_buff,
+ uchar *father_buff, uchar *father_keypos,
+ my_off_t father_page, my_bool insert_last);
+extern int _mi_split_page(MI_INFO *info,MI_KEYDEF *keyinfo,uchar *key,
+ uchar *buff,uchar *key_buff, my_bool insert_last);
+extern uchar *_mi_find_half_pos(uint nod_flag,MI_KEYDEF *keyinfo,uchar *page,
+ uchar *key,uint *return_key_length,
+ uchar **after_key);
+extern int _mi_calc_static_key_length(MI_KEYDEF *keyinfo,uint nod_flag,
+ uchar *key_pos, uchar *org_key,
+ uchar *key_buff,
+ uchar *key, MI_KEY_PARAM *s_temp);
+extern int _mi_calc_var_key_length(MI_KEYDEF *keyinfo,uint nod_flag,
+ uchar *key_pos, uchar *org_key,
+ uchar *key_buff,
+ uchar *key, MI_KEY_PARAM *s_temp);
+extern int _mi_calc_var_pack_key_length(MI_KEYDEF *keyinfo,uint nod_flag,
+ uchar *key_pos, uchar *org_key,
+ uchar *prev_key,
+ uchar *key, MI_KEY_PARAM *s_temp);
+extern int _mi_calc_bin_pack_key_length(MI_KEYDEF *keyinfo,uint nod_flag,
+ uchar *key_pos,uchar *org_key,
+ uchar *prev_key,
+ uchar *key, MI_KEY_PARAM *s_temp);
+void _mi_store_static_key(MI_KEYDEF *keyinfo, uchar *key_pos,
+ MI_KEY_PARAM *s_temp);
+void _mi_store_var_pack_key(MI_KEYDEF *keyinfo, uchar *key_pos,
+ MI_KEY_PARAM *s_temp);
+#ifdef NOT_USED
+void _mi_store_pack_key(MI_KEYDEF *keyinfo, uchar *key_pos,
+ MI_KEY_PARAM *s_temp);
+#endif
+void _mi_store_bin_pack_key(MI_KEYDEF *keyinfo, uchar *key_pos,
+ MI_KEY_PARAM *s_temp);
+
+extern int _mi_ck_delete(MI_INFO *info,uint keynr,uchar *key,uint key_length);
+extern int _mi_readinfo(MI_INFO *info,int lock_flag,int check_keybuffer);
+extern int _mi_writeinfo(MI_INFO *info,uint options);
+extern int _mi_test_if_changed(MI_INFO *info);
+extern int _mi_mark_file_changed(MI_INFO *info);
+extern int _mi_decrement_open_count(MI_INFO *info);
+extern int _mi_check_index(MI_INFO *info,int inx);
+extern int _mi_search(MI_INFO *info,MI_KEYDEF *keyinfo,uchar *key,uint key_len,
+ uint nextflag,my_off_t pos);
+extern int _mi_bin_search(struct st_myisam_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_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_compare_text(CHARSET_INFO *, uchar *, uint, uchar *, uint ,
+ my_bool);
+extern my_off_t _mi_kpos(uint nod_flag,uchar *after_key);
+extern void _mi_kpointer(MI_INFO *info,uchar *buff,my_off_t pos);
+extern my_off_t _mi_dpos(MI_INFO *info, uint nod_flag,uchar *after_key);
+extern my_off_t _mi_rec_pos(MYISAM_SHARE *info, uchar *ptr);
+extern void _mi_dpointer(MI_INFO *info, uchar *buff,my_off_t pos);
+extern int _mi_key_cmp(MI_KEYSEG *keyseg, uchar *a,uchar *b,
+ uint key_length,uint nextflag,uint *diff_length);
+extern uint _mi_get_static_key(MI_KEYDEF *keyinfo,uint nod_flag,uchar * *page,
+ uchar *key);
+extern uint _mi_get_pack_key(MI_KEYDEF *keyinfo,uint nod_flag,uchar * *page,
+ uchar *key);
+extern uint _mi_get_binary_pack_key(MI_KEYDEF *keyinfo, uint nod_flag,
+ uchar **page_pos, uchar *key);
+extern uchar *_mi_get_last_key(MI_INFO *info,MI_KEYDEF *keyinfo,uchar *keypos,
+ uchar *lastkey,uchar *endpos,
+ uint *return_key_length);
+extern uchar *_mi_get_key(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *page,
+ uchar *key, uchar *keypos, uint *return_key_length);
+extern uint _mi_keylength(MI_KEYDEF *keyinfo,uchar *key);
+extern uchar *_mi_move_key(MI_KEYDEF *keyinfo,uchar *to,uchar *from);
+extern int _mi_search_next(MI_INFO *info,MI_KEYDEF *keyinfo,uchar *key,
+ uint key_length,uint nextflag,my_off_t pos);
+extern int _mi_search_first(MI_INFO *info,MI_KEYDEF *keyinfo,my_off_t pos);
+extern int _mi_search_last(MI_INFO *info,MI_KEYDEF *keyinfo,my_off_t pos);
+extern uchar *_mi_fetch_keypage(MI_INFO *info,MI_KEYDEF *keyinfo,my_off_t page,
+ uchar *buff,int return_buffer);
+extern int _mi_write_keypage(MI_INFO *info,MI_KEYDEF *keyinfo,my_off_t page,
+ uchar *buff);
+extern int _mi_dispose(MI_INFO *info,MI_KEYDEF *keyinfo,my_off_t pos);
+extern my_off_t _mi_new(MI_INFO *info,MI_KEYDEF *keyinfo);
+extern uint _mi_make_key(MI_INFO *info,uint keynr,uchar *key,
+ const byte *record,my_off_t filepos);
+extern uint _mi_pack_key(MI_INFO *info,uint keynr,uchar *key,uchar *old,
+ uint key_length);
+extern int _mi_read_key_record(MI_INFO *info,my_off_t filepos,byte *buf);
+extern int _mi_read_cache(IO_CACHE *info,byte *buff,my_off_t pos,
+ uint length,int re_read_if_possibly);
+extern void update_auto_increment(MI_INFO *info,const byte *record);
+extern byte *mi_fix_rec_buff_for_blob(MI_INFO *info,ulong blob_length);
+extern ulong _mi_rec_unpack(MI_INFO *info,byte *to,byte *from,
+ ulong reclength);
+extern my_bool _mi_rec_check(MI_INFO *info,const char *from);
+extern int _mi_write_part_record(MI_INFO *info,my_off_t filepos,ulong length,
+ my_off_t next_filepos,byte **record,
+ ulong *reclength,int *flag);
+extern void _mi_print_key(FILE *stream,MI_KEYSEG *keyseg,const uchar *key,
+ uint length);
+extern my_bool _mi_read_pack_info(MI_INFO *info,pbool fix_keys);
+extern int _mi_read_pack_record(MI_INFO *info,my_off_t filepos,byte *buf);
+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);
+
+struct st_sort_info;
+
+
+typedef struct st_mi_block_info { /* Parameter to _mi_get_block_info */
+ uchar header[MI_BLOCK_INFO_HEADER_LENGTH];
+ ulong rec_len;
+ ulong data_len;
+ ulong block_len;
+ ulong blob_len;
+ my_off_t filepos;
+ my_off_t next_filepos;
+ my_off_t prev_filepos;
+ uint second_read;
+ uint offset;
+} MI_BLOCK_INFO;
+
+ /* bits in return from _mi_get_block_info */
+
+#define BLOCK_FIRST 1
+#define BLOCK_LAST 2
+#define BLOCK_DELETED 4
+#define BLOCK_ERROR 8 /* Wrong data */
+#define BLOCK_SYNC_ERROR 16 /* Right data at wrong place */
+#define BLOCK_FATAL_ERROR 32 /* hardware-error */
+
+#define NEAD_MEM ((uint) 10*4*(IO_SIZE+32)+32) /* Nead for recursion */
+#define MAXERR 20
+#define BUFFERS_WHEN_SORTING 16 /* Alloc for sort-key-tree */
+#define WRITE_COUNT MY_HOW_OFTEN_TO_WRITE
+#define INDEX_TMP_EXT ".TMM"
+#define DATA_TMP_EXT ".TMD"
+
+#define UPDATE_TIME 1
+#define UPDATE_STAT 2
+#define UPDATE_SORT 4
+#define UPDATE_AUTO_INC 8
+#define UPDATE_OPEN_COUNT 16
+
+#define USE_BUFFER_INIT (((1024L*512L-MALLOC_OVERHEAD)/IO_SIZE)*IO_SIZE)
+#define READ_BUFFER_INIT (1024L*256L-MALLOC_OVERHEAD)
+#define SORT_BUFFER_INIT (2048L*1024L-MALLOC_OVERHEAD)
+#define MIN_SORT_BUFFER (4096-MALLOC_OVERHEAD)
+
+enum myisam_log_commands {
+ MI_LOG_OPEN,MI_LOG_WRITE,MI_LOG_UPDATE,MI_LOG_DELETE,MI_LOG_CLOSE,MI_LOG_EXTRA,MI_LOG_LOCK,MI_LOG_DELETE_ALL
+};
+
+#define myisam_log(a,b,c,d) if (myisam_log_file >= 0) _myisam_log(a,b,c,d)
+#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)
+
+extern uint _mi_get_block_info(MI_BLOCK_INFO *,File, my_off_t);
+extern uint _mi_rec_pack(MI_INFO *info,byte *to,const byte *from);
+extern uint _mi_pack_get_block_info(MI_INFO *mysql, MI_BLOCK_INFO *, File,
+ my_off_t, char *rec_buf);
+extern void _my_store_blob_length(byte *pos,uint pack_length,uint length);
+extern void _myisam_log(enum myisam_log_commands command,MI_INFO *info,
+ const byte *buffert,uint length);
+extern void _myisam_log_command(enum myisam_log_commands command,
+ MI_INFO *info, const byte *buffert,
+ uint length, int result);
+extern void _myisam_log_record(enum myisam_log_commands command,MI_INFO *info,
+ const byte *record,my_off_t filepos,
+ int result);
+extern my_bool _mi_memmap_file(MI_INFO *info);
+extern void _mi_unmap_file(MI_INFO *info);
+extern uint save_pack_length(byte *block_buff,ulong length);
+
+uint mi_state_info_write(File file, MI_STATE_INFO *state, uint pWrite);
+char *mi_state_info_read(char *ptr, MI_STATE_INFO *state);
+uint mi_state_info_read_dsk(File file, MI_STATE_INFO *state, my_bool pRead);
+uint mi_base_info_write(File file, MI_BASE_INFO *base);
+char *my_n_base_info_read(char *ptr, MI_BASE_INFO *base);
+int mi_keyseg_write(File file, const MI_KEYSEG *keyseg);
+char *mi_keyseg_read(char *ptr, MI_KEYSEG *keyseg);
+uint mi_keydef_write(File file, MI_KEYDEF *keydef);
+char *mi_keydef_read(char *ptr, MI_KEYDEF *keydef);
+uint mi_uniquedef_write(File file, MI_UNIQUEDEF *keydef);
+char *mi_uniquedef_read(char *ptr, MI_UNIQUEDEF *keydef);
+uint mi_recinfo_write(File file, MI_COLUMNDEF *recinfo);
+char *mi_recinfo_read(char *ptr, MI_COLUMNDEF *recinfo);
+ulong _my_calc_total_blob_length(MI_INFO *info, const byte *record);
+ha_checksum mi_checksum(MI_INFO *info, const byte *buf);
+ha_checksum mi_static_checksum(MI_INFO *info, const byte *buf);
+my_bool mi_check_unique(MI_INFO *info, MI_UNIQUEDEF *def, byte *record,
+ ha_checksum unique_hash, my_off_t pos);
+ha_checksum mi_unique_hash(MI_UNIQUEDEF *def, const byte *buf);
+int _mi_cmp_static_unique(MI_INFO *info, MI_UNIQUEDEF *def,
+ const byte *record, my_off_t pos);
+int _mi_cmp_dynamic_unique(MI_INFO *info, MI_UNIQUEDEF *def,
+ const byte *record, my_off_t pos);
+int mi_unique_comp(MI_UNIQUEDEF *def, const byte *a, const byte *b,
+ my_bool null_are_equal);
+void mi_get_status(void* param);
+void mi_update_status(void* param);
+void mi_copy_status(void* to,void *from);
+my_bool mi_check_status(void* param);
+
+/* Functions needed by mi_check */
+#ifdef __cplusplus
+extern "C" {
+#endif
+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,...));
+
+#ifdef __cplusplus
+}
+#endif
+
diff --git a/myisam/myisamlog.c b/myisam/myisamlog.c
new file mode 100644
index 00000000000..c55aecfdfa6
--- /dev/null
+++ b/myisam/myisamlog.c
@@ -0,0 +1,832 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* write whats in isam.log */
+
+#ifndef USE_MY_FUNC
+#define USE_MY_FUNC
+#endif
+
+#include "myisamdef.h"
+#include "my_tree.h"
+#include <stdarg.h>
+#ifdef HAVE_GETRUSAGE
+#include <sys/resource.h>
+#endif
+
+#define FILENAME(A) (A ? A->show_name : "Unknown")
+
+struct file_info {
+ long process;
+ int filenr,id;
+ my_string name,show_name,record;
+ MI_INFO *isam;
+ bool closed,used;
+ ulong accessed;
+};
+
+struct test_if_open_param {
+ my_string name;
+ int max_id;
+};
+
+struct st_access_param
+{
+ ulong min_accessed;
+ struct file_info *found;
+};
+
+#define NO_FILEPOS (ulong) ~0L
+
+extern int main(int argc,char * *argv);
+static void get_options(int *argc,char ***argv);
+static int examine_log(my_string file_name,char **table_names);
+static int read_string(IO_CACHE *file,gptr *to,uint length);
+static int file_info_compare(void *a,void *b);
+static int test_if_open(struct file_info *key,element_count count,
+ struct test_if_open_param *param);
+static void fix_blob_pointers(MI_INFO *isam,byte *record);
+static uint set_maximum_open_files(uint);
+static int test_when_accessed(struct file_info *key,element_count count,
+ struct st_access_param *access_param);
+static void file_info_free(struct file_info *info);
+static int close_some_file(TREE *tree);
+static int reopen_closed_file(TREE *tree,struct file_info *file_info);
+static int find_record_with_key(struct file_info *file_info,byte *record);
+static void printf_log(const char *str,...);
+static bool cmp_filename(struct file_info *file_info,my_string name);
+
+static uint verbose=0,update=0,test_info=0,max_files=0,re_open_count=0,
+ recover=0,prefix_remove=0;
+static my_string log_filename=0,filepath=0,write_filename=0,record_pos_file=0;
+static ulong com_count[10][3],number_of_commands=(ulong) ~0L,
+ isamlog_process;
+static my_off_t isamlog_filepos,start_offset=0,record_pos= HA_OFFSET_ERROR;
+static const char *command_name[]=
+{"open","write","update","delete","close","extra","lock","re-open","delete-all", NullS};
+
+
+int main(int argc, char **argv)
+{
+ int error,i,first;
+ ulong total_count,total_error,total_recover;
+ MY_INIT(argv[0]);
+
+ log_filename=myisam_log_filename;
+ get_options(&argc,&argv);
+ /* Nr of isam-files */
+ max_files=(set_maximum_open_files(min(max_files,8))-6)/2;
+
+ if (update)
+ printf("Trying to %s isamfiles according to log '%s'\n",
+ (recover ? "recover" : "update"),log_filename);
+ error= examine_log(log_filename,argv);
+ if (update && ! error)
+ puts("isamfile:s updated successfully");
+ total_count=total_error=total_recover=0;
+ for (i=first=0 ; command_name[i] ; i++)
+ {
+ if (com_count[i][0])
+ {
+ if (!first++)
+ {
+ if (verbose || update)
+ puts("");
+ puts("Commands Used count Errors Recover errors");
+ }
+ printf("%-12s%9ld%10ld%17ld\n",command_name[i],com_count[i][0],
+ com_count[i][1],com_count[i][2]);
+ total_count+=com_count[i][0];
+ total_error+=com_count[i][1];
+ total_recover+=com_count[i][2];
+ }
+ }
+ if (total_count)
+ printf("%-12s%9ld%10ld%17ld\n","Total",total_count,total_error,
+ total_recover);
+ if (re_open_count)
+ printf("Had to do %d re-open because of too few possibly open files\n",
+ re_open_count);
+ VOID(mi_panic(HA_PANIC_CLOSE));
+ my_end(test_info ? MY_CHECK_ERROR | MY_GIVE_INFO : MY_CHECK_ERROR);
+ exit(error);
+ return 0; /* No compiler warning */
+} /* main */
+
+
+static void get_options(register int *argc, register char ***argv)
+{
+ int help,version;
+ const char *pos,*usage;
+ char option;
+
+ help=0;
+ usage="Usage: %s [-?iruvIV] [-c #] [-f #] [-F filepath/] [-o #] [-R file recordpos] [-w write_file] [log-filename [table ...]] \n";
+ pos="";
+
+ while (--*argc > 0 && *(pos = *(++*argv)) == '-' ) {
+ while (*++pos)
+ {
+ version=0;
+ switch((option=*pos)) {
+ case '#':
+ DBUG_PUSH (++pos);
+ pos=" "; /* Skipp rest of arg */
+ break;
+ case 'c':
+ if (! *++pos)
+ {
+ if (!--*argc)
+ goto err;
+ else
+ pos= *(++*argv);
+ }
+ number_of_commands=(ulong) atol(pos);
+ pos=" ";
+ break;
+ case 'u':
+ update=1;
+ break;
+ case 'f':
+ if (! *++pos)
+ {
+ if (!--*argc)
+ goto err;
+ else
+ pos= *(++*argv);
+ }
+ max_files=(uint) atoi(pos);
+ pos=" ";
+ break;
+ case 'i':
+ test_info=1;
+ break;
+ case 'o':
+ if (! *++pos)
+ {
+ if (!--*argc)
+ goto err;
+ else
+ pos= *(++*argv);
+ }
+ start_offset=(my_off_t) strtoll(pos,NULL,10);
+ pos=" ";
+ break;
+ case 'p':
+ if (! *++pos)
+ {
+ if (!--*argc)
+ goto err;
+ else
+ pos= *(++*argv);
+ }
+ prefix_remove=atoi(pos);
+ break;
+ case 'r':
+ update=1;
+ recover++;
+ break;
+ case 'R':
+ if (! *++pos)
+ {
+ if (!--*argc)
+ goto err;
+ else
+ pos= *(++*argv);
+ }
+ record_pos_file=(char*) pos;
+ if (!--*argc)
+ goto err;
+ record_pos=(my_off_t) strtoll(*(++*argv),NULL,10);
+ pos=" ";
+ break;
+ case 'v':
+ verbose++;
+ break;
+ case 'w':
+ if (! *++pos)
+ {
+ if (!--*argc)
+ goto err;
+ else
+ pos= *(++*argv);
+ }
+ write_filename=(char*) pos;
+ pos=" ";
+ break;
+ case 'F':
+ if (! *++pos)
+ {
+ if (!--*argc)
+ goto err;
+ else
+ pos= *(++*argv);
+ }
+ filepath= (char*) pos;
+ pos=" ";
+ break;
+ case 'V':
+ version=1;
+ /* Fall through */
+ case 'I':
+ case '?':
+ printf("%s Ver 1.1 for %s at %s\n",my_progname,SYSTEM_TYPE,
+ MACHINE_TYPE);
+ puts("By Monty, for your professional use\n");
+ if (version)
+ break;
+ puts("Write info about whats in a myisam log file.");
+ printf("If no file name is given %s is used\n",log_filename);
+ puts("");
+ printf(usage,my_progname);
+ puts("");
+ puts("Options: -? or -I \"Info\" -V \"version\" -c \"do only # commands\"");
+ puts(" -f \"max open files\" -F \"filepath\" -i \"extra info\"");
+ puts(" -o \"offset\" -p # \"remove # components from path\"");
+ puts(" -r \"recover\" -R \"file recordposition\"");
+ puts(" -u \"update\" -v \"verbose\" -w \"write file\"");
+ puts("\nOne can give a second and a third '-v' for more verbose.");
+ puts("Normaly one does a update (-u).");
+ puts("If a recover is done all writes and all possibly updates and deletes is done\nand errors are only counted.");
+ puts("If one gives table names as arguments only these tables will be updated\n");
+ help=1;
+ break;
+ default:
+ printf("illegal option: \"-%c\"\n",*pos);
+ break;
+ }
+ }
+ }
+ if (! *argc)
+ {
+ if (help)
+ exit(0);
+ (*argv)++;
+ }
+ if (*argc >= 1)
+ {
+ log_filename=(char*) pos;
+ (*argc)--;
+ (*argv)++;
+ }
+ return;
+ err:
+ VOID(fprintf(stderr,"option \"%c\" used without or with wrong argument\n",
+ option));
+ exit(1);
+}
+
+
+static int examine_log(my_string file_name, char **table_names)
+{
+ uint command,result,files_open;
+ ulong access_time,length;
+ my_off_t filepos;
+ int lock_command,mi_result;
+ char isam_file_name[FN_REFLEN],llbuff[21],llbuff2[21];
+ uchar head[20];
+ gptr buff;
+ struct test_if_open_param open_param;
+ IO_CACHE cache;
+ File file;
+ FILE *write_file;
+ enum ha_extra_function extra_command;
+ TREE tree;
+ struct file_info file_info,*curr_file_info;
+ DBUG_ENTER("examine_log");
+
+ if ((file=my_open(file_name,O_RDONLY,MYF(MY_WME))) < 0)
+ DBUG_RETURN(1);
+ write_file=0;
+ if (write_filename)
+ {
+ if (!(write_file=my_fopen(write_filename,O_WRONLY,MYF(MY_WME))))
+ {
+ my_close(file,MYF(0));
+ DBUG_RETURN(1);
+ }
+ }
+
+ init_io_cache(&cache,file,0,READ_CACHE,start_offset,0,MYF(0));
+ bzero((gptr) com_count,sizeof(com_count));
+ init_tree(&tree,0,sizeof(file_info),(qsort_cmp) file_info_compare,0,
+ (void(*)(void*)) file_info_free);
+ VOID(init_key_cache(KEY_CACHE_SIZE,(uint) (10*4*(IO_SIZE+MALLOC_OVERHEAD))));
+
+ files_open=0; access_time=0;
+ while (access_time++ != number_of_commands &&
+ !my_b_read(&cache,(byte*) head,9))
+ {
+ isamlog_filepos=my_b_tell(&cache)-9L;
+ file_info.filenr= mi_uint2korr(head+1);
+ isamlog_process=file_info.process=(long) mi_uint4korr(head+3);
+ result= mi_uint2korr(head+7);
+ if ((curr_file_info=(struct file_info*) tree_search(&tree,&file_info)))
+ {
+ curr_file_info->accessed=access_time;
+ if (update && curr_file_info->used && curr_file_info->closed)
+ {
+ if (reopen_closed_file(&tree,curr_file_info))
+ {
+ command=sizeof(com_count)/sizeof(com_count[0][0])/3;
+ result=0;
+ goto com_err;
+ }
+ }
+ }
+ command=(uint) head[0];
+ if (command < sizeof(com_count)/sizeof(com_count[0][0])/3 &&
+ (!curr_file_info || curr_file_info->used))
+ {
+ com_count[command][0]++;
+ if (result)
+ com_count[command][1]++;
+ }
+ switch ((enum myisam_log_commands) command) {
+ case MI_LOG_OPEN:
+ com_count[command][0]--; /* Must be counted explicite */
+ if (result)
+ com_count[command][1]--;
+
+ if (curr_file_info)
+ printf("\nWarning: %s is opened twice with same process and filenumber\n",
+ curr_file_info->show_name);
+ if (my_b_read(&cache,(byte*) head,2))
+ goto err;
+ file_info.name=0;
+ file_info.show_name=0;
+ file_info.record=0;
+ if (read_string(&cache,(gptr*) &file_info.name,
+ (uint) mi_uint2korr(head)))
+ goto err;
+ {
+ uint i;
+ char *pos=file_info.name,*to;
+ for (i=0 ; i < prefix_remove ; i++)
+ {
+ char *next;
+ if (!(next=strchr(pos,FN_LIBCHAR)))
+ break;
+ pos=next+1;
+ }
+ to=isam_file_name;
+ if (filepath)
+ {
+ strmov(isam_file_name,filepath);
+ convert_dirname(isam_file_name);
+ to=strend(isam_file_name);
+ }
+ strmov(to,pos);
+ fn_ext(isam_file_name)[0]=0; /* Remove extension */
+ }
+ open_param.name=file_info.name;
+ open_param.max_id=0;
+ VOID(tree_walk(&tree,(tree_walk_action) test_if_open,(void*) &open_param,
+ left_root_right));
+ file_info.id=open_param.max_id+1;
+ file_info.show_name=my_memdup(isam_file_name,
+ (uint) strlen(isam_file_name)+6,
+ MYF(MY_WME));
+ if (file_info.id > 1)
+ sprintf(strend(file_info.show_name),"<%d>",file_info.id);
+ file_info.closed=1;
+ file_info.accessed=access_time;
+ file_info.used=1;
+ if (table_names[0])
+ {
+ char **name;
+ file_info.used=0;
+ for (name=table_names ; *name ; name++)
+ {
+ if (!strcmp(*name,isam_file_name))
+ file_info.used=1; /* Update/log only this */
+ }
+ }
+ if (update && file_info.used)
+ {
+ if (files_open >= max_files)
+ {
+ if (close_some_file(&tree))
+ goto com_err;
+ files_open--;
+ }
+ if (!(file_info.isam= mi_open(isam_file_name,O_RDWR,
+ HA_OPEN_WAIT_IF_LOCKED)))
+ goto com_err;
+ if (!(file_info.record=my_malloc(file_info.isam->s->base.reclength,
+ MYF(MY_WME))))
+ goto end;
+ files_open++;
+ file_info.closed=0;
+ }
+ VOID(tree_insert(&tree,(gptr) &file_info,0));
+ if (file_info.used)
+ {
+ if (verbose && !record_pos_file)
+ printf_log("%s: open",file_info.show_name);
+ com_count[command][0]++;
+ if (result)
+ com_count[command][1]++;
+ }
+ break;
+ case MI_LOG_CLOSE:
+ if (verbose && !record_pos_file &&
+ (!table_names[0] || (curr_file_info && curr_file_info->used)))
+ printf_log("%s: %s -> %d",FILENAME(curr_file_info),
+ command_name[command],result);
+ if (curr_file_info)
+ {
+ if (!curr_file_info->closed)
+ files_open--;
+ VOID(tree_delete(&tree,(gptr) curr_file_info));
+ }
+ break;
+ case MI_LOG_EXTRA:
+ if (my_b_read(&cache,(byte*) head,1))
+ goto err;
+ extra_command=(enum ha_extra_function) head[0];
+ if (verbose && !record_pos_file &&
+ (!table_names[0] || (curr_file_info && curr_file_info->used)))
+ printf_log("%s: %s(%d) -> %d",FILENAME(curr_file_info),
+ command_name[command], (int) extra_command,result);
+ if (update && curr_file_info && !curr_file_info->closed)
+ {
+ if (mi_extra(curr_file_info->isam,
+ (int) extra_command) != (int) result)
+ {
+ VOID(fprintf(stderr,
+ "Warning: error %d, expected %d on command %s at %s\n",
+ my_errno,result,command_name[command],
+ llstr(isamlog_filepos,llbuff)));
+ }
+ }
+ break;
+ case MI_LOG_DELETE:
+ if (my_b_read(&cache,(byte*) head,8))
+ goto err;
+ filepos=mi_sizekorr(head);
+ if (verbose && (!record_pos_file ||
+ ((record_pos == filepos || record_pos == NO_FILEPOS) &&
+ !cmp_filename(curr_file_info,record_pos_file))) &&
+ (!table_names[0] || (curr_file_info && curr_file_info->used)))
+ printf_log("%s: %s at %ld -> %d",FILENAME(curr_file_info),
+ command_name[command],(long) filepos,result);
+ if (update && curr_file_info && !curr_file_info->closed)
+ {
+ if (mi_rrnd(curr_file_info->isam,curr_file_info->record,filepos))
+ {
+ if (!recover)
+ goto com_err;
+ com_count[command][2]++; /* Mark error */
+ }
+ mi_result=mi_delete(curr_file_info->isam,curr_file_info->record);
+ if ((mi_result == 0 && result) ||
+ (mi_result && (uint) my_errno != result))
+ {
+ if (!recover)
+ goto com_err;
+ if (mi_result)
+ com_count[command][2]++; /* Mark error */
+ }
+ }
+ break;
+ case MI_LOG_WRITE:
+ case MI_LOG_UPDATE:
+ if (my_b_read(&cache,(byte*) head,12))
+ goto err;
+ filepos=mi_sizekorr(head);
+ length=mi_uint4korr(head+8);
+ buff=0;
+ if (read_string(&cache,&buff,(uint) length))
+ goto err;
+ if ((!record_pos_file ||
+ ((record_pos == filepos || record_pos == NO_FILEPOS) &&
+ !cmp_filename(curr_file_info,record_pos_file))) &&
+ (!table_names[0] || (curr_file_info && curr_file_info->used)))
+ {
+ if (write_file &&
+ (my_fwrite(write_file,buff,length,MYF(MY_WAIT_IF_FULL | MY_NABP))))
+ goto end;
+ if (verbose)
+ printf_log("%s: %s at %ld, length=%ld -> %d",
+ FILENAME(curr_file_info),
+ command_name[command], filepos,length,result);
+ }
+ if (update && curr_file_info && !curr_file_info->closed)
+ {
+ if (curr_file_info->isam->s->base.blobs)
+ fix_blob_pointers(curr_file_info->isam,buff);
+ if ((enum myisam_log_commands) command == MI_LOG_UPDATE)
+ {
+ if (mi_rrnd(curr_file_info->isam,curr_file_info->record,filepos))
+ {
+ if (!recover)
+ {
+ result=0;
+ goto com_err;
+ }
+ if (recover == 1 || result ||
+ find_record_with_key(curr_file_info,buff))
+ {
+ com_count[command][2]++; /* Mark error */
+ break;
+ }
+ }
+ mi_result=mi_update(curr_file_info->isam,curr_file_info->record,
+ buff);
+ if ((mi_result == 0 && result) ||
+ (mi_result && (uint) my_errno != result))
+ {
+ if (!recover)
+ goto com_err;
+ if (mi_result)
+ com_count[command][2]++; /* Mark error */
+ }
+ }
+ else
+ {
+ mi_result=mi_write(curr_file_info->isam,buff);
+ if ((mi_result == 0 && result) ||
+ (mi_result && (uint) my_errno != result))
+ {
+ if (!recover)
+ goto com_err;
+ if (mi_result)
+ com_count[command][2]++; /* Mark error */
+ }
+ if (! recover && filepos != curr_file_info->isam->lastpos)
+ {
+ printf("Warning: Wrote at position: %s, should have been %s",
+ llstr(curr_file_info->isam->lastpos,llbuff),
+ llstr(filepos,llbuff2));
+ goto com_err;
+ }
+ }
+ }
+ my_free(buff,MYF(0));
+ break;
+ case MI_LOG_LOCK:
+ if (my_b_read(&cache,(byte*) head,sizeof(lock_command)))
+ goto err;
+ memcpy_fixed(&lock_command,head,sizeof(lock_command));
+ if (verbose && !record_pos_file &&
+ (!table_names[0] || (curr_file_info && curr_file_info->used)))
+ printf_log("%s: %s(%d) -> %d\n",FILENAME(curr_file_info),
+ command_name[command],lock_command,result);
+ if (update && curr_file_info && !curr_file_info->closed)
+ {
+ if (mi_lock_database(curr_file_info->isam,lock_command) !=
+ (int) result)
+ goto com_err;
+ }
+ break;
+ case MI_LOG_DELETE_ALL:
+ if (verbose && !record_pos_file &&
+ (!table_names[0] || (curr_file_info && curr_file_info->used)))
+ printf_log("%s: %s -> %d\n",FILENAME(curr_file_info),
+ command_name[command],result);
+ break;
+ default:
+ VOID(fprintf(stderr,
+ "Error: found unknown command %d in logfile, aborted\n",
+ command));
+ goto end;
+ }
+ }
+ end_key_cache();
+ delete_tree(&tree);
+ VOID(end_io_cache(&cache));
+ VOID(my_close(file,MYF(0)));
+ if (write_file && my_fclose(write_file,MYF(MY_WME)))
+ DBUG_RETURN(1);
+ DBUG_RETURN(0);
+
+ err:
+ VOID(fprintf(stderr,"Got error %d when reading from logfile\n",my_errno));
+ goto end;
+ com_err:
+ VOID(fprintf(stderr,"Got error %d, expected %d on command %s at %s\n",
+ my_errno,result,command_name[command],
+ llstr(isamlog_filepos,llbuff)));
+ end:
+ end_key_cache();
+ delete_tree(&tree);
+ VOID(end_io_cache(&cache));
+ VOID(my_close(file,MYF(0)));
+ if (write_file)
+ VOID(my_fclose(write_file,MYF(MY_WME)));
+ DBUG_RETURN(1);
+}
+
+
+static int read_string(IO_CACHE *file, register gptr *to, register uint length)
+{
+ DBUG_ENTER("read_string");
+
+ if (*to)
+ my_free((gptr) *to,MYF(0));
+ if (!(*to= (gptr) my_malloc(length+1,MYF(MY_WME))) ||
+ my_b_read(file,(byte*) *to,length))
+ {
+ if (*to)
+ my_free(*to,MYF(0));
+ *to= 0;
+ DBUG_RETURN(1);
+ }
+ *((char*) *to+length)= '\0';
+ DBUG_RETURN (0);
+} /* read_string */
+
+
+static int file_info_compare(void *a, void *b)
+{
+ long lint;
+
+ if ((lint=((struct file_info*) a)->process -
+ ((struct file_info*) b)->process))
+ return lint < 0L ? -1 : 1;
+ return ((struct file_info*) a)->filenr - ((struct file_info*) b)->filenr;
+}
+
+ /* ARGSUSED */
+
+static int test_if_open (struct file_info *key,
+ element_count count __attribute__((unused)),
+ struct test_if_open_param *param)
+{
+ if (!strcmp(key->name,param->name) && key->id > param->max_id)
+ param->max_id=key->id;
+ return 0;
+}
+
+
+static void fix_blob_pointers(MI_INFO *info, byte *record)
+{
+ byte *pos;
+ MI_BLOB *blob,*end;
+
+ pos=record+info->s->base.reclength;
+ for (end=info->blobs+info->s->base.blobs, blob= info->blobs;
+ blob != end ;
+ blob++)
+ {
+ memcpy_fixed(record+blob->offset+blob->pack_length,&pos,sizeof(char*));
+ pos+=_mi_calc_blob_length(blob->pack_length,record+blob->offset);
+ }
+}
+
+static uint set_maximum_open_files(uint maximum_files)
+{
+#if defined(HAVE_GETRUSAGE) && defined(RLIMIT_NOFILE)
+ struct rlimit rlimit;
+ int old_max;
+
+ if (maximum_files > MY_NFILE)
+ maximum_files=MY_NFILE; /* Don't crash my_open */
+
+ if (!getrlimit(RLIMIT_NOFILE,&rlimit))
+ {
+ old_max=rlimit.rlim_max;
+ if (maximum_files && (int) maximum_files > old_max)
+ rlimit.rlim_max=maximum_files;
+ rlimit.rlim_cur=rlimit.rlim_max;
+ if (setrlimit(RLIMIT_NOFILE,&rlimit))
+ {
+ if (old_max != (int) maximum_files)
+ { /* Set as much as we can */
+ rlimit.rlim_max=rlimit.rlim_cur=old_max;
+ setrlimit(RLIMIT_NOFILE,&rlimit);
+ }
+ }
+ getrlimit(RLIMIT_NOFILE,&rlimit); /* Read if broken setrlimit */
+ if (maximum_files && maximum_files < rlimit.rlim_cur)
+ VOID(fprintf(stderr,"Warning: Error from setrlimit: Max open files is %d\n",old_max));
+ return rlimit.rlim_cur;
+ }
+#endif
+ return min(maximum_files,MY_NFILE);
+}
+
+ /* close the file with hasn't been accessed for the longest time */
+ /* ARGSUSED */
+
+static int test_when_accessed (struct file_info *key,
+ element_count count __attribute__((unused)),
+ struct st_access_param *access_param)
+{
+ if (key->accessed < access_param->min_accessed && ! key->closed)
+ {
+ access_param->min_accessed=key->accessed;
+ access_param->found=key;
+ }
+ return 0;
+}
+
+
+static void file_info_free(struct file_info *fileinfo)
+{
+ DBUG_ENTER("file_info_free");
+ if (update)
+ {
+ if (!fileinfo->closed)
+ VOID(mi_close(fileinfo->isam));
+ if (fileinfo->record)
+ my_free(fileinfo->record,MYF(0));
+ }
+ my_free(fileinfo->name,MYF(0));
+ my_free(fileinfo->show_name,MYF(0));
+ DBUG_VOID_RETURN;
+}
+
+
+
+static int close_some_file(TREE *tree)
+{
+ struct st_access_param access_param;
+
+ access_param.min_accessed=LONG_MAX;
+ access_param.found=0;
+
+ VOID(tree_walk(tree,(tree_walk_action) test_when_accessed,
+ (void*) &access_param,left_root_right));
+ if (!access_param.found)
+ return 1; /* No open file that is possibly to close */
+ if (mi_close(access_param.found->isam))
+ return 1;
+ access_param.found->closed=1;
+ return 0;
+}
+
+
+static int reopen_closed_file(TREE *tree, struct file_info *fileinfo)
+{
+ char name[FN_REFLEN];
+ if (close_some_file(tree))
+ return 1; /* No file to close */
+ strmov(name,fileinfo->show_name);
+ if (fileinfo->id > 1)
+ *strrchr(name,'<')='\0'; /* Remove "<id>" */
+
+ if (!(fileinfo->isam= mi_open(name,O_RDWR,HA_OPEN_WAIT_IF_LOCKED)))
+ return 1;
+ fileinfo->closed=0;
+ re_open_count++;
+ return 0;
+}
+
+ /* Try to find record with uniq key */
+
+static int find_record_with_key(struct file_info *file_info, byte *record)
+{
+ uint key;
+ MI_INFO *info=file_info->isam;
+ uchar tmp_key[MI_MAX_KEY_BUFF];
+
+ for (key=0 ; key < info->s->base.keys ; key++)
+ {
+ if ((((ulonglong) 1 << key) & info->s->state.key_map) &&
+ info->s->keyinfo[key].flag & HA_NOSAME)
+ {
+ VOID(_mi_make_key(info,key,tmp_key,record,0L));
+ return mi_rkey(info,file_info->record,(int) key,(char*) tmp_key,0,
+ HA_READ_KEY_EXACT);
+ }
+ }
+ return 1;
+}
+
+
+static void printf_log(const char *format,...)
+{
+ char llbuff[21];
+ va_list args;
+ va_start(args,format);
+ if (verbose > 2)
+ printf("%9s:",llstr(isamlog_filepos,llbuff));
+ if (verbose > 1)
+ printf("%5ld ",isamlog_process); /* Write process number */
+ (void) vprintf((char*) format,args);
+ putchar('\n');
+ va_end(args);
+}
+
+
+static bool cmp_filename(struct file_info *file_info, my_string name)
+{
+ if (!file_info)
+ return 1;
+ return strcmp(file_info->name,name) ? 1 : 0;
+}
diff --git a/myisam/myisampack.c b/myisam/myisampack.c
new file mode 100644
index 00000000000..6f634f32ec9
--- /dev/null
+++ b/myisam/myisampack.c
@@ -0,0 +1,2140 @@
+/* Copyright (C) 1999 Monty Program KB
+
+ This software is distributed with NO WARRANTY OF ANY KIND. No author or
+ distributor accepts any responsibility for the consequences of using it, or
+ for whether it serves any particular purpose or works at all, unless he or
+ she says so in writing. Refer to the Free Public License (the "License")
+ for full details.
+ Every copy of this file must include a copy of the License, normally in a
+ plain ASCII text file named PUBLIC. The License grants you the right to
+ copy, modify and redistribute this file, but only under certain conditions
+ described in the License. Among other things, the License requires that
+ the copyright notice and this notice be preserved on all copies. */
+
+/* Pack isam file*/
+
+#ifndef USE_MY_FUNC
+#define USE_MY_FUNC /* We nead at least my_malloc */
+#endif
+
+#include "myisamdef.h"
+#include <queues.h>
+#include <my_tree.h>
+#include "mysys_err.h"
+#ifdef MSDOS
+#include <io.h>
+#endif
+#ifndef __GNU_LIBRARY__
+#define __GNU_LIBRARY__ /* Skipp warnings in getopt.h */
+#endif
+#include <getopt.h>
+
+#if INT_MAX > 32767
+#define BITS_SAVED 32
+#else
+#define BITS_SAVED 16
+#endif
+
+#define IS_OFFSET ((uint) 32768) /* Bit if offset or char in tree */
+#define HEAD_LENGTH 32
+#define ALLOWED_JOIN_DIFF 256 /* Diff allowed to join trees */
+
+#define DATA_TMP_EXT ".TMD"
+#define OLD_EXT ".OLD"
+#define WRITE_COUNT MY_HOW_OFTEN_TO_WRITE
+
+struct st_file_buffer {
+ File file;
+ char *buffer,*pos,*end;
+ my_off_t pos_in_file;
+ int bits;
+ uint byte;
+};
+
+struct st_huff_tree;
+struct st_huff_element;
+
+typedef struct st_huff_counts {
+ uint field_length,max_zero_fill;
+ uint pack_type;
+ uint max_end_space,max_pre_space,length_bits,min_space;
+ ulong max_length;
+ enum en_fieldtype field_type;
+ struct st_huff_tree *tree; /* Tree for field */
+ my_off_t counts[256];
+ my_off_t end_space[8];
+ my_off_t pre_space[8];
+ my_off_t tot_end_space,tot_pre_space,zero_fields,empty_fields,bytes_packed;
+ TREE int_tree;
+ byte *tree_buff;
+ byte *tree_pos;
+} HUFF_COUNTS;
+
+typedef struct st_huff_element HUFF_ELEMENT;
+
+struct st_huff_element {
+ my_off_t count;
+ union un_element {
+ struct st_nod {
+ HUFF_ELEMENT *left,*right;
+ } nod;
+ struct st_leaf {
+ HUFF_ELEMENT *null;
+ uint element_nr; /* Number of element */
+ } leaf;
+ } a;
+};
+
+
+typedef struct st_huff_tree {
+ HUFF_ELEMENT *root,*element_buffer;
+ HUFF_COUNTS *counts;
+ uint tree_number;
+ uint elements;
+ my_off_t bytes_packed;
+ uint tree_pack_length;
+ uint min_chr,max_chr,char_bits,offset_bits,max_offset,height;
+ ulong *code;
+ uchar *code_len;
+} HUFF_TREE;
+
+
+typedef struct st_isam_mrg {
+ MI_INFO **file,**current,**end;
+ uint free_file;
+ uint count;
+ uint min_pack_length; /* Theese is used by packed data */
+ uint max_pack_length;
+ uint ref_length;
+ uint max_blob_length;
+ my_off_t records;
+} MRG_INFO;
+
+
+extern int main(int argc,char * *argv);
+static void get_options(int *argc,char ***argv);
+static MI_INFO *open_isam_file(char *name,int mode);
+static bool open_isam_files(MRG_INFO *mrg,char **names,uint count);
+static int compress(MRG_INFO *file,char *join_name);
+static HUFF_COUNTS *init_huff_count(MI_INFO *info,my_off_t records);
+static void free_counts_and_tree_and_queue(HUFF_TREE *huff_trees,
+ uint trees,
+ HUFF_COUNTS *huff_counts,
+ uint fields);
+static int compare_tree(const uchar *s,const uchar *t);
+static int get_statistic(MRG_INFO *mrg,HUFF_COUNTS *huff_counts);
+static void check_counts(HUFF_COUNTS *huff_counts,uint trees,
+ my_off_t records);
+static int test_space_compress(HUFF_COUNTS *huff_counts,my_off_t records,
+ uint max_space_length,my_off_t *space_counts,
+ my_off_t tot_space_count,
+ enum en_fieldtype field_type);
+static HUFF_TREE* make_huff_trees(HUFF_COUNTS *huff_counts,uint trees);
+static int make_huff_tree(HUFF_TREE *tree,HUFF_COUNTS *huff_counts);
+static int compare_huff_elements(void *not_used, byte *a,byte *b);
+static int save_counts_in_queue(byte *key,element_count count,
+ HUFF_TREE *tree);
+static my_off_t calc_packed_length(HUFF_COUNTS *huff_counts,uint flag);
+static uint join_same_trees(HUFF_COUNTS *huff_counts,uint trees);
+static int make_huff_decode_table(HUFF_TREE *huff_tree,uint trees);
+static void make_traverse_code_tree(HUFF_TREE *huff_tree,
+ HUFF_ELEMENT *element,uint size,
+ ulong code);
+static int write_header(MRG_INFO *isam_file, uint header_length,uint trees,
+ my_off_t tot_elements,my_off_t filelength);
+static void write_field_info(HUFF_COUNTS *counts, uint fields,uint trees);
+static my_off_t write_huff_tree(HUFF_TREE *huff_tree,uint trees);
+static uint *make_offset_code_tree(HUFF_TREE *huff_tree,
+ HUFF_ELEMENT *element,
+ uint *offset);
+static uint max_bit(uint value);
+static int compress_isam_file(MRG_INFO *file,HUFF_COUNTS *huff_counts);
+static char *make_new_name(char *new_name,char *old_name);
+static char *make_old_name(char *new_name,char *old_name);
+static void init_file_buffer(File file,pbool read_buffer);
+static int flush_buffer(ulong neaded_length);
+static void end_file_buffer(void);
+static void write_bits(ulong value,uint bits);
+static void flush_bits(void);
+static int save_state(MI_INFO *isam_file,MRG_INFO *mrg,my_off_t new_length,
+ ha_checksum crc);
+static int save_state_mrg(File file,MRG_INFO *isam_file,my_off_t new_length,
+ ha_checksum crc);
+static int mrg_close(MRG_INFO *mrg);
+static int mrg_rrnd(MRG_INFO *info,byte *buf);
+static void mrg_reset(MRG_INFO *mrg);
+
+
+static int backup=0,error_on_write=0,test_only=0,verbose=0,silent=0,
+ write_loop=0,force_pack=0,opt_wait=0,isamchk_neaded=0;
+static int tmpfile_createflag=O_RDWR | O_TRUNC | O_EXCL;
+static uint tree_buff_length=8196-MALLOC_OVERHEAD;
+static char tmp_dir[FN_REFLEN]={0},*join_table;
+static my_off_t intervall_length;
+static ha_checksum glob_crc;
+static struct st_file_buffer file_buffer;
+static QUEUE queue;
+static HUFF_COUNTS *global_count;
+static char zero_string[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
+static const char *load_default_groups[]= { "myisampack",0 };
+
+ /* The main program */
+
+int main(int argc, char **argv)
+{
+ int error,ok;
+ MRG_INFO merge;
+ char **default_argv;
+ MY_INIT(argv[0]);
+
+ load_defaults("my",load_default_groups,&argc,&argv);
+ default_argv= argv;
+ get_options(&argc,&argv);
+
+ error=ok=isamchk_neaded=0;
+ if (join_table)
+ { /* Join files into one */
+ if (open_isam_files(&merge,argv,(uint) argc) ||
+ compress(&merge,join_table))
+ error=1;
+ }
+ else while (argc--)
+ {
+ MI_INFO *isam_file;
+ if (!(isam_file=open_isam_file(*argv++,O_RDWR)))
+ error=1;
+ else
+ {
+ merge.file= &isam_file;
+ merge.current=0;
+ merge.free_file=0;
+ merge.count=1;
+ if (compress(&merge,0))
+ error=1;
+ else
+ ok=1;
+ }
+ }
+ if (ok && isamchk_neaded && !silent)
+ puts("Remember to run myisamchk -rq on compressed tables");
+ VOID(fflush(stdout)); VOID(fflush(stderr));
+ free_defaults(default_argv);
+ my_end(verbose ? MY_CHECK_ERROR | MY_GIVE_INFO : MY_CHECK_ERROR);
+ exit(error ? 2 : 0);
+#ifndef _lint
+ return 0; /* No compiler warning */
+#endif
+}
+
+
+static struct option long_options[] =
+{
+ {"backup", no_argument, 0, 'b'},
+ {"debug", optional_argument, 0, '#'},
+ {"force", no_argument, 0, 'f'},
+ {"join", required_argument, 0, 'j'},
+ {"help", no_argument, 0, '?'},
+ {"packlength",required_argument, 0, 'p'},
+ {"silent", no_argument, 0, 's'},
+ {"tmpdir", required_argument, 0, 'T'},
+ {"test", no_argument, 0, 't'},
+ {"verbose", no_argument, 0, 'v'},
+ {"version", no_argument, 0, 'V'},
+ {"wait", no_argument, 0, 'w'},
+ {0, 0, 0, 0}
+};
+
+static void print_version(void)
+{
+ printf("%s Ver 1.7 for %s on %s\n",my_progname,SYSTEM_TYPE,MACHINE_TYPE);
+}
+
+static void usage(void)
+{
+ print_version();
+ puts("Copyright (C) 1999-2000 Monty Program KB.");
+ puts("This is not free software. You must have a licence to use this program");
+ puts("This software comes with ABSOLUTELY NO WARRANTY\n");
+ puts("Pack a MyISAM-table to take much smaller space");
+ puts("Keys are not updated, one must run myisamchk -rq on datafile afterwards");
+ puts("You should give the .MSI file as the filename argument");
+
+ printf("\nUsage: %s [OPTIONS] filename...\n", my_progname);
+ puts("\n\
+ -b, --backup Make a backup of the table as table_name.OLD\n\
+ -f, --force Force packing of table even if it's gets bigger or\n\
+ tempfile exists.\n\
+ -j, --join='new_table_name'\n\
+ Join all given tables into 'new_table_name'.\n\
+ All tables MUST have the identical layout.\n\
+ -s, --silent Be more silent.\n\
+ -t, --test Don't pack table, only test packing it\n\
+ -v, --verbose Write info about progress and packing result\n\
+ -w, --wait Wait and retry if table is in use\n\
+ -T, --tmpdir=# Use temporary directory to store temporary table\n\
+ -#, --debug=... output debug log. Often this is 'd:t:o,filename`\n\
+ -?, --help display this help and exit\n\
+ -V, --version output version information and exit");
+ print_defaults("my",load_default_groups);
+};
+
+ /* reads options */
+ /* Initiates DEBUG - but no debugging here ! */
+
+static void get_options(int *argc,char ***argv)
+{
+ int c,option_index=0;
+ uint length;
+
+ my_progname= argv[0][0];
+ if (isatty(fileno(stdout)))
+ write_loop=1;
+
+ while ((c=getopt_long(*argc,*argv,"bfj:stvwT:#::?V",long_options,
+ &option_index)) != EOF)
+ {
+ switch(c) {
+ case 'b':
+ backup=1;
+ break;
+ case 'f':
+ force_pack=1;
+ tmpfile_createflag=O_RDWR | O_TRUNC;
+ break;
+ case 'j':
+ join_table=optarg;
+ break;
+ case 's':
+ write_loop=verbose=0; silent=1;
+ break;
+ case 't':
+ test_only=verbose=1;
+ break;
+ case 'T':
+ length=(uint) (strmov(tmp_dir,optarg)-tmp_dir);
+ if (length != dirname_length(tmp_dir))
+ {
+ tmp_dir[length]=FN_LIBCHAR;
+ tmp_dir[length+1]=0;
+ }
+ break;
+ case 'v':
+ verbose=1; silent=0;
+ break;
+ case 'w':
+ opt_wait=1;
+ break;
+ case '#':
+ DBUG_PUSH(optarg ? optarg : "d:t:o");
+ break;
+ case 'V': print_version(); exit(0);
+ case 'I':
+ case '?':
+ usage();
+ exit(0);
+ default:
+ fprintf(stderr,"%s: Illegal option: -%c\n",my_progname,opterr);
+ usage();
+ exit(1);
+ }
+ }
+ (*argc)-=optind;
+ (*argv)+=optind;
+ if (!*argc)
+ {
+ usage();
+ exit(1);
+ }
+ if (join_table)
+ {
+ backup=0; /* Not needed */
+ tmp_dir[0]=0;
+ }
+ return;
+}
+
+
+static MI_INFO *open_isam_file(char *name,int mode)
+{
+ MI_INFO *isam_file;
+ MYISAM_SHARE *share;
+ DBUG_ENTER("open_isam_file");
+
+ if (!(isam_file=mi_open(name,mode,
+ (opt_wait ? HA_OPEN_WAIT_IF_LOCKED :
+ HA_OPEN_ABORT_IF_LOCKED))))
+ {
+ VOID(fprintf(stderr,"%s gave error %d on open\n",name,my_errno));
+ DBUG_RETURN(0);
+ }
+ share=isam_file->s;
+ if (share->options & HA_OPTION_COMPRESS_RECORD && !join_table)
+ {
+ if (!force_pack)
+ {
+ VOID(fprintf(stderr,"%s is already compressed\n",name));
+ VOID(mi_close(isam_file));
+ DBUG_RETURN(0);
+ }
+ if (verbose)
+ puts("Recompressing already compressed table");
+ share->options&= ~HA_OPTION_READ_ONLY_DATA; /* We are modifing it */
+ }
+ if (! force_pack && share->state.state.records != 0 &&
+ (share->state.state.records <= 1 ||
+ share->state.state.data_file_length < 1024))
+ {
+ VOID(fprintf(stderr,"%s is too small to compress\n",name));
+ VOID(mi_close(isam_file));
+ DBUG_RETURN(0);
+ }
+ VOID(mi_lock_database(isam_file,F_WRLCK));
+ DBUG_RETURN(isam_file);
+}
+
+
+static bool open_isam_files(MRG_INFO *mrg,char **names,uint count)
+{
+ uint i,j;
+ mrg->count=0;
+ mrg->current=0;
+ mrg->file=(MI_INFO**) my_malloc(sizeof(MI_INFO*)*count,MYF(MY_FAE));
+ mrg->free_file=1;
+ for (i=0; i < count ; i++)
+ {
+ if (!(mrg->file[i]=open_isam_file(names[i],O_RDONLY)))
+ goto error;
+ }
+ /* Check that files are identical */
+ for (j=0 ; j < count-1 ; j++)
+ {
+ MI_COLUMNDEF *m1,*m2,*end;
+ if (mrg->file[j]->s->base.reclength != mrg->file[j+1]->s->base.reclength ||
+ mrg->file[j]->s->base.fields != mrg->file[j+1]->s->base.fields)
+ goto diff_file;
+ m1=mrg->file[j]->s->rec;
+ end=m1+mrg->file[j]->s->base.fields;
+ m2=mrg->file[j+1]->s->rec;
+ for ( ; m1 != end ; m1++,m2++)
+ {
+ if (m1->type != m2->type || m1->length != m2->length)
+ goto diff_file;
+ }
+ }
+ mrg->count=count;
+ return 0;
+
+ diff_file:
+ fprintf(stderr,"%s: Tables '%s' and '%s' are not identical\n",
+ my_progname,names[j],names[j+1]);
+ error:
+ while (i--)
+ mi_close(mrg->file[i]);
+ my_free((gptr) mrg->file,MYF(0));
+ return 1;
+}
+
+
+static int compress(MRG_INFO *mrg,char *result_table)
+{
+ int error;
+ File new_file,join_isam_file;
+ MI_INFO *isam_file;
+ MYISAM_SHARE *share;
+ char org_name[FN_REFLEN],new_name[FN_REFLEN],temp_name[FN_REFLEN];
+ uint i,header_length,fields,trees,used_trees;
+ my_off_t old_length,new_length,tot_elements;
+ HUFF_COUNTS *huff_counts;
+ HUFF_TREE *huff_trees;
+ DBUG_ENTER("compress");
+
+ isam_file=mrg->file[0]; /* Take this as an example */
+ share=isam_file->s;
+ new_file=join_isam_file= -1;
+ trees=fields=0;
+ huff_trees=0;
+ huff_counts=0;
+
+ /* Create temporary or join file */
+
+ if (backup)
+ VOID(fn_format(org_name,isam_file->filename,"",MI_NAME_DEXT,2));
+ else
+ VOID(fn_format(org_name,isam_file->filename,"",MI_NAME_DEXT,2+4+16));
+ if (!test_only && result_table)
+ {
+ /* Make a new indexfile based on first file in list */
+ uint length;
+ char *buff;
+ strmov(org_name,result_table); /* Fix error messages */
+ VOID(fn_format(new_name,result_table,"",MI_NAME_IEXT,2));
+ if ((join_isam_file=my_create(new_name,0,tmpfile_createflag,MYF(MY_WME)))
+ < 0)
+ goto err;
+ length=(uint) share->base.keystart;
+ if (!(buff=my_malloc(length,MYF(MY_WME))))
+ goto err;
+ if (my_pread(share->kfile,buff,length,0L,MYF(MY_WME | MY_NABP)) ||
+ my_write(join_isam_file,buff,length,
+ MYF(MY_WME | MY_NABP | MY_WAIT_IF_FULL)))
+ {
+ my_free(buff,MYF(0));
+ goto err;
+ }
+ my_free(buff,MYF(0));
+ VOID(fn_format(new_name,result_table,"",MI_NAME_DEXT,2));
+ }
+ else if (!tmp_dir[0])
+ VOID(make_new_name(new_name,org_name));
+ else
+ VOID(fn_format(new_name,org_name,tmp_dir,DATA_TMP_EXT,1+2+4));
+ if (!test_only &&
+ (new_file=my_create(new_name,0,tmpfile_createflag,MYF(MY_WME))) < 0)
+ goto err;
+
+ /* Start calculating statistics */
+
+ mrg->records=0;
+ for (i=0 ; i < mrg->count ; i++)
+ mrg->records+=mrg->file[i]->s->state.state.records;
+ if (write_loop || verbose)
+ {
+ printf("Compressing %s: (%lu records)\n",
+ result_table ? new_name : org_name,(ulong) mrg->records);
+ }
+ trees=fields=share->base.fields;
+ huff_counts=init_huff_count(isam_file,mrg->records);
+ QUICK_SAFEMALLOC;
+ if (write_loop || verbose)
+ printf("- Calculating statistics\n");
+ if (get_statistic(mrg,huff_counts))
+ goto err;
+ NORMAL_SAFEMALLOC;
+ old_length=0;
+ for (i=0; i < mrg->count ; i++)
+ old_length+= (mrg->file[i]->s->state.state.data_file_length -
+ mrg->file[i]->s->state.state.empty);
+
+ if (init_queue(&queue,256,0,0,compare_huff_elements,0))
+ goto err;
+ check_counts(huff_counts,fields,mrg->records);
+ huff_trees=make_huff_trees(huff_counts,trees);
+ if ((int) (used_trees=join_same_trees(huff_counts,trees)) < 0)
+ goto err;
+ if (make_huff_decode_table(huff_trees,fields))
+ goto err;
+
+ init_file_buffer(new_file,0);
+ file_buffer.pos_in_file=HEAD_LENGTH;
+ if (! test_only)
+ VOID(my_seek(new_file,file_buffer.pos_in_file,MY_SEEK_SET,MYF(0)));
+
+ write_field_info(huff_counts,fields,used_trees);
+ if (!(tot_elements=write_huff_tree(huff_trees,trees)))
+ goto err;
+ header_length=(uint) file_buffer.pos_in_file+
+ (uint) (file_buffer.pos-file_buffer.buffer);
+
+ /* Compress file */
+ if (write_loop || verbose)
+ printf("- Compressing file\n");
+ error=compress_isam_file(mrg,huff_counts);
+ new_length=file_buffer.pos_in_file;
+ if (!error && !test_only)
+ {
+ char buff[MEMMAP_EXTRA_MARGIN]; /* End marginal for memmap */
+ bzero(buff,sizeof(buff));
+ error=my_write(file_buffer.file,buff,sizeof(buff),
+ MYF(MY_WME | MY_NABP | MY_WAIT_IF_FULL)) != 0;
+ }
+ if (!error)
+ error=write_header(mrg,header_length,used_trees,tot_elements,
+ new_length);
+ end_file_buffer();
+
+ if (verbose && mrg->records)
+ printf("Min record length: %6d Max length: %6d Mean total length: %6ld\n",
+ mrg->min_pack_length,mrg->max_pack_length,
+ (ulong) (new_length/mrg->records));
+
+ if (!test_only)
+ {
+ error|=my_close(new_file,MYF(MY_WME));
+ if (!result_table)
+ {
+ error|=my_close(isam_file->dfile,MYF(MY_WME));
+ isam_file->dfile= -1; /* Tell mi_close file is closed */
+ }
+ }
+
+ free_counts_and_tree_and_queue(huff_trees,trees,huff_counts,fields);
+ if (! test_only && ! error)
+ {
+ if (result_table)
+ {
+ error=save_state_mrg(join_isam_file,mrg,new_length,glob_crc);
+ }
+ else
+ {
+ if (backup)
+ {
+ if (my_rename(org_name,make_old_name(temp_name,isam_file->filename),
+ MYF(MY_WME)))
+ error=1;
+ else
+ {
+ if (tmp_dir[0])
+ {
+ if (!(error=my_copy(new_name,org_name,MYF(MY_WME))))
+ VOID(my_delete(new_name,MYF(MY_WME)));
+ }
+ else
+ error=my_rename(new_name,org_name,MYF(MY_WME));
+ if (!error)
+ VOID(my_copystat(temp_name,org_name,MYF(MY_COPYTIME)));
+ }
+ }
+ else
+ {
+ if (tmp_dir[0])
+ {
+
+ if (!(error=my_copy(new_name,org_name,
+ MYF(MY_WME | MY_HOLD_ORIGINAL_MODES
+ | MY_COPYTIME))))
+ VOID(my_delete(new_name,MYF(MY_WME)));
+ }
+ else
+ error=my_redel(org_name,new_name,MYF(MY_WME | MY_COPYTIME));
+ }
+ if (! error)
+ error=save_state(isam_file,mrg,new_length,glob_crc);
+ }
+ }
+ error|=mrg_close(mrg);
+ if (join_isam_file >= 0)
+ error|=my_close(join_isam_file,MYF(MY_WME));
+ if (error)
+ {
+ VOID(fprintf(stderr,"Aborting: %s is not compressed\n",org_name));
+ DBUG_RETURN(-1);
+ }
+ if (write_loop || verbose)
+ {
+ if (old_length)
+ printf("%.4g%% \n", (((longlong) (old_length -new_length))*100.0/
+ (longlong) old_length));
+ else
+ puts("Empty file saved in compressed format");
+ }
+ DBUG_RETURN(0);
+
+ err:
+ free_counts_and_tree_and_queue(huff_trees,trees,huff_counts,fields);
+ if (new_file >= 0)
+ VOID(my_close(new_file,MYF(0)));
+ if (join_isam_file >= 0)
+ VOID(my_close(join_isam_file,MYF(0)));
+ mrg_close(mrg);
+ VOID(fprintf(stderr,"Aborted: %s is not compressed\n",org_name));
+ DBUG_RETURN(-1);
+}
+
+ /* Init a huff_count-struct for each field and init it */
+
+static HUFF_COUNTS *init_huff_count(MI_INFO *info,my_off_t records)
+{
+ reg2 uint i;
+ reg1 HUFF_COUNTS *count;
+ if ((count = (HUFF_COUNTS*) my_malloc(info->s->base.fields*
+ sizeof(HUFF_COUNTS),
+ MYF(MY_ZEROFILL | MY_WME))))
+ {
+ for (i=0 ; i < info->s->base.fields ; i++)
+ {
+ enum en_fieldtype type;
+ count[i].field_length=info->s->rec[i].length;
+ type= count[i].field_type= (enum en_fieldtype) info->s->rec[i].type;
+ if (type == FIELD_INTERVALL ||
+ type == FIELD_CONSTANT ||
+ type == FIELD_ZERO)
+ type = FIELD_NORMAL;
+ if (count[i].field_length <= 8 &&
+ (type == FIELD_NORMAL ||
+ type == FIELD_SKIPP_ZERO))
+ count[i].max_zero_fill= count[i].field_length;
+ init_tree(&count[i].int_tree,0,-1,(qsort_cmp) compare_tree,0,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,
+ MYF(MY_WME));
+ }
+ }
+ return count;
+}
+
+
+ /* Free memory used by counts and trees */
+
+static void free_counts_and_tree_and_queue(HUFF_TREE *huff_trees, uint trees,
+ HUFF_COUNTS *huff_counts,
+ uint fields)
+{
+ register uint i;
+
+ if (huff_trees)
+ {
+ for (i=0 ; i < trees ; i++)
+ {
+ if (huff_trees[i].element_buffer)
+ my_free((gptr) huff_trees[i].element_buffer,MYF(0));
+ if (huff_trees[i].code)
+ my_free((gptr) huff_trees[i].code,MYF(0));
+ }
+ my_free((gptr) huff_trees,MYF(0));
+ }
+ if (huff_counts)
+ {
+ for (i=0 ; i < fields ; i++)
+ {
+ if (huff_counts[i].tree_buff)
+ {
+ my_free((gptr) huff_counts[i].tree_buff,MYF(0));
+ delete_tree(&huff_counts[i].int_tree);
+ }
+ }
+ my_free((gptr) huff_counts,MYF(0));
+ }
+ delete_queue(&queue); /* This is safe to free */
+ return;
+}
+
+ /* Read through old file and gather some statistics */
+
+static int get_statistic(MRG_INFO *mrg,HUFF_COUNTS *huff_counts)
+{
+ int error;
+ uint length;
+ ulong reclength,max_blob_length;
+ byte *record,*pos,*next_pos,*end_pos,*start_pos;
+ ha_rows record_count;
+ my_bool static_row_size;
+ HUFF_COUNTS *count,*end_count;
+ TREE_ELEMENT *element;
+ DBUG_ENTER("get_statistic");
+
+ reclength=mrg->file[0]->s->base.reclength;
+ record=(byte*) my_alloca(reclength);
+ end_count=huff_counts+mrg->file[0]->s->base.fields;
+ record_count=0; glob_crc=0;
+ max_blob_length=0;
+
+ /* Check how to calculate checksum */
+ static_row_size=1;
+ for (count=huff_counts ; count < end_count ; count++)
+ {
+ if (count->field_type == FIELD_BLOB || count->field_type == FIELD_VARCHAR)
+ {
+ static_row_size=0;
+ break;
+ }
+ }
+
+ mrg_reset(mrg);
+ while ((error=mrg_rrnd(mrg,record)) != HA_ERR_END_OF_FILE)
+ {
+ ulong tot_blob_length=0;
+ if (! error)
+ {
+ if (static_row_size)
+ glob_crc+=mi_static_checksum(mrg->file[0],record);
+ else
+ glob_crc+=mi_checksum(mrg->file[0],record);
+ for (pos=record,count=huff_counts ;
+ count < end_count ;
+ count++,
+ pos=next_pos)
+ {
+ next_pos=end_pos=(start_pos=pos)+count->field_length;
+
+ /* Put value in tree if there is room for it */
+ if (count->tree_buff)
+ {
+ global_count=count;
+ if (!(element=tree_insert(&count->int_tree,pos,0)) ||
+ (element->count == 1 &&
+ count->tree_buff + tree_buff_length <
+ count->tree_pos + count->field_length) ||
+ (count->field_length == 1 &&
+ count->int_tree.elements_in_tree > 1))
+ {
+ delete_tree(&count->int_tree);
+ my_free(count->tree_buff,MYF(0));
+ count->tree_buff=0;
+ }
+ else
+ {
+ if (element->count == 1)
+ { /* New element */
+ memcpy(count->tree_pos,pos,(size_t) count->field_length);
+ tree_set_pointer(element,count->tree_pos);
+ count->tree_pos+=count->field_length;
+ }
+ }
+ }
+
+ /* Save character counters and space-counts and zero-field-counts */
+ if (count->field_type == FIELD_NORMAL ||
+ count->field_type == FIELD_SKIPP_ENDSPACE)
+ {
+ for ( ; end_pos > pos ; end_pos--)
+ if (end_pos[-1] != ' ')
+ break;
+ if (end_pos == pos)
+ {
+ count->empty_fields++;
+ count->max_zero_fill=0;
+ continue;
+ }
+ length= (uint) (next_pos-end_pos);
+ count->tot_end_space+=length;
+ if (length < 8)
+ count->end_space[length]++;
+ if (count->max_end_space < length)
+ count->max_end_space = length;
+ }
+ if (count->field_type == FIELD_NORMAL ||
+ count->field_type == FIELD_SKIPP_PRESPACE)
+ {
+ for (pos=start_pos; pos < end_pos ; pos++)
+ if (pos[0] != ' ')
+ break;
+ if (end_pos == pos)
+ {
+ count->empty_fields++;
+ count->max_zero_fill=0;
+ continue;
+ }
+ length= (uint) (pos-start_pos);
+ count->tot_pre_space+=length;
+ if (length < 8)
+ count->pre_space[length]++;
+ if (count->max_pre_space < length)
+ count->max_pre_space = length;
+ }
+ if (count->field_type == FIELD_BLOB)
+ {
+ uint field_length=count->field_length -mi_portable_sizeof_char_ptr;
+ ulong blob_length= _mi_calc_blob_length(field_length, start_pos);
+ memcpy_fixed((char*) &pos, start_pos+field_length,sizeof(char*));
+ end_pos=pos+blob_length;
+ tot_blob_length+=blob_length;
+ set_if_bigger(count->max_length,blob_length);
+ }
+ else if (count->field_type == FIELD_VARCHAR)
+ {
+ length=uint2korr(start_pos);
+ pos=start_pos+2;
+ end_pos=start_pos+length;
+ set_if_bigger(count->max_length,length);
+ }
+ if (count->field_length <= 8 &&
+ (count->field_type == FIELD_NORMAL ||
+ count->field_type == FIELD_SKIPP_ZERO))
+ {
+ uint i;
+ if (!memcmp((byte*) start_pos,zero_string,count->field_length))
+ {
+ count->zero_fields++;
+ continue;
+ }
+ for (i =0 ; i < count->max_zero_fill && ! end_pos[-1 - (int) i] ;
+ i++) ;
+ if (i < count->max_zero_fill)
+ count->max_zero_fill=i;
+ }
+ if (count->field_type == FIELD_ZERO ||
+ count->field_type == FIELD_CHECK)
+ continue;
+ for ( ; pos < end_pos ; pos++)
+ count->counts[(uchar) *pos]++;
+ }
+ if (tot_blob_length > max_blob_length)
+ max_blob_length=tot_blob_length;
+ record_count++;
+ if (write_loop && record_count % WRITE_COUNT == 0)
+ {
+ printf("%lu\r",(ulong) record_count); VOID(fflush(stdout));
+ }
+ }
+ else if (error != HA_ERR_RECORD_DELETED)
+ {
+ fprintf(stderr,"Got error %d while reading rows",error);
+ break;
+ }
+ }
+ if (write_loop)
+ {
+ printf(" \r"); VOID(fflush(stdout));
+ }
+ mrg->records=record_count;
+ mrg->max_blob_length=max_blob_length;
+ my_afree((gptr) record);
+ DBUG_RETURN(error != HA_ERR_END_OF_FILE);
+}
+
+static int compare_huff_elements(void *not_used, byte *a, byte *b)
+{
+ return *((my_off_t*) a) < *((my_off_t*) b) ? -1 :
+ (*((my_off_t*) a) == *((my_off_t*) b) ? 0 : 1);
+}
+
+ /* Check each tree if we should use pre-space-compress, end-space-
+ compress, empty-field-compress or zero-field-compress */
+
+static void check_counts(HUFF_COUNTS *huff_counts, uint trees,
+ my_off_t records)
+{
+ uint space_fields,fill_zero_fields,field_count[(int) FIELD_VARCHAR+1];
+ my_off_t old_length,new_length,length;
+ DBUG_ENTER("check_counts");
+
+ bzero((gptr) field_count,sizeof(field_count));
+ space_fields=fill_zero_fields=0;
+
+ for (; trees-- ; huff_counts++)
+ {
+ if (huff_counts->field_type == FIELD_BLOB)
+ {
+ huff_counts->length_bits=max_bit(huff_counts->max_length);
+ goto found_pack;
+ }
+ else if (huff_counts->field_type == FIELD_VARCHAR)
+ {
+ huff_counts->length_bits=max_bit(huff_counts->max_length);
+ goto found_pack;
+ }
+ else if (huff_counts->field_type == FIELD_CHECK)
+ {
+ huff_counts->bytes_packed=0;
+ huff_counts->counts[0]=0;
+ goto found_pack;
+ }
+
+ huff_counts->field_type=FIELD_NORMAL;
+ huff_counts->pack_type=0;
+
+ if (huff_counts->zero_fields || ! records)
+ {
+ my_off_t old_space_count;
+ if (huff_counts->zero_fields == records)
+ {
+ huff_counts->field_type= FIELD_ZERO;
+ huff_counts->bytes_packed=0;
+ huff_counts->counts[0]=0;
+ goto found_pack;
+ }
+ old_space_count=huff_counts->counts[' '];
+ huff_counts->counts[' ']+=huff_counts->tot_end_space+
+ huff_counts->tot_pre_space +
+ huff_counts->empty_fields * huff_counts->field_length;
+ old_length=calc_packed_length(huff_counts,0)+records/8;
+ length=huff_counts->zero_fields*huff_counts->field_length;
+ huff_counts->counts[0]+=length;
+ new_length=calc_packed_length(huff_counts,0);
+ if (old_length < new_length && huff_counts->field_length > 1)
+ {
+ huff_counts->field_type=FIELD_SKIPP_ZERO;
+ huff_counts->counts[0]-=length;
+ huff_counts->bytes_packed=old_length- records/8;
+ goto found_pack;
+ }
+ huff_counts->counts[' ']=old_space_count;
+ }
+ huff_counts->bytes_packed=calc_packed_length(huff_counts,0);
+ if (huff_counts->empty_fields)
+ {
+ if (huff_counts->field_length > 2 &&
+ huff_counts->empty_fields + (records - huff_counts->empty_fields)*
+ (1+max_bit(max(huff_counts->max_pre_space,
+ huff_counts->max_end_space))) <
+ records * max_bit(huff_counts->field_length))
+ {
+ huff_counts->pack_type |= PACK_TYPE_SPACE_FIELDS;
+ }
+ else
+ {
+ length=huff_counts->empty_fields*huff_counts->field_length;
+ if (huff_counts->tot_end_space || ! huff_counts->tot_pre_space)
+ {
+ huff_counts->tot_end_space+=length;
+ huff_counts->max_end_space=huff_counts->field_length;
+ if (huff_counts->field_length < 8)
+ huff_counts->end_space[huff_counts->field_length]+=
+ huff_counts->empty_fields;
+ }
+ else
+ {
+ huff_counts->tot_pre_space+=length;
+ huff_counts->max_pre_space=huff_counts->field_length;
+ if (huff_counts->field_length < 8)
+ huff_counts->pre_space[huff_counts->field_length]+=
+ huff_counts->empty_fields;
+ }
+ }
+ }
+ if (huff_counts->tot_end_space)
+ {
+ huff_counts->counts[' ']+=huff_counts->tot_pre_space;
+ if (test_space_compress(huff_counts,records,huff_counts->max_end_space,
+ huff_counts->end_space,
+ huff_counts->tot_end_space,FIELD_SKIPP_ENDSPACE))
+ goto found_pack;
+ huff_counts->counts[' ']-=huff_counts->tot_pre_space;
+ }
+ if (huff_counts->tot_pre_space)
+ {
+ if (test_space_compress(huff_counts,records,huff_counts->max_pre_space,
+ huff_counts->pre_space,
+ huff_counts->tot_pre_space,FIELD_SKIPP_PRESPACE))
+ goto found_pack;
+ }
+
+ found_pack: /* Found field-packing */
+
+ /* Test if we can use zero-fill */
+
+ if (huff_counts->max_zero_fill &&
+ (huff_counts->field_type == FIELD_NORMAL ||
+ huff_counts->field_type == FIELD_SKIPP_ZERO))
+ {
+ huff_counts->counts[0]-=huff_counts->max_zero_fill*
+ (huff_counts->field_type == FIELD_SKIPP_ZERO ?
+ records - huff_counts->zero_fields : records);
+ huff_counts->pack_type|=PACK_TYPE_ZERO_FILL;
+ huff_counts->bytes_packed=calc_packed_length(huff_counts,0);
+ }
+
+ /* Test if intervall-field is better */
+
+ if (huff_counts->tree_buff)
+ {
+ HUFF_TREE tree;
+
+ tree.element_buffer=0;
+ if (!make_huff_tree(&tree,huff_counts) &&
+ tree.bytes_packed+tree.tree_pack_length < huff_counts->bytes_packed)
+ {
+ if (tree.elements == 1)
+ huff_counts->field_type=FIELD_CONSTANT;
+ else
+ huff_counts->field_type=FIELD_INTERVALL;
+ huff_counts->pack_type=0;
+ }
+ else
+ {
+ my_free((gptr) huff_counts->tree_buff,MYF(0));
+ delete_tree(&huff_counts->int_tree);
+ huff_counts->tree_buff=0;
+ }
+ if (tree.element_buffer)
+ my_free((gptr) tree.element_buffer,MYF(0));
+ }
+ if (huff_counts->pack_type & PACK_TYPE_SPACE_FIELDS)
+ space_fields++;
+ if (huff_counts->pack_type & PACK_TYPE_ZERO_FILL)
+ fill_zero_fields++;
+ field_count[huff_counts->field_type]++;
+ }
+ if (verbose)
+ printf("\nnormal: %3d empty-space: %3d empty-zero: %3d empty-fill: %3d\npre-space: %3d end-space: %3d 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_INTERVALL],
+ field_count[FIELD_ZERO]);
+ DBUG_VOID_RETURN;
+}
+
+ /* Test if we can use space-compression and empty-field-compression */
+
+static int
+test_space_compress(HUFF_COUNTS *huff_counts, my_off_t records,
+ uint max_space_length, my_off_t *space_counts,
+ my_off_t tot_space_count, enum en_fieldtype field_type)
+{
+ int min_pos;
+ uint length_bits,i;
+ my_off_t space_count,min_space_count,min_pack,new_length,skipp;
+
+ length_bits=max_bit(max_space_length);
+
+ /* Default no end_space-packing */
+ space_count=huff_counts->counts[(uint) ' '];
+ min_space_count= (huff_counts->counts[(uint) ' ']+= tot_space_count);
+ min_pack=calc_packed_length(huff_counts,0);
+ min_pos= -2;
+ huff_counts->counts[(uint) ' ']=space_count;
+
+ /* Test with allways space-count */
+ new_length=huff_counts->bytes_packed+length_bits*records/8;
+ if (new_length+1 < min_pack)
+ {
+ min_pos= -1;
+ min_pack=new_length;
+ min_space_count=space_count;
+ }
+ /* Test with length-flag */
+ for (skipp=0L, i=0 ; i < 8 ; i++)
+ {
+ if (space_counts[i])
+ {
+ if (i)
+ huff_counts->counts[(uint) ' ']+=space_counts[i];
+ skipp+=huff_counts->pre_space[i];
+ new_length=calc_packed_length(huff_counts,0)+
+ (records+(records-skipp)*(1+length_bits))/8;
+ if (new_length < min_pack)
+ {
+ min_pos=(int) i;
+ min_pack=new_length;
+ min_space_count=huff_counts->counts[(uint) ' '];
+ }
+ }
+ }
+
+ huff_counts->counts[(uint) ' ']=min_space_count;
+ huff_counts->bytes_packed=min_pack;
+ switch (min_pos) {
+ case -2:
+ return(0); /* No space-compress */
+ case -1: /* Always space-count */
+ huff_counts->field_type=field_type;
+ huff_counts->min_space=0;
+ huff_counts->length_bits=max_bit(max_space_length);
+ break;
+ default:
+ huff_counts->field_type=field_type;
+ huff_counts->min_space=(uint) min_pos;
+ huff_counts->pack_type|=PACK_TYPE_SELECTED;
+ huff_counts->length_bits=max_bit(max_space_length);
+ break;
+ }
+ return(1); /* Using space-compress */
+}
+
+
+ /* Make a huff_tree of each huff_count */
+
+static HUFF_TREE* make_huff_trees(HUFF_COUNTS *huff_counts, uint trees)
+{
+ uint tree;
+ HUFF_TREE *huff_tree;
+ DBUG_ENTER("make_huff_trees");
+
+ if (!(huff_tree=(HUFF_TREE*) my_malloc(trees*sizeof(HUFF_TREE),
+ MYF(MY_WME | MY_ZEROFILL))))
+ DBUG_RETURN(0);
+
+ for (tree=0 ; tree < trees ; tree++)
+ {
+ if (make_huff_tree(huff_tree+tree,huff_counts+tree))
+ {
+ while (tree--)
+ my_free((gptr) huff_tree[tree].element_buffer,MYF(0));
+ my_free((gptr) huff_tree,MYF(0));
+ DBUG_RETURN(0);
+ }
+ }
+ DBUG_RETURN(huff_tree);
+}
+
+ /* Update huff_tree according to huff_counts->counts or
+ huff_counts->tree_buff */
+
+static int make_huff_tree(HUFF_TREE *huff_tree, HUFF_COUNTS *huff_counts)
+{
+ uint i,found,bits_packed,first,last;
+ my_off_t bytes_packed;
+ HUFF_ELEMENT *a,*b,*new;
+
+ first=last=0;
+ if (huff_counts->tree_buff)
+ {
+ found= (uint) (huff_counts->tree_pos - huff_counts->tree_buff) /
+ huff_counts->field_length;
+ first=0; last=found-1;
+ }
+ else
+ {
+ for (i=found=0 ; i < 256 ; i++)
+ {
+ if (huff_counts->counts[i])
+ {
+ if (! found++)
+ first=i;
+ last=i;
+ }
+ }
+ if (found < 2)
+ found=2;
+ }
+
+ if (queue.max_elements < found)
+ {
+ delete_queue(&queue);
+ if (init_queue(&queue,found,0,0,compare_huff_elements,0))
+ return -1;
+ }
+
+ if (!huff_tree->element_buffer)
+ {
+ if (!(huff_tree->element_buffer=
+ (HUFF_ELEMENT*) my_malloc(found*2*sizeof(HUFF_ELEMENT),MYF(MY_WME))))
+ return 1;
+ }
+ else
+ {
+ HUFF_ELEMENT *temp;
+ if (!(temp=
+ (HUFF_ELEMENT*) my_realloc((gptr) huff_tree->element_buffer,
+ found*2*sizeof(HUFF_ELEMENT),
+ MYF(MY_WME))))
+ return 1;
+ huff_tree->element_buffer=temp;
+ }
+
+ huff_counts->tree=huff_tree;
+ huff_tree->counts=huff_counts;
+ huff_tree->min_chr=first;
+ huff_tree->max_chr=last;
+ huff_tree->char_bits=max_bit(last-first);
+ huff_tree->offset_bits=max_bit(found-1)+1;
+
+ if (huff_counts->tree_buff)
+ {
+ huff_tree->elements=0;
+ tree_walk(&huff_counts->int_tree,
+ (int (*)(void*, element_count,void*)) save_counts_in_queue,
+ (gptr) huff_tree, left_root_right);
+ huff_tree->tree_pack_length=(1+15+16+5+5+
+ (huff_tree->char_bits+1)*found+
+ (huff_tree->offset_bits+1)*
+ (found-2)+7)/8 +
+ (uint) (huff_tree->counts->tree_pos-
+ huff_tree->counts->tree_buff);
+ }
+ else
+ {
+ huff_tree->elements=found;
+ huff_tree->tree_pack_length=(9+9+5+5+
+ (huff_tree->char_bits+1)*found+
+ (huff_tree->offset_bits+1)*
+ (found-2)+7)/8;
+
+ for (i=first, found=0 ; i <= last ; i++)
+ {
+ if (huff_counts->counts[i])
+ {
+ new=huff_tree->element_buffer+(found++);
+ new->count=huff_counts->counts[i];
+ new->a.leaf.null=0;
+ new->a.leaf.element_nr=i;
+ queue.root[found]=(byte*) new;
+ }
+ }
+ while (found < 2)
+ { /* Our huff_trees request at least 2 elements */
+ new=huff_tree->element_buffer+(found++);
+ new->count=0;
+ new->a.leaf.null=0;
+ if (last)
+ new->a.leaf.element_nr=huff_tree->min_chr=last-1;
+ else
+ new->a.leaf.element_nr=huff_tree->max_chr=last+1;
+ queue.root[found]=(byte*) new;
+ }
+ }
+ queue.elements=found;
+
+ for (i=found/2 ; i > 0 ; i--)
+ _downheap(&queue,i);
+ bytes_packed=0; bits_packed=0;
+ for (i=1 ; i < found ; i++)
+ {
+ a=(HUFF_ELEMENT*) queue_remove(&queue,0);
+ b=(HUFF_ELEMENT*) queue.root[1];
+ new=huff_tree->element_buffer+found+i;
+ new->count=a->count+b->count;
+ bits_packed+=(uint) (new->count & 7);
+ bytes_packed+=new->count/8;
+ new->a.nod.left=a; /* lesser in left */
+ new->a.nod.right=b;
+ queue.root[1]=(byte*) new;
+ queue_replaced(&queue);
+ }
+ huff_tree->root=(HUFF_ELEMENT*) queue.root[1];
+ huff_tree->bytes_packed=bytes_packed+(bits_packed+7)/8;
+ return 0;
+}
+
+static int compare_tree(register const uchar *s, register const uchar *t)
+{
+ uint length;
+ for (length=global_count->field_length; length-- ;)
+ if (*s++ != *t++)
+ return (int) s[-1] - (int) t[-1];
+ return 0;
+}
+
+ /* Used by make_huff_tree to save intervall-counts in queue */
+
+static int save_counts_in_queue(byte *key, element_count count,
+ HUFF_TREE *tree)
+{
+ HUFF_ELEMENT *new;
+
+ new=tree->element_buffer+(tree->elements++);
+ new->count=count;
+ new->a.leaf.null=0;
+ new->a.leaf.element_nr= (uint) (key- tree->counts->tree_buff) /
+ tree->counts->field_length;
+ queue.root[tree->elements]=(byte*) new;
+ return 0;
+}
+
+
+ /* Calculate length of file if given counts should be used */
+ /* Its actually a faster version of make_huff_tree */
+
+static my_off_t calc_packed_length(HUFF_COUNTS *huff_counts,
+ uint add_tree_lenght)
+{
+ uint i,found,bits_packed,first,last;
+ my_off_t bytes_packed;
+ HUFF_ELEMENT element_buffer[256];
+ DBUG_ENTER("calc_packed_length");
+
+ first=last=0;
+ for (i=found=0 ; i < 256 ; i++)
+ {
+ if (huff_counts->counts[i])
+ {
+ if (! found++)
+ first=i;
+ last=i;
+ queue.root[found]=(byte*) &huff_counts->counts[i];
+ }
+ }
+ if (!found)
+ DBUG_RETURN(0); /* Empty tree */
+ if (found < 2)
+ queue.root[++found]=(byte*) &huff_counts->counts[last ? 0 : 1];
+
+ queue.elements=found;
+
+ bytes_packed=0; bits_packed=0;
+ if (add_tree_lenght)
+ bytes_packed=(8+9+5+5+(max_bit(last-first)+1)*found+
+ (max_bit(found-1)+1+1)*(found-2) +7)/8;
+ for (i=(found+1)/2 ; i > 0 ; i--)
+ _downheap(&queue,i);
+ for (i=0 ; i < found-1 ; i++)
+ {
+ HUFF_ELEMENT *a,*b,*new;
+ a=(HUFF_ELEMENT*) queue_remove(&queue,0);
+ b=(HUFF_ELEMENT*) queue.root[1];
+ new=element_buffer+i;
+ new->count=a->count+b->count;
+ bits_packed+=(uint) (new->count & 7);
+ bytes_packed+=new->count/8;
+ queue.root[1]=(byte*) new;
+ queue_replaced(&queue);
+ }
+ DBUG_RETURN(bytes_packed+(bits_packed+7)/8);
+}
+
+
+ /* Remove trees that don't give any compression */
+
+static uint join_same_trees(HUFF_COUNTS *huff_counts, uint trees)
+{
+ uint k,tree_number;
+ HUFF_COUNTS count,*i,*j,*last_count;
+
+ last_count=huff_counts+trees;
+ for (tree_number=0, i=huff_counts ; i < last_count ; i++)
+ {
+ if (!i->tree->tree_number)
+ {
+ i->tree->tree_number= ++tree_number;
+ if (i->tree_buff)
+ continue; /* Don't join intervall */
+ for (j=i+1 ; j < last_count ; j++)
+ {
+ if (! j->tree->tree_number && ! j->tree_buff)
+ {
+ for (k=0 ; k < 256 ; k++)
+ count.counts[k]=i->counts[k]+j->counts[k];
+ if (calc_packed_length(&count,1) <=
+ i->tree->bytes_packed + j->tree->bytes_packed+
+ i->tree->tree_pack_length+j->tree->tree_pack_length+
+ ALLOWED_JOIN_DIFF)
+ {
+ memcpy_fixed((byte*) i->counts,(byte*) count.counts,
+ sizeof(count.counts[0])*256);
+ my_free((gptr) j->tree->element_buffer,MYF(0));
+ j->tree->element_buffer=0;
+ j->tree=i->tree;
+ bmove((byte*) i->counts,(byte*) count.counts,
+ sizeof(count.counts[0])*256);
+ if (make_huff_tree(i->tree,i))
+ return (uint) -1;
+ }
+ }
+ }
+ }
+ }
+ if (verbose)
+ printf("Original trees: %d After join: %d\n",trees,tree_number);
+ return tree_number; /* Return trees left */
+}
+
+
+ /* Fill in huff_tree decode tables */
+
+static int make_huff_decode_table(HUFF_TREE *huff_tree, uint trees)
+{
+ uint elements;
+ for ( ; trees-- ; huff_tree++)
+ {
+ if (huff_tree->tree_number > 0)
+ {
+ elements=huff_tree->counts->tree_buff ? huff_tree->elements : 256;
+ if (!(huff_tree->code =
+ (ulong*) my_malloc(elements*
+ (sizeof(ulong)+sizeof(uchar)),
+ MYF(MY_WME | MY_ZEROFILL))))
+ return 1;
+ huff_tree->code_len=(uchar*) (huff_tree->code+elements);
+ make_traverse_code_tree(huff_tree,huff_tree->root,32,0);
+ }
+ }
+ return 0;
+}
+
+
+static void make_traverse_code_tree(HUFF_TREE *huff_tree,
+ HUFF_ELEMENT *element,
+ uint size, ulong code)
+{
+ uint chr;
+ if (!element->a.leaf.null)
+ {
+ chr=element->a.leaf.element_nr;
+ huff_tree->code_len[chr]=(uchar) (32-size);
+ huff_tree->code[chr]= (code >> size);
+ if (huff_tree->height < 32-size)
+ huff_tree->height= 32-size;
+ }
+ else
+ {
+ size--;
+ make_traverse_code_tree(huff_tree,element->a.nod.left,size,code);
+ make_traverse_code_tree(huff_tree,element->a.nod.right,size,
+ code+((ulong) 1L << size));
+ }
+ return;
+}
+
+
+ /* Write header to new packed data file */
+
+static int write_header(MRG_INFO *mrg,uint head_length,uint trees,
+ my_off_t tot_elements,my_off_t filelength)
+{
+ byte *buff=file_buffer.pos;
+
+ bzero(buff,HEAD_LENGTH);
+ memcpy_fixed(buff,myisam_pack_file_magic,4);
+ int4store(buff+4,head_length);
+ int4store(buff+8, mrg->min_pack_length);
+ int4store(buff+12,mrg->max_pack_length);
+ int4store(buff+16,tot_elements);
+ int4store(buff+20,intervall_length);
+ int2store(buff+24,trees);
+ buff[26]=(char) mrg->ref_length;
+ /* Save record pointer length */
+ buff[27]= (uchar) mi_get_pointer_length((ulonglong) filelength,2);
+ if (test_only)
+ return 0;
+ VOID(my_seek(file_buffer.file,0L,MY_SEEK_SET,MYF(0)));
+ return my_write(file_buffer.file,file_buffer.pos,HEAD_LENGTH,
+ MYF(MY_WME | MY_NABP | MY_WAIT_IF_FULL)) != 0;
+}
+
+ /* Write fieldinfo to new packed file */
+
+static void write_field_info(HUFF_COUNTS *counts, uint fields, uint trees)
+{
+ reg1 uint i;
+ uint huff_tree_bits;
+ huff_tree_bits=max_bit(trees ? trees-1 : 0);
+
+ for (i=0 ; i++ < fields ; counts++)
+ {
+ write_bits((ulong) (int) counts->field_type,5);
+ write_bits(counts->pack_type,6);
+ if (counts->pack_type & PACK_TYPE_ZERO_FILL)
+ write_bits(counts->max_zero_fill,5);
+ else
+ write_bits(counts->length_bits,5);
+ write_bits((ulong) counts->tree->tree_number-1,huff_tree_bits);
+ }
+ flush_bits();
+ return;
+}
+
+ /* Write all huff_trees to new datafile. Return tot count of
+ elements in all trees
+ Returns 0 on error */
+
+static my_off_t write_huff_tree(HUFF_TREE *huff_tree, uint trees)
+{
+ uint i,int_length;
+ uint *packed_tree,*offset,length;
+ my_off_t elements;
+
+ for (i=length=0 ; i < trees ; i++)
+ if (huff_tree[i].tree_number > 0 && huff_tree[i].elements > length)
+ length=huff_tree[i].elements;
+ if (!(packed_tree=(uint*) my_alloca(sizeof(uint)*length*2)))
+ {
+ my_error(EE_OUTOFMEMORY,MYF(ME_BELL),sizeof(uint)*length*2);
+ return 0;
+ }
+
+ intervall_length=0;
+ for (elements=0; trees-- ; huff_tree++)
+ {
+ if (huff_tree->tree_number == 0)
+ continue; /* Deleted tree */
+ elements+=huff_tree->elements;
+ huff_tree->max_offset=2;
+ if (huff_tree->elements <= 1)
+ offset=packed_tree;
+ else
+ offset=make_offset_code_tree(huff_tree,huff_tree->root,packed_tree);
+ huff_tree->offset_bits=max_bit(huff_tree->max_offset);
+ if (huff_tree->max_offset >= IS_OFFSET)
+ { /* This should be impossible */
+ VOID(fprintf(stderr,"Tree offset got too big: %d, aborted\n",
+ huff_tree->max_offset));
+ my_afree((gptr) packed_tree);
+ return 0;
+ }
+
+#ifdef EXTRA_DBUG
+ printf("pos: %d elements: %d tree-elements: %d char_bits: %d\n",
+ (uint) (file_buffer.pos-file_buffer.buffer),
+ huff_tree->elements, (offset-packed_tree),huff_tree->char_bits);
+#endif
+ if (!huff_tree->counts->tree_buff)
+ {
+ write_bits(0,1);
+ write_bits(huff_tree->min_chr,8);
+ write_bits(huff_tree->elements,9);
+ write_bits(huff_tree->char_bits,5);
+ write_bits(huff_tree->offset_bits,5);
+ int_length=0;
+ }
+ else
+ {
+ int_length=(uint) (huff_tree->counts->tree_pos -
+ huff_tree->counts->tree_buff);
+ write_bits(1,1);
+ write_bits(huff_tree->elements,15);
+ write_bits(int_length,16);
+ write_bits(huff_tree->char_bits,5);
+ write_bits(huff_tree->offset_bits,5);
+ intervall_length+=int_length;
+ }
+ length=(uint) (offset-packed_tree);
+ if (length != huff_tree->elements*2-2)
+ printf("error: Huff-tree-length: %d != calc_length: %d\n",
+ length,huff_tree->elements*2-2);
+
+ for (i=0 ; i < length ; i++)
+ {
+ if (packed_tree[i] & IS_OFFSET)
+ write_bits(packed_tree[i] - IS_OFFSET+ (1 << huff_tree->offset_bits),
+ huff_tree->offset_bits+1);
+ else
+ write_bits(packed_tree[i]-huff_tree->min_chr,huff_tree->char_bits+1);
+ }
+ flush_bits();
+ if (huff_tree->counts->tree_buff)
+ {
+ for (i=0 ; i < int_length ; i++)
+ write_bits((uint) (uchar) huff_tree->counts->tree_buff[i],8);
+ }
+ flush_bits();
+ }
+ my_afree((gptr) packed_tree);
+ return elements;
+}
+
+
+static uint *make_offset_code_tree(HUFF_TREE *huff_tree, HUFF_ELEMENT *element,
+ uint *offset)
+{
+ uint *prev_offset;
+
+ prev_offset= offset;
+ if (!element->a.nod.left->a.leaf.null)
+ {
+ offset[0] =(uint) element->a.nod.left->a.leaf.element_nr;
+ offset+=2;
+ }
+ else
+ {
+ prev_offset[0]= IS_OFFSET+2;
+ offset=make_offset_code_tree(huff_tree,element->a.nod.left,offset+2);
+ }
+ if (!element->a.nod.right->a.leaf.null)
+ {
+ prev_offset[1]=element->a.nod.right->a.leaf.element_nr;
+ return offset;
+ }
+ else
+ {
+ uint temp=(uint) (offset-prev_offset-1);
+ prev_offset[1]= IS_OFFSET+ temp;
+ if (huff_tree->max_offset < temp)
+ huff_tree->max_offset = temp;
+ return make_offset_code_tree(huff_tree,element->a.nod.right,offset);
+ }
+}
+
+ /* Get number of bits neaded to represent value */
+
+static uint max_bit(register uint value)
+{
+ reg2 uint power=1;
+
+ while ((value>>=1))
+ power++;
+ return (power);
+}
+
+
+static int compress_isam_file(MRG_INFO *mrg, HUFF_COUNTS *huff_counts)
+{
+ int error;
+ uint i,max_calc_length,pack_ref_length,min_record_length,max_record_length,
+ intervall,field_length,max_pack_length,pack_blob_length;
+ my_off_t record_count;
+ ulong length,pack_length;
+ byte *record,*pos,*end_pos,*record_pos,*start_pos;
+ HUFF_COUNTS *count,*end_count;
+ HUFF_TREE *tree;
+ MI_INFO *isam_file=mrg->file[0];
+ DBUG_ENTER("compress_isam_file");
+
+ if (!(record=(byte*) my_alloca(isam_file->s->base.reclength)))
+ return -1;
+ end_count=huff_counts+isam_file->s->base.fields;
+ min_record_length= (uint) ~0;
+ max_record_length=0;
+
+ for (i=max_calc_length=0 ; i < isam_file->s->base.fields ; i++)
+ {
+ if (!(huff_counts[i].pack_type & PACK_TYPE_ZERO_FILL))
+ huff_counts[i].max_zero_fill=0;
+ if (huff_counts[i].field_type == FIELD_CONSTANT ||
+ huff_counts[i].field_type == FIELD_ZERO ||
+ huff_counts[i].field_type == FIELD_CHECK)
+ continue;
+ if (huff_counts[i].field_type == FIELD_INTERVALL)
+ max_calc_length+=huff_counts[i].tree->height;
+ else if (huff_counts[i].field_type == FIELD_BLOB ||
+ huff_counts[i].field_type == FIELD_VARCHAR)
+ max_calc_length=huff_counts[i].tree->height*huff_counts[i].max_length + huff_counts[i].length_bits +1;
+ else
+ max_calc_length+=
+ (huff_counts[i].field_length - huff_counts[i].max_zero_fill)*
+ huff_counts[i].tree->height+huff_counts[i].length_bits;
+ }
+ max_calc_length/=8;
+ if (max_calc_length < 254)
+ pack_ref_length=1;
+ else if (max_calc_length <= 65535)
+ pack_ref_length=3;
+ else
+ pack_ref_length=4;
+ record_count=0;
+ pack_blob_length=0;
+ if (isam_file->s->base.blobs)
+ {
+ if (mrg->max_blob_length < 254)
+ pack_blob_length=1;
+ else if (mrg->max_blob_length <= 65535)
+ pack_blob_length=3;
+ else
+ pack_blob_length=4;
+ }
+ max_pack_length=pack_ref_length+pack_blob_length;
+
+ mrg_reset(mrg);
+ while ((error=mrg_rrnd(mrg,record)) != HA_ERR_END_OF_FILE)
+ {
+ ulong tot_blob_length=0;
+ if (! error)
+ {
+ if (flush_buffer(max_calc_length+max_pack_length))
+ break;
+ record_pos=file_buffer.pos;
+ file_buffer.pos+=max_pack_length;
+ for (start_pos=record, count= huff_counts; count < end_count ; count++)
+ {
+ end_pos=start_pos+(field_length=count->field_length);
+ tree=count->tree;
+
+ if (count->pack_type & PACK_TYPE_SPACE_FIELDS)
+ {
+ for (pos=start_pos ; *pos == ' ' && pos < end_pos; pos++) ;
+ if (pos == end_pos)
+ {
+ write_bits(1,1);
+ start_pos=end_pos;
+ continue;
+ }
+ write_bits(0,1);
+ }
+ end_pos-=count->max_zero_fill;
+ field_length-=count->max_zero_fill;
+
+ switch(count->field_type) {
+ case FIELD_SKIPP_ZERO:
+ if (!memcmp((byte*) start_pos,zero_string,field_length))
+ {
+ write_bits(1,1);
+ start_pos=end_pos;
+ break;
+ }
+ write_bits(0,1);
+ /* Fall through */
+ case FIELD_NORMAL:
+ for ( ; start_pos < end_pos ; start_pos++)
+ write_bits(tree->code[(uchar) *start_pos],
+ (uint) tree->code_len[(uchar) *start_pos]);
+ break;
+ case FIELD_SKIPP_ENDSPACE:
+ for (pos=end_pos ; pos > start_pos && pos[-1] == ' ' ; pos--) ;
+ length=(uint) (end_pos-pos);
+ if (count->pack_type & PACK_TYPE_SELECTED)
+ {
+ if (length > count->min_space)
+ {
+ write_bits(1,1);
+ write_bits(length,count->length_bits);
+ }
+ else
+ {
+ write_bits(0,1);
+ pos=end_pos;
+ }
+ }
+ else
+ write_bits(length,count->length_bits);
+ for ( ; start_pos < pos ; start_pos++)
+ write_bits(tree->code[(uchar) *start_pos],
+ (uint) tree->code_len[(uchar) *start_pos]);
+ start_pos=end_pos;
+ break;
+ case FIELD_SKIPP_PRESPACE:
+ for (pos=start_pos ; pos < end_pos && pos[0] == ' ' ; pos++) ;
+ length=(uint) (pos-start_pos);
+ if (count->pack_type & PACK_TYPE_SELECTED)
+ {
+ if (length > count->min_space)
+ {
+ write_bits(1,1);
+ write_bits(length,count->length_bits);
+ }
+ else
+ {
+ pos=start_pos;
+ write_bits(0,1);
+ }
+ }
+ else
+ write_bits(length,count->length_bits);
+ for (start_pos=pos ; start_pos < end_pos ; start_pos++)
+ write_bits(tree->code[(uchar) *start_pos],
+ (uint) tree->code_len[(uchar) *start_pos]);
+ break;
+ case FIELD_CONSTANT:
+ case FIELD_ZERO:
+ case FIELD_CHECK:
+ start_pos=end_pos;
+ break;
+ case FIELD_INTERVALL:
+ global_count=count;
+ pos=(byte*) tree_search(&count->int_tree,start_pos);
+ intervall=(uint) (pos - count->tree_buff)/field_length;
+ write_bits(tree->code[intervall],(uint) tree->code_len[intervall]);
+ start_pos=end_pos;
+ break;
+ case FIELD_BLOB:
+ {
+ ulong blob_length=_mi_calc_blob_length(field_length-
+ mi_portable_sizeof_char_ptr,
+ start_pos);
+ if (!blob_length)
+ {
+ write_bits(1,1); /* Empty blob */
+ }
+ else
+ {
+ byte *blob,*blob_end;
+ write_bits(0,1);
+ write_bits(blob_length,count->length_bits);
+ memcpy_fixed(&blob,end_pos-mi_portable_sizeof_char_ptr,
+ sizeof(char*));
+ blob_end=blob+blob_length;
+ for ( ; blob < blob_end ; blob++)
+ write_bits(tree->code[(uchar) *blob],
+ (uint) tree->code_len[(uchar) *blob]);
+ tot_blob_length+=blob_length;
+ }
+ start_pos= end_pos;
+ break;
+ }
+ case FIELD_VARCHAR:
+ {
+ ulong col_length= uint2korr(start_pos);
+ if (!col_length)
+ {
+ write_bits(1,1); /* Empty varchar */
+ }
+ else
+ {
+ byte *end=start_pos+2+col_length;
+ write_bits(0,1);
+ write_bits(col_length,count->length_bits);
+ for (start_pos+=2 ; start_pos < end ; start_pos++)
+ write_bits(tree->code[(uchar) *start_pos],
+ (uint) tree->code_len[(uchar) *start_pos]);
+ }
+ start_pos= end_pos;
+ break;
+ }
+ case FIELD_LAST:
+ abort(); /* Impossible */
+ }
+ start_pos+=count->max_zero_fill;
+ }
+ flush_bits();
+ length=(ulong) (file_buffer.pos-record_pos)-max_pack_length;
+ pack_length=save_pack_length(record_pos,length);
+ if (pack_blob_length)
+ pack_length+=save_pack_length(record_pos+pack_length,tot_blob_length);
+
+ /* Correct file buffer if the header was smaller */
+ if (pack_length != max_pack_length)
+ {
+ bmove(record_pos+pack_length,record_pos+max_pack_length,length);
+ file_buffer.pos-= (max_pack_length-pack_length);
+ }
+ if (length < (ulong) min_record_length)
+ min_record_length=(uint) length;
+ if (length > (ulong) max_record_length)
+ max_record_length=(uint) length;
+ if (write_loop && ++record_count % WRITE_COUNT == 0)
+ {
+ printf("%lu\r",(ulong) record_count); VOID(fflush(stdout));
+ }
+ }
+ else if (error != HA_ERR_RECORD_DELETED)
+ break;
+ }
+ if (error == HA_ERR_END_OF_FILE)
+ error=0;
+ else
+ {
+ fprintf(stderr,"%s: Got error %d reading records\n",my_progname,error);
+ }
+
+ my_afree((gptr) record);
+ mrg->ref_length=max_pack_length;
+ mrg->min_pack_length=max_record_length ? min_record_length : 0;
+ mrg->max_pack_length=max_record_length;
+ DBUG_RETURN(error || error_on_write || flush_buffer(~(ulong) 0));
+}
+
+
+static char *make_new_name(char *new_name, char *old_name)
+{
+ return fn_format(new_name,old_name,"",DATA_TMP_EXT,2+4);
+}
+
+static char *make_old_name(char *new_name, char *old_name)
+{
+ return fn_format(new_name,old_name,"",OLD_EXT,2+4);
+}
+
+ /* rutines for bit writing buffer */
+
+static void init_file_buffer(File file, pbool read_buffer)
+{
+ file_buffer.file=file;
+ file_buffer.buffer=my_malloc(ALIGN_SIZE(RECORD_CACHE_SIZE),MYF(MY_WME));
+ file_buffer.end=file_buffer.buffer+ALIGN_SIZE(RECORD_CACHE_SIZE)-8;
+ file_buffer.pos_in_file=0;
+ error_on_write=0;
+ if (read_buffer)
+ {
+
+ file_buffer.pos=file_buffer.end;
+ file_buffer.bits=0;
+ }
+ else
+ {
+ file_buffer.pos=file_buffer.buffer;
+ file_buffer.bits=BITS_SAVED;
+ }
+ file_buffer.byte=0;
+}
+
+
+static int flush_buffer(ulong neaded_length)
+{
+ ulong length;
+ if ((ulong) (file_buffer.end - file_buffer.pos) > neaded_length)
+ return 0;
+ length=(ulong) (file_buffer.pos-file_buffer.buffer);
+ file_buffer.pos=file_buffer.buffer;
+ file_buffer.pos_in_file+=length;
+ if (test_only)
+ return 0;
+ if (error_on_write|| my_write(file_buffer.file,file_buffer.buffer,
+ length,
+ MYF(MY_WME | MY_NABP | MY_WAIT_IF_FULL)))
+ {
+ error_on_write=1;
+ return 1;
+ }
+
+ if (neaded_length != ~(ulong) 0 &&
+ (ulong) (file_buffer.end-file_buffer.buffer) < neaded_length)
+ {
+ char *tmp;
+ neaded_length+=256; /* some margin */
+ tmp=my_realloc(file_buffer.buffer, neaded_length,MYF(MY_WME));
+ if (!tmp)
+ return 1;
+ file_buffer.pos= tmp + (ulong) (file_buffer.pos - file_buffer.buffer);
+ file_buffer.buffer=tmp;
+ file_buffer.end=tmp+neaded_length-8;
+ }
+ return 0;
+}
+
+
+static void end_file_buffer(void)
+{
+ my_free((gptr) file_buffer.buffer,MYF(0));
+}
+
+ /* output `bits` low bits of `value' */
+
+static void write_bits (register ulong value, register uint bits)
+{
+ if ((file_buffer.bits-=(int) bits) >= 0)
+ {
+ file_buffer.byte|=value << file_buffer.bits;
+ }
+ else
+ {
+ reg3 uint byte_buff;
+ bits= (uint) -file_buffer.bits;
+ byte_buff=file_buffer.byte | (uint) (value >> bits);
+#if BITS_SAVED == 32
+ *file_buffer.pos++= (byte) (byte_buff >> 24) ;
+ *file_buffer.pos++= (byte) (byte_buff >> 16) ;
+#endif
+ *file_buffer.pos++= (byte) (byte_buff >> 8) ;
+ *file_buffer.pos++= (byte) byte_buff;
+
+ value&=(1 << bits)-1;
+#if BITS_SAVED == 16
+ if (bits >= sizeof(uint))
+ {
+ bits-=8;
+ *file_buffer.pos++= (uchar) (value >> bits);
+ value&= (1 << bits)-1;
+ if (bits >= sizeof(uint))
+ {
+ bits-=8;
+ *file_buffer.pos++= (uchar) (value >> bits);
+ value&= (1 << bits)-1;
+ }
+ }
+#endif
+ if (file_buffer.pos >= file_buffer.end)
+ VOID(flush_buffer((uint) ~0));
+ file_buffer.bits=(int) (BITS_SAVED - bits);
+ file_buffer.byte=(uint) (value << (BITS_SAVED - bits));
+ }
+ return;
+}
+
+ /* Flush bits in bit_buffer to buffer */
+
+static void flush_bits (void)
+{
+ uint bits,byte_buff;
+
+ bits=(file_buffer.bits) & ~7;
+ byte_buff = file_buffer.byte >> bits;
+ bits=BITS_SAVED - bits;
+ while (bits > 0)
+ {
+ bits-=8;
+ *file_buffer.pos++= (byte) (uchar) (byte_buff >> bits) ;
+ }
+ file_buffer.bits=BITS_SAVED;
+ file_buffer.byte=0;
+ return;
+}
+
+
+/****************************************************************************
+** functions to handle the joined files
+****************************************************************************/
+
+static int save_state(MI_INFO *isam_file,MRG_INFO *mrg,my_off_t new_length,
+ ha_checksum crc)
+{
+ MYISAM_SHARE *share=isam_file->s;
+ uint options=mi_uint2korr(share->state.header.options);
+ uint key;
+ DBUG_ENTER("save_state");
+
+ options|= HA_OPTION_COMPRESS_RECORD | HA_OPTION_READ_ONLY_DATA;
+ mi_int2store(share->state.header.options,options);
+
+ share->state.state.data_file_length=new_length;
+ share->state.state.del=0;
+ share->state.state.empty=0;
+ share->state.dellink= HA_OFFSET_ERROR;
+ share->state.split=(ha_rows) mrg->records;
+ share->state.version=(ulong) time((time_t*) 0);
+ share->state.key_map=0;
+ share->state.state.key_file_length=share->base.keystart;
+ for (key=0 ; key < share->base.keys ; key++)
+ share->state.key_root[key]= HA_OFFSET_ERROR;
+ for (key=0 ; key < share->state.header.max_block_size ; key++)
+ share->state.key_del[key]= HA_OFFSET_ERROR;
+ share->state.checksum=crc; /* Save crc here */
+ share->changed=1; /* Force write of header */
+ share->state.open_count=0;
+ share->global_changed=0;
+ VOID(my_chsize(share->kfile,share->state.state.key_file_length,
+ MYF(0)));
+ if (share->base.keys)
+ isamchk_neaded=1;
+ DBUG_RETURN(mi_state_info_write(share->kfile,&share->state,1+2));
+}
+
+
+static int save_state_mrg(File file,MRG_INFO *mrg,my_off_t new_length,
+ ha_checksum crc)
+{
+ MI_STATE_INFO state;
+ MI_INFO *isam_file=mrg->file[0];
+ uint options;
+ DBUG_ENTER("save_state_mrg");
+
+ state= isam_file->s->state;
+ options= (mi_uint2korr(state.header.options) | HA_OPTION_COMPRESS_RECORD |
+ HA_OPTION_READ_ONLY_DATA);
+ mi_int2store(state.header.options,options);
+ state.state.data_file_length=new_length;
+ state.state.del=0;
+ state.state.empty=0;
+ state.state.records=state.split=(ha_rows) mrg->records;
+ state.state.key_file_length=isam_file->s->base.keystart;
+ state.dellink= HA_OFFSET_ERROR;
+ state.version=(ulong) time((time_t*) 0);
+ state.key_map=0;
+ state.checksum=crc;
+ if (isam_file->s->base.keys)
+ isamchk_neaded=1;
+ state.changed=1; /* Force one check of table */
+ DBUG_RETURN (mi_state_info_write(file,&state,1+2));
+}
+
+
+/* reset for mrg_rrnd */
+
+static void mrg_reset(MRG_INFO *mrg)
+{
+ if (mrg->current)
+ {
+ mi_extra(*mrg->current,HA_EXTRA_NO_CACHE);
+ mrg->current=0;
+ }
+}
+
+static int mrg_rrnd(MRG_INFO *info,byte *buf)
+{
+ int error;
+ MI_INFO *isam_info;
+ my_off_t filepos;
+
+ if (!info->current)
+ {
+ isam_info= *(info->current=info->file);
+ info->end=info->current+info->count;
+ mi_extra(isam_info,HA_EXTRA_CACHE);
+ mi_extra(isam_info,HA_EXTRA_RESET);
+ filepos=isam_info->s->pack.header_length;
+ }
+ else
+ {
+ isam_info= *info->current;
+ filepos= isam_info->nextpos;
+ }
+
+ for (;;)
+ {
+ isam_info->update&= HA_STATE_CHANGED;
+ if (!(error=(*isam_info->s->read_rnd)(isam_info,(byte*) buf,
+ filepos, 1)) ||
+ error != HA_ERR_END_OF_FILE)
+ return (error);
+ mi_extra(isam_info,HA_EXTRA_NO_CACHE);
+ if (info->current+1 == info->end)
+ return(HA_ERR_END_OF_FILE);
+ info->current++;
+ isam_info= *info->current;
+ filepos=isam_info->s->pack.header_length;
+ mi_extra(isam_info,HA_EXTRA_CACHE);
+ mi_extra(isam_info,HA_EXTRA_RESET);
+ }
+}
+
+
+static int mrg_close(MRG_INFO *mrg)
+{
+ uint i;
+ int error=0;
+ for (i=0 ; i < mrg->count ; i++)
+ error|=mi_close(mrg->file[i]);
+ if (mrg->free_file)
+ my_free((gptr) mrg->file,MYF(0));
+ return error;
+}
diff --git a/myisam/sort.c b/myisam/sort.c
new file mode 100644
index 00000000000..0a5b575242f
--- /dev/null
+++ b/myisam/sort.c
@@ -0,0 +1,531 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/*
+ Creates a index for a database by reading keys, sorting them and outputing
+ them in sorted order through SORT_INFO functions.
+*/
+
+#include "myisamdef.h"
+#if defined(MSDOS) || defined(__WIN__)
+#include <fcntl.h>
+#else
+#include <stddef.h>
+#endif
+#include <queues.h>
+
+ /* static variabels */
+
+#define MERGEBUFF 15
+#define MERGEBUFF2 31
+#define MIN_SORT_MEMORY (4096-MALLOC_OVERHEAD)
+#define MYF_RW MYF(MY_NABP | MY_WME | MY_WAIT_IF_FULL)
+
+typedef struct st_buffpek {
+ my_off_t file_pos; /* position to buffer */
+ ha_rows count; /* keys in buffer */
+ uchar *base,*key; /* Pekare inom sort_key - indexdel */
+ uint mem_count; /* keys left in memory */
+ uint max_keys; /* Max keys in buffert */
+} BUFFPEK;
+
+extern void print_error _VARARGS((const char *fmt,...));
+
+ /* functions defined in this file */
+
+static ha_rows NEAR_F find_all_keys(MI_SORT_PARAM *info,uint keys,
+ uchar * *sort_keys,
+ BUFFPEK *buffpek,int *maxbuffer,
+ FILE **tempfile, my_string tempname);
+static int NEAR_F write_keys(MI_SORT_PARAM *info,uchar * *sort_keys,
+ uint count, BUFFPEK *buffpek,FILE **tempfile,
+ my_string tempname);
+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,
+ uchar * *sort_keys,
+ BUFFPEK *buffpek,int *maxbuffer,
+ FILE * *t_file, my_string tempname);
+static uint NEAR_F read_to_buffer(FILE *fromfile,BUFFPEK *buffpek,
+ uint sort_length);
+static int NEAR_F merge_buffers(MI_SORT_PARAM *info,uint keys,FILE *from_file,
+ FILE *to_file, uchar * *sort_keys,
+ BUFFPEK *lastbuff,BUFFPEK *Fb,
+ BUFFPEK *Tb);
+static int NEAR_F merge_index(MI_SORT_PARAM *,uint,uchar **,BUFFPEK *, int,
+ FILE *);
+static char **make_char_array(uint fields,uint length,myf my_flag);
+static FILE *opentemp(my_string name,const char *temp_dir);
+static void closetemp(my_string name,FILE *stream);
+
+
+ /* Creates a index of sorted keys */
+ /* Returns 0 if everything went ok */
+
+int _create_index_by_sort(MI_SORT_PARAM *info,my_bool no_messages,
+ ulong sortbuff_size)
+{
+ int error,maxbuffer,skr;
+ uint memavl,old_memavl,keys,sort_length;
+ BUFFPEK *buffpek;
+ char tempname[FN_REFLEN];
+ ha_rows records;
+ uchar **sort_keys;
+ FILE *tempfile;
+ DBUG_ENTER("_create_index_by_sort");
+ DBUG_PRINT("enter",("sort_length: %d", info->key_length));
+
+ tempfile=0; buffpek= (BUFFPEK *) NULL; sort_keys= (uchar **) NULL; error= 1;
+ maxbuffer=1;
+
+ memavl=max(sortbuff_size,MIN_SORT_MEMORY);
+ records= info->max_records;
+ sort_length= info->key_length;
+ LINT_INIT(keys);
+
+ while (memavl >= MIN_SORT_MEMORY)
+ {
+ if ((my_off_t) (records+1)*(sort_length+sizeof(char*)) <=
+ (my_off_t) memavl)
+ keys= records+1;
+ else
+ do
+ {
+ skr=maxbuffer;
+ if (memavl < sizeof(BUFFPEK)*(uint) maxbuffer ||
+ (keys=(memavl-sizeof(BUFFPEK)*(uint) maxbuffer)/
+ (sort_length+sizeof(char*))) <= 1)
+ {
+ mi_check_print_error(info->sort_info->param,
+ "sort_buffer_size is to small");
+ goto err;
+ }
+ }
+ while ((maxbuffer= (int) (records/(keys-1)+1)) != skr);
+
+ if ((sort_keys= (uchar **) make_char_array(keys,sort_length,MYF(0))))
+ {
+ if ((buffpek = (BUFFPEK*) my_malloc((uint) (sizeof(BUFFPEK)*
+ (uint) maxbuffer),
+ MYF(0))))
+ break;
+ else
+ my_free((gptr) sort_keys,MYF(0));
+ }
+ old_memavl=memavl;
+ if ((memavl=memavl/4*3) < MIN_SORT_MEMORY && old_memavl > MIN_SORT_MEMORY)
+ memavl=MIN_SORT_MEMORY;
+ }
+ if (memavl < MIN_SORT_MEMORY)
+ {
+ mi_check_print_error(info->sort_info->param,"Sort buffer to small");
+ goto err;
+ }
+ (*info->lock_in_memory)(info->sort_info->param);/* Everything is allocated */
+
+ if (!no_messages)
+ printf(" - Searching for keys, allocating buffer for %d keys\n",keys);
+
+ if ((records=find_all_keys(info,keys,sort_keys,buffpek,&maxbuffer,&tempfile,
+ tempname))
+ == HA_POS_ERROR)
+ goto err;
+ if (maxbuffer == 0)
+ {
+ if (!no_messages)
+ printf(" - Dumping %lu keys\n",records);
+ if (write_index(info,sort_keys,(uint) records))
+ goto err;
+ }
+ else
+ {
+ keys=(keys*(sort_length+sizeof(char*)))/sort_length;
+ if (maxbuffer >= MERGEBUFF2)
+ {
+ if (!no_messages)
+ printf(" - Merging %lu keys\n",records);
+ if (merge_many_buff(info,keys,sort_keys,buffpek,&maxbuffer,&tempfile,
+ tempname))
+ goto err;
+ }
+ if (!no_messages)
+ puts(" - Last merge and dumping keys");
+ if (merge_index(info,keys,sort_keys,buffpek,maxbuffer,tempfile))
+ goto err;
+ }
+ error =0;
+
+err:
+ if (sort_keys)
+ my_free((gptr) sort_keys,MYF(0));
+ if (buffpek)
+ my_free((gptr) buffpek,MYF(0));
+ if (tempfile)
+ closetemp(tempname,tempfile);
+
+ DBUG_RETURN(error ? -1 : 0);
+} /* _create_index_by_sort */
+
+
+ /* Search after all keys and place them in a temp. file */
+
+static ha_rows NEAR_F find_all_keys(MI_SORT_PARAM *info, uint keys,
+ uchar **sort_keys, BUFFPEK *buffpek,
+ int *maxbuffer, FILE **tempfile,
+ my_string tempname)
+{
+ int error;
+ uint idx,indexpos;
+ DBUG_ENTER("find_all_keys");
+
+ idx=indexpos=error=0;
+
+ while (!(error=(*info->key_read)(info->sort_info,sort_keys[idx])))
+ {
+ if ((uint) ++idx == keys)
+ {
+ if (indexpos >= (uint) *maxbuffer ||
+ write_keys(info,sort_keys,idx-1,buffpek+indexpos,tempfile,
+ tempname))
+ DBUG_RETURN((ha_rows) -1);
+ memcpy(sort_keys[0],sort_keys[idx-1],(size_t) info->key_length);
+ idx=1; indexpos++;
+ }
+ }
+ if (error > 0)
+ DBUG_RETURN(HA_POS_ERROR); /* Aborted by get_key */
+ if (indexpos)
+ if (indexpos >= (uint) *maxbuffer ||
+ write_keys(info,sort_keys,idx,buffpek+indexpos,tempfile,tempname))
+ DBUG_RETURN(HA_POS_ERROR);
+ *maxbuffer=(int) indexpos;
+ DBUG_RETURN(indexpos*(keys-1)+idx);
+} /* find_all_keys */
+
+
+ /* Write all keys in memory to file for later merge */
+
+static int NEAR_F write_keys(MI_SORT_PARAM *info, register uchar **sort_keys,
+ uint count, BUFFPEK *buffpek,
+ register FILE **tempfile, my_string tempname)
+{
+ DBUG_ENTER("write_keys");
+
+ qsort2((byte*) sort_keys,count,sizeof(byte*),(qsort2_cmp) info->key_cmp,
+ info->sort_info);
+ if (! *tempfile && ! (*tempfile=opentemp(tempname,info->tmpdir)))
+ DBUG_RETURN(1);
+ buffpek->file_pos=my_ftell(*tempfile,MYF(0));
+ buffpek->count=count;
+ while (count--)
+ if (my_fwrite(*tempfile,(byte*)*sort_keys++,info->key_length,MYF_RW))
+ DBUG_RETURN(1);
+ DBUG_RETURN(0);
+} /* write_keys */
+
+
+ /* Write index */
+
+static int NEAR_F write_index(MI_SORT_PARAM *info, register uchar **sort_keys, register uint count)
+{
+ DBUG_ENTER("write_index");
+
+ qsort2((gptr) sort_keys,(size_t) count,sizeof(byte*),
+ (qsort2_cmp) info->key_cmp,info->sort_info);
+ while (count--)
+ if ((*info->key_write)(info->sort_info,*sort_keys++))
+ DBUG_RETURN(-1);
+ DBUG_RETURN(0);
+} /* write_index */
+
+
+ /* Merge buffers to make < MERGEBUFF2 buffers */
+
+static int NEAR_F merge_many_buff(MI_SORT_PARAM *info, uint keys,
+ uchar **sort_keys, BUFFPEK *buffpek,
+ int *maxbuffer, FILE **t_file,
+ my_string t_name)
+{
+ register int i;
+ FILE *from_file,*to_file,*temp;
+ FILE *t_file2;
+ char t_name2[FN_REFLEN];
+ BUFFPEK *lastbuff;
+ DBUG_ENTER("merge_many_buff");
+
+ if (!(t_file2=opentemp(t_name2,info->tmpdir)))
+ DBUG_RETURN(1);
+
+ from_file= *t_file ; to_file= t_file2;
+ while (*maxbuffer >= MERGEBUFF2)
+ {
+ lastbuff=buffpek;
+ for (i=0 ; i <= *maxbuffer-MERGEBUFF*3/2 ; i+=MERGEBUFF)
+ {
+ if (merge_buffers(info,keys,from_file,to_file,sort_keys,lastbuff++,
+ buffpek+i,buffpek+i+MERGEBUFF-1))
+ break;
+ }
+ if (merge_buffers(info,keys,from_file,to_file,sort_keys,lastbuff++,
+ buffpek+i,buffpek+ *maxbuffer))
+ break;
+ *maxbuffer= (int) (lastbuff-buffpek)-1;
+ temp=from_file; from_file=to_file; to_file=temp;
+ VOID(my_fseek(to_file,0L,MY_SEEK_SET,MYF(0)));
+ }
+ if (to_file == *t_file)
+ {
+ closetemp(t_name,to_file);
+ *t_file=t_file2;
+ VOID(strmov(t_name,t_name2));
+ }
+ else closetemp(t_name2,to_file);
+
+ DBUG_RETURN(*maxbuffer >= MERGEBUFF2); /* Return 1 if interrupted */
+} /* merge_many_buff */
+
+
+ /* Read data to buffer */
+ /* This returns (uint) -1 if something goes wrong */
+
+static uint NEAR_F read_to_buffer(FILE *fromfile, BUFFPEK *buffpek, uint sort_length)
+{
+ register uint count;
+ uint length;
+
+ count=buffpek->max_keys;
+ if ((ha_rows) count > buffpek->count)
+ count=(uint) buffpek->count;
+ if (count)
+ {
+ VOID(my_fseek(fromfile,buffpek->file_pos,MY_SEEK_SET,MYF(0)));
+ if (my_fread(fromfile,(byte*) buffpek->base,
+ (length= sort_length*count),MYF_RW))
+ return((uint) -1);
+ buffpek->key=buffpek->base;
+ buffpek->file_pos+= length; /* New filepos */
+ buffpek->count-= count;
+ buffpek->mem_count= count;
+ }
+ return (count*sort_length);
+} /* read_to_buffer */
+
+
+ /* Merge buffers to one buffer */
+ /* If to_file == 0 then use info->key_write */
+
+static int NEAR_F
+merge_buffers(MI_SORT_PARAM *info, uint keys, FILE *from_file, FILE *to_file,
+ uchar **sort_keys, BUFFPEK *lastbuff, BUFFPEK *Fb, BUFFPEK *Tb)
+{
+ int error;
+ uint sort_length,maxcount;
+ ha_rows count;
+ my_off_t to_start_filepos;
+ uchar *strpos;
+ BUFFPEK *buffpek,**refpek;
+ QUEUE queue;
+ DBUG_ENTER("merge_buffers");
+
+ count=error=0;
+ maxcount=keys/((uint) (Tb-Fb) +1);
+ sort_length=info->key_length;
+
+ LINT_INIT(to_start_filepos);
+ if (to_file)
+ to_start_filepos=my_ftell(to_file,MYF(0));
+ strpos=(uchar*) sort_keys;
+
+ if (init_queue(&queue,(uint) (Tb-Fb)+1,offsetof(BUFFPEK,key),0,
+ (int (*)(void*, byte *,byte*)) info->key_cmp,
+ (void*) info->sort_info))
+ DBUG_RETURN(1);
+
+ for (buffpek= Fb ; buffpek <= Tb && error != -1 ; buffpek++)
+ {
+ count+= buffpek->count;
+ buffpek->base= strpos;
+ buffpek->max_keys=maxcount;
+ strpos+= (uint) (error=(int) read_to_buffer(from_file,buffpek,
+ sort_length));
+ queue_insert(&queue,(void*) buffpek);
+ }
+ if (error == -1)
+ goto err;
+
+ while (queue.elements > 1)
+ {
+ for (;;)
+ {
+ buffpek=(BUFFPEK*) queue_top(&queue);
+ if (to_file)
+ {
+ if (my_fwrite(to_file,(byte*) buffpek->key,(uint) sort_length,
+ MYF_RW | MY_WAIT_IF_FULL))
+ {
+ error=1; goto err;
+ }
+ }
+ else
+ {
+ if ((*info->key_write)(info->sort_info,(void*) buffpek->key))
+ {
+ error=1; goto err;
+ }
+ }
+ buffpek->key+=sort_length;
+ if (! --buffpek->mem_count)
+ {
+ if (!(error=(int) read_to_buffer(from_file,buffpek,sort_length)))
+ {
+ uchar *base=buffpek->base;
+ uint max_keys=buffpek->max_keys;
+
+ VOID(queue_remove(&queue,0));
+
+ /* Put room used by buffer to use in other buffer */
+ for (refpek= (BUFFPEK**) &queue_top(&queue);
+ refpek <= (BUFFPEK**) &queue_end(&queue);
+ refpek++)
+ {
+ buffpek= *refpek;
+ if (buffpek->base+buffpek->max_keys*sort_length == base)
+ {
+ buffpek->max_keys+=max_keys;
+ break;
+ }
+ else if (base+max_keys*sort_length == buffpek->base)
+ {
+ buffpek->base=base;
+ buffpek->max_keys+=max_keys;
+ break;
+ }
+ }
+ break; /* One buffer have been removed */
+ }
+ }
+ queue_replaced(&queue); /* Top element has been replaced */
+ }
+ }
+ buffpek=(BUFFPEK*) queue_top(&queue);
+ buffpek->base=(uchar *) sort_keys;
+ buffpek->max_keys=keys;
+ do
+ {
+ if (to_file)
+ {
+ if (my_fwrite(to_file,(byte*) buffpek->key,
+ (uint) (sort_length*buffpek->mem_count),
+ MYF_RW | MY_WAIT_IF_FULL))
+ {
+ error=1; goto err;
+ }
+ }
+ else
+ {
+ register uchar *end;
+ strpos= buffpek->key;
+ for (end=strpos+buffpek->mem_count*sort_length;
+ strpos != end ;
+ strpos+=sort_length)
+ {
+ if ((*info->key_write)(info->sort_info,(void*) strpos))
+ {
+ error=1; goto err;
+ }
+ }
+ }
+ }
+ while ((error=(int) read_to_buffer(from_file,buffpek,sort_length)) != -1 &&
+ error != 0);
+
+ lastbuff->count=count;
+ if (to_file)
+ lastbuff->file_pos=to_start_filepos; /* New block starts here */
+err:
+ delete_queue(&queue);
+ DBUG_RETURN(error);
+} /* merge_buffers */
+
+
+ /* Do a merge to output-file (save only positions) */
+
+static int NEAR_F
+merge_index(MI_SORT_PARAM *info, uint keys, uchar **sort_keys,
+ BUFFPEK *buffpek, int maxbuffer, FILE *tempfile)
+{
+ DBUG_ENTER("merge_index");
+ if (merge_buffers(info,keys,tempfile,(FILE*) 0,sort_keys,buffpek,buffpek,
+ buffpek+maxbuffer))
+ DBUG_RETURN(1);
+ DBUG_RETURN(0);
+} /* merge_index */
+
+
+ /* Make a pointer of arrays to keys */
+
+static char **make_char_array(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 */
+
+
+/* Open a temporary file that will be deleted on close */
+
+static FILE *opentemp(my_string name,const char *temp_dir)
+{
+ FILE *stream;
+ reg1 my_string str_pos;
+ DBUG_ENTER("opentemp");
+
+ if (!(str_pos=my_tempnam(temp_dir,"ST",MYF(MY_WME))))
+ DBUG_RETURN(0);
+ VOID(strmov(name,str_pos));
+ (*free)(str_pos); /* Avoid the 'free' macro */
+
+ stream=my_fopen(name,(int) (O_RDWR | FILE_BINARY | O_CREAT | O_TEMPORARY),
+ MYF(MY_WME));
+#if O_TEMPORARY == 0 && !defined(CANT_DELETE_OPEN_FILES)
+ VOID(my_delete(name,MYF(MY_WME | ME_NOINPUT)));
+#endif
+ DBUG_PRINT("exit",("stream: %lx",stream));
+ DBUG_RETURN (stream);
+} /* opentemp */
+
+
+static void closetemp(my_string name __attribute__((unused)), FILE *stream)
+{
+ DBUG_ENTER("closetemp");
+
+ if (stream)
+ VOID(my_fclose(stream,MYF(MY_WME)));
+#if !(O_TEMPORARY == 0 && !defined(CANT_DELETE_OPEN_FILES))
+ if (name)
+ VOID(my_delete(name,MYF(MY_WME)));
+#endif
+ DBUG_VOID_RETURN;
+} /* closetemp */
diff --git a/myisam/test_pack b/myisam/test_pack
new file mode 100755
index 00000000000..0cbeb57ba70
--- /dev/null
+++ b/myisam/test_pack
@@ -0,0 +1,9 @@
+silent="-s"
+suffix=$MACH
+mi_test1$MACH -s ; myisampack$MACH --force -s test1 ; myisamchk$MACH -es test1 ; myisamchk$MACH -rqs test1 ; myisamchk$MACH -es test1 ; myisamchk$MACH -us test1 ; myisamchk$MACH -es test1
+mi_test1$MACH -s -S ; myisampack$MACH --force -s test1 ; myisamchk$MACH -es test1 ; myisamchk$MACH -rqs test1 ; myisamchk$MACH -es test1 ;myisamchk$MACH -us test1 ; myisamchk$MACH -es test1
+mi_test1$MACH -s -b ; myisampack$MACH --force -s test1 ; myisamchk$MACH -es test1 ; myisamchk$MACH -rqs test1 ; myisamchk$MACH -es test1
+mi_test1$MACH -s -w ; myisampack$MACH --force -s test1 ; myisamchk$MACH -es test1 ; myisamchk$MACH -ros test1 ; myisamchk$MACH -es test1
+
+mi_test2$MACH -s -t4 ; myisampack$MACH --force -s test2 ; myisamchk$MACH -es test2 ; myisamchk$MACH -ros test2 ; myisamchk$MACH -es test2 ; myisamchk$MACH -s -u test2 ; myisamchk$MACH -sm test2
+mi_test2$MACH -s -t4 -b -N ; myisampack$MACH --force -s test2 ; myisamchk$MACH -es test2 ; myisamchk$MACH -ros test2 ; myisamchk$MACH -es test2 ; myisamchk$MACH -s -u test2 ; myisamchk$MACH -sm test2
diff --git a/myisammrg/.cvsignore b/myisammrg/.cvsignore
new file mode 100644
index 00000000000..e9955884756
--- /dev/null
+++ b/myisammrg/.cvsignore
@@ -0,0 +1,3 @@
+.deps
+Makefile
+Makefile.in
diff --git a/myisammrg/Makefile.am b/myisammrg/Makefile.am
new file mode 100644
index 00000000000..e51b9b52faf
--- /dev/null
+++ b/myisammrg/Makefile.am
@@ -0,0 +1,31 @@
+# Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+INCLUDES = @MT_INCLUDES@ -I$(srcdir)/../include -I../include
+pkglib_LIBRARIES = libmyisammrg.a
+noinst_HEADERS = mymrgdef.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
+
+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
diff --git a/myisammrg/make-ccc b/myisammrg/make-ccc
new file mode 100755
index 00000000000..a7e3dfc3cdb
--- /dev/null
+++ b/myisammrg/make-ccc
@@ -0,0 +1,3 @@
+ccc -I./../include -I../include -DDBUG_OFF -fast -O3 -c myrg_close.c myrg_create.c myrg_delete.c myrg_extra.c myrg_info.c myrg_locking.c myrg_open.c myrg_panic.c myrg_rrnd.c myrg_rsame.c myrg_static.c myrg_update.c
+rm libmyisammrg.a
+ar -cr libmyisammrg.a myrg_close.o
diff --git a/myisammrg/mymrgdef.h b/myisammrg/mymrgdef.h
new file mode 100644
index 00000000000..794104fd8c8
--- /dev/null
+++ b/myisammrg/mymrgdef.h
@@ -0,0 +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 */
+
+/* This file is included by all myisam-merge files */
+
+#ifndef N_MAXKEY
+#include "../myisam/myisamdef.h"
+#endif
+
+#include "myisammrg.h"
+
+extern LIST *myrg_open_list;
+
+#ifdef THREAD
+extern pthread_mutex_t THR_LOCK_open;
+#endif
diff --git a/myisammrg/myrg_close.c b/myisammrg/myrg_close.c
new file mode 100644
index 00000000000..0b9acd921ae
--- /dev/null
+++ b/myisammrg/myrg_close.c
@@ -0,0 +1,40 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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"
+
+int myrg_close(info)
+register MYRG_INFO *info;
+{
+ int error=0,new_error;
+ MYRG_TABLE *file;
+ DBUG_ENTER("myrg_close");
+
+ for (file=info->open_tables ; file != info->end_table ; file++)
+ if ((new_error=mi_close(file->table)))
+ error=new_error;
+ pthread_mutex_lock(&THR_LOCK_open);
+ myrg_open_list=list_delete(myrg_open_list,&info->open_list);
+ pthread_mutex_unlock(&THR_LOCK_open);
+ my_free((gptr) info,MYF(0));
+ if (error)
+ {
+ DBUG_RETURN(my_errno=error);
+ }
+ DBUG_RETURN(0);
+}
diff --git a/myisammrg/myrg_create.c b/myisammrg/myrg_create.c
new file mode 100644
index 00000000000..e5f5b988d80
--- /dev/null
+++ b/myisammrg/myrg_create.c
@@ -0,0 +1,61 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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"
+
+ /* 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(name,table_names)
+const char *name,**table_names;
+{
+ int save_errno;
+ uint errpos;
+ File file;
+ char buff[FN_REFLEN],*end;
+ DBUG_ENTER("myrg_create");
+
+ errpos=0;
+ if ((file = my_create(fn_format(buff,name,"",MYRG_NAME_EXT,4),0,
+ O_RDWR | O_TRUNC,MYF(MY_WME))) < 0)
+ goto err;
+ errpos=1;
+ if (table_names)
+ for ( ; *table_names ; table_names++)
+ {
+ strmov(buff,*table_names);
+ fn_same(buff,name,4);
+ *(end=strend(buff))='\n';
+ if (my_write(file,*table_names,(uint) (end-buff+1),
+ MYF(MY_WME | MY_NABP)))
+ goto err;
+ }
+ if (my_close(file,MYF(0)))
+ goto err;
+ DBUG_RETURN(0);
+
+err:
+ save_errno=my_errno ? my_errno : -1;
+ switch (errpos) {
+ case 1:
+ VOID(my_close(file,MYF(0)));
+ }
+ DBUG_RETURN(my_errno=save_errno);
+} /* myrg_create */
diff --git a/myisammrg/myrg_delete.c b/myisammrg/myrg_delete.c
new file mode 100644
index 00000000000..a470b4876cf
--- /dev/null
+++ b/myisammrg/myrg_delete.c
@@ -0,0 +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 */
+
+/* Delete last read record */
+
+#include "mymrgdef.h"
+
+int myrg_delete(info,record)
+MYRG_INFO *info;
+const byte *record;
+{
+ if (!info->current_table)
+ {
+ return(my_errno=HA_ERR_NO_ACTIVE_RECORD);
+ }
+ return mi_delete(info->current_table->table,record);
+}
diff --git a/myisammrg/myrg_extra.c b/myisammrg/myrg_extra.c
new file mode 100644
index 00000000000..0927728e2c1
--- /dev/null
+++ b/myisammrg/myrg_extra.c
@@ -0,0 +1,46 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/*
+ Extra functions we want to do with a database
+ - All flags, exept record-cache-flags, are set in all used databases
+ record-cache-flags are set in myrg_rrnd when we are changing database.
+*/
+
+#include "mymrgdef.h"
+
+int myrg_extra(MYRG_INFO *info,enum ha_extra_function function)
+{
+ int error,save_error=0;
+ MYRG_TABLE *file;
+
+ if (function == HA_EXTRA_CACHE)
+ info->cache_in_use=1;
+ else
+ {
+ if (function == HA_EXTRA_NO_CACHE)
+ info->cache_in_use=0;
+ if (function == HA_EXTRA_RESET)
+ {
+ info->current_table=0;
+ info->last_used_table=info->open_tables;
+ }
+ for (file=info->open_tables ; file != info->end_table ; file++)
+ if ((error=mi_extra(file->table,function)))
+ save_error=error;
+ }
+ return save_error;
+}
diff --git a/myisammrg/myrg_info.c b/myisammrg/myrg_info.c
new file mode 100644
index 00000000000..959a34935fd
--- /dev/null
+++ b/myisammrg/myrg_info.c
@@ -0,0 +1,59 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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"
+
+ulonglong myrg_position(MYRG_INFO *info)
+{
+ MYRG_TABLE *current_table;
+
+ if (!(current_table = info->current_table) &&
+ info->open_tables != info->end_table)
+ current_table = info->open_tables;
+ return current_table ?
+ current_table->table->lastpos + current_table->file_offset :
+ ~(ulonglong) 0;
+}
+
+ /* If flag != 0 one only gets pos of last record */
+
+int myrg_status(MYRG_INFO *info,register MYMERGE_INFO *x,int flag)
+{
+ MYRG_TABLE *current_table;
+ DBUG_ENTER("myrg_status");
+
+ if (!(current_table = info->current_table) &&
+ info->open_tables != info->end_table)
+ current_table = info->open_tables;
+ x->recpos = info->current_table ?
+ info->current_table->table->lastpos + info->current_table->file_offset :
+ (ulong) -1L;
+ if (flag != HA_STATUS_POS)
+ {
+ x->records = info->records;
+ x->deleted = info->del;
+ x->data_file_length = info->data_file_length;
+ x->reclength = info->reclength;
+ if (current_table)
+ x->errkey = current_table->table->errkey;
+ else
+ { /* No tables in MRG */
+ x->errkey=0;
+ }
+ x->options = info->options;
+ }
+ DBUG_RETURN(0);
+}
diff --git a/myisammrg/myrg_locking.c b/myisammrg/myrg_locking.c
new file mode 100644
index 00000000000..fc03df9bf63
--- /dev/null
+++ b/myisammrg/myrg_locking.c
@@ -0,0 +1,35 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/*
+ Lock databases against read or write.
+*/
+
+#include "mymrgdef.h"
+
+int myrg_lock_database(info,lock_type)
+MYRG_INFO *info;
+int lock_type;
+{
+ int error,new_error;
+ MYRG_TABLE *file;
+
+ error=0;
+ for (file=info->open_tables ; file != info->end_table ; file++)
+ if ((new_error=mi_lock_database(file->table,lock_type)))
+ error=new_error;
+ return(error);
+}
diff --git a/myisammrg/myrg_open.c b/myisammrg/myrg_open.c
new file mode 100644
index 00000000000..0606e0d7d88
--- /dev/null
+++ b/myisammrg/myrg_open.c
@@ -0,0 +1,139 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 MYMERGE_-database */
+
+#include "mymrgdef.h"
+#include <stddef.h>
+#include <errno.h>
+#ifdef VMS
+#include "mrg_static.c"
+#endif
+
+/* open a MYMERGE_-database.
+
+ if handle_locking is 0 then exit with error if some database is locked
+ if handle_locking is 1 then wait if database is locked
+*/
+
+
+MYRG_INFO *myrg_open(name,mode,handle_locking)
+const char *name;
+int mode;
+int handle_locking;
+{
+ int save_errno,i,errpos;
+ uint files,dir_length;
+ ulonglong file_offset;
+ char name_buff[FN_REFLEN*2],buff[FN_REFLEN],*end;
+ MYRG_INFO info,*m_info;
+ FILE *file;
+ MI_INFO *isam,*last_isam;
+ DBUG_ENTER("myrg_open");
+
+ LINT_INIT(last_isam);
+ isam=0;
+ errpos=files=0;
+ bzero((gptr) &info,sizeof(info));
+ if (!(file=my_fopen(fn_format(name_buff,name,"",MYRG_NAME_EXT,4),
+ O_RDONLY | O_SHARE,MYF(0))))
+ goto err;
+ errpos=1;
+ dir_length=dirname_part(name_buff,name);
+ info.reclength=0;
+ while (fgets(buff,FN_REFLEN-1,file))
+ {
+ if ((end=strend(buff))[-1] == '\n')
+ end[-1]='\0';
+ if (buff[0]) /* Skipp empty lines */
+ {
+ last_isam=isam;
+ if (!test_if_hard_path(buff))
+ {
+ VOID(strmake(name_buff+dir_length,buff,
+ sizeof(name_buff)-1-dir_length));
+ VOID(cleanup_dirname(buff,name_buff));
+ }
+ if (!(isam=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;
+ goto err;
+ }
+ info.reclength=isam->s->base.reclength;
+ }
+ if (!(m_info= (MYRG_INFO*) my_malloc(sizeof(MYRG_INFO)+
+ files*sizeof(MYRG_TABLE),
+ MYF(MY_WME))))
+ goto err;
+ *m_info=info;
+ m_info->open_tables=(MYRG_TABLE *) (m_info+1);
+ m_info->tables=files;
+
+ for (i=files ; i-- > 0 ; )
+ {
+ m_info->open_tables[i].table=isam;
+ m_info->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);
+ }
+ /* Fix fileinfo for easyer debugging (actually set by rrnd) */
+ file_offset=0;
+ for (i=0 ; (uint) i < files ; i++)
+ {
+ m_info->open_tables[i].file_offset=(my_off_t) file_offset;
+ file_offset+=m_info->open_tables[i].table->state->data_file_length;
+ }
+ if (sizeof(my_off_t) == 4 && file_offset > (ulonglong) (ulong) ~0L)
+ {
+ my_errno=HA_ERR_RECORD_FILE_FULL;
+ my_free((char*) m_info,MYF(0));
+ goto err;
+ }
+
+ m_info->end_table=m_info->open_tables+files;
+ m_info->last_used_table=m_info->open_tables;
+
+ VOID(my_fclose(file,MYF(0)));
+ m_info->open_list.data=(void*) m_info;
+ pthread_mutex_lock(&THR_LOCK_open);
+ myrg_open_list=list_add(myrg_open_list,&m_info->open_list);
+ pthread_mutex_unlock(&THR_LOCK_open);
+ DBUG_RETURN(m_info);
+
+err:
+ save_errno=my_errno;
+ switch (errpos) {
+ case 1:
+ VOID(my_fclose(file,MYF(0)));
+ for (i=files ; i-- > 0 ; )
+ {
+ isam=last_isam;
+ if (i)
+ last_isam=(MI_INFO*) (isam->open_list.next->data);
+ mi_close(isam);
+ }
+ }
+ my_errno=save_errno;
+ DBUG_RETURN (NULL);
+}
diff --git a/myisammrg/myrg_panic.c b/myisammrg/myrg_panic.c
new file mode 100644
index 00000000000..8b6169c896b
--- /dev/null
+++ b/myisammrg/myrg_panic.c
@@ -0,0 +1,47 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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"
+
+ /* if flag == HA_PANIC_CLOSE then all misam files are closed */
+ /* if flag == HA_PANIC_WRITE then all misam files are unlocked and
+ all changed data in single user misam is written to file */
+ /* if flag == HA_PANIC_READ then all misam files that was locked when
+ mi_panic(HA_PANIC_WRITE) was done is locked. A mi_readinfo() is
+ done for all single user files to get changes in database */
+
+
+int myrg_panic(flag)
+enum ha_panic_function flag;
+{
+ int error=0;
+ LIST *list_element,*next_open;
+ MYRG_INFO *info;
+ DBUG_ENTER("myrg_panic");
+
+ for (list_element=myrg_open_list ; list_element ; list_element=next_open)
+ {
+ next_open=list_element->next; /* Save if close */
+ info=(MYRG_INFO*) list_element->data;
+ if (flag == HA_PANIC_CLOSE && myrg_close(info))
+ error=my_errno;
+ }
+ if (myrg_open_list && flag != HA_PANIC_CLOSE)
+ DBUG_RETURN(mi_panic(flag));
+ if (error)
+ my_errno=error;
+ DBUG_RETURN(error);
+}
diff --git a/myisammrg/myrg_rrnd.c b/myisammrg/myrg_rrnd.c
new file mode 100644
index 00000000000..2e6b8faaa66
--- /dev/null
+++ b/myisammrg/myrg_rrnd.c
@@ -0,0 +1,110 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/*
+ Read a record with random-access. The position to the record must
+ get by myrg_info(). The next record can be read with pos= -1 */
+
+
+#include "mymrgdef.h"
+
+static MYRG_TABLE *find_table(MYRG_TABLE *start,MYRG_TABLE *end,ulonglong pos);
+
+/*
+ If filepos == HA_OFFSET_ERROR, read next
+ Returns same as mi_rrnd:
+ 0 = Ok.
+ HA_ERR_RECORD_DELETED = Record is deleted.
+ HA_ERR_END_OF_FILE = EOF.
+*/
+
+int myrg_rrnd(MYRG_INFO *info,byte *buf,ulonglong filepos)
+{
+ int error;
+ MI_INFO *isam_info;
+
+ if (filepos == HA_OFFSET_ERROR)
+ {
+ if (!info->current_table)
+ {
+ if (info->open_tables == info->end_table)
+ { /* No tables */
+ return (my_errno=HA_ERR_END_OF_FILE);
+ }
+ isam_info=(info->current_table=info->open_tables)->table;
+ if (info->cache_in_use)
+ mi_extra(isam_info,HA_EXTRA_CACHE);
+ filepos=isam_info->s->pack.header_length;
+ isam_info->lastinx= (uint) -1; /* Can't forward or backward */
+ }
+ else
+ {
+ isam_info=info->current_table->table;
+ filepos= isam_info->nextpos;
+ }
+
+ for (;;)
+ {
+ isam_info->update&= HA_STATE_CHANGED;
+ if ((error=(*isam_info->s->read_rnd)(isam_info,(byte*) buf,
+ (my_off_t) filepos,1)) !=
+ HA_ERR_END_OF_FILE)
+ return (error);
+ if (info->cache_in_use)
+ mi_extra(info->current_table->table,HA_EXTRA_NO_CACHE);
+ if (info->current_table+1 == info->end_table)
+ return(HA_ERR_END_OF_FILE);
+ info->current_table++;
+ info->last_used_table=info->current_table;
+ if (info->cache_in_use)
+ mi_extra(info->current_table->table,HA_EXTRA_CACHE);
+ info->current_table->file_offset=
+ info->current_table[-1].file_offset+
+ info->current_table[-1].table->state->data_file_length;
+
+ isam_info=info->current_table->table;
+ filepos=isam_info->s->pack.header_length;
+ isam_info->lastinx= (uint) -1;
+ }
+ }
+ info->current_table=find_table(info->open_tables,
+ info->last_used_table,filepos);
+ isam_info=info->current_table->table;
+ isam_info->update&= HA_STATE_CHANGED;
+ return ((*isam_info->s->read_rnd)(isam_info,(byte*) buf,
+ (ha_rows) (filepos -
+ info->current_table->file_offset),
+ 0));
+}
+
+
+ /* Find which table to use according to file-pos */
+
+static MYRG_TABLE *find_table(MYRG_TABLE *start, MYRG_TABLE *end,
+ ulonglong pos)
+{
+ MYRG_TABLE *mid;
+
+ while (start != end)
+ {
+ mid=start+((uint) (end-start)+1)/2;
+ if (mid->file_offset > pos)
+ end=mid-1;
+ else
+ start=mid;
+ }
+ return start;
+}
diff --git a/myisammrg/myrg_rsame.c b/myisammrg/myrg_rsame.c
new file mode 100644
index 00000000000..301b96e667b
--- /dev/null
+++ b/myisammrg/myrg_rsame.c
@@ -0,0 +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 */
+
+#include "mymrgdef.h"
+
+int myrg_rsame(MYRG_INFO *info,byte *record,int inx)
+{
+ if (inx) /* not yet used, should be 0 */
+ {
+ return(my_errno=HA_ERR_WRONG_INDEX);
+ }
+ if (!info->current_table)
+ {
+ return(my_errno=HA_ERR_NO_ACTIVE_RECORD);
+ }
+ return mi_rsame(info->current_table->table,record,inx);
+}
diff --git a/myisammrg/myrg_static.c b/myisammrg/myrg_static.c
new file mode 100644
index 00000000000..88eb095382b
--- /dev/null
+++ b/myisammrg/myrg_static.c
@@ -0,0 +1,26 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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
+ a shared library
+*/
+
+#ifndef stdin
+#include "mymrgdef.h"
+#endif
+
+LIST *myrg_open_list=0;
diff --git a/myisammrg/myrg_update.c b/myisammrg/myrg_update.c
new file mode 100644
index 00000000000..b75c6ea6f9b
--- /dev/null
+++ b/myisammrg/myrg_update.c
@@ -0,0 +1,26 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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"
+
+int myrg_update(register MYRG_INFO *info,const byte *oldrec, byte *newrec)
+{
+ if (!info->current_table)
+ return(my_errno=HA_ERR_NO_ACTIVE_RECORD);
+ return mi_update(info->current_table->table,oldrec,newrec);
+}
diff --git a/mysql-test/mybin/mysql-test_install_db b/mysql-test/mybin/mysql-test_install_db
new file mode 100755
index 00000000000..592220f54ff
--- /dev/null
+++ b/mysql-test/mybin/mysql-test_install_db
@@ -0,0 +1,215 @@
+#!/bin/sh
+# Copyright (C) 1997, 1998, 1999 TCX DataKonsult AB & Monty Program KB & Detron HB
+# For a more info consult the file COPYRIGHT distributed with this file
+
+# This scripts creates the privilege tables db, host, user, tables_priv,
+# columns_priv in the mysql database, as well as the func table.
+
+ldata=var/lib
+mdata=$ldata/mysql
+execdir=../sql
+bindir=../client
+
+# Get mysqld/safe_mysqld options from /etc/my.cnf or ~/.my.cnf
+if test -w /
+then
+ conf=@sysconfdir@/my.cnf
+else
+ conf=$HOME/.my.cnf
+fi
+
+if test -f "$conf"
+then
+ if grep "^datadir" $conf >/dev/null
+ then
+ ldata=`grep "^datadir" $conf | sed '.*=[ \t]*//`
+ fi
+ if grep "^execdir" $conf >/dev/null
+ then
+ execdir=`grep "^execdir" $conf | sed '.*=[ \t]*//`
+ fi
+ if grep "^bindir" $conf >/dev/null
+ then
+ bindir=`grep "^bindir" $conf | sed '.*=[ \t]*//`
+ fi
+ if grep "^user" $conf >/dev/null
+ then
+ user=`grep "^user" $conf | sed '.*=[ \t]*//`
+ fi
+fi
+
+if test ! -x $execdir/mysqld
+then
+ echo "I can't find no stinking mysqld!"
+ exit 1
+fi
+
+# On IRIX hostname is in /usr/bsd so add this to the path
+PATH=$PATH:/usr/bsd
+hostname=`hostname` # Install this too in the user table
+
+resolved=127.0.0.1
+
+# Create database directories mysql & test
+if test ! -d $ldata; then mkdir $ldata; chmod 700 $ldata ; fi
+if test ! -d $ldata/mysql; then mkdir $ldata/mysql; chmod 700 $ldata/mysql ; fi
+if test ! -d $ldata/test; then mkdir $ldata/test; chmod 700 $ldata/test ; fi
+if test -w / -a ! -z "$user"; then
+ chown $user $ldata $ldata/mysql $ldata/test;
+fi
+
+# Initialize variables
+c_d="" i_d=""
+c_h="" i_h=""
+c_u="" i_u=""
+c_f="" i_f=""
+c_t="" c_c=""
+
+# Check for old tables
+if test ! -f $mdata/db.frm
+then
+ # mysqld --bootstrap wants one command/line
+ c_d="$c_d CREATE TABLE db ("
+ c_d="$c_d Host char(60) DEFAULT '' NOT NULL,"
+ c_d="$c_d Db char(64) DEFAULT '' NOT NULL,"
+ c_d="$c_d User char(16) DEFAULT '' NOT NULL,"
+ c_d="$c_d Select_priv enum('N','Y') DEFAULT 'N' NOT NULL,"
+ c_d="$c_d Insert_priv enum('N','Y') DEFAULT 'N' NOT NULL,"
+ c_d="$c_d Update_priv enum('N','Y') DEFAULT 'N' NOT NULL,"
+ c_d="$c_d Delete_priv enum('N','Y') DEFAULT 'N' NOT NULL,"
+ c_d="$c_d Create_priv enum('N','Y') DEFAULT 'N' NOT NULL,"
+ c_d="$c_d Drop_priv enum('N','Y') DEFAULT 'N' NOT NULL,"
+ c_d="$c_d Grant_priv enum('N','Y') DEFAULT 'N' NOT NULL,"
+ c_d="$c_d References_priv enum('N','Y') DEFAULT 'N' NOT NULL,"
+ c_d="$c_d Index_priv enum('N','Y') DEFAULT 'N' NOT NULL,"
+ c_d="$c_d Alter_priv enum('N','Y') DEFAULT 'N' NOT NULL,"
+ c_d="$c_d PRIMARY KEY Host (Host,Db,User),"
+ c_d="$c_d KEY User (User)"
+ c_d="$c_d )"
+ c_d="$c_d comment='Database privileges';"
+
+ i_d="INSERT INTO db VALUES ('%','test','','Y','Y','Y','Y','Y','Y','N','Y','Y','Y');
+ INSERT INTO db VALUES ('%','test\_%','','Y','Y','Y','Y','Y','Y','N','Y','Y','Y');"
+fi
+
+if test ! -f $mdata/host.frm
+then
+ c_h="$c_h CREATE TABLE host ("
+ c_h="$c_h Host char(60) DEFAULT '' NOT NULL,"
+ c_h="$c_h Db char(64) DEFAULT '' NOT NULL,"
+ c_h="$c_h Select_priv enum('N','Y') DEFAULT 'N' NOT NULL,"
+ c_h="$c_h Insert_priv enum('N','Y') DEFAULT 'N' NOT NULL,"
+ c_h="$c_h Update_priv enum('N','Y') DEFAULT 'N' NOT NULL,"
+ c_h="$c_h Delete_priv enum('N','Y') DEFAULT 'N' NOT NULL,"
+ c_h="$c_h Create_priv enum('N','Y') DEFAULT 'N' NOT NULL,"
+ c_h="$c_h Drop_priv enum('N','Y') DEFAULT 'N' NOT NULL,"
+ c_h="$c_h Grant_priv enum('N','Y') DEFAULT 'N' NOT NULL,"
+ c_h="$c_h References_priv enum('N','Y') DEFAULT 'N' NOT NULL,"
+ c_h="$c_h Index_priv enum('N','Y') DEFAULT 'N' NOT NULL,"
+ c_h="$c_h Alter_priv enum('N','Y') DEFAULT 'N' NOT NULL,"
+ c_h="$c_h PRIMARY KEY Host (Host,Db)"
+ c_h="$c_h )"
+ c_h="$c_h comment='Host privileges; Merged with database privileges';"
+fi
+
+if test ! -f $mdata/user.frm
+then
+ c_u="$c_u CREATE TABLE user ("
+ c_u="$c_u Host char(60) DEFAULT '' NOT NULL,"
+ c_u="$c_u User char(16) DEFAULT '' NOT NULL,"
+ c_u="$c_u Password char(16) DEFAULT '' NOT NULL,"
+ c_u="$c_u Select_priv enum('N','Y') DEFAULT 'N' NOT NULL,"
+ c_u="$c_u Insert_priv enum('N','Y') DEFAULT 'N' NOT NULL,"
+ c_u="$c_u Update_priv enum('N','Y') DEFAULT 'N' NOT NULL,"
+ c_u="$c_u Delete_priv enum('N','Y') DEFAULT 'N' NOT NULL,"
+ c_u="$c_u Create_priv enum('N','Y') DEFAULT 'N' NOT NULL,"
+ c_u="$c_u Drop_priv enum('N','Y') DEFAULT 'N' NOT NULL,"
+ c_u="$c_u Reload_priv enum('N','Y') DEFAULT 'N' NOT NULL,"
+ c_u="$c_u Shutdown_priv enum('N','Y') DEFAULT 'N' NOT NULL,"
+ c_u="$c_u Process_priv enum('N','Y') DEFAULT 'N' NOT NULL,"
+ c_u="$c_u File_priv enum('N','Y') DEFAULT 'N' NOT NULL,"
+ c_u="$c_u Grant_priv enum('N','Y') DEFAULT 'N' NOT NULL,"
+ 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 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 ('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');
+
+ 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');"
+fi
+
+if test ! -f $mdata/func.frm
+then
+ c_f="$c_f CREATE TABLE func ("
+ c_f="$c_f name char(64) DEFAULT '' NOT NULL,"
+ c_f="$c_f ret tinyint(1) DEFAULT '0' NOT NULL,"
+ c_f="$c_f dl char(128) DEFAULT '' NOT NULL,"
+ c_f="$c_f type enum ('function','aggregate') NOT NULL,"
+ c_f="$c_f PRIMARY KEY (name)"
+ c_f="$c_f )"
+ c_f="$c_f comment='User defined functions';"
+fi
+
+if test ! -f $mdata/tables_priv.frm
+then
+ c_t="$c_t CREATE TABLE tables_priv ("
+ c_t="$c_t Host char(60) DEFAULT '' NOT NULL,"
+ c_t="$c_t Db char(64) DEFAULT '' NOT NULL,"
+ c_t="$c_t User char(16) DEFAULT '' NOT NULL,"
+ c_t="$c_t Table_name char(60) DEFAULT '' NOT NULL,"
+ c_t="$c_t Grantor char(77) DEFAULT '' NOT NULL,"
+ c_t="$c_t Timestamp timestamp(14),"
+ c_t="$c_t Table_priv set('Select','Insert','Update','Delete','Create','Drop','Grant','References','Index','Alter') DEFAULT '' NOT NULL,"
+ c_t="$c_t Column_priv set('Select','Insert','Update','References') DEFAULT '' NOT NULL,"
+ c_t="$c_t PRIMARY KEY (Host,Db,User,Table_name),"
+ c_t="$c_t KEY Grantor (Grantor)"
+ c_t="$c_t )"
+ c_t="$c_t comment='Table privileges';"
+fi
+
+if test ! -f $mdata/columns_priv.frm
+then
+ c_c="$c_c CREATE TABLE columns_priv ("
+ c_c="$c_c Host char(60) DEFAULT '' NOT NULL,"
+ c_c="$c_c Db char(64) DEFAULT '' NOT NULL,"
+ c_c="$c_c User char(16) DEFAULT '' NOT NULL,"
+ c_c="$c_c Table_name char(64) DEFAULT '' NOT NULL,"
+ c_c="$c_c Column_name char(64) DEFAULT '' NOT NULL,"
+ c_c="$c_c Timestamp timestamp(14),"
+ c_c="$c_c Column_priv set('Select','Insert','Update','References') DEFAULT '' NOT NULL,"
+ c_c="$c_c PRIMARY KEY (Host,Db,User,Table_name,Column_name)"
+ c_c="$c_c )"
+ c_c="$c_c comment='Column privileges';"
+fi
+
+if $execdir/mysqld --bootstrap --skip-grant-tables \
+ --basedir=. --datadir=$ldata "$@" << END_OF_DATA
+use mysql;
+$c_d
+$i_d
+
+$c_h
+$i_h
+
+$c_u
+$i_u
+
+$c_f
+$i_f
+
+$c_t
+$c_c
+END_OF_DATA
+then
+ exit 0
+else
+ exit 1
+fi
diff --git a/mysql-test/mysql-test-run b/mysql-test/mysql-test-run
new file mode 100755
index 00000000000..55ee153dd65
--- /dev/null
+++ b/mysql-test/mysql-test-run
@@ -0,0 +1,262 @@
+#! /bin/sh
+
+#++
+# Access Definitions
+#--
+DB=test
+USER=test
+PASSWD=
+
+#++
+# Misc. Definitions
+#--
+CWD=`pwd`
+cd ..
+BASEDIR=`pwd`
+cd $CWD
+MYBIN="$CWD/mybin"
+TESTVER=3.23
+TESTDIR="$CWD/t/$TESTVER"
+TOT_PASS=0
+TOT_FAIL=0
+TOT_TEST=0
+TIME_FORMAT='%U\t%S\t%E\t%P'
+DASHBLANK="----\t----\t-------\t----"
+
+[ -z $COLUMNS ] && COLUMNS=80
+E=`expr $COLUMNS - 8`
+C=0
+
+while [ $C != $E ]
+do
+ DASH72="${DASH72}-"
+ C=`expr $C + 1`
+done
+
+#++
+# mysqld Environment Parameters
+#--
+MYPORT=9306
+MYDDIR="$CWD/var/lib"
+MYSOCK="$CWD/var/tmp/mysql.sock"
+MYPID="$CWD/var/run/mysqld.pid"
+MYLOG="$CWD/var/log/mysqld.log"
+MYERR="$CWD/var/log/mysqld.err"
+
+#++
+# Program Definitions
+#--
+TIME=/usr/bin/time
+MYSQLD="$BASEDIR/sql/mysqld"
+MYSQL_TEST="$BASEDIR/client/mysql-test"
+MYSQLADMIN="$BASEDIR/client/mysqladmin"
+MYSQL_TEST="$MYSQL_TEST --socket=$MYSOCK --database=$DB --user=$USER --password=$PASSWD --silent"
+INSTALL_DB="$MYBIN/mysql-test_install_db"
+
+
+#++
+# Terminal Modifications
+#--
+MOVE_TO_COL="echo -en \\033[300C\\033[20D"
+SETCOLOR_SUCCESS="echo -en \\033[1;32m"
+SETCOLOR_FAILURE="echo -en \\033[1;31m"
+SETCOLOR_WARNING="echo -en \\033[1;33m"
+SETCOLOR_NORMAL="echo -en \\033[0;39m"
+
+
+
+#++
+# Function Definitions
+#--
+echo_ok() {
+ $MOVE_TO_COL && $SETCOLOR_NORMAL
+ echo -n "[ "
+ $SETCOLOR_SUCCESS
+ echo -n "ok"
+ $SETCOLOR_NORMAL
+ echo " ]"
+ return 0
+}
+
+echo_notok() {
+ $MOVE_TO_COL && $SETCOLOR_NORMAL
+ echo -n "[ "
+ $SETCOLOR_FAILURE
+ echo -n "not ok"
+ $SETCOLOR_NORMAL
+ echo " ]"
+ return 0
+}
+
+echo_pass () {
+ $MOVE_TO_COL && $SETCOLOR_NORMAL
+ echo -n "[ "
+ $SETCOLOR_SUCCESS
+ echo -n "pass"
+ $SETCOLOR_NORMAL
+ echo " ]"
+ return 0
+}
+
+echo_fail () {
+ $MOVE_TO_COL && $SETCOLOR_NORMAL
+ echo -n "[ "
+ $SETCOLOR_FAILURE
+ echo -n "fail"
+ $SETCOLOR_NORMAL
+ echo " ]"
+ return 0
+}
+
+error () {
+
+ $SETCOLOR_FAILURE
+ echo -n "Error: " && $SETCOLOR_NORMAL && echo $1
+ $SETCOLOR_NORMAL
+ exit 1
+}
+
+pass_inc () {
+ TOT_PASS=`expr $TOT_PASS + 1`
+}
+
+fail_inc () {
+ TOT_FAIL=`expr $TOT_FAIL + 1`
+}
+
+total_inc () {
+ TOT_TEST=`expr $TOT_TEST + 1`
+}
+
+report_stats () {
+ if [ $TOT_FAIL == 0 ]; then
+ echo "All tests successful."
+ else
+ echo -n "Failed ${TOT_FAIL}/${TOT_TEST} tests, "
+
+ xten=`expr $TOT_PASS \* 10000` #
+ raw=`expr $xten / $TOT_TEST` # My God
+ raw=`printf %.4d $raw` # This is such a ...
+ whole=`printf %.2s $raw` # Narttu!!
+ xwhole=`expr $whole \* 100` # Hynda!!!
+ deci=`expr $raw - $xwhole` #
+
+ echo "${whole}.${deci}% successful."
+ fi
+}
+
+mysql_install_db () {
+ if [ `$INSTALL_DB` ]; then
+ error "Could not install tmp DBs"
+ fi
+
+ return 0
+}
+
+mysql_start () {
+
+ `$MYSQLD --no-defaults \
+ --skip-networking \
+ --basedir=$CWD \
+ --datadir=$MYDDIR \
+ --pid-file=$MYPID \
+ --socket=$MYSOCK \
+ --log=$MYLOG \
+ --language=english >> $MYERR 2>&1 &`
+
+ return 1
+}
+
+mysql_stop () {
+
+ `$MYSQLADMIN --socket=$MYSOCK -u root shutdown`
+
+ return 1
+}
+
+mysql_restart () {
+
+ mysql_stop
+ res=$?
+ [ $res != 1 ] && echo_notok && error "Stopping mysqld"
+
+ mysql_start
+ res=$?
+ [ $res != 1 ] && echo_notok && error "Starting mysqld"
+
+ return 1
+}
+
+mysql_loadstd () {
+
+ sleep 2
+ return 1
+}
+
+
+mysql_install_db
+
+$SETCOLOR_NORMAL && echo -n "Starting mysqld for Testing"
+mysql_start
+res=$?
+res=1
+[ $res != 1 ] && echo_notok && error "Starting mysqld"
+[ $res == 1 ] && echo_ok
+
+$SETCOLOR_NORMAL && echo -n "Loading Standard Test Database"
+mysql_loadstd
+res=$?
+[ $res != 1 ] && echo_notok && error "Loading STD"
+[ $res == 1 ] && echo_ok
+
+$SETCOLOR_NORMAL && echo -n "Starting Tests for MySQL $TESTVER Series"
+$SETCOLOR_SUCCESS && echo_ok
+
+echo
+echo -e " TEST\t\t\tUSER\tSYSTEM\tELAPSED\t%CPU\t RESULT"
+echo $DASH72
+
+for tf in $TESTDIR/*
+do
+ mytime=`$TIME -f $TIME_FORMAT $MYSQL_TEST < $tf 2>&1`
+ res=$?
+
+ tf=`basename $tf`
+
+ [ $res == 1 ] && mytime=`echo -ne $mytime | cut -b 39-` && mytime=${mytime// /\\t}
+ $SETCOLOR_NORMAL && echo -ne "$tf\t\t$mytime"
+ [ $res == 1 ] && fail_inc && echo_fail
+ [ $res != 1 ] && pass_inc && echo_pass
+
+ total_inc
+
+ if [ $res != 0 ]; then
+ echo
+ $SETCOLOR_NORMAL && echo -ne "Restarting mysqld\t$DASHBLANK"
+ mysql_restart
+ $SETCOLOR_SUCCESS && echo_ok
+ $SETCOLOR_NORMAL && echo -ne "Resuming Tests\t\t$DASHBLANK"
+ $SETCOLOR_SUCCESS && echo_ok
+ echo
+ fi
+done
+
+echo $DASH72
+echo
+$SETCOLOR_NORMAL && echo -n "Ending Tests for MySQL $TESTVER Series"
+$SETCOLOR_SUCCESS && echo_ok
+
+$SETCOLOR_NORMAL && echo -n "Shutdown mysqld"
+mysql_stop
+res=$?
+res=1
+[ $res != 1 ] && echo_notok && error "Shutdown mysqld"
+[ $res == 1 ] && echo_ok
+
+$SETCOLOR_NORMAL
+
+echo
+report_stats
+echo
+
+exit 0
diff --git a/mysql.proj b/mysql.proj
new file mode 100644
index 00000000000..85a0fca7313
--- /dev/null
+++ b/mysql.proj
Binary files differ
diff --git a/mysys/.cvsignore b/mysys/.cvsignore
new file mode 100644
index 00000000000..056ecc2691c
--- /dev/null
+++ b/mysys/.cvsignore
@@ -0,0 +1,10 @@
+.deps
+.libs
+Makefile
+Makefile.in
+st35l1t6
+test_charset
+test_thr_alarm
+test_thr_lock
+test_vsnprintf
+testhash
diff --git a/mysys/COPYING.LIB b/mysys/COPYING.LIB
new file mode 100755
index 00000000000..eb685a5ec98
--- /dev/null
+++ b/mysys/COPYING.LIB
@@ -0,0 +1,481 @@
+ GNU LIBRARY GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1991 Free Software Foundation, Inc.
+ 675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the library GPL. It is
+ numbered 2 because it goes with version 2 of the ordinary GPL.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Library General Public License, applies to some
+specially designated Free Software Foundation software, and to any
+other libraries whose authors decide to use it. You can use it for
+your libraries, 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 library, or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link a program with the library, you must provide
+complete object files to the recipients so that they can relink them
+with the library, after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ Our method of protecting your rights has two steps: (1) copyright
+the library, and (2) offer you this license which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ Also, for each distributor's protection, we want to make certain
+that everyone understands that there is no warranty for this free
+library. If the library is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original
+version, 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 companies distributing free
+software will individually obtain patent licenses, thus in effect
+transforming the program into proprietary software. To prevent this,
+we have made it clear that any patent must be licensed for everyone's
+free use or not licensed at all.
+
+ Most GNU software, including some libraries, is covered by the ordinary
+GNU General Public License, which was designed for utility programs. This
+license, the GNU Library General Public License, applies to certain
+designated libraries. This license is quite different from the ordinary
+one; be sure to read it in full, and don't assume that anything in it is
+the same as in the ordinary license.
+
+ The reason we have a separate public license for some libraries is that
+they blur the distinction we usually make between modifying or adding to a
+program and simply using it. Linking a program with a library, without
+changing the library, is in some sense simply using the library, and is
+analogous to running a utility program or application program. However, in
+a textual and legal sense, the linked executable is a combined work, a
+derivative of the original library, and the ordinary General Public License
+treats it as such.
+
+ Because of this blurred distinction, using the ordinary General
+Public License for libraries did not effectively promote software
+sharing, because most developers did not use the libraries. We
+concluded that weaker conditions might promote sharing better.
+
+ However, unrestricted linking of non-free programs would deprive the
+users of those programs of all benefit from the free status of the
+libraries themselves. This Library General Public License is intended to
+permit developers of non-free programs to use free libraries, while
+preserving your freedom as a user of such programs to change the free
+libraries that are incorporated in them. (We have not seen how to achieve
+this as regards changes in header files, but we have achieved it as regards
+changes in the actual functions of the Library.) The hope is that this
+will lead to faster development of free libraries.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, while the latter only
+works together with the library.
+
+ Note that it is possible for a library to be covered by the ordinary
+General Public License rather than by this special one.
+
+ GNU LIBRARY GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library which
+contains a notice placed by the copyright holder or other authorized
+party saying it may be distributed under the terms of this Library
+General Public License (also called "this License"). Each licensee is
+addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, 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 library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete 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 distribute a copy of this License along with the
+Library.
+
+ 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.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+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 Library, 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 Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you 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.
+
+ If distribution of 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 satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also compile or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ c) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ d) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. 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.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library 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.
+
+ 9. 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 Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+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.
+
+ 11. 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 Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library 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 Library.
+
+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.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library 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.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Library 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 Library
+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 Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+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.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "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
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. 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 LIBRARY 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
+LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ Appendix: How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. 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.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ 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.
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/mysys/ChangeLog b/mysys/ChangeLog
new file mode 100644
index 00000000000..e24fc00b493
--- /dev/null
+++ b/mysys/ChangeLog
@@ -0,0 +1,221 @@
+2000-02-16 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Added an extra argument to the compare routine for queues to allow
+ more advanced key compare functions.
+
+2000-02-10 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Added THR_READ_NO_INSERT lock privilege to thr_lock.
+
+1999-08-21 Michael Widenius <monty@tik.pp.sci.fi>
+
+* Fix that '-1.49 or -1.49' is true
+* Allow negative hexadecimal numbers (like -0x0f).
+* Fixed problem with auto_increment on float and double.
+
+Wed Dec 17 02:13:58 1997 <monty@monty.pp.sci.fi>
+
+* Faster flush of keycache.
+
+Sat Dec 2 21:36:20 1995 Michael Widenius (monty@bitch)
+
+ * array.c push_element & alloc_element.
+
+Wed Mar 3 00:54:20 1993 Michael Widenius (monty@bitch)
+
+ * Removed automatic O_TRUNC from my_create.
+
+Wed Oct 28 02:10:56 1992 Michael Widenius (monty@bitch)
+
+ * Enabled ASNYNC_IO on SUN.
+
+Mon Aug 31 23:51:13 1992 Michael Widenius (monty@bitch)
+
+ * Changed tree_insert to return element if ok.
+ * Added new define tree_set_pointer().
+ * Chagned delete_queue() to not free if allready freed.
+
+Mon Aug 17 01:46:36 1992 Michael Widenius (monty@bitch)
+
+ * Added ny cashing-rutine mf_iocash for quicker io.
+
+Wed Aug 12 13:41:18 1992 Michael Widenius (monty@bitch)
+
+ * Added new function get_copy_of_memory for combined malloc/copy.
+ * Splitted my_malloc to three files.
+
+Thu Jan 23 22:02:37 1992 Michael Widenius (monty at LYNX)
+
+ * Added range-checks and aligned checks on ptrs to
+ safe_malloc:free and safe_malloc:realloc to catch more
+ error nicely without core-dumps.
+
+Wed Nov 13 01:52:18 1991 Michael Widenius (monty at LYNX)
+
+ * Added use of mysys as a shared library.
+
+Sat Nov 9 14:38:21 1991 Michael Widenius (monty at LYNX)
+
+ * Added expand of ~username to unpack_dirname.
+
+Tue Sep 17 21:15:08 1991 Michael Widenius (monty at LYNX)
+
+ * Don't free null-pointers if passed to my_free
+
+Fri May 17 20:11:27 1991 Michael Widenius (monty at LYNX)
+
+ * Changed all char * to string. (Can't change const char * because
+ of bug in C-definition.
+
+Tue Apr 30 01:32:56 1991 Michael Widenius (monty at LYNX)
+
+ * my_path now examines environment for posix variable "_" if
+ progname is given and has no path.
+
+Mon Apr 22 16:12:56 1991 Michael Widenius (monty at LYNX)
+
+ * Added function my_load_path() to fix path to a hard-path.
+
+Mon Apr 15 22:08:58 1991 Michael Widenius (monty at LYNX)
+
+ * Added more info on DBUG-stream when freeing unallocated data.
+
+Wed Apr 3 18:41:28 1991 Michael Widenius (monty at LYNX)
+
+ * Added global flag sf_malloc_no_sanity to make it possibly
+ to avoid sanity-checks in right code with uses malloc a lot.
+
+Tue Mar 26 15:09:45 1991 Mikael WIDENIUS (monty at panther)
+
+ * Made soundex look nicer
+
+Sat Mar 23 10:49:49 1991 Michael Widenius (monty at LYNX)
+
+ * Added init of alarm variables to skipp some warnings from gcc.
+
+Tue Mar 5 16:50:34 1991 Michael Widenius (monty at LYNX)
+
+ * Our qsort now only test if compare() function returns >= 0
+ and is optimized for compare() returning > 0.
+
+Fri Nov 23 23:53:46 1990 Michael Widenius (monty at LYNX)
+
+ * Added function my_set_alarm_variable to get a variable set
+ on some time.
+ my_alarm.h added for functions who want to print stat after
+ a given time or after a number of loops.
+ Changed my_lock to use new function and use defines in my_alarm.h
+
+Mon Oct 1 13:16:15 1990 Michael Widenius (monty at LYNX)
+
+ * Added use of asynchronic io in read_cash_record().
+ * Added write_cash and flush_write_cash to record cashing.
+
+Sun Sep 16 22:05:25 1990 Michael Widenius (monty at LYNX)
+
+ * Added optional alarm to my_lock if one has FCNTL_LOCK. Added new
+ defines to my_sys.h.
+
+Mon Aug 27 22:20:38 1990 Michael Widenius (monty at lynx)
+
+ * my_end() now can print output about executed program.
+ * Added parameter-defines for my_end in my_sys.h
+
+Sun Apr 1 23:29:47 1990 Monty (monty at monty)
+
+ * Changed mf_keydisk.c to have separate functions for read and write.
+ Read can now return pointer to intern key-buffer to skipp
+ unessessary memcpy-s.
+
+Fri Mar 23 23:03:39 1990 Monty (monty at monty)
+
+ * function test_if_hard_pathname() added in dirname.c
+ * my_getwd now only saves changed current dir if dir is a
+ hard pathname.
+ * changed my_path() to use test_if_hard_pathname()
+
+Thu Mar 1 14:47:59 1990 Monty (monty at monty)
+
+ * New function my_path().
+
+Sat Feb 24 02:54:35 1990 Monty (monty at monty)
+
+ * Added print of my_progname in my_mess.c
+
+Sun Feb 11 17:55:58 1990 David Axmark (davida at isil)
+
+ * Concatenated libarys my_func and my_sys because of to much
+ crosswise dependencies.
+ * Fixed varagrs code in mf_fixadr.c
+
+Mon Dec 4 17:36:16 1989 Monty (monty at monty)
+
+ * Changed safemalloc() to use my_message() if out of memory and
+ to check MY_WME if we want this error-messages.
+ * Changed my_setwd() to use dos_setdrive() insted of system().
+
+Wed Oct 25 02:56:07 1989 Monty (monty at monty)
+
+ * Changed my_mktmp1() to work like tempnam() with default dirname.
+ * Changed name of my_mktmp1.c to my_tempnam.c
+
+Thu Oct 19 16:39:27 1989 David Axmark (davida at isil)
+
+ * Removed libary mysysnc. Instead added a hook to my_error that
+ can call my_message if needed.
+
+Thu Oct 5 01:33:29 1989 David Axmark (davida at isil)
+
+ * Use MY_SEEK_{SET,CUR,END} as arguments to my_seek
+
+ * Added a a array of structs that holds properties of open files.
+ Removed include file extras.h
+
+Wed Jun 21 01:34:04 1989 Monty (monty at monty)
+
+ * Added two new malloc-functions: my_once_alloc() and
+ my_once_free(). These give easyer and quicker startup.
+
+Mon May 22 14:03:44 1989 Monty (monty at monty)
+
+ * Fixed my_getwd and my_setwd so they work.
+ * Added extern variabel curr_char[] with is set to current
+ directory after my_getwd() or my_setwd();
+
+Mon Jan 23 03:38:50 1989 Monty (monty at monty)
+
+ * Changed my_chsize to check if NO_CHSIZE is defined. If new file
+ should be shorter it fills unused part with null.
+ * Changed my_lock to not check for arg 0 (Functions should use
+ LK_TO_EOF to lock all file.
+
+Tue Dec 6 15:09:44 1988 Monty (monty at monty)
+
+ * Added DBUG_PRINT if error in my_seek.
+
+Mon Dec 5 15:58:48 1988 Monty (monty at monty)
+
+ * Added DBUG_PRINT if not all byte read/written in my_read(),
+ my_fread(), my_write() and my_fwrite();
+
+Sat Dec 3 01:48:03 1988 Monty (monty at monty)
+
+ * Fixed bug in Makefile; quick did't work.
+ * Changed safemalloc to use bmove, bfill and memcpy when handling
+ memoryblocks.
+
+Fri Dec 2 03:29:21 1988 Monty (monty at monty)
+
+ * Added more defines under MEMORY in my_func.h
+ * Added functions to llib-lmysys.
+ * Removed RCS/* files and installed ewerything as stable.
+ (Because errors in old RCS-files.
+
+Wed Nov 9 00:32:33 1988 Monty (monty at monty)
+
+ * Changed realloc for MSDOS; Previous version freed old block on
+ * error, new version (of compiler) dosn't.
+
+Wed Oct 26 21:07:27 1988 Monty (monty at monty)
+
+ * Fixed missing updateing of my_stream_opened;
diff --git a/mysys/Makefile.am b/mysys/Makefile.am
new file mode 100644
index 00000000000..658b68d6861
--- /dev/null
+++ b/mysys/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
+
+MYSQLDATAdir = $(localstatedir)
+MYSQLSHAREdir = $(pkgdatadir)
+MYSQLBASEdir= $(prefix)
+INCLUDES = @MT_INCLUDES@ -I$(srcdir)/../include -I../include -I..
+pkglib_LIBRARIES = libmysys.a
+LDADD = libmysys.a ../dbug/libdbug.a \
+ ../strings/libmystrings.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_pread.c my_write.c \
+ mf_reccache.c mf_keycache.c mf_iocache.c mf_cache.c \
+ my_lock.c mf_brkhant.c my_alarm.c \
+ my_malloc.c my_realloc.c my_once.c mulalloc.c \
+ my_alloc.c safemalloc.c my_fopen.c my_fstream.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 \
+ mf_pack.c mf_pack2.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 \
+ tree.c list.c hash.c array.c string.c typelib.c \
+ my_copy.c my_append.c my_lib.c \
+ my_delete.c my_rename.c my_redel.c 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 \
+ default.c my_compress.c checksum.c raid.cc my_net.c \
+ my_vsnprintf.c charset.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@
+# test_fn removed 980815 since it not upp to date test_dir
+noinst_PROGRAMS = testhash test_charset @THREAD_LPROGRAMS@
+# test_dir_DEPENDENCIES= $(LIBRARIES)
+testhash_DEPENDENCIES= $(LIBRARIES)
+test_charset_DEPENDENCIES= $(LIBRARIES)
+EXTRA_PROGRAMS =
+DEFS = -DDEFAULT_BASEDIR=\"$(prefix)\" \
+ -DDATADIR="\"$(MYSQLDATAdir)\"" \
+ -DDEFAULT_CHARSET_HOME="\"$(MYSQLBASEdir)\"" \
+ -DDATADIR="\"$(MYSQLDATAdir)\"" \
+ -DSHAREDIR="\"$(MYSQLSHAREdir)\"" \
+ @DEFS@
+
+getopt1.o: @THREAD_LOBJECTS@
+
+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
+
+# I hope this always does the right thing. Otherwise this is only test programs
+FLAGS=$(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS)
+
+test_thr_alarm: thr_alarm.c $(LIBRARIES)
+ $(LINK) $(FLAGS) -DMAIN $(srcdir)/thr_alarm.c $(LDADD) $(LIBS)
+
+test_thr_lock: thr_lock.c $(LIBRARIES)
+ $(LINK) $(FLAGS) -DMAIN $(srcdir)/thr_lock.c $(LDADD) $(LIBS)
+
+test_dir: test_dir.c $(LIBRARIES)
+ $(LINK) $(FLAGS) -DMAIN $(srcdir)/test_dir.c $(LDADD) $(LIBS)
+
+test_charset: test_charset.c $(LIBRARIES)
+ $(LINK) $(FLAGS) -DMAIN $(srcdir)/test_charset.c $(LDADD) $(LIBS)
+
+test_vsnprintf: my_vsnprintf.c $(LIBRARIES)
+ $(LINK) $(FLAGS) -DMAIN $(srcdir)/my_vsnprintf.c $(LDADD) $(LIBS)
+
+test_hash: test_hash.c $(LIBRARIES)
+ $(LINK) $(FLAGS) -DMAIN $(srcdir)/test_dir.c $(LDADD) $(LIBS)
diff --git a/mysys/array.c b/mysys/array.c
new file mode 100644
index 00000000000..17e5ded322b
--- /dev/null
+++ b/mysys/array.c
@@ -0,0 +1,177 @@
+/* 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 */
+
+/* Handling of arrays that can grow dynamicly. */
+
+#if defined(WIN32) || defined(__WIN__)
+#undef SAFEMALLOC /* Problems with threads */
+#endif
+
+#include "mysys_priv.h"
+#include "m_string.h"
+
+/*
+ Initiate array and alloc space for init_alloc elements. Array is usable
+ even if space allocation failed
+*/
+
+my_bool init_dynamic_array(DYNAMIC_ARRAY *array, uint element_size,
+ uint init_alloc, uint alloc_increment)
+{
+ DBUG_ENTER("init_dynamic_array");
+ if (!alloc_increment)
+ {
+ alloc_increment=max((8192-MALLOC_OVERHEAD)/element_size,16);
+ if (init_alloc > 8 && alloc_increment > init_alloc * 2)
+ alloc_increment=init_alloc*2;
+ }
+
+ if (!init_alloc)
+ init_alloc=alloc_increment;
+ array->elements=0;
+ array->max_element=init_alloc;
+ array->alloc_increment=alloc_increment;
+ array->size_of_element=element_size;
+ if (!(array->buffer=(char*) my_malloc(element_size*init_alloc,MYF(MY_WME))))
+ {
+ array->max_element=0;
+ DBUG_RETURN(TRUE);
+ }
+ DBUG_RETURN(FALSE);
+}
+
+
+my_bool insert_dynamic(DYNAMIC_ARRAY *array, gptr element)
+{
+ gptr buffer;
+ if (array->elements == array->max_element)
+ { /* Call only when nessesary */
+ if (!(buffer=alloc_dynamic(array)))
+ return TRUE;
+ }
+ else
+ {
+ buffer=array->buffer+(array->elements * array->size_of_element);
+ array->elements++;
+ }
+ memcpy(buffer,element,(size_t) array->size_of_element);
+ return FALSE;
+}
+
+
+ /* Alloc room for one element */
+
+byte *alloc_dynamic(DYNAMIC_ARRAY *array)
+{
+ if (array->elements == array->max_element)
+ {
+ char *new_ptr;
+ if (!(new_ptr=(char*) my_realloc(array->buffer,(array->max_element+
+ array->alloc_increment)*
+ array->size_of_element,
+ MYF(MY_WME | MY_ALLOW_ZERO_PTR))))
+ return 0;
+ array->buffer=new_ptr;
+ array->max_element+=array->alloc_increment;
+ }
+ return array->buffer+(array->elements++ * array->size_of_element);
+}
+
+
+ /* remove last element from array and return it */
+
+byte *pop_dynamic(DYNAMIC_ARRAY *array)
+{
+ if (array->elements)
+ return array->buffer+(--array->elements * array->size_of_element);
+ return 0;
+}
+
+
+my_bool set_dynamic(DYNAMIC_ARRAY *array, gptr element, uint idx)
+{
+ if (idx >= array->elements)
+ {
+ if (idx >= array->max_element)
+ {
+ uint size;
+ char *new_ptr;
+ size=(idx+array->alloc_increment)/array->alloc_increment;
+ size*= array->alloc_increment;
+ if (!(new_ptr=(char*) my_realloc(array->buffer,size*
+ array->size_of_element,
+ MYF(MY_WME | MY_ALLOW_ZERO_PTR))))
+ return TRUE;
+ array->buffer=new_ptr;
+ array->max_element=size;
+ }
+ bzero((gptr) (array->buffer+array->elements*array->size_of_element),
+ (idx - array->elements)*array->size_of_element);
+ array->elements=idx+1;
+ }
+ memcpy(array->buffer+(idx * array->size_of_element),element,
+ (size_t) array->size_of_element);
+ return FALSE;
+}
+
+
+void get_dynamic(DYNAMIC_ARRAY *array, gptr element, uint idx)
+{
+ if (idx >= array->elements)
+ {
+ DBUG_PRINT("warning",("To big array idx: %d, array size is %d",
+ idx,array->elements));
+ bzero(element,array->size_of_element);
+ return;
+ }
+ memcpy(element,array->buffer+idx*array->size_of_element,
+ (size_t) array->size_of_element);
+}
+
+
+void delete_dynamic(DYNAMIC_ARRAY *array)
+{
+ if (array->buffer)
+ {
+ my_free(array->buffer,MYF(MY_WME));
+ array->buffer=0;
+ array->elements=array->max_element=0;
+ }
+}
+
+
+void delete_dynamic_element(DYNAMIC_ARRAY *array, uint idx)
+{
+ char *ptr=array->buffer+array->size_of_element*idx;
+ array->elements--;
+ memmove(ptr,ptr+array->size_of_element,
+ (array->elements-idx)*array->size_of_element);
+}
+
+
+void freeze_size(DYNAMIC_ARRAY *array)
+{
+ uint elements=max(array->elements,1);
+
+ if (array->buffer && array->max_element != elements)
+ {
+ array->buffer=(char*) my_realloc(array->buffer,
+ elements*array->size_of_element,
+ MYF(MY_WME));
+ array->max_element=elements;
+ }
+}
diff --git a/mysys/charset.c b/mysys/charset.c
new file mode 100644
index 00000000000..88b0972431e
--- /dev/null
+++ b/mysys/charset.c
@@ -0,0 +1,532 @@
+/* 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 "mysys_err.h"
+#include <m_ctype.h>
+#include <m_string.h>
+#include <my_dir.h>
+
+const char *charsets_dir = NULL;
+static DYNAMIC_ARRAY cs_info_table;
+static TYPELIB available_charsets;
+static int charset_initialized=0;
+
+#define MAX_LINE 1024
+
+#define CTYPE_TABLE_SIZE 257
+#define TO_LOWER_TABLE_SIZE 256
+#define TO_UPPER_TABLE_SIZE 256
+#define SORT_ORDER_TABLE_SIZE 256
+
+struct simpleconfig_buf_st {
+ FILE *f;
+ char buf[MAX_LINE];
+ 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 my_bool get_word(struct simpleconfig_buf_st *fb, char *buf)
+{
+ char *endptr=fb->p;
+
+ for (;;)
+ {
+ while (isspace(*endptr))
+ ++endptr;
+ if (*endptr && *endptr != '#') /* Not comment */
+ break; /* Found something */
+ if ((fgets(fb->buf, sizeof(fb->buf), fb->f)) == NULL)
+ return TRUE; /* end of file */
+ endptr = fb->buf;
+ }
+
+ while (!isspace(*endptr))
+ *buf++= *endptr++;
+ *buf=0;
+ fb->p = endptr;
+
+ return FALSE;
+}
+
+
+static char *get_charsets_dir(char *buf)
+{
+ const char *sharedir = SHAREDIR;
+ DBUG_ENTER("get_charsets_dir");
+
+ if (charsets_dir != NULL)
+ strnmov(buf, charsets_dir, FN_REFLEN);
+ else
+ {
+ if (test_if_hard_path(sharedir) ||
+ is_prefix(sharedir, DEFAULT_CHARSET_HOME))
+ strxmov(buf, sharedir, "/", CHARSET_DIR, NullS);
+ else
+ strxmov(buf, DEFAULT_CHARSET_HOME, "/", sharedir, "/", CHARSET_DIR,
+ NullS);
+ }
+ convert_dirname(buf);
+ DBUG_PRINT("info",("charsets dir='%s'", buf));
+ DBUG_RETURN(strend(buf));
+}
+
+
+static my_bool read_charset_index(TYPELIB *charsets, myf myflags)
+{
+ struct simpleconfig_buf_st fb;
+ char buf[MAX_LINE];
+ DYNAMIC_ARRAY cs;
+ my_string s;
+
+ strmov(get_charsets_dir(buf), "Index");
+
+ if ((fb.f = my_fopen(buf, O_RDONLY, myflags)) == NULL)
+ return TRUE;
+ fb.buf[0] = '\0';
+ fb.p = fb.buf;
+
+ if (init_dynamic_array(&cs, sizeof(my_string), 32, 32))
+ return TRUE;
+
+ while (!get_word(&fb, buf))
+ {
+ uint length;
+ if (!(s= (char*) my_once_alloc(length=strlen(buf)+1, myflags)))
+ {
+ my_fclose(fb.f,myflags);
+ return TRUE;
+ }
+ memcpy(s,buf,length);
+ insert_dynamic(&cs, (gptr) &s);
+ }
+ my_fclose(fb.f,myflags);
+
+ /* I seriously doubt this is the best way to initialize this
+ * TYPELIB from the Index file. But it's the best way I could
+ * come up with right now. */
+
+ charsets->count = cs.elements;
+ charsets->name = "";
+ if (!(charsets->type_names =
+ (const char **) my_once_alloc((cs.elements + 1) * sizeof(const char *),
+ myflags)))
+ return TRUE;
+ /* unwarranted chumminess with dynamic_array implementation? */
+ memcpy((char*) charsets->type_names, cs.buffer,
+ cs.elements * sizeof(my_string *));
+ charsets->type_names[cs.elements] = NullS;
+ delete_dynamic(&cs);
+
+ return FALSE;
+}
+
+
+static my_bool init_available_charsets(myf myflags)
+{
+ my_bool error=0;
+ /*
+ We have to use charset_initialized to not lock on THR_LOCK_charset
+ inside get_internal_charset...
+ */
+ if (!charset_initialized)
+ {
+ /*
+ To make things thread safe we are not allowing other threads to interfere
+ while we may changing the cs_info_table
+ */
+ pthread_mutex_lock(&THR_LOCK_charset);
+ if (!cs_info_table.buffer) /* If not initialized */
+ {
+ init_dynamic_array(&cs_info_table, sizeof(CHARSET_INFO*), 16, 8);
+ error = read_charset_index(&available_charsets, myflags);
+ }
+ charset_initialized=1;
+ pthread_mutex_unlock(&THR_LOCK_charset);
+ }
+ return error || available_charsets.count == 0;
+}
+
+
+void free_charsets(void)
+{
+ delete_dynamic(&cs_info_table);
+}
+
+
+static my_bool fill_array(uchar *array, int sz, struct simpleconfig_buf_st *fb)
+{
+ char buf[MAX_LINE];
+ while (sz--)
+ {
+ if (get_word(fb, buf))
+ {
+ DBUG_PRINT("error",("get_word failed, expecting %d more words", sz + 1));
+ return 1;
+ }
+ *array++ = (uchar) strtol(buf, NULL, 16);
+ }
+ return 0;
+}
+
+
+static void get_charset_conf_name(uint cs_number, char *buf)
+{
+ strxmov(get_charsets_dir(buf),
+ get_type(&available_charsets, cs_number - 1), ".conf", NullS);
+}
+
+
+static my_bool read_charset_file(uint cs_number, CHARSET_INFO *set,
+ myf myflags)
+{
+ struct simpleconfig_buf_st fb;
+ char buf[FN_REFLEN];
+ my_bool result;
+ DBUG_ENTER("read_charset_file");
+ DBUG_PRINT("enter",("cs_number: %d", cs_number));
+
+ if (cs_number <= 0)
+ DBUG_RETURN(TRUE);
+
+ get_charset_conf_name(cs_number, buf);
+ DBUG_PRINT("info",("file name: %s", buf));
+
+ if ((fb.f = my_fopen(buf, O_RDONLY, myflags)) == NULL)
+ DBUG_RETURN(TRUE);
+
+ fb.buf[0] = '\0'; /* Init for get_word */
+ fb.p = fb.buf;
+
+ result=FALSE;
+ if (fill_array(set->ctype, CTYPE_TABLE_SIZE, &fb) ||
+ fill_array(set->to_lower, TO_LOWER_TABLE_SIZE, &fb) ||
+ fill_array(set->to_upper, TO_UPPER_TABLE_SIZE, &fb) ||
+ fill_array(set->sort_order, SORT_ORDER_TABLE_SIZE, &fb))
+ result=TRUE;
+
+ my_fclose(fb.f, MYF(0));
+ DBUG_RETURN(result);
+}
+
+
+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 find_type((char*)charset_name, &available_charsets, 1);
+}
+
+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 get_type(&available_charsets, charset_number - 1);
+}
+
+
+static CHARSET_INFO *find_charset(CHARSET_INFO **table, uint cs_number,
+ size_t tablesz)
+{
+ uint i;
+ for (i = 0; i < tablesz; ++i)
+ if (table[i]->number == cs_number)
+ return table[i];
+ return NULL;
+}
+
+static CHARSET_INFO *find_charset_by_name(CHARSET_INFO **table, const char *name,
+ size_t tablesz)
+{
+ uint i;
+ for (i = 0; i < tablesz; ++i)
+ if (!strcmp(table[i]->name,name))
+ return table[i];
+ return NULL;
+}
+
+static CHARSET_INFO *add_charset(uint cs_number, const char *cs_name)
+{
+ CHARSET_INFO tmp_cs,*cs;
+ uchar tmp_ctype[CTYPE_TABLE_SIZE];
+ uchar tmp_to_lower[TO_LOWER_TABLE_SIZE];
+ uchar tmp_to_upper[TO_UPPER_TABLE_SIZE];
+ uchar tmp_sort_order[SORT_ORDER_TABLE_SIZE];
+
+ /* Don't allocate memory if we are not sure we can find the char set */
+ cs= &tmp_cs;
+ bzero((char*) cs, sizeof(*cs));
+ cs->ctype=tmp_ctype;
+ 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)))
+ return NULL;
+
+ cs = (CHARSET_INFO*) my_once_alloc(sizeof(CHARSET_INFO),
+ MYF(MY_WME));
+ *cs=tmp_cs;
+ cs->name = (char *) my_once_alloc(strlen(cs_name) + 1, MYF(MY_WME));
+ cs->ctype = (uchar*) my_once_alloc(CTYPE_TABLE_SIZE, MYF(MY_WME));
+ cs->to_lower = (uchar*) my_once_alloc(TO_LOWER_TABLE_SIZE, MYF(MY_WME));
+ cs->to_upper = (uchar*) my_once_alloc(TO_UPPER_TABLE_SIZE, MYF(MY_WME));
+ cs->sort_order=(uchar*) my_once_alloc(SORT_ORDER_TABLE_SIZE, MYF(MY_WME));
+ cs->number = cs_number;
+ memcpy((char*) cs->name, (char*) cs_name, strlen(cs_name) + 1);
+ memcpy((char*) cs->ctype, (char*) tmp_ctype, sizeof(tmp_ctype));
+ memcpy((char*) cs->to_lower, (char*) tmp_to_lower, sizeof(tmp_to_lower));
+ memcpy((char*) cs->to_upper, (char*) tmp_to_upper, sizeof(tmp_to_upper));
+ memcpy((char*) cs->sort_order, (char*) tmp_sort_order,
+ sizeof(tmp_sort_order));
+ insert_dynamic(&cs_info_table, (gptr) &cs);
+ return cs;
+}
+
+static CHARSET_INFO *get_internal_charset(uint cs_number)
+{
+ CHARSET_INFO *cs;
+ /*
+ To make things thread safe we are not allowing other threads to interfere
+ while we may changing the cs_info_table
+ */
+ pthread_mutex_lock(&THR_LOCK_charset);
+ 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));
+ pthread_mutex_unlock(&THR_LOCK_charset);
+ return cs;
+}
+
+
+static CHARSET_INFO *get_internal_charset_by_name(const char *name)
+{
+ CHARSET_INFO *cs;
+ /*
+ To make things thread safe we are not allowing other threads to interfere
+ while we may changing the cs_info_table
+ */
+ pthread_mutex_lock(&THR_LOCK_charset);
+ 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);
+ pthread_mutex_unlock(&THR_LOCK_charset);
+ return cs;
+}
+
+
+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);
+
+ if (!cs && flags & MY_WME)
+ {
+ char index_file[FN_REFLEN], cs_string[23];
+ strmov(get_charsets_dir(index_file), "Index");
+ cs_string[0]='#';
+ int10_to_str(cs_number, cs_string+1, 10);
+ my_error(EE_UNKNOWN_CHARSET, MYF(ME_BELL), cs_string, index_file);
+ }
+ return cs;
+}
+
+my_bool set_default_charset(uint cs, myf flags)
+{
+ CHARSET_INFO *new;
+ DBUG_ENTER("set_default_charset");
+ DBUG_PRINT("enter",("character set: %d",(int) cs));
+ new = get_charset(cs, flags);
+ if (!new)
+ {
+ DBUG_PRINT("error",("Couldn't set default character set"));
+ DBUG_RETURN(TRUE); /* error */
+ }
+ default_charset_info = new;
+ DBUG_RETURN(FALSE);
+}
+
+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);
+
+ if (!cs && (flags & MY_WME))
+ {
+ char index_file[FN_REFLEN];
+ strmov(get_charsets_dir(index_file), "Index");
+ my_error(EE_UNKNOWN_CHARSET, MYF(ME_BELL), cs_name, index_file);
+ }
+
+ return cs;
+}
+
+my_bool set_default_charset_by_name(const char *cs_name, myf flags)
+{
+ CHARSET_INFO *new;
+ DBUG_ENTER("set_default_charset_by_name");
+ DBUG_PRINT("enter",("character set: %s", cs_name));
+ new = get_charset_by_name(cs_name, flags);
+ if (!new)
+ {
+ DBUG_PRINT("error",("Couldn't set default character set"));
+ DBUG_RETURN(TRUE); /* error */
+ }
+
+ default_charset_info = new;
+ DBUG_RETURN(FALSE);
+}
+
+/* Only append name if it doesn't exist from before */
+
+static my_bool charset_in_string(const char *name, DYNAMIC_STRING *s)
+{
+ uint length=strlen(name);
+ const char *pos;
+ for (pos=s->str ; (pos=strstr(pos,name)) ; pos++)
+ {
+ if (! pos[length] || pos[length] == ' ')
+ return TRUE; /* Already existed */
+ }
+
+ return FALSE;
+}
+
+static void charset_append(DYNAMIC_STRING *s, const char *name)
+{
+ if (!charset_in_string(name, s)) {
+ dynstr_append(s, name);
+ dynstr_append(s, " ");
+ }
+}
+
+
+/* Returns a dynamically-allocated string listing the character sets
+ requested. The caller is responsible for freeing the memory. */
+
+char * list_charsets(myf want_flags)
+{
+ DYNAMIC_STRING s;
+ char *p;
+
+ init_dynamic_string(&s, NullS, 256, 1024);
+
+ if (want_flags & MY_COMPILED_SETS)
+ {
+ CHARSET_INFO *cs;
+ for (cs = compiled_charsets; cs->number > 0; cs++)
+ {
+ dynstr_append(&s, cs->name);
+ dynstr_append(&s, " ");
+ }
+ }
+
+ if (want_flags & MY_CONFIG_SETS)
+ {
+ uint i;
+ const char *cs_name;
+ char buf[FN_REFLEN];
+ MY_STAT stat;
+
+ for (i = 0; i < available_charsets.count; i++)
+ {
+ cs_name = get_type(&available_charsets, i);
+ if (charset_in_string(cs_name, &s))
+ continue;
+ get_charset_conf_name(i + 1, buf);
+ if (!my_stat(buf, &stat, MYF(0)))
+ continue; /* conf file doesn't exist */
+ dynstr_append(&s, cs_name);
+ dynstr_append(&s, " ");
+ }
+ }
+
+ if (want_flags & MY_INDEX_SETS)
+ {
+ uint i;
+ for (i = 0; i < available_charsets.count; i++)
+ charset_append(&s, get_type(&available_charsets, i));
+ }
+
+ if (want_flags & MY_LOADED_SETS)
+ {
+ uint i;
+ for (i = 0; i < cs_info_table.elements; i++)
+ charset_append(&s,
+ dynamic_element(&cs_info_table, i, CHARSET_INFO *)->name);
+ }
+ s.str[s.length - 1] = '\0'; /* chop trailing space */
+ p = my_strdup(s.str, MYF(MY_WME));
+ dynstr_free(&s);
+
+ return p;
+}
+
+/****************************************************************************
+* Code for debugging.
+****************************************************************************/
+
+
+static void _print_array(uint8 *data, uint size)
+{
+ uint i;
+ for (i = 0; i < size; ++i)
+ {
+ if (i == 0 || i % 16 == size % 16) printf(" ");
+ printf(" %02x", data[i]);
+ if ((i+1) % 16 == size % 16) printf("\n");
+ }
+}
+
+/* _print_csinfo is called from test_charset.c */
+void _print_csinfo(CHARSET_INFO *cs)
+{
+ printf("%s #%d\n", cs->name, cs->number);
+ printf("ctype:\n"); _print_array(cs->ctype, 257);
+ printf("to_lower:\n"); _print_array(cs->to_lower, 256);
+ printf("to_upper:\n"); _print_array(cs->to_upper, 256);
+ printf("sort_order:\n"); _print_array(cs->sort_order, 256);
+ printf("collate: %3s (%d, %p, %p, %p, %p, %p)\n",
+ cs->strxfrm_multiply ? "yes" : "no",
+ cs->strxfrm_multiply,
+ cs->strcoll,
+ cs->strxfrm,
+ cs->strnncoll,
+ cs->strnxfrm,
+ cs->like_range);
+ printf("multi-byte: %3s (%d, %p, %p, %p)\n",
+ cs->mbmaxlen ? "yes" : "no",
+ cs->mbmaxlen,
+ cs->ismbchar,
+ cs->ismbhead,
+ cs->mbcharlen);
+}
diff --git a/mysys/checksum.c b/mysys/checksum.c
new file mode 100644
index 00000000000..00861853945
--- /dev/null
+++ b/mysys/checksum.c
@@ -0,0 +1,30 @@
+/* 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 */
+
+/* Calculate a long checksum for a memoryblock. Used to verify pack_isam */
+
+#include <global.h>
+#include "my_sys.h"
+
+ulong checksum(const byte *mem, uint count)
+{
+ ulong crc;
+ for (crc=0; count-- ; mem++)
+ crc=((crc << 1) + *((uchar*) mem)) +
+ test(crc & ((ulong) 1L << (8*sizeof(ulong)-1)));
+ return crc;
+}
diff --git a/mysys/default.c b/mysys/default.c
new file mode 100644
index 00000000000..ae4ba5044be
--- /dev/null
+++ b/mysys/default.c
@@ -0,0 +1,362 @@
+/* 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 */
+
+/****************************************************************************
+** Add all options from files named "group".cnf from the default_directories
+** before the command line arguments.
+** On Windows defaults will also search in the Windows directory for a file
+** called 'group'.ini
+** As long as the program uses the last argument for conflicting
+** options one only have to add a call to "load_defaults" to enable
+** use of default values.
+** pre- and end 'blank space' are removed from options and values. The
+** following escape sequences are recognized in values: \b \t \n \r \\
+**
+** The following arguments are handled automaticly; If used, they must be
+** first argument on the command line!
+** --no-defaults ; no options are read.
+** --print-defaults ; Print the modified command line and exit
+** --defaults-file=full-path-to-default-file ; Only this file will be read.
+****************************************************************************/
+
+#undef SAFEMALLOC /* safe_malloc is not yet initailized */
+
+#include "mysys_priv.h"
+#include "m_string.h"
+#include "m_ctype.h"
+
+/* Which directories are searched for options (and in which order) */
+
+const char *default_directories[]= {
+#ifdef __WIN__
+"C:/",
+#else
+"/etc/",
+#endif
+#ifdef DATADIR
+DATADIR,
+#endif
+#ifndef __WIN__
+"~/",
+#endif
+NullS,
+};
+
+#define default_ext ".cnf" /* extension for config file */
+#ifdef __WIN__
+#include <winbase.h>
+#define windows_ext ".ini"
+#endif
+
+static my_bool search_default_file(DYNAMIC_ARRAY *args, MEM_ROOT *alloc,
+ const char *dir, const char *config_file,
+ const char *ext, TYPELIB *group);
+
+
+void load_defaults(const char *conf_file, const char **groups,
+ int *argc, char ***argv)
+{
+ DYNAMIC_ARRAY args;
+ const char **dirs, *extra_default_file;
+ TYPELIB group;
+ my_bool found_print_defaults=0;
+ MEM_ROOT alloc;
+ char *ptr,**res;
+ DBUG_ENTER("load_defaults");
+
+ init_alloc_root(&alloc,128);
+ if (*argc >= 2 && !strcmp(argv[0][1],"--no-defaults"))
+ {
+ /* remove the --no-defaults argument and return only the other arguments */
+ uint i;
+ if (!(ptr=(char*) alloc_root(&alloc,sizeof(alloc)+
+ (*argc + 1)*sizeof(char*))))
+ goto err;
+ res= (char**) (ptr+sizeof(alloc));
+ res[0]= **argv; /* Copy program name */
+ for (i=2 ; i < (uint) *argc ; i++)
+ res[i-1]=argv[0][i];
+ (*argc)--;
+ *argv=res;
+ *(MEM_ROOT*) ptr= alloc; /* Save alloc root for free */
+ DBUG_VOID_RETURN;
+ }
+
+ /* Check if we want to force the use a specific default file */
+ extra_default_file=0;
+ if (*argc >= 2 && is_prefix(argv[0][1],"--defaults-file="))
+ extra_default_file=strchr(argv[0][1],'=')+1;
+
+ group.count=0;
+ group.name= "defaults";
+ group.type_names= groups;
+ for (; *groups ; groups++)
+ group.count++;
+
+ if (init_dynamic_array(&args, sizeof(char*),*argc, 32))
+ goto err;
+ if (extra_default_file)
+ {
+ if (search_default_file(&args, &alloc, "", extra_default_file, "",
+ &group))
+ goto err;
+ }
+ else if (dirname_length(conf_file))
+ {
+ if (search_default_file(&args, &alloc, NullS, conf_file, default_ext,
+ &group))
+ goto err;
+ }
+ else
+ {
+#ifdef __WIN__
+ char system_dir[FN_REFLEN];
+ GetWindowsDirectory(system_dir,sizeof(system_dir));
+ if (search_default_file(&args, &alloc, system_dir, conf_file, windows_ext,
+ &group))
+ goto err;
+#endif
+ for (dirs=default_directories ; *dirs; dirs++)
+ {
+ if (search_default_file(&args, &alloc, *dirs, conf_file, default_ext,
+ &group))
+ goto err;
+ }
+ }
+ if (!(ptr=(char*) alloc_root(&alloc,sizeof(alloc)+
+ (args.elements + *argc +1) *sizeof(char*))))
+ goto err;
+ res= (char**) (ptr+sizeof(alloc));
+
+ /* copy name + found arguments + command line arguments to new array */
+ res[0]=argv[0][0];
+ memcpy((gptr) (res+1), args.buffer, args.elements*sizeof(char*));
+ if (extra_default_file)
+ {
+ --*argc; /* Skipp --defaults-file */
+ ++*argv;
+ }
+
+ /* Check if we wan't to see the new argument list */
+ if (*argc >= 2 && !strcmp(argv[0][1],"--print-defaults"))
+ {
+ found_print_defaults=1;
+ --*argc; ++*argv; /* skipp argument */
+ }
+
+ memcpy((gptr) (res+1+args.elements), (char*) ((*argv)+1),
+ (*argc-1)*sizeof(char*));
+ res[args.elements+ *argc]=0; /* last null */
+
+ (*argc)+=args.elements;
+ *argv= (char**) res;
+ *(MEM_ROOT*) ptr= alloc; /* Save alloc root for free */
+ delete_dynamic(&args);
+ if (found_print_defaults)
+ {
+ int i;
+ printf("%s would have been started with the following arguments:\n",
+ **argv);
+ for (i=1 ; i < *argc ; i++)
+ printf("%s ", (*argv)[i]);
+ puts("");
+ exit(1);
+ }
+ DBUG_VOID_RETURN;
+
+ err:
+ fprintf(stderr,"Program aborted\n");
+ exit(1);
+}
+
+
+void free_defaults(char **argv)
+{
+ MEM_ROOT ptr;
+ memcpy_fixed((char*) &ptr,(char *) argv - sizeof(ptr), sizeof(ptr));
+ free_root(&ptr);
+}
+
+
+static my_bool search_default_file(DYNAMIC_ARRAY *args, MEM_ROOT *alloc,
+ const char *dir, const char *config_file,
+ const char *ext, TYPELIB *group)
+{
+ char name[FN_REFLEN+10],buff[257],*ptr,*end,*value,*tmp;
+ FILE *fp;
+ uint line=0;
+ my_bool read_values=0,found_group=0;
+
+ if ((dir ? strlen(dir) : 0 )+strlen(config_file) >= FN_REFLEN-3)
+ return 0; /* Ignore wrong paths */
+ if (dir)
+ {
+ strmov(name,dir);
+ convert_dirname(name);
+ if (dir[0] == FN_HOMELIB) /* Add . to filenames in home */
+ strcat(name,".");
+ strxmov(strend(name),config_file,ext,NullS);
+ }
+ else
+ {
+ strmov(name,config_file);
+ }
+ if (!(fp = my_fopen(fn_format(name,name,"","",4),O_RDONLY,MYF(0))))
+ return 0; /* Ignore wrong files */
+
+ while (fgets(buff,sizeof(buff)-1,fp))
+ {
+ line++;
+ /* Ignore comment and empty lines */
+ for (ptr=buff ; isspace(*ptr) ; ptr++ ) ;
+ if (*ptr == '#' || *ptr == ';' || !*ptr)
+ continue;
+ if (*ptr == '[') /* Group name */
+ {
+ found_group=1;
+ if (!(end=(char *) strchr(++ptr,']')))
+ {
+ fprintf(stderr,
+ "error: Wrong group definition in config file: %s at line %d\n",
+ name,line);
+ goto err;
+ }
+ for ( ; isspace(end[-1]) ; end--) ; /* Remove end space */
+ end[0]=0;
+ read_values=find_type(ptr,group,3) > 0;
+ continue;
+ }
+ if (!found_group)
+ {
+ fprintf(stderr,
+ "error: Found option without preceding group in config file: %s at line: %d\n",
+ name,line);
+ goto err;
+ }
+ if (!read_values)
+ continue;
+ if (!(end=value=strchr(ptr,'=')))
+ end=strend(ptr); /* Option without argument */
+ for ( ; isspace(end[-1]) ; end--) ;
+ if (!value)
+ {
+ if (!(tmp=alloc_root(alloc,(uint) (end-ptr)+3)))
+ goto err;
+ strmake(strmov(tmp,"--"),ptr,(uint) (end-ptr));
+ if (insert_dynamic(args,(gptr) &tmp))
+ goto err;
+ }
+ else
+ {
+ /* Remove pre- and end space */
+ char *value_end;
+ for (value++ ; isspace(*value); value++) ;
+ value_end=strend(value);
+ for ( ; isspace(value_end[-1]) ; value_end--) ;
+ if (value_end < value) /* Empty string */
+ value_end=value;
+ if (!(tmp=alloc_root(alloc,(uint) (end-ptr)+3 +
+ (uint) (value_end-value)+1)))
+ goto err;
+ if (insert_dynamic(args,(gptr) &tmp))
+ goto err;
+ ptr=strnmov(strmov(tmp,"--"),ptr,(uint) (end-ptr));
+ *ptr++= '=';
+ for ( ; value != value_end; value++)
+ {
+ if (*value == '\\' && value != value_end-1)
+ {
+ switch(*++value) {
+ case 'n':
+ *ptr++='\n';
+ break;
+ case 't':
+ *ptr++= '\t';
+ break;
+ case 'r':
+ *ptr++ = '\r';
+ break;
+ case 'b':
+ *ptr++ = '\b';
+ break;
+ case 's':
+ *ptr++= ' '; /* space */
+ break;
+ case '\\':
+ *ptr++= '\\';
+ break;
+ default: /* Unknown; Keep '\' */
+ *ptr++= '\\';
+ *ptr++= *value;
+ break;
+ }
+ }
+ else
+ *ptr++= *value;
+ }
+ *ptr=0;
+ }
+ }
+ my_fclose(fp,MYF(0));
+ return(0);
+
+ err:
+ my_fclose(fp,MYF(0));
+ return 1;
+}
+
+
+void print_defaults(const char *conf_file, const char **groups)
+{
+#ifdef __WIN__
+ bool have_ext=fn_ext(conf_file)[0] != 0;
+#endif
+ char name[FN_REFLEN];
+ const char **dirs;
+ puts("\nDefault options are read from the following files in the given order:");
+
+ if (dirname_length(conf_file))
+ fputs(conf_file,stdout);
+ else
+ {
+#ifdef __WIN__
+ GetWindowsDirectory(name,sizeof(name));
+ printf("%s\\%s%s ",name,conf_file,have_ext ? "" : windows_ext);
+#endif
+ for (dirs=default_directories ; *dirs; dirs++)
+ {
+ strmov(name,*dirs);
+ convert_dirname(name);
+ if (name[0] == FN_HOMELIB) /* Add . to filenames in home */
+ strcat(name,".");
+ strxmov(strend(name),conf_file,default_ext," ",NullS);
+ fputs(name,stdout);
+ }
+ puts("");
+ }
+ fputs("The following groups are read:",stdout);
+ for ( ; *groups ; groups++)
+ {
+ fputc(' ',stdout);
+ fputs(*groups,stdout);
+ }
+ puts("\nThe following options may be given as the first argument:\n\
+--print-defaults Print the program argument list and exit\n\
+--no-defaults Don't read default options from any options file\n\
+--defaults-file=# Only read default options from the given file #");
+}
+
diff --git a/mysys/errors.c b/mysys/errors.c
new file mode 100644
index 00000000000..03b0b9d7f46
--- /dev/null
+++ b/mysys/errors.c
@@ -0,0 +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,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should 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 "mysys_err.h"
+
+#ifndef SHARED_LIBRARY
+
+const char * NEAR globerrs[GLOBERRS]=
+{
+ "File '%s' not found (Errcode: %d)",
+ "Can't create/write to file '%s' (Errcode: %d)",
+ "Error reading file '%s' (Errcode: %d)",
+ "Error writing file '%s' (Errcode: %d)",
+ "Error on close of '%s' (Errcode: %d)",
+ "Out of memory (Needed %u bytes)",
+ "Error on delete of '%s' (Errcode: %d)",
+ "Error on rename of '%s' to '%s' (Errcode: %d)",
+ "",
+ "Unexpected eof found when reading file '%s' (Errcode: %d)",
+ "Can't lock file (Errcode: %d)",
+ "Can't unlock file (Errcode: %d)",
+ "Can't read dir of '%s' (Errcode: %d)",
+ "Can't get stat of '%s' (Errcode: %d)",
+ "Can't change size of file (Errcode: %d)",
+ "Can't open stream from handle (Errcode: %d)",
+ "Can't get working dirctory (Errcode: %d)",
+ "Can't change dir to '%s' (Errcode: %d)",
+ "Warning: '%s' had %d links",
+ "%d files and %d streams is left open\n",
+ "Disk is full writing '%s'. Waiting for someone to free space...",
+ "Can't create directory '%s' (Errcode: %d)",
+ "Character set '%s' is not a compiled character set and is not specified in the '%s' file"
+};
+
+void init_glob_errs(void)
+{
+ errmsg[GLOB] = & globerrs[0];
+} /* init_glob_errs */
+
+#else
+
+void init_glob_errs()
+{
+ errmsg[GLOB] = & globerrs[0];
+
+ EE(EE_FILENOTFOUND) = "File '%s' not found (Errcode: %d)";
+ EE(EE_CANTCREATEFILE) = "Can't create/write to file '%s' (Errcode: %d)";
+ EE(EE_READ) = "Error reading file '%s' (Errcode: %d)";
+ EE(EE_WRITE) = "Error writing file '%s' (Errcode: %d)";
+ EE(EE_BADCLOSE) = "Error on close of '%'s (Errcode: %d)";
+ EE(EE_OUTOFMEMORY) = "Out of memory (Needed %u bytes)";
+ EE(EE_DELETE) = "Error on delete of '%s' (Errcode: %d)";
+ EE(EE_LINK) = "Error on rename of '%s' to '%s' (Errcode: %d)";
+ EE(EE_EOFERR) = "Unexpected eof found when reading file '%s' (Errcode: %d)";
+ EE(EE_CANTLOCK) = "Can't lock file (Errcode: %d)";
+ EE(EE_CANTUNLOCK) = "Can't unlock file (Errcode: %d)";
+ EE(EE_DIR) = "Can't read dir of '%s' (Errcode: %d)";
+ EE(EE_STAT) = "Can't get stat of '%s' (Errcode: %d)";
+ EE(EE_CANT_CHSIZE) = "Can't change size of file (Errcode: %d)";
+ EE(EE_CANT_OPEN_STREAM)= "Can't open stream from handle (Errcode: %d)";
+ EE(EE_GETWD) = "Can't get working dirctory (Errcode: %d)";
+ EE(EE_SETWD) = "Can't change dir to '%s' (Errcode: %d)";
+ EE(EE_LINK_WARNING) = "Warning: '%s' had %d links";
+ EE(EE_OPEN_WARNING) = "%d files and %d streams is left open\n";
+ EE(EE_DISK_FULL) = "Disk is full writing '%s'. Waiting for someone to free space...";
+ EE(EE_CANT_MKDIR) ="Can't create directory '%s' (Errcode: %d)";
+ EE(EE_UNKNOWN_CHARSET)= "Character set is not a compiled character set and is not specified in the %s file";
+}
+#endif
diff --git a/mysys/getopt.c b/mysys/getopt.c
new file mode 100644
index 00000000000..88fdbff7811
--- /dev/null
+++ b/mysys/getopt.c
@@ -0,0 +1,744 @@
+/* Getopt for GNU.
+ NOTE: getopt is now part of the C library, so if you don't know what
+ "Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu
+ before changing it!
+
+ Copyright (C) 1987, 88, 89, 90, 91, 92, 93, 94
+ Free Software Foundation, Inc.
+
+Changes by monty:
+- Added include of string.h when nessessary.
+- Removed two warnings from gcc.
+
+This file is part of the GNU C Library. Its master source is NOT part of
+the C library, however. The master source lives in /gd/gnu/lib.
+
+The GNU C Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+The GNU C 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 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
+#define _NO_PROTO
+#endif
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#if (!defined (__STDC__) || !__STDC__) && !defined(MSDOS)
+/* This is a separate conditional since some stdc systems
+ reject `defined (const)'. */
+#ifndef const
+#define const
+#endif
+#endif
+
+#include <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
+ actually compiling the library itself. This code is part of the GNU C
+ Library, but also included in many other GNU distributions. Compiling
+ and linking in this code is a waste when using the GNU C library
+ (especially if it is a shared library). Rather than having every GNU
+ program understand `configure --with-gnu-libc' and omit the object files,
+ it is simpler to just do this in the source for each such file. */
+
+#if defined (_LIBC) || !defined (__GNU_LIBRARY__)
+
+
+/* This needs to come after some library #include
+ to get __GNU_LIBRARY__ defined. */
+#ifdef __GNU_LIBRARY__
+/* Don't include stdlib.h for non-GNU C libraries because some of them
+ contain conflicting prototypes for getopt. */
+#include <stdlib.h>
+#endif /* GNU C library. */
+
+/* This version of `getopt' appears to the caller like standard Unix `getopt'
+ but it behaves differently for the user, since it allows the user
+ to intersperse the options with the other arguments.
+
+ As `getopt' works, it permutes the elements of ARGV so that,
+ when it is done, all the options precede everything else. Thus
+ all application programs are extended to handle flexible argument order.
+
+ Setting the environment variable POSIXLY_CORRECT disables permutation.
+ Then the behavior is completely standard.
+
+ GNU application programs can use a third alternative mode in which
+ they can distinguish the relative order of options and other arguments. */
+
+#include "getopt.h"
+
+/* For communication from `getopt' to the caller.
+ When `getopt' finds an option that takes an argument,
+ the argument value is returned here.
+ Also, when `ordering' is RETURN_IN_ORDER,
+ each non-option ARGV-element is returned here. */
+
+char *optarg = NULL;
+
+/* Index in ARGV of the next element to be scanned.
+ This is used for communication to and from the caller
+ and for communication between successive calls to `getopt'.
+
+ On entry to `getopt', zero means this is the first call; initialize.
+
+ When `getopt' returns EOF, this is the index of the first of the
+ non-option elements that the caller should itself scan.
+
+ Otherwise, `optind' communicates from one call to the next
+ how much of ARGV has been scanned so far. */
+
+/* XXX 1003.2 says this must be 1 before any call. */
+int optind = 1;
+
+/* The next char to be scanned in the option-element
+ in which the last option character we returned was found.
+ This allows us to pick up the scan where we left off.
+
+ If this is zero, or a null string, it means resume the scan
+ by advancing to the next ARGV-element. */
+
+static char *nextchar;
+
+/* Callers store zero here to inhibit the error message
+ for unrecognized options. */
+
+int opterr = 1;
+
+/* Set to an option character which was unrecognized.
+ This must be initialized on some systems to avoid linking in the
+ system's own getopt implementation. */
+
+int optopt = '?';
+
+/* Describe how to deal with options that follow non-option ARGV-elements.
+
+ If the caller did not specify anything,
+ the default is REQUIRE_ORDER if the environment variable
+ POSIXLY_CORRECT is defined, PERMUTE otherwise.
+
+ REQUIRE_ORDER means don't recognize them as options;
+ stop option processing when the first non-option is seen.
+ This is what Unix does.
+ This mode of operation is selected by either setting the environment
+ variable POSIXLY_CORRECT, or using `+' as the first character
+ of the list of option characters.
+
+ PERMUTE is the default. We permute the contents of ARGV as we scan,
+ so that eventually all the non-options are at the end. This allows options
+ to be given in any order, even with programs that were not written to
+ expect this.
+
+ RETURN_IN_ORDER is an option available to programs that were written
+ to expect options and other ARGV-elements in any order and that care about
+ the ordering of the two. We describe each non-option ARGV-element
+ as if it were the argument of an option with character code 1.
+ Using `-' as the first character of the list of option characters
+ selects this mode of operation.
+
+ The special argument `--' forces an end of option-scanning regardless
+ of the value of `ordering'. In the case of RETURN_IN_ORDER, only
+ `--' can cause `getopt' to return EOF with `optind' != ARGC. */
+
+static enum
+{
+ REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
+} ordering;
+
+/* Value of POSIXLY_CORRECT environment variable. */
+static char *posixly_correct;
+
+#ifdef __GNU_LIBRARY__
+/* We want to avoid inclusion of string.h with non-GNU libraries
+ because there are many ways it can cause trouble.
+ On some systems, it contains special magic macros that don't work
+ in GCC. */
+#include <string.h>
+#define my_index strchr
+#else
+
+/* Avoid depending on library functions or files
+ whose names are inconsistent. */
+
+char *getenv (const char *);
+
+static char *
+my_index (const char *str, int chr)
+{
+ while (*str)
+ {
+ if (*str == chr)
+ return (char *) str;
+ str++;
+ }
+ return 0;
+}
+
+/* If using GCC, we can safely declare strlen this way.
+ If not using GCC, it is ok not to declare it. */
+#ifdef __GNUC__
+/* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h.
+ That was relevant to code that was here before. */
+#if !defined (__STDC__) || !__STDC__
+/* gcc with -traditional declares the built-in strlen to return int,
+ and has done so at least since version 2.4.5. -- rms. */
+extern int strlen (const char *);
+#endif /* not __STDC__ */
+#endif /* __GNUC__ */
+
+#endif /* not __GNU_LIBRARY__ */
+
+/* Handle permutation of arguments. */
+
+/* Describe the part of ARGV that contains non-options that have
+ been skipped. `first_nonopt' is the index in ARGV of the first of them;
+ `last_nonopt' is the index after the last of them. */
+
+static int first_nonopt;
+static int last_nonopt;
+
+/* Exchange two adjacent subsequences of ARGV.
+ One subsequence is elements [first_nonopt,last_nonopt)
+ which contains all the non-options that have been skipped so far.
+ The other is elements [last_nonopt,optind), which contains all
+ the options processed since those non-options were skipped.
+
+ `first_nonopt' and `last_nonopt' are relocated so that they describe
+ the new indices of the non-options in ARGV after they are moved. */
+
+static void
+exchange (char **argv)
+{
+ int bottom = first_nonopt;
+ int middle = last_nonopt;
+ int top = optind;
+ char *tem;
+
+ /* Exchange the shorter segment with the far end of the longer segment.
+ That puts the shorter segment into the right place.
+ It leaves the longer segment in the right place overall,
+ but it consists of two parts that need to be swapped next. */
+
+ while (top > middle && middle > bottom)
+ {
+ if (top - middle > middle - bottom)
+ {
+ /* Bottom segment is the short one. */
+ int len = middle - bottom;
+ register int i;
+
+ /* Swap it with the top part of the top segment. */
+ for (i = 0; i < len; i++)
+ {
+ tem = argv[bottom + i];
+ argv[bottom + i] = argv[top - (middle - bottom) + i];
+ argv[top - (middle - bottom) + i] = tem;
+ }
+ /* Exclude the moved bottom segment from further swapping. */
+ top -= len;
+ }
+ else
+ {
+ /* Top segment is the short one. */
+ int len = top - middle;
+ register int i;
+
+ /* Swap it with the bottom part of the bottom segment. */
+ for (i = 0; i < len; i++)
+ {
+ tem = argv[bottom + i];
+ argv[bottom + i] = argv[middle + i];
+ argv[middle + i] = tem;
+ }
+ /* Exclude the moved top segment from further swapping. */
+ bottom += len;
+ }
+ }
+
+ /* Update records for the slots the non-options now occupy. */
+
+ first_nonopt += (optind - last_nonopt);
+ last_nonopt = optind;
+}
+
+/* Initialize the internal data when the first call is made. */
+
+static const char *
+_getopt_initialize (const char *optstring)
+{
+ /* Start processing options with ARGV-element 1 (since ARGV-element 0
+ is the program name); the sequence of previously skipped
+ non-option ARGV-elements is empty. */
+
+ first_nonopt = last_nonopt = optind = 1;
+
+ nextchar = NULL;
+
+ posixly_correct = getenv ("POSIXLY_CORRECT");
+
+ /* Determine how to handle the ordering of options and nonoptions. */
+
+ if (optstring[0] == '-')
+ {
+ ordering = RETURN_IN_ORDER;
+ ++optstring;
+ }
+ else if (optstring[0] == '+')
+ {
+ ordering = REQUIRE_ORDER;
+ ++optstring;
+ }
+ else if (posixly_correct != NULL)
+ ordering = REQUIRE_ORDER;
+ else
+ ordering = PERMUTE;
+
+ return optstring;
+}
+
+/* Scan elements of ARGV (whose length is ARGC) for option characters
+ given in OPTSTRING.
+
+ If an element of ARGV starts with '-', and is not exactly "-" or "--",
+ then it is an option element. The characters of this element
+ (aside from the initial '-') are option characters. If `getopt'
+ is called repeatedly, it returns successively each of the option characters
+ from each of the option elements.
+
+ If `getopt' finds another option character, it returns that character,
+ updating `optind' and `nextchar' so that the next call to `getopt' can
+ resume the scan with the following option character or ARGV-element.
+
+ If there are no more option characters, `getopt' returns `EOF'.
+ Then `optind' is the index in ARGV of the first ARGV-element
+ that is not an option. (The ARGV-elements have been permuted
+ so that those that are not options now come last.)
+
+ OPTSTRING is a string containing the legitimate option characters.
+ If an option character is seen that is not listed in OPTSTRING,
+ return '?' after printing an error message. If you set `opterr' to
+ zero, the error message is suppressed but we still return '?'.
+
+ If a char in OPTSTRING is followed by a colon, that means it wants an arg,
+ so the following text in the same ARGV-element, or the text of the following
+ ARGV-element, is returned in `optarg'. Two colons mean an option that
+ wants an optional arg; if there is text in the current ARGV-element,
+ it is returned in `optarg', otherwise `optarg' is set to zero.
+
+ If OPTSTRING starts with `-' or `+', it requests different methods of
+ handling the non-option ARGV-elements.
+ See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.
+
+ Long-named options begin with `--' instead of `-'.
+ Their names may be abbreviated as long as the abbreviation is unique
+ or is an exact match for some defined option. If they have an
+ argument, it follows the option name in the same ARGV-element, separated
+ from the option name by a `=', or else the in next ARGV-element.
+ When `getopt' finds a long-named option, it returns 0 if that option's
+ `flag' field is nonzero, the value of the option's `val' field
+ if the `flag' field is zero.
+
+ The elements of ARGV aren't really const, because we permute them.
+ But we pretend they're const in the prototype to be compatible
+ with other systems.
+
+ LONGOPTS is a vector of `struct option' terminated by an
+ element containing a name which is zero.
+
+ LONGIND returns the index in LONGOPT of the long-named option found.
+ It is only valid when a long-named option has been found by the most
+ recent call.
+
+ If LONG_ONLY is nonzero, '-' as well as '--' can introduce
+ long-named options. */
+
+int
+_getopt_internal (int argc, char *const *argv, const char *optstring, const struct option *longopts, int *longind, int long_only)
+{
+ optarg = NULL;
+
+ if (optind == 0)
+ optstring = _getopt_initialize (optstring);
+
+ if (nextchar == NULL || *nextchar == '\0')
+ {
+ /* Advance to the next ARGV-element. */
+
+ if (ordering == PERMUTE)
+ {
+ /* If we have just processed some options following some non-options,
+ exchange them so that the options come first. */
+
+ if (first_nonopt != last_nonopt && last_nonopt != optind)
+ exchange ((char **) argv);
+ else if (last_nonopt != optind)
+ first_nonopt = optind;
+
+ /* Skip any additional non-options
+ and extend the range of non-options previously skipped. */
+
+ while (optind < argc
+ && (argv[optind][0] != '-' || argv[optind][1] == '\0'))
+ optind++;
+ last_nonopt = optind;
+ }
+
+ /* The special ARGV-element `--' means premature end of options.
+ Skip it like a null option,
+ then exchange with previous non-options as if it were an option,
+ then skip everything else like a non-option. */
+
+ if (optind != argc && !strcmp (argv[optind], "--"))
+ {
+ optind++;
+
+ if (first_nonopt != last_nonopt && last_nonopt != optind)
+ exchange ((char **) argv);
+ else if (first_nonopt == last_nonopt)
+ first_nonopt = optind;
+ last_nonopt = argc;
+
+ optind = argc;
+ }
+
+ /* If we have done all the ARGV-elements, stop the scan
+ and back over any non-options that we skipped and permuted. */
+
+ if (optind == argc)
+ {
+ /* Set the next-arg-index to point at the non-options
+ that we previously skipped, so the caller will digest them. */
+ if (first_nonopt != last_nonopt)
+ optind = first_nonopt;
+ return EOF;
+ }
+
+ /* If we have come to a non-option and did not permute it,
+ either stop the scan or describe it to the caller and pass it by. */
+
+ if ((argv[optind][0] != '-' || argv[optind][1] == '\0'))
+ {
+ if (ordering == REQUIRE_ORDER)
+ return EOF;
+ optarg = argv[optind++];
+ return 1;
+ }
+
+ /* We have found another option-ARGV-element.
+ Skip the initial punctuation. */
+
+ nextchar = (argv[optind] + 1
+ + (longopts != NULL && argv[optind][1] == '-'));
+ }
+
+ /* Decode the current option-ARGV-element. */
+
+ /* Check whether the ARGV-element is a long option.
+
+ If long_only and the ARGV-element has the form "-f", where f is
+ a valid short option, don't consider it an abbreviated form of
+ a long option that starts with f. Otherwise there would be no
+ way to give the -f short option.
+
+ On the other hand, if there's a long option "fubar" and
+ the ARGV-element is "-fu", do consider that an abbreviation of
+ the long option, just like "--fu", and not "-f" with arg "u".
+
+ This distinction seems to be the most useful approach. */
+
+ if (longopts != NULL
+ && (argv[optind][1] == '-'
+ || (long_only && (argv[optind][2] || !my_index (optstring, argv[optind][1])))))
+ {
+ char *nameend;
+ const struct option *p;
+ const struct option *pfound = NULL;
+ int exact = 0;
+ int ambig = 0;
+ int indfound=0; /* Keep gcc happy */
+ int option_index;
+
+ for (nameend = nextchar; *nameend && *nameend != '='; nameend++)
+ /* Do nothing. */ ;
+
+ /* Test all long options for either exact match
+ or abbreviated matches. */
+ for (p = longopts, option_index = 0; p->name; p++, option_index++)
+ if (!strncmp (p->name, nextchar, nameend - nextchar))
+ {
+ if ((size_t) (nameend - nextchar) == (size_t) strlen (p->name))
+ {
+ /* Exact match found. */
+ pfound = p;
+ indfound = option_index;
+ exact = 1;
+ break;
+ }
+ else if (pfound == NULL)
+ {
+ /* First nonexact match found. */
+ pfound = p;
+ indfound = option_index;
+ }
+ else
+ /* Second or later nonexact match found. */
+ ambig = 1;
+ }
+
+ if (ambig && !exact)
+ {
+ if (opterr)
+ fprintf (stderr, "%s: option `%s' is ambiguous\n",
+ argv[0], argv[optind]);
+ nextchar += strlen (nextchar);
+ optind++;
+ return '?';
+ }
+
+ if (pfound != NULL)
+ {
+ option_index = indfound;
+ optind++;
+ if (*nameend)
+ {
+ /* Don't test has_arg with >, because some C compilers don't
+ allow it to be used on enums. */
+ if (pfound->has_arg)
+ optarg = nameend + 1;
+ else
+ {
+ if (opterr)
+ {
+ if (argv[optind - 1][1] == '-')
+ /* --option */
+ fprintf (stderr,
+ "%s: option `--%s' doesn't allow an argument\n",
+ argv[0], pfound->name);
+ else
+ /* +option or -option */
+ fprintf (stderr,
+ "%s: option `%c%s' doesn't allow an argument\n",
+ argv[0], argv[optind - 1][0], pfound->name);
+ }
+ nextchar += strlen (nextchar);
+ return '?';
+ }
+ }
+ else if (pfound->has_arg == 1)
+ {
+ if (optind < argc)
+ optarg = argv[optind++];
+ else
+ {
+ if (opterr)
+ fprintf (stderr, "%s: option `%s' requires an argument\n",
+ argv[0], argv[optind - 1]);
+ nextchar += strlen (nextchar);
+ return optstring[0] == ':' ? ':' : '?';
+ }
+ }
+ nextchar += strlen (nextchar);
+ if (longind != NULL)
+ *longind = option_index;
+ if (pfound->flag)
+ {
+ *(pfound->flag) = pfound->val;
+ return 0;
+ }
+ return pfound->val;
+ }
+
+ /* Can't find it as a long option. If this is not getopt_long_only,
+ or the option starts with '--' or is not a valid short
+ option, then it's an error.
+ Otherwise interpret it as a short option. */
+ if (!long_only || argv[optind][1] == '-'
+ || my_index (optstring, *nextchar) == NULL)
+ {
+ if (opterr)
+ {
+ if (argv[optind][1] == '-')
+ /* --option */
+ fprintf (stderr, "%s: unrecognized option `--%s'\n",
+ argv[0], nextchar);
+ else
+ /* +option or -option */
+ fprintf (stderr, "%s: unrecognized option `%c%s'\n",
+ argv[0], argv[optind][0], nextchar);
+ }
+ nextchar = (char *) "";
+ optind++;
+ return '?';
+ }
+ }
+
+ /* Look at and handle the next short option-character. */
+
+ {
+ char c = *nextchar++;
+ char *temp = my_index (optstring, c);
+
+ /* Increment `optind' when we start to process its last character. */
+ if (*nextchar == '\0')
+ ++optind;
+
+ if (temp == NULL || c == ':')
+ {
+ if (opterr)
+ {
+ if (posixly_correct)
+ /* 1003.2 specifies the format of this message. */
+ fprintf (stderr, "%s: illegal option -- %c\n", argv[0], c);
+ else
+ fprintf (stderr, "%s: invalid option -- %c\n", argv[0], c);
+ }
+ optopt = c;
+ return '?';
+ }
+ if (temp[1] == ':')
+ {
+ if (temp[2] == ':')
+ {
+ /* This is an option that accepts an argument optionally. */
+ if (*nextchar != '\0')
+ {
+ optarg = nextchar;
+ optind++;
+ }
+ else
+ optarg = NULL;
+ nextchar = NULL;
+ }
+ else
+ {
+ /* This is an option that requires an argument. */
+ if (*nextchar != '\0')
+ {
+ optarg = nextchar;
+ /* If we end this ARGV-element by taking the rest as an arg,
+ we must advance to the next element now. */
+ optind++;
+ }
+ else if (optind == argc)
+ {
+ if (opterr)
+ {
+ /* 1003.2 specifies the format of this message. */
+ fprintf (stderr, "%s: option requires an argument -- %c\n",
+ argv[0], c);
+ }
+ optopt = c;
+ if (optstring[0] == ':')
+ c = ':';
+ else
+ c = '?';
+ }
+ else
+ /* We already incremented `optind' once;
+ increment it again when taking next ARGV-elt as argument. */
+ optarg = argv[optind++];
+ nextchar = NULL;
+ }
+ }
+ return c;
+ }
+}
+
+int
+getopt (int argc, char *const *argv, const char *optstring)
+{
+ return _getopt_internal (argc, argv, optstring,
+ (const struct option *) 0,
+ (int *) 0,
+ 0);
+}
+
+#endif /* _LIBC or not __GNU_LIBRARY__. */
+
+#ifdef TEST
+
+/* Compile with -DTEST to make an executable for use in testing
+ the above definition of `getopt'. */
+
+int
+main (argc, argv)
+ int argc;
+ char **argv;
+{
+ int c;
+ int digit_optind = 0;
+
+ while (1)
+ {
+ int this_option_optind = optind ? optind : 1;
+
+ c = getopt (argc, argv, "abc:d:0123456789");
+ if (c == EOF)
+ break;
+
+ switch (c)
+ {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ if (digit_optind != 0 && digit_optind != this_option_optind)
+ printf ("digits occur in two different argv-elements.\n");
+ digit_optind = this_option_optind;
+ printf ("option %c\n", c);
+ break;
+
+ case 'a':
+ printf ("option a\n");
+ break;
+
+ case 'b':
+ printf ("option b\n");
+ break;
+
+ case 'c':
+ printf ("option c with value `%s'\n", optarg);
+ break;
+
+ case '?':
+ break;
+
+ default:
+ printf ("?? getopt returned character code 0%o ??\n", c);
+ }
+ }
+
+ if (optind < argc)
+ {
+ printf ("non-option ARGV-elements: ");
+ while (optind < argc)
+ printf ("%s ", argv[optind++]);
+ printf ("\n");
+ }
+
+ exit (0);
+}
+
+#endif /* TEST */
diff --git a/mysys/getopt1.c b/mysys/getopt1.c
new file mode 100644
index 00000000000..6068a036e7b
--- /dev/null
+++ b/mysys/getopt1.c
@@ -0,0 +1,170 @@
+/* getopt_long and getopt_long_only entry points for GNU getopt.
+ Copyright (C) 1987, 88, 89, 90, 91, 92, 1993, 1994
+ Free Software Foundation, Inc.
+
+This file is part of the GNU C Library. Its master source is NOT part of
+the C library, however. The master source lives in /gd/gnu/lib.
+
+The GNU C Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+The GNU C 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 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. */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <global.h>
+#include "getopt.h"
+
+#if (!defined (__STDC__) || !__STDC__) && !defined(MSDOS)
+/* This is a separate conditional since some stdc systems
+ reject `defined (const)'. */
+#ifndef const
+#define const
+#endif
+#endif
+
+#include <stdio.h>
+
+/* Comment out all this code if we are using the GNU C Library, and are not
+ actually compiling the library itself. This code is part of the GNU C
+ Library, but also included in many other GNU distributions. Compiling
+ and linking in this code is a waste when using the GNU C library
+ (especially if it is a shared library). Rather than having every GNU
+ program understand `configure --with-gnu-libc' and omit the object files,
+ it is simpler to just do this in the source for each such file. */
+
+#if defined (_LIBC) || !defined (__GNU_LIBRARY__)
+
+#ifndef __WIN__
+#include <stdlib.h>
+#endif /* __WIN__ */
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+int
+getopt_long (int argc, char *const *argv, const char *options, const struct option *long_options, int *opt_index)
+{
+ return _getopt_internal (argc, argv, options, long_options, opt_index, 0);
+}
+
+/* Like getopt_long, but '-' as well as '--' can indicate a long option.
+ If an option that starts with '-' (not '--') doesn't match a long option,
+ but does match a short option, it is parsed as a short option
+ instead. */
+
+int
+getopt_long_only (int argc, char *const *argv, const char *options, const struct option *long_options, int *opt_index)
+{
+ return _getopt_internal (argc, argv, options, long_options, opt_index, 1);
+}
+
+
+#endif /* _LIBC or not __GNU_LIBRARY__. */
+
+#ifdef TEST
+
+#include <stdio.h>
+
+int
+main (argc, argv)
+ int argc;
+ char **argv;
+{
+ int c;
+ int digit_optind = 0;
+
+ while (1)
+ {
+ int this_option_optind = optind ? optind : 1;
+ int option_index = 0;
+ static struct option long_options[] =
+ {
+ {"add", 1, 0, 0},
+ {"append", 0, 0, 0},
+ {"delete", 1, 0, 0},
+ {"verbose", 0, 0, 0},
+ {"create", 0, 0, 0},
+ {"file", 1, 0, 0},
+ {0, 0, 0, 0}
+ };
+
+ c = getopt_long (argc, argv, "abc:d:0123456789",
+ long_options, &option_index);
+ if (c == EOF)
+ break;
+
+ switch (c)
+ {
+ case 0:
+ printf ("option %s", long_options[option_index].name);
+ if (optarg)
+ printf (" with arg %s", optarg);
+ printf ("\n");
+ break;
+
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ if (digit_optind != 0 && digit_optind != this_option_optind)
+ printf ("digits occur in two different argv-elements.\n");
+ digit_optind = this_option_optind;
+ printf ("option %c\n", c);
+ break;
+
+ case 'a':
+ printf ("option a\n");
+ break;
+
+ case 'b':
+ printf ("option b\n");
+ break;
+
+ case 'c':
+ printf ("option c with value `%s'\n", optarg);
+ break;
+
+ case 'd':
+ printf ("option d with value `%s'\n", optarg);
+ break;
+
+ case '?':
+ break;
+
+ default:
+ printf ("?? getopt returned character code 0%o ??\n", c);
+ }
+ }
+
+ if (optind < argc)
+ {
+ printf ("non-option ARGV-elements: ");
+ while (optind < argc)
+ printf ("%s ", argv[optind++]);
+ printf ("\n");
+ }
+
+ exit (0);
+}
+
+#endif /* TEST */
diff --git a/mysys/getvar.c b/mysys/getvar.c
new file mode 100644
index 00000000000..1d452002490
--- /dev/null
+++ b/mysys/getvar.c
@@ -0,0 +1,105 @@
+/* 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 */
+
+/* Allow use of the -O variable= option to set long variables */
+
+#include "mysys_priv.h"
+#include <m_string.h>
+#include <m_ctype.h>
+
+ /* set all changeable variables */
+
+void set_all_changeable_vars(CHANGEABLE_VAR *vars)
+{
+ for ( ; vars->name ; vars++)
+ *vars->varptr= vars->def_value;
+}
+
+
+my_bool set_changeable_varval(const char* var, ulong val,
+ CHANGEABLE_VAR *vars)
+{
+ char buffer[256];
+ sprintf( buffer, "%s=%lu", var, (unsigned long) val );
+ return set_changeable_var( buffer, vars );
+}
+
+
+my_bool set_changeable_var(my_string str,CHANGEABLE_VAR *vars)
+{
+ char endchar;
+ my_string end;
+ DBUG_ENTER("set_changeable_var");
+ DBUG_PRINT("enter",("%s",str));
+
+ if (str)
+ {
+ if (!(end=strchr(str,'=')))
+ fprintf(stderr,"Can't find '=' in expression '%s' to option -O\n",str);
+ else
+ {
+ uint length=(uint) (end-str),found_count=0;
+ CHANGEABLE_VAR *var,*found;
+ const char *name;
+ long num;
+
+ for (var=vars,found=0 ; (name=var->name) ; var++)
+ {
+ if (!my_casecmp(name,str,length))
+ {
+ found=var; found_count++;
+ if (!name[length])
+ {
+ found_count=1;
+ break;
+ }
+ }
+ }
+ if (found_count == 0)
+ {
+ fprintf(stderr,"No variable match for: -O '%s'\n",str);
+ DBUG_RETURN(1);
+ }
+ if (found_count > 1)
+ {
+ fprintf(stderr,"Variable prefix '%*s' is not unique\n",length,str);
+ DBUG_RETURN(1);
+ }
+
+ num=(long) atol(end+1); endchar=strend(end+1)[-1];
+ if (endchar == 'k' || endchar == 'K')
+ num*=1024;
+ else if (endchar == 'm' || endchar == 'M')
+ num*=1024L*1024L;
+ else if (!isdigit(endchar))
+ {
+ fprintf(stderr,"Unknown prefix used for variable value '%s'\n",str);
+ DBUG_RETURN(1);
+ }
+ if (num < (long) found->min_value)
+ num=(long) found->min_value;
+ else if ((unsigned long) num >
+ (unsigned long) found->max_value)
+ num=(long) found->max_value;
+ *found->varptr=(long) ((ulong) (num-found->sub_size) /
+ (ulong) found->block_size);
+ (*found->varptr)*= (ulong) found->block_size;
+ DBUG_RETURN(0);
+ }
+ }
+ DBUG_RETURN(1);
+}
diff --git a/mysys/hash.c b/mysys/hash.c
new file mode 100644
index 00000000000..a6181443a42
--- /dev/null
+++ b/mysys/hash.c
@@ -0,0 +1,586 @@
+/* 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 */
+
+/* The hash functions used for saveing keys */
+/* One of key_length or key_length_offset must be given */
+/* Key length of 0 isn't allowed */
+
+#include "mysys_priv.h"
+#include <m_string.h>
+#include <m_ctype.h>
+#include "hash.h"
+
+#define NO_RECORD ((uint) -1)
+#define LOWFIND 1
+#define LOWUSED 2
+#define HIGHFIND 4
+#define HIGHUSED 8
+
+static uint hash_mask(uint hashnr,uint buffmax,uint maxlength);
+static void movelink(HASH_LINK *array,uint pos,uint next_link,uint newlink);
+static uint calc_hashnr(const byte *key,uint length);
+static uint calc_hashnr_caseup(const byte *key,uint length);
+static int hashcmp(HASH *hash,HASH_LINK *pos,const byte *key,uint length);
+
+
+my_bool hash_init(HASH *hash,uint size,uint key_offset,uint key_length,
+ hash_get_key get_key,
+ void (*free_element)(void*),uint flags)
+{
+ DBUG_ENTER("hash_init");
+ DBUG_PRINT("enter",("hash: %lx size: %d",hash,size));
+
+ hash->records=0;
+ if (init_dynamic_array(&hash->array,sizeof(HASH_LINK),size,0))
+ {
+ hash->free=0; /* Allow call to hash_free */
+ DBUG_RETURN(TRUE);
+ }
+ hash->key_offset=key_offset;
+ hash->key_length=key_length;
+ hash->blength=1;
+ hash->current_record= NO_RECORD; /* For the future */
+ hash->get_key=get_key;
+ hash->free=free_element;
+ hash->flags=flags;
+ if (flags & HASH_CASE_INSENSITIVE)
+ hash->calc_hashnr=calc_hashnr_caseup;
+ else
+ hash->calc_hashnr=calc_hashnr;
+ DBUG_RETURN(0);
+}
+
+
+void hash_free(HASH *hash)
+{
+ DBUG_ENTER("hash_free");
+ if (hash->free)
+ {
+ uint i,records;
+ HASH_LINK *data=dynamic_element(&hash->array,0,HASH_LINK*);
+ for (i=0,records=hash->records ; i < records ; i++)
+ (*hash->free)(data[i].data);
+ hash->free=0;
+ }
+ delete_dynamic(&hash->array);
+ hash->records=0;
+ DBUG_VOID_RETURN;
+}
+
+ /* some helper functions */
+
+static inline byte*
+hash_key(HASH *hash,const byte *record,uint *length,my_bool first)
+{
+ if (hash->get_key)
+ return (*hash->get_key)(record,length,first);
+ *length=hash->key_length;
+ return (byte*) record+hash->key_offset;
+}
+
+ /* Calculate pos according to keys */
+
+static uint hash_mask(uint hashnr,uint buffmax,uint maxlength)
+{
+ if ((hashnr & (buffmax-1)) < maxlength) return (hashnr & (buffmax-1));
+ return (hashnr & ((buffmax >> 1) -1));
+}
+
+static uint hash_rec_mask(HASH *hash,HASH_LINK *pos,uint buffmax,
+ uint maxlength)
+{
+ uint length;
+ byte *key=hash_key(hash,pos->data,&length,0);
+ return hash_mask((*hash->calc_hashnr)(key,length),buffmax,maxlength);
+}
+
+ /* Calc hashvalue for a key */
+
+static uint calc_hashnr(const byte *key,uint length)
+{
+ register uint nr=1, nr2=4;
+ while (length--)
+ {
+ nr^= (((nr & 63)+nr2)*((uint) (uchar) *key++))+ (nr << 8);
+ nr2+=3;
+ }
+ return((uint) nr);
+}
+
+ /* Calc hashvalue for a key, case indepenently */
+
+static uint calc_hashnr_caseup(const byte *key,uint length)
+{
+ register uint nr=1, nr2=4;
+ while (length--)
+ {
+ nr^= (((nr & 63)+nr2)*((uint) (uchar) toupper(*key++)))+ (nr << 8);
+ nr2+=3;
+ }
+ return((uint) nr);
+}
+
+
+static inline uint rec_hashnr(HASH *hash,const byte *record)
+{
+ uint length;
+ byte *key=hash_key(hash,record,&length,0);
+ return (*hash->calc_hashnr)(key,length);
+}
+
+
+ /* Search after a record based on a key */
+ /* Sets info->current_ptr to found record */
+
+gptr hash_search(HASH *hash,const byte *key,uint length)
+{
+ HASH_LINK *pos;
+ uint flag,idx;
+ DBUG_ENTER("hash_search");
+
+ flag=1;
+ if (hash->records)
+ {
+ idx=hash_mask((*hash->calc_hashnr)(key,length ? length :
+ hash->key_length),
+ hash->blength,hash->records);
+ do
+ {
+ pos= dynamic_element(&hash->array,idx,HASH_LINK*);
+ if (!hashcmp(hash,pos,key,length))
+ {
+ DBUG_PRINT("exit",("found key at %d",idx));
+ hash->current_record= idx;
+ DBUG_RETURN (pos->data);
+ }
+ if (flag)
+ {
+ flag=0; /* Reset flag */
+ if (hash_rec_mask(hash,pos,hash->blength,hash->records) != idx)
+ break; /* Wrong link */
+ }
+ }
+ while ((idx=pos->next) != NO_RECORD);
+ }
+ hash->current_record= NO_RECORD;
+ DBUG_RETURN(0);
+}
+
+ /* Get next record with identical key */
+ /* Can only be called if previous calls was hash_search */
+
+gptr hash_next(HASH *hash,const byte *key,uint length)
+{
+ HASH_LINK *pos;
+ uint idx;
+
+ if (hash->current_record != NO_RECORD)
+ {
+ HASH_LINK *data=dynamic_element(&hash->array,0,HASH_LINK*);
+ for (idx=data[hash->current_record].next; idx != NO_RECORD ; idx=pos->next)
+ {
+ pos=data+idx;
+ if (!hashcmp(hash,pos,key,length))
+ {
+ hash->current_record= idx;
+ return pos->data;
+ }
+ }
+ hash->current_record=NO_RECORD;
+ }
+ return 0;
+}
+
+
+ /* Change link from pos to new_link */
+
+static void movelink(HASH_LINK *array,uint find,uint next_link,uint newlink)
+{
+ HASH_LINK *old_link;
+ do
+ {
+ old_link=array+next_link;
+ }
+ while ((next_link=old_link->next) != find);
+ old_link->next= newlink;
+ return;
+}
+
+ /* Compare a key in a record to a whole key. Return 0 if identical */
+
+static int hashcmp(HASH *hash,HASH_LINK *pos,const byte *key,uint length)
+{
+ uint rec_keylength;
+ byte *rec_key=hash_key(hash,pos->data,&rec_keylength,1);
+ return (length && length != rec_keylength) ||
+ (hash->flags & HASH_CASE_INSENSITIVE ?
+ my_casecmp(rec_key,key,rec_keylength) :
+ memcmp(rec_key,key,rec_keylength));
+}
+
+
+ /* Write a hash-key to the hash-index */
+
+my_bool hash_insert(HASH *info,const byte *record)
+{
+ int flag;
+ uint halfbuff,hash_nr,first_index,idx;
+ byte *ptr_to_rec,*ptr_to_rec2;
+ HASH_LINK *data,*empty,*gpos,*gpos2,*pos;
+
+ LINT_INIT(gpos); LINT_INIT(gpos2);
+ LINT_INIT(ptr_to_rec); LINT_INIT(ptr_to_rec2);
+
+ flag=0;
+ if (!(empty=(HASH_LINK*) alloc_dynamic(&info->array)))
+ return(TRUE); /* No more memory */
+
+ info->current_record= NO_RECORD;
+ data=dynamic_element(&info->array,0,HASH_LINK*);
+ halfbuff= info->blength >> 1;
+
+ idx=first_index=info->records-halfbuff;
+ if (idx != info->records) /* If some records */
+ {
+ do
+ {
+ pos=data+idx;
+ hash_nr=rec_hashnr(info,pos->data);
+ if (flag == 0) /* First loop; Check if ok */
+ if (hash_mask(hash_nr,info->blength,info->records) != first_index)
+ break;
+ if (!(hash_nr & halfbuff))
+ { /* Key will not move */
+ if (!(flag & LOWFIND))
+ {
+ if (flag & HIGHFIND)
+ {
+ flag=LOWFIND | HIGHFIND;
+ /* key shall be moved to the current empty position */
+ gpos=empty;
+ ptr_to_rec=pos->data;
+ empty=pos; /* This place is now free */
+ }
+ else
+ {
+ flag=LOWFIND | LOWUSED; /* key isn't changed */
+ gpos=pos;
+ ptr_to_rec=pos->data;
+ }
+ }
+ else
+ {
+ if (!(flag & LOWUSED))
+ {
+ /* Change link of previous LOW-key */
+ gpos->data=ptr_to_rec;
+ gpos->next=(uint) (pos-data);
+ flag= (flag & HIGHFIND) | (LOWFIND | LOWUSED);
+ }
+ gpos=pos;
+ ptr_to_rec=pos->data;
+ }
+ }
+ else
+ { /* key will be moved */
+ if (!(flag & HIGHFIND))
+ {
+ flag= (flag & LOWFIND) | HIGHFIND;
+ /* key shall be moved to the last (empty) position */
+ gpos2 = empty; empty=pos;
+ ptr_to_rec2=pos->data;
+ }
+ else
+ {
+ if (!(flag & HIGHUSED))
+ {
+ /* Change link of previous hash-key and save */
+ gpos2->data=ptr_to_rec2;
+ gpos2->next=(uint) (pos-data);
+ flag= (flag & LOWFIND) | (HIGHFIND | HIGHUSED);
+ }
+ gpos2=pos;
+ ptr_to_rec2=pos->data;
+ }
+ }
+ }
+ while ((idx=pos->next) != NO_RECORD);
+
+ if ((flag & (LOWFIND | LOWUSED)) == LOWFIND)
+ {
+ gpos->data=ptr_to_rec;
+ gpos->next=NO_RECORD;
+ }
+ if ((flag & (HIGHFIND | HIGHUSED)) == HIGHFIND)
+ {
+ gpos2->data=ptr_to_rec2;
+ gpos2->next=NO_RECORD;
+ }
+ }
+ /* Check if we are at the empty position */
+
+ idx=hash_mask(rec_hashnr(info,record),info->blength,info->records+1);
+ pos=data+idx;
+ if (pos == empty)
+ {
+ pos->data=(byte*) record;
+ pos->next=NO_RECORD;
+ }
+ else
+ {
+ /* Check if more records in same hash-nr family */
+ empty[0]=pos[0];
+ gpos=data+hash_rec_mask(info,pos,info->blength,info->records+1);
+ if (pos == gpos)
+ {
+ pos->data=(byte*) record;
+ pos->next=(uint) (empty - data);
+ }
+ else
+ {
+ pos->data=(byte*) record;
+ pos->next=NO_RECORD;
+ movelink(data,(uint) (pos-data),(uint) (gpos-data),(uint) (empty-data));
+ }
+ }
+ if (++info->records == info->blength)
+ info->blength+= info->blength;
+ return(0);
+}
+
+
+/******************************************************************************
+** Remove one record from hash-table. The record with the same record
+** ptr is removed.
+** if there is a free-function it's called for record if found
+******************************************************************************/
+
+my_bool hash_delete(HASH *hash,byte *record)
+{
+ uint blength,pos2,pos_hashnr,lastpos_hashnr,idx,empty_index;
+ HASH_LINK *data,*lastpos,*gpos,*pos,*pos3,*empty;
+ DBUG_ENTER("hash_delete");
+
+ blength=hash->blength;
+ data=dynamic_element(&hash->array,0,HASH_LINK*);
+
+ /* Search after record with key */
+ pos=data+ hash_mask(rec_hashnr(hash,record),blength,hash->records);
+ gpos = 0;
+
+ while (pos->data != record)
+ {
+ gpos=pos;
+ if (pos->next == NO_RECORD)
+ DBUG_RETURN(1); /* Key not found */
+ pos=data+pos->next;
+ }
+
+ if ( --(hash->records) < hash->blength >> 1) hash->blength>>=1;
+ hash->current_record= NO_RECORD;
+ lastpos=data+hash->records;
+
+ /* Remove link to record */
+ empty=pos; empty_index=(uint) (empty-data);
+ if (gpos)
+ gpos->next=pos->next; /* unlink current ptr */
+ else if (pos->next != NO_RECORD)
+ {
+ empty=data+(empty_index=pos->next);
+ pos->data=empty->data;
+ pos->next=empty->next;
+ }
+
+ if (empty == lastpos) /* last key at wrong pos or no next link */
+ goto exit;
+
+ /* Move the last key (lastpos) */
+ lastpos_hashnr=rec_hashnr(hash,lastpos->data);
+ /* pos is where lastpos should be */
+ pos=data+hash_mask(lastpos_hashnr,hash->blength,hash->records);
+ if (pos == empty) /* Move to empty position. */
+ {
+ empty[0]=lastpos[0];
+ goto exit;
+ }
+ pos_hashnr=rec_hashnr(hash,pos->data);
+ /* pos3 is where the pos should be */
+ pos3= data+hash_mask(pos_hashnr,hash->blength,hash->records);
+ if (pos != pos3)
+ { /* pos is on wrong posit */
+ empty[0]=pos[0]; /* Save it here */
+ pos[0]=lastpos[0]; /* This should be here */
+ movelink(data,(uint) (pos-data),(uint) (pos3-data),empty_index);
+ goto exit;
+ }
+ pos2= hash_mask(lastpos_hashnr,blength,hash->records+1);
+ if (pos2 == hash_mask(pos_hashnr,blength,hash->records+1))
+ { /* Identical key-positions */
+ if (pos2 != hash->records)
+ {
+ empty[0]=lastpos[0];
+ movelink(data,(uint) (lastpos-data),(uint) (pos-data),empty_index);
+ goto exit;
+ }
+ idx= (uint) (pos-data); /* Link pos->next after lastpos */
+ }
+ else idx= NO_RECORD; /* Different positions merge */
+
+ empty[0]=lastpos[0];
+ movelink(data,idx,empty_index,pos->next);
+ pos->next=empty_index;
+
+exit:
+ VOID(pop_dynamic(&hash->array));
+ if (hash->free)
+ (*hash->free)((byte*) record);
+ DBUG_RETURN(0);
+}
+
+ /*
+ Update keys when record has changed.
+ This is much more efficent than using a delete & insert.
+ */
+
+my_bool hash_update(HASH *hash,byte *record,byte *old_key,uint old_key_length)
+{
+ uint idx,new_index,new_pos_index,blength,records,empty;
+ HASH_LINK org_link,*data,*previous,*pos;
+ DBUG_ENTER("hash_update");
+
+ data=dynamic_element(&hash->array,0,HASH_LINK*);
+ blength=hash->blength; records=hash->records;
+
+ /* Search after record with key */
+
+ idx=hash_mask((*hash->calc_hashnr)(old_key,(old_key_length ?
+ old_key_length :
+ hash->key_length)),
+ blength,records);
+ new_index=hash_mask(rec_hashnr(hash,record),blength,records);
+ if (idx == new_index)
+ DBUG_RETURN(0); /* Nothing to do (No record check) */
+ previous=0;
+ for (;;)
+ {
+
+ if ((pos= data+idx)->data == record)
+ break;
+ previous=pos;
+ if ((idx=pos->next) == NO_RECORD)
+ DBUG_RETURN(1); /* Not found in links */
+ }
+ hash->current_record= NO_RECORD;
+ org_link= *pos;
+ empty=idx;
+
+ /* Relink record from current chain */
+
+ if (!previous)
+ {
+ if (pos->next != NO_RECORD)
+ {
+ empty=pos->next;
+ *pos= data[pos->next];
+ }
+ }
+ else
+ previous->next=pos->next; /* unlink pos */
+
+ /* Move data to correct position */
+ pos=data+new_index;
+ new_pos_index=hash_rec_mask(hash,pos,blength,records);
+ if (new_index != new_pos_index)
+ { /* Other record in wrong position */
+ data[empty] = *pos;
+ movelink(data,new_index,new_pos_index,empty);
+ org_link.next=NO_RECORD;
+ data[new_index]= org_link;
+ }
+ else
+ { /* Link in chain at right position */
+ org_link.next=data[new_index].next;
+ data[empty]=org_link;
+ data[new_index].next=empty;
+ }
+ DBUG_RETURN(0);
+}
+
+
+byte *hash_element(HASH *hash,uint idx)
+{
+ if (idx < hash->records)
+ return dynamic_element(&hash->array,idx,HASH_LINK*)->data;
+ return 0;
+}
+
+
+#ifndef DBUG_OFF
+
+my_bool hash_check(HASH *hash)
+{
+ int error;
+ uint i,rec_link,found,max_links,seek,links,idx;
+ uint records,blength;
+ HASH_LINK *data,*hash_info;
+
+ records=hash->records; blength=hash->blength;
+ data=dynamic_element(&hash->array,0,HASH_LINK*);
+ error=0;
+
+ for (i=found=max_links=seek=0 ; i < records ; i++)
+ {
+ if (hash_rec_mask(hash,data+i,blength,records) == i)
+ {
+ found++; seek++; links=1;
+ for (idx=data[i].next ;
+ idx != NO_RECORD && found < records + 1;
+ idx=hash_info->next)
+ {
+ if (idx >= records)
+ {
+ DBUG_PRINT("error",
+ ("Found pointer outside array to %d from link starting at %d",
+ idx,i));
+ error=1;
+ }
+ hash_info=data+idx;
+ seek+= ++links;
+ if ((rec_link=hash_rec_mask(hash,hash_info,blength,records)) != i)
+ {
+ DBUG_PRINT("error",
+ ("Record in wrong link at %d: Start %d Record: %lx Record-link %d", idx,i,hash_info->data,rec_link));
+ error=1;
+ }
+ else
+ found++;
+ }
+ if (links > max_links) max_links=links;
+ }
+ }
+ if (found != records)
+ {
+ DBUG_PRINT("error",("Found %ld of %ld records"));
+ error=1;
+ }
+ if (records)
+ DBUG_PRINT("info",
+ ("records: %ld seeks: %d max links: %d hitrate: %.2f",
+ records,seek,max_links,(float) seek / (float) records));
+ return error;
+}
+#endif
diff --git a/mysys/list.c b/mysys/list.c
new file mode 100644
index 00000000000..0a6d900d6b9
--- /dev/null
+++ b/mysys/list.c
@@ -0,0 +1,116 @@
+/* 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 */
+
+/*
+ Code for handling dubble-linked lists in C
+*/
+
+#include "mysys_priv.h"
+#include <my_list.h>
+
+
+
+ /* Add a element to start of list */
+
+LIST *list_add(LIST *root, LIST *element)
+{
+ DBUG_ENTER("list_add");
+ DBUG_PRINT("enter",("root: %lx element: %lx", root, element));
+ if (root)
+ {
+ if (root->prev) /* If add in mid of list */
+ root->prev->next= element;
+ element->prev=root->prev;
+ root->prev=element;
+ }
+ else
+ element->prev=0;
+ element->next=root;
+ DBUG_RETURN(element); /* New root */
+}
+
+
+LIST *list_delete(LIST *root, LIST *element)
+{
+ if (element->prev)
+ element->prev->next=element->next;
+ else
+ root=element->next;
+ if (element->next)
+ element->next->prev=element->prev;
+ return root;
+}
+
+
+void list_free(LIST *root, pbool free_data)
+{
+ LIST *next;
+ while (root)
+ {
+ next=root->next;
+ if (free_data)
+ my_free((gptr) root->data,MYF(0));
+ my_free((gptr) root,MYF(0));
+ root=next;
+ }
+}
+
+
+LIST *list_cons(void *data, LIST *list)
+{
+ LIST *new=(LIST*) my_malloc(sizeof(LIST),MYF(MY_FAE));
+ if (!new)
+ return 0;
+ new->data=data;
+ return list_add(list,new);
+}
+
+
+LIST *list_reverse(LIST *root)
+{
+ LIST *last;
+
+ last=root;
+ while (root)
+ {
+ last=root;
+ root=root->next;
+ last->next=last->prev;
+ last->prev=root;
+ }
+ return last;
+}
+
+uint list_length(LIST *list)
+{
+ uint count;
+ for (count=0 ; list ; list=list->next, count++) ;
+ return count;
+}
+
+
+int list_walk(LIST *list, list_walk_action action, gptr argument)
+{
+ int error=0;
+ while (list)
+ {
+ if ((error = (*action)(list->data,argument)))
+ return error;
+ list=rest(list);
+ }
+ return 0;
+}
diff --git a/mysys/make-ccc b/mysys/make-ccc
new file mode 100755
index 00000000000..9c54185682a
--- /dev/null
+++ b/mysys/make-ccc
@@ -0,0 +1,4 @@
+rm -f .deps/* raid.o mf_iocache.o libmysys.a
+ccc -DDEFAULT_BASEDIR="\"/usr/local/mysql\"" -DDATADIR="\"/usr/local/mysql/var\"" -DHAVE_CONFIG_H -I./../include -I../include -I.. -DDBUG_OFF -fast -O3 -fomit-frame-pointer -c array.c checksum.c default.c errors.c getopt.c getopt1.c getvar.c hash.c list.c mf_brkhant.c mf_cache.c mf_casecnv.c mf_dirname.c mf_fn_ext.c mf_format.c mf_getdate.c mf_keycache.c mf_loadpath.c mf_pack.c mf_pack2.c mf_path.c mf_qsort.c mf_qsort2.c mf_radix.c mf_reccache.c mf_same.c mf_sort.c mf_soundex.c mf_stripp.c mf_unixpath.c mf_wcomp.c mf_wfile.c mulalloc.c my_alarm.c my_alloc.c my_append.c my_chsize.c my_clock.c my_compress.c my_copy.c my_create.c my_delete.c my_div.c my_error.c my_fopen.c my_fstream.c my_getwd.c my_init.c my_lib.c my_lockmem.c my_lread.c my_lwrite.c my_malloc.c my_messnc.c my_mkdir.c my_net.c my_once.c my_open.c my_pread.c my_pthread.c my_quick.c my_read.c my_realloc.c my_redel.c my_rename.c my_seek.c my_static.c my_tempnam.c my_thr_init.c my_write.c ptr_cmp.c queues.c safemalloc.c string.c thr_alarm.c thr_lock.c thr_mutex.c thr_rwlock.c tree.c typelib.c
+make raid.o mf_iocache.o my_lock.o
+ar -cr libmysys.a array.o raid.o mf_iocache.o my_lock.o
diff --git a/mysys/make-conf.c b/mysys/make-conf.c
new file mode 100644
index 00000000000..9db766574e2
--- /dev/null
+++ b/mysys/make-conf.c
@@ -0,0 +1,73 @@
+/* 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 */
+
+/* make-conf.c
+ * make a charset .conf file out of a ctype-charset.c file.
+ */
+
+#ifndef CHARSET
+#error You must define the charset, e.g.: -DCHARSET=latin1
+#endif
+
+/* some pre-processor tricks to get us going */
+#define _STRINGIZE_HELPER(x) #x
+#define STRINGIZE(x) _STRINGIZE_HELPER(x)
+
+#define _JOIN_WORDS_HELPER(a, b) a ## b
+#define JOIN_WORDS(a, b) _JOIN_WORDS_HELPER(a, b)
+
+#define CH_SRC ctype- ## CHARSET ## .c
+#define CH_INCLUDE STRINGIZE(CH_SRC)
+
+/* aaaah, that's better */
+#include <my_global.h>
+#include CH_INCLUDE
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#define ROW_LEN 16
+
+void print_array(const char *name, const uchar *array, uint size);
+
+int main(void)
+{
+ printf("# Configuration file for the "
+ STRINGIZE(CHARSET)
+ " character set.\n");
+
+ print_array("ctype", JOIN_WORDS(ctype_, CHARSET), 257);
+ print_array("to_lower", JOIN_WORDS(to_lower_, CHARSET), 256);
+ print_array("to_upper", JOIN_WORDS(to_upper_, CHARSET), 256);
+ print_array("sort_order", JOIN_WORDS(sort_order_, CHARSET), 256);
+
+ exit(EXIT_SUCCESS);
+}
+
+void print_array(const char *name, const uchar *array, uint size)
+{
+ uint i;
+
+ printf("\n# The %s array must have %d elements.\n", name, size);
+
+ for (i = 0; i < size; ++i) {
+ printf(" %02X", array[i]);
+
+ if ((i+1) % ROW_LEN == size % ROW_LEN)
+ printf("\n");
+ }
+}
diff --git a/mysys/mf_brkhant.c b/mysys/mf_brkhant.c
new file mode 100644
index 00000000000..4e4bc2410f9
--- /dev/null
+++ b/mysys/mf_brkhant.c
@@ -0,0 +1,76 @@
+/* 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 */
+
+/* Dont let the user break when you are doing something important */
+/* Remembers if it got 'SIGINT' and executes it on allow_break */
+/* A static buffer is used; don't call dont_break() twice in a row */
+
+#include "mysys_priv.h"
+#include "my_static.h"
+
+ /* Set variable that we can't break */
+
+void dont_break(void)
+{
+#if !defined(THREAD)
+ my_dont_interrupt=1;
+#endif
+ return;
+} /* dont_break */
+
+void allow_break(void)
+{
+#if !defined(THREAD)
+ {
+ reg1 int index;
+
+ my_dont_interrupt=0;
+ if (_my_signals)
+ {
+ if (_my_signals > MAX_SIGNALS)
+ _my_signals=MAX_SIGNALS;
+ for (index=0 ; index < _my_signals ; index++)
+ {
+ if (_my_sig_remember[index].func) /* Safequard */
+ {
+ (*_my_sig_remember[index].func)(_my_sig_remember[index].number);
+ _my_sig_remember[index].func=0;
+ }
+ }
+ _my_signals=0;
+ }
+ }
+#endif
+} /* dont_break */
+
+ /* Set old status */
+
+#if !defined(THREAD)
+void my_remember_signal(int signal_number, sig_handler (*func) (int))
+{
+#ifndef __WIN__
+ reg1 int index;
+
+ index=_my_signals++; /* Nobody can break a ++ ? */
+ if (index < MAX_SIGNALS)
+ {
+ _my_sig_remember[index].number=signal_number;
+ _my_sig_remember[index].func=func;
+ }
+#endif /* __WIN__ */
+} /* my_remember_signal */
+#endif /* THREAD */
diff --git a/mysys/mf_cache.c b/mysys/mf_cache.c
new file mode 100644
index 00000000000..c40cfa386d3
--- /dev/null
+++ b/mysys/mf_cache.c
@@ -0,0 +1,83 @@
+/* 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 */
+
+/* Open a temporary file and cache it with io_cache. Delete it on close */
+
+#include "mysys_priv.h"
+
+ /*
+ ** Open a cached tempfile by IO_CACHE
+ ** Should be used when no seeks are done (only reinit_io_buff)
+ ** Return 0 if cache is inited ok
+ ** The actual file is created when the IO_CACHE buffer gets filled
+ */
+
+my_bool open_cached_file(IO_CACHE *cache, const char* dir, const char *prefix,
+ uint cache_size, myf cache_myflags)
+{
+ DBUG_ENTER("open_cached_file");
+
+ cache->buffer=0; /* Mark that not open */
+ if (!(cache->file_name=my_tempnam(dir,prefix,MYF(MY_WME))))
+ DBUG_RETURN(1);
+ if (!init_io_cache(cache,-1,cache_size,WRITE_CACHE,0L,0,
+ MYF(cache_myflags | MY_NABP)))
+ {
+ DBUG_RETURN(0);
+ }
+ (*free)(cache->file_name); /* my_tempnam uses malloc() */
+ cache->file_name=0;
+ DBUG_RETURN(0);
+}
+
+
+my_bool real_open_cached_file(IO_CACHE *cache)
+{
+ DBUG_ENTER("real_open_cached_file");
+ if ((cache->file=my_create(cache->file_name,0,
+ (int) (O_RDWR | O_BINARY | O_TRUNC | O_TEMPORARY |
+ O_SHORT_LIVED),
+ MYF(MY_WME))) >= 0)
+ {
+#if O_TEMPORARY == 0 && !defined(CANT_DELETE_OPEN_FILES)
+ VOID(my_delete(cache->file_name,MYF(MY_WME | ME_NOINPUT)));
+#endif
+ DBUG_RETURN(0);
+ }
+ DBUG_RETURN(1);
+}
+
+
+void close_cached_file(IO_CACHE *cache)
+{
+ DBUG_ENTER("close_cached_file");
+
+ if (my_b_inited(cache))
+ {
+ VOID(end_io_cache(cache));
+ if (cache->file >= 0)
+ {
+ VOID(my_close(cache->file,MYF(MY_WME)));
+#ifdef CANT_DELETE_OPEN_FILES
+ VOID(my_delete(cache->file_name,MYF(MY_WME | ME_NOINPUT)));
+#endif
+ }
+ if (cache->file_name)
+ (*free)(cache->file_name); /* my_tempnam uses malloc() */
+ }
+ DBUG_VOID_RETURN;
+}
diff --git a/mysys/mf_casecnv.c b/mysys/mf_casecnv.c
new file mode 100644
index 00000000000..705e1361937
--- /dev/null
+++ b/mysys/mf_casecnv.c
@@ -0,0 +1,252 @@
+/* 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 */
+
+/*
+ Functions to convert to lover_case and to upper_case in scandinavia.
+
+ case_sort converts a character string to a representaion that can
+ be compared by strcmp to find with is alfabetical bigger.
+ (lower- and uppercase letters is compared as the same)
+*/
+
+#include "mysys_priv.h"
+#include <m_ctype.h>
+
+ /* string to uppercase */
+
+void caseup_str(my_string str)
+{
+#ifdef USE_MB
+ register uint32 l;
+ register char *end=str+strlen(str);
+ if (use_mb(default_charset_info))
+ while (*str)
+ {
+ if ((l=my_ismbchar(default_charset_info, str,end))) str+=l;
+ else *str=toupper(*str),++str;
+ }
+ else
+#endif
+ while ((*str = toupper(*str)) != 0)
+ str++;
+} /* caseup_str */
+
+ /* string to lowercase */
+
+void casedn_str(my_string str)
+{
+#ifdef USE_MB
+ register uint32 l;
+ register char *end=str+strlen(str);
+ if (use_mb(default_charset_info))
+ while (*str)
+ {
+ if ((l=my_ismbchar(default_charset_info, str,end))) str+=l;
+ else *str=tolower(*str),++str;
+ }
+ else
+#endif
+ while ((*str= tolower(*str)) != 0)
+ str++;
+} /* casedn_str */
+
+
+ /* to uppercase */
+
+void caseup(my_string str, uint length)
+{
+#ifdef USE_MB
+ register uint32 l;
+ register char *end=str+length;
+ if (use_mb(default_charset_info))
+ while (str<end)
+ {
+ if ((l=my_ismbchar(default_charset_info, str,end))) str+=l;
+ else *str=toupper(*str),++str;
+ }
+ else
+#endif
+ for ( ; length>0 ; length--, str++)
+ *str= toupper(*str);
+} /* caseup */
+
+ /* to lowercase */
+
+void casedn(my_string str, uint length)
+{
+#ifdef USE_MB
+ register uint32 l;
+ register char *end=str+length;
+ if (use_mb(default_charset_info))
+ while (str<end)
+ {
+ if ((l=my_ismbchar(default_charset_info, str,end))) str+=l;
+ else *str=tolower(*str),++str;
+ }
+ else
+#endif
+ for ( ; length>0 ; length--, str++)
+ *str= tolower(*str);
+} /* casedn */
+
+ /* to sort-string that can be compared to get text in order */
+
+void case_sort(my_string str, uint length)
+{
+ for ( ; length>0 ; length--, str++)
+ *str= (char) my_sort_order[(uchar) *str];
+} /* case_sort */
+
+ /* find string in another with no case_sensivity */
+
+/* ToDo: This function should be modified to support multibyte charset.
+ However it is not used untill 3.23.5.
+ Wei He (hewei@mail.ied.ac.cn)
+*/
+
+my_string my_strcasestr(const char *str, const char *search)
+{
+ uchar *i,*j,*pos;
+
+ pos=(uchar*) str;
+skipp:
+ while (*pos != '\0')
+ {
+ if (toupper((uchar) *pos++) == toupper((uchar) *search))
+ {
+ i=(uchar*) pos; j=(uchar*) search+1;
+ while (*j)
+ if (toupper(*i++) != toupper(*j++)) goto skipp;
+ return ((char*) pos-1);
+ }
+ }
+ return ((my_string) 0);
+} /* strcstr */
+
+
+ /* compare strings without regarding to case */
+
+int my_strcasecmp(const char *s, const char *t)
+{
+#ifdef USE_MB
+ register uint32 l;
+ register const char *end=s+strlen(s);
+ if (use_mb(default_charset_info))
+ {
+ while (s<end)
+ {
+ if ((l=my_ismbchar(default_charset_info, s,end)))
+ {
+ while (l--)
+ if (*s++ != *t++) return 1;
+ }
+ else if (my_ismbhead(default_charset_info, *t)) return 1;
+ else if (toupper((uchar) *s++) != toupper((uchar) *t++)) return 1;
+ }
+ return *t;
+ }
+ else
+#endif
+ {
+ while (toupper((uchar) *s) == toupper((uchar) *t++))
+ if (!*s++) return 0;
+ return ((int) toupper((uchar) s[0]) - (int) toupper((uchar) t[-1]));
+ }
+}
+
+
+int my_casecmp(const char *s, const char *t, uint len)
+{
+#ifdef USE_MB
+ register uint32 l;
+ register const char *end=s+len;
+ if (use_mb(default_charset_info))
+ {
+ while (s<end)
+ {
+ if ((l=my_ismbchar(default_charset_info, s,end)))
+ {
+ while (l--)
+ if (*s++ != *t++) return 1;
+ }
+ else if (my_ismbhead(default_charset_info, *t)) return 1;
+ else if (toupper((uchar) *s++) != toupper((uchar) *t++)) return 1;
+ }
+ return 0;
+ }
+ else
+#endif
+ {
+ while (len-- != 0 && toupper(*s++) == toupper(*t++)) ;
+ return (int) len+1;
+ }
+}
+
+
+int my_strsortcmp(const char *s, const char *t)
+{
+#ifdef USE_STRCOLL
+ if (use_strcoll(default_charset_info))
+ return my_strcoll(default_charset_info, (uchar *)s, (uchar *)t);
+ else
+#endif
+ {
+ while (my_sort_order[(uchar) *s] == my_sort_order[(uchar) *t++])
+ if (!*s++) return 0;
+ return ((int) my_sort_order[(uchar) s[0]] -
+ (int) my_sort_order[(uchar) t[-1]]);
+ }
+}
+
+int my_sortcmp(const char *s, const char *t, uint len)
+{
+#ifdef USE_STRCOLL
+ if (use_strcoll(default_charset_info))
+ return my_strnncoll(default_charset_info,
+ (uchar *)s, len, (uchar *)t, len);
+ else
+#endif
+ {
+ while (len--)
+ {
+ if (my_sort_order[(uchar) *s++] != my_sort_order[(uchar) *t++])
+ return ((int) my_sort_order[(uchar) s[-1]] -
+ (int) my_sort_order[(uchar) t[-1]]);
+ }
+ return 0;
+ }
+}
+
+int my_sortncmp(const char *s, uint s_len, const char *t, uint t_len)
+{
+#ifdef USE_STRCOLL
+ if (use_strcoll(default_charset_info))
+ return my_strnncoll(default_charset_info,
+ (uchar *)s, s_len, (uchar *)t, t_len);
+ else
+#endif
+ {
+ uint len= min(s_len,t_len);
+ while (len--)
+ {
+ if (my_sort_order[(uchar) *s++] != my_sort_order[(uchar) *t++])
+ return ((int) my_sort_order[(uchar) s[-1]] -
+ (int) my_sort_order[(uchar) t[-1]]);
+ }
+ return (int) (s_len - t_len);
+ }
+}
diff --git a/mysys/mf_dirname.c b/mysys/mf_dirname.c
new file mode 100644
index 00000000000..1bd6d256cfe
--- /dev/null
+++ b/mysys/mf_dirname.c
@@ -0,0 +1,106 @@
+/* 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>
+
+ /* Functions definied in this file */
+
+uint dirname_length(const char *name)
+{
+ register my_string pos,gpos;
+#ifdef FN_DEVCHAR
+ if ((pos=strrchr(name,FN_DEVCHAR)) == 0)
+#endif
+ pos=(char*) name-1;
+
+ gpos= pos++;
+ for ( ; *pos ; pos++) /* Find last FN_LIBCHAR */
+ if (*pos == FN_LIBCHAR || *pos == '/'
+#ifdef FN_C_AFTER_DIR
+ || *pos == FN_C_AFTER_DIR || *pos == FN_C_AFTER_DIR_2
+#endif
+ )
+ gpos=pos;
+ return ((uint) (uint) (gpos+1-(char*) name));
+}
+
+
+ /* Gives directory part of filename. Directory ends with '/' */
+ /* Returns length of directory part */
+
+uint dirname_part(my_string to, const char *name)
+{
+ uint length;
+ DBUG_ENTER("dirname_part");
+ DBUG_PRINT("enter",("'%s'",name));
+
+ length=dirname_length(name);
+ (void) strmake(to,(char*) name,min(length,FN_REFLEN-2));
+ convert_dirname(to); /* Convert chars */
+ 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 */
+
+#ifndef FN_DEVCHAR
+#define FN_DEVCHAR '\0' /* For easier code */
+#endif
+
+void convert_dirname(my_string to)
+{
+#ifdef FN_UPPER_CASE
+ caseup_str(to);
+#endif
+#ifdef FN_LOWER_CASE
+ casedn_str(to);
+#endif
+#if FN_LIBCHAR != '/'
+ {
+ reg1 my_string pos;
+ pos=to-1; /* Change from '/' */
+ while ((pos=strchr(pos+1,'/')) != 0)
+ *pos=FN_LIBCHAR;
+ }
+#endif
+#ifdef FN_C_BEFORE_DIR_2
+ {
+ reg1 my_string pos;
+ for (pos=to ; *pos ; pos++)
+ {
+ if (*pos == FN_C_BEFORE_DIR_2)
+ *pos=FN_C_BEFORE_DIR;
+ if (*pos == FN_C_AFTER_DIR_2)
+ *pos=FN_C_AFTER_DIR;
+ }
+ }
+#else
+ { /* Append FN_LIBCHAR if not there */
+ char *end=strend(to);
+ if (end != to && (end[-1] != FN_LIBCHAR && end[-1] != FN_DEVCHAR))
+ {
+ end[0]=FN_LIBCHAR;
+ end[1]=0;
+ }
+ }
+#endif
+} /* convert_dirname */
diff --git a/mysys/mf_fn_ext.c b/mysys/mf_fn_ext.c
new file mode 100644
index 00000000000..6a9b9d18341
--- /dev/null
+++ b/mysys/mf_fn_ext.c
@@ -0,0 +1,46 @@
+/* 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 */
+
+/* Returnerar en pekare till filnamnets extension. */
+
+#include "mysys_priv.h"
+#include <m_string.h>
+
+ /* Return a pointerto the extension of the filename
+ The pointer points at the extension character (normally '.'))
+ If there isn't any extension, the pointer points at the end
+ NULL of the filename
+ */
+
+my_string fn_ext(const char *name)
+{
+ register my_string pos,gpos;
+ DBUG_ENTER("fn_ext");
+ DBUG_PRINT("mfunkt",("name: '%s'",name));
+
+#if defined(FN_DEVCHAR) || defined(FN_C_AFTER_DIR)
+ {
+ char buff[FN_REFLEN];
+ gpos=(my_string) name+dirname_part(buff,(char*) name);
+ }
+#else
+ if (!(gpos=strrchr(name,FNLIBCHAR)))
+ gpos=name;
+#endif
+ pos=strrchr(gpos,FN_EXTCHAR);
+ DBUG_RETURN (pos ? pos : strend(gpos));
+} /* fn_ext */
diff --git a/mysys/mf_format.c b/mysys/mf_format.c
new file mode 100644
index 00000000000..623f1dbd19e
--- /dev/null
+++ b/mysys/mf_format.c
@@ -0,0 +1,146 @@
+/* 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>
+#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 */
+
+#ifdef MAXPATHLEN
+#define BUFF_LEN MAXPATHLEN
+#else
+#define BUFF_LEN FN_LEN
+#endif
+
+my_string fn_format(my_string to, const char *name, const char *dsk,
+ const char *form, int flag)
+{
+ reg1 uint length;
+ char dev[FN_REFLEN], buff[BUFF_LEN], *pos, *startpos;
+ const char *ext;
+ DBUG_ENTER("fn_format");
+ DBUG_PRINT("enter",("name: %s dsk: %s form: %s flag: %d",
+ name,dsk,form,flag));
+
+ /* Kopiera & skippa enheten */
+ name+=(length=dirname_part(dev,(startpos=(my_string) name)));
+ if (length == 0 || flag & 1)
+ {
+ (void) strmov(dev,dsk); /* Use given directory */
+ convert_dirname(dev); /* Fix to this OS */
+ }
+ if (flag & 8)
+ pack_dirname(dev,dev); /* Put in ./.. and ~/.. */
+ if (flag & 4)
+ (void) unpack_dirname(dev,dev); /* Replace ~/.. with dir */
+ if ((pos=strchr(name,FN_EXTCHAR)) != NullS)
+ {
+ if ((flag & 2) == 0) /* Skall vi byta extension ? */
+ {
+ length=strlength(name); /* Old extension */
+ ext = "";
+ }
+ else
+ {
+ length=(uint) (pos-(char*) name); /* Change extension */
+ ext= form;
+ }
+ }
+ else
+ {
+ length=strlength(name); /* Har ingen ext- tag nya */
+ ext=form;
+ }
+
+ if (strlen(dev)+length+strlen(ext) >= FN_REFLEN || length >= FN_LEN )
+ { /* To long path, return original */
+ uint 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));
+ }
+ else
+ {
+ if (to == startpos)
+ {
+ bmove(buff,(char*) name,length); /* Save name for last copy */
+ name=buff;
+ }
+ (void) strmov(strnmov(strmov(to,dev),name,length),ext);
+#ifdef FN_UPPER_CASE
+ caseup_str(to);
+#endif
+#ifdef FN_LOWER_CASE
+ casedn_str(to);
+#endif
+ }
+ /* Purify gives a lot of UMR errors when using realpath */
+#if defined(HAVE_REALPATH) && !defined(HAVE_purify)
+ if (flag & 16)
+ {
+ struct stat stat_buff;
+ if (flag & 32 || (!lstat(to,&stat_buff) && S_ISLNK(stat_buff.st_mode)))
+ {
+ if (realpath(to,buff))
+ strmov(to,buff);
+ }
+ }
+#endif
+ DBUG_RETURN (to);
+} /* fn_format */
+
+
+ /*
+ strlength(const string str)
+ Return length of string with end-space:s not counted.
+ */
+
+size_s strlength(const char *str)
+{
+ reg1 my_string pos;
+ reg2 my_string found;
+ DBUG_ENTER("strlength");
+
+ pos=found=(char*) str;
+
+ while (*pos)
+ {
+ if (*pos != ' ')
+ {
+ while (*++pos && *pos != ' ') {};
+ if (!*pos)
+ {
+ found=pos; /* String ends here */
+ break;
+ }
+ }
+ found=pos;
+ while (*++pos == ' ') {};
+ }
+ DBUG_RETURN((size_s) (found-(char*) str));
+} /* strlength */
diff --git a/mysys/mf_getdate.c b/mysys/mf_getdate.c
new file mode 100644
index 00000000000..627789dc802
--- /dev/null
+++ b/mysys/mf_getdate.c
@@ -0,0 +1,59 @@
+/* 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 */
+
+/* Get date in a printable form: yyyy-mm-dd hh:mm:ss */
+
+#include "mysys_priv.h"
+#include <m_string.h>
+
+ /*
+ If flag & 1 Return date and time
+ If flag & 2 Return short date format YYMMDD
+ */
+
+
+void get_date(register my_string to, int flag, time_t date)
+{
+ reg2 struct tm *start_time;
+ time_t skr;
+#if defined(HAVE_LOCALTIME_R) && defined(_REENTRANT)
+ struct tm tm_tmp;
+#endif
+
+ skr=date ? (time_t) date : time((time_t*) 0);
+#if defined(HAVE_LOCALTIME_R) && defined(_REENTRANT)
+ localtime_r(&skr,&tm_tmp);
+ start_time= &tm_tmp;
+#else
+ start_time=localtime(&skr);
+#endif
+ if (flag & 2)
+ sprintf(to,"%02d%02d%02d",
+ start_time->tm_year % 100,
+ start_time->tm_mon+1,
+ start_time->tm_mday);
+ else
+ sprintf(to,"%d-%02d-%02d",
+ start_time->tm_year+1900,
+ start_time->tm_mon+1,
+ start_time->tm_mday);
+ if (flag & 1)
+ sprintf(strend(to)," %2d:%02d:%02d",
+ start_time->tm_hour,
+ start_time->tm_min,
+ start_time->tm_sec);
+} /* get_date */
diff --git a/mysys/mf_iocache.c b/mysys/mf_iocache.c
new file mode 100644
index 00000000000..86cf5fc65e2
--- /dev/null
+++ b/mysys/mf_iocache.c
@@ -0,0 +1,603 @@
+/* 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 */
+
+/*
+ Cashing of files with only does (sequential) read or writes of fixed-
+ length records. A read isn't allowed to go over file-length. A read is ok
+ if it ends at file-length and next read can try to read after file-length
+ (and get a EOF-error).
+ Possibly use of asyncronic io.
+ macros for read and writes for faster io.
+ Used instead of FILE when reading or writing hole files.
+ This shall make mf_rec_cache obsolite.
+ One can change info->pos_in_file to a higer value to skipp bytes in file if
+ also info->rc_pos is set to info->rc_end.
+*/
+
+#define MAP_TO_USE_RAID
+#include "mysys_priv.h"
+#include <m_string.h>
+#ifdef HAVE_AIOWAIT
+#include "mysys_err.h"
+#include <errno.h>
+static void my_aiowait(my_aio_result *result);
+#endif
+
+
+ /*
+ ** if cachesize == 0 then use default cachesize (from s-file)
+ ** if file == -1 then real_open_cached_file() will be called to
+ ** 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));
+
+ 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 */
+ 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 */
+ }
+ }
+
+ 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 */
+ }
+ info->pos_in_file=seek_offset;
+ 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->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->type=type;
+ info->error=0;
+ info->read_function=_my_b_read;
+#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 (! 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 (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);
+#ifdef HAVE_AIOWAIT
+ my_aiowait(&info->aio_result); /* Wait for outstanding req */
+#endif
+ }
+ else
+ {
+ if (info->type == WRITE_CACHE && type == READ_CACHE)
+ info->end_of_file=my_b_tell(info);
+ if (flush_io_cache(info))
+ DBUG_RETURN(1);
+ info->pos_in_file=seek_offset;
+ info->rc_request_pos=info->rc_pos=info->buffer;
+ if (type == READ_CACHE)
+ {
+ 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=MY_FILEPOS_ERROR; /* May be changed by user */
+ }
+ }
+ info->type=type;
+ info->error=0;
+ info->read_function=_my_b_read;
+#ifdef HAVE_AIOWAIT
+ 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 */
+ /* Returns 0 if record read */
+
+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;
+
+ 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 (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->end_of_file - pos_in_file;
+ if (max_length > info->read_length-diff_length)
+ max_length=info->read_length-diff_length;
+
+ 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;
+}
+
+
+#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 (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 */
+ VOID(my_seek(info->file,info->pos_in_file,MY_SEEK_SET,MYF(0)));
+ 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
+ {
+ my_aiowait(&info->aio_result); /* Wait for outstanding req */
+ info->inited=0;
+ }
+#endif
+ 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 */
diff --git a/mysys/mf_keycache.c b/mysys/mf_keycache.c
new file mode 100644
index 00000000000..eca22039444
--- /dev/null
+++ b/mysys/mf_keycache.c
@@ -0,0 +1,753 @@
+/* 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 functions is handle keyblock cacheing for NISAM, MISAM and PISAM
+ databases.
+ One cache can handle many files. Every different blocksize has it owns
+ set of buffers that are allocated from block_mem.
+ init_key_cache() should be used to init cache handler.
+ */
+
+#include "mysys_priv.h"
+#include "my_static.h"
+#include <m_string.h>
+#include <errno.h>
+
+#if defined(MSDOS) && !defined(M_IC80386)
+ /* We nead much memory */
+#undef my_malloc_lock
+#undef my_free_lock
+#define my_malloc_lock(A,B) halloc((long) (A/IO_SIZE),IO_SIZE)
+#define my_free_lock(A,B) hfree(A)
+#endif
+
+/* size of map to be used to find changed files */
+
+#define CHANGED_BLOCKS_HASH 128 /* Must be power of 2 */
+#define CHANGED_BLOCKS_MASK (CHANGED_BLOCKS_HASH-1)
+#define FLUSH_CACHE 2000 /* Sort this many blocks at once */
+
+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 */
+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;
+ulong _my_blocks_used,_my_blocks_changed;
+ulong _my_cache_w_requests,_my_cache_write,_my_cache_r_requests,
+ _my_cache_read;
+static byte HUGE_PTR *_my_block_mem;
+static SEC_LINK *changed_blocks[CHANGED_BLOCKS_HASH];
+static SEC_LINK *file_blocks[CHANGED_BLOCKS_HASH];
+#ifndef DBUG_OFF
+static my_bool _my_printed;
+#endif
+
+
+ /* Init of disk_buffert */
+ /* Returns blocks in use */
+ /* ARGSUSED */
+
+int init_key_cache(ulong use_mem,
+ ulong leave_this_much_mem __attribute__((unused)))
+{
+ uint blocks,length;
+ byte *extra_mem=0;
+ DBUG_ENTER("init_key_cache");
+
+ if (key_cache_inited && _my_disk_blocks > 0)
+ {
+ DBUG_PRINT("warning",("key cache allready in use")); /* purecov: inspected */
+ DBUG_RETURN(0); /* purecov: inspected */
+ }
+ if (! key_cache_inited)
+ {
+ key_cache_inited=TRUE;
+ _my_disk_blocks= -1;
+#ifndef DBUG_OFF
+ _my_printed=0;
+#endif
+ }
+
+ blocks= (uint) (use_mem/(sizeof(SEC_LINK)+sizeof(SEC_LINK*)*5/4+KEYCACHE_BLOCK_SIZE));
+ /* No use to have very few blocks */
+ if (blocks >= 8 && _my_disk_blocks < 0)
+ {
+#if !defined(HAVE_ALLOCA) && !defined(THREAD)
+ if ((extra_mem=my_malloc((uint) leave_this_much_mem,MYF(0))) == 0)
+ goto err;
+#endif
+ for (;;)
+ {
+ if ((_my_hash_blocks=find_next_bigger_power((uint) blocks)) < blocks*5/4)
+ _my_hash_blocks<<=1;
+ while ((length=(uint) blocks*sizeof(SEC_LINK)+
+ sizeof(SEC_LINK*)*_my_hash_blocks)+(ulong) blocks*KEYCACHE_BLOCK_SIZE >
+ use_mem)
+ blocks--;
+ if ((_my_block_mem=my_malloc_lock((ulong) blocks * KEYCACHE_BLOCK_SIZE,MYF(0))))
+ {
+ if ((_my_block_root=(SEC_LINK*) my_malloc((uint) length,MYF(0))) != 0)
+ break;
+ my_free_lock(_my_block_mem,MYF(0));
+ }
+ if (blocks < 8)
+ goto err;
+ blocks=blocks/4*3;
+ }
+ _my_disk_blocks=(int) blocks;
+ _my_hash_root= (SEC_LINK**) (_my_block_root+blocks);
+ bzero((byte*) _my_hash_root,_my_hash_blocks*sizeof(SEC_LINK*));
+ _my_used_first=_my_used_last=0;
+ _my_blocks_used=_my_disk_blocks_used=_my_blocks_changed=0;
+ _my_cache_w_requests=_my_cache_r_requests=_my_cache_read=_my_cache_write=0;
+ DBUG_PRINT("exit",("disk_blocks: %d block_root: %lx _my_hash_blocks: %d hash_root: %lx",
+ _my_disk_blocks,_my_block_root,_my_hash_blocks,
+ _my_hash_root));
+#if !defined(HAVE_ALLOCA) && !defined(THREAD)
+ my_free(extra_mem,MYF(0));
+#endif
+ }
+ bzero((gptr) changed_blocks,sizeof(changed_blocks[0])*CHANGED_BLOCKS_HASH);
+ bzero((gptr) file_blocks,sizeof(file_blocks[0])*CHANGED_BLOCKS_HASH);
+ DBUG_RETURN((int) blocks);
+err:
+ if (extra_mem) /* purecov: inspected */
+ my_free(extra_mem,MYF(0));
+ my_errno=ENOMEM;
+ DBUG_RETURN(0);
+} /* init_key_cache */
+
+
+ /* Remove key_cache from memory */
+
+void end_key_cache(void)
+{
+ DBUG_ENTER("end_key_cache");
+ if (! _my_blocks_changed)
+ {
+ if (_my_disk_blocks > 0)
+ {
+ my_free_lock((gptr) _my_block_mem,MYF(0));
+ my_free((gptr) _my_block_root,MYF(0));
+ _my_disk_blocks= -1;
+ }
+ }
+ 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,
+ _my_cache_write,_my_cache_r_requests,_my_cache_read));
+ DBUG_VOID_RETURN;
+} /* 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];
+ next->prev_changed= ptr;
+ if ((next->next_changed= *ptr))
+ (*ptr)->prev_changed= &next->next_changed;
+ *ptr=next;
+}
+
+
+static inline void relink_into_file_blocks(SEC_LINK *next, int file)
+{
+ reg1 SEC_LINK **ptr= &file_blocks[(uint) file & CHANGED_BLOCKS_MASK];
+ if (next->next_changed)
+ next->next_changed->prev_changed=next->prev_changed;
+ *next->prev_changed=next->next_changed;
+ next->prev_changed= ptr;
+ if ((next->next_changed= *ptr))
+ (*ptr)->prev_changed= &next->next_changed;
+ *ptr=next;
+}
+
+static inline void link_changed_to_file(SEC_LINK *next,int file)
+{
+ reg1 SEC_LINK **ptr= &file_blocks[(uint) file & CHANGED_BLOCKS_MASK];
+ if (next->next_changed)
+ next->next_changed->prev_changed=next->prev_changed;
+ *next->prev_changed=next->next_changed;
+ next->prev_changed= ptr;
+ if ((next->next_changed= *ptr))
+ (*ptr)->prev_changed= &next->next_changed;
+ *ptr=next;
+ next->changed=0;
+ _my_blocks_changed--;
+}
+
+static inline void link_file_to_changed(SEC_LINK *next)
+{
+ reg1 SEC_LINK **ptr= &changed_blocks[(uint) next->file & CHANGED_BLOCKS_MASK];
+ if (next->next_changed)
+ next->next_changed->prev_changed=next->prev_changed;
+ *next->prev_changed=next->next_changed;
+ next->prev_changed= ptr;
+ if ((next->next_changed= *ptr))
+ (*ptr)->prev_changed= &next->next_changed;
+ *ptr=next;
+ next->changed=1;
+ _my_blocks_changed++;
+}
+
+
+#ifndef DBUG_OFF
+#define DBUG_OFF /* This should work */
+#endif
+
+#ifndef DBUG_OFF
+static void test_key_cache(char *where, my_bool lock);
+#endif
+
+
+ /*
+ ** read a key_buffer
+ ** filepos must point at a even KEYCACHE_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
+ */
+
+byte *key_cache_read(File file, my_off_t filepos, byte *buff, uint length,
+ uint block_length __attribute__((unused)),
+ int return_buffer __attribute__((unused)))
+{
+ reg1 SEC_LINK *next;
+ int error=0;
+
+#ifndef THREAD
+ if (block_length > KEYCACHE_BLOCK_SIZE)
+ return_buffer=0;
+#endif
+ if (_my_disk_blocks > 0)
+ { /* We have key_cacheing */
+ byte *start=buff;
+ uint read_length;
+ pthread_mutex_lock(&THR_LOCK_keycache);
+ do
+ {
+ _my_cache_r_requests++;
+ read_length= length > KEYCACHE_BLOCK_SIZE ? KEYCACHE_BLOCK_SIZE : length;
+ if (!(next=find_key_block(file,filepos,&error)))
+ {
+ pthread_mutex_unlock(&THR_LOCK_keycache);
+ 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);
+ }
+ _my_cache_read++;
+ }
+#ifndef THREAD /* buffer may be used a long time */
+ if (return_buffer)
+ {
+ pthread_mutex_unlock(&THR_LOCK_keycache);
+ return (next->buffer);
+ }
+#endif
+ if (! (read_length & 511))
+ bmove512(buff,next->buffer,read_length);
+ else
+ memcpy(buff,next->buffer,(size_t) read_length);
+ buff+=read_length;
+ filepos+=read_length;
+ } while ((length-= read_length));
+ pthread_mutex_unlock(&THR_LOCK_keycache);
+ return(start);
+ pthread_mutex_unlock(&THR_LOCK_keycache);
+ }
+ _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);
+} /* 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 */
+
+int key_cache_write(File file, my_off_t filepos, byte *buff, uint length,
+ uint block_length __attribute__((unused)),
+ int dont_write)
+{
+ reg1 SEC_LINK *next;
+ int error=0;
+
+ 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);
+ }
+
+#if !defined(DBUG_OFF) && defined(EXTRA_DEBUG)
+ DBUG_EXECUTE("exec",test_key_cache("start of key_cache_write",1););
+#endif
+ if (_my_disk_blocks > 0)
+ { /* We have key_cacheing */
+ uint read_length;
+ pthread_mutex_lock(&THR_LOCK_keycache);
+ _my_cache_w_requests++;
+ do
+ {
+ read_length= length > KEYCACHE_BLOCK_SIZE ? KEYCACHE_BLOCK_SIZE : length;
+ if (!(next=find_key_block(file,filepos,&error)))
+ goto end; /* Fatal error */
+ if (!dont_write) /* If we wrote buff at start */
+ {
+ if (next->changed) /* Unlink from changed list */
+ link_changed_to_file(next,next->file);
+ }
+ else if (!next->changed)
+ link_file_to_changed(next); /* Add to changed list */
+
+ if (!(read_length & 511))
+ bmove512(next->buffer,buff,read_length);
+ else
+ memcpy(next->buffer,buff,(size_t) read_length);
+ buff+=read_length;
+ filepos+=read_length;
+ } while ((length-= read_length));
+ error=0;
+ pthread_mutex_unlock(&THR_LOCK_keycache);
+ }
+ else if (dont_write)
+ { /* We must write, no cache */
+ _my_cache_w_requests++;
+ _my_cache_write++;
+ if (my_pwrite(file,(byte*) buff,length,filepos,
+ MYF(MY_NABP | MY_WAIT_IF_FULL)))
+ error=1;
+ }
+end:
+#if !defined(DBUG_OFF) && defined(EXTRA_DEBUG)
+ DBUG_EXECUTE("exec",test_key_cache("end of key_cache_write",1););
+#endif
+ return(error);
+} /* key_cache_write */
+
+
+ /* Find block in cache */
+ /* IF found sector and error is set then next->changed is cleared */
+
+static SEC_LINK *find_key_block(int file, my_off_t filepos, int *error)
+{
+ reg1 SEC_LINK *next,**start;
+
+#if !defined(DBUG_OFF) && defined(EXTRA_DEBUG)
+ DBUG_EXECUTE("exec",test_key_cache("start of find_key_block",0););
+#endif
+
+ *error=0;
+ next= *(start= &_my_hash_root[((ulong) (filepos/KEYCACHE_BLOCK_SIZE)+(ulong) file) &
+ (_my_hash_blocks-1)]);
+ while (next && (next->diskpos != filepos || next->file != file))
+ next= next->next_hash;
+
+ if (next)
+ { /* Found block */
+ if (next != _my_used_last)
+ { /* Relink used-chain */
+ if (next == _my_used_first)
+ _my_used_first=next->next_used;
+ else
+ {
+ next->prev_used->next_used = next->next_used;
+ next->next_used->prev_used = next->prev_used;
+ }
+ next->prev_used=_my_used_last;
+ _my_used_last->next_used=next;
+ }
+ }
+ else
+ { /* New block */
+ if (_my_disk_blocks_used+1 <= (uint) _my_disk_blocks)
+ { /* 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*);
+ /* link first in file_blocks */
+ next->changed=0;
+ link_into_file_blocks(next,file);
+ _my_disk_blocks_used++;
+ if (!_my_used_first)
+ _my_used_first=next;
+ if (_my_used_last)
+ _my_used_last->next_used=next; /* Last in used-chain */
+ }
+ else
+ { /* Reuse old block */
+ next= _my_used_first;
+ if (next->changed)
+ {
+ if (my_pwrite(next->file,next->buffer,KEYCACHE_BLOCK_SIZE,next->diskpos,
+ MYF(MY_NABP | MY_WAIT_IF_FULL)))
+ {
+ *error=1;
+ return((SEC_LINK*) 0);
+ }
+ _my_cache_write++;
+ link_changed_to_file(next,file);
+ }
+ else
+ {
+ if (next->file == -1)
+ link_into_file_blocks(next,file);
+ else
+ relink_into_file_blocks(next,file);
+ }
+ if (next->prev_hash) /* If in hash-link */
+ if ((*next->prev_hash=next->next_hash) != 0) /* Remove from link */
+ next->next_hash->prev_hash= next->prev_hash;
+
+ _my_used_last->next_used=next;
+ _my_used_first=next->next_used;
+ }
+ if (*start) /* Link in first in h.-chain */
+ (*start)->prev_hash= &next->next_hash;
+ next->next_hash= *start; next->prev_hash=start; *start=next;
+ next->prev_used=_my_used_last;
+ next->file=file;
+ next->diskpos=filepos;
+ *error=1; /* Block wasn't in memory */
+ }
+ _my_used_last=next;
+#if !defined(DBUG_OFF) && defined(EXTRA_DEBUG)
+ DBUG_EXECUTE("exec",test_key_cache("end of find_key_block",0););
+#endif
+ return next;
+} /* find_key_block */
+
+
+static void free_block(SEC_LINK *used)
+{
+ used->file= -1;
+ if (used != _my_used_first) /* Relink used-chain */
+ {
+ if (used == _my_used_last)
+ _my_used_last=used->prev_used;
+ else
+ {
+ used->prev_used->next_used = used->next_used;
+ used->next_used->prev_used = used->prev_used;
+ }
+ used->next_used=_my_used_first;
+ used->next_used->prev_used=used;
+ _my_used_first=used;
+ }
+ if ((*used->prev_hash=used->next_hash)) /* Relink hash-chain */
+ used->next_hash->prev_hash= used->prev_hash;
+ if (used->next_changed) /* Relink changed/file list */
+ used->next_changed->prev_changed=used->prev_changed;
+ *used->prev_changed=used->next_changed;
+ used->prev_hash=0; used->next_hash=0; /* Safety */
+}
+
+
+ /* Flush all changed blocks to disk. Free used blocks if requested */
+
+static int cmp_sec_link(SEC_LINK **a, SEC_LINK **b)
+{
+ return (((*a)->diskpos < (*b)->diskpos) ? -1 :
+ ((*a)->diskpos > (*b)->diskpos) ? 1 : 0);
+}
+
+static int flush_cached_blocks(File file, SEC_LINK **cache, uint count)
+{
+ uint last_errno=0;
+ 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,
+ MYF(MY_NABP | MY_WAIT_IF_FULL)))
+ {
+ if (!last_errno)
+ last_errno=errno ? errno : -1;
+ }
+ }
+ return last_errno;
+}
+
+
+int flush_key_blocks(File file, enum flush_type type)
+{
+ int error=0,last_errno=0;
+ uint count=0;
+ SEC_LINK *cache_buff[FLUSH_CACHE],**cache,**pos,**end;
+ SEC_LINK *used,*next;
+ DBUG_ENTER("flush_key_blocks");
+ DBUG_PRINT("enter",("file: %d blocks_used: %d blocks_changed: %d",
+ file,_my_blocks_used,_my_blocks_changed));
+
+ pthread_mutex_lock(&THR_LOCK_keycache);
+
+#if !defined(DBUG_OFF) && defined(EXTRA_DEBUG)
+ DBUG_EXECUTE("exec",test_key_cache("start of flush_key_blocks",0););
+#endif
+ cache=cache_buff; /* If no key cache */
+ if (_my_disk_blocks > 0 &&
+ (!my_disable_flush_key_blocks || type != FLUSH_KEEP))
+ {
+ if (type != FLUSH_IGNORE_CHANGED)
+ {
+ /* Count how many key blocks we have to cache to be able to
+ write everything with so few seeks as possible */
+
+ for (used=changed_blocks[(uint) file & CHANGED_BLOCKS_MASK];
+ used ;
+ used=used->next_changed)
+ {
+ if (used->file == file)
+ count++;
+ }
+ /* Only allocate a new buffer if its bigger than the one we have */
+ if (count <= FLUSH_CACHE ||
+ !(cache=(SEC_LINK**) my_malloc(sizeof(SEC_LINK*)*count,MYF(0))))
+ {
+ cache=cache_buff; /* Fall back to safe buffer */
+ count=FLUSH_CACHE;
+ }
+ end=cache+count;
+ }
+
+ /* Go through the keys and write them to buffer to be flushed */
+ end=(pos=cache)+count;
+ for (used=changed_blocks[(uint) file & CHANGED_BLOCKS_MASK];
+ used ;
+ used=next)
+ {
+ next=used->next_changed;
+ if (used->file == file)
+ {
+ if (type != FLUSH_IGNORE_CHANGED)
+ {
+ if (pos == end)
+ {
+ if ((error=flush_cached_blocks(file, cache, count)))
+ last_errno=error;
+ pos=cache;
+ }
+ *pos++=used;
+ _my_cache_write++;
+ }
+ if (type != FLUSH_KEEP && type != FLUSH_FORCE_WRITE)
+ {
+ /* This will not destroy position or data */
+ used->changed=0;
+ _my_blocks_changed--;
+ free_block(used);
+ }
+ else
+ link_changed_to_file(used,file);
+ }
+ }
+ if (pos != cache)
+ {
+ if ((error=flush_cached_blocks(file, cache, (uint) (pos-cache))))
+ last_errno=error;
+ }
+ /* The following happens very seldom */
+ if (type != FLUSH_KEEP && type != FLUSH_FORCE_WRITE)
+ {
+ for (used=file_blocks[(uint) file & CHANGED_BLOCKS_MASK];
+ used ;
+ used=next)
+ {
+ next=used->next_changed;
+ if (used->file == file && (!used->changed ||
+ type == FLUSH_IGNORE_CHANGED))
+ free_block(used);
+ }
+ }
+ }
+#ifndef DBUG_OFF
+ DBUG_EXECUTE("exec",test_key_cache("end of flush_key_blocks",0););
+#endif
+ pthread_mutex_unlock(&THR_LOCK_keycache);
+ if (cache != cache_buff)
+ my_free((gptr) cache,MYF(0));
+ if (last_errno)
+ errno=last_errno; /* Return first error */
+ DBUG_RETURN(last_errno != 0);
+} /* flush_key_blocks */
+
+
+#ifndef DBUG_OFF
+
+ /* Test if disk-cachee is ok */
+
+static void test_key_cache(char *where, my_bool lock)
+{
+ reg1 uint i,found,error,changed;
+ SEC_LINK *pos,**prev;
+
+ if (lock)
+ pthread_mutex_lock(&THR_LOCK_keycache);
+ found=error=0;
+ for (i= 0 ; i < _my_hash_blocks ; i++)
+ {
+
+ for (pos= *(prev= &_my_hash_root[i]) ;
+ pos && found < _my_blocks_used+2 ;
+ found++, pos= *(prev= &pos->next_hash))
+ {
+ if (prev != pos->prev_hash)
+ {
+ error=1;
+ DBUG_PRINT("error",
+ ("hash: %d pos: %lx : prev: %lx != pos->prev: %lx",
+ i,pos,prev,pos->prev_hash));
+ }
+
+ if (((pos->diskpos/KEYCACHE_BLOCK_SIZE)+pos->file) % _my_hash_blocks != i)
+ {
+ DBUG_PRINT("error",("hash: %d pos: %lx : Wrong disk_buffer %ld",
+ i,pos,pos->diskpos));
+ error=1;
+ }
+ }
+ }
+ if (found > _my_blocks_used)
+ {
+ DBUG_PRINT("error",("Found too many hash_pointers"));
+ error=1;
+ }
+ if (error && !_my_printed)
+ { /* Write all hash-pointers */
+ _my_printed=1;
+ for (i=0 ; i < _my_hash_blocks ; i++)
+ {
+ DBUG_PRINT("loop",("hash: %d _my_hash_root: %lx",i,&_my_hash_root[i]));
+ pos= _my_hash_root[i]; found=0;
+ while (pos && found < 10)
+ {
+ DBUG_PRINT("loop",("pos: %lx prev: %lx next: %lx file: %d disk_buffer: %ld", pos,pos->prev_hash,pos->next_hash,pos->file,pos->diskpos));
+ found++; pos= pos->next_hash;
+ }
+ }
+ }
+
+ found=changed=0;
+
+ if ((pos=_my_used_first))
+ {
+ while (pos != _my_used_last && found < _my_blocks_used+2)
+ {
+ found++;
+ if (pos->changed)
+ changed++;
+ if (pos->next_used->prev_used != pos)
+ {
+ DBUG_PRINT("error",("pos: %lx next_used: %lx next_used->prev: %lx",
+ pos,pos->next_used,pos->next_used->prev_hash));
+ error=1;
+ }
+ pos=pos->next_used;
+ }
+ found++;
+ if (pos->changed)
+ changed++;
+ }
+ if (found != _my_blocks_used)
+ {
+ DBUG_PRINT("error",("Found %d of %d keyblocks",found,_my_blocks_used));
+ error=1;
+ }
+
+ for (i= 0 ; i < CHANGED_BLOCKS_HASH ; i++)
+ {
+ found=0;
+ prev= &changed_blocks[i];
+ for (pos= *prev ; pos && found < _my_blocks_used+2; pos=pos->next_changed)
+ {
+ found++;
+ if (pos->prev_changed != prev)
+ {
+ DBUG_PRINT("error",("changed_block list %d doesn't point backwards properly",i));
+ error=1;
+ }
+ prev= &pos->next_changed;
+ if (((uint) pos->file & CHANGED_BLOCKS_MASK) != i)
+ {
+ DBUG_PRINT("error",("Wrong file %d in changed blocks: %d",pos->file,i));
+ error=1;
+ }
+ changed--;
+ }
+ if (pos)
+ {
+ DBUG_PRINT("error",("changed_blocks %d has recursive link",i));
+ error=1;
+ }
+
+ found=0;
+ prev= &file_blocks[i];
+ for (pos= *prev ; pos && found < _my_blocks_used+2; pos=pos->next_changed)
+ {
+ found++;
+ if (pos->prev_changed != prev)
+ {
+ DBUG_PRINT("error",("file_block list %d doesn't point backwards properly",i));
+ error=1;
+ }
+ prev= &pos->next_changed;
+ if (((uint) pos->file & CHANGED_BLOCKS_MASK) != i)
+ {
+ DBUG_PRINT("error",("Wrong file %d in file_blocks: %d",pos->file,i));
+ error=1;
+ }
+ }
+ if (pos)
+ {
+ DBUG_PRINT("error",("File_blocks %d has recursive link",i));
+ error=1;
+ }
+ }
+ if (changed != 0)
+ {
+ DBUG_PRINT("error",("Found %d blocks that wasn't in changed blocks",
+ changed));
+ error=1;
+ }
+ if (error)
+ DBUG_PRINT("error",("Found error at %s",where));
+ if (lock)
+ pthread_mutex_unlock(&THR_LOCK_keycache);
+ return;
+} /* test_key_cache */
+#endif
diff --git a/mysys/mf_loadpath.c b/mysys/mf_loadpath.c
new file mode 100644
index 00000000000..641528b8b5d
--- /dev/null
+++ b/mysys/mf_loadpath.c
@@ -0,0 +1,54 @@
+/* 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>
+
+ /* Returns full load-path for a file. to may be = path */
+ /* if path is a hard-path return path */
+ /* if path starts with home-dir return path */
+ /* if path starts with current dir or parent-dir unpack path */
+ /* if there is no path, prepend with own_path_prefix if given */
+ /* else unpack path according to current dir */
+
+my_string my_load_path(my_string to, const char *path,
+ const char *own_path_prefix)
+{
+ char buff[FN_REFLEN];
+ DBUG_ENTER("my_load_path");
+ DBUG_PRINT("enter",("path: %s prefix: %s",path,
+ own_path_prefix ? own_path_prefix : ""));
+
+ if ((path[0] == FN_HOMELIB && path[1] == FN_LIBCHAR) ||
+ 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) ||
+ ! own_path_prefix)
+ {
+ if (! my_getwd(buff,(uint) (FN_REFLEN-strlen(path)),MYF(0)))
+ VOID(strcat(buff,path));
+ else
+ VOID(strmov(buff,path));
+ }
+ else
+ VOID(strxmov(buff,own_path_prefix,path,NullS));
+ strmov(to,buff);
+ DBUG_PRINT("exit",("to: %s",to));
+ DBUG_RETURN(to);
+} /* my_load_path */
diff --git a/mysys/mf_pack.c b/mysys/mf_pack.c
new file mode 100644
index 00000000000..8aff6a3484a
--- /dev/null
+++ b/mysys/mf_pack.c
@@ -0,0 +1,528 @@
+/* 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>
+#ifdef HAVE_PWD_H
+#include <pwd.h>
+#endif
+#ifdef VMS
+#include <rms.h>
+#include <iodef.h>
+#include <descrip.h>
+#endif /* VMS */
+
+static my_string NEAR_F expand_tilde(my_string *path);
+
+ /* Pack a dirname ; Changes HOME to ~/ and current dev to ./ */
+ /* from is a dirname (from dirname() ?) ending with FN_LIBCHAR */
+
+void pack_dirname(my_string to, const char *from)
+
+ /* to may be == from */
+{
+ int cwd_err;
+ uint d_length,length,buff_length;
+ my_string start;
+ char buff[FN_REFLEN];
+ DBUG_ENTER("pack_dirname");
+
+ (void) intern_filename(to,from); /* Change to intern name */
+
+#ifdef FN_DEVCHAR
+ if ((start=strrchr(to,FN_DEVCHAR)) != 0) /* Skipp device part */
+ start++;
+ else
+#endif
+ start=to;
+
+ LINT_INIT(buff_length);
+ if (!(cwd_err= my_getwd(buff,FN_REFLEN,MYF(0))))
+ {
+ buff_length=strlen(buff);
+ d_length=(uint) (start-to);
+ if ((start == to ||
+ (buff_length == d_length && !bcmp(buff,start,d_length))) &&
+ *start != FN_LIBCHAR && *start)
+ { /* Put current dir before */
+ bchange(to,d_length,buff,buff_length,strlen(to)+1);
+ }
+ }
+
+ if ((d_length= cleanup_dirname(to,to)) != 0)
+ {
+ length=0;
+ if (home_dir)
+ {
+ length=strlen(home_dir);
+ if (home_dir[length-1] == FN_LIBCHAR)
+ length--; /* Don't test last '/' */
+ }
+ if (length > 1 && length < d_length)
+ { /* test if /xx/yy -> ~/yy */
+ if (bcmp(to,home_dir,length) == 0 && to[length] == FN_LIBCHAR)
+ {
+ to[0]=FN_HOMELIB; /* Filename begins with ~ */
+ (void) strmov_overlapp(to+1,to+length);
+ }
+ }
+ if (! cwd_err)
+ { /* Test if cwd is ~/... */
+ if (length > 1 && length < buff_length)
+ {
+ if (bcmp(buff,home_dir,length) == 0 && buff[length] == FN_LIBCHAR)
+ {
+ buff[0]=FN_HOMELIB;
+ (void) strmov_overlapp(buff+1,buff+length);
+ }
+ }
+ if (is_prefix(to,buff))
+ {
+ length=strlen(buff);
+ if (to[length])
+ (void) strmov_overlapp(to,to+length); /* Remove everything before */
+ else
+ {
+ to[0]= FN_CURLIB; /* Put ./ instead of cwd */
+ to[1]= FN_LIBCHAR;
+ to[2]= '\0';
+ }
+ }
+ }
+ }
+ DBUG_PRINT("exit",("to: '%s'",to));
+ DBUG_VOID_RETURN;
+} /* pack_dirname */
+
+
+ /* remove unwanted chars from dirname */
+ /* if "/../" removes prev dir; "/~/" removes all before ~ */
+ /* "//" is same as "/", except on Win32 at start of a file */
+ /* "/./" is removed */
+ /* Unpacks home_dir if "~/.." used */
+ /* Unpacks current dir if if "./.." used */
+
+uint cleanup_dirname(register my_string to, const char *from)
+ /* to may be == from */
+
+{
+ reg5 uint length;
+ reg2 my_string pos;
+ reg3 my_string from_ptr;
+ reg4 my_string start;
+ char parent[5], /* for "FN_PARENTDIR" */
+ buff[FN_REFLEN+1],*end_parentdir;
+ DBUG_ENTER("cleanup_dirname");
+ DBUG_PRINT("enter",("from: '%s'",from));
+
+ start=buff;
+ from_ptr=(my_string) from;
+#ifdef FN_DEVCHAR
+ if ((pos=strrchr(from_ptr,FN_DEVCHAR)) != 0)
+ { /* Skipp device part */
+ length=(uint) (pos-from_ptr)+1;
+ start=strnmov(buff,from_ptr,length); from_ptr+=length;
+ }
+#endif
+
+ parent[0]=FN_LIBCHAR;
+ length=(uint) (strmov(parent+1,FN_PARENTDIR)-parent);
+ for (pos=start ; (*pos= *from_ptr++) != 0 ; pos++)
+ {
+ if (*pos == '/')
+ *pos = FN_LIBCHAR;
+ if (*pos == FN_LIBCHAR)
+ {
+ if ((uint) (pos-start) > length && bcmp(pos-length,parent,length) == 0)
+ { /* If .../../; skipp prev */
+ pos-=length;
+ if (pos != start)
+ { /* not /../ */
+ pos--;
+ if (*pos == FN_HOMELIB && (pos == start || pos[-1] == FN_LIBCHAR))
+ {
+ if (!home_dir)
+ {
+ pos+=length+1; /* Don't unpack ~/.. */
+ continue;
+ }
+ pos=strmov(buff,home_dir)-1; /* Unpacks ~/.. */
+ if (*pos == FN_LIBCHAR)
+ pos--; /* home ended with '/' */
+ }
+ if (*pos == FN_CURLIB && (pos == start || pos[-1] == FN_LIBCHAR))
+ {
+ if (my_getwd(curr_dir,FN_REFLEN,MYF(0)))
+ {
+ pos+=length+1; /* Don't unpack ./.. */
+ continue;
+ }
+ pos=strmov(buff,curr_dir)-1; /* Unpacks ./.. */
+ if (*pos == FN_LIBCHAR)
+ pos--; /* home ended with '/' */
+ }
+ end_parentdir=pos;
+ while (pos >= start && *pos != FN_LIBCHAR) /* remove prev dir */
+ pos--;
+ if (pos[1] == FN_HOMELIB || bcmp(pos,parent,length) == 0)
+ { /* Don't remove ~user/ */
+ pos=strmov(end_parentdir+1,parent);
+ *pos=FN_LIBCHAR;
+ continue;
+ }
+ }
+ }
+ else if ((uint) (pos-start) == length-1 &&
+ !bcmp(start,parent+1,length-1))
+ start=pos; /* Starts with "../" */
+ else if (pos-start > 0 && pos[-1] == FN_LIBCHAR)
+ {
+#ifdef FN_NETWORK_DRIVES
+ if (pos-start != 1)
+#endif
+ pos--; /* Remove dupplicate '/' */
+ }
+ else if (pos-start > 1 && pos[-1] == FN_CURLIB && pos[-2] == FN_LIBCHAR)
+ pos-=2; /* Skipp /./ */
+ else if (pos > buff+1 && pos[-1] == FN_HOMELIB && pos[-2] == FN_LIBCHAR)
+ { /* Found ..../~/ */
+ buff[0]=FN_HOMELIB;
+ buff[1]=FN_LIBCHAR;
+ start=buff; pos=buff+1;
+ }
+ }
+ }
+ (void) strmov(to,buff);
+ DBUG_PRINT("exit",("to: '%s'",to));
+ DBUG_RETURN((uint) (pos-buff));
+} /* cleanup_dirname */
+
+
+ /*
+ On system where you don't have symbolic links, the following
+ code will allow you to create a file:
+ directory-name.lnk that should contain the real path
+ 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 */
+
+#ifdef USE_SYMDIR
+void symdirget(char *dir)
+{
+ char buff[FN_REFLEN];
+ char *pos=strend(dir);
+ if (dir[0] && pos[-1] != FN_DEVCHAR && access(dir, F_OK))
+ {
+ FILE *fp;
+ char temp= *(--pos); /* May be "/" or "\" */
+ strmov(pos,".sym");
+ fp = my_fopen(dir, O_RDONLY,MYF(0));
+ *pos++=temp; *pos=0; /* Restore old filename */
+ if (fp)
+ {
+ if (fgets(buff, sizeof(buff), fp))
+ {
+ for (pos=strend(buff);
+ pos > buff && (iscntrl(pos[-1]) || isspace(pos[-1])) ;
+ pos --);
+ strmake(dir,buff, (uint) (pos-buff));
+ }
+ my_fclose(fp,MYF(0));
+ }
+ }
+}
+#endif /* USE_SYMDIR */
+
+ /* Unpacks dirname to name that can be used by open... */
+ /* Make that last char of to is '/' if from not empty and
+ from doesn't end in FN_DEVCHAR */
+ /* Uses cleanup_dirname and changes ~/.. to home_dir/.. */
+ /* Returns length of new directory */
+
+uint unpack_dirname(my_string to, const char *from)
+
+ /* to may be == from */
+{
+ uint length,h_length;
+ char buff[FN_REFLEN+1+4],*suffix,*tilde_expansion;
+ DBUG_ENTER("unpack_dirname");
+
+ (void) intern_filename(buff,from); /* Change to intern name */
+ length=strlen(buff); /* Fix that '/' is last */
+ if (length &&
+#ifdef FN_DEVCHAR
+ buff[length-1] != FN_DEVCHAR &&
+#endif
+ buff[length-1] != FN_LIBCHAR && buff[length-1] != '/')
+ {
+ buff[length]=FN_LIBCHAR;
+ buff[length+1]= '\0';
+ }
+
+ length=cleanup_dirname(buff,buff);
+ if (buff[0] == FN_HOMELIB)
+ {
+ suffix=buff+1; tilde_expansion=expand_tilde(&suffix);
+ if (tilde_expansion)
+ {
+ length-=(uint) (suffix-buff)-1;
+ if (length+(h_length=strlen(tilde_expansion)) <= FN_REFLEN)
+ {
+ if (tilde_expansion[h_length-1] == FN_LIBCHAR)
+ h_length--;
+ if (buff+h_length < suffix)
+ bmove(buff+h_length,suffix,length);
+ else
+ bmove_upp(buff+h_length+length,suffix+length,length);
+ bmove(buff,tilde_expansion,h_length);
+ }
+ }
+ }
+#ifdef USE_SYMDIR
+ if (my_use_symdir)
+ symdirget(buff);
+#endif
+ DBUG_RETURN(system_filename(to,buff)); /* Fix for open */
+} /* unpack_dirname */
+
+
+ /* Expand tilde to home or user-directory */
+ /* Path is reset to point at FN_LIBCHAR after ~xxx */
+
+static my_string NEAR_F expand_tilde(my_string *path)
+{
+ if (path[0][0] == FN_LIBCHAR)
+ return home_dir; /* ~/ expanded to home */
+#ifdef HAVE_GETPWNAM
+ {
+ char *str,save;
+ struct passwd *user_entry;
+
+ if (!(str=strchr(*path,FN_LIBCHAR)))
+ str=strend(*path);
+ save= *str; *str= '\0';
+ user_entry=getpwnam(*path);
+ *str=save;
+ endpwent();
+ if (user_entry)
+ {
+ *path=str;
+ return user_entry->pw_dir;
+ }
+ }
+#endif
+ return (my_string) 0;
+}
+
+ /* fix filename so it can be used by open, create .. */
+ /* to may be == from */
+ /* Returns to */
+
+my_string unpack_filename(my_string to, const char *from)
+{
+ uint length,n_length;
+ char buff[FN_REFLEN];
+ DBUG_ENTER("unpack_filename");
+
+ length=dirname_part(buff,from); /* copy & convert dirname */
+ n_length=unpack_dirname(buff,buff);
+ if (n_length+strlen(from+length) < FN_REFLEN)
+ {
+ (void) strmov(buff+n_length,from+length);
+ (void) system_filename(to,buff); /* Fix to usably filename */
+ }
+ else
+ (void) system_filename(to,from); /* Fix to usably filename */
+ DBUG_RETURN(to);
+} /* unpack_filename */
+
+
+ /* Convert filename (unix standard) to system standard */
+ /* Used before system command's like open(), create() .. */
+ /* Returns to */
+
+uint system_filename(my_string to, const char *from)
+{
+#ifndef FN_C_BEFORE_DIR
+ return (uint) (strmake(to,from,FN_REFLEN-1)-to);
+#else /* VMS */
+
+ /* change 'dev:lib/xxx' to 'dev:[lib]xxx' */
+ /* change 'dev:xxx' to 'dev:xxx' */
+ /* change './xxx' to 'xxx' */
+ /* change './lib/' or lib/ to '[.lib]' */
+ /* change '/x/y/z to '[x.y]x' */
+ /* change 'dev:/x' to 'dev:[000000]x' */
+
+ int libchar_found,length;
+ my_string to_pos,from_pos,pos;
+ char buff[FN_REFLEN];
+ DBUG_ENTER("system_filename");
+
+ libchar_found=0;
+ (void) strmov(buff,from); /* If to == from */
+ from_pos= buff;
+ if ((pos=strrchr(from_pos,FN_DEVCHAR))) /* Skipp device part */
+ {
+ pos++;
+ to_pos=strnmov(to,from_pos,(size_s) (pos-from_pos));
+ from_pos=pos;
+ }
+ else
+ to_pos=to;
+
+ if (from_pos[0] == FN_CURLIB && from_pos[1] == FN_LIBCHAR)
+ from_pos+=2; /* Skipp './' */
+ if (strchr(from_pos,FN_LIBCHAR))
+ {
+ *(to_pos++) = FN_C_BEFORE_DIR;
+ if (strinstr(from_pos,FN_ROOTDIR) == 1)
+ {
+ from_pos+=strlen(FN_ROOTDIR); /* Actually +1 but... */
+ if (! strchr(from_pos,FN_LIBCHAR))
+ { /* No dir, use [000000] */
+ to_pos=strmov(to_pos,FN_C_ROOT_DIR);
+ libchar_found++;
+ }
+ }
+ else
+ *(to_pos++)=FN_C_DIR_SEP; /* '.' gives current dir */
+
+ while ((pos=strchr(from_pos,FN_LIBCHAR)))
+ {
+ if (libchar_found++)
+ *(to_pos++)=FN_C_DIR_SEP; /* Add '.' between dirs */
+ if (strinstr(from_pos,FN_PARENTDIR) == 1 &&
+ from_pos+strlen(FN_PARENTDIR) == pos)
+ to_pos=strmov(to_pos,FN_C_PARENT_DIR); /* Found '../' */
+ else
+ to_pos=strnmov(to_pos,from_pos,(size_s) (pos-from_pos));
+ from_pos=pos+1;
+ }
+ *(to_pos++)=FN_C_AFTER_DIR;
+ }
+ length=(int) (strmov(to_pos,from_pos)-to);
+ DBUG_PRINT("exit",("name: '%s'",to));
+ DBUG_RETURN((uint) length);
+#endif
+} /* system_filename */
+
+
+ /* Fix a filename to intern (UNIX format) */
+
+my_string intern_filename(my_string to, const char *from)
+{
+#ifndef VMS
+ {
+ uint length;
+ char buff[FN_REFLEN];
+ if (from == to)
+ { /* Dirname may destroy from */
+ strmov(buff,from);
+ from=buff;
+ }
+ length=dirname_part(to,from); /* Copy dirname & fix chars */
+ (void) strcat(to,from+length);
+ return (to);
+ }
+#else /* VMS */
+
+ /* change 'dev:[lib]xxx' to 'dev:lib/xxx' */
+ /* change 'dev:xxx' to 'dev:xxx' */
+ /* change 'dev:x/y/[.lib]' to 'dev:x/y/lib/ */
+ /* change '[.lib]' to './lib/' */
+ /* change '[x.y]' or '[x.][y]' or '[x][.y]' to '/x/y/' */
+ /* change '[000000.x] or [x.000000]' to '/x/' */
+
+ int par_length,root_length;
+ my_string pos,from_pos,to_pos,end_pos;
+ char buff[FN_REFLEN];
+
+ (void) strmov(buff,from);
+ convert_dirname(buff); /* change '<>' to '[]' */
+ from_pos=buff;
+ if ((pos=strrchr(from_pos,FN_DEVCHAR))) /* Skipp device part */
+ {
+ pos++;
+ to_pos=strnmov(to,from_pos,(size_s) (pos-from_pos));
+ from_pos=pos;
+ }
+ else
+ to_pos=to;
+
+ root_length=strlen(FN_C_ROOT_DIR);
+ if ((pos = strchr(from_pos,FN_C_BEFORE_DIR)) &&
+ (end_pos = strrchr(pos+1,FN_C_AFTER_DIR)))
+ {
+ to_pos=strnmov(to_pos,from_pos,(size_s) (pos-from_pos));
+ /* Copy all between ':' and '[' */
+ from_pos=pos+1;
+ if (strinstr(from_pos,FN_C_ROOT_DIR) == 1 &&
+ (from_pos[root_length] == FN_C_DIR_SEP ||
+ from_pos[root_length] == FN_C_AFTER_DIR))
+ {
+ from_pos+=root_length+1;
+ }
+ else if (*from_pos == FN_C_DIR_SEP)
+ *(to_pos++) = FN_CURLIB; /* Set ./ first */
+ *(to_pos++) = FN_LIBCHAR;
+
+ par_length=strlen(FN_C_PARENT_DIR);
+ pos=to_pos;
+ for (; from_pos <= end_pos ; from_pos++)
+ {
+ switch (*from_pos) {
+ case FN_C_DIR_SEP:
+ case FN_C_AFTER_DIR:
+ if (pos != to_pos)
+ {
+ if ((int) (to_pos-pos) == root_length &&
+ is_suffix(pos,FN_C_ROOT_DIR))
+ to_pos=pos; /* remove root-pos */
+ else
+ {
+ *(to_pos++)=FN_LIBCHAR; /* Find lib */
+ pos=to_pos;
+ }
+ }
+ break;
+ case FN_C_BEFORE_DIR:
+ break;
+ case '-': /* *(FN_C_PARENT_DIR): */
+ if (to_pos[-1] == FN_LIBCHAR &&
+ strncmp(from_pos,FN_C_PARENT_DIR,par_length) == 0)
+ { /* Change '-' to '..' */
+ to_pos=strmov(to_pos,FN_PARENTDIR);
+ *(to_pos++)=FN_LIBCHAR;
+ pos=to_pos;
+ from_pos+=par_length-1;
+ break;
+ }
+ /* Fall through */
+ default:
+ *(to_pos++)= *from_pos;
+ break;
+ }
+ }
+ }
+ (void) strmov(to_pos,from_pos);
+ return (to);
+#endif /* VMS */
+} /* intern_filename */
diff --git a/mysys/mf_pack2.c b/mysys/mf_pack2.c
new file mode 100644
index 00000000000..1cda7797457
--- /dev/null
+++ b/mysys/mf_pack2.c
@@ -0,0 +1,53 @@
+/* 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
new file mode 100644
index 00000000000..0a0a760cea1
--- /dev/null
+++ b/mysys/mf_path.c
@@ -0,0 +1,120 @@
+/* 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>
+
+static char *find_file_in_path(char *to,const char *name);
+
+ /* Finds where program can find it's files.
+ pre_pathname is found by first locking at progname (argv[0]).
+ if progname contains path the path is returned.
+ else if progname is found in path, return it
+ else if progname is given and POSIX environment variable "_" is set
+ then path is taken from "_".
+ If filename doesn't contain a path append MY_BASEDIR_VERSION or
+ MY_BASEDIR if defined, else append "/my/running".
+ own_path_name_part is concatinated to result.
+ my_path puts result in to and returns to */
+
+my_string my_path(my_string to, const char *progname,
+ const char *own_pathname_part)
+{
+ my_string start,end,prog;
+ DBUG_ENTER("my_path");
+
+ start=to; /* Return this */
+ if (progname && (dirname_part(to, progname) ||
+ find_file_in_path(to,progname) ||
+ ((prog=getenv("_")) != 0 && dirname_part(to,prog))))
+ {
+ VOID(intern_filename(to,to));
+ if (!test_if_hard_path(to))
+ {
+ if (!my_getwd(curr_dir,FN_REFLEN,MYF(0)))
+ bchange(to,0,curr_dir,strlen(curr_dir),strlen(to)+1);
+ }
+ }
+ else
+ {
+ if ((end = getenv("MY_BASEDIR_VERSION")) == 0 &&
+ (end = getenv("MY_BASEDIR")) == 0)
+ {
+#ifdef DEFAULT_BASEDIR
+ end= (char*) DEFAULT_BASEDIR;
+#else
+ end= (char*) "/my/";
+#endif
+ }
+ VOID(intern_filename(to,end));
+ to=strend(to);
+ if (to != start && to[-1] != FN_LIBCHAR)
+ *to++ = FN_LIBCHAR;
+ VOID(strmov(to,own_pathname_part));
+ }
+ DBUG_PRINT("exit",("to: '%s'",start));
+ DBUG_RETURN(start);
+} /* my_path */
+
+
+ /* test if file without filename is found in path */
+ /* Returns to if found and to has dirpart if found, else NullS */
+
+#if defined(MSDOS) || defined(__WIN__)
+#define F_OK 0
+#define PATH_SEP ';'
+#define PROGRAM_EXTENSION ".exe"
+#else
+#define PATH_SEP ':'
+#endif
+
+static char *find_file_in_path(char *to, const char *name)
+{
+ char *path,*pos,dir[2];
+ const char *ext="";
+
+ if (!(path=getenv("PATH")))
+ return NullS;
+ dir[0]=FN_LIBCHAR; dir[1]=0;
+#ifdef PROGRAM_EXTENSION
+ if (!fn_ext(name)[0])
+ ext=PROGRAM_EXTENSION;
+#endif
+
+ for (pos=path ; (pos=strchr(pos,PATH_SEP)) ; path= ++pos)
+ {
+ if (path != pos)
+ {
+ strxmov(strnmov(to,path,(uint) (pos-path)),dir,name,ext,NullS);
+ if (!access(to,F_OK))
+ {
+ to[(uint) (pos-path)+1]=0; /* Return path only */
+ return to;
+ }
+ }
+ }
+#ifdef __WIN__
+ to[0]=FN_CURLIB;
+ strxmov(to+1,dir,name,ext,NullS);
+ if (!access(to,F_OK)) /* Test in current dir */
+ {
+ to[2]=0; /* Leave ".\" */
+ return to;
+ }
+#endif
+ return NullS; /* File not found */
+}
diff --git a/mysys/mf_qsort.c b/mysys/mf_qsort.c
new file mode 100644
index 00000000000..15fa5638639
--- /dev/null
+++ b/mysys/mf_qsort.c
@@ -0,0 +1,258 @@
+/* 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 */
+
+/* Plug-compatible replacement for UNIX qsort.
+ Copyright (C) 1989 Free Software Foundation, Inc.
+ Written by Douglas C. Schmidt (schmidt@ics.uci.edu)
+ Optimized and modyfied for mysys by monty.
+
+This file is part of GNU CC.
+
+GNU QSORT is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 1, or (at your option)
+any later version.
+
+GNU QSORT is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU QSORT; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "mysys_priv.h"
+#if !defined(HAVE_purify) || defined(QSORT_EXTRA_CMP_ARGUMENT)
+
+/* Envoke the comparison function, returns either 0, < 0, or > 0. */
+#ifdef QSORT_EXTRA_CMP_ARGUMENT
+#define CMP(A,B) ((*cmp)(cmp_argument,(A),(B)))
+#else
+#define CMP(A,B) ((*cmp)((A),(B)))
+#endif
+
+/* Byte-wise swap two items of size SIZE. */
+#define SWAP(A,B,SIZE) do {int sz=(int)(SIZE); char *a = (A); char *b = (B); \
+ do { char _temp = *a;*a++ = *b;*b++ = _temp;} while (--sz);} while (0)
+
+/* Copy SIZE bytes from item B to item A. */
+#define COPY(A,B,SIZE) {int sz = (int) (SIZE); do { *(A)++ = *(B)++; } while (--sz); }
+
+/* This should be replaced by a standard ANSI macro. */
+#define BYTES_PER_WORD 8
+
+/* The next 4 #defines implement a very fast in-line stack abstraction. */
+#define STACK_SIZE (BYTES_PER_WORD * sizeof (long))
+#define PUSH(LOW,HIGH) do {top->lo = LOW;top++->hi = HIGH;} while (0)
+#define POP(LOW,HIGH) do {LOW = (--top)->lo;HIGH = top->hi;} while (0)
+#define STACK_NOT_EMPTY (stack < top)
+
+/* Discontinue quicksort algorithm when partition gets below this size.
+ This particular magic number was chosen to work best on a Sparc SLC. */
+#define MAX_THRESH 12
+
+/* Stack node declarations used to store unfulfilled partition obligations. */
+typedef struct
+{
+ char *lo;
+ char *hi;
+} stack_node;
+
+/* Order size using quicksort. This implementation incorporates
+ four optimizations discussed in Sedgewick:
+
+ 1. Non-recursive, using an explicit stack of pointer that store the
+ next array partition to sort. To save time, this maximum amount
+ of space required to store an array of MAX_INT is allocated on the
+ stack. Assuming a 32-bit integer, this needs only 32 *
+ sizeof (stack_node) == 136 bits. Pretty cheap, actually.
+
+ 2. Chose the pivot element using a median-of-three decision tree.
+ This reduces the probability of selecting a bad pivot value and
+ eliminates certain extraneous comparisons.
+
+ 3. Only quicksorts TOTAL_ELEMS / MAX_THRESH partitions, leaving
+ insertion sort to order the MAX_THRESH items within each partition.
+ This is a big win, since insertion sort is faster for small, mostly
+ sorted array segements.
+
+ 4. The larger of the two sub-partitions is always pushed onto the
+ stack first, with the algorithm then concentrating on the
+ smaller partition. This *guarantees* no more than log (n)
+ stack size is needed (actually O(1) in this case)! */
+
+#if defined(QSORT_TYPE_IS_VOID)
+#define SORT_RETURN return
+#else
+#define SORT_RETURN return 0
+#endif
+
+#ifdef QSORT_EXTRA_CMP_ARGUMENT
+qsort_t qsort2(void *base_ptr, size_t total_elems, size_t size, qsort2_cmp cmp,
+ void *cmp_argument)
+#else
+qsort_t qsort(void *base_ptr, size_t total_elems, size_t size, qsort_cmp cmp)
+#endif
+{
+ /* Allocating SIZE bytes for a pivot buffer facilitates a better
+ algorithm below since we can do comparisons directly on the pivot.
+ */
+ int max_thresh = (int) (MAX_THRESH * size);
+ if (total_elems <= 1)
+ SORT_RETURN; /* Crashes on MSDOS if continues */
+
+ if (total_elems > MAX_THRESH)
+ {
+ char *lo = base_ptr;
+ char *hi = lo + size * (total_elems - 1);
+ stack_node stack[STACK_SIZE]; /* Largest size needed for 32-bit int!!! */
+ stack_node *top = stack + 1;
+ char *pivot_buffer = (char *) my_alloca ((int) size);
+
+ while (STACK_NOT_EMPTY)
+ {
+ char *left_ptr;
+ char *right_ptr;
+ {
+ char *pivot = pivot_buffer;
+ {
+ /* Select median value from among LO, MID, and HI. Rearrange
+ LO and HI so the three values are sorted. This lowers the
+ probability of picking a pathological pivot value and
+ skips a comparison for both the LEFT_PTR and RIGHT_PTR. */
+
+ char *mid = lo + size * (((uint) (hi - lo) / (uint) size) >> 1);
+
+ if (CMP(hi,lo) < 0)
+ SWAP (hi, lo, size);
+ if (CMP (mid, lo) < 0)
+ SWAP (mid, lo, size);
+ else if (CMP (hi, mid) < 0)
+ SWAP (mid, hi, size);
+ COPY (pivot, mid, size);
+ pivot = pivot_buffer;
+ }
+ left_ptr = lo + size;
+ right_ptr = hi - size;
+
+ /* Here's the famous ``collapse the walls'' section of quicksort.
+ Gotta like those tight inner loops! They are the main reason
+ that this algorithm runs much faster than others. */
+ do
+ {
+ while (CMP (left_ptr, pivot) < 0)
+ left_ptr += size;
+
+ while (CMP (pivot, right_ptr) < 0)
+ right_ptr -= size;
+
+ if (left_ptr < right_ptr)
+ {
+ SWAP (left_ptr, right_ptr, size);
+ left_ptr += size;
+ right_ptr -= size;
+ }
+ else if (left_ptr == right_ptr)
+ {
+ left_ptr += size;
+ right_ptr -= size;
+ break;
+ }
+ }
+ while (left_ptr <= right_ptr);
+ }
+
+ /* Set up pointers for next iteration. First determine whether
+ left and right partitions are below the threshold size. If so,
+ ignore one or both. Otherwise, push the larger partition's
+ bounds on the stack and continue sorting the smaller one. */
+
+ if ((right_ptr - lo) <= max_thresh)
+ {
+ if ((hi - left_ptr) <= max_thresh) /* Ignore both small parts. */
+ POP (lo, hi);
+ else /* Ignore small left part. */
+ lo = left_ptr;
+ }
+ else if ((hi - left_ptr) <= max_thresh) /* Ignore small right part. */
+ hi = right_ptr;
+ else if ((right_ptr - lo) > (hi - left_ptr)) /* Push larger left part */
+ {
+ PUSH (lo, right_ptr);
+ lo = left_ptr;
+ }
+ else /* Push larger right part */
+ {
+ PUSH (left_ptr, hi);
+ hi = right_ptr;
+ }
+ }
+ my_afree(pivot_buffer);
+ }
+
+ /* Once the BASE_PTR array is partially sorted by quicksort the rest
+ is completely sorted using insertion sort, since this is efficient
+ for partitions below MAX_THRESH size. BASE_PTR points to the beginning
+ of the array to sort, and END_PTR points at the very last element in
+ the array (*not* one beyond it!). */
+
+ {
+ char *end_ptr = (char*) base_ptr + size * (total_elems - 1);
+ char *run_ptr;
+ char *tmp_ptr = (char*) base_ptr;
+ char *thresh = min (end_ptr, (char*) base_ptr + max_thresh);
+
+ /* Find smallest element in first threshold and place it at the
+ array's beginning. This is the smallest array element,
+ and the operation speeds up insertion sort's inner loop. */
+
+ for (run_ptr = tmp_ptr + size; run_ptr <= thresh; run_ptr += size)
+ if (CMP (run_ptr, tmp_ptr) < 0)
+ tmp_ptr = run_ptr;
+
+ if (tmp_ptr != (char*) base_ptr)
+ SWAP (tmp_ptr, (char*) base_ptr, size);
+
+ /* Insertion sort, running from left-hand-side up to `right-hand-side.'
+ Pretty much straight out of the original GNU qsort routine. */
+
+ for (run_ptr = (char*) base_ptr + size;
+ (tmp_ptr = run_ptr += size) <= end_ptr; )
+ {
+ while (CMP (run_ptr, tmp_ptr -= size) < 0) ;
+
+ if ((tmp_ptr += size) != run_ptr)
+ {
+ char *trav;
+
+ for (trav = run_ptr + size; --trav >= run_ptr;)
+ {
+ char c = *trav;
+ char *hi, *lo;
+
+ for (hi = lo = trav; (lo -= size) >= tmp_ptr; hi = lo)
+ *hi = *lo;
+ *hi = c;
+ }
+ }
+
+ }
+ }
+ SORT_RETURN;
+}
+#endif /* HAVE_purify */
diff --git a/mysys/mf_qsort2.c b/mysys/mf_qsort2.c
new file mode 100644
index 00000000000..7b1ca4e39ab
--- /dev/null
+++ b/mysys/mf_qsort2.c
@@ -0,0 +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,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should 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 */
+
+/* qsort that sends one extra argument to the compare subrutine */
+
+#define QSORT_EXTRA_CMP_ARGUMENT
+#include "mf_qsort.c"
diff --git a/mysys/mf_radix.c b/mysys/mf_radix.c
new file mode 100644
index 00000000000..99aa4d0b073
--- /dev/null
+++ b/mysys/mf_radix.c
@@ -0,0 +1,56 @@
+/* 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 */
+
+/*
+ Radixsort for pointers to fixed length strings.
+ A very quick sort for not to long (< 20 char) strings.
+ Neads a extra buffers of number_of_elements pointers but is
+ 2-3 times faster than quicksort
+*/
+
+#include "mysys_priv.h"
+#include <m_string.h>
+
+ /* Radixsort */
+
+void radixsort_for_str_ptr(uchar **base, uint number_of_elements, size_s size_of_element, uchar **buffer)
+{
+ uchar **end,**ptr,**buffer_ptr;
+ uint32 *count_ptr,*count_end,count[256];
+ int pass;
+
+ end=base+number_of_elements; count_end=count+256;
+ for (pass=(int) size_of_element-1 ; pass >= 0 ; pass--)
+ {
+ bzero((gptr) count,sizeof(uint32)*256);
+ for (ptr= base ; ptr < end ; ptr++)
+ count[ptr[0][pass]]++;
+ if (count[0] == number_of_elements)
+ goto next;
+ for (count_ptr=count+1 ; count_ptr < count_end ; count_ptr++)
+ {
+ if (*count_ptr == number_of_elements)
+ goto next;
+ (*count_ptr)+= *(count_ptr-1);
+ }
+ for (ptr= end ; ptr-- != base ;)
+ buffer[--count[ptr[0][pass]]]= *ptr;
+ for (ptr=base, buffer_ptr=buffer ; ptr < end ;)
+ (*ptr++) = *buffer_ptr++;
+ next:;
+ }
+}
diff --git a/mysys/mf_same.c b/mysys/mf_same.c
new file mode 100644
index 00000000000..5b8c5ecf970
--- /dev/null
+++ b/mysys/mf_same.c
@@ -0,0 +1,38 @@
+/* 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 */
+
+/* Kopierar biblioteksstrukturen och extensionen fr}n ett filnamn */
+
+#include "mysys_priv.h"
+#include <m_string.h>
+
+ /* Formaterar ett filnamn i avsende p} ett annat namn */
+ /* Klarar {ven to = name */
+ /* Denna funktion r|r inte p} utg}ngsnamnet */
+
+my_string fn_same(my_string toname, const char *name, int flag)
+{
+ char dev[FN_REFLEN];
+ const char *ext;
+ DBUG_ENTER("fn_same");
+ DBUG_PRINT("mfunkt",("to: %s name: %s flag: %d",toname,name,flag));
+
+ if ((ext=strrchr(name+dirname_part(dev,name),FN_EXTCHAR)) == 0)
+ ext="";
+
+ DBUG_RETURN(fn_format(toname,toname,dev,ext,flag));
+} /* fn_same */
diff --git a/mysys/mf_sleep.c b/mysys/mf_sleep.c
new file mode 100644
index 00000000000..f33a904cf5a
--- /dev/null
+++ b/mysys/mf_sleep.c
@@ -0,0 +1,36 @@
+/* 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 */
+
+/* Wait a given time (On systems that dont have sleep !!; MSDOS) */
+
+#include "mysys_priv.h"
+#include <m_string.h>
+
+#ifdef _MSC_VER
+
+void sleep(sec)
+int sec;
+{
+ ulong start;
+ DBUG_ENTER("sleep");
+
+ start=(ulong) time((time_t*) 0);
+ while ((ulong) time((time_t*) 0) < start+sec);
+ DBUG_VOID_RETURN;
+} /* sleep */
+
+#endif /* MSDOS */
diff --git a/mysys/mf_sort.c b/mysys/mf_sort.c
new file mode 100644
index 00000000000..754a1deb1a7
--- /dev/null
+++ b/mysys/mf_sort.c
@@ -0,0 +1,43 @@
+/* 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 */
+
+/* Sort of string pointers in string-order with radix or qsort */
+
+#include "mysys_priv.h"
+#include <m_string.h>
+
+void my_string_ptr_sort(void *base, uint items, size_s size)
+{
+#if INT_MAX > 65536L
+ uchar **ptr=0;
+
+ if (size <= 20 && items >= 1000 &&
+ (ptr= (uchar**) my_malloc(items*sizeof(char*),MYF(0))))
+ {
+ radixsort_for_str_ptr((uchar**) base,items,size,ptr);
+ my_free((gptr) ptr,MYF(0));
+ }
+ else
+#endif
+ {
+ if (size && items)
+ {
+ uint size_arg=size;
+ qsort2(base,items,sizeof(byte*),get_ptr_compare(size),(void*) &size_arg);
+ }
+ }
+}
diff --git a/mysys/mf_soundex.c b/mysys/mf_soundex.c
new file mode 100644
index 00000000000..827385a1466
--- /dev/null
+++ b/mysys/mf_soundex.c
@@ -0,0 +1,102 @@
+/* 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 */
+
+/****************************************************************
+* SOUNDEX ALGORITHM in C *
+* *
+* The basic Algorithm source is taken from EDN Nov. *
+* 14, 1985 pg. 36. *
+* *
+* As a test Those in Illinois will find that the *
+* first group of numbers in their drivers license *
+* number is the soundex number for their last name. *
+* *
+* RHW PC-IBBS ID. #1230 *
+* *
+* As an extension if remove_garbage is set then all non- *
+* alpha characters are skipped *
+****************************************************************/
+
+#include "mysys_priv.h"
+#include <m_ctype.h>
+#include "my_static.h"
+
+static char get_scode(char **ptr,pbool remove_garbage);
+
+ /* outputed string is 4 byte long */
+ /* out_pntr can be == in_pntr */
+
+void soundex(register my_string out_pntr, my_string in_pntr,
+ pbool remove_garbage)
+{
+ char ch,last_ch;
+ reg3 my_string end;
+
+ if (remove_garbage)
+ {
+ while (*in_pntr && isspace(*in_pntr)) /* Skipp pre-space */
+ in_pntr++;
+ }
+ *out_pntr++ = toupper(*in_pntr); /* Copy first letter */
+ last_ch = get_scode(&in_pntr,0); /* code of the first letter */
+ /* for the first 'double-letter */
+ /* check. */
+ end=out_pntr+3; /* Loop on input letters until */
+ /* end of input (null) or output */
+ /* letter code count = 3 */
+
+ in_pntr++;
+ while (out_pntr < end && (ch = get_scode(&in_pntr,remove_garbage)) != 0)
+ {
+ in_pntr++;
+ if ((ch != '0') && (ch != last_ch)) /* if not skipped or double */
+ {
+ *out_pntr++ = ch; /* letter, copy to output */
+ } /* for next double-letter check */
+ last_ch = ch; /* save code of last input letter */
+ }
+ while (out_pntr < end)
+ *out_pntr++ = '0';
+ *out_pntr=0; /* end string */
+ return;
+} /* soundex */
+
+
+ /*
+ If alpha, map input letter to soundex code.
+ If not alpha and remove_garbage is set then skipp to next char
+ else return 0
+ */
+
+static char get_scode(char **ptr, pbool remove_garbage)
+{
+ uchar ch;
+
+ if (remove_garbage)
+ {
+ while (**ptr && !isalpha(**ptr))
+ (*ptr)++;
+ }
+ ch=toupper(**ptr);
+ if (ch < 'A' || ch > 'Z')
+ {
+ if (isalpha(ch)) /* If exetended alfa (country spec) */
+ return '0'; /* threat as vokal */
+ return 0; /* Can't map */
+ }
+ return(soundex_map[ch-'A']);
+} /* get_scode */
diff --git a/mysys/mf_stripp.c b/mysys/mf_stripp.c
new file mode 100644
index 00000000000..6ebdce4cff6
--- /dev/null
+++ b/mysys/mf_stripp.c
@@ -0,0 +1,47 @@
+/* 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 */
+
+/* T|mmer en str{ng p{ slut_space */
+
+#include "mysys_priv.h"
+
+/*
+ stripp_sp(my_string str)
+ Strips end-space from string and returns new length.
+*/
+
+size_s stripp_sp(register my_string str)
+{
+ reg2 my_string found;
+ reg3 my_string start;
+
+ start=found=str;
+
+ while (*str)
+ {
+ if (*str != ' ')
+ {
+ while (*++str && *str != ' ') {};
+ if (!*str)
+ return (size_s) (str-start); /* Return stringlength */
+ }
+ found=str;
+ while (*++str == ' ') {};
+ }
+ *found= '\0'; /* Stripp at first space */
+ return (size_s) (found-start);
+} /* stripp_sp */
diff --git a/mysys/mf_unixpath.c b/mysys/mf_unixpath.c
new file mode 100644
index 00000000000..6ae29f99136
--- /dev/null
+++ b/mysys/mf_unixpath.c
@@ -0,0 +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,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should 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>
+
+ /* convert filename to unix style filename */
+ /* If MSDOS converts '\' to '/' */
+
+void to_unix_path(my_string to __attribute__((unused)))
+{
+#if FN_LIBCHAR != '/'
+ {
+ to--;
+ while ((to=strchr(to+1,FN_LIBCHAR)) != 0)
+ *to='/';
+ }
+#endif
+}
diff --git a/mysys/mf_util.c b/mysys/mf_util.c
new file mode 100644
index 00000000000..12af323680e
--- /dev/null
+++ b/mysys/mf_util.c
@@ -0,0 +1,49 @@
+/* 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 */
+
+/* Utilities with are missing on some systems */
+
+#include "mysys_priv.h"
+#ifdef __ZTC__
+#include <dos.h>
+#endif
+
+#ifdef __ZTC__
+
+ /* On ZORTECH C we don't have a getpid() call */
+
+int getpid(void)
+{
+ return (int) _psp;
+}
+
+#ifndef M_IC80386
+
+ /* Define halloc and hfree in as in MSC */
+
+void * __CDECL halloc(long count,size_t length)
+{
+ return (void*) MK_FP(dos_alloc((uint) ((count*length+15) >> 4)),0);
+}
+
+void __CDECL hfree(void *ptr)
+{
+ dos_free(FP_SEG(ptr));
+}
+
+#endif /* M_IC80386 */
+#endif /* __ZTC__ */
diff --git a/mysys/mf_wcomp.c b/mysys/mf_wcomp.c
new file mode 100644
index 00000000000..5f1ab9b813e
--- /dev/null
+++ b/mysys/mf_wcomp.c
@@ -0,0 +1,68 @@
+/* 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 */
+
+/* Funktions for comparing with wild-cards */
+
+#include "mysys_priv.h"
+
+ /* Test if a string is "comparable" to a wild-card string */
+ /* returns 0 if the strings are "comparable" */
+
+char wild_many='*';
+char wild_one='?';
+char wild_prefix=0;
+
+int wild_compare(register const char *str, register const char *wildstr)
+{
+ reg3 int flag;
+ DBUG_ENTER("wild_compare");
+
+ while (*wildstr)
+ {
+ while (*wildstr && *wildstr != wild_many && *wildstr != wild_one)
+ {
+ if (*wildstr == wild_prefix && wildstr[1])
+ wildstr++;
+ if (*wildstr++ != *str++) DBUG_RETURN(1);
+ }
+ if (! *wildstr ) DBUG_RETURN (*str != 0);
+ if (*wildstr++ == wild_one)
+ {
+ if (! *str++) DBUG_RETURN (1); /* One char; skipp */
+ }
+ else
+ { /* Found '*' */
+ if (!*wildstr) DBUG_RETURN(0); /* '*' as last char: OK */
+ flag=(*wildstr != wild_many && *wildstr != wild_one);
+ do
+ {
+ if (flag)
+ {
+ char cmp;
+ if ((cmp= *wildstr) == wild_prefix && wildstr[1])
+ cmp=wildstr[1];
+ while (*str && *str != cmp)
+ str++;
+ if (!*str) DBUG_RETURN (1);
+ }
+ if (wild_compare(str,wildstr) == 0) DBUG_RETURN (0);
+ } while (*str++ && wildstr[0] != wild_many);
+ DBUG_RETURN(1);
+ }
+ }
+ DBUG_RETURN (*str != '\0');
+} /* wild_compare */
diff --git a/mysys/mf_wfile.c b/mysys/mf_wfile.c
new file mode 100644
index 00000000000..02e155d9936
--- /dev/null
+++ b/mysys/mf_wfile.c
@@ -0,0 +1,132 @@
+/* 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 */
+
+/* Functions for finding files with wildcards */
+
+/*
+ The following file-name-test is supported:
+ - "name [[,] name...] ; Matches any of used filenames.
+ Each name can have "*" and/or "?"
+ wild-cards.
+ - [wildspec [,]] !wildspec2 ; File that matches wildspec and not
+ wildspec2.
+*/
+
+#include "mysys_priv.h"
+#include <m_string.h>
+
+ /* Store wildcard-string in a easyer format */
+
+WF_PACK *wf_comp(my_string str)
+{
+ uint ant;
+ int not_pos;
+ register my_string pos;
+ my_string buffer;
+ WF_PACK *ret;
+ DBUG_ENTER("wf_comp");
+
+ not_pos= -1; /* Skipp space and '!' in front */
+ while (*str == ' ')
+ str++;
+ if (*str == '!')
+ {
+ not_pos=0;
+ while (*++str == ' ') {};
+ }
+ if (*str == 0) /* Empty == everything */
+ DBUG_RETURN((WF_PACK *) NULL);
+
+ ant=1; /* Count filespecs */
+ for (pos=str ; *pos ; pos++)
+ ant+= test(*pos == ' ' || *pos == ',');
+
+#ifdef FN_UPPER_CASE
+ caseup(str,(int) (pos-str));
+#endif
+#ifdef FN_LOWER_CASE
+ casedn(str,(int) (pos-str));
+#endif
+
+ if ((ret= (WF_PACK*) my_malloc((uint) ant*(sizeof(my_string*)+2)+
+ sizeof(WF_PACK)+strlen(str)+1,MYF(MY_WME)))
+ == 0)
+ DBUG_RETURN((WF_PACK *) NULL);
+ ret->wild= (my_string*) (ret+1);
+ buffer= (my_string) (ret->wild+ant);
+
+ ant=0;
+ for (pos=str ; *pos ; str= pos)
+ {
+ ret->wild[ant++]=buffer;
+ while (*pos != ' ' && *pos != ',' && *pos != '!' && *pos)
+ *buffer++ = *pos++;
+
+ *buffer++ = '\0';
+ while (*pos == ' ' || *pos == ',' || *pos == '!' )
+ if (*pos++ == '!' && not_pos <0)
+ not_pos=(int) ant;
+ }
+
+ ret->wilds=ant;
+ if (not_pos <0)
+ ret->not_pos=ant;
+ else
+ ret->not_pos=(uint) not_pos;
+
+ DBUG_PRINT("exit",("antal: %d not_pos: %d",ret->wilds,ret->not_pos));
+ DBUG_RETURN(ret);
+} /* wf_comp */
+
+
+ /* Test if a given filename is matched */
+
+int wf_test(register WF_PACK *wf_pack, register const char *name)
+{
+ reg2 uint i;
+ reg3 uint not_pos;
+ DBUG_ENTER("wf_test");
+
+ if (! wf_pack || wf_pack->wilds == 0)
+ DBUG_RETURN(0); /* Everything goes */
+
+ not_pos=wf_pack->not_pos;
+ for (i=0 ; i < not_pos; i++)
+ if (wild_compare(name,wf_pack->wild[i]) == 0)
+ goto found;
+ if (i)
+ DBUG_RETURN(1); /* No-match */
+
+found:
+/* Test that it isn't in not-list */
+
+ for (i=not_pos ; i < wf_pack->wilds; i++)
+ if (wild_compare(name,wf_pack->wild[i]) == 0)
+ DBUG_RETURN(1);
+ DBUG_RETURN(0);
+} /* wf_test */
+
+
+ /* We need this because program don't know with malloc we used */
+
+void wf_end(WF_PACK *buffer)
+{
+ DBUG_ENTER("wf_end");
+ if (buffer)
+ my_free((gptr) buffer,MYF(0));
+ DBUG_VOID_RETURN;
+} /* wf_end */
diff --git a/mysys/mulalloc.c b/mysys/mulalloc.c
new file mode 100644
index 00000000000..8a7ee312aa9
--- /dev/null
+++ b/mysys/mulalloc.c
@@ -0,0 +1,53 @@
+/* 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 */
+
+ /* Malloc many pointers at the same time */
+ /* format myFlags,ptr,length,ptr,length ... until null ptr */
+
+#include "mysys_priv.h"
+#include <stdarg.h>
+
+gptr my_multi_malloc(myf myFlags, ...)
+{
+ va_list args;
+ char **ptr,*start,*res;
+ uint tot_length,length;
+ DBUG_ENTER("my_multi_malloc");
+
+ va_start(args,myFlags);
+ tot_length=0;
+ while ((ptr=va_arg(args, char **)))
+ {
+ length=va_arg(args,uint);
+ tot_length+=ALIGN_SIZE(length);
+ }
+ va_end(args);
+
+ if (!(start=(char *) my_malloc(tot_length,myFlags)))
+ DBUG_RETURN(0); /* purecov: inspected */
+
+ va_start(args,myFlags);
+ res=start;
+ while ((ptr=va_arg(args, char **)))
+ {
+ *ptr=res;
+ length=va_arg(args,uint);
+ res+=ALIGN_SIZE(length);
+ }
+ va_end(args);
+ DBUG_RETURN((gptr) start);
+}
diff --git a/mysys/my_alarm.c b/mysys/my_alarm.c
new file mode 100644
index 00000000000..aab01ad77f4
--- /dev/null
+++ b/mysys/my_alarm.c
@@ -0,0 +1,34 @@
+/* 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 */
+
+/* Function to set a varible when we got a alarm */
+/* Used by my_lock samt functions in m_alarm.h */
+
+
+#include "mysys_priv.h"
+#include "my_alarm.h"
+
+#ifdef HAVE_ALARM
+
+ /* ARGSUSED */
+sig_handler my_set_alarm_variable(int signo __attribute__((unused)))
+{
+ my_have_got_alarm=1; /* Tell program that time expired */
+ return;
+}
+
+#endif /* HAVE_ALARM */
diff --git a/mysys/my_alloc.c b/mysys/my_alloc.c
new file mode 100644
index 00000000000..693ffbfab78
--- /dev/null
+++ b/mysys/my_alloc.c
@@ -0,0 +1,129 @@
+/* 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 */
+
+/* Routines to handle mallocing of results which will be freed the same time */
+
+#include <global.h>
+#include <my_sys.h>
+#include <m_string.h>
+
+void init_alloc_root(MEM_ROOT *mem_root,uint block_size)
+{
+ mem_root->free=mem_root->used=0;
+ mem_root->min_malloc=16;
+ mem_root->block_size=block_size-MALLOC_OVERHEAD-sizeof(USED_MEM)-8;
+ mem_root->error_handler=0;
+}
+
+gptr alloc_root(MEM_ROOT *mem_root,unsigned int Size)
+{
+#if defined(HAVE_purify) && defined(EXTRA_DEBUG)
+ reg1 USED_MEM *next;
+ Size+=ALIGN_SIZE(sizeof(USED_MEM));
+
+ if (!(next = (USED_MEM*) my_malloc(Size,MYF(MY_WME))))
+ {
+ if (mem_root->error_handler)
+ (*mem_root->error_handler)();
+ return((gptr) 0); /* purecov: inspected */
+ }
+ next->next=mem_root->used;
+ mem_root->used=next;
+ return (gptr) (((char*) next)+ALIGN_SIZE(sizeof(USED_MEM)));
+#else
+ uint get_size,max_left;
+ gptr point;
+ reg1 USED_MEM *next;
+ reg2 USED_MEM **prev;
+
+ Size= ALIGN_SIZE(Size);
+ prev= &mem_root->free;
+ max_left=0;
+ for (next= *prev ; next && next->left < Size ; next= next->next)
+ {
+ if (next->left > max_left)
+ max_left=next->left;
+ prev= &next->next;
+ }
+ if (! next)
+ { /* Time to alloc new block */
+ get_size= Size+ALIGN_SIZE(sizeof(USED_MEM));
+ if (max_left*4 < mem_root->block_size && get_size < mem_root->block_size)
+ get_size=mem_root->block_size; /* Normal alloc */
+
+ if (!(next = (USED_MEM*) my_malloc(get_size,MYF(MY_WME))))
+ {
+ if (mem_root->error_handler)
+ (*mem_root->error_handler)();
+ return((gptr) 0); /* purecov: inspected */
+ }
+ next->next= *prev;
+ next->size= get_size;
+ next->left= get_size-ALIGN_SIZE(sizeof(USED_MEM));
+ *prev=next;
+ }
+ point= (gptr) ((char*) next+ (next->size-next->left));
+ if ((next->left-= Size) < mem_root->min_malloc)
+ { /* Full block */
+ *prev=next->next; /* Remove block from list */
+ next->next=mem_root->used;
+ mem_root->used=next;
+ }
+ return(point);
+#endif
+}
+
+ /* deallocate everything used by alloc_root */
+
+void free_root(MEM_ROOT *root)
+{
+ reg1 USED_MEM *next,*old;
+ DBUG_ENTER("free_root");
+
+ if (!root)
+ DBUG_VOID_RETURN; /* purecov: inspected */
+ for (next= root->used ; next ; )
+ {
+ old=next; next= next->next ;
+ my_free((gptr) old,MYF(0));
+ }
+ for (next= root->free ; next ; )
+ {
+ old=next; next= next->next ;
+ my_free((gptr) old,MYF(0));
+ }
+ root->used=root->free=0;
+ DBUG_VOID_RETURN;
+}
+
+char *strdup_root(MEM_ROOT *root,const char *str)
+{
+ uint len=strlen(str)+1;
+ char *pos;
+ if ((pos=alloc_root(root,len)))
+ memcpy(pos,str,len);
+ return pos;
+}
+
+
+char *memdup_root(MEM_ROOT *root,const char *str,uint len)
+{
+ char *pos;
+ if ((pos=alloc_root(root,len)))
+ memcpy(pos,str,len);
+ return pos;
+}
diff --git a/mysys/my_append.c b/mysys/my_append.c
new file mode 100644
index 00000000000..0d3296fb278
--- /dev/null
+++ b/mysys/my_append.c
@@ -0,0 +1,66 @@
+/* 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 */
+
+#define USES_TYPES /* sys/types is included */
+#include "mysys_priv.h"
+#include <sys/stat.h>
+#include <m_string.h>
+#if defined(HAVE_SYS_UTIME_H)
+#include <sys/utime.h>
+#elif defined(HAVE_UTIME_H)
+#include <utime.h>
+#elif !defined(HPUX)
+struct utimbuf {
+ time_t actime;
+ time_t modtime;
+};
+#endif
+
+ /* Append a file to another */
+
+int my_append(const char *from, const char *to, myf MyFlags)
+
+
+ /* Dont set MY_FNABP or MY_NABP bits on
+ when calling this funktion */
+{
+ uint Count;
+ File from_file,to_file;
+ char buff[IO_SIZE];
+ DBUG_ENTER("my_append");
+ DBUG_PRINT("my",("from %s to %s MyFlags %d", from, to, MyFlags));
+
+ from_file=to_file= -1;
+
+ if ((from_file=my_open(from,O_RDONLY,MyFlags)) >= 0)
+ {
+ if ((to_file=my_open(to,O_APPEND | O_WRONLY,MyFlags)) >= 0)
+ {
+ while ((Count=my_read(from_file,buff,IO_SIZE,MyFlags)) != 0)
+ if (Count == (uint) -1 ||
+ my_write(to_file,buff,Count,MYF(MyFlags | MY_NABP)))
+ goto err;
+ if (my_close(from_file,MyFlags) | my_close(to_file,MyFlags))
+ DBUG_RETURN(-1); /* Error on close */
+ DBUG_RETURN(0);
+ }
+ }
+err:
+ if (from_file >= 0) VOID(my_close(from_file,MyFlags));
+ if (to_file >= 0) VOID(my_close(to_file,MyFlags));
+ DBUG_RETURN(-1);
+}
diff --git a/mysys/my_chsize.c b/mysys/my_chsize.c
new file mode 100644
index 00000000000..1063e9381bf
--- /dev/null
+++ b/mysys/my_chsize.c
@@ -0,0 +1,86 @@
+/* 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 "mysys_err.h"
+#include "m_string.h"
+
+ /* Change size of file. Truncate file if shorter, */
+ /* else expand with zero. */
+
+int my_chsize(File fd, my_off_t newlength, myf MyFlags)
+{
+ DBUG_ENTER("my_chsize");
+ DBUG_PRINT("my",("fd: %d length: %lu MyFlags: %d",fd,(ulong) newlength,
+ MyFlags));
+
+#ifdef HAVE_CHSIZE
+ if (chsize(fd,(off_t) newlength))
+ {
+ DBUG_PRINT("error",("errno: %d",errno));
+ my_errno=errno;
+ if (MyFlags & MY_WME)
+ my_error(EE_CANT_CHSIZE,MYF(ME_BELL+ME_WAITTANG),errno);
+ DBUG_RETURN(1);
+ }
+ DBUG_RETURN(0);
+#else
+ /* if file is shorter, expand with null, else fill unused part with null */
+ {
+ my_off_t oldsize;
+ char buff[IO_SIZE];
+
+ bzero(buff,IO_SIZE);
+ oldsize = my_seek(fd, 0L, MY_SEEK_END, MYF(MY_WME+MY_FAE));
+
+#ifdef HAVE_FTRUNCATE
+ if (oldsize > newlength)
+ {
+ if (ftruncate(fd, (off_t) newlength))
+ {
+ my_errno=errno;
+ DBUG_PRINT("error",("errno: %d",errno));
+ if (MyFlags & MY_WME)
+ my_error(EE_CANT_CHSIZE, MYF(ME_BELL+ME_WAITTANG), errno);
+ DBUG_RETURN(1);
+ }
+ DBUG_RETURN(0);
+ }
+#else
+ if (oldsize > newlength)
+ { /* Fill diff with null */
+ VOID(my_seek(fd, newlength, MY_SEEK_SET, MYF(MY_WME+MY_FAE)));
+ swap(long, newlength, oldsize);
+ }
+#endif
+ while (newlength-oldsize > IO_SIZE)
+ {
+ if (my_write(fd,(byte*) buff,IO_SIZE,MYF(MY_NABP)))
+ goto err;
+ oldsize+= IO_SIZE;
+ }
+ if (my_write(fd,(byte*) buff,(uint) (newlength-oldsize),MYF(MY_NABP)))
+ goto err;
+ DBUG_RETURN(0);
+ err:
+ if (MyFlags & MY_WME)
+ my_error(EE_CANT_CHSIZE,MYF(ME_BELL+ME_WAITTANG),my_errno);
+ DBUG_PRINT("error",("errno: %d",my_errno));
+ DBUG_RETURN(1);
+ }
+#endif
+} /* my_chsize */
diff --git a/mysys/my_clock.c b/mysys/my_clock.c
new file mode 100644
index 00000000000..d13d69a7b88
--- /dev/null
+++ b/mysys/my_clock.c
@@ -0,0 +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,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should 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 */
+
+#define USES_TYPES
+#include "global.h"
+
+#if !defined(_MSC_VER) && !defined(__BORLANDC__)
+#include "mysys_priv.h"
+#include <sys/times.h>
+#endif
+
+long my_clock(void)
+{
+#if !defined(MSDOS) && !defined(__WIN__)
+ struct tms tmsbuf;
+ VOID(times(&tmsbuf));
+ return (tmsbuf.tms_utime + tmsbuf.tms_stime);
+#else
+ return clock();
+#endif
+}
diff --git a/mysys/my_compress.c b/mysys/my_compress.c
new file mode 100644
index 00000000000..d1e32234135
--- /dev/null
+++ b/mysys/my_compress.c
@@ -0,0 +1,87 @@
+/* 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 */
+
+/* Written by Sinisa Milivojevic <sinisa@coresinc.com> */
+
+#include <global.h>
+#ifdef HAVE_COMPRESS
+#include <my_sys.h>
+#include <zlib.h>
+
+/*
+** This replaces the packet with a compressed packet
+** Returns 1 on error
+** *complen is 0 if the packet wasn't compressed
+*/
+
+my_bool my_compress(byte *packet, ulong *len, ulong *complen)
+{
+ if (*len < MIN_COMPRESS_LENGTH)
+ *complen=0;
+ else
+ {
+ byte *compbuf=my_compress_alloc(packet,len,complen);
+ if (!compbuf)
+ return *complen ? 0 : 1;
+ memcpy(packet,compbuf,*len);
+ my_free(compbuf,MYF(MY_WME)); }
+ return 0;
+}
+
+
+byte *my_compress_alloc(const byte *packet, ulong *len, ulong *complen)
+{
+ byte *compbuf;
+ *complen = *len * 120 / 100 + 12;
+ if (!(compbuf = (byte *) my_malloc(*complen,MYF(MY_WME))))
+ return 0; /* Not enough memory */
+ if (compress((Bytef*) compbuf,(ulong *) complen, (Bytef*) packet,
+ (uLong) *len ) != Z_OK)
+ {
+ my_free(compbuf,MYF(MY_WME));
+ return 0;
+ }
+ if (*complen >= *len)
+ {
+ *complen=0;
+ my_free(compbuf,MYF(MY_WME));
+ return 0;
+ }
+ swap(ulong,*len,*complen); /* *len is now packet length */
+ return compbuf;
+}
+
+
+my_bool my_uncompress (byte *packet, ulong *len, ulong *complen)
+{
+ if (*complen) /* If compressed */
+ {
+ byte *compbuf = (byte *) my_malloc (*complen,MYF(MY_WME));
+ if (!compbuf)
+ return 1; /* Not enough memory */
+ if (uncompress((Bytef*) compbuf, complen, (Bytef*) packet, *len) != Z_OK)
+ { /* Probably wrong packet */
+ my_free (compbuf,MYF(MY_WME));
+ return 1;
+ }
+ *len = *complen;
+ memcpy(packet,compbuf,*len);
+ my_free(compbuf,MYF(MY_WME));
+ }
+ return 0;
+}
+#endif /* HAVE_COMPRESS */
diff --git a/mysys/my_copy.c b/mysys/my_copy.c
new file mode 100644
index 00000000000..bfd7e957585
--- /dev/null
+++ b/mysys/my_copy.c
@@ -0,0 +1,103 @@
+/* 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 */
+
+#define USES_TYPES /* sys/types is included */
+#include "mysys_priv.h"
+#include <sys/stat.h>
+#include <m_string.h>
+#if defined(HAVE_SYS_UTIME_H)
+#include <sys/utime.h>
+#elif defined(HAVE_UTIME_H)
+#include <utime.h>
+#elif !defined(HPUX)
+#include <time.h>
+struct utimbuf {
+ time_t actime;
+ time_t modtime;
+};
+#endif
+
+
+ /*
+ Ordinary ownership and accesstimes are copied from 'from-file'
+ if MyFlags & MY_HOLD_ORIGINAL_MODES is set and to-file exists then
+ the modes of to-file isn't changed
+ Dont set MY_FNABP or MY_NABP bits on when calling this function !
+ */
+
+int my_copy(const char *from, const char *to, myf MyFlags)
+{
+ uint Count;
+ int new_file_stat;
+ File from_file,to_file;
+ char buff[IO_SIZE];
+ struct stat stat_buff,new_stat_buff;
+ DBUG_ENTER("my_copy");
+ DBUG_PRINT("my",("from %s to %s MyFlags %d", from, to, MyFlags));
+
+ from_file=to_file= -1;
+ new_file_stat=0;
+ if (MyFlags & MY_HOLD_ORIGINAL_MODES) /* Copy stat if possible */
+ new_file_stat=stat((char*) to, &new_stat_buff);
+
+ if ((from_file=my_open(from,O_RDONLY,MyFlags)) >= 0)
+ {
+ if (stat(from,&stat_buff))
+ {
+ my_errno=errno;
+ goto err;
+ }
+ if (MyFlags & MY_HOLD_ORIGINAL_MODES && !new_file_stat)
+ stat_buff=new_stat_buff;
+ if ((to_file= my_create(to,(int) stat_buff.st_mode,
+ O_WRONLY | O_TRUNC | O_BINARY,
+ MyFlags)) < 0)
+ goto err;
+
+ while ((Count=my_read(from_file,buff,IO_SIZE,MyFlags)) != 0)
+ if (Count == (uint) -1 ||
+ my_write(to_file,buff,Count,MYF(MyFlags | MY_NABP)))
+ goto err;
+
+ if (my_close(from_file,MyFlags) | my_close(to_file,MyFlags))
+ DBUG_RETURN(-1); /* Error on close */
+
+ /* Copy modes if possible */
+
+ if (MyFlags & MY_HOLD_ORIGINAL_MODES && new_file_stat)
+ DBUG_RETURN(0); /* File copyed but not stat */
+ VOID(chmod(to, stat_buff.st_mode & 07777)); /* Copy modes */
+#if !defined(MSDOS) && !defined(__WIN__) && !defined(__EMX__)
+ VOID(chown(to, stat_buff.st_uid,stat_buff.st_gid)); /* Copy ownership */
+#endif
+#if !defined(VMS) && !defined(__ZTC__)
+ if (MyFlags & MY_COPYTIME)
+ {
+ struct utimbuf timep;
+ timep.actime = stat_buff.st_atime;
+ timep.modtime = stat_buff.st_mtime;
+ VOID(utime((char*) to, &timep)); /* last accessed and modified times */
+ }
+#endif
+ DBUG_RETURN(0);
+ }
+
+err:
+ if (from_file >= 0) VOID(my_close(from_file,MyFlags));
+ if (to_file >= 0) VOID(my_close(to_file,MyFlags));
+ DBUG_RETURN(-1);
+} /* my_copy */
diff --git a/mysys/my_create.c b/mysys/my_create.c
new file mode 100644
index 00000000000..866c0dfd465
--- /dev/null
+++ b/mysys/my_create.c
@@ -0,0 +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,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should 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 */
+
+#define USES_TYPES
+#include "mysys_priv.h"
+#include <my_dir.h>
+#include "mysys_err.h"
+#include <errno.h>
+#if defined(MSDOS) || defined(__WIN__)
+#include <share.h>
+#endif
+
+ /*
+ ** Create a new file
+ ** Arguments:
+ ** Path-name of file
+ ** Read | write on file (umask value)
+ ** Read & Write on open file
+ ** Special flags
+ */
+
+
+File my_create(const char *FileName, int CreateFlags, int access_flags,
+ myf MyFlags)
+{
+ int fd;
+ DBUG_ENTER("my_create");
+ DBUG_PRINT("my",("Name: '%s' CreateFlags: %d AccessFlags: %d MyFlags: %d",
+ FileName, CreateFlags, access_flags, MyFlags));
+
+#if !defined(NO_OPEN_3)
+ fd = open((my_string) FileName, access_flags | O_CREAT,
+ CreateFlags ? CreateFlags : my_umask);
+#elif defined(VMS)
+ fd = open((my_string) FileName, access_flags | O_CREAT, 0,
+ "ctx=stm","ctx=bin");
+#elif defined(MSDOS) || defined(__WIN__)
+ if (access_flags & O_SHARE)
+ fd = sopen((my_string) FileName, access_flags | O_CREAT | O_BINARY,
+ SH_DENYNO, MY_S_IREAD | MY_S_IWRITE);
+ else
+ fd = open((my_string) FileName, access_flags | O_CREAT | O_BINARY,
+ MY_S_IREAD | MY_S_IWRITE);
+#else
+ fd = open(FileName, access_flags);
+#endif
+
+ if (fd >= 0)
+ {
+ if ((int) fd >= MY_NFILE)
+ {
+ DBUG_PRINT("exit",("fd: %d",fd));
+ DBUG_RETURN(fd); /* safeguard */
+ }
+ if ((my_file_info[fd].name = (char*) my_strdup(FileName,MyFlags)))
+ {
+ my_file_opened++;
+ my_file_info[fd].type = FILE_BY_CREATE;
+ DBUG_PRINT("exit",("fd: %d",fd));
+ DBUG_RETURN(fd);
+ }
+ VOID(my_close(fd,MyFlags));
+ my_errno=ENOMEM;
+ }
+ else
+ my_errno=errno;
+ if (MyFlags & (MY_FFNF | MY_FAE | MY_WME))
+ my_error(EE_CANTCREATEFILE, MYF(ME_BELL+ME_WAITTANG), FileName,my_errno);
+ DBUG_RETURN(-1);
+} /* my_create */
diff --git a/mysys/my_delete.c b/mysys/my_delete.c
new file mode 100644
index 00000000000..77d5f311418
--- /dev/null
+++ b/mysys/my_delete.c
@@ -0,0 +1,36 @@
+/* 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 "mysys_err.h"
+
+int my_delete(const char *name, myf MyFlags)
+{
+ int err;
+ DBUG_ENTER("my_delete");
+ DBUG_PRINT("my",("name %s MyFlags %d", name, MyFlags));
+
+ if ((err = unlink(name)) == -1)
+ {
+ my_errno=errno;
+ if (MyFlags & (MY_FAE+MY_WME))
+ my_error(EE_DELETE,MYF(ME_BELL+ME_WAITTANG+(MyFlags & ME_NOINPUT)),
+ name,errno);
+ }
+ DBUG_RETURN(err);
+} /* my_delete */
diff --git a/mysys/my_div.c b/mysys/my_div.c
new file mode 100644
index 00000000000..24794679376
--- /dev/null
+++ b/mysys/my_div.c
@@ -0,0 +1,31 @@
+/* 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"
+
+my_string my_filename(File fd)
+{
+ DBUG_ENTER("my_filename");
+ if (fd >= MY_NFILE)
+ DBUG_RETURN((char*) "UNKNOWN");
+ if (fd >= 0 && my_file_info[fd].type != UNOPEN)
+ {
+ DBUG_RETURN(my_file_info[fd].name);
+ }
+ else
+ DBUG_RETURN((char*) "UNOPENED"); /* Debug message */
+}
diff --git a/mysys/my_error.c b/mysys/my_error.c
new file mode 100644
index 00000000000..26510f08480
--- /dev/null
+++ b/mysys/my_error.c
@@ -0,0 +1,122 @@
+/* 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 "mysys_err.h"
+#include <m_string.h>
+#include <stdarg.h>
+#include <m_ctype.h>
+
+/* Define some external variables for error handling */
+
+const char ** NEAR errmsg[MAXMAPS]={0,0,0,0};
+char NEAR errbuff[NRERRBUFFS][ERRMSGSIZE];
+
+/* Error message to user */
+/*VARARGS2*/
+
+int my_error(int nr,myf MyFlags, ...)
+{
+ va_list ap;
+ uint olen, plen;
+ reg1 const char *tpos;
+ reg2 char *endpos;
+ char * par;
+ char ebuff[ERRMSGSIZE+20];
+ DBUG_ENTER("my_error");
+
+ va_start(ap,MyFlags);
+ DBUG_PRINT("my", ("nr: %d MyFlags: %d errno: %d", nr, MyFlags, errno));
+
+ if (nr / ERRMOD == GLOB && errmsg[GLOB] == 0)
+ init_glob_errs();
+
+ olen=(uint) strlen(tpos=errmsg[nr / ERRMOD][nr % ERRMOD]);
+ endpos=ebuff;
+
+ while (*tpos)
+ {
+ if (tpos[0] != '%')
+ {
+ *endpos++= *tpos++; /* Copy ordinary char */
+ olen++;
+ continue;
+ }
+ if (*++tpos == '%') /* test if %% */
+ {
+ olen--;
+ }
+ else
+ {
+ /* Skipp if max size is used (to be compatible with printf) */
+ while (isdigit(*tpos) || *tpos == '.' || *tpos == '-')
+ tpos++;
+ if (*tpos == 's') /* String parameter */
+ {
+ par = va_arg(ap, char *);
+ plen = (uint) strlen(par);
+ if (olen + plen < ERRMSGSIZE+2) /* Replace if possible */
+ {
+ endpos=strmov(endpos,par);
+ tpos++;
+ olen+=plen-2;
+ continue;
+ }
+ }
+ else if (*tpos == 'd' || *tpos == 'u') /* Integer parameter */
+ {
+ register int iarg;
+ iarg = va_arg(ap, int);
+ if (*tpos == 'd')
+ plen= (uint) (int2str((long) iarg,endpos, -10) - endpos);
+ else
+ plen= (uint) (int2str((long) (uint) iarg,endpos,10)- endpos);
+ if (olen + plen < ERRMSGSIZE+2) /* Replace parameter if possible */
+ {
+ endpos+=plen;
+ tpos++;
+ olen+=plen-2;
+ continue;
+ }
+ }
+ }
+ *endpos++='%'; /* % used as % or unknown code */
+ }
+ *endpos='\0'; /* End of errmessage */
+ va_end(ap);
+ DBUG_RETURN((*error_handler_hook)(nr, ebuff, MyFlags));
+}
+
+ /* Error as printf */
+
+int my_printf_error (uint error, const char *format, myf MyFlags, ...)
+{
+ va_list args;
+ char ebuff[ERRMSGSIZE+20];
+
+ va_start(args,MyFlags);
+ (void) vsprintf (ebuff,format,args);
+ va_end(args);
+ return (*error_handler_hook)(error, ebuff, MyFlags);
+}
+
+ /* Give message using error_handler_hook */
+
+int my_message(uint error, const char *str, register myf MyFlags)
+{
+ return (*error_handler_hook)(error, str, MyFlags);
+}
diff --git a/mysys/my_fopen.c b/mysys/my_fopen.c
new file mode 100644
index 00000000000..b2e99518792
--- /dev/null
+++ b/mysys/my_fopen.c
@@ -0,0 +1,165 @@
+/* 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 "my_static.h"
+#include <errno.h>
+#include "mysys_err.h"
+
+static void make_ftype(my_string to,int flag);
+
+ /* Open a file as stream */
+
+FILE *my_fopen(const char *FileName, int Flags, myf MyFlags)
+ /* Path-name of file */
+ /* Read | write .. */
+ /* Special flags */
+{
+ FILE *fd;
+ char type[5];
+ DBUG_ENTER("my_fopen");
+ DBUG_PRINT("my",("Name: '%s' Flags: %d MyFlags: %d",
+ FileName, Flags, MyFlags));
+
+ make_ftype(type,Flags);
+ if ((fd = fopen(FileName, type)) != 0)
+ {
+ /*
+ The test works if MY_NFILE < 128. The problem is that fileno() is char
+ on some OS (SUNOS). Actually the filename save isn't that important
+ so we can ignore if this doesn't work.
+ */
+ if ((uint) fileno(fd) >= MY_NFILE)
+ DBUG_RETURN(fd); /* safeguard */
+ pthread_mutex_lock(&THR_LOCK_open);
+ if ((my_file_info[fileno(fd)].name = (char*)
+ my_strdup(FileName,MyFlags)))
+ {
+ my_stream_opened++;
+ my_file_info[fileno(fd)].type = STREAM_BY_FOPEN;
+ pthread_mutex_unlock(&THR_LOCK_open);
+ DBUG_PRINT("exit",("stream: %lx",fd));
+ DBUG_RETURN(fd);
+ }
+ pthread_mutex_unlock(&THR_LOCK_open);
+ (void) my_fclose(fd,MyFlags);
+ my_errno=ENOMEM;
+ }
+ else
+ my_errno=errno;
+ DBUG_PRINT("error",("Got error %d on open",my_errno));
+ if (MyFlags & (MY_FFNF | MY_FAE | MY_WME))
+ my_error((Flags & O_RDONLY) || (Flags == O_RDONLY ) ? EE_FILENOTFOUND :
+ EE_CANTCREATEFILE,
+ MYF(ME_BELL+ME_WAITTANG), FileName,my_errno);
+ DBUG_RETURN((FILE*) 0);
+} /* my_fopen */
+
+
+ /* Close a stream */
+
+int my_fclose(FILE *fd, myf MyFlags)
+{
+ int err,file;
+ DBUG_ENTER("my_fclose");
+ DBUG_PRINT("my",("stream: %lx MyFlags: %d",fd, MyFlags));
+
+ pthread_mutex_lock(&THR_LOCK_open);
+ file=fileno(fd);
+ if ((err = fclose(fd)) < 0)
+ {
+ my_errno=errno;
+ if (MyFlags & (MY_FAE | MY_WME))
+ my_error(EE_BADCLOSE, MYF(ME_BELL+ME_WAITTANG),
+ my_filename(file),errno);
+ }
+ if ((uint) file < MY_NFILE && my_file_info[file].type != UNOPEN)
+ {
+ my_file_info[file].type = UNOPEN;
+ my_free(my_file_info[file].name, MYF(0));
+ my_stream_opened--;
+ }
+ pthread_mutex_unlock(&THR_LOCK_open);
+ DBUG_RETURN(err);
+} /* my_fclose */
+
+
+ /* Make a stream out of a file handle */
+
+FILE *my_fdopen(File Filedes, int Flags, myf MyFlags)
+
+ /* Read | write .. */
+ /* Special flags */
+{
+ FILE *fd;
+ char type[5];
+ DBUG_ENTER("my_fdopen");
+ DBUG_PRINT("my",("Fd: %d Flags: %d MyFlags: %d",
+ Filedes, Flags, MyFlags));
+
+ make_ftype(type,Flags);
+ if ((fd = fdopen(Filedes, type)) == 0)
+ {
+ my_errno=errno;
+ if (MyFlags & (MY_FAE | MY_WME))
+ my_error(EE_CANT_OPEN_STREAM, MYF(ME_BELL+ME_WAITTANG),errno);
+ }
+ else
+ {
+ pthread_mutex_lock(&THR_LOCK_open);
+ if (my_file_info[Filedes].type != UNOPEN)
+ {
+ my_file_info[Filedes].type = STREAM_BY_FDOPEN;
+ my_file_opened--; /* File is opened with my_open ! */
+ my_stream_opened++;
+ }
+ pthread_mutex_unlock(&THR_LOCK_open);
+ }
+
+ DBUG_PRINT("exit",("stream: %lx",fd));
+ DBUG_RETURN(fd);
+} /* my_fdopen */
+
+
+ /* Make a filehandler-open-typestring from ordinary inputflags */
+
+static void make_ftype(register my_string to, register int flag)
+{
+#if FILE_BINARY /* If we have binary-files */
+ reg3 int org_flag=flag;
+#endif
+ flag&= ~FILE_BINARY; /* remove binary bit */
+ if (flag == O_RDONLY)
+ *to++= 'r';
+ else if (flag == O_WRONLY)
+ *to++= 'w';
+ else
+ { /* Add '+' after theese */
+ if (flag == O_RDWR)
+ *to++= 'r';
+ else if (flag & O_APPEND)
+ *to++= 'a';
+ else
+ *to++= 'w'; /* Create file */
+ *to++= '+';
+ }
+#if FILE_BINARY /* If we have binary-files */
+ if (org_flag & FILE_BINARY)
+ *to++='b';
+#endif
+ *to='\0';
+} /* make_ftype */
diff --git a/mysys/my_fstream.c b/mysys/my_fstream.c
new file mode 100644
index 00000000000..76bd12abe32
--- /dev/null
+++ b/mysys/my_fstream.c
@@ -0,0 +1,170 @@
+/* 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 */
+
+/* USE_MY_STREAM isn't set because we can't thrust my_fclose! */
+
+#include "mysys_priv.h"
+#include "mysys_err.h"
+#include <errno.h>
+
+#ifdef HAVE_FSEEKO
+#undef ftell
+#undef fseek
+#define ftell(A) ftello(A)
+#define fseek(A,B,C) fseeko((A),(B),(C))
+#endif
+
+ /* Read a chunk of bytes from a file */
+ /* Returns (uint) -1 if error as my_read() */
+
+uint my_fread(FILE *stream, byte *Buffer, uint Count, myf MyFlags)
+ /* File descriptor */
+ /* Buffer must be at least count bytes */
+ /* Max number of bytes returnd */
+ /* Flags on what to do on error */
+{
+ uint readbytes;
+ DBUG_ENTER("my_fread");
+ DBUG_PRINT("my",("stream: %lx Buffer: %lx Count: %u MyFlags: %d",
+ stream, Buffer, Count, MyFlags));
+
+ if ((readbytes = (uint) fread(Buffer,sizeof(char),(size_t) Count,stream))
+ != Count)
+ {
+ DBUG_PRINT("error",("Read only %d bytes",readbytes));
+ if (MyFlags & (MY_WME | MY_FAE | MY_FNABP))
+ {
+ if (ferror(stream))
+ my_error(EE_READ, MYF(ME_BELL+ME_WAITTANG),
+ my_filename(fileno(stream)),errno);
+ else
+ if (MyFlags & (MY_NABP | MY_FNABP))
+ my_error(EE_EOFERR, MYF(ME_BELL+ME_WAITTANG),
+ my_filename(fileno(stream)),errno);
+ }
+ my_errno=errno ? errno : -1;
+ if (ferror(stream) || MyFlags & (MY_NABP | MY_FNABP))
+ DBUG_RETURN((uint) -1); /* Return with error */
+ }
+ if (MyFlags & (MY_NABP | MY_FNABP))
+ DBUG_RETURN(0); /* Read ok */
+ DBUG_RETURN(readbytes);
+} /* my_fread */
+
+
+/*
+** Write a chunk of bytes to a stream
+** Returns (uint) -1 if error as my_write()
+** Does retries if interrupted
+*/
+
+uint my_fwrite(FILE *stream, const byte *Buffer, uint Count, myf MyFlags)
+{
+ uint writenbytes=0;
+ off_t seekptr;
+#if !defined(NO_BACKGROUND) && defined(USE_MY_STREAM)
+ uint errors;
+#endif
+ DBUG_ENTER("my_fwrite");
+ DBUG_PRINT("my",("stream: %lx Buffer: %lx Count: %u MyFlags: %d",
+ stream, Buffer, Count, MyFlags));
+
+#if !defined(NO_BACKGROUND) && defined(USE_MY_STREAM)
+ errors=0;
+#endif
+ seekptr=ftell(stream);
+ for (;;)
+ {
+ uint writen;
+ if ((writen = (uint) fwrite((char*) Buffer,sizeof(char),
+ (size_t) Count, stream)) != Count)
+ {
+ DBUG_PRINT("error",("Write only %d bytes",writenbytes));
+ my_errno=errno;
+ if (writen != (uint) -1)
+ {
+ seekptr+=writen;
+ Buffer+=writen;
+ writenbytes+=writen;
+ Count-=writen;
+ }
+#ifdef EINTR
+ if (errno == EINTR)
+ {
+ VOID(my_fseek(stream,seekptr,MY_SEEK_SET,MYF(0)));
+ continue;
+ }
+#endif
+#if !defined(NO_BACKGROUND) && defined(USE_MY_STREAM)
+#ifdef THREAD
+ if (my_thread_var->abort)
+ MyFlags&= ~ MY_WAIT_IF_FULL; /* End if aborted by user */
+#endif
+ if (errno == ENOSPC && (MyFlags & MY_WAIT_IF_FULL))
+ {
+ if (!(errors++ % MY_WAIT_GIVE_USER_A_MESSAGE))
+ my_error(EE_DISK_FULL,MYF(ME_BELL | ME_NOREFRESH));
+ sleep(MY_WAIT_FOR_USER_TO_FIX_PANIC);
+ VOID(my_fseek(stream,seekptr,MY_SEEK_SET,MYF(0)));
+ continue;
+ }
+#endif
+ if (ferror(stream) || (MyFlags & (MY_NABP | MY_FNABP)))
+ {
+ if (MyFlags & (MY_WME | MY_FAE | MY_FNABP))
+ {
+ my_error(EE_WRITE, MYF(ME_BELL+ME_WAITTANG),
+ my_filename(fileno(stream)),errno);
+ }
+ writenbytes=(uint) -1; /* Return that we got error */
+ break;
+ }
+ }
+ if (MyFlags & (MY_NABP | MY_FNABP))
+ writenbytes=0; /* Everything OK */
+ else
+ writenbytes+=writen;
+ break;
+ }
+ DBUG_RETURN(writenbytes);
+} /* my_fwrite */
+
+ /* Seek to position in file */
+ /* ARGSUSED */
+
+my_off_t my_fseek(FILE *stream, my_off_t pos, int whence, myf MyFlags)
+{
+ DBUG_ENTER("my_fseek");
+ DBUG_PRINT("my",("stream: %lx pos: %lu whence: %d MyFlags: %d",
+ stream, pos, whence, MyFlags));
+ DBUG_RETURN(fseek(stream, (off_t) pos, whence) ?
+ MY_FILEPOS_ERROR : (my_off_t) ftell(stream));
+} /* my_seek */
+
+
+ /* Tell current position of file */
+ /* ARGSUSED */
+
+my_off_t my_ftell(FILE *stream, myf MyFlags)
+{
+ off_t pos;
+ DBUG_ENTER("my_ftell");
+ DBUG_PRINT("my",("stream: %lx MyFlags: %d",stream, MyFlags));
+ pos=ftell(stream);
+ DBUG_PRINT("exit",("ftell: %lu",(ulong) pos));
+ DBUG_RETURN((my_off_t) pos);
+} /* my_ftell */
diff --git a/mysys/my_getwd.c b/mysys/my_getwd.c
new file mode 100644
index 00000000000..3d674276731
--- /dev/null
+++ b/mysys/my_getwd.c
@@ -0,0 +1,182 @@
+/* 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 */
+
+/* my_setwd() and my_getwd() works with intern_filenames !! */
+
+#include "mysys_priv.h"
+#include <m_string.h>
+#include "mysys_err.h"
+#ifdef HAVE_GETWD
+#include <sys/param.h>
+#endif
+#if defined(MSDOS) || defined(__WIN__)
+#include <m_ctype.h>
+#include <dos.h>
+#include <direct.h>
+#endif
+
+
+ /* Gets current working directory in buff. Directory is allways ended
+ with FN_LIBCHAR */
+ /* One must pass a buffer to my_getwd. One can allways use
+ curr_dir[] */
+
+int my_getwd(my_string buf, uint size, myf MyFlags)
+{
+ my_string pos;
+ DBUG_ENTER("my_getwd");
+ DBUG_PRINT("my",("buf: %lx size: %d MyFlags %d", buf,size,MyFlags));
+
+#if ! defined(MSDOS)
+ if (curr_dir[0]) /* Current pos is saved here */
+ VOID(strmake(buf,&curr_dir[0],size-1));
+ else
+#endif
+ {
+#if defined(HAVE_GETCWD)
+ if (!getcwd(buf,size-2) && MyFlags & MY_WME)
+ {
+ my_errno=errno;
+ my_error(EE_GETWD,MYF(ME_BELL+ME_WAITTANG),errno);
+ return(-1);
+ }
+#elif defined(HAVE_GETWD)
+ {
+ char pathname[MAXPATHLEN];
+ getwd(pathname);
+ strmake(buf,pathname,size-1);
+ }
+#elif defined(VMS)
+ if (!getcwd(buf,size-2,1) && MyFlags & MY_WME)
+ {
+ my_errno=errno;
+ my_error(EE_GETWD,MYF(ME_BELL+ME_WAITTANG),errno);
+ return(-1);
+ }
+ intern_filename(buf,buf);
+#else
+#error "No way to get current directory"
+#endif
+ if (*((pos=strend(buf))-1) != FN_LIBCHAR) /* End with FN_LIBCHAR */
+ {
+ pos[0]= FN_LIBCHAR;
+ pos[1]=0;
+ }
+ (void) strmake(&curr_dir[0],buf,(size_s) (FN_REFLEN-1));
+ }
+ DBUG_RETURN(0);
+} /* my_getwd */
+
+
+ /* Set new working directory */
+
+int my_setwd(const char *dir, myf MyFlags)
+{
+ int res;
+ size_s length;
+ my_string start,pos;
+#if defined(VMS) || defined(MSDOS)
+ char buff[FN_REFLEN];
+#endif
+ DBUG_ENTER("my_setwd");
+ DBUG_PRINT("my",("dir: '%s' MyFlags %d", dir, MyFlags));
+
+ start=(my_string) dir;
+#if defined(MSDOS) /* MSDOS chdir can't change drive */
+#if !defined(_DDL) && !defined(WIN32)
+ if ((pos=strchr(dir,FN_DEVCHAR)) != 0)
+ {
+ uint drive,drives;
+
+ pos++; /* Skipp FN_DEVCHAR */
+ drive=(uint) (toupper(dir[0])-'A'+1); drives= (uint) -1;
+ if ((pos-(byte*) dir) == 2 && drive > 0 && drive < 32)
+ {
+ _dos_setdrive(drive,&drives);
+ _dos_getdrive(&drives);
+ }
+ if (drive != drives)
+ {
+ *pos='\0'; /* Dir is now only drive */
+ my_errno=errno;
+ my_error(EE_SETWD,MYF(ME_BELL+ME_WAITTANG),dir,ENOENT);
+ DBUG_RETURN(-1);
+ }
+ dir=pos; /* drive changed, change now path */
+ }
+#endif
+ if (*((pos=strend(dir)-1)) == FN_LIBCHAR && pos != dir)
+ {
+ strmov(buff,dir)[-1]=0; /* Remove last '/' */
+ dir=buff;
+ }
+#endif /* MSDOS*/
+ if (! dir[0] || (dir[0] == FN_LIBCHAR && dir[1] == 0))
+ dir=FN_ROOTDIR;
+#ifdef VMS
+ {
+ pos=strmov(buff,dir);
+ if (pos[-1] != FN_LIBCHAR)
+ {
+ pos[0]=FN_LIBCHAR; /* Mark as directory */
+ pos[1]=0;
+ }
+ system_filename(buff,buff); /* Change to VMS format */
+ dir=buff;
+ }
+#endif /* VMS */
+ if ((res=chdir((char*) dir)) != 0)
+ {
+ my_errno=errno;
+ if (MyFlags & MY_WME)
+ my_error(EE_SETWD,MYF(ME_BELL+ME_WAITTANG),start,errno);
+ }
+ else
+ {
+ if (test_if_hard_path(start))
+ { /* Hard pathname */
+ pos=strmake(&curr_dir[0],start,(size_s) FN_REFLEN-1);
+ if (pos[-1] != FN_LIBCHAR)
+ {
+ length=(uint) (pos-(char*) curr_dir);
+ curr_dir[length]=FN_LIBCHAR; /* must end with '/' */
+ curr_dir[length+1]='\0';
+ }
+ }
+ else
+ curr_dir[0]='\0'; /* Don't save name */
+ }
+ DBUG_RETURN(res);
+} /* my_setwd */
+
+
+
+ /* Test if hard pathname */
+ /* Returns 1 if dirname is a hard path */
+
+int test_if_hard_path(register const char *dir_name)
+{
+ if (dir_name[0] == FN_HOMELIB && dir_name[1] == FN_LIBCHAR)
+ return (home_dir != NullS && test_if_hard_path(home_dir));
+ if (dir_name[0] == FN_LIBCHAR)
+ return (TRUE);
+#ifdef FN_DEVCHAR
+ return (strchr(dir_name,FN_DEVCHAR) != 0);
+#else
+ return FALSE;
+#endif
+} /* test_if_hard_path */
diff --git a/mysys/my_init.c b/mysys/my_init.c
new file mode 100644
index 00000000000..912e80d9ebd
--- /dev/null
+++ b/mysys/my_init.c
@@ -0,0 +1,301 @@
+/* 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 "my_static.h"
+#include "mysys_err.h"
+#include "m_ctype.h"
+#include <m_string.h>
+#include <m_ctype.h>
+#ifdef THREAD
+#include <my_pthread.h>
+#endif
+#ifdef HAVE_GETRUSAGE
+#include <sys/resource.h>
+/* extern int getrusage(int, struct rusage *); */
+#endif
+#include <signal.h>
+#ifdef VMS
+#include <my_static.c>
+#include <m_ctype.h>
+#endif
+#ifdef __WIN__
+#ifdef _MSC_VER
+#include <locale.h>
+#include <crtdbg.h>
+#endif
+my_bool have_tcpip=0;
+static void my_win_init(void);
+static my_bool win32_have_tcpip(void);
+static my_bool win32_init_tcp_ip();
+#else
+#define my_win_init()
+#endif
+static my_bool my_init_done=0;
+
+ /* Init my_sys functions and my_sys variabels */
+
+void my_init(void)
+{
+ my_string str;
+ if (my_init_done)
+ return;
+ my_init_done=1;
+#ifdef THREAD
+#if defined(HAVE_PTHREAD_INIT)
+ pthread_init(); /* Must be called before DBUG_ENTER */
+#endif
+ my_thread_global_init();
+#ifndef __WIN__
+ sigfillset(&my_signals); /* signals blocked by mf_brkhant */
+#endif
+#endif
+ {
+ DBUG_ENTER("my_init");
+ DBUG_PROCESS(my_progname ? my_progname : (char*) "unknown");
+ if (!home_dir)
+ { /* Don't initialize twice */
+ my_win_init();
+ if ((home_dir=getenv("HOME")) != 0)
+ home_dir=intern_filename(home_dir_buff,home_dir);
+#ifndef VMS
+ if ((str=getenv("UMASK")) != 0)
+ my_umask=atoi(str) | 0600; /* Default creation of new files */
+ if ((str=getenv("UMASK_DIR")) != 0)
+ my_umask_dir=atoi(str) | 0700; /* Default creation of new dir's */
+#endif
+#ifdef VMS
+ init_ctype(); /* Stupid linker don't link _ctype.c */
+#endif
+ DBUG_PRINT("exit",("home: '%s'",home_dir));
+ }
+#ifdef __WIN__
+ win32_init_tcp_ip();
+#endif
+ DBUG_VOID_RETURN;
+ }
+} /* my_init */
+
+
+ /* End my_sys */
+
+void my_end(int infoflag)
+{
+ FILE *info_file;
+ if (!(info_file=DBUG_FILE))
+ info_file=stderr;
+ if (infoflag & MY_CHECK_ERROR || info_file != stderr)
+ { /* Test if some file is left open */
+ if (my_file_opened | my_stream_opened)
+ {
+ sprintf(errbuff[0],EE(EE_OPEN_WARNING),my_file_opened,my_stream_opened);
+ (void) my_message_no_curses(EE_OPEN_WARNING,errbuff[0],ME_BELL);
+ DBUG_PRINT("error",("%s",errbuff[0]));
+ }
+ }
+ if (infoflag & MY_GIVE_INFO || info_file != stderr)
+ {
+#ifdef HAVE_GETRUSAGE
+ struct rusage rus;
+ if (!getrusage(RUSAGE_SELF, &rus))
+ fprintf(info_file,"\nUser time %.2f, System time %.2f\nMaximum resident set size %ld, Integral resident set size %ld\nNon physical pagefaults %ld, Physical pagefaults %ld, Swaps %ld\nBlocks in %ld out %ld, Messages in %ld out %ld, Signals %ld\nVouluntary context switches %ld, Invouluntary context switches %ld\n",
+ (rus.ru_utime.tv_sec * SCALE_SEC +
+ rus.ru_utime.tv_usec / SCALE_USEC) / 100.0,
+ (rus.ru_stime.tv_sec * SCALE_SEC +
+ rus.ru_stime.tv_usec / SCALE_USEC) / 100.0,
+ rus.ru_maxrss, rus.ru_idrss,
+ rus.ru_minflt, rus.ru_majflt,
+ rus.ru_nswap, rus.ru_inblock, rus.ru_oublock,
+ rus.ru_msgsnd, rus.ru_msgrcv, rus.ru_nsignals,
+ rus.ru_nvcsw, rus.ru_nivcsw);
+#endif
+#if defined(MSDOS) && !defined(__WIN__)
+ fprintf(info_file,"\nRun time: %.1f\n",(double) clock()/CLOCKS_PER_SEC);
+#endif
+ free_charsets();
+#if defined(SAFEMALLOC)
+ TERMINATE(stderr); /* Give statistic on screen */
+#elif defined(__WIN__) && defined(_MSC_VER)
+ _CrtSetReportMode( _CRT_WARN, _CRTDBG_MODE_FILE );
+ _CrtSetReportFile( _CRT_WARN, _CRTDBG_FILE_STDERR );
+ _CrtSetReportMode( _CRT_ERROR, _CRTDBG_MODE_FILE );
+ _CrtSetReportFile( _CRT_ERROR, _CRTDBG_FILE_STDERR );
+ _CrtSetReportMode( _CRT_ASSERT, _CRTDBG_MODE_FILE );
+ _CrtSetReportFile( _CRT_ASSERT, _CRTDBG_FILE_STDERR );
+ _CrtCheckMemory();
+ _CrtDumpMemoryLeaks();
+#endif
+ }
+#ifdef THREAD
+ pthread_mutex_destroy(&THR_LOCK_keycache);
+ pthread_mutex_destroy(&THR_LOCK_malloc);
+ pthread_mutex_destroy(&THR_LOCK_open);
+ DBUG_POP(); /* Must be done before my_thread_end */
+ my_thread_end();
+ my_thread_global_end();
+#endif
+#ifdef __WIN__
+ if (have_tcpip);
+ WSACleanup( );
+#endif /* __WIN__ */
+} /* my_end */
+
+#ifdef __WIN__
+
+/*
+ This code is specially for running MySQL, but it should work in
+ other cases too.
+
+ Inizializzazione delle variabili d'ambiente per Win a 32 bit.
+
+ Vengono inserite nelle variabili d'ambiente (utilizzando cosi'
+ le funzioni getenv e putenv) i valori presenti nelle chiavi
+ del file di registro:
+
+ HKEY_LOCAL_MACHINE\software\MySQL
+
+ Se la kiave non esiste nonn inserisce nessun valore
+*/
+
+/* Crea la stringa d'ambiente */
+
+void setEnvString(char *ret, const char *name, const char *value)
+{
+ DBUG_ENTER("setEnvString");
+ strxmov(ret, name,"=",value,NullS);
+ DBUG_VOID_RETURN ;
+}
+
+static void my_win_init(void)
+{
+ HKEY hSoftMysql ;
+ DWORD dimName = 256 ;
+ DWORD dimData = 1024 ;
+ DWORD dimNameValueBuffer = 256 ;
+ DWORD dimDataValueBuffer = 1024 ;
+ DWORD indexValue = 0 ;
+ long retCodeEnumValue ;
+ char NameValueBuffer[256] ;
+ char DataValueBuffer[1024] ;
+ char EnvString[1271] ;
+ const char *targetKey = "Software\\MySQL" ;
+ DBUG_ENTER("my_win_init");
+
+ setlocale(LC_CTYPE, ""); /* To get right sortorder */
+
+ /* apre la chiave HKEY_LOCAL_MACHINES\software\MySQL */
+ if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,(LPCTSTR)targetKey,0,
+ KEY_READ,&hSoftMysql) != ERROR_SUCCESS)
+ DBUG_VOID_RETURN;
+
+ /*
+ ** Ne legge i valori e li inserisce nell'ambiente
+ ** suppone che tutti i valori letti siano di tipo stringa + '\0'
+ ** Legge il valore con indice 0 e lo scarta
+ */
+ retCodeEnumValue = RegEnumValue(hSoftMysql, indexValue++,
+ (LPTSTR)NameValueBuffer, &dimNameValueBuffer,
+ NULL, NULL, (LPBYTE)DataValueBuffer,
+ &dimDataValueBuffer) ;
+
+ while (retCodeEnumValue != ERROR_NO_MORE_ITEMS)
+ {
+ char *my_env;
+ /* Crea la stringa d'ambiente */
+ setEnvString(EnvString, NameValueBuffer, DataValueBuffer) ;
+
+ /* Inserisce i dati come variabili d'ambiente */
+ my_env=strdup(EnvString); /* variable for putenv must be allocated ! */
+ putenv(EnvString) ;
+
+ dimNameValueBuffer = dimName ;
+ dimDataValueBuffer = dimData ;
+
+ retCodeEnumValue = RegEnumValue(hSoftMysql, indexValue++,
+ NameValueBuffer, &dimNameValueBuffer,
+ NULL, NULL, (LPBYTE)DataValueBuffer,
+ &dimDataValueBuffer) ;
+ }
+
+ /* chiude la chiave */
+ RegCloseKey(hSoftMysql) ;
+ DBUG_VOID_RETURN ;
+}
+
+
+/*------------------------------------------------------------------
+** Name: CheckForTcpip| Desc: checks if tcpip has been installed on system
+** According to Microsoft Developers documentation the first registry
+** entry should be enough to check if TCP/IP is installed, but as expected
+** this doesn't work on all Win32 machines :(
+------------------------------------------------------------------*/
+
+#define TCPIPKEY "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters"
+#define WINSOCK2KEY "SYSTEM\\CurrentControlSet\\Services\\Winsock2\\Parameters"
+#define WINSOCKKEY "SYSTEM\\CurrentControlSet\\Services\\Winsock\\Parameters"
+
+static my_bool win32_have_tcpip(void)
+{
+ HKEY hTcpipRegKey;
+ if (RegOpenKeyEx ( HKEY_LOCAL_MACHINE, TCPIPKEY, 0, KEY_READ,
+ &hTcpipRegKey) != ERROR_SUCCESS)
+ {
+ if (RegOpenKeyEx ( HKEY_LOCAL_MACHINE, WINSOCK2KEY, 0, KEY_READ,
+ &hTcpipRegKey) != ERROR_SUCCESS)
+ {
+ if (RegOpenKeyEx ( HKEY_LOCAL_MACHINE, WINSOCKKEY, 0, KEY_READ,
+ &hTcpipRegKey) != ERROR_SUCCESS)
+ if (!getenv("HAVE_TCPIP") || have_tcpip) /* Provide a workaround */
+ return (FALSE);
+ }
+ }
+ RegCloseKey ( hTcpipRegKey);
+ return (TRUE);
+}
+
+static my_bool win32_init_tcp_ip()
+{
+ if (win32_have_tcpip())
+ {
+ WORD wVersionRequested = MAKEWORD( 2, 0 );
+ WSADATA wsaData;
+ /* Be a good citizen: maybe another lib has already initialised
+ sockets, so dont clobber them unless necessary */
+ if (WSAStartup( wVersionRequested, &wsaData ))
+ {
+ /* Load failed, maybe because of previously loaded
+ incompatible version; try again */
+ WSACleanup( );
+ if (!WSAStartup( wVersionRequested, &wsaData ))
+ have_tcpip=1;
+ }
+ else
+ {
+ if (wsaData.wVersion != wVersionRequested)
+ {
+ /* Version is no good, try again */
+ WSACleanup( );
+ if (!WSAStartup( wVersionRequested, &wsaData ))
+ have_tcpip=1;
+ }
+ else
+ have_tcpip=1;
+ }
+ }
+ return(0);
+}
+#endif
diff --git a/mysys/my_lib.c b/mysys/my_lib.c
new file mode 100644
index 00000000000..b8554b08d28
--- /dev/null
+++ b/mysys/my_lib.c
@@ -0,0 +1,607 @@
+/* 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 */
+
+/* TODO: check for overun of memory for names. */
+/* Convert MSDOS-TIME to standar time_t */
+
+#define USES_TYPES /* sys/types is included */
+#include "mysys_priv.h"
+#include <m_string.h>
+#include <my_dir.h> /* Structs used by my_dir,includes sys/types */
+#include "mysys_err.h"
+#if defined(HAVE_DIRENT_H)
+# include <dirent.h>
+# define NAMLEN(dirent) strlen((dirent)->d_name)
+#else
+# define dirent direct
+# define NAMLEN(dirent) (dirent)->d_namlen
+# if defined(HAVE_SYS_NDIR_H)
+# include <sys/ndir.h>
+# endif
+# if defined(HAVE_SYS_DIR_H)
+# include <sys/dir.h>
+# endif
+# if defined(HAVE_NDIR_H)
+# include <ndir.h>
+# endif
+# if defined(MSDOS) || defined(__WIN__)
+# include <dos.h>
+# ifdef __BORLANDC__
+# include <dir.h>
+# endif
+# endif
+#endif
+#ifdef VMS
+#include <rms.h>
+#include <iodef.h>
+#include <descrip.h>
+#endif
+#if defined(THREAD) && defined(HAVE_READDIR_R)
+#define READDIR(A,B,C) ((errno=readdir_r(A,B,&C)) != 0 || !C)
+#else
+#define READDIR(A,B,C) (!(C=readdir(A)))
+#endif
+
+
+#define STARTSIZE ONCE_ALLOC_INIT*8 /* some mallocmargin */
+
+static int comp_names(struct fileinfo *a,struct fileinfo *b);
+
+
+ /* We need this because program don't know with malloc we used */
+
+void my_dirend(MY_DIR *buffer)
+{
+ DBUG_ENTER("my_dirend");
+ if (buffer)
+ my_free((gptr) buffer,MYF(0));
+ DBUG_VOID_RETURN;
+} /* my_dirend */
+
+
+ /* Compare in sort of filenames */
+
+static int comp_names(struct fileinfo *a, struct fileinfo *b)
+{
+ return (strcmp(a->name,b->name));
+} /* comp_names */
+
+
+#if !defined(MSDOS) && !defined(__WIN__)
+
+MY_DIR *my_dir(const char *path, myf MyFlags)
+{
+ DIR *dirp;
+ struct dirent *dp;
+ struct fileinfo *fnames;
+ char *buffer, *obuffer, *tempptr;
+ uint fcnt,i,size,firstfcnt, maxfcnt,length;
+ char tmp_path[FN_REFLEN+1],*tmp_file;
+ my_ptrdiff_t diff;
+ bool eof;
+#ifdef THREAD
+ char dirent_tmp[sizeof(struct dirent)+_POSIX_PATH_MAX+1];
+#endif
+ DBUG_ENTER("my_dir");
+ DBUG_PRINT("my",("path: '%s' stat: %d MyFlags: %d",path,MyFlags));
+
+#if defined(THREAD) && !defined(HAVE_READDIR_R)
+ pthread_mutex_lock(&THR_LOCK_open);
+#endif
+
+ dirp = opendir(directory_file_name(tmp_path,(my_string) path));
+ size = STARTSIZE;
+ if (dirp == NULL || ! (buffer = (char *) my_malloc(size, MyFlags)))
+ goto error;
+
+ fcnt = 0;
+ tmp_file=strend(tmp_path);
+ firstfcnt = maxfcnt = (size - sizeof(MY_DIR)) /
+ (sizeof(struct fileinfo) + FN_LEN);
+ fnames= (struct fileinfo *) (buffer + sizeof(MY_DIR));
+ tempptr = (char *) (fnames + maxfcnt);
+
+#ifdef THREAD
+ dp= (struct dirent*) dirent_tmp;
+#else
+ dp=0;
+#endif
+ eof=0;
+ for (;;)
+ {
+ while (fcnt < maxfcnt &&
+ !(eof= READDIR(dirp,(struct dirent*) dirent_tmp,dp)))
+ {
+ bzero((gptr) (fnames+fcnt),sizeof(fnames[0])); /* for purify */
+ fnames[fcnt].name = tempptr;
+ tempptr = strmov(tempptr,dp->d_name) + 1;
+ if (MyFlags & MY_WANT_STAT)
+ {
+ VOID(strmov(tmp_file,dp->d_name));
+ VOID(my_stat(tmp_path, &fnames[fcnt].mystat, MyFlags));
+ }
+ ++fcnt;
+ }
+ if (eof)
+ break;
+ size += STARTSIZE; obuffer = buffer;
+ if (!(buffer = (char *) my_realloc((gptr) buffer, size,
+ MyFlags | MY_FREE_ON_ERROR)))
+ goto error; /* No memory */
+ length= (uint) (sizeof(struct fileinfo ) * firstfcnt);
+ diff= PTR_BYTE_DIFF(buffer , obuffer) + (int) length;
+ fnames= (struct fileinfo *) (buffer + sizeof(MY_DIR));
+ tempptr= ADD_TO_PTR(tempptr,diff,char*);
+ for (i = 0; i < maxfcnt; i++)
+ fnames[i].name = ADD_TO_PTR(fnames[i].name,diff,char*);
+
+ /* move filenames upp a bit */
+ maxfcnt += firstfcnt;
+ bmove_upp(tempptr,tempptr-length,
+ (uint) (tempptr- (char*) (fnames+maxfcnt)));
+ }
+
+ (void) closedir(dirp);
+ {
+ MY_DIR * s = (MY_DIR *) buffer;
+ s->number_off_files = (uint) fcnt;
+ s->dir_entry = fnames;
+ }
+ if (!(MyFlags & MY_DONT_SORT))
+ qsort((void *) fnames, (size_s) fcnt, sizeof(struct fileinfo),
+ (qsort_cmp) comp_names);
+#if defined(THREAD) && !defined(HAVE_READDIR_R)
+ pthread_mutex_unlock(&THR_LOCK_open);
+#endif
+ DBUG_RETURN((MY_DIR *) buffer);
+
+ error:
+#if defined(THREAD) && !defined(HAVE_READDIR_R)
+ pthread_mutex_unlock(&THR_LOCK_open);
+#endif
+ my_errno=errno;
+ if (dirp)
+ (void) closedir(dirp);
+ 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 */
+
+
+/*
+ * Convert from directory name to filename.
+ * On VMS:
+ * xyzzy:[mukesh.emacs] => xyzzy:[mukesh]emacs.dir.1
+ * xyzzy:[mukesh] => xyzzy:[000000]mukesh.dir.1
+ * On UNIX, it's simple: just make sure there is a terminating /
+
+ * Returns pointer to dst;
+ */
+
+my_string directory_file_name (my_string dst, const char *src)
+{
+#ifndef VMS
+
+ /* Process as Unix format: just remove test the final slash. */
+
+ my_string end;
+
+ if (src[0] == 0)
+ src= (char*) "."; /* Use empty as current */
+ end=strmov(dst, src);
+ if (end[-1] != FN_LIBCHAR)
+ {
+ end[0]=FN_LIBCHAR; /* Add last '/' */
+ end[1]='\0';
+ }
+ return dst;
+
+#else /* VMS */
+
+ long slen;
+ long rlen;
+ my_string ptr, rptr;
+ char bracket;
+ struct FAB fab = cc$rms_fab;
+ struct NAM nam = cc$rms_nam;
+ char esa[NAM$C_MAXRSS];
+
+ if (! src[0])
+ src="[.]"; /* Empty is == current dir */
+
+ slen = strlen (src) - 1;
+ if (src[slen] == FN_C_AFTER_DIR || src[slen] == FN_C_AFTER_DIR_2 ||
+ src[slen] == FN_DEVCHAR)
+ {
+ /* VMS style - convert [x.y.z] to [x.y]z, [x] to [000000]x */
+ fab.fab$l_fna = src;
+ fab.fab$b_fns = slen + 1;
+ fab.fab$l_nam = &nam;
+ fab.fab$l_fop = FAB$M_NAM;
+
+ nam.nam$l_esa = esa;
+ nam.nam$b_ess = sizeof esa;
+ nam.nam$b_nop |= NAM$M_SYNCHK;
+
+ /* We call SYS$PARSE to handle such things as [--] for us. */
+ if (SYS$PARSE(&fab, 0, 0) == RMS$_NORMAL)
+ {
+ slen = nam.nam$b_esl - 1;
+ if (esa[slen] == ';' && esa[slen - 1] == '.')
+ slen -= 2;
+ esa[slen + 1] = '\0';
+ src = esa;
+ }
+ if (src[slen] != FN_C_AFTER_DIR && src[slen] != FN_C_AFTER_DIR_2)
+ {
+ /* what about when we have logical_name:???? */
+ if (src[slen] == FN_DEVCHAR)
+ { /* Xlate logical name and see what we get */
+ VOID(strmov(dst,src));
+ dst[slen] = 0; /* remove colon */
+ if (!(src = getenv (dst)))
+ return dst; /* Can't translate */
+
+ /* should we jump to the beginning of this procedure?
+ Good points: allows us to use logical names that xlate
+ to Unix names,
+ Bad points: can be a problem if we just translated to a device
+ name...
+ For now, I'll punt and always expect VMS names, and hope for
+ the best! */
+
+ slen = strlen (src) - 1;
+ if (src[slen] != FN_C_AFTER_DIR && src[slen] != FN_C_AFTER_DIR_2)
+ { /* no recursion here! */
+ VOID(strmov(dst, src));
+ return(dst);
+ }
+ }
+ else
+ { /* not a directory spec */
+ VOID(strmov(dst, src));
+ return(dst);
+ }
+ }
+
+ bracket = src[slen]; /* End char */
+ if (!(ptr = strchr (src, bracket - 2)))
+ { /* no opening bracket */
+ VOID(strmov (dst, src));
+ return dst;
+ }
+ if (!(rptr = strrchr (src, '.')))
+ rptr = ptr;
+ slen = rptr - src;
+ VOID(strmake (dst, src, slen));
+
+ if (*rptr == '.')
+ { /* Put bracket and add */
+ dst[slen++] = bracket; /* (rptr+1) after this */
+ }
+ else
+ {
+ /* If we have the top-level of a rooted directory (i.e. xx:[000000]),
+ then translate the device and recurse. */
+
+ if (dst[slen - 1] == ':'
+ && dst[slen - 2] != ':' /* skip decnet nodes */
+ && strcmp(src + slen, "[000000]") == 0)
+ {
+ dst[slen - 1] = '\0';
+ if ((ptr = getenv (dst))
+ && (rlen = strlen (ptr) - 1) > 0
+ && (ptr[rlen] == FN_C_AFTER_DIR || ptr[rlen] == FN_C_AFTER_DIR_2)
+ && ptr[rlen - 1] == '.')
+ {
+ VOID(strmov(esa,ptr));
+ esa[rlen - 1] = FN_C_AFTER_DIR;
+ esa[rlen] = '\0';
+ return (directory_file_name (dst, esa));
+ }
+ else
+ dst[slen - 1] = ':';
+ }
+ VOID(strmov(dst+slen,"[000000]"));
+ slen += 8;
+ }
+ VOID(strmov(strmov(dst+slen,rptr+1)-1,".DIR.1"));
+ return dst;
+ }
+ VOID(strmov(dst, src));
+ if (dst[slen] == '/' && slen > 1)
+ dst[slen] = 0;
+ return dst;
+#endif /* VMS */
+} /* directory_file_name */
+
+#elif defined(WIN32)
+
+/*
+*****************************************************************************
+** Read long filename using windows rutines
+*****************************************************************************
+*/
+
+MY_DIR *my_dir(path, MyFlags)
+const char *path;
+myf MyFlags;
+{
+ struct fileinfo *fnames;
+ char *buffer, *obuffer, *tempptr;
+ int eof,i,fcnt,firstfcnt,length,maxfcnt;
+ uint size;
+#ifdef __BORLANDC__
+ struct ffblk find;
+#else
+ struct _finddata_t find;
+#endif
+ ushort mode;
+ char tmp_path[FN_REFLEN],*tmp_file,attrib;
+ my_ptrdiff_t diff;
+ long handle;
+ DBUG_ENTER("my_dir");
+ DBUG_PRINT("my",("path: '%s' stat: %d MyFlags: %d",path,MyFlags));
+
+ /* Put LIB-CHAR as last path-character if not there */
+
+ tmp_file=tmp_path;
+ if (!*path)
+ *tmp_file++ ='.'; /* From current dir */
+ tmp_file= strmov(tmp_file,path);
+ if (tmp_file[-1] == FN_DEVCHAR)
+ *tmp_file++= '.'; /* From current dev-dir */
+ if (tmp_file[-1] != FN_LIBCHAR)
+ *tmp_file++ =FN_LIBCHAR;
+ tmp_file[0]='*'; /* MSDOS needs this !??? */
+ tmp_file[1]='.';
+ tmp_file[2]='*';
+ tmp_file[3]='\0';
+
+#ifdef __BORLANDC__
+ if ((handle= findfirst(tmp_path,&find,0)) == -1L)
+ goto error;
+#else
+ if ((handle=_findfirst(tmp_path,&find)) == -1L)
+ goto error;
+#endif
+
+ size = STARTSIZE;
+ firstfcnt = maxfcnt = (size - sizeof(MY_DIR)) /
+ (sizeof(struct fileinfo) + FN_LEN);
+ if ((buffer = (char *) my_malloc(size, MyFlags)) == 0)
+ goto error;
+ fnames= (struct fileinfo *) (buffer + sizeof(MY_DIR));
+ tempptr = (char *) (fnames + maxfcnt);
+
+ fcnt = 0;
+ for (;;)
+ {
+ do
+ {
+ fnames[fcnt].name = tempptr;
+#ifdef __BORLANDC__
+ tempptr = strmov(tempptr,find.ff_name) + 1;
+ fnames[fcnt].mystat.st_size=find.ff_fsize;
+ fnames[fcnt].mystat.st_uid=fnames[fcnt].mystat.st_gid=0;
+ mode=MY_S_IREAD; attrib=find.ff_attrib;
+#else
+ tempptr = strmov(tempptr,find.name) + 1;
+ fnames[fcnt].mystat.st_size=find.size;
+ fnames[fcnt].mystat.st_uid=fnames[fcnt].mystat.st_gid=0;
+ mode=MY_S_IREAD; attrib=find.attrib;
+#endif
+ if (!(attrib & _A_RDONLY))
+ mode|=MY_S_IWRITE;
+ if (attrib & _A_SUBDIR)
+ mode|=MY_S_IFDIR;
+ fnames[fcnt].mystat.st_mode=mode;
+#ifdef __BORLANDC__
+ fnames[fcnt].mystat.st_mtime=((uint32) find.ff_ftime);
+#else
+ fnames[fcnt].mystat.st_mtime=((uint32) find.time_write);
+#endif
+ ++fcnt;
+#ifdef __BORLANDC__
+ } while ((eof= findnext(&find)) == 0 && fcnt < maxfcnt);
+#else
+ } while ((eof= _findnext(handle,&find)) == 0 && fcnt < maxfcnt);
+#endif
+
+ DBUG_PRINT("test",("eof: %d errno: %d",eof,errno));
+ if (eof)
+ break;
+ size += STARTSIZE; obuffer = buffer;
+ if (!(buffer = (char *) my_realloc((gptr) buffer, size,
+ MyFlags | MY_FREE_ON_ERROR)))
+ goto error;
+ length= sizeof(struct fileinfo ) * firstfcnt;
+ diff= PTR_BYTE_DIFF(buffer , obuffer) +length;
+ fnames= (struct fileinfo *) (buffer + sizeof(MY_DIR));
+ tempptr= ADD_TO_PTR(tempptr,diff,char*);
+ for (i = 0; i < maxfcnt; i++)
+ fnames[i].name = ADD_TO_PTR(fnames[i].name,diff,char*);
+
+ /* move filenames upp a bit */
+ maxfcnt += firstfcnt;
+ bmove_upp(tempptr,ADD_TO_PTR(tempptr,-length,char*),
+ (int) PTR_BYTE_DIFF(tempptr,fnames+maxfcnt));
+ }
+ {
+ MY_DIR * s = (MY_DIR *) buffer;
+ s->number_off_files = (uint) fcnt;
+ s->dir_entry = fnames;
+ }
+ if (!(MyFlags & MY_DONT_SORT))
+ qsort(fnames,fcnt,sizeof(struct fileinfo),(qsort_cmp) comp_names);
+#ifndef __BORLANDC__
+ _findclose(handle);
+#endif
+ DBUG_RETURN((MY_DIR *) buffer);
+
+error:
+ my_errno=errno;
+#ifndef __BORLANDC__
+ if (handle != -1)
+ _findclose(handle);
+#endif
+ if (MyFlags & MY_FAE+MY_WME)
+ my_error(EE_DIR,MYF(ME_BELL+ME_WAITTANG),path,errno);
+ DBUG_RETURN((MY_DIR *) NULL);
+} /* my_dir */
+
+#else /* MSDOS and not WIN32 */
+
+
+/******************************************************************************
+** At MSDOS you always get stat of files, but time is in packed MSDOS-format
+******************************************************************************/
+
+MY_DIR *my_dir(path, MyFlags)
+const char *path;
+myf MyFlags;
+{
+ struct fileinfo *fnames;
+ char *buffer, *obuffer, *tempptr;
+ int eof,i,fcnt,firstfcnt,length,maxfcnt;
+ uint size;
+ struct find_t find;
+ ushort mode;
+ char tmp_path[FN_REFLEN],*tmp_file,attrib;
+ my_ptrdiff_t diff;
+ DBUG_ENTER("my_dir");
+ DBUG_PRINT("my",("path: '%s' stat: %d MyFlags: %d",path,MyFlags));
+
+ /* Put LIB-CHAR as last path-character if not there */
+
+ tmp_file=tmp_path;
+ if (!*path)
+ *tmp_file++ ='.'; /* From current dir */
+ tmp_file= strmov(tmp_file,path);
+ if (tmp_file[-1] == FN_DEVCHAR)
+ *tmp_file++= '.'; /* From current dev-dir */
+ if (tmp_file[-1] != FN_LIBCHAR)
+ *tmp_file++ =FN_LIBCHAR;
+ tmp_file[0]='*'; /* MSDOS needs this !??? */
+ tmp_file[1]='.';
+ tmp_file[2]='*';
+ tmp_file[3]='\0';
+
+ if (_dos_findfirst(tmp_path,_A_NORMAL | _A_SUBDIR, &find))
+ goto error;
+
+ size = STARTSIZE;
+ firstfcnt = maxfcnt = (size - sizeof(MY_DIR)) /
+ (sizeof(struct fileinfo) + FN_LEN);
+ if ((buffer = (char *) my_malloc(size, MyFlags)) == 0)
+ goto error;
+ fnames= (struct fileinfo *) (buffer + sizeof(MY_DIR));
+ tempptr = (char *) (fnames + maxfcnt);
+
+ fcnt = 0;
+ for (;;)
+ {
+ do
+ {
+ fnames[fcnt].name = tempptr;
+ tempptr = strmov(tempptr,find.name) + 1;
+ fnames[fcnt].mystat.st_size=find.size;
+ fnames[fcnt].mystat.st_uid=fnames[fcnt].mystat.st_gid=0;
+ mode=MY_S_IREAD; attrib=find.attrib;
+ if (!(attrib & _A_RDONLY))
+ mode|=MY_S_IWRITE;
+ if (attrib & _A_SUBDIR)
+ mode|=MY_S_IFDIR;
+ fnames[fcnt].mystat.st_mode=mode;
+ fnames[fcnt].mystat.st_mtime=((uint32) find.wr_date << 16) +
+ find.wr_time;
+ ++fcnt;
+ } while ((eof= _dos_findnext(&find)) == 0 && fcnt < maxfcnt);
+
+ DBUG_PRINT("test",("eof: %d errno: %d",eof,errno));
+ if (eof)
+ break;
+ size += STARTSIZE; obuffer = buffer;
+ if (!(buffer = (char *) my_realloc((gptr) buffer, size,
+ MyFlags | MY_FREE_ON_ERROR)))
+ goto error;
+ length= sizeof(struct fileinfo ) * firstfcnt;
+ diff= PTR_BYTE_DIFF(buffer , obuffer) +length;
+ fnames= (struct fileinfo *) (buffer + sizeof(MY_DIR));
+ tempptr= ADD_TO_PTR(tempptr,diff,char*);
+ for (i = 0; i < maxfcnt; i++)
+ fnames[i].name = ADD_TO_PTR(fnames[i].name,diff,char*);
+
+ /* move filenames upp a bit */
+ maxfcnt += firstfcnt;
+ bmove_upp(tempptr,ADD_TO_PTR(tempptr,-length,char*),
+ (int) PTR_BYTE_DIFF(tempptr,fnames+maxfcnt));
+ }
+ {
+ MY_DIR * s = (MY_DIR *) buffer;
+ s->number_off_files = (uint) fcnt;
+ s->dir_entry = fnames;
+ }
+ if (!(MyFlags & MY_DONT_SORT))
+ qsort(fnames,fcnt,sizeof(struct fileinfo),(qsort_cmp) comp_names);
+ DBUG_RETURN((MY_DIR *) buffer);
+
+error:
+ if (MyFlags & MY_FAE+MY_WME)
+ my_error(EE_DIR,MYF(ME_BELL+ME_WAITTANG),path,errno);
+ DBUG_RETURN((MY_DIR *) NULL);
+} /* my_dir */
+
+#endif /* WIN32 && MSDOS */
+
+/****************************************************************************
+** File status
+** Note that MY_STAT is assumed to be same as struct stat
+****************************************************************************/
+
+int my_fstat(int Filedes, MY_STAT *stat_area, myf MyFlags )
+{
+ 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;
+ DBUG_ENTER("my_stat");
+ DBUG_PRINT("my", ("path: '%s', stat_area: %lx, MyFlags: %d", path,
+ (byte *) stat_area, my_flags));
+
+ if ((m_used= (stat_area == NULL)))
+ if (!(stat_area = (MY_STAT *) my_malloc(sizeof(MY_STAT), my_flags)))
+ goto error;
+ if ( ! stat((my_string) path, (struct stat *) stat_area) )
+ DBUG_RETURN(stat_area);
+ my_errno=errno;
+ if (m_used) /* Free if new area */
+ my_free((gptr) stat_area,MYF(0));
+
+error:
+ if (my_flags & (MY_FAE+MY_WME))
+ {
+ my_error(EE_STAT, MYF(ME_BELL+ME_WAITTANG),path,my_errno);
+ DBUG_RETURN((MY_STAT *) NULL);
+ }
+ DBUG_RETURN((MY_STAT *) NULL);
+} /* my_stat */
+
diff --git a/mysys/my_lock.c b/mysys/my_lock.c
new file mode 100644
index 00000000000..4f1506f20cf
--- /dev/null
+++ b/mysys/my_lock.c
@@ -0,0 +1,161 @@
+/* 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 "mysys_err.h"
+#include <errno.h>
+#undef MY_HOW_OFTEN_TO_ALARM
+#define MY_HOW_OFTEN_TO_ALARM ((int) my_time_to_wait_for_lock)
+#ifdef NO_ALARM_LOOP
+#undef NO_ALARM_LOOP
+#endif
+#include <my_alarm.h>
+#ifdef __WIN__
+#include <sys/locking.h>
+#endif
+#ifdef __EMX__
+#define INCL_BASE
+#define INCL_NOPMAPI
+#include <os2emx.h>
+#endif
+
+#ifdef HAVE_FCNTL
+static struct flock lock; /* Must be static for sun-sparc */
+#endif
+
+ /* Lock a part of a file */
+
+int my_lock(File fd, int locktype, my_off_t start, my_off_t length,
+ myf MyFlags)
+{
+#ifdef __EMX__
+ FILELOCK LockArea = {0,0}, UnlockArea = {0,0};
+ APIRET rc = 0;
+ fpos_t oldpos;
+ int lockflags = 0;
+#endif
+#ifdef HAVE_FCNTL
+ int value;
+ ALARM_VARIABLES;
+#endif
+ DBUG_ENTER("my_lock");
+ DBUG_PRINT("my",("Fd: %d Op: %d start: %ld Length: %ld MyFlags: %d",
+ fd,locktype,(long) start,(long) length,MyFlags));
+#ifdef VMS
+ DBUG_RETURN(0);
+#else
+ if (my_disable_locking)
+ DBUG_RETURN(0);
+#if defined(__EMX__)
+ if (locktype == F_UNLCK) {
+ UnlockArea.lOffset = start;
+ if (length)
+ UnlockArea.lRange = length;
+ else
+ UnlockArea.lRange = 0x7FFFFFFFL;
+ } else
+ if (locktype == F_RDLCK || locktype == F_WRLCK) {
+ if (locktype == F_RDLCK) lockflags |= 1;
+ LockArea.lOffset = start;
+ if (length)
+ LockArea.lRange = length;
+ else
+ LockArea.lRange = 0x7FFFFFFFL;
+ } else {
+ my_errno = EINVAL;
+ DBUG_RETURN(-1);
+ }
+ if (!LockArea.lRange && !UnlockArea.lRange)
+ DBUG_RETURN(0);
+ if (MyFlags & MY_DONT_WAIT) {
+ if (!(rc = DosSetFileLocks(fd,&UnlockArea,&LockArea,0,lockflags)))
+ DBUG_RETURN(0); /* Lock was OK */
+ if (rc == 175 && locktype == F_RDLCK) {
+ lockflags &= ~1;
+ rc = DosSetFileLocks(fd,&UnlockArea,&LockArea,0,lockflags);
+ }
+ if (rc == 33) { /* Lock Violation */
+ DBUG_PRINT("info",("Was locked, trying with timeout"));
+ rc = DosSetFileLocks(fd,&UnlockArea,&LockArea,MY_HOW_OFTEN_TO_ALARM * 1000,lockflags);
+ }
+ if (!rc) DBUG_RETURN(0);
+ if (rc == 33) errno = EAGAIN;
+ else {
+ errno = EINVAL;
+ printf("Error: DosSetFileLocks() == %d\n",rc);
+ }
+ } else {
+ while (rc = DosSetFileLocks(fd,&UnlockArea,&LockArea,
+ MY_HOW_OFTEN_TO_ALARM * 1000,lockflags) && (rc == 33 || rc == 175)) {
+ printf(".");
+ if (rc == 175) lockflags &= ~1;
+ }
+ if (!rc) DBUG_RETURN(0);
+ errno = EINVAL;
+ printf("Error: DosSetFileLocks() == %d\n",rc);
+ }
+#elif defined(HAVE_LOCKING)
+ if (MyFlags & MY_SEEK_NOT_DONE)
+ VOID(my_seek(fd,start,MY_SEEK_SET,MYF(MyFlags & ~MY_SEEK_NOT_DONE)));
+ if (!locking(fd,locktype,(ulong) length) || errno == EINVAL)
+ DBUG_RETURN(0);
+#else
+#if defined(HAVE_FCNTL)
+ lock.l_type= (short) locktype;
+ lock.l_whence=0L;
+ lock.l_start=(long) start;
+ lock.l_len=(long) length;
+ if (MyFlags & MY_DONT_WAIT)
+ {
+ if (fcntl(fd,F_SETLK,&lock) != -1) /* Check if we can lock */
+ DBUG_RETURN(0); /* Ok, file locked */
+ DBUG_PRINT("info",("Was locked, trying with alarm"));
+ ALARM_INIT;
+ while ((value=fcntl(fd,F_SETLKW,&lock)) && ! ALARM_TEST &&
+ errno == EINTR)
+ { /* Setup again so we don`t miss it */
+ ALARM_REINIT;
+ }
+ ALARM_END;
+ if (value != -1)
+ DBUG_RETURN(0);
+ if (errno == EINTR)
+ errno=EAGAIN;
+ }
+ else if (fcntl(fd,F_SETLKW,&lock) != -1) /* Wait until a lock */
+ DBUG_RETURN(0);
+#else
+ if (MyFlags & MY_SEEK_NOT_DONE)
+ VOID(my_seek(fd,start,MY_SEEK_SET,MYF(MyFlags & ~MY_SEEK_NOT_DONE)));
+ if (lockf(fd,locktype,length) != -1)
+ DBUG_RETURN(0);
+#endif /* HAVE_FCNTL */
+#endif /* HAVE_LOCKING */
+
+ /* We got an error. We don't want EACCES errors */
+ my_errno=(errno == EACCES) ? EAGAIN : errno ? errno : -1;
+ if (MyFlags & MY_WME)
+ {
+ if (locktype == F_UNLCK)
+ my_error(EE_CANTUNLOCK,MYF(ME_BELL+ME_WAITTANG),my_errno);
+ else
+ my_error(EE_CANTLOCK,MYF(ME_BELL+ME_WAITTANG),my_errno);
+ }
+ DBUG_PRINT("error",("my_errno: %d (%d)",my_errno,errno));
+ DBUG_RETURN(-1);
+#endif /* ! VMS */
+} /* my_lock */
diff --git a/mysys/my_lockmem.c b/mysys/my_lockmem.c
new file mode 100644
index 00000000000..9c77c885797
--- /dev/null
+++ b/mysys/my_lockmem.c
@@ -0,0 +1,101 @@
+/* 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 */
+
+/* Alloc a block of locked memory */
+
+#include "mysys_priv.h"
+#include "mysys_err.h"
+#include <my_list.h>
+
+#ifdef HAVE_MLOCK
+#include <sys/mman.h>
+
+struct st_mem_list
+{
+ LIST list;
+ byte *page;
+ uint size;
+};
+
+LIST *mem_list;
+
+byte *my_malloc_lock(uint size,myf MyFlags)
+{
+ int success;
+ uint pagesize=sysconf(_SC_PAGESIZE);
+ byte *ptr;
+ struct st_mem_list *element;
+ DBUG_ENTER("my_malloc_lock");
+
+ size=((size-1) & ~(pagesize-1))+pagesize;
+ if (!(ptr=memalign(pagesize,size)))
+ {
+ if (MyFlags & (MY_FAE+MY_WME))
+ my_error(EE_OUTOFMEMORY, MYF(ME_BELL+ME_WAITTANG),size);
+ DBUG_RETURN(0);
+ }
+ success = mlock((byte*) ptr,size);
+ if (success != 0 && geteuid() == 0)
+ {
+ DBUG_PRINT("warning",("Failed to lock memory. errno %d\n",
+ errno));
+ fprintf(stderr, "Warning: Failed to lock memory. errno %d\n",
+ errno);
+ }
+ else
+ {
+ /* Add block in a list for munlock */
+ if (!(element=(struct st_mem_list*) my_malloc(sizeof(*element),MyFlags)))
+ {
+ VOID(munlock((byte*) ptr,size));
+ free(ptr);
+ DBUG_RETURN(0);
+ }
+ element->list.data=(byte*) element;
+ element->page=ptr;
+ element->size=size;
+ pthread_mutex_lock(&THR_LOCK_malloc);
+ mem_list=list_add(mem_list,&element->list);
+ pthread_mutex_unlock(&THR_LOCK_malloc);
+ }
+ DBUG_RETURN(ptr);
+}
+
+
+void my_free_lock(byte *ptr,myf Myflags __attribute__((unused)))
+{
+ LIST *list;
+ struct st_mem_list *element=0;
+
+ pthread_mutex_lock(&THR_LOCK_malloc);
+ for (list=mem_list ; list ; list=list->next)
+ {
+ element=(struct st_mem_list*) list->data;
+ if (ptr == element->page)
+ { /* Found locked mem */
+ VOID(munlock((byte*) ptr,element->size));
+ mem_list=list_delete(mem_list,list);
+ break;
+ }
+ }
+ pthread_mutex_unlock(&THR_LOCK_malloc);
+ if (element)
+ my_free((gptr) element,MYF(0));
+ free(ptr); /* Free even if not locked */
+}
+
+#endif /* HAVE_MLOCK */
diff --git a/mysys/my_lread.c b/mysys/my_lread.c
new file mode 100644
index 00000000000..c3b8a6704c3
--- /dev/null
+++ b/mysys/my_lread.c
@@ -0,0 +1,54 @@
+/* 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 "mysys_err.h"
+
+ /* Read a chunk of bytes from a file */
+
+uint32 my_lread(int Filedes, byte *Buffer, uint32 Count, myf MyFlags)
+ /* File descriptor */
+ /* Buffer must be at least count bytes */
+ /* Max number of bytes returnd */
+ /* Flags on what to do on error */
+{
+ uint32 readbytes;
+ DBUG_ENTER("my_lread");
+ DBUG_PRINT("my",("Fd: %d Buffer: %ld Count: %ld MyFlags: %d",
+ Filedes, Buffer, Count, MyFlags));
+
+ /* Temp hack to get count to int32 while read wants int */
+ if ((readbytes = (uint32) read(Filedes, Buffer, (size_t) Count)) != Count)
+ {
+ my_errno=errno;
+ if (MyFlags & (MY_WME | MY_FAE | MY_FNABP))
+ {
+ if (readbytes == MY_FILE_ERROR)
+ my_error(EE_READ, MYF(ME_BELL+ME_WAITTANG),
+ my_filename(Filedes),errno);
+ else
+ if (MyFlags & (MY_NABP | MY_FNABP))
+ my_error(EE_EOFERR, MYF(ME_BELL+ME_WAITTANG),
+ my_filename(Filedes),errno);
+ }
+ if (readbytes == MY_FILE_ERROR || MyFlags & (MY_NABP | MY_FNABP))
+ DBUG_RETURN((uint32) -1); /* Return med felkod */
+ }
+ if (MyFlags & (MY_NABP | MY_FNABP))
+ DBUG_RETURN(0); /* Ok vid l{sning */
+ DBUG_RETURN(readbytes);
+} /* my_lread */
diff --git a/mysys/my_lwrite.c b/mysys/my_lwrite.c
new file mode 100644
index 00000000000..201c36f619c
--- /dev/null
+++ b/mysys/my_lwrite.c
@@ -0,0 +1,47 @@
+/* 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 "mysys_err.h"
+
+ /* Write a chunk of bytes to a file */
+
+uint32 my_lwrite(int Filedes, const byte *Buffer, uint32 Count, myf MyFlags)
+{
+ uint32 writenbytes;
+ DBUG_ENTER("my_lwrite");
+ DBUG_PRINT("my",("Fd: %d Buffer: %lx Count: %ld MyFlags: %d",
+ Filedes, Buffer, Count, MyFlags));
+
+ /* Temp hack to get count to int32 while write wants int */
+ if ((writenbytes = (uint32) write(Filedes, Buffer, (size_t) Count)) != Count)
+ {
+ my_errno=errno;
+ if (writenbytes == (uint32) -1 || MyFlags & (MY_NABP | MY_FNABP))
+ {
+ if (MyFlags & (MY_WME | MY_FAE | MY_FNABP))
+ {
+ my_error(EE_WRITE, MYF(ME_BELL+ME_WAITTANG),
+ my_filename(Filedes),errno);
+ }
+ DBUG_RETURN((uint32) -1); /* Return med felkod */
+ }
+ }
+ if (MyFlags & (MY_NABP | MY_FNABP))
+ DBUG_RETURN(0); /* Ok vid l{sning */
+ DBUG_RETURN(writenbytes);
+} /* my_lwrite */
diff --git a/mysys/my_malloc.c b/mysys/my_malloc.c
new file mode 100644
index 00000000000..6cae6fe3a4d
--- /dev/null
+++ b/mysys/my_malloc.c
@@ -0,0 +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,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should 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 */
+
+#ifdef SAFEMALLOC /* We don't need SAFEMALLOC here */
+#undef SAFEMALLOC
+#endif
+
+#include "mysys_priv.h"
+#include "mysys_err.h"
+#include <m_string.h>
+
+ /* My memory allocator */
+
+gptr my_malloc(unsigned int Size, myf MyFlags)
+{
+ gptr point;
+ DBUG_ENTER("my_malloc");
+ DBUG_PRINT("my",("Size: %u MyFlags: %d",Size, MyFlags));
+
+ if (!Size)
+ Size=1; /* Safety */
+ if ((point = malloc(Size)) == NULL)
+ {
+ my_errno=errno;
+ if (MyFlags & MY_FAE)
+ error_handler_hook=fatal_error_handler_hook;
+ if (MyFlags & (MY_FAE+MY_WME))
+ my_error(EE_OUTOFMEMORY, MYF(ME_BELL+ME_WAITTANG),Size);
+ if (MyFlags & MY_FAE)
+ exit(1);
+ }
+ else if (MyFlags & MY_ZEROFILL)
+ bzero(point,Size);
+ DBUG_PRINT("exit",("ptr: %lx",point));
+ DBUG_RETURN(point);
+} /* my_malloc */
+
+
+ /* Free memory allocated with my_malloc */
+ /*ARGSUSED*/
+
+void my_no_flags_free(gptr ptr)
+{
+ DBUG_ENTER("my_free");
+ DBUG_PRINT("my",("ptr: %lx",ptr));
+ if (ptr)
+ free(ptr);
+ DBUG_VOID_RETURN;
+} /* my_free */
+
+
+ /* malloc and copy */
+
+gptr my_memdup(const byte *from, uint length, myf MyFlags)
+{
+ gptr ptr;
+ if ((ptr=my_malloc(length,MyFlags)) != 0)
+ memcpy((byte*) ptr, (byte*) from,(size_t) length);
+ return(ptr);
+}
+
+
+my_string my_strdup(const char *from, myf MyFlags)
+{
+ gptr ptr;
+ uint length=(uint) strlen(from)+1;
+ if ((ptr=my_malloc(length,MyFlags)) != 0)
+ memcpy((byte*) ptr, (byte*) from,(size_t) length);
+ return((my_string) ptr);
+}
diff --git a/mysys/my_messnc.c b/mysys/my_messnc.c
new file mode 100644
index 00000000000..0dd3be5ba98
--- /dev/null
+++ b/mysys/my_messnc.c
@@ -0,0 +1,36 @@
+/* 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"
+
+int my_message_no_curses(uint error __attribute__((unused)),
+ const char *str, myf MyFlags)
+{
+ DBUG_ENTER("my_message_no_curses");
+ DBUG_PRINT("enter",("message: %s",str));
+ (void) fflush(stdout);
+ if (MyFlags & ME_BELL)
+ (void) fputc('\007',stderr); /* Bell */
+ if (my_progname)
+ {
+ (void)fputs(my_progname,stderr); (void)fputs(": ",stderr);
+ }
+ (void)fputs(str,stderr);
+ (void)fputc('\n',stderr);
+ (void)fflush(stderr);
+ DBUG_RETURN(0);
+}
diff --git a/mysys/my_mkdir.c b/mysys/my_mkdir.c
new file mode 100644
index 00000000000..773cd26cb03
--- /dev/null
+++ b/mysys/my_mkdir.c
@@ -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 */
+
+#include "mysys_priv.h"
+#include "mysys_err.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef __WIN__
+#include <direct.h>
+#endif
+
+int my_mkdir(const char *dir, int Flags, myf MyFlags)
+{
+ DBUG_ENTER("my_dir");
+ DBUG_PRINT("enter",("dir: %s",dir));
+
+#ifdef __WIN__
+ if (mkdir(dir))
+#else
+ if (mkdir((char*) dir, Flags & my_umask_dir))
+#endif
+ {
+ my_errno=errno;
+ DBUG_PRINT("error",("error %d when creating direcory %s",my_errno,dir));
+ if (MyFlags & (MY_FFNF | MY_FAE | MY_WME))
+ my_error(EE_CANT_MKDIR, MYF(ME_BELL+ME_WAITTANG), dir, my_errno);
+ DBUG_RETURN(-1);
+ }
+ DBUG_RETURN(0);
+}
diff --git a/mysys/my_net.c b/mysys/my_net.c
new file mode 100644
index 00000000000..1c91f7ff802
--- /dev/null
+++ b/mysys/my_net.c
@@ -0,0 +1,49 @@
+/* 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 */
+
+/* thread safe version of some common functions */
+
+#include "mysys_priv.h"
+#include <m_string.h>
+
+/* for thread safe my_inet_ntoa */
+#if !defined(MSDOS) && !defined(__WIN__)
+#include <netdb.h>
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#endif /* !defined(MSDOS) && !defined(__WIN__) */
+
+#ifndef THREAD
+#define pthread_mutex_lock(A)
+#define pthread_mutex_unlock(A)
+#endif
+
+void my_inet_ntoa(struct in_addr in, char *buf)
+{
+ char *ptr;
+ pthread_mutex_lock(&THR_LOCK_net);
+ ptr=inet_ntoa(in);
+ strmov(buf,ptr);
+ pthread_mutex_unlock(&THR_LOCK_net);
+}
diff --git a/mysys/my_once.c b/mysys/my_once.c
new file mode 100644
index 00000000000..0b8b5addc16
--- /dev/null
+++ b/mysys/my_once.c
@@ -0,0 +1,88 @@
+/* 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 */
+
+/* Not MT-SAFE */
+
+#ifdef SAFEMALLOC /* We don't need SAFEMALLOC here */
+#undef SAFEMALLOC
+#endif
+
+#include "mysys_priv.h"
+#include "my_static.h"
+#include "mysys_err.h"
+
+ /* alloc for things we don't nead to free */
+ /* No DBUG_ENTER... here to get smaller dbug-startup */
+
+gptr my_once_alloc(unsigned int Size, myf MyFlags)
+{
+ uint get_size,max_left;
+ gptr point;
+ reg1 USED_MEM *next;
+ reg2 USED_MEM **prev;
+
+ Size= ALIGN_SIZE(Size);
+ prev= &my_once_root_block;
+ max_left=0;
+ for (next=my_once_root_block ; next && next->left < Size ; next= next->next)
+ {
+ if (next->left > max_left)
+ max_left=next->left;
+ prev= &next->next;
+ }
+ if (! next)
+ { /* Time to alloc new block */
+ get_size= Size+ALIGN_SIZE(sizeof(USED_MEM));
+ if (max_left*4 < my_once_extra && get_size < my_once_extra)
+ get_size=my_once_extra; /* Normal alloc */
+
+ if ((next = (USED_MEM*) malloc(get_size)) == 0)
+ {
+ my_errno=errno;
+ if (MyFlags & (MY_FAE+MY_WME))
+ my_error(EE_OUTOFMEMORY, MYF(ME_BELL+ME_WAITTANG),get_size);
+ return((gptr) 0);
+ }
+ DBUG_PRINT("test",("my_once_malloc %u byte malloced",get_size));
+ next->next= 0;
+ next->size= get_size;
+ next->left= get_size-ALIGN_SIZE(sizeof(USED_MEM));
+ *prev=next;
+ }
+ point= (gptr) ((char*) next+ (next->size-next->left));
+ next->left-= Size;
+
+ return(point);
+} /* my_once_alloc */
+
+
+ /* deallocate everything used by my_once_alloc */
+
+void my_once_free(void)
+{
+ reg1 USED_MEM *next,*old;
+ DBUG_ENTER("my_once_free");
+
+ for (next=my_once_root_block ; next ; )
+ {
+ old=next; next= next->next ;
+ free((gptr) old);
+ }
+ my_once_root_block=0;
+
+ DBUG_VOID_RETURN;
+} /* my_once_free */
diff --git a/mysys/my_open.c b/mysys/my_open.c
new file mode 100644
index 00000000000..ef1db41e3f5
--- /dev/null
+++ b/mysys/my_open.c
@@ -0,0 +1,97 @@
+/* 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 */
+
+#define USES_TYPES
+#include "mysys_priv.h"
+#include "mysys_err.h"
+#include <errno.h>
+#if defined(MSDOS) || defined(__WIN__)
+#include <share.h>
+#endif
+
+ /* Open a file */
+
+File my_open(const char *FileName, int Flags, myf MyFlags)
+ /* Path-name of file */
+ /* Read | write .. */
+ /* Special flags */
+{
+ File fd;
+ DBUG_ENTER("my_open");
+ DBUG_PRINT("my",("Name: '%s' Flags: %d MyFlags: %d",
+ FileName, Flags, MyFlags));
+#if defined(MSDOS) || defined(__WIN__)
+ if (Flags & O_SHARE)
+ fd = sopen((my_string) FileName, (Flags & ~O_SHARE) | O_BINARY, SH_DENYNO);
+ else
+ fd = open((my_string) FileName, Flags | O_BINARY);
+#elif !defined(NO_OPEN_3)
+ fd = open(FileName, Flags, 0); /* Normal unix */
+#else
+ fd = open((my_string) FileName, Flags);
+#endif
+
+ if ((int) fd >= 0)
+ {
+ if ((int) fd >= MY_NFILE)
+ DBUG_RETURN(fd); /* safeguard */
+ pthread_mutex_lock(&THR_LOCK_open);
+ if ((my_file_info[fd].name = (char*) my_strdup(FileName,MyFlags)))
+ {
+ my_file_opened++;
+ my_file_info[fd].type = FILE_BY_OPEN;
+ pthread_mutex_unlock(&THR_LOCK_open);
+ DBUG_PRINT("exit",("fd: %d",fd));
+ DBUG_RETURN(fd);
+ }
+ pthread_mutex_unlock(&THR_LOCK_open);
+ (void) my_close(fd,MyFlags);
+ my_errno=ENOMEM;
+ }
+ else
+ my_errno=errno;
+ DBUG_PRINT("error",("Got error %d on open",my_errno));
+ if (MyFlags & (MY_FFNF | MY_FAE | MY_WME))
+ my_error(EE_FILENOTFOUND, MYF(ME_BELL+ME_WAITTANG), FileName,my_errno);
+ DBUG_RETURN(fd);
+} /* my_open */
+
+
+ /* Close a file */
+
+int my_close(File fd, myf MyFlags)
+{
+ int err;
+ DBUG_ENTER("my_close");
+ DBUG_PRINT("my",("fd: %d MyFlags: %d",fd, MyFlags));
+
+ pthread_mutex_lock(&THR_LOCK_open);
+ if ((err = close(fd)) != 0)
+ {
+ my_errno=errno;
+ if (MyFlags & (MY_FAE | MY_WME))
+ my_error(EE_BADCLOSE, MYF(ME_BELL+ME_WAITTANG),my_filename(fd),errno);
+ }
+ if ((uint) fd < MY_NFILE && my_file_info[fd].type != UNOPEN)
+ {
+ my_file_opened--;
+ my_free(my_file_info[fd].name, MYF(0));
+ my_file_info[fd].type = UNOPEN;
+ }
+ pthread_mutex_unlock(&THR_LOCK_open);
+ DBUG_RETURN(err);
+} /* my_close */
diff --git a/mysys/my_pread.c b/mysys/my_pread.c
new file mode 100644
index 00000000000..1190f2cc81b
--- /dev/null
+++ b/mysys/my_pread.c
@@ -0,0 +1,137 @@
+/* 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 "mysys_err.h"
+#include <errno.h>
+#ifdef HAVE_PREAD
+#include <unistd.h>
+#endif
+
+ /* Read a chunk of bytes from a file */
+
+uint my_pread(File Filedes, byte *Buffer, uint Count, my_off_t offset,
+ myf MyFlags)
+{
+ uint readbytes;
+ DBUG_ENTER("my_pread");
+ DBUG_PRINT("my",("Fd: %d Seek: %lu Buffer: %lx Count: %u MyFlags: %d",
+ Filedes, (ulong) offset, Buffer, Count, MyFlags));
+
+ for (;;)
+ {
+#ifndef __WIN__
+ errno=0; /* Linux doesn't reset this */
+#endif
+#ifndef HAVE_PREAD
+ readbytes= (uint) -1;
+ if (lseek(Filedes, offset, MY_SEEK_SET) == -1L ||
+ (readbytes = (uint) read(Filedes, Buffer, Count)) != Count)
+#else
+ if ((readbytes = (uint) pread(Filedes, Buffer, Count, offset)) != Count)
+#endif
+ {
+ my_errno=errno;
+ DBUG_PRINT("warning",("Read only %ld bytes off %ld from %d, errno: %d",
+ readbytes,Count,Filedes,my_errno));
+#ifdef THREAD
+ if (readbytes == 0 && errno == EINTR)
+ continue; /* Interrupted */
+#endif
+ if (MyFlags & (MY_WME | MY_FAE | MY_FNABP))
+ {
+ if ((int) readbytes == -1)
+ my_error(EE_READ, MYF(ME_BELL+ME_WAITTANG),
+ my_filename(Filedes),my_errno);
+ else if (MyFlags & (MY_NABP | MY_FNABP))
+ my_error(EE_EOFERR, MYF(ME_BELL+ME_WAITTANG),
+ my_filename(Filedes),my_errno);
+ }
+ if ((int) readbytes == -1 || (MyFlags & (MY_FNABP | MY_NABP)))
+ DBUG_RETURN(MY_FILE_ERROR); /* Return with error */
+ }
+ if (MyFlags & (MY_NABP | MY_FNABP))
+ DBUG_RETURN(0); /* Ok vid l{sning */
+ DBUG_RETURN(readbytes); /* purecov: inspected */
+ }
+} /* my_pread */
+
+
+ /* Write a chunk of bytes to a file */
+
+uint my_pwrite(int Filedes, const byte *Buffer, uint Count, my_off_t offset,
+ myf MyFlags)
+{
+ uint writenbytes,errors;
+ ulong written;
+ DBUG_ENTER("my_pwrite");
+ DBUG_PRINT("my",("Fd: %d Seek: %lu Buffer: %lx Count: %d MyFlags: %d",
+ Filedes, (ulong) offset,Buffer, Count, MyFlags));
+ errors=0; written=0L;
+
+ for (;;)
+ {
+#ifndef HAVE_PREAD
+ writenbytes= (uint) -1;
+ if (lseek(Filedes, offset, MY_SEEK_SET) != -1L &&
+ (writenbytes = (uint) write(Filedes, Buffer, Count)) == Count)
+#else
+ if ((writenbytes = (uint) pwrite(Filedes, Buffer, Count,offset)) == Count)
+#endif
+ break;
+ if ((int) writenbytes != -1)
+ { /* Safegueard */
+ written+=writenbytes;
+ Buffer+=writenbytes;
+ Count-=writenbytes;
+ offset+=writenbytes;
+ }
+ my_errno=errno;
+ DBUG_PRINT("error",("Write only %d bytes",writenbytes));
+#ifndef NO_BACKGROUND
+#ifdef THREAD
+ if (my_thread_var->abort)
+ MyFlags&= ~ MY_WAIT_IF_FULL; /* End if aborted by user */
+#endif
+ if (my_errno == ENOSPC && (MyFlags & MY_WAIT_IF_FULL))
+ {
+ if (!(errors++ % MY_WAIT_GIVE_USER_A_MESSAGE))
+ my_error(EE_DISK_FULL,MYF(ME_BELL | ME_NOREFRESH),
+ my_filename(Filedes));
+ VOID(sleep(MY_WAIT_FOR_USER_TO_FIX_PANIC));
+ continue;
+ }
+ if ((writenbytes == 0 && my_errno == EINTR) ||
+ (writenbytes > 0 && (uint) writenbytes != (uint) -1))
+ continue; /* Retry */
+#endif
+ if (MyFlags & (MY_NABP | MY_FNABP))
+ {
+ if (MyFlags & (MY_WME | MY_FAE | MY_FNABP))
+ {
+ my_error(EE_WRITE, MYF(ME_BELL+ME_WAITTANG),
+ my_filename(Filedes),my_errno);
+ }
+ DBUG_RETURN(MY_FILE_ERROR); /* Error on read */
+ }
+ else
+ break; /* Return bytes written */
+ }
+ if (MyFlags & (MY_NABP | MY_FNABP))
+ DBUG_RETURN(0); /* Want only errors */
+ DBUG_RETURN(writenbytes+written); /* purecov: inspected */
+} /* my_write */
diff --git a/mysys/my_pthread.c b/mysys/my_pthread.c
new file mode 100644
index 00000000000..4bf3e5e702a
--- /dev/null
+++ b/mysys/my_pthread.c
@@ -0,0 +1,476 @@
+/* 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 */
+
+/* Functions to get threads more portable */
+
+#include "mysys_priv.h"
+#ifdef THREAD
+#include <signal.h>
+#include <m_string.h>
+#include <thr_alarm.h>
+#include <assert.h>
+#if !defined(MSDOS) && !defined(__WIN__)
+#include <netdb.h>
+#endif
+
+#if (defined(__BSD__) || defined(_BSDI_VERSION)) && !defined(HAVE_mit_thread)
+#define SCHED_POLICY SCHED_RR
+#else
+#define SCHED_POLICY SCHED_OTHER
+#endif
+
+#ifndef my_pthread_setprio
+void my_pthread_setprio(pthread_t thread_id,int prior)
+{
+#ifdef HAVE_PTHREAD_SETSCHEDPARAM
+ struct sched_param tmp_sched_param;
+ bzero((char*) &tmp_sched_param,sizeof(tmp_sched_param));
+ tmp_sched_param.sched_priority=prior;
+ VOID(pthread_setschedparam(thread_id,SCHED_POLICY,&tmp_sched_param));
+#endif
+}
+#endif
+
+#ifndef my_pthread_getprio
+int my_pthread_getprio(pthread_t thread_id)
+{
+#ifdef HAVE_PTHREAD_SETSCHEDPARAM
+ struct sched_param tmp_sched_param;
+ int policy;
+ if (!pthread_getschedparam(thread_id,&policy,&tmp_sched_param))
+ {
+ DBUG_PRINT("thread",("policy: %d priority: %d",
+ policy,tmp_sched_param.sched_priority));
+ return tmp_sched_param.sched_priority;
+ }
+#endif
+ return -1;
+}
+#endif
+
+#ifndef my_pthread_attr_setprio
+void my_pthread_attr_setprio(pthread_attr_t *attr, int priority)
+{
+#ifdef HAVE_PTHREAD_SETSCHEDPARAM
+ struct sched_param tmp_sched_param;
+ bzero((char*) &tmp_sched_param,sizeof(tmp_sched_param));
+ tmp_sched_param.sched_priority=priority;
+ VOID(pthread_attr_setschedparam(attr,&tmp_sched_param));
+#endif
+}
+#endif
+
+
+/* To allow use of pthread_getspecific with two arguments */
+
+#ifdef HAVE_NONPOSIX_PTHREAD_GETSPECIFIC
+#undef pthread_getspecific
+#ifdef HAVE_UNIXWARE7_THREADS
+#define pthread_getspecific thr_getspecific
+#endif
+
+void *my_pthread_getspecific_imp(pthread_key_t key)
+{
+ void *value;
+ if (pthread_getspecific(key,(void *) &value))
+ return 0;
+ return value;
+}
+#endif
+
+
+/* Some functions for RTS threads, AIX, Siemens Unix and UnixWare 7
+ (and DEC OSF/1 3.2 too) */
+
+int my_pthread_create_detached=1;
+
+#if defined(HAVE_NONPOSIX_SIGWAIT) || defined(HAVE_DEC_3_2_THREADS)
+
+int my_sigwait(sigset_t *set,int *sig)
+{
+ int signal=sigwait(set);
+ if (signal < 0)
+ return errno;
+ *sig=signal;
+ return 0;
+}
+#endif
+
+/* localtime_r for SCO 3.2V4.2 */
+
+#ifndef HAVE_LOCALTIME_R
+
+extern pthread_mutex_t LOCK_localtime_r;
+
+struct tm *localtime_r(const time_t *clock, struct tm *res)
+{
+ struct tm *tmp;
+ pthread_mutex_lock(&LOCK_localtime_r);
+ tmp=localtime(clock);
+ *res= *tmp;
+ pthread_mutex_unlock(&LOCK_localtime_r);
+ return res;
+}
+#endif
+
+
+/****************************************************************************
+** Replacement of sigwait if the system doesn't have one (like BSDI 3.0)
+**
+** Note:
+** This version of sigwait() is assumed to called in a loop so the signalmask
+** is permanently modified to reflect the signal set. This is done to get
+** a much faster implementation.
+**
+** This implementation isn't thread safe: It assumes that only one
+** thread is using sigwait.
+**
+** If one later supplies a different signal mask, all old signals that
+** was used before are unblocked and set to SIGDFL.
+**
+** Author: Gary Wisniewski <garyw@spidereye.com.au>, much modified by Monty
+****************************************************************************/
+
+#if !defined(HAVE_SIGWAIT) && !defined(HAVE_mit_thread) && !defined(sigwait) && !defined(__WIN__) && !defined(HAVE_rts_threads) && !defined(HAVE_NONPOSIX_SIGWAIT) && !defined(HAVE_DEC_3_2_THREADS)
+
+#if !defined(DONT_USE_SIGSUSPEND)
+
+static sigset_t sigwait_set,rev_sigwait_set,px_recd;
+
+void px_handle_sig(int sig)
+{
+ sigaddset(&px_recd, sig);
+}
+
+
+void sigwait_setup(sigset_t *set)
+{
+ int i;
+ struct sigaction sact,sact1;
+ sigset_t unblock_mask;
+
+ sact.sa_flags = 0;
+ sact.sa_handler = px_handle_sig;
+ memcpy_fixed(&sact.sa_mask,set,sizeof(*set)); /* handler isn't thread_safe */
+ sigemptyset(&unblock_mask);
+ pthread_sigmask(SIG_UNBLOCK,(sigset_t*) 0,&rev_sigwait_set);
+
+ for (i = 1; i <= sizeof(sigwait_set)*8; i++)
+ {
+ if (sigismember(set,i))
+ {
+ sigdelset(&rev_sigwait_set,i);
+ if (!sigismember(&sigwait_set,i))
+ sigaction(i, &sact, (struct sigaction*) 0);
+ }
+ else
+ {
+ sigdelset(&px_recd,i); /* Don't handle this */
+ if (sigismember(&sigwait_set,i))
+ { /* Remove the old handler */
+ sigaddset(&unblock_mask,i);
+ sigdelset(&rev_sigwait_set,i);
+ sact1.sa_flags = 0;
+ sact1.sa_handler = SIG_DFL;
+ sigemptyset(&sact1.sa_mask);
+ sigaction(i, &sact1, 0);
+ }
+ }
+ }
+ memcpy_fixed(&sigwait_set,set,sizeof(*set));
+ pthread_sigmask(SIG_BLOCK,(sigset_t*) set,(sigset_t*) 0);
+ pthread_sigmask(SIG_UNBLOCK,&unblock_mask,(sigset_t*) 0);
+}
+
+
+int sigwait(sigset_t *setp, int *sigp)
+{
+ if (memcmp(setp,&sigwait_set,sizeof(sigwait_set)))
+ sigwait_setup(setp); /* Init or change of set */
+
+ for (;;)
+ {
+ /*
+ This is a fast, not 100% portable implementation to find the signal.
+ Because the handler is blocked there should be at most 1 bit set, but
+ the specification on this is somewhat shady so we use a set instead a
+ single variable.
+ */
+
+ ulong *ptr= (ulong*) &px_recd;
+ ulong *end=ptr+sizeof(px_recd)/sizeof(ulong);
+
+ for ( ; ptr != end ; ptr++)
+ {
+ if (*ptr)
+ {
+ ulong set= *ptr;
+ int found= (int) ((char*) ptr - (char*) &px_recd)*8+1;
+ while (!(set & 1))
+ {
+ found++;
+ set>>=1;
+ }
+ *sigp=found;
+ sigdelset(&px_recd,found);
+ return 0;
+ }
+ }
+ sigsuspend(&rev_sigwait_set);
+ }
+ return 0;
+}
+#else /* !DONT_USE_SIGSUSPEND */
+
+/****************************************************************************
+** Replacement of sigwait if the system doesn't have one (like BSDI 3.0)
+**
+** Note:
+** This version of sigwait() is assumed to called in a loop so the signalmask
+** is permanently modified to reflect the signal set. This is done to get
+** a much faster implementation.
+**
+** This implementation uses a extra thread to handle the signals and one
+** must always call sigwait() with the same signal mask!
+**
+** BSDI 3.0 NOTE:
+**
+** pthread_kill() doesn't work on a thread in a select() or sleep() loop?
+** After adding the sleep to sigwait_thread, all signals are checked and
+** delivered every second. This isn't that terrible performance vice, but
+** someone should report this to BSDI and ask for a fix!
+** Another problem is that when the sleep() ends, every select() in other
+** threads are interrupted!
+****************************************************************************/
+
+static sigset_t pending_set;
+static bool inited=0;
+static pthread_cond_t COND_sigwait;
+static pthread_mutex_t LOCK_sigwait;
+
+
+void sigwait_handle_sig(int sig)
+{
+ pthread_mutex_lock(&LOCK_sigwait);
+ sigaddset(&pending_set, sig);
+ VOID(pthread_cond_signal(&COND_sigwait)); /* inform sigwait() about signal */
+ pthread_mutex_unlock(&LOCK_sigwait);
+}
+
+extern pthread_t alarm_thread;
+
+void *sigwait_thread(void *set_arg)
+{
+ sigset_t *set=(sigset_t*) set_arg;
+
+ int i;
+ struct sigaction sact;
+ sact.sa_flags = 0;
+ sact.sa_handler = sigwait_handle_sig;
+ memcpy_fixed(&sact.sa_mask,set,sizeof(*set)); /* handler isn't thread_safe */
+ sigemptyset(&pending_set);
+
+ for (i = 1; i <= sizeof(pending_set)*8; i++)
+ {
+ if (sigismember(set,i))
+ {
+ sigaction(i, &sact, (struct sigaction*) 0);
+ }
+ }
+ sigaddset(set,THR_CLIENT_ALARM);
+ pthread_sigmask(SIG_UNBLOCK,(sigset_t*) set,(sigset_t*) 0);
+ alarm_thread=pthread_self(); /* For thr_alarm */
+
+ for (;;)
+ { /* Wait for signals */
+#ifdef HAVE_NOT_BROKEN_SELECT
+ fd_set fd;
+ FD_ZERO(&fd);
+ select(0,&fd,0,0,0);
+#else
+ sleep(1); /* Because of broken BSDI */
+#endif
+ }
+}
+
+
+int sigwait(sigset_t *setp, int *sigp)
+{
+ if (!inited)
+ {
+ pthread_attr_t thr_attr;
+ pthread_t sigwait_thread_id;
+ inited=1;
+ sigemptyset(&pending_set);
+ pthread_mutex_init(&LOCK_sigwait,NULL);
+ pthread_cond_init(&COND_sigwait,NULL);
+
+ pthread_attr_init(&thr_attr);
+ pthread_attr_setscope(&thr_attr,PTHREAD_SCOPE_PROCESS);
+ pthread_attr_setdetachstate(&thr_attr,PTHREAD_CREATE_DETACHED);
+ pthread_attr_setstacksize(&thr_attr,8196);
+ my_pthread_attr_setprio(&thr_attr,100); /* Very high priority */
+ VOID(pthread_create(&sigwait_thread_id,&thr_attr,sigwait_thread,setp));
+ VOID(pthread_attr_destroy(&thr_attr));
+ }
+
+ pthread_mutex_lock(&LOCK_sigwait);
+ for (;;)
+ {
+ ulong *ptr= (ulong*) &pending_set;
+ ulong *end=ptr+sizeof(pending_set)/sizeof(ulong);
+
+ for ( ; ptr != end ; ptr++)
+ {
+ if (*ptr)
+ {
+ ulong set= *ptr;
+ int found= (int) ((char*) ptr - (char*) &pending_set)*8+1;
+ while (!(set & 1))
+ {
+ found++;
+ set>>=1;
+ }
+ *sigp=found;
+ sigdelset(&pending_set,found);
+ pthread_mutex_unlock(&LOCK_sigwait);
+ return 0;
+ }
+ }
+ VOID(pthread_cond_wait(&COND_sigwait,&LOCK_sigwait));
+ }
+ return 0;
+}
+
+#endif /* DONT_USE_SIGSUSPEND */
+#endif /* HAVE_SIGWAIT */
+
+/*****************************************************************************
+** Implement pthread_signal for systems that can't use signal() with threads
+** Currently this is only used with BSDI 3.0
+*****************************************************************************/
+
+#ifdef USE_PTHREAD_SIGNAL
+
+int pthread_signal(int sig, void (*func)())
+{
+ struct sigaction sact;
+ sact.sa_flags= 0;
+ sact.sa_handler= func;
+ sigemptyset(&sact.sa_mask);
+ sigaction(sig, &sact, (struct sigaction*) 0);
+ return 0;
+}
+
+#endif
+
+/*****************************************************************************
+** Patches for AIX and DEC OSF/1 3.2
+*****************************************************************************/
+
+#if (defined(HAVE_NONPOSIX_PTHREAD_MUTEX_INIT) && !defined(HAVE_UNIXWARE7_THREADS)) || defined(HAVE_DEC_3_2_THREADS)
+#undef pthread_mutex_init
+#undef pthread_cond_init
+
+#include <netdb.h>
+
+int my_pthread_mutex_init(pthread_mutex_t *mp, const pthread_mutexattr_t *attr)
+{
+ int error;
+ if (!attr)
+ error=pthread_mutex_init(mp,pthread_mutexattr_default);
+ else
+ error=pthread_mutex_init(mp,*attr);
+ return error;
+}
+
+int my_pthread_cond_init(pthread_cond_t *mp, const pthread_condattr_t *attr)
+{
+ int error;
+ if (!attr)
+ error=pthread_cond_init(mp,pthread_condattr_default);
+ else
+ error=pthread_cond_init(mp,*attr);
+ return error;
+}
+
+#endif
+
+/*
+** Emulate SOLARIS style calls, not because it's better, but just to make the
+** usage of getbostbyname_r simpler.
+*/
+
+#if !defined(my_gethostbyname_r) && defined(HAVE_GETHOSTBYNAME_R)
+
+#if defined(HAVE_GLIBC2_STYLE_GETHOSTBYNAME_R)
+
+struct hostent *my_gethostbyname_r(const char *name,
+ struct hostent *result, char *buffer,
+ int buflen, int *h_errnop)
+{
+ struct hostent *hp;
+ assert((size_t) buflen >= sizeof(*result));
+ if (gethostbyname_r(name,result, buffer, (size_t) buflen, &hp, h_errnop))
+ return 0;
+ return hp;
+}
+
+#elif defined(_HPUX_SOURCE) || (defined(_AIX) && !defined(_AIX32_THREADS))
+
+struct hostent *my_gethostbyname_r(const char *name,
+ struct hostent *result, char *buffer,
+ int buflen, int *h_errnop)
+{
+ assert(buflen >= sizeof(struct hostent_data));
+ if (gethostbyname_r(name,result,(struct hostent_data *) buffer) == -1)
+ {
+ *h_errnop= errno;
+ return 0;
+ }
+ return result;
+}
+
+#else
+
+struct hostent *my_gethostbyname_r(const char *name,
+ struct hostent *result, char *buffer,
+ int buflen, int *h_errnop)
+{
+ struct hostent *hp;
+ assert(buflen >= sizeof(struct hostent_data));
+ hp= gethostbyname_r(name,result,(struct hostent_data *) buffer);
+ *h_errnop= errno;
+ return hp;
+}
+
+#endif /* GLIBC2_STYLE_GETHOSTBYNAME_R */
+#endif
+
+
+/* Some help functions */
+
+int pthread_no_free(void *not_used __attribute__((unused)))
+{
+ return 0;
+}
+
+int pthread_dummy(int ret)
+{
+ return ret;
+}
+#endif /* THREAD */
diff --git a/mysys/my_quick.c b/mysys/my_quick.c
new file mode 100644
index 00000000000..6151d5037ae
--- /dev/null
+++ b/mysys/my_quick.c
@@ -0,0 +1,45 @@
+/* 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 */
+
+/* Quicker interface to read & write. Used with my_nosys.h */
+
+#include "mysys_priv.h"
+#include "my_nosys.h"
+
+
+uint my_quick_read(File Filedes,byte *Buffer,uint Count,myf MyFlags)
+{
+ uint readbytes;
+
+ if ((readbytes = (uint) read(Filedes, Buffer, Count)) != Count)
+ {
+ my_errno=errno;
+ return readbytes;
+ }
+ return (MyFlags & (MY_NABP | MY_FNABP)) ? 0 : readbytes;
+}
+
+
+uint my_quick_write(File Filedes,const byte *Buffer,uint Count)
+{
+ if ((uint) write(Filedes,Buffer,Count) != Count)
+ {
+ my_errno=errno;
+ return (uint) -1;
+ }
+ return 0;
+}
diff --git a/mysys/my_read.c b/mysys/my_read.c
new file mode 100644
index 00000000000..b317630f4bd
--- /dev/null
+++ b/mysys/my_read.c
@@ -0,0 +1,66 @@
+/* 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 "mysys_err.h"
+#include <errno.h>
+
+
+ /* Read a chunk of bytes from a file */
+
+uint my_read(File Filedes, byte *Buffer, uint Count, myf MyFlags)
+ /* File descriptor */
+ /* Buffer must be at least count bytes */
+ /* Max number of bytes returnd */
+ /* Flags on what to do on error */
+{
+ uint readbytes;
+ DBUG_ENTER("my_read");
+ DBUG_PRINT("my",("Fd: %d Buffer: %lx Count: %u MyFlags: %d",
+ Filedes, Buffer, Count, MyFlags));
+
+ for (;;)
+ {
+ errno=0; /* Linux doesn't reset this */
+ if ((readbytes = (uint) read(Filedes, Buffer, Count)) != Count)
+ {
+ my_errno=errno ? errno : -1;
+ DBUG_PRINT("warning",("Read only %ld bytes off %ld from %d, errno: %d",
+ readbytes,Count,Filedes,my_errno));
+#ifdef THREAD
+ if (readbytes == 0 && errno == EINTR)
+ continue; /* Interrupted */
+#endif
+ if (MyFlags & (MY_WME | MY_FAE | MY_FNABP))
+ {
+ if ((int) readbytes == -1)
+ my_error(EE_READ, MYF(ME_BELL+ME_WAITTANG),
+ my_filename(Filedes),my_errno);
+ else if (MyFlags & (MY_NABP | MY_FNABP))
+ my_error(EE_EOFERR, MYF(ME_BELL+ME_WAITTANG),
+ my_filename(Filedes),my_errno);
+ }
+ if ((int) readbytes == -1 || (MyFlags & (MY_FNABP | MY_NABP)))
+ DBUG_RETURN(MY_FILE_ERROR); /* Return with error */
+ }
+
+ if (MyFlags & (MY_NABP | MY_FNABP))
+ readbytes=0; /* Ok on read */
+ break;
+ }
+ DBUG_RETURN(readbytes);
+} /* my_read */
diff --git a/mysys/my_realloc.c b/mysys/my_realloc.c
new file mode 100644
index 00000000000..c9d8edd6ddf
--- /dev/null
+++ b/mysys/my_realloc.c
@@ -0,0 +1,65 @@
+/* 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 */
+
+#ifdef SAFEMALLOC /* We don't need SAFEMALLOC here */
+#undef SAFEMALLOC
+#endif
+
+#include "mysys_priv.h"
+#include "mysys_err.h"
+
+ /* My memory re allocator */
+
+gptr my_realloc(gptr oldpoint, uint Size, myf MyFlags)
+{
+ gptr point;
+ DBUG_ENTER("my_realloc");
+ DBUG_PRINT("my",("ptr: %lx Size: %u MyFlags: %d",oldpoint, Size, MyFlags));
+
+ if (!oldpoint && (MyFlags & MY_ALLOW_ZERO_PTR))
+ DBUG_RETURN(my_malloc(Size,MyFlags));
+#ifdef USE_HALLOC
+ if (!(point = malloc(Size)))
+ {
+ if (MyFlags & MY_FREE_ON_ERROR)
+ my_free(oldpoint,MyFlags);
+ if (MyFlags & MY_HOLD_ON_ERROR)
+ DBUG_RETURN(oldpoint);
+ my_errno=errno;
+ if (MyFlags & MY_FAE+MY_WME)
+ my_error(EE_OUTOFMEMORY, MYF(ME_BELL+ME_WAITTANG),Size);
+ }
+ else
+ {
+ memcpy(point,oldpoint,Size);
+ free(oldpoint);
+ }
+#else
+ if ((point = realloc(oldpoint,Size)) == NULL)
+ {
+ if (MyFlags & MY_FREE_ON_ERROR)
+ my_free(oldpoint,MyFLAGS);
+ if (MyFlags & MY_HOLD_ON_ERROR)
+ DBUG_RETURN(oldpoint);
+ my_errno=errno;
+ if (MyFlags & (MY_FAE+MY_WME))
+ my_error(EE_OUTOFMEMORY, MYF(ME_BELL+ME_WAITTANG), Size);
+ }
+#endif
+ DBUG_PRINT("exit",("ptr: %lx",point));
+ DBUG_RETURN(point);
+} /* my_realloc */
diff --git a/mysys/my_redel.c b/mysys/my_redel.c
new file mode 100644
index 00000000000..da03b026c9f
--- /dev/null
+++ b/mysys/my_redel.c
@@ -0,0 +1,98 @@
+/* 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 */
+
+#define USES_TYPES /* sys/types is included */
+#include "mysys_priv.h"
+#include <my_dir.h>
+#include "mysys_err.h"
+#if defined(HAVE_SYS_UTIME_H)
+#include <sys/utime.h>
+#elif defined(HAVE_UTIME_H)
+#include <utime.h>
+#elif !defined(HPUX)
+struct utimbuf {
+ time_t actime;
+ time_t modtime;
+};
+#endif
+
+ /* Rename with copy stat form old file */
+ /* Copy stats from old file to new file, deletes orginal and */
+ /* changes new file name to old file name */
+
+int my_redel(const char *org_name, const char *tmp_name, myf MyFlags)
+{
+ DBUG_ENTER("my_redel");
+ DBUG_PRINT("my",("org_name: '%s' tmp_name: '%s' MyFlags: %d",
+ org_name,tmp_name,MyFlags));
+
+ if (my_copystat(org_name,tmp_name,MyFlags) < 0 ||
+ my_delete(org_name,MyFlags) ||
+ my_rename(tmp_name,org_name,MyFlags))
+ DBUG_RETURN(1);
+ DBUG_RETURN(0);
+} /* my_redel */
+
+
+ /* Copy stat from one file to another */
+ /* Return -1 if can't get stat, 1 if wrong type of file */
+
+int my_copystat(const char *from, const char *to, int MyFlags)
+{
+ struct stat statbuf;
+
+ if (stat((char*) from, &statbuf))
+ {
+ my_errno=errno;
+ if (MyFlags & (MY_FAE+MY_WME))
+ my_error(EE_STAT, MYF(ME_BELL+ME_WAITTANG),from,errno);
+ return -1; /* Can't get stat on input file */
+ }
+ if ((statbuf.st_mode & S_IFMT) != S_IFREG)
+ return 1;
+ VOID(chmod(to, statbuf.st_mode & 07777)); /* Copy modes */
+
+#if !defined(MSDOS) && !defined(__WIN__) && !defined(__EMX__)
+ if (statbuf.st_nlink > 1 && MyFlags & MY_LINK_WARNING)
+ {
+ if (MyFlags & MY_LINK_WARNING)
+ my_error(EE_LINK_WARNING,MYF(ME_BELL+ME_WAITTANG),from,statbuf.st_nlink);
+ }
+ VOID(chown(to, statbuf.st_uid, statbuf.st_gid)); /* Copy ownership */
+#endif /* MSDOS */
+
+#ifndef VMS
+#ifndef __ZTC__
+ if (MyFlags & MY_COPYTIME)
+ {
+ struct utimbuf timep;
+ timep.actime = statbuf.st_atime;
+ timep.modtime = statbuf.st_mtime;
+ VOID(utime((char*) to, &timep));/* Update last accessed and modified times */
+ }
+#else
+ if (MyFlags & MY_COPYTIME)
+ {
+ time_t time[2];
+ time[0]= statbuf.st_atime;
+ time[1]= statbuf.st_mtime;
+ VOID(utime((char*) to, time));/* Update last accessed and modified times */
+ }
+#endif
+#endif
+ return 0;
+} /* my_copystat */
diff --git a/mysys/my_rename.c b/mysys/my_rename.c
new file mode 100644
index 00000000000..ea895ffcf76
--- /dev/null
+++ b/mysys/my_rename.c
@@ -0,0 +1,60 @@
+/* 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 */
+
+#define USES_TYPES
+#include "mysys_priv.h"
+#include <my_dir.h>
+#include "mysys_err.h"
+
+#undef my_rename
+ /* On unix rename deletes to file if it exists */
+
+int my_rename(const char *from, const char *to, myf MyFlags)
+{
+ int error = 0;
+ DBUG_ENTER("my_rename");
+ DBUG_PRINT("my",("from %s to %s MyFlags %d", from, to, MyFlags));
+
+#if defined(HAVE_FILE_VERSIONS)
+ { /* Check that there isn't a old file */
+ int save_errno;
+ MY_STAT my_stat_result;
+ save_errno=my_errno;
+ if (my_stat(to,&my_stat_result,MYF(0)))
+ {
+ my_errno=EEXIST;
+ error= -1;
+ if (MyFlags & MY_FAE+MY_WME)
+ my_error(EE_LINK, MYF(ME_BELL+ME_WAITTANG),from,to,my_errno);
+ DBUG_RETURN(error);
+ }
+ my_errno=save_errno;
+ }
+#endif
+#if defined(HAVE_RENAME)
+ if (rename(from,to))
+#else
+ if (link(from, to) || unlink(from))
+#endif
+ {
+ my_errno=errno;
+ error = -1;
+ if (MyFlags & (MY_FAE+MY_WME))
+ my_error(EE_LINK, MYF(ME_BELL+ME_WAITTANG),from,to,my_errno);
+ }
+ DBUG_RETURN(error);
+} /* my_rename */
diff --git a/mysys/my_seek.c b/mysys/my_seek.c
new file mode 100644
index 00000000000..12f8ced0642
--- /dev/null
+++ b/mysys/my_seek.c
@@ -0,0 +1,57 @@
+/* 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"
+
+ /* Seek to position in file */
+ /*ARGSUSED*/
+
+my_off_t my_seek(File fd, my_off_t pos, int whence, myf MyFlags)
+{
+ reg1 os_off_t newpos;
+ DBUG_ENTER("my_seek");
+ DBUG_PRINT("my",("Fd: %d Pos: %lu Whence: %d MyFlags: %d",
+ fd, (ulong) pos, whence, MyFlags));
+ newpos=lseek(fd, pos, whence);
+ if (newpos == (os_off_t) -1)
+ {
+ my_errno=errno;
+ DBUG_PRINT("error",("lseek: %lu, errno: %d",newpos,errno));
+ DBUG_RETURN(MY_FILEPOS_ERROR);
+ }
+ DBUG_RETURN((my_off_t) newpos);
+} /* my_seek */
+
+
+ /* Tell current position of file */
+ /* ARGSUSED */
+
+my_off_t my_tell(File fd, myf MyFlags)
+{
+ os_off_t pos;
+ DBUG_ENTER("my_tell");
+ DBUG_PRINT("my",("Fd: %d MyFlags: %d",fd, MyFlags));
+#ifdef HAVE_TELL
+ pos=tell(fd);
+#else
+ pos=lseek(fd, 0L, MY_SEEK_CUR);
+#endif
+ if (pos == (os_off_t) -1)
+ my_errno=errno;
+ DBUG_PRINT("exit",("pos: %lu",pos));
+ DBUG_RETURN((my_off_t) pos);
+} /* my_tell */
diff --git a/mysys/my_static.c b/mysys/my_static.c
new file mode 100644
index 00000000000..db942d96db9
--- /dev/null
+++ b/mysys/my_static.c
@@ -0,0 +1,100 @@
+/* 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 */
+
+/*
+ Static variables for mysys library. All definied here for easy making of
+ a shared library
+*/
+
+#ifndef stdin
+#include "mysys_priv.h"
+#include "my_static.h"
+#include "my_alarm.h"
+#endif
+
+ /* from my_init */
+my_string home_dir=0,my_progname=0;
+char NEAR curr_dir[FN_REFLEN]= {0},
+ NEAR home_dir_buff[FN_REFLEN]= {0};
+uint my_stream_opened=0,my_file_opened=0;
+int NEAR my_umask=0664, NEAR my_umask_dir=0777;
+#ifndef THREAD
+int NEAR my_errno=0;
+#endif
+struct my_file_info my_file_info[MY_NFILE]= {{0,UNOPEN}};
+
+ /* From mf_brkhant */
+int NEAR my_dont_interrupt=0;
+volatile int _my_signals=0;
+struct st_remember _my_sig_remember[MAX_SIGNALS]={{0,0}};
+#ifdef THREAD
+sigset_t my_signals; /* signals blocked by mf_brkhant */
+#endif
+
+ /* from mf_keycache.c */
+my_bool key_cache_inited=0;
+
+ /* from mf_reccache.c */
+ulong my_default_record_cache_size=RECORD_CACHE_SIZE;
+
+ /* from soundex.c */
+ /* ABCDEFGHIJKLMNOPQRSTUVWXYZ */
+ /* :::::::::::::::::::::::::: */
+const char *soundex_map= "01230120022455012623010202";
+
+ /* from my_malloc */
+USED_MEM* my_once_root_block=0; /* pointer to first block */
+uint my_once_extra=ONCE_ALLOC_INIT; /* Memory to alloc / block */
+
+ /* from my_tempnam */
+#ifndef HAVE_TEMPNAM
+int _my_tempnam_used=0;
+#endif
+
+ /* from safe_malloc */
+uint sf_malloc_prehunc=0, /* If you have problem with core- */
+ sf_malloc_endhunc=0, /* dump when malloc-message.... */
+ /* set theese to 64 or 128 */
+ sf_malloc_quick=0; /* set if no calls to sanity */
+long lCurMemory = 0L; /* Current memory usage */
+long lMaxMemory = 0L; /* Maximum memory usage */
+uint cNewCount = 0; /* Number of times NEW() was called */
+byte *sf_min_adress= (byte*) ~(unsigned long) 0L,
+ *sf_max_adress= (byte*) 0L;
+
+/* Root of the linked list of remembers */
+struct remember *pRememberRoot = NULL;
+
+ /* from my_alarm */
+int volatile my_have_got_alarm=0; /* declare variable to reset */
+ulong my_time_to_wait_for_lock=2; /* In seconds */
+
+ /* from errors.c */
+#ifdef SHARED_LIBRARY
+char * NEAR globerrs[GLOBERRS]; /* my_error_messages is here */
+#endif
+void (*my_abort_hook)(int) = (void(*)(int)) exit;
+int (*error_handler_hook)(uint error,const char *str,myf MyFlags)=
+ my_message_no_curses;
+int (*fatal_error_handler_hook)(uint error,const char *str,myf MyFlags)=
+ my_message_no_curses;
+
+ /* How to disable options */
+my_bool NEAR my_disable_locking=0;
+my_bool NEAR my_disable_async_io=0;
+my_bool NEAR my_disable_flush_key_blocks=0;
+my_bool NEAR mysys_uses_curses=0;
diff --git a/mysys/my_static.h b/mysys/my_static.h
new file mode 100644
index 00000000000..dd80a8da1f9
--- /dev/null
+++ b/mysys/my_static.h
@@ -0,0 +1,82 @@
+/* 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 */
+
+/*
+ Static variables for mysys library. All definied here for easy making of
+ a shared library
+*/
+
+#include "mysys_priv.h"
+#include <signal.h>
+
+#define MAX_SIGNALS 10 /* Max signals under a dont-allow */
+#define MIN_KEYBLOCK (min(IO_SIZE,1024))
+#define MAX_KEYBLOCK 8192 /* Max keyblocklength == 8*IO_SIZE */
+#define MAX_BLOCK_TYPES MAX_KEYBLOCK/MIN_KEYBLOCK
+
+struct st_remember {
+ int number;
+ sig_handler (*func)(int number);
+};
+
+typedef struct sec_link {
+ struct sec_link *next_hash,**prev_hash;/* Blocks linked acc. to hash-value */
+ struct sec_link *next_used,*prev_used;
+ struct sec_link *next_changed,**prev_changed;
+ File file;
+ my_off_t diskpos;
+ byte *buffer;
+ my_bool changed;
+} SEC_LINK;
+
+struct irem {
+ struct remember *_pNext; /* Linked list of structures */
+ struct remember *_pPrev; /* Other link */
+ my_string _sFileName; /* File in which memory was new'ed */
+ uint _uLineNum; /* Line number in above file */
+ uint _uDataSize; /* Size requested */
+ long _lSpecialValue; /* Underrun marker value */
+};
+
+struct remember {
+ struct irem tInt;
+ char aData[1];
+};
+
+extern char NEAR curr_dir[FN_REFLEN],NEAR home_dir_buff[FN_REFLEN];
+
+extern volatile int _my_signals;
+extern struct st_remember _my_sig_remember[MAX_SIGNALS];
+
+extern my_bool key_cache_inited;
+
+extern const char *soundex_map;
+
+extern USED_MEM* my_once_root_block;
+extern uint my_once_extra;
+
+#ifndef HAVE_TEMPNAM
+extern int _my_tempnam_used;
+#endif
+
+extern byte *sf_min_adress,*sf_max_adress;
+extern uint cNewCount;
+extern struct remember *pRememberRoot;
+
+#if defined(THREAD) && !defined(__WIN__)
+extern sigset_t my_signals; /* signals blocked by mf_brkhant */
+#endif
diff --git a/mysys/my_tempnam.c b/mysys/my_tempnam.c
new file mode 100644
index 00000000000..7e5b953fe53
--- /dev/null
+++ b/mysys/my_tempnam.c
@@ -0,0 +1,142 @@
+/* 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>
+#include "my_static.h"
+#include "mysys_err.h"
+
+#define TMP_EXT ".tmp" /* Extension of tempfile */
+#if ! defined(P_tmpdir)
+#define P_tmpdir ""
+#endif
+
+#ifdef HAVE_TEMPNAM
+#ifndef MSDOS
+extern char **environ;
+#endif
+#endif
+
+/* 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 8 length-string and
+ TMP_EXT after pfx.
+ Returns pointer to malloced area for filename. Should be freed by
+ free().
+ The name should be uniq, but it isn't checked if it file allready exists.
+ Uses tempnam() if function exist on system.
+ This function fixes that if dir is given it's used. For example
+ MSDOS tempnam() uses always TMP environment-variable if it exists.
+*/
+ /* ARGSUSED */
+
+my_string my_tempnam(const char *dir, const char *pfx,
+ myf MyFlags __attribute__((unused)))
+{
+#ifdef _MSC_VER
+ char temp[FN_REFLEN],*end,*res,**old_env,*temp_env[1];
+ old_env=environ;
+ if (dir)
+ {
+ end=strend(dir)-1;
+ if (!dir[0])
+ { /* Change empty string to current dir */
+ temp[0]= FN_CURLIB;
+ temp[1]= 0;
+ dir=temp;
+ }
+ else if (*end == FN_DEVCHAR)
+ { /* Get current dir for drive */
+ _fullpath(temp,dir,FN_REFLEN);
+ dir=temp;
+ }
+ else if (*end == FN_LIBCHAR && dir < end && end[-1] != FN_DEVCHAR)
+ {
+ strmake(temp,dir,(uint) (end-dir)); /* Copy and remove last '\' */
+ dir=temp;
+ }
+ environ=temp_env; /* Force use of dir (dir not checked) */
+ temp_env[0]=0;
+ }
+ res=tempnam((char*) dir,(my_string) pfx);
+ environ=old_env;
+ return res;
+#else
+#ifdef __ZTC__
+ if (!dir)
+ { /* If empty test first if TMP can be used */
+ dir=getenv("TMP");
+ }
+ return tempnam((char*) dir,(my_string) pfx); /* Use stand. dir with prefix */
+#else
+#ifdef HAVE_TEMPNAM
+ char temp[2],*res,**old_env,*temp_env[1];
+
+ if (dir && !dir[0])
+ { /* Change empty string to current dir */
+ temp[0]= FN_CURLIB;
+ temp[1]= 0;
+ dir=temp;
+ }
+ old_env=environ;
+ if (dir)
+ { /* Don't use TMPDIR if dir is given */
+ environ=temp_env;
+ temp_env[0]=0;
+ }
+ res=tempnam((char*) dir,(my_string) pfx); /* Use stand. dir with prefix */
+ environ=old_env;
+ if (!res)
+ DBUG_PRINT("error",("Got error: %d from tempnam",errno));
+ return res;
+#else
+ register long uniq;
+ register int length;
+ my_string pos,end_pos;
+ DBUG_ENTER("my_tempnam");
+ /* Make a uniq nummber */
+ pthread_mutex_lock(&THR_LOCK_open);
+ uniq= ((long) getpid() << 20) + (long) _my_tempnam_used++ ;
+ pthread_mutex_unlock(&THR_LOCK_open);
+ if (!dir && !(dir=getenv("TMPDIR"))) /* Use this if possibly */
+ dir=P_tmpdir; /* Use system default */
+ length=strlen(dir)+strlen(pfx)+1;
+
+ DBUG_PRINT("test",("mallocing %d byte",length+8+sizeof(TMP_EXT)+1));
+ if (!(pos=(char*) malloc(length+8+sizeof(TMP_EXT)+1)))
+ {
+ if (MyFlags & MY_FAE+MY_WME)
+ my_error(EE_OUTOFMEMORY, MYF(ME_BELL+ME_WAITTANG),
+ length+8+sizeof(TMP_EXT)+1);
+ DBUG_RETURN(NullS);
+ }
+ end_pos=strmov(pos,dir);
+ if (end_pos != pos && 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)];
+ uniq >>= 5;
+ }
+ VOID(strmov(end_pos,TMP_EXT));
+ DBUG_PRINT("exit",("tempnam: '%s'",pos));
+ DBUG_RETURN(pos);
+#endif /* HAVE_TEMPNAM */
+#endif /* __ZTC__ */
+#endif /* _MSC_VER */
+} /* my_tempnam */
diff --git a/mysys/my_thr_init.c b/mysys/my_thr_init.c
new file mode 100644
index 00000000000..d879da8e65d
--- /dev/null
+++ b/mysys/my_thr_init.c
@@ -0,0 +1,194 @@
+/* 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 */
+
+/*
+** Functions to handle initializating and allocationg of all mysys & debug
+** thread variables.
+*/
+
+#include "mysys_priv.h"
+#include <m_string.h>
+
+#ifdef THREAD
+#ifdef USE_TLS
+pthread_key(struct st_my_thread_var*, THR_KEY_mysys);
+#else
+pthread_key(struct st_my_thread_var, THR_KEY_mysys);
+#endif
+pthread_mutex_t THR_LOCK_malloc,THR_LOCK_open,THR_LOCK_keycache,
+ THR_LOCK_lock,THR_LOCK_isam,THR_LOCK_myisam,THR_LOCK_heap,
+ THR_LOCK_net, THR_LOCK_charset;
+#ifndef HAVE_LOCALTIME_R
+pthread_mutex_t LOCK_localtime_r;
+#endif
+#ifdef __WIN__
+pthread_mutex_t THR_LOCK_thread;
+#endif
+
+/* FIXME Note. TlsAlloc does not set an auto destructor, so
+ the function my_thread_global_free must be called from
+ somewhere before final exit of the library */
+
+my_bool my_thread_global_init(void)
+{
+ if (pthread_key_create(&THR_KEY_mysys,free))
+ {
+ fprintf(stderr,"Can't initialize threads: error %d\n",errno);
+ exit(1);
+ }
+ pthread_mutex_init(&THR_LOCK_malloc,NULL);
+ pthread_mutex_init(&THR_LOCK_open,NULL);
+ pthread_mutex_init(&THR_LOCK_keycache,NULL);
+ pthread_mutex_init(&THR_LOCK_lock,NULL);
+ pthread_mutex_init(&THR_LOCK_isam,NULL);
+ pthread_mutex_init(&THR_LOCK_myisam,NULL);
+ pthread_mutex_init(&THR_LOCK_heap,NULL);
+ pthread_mutex_init(&THR_LOCK_net,NULL);
+ pthread_mutex_init(&THR_LOCK_charset,NULL);
+#ifdef __WIN__
+ pthread_mutex_init(&THR_LOCK_thread,NULL);
+#endif
+#ifndef HAVE_LOCALTIME_R
+ pthread_mutex_init(&LOCK_localtime_r,NULL);
+#endif
+ return my_thread_init();
+}
+
+void my_thread_global_end(void)
+{
+#if defined(USE_TLS)
+ (void) TlsFree(THR_KEY_mysys);
+#endif
+}
+
+static long thread_id=0;
+
+my_bool my_thread_init(void)
+{
+ struct st_my_thread_var *tmp;
+ pthread_mutex_lock(&THR_LOCK_lock);
+#if !defined(__WIN__) || defined(USE_TLS)
+ if (my_pthread_getspecific(struct st_my_thread_var *,THR_KEY_mysys))
+ {
+ pthread_mutex_unlock(&THR_LOCK_lock);
+ return 0; /* Safequard */
+ }
+ /* We must have many calloc() here because these are freed on
+ pthread_exit */
+ if (!(tmp=(struct st_my_thread_var *)
+ calloc(1,sizeof(struct st_my_thread_var))))
+ {
+ pthread_mutex_unlock(&THR_LOCK_lock);
+ return 1;
+ }
+ pthread_setspecific(THR_KEY_mysys,tmp);
+
+#else
+ if (THR_KEY_mysys.id) /* Allready initialized */
+ {
+ pthread_mutex_unlock(&THR_LOCK_lock);
+ return 0;
+ }
+ tmp= &THR_KEY_mysys;
+#endif
+ tmp->id= ++thread_id;
+ pthread_mutex_init(&tmp->mutex,NULL);
+ pthread_cond_init(&tmp->suspend, NULL);
+ pthread_mutex_unlock(&THR_LOCK_lock);
+ return 0;
+}
+
+void my_thread_end(void)
+{
+ struct st_my_thread_var *tmp=my_thread_var;
+ if (tmp)
+ {
+#if !defined(DBUG_OFF)
+ if (tmp->dbug)
+ {
+ free(tmp->dbug);
+ tmp->dbug=0;
+ }
+#endif
+#if !defined(__bsdi__) || defined(HAVE_mit_thread) /* bsdi dumps core here */
+ pthread_cond_destroy(&tmp->suspend);
+#endif
+ pthread_mutex_destroy(&tmp->mutex);
+#if !defined(__WIN__) || defined(USE_TLS)
+ free(tmp);
+#endif
+ }
+#if !defined(__WIN__) || defined(USE_TLS)
+ pthread_setspecific(THR_KEY_mysys,0);
+#endif
+}
+
+struct st_my_thread_var *_my_thread_var(void)
+{
+ struct st_my_thread_var *tmp=
+ my_pthread_getspecific(struct st_my_thread_var*,THR_KEY_mysys);
+#if defined(USE_TLS)
+ /* This can only happen in a .DLL */
+ if (!tmp)
+ {
+ my_thread_init();
+ tmp=my_pthread_getspecific(struct st_my_thread_var*,THR_KEY_mysys);
+ }
+#endif
+ return tmp;
+}
+
+/****************************************************************************
+** Get name of current thread.
+****************************************************************************/
+
+#define UNKNOWN_THREAD -1
+
+long my_thread_id()
+{
+#if defined(HAVE_PTHREAD_GETSEQUENCE_NP)
+ return pthread_getsequence_np(pthread_self());
+#elif (defined(__sun) || defined(__sgi) || defined(__linux__)) && !defined(HAVE_mit_thread)
+ return pthread_self();
+#else
+ return my_thread_var->id;
+#endif
+}
+
+#ifdef DBUG_OFF
+char *my_thread_name(void)
+{
+ return "no_name";
+}
+
+#else
+
+char *my_thread_name(void)
+{
+ char name_buff[100];
+ struct st_my_thread_var *tmp=my_thread_var;
+ if (!tmp->name[0])
+ {
+ long id=my_thread_id();
+ sprintf(name_buff,"T@%ld", id);
+ strmake(tmp->name,name_buff,THREAD_NAME_SIZE);
+ }
+ return tmp->name;
+}
+#endif /* DBUG_OFF */
+
+#endif /* THREAD */
diff --git a/mysys/my_vsnprintf.c b/mysys/my_vsnprintf.c
new file mode 100644
index 00000000000..63730926156
--- /dev/null
+++ b/mysys/my_vsnprintf.c
@@ -0,0 +1,94 @@
+/* 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 "mysys_err.h"
+#include <m_string.h>
+#include <stdarg.h>
+#include <m_ctype.h>
+
+
+
+int my_vsnprintf(char* str, size_t n, const char* fmt, va_list ap)
+{
+ uint olen = 0, plen;
+ const char *tpos;
+ reg1 char *endpos;
+ reg2 char * par;
+ char* ebuff = str;
+
+ endpos=ebuff;
+ tpos = fmt;
+
+ while (*tpos)
+ {
+ if (tpos[0] != '%')
+ {
+ if(olen + 1 >= n)
+ break;
+
+ *endpos++= *tpos++; /* Copy ordinary char */
+ olen++;
+ continue;
+ }
+ if (*++tpos == '%') /* test if %% */
+ {
+ olen--;
+ }
+ else
+ {
+ /* Skipp if max size is used (to be compatible with printf) */
+ while (isdigit(*tpos) || *tpos == '.' || *tpos == '-')
+ tpos++;
+ if (*tpos == 's') /* String parameter */
+ {
+ par = va_arg(ap, char *);
+ plen = (uint) strlen(par);
+ if (olen + plen < n) /* Replace if possible */
+ {
+ endpos=strmov(endpos,par);
+ tpos++;
+ olen+=plen;
+ continue;
+ }
+ }
+ else if (*tpos == 'd' || *tpos == 'u') /* Integer parameter */
+ {
+ register int iarg;
+ iarg = va_arg(ap, int);
+ if(olen + 16 >= n) break;
+
+ if (*tpos == 'd')
+ plen= (uint) (int2str((long) iarg,endpos, -10) - endpos);
+ else
+ plen= (uint) (int2str((long) (uint) iarg,endpos,10)- endpos);
+ if (olen + plen < n) /* Replace parameter if possible */
+ {
+ endpos+=plen;
+ tpos++;
+ olen+=plen;
+ continue;
+ }
+ }
+ }
+ *endpos++='%'; /* % used as % or unknown code */
+ }
+ *endpos='\0';
+ /* End of errmessage */
+ return olen;
+}
+
diff --git a/mysys/my_wincond.c b/mysys/my_wincond.c
new file mode 100644
index 00000000000..3643d0ec0a6
--- /dev/null
+++ b/mysys/my_wincond.c
@@ -0,0 +1,141 @@
+/* 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 */
+
+/*****************************************************************************
+** The following is a simple implementation of posix conditions
+*****************************************************************************/
+
+#include "mysys_priv.h"
+#if defined(THREAD) && defined(__WIN__)
+#include <m_string.h>
+#undef getpid
+#include <process.h>
+#include <sys/timeb.h>
+
+int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr)
+{
+ cond->waiting=0;
+ cond->semaphore=CreateSemaphore(NULL,0,0x7FFFFFFF,NullS);
+ if (!cond->semaphore)
+ return ENOMEM;
+ return 0;
+}
+
+int pthread_cond_destroy(pthread_cond_t *cond)
+{
+ return CloseHandle(cond->semaphore) ? 0 : EINVAL;
+}
+
+
+int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
+{
+ InterlockedIncrement(&cond->waiting);
+ LeaveCriticalSection(mutex);
+ WaitForSingleObject(cond->semaphore,INFINITE);
+ InterlockedDecrement(&cond->waiting);
+ EnterCriticalSection(mutex);
+ return 0 ;
+}
+
+int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
+ struct timespec *abstime)
+{
+ struct _timeb curtime;
+ int result;
+ long timeout;
+ _ftime(&curtime);
+ timeout= ((long) (abstime->tv_sec - curtime.time)*1000L +
+ (long)((abstime->tv_nsec/1000) - curtime.millitm)/1000L);
+ if (timeout < 0) /* Some safety */
+ timeout = 0L;
+ InterlockedIncrement(&cond->waiting);
+ LeaveCriticalSection(mutex);
+ result=WaitForSingleObject(cond->semaphore,timeout);
+ InterlockedDecrement(&cond->waiting);
+ EnterCriticalSection(mutex);
+
+ return result == WAIT_TIMEOUT ? ETIMEDOUT : 0;
+}
+
+
+int pthread_cond_signal(pthread_cond_t *cond)
+{
+ long prev_count;
+ if (cond->waiting)
+ ReleaseSemaphore(cond->semaphore,1,&prev_count);
+ return 0;
+}
+
+
+int pthread_cond_broadcast(pthread_cond_t *cond)
+{
+ long prev_count;
+ if (cond->waiting)
+ ReleaseSemaphore(cond->semaphore,cond->waiting,&prev_count);
+ return 0 ;
+}
+
+
+int pthread_attr_init(pthread_attr_t *connect_att)
+{
+ connect_att->dwStackSize = 0;
+ connect_att->dwCreatingFlag = 0;
+ connect_att->priority = 0;
+ return 0;
+}
+
+int pthread_attr_setstacksize(pthread_attr_t *connect_att,DWORD stack)
+{
+ connect_att->dwStackSize=stack;
+ return 0;
+}
+
+int pthread_attr_setprio(pthread_attr_t *connect_att,int priority)
+{
+ connect_att->priority=priority;
+ return 0;
+}
+
+int pthread_attr_destroy(pthread_attr_t *connect_att)
+{
+ bzero((gptr) connect_att,sizeof(*connect_att));
+ return 0;
+}
+
+/****************************************************************************
+** Fix localtime_r() to be a bit safer
+****************************************************************************/
+
+struct tm *localtime_r(const time_t *timep,struct tm *tmp)
+{
+ if (*timep == (time_t) -1) /* This will crash win32 */
+ {
+ bzero(tmp,sizeof(*tmp));
+ }
+ else
+ {
+ struct tm *res=localtime(timep);
+ if (!res) /* Wrong date */
+ {
+ bzero(tmp,sizeof(*tmp)); /* Keep things safe */
+ return 0;
+ }
+ *tmp= *res;
+ }
+ return tmp;
+}
+#endif /* __WIN__ */
diff --git a/mysys/my_winthread.c b/mysys/my_winthread.c
new file mode 100644
index 00000000000..436fc954d93
--- /dev/null
+++ b/mysys/my_winthread.c
@@ -0,0 +1,111 @@
+/* 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 */
+
+/*****************************************************************************
+** Simulation of posix threads calls for WIN95 and NT
+*****************************************************************************/
+
+#include "mysys_priv.h"
+#if defined(THREAD) && defined(__WIN__)
+#include <m_string.h>
+#undef getpid
+#include <process.h>
+
+extern pthread_mutex_t THR_LOCK_thread;
+
+struct pthread_map
+{
+ HANDLE pthreadself;
+ pthread_handler func;
+ void *param;
+};
+
+/*
+** We have tried to use '_beginthreadex' instead of '_beginthread' here
+** but in this case the program leaks about 512 characters for each
+** created thread !
+** As we want to save the created thread handler for other threads to
+** use and to be returned by pthread_self() (instead of the Win32 pseudo
+** handler), we have to go trough pthread_start() to catch the returned handler
+** in the new thread.
+*/
+
+static pthread_handler_decl(pthread_start,param)
+{
+ pthread_handler func=((struct pthread_map *) param)->func;
+ void *func_param=((struct pthread_map *) param)->param;
+ my_thread_init();
+ pthread_mutex_lock(&THR_LOCK_thread); /* Wait for beingthread to return */
+ win_pthread_self=((struct pthread_map *) param)->pthreadself;
+ pthread_mutex_unlock(&THR_LOCK_thread);
+ free((char*) param);
+ pthread_exit((*func)(func_param));
+ return 0;
+}
+
+
+int pthread_create(pthread_t *thread_id, pthread_attr_t *attr,
+ pthread_handler func, void *param)
+{
+ HANDLE hThread;
+ struct pthread_map *map;
+ DBUG_ENTER("pthread_create");
+
+ if (!(map=malloc(sizeof(*map))))
+ DBUG_RETURN(-1);
+ map->func=func;
+ map->param=param;
+ pthread_mutex_lock(&THR_LOCK_thread);
+#ifdef __BORLANDC__
+ hThread=(HANDLE)_beginthread((void(_USERENTRY *)(void *)) pthread_start,
+ attr->dwStackSize ? attr->dwStackSize :
+ 65535, (void*) map);
+#else
+ hThread=(HANDLE)_beginthread(pthread_start,
+ attr->dwStackSize ? attr->dwStackSize :
+ 65535, (void*) map);
+#endif
+ DBUG_PRINT("info", ("hThread=%lu",(long) hThread));
+ *thread_id=map->pthreadself=hThread;
+ pthread_mutex_unlock(&THR_LOCK_thread);
+
+ if ((long) hThread == -1L)
+ {
+ long error=errno;
+ DBUG_PRINT("error",
+ ("Can't create thread to handle request (error %ld)",error));
+ DBUG_RETURN(error ? error : -1);
+ }
+ VOID(SetThreadPriority(hThread, attr->priority)) ;
+ DBUG_RETURN(0);
+}
+
+
+void pthread_exit(unsigned A)
+{
+ _endthread();
+}
+
+/* This is neaded to get the macro pthread_setspecific to work */
+
+int win_pthread_setspecific(void *a,void *b,uint length)
+{
+ memcpy(a,b,length);
+ return 0;
+}
+
+#endif
diff --git a/mysys/my_write.c b/mysys/my_write.c
new file mode 100644
index 00000000000..0ff32094ed7
--- /dev/null
+++ b/mysys/my_write.c
@@ -0,0 +1,77 @@
+/* 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 "mysys_err.h"
+#include <errno.h>
+
+ /* Write a chunk of bytes to a file */
+
+uint my_write(int Filedes, const byte *Buffer, uint Count, myf MyFlags)
+{
+ uint writenbytes,errors;
+ ulong written;
+ DBUG_ENTER("my_write");
+ DBUG_PRINT("my",("Fd: %d Buffer: %lx Count: %d MyFlags: %d",
+ Filedes, Buffer, Count, MyFlags));
+ errors=0; written=0L;
+
+ for (;;)
+ {
+ if ((writenbytes = (uint) write(Filedes, Buffer, Count)) == Count)
+ break;
+ if ((int) writenbytes != -1)
+ { /* Safeguard */
+ written+=writenbytes;
+ Buffer+=writenbytes;
+ Count-=writenbytes;
+ }
+ my_errno=errno;
+ DBUG_PRINT("error",("Write only %d bytes",writenbytes));
+#ifndef NO_BACKGROUND
+#ifdef THREAD
+ if (my_thread_var->abort)
+ MyFlags&= ~ MY_WAIT_IF_FULL; /* End if aborted by user */
+#endif
+ if (my_errno == ENOSPC && (MyFlags & MY_WAIT_IF_FULL))
+ {
+ if (!(errors++ % MY_WAIT_GIVE_USER_A_MESSAGE))
+ my_error(EE_DISK_FULL,MYF(ME_BELL | ME_NOREFRESH),
+ my_filename(Filedes));
+ VOID(sleep(MY_WAIT_FOR_USER_TO_FIX_PANIC));
+ continue;
+ }
+ if ((writenbytes == 0 && my_errno == EINTR) ||
+ (writenbytes > 0 && (uint) writenbytes != (uint) -1))
+ continue; /* Retry */
+#endif
+ if (MyFlags & (MY_NABP | MY_FNABP))
+ {
+ if (MyFlags & (MY_WME | MY_FAE | MY_FNABP))
+ {
+ my_error(EE_WRITE, MYF(ME_BELL+ME_WAITTANG),
+ my_filename(Filedes),my_errno);
+ }
+ DBUG_RETURN(MY_FILE_ERROR); /* Error on read */
+ }
+ else
+ break; /* Return bytes written */
+ }
+ if (MyFlags & (MY_NABP | MY_FNABP))
+ DBUG_RETURN(0); /* Want only errors */
+ DBUG_RETURN(writenbytes+written);
+} /* my_write */
diff --git a/mysys/mysys_priv.h b/mysys/mysys_priv.h
new file mode 100644
index 00000000000..86c32202e99
--- /dev/null
+++ b/mysys/mysys_priv.h
@@ -0,0 +1,31 @@
+/* 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>
+#include <my_sys.h>
+
+#ifdef USE_SYSTEM_WRAPPERS
+#include "system_wrappers.h"
+#endif
+
+#ifdef THREAD
+extern pthread_mutex_t THR_LOCK_malloc,THR_LOCK_open,THR_LOCK_keycache,
+ THR_LOCK_lock,THR_LOCK_isam,THR_LOCK_net,THR_LOCK_charset;
+#else /* THREAD */
+#define pthread_mutex_lock(A)
+#define pthread_mutex_unlock(A)
+#endif
diff --git a/mysys/ptr_cmp.c b/mysys/ptr_cmp.c
new file mode 100644
index 00000000000..65b2c51aafd
--- /dev/null
+++ b/mysys/ptr_cmp.c
@@ -0,0 +1,158 @@
+/* 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 */
+
+/*
+ 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"
+
+static int ptr_compare(uint *compare_length, uchar **a, uchar **b);
+static int ptr_compare_0(uint *compare_length, uchar **a, uchar **b);
+static int ptr_compare_1(uint *compare_length, uchar **a, uchar **b);
+static int ptr_compare_2(uint *compare_length, uchar **a, uchar **b);
+static int ptr_compare_3(uint *compare_length, uchar **a, uchar **b);
+
+ /* Get a pointer to a optimal byte-compare function for a given size */
+
+qsort2_cmp get_ptr_compare (uint size)
+{
+ if (size < 4)
+ return (qsort2_cmp) ptr_compare;
+ switch (size & 3) {
+ case 0: return (qsort2_cmp) ptr_compare_0;
+ case 1: return (qsort2_cmp) ptr_compare_1;
+ case 2: return (qsort2_cmp) ptr_compare_2;
+ case 3: return (qsort2_cmp) ptr_compare_3;
+ }
+ return 0; /* Impossible */
+}
+
+
+ /*
+ Compare to keys to see witch is smaller.
+ Loop unrolled to make it quick !!
+ */
+
+#define cmp(N) if (first[N] != last[N]) return (int) first[N] - (int) last[N]
+
+static int ptr_compare(uint *compare_length, uchar **a, uchar **b)
+{
+ reg3 int length= *compare_length;
+ reg1 uchar *first,*last;
+
+ first= *a; last= *b;
+ while (--length)
+ {
+ if (*first++ != *last++)
+ return (int) first[-1] - (int) last[-1];
+ }
+ return (int) first[0] - (int) last[0];
+}
+
+
+static int ptr_compare_0(uint *compare_length,uchar **a, uchar **b)
+{
+ reg3 int length= *compare_length;
+ reg1 uchar *first,*last;
+
+ first= *a; last= *b;
+ loop:
+ cmp(0);
+ cmp(1);
+ cmp(2);
+ cmp(3);
+ if ((length-=4))
+ {
+ first+=4;
+ last+=4;
+ goto loop;
+ }
+ return (0);
+}
+
+
+static int ptr_compare_1(uint *compare_length,uchar **a, uchar **b)
+{
+ reg3 int length= *compare_length-1;
+ reg1 uchar *first,*last;
+
+ first= *a+1; last= *b+1;
+ cmp(-1);
+ loop:
+ cmp(0);
+ cmp(1);
+ cmp(2);
+ cmp(3);
+ if ((length-=4))
+ {
+ first+=4;
+ last+=4;
+ goto loop;
+ }
+ return (0);
+}
+
+static int ptr_compare_2(uint *compare_length,uchar **a, uchar **b)
+{
+ reg3 int length= *compare_length-2;
+ reg1 uchar *first,*last;
+
+ first= *a +2 ; last= *b +2;
+ cmp(-2);
+ cmp(-1);
+ loop:
+ cmp(0);
+ cmp(1);
+ cmp(2);
+ cmp(3);
+ if ((length-=4))
+ {
+ first+=4;
+ last+=4;
+ goto loop;
+ }
+ return (0);
+}
+
+static int ptr_compare_3(uint *compare_length,uchar **a, uchar **b)
+{
+ reg3 int length= *compare_length-3;
+ reg1 uchar *first,*last;
+
+ first= *a +3 ; last= *b +3;
+ cmp(-3);
+ cmp(-2);
+ cmp(-1);
+ loop:
+ cmp(0);
+ cmp(1);
+ cmp(2);
+ cmp(3);
+ if ((length-=4))
+ {
+ first+=4;
+ last+=4;
+ goto loop;
+ }
+ return (0);
+}
diff --git a/mysys/queues.c b/mysys/queues.c
new file mode 100644
index 00000000000..f33856b892d
--- /dev/null
+++ b/mysys/queues.c
@@ -0,0 +1,141 @@
+/* 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 */
+
+/*
+ Code for generell handling of priority Queues.
+ Implemention of queues from "Algoritms in C" by Robert Sedgewick.
+*/
+
+#include "mysys_priv.h"
+#include <queues.h>
+
+
+ /* The actuall code for handling queues */
+
+int init_queue(QUEUE *queue, uint max_elements, uint offset_to_key,
+ pbool max_at_top, int (*compare) (void *, byte *, byte *),
+ void *first_cmp_arg)
+{
+ DBUG_ENTER("init_queue");
+ if ((queue->root= (byte **) my_malloc((max_elements+1)*sizeof(void*),
+ MYF(MY_WME))) == 0)
+ DBUG_RETURN(1);
+ queue->elements=0;
+ queue->compare=compare;
+ queue->first_cmp_arg=first_cmp_arg;
+ queue->max_elements=max_elements;
+ queue->offset_to_key=offset_to_key;
+ queue->max_at_top= max_at_top ? (-1 ^ 1) : 0;
+ DBUG_RETURN(0);
+}
+
+void delete_queue(QUEUE *queue)
+{
+ DBUG_ENTER("delete_queue");
+ if (queue->root)
+ {
+ my_free((gptr) queue->root,MYF(0));
+ queue->root=0;
+ }
+ DBUG_VOID_RETURN;
+}
+
+
+ /* Code for insert, search and delete of elements */
+
+void queue_insert(register QUEUE *queue, byte *element)
+{
+ reg2 uint idx,next;
+
+#ifndef DBUG_OFF
+ if (queue->elements < queue->max_elements)
+#endif
+ {
+ queue->root[0]=element;
+ idx= ++queue->elements;
+
+ while ((queue->compare(queue->first_cmp_arg,
+ element+queue->offset_to_key,
+ queue->root[(next=idx >> 1)]+queue->offset_to_key)
+ ^ queue->max_at_top) < 0)
+ {
+ queue->root[idx]=queue->root[next];
+ idx=next;
+ }
+ queue->root[idx]=element;
+ }
+}
+
+ /* Remove item from queue */
+ /* Returns pointer to removed element */
+
+byte *queue_remove(register QUEUE *queue, uint idx)
+{
+#ifndef DBUG_OFF
+ if (idx >= queue->max_elements)
+ return 0;
+#endif
+ {
+ byte *element=queue->root[++idx]; /* Intern index starts from 1 */
+ queue->root[idx]=queue->root[queue->elements--];
+ _downheap(queue,idx);
+ return element;
+ }
+}
+
+
+ /* Fix when element on top has been replaced */
+
+#ifndef queue_replaced
+void queue_replaced(queue)
+QUEUE *queue;
+{
+ _downheap(queue,1);
+}
+#endif
+
+ /* Fix heap when index have changed */
+
+void _downheap(register QUEUE *queue, uint idx)
+{
+ byte *element;
+ uint elements,half_queue,next_index,offset_to_key;
+ int cmp;
+
+ offset_to_key=queue->offset_to_key;
+ element=queue->root[idx];
+ half_queue=(elements=queue->elements) >> 1;
+
+ while (idx <= half_queue)
+ {
+ next_index=idx+idx;
+ if (next_index < elements &&
+ (queue->compare(queue->first_cmp_arg,
+ queue->root[next_index]+offset_to_key,
+ queue->root[next_index+1]+offset_to_key) ^
+ queue->max_at_top) > 0)
+ next_index++;
+ if ((cmp=queue->compare(queue->first_cmp_arg,
+ queue->root[next_index]+offset_to_key,
+ element+offset_to_key)) == 0 ||
+ (cmp ^ queue->max_at_top) > 0)
+ break;
+ queue->root[idx]=queue->root[next_index];
+ idx=next_index;
+ }
+ queue->root[idx]=element;
+}
diff --git a/mysys/raid.cc b/mysys/raid.cc
new file mode 100644
index 00000000000..a92647d1d95
--- /dev/null
+++ b/mysys/raid.cc
@@ -0,0 +1,809 @@
+/* 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 */
+
+/* --------------------------------------------------------*
+*
+* 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
+#endif
+
+#include "mysys_priv.h"
+#include "my_dir.h"
+#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
+#define RAID_SIZE_UNKNOWN ~(my_off_t) 0
+
+DYNAMIC_ARRAY RaidFd::_raid_map;
+
+
+/* --------------- C compatibility ---------------*/
+
+extern "C" {
+
+ void init_raid(void)
+ {
+ /* Allocate memory for global file to raid map */
+ init_dynamic_array(&RaidFd::_raid_map, sizeof(RaidFd*), 4096, 1024);
+ }
+ void end_raid(void)
+ {
+ /* Free memory used by raid */
+ delete_dynamic(&RaidFd::_raid_map);
+ }
+
+ bool is_raid(File fd)
+ {
+ return RaidFd::IsRaid(fd);
+ }
+
+ File my_raid_create(const char *FileName, int CreateFlags, int access_flags,
+ uint raid_type, uint raid_chunks, ulong raid_chunksize,
+ myf MyFlags)
+ {
+ DBUG_ENTER("my_raid_create");
+ DBUG_PRINT("enter",("Filename: %s CreateFlags: %d access_flags: %d MyFlags: %d",
+ FileName, CreateFlags, access_flags, MyFlags));
+ if (raid_type)
+ {
+ RaidFd *raid = new RaidFd(raid_type, raid_chunks , raid_chunksize);
+ File res = raid->Create(FileName,CreateFlags,access_flags,MyFlags);
+ if (res < 0 || set_dynamic(&RaidFd::_raid_map,(char*) &raid,res))
+ {
+ delete raid;
+ DBUG_RETURN(-1);
+ }
+ DBUG_RETURN(res);
+ }
+ else
+ DBUG_RETURN(my_create(FileName, CreateFlags, access_flags, MyFlags));
+ }
+
+ File my_raid_open(const char *FileName, int Flags,
+ uint raid_type, uint raid_chunks, ulong raid_chunksize,
+ myf MyFlags)
+ {
+ DBUG_ENTER("my_raid_open");
+ DBUG_PRINT("enter",("Filename: %s Flags: %d MyFlags: %d",
+ FileName, Flags, MyFlags));
+ if (raid_type)
+ {
+ RaidFd *raid = new RaidFd(raid_type, raid_chunks , raid_chunksize);
+ File res = raid->Open(FileName,Flags,MyFlags);
+ if (res < 0 || set_dynamic(&RaidFd::_raid_map,(char*) &raid,res))
+ {
+ delete raid;
+ DBUG_RETURN(-1);
+ }
+ DBUG_RETURN(res);
+ }
+ else
+ DBUG_RETURN(my_open(FileName, Flags, MyFlags));
+ }
+
+ my_off_t my_raid_seek(File fd, my_off_t pos,int whence,myf MyFlags)
+ {
+ DBUG_ENTER("my_raid_seek");
+ DBUG_PRINT("enter",("Fd: %d pos: %lu whence: %d MyFlags: %d",
+ fd, (ulong) pos, whence, MyFlags));
+
+ assert(pos != MY_FILEPOS_ERROR);
+
+ if (is_raid(fd))
+ {
+ RaidFd *raid= (*dynamic_element(&RaidFd::_raid_map,fd,RaidFd**));
+ DBUG_RETURN(raid->Seek(pos,whence,MyFlags));
+ }
+ else
+ DBUG_RETURN(my_seek(fd, pos, whence, MyFlags));
+ }
+
+ my_off_t my_raid_tell(File fd,myf MyFlags)
+ {
+ DBUG_ENTER("my_raid_tell");
+ DBUG_PRINT("enter",("Fd: %d MyFlags: %d",
+ fd, MyFlags));
+ if (is_raid(fd))
+ {
+ RaidFd *raid= (*dynamic_element(&RaidFd::_raid_map,fd,RaidFd**));
+ DBUG_RETURN(raid->Tell(MyFlags));
+ }
+ else
+ DBUG_RETURN(my_tell(fd, MyFlags));
+ }
+
+ uint my_raid_write(File fd,const byte *Buffer, uint Count, myf MyFlags)
+ {
+ DBUG_ENTER("my_raid_write");
+ DBUG_PRINT("enter",("Fd: %d Buffer: %lx Count: %u MyFlags: %d",
+ fd, Buffer, Count, MyFlags));
+ if (is_raid(fd))
+ {
+ RaidFd *raid= (*dynamic_element(&RaidFd::_raid_map,fd,RaidFd**));
+ DBUG_RETURN(raid->Write(Buffer,Count,MyFlags));
+ } else
+ DBUG_RETURN(my_write(fd,Buffer,Count,MyFlags));
+ }
+
+ uint my_raid_read(File fd, byte *Buffer, uint Count, myf MyFlags)
+ {
+ DBUG_ENTER("my_raid_read");
+ DBUG_PRINT("enter",("Fd: %d Buffer: %lx Count: %u MyFlags: %d",
+ fd, Buffer, Count, MyFlags));
+ if (is_raid(fd))
+ {
+ RaidFd *raid= (*dynamic_element(&RaidFd::_raid_map,fd,RaidFd**));
+ DBUG_RETURN(raid->Read(Buffer,Count,MyFlags));
+ } else
+ DBUG_RETURN(my_read(fd,Buffer,Count,MyFlags));
+ }
+
+ uint my_raid_pread(File Filedes, byte *Buffer, uint Count, my_off_t offset,
+ myf MyFlags)
+ {
+ DBUG_ENTER("my_raid_pread");
+ DBUG_PRINT("enter",("Fd: %d Buffer: %lx Count: %u offset: %u MyFlags: %d",
+ Filedes, Buffer, Count, offset, MyFlags));
+ if (is_raid(Filedes))
+ {
+ assert(offset != MY_FILEPOS_ERROR);
+
+ RaidFd *raid= (*dynamic_element(&RaidFd::_raid_map,Filedes,RaidFd**));
+ /* Returning value isn't important because real seek is done later. */
+ raid->Seek(offset,MY_SEEK_SET,MyFlags);
+ DBUG_RETURN(raid->Read(Buffer,Count,MyFlags));
+ }
+ else
+ DBUG_RETURN(my_pread(Filedes, Buffer, Count, offset, MyFlags));
+ }
+
+ uint my_raid_pwrite(int Filedes, const byte *Buffer, uint Count,
+ my_off_t offset, myf MyFlags)
+ {
+ DBUG_ENTER("my_raid_pwrite");
+ DBUG_PRINT("enter",("Fd: %d Buffer: %lx Count: %u offset: %u MyFlags: %d",
+ Filedes, Buffer, Count, offset, MyFlags));
+ if (is_raid(Filedes))
+ {
+ assert(offset != MY_FILEPOS_ERROR);
+
+ RaidFd *raid= (*dynamic_element(&RaidFd::_raid_map,Filedes,RaidFd**));
+ /* Returning value isn't important because real seek is done later. */
+ raid->Seek(offset,MY_SEEK_SET,MyFlags);
+ DBUG_RETURN(raid->Write(Buffer,Count,MyFlags));
+ }
+ else
+ DBUG_RETURN(my_pwrite(Filedes, Buffer, Count, offset, MyFlags));
+ }
+
+ int my_raid_lock(File fd, int locktype, my_off_t start, my_off_t length,
+ myf MyFlags)
+ {
+ DBUG_ENTER("my_raid_lock");
+ DBUG_PRINT("enter",("Fd: %d start: %u length: %u MyFlags: %d",
+ fd, start, length, MyFlags));
+ if (my_disable_locking)
+ DBUG_RETURN(0);
+ if (is_raid(fd))
+ {
+ RaidFd *raid= (*dynamic_element(&RaidFd::_raid_map,fd,RaidFd**));
+ DBUG_RETURN(raid->Lock(locktype, start, length, MyFlags));
+ }
+ else
+ DBUG_RETURN(my_lock(fd, locktype, start, length, MyFlags));
+ }
+
+ int my_raid_close(File fd, myf MyFlags)
+ {
+ DBUG_ENTER("my_raid_close");
+ DBUG_PRINT("enter",("Fd: %d MyFlags: %d",
+ fd, MyFlags));
+ if (is_raid(fd))
+ {
+ RaidFd *raid= (*dynamic_element(&RaidFd::_raid_map,fd,RaidFd**));
+ RaidFd *tmp=0;
+ set_dynamic(&RaidFd::_raid_map,(char*) &tmp,fd);
+ int res = raid->Close(MyFlags);
+ delete raid;
+ DBUG_RETURN(res);
+ }
+ else
+ DBUG_RETURN(my_close(fd, MyFlags));
+ }
+
+ int my_raid_chsize(File fd, my_off_t newlength, myf MyFlags)
+ {
+ DBUG_ENTER("my_raid_chsize");
+ DBUG_PRINT("enter",("Fd: %d newlength: %u MyFlags: %d",
+ fd, newlength, MyFlags));
+ if (is_raid(fd))
+ {
+ RaidFd *raid= (*dynamic_element(&RaidFd::_raid_map,fd,RaidFd**));
+ DBUG_RETURN(raid->Chsize(fd, newlength, MyFlags));
+ }
+ else
+ DBUG_RETURN(my_chsize(fd, newlength, MyFlags));
+ }
+
+ int my_raid_rename(const char *from, const char *to,
+ uint raid_chunks, myf MyFlags)
+ {
+ char from_tmp[FN_REFLEN];
+ char to_tmp[FN_REFLEN];
+ DBUG_ENTER("my_raid_rename");
+
+ uint from_pos = dirname_length(from);
+ uint to_pos = dirname_length(to);
+ memcpy(from_tmp, from, from_pos);
+ memcpy(to_tmp, to, to_pos);
+ for (uint i = 0 ; i < raid_chunks ; i++ )
+ {
+ sprintf(from_tmp+from_pos,"%02x/%s", i, from + from_pos);
+ sprintf(to_tmp+to_pos,"%02x/%s", i, to+ to_pos);
+ /* Convert if not unix */
+ unpack_filename(from_tmp, from_tmp);
+ unpack_filename(to_tmp,to_tmp);
+ if (my_rename(from_tmp, to_tmp, MyFlags))
+ DBUG_RETURN(-1);
+ }
+ DBUG_RETURN(0);
+ }
+
+ int my_raid_delete(const char *from, uint raid_chunks, myf MyFlags)
+ {
+ char from_tmp[FN_REFLEN];
+ uint from_pos = dirname_length(from);
+ DBUG_ENTER("my_raid_delete");
+
+ if (!raid_chunks)
+ DBUG_RETURN(my_delete(from,MyFlags));
+ for (uint i = 0 ; i < raid_chunks ; i++ )
+ {
+ memcpy(from_tmp, from, from_pos);
+ sprintf(from_tmp+from_pos,"%02x/%s", i, from + from_pos);
+ /* Convert if not unix */
+ unpack_filename(from_tmp, from_tmp);
+ if (my_delete(from_tmp, MyFlags))
+ DBUG_RETURN(-1);
+ }
+ DBUG_RETURN(0);
+ }
+
+ int my_raid_redel(const char *old_name, const char *new_name,
+ uint raid_chunks, myf MyFlags)
+ {
+ char new_name_buff[FN_REFLEN], old_name_buff[FN_REFLEN];
+ char *new_end, *old_end;
+ uint i,old_length,new_length;
+ int error=0;
+ DBUG_ENTER("my_raid_redel");
+
+ old_end=old_name_buff+dirname_part(old_name_buff,old_name);
+ old_length=dirname_length(old_name);
+ new_end=new_name_buff+dirname_part(new_name_buff,new_name);
+ new_length=dirname_length(new_name);
+ for (i=0 ; i < raid_chunks ; i++)
+ {
+ MY_STAT status;
+ sprintf(new_end,"%02x",i);
+ if (my_stat(new_name_buff,&status, MYF(0)))
+ {
+ DBUG_PRINT("info",("%02x exists, skipping directory creation",i));
+ }
+ else
+ {
+ if (my_mkdir(new_name_buff,0777,MYF(0)))
+ {
+ DBUG_PRINT("error",("mkdir failed for %02x",i));
+ DBUG_RETURN(-1);
+ }
+ }
+ strxmov(strend(new_end),"/",new_name+new_length,NullS);
+ sprintf(old_end,"%02x/%s",i, old_name+old_length);
+ if (my_redel(old_name_buff, new_name_buff, MyFlags))
+ error=1;
+ }
+ DBUG_RETURN(error);
+ }
+}
+
+int my_raid_fstat(int fd, MY_STAT *stat_area, myf MyFlags )
+{
+ DBUG_ENTER("my_raid_fstat");
+ if (is_raid(fd))
+ {
+ RaidFd *raid= (*dynamic_element(&RaidFd::_raid_map,fd,RaidFd**));
+ DBUG_RETURN(raid->Fstat(fd, stat_area, MyFlags));
+ }
+ else
+ DBUG_RETURN(my_fstat(fd, stat_area, MyFlags));
+}
+
+
+/* -------------- RaidFd base class begins ----------------*/
+/*
+ RaidFd - raided file is identified by file descriptor
+ this is useful when we open/write/read/close files
+*/
+
+
+bool RaidFd::
+IsRaid(File fd)
+{
+ DBUG_ENTER("RaidFd::IsRaid");
+ DBUG_RETURN((uint) fd < _raid_map.elements &&
+ *dynamic_element(&RaidFd::_raid_map,fd,RaidFd**));
+}
+
+
+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)
+{
+ DBUG_ENTER("RaidFd::RaidFd");
+ DBUG_PRINT("enter",("RaidFd_type: %u Disks: %u Chunksize: %d",
+ raid_type, raid_chunks, raid_chunksize));
+
+ /* TODO: Here we should add checks if the malloc fails */
+ _seek_vector=0; /* In case of errors */
+ my_multi_malloc(MYF(MY_WME),
+ &_seek_vector,sizeof(off_t)*_raid_chunks,
+ &_fd_vector, sizeof(File) *_raid_chunks,
+ NullS);
+ if (!RaidFd::_raid_map.buffer)
+ { /* Not initied */
+ pthread_mutex_lock(&THR_LOCK_open); /* Ensure that no other thread */
+ if (!RaidFd::_raid_map.buffer) /* has done init in between */
+ init_raid();
+ pthread_mutex_unlock(&THR_LOCK_open);
+ }
+ DBUG_VOID_RETURN;
+}
+
+
+RaidFd::
+~RaidFd() {
+ DBUG_ENTER("RaidFd::~RaidFd");
+ /* We don't have to free _fd_vector ! */
+ my_free((char*) _seek_vector, MYF(MY_ALLOW_ZERO_PTR));
+ DBUG_VOID_RETURN;
+}
+
+
+File RaidFd::
+Create(const char *FileName, int CreateFlags, int access_flags, myf MyFlags)
+{
+ char RaidFdFileName[FN_REFLEN];
+ DBUG_ENTER("RaidFd::Create");
+ DBUG_PRINT("enter",
+ ("FileName: %s CreateFlags: %d access_flags: %d MyFlags: %d",
+ FileName, CreateFlags, access_flags, MyFlags));
+ char DirName[FN_REFLEN];
+ uint pos = dirname_part(DirName, FileName);
+ MY_STAT status;
+ if (!_seek_vector)
+ DBUG_RETURN(-1); /* Not enough memory */
+
+ uint i = _raid_chunks-1;
+ do
+ {
+ /* Create subdir */
+ (void)sprintf(RaidFdFileName,"%s%02x", DirName,i);
+ unpack_dirname(RaidFdFileName,RaidFdFileName); /* Convert if not unix */
+ if (my_stat(RaidFdFileName,&status, MYF(0)))
+ {
+ DBUG_PRINT("info",("%02x exists, skipping directory creation",i));
+ }
+ else
+ {
+ if (my_mkdir(RaidFdFileName,0777,MYF(0)))
+ {
+ DBUG_PRINT("error",("mkdir failed for %d",i));
+ goto error;
+ }
+ }
+ /* Create file */
+ sprintf(RaidFdFileName,"%s%02x/%s",DirName, i, FileName + pos);
+ unpack_filename(RaidFdFileName,RaidFdFileName); /* Convert if not unix */
+ _fd = my_create(RaidFdFileName, CreateFlags ,access_flags, (myf)MyFlags);
+ if (_fd < 0)
+ goto error;
+ _fd_vector[i]=_fd;
+ _seek_vector[i]=RAID_SEEK_DONE;
+ } while (i--);
+ _size=0;
+ DBUG_RETURN(_fd); /* Last filenr is pointer to map */
+
+error:
+ {
+ int save_errno=my_errno;
+ while (++i < _raid_chunks)
+ {
+ my_close(_fd_vector[i],MYF(0));
+ sprintf(RaidFdFileName,"%s%02x/%s",DirName, i, FileName + pos);
+ unpack_filename(RaidFdFileName,RaidFdFileName);
+ my_delete(RaidFdFileName,MYF(0));
+ }
+ my_errno=save_errno;
+ }
+ DBUG_RETURN(-1);
+}
+
+
+File RaidFd::
+Open(const char *FileName, int Flags, myf MyFlags)
+{
+ DBUG_ENTER("RaidFd::Open");
+ DBUG_PRINT("enter",("FileName: %s Flags: %d MyFlags: %d",
+ FileName, Flags, MyFlags));
+ char DirName[FN_REFLEN];
+ uint pos = dirname_part(DirName, FileName);
+ if (!_seek_vector)
+ DBUG_RETURN(-1); /* Not enough memory */
+
+ for( uint i = 0 ; i < _raid_chunks ; i++ )
+ {
+ char RaidFdFileName[FN_REFLEN];
+ sprintf(RaidFdFileName,"%s%02x/%s",DirName, i, FileName + pos);
+ unpack_filename(RaidFdFileName,RaidFdFileName); /* Convert if not unix */
+ _fd = my_open(RaidFdFileName, Flags, MyFlags);
+ if (_fd < 0)
+ {
+ int save_errno=my_errno;
+ while (i-- != 0)
+ my_close(_fd_vector[i],MYF(0));
+ my_errno=save_errno;
+ DBUG_RETURN(_fd);
+ }
+ _fd_vector[i]=_fd;
+ _seek_vector[i]=RAID_SEEK_DONE;
+ }
+ Seek(0L,MY_SEEK_END,MYF(0)); // Trick. We just need to know, how big the file is
+ DBUG_PRINT("info",("MYD file logical size: %llu", _size));
+ DBUG_RETURN(_fd);
+}
+
+
+int RaidFd::
+Write(const byte *Buffer, uint Count, myf MyFlags)
+{
+ DBUG_ENTER("RaidFd::Write");
+ DBUG_PRINT("enter",("Count: %d MyFlags: %d",
+ Count, MyFlags));
+ const byte *bufptr = Buffer;
+ uint res=0, GotBytes, ReadNowCount;
+
+ // Loop until data is written
+ do {
+ Calculate();
+ // Do seeks when neccessary
+ if (_seek_vector[_this_block] != RAID_SEEK_DONE)
+ {
+ if (my_seek(_fd_vector[_this_block], _seek_vector[_this_block],
+ MY_SEEK_SET,
+ MyFlags) == MY_FILEPOS_ERROR)
+ DBUG_RETURN(-1);
+ _seek_vector[_this_block]=RAID_SEEK_DONE;
+ }
+ ReadNowCount = min(Count, _remaining_bytes);
+ GotBytes = my_write(_fd_vector[_this_block], bufptr, ReadNowCount,
+ MyFlags);
+ DBUG_PRINT("loop",("Wrote bytes: %d", GotBytes));
+ if (GotBytes == MY_FILE_ERROR)
+ DBUG_RETURN(-1);
+ res+= GotBytes;
+ if (MyFlags & (MY_NABP | MY_FNABP))
+ GotBytes=ReadNowCount;
+ bufptr += GotBytes;
+ Count -= GotBytes;
+ _position += GotBytes;
+ } while(Count);
+ set_if_bigger(_size,_position);
+ DBUG_RETURN(res);
+}
+
+
+int RaidFd::
+Read(const byte *Buffer, uint Count, myf MyFlags)
+{
+ DBUG_ENTER("RaidFd::Read");
+ DBUG_PRINT("enter",("Count: %d MyFlags: %d",
+ Count, MyFlags));
+ byte *bufptr = (byte *)Buffer;
+ uint res= 0, GotBytes, ReadNowCount;
+
+ // Loop until all data is read (Note that Count may be 0)
+ while (Count)
+ {
+ Calculate();
+ // Do seek when neccessary
+ if (_seek_vector[_this_block] != RAID_SEEK_DONE)
+ {
+ if (my_seek(_fd_vector[_this_block], _seek_vector[_this_block],
+ MY_SEEK_SET,
+ MyFlags) == MY_FILEPOS_ERROR)
+ DBUG_RETURN(-1);
+ _seek_vector[_this_block]=RAID_SEEK_DONE;
+ }
+ // and read
+ ReadNowCount = min(Count, _remaining_bytes);
+ GotBytes = my_read(_fd_vector[_this_block], bufptr, ReadNowCount,
+ MyFlags & ~(MY_NABP | MY_FNABP));
+ DBUG_PRINT("loop",("Got bytes: %u", GotBytes));
+ if (GotBytes == MY_FILE_ERROR)
+ DBUG_RETURN(-1);
+ if (!GotBytes) // End of file.
+ {
+ DBUG_RETURN((MyFlags & (MY_NABP | MY_FNABP)) ? -1 : (int) res);
+ }
+ res+= GotBytes;
+ bufptr += GotBytes;
+ Count -= GotBytes;
+ _position += GotBytes;
+ }
+ DBUG_RETURN((MyFlags & (MY_NABP | MY_FNABP)) ? 0 : res);
+}
+
+
+int RaidFd::
+Lock(int locktype, my_off_t start, my_off_t length, myf MyFlags)
+{
+ DBUG_ENTER("RaidFd::Lock");
+ DBUG_PRINT("enter",("locktype: %d start: %lu length: %lu MyFlags: %d",
+ locktype, start, length, MyFlags));
+ my_off_t bufptr = start;
+ // Loop until all data is locked
+ while(length)
+ {
+ Calculate();
+ for (uint i = _this_block ; (i < _raid_chunks) && length ; i++ )
+ {
+ uint ReadNowCount = min(length, _remaining_bytes);
+ uint GotBytes = my_lock(_fd_vector[i], locktype, bufptr, ReadNowCount,
+ MyFlags);
+ if ((int) GotBytes == -1)
+ DBUG_RETURN(-1);
+ bufptr += ReadNowCount;
+ length -= ReadNowCount;
+ Calculate();
+ }
+ }
+ DBUG_RETURN(0);
+}
+
+
+int RaidFd::
+Close(myf MyFlags)
+{
+ DBUG_ENTER("RaidFd::Close");
+ DBUG_PRINT("enter",("MyFlags: %d",
+ MyFlags));
+ for (uint i = 0 ; i < _raid_chunks ; ++i )
+ {
+ int err = my_close(_fd_vector[i], MyFlags);
+ if (err != 0)
+ DBUG_RETURN(err);
+ }
+ /* _fd_vector is erased when RaidFd is released */
+ DBUG_RETURN(0);
+}
+
+
+my_off_t RaidFd::
+Seek(my_off_t pos,int whence,myf MyFlags)
+{
+ DBUG_ENTER("RaidFd::Seek");
+ DBUG_PRINT("enter",("Pos: %lu Whence: %d MyFlags: %d",
+ (ulong) pos, whence, MyFlags));
+ switch (whence) {
+ case MY_SEEK_CUR:
+ // FIXME: This is wrong, what is going on there
+ // Just I am relied on fact that MySQL 3.23.7 never uses MY_SEEK_CUR
+ // for anything else except things like ltell()
+ break;
+ case MY_SEEK_SET:
+ if ( _position != pos) // we can be already in right place
+ {
+ uint i;
+ off_t _rounds;
+ _position = pos;
+ Calculate();
+ _rounds = _total_block / _raid_chunks; // INT() assumed
+ _rounds*= _raid_chunksize;
+ for (i = 0; i < _raid_chunks ; i++ )
+ if ( i < _this_block )
+ _seek_vector[i] = _rounds + _raid_chunksize;
+ else if ( i == _this_block )
+ _seek_vector[i] = _rounds + _raid_chunksize -_remaining_bytes;
+ else // if ( i > _this_block )
+ _seek_vector[i] = _rounds;
+ }
+ break;
+ case MY_SEEK_END:
+ if (_size==RAID_SIZE_UNKNOWN) // We don't know table size yet
+ {
+ uint i;
+ _position = 0;
+ for (i = 0; i < _raid_chunks ; i++ )
+ {
+ my_off_t newpos = my_seek(_fd_vector[i], 0L, MY_SEEK_END, MyFlags);
+ if (newpos == MY_FILEPOS_ERROR)
+ DBUG_RETURN (MY_FILEPOS_ERROR);
+ _seek_vector[i]=RAID_SEEK_DONE;
+ _position += newpos;
+ }
+ _size=_position;
+ }
+ else if (_position != _size) // Aren't we also already in the end?
+ {
+ uint i;
+ off_t _rounds;
+ _position = _size;
+ Calculate();
+ _rounds = _total_block / _raid_chunks; // INT() assumed
+ _rounds*= _raid_chunksize;
+ for (i = 0; i < _raid_chunks ; i++ )
+ if ( i < _this_block )
+ _seek_vector[i] = _rounds + _raid_chunksize;
+ else if ( i == _this_block )
+ _seek_vector[i] = _rounds + _raid_chunksize - _remaining_bytes;
+ else // if ( i > _this_block )
+ _seek_vector[i] = _rounds;
+ _position=_size;
+ }
+ }
+ DBUG_RETURN(_position);
+}
+
+
+my_off_t RaidFd::
+Tell(myf MyFlags)
+{
+ DBUG_ENTER("RaidFd::Tell");
+ DBUG_PRINT("enter",("MyFlags: %d _position %d",
+ MyFlags,_position));
+ DBUG_RETURN(_position);
+}
+
+int RaidFd::
+Chsize(File fd, my_off_t newlength, myf MyFlags)
+{
+ DBUG_ENTER("RaidFd::Chsize");
+ DBUG_PRINT("enter",("Fd: %d, newlength: %d, MyFlags: %d",
+ fd, newlength,MyFlags));
+ _position = newlength;
+ Calculate();
+ uint _rounds = _total_block / _raid_chunks; // INT() assumed
+ for (uint i = 0; i < _raid_chunks ; i++ )
+ {
+ int newpos;
+ if ( i < _this_block )
+ newpos = my_chsize(_fd_vector[i],
+ _this_block * _raid_chunksize + (_rounds + 1) *
+ _raid_chunksize,
+ MyFlags);
+ else if ( i == _this_block )
+ newpos = my_chsize(_fd_vector[i],
+ _this_block * _raid_chunksize + _rounds *
+ _raid_chunksize + (newlength % _raid_chunksize),
+ MyFlags);
+ else // this means: i > _this_block
+ newpos = my_chsize(_fd_vector[i],
+ _this_block * _raid_chunksize + _rounds *
+ _raid_chunksize, MyFlags);
+ if (newpos)
+ DBUG_RETURN(1);
+ }
+ DBUG_RETURN(0);
+}
+
+
+int RaidFd::
+Fstat(int fd, MY_STAT *stat_area, myf MyFlags )
+{
+ DBUG_ENTER("RaidFd::Fstat");
+ DBUG_PRINT("enter",("fd: %d MyFlags: %d",fd,MyFlags));
+ uint i;
+ int error=0;
+ MY_STAT my_stat;
+ stat_area->st_size=0;
+ stat_area->st_mtime=0;
+ stat_area->st_atime=0;
+ stat_area->st_ctime=0;
+
+ for(i=0 ; i < _raid_chunks ; i++)
+ {
+ if (my_fstat(_fd_vector[i],&my_stat,MyFlags))
+ error=1;
+ stat_area->st_size+=my_stat.st_size;
+ set_if_bigger(stat_area->st_mtime,my_stat.st_mtime);
+ set_if_bigger(stat_area->st_atime,my_stat.st_atime);
+ set_if_bigger(stat_area->st_ctime,my_stat.st_ctime);
+ }
+ DBUG_RETURN(error);
+}
+
+#endif /* defined(USE_RAID) && !defined(MYSQL_CLIENT) */
diff --git a/mysys/safemalloc.c b/mysys/safemalloc.c
new file mode 100644
index 00000000000..d715f69e38a
--- /dev/null
+++ b/mysys/safemalloc.c
@@ -0,0 +1,518 @@
+/* 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 posting refers to an article entitled "oops, corrupted memory
+ * again!" in net.lang.c. I am posting it here because it is source.]
+ *
+ * My tool for approaching this problem is to build another level of data
+ * abstraction on top of malloc() and free() that implements some checking.
+ * This does a number of things for you:
+ * - Checks for overruns and underruns on allocated data
+ * - Keeps track of where in the program the memory was malloc'ed
+ * - Reports on pieces of memory that were not free'ed
+ * - Records some statistics such as maximum memory used
+ * - Marks newly malloc'ed and newly free'ed memory with special values
+ * You can use this scheme to:
+ * - Find bugs such as overrun, underrun, etc because you know where
+ * a piece of data was malloc'ed and where it was free'ed
+ * - Find bugs where memory was not free'ed
+ * - Find bugs where newly malloc'ed memory is used without initializing
+ * - Find bugs where newly free'ed memory is still used
+ * - Determine how much memory your program really uses
+ * - and other things
+ */
+
+/*
+ * To implement my scheme you must have a C compiler that has __LINE__ and
+ * __FILE__ macros. If your compiler doesn't have these then (a) buy another:
+ * compilers that do are available on UNIX 4.2bsd based systems and the PC,
+ * and probably on other machines; or (b) change my scheme somehow. I have
+ * recomendations on both these points if you would like them (e-mail please).
+ *
+ * There are 4 functions in my package:
+ * char *NEW( uSize ) Allocate memory of uSize bytes
+ * (equivalent to malloc())
+ * char *REA( pPtr, uSize) Allocate memory of uSize bytes, move data and
+ * free pPtr.
+ * (equivalent to realloc())
+ * FREE( pPtr ) Free memory allocated by NEW
+ * (equivalent to free())
+ * TERMINATE(file) End system, report errors and stats on file
+ * I personally use two more functions, but have not included them here:
+ * char *STRSAVE( sPtr ) Save a copy of the string in dynamic memory
+ * char *RENEW( pPtr, uSize )
+ * (equivalent to realloc())
+ */
+
+/*
+ * Memory sub-system, written by Bjorn Benson
+ Fixed to use my_sys scheme by Michael Widenius
+ */
+
+#ifndef SAFEMALLOC
+#define SAFEMALLOC /* Get protos from my_sys */
+#endif
+
+#include "mysys_priv.h"
+#include <m_string.h>
+#include "my_static.h"
+#include "mysys_err.h"
+
+#define pNext tInt._pNext
+#define pPrev tInt._pPrev
+#define sFileName tInt._sFileName
+#define uLineNum tInt._uLineNum
+#define uDataSize tInt._uDataSize
+#define lSpecialValue tInt._lSpecialValue
+
+ /* Static functions prototypes */
+
+static int check_ptr(const char *where, byte *ptr, const char *sFile,
+ uint uLine);
+static int _checkchunk(struct remember *pRec, const char *sFile, uint uLine);
+
+/*
+ * Note: both these refer to the NEW'ed
+ * data only. They do not include
+ * malloc() roundoff or the extra
+ * space required by the remember
+ * structures.
+ */
+
+#define ALLOC_VAL (uchar) 0xA5 /* NEW'ed memory is filled with this */
+ /* value so that references to it will */
+ /* end up being very strange. */
+#define FREE_VAL (uchar) 0x8F /* FREE'ed memory is filled with this */
+ /* value so that references to it will */
+ /* also end up being strange. */
+
+#define MAGICKEY 0x14235296 /* A magic value for underrun key */
+#define MAGICEND0 0x68 /* Magic values for overrun keys */
+#define MAGICEND1 0x34 /* " */
+#define MAGICEND2 0x7A /* " */
+#define MAGICEND3 0x15 /* " */
+
+ /* Warning: do not change the MAGICEND? values to */
+ /* something with the high bit set. Various C */
+ /* compilers (like the 4.2bsd one) do not do the */
+ /* sign extension right later on in this code and */
+ /* you will get erroneous errors. */
+
+
+/*
+ * gptr _mymalloc( uint uSize, my_string sFile, uint uLine, MyFlags )
+ * Allocate some memory.
+ */
+
+gptr _mymalloc (uint uSize, const char *sFile, uint uLine, myf MyFlags)
+{
+ struct remember *pTmp;
+ DBUG_ENTER("_mymalloc");
+ DBUG_PRINT("enter",("Size: %u",uSize));
+
+ if (!sf_malloc_quick)
+ (void) _sanity (sFile, uLine);
+
+ /* Allocate the physical memory */
+ pTmp = (struct remember *) malloc (
+ sizeof (struct irem) /* remember data */
+ + sf_malloc_prehunc
+ + uSize /* size requested */
+ + 4 /* overrun mark */
+ + sf_malloc_endhunc
+ );
+
+ /* Check if there isn't anymore memory avaiable */
+ if (pTmp == NULL)
+ {
+ if (MyFlags & MY_FAE)
+ error_handler_hook=fatal_error_handler_hook;
+ if (MyFlags & (MY_FAE+MY_WME))
+ {
+ char buff[SC_MAXWIDTH];
+ my_errno=errno;
+ sprintf(buff,"Out of memory at line %d, '%s'", uLine, sFile);
+ my_message(EE_OUTOFMEMORY,buff,MYF(ME_BELL+ME_WAITTANG));
+ sprintf(buff,"needed %d byte (%ldk), memory in use: %ld bytes (%ldk)",
+ uSize, (uSize + 1023L) / 1024L,
+ lMaxMemory, (lMaxMemory + 1023L) / 1024L);
+ my_message(EE_OUTOFMEMORY,buff,MYF(ME_BELL+ME_WAITTANG));
+ }
+ DBUG_PRINT("error",("Out of memory, in use: %ld at line %d, '%s'",
+ lMaxMemory,uLine, sFile));
+ if (MyFlags & MY_FAE)
+ exit(1);
+ DBUG_RETURN ((gptr) NULL);
+ }
+
+ /* Fill up the structure */
+ *((long*) ((char*) &pTmp -> lSpecialValue+sf_malloc_prehunc)) = MAGICKEY;
+ pTmp -> aData[uSize + sf_malloc_prehunc+0] = MAGICEND0;
+ pTmp -> aData[uSize + sf_malloc_prehunc+1] = MAGICEND1;
+ pTmp -> aData[uSize + sf_malloc_prehunc+2] = MAGICEND2;
+ pTmp -> aData[uSize + sf_malloc_prehunc+3] = MAGICEND3;
+ pTmp -> sFileName = (my_string) sFile;
+ pTmp -> uLineNum = uLine;
+ pTmp -> uDataSize = uSize;
+ pTmp -> pPrev = NULL;
+
+ /* Add this remember structure to the linked list */
+ pthread_mutex_lock(&THR_LOCK_malloc);
+ if ((pTmp->pNext=pRememberRoot))
+ {
+ pRememberRoot -> pPrev = pTmp;
+ }
+ pRememberRoot = pTmp;
+
+ /* Keep the statistics */
+ lCurMemory += uSize;
+ if (lCurMemory > lMaxMemory) {
+ lMaxMemory = lCurMemory;
+ }
+ cNewCount++;
+ pthread_mutex_unlock(&THR_LOCK_malloc);
+
+ /* Set the memory to the aribtrary wierd value */
+#ifdef HAVE_purify
+ if (MyFlags & MY_ZEROFILL)
+#endif
+ bfill(&pTmp -> aData[sf_malloc_prehunc],uSize,
+ (char) (MyFlags & MY_ZEROFILL ? 0 : ALLOC_VAL));
+ /* Return a pointer to the real data */
+ DBUG_PRINT("exit",("ptr: %lx",&(pTmp -> aData[sf_malloc_prehunc])));
+ if (sf_min_adress > &(pTmp -> aData[sf_malloc_prehunc]))
+ sf_min_adress = &(pTmp -> aData[sf_malloc_prehunc]);
+ if (sf_max_adress < &(pTmp -> aData[sf_malloc_prehunc]))
+ sf_max_adress = &(pTmp -> aData[sf_malloc_prehunc]);
+ DBUG_RETURN ((gptr) &(pTmp -> aData[sf_malloc_prehunc]));
+}
+
+/*
+ * Allocate some new memory and move old memoryblock there.
+ * Free then old memoryblock
+ */
+
+gptr _myrealloc (register gptr pPtr, register uint uSize,
+ const char *sFile, uint uLine, myf MyFlags)
+{
+ struct remember *pRec;
+ gptr ptr;
+ DBUG_ENTER("_myrealloc");
+
+ if (!pPtr && (MyFlags & MY_ALLOW_ZERO_PTR))
+ DBUG_RETURN(_mymalloc(uSize,sFile,uLine,MyFlags));
+
+ if (!sf_malloc_quick)
+ (void) _sanity (sFile, uLine);
+
+ if (check_ptr("Reallocating",(byte*) pPtr,sFile,uLine))
+ DBUG_RETURN((gptr) NULL);
+
+ pRec = (struct remember *) ((char*) pPtr - sizeof (struct irem)-
+ sf_malloc_prehunc);
+ if (*((long*) ((char*) &pRec -> lSpecialValue+sf_malloc_prehunc))
+ != MAGICKEY)
+ {
+ fprintf (stderr, "Reallocating unallocated data at line %d, '%s'\n",
+ uLine, sFile);
+ DBUG_PRINT("safe",("Reallocating unallocated data at line %d, '%s'",
+ uLine, sFile));
+ (void) fflush(stderr);
+ DBUG_RETURN((gptr) NULL);
+ }
+
+ if ((ptr=_mymalloc(uSize,sFile,uLine,MyFlags))) /* Allocate new area */
+ {
+ uSize=min(uSize,pRec-> uDataSize); /* Move as much as possibly */
+ memcpy((byte*) ptr,pPtr,(size_t) uSize); /* Copy old data */
+ _myfree(pPtr,sFile,uLine,0); /* Free not needed area */
+ }
+ else
+ {
+ if (MyFlags & MY_HOLD_ON_ERROR)
+ DBUG_RETURN(pPtr);
+ if (MyFlags & MY_FREE_ON_ERROR)
+ _myfree(pPtr,sFile,uLine,0);
+ }
+ DBUG_RETURN(ptr);
+} /* _myrealloc */
+
+
+/*
+ * void _myfree( my_string pPtr, my_string sFile, uint uLine, myf myflags)
+ * Deallocate some memory.
+ */
+
+void _myfree (gptr pPtr, const char *sFile, uint uLine, myf myflags)
+{
+ struct remember *pRec;
+ DBUG_ENTER("_myfree");
+ DBUG_PRINT("enter",("ptr: %lx",pPtr));
+
+ if (!sf_malloc_quick)
+ (void) _sanity (sFile, uLine);
+
+ if ((!pPtr && (myflags & MY_ALLOW_ZERO_PTR)) ||
+ check_ptr("Freeing",(byte*) pPtr,sFile,uLine))
+ DBUG_VOID_RETURN;
+
+ /* Calculate the address of the remember structure */
+ pRec = (struct remember *) ((byte*) pPtr-sizeof(struct irem)-
+ sf_malloc_prehunc);
+
+ /* Check to make sure that we have a real remember structure */
+ /* Note: this test could fail for four reasons: */
+ /* (1) The memory was already free'ed */
+ /* (2) The memory was never new'ed */
+ /* (3) There was an underrun */
+ /* (4) A stray pointer hit this location */
+
+ if (*((long*) ((char*) &pRec -> lSpecialValue+sf_malloc_prehunc))
+ != MAGICKEY)
+ {
+ fprintf (stderr, "Freeing unallocated data at line %d, '%s'\n",
+ uLine, sFile);
+ DBUG_PRINT("safe",("Unallocated data at line %d, '%s'",uLine,sFile));
+ (void) fflush(stderr);
+ DBUG_VOID_RETURN;
+ }
+
+ /* Remove this structure from the linked list */
+ pthread_mutex_lock(&THR_LOCK_malloc);
+ if (pRec -> pPrev) {
+ pRec -> pPrev -> pNext = pRec -> pNext;
+ } else {
+ pRememberRoot = pRec -> pNext;
+ }
+ if (pRec -> pNext) {
+ pRec -> pNext -> pPrev = pRec -> pPrev;
+ }
+ /* Handle the statistics */
+ lCurMemory -= pRec -> uDataSize;
+ cNewCount--;
+ pthread_mutex_unlock(&THR_LOCK_malloc);
+
+#ifndef HAVE_purify
+ /* Mark this data as free'ed */
+ bfill(&pRec->aData[sf_malloc_prehunc],pRec->uDataSize,(pchar) FREE_VAL);
+#endif
+ *((long*) ((char*) &pRec -> lSpecialValue+sf_malloc_prehunc)) = ~MAGICKEY;
+
+ /* Actually free the memory */
+ free ((my_string ) pRec);
+ DBUG_VOID_RETURN;
+}
+
+ /* Check if we have a wrong pointer */
+
+static int check_ptr(const char *where, byte *ptr, const char *sFile,
+ uint uLine)
+{
+ if (!ptr)
+ {
+ fprintf (stderr, "%s NULL pointer at line %d, '%s'\n",
+ where,uLine, sFile);
+ DBUG_PRINT("safe",("Null pointer at line %d '%s'", uLine, sFile));
+ (void) fflush(stderr);
+ return 1;
+ }
+#ifndef _MSC_VER
+ if ((long) ptr & (MY_ALIGN(1,sizeof(char *))-1))
+ {
+ fprintf (stderr, "%s wrong aligned pointer at line %d, '%s'\n",
+ where,uLine, sFile);
+ DBUG_PRINT("safe",("Wrong aligned pointer at line %d, '%s'",
+ uLine,sFile));
+ (void) fflush(stderr);
+ return 1;
+ }
+#endif
+ if (ptr < sf_min_adress || ptr > sf_max_adress)
+ {
+ fprintf (stderr, "%s pointer out of range at line %d, '%s'\n",
+ where,uLine, sFile);
+ DBUG_PRINT("safe",("Pointer out of range at line %d '%s'",
+ uLine,sFile));
+ (void) fflush(stderr);
+ return 1;
+ }
+ return 0;
+}
+
+
+/*
+ * TERMINATE(FILE *file)
+ * Report on all the memory pieces that have not been
+ * free'ed as well as the statistics.
+ */
+
+void TERMINATE (FILE *file)
+{
+ struct remember *pPtr;
+ DBUG_ENTER("TERMINATE");
+ pthread_mutex_lock(&THR_LOCK_malloc);
+
+ /* Report the difference between number of calls to */
+ /* NEW and the number of calls to FREE. >0 means more */
+ /* NEWs than FREEs. <0, etc. */
+
+ if (cNewCount)
+ {
+ if (file)
+ {
+ fprintf (file, "cNewCount: %d\n", cNewCount);
+ (void) fflush(file);
+ }
+ DBUG_PRINT("safe",("cNewCount: %d",cNewCount));
+ }
+
+ /* Report on all the memory that was allocated with NEW */
+ /* but not free'ed with FREE. */
+
+ if ((pPtr=pRememberRoot))
+ {
+ if (file)
+ {
+ fprintf(file, "Memory that was not free'ed (%ld bytes):\n",lCurMemory);
+ (void) fflush(file);
+ }
+ DBUG_PRINT("safe",("Memory that was not free'ed (%ld bytes):",lCurMemory));
+ while (pPtr)
+ {
+ if (file)
+ {
+ fprintf (file,
+ "\t%6u bytes at 0x%09lx, allocated at line %4u in '%s'\n",
+ pPtr -> uDataSize,
+ (ulong) &(pPtr -> aData[sf_malloc_prehunc]),
+ pPtr -> uLineNum, pPtr -> sFileName);
+ (void) fflush(file);
+ }
+ DBUG_PRINT("safe",
+ ("%6u bytes at 0x%09lx, allocated at line %4d in '%s'",
+ pPtr -> uDataSize, &(pPtr -> aData[sf_malloc_prehunc]),
+ pPtr -> uLineNum, pPtr -> sFileName));
+ pPtr = pPtr -> pNext;
+ }
+ }
+ /* Report the memory usage statistics */
+ if (file)
+ {
+ fprintf (file, "Maximum memory usage: %ld bytes (%ldk)\n",
+ lMaxMemory, (lMaxMemory + 1023L) / 1024L);
+ (void) fflush(file);
+ }
+ DBUG_PRINT("safe",("Maximum memory usage: %ld bytes (%ldk)",
+ lMaxMemory, (lMaxMemory + 1023L) / 1024L));
+ pthread_mutex_unlock(&THR_LOCK_malloc);
+ DBUG_VOID_RETURN;
+}
+
+
+ /* Returns 0 if chunk is ok */
+
+static int _checkchunk (register struct remember *pRec, const char *sFile,
+ uint uLine)
+{
+ reg1 uint uSize;
+ reg2 my_string magicp;
+ reg3 int flag=0;
+
+ /* Check for a possible underrun */
+ if (*((long*) ((char*) &pRec -> lSpecialValue+sf_malloc_prehunc))
+ != MAGICKEY)
+ {
+ fprintf (stderr, "Memory allocated at %s:%d was underrun,",
+ pRec -> sFileName, pRec -> uLineNum);
+ fprintf (stderr, " discovered at %s:%d\n", sFile, uLine);
+ (void) fflush(stderr);
+ DBUG_PRINT("safe",("Underrun at %lx, allocated at %s:%d",
+ &(pRec -> aData[sf_malloc_prehunc]),
+ pRec -> sFileName,
+ pRec -> uLineNum));
+ flag=1;
+ }
+
+ /* Check for a possible overrun */
+ uSize = pRec -> uDataSize;
+ magicp = &(pRec -> aData[uSize+sf_malloc_prehunc]);
+ if (*magicp++ != MAGICEND0 ||
+ *magicp++ != MAGICEND1 ||
+ *magicp++ != MAGICEND2 ||
+ *magicp++ != MAGICEND3)
+ {
+ fprintf (stderr, "Memory allocated at %s:%d was overrun,",
+ pRec -> sFileName, pRec -> uLineNum);
+ fprintf (stderr, " discovered at '%s:%d'\n", sFile, uLine);
+ (void) fflush(stderr);
+ DBUG_PRINT("safe",("Overrun at %lx, allocated at %s:%d",
+ &(pRec -> aData[sf_malloc_prehunc]),
+ pRec -> sFileName,
+ pRec -> uLineNum));
+ flag=1;
+ }
+ return(flag);
+}
+
+
+ /* Returns how many wrong chunks */
+
+int _sanity (const char *sFile, uint uLine)
+{
+ reg1 struct remember *pTmp;
+ reg2 int flag=0;
+ uint count=0;
+
+ pthread_mutex_lock(&THR_LOCK_malloc);
+ count=cNewCount;
+ for (pTmp = pRememberRoot; pTmp != NULL && count-- ; pTmp = pTmp -> pNext)
+ flag+=_checkchunk (pTmp, sFile, uLine);
+ pthread_mutex_unlock(&THR_LOCK_malloc);
+ if (count || pTmp)
+ {
+ const char *format="Safemalloc link list destroyed, discovered at '%s:%d'";
+ fprintf (stderr, format, sFile, uLine); fputc('\n',stderr);
+ (void) fflush(stderr);
+ DBUG_PRINT("safe",(format, sFile, uLine));
+ flag=1;
+ }
+ return flag;
+} /* _sanity */
+
+
+ /* malloc and copy */
+
+gptr _my_memdup(const byte *from, uint length, const char *sFile, uint uLine,
+ myf MyFlags)
+{
+ gptr ptr;
+ if ((ptr=_mymalloc(length,sFile,uLine,MyFlags)) != 0)
+ memcpy((byte*) ptr, (byte*) from,(size_t) length);
+ return(ptr);
+} /*_my_memdup */
+
+
+my_string _my_strdup(const char *from, const char *sFile, uint uLine,
+ myf MyFlags)
+{
+ gptr ptr;
+ uint length=(uint) strlen(from)+1;
+ if ((ptr=_mymalloc(length,sFile,uLine,MyFlags)) != 0)
+ memcpy((byte*) ptr, (byte*) from,(size_t) length);
+ return((my_string) ptr);
+} /* _my_strdup */
diff --git a/mysys/string.c b/mysys/string.c
new file mode 100644
index 00000000000..f7e265a43e6
--- /dev/null
+++ b/mysys/string.c
@@ -0,0 +1,117 @@
+/* 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 */
+
+/*
+ Code for handling strings with can grow dynamicly.
+ Copyright Monty Program KB.
+ By monty.
+*/
+
+#include "mysys_priv.h"
+#include <m_string.h>
+
+my_bool init_dynamic_string(DYNAMIC_STRING *str, const char *init_str,
+ uint init_alloc, uint alloc_increment)
+{
+ uint length;
+ DBUG_ENTER("init_dynamic_string");
+
+ if (!alloc_increment)
+ alloc_increment=128;
+ length=1;
+ if (init_str && (length=strlen(init_str)+1) < init_alloc)
+ init_alloc=((length+alloc_increment-1)/alloc_increment)*alloc_increment;
+ if (!init_alloc)
+ init_alloc=alloc_increment;
+
+ if (!(str->str=(char*) my_malloc(init_alloc,MYF(MY_WME))))
+ DBUG_RETURN(TRUE);
+ str->length=length-1;
+ if (init_str)
+ memcpy(str->str,init_str,length);
+ str->max_length=init_alloc;
+ str->alloc_increment=alloc_increment;
+ DBUG_RETURN(FALSE);
+}
+
+my_bool dynstr_set(DYNAMIC_STRING *str, const char *init_str)
+{
+ uint length;
+ DBUG_ENTER("dynstr_set");
+
+ if (init_str && (length=strlen(init_str)+1) > str->max_length)
+ {
+ str->max_length=((length+str->alloc_increment-1)/str->alloc_increment)*
+ str->alloc_increment;
+ if (!str->max_length)
+ str->max_length=str->alloc_increment;
+ if (!(str->str=(char*) my_realloc(str->str,str->max_length,MYF(MY_WME))))
+ DBUG_RETURN(TRUE);
+ }
+ if (init_str)
+ {
+ str->length=length-1;
+ memcpy(str->str,init_str,length);
+ }
+ else
+ str->length=0;
+ DBUG_RETURN(FALSE);
+}
+
+my_bool dynstr_realloc(DYNAMIC_STRING *str, ulong additional_size)
+{
+ DBUG_ENTER("dynstr_realloc");
+
+ if (!additional_size) DBUG_RETURN(FALSE);
+ if (str->length + additional_size > str->max_length)
+ {
+ str->max_length=((str->length + additional_size+str->alloc_increment-1)/
+ str->alloc_increment)*str->alloc_increment;
+ if (!(str->str=(char*) my_realloc(str->str,str->max_length,MYF(MY_WME))))
+ DBUG_RETURN(TRUE);
+ }
+ DBUG_RETURN(FALSE);
+}
+
+
+my_bool dynstr_append(DYNAMIC_STRING *str, const char *append)
+{
+ char *new_ptr;
+ uint length=(uint) strlen(append)+1;
+ if (str->length+length > str->max_length)
+ {
+ uint new_length=(str->length+length+str->alloc_increment-1)/
+ str->alloc_increment;
+ new_length*=str->alloc_increment;
+ if (!(new_ptr=(char*) my_realloc(str->str,new_length,MYF(MY_WME))))
+ return TRUE;
+ str->str=new_ptr;
+ str->max_length=new_length;
+ }
+ memcpy(str->str + str->length,append,length);
+ str->length+=length-1;
+ return FALSE;
+}
+
+void dynstr_free(DYNAMIC_STRING *str)
+{
+ if (str->str)
+ {
+ my_free(str->str,MYF(MY_WME));
+ str->str=0;
+ }
+}
diff --git a/mysys/test_charset.c b/mysys/test_charset.c
new file mode 100644
index 00000000000..a04bdbd9a58
--- /dev/null
+++ b/mysys/test_charset.c
@@ -0,0 +1,59 @@
+/* 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>
+#include <m_ctype.h>
+#include <my_sys.h>
+#include <mysql_version.h>
+
+#include <stdio.h>
+
+extern void _print_csinfo();
+
+int main(int argc, char **argv) {
+ const char *the_set = MYSQL_CHARSET;
+ char *cs_list;
+ int argcnt = 1;
+
+ my_init();
+
+ if (argc > argcnt && argv[argcnt][0] == '-' && argv[argcnt][1] == '#')
+ DBUG_PUSH(argv[argcnt++]+2);
+
+ if (argc > argcnt)
+ the_set = argv[argcnt++];
+
+ if (argc > argcnt)
+ charsets_dir = argv[argcnt++];
+
+ if (set_default_charset_by_name(the_set, MYF(MY_WME)))
+ return 1;
+
+ puts("CHARSET INFO:");
+ _print_csinfo(default_charset_info);
+ fflush(stdout);
+
+ cs_list = list_charsets(MYF(MY_COMPILED_SETS | MY_CONFIG_SETS));
+ printf("LIST OF CHARSETS (compiled + *.conf):\n%s\n", cs_list);
+ free(cs_list);
+
+ cs_list = list_charsets(MYF(MY_INDEX_SETS | MY_LOADED_SETS));
+ printf("LIST OF CHARSETS (index + loaded):\n%s\n", cs_list);
+ free(cs_list);
+
+ return 0;
+}
diff --git a/mysys/test_dir.c b/mysys/test_dir.c
new file mode 100644
index 00000000000..fafdde137b6
--- /dev/null
+++ b/mysys/test_dir.c
@@ -0,0 +1,50 @@
+/* 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 */
+
+/* TODO: Test all functions */
+
+#define USES_TYPES
+#include "mysys_priv.h"
+#include "my_dir.h"
+
+int main(int argc, char *argv[])
+{
+ MY_DIR *a;
+ uint f;
+ DBUG_ENTER ("main");
+ DBUG_PROCESS (argv[0]);
+
+ if (--argc > 0 && (*(++argv))[0] == '-' && (*argv)[1] == '#' )
+ DBUG_PUSH (*argv+2);
+
+ a = my_dir("./", 0);
+ for (f = 0; f < a->number_off_files; f++)
+ {
+ printf("%s\n", a->dir_entry[f].name);
+ }
+
+ a = my_dir("./", MY_WANT_STAT);
+ for (f = 0; f < a->number_off_files; f++)
+ {
+ printf("%s %d %d %d %s\n", a->dir_entry[f].name,
+ (int) a->dir_entry[f].mystat.st_size,
+ (int) a->dir_entry[f].mystat.st_uid,
+ (int) a->dir_entry[f].mystat.st_gid,
+ S_ISDIR(a->dir_entry[f].mystat.st_mode) ? "dir" : "");
+ }
+ return 0;
+}
diff --git a/mysys/test_fn.c b/mysys/test_fn.c
new file mode 100644
index 00000000000..224b899ebe1
--- /dev/null
+++ b/mysys/test_fn.c
@@ -0,0 +1,70 @@
+/* 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"
+
+const char *test_names[]=
+{
+ "/usr/my/include/srclib/myfunc/dbug/test",
+ "test",
+ "dbug/test",
+ "/usr/my/srclib/myfunc/dbug/test",
+ "/usr/monty/oldcopy/jazz/setupp.frm",
+ "~/monty.tst",
+ "~/dbug/monty.tst",
+ "./hejsan",
+ "./dbug/test",
+ "../dbug/test",
+ "../myfunc/test",
+ "../../monty/rutedit",
+ "/usr/monty//usr/monty/rutedit",
+ "/usr/./monty/rutedit",
+ "/usr/my/../monty/rutedit",
+ "/usr/my/~/rutedit",
+ "~/../my",
+ "~/../my/srclib/myfunc/test",
+ "~/../my/srclib/myfunc/./dbug/test",
+ "/../usr/my/srclib/dbug",
+ "c/../my",
+ "/c/../my",
+ NullS,
+};
+
+int main(int argc __attribute__((unused)), char **argv)
+{
+ const char **pos;
+ char buff[FN_REFLEN],buff2[FN_REFLEN];
+ DBUG_ENTER ("main");
+ DBUG_PROCESS (argv[0]);
+ MY_INIT(argv[0]);
+
+ if (argv[1] && argv[1][1] == '#')
+ DBUG_PUSH(argv[1]+2);
+
+ for (pos=test_names; *pos ; pos++)
+ {
+ printf("org : '%s'\n",*pos);
+ printf("pack: '%s'\n",fn_format(buff,*pos,"","",8));
+ printf("unpack: '%s'\n",fn_format(buff2,*pos,"","",4));
+ if (strcmp(unpack_filename(buff,buff),buff2) != 0)
+ {
+ printf("error on cmp: '%s' != '%s'\n",buff,buff2);
+ }
+ puts("");
+ }
+ DBUG_RETURN(0);
+}
diff --git a/mysys/test_vsnprintf.c b/mysys/test_vsnprintf.c
new file mode 100644
index 00000000000..b9ffb014181
--- /dev/null
+++ b/mysys/test_vsnprintf.c
@@ -0,0 +1,45 @@
+/* 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"
+
+static void my_printf(const char * fmt, ...)
+{
+ char buf[32];
+ int n;
+ va_list ar;
+ va_start(ar, fmt);
+ n = my_vsnprintf(buf, sizeof(buf),fmt, ar);
+ printf(buf);
+ printf("n=%d, strlen=%d\n", n, strlen(buf));
+ 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");
+ my_printf("Hello hack hack hack hack hack hack hack %d\n", 1);
+ my_printf("Hello %d hack %d\n", 1, 4);
+ my_printf("Hello %d hack hack hack hack hack %d\n", 1, 4);
+ my_printf("Hello '%s' hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh\n", "hack");
+ my_printf("Hello hhhhhhhhhhhhhh %d sssssssssssssss\n", 1);
+ my_printf("Hello %u\n", 1);
+ return 0;
+}
diff --git a/mysys/testhash.c b/mysys/testhash.c
new file mode 100644
index 00000000000..a8fbf800595
--- /dev/null
+++ b/mysys/testhash.c
@@ -0,0 +1,291 @@
+/* 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 av hash libarary: stor test */
+
+#include <global.h>
+#include <my_sys.h>
+#include <hash.h>
+#include <m_string.h>
+
+#define MAX_RECORDS 100000
+#define MAX_KEYS 3
+
+static int get_options(int argc, char *argv[]);
+static int do_test();
+static int rnd(int max_value);
+
+static uint testflag=0,recant=10000,reclength=37;
+static uint16 key1[1000];
+
+#ifdef DBUG_OFF
+#define hash_check(A) 0
+#else
+my_bool hash_check(HASH *hash);
+#endif
+void free_record(void *record);
+
+static byte *hash2_key(const byte *rec,uint *length,
+ my_bool not_used __attribute__((unused)))
+{
+ *length=(uint) (uchar) rec[reclength-1];
+ return (byte*) rec;
+}
+
+ /* Huvudprogrammet */
+
+int main(int argc,char *argv[])
+{
+ MY_INIT(argv[0]);
+ DBUG_PROCESS(argv[0]);
+
+ get_options(argc,argv);
+
+ exit(do_test());
+}
+
+static int do_test()
+{
+ register uint i,j;
+ uint n1,n2,n3;
+ uint write_count,update,delete;
+ ulong pos;
+ unsigned long key_check;
+ char *record,*recpos,oldrecord[120],key[10];
+ HASH hash,hash2;
+ DBUG_ENTER("do_test");
+
+ write_count=update=delete=0;
+ key_check=0;
+ bzero((char*) key1,sizeof(key1[0])*1000);
+
+ printf("- Creating hash\n");
+ if (hash_init(&hash,recant/2,0,6,0,free_record,0))
+ goto err;
+ printf("- Writing records:s\n");
+
+ for (i=0 ; i < recant ; i++)
+ {
+ n1=rnd(1000); n2=rnd(100); n3=rnd(min(recant*5,MAX_RECORDS));
+ record= (char*) my_malloc(reclength,MYF(MY_FAE));
+ sprintf(record,"%6d:%4d:%8d:Pos: %4d ",n1,n2,n3,write_count);
+ if (hash_insert(&hash,record))
+ {
+ printf("Error: %d in write at record: %d\n",my_errno,i);
+ goto err;
+ }
+ key1[n1]++;
+ key_check+=n1;
+ write_count++;
+ }
+ if (hash_check(&hash))
+ {
+ puts("Heap keys crashed");
+ goto err;
+ }
+ printf("- Delete\n");
+ for (i=0 ; i < write_count/10 ; i++)
+ {
+ for (j=rnd(1000) ; j>0 && key1[j] == 0 ; j--) ;
+ if (j != 0)
+ {
+ sprintf(key,"%6d",j);
+ if (!(recpos=hash_search(&hash,key,0)))
+ {
+ printf("can't find key1: \"%s\"\n",key);
+ goto err;
+ }
+ key1[atoi(recpos)]--;
+ key_check-=atoi(recpos);
+ memcpy(oldrecord,recpos,reclength);
+ if (hash_delete(&hash,recpos))
+ {
+ printf("error: %d; can't delete record: \"%s\"\n", my_errno,oldrecord);
+ goto err;
+ }
+ delete++;
+ if (testflag == 2 && hash_check(&hash))
+ {
+ puts("Heap keys crashed");
+ goto err;
+ }
+ }
+ }
+ if (hash_check(&hash))
+ {
+ puts("Hash keys crashed");
+ goto err;
+ }
+
+ printf("- Update\n");
+ for (i=0 ; i < write_count/10 ; i++)
+ {
+ n1=rnd(1000); n2=rnd(100); n3=rnd(min(recant*2,MAX_RECORDS));
+ for (j=rnd(1000) ; j>0 && key1[j] == 0 ; j--) ;
+ if (j)
+ {
+ sprintf(key,"%6d",j);
+ if (!(recpos=hash_search(&hash,key,0)))
+ {
+ printf("can't find key1: \"%s\"\n",key);
+ goto err;
+ }
+ key1[atoi(recpos)]--;
+ key_check=key_check-atoi(recpos)+n1;
+ key1[n1]++;
+ sprintf(recpos,"%6d:%4d:%8d:XXX: %4d ",n1,n2,n3,update);
+ update++;
+ if (hash_update(&hash,recpos,key,0))
+ {
+ printf("can't update key1: \"%s\"\n",key);
+ goto err;
+ }
+ if (testflag == 3 && hash_check(&hash))
+ {
+ printf("Heap keys crashed for %d update\n",update);
+ goto err;
+ }
+ }
+ }
+ if (hash_check(&hash))
+ {
+ puts("Heap keys crashed");
+ goto err;
+ }
+
+ for (j=0 ; j < 1000 ; j++)
+ if (key1[j] > 1)
+ break;
+ if (key1[j] > 1)
+ {
+ printf("- Testing identical read\n");
+ sprintf(key,"%6d",j);
+ pos=1;
+ if (!(recpos=hash_search(&hash,key,0)))
+ {
+ printf("can't find key1: \"%s\"\n",key);
+ goto err;
+ }
+ while (hash_next(&hash,key,0) && pos < (ulong) (key1[j]+10))
+ pos++;
+ if (pos != (ulong) key1[j])
+ {
+ printf("Found %ld copies of key: %s. Should be %d",pos,key,key1[j]);
+ goto err;
+ }
+ }
+ printf("- Creating output heap-file 2\n");
+ if (hash_init(&hash2,hash.records,0,0,hash2_key,free_record,0))
+ goto err;
+
+ printf("- Copying and removing records\n");
+ pos=0;
+ while ((recpos=hash_element(&hash,0)))
+ {
+ record=(byte*) my_malloc(reclength,MYF(MY_FAE));
+ memcpy(record,recpos,reclength);
+ record[reclength-1]=rnd(5)+1;
+ if (hash_insert(&hash2,record))
+ {
+ printf("Got error when inserting record: %*s",reclength,record);
+ goto err;
+ }
+ key_check-=atoi(record);
+ write_count++;
+ if (hash_delete(&hash,recpos))
+ {
+ printf("Got error when deleting record: %*s",reclength,recpos);
+ goto err;
+ }
+ if (testflag==4)
+ {
+ if (hash_check(&hash) || hash_check(&hash2))
+ {
+ puts("Hash keys crashed");
+ goto err;
+ }
+ }
+ pos++;
+ }
+ if (hash_check(&hash) || hash_check(&hash2))
+ {
+ puts("Hash keys crashed");
+ goto err;
+ }
+ if (key_check != 0)
+ {
+ printf("Key check didn't get to 0 (%ld)\n",key_check);
+ }
+
+ printf("\nFollowing test have been made:\n");
+ printf("Write records: %d\nUpdate records: %d\nDelete records: %d\n", write_count,
+ update,delete);
+ hash_free(&hash); hash_free(&hash2);
+ my_end(MY_GIVE_INFO);
+ DBUG_RETURN(0);
+err:
+ printf("Got error: %d when using hashing\n",my_errno);
+ DBUG_RETURN(-1);
+} /* main */
+
+
+ /* l{ser optioner */
+ /* OBS! intierar endast DEBUG - ingen debuggning h{r ! */
+
+static int get_options(int argc, char **argv)
+{
+ char *pos,*progname;
+ DEBUGGER_OFF;
+
+ progname= argv[0];
+
+ while (--argc >0 && *(pos = *(++argv)) == '-' ) {
+ switch(*++pos) {
+ case 'm': /* records */
+ recant=atoi(++pos);
+ break;
+ case 't':
+ testflag=atoi(++pos); /* testmod */
+ break;
+ case 'V':
+ case 'I':
+ case '?':
+ printf("%s Ver 1.0 for %s at %s\n",progname,SYSTEM_TYPE,MACHINE_TYPE);
+ puts("TCX Datakonsult AB, by Monty, for your professional use\n");
+ printf("Usage: %s [-?ABIKLWv] [-m#] [-t#]\n",progname);
+ exit(0);
+ case '#':
+ DEBUGGER_ON;
+ DBUG_PUSH (++pos);
+ break;
+ }
+ }
+ return 0;
+} /* get options */
+
+ /* Ge ett randomv{rde inom ett intervall 0 <=x <= n */
+
+static int rnd(int max_value)
+{
+ return (int) ((rand() & 32767)/32767.0*max_value);
+} /* rnd */
+
+
+void free_record(void *record)
+{
+ my_free(record,MYF(0));
+}
diff --git a/mysys/thr_alarm.c b/mysys/thr_alarm.c
new file mode 100644
index 00000000000..a681c1b110d
--- /dev/null
+++ b/mysys/thr_alarm.c
@@ -0,0 +1,874 @@
+/* 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>
+#include <errno.h>
+#include <my_pthread.h>
+#include <signal.h>
+#include <my_sys.h>
+#include <m_string.h>
+#include <queues.h>
+#include "thr_alarm.h"
+
+#ifdef THREAD
+
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h> /* AIX needs this for fd_set */
+#endif
+
+#ifndef ETIME
+#define ETIME ETIMEDOUT
+#endif
+
+static my_bool alarm_aborted=1;
+my_bool thr_alarm_inited=0;
+
+#if !defined(__WIN__) && !defined(__OS2__)
+#ifndef DONT_USE_THR_ALARM /* thr_alarm disabled */
+
+static pthread_mutex_t LOCK_alarm;
+static sigset_t full_signal_set;
+static QUEUE alarm_queue;
+pthread_t alarm_thread;
+
+#ifdef USE_ALARM_THREAD
+static pthread_cond_t COND_alarm;
+static void *alarm_handler(void *arg);
+#define reschedule_alarms() pthread_cond_signal(&COND_alarm)
+#else
+#define reschedule_alarms() pthread_kill(alarm_thread,THR_SERVER_ALARM)
+#endif
+
+#if THR_CLIENT_ALARM != SIGALRM || defined(USE_ALARM_THREAD)
+static sig_handler thread_alarm(int sig __attribute__((unused)));
+#endif
+
+static int compare_ulong(void *not_used __attribute__((unused)),
+ byte *a_ptr,byte* b_ptr)
+{
+ ulong a=*((ulong*) a_ptr),b= *((ulong*) b_ptr);
+ return (a < b) ? -1 : (a == b) ? 0 : 1;
+}
+
+void init_thr_alarm(uint max_alarms)
+{
+ sigset_t s;
+ DBUG_ENTER("init_thr_alarm");
+ alarm_aborted=0;
+ init_queue(&alarm_queue,max_alarms+1,offsetof(ALARM,expire_time),0,
+ compare_ulong,NullS);
+ sigfillset(&full_signal_set); /* Neaded to block signals */
+ pthread_mutex_init(&LOCK_alarm,NULL);
+#if THR_CLIENT_ALARM != SIGALRM || defined(USE_ALARM_THREAD)
+#if defined(HAVE_mit_thread)
+ sigset(THR_CLIENT_ALARM,thread_alarm); /* int. thread system calls */
+#else
+ {
+ struct sigaction sact;
+ sact.sa_flags = 0;
+ sact.sa_handler = thread_alarm;
+ sigaction(THR_CLIENT_ALARM, &sact, (struct sigaction*) 0);
+ }
+#endif
+#endif
+ sigemptyset(&s);
+ sigaddset(&s, THR_SERVER_ALARM);
+ alarm_thread=pthread_self();
+#if defined(USE_ALARM_THREAD)
+ {
+ pthread_attr_t thr_attr;
+ pthread_attr_init(&thr_attr);
+ pthread_cond_init(&COND_alarm,NULL);
+ pthread_attr_setscope(&thr_attr,PTHREAD_SCOPE_PROCESS);
+ pthread_attr_setdetachstate(&thr_attr,PTHREAD_CREATE_DETACHED);
+ pthread_attr_setstacksize(&thr_attr,8196);
+
+ my_pthread_attr_setprio(&thr_attr,100); /* Very high priority */
+ VOID(pthread_create(&alarm_thread,&thr_attr,alarm_handler,NULL));
+ VOID(pthread_attr_destroy(&thr_attr));
+ }
+#elif defined(USE_ONE_SIGNAL_HAND)
+ pthread_sigmask(SIG_BLOCK, &s, NULL); /* used with sigwait() */
+#if THR_SERVER_ALARM == THR_CLIENT_ALARM
+ sigset(THR_CLIENT_ALARM,process_alarm); /* Linuxthreads */
+ pthread_sigmask(SIG_UNBLOCK, &s, NULL);
+#endif
+#else
+ pthread_sigmask(SIG_UNBLOCK, &s, NULL);
+ sigset(THR_SERVER_ALARM,process_alarm);
+#endif
+ DBUG_VOID_RETURN;
+}
+
+/*
+** Request alarm after sec seconds.
+** A pointer is returned with points to a non-zero int when the alarm has been
+** given. This can't be called from the alarm-handling thread.
+** Returns 0 if no more alarms are allowed (aborted by process)
+*/
+
+bool thr_alarm(thr_alarm_t *alrm, uint sec, ALARM *alarm_data)
+{
+ ulong now;
+ sigset_t old_mask;
+ my_bool reschedule;
+ DBUG_ENTER("thr_alarm");
+ DBUG_PRINT("enter",("thread: %s sec: %d",my_thread_name(),sec));
+
+ now=(ulong) time((time_t*) 0);
+ pthread_sigmask(SIG_BLOCK,&full_signal_set,&old_mask);
+ pthread_mutex_lock(&LOCK_alarm); /* Lock from threads & alarms */
+ if (alarm_aborted)
+ { /* No signal thread */
+ DBUG_PRINT("info", ("alarm aborted"));
+ pthread_mutex_unlock(&LOCK_alarm);
+ pthread_sigmask(SIG_SETMASK,&old_mask,NULL);
+ DBUG_RETURN(1);
+ }
+ if (alarm_queue.elements == alarm_queue.max_elements)
+ {
+ DBUG_PRINT("info", ("alarm queue full"));
+ fprintf(stderr,"Warning: thr_alarm queue is full\n");
+ pthread_mutex_unlock(&LOCK_alarm);
+ pthread_sigmask(SIG_SETMASK,&old_mask,NULL);
+ DBUG_RETURN(1);
+ }
+ reschedule= (!alarm_queue.elements ||
+ (int) (((ALARM*) queue_top(&alarm_queue))->expire_time - now) >
+ (int) sec);
+ if (!alarm_data)
+ {
+ if (!(alarm_data=(ALARM*) my_malloc(sizeof(ALARM),MYF(MY_WME))))
+ {
+ DBUG_PRINT("info", ("failed my_malloc()"));
+ pthread_mutex_unlock(&LOCK_alarm);
+ pthread_sigmask(SIG_SETMASK,&old_mask,NULL);
+ DBUG_RETURN(1);
+ }
+ alarm_data->malloced=1;
+ }
+ else
+ alarm_data->malloced=0;
+ alarm_data->expire_time=now+sec;
+ alarm_data->alarmed=0;
+ alarm_data->thread=pthread_self();
+ queue_insert(&alarm_queue,(byte*) alarm_data);
+
+ /* Reschedule alarm if the current one has more than sec left */
+ if (reschedule)
+ {
+ DBUG_PRINT("info", ("reschedule"));
+ if (pthread_equal(pthread_self(),alarm_thread))
+ alarm(sec); /* purecov: inspected */
+ else
+ reschedule_alarms(); /* Reschedule alarms */
+ }
+ pthread_mutex_unlock(&LOCK_alarm);
+ pthread_sigmask(SIG_SETMASK,&old_mask,NULL);
+ (*alrm)= &alarm_data->alarmed;
+ DBUG_RETURN(0);
+}
+
+
+/*
+** Remove alarm from list of alarms
+*/
+
+void thr_end_alarm(thr_alarm_t *alarmed)
+{
+ ALARM *alarm_data;
+ sigset_t old_mask;
+ uint i;
+ bool found=0;
+ DBUG_ENTER("thr_end_alarm");
+
+ pthread_sigmask(SIG_BLOCK,&full_signal_set,&old_mask);
+ pthread_mutex_lock(&LOCK_alarm);
+
+ alarm_data= (ALARM*) ((byte*) *alarmed - offsetof(ALARM,alarmed));
+ for (i=0 ; i < alarm_queue.elements ; i++)
+ {
+ if ((ALARM*) queue_element(&alarm_queue,i) == alarm_data)
+ {
+ queue_remove(&alarm_queue,i),MYF(0);
+ if (alarm_data->malloced)
+ my_free((gptr) alarm_data,MYF(0));
+ found=1;
+ break;
+ }
+ }
+ if (!found)
+ {
+#ifdef MAIN
+ printf("Warning: Didn't find alarm %lx in queue of %d alarms\n",
+ (long) *alarmed, alarm_queue.elements);
+#endif
+ DBUG_PRINT("warning",("Didn't find alarm %lx in queue\n",*alarmed));
+ }
+ if (alarm_aborted && !alarm_queue.elements)
+ delete_queue(&alarm_queue);
+ pthread_mutex_unlock(&LOCK_alarm);
+ pthread_sigmask(SIG_SETMASK,&old_mask,NULL);
+ DBUG_VOID_RETURN;
+}
+
+ /*
+ Come here when some alarm in queue is due.
+ Mark all alarms with are finnished in list.
+ Shedule alarms to be sent again after 1-10 sec (many alarms at once)
+ If alarm_aborted is set then all alarms are given and resent
+ every second.
+ */
+
+sig_handler process_alarm(int sig __attribute__((unused)))
+{
+ sigset_t old_mask;
+ ALARM *alarm_data;
+ DBUG_ENTER("process_alarm");
+ DBUG_PRINT("info",("sig: %d active alarms: %d",sig,alarm_queue.elements));
+
+#if THR_SERVER_ALARM == THR_CLIENT_ALARM
+ if (!pthread_equal(pthread_self(),alarm_thread))
+ {
+#if defined(MAIN) && !defined(__bsdi__)
+ printf("thread_alarm\n"); fflush(stdout);
+#endif
+#ifdef DONT_REMEMBER_SIGNAL
+ sigset(THR_CLIENT_ALARM,process_alarm); /* int. thread system calls */
+#endif
+ DBUG_VOID_RETURN;
+ }
+#endif
+
+#if defined(MAIN) && !defined(__bsdi__)
+ printf("process_alarm\n"); fflush(stdout);
+#endif
+#ifndef USE_ALARM_THREAD
+ pthread_sigmask(SIG_SETMASK,&full_signal_set,&old_mask);
+ pthread_mutex_lock(&LOCK_alarm);
+#endif
+ if (alarm_queue.elements)
+ {
+ if (alarm_aborted)
+ {
+ uint i;
+ for (i=0 ; i < alarm_queue.elements ;)
+ {
+ alarm_data=(ALARM*) queue_element(&alarm_queue,i);
+ alarm_data->alarmed=1; /* Info to thread */
+ if (pthread_equal(alarm_data->thread,alarm_thread) ||
+ pthread_kill(alarm_data->thread, THR_CLIENT_ALARM))
+ {
+#ifdef MAIN
+ printf("Warning: pthread_kill couldn't find thread!!!\n");
+#endif
+ queue_remove(&alarm_queue,i); /* No thread. Remove alarm */
+ }
+ else
+ i++; /* Signal next thread */
+ }
+#ifndef USE_ALARM_THREAD
+ if (alarm_queue.elements)
+ alarm(1); /* Signal soon again */
+#endif
+ }
+ else
+ {
+ ulong now=(ulong) time((time_t*) 0);
+ ulong next=now+10-(now%10);
+ while ((alarm_data=(ALARM*) queue_top(&alarm_queue))->expire_time <= now)
+ {
+ alarm_data->alarmed=1; /* Info to thread */
+ DBUG_PRINT("info",("sending signal to waiting thread"));
+ if (pthread_equal(alarm_data->thread,alarm_thread) ||
+ pthread_kill(alarm_data->thread, THR_CLIENT_ALARM))
+ {
+#ifdef MAIN
+ printf("Warning: pthread_kill couldn't find thread!!!\n");
+#endif
+ queue_remove(&alarm_queue,0); /* No thread. Remove alarm */
+ if (!alarm_queue.elements)
+ break;
+ }
+ else
+ {
+ alarm_data->expire_time=next;
+ queue_replaced(&alarm_queue);
+ }
+ }
+#ifndef USE_ALARM_THREAD
+ if (alarm_queue.elements)
+ {
+#ifdef __bsdi__
+ alarm(0); /* Remove old alarm */
+#endif
+ alarm((uint) (alarm_data->expire_time-now));
+ }
+#endif
+ }
+ }
+#ifndef USE_ALARM_THREAD
+#if defined(DONT_REMEMBER_SIGNAL) && !defined(USE_ONE_SIGNAL_HAND)
+ sigset(THR_SERVER_ALARM,process_alarm);
+#endif
+ pthread_mutex_unlock(&LOCK_alarm);
+ pthread_sigmask(SIG_SETMASK,&old_mask,NULL);
+#endif
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+** Shedule all alarms now.
+** When all alarms are given, Free alarm memory and don't allow more alarms.
+*/
+
+void end_thr_alarm(void)
+{
+ DBUG_ENTER("end_thr_alarm");
+ pthread_mutex_lock(&LOCK_alarm);
+ if (!alarm_aborted)
+ {
+ DBUG_PRINT("info",("Resheduling %d waiting alarms",alarm_queue.elements));
+ alarm_aborted=1; /* mark aborted */
+ if (!alarm_queue.elements)
+ delete_queue(&alarm_queue);
+ if (pthread_equal(pthread_self(),alarm_thread))
+ alarm(1); /* Shut down everything soon */
+ else
+ reschedule_alarms();
+ }
+ pthread_mutex_unlock(&LOCK_alarm);
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+** Remove another thread from the alarm
+*/
+
+void thr_alarm_kill(pthread_t thread_id)
+{
+ uint i;
+ pthread_mutex_lock(&LOCK_alarm);
+ for (i=0 ; i < alarm_queue.elements ; i++)
+ {
+ if (pthread_equal(((ALARM*) queue_element(&alarm_queue,i))->thread,
+ thread_id))
+ {
+ ALARM *tmp=(ALARM*) queue_remove(&alarm_queue,i);
+ tmp->expire_time=0;
+ queue_insert(&alarm_queue,(byte*) tmp);
+ reschedule_alarms();
+ break;
+ }
+ }
+ pthread_mutex_unlock(&LOCK_alarm);
+}
+
+
+/*
+** This is here for thread to get interruptet from read/write/fcntl
+** ARGSUSED
+*/
+
+#if THR_CLIENT_ALARM != SIGALRM || defined(USE_ALARM_THREAD)
+static sig_handler thread_alarm(int sig)
+{
+#ifdef MAIN
+ printf("thread_alarm\n"); fflush(stdout);
+#endif
+#ifdef DONT_REMEMBER_SIGNAL
+ sigset(sig,thread_alarm); /* int. thread system calls */
+#endif
+}
+#endif
+
+
+#ifdef HAVE_TIMESPEC_TS_SEC
+#define tv_sec ts_sec
+#define tv_nsec ts_nsec
+#endif
+
+/* set up a alarm thread with uses 'sleep' to sleep between alarms */
+
+#ifdef USE_ALARM_THREAD
+static void *alarm_handler(void *arg __attribute__((unused)))
+{
+ int error;
+ struct timespec abstime;
+#ifdef MAIN
+ puts("Starting alarm thread");
+#endif
+ my_thread_init();
+ pthread_mutex_lock(&LOCK_alarm);
+ for (;;)
+ {
+ if (alarm_queue.elements)
+ {
+ ulong sleep_time,now=time((time_t*) 0);
+ if (alarm_aborted)
+ sleep_time=now+1;
+ else
+ sleep_time= ((ALARM*) queue_top(&alarm_queue))->expire_time;
+ if (sleep_time > now)
+ {
+ abstime.tv_sec=sleep_time;
+ abstime.tv_nsec=0;
+ if ((error=pthread_cond_timedwait(&COND_alarm,&LOCK_alarm,&abstime)) &&
+ error != ETIME && error != ETIMEDOUT)
+ {
+#ifdef MAIN
+ printf("Got error: %d from ptread_cond_timedwait (errno: %d)\n",
+ error,errno);
+#endif
+ }
+ }
+ }
+ else if (alarm_aborted)
+ break;
+ else if ((error=pthread_cond_wait(&COND_alarm,&LOCK_alarm)))
+ {
+#ifdef MAIN
+ printf("Got error: %d from ptread_cond_wait (errno: %d)\n",
+ error,errno);
+#endif
+ }
+ process_alarm(0);
+ }
+ bzero((char*) &alarm_thread,sizeof(alarm_thread)); /* For easy debugging */
+ pthread_mutex_unlock(&LOCK_alarm);
+ pthread_exit(0);
+ return 0; /* Impossible */
+}
+#endif
+
+
+#ifdef MAIN
+
+static pthread_cond_t COND_thread_count;
+static pthread_mutex_t LOCK_thread_count;
+static uint thread_count;
+
+#ifdef HPUX
+typedef int * fd_set_ptr;
+#else
+typedef fd_set * fd_set_ptr;
+#endif
+
+static void *test_thread(void *arg)
+{
+ int i,param=*((int*) arg),wait_time,retry;
+ time_t start_time;
+ thr_alarm_t got_alarm;
+ fd_set fd;
+ FD_ZERO(&fd);
+ my_thread_init();
+ printf("Tread %d (%s) started\n",param,my_thread_name()); fflush(stdout);
+ for (i=1 ; i <= 10 ; i++)
+ {
+ wait_time=param ? 11-i : i;
+ start_time=time((time_t*) 0);
+ if (thr_alarm(&got_alarm,wait_time,0))
+ {
+ printf("Thread: %s Alarms aborted\n",my_thread_name());
+ break;
+ }
+ if (wait_time == 3)
+ {
+ printf("Thread: %s Simulation of no alarm needed\n",my_thread_name());
+ fflush(stdout);
+ }
+ else
+ {
+ for (retry=0 ; !thr_got_alarm(got_alarm) && retry < 10 ; retry++)
+ {
+ printf("Thread: %s Waiting %d sec\n",my_thread_name(),wait_time);
+ select(0,(fd_set_ptr) &fd,0,0,0);
+ }
+ if (!thr_got_alarm(got_alarm))
+ {
+ printf("Thread: %s didn't get an alarm. Aborting!\n",
+ my_thread_name());
+ break;
+ }
+ if (wait_time == 7)
+ { /* Simulate alarm-miss */
+ fd_set readFDs;
+ uint max_connection=fileno(stdin);
+ FD_ZERO(&readFDs);
+ FD_SET(max_connection,&readFDs);
+ retry=0;
+ for (;;)
+ {
+ printf("Thread: %s Simulating alarm miss\n",my_thread_name());
+ fflush(stdout);
+ if (select(max_connection+1, (fd_set_ptr) &readFDs,0,0,0) < 0)
+ {
+ if (errno == EINTR)
+ break; /* Got new interrupt */
+ printf("Got errno: %d from select. Retrying..\n",errno);
+ if (retry++ >= 3)
+ {
+ printf("Warning: Interrupt of select() doesn't set errno!\n");
+ break;
+ }
+ }
+ else /* This shouldn't happen */
+ {
+ if (!FD_ISSET(max_connection,&readFDs))
+ {
+ printf("Select interrupted, but errno not set\n");
+ fflush(stdout);
+ if (retry++ >= 3)
+ break;
+ continue;
+ }
+ VOID(getchar()); /* Somebody was playing */
+ }
+ }
+ }
+ }
+ printf("Thread: %s Slept for %d (%d) sec\n",my_thread_name(),
+ (int) (time((time_t*) 0)-start_time), wait_time); fflush(stdout);
+ thr_end_alarm(&got_alarm);
+ fflush(stdout);
+ }
+ pthread_mutex_lock(&LOCK_thread_count);
+ thread_count--;
+ VOID(pthread_cond_signal(&COND_thread_count)); /* Tell main we are ready */
+ pthread_mutex_unlock(&LOCK_thread_count);
+ free((gptr) arg);
+ return 0;
+}
+
+#ifdef USE_ONE_SIGNAL_HAND
+static sig_handler print_signal_warning(int sig)
+{
+ printf("Warning: Got signal %d from thread %s\n",sig,my_thread_name());
+ fflush(stdout);
+#ifdef DONT_REMEMBER_SIGNAL
+ sigset(sig,print_signal_warning); /* int. thread system calls */
+#endif
+ if (sig == SIGALRM)
+ alarm(2); /* reschedule alarm */
+}
+#endif
+
+
+
+static void *signal_hand(void *arg __attribute__((unused)))
+{
+ sigset_t set;
+ int sig,error,err_count=0;;
+
+ my_thread_init();
+ pthread_detach_this_thread();
+ init_thr_alarm(10); /* Setup alarm handler */
+ pthread_mutex_lock(&LOCK_thread_count); /* Required by bsdi */
+ VOID(pthread_cond_signal(&COND_thread_count)); /* Tell main we are ready */
+ pthread_mutex_unlock(&LOCK_thread_count);
+
+ sigemptyset(&set); /* Catch all signals */
+ sigaddset(&set,SIGINT);
+ sigaddset(&set,SIGQUIT);
+ sigaddset(&set,SIGTERM);
+#if THR_CLIENT_ALARM != SIGHUP
+ sigaddset(&set,SIGHUP);
+#endif
+#ifdef SIGTSTP
+ sigaddset(&set,SIGTSTP);
+#endif
+#ifdef USE_ONE_SIGNAL_HAND
+ sigaddset(&set,THR_SERVER_ALARM); /* For alarms */
+ puts("Starting signal and alarm handling thread");
+#else
+ puts("Starting signal handling thread");
+#endif
+ printf("server alarm: %d thread alarm: %d\n",
+ THR_SERVER_ALARM,THR_CLIENT_ALARM);
+ DBUG_PRINT("info",("Starting signal and alarm handling thread"));
+ for(;;)
+ {
+ while ((error=my_sigwait(&set,&sig)) == EINTR)
+ printf("sigwait restarted\n");
+ if (error)
+ {
+ fprintf(stderr,"Got error %d from sigwait\n",error);
+ if (err_count++ > 5)
+ exit(1); /* Too many errors in test */
+ continue;
+ }
+#ifdef USE_ONE_SIGNAL_HAND
+ if (sig != THR_SERVER_ALARM)
+#endif
+ printf("Main thread: Got signal %d\n",sig);
+ switch (sig) {
+ case SIGINT:
+ case SIGQUIT:
+ case SIGTERM:
+ case SIGHUP:
+ printf("Aborting nicely\n");
+ end_thr_alarm();
+ break;
+#ifdef SIGTSTP
+ case SIGTSTP:
+ printf("Aborting\n");
+ exit(1);
+ return 0; /* Keep some compilers happy */
+#endif
+#ifdef USE_ONE_SIGNAL_HAND
+ case THR_SERVER_ALARM:
+ process_alarm(sig);
+ break;
+#endif
+ }
+ }
+}
+
+
+int main(int argc __attribute__((unused)),char **argv __attribute__((unused)))
+{
+ pthread_t tid;
+ pthread_attr_t thr_attr;
+ int i,*param,error;
+ sigset_t set;
+ MY_INIT(argv[0]);
+
+ if (argc > 1 && argv[1][0] == '-' && argv[1][1] == '#')
+ DBUG_PUSH(argv[1]+2);
+
+ pthread_mutex_init(&LOCK_thread_count,NULL);
+ pthread_cond_init(&COND_thread_count,NULL);
+
+ /* Start a alarm handling thread */
+ sigemptyset(&set);
+ sigaddset(&set,SIGINT);
+ sigaddset(&set,SIGQUIT);
+ sigaddset(&set,SIGTERM);
+ sigaddset(&set,SIGHUP);
+ signal(SIGTERM,SIG_DFL); /* If it's blocked by parent */
+#ifdef SIGTSTP
+ sigaddset(&set,SIGTSTP);
+#endif
+ sigaddset(&set,THR_SERVER_ALARM);
+ sigdelset(&set,THR_CLIENT_ALARM);
+ (void) pthread_sigmask(SIG_SETMASK,&set,NULL);
+#ifdef NOT_USED
+ sigemptyset(&set);
+ sigaddset(&set,THR_CLIENT_ALARM);
+ VOID(pthread_sigmask(SIG_UNBLOCK, &set, (sigset_t*) 0));
+#endif
+
+ pthread_attr_init(&thr_attr);
+ pthread_attr_setscope(&thr_attr,PTHREAD_SCOPE_PROCESS);
+ pthread_attr_setdetachstate(&thr_attr,PTHREAD_CREATE_DETACHED);
+ pthread_attr_setstacksize(&thr_attr,65536L);
+
+ /* Start signal thread and wait for it to start */
+ VOID(pthread_mutex_lock(&LOCK_thread_count));
+ pthread_create(&tid,&thr_attr,signal_hand,NULL);
+ VOID(pthread_cond_wait(&COND_thread_count,&LOCK_thread_count));
+ VOID(pthread_mutex_unlock(&LOCK_thread_count));
+ DBUG_PRINT("info",("signal thread created"));
+
+ thr_setconcurrency(3);
+ pthread_attr_setscope(&thr_attr,PTHREAD_SCOPE_PROCESS);
+ printf("Main thread: %s\n",my_thread_name());
+ for (i=0 ; i < 2 ; i++)
+ {
+ param=(int*) malloc(sizeof(int));
+ *param= i;
+ pthread_mutex_lock(&LOCK_thread_count);
+ if ((error=pthread_create(&tid,&thr_attr,test_thread,(void*) param)))
+ {
+ printf("Can't create thread %d, error: %d\n",i,error);
+ exit(1);
+ }
+ thread_count++;
+ pthread_mutex_unlock(&LOCK_thread_count);
+ }
+
+ pthread_attr_destroy(&thr_attr);
+ pthread_mutex_lock(&LOCK_thread_count);
+ while (thread_count)
+ {
+ VOID(pthread_cond_wait(&COND_thread_count,&LOCK_thread_count));
+ if (thread_count == 1)
+ {
+ printf("Calling end_thr_alarm. This should cancel the last thread\n");
+ end_thr_alarm();
+ }
+ }
+ pthread_mutex_unlock(&LOCK_thread_count);
+ printf("Test succeeded\n");
+ return 0;
+}
+#endif /* MAIN */
+
+#else /* DONT_USE_THR_ALARM */
+
+#ifdef MAIN
+int main(int argc __attribute__((unused)),char **argv __attribute__((unused)))
+{
+ printf("thr_alarm disabled with DONT_USE_THR_ALARM\n");
+ exit(1);
+}
+#endif
+#endif
+
+/*****************************************************************************
+** thr_alarm for OS/2
+*****************************************************************************/
+
+#elif defined(__OS2__)
+
+#define INCL_BASE
+#define INCL_NOPMAPI
+#include <os2.h>
+
+bool thr_alarm(thr_alarm_t *alrm, uint sec, ALARM *alarm)
+{
+ APIRET rc;
+ if (alarm_aborted)
+ {
+ alrm->crono=0;
+ alrm->event=0;
+ return 1;
+ }
+ if (!(rc = DosCreateEventSem(NULL,(HEV *)&alrm->event,DC_SEM_SHARED,FALSE)))
+ {
+ printf("Error creating event semaphore! [%d] \n",rc);
+ alrm->crono=0;
+ alrm->event=0;
+ return 1;
+ }
+ if (!(rc = DosAsyncTimer((long) sec*1000L, (HSEM) alrm->event,(HTIMER *) &alrm->crono))) {
+ printf("Error starting async timer! [%d] \n",rc);
+ DosCloseEventSem((HEV) alrm->event);
+ alrm->crono=0;
+ alrm->event=0;
+ return 1;
+ } /* endif */
+
+ return 1;
+}
+
+
+bool thr_got_alarm(thr_alarm_t *alrm)
+{
+ APIRET rc;
+
+ if (alrm->crono)
+ {
+ rc = DosWaitEventSem((HEV) alrm->event, SEM_IMMEDIATE_RETURN);
+ if (rc == 0) {
+ DosCloseEventSem((HEV) alrm->event);
+ alrm->crono = 0;
+ alrm->event = 0;
+ } /* endif */
+ }
+ return !alrm->crono || alarm_aborted;
+}
+
+
+void thr_end_alarm(thr_alarm_t *alrm)
+{
+ if (alrm->crono)
+ {
+ DosStopTimer((HTIMER) alrm->crono);
+ DosCloseEventSem((HEV) alrm->event);
+ alrm->crono = 0;
+ alrm->event = 0;
+ }
+}
+
+void end_thr_alarm(void)
+{
+ DBUG_ENTER("end_thr_alarm");
+ alarm_aborted=1; /* No more alarms */
+ DBUG_VOID_RETURN;
+}
+
+void init_thr_alarm(uint max_alarm)
+{
+ DBUG_ENTER("init_thr_alarm");
+ alarm_aborted=0; /* Yes, Gimmie alarms */
+ DBUG_VOID_RETURN;
+}
+
+#ifdef MAIN
+void main()
+{
+ printf("hello world\n");
+}
+#endif
+
+/*****************************************************************************
+** thr_alarm for win95
+*****************************************************************************/
+
+#else /* __WIN__ */
+
+bool thr_alarm(thr_alarm_t *alrm, uint sec, ALARM *alarm)
+{
+ if (alarm_aborted)
+ {
+ alrm->crono=0;
+ return 1;
+ }
+ if (!(alrm->crono=SetTimer(NULL,0,(long) sec*1000L, (TIMERPROC) NULL)))
+ return 1;
+ return 0;
+}
+
+
+bool thr_got_alarm(thr_alarm_t *alrm)
+{
+ MSG msg;
+ if (alrm->crono)
+ {
+ PeekMessage(&msg,NULL,WM_TIMER,WM_TIMER,PM_REMOVE) ;
+ if (msg.message == WM_TIMER || alarm_aborted)
+ {
+ KillTimer(NULL, alrm->crono);
+ alrm->crono = 0;
+ }
+ }
+ return !alrm->crono || alarm_aborted;
+}
+
+
+void thr_end_alarm(thr_alarm_t *alrm)
+{
+ if (alrm->crono)
+ {
+ KillTimer(NULL, alrm->crono);
+ alrm->crono = 0;
+ }
+}
+
+void end_thr_alarm(void)
+{
+ DBUG_ENTER("end_thr_alarm");
+ alarm_aborted=1; /* No more alarms */
+ DBUG_VOID_RETURN;
+}
+
+#endif /* __WIN__ */
+
+#endif
diff --git a/mysys/thr_lock.c b/mysys/thr_lock.c
new file mode 100644
index 00000000000..5c0803c6402
--- /dev/null
+++ b/mysys/thr_lock.c
@@ -0,0 +1,1288 @@
+/* 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 */
+
+/*
+Read and write locks for Posix threads. All tread must acquire
+all locks it needs through thr_multi_lock() to avoid dead-locks.
+A lock consists of a master lock (THR_LOCK), and lock instances
+(THR_LOCK_DATA).
+Any thread can have any number of lock instances (read and write:s) on
+any lock. All lock instances must be freed.
+Locks are prioritized according to:
+
+The current lock types are:
+
+TL_READ # Low priority read
+TL_READ_HIGH_PRIORITY # High priority read
+TL_READ_NO_INSERT # Read without concurrent inserts
+TL_WRITE_ALLOW_WRITE # Write lock that allows other writers
+TL_WRITE_ALLOW_READ # Write lock, but allow reading
+TL_WRITE_CONCURRENT_INSERT
+ # Insert that can be mixed when selects
+TL_WRITE_DELAYED # Used by delayed insert
+ # Allows lower locks to take over
+TL_WRITE_LOW_PRIORITY # Low priority write
+TL_WRITE # High priority write
+TL_WRITE_ONLY # High priority write
+ # Abort all new lock request with an error
+
+Locks are prioritized according to:
+
+WRITE_ALLOW_WRITE, WRITE_ALLOW_READ, WRITE_CONCURRENT_INSERT, WRITE_DELAYED,
+WRITE_LOW_PRIORITY, READ, WRITE, READ_HIGH_PRIORITY and WRITE_ONLY
+
+Locks in the same privilege level are scheduled in first-in-first-out order.
+
+To allow concurrent read/writes locks, with 'WRITE_CONCURRENT_INSERT' one
+should put a pointer to the following functions in the lock structure:
+(If the pointer is zero (default), the function is not called)
+
+check_status:
+ Before giving a lock of type TL_WRITE_CONCURRENT_INSERT,
+ we check if this function exists and returns 0.
+ If not, then the lock is upgraded to TL_WRITE_LOCK
+ In MyISAM this is a simple check if the insert can be done
+ at the end of the datafile.
+update_status:
+ Before a write lock is released, this function is called.
+ In MyISAM this functions updates the count and length of the datafile
+get_status:
+ When one gets a lock this functions is called.
+ In MyISAM this stores the number of rows and size of the datafile
+ for concurrent reads.
+
+The lock algorithm allows one to have one TL_WRITE_ALLOW_READ,
+TL_WRITE_CONCURRENT_INSERT or one TL_WRITE_DELAYED lock at the same time as
+multiple read locks.
+
+*/
+
+#if !defined(MAIN) && !defined(DBUG_OFF) && !defined(EXTRA_DEBUG)
+#define DBUG_OFF
+#endif
+
+#include "mysys_priv.h"
+#include "thr_lock.h"
+#include <m_string.h>
+#include <errno.h>
+
+my_bool thr_lock_inited=0;
+
+#ifdef THREAD
+
+/* The following constants are only for debug output */
+#define MAX_THREADS 100
+#define MAX_LOCKS 100
+
+
+static LIST *thread_list; /* List of threads in use */
+ulong max_write_lock_count= ~(ulong) 0L;
+
+static inline pthread_cond_t *get_cond(void)
+{
+ return &my_thread_var->suspend;
+}
+
+/*
+** For the future (now the thread specific cond is alloced by my_pthread.c)
+*/
+
+my_bool init_thr_lock()
+{
+ thr_lock_inited=1;
+ return 0;
+}
+
+#ifdef EXTRA_DEBUG
+static int found_errors=0;
+
+static int check_lock(struct st_lock_list *list, const char* lock_type,
+ const char *where, my_bool same_thread)
+{
+ THR_LOCK_DATA *data,**prev;
+ uint count=0;
+ pthread_t first_thread;
+ LINT_INIT(first_thread);
+
+ prev= &list->data;
+ if (list->data)
+ {
+ enum thr_lock_type last_lock_type=list->data->type;
+
+ if (same_thread && list->data)
+ first_thread=list->data->thread;
+ for (data=list->data; data && count++ < MAX_LOCKS ; data=data->next)
+ {
+ if (data->type != last_lock_type)
+ last_lock_type=TL_IGNORE;
+ if (data->prev != prev)
+ {
+ fprintf(stderr,
+ "Warning: prev link %d didn't point at previous lock at %s: %s\n",
+ count, lock_type, where);
+ return 1;
+ }
+ if (same_thread && ! pthread_equal(data->thread,first_thread) &&
+ last_lock_type != TL_WRITE_ALLOW_WRITE)
+ {
+ fprintf(stderr,
+ "Warning: Found locks from different threads in %s: %s\n",
+ lock_type,where);
+ return 1;
+ }
+ prev= &data->next;
+ }
+ if (data)
+ {
+ fprintf(stderr,"Warning: found too many locks at %s: %s\n",
+ lock_type,where);
+ return 1;
+ }
+ }
+ if (prev != list->last)
+ {
+ fprintf(stderr,"Warning: last didn't point at last lock at %s: %s\n",
+ lock_type, where);
+ return 1;
+ }
+ return 0;
+}
+
+static void check_locks(THR_LOCK *lock, const char *where,
+ my_bool allow_no_locks)
+{
+ if (!found_errors)
+ {
+ if (check_lock(&lock->write,"write",where,1) |
+ check_lock(&lock->write_wait,"write_wait",where,0) |
+ check_lock(&lock->read,"read",where,0) |
+ check_lock(&lock->read_wait,"read_wait",where,0))
+ found_errors=1;
+
+ if (!found_errors)
+ {
+ uint count=0;
+ THR_LOCK_DATA *data;
+ for (data=lock->read.data ; data ; data=data->next)
+ {
+ if ((int) data->type == (int) TL_READ_NO_INSERT)
+ count++;
+ }
+ if (count != lock->read_no_write_count)
+ {
+ found_errors=1;
+ fprintf(stderr,
+ "Warning at '%s': Locks read_no_write_count was %u when it should have been %u\n", where, lock->read_no_write_count,count);
+ }
+
+ if (!lock->write.data)
+ {
+ if (!allow_no_locks && !lock->read.data &&
+ (lock->write_wait.data || lock->read_wait.data))
+ {
+ found_errors=1;
+ fprintf(stderr,
+ "Warning at '%s': No locks in use but locks are in wait queue\n",
+ where);
+ }
+ if (!lock->write_wait.data)
+ {
+ if (!allow_no_locks && lock->read_wait.data)
+ {
+ found_errors=1;
+ fprintf(stderr,
+ "Warning at '%s': No write locks and waiting read locks\n",
+ where);
+ }
+ }
+ else
+ {
+ if (!allow_no_locks &&
+ (((lock->write_wait.data->type == TL_WRITE_CONCURRENT_INSERT ||
+ lock->write_wait.data->type == TL_WRITE_ALLOW_WRITE) &&
+ !lock->read_no_write_count) ||
+ lock->write_wait.data->type == TL_WRITE_ALLOW_READ ||
+ (lock->write_wait.data->type == TL_WRITE_DELAYED &&
+ !lock->read.data)))
+ {
+ found_errors=1;
+ fprintf(stderr,
+ "Warning at '%s': Write lock %d waiting while no exclusive read locks\n",where,(int) lock->write_wait.data->type);
+ }
+ }
+ }
+ else
+ { /* Have write lock */
+ if (lock->write_wait.data)
+ {
+ if (!allow_no_locks &&
+ lock->write.data->type == TL_WRITE_ALLOW_WRITE &&
+ lock->write_wait.data->type == TL_WRITE_ALLOW_WRITE)
+ {
+ found_errors=1;
+ fprintf(stderr,
+ "Warning at '%s': Found WRITE_ALLOW_WRITE lock waiting for WRITE_ALLOW_WRITE lock\n",
+ where);
+ }
+ }
+ if (lock->read.data)
+ {
+ if ((!pthread_equal(lock->write.data->thread,lock->read.data->thread) &&
+ lock->write.data->type > TL_WRITE_DELAYED) ||
+ ((lock->write.data->type == TL_WRITE_CONCURRENT_INSERT ||
+ lock->write.data->type == TL_WRITE_ALLOW_WRITE) &&
+ lock->read_no_write_count))
+ {
+ found_errors=1;
+ fprintf(stderr,
+ "Warning at '%s': Found lock that is write and read locked\n",
+ where);
+ }
+ }
+ if (lock->read_wait.data)
+ {
+ if (!allow_no_locks && lock->write.data->type <= TL_WRITE_DELAYED &&
+ lock->read_wait.data->type <= TL_READ_HIGH_PRIORITY)
+ {
+ found_errors=1;
+ fprintf(stderr,
+ "Warning at '%s': Found read lock of type %d waiting for write lock of type %d\n",
+ where,
+ (int) lock->read_wait.data->type,
+ (int) lock->write.data->type);
+ }
+ }
+ }
+ }
+ if (found_errors)
+ {
+ DBUG_PRINT("error",("Found wrong lock"));
+ }
+ }
+}
+
+#else /* EXTRA_DEBUG */
+#define check_locks(A,B,C)
+#endif
+
+
+ /* Initialize a lock */
+
+void thr_lock_init(THR_LOCK *lock)
+{
+ DBUG_ENTER("thr_lock_init");
+ bzero((char*) lock,sizeof(*lock));
+ VOID(pthread_mutex_init(&lock->mutex,NULL));
+ lock->read.last= &lock->read.data;
+ lock->read_wait.last= &lock->read_wait.data;
+ lock->write_wait.last= &lock->write_wait.data;
+ lock->write.last= &lock->write.data;
+
+ pthread_mutex_lock(&THR_LOCK_lock); /* Add to locks in use */
+ lock->list.data=(void*) lock;
+ thread_list=list_add(thread_list,&lock->list);
+ pthread_mutex_unlock(&THR_LOCK_lock);
+ DBUG_VOID_RETURN;
+}
+
+
+void thr_lock_delete(THR_LOCK *lock)
+{
+ DBUG_ENTER("thr_lock_delete");
+ VOID(pthread_mutex_destroy(&lock->mutex));
+ pthread_mutex_lock(&THR_LOCK_lock);
+ thread_list=list_delete(thread_list,&lock->list);
+ pthread_mutex_unlock(&THR_LOCK_lock);
+ DBUG_VOID_RETURN;
+}
+
+ /* Initialize a lock instance */
+
+void thr_lock_data_init(THR_LOCK *lock,THR_LOCK_DATA *data, void *param)
+{
+ data->lock=lock;
+ data->type=TL_UNLOCK;
+ data->thread=pthread_self();
+ data->thread_id=my_thread_id(); /* for debugging */
+ data->status_param=param;
+}
+
+
+static inline my_bool have_old_read_lock(THR_LOCK_DATA *data,pthread_t thread)
+{
+ for ( ; data ; data=data->next)
+ {
+ if ((pthread_equal(data->thread,thread)))
+ return 1; /* Already locked by thread */
+ }
+ return 0;
+}
+
+static inline my_bool have_specific_lock(THR_LOCK_DATA *data,
+ enum thr_lock_type type)
+{
+ for ( ; data ; data=data->next)
+ {
+ if (data->type == type)
+ return 1;
+ }
+ return 0;
+}
+
+
+static my_bool wait_for_lock(struct st_lock_list *wait, THR_LOCK_DATA *data,
+ my_bool in_wait_list)
+{
+ pthread_cond_t *cond=get_cond();
+ struct st_my_thread_var *thread_var=my_thread_var;
+ int result;
+
+ if (!in_wait_list)
+ {
+ (*wait->last)=data; /* Wait for lock */
+ data->prev= wait->last;
+ wait->last= &data->next;
+ }
+
+ /* Set up control struct to allow others to abort locks */
+ pthread_mutex_lock(&thread_var->mutex);
+ thread_var->current_mutex= &data->lock->mutex;
+ thread_var->current_cond= cond;
+ pthread_mutex_unlock(&thread_var->mutex);
+
+ data->cond=cond;
+ do
+ {
+ pthread_cond_wait(cond,&data->lock->mutex);
+ } while (data->cond == cond && !thread_var->abort);
+
+ if (data->cond || data->type == TL_UNLOCK)
+ {
+ if (data->cond) /* aborted */
+ {
+ if (((*data->prev)=data->next)) /* remove from wait-list */
+ data->next->prev= data->prev;
+ else
+ wait->last=data->prev;
+ }
+ data->type=TL_UNLOCK; /* No lock */
+ result=1; /* Didn't get lock */
+ check_locks(data->lock,"failed wait_for_lock",0);
+ }
+ else
+ {
+ result=0;
+ if (data->lock->get_status)
+ (*data->lock->get_status)(data->status_param);
+ check_locks(data->lock,"got wait_for_lock",0);
+ }
+ pthread_mutex_unlock(&data->lock->mutex);
+
+ /* The following must be done after unlock of lock->mutex */
+ pthread_mutex_lock(&thread_var->mutex);
+ thread_var->current_mutex= 0;
+ thread_var->current_cond= 0;
+ pthread_mutex_unlock(&thread_var->mutex);
+ return result;
+}
+
+
+int thr_lock(THR_LOCK_DATA *data,enum thr_lock_type lock_type)
+{
+ THR_LOCK *lock=data->lock;
+ int result=0;
+ DBUG_ENTER("thr_lock");
+
+ data->next=0;
+ data->type=lock_type;
+ data->thread=pthread_self(); /* Must be reset ! */
+ data->thread_id=my_thread_id(); /* Must be reset ! */
+ VOID(pthread_mutex_lock(&lock->mutex));
+ DBUG_PRINT("lock",("data: %lx thread: %ld lock: %lx type: %d",
+ data,data->thread_id,lock,(int) lock_type));
+ check_locks(lock,(uint) lock_type <= (uint) TL_READ_NO_INSERT ?
+ "enter read_lock" : "enter write_lock",0);
+ if ((int) lock_type <= (int) TL_READ_NO_INSERT)
+ {
+ /* Request for READ lock */
+ if (lock->write.data)
+ {
+ /* We can get allow a read lock even if there is already a write lock
+ one the table in one the following cases:
+ - This thread alread have a write lock on the table
+ - The write lock is TL_WRITE_ALLOW_READ or TL_WRITE_DELAYED
+ and the read lock is TL_READ_HIGH_PRIORITY or TL_READ
+ - The write lock is TL_WRITE_CONCURRENT_INSERT or TL_WRITE_ALLOW_WRITE
+ and the read lock is not TL_READ_NO_INSERT
+ */
+
+ DBUG_PRINT("lock",("write locked by thread: %ld",
+ lock->write.data->thread_id));
+ if (pthread_equal(data->thread,lock->write.data->thread) ||
+ (lock->write.data->type <= TL_WRITE_DELAYED &&
+ (((int) lock_type <= (int) TL_READ_HIGH_PRIORITY) ||
+ (lock->write.data->type != TL_WRITE_CONCURRENT_INSERT &&
+ lock->write.data->type != TL_WRITE_ALLOW_READ))))
+ { /* Already got a write lock */
+ (*lock->read.last)=data; /* Add to running FIFO */
+ data->prev=lock->read.last;
+ lock->read.last= &data->next;
+ if ((int) lock_type == (int) TL_READ_NO_INSERT)
+ lock->read_no_write_count++;
+ check_locks(lock,"read lock with old write lock",0);
+ if (lock->get_status)
+ (*lock->get_status)(data->status_param);
+ goto end;
+ }
+ if (lock->write.data->type == TL_WRITE_ONLY)
+ {
+ /* We are not allowed to get a READ lock in this case */
+ data->type=TL_UNLOCK;
+ result=1; /* Can't wait for this one */
+ goto end;
+ }
+ }
+ else if (!lock->write_wait.data ||
+ lock->write_wait.data->type <= TL_WRITE_LOW_PRIORITY ||
+ lock_type == TL_READ_HIGH_PRIORITY ||
+ have_old_read_lock(lock->read.data,data->thread))
+ { /* No important write-locks */
+ (*lock->read.last)=data; /* Add to running FIFO */
+ data->prev=lock->read.last;
+ lock->read.last= &data->next;
+ if (lock->get_status)
+ (*lock->get_status)(data->status_param);
+ if ((int) lock_type == (int) TL_READ_NO_INSERT)
+ lock->read_no_write_count++;
+ check_locks(lock,"read lock with no write locks",0);
+ goto end;
+ }
+ /* Can't get lock yet; Wait for it */
+ DBUG_RETURN(wait_for_lock(&lock->read_wait,data,0));
+ }
+ else /* Request for WRITE lock */
+ {
+ if (lock_type == TL_WRITE_DELAYED)
+ {
+ if (lock->write.data && lock->write.data->type == TL_WRITE_ONLY)
+ {
+ data->type=TL_UNLOCK;
+ result=1; /* Can't wait for this one */
+ goto end;
+ }
+ /*
+ if there is a TL_WRITE_ALLOW_READ lock, we have to wait for a lock
+ (TL_WRITE_ALLOW_READ is used for ALTER TABLE in MySQL)
+ */
+ if ((!lock->write.data ||
+ lock->write.data->type != TL_WRITE_ALLOW_READ) &&
+ !have_specific_lock(lock->write_wait.data,TL_WRITE_ALLOW_READ) &&
+ (lock->write.data || lock->read.data))
+ {
+ /* Add delayed write lock to write_wait queue, and return at once */
+ (*lock->write_wait.last)=data;
+ data->prev=lock->write_wait.last;
+ lock->write_wait.last= &data->next;
+ data->cond=get_cond();
+ if (lock->get_status)
+ (*lock->get_status)(data->status_param);
+ goto end;
+ }
+ }
+ else if (lock_type == TL_WRITE_CONCURRENT_INSERT && ! lock->check_status)
+ data->type=lock_type= TL_WRITE; /* not supported */
+
+ if (lock->write.data) /* If there is a write lock */
+ {
+ if (lock->write.data->type == TL_WRITE_ONLY)
+ {
+ /* We are not allowed to get a lock in this case */
+ data->type=TL_UNLOCK;
+ result=1; /* Can't wait for this one */
+ goto end;
+ }
+
+ /*
+ The following test will not work if the old lock was a
+ TL_WRITE_ALLOW_WRITE, TL_WRITE_ALLOW_READ or TL_WRITE_DELAYED in
+ the same thread, but this will never happen within MySQL.
+ */
+ if (pthread_equal(data->thread,lock->write.data->thread) ||
+ (lock_type == TL_WRITE_ALLOW_WRITE &&
+ !lock->write_wait.data &&
+ lock->write.data->type == TL_WRITE_ALLOW_WRITE))
+ {
+ /* We have already got a write lock or all locks are
+ TL_WRITE_ALLOW_WRITE */
+ (*lock->write.last)=data; /* Add to running fifo */
+ data->prev=lock->write.last;
+ lock->write.last= &data->next;
+ check_locks(lock,"second write lock",0);
+ if (data->lock->get_status)
+ (*data->lock->get_status)(data->status_param);
+ goto end;
+ }
+ DBUG_PRINT("lock",("write locked by thread: %ld",
+ lock->write.data->thread_id));
+ }
+ else
+ {
+ if (!lock->write_wait.data)
+ { /* no scheduled write locks */
+ if (lock_type == TL_WRITE_CONCURRENT_INSERT &&
+ (*lock->check_status)(data->status_param))
+ data->type=lock_type=TL_WRITE; /* Upgrade lock */
+
+ if (!lock->read.data ||
+ (lock_type <= TL_WRITE_DELAYED &&
+ ((lock_type != TL_WRITE_CONCURRENT_INSERT &&
+ lock_type != TL_WRITE_ALLOW_WRITE) ||
+ !lock->read_no_write_count)))
+ {
+ (*lock->write.last)=data; /* Add as current write lock */
+ data->prev=lock->write.last;
+ lock->write.last= &data->next;
+ if (data->lock->get_status)
+ (*data->lock->get_status)(data->status_param);
+ check_locks(lock,"only write lock",0);
+ goto end;
+ }
+ }
+ DBUG_PRINT("lock",("write locked by thread: %ld, type: %ld",
+ lock->read.data->thread_id,data->type));
+ }
+ DBUG_RETURN(wait_for_lock(&lock->write_wait,data,0));
+ }
+end:
+ pthread_mutex_unlock(&lock->mutex);
+ DBUG_RETURN(result);
+}
+
+
+static inline void free_all_read_locks(THR_LOCK *lock,
+ bool using_concurrent_insert)
+{
+ THR_LOCK_DATA *data=lock->read_wait.data;
+
+ check_locks(lock,"before freeing read locks",1);
+
+ /* move all locks from read_wait list to read list */
+ (*lock->read.last)=data;
+ data->prev=lock->read.last;
+ lock->read.last=lock->read_wait.last;
+
+ /* Clear read_wait list */
+ lock->read_wait.last= &lock->read_wait.data;
+
+ do
+ {
+ pthread_cond_t *cond=data->cond;
+ if ((int) data->type == (int) TL_READ_NO_INSERT)
+ {
+ if (using_concurrent_insert)
+ {
+ /*
+ We can't free this lock;
+ Link lock away from read chain back into read_wait chain
+ */
+ if (((*data->prev)=data->next))
+ data->next->prev=data->prev;
+ else
+ lock->read.last=data->prev;
+ *lock->read_wait.last= data;
+ data->prev= lock->read_wait.last;
+ lock->read_wait.last= &data->next;
+ continue;
+ }
+ lock->read_no_write_count++;
+ }
+ DBUG_PRINT("lock",("giving read lock to thread: %ld",
+ data->thread_id));
+ data->cond=0; /* Mark thread free */
+ VOID(pthread_cond_signal(cond));
+ } while ((data=data->next));
+ *lock->read_wait.last=0;
+ if (!lock->read_wait.data)
+ lock->write_lock_count=0;
+ check_locks(lock,"after giving read locks",0);
+}
+
+ /* Unlock lock and free next thread on same lock */
+
+void thr_unlock(THR_LOCK_DATA *data)
+{
+ THR_LOCK *lock=data->lock;
+ enum thr_lock_type lock_type=data->type;
+ DBUG_ENTER("thr_unlock");
+ DBUG_PRINT("lock",("data: %lx thread: %ld lock: %lx",
+ data,data->thread_id,lock));
+ pthread_mutex_lock(&lock->mutex);
+ check_locks(lock,"start of release lock",0);
+
+ if (((*data->prev)=data->next)) /* remove from lock-list */
+ data->next->prev= data->prev;
+ else if (lock_type <= TL_READ_NO_INSERT)
+ lock->read.last=data->prev;
+ else if (lock_type == TL_WRITE_DELAYED && data->cond)
+ {
+ /* This only happens in extreme circumstances when a
+ write delayed lock that is waiting for a lock */
+ lock->write_wait.last=data->prev; /* Put it on wait queue */
+ }
+ else
+ lock->write.last=data->prev;
+ if (lock_type >= TL_WRITE_CONCURRENT_INSERT && lock->update_status)
+ (*lock->update_status)(data->status_param);
+ if (lock_type == TL_READ_NO_INSERT)
+ lock->read_no_write_count--;
+ data->type=TL_UNLOCK; /* Mark unlocked */
+ check_locks(lock,"after releasing lock",1);
+
+ if (!lock->write.data) /* If no active read locks */
+ {
+ data=lock->write_wait.data;
+ if (!lock->read.data) /* If no more locks in use */
+ {
+ /* Release write-locks with TL_WRITE or TL_WRITE_ONLY priority first */
+ if (data &&
+ (data->type != TL_WRITE_LOW_PRIORITY || !lock->read_wait.data ||
+ lock->read_wait.data->type == TL_READ))
+ {
+ if (lock->write_lock_count++ > max_write_lock_count)
+ {
+ /* Too many write locks in a row; Release all waiting read locks */
+ lock->write_lock_count=0;
+ if (lock->read_wait.data)
+ {
+ DBUG_PRINT("info",("Freeing all read_locks because of max_write_lock_count"));
+ free_all_read_locks(lock,0);
+ goto end;
+ }
+ }
+ for (;;)
+ {
+ if (((*data->prev)=data->next)) /* remove from wait-list */
+ data->next->prev= data->prev;
+ else
+ lock->write_wait.last=data->prev;
+ (*lock->write.last)=data; /* Put in execute list */
+ data->prev=lock->write.last;
+ data->next=0;
+ lock->write.last= &data->next;
+ if (data->type == TL_WRITE_CONCURRENT_INSERT &&
+ (*lock->check_status)(data->status_param))
+ data->type=TL_WRITE; /* Upgrade lock */
+ DBUG_PRINT("lock",("giving write lock of type %d to thread: %ld",
+ data->type,data->thread_id));
+ {
+ pthread_cond_t *cond=data->cond;
+ data->cond=0; /* Mark thread free */
+ VOID(pthread_cond_signal(cond)); /* Start waiting thread */
+ }
+ if (data->type != TL_WRITE_ALLOW_WRITE ||
+ !lock->write_wait.data ||
+ lock->write_wait.data->type != TL_WRITE_ALLOW_WRITE)
+ break;
+ data=lock->write_wait.data; /* Free this too */
+ }
+ if (data->type >= TL_WRITE_LOW_PRIORITY)
+ {
+ check_locks(lock,"giving write lock",0);
+ pthread_mutex_unlock(&lock->mutex);
+ DBUG_VOID_RETURN;
+ }
+ /* Release possible read locks together with the write lock */
+ }
+ if (lock->read_wait.data)
+ free_all_read_locks(lock,
+ data &&
+ (data->type == TL_WRITE_CONCURRENT_INSERT ||
+ data->type == TL_WRITE_ALLOW_WRITE));
+ else
+ {
+ DBUG_PRINT("lock",("No locks to free"));
+ }
+ }
+ else if (data &&
+ (lock_type=data->type) <= TL_WRITE_DELAYED &&
+ ((lock_type != TL_WRITE_CONCURRENT_INSERT &&
+ lock_type != TL_WRITE_ALLOW_WRITE) ||
+ !lock->read_no_write_count))
+ {
+ /*
+ For DELAYED, ALLOW_READ, WRITE_ALLOW_WRITE or CONCURRENT_INSERT locks
+ start WRITE locks together with the READ locks
+ */
+ if (lock_type == TL_WRITE_CONCURRENT_INSERT &&
+ (*lock->check_status)(data->status_param))
+ {
+ data->type=TL_WRITE; /* Upgrade lock */
+ if (lock->read_wait.data)
+ free_all_read_locks(lock,0);
+ goto end;
+ }
+ do {
+ pthread_cond_t *cond=data->cond;
+ if (((*data->prev)=data->next)) /* remove from wait-list */
+ data->next->prev= data->prev;
+ else
+ lock->write_wait.last=data->prev;
+ (*lock->write.last)=data; /* Put in execute list */
+ data->prev=lock->write.last;
+ lock->write.last= &data->next;
+ data->next=0; /* Only one write lock */
+ data->cond=0; /* Mark thread free */
+ VOID(pthread_cond_signal(cond)); /* Start waiting thread */
+ } while (lock_type == TL_WRITE_ALLOW_WRITE &&
+ (data=lock->write_wait.data) &&
+ data->type == TL_WRITE_ALLOW_WRITE);
+ if (lock->read_wait.data)
+ free_all_read_locks(lock,
+ (lock_type == TL_WRITE_CONCURRENT_INSERT ||
+ lock_type == TL_WRITE_ALLOW_WRITE));
+ }
+ else if (lock->read_wait.data)
+ free_all_read_locks(lock,0);
+ }
+end:
+ check_locks(lock,"thr_unlock",0);
+ pthread_mutex_unlock(&lock->mutex);
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+** Get all locks in a specific order to avoid dead-locks
+** Sort acording to lock position and put write_locks before read_locks if
+** lock on same lock.
+*/
+
+
+#define LOCK_CMP(A,B) ((byte*) (A->lock) - (uint) ((A)->type) < (byte*) (B->lock)- (uint) ((B)->type))
+
+static void sort_locks(THR_LOCK_DATA **data,uint count)
+{
+ THR_LOCK_DATA **pos,**end,**prev,*tmp;
+
+ /* Sort locks with insertion sort (fast because almost always few locks) */
+
+ for (pos=data+1,end=data+count; pos < end ; pos++)
+ {
+ tmp= *pos;
+ if (LOCK_CMP(tmp,pos[-1]))
+ {
+ prev=pos;
+ do {
+ prev[0]=prev[-1];
+ } while (--prev != data && LOCK_CMP(tmp,prev[-1]));
+ prev[0]=tmp;
+ }
+ }
+}
+
+
+int thr_multi_lock(THR_LOCK_DATA **data,uint count)
+{
+ THR_LOCK_DATA **pos,**end;
+ DBUG_ENTER("thr_multi_lock");
+ DBUG_PRINT("lock",("data: %lx count: %d",data,count));
+ if (count > 1)
+ sort_locks(data,count);
+ /* lock everything */
+ for (pos=data,end=data+count; pos < end ; pos++)
+ {
+ if (thr_lock(*pos,(*pos)->type))
+ { /* Aborted */
+ thr_multi_unlock(data,(uint) (pos-data));
+ DBUG_RETURN(1);
+ }
+#ifdef MAIN
+ printf("Thread: %s Got lock: %lx type: %d\n",my_thread_name(),
+ (long) pos[0]->lock, pos[0]->type); fflush(stdout);
+#endif
+ }
+ /*
+ Ensure that all get_locks() have the same status
+ If we lock the same table multiple times, we must use the same
+ status_param!
+ */
+#if !defined(DONT_USE_RW_LOCKS)
+ if (count > 1)
+ {
+ THR_LOCK_DATA *last_lock= end[-1];
+ pos=end-1;
+ do
+ {
+ pos--;
+ if (last_lock->lock == (*pos)->lock &&
+ last_lock->lock->copy_status)
+ {
+ if (last_lock->type <= TL_READ_NO_INSERT)
+ {
+ THR_LOCK_DATA **read_lock;
+ /*
+ If we are locking the same table with read locks we must ensure
+ that all tables share the status of the last write lock or
+ the same read lock.
+ */
+ for (;
+ (*pos)->type <= TL_READ_NO_INSERT &&
+ pos != data &&
+ pos[-1]->lock == (*pos)->lock ;
+ pos--) ;
+
+ read_lock = pos+1;
+ do
+ {
+ (last_lock->lock->copy_status)((*read_lock)->status_param,
+ (*pos)->status_param);
+ } while (*(read_lock++) != last_lock);
+ last_lock= (*pos); /* Point at last write lock */
+ }
+ else
+ (*last_lock->lock->copy_status)((*pos)->status_param,
+ last_lock->status_param);
+ }
+ else
+ last_lock=(*pos);
+ } while (pos != data);
+ }
+#endif
+ DBUG_RETURN(0);
+}
+
+ /* free all locks */
+
+void thr_multi_unlock(THR_LOCK_DATA **data,uint count)
+{
+ THR_LOCK_DATA **pos,**end;
+ DBUG_ENTER("thr_multi_unlock");
+ DBUG_PRINT("lock",("data: %lx count: %d",data,count));
+
+ for (pos=data,end=data+count; pos < end ; pos++)
+ {
+#ifdef MAIN
+ printf("Thread: %s Rel lock: %lx type: %d\n",
+ my_thread_name(), (long) pos[0]->lock, pos[0]->type);
+ fflush(stdout);
+#endif
+ if ((*pos)->type != TL_UNLOCK)
+ thr_unlock(*pos);
+ else
+ {
+ DBUG_PRINT("lock",("Free lock: data: %lx thread: %ld lock: %lx",
+ *pos,(*pos)->thread_id,(*pos)->lock));
+ }
+ }
+ DBUG_VOID_RETURN;
+}
+
+/* Abort all threads waiting for a lock. The lock will be upgraded to a
+ TL_WRITE_ONLY to abort any new accesses to the lock
+*/
+
+void thr_abort_locks(THR_LOCK *lock)
+{
+ THR_LOCK_DATA *data;
+ DBUG_ENTER("thr_abort_locks");
+ pthread_mutex_lock(&lock->mutex);
+
+ for (data=lock->read_wait.data; data ; data=data->next)
+ {
+ data->type=TL_UNLOCK; /* Mark killed */
+ pthread_cond_signal(data->cond);
+ data->cond=0; /* Removed from list */
+ }
+ for (data=lock->write_wait.data; data ; data=data->next)
+ {
+ data->type=TL_UNLOCK;
+ pthread_cond_signal(data->cond);
+ data->cond=0;
+ }
+ lock->read_wait.last= &lock->read_wait.data;
+ lock->write_wait.last= &lock->write_wait.data;
+ lock->read_wait.data=lock->write_wait.data=0;
+ if (lock->write.data)
+ lock->write.data->type=TL_WRITE_ONLY;
+ pthread_mutex_unlock(&lock->mutex);
+ DBUG_VOID_RETURN;
+}
+
+
+/* Upgrade a WRITE_DELAY lock to a WRITE_LOCK */
+
+my_bool thr_upgrade_write_delay_lock(THR_LOCK_DATA *data)
+{
+ THR_LOCK *lock=data->lock;
+ DBUG_ENTER("thr_upgrade_write_delay_lock");
+
+ pthread_mutex_lock(&lock->mutex);
+ if (data->type == TL_UNLOCK || data->type == TL_WRITE) /* Aborted */
+ {
+ pthread_mutex_unlock(&lock->mutex);
+ DBUG_RETURN(data->type == TL_UNLOCK);
+ }
+ check_locks(lock,"before upgrading lock",0);
+ /* TODO: Upgrade to TL_WRITE_CONCURRENT_INSERT in some cases */
+ data->type=TL_WRITE; /* Upgrade lock */
+
+ /* Check if someone has given us the lock */
+ if (!data->cond)
+ {
+ if (!lock->read.data) /* No read locks */
+ { /* We have the lock */
+ if (data->lock->get_status)
+ (*data->lock->get_status)(data->status_param);
+ pthread_mutex_unlock(&lock->mutex);
+ DBUG_RETURN(0);
+ }
+
+ if (((*data->prev)=data->next)) /* remove from lock-list */
+ data->next->prev= data->prev;
+ else
+ lock->write.last=data->prev;
+
+ if ((data->next=lock->write_wait.data)) /* Put first in lock_list */
+ data->next->prev= &data->next;
+ else
+ lock->write_wait.last= &data->next;
+ data->prev= &lock->write_wait.data;
+ lock->write_wait.data=data;
+ check_locks(lock,"upgrading lock",0);
+ }
+ DBUG_RETURN(wait_for_lock(&lock->write_wait,data,1));
+}
+
+
+/* downgrade a WRITE lock to a WRITE_DELAY lock if there is pending locks */
+
+my_bool thr_reschedule_write_lock(THR_LOCK_DATA *data)
+{
+ THR_LOCK *lock=data->lock;
+ DBUG_ENTER("thr_reschedule_write_lock");
+
+ pthread_mutex_lock(&lock->mutex);
+ if (!lock->read_wait.data) /* No waiting read locks */
+ {
+ pthread_mutex_unlock(&lock->mutex);
+ DBUG_RETURN(0);
+ }
+
+ data->type=TL_WRITE_DELAYED;
+ if (lock->update_status)
+ (*lock->update_status)(data->status_param);
+ if (((*data->prev)=data->next)) /* remove from lock-list */
+ data->next->prev= data->prev;
+ else
+ lock->write.last=data->prev;
+
+ if ((data->next=lock->write_wait.data)) /* Put first in lock_list */
+ data->next->prev= &data->next;
+ else
+ lock->write_wait.last= &data->next;
+ data->prev= &lock->write_wait.data;
+ data->cond=get_cond(); /* This was zero */
+ lock->write_wait.data=data;
+ free_all_read_locks(lock,0);
+
+ pthread_mutex_unlock(&lock->mutex);
+ DBUG_RETURN(thr_upgrade_write_delay_lock(data));
+}
+
+
+#include <my_sys.h>
+
+static void thr_print_lock(const char* name,struct st_lock_list *list)
+{
+ THR_LOCK_DATA *data,**prev;
+ uint count=0;
+
+ if (list->data)
+ {
+ printf("%-10s: ",name);
+ prev= &list->data;
+ for (data=list->data; data && count++ < MAX_LOCKS ; data=data->next)
+ {
+ printf("%lx (%lu:%d); ",(ulong) data,data->thread_id,(int) data->type);
+ if (data->prev != prev)
+ printf("\nWarning: prev didn't point at previous lock\n");
+ prev= &data->next;
+ }
+ puts("");
+ if (prev != list->last)
+ printf("Warning: last didn't point at last lock\n");
+ }
+}
+
+void thr_print_locks(void)
+{
+ LIST *list;
+ uint count=0;
+
+ pthread_mutex_lock(&THR_LOCK_lock);
+ puts("Current locks:");
+ for (list=thread_list ; list && count++ < MAX_THREADS ; list=rest(list))
+ {
+ THR_LOCK *lock=(THR_LOCK*) list->data;
+ VOID(pthread_mutex_lock(&lock->mutex));
+ printf("lock: %lx:",(ulong) lock);
+ if ((lock->write_wait.data || lock->read_wait.data) &&
+ (! lock->read.data && ! lock->write.data))
+ printf(" WARNING: ");
+ if (lock->write.data)
+ printf(" write");
+ if (lock->write_wait.data)
+ printf(" write_wait");
+ if (lock->read.data)
+ printf(" read");
+ if (lock->read_wait.data)
+ printf(" read_wait");
+ puts("");
+ thr_print_lock("write",&lock->write);
+ thr_print_lock("write_wait",&lock->write_wait);
+ thr_print_lock("read",&lock->read);
+ thr_print_lock("read_wait",&lock->read_wait);
+ VOID(pthread_mutex_unlock(&lock->mutex));
+ puts("");
+ }
+ fflush(stdout);
+ pthread_mutex_unlock(&THR_LOCK_lock);
+}
+
+#ifdef MAIN
+
+struct st_test {
+ uint lock_nr;
+ enum thr_lock_type lock_type;
+};
+
+THR_LOCK locks[5]; /* 4 locks */
+
+struct st_test test_0[] = {{0,TL_READ}}; /* One lock */
+struct st_test test_1[] = {{0,TL_READ},{0,TL_WRITE}}; /* Read and write lock of lock 0 */
+struct st_test test_2[] = {{1,TL_WRITE},{0,TL_READ},{2,TL_READ}};
+struct st_test test_3[] = {{2,TL_WRITE},{1,TL_READ},{0,TL_READ}}; /* Deadlock with test_2 ? */
+struct st_test test_4[] = {{0,TL_WRITE},{0,TL_READ},{0,TL_WRITE},{0,TL_READ}};
+struct st_test test_5[] = {{0,TL_READ},{1,TL_READ},{2,TL_READ},{3,TL_READ}}; /* Many reads */
+struct st_test test_6[] = {{0,TL_WRITE},{1,TL_WRITE},{2,TL_WRITE},{3,TL_WRITE}}; /* Many writes */
+struct st_test test_7[] = {{3,TL_READ}};
+struct st_test test_8[] = {{1,TL_READ_NO_INSERT},{2,TL_READ_NO_INSERT},{3,TL_READ_NO_INSERT}}; /* Should be quick */
+struct st_test test_9[] = {{4,TL_READ_HIGH_PRIORITY}};
+struct st_test test_10[] ={{4,TL_WRITE}};
+struct st_test test_11[] = {{0,TL_WRITE_LOW_PRIORITY},{1,TL_WRITE_LOW_PRIORITY},{2,TL_WRITE_LOW_PRIORITY},{3,TL_WRITE_LOW_PRIORITY}}; /* Many writes */
+struct st_test test_12[] = {{0,TL_WRITE_ALLOW_READ},{1,TL_WRITE_ALLOW_READ},{2,TL_WRITE_ALLOW_READ},{3,TL_WRITE_ALLOW_READ}}; /* Many writes */
+struct st_test test_13[] = {{0,TL_WRITE_CONCURRENT_INSERT},{1,TL_WRITE_CONCURRENT_INSERT},{2,TL_WRITE_CONCURRENT_INSERT},{3,TL_WRITE_CONCURRENT_INSERT}};
+struct st_test test_14[] = {{0,TL_WRITE_CONCURRENT_INSERT},{1,TL_READ}};
+struct st_test test_15[] = {{0,TL_WRITE_ALLOW_WRITE},{1,TL_READ}};
+struct st_test test_16[] = {{0,TL_WRITE_ALLOW_WRITE},{1,TL_WRITE_ALLOW_WRITE}};
+
+struct st_test *tests[] = {test_0,test_1,test_2,test_3,test_4,test_5,test_6,
+ test_7,test_8,test_9,test_10,test_11,test_12,
+ test_13,test_14,test_15,test_16};
+int lock_counts[]= {sizeof(test_0)/sizeof(struct st_test),
+ sizeof(test_1)/sizeof(struct st_test),
+ sizeof(test_2)/sizeof(struct st_test),
+ sizeof(test_3)/sizeof(struct st_test),
+ sizeof(test_4)/sizeof(struct st_test),
+ sizeof(test_5)/sizeof(struct st_test),
+ sizeof(test_6)/sizeof(struct st_test),
+ sizeof(test_7)/sizeof(struct st_test),
+ sizeof(test_8)/sizeof(struct st_test),
+ sizeof(test_9)/sizeof(struct st_test),
+ sizeof(test_10)/sizeof(struct st_test),
+ sizeof(test_11)/sizeof(struct st_test),
+ sizeof(test_12)/sizeof(struct st_test),
+ sizeof(test_13)/sizeof(struct st_test),
+ sizeof(test_14)/sizeof(struct st_test),
+ sizeof(test_15)/sizeof(struct st_test),
+ sizeof(test_16)/sizeof(struct st_test)
+};
+
+
+static pthread_cond_t COND_thread_count;
+static pthread_mutex_t LOCK_thread_count;
+static uint thread_count;
+static ulong sum=0;
+
+#define MAX_LOCK_COUNT 8
+
+/* The following functions is for WRITE_CONCURRENT_INSERT */
+
+static void test_get_status(void* param __attribute__((unused)))
+{
+}
+
+static void test_copy_status(void* to __attribute__((unused)) ,
+ void *from __attribute__((unused)))
+{
+}
+
+static my_bool test_check_status(void* param __attribute__((unused)))
+{
+ return 0;
+}
+
+
+static void *test_thread(void *arg)
+{
+ int i,j,param=*((int*) arg);
+ THR_LOCK_DATA data[MAX_LOCK_COUNT];
+ THR_LOCK_DATA *multi_locks[MAX_LOCK_COUNT];
+ my_thread_init();
+
+ printf("Thread %s (%d) started\n",my_thread_name(),param); fflush(stdout);
+
+ for (i=0; i < lock_counts[param] ; i++)
+ thr_lock_data_init(locks+tests[param][i].lock_nr,data+i,NULL);
+ for (j=1 ; j < 10 ; j++) /* try locking 10 times */
+ {
+ for (i=0; i < lock_counts[param] ; i++)
+ { /* Init multi locks */
+ multi_locks[i]= &data[i];
+ data[i].type= tests[param][i].lock_type;
+ }
+ thr_multi_lock(multi_locks,lock_counts[param]);
+ pthread_mutex_lock(&LOCK_thread_count);
+ {
+ int tmp=rand() & 7; /* Do something from 0-2 sec */
+ if (tmp == 0)
+ sleep(1);
+ else if (tmp == 1)
+ sleep(2);
+ else
+ {
+ ulong k;
+ for (k=0 ; k < (ulong) (tmp-2)*100000L ; k++)
+ sum+=k;
+ }
+ }
+ pthread_mutex_unlock(&LOCK_thread_count);
+ thr_multi_unlock(multi_locks,lock_counts[param]);
+ }
+
+ printf("Tread %s (%d) ended\n",my_thread_name(),param); fflush(stdout);
+ thr_print_locks();
+ pthread_mutex_lock(&LOCK_thread_count);
+ thread_count--;
+ VOID(pthread_cond_signal(&COND_thread_count)); /* Tell main we are ready */
+ pthread_mutex_unlock(&LOCK_thread_count);
+ free((gptr) arg);
+ return 0;
+}
+
+
+int main(int argc __attribute__((unused)),char **argv __attribute__((unused)))
+{
+ pthread_t tid;
+ pthread_attr_t thr_attr;
+ int i,*param,error;
+ MY_INIT(argv[0]);
+ if (argc > 1 && argv[1][0] == '-' && argv[1][1] == '#')
+ DBUG_PUSH(argv[1]+2);
+
+ printf("Main thread: %s\n",my_thread_name());
+
+ if ((error=pthread_cond_init(&COND_thread_count,NULL)))
+ {
+ fprintf(stderr,"Got error: %d from pthread_cond_init (errno: %d)",
+ error,errno);
+ exit(1);
+ }
+ if ((error=pthread_mutex_init(&LOCK_thread_count,NULL)))
+ {
+ fprintf(stderr,"Got error: %d from pthread_cond_init (errno: %d)",
+ error,errno);
+ exit(1);
+ }
+
+ for (i=0 ; i < (int) array_elements(locks) ; i++)
+ {
+ thr_lock_init(locks+i);
+ locks[i].check_status= test_check_status;
+ locks[i].update_status=test_get_status;
+ locks[i].copy_status= test_copy_status;
+ locks[i].get_status= test_get_status;
+ }
+ if ((error=pthread_attr_init(&thr_attr)))
+ {
+ fprintf(stderr,"Got error: %d from pthread_attr_init (errno: %d)",
+ error,errno);
+ exit(1);
+ }
+ if ((error=pthread_attr_setdetachstate(&thr_attr,PTHREAD_CREATE_DETACHED)))
+ {
+ fprintf(stderr,
+ "Got error: %d from pthread_attr_setdetachstate (errno: %d)",
+ error,errno);
+ exit(1);
+ }
+#ifndef pthread_attr_setstacksize /* void return value */
+ if ((error=pthread_attr_setstacksize(&thr_attr,65536L)))
+ {
+ fprintf(stderr,"Got error: %d from pthread_attr_setstacksize (errno: %d)",
+ error,errno);
+ exit(1);
+ }
+#endif
+#ifdef HAVE_THR_SETCONCURRENCY
+ VOID(thr_setconcurrency(2));
+#endif
+ for (i=0 ; i < (int) array_elements(lock_counts) ; i++)
+ {
+ param=(int*) malloc(sizeof(int));
+ *param=i;
+
+ if ((error=pthread_mutex_lock(&LOCK_thread_count)))
+ {
+ fprintf(stderr,"Got error: %d from pthread_mutex_lock (errno: %d)",
+ error,errno);
+ exit(1);
+ }
+ if ((error=pthread_create(&tid,&thr_attr,test_thread,(void*) param)))
+ {
+ fprintf(stderr,"Got error: %d from pthread_create (errno: %d)\n",
+ error,errno);
+ pthread_mutex_unlock(&LOCK_thread_count);
+ exit(1);
+ }
+ thread_count++;
+ pthread_mutex_unlock(&LOCK_thread_count);
+ }
+
+ pthread_attr_destroy(&thr_attr);
+ if ((error=pthread_mutex_lock(&LOCK_thread_count)))
+ fprintf(stderr,"Got error: %d from pthread_mutex_lock\n",error);
+ while (thread_count)
+ {
+ if ((error=pthread_cond_wait(&COND_thread_count,&LOCK_thread_count)))
+ fprintf(stderr,"Got error: %d from pthread_cond_wait\n",error);
+ }
+ if ((error=pthread_mutex_unlock(&LOCK_thread_count)))
+ fprintf(stderr,"Got error: %d from pthread_mutex_unlock\n",error);
+ for (i=0 ; i < (int) array_elements(locks) ; i++)
+ thr_lock_delete(locks+i);
+#ifdef EXTRA_DEBUG
+ if (found_errors)
+ printf("Got %d warnings\n",found_errors);
+ else
+#endif
+ printf("Test succeeded\n");
+ return 0;
+}
+#endif
+
+#endif
diff --git a/mysys/thr_mutex.c b/mysys/thr_mutex.c
new file mode 100644
index 00000000000..7eea5be473b
--- /dev/null
+++ b/mysys/thr_mutex.c
@@ -0,0 +1,214 @@
+/* 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 makes a wrapper for mutex handling to make it easier to debug mutex */
+
+#include <global.h>
+#if defined(HAVE_LINUXTHREADS) && !defined (__USE_UNIX98)
+#define __USE_UNIX98 /* To get rw locks under Linux */
+#endif
+#include <m_string.h>
+#if defined(THREAD) && defined(SAFE_MUTEX)
+#undef SAFE_MUTEX /* Avoid safe_mutex redefinitions */
+#include <my_pthread.h>
+
+#ifndef DO_NOT_REMOVE_THREAD_WRAPPERS
+/* Remove wrappers */
+#undef pthread_mutex_init
+#undef pthread_mutex_lock
+#undef pthread_mutex_unlock
+#undef pthread_mutex_destroy
+#undef pthread_cond_wait
+#undef pthread_cond_timedwait
+#ifdef HAVE_NONPOSIX_PTHREAD_MUTEX_INIT
+#define pthread_mutex_init(a,b) my_pthread_mutex_init((a),(b))
+#endif
+#endif
+
+int safe_mutex_init(safe_mutex_t *mp,
+ const pthread_mutexattr_t *attr __attribute__((unused)))
+{
+ bzero((char*) mp,sizeof(*mp));
+#ifdef HAVE_LINUXTHREADS /* Some extra safety */
+ {
+ pthread_mutexattr_t tmp;
+ pthread_mutexattr_init(&tmp);
+ pthread_mutexattr_setkind_np(&tmp,PTHREAD_MUTEX_ERRORCHECK_NP);
+ pthread_mutex_init(&mp->global,&tmp);
+ pthread_mutex_init(&mp->mutex, &tmp);
+ pthread_mutexattr_destroy(&tmp);
+ }
+#else
+ pthread_mutex_init(&mp->global,NULL);
+ pthread_mutex_init(&mp->mutex,attr);
+#endif
+ return 0;
+}
+
+int safe_mutex_lock(safe_mutex_t *mp,const char *file, uint line)
+{
+ int error;
+ pthread_mutex_lock(&mp->global);
+ if (mp->count > 0 && pthread_equal(pthread_self(),mp->thread))
+ {
+ fprintf(stderr,"safe_mutex: Trying to lock mutex at %s, line %d, when the mutex was already locked at %s, line %d\n",
+ file,line,mp->file,mp->line);
+ abort();
+ }
+ pthread_mutex_unlock(&mp->global);
+ error=pthread_mutex_lock(&mp->mutex);
+ if (error || (error=pthread_mutex_lock(&mp->global)))
+ {
+ fprintf(stderr,"Got error %d when trying to lock mutex at %s, line %d\n",
+ error, file, line);
+ abort();
+ }
+ if (mp->count++)
+ {
+ fprintf(stderr,"safe_mutex: Error in thread libray: Got mutex at %s, line %d more than 1 time\n", file,line);
+ abort();
+ }
+ mp->thread=pthread_self();
+ mp->file= (char*) file;
+ mp->line=line;
+ pthread_mutex_unlock(&mp->global);
+ return error;
+}
+
+
+int safe_mutex_unlock(safe_mutex_t *mp,const char *file, uint line)
+{
+ int error;
+ pthread_mutex_lock(&mp->global);
+ if (mp->count == 0)
+ {
+ fprintf(stderr,"safe_mutex: Trying to unlock mutex that wasn't locked at %s, line %d\n Last used at %s, line: %d\n",
+ file,line,mp->file ? mp->file : "",mp->line);
+ abort();
+ }
+ if (!pthread_equal(pthread_self(),mp->thread))
+ {
+ fprintf(stderr,"safe_mutex: Trying to unlock mutex at %s, line %d that was locked by another thread at: %s, line: %d\n",
+ file,line,mp->file,mp->line);
+ abort();
+ }
+ mp->count--;
+ 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);
+ abort();
+ }
+ pthread_mutex_unlock(&mp->global);
+ return error;
+}
+
+
+int safe_cond_wait(pthread_cond_t *cond, safe_mutex_t *mp, const char *file,
+ uint line)
+{
+ int error;
+ pthread_mutex_lock(&mp->global);
+ if (mp->count == 0)
+ {
+ fprintf(stderr,"safe_mutex: Trying to cond_wait on a unlocked mutex at %s, line %d\n",file,line);
+ abort();
+ }
+ if (!pthread_equal(pthread_self(),mp->thread))
+ {
+ fprintf(stderr,"safe_mutex: Trying to cond_wait on a mutex at %s, line %d that was locked by another thread at: %s, line: %d\n",
+ file,line,mp->file,mp->line);
+ abort();
+ }
+
+ if (mp->count-- != 1)
+ {
+ fprintf(stderr,"safe_mutex: Count was %d on locked mutex at %s, line %d\n",
+ mp->count+1, file, line);
+ abort();
+ }
+ pthread_mutex_unlock(&mp->global);
+ error=pthread_cond_wait(cond,&mp->mutex);
+ 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);
+ abort();
+ }
+ if (mp->count++)
+ {
+ fprintf(stderr,
+ "safe_mutex: Count was %d in thread %lx when locking mutex at %s, line %d\n",
+ mp->count-1, my_thread_id(), file, line);
+ abort();
+ }
+ mp->thread=pthread_self();
+ mp->file= (char*) file;
+ mp->line=line;
+ pthread_mutex_unlock(&mp->global);
+ return error;
+}
+
+
+int safe_cond_timedwait(pthread_cond_t *cond, safe_mutex_t *mp,
+ struct timespec *abstime,
+ const char *file, uint line)
+{
+ int error;
+ pthread_mutex_lock(&mp->global);
+ if (mp->count != 1 || !pthread_equal(pthread_self(),mp->thread))
+ {
+ fprintf(stderr,"safe_mutex: Trying to cond_wait at %s, line %d on a not hold mutex\n",file,line);
+ abort();
+ }
+ mp->count--; /* Mutex will be released */
+ pthread_mutex_unlock(&mp->global);
+ error=pthread_cond_timedwait(cond,&mp->mutex,abstime);
+#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);
+ }
+#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);
+ abort();
+ }
+ mp->thread=pthread_self();
+ mp->file= (char*) file;
+ mp->line=line;
+ pthread_mutex_unlock(&mp->global);
+ return error;
+}
+
+int safe_mutex_destroy(safe_mutex_t *mp, const char *file, uint line)
+{
+ if (mp->count != 0)
+ {
+ fprintf(stderr,"safe_mutex: Trying to destroy a mutex that was locked at %s, line %d at %s, line %d\n",
+ mp->file,mp->line, file, line);
+ abort();
+ }
+ pthread_mutex_destroy(&mp->global);
+ return pthread_mutex_destroy(&mp->mutex);
+}
+
+#endif /* SAFE_MUTEX */
diff --git a/mysys/thr_rwlock.c b/mysys/thr_rwlock.c
new file mode 100644
index 00000000000..fc2eea551da
--- /dev/null
+++ b/mysys/thr_rwlock.c
@@ -0,0 +1,139 @@
+/* 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 */
+
+/* Synchronization - readers / writer thread locks */
+
+#include "mysys_priv.h"
+#include <my_pthread.h>
+#if defined(THREAD) && !defined(HAVE_PTHREAD_RWLOCK_RDLOCK) && !defined(HAVE_RWLOCK_INIT)
+
+/*
+ * Source base from Sun Microsystems SPILT, simplified
+ * for MySQL use -- Joshua Chamas
+ */
+
+/*
+* Multithreaded Demo Source
+*
+* Copyright (C) 1995 by Sun Microsystems, Inc.
+* All rights reserved.
+*
+* This file is a product of SunSoft, Inc. and is provided for
+* unrestricted use provided that this legend is included on all
+* media and as a part of the software program in whole or part.
+* Users may copy, modify or distribute this file at will.
+*
+* THIS FILE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING
+* THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+* PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+*
+* This file is provided with no support and without any obligation on the
+* part of SunSoft, Inc. to assist in its use, correction, modification or
+* enhancement.
+*
+* SUNSOFT AND SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT
+* TO THE INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS
+* FILE OR ANY PART THEREOF.
+*
+* IN NO EVENT WILL SUNSOFT OR SUN MICROSYSTEMS, INC. BE LIABLE FOR ANY
+* LOST REVENUE OR PROFITS OR OTHER SPECIAL, INDIRECT AND CONSEQUENTIAL
+* DAMAGES, EVEN IF THEY HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH
+* DAMAGES.
+*
+* SunSoft, Inc.
+* 2550 Garcia Avenue
+* Mountain View, California 94043
+*/
+
+int my_rwlock_init( rw_lock_t *rwp, void *arg __attribute__((unused)))
+{
+ pthread_condattr_t cond_attr;
+
+ pthread_mutex_init( &rwp->lock, NULL );
+ pthread_condattr_init( &cond_attr );
+ pthread_cond_init( &rwp->readers, &cond_attr );
+ pthread_cond_init( &rwp->writers, &cond_attr );
+ pthread_condattr_destroy(&cond_attr);
+
+ rwp->state = 0;
+ rwp->waiters = 0;
+
+ return( 0 );
+}
+
+int my_rwlock_destroy( rw_lock_t *rwp ) {
+ pthread_mutex_destroy( &rwp->lock );
+ pthread_cond_destroy( &rwp->readers );
+ pthread_cond_destroy( &rwp->writers );
+
+ return( 0 );
+}
+
+int my_rw_rdlock( rw_lock_t *rwp ) {
+ pthread_mutex_lock(&rwp->lock);
+
+ /* active or queued writers */
+ while ( ( rwp->state < 0 ) && rwp->waiters )
+ pthread_cond_wait( &rwp->readers, &rwp->lock);
+
+ rwp->state++;
+ pthread_mutex_unlock(&rwp->lock);
+
+ return( 0 );
+}
+
+int my_rw_wrlock( rw_lock_t *rwp ) {
+
+ pthread_mutex_lock(&rwp->lock);
+ rwp->waiters++; /* another writer queued */
+
+ while ( rwp->state )
+ pthread_cond_wait( &rwp->writers, &rwp->lock);
+
+ rwp->state = -1;
+
+ if ( ( --rwp->waiters == 0 ) && ( rwp->state >= 0 ) )
+ pthread_cond_broadcast( &rwp->readers );
+
+ pthread_mutex_unlock( &rwp->lock );
+
+ return( 0 );
+}
+
+int my_rw_unlock( rw_lock_t *rwp ) {
+ DBUG_PRINT("rw_unlock",
+ ("state: %d waiters: %d", rwp->state, rwp->waiters));
+ pthread_mutex_lock(&rwp->lock);
+
+ if ( rwp->state == -1 ) { /* writer releasing */
+ rwp->state = 0; /* mark as available */
+
+ if ( rwp->waiters ) /* writers queued */
+ pthread_cond_signal( &rwp->writers );
+ else
+ pthread_cond_broadcast( &rwp->readers );
+ } else {
+ if ( --rwp->state == 0 ) /* no more readers */
+ pthread_cond_signal( &rwp->writers );
+ }
+
+ pthread_mutex_unlock( &rwp->lock );
+
+ return( 0 );
+}
+
+#endif
diff --git a/mysys/tree.c b/mysys/tree.c
new file mode 100644
index 00000000000..259fc5fb9d0
--- /dev/null
+++ b/mysys/tree.c
@@ -0,0 +1,513 @@
+/* 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 */
+
+/*
+ Code for handling red-black (balanced) binary trees.
+ key in tree is allocated accrding to following:
+ 1) If free_element function is given to init_tree or size < 0 then tree
+ will not allocate keys and only a pointer to each key is saved in tree.
+ key_sizes must be 0 to init and search.
+ compare and search functions uses and returns key-pointer.
+ 2) if key_size is given to init_tree then each node will continue the
+ key and calls to insert_key may increase length of key.
+ if key_size > sizeof(pointer) and key_size is a multiple of 8 (double
+ allign) then key will be put on a 8 alligned adress. Else
+ the key will be on adress (element+1). This is transparent for user
+ compare and search functions uses a pointer to given key-argument.
+ 3) If init_tree - keysize is 0 then key_size must be given to tree_insert
+ and tree_insert will alloc space for key.
+ compare and search functions uses a pointer to given key-argument.
+
+ The actual key in TREE_ELEMENT is saved as a pointer or after the
+ TREE_ELEMENT struct.
+ If one uses only pointers in tree one can use tree_set_pointer() to
+ change address of data.
+ Copyright Monty Program KB.
+ By monty.
+*/
+
+#include "mysys_priv.h"
+#include <m_string.h>
+#include <my_tree.h>
+
+#define BLACK 1
+#define RED 0
+#define DEFAULT_ALLOC_SIZE (8192-MALLOC_OVERHEAD)
+
+static void delete_tree_element(TREE *,TREE_ELEMENT *);
+static int tree_walk_left_root_right(TREE *,TREE_ELEMENT *,
+ tree_walk_action,void *);
+static int tree_walk_right_root_left(TREE *,TREE_ELEMENT *,
+ tree_walk_action,void *);
+static void left_rotate(TREE_ELEMENT **parent,TREE_ELEMENT *leaf);
+static void right_rotate(TREE_ELEMENT **parent, TREE_ELEMENT *leaf);
+static void rb_insert(TREE *tree,TREE_ELEMENT ***parent,
+ TREE_ELEMENT *leaf);
+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 *))
+{
+ DBUG_ENTER("init_tree");
+ DBUG_PRINT("enter",("tree: %lx size: %d",tree,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->free=free_element;
+ tree->elements_in_tree=0;
+ 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 */
+ default_alloc_size/=(sizeof(TREE_ELEMENT)+size);
+ if (!default_alloc_size)
+ default_alloc_size=1;
+ default_alloc_size*=(sizeof(TREE_ELEMENT)+size);
+ }
+ else
+ {
+ tree->offset_to_key=0; /* use key through pointer */
+ tree->size_of_element+=sizeof(void*);
+ }
+ if (!(tree->with_delete=with_delete))
+ {
+ init_alloc_root(&tree->mem_root, default_alloc_size);
+ tree->mem_root.min_malloc=(sizeof(TREE_ELEMENT)+tree->size_of_element);
+ }
+ DBUG_VOID_RETURN;
+}
+
+void delete_tree(TREE *tree)
+{
+ DBUG_ENTER("delete_tree");
+ DBUG_PRINT("enter",("tree: %lx",tree));
+
+ if (tree->root) /* If initialized */
+ {
+ if (tree->with_delete)
+ delete_tree_element(tree,tree->root);
+ else
+ {
+ if (tree->free)
+ delete_tree_element(tree,tree->root);
+ free_root(&tree->mem_root);
+ }
+ }
+ tree->root= &tree->null_element;
+ tree->elements_in_tree=0;
+
+ DBUG_VOID_RETURN;
+}
+
+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));
+ if (tree->with_delete)
+ my_free((void*) element,MYF(0));
+ }
+}
+
+ /* Code for insert, search and delete of elements */
+ /* parent[0] = & parent[-1][0]->left ||
+ parent[0] = & parent[-1][0]->right */
+
+
+TREE_ELEMENT *tree_insert(TREE *tree, void *key, uint key_size)
+{
+ int cmp;
+ TREE_ELEMENT *element,***parent;
+
+ parent= tree->parents;
+ *parent = &tree->root; element= tree->root;
+ for (;;)
+ {
+ if (element == &tree->null_element ||
+ (cmp=(*tree->compare)(ELEMENT_KEY(tree,element),key)) == 0)
+ break;
+ if (cmp < 0)
+ {
+ *++parent= &element->right; element= element->right;
+ }
+ else
+ {
+ *++parent = &element->left; element= element->left;
+ }
+ }
+ if (element == &tree->null_element)
+ {
+ key_size+=tree->size_of_element;
+ if (tree->with_delete)
+ element=(TREE_ELEMENT *) my_malloc(sizeof(TREE_ELEMENT)+key_size,
+ MYF(MY_WME));
+ else
+ element=(TREE_ELEMENT *)
+ alloc_root(&tree->mem_root,sizeof(TREE_ELEMENT)+key_size);
+ if (!element)
+ return(NULL);
+ **parent=element;
+ element->left=element->right= &tree->null_element;
+ if (!tree->offset_to_key)
+ {
+ if (key_size == sizeof(void*)) /* no length, save pointer */
+ *((void**) (element+1))=key;
+ else
+ {
+ *((void**) (element+1))= (void*) ((void **) (element+1)+1);
+ memcpy((byte*) *((void **) (element+1)),key,
+ (size_t) (key_size-sizeof(void*)));
+ }
+ }
+ else
+ memcpy((byte*) element+tree->offset_to_key,key,(size_t) key_size);
+ element->count=1; /* May give warning in purify */
+ tree->elements_in_tree++;
+ rb_insert(tree,parent,element); /* rebalance tree */
+ }
+ else
+ element->count++;
+ return element;
+}
+
+
+int tree_delete(TREE *tree, void *key)
+{
+ int cmp,remove_colour;
+ TREE_ELEMENT *element,***parent, ***org_parent, *nod;
+ if (!tree->with_delete)
+ return 1; /* not allowed */
+
+ parent= tree->parents;
+ *parent= &tree->root; element= tree->root;
+ for (;;)
+ {
+ if (element == &tree->null_element)
+ return 1; /* Was not in tree */
+ if ((cmp=(*tree->compare)(ELEMENT_KEY(tree,element),key)) == 0)
+ break;
+ if (cmp < 0)
+ {
+ *++parent= &element->right; element= element->right;
+ }
+ else
+ {
+ *++parent = &element->left; element= element->left;
+ }
+ }
+ if (element->left == &tree->null_element)
+ {
+ (**parent)=element->right;
+ remove_colour= element->colour;
+ }
+ else if (element->right == &tree->null_element)
+ {
+ (**parent)=element->left;
+ remove_colour= element->colour;
+ }
+ else
+ {
+ org_parent= parent;
+ *++parent= &element->right; nod= element->right;
+ while (nod->left != &tree->null_element)
+ {
+ *++parent= &nod->left; nod= nod->left;
+ }
+ (**parent)=nod->right; /* unlink nod from tree */
+ remove_colour= nod->colour;
+ org_parent[0][0]=nod; /* put y in place of element */
+ org_parent[1]= &nod->right;
+ nod->left=element->left;
+ nod->right=element->right;
+ nod->colour=element->colour;
+ }
+ if (remove_colour == BLACK)
+ rb_delete_fixup(tree,parent);
+ my_free((gptr) element,MYF(0));
+ tree->elements_in_tree--;
+ return 0;
+}
+
+
+void *tree_search(TREE *tree, void *key)
+{
+ int cmp;
+ TREE_ELEMENT *element=tree->root;
+
+ for (;;)
+ {
+ if (element == &tree->null_element)
+ return (void*) 0;
+ if ((cmp=(*tree->compare)(ELEMENT_KEY(tree,element),key)) == 0)
+ return ELEMENT_KEY(tree,element);
+ if (cmp < 0)
+ element=element->right;
+ else
+ element=element->left;
+ }
+}
+
+
+int tree_walk(TREE *tree, tree_walk_action action, void *argument, TREE_WALK visit)
+{
+ switch (visit) {
+ case left_root_right:
+ return tree_walk_left_root_right(tree,tree->root,action,argument);
+ case right_root_left:
+ return tree_walk_right_root_left(tree,tree->root,action,argument);
+ }
+ return 0; /* Keep gcc happy */
+}
+
+static int tree_walk_left_root_right(TREE *tree, TREE_ELEMENT *element, tree_walk_action action, void *argument)
+{
+ int error;
+ if (element->left) /* Not null_element */
+ {
+ if ((error=tree_walk_left_root_right(tree,element->left,action,
+ argument)) == 0 &&
+ (error=(*action)(ELEMENT_KEY(tree,element),
+ (element_count) element->count,
+ argument)) == 0)
+ error=tree_walk_left_root_right(tree,element->right,action,argument);
+ return error;
+ }
+ return 0;
+}
+
+static int tree_walk_right_root_left(TREE *tree, TREE_ELEMENT *element, tree_walk_action action, void *argument)
+{
+ int error;
+ if (element->right) /* Not null_element */
+ {
+ if ((error=tree_walk_right_root_left(tree,element->right,action,
+ argument)) == 0 &&
+ (error=(*action)(ELEMENT_KEY(tree,element),
+ (element_count) element->count,
+ argument)) == 0)
+ error=tree_walk_right_root_left(tree,element->left,action,argument);
+ return error;
+ }
+ return 0;
+}
+
+
+ /* Functions to fix up the tree after insert and delete */
+
+static void left_rotate(TREE_ELEMENT **parent, TREE_ELEMENT *leaf)
+{
+ TREE_ELEMENT *y;
+
+ y=leaf->right;
+ leaf->right=y->left;
+ parent[0]=y;
+ y->left=leaf;
+}
+
+static void right_rotate(TREE_ELEMENT **parent, TREE_ELEMENT *leaf)
+{
+ TREE_ELEMENT *x;
+
+ x=leaf->left;
+ leaf->left=x->right;
+ parent[0]=x;
+ x->right=leaf;
+}
+
+static void rb_insert(TREE *tree, TREE_ELEMENT ***parent, TREE_ELEMENT *leaf)
+{
+ TREE_ELEMENT *y,*par,*par2;
+
+ leaf->colour=RED;
+ while (leaf != tree->root && (par=parent[-1][0])->colour == RED)
+ {
+ if (par == (par2=parent[-2][0])->left)
+ {
+ y= par2->right;
+ if (y->colour == RED)
+ {
+ par->colour=BLACK;
+ y->colour=BLACK;
+ leaf=par2;
+ parent-=2;
+ leaf->colour=RED; /* And the loop continues */
+ }
+ else
+ {
+ if (leaf == par->right)
+ {
+ left_rotate(parent[-1],par);
+ par=leaf; /* leaf is now parent to old leaf */
+ }
+ par->colour=BLACK;
+ par2->colour=RED;
+ right_rotate(parent[-2],par2);
+ break;
+ }
+ }
+ else
+ {
+ y= par2->left;
+ if (y->colour == RED)
+ {
+ par->colour=BLACK;
+ y->colour=BLACK;
+ leaf=par2;
+ parent-=2;
+ leaf->colour=RED; /* And the loop continues */
+ }
+ else
+ {
+ if (leaf == par->left)
+ {
+ right_rotate(parent[-1],par);
+ par=leaf;
+ }
+ par->colour=BLACK;
+ par2->colour=RED;
+ left_rotate(parent[-2],par2);
+ break;
+ }
+ }
+ }
+ tree->root->colour=BLACK;
+}
+
+static void rb_delete_fixup(TREE *tree, TREE_ELEMENT ***parent)
+{
+ TREE_ELEMENT *x,*w,*par;
+
+ x= **parent;
+ while (x != tree->root && x->colour == BLACK)
+ {
+ if (x == (par=parent[-1][0])->left)
+ {
+ w=par->right;
+ if (w->colour == RED)
+ {
+ w->colour=BLACK;
+ par->colour=RED;
+ left_rotate(parent[-1],par);
+ parent[0]= &w->left;
+ *++parent= &par->left;
+ w=par->right;
+ }
+ if (w->left->colour == BLACK && w->right->colour == BLACK)
+ {
+ w->colour=RED;
+ x=par;
+ parent--;
+ }
+ else
+ {
+ if (w->right->colour == BLACK)
+ {
+ w->left->colour=BLACK;
+ w->colour=RED;
+ right_rotate(&par->right,w);
+ w=par->right;
+ }
+ w->colour=par->colour;
+ par->colour=BLACK;
+ w->right->colour=BLACK;
+ left_rotate(parent[-1],par);
+ x=tree->root;
+ break;
+ }
+ }
+ else
+ {
+ w=par->left;
+ if (w->colour == RED)
+ {
+ w->colour=BLACK;
+ par->colour=RED;
+ right_rotate(parent[-1],par);
+ parent[0]= &w->right;
+ *++parent= &par->right;
+ w=par->left;
+ }
+ if (w->right->colour == BLACK && w->left->colour == BLACK)
+ {
+ w->colour=RED;
+ x=par;
+ parent--;
+ }
+ else
+ {
+ if (w->left->colour == BLACK)
+ {
+ w->right->colour=BLACK;
+ w->colour=RED;
+ left_rotate(&par->left,w);
+ w=par->left;
+ }
+ w->colour=par->colour;
+ par->colour=BLACK;
+ w->left->colour=BLACK;
+ right_rotate(parent[-1],par);
+ x=tree->root;
+ break;
+ }
+ }
+ }
+ x->colour=BLACK;
+}
+
+
+#ifdef TESTING_TREES
+
+ /* Test that the proporties for a red-black tree holds */
+
+static int test_rb_tree(TREE_ELEMENT *element)
+{
+ int count_l,count_r;
+
+ if (!element->left)
+ return 0; /* Found end of tree */
+ if (element->colour == RED &&
+ (element->left->colour == RED || element->right->colour == RED))
+ {
+ printf("Wrong tree: Found two red in a row\n");
+ return -1;
+ }
+ count_l=test_rb_tree(element->left);
+ count_r=test_rb_tree(element->right);
+ if (count_l >= 0 && count_r >= 0)
+ {
+ if (count_l == count_r)
+ return count_l+(element->colour == BLACK);
+ printf("Wrong tree: Incorrect black-count: %d - %d\n",count_l,count_r);
+ }
+ return -1;
+}
+
+#endif
diff --git a/mysys/typelib.c b/mysys/typelib.c
new file mode 100644
index 00000000000..903a7304065
--- /dev/null
+++ b/mysys/typelib.c
@@ -0,0 +1,106 @@
+/* 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 */
+
+/* Functions to handle typelib */
+
+#include "mysys_priv.h"
+#include <m_string.h>
+#include <m_ctype.h>
+
+/***************************************************************************
+** Search after a fieldtype. Endspace in x is not compared.
+** If part, uniq field is found and full_name == 0 then x is expanded
+** to full field.
+** full_name has the following bit values:
+** If & 1 accept only hole names
+** If & 2 don't expand if half field
+** If & 4 allow #number# as type
+****************************************************************************/
+
+int find_type(my_string x, TYPELIB *typelib, uint full_name)
+{
+ int find,pos,findpos;
+ reg1 my_string i;
+ reg2 const char *j;
+ DBUG_ENTER("find_type");
+ DBUG_PRINT("enter",("x: '%s' lib: %lx",x,typelib));
+
+ if (!typelib->count)
+ {
+ DBUG_PRINT("exit",("no count"));
+ DBUG_RETURN(0);
+ }
+ LINT_INIT(findpos);
+ find=0;
+ for (pos=0 ; (j=typelib->type_names[pos]) ; pos++)
+ {
+ for (i=x ; *i && toupper(*i) == toupper(*j) ; i++, j++) ;
+ if (! *j)
+ {
+ while (*i == ' ')
+ i++; /* skipp_end_space */
+ if (! *i)
+ DBUG_RETURN(pos+1);
+ }
+ if (! *i)
+ {
+ find++;
+ findpos=pos;
+ }
+ }
+ if (find == 0 && (full_name & 4) && x[0] == '#' && strend(x)[-1] == '#' &&
+ (findpos=atoi(x+1)-1) >= 0 && (uint) findpos < typelib->count)
+ find=1;
+ else if (find == 0 || ! x[0])
+ {
+ DBUG_PRINT("exit",("Couldn't find type"));
+ DBUG_RETURN(0);
+ }
+ else if (find != 1 || (full_name & 1))
+ {
+ DBUG_PRINT("exit",("Too many possybilities"));
+ DBUG_RETURN(-1);
+ }
+ if (!(full_name & 2))
+ (void) strmov(x,typelib->type_names[findpos]);
+ DBUG_RETURN(findpos+1);
+} /* find_type */
+
+
+ /* 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)
+{
+ DBUG_ENTER("make_type");
+ if (!nr)
+ to[0]=0;
+ else
+ (void) strmov(to,get_type(typelib,nr-1));
+ DBUG_VOID_RETURN;
+} /* make_type */
+
+
+ /* Get type */
+ /* Warning first type is 0 */
+
+const char *get_type(TYPELIB *typelib, uint nr)
+{
+ if (nr < (uint) typelib->count && typelib->type_names)
+ return(typelib->type_names[nr]);
+ return "?";
+}
diff --git a/readline/.cvsignore b/readline/.cvsignore
new file mode 100644
index 00000000000..e9955884756
--- /dev/null
+++ b/readline/.cvsignore
@@ -0,0 +1,3 @@
+.deps
+Makefile
+Makefile.in
diff --git a/readline/COPYING b/readline/COPYING
new file mode 100644
index 00000000000..a43ea2126fb
--- /dev/null
+++ b/readline/COPYING
@@ -0,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ 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.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. 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.
+
+ 1. 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.
+
+ 2. 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:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) 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.
+
+ c) 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.)
+
+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.
+
+ 3. 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:
+
+ a) 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,
+
+ b) 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,
+
+ c) 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.)
+
+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.
+
+ 4. 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.
+
+ 5. 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.
+
+ 6. 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.
+
+ 7. 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.
+
+ 8. 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.
+
+ 9. 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.
+
+ 10. 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.
+
+ NO WARRANTY
+
+ 11. 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.
+
+ 12. 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 OF TERMS AND CONDITIONS
+
+ Appendix: 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.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+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:
+
+ Gnomovision version 69, Copyright (C) 19yy 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.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `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:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+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.
diff --git a/readline/INSTALL b/readline/INSTALL
new file mode 100644
index 00000000000..95d84c820fb
--- /dev/null
+++ b/readline/INSTALL
@@ -0,0 +1,176 @@
+Basic Installation
+==================
+
+ These are generic installation instructions.
+
+ The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation. It uses
+those values to create a `Makefile' in each directory of the package.
+It may also create one or more `.h' files containing system-dependent
+definitions. Finally, it creates a shell script `config.status' that
+you can run in the future to recreate the current configuration, a file
+`config.cache' that saves the results of its tests to speed up
+reconfiguring, and a file `config.log' containing compiler output
+(useful mainly for debugging `configure').
+
+ If you need to do unusual things to compile the package, please try
+to figure out how `configure' could check whether to do them, and mail
+diffs or instructions to the address given in the `README' so they can
+be considered for the next release. If at some point `config.cache'
+contains results you don't want to keep, you may remove or edit it.
+
+ The file `configure.in' is used to create `configure' by a program
+called `autoconf'. You only need `configure.in' if you want to change
+it or regenerate `configure' using a newer version of `autoconf'.
+
+The simplest way to compile this package is:
+
+ 1. `cd' to the directory containing the package's source code and type
+ `./configure' to configure the package for your system. If you're
+ using `csh' on an old version of System V, you might need to type
+ `sh ./configure' instead to prevent `csh' from trying to execute
+ `configure' itself.
+
+ Running `configure' takes awhile. While running, it prints some
+ messages telling which features it is checking for.
+
+ 2. Type `make' to compile the package.
+
+ 3. Optionally, type `make check' to run any self-tests that come with
+ the package.
+
+ 4. Type `make install' to install the programs and any data files and
+ documentation.
+
+ 5. You can remove the program binaries and object files from the
+ source code directory by typing `make clean'. To also remove the
+ files that `configure' created (so you can compile the package for
+ a different kind of computer), type `make distclean'. There is
+ also a `make maintainer-clean' target, but that is intended mainly
+ for the package's developers. If you use it, you may have to get
+ all sorts of other programs in order to regenerate files that came
+ with the distribution.
+
+Compilers and Options
+=====================
+
+ Some systems require unusual options for compilation or linking that
+the `configure' script does not know about. You can give `configure'
+initial values for variables by setting them in the environment. Using
+a Bourne-compatible shell, you can do that on the command line like
+this:
+ CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure
+
+Or on systems that have the `env' program, you can do it like this:
+ env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure
+
+Compiling For Multiple Architectures
+====================================
+
+ You can compile the package for more than one kind of computer at the
+same time, by placing the object files for each architecture in their
+own directory. To do this, you must use a version of `make' that
+supports the `VPATH' variable, such as GNU `make'. `cd' to the
+directory where you want the object files and executables to go and run
+the `configure' script. `configure' automatically checks for the
+source code in the directory that `configure' is in and in `..'.
+
+ If you have to use a `make' that does not supports the `VPATH'
+variable, you have to compile the package for one architecture at a time
+in the source code directory. After you have installed the package for
+one architecture, use `make distclean' before reconfiguring for another
+architecture.
+
+Installation Names
+==================
+
+ By default, `make install' will install the package's files in
+`/usr/local/bin', `/usr/local/man', etc. You can specify an
+installation prefix other than `/usr/local' by giving `configure' the
+option `--prefix=PATH'.
+
+ You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files. If you
+give `configure' the option `--exec-prefix=PATH', the package will use
+PATH as the prefix for installing programs and libraries.
+Documentation and other data files will still use the regular prefix.
+
+ If the package supports it, you can cause programs to be installed
+with an extra prefix or suffix on their names by giving `configure' the
+option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
+
+Optional Features
+=================
+
+ Some packages pay attention to `--enable-FEATURE' options to
+`configure', where FEATURE indicates an optional part of the package.
+They may also pay attention to `--with-PACKAGE' options, where PACKAGE
+is something like `gnu-as' or `x' (for the X Window System). The
+`README' should mention any `--enable-' and `--with-' options that the
+package recognizes.
+
+ For packages that use the X Window System, `configure' can usually
+find the X include and library files automatically, but if it doesn't,
+you can use the `configure' options `--x-includes=DIR' and
+`--x-libraries=DIR' to specify their locations.
+
+Specifying the System Type
+==========================
+
+ There may be some features `configure' can not figure out
+automatically, but needs to determine by the type of host the package
+will run on. Usually `configure' can figure that out, but if it prints
+a message saying it can not guess the host type, give it the
+`--host=TYPE' option. TYPE can either be a short name for the system
+type, such as `sun4', or a canonical name with three fields:
+ CPU-COMPANY-SYSTEM
+
+See the file `config.sub' for the possible values of each field. If
+`config.sub' isn't included in this package, then this package doesn't
+need to know the host type.
+
+ If you are building compiler tools for cross-compiling, you can also
+use the `--target=TYPE' option to select the type of system they will
+produce code for and the `--build=TYPE' option to select the type of
+system on which you are compiling the package.
+
+Sharing Defaults
+================
+
+ If you want to set default values for `configure' scripts to share,
+you can create a site shell script called `config.site' that gives
+default values for variables like `CC', `cache_file', and `prefix'.
+`configure' looks for `PREFIX/share/config.site' if it exists, then
+`PREFIX/etc/config.site' if it exists. Or, you can set the
+`CONFIG_SITE' environment variable to the location of the site script.
+A warning: not all `configure' scripts look for a site script.
+
+Operation Controls
+==================
+
+ `configure' recognizes the following options to control how it
+operates.
+
+`--cache-file=FILE'
+ Use and save the results of the tests in FILE instead of
+ `./config.cache'. Set FILE to `/dev/null' to disable caching, for
+ debugging `configure'.
+
+`--help'
+ Print a summary of the options to `configure', and exit.
+
+`--quiet'
+`--silent'
+`-q'
+ Do not print messages saying which checks are being made.
+
+`--srcdir=DIR'
+ Look for the package's source code in directory DIR. Usually
+ `configure' can determine that directory automatically.
+
+`--version'
+ Print the version of Autoconf used to generate the `configure'
+ script, and exit.
+
+`configure' also accepts some other, not widely useful, options.
+
diff --git a/readline/Makefile.am b/readline/Makefile.am
new file mode 100644
index 00000000000..dd79b693e3d
--- /dev/null
+++ b/readline/Makefile.am
@@ -0,0 +1,29 @@
+## Process this file with automake to create Makefile.in
+# Makefile for the GNU readline library.
+# Copyright (C) 1994,1996,1997 Free Software Foundation, Inc.
+
+INCLUDES = -I$(srcdir)/../include -I$(srcdir)/.. -I..
+
+noinst_LIBRARIES = libreadline.a
+
+libreadline_a_SOURCES = readline.c funmap.c keymaps.c \
+ vi_mode.c parens.c rltty.c \
+ complete.c bind.c isearch.c \
+ display.c signals.c \
+ util.c kill.c \
+ undo.c macro.c input.c \
+ callback.c terminal.c xmalloc.c \
+ history.c histsearch.c histexpand.c \
+ histfile.c nls.c search.c \
+ shell.c tilde.c
+
+pkginclude_HEADERS = readline.h chardefs.h keymaps.h history.h tilde.h
+
+noinst_HEADERS = rldefs.h histlib.h rlwinsize.h \
+ posixstat.h posixdir.h posixjmp.h \
+ tilde.h rlconf.h rltty.h ansi_stdlib.h \
+ tcap.h rlstdc.h
+
+EXTRA_DIST= emacs_keymap.c vi_keymap.c
+
+DEFS = -DUNDEF_THREADS_HACK -DHAVE_CONFIG_H
diff --git a/readline/README b/readline/README
new file mode 100644
index 00000000000..56565b2fb80
--- /dev/null
+++ b/readline/README
@@ -0,0 +1,163 @@
+Introduction
+============
+
+This is the Gnu Readline library, version 4.0.
+
+The Readline library provides a set of functions for use by applications
+that allow users to edit command lines as they are typed in. Both
+Emacs and vi editing modes are available. The Readline library includes
+additional functions to maintain a list of previously-entered command
+lines, to recall and perhaps reedit those lines, and perform csh-like
+history expansion on previous commands.
+
+The history facilites are also placed into a separate library, the
+History library, as part of the build process. The History library
+may be used without Readline in applications which desire its
+capabilities.
+
+The Readline library is free software, distributed under the terms of
+the GNU Public License, version 2. For more information, see the file
+COPYING.
+
+To build the library, try typing `./configure', then `make'. The
+configuration process is automated, so no further intervention should
+be necessary. Readline builds with `gcc' by default if it is
+available. If you want to use `cc' instead, type
+
+ CC=cc ./configure
+
+if you are using a Bourne-style shell. If you are not, the following
+may work:
+
+ env CC=cc ./configure
+
+Read the file INSTALL in this directory for more information about how
+to customize and control the build process.
+
+The file rlconf.h contains C preprocessor defines that enable and disable
+certain Readline features.
+
+Examples
+========
+
+There are several example programs that use Readline features in the
+examples directory. The `rl' program is of particular interest. It
+is a command-line interface to Readline, suitable for use in shell
+scripts in place of `read'.
+
+Shared Libraries
+================
+
+There is skeletal support for building shared versions of the
+Readline and History libraries. The configure script creates
+a Makefile in the `shlib' subdirectory, and typing `make shared'
+will cause shared versions of the Readline and History libraries
+to be built on supported platforms.
+
+Configure calls the script support/shobj-conf to test whether or
+not shared library creation is supported and to generate the values
+of variables that are substituted into shlib/Makefile. If you
+try to build shared libraries on an unsupported platform, `make'
+will display a message asking you to update support/shobj-conf for
+your platform.
+
+If you need to update support/shobj-conf, you will need to create
+a `stanza' for your operating system and compiler. The script uses
+the value of host_os and ${CC} as determined by configure. For
+instance, FreeBSD 2.2.5 with any version of gcc is identified as
+`freebsd2.2.5-gcc*'.
+
+In the stanza for your operating system-compiler pair, you will need to
+define several variables. They are:
+
+SHOBJ_CC The C compiler used to compile source files into shareable
+ object files. This is normally set to the value of ${CC}
+ by configure, and should not need to be changed.
+
+SHOBJ_CFLAGS Flags to pass to the C compiler ($SHOBJ_CC) to create
+ position-independent code. If you are using gcc, this
+ should probably be set to `-fpic'.
+
+SHOBJ_LD The link editor to be used to create the shared library from
+ the object files created by $SHOBJ_CC. If you are using
+ gcc, a value of `gcc' will probably work.
+
+SHOBJ_LDFLAGS Flags to pass to SHOBJ_LD to enable shared object creation.
+ If you are using gcc, `-shared' may be all that is necessary.
+ These should be the flags needed for generic shared object
+ creation.
+
+SHLIB_XLDFLAGS Additional flags to pass to SHOBJ_LD for shared library
+ creation. Many systems use the -R option to the link
+ editor to embed a path within the library for run-time
+ library searches. A reasonable value for such systems would
+ be `-R$(libdir)'.
+
+SHLIB_LIBS Any additional libraries that shared libraries should be
+ linked against when they are created.
+
+SHLIB_LIBSUFF The suffix to add to `libreadline' and `libhistory' when
+ generating the filename of the shared library. Many systems
+ use `so'; HP-UX uses `sl'.
+
+SHLIB_LIBVERSION The string to append to the filename to indicate the version
+ of the shared library. It should begin with $(SHLIB_LIBSUFF),
+ and possibly include version information that allows the
+ run-time loader to load the version of the shared library
+ appropriate for a particular program. Systems using shared
+ libraries similar to SunOS 4.x use major and minor library
+ version numbers; for those systems a value of
+ `$(SHLIB_LIBSUFF).$(SHLIB_MAJOR)$(SHLIB_MINOR)' is appropriate.
+ Systems based on System V Release 4 don't use minor version
+ numbers; use `$(SHLIB_LIBSUFF).$(SHLIB_MAJOR)' on those systems.
+ Other Unix versions use different schemes.
+
+SHLIB_STATUS Set this to `supported' when you have defined the other
+ necessary variables. Make uses this to determine whether
+ or not shared library creation should be attempted.
+
+You should look at the existing stanzas in support/shobj-conf for ideas.
+
+Once you have updated support/shobj-conf, re-run configure and type
+`make shared'. The shared libraries will be created in the shlib
+subdirectory.
+
+Since shared libraries are not created on all platforms, `make install'
+will not automatically install the shared libraries. To install them,
+change the current directory to shlib and type `make install'. Running
+`make install-shared' from the top-level build directory will also work.
+
+Documentation
+=============
+
+The documentation for the Readline and History libraries appears in the
+`doc' subdirectory. There are two texinfo files and a Unix-style manual
+page describing the programming facilities available in the Readline
+library. The texinfo files include both user and programmer's manuals.
+
+Reporting Bugs
+==============
+
+Bug reports for Readline should be sent to:
+
+ bug-readline@gnu.org
+
+When reporting a bug, please include the following information:
+
+ * the version number and release status of Readline (e.g., 4.0-release)
+ * the machine and OS that it is running on
+ * a list of the compilation flags or the contents of `config.h', if
+ appropriate
+ * a description of the bug
+ * a recipe for recreating the bug reliably
+ * a fix for the bug if you have one!
+
+If you would like to contact the Readline maintainer directly, send mail
+to bash-maintainers@gnu.org.
+
+Since Readline is developed along with bash, the bug-bash@gnu.org mailing
+list (mirrored to the Usenet newsgroup gnu.bash.bug) often contains
+Readline bug reports and fixes.
+
+Chet Ramey
+chet@po.cwru.edu
diff --git a/readline/ansi_stdlib.h b/readline/ansi_stdlib.h
new file mode 100644
index 00000000000..52339da5d33
--- /dev/null
+++ b/readline/ansi_stdlib.h
@@ -0,0 +1,41 @@
+/* ansi_stdlib.h -- An ANSI Standard stdlib.h. */
+/* A minimal stdlib.h containing extern declarations for those functions
+ that bash uses. */
+
+/* Copyright (C) 1993 Free Software Foundation, Inc.
+
+ This file is part of GNU Bash, the Bourne Again SHell.
+
+ Bash is free software; you can redistribute 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.
+
+ Bash is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with Bash; see the file COPYING. If not, write to the Free Software
+ Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#if !defined (_STDLIB_H_)
+#define _STDLIB_H_ 1
+
+/* String conversion functions. */
+extern int atoi ();
+extern long int atol ();
+
+/* Memory allocation functions. */
+extern char *malloc ();
+extern char *realloc ();
+extern void free ();
+
+/* Other miscellaneous functions. */
+extern void abort ();
+extern void exit ();
+extern char *getenv ();
+extern void qsort ();
+
+#endif /* _STDLIB_H */
diff --git a/readline/bind.c b/readline/bind.c
new file mode 100644
index 00000000000..f446dc8cd10
--- /dev/null
+++ b/readline/bind.c
@@ -0,0 +1,1996 @@
+/* bind.c -- key binding and startup file support for the readline library. */
+
+/* Copyright (C) 1987, 1989, 1992 Free Software Foundation, Inc.
+
+ This file is part of the GNU Readline Library, a library for
+ reading lines of text with interactive input and history editing.
+
+ The GNU Readline Library is free software; you can redistribute it
+ and/or modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 1, or
+ (at your option) any later version.
+
+ The GNU Readline 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 General Public License for more details.
+
+ The GNU General Public License is often shipped with GNU software, and
+ is generally kept in a file called COPYING or LICENSE. If you do not
+ have a copy of the license, write to the Free Software Foundation,
+ 675 Mass Ave, Cambridge, MA 02139, USA. */
+#define READLINE_LIBRARY
+
+#if defined (HAVE_CONFIG_H)
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#if defined (HAVE_SYS_FILE_H)
+# include <sys/file.h>
+#endif /* HAVE_SYS_FILE_H */
+
+#if defined (HAVE_UNISTD_H)
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+
+#if defined (HAVE_STDLIB_H)
+# include <stdlib.h>
+#else
+# include "ansi_stdlib.h"
+#endif /* HAVE_STDLIB_H */
+
+#include <signal.h>
+#include <errno.h>
+
+#if !defined (errno)
+extern int errno;
+#endif /* !errno */
+
+#include "posixstat.h"
+
+/* System-specific feature definitions and include files. */
+#include "rldefs.h"
+
+/* Some standard library routines. */
+#include "readline.h"
+#include "history.h"
+
+#if !defined (strchr) && !defined (__STDC__)
+extern char *strchr (), *strrchr ();
+#endif /* !strchr && !__STDC__ */
+
+extern int _rl_horizontal_scroll_mode;
+extern int _rl_mark_modified_lines;
+extern int _rl_bell_preference;
+extern int _rl_meta_flag;
+extern int _rl_convert_meta_chars_to_ascii;
+extern int _rl_output_meta_chars;
+extern int _rl_complete_show_all;
+extern int _rl_complete_mark_directories;
+extern int _rl_print_completions_horizontally;
+extern int _rl_completion_case_fold;
+extern int _rl_enable_keypad;
+#if defined (PAREN_MATCHING)
+extern int rl_blink_matching_paren;
+#endif /* PAREN_MATCHING */
+#if defined (VISIBLE_STATS)
+extern int rl_visible_stats;
+#endif /* VISIBLE_STATS */
+extern int rl_complete_with_tilde_expansion;
+extern int rl_completion_query_items;
+extern int rl_inhibit_completion;
+extern char *_rl_comment_begin;
+extern unsigned char *_rl_isearch_terminators;
+
+extern int rl_explicit_arg;
+extern int rl_editing_mode;
+extern unsigned char _rl_parsing_conditionalized_out;
+extern Keymap _rl_keymap;
+
+extern char *possible_control_prefixes[], *possible_meta_prefixes[];
+
+/* Functions imported from funmap.c */
+extern char **rl_funmap_names ();
+extern int rl_add_funmap_entry ();
+
+/* Functions imported from util.c */
+extern char *_rl_strindex ();
+
+/* Functions imported from shell.c */
+extern char *get_env_value ();
+
+/* Variables exported by this file. */
+Keymap rl_binding_keymap;
+
+/* Forward declarations */
+void rl_set_keymap_from_edit_mode ();
+
+static int _rl_read_init_file ();
+static int glean_key_from_name ();
+static int substring_member_of_array ();
+
+extern char *xmalloc (), *xrealloc ();
+
+/* **************************************************************** */
+/* */
+/* Binding keys */
+/* */
+/* **************************************************************** */
+
+/* rl_add_defun (char *name, Function *function, int key)
+ Add NAME to the list of named functions. Make FUNCTION be the function
+ that gets called. If KEY is not -1, then bind it. */
+int
+rl_add_defun (name, function, key)
+ char *name;
+ Function *function;
+ int key;
+{
+ if (key != -1)
+ rl_bind_key (key, function);
+ rl_add_funmap_entry (name, function);
+ return 0;
+}
+
+/* Bind KEY to FUNCTION. Returns non-zero if KEY is out of range. */
+int
+rl_bind_key (key, function)
+ int key;
+ Function *function;
+{
+ if (key < 0)
+ return (key);
+
+ if (META_CHAR (key) && _rl_convert_meta_chars_to_ascii)
+ {
+ if (_rl_keymap[ESC].type == ISKMAP)
+ {
+ Keymap escmap;
+
+ escmap = FUNCTION_TO_KEYMAP (_rl_keymap, ESC);
+ key = UNMETA (key);
+ escmap[key].type = ISFUNC;
+ escmap[key].function = function;
+ return (0);
+ }
+ return (key);
+ }
+
+ _rl_keymap[key].type = ISFUNC;
+ _rl_keymap[key].function = function;
+ rl_binding_keymap = _rl_keymap;
+ return (0);
+}
+
+/* Bind KEY to FUNCTION in MAP. Returns non-zero in case of invalid
+ KEY. */
+int
+rl_bind_key_in_map (key, function, map)
+ int key;
+ Function *function;
+ Keymap map;
+{
+ int result;
+ Keymap oldmap;
+
+ oldmap = _rl_keymap;
+ _rl_keymap = map;
+ result = rl_bind_key (key, function);
+ _rl_keymap = oldmap;
+ return (result);
+}
+
+/* Make KEY do nothing in the currently selected keymap.
+ Returns non-zero in case of error. */
+int
+rl_unbind_key (key)
+ int key;
+{
+ return (rl_bind_key (key, (Function *)NULL));
+}
+
+/* Make KEY do nothing in MAP.
+ Returns non-zero in case of error. */
+int
+rl_unbind_key_in_map (key, map)
+ int key;
+ Keymap map;
+{
+ return (rl_bind_key_in_map (key, (Function *)NULL, map));
+}
+
+/* Unbind all keys bound to FUNCTION in MAP. */
+int
+rl_unbind_function_in_map (func, map)
+ Function *func;
+ Keymap map;
+{
+ register int i, rval;
+
+ for (i = rval = 0; i < KEYMAP_SIZE; i++)
+ {
+ if (map[i].type == ISFUNC && map[i].function == func)
+ {
+ map[i].function = (Function *)NULL;
+ rval = 1;
+ }
+ }
+ return rval;
+}
+
+int
+rl_unbind_command_in_map (command, map)
+ char *command;
+ Keymap map;
+{
+ Function *func;
+
+ func = rl_named_function (command);
+ if (func == 0)
+ return 0;
+ return (rl_unbind_function_in_map (func, map));
+}
+
+/* Bind the key sequence represented by the string KEYSEQ to
+ FUNCTION. This makes new keymaps as necessary. The initial
+ place to do bindings is in MAP. */
+int
+rl_set_key (keyseq, function, map)
+ char *keyseq;
+ Function *function;
+ Keymap map;
+{
+ return (rl_generic_bind (ISFUNC, keyseq, (char *)function, map));
+}
+
+/* Bind the key sequence represented by the string KEYSEQ to
+ the string of characters MACRO. This makes new keymaps as
+ necessary. The initial place to do bindings is in MAP. */
+int
+rl_macro_bind (keyseq, macro, map)
+ char *keyseq, *macro;
+ Keymap map;
+{
+ char *macro_keys;
+ int macro_keys_len;
+
+ macro_keys = (char *)xmalloc ((2 * strlen (macro)) + 1);
+
+ if (rl_translate_keyseq (macro, macro_keys, &macro_keys_len))
+ {
+ free (macro_keys);
+ return -1;
+ }
+ rl_generic_bind (ISMACR, keyseq, macro_keys, map);
+ return 0;
+}
+
+/* Bind the key sequence represented by the string KEYSEQ to
+ the arbitrary pointer DATA. TYPE says what kind of data is
+ pointed to by DATA, right now this can be a function (ISFUNC),
+ a macro (ISMACR), or a keymap (ISKMAP). This makes new keymaps
+ as necessary. The initial place to do bindings is in MAP. */
+int
+rl_generic_bind (type, keyseq, data, map)
+ int type;
+ char *keyseq, *data;
+ Keymap map;
+{
+ char *keys;
+ int keys_len;
+ register int i;
+
+ /* If no keys to bind to, exit right away. */
+ if (!keyseq || !*keyseq)
+ {
+ if (type == ISMACR)
+ free (data);
+ return -1;
+ }
+
+ keys = xmalloc (1 + (2 * strlen (keyseq)));
+
+ /* Translate the ASCII representation of KEYSEQ into an array of
+ characters. Stuff the characters into KEYS, and the length of
+ KEYS into KEYS_LEN. */
+ if (rl_translate_keyseq (keyseq, keys, &keys_len))
+ {
+ free (keys);
+ return -1;
+ }
+
+ /* Bind keys, making new keymaps as necessary. */
+ for (i = 0; i < keys_len; i++)
+ {
+ int ic = (int) ((unsigned char)keys[i]);
+
+ if (_rl_convert_meta_chars_to_ascii && META_CHAR (ic))
+ {
+ ic = UNMETA (ic);
+ if (map[ESC].type == ISKMAP)
+ map = FUNCTION_TO_KEYMAP (map, ESC);
+ }
+
+ if ((i + 1) < keys_len)
+ {
+ if (map[ic].type != ISKMAP)
+ {
+ if (map[ic].type == ISMACR)
+ free ((char *)map[ic].function);
+
+ map[ic].type = ISKMAP;
+ map[ic].function = KEYMAP_TO_FUNCTION (rl_make_bare_keymap());
+ }
+ map = FUNCTION_TO_KEYMAP (map, ic);
+ }
+ else
+ {
+ if (map[ic].type == ISMACR)
+ free ((char *)map[ic].function);
+
+ map[ic].function = KEYMAP_TO_FUNCTION (data);
+ map[ic].type = type;
+ }
+
+ rl_binding_keymap = map;
+ }
+ free (keys);
+ return 0;
+}
+
+/* Translate the ASCII representation of SEQ, stuffing the values into ARRAY,
+ an array of characters. LEN gets the final length of ARRAY. Return
+ non-zero if there was an error parsing SEQ. */
+int
+rl_translate_keyseq (seq, array, len)
+ char *seq, *array;
+ int *len;
+{
+ register int i, c, l, temp;
+
+ for (i = l = 0; c = seq[i]; i++)
+ {
+ if (c == '\\')
+ {
+ c = seq[++i];
+
+ if (c == 0)
+ break;
+
+ /* Handle \C- and \M- prefixes. */
+ if ((c == 'C' || c == 'M') && seq[i + 1] == '-')
+ {
+ /* Handle special case of backwards define. */
+ if (strncmp (&seq[i], "C-\\M-", 5) == 0)
+ {
+ array[l++] = ESC;
+ i += 5;
+ array[l++] = CTRL (_rl_to_upper (seq[i]));
+ if (seq[i] == '\0')
+ i--;
+ }
+ else if (c == 'M')
+ {
+ i++;
+ array[l++] = ESC; /* XXX */
+ }
+ else if (c == 'C')
+ {
+ i += 2;
+ /* Special hack for C-?... */
+ array[l++] = (seq[i] == '?') ? RUBOUT : CTRL (_rl_to_upper (seq[i]));
+ }
+ continue;
+ }
+
+ /* Translate other backslash-escaped characters. These are the
+ same escape sequences that bash's `echo' and `printf' builtins
+ handle, with the addition of \d -> RUBOUT. A backslash
+ preceding a character that is not special is stripped. */
+ switch (c)
+ {
+ case 'a':
+ array[l++] = '\007';
+ break;
+ case 'b':
+ array[l++] = '\b';
+ break;
+ case 'd':
+ array[l++] = RUBOUT; /* readline-specific */
+ break;
+ case 'e':
+ array[l++] = ESC;
+ break;
+ case 'f':
+ array[l++] = '\f';
+ break;
+ case 'n':
+ array[l++] = NEWLINE;
+ break;
+ case 'r':
+ array[l++] = RETURN;
+ break;
+ case 't':
+ array[l++] = TAB;
+ break;
+ case 'v':
+ array[l++] = 0x0B;
+ break;
+ case '\\':
+ array[l++] = '\\';
+ break;
+ case '0': case '1': case '2': case '3':
+ case '4': case '5': case '6': case '7':
+ i++;
+ for (temp = 2, c -= '0'; ISOCTAL (seq[i]) && temp--; i++)
+ c = (c * 8) + OCTVALUE (seq[i]);
+ i--; /* auto-increment in for loop */
+ array[l++] = c % (largest_char + 1);
+ break;
+ case 'x':
+ i++;
+ for (temp = 3, c = 0; isxdigit (seq[i]) && temp--; i++)
+ c = (c * 16) + HEXVALUE (seq[i]);
+ if (temp == 3)
+ c = 'x';
+ i--; /* auto-increment in for loop */
+ array[l++] = c % (largest_char + 1);
+ break;
+ default: /* backslashes before non-special chars just add the char */
+ array[l++] = c;
+ break; /* the backslash is stripped */
+ }
+ continue;
+ }
+
+ array[l++] = c;
+ }
+
+ *len = l;
+ array[l] = '\0';
+ return (0);
+}
+
+char *
+rl_untranslate_keyseq (seq)
+ int seq;
+{
+ static char kseq[16];
+ int i, c;
+
+ i = 0;
+ c = seq;
+ if (META_CHAR (c))
+ {
+ kseq[i++] = '\\';
+ kseq[i++] = 'M';
+ kseq[i++] = '-';
+ c = UNMETA (c);
+ }
+ else if (CTRL_CHAR (c))
+ {
+ kseq[i++] = '\\';
+ kseq[i++] = 'C';
+ kseq[i++] = '-';
+ c = _rl_to_lower (UNCTRL (c));
+ }
+ else if (c == RUBOUT)
+ {
+ kseq[i++] = '\\';
+ kseq[i++] = 'C';
+ kseq[i++] = '-';
+ c = '?';
+ }
+
+ if (c == ESC)
+ {
+ kseq[i++] = '\\';
+ c = 'e';
+ }
+ else if (c == '\\' || c == '"')
+ {
+ kseq[i++] = '\\';
+ }
+
+ kseq[i++] = (unsigned char) c;
+ kseq[i] = '\0';
+ return kseq;
+}
+
+static char *
+_rl_untranslate_macro_value (seq)
+ char *seq;
+{
+ char *ret, *r, *s;
+ int c;
+
+ r = ret = xmalloc (7 * strlen (seq) + 1);
+ for (s = seq; *s; s++)
+ {
+ c = *s;
+ if (META_CHAR (c))
+ {
+ *r++ = '\\';
+ *r++ = 'M';
+ *r++ = '-';
+ c = UNMETA (c);
+ }
+ else if (CTRL_CHAR (c) && c != ESC)
+ {
+ *r++ = '\\';
+ *r++ = 'C';
+ *r++ = '-';
+ c = _rl_to_lower (UNCTRL (c));
+ }
+ else if (c == RUBOUT)
+ {
+ *r++ = '\\';
+ *r++ = 'C';
+ *r++ = '-';
+ c = '?';
+ }
+
+ if (c == ESC)
+ {
+ *r++ = '\\';
+ c = 'e';
+ }
+ else if (c == '\\' || c == '"')
+ *r++ = '\\';
+
+ *r++ = (unsigned char)c;
+ }
+ *r = '\0';
+ return ret;
+}
+
+/* Return a pointer to the function that STRING represents.
+ If STRING doesn't have a matching function, then a NULL pointer
+ is returned. */
+Function *
+rl_named_function (string)
+ char *string;
+{
+ register int i;
+
+ rl_initialize_funmap ();
+
+ for (i = 0; funmap[i]; i++)
+ if (_rl_stricmp (funmap[i]->name, string) == 0)
+ return (funmap[i]->function);
+ return ((Function *)NULL);
+}
+
+/* Return the function (or macro) definition which would be invoked via
+ KEYSEQ if executed in MAP. If MAP is NULL, then the current keymap is
+ used. TYPE, if non-NULL, is a pointer to an int which will receive the
+ 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;
+{
+ register int i;
+
+ if (!map)
+ map = _rl_keymap;
+
+ for (i = 0; keyseq && keyseq[i]; i++)
+ {
+ int ic = keyseq[i];
+
+ if (META_CHAR (ic) && _rl_convert_meta_chars_to_ascii)
+ {
+ if (map[ESC].type != ISKMAP)
+ {
+ if (type)
+ *type = map[ESC].type;
+
+ return (map[ESC].function);
+ }
+ else
+ {
+ map = FUNCTION_TO_KEYMAP (map, ESC);
+ ic = UNMETA (ic);
+ }
+ }
+
+ if (map[ic].type == ISKMAP)
+ {
+ /* If this is the last key in the key sequence, return the
+ map. */
+ if (!keyseq[i + 1])
+ {
+ if (type)
+ *type = ISKMAP;
+
+ return (map[ic].function);
+ }
+ else
+ map = FUNCTION_TO_KEYMAP (map, ic);
+ }
+ else
+ {
+ if (type)
+ *type = map[ic].type;
+
+ return (map[ic].function);
+ }
+ }
+ return ((Function *) NULL);
+}
+
+/* The last key bindings file read. */
+static char *last_readline_init_file = (char *)NULL;
+
+/* The file we're currently reading key bindings from. */
+static char *current_readline_init_file;
+static int current_readline_init_include_level;
+static int current_readline_init_lineno;
+
+/* Read FILENAME into a locally-allocated buffer and return the buffer.
+ The size of the buffer is returned in *SIZEP. Returns NULL if any
+ errors were encountered. */
+static char *
+_rl_read_file (filename, sizep)
+ char *filename;
+ size_t *sizep;
+{
+ struct stat finfo;
+ size_t file_size;
+ char *buffer;
+ int i, file;
+
+ if ((stat (filename, &finfo) < 0) || (file = open (filename, O_RDONLY, 0666)) < 0)
+ return ((char *)NULL);
+
+ file_size = (size_t)finfo.st_size;
+
+ /* check for overflow on very large files */
+ if (file_size != finfo.st_size || file_size + 1 < file_size)
+ {
+ if (file >= 0)
+ close (file);
+#if defined (EFBIG)
+ errno = EFBIG;
+#endif
+ return ((char *)NULL);
+ }
+
+ /* Read the file into BUFFER. */
+ buffer = (char *)xmalloc (file_size + 1);
+ i = read (file, buffer, file_size);
+ close (file);
+
+#if 0
+ if (i < file_size)
+#else
+ if (i < 0)
+#endif
+ {
+ free (buffer);
+ return ((char *)NULL);
+ }
+
+ buffer[file_size] = '\0';
+ if (sizep)
+ *sizep = file_size;
+ return (buffer);
+}
+
+/* Re-read the current keybindings file. */
+int
+rl_re_read_init_file (count, ignore)
+ int count, ignore;
+{
+ int r;
+ r = rl_read_init_file ((char *)NULL);
+ rl_set_keymap_from_edit_mode ();
+ return r;
+}
+
+/* Do key bindings from a file. If FILENAME is NULL it defaults
+ to the first non-null filename from this list:
+ 1. the filename used for the previous call
+ 2. the value of the shell variable `INPUTRC'
+ 3. ~/.inputrc
+ 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;
+{
+ /* Default the filename. */
+ if (filename == 0)
+ {
+ filename = last_readline_init_file;
+ if (filename == 0)
+ filename = get_env_value ("INPUTRC");
+ if (filename == 0)
+ filename = DEFAULT_INPUTRC;
+ }
+
+ if (*filename == 0)
+ filename = DEFAULT_INPUTRC;
+
+ return (_rl_read_init_file (filename, 0));
+}
+
+static int
+_rl_read_init_file (filename, include_level)
+ char *filename;
+ int include_level;
+{
+ register int i;
+ char *buffer, *openname, *line, *end;
+ size_t file_size;
+
+ current_readline_init_file = filename;
+ current_readline_init_include_level = include_level;
+
+ openname = tilde_expand (filename);
+ buffer = _rl_read_file (openname, &file_size);
+ free (openname);
+
+ if (buffer == 0)
+ return (errno);
+
+ if (include_level == 0 && filename != last_readline_init_file)
+ {
+ FREE (last_readline_init_file);
+ last_readline_init_file = savestring (filename);
+ }
+
+ /* Loop over the lines in the file. Lines that start with `#' are
+ comments; all other lines are commands for readline initialization. */
+ current_readline_init_lineno = 1;
+ line = buffer;
+ end = buffer + file_size;
+ while (line < end)
+ {
+ /* Find the end of this line. */
+ for (i = 0; line + i != end && line[i] != '\n'; i++);
+
+ /* Mark end of line. */
+ line[i] = '\0';
+
+ /* Skip leading whitespace. */
+ while (*line && whitespace (*line))
+ {
+ line++;
+ i--;
+ }
+
+ /* If the line is not a comment, then parse it. */
+ if (*line && *line != '#')
+ rl_parse_and_bind (line);
+
+ /* Move to the next line. */
+ line += i + 1;
+ current_readline_init_lineno++;
+ }
+
+ free (buffer);
+ return (0);
+}
+
+static void
+_rl_init_file_error (msg)
+ char *msg;
+{
+ fprintf (stderr, "readline: %s: line %d: %s\n", current_readline_init_file,
+ current_readline_init_lineno,
+ msg);
+}
+
+/* **************************************************************** */
+/* */
+/* Parser Directives */
+/* */
+/* **************************************************************** */
+
+/* Conditionals. */
+
+/* Calling programs set this to have their argv[0]. */
+char *rl_readline_name = "other";
+
+/* Stack of previous values of parsing_conditionalized_out. */
+static unsigned char *if_stack = (unsigned char *)NULL;
+static int if_stack_depth;
+static int if_stack_size;
+
+/* Push _rl_parsing_conditionalized_out, and set parser state based
+ on ARGS. */
+static int
+parser_if (args)
+ char *args;
+{
+ register int i;
+
+ /* Push parser state. */
+ if (if_stack_depth + 1 >= if_stack_size)
+ {
+ if (!if_stack)
+ if_stack = (unsigned char *)xmalloc (if_stack_size = 20);
+ else
+ if_stack = (unsigned char *)xrealloc (if_stack, if_stack_size += 20);
+ }
+ if_stack[if_stack_depth++] = _rl_parsing_conditionalized_out;
+
+ /* If parsing is turned off, then nothing can turn it back on except
+ for finding the matching endif. In that case, return right now. */
+ if (_rl_parsing_conditionalized_out)
+ return 0;
+
+ /* Isolate first argument. */
+ for (i = 0; args[i] && !whitespace (args[i]); i++);
+
+ if (args[i])
+ args[i++] = '\0';
+
+ /* Handle "$if term=foo" and "$if mode=emacs" constructs. If this
+ isn't term=foo, or mode=emacs, then check to see if the first
+ word in ARGS is the same as the value stored in rl_readline_name. */
+ if (rl_terminal_name && _rl_strnicmp (args, "term=", 5) == 0)
+ {
+ char *tem, *tname;
+
+ /* Terminals like "aaa-60" are equivalent to "aaa". */
+ tname = savestring (rl_terminal_name);
+ tem = strchr (tname, '-');
+ if (tem)
+ *tem = '\0';
+
+ /* Test the `long' and `short' forms of the terminal name so that
+ if someone has a `sun-cmd' and does not want to have bindings
+ that will be executed if the terminal is a `sun', they can put
+ `$if term=sun-cmd' into their .inputrc. */
+ _rl_parsing_conditionalized_out = _rl_stricmp (args + 5, tname) &&
+ _rl_stricmp (args + 5, rl_terminal_name);
+ free (tname);
+ }
+#if defined (VI_MODE)
+ else if (_rl_strnicmp (args, "mode=", 5) == 0)
+ {
+ int mode;
+
+ if (_rl_stricmp (args + 5, "emacs") == 0)
+ mode = emacs_mode;
+ else if (_rl_stricmp (args + 5, "vi") == 0)
+ mode = vi_mode;
+ else
+ mode = no_mode;
+
+ _rl_parsing_conditionalized_out = mode != rl_editing_mode;
+ }
+#endif /* VI_MODE */
+ /* Check to see if the first word in ARGS is the same as the
+ value stored in rl_readline_name. */
+ else if (_rl_stricmp (args, rl_readline_name) == 0)
+ _rl_parsing_conditionalized_out = 0;
+ else
+ _rl_parsing_conditionalized_out = 1;
+ return 0;
+}
+
+/* Invert the current parser state if there is anything on the stack. */
+static int
+parser_else (args)
+ char *args;
+{
+ register int i;
+
+ if (if_stack_depth == 0)
+ {
+ _rl_init_file_error ("$else found without matching $if");
+ return 0;
+ }
+
+ /* Check the previous (n - 1) levels of the stack to make sure that
+ we haven't previously turned off parsing. */
+ for (i = 0; i < if_stack_depth - 1; i++)
+ if (if_stack[i] == 1)
+ return 0;
+
+ /* Invert the state of parsing if at top level. */
+ _rl_parsing_conditionalized_out = !_rl_parsing_conditionalized_out;
+ return 0;
+}
+
+/* Terminate a conditional, popping the value of
+ _rl_parsing_conditionalized_out from the stack. */
+static int
+parser_endif (args)
+ char *args;
+{
+ if (if_stack_depth)
+ _rl_parsing_conditionalized_out = if_stack[--if_stack_depth];
+ else
+ _rl_init_file_error ("$endif without matching $if");
+ return 0;
+}
+
+static int
+parser_include (args)
+ char *args;
+{
+ char *old_init_file, *e;
+ int old_line_number, old_include_level, r;
+
+ if (_rl_parsing_conditionalized_out)
+ return (0);
+
+ old_init_file = current_readline_init_file;
+ old_line_number = current_readline_init_lineno;
+ old_include_level = current_readline_init_include_level;
+
+ e = strchr (args, '\n');
+ if (e)
+ *e = '\0';
+ r = _rl_read_init_file (args, old_include_level + 1);
+
+ current_readline_init_file = old_init_file;
+ current_readline_init_lineno = old_line_number;
+ current_readline_init_include_level = old_include_level;
+
+ return r;
+}
+
+/* Associate textual names with actual functions. */
+static struct {
+ char *name;
+ Function *function;
+} parser_directives [] = {
+ { "if", parser_if },
+ { "endif", parser_endif },
+ { "else", parser_else },
+ { "include", parser_include },
+ { (char *)0x0, (Function *)0x0 }
+};
+
+/* Handle a parser directive. STATEMENT is the line of the directive
+ without any leading `$'. */
+static int
+handle_parser_directive (statement)
+ char *statement;
+{
+ register int i;
+ char *directive, *args;
+
+ /* Isolate the actual directive. */
+
+ /* Skip whitespace. */
+ for (i = 0; whitespace (statement[i]); i++);
+
+ directive = &statement[i];
+
+ for (; statement[i] && !whitespace (statement[i]); i++);
+
+ if (statement[i])
+ statement[i++] = '\0';
+
+ for (; statement[i] && whitespace (statement[i]); i++);
+
+ args = &statement[i];
+
+ /* Lookup the command, and act on it. */
+ for (i = 0; parser_directives[i].name; i++)
+ if (_rl_stricmp (directive, parser_directives[i].name) == 0)
+ {
+ (*parser_directives[i].function) (args);
+ return (0);
+ }
+
+ /* display an error message about the unknown parser directive */
+ _rl_init_file_error ("unknown parser directive");
+ return (1);
+}
+
+/* Read the binding command from STRING and perform it.
+ A key binding command looks like: Keyname: function-name\0,
+ a variable binding command looks like: set variable value.
+ A new-style keybinding looks like "\C-x\C-x": exchange-point-and-mark. */
+int
+rl_parse_and_bind (string)
+ char *string;
+{
+ char *funname, *kname;
+ register int c, i;
+ int key, equivalency;
+
+ while (string && whitespace (*string))
+ string++;
+
+ if (!string || !*string || *string == '#')
+ return 0;
+
+ /* If this is a parser directive, act on it. */
+ if (*string == '$')
+ {
+ handle_parser_directive (&string[1]);
+ return 0;
+ }
+
+ /* If we aren't supposed to be parsing right now, then we're done. */
+ if (_rl_parsing_conditionalized_out)
+ return 0;
+
+ i = 0;
+ /* If this keyname is a complex key expression surrounded by quotes,
+ advance to after the matching close quote. This code allows the
+ backslash to quote characters in the key expression. */
+ if (*string == '"')
+ {
+ int passc = 0;
+
+ for (i = 1; c = string[i]; i++)
+ {
+ if (passc)
+ {
+ passc = 0;
+ continue;
+ }
+
+ if (c == '\\')
+ {
+ passc++;
+ continue;
+ }
+
+ if (c == '"')
+ break;
+ }
+ /* If we didn't find a closing quote, abort the line. */
+ if (string[i] == '\0')
+ {
+ _rl_init_file_error ("no closing `\"' in key binding");
+ return 1;
+ }
+ }
+
+ /* Advance to the colon (:) or whitespace which separates the two objects. */
+ for (; (c = string[i]) && c != ':' && c != ' ' && c != '\t'; i++ );
+
+ equivalency = (c == ':' && string[i + 1] == '=');
+
+ /* Mark the end of the command (or keyname). */
+ if (string[i])
+ string[i++] = '\0';
+
+ /* If doing assignment, skip the '=' sign as well. */
+ if (equivalency)
+ string[i++] = '\0';
+
+ /* If this is a command to set a variable, then do that. */
+ if (_rl_stricmp (string, "set") == 0)
+ {
+ char *var = string + i;
+ char *value;
+
+ /* Make VAR point to start of variable name. */
+ while (*var && whitespace (*var)) var++;
+
+ /* Make value point to start of value string. */
+ value = var;
+ while (*value && !whitespace (*value)) value++;
+ if (*value)
+ *value++ = '\0';
+ while (*value && whitespace (*value)) value++;
+
+ rl_variable_bind (var, value);
+ return 0;
+ }
+
+ /* Skip any whitespace between keyname and funname. */
+ for (; string[i] && whitespace (string[i]); i++);
+ funname = &string[i];
+
+ /* Now isolate funname.
+ For straight function names just look for whitespace, since
+ that will signify the end of the string. But this could be a
+ macro definition. In that case, the string is quoted, so skip
+ to the matching delimiter. We allow the backslash to quote the
+ delimiter characters in the macro body. */
+ /* This code exists to allow whitespace in macro expansions, which
+ would otherwise be gobbled up by the next `for' loop.*/
+ /* XXX - it may be desirable to allow backslash quoting only if " is
+ the quoted string delimiter, like the shell. */
+ if (*funname == '\'' || *funname == '"')
+ {
+ int delimiter = string[i++], passc;
+
+ for (passc = 0; c = string[i]; i++)
+ {
+ if (passc)
+ {
+ passc = 0;
+ continue;
+ }
+
+ if (c == '\\')
+ {
+ passc = 1;
+ continue;
+ }
+
+ if (c == delimiter)
+ break;
+ }
+ if (c)
+ i++;
+ }
+
+ /* Advance to the end of the string. */
+ for (; string[i] && !whitespace (string[i]); i++);
+
+ /* No extra whitespace at the end of the string. */
+ string[i] = '\0';
+
+ /* Handle equivalency bindings here. Make the left-hand side be exactly
+ whatever the right-hand evaluates to, including keymaps. */
+ if (equivalency)
+ {
+ return 0;
+ }
+
+ /* If this is a new-style key-binding, then do the binding with
+ rl_set_key (). Otherwise, let the older code deal with it. */
+ if (*string == '"')
+ {
+ char *seq;
+ register int j, k, passc;
+
+ seq = xmalloc (1 + strlen (string));
+ for (j = 1, k = passc = 0; string[j]; j++)
+ {
+ /* Allow backslash to quote characters, but leave them in place.
+ This allows a string to end with a backslash quoting another
+ backslash, or with a backslash quoting a double quote. The
+ backslashes are left in place for rl_translate_keyseq (). */
+ if (passc || (string[j] == '\\'))
+ {
+ seq[k++] = string[j];
+ passc = !passc;
+ continue;
+ }
+
+ if (string[j] == '"')
+ break;
+
+ seq[k++] = string[j];
+ }
+ seq[k] = '\0';
+
+ /* Binding macro? */
+ if (*funname == '\'' || *funname == '"')
+ {
+ j = strlen (funname);
+
+ /* Remove the delimiting quotes from each end of FUNNAME. */
+ if (j && funname[j - 1] == *funname)
+ funname[j - 1] = '\0';
+
+ rl_macro_bind (seq, &funname[1], _rl_keymap);
+ }
+ else
+ rl_set_key (seq, rl_named_function (funname), _rl_keymap);
+
+ free (seq);
+ return 0;
+ }
+
+ /* Get the actual character we want to deal with. */
+ kname = strrchr (string, '-');
+ if (!kname)
+ kname = string;
+ else
+ kname++;
+
+ key = glean_key_from_name (kname);
+
+ /* Add in control and meta bits. */
+ if (substring_member_of_array (string, possible_control_prefixes))
+ key = CTRL (_rl_to_upper (key));
+
+ if (substring_member_of_array (string, possible_meta_prefixes))
+ key = META (key);
+
+ /* Temporary. Handle old-style keyname with macro-binding. */
+ if (*funname == '\'' || *funname == '"')
+ {
+ unsigned char useq[2];
+ int fl = strlen (funname);
+
+ useq[0] = key; useq[1] = '\0';
+ if (fl && funname[fl - 1] == *funname)
+ funname[fl - 1] = '\0';
+
+ rl_macro_bind (useq, &funname[1], _rl_keymap);
+ }
+#if defined (PREFIX_META_HACK)
+ /* Ugly, but working hack to keep prefix-meta around. */
+ else if (_rl_stricmp (funname, "prefix-meta") == 0)
+ {
+ char seq[2];
+
+ seq[0] = key;
+ seq[1] = '\0';
+ rl_generic_bind (ISKMAP, seq, (char *)emacs_meta_keymap, _rl_keymap);
+ }
+#endif /* PREFIX_META_HACK */
+ else
+ rl_bind_key (key, rl_named_function (funname));
+ return 0;
+}
+
+/* Simple structure for boolean readline variables (i.e., those that can
+ have one of two values; either "On" or 1 for truth, or "Off" or 0 for
+ false. */
+
+static struct {
+ char *name;
+ int *value;
+} boolean_varlist [] = {
+#if defined (PAREN_MATCHING)
+ { "blink-matching-paren", &rl_blink_matching_paren },
+#endif
+ { "completion-ignore-case", &_rl_completion_case_fold },
+ { "convert-meta", &_rl_convert_meta_chars_to_ascii },
+ { "disable-completion", &rl_inhibit_completion },
+ { "enable-keypad", &_rl_enable_keypad },
+ { "expand-tilde", &rl_complete_with_tilde_expansion },
+ { "horizontal-scroll-mode", &_rl_horizontal_scroll_mode },
+ { "input-meta", &_rl_meta_flag },
+ { "mark-directories", &_rl_complete_mark_directories },
+ { "mark-modified-lines", &_rl_mark_modified_lines },
+ { "meta-flag", &_rl_meta_flag },
+ { "output-meta", &_rl_output_meta_chars },
+ { "print-completions-horizontally", &_rl_print_completions_horizontally },
+ { "show-all-if-ambiguous", &_rl_complete_show_all },
+#if defined (VISIBLE_STATS)
+ { "visible-stats", &rl_visible_stats },
+#endif /* VISIBLE_STATS */
+ { (char *)NULL, (int *)NULL }
+};
+
+int
+rl_variable_bind (name, value)
+ char *name, *value;
+{
+ register int i;
+
+ /* Check for simple variables first. */
+ for (i = 0; boolean_varlist[i].name; i++)
+ {
+ if (_rl_stricmp (name, boolean_varlist[i].name) == 0)
+ {
+ /* A variable is TRUE if the "value" is "on", "1" or "". */
+ *boolean_varlist[i].value = *value == 0 ||
+ _rl_stricmp (value, "on") == 0 ||
+ (value[0] == '1' && value[1] == '\0');
+ return 0;
+ }
+ }
+
+ /* Not a boolean variable, so check for specials. */
+
+ /* Editing mode change? */
+ if (_rl_stricmp (name, "editing-mode") == 0)
+ {
+ if (_rl_strnicmp (value, "vi", 2) == 0)
+ {
+#if defined (VI_MODE)
+ _rl_keymap = vi_insertion_keymap;
+ rl_editing_mode = vi_mode;
+#endif /* VI_MODE */
+ }
+ else if (_rl_strnicmp (value, "emacs", 5) == 0)
+ {
+ _rl_keymap = emacs_standard_keymap;
+ rl_editing_mode = emacs_mode;
+ }
+ }
+
+ /* Comment string change? */
+ else if (_rl_stricmp (name, "comment-begin") == 0)
+ {
+ if (*value)
+ {
+ if (_rl_comment_begin)
+ free (_rl_comment_begin);
+
+ _rl_comment_begin = savestring (value);
+ }
+ }
+ else if (_rl_stricmp (name, "completion-query-items") == 0)
+ {
+ int nval = 100;
+ if (*value)
+ {
+ nval = atoi (value);
+ if (nval < 0)
+ nval = 0;
+ }
+ rl_completion_query_items = nval;
+ }
+ else if (_rl_stricmp (name, "keymap") == 0)
+ {
+ Keymap kmap;
+ kmap = rl_get_keymap_by_name (value);
+ if (kmap)
+ rl_set_keymap (kmap);
+ }
+ else if (_rl_stricmp (name, "bell-style") == 0)
+ {
+ if (!*value)
+ _rl_bell_preference = AUDIBLE_BELL;
+ else
+ {
+ if (_rl_stricmp (value, "none") == 0 || _rl_stricmp (value, "off") == 0)
+ _rl_bell_preference = NO_BELL;
+ else if (_rl_stricmp (value, "audible") == 0 || _rl_stricmp (value, "on") == 0)
+ _rl_bell_preference = AUDIBLE_BELL;
+ else if (_rl_stricmp (value, "visible") == 0)
+ _rl_bell_preference = VISIBLE_BELL;
+ }
+ }
+ else if (_rl_stricmp (name, "prefer-visible-bell") == 0)
+ {
+ /* Backwards compatibility. */
+ if (*value && (_rl_stricmp (value, "on") == 0 ||
+ (*value == '1' && !value[1])))
+ _rl_bell_preference = VISIBLE_BELL;
+ else
+ _rl_bell_preference = AUDIBLE_BELL;
+ }
+ else if (_rl_stricmp (name, "isearch-terminators") == 0)
+ {
+ /* Isolate the value and translate it into a character string. */
+ int beg, end;
+ char *v;
+
+ v = savestring (value);
+ FREE (_rl_isearch_terminators);
+ if (v[0] == '"' || v[0] == '\'')
+ {
+ int delim = v[0];
+ for (beg = end = 1; v[end] && v[end] != delim; end++)
+ ;
+ }
+ else
+ {
+ for (beg = end = 0; whitespace (v[end]) == 0; end++)
+ ;
+ }
+
+ v[end] = '\0';
+ /* The value starts at v + beg. Translate it into a character string. */
+ _rl_isearch_terminators = (unsigned char *)xmalloc (2 * strlen (v) + 1);
+ rl_translate_keyseq (v + beg, _rl_isearch_terminators, &end);
+ _rl_isearch_terminators[end] = '\0';
+ free (v);
+ }
+
+ /* For the time being, unknown variable names are simply ignored. */
+ return 0;
+}
+
+/* Return the character which matches NAME.
+ For example, `Space' returns ' '. */
+
+typedef struct {
+ char *name;
+ int value;
+} assoc_list;
+
+static assoc_list name_key_alist[] = {
+ { "DEL", 0x7f },
+ { "ESC", '\033' },
+ { "Escape", '\033' },
+ { "LFD", '\n' },
+ { "Newline", '\n' },
+ { "RET", '\r' },
+ { "Return", '\r' },
+ { "Rubout", 0x7f },
+ { "SPC", ' ' },
+ { "Space", ' ' },
+ { "Tab", 0x09 },
+ { (char *)0x0, 0 }
+};
+
+static int
+glean_key_from_name (name)
+ char *name;
+{
+ register int i;
+
+ for (i = 0; name_key_alist[i].name; i++)
+ if (_rl_stricmp (name, name_key_alist[i].name) == 0)
+ return (name_key_alist[i].value);
+
+ return (*(unsigned char *)name); /* XXX was return (*name) */
+}
+
+/* Auxiliary functions to manage keymaps. */
+static struct {
+ char *name;
+ Keymap map;
+} keymap_names[] = {
+ { "emacs", emacs_standard_keymap },
+ { "emacs-standard", emacs_standard_keymap },
+ { "emacs-meta", emacs_meta_keymap },
+ { "emacs-ctlx", emacs_ctlx_keymap },
+#if defined (VI_MODE)
+ { "vi", vi_movement_keymap },
+ { "vi-move", vi_movement_keymap },
+ { "vi-command", vi_movement_keymap },
+ { "vi-insert", vi_insertion_keymap },
+#endif /* VI_MODE */
+ { (char *)0x0, (Keymap)0x0 }
+};
+
+Keymap
+rl_get_keymap_by_name (name)
+ char *name;
+{
+ register int i;
+
+ for (i = 0; keymap_names[i].name; i++)
+ if (strcmp (name, keymap_names[i].name) == 0)
+ return (keymap_names[i].map);
+ return ((Keymap) NULL);
+}
+
+char *
+rl_get_keymap_name (map)
+ Keymap map;
+{
+ register int i;
+ for (i = 0; keymap_names[i].name; i++)
+ if (map == keymap_names[i].map)
+ return (keymap_names[i].name);
+ return ((char *)NULL);
+}
+
+void
+rl_set_keymap (map)
+ Keymap map;
+{
+ if (map)
+ _rl_keymap = map;
+}
+
+Keymap
+rl_get_keymap ()
+{
+ return (_rl_keymap);
+}
+
+void
+rl_set_keymap_from_edit_mode ()
+{
+ if (rl_editing_mode == emacs_mode)
+ _rl_keymap = emacs_standard_keymap;
+#if defined (VI_MODE)
+ else if (rl_editing_mode == vi_mode)
+ _rl_keymap = vi_insertion_keymap;
+#endif /* VI_MODE */
+}
+
+char *
+rl_get_keymap_name_from_edit_mode ()
+{
+ if (rl_editing_mode == emacs_mode)
+ return "emacs";
+#if defined (VI_MODE)
+ else if (rl_editing_mode == vi_mode)
+ return "vi";
+#endif /* VI_MODE */
+ else
+ return "none";
+}
+
+/* **************************************************************** */
+/* */
+/* Key Binding and Function Information */
+/* */
+/* **************************************************************** */
+
+/* Each of the following functions produces information about the
+ state of keybindings and functions known to Readline. The info
+ is always printed to rl_outstream, and in such a way that it can
+ be read back in (i.e., passed to rl_parse_and_bind (). */
+
+/* Print the names of functions known to Readline. */
+void
+rl_list_funmap_names ()
+{
+ register int i;
+ char **funmap_names;
+
+ funmap_names = rl_funmap_names ();
+
+ if (!funmap_names)
+ return;
+
+ for (i = 0; funmap_names[i]; i++)
+ fprintf (rl_outstream, "%s\n", funmap_names[i]);
+
+ free (funmap_names);
+}
+
+static char *
+_rl_get_keyname (key)
+ int key;
+{
+ char *keyname;
+ int i, c;
+
+ keyname = (char *)xmalloc (8);
+
+ c = key;
+ /* Since this is going to be used to write out keysequence-function
+ pairs for possible inclusion in an inputrc file, we don't want to
+ do any special meta processing on KEY. */
+
+#if 0
+ /* We might want to do this, but the old version of the code did not. */
+
+ /* If this is an escape character, we don't want to do any more processing.
+ Just add the special ESC key sequence and return. */
+ if (c == ESC)
+ {
+ keyseq[0] = '\\';
+ keyseq[1] = 'e';
+ keyseq[2] = '\0';
+ return keyseq;
+ }
+#endif
+
+ /* RUBOUT is translated directly into \C-? */
+ if (key == RUBOUT)
+ {
+ keyname[0] = '\\';
+ keyname[1] = 'C';
+ keyname[2] = '-';
+ keyname[3] = '?';
+ keyname[4] = '\0';
+ return keyname;
+ }
+
+ i = 0;
+ /* Now add special prefixes needed for control characters. This can
+ potentially change C. */
+ if (CTRL_CHAR (c))
+ {
+ keyname[i++] = '\\';
+ keyname[i++] = 'C';
+ keyname[i++] = '-';
+ c = _rl_to_lower (UNCTRL (c));
+ }
+
+ /* XXX experimental code. Turn the characters that are not ASCII or
+ ISO Latin 1 (128 - 159) into octal escape sequences (\200 - \237).
+ This changes C. */
+ if (c >= 128 && c <= 159)
+ {
+ keyname[i++] = '\\';
+ keyname[i++] = '2';
+ c -= 128;
+ keyname[i++] = (c / 8) + '0';
+ c = (c % 8) + '0';
+ }
+
+ /* Now, if the character needs to be quoted with a backslash, do that. */
+ if (c == '\\' || c == '"')
+ keyname[i++] = '\\';
+
+ /* Now add the key, terminate the string, and return it. */
+ keyname[i++] = (char) c;
+ keyname[i] = '\0';
+
+ return keyname;
+}
+
+/* Return a NULL terminated array of strings which represent the key
+ sequences that are used to invoke FUNCTION in MAP. */
+char **
+rl_invoking_keyseqs_in_map (function, map)
+ Function *function;
+ Keymap map;
+{
+ register int key;
+ char **result;
+ int result_index, result_size;
+
+ result = (char **)NULL;
+ result_index = result_size = 0;
+
+ for (key = 0; key < KEYMAP_SIZE; key++)
+ {
+ switch (map[key].type)
+ {
+ case ISMACR:
+ /* Macros match, if, and only if, the pointers are identical.
+ Thus, they are treated exactly like functions in here. */
+ case ISFUNC:
+ /* If the function in the keymap is the one we are looking for,
+ then add the current KEY to the list of invoking keys. */
+ if (map[key].function == function)
+ {
+ char *keyname;
+
+ keyname = _rl_get_keyname (key);
+
+ if (result_index + 2 > result_size)
+ {
+ result_size += 10;
+ result = (char **) xrealloc (result, result_size * sizeof (char *));
+ }
+
+ result[result_index++] = keyname;
+ result[result_index] = (char *)NULL;
+ }
+ break;
+
+ case ISKMAP:
+ {
+ char **seqs;
+ register int i;
+
+ /* Find the list of keyseqs in this map which have FUNCTION as
+ their target. Add the key sequences found to RESULT. */
+ if (map[key].function)
+ seqs =
+ rl_invoking_keyseqs_in_map (function, FUNCTION_TO_KEYMAP (map, key));
+ else
+ break;
+
+ if (seqs == 0)
+ break;
+
+ for (i = 0; seqs[i]; i++)
+ {
+ char *keyname = (char *)xmalloc (6 + strlen (seqs[i]));
+
+ if (key == ESC)
+ sprintf (keyname, "\\e");
+ else if (CTRL_CHAR (key))
+ sprintf (keyname, "\\C-%c", _rl_to_lower (UNCTRL (key)));
+ else if (key == RUBOUT)
+ sprintf (keyname, "\\C-?");
+ else if (key == '\\' || key == '"')
+ {
+ keyname[0] = '\\';
+ keyname[1] = (char) key;
+ keyname[2] = '\0';
+ }
+ else
+ {
+ keyname[0] = (char) key;
+ keyname[1] = '\0';
+ }
+
+ strcat (keyname, seqs[i]);
+ free (seqs[i]);
+
+ if (result_index + 2 > result_size)
+ {
+ result_size += 10;
+ result = (char **) xrealloc (result, result_size * sizeof (char *));
+ }
+
+ result[result_index++] = keyname;
+ result[result_index] = (char *)NULL;
+ }
+
+ free (seqs);
+ }
+ break;
+ }
+ }
+ return (result);
+}
+
+/* Return a NULL terminated array of strings which represent the key
+ sequences that can be used to invoke FUNCTION using the current keymap. */
+char **
+rl_invoking_keyseqs (function)
+ Function *function;
+{
+ return (rl_invoking_keyseqs_in_map (function, _rl_keymap));
+}
+
+/* Print all of the functions and their bindings to rl_outstream. If
+ PRINT_READABLY is non-zero, then print the output in such a way
+ that it can be read back in. */
+void
+rl_function_dumper (print_readably)
+ int print_readably;
+{
+ register int i;
+ char **names;
+ char *name;
+
+ names = rl_funmap_names ();
+
+ fprintf (rl_outstream, "\n");
+
+ for (i = 0; name = names[i]; i++)
+ {
+ Function *function;
+ char **invokers;
+
+ function = rl_named_function (name);
+ invokers = rl_invoking_keyseqs_in_map (function, _rl_keymap);
+
+ if (print_readably)
+ {
+ if (!invokers)
+ fprintf (rl_outstream, "# %s (not bound)\n", name);
+ else
+ {
+ register int j;
+
+ for (j = 0; invokers[j]; j++)
+ {
+ fprintf (rl_outstream, "\"%s\": %s\n",
+ invokers[j], name);
+ free (invokers[j]);
+ }
+
+ free (invokers);
+ }
+ }
+ else
+ {
+ if (!invokers)
+ fprintf (rl_outstream, "%s is not bound to any keys\n",
+ name);
+ else
+ {
+ register int j;
+
+ fprintf (rl_outstream, "%s can be found on ", name);
+
+ for (j = 0; invokers[j] && j < 5; j++)
+ {
+ fprintf (rl_outstream, "\"%s\"%s", invokers[j],
+ invokers[j + 1] ? ", " : ".\n");
+ }
+
+ if (j == 5 && invokers[j])
+ fprintf (rl_outstream, "...\n");
+
+ for (j = 0; invokers[j]; j++)
+ free (invokers[j]);
+
+ free (invokers);
+ }
+ }
+ }
+}
+
+/* Print all of the current functions and their bindings to
+ 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;
+{
+ if (rl_dispatching)
+ fprintf (rl_outstream, "\r\n");
+ rl_function_dumper (rl_explicit_arg);
+ rl_on_new_line ();
+ return (0);
+}
+
+static void
+_rl_macro_dumper_internal (print_readably, map, prefix)
+ int print_readably;
+ Keymap map;
+ char *prefix;
+{
+ register int key;
+ char *keyname, *out;
+ int prefix_len;
+
+ for (key = 0; key < KEYMAP_SIZE; key++)
+ {
+ switch (map[key].type)
+ {
+ case ISMACR:
+ keyname = _rl_get_keyname (key);
+#if 0
+ out = (char *)map[key].function;
+#else
+ out = _rl_untranslate_macro_value ((char *)map[key].function);
+#endif
+ if (print_readably)
+ fprintf (rl_outstream, "\"%s%s\": \"%s\"\n", prefix ? prefix : "",
+ keyname,
+ out ? out : "");
+ else
+ fprintf (rl_outstream, "%s%s outputs %s\n", prefix ? prefix : "",
+ keyname,
+ out ? out : "");
+ free (keyname);
+#if 1
+ free (out);
+#endif
+ break;
+ case ISFUNC:
+ break;
+ case ISKMAP:
+ prefix_len = prefix ? strlen (prefix) : 0;
+ if (key == ESC)
+ {
+ keyname = xmalloc (3 + prefix_len);
+ if (prefix)
+ strcpy (keyname, prefix);
+ keyname[prefix_len] = '\\';
+ keyname[prefix_len + 1] = 'e';
+ keyname[prefix_len + 2] = '\0';
+ }
+ else
+ {
+ keyname = _rl_get_keyname (key);
+ if (prefix)
+ {
+ out = xmalloc (strlen (keyname) + prefix_len + 1);
+ strcpy (out, prefix);
+ strcpy (out + prefix_len, keyname);
+ free (keyname);
+ keyname = out;
+ }
+ }
+
+ _rl_macro_dumper_internal (print_readably, FUNCTION_TO_KEYMAP (map, key), keyname);
+ free (keyname);
+ break;
+ }
+ }
+}
+
+void
+rl_macro_dumper (print_readably)
+ int print_readably;
+{
+ _rl_macro_dumper_internal (print_readably, _rl_keymap, (char *)NULL);
+}
+
+int
+rl_dump_macros (count, key)
+ int count, key;
+{
+ if (rl_dispatching)
+ fprintf (rl_outstream, "\r\n");
+ rl_macro_dumper (rl_explicit_arg);
+ rl_on_new_line ();
+ return (0);
+}
+
+void
+rl_variable_dumper (print_readably)
+ int print_readably;
+{
+ int i;
+ char *kname;
+
+ for (i = 0; boolean_varlist[i].name; i++)
+ {
+ if (print_readably)
+ fprintf (rl_outstream, "set %s %s\n", boolean_varlist[i].name,
+ *boolean_varlist[i].value ? "on" : "off");
+ else
+ fprintf (rl_outstream, "%s is set to `%s'\n", boolean_varlist[i].name,
+ *boolean_varlist[i].value ? "on" : "off");
+ }
+
+ /* bell-style */
+ switch (_rl_bell_preference)
+ {
+ case NO_BELL:
+ kname = "none"; break;
+ case VISIBLE_BELL:
+ kname = "visible"; break;
+ case AUDIBLE_BELL:
+ default:
+ kname = "audible"; break;
+ }
+ if (print_readably)
+ fprintf (rl_outstream, "set bell-style %s\n", kname);
+ else
+ fprintf (rl_outstream, "bell-style is set to `%s'\n", kname);
+
+ /* comment-begin */
+ if (print_readably)
+ fprintf (rl_outstream, "set comment-begin %s\n", _rl_comment_begin ? _rl_comment_begin : RL_COMMENT_BEGIN_DEFAULT);
+ else
+ fprintf (rl_outstream, "comment-begin is set to `%s'\n", _rl_comment_begin ? _rl_comment_begin : "");
+
+ /* completion-query-items */
+ if (print_readably)
+ fprintf (rl_outstream, "set completion-query-items %d\n", rl_completion_query_items);
+ else
+ fprintf (rl_outstream, "completion-query-items is set to `%d'\n", rl_completion_query_items);
+
+ /* editing-mode */
+ if (print_readably)
+ fprintf (rl_outstream, "set editing-mode %s\n", (rl_editing_mode == emacs_mode) ? "emacs" : "vi");
+ else
+ fprintf (rl_outstream, "editing-mode is set to `%s'\n", (rl_editing_mode == emacs_mode) ? "emacs" : "vi");
+
+ /* keymap */
+ kname = rl_get_keymap_name (_rl_keymap);
+ if (kname == 0)
+ kname = rl_get_keymap_name_from_edit_mode ();
+ if (print_readably)
+ fprintf (rl_outstream, "set keymap %s\n", kname ? kname : "none");
+ else
+ fprintf (rl_outstream, "keymap is set to `%s'\n", kname ? kname : "none");
+
+ /* isearch-terminators */
+ if (_rl_isearch_terminators)
+ {
+ char *disp;
+
+ disp = _rl_untranslate_macro_value (_rl_isearch_terminators);
+
+ if (print_readably)
+ fprintf (rl_outstream, "set isearch-terminators \"%s\"\n", disp);
+ else
+ fprintf (rl_outstream, "isearch-terminators is set to \"%s\"\n", disp);
+
+ free (disp);
+ }
+}
+
+/* Print all of the current variables and their values to
+ 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;
+{
+ if (rl_dispatching)
+ fprintf (rl_outstream, "\r\n");
+ rl_variable_dumper (rl_explicit_arg);
+ rl_on_new_line ();
+ return (0);
+}
+
+/* Bind key sequence KEYSEQ to DEFAULT_FUNC if KEYSEQ is unbound. */
+void
+_rl_bind_if_unbound (keyseq, default_func)
+ char *keyseq;
+ Function *default_func;
+{
+ Function *func;
+
+ if (keyseq)
+ {
+ func = rl_function_of_keyseq (keyseq, _rl_keymap, (int *)NULL);
+ if (!func || func == rl_do_lowercase_version)
+ rl_set_key (keyseq, default_func, _rl_keymap);
+ }
+}
+
+/* Return non-zero if any members of ARRAY are a substring in STRING. */
+static int
+substring_member_of_array (string, array)
+ char *string, **array;
+{
+ while (*array)
+ {
+ if (_rl_strindex (string, *array))
+ return (1);
+ array++;
+ }
+ return (0);
+}
diff --git a/readline/callback.c b/readline/callback.c
new file mode 100644
index 00000000000..6915be483a4
--- /dev/null
+++ b/readline/callback.c
@@ -0,0 +1,149 @@
+/* callback.c -- functions to use readline as an X `callback' mechanism. */
+
+/* Copyright (C) 1987, 1989, 1992 Free Software Foundation, Inc.
+
+ This file is part of the GNU Readline Library, a library for
+ reading lines of text with interactive input and history editing.
+
+ The GNU Readline Library is free software; you can redistribute it
+ and/or modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 1, or
+ (at your option) any later version.
+
+ The GNU Readline 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 General Public License for more details.
+
+ The GNU General Public License is often shipped with GNU software, and
+ is generally kept in a file called COPYING or LICENSE. If you do not
+ have a copy of the license, write to the Free Software Foundation,
+ 675 Mass Ave, Cambridge, MA 02139, USA. */
+#define READLINE_LIBRARY
+
+#if defined (HAVE_CONFIG_H)
+# include <config.h>
+#endif
+
+#include "rlconf.h"
+
+#if defined (READLINE_CALLBACKS)
+
+#include <sys/types.h>
+#include <stdio.h>
+
+/* System-specific feature definitions and include files. */
+#include "rldefs.h"
+#include "readline.h"
+
+extern void readline_internal_setup ();
+extern char *readline_internal_teardown ();
+extern int readline_internal_char ();
+extern void _rl_init_line_state ();
+
+extern int _rl_meta_flag;
+extern char *rl_prompt;
+extern int rl_visible_prompt_length;
+
+/* **************************************************************** */
+/* */
+/* Callback Readline Functions */
+/* */
+/* **************************************************************** */
+
+/* Allow using readline in situations where a program may have multiple
+ things to handle at once, and dispatches them via select(). Call
+ rl_callback_handler_install() with the prompt and a function to call
+ whenever a complete line of input is ready. The user must then
+ call rl_callback_read_char() every time some input is available, and
+ rl_callback_read_char() will call the user's function with the complete
+ text read in at each end of line. The terminal is kept prepped and
+ signals handled all the time, except during calls to the user's function. */
+
+VFunction *rl_linefunc; /* user callback function */
+static int in_handler; /* terminal_prepped and signals set? */
+
+/* Make sure the terminal is set up, initialize readline, and prompt. */
+static void
+_rl_callback_newline ()
+{
+ rl_initialize ();
+
+ if (in_handler == 0)
+ {
+ in_handler = 1;
+
+ (*rl_prep_term_function) (_rl_meta_flag);
+
+#if defined (HANDLE_SIGNALS)
+ rl_set_signals ();
+#endif
+ }
+
+ readline_internal_setup ();
+}
+
+/* Install a readline handler, set up the terminal, and issue the prompt. */
+void
+rl_callback_handler_install (prompt, linefunc)
+ char *prompt;
+ VFunction *linefunc;
+{
+ rl_prompt = prompt;
+ rl_visible_prompt_length = rl_prompt ? rl_expand_prompt (rl_prompt) : 0;
+ rl_linefunc = linefunc;
+ _rl_callback_newline ();
+}
+
+/* Read one character, and dispatch to the handler if it ends the line. */
+void
+rl_callback_read_char ()
+{
+ char *line;
+ int eof;
+
+ if (rl_linefunc == NULL)
+ {
+ fprintf (stderr, "readline: readline_callback_read_char() called with no handler!\r\n");
+ abort ();
+ }
+
+ eof = readline_internal_char ();
+
+ if (rl_done)
+ {
+ line = readline_internal_teardown (eof);
+
+ (*rl_deprep_term_function) ();
+#if defined (HANDLE_SIGNALS)
+ rl_clear_signals ();
+#endif
+ in_handler = 0;
+ (*rl_linefunc) (line);
+
+ /* If the user did not clear out the line, do it for him. */
+ if (rl_line_buffer[0])
+ _rl_init_line_state ();
+
+ /* Redisplay the prompt if readline_handler_{install,remove} not called. */
+ if (in_handler == 0 && rl_linefunc)
+ _rl_callback_newline ();
+ }
+}
+
+/* Remove the handler, and make sure the terminal is in its normal state. */
+void
+rl_callback_handler_remove ()
+{
+ rl_linefunc = NULL;
+ if (in_handler)
+ {
+ in_handler = 0;
+ (*rl_deprep_term_function) ();
+#if defined (HANDLE_SIGNALS)
+ rl_clear_signals ();
+#endif
+ }
+}
+
+#endif
diff --git a/readline/chardefs.h b/readline/chardefs.h
new file mode 100644
index 00000000000..740f14b185b
--- /dev/null
+++ b/readline/chardefs.h
@@ -0,0 +1,142 @@
+/* chardefs.h -- Character definitions for readline. */
+
+/* Copyright (C) 1994 Free Software Foundation, Inc.
+
+ This file is part of the GNU Readline Library, a library for
+ reading lines of text with interactive input and history editing.
+
+ The GNU Readline Library is free software; you can redistribute it
+ and/or modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 1, or
+ (at your option) any later version.
+
+ The GNU Readline 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 General Public License for more details.
+
+ The GNU General Public License is often shipped with GNU software, and
+ is generally kept in a file called COPYING or LICENSE. If you do not
+ have a copy of the license, write to the Free Software Foundation,
+ 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef _CHARDEFS_H_
+#define _CHARDEFS_H_
+
+#ifndef _m_ctype_h
+#include <ctype.h>
+#endif
+
+#if defined (HAVE_CONFIG_H)
+# if defined (HAVE_STRING_H)
+# include <string.h>
+# else
+# include <strings.h>
+# endif /* HAVE_STRING_H */
+#else
+# include <string.h>
+#endif /* !HAVE_CONFIG_H */
+
+#ifndef whitespace
+#define whitespace(c) (((c) == ' ') || ((c) == '\t'))
+#endif
+
+#ifdef CTRL
+#undef CTRL
+#endif
+
+/* Some character stuff. */
+#define control_character_threshold 0x020 /* Smaller than this is control. */
+#define control_character_mask 0x1f /* 0x20 - 1 */
+#define meta_character_threshold 0x07f /* Larger than this is Meta. */
+#define control_character_bit 0x40 /* 0x000000, must be off. */
+#define meta_character_bit 0x080 /* x0000000, must be on. */
+#define largest_char 255 /* Largest character value. */
+
+#define CTRL_CHAR(c) ((c) < control_character_threshold && (c) >= 0)
+#define META_CHAR(c) ((c) > meta_character_threshold && (c) <= largest_char)
+
+#define CTRL(c) ((c) & control_character_mask)
+#define META(c) ((c) | meta_character_bit)
+
+#define UNMETA(c) ((c) & (~meta_character_bit))
+#define UNCTRL(c) _rl_to_upper(((c)|control_character_bit))
+
+/* Old versions
+#define _rl_lowercase_p(c) (((c) > ('a' - 1) && (c) < ('z' + 1)))
+#define _rl_uppercase_p(c) (((c) > ('A' - 1) && (c) < ('Z' + 1)))
+#define _rl_digit_p(c) ((c) >= '0' && (c) <= '9')
+*/
+
+#define _rl_lowercase_p(c) (islower(c))
+#define _rl_uppercase_p(c) (isupper(c))
+#define _rl_digit_p(x) (isdigit (x))
+
+#define _rl_pure_alphabetic(c) (_rl_lowercase_p(c) || _rl_uppercase_p(c))
+#define ALPHABETIC(c) (_rl_lowercase_p(c) || _rl_uppercase_p(c) || _rl_digit_p(c))
+
+/* Old versions
+# define _rl_to_upper(c) (_rl_lowercase_p(c) ? ((c) - 32) : (c))
+# define _rl_to_lower(c) (_rl_uppercase_p(c) ? ((c) + 32) : (c))
+*/
+
+#ifndef _rl_to_upper
+# define _rl_to_upper(c) (islower(c) ? toupper(c) : (c))
+# define _rl_to_lower(c) (isupper(c) ? tolower(c) : (c))
+#endif
+
+#ifndef _rl_digit_value
+#define _rl_digit_value(x) ((x) - '0')
+#endif
+
+#ifndef NEWLINE
+#define NEWLINE '\n'
+#endif
+
+#ifndef RETURN
+#define RETURN CTRL('M')
+#endif
+
+#ifndef RUBOUT
+#define RUBOUT 0x7f
+#endif
+
+#ifndef TAB
+#define TAB '\t'
+#endif
+
+#ifdef ABORT_CHAR
+#undef ABORT_CHAR
+#endif
+#define ABORT_CHAR CTRL('G')
+
+#ifdef PAGE
+#undef PAGE
+#endif
+#define PAGE CTRL('L')
+
+#ifdef SPACE
+#undef SPACE
+#endif
+#define SPACE ' ' /* XXX - was 0x20 */
+
+#ifdef ESC
+#undef ESC
+#endif
+#define ESC CTRL('[')
+
+#ifndef ISOCTAL
+#define ISOCTAL(c) ((c) >= '0' && (c) <= '7')
+#endif
+#define OCTVALUE(c) ((c) - '0')
+
+#ifndef isxdigit
+# define isxdigit(c) (isdigit((c)) || ((c) >= 'a' && (c) <= 'f') || ((c) >= 'A' && (c) <= 'F'))
+#endif
+
+#define HEXVALUE(c) \
+ (((c) >= 'a' && (c) <= 'f') \
+ ? (c)-'a'+10 \
+ : (c) >= 'A' && (c) <= 'F' ? (c)-'A'+10 : (c)-'0')
+
+#endif /* _CHARDEFS_H_ */
diff --git a/readline/complete.c b/readline/complete.c
new file mode 100644
index 00000000000..dfb1ce0375c
--- /dev/null
+++ b/readline/complete.c
@@ -0,0 +1,1755 @@
+/* complete.c -- filename completion for readline. */
+
+/* Copyright (C) 1987, 1989, 1992 Free Software Foundation, Inc.
+
+ This file is part of the GNU Readline Library, a library for
+ reading lines of text with interactive input and history editing.
+
+ The GNU Readline Library is free software; you can redistribute it
+ and/or modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 1, or
+ (at your option) any later version.
+
+ The GNU Readline 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 General Public License for more details.
+
+ The GNU General Public License is often shipped with GNU software, and
+ is generally kept in a file called COPYING or LICENSE. If you do not
+ have a copy of the license, write to the Free Software Foundation,
+ 675 Mass Ave, Cambridge, MA 02139, USA. */
+#define READLINE_LIBRARY
+
+#if defined (HAVE_CONFIG_H)
+# include <config.h>
+#endif
+
+#include <sys/types.h>
+#include <fcntl.h>
+#if defined (HAVE_SYS_FILE_H)
+#include <sys/file.h>
+#endif
+
+#if defined (HAVE_UNISTD_H)
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+
+#if defined (HAVE_STDLIB_H)
+# include <stdlib.h>
+#else
+# include "ansi_stdlib.h"
+#endif /* HAVE_STDLIB_H */
+
+#include <stdio.h>
+
+#include <errno.h>
+#if !defined (errno)
+extern int errno;
+#endif /* !errno */
+
+#include <pwd.h>
+#if !defined (HAVE_GETPW_DECLS)
+extern struct passwd *getpwent ();
+#endif /* USG && !HAVE_GETPW_DECLS */
+
+/* ISC systems don't define getpwent() if _POSIX_SOURCE is defined. */
+#if defined (isc386) && defined (_POSIX_SOURCE)
+# if defined (__STDC__)
+extern struct passwd *getpwent (void);
+# else
+extern struct passwd *getpwent ();
+# endif /* !__STDC__ */
+#endif /* isc386 && _POSIX_SOURCE */
+
+#include "posixdir.h"
+#include "posixstat.h"
+
+/* System-specific feature definitions and include files. */
+#include "rldefs.h"
+
+/* Some standard library routines. */
+#include "readline.h"
+
+extern char *tilde_expand ();
+extern char *rl_copy_text ();
+extern void _rl_abort_internal ();
+extern int _rl_qsort_string_compare ();
+extern void _rl_replace_text ();
+
+extern Function *rl_last_func;
+extern int rl_editing_mode;
+extern int screenwidth;
+
+extern void _rl_move_vert ();
+extern int _rl_vis_botlin;
+extern int rl_display_fixed;
+
+/* If non-zero, then this is the address of a function to call when
+ completing a word would normally display the list of possible matches.
+ This function is called instead of actually doing the display.
+ It takes three arguments: (char **matches, int num_matches, int max_length)
+ where MATCHES is the array of strings that matched, NUM_MATCHES is the
+ number of strings in that array, and MAX_LENGTH is the length of the
+ longest string in that array. */
+VFunction *rl_completion_display_matches_hook = (VFunction *)NULL;
+
+/* Forward declarations for functions defined and used in this file. */
+char *filename_completion_function ();
+char **completion_matches ();
+
+#if defined (VISIBLE_STATS)
+# if !defined (X_OK)
+# define X_OK 1
+# endif
+static int stat_char ();
+#endif
+
+static char *rl_quote_filename ();
+static char *rl_strpbrk ();
+
+static char **remove_duplicate_matches ();
+static void insert_match ();
+static int append_to_match ();
+static void insert_all_matches ();
+static void display_matches ();
+static int compute_lcd_of_matches ();
+
+extern char *xmalloc (), *xrealloc ();
+
+/* **************************************************************** */
+/* */
+/* Completion matching, from readline's point of view. */
+/* */
+/* **************************************************************** */
+
+/* Variables known only to the readline library. */
+
+/* If non-zero, non-unique completions always show the list of matches. */
+int _rl_complete_show_all = 0;
+
+/* If non-zero, completed directory names have a slash appended. */
+int _rl_complete_mark_directories = 1;
+
+/* If non-zero, completions are printed horizontally in alphabetical order,
+ like `ls -x'. */
+int _rl_print_completions_horizontally;
+
+/* Non-zero means that case is not significant in filename completion. */
+int _rl_completion_case_fold;
+
+/* Global variables available to applications using readline. */
+
+#if defined (VISIBLE_STATS)
+/* Non-zero means add an additional character to each filename displayed
+ during listing completion iff rl_filename_completion_desired which helps
+ to indicate the type of file being listed. */
+int rl_visible_stats = 0;
+#endif /* VISIBLE_STATS */
+
+/* If non-zero, then this is the address of a function to call when
+ completing on a directory name. The function is called with
+ the address of a string (the current directory name) as an arg. */
+Function *rl_directory_completion_hook = (Function *)NULL;
+
+/* Non-zero means readline completion functions perform tilde expansion. */
+int rl_complete_with_tilde_expansion = 0;
+
+/* Pointer to the generator function for completion_matches ().
+ NULL means to use filename_completion_function (), the default filename
+ completer. */
+Function *rl_completion_entry_function = (Function *)NULL;
+
+/* Pointer to alternative function to create matches.
+ Function is called with TEXT, START, and END.
+ START and END are indices in RL_LINE_BUFFER saying what the boundaries
+ of TEXT are.
+ If this function exists and returns NULL then call the value of
+ rl_completion_entry_function to try to match, otherwise use the
+ array of strings returned. */
+CPPFunction *rl_attempted_completion_function = (CPPFunction *)NULL;
+
+/* Non-zero means to suppress normal filename completion after the
+ user-specified completion function has been called. */
+int rl_attempted_completion_over = 0;
+
+/* Set to a character indicating the type of completion being performed
+ by rl_complete_internal, available for use by application completion
+ functions. */
+int rl_completion_type = 0;
+
+/* Up to this many items will be displayed in response to a
+ possible-completions call. After that, we ask the user if
+ she is sure she wants to see them all. */
+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\"\\'`@$><=;|&{(";
+
+/* List of basic quoting characters. */
+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;
+
+/* List of characters which can be used to quote a substring of the line.
+ Completion occurs on the entire substring, and within the substring
+ rl_completer_word_break_characters are treated as any other character,
+ unless they also appear within this list. */
+char *rl_completer_quote_characters = (char *)NULL;
+
+/* List of characters that should be quoted in filenames by the completer. */
+char *rl_filename_quote_characters = (char *)NULL;
+
+/* List of characters that are word break characters, but should be left
+ in TEXT when it is passed to the completion function. The shell uses
+ this to help determine what kind of completing to do. */
+char *rl_special_prefixes = (char *)NULL;
+
+/* If non-zero, then disallow duplicates in the matches. */
+int rl_ignore_completion_duplicates = 1;
+
+/* Non-zero means that the results of the matches are to be treated
+ as filenames. This is ALWAYS zero on entry, and can only be changed
+ within a completion entry finder function. */
+int rl_filename_completion_desired = 0;
+
+/* Non-zero means that the results of the matches are to be quoted using
+ double quotes (or an application-specific quoting mechanism) if the
+ filename contains any characters in rl_filename_quote_chars. This is
+ ALWAYS non-zero on entry, and can only be changed within a completion
+ entry finder function. */
+int rl_filename_quoting_desired = 1;
+
+/* This function, if defined, is called by the completer when real
+ filename completion is done, after all the matching names have been
+ generated. It is passed a (char**) known as matches in the code below.
+ It consists of a NULL-terminated array of pointers to potential
+ matching strings. The 1st element (matches[0]) is the maximal
+ substring that is common to all matches. This function can re-arrange
+ the list of matches as required, but all elements of the array must be
+ free()'d if they are deleted. The main intent of this function is
+ to implement FIGNORE a la SunOS csh. */
+Function *rl_ignore_some_completions_function = (Function *)NULL;
+
+/* Set to a function to quote a filename in an application-specific fashion.
+ Called with the text to quote, the type of match found (single or multiple)
+ 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
+ with this; it's set only by applications. */
+CPFunction *rl_filename_dequoting_function = (CPFunction *)NULL;
+
+/* Function to call to decide whether or not a word break character is
+ quoted. If a character is quoted, it does not break words for the
+ completer. */
+Function *rl_char_is_quoted_p = (Function *)NULL;
+
+/* Character appended to completed words when at the end of the line. The
+ default is a space. */
+int rl_completion_append_character = ' ';
+
+/* If non-zero, inhibit completion (temporarily). */
+int rl_inhibit_completion;
+
+/* Variables local to this file. */
+
+/* Local variable states what happened during the last completion attempt. */
+static int completion_changed_buffer;
+
+/*************************************/
+/* */
+/* Bindable completion functions */
+/* */
+/*************************************/
+
+/* Complete the word at or before point. You have supplied the function
+ that does the initial simple matching selection algorithm (see
+ completion_matches ()). The default is to do filename completion. */
+int
+rl_complete (ignore, invoking_key)
+ int ignore, invoking_key;
+{
+ if (rl_inhibit_completion)
+ return (rl_insert (ignore, invoking_key));
+ else if (rl_last_func == rl_complete && !completion_changed_buffer)
+ return (rl_complete_internal ('?'));
+ else if (_rl_complete_show_all)
+ return (rl_complete_internal ('!'));
+ else
+ return (rl_complete_internal (TAB));
+}
+
+/* List the possible completions. See description of rl_complete (). */
+int
+rl_possible_completions (ignore, invoking_key)
+ int ignore, invoking_key;
+{
+ return (rl_complete_internal ('?'));
+}
+
+int
+rl_insert_completions (ignore, invoking_key)
+ int ignore, invoking_key;
+{
+ return (rl_complete_internal ('*'));
+}
+
+/************************************/
+/* */
+/* Completion utility functions */
+/* */
+/************************************/
+
+/* Find the first occurrence in STRING1 of any character from STRING2.
+ Return a pointer to the character in STRING1. */
+static char *
+rl_strpbrk (string1, string2)
+ char *string1, *string2;
+{
+ register char *scan;
+
+ for (; *string1; string1++)
+ {
+ for (scan = string2; *scan; scan++)
+ {
+ if (*string1 == *scan)
+ {
+ return (string1);
+ }
+ }
+ }
+ return ((char *)NULL);
+}
+
+/* The user must press "y" or "n". Non-zero return means "y" pressed. */
+static int
+get_y_or_n ()
+{
+ int c;
+
+ for (;;)
+ {
+ c = rl_read_key ();
+ if (c == 'y' || c == 'Y' || c == ' ')
+ return (1);
+ if (c == 'n' || c == 'N' || c == RUBOUT)
+ return (0);
+ if (c == ABORT_CHAR)
+ _rl_abort_internal ();
+ ding ();
+ }
+}
+
+#if defined (VISIBLE_STATS)
+/* Return the character which best describes FILENAME.
+ `@' for symbolic links
+ `/' for directories
+ `*' for executables
+ `=' for sockets
+ `|' for FIFOs
+ `%' for character special devices
+ `#' for block special devices */
+static int
+stat_char (filename)
+ char *filename;
+{
+ struct stat finfo;
+ int character, r;
+
+#if defined (HAVE_LSTAT) && defined (S_ISLNK)
+ r = lstat (filename, &finfo);
+#else
+ r = stat (filename, &finfo);
+#endif
+
+ if (r == -1)
+ return (0);
+
+ character = 0;
+ if (S_ISDIR (finfo.st_mode))
+ character = '/';
+#if defined (S_ISCHR)
+ else if (S_ISCHR (finfo.st_mode))
+ character = '%';
+#endif /* S_ISCHR */
+#if defined (S_ISBLK)
+ else if (S_ISBLK (finfo.st_mode))
+ character = '#';
+#endif /* S_ISBLK */
+#if defined (S_ISLNK)
+ else if (S_ISLNK (finfo.st_mode))
+ character = '@';
+#endif /* S_ISLNK */
+#if defined (S_ISSOCK)
+ else if (S_ISSOCK (finfo.st_mode))
+ character = '=';
+#endif /* S_ISSOCK */
+#if defined (S_ISFIFO)
+ else if (S_ISFIFO (finfo.st_mode))
+ character = '|';
+#endif
+ else if (S_ISREG (finfo.st_mode))
+ {
+ if (access (filename, X_OK) == 0)
+ character = '*';
+ }
+ return (character);
+}
+#endif /* VISIBLE_STATS */
+
+/* Return the portion of PATHNAME that should be output when listing
+ possible completions. If we are hacking filename completion, we
+ are only interested in the basename, the portion following the
+ final slash. Otherwise, we return what we were passed. */
+static char *
+printable_part (pathname)
+ char *pathname;
+{
+ char *temp;
+
+ temp = rl_filename_completion_desired ? strrchr (pathname, '/') : (char *)NULL;
+ return (temp ? ++temp : pathname);
+}
+
+/* Output TO_PRINT to rl_outstream. If VISIBLE_STATS is defined and we
+ are using it, check for and output a single character for `special'
+ filenames. Return the number of characters we output. */
+
+#define PUTX(c) \
+ do { \
+ if (CTRL_CHAR (c)) \
+ { \
+ putc ('^', rl_outstream); \
+ putc (UNCTRL (c), rl_outstream); \
+ printed_len += 2; \
+ } \
+ else if (c == RUBOUT) \
+ { \
+ putc ('^', rl_outstream); \
+ putc ('?', rl_outstream); \
+ printed_len += 2; \
+ } \
+ else \
+ { \
+ putc (c, rl_outstream); \
+ printed_len++; \
+ } \
+ } while (0)
+
+static int
+print_filename (to_print, full_pathname)
+ char *to_print, *full_pathname;
+{
+ int printed_len = 0;
+#if !defined (VISIBLE_STATS)
+ char *s;
+
+ for (s = to_print; *s; s++)
+ {
+ PUTX (*s);
+ }
+#else
+ char *s, c, *new_full_pathname;
+ int extension_char, slen, tlen;
+
+ for (s = to_print; *s; s++)
+ {
+ PUTX (*s);
+ }
+
+ if (rl_filename_completion_desired && rl_visible_stats)
+ {
+ /* If to_print != full_pathname, to_print is the basename of the
+ path passed. In this case, we try to expand the directory
+ name before checking for the stat character. */
+ if (to_print != full_pathname)
+ {
+ /* Terminate the directory name. */
+ c = to_print[-1];
+ to_print[-1] = '\0';
+
+ s = tilde_expand (full_pathname);
+ if (rl_directory_completion_hook)
+ (*rl_directory_completion_hook) (&s);
+
+ slen = strlen (s);
+ tlen = strlen (to_print);
+ new_full_pathname = xmalloc (slen + tlen + 2);
+ strcpy (new_full_pathname, s);
+ new_full_pathname[slen] = '/';
+ strcpy (new_full_pathname + slen + 1, to_print);
+
+ extension_char = stat_char (new_full_pathname);
+
+ free (new_full_pathname);
+ to_print[-1] = c;
+ }
+ else
+ {
+ s = tilde_expand (full_pathname);
+ extension_char = stat_char (s);
+ }
+
+ free (s);
+ if (extension_char)
+ {
+ putc (extension_char, rl_outstream);
+ printed_len++;
+ }
+ }
+#endif /* VISIBLE_STATS */
+ return printed_len;
+}
+
+static char *
+rl_quote_filename (s, rtype, qcp)
+ char *s;
+ int rtype;
+ char *qcp;
+{
+ char *r;
+
+ r = xmalloc (strlen (s) + 2);
+ *r = *rl_completer_quote_characters;
+ strcpy (r + 1, s);
+ if (qcp)
+ *qcp = *rl_completer_quote_characters;
+ return r;
+}
+
+/* Find the bounds of the current word for completion purposes, and leave
+ rl_point set to the end of the word. This function skips quoted
+ substrings (characters between matched pairs of characters in
+ rl_completer_quote_characters. First we try to find an unclosed
+ quoted substring on which to do matching. If one is not found, we use
+ the word break characters to find the boundaries of the current word.
+ We call an application-specific function to decide whether or not a
+ particular word break character is quoted; if that function returns a
+ non-zero result, the character does not break a word. This function
+ returns the opening quote character if we found an unclosed quoted
+ substring, '\0' otherwise. FP, if non-null, is set to a value saying
+ which (shell-like) quote characters we found (single quote, double
+ quote, or backslash) anywhere in the string. DP, if non-null, is set to
+ the value of the delimiter character that caused a word break. */
+
+static char
+find_completion_word (fp, dp)
+ int *fp, *dp;
+{
+ int scan, end, found_quote, delimiter, pass_next, isbrk;
+ char quote_char;
+
+ end = rl_point;
+ found_quote = delimiter = 0;
+ quote_char = '\0';
+
+ if (rl_completer_quote_characters)
+ {
+ /* We have a list of characters which can be used in pairs to
+ quote substrings for the completer. Try to find the start
+ of an unclosed quoted substring. */
+ /* FOUND_QUOTE is set so we know what kind of quotes we found. */
+ for (scan = pass_next = 0; scan < end; scan++)
+ {
+ if (pass_next)
+ {
+ pass_next = 0;
+ continue;
+ }
+
+ if (rl_line_buffer[scan] == '\\')
+ {
+ pass_next = 1;
+ found_quote |= RL_QF_BACKSLASH;
+ continue;
+ }
+
+ if (quote_char != '\0')
+ {
+ /* Ignore everything until the matching close quote char. */
+ if (rl_line_buffer[scan] == quote_char)
+ {
+ /* Found matching close. Abandon this substring. */
+ quote_char = '\0';
+ rl_point = end;
+ }
+ }
+ else if (strchr (rl_completer_quote_characters, rl_line_buffer[scan]))
+ {
+ /* Found start of a quoted substring. */
+ quote_char = rl_line_buffer[scan];
+ rl_point = scan + 1;
+ /* Shell-like quoting conventions. */
+ if (quote_char == '\'')
+ found_quote |= RL_QF_SINGLE_QUOTE;
+ else if (quote_char == '"')
+ found_quote |= RL_QF_DOUBLE_QUOTE;
+ }
+ }
+ }
+
+ if (rl_point == end && quote_char == '\0')
+ {
+ /* We didn't find an unclosed quoted substring upon which to do
+ completion, so use the word break characters to find the
+ substring on which to complete. */
+ while (--rl_point)
+ {
+ scan = rl_line_buffer[rl_point];
+
+ if (strchr (rl_completer_word_break_characters, scan) == 0)
+ continue;
+
+ /* Call the application-specific function to tell us whether
+ this word break character is quoted and should be skipped. */
+ if (rl_char_is_quoted_p && found_quote &&
+ (*rl_char_is_quoted_p) (rl_line_buffer, rl_point))
+ continue;
+
+ /* Convoluted code, but it avoids an n^2 algorithm with calls
+ to char_is_quoted. */
+ break;
+ }
+ }
+
+ /* If we are at an unquoted word break, then advance past it. */
+ scan = rl_line_buffer[rl_point];
+
+ /* If there is an application-specific function to say whether or not
+ a character is quoted and we found a quote character, let that
+ function decide whether or not a character is a word break, even
+ if it is found in rl_completer_word_break_characters. */
+ if (rl_char_is_quoted_p)
+ isbrk = (found_quote == 0 ||
+ (*rl_char_is_quoted_p) (rl_line_buffer, rl_point) == 0) &&
+ strchr (rl_completer_word_break_characters, scan) != 0;
+ else
+ isbrk = strchr (rl_completer_word_break_characters, scan) != 0;
+
+ if (isbrk)
+ {
+ /* If the character that caused the word break was a quoting
+ character, then remember it as the delimiter. */
+ if (rl_basic_quote_characters && strchr (rl_basic_quote_characters, scan) && (end - rl_point) > 1)
+ delimiter = scan;
+
+ /* If the character isn't needed to determine something special
+ about what kind of completion to perform, then advance past it. */
+ if (rl_special_prefixes == 0 || strchr (rl_special_prefixes, scan) == 0)
+ rl_point++;
+ }
+
+ if (fp)
+ *fp = found_quote;
+ if (dp)
+ *dp = delimiter;
+
+ return (quote_char);
+}
+
+static char **
+gen_completion_matches (text, start, end, our_func, found_quote, quote_char)
+ char *text;
+ int start, end;
+ Function *our_func;
+ int found_quote, quote_char;
+{
+ char **matches, *temp;
+
+ /* If the user wants to TRY to complete, but then wants to give
+ up and use the default completion function, they set the
+ variable rl_attempted_completion_function. */
+ if (rl_attempted_completion_function)
+ {
+ matches = (*rl_attempted_completion_function) (text, start, end);
+
+ if (matches || rl_attempted_completion_over)
+ {
+ rl_attempted_completion_over = 0;
+ return (matches);
+ }
+ }
+
+ /* Beware -- we're stripping the quotes here. Do this only if we know
+ we are doing filename completion and the application has defined a
+ filename dequoting function. */
+ temp = (char *)NULL;
+
+ if (found_quote && our_func == (Function *)filename_completion_function &&
+ rl_filename_dequoting_function)
+ {
+ /* delete single and double quotes */
+ temp = (*rl_filename_dequoting_function) (text, quote_char);
+ text = temp; /* not freeing text is not a memory leak */
+ }
+
+ matches = completion_matches (text, (CPFunction *)our_func);
+ FREE (temp);
+ return matches;
+}
+
+/* Filter out duplicates in MATCHES. This frees up the strings in
+ MATCHES. */
+static char **
+remove_duplicate_matches (matches)
+ char **matches;
+{
+ char *lowest_common;
+ int i, j, newlen;
+ char dead_slot;
+ char **temp_array;
+
+ /* Sort the items. */
+ for (i = 0; matches[i]; i++)
+ ;
+
+ /* Sort the array without matches[0], since we need it to
+ stay in place no matter what. */
+ if (i)
+ qsort (matches+1, i-1, sizeof (char *), _rl_qsort_string_compare);
+
+ /* Remember the lowest common denominator for it may be unique. */
+ lowest_common = savestring (matches[0]);
+
+ for (i = newlen = 0; matches[i + 1]; i++)
+ {
+ if (strcmp (matches[i], matches[i + 1]) == 0)
+ {
+ free (matches[i]);
+ matches[i] = (char *)&dead_slot;
+ }
+ else
+ newlen++;
+ }
+
+ /* We have marked all the dead slots with (char *)&dead_slot.
+ Copy all the non-dead entries into a new array. */
+ temp_array = (char **)xmalloc ((3 + newlen) * sizeof (char *));
+ for (i = j = 1; matches[i]; i++)
+ {
+ if (matches[i] != (char *)&dead_slot)
+ temp_array[j++] = matches[i];
+ }
+ temp_array[j] = (char *)NULL;
+
+ if (matches[0] != (char *)&dead_slot)
+ free (matches[0]);
+
+ /* Place the lowest common denominator back in [0]. */
+ temp_array[0] = lowest_common;
+
+ /* If there is one string left, and it is identical to the
+ lowest common denominator, then the LCD is the string to
+ insert. */
+ if (j == 2 && strcmp (temp_array[0], temp_array[1]) == 0)
+ {
+ free (temp_array[1]);
+ temp_array[1] = (char *)NULL;
+ }
+ return (temp_array);
+}
+
+/* Find the common prefix of the list of matches, and put it into
+ matches[0]. */
+static int
+compute_lcd_of_matches (match_list, matches, text)
+ char **match_list;
+ int matches;
+ char *text;
+{
+ register int i, c1, c2, si;
+ int low; /* Count of max-matched characters. */
+
+ /* If only one match, just use that. Otherwise, compare each
+ member of the list with the next, finding out where they
+ stop matching. */
+ if (matches == 1)
+ {
+ match_list[0] = match_list[1];
+ match_list[1] = (char *)NULL;
+ return 1;
+ }
+
+ for (i = 1, low = 100000; i < matches; i++)
+ {
+ if (_rl_completion_case_fold)
+ {
+ for (si = 0;
+ (c1 = _rl_to_lower(match_list[i][si])) &&
+ (c2 = _rl_to_lower(match_list[i + 1][si]));
+ si++)
+ if (c1 != c2)
+ break;
+ }
+ else
+ {
+ for (si = 0;
+ (c1 = match_list[i][si]) &&
+ (c2 = match_list[i + 1][si]);
+ si++)
+ if (c1 != c2)
+ break;
+ }
+
+ if (low > si)
+ low = si;
+ }
+
+ /* If there were multiple matches, but none matched up to even the
+ first character, and the user typed something, use that as the
+ value of matches[0]. */
+ if (low == 0 && text && *text)
+ {
+ match_list[0] = xmalloc (strlen (text) + 1);
+ strcpy (match_list[0], text);
+ }
+ else
+ {
+ match_list[0] = xmalloc (low + 1);
+ strncpy (match_list[0], match_list[1], low);
+ match_list[0][low] = '\0';
+ }
+
+ return matches;
+}
+
+static int
+postprocess_matches (matchesp, matching_filenames)
+ char ***matchesp;
+ int matching_filenames;
+{
+ char *t, **matches, **temp_matches;
+ int nmatch, i;
+
+ matches = *matchesp;
+
+ /* It seems to me that in all the cases we handle we would like
+ to ignore duplicate possiblilities. Scan for the text to
+ insert being identical to the other completions. */
+ if (rl_ignore_completion_duplicates)
+ {
+ temp_matches = remove_duplicate_matches (matches);
+ free (matches);
+ matches = temp_matches;
+ }
+
+ /* If we are matching filenames, then here is our chance to
+ do clever processing by re-examining the list. Call the
+ ignore function with the array as a parameter. It can
+ munge the array, deleting matches as it desires. */
+ if (rl_ignore_some_completions_function && matching_filenames)
+ {
+ for (nmatch = 1; matches[nmatch]; nmatch++)
+ ;
+ (void)(*rl_ignore_some_completions_function) (matches);
+ if (matches == 0 || matches[0] == 0)
+ {
+ FREE (matches);
+ *matchesp = (char **)0;
+ return 0;
+ }
+ else
+ {
+ /* If we removed some matches, recompute the common prefix. */
+ for (i = 1; matches[i]; i++)
+ ;
+ if (i > 1 && i < nmatch)
+ {
+ t = matches[0];
+ compute_lcd_of_matches (matches, i - 1, t);
+ FREE (t);
+ }
+ }
+ }
+
+ *matchesp = matches;
+ return (1);
+}
+
+/* A convenience function for displaying a list of strings in
+ columnar format on readline's output stream. MATCHES is the list
+ of strings, in argv format, LEN is the number of strings in MATCHES,
+ and MAX is the length of the longest string in MATCHES. */
+void
+rl_display_match_list (matches, len, max)
+ char **matches;
+ int len, max;
+{
+ int count, limit, printed_len;
+ int i, j, k, l;
+ char *temp;
+
+ /* How many items of MAX length can we fit in the screen window? */
+ max += 2;
+ limit = screenwidth / max;
+ if (limit != 1 && (limit * max == screenwidth))
+ limit--;
+
+ /* Avoid a possible floating exception. If max > screenwidth,
+ limit will be 0 and a divide-by-zero fault will result. */
+ if (limit == 0)
+ limit = 1;
+
+ /* How many iterations of the printing loop? */
+ count = (len + (limit - 1)) / limit;
+
+ /* Watch out for special case. If LEN is less than LIMIT, then
+ just do the inner printing loop.
+ 0 < len <= limit implies count = 1. */
+
+ /* Sort the items if they are not already sorted. */
+ if (rl_ignore_completion_duplicates == 0)
+ qsort (matches + 1, len, sizeof (char *), _rl_qsort_string_compare);
+
+ crlf ();
+
+ if (_rl_print_completions_horizontally == 0)
+ {
+ /* Print the sorted items, up-and-down alphabetically, like ls. */
+ for (i = 1; i <= count; i++)
+ {
+ for (j = 0, l = i; j < limit; j++)
+ {
+ if (l > len || matches[l] == 0)
+ break;
+ else
+ {
+ temp = printable_part (matches[l]);
+ printed_len = print_filename (temp, matches[l]);
+
+ if (j + 1 < limit)
+ for (k = 0; k < max - printed_len; k++)
+ putc (' ', rl_outstream);
+ }
+ l += count;
+ }
+ crlf ();
+ }
+ }
+ else
+ {
+ /* Print the sorted items, across alphabetically, like ls -x. */
+ for (i = 1; matches[i]; i++)
+ {
+ temp = printable_part (matches[i]);
+ printed_len = print_filename (temp, matches[i]);
+ /* Have we reached the end of this line? */
+ if (matches[i+1])
+ {
+ if (i && (limit > 1) && (i % limit) == 0)
+ crlf ();
+ else
+ for (k = 0; k < max - printed_len; k++)
+ putc (' ', rl_outstream);
+ }
+ }
+ crlf ();
+ }
+}
+
+/* Display MATCHES, a list of matching filenames in argv format. This
+ handles the simple case -- a single match -- first. If there is more
+ than one match, we compute the number of strings in the list and the
+ length of the longest string, which will be needed by the display
+ function. If the application wants to handle displaying the list of
+ matches itself, it sets RL_COMPLETION_DISPLAY_MATCHES_HOOK to the
+ address of a function, and we just call it. If we're handling the
+ display ourselves, we just call rl_display_match_list. We also check
+ that the list of matches doesn't exceed the user-settable threshold,
+ and ask the user if he wants to see the list if there are more matches
+ than RL_COMPLETION_QUERY_ITEMS. */
+static void
+display_matches (matches)
+ char **matches;
+{
+ int len, max, i;
+ char *temp;
+
+ /* Move to the last visible line of a possibly-multiple-line command. */
+ _rl_move_vert (_rl_vis_botlin);
+
+ /* Handle simple case first. What if there is only one answer? */
+ if (matches[1] == 0)
+ {
+ temp = printable_part (matches[0]);
+ crlf ();
+ print_filename (temp, matches[0]);
+ crlf ();
+
+ rl_forced_update_display ();
+ rl_display_fixed = 1;
+
+ return;
+ }
+
+ /* There is more than one answer. Find out how many there are,
+ and find the maximum printed length of a single entry. */
+ for (max = 0, i = 1; matches[i]; i++)
+ {
+ temp = printable_part (matches[i]);
+ len = strlen (temp);
+
+ if (len > max)
+ max = len;
+ }
+
+ len = i - 1;
+
+ /* If the caller has defined a display hook, then call that now. */
+ if (rl_completion_display_matches_hook)
+ {
+ (*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)
+ {
+ crlf ();
+ fprintf (rl_outstream, "Display all %d possibilities? (y or n)", len);
+ fflush (rl_outstream);
+ if (get_y_or_n () == 0)
+ {
+ crlf ();
+
+ rl_forced_update_display ();
+ rl_display_fixed = 1;
+
+ return;
+ }
+ }
+
+ rl_display_match_list (matches, len, max);
+
+ rl_forced_update_display ();
+ rl_display_fixed = 1;
+}
+
+static char *
+make_quoted_replacement (match, mtype, qc)
+ char *match;
+ int mtype;
+ char *qc; /* Pointer to quoting character, if any */
+{
+ int should_quote, do_replace;
+ char *replacement;
+
+ /* If we are doing completion on quoted substrings, and any matches
+ contain any of the completer_word_break_characters, then auto-
+ matically prepend the substring with a quote character (just pick
+ the first one from the list of such) if it does not already begin
+ with a quote string. FIXME: Need to remove any such automatically
+ inserted quote character when it no longer is necessary, such as
+ if we change the string we are completing on and the new set of
+ matches don't require a quoted substring. */
+ replacement = match;
+
+ should_quote = match && rl_completer_quote_characters &&
+ rl_filename_completion_desired &&
+ rl_filename_quoting_desired;
+
+ if (should_quote)
+ should_quote = should_quote && (!qc || !*qc ||
+ (rl_completer_quote_characters && strchr (rl_completer_quote_characters, *qc)));
+
+ if (should_quote)
+ {
+ /* If there is a single match, see if we need to quote it.
+ This also checks whether the common prefix of several
+ matches needs to be quoted. */
+ should_quote = rl_filename_quote_characters
+ ? (rl_strpbrk (match, rl_filename_quote_characters) != 0)
+ : 0;
+
+ do_replace = should_quote ? mtype : NO_MATCH;
+ /* Quote the replacement, since we found an embedded
+ word break character in a potential match. */
+ if (do_replace != NO_MATCH && rl_filename_quoting_function)
+ replacement = (*rl_filename_quoting_function) (match, do_replace, qc);
+ }
+ return (replacement);
+}
+
+static void
+insert_match (match, start, mtype, qc)
+ char *match;
+ int start, mtype;
+ char *qc;
+{
+ char *replacement;
+ char oqc;
+
+ oqc = qc ? *qc : '\0';
+ replacement = make_quoted_replacement (match, mtype, qc);
+
+ /* Now insert the match. */
+ if (replacement)
+ {
+ /* Don't double an opening quote character. */
+ if (qc && *qc && start && rl_line_buffer[start - 1] == *qc &&
+ replacement[0] == *qc)
+ start--;
+ /* If make_quoted_replacement changed the quoting character, remove
+ the opening quote and insert the (fully-quoted) replacement. */
+ else if (qc && (*qc != oqc) && start && rl_line_buffer[start - 1] == oqc &&
+ replacement[0] != oqc)
+ start--;
+ _rl_replace_text (replacement, start, rl_point - 1);
+ if (replacement != match)
+ free (replacement);
+ }
+}
+
+/* Append any necessary closing quote and a separator character to the
+ just-inserted match. If the user has specified that directories
+ should be marked by a trailing `/', append one of those instead. The
+ default trailing character is a space. Returns the number of characters
+ appended. */
+static int
+append_to_match (text, delimiter, quote_char)
+ char *text;
+ int delimiter, quote_char;
+{
+ char temp_string[4], *filename;
+ int temp_string_index;
+ struct stat finfo;
+
+ temp_string_index = 0;
+ if (quote_char && rl_point && rl_line_buffer[rl_point - 1] != quote_char)
+ temp_string[temp_string_index++] = quote_char;
+
+ if (delimiter)
+ temp_string[temp_string_index++] = delimiter;
+ else if (rl_completion_append_character)
+ temp_string[temp_string_index++] = rl_completion_append_character;
+
+ temp_string[temp_string_index++] = '\0';
+
+ if (rl_filename_completion_desired)
+ {
+ filename = tilde_expand (text);
+ if (stat (filename, &finfo) == 0 && S_ISDIR (finfo.st_mode))
+ {
+ if (_rl_complete_mark_directories && rl_line_buffer[rl_point] != '/')
+ rl_insert_text ("/");
+ }
+ else
+ {
+ if (rl_point == rl_end)
+ rl_insert_text (temp_string);
+ }
+ free (filename);
+ }
+ else
+ {
+ if (rl_point == rl_end)
+ rl_insert_text (temp_string);
+ }
+
+ return (temp_string_index);
+}
+
+static void
+insert_all_matches (matches, point, qc)
+ char **matches;
+ int point;
+ char *qc;
+{
+ int i;
+ char *rp;
+
+ rl_begin_undo_group ();
+ /* remove any opening quote character; make_quoted_replacement will add
+ it back. */
+ if (qc && *qc && point && rl_line_buffer[point - 1] == *qc)
+ point--;
+ rl_delete_text (point, rl_point);
+ rl_point = point;
+
+ if (matches[1])
+ {
+ for (i = 1; matches[i]; i++)
+ {
+ rp = make_quoted_replacement (matches[i], SINGLE_MATCH, qc);
+ rl_insert_text (rp);
+ rl_insert_text (" ");
+ if (rp != matches[i])
+ free (rp);
+ }
+ }
+ else
+ {
+ rp = make_quoted_replacement (matches[0], SINGLE_MATCH, qc);
+ rl_insert_text (rp);
+ rl_insert_text (" ");
+ if (rp != matches[0])
+ free (rp);
+ }
+ rl_end_undo_group ();
+}
+
+static void
+free_match_list (matches)
+ char **matches;
+{
+ register int i;
+
+ for (i = 0; matches[i]; i++)
+ free (matches[i]);
+ free (matches);
+}
+
+/* Complete the word at or before point.
+ WHAT_TO_DO says what to do with the completion.
+ `?' means list the possible completions.
+ TAB means do standard completion.
+ `*' means insert all of the possible completions.
+ `!' means to do standard completion, and list all possible completions if
+ there is more than one. */
+int
+rl_complete_internal (what_to_do)
+ int what_to_do;
+{
+ char **matches;
+ Function *our_func;
+ int start, end, delimiter, found_quote, i;
+ char *text, *saved_line_buffer;
+ char quote_char;
+
+ /* Only the completion entry function can change these. */
+ rl_filename_completion_desired = 0;
+ rl_filename_quoting_desired = 1;
+ rl_completion_type = what_to_do;
+
+ saved_line_buffer = rl_line_buffer ? savestring (rl_line_buffer) : (char *)NULL;
+ our_func = rl_completion_entry_function
+ ? rl_completion_entry_function
+ : (Function *)filename_completion_function;
+
+ /* We now look backwards for the start of a filename/variable word. */
+ end = rl_point;
+ found_quote = delimiter = 0;
+ quote_char = '\0';
+
+ if (rl_point)
+ /* This (possibly) changes rl_point. If it returns a non-zero char,
+ we know we have an open quote. */
+ quote_char = find_completion_word (&found_quote, &delimiter);
+
+ start = rl_point;
+ rl_point = end;
+
+ text = rl_copy_text (start, end);
+ matches = gen_completion_matches (text, start, end, our_func, found_quote, quote_char);
+ free (text);
+
+ if (matches == 0)
+ {
+ ding ();
+ FREE (saved_line_buffer);
+ return (0);
+ }
+
+#if 0
+ /* If we are matching filenames, our_func will have been set to
+ filename_completion_function */
+ i = our_func == (Function *)filename_completion_function;
+#else
+ /* If we are matching filenames, the attempted completion function will
+ have set rl_filename_completion_desired to a non-zero value. The basic
+ filename_completion_function does this. */
+ i = rl_filename_completion_desired;
+#endif
+
+ if (postprocess_matches (&matches, i) == 0)
+ {
+ ding ();
+ FREE (saved_line_buffer);
+ completion_changed_buffer = 0;
+ return (0);
+ }
+
+ switch (what_to_do)
+ {
+ case TAB:
+ case '!':
+ /* Insert the first match with proper quoting. */
+ if (*matches[0])
+ insert_match (matches[0], start, matches[1] ? MULT_MATCH : SINGLE_MATCH, &quote_char);
+
+ /* If there are more matches, ring the bell to indicate.
+ If we are in vi mode, Posix.2 says to not ring the bell.
+ If the `show-all-if-ambiguous' variable is set, display
+ all the matches immediately. Otherwise, if this was the
+ only match, and we are hacking files, check the file to
+ see if it was a directory. If so, and the `mark-directories'
+ variable is set, add a '/' to the name. If not, and we
+ are at the end of the line, then add a space. */
+ if (matches[1])
+ {
+ if (what_to_do == '!')
+ {
+ display_matches (matches);
+ break;
+ }
+ else if (rl_editing_mode != vi_mode)
+ ding (); /* There are other matches remaining. */
+ }
+ else
+ append_to_match (matches[0], delimiter, quote_char);
+
+ break;
+
+ case '*':
+ insert_all_matches (matches, start, &quote_char);
+ break;
+
+ case '?':
+ display_matches (matches);
+ break;
+
+ default:
+ fprintf (stderr, "\r\nreadline: bad value %d for what_to_do in rl_complete\n", what_to_do);
+ ding ();
+ FREE (saved_line_buffer);
+ return 1;
+ }
+
+ free_match_list (matches);
+
+ /* Check to see if the line has changed through all of this manipulation. */
+ if (saved_line_buffer)
+ {
+ completion_changed_buffer = strcmp (rl_line_buffer, saved_line_buffer) != 0;
+ free (saved_line_buffer);
+ }
+
+ return 0;
+}
+
+/***************************************************************/
+/* */
+/* Application-callable completion match generator functions */
+/* */
+/***************************************************************/
+
+/* Return an array of (char *) which is a list of completions for TEXT.
+ If there are no completions, return a NULL pointer.
+ The first entry in the returned array is the substitution for TEXT.
+ The remaining entries are the possible completions.
+ The array is terminated with a NULL pointer.
+
+ ENTRY_FUNCTION is a function of two args, and returns a (char *).
+ The first argument is TEXT.
+ The second is a state argument; it should be zero on the first call, and
+ non-zero on subsequent calls. It returns a NULL pointer to the caller
+ when there are no more matches.
+ */
+char **
+completion_matches (text, entry_function)
+ char *text;
+ CPFunction *entry_function;
+{
+ /* Number of slots in match_list. */
+ int match_list_size;
+
+ /* The list of matches. */
+ char **match_list;
+
+ /* Number of matches actually found. */
+ int matches;
+
+ /* Temporary string binder. */
+ char *string;
+
+ matches = 0;
+ match_list_size = 10;
+ match_list = (char **)xmalloc ((match_list_size + 1) * sizeof (char *));
+ match_list[1] = (char *)NULL;
+
+ while (string = (*entry_function) (text, matches))
+ {
+ if (matches + 1 == match_list_size)
+ match_list = (char **)xrealloc
+ (match_list, ((match_list_size += 10) + 1) * sizeof (char *));
+
+ match_list[++matches] = string;
+ match_list[matches + 1] = (char *)NULL;
+ }
+
+ /* If there were any matches, then look through them finding out the
+ lowest common denominator. That then becomes match_list[0]. */
+ if (matches)
+ compute_lcd_of_matches (match_list, matches, text);
+ else /* There were no matches. */
+ {
+ free (match_list);
+ match_list = (char **)NULL;
+ }
+ return (match_list);
+}
+
+/* A completion function for usernames.
+ TEXT contains a partial username preceded by a random
+ character (usually `~'). */
+char *
+username_completion_function (text, state)
+ char *text;
+ int state;
+{
+#if defined (__GO32__) || defined (__WIN__) || defined (__OPENNT)
+ return (char *)NULL;
+#else /* !__GO32__ */
+ static char *username = (char *)NULL;
+ static struct passwd *entry;
+ static int namelen, first_char, first_char_loc;
+ char *value;
+
+ if (state == 0)
+ {
+ FREE (username);
+
+ first_char = *text;
+ first_char_loc = first_char == '~';
+
+ username = savestring (&text[first_char_loc]);
+ namelen = strlen (username);
+ setpwent ();
+ }
+
+ while (entry = getpwent ())
+ {
+ /* Null usernames should result in all users as possible completions. */
+ if (namelen == 0 || (STREQN (username, entry->pw_name, namelen)))
+ break;
+ }
+
+ if (entry == 0)
+ {
+ endpwent ();
+ return ((char *)NULL);
+ }
+ else
+ {
+ value = xmalloc (2 + strlen (entry->pw_name));
+
+ *value = *text;
+
+ strcpy (value + first_char_loc, entry->pw_name);
+
+ if (first_char == '~')
+ rl_filename_completion_desired = 1;
+
+ return (value);
+ }
+#endif /* !__GO32__ */
+}
+
+/* Okay, now we write the entry_function for filename completion. In the
+ general case. Note that completion in the shell is a little different
+ 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;
+{
+ static DIR *directory = (DIR *)NULL;
+ static char *filename = (char *)NULL;
+ static char *dirname = (char *)NULL;
+ static char *users_dirname = (char *)NULL;
+ static int filename_len;
+ char *temp;
+ int dirlen;
+ struct dirent *entry;
+
+ /* If we don't have any state, then do some initialization. */
+ if (state == 0)
+ {
+ /* If we were interrupted before closing the directory or reading
+ all of its contents, close it. */
+ if (directory)
+ {
+ closedir (directory);
+ directory = (DIR *)NULL;
+ }
+ FREE (dirname);
+ FREE (filename);
+ FREE (users_dirname);
+
+ filename = savestring (text);
+ if (*text == 0)
+ text = ".";
+ dirname = savestring (text);
+
+ temp = strrchr (dirname, '/');
+
+ if (temp)
+ {
+ strcpy (filename, ++temp);
+ *temp = '\0';
+ }
+ else
+ {
+ dirname[0] = '.';
+ dirname[1] = '\0';
+ }
+
+ /* We aren't done yet. We also support the "~user" syntax. */
+
+ /* Save the version of the directory that the user typed. */
+ users_dirname = savestring (dirname);
+
+ if (*dirname == '~')
+ {
+ temp = tilde_expand (dirname);
+ free (dirname);
+ dirname = temp;
+ }
+
+ if (rl_directory_completion_hook && (*rl_directory_completion_hook) (&dirname))
+ {
+ free (users_dirname);
+ users_dirname = savestring (dirname);
+ }
+
+ directory = opendir (dirname);
+ filename_len = strlen (filename);
+
+ rl_filename_completion_desired = 1;
+ }
+
+ /* At this point we should entertain the possibility of hacking wildcarded
+ filenames, like /usr/man/man<WILD>/te<TAB>. If the directory name
+ contains globbing characters, then build an array of directories, and
+ then map over that list while completing. */
+ /* *** UNIMPLEMENTED *** */
+
+ /* Now that we have some state, we can read the directory. */
+
+ entry = (struct dirent *)NULL;
+ while (directory && (entry = readdir (directory)))
+ {
+ /* Special case for no filename.
+ All entries except "." and ".." match. */
+ if (filename_len == 0)
+ {
+ if (entry->d_name[0] != '.' ||
+ (entry->d_name[1] &&
+ (entry->d_name[1] != '.' || entry->d_name[2])))
+ break;
+ }
+ else
+ {
+ /* Otherwise, if these match up to the length of filename, then
+ it is a match. */
+ if (_rl_completion_case_fold)
+ {
+ if ((_rl_to_lower (entry->d_name[0]) == _rl_to_lower (filename[0])) &&
+ (((int)D_NAMLEN (entry)) >= filename_len) &&
+ (_rl_strnicmp (filename, entry->d_name, filename_len) == 0))
+ break;
+ }
+ else
+ {
+ if ((entry->d_name[0] == filename[0]) &&
+ (((int)D_NAMLEN (entry)) >= filename_len) &&
+ (strncmp (filename, entry->d_name, filename_len) == 0))
+ break;
+ }
+ }
+ }
+
+ if (entry == 0)
+ {
+ if (directory)
+ {
+ closedir (directory);
+ directory = (DIR *)NULL;
+ }
+ if (dirname)
+ {
+ free (dirname);
+ dirname = (char *)NULL;
+ }
+ if (filename)
+ {
+ free (filename);
+ filename = (char *)NULL;
+ }
+ if (users_dirname)
+ {
+ free (users_dirname);
+ users_dirname = (char *)NULL;
+ }
+
+ return (char *)NULL;
+ }
+ else
+ {
+ /* dirname && (strcmp (dirname, ".") != 0) */
+ if (dirname && (dirname[0] != '.' || dirname[1]))
+ {
+ if (rl_complete_with_tilde_expansion && *users_dirname == '~')
+ {
+ dirlen = strlen (dirname);
+ temp = xmalloc (2 + dirlen + D_NAMLEN (entry));
+ strcpy (temp, dirname);
+ /* Canonicalization cuts off any final slash present. We
+ may need to add it back. */
+ if (dirname[dirlen - 1] != '/')
+ {
+ temp[dirlen++] = '/';
+ temp[dirlen] = '\0';
+ }
+ }
+ else
+ {
+ dirlen = strlen (users_dirname);
+ temp = xmalloc (1 + dirlen + D_NAMLEN (entry));
+ strcpy (temp, users_dirname);
+ }
+
+ strcpy (temp + dirlen, entry->d_name);
+ }
+ else
+ temp = savestring (entry->d_name);
+
+ return (temp);
+ }
+}
+
+/* An initial implementation of a menu completion function a la tcsh. The
+ first time (if the last readline command was not rl_menu_complete), we
+ generate the list of matches. This code is very similar to the code in
+ rl_complete_internal -- there should be a way to combine the two. Then,
+ for each item in the list of matches, we insert the match in an undoable
+ fashion, with the appropriate character appended (this happens on the
+ second and subsequent consecutive calls to rl_menu_complete). When we
+ 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;
+{
+ Function *our_func;
+ int matching_filenames, found_quote;
+
+ static char *orig_text;
+ static char **matches = (char **)0;
+ static int match_list_index = 0;
+ static int match_list_size = 0;
+ static int orig_start, orig_end;
+ static char quote_char;
+ static int delimiter;
+
+ /* The first time through, we generate the list of matches and set things
+ up to insert them. */
+ if (rl_last_func != rl_menu_complete)
+ {
+ /* Clean up from previous call, if any. */
+ FREE (orig_text);
+ if (matches)
+ {
+ for (match_list_index = 0; matches[match_list_index]; match_list_index++)
+ free (matches[match_list_index]);
+ free (matches);
+ }
+
+ match_list_index = match_list_size = 0;
+ matches = (char **)NULL;
+
+ /* Only the completion entry function can change these. */
+ rl_filename_completion_desired = 0;
+ rl_filename_quoting_desired = 1;
+ rl_completion_type = '%';
+
+ our_func = rl_completion_entry_function
+ ? rl_completion_entry_function
+ : (Function *)filename_completion_function;
+
+ /* We now look backwards for the start of a filename/variable word. */
+ orig_end = rl_point;
+ found_quote = delimiter = 0;
+ quote_char = '\0';
+
+ if (rl_point)
+ /* This (possibly) changes rl_point. If it returns a non-zero char,
+ we know we have an open quote. */
+ quote_char = find_completion_word (&found_quote, &delimiter);
+
+ orig_start = rl_point;
+ rl_point = orig_end;
+
+ orig_text = rl_copy_text (orig_start, orig_end);
+ matches = gen_completion_matches (orig_text, orig_start, orig_end,
+ our_func, found_quote, quote_char);
+
+#if 0
+ /* If we are matching filenames, our_func will have been set to
+ filename_completion_function */
+ matching_filenames = our_func == (Function *)filename_completion_function;
+#else
+ /* If we are matching filenames, the attempted completion function will
+ have set rl_filename_completion_desired to a non-zero value. The basic
+ filename_completion_function does this. */
+ matching_filenames = rl_filename_completion_desired;
+#endif
+ if (matches == 0 || postprocess_matches (&matches, matching_filenames) == 0)
+ {
+ ding ();
+ FREE (matches);
+ matches = (char **)0;
+ FREE (orig_text);
+ orig_text = (char *)0;
+ completion_changed_buffer = 0;
+ return (0);
+ }
+
+ for (match_list_size = 0; matches[match_list_size]; match_list_size++)
+ ;
+ /* matches[0] is lcd if match_list_size > 1, but the circular buffer
+ code below should take care of it. */
+ }
+
+ /* Now we have the list of matches. Replace the text between
+ rl_line_buffer[orig_start] and rl_line_buffer[rl_point] with
+ matches[match_list_index], and add any necessary closing char. */
+
+ if (matches == 0 || match_list_size == 0)
+ {
+ ding ();
+ FREE (matches);
+ matches = (char **)0;
+ completion_changed_buffer = 0;
+ return (0);
+ }
+
+ match_list_index = (match_list_index + count) % match_list_size;
+ if (match_list_index < 0)
+ match_list_index += match_list_size;
+
+ if (match_list_index == 0 && match_list_size > 1)
+ {
+ ding ();
+ insert_match (orig_text, orig_start, MULT_MATCH, &quote_char);
+ }
+ else
+ {
+ insert_match (matches[match_list_index], orig_start, SINGLE_MATCH, &quote_char);
+ append_to_match (matches[match_list_index], delimiter, quote_char);
+ }
+
+ completion_changed_buffer = 1;
+ return (0);
+}
diff --git a/readline/configure b/readline/configure
new file mode 100755
index 00000000000..454a177e35d
--- /dev/null
+++ b/readline/configure
@@ -0,0 +1,2849 @@
+#! /bin/sh
+
+# From configure.in for Readline 4.0, version 2.14, from autoconf version 2.12
+LIBVERSION=4.0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# Guess values for system-dependent variables and create Makefiles.
+# Generated automatically using autoconf version 2.12
+# Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc.
+#
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+
+# Defaults:
+ac_help=
+ac_default_prefix=/usr/local
+# Any additions from configure.in:
+ac_help="$ac_help
+--with-curses use the curses library instead of the termcap library"
+
+# Initialize some variables set by options.
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+build=NONE
+cache_file=./config.cache
+exec_prefix=NONE
+host=NONE
+no_create=
+nonopt=NONE
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+target=NONE
+verbose=
+x_includes=NONE
+x_libraries=NONE
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datadir='${prefix}/share'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+libdir='${exec_prefix}/lib'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+infodir='${prefix}/info'
+mandir='${prefix}/man'
+
+# Initialize some other variables.
+subdirs=
+MFLAGS= MAKEFLAGS=
+# Maximum number of lines to put in a shell here document.
+ac_max_here_lines=12
+
+ac_prev=
+for ac_option
+do
+
+ # If the previous option needs an argument, assign it.
+ if test -n "$ac_prev"; then
+ eval "$ac_prev=\$ac_option"
+ ac_prev=
+ continue
+ fi
+
+ case "$ac_option" in
+ -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
+ *) ac_optarg= ;;
+ esac
+
+ # Accept the important Cygnus configure options, so we can diagnose typos.
+
+ case "$ac_option" in
+
+ -bindir | --bindir | --bindi | --bind | --bin | --bi)
+ ac_prev=bindir ;;
+ -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+ bindir="$ac_optarg" ;;
+
+ -build | --build | --buil | --bui | --bu)
+ ac_prev=build ;;
+ -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+ build="$ac_optarg" ;;
+
+ -cache-file | --cache-file | --cache-fil | --cache-fi \
+ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+ ac_prev=cache_file ;;
+ -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+ cache_file="$ac_optarg" ;;
+
+ -datadir | --datadir | --datadi | --datad | --data | --dat | --da)
+ ac_prev=datadir ;;
+ -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \
+ | --da=*)
+ datadir="$ac_optarg" ;;
+
+ -disable-* | --disable-*)
+ ac_feature=`echo $ac_option|sed -e 's/-*disable-//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then
+ { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+ fi
+ ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+ eval "enable_${ac_feature}=no" ;;
+
+ -enable-* | --enable-*)
+ ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then
+ { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+ fi
+ ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+ case "$ac_option" in
+ *=*) ;;
+ *) ac_optarg=yes ;;
+ esac
+ eval "enable_${ac_feature}='$ac_optarg'" ;;
+
+ -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+ | --exec | --exe | --ex)
+ ac_prev=exec_prefix ;;
+ -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+ | --exec=* | --exe=* | --ex=*)
+ exec_prefix="$ac_optarg" ;;
+
+ -gas | --gas | --ga | --g)
+ # Obsolete; use --with-gas.
+ with_gas=yes ;;
+
+ -help | --help | --hel | --he)
+ # Omit some internal or obsolete options to make the list less imposing.
+ # This message is too long to be a string in the A/UX 3.1 sh.
+ cat << EOF
+Usage: configure [options] [host]
+Options: [defaults in brackets after descriptions]
+Configuration:
+ --cache-file=FILE cache test results in FILE
+ --help print this message
+ --no-create do not create output files
+ --quiet, --silent do not print \`checking...' messages
+ --version print the version of autoconf that created configure
+Directory and file names:
+ --prefix=PREFIX install architecture-independent files in PREFIX
+ [$ac_default_prefix]
+ --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
+ [same as prefix]
+ --bindir=DIR user executables in DIR [EPREFIX/bin]
+ --sbindir=DIR system admin executables in DIR [EPREFIX/sbin]
+ --libexecdir=DIR program executables in DIR [EPREFIX/libexec]
+ --datadir=DIR read-only architecture-independent data in DIR
+ [PREFIX/share]
+ --sysconfdir=DIR read-only single-machine data in DIR [PREFIX/etc]
+ --sharedstatedir=DIR modifiable architecture-independent data in DIR
+ [PREFIX/com]
+ --localstatedir=DIR modifiable single-machine data in DIR [PREFIX/var]
+ --libdir=DIR object code libraries in DIR [EPREFIX/lib]
+ --includedir=DIR C header files in DIR [PREFIX/include]
+ --oldincludedir=DIR C header files for non-gcc in DIR [/usr/include]
+ --infodir=DIR info documentation in DIR [PREFIX/info]
+ --mandir=DIR man documentation in DIR [PREFIX/man]
+ --srcdir=DIR find the sources in DIR [configure dir or ..]
+ --program-prefix=PREFIX prepend PREFIX to installed program names
+ --program-suffix=SUFFIX append SUFFIX to installed program names
+ --program-transform-name=PROGRAM
+ run sed PROGRAM on installed program names
+EOF
+ cat << EOF
+Host type:
+ --build=BUILD configure for building on BUILD [BUILD=HOST]
+ --host=HOST configure for HOST [guessed]
+ --target=TARGET configure for TARGET [TARGET=HOST]
+Features and packages:
+ --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no)
+ --enable-FEATURE[=ARG] include FEATURE [ARG=yes]
+ --with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
+ --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
+ --x-includes=DIR X include files are in DIR
+ --x-libraries=DIR X library files are in DIR
+EOF
+ if test -n "$ac_help"; then
+ echo "--enable and --with options recognized:$ac_help"
+ fi
+ exit 0 ;;
+
+ -host | --host | --hos | --ho)
+ ac_prev=host ;;
+ -host=* | --host=* | --hos=* | --ho=*)
+ host="$ac_optarg" ;;
+
+ -includedir | --includedir | --includedi | --included | --include \
+ | --includ | --inclu | --incl | --inc)
+ ac_prev=includedir ;;
+ -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+ | --includ=* | --inclu=* | --incl=* | --inc=*)
+ includedir="$ac_optarg" ;;
+
+ -infodir | --infodir | --infodi | --infod | --info | --inf)
+ ac_prev=infodir ;;
+ -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+ infodir="$ac_optarg" ;;
+
+ -libdir | --libdir | --libdi | --libd)
+ ac_prev=libdir ;;
+ -libdir=* | --libdir=* | --libdi=* | --libd=*)
+ libdir="$ac_optarg" ;;
+
+ -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+ | --libexe | --libex | --libe)
+ ac_prev=libexecdir ;;
+ -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+ | --libexe=* | --libex=* | --libe=*)
+ libexecdir="$ac_optarg" ;;
+
+ -localstatedir | --localstatedir | --localstatedi | --localstated \
+ | --localstate | --localstat | --localsta | --localst \
+ | --locals | --local | --loca | --loc | --lo)
+ ac_prev=localstatedir ;;
+ -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+ | --localstate=* | --localstat=* | --localsta=* | --localst=* \
+ | --locals=* | --local=* | --loca=* | --loc=* | --lo=*)
+ localstatedir="$ac_optarg" ;;
+
+ -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+ ac_prev=mandir ;;
+ -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+ mandir="$ac_optarg" ;;
+
+ -nfp | --nfp | --nf)
+ # Obsolete; use --without-fp.
+ with_fp=no ;;
+
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c)
+ no_create=yes ;;
+
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+ no_recursion=yes ;;
+
+ -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+ | --oldin | --oldi | --old | --ol | --o)
+ ac_prev=oldincludedir ;;
+ -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+ oldincludedir="$ac_optarg" ;;
+
+ -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+ ac_prev=prefix ;;
+ -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+ prefix="$ac_optarg" ;;
+
+ -program-prefix | --program-prefix | --program-prefi | --program-pref \
+ | --program-pre | --program-pr | --program-p)
+ ac_prev=program_prefix ;;
+ -program-prefix=* | --program-prefix=* | --program-prefi=* \
+ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+ program_prefix="$ac_optarg" ;;
+
+ -program-suffix | --program-suffix | --program-suffi | --program-suff \
+ | --program-suf | --program-su | --program-s)
+ ac_prev=program_suffix ;;
+ -program-suffix=* | --program-suffix=* | --program-suffi=* \
+ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+ program_suffix="$ac_optarg" ;;
+
+ -program-transform-name | --program-transform-name \
+ | --program-transform-nam | --program-transform-na \
+ | --program-transform-n | --program-transform- \
+ | --program-transform | --program-transfor \
+ | --program-transfo | --program-transf \
+ | --program-trans | --program-tran \
+ | --progr-tra | --program-tr | --program-t)
+ ac_prev=program_transform_name ;;
+ -program-transform-name=* | --program-transform-name=* \
+ | --program-transform-nam=* | --program-transform-na=* \
+ | --program-transform-n=* | --program-transform-=* \
+ | --program-transform=* | --program-transfor=* \
+ | --program-transfo=* | --program-transf=* \
+ | --program-trans=* | --program-tran=* \
+ | --progr-tra=* | --program-tr=* | --program-t=*)
+ program_transform_name="$ac_optarg" ;;
+
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ silent=yes ;;
+
+ -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+ ac_prev=sbindir ;;
+ -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+ | --sbi=* | --sb=*)
+ sbindir="$ac_optarg" ;;
+
+ -sharedstatedir | --sharedstatedir | --sharedstatedi \
+ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+ | --sharedst | --shareds | --shared | --share | --shar \
+ | --sha | --sh)
+ ac_prev=sharedstatedir ;;
+ -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+ | --sha=* | --sh=*)
+ sharedstatedir="$ac_optarg" ;;
+
+ -site | --site | --sit)
+ ac_prev=site ;;
+ -site=* | --site=* | --sit=*)
+ site="$ac_optarg" ;;
+
+ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+ ac_prev=srcdir ;;
+ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+ srcdir="$ac_optarg" ;;
+
+ -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+ | --syscon | --sysco | --sysc | --sys | --sy)
+ ac_prev=sysconfdir ;;
+ -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+ sysconfdir="$ac_optarg" ;;
+
+ -target | --target | --targe | --targ | --tar | --ta | --t)
+ ac_prev=target ;;
+ -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+ target="$ac_optarg" ;;
+
+ -v | -verbose | --verbose | --verbos | --verbo | --verb)
+ verbose=yes ;;
+
+ -version | --version | --versio | --versi | --vers)
+ echo "configure generated by autoconf version 2.12"
+ exit 0 ;;
+
+ -with-* | --with-*)
+ ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then
+ { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+ fi
+ ac_package=`echo $ac_package| sed 's/-/_/g'`
+ case "$ac_option" in
+ *=*) ;;
+ *) ac_optarg=yes ;;
+ esac
+ eval "with_${ac_package}='$ac_optarg'" ;;
+
+ -without-* | --without-*)
+ ac_package=`echo $ac_option|sed -e 's/-*without-//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then
+ { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+ fi
+ ac_package=`echo $ac_package| sed 's/-/_/g'`
+ eval "with_${ac_package}=no" ;;
+
+ --x)
+ # Obsolete; use --with-x.
+ with_x=yes ;;
+
+ -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+ | --x-incl | --x-inc | --x-in | --x-i)
+ ac_prev=x_includes ;;
+ -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+ x_includes="$ac_optarg" ;;
+
+ -x-libraries | --x-libraries | --x-librarie | --x-librari \
+ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+ ac_prev=x_libraries ;;
+ -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+ x_libraries="$ac_optarg" ;;
+
+ -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; }
+ ;;
+
+ *)
+ if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then
+ echo "configure: warning: $ac_option: invalid host type" 1>&2
+ fi
+ if test "x$nonopt" != xNONE; then
+ { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; }
+ fi
+ nonopt="$ac_option"
+ ;;
+
+ esac
+done
+
+if test -n "$ac_prev"; then
+ { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; }
+fi
+
+trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
+
+# File descriptor usage:
+# 0 standard input
+# 1 file creation
+# 2 errors and warnings
+# 3 some systems may open it to /dev/tty
+# 4 used on the Kubota Titan
+# 6 checking for... messages and results
+# 5 compiler messages saved in config.log
+if test "$silent" = yes; then
+ exec 6>/dev/null
+else
+ exec 6>&1
+fi
+exec 5>./config.log
+
+echo "\
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+" 1>&5
+
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Also quote any args containing shell metacharacters.
+ac_configure_args=
+for ac_arg
+do
+ case "$ac_arg" in
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c) ;;
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;;
+ *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*)
+ ac_configure_args="$ac_configure_args '$ac_arg'" ;;
+ *) ac_configure_args="$ac_configure_args $ac_arg" ;;
+ esac
+done
+
+# NLS nuisances.
+# Only set these to C if already set. These must not be set unconditionally
+# because not all systems understand e.g. LANG=C (notably SCO).
+# Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'!
+# Non-C LC_CTYPE values break the ctype check.
+if test "${LANG+set}" = set; then LANG=C; export LANG; fi
+if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi
+if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi
+if test "${LC_CTYPE+set}" = set; then LC_CTYPE=C; export LC_CTYPE; fi
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -rf conftest* confdefs.h
+# AIX cpp loses on an empty file, so make sure it contains at least a newline.
+echo > confdefs.h
+
+# A filename unique to this package, relative to the directory that
+# configure is in, which we can look for to find out if srcdir is correct.
+ac_unique_file=readline.h
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+ ac_srcdir_defaulted=yes
+ # Try the directory containing this script, then its parent.
+ ac_prog=$0
+ ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'`
+ test "x$ac_confdir" = "x$ac_prog" && ac_confdir=.
+ srcdir=$ac_confdir
+ if test ! -r $srcdir/$ac_unique_file; then
+ srcdir=..
+ fi
+else
+ ac_srcdir_defaulted=no
+fi
+if test ! -r $srcdir/$ac_unique_file; then
+ if test "$ac_srcdir_defaulted" = yes; then
+ { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; }
+ else
+ { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; }
+ fi
+fi
+srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'`
+
+# Prefer explicitly selected file to automatically selected ones.
+if test -z "$CONFIG_SITE"; then
+ if test "x$prefix" != xNONE; then
+ CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site"
+ else
+ CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site"
+ fi
+fi
+for ac_site_file in $CONFIG_SITE; do
+ if test -r "$ac_site_file"; then
+ echo "loading site script $ac_site_file"
+ . "$ac_site_file"
+ fi
+done
+
+if test -r "$cache_file"; then
+ echo "loading cache $cache_file"
+ . $cache_file
+else
+ echo "creating cache $cache_file"
+ > $cache_file
+fi
+
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then
+ # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu.
+ if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then
+ ac_n= ac_c='
+' ac_t=' '
+ else
+ ac_n=-n ac_c= ac_t=
+ fi
+else
+ ac_n= ac_c='\c' ac_t=
+fi
+
+
+
+
+
+
+ac_aux_dir=
+for ac_dir in ./support $srcdir/./support; do
+ if test -f $ac_dir/install-sh; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install-sh -c"
+ break
+ elif test -f $ac_dir/install.sh; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install.sh -c"
+ break
+ fi
+done
+if test -z "$ac_aux_dir"; then
+ { echo "configure: error: can not find install-sh or install.sh in ./support $srcdir/./support" 1>&2; exit 1; }
+fi
+ac_config_guess=$ac_aux_dir/config.guess
+ac_config_sub=$ac_aux_dir/config.sub
+ac_configure=$ac_aux_dir/configure # This should be Cygnus configure.
+
+
+
+# Make sure we can run config.sub.
+if $ac_config_sub sun4 >/dev/null 2>&1; then :
+else { echo "configure: error: can not run $ac_config_sub" 1>&2; exit 1; }
+fi
+
+echo $ac_n "checking host system type""... $ac_c" 1>&6
+echo "configure:646: checking host system type" >&5
+
+host_alias=$host
+case "$host_alias" in
+NONE)
+ case $nonopt in
+ NONE)
+ if host_alias=`$ac_config_guess`; then :
+ else { echo "configure: error: can not guess host type; you must specify one" 1>&2; exit 1; }
+ fi ;;
+ *) host_alias=$nonopt ;;
+ esac ;;
+esac
+
+host=`$ac_config_sub $host_alias`
+host_cpu=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
+host_vendor=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
+host_os=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
+echo "$ac_t""$host" 1>&6
+
+
+opt_curses=no
+opt_shared=no
+
+# Check whether --with-curses or --without-curses was given.
+if test "${with_curses+set}" = set; then
+ withval="$with_curses"
+ opt_curses=$withval
+fi
+
+
+if test "$opt_curses" = "yes"; then
+ prefer_curses=yes
+fi
+
+# We want these before the checks, so the checks can modify their values.
+test -z "$CFLAGS" && CFLAGS=-g auto_cflags=1
+
+# Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:687: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+ for ac_dir in $PATH; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_prog_CC="gcc"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+ echo "$ac_t""$CC" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+if test -z "$CC"; then
+ # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:716: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+ ac_prog_rejected=no
+ for ac_dir in $PATH; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then
+ ac_prog_rejected=yes
+ continue
+ fi
+ ac_cv_prog_CC="cc"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+if test $ac_prog_rejected = yes; then
+ # We found a bogon in the path, so make sure we never use it.
+ set dummy $ac_cv_prog_CC
+ shift
+ if test $# -gt 0; then
+ # We chose a different compiler from the bogus one.
+ # However, it has the same basename, so the bogon will be chosen
+ # first if we set CC to just the basename; use the full file name.
+ shift
+ set dummy "$ac_dir/$ac_word" "$@"
+ shift
+ ac_cv_prog_CC="$@"
+ fi
+fi
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+ echo "$ac_t""$CC" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+ test -z "$CC" && { echo "configure: error: no acceptable cc found in \$PATH" 1>&2; exit 1; }
+fi
+
+echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6
+echo "configure:764: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5
+
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+cat > conftest.$ac_ext <<EOF
+#line 774 "configure"
+#include "confdefs.h"
+main(){return(0);}
+EOF
+if { (eval echo configure:778: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+ ac_cv_prog_cc_works=yes
+ # If we can't run a trivial program, we are probably using a cross compiler.
+ if (./conftest; exit) 2>/dev/null; then
+ ac_cv_prog_cc_cross=no
+ else
+ ac_cv_prog_cc_cross=yes
+ fi
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ ac_cv_prog_cc_works=no
+fi
+rm -fr conftest*
+
+echo "$ac_t""$ac_cv_prog_cc_works" 1>&6
+if test $ac_cv_prog_cc_works = no; then
+ { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; }
+fi
+echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6
+echo "configure:798: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5
+echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6
+cross_compiling=$ac_cv_prog_cc_cross
+
+echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6
+echo "configure:803: checking whether we are using GNU C" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.c <<EOF
+#ifdef __GNUC__
+ yes;
+#endif
+EOF
+if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:812: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
+ ac_cv_prog_gcc=yes
+else
+ ac_cv_prog_gcc=no
+fi
+fi
+
+echo "$ac_t""$ac_cv_prog_gcc" 1>&6
+
+if test $ac_cv_prog_gcc = yes; then
+ GCC=yes
+ ac_test_CFLAGS="${CFLAGS+set}"
+ ac_save_CFLAGS="$CFLAGS"
+ CFLAGS=
+ echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6
+echo "configure:827: checking whether ${CC-cc} accepts -g" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ echo 'void f(){}' > conftest.c
+if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then
+ ac_cv_prog_cc_g=yes
+else
+ ac_cv_prog_cc_g=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_prog_cc_g" 1>&6
+ if test "$ac_test_CFLAGS" = set; then
+ CFLAGS="$ac_save_CFLAGS"
+ elif test $ac_cv_prog_cc_g = yes; then
+ CFLAGS="-g -O2"
+ else
+ CFLAGS="-O2"
+ fi
+else
+ GCC=
+ test "${CFLAGS+set}" = set || CFLAGS="-g"
+fi
+
+echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6
+echo "configure:855: checking how to run the C preprocessor" >&5
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+ CPP=
+fi
+if test -z "$CPP"; then
+if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ # This must be in double quotes, not single quotes, because CPP may get
+ # substituted into the Makefile and "${CC-cc}" will confuse make.
+ CPP="${CC-cc} -E"
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp.
+ cat > conftest.$ac_ext <<EOF
+#line 870 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:876: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out`
+if test -z "$ac_err"; then
+ :
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ CPP="${CC-cc} -E -traditional-cpp"
+ cat > conftest.$ac_ext <<EOF
+#line 887 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:893: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out`
+if test -z "$ac_err"; then
+ :
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ CPP=/lib/cpp
+fi
+rm -f conftest*
+fi
+rm -f conftest*
+ ac_cv_prog_CPP="$CPP"
+fi
+ CPP="$ac_cv_prog_CPP"
+else
+ ac_cv_prog_CPP="$CPP"
+fi
+echo "$ac_t""$CPP" 1>&6
+
+ac_safe=`echo "minix/config.h" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for minix/config.h""... $ac_c" 1>&6
+echo "configure:917: checking for minix/config.h" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 922 "configure"
+#include "confdefs.h"
+#include <minix/config.h>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:927: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=yes"
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ MINIX=yes
+else
+ echo "$ac_t""no" 1>&6
+MINIX=
+fi
+
+if test "$MINIX" = yes; then
+ cat >> confdefs.h <<\EOF
+#define _POSIX_SOURCE 1
+EOF
+
+ cat >> confdefs.h <<\EOF
+#define _POSIX_1_SOURCE 2
+EOF
+
+ cat >> confdefs.h <<\EOF
+#define _MINIX 1
+EOF
+
+fi
+
+
+# If we're using gcc and the user hasn't specified CFLAGS, add -O to CFLAGS.
+test -n "$GCC" && test -n "$auto_cflags" && CFLAGS="$CFLAGS -O"
+
+if test $ac_cv_prog_gcc = yes; then
+ echo $ac_n "checking whether ${CC-cc} needs -traditional""... $ac_c" 1>&6
+echo "configure:970: checking whether ${CC-cc} needs -traditional" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_gcc_traditional'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_pattern="Autoconf.*'x'"
+ cat > conftest.$ac_ext <<EOF
+#line 976 "configure"
+#include "confdefs.h"
+#include <sgtty.h>
+Autoconf TIOCGETP
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "$ac_pattern" >/dev/null 2>&1; then
+ rm -rf conftest*
+ ac_cv_prog_gcc_traditional=yes
+else
+ rm -rf conftest*
+ ac_cv_prog_gcc_traditional=no
+fi
+rm -f conftest*
+
+
+ if test $ac_cv_prog_gcc_traditional = no; then
+ cat > conftest.$ac_ext <<EOF
+#line 994 "configure"
+#include "confdefs.h"
+#include <termio.h>
+Autoconf TCGETA
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "$ac_pattern" >/dev/null 2>&1; then
+ rm -rf conftest*
+ ac_cv_prog_gcc_traditional=yes
+fi
+rm -f conftest*
+
+ fi
+fi
+
+echo "$ac_t""$ac_cv_prog_gcc_traditional" 1>&6
+ if test $ac_cv_prog_gcc_traditional = yes; then
+ CC="$CC -traditional"
+ fi
+fi
+
+# Find a good install program. We prefer a C program (faster),
+# so one script is as good as another. But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# ./install, which can be erroneously created by make from ./install.sh.
+echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6
+echo "configure:1026: checking for a BSD compatible install" >&5
+if test -z "$INSTALL"; then
+if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ IFS="${IFS= }"; ac_save_IFS="$IFS"; IFS="${IFS}:"
+ for ac_dir in $PATH; do
+ # Account for people who put trailing slashes in PATH elements.
+ case "$ac_dir/" in
+ /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;;
+ *)
+ # OSF1 and SCO ODT 3.0 have their own names for install.
+ for ac_prog in ginstall installbsd scoinst install; do
+ if test -f $ac_dir/$ac_prog; then
+ if test $ac_prog = install &&
+ grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then
+ # AIX install. It has an incompatible calling convention.
+ # OSF/1 installbsd also uses dspmsg, but is usable.
+ :
+ else
+ ac_cv_path_install="$ac_dir/$ac_prog -c"
+ break 2
+ fi
+ fi
+ done
+ ;;
+ esac
+ done
+ IFS="$ac_save_IFS"
+
+fi
+ if test "${ac_cv_path_install+set}" = set; then
+ INSTALL="$ac_cv_path_install"
+ else
+ # As a last resort, use the slow shell script. We don't cache a
+ # path for INSTALL within a source directory, because that will
+ # break other packages using the cache if that directory is
+ # removed, or if the path is relative.
+ INSTALL="$ac_install_sh"
+ fi
+fi
+echo "$ac_t""$INSTALL" 1>&6
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+# Extract the first word of "ar", so it can be a program name with args.
+set dummy ar; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:1078: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_AR'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$AR"; then
+ ac_cv_prog_AR="$AR" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+ for ac_dir in $PATH; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_prog_AR="ar"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+fi
+fi
+AR="$ac_cv_prog_AR"
+if test -n "$AR"; then
+ echo "$ac_t""$AR" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+test -n "$ARFLAGS" || ARFLAGS="cr"
+# Extract the first word of "ranlib", so it can be a program name with args.
+set dummy ranlib; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:1107: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$RANLIB"; then
+ ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+ for ac_dir in $PATH; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_prog_RANLIB="ranlib"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+ test -z "$ac_cv_prog_RANLIB" && ac_cv_prog_RANLIB=":"
+fi
+fi
+RANLIB="$ac_cv_prog_RANLIB"
+if test -n "$RANLIB"; then
+ echo "$ac_t""$RANLIB" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+
+MAKE_SHELL=/bin/sh
+
+
+echo $ac_n "checking return type of signal handlers""... $ac_c" 1>&6
+echo "configure:1138: checking return type of signal handlers" >&5
+if eval "test \"`echo '$''{'ac_cv_type_signal'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1143 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <signal.h>
+#ifdef signal
+#undef signal
+#endif
+#ifdef __cplusplus
+extern "C" void (*signal (int, void (*)(int)))(int);
+#else
+void (*signal ()) ();
+#endif
+
+int main() {
+int i;
+; return 0; }
+EOF
+if { (eval echo configure:1160: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ac_cv_type_signal=void
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ac_cv_type_signal=int
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_type_signal" 1>&6
+cat >> confdefs.h <<EOF
+#define RETSIGTYPE $ac_cv_type_signal
+EOF
+
+
+
+echo $ac_n "checking whether stat file-mode macros are broken""... $ac_c" 1>&6
+echo "configure:1180: checking whether stat file-mode macros are broken" >&5
+if eval "test \"`echo '$''{'ac_cv_header_stat_broken'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1185 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#if defined(S_ISBLK) && defined(S_IFDIR)
+# if S_ISBLK (S_IFDIR)
+You lose.
+# endif
+#endif
+
+#if defined(S_ISBLK) && defined(S_IFCHR)
+# if S_ISBLK (S_IFCHR)
+You lose.
+# endif
+#endif
+
+#if defined(S_ISLNK) && defined(S_IFREG)
+# if S_ISLNK (S_IFREG)
+You lose.
+# endif
+#endif
+
+#if defined(S_ISSOCK) && defined(S_IFREG)
+# if S_ISSOCK (S_IFREG)
+You lose.
+# endif
+#endif
+
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "You lose" >/dev/null 2>&1; then
+ rm -rf conftest*
+ ac_cv_header_stat_broken=yes
+else
+ rm -rf conftest*
+ ac_cv_header_stat_broken=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_header_stat_broken" 1>&6
+if test $ac_cv_header_stat_broken = yes; then
+ cat >> confdefs.h <<\EOF
+#define STAT_MACROS_BROKEN 1
+EOF
+
+fi
+
+ac_header_dirent=no
+for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr that defines DIR""... $ac_c" 1>&6
+echo "configure:1240: checking for $ac_hdr that defines DIR" >&5
+if eval "test \"`echo '$''{'ac_cv_header_dirent_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1245 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <$ac_hdr>
+int main() {
+DIR *dirp = 0;
+; return 0; }
+EOF
+if { (eval echo configure:1253: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ eval "ac_cv_header_dirent_$ac_safe=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_header_dirent_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_dirent_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+ ac_header_dirent=$ac_hdr; break
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+# Two versions of opendir et al. are in -ldir and -lx on SCO Xenix.
+if test $ac_header_dirent = dirent.h; then
+echo $ac_n "checking for opendir in -ldir""... $ac_c" 1>&6
+echo "configure:1278: checking for opendir in -ldir" >&5
+ac_lib_var=`echo dir'_'opendir | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-ldir $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1286 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char opendir();
+
+int main() {
+opendir()
+; return 0; }
+EOF
+if { (eval echo configure:1297: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ LIBS="$LIBS -ldir"
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+else
+echo $ac_n "checking for opendir in -lx""... $ac_c" 1>&6
+echo "configure:1319: checking for opendir in -lx" >&5
+ac_lib_var=`echo x'_'opendir | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-lx $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1327 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char opendir();
+
+int main() {
+opendir()
+; return 0; }
+EOF
+if { (eval echo configure:1338: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ LIBS="$LIBS -lx"
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+fi
+
+
+for ac_func in strcasecmp select setenv putenv tcgetattr setlocale lstat
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:1364: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1369 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:1392: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+
+echo $ac_n "checking for working strcoll""... $ac_c" 1>&6
+echo "configure:1418: checking for working strcoll" >&5
+if eval "test \"`echo '$''{'ac_cv_func_strcoll_works'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test "$cross_compiling" = yes; then
+ ac_cv_func_strcoll_works=no
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1426 "configure"
+#include "confdefs.h"
+#include <string.h>
+main ()
+{
+ exit (strcoll ("abc", "def") >= 0 ||
+ strcoll ("ABC", "DEF") >= 0 ||
+ strcoll ("123", "456") >= 0);
+}
+EOF
+if { (eval echo configure:1436: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null
+then
+ ac_cv_func_strcoll_works=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ ac_cv_func_strcoll_works=no
+fi
+rm -fr conftest*
+fi
+
+fi
+
+echo "$ac_t""$ac_cv_func_strcoll_works" 1>&6
+if test $ac_cv_func_strcoll_works = yes; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_STRCOLL 1
+EOF
+
+fi
+
+
+for ac_hdr in unistd.h stdlib.h varargs.h stdarg.h string.h \
+ sys/ptem.h sys/pte.h sys/stream.h sys/select.h \
+ termcap.h termios.h termio.h sys/file.h locale.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:1465: checking for $ac_hdr" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1470 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1475: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=yes"
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+
+
+echo $ac_n "checking for type of signal functions""... $ac_c" 1>&6
+echo "configure:1504: checking for type of signal functions" >&5
+if eval "test \"`echo '$''{'bash_cv_signal_vintage'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+ cat > conftest.$ac_ext <<EOF
+#line 1510 "configure"
+#include "confdefs.h"
+#include <signal.h>
+int main() {
+
+ sigset_t ss;
+ struct sigaction sa;
+ sigemptyset(&ss); sigsuspend(&ss);
+ sigaction(SIGINT, &sa, (struct sigaction *) 0);
+ sigprocmask(SIG_BLOCK, &ss, (sigset_t *) 0);
+
+; return 0; }
+EOF
+if { (eval echo configure:1523: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+ rm -rf conftest*
+ bash_cv_signal_vintage=posix
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+
+ cat > conftest.$ac_ext <<EOF
+#line 1532 "configure"
+#include "confdefs.h"
+#include <signal.h>
+int main() {
+
+ int mask = sigmask(SIGINT);
+ sigsetmask(mask); sigblock(mask); sigpause(mask);
+
+; return 0; }
+EOF
+if { (eval echo configure:1542: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+ rm -rf conftest*
+ bash_cv_signal_vintage=4.2bsd
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+
+ cat > conftest.$ac_ext <<EOF
+#line 1551 "configure"
+#include "confdefs.h"
+
+ #include <signal.h>
+ RETSIGTYPE foo() { }
+int main() {
+
+ int mask = sigmask(SIGINT);
+ sigset(SIGINT, foo); sigrelse(SIGINT);
+ sighold(SIGINT); sigpause(SIGINT);
+
+; return 0; }
+EOF
+if { (eval echo configure:1564: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+ rm -rf conftest*
+ bash_cv_signal_vintage=svr3
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ bash_cv_signal_vintage=v7
+
+fi
+rm -f conftest*
+
+fi
+rm -f conftest*
+
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$bash_cv_signal_vintage" 1>&6
+if test "$bash_cv_signal_vintage" = posix; then
+cat >> confdefs.h <<\EOF
+#define HAVE_POSIX_SIGNALS 1
+EOF
+
+elif test "$bash_cv_signal_vintage" = "4.2bsd"; then
+cat >> confdefs.h <<\EOF
+#define HAVE_BSD_SIGNALS 1
+EOF
+
+elif test "$bash_cv_signal_vintage" = svr3; then
+cat >> confdefs.h <<\EOF
+#define HAVE_USG_SIGHOLD 1
+EOF
+
+fi
+
+
+
+echo $ac_n "checking if signal handlers must be reinstalled when invoked""... $ac_c" 1>&6
+echo "configure:1605: checking if signal handlers must be reinstalled when invoked" >&5
+if eval "test \"`echo '$''{'bash_cv_must_reinstall_sighandlers'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test "$cross_compiling" = yes; then
+ echo "configure: warning: cannot check signal handling if cross compiling -- defaulting to no" 1>&2
+ bash_cv_must_reinstall_sighandlers=no
+
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1615 "configure"
+#include "confdefs.h"
+
+#include <signal.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+typedef RETSIGTYPE sigfunc();
+
+int nsigint;
+
+#ifdef HAVE_POSIX_SIGNALS
+sigfunc *
+set_signal_handler(sig, handler)
+ int sig;
+ sigfunc *handler;
+{
+ struct sigaction act, oact;
+ act.sa_handler = handler;
+ act.sa_flags = 0;
+ sigemptyset (&act.sa_mask);
+ sigemptyset (&oact.sa_mask);
+ sigaction (sig, &act, &oact);
+ return (oact.sa_handler);
+}
+#else
+#define set_signal_handler(s, h) signal(s, h)
+#endif
+
+RETSIGTYPE
+sigint(s)
+int s;
+{
+ nsigint++;
+}
+
+main()
+{
+ nsigint = 0;
+ set_signal_handler(SIGINT, sigint);
+ kill((int)getpid(), SIGINT);
+ kill((int)getpid(), SIGINT);
+ exit(nsigint != 2);
+}
+
+EOF
+if { (eval echo configure:1662: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null
+then
+ bash_cv_must_reinstall_sighandlers=no
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ bash_cv_must_reinstall_sighandlers=yes
+fi
+rm -fr conftest*
+fi
+
+fi
+
+echo "$ac_t""$bash_cv_must_reinstall_sighandlers" 1>&6
+if test $bash_cv_must_reinstall_sighandlers = yes; then
+cat >> confdefs.h <<\EOF
+#define MUST_REINSTALL_SIGHANDLERS 1
+EOF
+
+fi
+
+
+
+echo $ac_n "checking for presence of POSIX-style sigsetjmp/siglongjmp""... $ac_c" 1>&6
+echo "configure:1687: checking for presence of POSIX-style sigsetjmp/siglongjmp" >&5
+if eval "test \"`echo '$''{'bash_cv_func_sigsetjmp'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test "$cross_compiling" = yes; then
+ echo "configure: warning: cannot check for sigsetjmp/siglongjmp if cross-compiling -- defaulting to missing" 1>&2
+ bash_cv_func_sigsetjmp=missing
+
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1697 "configure"
+#include "confdefs.h"
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <sys/types.h>
+#include <signal.h>
+#include <setjmp.h>
+
+main()
+{
+#if !defined (_POSIX_VERSION) || !defined (HAVE_POSIX_SIGNALS)
+exit (1);
+#else
+
+int code;
+sigset_t set, oset;
+sigjmp_buf xx;
+
+/* get the mask */
+sigemptyset(&set);
+sigemptyset(&oset);
+sigprocmask(SIG_BLOCK, (sigset_t *)NULL, &set);
+sigprocmask(SIG_BLOCK, (sigset_t *)NULL, &oset);
+
+/* save it */
+code = sigsetjmp(xx, 1);
+if (code)
+ exit(0); /* could get sigmask and compare to oset here. */
+
+/* change it */
+sigaddset(&set, SIGINT);
+sigprocmask(SIG_BLOCK, &set, (sigset_t *)NULL);
+
+/* and siglongjmp */
+siglongjmp(xx, 10);
+exit(1);
+#endif
+}
+EOF
+if { (eval echo configure:1738: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null
+then
+ bash_cv_func_sigsetjmp=present
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ bash_cv_func_sigsetjmp=missing
+fi
+rm -fr conftest*
+fi
+
+fi
+
+echo "$ac_t""$bash_cv_func_sigsetjmp" 1>&6
+if test $bash_cv_func_sigsetjmp = present; then
+cat >> confdefs.h <<\EOF
+#define HAVE_POSIX_SIGSETJMP 1
+EOF
+
+fi
+
+echo $ac_n "checking for lstat""... $ac_c" 1>&6
+echo "configure:1761: checking for lstat" >&5
+if eval "test \"`echo '$''{'bash_cv_func_lstat'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1766 "configure"
+#include "confdefs.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+int main() {
+ lstat(".",(struct stat *)0);
+; return 0; }
+EOF
+if { (eval echo configure:1776: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+ rm -rf conftest*
+ bash_cv_func_lstat=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ bash_cv_func_lstat=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$bash_cv_func_lstat" 1>&6
+if test $bash_cv_func_lstat = yes; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_LSTAT 1
+EOF
+
+fi
+
+echo $ac_n "checking whether programs are able to redeclare getpw functions""... $ac_c" 1>&6
+echo "configure:1797: checking whether programs are able to redeclare getpw functions" >&5
+if eval "test \"`echo '$''{'bash_cv_can_redecl_getpw'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1802 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <pwd.h>
+extern struct passwd *getpwent();
+extern struct passwd *getpwuid();
+extern struct passwd *getpwnam();
+int main() {
+struct passwd *z; z = getpwent(); z = getpwuid(0); z = getpwnam("root");
+; return 0; }
+EOF
+if { (eval echo configure:1813: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ bash_cv_can_redecl_getpw=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ bash_cv_can_redecl_getpw=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$bash_cv_can_redecl_getpw" 1>&6
+if test $bash_cv_can_redecl_getpw = no; then
+cat >> confdefs.h <<\EOF
+#define HAVE_GETPW_DECLS 1
+EOF
+
+fi
+
+
+echo $ac_n "checking whether or not strcoll and strcmp differ""... $ac_c" 1>&6
+echo "configure:1835: checking whether or not strcoll and strcmp differ" >&5
+if eval "test \"`echo '$''{'bash_cv_func_strcoll_broken'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test "$cross_compiling" = yes; then
+ echo "configure: warning: cannot check strcoll if cross compiling -- defaulting to no" 1>&2
+ bash_cv_func_strcoll_broken=no
+
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1845 "configure"
+#include "confdefs.h"
+
+#include <stdio.h>
+#if defined (HAVE_LOCALE_H)
+#include <locale.h>
+#endif
+
+main(c, v)
+int c;
+char *v[];
+{
+ int r1, r2;
+ char *deflocale, *defcoll;
+
+#ifdef HAVE_SETLOCALE
+ deflocale = setlocale(LC_ALL, "");
+ defcoll = setlocale(LC_COLLATE, "");
+#endif
+
+#ifdef HAVE_STRCOLL
+ /* These two values are taken from tests/glob-test. */
+ r1 = strcoll("abd", "aXd");
+#else
+ r1 = 0;
+#endif
+ r2 = strcmp("abd", "aXd");
+
+ /* These two should both be greater than 0. It is permissible for
+ a system to return different values, as long as the sign is the
+ same. */
+
+ /* Exit with 1 (failure) if these two values are both > 0, since
+ this tests whether strcoll(3) is broken with respect to strcmp(3)
+ in the default locale. */
+ exit (r1 > 0 && r2 > 0);
+}
+
+EOF
+if { (eval echo configure:1884: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null
+then
+ bash_cv_func_strcoll_broken=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ bash_cv_func_strcoll_broken=no
+fi
+rm -fr conftest*
+fi
+
+fi
+
+echo "$ac_t""$bash_cv_func_strcoll_broken" 1>&6
+if test $bash_cv_func_strcoll_broken = yes; then
+cat >> confdefs.h <<\EOF
+#define STRCOLL_BROKEN 1
+EOF
+
+fi
+
+
+echo $ac_n "checking whether signal handlers are of type void""... $ac_c" 1>&6
+echo "configure:1908: checking whether signal handlers are of type void" >&5
+if eval "test \"`echo '$''{'bash_cv_void_sighandler'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1913 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <signal.h>
+#ifdef signal
+#undef signal
+#endif
+#ifdef __cplusplus
+extern "C"
+#endif
+void (*signal ()) ();
+int main() {
+int i;
+; return 0; }
+EOF
+if { (eval echo configure:1928: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ bash_cv_void_sighandler=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ bash_cv_void_sighandler=no
+fi
+rm -f conftest*
+fi
+echo "$ac_t""$bash_cv_void_sighandler" 1>&6
+if test $bash_cv_void_sighandler = yes; then
+cat >> confdefs.h <<\EOF
+#define VOID_SIGHANDLER 1
+EOF
+
+fi
+
+echo $ac_n "checking for TIOCGWINSZ in sys/ioctl.h""... $ac_c" 1>&6
+echo "configure:1948: checking for TIOCGWINSZ in sys/ioctl.h" >&5
+if eval "test \"`echo '$''{'bash_cv_tiocgwinsz_in_ioctl'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1953 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <sys/ioctl.h>
+int main() {
+int x = TIOCGWINSZ;
+; return 0; }
+EOF
+if { (eval echo configure:1961: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ bash_cv_tiocgwinsz_in_ioctl=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ bash_cv_tiocgwinsz_in_ioctl=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$bash_cv_tiocgwinsz_in_ioctl" 1>&6
+if test $bash_cv_tiocgwinsz_in_ioctl = yes; then
+cat >> confdefs.h <<\EOF
+#define GWINSZ_IN_SYS_IOCTL 1
+EOF
+
+fi
+
+echo $ac_n "checking for TIOCSTAT in sys/ioctl.h""... $ac_c" 1>&6
+echo "configure:1982: checking for TIOCSTAT in sys/ioctl.h" >&5
+if eval "test \"`echo '$''{'bash_cv_tiocstat_in_ioctl'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1987 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <sys/ioctl.h>
+int main() {
+int x = TIOCSTAT;
+; return 0; }
+EOF
+if { (eval echo configure:1995: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ bash_cv_tiocstat_in_ioctl=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ bash_cv_tiocstat_in_ioctl=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$bash_cv_tiocstat_in_ioctl" 1>&6
+if test $bash_cv_tiocstat_in_ioctl = yes; then
+cat >> confdefs.h <<\EOF
+#define TIOCSTAT_IN_SYS_IOCTL 1
+EOF
+
+fi
+
+echo $ac_n "checking for FIONREAD in sys/ioctl.h""... $ac_c" 1>&6
+echo "configure:2016: checking for FIONREAD in sys/ioctl.h" >&5
+if eval "test \"`echo '$''{'bash_cv_fionread_in_ioctl'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2021 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <sys/ioctl.h>
+int main() {
+int x = FIONREAD;
+; return 0; }
+EOF
+if { (eval echo configure:2029: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ bash_cv_fionread_in_ioctl=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ bash_cv_fionread_in_ioctl=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$bash_cv_fionread_in_ioctl" 1>&6
+if test $bash_cv_fionread_in_ioctl = yes; then
+cat >> confdefs.h <<\EOF
+#define FIONREAD_IN_SYS_IOCTL 1
+EOF
+
+fi
+
+echo $ac_n "checking for speed_t in sys/types.h""... $ac_c" 1>&6
+echo "configure:2050: checking for speed_t in sys/types.h" >&5
+if eval "test \"`echo '$''{'bash_cv_speed_t_in_sys_types'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2055 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+int main() {
+speed_t x;
+; return 0; }
+EOF
+if { (eval echo configure:2062: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ bash_cv_speed_t_in_sys_types=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ bash_cv_speed_t_in_sys_types=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$bash_cv_speed_t_in_sys_types" 1>&6
+if test $bash_cv_speed_t_in_sys_types = yes; then
+cat >> confdefs.h <<\EOF
+#define SPEED_T_IN_SYS_TYPES 1
+EOF
+
+fi
+
+echo $ac_n "checking for struct winsize in sys/ioctl.h and termios.h""... $ac_c" 1>&6
+echo "configure:2083: checking for struct winsize in sys/ioctl.h and termios.h" >&5
+if eval "test \"`echo '$''{'bash_cv_struct_winsize_header'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2088 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <sys/ioctl.h>
+int main() {
+struct winsize x;
+; return 0; }
+EOF
+if { (eval echo configure:2096: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ bash_cv_struct_winsize_header=ioctl_h
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ cat > conftest.$ac_ext <<EOF
+#line 2104 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <termios.h>
+int main() {
+struct winsize x;
+; return 0; }
+EOF
+if { (eval echo configure:2112: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ bash_cv_struct_winsize_header=termios_h
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ bash_cv_struct_winsize_header=other
+fi
+rm -f conftest*
+
+fi
+rm -f conftest*
+fi
+
+if test $bash_cv_struct_winsize_header = ioctl_h; then
+ echo "$ac_t""sys/ioctl.h" 1>&6
+ cat >> confdefs.h <<\EOF
+#define STRUCT_WINSIZE_IN_SYS_IOCTL 1
+EOF
+
+elif test $bash_cv_struct_winsize_header = termios_h; then
+ echo "$ac_t""termios.h" 1>&6
+ cat >> confdefs.h <<\EOF
+#define STRUCT_WINSIZE_IN_TERMIOS 1
+EOF
+
+else
+ echo "$ac_t""not found" 1>&6
+fi
+
+
+echo $ac_n "checking if struct dirent has a d_ino member""... $ac_c" 1>&6
+echo "configure:2145: checking if struct dirent has a d_ino member" >&5
+if eval "test \"`echo '$''{'bash_cv_dirent_has_dino'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2150 "configure"
+#include "confdefs.h"
+
+#include <stdio.h>
+#include <sys/types.h>
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#if defined(HAVE_DIRENT_H)
+# include <dirent.h>
+#else
+# define dirent direct
+# ifdef HAVE_SYS_NDIR_H
+# include <sys/ndir.h>
+# endif /* SYSNDIR */
+# ifdef HAVE_SYS_DIR_H
+# include <sys/dir.h>
+# endif /* SYSDIR */
+# ifdef HAVE_NDIR_H
+# include <ndir.h>
+# endif
+#endif /* HAVE_DIRENT_H */
+
+int main() {
+
+struct dirent d; int z; z = d.d_ino;
+
+; return 0; }
+EOF
+if { (eval echo configure:2179: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ bash_cv_dirent_has_dino=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ bash_cv_dirent_has_dino=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$bash_cv_dirent_has_dino" 1>&6
+if test $bash_cv_dirent_has_dino = yes; then
+cat >> confdefs.h <<\EOF
+#define STRUCT_DIRENT_HAS_D_INO 1
+EOF
+
+fi
+
+
+echo $ac_n "checking if struct dirent has a d_fileno member""... $ac_c" 1>&6
+echo "configure:2201: checking if struct dirent has a d_fileno member" >&5
+if eval "test \"`echo '$''{'bash_cv_dirent_has_d_fileno'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2206 "configure"
+#include "confdefs.h"
+
+#include <stdio.h>
+#include <sys/types.h>
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#if defined(HAVE_DIRENT_H)
+# include <dirent.h>
+#else
+# define dirent direct
+# ifdef HAVE_SYS_NDIR_H
+# include <sys/ndir.h>
+# endif /* SYSNDIR */
+# ifdef HAVE_SYS_DIR_H
+# include <sys/dir.h>
+# endif /* SYSDIR */
+# ifdef HAVE_NDIR_H
+# include <ndir.h>
+# endif
+#endif /* HAVE_DIRENT_H */
+
+int main() {
+
+struct dirent d; int z; z = d.d_fileno;
+
+; return 0; }
+EOF
+if { (eval echo configure:2235: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ bash_cv_dirent_has_d_fileno=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ bash_cv_dirent_has_d_fileno=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$bash_cv_dirent_has_d_fileno" 1>&6
+if test $bash_cv_dirent_has_d_fileno = yes; then
+cat >> confdefs.h <<\EOF
+#define STRUCT_DIRENT_HAS_D_FILENO 1
+EOF
+
+fi
+
+
+case "$host_os" in
+aix*) prefer_curses=yes ;;
+esac
+
+if test "X$bash_cv_termcap_lib" = "X"; then
+_bash_needmsg=yes
+else
+echo $ac_n "checking which library has the termcap functions""... $ac_c" 1>&6
+echo "configure:2264: checking which library has the termcap functions" >&5
+_bash_needmsg=
+fi
+if eval "test \"`echo '$''{'bash_cv_termcap_lib'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ echo $ac_n "checking for tgetent in -ltermcap""... $ac_c" 1>&6
+echo "configure:2271: checking for tgetent in -ltermcap" >&5
+ac_lib_var=`echo termcap'_'tgetent | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-ltermcap $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 2279 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char tgetent();
+
+int main() {
+tgetent()
+; return 0; }
+EOF
+if { (eval echo configure:2290: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ bash_cv_termcap_lib=libtermcap
+else
+ echo "$ac_t""no" 1>&6
+echo $ac_n "checking for tgetent in -lcurses""... $ac_c" 1>&6
+echo "configure:2309: checking for tgetent in -lcurses" >&5
+ac_lib_var=`echo curses'_'tgetent | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-lcurses $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 2317 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char tgetent();
+
+int main() {
+tgetent()
+; return 0; }
+EOF
+if { (eval echo configure:2328: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ bash_cv_termcap_lib=libcurses
+else
+ echo "$ac_t""no" 1>&6
+echo $ac_n "checking for tgetent in -lncurses""... $ac_c" 1>&6
+echo "configure:2347: checking for tgetent in -lncurses" >&5
+ac_lib_var=`echo ncurses'_'tgetent | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-lncurses $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 2355 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char tgetent();
+
+int main() {
+tgetent()
+; return 0; }
+EOF
+if { (eval echo configure:2366: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ bash_cv_termcap_lib=libncurses
+else
+ echo "$ac_t""no" 1>&6
+bash_cv_termcap_lib=gnutermcap
+fi
+
+fi
+
+fi
+
+fi
+
+if test "X$_bash_needmsg" = "Xyes"; then
+echo $ac_n "checking which library has the termcap functions""... $ac_c" 1>&6
+echo "configure:2395: checking which library has the termcap functions" >&5
+fi
+echo "$ac_t""using $bash_cv_termcap_lib" 1>&6
+if test $bash_cv_termcap_lib = gnutermcap && test -z "$prefer_curses"; then
+LDFLAGS="$LDFLAGS -L./lib/termcap"
+TERMCAP_LIB="./lib/termcap/libtermcap.a"
+TERMCAP_DEP="./lib/termcap/libtermcap.a"
+elif test $bash_cv_termcap_lib = libtermcap && test -z "$prefer_curses"; then
+TERMCAP_LIB=-ltermcap
+TERMCAP_DEP=
+elif test $bash_cv_termcap_lib = libncurses; then
+TERMCAP_LIB=-lncurses
+TERMCAP_DEP=
+else
+TERMCAP_LIB=-lcurses
+TERMCAP_DEP=
+fi
+
+if test "$TERMCAP_LIB" = "./lib/termcap/libtermcap.a"; then
+ TERMCAP_LIB=-ltermcap #default
+fi
+
+case "$host_cpu" in
+*cray*) LOCAL_CFLAGS=-DCRAY ;;
+esac
+
+case "$host_os" in
+isc*) LOCAL_CFLAGS=-Disc386 ;;
+esac
+
+# shared library configuration section
+#
+# Shared object configuration section. These values are generated by
+# ${srcdir}/support/shobj-conf
+#
+if test -f ${srcdir}/support/shobj-conf; then
+ echo $ac_n "checking configuration for building shared libraries""... $ac_c" 1>&6
+echo "configure:2432: checking configuration for building shared libraries" >&5
+ eval `${CONFIG_SHELL-/bin/sh} ${srcdir}/support/shobj-conf -C ${CC} -c ${host_cpu} -o ${host_os} -v ${host_vendor}`
+
+
+
+
+
+
+
+
+
+
+
+
+ echo "$ac_t""$SHLIB_STATUS" 1>&6
+fi
+
+BUILD_DIR=`pwd`
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+trap '' 1 2 15
+cat > confcache <<\EOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs. It is not useful on other systems.
+# If it contains results you don't want to keep, you may remove or edit it.
+#
+# By default, configure uses ./config.cache as the cache file,
+# creating it if it does not exist already. You can give configure
+# the --cache-file=FILE option to use a different cache file; that is
+# what configure does when it calls configure scripts in
+# subdirectories, so they share the cache.
+# Giving --cache-file=/dev/null disables caching, for debugging configure.
+# config.status only pays attention to the cache file if you give it the
+# --recheck option to rerun configure.
+#
+EOF
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, don't put newlines in cache variables' values.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(set) 2>&1 |
+ case `(ac_space=' '; set) 2>&1` in
+ *ac_space=\ *)
+ # `set' does not quote correctly, so add quotes (double-quote substitution
+ # turns \\\\ into \\, and sed turns \\ into \).
+ sed -n \
+ -e "s/'/'\\\\''/g" \
+ -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p"
+ ;;
+ *)
+ # `set' quotes correctly as required by POSIX, so do not add quotes.
+ sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p'
+ ;;
+ esac >> confcache
+if cmp -s $cache_file confcache; then
+ :
+else
+ if test -w $cache_file; then
+ echo "updating cache $cache_file"
+ cat confcache > $cache_file
+ else
+ echo "not updating unwritable cache $cache_file"
+ fi
+fi
+rm -f confcache
+
+trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+# Any assignment to VPATH causes Sun make to only execute
+# the first set of double-colon rules, so remove it if not needed.
+# If there is a colon in the path, we need to keep it.
+if test "x$srcdir" = x.; then
+ ac_vpsub='/^[ ]*VPATH[ ]*=[^:]*$/d'
+fi
+
+trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15
+
+DEFS=-DHAVE_CONFIG_H
+
+# Without the "./", some shells look in PATH for config.status.
+: ${CONFIG_STATUS=./config.status}
+
+echo creating $CONFIG_STATUS
+rm -f $CONFIG_STATUS
+cat > $CONFIG_STATUS <<EOF
+#! /bin/sh
+# Generated automatically by configure.
+# Run this file to recreate the current configuration.
+# This directory was configured as follows,
+# on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+#
+# $0 $ac_configure_args
+#
+# Compiler output produced by configure, useful for debugging
+# configure, is in ./config.log if it exists.
+
+ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]"
+for ac_option
+do
+ case "\$ac_option" in
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion"
+ exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;;
+ -version | --version | --versio | --versi | --vers | --ver | --ve | --v)
+ echo "$CONFIG_STATUS generated by autoconf version 2.12"
+ exit 0 ;;
+ -help | --help | --hel | --he | --h)
+ echo "\$ac_cs_usage"; exit 0 ;;
+ *) echo "\$ac_cs_usage"; exit 1 ;;
+ esac
+done
+
+ac_given_srcdir=$srcdir
+ac_given_INSTALL="$INSTALL"
+
+trap 'rm -fr `echo "Makefile doc/Makefile examples/Makefile shlib/Makefile config.h" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15
+EOF
+cat >> $CONFIG_STATUS <<EOF
+
+# Protect against being on the right side of a sed subst in config.status.
+sed 's/%@/@@/; s/@%/@@/; s/%g\$/@g/; /@g\$/s/[\\\\&%]/\\\\&/g;
+ s/@@/%@/; s/@@/@%/; s/@g\$/%g/' > conftest.subs <<\\CEOF
+$ac_vpsub
+$extrasub
+s%@CFLAGS@%$CFLAGS%g
+s%@CPPFLAGS@%$CPPFLAGS%g
+s%@CXXFLAGS@%$CXXFLAGS%g
+s%@DEFS@%$DEFS%g
+s%@LDFLAGS@%$LDFLAGS%g
+s%@LIBS@%$LIBS%g
+s%@exec_prefix@%$exec_prefix%g
+s%@prefix@%$prefix%g
+s%@program_transform_name@%$program_transform_name%g
+s%@bindir@%$bindir%g
+s%@sbindir@%$sbindir%g
+s%@libexecdir@%$libexecdir%g
+s%@datadir@%$datadir%g
+s%@sysconfdir@%$sysconfdir%g
+s%@sharedstatedir@%$sharedstatedir%g
+s%@localstatedir@%$localstatedir%g
+s%@libdir@%$libdir%g
+s%@includedir@%$includedir%g
+s%@oldincludedir@%$oldincludedir%g
+s%@infodir@%$infodir%g
+s%@mandir@%$mandir%g
+s%@host@%$host%g
+s%@host_alias@%$host_alias%g
+s%@host_cpu@%$host_cpu%g
+s%@host_vendor@%$host_vendor%g
+s%@host_os@%$host_os%g
+s%@CC@%$CC%g
+s%@CPP@%$CPP%g
+s%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g
+s%@INSTALL_DATA@%$INSTALL_DATA%g
+s%@AR@%$AR%g
+s%@RANLIB@%$RANLIB%g
+s%@MAKE_SHELL@%$MAKE_SHELL%g
+s%@SHOBJ_CC@%$SHOBJ_CC%g
+s%@SHOBJ_CFLAGS@%$SHOBJ_CFLAGS%g
+s%@SHOBJ_LD@%$SHOBJ_LD%g
+s%@SHOBJ_LDFLAGS@%$SHOBJ_LDFLAGS%g
+s%@SHOBJ_XLDFLAGS@%$SHOBJ_XLDFLAGS%g
+s%@SHOBJ_LIBS@%$SHOBJ_LIBS%g
+s%@SHOBJ_STATUS@%$SHOBJ_STATUS%g
+s%@SHLIB_STATUS@%$SHLIB_STATUS%g
+s%@SHLIB_XLDFLAGS@%$SHLIB_XLDFLAGS%g
+s%@SHLIB_LIBSUFF@%$SHLIB_LIBSUFF%g
+s%@SHLIB_LIBVERSION@%$SHLIB_LIBVERSION%g
+s%@SHLIB_LIBS@%$SHLIB_LIBS%g
+s%@BUILD_DIR@%$BUILD_DIR%g
+s%@LOCAL_CFLAGS@%$LOCAL_CFLAGS%g
+s%@LOCAL_LDFLAGS@%$LOCAL_LDFLAGS%g
+s%@LOCAL_DEFS@%$LOCAL_DEFS%g
+s%@ARFLAGS@%$ARFLAGS%g
+s%@LIBVERSION@%$LIBVERSION%g
+s%@TERMCAP_LIB@%$TERMCAP_LIB%g
+
+CEOF
+EOF
+
+cat >> $CONFIG_STATUS <<\EOF
+
+# Split the substitutions into bite-sized pieces for seds with
+# small command number limits, like on Digital OSF/1 and HP-UX.
+ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script.
+ac_file=1 # Number of current file.
+ac_beg=1 # First line for current file.
+ac_end=$ac_max_sed_cmds # Line after last line for current file.
+ac_more_lines=:
+ac_sed_cmds=""
+while $ac_more_lines; do
+ if test $ac_beg -gt 1; then
+ sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file
+ else
+ sed "${ac_end}q" conftest.subs > conftest.s$ac_file
+ fi
+ if test ! -s conftest.s$ac_file; then
+ ac_more_lines=false
+ rm -f conftest.s$ac_file
+ else
+ if test -z "$ac_sed_cmds"; then
+ ac_sed_cmds="sed -f conftest.s$ac_file"
+ else
+ ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file"
+ fi
+ ac_file=`expr $ac_file + 1`
+ ac_beg=$ac_end
+ ac_end=`expr $ac_end + $ac_max_sed_cmds`
+ fi
+done
+if test -z "$ac_sed_cmds"; then
+ ac_sed_cmds=cat
+fi
+EOF
+
+cat >> $CONFIG_STATUS <<EOF
+
+CONFIG_FILES=\${CONFIG_FILES-"Makefile doc/Makefile examples/Makefile shlib/Makefile"}
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then
+ # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+ case "$ac_file" in
+ *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'`
+ ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
+ *) ac_file_in="${ac_file}.in" ;;
+ esac
+
+ # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories.
+
+ # Remove last slash and all that follows it. Not all systems have dirname.
+ ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
+ if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
+ # The file is in a subdirectory.
+ test ! -d "$ac_dir" && mkdir "$ac_dir"
+ ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`"
+ # A "../" for each directory in $ac_dir_suffix.
+ ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'`
+ else
+ ac_dir_suffix= ac_dots=
+ fi
+
+ case "$ac_given_srcdir" in
+ .) srcdir=.
+ if test -z "$ac_dots"; then top_srcdir=.
+ else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;;
+ /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;;
+ *) # Relative path.
+ srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix"
+ top_srcdir="$ac_dots$ac_given_srcdir" ;;
+ esac
+
+ case "$ac_given_INSTALL" in
+ [/$]*) INSTALL="$ac_given_INSTALL" ;;
+ *) INSTALL="$ac_dots$ac_given_INSTALL" ;;
+ esac
+
+ echo creating "$ac_file"
+ rm -f "$ac_file"
+ configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure."
+ case "$ac_file" in
+ *Makefile*) ac_comsub="1i\\
+# $configure_input" ;;
+ *) ac_comsub= ;;
+ esac
+
+ ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"`
+ sed -e "$ac_comsub
+s%@configure_input@%$configure_input%g
+s%@srcdir@%$srcdir%g
+s%@top_srcdir@%$top_srcdir%g
+s%@INSTALL@%$INSTALL%g
+" $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file
+fi; done
+rm -f conftest.s*
+
+# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where
+# NAME is the cpp macro being defined and VALUE is the value it is being given.
+#
+# ac_d sets the value in "#define NAME VALUE" lines.
+ac_dA='s%^\([ ]*\)#\([ ]*define[ ][ ]*\)'
+ac_dB='\([ ][ ]*\)[^ ]*%\1#\2'
+ac_dC='\3'
+ac_dD='%g'
+# ac_u turns "#undef NAME" with trailing blanks into "#define NAME VALUE".
+ac_uA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)'
+ac_uB='\([ ]\)%\1#\2define\3'
+ac_uC=' '
+ac_uD='\4%g'
+# ac_e turns "#undef NAME" without trailing blanks into "#define NAME VALUE".
+ac_eA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)'
+ac_eB='$%\1#\2define\3'
+ac_eC=' '
+ac_eD='%g'
+
+if test "${CONFIG_HEADERS+set}" != set; then
+EOF
+cat >> $CONFIG_STATUS <<EOF
+ CONFIG_HEADERS="config.h"
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+fi
+for ac_file in .. $CONFIG_HEADERS; do if test "x$ac_file" != x..; then
+ # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+ case "$ac_file" in
+ *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'`
+ ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
+ *) ac_file_in="${ac_file}.in" ;;
+ esac
+
+ echo creating $ac_file
+
+ rm -f conftest.frag conftest.in conftest.out
+ ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"`
+ cat $ac_file_inputs > conftest.in
+
+EOF
+
+# Transform confdefs.h into a sed script conftest.vals that substitutes
+# the proper values into config.h.in to produce config.h. And first:
+# Protect against being on the right side of a sed subst in config.status.
+# Protect against being in an unquoted here document in config.status.
+rm -f conftest.vals
+cat > conftest.hdr <<\EOF
+s/[\\&%]/\\&/g
+s%[\\$`]%\\&%g
+s%#define \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD}%gp
+s%ac_d%ac_u%gp
+s%ac_u%ac_e%gp
+EOF
+sed -n -f conftest.hdr confdefs.h > conftest.vals
+rm -f conftest.hdr
+
+# This sed command replaces #undef with comments. This is necessary, for
+# example, in the case of _POSIX_SOURCE, which is predefined and required
+# on some systems where configure will not decide to define it.
+cat >> conftest.vals <<\EOF
+s%^[ ]*#[ ]*undef[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*%/* & */%
+EOF
+
+# Break up conftest.vals because some shells have a limit on
+# the size of here documents, and old seds have small limits too.
+
+rm -f conftest.tail
+while :
+do
+ ac_lines=`grep -c . conftest.vals`
+ # grep -c gives empty output for an empty file on some AIX systems.
+ if test -z "$ac_lines" || test "$ac_lines" -eq 0; then break; fi
+ # Write a limited-size here document to conftest.frag.
+ echo ' cat > conftest.frag <<CEOF' >> $CONFIG_STATUS
+ sed ${ac_max_here_lines}q conftest.vals >> $CONFIG_STATUS
+ echo 'CEOF
+ sed -f conftest.frag conftest.in > conftest.out
+ rm -f conftest.in
+ mv conftest.out conftest.in
+' >> $CONFIG_STATUS
+ sed 1,${ac_max_here_lines}d conftest.vals > conftest.tail
+ rm -f conftest.vals
+ mv conftest.tail conftest.vals
+done
+rm -f conftest.vals
+
+cat >> $CONFIG_STATUS <<\EOF
+ rm -f conftest.frag conftest.h
+ echo "/* $ac_file. Generated automatically by configure. */" > conftest.h
+ cat conftest.in >> conftest.h
+ rm -f conftest.in
+ if cmp -s $ac_file conftest.h 2>/dev/null; then
+ echo "$ac_file is unchanged"
+ rm -f conftest.h
+ else
+ # Remove last slash and all that follows it. Not all systems have dirname.
+ ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
+ if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
+ # The file is in a subdirectory.
+ test ! -d "$ac_dir" && mkdir "$ac_dir"
+ fi
+ rm -f $ac_file
+ mv conftest.h $ac_file
+ fi
+fi; done
+
+EOF
+cat >> $CONFIG_STATUS <<EOF
+
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+
+# Makefile uses this timestamp file to record whether config.h is up to date.
+echo > stamp-h
+
+exit 0
+EOF
+chmod +x $CONFIG_STATUS
+rm -fr confdefs* $ac_clean_files
+test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1
+
diff --git a/readline/configure.in b/readline/configure.in
new file mode 100644
index 00000000000..240a3addc45
--- /dev/null
+++ b/readline/configure.in
@@ -0,0 +1,143 @@
+dnl
+dnl Configure script for readline library
+dnl
+dnl report bugs to chet@po.cwru.edu
+dnl
+dnl Process this file with autoconf to produce a configure script.
+AC_REVISION([for Readline 4.0, version 2.14, from autoconf version] AC_ACVERSION)
+LIBVERSION=4.0
+
+AC_INIT(readline.h)
+AC_CONFIG_HEADER(config.h)
+
+dnl make sure we are using a recent autoconf version
+AC_PREREQ(2.10)
+
+AC_CONFIG_AUX_DIR(./support)
+
+AC_CANONICAL_HOST
+
+dnl configure defaults
+opt_curses=no
+opt_shared=no
+
+dnl arguments to configure
+AC_ARG_WITH(curses, --with-curses use the curses library instead of the termcap library,opt_curses=$withval)
+
+if test "$opt_curses" = "yes"; then
+ prefer_curses=yes
+fi
+
+# We want these before the checks, so the checks can modify their values.
+test -z "$CFLAGS" && CFLAGS=-g auto_cflags=1
+
+AC_PROG_CC
+AC_MINIX
+
+# If we're using gcc and the user hasn't specified CFLAGS, add -O to CFLAGS.
+test -n "$GCC" && test -n "$auto_cflags" && CFLAGS="$CFLAGS -O"
+
+AC_PROG_GCC_TRADITIONAL
+AC_PROG_INSTALL
+AC_CHECK_PROG(AR, ar, ar)
+dnl Set default for ARFLAGS, since autoconf does not have a macro for it.
+dnl This allows people to set it when running configure or make
+test -n "$ARFLAGS" || ARFLAGS="cr"
+AC_PROG_RANLIB
+
+MAKE_SHELL=/bin/sh
+AC_SUBST(MAKE_SHELL)
+
+AC_RETSIGTYPE
+
+AC_HEADER_STAT
+AC_HEADER_DIRENT
+
+AC_CHECK_FUNCS(strcasecmp select setenv putenv tcgetattr setlocale lstat)
+
+AC_FUNC_STRCOLL
+
+AC_CHECK_HEADERS(unistd.h stdlib.h varargs.h stdarg.h string.h \
+ sys/ptem.h sys/pte.h sys/stream.h sys/select.h \
+ termcap.h termios.h termio.h sys/file.h locale.h)
+
+BASH_SIGNAL_CHECK
+BASH_REINSTALL_SIGHANDLERS
+
+BASH_FUNC_POSIX_SETJMP
+BASH_FUNC_LSTAT
+BASH_CHECK_GETPW_FUNCS
+BASH_FUNC_STRCOLL
+
+BASH_TYPE_SIGHANDLER
+BASH_HAVE_TIOCGWINSZ
+BASH_HAVE_TIOCSTAT
+BASH_HAVE_FIONREAD
+BASH_MISC_SPEED_T
+BASH_STRUCT_WINSIZE
+BASH_STRUCT_DIRENT_D_INO
+BASH_STRUCT_DIRENT_D_FILENO
+
+dnl yuck
+case "$host_os" in
+aix*) prefer_curses=yes ;;
+esac
+BASH_CHECK_LIB_TERMCAP
+if test "$TERMCAP_LIB" = "./lib/termcap/libtermcap.a"; then
+ TERMCAP_LIB=-ltermcap #default
+fi
+
+case "$host_cpu" in
+*cray*) LOCAL_CFLAGS=-DCRAY ;;
+esac
+
+case "$host_os" in
+isc*) LOCAL_CFLAGS=-Disc386 ;;
+esac
+
+# shared library configuration section
+#
+# Shared object configuration section. These values are generated by
+# ${srcdir}/support/shobj-conf
+#
+if test -f ${srcdir}/support/shobj-conf; then
+ AC_MSG_CHECKING(configuration for building shared libraries)
+ eval `${CONFIG_SHELL-/bin/sh} ${srcdir}/support/shobj-conf -C ${CC} -c ${host_cpu} -o ${host_os} -v ${host_vendor}`
+ AC_SUBST(SHOBJ_CC)
+ AC_SUBST(SHOBJ_CFLAGS)
+ AC_SUBST(SHOBJ_LD)
+ AC_SUBST(SHOBJ_LDFLAGS)
+ AC_SUBST(SHOBJ_XLDFLAGS)
+ AC_SUBST(SHOBJ_LIBS)
+ AC_SUBST(SHOBJ_STATUS)
+ AC_SUBST(SHLIB_STATUS)
+ AC_SUBST(SHLIB_XLDFLAGS)
+ AC_SUBST(SHLIB_LIBSUFF)
+ AC_SUBST(SHLIB_LIBVERSION)
+ AC_SUBST(SHLIB_LIBS)
+ AC_MSG_RESULT($SHLIB_STATUS)
+fi
+
+BUILD_DIR=`pwd`
+AC_SUBST(BUILD_DIR)
+
+AC_SUBST(CFLAGS)
+AC_SUBST(LOCAL_CFLAGS)
+AC_SUBST(LOCAL_LDFLAGS)
+AC_SUBST(LOCAL_DEFS)
+
+AC_SUBST(AR)
+AC_SUBST(ARFLAGS)
+
+AC_SUBST(host_cpu)
+AC_SUBST(host_os)
+
+AC_SUBST(LIBVERSION)
+
+AC_SUBST(TERMCAP_LIB)
+
+AC_OUTPUT([Makefile doc/Makefile examples/Makefile shlib/Makefile],
+[
+# Makefile uses this timestamp file to record whether config.h is up to date.
+echo > stamp-h
+])
diff --git a/readline/display.c b/readline/display.c
new file mode 100644
index 00000000000..25aba64ca67
--- /dev/null
+++ b/readline/display.c
@@ -0,0 +1,1573 @@
+/* display.c -- readline redisplay facility. */
+
+/* Copyright (C) 1987, 1989, 1992 Free Software Foundation, Inc.
+
+ This file is part of the GNU Readline Library, a library for
+ reading lines of text with interactive input and history editing.
+
+ The GNU Readline Library is free software; you can redistribute it
+ and/or modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 1, or
+ (at your option) any later version.
+
+ The GNU Readline 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 General Public License for more details.
+
+ The GNU General Public License is often shipped with GNU software, and
+ is generally kept in a file called COPYING or LICENSE. If you do not
+ have a copy of the license, write to the Free Software Foundation,
+ 675 Mass Ave, Cambridge, MA 02139, USA. */
+#define READLINE_LIBRARY
+
+#if defined (HAVE_CONFIG_H)
+# include <config.h>
+#endif
+
+#include <sys/types.h>
+
+#if defined (HAVE_UNISTD_H)
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+
+#include "posixstat.h"
+
+#if defined (HAVE_STDLIB_H)
+# include <stdlib.h>
+#else
+# include "ansi_stdlib.h"
+#endif /* HAVE_STDLIB_H */
+
+#include <stdio.h>
+
+#if defined (__GO32__)
+# include <go32.h>
+# include <pc.h>
+#endif /* __GO32__ */
+
+/* System-specific feature definitions and include files. */
+#include "rldefs.h"
+
+/* Termcap library stuff. */
+#include "tcap.h"
+
+/* Some standard library routines. */
+#include "readline.h"
+#include "history.h"
+
+#if !defined (strchr) && !defined (__STDC__)
+extern char *strchr (), *strrchr ();
+#endif /* !strchr && !__STDC__ */
+
+/* Global and pseudo-global variables and functions
+ imported from readline.c. */
+extern char *rl_prompt;
+extern int readline_echoing_p;
+
+extern int _rl_output_meta_chars;
+extern int _rl_horizontal_scroll_mode;
+extern int _rl_mark_modified_lines;
+extern int _rl_prefer_visible_bell;
+
+/* Variables and functions imported from terminal.c */
+extern void _rl_output_some_chars ();
+#ifdef _MINIX
+extern void _rl_output_character_function ();
+#else
+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 int screenheight, screenwidth, screenchars;
+extern int terminal_can_insert, _rl_term_autowrap;
+
+/* Pseudo-global functions (local to the readline library) exported
+ by this file. */
+void _rl_move_cursor_relative (), _rl_output_some_chars ();
+void _rl_move_vert ();
+void _rl_clear_to_eol (), _rl_clear_screen ();
+
+static void update_line (), space_to_eol ();
+static void delete_chars (), insert_some_chars ();
+static void cr ();
+
+static int *inv_lbreaks, *vis_lbreaks;
+
+extern char *xmalloc (), *xrealloc ();
+
+/* Heuristic used to decide whether it is faster to move from CUR to NEW
+ by backing up or outputting a carriage return and moving forward. */
+#define CR_FASTER(new, cur) (((new) + 1) < ((cur) - (new)))
+
+/* **************************************************************** */
+/* */
+/* Display stuff */
+/* */
+/* **************************************************************** */
+
+/* This is the stuff that is hard for me. I never seem to write good
+ display routines in C. Let's see how I do this time. */
+
+/* (PWP) Well... Good for a simple line updater, but totally ignores
+ the problems of input lines longer than the screen width.
+
+ update_line and the code that calls it makes a multiple line,
+ automatically wrapping line update. Careful attention needs
+ to be paid to the vertical position variables. */
+
+/* Keep two buffers; one which reflects the current contents of the
+ screen, and the other to draw what we think the new contents should
+ be. Then compare the buffers, and make whatever changes to the
+ screen itself that we should. Finally, make the buffer that we
+ just drew into be the one which reflects the current contents of the
+ screen, and place the cursor where it belongs.
+
+ Commands that want to can fix the display themselves, and then let
+ this function know that the display has been fixed by setting the
+ RL_DISPLAY_FIXED variable. This is good for efficiency. */
+
+/* Application-specific redisplay function. */
+VFunction *rl_redisplay_function = rl_redisplay;
+
+/* Global variables declared here. */
+/* What YOU turn on when you have handled all redisplay yourself. */
+int rl_display_fixed = 0;
+
+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;
+
+/* Pseudo-global variables declared here. */
+/* The visible cursor position. If you print some text, adjust this. */
+int _rl_last_c_pos = 0;
+int _rl_last_v_pos = 0;
+
+/* Number of lines currently on screen minus 1. */
+int _rl_vis_botlin = 0;
+
+/* Variables used only in this file. */
+/* The last left edge of text that was displayed. This is used when
+ doing horizontal scrolling. It shifts in thirds of a screenwidth. */
+static int last_lmargin;
+
+/* The line display buffers. One is the line currently displayed on
+ the screen. The other is the line about to be displayed. */
+static char *visible_line = (char *)NULL;
+static char *invisible_line = (char *)NULL;
+
+/* A buffer for `modeline' messages. */
+static char msg_buf[128];
+
+/* Non-zero forces the redisplay even if we thought it was unnecessary. */
+static int forced_display;
+
+/* Default and initial buffer size. Can grow. */
+static int line_size = 1024;
+
+static char *local_prompt, *local_prompt_prefix;
+static int visible_length, prefix_length;
+
+/* The number of invisible characters in the line currently being
+ displayed on the screen. */
+static int visible_wrap_offset;
+
+/* static so it can be shared between rl_redisplay and update_line */
+static int wrap_offset;
+
+/* The index of the last invisible_character in the prompt string. */
+static int last_invisible;
+
+/* The length (buffer offset) of the first line of the last (possibly
+ multi-line) buffer displayed on the screen. */
+static int visible_first_line_len;
+
+/* Expand the prompt string S and return the number of visible
+ characters in *LP, if LP is not null. This is currently more-or-less
+ a placeholder for expansion. LIP, if non-null is a place to store the
+ index of the last invisible character in ther eturned string. */
+
+/* Current implementation:
+ \001 (^A) start non-visible characters
+ \002 (^B) end non-visible characters
+ all characters except \001 and \002 (following a \001) are copied to
+ the returned string; all characters except those between \001 and
+ \002 are assumed to be `visible'. */
+
+static char *
+expand_prompt (pmt, lp, lip)
+ char *pmt;
+ int *lp, *lip;
+{
+ char *r, *ret, *p;
+ int l, rl, last, ignoring;
+
+ /* Short-circuit if we can. */
+ if (strchr (pmt, RL_PROMPT_START_IGNORE) == 0)
+ {
+ r = savestring (pmt);
+ if (lp)
+ *lp = strlen (r);
+ return r;
+ }
+
+ 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
+ RL_PROMPT_START_IGNORE and RL_PROMPT_END_IGNORE */
+ if (*p == RL_PROMPT_START_IGNORE)
+ {
+ ignoring++;
+ continue;
+ }
+ else if (ignoring && *p == RL_PROMPT_END_IGNORE)
+ {
+ ignoring = 0;
+ last = r - ret - 1;
+ continue;
+ }
+ else
+ {
+ *r++ = *p;
+ if (!ignoring)
+ rl++;
+ }
+ }
+
+ *r = '\0';
+ if (lp)
+ *lp = rl;
+ if (lip)
+ *lip = last;
+ return ret;
+}
+
+/*
+ * Expand the prompt string into the various display components, if
+ * necessary.
+ *
+ * local_prompt = expanded last line of string in rl_display_prompt
+ * (portion after the final newline)
+ * local_prompt_prefix = portion before last newline of rl_display_prompt,
+ * expanded via expand_prompt
+ * visible_length = number of visible characters in local_prompt
+ * prefix_length = number of visible characters in local_prompt_prefix
+ *
+ * This function is called once per call to readline(). It may also be
+ * called arbitrarily to expand the primary prompt.
+ *
+ * The return value is the number of visible characters on the last line
+ * of the (possibly multi-line) prompt.
+ */
+int
+rl_expand_prompt (prompt)
+ char *prompt;
+{
+ char *p, *t;
+ int c;
+
+ /* Clear out any saved values. */
+ if (local_prompt)
+ free (local_prompt);
+ if (local_prompt_prefix)
+ free (local_prompt_prefix);
+ local_prompt = local_prompt_prefix = (char *)0;
+ last_invisible = visible_length = 0;
+
+ if (prompt == 0 || *prompt == 0)
+ return (0);
+
+ p = strrchr (prompt, '\n');
+ if (!p)
+ {
+ /* The prompt is only one line. */
+ local_prompt = expand_prompt (prompt, &visible_length, &last_invisible);
+ local_prompt_prefix = (char *)0;
+ return (visible_length);
+ }
+ else
+ {
+ /* The prompt spans multiple lines. */
+ t = ++p;
+ local_prompt = expand_prompt (p, &visible_length, &last_invisible);
+ c = *t; *t = '\0';
+ /* The portion of the prompt string up to and including the
+ final newline is now null-terminated. */
+ local_prompt_prefix = expand_prompt (prompt, &prefix_length, (int *)NULL);
+ *t = c;
+ return (prefix_length);
+ }
+}
+
+/* Basic redisplay algorithm. */
+void
+rl_redisplay ()
+{
+ register int in, out, c, linenum, cursor_linenum;
+ register char *line;
+ int c_pos, inv_botlin, lb_botlin, lb_linenum;
+ int newlines, lpos, temp;
+ char *prompt_this_line;
+
+ if (!readline_echoing_p)
+ return;
+
+ if (!rl_display_prompt)
+ rl_display_prompt = "";
+
+ if (invisible_line == 0)
+ {
+ visible_line = xmalloc (line_size);
+ invisible_line = xmalloc (line_size);
+ for (in = 0; in < line_size; in++)
+ {
+ visible_line[in] = 0;
+ invisible_line[in] = 1;
+ }
+
+ /* should be enough, but then again, this is just for testing. */
+ inv_lbreaks = (int *)malloc (256 * sizeof (int));
+ vis_lbreaks = (int *)malloc (256 * sizeof (int));
+ inv_lbreaks[0] = vis_lbreaks[0] = 0;
+
+ rl_on_new_line ();
+ }
+
+ /* Draw the line into the buffer. */
+ c_pos = -1;
+
+ line = invisible_line;
+ out = inv_botlin = 0;
+
+ /* Mark the line as modified or not. We only do this for history
+ lines. */
+ if (_rl_mark_modified_lines && current_history () && rl_undo_list)
+ {
+ line[out++] = '*';
+ line[out] = '\0';
+ }
+
+ /* If someone thought that the redisplay was handled, but the currently
+ visible line has a different modification state than the one about
+ to become visible, then correct the caller's misconception. */
+ if (visible_line[0] != invisible_line[0])
+ rl_display_fixed = 0;
+
+ /* If the prompt to be displayed is the `primary' readline prompt (the
+ one passed to readline()), use the values we have already expanded.
+ If not, use what's already in rl_display_prompt. WRAP_OFFSET is the
+ number of non-visible characters in the prompt string. */
+ if (rl_display_prompt == rl_prompt || local_prompt)
+ {
+ int local_len = local_prompt ? strlen (local_prompt) : 0;
+ if (local_prompt_prefix && forced_display)
+ _rl_output_some_chars (local_prompt_prefix, strlen (local_prompt_prefix));
+
+ if (local_len > 0)
+ {
+ temp = local_len + out + 2;
+ if (temp >= line_size)
+ {
+ line_size = (temp + 1024) - (temp % 1024);
+ visible_line = xrealloc (visible_line, line_size);
+ line = invisible_line = xrealloc (invisible_line, line_size);
+ }
+ strncpy (line + out, local_prompt, local_len);
+ out += local_len;
+ }
+ line[out] = '\0';
+ wrap_offset = local_len - visible_length;
+ }
+ else
+ {
+ int pmtlen;
+ prompt_this_line = strrchr (rl_display_prompt, '\n');
+ if (!prompt_this_line)
+ prompt_this_line = rl_display_prompt;
+ else
+ {
+ prompt_this_line++;
+ if (forced_display)
+ {
+ _rl_output_some_chars (rl_display_prompt, prompt_this_line - rl_display_prompt);
+ /* Make sure we are at column zero even after a newline,
+ regardless of the state of terminal output processing. */
+ if (prompt_this_line[-2] != '\r')
+ cr ();
+ }
+ }
+
+ pmtlen = strlen (prompt_this_line);
+ temp = pmtlen + out + 2;
+ if (temp >= line_size)
+ {
+ line_size = (temp + 1024) - (temp % 1024);
+ visible_line = xrealloc (visible_line, line_size);
+ line = invisible_line = xrealloc (invisible_line, line_size);
+ }
+ strncpy (line + out, prompt_this_line, pmtlen);
+ out += pmtlen;
+ line[out] = '\0';
+ wrap_offset = 0;
+ }
+
+#define CHECK_LPOS() \
+ do { \
+ lpos++; \
+ if (lpos >= screenwidth) \
+ { \
+ inv_lbreaks[++newlines] = out; \
+ lpos = 0; \
+ } \
+ } while (0)
+
+ /* inv_lbreaks[i] is where line i starts in the buffer. */
+ inv_lbreaks[newlines = 0] = 0;
+ lpos = out - wrap_offset;
+
+ /* XXX - what if lpos is already >= screenwidth before we start drawing the
+ contents of the command line? */
+ while (lpos >= screenwidth)
+ {
+#if 0
+ temp = ((newlines + 1) * screenwidth) - ((newlines == 0) ? wrap_offset : 0);
+#else
+ /* XXX - possible fix from Darin Johnson <darin@acuson.com> for prompt
+ string with invisible characters that is longer than the screen
+ width. */
+ temp = ((newlines + 1) * screenwidth) + ((newlines == 0) ? wrap_offset : 0);
+#endif
+ inv_lbreaks[++newlines] = temp;
+ lpos -= screenwidth;
+ }
+
+ lb_linenum = 0;
+ for (in = 0; in < rl_end; in++)
+ {
+ c = (unsigned char)rl_line_buffer[in];
+
+ if (out + 8 >= line_size) /* XXX - 8 for \t */
+ {
+ line_size *= 2;
+ visible_line = xrealloc (visible_line, line_size);
+ invisible_line = xrealloc (invisible_line, line_size);
+ line = invisible_line;
+ }
+
+ if (in == rl_point)
+ {
+ c_pos = out;
+ lb_linenum = newlines;
+ }
+
+ if (META_CHAR (c))
+ {
+ if (_rl_output_meta_chars == 0)
+ {
+ sprintf (line + out, "\\%o", c);
+
+ if (lpos + 4 >= screenwidth)
+ {
+ temp = screenwidth - lpos;
+ inv_lbreaks[++newlines] = out + temp;
+ lpos = 4 - temp;
+ }
+ else
+ lpos += 4;
+
+ out += 4;
+ }
+ else
+ {
+ line[out++] = c;
+ CHECK_LPOS();
+ }
+ }
+#if defined (DISPLAY_TABS)
+ else if (c == '\t')
+ {
+ register int temp, newout;
+
+#if 0
+ newout = (out | (int)7) + 1;
+#else
+ newout = out + 8 - lpos % 8;
+#endif
+ temp = newout - out;
+ if (lpos + temp >= screenwidth)
+ {
+ register int temp2;
+ temp2 = screenwidth - lpos;
+ inv_lbreaks[++newlines] = out + temp2;
+ lpos = temp - temp2;
+ while (out < newout)
+ line[out++] = ' ';
+ }
+ else
+ {
+ while (out < newout)
+ line[out++] = ' ';
+ lpos += temp;
+ }
+ }
+#endif
+ else if (c == '\n' && _rl_horizontal_scroll_mode == 0 && term_up && *term_up)
+ {
+ line[out++] = '\0'; /* XXX - sentinel */
+ inv_lbreaks[++newlines] = out;
+ lpos = 0;
+ }
+ else if (CTRL_CHAR (c) || c == RUBOUT)
+ {
+ line[out++] = '^';
+ CHECK_LPOS();
+ line[out++] = CTRL_CHAR (c) ? UNCTRL (c) : '?';
+ CHECK_LPOS();
+ }
+ else
+ {
+ line[out++] = c;
+ CHECK_LPOS();
+ }
+ }
+ line[out] = '\0';
+ if (c_pos < 0)
+ {
+ c_pos = out;
+ lb_linenum = newlines;
+ }
+
+ inv_botlin = lb_botlin = newlines;
+ inv_lbreaks[newlines+1] = out;
+ cursor_linenum = lb_linenum;
+
+ /* C_POS == position in buffer where cursor should be placed. */
+
+ /* PWP: now is when things get a bit hairy. The visible and invisible
+ line buffers are really multiple lines, which would wrap every
+ (screenwidth - 1) characters. Go through each in turn, finding
+ the changed region and updating it. The line order is top to bottom. */
+
+ /* If we can move the cursor up and down, then use multiple lines,
+ otherwise, let long lines display in a single terminal line, and
+ horizontally scroll it. */
+
+ if (_rl_horizontal_scroll_mode == 0 && term_up && *term_up)
+ {
+ int nleft, pos, changed_screen_line;
+
+ if (!rl_display_fixed || forced_display)
+ {
+ forced_display = 0;
+
+ /* If we have more than a screenful of material to display, then
+ only display a screenful. We should display the last screen,
+ not the first. */
+ if (out >= screenchars)
+ out = screenchars - 1;
+
+ /* The first line is at character position 0 in the buffer. The
+ second and subsequent lines start at inv_lbreaks[N], offset by
+ OFFSET (which has already been calculated above). */
+
+#define W_OFFSET(line, offset) ((line) == 0 ? offset : 0)
+#define VIS_LLEN(l) ((l) > _rl_vis_botlin ? 0 : (vis_lbreaks[l+1] - vis_lbreaks[l]))
+#define INV_LLEN(l) (inv_lbreaks[l+1] - inv_lbreaks[l])
+#define VIS_CHARS(line) (visible_line + vis_lbreaks[line])
+#define VIS_LINE(line) ((line) > _rl_vis_botlin) ? "" : VIS_CHARS(line)
+#define INV_LINE(line) (invisible_line + inv_lbreaks[line])
+
+ /* For each line in the buffer, do the updating display. */
+ for (linenum = 0; linenum <= inv_botlin; linenum++)
+ {
+ update_line (VIS_LINE(linenum), INV_LINE(linenum), linenum,
+ VIS_LLEN(linenum), INV_LLEN(linenum), inv_botlin);
+
+ /* If this is the line with the prompt, we might need to
+ compensate for invisible characters in the new line. Do
+ this only if there is not more than one new line (which
+ implies that we completely overwrite the old visible line)
+ and the new line is shorter than the old. Make sure we are
+ at the end of the new line before clearing. */
+ if (linenum == 0 &&
+ inv_botlin == 0 && _rl_last_c_pos == out &&
+ (wrap_offset > visible_wrap_offset) &&
+ (_rl_last_c_pos < visible_first_line_len))
+ {
+ nleft = screenwidth + wrap_offset - _rl_last_c_pos;
+ if (nleft)
+ _rl_clear_to_eol (nleft);
+ }
+
+ /* Since the new first line is now visible, save its length. */
+ if (linenum == 0)
+ visible_first_line_len = (inv_botlin > 0) ? inv_lbreaks[1] : out - wrap_offset;
+ }
+
+ /* We may have deleted some lines. If so, clear the left over
+ blank ones at the bottom out. */
+ if (_rl_vis_botlin > inv_botlin)
+ {
+ char *tt;
+ for (; linenum <= _rl_vis_botlin; linenum++)
+ {
+ tt = VIS_CHARS (linenum);
+ _rl_move_vert (linenum);
+ _rl_move_cursor_relative (0, tt);
+ _rl_clear_to_eol
+ ((linenum == _rl_vis_botlin) ? strlen (tt) : screenwidth);
+ }
+ }
+ _rl_vis_botlin = inv_botlin;
+
+ /* CHANGED_SCREEN_LINE is set to 1 if we have moved to a
+ different screen line during this redisplay. */
+ changed_screen_line = _rl_last_v_pos != cursor_linenum;
+ if (changed_screen_line)
+ {
+ _rl_move_vert (cursor_linenum);
+ /* If we moved up to the line with the prompt using term_up,
+ the physical cursor position on the screen stays the same,
+ but the buffer position needs to be adjusted to account
+ for invisible characters. */
+ if (cursor_linenum == 0 && wrap_offset)
+ _rl_last_c_pos += wrap_offset;
+ }
+
+ /* We have to reprint the prompt if it contains invisible
+ characters, since it's not generally OK to just reprint
+ the characters from the current cursor position. But we
+ only need to reprint it if the cursor is before the last
+ invisible character in the prompt string. */
+ nleft = visible_length + wrap_offset;
+ if (cursor_linenum == 0 && wrap_offset > 0 && _rl_last_c_pos > 0 &&
+ _rl_last_c_pos <= last_invisible && local_prompt)
+ {
+ if (term_cr)
+ tputs (term_cr, 1, _rl_output_character_function);
+ _rl_output_some_chars (local_prompt, nleft);
+ _rl_last_c_pos = nleft;
+ }
+
+ /* Where on that line? And where does that line start
+ in the buffer? */
+ pos = inv_lbreaks[cursor_linenum];
+ /* nleft == number of characters in the line buffer between the
+ start of the line and the cursor position. */
+ nleft = c_pos - pos;
+
+ /* Since _rl_backspace() doesn't know about invisible characters in the
+ prompt, and there's no good way to tell it, we compensate for
+ those characters here and call _rl_backspace() directly. */
+ if (wrap_offset && cursor_linenum == 0 && nleft < _rl_last_c_pos)
+ {
+ _rl_backspace (_rl_last_c_pos - nleft);
+ _rl_last_c_pos = nleft;
+ }
+
+ if (nleft != _rl_last_c_pos)
+ _rl_move_cursor_relative (nleft, &invisible_line[pos]);
+ }
+ }
+ else /* Do horizontal scrolling. */
+ {
+#define M_OFFSET(margin, offset) ((margin) == 0 ? offset : 0)
+ int lmargin, ndisp, nleft, phys_c_pos, t;
+
+ /* Always at top line. */
+ _rl_last_v_pos = 0;
+
+ /* Compute where in the buffer the displayed line should start. This
+ will be LMARGIN. */
+
+ /* The number of characters that will be displayed before the cursor. */
+ ndisp = c_pos - wrap_offset;
+ nleft = visible_length + wrap_offset;
+ /* Where the new cursor position will be on the screen. This can be
+ longer than SCREENWIDTH; if it is, lmargin will be adjusted. */
+ phys_c_pos = c_pos - (last_lmargin ? last_lmargin : wrap_offset);
+ t = screenwidth / 3;
+
+ /* If the number of characters had already exceeded the screenwidth,
+ last_lmargin will be > 0. */
+
+ /* If the number of characters to be displayed is more than the screen
+ width, compute the starting offset so that the cursor is about
+ two-thirds of the way across the screen. */
+ if (phys_c_pos > screenwidth - 2)
+ {
+ lmargin = c_pos - (2 * t);
+ if (lmargin < 0)
+ lmargin = 0;
+ /* If the left margin would be in the middle of a prompt with
+ invisible characters, don't display the prompt at all. */
+ if (wrap_offset && lmargin > 0 && lmargin < nleft)
+ lmargin = nleft;
+ }
+ else if (ndisp < screenwidth - 2) /* XXX - was -1 */
+ lmargin = 0;
+ else if (phys_c_pos < 1)
+ {
+ /* If we are moving back towards the beginning of the line and
+ the last margin is no longer correct, compute a new one. */
+ lmargin = ((c_pos - 1) / t) * t; /* XXX */
+ if (wrap_offset && lmargin > 0 && lmargin < nleft)
+ lmargin = nleft;
+ }
+ else
+ lmargin = last_lmargin;
+
+ /* If the first character on the screen isn't the first character
+ in the display line, indicate this with a special character. */
+ if (lmargin > 0)
+ line[lmargin] = '<';
+
+ /* If SCREENWIDTH characters starting at LMARGIN do not encompass
+ the whole line, indicate that with a special character at the
+ right edge of the screen. If LMARGIN is 0, we need to take the
+ wrap offset into account. */
+ t = lmargin + M_OFFSET (lmargin, wrap_offset) + screenwidth;
+ if (t < out)
+ line[t - 1] = '>';
+
+ if (!rl_display_fixed || forced_display || lmargin != last_lmargin)
+ {
+ forced_display = 0;
+ update_line (&visible_line[last_lmargin],
+ &invisible_line[lmargin],
+ 0,
+ screenwidth + visible_wrap_offset,
+ screenwidth + (lmargin ? 0 : wrap_offset),
+ 0);
+
+ /* If the visible new line is shorter than the old, but the number
+ of invisible characters is greater, and we are at the end of
+ the new line, we need to clear to eol. */
+ t = _rl_last_c_pos - M_OFFSET (lmargin, wrap_offset);
+ if ((M_OFFSET (lmargin, wrap_offset) > visible_wrap_offset) &&
+ (_rl_last_c_pos == out) &&
+ t < visible_first_line_len)
+ {
+ nleft = screenwidth - t;
+ _rl_clear_to_eol (nleft);
+ }
+ visible_first_line_len = out - lmargin - M_OFFSET (lmargin, wrap_offset);
+ if (visible_first_line_len > screenwidth)
+ visible_first_line_len = screenwidth;
+
+ _rl_move_cursor_relative (c_pos - lmargin, &invisible_line[lmargin]);
+ last_lmargin = lmargin;
+ }
+ }
+ fflush (rl_outstream);
+
+ /* Swap visible and non-visible lines. */
+ {
+ char *temp = visible_line;
+ int *itemp = vis_lbreaks;
+ visible_line = invisible_line;
+ invisible_line = temp;
+ vis_lbreaks = inv_lbreaks;
+ inv_lbreaks = itemp;
+ rl_display_fixed = 0;
+ /* If we are displaying on a single line, and last_lmargin is > 0, we
+ are not displaying any invisible characters, so set visible_wrap_offset
+ to 0. */
+ if (_rl_horizontal_scroll_mode && last_lmargin)
+ visible_wrap_offset = 0;
+ else
+ visible_wrap_offset = wrap_offset;
+ }
+}
+
+/* PWP: update_line() is based on finding the middle difference of each
+ line on the screen; vis:
+
+ /old first difference
+ /beginning of line | /old last same /old EOL
+ v v v v
+old: eddie> Oh, my little gruntle-buggy is to me, as lurgid as
+new: eddie> Oh, my little buggy says to me, as lurgid as
+ ^ ^ ^ ^
+ \beginning of line | \new last same \new end of line
+ \new first difference
+
+ All are character pointers for the sake of speed. Special cases for
+ no differences, as well as for end of line additions must be handled.
+
+ Could be made even smarter, but this works well enough */
+static void
+update_line (old, new, current_line, omax, nmax, inv_botlin)
+ register char *old, *new;
+ int current_line, omax, nmax, inv_botlin;
+{
+ register char *ofd, *ols, *oe, *nfd, *nls, *ne;
+ int temp, lendiff, wsatend, od, nd;
+ int current_invis_chars;
+
+ /* If we're at the right edge of a terminal that supports xn, we're
+ ready to wrap around, so do so. This fixes problems with knowing
+ the exact cursor position and cut-and-paste with certain terminal
+ emulators. In this calculation, TEMP is the physical screen
+ position of the cursor. */
+ temp = _rl_last_c_pos - W_OFFSET(_rl_last_v_pos, visible_wrap_offset);
+ if (temp == screenwidth && _rl_term_autowrap && !_rl_horizontal_scroll_mode
+ && _rl_last_v_pos == current_line - 1)
+ {
+ if (new[0])
+ putc (new[0], rl_outstream);
+ else
+ putc (' ', rl_outstream);
+ _rl_last_c_pos = 1; /* XXX */
+ _rl_last_v_pos++;
+ if (old[0] && new[0])
+ old[0] = new[0];
+ }
+
+ /* Find first difference. */
+ for (ofd = old, nfd = new;
+ (ofd - old < omax) && *ofd && (*ofd == *nfd);
+ ofd++, nfd++)
+ ;
+
+ /* Move to the end of the screen line. ND and OD are used to keep track
+ of the distance between ne and new and oe and old, respectively, to
+ move a subtraction out of each loop. */
+ for (od = ofd - old, oe = ofd; od < omax && *oe; oe++, od++);
+ for (nd = nfd - new, ne = nfd; nd < nmax && *ne; ne++, nd++);
+
+ /* If no difference, continue to next line. */
+ if (ofd == oe && nfd == ne)
+ return;
+
+ wsatend = 1; /* flag for trailing whitespace */
+ ols = oe - 1; /* find last same */
+ nls = ne - 1;
+ while ((ols > ofd) && (nls > nfd) && (*ols == *nls))
+ {
+ if (*ols != ' ')
+ wsatend = 0;
+ ols--;
+ nls--;
+ }
+
+ if (wsatend)
+ {
+ ols = oe;
+ nls = ne;
+ }
+ else if (*ols != *nls)
+ {
+ if (*ols) /* don't step past the NUL */
+ ols++;
+ if (*nls)
+ nls++;
+ }
+
+ /* count of invisible characters in the current invisible line. */
+ current_invis_chars = W_OFFSET (current_line, wrap_offset);
+ if (_rl_last_v_pos != current_line)
+ {
+ _rl_move_vert (current_line);
+ if (current_line == 0 && visible_wrap_offset)
+ _rl_last_c_pos += visible_wrap_offset;
+ }
+
+ /* If this is the first line and there are invisible characters in the
+ prompt string, and the prompt string has not changed, and the current
+ cursor position is before the last invisible character in the prompt,
+ and the index of the character to move to is past the end of the prompt
+ string, then redraw the entire prompt string. We can only do this
+ reliably if the terminal supports a `cr' capability.
+
+ This is not an efficiency hack -- there is a problem with redrawing
+ portions of the prompt string if they contain terminal escape
+ sequences (like drawing the `unbold' sequence without a corresponding
+ `bold') that manifests itself on certain terminals. */
+
+ lendiff = local_prompt ? strlen (local_prompt) : 0;
+ od = ofd - old; /* index of first difference in visible line */
+ if (current_line == 0 && !_rl_horizontal_scroll_mode &&
+ term_cr && lendiff > visible_length && _rl_last_c_pos > 0 &&
+ od > lendiff && _rl_last_c_pos < last_invisible)
+ {
+ tputs (term_cr, 1, _rl_output_character_function);
+ _rl_output_some_chars (local_prompt, lendiff);
+ _rl_last_c_pos = lendiff;
+ }
+
+ _rl_move_cursor_relative (od, old);
+
+ /* if (len (new) > len (old)) */
+ lendiff = (nls - nfd) - (ols - ofd);
+
+ /* If we are changing the number of invisible characters in a line, and
+ the spot of first difference is before the end of the invisible chars,
+ lendiff needs to be adjusted. */
+ if (current_line == 0 && !_rl_horizontal_scroll_mode &&
+ current_invis_chars != visible_wrap_offset)
+ lendiff += visible_wrap_offset - current_invis_chars;
+
+ /* Insert (diff (len (old), len (new)) ch. */
+ temp = ne - nfd;
+ if (lendiff > 0)
+ {
+ /* Non-zero if we're increasing the number of lines. */
+ int gl = current_line >= _rl_vis_botlin && inv_botlin > _rl_vis_botlin;
+ /* Sometimes it is cheaper to print the characters rather than
+ use the terminal's capabilities. If we're growing the number
+ of lines, make sure we actually cause the new line to wrap
+ around on auto-wrapping terminals. */
+ if (terminal_can_insert && ((2 * temp) >= lendiff || term_IC) && (!_rl_term_autowrap || !gl))
+ {
+ /* If lendiff > visible_length and _rl_last_c_pos == 0 and
+ _rl_horizontal_scroll_mode == 1, inserting the characters with
+ term_IC or term_ic will screw up the screen because of the
+ invisible characters. We need to just draw them. */
+ if (*ols && (!_rl_horizontal_scroll_mode || _rl_last_c_pos > 0 ||
+ lendiff <= visible_length || !current_invis_chars))
+ {
+ insert_some_chars (nfd, lendiff);
+ _rl_last_c_pos += lendiff;
+ }
+ else if (*ols == 0)
+ {
+ /* At the end of a line the characters do not have to
+ be "inserted". They can just be placed on the screen. */
+ /* However, this screws up the rest of this block, which
+ assumes you've done the insert because you can. */
+ _rl_output_some_chars (nfd, lendiff);
+ _rl_last_c_pos += lendiff;
+ }
+ else
+ {
+ /* We have horizontal scrolling and we are not inserting at
+ the end. We have invisible characters in this line. This
+ is a dumb update. */
+ _rl_output_some_chars (nfd, temp);
+ _rl_last_c_pos += temp;
+ return;
+ }
+ /* Copy (new) chars to screen from first diff to last match. */
+ temp = nls - nfd;
+ if ((temp - lendiff) > 0)
+ {
+ _rl_output_some_chars (nfd + lendiff, temp - lendiff);
+ _rl_last_c_pos += temp - lendiff;
+ }
+ }
+ else
+ {
+ /* cannot insert chars, write to EOL */
+ _rl_output_some_chars (nfd, temp);
+ _rl_last_c_pos += temp;
+ }
+ }
+ else /* Delete characters from line. */
+ {
+ /* If possible and inexpensive to use terminal deletion, then do so. */
+ if (term_dc && (2 * temp) >= -lendiff)
+ {
+ /* If all we're doing is erasing the invisible characters in the
+ prompt string, don't bother. It screws up the assumptions
+ about what's on the screen. */
+ if (_rl_horizontal_scroll_mode && _rl_last_c_pos == 0 &&
+ -lendiff == visible_wrap_offset)
+ lendiff = 0;
+
+ if (lendiff)
+ delete_chars (-lendiff); /* delete (diff) characters */
+
+ /* Copy (new) chars to screen from first diff to last match */
+ temp = nls - nfd;
+ if (temp > 0)
+ {
+ _rl_output_some_chars (nfd, temp);
+ _rl_last_c_pos += temp;
+ }
+ }
+ /* Otherwise, print over the existing material. */
+ else
+ {
+ if (temp > 0)
+ {
+ _rl_output_some_chars (nfd, temp);
+ _rl_last_c_pos += temp;
+ }
+ lendiff = (oe - old) - (ne - new);
+ if (lendiff)
+ {
+ if (_rl_term_autowrap && current_line < inv_botlin)
+ space_to_eol (lendiff);
+ else
+ _rl_clear_to_eol (lendiff);
+ }
+ }
+ }
+}
+
+/* Tell the update routines that we have moved onto a new (empty) line. */
+int
+rl_on_new_line ()
+{
+ if (visible_line)
+ visible_line[0] = '\0';
+
+ _rl_last_c_pos = _rl_last_v_pos = 0;
+ _rl_vis_botlin = last_lmargin = 0;
+ if (vis_lbreaks)
+ vis_lbreaks[0] = vis_lbreaks[1] = 0;
+ visible_wrap_offset = 0;
+ return 0;
+}
+
+/* Actually update the display, period. */
+int
+rl_forced_update_display ()
+{
+ if (visible_line)
+ {
+ register char *temp = visible_line;
+
+ while (*temp)
+ *temp++ = '\0';
+ }
+ rl_on_new_line ();
+ forced_display++;
+ (*rl_redisplay_function) ();
+ return 0;
+}
+
+/* Move the cursor from _rl_last_c_pos to NEW, which are buffer indices.
+ DATA is the contents of the screen line of interest; i.e., where
+ the movement is being done. */
+void
+_rl_move_cursor_relative (new, data)
+ int new;
+ char *data;
+{
+ register int i;
+
+ /* If we don't have to do anything, then return. */
+ if (_rl_last_c_pos == new) return;
+
+ /* It may be faster to output a CR, and then move forwards instead
+ of moving backwards. */
+ /* i == current physical cursor position. */
+ i = _rl_last_c_pos - W_OFFSET(_rl_last_v_pos, visible_wrap_offset);
+ if (new == 0 || CR_FASTER (new, _rl_last_c_pos) ||
+ (_rl_term_autowrap && i == screenwidth))
+ {
+#if defined (__MSDOS__)
+ putc ('\r', rl_outstream);
+#else
+ tputs (term_cr, 1, _rl_output_character_function);
+#endif /* !__MSDOS__ */
+ _rl_last_c_pos = 0;
+ }
+
+ if (_rl_last_c_pos < new)
+ {
+ /* Move the cursor forward. We do it by printing the command
+ to move the cursor forward if there is one, else print that
+ portion of the output buffer again. Which is cheaper? */
+
+ /* The above comment is left here for posterity. It is faster
+ to print one character (non-control) than to print a control
+ sequence telling the terminal to move forward one character.
+ That kind of control is for people who don't know what the
+ data is underneath the cursor. */
+#if defined (HACK_TERMCAP_MOTION)
+ extern char *term_forward_char;
+
+ if (term_forward_char)
+ for (i = _rl_last_c_pos; i < new; i++)
+ tputs (term_forward_char, 1, _rl_output_character_function);
+ else
+ for (i = _rl_last_c_pos; i < new; i++)
+ putc (data[i], rl_outstream);
+#else
+ for (i = _rl_last_c_pos; i < new; i++)
+ putc (data[i], rl_outstream);
+#endif /* HACK_TERMCAP_MOTION */
+ }
+ else if (_rl_last_c_pos > new)
+ _rl_backspace (_rl_last_c_pos - new);
+ _rl_last_c_pos = new;
+}
+
+/* PWP: move the cursor up or down. */
+void
+_rl_move_vert (to)
+ int to;
+{
+ register int delta, i;
+
+ if (_rl_last_v_pos == to || to > screenheight)
+ return;
+
+#if defined (__GO32__)
+ {
+ int row, col;
+
+ ScreenGetCursor (&row, &col);
+ ScreenSetCursor ((row + to - _rl_last_v_pos), col);
+ }
+#else /* !__GO32__ */
+
+ if ((delta = to - _rl_last_v_pos) > 0)
+ {
+ for (i = 0; i < delta; i++)
+ putc ('\n', rl_outstream);
+ tputs (term_cr, 1, _rl_output_character_function);
+ _rl_last_c_pos = 0;
+ }
+ else
+ { /* delta < 0 */
+ if (term_up && *term_up)
+ for (i = 0; i < -delta; i++)
+ tputs (term_up, 1, _rl_output_character_function);
+ }
+#endif /* !__GO32__ */
+ _rl_last_v_pos = to; /* Now TO is here */
+}
+
+/* Physically print C on rl_outstream. This is for functions which know
+ how to optimize the display. Return the number of characters output. */
+int
+rl_show_char (c)
+ int c;
+{
+ int n = 1;
+ if (META_CHAR (c) && (_rl_output_meta_chars == 0))
+ {
+ fprintf (rl_outstream, "M-");
+ n += 2;
+ c = UNMETA (c);
+ }
+
+#if defined (DISPLAY_TABS)
+ if ((CTRL_CHAR (c) && c != '\t') || c == RUBOUT)
+#else
+ if (CTRL_CHAR (c) || c == RUBOUT)
+#endif /* !DISPLAY_TABS */
+ {
+ fprintf (rl_outstream, "C-");
+ n += 2;
+ c = CTRL_CHAR (c) ? UNCTRL (c) : '?';
+ }
+
+ putc (c, rl_outstream);
+ fflush (rl_outstream);
+ return n;
+}
+
+int
+rl_character_len (c, pos)
+ register int c, pos;
+{
+ unsigned char uc;
+
+ uc = (unsigned char)c;
+
+ if (META_CHAR (uc))
+ return ((_rl_output_meta_chars == 0) ? 4 : 1);
+
+ if (uc == '\t')
+ {
+#if defined (DISPLAY_TABS)
+ return (((pos | 7) + 1) - pos);
+#else
+ return (2);
+#endif /* !DISPLAY_TABS */
+ }
+
+ if (CTRL_CHAR (c) || c == RUBOUT)
+ return (2);
+
+ return ((isprint (uc)) ? 1 : 2);
+}
+
+/* How to print things in the "echo-area". The prompt is treated as a
+ mini-modeline. */
+
+#if defined (USE_VARARGS)
+int
+#if defined (PREFER_STDARG)
+rl_message (const char *format, ...)
+#else
+rl_message (va_alist)
+ va_dcl
+#endif
+{
+ va_list args;
+#if defined (PREFER_VARARGS)
+ char *format;
+#endif
+
+#if defined (PREFER_STDARG)
+ va_start (args, format);
+#else
+ va_start (args);
+ format = va_arg (args, char *);
+#endif
+
+ vsprintf (msg_buf, format, args);
+ va_end (args);
+
+ rl_display_prompt = msg_buf;
+ (*rl_redisplay_function) ();
+ return 0;
+}
+#else /* !USE_VARARGS */
+int
+rl_message (format, arg1, arg2)
+ char *format;
+{
+ sprintf (msg_buf, format, arg1, arg2);
+ rl_display_prompt = msg_buf;
+ (*rl_redisplay_function) ();
+ return 0;
+}
+#endif /* !USE_VARARGS */
+
+/* How to clear things from the "echo-area". */
+int
+rl_clear_message ()
+{
+ rl_display_prompt = rl_prompt;
+ (*rl_redisplay_function) ();
+ return 0;
+}
+
+int
+rl_reset_line_state ()
+{
+ rl_on_new_line ();
+
+ rl_display_prompt = rl_prompt ? rl_prompt : "";
+ forced_display = 1;
+ return 0;
+}
+
+static char *saved_local_prompt;
+static char *saved_local_prefix;
+static int saved_last_invisible;
+static int saved_visible_length;
+
+void
+rl_save_prompt ()
+{
+ saved_local_prompt = local_prompt;
+ saved_local_prefix = local_prompt_prefix;
+ saved_last_invisible = last_invisible;
+ saved_visible_length = visible_length;
+
+ local_prompt = local_prompt_prefix = (char *)0;
+ last_invisible = visible_length = 0;
+}
+
+void
+rl_restore_prompt ()
+{
+ if (local_prompt)
+ free (local_prompt);
+ if (local_prompt_prefix)
+ free (local_prompt_prefix);
+
+ local_prompt = saved_local_prompt;
+ local_prompt_prefix = saved_local_prefix;
+ last_invisible = saved_last_invisible;
+ visible_length = saved_visible_length;
+}
+
+char *
+_rl_make_prompt_for_search (pchar)
+ int pchar;
+{
+ int len;
+ char *pmt;
+
+ rl_save_prompt ();
+
+ if (saved_local_prompt == 0)
+ {
+ len = (rl_prompt && *rl_prompt) ? strlen (rl_prompt) : 0;
+ pmt = xmalloc (len + 2);
+ if (len)
+ strcpy (pmt, rl_prompt);
+ pmt[len] = pchar;
+ pmt[len+1] = '\0';
+ }
+ else
+ {
+ len = *saved_local_prompt ? strlen (saved_local_prompt) : 0;
+ pmt = xmalloc (len + 2);
+ if (len)
+ strcpy (pmt, saved_local_prompt);
+ pmt[len] = pchar;
+ pmt[len+1] = '\0';
+ local_prompt = savestring (pmt);
+ last_invisible = saved_last_invisible;
+ visible_length = saved_visible_length + 1;
+ }
+ return pmt;
+}
+
+/* Quick redisplay hack when erasing characters at the end of the line. */
+void
+_rl_erase_at_end_of_line (l)
+ int l;
+{
+ register int i;
+
+ _rl_backspace (l);
+ for (i = 0; i < l; i++)
+ putc (' ', rl_outstream);
+ _rl_backspace (l);
+ for (i = 0; i < l; i++)
+ visible_line[--_rl_last_c_pos] = '\0';
+ rl_display_fixed++;
+}
+
+/* Clear to the end of the line. COUNT is the minimum
+ number of character spaces to clear, */
+void
+_rl_clear_to_eol (count)
+ int count;
+{
+#if !defined (__GO32__)
+ if (term_clreol)
+ tputs (term_clreol, 1, _rl_output_character_function);
+ else if (count)
+#endif /* !__GO32__ */
+ space_to_eol (count);
+}
+
+/* Clear to the end of the line using spaces. COUNT is the minimum
+ number of character spaces to clear, */
+static void
+space_to_eol (count)
+ int count;
+{
+ register int i;
+
+ for (i = 0; i < count; i++)
+ putc (' ', rl_outstream);
+
+ _rl_last_c_pos += count;
+}
+
+void
+_rl_clear_screen ()
+{
+#if !defined (__GO32__)
+ if (term_clrpag)
+ tputs (term_clrpag, 1, _rl_output_character_function);
+ else
+#endif /* !__GO32__ */
+ crlf ();
+}
+
+/* Insert COUNT characters from STRING to the output stream. */
+static void
+insert_some_chars (string, count)
+ char *string;
+ int count;
+{
+#if defined (__GO32__)
+ int row, col, width;
+ char *row_start;
+
+ ScreenGetCursor (&row, &col);
+ width = ScreenCols ();
+ row_start = ScreenPrimary + (row * width);
+
+ memcpy (row_start + col + count, row_start + col, width - col - count);
+
+ /* Place the text on the screen. */
+ _rl_output_some_chars (string, count);
+#else /* !_GO32 */
+
+ /* If IC is defined, then we do not have to "enter" insert mode. */
+ if (term_IC)
+ {
+ char *buffer;
+ buffer = tgoto (term_IC, 0, count);
+ tputs (buffer, 1, _rl_output_character_function);
+ _rl_output_some_chars (string, count);
+ }
+ else
+ {
+ register int i;
+
+ /* If we have to turn on insert-mode, then do so. */
+ if (term_im && *term_im)
+ tputs (term_im, 1, _rl_output_character_function);
+
+ /* If there is a special command for inserting characters, then
+ use that first to open up the space. */
+ if (term_ic && *term_ic)
+ {
+ for (i = count; i--; )
+ tputs (term_ic, 1, _rl_output_character_function);
+ }
+
+ /* Print the text. */
+ _rl_output_some_chars (string, count);
+
+ /* If there is a string to turn off insert mode, we had best use
+ it now. */
+ if (term_ei && *term_ei)
+ tputs (term_ei, 1, _rl_output_character_function);
+ }
+#endif /* !__GO32__ */
+}
+
+/* Delete COUNT characters from the display line. */
+static void
+delete_chars (count)
+ int count;
+{
+#if defined (__GO32__)
+ int row, col, width;
+ char *row_start;
+
+ ScreenGetCursor (&row, &col);
+ width = ScreenCols ();
+ row_start = ScreenPrimary + (row * width);
+
+ memcpy (row_start + col, row_start + col + count, width - col - count);
+ memset (row_start + width - count, 0, count * 2);
+#else /* !_GO32 */
+
+ if (count > screenwidth) /* XXX */
+ return;
+
+ if (term_DC && *term_DC)
+ {
+ char *buffer;
+ buffer = tgoto (term_DC, count, count);
+ tputs (buffer, count, _rl_output_character_function);
+ }
+ else
+ {
+ if (term_dc && *term_dc)
+ while (count--)
+ tputs (term_dc, 1, _rl_output_character_function);
+ }
+#endif /* !__GO32__ */
+}
+
+void
+_rl_update_final ()
+{
+ int full_lines;
+
+ full_lines = 0;
+ /* If the cursor is the only thing on an otherwise-blank last line,
+ compensate so we don't print an extra CRLF. */
+ if (_rl_vis_botlin && _rl_last_c_pos == 0 &&
+ visible_line[vis_lbreaks[_rl_vis_botlin]] == 0)
+ {
+ _rl_vis_botlin--;
+ full_lines = 1;
+ }
+ _rl_move_vert (_rl_vis_botlin);
+ /* If we've wrapped lines, remove the final xterm line-wrap flag. */
+ if (full_lines && _rl_term_autowrap && (VIS_LLEN(_rl_vis_botlin) == screenwidth))
+ {
+ char *last_line;
+ last_line = &visible_line[inv_lbreaks[_rl_vis_botlin]];
+ _rl_move_cursor_relative (screenwidth - 1, last_line);
+ _rl_clear_to_eol (0);
+ putc (last_line[screenwidth - 1], rl_outstream);
+ }
+ _rl_vis_botlin = 0;
+ crlf ();
+ fflush (rl_outstream);
+ rl_display_fixed++;
+}
+
+/* Move to the start of the current line. */
+static void
+cr ()
+{
+ if (term_cr)
+ {
+ tputs (term_cr, 1, _rl_output_character_function);
+ _rl_last_c_pos = 0;
+ }
+}
+
+/* Redisplay the current line after a SIGWINCH is received. */
+void
+_rl_redisplay_after_sigwinch ()
+{
+ char *t, *oldp, *oldl, *oldlprefix;
+
+ /* 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. */
+ if (term_cr)
+ {
+ tputs (term_cr, 1, _rl_output_character_function);
+ _rl_last_c_pos = 0;
+ if (term_clreol)
+ tputs (term_clreol, 1, _rl_output_character_function);
+ else
+ {
+ space_to_eol (screenwidth);
+ tputs (term_cr, 1, _rl_output_character_function);
+ }
+ if (_rl_last_v_pos > 0)
+ _rl_move_vert (0);
+ }
+ else
+ crlf ();
+
+ /* Redraw only the last line of a multi-line prompt. */
+ t = strrchr (rl_display_prompt, '\n');
+ if (t)
+ {
+ oldp = rl_display_prompt;
+ oldl = local_prompt;
+ oldlprefix = local_prompt_prefix;
+ rl_display_prompt = ++t;
+ local_prompt = local_prompt_prefix = (char *)NULL;
+ rl_forced_update_display ();
+ rl_display_prompt = oldp;
+ local_prompt = oldl;
+ local_prompt_prefix = oldlprefix;
+ }
+ else
+ rl_forced_update_display ();
+}
+
+void
+_rl_clean_up_for_exit ()
+{
+ if (readline_echoing_p)
+ {
+ _rl_move_vert (_rl_vis_botlin);
+ _rl_vis_botlin = 0;
+ fflush (rl_outstream);
+ rl_restart_output (1, 0);
+ }
+}
+
+void
+_rl_erase_entire_line ()
+{
+ cr ();
+ _rl_clear_to_eol (0);
+ cr ();
+ fflush (rl_outstream);
+}
diff --git a/readline/emacs_keymap.c b/readline/emacs_keymap.c
new file mode 100644
index 00000000000..4ba385843f6
--- /dev/null
+++ b/readline/emacs_keymap.c
@@ -0,0 +1,885 @@
+/* emacs_keymap.c -- the keymap for emacs_mode in readline (). */
+
+/* Copyright (C) 1987, 1989, 1992 Free Software Foundation, Inc.
+
+ This file is part of the GNU Readline Library, a library for
+ reading lines of text with interactive input and history editing.
+
+ The GNU Readline Library is free software; you can redistribute it
+ and/or modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 1, or
+ (at your option) any later version.
+
+ The GNU Readline 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 General Public License for more details.
+
+ The GNU General Public License is often shipped with GNU software, and
+ is generally kept in a file called COPYING or LICENSE. If you do not
+ have a copy of the license, write to the Free Software Foundation,
+ 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#if !defined (BUFSIZ)
+#include <stdio.h>
+#endif /* !BUFSIZ */
+
+#include "readline.h"
+
+/* An array of function pointers, one for each possible key.
+ If the type byte is ISKMAP, then the pointer is the address of
+ a keymap. */
+
+KEYMAP_ENTRY_ARRAY emacs_standard_keymap = {
+
+ /* Control keys. */
+ { ISFUNC, rl_set_mark }, /* Control-@ */
+ { ISFUNC, rl_beg_of_line }, /* Control-a */
+ { ISFUNC, rl_backward }, /* Control-b */
+ { ISFUNC, (Function *)0x0 }, /* Control-c */
+ { ISFUNC, rl_delete }, /* Control-d */
+ { ISFUNC, rl_end_of_line }, /* Control-e */
+ { ISFUNC, rl_forward }, /* Control-f */
+ { ISFUNC, rl_abort }, /* Control-g */
+ { ISFUNC, rl_rubout }, /* Control-h */
+ { ISFUNC, rl_complete }, /* Control-i */
+ { ISFUNC, rl_newline }, /* Control-j */
+ { ISFUNC, rl_kill_line }, /* Control-k */
+ { ISFUNC, rl_clear_screen }, /* Control-l */
+ { ISFUNC, rl_newline }, /* Control-m */
+ { ISFUNC, rl_get_next_history }, /* Control-n */
+ { ISFUNC, (Function *)0x0 }, /* Control-o */
+ { ISFUNC, rl_get_previous_history }, /* Control-p */
+ { ISFUNC, rl_quoted_insert }, /* Control-q */
+ { ISFUNC, rl_reverse_search_history }, /* Control-r */
+ { ISFUNC, rl_forward_search_history }, /* Control-s */
+ { ISFUNC, rl_transpose_chars }, /* Control-t */
+ { ISFUNC, rl_unix_line_discard }, /* Control-u */
+ { ISFUNC, rl_quoted_insert }, /* Control-v */
+ { ISFUNC, rl_unix_word_rubout }, /* Control-w */
+ { ISKMAP, (Function *)emacs_ctlx_keymap }, /* Control-x */
+ { ISFUNC, rl_yank }, /* Control-y */
+ { ISFUNC, (Function *)0x0 }, /* Control-z */
+ { ISKMAP, (Function *)emacs_meta_keymap }, /* Control-[ */
+ { ISFUNC, (Function *)0x0 }, /* Control-\ */
+ { ISFUNC, rl_char_search }, /* Control-] */
+ { ISFUNC, (Function *)0x0 }, /* Control-^ */
+ { ISFUNC, rl_undo_command }, /* Control-_ */
+
+ /* The start of printing characters. */
+ { ISFUNC, rl_insert }, /* SPACE */
+ { ISFUNC, rl_insert }, /* ! */
+ { ISFUNC, rl_insert }, /* " */
+ { ISFUNC, rl_insert }, /* # */
+ { ISFUNC, rl_insert }, /* $ */
+ { ISFUNC, rl_insert }, /* % */
+ { ISFUNC, rl_insert }, /* & */
+ { ISFUNC, rl_insert }, /* ' */
+ { ISFUNC, rl_insert }, /* ( */
+#if defined (PAREN_MATCHING)
+ { ISFUNC, rl_insert_close }, /* ) */
+#else
+ { ISFUNC, rl_insert }, /* ) */
+#endif /* !PAREN_MATCHING */
+ { ISFUNC, rl_insert }, /* * */
+ { ISFUNC, rl_insert }, /* + */
+ { ISFUNC, rl_insert }, /* , */
+ { ISFUNC, rl_insert }, /* - */
+ { ISFUNC, rl_insert }, /* . */
+ { ISFUNC, rl_insert }, /* / */
+
+ /* Regular digits. */
+ { ISFUNC, rl_insert }, /* 0 */
+ { ISFUNC, rl_insert }, /* 1 */
+ { ISFUNC, rl_insert }, /* 2 */
+ { ISFUNC, rl_insert }, /* 3 */
+ { ISFUNC, rl_insert }, /* 4 */
+ { ISFUNC, rl_insert }, /* 5 */
+ { ISFUNC, rl_insert }, /* 6 */
+ { ISFUNC, rl_insert }, /* 7 */
+ { ISFUNC, rl_insert }, /* 8 */
+ { ISFUNC, rl_insert }, /* 9 */
+
+ /* A little more punctuation. */
+ { ISFUNC, rl_insert }, /* : */
+ { ISFUNC, rl_insert }, /* ; */
+ { ISFUNC, rl_insert }, /* < */
+ { ISFUNC, rl_insert }, /* = */
+ { ISFUNC, rl_insert }, /* > */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* @ */
+
+ /* Uppercase alphabet. */
+ { ISFUNC, rl_insert }, /* A */
+ { ISFUNC, rl_insert }, /* B */
+ { ISFUNC, rl_insert }, /* C */
+ { ISFUNC, rl_insert }, /* D */
+ { ISFUNC, rl_insert }, /* E */
+ { ISFUNC, rl_insert }, /* F */
+ { ISFUNC, rl_insert }, /* G */
+ { ISFUNC, rl_insert }, /* H */
+ { ISFUNC, rl_insert }, /* I */
+ { ISFUNC, rl_insert }, /* J */
+ { ISFUNC, rl_insert }, /* K */
+ { ISFUNC, rl_insert }, /* L */
+ { ISFUNC, rl_insert }, /* M */
+ { ISFUNC, rl_insert }, /* N */
+ { ISFUNC, rl_insert }, /* O */
+ { ISFUNC, rl_insert }, /* P */
+ { ISFUNC, rl_insert }, /* Q */
+ { ISFUNC, rl_insert }, /* R */
+ { ISFUNC, rl_insert }, /* S */
+ { ISFUNC, rl_insert }, /* T */
+ { ISFUNC, rl_insert }, /* U */
+ { ISFUNC, rl_insert }, /* V */
+ { ISFUNC, rl_insert }, /* W */
+ { ISFUNC, rl_insert }, /* X */
+ { ISFUNC, rl_insert }, /* Y */
+ { ISFUNC, rl_insert }, /* Z */
+
+ /* Some more punctuation. */
+ { ISFUNC, rl_insert }, /* [ */
+ { ISFUNC, rl_insert }, /* \ */
+#if defined (PAREN_MATCHING)
+ { ISFUNC, rl_insert_close }, /* ] */
+#else
+ { ISFUNC, rl_insert }, /* ] */
+#endif /* !PAREN_MATCHING */
+ { ISFUNC, rl_insert }, /* ^ */
+ { ISFUNC, rl_insert }, /* _ */
+ { ISFUNC, rl_insert }, /* ` */
+
+ /* Lowercase alphabet. */
+ { ISFUNC, rl_insert }, /* a */
+ { ISFUNC, rl_insert }, /* b */
+ { ISFUNC, rl_insert }, /* c */
+ { ISFUNC, rl_insert }, /* d */
+ { ISFUNC, rl_insert }, /* e */
+ { ISFUNC, rl_insert }, /* f */
+ { ISFUNC, rl_insert }, /* g */
+ { ISFUNC, rl_insert }, /* h */
+ { ISFUNC, rl_insert }, /* i */
+ { ISFUNC, rl_insert }, /* j */
+ { ISFUNC, rl_insert }, /* k */
+ { ISFUNC, rl_insert }, /* l */
+ { ISFUNC, rl_insert }, /* m */
+ { ISFUNC, rl_insert }, /* n */
+ { ISFUNC, rl_insert }, /* o */
+ { ISFUNC, rl_insert }, /* p */
+ { ISFUNC, rl_insert }, /* q */
+ { ISFUNC, rl_insert }, /* r */
+ { ISFUNC, rl_insert }, /* s */
+ { ISFUNC, rl_insert }, /* t */
+ { ISFUNC, rl_insert }, /* u */
+ { ISFUNC, rl_insert }, /* v */
+ { ISFUNC, rl_insert }, /* w */
+ { ISFUNC, rl_insert }, /* x */
+ { ISFUNC, rl_insert }, /* y */
+ { ISFUNC, rl_insert }, /* z */
+
+ /* Final punctuation. */
+ { ISFUNC, rl_insert }, /* { */
+ { ISFUNC, rl_insert }, /* | */
+#if defined (PAREN_MATCHING)
+ { ISFUNC, rl_insert_close }, /* } */
+#else
+ { ISFUNC, rl_insert }, /* } */
+#endif /* !PAREN_MATCHING */
+ { ISFUNC, rl_insert }, /* ~ */
+ { ISFUNC, rl_rubout }, /* RUBOUT */
+
+#if KEYMAP_SIZE > 128
+ /* Pure 8-bit characters (128 - 159).
+ These might be used in some
+ character sets. */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+
+ /* ISO Latin-1 characters (160 - 255) */
+ { ISFUNC, rl_insert }, /* No-break space */
+ { ISFUNC, rl_insert }, /* Inverted exclamation mark */
+ { ISFUNC, rl_insert }, /* Cent sign */
+ { ISFUNC, rl_insert }, /* Pound sign */
+ { ISFUNC, rl_insert }, /* Currency sign */
+ { ISFUNC, rl_insert }, /* Yen sign */
+ { ISFUNC, rl_insert }, /* Broken bar */
+ { ISFUNC, rl_insert }, /* Section sign */
+ { ISFUNC, rl_insert }, /* Diaeresis */
+ { ISFUNC, rl_insert }, /* Copyright sign */
+ { ISFUNC, rl_insert }, /* Feminine ordinal indicator */
+ { ISFUNC, rl_insert }, /* Left pointing double angle quotation mark */
+ { ISFUNC, rl_insert }, /* Not sign */
+ { ISFUNC, rl_insert }, /* Soft hyphen */
+ { ISFUNC, rl_insert }, /* Registered sign */
+ { ISFUNC, rl_insert }, /* Macron */
+ { ISFUNC, rl_insert }, /* Degree sign */
+ { ISFUNC, rl_insert }, /* Plus-minus sign */
+ { ISFUNC, rl_insert }, /* Superscript two */
+ { ISFUNC, rl_insert }, /* Superscript three */
+ { ISFUNC, rl_insert }, /* Acute accent */
+ { ISFUNC, rl_insert }, /* Micro sign */
+ { ISFUNC, rl_insert }, /* Pilcrow sign */
+ { ISFUNC, rl_insert }, /* Middle dot */
+ { ISFUNC, rl_insert }, /* Cedilla */
+ { ISFUNC, rl_insert }, /* Superscript one */
+ { ISFUNC, rl_insert }, /* Masculine ordinal indicator */
+ { ISFUNC, rl_insert }, /* Right pointing double angle quotation mark */
+ { ISFUNC, rl_insert }, /* Vulgar fraction one quarter */
+ { ISFUNC, rl_insert }, /* Vulgar fraction one half */
+ { ISFUNC, rl_insert }, /* Vulgar fraction three quarters */
+ { ISFUNC, rl_insert }, /* Inverted questionk mark */
+ { ISFUNC, rl_insert }, /* Latin capital letter a with grave */
+ { ISFUNC, rl_insert }, /* Latin capital letter a with acute */
+ { ISFUNC, rl_insert }, /* Latin capital letter a with circumflex */
+ { ISFUNC, rl_insert }, /* Latin capital letter a with tilde */
+ { ISFUNC, rl_insert }, /* Latin capital letter a with diaeresis */
+ { ISFUNC, rl_insert }, /* Latin capital letter a with ring above */
+ { ISFUNC, rl_insert }, /* Latin capital letter ae */
+ { ISFUNC, rl_insert }, /* Latin capital letter c with cedilla */
+ { ISFUNC, rl_insert }, /* Latin capital letter e with grave */
+ { ISFUNC, rl_insert }, /* Latin capital letter e with acute */
+ { ISFUNC, rl_insert }, /* Latin capital letter e with circumflex */
+ { ISFUNC, rl_insert }, /* Latin capital letter e with diaeresis */
+ { ISFUNC, rl_insert }, /* Latin capital letter i with grave */
+ { ISFUNC, rl_insert }, /* Latin capital letter i with acute */
+ { ISFUNC, rl_insert }, /* Latin capital letter i with circumflex */
+ { ISFUNC, rl_insert }, /* Latin capital letter i with diaeresis */
+ { ISFUNC, rl_insert }, /* Latin capital letter eth (Icelandic) */
+ { ISFUNC, rl_insert }, /* Latin capital letter n with tilde */
+ { ISFUNC, rl_insert }, /* Latin capital letter o with grave */
+ { ISFUNC, rl_insert }, /* Latin capital letter o with acute */
+ { ISFUNC, rl_insert }, /* Latin capital letter o with circumflex */
+ { ISFUNC, rl_insert }, /* Latin capital letter o with tilde */
+ { ISFUNC, rl_insert }, /* Latin capital letter o with diaeresis */
+ { ISFUNC, rl_insert }, /* Multiplication sign */
+ { ISFUNC, rl_insert }, /* Latin capital letter o with stroke */
+ { ISFUNC, rl_insert }, /* Latin capital letter u with grave */
+ { ISFUNC, rl_insert }, /* Latin capital letter u with acute */
+ { ISFUNC, rl_insert }, /* Latin capital letter u with circumflex */
+ { ISFUNC, rl_insert }, /* Latin capital letter u with diaeresis */
+ { ISFUNC, rl_insert }, /* Latin capital letter Y with acute */
+ { ISFUNC, rl_insert }, /* Latin capital letter thorn (Icelandic) */
+ { ISFUNC, rl_insert }, /* Latin small letter sharp s (German) */
+ { ISFUNC, rl_insert }, /* Latin small letter a with grave */
+ { ISFUNC, rl_insert }, /* Latin small letter a with acute */
+ { ISFUNC, rl_insert }, /* Latin small letter a with circumflex */
+ { ISFUNC, rl_insert }, /* Latin small letter a with tilde */
+ { ISFUNC, rl_insert }, /* Latin small letter a with diaeresis */
+ { ISFUNC, rl_insert }, /* Latin small letter a with ring above */
+ { ISFUNC, rl_insert }, /* Latin small letter ae */
+ { ISFUNC, rl_insert }, /* Latin small letter c with cedilla */
+ { ISFUNC, rl_insert }, /* Latin small letter e with grave */
+ { ISFUNC, rl_insert }, /* Latin small letter e with acute */
+ { ISFUNC, rl_insert }, /* Latin small letter e with circumflex */
+ { ISFUNC, rl_insert }, /* Latin small letter e with diaeresis */
+ { ISFUNC, rl_insert }, /* Latin small letter i with grave */
+ { ISFUNC, rl_insert }, /* Latin small letter i with acute */
+ { ISFUNC, rl_insert }, /* Latin small letter i with circumflex */
+ { ISFUNC, rl_insert }, /* Latin small letter i with diaeresis */
+ { ISFUNC, rl_insert }, /* Latin small letter eth (Icelandic) */
+ { ISFUNC, rl_insert }, /* Latin small letter n with tilde */
+ { ISFUNC, rl_insert }, /* Latin small letter o with grave */
+ { ISFUNC, rl_insert }, /* Latin small letter o with acute */
+ { ISFUNC, rl_insert }, /* Latin small letter o with circumflex */
+ { ISFUNC, rl_insert }, /* Latin small letter o with tilde */
+ { ISFUNC, rl_insert }, /* Latin small letter o with diaeresis */
+ { ISFUNC, rl_insert }, /* Division sign */
+ { ISFUNC, rl_insert }, /* Latin small letter o with stroke */
+ { ISFUNC, rl_insert }, /* Latin small letter u with grave */
+ { ISFUNC, rl_insert }, /* Latin small letter u with acute */
+ { ISFUNC, rl_insert }, /* Latin small letter u with circumflex */
+ { ISFUNC, rl_insert }, /* Latin small letter u with diaeresis */
+ { ISFUNC, rl_insert }, /* Latin small letter y with acute */
+ { ISFUNC, rl_insert }, /* Latin small letter thorn (Icelandic) */
+ { ISFUNC, rl_insert } /* Latin small letter y with diaeresis */
+#endif /* KEYMAP_SIZE > 128 */
+};
+
+KEYMAP_ENTRY_ARRAY emacs_meta_keymap = {
+
+ /* Meta keys. Just like above, but the high bit is set. */
+ { ISFUNC, (Function *)0x0 }, /* Meta-Control-@ */
+ { ISFUNC, (Function *)0x0 }, /* Meta-Control-a */
+ { ISFUNC, (Function *)0x0 }, /* Meta-Control-b */
+ { ISFUNC, (Function *)0x0 }, /* Meta-Control-c */
+ { ISFUNC, (Function *)0x0 }, /* Meta-Control-d */
+ { ISFUNC, (Function *)0x0 }, /* Meta-Control-e */
+ { ISFUNC, (Function *)0x0 }, /* Meta-Control-f */
+ { ISFUNC, rl_abort }, /* Meta-Control-g */
+ { ISFUNC, rl_backward_kill_word }, /* Meta-Control-h */
+ { ISFUNC, rl_tab_insert }, /* Meta-Control-i */
+ { ISFUNC, rl_vi_editing_mode }, /* Meta-Control-j */
+ { ISFUNC, (Function *)0x0 }, /* Meta-Control-k */
+ { ISFUNC, (Function *)0x0 }, /* Meta-Control-l */
+ { ISFUNC, rl_vi_editing_mode }, /* Meta-Control-m */
+ { ISFUNC, (Function *)0x0 }, /* Meta-Control-n */
+ { ISFUNC, (Function *)0x0 }, /* Meta-Control-o */
+ { ISFUNC, (Function *)0x0 }, /* Meta-Control-p */
+ { ISFUNC, (Function *)0x0 }, /* Meta-Control-q */
+ { ISFUNC, rl_revert_line }, /* Meta-Control-r */
+ { ISFUNC, (Function *)0x0 }, /* Meta-Control-s */
+ { ISFUNC, (Function *)0x0 }, /* Meta-Control-t */
+ { ISFUNC, (Function *)0x0 }, /* Meta-Control-u */
+ { ISFUNC, (Function *)0x0 }, /* Meta-Control-v */
+ { ISFUNC, (Function *)0x0 }, /* Meta-Control-w */
+ { ISFUNC, (Function *)0x0 }, /* Meta-Control-x */
+ { ISFUNC, rl_yank_nth_arg }, /* Meta-Control-y */
+ { ISFUNC, (Function *)0x0 }, /* Meta-Control-z */
+
+ { ISFUNC, rl_complete }, /* Meta-Control-[ */
+ { ISFUNC, (Function *)0x0 }, /* Meta-Control-\ */
+ { ISFUNC, rl_backward_char_search }, /* Meta-Control-] */
+ { ISFUNC, (Function *)0x0 }, /* Meta-Control-^ */
+ { ISFUNC, (Function *)0x0 }, /* Meta-Control-_ */
+
+ /* The start of printing characters. */
+ { ISFUNC, rl_set_mark }, /* Meta-SPACE */
+ { ISFUNC, (Function *)0x0 }, /* Meta-! */
+ { ISFUNC, (Function *)0x0 }, /* Meta-" */
+ { ISFUNC, rl_insert_comment },/* Meta-# */
+ { ISFUNC, (Function *)0x0 }, /* Meta-$ */
+ { ISFUNC, (Function *)0x0 }, /* Meta-% */
+ { ISFUNC, rl_tilde_expand }, /* Meta-& */
+ { ISFUNC, (Function *)0x0 }, /* Meta-' */
+ { ISFUNC, (Function *)0x0 }, /* Meta-( */
+ { ISFUNC, (Function *)0x0 }, /* Meta-) */
+ { ISFUNC, rl_insert_completions }, /* Meta-* */
+ { ISFUNC, (Function *)0x0 }, /* Meta-+ */
+ { ISFUNC, (Function *)0x0 }, /* Meta-, */
+ { ISFUNC, rl_digit_argument }, /* Meta-- */
+ { ISFUNC, rl_yank_last_arg}, /* Meta-. */
+ { ISFUNC, (Function *)0x0 }, /* Meta-/ */
+
+ /* Regular digits. */
+ { ISFUNC, rl_digit_argument }, /* Meta-0 */
+ { ISFUNC, rl_digit_argument }, /* Meta-1 */
+ { ISFUNC, rl_digit_argument }, /* Meta-2 */
+ { ISFUNC, rl_digit_argument }, /* Meta-3 */
+ { ISFUNC, rl_digit_argument }, /* Meta-4 */
+ { ISFUNC, rl_digit_argument }, /* Meta-5 */
+ { ISFUNC, rl_digit_argument }, /* Meta-6 */
+ { ISFUNC, rl_digit_argument }, /* Meta-7 */
+ { ISFUNC, rl_digit_argument }, /* Meta-8 */
+ { ISFUNC, rl_digit_argument }, /* Meta-9 */
+
+ /* A little more punctuation. */
+ { ISFUNC, (Function *)0x0 }, /* Meta-: */
+ { ISFUNC, (Function *)0x0 }, /* Meta-; */
+ { ISFUNC, rl_beginning_of_history }, /* Meta-< */
+ { ISFUNC, rl_possible_completions }, /* Meta-= */
+ { ISFUNC, rl_end_of_history }, /* Meta-> */
+ { ISFUNC, rl_possible_completions }, /* Meta-? */
+ { ISFUNC, (Function *)0x0 }, /* Meta-@ */
+
+ /* Uppercase alphabet. */
+ { ISFUNC, rl_do_lowercase_version }, /* Meta-A */
+ { ISFUNC, rl_do_lowercase_version }, /* Meta-B */
+ { ISFUNC, rl_do_lowercase_version }, /* Meta-C */
+ { ISFUNC, rl_do_lowercase_version }, /* Meta-D */
+ { ISFUNC, rl_do_lowercase_version }, /* Meta-E */
+ { ISFUNC, rl_do_lowercase_version }, /* Meta-F */
+ { ISFUNC, rl_do_lowercase_version }, /* Meta-G */
+ { ISFUNC, rl_do_lowercase_version }, /* Meta-H */
+ { ISFUNC, rl_do_lowercase_version }, /* Meta-I */
+ { ISFUNC, rl_do_lowercase_version }, /* Meta-J */
+ { ISFUNC, rl_do_lowercase_version }, /* Meta-K */
+ { ISFUNC, rl_do_lowercase_version }, /* Meta-L */
+ { ISFUNC, rl_do_lowercase_version }, /* Meta-M */
+ { ISFUNC, rl_do_lowercase_version }, /* Meta-N */
+ { ISFUNC, rl_do_lowercase_version }, /* Meta-O */
+ { ISFUNC, rl_do_lowercase_version }, /* Meta-P */
+ { ISFUNC, rl_do_lowercase_version }, /* Meta-Q */
+ { ISFUNC, rl_do_lowercase_version }, /* Meta-R */
+ { ISFUNC, rl_do_lowercase_version }, /* Meta-S */
+ { ISFUNC, rl_do_lowercase_version }, /* Meta-T */
+ { ISFUNC, rl_do_lowercase_version }, /* Meta-U */
+ { ISFUNC, rl_do_lowercase_version }, /* Meta-V */
+ { ISFUNC, rl_do_lowercase_version }, /* Meta-W */
+ { ISFUNC, rl_do_lowercase_version }, /* Meta-X */
+ { ISFUNC, rl_do_lowercase_version }, /* Meta-Y */
+ { ISFUNC, rl_do_lowercase_version }, /* Meta-Z */
+
+ /* Some more punctuation. */
+ { ISFUNC, (Function *)0x0 }, /* Meta-[ */ /* was rl_arrow_keys */
+ { ISFUNC, rl_delete_horizontal_space }, /* Meta-\ */
+ { ISFUNC, (Function *)0x0 }, /* Meta-] */
+ { ISFUNC, (Function *)0x0 }, /* Meta-^ */
+ { ISFUNC, rl_yank_last_arg }, /* Meta-_ */
+ { ISFUNC, (Function *)0x0 }, /* Meta-` */
+
+ /* Lowercase alphabet. */
+ { ISFUNC, (Function *)0x0 }, /* Meta-a */
+ { ISFUNC, rl_backward_word }, /* Meta-b */
+ { ISFUNC, rl_capitalize_word }, /* Meta-c */
+ { ISFUNC, rl_kill_word }, /* Meta-d */
+ { ISFUNC, (Function *)0x0 }, /* Meta-e */
+ { ISFUNC, rl_forward_word }, /* Meta-f */
+ { ISFUNC, (Function *)0x0 }, /* Meta-g */
+ { ISFUNC, (Function *)0x0 }, /* Meta-h */
+ { ISFUNC, (Function *)0x0 }, /* Meta-i */
+ { ISFUNC, (Function *)0x0 }, /* Meta-j */
+ { ISFUNC, (Function *)0x0 }, /* Meta-k */
+ { ISFUNC, rl_downcase_word }, /* Meta-l */
+ { ISFUNC, (Function *)0x0 }, /* Meta-m */
+ { ISFUNC, rl_noninc_forward_search }, /* Meta-n */
+ { ISFUNC, (Function *)0x0 }, /* Meta-o */ /* was rl_arrow_keys */
+ { ISFUNC, rl_noninc_reverse_search }, /* Meta-p */
+ { ISFUNC, (Function *)0x0 }, /* Meta-q */
+ { ISFUNC, rl_revert_line }, /* Meta-r */
+ { ISFUNC, (Function *)0x0 }, /* Meta-s */
+ { ISFUNC, rl_transpose_words }, /* Meta-t */
+ { ISFUNC, rl_upcase_word }, /* Meta-u */
+ { ISFUNC, (Function *)0x0 }, /* Meta-v */
+ { ISFUNC, (Function *)0x0 }, /* Meta-w */
+ { ISFUNC, (Function *)0x0 }, /* Meta-x */
+ { ISFUNC, rl_yank_pop }, /* Meta-y */
+ { ISFUNC, (Function *)0x0 }, /* Meta-z */
+
+ /* Final punctuation. */
+ { ISFUNC, (Function *)0x0 }, /* Meta-{ */
+ { ISFUNC, (Function *)0x0 }, /* Meta-| */
+ { ISFUNC, (Function *)0x0 }, /* Meta-} */
+ { ISFUNC, rl_tilde_expand }, /* Meta-~ */
+ { ISFUNC, rl_backward_kill_word }, /* Meta-rubout */
+
+#if KEYMAP_SIZE > 128
+ /* Undefined keys. */
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 }
+#endif /* KEYMAP_SIZE > 128 */
+};
+
+KEYMAP_ENTRY_ARRAY emacs_ctlx_keymap = {
+
+ /* Control keys. */
+ { ISFUNC, (Function *)0x0 }, /* Control-@ */
+ { ISFUNC, (Function *)0x0 }, /* Control-a */
+ { ISFUNC, (Function *)0x0 }, /* Control-b */
+ { ISFUNC, (Function *)0x0 }, /* Control-c */
+ { ISFUNC, (Function *)0x0 }, /* Control-d */
+ { ISFUNC, (Function *)0x0 }, /* Control-e */
+ { ISFUNC, (Function *)0x0 }, /* Control-f */
+ { ISFUNC, rl_abort }, /* Control-g */
+ { ISFUNC, (Function *)0x0 }, /* Control-h */
+ { ISFUNC, (Function *)0x0 }, /* Control-i */
+ { ISFUNC, (Function *)0x0 }, /* Control-j */
+ { ISFUNC, (Function *)0x0 }, /* Control-k */
+ { ISFUNC, (Function *)0x0 }, /* Control-l */
+ { ISFUNC, (Function *)0x0 }, /* Control-m */
+ { ISFUNC, (Function *)0x0 }, /* Control-n */
+ { ISFUNC, (Function *)0x0 }, /* Control-o */
+ { ISFUNC, (Function *)0x0 }, /* Control-p */
+ { ISFUNC, (Function *)0x0 }, /* Control-q */
+ { ISFUNC, rl_re_read_init_file }, /* Control-r */
+ { ISFUNC, (Function *)0x0 }, /* Control-s */
+ { ISFUNC, (Function *)0x0 }, /* Control-t */
+ { ISFUNC, rl_undo_command }, /* Control-u */
+ { ISFUNC, (Function *)0x0 }, /* Control-v */
+ { ISFUNC, (Function *)0x0 }, /* Control-w */
+ { ISFUNC, rl_exchange_point_and_mark },/* Control-x */
+ { ISFUNC, (Function *)0x0 }, /* Control-y */
+ { ISFUNC, (Function *)0x0 }, /* Control-z */
+ { ISFUNC, (Function *)0x0 }, /* Control-[ */
+ { ISFUNC, (Function *)0x0 }, /* Control-\ */
+ { ISFUNC, (Function *)0x0 }, /* Control-] */
+ { ISFUNC, (Function *)0x0 }, /* Control-^ */
+ { ISFUNC, (Function *)0x0 }, /* Control-_ */
+
+ /* The start of printing characters. */
+ { ISFUNC, (Function *)0x0 }, /* SPACE */
+ { ISFUNC, (Function *)0x0 }, /* ! */
+ { ISFUNC, (Function *)0x0 }, /* " */
+ { ISFUNC, (Function *)0x0 }, /* # */
+ { ISFUNC, (Function *)0x0 }, /* $ */
+ { ISFUNC, (Function *)0x0 }, /* % */
+ { ISFUNC, (Function *)0x0 }, /* & */
+ { ISFUNC, (Function *)0x0 }, /* ' */
+ { ISFUNC, rl_start_kbd_macro }, /* ( */
+ { ISFUNC, rl_end_kbd_macro }, /* ) */
+ { ISFUNC, (Function *)0x0 }, /* * */
+ { ISFUNC, (Function *)0x0 }, /* + */
+ { ISFUNC, (Function *)0x0 }, /* , */
+ { ISFUNC, (Function *)0x0 }, /* - */
+ { ISFUNC, (Function *)0x0 }, /* . */
+ { ISFUNC, (Function *)0x0 }, /* / */
+
+ /* Regular digits. */
+ { ISFUNC, (Function *)0x0 }, /* 0 */
+ { ISFUNC, (Function *)0x0 }, /* 1 */
+ { ISFUNC, (Function *)0x0 }, /* 2 */
+ { ISFUNC, (Function *)0x0 }, /* 3 */
+ { ISFUNC, (Function *)0x0 }, /* 4 */
+ { ISFUNC, (Function *)0x0 }, /* 5 */
+ { ISFUNC, (Function *)0x0 }, /* 6 */
+ { ISFUNC, (Function *)0x0 }, /* 7 */
+ { ISFUNC, (Function *)0x0 }, /* 8 */
+ { ISFUNC, (Function *)0x0 }, /* 9 */
+
+ /* A little more punctuation. */
+ { ISFUNC, (Function *)0x0 }, /* : */
+ { ISFUNC, (Function *)0x0 }, /* ; */
+ { ISFUNC, (Function *)0x0 }, /* < */
+ { ISFUNC, (Function *)0x0 }, /* = */
+ { ISFUNC, (Function *)0x0 }, /* > */
+ { ISFUNC, (Function *)0x0 }, /* ? */
+ { ISFUNC, (Function *)0x0 }, /* @ */
+
+ /* Uppercase alphabet. */
+ { ISFUNC, rl_do_lowercase_version }, /* A */
+ { ISFUNC, rl_do_lowercase_version }, /* B */
+ { ISFUNC, rl_do_lowercase_version }, /* C */
+ { ISFUNC, rl_do_lowercase_version }, /* D */
+ { ISFUNC, rl_do_lowercase_version }, /* E */
+ { ISFUNC, rl_do_lowercase_version }, /* F */
+ { ISFUNC, rl_do_lowercase_version }, /* G */
+ { ISFUNC, rl_do_lowercase_version }, /* H */
+ { ISFUNC, rl_do_lowercase_version }, /* I */
+ { ISFUNC, rl_do_lowercase_version }, /* J */
+ { ISFUNC, rl_do_lowercase_version }, /* K */
+ { ISFUNC, rl_do_lowercase_version }, /* L */
+ { ISFUNC, rl_do_lowercase_version }, /* M */
+ { ISFUNC, rl_do_lowercase_version }, /* N */
+ { ISFUNC, rl_do_lowercase_version }, /* O */
+ { ISFUNC, rl_do_lowercase_version }, /* P */
+ { ISFUNC, rl_do_lowercase_version }, /* Q */
+ { ISFUNC, rl_do_lowercase_version }, /* R */
+ { ISFUNC, rl_do_lowercase_version }, /* S */
+ { ISFUNC, rl_do_lowercase_version }, /* T */
+ { ISFUNC, rl_do_lowercase_version }, /* U */
+ { ISFUNC, rl_do_lowercase_version }, /* V */
+ { ISFUNC, rl_do_lowercase_version }, /* W */
+ { ISFUNC, rl_do_lowercase_version }, /* X */
+ { ISFUNC, rl_do_lowercase_version }, /* Y */
+ { ISFUNC, rl_do_lowercase_version }, /* Z */
+
+ /* Some more punctuation. */
+ { ISFUNC, (Function *)0x0 }, /* [ */
+ { ISFUNC, (Function *)0x0 }, /* \ */
+ { ISFUNC, (Function *)0x0 }, /* ] */
+ { ISFUNC, (Function *)0x0 }, /* ^ */
+ { ISFUNC, (Function *)0x0 }, /* _ */
+ { ISFUNC, (Function *)0x0 }, /* ` */
+
+ /* Lowercase alphabet. */
+ { ISFUNC, (Function *)0x0 }, /* a */
+ { ISFUNC, (Function *)0x0 }, /* b */
+ { ISFUNC, (Function *)0x0 }, /* c */
+ { ISFUNC, (Function *)0x0 }, /* d */
+ { ISFUNC, rl_call_last_kbd_macro }, /* e */
+ { ISFUNC, (Function *)0x0 }, /* f */
+ { ISFUNC, (Function *)0x0 }, /* g */
+ { ISFUNC, (Function *)0x0 }, /* h */
+ { ISFUNC, (Function *)0x0 }, /* i */
+ { ISFUNC, (Function *)0x0 }, /* j */
+ { ISFUNC, (Function *)0x0 }, /* k */
+ { ISFUNC, (Function *)0x0 }, /* l */
+ { ISFUNC, (Function *)0x0 }, /* m */
+ { ISFUNC, (Function *)0x0 }, /* n */
+ { ISFUNC, (Function *)0x0 }, /* o */
+ { ISFUNC, (Function *)0x0 }, /* p */
+ { ISFUNC, (Function *)0x0 }, /* q */
+ { ISFUNC, (Function *)0x0 }, /* r */
+ { ISFUNC, (Function *)0x0 }, /* s */
+ { ISFUNC, (Function *)0x0 }, /* t */
+ { ISFUNC, (Function *)0x0 }, /* u */
+ { ISFUNC, (Function *)0x0 }, /* v */
+ { ISFUNC, (Function *)0x0 }, /* w */
+ { ISFUNC, (Function *)0x0 }, /* x */
+ { ISFUNC, (Function *)0x0 }, /* y */
+ { ISFUNC, (Function *)0x0 }, /* z */
+
+ /* Final punctuation. */
+ { ISFUNC, (Function *)0x0 }, /* { */
+ { ISFUNC, (Function *)0x0 }, /* | */
+ { ISFUNC, (Function *)0x0 }, /* } */
+ { ISFUNC, (Function *)0x0 }, /* ~ */
+ { ISFUNC, rl_backward_kill_line }, /* RUBOUT */
+
+#if KEYMAP_SIZE > 128
+ /* Undefined keys. */
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 }
+#endif /* KEYMAP_SIZE > 128 */
+};
diff --git a/readline/funmap.c b/readline/funmap.c
new file mode 100644
index 00000000000..f6b86286fe0
--- /dev/null
+++ b/readline/funmap.c
@@ -0,0 +1,254 @@
+/* funmap.c -- attach names to functions. */
+
+/* Copyright (C) 1987, 1989, 1992 Free Software Foundation, Inc.
+
+ This file is part of the GNU Readline Library, a library for
+ reading lines of text with interactive input and history editing.
+
+ The GNU Readline Library is free software; you can redistribute it
+ and/or modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 1, or
+ (at your option) any later version.
+
+ The GNU Readline 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 General Public License for more details.
+
+ The GNU General Public License is often shipped with GNU software, and
+ is generally kept in a file called COPYING or LICENSE. If you do not
+ have a copy of the license, write to the Free Software Foundation,
+ 675 Mass Ave, Cambridge, MA 02139, USA. */
+#define READLINE_LIBRARY
+
+#if defined (HAVE_CONFIG_H)
+# include <config.h>
+#endif
+
+extern char *xmalloc (), *xrealloc ();
+
+#if !defined (BUFSIZ)
+#include <stdio.h>
+#endif /* BUFSIZ */
+
+#if defined (HAVE_STDLIB_H)
+# include <stdlib.h>
+#else
+# include "ansi_stdlib.h"
+#endif /* HAVE_STDLIB_H */
+
+#include "rlconf.h"
+#include "readline.h"
+
+extern int _rl_qsort_string_compare ();
+
+FUNMAP **funmap;
+static int funmap_size;
+static int funmap_entry;
+
+/* After initializing the function map, this is the index of the first
+ program specific function. */
+int funmap_program_specific_entry_start;
+
+static FUNMAP default_funmap[] = {
+ { "abort", rl_abort },
+ { "accept-line", rl_newline },
+ { "arrow-key-prefix", rl_arrow_keys },
+ { "backward-char", rl_backward },
+ { "backward-delete-char", rl_rubout },
+ { "backward-kill-line", rl_backward_kill_line },
+ { "backward-kill-word", rl_backward_kill_word },
+ { "backward-word", rl_backward_word },
+ { "beginning-of-history", rl_beginning_of_history },
+ { "beginning-of-line", rl_beg_of_line },
+ { "call-last-kbd-macro", rl_call_last_kbd_macro },
+ { "capitalize-word", rl_capitalize_word },
+ { "character-search", rl_char_search },
+ { "character-search-backward", rl_backward_char_search },
+ { "clear-screen", rl_clear_screen },
+ { "complete", rl_complete },
+ { "copy-backward-word", rl_copy_backward_word },
+ { "copy-forward-word", rl_copy_forward_word },
+ { "copy-region-as-kill", rl_copy_region_to_kill },
+ { "delete-char", rl_delete },
+ { "delete-char-or-list", rl_delete_or_show_completions },
+ { "delete-horizontal-space", rl_delete_horizontal_space },
+ { "digit-argument", rl_digit_argument },
+ { "do-lowercase-version", rl_do_lowercase_version },
+ { "downcase-word", rl_downcase_word },
+ { "dump-functions", rl_dump_functions },
+ { "dump-macros", rl_dump_macros },
+ { "dump-variables", rl_dump_variables },
+ { "emacs-editing-mode", rl_emacs_editing_mode },
+ { "end-kbd-macro", rl_end_kbd_macro },
+ { "end-of-history", rl_end_of_history },
+ { "end-of-line", rl_end_of_line },
+ { "exchange-point-and-mark", rl_exchange_point_and_mark },
+ { "forward-backward-delete-char", rl_rubout_or_delete },
+ { "forward-char", rl_forward },
+ { "forward-search-history", rl_forward_search_history },
+ { "forward-word", rl_forward_word },
+ { "history-search-backward", rl_history_search_backward },
+ { "history-search-forward", rl_history_search_forward },
+ { "insert-comment", rl_insert_comment },
+ { "insert-completions", rl_insert_completions },
+ { "kill-whole-line", rl_kill_full_line },
+ { "kill-line", rl_kill_line },
+ { "kill-region", rl_kill_region },
+ { "kill-word", rl_kill_word },
+ { "menu-complete", rl_menu_complete },
+ { "next-history", rl_get_next_history },
+ { "non-incremental-forward-search-history", rl_noninc_forward_search },
+ { "non-incremental-reverse-search-history", rl_noninc_reverse_search },
+ { "non-incremental-forward-search-history-again", rl_noninc_forward_search_again },
+ { "non-incremental-reverse-search-history-again", rl_noninc_reverse_search_again },
+#ifdef __CYGWIN32__
+ { "paste-from-clipboard", rl_paste_from_clipboard },
+#endif
+ { "possible-completions", rl_possible_completions },
+ { "previous-history", rl_get_previous_history },
+ { "quoted-insert", rl_quoted_insert },
+ { "re-read-init-file", rl_re_read_init_file },
+ { "redraw-current-line", rl_refresh_line},
+ { "reverse-search-history", rl_reverse_search_history },
+ { "revert-line", rl_revert_line },
+ { "self-insert", rl_insert },
+ { "set-mark", rl_set_mark },
+ { "start-kbd-macro", rl_start_kbd_macro },
+ { "tab-insert", rl_tab_insert },
+ { "tilde-expand", rl_tilde_expand },
+ { "transpose-chars", rl_transpose_chars },
+ { "transpose-words", rl_transpose_words },
+ { "tty-status", rl_tty_status },
+ { "undo", rl_undo_command },
+ { "universal-argument", rl_universal_argument },
+ { "unix-line-discard", rl_unix_line_discard },
+ { "unix-word-rubout", rl_unix_word_rubout },
+ { "upcase-word", rl_upcase_word },
+ { "yank", rl_yank },
+ { "yank-last-arg", rl_yank_last_arg },
+ { "yank-nth-arg", rl_yank_nth_arg },
+ { "yank-pop", rl_yank_pop },
+
+#if defined (VI_MODE)
+ { "vi-append-eol", rl_vi_append_eol },
+ { "vi-append-mode", rl_vi_append_mode },
+ { "vi-arg-digit", rl_vi_arg_digit },
+ { "vi-back-to-indent", rl_vi_back_to_indent },
+ { "vi-bWord", rl_vi_bWord },
+ { "vi-bracktype", rl_vi_bracktype },
+ { "vi-bword", rl_vi_bword },
+ { "vi-change-case", rl_vi_change_case },
+ { "vi-change-char", rl_vi_change_char },
+ { "vi-change-to", rl_vi_change_to },
+ { "vi-char-search", rl_vi_char_search },
+ { "vi-column", rl_vi_column },
+ { "vi-complete", rl_vi_complete },
+ { "vi-delete", rl_vi_delete },
+ { "vi-delete-to", rl_vi_delete_to },
+ { "vi-eWord", rl_vi_eWord },
+ { "vi-editing-mode", rl_vi_editing_mode },
+ { "vi-end-word", rl_vi_end_word },
+ { "vi-eof-maybe", rl_vi_eof_maybe },
+ { "vi-eword", rl_vi_eword },
+ { "vi-fWord", rl_vi_fWord },
+ { "vi-fetch-history", rl_vi_fetch_history },
+ { "vi-first-print", rl_vi_first_print },
+ { "vi-fword", rl_vi_fword },
+ { "vi-goto-mark", rl_vi_goto_mark },
+ { "vi-insert-beg", rl_vi_insert_beg },
+ { "vi-insertion-mode", rl_vi_insertion_mode },
+ { "vi-match", rl_vi_match },
+ { "vi-movement-mode", rl_vi_movement_mode },
+ { "vi-next-word", rl_vi_next_word },
+ { "vi-overstrike", rl_vi_overstrike },
+ { "vi-overstrike-delete", rl_vi_overstrike_delete },
+ { "vi-prev-word", rl_vi_prev_word },
+ { "vi-put", rl_vi_put },
+ { "vi-redo", rl_vi_redo },
+ { "vi-replace", rl_vi_replace },
+ { "vi-search", rl_vi_search },
+ { "vi-search-again", rl_vi_search_again },
+ { "vi-set-mark", rl_vi_set_mark },
+ { "vi-subst", rl_vi_subst },
+ { "vi-tilde-expand", rl_vi_tilde_expand },
+ { "vi-yank-arg", rl_vi_yank_arg },
+ { "vi-yank-to", rl_vi_yank_to },
+#endif /* VI_MODE */
+
+ {(char *)NULL, (Function *)NULL }
+};
+
+int
+rl_add_funmap_entry (name, function)
+ 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;
+
+ funmap[++funmap_entry] = (FUNMAP *)NULL;
+ return funmap_entry;
+}
+
+static int funmap_initialized;
+
+/* Make the funmap contain all of the default entries. */
+void
+rl_initialize_funmap ()
+{
+ register int i;
+
+ if (funmap_initialized)
+ return;
+
+ for (i = 0; default_funmap[i].name; i++)
+ rl_add_funmap_entry (default_funmap[i].name, default_funmap[i].function);
+
+ funmap_initialized = 1;
+ funmap_program_specific_entry_start = i;
+}
+
+/* Produce a NULL terminated array of known function names. The array
+ is sorted. The array itself is allocated, but not the strings inside.
+ You should free () the array when you done, but not the pointrs. */
+char **
+rl_funmap_names ()
+{
+ char **result;
+ int result_size, result_index;
+
+ /* Make sure that the function map has been initialized. */
+ rl_initialize_funmap ();
+
+ for (result_index = result_size = 0, result = (char **)NULL; funmap[result_index]; result_index++)
+ {
+ if (result_index + 2 > result_size)
+ {
+ result_size += 20;
+ result = (char **)xrealloc (result, result_size * sizeof (char *));
+ }
+
+ result[result_index] = funmap[result_index]->name;
+ result[result_index + 1] = (char *)NULL;
+ }
+
+ qsort (result, result_index, sizeof (char *), _rl_qsort_string_compare);
+ return (result);
+}
+
+/* Things that mean `Control'. */
+char *possible_control_prefixes[] = {
+ "Control-", "C-", "CTRL-", (char *)NULL
+};
+
+char *possible_meta_prefixes[] = {
+ "Meta", "M-", (char *)NULL
+};
diff --git a/readline/histexpand.c b/readline/histexpand.c
new file mode 100644
index 00000000000..392e6d38d9e
--- /dev/null
+++ b/readline/histexpand.c
@@ -0,0 +1,1359 @@
+/* histexpand.c -- history expansion. */
+
+/* Copyright (C) 1989, 1992 Free Software Foundation, Inc.
+
+ This file contains the GNU History Library (the Library), a set of
+ routines for managing the text of previously typed lines.
+
+ The Library is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 1, or (at your option)
+ any later version.
+
+ The 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
+ General Public License for more details.
+
+ The GNU General Public License is often shipped with GNU software, and
+ is generally kept in a file called COPYING or LICENSE. If you do not
+ have a copy of the license, write to the Free Software Foundation,
+ 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#define READLINE_LIBRARY
+
+#if defined (HAVE_CONFIG_H)
+# include <config.h>
+#endif
+
+#include <stdio.h>
+
+#if defined (HAVE_STDLIB_H)
+# include <stdlib.h>
+#else
+# include "ansi_stdlib.h"
+#endif /* HAVE_STDLIB_H */
+
+#if defined (HAVE_UNISTD_H)
+# ifndef _MINIX
+# include <sys/types.h>
+# endif
+# include <unistd.h>
+#endif
+
+#if defined (HAVE_STRING_H)
+# include <string.h>
+#else
+# include <strings.h>
+#endif /* !HAVE_STRING_H */
+
+#include "history.h"
+#include "histlib.h"
+
+#define HISTORY_WORD_DELIMITERS " \t\n;&()|<>"
+#define HISTORY_QUOTE_CHARACTERS "\"'`"
+
+static char error_pointer;
+
+static char *subst_lhs;
+static char *subst_rhs;
+static int subst_lhs_len;
+static int subst_rhs_len;
+
+static char *get_history_word_specifier ();
+static char *history_find_word ();
+
+extern int history_offset;
+
+extern char *single_quote ();
+static char *quote_breaks ();
+
+extern char *xmalloc (), *xrealloc ();
+
+/* Variables exported by this file. */
+/* The character that represents the start of a history expansion
+ request. This is usually `!'. */
+char history_expansion_char = '!';
+
+/* The character that invokes word substitution if found at the start of
+ a line. This is usually `^'. */
+char history_subst_char = '^';
+
+/* During tokenization, if this character is seen as the first character
+ of a word, then it, and all subsequent characters upto a newline are
+ ignored. For a Bourne shell, this should be '#'. Bash special cases
+ the interactive comment character to not be a comment delimiter. */
+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=";
+
+/* If set to a non-zero value, single quotes inhibit history expansion.
+ The default is 0. */
+int history_quotes_inhibit_expansion = 0;
+
+/* If set, this points to a function that is called to verify that a
+ particular history expansion should be performed. */
+Function *history_inhibit_expansion_function;
+
+/* **************************************************************** */
+/* */
+/* History Expansion */
+/* */
+/* **************************************************************** */
+
+/* Hairy history expansion on text, not tokens. This is of general
+ use, and thus belongs in this library. */
+
+/* The last string searched for by a !?string? search. */
+static char *search_string;
+
+/* The last string matched by a !?string? search. */
+static char *search_match;
+
+/* Return the event specified at TEXT + OFFSET modifying OFFSET to
+ point to after the event specifier. Just a pointer to the history
+ line is returned; NULL is returned in the event of a bad specifier.
+ You pass STRING with *INDEX equal to the history_expansion_char that
+ begins this specification.
+ DELIMITING_QUOTE is a character that is allowed to end the string
+ specification for what to search for in addition to the normal
+ characters `:', ` ', `\t', `\n', and sometimes `?'.
+ So you might call this function like:
+ line = get_history_event ("!echo:p", &index, 0); */
+char *
+get_history_event (string, caller_index, delimiting_quote)
+ char *string;
+ int *caller_index;
+ int delimiting_quote;
+{
+ register int i;
+ register char c;
+ HIST_ENTRY *entry;
+ int which, sign, local_index, substring_okay;
+ Function *search_func;
+ char *temp;
+
+ /* The event can be specified in a number of ways.
+
+ !! the previous command
+ !n command line N
+ !-n current command-line minus N
+ !str the most recent command starting with STR
+ !?str[?]
+ the most recent command containing STR
+
+ All values N are determined via HISTORY_BASE. */
+
+ i = *caller_index;
+
+ if (string[i] != history_expansion_char)
+ return ((char *)NULL);
+
+ /* Move on to the specification. */
+ i++;
+
+ sign = 1;
+ substring_okay = 0;
+
+#define RETURN_ENTRY(e, w) \
+ return ((e = history_get (w)) ? e->line : (char *)NULL)
+
+ /* Handle !! case. */
+ if (string[i] == history_expansion_char)
+ {
+ i++;
+ which = history_base + (history_length - 1);
+ *caller_index = i;
+ RETURN_ENTRY (entry, which);
+ }
+
+ /* Hack case of numeric line specification. */
+ if (string[i] == '-')
+ {
+ sign = -1;
+ i++;
+ }
+
+ if (_rl_digit_p (string[i]))
+ {
+ /* Get the extent of the digits and compute the value. */
+ for (which = 0; _rl_digit_p (string[i]); i++)
+ which = (which * 10) + _rl_digit_value (string[i]);
+
+ *caller_index = i;
+
+ if (sign < 0)
+ which = (history_length + history_base) - which;
+
+ RETURN_ENTRY (entry, which);
+ }
+
+ /* This must be something to search for. If the spec begins with
+ a '?', then the string may be anywhere on the line. Otherwise,
+ the string must be found at the start of a line. */
+ if (string[i] == '?')
+ {
+ substring_okay++;
+ i++;
+ }
+
+ /* Only a closing `?' or a newline delimit a substring search string. */
+ for (local_index = i; c = string[i]; i++)
+ if ((!substring_okay && (whitespace (c) || c == ':' ||
+ (history_search_delimiter_chars && member (c, history_search_delimiter_chars)) ||
+ string[i] == delimiting_quote)) ||
+ string[i] == '\n' ||
+ (substring_okay && string[i] == '?'))
+ break;
+
+ which = i - local_index;
+ temp = xmalloc (1 + which);
+ if (which)
+ strncpy (temp, string + local_index, which);
+ temp[which] = '\0';
+
+ if (substring_okay && string[i] == '?')
+ i++;
+
+ *caller_index = i;
+
+#define FAIL_SEARCH() \
+ do { \
+ history_offset = history_length; free (temp) ; return (char *)NULL; \
+ } while (0)
+
+ /* If there is no search string, try to use the previous search string,
+ if one exists. If not, fail immediately. */
+ if (*temp == '\0' && substring_okay)
+ {
+ if (search_string)
+ {
+ free (temp);
+ temp = savestring (search_string);
+ }
+ else
+ FAIL_SEARCH ();
+ }
+
+ search_func = substring_okay ? history_search : history_search_prefix;
+ while (1)
+ {
+ local_index = (*search_func) (temp, -1);
+
+ if (local_index < 0)
+ FAIL_SEARCH ();
+
+ if (local_index == 0 || substring_okay)
+ {
+ 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)
+ {
+ FREE (search_string);
+ search_string = temp;
+
+ FREE (search_match);
+ search_match = history_find_word (entry->line, local_index);
+ }
+ else
+ free (temp);
+
+ return (entry->line);
+ }
+
+ if (history_offset)
+ history_offset--;
+ else
+ FAIL_SEARCH ();
+ }
+#undef FAIL_SEARCH
+#undef RETURN_ENTRY
+}
+
+/* Function for extracting single-quoted strings. Used for inhibiting
+ history expansion within single quotes. */
+
+/* Extract the contents of STRING as if it is enclosed in single quotes.
+ SINDEX, when passed in, is the offset of the character immediately
+ following the opening single quote; on exit, SINDEX is left pointing
+ to the closing single quote. */
+static void
+hist_string_extract_single_quoted (string, sindex)
+ char *string;
+ int *sindex;
+{
+ register int i;
+
+ for (i = *sindex; string[i] && string[i] != '\''; i++)
+ ;
+
+ *sindex = i;
+}
+
+static char *
+quote_breaks (s)
+ char *s;
+{
+ register char *p, *r;
+ char *ret;
+ int len = 3;
+
+ for (p = s; p && *p; p++, len++)
+ {
+ if (*p == '\'')
+ len += 3;
+ else if (whitespace (*p) || *p == '\n')
+ len += 2;
+ }
+
+ r = ret = xmalloc (len);
+ *r++ = '\'';
+ for (p = s; p && *p; )
+ {
+ if (*p == '\'')
+ {
+ *r++ = '\'';
+ *r++ = '\\';
+ *r++ = '\'';
+ *r++ = '\'';
+ p++;
+ }
+ else if (whitespace (*p) || *p == '\n')
+ {
+ *r++ = '\'';
+ *r++ = *p++;
+ *r++ = '\'';
+ }
+ else
+ *r++ = *p++;
+ }
+ *r++ = '\'';
+ *r = '\0';
+ return ret;
+}
+
+static char *
+hist_error(s, start, current, errtype)
+ char *s;
+ int start, current, errtype;
+{
+ char *temp, *emsg;
+ int ll, elen;
+
+ ll = current - start;
+
+ switch (errtype)
+ {
+ case EVENT_NOT_FOUND:
+ emsg = "event not found";
+ elen = 15;
+ break;
+ case BAD_WORD_SPEC:
+ emsg = "bad word specifier";
+ elen = 18;
+ break;
+ case SUBST_FAILED:
+ emsg = "substitution failed";
+ elen = 19;
+ break;
+ case BAD_MODIFIER:
+ emsg = "unrecognized history modifier";
+ elen = 29;
+ break;
+ case NO_PREV_SUBST:
+ emsg = "no previous substitution";
+ elen = 24;
+ break;
+ default:
+ emsg = "unknown expansion error";
+ elen = 23;
+ break;
+ }
+
+ temp = xmalloc (ll + elen + 3);
+ strncpy (temp, s + start, ll);
+ temp[ll] = ':';
+ temp[ll + 1] = ' ';
+ strcpy (temp + ll + 2, emsg);
+ return (temp);
+}
+
+/* Get a history substitution string from STR starting at *IPTR
+ and return it. The length is returned in LENPTR.
+
+ A backslash can quote the delimiter. If the string is the
+ empty string, the previous pattern is used. If there is
+ no previous pattern for the lhs, the last history search
+ string is used.
+
+ If IS_RHS is 1, we ignore empty strings and set the pattern
+ to "" anyway. subst_lhs is not changed if the lhs is empty;
+ subst_rhs is allowed to be set to the empty string. */
+
+static char *
+get_subst_pattern (str, iptr, delimiter, is_rhs, lenptr)
+ char *str;
+ int *iptr, delimiter, is_rhs, *lenptr;
+{
+ register int si, i, j, k;
+ char *s = (char *) NULL;
+
+ i = *iptr;
+
+ for (si = i; str[si] && str[si] != delimiter; si++)
+ if (str[si] == '\\' && str[si + 1] == delimiter)
+ si++;
+
+ if (si > i || is_rhs)
+ {
+ s = xmalloc (si - i + 1);
+ for (j = 0, k = i; k < si; j++, k++)
+ {
+ /* Remove a backslash quoting the search string delimiter. */
+ if (str[k] == '\\' && str[k + 1] == delimiter)
+ k++;
+ s[j] = str[k];
+ }
+ s[j] = '\0';
+ if (lenptr)
+ *lenptr = j;
+ }
+
+ i = si;
+ if (str[i])
+ i++;
+ *iptr = i;
+
+ return s;
+}
+
+static void
+postproc_subst_rhs ()
+{
+ char *new;
+ int i, j, new_size;
+
+ new = xmalloc (new_size = subst_rhs_len + subst_lhs_len);
+ for (i = j = 0; i < subst_rhs_len; i++)
+ {
+ if (subst_rhs[i] == '&')
+ {
+ if (j + subst_lhs_len >= new_size)
+ new = xrealloc (new, (new_size = new_size * 2 + subst_lhs_len));
+ strcpy (new + j, subst_lhs);
+ j += subst_lhs_len;
+ }
+ else
+ {
+ /* a single backslash protects the `&' from lhs interpolation */
+ if (subst_rhs[i] == '\\' && subst_rhs[i + 1] == '&')
+ i++;
+ if (j >= new_size)
+ new = xrealloc (new, new_size *= 2);
+ new[j++] = subst_rhs[i];
+ }
+ }
+ new[j] = '\0';
+ free (subst_rhs);
+ subst_rhs = new;
+ subst_rhs_len = j;
+}
+
+/* Expand the bulk of a history specifier starting at STRING[START].
+ Returns 0 if everything is OK, -1 if an error occurred, and 1
+ if the `p' modifier was supplied and the caller should just print
+ the returned string. Returns the new index into string in
+ *END_INDEX_PTR, and the expanded specifier in *RET_STRING. */
+static int
+history_expand_internal (string, start, end_index_ptr, ret_string, current_line)
+ char *string;
+ int start, *end_index_ptr;
+ char **ret_string;
+ char *current_line; /* for !# */
+{
+ int i, n, starting_index;
+ int substitute_globally, want_quotes, print_only;
+ char *event, *temp, *result, *tstr, *t, c, *word_spec;
+ int result_len;
+
+ result = xmalloc (result_len = 128);
+
+ i = start;
+
+ /* If it is followed by something that starts a word specifier,
+ then !! is implied as the event specifier. */
+
+ if (member (string[i + 1], ":$*%^"))
+ {
+ char fake_s[3];
+ int fake_i = 0;
+ i++;
+ fake_s[0] = fake_s[1] = history_expansion_char;
+ fake_s[2] = '\0';
+ event = get_history_event (fake_s, &fake_i, 0);
+ }
+ else if (string[i + 1] == '#')
+ {
+ i += 2;
+ event = current_line;
+ }
+ else
+ {
+ int quoted_search_delimiter = 0;
+
+ /* If the character before this `!' is a double or single
+ quote, then this expansion takes place inside of the
+ quoted string. If we have to search for some text ("!foo"),
+ allow the delimiter to end the search string. */
+ if (i && (string[i - 1] == '\'' || string[i - 1] == '"'))
+ 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);
+ free (result);
+ return (-1);
+ }
+
+ /* If a word specifier is found, then do what that requires. */
+ starting_index = i;
+ word_spec = get_history_word_specifier (string, event, &i);
+
+ /* There is no such thing as a `malformed word specifier'. However,
+ it is possible for a specifier that has no match. In that case,
+ we complain. */
+ if (word_spec == (char *)&error_pointer)
+ {
+ *ret_string = hist_error (string, starting_index, i, BAD_WORD_SPEC);
+ free (result);
+ return (-1);
+ }
+
+ /* If no word specifier, than the thing of interest was the event. */
+ temp = word_spec ? savestring (word_spec) : savestring (event);
+ FREE (word_spec);
+
+ /* Perhaps there are other modifiers involved. Do what they say. */
+ want_quotes = substitute_globally = print_only = 0;
+ starting_index = i;
+
+ while (string[i] == ':')
+ {
+ c = string[i + 1];
+
+ if (c == 'g')
+ {
+ substitute_globally = 1;
+ i++;
+ c = string[i + 1];
+ }
+
+ switch (c)
+ {
+ default:
+ *ret_string = hist_error (string, i+1, i+2, BAD_MODIFIER);
+ free (result);
+ free (temp);
+ return -1;
+
+ case 'q':
+ want_quotes = 'q';
+ break;
+
+ case 'x':
+ want_quotes = 'x';
+ break;
+
+ /* :p means make this the last executed line. So we
+ return an error state after adding this line to the
+ history. */
+ case 'p':
+ print_only++;
+ break;
+
+ /* :t discards all but the last part of the pathname. */
+ case 't':
+ tstr = strrchr (temp, '/');
+ if (tstr)
+ {
+ tstr++;
+ t = savestring (tstr);
+ free (temp);
+ temp = t;
+ }
+ break;
+
+ /* :h discards the last part of a pathname. */
+ case 'h':
+ tstr = strrchr (temp, '/');
+ if (tstr)
+ *tstr = '\0';
+ break;
+
+ /* :r discards the suffix. */
+ case 'r':
+ tstr = strrchr (temp, '.');
+ if (tstr)
+ *tstr = '\0';
+ break;
+
+ /* :e discards everything but the suffix. */
+ case 'e':
+ tstr = strrchr (temp, '.');
+ if (tstr)
+ {
+ t = savestring (tstr);
+ free (temp);
+ temp = t;
+ }
+ break;
+
+ /* :s/this/that substitutes `that' for the first
+ occurrence of `this'. :gs/this/that substitutes `that'
+ for each occurrence of `this'. :& repeats the last
+ substitution. :g& repeats the last substitution
+ globally. */
+
+ case '&':
+ case 's':
+ {
+ char *new_event, *t;
+ int delimiter, failed, si, l_temp;
+
+ if (c == 's')
+ {
+ if (i + 2 < (int)strlen (string))
+ delimiter = string[i + 2];
+ else
+ break; /* no search delimiter */
+
+ i += 3;
+
+ t = get_subst_pattern (string, &i, delimiter, 0, &subst_lhs_len);
+ /* An empty substitution lhs with no previous substitution
+ uses the last search string as the lhs. */
+ if (t)
+ {
+ FREE (subst_lhs);
+ subst_lhs = t;
+ }
+ else if (!subst_lhs)
+ {
+ if (search_string && *search_string)
+ {
+ subst_lhs = savestring (search_string);
+ subst_lhs_len = strlen (subst_lhs);
+ }
+ else
+ {
+ subst_lhs = (char *) NULL;
+ subst_lhs_len = 0;
+ }
+ }
+
+ FREE (subst_rhs);
+ subst_rhs = get_subst_pattern (string, &i, delimiter, 1, &subst_rhs_len);
+
+ /* If `&' appears in the rhs, it's supposed to be replaced
+ with the lhs. */
+ if (member ('&', subst_rhs))
+ postproc_subst_rhs ();
+ }
+ else
+ i += 2;
+
+ /* If there is no lhs, the substitution can't succeed. */
+ if (subst_lhs_len == 0)
+ {
+ *ret_string = hist_error (string, starting_index, i, NO_PREV_SUBST);
+ free (result);
+ free (temp);
+ return -1;
+ }
+
+ l_temp = strlen (temp);
+ /* Ignore impossible cases. */
+ if (subst_lhs_len > l_temp)
+ {
+ *ret_string = hist_error (string, starting_index, i, SUBST_FAILED);
+ free (result);
+ free (temp);
+ return (-1);
+ }
+
+ /* Find the first occurrence of THIS in TEMP. */
+ si = 0;
+ for (failed = 1; (si + subst_lhs_len) <= l_temp; si++)
+ if (STREQN (temp+si, subst_lhs, subst_lhs_len))
+ {
+ int len = subst_rhs_len - subst_lhs_len + l_temp;
+ new_event = xmalloc (1 + len);
+ strncpy (new_event, temp, si);
+ strncpy (new_event + si, subst_rhs, subst_rhs_len);
+ strncpy (new_event + si + subst_rhs_len,
+ temp + si + subst_lhs_len,
+ l_temp - (si + subst_lhs_len));
+ new_event[len] = '\0';
+ free (temp);
+ temp = new_event;
+
+ failed = 0;
+
+ if (substitute_globally)
+ {
+ si += subst_rhs_len;
+ l_temp = strlen (temp);
+ substitute_globally++;
+ continue;
+ }
+ else
+ break;
+ }
+
+ if (substitute_globally > 1)
+ {
+ substitute_globally = 0;
+ continue; /* don't want to increment i */
+ }
+
+ if (failed == 0)
+ continue; /* don't want to increment i */
+
+ *ret_string = hist_error (string, starting_index, i, SUBST_FAILED);
+ free (result);
+ free (temp);
+ return (-1);
+ }
+ }
+ i += 2;
+ }
+ /* Done with modfiers. */
+ /* Believe it or not, we have to back the pointer up by one. */
+ --i;
+
+ if (want_quotes)
+ {
+ char *x;
+
+ if (want_quotes == 'q')
+ x = single_quote (temp);
+ else if (want_quotes == 'x')
+ x = quote_breaks (temp);
+ else
+ x = savestring (temp);
+
+ free (temp);
+ temp = x;
+ }
+
+ n = strlen (temp);
+ if (n >= result_len)
+ result = xrealloc (result, n + 2);
+ strcpy (result, temp);
+ free (temp);
+
+ *end_index_ptr = i;
+ *ret_string = result;
+ return (print_only);
+}
+
+/* Expand the string STRING, placing the result into OUTPUT, a pointer
+ to a string. Returns:
+
+ -1) If there was an error in expansion.
+ 0) If no expansions took place (or, if the only change in
+ the text was the de-slashifying of the history expansion
+ character)
+ 1) If expansions did take place
+ 2) If the `p' modifier was given and the caller should print the result
+
+ If an error ocurred in expansion, then OUTPUT contains a descriptive
+ error message. */
+
+#define ADD_STRING(s) \
+ do \
+ { \
+ int sl = strlen (s); \
+ j += sl; \
+ if (j >= result_len) \
+ { \
+ while (j >= result_len) \
+ result_len += 128; \
+ result = xrealloc (result, result_len); \
+ } \
+ strcpy (result + j - sl, s); \
+ } \
+ while (0)
+
+#define ADD_CHAR(c) \
+ do \
+ { \
+ if (j >= result_len - 1) \
+ result = xrealloc (result, result_len += 64); \
+ result[j++] = c; \
+ result[j] = '\0'; \
+ } \
+ while (0)
+
+int
+history_expand (hstring, output)
+ char *hstring;
+ char **output;
+{
+ register int j;
+ int i, r, l, passc, cc, modified, eindex, only_printing;
+ char *string;
+
+ /* The output string, and its length. */
+ int result_len;
+ char *result;
+
+ /* Used when adding the string. */
+ char *temp;
+
+ /* Setting the history expansion character to 0 inhibits all
+ history expansion. */
+ if (history_expansion_char == 0)
+ {
+ *output = savestring (hstring);
+ return (0);
+ }
+
+ /* Prepare the buffer for printing error messages. */
+ result = xmalloc (result_len = 256);
+ result[0] = '\0';
+
+ only_printing = modified = 0;
+ l = strlen (hstring);
+
+ /* Grovel the string. Only backslash and single quotes can quote the
+ history escape character. We also handle arg specifiers. */
+
+ /* Before we grovel forever, see if the history_expansion_char appears
+ anywhere within the text. */
+
+ /* The quick substitution character is a history expansion all right. That
+ is to say, "^this^that^" is equivalent to "!!:s^this^that^", and in fact,
+ that is the substitution that we do. */
+ if (hstring[0] == history_subst_char)
+ {
+ string = xmalloc (l + 5);
+
+ string[0] = string[1] = history_expansion_char;
+ string[2] = ':';
+ string[3] = 's';
+ strcpy (string + 4, hstring);
+ l += 4;
+ }
+ else
+ {
+ string = hstring;
+ /* If not quick substitution, still maybe have to do expansion. */
+
+ /* `!' followed by one of the characters in history_no_expand_chars
+ is NOT an expansion. */
+ for (i = 0; string[i]; i++)
+ {
+ cc = string[i + 1];
+ /* The history_comment_char, if set, appearing that the beginning
+ of a word signifies that the rest of the line should not have
+ history expansion performed on it.
+ Skip the rest of the line and break out of the loop. */
+ if (history_comment_char && string[i] == history_comment_char &&
+ (i == 0 || member (string[i - 1], HISTORY_WORD_DELIMITERS)))
+ {
+ while (string[i])
+ i++;
+ break;
+ }
+ else if (string[i] == history_expansion_char)
+ {
+ if (!cc || member (cc, history_no_expand_chars))
+ continue;
+ /* If the calling application has set
+ history_inhibit_expansion_function to a function that checks
+ for special cases that should not be history expanded,
+ call the function and skip the expansion if it returns a
+ non-zero value. */
+ else if (history_inhibit_expansion_function &&
+ (*history_inhibit_expansion_function) (string, i))
+ continue;
+ else
+ break;
+ }
+ /* XXX - at some point, might want to extend this to handle
+ double quotes as well. */
+ else if (history_quotes_inhibit_expansion && string[i] == '\'')
+ {
+ /* If this is bash, single quotes inhibit history expansion. */
+ i++;
+ hist_string_extract_single_quoted (string, &i);
+ }
+ else if (history_quotes_inhibit_expansion && string[i] == '\\')
+ {
+ /* If this is bash, allow backslashes to quote single
+ quotes and the history expansion character. */
+ if (cc == '\'' || cc == history_expansion_char)
+ i++;
+ }
+ }
+
+ if (string[i] != history_expansion_char)
+ {
+ free (result);
+ *output = savestring (string);
+ return (0);
+ }
+ }
+
+ /* Extract and perform the substitution. */
+ for (passc = i = j = 0; i < l; i++)
+ {
+ int tchar = string[i];
+
+ if (passc)
+ {
+ passc = 0;
+ ADD_CHAR (tchar);
+ continue;
+ }
+
+ if (tchar == history_expansion_char)
+ tchar = -3;
+ else if (tchar == history_comment_char)
+ tchar = -2;
+
+ switch (tchar)
+ {
+ default:
+ ADD_CHAR (string[i]);
+ break;
+
+ case '\\':
+ passc++;
+ ADD_CHAR (tchar);
+ break;
+
+ case '\'':
+ {
+ /* If history_quotes_inhibit_expansion is set, single quotes
+ inhibit history expansion. */
+ if (history_quotes_inhibit_expansion)
+ {
+ int quote, slen;
+
+ quote = i++;
+ hist_string_extract_single_quoted (string, &i);
+
+ slen = i - quote + 2;
+ temp = xmalloc (slen);
+ strncpy (temp, string + quote, slen);
+ temp[slen - 1] = '\0';
+ ADD_STRING (temp);
+ free (temp);
+ }
+ else
+ ADD_CHAR (string[i]);
+ break;
+ }
+
+ case -2: /* history_comment_char */
+ if (i == 0 || member (string[i - 1], HISTORY_WORD_DELIMITERS))
+ {
+ temp = xmalloc (l - i + 1);
+ strcpy (temp, string + i);
+ ADD_STRING (temp);
+ free (temp);
+ i = l;
+ }
+ else
+ ADD_CHAR (string[i]);
+ break;
+
+ case -3: /* history_expansion_char */
+ cc = string[i + 1];
+
+ /* If the history_expansion_char is followed by one of the
+ characters in history_no_expand_chars, then it is not a
+ candidate for expansion of any kind. */
+ if (member (cc, history_no_expand_chars))
+ {
+ ADD_CHAR (string[i]);
+ break;
+ }
+
+#if defined (NO_BANG_HASH_MODIFIERS)
+ /* There is something that is listed as a `word specifier' in csh
+ documentation which means `the expanded text to this point'.
+ That is not a word specifier, it is an event specifier. If we
+ don't want to allow modifiers with `!#', just stick the current
+ output line in again. */
+ if (cc == '#')
+ {
+ if (result)
+ {
+ temp = xmalloc (1 + strlen (result));
+ strcpy (temp, result);
+ ADD_STRING (temp);
+ free (temp);
+ }
+ i++;
+ break;
+ }
+#endif
+
+ r = history_expand_internal (string, i, &eindex, &temp, result);
+ if (r < 0)
+ {
+ *output = temp;
+ free (result);
+ if (string != hstring)
+ free (string);
+ return -1;
+ }
+ else
+ {
+ if (temp)
+ {
+ modified++;
+ if (*temp)
+ ADD_STRING (temp);
+ free (temp);
+ }
+ only_printing = r == 1;
+ i = eindex;
+ }
+ break;
+ }
+ }
+
+ *output = result;
+ if (string != hstring)
+ free (string);
+
+ if (only_printing)
+ {
+ add_history (result);
+ return (2);
+ }
+
+ return (modified != 0);
+}
+
+/* Return a consed string which is the word specified in SPEC, and found
+ in FROM. NULL is returned if there is no spec. The address of
+ ERROR_POINTER is returned if the word specified cannot be found.
+ CALLER_INDEX is the offset in SPEC to start looking; it is updated
+ to point to just after the last character parsed. */
+static char *
+get_history_word_specifier (spec, from, caller_index)
+ char *spec, *from;
+ int *caller_index;
+{
+ register int i = *caller_index;
+ int first, last;
+ int expecting_word_spec = 0;
+ char *result;
+
+ /* The range of words to return doesn't exist yet. */
+ first = last = 0;
+ result = (char *)NULL;
+
+ /* If we found a colon, then this *must* be a word specification. If
+ it isn't, then it is an error. */
+ if (spec[i] == ':')
+ {
+ i++;
+ expecting_word_spec++;
+ }
+
+ /* Handle special cases first. */
+
+ /* `%' is the word last searched for. */
+ if (spec[i] == '%')
+ {
+ *caller_index = i + 1;
+ return (search_match ? savestring (search_match) : savestring (""));
+ }
+
+ /* `*' matches all of the arguments, but not the command. */
+ if (spec[i] == '*')
+ {
+ *caller_index = i + 1;
+ result = history_arg_extract (1, '$', from);
+ return (result ? result : savestring (""));
+ }
+
+ /* `$' is last arg. */
+ if (spec[i] == '$')
+ {
+ *caller_index = i + 1;
+ return (history_arg_extract ('$', '$', from));
+ }
+
+ /* Try to get FIRST and LAST figured out. */
+
+ if (spec[i] == '-')
+ first = 0;
+ else if (spec[i] == '^')
+ first = 1;
+ else if (_rl_digit_p (spec[i]) && expecting_word_spec)
+ {
+ for (first = 0; _rl_digit_p (spec[i]); i++)
+ first = (first * 10) + _rl_digit_value (spec[i]);
+ }
+ else
+ return ((char *)NULL); /* no valid `first' for word specifier */
+
+ if (spec[i] == '^' || spec[i] == '*')
+ {
+ last = (spec[i] == '^') ? 1 : '$'; /* x* abbreviates x-$ */
+ i++;
+ }
+ else if (spec[i] != '-')
+ last = first;
+ else
+ {
+ i++;
+
+ if (_rl_digit_p (spec[i]))
+ {
+ for (last = 0; _rl_digit_p (spec[i]); i++)
+ last = (last * 10) + _rl_digit_value (spec[i]);
+ }
+ else if (spec[i] == '$')
+ {
+ i++;
+ last = '$';
+ }
+ else if (!spec[i] || spec[i] == ':') /* could be modifier separator */
+ last = -1; /* x- abbreviates x-$ omitting word `$' */
+ }
+
+ *caller_index = i;
+
+ if (last >= first || last == '$' || last < 0)
+ result = history_arg_extract (first, last, from);
+
+ return (result ? result : (char *)&error_pointer);
+}
+
+/* Extract the args specified, starting at FIRST, and ending at LAST.
+ The args are taken from STRING. If either FIRST or LAST is < 0,
+ then make that arg count from the right (subtract from the number of
+ tokens, so that FIRST = -1 means the next to last token on the line).
+ If LAST is `$' the last arg from STRING is used. */
+char *
+history_arg_extract (first, last, string)
+ int first, last;
+ char *string;
+{
+ register int i, len;
+ char *result;
+ int size, offset;
+ char **list;
+
+ /* XXX - think about making history_tokenize return a struct array,
+ each struct in array being a string and a length to avoid the
+ calls to strlen below. */
+ if ((list = history_tokenize (string)) == NULL)
+ return ((char *)NULL);
+
+ for (len = 0; list[len]; len++)
+ ;
+
+ if (last < 0)
+ last = len + last - 1;
+
+ if (first < 0)
+ first = len + first - 1;
+
+ if (last == '$')
+ last = len - 1;
+
+ if (first == '$')
+ first = len - 1;
+
+ last++;
+
+ if (first >= len || last > len || first < 0 || last < 0 || first > last)
+ result = ((char *)NULL);
+ else
+ {
+ for (size = 0, i = first; i < last; i++)
+ size += strlen (list[i]) + 1;
+ result = xmalloc (size + 1);
+ result[0] = '\0';
+
+ for (i = first, offset = 0; i < last; i++)
+ {
+ strcpy (result + offset, list[i]);
+ offset += strlen (list[i]);
+ if (i + 1 < last)
+ {
+ result[offset++] = ' ';
+ result[offset] = 0;
+ }
+ }
+ }
+
+ for (i = 0; i < len; i++)
+ free (list[i]);
+ free (list);
+
+ return (result);
+}
+
+#define slashify_in_quotes "\\`\"$"
+
+/* Parse STRING into tokens and return an array of strings. If WIND is
+ not -1 and INDP is not null, we also want the word surrounding index
+ WIND. The position in the returned array of strings is returned in
+ *INDP. */
+static char **
+history_tokenize_internal (string, wind, indp)
+ char *string;
+ int wind, *indp;
+{
+ char **result;
+ register int i, start, result_index, size;
+ int len, delimiter;
+
+ /* Get a token, and stuff it into RESULT. The tokens are split
+ exactly where the shell would split them. */
+ for (i = result_index = size = 0, result = (char **)NULL; string[i]; )
+ {
+ delimiter = 0;
+
+ /* Skip leading whitespace. */
+ for (; string[i] && whitespace (string[i]); i++)
+ ;
+ if (string[i] == 0 || string[i] == history_comment_char)
+ return (result);
+
+ start = i;
+
+ if (member (string[i], "()\n"))
+ {
+ i++;
+ goto got_token;
+ }
+
+ if (member (string[i], "<>;&|$"))
+ {
+ int peek = string[i + 1];
+
+ if (peek == string[i] && peek != '$')
+ {
+ if (peek == '<' && string[i + 2] == '-')
+ i++;
+ i += 2;
+ goto got_token;
+ }
+ else
+ {
+ if ((peek == '&' && (string[i] == '>' || string[i] == '<')) ||
+ ((peek == '>') && (string[i] == '&')) ||
+ ((peek == '(') && (string[i] == '$')))
+ {
+ i += 2;
+ goto got_token;
+ }
+ }
+ if (string[i] != '$')
+ {
+ i++;
+ goto got_token;
+ }
+ }
+
+ /* Get word from string + i; */
+
+ if (member (string[i], HISTORY_QUOTE_CHARACTERS))
+ delimiter = string[i++];
+
+ for (; string[i]; i++)
+ {
+ if (string[i] == '\\' && string[i + 1] == '\n')
+ {
+ i++;
+ continue;
+ }
+
+ if (string[i] == '\\' && delimiter != '\'' &&
+ (delimiter != '"' || member (string[i], slashify_in_quotes)))
+ {
+ i++;
+ continue;
+ }
+
+ if (delimiter && string[i] == delimiter)
+ {
+ delimiter = 0;
+ continue;
+ }
+
+ if (!delimiter && (member (string[i], HISTORY_WORD_DELIMITERS)))
+ break;
+
+ if (!delimiter && member (string[i], HISTORY_QUOTE_CHARACTERS))
+ delimiter = string[i];
+ }
+
+ got_token:
+
+ /* If we are looking for the word in which the character at a
+ particular index falls, remember it. */
+ if (indp && wind != -1 && wind >= start && wind < i)
+ *indp = result_index;
+
+ len = i - start;
+ if (result_index + 2 >= size)
+ result = (char **)xrealloc (result, ((size += 10) * sizeof (char *)));
+ result[result_index] = xmalloc (1 + len);
+ strncpy (result[result_index], string + start, len);
+ result[result_index][len] = '\0';
+ result[++result_index] = (char *)NULL;
+ }
+
+ return (result);
+}
+
+/* Return an array of tokens, much as the shell might. The tokens are
+ parsed out of STRING. */
+char **
+history_tokenize (string)
+ char *string;
+{
+ return (history_tokenize_internal (string, -1, (int *)NULL));
+}
+
+/* Find and return the word which contains the character at index IND
+ in the history line LINE. Used to save the word matched by the
+ last history !?string? search. */
+static char *
+history_find_word (line, ind)
+ char *line;
+ int ind;
+{
+ char **words, *s;
+ int i, wind;
+
+ words = history_tokenize_internal (line, ind, &wind);
+ if (wind == -1)
+ return ((char *)NULL);
+ s = words[wind];
+ for (i = 0; i < wind; i++)
+ free (words[i]);
+ for (i = wind + 1; words[i]; i++)
+ free (words[i]);
+ free (words);
+ return s;
+}
diff --git a/readline/histfile.c b/readline/histfile.c
new file mode 100644
index 00000000000..3325b7fc1f7
--- /dev/null
+++ b/readline/histfile.c
@@ -0,0 +1,376 @@
+/* histfile.c - functions to manipulate the history file. */
+
+/* Copyright (C) 1989, 1992 Free Software Foundation, Inc.
+
+ This file contains the GNU History Library (the Library), a set of
+ routines for managing the text of previously typed lines.
+
+ The Library is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 1, or (at your option)
+ any later version.
+
+ The 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
+ General Public License for more details.
+
+ The GNU General Public License is often shipped with GNU software, and
+ is generally kept in a file called COPYING or LICENSE. If you do not
+ have a copy of the license, write to the Free Software Foundation,
+ 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* The goal is to make the implementation transparent, so that you
+ don't have to know what data types are used, just what functions
+ you can call. I think I have done that. */
+#define READLINE_LIBRARY
+
+#if defined (HAVE_CONFIG_H)
+# include <config.h>
+#endif
+
+#include <stdio.h>
+
+#include <sys/types.h>
+#ifndef _MINIX
+# include <sys/file.h>
+#endif
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#if defined (HAVE_STDLIB_H)
+# include <stdlib.h>
+#else
+# include "ansi_stdlib.h"
+#endif /* HAVE_STDLIB_H */
+
+#if defined (HAVE_UNISTD_H)
+# include <unistd.h>
+#endif
+
+#if defined (HAVE_STRING_H)
+# include <string.h>
+#else
+# include <strings.h>
+#endif /* !HAVE_STRING_H */
+
+#if defined (__EMX__)
+# ifndef O_BINARY
+# define O_BINARY 0
+# endif
+#else /* !__EMX__ */
+ /* If we're not compiling for __EMX__, we don't want this at all. Ever. */
+# undef O_BINARY
+# define O_BINARY 0
+#endif /* !__EMX__ */
+
+#include <errno.h>
+#if !defined (errno)
+extern int errno;
+#endif /* !errno */
+
+#include "history.h"
+#include "histlib.h"
+
+/* Functions imported from shell.c */
+extern char *get_env_value ();
+
+extern char *xmalloc (), *xrealloc ();
+
+/* Return the string that should be used in the place of this
+ filename. This only matters when you don't specify the
+ filename to read_history (), or write_history (). */
+static char *
+history_filename (filename)
+ char *filename;
+{
+ char *return_val, *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)
+ {
+ home = ".";
+ home_len = 1;
+ }
+ else
+ home_len = strlen (home);
+
+ return_val = xmalloc (2 + home_len + 8); /* strlen(".history") == 8 */
+ strcpy (return_val, home);
+ return_val[home_len] = '/';
+ strcpy (return_val + home_len + 1, ".history");
+
+ return (return_val);
+}
+
+/* Add the contents of FILENAME to the history list, a line at a time.
+ If FILENAME is NULL, then read from ~/.history. Returns 0 if
+ successful, or errno if not. */
+int
+read_history (filename)
+ char *filename;
+{
+ return (read_history_range (filename, 0, -1));
+}
+
+/* Read a range of lines from FILENAME, adding them to the history list.
+ Start reading at the FROM'th line and end at the TO'th. If FROM
+ is zero, start at the beginning. If TO is less than FROM, read
+ until the end of the file. If FILENAME is NULL, then read from
+ ~/.history. Returns 0 if successful, or errno if not. */
+int
+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;
+
+ buffer = (char *)NULL;
+ input = history_filename (filename);
+ file = open (input, O_RDONLY|O_BINARY, 0666);
+
+ if ((file < 0) || (fstat (file, &finfo) == -1))
+ goto error_and_exit;
+
+ file_size = (size_t)finfo.st_size;
+
+ /* check for overflow on very large files */
+ if (file_size != finfo.st_size || file_size + 1 < file_size)
+ {
+#if defined (EFBIG)
+ errno = EFBIG;
+#endif
+ goto error_and_exit;
+ }
+
+ buffer = xmalloc (file_size + 1);
+#if 0
+ if (read (file, buffer, file_size) != file_size)
+#else
+ if (read (file, buffer, file_size) < 0)
+#endif
+ {
+ error_and_exit:
+ if (file >= 0)
+ close (file);
+
+ FREE (input);
+ FREE (buffer);
+
+ return (errno);
+ }
+
+ close (file);
+
+ /* Set TO to larger than end of file if negative. */
+ if (to < 0)
+ to = file_size;
+
+ /* Start at beginning of file, work to end. */
+ line_start = line_end = current_line = 0;
+
+ /* Skip lines until we are at FROM. */
+ while (line_start < file_size && current_line < from)
+ {
+ for (line_end = line_start; line_end < file_size; line_end++)
+ if (buffer[line_end] == '\n')
+ {
+ current_line++;
+ line_start = line_end + 1;
+ if (current_line == from)
+ break;
+ }
+ }
+
+ /* If there are lines left to gobble, then gobble them now. */
+ for (line_end = line_start; line_end < file_size; line_end++)
+ if (buffer[line_end] == '\n')
+ {
+ buffer[line_end] = '\0';
+
+ if (buffer[line_start])
+ add_history (buffer + line_start);
+
+ current_line++;
+
+ if (current_line >= to)
+ break;
+
+ line_start = line_end + 1;
+ }
+
+ FREE (input);
+ FREE (buffer);
+
+ return (0);
+}
+
+/* Truncate the history file FNAME, leaving only LINES trailing lines.
+ If FNAME is NULL, then use ~/.history. */
+int
+history_truncate_file (fname, lines)
+ char *fname;
+ int lines;
+{
+ register int i;
+ int file, chars_read;
+ char *buffer, *filename;
+ struct stat finfo;
+ size_t file_size;
+
+ buffer = (char *)NULL;
+ filename = history_filename (fname);
+ file = open (filename, O_RDONLY|O_BINARY, 0666);
+
+ if (file == -1 || fstat (file, &finfo) == -1)
+ goto truncate_exit;
+
+ file_size = (size_t)finfo.st_size;
+
+ /* check for overflow on very large files */
+ if (file_size != finfo.st_size || file_size + 1 < file_size)
+ {
+ close (file);
+#if defined (EFBIG)
+ errno = EFBIG;
+#endif
+ goto truncate_exit;
+ }
+
+ buffer = xmalloc (file_size + 1);
+ chars_read = read (file, buffer, file_size);
+ close (file);
+
+ if (chars_read <= 0)
+ goto truncate_exit;
+
+ /* Count backwards from the end of buffer until we have passed
+ LINES lines. */
+ for (i = chars_read - 1; lines && i; i--)
+ {
+ if (buffer[i] == '\n')
+ lines--;
+ }
+
+ /* If this is the first line, then the file contains exactly the
+ number of lines we want to truncate to, so we don't need to do
+ anything. It's the first line if we don't find a newline between
+ the current value of i and 0. Otherwise, write from the start of
+ this line until the end of the buffer. */
+ for ( ; i; i--)
+ if (buffer[i] == '\n')
+ {
+ i++;
+ break;
+ }
+
+ /* Write only if there are more lines in the file than we want to
+ truncate to. */
+ if (i && ((file = open (filename, O_WRONLY|O_TRUNC|O_BINARY, 0600)) != -1))
+ {
+ write (file, buffer + i, file_size - i);
+
+#if defined (__BEOS__)
+ /* BeOS ignores O_TRUNC. */
+ ftruncate (file, file_size - i);
+#endif
+
+ close (file);
+ }
+
+ truncate_exit:
+
+ FREE (buffer);
+
+ free (filename);
+ return 0;
+}
+
+/* Workhorse function for writing history. Writes NELEMENT entries
+ from the history list to FILENAME. OVERWRITE is non-zero if you
+ wish to replace FILENAME with the entries. */
+static int
+history_do_write (filename, nelements, overwrite)
+ char *filename;
+ int nelements, overwrite;
+{
+ register int i;
+ char *output;
+ int file, mode;
+
+ mode = overwrite ? O_WRONLY|O_CREAT|O_TRUNC|O_BINARY : O_WRONLY|O_APPEND|O_BINARY;
+ output = history_filename (filename);
+
+ if ((file = open (output, mode, 0600)) == -1)
+ {
+ FREE (output);
+ return (errno);
+ }
+
+ if (nelements > history_length)
+ nelements = history_length;
+
+ /* Build a buffer of all the lines to write, and write them in one syscall.
+ Suggested by Peter Ho (peter@robosts.oxford.ac.uk). */
+ {
+ HIST_ENTRY **the_history; /* local */
+ register int j;
+ int buffer_size;
+ char *buffer;
+
+ the_history = history_list ();
+ /* Calculate the total number of bytes to write. */
+ for (buffer_size = 0, i = history_length - nelements; i < history_length; i++)
+ buffer_size += 1 + strlen (the_history[i]->line);
+
+ /* Allocate the buffer, and fill it. */
+ buffer = xmalloc (buffer_size);
+
+ for (j = 0, i = history_length - nelements; i < history_length; i++)
+ {
+ strcpy (buffer + j, the_history[i]->line);
+ j += strlen (the_history[i]->line);
+ buffer[j++] = '\n';
+ }
+
+ write (file, buffer, buffer_size);
+ free (buffer);
+ }
+
+ close (file);
+
+ FREE (output);
+
+ return (0);
+}
+
+/* Append NELEMENT entries to FILENAME. The entries appended are from
+ the end of the list minus NELEMENTs up to the end of the list. */
+int
+append_history (nelements, filename)
+ int nelements;
+ char *filename;
+{
+ return (history_do_write (filename, nelements, HISTORY_APPEND));
+}
+
+/* Overwrite FILENAME with the current history. If FILENAME is NULL,
+ then write the history list to ~/.history. Values returned
+ are as in read_history ().*/
+int
+write_history (filename)
+ char *filename;
+{
+ return (history_do_write (filename, history_length, HISTORY_OVERWRITE));
+}
diff --git a/readline/histlib.h b/readline/histlib.h
new file mode 100644
index 00000000000..422cf5974db
--- /dev/null
+++ b/readline/histlib.h
@@ -0,0 +1,82 @@
+/* histlib.h -- internal definitions for the history library. */
+/* Copyright (C) 1989, 1992 Free Software Foundation, Inc.
+
+ This file contains the GNU History Library (the Library), a set of
+ routines for managing the text of previously typed lines.
+
+ The Library is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 1, or (at your option)
+ any later version.
+
+ The 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
+ General Public License for more details.
+
+ The GNU General Public License is often shipped with GNU software, and
+ is generally kept in a file called COPYING or LICENSE. If you do not
+ have a copy of the license, write to the Free Software Foundation,
+ 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#if !defined (_HISTLIB_H_)
+#define _HISTLIB_H_
+
+/* Function pointers can be declared as (Function *)foo. */
+#if !defined (_FUNCTION_DEF)
+# define _FUNCTION_DEF
+typedef int Function ();
+typedef void VFunction ();
+typedef char *CPFunction ();
+typedef char **CPPFunction ();
+#endif /* _FUNCTION_DEF */
+
+#define STREQ(a, b) (((a)[0] == (b)[0]) && (strcmp ((a), (b)) == 0))
+#define STREQN(a, b, n) (((a)[0] == (b)[0]) && (strncmp ((a), (b), (n)) == 0))
+
+#ifndef savestring
+# ifndef strcpy
+extern char *strcpy ();
+# endif
+#define savestring(x) strcpy (xmalloc (1 + strlen (x)), (x))
+#endif
+
+#ifndef whitespace
+#define whitespace(c) (((c) == ' ') || ((c) == '\t'))
+#endif
+
+#ifndef _rl_digit_p
+#define _rl_digit_p(c) ((c) >= '0' && (c) <= '9')
+#endif
+
+#ifndef _rl_digit_value
+#define _rl_digit_value(c) ((c) - '0')
+#endif
+
+#ifndef member
+# ifndef strchr
+extern char *strchr ();
+# endif
+#define member(c, s) ((c) ? ((char *)strchr ((s), (c)) != (char *)NULL) : 0)
+#endif
+
+#ifndef FREE
+# define FREE(x) if (x) free (x)
+#endif
+
+/* Possible history errors passed to hist_error. */
+#define EVENT_NOT_FOUND 0
+#define BAD_WORD_SPEC 1
+#define SUBST_FAILED 2
+#define BAD_MODIFIER 3
+#define NO_PREV_SUBST 4
+
+/* Possible definitions for history starting point specification. */
+#define ANCHORED_SEARCH 1
+#define NON_ANCHORED_SEARCH 0
+
+/* Possible definitions for what style of writing the history file we want. */
+#define HISTORY_APPEND 0
+#define HISTORY_OVERWRITE 1
+
+#endif /* !_HISTLIB_H_ */
diff --git a/readline/history.c b/readline/history.c
new file mode 100644
index 00000000000..d56ffacc6a0
--- /dev/null
+++ b/readline/history.c
@@ -0,0 +1,388 @@
+/* History.c -- standalone history library */
+
+/* Copyright (C) 1989, 1992 Free Software Foundation, Inc.
+
+ This file contains the GNU History Library (the Library), a set of
+ routines for managing the text of previously typed lines.
+
+ The Library is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 1, or (at your option)
+ any later version.
+
+ The 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
+ General Public License for more details.
+
+ The GNU General Public License is often shipped with GNU software, and
+ is generally kept in a file called COPYING or LICENSE. If you do not
+ have a copy of the license, write to the Free Software Foundation,
+ 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* The goal is to make the implementation transparent, so that you
+ don't have to know what data types are used, just what functions
+ you can call. I think I have done that. */
+#define READLINE_LIBRARY
+
+#if defined (HAVE_CONFIG_H)
+# include <config.h>
+#endif
+
+#include <stdio.h>
+
+#if defined (HAVE_STDLIB_H)
+# include <stdlib.h>
+#else
+# include "ansi_stdlib.h"
+#endif /* HAVE_STDLIB_H */
+
+#if defined (HAVE_UNISTD_H)
+# ifdef _MINIX
+# include <sys/types.h>
+# endif
+# include <unistd.h>
+#endif
+
+#if defined (HAVE_STRING_H)
+# include <string.h>
+#else
+# include <strings.h>
+#endif /* !HAVE_STRING_H */
+
+#include "history.h"
+#include "histlib.h"
+
+extern char *xmalloc (), *xrealloc ();
+
+/* The number of slots to increase the_history by. */
+#define DEFAULT_HISTORY_GROW_SIZE 50
+
+/* **************************************************************** */
+/* */
+/* History Functions */
+/* */
+/* **************************************************************** */
+
+/* An array of HIST_ENTRY. This is where we store the history. */
+static HIST_ENTRY **the_history = (HIST_ENTRY **)NULL;
+
+/* Non-zero means that we have enforced a limit on the amount of
+ history that we save. */
+static int history_stifled;
+
+/* If HISTORY_STIFLED is non-zero, then this is the maximum number of
+ entries to remember. */
+int max_input_history;
+
+/* The current location of the interactive history pointer. Just makes
+ life easier for outside callers. */
+int history_offset;
+
+/* The number of strings currently stored in the history list. */
+int history_length;
+
+/* The current number of slots allocated to the input_history. */
+static int history_size;
+
+/* The logical `base' of the history array. It defaults to 1. */
+int history_base = 1;
+
+/* Return the current HISTORY_STATE of the history. */
+HISTORY_STATE *
+history_get_history_state ()
+{
+ HISTORY_STATE *state;
+
+ state = (HISTORY_STATE *)xmalloc (sizeof (HISTORY_STATE));
+ state->entries = the_history;
+ state->offset = history_offset;
+ state->length = history_length;
+ state->size = history_size;
+ state->flags = 0;
+ if (history_stifled)
+ state->flags |= HS_STIFLED;
+
+ return (state);
+}
+
+/* Set the state of the current history array to STATE. */
+void
+history_set_history_state (state)
+ HISTORY_STATE *state;
+{
+ the_history = state->entries;
+ history_offset = state->offset;
+ history_length = state->length;
+ history_size = state->size;
+ if (state->flags & HS_STIFLED)
+ history_stifled = 1;
+}
+
+/* Begin a session in which the history functions might be used. This
+ initializes interactive variables. */
+void
+using_history ()
+{
+ history_offset = history_length;
+}
+
+/* Return the number of bytes that the primary history entries are using.
+ This just adds up the lengths of the_history->lines. */
+int
+history_total_bytes ()
+{
+ register int i, result;
+
+ result = 0;
+
+ for (i = 0; the_history && the_history[i]; i++)
+ result += strlen (the_history[i]->line);
+
+ return (result);
+}
+
+/* Returns the magic number which says what history element we are
+ looking at now. In this implementation, it returns history_offset. */
+int
+where_history ()
+{
+ return (history_offset);
+}
+
+/* Make the current history item be the one at POS, an absolute index.
+ Returns zero if POS is out of range, else non-zero. */
+int
+history_set_pos (pos)
+ int pos;
+{
+ if (pos > history_length || pos < 0 || !the_history)
+ return (0);
+ 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. */
+HIST_ENTRY **
+history_list ()
+{
+ return (the_history);
+}
+
+/* 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 ()
+{
+ return ((history_offset == history_length) || the_history == 0)
+ ? (HIST_ENTRY *)NULL
+ : the_history[history_offset];
+}
+
+/* Back up history_offset to the previous history entry, and return
+ a pointer to that entry. If there is no previous entry then return
+ a NULL pointer. */
+HIST_ENTRY *
+previous_history ()
+{
+ return history_offset ? the_history[--history_offset] : (HIST_ENTRY *)NULL;
+}
+
+/* Move history_offset forward to the next history entry, and return
+ a pointer to that entry. If there is no next entry then return a
+ NULL pointer. */
+HIST_ENTRY *
+next_history ()
+{
+ return (history_offset == history_length) ? (HIST_ENTRY *)NULL : the_history[++history_offset];
+}
+
+/* Return the history entry which is logically at OFFSET in the history array.
+ OFFSET is relative to history_base. */
+HIST_ENTRY *
+history_get (offset)
+ int offset;
+{
+ int local_index;
+
+ local_index = offset - history_base;
+ return (local_index >= history_length || local_index < 0 || !the_history)
+ ? (HIST_ENTRY *)NULL
+ : the_history[local_index];
+}
+
+/* Place STRING at the end of the history list. The data field
+ is set to NULL. */
+void
+add_history (string)
+ char *string;
+{
+ HIST_ENTRY *temp;
+
+ if (history_stifled && (history_length == max_input_history))
+ {
+ register int i;
+
+ /* If the history is stifled, and history_length is zero,
+ and it equals max_input_history, we don't save items. */
+ if (history_length == 0)
+ return;
+
+ /* If there is something in the slot, then remove it. */
+ if (the_history[0])
+ {
+ free (the_history[0]->line);
+ free (the_history[0]);
+ }
+
+ /* Copy the rest of the entries, moving down one slot. */
+ for (i = 0; i < history_length; i++)
+ the_history[i] = the_history[i + 1];
+
+ history_base++;
+ }
+ else
+ {
+ if (history_size == 0)
+ {
+ history_size = DEFAULT_HISTORY_GROW_SIZE;
+ the_history = (HIST_ENTRY **)xmalloc (history_size * sizeof (HIST_ENTRY *));
+ history_length = 1;
+ }
+ else
+ {
+ if (history_length == (history_size - 1))
+ {
+ history_size += DEFAULT_HISTORY_GROW_SIZE;
+ the_history = (HIST_ENTRY **)
+ xrealloc (the_history, history_size * sizeof (HIST_ENTRY *));
+ }
+ history_length++;
+ }
+ }
+
+ temp = (HIST_ENTRY *)xmalloc (sizeof (HIST_ENTRY));
+ temp->line = savestring (string);
+ temp->data = (char *)NULL;
+
+ the_history[history_length] = (HIST_ENTRY *)NULL;
+ the_history[history_length - 1] = temp;
+}
+
+/* Make the history entry at WHICH have LINE and DATA. This returns
+ the old entry so you can dispose of the data. In the case of an
+ invalid WHICH, a NULL pointer is returned. */
+HIST_ENTRY *
+replace_history_entry (which, line, data)
+ int which;
+ char *line;
+ histdata_t data;
+{
+ HIST_ENTRY *temp = (HIST_ENTRY *)xmalloc (sizeof (HIST_ENTRY));
+ HIST_ENTRY *old_value;
+
+ if (which >= history_length)
+ return ((HIST_ENTRY *)NULL);
+
+ old_value = the_history[which];
+
+ temp->line = savestring (line);
+ temp->data = data;
+ the_history[which] = temp;
+
+ return (old_value);
+}
+
+/* Remove history element WHICH from the history. The removed
+ element is returned to you so you can free the line, data,
+ and containing structure. */
+HIST_ENTRY *
+remove_history (which)
+ int which;
+{
+ HIST_ENTRY *return_value;
+
+ if (which >= history_length || !history_length)
+ return_value = (HIST_ENTRY *)NULL;
+ else
+ {
+ register int i;
+ return_value = the_history[which];
+
+ for (i = which; i < history_length; i++)
+ the_history[i] = the_history[i + 1];
+
+ history_length--;
+ }
+
+ return (return_value);
+}
+
+/* Stifle the history list, remembering only MAX number of lines. */
+void
+stifle_history (max)
+ int max;
+{
+ if (max < 0)
+ max = 0;
+
+ if (history_length > max)
+ {
+ register int i, j;
+
+ /* This loses because we cannot free the data. */
+ for (i = 0, j = history_length - max; i < j; i++)
+ {
+ free (the_history[i]->line);
+ free (the_history[i]);
+ }
+
+ history_base = i;
+ for (j = 0, i = history_length - max; j < max; i++, j++)
+ the_history[j] = the_history[i];
+ the_history[j] = (HIST_ENTRY *)NULL;
+ history_length = j;
+ }
+
+ history_stifled = 1;
+ max_input_history = max;
+}
+
+/* Stop stifling the history. This returns the previous amount the
+ history was stifled by. The value is positive if the history was
+ stifled, negative if it wasn't. */
+int
+unstifle_history ()
+{
+ if (history_stifled)
+ {
+ history_stifled = 0;
+ return (-max_input_history);
+ }
+
+ return (max_input_history);
+}
+
+int
+history_is_stifled ()
+{
+ return (history_stifled);
+}
+
+void
+clear_history ()
+{
+ register int i;
+
+ /* This loses because we cannot free the data. */
+ for (i = 0; i < history_length; i++)
+ {
+ free (the_history[i]->line);
+ free (the_history[i]);
+ the_history[i] = (HIST_ENTRY *)NULL;
+ }
+
+ history_offset = history_length = 0;
+}
diff --git a/readline/history.h b/readline/history.h
new file mode 100644
index 00000000000..8ecce726779
--- /dev/null
+++ b/readline/history.h
@@ -0,0 +1,248 @@
+/* History.h -- the names of functions that you can call in history. */
+/* Copyright (C) 1989, 1992 Free Software Foundation, Inc.
+
+ This file contains the GNU History Library (the Library), a set of
+ routines for managing the text of previously typed lines.
+
+ The Library is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 1, or (at your option)
+ any later version.
+
+ The 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
+ General Public License for more details.
+
+ The GNU General Public License is often shipped with GNU software, and
+ is generally kept in a file called COPYING or LICENSE. If you do not
+ have a copy of the license, write to the Free Software Foundation,
+ 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef _HISTORY_H_
+#define _HISTORY_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if defined READLINE_LIBRARY
+# include "rlstdc.h"
+#else
+# include <readline/rlstdc.h>
+#endif
+
+#if !defined (_FUNCTION_DEF)
+# define _FUNCTION_DEF
+typedef int Function ();
+typedef void VFunction ();
+typedef char *CPFunction ();
+typedef char **CPPFunction ();
+#endif
+
+#ifdef __STDC__
+typedef void *histdata_t;
+#else
+typedef char *histdata_t;
+#endif
+
+/* The structure used to store a history entry. */
+typedef struct _hist_entry {
+ char *line;
+ histdata_t data;
+} HIST_ENTRY;
+
+/* A structure used to pass the current state of the history stuff around. */
+typedef struct _hist_state {
+ HIST_ENTRY **entries; /* Pointer to the entries themselves. */
+ int offset; /* The location pointer within this array. */
+ int length; /* Number of elements within this array. */
+ int size; /* Number of slots allocated to this array. */
+ int flags;
+} HISTORY_STATE;
+
+/* Flag values for the `flags' member of HISTORY_STATE. */
+#define HS_STIFLED 0x01
+
+/* Initialization and state management. */
+
+/* Begin a session in which the history functions might be used. This
+ just initializes the interactive variables. */
+extern void using_history __P((void));
+
+/* Return the current HISTORY_STATE of the history. */
+extern HISTORY_STATE *history_get_history_state __P((void));
+
+/* Set the state of the current history array to STATE. */
+extern void history_set_history_state __P((HISTORY_STATE *));
+
+/* Manage the history list. */
+
+/* Place STRING at the end of the history list.
+ The associated data field (if any) is set to NULL. */
+extern void add_history __P((char *));
+
+/* A reasonably useless function, only here for completeness. WHICH
+ is the magic number that tells us which element to delete. The
+ elements are numbered from 0. */
+extern HIST_ENTRY *remove_history __P((int));
+
+/* Make the history entry at WHICH have LINE and DATA. This returns
+ the old entry so you can dispose of the data. In the case of an
+ invalid WHICH, a NULL pointer is returned. */
+extern HIST_ENTRY *replace_history_entry __P((int, char *, histdata_t));
+
+/* Clear the history list and start over. */
+extern void clear_history __P((void));
+
+/* Stifle the history list, remembering only MAX number of entries. */
+extern void stifle_history __P((int));
+
+/* Stop stifling the history. This returns the previous amount the
+ history was stifled by. The value is positive if the history was
+ stifled, negative if it wasn't. */
+extern int unstifle_history __P((void));
+
+/* Return 1 if the history is stifled, 0 if it is not. */
+extern int history_is_stifled __P((void));
+
+/* Information about the history list. */
+
+/* Return a NULL terminated array of HIST_ENTRY which is the current input
+ history. Element 0 of this list is the beginning of time. If there
+ is no history, return NULL. */
+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));
+
+/* Return the history entry which is logically at OFFSET in the history
+ array. OFFSET is relative to history_base. */
+extern HIST_ENTRY *history_get __P((int));
+
+/* Return the number of bytes that the primary history entries are using.
+ This just adds up the lengths of the_history->lines. */
+extern int history_total_bytes __P((void));
+
+/* Moving around the history list. */
+
+/* Set the position in the history list to POS. */
+int history_set_pos __P((int));
+
+/* Back up history_offset to the previous history entry, and return
+ a pointer to that entry. If there is no previous entry, return
+ a NULL pointer. */
+extern HIST_ENTRY *previous_history __P((void));
+
+/* Move history_offset forward to the next item in the input_history,
+ and return the a pointer to that entry. If there is no next entry,
+ return a NULL pointer. */
+extern HIST_ENTRY *next_history __P((void));
+
+/* Searching the history list. */
+
+/* Search the history for STRING, starting at history_offset.
+ If DIRECTION < 0, then the search is through previous entries,
+ else through subsequent. If the string is found, then
+ current_history () is the history entry, and the value of this function
+ is the offset in the line of that history entry that the string was
+ found in. Otherwise, nothing is changed, and a -1 is returned. */
+extern int history_search __P((char *, int));
+
+/* Search the history for STRING, starting at history_offset.
+ The search is anchored: matching lines must begin with string.
+ DIRECTION is as in history_search(). */
+extern int history_search_prefix __P((char *, int));
+
+/* Search for STRING in the history list, starting at POS, an
+ absolute index into the list. DIR, if negative, says to search
+ backwards from POS, else forwards.
+ Returns the absolute index of the history element where STRING
+ was found, or -1 otherwise. */
+extern int history_search_pos __P((char *, int, int));
+
+/* Managing the history file. */
+
+/* Add the contents of FILENAME to the history list, a line at a time.
+ If FILENAME is NULL, then read from ~/.history. Returns 0 if
+ successful, or errno if not. */
+extern int read_history __P((char *));
+
+/* Read a range of lines from FILENAME, adding them to the history list.
+ Start reading at the FROM'th line and end at the TO'th. If FROM
+ is zero, start at the beginning. If TO is less than FROM, read
+ until the end of the file. If FILENAME is NULL, then read from
+ ~/.history. Returns 0 if successful, or errno if not. */
+extern int read_history_range __P((char *, int, int));
+
+/* Write the current history to FILENAME. If FILENAME is NULL,
+ then write the history list to ~/.history. Values returned
+ are as in read_history (). */
+extern int write_history __P((char *));
+
+/* Append NELEMENT entries to FILENAME. The entries appended are from
+ the end of the list minus NELEMENTs up to the end of the list. */
+int append_history __P((int, char *));
+
+/* Truncate the history file, leaving only the last NLINES lines. */
+extern int history_truncate_file __P((char *, int));
+
+/* History expansion. */
+
+/* Expand the string STRING, placing the result into OUTPUT, a pointer
+ to a string. Returns:
+
+ 0) If no expansions took place (or, if the only change in
+ the text was the de-slashifying of the history expansion
+ character)
+ 1) If expansions did take place
+ -1) If there was an error in expansion.
+ 2) If the returned line should just be printed.
+
+ If an error ocurred in expansion, then OUTPUT contains a descriptive
+ error message. */
+extern int history_expand __P((char *, char **));
+
+/* Extract a string segment consisting of the FIRST through LAST
+ arguments present in STRING. Arguments are broken up as in
+ the shell. */
+extern char *history_arg_extract __P((int, int, char *));
+
+/* Return the text of the history event beginning at the current
+ offset into STRING. Pass STRING with *INDEX equal to the
+ history_expansion_char that begins this specification.
+ DELIMITING_QUOTE is a character that is allowed to end the string
+ specification for what to search for in addition to the normal
+ characters `:', ` ', `\t', `\n', and sometimes `?'. */
+extern char *get_history_event __P((char *, int *, int));
+
+/* Return an array of tokens, much as the shell might. The tokens are
+ parsed out of STRING. */
+extern char **history_tokenize __P((char *));
+
+/* Exported history variables. */
+extern int history_base;
+extern int history_length;
+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 int history_quotes_inhibit_expansion;
+
+/* If set, this function is called to decide whether or not a particular
+ history expansion should be treated as a special case for the calling
+ application and not expanded. */
+extern Function *history_inhibit_expansion_function;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !_HISTORY_H_ */
diff --git a/readline/histsearch.c b/readline/histsearch.c
new file mode 100644
index 00000000000..7e98e950acb
--- /dev/null
+++ b/readline/histsearch.c
@@ -0,0 +1,200 @@
+/* histsearch.c -- searching the history list. */
+
+/* Copyright (C) 1989, 1992 Free Software Foundation, Inc.
+
+ This file contains the GNU History Library (the Library), a set of
+ routines for managing the text of previously typed lines.
+
+ The Library is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 1, or (at your option)
+ any later version.
+
+ The 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
+ General Public License for more details.
+
+ The GNU General Public License is often shipped with GNU software, and
+ is generally kept in a file called COPYING or LICENSE. If you do not
+ have a copy of the license, write to the Free Software Foundation,
+ 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#define READLINE_LIBRARY
+
+#if defined (HAVE_CONFIG_H)
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#if defined (HAVE_STDLIB_H)
+# include <stdlib.h>
+#else
+# include "ansi_stdlib.h"
+#endif /* HAVE_STDLIB_H */
+#if defined (HAVE_UNISTD_H)
+# ifdef _MINIX
+# include <sys/types.h>
+# endif
+# include <unistd.h>
+#endif
+#if defined (HAVE_STRING_H)
+# include <string.h>
+#else
+# include <strings.h>
+#endif /* !HAVE_STRING_H */
+
+#include "history.h"
+#include "histlib.h"
+
+/* Variables imported from other history library files. */
+extern int history_offset;
+
+/* The list of alternate characters that can delimit a history search
+ string. */
+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
+ through subsequent. If ANCHORED is non-zero, the string must
+ appear at the beginning of a history line, otherwise, the string
+ may appear anywhere in the line. If the string is found, then
+ current_history () is the history entry, and the value of this
+ function is the offset in the line of that history entry that the
+ string was found in. Otherwise, nothing is changed, and a -1 is
+ returned. */
+
+static int
+history_search_internal (string, direction, anchored)
+ char *string;
+ int direction, anchored;
+{
+ register int i, reverse;
+ register char *line;
+ register int line_index;
+ int string_len;
+ HIST_ENTRY **the_history; /* local */
+
+ i = history_offset;
+ reverse = (direction < 0);
+
+ /* Take care of trivial cases first. */
+ if (string == 0 || *string == '\0')
+ return (-1);
+
+ if (!history_length || ((i == history_length) && !reverse))
+ return (-1);
+
+ if (reverse && (i == history_length))
+ i--;
+
+#define NEXT_LINE() do { if (reverse) i--; else i++; } while (0)
+
+ the_history = history_list ();
+ string_len = strlen (string);
+ while (1)
+ {
+ /* Search each line in the history list for STRING. */
+
+ /* At limit for direction? */
+ if ((reverse && i < 0) || (!reverse && i == history_length))
+ return (-1);
+
+ line = the_history[i]->line;
+ line_index = strlen (line);
+
+ /* If STRING is longer than line, no match. */
+ if (string_len > line_index)
+ {
+ NEXT_LINE ();
+ continue;
+ }
+
+ /* Handle anchored searches first. */
+ if (anchored == ANCHORED_SEARCH)
+ {
+ if (STREQN (string, line, string_len))
+ {
+ history_offset = i;
+ return (0);
+ }
+
+ NEXT_LINE ();
+ continue;
+ }
+
+ /* Do substring search. */
+ if (reverse)
+ {
+ line_index -= string_len;
+
+ while (line_index >= 0)
+ {
+ if (STREQN (string, line + line_index, string_len))
+ {
+ history_offset = i;
+ return (line_index);
+ }
+ line_index--;
+ }
+ }
+ else
+ {
+ register int limit;
+
+ limit = line_index - string_len + 1;
+ line_index = 0;
+
+ while (line_index < limit)
+ {
+ if (STREQN (string, line + line_index, string_len))
+ {
+ history_offset = i;
+ return (line_index);
+ }
+ line_index++;
+ }
+ }
+ NEXT_LINE ();
+ }
+}
+
+/* Do a non-anchored search for STRING through the history in DIRECTION. */
+int
+history_search (string, direction)
+ char *string;
+ int direction;
+{
+ return (history_search_internal (string, direction, NON_ANCHORED_SEARCH));
+}
+
+/* Do an anchored search for string through the history in DIRECTION. */
+int
+history_search_prefix (string, direction)
+ char *string;
+ int direction;
+{
+ return (history_search_internal (string, direction, ANCHORED_SEARCH));
+}
+
+/* Search for STRING in the history list. DIR is < 0 for searching
+ backwards. POS is an absolute index into the history list at
+ which point to begin searching. */
+int
+history_search_pos (string, dir, pos)
+ char *string;
+ int dir, pos;
+{
+ int ret, old;
+
+ old = where_history ();
+ history_set_pos (pos);
+ if (history_search (string, dir) == -1)
+ {
+ history_set_pos (old);
+ return (-1);
+ }
+ ret = where_history ();
+ history_set_pos (old);
+ return ret;
+}
diff --git a/readline/input.c b/readline/input.c
new file mode 100644
index 00000000000..3b48483d262
--- /dev/null
+++ b/readline/input.c
@@ -0,0 +1,459 @@
+/* input.c -- character input functions for readline. */
+
+/* Copyright (C) 1994 Free Software Foundation, Inc.
+
+ This file is part of the GNU Readline Library, a library for
+ reading lines of text with interactive input and history editing.
+
+ The GNU Readline Library is free software; you can redistribute 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.
+
+ The GNU Readline 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 General Public License for more details.
+
+ The GNU General Public License is often shipped with GNU software, and
+ is generally kept in a file called COPYING or LICENSE. If you do not
+ have a copy of the license, write to the Free Software Foundation,
+ 675 Mass Ave, Cambridge, MA 02139, USA. */
+#define READLINE_LIBRARY
+
+#if defined (HAVE_CONFIG_H)
+# include <config.h>
+#endif
+
+#include <sys/types.h>
+#include <fcntl.h>
+#if defined (HAVE_SYS_FILE_H)
+# include <sys/file.h>
+#endif /* HAVE_SYS_FILE_H */
+
+#if defined (HAVE_UNISTD_H)
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+
+#if defined (HAVE_STDLIB_H)
+# include <stdlib.h>
+#else
+# include "ansi_stdlib.h"
+#endif /* HAVE_STDLIB_H */
+
+#if defined (HAVE_SELECT)
+# if !defined (HAVE_SYS_SELECT_H) || !defined (M_UNIX)
+# include <sys/time.h>
+# endif
+#endif /* HAVE_SELECT */
+#if defined (HAVE_SYS_SELECT_H)
+# include <sys/select.h>
+#endif
+
+#if defined (FIONREAD_IN_SYS_IOCTL)
+# include <sys/ioctl.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+
+#if !defined (errno)
+extern int errno;
+#endif /* !errno */
+
+/* System-specific feature definitions and include files. */
+#include "rldefs.h"
+
+/* Some standard library routines. */
+#include "readline.h"
+
+/* What kind of non-blocking I/O do we have? */
+#if !defined (O_NDELAY) && defined (O_NONBLOCK)
+# define O_NDELAY O_NONBLOCK /* Posix style */
+#endif
+
+/* Functions imported from other files in the library. */
+extern char *xmalloc (), *xrealloc ();
+
+/* Variables and functions from macro.c. */
+extern void _rl_add_macro_char ();
+extern void _rl_with_macro_input ();
+extern int _rl_next_macro_key ();
+extern int _rl_defining_kbd_macro;
+
+#if defined (VI_MODE)
+extern void _rl_vi_set_last ();
+extern int _rl_vi_textmod_command ();
+#endif /* VI_MODE */
+
+extern FILE *rl_instream, *rl_outstream;
+extern Function *rl_last_func;
+extern int rl_key_sequence_length;
+extern int rl_pending_input;
+extern int rl_editing_mode;
+
+extern Keymap _rl_keymap;
+
+extern int _rl_convert_meta_chars_to_ascii;
+
+#if defined (__GO32__)
+# include <pc.h>
+#endif /* __GO32__ */
+
+/* Non-null means it is a pointer to a function to run while waiting for
+ character input. */
+Function *rl_event_hook = (Function *)NULL;
+
+Function *rl_getc_function = rl_getc;
+
+/* **************************************************************** */
+/* */
+/* Character Input Buffering */
+/* */
+/* **************************************************************** */
+
+static int pop_index, push_index;
+static unsigned char ibuffer[512];
+static int ibuffer_len = sizeof (ibuffer) - 1;
+
+#define any_typein (push_index != pop_index)
+
+int
+_rl_any_typein ()
+{
+ return any_typein;
+}
+
+/* Return the amount of space available in the buffer for stuffing
+ characters. */
+static int
+ibuffer_space ()
+{
+ if (pop_index > push_index)
+ return (pop_index - push_index - 1);
+ else
+ return (ibuffer_len - (push_index - pop_index));
+}
+
+/* Get a key from the buffer of characters to be read.
+ Return the key in KEY.
+ Result is KEY if there was a key, or 0 if there wasn't. */
+static int
+rl_get_char (key)
+ int *key;
+{
+ if (push_index == pop_index)
+ return (0);
+
+ *key = ibuffer[pop_index++];
+
+ if (pop_index >= ibuffer_len)
+ pop_index = 0;
+
+ return (1);
+}
+
+/* Stuff KEY into the *front* of the input buffer.
+ Returns non-zero if successful, zero if there is
+ no space left in the buffer. */
+static int
+rl_unget_char (key)
+ int key;
+{
+ if (ibuffer_space ())
+ {
+ pop_index--;
+ if (pop_index < 0)
+ pop_index = ibuffer_len - 1;
+ ibuffer[pop_index] = key;
+ return (1);
+ }
+ return (0);
+}
+
+/* If a character is available to be read, then read it
+ and stuff it into IBUFFER. Otherwise, just return. */
+static void
+rl_gather_tyi ()
+{
+#if defined (__GO32__)
+ char input;
+
+ if (isatty (0) && kbhit () && ibuffer_space ())
+ {
+ int i;
+ i = (*rl_getc_function) (rl_instream);
+ rl_stuff_char (i);
+ }
+#else /* !__GO32__ */
+
+ int tty;
+ register int tem, result;
+ int chars_avail;
+ char input;
+#if defined(HAVE_SELECT)
+ fd_set readfds, exceptfds;
+ struct timeval timeout;
+#endif
+
+ tty = fileno (rl_instream);
+
+#if defined (HAVE_SELECT)
+ FD_ZERO (&readfds);
+ FD_ZERO (&exceptfds);
+ FD_SET (tty, &readfds);
+ FD_SET (tty, &exceptfds);
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 100000; /* 0.1 seconds */
+ if (select (tty + 1, &readfds, (fd_set *)NULL, &exceptfds, &timeout) <= 0)
+ return; /* Nothing to read. */
+#endif
+
+ result = -1;
+#if defined (FIONREAD)
+ result = ioctl (tty, FIONREAD, &chars_avail);
+#endif
+
+#if defined (O_NDELAY)
+ if (result == -1)
+ {
+ tem = fcntl (tty, F_GETFL, 0);
+
+ fcntl (tty, F_SETFL, (tem | O_NDELAY));
+ chars_avail = read (tty, &input, 1);
+
+ fcntl (tty, F_SETFL, tem);
+ if (chars_avail == -1 && errno == EAGAIN)
+ return;
+ }
+#endif /* O_NDELAY */
+
+ /* If there's nothing available, don't waste time trying to read
+ something. */
+ if (chars_avail <= 0)
+ return;
+
+ tem = ibuffer_space ();
+
+ if (chars_avail > tem)
+ chars_avail = tem;
+
+ /* One cannot read all of the available input. I can only read a single
+ character at a time, or else programs which require input can be
+ thwarted. If the buffer is larger than one character, I lose.
+ Damn! */
+ if (tem < ibuffer_len)
+ chars_avail = 0;
+
+ if (result != -1)
+ {
+ while (chars_avail--)
+ rl_stuff_char ((*rl_getc_function) (rl_instream));
+ }
+ else
+ {
+ if (chars_avail)
+ rl_stuff_char (input);
+ }
+#endif /* !__GO32__ */
+}
+
+/* Is there input available to be read on the readline input file
+ descriptor? Only works if the system has select(2) or FIONREAD. */
+int
+_rl_input_available ()
+{
+#if defined(HAVE_SELECT)
+ fd_set readfds, exceptfds;
+ struct timeval timeout;
+#endif
+#if defined(FIONREAD)
+ int chars_avail;
+#endif
+ int tty;
+
+ tty = fileno (rl_instream);
+
+#if defined (HAVE_SELECT)
+ FD_ZERO (&readfds);
+ FD_ZERO (&exceptfds);
+ FD_SET (tty, &readfds);
+ FD_SET (tty, &exceptfds);
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 100000; /* 0.1 seconds */
+ return (select (tty + 1, &readfds, (fd_set *)NULL, &exceptfds, &timeout) > 0);
+#endif
+
+#if defined (FIONREAD)
+ if (ioctl (tty, FIONREAD, &chars_avail) == 0)
+ return (chars_avail);
+#endif
+
+ return 0;
+}
+
+void
+_rl_insert_typein (c)
+ int c;
+{
+ int key, t, i;
+ char *string;
+
+ i = key = 0;
+ string = xmalloc (ibuffer_len + 1);
+ string[i++] = (char) c;
+
+ while ((t = rl_get_char (&key)) &&
+ _rl_keymap[key].type == ISFUNC &&
+ _rl_keymap[key].function == rl_insert)
+ string[i++] = key;
+
+ if (t)
+ rl_unget_char (key);
+
+ string[i] = '\0';
+ rl_insert_text (string);
+ free (string);
+}
+
+/* Add KEY to the buffer of characters to be read. Returns 1 if the
+ character was stuffed correctly; 0 otherwise. */
+int
+rl_stuff_char (key)
+ int key;
+{
+ if (ibuffer_space () == 0)
+ return 0;
+
+ if (key == EOF)
+ {
+ key = NEWLINE;
+ rl_pending_input = EOF;
+ }
+ ibuffer[push_index++] = key;
+ if (push_index >= ibuffer_len)
+ push_index = 0;
+
+ return 1;
+}
+
+/* Make C be the next command to be executed. */
+int
+rl_execute_next (c)
+ int c;
+{
+ rl_pending_input = c;
+ return 0;
+}
+
+/* **************************************************************** */
+/* */
+/* Character Input */
+/* */
+/* **************************************************************** */
+
+/* Read a key, including pending input. */
+int
+rl_read_key ()
+{
+ int c;
+
+ rl_key_sequence_length++;
+
+ if (rl_pending_input)
+ {
+ c = rl_pending_input;
+ rl_pending_input = 0;
+ }
+ else
+ {
+ /* If input is coming from a macro, then use that. */
+ if (c = _rl_next_macro_key ())
+ return (c);
+
+ /* If the user has an event function, then call it periodically. */
+ if (rl_event_hook)
+ {
+ while (rl_event_hook && rl_get_char (&c) == 0)
+ {
+ (*rl_event_hook) ();
+ rl_gather_tyi ();
+ }
+ }
+ else
+ {
+ if (rl_get_char (&c) == 0)
+ c = (*rl_getc_function) (rl_instream);
+ }
+ }
+
+ return (c);
+}
+
+int
+rl_getc (stream)
+ FILE *stream;
+{
+ int result, flags;
+ unsigned char c;
+
+#if defined (__GO32__)
+ if (isatty (0))
+ return (getkey () & 0x7F);
+#endif /* __GO32__ */
+
+ while (1)
+ {
+ result = read (fileno (stream), &c, sizeof (unsigned char));
+
+ if (result == sizeof (unsigned char))
+ return (c);
+
+ /* If zero characters are returned, then the file that we are
+ reading from is empty! Return EOF in that case. */
+ if (result == 0)
+ return (EOF);
+
+#if defined (__BEOS__)
+ if (errno == EINTR)
+ continue;
+#endif
+
+#if defined (EWOULDBLOCK)
+ if (errno == EWOULDBLOCK)
+ {
+ if ((flags = fcntl (fileno (stream), F_GETFL, 0)) < 0)
+ return (EOF);
+ if (flags & O_NDELAY)
+ {
+ flags &= ~O_NDELAY;
+ fcntl (fileno (stream), F_SETFL, flags);
+ continue;
+ }
+ continue;
+ }
+#endif /* EWOULDBLOCK */
+
+#if defined (_POSIX_VERSION) && defined (EAGAIN) && defined (O_NONBLOCK)
+ if (errno == EAGAIN)
+ {
+ if ((flags = fcntl (fileno (stream), F_GETFL, 0)) < 0)
+ return (EOF);
+ if (flags & O_NONBLOCK)
+ {
+ flags &= ~O_NONBLOCK;
+ fcntl (fileno (stream), F_SETFL, flags);
+ continue;
+ }
+ }
+#endif /* _POSIX_VERSION && EAGAIN && O_NONBLOCK */
+
+#if !defined (__GO32__)
+ /* If the error that we received was SIGINT, then try again,
+ this is simply an interrupted system call to read ().
+ Otherwise, some error ocurred, also signifying EOF. */
+ if (errno != EINTR)
+ return (EOF);
+#endif /* !__GO32__ */
+ }
+}
diff --git a/readline/isearch.c b/readline/isearch.c
new file mode 100644
index 00000000000..67279e18924
--- /dev/null
+++ b/readline/isearch.c
@@ -0,0 +1,449 @@
+/* **************************************************************** */
+/* */
+/* I-Search and Searching */
+/* */
+/* **************************************************************** */
+
+/* Copyright (C) 1987,1989 Free Software Foundation, Inc.
+
+ This file contains the Readline Library (the Library), a set of
+ routines for providing Emacs style line input to programs that ask
+ for it.
+
+ The Library is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 1, or (at your option)
+ any later version.
+
+ The 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
+ General Public License for more details.
+
+ The GNU General Public License is often shipped with GNU software, and
+ is generally kept in a file called COPYING or LICENSE. If you do not
+ have a copy of the license, write to the Free Software Foundation,
+ 675 Mass Ave, Cambridge, MA 02139, USA. */
+#define READLINE_LIBRARY
+
+#if defined (HAVE_CONFIG_H)
+# include <config.h>
+#endif
+
+#include <sys/types.h>
+
+#include <stdio.h>
+
+#if defined (HAVE_UNISTD_H)
+# include <unistd.h>
+#endif
+
+#if defined (HAVE_STDLIB_H)
+# include <stdlib.h>
+#else
+# include "ansi_stdlib.h"
+#endif
+
+#include "rldefs.h"
+#include "readline.h"
+#include "history.h"
+
+/* Variables exported to other files in the readline library. */
+unsigned char *_rl_isearch_terminators = (unsigned char *)NULL;
+
+/* Variables imported from other files in the readline library. */
+extern Keymap _rl_keymap;
+extern HIST_ENTRY *saved_line_for_history;
+extern int rl_line_buffer_len;
+extern int rl_point, rl_end;
+extern char *rl_line_buffer;
+
+extern int rl_execute_next ();
+extern void rl_extend_line_buffer ();
+
+extern int _rl_input_available ();
+
+extern char *xmalloc (), *xrealloc ();
+
+static int rl_search_history ();
+
+/* Last line found by the current incremental search, so we don't `find'
+ identical lines many times in a row. */
+static char *prev_line_found;
+
+/* Search backwards through the history looking for a string which is typed
+ interactively. Start with the current line. */
+int
+rl_reverse_search_history (sign, key)
+ int sign, key;
+{
+ return (rl_search_history (-sign, key));
+}
+
+/* Search forwards through the history looking for a string which is typed
+ interactively. Start with the current line. */
+int
+rl_forward_search_history (sign, key)
+ int sign, key;
+{
+ return (rl_search_history (sign, key));
+}
+
+/* Display the current state of the search in the echo-area.
+ SEARCH_STRING contains the string that is being searched for,
+ DIRECTION is zero for forward, or 1 for reverse,
+ WHERE is the history list number of the current line. If it is
+ -1, then this line is the starting one. */
+static void
+rl_display_search (search_string, reverse_p, where)
+ char *search_string;
+ int reverse_p, where;
+{
+ char *message;
+ int msglen, searchlen;
+
+ searchlen = (search_string && *search_string) ? strlen (search_string) : 0;
+
+ message = xmalloc (searchlen + 33);
+ msglen = 0;
+
+#if defined (NOTDEF)
+ if (where != -1)
+ {
+ sprintf (message, "[%d]", where + history_base);
+ msglen = strlen (message);
+ }
+#endif /* NOTDEF */
+
+ message[msglen++] = '(';
+
+ if (reverse_p)
+ {
+ strcpy (message + msglen, "reverse-");
+ msglen += 8;
+ }
+
+ strcpy (message + msglen, "i-search)`");
+ msglen += 10;
+
+ if (search_string)
+ {
+ strcpy (message + msglen, search_string);
+ msglen += searchlen;
+ }
+
+ strcpy (message + msglen, "': ");
+
+ rl_message ("%s", message, 0);
+ free (message);
+ (*rl_redisplay_function) ();
+}
+
+/* Search through the history looking for an interactively typed string.
+ This is analogous to i-search. We start the search in the current line.
+ DIRECTION is which direction to search; >= 0 means forward, < 0 means
+ backwards. */
+static int
+rl_search_history (direction, invoking_key)
+ int direction, invoking_key;
+{
+ /* The string that the user types in to search for. */
+ char *search_string;
+
+ /* The current length of SEARCH_STRING. */
+ int search_string_index;
+
+ /* The amount of space that SEARCH_STRING has allocated to it. */
+ int search_string_size;
+
+ /* The list of lines to search through. */
+ char **lines, *allocated_line;
+
+ /* The length of LINES. */
+ int hlen;
+
+ /* Where we get LINES from. */
+ HIST_ENTRY **hlist;
+
+ register int i;
+ int orig_point, orig_line, last_found_line;
+ int c, found, failed, sline_len;
+
+ /* The line currently being searched. */
+ char *sline;
+
+ /* Offset in that line. */
+ int line_index;
+
+ /* Non-zero if we are doing a reverse search. */
+ int reverse;
+
+ /* The list of characters which terminate the search, but are not
+ subsequently executed. If the variable isearch-terminators has
+ been set, we use that value, otherwise we use ESC and C-J. */
+ unsigned char *isearch_terminators;
+
+ orig_point = rl_point;
+ last_found_line = orig_line = where_history ();
+ reverse = direction < 0;
+ hlist = history_list ();
+ allocated_line = (char *)NULL;
+
+ isearch_terminators = _rl_isearch_terminators ? _rl_isearch_terminators
+ : (unsigned char *)"\033\012";
+
+ /* Create an arrary of pointers to the lines that we want to search. */
+ maybe_replace_line ();
+ i = 0;
+ if (hlist)
+ for (i = 0; hlist[i]; i++);
+
+ /* Allocate space for this many lines, +1 for the current input line,
+ and remember those lines. */
+ lines = (char **)xmalloc ((1 + (hlen = i)) * sizeof (char *));
+ for (i = 0; i < hlen; i++)
+ lines[i] = hlist[i]->line;
+
+ if (saved_line_for_history)
+ lines[i] = saved_line_for_history->line;
+ else
+ {
+ /* Keep track of this so we can free it. */
+ allocated_line = xmalloc (1 + strlen (rl_line_buffer));
+ strcpy (allocated_line, &rl_line_buffer[0]);
+ lines[i] = allocated_line;
+ }
+
+ hlen++;
+
+ /* The line where we start the search. */
+ i = orig_line;
+
+ rl_save_prompt ();
+
+ /* Initialize search parameters. */
+ search_string = xmalloc (search_string_size = 128);
+ *search_string = '\0';
+ search_string_index = 0;
+ prev_line_found = (char *)0; /* XXX */
+
+ /* Normalize DIRECTION into 1 or -1. */
+ direction = (direction >= 0) ? 1 : -1;
+
+ rl_display_search (search_string, reverse, -1);
+
+ sline = rl_line_buffer;
+ sline_len = strlen (sline);
+ line_index = rl_point;
+
+ found = failed = 0;
+ for (;;)
+ {
+ Function *f = (Function *)NULL;
+
+ /* Read a key and decide how to proceed. */
+ c = rl_read_key ();
+
+ if (_rl_keymap[c].type == ISFUNC)
+ {
+ f = _rl_keymap[c].function;
+
+ if (f == rl_reverse_search_history)
+ c = reverse ? -1 : -2;
+ else if (f == rl_forward_search_history)
+ c = !reverse ? -1 : -2;
+ }
+
+#if 0
+ /* Let NEWLINE (^J) terminate the search for people who don't like
+ using ESC. ^M can still be used to terminate the search and
+ immediately execute the command. */
+ if (c == ESC || c == NEWLINE)
+#else
+ /* The characters in isearch_terminators (set from the user-settable
+ variable isearch-terminators) are used to terminate the search but
+ not subsequently execute the character as a command. The default
+ value is "\033\012" (ESC and C-J). */
+ if (strchr (isearch_terminators, c))
+#endif
+ {
+ /* ESC still terminates the search, but if there is pending
+ input or if input arrives within 0.1 seconds (on systems
+ with select(2)) it is used as a prefix character
+ with rl_execute_next. WATCH OUT FOR THIS! This is intended
+ to allow the arrow keys to be used like ^F and ^B are used
+ to terminate the search and execute the movement command. */
+ if (c == ESC && _rl_input_available ()) /* XXX */
+ rl_execute_next (ESC);
+ break;
+ }
+
+ if (c >= 0 && (CTRL_CHAR (c) || META_CHAR (c) || c == RUBOUT) && c != CTRL ('G'))
+ {
+ rl_execute_next (c);
+ break;
+ }
+
+ switch (c)
+ {
+ case -1:
+ if (search_string_index == 0)
+ continue;
+ else if (reverse)
+ --line_index;
+ else if (line_index != sline_len)
+ ++line_index;
+ else
+ ding ();
+ break;
+
+ /* switch directions */
+ case -2:
+ direction = -direction;
+ reverse = direction < 0;
+ break;
+
+ case CTRL ('G'):
+ strcpy (rl_line_buffer, lines[orig_line]);
+ rl_point = orig_point;
+ rl_end = strlen (rl_line_buffer);
+ rl_restore_prompt();
+ rl_clear_message ();
+ if (allocated_line)
+ free (allocated_line);
+ free (lines);
+ return 0;
+
+#if 0
+ /* delete character from search string. */
+ case -3:
+ if (search_string_index == 0)
+ ding ();
+ else
+ {
+ search_string[--search_string_index] = '\0';
+ /* This is tricky. To do this right, we need to keep a
+ stack of search positions for the current search, with
+ sentinels marking the beginning and end. */
+ }
+ break;
+#endif
+
+ default:
+ /* Add character to search string and continue search. */
+ if (search_string_index + 2 >= search_string_size)
+ {
+ search_string_size += 128;
+ search_string = xrealloc (search_string, search_string_size);
+ }
+ search_string[search_string_index++] = c;
+ search_string[search_string_index] = '\0';
+ break;
+ }
+
+ for (found = failed = 0;;)
+ {
+ int limit = sline_len - search_string_index + 1;
+
+ /* Search the current line. */
+ while (reverse ? (line_index >= 0) : (line_index < limit))
+ {
+ if (STREQN (search_string, sline + line_index, search_string_index))
+ {
+ found++;
+ break;
+ }
+ else
+ line_index += direction;
+ }
+ if (found)
+ break;
+
+ /* Move to the next line, but skip new copies of the line
+ we just found and lines shorter than the string we're
+ searching for. */
+ do
+ {
+ /* Move to the next line. */
+ i += direction;
+
+ /* At limit for direction? */
+ if (reverse ? (i < 0) : (i == hlen))
+ {
+ failed++;
+ break;
+ }
+
+ /* We will need these later. */
+ sline = lines[i];
+ sline_len = strlen (sline);
+ }
+ while ((prev_line_found && STREQ (prev_line_found, lines[i])) ||
+ (search_string_index > sline_len));
+
+ if (failed)
+ break;
+
+ /* Now set up the line for searching... */
+ line_index = reverse ? sline_len - search_string_index : 0;
+ }
+
+ if (failed)
+ {
+ /* We cannot find the search string. Ding the bell. */
+ ding ();
+ i = last_found_line;
+ continue; /* XXX - was break */
+ }
+
+ /* We have found the search string. Just display it. But don't
+ actually move there in the history list until the user accepts
+ the location. */
+ if (found)
+ {
+ int line_len;
+
+ prev_line_found = lines[i];
+ line_len = strlen (lines[i]);
+
+ if (line_len >= rl_line_buffer_len)
+ rl_extend_line_buffer (line_len);
+
+ strcpy (rl_line_buffer, lines[i]);
+ rl_point = line_index;
+ rl_end = line_len;
+ last_found_line = i;
+ rl_display_search (search_string, reverse, (i == orig_line) ? -1 : i);
+ }
+ }
+
+ /* The searching is over. The user may have found the string that she
+ was looking for, or else she may have exited a failing search. If
+ LINE_INDEX is -1, then that shows that the string searched for was
+ not found. We use this to determine where to place rl_point. */
+
+ /* First put back the original state. */
+ strcpy (rl_line_buffer, lines[orig_line]);
+
+ rl_restore_prompt ();
+
+ /* Free the search string. */
+ free (search_string);
+
+ if (last_found_line < orig_line)
+ rl_get_previous_history (orig_line - last_found_line, 0);
+ else
+ rl_get_next_history (last_found_line - orig_line, 0);
+
+ /* If the string was not found, put point at the end of the line. */
+ if (line_index < 0)
+ line_index = strlen (rl_line_buffer);
+ rl_point = line_index;
+ rl_clear_message ();
+
+ if (allocated_line)
+ free (allocated_line);
+ free (lines);
+
+ return 0;
+}
diff --git a/readline/keymaps.c b/readline/keymaps.c
new file mode 100644
index 00000000000..c73666bf273
--- /dev/null
+++ b/readline/keymaps.c
@@ -0,0 +1,150 @@
+/* keymaps.c -- Functions and keymaps for the GNU Readline library. */
+
+/* Copyright (C) 1988,1989 Free Software Foundation, Inc.
+
+ This file is part of GNU Readline, a library for reading lines
+ of text with interactive input and history editing.
+
+ Readline is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 1, or (at your option) any
+ later version.
+
+ Readline is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Readline; see the file COPYING. If not, write to the Free
+ Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+#define READLINE_LIBRARY
+
+#if defined (HAVE_CONFIG_H)
+# include <config.h>
+#endif
+
+#if defined (HAVE_STDLIB_H)
+# include <stdlib.h>
+#else
+# include "ansi_stdlib.h"
+#endif /* HAVE_STDLIB_H */
+
+#include "rlconf.h"
+#include "keymaps.h"
+#include "emacs_keymap.c"
+
+#if defined (VI_MODE)
+#include "vi_keymap.c"
+#endif
+
+extern int rl_do_lowercase_version ();
+extern int rl_rubout (), rl_insert ();
+
+extern char *xmalloc (), *xrealloc ();
+
+/* **************************************************************** */
+/* */
+/* Functions for manipulating Keymaps. */
+/* */
+/* **************************************************************** */
+
+
+/* Return a new, empty keymap.
+ Free it with free() when you are done. */
+Keymap
+rl_make_bare_keymap ()
+{
+ register int i;
+ Keymap keymap = (Keymap)xmalloc (KEYMAP_SIZE * sizeof (KEYMAP_ENTRY));
+
+ for (i = 0; i < KEYMAP_SIZE; i++)
+ {
+ keymap[i].type = ISFUNC;
+ keymap[i].function = (Function *)NULL;
+ }
+
+ for (i = 'A'; i < ('Z' + 1); i++)
+ {
+ keymap[i].type = ISFUNC;
+ keymap[i].function = rl_do_lowercase_version;
+ }
+
+ return (keymap);
+}
+
+/* Return a new keymap which is a copy of MAP. */
+Keymap
+rl_copy_keymap (map)
+ Keymap map;
+{
+ register int i;
+ Keymap temp = rl_make_bare_keymap ();
+
+ for (i = 0; i < KEYMAP_SIZE; i++)
+ {
+ temp[i].type = map[i].type;
+ temp[i].function = map[i].function;
+ }
+ return (temp);
+}
+
+/* Return a new keymap with the printing characters bound to rl_insert,
+ the uppercase Meta characters bound to run their lowercase equivalents,
+ and the Meta digits bound to produce numeric arguments. */
+Keymap
+rl_make_keymap ()
+{
+ register int i;
+ Keymap newmap;
+
+ newmap = rl_make_bare_keymap ();
+
+ /* All ASCII printing characters are self-inserting. */
+ for (i = ' '; i < 127; i++)
+ newmap[i].function = rl_insert;
+
+ newmap[TAB].function = rl_insert;
+ newmap[RUBOUT].function = rl_rubout; /* RUBOUT == 127 */
+ newmap[CTRL('H')].function = rl_rubout;
+
+#if KEYMAP_SIZE > 128
+ /* Printing characters in some 8-bit character sets. */
+ for (i = 128; i < 160; i++)
+ newmap[i].function = rl_insert;
+
+ /* ISO Latin-1 printing characters should self-insert. */
+ for (i = 160; i < 256; i++)
+ newmap[i].function = rl_insert;
+#endif /* KEYMAP_SIZE > 128 */
+
+ return (newmap);
+}
+
+/* Free the storage associated with MAP. */
+void
+rl_discard_keymap (map)
+ Keymap map;
+{
+ int i;
+
+ if (!map)
+ return;
+
+ for (i = 0; i < KEYMAP_SIZE; i++)
+ {
+ switch (map[i].type)
+ {
+ case ISFUNC:
+ break;
+
+ case ISKMAP:
+ rl_discard_keymap ((Keymap)map[i].function);
+ break;
+
+ case ISMACR:
+ free ((char *)map[i].function);
+ break;
+ }
+ }
+}
diff --git a/readline/keymaps.h b/readline/keymaps.h
new file mode 100644
index 00000000000..5dff46f56c2
--- /dev/null
+++ b/readline/keymaps.h
@@ -0,0 +1,100 @@
+/* keymaps.h -- Manipulation of readline keymaps. */
+
+/* Copyright (C) 1987, 1989, 1992 Free Software Foundation, Inc.
+
+ This file is part of the GNU Readline Library, a library for
+ reading lines of text with interactive input and history editing.
+
+ The GNU Readline Library is free software; you can redistribute it
+ and/or modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 1, or
+ (at your option) any later version.
+
+ The GNU Readline 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 General Public License for more details.
+
+ The GNU General Public License is often shipped with GNU software, and
+ is generally kept in a file called COPYING or LICENSE. If you do not
+ have a copy of the license, write to the Free Software Foundation,
+ 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef _KEYMAPS_H_
+#define _KEYMAPS_H_
+
+#if defined (READLINE_LIBRARY)
+# include "rlstdc.h"
+# include "chardefs.h"
+#else
+# include <readline/rlstdc.h>
+# include <readline/chardefs.h>
+#endif
+
+#if !defined (_FUNCTION_DEF)
+# define _FUNCTION_DEF
+typedef int Function ();
+typedef void VFunction ();
+typedef char *CPFunction ();
+typedef char **CPPFunction ();
+#endif
+
+/* A keymap contains one entry for each key in the ASCII set.
+ Each entry consists of a type and a pointer.
+ FUNCTION is the address of a function to run, or the
+ address of a keymap to indirect through.
+ TYPE says which kind of thing FUNCTION is. */
+typedef struct _keymap_entry {
+ char type;
+ Function *function;
+} KEYMAP_ENTRY;
+
+/* This must be large enough to hold bindings for all of the characters
+ in a desired character set (e.g, 128 for ASCII, 256 for ISO Latin-x,
+ and so on). */
+#define KEYMAP_SIZE 256
+
+/* I wanted to make the above structure contain a union of:
+ union { Function *function; struct _keymap_entry *keymap; } value;
+ but this made it impossible for me to create a static array.
+ Maybe I need C lessons. */
+
+typedef KEYMAP_ENTRY KEYMAP_ENTRY_ARRAY[KEYMAP_SIZE];
+typedef KEYMAP_ENTRY *Keymap;
+
+/* The values that TYPE can have in a keymap entry. */
+#define ISFUNC 0
+#define ISKMAP 1
+#define ISMACR 2
+
+extern KEYMAP_ENTRY_ARRAY emacs_standard_keymap, emacs_meta_keymap, emacs_ctlx_keymap;
+extern KEYMAP_ENTRY_ARRAY vi_insertion_keymap, vi_movement_keymap;
+
+/* Return a new, empty keymap.
+ Free it with free() when you are done. */
+extern Keymap rl_make_bare_keymap __P((void));
+
+/* Return a new keymap which is a copy of MAP. */
+extern Keymap rl_copy_keymap __P((Keymap));
+
+/* Return a new keymap with the printing characters bound to rl_insert,
+ the lowercase Meta characters bound to run their equivalents, and
+ the Meta digits bound to produce numeric arguments. */
+extern Keymap rl_make_keymap __P((void));
+
+/* Free the storage associated with a keymap. */
+extern void rl_discard_keymap __P((Keymap));
+
+/* These functions actually appear in bind.c */
+
+/* Return the keymap corresponding to a given name. Names look like
+ `emacs' or `emacs-meta' or `vi-insert'. */
+extern Keymap rl_get_keymap_by_name __P((char *));
+
+/* Return the current keymap. */
+extern Keymap rl_get_keymap __P((void));
+
+/* Set the current keymap to MAP. */
+extern void rl_set_keymap __P((Keymap));
+
+#endif /* _KEYMAPS_H_ */
diff --git a/readline/kill.c b/readline/kill.c
new file mode 100644
index 00000000000..0b4714fafa8
--- /dev/null
+++ b/readline/kill.c
@@ -0,0 +1,639 @@
+/* kill.c -- kill ring management. */
+
+/* Copyright (C) 1994 Free Software Foundation, Inc.
+
+ This file is part of the GNU Readline Library, a library for
+ reading lines of text with interactive input and history editing.
+
+ The GNU Readline Library is free software; you can redistribute it
+ and/or modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 1, or
+ (at your option) any later version.
+
+ The GNU Readline 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 General Public License for more details.
+
+ The GNU General Public License is often shipped with GNU software, and
+ is generally kept in a file called COPYING or LICENSE. If you do not
+ have a copy of the license, write to the Free Software Foundation,
+ 675 Mass Ave, Cambridge, MA 02139, USA. */
+#define READLINE_LIBRARY
+
+#if defined (HAVE_CONFIG_H)
+# include <config.h>
+#endif
+
+#include <sys/types.h>
+
+#if defined (HAVE_UNISTD_H)
+# include <unistd.h> /* for _POSIX_VERSION */
+#endif /* HAVE_UNISTD_H */
+
+#if defined (HAVE_STDLIB_H)
+# include <stdlib.h>
+#else
+# include "ansi_stdlib.h"
+#endif /* HAVE_STDLIB_H */
+
+#include <stdio.h>
+
+/* System-specific feature definitions and include files. */
+#include "rldefs.h"
+
+/* Some standard library routines. */
+#include "readline.h"
+#include "history.h"
+
+extern int _rl_last_command_was_kill;
+extern int rl_editing_mode;
+extern int rl_explicit_arg;
+extern Function *rl_last_func;
+
+extern void _rl_init_argument ();
+extern int _rl_set_mark_at_pos ();
+extern void _rl_fix_point ();
+extern void _rl_abort_internal ();
+
+extern char *xmalloc (), *xrealloc ();
+
+/* **************************************************************** */
+/* */
+/* Killing Mechanism */
+/* */
+/* **************************************************************** */
+
+/* What we assume for a max number of kills. */
+#define DEFAULT_MAX_KILLS 10
+
+/* The real variable to look at to find out when to flush kills. */
+static int rl_max_kills = DEFAULT_MAX_KILLS;
+
+/* Where to store killed text. */
+static char **rl_kill_ring = (char **)NULL;
+
+/* Where we are in the kill ring. */
+static int rl_kill_index;
+
+/* How many slots we have in the kill ring. */
+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;
+{
+ return 0;
+}
+
+/* Add TEXT to the kill ring, allocating a new kill ring slot as necessary.
+ This uses TEXT directly, so the caller must not free it. If APPEND is
+ non-zero, and the last command was a kill, the text is appended to the
+ current kill ring slot, otherwise prepended. */
+static int
+_rl_copy_to_kill_ring (text, append)
+ char *text;
+ int append;
+{
+ char *old, *new;
+ int slot;
+
+ /* First, find the slot to work with. */
+ if (_rl_last_command_was_kill == 0)
+ {
+ /* Get a new slot. */
+ if (rl_kill_ring == 0)
+ {
+ /* If we don't have any defined, then make one. */
+ rl_kill_ring = (char **)
+ xmalloc (((rl_kill_ring_length = 1) + 1) * sizeof (char *));
+ rl_kill_ring[slot = 0] = (char *)NULL;
+ }
+ else
+ {
+ /* We have to add a new slot on the end, unless we have
+ exceeded the max limit for remembering kills. */
+ slot = rl_kill_ring_length;
+ if (slot == rl_max_kills)
+ {
+ register int i;
+ free (rl_kill_ring[0]);
+ for (i = 0; i < slot; i++)
+ rl_kill_ring[i] = rl_kill_ring[i + 1];
+ }
+ else
+ {
+ slot = rl_kill_ring_length += 1;
+ rl_kill_ring = (char **)xrealloc (rl_kill_ring, slot * sizeof (char *));
+ }
+ rl_kill_ring[--slot] = (char *)NULL;
+ }
+ }
+ else
+ slot = rl_kill_ring_length - 1;
+
+ /* If the last command was a kill, prepend or append. */
+ if (_rl_last_command_was_kill && rl_editing_mode != vi_mode)
+ {
+ old = rl_kill_ring[slot];
+ new = xmalloc (1 + strlen (old) + strlen (text));
+
+ if (append)
+ {
+ strcpy (new, old);
+ strcat (new, text);
+ }
+ else
+ {
+ strcpy (new, text);
+ strcat (new, old);
+ }
+ free (old);
+ free (text);
+ rl_kill_ring[slot] = new;
+ }
+ else
+ rl_kill_ring[slot] = text;
+
+ rl_kill_index = slot;
+ return 0;
+}
+
+/* The way to kill something. This appends or prepends to the last
+ kill, if the last command was a kill command. if FROM is less
+ than TO, then the text is appended, otherwise prepended. If the
+ last command was not a kill command, then a new slot is made for
+ this kill. */
+int
+rl_kill_text (from, to)
+ int from, to;
+{
+ char *text;
+
+ /* Is there anything to kill? */
+ if (from == to)
+ {
+ _rl_last_command_was_kill++;
+ return 0;
+ }
+
+ text = rl_copy_text (from, to);
+
+ /* Delete the copied text from the line. */
+ rl_delete_text (from, to);
+
+ _rl_copy_to_kill_ring (text, from < to);
+
+ _rl_last_command_was_kill++;
+ return 0;
+}
+
+/* Now REMEMBER! In order to do prepending or appending correctly, kill
+ commands always make rl_point's original position be the FROM argument,
+ and rl_point's extent be the TO argument. */
+
+/* **************************************************************** */
+/* */
+/* Killing Commands */
+/* */
+/* **************************************************************** */
+
+/* Delete the word at point, saving the text in the kill ring. */
+int
+rl_kill_word (count, key)
+ int count, key;
+{
+ int orig_point = rl_point;
+
+ if (count < 0)
+ return (rl_backward_kill_word (-count, key));
+ else
+ {
+ rl_forward_word (count, key);
+
+ if (rl_point != orig_point)
+ rl_kill_text (orig_point, rl_point);
+
+ rl_point = orig_point;
+ }
+ return 0;
+}
+
+/* Rubout the word before point, placing it on the kill ring. */
+int
+rl_backward_kill_word (count, ignore)
+ int count, ignore;
+{
+ int orig_point = rl_point;
+
+ if (count < 0)
+ return (rl_kill_word (-count, ignore));
+ else
+ {
+ rl_backward_word (count, ignore);
+
+ if (rl_point != orig_point)
+ rl_kill_text (orig_point, rl_point);
+ }
+ return 0;
+}
+
+/* Kill from here to the end of the line. If DIRECTION is negative, kill
+ back to the line start instead. */
+int
+rl_kill_line (direction, ignore)
+ int direction, ignore;
+{
+ int orig_point = rl_point;
+
+ if (direction < 0)
+ return (rl_backward_kill_line (1, ignore));
+ else
+ {
+ rl_end_of_line (1, ignore);
+ if (orig_point != rl_point)
+ rl_kill_text (orig_point, rl_point);
+ rl_point = orig_point;
+ }
+ return 0;
+}
+
+/* Kill backwards to the start of the line. If DIRECTION is negative, kill
+ forwards to the line end instead. */
+int
+rl_backward_kill_line (direction, ignore)
+ int direction, ignore;
+{
+ int orig_point = rl_point;
+
+ if (direction < 0)
+ return (rl_kill_line (1, ignore));
+ else
+ {
+ if (!rl_point)
+ ding ();
+ else
+ {
+ rl_beg_of_line (1, ignore);
+ rl_kill_text (orig_point, rl_point);
+ }
+ }
+ return 0;
+}
+
+/* Kill the whole line, no matter where point is. */
+int
+rl_kill_full_line (count, ignore)
+ int count, ignore;
+{
+ rl_begin_undo_group ();
+ rl_point = 0;
+ rl_kill_text (rl_point, rl_end);
+ rl_end_undo_group ();
+ return 0;
+}
+
+/* The next two functions mimic unix line editing behaviour, except they
+ save the deleted text on the kill ring. This is safer than not saving
+ it, and since we have a ring, nobody should get screwed. */
+
+/* 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;
+{
+ int orig_point;
+
+ if (rl_point == 0)
+ ding ();
+ else
+ {
+ orig_point = rl_point;
+ if (count <= 0)
+ count = 1;
+
+ while (count--)
+ {
+ while (rl_point && whitespace (rl_line_buffer[rl_point - 1]))
+ rl_point--;
+
+ while (rl_point && (whitespace (rl_line_buffer[rl_point - 1]) == 0))
+ rl_point--;
+ }
+
+ rl_kill_text (orig_point, rl_point);
+ }
+ return 0;
+}
+
+/* Here is C-u doing what Unix does. You don't *have* to use these
+ key-bindings. We have a choice of killing the entire line, or
+ killing from where we are to the start of the line. We choose the
+ latter, because if you are a Unix weenie, then you haven't backspaced
+ 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;
+{
+ if (rl_point == 0)
+ ding ();
+ else
+ {
+ rl_kill_text (rl_point, 0);
+ rl_point = 0;
+ }
+ return 0;
+}
+
+/* Copy the text in the `region' to the kill ring. If DELETE is non-zero,
+ delete the text from the line as well. */
+static int
+region_kill_internal (delete)
+ int delete;
+{
+ char *text;
+
+ if (rl_mark == rl_point)
+ {
+ _rl_last_command_was_kill++;
+ return 0;
+ }
+
+ text = rl_copy_text (rl_point, rl_mark);
+ if (delete)
+ rl_delete_text (rl_point, rl_mark);
+ _rl_copy_to_kill_ring (text, rl_point < rl_mark);
+
+ _rl_last_command_was_kill++;
+ return 0;
+}
+
+/* Copy the text in the region to the kill ring. */
+int
+rl_copy_region_to_kill (count, ignore)
+ int count, ignore;
+{
+ return (region_kill_internal (0));
+}
+
+/* Kill the text between the point and mark. */
+int
+rl_kill_region (count, ignore)
+ int count, ignore;
+{
+ int r;
+
+ r = region_kill_internal (1);
+ _rl_fix_point (1);
+ return r;
+}
+
+/* Copy COUNT words to the kill ring. DIR says which direction we look
+ to find the words. */
+static int
+_rl_copy_word_as_kill (count, dir)
+ int count, dir;
+{
+ int om, op, r;
+
+ om = rl_mark;
+ op = rl_point;
+
+ if (dir > 0)
+ rl_forward_word (count, 0);
+ else
+ rl_backward_word (count, 0);
+
+ rl_mark = rl_point;
+
+ if (dir > 0)
+ rl_backward_word (count, 0);
+ else
+ rl_forward_word (count, 0);
+
+ r = region_kill_internal (0);
+
+ rl_mark = om;
+ rl_point = op;
+
+ return r;
+}
+
+int
+rl_copy_forward_word (count, key)
+ int count, key;
+{
+ if (count < 0)
+ return (rl_copy_backward_word (-count, key));
+
+ return (_rl_copy_word_as_kill (count, 1));
+}
+
+int
+rl_copy_backward_word (count, key)
+ int count, key;
+{
+ if (count < 0)
+ return (rl_copy_forward_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;
+{
+ if (rl_kill_ring == 0)
+ {
+ _rl_abort_internal ();
+ return -1;
+ }
+
+ _rl_set_mark_at_pos (rl_point);
+ rl_insert_text (rl_kill_ring[rl_kill_index]);
+ return 0;
+}
+
+/* If the last command was yank, or yank_pop, and the text just
+ before point is identical to the current kill item, then
+ 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;
+{
+ int l, n;
+
+ if (((rl_last_func != rl_yank_pop) && (rl_last_func != rl_yank)) ||
+ !rl_kill_ring)
+ {
+ _rl_abort_internal ();
+ return -1;
+ }
+
+ l = strlen (rl_kill_ring[rl_kill_index]);
+ n = rl_point - l;
+ if (n >= 0 && STREQN (rl_line_buffer + n, rl_kill_ring[rl_kill_index], l))
+ {
+ rl_delete_text (n, rl_point);
+ rl_point = n;
+ rl_kill_index--;
+ if (rl_kill_index < 0)
+ rl_kill_index = rl_kill_ring_length - 1;
+ rl_yank (1, 0);
+ return 0;
+ }
+ else
+ {
+ _rl_abort_internal ();
+ return -1;
+ }
+}
+
+/* Yank the COUNTh argument from the previous history line, skipping
+ HISTORY_SKIP lines before looking for the `previous line'. */
+static int
+rl_yank_nth_arg_internal (count, ignore, history_skip)
+ int count, ignore, history_skip;
+{
+ register HIST_ENTRY *entry;
+ char *arg;
+ int i;
+
+ if (history_skip)
+ {
+ for (i = 0; i < history_skip; i++)
+ entry = previous_history ();
+ }
+
+ entry = previous_history ();
+ if (entry)
+ {
+ if (history_skip)
+ {
+ for (i = 0; i < history_skip; i++)
+ next_history ();
+ }
+ next_history ();
+ }
+ else
+ {
+ ding ();
+ return -1;
+ }
+
+ arg = history_arg_extract (count, count, entry->line);
+ if (!arg || !*arg)
+ {
+ ding ();
+ return -1;
+ }
+
+ rl_begin_undo_group ();
+
+#if defined (VI_MODE)
+ /* Vi mode always inserts a space before yanking the argument, and it
+ inserts it right *after* rl_point. */
+ if (rl_editing_mode == vi_mode)
+ {
+ rl_vi_append_mode (1, ignore);
+ rl_insert_text (" ");
+ }
+#endif /* VI_MODE */
+
+ rl_insert_text (arg);
+ free (arg);
+
+ rl_end_undo_group ();
+ return 0;
+}
+
+/* Yank the COUNTth argument from the previous history line. */
+int
+rl_yank_nth_arg (count, ignore)
+ int count, ignore;
+{
+ return (rl_yank_nth_arg_internal (count, ignore, 0));
+}
+
+/* Yank the last argument from the previous history line. This `knows'
+ how rl_yank_nth_arg treats a count of `$'. With an argument, this
+ behaves the same as rl_yank_nth_arg. */
+int
+rl_yank_last_arg (count, key)
+ int count, key;
+{
+ static int history_skip = 0;
+ static int explicit_arg_p = 0;
+ static int count_passed = 1;
+ static int direction = 1;
+ static int undo_needed = 0;
+ int retval;
+
+ if (rl_last_func != rl_yank_last_arg)
+ {
+ history_skip = 0;
+ explicit_arg_p = rl_explicit_arg;
+ count_passed = count;
+ direction = 1;
+ }
+ else
+ {
+ if (undo_needed)
+ rl_do_undo ();
+ if (count < 1)
+ direction = -direction;
+ history_skip += direction;
+ if (history_skip < 0)
+ history_skip = 0;
+ }
+
+ if (explicit_arg_p)
+ retval = rl_yank_nth_arg_internal (count_passed, key, history_skip);
+ else
+ retval = rl_yank_nth_arg_internal ('$', key, history_skip);
+
+ undo_needed = retval == 0;
+ return retval;
+}
+
+/* A special paste command for users of Cygnus's cygwin32. */
+#if defined (__CYGWIN32__)
+#include <windows.h>
+
+int
+rl_paste_from_clipboard (count, key)
+ int count, key;
+{
+ char *data, *ptr;
+ int len;
+
+ if (OpenClipboard (NULL) == 0)
+ return (0);
+
+ data = (char *)GetClipboardData (CF_TEXT);
+ if (data)
+ {
+ ptr = strchr (data, '\r');
+ if (ptr)
+ {
+ len = ptr - data;
+ ptr = xmalloc (len + 1);
+ ptr[len] = '\0';
+ strncpy (ptr, data, len);
+ }
+ else
+ ptr = data;
+ rl_insert_text (ptr);
+ if (ptr != data)
+ free (ptr);
+ CloseClipboard ();
+ }
+ return (0);
+}
+#endif /* __CYGWIN32__ */
diff --git a/readline/macro.c b/readline/macro.c
new file mode 100644
index 00000000000..f3c442b41c3
--- /dev/null
+++ b/readline/macro.c
@@ -0,0 +1,277 @@
+/* macro.c -- keyboard macros for readline. */
+
+/* Copyright (C) 1994 Free Software Foundation, Inc.
+
+ This file is part of the GNU Readline Library, a library for
+ reading lines of text with interactive input and history editing.
+
+ The GNU Readline Library is free software; you can redistribute it
+ and/or modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 1, or
+ (at your option) any later version.
+
+ The GNU Readline 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 General Public License for more details.
+
+ The GNU General Public License is often shipped with GNU software, and
+ is generally kept in a file called COPYING or LICENSE. If you do not
+ have a copy of the license, write to the Free Software Foundation,
+ 675 Mass Ave, Cambridge, MA 02139, USA. */
+#define READLINE_LIBRARY
+
+#if defined (HAVE_CONFIG_H)
+# include <config.h>
+#endif
+
+#include <sys/types.h>
+
+#if defined (HAVE_UNISTD_H)
+# include <unistd.h> /* for _POSIX_VERSION */
+#endif /* HAVE_UNISTD_H */
+
+#if defined (HAVE_STDLIB_H)
+# include <stdlib.h>
+#else
+# include "ansi_stdlib.h"
+#endif /* HAVE_STDLIB_H */
+
+#include <stdio.h>
+
+/* System-specific feature definitions and include files. */
+#include "rldefs.h"
+
+/* Some standard library routines. */
+#include "readline.h"
+#include "history.h"
+
+#define SWAP(s, e) do { int t; t = s; s = e; e = t; } while (0)
+
+/* Forward definitions. */
+void _rl_push_executing_macro (), _rl_pop_executing_macro ();
+void _rl_add_macro_char ();
+
+/* Extern declarations. */
+extern int rl_explicit_arg;
+extern int rl_key_sequence_length;
+
+extern void _rl_abort_internal ();
+
+extern char *xmalloc (), *xrealloc ();
+
+/* **************************************************************** */
+/* */
+/* Hacking Keyboard Macros */
+/* */
+/* **************************************************************** */
+
+/* Non-zero means to save keys that we dispatch on in a kbd macro. */
+int _rl_defining_kbd_macro = 0;
+
+/* The currently executing macro string. If this is non-zero,
+ then it is a malloc ()'ed string where input is coming from. */
+char *_rl_executing_macro = (char *)NULL;
+
+/* The offset in the above string to the next character to be read. */
+static int executing_macro_index;
+
+/* The current macro string being built. Characters get stuffed
+ in here by add_macro_char (). */
+static char *current_macro = (char *)NULL;
+
+/* The size of the buffer allocated to current_macro. */
+static int current_macro_size;
+
+/* The index at which characters are being added to current_macro. */
+static int current_macro_index;
+
+/* A structure used to save nested macro strings.
+ It is a linked list of string/index for each saved macro. */
+struct saved_macro {
+ struct saved_macro *next;
+ char *string;
+ int sindex;
+};
+
+/* The list of saved macros. */
+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_push_executing_macro ();
+ _rl_executing_macro = string;
+ executing_macro_index = 0;
+}
+
+/* Return the next character available from a macro, or 0 if
+ there are no macro characters. */
+int
+_rl_next_macro_key ()
+{
+ if (_rl_executing_macro == 0)
+ return (0);
+
+ if (_rl_executing_macro[executing_macro_index] == 0)
+ {
+ _rl_pop_executing_macro ();
+ return (_rl_next_macro_key ());
+ }
+
+ return (_rl_executing_macro[executing_macro_index++]);
+}
+
+/* Save the currently executing macro on a stack of saved macros. */
+void
+_rl_push_executing_macro ()
+{
+ struct saved_macro *saver;
+
+ saver = (struct saved_macro *)xmalloc (sizeof (struct saved_macro));
+ saver->next = macro_list;
+ saver->sindex = executing_macro_index;
+ saver->string = _rl_executing_macro;
+
+ macro_list = saver;
+}
+
+/* Discard the current macro, replacing it with the one
+ on the top of the stack of saved macros. */
+void
+_rl_pop_executing_macro ()
+{
+ struct saved_macro *macro;
+
+ if (_rl_executing_macro)
+ free (_rl_executing_macro);
+
+ _rl_executing_macro = (char *)NULL;
+ executing_macro_index = 0;
+
+ if (macro_list)
+ {
+ macro = macro_list;
+ _rl_executing_macro = macro_list->string;
+ executing_macro_index = macro_list->sindex;
+ macro_list = macro_list->next;
+ free (macro);
+ }
+}
+
+/* Add a character to the macro being built. */
+void
+_rl_add_macro_char (c)
+ int c;
+{
+ if (current_macro_index + 1 >= current_macro_size)
+ {
+ if (current_macro == 0)
+ current_macro = xmalloc (current_macro_size = 25);
+ else
+ current_macro = xrealloc (current_macro, current_macro_size += 25);
+ }
+
+ current_macro[current_macro_index++] = c;
+ current_macro[current_macro_index] = '\0';
+}
+
+void
+_rl_kill_kbd_macro ()
+{
+ if (current_macro)
+ {
+ free (current_macro);
+ current_macro = (char *) NULL;
+ }
+ current_macro_size = current_macro_index = 0;
+
+ if (_rl_executing_macro)
+ {
+ free (_rl_executing_macro);
+ _rl_executing_macro = (char *) NULL;
+ }
+ executing_macro_index = 0;
+
+ _rl_defining_kbd_macro = 0;
+}
+
+/* Begin defining a keyboard macro.
+ Keystrokes are recorded as they are executed.
+ End the definition with rl_end_kbd_macro ().
+ If a numeric argument was explicitly typed, then append this
+ 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;
+{
+ if (_rl_defining_kbd_macro)
+ {
+ _rl_abort_internal ();
+ return -1;
+ }
+
+ if (rl_explicit_arg)
+ {
+ if (current_macro)
+ _rl_with_macro_input (savestring (current_macro));
+ }
+ else
+ current_macro_index = 0;
+
+ _rl_defining_kbd_macro = 1;
+ return 0;
+}
+
+/* Stop defining a keyboard macro.
+ 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;
+{
+ if (_rl_defining_kbd_macro == 0)
+ {
+ _rl_abort_internal ();
+ return -1;
+ }
+
+ current_macro_index -= rl_key_sequence_length - 1;
+ current_macro[current_macro_index] = '\0';
+
+ _rl_defining_kbd_macro = 0;
+
+ return (rl_call_last_kbd_macro (--count, 0));
+}
+
+/* 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;
+{
+ if (current_macro == 0)
+ _rl_abort_internal ();
+
+ if (_rl_defining_kbd_macro)
+ {
+ ding (); /* no recursive macros */
+ current_macro[--current_macro_index] = '\0'; /* erase this char */
+ return 0;
+ }
+
+ while (count--)
+ _rl_with_macro_input (savestring (current_macro));
+ return 0;
+}
+
+void
+rl_push_macro_input (macro)
+ char *macro;
+{
+ _rl_with_macro_input (macro);
+}
diff --git a/readline/nls.c b/readline/nls.c
new file mode 100644
index 00000000000..f2d413d59d5
--- /dev/null
+++ b/readline/nls.c
@@ -0,0 +1,228 @@
+/* nls.c -- skeletal internationalization code. */
+
+/* Copyright (C) 1996 Free Software Foundation, Inc.
+
+ This file is part of the GNU Readline Library, a library for
+ reading lines of text with interactive input and history editing.
+
+ The GNU Readline Library is free software; you can redistribute it
+ and/or modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 1, or
+ (at your option) any later version.
+
+ The GNU Readline 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 General Public License for more details.
+
+ The GNU General Public License is often shipped with GNU software, and
+ is generally kept in a file called COPYING or LICENSE. If you do not
+ have a copy of the license, write to the Free Software Foundation,
+ 675 Mass Ave, Cambridge, MA 02139, USA. */
+#define READLINE_LIBRARY
+
+#if defined (HAVE_CONFIG_H)
+# include <config.h>
+#endif
+
+#include <sys/types.h>
+
+#if defined (HAVE_UNISTD_H)
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+
+#if defined (HAVE_STDLIB_H)
+# include <stdlib.h>
+#else
+# include "ansi_stdlib.h"
+#endif /* HAVE_STDLIB_H */
+
+#if defined (HAVE_LOCALE_H)
+# include <locale.h>
+#endif
+
+#include <ctype.h>
+
+#include "rldefs.h"
+
+extern int _rl_convert_meta_chars_to_ascii;
+extern int _rl_output_meta_chars;
+extern int _rl_meta_flag;
+
+/* Functions imported from shell.c */
+extern char *get_env_value ();
+
+#if !defined (HAVE_SETLOCALE)
+/* A list of legal values for the LANG or LC_CTYPE environment variables.
+ If a locale name in this list is the value for the LC_ALL, LC_CTYPE,
+ or LANG environment variable (using the first of those with a value),
+ readline eight-bit mode is enabled. */
+static char *legal_lang_values[] =
+{
+ "iso88591",
+ "iso88592",
+ "iso88593",
+ "iso88594",
+ "iso88595",
+ "iso88596",
+ "iso88597",
+ "iso88598",
+ "iso88599",
+ "iso885910",
+ "koi8r",
+ "koi8-r",
+ 0
+};
+
+static char *normalize_codeset ();
+static char *find_codeset ();
+#endif /* !HAVE_SETLOCALE */
+
+/* Check for LC_ALL, LC_CTYPE, and LANG and use the first with a value
+ to decide the defaults for 8-bit character input and output. Returns
+ 1 if we set eight-bit mode. */
+int
+_rl_init_eightbit ()
+{
+/* If we have setlocale(3), just check the current LC_CTYPE category
+ value, and go into eight-bit mode if it's not C or POSIX. */
+#if defined (HAVE_SETLOCALE)
+ char *t;
+
+ /* Set the LC_CTYPE locale category from environment variables. */
+ t = setlocale (LC_CTYPE, "");
+ if (t && *t && (t[0] != 'C' || t[1]) && (STREQ (t, "POSIX") == 0))
+ {
+ _rl_meta_flag = 1;
+ _rl_convert_meta_chars_to_ascii = 0;
+ _rl_output_meta_chars = 1;
+ return (1);
+ }
+ else
+ return (0);
+
+#else /* !HAVE_SETLOCALE */
+ char *lspec, *t;
+ int i;
+
+ /* We don't have setlocale. Finesse it. Check the environment for the
+ appropriate variables and set eight-bit mode if they have the right
+ values. */
+ lspec = get_env_value ("LC_ALL");
+ if (lspec == 0) lspec = get_env_value ("LC_CTYPE");
+ if (lspec == 0) lspec = get_env_value ("LANG");
+ if (lspec == 0 || (t = normalize_codeset (lspec)) == 0)
+ return (0);
+ for (i = 0; t && legal_lang_values[i]; i++)
+ if (STREQ (t, legal_lang_values[i]))
+ {
+ _rl_meta_flag = 1;
+ _rl_convert_meta_chars_to_ascii = 0;
+ _rl_output_meta_chars = 1;
+ break;
+ }
+ free (t);
+ return (legal_lang_values[i] ? 1 : 0);
+
+#endif /* !HAVE_SETLOCALE */
+}
+
+#if !defined (HAVE_SETLOCALE)
+static char *
+normalize_codeset (codeset)
+ char *codeset;
+{
+ size_t namelen, i;
+ int len, all_digits;
+ char *wp, *retval;
+
+ codeset = find_codeset (codeset, &namelen);
+
+ if (codeset == 0)
+ return (codeset);
+
+ all_digits = 1;
+ for (len = 0, i = 0; i < namelen; i++)
+ {
+ if (isalnum (codeset[i]))
+ {
+ len++;
+ all_digits &= isdigit (codeset[i]);
+ }
+ }
+
+ retval = (char *)malloc ((all_digits ? 3 : 0) + len + 1);
+ if (retval == 0)
+ return ((char *)0);
+
+ wp = retval;
+ /* Add `iso' to beginning of an all-digit codeset */
+ if (all_digits)
+ {
+ *wp++ = 'i';
+ *wp++ = 's';
+ *wp++ = 'o';
+ }
+
+ for (i = 0; i < namelen; i++)
+ if (isalpha (codeset[i]))
+ *wp++ = (isupper (codeset[i])) ? tolower (codeset[i]) : codeset[i];
+ else if (isdigit (codeset[i]))
+ *wp++ = codeset[i];
+ *wp = '\0';
+
+ return retval;
+}
+
+/* Isolate codeset portion of locale specification. */
+static char *
+find_codeset (name, lenp)
+ char *name;
+ size_t *lenp;
+{
+ char *cp, *language, *result;
+
+ cp = language = name;
+ result = (char *)0;
+
+ while (*cp && *cp != '_' && *cp != '@' && *cp != '+' && *cp != ',')
+ cp++;
+
+ /* This does not make sense: language has to be specified. As
+ an exception we allow the variable to contain only the codeset
+ name. Perhaps there are funny codeset names. */
+ if (language == cp)
+ {
+ *lenp = strlen (language);
+ result = language;
+ }
+ else
+ {
+ /* Next is the territory. */
+ if (*cp == '_')
+ do
+ ++cp;
+ while (*cp && *cp != '.' && *cp != '@' && *cp != '+' && *cp != ',' && *cp != '_');
+
+ /* Now, finally, is the codeset. */
+ result = cp;
+ if (*cp == '.')
+ do
+ ++cp;
+ while (*cp && *cp != '@');
+
+ if (cp - result > 2)
+ {
+ result++;
+ *lenp = cp - result;
+ }
+ else
+ {
+ *lenp = strlen (language);
+ result = language;
+ }
+ }
+
+ return result;
+}
+#endif /* !HAVE_SETLOCALE */
diff --git a/readline/parens.c b/readline/parens.c
new file mode 100644
index 00000000000..a500c0afac7
--- /dev/null
+++ b/readline/parens.c
@@ -0,0 +1,156 @@
+/* parens.c -- Implementation of matching parentheses feature. */
+
+/* Copyright (C) 1987, 1989, 1992 Free Software Foundation, Inc.
+
+ This file is part of the GNU Readline Library, a library for
+ reading lines of text with interactive input and history editing.
+
+ The GNU Readline Library is free software; you can redistribute it
+ and/or modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 1, or
+ (at your option) any later version.
+
+ The GNU Readline 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 General Public License for more details.
+
+ The GNU General Public License is often shipped with GNU software, and
+ is generally kept in a file called COPYING or LICENSE. If you do not
+ have a copy of the license, write to the Free Software Foundation,
+ 675 Mass Ave, Cambridge, MA 02139, USA. */
+#define READLINE_LIBRARY
+
+#include "rlconf.h"
+
+#if !defined (PAREN_MATCHING)
+extern int rl_insert ();
+
+int
+rl_insert_close (count, invoking_key)
+ int count, invoking_key;
+{
+ return (rl_insert (count, invoking_key));
+}
+
+#else /* PAREN_MATCHING */
+
+#if defined (HAVE_CONFIG_H)
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <sys/types.h>
+
+#if defined (FD_SET) && !defined (HAVE_SELECT)
+# define HAVE_SELECT
+#endif
+
+#if defined (HAVE_SELECT)
+# include <sys/time.h>
+#endif /* HAVE_SELECT */
+#if defined (HAVE_SYS_SELECT_H)
+# include <sys/select.h>
+#endif
+
+#if defined (HAVE_STRING_H)
+# include <string.h>
+#else /* !HAVE_STRING_H */
+# include <strings.h>
+#endif /* !HAVE_STRING_H */
+
+#if !defined (strchr) && !defined (__STDC__)
+extern char *strchr (), *strrchr ();
+#endif /* !strchr && !__STDC__ */
+
+#include "readline.h"
+
+extern int rl_explicit_arg;
+
+/* Non-zero means try to blink the matching open parenthesis when the
+ close parenthesis is inserted. */
+#if defined (HAVE_SELECT)
+int rl_blink_matching_paren = 1;
+#else /* !HAVE_SELECT */
+int rl_blink_matching_paren = 0;
+#endif /* !HAVE_SELECT */
+
+static int find_matching_open ();
+
+int
+rl_insert_close (count, invoking_key)
+ int count, invoking_key;
+{
+ if (rl_explicit_arg || !rl_blink_matching_paren)
+ rl_insert (count, invoking_key);
+ else
+ {
+#if defined (HAVE_SELECT)
+ int orig_point, match_point, ready;
+ struct timeval timer;
+ fd_set readfds;
+
+ rl_insert (1, invoking_key);
+ (*rl_redisplay_function) ();
+ match_point =
+ find_matching_open (rl_line_buffer, rl_point - 2, invoking_key);
+
+ /* Emacs might message or ring the bell here, but I don't. */
+ if (match_point < 0)
+ return -1;
+
+ FD_ZERO (&readfds);
+ FD_SET (fileno (rl_instream), &readfds);
+ timer.tv_sec = 0;
+ timer.tv_usec = 500000;
+
+ orig_point = rl_point;
+ rl_point = match_point;
+ (*rl_redisplay_function) ();
+ ready = select (1, &readfds, (fd_set *)NULL, (fd_set *)NULL, &timer);
+ rl_point = orig_point;
+#else /* !HAVE_SELECT */
+ rl_insert (count, invoking_key);
+#endif /* !HAVE_SELECT */
+ }
+ return 0;
+}
+
+static int
+find_matching_open (string, from, closer)
+ char *string;
+ int from, closer;
+{
+ register int i;
+ int opener, level, delimiter;
+
+ switch (closer)
+ {
+ case ']': opener = '['; break;
+ case '}': opener = '{'; break;
+ case ')': opener = '('; break;
+ default:
+ return (-1);
+ }
+
+ level = 1; /* The closer passed in counts as 1. */
+ delimiter = 0; /* Delimited state unknown. */
+
+ for (i = from; i > -1; i--)
+ {
+ if (delimiter && (string[i] == delimiter))
+ delimiter = 0;
+ else if (rl_basic_quote_characters && strchr (rl_basic_quote_characters, string[i]))
+ delimiter = string[i];
+ else if (!delimiter && (string[i] == closer))
+ level++;
+ else if (!delimiter && (string[i] == opener))
+ level--;
+
+ if (!level)
+ break;
+ }
+ return (i);
+}
+
+#endif /* PAREN_MATCHING */
diff --git a/readline/posixdir.h b/readline/posixdir.h
new file mode 100644
index 00000000000..7480a93d5db
--- /dev/null
+++ b/readline/posixdir.h
@@ -0,0 +1,49 @@
+/* posixdir.h -- Posix directory reading includes and defines. */
+
+/* Copyright (C) 1987,1991 Free Software Foundation, Inc.
+
+ This file is part of GNU Bash, the Bourne Again SHell.
+
+ Bash is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 1, or (at your option)
+ any later version.
+
+ Bash is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Bash; see the file COPYING. If not, write to the Free
+ Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* This file should be included instead of <dirent.h> or <sys/dir.h>. */
+
+#if !defined (_POSIXDIR_H_)
+#define _POSIXDIR_H_
+
+#if defined (HAVE_DIRENT_H)
+# include <dirent.h>
+# define D_NAMLEN(d) (strlen ((d)->d_name))
+#else
+# if defined (HAVE_SYS_NDIR_H)
+# include <sys/ndir.h>
+# endif
+# if defined (HAVE_SYS_DIR_H)
+# include <sys/dir.h>
+# endif
+# if defined (HAVE_NDIR_H)
+# include <ndir.h>
+# endif
+# if !defined (dirent)
+# define dirent direct
+# endif /* !dirent */
+# define D_NAMLEN(d) ((d)->d_namlen)
+#endif /* !HAVE_DIRENT_H */
+
+#if defined (STRUCT_DIRENT_HAS_D_INO) && !defined (STRUCT_DIRENT_HAS_D_FILENO)
+# define d_fileno d_ino
+#endif
+
+#endif /* !_POSIXDIR_H_ */
diff --git a/readline/posixjmp.h b/readline/posixjmp.h
new file mode 100644
index 00000000000..1347cc07ebc
--- /dev/null
+++ b/readline/posixjmp.h
@@ -0,0 +1,22 @@
+/* posixjmp.h -- wrapper for setjmp.h with changes for POSIX systems. */
+
+#ifndef _POSIXJMP_H_
+#define _POSIXJMP_H_
+
+#include <setjmp.h>
+
+/* This *must* be included *after* config.h */
+
+#if defined (HAVE_POSIX_SIGSETJMP)
+# define procenv_t sigjmp_buf
+# if !defined (__OPENNT)
+# undef setjmp
+# define setjmp(x) sigsetjmp((x), 1)
+# undef longjmp
+# define longjmp(x, n) siglongjmp((x), (n))
+# endif /* !__OPENNT */
+#else
+# define procenv_t jmp_buf
+#endif
+
+#endif /* _POSIXJMP_H_ */
diff --git a/readline/posixstat.h b/readline/posixstat.h
new file mode 100644
index 00000000000..bfce8c04fef
--- /dev/null
+++ b/readline/posixstat.h
@@ -0,0 +1,142 @@
+/* posixstat.h -- Posix stat(2) definitions for systems that
+ don't have them. */
+
+/* Copyright (C) 1987,1991 Free Software Foundation, Inc.
+
+ This file is part of GNU Bash, the Bourne Again SHell.
+
+ Bash is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 1, or (at your option)
+ any later version.
+
+ Bash is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Bash; see the file COPYING. If not, write to the Free
+ Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* This file should be included instead of <sys/stat.h>.
+ It relies on the local sys/stat.h to work though. */
+#if !defined (_POSIXSTAT_H_)
+#define _POSIXSTAT_H_
+
+#include <sys/stat.h>
+
+#if defined (STAT_MACROS_BROKEN)
+# undef S_ISBLK
+# undef S_ISCHR
+# undef S_ISDIR
+# undef S_ISFIFO
+# undef S_ISREG
+# undef S_ISLNK
+#endif /* STAT_MACROS_BROKEN */
+
+/* These are guaranteed to work only on isc386 */
+#if !defined (S_IFDIR) && !defined (S_ISDIR)
+# define S_IFDIR 0040000
+#endif /* !S_IFDIR && !S_ISDIR */
+#if !defined (S_IFMT)
+# define S_IFMT 0170000
+#endif /* !S_IFMT */
+
+/* Posix 1003.1 5.6.1.1 <sys/stat.h> file types */
+
+/* Some Posix-wannabe systems define _S_IF* macros instead of S_IF*, but
+ do not provide the S_IS* macros that Posix requires. */
+
+#if defined (_S_IFMT) && !defined (S_IFMT)
+#define S_IFMT _S_IFMT
+#endif
+#if defined (_S_IFIFO) && !defined (S_IFIFO)
+#define S_IFIFO _S_IFIFO
+#endif
+#if defined (_S_IFCHR) && !defined (S_IFCHR)
+#define S_IFCHR _S_IFCHR
+#endif
+#if defined (_S_IFDIR) && !defined (S_IFDIR)
+#define S_IFDIR _S_IFDIR
+#endif
+#if defined (_S_IFBLK) && !defined (S_IFBLK)
+#define S_IFBLK _S_IFBLK
+#endif
+#if defined (_S_IFREG) && !defined (S_IFREG)
+#define S_IFREG _S_IFREG
+#endif
+#if defined (_S_IFLNK) && !defined (S_IFLNK)
+#define S_IFLNK _S_IFLNK
+#endif
+#if defined (_S_IFSOCK) && !defined (S_IFSOCK)
+#define S_IFSOCK _S_IFSOCK
+#endif
+
+/* Test for each symbol individually and define the ones necessary (some
+ systems claiming Posix compatibility define some but not all). */
+
+#if defined (S_IFBLK) && !defined (S_ISBLK)
+#define S_ISBLK(m) (((m)&S_IFMT) == S_IFBLK) /* block device */
+#endif
+
+#if defined (S_IFCHR) && !defined (S_ISCHR)
+#define S_ISCHR(m) (((m)&S_IFMT) == S_IFCHR) /* character device */
+#endif
+
+#if defined (S_IFDIR) && !defined (S_ISDIR)
+#define S_ISDIR(m) (((m)&S_IFMT) == S_IFDIR) /* directory */
+#endif
+
+#if defined (S_IFREG) && !defined (S_ISREG)
+#define S_ISREG(m) (((m)&S_IFMT) == S_IFREG) /* file */
+#endif
+
+#if defined (S_IFIFO) && !defined (S_ISFIFO)
+#define S_ISFIFO(m) (((m)&S_IFMT) == S_IFIFO) /* fifo - named pipe */
+#endif
+
+#if defined (S_IFLNK) && !defined (S_ISLNK)
+#define S_ISLNK(m) (((m)&S_IFMT) == S_IFLNK) /* symbolic link */
+#endif
+
+#if defined (S_IFSOCK) && !defined (S_ISSOCK)
+#define S_ISSOCK(m) (((m)&S_IFMT) == S_IFSOCK) /* socket */
+#endif
+
+/*
+ * POSIX 1003.1 5.6.1.2 <sys/stat.h> File Modes
+ */
+
+#if !defined (S_IRWXU)
+# if !defined (S_IREAD)
+# define S_IREAD 00400
+# define S_IWRITE 00200
+# define S_IEXEC 00100
+# endif /* S_IREAD */
+
+# if !defined (S_IRUSR)
+# define S_IRUSR S_IREAD /* read, owner */
+# define S_IWUSR S_IWRITE /* write, owner */
+# define S_IXUSR S_IEXEC /* execute, owner */
+
+# define S_IRGRP (S_IREAD >> 3) /* read, group */
+# define S_IWGRP (S_IWRITE >> 3) /* write, group */
+# define S_IXGRP (S_IEXEC >> 3) /* execute, group */
+
+# define S_IROTH (S_IREAD >> 6) /* read, other */
+# define S_IWOTH (S_IWRITE >> 6) /* write, other */
+# define S_IXOTH (S_IEXEC >> 6) /* execute, other */
+# endif /* !S_IRUSR */
+
+# define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR)
+# define S_IRWXG (S_IRGRP | S_IWGRP | S_IXGRP)
+# define S_IRWXO (S_IROTH | S_IWOTH | S_IXOTH)
+#endif /* !S_IRWXU */
+
+/* These are non-standard, but are used in builtins.c$symbolic_umask() */
+#define S_IRUGO (S_IRUSR | S_IRGRP | S_IROTH)
+#define S_IWUGO (S_IWUSR | S_IWGRP | S_IWOTH)
+#define S_IXUGO (S_IXUSR | S_IXGRP | S_IXOTH)
+
+#endif /* _POSIXSTAT_H_ */
diff --git a/readline/readline.c b/readline/readline.c
new file mode 100644
index 00000000000..622811fc11e
--- /dev/null
+++ b/readline/readline.c
@@ -0,0 +1,2156 @@
+/* readline.c -- a general facility for reading lines of input
+ with emacs style editing and completion. */
+
+/* Copyright (C) 1987, 1989, 1992 Free Software Foundation, Inc.
+
+ This file is part of the GNU Readline Library, a library for
+ reading lines of text with interactive input and history editing.
+
+ The GNU Readline Library is free software; you can redistribute it
+ and/or modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 1, or
+ (at your option) any later version.
+
+ The GNU Readline 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 General Public License for more details.
+
+ The GNU General Public License is often shipped with GNU software, and
+ is generally kept in a file called COPYING or LICENSE. If you do not
+ have a copy of the license, write to the Free Software Foundation,
+ 675 Mass Ave, Cambridge, MA 02139, USA. */
+#define READLINE_LIBRARY
+
+#if defined (HAVE_CONFIG_H)
+# include <config.h>
+#endif
+
+#include <sys/types.h>
+#include "posixstat.h"
+#include <fcntl.h>
+#if defined (HAVE_SYS_FILE_H)
+# include <sys/file.h>
+#endif /* HAVE_SYS_FILE_H */
+
+#if defined (HAVE_UNISTD_H)
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+
+#if defined (HAVE_STDLIB_H)
+# include <stdlib.h>
+#else
+# include "ansi_stdlib.h"
+#endif /* HAVE_STDLIB_H */
+
+#if defined (HAVE_LOCALE_H)
+# include <locale.h>
+#endif
+
+#include <signal.h>
+#include <stdio.h>
+#include "posixjmp.h"
+
+/* System-specific feature definitions and include files. */
+#include "rldefs.h"
+
+#if defined (__EMX__)
+# define INCL_DOSPROCESS
+# include <os2.h>
+#endif /* __EMX__ */
+
+/* Some standard library routines. */
+#include "readline.h"
+#include "history.h"
+
+#ifndef RL_LIBRARY_VERSION
+# define RL_LIBRARY_VERSION "4.0"
+#endif
+
+/* Evaluates its arguments multiple times. */
+#define SWAP(s, e) do { int t; t = s; s = e; e = t; } while (0)
+
+/* NOTE: Functions and variables prefixed with `_rl_' are
+ pseudo-global: they are global so they can be shared
+ between files in the readline library, but are not intended
+ to be visible to readline callers. */
+
+/* Variables and functions imported from terminal.c */
+extern int _rl_init_terminal_io ();
+extern void _rl_enable_meta_key ();
+#ifdef _MINIX
+extern void _rl_output_character_function ();
+#else
+extern int _rl_output_character_function ();
+#endif
+
+extern int _rl_enable_meta;
+extern int _rl_term_autowrap;
+extern int screenwidth, screenheight, screenchars;
+
+/* Variables and functions imported from rltty.c. */
+extern void rl_prep_terminal (), rl_deprep_terminal ();
+extern void rltty_set_default_bindings ();
+
+/* Functions imported from util.c. */
+extern void _rl_abort_internal ();
+extern void rl_extend_line_buffer ();
+extern int alphabetic ();
+
+/* Functions imported from bind.c. */
+extern void _rl_bind_if_unbound ();
+
+/* Functions imported from input.c. */
+extern int _rl_any_typein ();
+extern void _rl_insert_typein ();
+extern int rl_read_key ();
+
+/* Functions imported from nls.c */
+extern int _rl_init_eightbit ();
+
+/* Functions imported from shell.c */
+extern char *get_env_value ();
+
+/* External redisplay functions and variables from display.c */
+extern void _rl_move_vert ();
+extern void _rl_update_final ();
+extern void _rl_clear_to_eol ();
+extern void _rl_clear_screen ();
+extern void _rl_erase_entire_line ();
+
+extern void _rl_erase_at_end_of_line ();
+extern void _rl_move_cursor_relative ();
+
+extern int _rl_vis_botlin;
+extern int _rl_last_c_pos;
+extern int _rl_horizontal_scroll_mode;
+extern int rl_display_fixed;
+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 int rl_completion_query_items;
+extern int rl_complete_with_tilde_expansion;
+
+/* Variables and functions from macro.c. */
+extern void _rl_add_macro_char ();
+extern void _rl_with_macro_input ();
+extern int _rl_next_macro_key ();
+extern int _rl_defining_kbd_macro;
+
+#if defined (VI_MODE)
+/* Functions imported from vi_mode.c. */
+extern void _rl_vi_set_last ();
+extern void _rl_vi_reset_last ();
+extern void _rl_vi_done_inserting ();
+extern int _rl_vi_textmod_command ();
+extern void _rl_vi_initialize_line ();
+#endif /* VI_MODE */
+
+extern UNDO_LIST *rl_undo_list;
+extern int _rl_doing_an_undo;
+
+/* Forward declarations used in this file. */
+void _rl_free_history_entry ();
+
+int _rl_dispatch ();
+int _rl_init_argument ();
+
+static char *readline_internal ();
+static void readline_initialize_everything ();
+static void start_using_history ();
+static void bind_arrow_keys ();
+
+#if !defined (__GO32__)
+static void readline_default_bindings ();
+#endif /* !__GO32__ */
+
+#if defined (__GO32__)
+# include <go32.h>
+# include <pc.h>
+# undef HANDLE_SIGNALS
+#endif /* __GO32__ */
+
+extern char *xmalloc (), *xrealloc ();
+
+/* **************************************************************** */
+/* */
+/* Line editing input utility */
+/* */
+/* **************************************************************** */
+
+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. */
+Keymap _rl_keymap = emacs_standard_keymap;
+
+/* The current style of editing. */
+int rl_editing_mode = emacs_mode;
+
+/* Non-zero if we called this function from _rl_dispatch(). It's present
+ so functions can find out whether they were called from a key binding
+ or directly from an application. */
+int rl_dispatching;
+
+/* Non-zero if the previous command was a kill command. */
+int _rl_last_command_was_kill = 0;
+
+/* The current value of the numeric argument specified by the user. */
+int rl_numeric_arg = 1;
+
+/* Non-zero if an argument was typed. */
+int rl_explicit_arg = 0;
+
+/* Temporary value used while generating the argument. */
+int rl_arg_sign = 1;
+
+/* Non-zero means we have been called at least once before. */
+static int rl_initialized;
+
+/* If non-zero, this program is running in an EMACS buffer. */
+static int running_in_emacs;
+
+/* The current offset in the current input line. */
+int rl_point;
+
+/* Mark in the current input line. */
+int rl_mark;
+
+/* Length of the current input line. */
+int rl_end;
+
+/* Make this non-zero to return the current input_line. */
+int rl_done;
+
+/* The last function executed by readline. */
+Function *rl_last_func = (Function *)NULL;
+
+/* Top level environment for readline_internal (). */
+procenv_t readline_top_level;
+
+/* The streams we interact with. */
+FILE *_rl_in_stream, *_rl_out_stream;
+
+/* The names of the streams that we do input and output to. */
+FILE *rl_instream = (FILE *)NULL;
+FILE *rl_outstream = (FILE *)NULL;
+
+/* Non-zero means echo characters as they are read. */
+int readline_echoing_p = 1;
+
+/* Current prompt. */
+char *rl_prompt;
+int rl_visible_prompt_length = 0;
+
+/* The number of characters read in order to type this complete command. */
+int rl_key_sequence_length = 0;
+
+/* If non-zero, then this is the address of a function to call just
+ before readline_internal_setup () prints the first prompt. */
+Function *rl_startup_hook = (Function *)NULL;
+
+/* If non-zero, this is the address of a function to call just before
+ readline_internal_setup () returns and readline_internal starts
+ reading input characters. */
+Function *rl_pre_input_hook = (Function *)NULL;
+
+/* What we use internally. You should always refer to RL_LINE_BUFFER. */
+static char *the_line;
+
+/* The character that can generate an EOF. Really read from
+ the terminal driver... just defaulted here. */
+int _rl_eof_char = CTRL ('D');
+
+/* Non-zero makes this the next keystroke to read. */
+int rl_pending_input = 0;
+
+/* Pointer to a useful terminal name. */
+char *rl_terminal_name = (char *)NULL;
+
+/* Non-zero means to always use horizontal scrolling in line display. */
+int _rl_horizontal_scroll_mode = 0;
+
+/* Non-zero means to display an asterisk at the starts of history lines
+ which have been modified. */
+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;
+
+/* Keymap holding the function currently being executed. */
+Keymap rl_executing_keymap;
+
+/* Non-zero means to erase entire line, including prompt, on empty input lines. */
+int rl_erase_empty_line = 0;
+
+/* Line buffer and maintenence. */
+char *rl_line_buffer = (char *)NULL;
+int rl_line_buffer_len = 0;
+
+/* Forward declarations used by the display and termcap code. */
+
+/* **************************************************************** */
+/* */
+/* `Forward' declarations */
+/* */
+/* **************************************************************** */
+
+/* Non-zero means do not parse any lines other than comments and
+ parser directives. */
+unsigned char _rl_parsing_conditionalized_out = 0;
+
+/* Non-zero means to convert characters with the meta bit set to
+ escape-prefixed characters so we can indirect through
+ emacs_meta_keymap or vi_escape_keymap. */
+int _rl_convert_meta_chars_to_ascii = 1;
+
+/* Non-zero means to output characters with the meta bit set directly
+ rather than as a meta-prefixed escape sequence. */
+int _rl_output_meta_chars = 0;
+
+/* **************************************************************** */
+/* */
+/* Top Level Functions */
+/* */
+/* **************************************************************** */
+
+/* Non-zero means treat 0200 bit in terminal input as Meta bit. */
+int _rl_meta_flag = 0; /* Forward declaration */
+
+/* Read a line of input. Prompt with PROMPT. An empty PROMPT means
+ none. A return value of NULL means that EOF was encountered. */
+char *
+readline (prompt)
+ char *prompt;
+{
+ char *value;
+
+ rl_prompt = prompt;
+
+ /* If we are at EOF return a NULL string. */
+ if (rl_pending_input == EOF)
+ {
+ rl_pending_input = 0;
+ return ((char *)NULL);
+ }
+
+ rl_visible_prompt_length = rl_expand_prompt (rl_prompt);
+
+ rl_initialize ();
+ (*rl_prep_term_function) (_rl_meta_flag);
+
+#if defined (HANDLE_SIGNALS)
+ rl_set_signals ();
+#endif
+
+ value = readline_internal ();
+ (*rl_deprep_term_function) ();
+
+#if defined (HANDLE_SIGNALS)
+ rl_clear_signals ();
+#endif
+
+ return (value);
+}
+
+#if defined (READLINE_CALLBACKS)
+# define STATIC_CALLBACK
+#else
+# define STATIC_CALLBACK static
+#endif
+
+STATIC_CALLBACK void
+readline_internal_setup ()
+{
+ _rl_in_stream = rl_instream;
+ _rl_out_stream = rl_outstream;
+
+ if (rl_startup_hook)
+ (*rl_startup_hook) ();
+
+ if (readline_echoing_p == 0)
+ {
+ if (rl_prompt)
+ {
+ fprintf (_rl_out_stream, "%s", rl_prompt);
+ fflush (_rl_out_stream);
+ }
+ }
+ else
+ {
+ rl_on_new_line ();
+ (*rl_redisplay_function) ();
+#if defined (VI_MODE)
+ if (rl_editing_mode == vi_mode)
+ rl_vi_insertion_mode (1, 0);
+#endif /* VI_MODE */
+ }
+
+ if (rl_pre_input_hook)
+ (*rl_pre_input_hook) ();
+}
+
+STATIC_CALLBACK char *
+readline_internal_teardown (eof)
+ int eof;
+{
+ char *temp;
+ HIST_ENTRY *entry;
+
+ /* Restore the original of this history line, iff the line that we
+ are editing was originally in the history, AND the line has changed. */
+ entry = current_history ();
+
+ if (entry && rl_undo_list)
+ {
+ temp = savestring (the_line);
+ rl_revert_line (1, 0);
+ entry = replace_history_entry (where_history (), the_line, (histdata_t)NULL);
+ _rl_free_history_entry (entry);
+
+ strcpy (the_line, temp);
+ free (temp);
+ }
+
+ /* At any rate, it is highly likely that this line has an undo list. Get
+ rid of it now. */
+ if (rl_undo_list)
+ free_undo_list ();
+
+ return (eof ? (char *)NULL : savestring (the_line));
+}
+
+STATIC_CALLBACK int
+#if defined (READLINE_CALLBACKS)
+readline_internal_char ()
+#else
+readline_internal_charloop ()
+#endif
+{
+ static int lastc, eof_found;
+ int c, code, lk;
+
+ lastc = -1;
+ eof_found = 0;
+
+#if !defined (READLINE_CALLBACKS)
+ while (rl_done == 0)
+ {
+#endif
+ lk = _rl_last_command_was_kill;
+
+ code = setjmp (readline_top_level);
+
+ if (code)
+ (*rl_redisplay_function) ();
+
+ if (rl_pending_input == 0)
+ {
+ /* Then initialize the argument and number of keys read. */
+ _rl_init_argument ();
+ rl_key_sequence_length = 0;
+ }
+
+ c = rl_read_key ();
+
+ /* EOF typed to a non-blank line is a <NL>. */
+ if (c == EOF && rl_end)
+ c = NEWLINE;
+
+ /* The character _rl_eof_char typed to blank line, and not as the
+ previous character is interpreted as EOF. */
+ if (((c == _rl_eof_char && lastc != c) || c == EOF) && !rl_end)
+ {
+#if defined (READLINE_CALLBACKS)
+ return (rl_done = 1);
+#else
+ eof_found = 1;
+ break;
+#endif
+ }
+
+ lastc = c;
+ _rl_dispatch (c, _rl_keymap);
+
+ /* If there was no change in _rl_last_command_was_kill, then no kill
+ has taken place. Note that if input is pending we are reading
+ a prefix command, so nothing has changed yet. */
+ if (rl_pending_input == 0 && lk == _rl_last_command_was_kill)
+ _rl_last_command_was_kill = 0;
+
+#if defined (VI_MODE)
+ /* In vi mode, when you exit insert mode, the cursor moves back
+ over the previous character. We explicitly check for that here. */
+ if (rl_editing_mode == vi_mode && _rl_keymap == vi_movement_keymap)
+ rl_vi_check ();
+#endif /* VI_MODE */
+
+ if (rl_done == 0)
+ (*rl_redisplay_function) ();
+
+ /* If the application writer has told us to erase the entire line if
+ the only character typed was something bound to rl_newline, do so. */
+ if (rl_erase_empty_line && rl_done && rl_last_func == rl_newline &&
+ rl_point == 0 && rl_end == 0)
+ _rl_erase_entire_line ();
+
+#if defined (READLINE_CALLBACKS)
+ return 0;
+#else
+ }
+
+ return (eof_found);
+#endif
+}
+
+#if defined (READLINE_CALLBACKS)
+static int
+readline_internal_charloop ()
+{
+ int eof = 1;
+
+ while (rl_done == 0)
+ eof = readline_internal_char ();
+ return (eof);
+}
+#endif /* READLINE_CALLBACKS */
+
+/* Read a line of input from the global rl_instream, doing output on
+ the global rl_outstream.
+ If rl_prompt is non-null, then that is our prompt. */
+static char *
+readline_internal ()
+{
+ int eof;
+
+ readline_internal_setup ();
+ eof = readline_internal_charloop ();
+ return (readline_internal_teardown (eof));
+}
+
+void
+_rl_init_line_state ()
+{
+ rl_point = rl_end = 0;
+ the_line = rl_line_buffer;
+ the_line[0] = 0;
+}
+
+void
+_rl_set_the_line ()
+{
+ the_line = rl_line_buffer;
+}
+
+/* Do the command associated with KEY in MAP.
+ If the associated command is really a keymap, then read
+ another key, and dispatch into that map. */
+int
+_rl_dispatch (key, map)
+ register int key;
+ Keymap map;
+{
+ int r, newkey;
+ char *macro;
+ Function *func;
+
+ if (META_CHAR (key) && _rl_convert_meta_chars_to_ascii)
+ {
+ if (map[ESC].type == ISKMAP)
+ {
+ if (_rl_defining_kbd_macro)
+ _rl_add_macro_char (ESC);
+ map = FUNCTION_TO_KEYMAP (map, ESC);
+ key = UNMETA (key);
+ rl_key_sequence_length += 2;
+ return (_rl_dispatch (key, map));
+ }
+ else
+ ding ();
+ return 0;
+ }
+
+ if (_rl_defining_kbd_macro)
+ _rl_add_macro_char (key);
+
+ r = 0;
+ switch (map[key].type)
+ {
+ case ISFUNC:
+ func = map[key].function;
+ if (func != (Function *)NULL)
+ {
+ /* Special case rl_do_lowercase_version (). */
+ if (func == rl_do_lowercase_version)
+ return (_rl_dispatch (_rl_to_lower (key), map));
+
+ rl_executing_keymap = map;
+
+#if 0
+ _rl_suppress_redisplay = (map[key].function == rl_insert) && _rl_input_available ();
+#endif
+
+ rl_dispatching = 1;
+ r = (*map[key].function)(rl_numeric_arg * rl_arg_sign, key);
+ rl_dispatching = 0;
+
+ /* If we have input pending, then the last command was a prefix
+ command. Don't change the state of rl_last_func. Otherwise,
+ remember the last command executed in this variable. */
+ if (!rl_pending_input && map[key].function != rl_digit_argument)
+ rl_last_func = map[key].function;
+ }
+ else
+ {
+ _rl_abort_internal ();
+ return -1;
+ }
+ break;
+
+ case ISKMAP:
+ if (map[key].function != (Function *)NULL)
+ {
+ rl_key_sequence_length++;
+ newkey = rl_read_key ();
+ r = _rl_dispatch (newkey, FUNCTION_TO_KEYMAP (map, key));
+ }
+ else
+ {
+ _rl_abort_internal ();
+ return -1;
+ }
+ break;
+
+ case ISMACR:
+ if (map[key].function != (Function *)NULL)
+ {
+ macro = savestring ((char *)map[key].function);
+ _rl_with_macro_input (macro);
+ return 0;
+ }
+ break;
+ }
+#if defined (VI_MODE)
+ if (rl_editing_mode == vi_mode && _rl_keymap == vi_movement_keymap &&
+ _rl_vi_textmod_command (key))
+ _rl_vi_set_last (key, rl_numeric_arg, rl_arg_sign);
+#endif
+ return (r);
+}
+
+/* **************************************************************** */
+/* */
+/* Initializations */
+/* */
+/* **************************************************************** */
+
+/* Initialize readline (and terminal if not already). */
+int
+rl_initialize ()
+{
+ /* If we have never been called before, initialize the
+ terminal and data structures. */
+ if (!rl_initialized)
+ {
+ readline_initialize_everything ();
+ rl_initialized++;
+ }
+
+ /* Initalize the current line information. */
+ _rl_init_line_state ();
+
+ /* We aren't done yet. We haven't even gotten started yet! */
+ rl_done = 0;
+
+ /* Tell the history routines what is going on. */
+ start_using_history ();
+
+ /* Make the display buffer match the state of the line. */
+ rl_reset_line_state ();
+
+ /* No such function typed yet. */
+ rl_last_func = (Function *)NULL;
+
+ /* Parsing of key-bindings begins in an enabled state. */
+ _rl_parsing_conditionalized_out = 0;
+
+#if defined (VI_MODE)
+ if (rl_editing_mode == vi_mode)
+ _rl_vi_initialize_line ();
+#endif
+
+ return 0;
+}
+
+#if defined (__EMX__)
+static void
+_emx_build_environ ()
+{
+ TIB *tibp;
+ PIB *pibp;
+ char *t, **tp;
+ int c;
+
+ DosGetInfoBlocks (&tibp, &pibp);
+ t = pibp->pib_pchenv;
+ for (c = 1; *t; c++)
+ t += strlen (t) + 1;
+ tp = environ = (char **)xmalloc ((c + 1) * sizeof (char *));
+ t = pibp->pib_pchenv;
+ while (*t)
+ {
+ *tp++ = t;
+ t += strlen (t) + 1;
+ }
+ *tp = 0;
+}
+#endif /* __EMX__ */
+
+/* Initialize the entire state of the world. */
+static void
+readline_initialize_everything ()
+{
+#if defined (__EMX__)
+ if (environ == 0)
+ _emx_build_environ ();
+#endif
+
+ /* Find out if we are running in Emacs. */
+ running_in_emacs = get_env_value ("EMACS") != (char *)0;
+
+ /* Set up input and output if they are not already set up. */
+ if (!rl_instream)
+ rl_instream = stdin;
+
+ if (!rl_outstream)
+ rl_outstream = stdout;
+
+ /* Bind _rl_in_stream and _rl_out_stream immediately. These values
+ may change, but they may also be used before readline_internal ()
+ is called. */
+ _rl_in_stream = rl_instream;
+ _rl_out_stream = rl_outstream;
+
+ /* Allocate data structures. */
+ if (rl_line_buffer == 0)
+ rl_line_buffer = xmalloc (rl_line_buffer_len = DEFAULT_BUFFER_SIZE);
+
+ /* Initialize the terminal interface. */
+ _rl_init_terminal_io ((char *)NULL);
+
+#if !defined (__GO32__)
+ /* Bind tty characters to readline functions. */
+ readline_default_bindings ();
+#endif /* !__GO32__ */
+
+ /* Initialize the function names. */
+ rl_initialize_funmap ();
+
+ /* Decide whether we should automatically go into eight-bit mode. */
+ _rl_init_eightbit ();
+
+ /* Read in the init file. */
+ rl_read_init_file ((char *)NULL);
+
+ /* XXX */
+ if (_rl_horizontal_scroll_mode && _rl_term_autowrap)
+ {
+ screenwidth--;
+ screenchars -= screenheight;
+ }
+
+ /* Override the effect of any `set keymap' assignments in the
+ inputrc file. */
+ rl_set_keymap_from_edit_mode ();
+
+ /* Try to bind a common arrow key prefix, if not already bound. */
+ bind_arrow_keys ();
+
+ /* Enable the meta key, if this terminal has one. */
+ if (_rl_enable_meta)
+ _rl_enable_meta_key ();
+
+ /* If the completion parser's default word break characters haven't
+ been set yet, then do so now. */
+ if (rl_completer_word_break_characters == (char *)NULL)
+ rl_completer_word_break_characters = rl_basic_word_break_characters;
+}
+
+/* If this system allows us to look at the values of the regular
+ input editing characters, then bind them to their readline
+ equivalents, iff the characters are not bound to keymaps. */
+static void
+readline_default_bindings ()
+{
+ rltty_set_default_bindings (_rl_keymap);
+}
+
+static void
+bind_arrow_keys_internal ()
+{
+ Function *f;
+
+ f = rl_function_of_keyseq ("\033[A", _rl_keymap, (int *)NULL);
+ if (!f || f == rl_do_lowercase_version)
+ {
+ _rl_bind_if_unbound ("\033[A", rl_get_previous_history);
+ _rl_bind_if_unbound ("\033[B", rl_get_next_history);
+ _rl_bind_if_unbound ("\033[C", rl_forward);
+ _rl_bind_if_unbound ("\033[D", rl_backward);
+ }
+
+ f = rl_function_of_keyseq ("\033OA", _rl_keymap, (int *)NULL);
+ if (!f || f == rl_do_lowercase_version)
+ {
+ _rl_bind_if_unbound ("\033OA", rl_get_previous_history);
+ _rl_bind_if_unbound ("\033OB", rl_get_next_history);
+ _rl_bind_if_unbound ("\033OC", rl_forward);
+ _rl_bind_if_unbound ("\033OD", rl_backward);
+ }
+}
+
+/* Try and bind the common arrow key prefix after giving termcap and
+ the inputrc file a chance to bind them and create `real' keymaps
+ for the arrow key prefix. */
+static void
+bind_arrow_keys ()
+{
+ Keymap xkeymap;
+
+ xkeymap = _rl_keymap;
+
+ _rl_keymap = emacs_standard_keymap;
+ bind_arrow_keys_internal ();
+
+#if defined (VI_MODE)
+ _rl_keymap = vi_movement_keymap;
+ bind_arrow_keys_internal ();
+#endif
+
+ _rl_keymap = xkeymap;
+}
+
+
+/* **************************************************************** */
+/* */
+/* Numeric Arguments */
+/* */
+/* **************************************************************** */
+
+/* Handle C-u style numeric args, as well as M--, and M-digits. */
+static int
+rl_digit_loop ()
+{
+ int key, c, sawminus, sawdigits;
+
+ rl_save_prompt ();
+
+ sawminus = sawdigits = 0;
+ while (1)
+ {
+ if (rl_numeric_arg > 1000000)
+ {
+ sawdigits = rl_explicit_arg = rl_numeric_arg = 0;
+ ding ();
+ rl_restore_prompt ();
+ rl_clear_message ();
+ return 1;
+ }
+ rl_message ("(arg: %d) ", rl_arg_sign * rl_numeric_arg);
+ key = c = rl_read_key ();
+
+ /* If we see a key bound to `universal-argument' after seeing digits,
+ it ends the argument but is otherwise ignored. */
+ if (_rl_keymap[c].type == ISFUNC &&
+ _rl_keymap[c].function == rl_universal_argument)
+ {
+ if (sawdigits == 0)
+ {
+ rl_numeric_arg *= 4;
+ continue;
+ }
+ else
+ {
+ key = rl_read_key ();
+ rl_restore_prompt ();
+ rl_clear_message ();
+ return (_rl_dispatch (key, _rl_keymap));
+ }
+ }
+
+ c = UNMETA (c);
+
+ if (_rl_digit_p (c))
+ {
+ rl_numeric_arg = rl_explicit_arg ? (rl_numeric_arg * 10) + c - '0' : c - '0';
+ sawdigits = rl_explicit_arg = 1;
+ }
+ else if (c == '-' && rl_explicit_arg == 0)
+ {
+ rl_numeric_arg = sawminus = 1;
+ rl_arg_sign = -1;
+ }
+ else
+ {
+ /* Make M-- command equivalent to M--1 command. */
+ if (sawminus && rl_numeric_arg == 1 && rl_explicit_arg == 0)
+ rl_explicit_arg = 1;
+ rl_restore_prompt ();
+ rl_clear_message ();
+ return (_rl_dispatch (key, _rl_keymap));
+ }
+ }
+
+ return 0;
+}
+
+/* Add the current digit to the argument in progress. */
+int
+rl_digit_argument (ignore, key)
+ int ignore, key;
+{
+ rl_pending_input = key;
+ return (rl_digit_loop ());
+}
+
+/* What to do when you abort reading an argument. */
+int
+rl_discard_argument ()
+{
+ ding ();
+ rl_clear_message ();
+ _rl_init_argument ();
+ return 0;
+}
+
+/* Create a default argument. */
+int
+_rl_init_argument ()
+{
+ rl_numeric_arg = rl_arg_sign = 1;
+ rl_explicit_arg = 0;
+ return 0;
+}
+
+/* C-u, universal argument. Multiply the current argument by 4.
+ Read a key. If the key has nothing to do with arguments, then
+ dispatch on it. If the key is the abort character then abort. */
+int
+rl_universal_argument (count, key)
+ int count, key;
+{
+ rl_numeric_arg *= 4;
+ return (rl_digit_loop ());
+}
+
+/* **************************************************************** */
+/* */
+/* Insert and Delete */
+/* */
+/* **************************************************************** */
+
+/* Insert a string of text into the line at point. This is the only
+ way that you should do insertion. rl_insert () calls this
+ function. */
+int
+rl_insert_text (string)
+ char *string;
+{
+ register int i, l = strlen (string);
+
+ if (rl_end + l >= rl_line_buffer_len)
+ rl_extend_line_buffer (rl_end + l);
+
+ for (i = rl_end; i >= rl_point; i--)
+ the_line[i + l] = the_line[i];
+ strncpy (the_line + rl_point, string, l);
+
+ /* Remember how to undo this if we aren't undoing something. */
+ if (!_rl_doing_an_undo)
+ {
+ /* If possible and desirable, concatenate the undos. */
+ if ((l == 1) &&
+ rl_undo_list &&
+ (rl_undo_list->what == UNDO_INSERT) &&
+ (rl_undo_list->end == rl_point) &&
+ (rl_undo_list->end - rl_undo_list->start < 20))
+ rl_undo_list->end++;
+ else
+ rl_add_undo (UNDO_INSERT, rl_point, rl_point + l, (char *)NULL);
+ }
+ rl_point += l;
+ rl_end += l;
+ the_line[rl_end] = '\0';
+ return l;
+}
+
+/* Delete the string between FROM and TO. FROM is
+ inclusive, TO is not. */
+int
+rl_delete_text (from, to)
+ int from, to;
+{
+ register char *text;
+ register int diff, i;
+
+ /* Fix it if the caller is confused. */
+ if (from > to)
+ SWAP (from, to);
+
+ /* fix boundaries */
+ if (to > rl_end)
+ {
+ to = rl_end;
+ if (from > to)
+ from = to;
+ }
+
+ text = rl_copy_text (from, to);
+
+ /* Some versions of strncpy() can't handle overlapping arguments. */
+ diff = to - from;
+ for (i = from; i < rl_end - diff; i++)
+ the_line[i] = the_line[i + diff];
+
+ /* Remember how to undo this delete. */
+ if (_rl_doing_an_undo == 0)
+ rl_add_undo (UNDO_DELETE, from, to, text);
+ else
+ free (text);
+
+ rl_end -= diff;
+ the_line[rl_end] = '\0';
+ return (diff);
+}
+
+/* Fix up point so that it is within the line boundaries after killing
+ text. If FIX_MARK_TOO is non-zero, the mark is forced within line
+ boundaries also. */
+
+#define _RL_FIX_POINT(x) \
+ do { \
+ if (x > rl_end) \
+ x = rl_end; \
+ else if (x < 0) \
+ x = 0; \
+ } while (0)
+
+void
+_rl_fix_point (fix_mark_too)
+ int fix_mark_too;
+{
+ _RL_FIX_POINT (rl_point);
+ if (fix_mark_too)
+ _RL_FIX_POINT (rl_mark);
+}
+#undef _RL_FIX_POINT
+
+void
+_rl_replace_text (text, start, end)
+ char *text;
+ int start, end;
+{
+ rl_begin_undo_group ();
+ rl_delete_text (start, end + 1);
+ rl_point = start;
+ rl_insert_text (text);
+ rl_end_undo_group ();
+}
+
+/* **************************************************************** */
+/* */
+/* Readline character functions */
+/* */
+/* **************************************************************** */
+
+/* This is not a gap editor, just a stupid line input routine. No hair
+ is involved in writing any of the functions, and none should be. */
+
+/* Note that:
+
+ rl_end is the place in the string that we would place '\0';
+ i.e., it is always safe to place '\0' there.
+
+ rl_point is the place in the string where the cursor is. Sometimes
+ this is the same as rl_end.
+
+ Any command that is called interactively receives two arguments.
+ The first is a count: the numeric arg pased to this command.
+ The second is the key which invoked this command.
+*/
+
+/* **************************************************************** */
+/* */
+/* Movement Commands */
+/* */
+/* **************************************************************** */
+
+/* Note that if you `optimize' the display for these functions, you cannot
+ use said functions in other functions which do not do optimizing display.
+ I.e., you will have to update the data base for rl_redisplay, and you
+ might as well let rl_redisplay do that job. */
+
+/* Move forward COUNT characters. */
+int
+rl_forward (count, key)
+ int count, key;
+{
+ if (count < 0)
+ rl_backward (-count, key);
+ else if (count > 0)
+ {
+ int end = rl_point + count;
+#if defined (VI_MODE)
+ int lend = rl_end - (rl_editing_mode == vi_mode);
+#else
+ int lend = rl_end;
+#endif
+
+ if (end > lend)
+ {
+ rl_point = lend;
+ ding ();
+ }
+ else
+ rl_point = end;
+ }
+ return 0;
+}
+
+/* Move backward COUNT characters. */
+int
+rl_backward (count, key)
+ int count, key;
+{
+ if (count < 0)
+ rl_forward (-count, key);
+ else if (count > 0)
+ {
+ if (rl_point < count)
+ {
+ rl_point = 0;
+ ding ();
+ }
+ else
+ rl_point -= count;
+ }
+ return 0;
+}
+
+/* Move to the beginning of the line. */
+int
+rl_beg_of_line (count, key)
+ int count, key;
+{
+ rl_point = 0;
+ return 0;
+}
+
+/* Move to the end of the line. */
+int
+rl_end_of_line (count, key)
+ int count, key;
+{
+ rl_point = rl_end;
+ return 0;
+}
+
+/* Move forward a word. We do what Emacs does. */
+int
+rl_forward_word (count, key)
+ int count, key;
+{
+ int c;
+
+ if (count < 0)
+ {
+ rl_backward_word (-count, key);
+ return 0;
+ }
+
+ while (count)
+ {
+ if (rl_point == rl_end)
+ return 0;
+
+ /* If we are not in a word, move forward until we are in one.
+ Then, move forward until we hit a non-alphabetic character. */
+ c = the_line[rl_point];
+ if (alphabetic (c) == 0)
+ {
+ while (++rl_point < rl_end)
+ {
+ c = the_line[rl_point];
+ if (alphabetic (c))
+ break;
+ }
+ }
+ if (rl_point == rl_end)
+ return 0;
+ while (++rl_point < rl_end)
+ {
+ c = the_line[rl_point];
+ if (alphabetic (c) == 0)
+ break;
+ }
+ --count;
+ }
+ return 0;
+}
+
+/* Move backward a word. We do what Emacs does. */
+int
+rl_backward_word (count, key)
+ int count, key;
+{
+ int c;
+
+ if (count < 0)
+ {
+ rl_forward_word (-count, key);
+ return 0;
+ }
+
+ while (count)
+ {
+ if (!rl_point)
+ return 0;
+
+ /* Like rl_forward_word (), except that we look at the characters
+ just before point. */
+
+ c = the_line[rl_point - 1];
+ if (alphabetic (c) == 0)
+ {
+ while (--rl_point)
+ {
+ c = the_line[rl_point - 1];
+ if (alphabetic (c))
+ break;
+ }
+ }
+
+ while (rl_point)
+ {
+ c = the_line[rl_point - 1];
+ if (alphabetic (c) == 0)
+ break;
+ else
+ --rl_point;
+ }
+ --count;
+ }
+ return 0;
+}
+
+/* Clear the current line. Numeric argument to C-l does this. */
+int
+rl_refresh_line (ignore1, ignore2)
+ int ignore1, ignore2;
+{
+ int curr_line, nleft;
+
+ /* Find out whether or not there might be invisible characters in the
+ editing buffer. */
+ if (rl_display_prompt == rl_prompt)
+ nleft = _rl_last_c_pos - screenwidth - rl_visible_prompt_length;
+ else
+ nleft = _rl_last_c_pos - screenwidth;
+
+ if (nleft > 0)
+ curr_line = 1 + nleft / screenwidth;
+ else
+ curr_line = 0;
+
+ _rl_move_vert (curr_line);
+ _rl_move_cursor_relative (0, the_line); /* XXX is this right */
+
+#if defined (__GO32__)
+ {
+ int row, col, width, row_start;
+
+ ScreenGetCursor (&row, &col);
+ width = ScreenCols ();
+ row_start = ScreenPrimary + (row * width);
+ memset (row_start + col, 0, (width - col) * 2);
+ }
+#else /* !__GO32__ */
+ _rl_clear_to_eol (0); /* arg of 0 means to not use spaces */
+#endif /* !__GO32__ */
+
+ rl_forced_update_display ();
+ rl_display_fixed = 1;
+
+ return 0;
+}
+
+/* C-l typed to a line without quoting clears the screen, and then reprints
+ the prompt and the current input line. Given a numeric arg, redraw only
+ the current line. */
+int
+rl_clear_screen (count, key)
+ int count, key;
+{
+ if (rl_explicit_arg)
+ {
+ rl_refresh_line (count, key);
+ return 0;
+ }
+
+ _rl_clear_screen (); /* calls termcap function to clear screen */
+ rl_forced_update_display ();
+ rl_display_fixed = 1;
+
+ return 0;
+}
+
+int
+rl_arrow_keys (count, c)
+ int count, c;
+{
+ int ch;
+
+ ch = rl_read_key ();
+
+ switch (_rl_to_upper (ch))
+ {
+ case 'A':
+ rl_get_previous_history (count, ch);
+ break;
+
+ case 'B':
+ rl_get_next_history (count, ch);
+ break;
+
+ case 'C':
+ rl_forward (count, ch);
+ break;
+
+ case 'D':
+ rl_backward (count, ch);
+ break;
+
+ default:
+ ding ();
+ }
+ return 0;
+}
+
+
+/* **************************************************************** */
+/* */
+/* Text commands */
+/* */
+/* **************************************************************** */
+
+/* Insert the character C at the current location, moving point forward. */
+int
+rl_insert (count, c)
+ int count, c;
+{
+ register int i;
+ char *string;
+
+ if (count <= 0)
+ return 0;
+
+ /* If we can optimize, then do it. But don't let people crash
+ readline because of extra large arguments. */
+ if (count > 1 && count <= 1024)
+ {
+ string = xmalloc (1 + count);
+
+ for (i = 0; i < count; i++)
+ string[i] = c;
+
+ string[i] = '\0';
+ rl_insert_text (string);
+ free (string);
+
+ return 0;
+ }
+
+ if (count > 1024)
+ {
+ int decreaser;
+ char str[1024+1];
+
+ for (i = 0; i < 1024; i++)
+ str[i] = c;
+
+ while (count)
+ {
+ decreaser = (count > 1024 ? 1024 : count);
+ str[decreaser] = '\0';
+ rl_insert_text (str);
+ count -= decreaser;
+ }
+
+ return 0;
+ }
+
+ /* We are inserting a single character.
+ If there is pending input, then make a string of all of the
+ pending characters that are bound to rl_insert, and insert
+ them all. */
+ if (_rl_any_typein ())
+ _rl_insert_typein (c);
+ else
+ {
+ /* Inserting a single character. */
+ char str[2];
+
+ str[1] = '\0';
+ str[0] = c;
+ rl_insert_text (str);
+ }
+ return 0;
+}
+
+/* Insert the next typed character verbatim. */
+int
+rl_quoted_insert (count, key)
+ int count, key;
+{
+ int c;
+
+ c = rl_read_key ();
+ return (rl_insert (count, c));
+}
+
+/* Insert a tab character. */
+int
+rl_tab_insert (count, key)
+ int count, key;
+{
+ return (rl_insert (count, '\t'));
+}
+
+/* What to do when a NEWLINE is pressed. We accept the whole line.
+ KEY is the key that invoked this command. I guess it could have
+ meaning in the future. */
+int
+rl_newline (count, key)
+ int count, key;
+{
+ rl_done = 1;
+
+#if defined (VI_MODE)
+ if (rl_editing_mode == vi_mode)
+ {
+ _rl_vi_done_inserting ();
+ _rl_vi_reset_last ();
+ }
+#endif /* VI_MODE */
+
+ /* If we've been asked to erase empty lines, suppress the final update,
+ since _rl_update_final calls crlf(). */
+ if (rl_erase_empty_line && rl_point == 0 && rl_end == 0)
+ return 0;
+
+ if (readline_echoing_p)
+ _rl_update_final ();
+ return 0;
+}
+
+/* What to do for some uppercase characters, like meta characters,
+ and some characters appearing in emacs_ctlx_keymap. This function
+ is just a stub, you bind keys to it and the code in _rl_dispatch ()
+ is special cased. */
+int
+rl_do_lowercase_version (ignore1, ignore2)
+ int ignore1, ignore2;
+{
+ return 0;
+}
+
+/* Rubout the character behind point. */
+int
+rl_rubout (count, key)
+ int count, key;
+{
+ if (count < 0)
+ {
+ rl_delete (-count, key);
+ return 0;
+ }
+
+ if (!rl_point)
+ {
+ ding ();
+ return -1;
+ }
+
+ if (count > 1 || rl_explicit_arg)
+ {
+ int orig_point = rl_point;
+ rl_backward (count, key);
+ rl_kill_text (orig_point, rl_point);
+ }
+ else
+ {
+ int c = the_line[--rl_point];
+ rl_delete_text (rl_point, rl_point + 1);
+
+ if (rl_point == rl_end && isprint (c) && _rl_last_c_pos)
+ {
+ int l;
+ l = rl_character_len (c, rl_point);
+ _rl_erase_at_end_of_line (l);
+ }
+ }
+ return 0;
+}
+
+/* Delete the character under the cursor. Given a numeric argument,
+ kill that many characters instead. */
+int
+rl_delete (count, key)
+ int count, key;
+{
+ if (count < 0)
+ return (rl_rubout (-count, key));
+
+ if (rl_point == rl_end)
+ {
+ ding ();
+ return -1;
+ }
+
+ if (count > 1 || rl_explicit_arg)
+ {
+ int orig_point = rl_point;
+ rl_forward (count, key);
+ rl_kill_text (orig_point, rl_point);
+ rl_point = orig_point;
+ return 0;
+ }
+ else
+ return (rl_delete_text (rl_point, rl_point + 1));
+}
+
+/* Delete the character under the cursor, unless the insertion
+ point is at the end of the line, in which case the character
+ behind the cursor is deleted. COUNT is obeyed and may be used
+ to delete forward or backward that many characters. */
+int
+rl_rubout_or_delete (count, key)
+ int count, key;
+{
+ if (rl_end != 0 && rl_point == rl_end)
+ 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 start = rl_point;
+
+ while (rl_point && whitespace (the_line[rl_point - 1]))
+ rl_point--;
+
+ start = rl_point;
+
+ while (rl_point < rl_end && whitespace (the_line[rl_point]))
+ rl_point++;
+
+ if (start != rl_point)
+ {
+ rl_delete_text (start, rl_point);
+ rl_point = start;
+ }
+ return 0;
+}
+
+/* Like the tcsh editing function delete-char-or-list. The eof character
+ is caught before this is invoked, so this really does the same thing as
+ delete-char-or-list-or-eof, as long as it's bound to the eof character. */
+int
+rl_delete_or_show_completions (count, key)
+ int count, key;
+{
+ if (rl_end != 0 && rl_point == rl_end)
+ return (rl_possible_completions (count, key));
+ else
+ return (rl_delete (count, key));
+}
+
+#ifndef RL_COMMENT_BEGIN_DEFAULT
+#define RL_COMMENT_BEGIN_DEFAULT "#"
+#endif
+
+/* Turn the current line into a comment in shell history.
+ A K*rn shell style function. */
+int
+rl_insert_comment (count, key)
+ int count, key;
+{
+ rl_beg_of_line (1, key);
+ rl_insert_text (_rl_comment_begin ? _rl_comment_begin
+ : RL_COMMENT_BEGIN_DEFAULT);
+ (*rl_redisplay_function) ();
+ rl_newline (1, '\n');
+ return (0);
+}
+
+/* **************************************************************** */
+/* */
+/* Changing Case */
+/* */
+/* **************************************************************** */
+
+/* The three kinds of things that we know how to do. */
+#define UpCase 1
+#define DownCase 2
+#define CapCase 3
+
+static int rl_change_case ();
+
+/* Uppercase the word at point. */
+int
+rl_upcase_word (count, key)
+ int count, key;
+{
+ return (rl_change_case (count, UpCase));
+}
+
+/* Lowercase the word at point. */
+int
+rl_downcase_word (count, key)
+ int count, key;
+{
+ return (rl_change_case (count, DownCase));
+}
+
+/* Upcase the first letter, downcase the rest. */
+int
+rl_capitalize_word (count, key)
+ int count, key;
+{
+ return (rl_change_case (count, CapCase));
+}
+
+/* The meaty function.
+ Change the case of COUNT words, performing OP on them.
+ OP is one of UpCase, DownCase, or CapCase.
+ If a negative argument is given, leave point where it started,
+ otherwise, leave it where it moves to. */
+static int
+rl_change_case (count, op)
+ int count, op;
+{
+ register int start, end;
+ int inword, c;
+
+ start = rl_point;
+ rl_forward_word (count, 0);
+ end = rl_point;
+
+ if (count < 0)
+ SWAP (start, end);
+
+ /* We are going to modify some text, so let's prepare to undo it. */
+ rl_modifying (start, end);
+
+ for (inword = 0; start < end; start++)
+ {
+ c = the_line[start];
+ switch (op)
+ {
+ case UpCase:
+ the_line[start] = _rl_to_upper (c);
+ break;
+
+ case DownCase:
+ the_line[start] = _rl_to_lower (c);
+ break;
+
+ case CapCase:
+ the_line[start] = (inword == 0) ? _rl_to_upper (c) : _rl_to_lower (c);
+ inword = alphabetic (the_line[start]);
+ break;
+
+ default:
+ ding ();
+ return -1;
+ }
+ }
+ rl_point = end;
+ return 0;
+}
+
+/* **************************************************************** */
+/* */
+/* Transposition */
+/* */
+/* **************************************************************** */
+
+/* Transpose the words at point. */
+int
+rl_transpose_words (count, key)
+ int count, key;
+{
+ char *word1, *word2;
+ int w1_beg, w1_end, w2_beg, w2_end;
+ int orig_point = rl_point;
+
+ if (!count)
+ return 0;
+
+ /* Find the two words. */
+ rl_forward_word (count, key);
+ w2_end = rl_point;
+ rl_backward_word (1, key);
+ w2_beg = rl_point;
+ rl_backward_word (count, key);
+ w1_beg = rl_point;
+ rl_forward_word (1, key);
+ w1_end = rl_point;
+
+ /* Do some check to make sure that there really are two words. */
+ if ((w1_beg == w2_beg) || (w2_beg < w1_end))
+ {
+ ding ();
+ rl_point = orig_point;
+ return -1;
+ }
+
+ /* Get the text of the words. */
+ word1 = rl_copy_text (w1_beg, w1_end);
+ word2 = rl_copy_text (w2_beg, w2_end);
+
+ /* We are about to do many insertions and deletions. Remember them
+ as one operation. */
+ rl_begin_undo_group ();
+
+ /* Do the stuff at word2 first, so that we don't have to worry
+ about word1 moving. */
+ rl_point = w2_beg;
+ rl_delete_text (w2_beg, w2_end);
+ rl_insert_text (word1);
+
+ rl_point = w1_beg;
+ rl_delete_text (w1_beg, w1_end);
+ rl_insert_text (word2);
+
+ /* This is exactly correct since the text before this point has not
+ changed in length. */
+ rl_point = w2_end;
+
+ /* I think that does it. */
+ rl_end_undo_group ();
+ free (word1);
+ free (word2);
+
+ return 0;
+}
+
+/* Transpose the characters at point. If point is at the end of the line,
+ then transpose the characters before point. */
+int
+rl_transpose_chars (count, key)
+ int count, key;
+{
+ char dummy[2];
+
+ if (!count)
+ return 0;
+
+ if (!rl_point || rl_end < 2)
+ {
+ ding ();
+ return -1;
+ }
+
+ rl_begin_undo_group ();
+
+ if (rl_point == rl_end)
+ {
+ --rl_point;
+ count = 1;
+ }
+ rl_point--;
+
+ dummy[0] = the_line[rl_point];
+ dummy[1] = '\0';
+
+ rl_delete_text (rl_point, rl_point + 1);
+
+ rl_point += count;
+ _rl_fix_point (0);
+ rl_insert_text (dummy);
+
+ rl_end_undo_group ();
+ return 0;
+}
+
+/* **************************************************************** */
+/* */
+/* Character Searching */
+/* */
+/* **************************************************************** */
+
+int
+_rl_char_search_internal (count, dir, schar)
+ int count, dir, schar;
+{
+ int pos, inc;
+
+ pos = rl_point;
+ inc = (dir < 0) ? -1 : 1;
+ while (count)
+ {
+ if ((dir < 0 && pos <= 0) || (dir > 0 && pos >= rl_end))
+ {
+ ding ();
+ return -1;
+ }
+
+ pos += inc;
+ do
+ {
+ if (rl_line_buffer[pos] == schar)
+ {
+ count--;
+ if (dir < 0)
+ rl_point = (dir == BTO) ? pos + 1 : pos;
+ else
+ rl_point = (dir == FTO) ? pos - 1 : pos;
+ break;
+ }
+ }
+ while ((dir < 0) ? pos-- : ++pos < rl_end);
+ }
+ return (0);
+}
+
+/* Search COUNT times for a character read from the current input stream.
+ FDIR is the direction to search if COUNT is non-negative; otherwise
+ the search goes in BDIR. */
+static int
+_rl_char_search (count, fdir, bdir)
+ int count, fdir, bdir;
+{
+ int c;
+
+ c = rl_read_key ();
+ if (count < 0)
+ return (_rl_char_search_internal (-count, bdir, c));
+ else
+ return (_rl_char_search_internal (count, fdir, c));
+}
+
+int
+rl_char_search (count, key)
+ int count, key;
+{
+ return (_rl_char_search (count, FFIND, BFIND));
+}
+
+int
+rl_backward_char_search (count, key)
+ int count, key;
+{
+ return (_rl_char_search (count, BFIND, FFIND));
+}
+
+/* **************************************************************** */
+/* */
+/* History Utilities */
+/* */
+/* **************************************************************** */
+
+/* We already have a history library, and that is what we use to control
+ the history features of readline. This is our local interface to
+ the history mechanism. */
+
+/* While we are editing the history, this is the saved
+ version of the original line. */
+HIST_ENTRY *saved_line_for_history = (HIST_ENTRY *)NULL;
+
+/* Set the history pointer back to the last entry in the history. */
+static void
+start_using_history ()
+{
+ using_history ();
+ if (saved_line_for_history)
+ _rl_free_history_entry (saved_line_for_history);
+
+ saved_line_for_history = (HIST_ENTRY *)NULL;
+}
+
+/* Free the contents (and containing structure) of a HIST_ENTRY. */
+void
+_rl_free_history_entry (entry)
+ HIST_ENTRY *entry;
+{
+ if (entry == 0)
+ return;
+ if (entry->line)
+ free (entry->line);
+ free (entry);
+}
+
+/* Perhaps put back the current line if it has changed. */
+int
+maybe_replace_line ()
+{
+ HIST_ENTRY *temp;
+
+ temp = current_history ();
+ /* If the current line has changed, save the changes. */
+ if (temp && ((UNDO_LIST *)(temp->data) != rl_undo_list))
+ {
+ temp = replace_history_entry (where_history (), the_line, (histdata_t)rl_undo_list);
+ free (temp->line);
+ free (temp);
+ }
+ return 0;
+}
+
+/* Put back the saved_line_for_history if there is one. */
+int
+maybe_unsave_line ()
+{
+ int line_len;
+
+ if (saved_line_for_history)
+ {
+ line_len = strlen (saved_line_for_history->line);
+
+ if (line_len >= rl_line_buffer_len)
+ rl_extend_line_buffer (line_len);
+
+ strcpy (the_line, saved_line_for_history->line);
+ rl_undo_list = (UNDO_LIST *)saved_line_for_history->data;
+ _rl_free_history_entry (saved_line_for_history);
+ saved_line_for_history = (HIST_ENTRY *)NULL;
+ rl_end = rl_point = strlen (the_line);
+ }
+ else
+ ding ();
+ return 0;
+}
+
+/* Save the current line in saved_line_for_history. */
+int
+maybe_save_line ()
+{
+ if (saved_line_for_history == 0)
+ {
+ saved_line_for_history = (HIST_ENTRY *)xmalloc (sizeof (HIST_ENTRY));
+ saved_line_for_history->line = savestring (the_line);
+ saved_line_for_history->data = (char *)rl_undo_list;
+ }
+ return 0;
+}
+
+/* **************************************************************** */
+/* */
+/* History Commands */
+/* */
+/* **************************************************************** */
+
+/* Meta-< goes to the start of the history. */
+int
+rl_beginning_of_history (count, key)
+ int count, key;
+{
+ return (rl_get_previous_history (1 + where_history (), key));
+}
+
+/* Meta-> goes to the end of the history. (The current line). */
+int
+rl_end_of_history (count, key)
+ int count, key;
+{
+ maybe_replace_line ();
+ using_history ();
+ maybe_unsave_line ();
+ return 0;
+}
+
+/* Move down to the next history line. */
+int
+rl_get_next_history (count, key)
+ int count, key;
+{
+ HIST_ENTRY *temp;
+ int line_len;
+
+ if (count < 0)
+ return (rl_get_previous_history (-count, key));
+
+ if (count == 0)
+ return 0;
+
+ maybe_replace_line ();
+
+ temp = (HIST_ENTRY *)NULL;
+ while (count)
+ {
+ temp = next_history ();
+ if (!temp)
+ break;
+ --count;
+ }
+
+ if (temp == 0)
+ maybe_unsave_line ();
+ else
+ {
+ line_len = strlen (temp->line);
+
+ if (line_len >= rl_line_buffer_len)
+ rl_extend_line_buffer (line_len);
+
+ strcpy (the_line, temp->line);
+ rl_undo_list = (UNDO_LIST *)temp->data;
+ rl_end = rl_point = strlen (the_line);
+#if defined (VI_MODE)
+ if (rl_editing_mode == vi_mode)
+ rl_point = 0;
+#endif /* VI_MODE */
+ }
+ return 0;
+}
+
+/* Get the previous item out of our interactive history, making it the current
+ line. If there is no previous history, just ding. */
+int
+rl_get_previous_history (count, key)
+ int count, key;
+{
+ HIST_ENTRY *old_temp, *temp;
+ int line_len;
+
+ if (count < 0)
+ return (rl_get_next_history (-count, key));
+
+ if (count == 0)
+ return 0;
+
+ /* If we don't have a line saved, then save this one. */
+ maybe_save_line ();
+
+ /* If the current line has changed, save the changes. */
+ maybe_replace_line ();
+
+ temp = old_temp = (HIST_ENTRY *)NULL;
+ while (count)
+ {
+ temp = previous_history ();
+ if (temp == 0)
+ break;
+
+ old_temp = temp;
+ --count;
+ }
+
+ /* If there was a large argument, and we moved back to the start of the
+ history, that is not an error. So use the last value found. */
+ if (!temp && old_temp)
+ temp = old_temp;
+
+ if (temp == 0)
+ ding ();
+ else
+ {
+ line_len = strlen (temp->line);
+
+ if (line_len >= rl_line_buffer_len)
+ rl_extend_line_buffer (line_len);
+
+ strcpy (the_line, temp->line);
+ rl_undo_list = (UNDO_LIST *)temp->data;
+ rl_end = rl_point = line_len;
+
+#if defined (VI_MODE)
+ if (rl_editing_mode == vi_mode)
+ rl_point = 0;
+#endif /* VI_MODE */
+ }
+ return 0;
+}
+
+/* **************************************************************** */
+/* */
+/* The Mark and the Region. */
+/* */
+/* **************************************************************** */
+
+/* Set the mark at POSITION. */
+int
+_rl_set_mark_at_pos (position)
+ int position;
+{
+ if (position > rl_end)
+ return -1;
+
+ rl_mark = position;
+ return 0;
+}
+
+/* A bindable command to set the mark. */
+int
+rl_set_mark (count, key)
+ int count, key;
+{
+ return (_rl_set_mark_at_pos (rl_explicit_arg ? count : rl_point));
+}
+
+/* Exchange the position of mark and point. */
+int
+rl_exchange_point_and_mark (count, key)
+ int count, key;
+{
+ if (rl_mark > rl_end)
+ rl_mark = -1;
+
+ if (rl_mark == -1)
+ {
+ ding ();
+ return -1;
+ }
+ else
+ SWAP (rl_point, rl_mark);
+
+ return 0;
+}
+
+/* **************************************************************** */
+/* */
+/* Editing Modes */
+/* */
+/* **************************************************************** */
+/* How to toggle back and forth between editing modes. */
+int
+rl_vi_editing_mode (count, key)
+ int count, key;
+{
+#if defined (VI_MODE)
+ rl_editing_mode = vi_mode;
+ rl_vi_insertion_mode (1, key);
+#endif /* VI_MODE */
+ return 0;
+}
+
+int
+rl_emacs_editing_mode (count, key)
+ int count, key;
+{
+ rl_editing_mode = emacs_mode;
+ _rl_keymap = emacs_standard_keymap;
+ return 0;
+}
diff --git a/readline/readline.h b/readline/readline.h
new file mode 100644
index 00000000000..dba1a0fdde9
--- /dev/null
+++ b/readline/readline.h
@@ -0,0 +1,621 @@
+/* Readline.h -- the names of functions callable from within readline. */
+
+/* Copyright (C) 1987, 1989, 1992 Free Software Foundation, Inc.
+
+ This file is part of the GNU Readline Library, a library for
+ reading lines of text with interactive input and history editing.
+
+ The GNU Readline Library is free software; you can redistribute it
+ and/or modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 1, or
+ (at your option) any later version.
+
+ The GNU Readline 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 General Public License for more details.
+
+ The GNU General Public License is often shipped with GNU software, and
+ is generally kept in a file called COPYING or LICENSE. If you do not
+ have a copy of the license, write to the Free Software Foundation,
+ 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#if !defined (_READLINE_H_)
+#define _READLINE_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if defined (READLINE_LIBRARY)
+# include "rlstdc.h"
+# include "keymaps.h"
+# include "tilde.h"
+#else
+# include <readline/rlstdc.h>
+# include <readline/keymaps.h>
+# include <readline/tilde.h>
+#endif
+
+/* Readline data structures. */
+
+/* Maintaining the state of undo. We remember individual deletes and inserts
+ on a chain of things to do. */
+
+/* The actions that undo knows how to undo. Notice that UNDO_DELETE means
+ to insert some text, and UNDO_INSERT means to delete some text. I.e.,
+ the code tells undo what to undo, not how to undo it. */
+enum undo_code { UNDO_DELETE, UNDO_INSERT, UNDO_BEGIN, UNDO_END };
+
+/* What an element of THE_UNDO_LIST looks like. */
+typedef struct undo_list {
+ struct undo_list *next;
+ int start, end; /* Where the change took place. */
+ char *text; /* The text to insert, if undoing a delete. */
+ enum undo_code what; /* Delete, Insert, Begin, End. */
+} UNDO_LIST;
+
+/* The current undo list for RL_LINE_BUFFER. */
+extern UNDO_LIST *rl_undo_list;
+
+/* The data structure for mapping textual names to code addresses. */
+typedef struct _funmap {
+ char *name;
+ Function *function;
+} FUNMAP;
+
+extern FUNMAP **funmap;
+
+/* **************************************************************** */
+/* */
+/* Functions available to bind to key sequences */
+/* */
+/* **************************************************************** */
+
+/* Bindable commands for numeric arguments. */
+extern int rl_digit_argument __P((int, int));
+extern int rl_universal_argument __P((int, int));
+
+/* Bindable commands for moving the cursor. */
+extern int rl_forward __P((int, int));
+extern int rl_backward __P((int, int));
+extern int rl_beg_of_line __P((int, int));
+extern int rl_end_of_line __P((int, int));
+extern int rl_forward_word __P((int, int));
+extern int rl_backward_word __P((int, int));
+extern int rl_refresh_line __P((int, int));
+extern int rl_clear_screen __P((int, int));
+extern int rl_arrow_keys __P((int, int));
+
+/* Bindable commands for inserting and deleting text. */
+extern int rl_insert __P((int, int));
+extern int rl_quoted_insert __P((int, int));
+extern int rl_tab_insert __P((int, int));
+extern int rl_newline __P((int, int));
+extern int rl_do_lowercase_version __P((int, int));
+extern int rl_rubout __P((int, int));
+extern int rl_delete __P((int, int));
+extern int rl_rubout_or_delete __P((int, int));
+extern int rl_delete_horizontal_space __P((int, int));
+extern int rl_delete_or_show_completions __P((int, int));
+extern int rl_insert_comment __P((int, int));
+
+/* Bindable commands for changing case. */
+extern int rl_upcase_word __P((int, int));
+extern int rl_downcase_word __P((int, int));
+extern int rl_capitalize_word __P((int, int));
+
+/* Bindable commands for transposing characters and words. */
+extern int rl_transpose_words __P((int, int));
+extern int rl_transpose_chars __P((int, int));
+
+/* Bindable commands for searching within a line. */
+extern int rl_char_search __P((int, int));
+extern int rl_backward_char_search __P((int, int));
+
+/* Bindable commands for readline's interface to the command history. */
+extern int rl_beginning_of_history __P((int, int));
+extern int rl_end_of_history __P((int, int));
+extern int rl_get_next_history __P((int, int));
+extern int rl_get_previous_history __P((int, int));
+
+/* Bindable commands for managing the mark and region. */
+extern int rl_set_mark __P((int, int));
+extern int rl_exchange_point_and_mark __P((int, int));
+
+/* Bindable commands to set the editing mode (emacs or vi). */
+extern int rl_vi_editing_mode __P((int, int));
+extern int rl_emacs_editing_mode __P((int, int));
+
+/* Bindable commands for managing key bindings. */
+extern int rl_re_read_init_file __P((int, int));
+extern int rl_dump_functions __P((int, int));
+extern int rl_dump_macros __P((int, int));
+extern int rl_dump_variables __P((int, int));
+
+/* Bindable commands for word completion. */
+extern int rl_complete __P((int, int));
+extern int rl_possible_completions __P((int, int));
+extern int rl_insert_completions __P((int, int));
+extern int rl_menu_complete __P((int, int));
+
+/* Bindable commands for killing and yanking text, and managing the kill ring. */
+extern int rl_kill_word __P((int, int));
+extern int rl_backward_kill_word __P((int, int));
+extern int rl_kill_line __P((int, int));
+extern int rl_backward_kill_line __P((int, int));
+extern int rl_kill_full_line __P((int, int));
+extern int rl_unix_word_rubout __P((int, int));
+extern int rl_unix_line_discard __P((int, int));
+extern int rl_copy_region_to_kill __P((int, int));
+extern int rl_kill_region __P((int, int));
+extern int rl_copy_forward_word __P((int, int));
+extern int rl_copy_backward_word __P((int, int));
+extern int rl_yank __P((int, int));
+extern int rl_yank_pop __P((int, int));
+extern int rl_yank_nth_arg __P((int, int));
+extern int rl_yank_last_arg __P((int, int));
+/* Not available unless __CYGWIN32__ is defined. */
+#ifdef __CYGWIN32__
+extern int rl_paste_from_clipboard __P((int, int));
+#endif
+
+/* Bindable commands for incremental searching. */
+extern int rl_reverse_search_history __P((int, int));
+extern int rl_forward_search_history __P((int, int));
+
+/* Bindable keyboard macro commands. */
+extern int rl_start_kbd_macro __P((int, int));
+extern int rl_end_kbd_macro __P((int, int));
+extern int rl_call_last_kbd_macro __P((int, int));
+
+/* Bindable undo commands. */
+extern int rl_revert_line __P((int, int));
+extern int rl_undo_command __P((int, int));
+
+/* Bindable tilde expansion commands. */
+extern int rl_tilde_expand __P((int, int));
+
+/* Bindable terminal control commands. */
+extern int rl_restart_output __P((int, int));
+extern int rl_stop_output __P((int, int));
+
+/* Miscellaneous bindable commands. */
+extern int rl_abort __P((int, int));
+extern int rl_tty_status __P((int, int));
+
+/* Bindable commands for incremental and non-incremental history searching. */
+extern int rl_history_search_forward __P((int, int));
+extern int rl_history_search_backward __P((int, int));
+extern int rl_noninc_forward_search __P((int, int));
+extern int rl_noninc_reverse_search __P((int, int));
+extern int rl_noninc_forward_search_again __P((int, int));
+extern int rl_noninc_reverse_search_again __P((int, int));
+
+/* Not available unless readline is compiled -DPAREN_MATCHING. */
+extern int rl_insert_close __P((int, int));
+
+/* Not available unless READLINE_CALLBACKS is defined. */
+extern void rl_callback_handler_install __P((char *, VFunction *));
+extern void rl_callback_read_char __P((void));
+extern void rl_callback_handler_remove __P((void));
+
+/* Things for vi mode. Not available unless readline is compiled -DVI_MODE. */
+/* VI-mode bindable commands. */
+extern int rl_vi_redo __P((int, int));
+extern int rl_vi_undo __P((int, int));
+extern int rl_vi_yank_arg __P((int, int));
+extern int rl_vi_fetch_history __P((int, int));
+extern int rl_vi_search_again __P((int, int));
+extern int rl_vi_search __P((int, int));
+extern int rl_vi_complete __P((int, int));
+extern int rl_vi_tilde_expand __P((int, int));
+extern int rl_vi_prev_word __P((int, int));
+extern int rl_vi_next_word __P((int, int));
+extern int rl_vi_end_word __P((int, int));
+extern int rl_vi_insert_beg __P((int, int));
+extern int rl_vi_append_mode __P((int, int));
+extern int rl_vi_append_eol __P((int, int));
+extern int rl_vi_eof_maybe __P((int, int));
+extern int rl_vi_insertion_mode __P((int, int));
+extern int rl_vi_movement_mode __P((int, int));
+extern int rl_vi_arg_digit __P((int, int));
+extern int rl_vi_change_case __P((int, int));
+extern int rl_vi_put __P((int, int));
+extern int rl_vi_column __P((int, int));
+extern int rl_vi_delete_to __P((int, int));
+extern int rl_vi_change_to __P((int, int));
+extern int rl_vi_yank_to __P((int, int));
+extern int rl_vi_delete __P((int, int));
+extern int rl_vi_back_to_indent __P((int, int));
+extern int rl_vi_first_print __P((int, int));
+extern int rl_vi_char_search __P((int, int));
+extern int rl_vi_match __P((int, int));
+extern int rl_vi_change_char __P((int, int));
+extern int rl_vi_subst __P((int, int));
+extern int rl_vi_overstrike __P((int, int));
+extern int rl_vi_overstrike_delete __P((int, int));
+extern int rl_vi_replace __P((int, int));
+extern int rl_vi_set_mark __P((int, int));
+extern int rl_vi_goto_mark __P((int, int));
+
+/* VI-mode utility functions. */
+extern int rl_vi_check __P((void));
+extern int rl_vi_domove __P((int, int *));
+extern int rl_vi_bracktype __P((int));
+
+/* VI-mode pseudo-bindable commands, used as utility functions. */
+extern int rl_vi_fWord __P((int, int));
+extern int rl_vi_bWord __P((int, int));
+extern int rl_vi_eWord __P((int, int));
+extern int rl_vi_fword __P((int, int));
+extern int rl_vi_bword __P((int, int));
+extern int rl_vi_eword __P((int, int));
+
+/* **************************************************************** */
+/* */
+/* Well Published Functions */
+/* */
+/* **************************************************************** */
+
+/* Readline functions. */
+/* Read a line of input. Prompt with PROMPT. A NULL PROMPT means none. */
+extern char *readline __P((char *));
+
+extern int rl_initialize __P((void));
+
+extern int rl_discard_argument __P((void));
+
+/* Utility functions to bind keys to readline commands. */
+extern int rl_add_defun __P((char *, Function *, int));
+extern int rl_bind_key __P((int, Function *));
+extern int rl_bind_key_in_map __P((int, Function *, Keymap));
+extern int rl_unbind_key __P((int));
+extern int rl_unbind_key_in_map __P((int, Keymap));
+extern int rl_unbind_function_in_map __P((Function *, Keymap));
+extern int rl_unbind_command_in_map __P((char *, Keymap));
+extern int rl_set_key __P((char *, Function *, Keymap));
+extern int rl_generic_bind __P((int, char *, char *, Keymap));
+extern int rl_variable_bind __P((char *, char *));
+
+/* Backwards compatibility, use rl_generic_bind instead. */
+extern int rl_macro_bind __P((char *, char *, Keymap));
+
+/* Undocumented in the texinfo manual; not really useful to programs. */
+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 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_parse_and_bind __P((char *));
+
+/* Functions for manipulating keymaps. */
+extern Keymap rl_make_bare_keymap __P((void));
+extern Keymap rl_copy_keymap __P((Keymap));
+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 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));
+
+/* Functions for manipulating the funmap, which maps command names to functions. */
+extern int rl_add_funmap_entry __P((char *, Function *));
+extern void rl_initialize_funmap __P((void));
+extern char **rl_funmap_names __P((void));
+
+/* Utility functions for managing keyboard macros. */
+extern void rl_push_macro_input __P((char *));
+
+/* Functions for undoing, from undo.c */
+extern void rl_add_undo __P((enum undo_code, int, int, char *));
+extern void free_undo_list __P((void));
+extern int rl_do_undo __P((void));
+extern int rl_begin_undo_group __P((void));
+extern int rl_end_undo_group __P((void));
+extern int rl_modifying __P((int, int));
+
+/* Functions for redisplay. */
+extern void rl_redisplay __P((void));
+extern int rl_on_new_line __P((void));
+extern int rl_forced_update_display __P((void));
+extern int rl_clear_message __P((void));
+extern int rl_reset_line_state __P((void));
+
+#if defined (__STDC__) && defined (USE_VARARGS) && defined (PREFER_STDARG)
+extern int rl_message (const char *, ...);
+#else
+extern int rl_message ();
+#endif
+
+/* Undocumented in texinfo manual. */
+extern int rl_show_char __P((int));
+extern int rl_character_len __P((int, int));
+extern int crlf __P((void));
+
+/* Save and restore internal prompt redisplay information. */
+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_delete_text __P((int, int));
+extern int rl_kill_text __P((int, int));
+extern char *rl_copy_text __P((int, int));
+
+/* Terminal and tty mode management. */
+extern void rl_prep_terminal __P((int));
+extern void rl_deprep_terminal __P((void));
+extern void rltty_set_default_bindings __P((Keymap));
+
+extern int rl_reset_terminal __P((char *));
+extern void rl_resize_terminal __P((void));
+
+/* `Public' utility functions . */
+extern void rl_extend_line_buffer __P((int));
+extern int ding __P((void));
+
+/* Functions for character input. */
+extern int rl_stuff_char __P((int));
+extern int rl_execute_next __P((int));
+extern int rl_read_key __P((void));
+extern int rl_getc __P((FILE *));
+
+/* Readline signal handling, from signals.c */
+extern int rl_set_signals __P((void));
+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 *));
+
+extern int maybe_save_line __P((void));
+extern int maybe_unsave_line __P((void));
+extern int maybe_replace_line __P((void));
+
+/* Completion functions. */
+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));
+
+/* **************************************************************** */
+/* */
+/* Well Published Variables */
+/* */
+/* **************************************************************** */
+
+/* The version of this incarnation of the readline library. */
+extern 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;
+
+/* The prompt readline uses. This is set from the argument to
+ readline (), and should not be assigned to directly. */
+extern char *rl_prompt;
+
+/* The line buffer that is in use. */
+extern char *rl_line_buffer;
+
+/* The location of point, and end. */
+extern int rl_point, rl_end;
+
+/* The mark, or saved cursor position. */
+extern int rl_mark;
+
+/* Flag to indicate that readline has finished with the current input
+ line and should return it. */
+extern int rl_done;
+
+/* If set to a character value, that will be the next keystroke read. */
+extern int rl_pending_input;
+
+/* Non-zero if we called this function from _rl_dispatch(). It's present
+ so functions can find out whether they were called from a key binding
+ or directly from an application. */
+extern int rl_dispatching;
+
+/* The name of the terminal to use. */
+extern char *rl_terminal_name;
+
+/* The input and output streams. */
+extern FILE *rl_instream, *rl_outstream;
+
+/* If non-zero, then this is the address of a function to call just
+ before readline_internal () prints the first prompt. */
+extern Function *rl_startup_hook;
+
+/* If non-zero, this is the address of a function to call just before
+ 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;
+
+extern Function *rl_getc_function;
+extern VFunction *rl_redisplay_function;
+extern VFunction *rl_prep_term_function;
+extern VFunction *rl_deprep_term_function;
+
+/* Dispatch variables. */
+extern Keymap rl_executing_keymap;
+extern Keymap rl_binding_keymap;
+
+/* Display variables. */
+/* If non-zero, readline will erase the entire line, including any prompt,
+ if the only thing typed on an otherwise-blank line is something bound to
+ rl_newline. */
+extern int rl_erase_empty_line;
+
+/* Variables to control readline signal handling. */
+/* If non-zero, readline will install its own signal handlers for
+ SIGINT, SIGTERM, SIGQUIT, SIGALRM, SIGTSTP, SIGTTIN, and SIGTTOU. */
+extern int rl_catch_signals;
+
+/* If non-zero, readline will install a signal handler for SIGWINCH
+ that also attempts to call any calling application's SIGWINCH signal
+ handler. Note that the terminal is not cleaned up before the
+ application's signal handler is called; use rl_cleanup_after_signal()
+ to do that. */
+extern int rl_catch_sigwinch;
+
+/* Completion variables. */
+/* Pointer to the generator function for completion_matches ().
+ NULL means to use filename_entry_function (), the default filename
+ completer. */
+extern Function *rl_completion_entry_function;
+
+/* If rl_ignore_some_completions_function is non-NULL it is the address
+ of a function to call after all of the possible matches have been
+ generated, but before the actual completion is done to the input line.
+ The function is called with one argument; a NULL terminated array
+ of (char *). If your function removes any of the elements, they
+ must be free()'ed. */
+extern Function *rl_ignore_some_completions_function;
+
+/* Pointer to alternative function to create matches.
+ Function is called with TEXT, START, and END.
+ START and END are indices in RL_LINE_BUFFER saying what the boundaries
+ of TEXT are.
+ If this function exists and returns NULL then call the value of
+ rl_completion_entry_function to try to match, otherwise use the
+ array of strings returned. */
+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;
+
+/* 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;
+
+/* List of characters which can be used to quote a substring of the line.
+ Completion occurs on the entire substring, and within the substring
+ rl_completer_word_break_characters are treated as any other character,
+ unless they also appear within this list. */
+extern char *rl_completer_quote_characters;
+
+/* List of quote characters which cause a word break. */
+extern char *rl_basic_quote_characters;
+
+/* List of characters that need to be quoted in filenames by the completer. */
+extern char *rl_filename_quote_characters;
+
+/* List of characters that are word break characters, but should be left
+ in TEXT when it is passed to the completion function. The shell uses
+ this to help determine what kind of completing to do. */
+extern char *rl_special_prefixes;
+
+/* If non-zero, then this is the address of a function to call when
+ completing on a directory name. The function is called with
+ the address of a string (the current directory name) as an arg. */
+extern Function *rl_directory_completion_hook;
+
+/* Backwards compatibility with previous versions of readline. */
+#define rl_symbolic_link_hook rl_directory_completion_hook
+
+/* If non-zero, then this is the address of a function to call when
+ completing a word would normally display the list of possible matches.
+ This function is called instead of actually doing the display.
+ It takes three arguments: (char **matches, int num_matches, int max_length)
+ where MATCHES is the array of strings that matched, NUM_MATCHES is the
+ number of strings in that array, and MAX_LENGTH is the length of the
+ longest string in that array. */
+extern VFunction *rl_completion_display_matches_hook;
+
+/* Non-zero means that the results of the matches are to be treated
+ as filenames. This is ALWAYS zero on entry, and can only be changed
+ within a completion entry finder function. */
+extern int rl_filename_completion_desired;
+
+/* Non-zero means that the results of the matches are to be quoted using
+ double quotes (or an application-specific quoting mechanism) if the
+ filename contains any characters in rl_word_break_chars. This is
+ ALWAYS non-zero on entry, and can only be changed within a completion
+ entry finder function. */
+extern int rl_filename_quoting_desired;
+
+/* Set to a function to quote a filename in an application-specific fashion.
+ Called with the text to quote, the type of match found (single or multiple)
+ and a pointer to the quoting character to be used, which the function can
+ reset if desired. */
+extern CPFunction *rl_filename_quoting_function;
+
+/* 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. */
+extern CPFunction *rl_filename_dequoting_function;
+
+/* Function to call to decide whether or not a word break character is
+ quoted. If a character is quoted, it does not break words for the
+ completer. */
+extern Function *rl_char_is_quoted_p;
+
+/* Non-zero means to suppress normal filename completion after the
+ user-specified completion function has been called. */
+extern int rl_attempted_completion_over;
+
+/* Set to a character describing the type of completion being attempted by
+ rl_complete_internal; available for use by application completion
+ functions. */
+extern int rl_completion_type;
+
+/* Character appended to completed words when at the end of the line. The
+ default is a space. Nothing is added if this is '\0'. */
+extern int rl_completion_append_character;
+
+/* Up to this many items will be displayed in response to a
+ possible-completions call. After that, we ask the user if she
+ is sure she wants to see them all. The default value is 100. */
+extern int rl_completion_query_items;
+
+/* If non-zero, then disallow duplicates in the matches. */
+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'
+
+/* Possible values for do_replace argument to rl_filename_quoting_function,
+ called by rl_complete_internal. */
+#define NO_MATCH 0
+#define SINGLE_MATCH 1
+#define MULT_MATCH 2
+
+#if !defined (savestring)
+extern char *savestring (); /* XXX backwards compatibility */
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _READLINE_H_ */
diff --git a/readline/rlconf.h b/readline/rlconf.h
new file mode 100644
index 00000000000..1356fd87924
--- /dev/null
+++ b/readline/rlconf.h
@@ -0,0 +1,61 @@
+/* rlconf.h -- readline configuration definitions */
+
+/* Copyright (C) 1994 Free Software Foundation, Inc.
+
+ This file contains the Readline Library (the Library), a set of
+ routines for providing Emacs style line input to programs that ask
+ for it.
+
+ The Library is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 1, or (at your option)
+ any later version.
+
+ The 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
+ General Public License for more details.
+
+ The GNU General Public License is often shipped with GNU software, and
+ is generally kept in a file called COPYING or LICENSE. If you do not
+ have a copy of the license, write to the Free Software Foundation,
+ 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#if !defined (_RLCONF_H_)
+#define _RLCONF_H_
+
+/* Define this if you want the vi-mode editing available. */
+#define VI_MODE
+
+/* Define this to get an indication of file type when listing completions. */
+#define VISIBLE_STATS
+
+/* If defined, readline shows opening parens and braces when closing
+ paren or brace entered. */
+/* #define PAREN_MATCHING */
+
+/* This definition is needed by readline.c, rltty.c, and signals.c. */
+/* If on, then readline handles signals in a way that doesn't screw. */
+#define HANDLE_SIGNALS
+
+/* Ugly but working hack for binding prefix meta. */
+#define PREFIX_META_HACK
+
+/* The final, last-ditch effort file name for an init file. */
+#define DEFAULT_INPUTRC "~/.inputrc"
+
+/* If defined, expand tabs to spaces. */
+#define DISPLAY_TABS
+
+/* If defined, use the terminal escape sequence to move the cursor forward
+ over a character when updating the line rather than rewriting it. */
+/* #define HACK_TERMCAP_MOTION */
+
+/* The string inserted by the `insert comment' command. */
+#define RL_COMMENT_BEGIN_DEFAULT "#"
+
+/* Define this if you want code that allows readline to be used in an
+ X `callback' style. */
+#define READLINE_CALLBACKS
+
+#endif /* _RLCONF_H_ */
diff --git a/readline/rldefs.h b/readline/rldefs.h
new file mode 100644
index 00000000000..d4aced43e2a
--- /dev/null
+++ b/readline/rldefs.h
@@ -0,0 +1,135 @@
+/* rldefs.h -- an attempt to isolate some of the system-specific defines
+ for readline. This should be included after any files that define
+ system-specific constants like _POSIX_VERSION or USG. */
+
+/* Copyright (C) 1987,1989 Free Software Foundation, Inc.
+
+ This file contains the Readline Library (the Library), a set of
+ routines for providing Emacs style line input to programs that ask
+ for it.
+
+ The Library is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 1, or (at your option)
+ any later version.
+
+ The 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
+ General Public License for more details.
+
+ The GNU General Public License is often shipped with GNU software, and
+ is generally kept in a file called COPYING or LICENSE. If you do not
+ have a copy of the license, write to the Free Software Foundation,
+ 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#if !defined (_RLDEFS_H_)
+#define _RLDEFS_H_
+
+#if defined (HAVE_CONFIG_H)
+# include "config.h"
+#endif
+
+#if defined (_POSIX_VERSION) && !defined (TERMIOS_MISSING)
+# define TERMIOS_TTY_DRIVER
+#else
+# if defined (HAVE_TERMIO_H)
+# define TERMIO_TTY_DRIVER
+# else
+# define NEW_TTY_DRIVER
+# endif
+#endif
+
+/* Posix macro to check file in statbuf for directory-ness.
+ This requires that <sys/stat.h> be included before this test. */
+#if defined (S_IFDIR) && !defined (S_ISDIR)
+# define S_ISDIR(m) (((m)&S_IFMT) == S_IFDIR)
+#endif
+
+/* Decide which flavor of the header file describing the C library
+ string functions to include and include it. */
+
+#if defined (HAVE_STRING_H)
+# include <string.h>
+#else /* !HAVE_STRING_H */
+# include <strings.h>
+#endif /* !HAVE_STRING_H */
+
+#if !defined (strchr) && !defined (__STDC__)
+extern char *strchr (), *strrchr ();
+#endif /* !strchr && !__STDC__ */
+
+#if defined (PREFER_STDARG)
+# include <stdarg.h>
+#else
+# if defined (PREFER_VARARGS)
+# include <varargs.h>
+# endif
+#endif
+
+#if defined (HAVE_STRCASECMP)
+#define _rl_stricmp strcasecmp
+#define _rl_strnicmp strncasecmp
+#else
+extern int _rl_stricmp (), _rl_strnicmp ();
+#endif
+
+#if !defined (emacs_mode)
+# define no_mode -1
+# define vi_mode 0
+# define emacs_mode 1
+#endif
+
+/* If you cast map[key].function to type (Keymap) on a Cray,
+ the compiler takes the value of map[key].function and
+ divides it by 4 to convert between pointer types (pointers
+ to functions and pointers to structs are different sizes).
+ This is not what is wanted. */
+#if defined (CRAY)
+# define FUNCTION_TO_KEYMAP(map, key) (Keymap)((int)map[key].function)
+# define KEYMAP_TO_FUNCTION(data) (Function *)((int)(data))
+#else
+# define FUNCTION_TO_KEYMAP(map, key) (Keymap)(map[key].function)
+# define KEYMAP_TO_FUNCTION(data) (Function *)(data)
+#endif
+
+#ifndef savestring
+extern char *xmalloc ();
+#define savestring(x) strcpy (xmalloc (1 + strlen (x)), (x))
+#endif
+
+/* Possible values for _rl_bell_preference. */
+#define NO_BELL 0
+#define AUDIBLE_BELL 1
+#define VISIBLE_BELL 2
+
+/* Definitions used when searching the line for characters. */
+/* NOTE: it is necessary that opposite directions are inverses */
+#define FTO 1 /* forward to */
+#define BTO -1 /* backward to */
+#define FFIND 2 /* forward find */
+#define BFIND -2 /* backward find */
+
+/* Possible values for the found_quote flags word used by the completion
+ functions. It says what kind of (shell-like) quoting we found anywhere
+ in the line. */
+#define RL_QF_SINGLE_QUOTE 0x1
+#define RL_QF_DOUBLE_QUOTE 0x2
+#define RL_QF_BACKSLASH 0x4
+
+/* Default readline line buffer length. */
+#define DEFAULT_BUFFER_SIZE 256
+
+#if !defined (STREQ)
+#define STREQ(a, b) (((a)[0] == (b)[0]) && (strcmp ((a), (b)) == 0))
+#define STREQN(a, b, n) (((a)[0] == (b)[0]) && (strncmp ((a), (b), (n)) == 0))
+#endif
+
+#if !defined (FREE)
+# define FREE(x) if (x) free (x)
+#endif
+
+/* CONFIGURATION SECTION */
+#include "rlconf.h"
+
+#endif /* !_RLDEFS_H_ */
diff --git a/readline/rlstdc.h b/readline/rlstdc.h
new file mode 100644
index 00000000000..d2c5f874d7a
--- /dev/null
+++ b/readline/rlstdc.h
@@ -0,0 +1,79 @@
+/* stdc.h -- macros to make source compile on both ANSI C and K&R C
+ compilers. */
+
+/* Copyright (C) 1993 Free Software Foundation, Inc.
+
+ This file is part of GNU Bash, the Bourne Again SHell.
+
+ Bash is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 1, or (at your option)
+ any later version.
+
+ Bash is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Bash; see the file COPYING. If not, write to the Free
+ Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#if !defined (_RL_STDC_H_)
+#define _RL_STDC_H_
+
+/* Adapted from BSD /usr/include/sys/cdefs.h. */
+
+/* A function can be defined using prototypes and compile on both ANSI C
+ and traditional C compilers with something like this:
+ extern char *func __P((char *, char *, int)); */
+
+#if defined (__STDC__) || defined(__cplusplus)
+
+# if !defined (__P)
+# define __P(protos) protos
+# endif
+# define __STRING(x) #x
+
+# if !defined (__GNUC__) && !defined(__cplusplus) && !defined(inline)
+# define inline
+# endif
+
+#else /* !__STDC__ */
+
+# if !defined (__P)
+# define __P(protos) ()
+# endif
+# define __STRING(x) "x"
+
+#if defined (__GNUC__) /* gcc with -traditional */
+# if !defined (const)
+# define const __const
+# endif
+# if !defined (inline)
+# define inline __inline
+# endif
+# if !defined (signed)
+# define signed __signed
+# endif
+# if !defined (volatile)
+# define volatile __volatile
+# endif
+#else /* !__GNUC__ */
+# if !defined (const)
+# define const
+# endif
+# if !defined (inline)
+# define inline
+# endif
+# if !defined (signed)
+# define signed
+# endif
+# if !defined (volatile)
+# define volatile
+# endif
+#endif /* !__GNUC__ */
+
+#endif /* !__STDC__ */
+
+#endif /* !_RL_STDC_H_ */
diff --git a/readline/rltty.c b/readline/rltty.c
new file mode 100644
index 00000000000..a5ef938b5c0
--- /dev/null
+++ b/readline/rltty.c
@@ -0,0 +1,727 @@
+/* rltty.c -- functions to prepare and restore the terminal for readline's
+ use. */
+
+/* Copyright (C) 1992 Free Software Foundation, Inc.
+
+ This file is part of the GNU Readline Library, a library for
+ reading lines of text with interactive input and history editing.
+
+ The GNU Readline Library is free software; you can redistribute it
+ and/or modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 1, or
+ (at your option) any later version.
+
+ The GNU Readline 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 General Public License for more details.
+
+ The GNU General Public License is often shipped with GNU software, and
+ is generally kept in a file called COPYING or LICENSE. If you do not
+ have a copy of the license, write to the Free Software Foundation,
+ 675 Mass Ave, Cambridge, MA 02139, USA. */
+#define READLINE_LIBRARY
+
+#if defined (HAVE_CONFIG_H)
+# include <config.h>
+#endif
+
+#include <sys/types.h>
+#include <signal.h>
+#include <errno.h>
+#include <stdio.h>
+
+#if defined (HAVE_UNISTD_H)
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+
+#include "rldefs.h"
+
+#if defined (GWINSZ_IN_SYS_IOCTL)
+# include <sys/ioctl.h>
+#endif /* GWINSZ_IN_SYS_IOCTL */
+
+#include "rltty.h"
+#include "readline.h"
+
+#if !defined (errno)
+extern int errno;
+#endif /* !errno */
+
+extern int readline_echoing_p;
+extern int _rl_eof_char;
+
+extern int _rl_enable_keypad, _rl_enable_meta;
+
+extern void _rl_control_keypad ();
+
+#if defined (__GO32__)
+# include <pc.h>
+# undef HANDLE_SIGNALS
+#endif /* __GO32__ */
+
+/* Indirect functions to allow apps control over terminal management. */
+extern void rl_prep_terminal (), rl_deprep_terminal ();
+
+VFunction *rl_prep_term_function = rl_prep_terminal;
+VFunction *rl_deprep_term_function = rl_deprep_terminal;
+
+/* **************************************************************** */
+/* */
+/* Signal Management */
+/* */
+/* **************************************************************** */
+
+#if defined (HAVE_POSIX_SIGNALS)
+static sigset_t sigint_set, sigint_oset;
+#else /* !HAVE_POSIX_SIGNALS */
+# if defined (HAVE_BSD_SIGNALS)
+static int sigint_oldmask;
+# endif /* HAVE_BSD_SIGNALS */
+#endif /* !HAVE_POSIX_SIGNALS */
+
+static int sigint_blocked;
+
+/* Cause SIGINT to not be delivered until the corresponding call to
+ release_sigint(). */
+static void
+block_sigint ()
+{
+ if (sigint_blocked)
+ return;
+
+#if defined (HAVE_POSIX_SIGNALS)
+ sigemptyset (&sigint_set);
+ sigemptyset (&sigint_oset);
+ sigaddset (&sigint_set, SIGINT);
+ sigprocmask (SIG_BLOCK, &sigint_set, &sigint_oset);
+#else /* !HAVE_POSIX_SIGNALS */
+# if defined (HAVE_BSD_SIGNALS)
+ sigint_oldmask = sigblock (sigmask (SIGINT));
+# else /* !HAVE_BSD_SIGNALS */
+# if defined (HAVE_USG_SIGHOLD)
+ sighold (SIGINT);
+# endif /* HAVE_USG_SIGHOLD */
+# endif /* !HAVE_BSD_SIGNALS */
+#endif /* !HAVE_POSIX_SIGNALS */
+ sigint_blocked = 1;
+}
+
+/* Allow SIGINT to be delivered. */
+static void
+release_sigint ()
+{
+ if (!sigint_blocked)
+ return;
+
+#if defined (HAVE_POSIX_SIGNALS)
+ sigprocmask (SIG_SETMASK, &sigint_oset, (sigset_t *)NULL);
+#else
+# if defined (HAVE_BSD_SIGNALS)
+ sigsetmask (sigint_oldmask);
+# else /* !HAVE_BSD_SIGNALS */
+# if defined (HAVE_USG_SIGHOLD)
+ sigrelse (SIGINT);
+# endif /* HAVE_USG_SIGHOLD */
+# endif /* !HAVE_BSD_SIGNALS */
+#endif /* !HAVE_POSIX_SIGNALS */
+
+ sigint_blocked = 0;
+}
+
+/* **************************************************************** */
+/* */
+/* Saving and Restoring the TTY */
+/* */
+/* **************************************************************** */
+
+/* Non-zero means that the terminal is in a prepped state. */
+static int terminal_prepped;
+
+/* If non-zero, means that this process has called tcflow(fd, TCOOFF)
+ and output is suspended. */
+#if defined (__ksr1__)
+static int ksrflow;
+#endif
+
+#if defined (TIOCGWINSZ)
+/* Dummy call to force a backgrounded readline to stop before it tries
+ to get the tty settings. */
+static void
+set_winsize (tty)
+ int tty;
+{
+ struct winsize w;
+
+ if (ioctl (tty, TIOCGWINSZ, &w) == 0)
+ (void) ioctl (tty, TIOCSWINSZ, &w);
+}
+#endif /* TIOCGWINSZ */
+
+#if defined (NEW_TTY_DRIVER)
+
+/* Values for the `flags' field of a struct bsdtty. This tells which
+ elements of the struct bsdtty have been fetched from the system and
+ are valid. */
+#define SGTTY_SET 0x01
+#define LFLAG_SET 0x02
+#define TCHARS_SET 0x04
+#define LTCHARS_SET 0x08
+
+struct bsdtty {
+ struct sgttyb sgttyb; /* Basic BSD tty driver information. */
+ int lflag; /* Local mode flags, like LPASS8. */
+#if defined (TIOCGETC)
+ struct tchars tchars; /* Terminal special characters, including ^S and ^Q. */
+#endif
+#if defined (TIOCGLTC)
+ struct ltchars ltchars; /* 4.2 BSD editing characters */
+#endif
+ int flags; /* Bitmap saying which parts of the struct are valid. */
+};
+
+#define TIOTYPE struct bsdtty
+
+static TIOTYPE otio;
+
+static int
+get_tty_settings (tty, tiop)
+ int tty;
+ TIOTYPE *tiop;
+{
+ set_winsize (tty);
+
+ tiop->flags = tiop->lflag = 0;
+
+ ioctl (tty, TIOCGETP, &(tiop->sgttyb));
+ tiop->flags |= SGTTY_SET;
+
+#if defined (TIOCLGET)
+ ioctl (tty, TIOCLGET, &(tiop->lflag));
+ tiop->flags |= LFLAG_SET;
+#endif
+
+#if defined (TIOCGETC)
+ ioctl (tty, TIOCGETC, &(tiop->tchars));
+ tiop->flags |= TCHARS_SET;
+#endif
+
+#if defined (TIOCGLTC)
+ ioctl (tty, TIOCGLTC, &(tiop->ltchars));
+ tiop->flags |= LTCHARS_SET;
+#endif
+
+ return 0;
+}
+
+static int
+set_tty_settings (tty, tiop)
+ int tty;
+ TIOTYPE *tiop;
+{
+ if (tiop->flags & SGTTY_SET)
+ {
+ ioctl (tty, TIOCSETN, &(tiop->sgttyb));
+ tiop->flags &= ~SGTTY_SET;
+ }
+ readline_echoing_p = 1;
+
+#if defined (TIOCLSET)
+ if (tiop->flags & LFLAG_SET)
+ {
+ ioctl (tty, TIOCLSET, &(tiop->lflag));
+ tiop->flags &= ~LFLAG_SET;
+ }
+#endif
+
+#if defined (TIOCSETC)
+ if (tiop->flags & TCHARS_SET)
+ {
+ ioctl (tty, TIOCSETC, &(tiop->tchars));
+ tiop->flags &= ~TCHARS_SET;
+ }
+#endif
+
+#if defined (TIOCSLTC)
+ if (tiop->flags & LTCHARS_SET)
+ {
+ ioctl (tty, TIOCSLTC, &(tiop->ltchars));
+ tiop->flags &= ~LTCHARS_SET;
+ }
+#endif
+
+ return 0;
+}
+
+static void
+prepare_terminal_settings (meta_flag, otio, tiop)
+ int meta_flag;
+ TIOTYPE otio, *tiop;
+{
+#if !defined (__GO32__)
+ readline_echoing_p = (otio.sgttyb.sg_flags & ECHO);
+
+ /* Copy the original settings to the structure we're going to use for
+ our settings. */
+ tiop->sgttyb = otio.sgttyb;
+ tiop->lflag = otio.lflag;
+#if defined (TIOCGETC)
+ tiop->tchars = otio.tchars;
+#endif
+#if defined (TIOCGLTC)
+ tiop->ltchars = otio.ltchars;
+#endif
+ tiop->flags = otio.flags;
+
+ /* First, the basic settings to put us into character-at-a-time, no-echo
+ input mode. */
+ tiop->sgttyb.sg_flags &= ~(ECHO | CRMOD);
+ tiop->sgttyb.sg_flags |= CBREAK;
+
+ /* If this terminal doesn't care how the 8th bit is used, then we can
+ use it for the meta-key. If only one of even or odd parity is
+ specified, then the terminal is using parity, and we cannot. */
+#if !defined (ANYP)
+# define ANYP (EVENP | ODDP)
+#endif
+ if (((otio.sgttyb.sg_flags & ANYP) == ANYP) ||
+ ((otio.sgttyb.sg_flags & ANYP) == 0))
+ {
+ tiop->sgttyb.sg_flags |= ANYP;
+
+ /* Hack on local mode flags if we can. */
+#if defined (TIOCLGET)
+# if defined (LPASS8)
+ tiop->lflag |= LPASS8;
+# endif /* LPASS8 */
+#endif /* TIOCLGET */
+ }
+
+#if defined (TIOCGETC)
+# if defined (USE_XON_XOFF)
+ /* Get rid of terminal output start and stop characters. */
+ tiop->tchars.t_stopc = -1; /* C-s */
+ tiop->tchars.t_startc = -1; /* C-q */
+
+ /* If there is an XON character, bind it to restart the output. */
+ if (otio.tchars.t_startc != -1)
+ rl_bind_key (otio.tchars.t_startc, rl_restart_output);
+# endif /* USE_XON_XOFF */
+
+ /* If there is an EOF char, bind _rl_eof_char to it. */
+ if (otio.tchars.t_eofc != -1)
+ _rl_eof_char = otio.tchars.t_eofc;
+
+# if defined (NO_KILL_INTR)
+ /* Get rid of terminal-generated SIGQUIT and SIGINT. */
+ tiop->tchars.t_quitc = -1; /* C-\ */
+ tiop->tchars.t_intrc = -1; /* C-c */
+# endif /* NO_KILL_INTR */
+#endif /* TIOCGETC */
+
+#if defined (TIOCGLTC)
+ /* Make the interrupt keys go away. Just enough to make people happy. */
+ tiop->ltchars.t_dsuspc = -1; /* C-y */
+ tiop->ltchars.t_lnextc = -1; /* C-v */
+#endif /* TIOCGLTC */
+#endif /* !__GO32__ */
+}
+
+#else /* !defined (NEW_TTY_DRIVER) */
+
+#if !defined (VMIN)
+# define VMIN VEOF
+#endif
+
+#if !defined (VTIME)
+# define VTIME VEOL
+#endif
+
+#if defined (TERMIOS_TTY_DRIVER)
+# define TIOTYPE struct termios
+# define DRAIN_OUTPUT(fd) tcdrain (fd)
+# define GETATTR(tty, tiop) (tcgetattr (tty, tiop))
+# ifdef M_UNIX
+# define SETATTR(tty, tiop) (tcsetattr (tty, TCSANOW, tiop))
+# else
+# define SETATTR(tty, tiop) (tcsetattr (tty, TCSADRAIN, tiop))
+# endif /* !M_UNIX */
+#else
+# define TIOTYPE struct termio
+# define DRAIN_OUTPUT(fd)
+# define GETATTR(tty, tiop) (ioctl (tty, TCGETA, tiop))
+# define SETATTR(tty, tiop) (ioctl (tty, TCSETA, tiop))
+#endif /* !TERMIOS_TTY_DRIVER */
+
+static TIOTYPE otio;
+
+#if defined (FLUSHO)
+# define OUTPUT_BEING_FLUSHED(tp) (tp->c_lflag & FLUSHO)
+#else
+# define OUTPUT_BEING_FLUSHED(tp) 0
+#endif
+
+static void
+rltty_warning (msg)
+ char *msg;
+{
+ fprintf (stderr, "readline: warning: %s\n", msg);
+}
+
+#if defined (_AIX)
+void
+setopost(tp)
+TIOTYPE *tp;
+{
+ if ((tp->c_oflag & OPOST) == 0)
+ {
+ rltty_warning ("turning on OPOST for terminal\r");
+ tp->c_oflag |= OPOST|ONLCR;
+ }
+}
+#endif
+
+static int
+get_tty_settings (tty, tiop)
+ int tty;
+ TIOTYPE *tiop;
+{
+ int ioctl_ret;
+
+ set_winsize (tty);
+
+ while (1)
+ {
+ ioctl_ret = GETATTR (tty, tiop);
+ if (ioctl_ret < 0)
+ {
+ if (errno != EINTR)
+ return -1;
+ else
+ continue;
+ }
+ if (OUTPUT_BEING_FLUSHED (tiop))
+ {
+#if defined (FLUSHO) && defined (_AIX41)
+ rltty_warning ("turning off output flushing");
+ tiop->c_lflag &= ~FLUSHO;
+ break;
+#else
+ continue;
+#endif
+ }
+ break;
+ }
+
+#if defined (_AIX)
+ setopost(tiop);
+#endif
+
+ return 0;
+}
+
+static int
+set_tty_settings (tty, tiop)
+ int tty;
+ TIOTYPE *tiop;
+{
+ while (SETATTR (tty, tiop) < 0)
+ {
+ if (errno != EINTR)
+ return -1;
+ errno = 0;
+ }
+
+#if 0
+
+#if defined (TERMIOS_TTY_DRIVER)
+# if defined (__ksr1__)
+ if (ksrflow)
+ {
+ ksrflow = 0;
+ tcflow (tty, TCOON);
+ }
+# else /* !ksr1 */
+ tcflow (tty, TCOON); /* Simulate a ^Q. */
+# endif /* !ksr1 */
+#else
+ ioctl (tty, TCXONC, 1); /* Simulate a ^Q. */
+#endif /* !TERMIOS_TTY_DRIVER */
+
+#endif
+
+ return 0;
+}
+
+static void
+prepare_terminal_settings (meta_flag, otio, tiop)
+ int meta_flag;
+ TIOTYPE otio, *tiop;
+{
+ readline_echoing_p = (otio.c_lflag & ECHO);
+
+ tiop->c_lflag &= ~(ICANON | ECHO);
+
+ if ((unsigned char) otio.c_cc[VEOF] != (unsigned char) _POSIX_VDISABLE)
+ _rl_eof_char = otio.c_cc[VEOF];
+
+#if defined (USE_XON_XOFF)
+#if defined (IXANY)
+ tiop->c_iflag &= ~(IXON | IXOFF | IXANY);
+#else
+ /* `strict' Posix systems do not define IXANY. */
+ tiop->c_iflag &= ~(IXON | IXOFF);
+#endif /* IXANY */
+#endif /* USE_XON_XOFF */
+
+ /* Only turn this off if we are using all 8 bits. */
+ if (((tiop->c_cflag & CSIZE) == CS8) || meta_flag)
+ tiop->c_iflag &= ~(ISTRIP | INPCK);
+
+ /* Make sure we differentiate between CR and NL on input. */
+ tiop->c_iflag &= ~(ICRNL | INLCR);
+
+#if !defined (HANDLE_SIGNALS)
+ tiop->c_lflag &= ~ISIG;
+#else
+ tiop->c_lflag |= ISIG;
+#endif
+
+ tiop->c_cc[VMIN] = 1;
+ tiop->c_cc[VTIME] = 0;
+
+#if defined (FLUSHO)
+ if (OUTPUT_BEING_FLUSHED (tiop))
+ {
+ tiop->c_lflag &= ~FLUSHO;
+ otio.c_lflag &= ~FLUSHO;
+ }
+#endif
+
+ /* Turn off characters that we need on Posix systems with job control,
+ just to be sure. This includes ^Y and ^V. This should not really
+ be necessary. */
+#if defined (TERMIOS_TTY_DRIVER) && defined (_POSIX_VDISABLE)
+
+#if defined (VLNEXT)
+ tiop->c_cc[VLNEXT] = _POSIX_VDISABLE;
+#endif
+
+#if defined (VDSUSP)
+ tiop->c_cc[VDSUSP] = _POSIX_VDISABLE;
+#endif
+
+#endif /* TERMIOS_TTY_DRIVER && _POSIX_VDISABLE */
+}
+#endif /* NEW_TTY_DRIVER */
+
+/* Put the terminal in CBREAK mode so that we can detect key presses. */
+void
+rl_prep_terminal (meta_flag)
+ int meta_flag;
+{
+#if !defined (__GO32__)
+ int tty;
+ TIOTYPE tio;
+
+ if (terminal_prepped)
+ return;
+
+ /* Try to keep this function from being INTerrupted. */
+ block_sigint ();
+
+ tty = fileno (rl_instream);
+
+ if (get_tty_settings (tty, &tio) < 0)
+ {
+ release_sigint ();
+ return;
+ }
+
+ otio = tio;
+
+ prepare_terminal_settings (meta_flag, otio, &tio);
+
+ if (set_tty_settings (tty, &tio) < 0)
+ {
+ release_sigint ();
+ return;
+ }
+
+ if (_rl_enable_keypad)
+ _rl_control_keypad (1);
+
+ fflush (rl_outstream);
+ terminal_prepped = 1;
+
+ release_sigint ();
+#endif /* !__GO32__ */
+}
+
+/* Restore the terminal's normal settings and modes. */
+void
+rl_deprep_terminal ()
+{
+#if !defined (__GO32__)
+ int tty;
+
+ if (!terminal_prepped)
+ return;
+
+ /* Try to keep this function from being interrupted. */
+ block_sigint ();
+
+ tty = fileno (rl_instream);
+
+ if (_rl_enable_keypad)
+ _rl_control_keypad (0);
+
+ fflush (rl_outstream);
+
+ if (set_tty_settings (tty, &otio) < 0)
+ {
+ release_sigint ();
+ return;
+ }
+
+ terminal_prepped = 0;
+
+ release_sigint ();
+#endif /* !__GO32__ */
+}
+
+/* **************************************************************** */
+/* */
+/* Bogus Flow Control */
+/* */
+/* **************************************************************** */
+
+int
+rl_restart_output (count, key)
+ int count, key;
+{
+ int fildes = fileno (rl_outstream);
+#if defined (TIOCSTART)
+#if defined (apollo)
+ ioctl (&fildes, TIOCSTART, 0);
+#else
+ ioctl (fildes, TIOCSTART, 0);
+#endif /* apollo */
+
+#else /* !TIOCSTART */
+# if defined (TERMIOS_TTY_DRIVER)
+# if defined (__ksr1__)
+ if (ksrflow)
+ {
+ ksrflow = 0;
+ tcflow (fildes, TCOON);
+ }
+# else /* !ksr1 */
+ tcflow (fildes, TCOON); /* Simulate a ^Q. */
+# endif /* !ksr1 */
+# else /* !TERMIOS_TTY_DRIVER */
+# if defined (TCXONC)
+ ioctl (fildes, TCXONC, TCOON);
+# endif /* TCXONC */
+# endif /* !TERMIOS_TTY_DRIVER */
+#endif /* !TIOCSTART */
+
+ return 0;
+}
+
+int
+rl_stop_output (count, key)
+ int count, key;
+{
+ int fildes = fileno (rl_instream);
+
+#if defined (TIOCSTOP)
+# if defined (apollo)
+ ioctl (&fildes, TIOCSTOP, 0);
+# else
+ ioctl (fildes, TIOCSTOP, 0);
+# endif /* apollo */
+#else /* !TIOCSTOP */
+# if defined (TERMIOS_TTY_DRIVER)
+# if defined (__ksr1__)
+ ksrflow = 1;
+# endif /* ksr1 */
+ tcflow (fildes, TCOOFF);
+# else
+# if defined (TCXONC)
+ ioctl (fildes, TCXONC, TCOON);
+# endif /* TCXONC */
+# endif /* !TERMIOS_TTY_DRIVER */
+#endif /* !TIOCSTOP */
+
+ return 0;
+}
+
+/* **************************************************************** */
+/* */
+/* Default Key Bindings */
+/* */
+/* **************************************************************** */
+void
+rltty_set_default_bindings (kmap)
+ Keymap kmap;
+{
+ TIOTYPE ttybuff;
+ int tty = fileno (rl_instream);
+
+#if defined (NEW_TTY_DRIVER)
+
+#define SET_SPECIAL(sc, func) \
+ do \
+ { \
+ int ic; \
+ ic = sc; \
+ if (ic != -1 && kmap[ic].type == ISFUNC) \
+ kmap[ic].function = func; \
+ } \
+ while (0)
+
+ if (get_tty_settings (tty, &ttybuff) == 0)
+ {
+ if (ttybuff.flags & SGTTY_SET)
+ {
+ SET_SPECIAL (ttybuff.sgttyb.sg_erase, rl_rubout);
+ SET_SPECIAL (ttybuff.sgttyb.sg_kill, rl_unix_line_discard);
+ }
+
+# if defined (TIOCGLTC)
+ if (ttybuff.flags & LTCHARS_SET)
+ {
+ SET_SPECIAL (ttybuff.ltchars.t_werasc, rl_unix_word_rubout);
+ SET_SPECIAL (ttybuff.ltchars.t_lnextc, rl_quoted_insert);
+ }
+# endif /* TIOCGLTC */
+ }
+
+#else /* !NEW_TTY_DRIVER */
+
+#define SET_SPECIAL(sc, func) \
+ do \
+ { \
+ unsigned char uc; \
+ uc = ttybuff.c_cc[sc]; \
+ if (uc != (unsigned char)_POSIX_VDISABLE && kmap[uc].type == ISFUNC) \
+ kmap[uc].function = func; \
+ } \
+ while (0)
+
+ if (get_tty_settings (tty, &ttybuff) == 0)
+ {
+ SET_SPECIAL (VERASE, rl_rubout);
+ SET_SPECIAL (VKILL, rl_unix_line_discard);
+
+# if defined (VLNEXT) && defined (TERMIOS_TTY_DRIVER)
+ SET_SPECIAL (VLNEXT, rl_quoted_insert);
+# endif /* VLNEXT && TERMIOS_TTY_DRIVER */
+
+# if defined (VWERASE) && defined (TERMIOS_TTY_DRIVER)
+ SET_SPECIAL (VWERASE, rl_unix_word_rubout);
+# endif /* VWERASE && TERMIOS_TTY_DRIVER */
+ }
+#endif /* !NEW_TTY_DRIVER */
+}
diff --git a/readline/rltty.h b/readline/rltty.h
new file mode 100644
index 00000000000..fe783463f6a
--- /dev/null
+++ b/readline/rltty.h
@@ -0,0 +1,63 @@
+/* rltty.h - tty driver-related definitions used by some library files. */
+
+/* Copyright (C) 1995 Free Software Foundation, Inc.
+
+ This file contains the Readline Library (the Library), a set of
+ routines for providing Emacs style line input to programs that ask
+ for it.
+
+ The Library is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 1, or (at your option)
+ any later version.
+
+ The 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
+ General Public License for more details.
+
+ The GNU General Public License is often shipped with GNU software, and
+ is generally kept in a file called COPYING or LICENSE. If you do not
+ have a copy of the license, write to the Free Software Foundation,
+ 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#if !defined (_RLTTY_H_)
+#define _RLTTY_H
+
+/* Posix systems use termios and the Posix signal functions. */
+#if defined (TERMIOS_TTY_DRIVER)
+# include <termios.h>
+#endif /* TERMIOS_TTY_DRIVER */
+
+/* System V machines use termio. */
+#if defined (TERMIO_TTY_DRIVER)
+# include <termio.h>
+# if !defined (TCOON)
+# define TCOON 1
+# endif
+#endif /* TERMIO_TTY_DRIVER */
+
+/* Other (BSD) machines use sgtty. */
+#if defined (NEW_TTY_DRIVER)
+# include <sgtty.h>
+#endif
+
+#include "rlwinsize.h"
+
+/* Define _POSIX_VDISABLE if we are not using the `new' tty driver and
+ it is not already defined. It is used both to determine if a
+ special character is disabled and to disable certain special
+ characters. Posix systems should set to 0, USG systems to -1. */
+#if !defined (NEW_TTY_DRIVER) && !defined (_POSIX_VDISABLE)
+# if defined (_SVR4_VDISABLE)
+# define _POSIX_VDISABLE _SVR4_VDISABLE
+# else
+# if defined (_POSIX_VERSION)
+# define _POSIX_VDISABLE 0
+# else /* !_POSIX_VERSION */
+# define _POSIX_VDISABLE -1
+# endif /* !_POSIX_VERSION */
+# endif /* !_SVR4_DISABLE */
+#endif /* !NEW_TTY_DRIVER && !_POSIX_VDISABLE */
+
+#endif /* _RLTTY_H_ */
diff --git a/readline/rlwinsize.h b/readline/rlwinsize.h
new file mode 100644
index 00000000000..92b3de174bf
--- /dev/null
+++ b/readline/rlwinsize.h
@@ -0,0 +1,58 @@
+/* rlwinsize.h -- an attempt to isolate some of the system-specific defines
+ for `struct winsize' and TIOCGWINSZ. */
+
+/* Copyright (C) 1997 Free Software Foundation, Inc.
+
+ This file contains the Readline Library (the Library), a set of
+ routines for providing Emacs style line input to programs that ask
+ for it.
+
+ The Library is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 1, or (at your option)
+ any later version.
+
+ The 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
+ General Public License for more details.
+
+ The GNU General Public License is often shipped with GNU software, and
+ is generally kept in a file called COPYING or LICENSE. If you do not
+ have a copy of the license, write to the Free Software Foundation,
+ 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#if !defined (_RLWINSIZE_H_)
+#define _RLWINSIZE_H_
+
+#if defined (HAVE_CONFIG_H)
+# include "config.h"
+#endif
+
+/* Try to find the definitions of `struct winsize' and TIOGCWINSZ */
+
+#if defined (GWINSZ_IN_SYS_IOCTL) && !defined (TIOCGWINSZ)
+# include <sys/ioctl.h>
+#endif /* GWINSZ_IN_SYS_IOCTL && !TIOCGWINSZ */
+
+#if defined (STRUCT_WINSIZE_IN_TERMIOS) && !defined (STRUCT_WINSIZE_IN_SYS_IOCTL)
+# include <termios.h>
+#endif /* STRUCT_WINSIZE_IN_TERMIOS && !STRUCT_WINSIZE_IN_SYS_IOCTL */
+
+/* Not in either of the standard places, look around. */
+#if !defined (STRUCT_WINSIZE_IN_TERMIOS) && !defined (STRUCT_WINSIZE_IN_SYS_IOCTL)
+# if defined (HAVE_SYS_STREAM_H)
+# include <sys/stream.h>
+# endif /* HAVE_SYS_STREAM_H */
+# if defined (HAVE_SYS_PTEM_H) /* SVR4.2, at least, has it here */
+# include <sys/ptem.h>
+# define _IO_PTEM_H /* work around SVR4.2 1.1.4 bug */
+# endif /* HAVE_SYS_PTEM_H */
+# if defined (HAVE_SYS_PTE_H) /* ??? */
+# include <sys/pte.h>
+# endif /* HAVE_SYS_PTE_H */
+#endif /* !STRUCT_WINSIZE_IN_TERMIOS && !STRUCT_WINSIZE_IN_SYS_IOCTL */
+
+#endif /* _RL_WINSIZE_H */
+
+
diff --git a/readline/search.c b/readline/search.c
new file mode 100644
index 00000000000..6c76e1a1c96
--- /dev/null
+++ b/readline/search.c
@@ -0,0 +1,377 @@
+/* search.c - code for non-incremental searching in emacs and vi modes. */
+
+/* Copyright (C) 1992 Free Software Foundation, Inc.
+
+ This file is part of the Readline Library (the Library), a set of
+ routines for providing Emacs style line input to programs that ask
+ for it.
+
+ The Library is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 1, or (at your option)
+ any later version.
+
+ The 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
+ General Public License for more details.
+
+ The GNU General Public License is often shipped with GNU software, and
+ is generally kept in a file called COPYING or LICENSE. If you do not
+ have a copy of the license, write to the Free Software Foundation,
+ 675 Mass Ave, Cambridge, MA 02139, USA. */
+#define READLINE_LIBRARY
+
+#if defined (HAVE_CONFIG_H)
+# include <config.h>
+#endif
+
+#include <sys/types.h>
+#include <stdio.h>
+
+#if defined (HAVE_UNISTD_H)
+# include <unistd.h>
+#endif
+
+#if defined (HAVE_STDLIB_H)
+# include <stdlib.h>
+#else
+# include "ansi_stdlib.h"
+#endif
+
+#include "rldefs.h"
+#include "readline.h"
+#include "history.h"
+
+#ifdef abs
+# undef abs
+#endif
+#define abs(x) (((x) >= 0) ? (x) : -(x))
+
+extern char *xmalloc (), *xrealloc ();
+
+/* Variables imported from readline.c */
+extern int rl_point, rl_end, rl_line_buffer_len;
+extern int rl_editing_mode;
+extern char *rl_prompt;
+extern char *rl_line_buffer;
+extern HIST_ENTRY *saved_line_for_history;
+extern Function *rl_last_func;
+
+/* Functions imported from the rest of the library. */
+extern int _rl_free_history_entry ();
+extern char *_rl_make_prompt_for_search ();
+extern void rl_extend_line_buffer ();
+
+static char *noninc_search_string = (char *) NULL;
+static int noninc_history_pos;
+static char *prev_line_found = (char *) NULL;
+
+/* Search the history list for STRING starting at absolute history position
+ POS. If STRING begins with `^', the search must match STRING at the
+ beginning of a history line, otherwise a full substring match is performed
+ for STRING. DIR < 0 means to search backwards through the history list,
+ DIR >= 0 means to search forward. */
+static int
+noninc_search_from_pos (string, pos, dir)
+ char *string;
+ int pos, dir;
+{
+ int ret, old;
+
+ old = where_history ();
+ history_set_pos (pos);
+
+ if (*string == '^')
+ ret = history_search_prefix (string + 1, dir);
+ else
+ ret = history_search (string, dir);
+
+ if (ret != -1)
+ ret = where_history ();
+
+ history_set_pos (old);
+ return (ret);
+}
+
+/* Search for a line in the history containing STRING. If DIR is < 0, the
+ search is backwards through previous entries, else through subsequent
+ entries. */
+static void
+noninc_dosearch (string, dir)
+ char *string;
+ int dir;
+{
+ int oldpos, pos, line_len;
+ HIST_ENTRY *entry;
+
+ if (string == 0 || *string == '\0' || noninc_history_pos < 0)
+ {
+ ding ();
+ return;
+ }
+
+ pos = noninc_search_from_pos (string, noninc_history_pos + dir, dir);
+ if (pos == -1)
+ {
+ /* Search failed, current history position unchanged. */
+ maybe_unsave_line ();
+ rl_clear_message ();
+ rl_point = 0;
+ ding ();
+ return;
+ }
+
+ noninc_history_pos = pos;
+
+ oldpos = where_history ();
+ history_set_pos (noninc_history_pos);
+ entry = current_history ();
+#if defined (VI_MODE)
+ if (rl_editing_mode != vi_mode)
+#endif
+ history_set_pos (oldpos);
+
+ line_len = strlen (entry->line);
+ if (line_len >= rl_line_buffer_len)
+ rl_extend_line_buffer (line_len);
+ strcpy (rl_line_buffer, entry->line);
+
+ rl_undo_list = (UNDO_LIST *)entry->data;
+ rl_end = strlen (rl_line_buffer);
+ rl_point = 0;
+ rl_clear_message ();
+
+ if (saved_line_for_history)
+ _rl_free_history_entry (saved_line_for_history);
+ saved_line_for_history = (HIST_ENTRY *)NULL;
+}
+
+/* Search non-interactively through the history list. DIR < 0 means to
+ search backwards through the history of previous commands; otherwise
+ the search is for commands subsequent to the current position in the
+ history list. PCHAR is the character to use for prompting when reading
+ the search string; if not specified (0), it defaults to `:'. */
+static void
+noninc_search (dir, pchar)
+ int dir;
+ int pchar;
+{
+ int saved_point, c;
+ char *p;
+
+ maybe_save_line ();
+ saved_point = rl_point;
+
+ /* Use the line buffer to read the search string. */
+ rl_line_buffer[0] = 0;
+ rl_end = rl_point = 0;
+
+ p = _rl_make_prompt_for_search (pchar ? pchar : ':');
+ rl_message (p, 0, 0);
+ free (p);
+
+#define SEARCH_RETURN rl_restore_prompt (); return
+
+ /* Read the search string. */
+ while (c = rl_read_key ())
+ {
+ switch (c)
+ {
+ case CTRL('H'):
+ case RUBOUT:
+ if (rl_point == 0)
+ {
+ maybe_unsave_line ();
+ rl_clear_message ();
+ rl_point = saved_point;
+ SEARCH_RETURN;
+ }
+ rl_rubout (1, c);
+ break;
+
+ case CTRL('W'):
+ rl_unix_word_rubout (1, c);
+ break;
+
+ case CTRL('U'):
+ rl_unix_line_discard (1, c);
+ break;
+
+ case RETURN:
+ case NEWLINE:
+ goto dosearch;
+ /* NOTREACHED */
+ break;
+
+ case CTRL('C'):
+ case CTRL('G'):
+ maybe_unsave_line ();
+ rl_clear_message ();
+ rl_point = saved_point;
+ ding ();
+ SEARCH_RETURN;
+
+ default:
+ rl_insert (1, c);
+ break;
+ }
+ (*rl_redisplay_function) ();
+ }
+
+ dosearch:
+ /* If rl_point == 0, we want to re-use the previous search string and
+ start from the saved history position. If there's no previous search
+ string, punt. */
+ if (rl_point == 0)
+ {
+ if (!noninc_search_string)
+ {
+ ding ();
+ SEARCH_RETURN;
+ }
+ }
+ else
+ {
+ /* We want to start the search from the current history position. */
+ noninc_history_pos = where_history ();
+ if (noninc_search_string)
+ free (noninc_search_string);
+ noninc_search_string = savestring (rl_line_buffer);
+ }
+
+ rl_restore_prompt ();
+ noninc_dosearch (noninc_search_string, dir);
+}
+
+/* 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;
+{
+ noninc_search (1, (key == '?') ? '?' : 0);
+ return 0;
+}
+
+/* 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;
+{
+ noninc_search (-1, (key == '/') ? '/' : 0);
+ return 0;
+}
+
+/* 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;
+{
+ if (!noninc_search_string)
+ {
+ ding ();
+ return (-1);
+ }
+ noninc_dosearch (noninc_search_string, 1);
+ return 0;
+}
+
+/* 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;
+{
+ if (!noninc_search_string)
+ {
+ ding ();
+ return (-1);
+ }
+ noninc_dosearch (noninc_search_string, -1);
+ return 0;
+}
+
+static int
+rl_history_search_internal (count, direction)
+ int count, direction;
+{
+ HIST_ENTRY *temp, *old_temp;
+ int line_len;
+
+ maybe_save_line ();
+
+ temp = old_temp = (HIST_ENTRY *)NULL;
+ while (count)
+ {
+ temp = (direction < 0) ? previous_history () : next_history ();
+ if (temp == 0)
+ break;
+ /* On an empty prefix, make this the same as previous-history. */
+ if (rl_point == 0)
+ {
+ count--;
+ continue;
+ }
+ if (STREQN (rl_line_buffer, temp->line, rl_point))
+ {
+ /* Don't find multiple instances of the same line. */
+ if (prev_line_found && STREQ (prev_line_found, temp->line))
+ continue;
+ if (direction < 0)
+ old_temp = temp;
+ prev_line_found = temp->line;
+ count--;
+ }
+ }
+
+ if (temp == 0)
+ {
+ if (direction < 0 && old_temp)
+ temp = old_temp;
+ else
+ {
+ maybe_unsave_line ();
+ ding ();
+ return 1;
+ }
+ }
+
+ line_len = strlen (temp->line);
+ if (line_len >= rl_line_buffer_len)
+ rl_extend_line_buffer (line_len);
+ strcpy (rl_line_buffer, temp->line);
+ rl_undo_list = (UNDO_LIST *)temp->data;
+ rl_end = line_len;
+ return 0;
+}
+
+/* Search forward in the history for the string of characters
+ 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;
+{
+ if (count == 0)
+ return (0);
+ if (rl_last_func != rl_history_search_forward)
+ prev_line_found = (char *)NULL;
+ return (rl_history_search_internal (abs (count), (count > 0) ? 1 : -1));
+}
+
+/* Search backward through the history for the string of characters
+ 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;
+{
+ if (count == 0)
+ return (0);
+ if (rl_last_func != rl_history_search_backward)
+ prev_line_found = (char *)NULL;
+ return (rl_history_search_internal (abs (count), (count > 0) ? -1 : 1));
+}
diff --git a/readline/shell.c b/readline/shell.c
new file mode 100644
index 00000000000..091ec08f645
--- /dev/null
+++ b/readline/shell.c
@@ -0,0 +1,133 @@
+/* shell.c -- readline utility functions that are normally provided by
+ bash when readline is linked as part of the shell. */
+
+/* Copyright (C) 1997 Free Software Foundation, Inc.
+
+ This file is part of the GNU Readline Library, a library for
+ reading lines of text with interactive input and history editing.
+
+ The GNU Readline Library is free software; you can redistribute it
+ and/or modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 1, or
+ (at your option) any later version.
+
+ The GNU Readline 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 General Public License for more details.
+
+ The GNU General Public License is often shipped with GNU software, and
+ is generally kept in a file called COPYING or LICENSE. If you do not
+ have a copy of the license, write to the Free Software Foundation,
+ 675 Mass Ave, Cambridge, MA 02139, USA. */
+#define READLINE_LIBRARY
+
+#if defined (HAVE_CONFIG_H)
+# include <config.h>
+#endif
+
+#include <sys/types.h>
+
+#if defined (HAVE_UNISTD_H)
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+
+#if defined (HAVE_STDLIB_H)
+# include <stdlib.h>
+#else
+# include "ansi_stdlib.h"
+#endif /* HAVE_STDLIB_H */
+
+#if defined (HAVE_STRING_H)
+# include <string.h>
+#else
+# include <strings.h>
+#endif /* !HAVE_STRING_H */
+
+#include <pwd.h>
+
+#if !defined (HAVE_GETPW_DECLS)
+extern struct passwd *getpwuid ();
+#endif /* !HAVE_GETPW_DECLS */
+
+extern char *xmalloc ();
+
+/* All of these functions are resolved from bash if we are linking readline
+ as part of bash. */
+
+/* Does shell-like quoting using single quotes. */
+char *
+single_quote (string)
+ char *string;
+{
+ register int c;
+ char *result, *r, *s;
+
+ result = (char *)xmalloc (3 + (3 * strlen (string)));
+ r = result;
+ *r++ = '\'';
+
+ for (s = string; s && (c = *s); s++)
+ {
+ *r++ = c;
+
+ if (c == '\'')
+ {
+ *r++ = '\\'; /* insert escaped single quote */
+ *r++ = '\'';
+ *r++ = '\''; /* start new quoted string */
+ }
+ }
+
+ *r++ = '\'';
+ *r = '\0';
+
+ return (result);
+}
+
+/* Set the environment variables LINES and COLUMNS to lines and cols,
+ respectively. */
+void
+set_lines_and_columns (lines, cols)
+ int lines, cols;
+{
+ char *b;
+
+#if defined (HAVE_PUTENV)
+ b = xmalloc (24);
+ sprintf (b, "LINES=%d", lines);
+ putenv (b);
+ b = xmalloc (24);
+ sprintf (b, "COLUMNS=%d", cols);
+ putenv (b);
+#else /* !HAVE_PUTENV */
+# if defined (HAVE_SETENV)
+ b = xmalloc (8);
+ sprintf (b, "%d", lines);
+ setenv ("LINES", b, 1);
+ b = xmalloc (8);
+ sprintf (b, "%d", cols);
+ setenv ("COLUMNS", b, 1);
+# endif /* HAVE_SETENV */
+#endif /* !HAVE_PUTENV */
+}
+
+char *
+get_env_value (varname)
+ char *varname;
+{
+ return ((char *)getenv (varname));
+}
+
+char *
+get_home_dir ()
+{
+ char *home_dir;
+ struct passwd *entry;
+
+ home_dir = (char *)NULL;
+ entry = getpwuid (getuid ());
+ if (entry)
+ home_dir = entry->pw_dir;
+ return (home_dir);
+}
diff --git a/readline/signals.c b/readline/signals.c
new file mode 100644
index 00000000000..3a34432f143
--- /dev/null
+++ b/readline/signals.c
@@ -0,0 +1,394 @@
+/* signals.c -- signal handling support for readline. */
+
+/* Copyright (C) 1987, 1989, 1992 Free Software Foundation, Inc.
+
+ This file is part of the GNU Readline Library, a library for
+ reading lines of text with interactive input and history editing.
+
+ The GNU Readline Library is free software; you can redistribute it
+ and/or modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 1, or
+ (at your option) any later version.
+
+ The GNU Readline 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 General Public License for more details.
+
+ The GNU General Public License is often shipped with GNU software, and
+ is generally kept in a file called COPYING or LICENSE. If you do not
+ have a copy of the license, write to the Free Software Foundation,
+ 675 Mass Ave, Cambridge, MA 02139, USA. */
+#define READLINE_LIBRARY
+
+#if defined (HAVE_CONFIG_H)
+# include <config.h>
+#endif
+
+#include <stdio.h> /* Just for NULL. Yuck. */
+#include <sys/types.h>
+#include <signal.h>
+
+#if defined (HAVE_UNISTD_H)
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+
+/* System-specific feature definitions and include files. */
+#include "rldefs.h"
+
+#if defined (GWINSZ_IN_SYS_IOCTL)
+# include <sys/ioctl.h>
+#endif /* GWINSZ_IN_SYS_IOCTL */
+
+#if defined (__GO32__)
+# undef HANDLE_SIGNALS
+#endif /* __GO32__ */
+
+#if defined (HANDLE_SIGNALS)
+/* Some standard library routines. */
+#include "readline.h"
+#include "history.h"
+
+#if !defined (RETSIGTYPE)
+# if defined (VOID_SIGHANDLER)
+# define RETSIGTYPE void
+# else
+# define RETSIGTYPE int
+# endif /* !VOID_SIGHANDLER */
+#endif /* !RETSIGTYPE */
+
+#if defined (VOID_SIGHANDLER)
+# define SIGHANDLER_RETURN return
+#else
+# define SIGHANDLER_RETURN return (0)
+#endif
+
+/* This typedef is equivalant to the one for Function; it allows us
+ to say SigHandler *foo = signal (SIGKILL, SIG_IGN); */
+typedef RETSIGTYPE SigHandler ();
+
+extern int readline_echoing_p;
+extern int rl_pending_input;
+extern int _rl_meta_flag;
+
+extern void free_undo_list ();
+extern void _rl_get_screen_size ();
+extern void _rl_redisplay_after_sigwinch ();
+extern void _rl_clean_up_for_exit ();
+extern void _rl_kill_kbd_macro ();
+extern void _rl_init_argument ();
+extern void rl_deprep_terminal (), rl_prep_terminal ();
+
+static SigHandler *rl_set_sighandler ();
+
+/* Exported variables for use by applications. */
+
+/* If non-zero, readline will install its own signal handlers for
+ SIGINT, SIGTERM, SIGQUIT, SIGALRM, SIGTSTP, SIGTTIN, and SIGTTOU. */
+int rl_catch_signals = 1;
+
+/* If non-zero, readline will install a signal handler for SIGWINCH. */
+#ifdef SIGWINCH
+int rl_catch_sigwinch = 1;
+#endif
+
+static int signals_set_flag;
+static int sigwinch_set_flag;
+
+/* **************************************************************** */
+/* */
+/* Signal Handling */
+/* */
+/* **************************************************************** */
+
+#if defined (HAVE_POSIX_SIGNALS)
+typedef struct sigaction sighandler_cxt;
+# define rl_sigaction(s, nh, oh) sigaction(s, nh, oh)
+#else
+typedef struct { SigHandler *sa_handler; int sa_mask, sa_flags; } sighandler_cxt;
+# define sigemptyset(m)
+#endif /* !HAVE_POSIX_SIGNALS */
+
+static sighandler_cxt old_int, old_term, old_alrm, old_quit;
+#if defined (SIGTSTP)
+static sighandler_cxt old_tstp, old_ttou, old_ttin;
+#endif
+#if defined (SIGWINCH)
+static sighandler_cxt old_winch;
+#endif
+
+/* Readline signal handler functions. */
+
+static RETSIGTYPE
+rl_signal_handler (sig)
+ int sig;
+{
+#if defined (HAVE_POSIX_SIGNALS)
+ sigset_t set;
+#else /* !HAVE_POSIX_SIGNALS */
+# if defined (HAVE_BSD_SIGNALS)
+ long omask;
+# else /* !HAVE_BSD_SIGNALS */
+ sighandler_cxt dummy_cxt; /* needed for rl_set_sighandler call */
+# endif /* !HAVE_BSD_SIGNALS */
+#endif /* !HAVE_POSIX_SIGNALS */
+
+#if !defined (HAVE_BSD_SIGNALS) && !defined (HAVE_POSIX_SIGNALS)
+ /* Since the signal will not be blocked while we are in the signal
+ handler, ignore it until rl_clear_signals resets the catcher. */
+ if (sig == SIGINT || sig == SIGALRM)
+ rl_set_sighandler (sig, SIG_IGN, &dummy_cxt);
+#endif /* !HAVE_BSD_SIGNALS && !HAVE_POSIX_SIGNALS */
+
+ switch (sig)
+ {
+ case SIGINT:
+ rl_free_line_state ();
+ /* FALLTHROUGH */
+
+#if defined (SIGTSTP)
+ case SIGTSTP:
+ case SIGTTOU:
+ case SIGTTIN:
+#endif /* SIGTSTP */
+ case SIGALRM:
+ case SIGTERM:
+ case SIGQUIT:
+ rl_cleanup_after_signal ();
+
+#if defined (HAVE_POSIX_SIGNALS)
+ sigprocmask (SIG_BLOCK, (sigset_t *)NULL, &set);
+ sigdelset (&set, sig);
+#else /* !HAVE_POSIX_SIGNALS */
+# if defined (HAVE_BSD_SIGNALS)
+ omask = sigblock (0);
+# endif /* HAVE_BSD_SIGNALS */
+#endif /* !HAVE_POSIX_SIGNALS */
+
+ kill (getpid (), sig);
+
+ /* Let the signal that we just sent through. */
+#if defined (HAVE_POSIX_SIGNALS)
+ sigprocmask (SIG_SETMASK, &set, (sigset_t *)NULL);
+#else /* !HAVE_POSIX_SIGNALS */
+# if defined (HAVE_BSD_SIGNALS)
+ sigsetmask (omask & ~(sigmask (sig)));
+# endif /* HAVE_BSD_SIGNALS */
+#endif /* !HAVE_POSIX_SIGNALS */
+
+ rl_reset_after_signal ();
+ }
+
+ SIGHANDLER_RETURN;
+}
+
+#if defined (SIGWINCH)
+static RETSIGTYPE
+rl_sigwinch_handler (sig)
+ int sig;
+{
+ SigHandler *oh;
+
+#if defined (MUST_REINSTALL_SIGHANDLERS)
+ sighandler_cxt dummy_winch;
+
+ /* We don't want to change old_winch -- it holds the state of SIGWINCH
+ disposition set by the calling application. We need this state
+ because we call the application's SIGWINCH handler after updating
+ our own idea of the screen size. */
+ rl_set_sighandler (SIGWINCH, rl_sigwinch_handler, &dummy_winch);
+#endif
+
+ rl_resize_terminal ();
+
+ /* If another sigwinch handler has been installed, call it. */
+ oh = (SigHandler *)old_winch.sa_handler;
+ if (oh && oh != (SigHandler *)SIG_IGN && oh != (SigHandler *)SIG_DFL)
+ (*oh) (sig);
+
+ SIGHANDLER_RETURN;
+}
+#endif /* SIGWINCH */
+
+/* Functions to manage signal handling. */
+
+#if !defined (HAVE_POSIX_SIGNALS)
+static int
+rl_sigaction (sig, nh, oh)
+ int sig;
+ sighandler_cxt *nh, *oh;
+{
+ oh->sa_handler = signal (sig, nh->sa_handler);
+ return 0;
+}
+#endif /* !HAVE_POSIX_SIGNALS */
+
+/* Set up a readline-specific signal handler, saving the old signal
+ information in OHANDLER. Return the old signal handler, like
+ signal(). */
+static SigHandler *
+rl_set_sighandler (sig, handler, ohandler)
+ int sig;
+ SigHandler *handler;
+ sighandler_cxt *ohandler;
+{
+#if defined (HAVE_POSIX_SIGNALS)
+ struct sigaction act;
+
+ act.sa_handler = handler;
+ act.sa_flags = 0;
+ sigemptyset (&act.sa_mask);
+ sigemptyset (&ohandler->sa_mask);
+ sigaction (sig, &act, ohandler);
+#else
+ ohandler->sa_handler = (SigHandler *)signal (sig, handler);
+#endif /* !HAVE_POSIX_SIGNALS */
+ return (ohandler->sa_handler);
+}
+
+static void
+rl_maybe_set_sighandler (sig, handler, ohandler)
+ int sig;
+ SigHandler *handler;
+ sighandler_cxt *ohandler;
+{
+ sighandler_cxt dummy;
+ SigHandler *oh;
+
+ sigemptyset (&dummy.sa_mask);
+ oh = rl_set_sighandler (sig, handler, ohandler);
+ if (oh == (SigHandler *)SIG_IGN)
+ rl_sigaction (sig, ohandler, &dummy);
+}
+
+int
+rl_set_signals ()
+{
+ sighandler_cxt dummy;
+ SigHandler *oh;
+
+ if (rl_catch_signals && signals_set_flag == 0)
+ {
+ rl_maybe_set_sighandler (SIGINT, rl_signal_handler, &old_int);
+ rl_maybe_set_sighandler (SIGTERM, rl_signal_handler, &old_term);
+ rl_maybe_set_sighandler (SIGQUIT, rl_signal_handler, &old_quit);
+
+ oh = rl_set_sighandler (SIGALRM, rl_signal_handler, &old_alrm);
+ if (oh == (SigHandler *)SIG_IGN)
+ rl_sigaction (SIGALRM, &old_alrm, &dummy);
+#if defined (HAVE_POSIX_SIGNALS) && defined (SA_RESTART)
+ /* If the application using readline has already installed a signal
+ handler with SA_RESTART, SIGALRM will cause reads to be restarted
+ automatically, so readline should just get out of the way. Since
+ we tested for SIG_IGN above, we can just test for SIG_DFL here. */
+ if (oh != (SigHandler *)SIG_DFL && (old_alrm.sa_flags & SA_RESTART))
+ rl_sigaction (SIGALRM, &old_alrm, &dummy);
+#endif /* HAVE_POSIX_SIGNALS */
+
+#if defined (SIGTSTP)
+ rl_maybe_set_sighandler (SIGTSTP, rl_signal_handler, &old_tstp);
+#endif /* SIGTSTP */
+
+#if defined (SIGTTOU)
+ rl_maybe_set_sighandler (SIGTTOU, rl_signal_handler, &old_ttou);
+#endif /* SIGTTOU */
+
+#if defined (SIGTTIN)
+ rl_maybe_set_sighandler (SIGTTIN, rl_signal_handler, &old_ttin);
+#endif /* SIGTTIN */
+
+ signals_set_flag = 1;
+ }
+
+#if defined (SIGWINCH)
+ if (rl_catch_sigwinch && sigwinch_set_flag == 0)
+ {
+ rl_maybe_set_sighandler (SIGWINCH, rl_sigwinch_handler, &old_winch);
+ sigwinch_set_flag = 1;
+ }
+#endif /* SIGWINCH */
+
+ return 0;
+}
+
+int
+rl_clear_signals ()
+{
+ sighandler_cxt dummy;
+
+ if (rl_catch_signals && signals_set_flag == 1)
+ {
+ sigemptyset (&dummy.sa_mask);
+
+ rl_sigaction (SIGINT, &old_int, &dummy);
+ rl_sigaction (SIGTERM, &old_term, &dummy);
+ rl_sigaction (SIGQUIT, &old_quit, &dummy);
+ rl_sigaction (SIGALRM, &old_alrm, &dummy);
+
+#if defined (SIGTSTP)
+ rl_sigaction (SIGTSTP, &old_tstp, &dummy);
+#endif /* SIGTSTP */
+
+#if defined (SIGTTOU)
+ rl_sigaction (SIGTTOU, &old_ttou, &dummy);
+#endif /* SIGTTOU */
+
+#if defined (SIGTTIN)
+ rl_sigaction (SIGTTIN, &old_ttin, &dummy);
+#endif /* SIGTTIN */
+
+ signals_set_flag = 0;
+ }
+
+#if defined (SIGWINCH)
+ if (rl_catch_sigwinch && sigwinch_set_flag == 1)
+ {
+ sigemptyset (&dummy.sa_mask);
+ rl_sigaction (SIGWINCH, &old_winch, &dummy);
+ sigwinch_set_flag = 0;
+ }
+#endif
+
+ return 0;
+}
+
+/* Clean up the terminal and readline state after catching a signal, before
+ resending it to the calling application. */
+void
+rl_cleanup_after_signal ()
+{
+ _rl_clean_up_for_exit ();
+ (*rl_deprep_term_function) ();
+ rl_clear_signals ();
+ rl_pending_input = 0;
+}
+
+/* Reset the terminal and readline state after a signal handler returns. */
+void
+rl_reset_after_signal ()
+{
+ (*rl_prep_term_function) (_rl_meta_flag);
+ rl_set_signals ();
+}
+
+/* Free up the readline variable line state for the current line (undo list,
+ any partial history entry, any keyboard macros in progress, and any
+ numeric arguments in process) after catching a signal, before calling
+ rl_cleanup_after_signal(). */
+void
+rl_free_line_state ()
+{
+ register HIST_ENTRY *entry;
+
+ free_undo_list ();
+
+ entry = current_history ();
+ if (entry)
+ entry->data = (char *)NULL;
+
+ _rl_kill_kbd_macro ();
+ rl_clear_message ();
+ _rl_init_argument ();
+}
+
+#endif /* HANDLE_SIGNALS */
diff --git a/readline/tcap.h b/readline/tcap.h
new file mode 100644
index 00000000000..acb2d76ab48
--- /dev/null
+++ b/readline/tcap.h
@@ -0,0 +1,60 @@
+/* tcap.h -- termcap library functions and variables. */
+
+/* Copyright (C) 1996 Free Software Foundation, Inc.
+
+ This file contains the Readline Library (the Library), a set of
+ routines for providing Emacs style line input to programs that ask
+ for it.
+
+ The Library is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 1, or (at your option)
+ any later version.
+
+ The 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
+ General Public License for more details.
+
+ The GNU General Public License is often shipped with GNU software, and
+ is generally kept in a file called COPYING or LICENSE. If you do not
+ have a copy of the license, write to the Free Software Foundation,
+ 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#if !defined (_RLTCAP_H_)
+#define _RLTCAP_H_
+
+#if defined (HAVE_CONFIG_H)
+# include "config.h"
+#endif
+
+#if defined (HAVE_TERMCAP_H)
+# if defined (__linux__) && !defined (SPEED_T_IN_SYS_TYPES)
+# include "rltty.h"
+# endif
+# include <termcap.h>
+#else
+
+/* On Solaris2, sys/types.h #includes sys/reg.h, which #defines PC.
+ Unfortunately, PC is a global variable used by the termcap library. */
+#ifdef PC
+# undef PC
+#endif
+
+extern char PC;
+extern char *UP, *BC;
+
+extern short ospeed;
+
+extern int tgetent ();
+extern int tgetflag ();
+extern int tgetnum ();
+extern char *tgetstr ();
+
+extern int tputs ();
+
+extern char *tgoto ();
+
+#endif /* HAVE_TERMCAP_H */
+
+#endif /* !_RLTCAP_H_ */
diff --git a/readline/terminal.c b/readline/terminal.c
new file mode 100644
index 00000000000..c22ec5170bd
--- /dev/null
+++ b/readline/terminal.c
@@ -0,0 +1,555 @@
+/* terminal.c -- controlling the terminal with termcap. */
+
+/* Copyright (C) 1996 Free Software Foundation, Inc.
+
+ This file is part of the GNU Readline Library, a library for
+ reading lines of text with interactive input and history editing.
+
+ The GNU Readline Library is free software; you can redistribute it
+ and/or modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 1, or
+ (at your option) any later version.
+
+ The GNU Readline 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 General Public License for more details.
+
+ The GNU General Public License is often shipped with GNU software, and
+ is generally kept in a file called COPYING or LICENSE. If you do not
+ have a copy of the license, write to the Free Software Foundation,
+ 675 Mass Ave, Cambridge, MA 02139, USA. */
+#define READLINE_LIBRARY
+
+#if defined (HAVE_CONFIG_H)
+# include <config.h>
+#endif
+
+#include <sys/types.h>
+#include "posixstat.h"
+#include <fcntl.h>
+#if defined (HAVE_SYS_FILE_H)
+# include <sys/file.h>
+#endif /* HAVE_SYS_FILE_H */
+
+#if defined (HAVE_UNISTD_H)
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+
+#if defined (HAVE_STDLIB_H)
+# include <stdlib.h>
+#else
+# include "ansi_stdlib.h"
+#endif /* HAVE_STDLIB_H */
+
+#if defined (HAVE_LOCALE_H)
+# include <locale.h>
+#endif
+
+#include <signal.h>
+#include <stdio.h>
+#include <setjmp.h>
+
+/* System-specific feature definitions and include files. */
+#include "rldefs.h"
+
+#if defined (GWINSZ_IN_SYS_IOCTL) && !defined (TIOCGWINSZ)
+# include <sys/ioctl.h>
+#endif /* GWINSZ_IN_SYS_IOCTL && !TIOCGWINSZ */
+
+#include "rltty.h"
+#include "tcap.h"
+
+/* Some standard library routines. */
+#include "readline.h"
+#include "history.h"
+
+/* Variables and functions imported from readline.c */
+extern FILE *_rl_in_stream, *_rl_out_stream;
+extern int readline_echoing_p;
+extern int _rl_bell_preference;
+extern Keymap _rl_keymap;
+
+/* Functions imported from bind.c */
+extern void _rl_bind_if_unbound ();
+
+/* Functions imported from shell.c */
+extern void set_lines_and_columns ();
+extern char *get_env_value ();
+
+/* **************************************************************** */
+/* */
+/* Terminal and Termcap */
+/* */
+/* **************************************************************** */
+
+static char *term_buffer = (char *)NULL;
+static char *term_string_buffer = (char *)NULL;
+
+static int tcap_initialized;
+
+/* Non-zero means this terminal can't really do anything. */
+static int dumb_term;
+
+#if !defined (__linux__)
+# if defined (__EMX__) || defined (NEED_EXTERN_PC)
+extern
+# endif /* __EMX__ || NEED_EXTERN_PC */
+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;
+
+/* Non-zero if we determine that the terminal can do character insertion. */
+int terminal_can_insert = 0;
+
+/* How to insert characters. */
+char *term_im, *term_ei, *term_ic, *term_ip, *term_IC;
+
+/* How to delete characters. */
+char *term_dc, *term_DC;
+
+#if defined (HACK_TERMCAP_MOTION)
+char *term_forward_char;
+#endif /* HACK_TERMCAP_MOTION */
+
+/* How to go up a line. */
+char *term_up;
+
+/* A visible bell, if the terminal can be made to flash the screen. */
+static char *visible_bell;
+
+/* Non-zero means the terminal can auto-wrap lines. */
+int _rl_term_autowrap;
+
+/* Non-zero means that this terminal has a meta key. */
+static int term_has_meta;
+
+/* The sequences to write to turn on and off the meta key, if this
+ terminal has one. */
+static char *term_mm, *term_mo;
+
+/* The key sequences output by the arrow keys, if this terminal has any. */
+static char *term_ku, *term_kd, *term_kr, *term_kl;
+
+/* How to initialize and reset the arrow keys, if this terminal has any. */
+static char *term_ks, *term_ke;
+
+/* The key sequences sent by the Home and End keys, if any. */
+static char *term_kh, *term_kH;
+
+/* Variables that hold the screen dimensions, used by the display code. */
+int screenwidth, screenheight, screenchars;
+
+/* Non-zero means the user wants to enable the keypad. */
+int _rl_enable_keypad;
+
+/* Non-zero means the user wants to enable a meta key. */
+int _rl_enable_meta = 1;
+
+/* Get readline's idea of the screen size. TTY is a file descriptor open
+ to the terminal. If IGNORE_ENV is true, we do not pay attention to the
+ values of $LINES and $COLUMNS. The tests for TERM_STRING_BUFFER being
+ non-null serve to check whether or not we have initialized termcap. */
+void
+_rl_get_screen_size (tty, ignore_env)
+ int tty, ignore_env;
+{
+ char *ss;
+#if defined (TIOCGWINSZ)
+ struct winsize window_size;
+#endif /* TIOCGWINSZ */
+#if defined (__EMX__)
+ int sz[2];
+#endif
+
+#if defined (TIOCGWINSZ)
+ if (ioctl (tty, TIOCGWINSZ, &window_size) == 0)
+ {
+ screenwidth = (int) window_size.ws_col;
+ screenheight = (int) window_size.ws_row;
+ }
+#endif /* TIOCGWINSZ */
+
+#if defined (__EMX__)
+ _scrsize (sz);
+ screenwidth = sz[0];
+ screenheight = sz[1];
+#endif
+
+ /* Environment variable COLUMNS overrides setting of "co" if IGNORE_ENV
+ is unset. */
+ if (screenwidth <= 0)
+ {
+ if (ignore_env == 0 && (ss = get_env_value ("COLUMNS")))
+ screenwidth = atoi (ss);
+
+ if (screenwidth <= 0 && term_string_buffer)
+ screenwidth = tgetnum ("co");
+ }
+
+ /* Environment variable LINES overrides setting of "li" if IGNORE_ENV
+ is unset. */
+ if (screenheight <= 0)
+ {
+ if (ignore_env == 0 && (ss = get_env_value ("LINES")))
+ screenheight = atoi (ss);
+
+ if (screenheight <= 0 && term_string_buffer)
+ screenheight = tgetnum ("li");
+ }
+
+ /* If all else fails, default to 80x24 terminal. */
+ if (screenwidth <= 1)
+ screenwidth = 80;
+
+ if (screenheight <= 0)
+ screenheight = 24;
+
+ /* If we're being compiled as part of bash, set the environment
+ variables $LINES and $COLUMNS to new values. Otherwise, just
+ do a pair of putenv () or setenv () calls. */
+ set_lines_and_columns (screenheight, screenwidth);
+
+ if (!_rl_term_autowrap)
+ screenwidth--;
+
+ screenchars = screenwidth * screenheight;
+}
+
+void
+_rl_set_screen_size (rows, cols)
+ int rows, cols;
+{
+ screenheight = rows;
+ screenwidth = cols;
+
+ if (_rl_term_autowrap == 0)
+ screenwidth--;
+
+ screenchars = screenwidth * screenheight;
+}
+
+void
+rl_resize_terminal ()
+{
+ if (readline_echoing_p)
+ {
+ _rl_get_screen_size (fileno (rl_instream), 1);
+ _rl_redisplay_after_sigwinch ();
+ }
+}
+
+struct _tc_string {
+ char *tc_var;
+ char **tc_value;
+};
+
+/* This should be kept sorted, just in case we decide to change the
+ search algorithm to something smarter. */
+static struct _tc_string tc_strings[] =
+{
+ "DC", &term_DC,
+ "IC", &term_IC,
+ "ce", &term_clreol,
+ "cl", &term_clrpag,
+ "cr", &term_cr,
+ "dc", &term_dc,
+ "ei", &term_ei,
+ "ic", &term_ic,
+ "im", &term_im,
+ "kd", &term_kd,
+ "kh", &term_kh, /* home */
+ "kH", &term_kH, /* end */
+ "kl", &term_kl,
+ "kr", &term_kr,
+ "ku", &term_ku,
+ "ks", &term_ks,
+ "ke", &term_ke,
+ "le", &term_backspace,
+ "mm", &term_mm,
+ "mo", &term_mo,
+#if defined (HACK_TERMCAP_MOTION)
+ "nd", &term_forward_char,
+#endif
+ "pc", &term_pc,
+ "up", &term_up,
+ "vb", &visible_bell,
+};
+
+#define NUM_TC_STRINGS (sizeof (tc_strings) / sizeof (struct _tc_string))
+
+/* Read the desired terminal capability strings into BP. The capabilities
+ are described in the TC_STRINGS table. */
+static void
+get_term_capabilities (bp)
+ char **bp;
+{
+ register int i;
+
+ for (i = 0; i < NUM_TC_STRINGS; i++)
+ *(tc_strings[i].tc_value) = tgetstr (tc_strings[i].tc_var, bp);
+ tcap_initialized = 1;
+}
+
+int
+_rl_init_terminal_io (terminal_name)
+ char *terminal_name;
+{
+#if defined (__GO32__)
+ screenwidth = ScreenCols ();
+ screenheight = ScreenRows ();
+ screenchars = screenwidth * screenheight;
+ term_cr = "\r";
+ term_im = term_ei = term_ic = term_IC = (char *)NULL;
+ term_up = term_dc = term_DC = visible_bell = (char *)NULL;
+
+ /* Does the __GO32__ have a meta key? I don't know. */
+ term_has_meta = 0;
+ term_mm = term_mo = (char *)NULL;
+
+ /* It probably has arrow keys, but I don't know what they are. */
+ term_ku = term_kd = term_kr = term_kl = (char *)NULL;
+
+#if defined (HACK_TERMCAP_MOTION)
+ term_forward_char = (char *)NULL;
+#endif /* HACK_TERMCAP_MOTION */
+ terminal_can_insert = _rl_term_autowrap = 0;
+ return;
+#else /* !__GO32__ */
+
+ char *term, *buffer;
+ int tty;
+ Keymap xkeymap;
+
+ term = terminal_name ? terminal_name : get_env_value ("TERM");
+
+ if (term_string_buffer == 0)
+ term_string_buffer = xmalloc (2032);
+
+ if (term_buffer == 0)
+ term_buffer = xmalloc (4080);
+
+ buffer = term_string_buffer;
+
+ term_clrpag = term_cr = term_clreol = (char *)NULL;
+
+ if (term == 0)
+ term = "dumb";
+
+ if (tgetent (term_buffer, term) <= 0)
+ {
+ dumb_term = 1;
+ screenwidth = 79;
+ screenheight = 24;
+ screenchars = 79 * 24;
+ term_cr = "\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;
+#if defined (HACK_TERMCAP_MOTION)
+ term_forward_char = (char *)NULL;
+#endif
+ terminal_can_insert = 0;
+ return 0;
+ }
+
+ get_term_capabilities (&buffer);
+
+ /* Set up the variables that the termcap library expects the application
+ to provide. */
+ PC = term_pc ? *term_pc : 0;
+ BC = term_backspace;
+ UP = term_up;
+
+ if (!term_cr)
+ term_cr = "\r";
+
+ tty = rl_instream ? fileno (rl_instream) : 0;
+
+ screenwidth = screenheight = 0;
+
+ _rl_term_autowrap = tgetflag ("am") && tgetflag ("xn");
+
+ _rl_get_screen_size (tty, 0);
+
+ /* "An application program can assume that the terminal can do
+ character insertion if *any one of* the capabilities `IC',
+ `im', `ic' or `ip' is provided." But we can't do anything if
+ only `ip' is provided, so... */
+ terminal_can_insert = (term_IC || term_im || term_ic);
+
+ /* Check to see if this terminal has a meta key and clear the capability
+ variables if there is none. */
+ term_has_meta = (tgetflag ("km") || tgetflag ("MT"));
+ if (!term_has_meta)
+ term_mm = term_mo = (char *)NULL;
+
+ /* Attempt to find and bind the arrow keys. Do not override already
+ bound keys in an overzealous attempt, however. */
+ xkeymap = _rl_keymap;
+
+ _rl_keymap = emacs_standard_keymap;
+ _rl_bind_if_unbound (term_ku, rl_get_previous_history);
+ _rl_bind_if_unbound (term_kd, rl_get_next_history);
+ _rl_bind_if_unbound (term_kr, rl_forward);
+ _rl_bind_if_unbound (term_kl, rl_backward);
+
+ _rl_bind_if_unbound (term_kh, rl_beg_of_line); /* Home */
+ _rl_bind_if_unbound (term_kH, rl_end_of_line); /* End */
+
+#if defined (VI_MODE)
+ _rl_keymap = vi_movement_keymap;
+ _rl_bind_if_unbound (term_ku, rl_get_previous_history);
+ _rl_bind_if_unbound (term_kd, rl_get_next_history);
+ _rl_bind_if_unbound (term_kr, rl_forward);
+ _rl_bind_if_unbound (term_kl, rl_backward);
+
+ _rl_bind_if_unbound (term_kh, rl_beg_of_line); /* Home */
+ _rl_bind_if_unbound (term_kH, rl_end_of_line); /* End */
+#endif /* VI_MODE */
+
+ _rl_keymap = xkeymap;
+
+#endif /* !__GO32__ */
+ return 0;
+}
+
+char *
+rl_get_termcap (cap)
+ char *cap;
+{
+ register int i;
+
+ if (tcap_initialized == 0)
+ return ((char *)NULL);
+ for (i = 0; i < 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);
+ }
+ return ((char *)NULL);
+}
+
+/* Re-initialize the terminal considering that the TERM/TERMCAP variable
+ has changed. */
+int
+rl_reset_terminal (terminal_name)
+ char *terminal_name;
+{
+ _rl_init_terminal_io (terminal_name);
+ return 0;
+}
+
+/* A function for the use of tputs () */
+#ifdef _MINIX
+void
+_rl_output_character_function (c)
+ int c;
+{
+ putc (c, _rl_out_stream);
+}
+#else /* !_MINIX */
+int
+_rl_output_character_function (c)
+ int c;
+{
+ return putc (c, _rl_out_stream);
+}
+#endif /* !_MINIX */
+/* Write COUNT characters from STRING to the output stream. */
+void
+_rl_output_some_chars (string, count)
+ char *string;
+ int count;
+{
+ fwrite (string, 1, count, _rl_out_stream);
+}
+
+/* Move the cursor back. */
+int
+_rl_backspace (count)
+ int count;
+{
+ register int i;
+
+#if !defined (__GO32__)
+ if (term_backspace)
+ for (i = 0; i < count; i++)
+ tputs (term_backspace, 1, _rl_output_character_function);
+ else
+#endif /* !__GO32__ */
+ for (i = 0; i < count; i++)
+ putc ('\b', _rl_out_stream);
+ return 0;
+}
+
+/* Move to the start of the next line. */
+int
+crlf ()
+{
+#if defined (NEW_TTY_DRIVER)
+ if (term_cr)
+ tputs (term_cr, 1, _rl_output_character_function);
+#endif /* NEW_TTY_DRIVER */
+ putc ('\n', _rl_out_stream);
+ return 0;
+}
+
+/* Ring the terminal bell. */
+int
+ding ()
+{
+ if (readline_echoing_p)
+ {
+#if !defined (__GO32__)
+ switch (_rl_bell_preference)
+ {
+ case NO_BELL:
+ default:
+ break;
+ case VISIBLE_BELL:
+ if (visible_bell)
+ {
+ tputs (visible_bell, 1, _rl_output_character_function);
+ break;
+ }
+ /* FALLTHROUGH */
+ case AUDIBLE_BELL:
+ fprintf (stderr, "\007");
+ fflush (stderr);
+ break;
+ }
+#else /* __GO32__ */
+ fprintf (stderr, "\007");
+ fflush (stderr);
+#endif /* __GO32__ */
+ return (0);
+ }
+ return (-1);
+}
+
+/* **************************************************************** */
+/* */
+/* Controlling the Meta Key and Keypad */
+/* */
+/* **************************************************************** */
+
+void
+_rl_enable_meta_key ()
+{
+ if (term_has_meta && term_mm)
+ tputs (term_mm, 1, _rl_output_character_function);
+}
+
+void
+_rl_control_keypad (on)
+ int on;
+{
+ if (on && term_ks)
+ tputs (term_ks, 1, _rl_output_character_function);
+ else if (!on && term_ke)
+ tputs (term_ke, 1, _rl_output_character_function);
+}
diff --git a/readline/tilde.c b/readline/tilde.c
new file mode 100644
index 00000000000..d1853bd63d6
--- /dev/null
+++ b/readline/tilde.c
@@ -0,0 +1,438 @@
+/* tilde.c -- Tilde expansion code (~/foo := $HOME/foo). */
+
+/* Copyright (C) 1988,1989 Free Software Foundation, Inc.
+
+ This file is part of GNU Readline, a library for reading lines
+ of text with interactive input and history editing.
+
+ Readline is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 1, or (at your option) any
+ later version.
+
+ Readline is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Readline; see the file COPYING. If not, write to the Free
+ Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#if defined (HAVE_CONFIG_H)
+# include <config.h>
+#endif
+
+#if defined (HAVE_UNISTD_H)
+# ifdef _MINIX
+# include <sys/types.h>
+# endif
+# include <unistd.h>
+#endif
+
+#if defined (HAVE_STRING_H)
+# include <string.h>
+#else /* !HAVE_STRING_H */
+# include <strings.h>
+#endif /* !HAVE_STRING_H */
+
+#if defined (HAVE_STDLIB_H)
+# include <stdlib.h>
+#else
+# include "ansi_stdlib.h"
+#endif /* HAVE_STDLIB_H */
+
+#include <sys/types.h>
+#include <pwd.h>
+
+#include "tilde.h"
+
+#if !defined (HAVE_GETPW_DECLS)
+extern struct passwd *getpwuid (), *getpwnam ();
+#endif /* !HAVE_GETPW_DECLS */
+
+#if !defined (savestring)
+extern char *xmalloc ();
+# ifndef strcpy
+extern char *strcpy ();
+# endif
+#define savestring(x) strcpy (xmalloc (1 + strlen (x)), (x))
+#endif /* !savestring */
+
+#if !defined (NULL)
+# if defined (__STDC__)
+# define NULL ((void *) 0)
+# else
+# define NULL 0x0
+# endif /* !__STDC__ */
+#endif /* !NULL */
+
+#if defined (TEST) || defined (STATIC_MALLOC)
+static char *xmalloc (), *xrealloc ();
+#else
+extern char *xmalloc (), *xrealloc ();
+#endif /* TEST || STATIC_MALLOC */
+
+/* If being compiled as part of bash, these will be satisfied from
+ variables.o. If being compiled as part of readline, they will
+ be satisfied from shell.o. */
+extern char *get_home_dir ();
+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[] =
+ { " ~", "\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[] =
+ { " ", "\n", (char *)NULL };
+
+/* If non-null, this contains the address of a function that the application
+ wants called before trying the standard tilde expansions. The function
+ is called with the text sans tilde, and returns a malloc()'ed string
+ which is the expansion, or a NULL pointer if the expansion fails. */
+CPFunction *tilde_expansion_preexpansion_hook = (CPFunction *)NULL;
+
+/* If non-null, this contains the address of a function to call if the
+ standard meaning for expanding a tilde fails. The function is called
+ with the text (sans tilde, as in "foo"), and returns a malloc()'ed string
+ which is the expansion, or a NULL pointer if there is no expansion. */
+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;
+
+/* 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;
+
+/* 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
+ which identified this tilde starter in LEN, excluding the tilde itself. */
+static int
+tilde_find_prefix (string, len)
+ char *string;
+ int *len;
+{
+ register int i, j, string_len;
+ register char **prefixes = tilde_additional_prefixes;
+
+ string_len = strlen (string);
+ *len = 0;
+
+ if (*string == '\0' || *string == '~')
+ return (0);
+
+ if (prefixes)
+ {
+ for (i = 0; i < string_len; i++)
+ {
+ for (j = 0; prefixes[j]; j++)
+ {
+ if (strncmp (string + i, prefixes[j], strlen (prefixes[j])) == 0)
+ {
+ *len = strlen (prefixes[j]) - 1;
+ return (i + *len);
+ }
+ }
+ }
+ }
+ return (string_len);
+}
+
+/* Find the end of a tilde expansion in STRING, and return the index of
+ the character which ends the tilde definition. */
+static int
+tilde_find_suffix (string)
+ char *string;
+{
+ register int i, j, string_len;
+ register char **suffixes;
+
+ suffixes = tilde_additional_suffixes;
+ string_len = strlen (string);
+
+ for (i = 0; i < string_len; i++)
+ {
+ if (string[i] == '/' /* || !string[i] */)
+ break;
+
+ for (j = 0; suffixes && suffixes[j]; j++)
+ {
+ if (strncmp (string + i, suffixes[j], strlen (suffixes[j])) == 0)
+ return (i);
+ }
+ }
+ return (i);
+}
+
+/* Return a new string which is the result of tilde expanding STRING. */
+char *
+tilde_expand (string)
+ char *string;
+{
+ char *result;
+ int result_size, result_index;
+
+ result_index = result_size = 0;
+ if (result = strchr (string, '~'))
+ result = xmalloc (result_size = (strlen (string) + 16));
+ else
+ result = xmalloc (result_size = (strlen (string) + 1));
+
+ /* Scan through STRING expanding tildes as we come to them. */
+ while (1)
+ {
+ register int start, end;
+ char *tilde_word, *expansion;
+ int len;
+
+ /* Make START point to the tilde which starts the expansion. */
+ start = tilde_find_prefix (string, &len);
+
+ /* Copy the skipped text into the result. */
+ if ((result_index + start + 1) > result_size)
+ result = xrealloc (result, 1 + (result_size += (start + 20)));
+
+ strncpy (result + result_index, string, start);
+ result_index += start;
+
+ /* Advance STRING to the starting tilde. */
+ string += start;
+
+ /* Make END be the index of one after the last character of the
+ username. */
+ end = tilde_find_suffix (string);
+
+ /* If both START and END are zero, we are all done. */
+ if (!start && !end)
+ break;
+
+ /* Expand the entire tilde word, and copy it into RESULT. */
+ tilde_word = xmalloc (1 + end);
+ strncpy (tilde_word, string, end);
+ tilde_word[end] = '\0';
+ string += end;
+
+ expansion = tilde_expand_word (tilde_word);
+ free (tilde_word);
+
+ len = strlen (expansion);
+ if ((result_index + len + 1) > result_size)
+ result = xrealloc (result, 1 + (result_size += (len + 20)));
+
+ strcpy (result + result_index, expansion);
+ result_index += len;
+ free (expansion);
+ }
+
+ result[result_index] = '\0';
+
+ return (result);
+}
+
+/* Take FNAME and return the tilde prefix we want expanded. If LENP is
+ non-null, the index of the end of the prefix into FNAME is returned in
+ the location it points to. */
+static char *
+isolate_tilde_prefix (fname, lenp)
+ char *fname;
+ int *lenp;
+{
+ char *ret;
+ int i;
+
+ ret = xmalloc (strlen (fname));
+ for (i = 1; fname[i] && fname[i] != '/'; i++)
+ ret[i - 1] = fname[i];
+ ret[i - 1] = '\0';
+ if (lenp)
+ *lenp = i;
+ return ret;
+}
+
+/* Return a string that is PREFIX concatenated with SUFFIX starting at
+ SUFFIND. */
+static char *
+glue_prefix_and_suffix (prefix, suffix, suffind)
+ char *prefix, *suffix;
+ int suffind;
+{
+ char *ret;
+ int plen, slen;
+
+ plen = (prefix && *prefix) ? strlen (prefix) : 0;
+ slen = strlen (suffix + suffind);
+ ret = xmalloc (plen + slen + 1);
+ if (prefix && *prefix)
+ strcpy (ret, prefix);
+ strcpy (ret + plen, suffix + suffind);
+ return ret;
+}
+
+/* Do the work of tilde expansion on FILENAME. FILENAME starts with a
+ tilde. If there is no expansion, call tilde_expansion_failure_hook.
+ This always returns a newly-allocated string, never static storage. */
+char *
+tilde_expand_word (filename)
+ char *filename;
+{
+ char *dirname, *expansion, *username;
+ int user_len;
+ struct passwd *user_entry;
+
+ if (filename == 0)
+ return ((char *)NULL);
+
+ if (*filename != '~')
+ return (savestring (filename));
+
+ /* A leading `~/' or a bare `~' is *always* translated to the value of
+ $HOME or the home directory of the current user, regardless of any
+ preexpansion hook. */
+ if (filename[1] == '\0' || filename[1] == '/')
+ {
+ /* Prefix $HOME to the rest of the string. */
+ expansion = get_env_value ("HOME");
+
+ /* If there is no HOME variable, look up the directory in
+ the password database. */
+ if (expansion == 0)
+ expansion = get_home_dir ();
+
+ return (glue_prefix_and_suffix (expansion, filename, 1));
+ }
+
+ username = isolate_tilde_prefix (filename, &user_len);
+
+ if (tilde_expansion_preexpansion_hook)
+ {
+ expansion = (*tilde_expansion_preexpansion_hook) (username);
+ if (expansion)
+ {
+ dirname = glue_prefix_and_suffix (expansion, filename, user_len);
+ free (username);
+ free (expansion);
+ return (dirname);
+ }
+ }
+
+ /* No preexpansion hook, or the preexpansion hook failed. Look in the
+ password database. */
+ dirname = (char *)NULL;
+ user_entry = getpwnam (username);
+ if (user_entry == 0)
+ {
+ /* If the calling program has a special syntax for expanding tildes,
+ and we couldn't find a standard expansion, then let them try. */
+ if (tilde_expansion_failure_hook)
+ {
+ expansion = (*tilde_expansion_failure_hook) (username);
+ if (expansion)
+ {
+ dirname = glue_prefix_and_suffix (expansion, filename, user_len);
+ free (expansion);
+ }
+ }
+ free (username);
+ /* If we don't have a failure hook, or if the failure hook did not
+ expand the tilde, return a copy of what we were passed. */
+ if (dirname == 0)
+ dirname = savestring (filename);
+ }
+ else
+ {
+ free (username);
+ dirname = glue_prefix_and_suffix (user_entry->pw_dir, filename, user_len);
+ }
+
+ endpwent ();
+ return (dirname);
+}
+
+
+#if defined (TEST)
+#undef NULL
+#include <stdio.h>
+
+main (argc, argv)
+ int argc;
+ char **argv;
+{
+ char *result, line[512];
+ int done = 0;
+
+ while (!done)
+ {
+ printf ("~expand: ");
+ fflush (stdout);
+
+ if (!gets (line))
+ strcpy (line, "done");
+
+ if ((strcmp (line, "done") == 0) ||
+ (strcmp (line, "quit") == 0) ||
+ (strcmp (line, "exit") == 0))
+ {
+ done = 1;
+ break;
+ }
+
+ result = tilde_expand (line);
+ printf (" --> %s\n", result);
+ free (result);
+ }
+ exit (0);
+}
+
+static void memory_error_and_abort ();
+
+static char *
+xmalloc (bytes)
+ int bytes;
+{
+ char *temp = (char *)malloc (bytes);
+
+ if (!temp)
+ memory_error_and_abort ();
+ return (temp);
+}
+
+static char *
+xrealloc (pointer, bytes)
+ char *pointer;
+ int bytes;
+{
+ char *temp;
+
+ if (!pointer)
+ temp = (char *)malloc (bytes);
+ else
+ temp = (char *)realloc (pointer, bytes);
+
+ if (!temp)
+ memory_error_and_abort ();
+
+ return (temp);
+}
+
+static void
+memory_error_and_abort ()
+{
+ fprintf (stderr, "readline: out of virtual memory\n");
+ abort ();
+}
+
+/*
+ * Local variables:
+ * compile-command: "gcc -g -DTEST -o tilde tilde.c"
+ * end:
+ */
+#endif /* TEST */
diff --git a/readline/tilde.h b/readline/tilde.h
new file mode 100644
index 00000000000..634b95449aa
--- /dev/null
+++ b/readline/tilde.h
@@ -0,0 +1,65 @@
+/* tilde.h: Externally available variables and function in libtilde.a. */
+
+/* Copyright (C) 1992 Free Software Foundation, Inc.
+
+ This file contains the Readline Library (the Library), a set of
+ routines for providing Emacs style line input to programs that ask
+ for it.
+
+ The Library is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 1, or (at your option)
+ any later version.
+
+ The 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
+ General Public License for more details.
+
+ The GNU General Public License is often shipped with GNU software, and
+ is generally kept in a file called COPYING or LICENSE. If you do not
+ have a copy of the license, write to the Free Software Foundation,
+ 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#if !defined (_TILDE_H_)
+# define _TILDE_H_
+
+/* Function pointers can be declared as (Function *)foo. */
+#if !defined (_FUNCTION_DEF)
+# define _FUNCTION_DEF
+typedef int Function ();
+typedef void VFunction ();
+typedef char *CPFunction ();
+typedef char **CPPFunction ();
+#endif /* _FUNCTION_DEF */
+
+/* If non-null, this contains the address of a function that the application
+ wants called before trying the standard tilde expansions. The function
+ is called with the text sans tilde, and returns a malloc()'ed string
+ which is the expansion, or a NULL pointer if the expansion fails. */
+extern CPFunction *tilde_expansion_preexpansion_hook;
+
+/* If non-null, this contains the address of a function to call if the
+ standard meaning for expanding a tilde fails. The function is called
+ with the text (sans tilde, as in "foo"), and returns a malloc()'ed string
+ which is the expansion, or a NULL pointer if there is no expansion. */
+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;
+
+/* 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;
+
+/* Return a new string which is the result of tilde expanding STRING. */
+extern char *tilde_expand ();
+
+/* Do the work of tilde expansion on FILENAME. FILENAME starts with a
+ tilde. If there is no expansion, call tilde_expansion_failure_hook. */
+extern char *tilde_expand_word ();
+
+#endif /* _TILDE_H_ */
diff --git a/readline/undo.c b/readline/undo.c
new file mode 100644
index 00000000000..28ebcc85b93
--- /dev/null
+++ b/readline/undo.c
@@ -0,0 +1,260 @@
+/* readline.c -- a general facility for reading lines of input
+ with emacs style editing and completion. */
+
+/* Copyright (C) 1987, 1989, 1992 Free Software Foundation, Inc.
+
+ This file is part of the GNU Readline Library, a library for
+ reading lines of text with interactive input and history editing.
+
+ The GNU Readline Library is free software; you can redistribute it
+ and/or modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 1, or
+ (at your option) any later version.
+
+ The GNU Readline 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 General Public License for more details.
+
+ The GNU General Public License is often shipped with GNU software, and
+ is generally kept in a file called COPYING or LICENSE. If you do not
+ have a copy of the license, write to the Free Software Foundation,
+ 675 Mass Ave, Cambridge, MA 02139, USA. */
+#define READLINE_LIBRARY
+
+#if defined (HAVE_CONFIG_H)
+# include <config.h>
+#endif
+
+#include <sys/types.h>
+
+#if defined (HAVE_UNISTD_H)
+# include <unistd.h> /* for _POSIX_VERSION */
+#endif /* HAVE_UNISTD_H */
+
+#if defined (HAVE_STDLIB_H)
+# include <stdlib.h>
+#else
+# include "ansi_stdlib.h"
+#endif /* HAVE_STDLIB_H */
+
+#include <stdio.h>
+
+/* System-specific feature definitions and include files. */
+#include "rldefs.h"
+
+/* Some standard library routines. */
+#include "readline.h"
+#include "history.h"
+
+#define SWAP(s, e) do { int t; t = s; s = e; e = t; } while (0)
+
+/* Non-zero tells rl_delete_text and rl_insert_text to not add to
+ the undo list. */
+int _rl_doing_an_undo = 0;
+
+/* How many unclosed undo groups we currently have. */
+int _rl_undo_group_level = 0;
+
+/* The current undo list for THE_LINE. */
+UNDO_LIST *rl_undo_list = (UNDO_LIST *)NULL;
+
+/* **************************************************************** */
+/* */
+/* Undo, and Undoing */
+/* */
+/* **************************************************************** */
+
+/* Remember how to undo something. Concatenate some undos if that
+ seems right. */
+void
+rl_add_undo (what, start, end, text)
+ enum undo_code what;
+ int start, end;
+ char *text;
+{
+ UNDO_LIST *temp = (UNDO_LIST *)xmalloc (sizeof (UNDO_LIST));
+ temp->what = what;
+ temp->start = start;
+ temp->end = end;
+ temp->text = text;
+ temp->next = rl_undo_list;
+ rl_undo_list = temp;
+}
+
+/* Free the existing undo list. */
+void
+free_undo_list ()
+{
+ while (rl_undo_list)
+ {
+ UNDO_LIST *release = rl_undo_list;
+ rl_undo_list = rl_undo_list->next;
+
+ if (release->what == UNDO_DELETE)
+ free (release->text);
+
+ free (release);
+ }
+ rl_undo_list = (UNDO_LIST *)NULL;
+}
+
+/* Undo the next thing in the list. Return 0 if there
+ is nothing to undo, or non-zero if there was. */
+int
+rl_do_undo ()
+{
+ UNDO_LIST *release;
+ int waiting_for_begin = 0;
+ int start, end;
+
+#define TRANS(i) ((i) == -1 ? rl_point : ((i) == -2 ? rl_end : (i)))
+
+ do
+ {
+ if (!rl_undo_list)
+ return (0);
+
+ _rl_doing_an_undo = 1;
+
+ /* To better support vi-mode, a start or end value of -1 means
+ rl_point, and a value of -2 means rl_end. */
+ if (rl_undo_list->what == UNDO_DELETE || rl_undo_list->what == UNDO_INSERT)
+ {
+ start = TRANS (rl_undo_list->start);
+ end = TRANS (rl_undo_list->end);
+ }
+
+ switch (rl_undo_list->what)
+ {
+ /* Undoing deletes means inserting some text. */
+ case UNDO_DELETE:
+ rl_point = start;
+ rl_insert_text (rl_undo_list->text);
+ free (rl_undo_list->text);
+ break;
+
+ /* Undoing inserts means deleting some text. */
+ case UNDO_INSERT:
+ rl_delete_text (start, end);
+ rl_point = start;
+ break;
+
+ /* Undoing an END means undoing everything 'til we get to a BEGIN. */
+ case UNDO_END:
+ waiting_for_begin++;
+ break;
+
+ /* Undoing a BEGIN means that we are done with this group. */
+ case UNDO_BEGIN:
+ if (waiting_for_begin)
+ waiting_for_begin--;
+ else
+ ding ();
+ break;
+ }
+
+ _rl_doing_an_undo = 0;
+
+ release = rl_undo_list;
+ rl_undo_list = rl_undo_list->next;
+ free (release);
+ }
+ while (waiting_for_begin);
+
+ return (1);
+}
+#undef TRANS
+
+int
+_rl_fix_last_undo_of_type (type, start, end)
+ int type, start, end;
+{
+ UNDO_LIST *rl;
+
+ for (rl = rl_undo_list; rl; rl = rl->next)
+ {
+ if (rl->what == type)
+ {
+ rl->start = start;
+ rl->end = end;
+ return 0;
+ }
+ }
+ return 1;
+}
+
+/* Begin a group. Subsequent undos are undone as an atomic operation. */
+int
+rl_begin_undo_group ()
+{
+ rl_add_undo (UNDO_BEGIN, 0, 0, 0);
+ _rl_undo_group_level++;
+ return 0;
+}
+
+/* End an undo group started with rl_begin_undo_group (). */
+int
+rl_end_undo_group ()
+{
+ rl_add_undo (UNDO_END, 0, 0, 0);
+ _rl_undo_group_level--;
+ return 0;
+}
+
+/* Save an undo entry for the text from START to END. */
+int
+rl_modifying (start, end)
+ int start, end;
+{
+ if (start > end)
+ {
+ SWAP (start, end);
+ }
+
+ if (start != end)
+ {
+ char *temp = rl_copy_text (start, end);
+ rl_begin_undo_group ();
+ rl_add_undo (UNDO_DELETE, start, end, temp);
+ rl_add_undo (UNDO_INSERT, start, end, (char *)NULL);
+ rl_end_undo_group ();
+ }
+ return 0;
+}
+
+/* Revert the current line to its previous state. */
+int
+rl_revert_line (count, key)
+ int count, key;
+{
+ if (!rl_undo_list)
+ ding ();
+ else
+ {
+ while (rl_undo_list)
+ rl_do_undo ();
+ }
+ return 0;
+}
+
+/* Do some undoing of things that were done. */
+int
+rl_undo_command (count, key)
+ int count, key;
+{
+ if (count < 0)
+ return 0; /* Nothing to do. */
+
+ while (count)
+ {
+ if (rl_do_undo ())
+ count--;
+ else
+ {
+ ding ();
+ break;
+ }
+ }
+ return 0;
+}
diff --git a/readline/util.c b/readline/util.c
new file mode 100644
index 00000000000..1dc3b664f1c
--- /dev/null
+++ b/readline/util.c
@@ -0,0 +1,365 @@
+/* util.c -- readline utility functions */
+
+/* Copyright (C) 1987, 1989, 1992 Free Software Foundation, Inc.
+
+ This file is part of the GNU Readline Library, a library for
+ reading lines of text with interactive input and history editing.
+
+ The GNU Readline Library is free software; you can redistribute it
+ and/or modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 1, or
+ (at your option) any later version.
+
+ The GNU Readline 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 General Public License for more details.
+
+ The GNU General Public License is often shipped with GNU software, and
+ is generally kept in a file called COPYING or LICENSE. If you do not
+ have a copy of the license, write to the Free Software Foundation,
+ 675 Mass Ave, Cambridge, MA 02139, USA. */
+#define READLINE_LIBRARY
+
+#if defined (HAVE_CONFIG_H)
+# include <config.h>
+#endif
+
+#include <sys/types.h>
+#include <fcntl.h>
+#include "posixjmp.h"
+
+#if defined (HAVE_UNISTD_H)
+# include <unistd.h> /* for _POSIX_VERSION */
+#endif /* HAVE_UNISTD_H */
+
+#if defined (HAVE_STDLIB_H)
+# include <stdlib.h>
+#else
+# include "ansi_stdlib.h"
+#endif /* HAVE_STDLIB_H */
+
+#include <stdio.h>
+#include <ctype.h>
+
+/* System-specific feature definitions and include files. */
+#include "rldefs.h"
+
+#if defined (TIOCSTAT_IN_SYS_IOCTL)
+# include <sys/ioctl.h>
+#endif /* TIOCSTAT_IN_SYS_IOCTL */
+
+/* Some standard library routines. */
+#include "readline.h"
+
+#define SWAP(s, e) do { int t; t = s; s = e; e = t; } while (0)
+
+/* Pseudo-globals imported from readline.c */
+extern int readline_echoing_p;
+extern procenv_t readline_top_level;
+extern int rl_line_buffer_len;
+extern Function *rl_last_func;
+
+extern int _rl_defining_kbd_macro;
+extern char *_rl_executing_macro;
+
+/* Pseudo-global functions imported from other library files. */
+extern void _rl_replace_text ();
+extern void _rl_pop_executing_macro ();
+extern void _rl_set_the_line ();
+extern void _rl_init_argument ();
+
+extern char *xmalloc (), *xrealloc ();
+
+/* **************************************************************** */
+/* */
+/* Utility Functions */
+/* */
+/* **************************************************************** */
+
+/* Return 0 if C is not a member of the class of characters that belong
+ in words, or 1 if it is. */
+
+int _rl_allow_pathname_alphabetic_chars = 0;
+static char *pathname_alphabetic_chars = "/-_=~.#$";
+
+int
+alphabetic (c)
+ int c;
+{
+ if (ALPHABETIC (c))
+ return (1);
+
+ return (_rl_allow_pathname_alphabetic_chars &&
+ strchr (pathname_alphabetic_chars, c) != NULL);
+}
+
+/* How to abort things. */
+int
+_rl_abort_internal ()
+{
+ ding ();
+ rl_clear_message ();
+ _rl_init_argument ();
+ rl_pending_input = 0;
+
+ _rl_defining_kbd_macro = 0;
+ while (_rl_executing_macro)
+ _rl_pop_executing_macro ();
+
+ rl_last_func = (Function *)NULL;
+ longjmp (readline_top_level, 1);
+ return (0);
+}
+
+int
+rl_abort (count, key)
+ int count, key;
+{
+ return (_rl_abort_internal ());
+}
+
+int
+rl_tty_status (count, key)
+ int count, key;
+{
+#if defined (TIOCSTAT)
+ ioctl (1, TIOCSTAT, (char *)0);
+ rl_refresh_line (count, key);
+#else
+ ding ();
+#endif
+ return 0;
+}
+
+/* Return a copy of the string between FROM and TO.
+ FROM is inclusive, TO is not. */
+char *
+rl_copy_text (from, to)
+ int from, to;
+{
+ register int length;
+ char *copy;
+
+ /* Fix it if the caller is confused. */
+ if (from > to)
+ SWAP (from, to);
+
+ length = to - from;
+ copy = xmalloc (1 + length);
+ strncpy (copy, rl_line_buffer + from, length);
+ copy[length] = '\0';
+ return (copy);
+}
+
+/* Increase the size of RL_LINE_BUFFER until it has enough space to hold
+ LEN characters. */
+void
+rl_extend_line_buffer (len)
+ int len;
+{
+ while (len >= rl_line_buffer_len)
+ {
+ rl_line_buffer_len += DEFAULT_BUFFER_SIZE;
+ rl_line_buffer = xrealloc (rl_line_buffer, rl_line_buffer_len);
+ }
+
+ _rl_set_the_line ();
+}
+
+
+/* A function for simple tilde expansion. */
+int
+rl_tilde_expand (ignore, key)
+ int ignore, key;
+{
+ register int start, end;
+ char *homedir, *temp;
+ int len;
+
+ end = rl_point;
+ start = end - 1;
+
+ if (rl_point == rl_end && rl_line_buffer[rl_point] == '~')
+ {
+ homedir = tilde_expand ("~");
+ _rl_replace_text (homedir, start, end);
+ return (0);
+ }
+ else if (rl_line_buffer[start] != '~')
+ {
+ for (; !whitespace (rl_line_buffer[start]) && start >= 0; start--)
+ ;
+ start++;
+ }
+
+ end = start;
+ do
+ end++;
+ while (whitespace (rl_line_buffer[end]) == 0 && end < rl_end);
+
+ if (whitespace (rl_line_buffer[end]) || end >= rl_end)
+ end--;
+
+ /* If the first character of the current word is a tilde, perform
+ tilde expansion and insert the result. If not a tilde, do
+ nothing. */
+ if (rl_line_buffer[start] == '~')
+ {
+ len = end - start + 1;
+ temp = xmalloc (len + 1);
+ strncpy (temp, rl_line_buffer + start, len);
+ temp[len] = '\0';
+ homedir = tilde_expand (temp);
+ free (temp);
+
+ _rl_replace_text (homedir, start, end);
+ }
+
+ return (0);
+}
+
+/* **************************************************************** */
+/* */
+/* String Utility Functions */
+/* */
+/* **************************************************************** */
+
+/* Determine if s2 occurs in s1. If so, return a pointer to the
+ match in s1. The compare is case insensitive. */
+char *
+_rl_strindex (s1, s2)
+ register char *s1, *s2;
+{
+ register int i, l, len;
+
+ for (i = 0, l = strlen (s2), len = strlen (s1); (len - i) >= l; i++)
+ if (_rl_strnicmp (s1 + i, s2, l) == 0)
+ return (s1 + i);
+ return ((char *)NULL);
+}
+
+#if !defined (HAVE_STRCASECMP)
+/* Compare at most COUNT characters from string1 to string2. Case
+ doesn't matter. */
+int
+_rl_strnicmp (string1, string2, count)
+ char *string1, *string2;
+ int count;
+{
+ register char ch1, ch2;
+
+ while (count)
+ {
+ ch1 = *string1++;
+ ch2 = *string2++;
+ if (_rl_to_upper(ch1) == _rl_to_upper(ch2))
+ count--;
+ else
+ break;
+ }
+ return (count);
+}
+
+/* strcmp (), but caseless. */
+int
+_rl_stricmp (string1, string2)
+ char *string1, *string2;
+{
+ register char ch1, ch2;
+
+ while (*string1 && *string2)
+ {
+ ch1 = *string1++;
+ ch2 = *string2++;
+ if (_rl_to_upper(ch1) != _rl_to_upper(ch2))
+ return (1);
+ }
+ return (*string1 - *string2);
+}
+#endif /* !HAVE_STRCASECMP */
+
+/* Stupid comparison routine for qsort () ing strings. */
+int
+_rl_qsort_string_compare (s1, s2)
+ char **s1, **s2;
+{
+#if defined (HAVE_STRCOLL)
+ return (strcoll (*s1, *s2));
+#else
+ int result;
+
+ result = **s1 - **s2;
+ if (result == 0)
+ result = strcmp (*s1, *s2);
+
+ return result;
+#endif
+}
+
+/* Function equivalents for the macros defined in chartypes.h. */
+#undef _rl_uppercase_p
+int
+_rl_uppercase_p (c)
+ int c;
+{
+ return (isupper (c));
+}
+
+#undef _rl_lowercase_p
+int
+_rl_lowercase_p (c)
+ int c;
+{
+ return (islower (c));
+}
+
+#undef _rl_pure_alphabetic
+int
+_rl_pure_alphabetic (c)
+ int c;
+{
+ return (isupper (c) || islower (c));
+}
+
+#undef _rl_digit_p
+int
+_rl_digit_p (c)
+ int c;
+{
+ return (isdigit (c));
+}
+
+#undef _rl_to_lower
+int
+_rl_to_lower (c)
+ int c;
+{
+ return (isupper (c) ? tolower (c) : c);
+}
+
+#undef _rl_to_upper
+int
+_rl_to_upper (c)
+ int c;
+{
+ return (islower (c) ? toupper (c) : c);
+}
+
+#undef _rl_digit_value
+int
+_rl_digit_value (c)
+ int c;
+{
+ return (isdigit (c) ? c - '0' : c);
+}
+
+/* Backwards compatibility, now that savestring has been removed from
+ all `public' readline header files. */
+#undef _rl_savestring
+char *
+_rl_savestring (s)
+ char *s;
+{
+ return ((char *)strcpy (xmalloc (1 + (int)strlen (s)), (s)));
+}
diff --git a/readline/vi_keymap.c b/readline/vi_keymap.c
new file mode 100644
index 00000000000..14929a31930
--- /dev/null
+++ b/readline/vi_keymap.c
@@ -0,0 +1,877 @@
+/* vi_keymap.c -- the keymap for vi_mode in readline (). */
+
+/* Copyright (C) 1987, 1989, 1992 Free Software Foundation, Inc.
+
+ This file is part of the GNU Readline Library, a library for
+ reading lines of text with interactive input and history editing.
+
+ The GNU Readline Library is free software; you can redistribute it
+ and/or modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 1, or
+ (at your option) any later version.
+
+ The GNU Readline 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 General Public License for more details.
+
+ The GNU General Public License is often shipped with GNU software, and
+ is generally kept in a file called COPYING or LICENSE. If you do not
+ have a copy of the license, write to the Free Software Foundation,
+ 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#if !defined (BUFSIZ)
+#include <stdio.h>
+#endif /* !BUFSIZ */
+
+#include "readline.h"
+
+#if 0
+extern KEYMAP_ENTRY_ARRAY vi_escape_keymap;
+#endif
+
+/* The keymap arrays for handling vi mode. */
+KEYMAP_ENTRY_ARRAY vi_movement_keymap = {
+ /* The regular control keys come first. */
+ { ISFUNC, (Function *)0x0 }, /* Control-@ */
+ { ISFUNC, (Function *)0x0 }, /* Control-a */
+ { ISFUNC, (Function *)0x0 }, /* Control-b */
+ { ISFUNC, (Function *)0x0 }, /* Control-c */
+ { ISFUNC, rl_vi_eof_maybe }, /* Control-d */
+ { ISFUNC, rl_emacs_editing_mode }, /* Control-e */
+ { ISFUNC, (Function *)0x0 }, /* Control-f */
+ { ISFUNC, rl_abort }, /* Control-g */
+ { ISFUNC, rl_backward }, /* Control-h */
+ { ISFUNC, (Function *)0x0 }, /* Control-i */
+ { ISFUNC, rl_newline }, /* Control-j */
+ { ISFUNC, rl_kill_line }, /* Control-k */
+ { ISFUNC, rl_clear_screen }, /* Control-l */
+ { ISFUNC, rl_newline }, /* Control-m */
+ { ISFUNC, rl_get_next_history }, /* Control-n */
+ { ISFUNC, (Function *)0x0 }, /* Control-o */
+ { ISFUNC, rl_get_previous_history }, /* Control-p */
+ { ISFUNC, rl_quoted_insert }, /* Control-q */
+ { ISFUNC, rl_reverse_search_history }, /* Control-r */
+ { ISFUNC, rl_forward_search_history }, /* Control-s */
+ { ISFUNC, rl_transpose_chars }, /* Control-t */
+ { ISFUNC, rl_unix_line_discard }, /* Control-u */
+ { ISFUNC, rl_quoted_insert }, /* Control-v */
+ { ISFUNC, rl_unix_word_rubout }, /* Control-w */
+ { ISFUNC, (Function *)0x0 }, /* Control-x */
+ { ISFUNC, rl_yank }, /* Control-y */
+ { ISFUNC, (Function *)0x0 }, /* Control-z */
+
+ { ISFUNC, (Function *)0x0 }, /* Control-[ */ /* vi_escape_keymap */
+ { ISFUNC, (Function *)0x0 }, /* Control-\ */
+ { ISFUNC, (Function *)0x0 }, /* Control-] */
+ { ISFUNC, (Function *)0x0 }, /* Control-^ */
+ { ISFUNC, rl_vi_undo }, /* Control-_ */
+
+ /* The start of printing characters. */
+ { ISFUNC, rl_forward }, /* SPACE */
+ { ISFUNC, (Function *)0x0 }, /* ! */
+ { ISFUNC, (Function *)0x0 }, /* " */
+ { ISFUNC, rl_insert_comment }, /* # */
+ { ISFUNC, rl_end_of_line }, /* $ */
+ { ISFUNC, rl_vi_match }, /* % */
+ { ISFUNC, rl_vi_tilde_expand }, /* & */
+ { ISFUNC, (Function *)0x0 }, /* ' */
+ { ISFUNC, (Function *)0x0 }, /* ( */
+ { ISFUNC, (Function *)0x0 }, /* ) */
+ { ISFUNC, rl_vi_complete }, /* * */
+ { ISFUNC, rl_get_next_history}, /* + */
+ { ISFUNC, rl_vi_char_search }, /* , */
+ { ISFUNC, rl_get_previous_history }, /* - */
+ { ISFUNC, rl_vi_redo }, /* . */
+ { ISFUNC, rl_vi_search }, /* / */
+
+ /* Regular digits. */
+ { ISFUNC, rl_beg_of_line }, /* 0 */
+ { ISFUNC, rl_vi_arg_digit }, /* 1 */
+ { ISFUNC, rl_vi_arg_digit }, /* 2 */
+ { ISFUNC, rl_vi_arg_digit }, /* 3 */
+ { ISFUNC, rl_vi_arg_digit }, /* 4 */
+ { ISFUNC, rl_vi_arg_digit }, /* 5 */
+ { ISFUNC, rl_vi_arg_digit }, /* 6 */
+ { ISFUNC, rl_vi_arg_digit }, /* 7 */
+ { ISFUNC, rl_vi_arg_digit }, /* 8 */
+ { ISFUNC, rl_vi_arg_digit }, /* 9 */
+
+ /* A little more punctuation. */
+ { ISFUNC, (Function *)0x0 }, /* : */
+ { ISFUNC, rl_vi_char_search }, /* ; */
+ { ISFUNC, (Function *)0x0 }, /* < */
+ { ISFUNC, rl_vi_complete }, /* = */
+ { ISFUNC, (Function *)0x0 }, /* > */
+ { ISFUNC, rl_vi_search }, /* ? */
+ { ISFUNC, (Function *)0x0 }, /* @ */
+
+ /* Uppercase alphabet. */
+ { ISFUNC, rl_vi_append_eol }, /* A */
+ { ISFUNC, rl_vi_prev_word}, /* B */
+ { ISFUNC, rl_vi_change_to }, /* C */
+ { ISFUNC, rl_vi_delete_to }, /* D */
+ { ISFUNC, rl_vi_end_word }, /* E */
+ { ISFUNC, rl_vi_char_search }, /* F */
+ { ISFUNC, rl_vi_fetch_history }, /* G */
+ { ISFUNC, (Function *)0x0 }, /* H */
+ { ISFUNC, rl_vi_insert_beg }, /* I */
+ { ISFUNC, (Function *)0x0 }, /* J */
+ { ISFUNC, (Function *)0x0 }, /* K */
+ { ISFUNC, (Function *)0x0 }, /* L */
+ { ISFUNC, (Function *)0x0 }, /* M */
+ { ISFUNC, rl_vi_search_again }, /* N */
+ { ISFUNC, (Function *)0x0 }, /* O */
+ { ISFUNC, rl_vi_put }, /* P */
+ { ISFUNC, (Function *)0x0 }, /* Q */
+ { ISFUNC, rl_vi_replace }, /* R */
+ { ISFUNC, rl_vi_subst }, /* S */
+ { ISFUNC, rl_vi_char_search }, /* T */
+ { ISFUNC, rl_revert_line }, /* U */
+ { ISFUNC, (Function *)0x0 }, /* V */
+ { ISFUNC, rl_vi_next_word }, /* W */
+ { ISFUNC, rl_rubout }, /* X */
+ { ISFUNC, rl_vi_yank_to }, /* Y */
+ { ISFUNC, (Function *)0x0 }, /* Z */
+
+ /* Some more punctuation. */
+ { ISFUNC, (Function *)0x0 }, /* [ */
+ { ISFUNC, rl_vi_complete }, /* \ */
+ { ISFUNC, (Function *)0x0 }, /* ] */
+ { ISFUNC, rl_vi_first_print }, /* ^ */
+ { ISFUNC, rl_vi_yank_arg }, /* _ */
+ { ISFUNC, rl_vi_goto_mark }, /* ` */
+
+ /* Lowercase alphabet. */
+ { ISFUNC, rl_vi_append_mode }, /* a */
+ { ISFUNC, rl_vi_prev_word }, /* b */
+ { ISFUNC, rl_vi_change_to }, /* c */
+ { ISFUNC, rl_vi_delete_to }, /* d */
+ { ISFUNC, rl_vi_end_word }, /* e */
+ { ISFUNC, rl_vi_char_search }, /* f */
+ { ISFUNC, (Function *)0x0 }, /* g */
+ { ISFUNC, rl_backward }, /* h */
+ { ISFUNC, rl_vi_insertion_mode }, /* i */
+ { ISFUNC, rl_get_next_history }, /* j */
+ { ISFUNC, rl_get_previous_history }, /* k */
+ { ISFUNC, rl_forward }, /* l */
+ { ISFUNC, rl_vi_set_mark }, /* m */
+ { ISFUNC, rl_vi_search_again }, /* n */
+ { ISFUNC, (Function *)0x0 }, /* o */
+ { ISFUNC, rl_vi_put }, /* p */
+ { ISFUNC, (Function *)0x0 }, /* q */
+ { ISFUNC, rl_vi_change_char }, /* r */
+ { ISFUNC, rl_vi_subst }, /* s */
+ { ISFUNC, rl_vi_char_search }, /* t */
+ { ISFUNC, rl_vi_undo }, /* u */
+ { ISFUNC, (Function *)0x0 }, /* v */
+ { ISFUNC, rl_vi_next_word }, /* w */
+ { ISFUNC, rl_vi_delete }, /* x */
+ { ISFUNC, rl_vi_yank_to }, /* y */
+ { ISFUNC, (Function *)0x0 }, /* z */
+
+ /* Final punctuation. */
+ { ISFUNC, (Function *)0x0 }, /* { */
+ { ISFUNC, rl_vi_column }, /* | */
+ { ISFUNC, (Function *)0x0 }, /* } */
+ { ISFUNC, rl_vi_change_case }, /* ~ */
+ { ISFUNC, (Function *)0x0 }, /* RUBOUT */
+
+#if KEYMAP_SIZE > 128
+ /* Undefined keys. */
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 }
+#endif /* KEYMAP_SIZE > 128 */
+};
+
+
+KEYMAP_ENTRY_ARRAY vi_insertion_keymap = {
+ /* The regular control keys come first. */
+ { ISFUNC, (Function *)0x0 }, /* Control-@ */
+ { ISFUNC, rl_insert }, /* Control-a */
+ { ISFUNC, rl_insert }, /* Control-b */
+ { ISFUNC, rl_insert }, /* Control-c */
+ { ISFUNC, rl_vi_eof_maybe }, /* Control-d */
+ { ISFUNC, rl_insert }, /* Control-e */
+ { ISFUNC, rl_insert }, /* Control-f */
+ { ISFUNC, rl_insert }, /* Control-g */
+ { ISFUNC, rl_rubout }, /* Control-h */
+ { ISFUNC, rl_complete }, /* Control-i */
+ { ISFUNC, rl_newline }, /* Control-j */
+ { ISFUNC, rl_insert }, /* Control-k */
+ { ISFUNC, rl_insert }, /* Control-l */
+ { ISFUNC, rl_newline }, /* Control-m */
+ { ISFUNC, rl_insert }, /* Control-n */
+ { ISFUNC, rl_insert }, /* Control-o */
+ { ISFUNC, rl_insert }, /* Control-p */
+ { ISFUNC, rl_insert }, /* Control-q */
+ { ISFUNC, rl_reverse_search_history }, /* Control-r */
+ { ISFUNC, rl_forward_search_history }, /* Control-s */
+ { ISFUNC, rl_transpose_chars }, /* Control-t */
+ { ISFUNC, rl_unix_line_discard }, /* Control-u */
+ { ISFUNC, rl_quoted_insert }, /* Control-v */
+ { ISFUNC, rl_unix_word_rubout }, /* Control-w */
+ { ISFUNC, rl_insert }, /* Control-x */
+ { ISFUNC, rl_yank }, /* Control-y */
+ { ISFUNC, rl_insert }, /* Control-z */
+
+ { ISFUNC, rl_vi_movement_mode }, /* Control-[ */
+ { ISFUNC, rl_insert }, /* Control-\ */
+ { ISFUNC, rl_insert }, /* Control-] */
+ { ISFUNC, rl_insert }, /* Control-^ */
+ { ISFUNC, rl_vi_undo }, /* Control-_ */
+
+ /* The start of printing characters. */
+ { ISFUNC, rl_insert }, /* SPACE */
+ { ISFUNC, rl_insert }, /* ! */
+ { ISFUNC, rl_insert }, /* " */
+ { ISFUNC, rl_insert }, /* # */
+ { ISFUNC, rl_insert }, /* $ */
+ { ISFUNC, rl_insert }, /* % */
+ { ISFUNC, rl_insert }, /* & */
+ { ISFUNC, rl_insert }, /* ' */
+ { ISFUNC, rl_insert }, /* ( */
+ { ISFUNC, rl_insert }, /* ) */
+ { ISFUNC, rl_insert }, /* * */
+ { ISFUNC, rl_insert }, /* + */
+ { ISFUNC, rl_insert }, /* , */
+ { ISFUNC, rl_insert }, /* - */
+ { ISFUNC, rl_insert }, /* . */
+ { ISFUNC, rl_insert }, /* / */
+
+ /* Regular digits. */
+ { ISFUNC, rl_insert }, /* 0 */
+ { ISFUNC, rl_insert }, /* 1 */
+ { ISFUNC, rl_insert }, /* 2 */
+ { ISFUNC, rl_insert }, /* 3 */
+ { ISFUNC, rl_insert }, /* 4 */
+ { ISFUNC, rl_insert }, /* 5 */
+ { ISFUNC, rl_insert }, /* 6 */
+ { ISFUNC, rl_insert }, /* 7 */
+ { ISFUNC, rl_insert }, /* 8 */
+ { ISFUNC, rl_insert }, /* 9 */
+
+ /* A little more punctuation. */
+ { ISFUNC, rl_insert }, /* : */
+ { ISFUNC, rl_insert }, /* ; */
+ { ISFUNC, rl_insert }, /* < */
+ { ISFUNC, rl_insert }, /* = */
+ { ISFUNC, rl_insert }, /* > */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* @ */
+
+ /* Uppercase alphabet. */
+ { ISFUNC, rl_insert }, /* A */
+ { ISFUNC, rl_insert }, /* B */
+ { ISFUNC, rl_insert }, /* C */
+ { ISFUNC, rl_insert }, /* D */
+ { ISFUNC, rl_insert }, /* E */
+ { ISFUNC, rl_insert }, /* F */
+ { ISFUNC, rl_insert }, /* G */
+ { ISFUNC, rl_insert }, /* H */
+ { ISFUNC, rl_insert }, /* I */
+ { ISFUNC, rl_insert }, /* J */
+ { ISFUNC, rl_insert }, /* K */
+ { ISFUNC, rl_insert }, /* L */
+ { ISFUNC, rl_insert }, /* M */
+ { ISFUNC, rl_insert }, /* N */
+ { ISFUNC, rl_insert }, /* O */
+ { ISFUNC, rl_insert }, /* P */
+ { ISFUNC, rl_insert }, /* Q */
+ { ISFUNC, rl_insert }, /* R */
+ { ISFUNC, rl_insert }, /* S */
+ { ISFUNC, rl_insert }, /* T */
+ { ISFUNC, rl_insert }, /* U */
+ { ISFUNC, rl_insert }, /* V */
+ { ISFUNC, rl_insert }, /* W */
+ { ISFUNC, rl_insert }, /* X */
+ { ISFUNC, rl_insert }, /* Y */
+ { ISFUNC, rl_insert }, /* Z */
+
+ /* Some more punctuation. */
+ { ISFUNC, rl_insert }, /* [ */
+ { ISFUNC, rl_insert }, /* \ */
+ { ISFUNC, rl_insert }, /* ] */
+ { ISFUNC, rl_insert }, /* ^ */
+ { ISFUNC, rl_insert }, /* _ */
+ { ISFUNC, rl_insert }, /* ` */
+
+ /* Lowercase alphabet. */
+ { ISFUNC, rl_insert }, /* a */
+ { ISFUNC, rl_insert }, /* b */
+ { ISFUNC, rl_insert }, /* c */
+ { ISFUNC, rl_insert }, /* d */
+ { ISFUNC, rl_insert }, /* e */
+ { ISFUNC, rl_insert }, /* f */
+ { ISFUNC, rl_insert }, /* g */
+ { ISFUNC, rl_insert }, /* h */
+ { ISFUNC, rl_insert }, /* i */
+ { ISFUNC, rl_insert }, /* j */
+ { ISFUNC, rl_insert }, /* k */
+ { ISFUNC, rl_insert }, /* l */
+ { ISFUNC, rl_insert }, /* m */
+ { ISFUNC, rl_insert }, /* n */
+ { ISFUNC, rl_insert }, /* o */
+ { ISFUNC, rl_insert }, /* p */
+ { ISFUNC, rl_insert }, /* q */
+ { ISFUNC, rl_insert }, /* r */
+ { ISFUNC, rl_insert }, /* s */
+ { ISFUNC, rl_insert }, /* t */
+ { ISFUNC, rl_insert }, /* u */
+ { ISFUNC, rl_insert }, /* v */
+ { ISFUNC, rl_insert }, /* w */
+ { ISFUNC, rl_insert }, /* x */
+ { ISFUNC, rl_insert }, /* y */
+ { ISFUNC, rl_insert }, /* z */
+
+ /* Final punctuation. */
+ { ISFUNC, rl_insert }, /* { */
+ { ISFUNC, rl_insert }, /* | */
+ { ISFUNC, rl_insert }, /* } */
+ { ISFUNC, rl_insert }, /* ~ */
+ { ISFUNC, rl_rubout }, /* RUBOUT */
+
+#if KEYMAP_SIZE > 128
+ /* Pure 8-bit characters (128 - 159).
+ These might be used in some
+ character sets. */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+ { ISFUNC, rl_insert }, /* ? */
+
+ /* ISO Latin-1 characters (160 - 255) */
+ { ISFUNC, rl_insert }, /* No-break space */
+ { ISFUNC, rl_insert }, /* Inverted exclamation mark */
+ { ISFUNC, rl_insert }, /* Cent sign */
+ { ISFUNC, rl_insert }, /* Pound sign */
+ { ISFUNC, rl_insert }, /* Currency sign */
+ { ISFUNC, rl_insert }, /* Yen sign */
+ { ISFUNC, rl_insert }, /* Broken bar */
+ { ISFUNC, rl_insert }, /* Section sign */
+ { ISFUNC, rl_insert }, /* Diaeresis */
+ { ISFUNC, rl_insert }, /* Copyright sign */
+ { ISFUNC, rl_insert }, /* Feminine ordinal indicator */
+ { ISFUNC, rl_insert }, /* Left pointing double angle quotation mark */
+ { ISFUNC, rl_insert }, /* Not sign */
+ { ISFUNC, rl_insert }, /* Soft hyphen */
+ { ISFUNC, rl_insert }, /* Registered sign */
+ { ISFUNC, rl_insert }, /* Macron */
+ { ISFUNC, rl_insert }, /* Degree sign */
+ { ISFUNC, rl_insert }, /* Plus-minus sign */
+ { ISFUNC, rl_insert }, /* Superscript two */
+ { ISFUNC, rl_insert }, /* Superscript three */
+ { ISFUNC, rl_insert }, /* Acute accent */
+ { ISFUNC, rl_insert }, /* Micro sign */
+ { ISFUNC, rl_insert }, /* Pilcrow sign */
+ { ISFUNC, rl_insert }, /* Middle dot */
+ { ISFUNC, rl_insert }, /* Cedilla */
+ { ISFUNC, rl_insert }, /* Superscript one */
+ { ISFUNC, rl_insert }, /* Masculine ordinal indicator */
+ { ISFUNC, rl_insert }, /* Right pointing double angle quotation mark */
+ { ISFUNC, rl_insert }, /* Vulgar fraction one quarter */
+ { ISFUNC, rl_insert }, /* Vulgar fraction one half */
+ { ISFUNC, rl_insert }, /* Vulgar fraction three quarters */
+ { ISFUNC, rl_insert }, /* Inverted questionk mark */
+ { ISFUNC, rl_insert }, /* Latin capital letter a with grave */
+ { ISFUNC, rl_insert }, /* Latin capital letter a with acute */
+ { ISFUNC, rl_insert }, /* Latin capital letter a with circumflex */
+ { ISFUNC, rl_insert }, /* Latin capital letter a with tilde */
+ { ISFUNC, rl_insert }, /* Latin capital letter a with diaeresis */
+ { ISFUNC, rl_insert }, /* Latin capital letter a with ring above */
+ { ISFUNC, rl_insert }, /* Latin capital letter ae */
+ { ISFUNC, rl_insert }, /* Latin capital letter c with cedilla */
+ { ISFUNC, rl_insert }, /* Latin capital letter e with grave */
+ { ISFUNC, rl_insert }, /* Latin capital letter e with acute */
+ { ISFUNC, rl_insert }, /* Latin capital letter e with circumflex */
+ { ISFUNC, rl_insert }, /* Latin capital letter e with diaeresis */
+ { ISFUNC, rl_insert }, /* Latin capital letter i with grave */
+ { ISFUNC, rl_insert }, /* Latin capital letter i with acute */
+ { ISFUNC, rl_insert }, /* Latin capital letter i with circumflex */
+ { ISFUNC, rl_insert }, /* Latin capital letter i with diaeresis */
+ { ISFUNC, rl_insert }, /* Latin capital letter eth (Icelandic) */
+ { ISFUNC, rl_insert }, /* Latin capital letter n with tilde */
+ { ISFUNC, rl_insert }, /* Latin capital letter o with grave */
+ { ISFUNC, rl_insert }, /* Latin capital letter o with acute */
+ { ISFUNC, rl_insert }, /* Latin capital letter o with circumflex */
+ { ISFUNC, rl_insert }, /* Latin capital letter o with tilde */
+ { ISFUNC, rl_insert }, /* Latin capital letter o with diaeresis */
+ { ISFUNC, rl_insert }, /* Multiplication sign */
+ { ISFUNC, rl_insert }, /* Latin capital letter o with stroke */
+ { ISFUNC, rl_insert }, /* Latin capital letter u with grave */
+ { ISFUNC, rl_insert }, /* Latin capital letter u with acute */
+ { ISFUNC, rl_insert }, /* Latin capital letter u with circumflex */
+ { ISFUNC, rl_insert }, /* Latin capital letter u with diaeresis */
+ { ISFUNC, rl_insert }, /* Latin capital letter Y with acute */
+ { ISFUNC, rl_insert }, /* Latin capital letter thorn (Icelandic) */
+ { ISFUNC, rl_insert }, /* Latin small letter sharp s (German) */
+ { ISFUNC, rl_insert }, /* Latin small letter a with grave */
+ { ISFUNC, rl_insert }, /* Latin small letter a with acute */
+ { ISFUNC, rl_insert }, /* Latin small letter a with circumflex */
+ { ISFUNC, rl_insert }, /* Latin small letter a with tilde */
+ { ISFUNC, rl_insert }, /* Latin small letter a with diaeresis */
+ { ISFUNC, rl_insert }, /* Latin small letter a with ring above */
+ { ISFUNC, rl_insert }, /* Latin small letter ae */
+ { ISFUNC, rl_insert }, /* Latin small letter c with cedilla */
+ { ISFUNC, rl_insert }, /* Latin small letter e with grave */
+ { ISFUNC, rl_insert }, /* Latin small letter e with acute */
+ { ISFUNC, rl_insert }, /* Latin small letter e with circumflex */
+ { ISFUNC, rl_insert }, /* Latin small letter e with diaeresis */
+ { ISFUNC, rl_insert }, /* Latin small letter i with grave */
+ { ISFUNC, rl_insert }, /* Latin small letter i with acute */
+ { ISFUNC, rl_insert }, /* Latin small letter i with circumflex */
+ { ISFUNC, rl_insert }, /* Latin small letter i with diaeresis */
+ { ISFUNC, rl_insert }, /* Latin small letter eth (Icelandic) */
+ { ISFUNC, rl_insert }, /* Latin small letter n with tilde */
+ { ISFUNC, rl_insert }, /* Latin small letter o with grave */
+ { ISFUNC, rl_insert }, /* Latin small letter o with acute */
+ { ISFUNC, rl_insert }, /* Latin small letter o with circumflex */
+ { ISFUNC, rl_insert }, /* Latin small letter o with tilde */
+ { ISFUNC, rl_insert }, /* Latin small letter o with diaeresis */
+ { ISFUNC, rl_insert }, /* Division sign */
+ { ISFUNC, rl_insert }, /* Latin small letter o with stroke */
+ { ISFUNC, rl_insert }, /* Latin small letter u with grave */
+ { ISFUNC, rl_insert }, /* Latin small letter u with acute */
+ { ISFUNC, rl_insert }, /* Latin small letter u with circumflex */
+ { ISFUNC, rl_insert }, /* Latin small letter u with diaeresis */
+ { ISFUNC, rl_insert }, /* Latin small letter y with acute */
+ { ISFUNC, rl_insert }, /* Latin small letter thorn (Icelandic) */
+ { ISFUNC, rl_insert } /* Latin small letter y with diaeresis */
+#endif /* KEYMAP_SIZE > 128 */
+};
+
+/* Unused for the time being. */
+#if 0
+KEYMAP_ENTRY_ARRAY vi_escape_keymap = {
+ /* The regular control keys come first. */
+ { ISFUNC, (Function *)0x0 }, /* Control-@ */
+ { ISFUNC, (Function *)0x0 }, /* Control-a */
+ { ISFUNC, (Function *)0x0 }, /* Control-b */
+ { ISFUNC, (Function *)0x0 }, /* Control-c */
+ { ISFUNC, (Function *)0x0 }, /* Control-d */
+ { ISFUNC, (Function *)0x0 }, /* Control-e */
+ { ISFUNC, (Function *)0x0 }, /* Control-f */
+ { ISFUNC, (Function *)0x0 }, /* Control-g */
+ { ISFUNC, (Function *)0x0 }, /* Control-h */
+ { ISFUNC, rl_tab_insert}, /* Control-i */
+ { ISFUNC, rl_emacs_editing_mode}, /* Control-j */
+ { ISFUNC, rl_kill_line }, /* Control-k */
+ { ISFUNC, (Function *)0x0 }, /* Control-l */
+ { ISFUNC, rl_emacs_editing_mode}, /* Control-m */
+ { ISFUNC, (Function *)0x0 }, /* Control-n */
+ { ISFUNC, (Function *)0x0 }, /* Control-o */
+ { ISFUNC, (Function *)0x0 }, /* Control-p */
+ { ISFUNC, (Function *)0x0 }, /* Control-q */
+ { ISFUNC, (Function *)0x0 }, /* Control-r */
+ { ISFUNC, (Function *)0x0 }, /* Control-s */
+ { ISFUNC, (Function *)0x0 }, /* Control-t */
+ { ISFUNC, (Function *)0x0 }, /* Control-u */
+ { ISFUNC, (Function *)0x0 }, /* Control-v */
+ { ISFUNC, (Function *)0x0 }, /* Control-w */
+ { ISFUNC, (Function *)0x0 }, /* Control-x */
+ { ISFUNC, (Function *)0x0 }, /* Control-y */
+ { ISFUNC, (Function *)0x0 }, /* Control-z */
+
+ { ISFUNC, rl_vi_movement_mode }, /* Control-[ */
+ { ISFUNC, (Function *)0x0 }, /* Control-\ */
+ { ISFUNC, (Function *)0x0 }, /* Control-] */
+ { ISFUNC, (Function *)0x0 }, /* Control-^ */
+ { ISFUNC, rl_vi_undo }, /* Control-_ */
+
+ /* The start of printing characters. */
+ { ISFUNC, (Function *)0x0 }, /* SPACE */
+ { ISFUNC, (Function *)0x0 }, /* ! */
+ { ISFUNC, (Function *)0x0 }, /* " */
+ { ISFUNC, (Function *)0x0 }, /* # */
+ { ISFUNC, (Function *)0x0 }, /* $ */
+ { ISFUNC, (Function *)0x0 }, /* % */
+ { ISFUNC, (Function *)0x0 }, /* & */
+ { ISFUNC, (Function *)0x0 }, /* ' */
+ { ISFUNC, (Function *)0x0 }, /* ( */
+ { ISFUNC, (Function *)0x0 }, /* ) */
+ { ISFUNC, (Function *)0x0 }, /* * */
+ { ISFUNC, (Function *)0x0 }, /* + */
+ { ISFUNC, (Function *)0x0 }, /* , */
+ { ISFUNC, (Function *)0x0 }, /* - */
+ { ISFUNC, (Function *)0x0 }, /* . */
+ { ISFUNC, (Function *)0x0 }, /* / */
+
+ /* Regular digits. */
+ { ISFUNC, rl_vi_arg_digit }, /* 0 */
+ { ISFUNC, rl_vi_arg_digit }, /* 1 */
+ { ISFUNC, rl_vi_arg_digit }, /* 2 */
+ { ISFUNC, rl_vi_arg_digit }, /* 3 */
+ { ISFUNC, rl_vi_arg_digit }, /* 4 */
+ { ISFUNC, rl_vi_arg_digit }, /* 5 */
+ { ISFUNC, rl_vi_arg_digit }, /* 6 */
+ { ISFUNC, rl_vi_arg_digit }, /* 7 */
+ { ISFUNC, rl_vi_arg_digit }, /* 8 */
+ { ISFUNC, rl_vi_arg_digit }, /* 9 */
+
+ /* A little more punctuation. */
+ { ISFUNC, (Function *)0x0 }, /* : */
+ { ISFUNC, (Function *)0x0 }, /* ; */
+ { ISFUNC, (Function *)0x0 }, /* < */
+ { ISFUNC, (Function *)0x0 }, /* = */
+ { ISFUNC, (Function *)0x0 }, /* > */
+ { ISFUNC, (Function *)0x0 }, /* ? */
+ { ISFUNC, (Function *)0x0 }, /* @ */
+
+ /* Uppercase alphabet. */
+ { ISFUNC, rl_do_lowercase_version }, /* A */
+ { ISFUNC, rl_do_lowercase_version }, /* B */
+ { ISFUNC, rl_do_lowercase_version }, /* C */
+ { ISFUNC, rl_do_lowercase_version }, /* D */
+ { ISFUNC, rl_do_lowercase_version }, /* E */
+ { ISFUNC, rl_do_lowercase_version }, /* F */
+ { ISFUNC, rl_do_lowercase_version }, /* G */
+ { ISFUNC, rl_do_lowercase_version }, /* H */
+ { ISFUNC, rl_do_lowercase_version }, /* I */
+ { ISFUNC, rl_do_lowercase_version }, /* J */
+ { ISFUNC, rl_do_lowercase_version }, /* K */
+ { ISFUNC, rl_do_lowercase_version }, /* L */
+ { ISFUNC, rl_do_lowercase_version }, /* M */
+ { ISFUNC, rl_do_lowercase_version }, /* N */
+ { ISFUNC, rl_do_lowercase_version }, /* O */
+ { ISFUNC, rl_do_lowercase_version }, /* P */
+ { ISFUNC, rl_do_lowercase_version }, /* Q */
+ { ISFUNC, rl_do_lowercase_version }, /* R */
+ { ISFUNC, rl_do_lowercase_version }, /* S */
+ { ISFUNC, rl_do_lowercase_version }, /* T */
+ { ISFUNC, rl_do_lowercase_version }, /* U */
+ { ISFUNC, rl_do_lowercase_version }, /* V */
+ { ISFUNC, rl_do_lowercase_version }, /* W */
+ { ISFUNC, rl_do_lowercase_version }, /* X */
+ { ISFUNC, rl_do_lowercase_version }, /* Y */
+ { ISFUNC, rl_do_lowercase_version }, /* Z */
+
+ /* Some more punctuation. */
+ { ISFUNC, rl_arrow_keys }, /* [ */
+ { ISFUNC, (Function *)0x0 }, /* \ */
+ { ISFUNC, (Function *)0x0 }, /* ] */
+ { ISFUNC, (Function *)0x0 }, /* ^ */
+ { ISFUNC, (Function *)0x0 }, /* _ */
+ { ISFUNC, (Function *)0x0 }, /* ` */
+
+ /* Lowercase alphabet. */
+ { ISFUNC, (Function *)0x0 }, /* a */
+ { ISFUNC, (Function *)0x0 }, /* b */
+ { ISFUNC, (Function *)0x0 }, /* c */
+ { ISFUNC, (Function *)0x0 }, /* d */
+ { ISFUNC, (Function *)0x0 }, /* e */
+ { ISFUNC, (Function *)0x0 }, /* f */
+ { ISFUNC, (Function *)0x0 }, /* g */
+ { ISFUNC, (Function *)0x0 }, /* h */
+ { ISFUNC, (Function *)0x0 }, /* i */
+ { ISFUNC, (Function *)0x0 }, /* j */
+ { ISFUNC, (Function *)0x0 }, /* k */
+ { ISFUNC, (Function *)0x0 }, /* l */
+ { ISFUNC, (Function *)0x0 }, /* m */
+ { ISFUNC, (Function *)0x0 }, /* n */
+ { ISFUNC, rl_arrow_keys }, /* o */
+ { ISFUNC, (Function *)0x0 }, /* p */
+ { ISFUNC, (Function *)0x0 }, /* q */
+ { ISFUNC, (Function *)0x0 }, /* r */
+ { ISFUNC, (Function *)0x0 }, /* s */
+ { ISFUNC, (Function *)0x0 }, /* t */
+ { ISFUNC, (Function *)0x0 }, /* u */
+ { ISFUNC, (Function *)0x0 }, /* v */
+ { ISFUNC, (Function *)0x0 }, /* w */
+ { ISFUNC, (Function *)0x0 }, /* x */
+ { ISFUNC, (Function *)0x0 }, /* y */
+ { ISFUNC, (Function *)0x0 }, /* z */
+
+ /* Final punctuation. */
+ { ISFUNC, (Function *)0x0 }, /* { */
+ { ISFUNC, (Function *)0x0 }, /* | */
+ { ISFUNC, (Function *)0x0 }, /* } */
+ { ISFUNC, (Function *)0x0 }, /* ~ */
+ { ISFUNC, rl_backward_kill_word }, /* RUBOUT */
+
+#if KEYMAP_SIZE > 128
+ /* Undefined keys. */
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 },
+ { ISFUNC, (Function *)0x0 }
+#endif /* KEYMAP_SIZE > 128 */
+};
+#endif
diff --git a/readline/vi_mode.c b/readline/vi_mode.c
new file mode 100644
index 00000000000..d4868bf3b13
--- /dev/null
+++ b/readline/vi_mode.c
@@ -0,0 +1,1385 @@
+/* vi_mode.c -- A vi emulation mode for Bash.
+ Derived from code written by Jeff Sparkes (jsparkes@bnr.ca). */
+
+/* Copyright (C) 1987, 1989, 1992 Free Software Foundation, Inc.
+
+ This file is part of the GNU Readline Library, a library for
+ reading lines of text with interactive input and history editing.
+
+ The GNU Readline Library is free software; you can redistribute it
+ and/or modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 1, or
+ (at your option) any later version.
+
+ The GNU Readline 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 General Public License for more details.
+
+ The GNU General Public License is often shipped with GNU software, and
+ is generally kept in a file called COPYING or LICENSE. If you do not
+ have a copy of the license, write to the Free Software Foundation,
+ 675 Mass Ave, Cambridge, MA 02139, USA. */
+#define READLINE_LIBRARY
+
+/* **************************************************************** */
+/* */
+/* VI Emulation Mode */
+/* */
+/* **************************************************************** */
+#include "rlconf.h"
+
+#if defined (VI_MODE)
+
+#if defined (HAVE_CONFIG_H)
+# include <config.h>
+#endif
+
+#include <sys/types.h>
+
+#if defined (HAVE_STDLIB_H)
+# include <stdlib.h>
+#else
+# include "ansi_stdlib.h"
+#endif /* HAVE_STDLIB_H */
+
+#if defined (HAVE_UNISTD_H)
+# include <unistd.h>
+#endif
+
+#include <stdio.h>
+
+/* Some standard library routines. */
+#include "rldefs.h"
+#include "readline.h"
+#include "history.h"
+
+#ifndef _rl_digit_p
+#define _rl_digit_p(c) ((c) >= '0' && (c) <= '9')
+#endif
+
+#ifndef _rl_digit_value
+#define _rl_digit_value(c) ((c) - '0')
+#endif
+
+#ifndef member
+#define member(c, s) ((c) ? (char *)strchr ((s), (c)) != (char *)NULL : 0)
+#endif
+
+#ifndef isident
+#define isident(c) ((_rl_pure_alphabetic (c) || _rl_digit_p (c) || c == '_'))
+#endif
+
+#ifndef exchange
+#define exchange(x, y) do {int temp = x; x = y; y = temp;} while (0)
+#endif
+
+extern char *xmalloc (), *xrealloc ();
+
+/* Variables imported from readline.c */
+extern int rl_point, rl_end, rl_mark;
+extern FILE *rl_instream;
+extern int rl_line_buffer_len, rl_explicit_arg, rl_numeric_arg;
+extern Keymap _rl_keymap;
+extern char *rl_prompt;
+extern char *rl_line_buffer;
+extern int rl_arg_sign;
+
+extern int _rl_doing_an_undo;
+extern int _rl_undo_group_level;
+
+extern void _rl_dispatch ();
+extern int _rl_char_search_internal ();
+
+extern void rl_extend_line_buffer ();
+extern int rl_vi_check ();
+
+/* Non-zero means enter insertion mode. */
+static int _rl_vi_doing_insert;
+
+/* Command keys which do movement for xxx_to commands. */
+static char *vi_motion = " hl^$0ftFt;,%wbeWBE|";
+
+/* Keymap used for vi replace characters. Created dynamically since
+ rarely used. */
+static Keymap vi_replace_map;
+
+/* The number of characters inserted in the last replace operation. */
+static int vi_replace_count;
+
+/* If non-zero, we have text inserted after a c[motion] command that put
+ us implicitly into insert mode. Some people want this text to be
+ attached to the command so that it is `redoable' with `.'. */
+static int vi_continued_command;
+static char *vi_insert_buffer;
+static int vi_insert_buffer_size;
+
+static int _rl_vi_last_command = 'i'; /* default `.' puts you in insert mode */
+static int _rl_vi_last_repeat = 1;
+static int _rl_vi_last_arg_sign = 1;
+static int _rl_vi_last_motion;
+static int _rl_vi_last_search_char;
+static int _rl_vi_last_replacement;
+
+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~";
+
+/* Arrays for the saved marks. */
+static int vi_mark_chars[27];
+
+static int rl_digit_loop1 ();
+
+void
+_rl_vi_initialize_line ()
+{
+ register int i;
+
+ for (i = 0; i < sizeof (vi_mark_chars) / sizeof (int); i++)
+ vi_mark_chars[i] = -1;
+}
+
+void
+_rl_vi_reset_last ()
+{
+ _rl_vi_last_command = 'i';
+ _rl_vi_last_repeat = 1;
+ _rl_vi_last_arg_sign = 1;
+ _rl_vi_last_motion = 0;
+}
+
+void
+_rl_vi_set_last (key, repeat, sign)
+ int key, repeat, sign;
+{
+ _rl_vi_last_command = key;
+ _rl_vi_last_repeat = repeat;
+ _rl_vi_last_arg_sign = sign;
+}
+
+/* Is the command C a VI mode text modification command? */
+int
+_rl_vi_textmod_command (c)
+ int c;
+{
+ return (member (c, vi_textmod));
+}
+
+static void
+_rl_vi_stuff_insert (count)
+ int count;
+{
+ rl_begin_undo_group ();
+ while (count--)
+ rl_insert_text (vi_insert_buffer);
+ rl_end_undo_group ();
+}
+
+/* Bound to `.'. Called from command mode, so we know that we have to
+ redo a text modification command. The default for _rl_vi_last_command
+ puts you back into insert mode. */
+int
+rl_vi_redo (count, c)
+ int count, c;
+{
+ if (!rl_explicit_arg)
+ {
+ rl_numeric_arg = _rl_vi_last_repeat;
+ rl_arg_sign = _rl_vi_last_arg_sign;
+ }
+
+ vi_redoing = 1;
+ /* If we're redoing an insert with `i', stuff in the inserted text
+ and do not go into insertion mode. */
+ if (_rl_vi_last_command == 'i' && vi_insert_buffer && *vi_insert_buffer)
+ {
+ _rl_vi_stuff_insert (count);
+ /* And back up point over the last character inserted. */
+ if (rl_point > 0)
+ rl_point--;
+ }
+ else
+ _rl_dispatch (_rl_vi_last_command, _rl_keymap);
+ vi_redoing = 0;
+
+ return (0);
+}
+
+/* A placeholder for further expansion. */
+int
+rl_vi_undo (count, key)
+ int 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;
+{
+ /* 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. */
+ if (rl_explicit_arg)
+ rl_yank_nth_arg (count - 1, 0);
+ else
+ rl_yank_nth_arg ('$', 0);
+
+ return (0);
+}
+
+/* With an argument, move back that many history lines, else move to the
+ beginning of history. */
+int
+rl_vi_fetch_history (count, c)
+ int count, c;
+{
+ int wanted;
+
+ /* Giving an argument of n means we want the nth command in the history
+ file. The command number is interpreted the same way that the bash
+ `history' command does it -- that is, giving an argument count of 450
+ to this command would get the command listed as number 450 in the
+ output of `history'. */
+ if (rl_explicit_arg)
+ {
+ wanted = history_base + where_history () - count;
+ if (wanted <= 0)
+ rl_beginning_of_history (0, 0);
+ else
+ rl_get_previous_history (wanted, c);
+ }
+ else
+ rl_beginning_of_history (count, 0);
+ return (0);
+}
+
+/* Search again for the last thing searched for. */
+int
+rl_vi_search_again (count, key)
+ int count, key;
+{
+ switch (key)
+ {
+ case 'n':
+ rl_noninc_reverse_search_again (count, key);
+ break;
+
+ case 'N':
+ rl_noninc_forward_search_again (count, key);
+ break;
+ }
+ return (0);
+}
+
+/* Do a vi style search. */
+int
+rl_vi_search (count, key)
+ int count, key;
+{
+ switch (key)
+ {
+ case '?':
+ rl_noninc_forward_search (count, key);
+ break;
+
+ case '/':
+ rl_noninc_reverse_search (count, key);
+ break;
+
+ default:
+ ding ();
+ break;
+ }
+ return (0);
+}
+
+/* Completion, from vi's point of view. */
+int
+rl_vi_complete (ignore, key)
+ int ignore, key;
+{
+ if ((rl_point < rl_end) && (!whitespace (rl_line_buffer[rl_point])))
+ {
+ if (!whitespace (rl_line_buffer[rl_point + 1]))
+ rl_vi_end_word (1, 'E');
+ rl_point++;
+ }
+
+ if (key == '*')
+ rl_complete_internal ('*'); /* Expansion and replacement. */
+ else if (key == '=')
+ rl_complete_internal ('?'); /* List possible completions. */
+ else if (key == '\\')
+ rl_complete_internal (TAB); /* Standard Readline completion. */
+ else
+ rl_complete (0, key);
+
+ if (key == '*' || key == '\\')
+ {
+ _rl_vi_set_last (key, 1, rl_arg_sign);
+ rl_vi_insertion_mode (1, key);
+ }
+ return (0);
+}
+
+/* Tilde expansion for vi mode. */
+int
+rl_vi_tilde_expand (ignore, key)
+ int ignore, key;
+{
+ rl_tilde_expand (0, key);
+ _rl_vi_set_last (key, 1, rl_arg_sign); /* XXX */
+ rl_vi_insertion_mode (1, key);
+ return (0);
+}
+
+/* Previous word in vi mode. */
+int
+rl_vi_prev_word (count, key)
+ int count, key;
+{
+ if (count < 0)
+ return (rl_vi_next_word (-count, key));
+
+ if (rl_point == 0)
+ {
+ ding ();
+ return (0);
+ }
+
+ if (_rl_uppercase_p (key))
+ rl_vi_bWord (count, key);
+ else
+ rl_vi_bword (count, key);
+
+ return (0);
+}
+
+/* Next word in vi mode. */
+int
+rl_vi_next_word (count, key)
+ int count, key;
+{
+ if (count < 0)
+ return (rl_vi_prev_word (-count, key));
+
+ if (rl_point >= (rl_end - 1))
+ {
+ ding ();
+ return (0);
+ }
+
+ if (_rl_uppercase_p (key))
+ rl_vi_fWord (count, key);
+ else
+ rl_vi_fword (count, key);
+ return (0);
+}
+
+/* Move to the end of the ?next? word. */
+int
+rl_vi_end_word (count, key)
+ int count, key;
+{
+ if (count < 0)
+ {
+ ding ();
+ return -1;
+ }
+
+ if (_rl_uppercase_p (key))
+ rl_vi_eWord (count, key);
+ else
+ rl_vi_eword (count, key);
+ return (0);
+}
+
+/* Move forward a word the way that 'W' does. */
+int
+rl_vi_fWord (count, ignore)
+ int count, ignore;
+{
+ while (count-- && rl_point < (rl_end - 1))
+ {
+ /* Skip until whitespace. */
+ while (!whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end)
+ rl_point++;
+
+ /* Now skip whitespace. */
+ while (whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end)
+ rl_point++;
+ }
+ return (0);
+}
+
+int
+rl_vi_bWord (count, ignore)
+ int count, ignore;
+{
+ while (count-- && rl_point > 0)
+ {
+ /* If we are at the start of a word, move back to whitespace so
+ we will go back to the start of the previous word. */
+ if (!whitespace (rl_line_buffer[rl_point]) &&
+ whitespace (rl_line_buffer[rl_point - 1]))
+ rl_point--;
+
+ while (rl_point > 0 && whitespace (rl_line_buffer[rl_point]))
+ rl_point--;
+
+ if (rl_point > 0)
+ {
+ while (--rl_point >= 0 && !whitespace (rl_line_buffer[rl_point]));
+ rl_point++;
+ }
+ }
+ return (0);
+}
+
+int
+rl_vi_eWord (count, ignore)
+ int count, ignore;
+{
+ while (count-- && rl_point < (rl_end - 1))
+ {
+ if (!whitespace (rl_line_buffer[rl_point]))
+ rl_point++;
+
+ /* Move to the next non-whitespace character (to the start of the
+ next word). */
+ while (++rl_point < rl_end && whitespace (rl_line_buffer[rl_point]));
+
+ if (rl_point && rl_point < rl_end)
+ {
+ /* Skip whitespace. */
+ while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point]))
+ rl_point++;
+
+ /* Skip until whitespace. */
+ while (rl_point < rl_end && !whitespace (rl_line_buffer[rl_point]))
+ rl_point++;
+
+ /* Move back to the last character of the word. */
+ rl_point--;
+ }
+ }
+ return (0);
+}
+
+int
+rl_vi_fword (count, ignore)
+ int count, ignore;
+{
+ while (count-- && rl_point < (rl_end - 1))
+ {
+ /* Move to white space (really non-identifer). */
+ if (isident (rl_line_buffer[rl_point]))
+ {
+ while (isident (rl_line_buffer[rl_point]) && rl_point < rl_end)
+ rl_point++;
+ }
+ else /* if (!whitespace (rl_line_buffer[rl_point])) */
+ {
+ while (!isident (rl_line_buffer[rl_point]) &&
+ !whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end)
+ rl_point++;
+ }
+
+ /* Move past whitespace. */
+ while (whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end)
+ rl_point++;
+ }
+ return (0);
+}
+
+int
+rl_vi_bword (count, ignore)
+ int count, ignore;
+{
+ while (count-- && rl_point > 0)
+ {
+ int last_is_ident;
+
+ /* If we are at the start of a word, move back to whitespace
+ so we will go back to the start of the previous word. */
+ if (!whitespace (rl_line_buffer[rl_point]) &&
+ whitespace (rl_line_buffer[rl_point - 1]))
+ rl_point--;
+
+ /* If this character and the previous character are `opposite', move
+ back so we don't get messed up by the rl_point++ down there in
+ the while loop. Without this code, words like `l;' screw up the
+ function. */
+ last_is_ident = isident (rl_line_buffer[rl_point - 1]);
+ if ((isident (rl_line_buffer[rl_point]) && !last_is_ident) ||
+ (!isident (rl_line_buffer[rl_point]) && last_is_ident))
+ rl_point--;
+
+ while (rl_point > 0 && whitespace (rl_line_buffer[rl_point]))
+ rl_point--;
+
+ if (rl_point > 0)
+ {
+ if (isident (rl_line_buffer[rl_point]))
+ while (--rl_point >= 0 && isident (rl_line_buffer[rl_point]));
+ else
+ while (--rl_point >= 0 && !isident (rl_line_buffer[rl_point]) &&
+ !whitespace (rl_line_buffer[rl_point]));
+ rl_point++;
+ }
+ }
+ return (0);
+}
+
+int
+rl_vi_eword (count, ignore)
+ int count, ignore;
+{
+ while (count-- && rl_point < rl_end - 1)
+ {
+ if (!whitespace (rl_line_buffer[rl_point]))
+ rl_point++;
+
+ while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point]))
+ rl_point++;
+
+ if (rl_point < rl_end)
+ {
+ if (isident (rl_line_buffer[rl_point]))
+ while (++rl_point < rl_end && isident (rl_line_buffer[rl_point]));
+ else
+ while (++rl_point < rl_end && !isident (rl_line_buffer[rl_point])
+ && !whitespace (rl_line_buffer[rl_point]));
+ }
+ rl_point--;
+ }
+ return (0);
+}
+
+int
+rl_vi_insert_beg (count, key)
+ int count, key;
+{
+ rl_beg_of_line (1, key);
+ rl_vi_insertion_mode (1, key);
+ return (0);
+}
+
+int
+rl_vi_append_mode (count, key)
+ int count, key;
+{
+ if (rl_point < rl_end)
+ rl_point++;
+ rl_vi_insertion_mode (1, key);
+ return (0);
+}
+
+int
+rl_vi_append_eol (count, key)
+ int count, key;
+{
+ rl_end_of_line (1, key);
+ rl_vi_append_mode (1, key);
+ return (0);
+}
+
+/* What to do in the case of C-d. */
+int
+rl_vi_eof_maybe (count, c)
+ int count, c;
+{
+ return (rl_newline (1, '\n'));
+}
+
+/* Insertion mode stuff. */
+
+/* Switching from one mode to the other really just involves
+ switching keymaps. */
+int
+rl_vi_insertion_mode (count, key)
+ int count, key;
+{
+ _rl_keymap = vi_insertion_keymap;
+ _rl_vi_last_key_before_insert = key;
+ return (0);
+}
+
+static void
+_rl_vi_save_insert (up)
+ UNDO_LIST *up;
+{
+ int len, start, end;
+
+ if (up == 0)
+ {
+ if (vi_insert_buffer_size >= 1)
+ vi_insert_buffer[0] = '\0';
+ return;
+ }
+
+ start = up->start;
+ end = up->end;
+ len = end - start + 1;
+ if (len >= vi_insert_buffer_size)
+ {
+ vi_insert_buffer_size += (len + 32) - (len % 32);
+ vi_insert_buffer = xrealloc (vi_insert_buffer, vi_insert_buffer_size);
+ }
+ strncpy (vi_insert_buffer, rl_line_buffer + start, len - 1);
+ vi_insert_buffer[len-1] = '\0';
+}
+
+void
+_rl_vi_done_inserting ()
+{
+ if (_rl_vi_doing_insert)
+ {
+ rl_end_undo_group ();
+ /* Now, the text between rl_undo_list->next->start and
+ rl_undo_list->next->end is what was inserted while in insert
+ mode. It gets copied to VI_INSERT_BUFFER because it depends
+ on absolute indices into the line which may change (though they
+ probably will not). */
+ _rl_vi_doing_insert = 0;
+ _rl_vi_save_insert (rl_undo_list->next);
+ vi_continued_command = 1;
+ }
+ else
+ {
+ if (_rl_vi_last_key_before_insert == 'i' && rl_undo_list)
+ _rl_vi_save_insert (rl_undo_list);
+ /* XXX - Other keys probably need to be checked. */
+ else if (_rl_vi_last_key_before_insert == 'C')
+ rl_end_undo_group ();
+ while (_rl_undo_group_level > 0)
+ rl_end_undo_group ();
+ vi_continued_command = 0;
+ }
+}
+
+int
+rl_vi_movement_mode (count, key)
+ int count, key;
+{
+ if (rl_point > 0)
+ rl_backward (1, key);
+
+ _rl_keymap = vi_movement_keymap;
+ _rl_vi_done_inserting ();
+ return (0);
+}
+
+int
+rl_vi_arg_digit (count, c)
+ int count, c;
+{
+ if (c == '0' && rl_numeric_arg == 1 && !rl_explicit_arg)
+ return (rl_beg_of_line (1, c));
+ else
+ return (rl_digit_argument (count, c));
+}
+
+int
+rl_vi_change_case (count, ignore)
+ int count, ignore;
+{
+ char c = 0;
+
+ /* Don't try this on an empty line. */
+ if (rl_point >= rl_end)
+ return (0);
+
+ while (count-- && rl_point < rl_end)
+ {
+ if (_rl_uppercase_p (rl_line_buffer[rl_point]))
+ c = _rl_to_lower (rl_line_buffer[rl_point]);
+ else if (_rl_lowercase_p (rl_line_buffer[rl_point]))
+ c = _rl_to_upper (rl_line_buffer[rl_point]);
+ else
+ {
+ /* Just skip over characters neither upper nor lower case. */
+ rl_forward (1, c);
+ continue;
+ }
+
+ /* Vi is kind of strange here. */
+ if (c)
+ {
+ rl_begin_undo_group ();
+ rl_delete (1, c);
+ rl_insert (1, c);
+ rl_end_undo_group ();
+ rl_vi_check ();
+ }
+ else
+ rl_forward (1, c);
+ }
+ return (0);
+}
+
+int
+rl_vi_put (count, key)
+ int count, key;
+{
+ if (!_rl_uppercase_p (key) && (rl_point + 1 <= rl_end))
+ rl_point++;
+
+ rl_yank (1, key);
+ rl_backward (1, key);
+ return (0);
+}
+
+int
+rl_vi_check ()
+{
+ if (rl_point && rl_point == rl_end)
+ rl_point--;
+ return (0);
+}
+
+int
+rl_vi_column (count, key)
+ int count, key;
+{
+ if (count > rl_end)
+ rl_end_of_line (1, key);
+ else
+ rl_point = count - 1;
+ return (0);
+}
+
+int
+rl_vi_domove (key, nextkey)
+ int key, *nextkey;
+{
+ int c, save;
+ int old_end;
+
+ rl_mark = rl_point;
+ c = rl_read_key ();
+ *nextkey = c;
+
+ if (!member (c, vi_motion))
+ {
+ if (_rl_digit_p (c))
+ {
+ save = rl_numeric_arg;
+ rl_numeric_arg = _rl_digit_value (c);
+ rl_digit_loop1 ();
+ rl_numeric_arg *= save;
+ c = rl_read_key (); /* real command */
+ *nextkey = c;
+ }
+ else if (key == c && (key == 'd' || key == 'y' || key == 'c'))
+ {
+ rl_mark = rl_end;
+ rl_beg_of_line (1, c);
+ _rl_vi_last_motion = c;
+ return (0);
+ }
+ else
+ return (-1);
+ }
+
+ _rl_vi_last_motion = c;
+
+ /* Append a blank character temporarily so that the motion routines
+ work right at the end of the line. */
+ old_end = rl_end;
+ rl_line_buffer[rl_end++] = ' ';
+ rl_line_buffer[rl_end] = '\0';
+
+ _rl_dispatch (c, _rl_keymap);
+
+ /* Remove the blank that we added. */
+ rl_end = old_end;
+ rl_line_buffer[rl_end] = '\0';
+ if (rl_point > rl_end)
+ rl_point = rl_end;
+
+ /* No change in position means the command failed. */
+ if (rl_mark == rl_point)
+ return (-1);
+
+ /* rl_vi_f[wW]ord () leaves the cursor on the first character of the next
+ word. If we are not at the end of the line, and we are on a
+ non-whitespace character, move back one (presumably to whitespace). */
+ if ((_rl_to_upper (c) == 'W') && rl_point < rl_end && rl_point > rl_mark &&
+ !whitespace (rl_line_buffer[rl_point]))
+ rl_point--;
+
+ /* If cw or cW, back up to the end of a word, so the behaviour of ce
+ or cE is the actual result. Brute-force, no subtlety. */
+ if (key == 'c' && rl_point >= rl_mark && (_rl_to_upper (c) == 'W'))
+ {
+ /* Don't move farther back than where we started. */
+ while (rl_point > rl_mark && whitespace (rl_line_buffer[rl_point]))
+ rl_point--;
+
+ /* Posix.2 says that if cw or cW moves the cursor towards the end of
+ the line, the character under the cursor should be deleted. */
+ if (rl_point == rl_mark)
+ rl_point++;
+ else
+ {
+ /* Move past the end of the word so that the kill doesn't
+ remove the last letter of the previous word. Only do this
+ if we are not at the end of the line. */
+ if (rl_point >= 0 && rl_point < (rl_end - 1) && !whitespace (rl_line_buffer[rl_point]))
+ rl_point++;
+ }
+ }
+
+ if (rl_mark < rl_point)
+ exchange (rl_point, rl_mark);
+
+ return (0);
+}
+
+/* A simplified loop for vi. Don't dispatch key at end.
+ Don't recognize minus sign? */
+static int
+rl_digit_loop1 ()
+{
+ int key, c;
+
+ while (1)
+ {
+ rl_message ("(arg: %d) ", rl_arg_sign * rl_numeric_arg, 0);
+ key = c = rl_read_key ();
+
+ if (_rl_keymap[c].type == ISFUNC &&
+ _rl_keymap[c].function == rl_universal_argument)
+ {
+ rl_numeric_arg *= 4;
+ continue;
+ }
+
+ c = UNMETA (c);
+ if (_rl_digit_p (c))
+ {
+ if (rl_explicit_arg)
+ rl_numeric_arg = (rl_numeric_arg * 10) + _rl_digit_value (c);
+ else
+ rl_numeric_arg = _rl_digit_value (c);
+ rl_explicit_arg = 1;
+ }
+ else
+ {
+ rl_clear_message ();
+ rl_stuff_char (key);
+ break;
+ }
+ }
+ return (0);
+}
+
+int
+rl_vi_delete_to (count, key)
+ int count, key;
+{
+ int c;
+
+ if (_rl_uppercase_p (key))
+ rl_stuff_char ('$');
+ else if (vi_redoing)
+ rl_stuff_char (_rl_vi_last_motion);
+
+ if (rl_vi_domove (key, &c))
+ {
+ ding ();
+ return -1;
+ }
+
+ /* These are the motion commands that do not require adjusting the
+ mark. */
+ if ((strchr (" l|h^0bB", c) == 0) && (rl_mark < rl_end))
+ rl_mark++;
+
+ rl_kill_text (rl_point, rl_mark);
+ return (0);
+}
+
+int
+rl_vi_change_to (count, key)
+ int count, key;
+{
+ int c, start_pos;
+
+ if (_rl_uppercase_p (key))
+ rl_stuff_char ('$');
+ else if (vi_redoing)
+ rl_stuff_char (_rl_vi_last_motion);
+
+ start_pos = rl_point;
+
+ if (rl_vi_domove (key, &c))
+ {
+ ding ();
+ return -1;
+ }
+
+ /* These are the motion commands that do not require adjusting the
+ mark. c[wW] are handled by special-case code in rl_vi_domove(),
+ and already leave the mark at the correct location. */
+ if ((strchr (" l|hwW^0bB", c) == 0) && (rl_mark < rl_end))
+ rl_mark++;
+
+ /* The cursor never moves with c[wW]. */
+ if ((_rl_to_upper (c) == 'W') && rl_point < start_pos)
+ rl_point = start_pos;
+
+ if (vi_redoing)
+ {
+ if (vi_insert_buffer && *vi_insert_buffer)
+ rl_begin_undo_group ();
+ rl_delete_text (rl_point, rl_mark);
+ if (vi_insert_buffer && *vi_insert_buffer)
+ {
+ rl_insert_text (vi_insert_buffer);
+ rl_end_undo_group ();
+ }
+ }
+ else
+ {
+ rl_begin_undo_group (); /* to make the `u' command work */
+ rl_kill_text (rl_point, rl_mark);
+ /* `C' does not save the text inserted for undoing or redoing. */
+ if (_rl_uppercase_p (key) == 0)
+ _rl_vi_doing_insert = 1;
+ _rl_vi_set_last (key, count, rl_arg_sign);
+ rl_vi_insertion_mode (1, key);
+ }
+
+ return (0);
+}
+
+int
+rl_vi_yank_to (count, key)
+ int count, key;
+{
+ int c, save = rl_point;
+
+ if (_rl_uppercase_p (key))
+ rl_stuff_char ('$');
+
+ if (rl_vi_domove (key, &c))
+ {
+ ding ();
+ return -1;
+ }
+
+ /* These are the motion commands that do not require adjusting the
+ mark. */
+ if ((strchr (" l|h^0%bB", c) == 0) && (rl_mark < rl_end))
+ rl_mark++;
+
+ rl_begin_undo_group ();
+ rl_kill_text (rl_point, rl_mark);
+ rl_end_undo_group ();
+ rl_do_undo ();
+ rl_point = save;
+
+ return (0);
+}
+
+int
+rl_vi_delete (count, key)
+ int count, key;
+{
+ int end;
+
+ if (rl_end == 0)
+ {
+ ding ();
+ return -1;
+ }
+
+ end = rl_point + count;
+
+ if (end >= rl_end)
+ end = rl_end;
+
+ rl_kill_text (rl_point, end);
+
+ if (rl_point > 0 && rl_point == rl_end)
+ rl_backward (1, key);
+ return (0);
+}
+
+int
+rl_vi_back_to_indent (count, key)
+ int count, key;
+{
+ rl_beg_of_line (1, key);
+ while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point]))
+ rl_point++;
+ return (0);
+}
+
+int
+rl_vi_first_print (count, key)
+ int count, key;
+{
+ return (rl_vi_back_to_indent (1, key));
+}
+
+int
+rl_vi_char_search (count, key)
+ int count, key;
+{
+ static char target;
+ static int orig_dir, dir;
+
+ if (key == ';' || key == ',')
+ dir = key == ';' ? orig_dir : -orig_dir;
+ else
+ {
+ if (vi_redoing)
+ target = _rl_vi_last_search_char;
+ else
+ _rl_vi_last_search_char = target = rl_getc (rl_instream);
+
+ switch (key)
+ {
+ case 't':
+ orig_dir = dir = FTO;
+ break;
+
+ case 'T':
+ orig_dir = dir = BTO;
+ break;
+
+ case 'f':
+ orig_dir = dir = FFIND;
+ break;
+
+ case 'F':
+ orig_dir = dir = BFIND;
+ break;
+ }
+ }
+
+ return (_rl_char_search_internal (count, dir, target));
+}
+
+/* Match brackets */
+int
+rl_vi_match (ignore, key)
+ int ignore, key;
+{
+ int count = 1, brack, pos;
+
+ pos = rl_point;
+ if ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0)
+ {
+ while ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0 &&
+ rl_point < rl_end - 1)
+ rl_forward (1, key);
+
+ if (brack <= 0)
+ {
+ rl_point = pos;
+ ding ();
+ return -1;
+ }
+ }
+
+ pos = rl_point;
+
+ if (brack < 0)
+ {
+ while (count)
+ {
+ if (--pos >= 0)
+ {
+ int b = rl_vi_bracktype (rl_line_buffer[pos]);
+ if (b == -brack)
+ count--;
+ else if (b == brack)
+ count++;
+ }
+ else
+ {
+ ding ();
+ return -1;
+ }
+ }
+ }
+ else
+ { /* brack > 0 */
+ while (count)
+ {
+ if (++pos < rl_end)
+ {
+ int b = rl_vi_bracktype (rl_line_buffer[pos]);
+ if (b == -brack)
+ count--;
+ else if (b == brack)
+ count++;
+ }
+ else
+ {
+ ding ();
+ return -1;
+ }
+ }
+ }
+ rl_point = pos;
+ return (0);
+}
+
+int
+rl_vi_bracktype (c)
+ int c;
+{
+ switch (c)
+ {
+ case '(': return 1;
+ case ')': return -1;
+ case '[': return 2;
+ case ']': return -2;
+ case '{': return 3;
+ case '}': return -3;
+ default: return 0;
+ }
+}
+
+int
+rl_vi_change_char (count, key)
+ int count, key;
+{
+ int c;
+
+ if (vi_redoing)
+ c = _rl_vi_last_replacement;
+ else
+ _rl_vi_last_replacement = c = rl_getc (rl_instream);
+
+ if (c == '\033' || c == CTRL ('C'))
+ return -1;
+
+ while (count-- && rl_point < rl_end)
+ {
+ rl_begin_undo_group ();
+
+ rl_delete (1, c);
+ rl_insert (1, c);
+ if (count == 0)
+ rl_backward (1, c);
+
+ rl_end_undo_group ();
+ }
+ return (0);
+}
+
+int
+rl_vi_subst (count, key)
+ int count, key;
+{
+ rl_begin_undo_group ();
+
+ if (_rl_uppercase_p (key))
+ {
+ rl_beg_of_line (1, key);
+ rl_kill_line (1, key);
+ }
+ else
+ rl_delete_text (rl_point, rl_point+count);
+
+ rl_end_undo_group ();
+
+ _rl_vi_set_last (key, count, rl_arg_sign);
+
+ if (vi_redoing)
+ {
+ int o = _rl_doing_an_undo;
+
+ _rl_doing_an_undo = 1;
+ if (vi_insert_buffer && *vi_insert_buffer)
+ rl_insert_text (vi_insert_buffer);
+ _rl_doing_an_undo = o;
+ }
+ else
+ {
+ rl_begin_undo_group ();
+ _rl_vi_doing_insert = 1;
+ rl_vi_insertion_mode (1, key);
+ }
+
+ return (0);
+}
+
+int
+rl_vi_overstrike (count, key)
+ int count, key;
+{
+ int i;
+
+ if (_rl_vi_doing_insert == 0)
+ {
+ _rl_vi_doing_insert = 1;
+ rl_begin_undo_group ();
+ }
+
+ for (i = 0; i < count; i++)
+ {
+ vi_replace_count++;
+ rl_begin_undo_group ();
+
+ if (rl_point < rl_end)
+ {
+ rl_delete (1, key);
+ rl_insert (1, key);
+ }
+ else
+ rl_insert (1, key);
+
+ rl_end_undo_group ();
+ }
+ return (0);
+}
+
+int
+rl_vi_overstrike_delete (count, key)
+ int count, key;
+{
+ int i, s;
+
+ for (i = 0; i < count; i++)
+ {
+ if (vi_replace_count == 0)
+ {
+ ding ();
+ break;
+ }
+ s = rl_point;
+
+ if (rl_do_undo ())
+ vi_replace_count--;
+
+ if (rl_point == s)
+ rl_backward (1, key);
+ }
+
+ if (vi_replace_count == 0 && _rl_vi_doing_insert)
+ {
+ rl_end_undo_group ();
+ rl_do_undo ();
+ _rl_vi_doing_insert = 0;
+ }
+ return (0);
+}
+
+int
+rl_vi_replace (count, key)
+ int count, key;
+{
+ int i;
+
+ vi_replace_count = 0;
+
+ if (!vi_replace_map)
+ {
+ vi_replace_map = rl_make_bare_keymap ();
+
+ for (i = ' '; i < KEYMAP_SIZE; i++)
+ vi_replace_map[i].function = rl_vi_overstrike;
+
+ vi_replace_map[RUBOUT].function = rl_vi_overstrike_delete;
+ vi_replace_map[ESC].function = rl_vi_movement_mode;
+ vi_replace_map[RETURN].function = rl_newline;
+ vi_replace_map[NEWLINE].function = rl_newline;
+
+ /* If the normal vi insertion keymap has ^H bound to erase, do the
+ same here. Probably should remove the assignment to RUBOUT up
+ there, but I don't think it will make a difference in real life. */
+ if (vi_insertion_keymap[CTRL ('H')].type == ISFUNC &&
+ vi_insertion_keymap[CTRL ('H')].function == rl_rubout)
+ vi_replace_map[CTRL ('H')].function = rl_vi_overstrike_delete;
+
+ }
+ _rl_keymap = vi_replace_map;
+ return (0);
+}
+
+#if 0
+/* Try to complete the word we are standing on or the word that ends with
+ the previous character. A space matches everything. Word delimiters are
+ space and ;. */
+int
+rl_vi_possible_completions()
+{
+ int save_pos = rl_point;
+
+ if (rl_line_buffer[rl_point] != ' ' && rl_line_buffer[rl_point] != ';')
+ {
+ while (rl_point < rl_end && rl_line_buffer[rl_point] != ' ' &&
+ rl_line_buffer[rl_point] != ';')
+ rl_point++;
+ }
+ else if (rl_line_buffer[rl_point - 1] == ';')
+ {
+ ding ();
+ return (0);
+ }
+
+ rl_possible_completions ();
+ rl_point = save_pos;
+
+ return (0);
+}
+#endif
+
+/* Functions to save and restore marks. */
+int
+rl_vi_set_mark (count, key)
+ int count, key;
+{
+ int ch;
+
+ ch = rl_read_key ();
+ if (_rl_lowercase_p (ch) == 0)
+ {
+ ding ();
+ return -1;
+ }
+ ch -= 'a';
+ vi_mark_chars[ch] = rl_point;
+ return 0;
+}
+
+int
+rl_vi_goto_mark (count, key)
+ int count, key;
+{
+ int ch;
+
+ ch = rl_read_key ();
+ if (ch == '`')
+ {
+ rl_point = rl_mark;
+ return 0;
+ }
+ else if (_rl_lowercase_p (ch) == 0)
+ {
+ ding ();
+ return -1;
+ }
+
+ ch -= 'a';
+ if (vi_mark_chars[ch] == -1)
+ {
+ ding ();
+ return -1;
+ }
+ rl_point = vi_mark_chars[ch];
+ return 0;
+}
+
+#endif /* VI_MODE */
diff --git a/readline/xmalloc.c b/readline/xmalloc.c
new file mode 100644
index 00000000000..4160651191b
--- /dev/null
+++ b/readline/xmalloc.c
@@ -0,0 +1,87 @@
+/* xmalloc.c -- safe versions of malloc and realloc */
+
+/* Copyright (C) 1991 Free Software Foundation, Inc.
+
+ This file is part of GNU Readline, a library for reading lines
+ of text with interactive input and history editing.
+
+ Readline is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 1, or (at your option) any
+ later version.
+
+ Readline is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Readline; see the file COPYING. If not, write to the Free
+ Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#if defined (HAVE_CONFIG_H)
+#include <config.h>
+#endif
+
+#include <stdio.h>
+
+#if defined (HAVE_STDLIB_H)
+# include <stdlib.h>
+#else
+# include "ansi_stdlib.h"
+#endif /* HAVE_STDLIB_H */
+
+static void memory_error_and_abort ();
+
+/* **************************************************************** */
+/* */
+/* Memory Allocation and Deallocation. */
+/* */
+/* **************************************************************** */
+
+/* Return a pointer to free()able block of memory large enough
+ to hold BYTES number of bytes. If the memory cannot be allocated,
+ print an error message and abort. */
+char *
+xmalloc (bytes)
+ int bytes;
+{
+ char *temp;
+
+ temp = (char *)malloc (bytes);
+ if (temp == 0)
+ memory_error_and_abort ("xmalloc");
+ return (temp);
+}
+
+char *
+xrealloc (pointer, bytes)
+ char *pointer;
+ int bytes;
+{
+ char *temp;
+
+ temp = pointer ? (char *)realloc (pointer, bytes) : (char *)malloc (bytes);
+
+ if (temp == 0)
+ memory_error_and_abort ("xrealloc");
+ return (temp);
+}
+
+static void
+memory_error_and_abort (fname)
+ char *fname;
+{
+ fprintf (stderr, "%s: out of virtual memory\n", fname);
+ exit (2);
+}
+
+/* Use this as the function to call when adding unwind protects so we
+ don't need to know what free() returns. */
+void
+xfree (string)
+ char *string;
+{
+ if (string)
+ free (string);
+}
diff --git a/regex/.cvsignore b/regex/.cvsignore
new file mode 100644
index 00000000000..a9cd65d8ba0
--- /dev/null
+++ b/regex/.cvsignore
@@ -0,0 +1,5 @@
+.deps
+.libs
+Makefile
+Makefile.in
+re
diff --git a/regex/CHANGES b/regex/CHANGES
new file mode 100644
index 00000000000..2bd0fb7639f
--- /dev/null
+++ b/regex/CHANGES
@@ -0,0 +1,19 @@
+This is an altered distribution of regexp for mysql.
+The follwing changes has been done to use the mysql configuration system and
+ISOLATIN1 characters.
+
+New Makefile
+
+Changed all files to include global.h
+
+Some changes in types to suppress warning errors from gcc.
+
+debug.c ; extra parameter to regchar
+
+Made regex_init & regex_end calls to init & free dynamic cclasses array.
+
+Fixed memory allocation bug in 'matcher'
+
+Changed regcomp.c to use bmove_upp() instead of memmove()
+
+Changed name of function try to rx_try in main.cc for Digitial C compiler.
diff --git a/regex/COPYRIGHT b/regex/COPYRIGHT
new file mode 100644
index 00000000000..d43362fbfc9
--- /dev/null
+++ b/regex/COPYRIGHT
@@ -0,0 +1,20 @@
+Copyright 1992, 1993, 1994 Henry Spencer. All rights reserved.
+This software is not subject to any license of the American Telephone
+and Telegraph Company or of the Regents of the University of California.
+
+Permission is granted to anyone to use this software for any purpose on
+any computer system, and to alter it and redistribute it, subject
+to the following restrictions:
+
+1. The author is not responsible for the consequences of use of this
+ software, no matter how awful, even if they arise from flaws in it.
+
+2. The origin of this software must not be misrepresented, either by
+ explicit claim or by omission. Since few users ever read sources,
+ credits must appear in the documentation.
+
+3. Altered versions must be plainly marked as such, and must not be
+ misrepresented as being the original software. Since few users
+ ever read sources, credits must appear in the documentation.
+
+4. This notice may not be removed or altered.
diff --git a/regex/Makefile.am b/regex/Makefile.am
new file mode 100644
index 00000000000..6cf7e74cec1
--- /dev/null
+++ b/regex/Makefile.am
@@ -0,0 +1,42 @@
+# 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
+
+INCLUDES = @MT_INCLUDES@ -I$(srcdir)/../include -I../include
+noinst_LIBRARIES = libregex.a
+LDADD = libregex.a ../strings/libmystrings.a
+noinst_HEADERS = cclass.h cname.h regex2.h utils.h engine.c regex.h
+libregex_a_SOURCES = regerror.c regcomp.c regexec.c regfree.c reginit.c
+noinst_PROGRAMS = re
+re_SOURCES = split.c debug.c main.c
+re_DEPENDENCIES= $(LIBRARIES)
+EXTRA_DIST = tests CHANGES COPYRIGHT WHATSNEW regexp.c \
+ debug.ih engine.ih main.ih regcomp.ih regerror.ih \
+ regex.3 regex.7
+
+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
+
+test: re tests
+ ./re < tests
+ ./re -el < tests
+ ./re -er < tests
diff --git a/regex/README b/regex/README
new file mode 100644
index 00000000000..cea9b67b666
--- /dev/null
+++ b/regex/README
@@ -0,0 +1,32 @@
+alpha3.4 release.
+Thu Mar 17 23:17:18 EST 1994
+henry@zoo.toronto.edu
+
+See WHATSNEW for change listing.
+
+installation notes:
+--------
+Read the comments at the beginning of Makefile before running.
+
+Utils.h contains some things that just might have to be modified on
+some systems, as well as a nested include (ugh) of <assert.h>.
+
+The "fake" directory contains quick-and-dirty fakes for some header
+files and routines that old systems may not have. Note also that
+-DUSEBCOPY will make utils.h substitute bcopy() for memmove().
+
+After that, "make r" will build regcomp.o, regexec.o, regfree.o,
+and regerror.o (the actual routines), bundle them together into a test
+program, and run regression tests on them. No output is good output.
+
+"make lib" builds just the .o files for the actual routines (when
+you're happy with testing and have adjusted CFLAGS for production),
+and puts them together into libregex.a. You can pick up either the
+library or *.o ("make lib" makes sure there are no other .o files left
+around to confuse things).
+
+Main.c, debug.c, split.c are used for regression testing but are not part
+of the RE routines themselves.
+
+Regex.h goes in /usr/include. All other .h files are internal only.
+--------
diff --git a/regex/WHATSNEW b/regex/WHATSNEW
new file mode 100644
index 00000000000..6e82e1dae0c
--- /dev/null
+++ b/regex/WHATSNEW
@@ -0,0 +1,92 @@
+New in alpha3.4: The complex bug alluded to below has been fixed (in a
+slightly kludgey temporary way that may hurt efficiency a bit; this is
+another "get it out the door for 4.4" release). The tests at the end of
+the tests file have accordingly been uncommented. The primary sign of
+the bug was that something like a?b matching ab matched b rather than ab.
+(The bug was essentially specific to this exact situation, else it would
+have shown up earlier.)
+
+New in alpha3.3: The definition of word boundaries has been altered
+slightly, to more closely match the usual programming notion that "_"
+is an alphabetic. Stuff used for pre-ANSI systems is now in a subdir,
+and the makefile no longer alludes to it in mysterious ways. The
+makefile has generally been cleaned up some. Fixes have been made
+(again!) so that the regression test will run without -DREDEBUG, at
+the cost of weaker checking. A workaround for a bug in some folks'
+<assert.h> has been added. And some more things have been added to
+tests, including a couple right at the end which are commented out
+because the code currently flunks them (complex bug; fix coming).
+Plus the usual minor cleanup.
+
+New in alpha3.2: Assorted bits of cleanup and portability improvement
+(the development base is now a BSDI system using GCC instead of an ancient
+Sun system, and the newer compiler exposed some glitches). Fix for a
+serious bug that affected REs using many [] (including REG_ICASE REs
+because of the way they are implemented), *sometimes*, depending on
+memory-allocation patterns. The header-file prototypes no longer name
+the parameters, avoiding possible name conflicts. The possibility that
+some clot has defined CHAR_MIN as (say) `-128' instead of `(-128)' is
+now handled gracefully. "uchar" is no longer used as an internal type
+name (too many people have the same idea). Still the same old lousy
+performance, alas.
+
+New in alpha3.1: Basically nothing, this release is just a bookkeeping
+convenience. Stay tuned.
+
+New in alpha3.0: Performance is no better, alas, but some fixes have been
+made and some functionality has been added. (This is basically the "get
+it out the door in time for 4.4" release.) One bug fix: regfree() didn't
+free the main internal structure (how embarrassing). It is now possible
+to put NULs in either the RE or the target string, using (resp.) a new
+REG_PEND flag and the old REG_STARTEND flag. The REG_NOSPEC flag to
+regcomp() makes all characters ordinary, so you can match a literal
+string easily (this will become more useful when performance improves!).
+There are now primitives to match beginnings and ends of words, although
+the syntax is disgusting and so is the implementation. The REG_ATOI
+debugging interface has changed a bit. And there has been considerable
+internal cleanup of various kinds.
+
+New in alpha2.3: Split change list out of README, and moved flags notes
+into Makefile. Macro-ized the name of regex(7) in regex(3), since it has
+to change for 4.4BSD. Cleanup work in engine.c, and some new regression
+tests to catch tricky cases thereof.
+
+New in alpha2.2: Out-of-date manpages updated. Regerror() acquires two
+small extensions -- REG_ITOA and REG_ATOI -- which avoid debugging kludges
+in my own test program and might be useful to others for similar purposes.
+The regression test will now compile (and run) without REDEBUG. The
+BRE \$ bug is fixed. Most uses of "uchar" are gone; it's all chars now.
+Char/uchar parameters are now written int/unsigned, to avoid possible
+portability problems with unpromoted parameters. Some unsigned casts have
+been introduced to minimize portability problems with shifting into sign
+bits.
+
+New in alpha2.1: Lots of little stuff, cleanup and fixes. The one big
+thing is that regex.h is now generated, using mkh, rather than being
+supplied in the distribution; due to circularities in dependencies,
+you have to build regex.h explicitly by "make h". The two known bugs
+have been fixed (and the regression test now checks for them), as has a
+problem with assertions not being suppressed in the absence of REDEBUG.
+No performance work yet.
+
+New in alpha2: Backslash-anything is an ordinary character, not an
+error (except, of course, for the handful of backslashed metacharacters
+in BREs), which should reduce script breakage. The regression test
+checks *where* null strings are supposed to match, and has generally
+been tightened up somewhat. Small bug fixes in parameter passing (not
+harmful, but technically errors) and some other areas. Debugging
+invoked by defining REDEBUG rather than not defining NDEBUG.
+
+New in alpha+3: full prototyping for internal routines, using a little
+helper program, mkh, which extracts prototypes given in stylized comments.
+More minor cleanup. Buglet fix: it's CHAR_BIT, not CHAR_BITS. Simple
+pre-screening of input when a literal string is known to be part of the
+RE; this does wonders for performance.
+
+New in alpha+2: minor bits of cleanup. Notably, the number "32" for the
+word width isn't hardwired into regexec.c any more, the public header
+file prototypes the functions if __STDC__ is defined, and some small typos
+in the manpages have been fixed.
+
+New in alpha+1: improvements to the manual pages, and an important
+extension, the REG_STARTEND option to regexec().
diff --git a/regex/cclass.h b/regex/cclass.h
new file mode 100644
index 00000000000..7d9a7ccc7c2
--- /dev/null
+++ b/regex/cclass.h
@@ -0,0 +1,21 @@
+/* character-class table */
+
+#define CCLASS_ALNUM 0
+#define CCLASS_ALPHA 1
+#define CCLASS_BLANK 2
+#define CCLASS_CNTRL 3
+#define CCLASS_DIGIT 4
+#define CCLASS_GRAPH 5
+#define CCLASS_LOWER 6
+#define CCLASS_PRINT 7
+#define CCLASS_PUNCT 8
+#define CCLASS_SPACE 9
+#define CCLASS_UPPER 10
+#define CCLASS_XDIGIT 11
+#define CCLASS_LAST 12
+
+extern struct cclass {
+ char *name;
+ char *chars;
+ char *multis;
+} cclasses[];
diff --git a/regex/cname.h b/regex/cname.h
new file mode 100644
index 00000000000..02e86e912e3
--- /dev/null
+++ b/regex/cname.h
@@ -0,0 +1,102 @@
+/* character-name table */
+static struct cname {
+ char *name;
+ char code;
+} cnames[] = {
+ "NUL", '\0',
+ "SOH", '\001',
+ "STX", '\002',
+ "ETX", '\003',
+ "EOT", '\004',
+ "ENQ", '\005',
+ "ACK", '\006',
+ "BEL", '\007',
+ "alert", '\007',
+ "BS", '\010',
+ "backspace", '\b',
+ "HT", '\011',
+ "tab", '\t',
+ "LF", '\012',
+ "newline", '\n',
+ "VT", '\013',
+ "vertical-tab", '\v',
+ "FF", '\014',
+ "form-feed", '\f',
+ "CR", '\015',
+ "carriage-return", '\r',
+ "SO", '\016',
+ "SI", '\017',
+ "DLE", '\020',
+ "DC1", '\021',
+ "DC2", '\022',
+ "DC3", '\023',
+ "DC4", '\024',
+ "NAK", '\025',
+ "SYN", '\026',
+ "ETB", '\027',
+ "CAN", '\030',
+ "EM", '\031',
+ "SUB", '\032',
+ "ESC", '\033',
+ "IS4", '\034',
+ "FS", '\034',
+ "IS3", '\035',
+ "GS", '\035',
+ "IS2", '\036',
+ "RS", '\036',
+ "IS1", '\037',
+ "US", '\037',
+ "space", ' ',
+ "exclamation-mark", '!',
+ "quotation-mark", '"',
+ "number-sign", '#',
+ "dollar-sign", '$',
+ "percent-sign", '%',
+ "ampersand", '&',
+ "apostrophe", '\'',
+ "left-parenthesis", '(',
+ "right-parenthesis", ')',
+ "asterisk", '*',
+ "plus-sign", '+',
+ "comma", ',',
+ "hyphen", '-',
+ "hyphen-minus", '-',
+ "period", '.',
+ "full-stop", '.',
+ "slash", '/',
+ "solidus", '/',
+ "zero", '0',
+ "one", '1',
+ "two", '2',
+ "three", '3',
+ "four", '4',
+ "five", '5',
+ "six", '6',
+ "seven", '7',
+ "eight", '8',
+ "nine", '9',
+ "colon", ':',
+ "semicolon", ';',
+ "less-than-sign", '<',
+ "equals-sign", '=',
+ "greater-than-sign", '>',
+ "question-mark", '?',
+ "commercial-at", '@',
+ "left-square-bracket", '[',
+ "backslash", '\\',
+ "reverse-solidus", '\\',
+ "right-square-bracket", ']',
+ "circumflex", '^',
+ "circumflex-accent", '^',
+ "underscore", '_',
+ "low-line", '_',
+ "grave-accent", '`',
+ "left-brace", '{',
+ "left-curly-bracket", '{',
+ "vertical-line", '|',
+ "right-brace", '}',
+ "right-curly-bracket", '}',
+ "tilde", '~',
+ "DEL", '\177',
+ NULL, 0,
+};
diff --git a/regex/debug.c b/regex/debug.c
new file mode 100644
index 00000000000..145a9736d39
--- /dev/null
+++ b/regex/debug.c
@@ -0,0 +1,243 @@
+#include <global.h>
+#include <m_ctype.h>
+#include <m_string.h>
+#include <sys/types.h>
+#include <regex.h>
+#include "utils.h"
+#include "regex2.h"
+#include "debug.ih"
+
+/* Added extra paramter to regchar to remove static buffer ; Monty 96.11.27 */
+
+/*
+ - regprint - print a regexp for debugging
+ == void regprint(regex_t *r, FILE *d);
+ */
+void
+regprint(r, d)
+regex_t *r;
+FILE *d;
+{
+ register struct re_guts *g = r->re_g;
+ register int i;
+ register int c;
+ register int last;
+ int nincat[NC];
+ char buf[10];
+
+ fprintf(d, "%ld states, %d categories", (long)g->nstates,
+ g->ncategories);
+ fprintf(d, ", first %ld last %ld", (long)g->firststate,
+ (long)g->laststate);
+ if (g->iflags&USEBOL)
+ fprintf(d, ", USEBOL");
+ if (g->iflags&USEEOL)
+ fprintf(d, ", USEEOL");
+ if (g->iflags&BAD)
+ fprintf(d, ", BAD");
+ if (g->nsub > 0)
+ fprintf(d, ", nsub=%ld", (long)g->nsub);
+ if (g->must != NULL)
+ fprintf(d, ", must(%ld) `%*s'", (long)g->mlen, (int)g->mlen,
+ g->must);
+ if (g->backrefs)
+ fprintf(d, ", backrefs");
+ if (g->nplus > 0)
+ fprintf(d, ", nplus %ld", (long)g->nplus);
+ fprintf(d, "\n");
+ s_print(g, d);
+ for (i = 0; i < g->ncategories; i++) {
+ nincat[i] = 0;
+ for (c = CHAR_MIN; c <= CHAR_MAX; c++)
+ if (g->categories[c] == i)
+ nincat[i]++;
+ }
+ fprintf(d, "cc0#%d", nincat[0]);
+ for (i = 1; i < g->ncategories; i++)
+ if (nincat[i] == 1) {
+ for (c = CHAR_MIN; c <= CHAR_MAX; c++)
+ if (g->categories[c] == i)
+ break;
+ fprintf(d, ", %d=%s", i, regchar(c,buf));
+ }
+ fprintf(d, "\n");
+ for (i = 1; i < g->ncategories; i++)
+ if (nincat[i] != 1) {
+ fprintf(d, "cc%d\t", i);
+ last = -1;
+ for (c = CHAR_MIN; c <= CHAR_MAX+1; c++) /* +1 does flush */
+ if (c <= CHAR_MAX && g->categories[c] == i) {
+ if (last < 0) {
+ fprintf(d, "%s", regchar(c,buf));
+ last = c;
+ }
+ } else {
+ if (last >= 0) {
+ if (last != c-1)
+ fprintf(d, "-%s",
+ regchar(c-1,buf));
+ last = -1;
+ }
+ }
+ fprintf(d, "\n");
+ }
+}
+
+/*
+ - s_print - print the strip for debugging
+ == static void s_print(register struct re_guts *g, FILE *d);
+ */
+static void
+s_print(g, d)
+register struct re_guts *g;
+FILE *d;
+{
+ register sop *s;
+ register cset *cs;
+ register int i;
+ register int done = 0;
+ register sop opnd;
+ register int col = 0;
+ register int last;
+ register sopno offset = 2;
+ char buf[10];
+# define GAP() { if (offset % 5 == 0) { \
+ if (col > 40) { \
+ fprintf(d, "\n\t"); \
+ col = 0; \
+ } else { \
+ fprintf(d, " "); \
+ col++; \
+ } \
+ } else \
+ col++; \
+ offset++; \
+ }
+
+ if (OP(g->strip[0]) != OEND)
+ fprintf(d, "missing initial OEND!\n");
+ for (s = &g->strip[1]; !done; s++) {
+ opnd = OPND(*s);
+ switch (OP(*s)) {
+ case OEND:
+ fprintf(d, "\n");
+ done = 1;
+ break;
+ case OCHAR:
+ if (strchr("\\|()^$.[+*?{}!<> ", (char)opnd) != NULL)
+ fprintf(d, "\\%c", (char)opnd);
+ else
+ fprintf(d, "%s", regchar((char)opnd,buf));
+ break;
+ case OBOL:
+ fprintf(d, "^");
+ break;
+ case OEOL:
+ fprintf(d, "$");
+ break;
+ case OBOW:
+ fprintf(d, "\\{");
+ break;
+ case OEOW:
+ fprintf(d, "\\}");
+ break;
+ case OANY:
+ fprintf(d, ".");
+ break;
+ case OANYOF:
+ fprintf(d, "[(%ld)", (long)opnd);
+ cs = &g->sets[opnd];
+ last = -1;
+ for (i = 0; i < g->csetsize+1; i++) /* +1 flushes */
+ if (CHIN(cs, i) && i < g->csetsize) {
+ if (last < 0) {
+ fprintf(d, "%s", regchar(i,buf));
+ last = i;
+ }
+ } else {
+ if (last >= 0) {
+ if (last != i-1)
+ fprintf(d, "-%s",
+ regchar(i-1,buf));
+ last = -1;
+ }
+ }
+ fprintf(d, "]");
+ break;
+ case OBACK_:
+ fprintf(d, "(\\<%ld>", (long)opnd);
+ break;
+ case O_BACK:
+ fprintf(d, "<%ld>\\)", (long)opnd);
+ break;
+ case OPLUS_:
+ fprintf(d, "(+");
+ if (OP(*(s+opnd)) != O_PLUS)
+ fprintf(d, "<%ld>", (long)opnd);
+ break;
+ case O_PLUS:
+ if (OP(*(s-opnd)) != OPLUS_)
+ fprintf(d, "<%ld>", (long)opnd);
+ fprintf(d, "+)");
+ break;
+ case OQUEST_:
+ fprintf(d, "(?");
+ if (OP(*(s+opnd)) != O_QUEST)
+ fprintf(d, "<%ld>", (long)opnd);
+ break;
+ case O_QUEST:
+ if (OP(*(s-opnd)) != OQUEST_)
+ fprintf(d, "<%ld>", (long)opnd);
+ fprintf(d, "?)");
+ break;
+ case OLPAREN:
+ fprintf(d, "((<%ld>", (long)opnd);
+ break;
+ case ORPAREN:
+ fprintf(d, "<%ld>))", (long)opnd);
+ break;
+ case OCH_:
+ fprintf(d, "<");
+ if (OP(*(s+opnd)) != OOR2)
+ fprintf(d, "<%ld>", (long)opnd);
+ break;
+ case OOR1:
+ if (OP(*(s-opnd)) != OOR1 && OP(*(s-opnd)) != OCH_)
+ fprintf(d, "<%ld>", (long)opnd);
+ fprintf(d, "|");
+ break;
+ case OOR2:
+ fprintf(d, "|");
+ if (OP(*(s+opnd)) != OOR2 && OP(*(s+opnd)) != O_CH)
+ fprintf(d, "<%ld>", (long)opnd);
+ break;
+ case O_CH:
+ if (OP(*(s-opnd)) != OOR1)
+ fprintf(d, "<%ld>", (long)opnd);
+ fprintf(d, ">");
+ break;
+ default:
+ fprintf(d, "!%d(%d)!", OP(*s), opnd);
+ break;
+ }
+ if (!done)
+ GAP();
+ }
+}
+
+/*
+ - regchar - make a character printable
+ == static char *regchar(int ch);
+ */
+static char * /* -> representation */
+regchar(ch,buf)
+int ch;
+char *buf;
+{
+
+ if (isprint(ch) || ch == ' ')
+ sprintf(buf, "%c", ch);
+ else
+ sprintf(buf, "\\%o", ch);
+ return(buf);
+}
diff --git a/regex/debug.ih b/regex/debug.ih
new file mode 100644
index 00000000000..532ec5086e5
--- /dev/null
+++ b/regex/debug.ih
@@ -0,0 +1,14 @@
+/* ========= begin header generated by ./mkh ========= */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* === debug.c === */
+void regprint(regex_t *r, FILE *d);
+static void s_print(register struct re_guts *g, FILE *d);
+static char *regchar(int ch,char *buf);
+
+#ifdef __cplusplus
+}
+#endif
+/* ========= end header generated by ./mkh ========= */
diff --git a/regex/engine.c b/regex/engine.c
new file mode 100644
index 00000000000..6453a66d21c
--- /dev/null
+++ b/regex/engine.c
@@ -0,0 +1,1026 @@
+/*
+ * The matching engine and friends. This file is #included by regexec.c
+ * after suitable #defines of a variety of macros used herein, so that
+ * different state representations can be used without duplicating masses
+ * of code.
+ */
+
+#ifdef SNAMES
+#define matcher smatcher
+#define fast sfast
+#define slow sslow
+#define dissect sdissect
+#define backref sbackref
+#define step sstep
+#define print sprint
+#define at sat
+#define match smat
+#endif
+#ifdef LNAMES
+#define matcher lmatcher
+#define fast lfast
+#define slow lslow
+#define dissect ldissect
+#define backref lbackref
+#define step lstep
+#define print lprint
+#define at lat
+#define match lmat
+#endif
+
+/* another structure passed up and down to avoid zillions of parameters */
+struct match {
+ struct re_guts *g;
+ int eflags;
+ regmatch_t *pmatch; /* [nsub+1] (0 element unused) */
+ char *offp; /* offsets work from here */
+ char *beginp; /* start of string -- virtual NUL precedes */
+ char *endp; /* end of string -- virtual NUL here */
+ char *coldp; /* can be no match starting before here */
+ char **lastpos; /* [nplus+1] */
+ STATEVARS;
+ states st; /* current states */
+ states fresh; /* states for a fresh start */
+ states tmp; /* temporary */
+ states empty; /* empty set of states */
+};
+
+#include "engine.ih"
+
+#ifdef REDEBUG
+#define SP(t, s, c) print(m, t, s, c, stdout)
+#define AT(t, p1, p2, s1, s2) at(m, t, p1, p2, s1, s2)
+#define NOTE(str) { if (m->eflags&REG_TRACE) printf("=%s\n", (str)); }
+#else
+#define SP(t, s, c) /* nothing */
+#define AT(t, p1, p2, s1, s2) /* nothing */
+#define NOTE(s) /* nothing */
+#endif
+
+/*
+ - matcher - the actual matching engine
+ == static int matcher(register struct re_guts *g, char *string, \
+ == size_t nmatch, regmatch_t pmatch[], int eflags);
+ */
+static int /* 0 success, REG_NOMATCH failure */
+matcher(g, str, nmatch, pmatch, eflags)
+register struct re_guts *g;
+char *str;
+size_t nmatch;
+regmatch_t pmatch[];
+int eflags;
+{
+ register char *endp;
+ register uint i;
+ struct match mv;
+ register struct match *m = &mv;
+ register char *dp;
+ register const sopno gf = g->firststate+1; /* +1 for OEND */
+ register const sopno gl = g->laststate;
+ char *start;
+ char *stop;
+
+ /* simplify the situation where possible */
+ if (g->cflags&REG_NOSUB)
+ nmatch = 0;
+ if (eflags&REG_STARTEND) {
+ start = str + pmatch[0].rm_so;
+ stop = str + pmatch[0].rm_eo;
+ } else {
+ start = str;
+ stop = start + strlen(start);
+ }
+ if (stop < start)
+ return(REG_INVARG);
+
+ /* prescreening; this does wonders for this rather slow code */
+ if (g->must != NULL) {
+ for (dp = start; dp < stop; dp++)
+ if (*dp == g->must[0] && stop - dp >= g->mlen &&
+ memcmp(dp, g->must, (size_t)g->mlen) == 0)
+ break;
+ if (dp == stop) /* we didn't find g->must */
+ return(REG_NOMATCH);
+ }
+
+ /* match struct setup */
+ m->g = g;
+ m->eflags = eflags;
+ m->pmatch = NULL;
+ m->lastpos = NULL;
+ m->offp = str;
+ m->beginp = start;
+ m->endp = stop;
+ STATESETUP(m, 4);
+ SETUP(m->st);
+ SETUP(m->fresh);
+ SETUP(m->tmp);
+ SETUP(m->empty);
+ CLEAR(m->empty);
+
+ /* this loop does only one repetition except for backrefs */
+ for (;;) {
+ endp = fast(m, start, stop, gf, gl);
+ if (endp == NULL) { /* a miss */
+ if (m->pmatch != NULL)
+ free((char *)m->pmatch);
+ if (m->lastpos != NULL)
+ free((char *)m->lastpos);
+ STATETEARDOWN(m);
+ return(REG_NOMATCH);
+ }
+ if (nmatch == 0 && !g->backrefs)
+ break; /* no further info needed */
+
+ /* where? */
+ assert(m->coldp != NULL);
+ for (;;) {
+ NOTE("finding start");
+ endp = slow(m, m->coldp, stop, gf, gl);
+ if (endp != NULL)
+ break;
+ assert(m->coldp < m->endp);
+ m->coldp++;
+ }
+ if (nmatch == 1 && !g->backrefs)
+ break; /* no further info needed */
+
+ /* oh my, he wants the subexpressions... */
+ if (m->pmatch == NULL)
+ m->pmatch = (regmatch_t *)malloc((m->g->nsub + 1) *
+ sizeof(regmatch_t));
+ if (m->pmatch == NULL) {
+ if (m->lastpos != NULL)
+ free((char *)m->lastpos);
+ STATETEARDOWN(m);
+ return(REG_ESPACE);
+ }
+ for (i = 1; i <= m->g->nsub; i++)
+ m->pmatch[i].rm_so = m->pmatch[i].rm_eo = -1;
+ if (!g->backrefs && !(m->eflags&REG_BACKR)) {
+ NOTE("dissecting");
+ dp = dissect(m, m->coldp, endp, gf, gl);
+ } else {
+ if (g->nplus > 0 && m->lastpos == NULL)
+ m->lastpos = (char **)malloc((g->nplus+1) *
+ sizeof(char *));
+ if (g->nplus > 0 && m->lastpos == NULL) {
+ free(m->pmatch);
+ STATETEARDOWN(m);
+ return(REG_ESPACE);
+ }
+ NOTE("backref dissect");
+ dp = backref(m, m->coldp, endp, gf, gl, (sopno)0);
+ }
+ if (dp != NULL)
+ break;
+
+ /* uh-oh... we couldn't find a subexpression-level match */
+ assert(g->backrefs); /* must be back references doing it */
+ assert(g->nplus == 0 || m->lastpos != NULL);
+ for (;;) {
+ if (dp != NULL || endp <= m->coldp)
+ break; /* defeat */
+ NOTE("backoff");
+ endp = slow(m, m->coldp, endp-1, gf, gl);
+ if (endp == NULL)
+ break; /* defeat */
+ /* try it on a shorter possibility */
+#ifndef NDEBUG
+ for (i = 1; i <= m->g->nsub; i++) {
+ assert(m->pmatch[i].rm_so == -1);
+ assert(m->pmatch[i].rm_eo == -1);
+ }
+#endif
+ NOTE("backoff dissect");
+ dp = backref(m, m->coldp, endp, gf, gl, (sopno)0);
+ }
+ assert(dp == NULL || dp == endp);
+ if (dp != NULL) /* found a shorter one */
+ break;
+
+ /* despite initial appearances, there is no match here */
+ NOTE("false alarm");
+ start = m->coldp + 1; /* recycle starting later */
+ assert(start <= stop);
+ }
+
+ /* fill in the details if requested */
+ if (nmatch > 0) {
+ pmatch[0].rm_so = m->coldp - m->offp;
+ pmatch[0].rm_eo = endp - m->offp;
+ }
+ if (nmatch > 1) {
+ assert(m->pmatch != NULL);
+ for (i = 1; i < nmatch; i++)
+ if (i <= m->g->nsub)
+ pmatch[i] = m->pmatch[i];
+ else {
+ pmatch[i].rm_so = -1;
+ pmatch[i].rm_eo = -1;
+ }
+ }
+
+ if (m->pmatch != NULL)
+ free((char *)m->pmatch);
+ if (m->lastpos != NULL)
+ free((char *)m->lastpos);
+ STATETEARDOWN(m);
+ return(0);
+}
+
+/*
+ - dissect - figure out what matched what, no back references
+ == static char *dissect(register struct match *m, char *start, \
+ == char *stop, sopno startst, sopno stopst);
+ */
+static char * /* == stop (success) always */
+dissect(m, start, stop, startst, stopst)
+register struct match *m;
+char *start;
+char *stop;
+sopno startst;
+sopno stopst;
+{
+ register uint i;
+ register sopno ss; /* start sop of current subRE */
+ register sopno es; /* end sop of current subRE */
+ register char *sp; /* start of string matched by it */
+ register char *stp; /* string matched by it cannot pass here */
+ register char *rest; /* start of rest of string */
+ register char *tail; /* string unmatched by rest of RE */
+ register sopno ssub; /* start sop of subsubRE */
+ register sopno esub; /* end sop of subsubRE */
+ register char *ssp; /* start of string matched by subsubRE */
+ register char *sep; /* end of string matched by subsubRE */
+ register char *oldssp; /* previous ssp */
+ register char *dp;
+
+ AT("diss", start, stop, startst, stopst);
+ sp = start;
+ for (ss = startst; ss < stopst; ss = es) {
+ /* identify end of subRE */
+ es = ss;
+ switch (OP(m->g->strip[es])) {
+ case OPLUS_:
+ case OQUEST_:
+ es += OPND(m->g->strip[es]);
+ break;
+ case OCH_:
+ while (OP(m->g->strip[es]) != O_CH)
+ es += OPND(m->g->strip[es]);
+ break;
+ }
+ es++;
+
+ /* figure out what it matched */
+ switch (OP(m->g->strip[ss])) {
+ case OEND:
+ assert(nope);
+ break;
+ case OCHAR:
+ sp++;
+ break;
+ case OBOL:
+ case OEOL:
+ case OBOW:
+ case OEOW:
+ break;
+ case OANY:
+ case OANYOF:
+ sp++;
+ break;
+ case OBACK_:
+ case O_BACK:
+ assert(nope);
+ break;
+ /* cases where length of match is hard to find */
+ case OQUEST_:
+ stp = stop;
+ for (;;) {
+ /* how long could this one be? */
+ rest = slow(m, sp, stp, ss, es);
+ assert(rest != NULL); /* it did match */
+ /* could the rest match the rest? */
+ tail = slow(m, rest, stop, es, stopst);
+ if (tail == stop)
+ break; /* yes! */
+ /* no -- try a shorter match for this one */
+ stp = rest - 1;
+ assert(stp >= sp); /* it did work */
+ }
+ ssub = ss + 1;
+ esub = es - 1;
+ /* did innards match? */
+ if (slow(m, sp, rest, ssub, esub) != NULL) {
+ dp = dissect(m, sp, rest, ssub, esub);
+ assert(dp == rest);
+ } else /* no */
+ assert(sp == rest);
+ sp = rest;
+ break;
+ case OPLUS_:
+ stp = stop;
+ for (;;) {
+ /* how long could this one be? */
+ rest = slow(m, sp, stp, ss, es);
+ assert(rest != NULL); /* it did match */
+ /* could the rest match the rest? */
+ tail = slow(m, rest, stop, es, stopst);
+ if (tail == stop)
+ break; /* yes! */
+ /* no -- try a shorter match for this one */
+ stp = rest - 1;
+ assert(stp >= sp); /* it did work */
+ }
+ ssub = ss + 1;
+ esub = es - 1;
+ ssp = sp;
+ oldssp = ssp;
+ for (;;) { /* find last match of innards */
+ sep = slow(m, ssp, rest, ssub, esub);
+ if (sep == NULL || sep == ssp)
+ break; /* failed or matched null */
+ oldssp = ssp; /* on to next try */
+ ssp = sep;
+ }
+ if (sep == NULL) {
+ /* last successful match */
+ sep = ssp;
+ ssp = oldssp;
+ }
+ assert(sep == rest); /* must exhaust substring */
+ assert(slow(m, ssp, sep, ssub, esub) == rest);
+ dp = dissect(m, ssp, sep, ssub, esub);
+ assert(dp == sep);
+ sp = rest;
+ break;
+ case OCH_:
+ stp = stop;
+ for (;;) {
+ /* how long could this one be? */
+ rest = slow(m, sp, stp, ss, es);
+ assert(rest != NULL); /* it did match */
+ /* could the rest match the rest? */
+ tail = slow(m, rest, stop, es, stopst);
+ if (tail == stop)
+ break; /* yes! */
+ /* no -- try a shorter match for this one */
+ stp = rest - 1;
+ assert(stp >= sp); /* it did work */
+ }
+ ssub = ss + 1;
+ esub = ss + OPND(m->g->strip[ss]) - 1;
+ assert(OP(m->g->strip[esub]) == OOR1);
+ for (;;) { /* find first matching branch */
+ if (slow(m, sp, rest, ssub, esub) == rest)
+ break; /* it matched all of it */
+ /* that one missed, try next one */
+ assert(OP(m->g->strip[esub]) == OOR1);
+ esub++;
+ assert(OP(m->g->strip[esub]) == OOR2);
+ ssub = esub + 1;
+ esub += OPND(m->g->strip[esub]);
+ if (OP(m->g->strip[esub]) == OOR2)
+ esub--;
+ else
+ assert(OP(m->g->strip[esub]) == O_CH);
+ }
+ dp = dissect(m, sp, rest, ssub, esub);
+ assert(dp == rest);
+ sp = rest;
+ break;
+ case O_PLUS:
+ case O_QUEST:
+ case OOR1:
+ case OOR2:
+ case O_CH:
+ assert(nope);
+ break;
+ case OLPAREN:
+ i = OPND(m->g->strip[ss]);
+ assert(0 < i && i <= m->g->nsub);
+ m->pmatch[i].rm_so = sp - m->offp;
+ break;
+ case ORPAREN:
+ i = OPND(m->g->strip[ss]);
+ assert(0 < i && i <= m->g->nsub);
+ m->pmatch[i].rm_eo = sp - m->offp;
+ break;
+ default: /* uh oh */
+ assert(nope);
+ break;
+ }
+ }
+
+ assert(sp == stop);
+ return(sp);
+}
+
+/*
+ - backref - figure out what matched what, figuring in back references
+ == static char *backref(register struct match *m, char *start, \
+ == char *stop, sopno startst, sopno stopst, sopno lev);
+ */
+static char * /* == stop (success) or NULL (failure) */
+backref(m, start, stop, startst, stopst, lev)
+register struct match *m;
+char *start;
+char *stop;
+sopno startst;
+sopno stopst;
+sopno lev; /* PLUS nesting level */
+{
+ register uint i;
+ register sopno ss; /* start sop of current subRE */
+ register char *sp; /* start of string matched by it */
+ register sopno ssub; /* start sop of subsubRE */
+ register sopno esub; /* end sop of subsubRE */
+ register char *ssp; /* start of string matched by subsubRE */
+ register char *dp;
+ register size_t len;
+ register int hard;
+ register sop s;
+ register regoff_t offsave;
+ register cset *cs;
+
+ AT("back", start, stop, startst, stopst);
+ sp = start;
+
+ /* get as far as we can with easy stuff */
+ hard = 0;
+ for (ss = startst; !hard && ss < stopst; ss++)
+ switch (OP(s = m->g->strip[ss])) {
+ case OCHAR:
+ if (sp == stop || *sp++ != (char)OPND(s))
+ return(NULL);
+ break;
+ case OANY:
+ if (sp == stop)
+ return(NULL);
+ sp++;
+ break;
+ case OANYOF:
+ cs = &m->g->sets[OPND(s)];
+ if (sp == stop || !CHIN(cs, *sp++))
+ return(NULL);
+ break;
+ case OBOL:
+ if ( (sp == m->beginp && !(m->eflags&REG_NOTBOL)) ||
+ (sp < m->endp && *(sp-1) == '\n' &&
+ (m->g->cflags&REG_NEWLINE)) )
+ { /* yes */ }
+ else
+ return(NULL);
+ break;
+ case OEOL:
+ if ( (sp == m->endp && !(m->eflags&REG_NOTEOL)) ||
+ (sp < m->endp && *sp == '\n' &&
+ (m->g->cflags&REG_NEWLINE)) )
+ { /* yes */ }
+ else
+ return(NULL);
+ break;
+ case OBOW:
+ if (( (sp == m->beginp && !(m->eflags&REG_NOTBOL)) ||
+ (sp < m->endp && *(sp-1) == '\n' &&
+ (m->g->cflags&REG_NEWLINE)) ||
+ (sp > m->beginp &&
+ !ISWORD(*(sp-1))) ) &&
+ (sp < m->endp && ISWORD(*sp)) )
+ { /* yes */ }
+ else
+ return(NULL);
+ break;
+ case OEOW:
+ if (( (sp == m->endp && !(m->eflags&REG_NOTEOL)) ||
+ (sp < m->endp && *sp == '\n' &&
+ (m->g->cflags&REG_NEWLINE)) ||
+ (sp < m->endp && !ISWORD(*sp)) ) &&
+ (sp > m->beginp && ISWORD(*(sp-1))) )
+ { /* yes */ }
+ else
+ return(NULL);
+ break;
+ case O_QUEST:
+ break;
+ case OOR1: /* matches null but needs to skip */
+ ss++;
+ s = m->g->strip[ss];
+ do {
+ assert(OP(s) == OOR2);
+ ss += OPND(s);
+ } while (OP(s = m->g->strip[ss]) != O_CH);
+ /* note that the ss++ gets us past the O_CH */
+ break;
+ default: /* have to make a choice */
+ hard = 1;
+ break;
+ }
+ if (!hard) { /* that was it! */
+ if (sp != stop)
+ return(NULL);
+ return(sp);
+ }
+ ss--; /* adjust for the for's final increment */
+
+ /* the hard stuff */
+ AT("hard", sp, stop, ss, stopst);
+ s = m->g->strip[ss];
+ switch (OP(s)) {
+ case OBACK_: /* the vilest depths */
+ i = OPND(s);
+ assert(0 < i && i <= m->g->nsub);
+ if (m->pmatch[i].rm_eo == -1)
+ return(NULL);
+ assert(m->pmatch[i].rm_so != -1);
+ len = m->pmatch[i].rm_eo - m->pmatch[i].rm_so;
+ assert((size_t) (stop - m->beginp) >= len);
+ if (sp > stop - len)
+ return(NULL); /* not enough left to match */
+ ssp = m->offp + m->pmatch[i].rm_so;
+ if (memcmp(sp, ssp, len) != 0)
+ return(NULL);
+ while (m->g->strip[ss] != SOP(O_BACK, i))
+ ss++;
+ return(backref(m, sp+len, stop, ss+1, stopst, lev));
+ break;
+ case OQUEST_: /* to null or not */
+ dp = backref(m, sp, stop, ss+1, stopst, lev);
+ if (dp != NULL)
+ return(dp); /* not */
+ return(backref(m, sp, stop, ss+OPND(s)+1, stopst, lev));
+ break;
+ case OPLUS_:
+ assert(m->lastpos != NULL);
+ assert(lev+1 <= m->g->nplus);
+ m->lastpos[lev+1] = sp;
+ return(backref(m, sp, stop, ss+1, stopst, lev+1));
+ break;
+ case O_PLUS:
+ if (sp == m->lastpos[lev]) /* last pass matched null */
+ return(backref(m, sp, stop, ss+1, stopst, lev-1));
+ /* try another pass */
+ m->lastpos[lev] = sp;
+ dp = backref(m, sp, stop, ss-OPND(s)+1, stopst, lev);
+ if (dp == NULL)
+ return(backref(m, sp, stop, ss+1, stopst, lev-1));
+ else
+ return(dp);
+ break;
+ case OCH_: /* find the right one, if any */
+ ssub = ss + 1;
+ esub = ss + OPND(s) - 1;
+ assert(OP(m->g->strip[esub]) == OOR1);
+ for (;;) { /* find first matching branch */
+ dp = backref(m, sp, stop, ssub, esub, lev);
+ if (dp != NULL)
+ return(dp);
+ /* that one missed, try next one */
+ if (OP(m->g->strip[esub]) == O_CH)
+ return(NULL); /* there is none */
+ esub++;
+ assert(OP(m->g->strip[esub]) == OOR2);
+ ssub = esub + 1;
+ esub += OPND(m->g->strip[esub]);
+ if (OP(m->g->strip[esub]) == OOR2)
+ esub--;
+ else
+ assert(OP(m->g->strip[esub]) == O_CH);
+ }
+ break;
+ case OLPAREN: /* must undo assignment if rest fails */
+ i = OPND(s);
+ assert(0 < i && i <= m->g->nsub);
+ offsave = m->pmatch[i].rm_so;
+ m->pmatch[i].rm_so = sp - m->offp;
+ dp = backref(m, sp, stop, ss+1, stopst, lev);
+ if (dp != NULL)
+ return(dp);
+ m->pmatch[i].rm_so = offsave;
+ return(NULL);
+ break;
+ case ORPAREN: /* must undo assignment if rest fails */
+ i = OPND(s);
+ assert(0 < i && i <= m->g->nsub);
+ offsave = m->pmatch[i].rm_eo;
+ m->pmatch[i].rm_eo = sp - m->offp;
+ dp = backref(m, sp, stop, ss+1, stopst, lev);
+ if (dp != NULL)
+ return(dp);
+ m->pmatch[i].rm_eo = offsave;
+ return(NULL);
+ break;
+ default: /* uh oh */
+ assert(nope);
+ break;
+ }
+
+ /* "can't happen" */
+ assert(nope);
+ /* NOTREACHED */
+ return 0; /* Keep gcc happy */
+}
+
+/*
+ - fast - step through the string at top speed
+ == static char *fast(register struct match *m, char *start, \
+ == char *stop, sopno startst, sopno stopst);
+ */
+static char * /* where tentative match ended, or NULL */
+fast(m, start, stop, startst, stopst)
+register struct match *m;
+char *start;
+char *stop;
+sopno startst;
+sopno stopst;
+{
+ register states st = m->st;
+ register states fresh = m->fresh;
+ register states tmp = m->tmp;
+ register char *p = start;
+ register int c = (start == m->beginp) ? OUT : *(start-1);
+ register int lastc; /* previous c */
+ register int flagch;
+ register int i;
+ register char *coldp; /* last p after which no match was underway */
+
+ CLEAR(st);
+ SET1(st, startst);
+ st = step(m->g, startst, stopst, st, NOTHING, st);
+ ASSIGN(fresh, st);
+ SP("start", st, *p);
+ coldp = NULL;
+ for (;;) {
+ /* next character */
+ lastc = c;
+ c = (p == m->endp) ? OUT : *p;
+ if (EQ(st, fresh))
+ coldp = p;
+
+ /* is there an EOL and/or BOL between lastc and c? */
+ flagch = '\0';
+ i = 0;
+ if ( (lastc == '\n' && m->g->cflags&REG_NEWLINE) ||
+ (lastc == OUT && !(m->eflags&REG_NOTBOL)) ) {
+ flagch = BOL;
+ i = m->g->nbol;
+ }
+ if ( (c == '\n' && m->g->cflags&REG_NEWLINE) ||
+ (c == OUT && !(m->eflags&REG_NOTEOL)) ) {
+ flagch = (flagch == BOL) ? BOLEOL : EOL;
+ i += m->g->neol;
+ }
+ if (i != 0) {
+ for (; i > 0; i--)
+ st = step(m->g, startst, stopst, st, flagch, st);
+ SP("boleol", st, c);
+ }
+
+ /* how about a word boundary? */
+ if ( (flagch == BOL || (lastc != OUT && !ISWORD(lastc))) &&
+ (c != OUT && ISWORD(c)) ) {
+ flagch = BOW;
+ }
+ if ( (lastc != OUT && ISWORD(lastc)) &&
+ (flagch == EOL || (c != OUT && !ISWORD(c))) ) {
+ flagch = EOW;
+ }
+ if (flagch == BOW || flagch == EOW) {
+ st = step(m->g, startst, stopst, st, flagch, st);
+ SP("boweow", st, c);
+ }
+
+ /* are we done? */
+ if (ISSET(st, stopst) || p == stop)
+ break; /* NOTE BREAK OUT */
+
+ /* no, we must deal with this character */
+ ASSIGN(tmp, st);
+ ASSIGN(st, fresh);
+ assert(c != OUT);
+ st = step(m->g, startst, stopst, tmp, c, st);
+ SP("aft", st, c);
+ assert(EQ(step(m->g, startst, stopst, st, NOTHING, st), st));
+ p++;
+ }
+
+ assert(coldp != NULL);
+ m->coldp = coldp;
+ if (ISSET(st, stopst))
+ return(p+1);
+ else
+ return(NULL);
+}
+
+/*
+ - slow - step through the string more deliberately
+ == static char *slow(register struct match *m, char *start, \
+ == char *stop, sopno startst, sopno stopst);
+ */
+static char * /* where it ended */
+slow(m, start, stop, startst, stopst)
+register struct match *m;
+char *start;
+char *stop;
+sopno startst;
+sopno stopst;
+{
+ register states st = m->st;
+ register states empty = m->empty;
+ register states tmp = m->tmp;
+ register char *p = start;
+ register int c = (start == m->beginp) ? OUT : *(start-1);
+ register int lastc; /* previous c */
+ register int flagch;
+ register int i;
+ register char *matchp; /* last p at which a match ended */
+
+ AT("slow", start, stop, startst, stopst);
+ CLEAR(st);
+ SET1(st, startst);
+ SP("sstart", st, *p);
+ st = step(m->g, startst, stopst, st, NOTHING, st);
+ matchp = NULL;
+ for (;;) {
+ /* next character */
+ lastc = c;
+ c = (p == m->endp) ? OUT : *p;
+
+ /* is there an EOL and/or BOL between lastc and c? */
+ flagch = '\0';
+ i = 0;
+ if ( (lastc == '\n' && m->g->cflags&REG_NEWLINE) ||
+ (lastc == OUT && !(m->eflags&REG_NOTBOL)) ) {
+ flagch = BOL;
+ i = m->g->nbol;
+ }
+ if ( (c == '\n' && m->g->cflags&REG_NEWLINE) ||
+ (c == OUT && !(m->eflags&REG_NOTEOL)) ) {
+ flagch = (flagch == BOL) ? BOLEOL : EOL;
+ i += m->g->neol;
+ }
+ if (i != 0) {
+ for (; i > 0; i--)
+ st = step(m->g, startst, stopst, st, flagch, st);
+ SP("sboleol", st, c);
+ }
+
+ /* how about a word boundary? */
+ if ( (flagch == BOL || (lastc != OUT && !ISWORD(lastc))) &&
+ (c != OUT && ISWORD(c)) ) {
+ flagch = BOW;
+ }
+ if ( (lastc != OUT && ISWORD(lastc)) &&
+ (flagch == EOL || (c != OUT && !ISWORD(c))) ) {
+ flagch = EOW;
+ }
+ if (flagch == BOW || flagch == EOW) {
+ st = step(m->g, startst, stopst, st, flagch, st);
+ SP("sboweow", st, c);
+ }
+
+ /* are we done? */
+ if (ISSET(st, stopst))
+ matchp = p;
+ if (EQ(st, empty) || p == stop)
+ break; /* NOTE BREAK OUT */
+
+ /* no, we must deal with this character */
+ ASSIGN(tmp, st);
+ ASSIGN(st, empty);
+ assert(c != OUT);
+ st = step(m->g, startst, stopst, tmp, c, st);
+ SP("saft", st, c);
+ assert(EQ(step(m->g, startst, stopst, st, NOTHING, st), st));
+ p++;
+ }
+
+ return(matchp);
+}
+
+
+/*
+ - step - map set of states reachable before char to set reachable after
+ == static states step(register struct re_guts *g, sopno start, sopno stop, \
+ == register states bef, int ch, register states aft);
+ == #define BOL (OUT+1)
+ == #define EOL (BOL+1)
+ == #define BOLEOL (BOL+2)
+ == #define NOTHING (BOL+3)
+ == #define BOW (BOL+4)
+ == #define EOW (BOL+5)
+ == #define CODEMAX (BOL+5) // highest code used
+ == #define NONCHAR(c) ((c) > CHAR_MAX)
+ == #define NNONCHAR (CODEMAX-CHAR_MAX)
+ */
+static states
+step(g, start, stop, bef, ch, aft)
+register struct re_guts *g;
+sopno start; /* start state within strip */
+sopno stop; /* state after stop state within strip */
+register states bef; /* states reachable before */
+int ch; /* character or NONCHAR code */
+register states aft; /* states already known reachable after */
+{
+ register cset *cs;
+ register sop s;
+ register sopno pc;
+ register onestate here; /* note, macros know this name */
+ register sopno look;
+ register int i;
+
+ for (pc = start, INIT(here, pc); pc != stop; pc++, INC(here)) {
+ s = g->strip[pc];
+ switch (OP(s)) {
+ case OEND:
+ assert(pc == stop-1);
+ break;
+ case OCHAR:
+ /* only characters can match */
+ assert(!NONCHAR(ch) || ch != (char)OPND(s));
+ if (ch == (char)OPND(s))
+ FWD(aft, bef, 1);
+ break;
+ case OBOL:
+ if (ch == BOL || ch == BOLEOL)
+ FWD(aft, bef, 1);
+ break;
+ case OEOL:
+ if (ch == EOL || ch == BOLEOL)
+ FWD(aft, bef, 1);
+ break;
+ case OBOW:
+ if (ch == BOW)
+ FWD(aft, bef, 1);
+ break;
+ case OEOW:
+ if (ch == EOW)
+ FWD(aft, bef, 1);
+ break;
+ case OANY:
+ if (!NONCHAR(ch))
+ FWD(aft, bef, 1);
+ break;
+ case OANYOF:
+ cs = &g->sets[OPND(s)];
+ if (!NONCHAR(ch) && CHIN(cs, ch))
+ FWD(aft, bef, 1);
+ break;
+ case OBACK_: /* ignored here */
+ case O_BACK:
+ FWD(aft, aft, 1);
+ break;
+ case OPLUS_: /* forward, this is just an empty */
+ FWD(aft, aft, 1);
+ break;
+ case O_PLUS: /* both forward and back */
+ FWD(aft, aft, 1);
+ i = ISSETBACK(aft, OPND(s));
+ BACK(aft, aft, OPND(s));
+ if (!i && ISSETBACK(aft, OPND(s))) {
+ /* oho, must reconsider loop body */
+ pc -= OPND(s) + 1;
+ INIT(here, pc);
+ }
+ break;
+ case OQUEST_: /* two branches, both forward */
+ FWD(aft, aft, 1);
+ FWD(aft, aft, OPND(s));
+ break;
+ case O_QUEST: /* just an empty */
+ FWD(aft, aft, 1);
+ break;
+ case OLPAREN: /* not significant here */
+ case ORPAREN:
+ FWD(aft, aft, 1);
+ break;
+ case OCH_: /* mark the first two branches */
+ FWD(aft, aft, 1);
+ assert(OP(g->strip[pc+OPND(s)]) == OOR2);
+ FWD(aft, aft, OPND(s));
+ break;
+ case OOR1: /* done a branch, find the O_CH */
+ if (ISSTATEIN(aft, here)) {
+ for (look = 1;
+ OP(s = g->strip[pc+look]) != O_CH;
+ look += OPND(s))
+ assert(OP(s) == OOR2);
+ FWD(aft, aft, look);
+ }
+ break;
+ case OOR2: /* propagate OCH_'s marking */
+ FWD(aft, aft, 1);
+ if (OP(g->strip[pc+OPND(s)]) != O_CH) {
+ assert(OP(g->strip[pc+OPND(s)]) == OOR2);
+ FWD(aft, aft, OPND(s));
+ }
+ break;
+ case O_CH: /* just empty */
+ FWD(aft, aft, 1);
+ break;
+ default: /* ooooops... */
+ assert(nope);
+ break;
+ }
+ }
+
+ return(aft);
+}
+
+#ifdef REDEBUG
+/*
+ - print - print a set of states
+ == #ifdef REDEBUG
+ == static void print(struct match *m, char *caption, states st, \
+ == int ch, FILE *d);
+ == #endif
+ */
+static void
+print(m, caption, st, ch, d)
+struct match *m;
+char *caption;
+states st;
+int ch;
+FILE *d;
+{
+ register struct re_guts *g = m->g;
+ register int i;
+ register int first = 1;
+ char buf[10];
+
+ if (!(m->eflags&REG_TRACE))
+ return;
+
+ fprintf(d, "%s", caption);
+ if (ch != '\0')
+ fprintf(d, " %s", printchar(ch,buf));
+ for (i = 0; i < g->nstates; i++)
+ if (ISSET(st, i)) {
+ fprintf(d, "%s%d", (first) ? "\t" : ", ", i);
+ first = 0;
+ }
+ fprintf(d, "\n");
+}
+
+/*
+ - at - print current situation
+ == #ifdef REDEBUG
+ == static void at(struct match *m, char *title, char *start, char *stop, \
+ == sopno startst, sopno stopst);
+ == #endif
+ */
+static void
+at(m, title, start, stop, startst, stopst)
+struct match *m;
+char *title;
+char *start;
+char *stop;
+sopno startst;
+sopno stopst;
+{
+ char buf[10];
+ if (!(m->eflags&REG_TRACE))
+ return;
+
+ printf("%s %s-", title, printchar(*start,buf));
+ printf("%s ", printchar(*stop,buf));
+ printf("%ld-%ld\n", (long)startst, (long)stopst,buf);
+}
+
+#ifndef PCHARDONE
+#define PCHARDONE /* never again */
+/*
+ - printchar - make a character printable
+ == #ifdef REDEBUG
+ == static char *printchar(int ch);
+ == #endif
+ *
+ * Is this identical to regchar() over in debug.c? Well, yes. But a
+ * duplicate here avoids having a debugging-capable regexec.o tied to
+ * a matching debug.o, and this is convenient. It all disappears in
+ * the non-debug compilation anyway, so it doesn't matter much.
+ */
+static char * /* -> representation */
+printchar(ch,pbuf)
+int ch;
+char *pbuf;
+{
+ if (isprint(ch) || ch == ' ')
+ sprintf(pbuf, "%c", ch);
+ else
+ sprintf(pbuf, "\\%o", ch);
+ return(pbuf);
+}
+#endif
+#endif
+
+#undef matcher
+#undef fast
+#undef slow
+#undef dissect
+#undef backref
+#undef step
+#undef print
+#undef at
+#undef match
diff --git a/regex/engine.ih b/regex/engine.ih
new file mode 100644
index 00000000000..c65733b5756
--- /dev/null
+++ b/regex/engine.ih
@@ -0,0 +1,35 @@
+/* ========= begin header generated by ./mkh ========= */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* === engine.c === */
+static int matcher(register struct re_guts *g, char *string, size_t nmatch, regmatch_t pmatch[], int eflags);
+static char *dissect(register struct match *m, char *start, char *stop, sopno startst, sopno stopst);
+static char *backref(register struct match *m, char *start, char *stop, sopno startst, sopno stopst, sopno lev);
+static char *fast(register struct match *m, char *start, char *stop, sopno startst, sopno stopst);
+static char *slow(register struct match *m, char *start, char *stop, sopno startst, sopno stopst);
+static states step(register struct re_guts *g, sopno start, sopno stop, register states bef, int ch, register states aft);
+#define BOL (OUT+1)
+#define EOL (BOL+1)
+#define BOLEOL (BOL+2)
+#define NOTHING (BOL+3)
+#define BOW (BOL+4)
+#define EOW (BOL+5)
+#define CODEMAX (BOL+5) /* highest code used */
+#define NONCHAR(c) ((c) > CHAR_MAX)
+#define NNONCHAR (CODEMAX-CHAR_MAX)
+#ifdef REDEBUG
+static void print(struct match *m, char *caption, states st, int ch, FILE *d);
+#endif
+#ifdef REDEBUG
+static void at(struct match *m, char *title, char *start, char *stop, sopno startst, sopno stopst);
+#endif
+#ifdef REDEBUG
+static char *printchar(int ch,char *buf);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+/* ========= end header generated by ./mkh ========= */
diff --git a/regex/main.c b/regex/main.c
new file mode 100644
index 00000000000..beed2738b1d
--- /dev/null
+++ b/regex/main.c
@@ -0,0 +1,509 @@
+#include <global.h>
+#include <m_string.h>
+#include <sys/types.h>
+#include <regex.h>
+#include <assert.h>
+
+#include "main.ih"
+
+char *progname;
+int debug = 0;
+int line = 0;
+int status = 0;
+
+int copts = REG_EXTENDED;
+int eopts = 0;
+regoff_t startoff = 0;
+regoff_t endoff = 0;
+
+
+extern int split();
+extern void regprint();
+
+/*
+ - main - do the simple case, hand off to regress() for regression
+ */
+int main(argc, argv)
+int argc;
+char *argv[];
+{
+ regex_t re;
+# define NS 10
+ regmatch_t subs[NS];
+ char erbuf[100];
+ int err;
+ size_t len;
+ int c;
+ int errflg = 0;
+ register int i;
+ extern int optind;
+ extern char *optarg;
+
+ progname = argv[0];
+
+ while ((c = getopt(argc, argv, "c:e:S:E:x")) != EOF)
+ switch (c) {
+ case 'c': /* compile options */
+ copts = options('c', optarg);
+ break;
+ case 'e': /* execute options */
+ eopts = options('e', optarg);
+ break;
+ case 'S': /* start offset */
+ startoff = (regoff_t)atoi(optarg);
+ break;
+ case 'E': /* end offset */
+ endoff = (regoff_t)atoi(optarg);
+ break;
+ case 'x': /* Debugging. */
+ debug++;
+ break;
+ case '?':
+ default:
+ errflg++;
+ break;
+ }
+ if (errflg) {
+ fprintf(stderr, "usage: %s ", progname);
+ fprintf(stderr, "[-c copt][-C][-d] [re]\n");
+ exit(2);
+ }
+
+ if (optind >= argc) {
+ regress(stdin);
+ exit(status);
+ }
+
+ err = regcomp(&re, argv[optind++], copts);
+ if (err) {
+ len = regerror(err, &re, erbuf, sizeof(erbuf));
+ fprintf(stderr, "error %s, %d/%d `%s'\n",
+ eprint(err), len, sizeof(erbuf), erbuf);
+ exit(status);
+ }
+ regprint(&re, stdout);
+
+ if (optind >= argc) {
+ regfree(&re);
+ exit(status);
+ }
+
+ if (eopts&REG_STARTEND) {
+ subs[0].rm_so = startoff;
+ subs[0].rm_eo = strlen(argv[optind]) - endoff;
+ }
+ err = regexec(&re, argv[optind], (size_t)NS, subs, eopts);
+ if (err) {
+ len = regerror(err, &re, erbuf, sizeof(erbuf));
+ fprintf(stderr, "error %s, %d/%d `%s'\n",
+ eprint(err), len, sizeof(erbuf), erbuf);
+ exit(status);
+ }
+ if (!(copts&REG_NOSUB)) {
+ len = (int)(subs[0].rm_eo - subs[0].rm_so);
+ if (subs[0].rm_so != -1) {
+ if (len != 0)
+ printf("match `%.*s'\n", len,
+ argv[optind] + subs[0].rm_so);
+ else
+ printf("match `'@%.1s\n",
+ argv[optind] + subs[0].rm_so);
+ }
+ for (i = 1; i < NS; i++)
+ if (subs[i].rm_so != -1)
+ printf("(%d) `%.*s'\n", i,
+ (int)(subs[i].rm_eo - subs[i].rm_so),
+ argv[optind] + subs[i].rm_so);
+ }
+ exit(status);
+}
+
+/*
+ - regress - main loop of regression test
+ == void regress(FILE *in);
+ */
+void
+regress(in)
+FILE *in;
+{
+ char inbuf[1000];
+# define MAXF 10
+ char *f[MAXF];
+ int nf;
+ int i;
+ char erbuf[100];
+ size_t ne;
+ char *badpat = "invalid regular expression";
+# define SHORT 10
+ char *bpname = "REG_BADPAT";
+ regex_t re;
+
+ while (fgets(inbuf, sizeof(inbuf), in) != NULL) {
+ line++;
+ if (inbuf[0] == '#' || inbuf[0] == '\n')
+ continue; /* NOTE CONTINUE */
+ inbuf[strlen(inbuf)-1] = '\0'; /* get rid of stupid \n */
+ if (debug)
+ fprintf(stdout, "%d:\n", line);
+ nf = split(inbuf, f, MAXF, "\t\t");
+ if (nf < 3) {
+ fprintf(stderr, "bad input, line %d\n", line);
+ exit(1);
+ }
+ for (i = 0; i < nf; i++)
+ if (strcmp(f[i], "\"\"") == 0)
+ f[i] = "";
+ if (nf <= 3)
+ f[3] = NULL;
+ if (nf <= 4)
+ f[4] = NULL;
+ rx_try(f[0], f[1], f[2], f[3], f[4], options('c', f[1]));
+ if (opt('&', f[1])) /* try with either type of RE */
+ rx_try(f[0], f[1], f[2], f[3], f[4],
+ options('c', f[1]) &~ REG_EXTENDED);
+ }
+
+ ne = regerror(REG_BADPAT, (regex_t *)NULL, erbuf, sizeof(erbuf));
+ if (strcmp(erbuf, badpat) != 0 || ne != strlen(badpat)+1) {
+ fprintf(stderr, "end: regerror() test gave `%s' not `%s'\n",
+ erbuf, badpat);
+ status = 1;
+ }
+ ne = regerror(REG_BADPAT, (regex_t *)NULL, erbuf, (size_t)SHORT);
+ if (strncmp(erbuf, badpat, SHORT-1) != 0 || erbuf[SHORT-1] != '\0' ||
+ ne != strlen(badpat)+1) {
+ fprintf(stderr, "end: regerror() short test gave `%s' not `%.*s'\n",
+ erbuf, SHORT-1, badpat);
+ status = 1;
+ }
+ ne = regerror(REG_ITOA|REG_BADPAT, (regex_t *)NULL, erbuf, sizeof(erbuf));
+ if (strcmp(erbuf, bpname) != 0 || ne != strlen(bpname)+1) {
+ fprintf(stderr, "end: regerror() ITOA test gave `%s' not `%s'\n",
+ erbuf, bpname);
+ status = 1;
+ }
+ re.re_endp = bpname;
+ ne = regerror(REG_ATOI, &re, erbuf, sizeof(erbuf));
+ if (atoi(erbuf) != (int)REG_BADPAT) {
+ fprintf(stderr, "end: regerror() ATOI test gave `%s' not `%ld'\n",
+ erbuf, (long)REG_BADPAT);
+ status = 1;
+ } else if (ne != strlen(erbuf)+1) {
+ fprintf(stderr, "end: regerror() ATOI test len(`%s') = %ld\n",
+ erbuf, (long)REG_BADPAT);
+ status = 1;
+ }
+}
+
+/*
+ - rx_try - try it, and report on problems
+ == void rx_try(char *f0, char *f1, char *f2, char *f3, char *f4, int opts);
+ */
+void
+rx_try(f0, f1, f2, f3, f4, opts)
+char *f0;
+char *f1;
+char *f2;
+char *f3;
+char *f4;
+int opts; /* may not match f1 */
+{
+ regex_t re;
+# define NSUBS 10
+ regmatch_t subs[NSUBS];
+# define NSHOULD 15
+ char *should[NSHOULD];
+ int nshould;
+ char erbuf[100];
+ int err;
+ int len;
+ char *type = (opts & REG_EXTENDED) ? "ERE" : "BRE";
+ register int i;
+ char *grump;
+ char f0copy[1000];
+ char f2copy[1000];
+
+ strcpy(f0copy, f0);
+ re.re_endp = (opts&REG_PEND) ? f0copy + strlen(f0copy) : NULL;
+ fixstr(f0copy);
+ err = regcomp(&re, f0copy, opts);
+ if (err != 0 && (!opt('C', f1) || err != efind(f2))) {
+ /* unexpected error or wrong error */
+ len = regerror(err, &re, erbuf, sizeof(erbuf));
+ fprintf(stderr, "%d: %s error %s, %d/%d `%s'\n",
+ line, type, eprint(err), len,
+ sizeof(erbuf), erbuf);
+ status = 1;
+ } else if (err == 0 && opt('C', f1)) {
+ /* unexpected success */
+ fprintf(stderr, "%d: %s should have given REG_%s\n",
+ line, type, f2);
+ status = 1;
+ err = 1; /* so we won't try regexec */
+ }
+
+ if (err != 0) {
+ regfree(&re);
+ return;
+ }
+
+ strcpy(f2copy, f2);
+ fixstr(f2copy);
+
+ if (options('e', f1)&REG_STARTEND) {
+ if (strchr(f2, '(') == NULL || strchr(f2, ')') == NULL)
+ fprintf(stderr, "%d: bad STARTEND syntax\n", line);
+ subs[0].rm_so = strchr(f2, '(') - f2 + 1;
+ subs[0].rm_eo = strchr(f2, ')') - f2;
+ }
+ err = regexec(&re, f2copy, NSUBS, subs, options('e', f1));
+
+ if (err != 0 && (f3 != NULL || err != REG_NOMATCH)) {
+ /* unexpected error or wrong error */
+ len = regerror(err, &re, erbuf, sizeof(erbuf));
+ fprintf(stderr, "%d: %s exec error %s, %d/%d `%s'\n",
+ line, type, eprint(err), len,
+ sizeof(erbuf), erbuf);
+ status = 1;
+ } else if (err != 0) {
+ /* nothing more to check */
+ } else if (f3 == NULL) {
+ /* unexpected success */
+ fprintf(stderr, "%d: %s exec should have failed\n",
+ line, type);
+ status = 1;
+ err = 1; /* just on principle */
+ } else if (opts&REG_NOSUB) {
+ /* nothing more to check */
+ } else if ((grump = check(f2, subs[0], f3)) != NULL) {
+ fprintf(stderr, "%d: %s %s\n", line, type, grump);
+ status = 1;
+ err = 1;
+ }
+
+ if (err != 0 || f4 == NULL) {
+ regfree(&re);
+ return;
+ }
+
+ for (i = 1; i < NSHOULD; i++)
+ should[i] = NULL;
+ nshould = split(f4, should+1, NSHOULD-1, ",");
+ if (nshould == 0) {
+ nshould = 1;
+ should[1] = "";
+ }
+ for (i = 1; i < NSUBS; i++) {
+ grump = check(f2, subs[i], should[i]);
+ if (grump != NULL) {
+ fprintf(stderr, "%d: %s $%d %s\n", line,
+ type, i, grump);
+ status = 1;
+ err = 1;
+ }
+ }
+
+ regfree(&re);
+}
+
+/*
+ - options - pick options out of a regression-test string
+ == int options(int type, char *s);
+ */
+int
+options(type, s)
+int type; /* 'c' compile, 'e' exec */
+char *s;
+{
+ register char *p;
+ register int o = (type == 'c') ? copts : eopts;
+ register char *legal = (type == 'c') ? "bisnmp" : "^$#tl";
+
+ for (p = s; *p != '\0'; p++)
+ if (strchr(legal, *p) != NULL)
+ switch (*p) {
+ case 'b':
+ o &= ~REG_EXTENDED;
+ break;
+ case 'i':
+ o |= REG_ICASE;
+ break;
+ case 's':
+ o |= REG_NOSUB;
+ break;
+ case 'n':
+ o |= REG_NEWLINE;
+ break;
+ case 'm':
+ o &= ~REG_EXTENDED;
+ o |= REG_NOSPEC;
+ break;
+ case 'p':
+ o |= REG_PEND;
+ break;
+ case '^':
+ o |= REG_NOTBOL;
+ break;
+ case '$':
+ o |= REG_NOTEOL;
+ break;
+ case '#':
+ o |= REG_STARTEND;
+ break;
+ case 't': /* trace */
+ o |= REG_TRACE;
+ break;
+ case 'l': /* force long representation */
+ o |= REG_LARGE;
+ break;
+ case 'r': /* force backref use */
+ o |= REG_BACKR;
+ break;
+ }
+ return(o);
+}
+
+/*
+ - opt - is a particular option in a regression string?
+ == int opt(int c, char *s);
+ */
+int /* predicate */
+opt(c, s)
+int c;
+char *s;
+{
+ return(strchr(s, c) != NULL);
+}
+
+/*
+ - fixstr - transform magic characters in strings
+ == void fixstr(register char *p);
+ */
+void
+fixstr(p)
+register char *p;
+{
+ if (p == NULL)
+ return;
+
+ for (; *p != '\0'; p++)
+ if (*p == 'N')
+ *p = '\n';
+ else if (*p == 'T')
+ *p = '\t';
+ else if (*p == 'S')
+ *p = ' ';
+ else if (*p == 'Z')
+ *p = '\0';
+}
+
+/*
+ - check - check a substring match
+ == char *check(char *str, regmatch_t sub, char *should);
+ */
+char * /* NULL or complaint */
+check(str, sub, should)
+char *str;
+regmatch_t sub;
+char *should;
+{
+ register int len;
+ register int shlen;
+ register char *p;
+ static char grump[500];
+ register char *at = NULL;
+
+ if (should != NULL && strcmp(should, "-") == 0)
+ should = NULL;
+ if (should != NULL && should[0] == '@') {
+ at = should + 1;
+ should = "";
+ }
+
+ /* check rm_so and rm_eo for consistency */
+ if (sub.rm_so > sub.rm_eo || (sub.rm_so == -1 && sub.rm_eo != -1) ||
+ (sub.rm_so != -1 && sub.rm_eo == -1) ||
+ (sub.rm_so != -1 && sub.rm_so < 0) ||
+ (sub.rm_eo != -1 && sub.rm_eo < 0) ) {
+ sprintf(grump, "start %ld end %ld", (long)sub.rm_so,
+ (long)sub.rm_eo);
+ return(grump);
+ }
+
+ /* check for no match */
+ if (sub.rm_so == -1 && should == NULL)
+ return(NULL);
+ if (sub.rm_so == -1)
+ return("did not match");
+
+ /* check for in range */
+ if ((int) sub.rm_eo > (int) strlen(str)) {
+ sprintf(grump, "start %ld end %ld, past end of string",
+ (long)sub.rm_so, (long)sub.rm_eo);
+ return(grump);
+ }
+
+ len = (int)(sub.rm_eo - sub.rm_so);
+ shlen = (int)strlen(should);
+ p = str + sub.rm_so;
+
+ /* check for not supposed to match */
+ if (should == NULL) {
+ sprintf(grump, "matched `%.*s'", len, p);
+ return(grump);
+ }
+
+ /* check for wrong match */
+ if (len != shlen || strncmp(p, should, (size_t)shlen) != 0) {
+ sprintf(grump, "matched `%.*s' instead", len, p);
+ return(grump);
+ }
+ if (shlen > 0)
+ return(NULL);
+
+ /* check null match in right place */
+ if (at == NULL)
+ return(NULL);
+ shlen = strlen(at);
+ if (shlen == 0)
+ shlen = 1; /* force check for end-of-string */
+ if (strncmp(p, at, shlen) != 0) {
+ sprintf(grump, "matched null at `%.20s'", p);
+ return(grump);
+ }
+ return(NULL);
+}
+
+/*
+ - eprint - convert error number to name
+ == static char *eprint(int err);
+ */
+static char *
+eprint(err)
+int err;
+{
+ static char epbuf[100];
+ size_t len;
+
+ len = regerror(REG_ITOA|err, (regex_t *)NULL, epbuf, sizeof(epbuf));
+ assert(len <= sizeof(epbuf));
+ return(epbuf);
+}
+
+/*
+ - efind - convert error name to number
+ == static int efind(char *name);
+ */
+static int
+efind(name)
+char *name;
+{
+ static char efbuf[100];
+ regex_t re;
+
+ sprintf(efbuf, "REG_%s", name);
+ assert(strlen(efbuf) < sizeof(efbuf));
+ re.re_endp = efbuf;
+ (void) regerror(REG_ATOI, &re, efbuf, sizeof(efbuf));
+ return(atoi(efbuf));
+}
diff --git a/regex/main.ih b/regex/main.ih
new file mode 100644
index 00000000000..4b16e676ad3
--- /dev/null
+++ b/regex/main.ih
@@ -0,0 +1,19 @@
+/* ========= begin header generated by ./mkh ========= */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* === main.c === */
+void regress(FILE *in);
+void rx_try(char *f0, char *f1, char *f2, char *f3, char *f4, int opts);
+int options(int type, char *s);
+int opt(int c, char *s);
+void fixstr(register char *p);
+char *check(char *str, regmatch_t sub, char *should);
+static char *eprint(int err);
+static int efind(char *name);
+
+#ifdef __cplusplus
+}
+#endif
+/* ========= end header generated by ./mkh ========= */
diff --git a/regex/make-ccc b/regex/make-ccc
new file mode 100755
index 00000000000..561c5a9bddc
--- /dev/null
+++ b/regex/make-ccc
@@ -0,0 +1,3 @@
+ccc -DHAVE_CONFIG_H -I. -I. -I.. -I./../include -I../include -O -DDBUG_OFF -fast -O3 -c regerror.c regcomp.c regexec.c regfree.c reginit.c
+rm libregex.a
+ar -cr libregex.a regerror.o
diff --git a/regex/regcomp.c b/regex/regcomp.c
new file mode 100644
index 00000000000..5990b121f9b
--- /dev/null
+++ b/regex/regcomp.c
@@ -0,0 +1,1627 @@
+#include <global.h>
+#include <m_string.h>
+#include <m_ctype.h>
+#include <regex.h>
+#ifdef __WIN__
+#include <limits.h>
+#endif
+
+#include "utils.h"
+#include "regex2.h"
+
+#include "cclass.h"
+#include "cname.h"
+
+/*
+ * parse structure, passed up and down to avoid global variables and
+ * other clumsinesses
+ */
+struct parse {
+ char *next; /* next character in RE */
+ char *end; /* end of string (-> NUL normally) */
+ int error; /* has an error been seen? */
+ sop *strip; /* malloced strip */
+ sopno ssize; /* malloced strip size (allocated) */
+ sopno slen; /* malloced strip length (used) */
+ int ncsalloc; /* number of csets allocated */
+ struct re_guts *g;
+# define NPAREN 10 /* we need to remember () 1-9 for back refs */
+ sopno pbegin[NPAREN]; /* -> ( ([0] unused) */
+ sopno pend[NPAREN]; /* -> ) ([0] unused) */
+};
+
+#include "regcomp.ih"
+
+static char nuls[10]; /* place to point scanner in event of error */
+
+struct cclass cclasses[CCLASS_LAST+1]= {
+ { "alnum", "","" },
+ { "alpha", "","" },
+ { "blank", "","" },
+ { "cntrl", "","" },
+ { "digit", "","" },
+ { "graph", "","" },
+ { "lower", "","" },
+ { "print", "","" },
+ { "punct", "","" },
+ { "space", "","" },
+ { "upper", "","" },
+ { "xdigit", "","" },
+ { NULL,NULL,NULL }
+};
+
+/*
+ * macros for use with parse structure
+ * BEWARE: these know that the parse structure is named `p' !!!
+ */
+#define PEEK() (*p->next)
+#define PEEK2() (*(p->next+1))
+#define MORE() (p->next < p->end)
+#define MORE2() (p->next+1 < p->end)
+#define SEE(c) (MORE() && PEEK() == (c))
+#define SEETWO(a, b) (MORE() && MORE2() && PEEK() == (a) && PEEK2() == (b))
+#define EAT(c) ((SEE(c)) ? (NEXT(), 1) : 0)
+#define EATTWO(a, b) ((SEETWO(a, b)) ? (NEXT2(), 1) : 0)
+#define NEXT() (p->next++)
+#define NEXT2() (p->next += 2)
+#define NEXTn(n) (p->next += (n))
+#define GETNEXT() (*p->next++)
+#define SETERROR(e) seterr(p, (e))
+#define REQUIRE(co, e) ((co) || SETERROR(e))
+#define MUSTSEE(c, e) (REQUIRE(MORE() && PEEK() == (c), e))
+#define MUSTEAT(c, e) (REQUIRE(MORE() && GETNEXT() == (c), e))
+#define MUSTNOTSEE(c, e) (REQUIRE(!MORE() || PEEK() != (c), e))
+#define EMIT(op, sopnd) doemit(p, (sop)(op), (size_t)(sopnd))
+#define INSERT(op, pos) doinsert(p, (sop)(op), HERE()-(pos)+1, pos)
+#define AHEAD(pos) dofwd(p, pos, HERE()-(pos))
+#define ASTERN(sop, pos) EMIT(sop, HERE()-pos)
+#define HERE() (p->slen)
+#define THERE() (p->slen - 1)
+#define THERETHERE() (p->slen - 2)
+#define DROP(n) (p->slen -= (n))
+
+#ifndef NDEBUG
+static int never = 0; /* for use in asserts; shuts lint up */
+#else
+#define never 0 /* some <assert.h>s have bugs too */
+#endif
+
+/*
+ - regcomp - interface for parser and compilation
+ = extern int regcomp(regex_t *, const char *, int);
+ = #define REG_BASIC 0000
+ = #define REG_EXTENDED 0001
+ = #define REG_ICASE 0002
+ = #define REG_NOSUB 0004
+ = #define REG_NEWLINE 0010
+ = #define REG_NOSPEC 0020
+ = #define REG_PEND 0040
+ = #define REG_DUMP 0200
+ */
+int /* 0 success, otherwise REG_something */
+regcomp(preg, pattern, cflags)
+regex_t *preg;
+const char *pattern;
+int cflags;
+{
+ struct parse pa;
+ register struct re_guts *g;
+ register struct parse *p = &pa;
+ register int i;
+ register size_t len;
+#ifdef REDEBUG
+# define GOODFLAGS(f) (f)
+#else
+# define GOODFLAGS(f) ((f)&~REG_DUMP)
+#endif
+
+ regex_init(); /* Init cclass if neaded */
+ cflags = GOODFLAGS(cflags);
+ if ((cflags&REG_EXTENDED) && (cflags&REG_NOSPEC))
+ return(REG_INVARG);
+
+ if (cflags&REG_PEND) {
+ if (preg->re_endp < pattern)
+ return(REG_INVARG);
+ len = preg->re_endp - pattern;
+ } else
+ len = strlen((char *)pattern);
+
+ /* do the mallocs early so failure handling is easy */
+ g = (struct re_guts *)malloc(sizeof(struct re_guts) +
+ (NC-1)*sizeof(cat_t));
+ if (g == NULL)
+ return(REG_ESPACE);
+ p->ssize = len/(size_t)2*(size_t)3 + (size_t)1; /* ugh */
+ p->strip = (sop *)malloc(p->ssize * sizeof(sop));
+ p->slen = 0;
+ if (p->strip == NULL) {
+ free((char *)g);
+ return(REG_ESPACE);
+ }
+
+ /* set things up */
+ p->g = g;
+ p->next = (char *)pattern; /* convenience; we do not modify it */
+ p->end = p->next + len;
+ p->error = 0;
+ p->ncsalloc = 0;
+ for (i = 0; i < NPAREN; i++) {
+ p->pbegin[i] = 0;
+ p->pend[i] = 0;
+ }
+ g->csetsize = NC;
+ g->sets = NULL;
+ g->setbits = NULL;
+ g->ncsets = 0;
+ g->cflags = cflags;
+ g->iflags = 0;
+ g->nbol = 0;
+ g->neol = 0;
+ g->must = NULL;
+ g->mlen = 0;
+ g->nsub = 0;
+ g->ncategories = 1; /* category 0 is "everything else" */
+ g->categories = &g->catspace[-(CHAR_MIN)];
+ (void) memset((char *)g->catspace, 0, NC*sizeof(cat_t));
+ g->backrefs = 0;
+
+ /* do it */
+ EMIT(OEND, 0);
+ g->firststate = THERE();
+ if (cflags&REG_EXTENDED)
+ p_ere(p, OUT);
+ else if (cflags&REG_NOSPEC)
+ p_str(p);
+ else
+ p_bre(p, OUT, OUT);
+ EMIT(OEND, 0);
+ g->laststate = THERE();
+
+ /* tidy up loose ends and fill things in */
+ categorize(p, g);
+ stripsnug(p, g);
+ findmust(p, g);
+ g->nplus = pluscount(p, g);
+ g->magic = MAGIC2;
+ preg->re_nsub = g->nsub;
+ preg->re_g = g;
+ preg->re_magic = MAGIC1;
+#ifndef REDEBUG
+ /* not debugging, so can't rely on the assert() in regexec() */
+ if (g->iflags&BAD)
+ SETERROR(REG_ASSERT);
+#endif
+
+ /* win or lose, we're done */
+ if (p->error != 0) /* lose */
+ regfree(preg);
+ return(p->error);
+}
+
+/*
+ - p_ere - ERE parser top level, concatenation and alternation
+ == static void p_ere(register struct parse *p, int stop);
+ */
+static void
+p_ere(p, stop)
+register struct parse *p;
+int stop; /* character this ERE should end at */
+{
+ register char c;
+ register sopno prevback;
+ register sopno prevfwd;
+ register sopno conc;
+ register int first = 1; /* is this the first alternative? */
+ LINT_INIT(prevback); LINT_INIT(prevfwd);
+ for (;;) {
+ /* do a bunch of concatenated expressions */
+ conc = HERE();
+ while (MORE() && (c = PEEK()) != '|' && c != stop)
+ p_ere_exp(p);
+ REQUIRE(HERE() != conc, REG_EMPTY); /* require nonempty */
+
+ if (!EAT('|'))
+ break; /* NOTE BREAK OUT */
+
+ if (first) {
+ INSERT(OCH_, conc); /* offset is wrong */
+ prevfwd = conc;
+ prevback = conc;
+ first = 0;
+ }
+ ASTERN(OOR1, prevback);
+ prevback = THERE();
+ AHEAD(prevfwd); /* fix previous offset */
+ prevfwd = HERE();
+ EMIT(OOR2, 0); /* offset is very wrong */
+ }
+
+ if (!first) { /* tail-end fixups */
+ AHEAD(prevfwd);
+ ASTERN(O_CH, prevback);
+ }
+
+ assert(!MORE() || SEE(stop));
+}
+
+/*
+ - p_ere_exp - parse one subERE, an atom possibly followed by a repetition op
+ == static void p_ere_exp(register struct parse *p);
+ */
+static void
+p_ere_exp(p)
+register struct parse *p;
+{
+ register char c;
+ register sopno pos;
+ register int count;
+ register int count2;
+ register sopno subno;
+ int wascaret = 0;
+
+ assert(MORE()); /* caller should have ensured this */
+ c = GETNEXT();
+
+ pos = HERE();
+ switch (c) {
+ case '(':
+ REQUIRE(MORE(), REG_EPAREN);
+ p->g->nsub++;
+ subno = p->g->nsub;
+ if (subno < NPAREN)
+ p->pbegin[subno] = HERE();
+ EMIT(OLPAREN, subno);
+ if (!SEE(')'))
+ p_ere(p, ')');
+ if (subno < NPAREN) {
+ p->pend[subno] = HERE();
+ assert(p->pend[subno] != 0);
+ }
+ EMIT(ORPAREN, subno);
+ MUSTEAT(')', REG_EPAREN);
+ break;
+#ifndef POSIX_MISTAKE
+ case ')': /* happens only if no current unmatched ( */
+ /*
+ * You may ask, why the ifndef? Because I didn't notice
+ * this until slightly too late for 1003.2, and none of the
+ * other 1003.2 regular-expression reviewers noticed it at
+ * all. So an unmatched ) is legal POSIX, at least until
+ * we can get it fixed.
+ */
+ SETERROR(REG_EPAREN);
+ break;
+#endif
+ case '^':
+ EMIT(OBOL, 0);
+ p->g->iflags |= USEBOL;
+ p->g->nbol++;
+ wascaret = 1;
+ break;
+ case '$':
+ EMIT(OEOL, 0);
+ p->g->iflags |= USEEOL;
+ p->g->neol++;
+ break;
+ case '|':
+ SETERROR(REG_EMPTY);
+ break;
+ case '*':
+ case '+':
+ case '?':
+ SETERROR(REG_BADRPT);
+ break;
+ case '.':
+ if (p->g->cflags&REG_NEWLINE)
+ nonnewline(p);
+ else
+ EMIT(OANY, 0);
+ break;
+ case '[':
+ p_bracket(p);
+ break;
+ case '\\':
+ REQUIRE(MORE(), REG_EESCAPE);
+ c = GETNEXT();
+ ordinary(p, c);
+ break;
+ case '{': /* okay as ordinary except if digit follows */
+ REQUIRE(!MORE() || !isdigit(PEEK()), REG_BADRPT);
+ /* FALLTHROUGH */
+ default:
+ ordinary(p, c);
+ break;
+ }
+
+ if (!MORE())
+ return;
+ c = PEEK();
+ /* we call { a repetition if followed by a digit */
+ if (!( c == '*' || c == '+' || c == '?' ||
+ (c == '{' && MORE2() && isdigit(PEEK2())) ))
+ return; /* no repetition, we're done */
+ NEXT();
+
+ REQUIRE(!wascaret, REG_BADRPT);
+ switch (c) {
+ case '*': /* implemented as +? */
+ /* this case does not require the (y|) trick, noKLUDGE */
+ INSERT(OPLUS_, pos);
+ ASTERN(O_PLUS, pos);
+ INSERT(OQUEST_, pos);
+ ASTERN(O_QUEST, pos);
+ break;
+ case '+':
+ INSERT(OPLUS_, pos);
+ ASTERN(O_PLUS, pos);
+ break;
+ case '?':
+ /* KLUDGE: emit y? as (y|) until subtle bug gets fixed */
+ INSERT(OCH_, pos); /* offset slightly wrong */
+ ASTERN(OOR1, pos); /* this one's right */
+ AHEAD(pos); /* fix the OCH_ */
+ EMIT(OOR2, 0); /* offset very wrong... */
+ AHEAD(THERE()); /* ...so fix it */
+ ASTERN(O_CH, THERETHERE());
+ break;
+ case '{':
+ count = p_count(p);
+ if (EAT(',')) {
+ if (isdigit(PEEK())) {
+ count2 = p_count(p);
+ REQUIRE(count <= count2, REG_BADBR);
+ } else /* single number with comma */
+ count2 = RE_INFINITY;
+ } else /* just a single number */
+ count2 = count;
+ repeat(p, pos, count, count2);
+ if (!EAT('}')) { /* error heuristics */
+ while (MORE() && PEEK() != '}')
+ NEXT();
+ REQUIRE(MORE(), REG_EBRACE);
+ SETERROR(REG_BADBR);
+ }
+ break;
+ }
+
+ if (!MORE())
+ return;
+ c = PEEK();
+ if (!( c == '*' || c == '+' || c == '?' ||
+ (c == '{' && MORE2() && isdigit(PEEK2())) ) )
+ return;
+ SETERROR(REG_BADRPT);
+}
+
+/*
+ - p_str - string (no metacharacters) "parser"
+ == static void p_str(register struct parse *p);
+ */
+static void
+p_str(p)
+register struct parse *p;
+{
+ REQUIRE(MORE(), REG_EMPTY);
+ while (MORE())
+ ordinary(p, GETNEXT());
+}
+
+/*
+ - p_bre - BRE parser top level, anchoring and concatenation
+ == static void p_bre(register struct parse *p, register int end1, \
+ == register int end2);
+ * Giving end1 as OUT essentially eliminates the end1/end2 check.
+ *
+ * This implementation is a bit of a kludge, in that a trailing $ is first
+ * taken as an ordinary character and then revised to be an anchor. The
+ * only undesirable side effect is that '$' gets included as a character
+ * category in such cases. This is fairly harmless; not worth fixing.
+ * The amount of lookahead needed to avoid this kludge is excessive.
+ */
+static void
+p_bre(p, end1, end2)
+register struct parse *p;
+register int end1; /* first terminating character */
+register int end2; /* second terminating character */
+{
+ register sopno start = HERE();
+ register int first = 1; /* first subexpression? */
+ register int wasdollar = 0;
+
+ if (EAT('^')) {
+ EMIT(OBOL, 0);
+ p->g->iflags |= USEBOL;
+ p->g->nbol++;
+ }
+ while (MORE() && !SEETWO(end1, end2)) {
+ wasdollar = p_simp_re(p, first);
+ first = 0;
+ }
+ if (wasdollar) { /* oops, that was a trailing anchor */
+ DROP(1);
+ EMIT(OEOL, 0);
+ p->g->iflags |= USEEOL;
+ p->g->neol++;
+ }
+
+ REQUIRE(HERE() != start, REG_EMPTY); /* require nonempty */
+}
+
+/*
+ - p_simp_re - parse a simple RE, an atom possibly followed by a repetition
+ == static int p_simp_re(register struct parse *p, int starordinary);
+ */
+static int /* was the simple RE an unbackslashed $? */
+p_simp_re(p, starordinary)
+register struct parse *p;
+int starordinary; /* is a leading * an ordinary character? */
+{
+ register int c;
+ register int count;
+ register int count2;
+ register sopno pos;
+ register int i;
+ register sopno subno;
+# define BACKSL (1<<CHAR_BIT)
+
+ pos = HERE(); /* repetion op, if any, covers from here */
+
+ assert(MORE()); /* caller should have ensured this */
+ c = GETNEXT();
+ if (c == '\\') {
+ REQUIRE(MORE(), REG_EESCAPE);
+ c = BACKSL | (unsigned char)GETNEXT();
+ }
+ switch (c) {
+ case '.':
+ if (p->g->cflags&REG_NEWLINE)
+ nonnewline(p);
+ else
+ EMIT(OANY, 0);
+ break;
+ case '[':
+ p_bracket(p);
+ break;
+ case BACKSL|'{':
+ SETERROR(REG_BADRPT);
+ break;
+ case BACKSL|'(':
+ p->g->nsub++;
+ subno = p->g->nsub;
+ if (subno < NPAREN)
+ p->pbegin[subno] = HERE();
+ EMIT(OLPAREN, subno);
+ /* the MORE here is an error heuristic */
+ if (MORE() && !SEETWO('\\', ')'))
+ p_bre(p, '\\', ')');
+ if (subno < NPAREN) {
+ p->pend[subno] = HERE();
+ assert(p->pend[subno] != 0);
+ }
+ EMIT(ORPAREN, subno);
+ REQUIRE(EATTWO('\\', ')'), REG_EPAREN);
+ break;
+ case BACKSL|')': /* should not get here -- must be user */
+ case BACKSL|'}':
+ SETERROR(REG_EPAREN);
+ break;
+ case BACKSL|'1':
+ case BACKSL|'2':
+ case BACKSL|'3':
+ case BACKSL|'4':
+ case BACKSL|'5':
+ case BACKSL|'6':
+ case BACKSL|'7':
+ case BACKSL|'8':
+ case BACKSL|'9':
+ i = (c&~BACKSL) - '0';
+ assert(i < NPAREN);
+ if (p->pend[i] != 0) {
+ assert((uint) i <= p->g->nsub);
+ EMIT(OBACK_, i);
+ assert(p->pbegin[i] != 0);
+ assert(OP(p->strip[p->pbegin[i]]) == OLPAREN);
+ assert(OP(p->strip[p->pend[i]]) == ORPAREN);
+ (void) dupl(p, p->pbegin[i]+1, p->pend[i]);
+ EMIT(O_BACK, i);
+ } else
+ SETERROR(REG_ESUBREG);
+ p->g->backrefs = 1;
+ break;
+ case '*':
+ REQUIRE(starordinary, REG_BADRPT);
+ /* FALLTHROUGH */
+ default:
+ ordinary(p, c &~ BACKSL);
+ break;
+ }
+
+ if (EAT('*')) { /* implemented as +? */
+ /* this case does not require the (y|) trick, noKLUDGE */
+ INSERT(OPLUS_, pos);
+ ASTERN(O_PLUS, pos);
+ INSERT(OQUEST_, pos);
+ ASTERN(O_QUEST, pos);
+ } else if (EATTWO('\\', '{')) {
+ count = p_count(p);
+ if (EAT(',')) {
+ if (MORE() && isdigit(PEEK())) {
+ count2 = p_count(p);
+ REQUIRE(count <= count2, REG_BADBR);
+ } else /* single number with comma */
+ count2 = RE_INFINITY;
+ } else /* just a single number */
+ count2 = count;
+ repeat(p, pos, count, count2);
+ if (!EATTWO('\\', '}')) { /* error heuristics */
+ while (MORE() && !SEETWO('\\', '}'))
+ NEXT();
+ REQUIRE(MORE(), REG_EBRACE);
+ SETERROR(REG_BADBR);
+ }
+ } else if (c == (unsigned char)'$') /* $ (but not \$) ends it */
+ return(1);
+
+ return(0);
+}
+
+/*
+ - p_count - parse a repetition count
+ == static int p_count(register struct parse *p);
+ */
+static int /* the value */
+p_count(p)
+register struct parse *p;
+{
+ register int count = 0;
+ register int ndigits = 0;
+
+ while (MORE() && isdigit(PEEK()) && count <= DUPMAX) {
+ count = count*10 + (GETNEXT() - '0');
+ ndigits++;
+ }
+
+ REQUIRE(ndigits > 0 && count <= DUPMAX, REG_BADBR);
+ return(count);
+}
+
+/*
+ - p_bracket - parse a bracketed character list
+ == static void p_bracket(register struct parse *p);
+ *
+ * Note a significant property of this code: if the allocset() did SETERROR,
+ * no set operations are done.
+ */
+static void
+p_bracket(p)
+register struct parse *p;
+{
+ register cset *cs = allocset(p);
+ register int invert = 0;
+
+ /* Dept of Truly Sickening Special-Case Kludges */
+ if (p->next + 5 < p->end && strncmp(p->next, "[:<:]]", 6) == 0) {
+ EMIT(OBOW, 0);
+ NEXTn(6);
+ return;
+ }
+ if (p->next + 5 < p->end && strncmp(p->next, "[:>:]]", 6) == 0) {
+ EMIT(OEOW, 0);
+ NEXTn(6);
+ return;
+ }
+
+ if (EAT('^'))
+ invert++; /* make note to invert set at end */
+ if (EAT(']'))
+ CHadd(cs, ']');
+ else if (EAT('-'))
+ CHadd(cs, '-');
+ while (MORE() && PEEK() != ']' && !SEETWO('-', ']'))
+ p_b_term(p, cs);
+ if (EAT('-'))
+ CHadd(cs, '-');
+ MUSTEAT(']', REG_EBRACK);
+
+ if (p->error != 0) /* don't mess things up further */
+ return;
+
+ if (p->g->cflags&REG_ICASE) {
+ register int i;
+ register int ci;
+
+ for (i = p->g->csetsize - 1; i >= 0; i--)
+ if (CHIN(cs, i) && isalpha(i)) {
+ ci = othercase(i);
+ if (ci != i)
+ CHadd(cs, ci);
+ }
+ if (cs->multis != NULL)
+ mccase(p, cs);
+ }
+ if (invert) {
+ register int i;
+
+ for (i = p->g->csetsize - 1; i >= 0; i--)
+ if (CHIN(cs, i))
+ CHsub(cs, i);
+ else
+ CHadd(cs, i);
+ if (p->g->cflags&REG_NEWLINE)
+ CHsub(cs, '\n');
+ if (cs->multis != NULL)
+ mcinvert(p, cs);
+ }
+
+ assert(cs->multis == NULL); /* xxx */
+
+ if (nch(p, cs) == 1) { /* optimize singleton sets */
+ ordinary(p, firstch(p, cs));
+ freeset(p, cs);
+ } else
+ EMIT(OANYOF, freezeset(p, cs));
+}
+
+/*
+ - p_b_term - parse one term of a bracketed character list
+ == static void p_b_term(register struct parse *p, register cset *cs);
+ */
+static void
+p_b_term(p, cs)
+register struct parse *p;
+register cset *cs;
+{
+ register char c;
+ register char start, finish;
+ register int i;
+
+ /* classify what we've got */
+ switch ((MORE()) ? PEEK() : '\0') {
+ case '[':
+ c = (MORE2()) ? PEEK2() : '\0';
+ break;
+ case '-':
+ SETERROR(REG_ERANGE);
+ return; /* NOTE RETURN */
+ break;
+ default:
+ c = '\0';
+ break;
+ }
+
+ switch (c) {
+ case ':': /* character class */
+ NEXT2();
+ REQUIRE(MORE(), REG_EBRACK);
+ c = PEEK();
+ REQUIRE(c != '-' && c != ']', REG_ECTYPE);
+ p_b_cclass(p, cs);
+ REQUIRE(MORE(), REG_EBRACK);
+ REQUIRE(EATTWO(':', ']'), REG_ECTYPE);
+ break;
+ case '=': /* equivalence class */
+ NEXT2();
+ REQUIRE(MORE(), REG_EBRACK);
+ c = PEEK();
+ REQUIRE(c != '-' && c != ']', REG_ECOLLATE);
+ p_b_eclass(p, cs);
+ REQUIRE(MORE(), REG_EBRACK);
+ REQUIRE(EATTWO('=', ']'), REG_ECOLLATE);
+ break;
+ default: /* symbol, ordinary character, or range */
+/* xxx revision needed for multichar stuff */
+ start = p_b_symbol(p);
+ if (SEE('-') && MORE2() && PEEK2() != ']') {
+ /* range */
+ NEXT();
+ if (EAT('-'))
+ finish = '-';
+ else
+ finish = p_b_symbol(p);
+ } else
+ finish = start;
+/* xxx what about signed chars here... */
+ REQUIRE(start <= finish, REG_ERANGE);
+ for (i = start; i <= finish; i++)
+ CHadd(cs, i);
+ break;
+ }
+}
+
+/*
+ - p_b_cclass - parse a character-class name and deal with it
+ == static void p_b_cclass(register struct parse *p, register cset *cs);
+ */
+static void
+p_b_cclass(p, cs)
+register struct parse *p;
+register cset *cs;
+{
+ register char *sp = p->next;
+ register struct cclass *cp;
+ register size_t len;
+ register char *u;
+ register char c;
+
+ while (MORE() && isalpha(PEEK()))
+ NEXT();
+ len = p->next - sp;
+ for (cp = cclasses; cp->name != NULL; cp++)
+ if (strncmp(cp->name, sp, len) == 0 && cp->name[len] == '\0')
+ break;
+ if (cp->name == NULL) {
+ /* oops, didn't find it */
+ SETERROR(REG_ECTYPE);
+ return;
+ }
+
+ u = cp->chars;
+ while ((c = *u++) != '\0')
+ CHadd(cs, c);
+ for (u = cp->multis; *u != '\0'; u += strlen(u) + 1)
+ MCadd(p, cs, u);
+}
+
+/*
+ - p_b_eclass - parse an equivalence-class name and deal with it
+ == static void p_b_eclass(register struct parse *p, register cset *cs);
+ *
+ * This implementation is incomplete. xxx
+ */
+static void
+p_b_eclass(p, cs)
+register struct parse *p;
+register cset *cs;
+{
+ register char c;
+
+ c = p_b_coll_elem(p, '=');
+ CHadd(cs, c);
+}
+
+/*
+ - p_b_symbol - parse a character or [..]ed multicharacter collating symbol
+ == static char p_b_symbol(register struct parse *p);
+ */
+static char /* value of symbol */
+p_b_symbol(p)
+register struct parse *p;
+{
+ register char value;
+
+ REQUIRE(MORE(), REG_EBRACK);
+ if (!EATTWO('[', '.'))
+ return(GETNEXT());
+
+ /* collating symbol */
+ value = p_b_coll_elem(p, '.');
+ REQUIRE(EATTWO('.', ']'), REG_ECOLLATE);
+ return(value);
+}
+
+/*
+ - p_b_coll_elem - parse a collating-element name and look it up
+ == static char p_b_coll_elem(register struct parse *p, int endc);
+ */
+static char /* value of collating element */
+p_b_coll_elem(p, endc)
+register struct parse *p;
+int endc; /* name ended by endc,']' */
+{
+ register char *sp = p->next;
+ register struct cname *cp;
+ register int len;
+
+ while (MORE() && !SEETWO(endc, ']'))
+ NEXT();
+ if (!MORE()) {
+ SETERROR(REG_EBRACK);
+ return(0);
+ }
+ len = p->next - sp;
+ for (cp = cnames; cp->name != NULL; cp++)
+ if (strncmp(cp->name, sp, len) == 0 && cp->name[len] == '\0')
+ return(cp->code); /* known name */
+ if (len == 1)
+ return(*sp); /* single character */
+ SETERROR(REG_ECOLLATE); /* neither */
+ return(0);
+}
+
+/*
+ - othercase - return the case counterpart of an alphabetic
+ == static char othercase(int ch);
+ */
+static char /* if no counterpart, return ch */
+othercase(ch)
+int ch;
+{
+ assert(isalpha(ch));
+ if (isupper(ch))
+ return(tolower(ch));
+ else if (islower(ch))
+ return(toupper(ch));
+ else /* peculiar, but could happen */
+ return(ch);
+}
+
+/*
+ - bothcases - emit a dualcase version of a two-case character
+ == static void bothcases(register struct parse *p, int ch);
+ *
+ * Boy, is this implementation ever a kludge...
+ */
+static void
+bothcases(p, ch)
+register struct parse *p;
+int ch;
+{
+ register char *oldnext = p->next;
+ register char *oldend = p->end;
+ char bracket[3];
+
+ assert(othercase(ch) != ch); /* p_bracket() would recurse */
+ p->next = bracket;
+ p->end = bracket+2;
+ bracket[0] = ch;
+ bracket[1] = ']';
+ bracket[2] = '\0';
+ p_bracket(p);
+ assert(p->next == bracket+2);
+ p->next = oldnext;
+ p->end = oldend;
+}
+
+/*
+ - ordinary - emit an ordinary character
+ == static void ordinary(register struct parse *p, register int ch);
+ */
+static void
+ordinary(p, ch)
+register struct parse *p;
+register int ch;
+{
+ register cat_t *cap = p->g->categories;
+
+ if ((p->g->cflags&REG_ICASE) && isalpha(ch) && othercase(ch) != ch)
+ bothcases(p, ch);
+ else {
+ EMIT(OCHAR, (unsigned char)ch);
+ if (cap[ch] == 0)
+ cap[ch] = p->g->ncategories++;
+ }
+}
+
+/*
+ - nonnewline - emit REG_NEWLINE version of OANY
+ == static void nonnewline(register struct parse *p);
+ *
+ * Boy, is this implementation ever a kludge...
+ */
+static void
+nonnewline(p)
+register struct parse *p;
+{
+ register char *oldnext = p->next;
+ register char *oldend = p->end;
+ char bracket[4];
+
+ p->next = bracket;
+ p->end = bracket+3;
+ bracket[0] = '^';
+ bracket[1] = '\n';
+ bracket[2] = ']';
+ bracket[3] = '\0';
+ p_bracket(p);
+ assert(p->next == bracket+3);
+ p->next = oldnext;
+ p->end = oldend;
+}
+
+/*
+ - repeat - generate code for a bounded repetition, recursively if needed
+ == static void repeat(register struct parse *p, sopno start, int from, int to);
+ */
+static void
+repeat(p, start, from, to)
+register struct parse *p;
+sopno start; /* operand from here to end of strip */
+int from; /* repeated from this number */
+int to; /* to this number of times (maybe RE_INFINITY) */
+{
+ register sopno finish = HERE();
+# define N 2
+# define INF 3
+# define REP(f, t) ((f)*8 + (t))
+# define MAP(n) (((n) <= 1) ? (n) : ((n) == RE_INFINITY) ? INF : N)
+ register sopno copy;
+
+ if (p->error != 0) /* head off possible runaway recursion */
+ return;
+
+ assert(from <= to);
+
+ switch (REP(MAP(from), MAP(to))) {
+ case REP(0, 0): /* must be user doing this */
+ DROP(finish-start); /* drop the operand */
+ break;
+ case REP(0, 1): /* as x{1,1}? */
+ case REP(0, N): /* as x{1,n}? */
+ case REP(0, INF): /* as x{1,}? */
+ /* KLUDGE: emit y? as (y|) until subtle bug gets fixed */
+ INSERT(OCH_, start); /* offset is wrong... */
+ repeat(p, start+1, 1, to);
+ ASTERN(OOR1, start);
+ AHEAD(start); /* ... fix it */
+ EMIT(OOR2, 0);
+ AHEAD(THERE());
+ ASTERN(O_CH, THERETHERE());
+ break;
+ case REP(1, 1): /* trivial case */
+ /* done */
+ break;
+ case REP(1, N): /* as x?x{1,n-1} */
+ /* KLUDGE: emit y? as (y|) until subtle bug gets fixed */
+ INSERT(OCH_, start);
+ ASTERN(OOR1, start);
+ AHEAD(start);
+ EMIT(OOR2, 0); /* offset very wrong... */
+ AHEAD(THERE()); /* ...so fix it */
+ ASTERN(O_CH, THERETHERE());
+ copy = dupl(p, start+1, finish+1);
+ assert(copy == finish+4);
+ repeat(p, copy, 1, to-1);
+ break;
+ case REP(1, INF): /* as x+ */
+ INSERT(OPLUS_, start);
+ ASTERN(O_PLUS, start);
+ break;
+ case REP(N, N): /* as xx{m-1,n-1} */
+ copy = dupl(p, start, finish);
+ repeat(p, copy, from-1, to-1);
+ break;
+ case REP(N, INF): /* as xx{n-1,INF} */
+ copy = dupl(p, start, finish);
+ repeat(p, copy, from-1, to);
+ break;
+ default: /* "can't happen" */
+ SETERROR(REG_ASSERT); /* just in case */
+ break;
+ }
+}
+
+/*
+ - seterr - set an error condition
+ == static int seterr(register struct parse *p, int e);
+ */
+static int /* useless but makes type checking happy */
+seterr(p, e)
+register struct parse *p;
+int e;
+{
+ if (p->error == 0) /* keep earliest error condition */
+ p->error = e;
+ p->next = nuls; /* try to bring things to a halt */
+ p->end = nuls;
+ return(0); /* make the return value well-defined */
+}
+
+/*
+ - allocset - allocate a set of characters for []
+ == static cset *allocset(register struct parse *p);
+ */
+static cset *
+allocset(p)
+register struct parse *p;
+{
+ register int no = p->g->ncsets++;
+ register size_t nc;
+ register size_t nbytes;
+ register cset *cs;
+ register size_t css = (size_t)p->g->csetsize;
+ register int i;
+
+ if (no >= p->ncsalloc) { /* need another column of space */
+ p->ncsalloc += CHAR_BIT;
+ nc = p->ncsalloc;
+ assert(nc % CHAR_BIT == 0);
+ nbytes = nc / CHAR_BIT * css;
+ if (p->g->sets == NULL)
+ p->g->sets = (cset *)malloc(nc * sizeof(cset));
+ else
+ p->g->sets = (cset *)realloc((char *)p->g->sets,
+ nc * sizeof(cset));
+ if (p->g->setbits == NULL)
+ p->g->setbits = (uch *)malloc(nbytes);
+ else {
+ p->g->setbits = (uch *)realloc((char *)p->g->setbits,
+ nbytes);
+ /* xxx this isn't right if setbits is now NULL */
+ for (i = 0; i < no; i++)
+ p->g->sets[i].ptr = p->g->setbits + css*(i/CHAR_BIT);
+ }
+ if (p->g->sets != NULL && p->g->setbits != NULL)
+ (void) memset((char *)p->g->setbits + (nbytes - css),
+ 0, css);
+ else {
+ no = 0;
+ SETERROR(REG_ESPACE);
+ /* caller's responsibility not to do set ops */
+ }
+ }
+
+ assert(p->g->sets != NULL); /* xxx */
+ cs = &p->g->sets[no];
+ cs->ptr = p->g->setbits + css*((no)/CHAR_BIT);
+ cs->mask = 1 << ((no) % CHAR_BIT);
+ cs->hash = 0;
+ cs->smultis = 0;
+ cs->multis = NULL;
+
+ return(cs);
+}
+
+/*
+ - freeset - free a now-unused set
+ == static void freeset(register struct parse *p, register cset *cs);
+ */
+static void
+freeset(p, cs)
+register struct parse *p;
+register cset *cs;
+{
+ register size_t i;
+ register cset *top = &p->g->sets[p->g->ncsets];
+ register size_t css = (size_t)p->g->csetsize;
+
+ for (i = 0; i < css; i++)
+ CHsub(cs, i);
+ if (cs == top-1) /* recover only the easy case */
+ p->g->ncsets--;
+}
+
+/*
+ - freezeset - final processing on a set of characters
+ == static int freezeset(register struct parse *p, register cset *cs);
+ *
+ * The main task here is merging identical sets. This is usually a waste
+ * of time (although the hash code minimizes the overhead), but can win
+ * big if REG_ICASE is being used. REG_ICASE, by the way, is why the hash
+ * is done using addition rather than xor -- all ASCII [aA] sets xor to
+ * the same value!
+ */
+static int /* set number */
+freezeset(p, cs)
+register struct parse *p;
+register cset *cs;
+{
+ register uch h = cs->hash;
+ register size_t i;
+ register cset *top = &p->g->sets[p->g->ncsets];
+ register cset *cs2;
+ register size_t css = (size_t)p->g->csetsize;
+
+ /* look for an earlier one which is the same */
+ for (cs2 = &p->g->sets[0]; cs2 < top; cs2++)
+ if (cs2->hash == h && cs2 != cs) {
+ /* maybe */
+ for (i = 0; i < css; i++)
+ if (!!CHIN(cs2, i) != !!CHIN(cs, i))
+ break; /* no */
+ if (i == css)
+ break; /* yes */
+ }
+
+ if (cs2 < top) { /* found one */
+ freeset(p, cs);
+ cs = cs2;
+ }
+
+ return((int)(cs - p->g->sets));
+}
+
+/*
+ - firstch - return first character in a set (which must have at least one)
+ == static int firstch(register struct parse *p, register cset *cs);
+ */
+static int /* character; there is no "none" value */
+firstch(p, cs)
+register struct parse *p;
+register cset *cs;
+{
+ register size_t i;
+ register size_t css = (size_t)p->g->csetsize;
+
+ for (i = 0; i < css; i++)
+ if (CHIN(cs, i))
+ return((char)i);
+ assert(never);
+ return(0); /* arbitrary */
+}
+
+/*
+ - nch - number of characters in a set
+ == static int nch(register struct parse *p, register cset *cs);
+ */
+static int
+nch(p, cs)
+register struct parse *p;
+register cset *cs;
+{
+ register size_t i;
+ register size_t css = (size_t)p->g->csetsize;
+ register int n = 0;
+
+ for (i = 0; i < css; i++)
+ if (CHIN(cs, i))
+ n++;
+ return(n);
+}
+
+/*
+ - mcadd - add a collating element to a cset
+ == static void mcadd(register struct parse *p, register cset *cs, \
+ == register char *cp);
+ */
+static void
+mcadd(p, cs, cp)
+register struct parse *p;
+register cset *cs;
+register char *cp;
+{
+ register size_t oldend = cs->smultis;
+
+ cs->smultis += strlen(cp) + 1;
+ if (cs->multis == NULL)
+ cs->multis = malloc(cs->smultis);
+ else
+ cs->multis = realloc(cs->multis, cs->smultis);
+ if (cs->multis == NULL) {
+ SETERROR(REG_ESPACE);
+ return;
+ }
+
+ (void) strcpy(cs->multis + oldend - 1, cp);
+ cs->multis[cs->smultis - 1] = '\0';
+}
+
+/*
+ - mcsub - subtract a collating element from a cset
+ == static void mcsub(register cset *cs, register char *cp);
+ */
+static void
+mcsub(cs, cp)
+register cset *cs;
+register char *cp;
+{
+ register char *fp = mcfind(cs, cp);
+ register size_t len = strlen(fp);
+
+ assert(fp != NULL);
+ (void) memmove(fp, fp + len + 1,
+ cs->smultis - (fp + len + 1 - cs->multis));
+ cs->smultis -= len;
+
+ if (cs->smultis == 0) {
+ free(cs->multis);
+ cs->multis = NULL;
+ return;
+ }
+
+ cs->multis = realloc(cs->multis, cs->smultis);
+ assert(cs->multis != NULL);
+}
+
+/*
+ - mcin - is a collating element in a cset?
+ == static int mcin(register cset *cs, register char *cp);
+ */
+static int
+mcin(cs, cp)
+register cset *cs;
+register char *cp;
+{
+ return(mcfind(cs, cp) != NULL);
+}
+
+/*
+ - mcfind - find a collating element in a cset
+ == static char *mcfind(register cset *cs, register char *cp);
+ */
+static char *
+mcfind(cs, cp)
+register cset *cs;
+register char *cp;
+{
+ register char *p;
+
+ if (cs->multis == NULL)
+ return(NULL);
+ for (p = cs->multis; *p != '\0'; p += strlen(p) + 1)
+ if (strcmp(cp, p) == 0)
+ return(p);
+ return(NULL);
+}
+
+/*
+ - mcinvert - invert the list of collating elements in a cset
+ == static void mcinvert(register struct parse *p, register cset *cs);
+ *
+ * This would have to know the set of possibilities. Implementation
+ * is deferred.
+ */
+static void
+mcinvert(p, cs)
+register struct parse *p;
+register cset *cs;
+{
+ assert(cs->multis == NULL); /* xxx */
+}
+
+/*
+ - mccase - add case counterparts of the list of collating elements in a cset
+ == static void mccase(register struct parse *p, register cset *cs);
+ *
+ * This would have to know the set of possibilities. Implementation
+ * is deferred.
+ */
+static void
+mccase(p, cs)
+register struct parse *p;
+register cset *cs;
+{
+ assert(cs->multis == NULL); /* xxx */
+}
+
+/*
+ - isinsets - is this character in any sets?
+ == static int isinsets(register struct re_guts *g, int c);
+ */
+static int /* predicate */
+isinsets(g, c)
+register struct re_guts *g;
+int c;
+{
+ register uch *col;
+ register int i;
+ register int ncols = (g->ncsets+(CHAR_BIT-1)) / CHAR_BIT;
+ register unsigned uc = (unsigned char)c;
+
+ for (i = 0, col = g->setbits; i < ncols; i++, col += g->csetsize)
+ if (col[uc] != 0)
+ return(1);
+ return(0);
+}
+
+/*
+ - samesets - are these two characters in exactly the same sets?
+ == static int samesets(register struct re_guts *g, int c1, int c2);
+ */
+static int /* predicate */
+samesets(g, c1, c2)
+register struct re_guts *g;
+int c1;
+int c2;
+{
+ register uch *col;
+ register int i;
+ register int ncols = (g->ncsets+(CHAR_BIT-1)) / CHAR_BIT;
+ register unsigned uc1 = (unsigned char)c1;
+ register unsigned uc2 = (unsigned char)c2;
+
+ for (i = 0, col = g->setbits; i < ncols; i++, col += g->csetsize)
+ if (col[uc1] != col[uc2])
+ return(0);
+ return(1);
+}
+
+/*
+ - categorize - sort out character categories
+ == static void categorize(struct parse *p, register struct re_guts *g);
+ */
+static void
+categorize(p, g)
+struct parse *p;
+register struct re_guts *g;
+{
+ register cat_t *cats = g->categories;
+ register int c;
+ register int c2;
+ register cat_t cat;
+
+ /* avoid making error situations worse */
+ if (p->error != 0)
+ return;
+
+ for (c = CHAR_MIN; c <= CHAR_MAX; c++)
+ if (cats[c] == 0 && isinsets(g, c)) {
+ cat = g->ncategories++;
+ cats[c] = cat;
+ for (c2 = c+1; c2 <= CHAR_MAX; c2++)
+ if (cats[c2] == 0 && samesets(g, c, c2))
+ cats[c2] = cat;
+ }
+}
+
+/*
+ - dupl - emit a duplicate of a bunch of sops
+ == static sopno dupl(register struct parse *p, sopno start, sopno finish);
+ */
+static sopno /* start of duplicate */
+dupl(p, start, finish)
+register struct parse *p;
+sopno start; /* from here */
+sopno finish; /* to this less one */
+{
+ register sopno ret = HERE();
+ register sopno len = finish - start;
+
+ assert(finish >= start);
+ if (len == 0)
+ return(ret);
+ enlarge(p, p->ssize + len); /* this many unexpected additions */
+ assert(p->ssize >= p->slen + len);
+ (void) memcpy((char *)(p->strip + p->slen),
+ (char *)(p->strip + start), (size_t)len*sizeof(sop));
+ p->slen += len;
+ return(ret);
+}
+
+/*
+ - doemit - emit a strip operator
+ == static void doemit(register struct parse *p, sop op, size_t opnd);
+ *
+ * It might seem better to implement this as a macro with a function as
+ * hard-case backup, but it's just too big and messy unless there are
+ * some changes to the data structures. Maybe later.
+ */
+static void
+doemit(p, op, opnd)
+register struct parse *p;
+sop op;
+size_t opnd;
+{
+ /* avoid making error situations worse */
+ if (p->error != 0)
+ return;
+
+ /* deal with oversize operands ("can't happen", more or less) */
+ assert(opnd < 1<<OPSHIFT);
+
+ /* deal with undersized strip */
+ if (p->slen >= p->ssize)
+ enlarge(p, (p->ssize+1) / 2 * 3); /* +50% */
+ assert(p->slen < p->ssize);
+
+ /* finally, it's all reduced to the easy case */
+ p->strip[p->slen++] = SOP(op, opnd);
+}
+
+/*
+ - doinsert - insert a sop into the strip
+ == static void doinsert(register struct parse *p, sop op, size_t opnd, sopno pos);
+ */
+static void
+doinsert(p, op, opnd, pos)
+register struct parse *p;
+sop op;
+size_t opnd;
+sopno pos;
+{
+ register sopno sn;
+ register sop s;
+ register int i;
+
+ /* avoid making error situations worse */
+ if (p->error != 0)
+ return;
+
+ sn = HERE();
+ EMIT(op, opnd); /* do checks, ensure space */
+ assert(HERE() == sn+1);
+ s = p->strip[sn];
+
+ /* adjust paren pointers */
+ assert(pos > 0);
+ for (i = 1; i < NPAREN; i++) {
+ if (p->pbegin[i] >= pos) {
+ p->pbegin[i]++;
+ }
+ if (p->pend[i] >= pos) {
+ p->pend[i]++;
+ }
+ }
+ {
+ int length=(HERE()-pos-1)*sizeof(sop);
+ bmove_upp((char *) &p->strip[pos+1]+length,
+ (char *) &p->strip[pos]+length,
+ length);
+ }
+#ifdef OLD_CODE
+ memmove((char *)&p->strip[pos+1], (char *)&p->strip[pos],
+ (HERE()-pos-1)*sizeof(sop));
+#endif
+ p->strip[pos] = s;
+}
+
+/*
+ - dofwd - complete a forward reference
+ == static void dofwd(register struct parse *p, sopno pos, sop value);
+ */
+static void
+dofwd(p, pos, value)
+register struct parse *p;
+register sopno pos;
+sop value;
+{
+ /* avoid making error situations worse */
+ if (p->error != 0)
+ return;
+
+ assert(value < 1<<OPSHIFT);
+ p->strip[pos] = OP(p->strip[pos]) | value;
+}
+
+/*
+ - enlarge - enlarge the strip
+ == static void enlarge(register struct parse *p, sopno size);
+ */
+static void
+enlarge(p, size)
+register struct parse *p;
+register sopno size;
+{
+ register sop *sp;
+
+ if (p->ssize >= size)
+ return;
+
+ sp = (sop *)realloc(p->strip, size*sizeof(sop));
+ if (sp == NULL) {
+ SETERROR(REG_ESPACE);
+ return;
+ }
+ p->strip = sp;
+ p->ssize = size;
+}
+
+/*
+ - stripsnug - compact the strip
+ == static void stripsnug(register struct parse *p, register struct re_guts *g);
+ */
+static void
+stripsnug(p, g)
+register struct parse *p;
+register struct re_guts *g;
+{
+ g->nstates = p->slen;
+ g->strip = (sop *)realloc((char *)p->strip, p->slen * sizeof(sop));
+ if (g->strip == NULL) {
+ SETERROR(REG_ESPACE);
+ g->strip = p->strip;
+ }
+}
+
+/*
+ - findmust - fill in must and mlen with longest mandatory literal string
+ == static void findmust(register struct parse *p, register struct re_guts *g);
+ *
+ * This algorithm could do fancy things like analyzing the operands of |
+ * for common subsequences. Someday. This code is simple and finds most
+ * of the interesting cases.
+ *
+ * Note that must and mlen got initialized during setup.
+ */
+static void
+findmust(p, g)
+struct parse *p;
+register struct re_guts *g;
+{
+ register sop *scan;
+ sop *start;
+ register sop *newstart;
+ register sopno newlen;
+ register sop s;
+ register char *cp;
+ register sopno i;
+ LINT_INIT(start); LINT_INIT(newstart);
+ /* avoid making error situations worse */
+ if (p->error != 0)
+ return;
+
+ /* find the longest OCHAR sequence in strip */
+ newlen = 0;
+ scan = g->strip + 1;
+ do {
+ s = *scan++;
+ switch (OP(s)) {
+ case OCHAR: /* sequence member */
+ if (newlen == 0) /* new sequence */
+ newstart = scan - 1;
+ newlen++;
+ break;
+ case OPLUS_: /* things that don't break one */
+ case OLPAREN:
+ case ORPAREN:
+ break;
+ case OQUEST_: /* things that must be skipped */
+ case OCH_:
+ scan--;
+ do {
+ scan += OPND(s);
+ s = *scan;
+ /* assert() interferes w debug printouts */
+ if (OP(s) != O_QUEST && OP(s) != O_CH &&
+ OP(s) != OOR2) {
+ g->iflags |= BAD;
+ return;
+ }
+ } while (OP(s) != O_QUEST && OP(s) != O_CH);
+ /* fallthrough */
+ default: /* things that break a sequence */
+ if (newlen > g->mlen) { /* ends one */
+ start = newstart;
+ g->mlen = newlen;
+ }
+ newlen = 0;
+ break;
+ }
+ } while (OP(s) != OEND);
+
+ if (g->mlen == 0) /* there isn't one */
+ return;
+
+ /* turn it into a character string */
+ g->must = malloc((size_t)g->mlen + 1);
+ if (g->must == NULL) { /* argh; just forget it */
+ g->mlen = 0;
+ return;
+ }
+ cp = g->must;
+ scan = start;
+ for (i = g->mlen; i > 0; i--) {
+ while (OP(s = *scan++) != OCHAR)
+ continue;
+ assert(cp < g->must + g->mlen);
+ *cp++ = (char)OPND(s);
+ }
+ assert(cp == g->must + g->mlen);
+ *cp++ = '\0'; /* just on general principles */
+}
+
+/*
+ - pluscount - count + nesting
+ == static sopno pluscount(register struct parse *p, register struct re_guts *g);
+ */
+static sopno /* nesting depth */
+pluscount(p, g)
+struct parse *p;
+register struct re_guts *g;
+{
+ register sop *scan;
+ register sop s;
+ register sopno plusnest = 0;
+ register sopno maxnest = 0;
+
+ if (p->error != 0)
+ return(0); /* there may not be an OEND */
+
+ scan = g->strip + 1;
+ do {
+ s = *scan++;
+ switch (OP(s)) {
+ case OPLUS_:
+ plusnest++;
+ break;
+ case O_PLUS:
+ if (plusnest > maxnest)
+ maxnest = plusnest;
+ plusnest--;
+ break;
+ }
+ } while (OP(s) != OEND);
+ if (plusnest != 0)
+ g->iflags |= BAD;
+ return(maxnest);
+}
diff --git a/regex/regcomp.ih b/regex/regcomp.ih
new file mode 100644
index 00000000000..0776e7185cd
--- /dev/null
+++ b/regex/regcomp.ih
@@ -0,0 +1,51 @@
+/* ========= begin header generated by ./mkh ========= */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* === regcomp.c === */
+static void p_ere(register struct parse *p, int stop);
+static void p_ere_exp(register struct parse *p);
+static void p_str(register struct parse *p);
+static void p_bre(register struct parse *p, register int end1, register int end2);
+static int p_simp_re(register struct parse *p, int starordinary);
+static int p_count(register struct parse *p);
+static void p_bracket(register struct parse *p);
+static void p_b_term(register struct parse *p, register cset *cs);
+static void p_b_cclass(register struct parse *p, register cset *cs);
+static void p_b_eclass(register struct parse *p, register cset *cs);
+static char p_b_symbol(register struct parse *p);
+static char p_b_coll_elem(register struct parse *p, int endc);
+static char othercase(int ch);
+static void bothcases(register struct parse *p, int ch);
+static void ordinary(register struct parse *p, register int ch);
+static void nonnewline(register struct parse *p);
+static void repeat(register struct parse *p, sopno start, int from, int to);
+static int seterr(register struct parse *p, int e);
+static cset *allocset(register struct parse *p);
+static void freeset(register struct parse *p, register cset *cs);
+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);
+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);
+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);
+static int samesets(register struct re_guts *g, int c1, int c2);
+static void categorize(struct parse *p, register struct re_guts *g);
+static sopno dupl(register struct parse *p, sopno start, sopno finish);
+static void doemit(register struct parse *p, sop op, size_t opnd);
+static void doinsert(register struct parse *p, sop op, size_t opnd, sopno pos);
+static void dofwd(register struct parse *p, sopno pos, sop value);
+static void enlarge(register struct parse *p, sopno size);
+static void stripsnug(register struct parse *p, register struct re_guts *g);
+static void findmust(register struct parse *p, register struct re_guts *g);
+static sopno pluscount(register struct parse *p, register struct re_guts *g);
+
+#ifdef __cplusplus
+}
+#endif
+/* ========= end header generated by ./mkh ========= */
diff --git a/regex/regerror.c b/regex/regerror.c
new file mode 100644
index 00000000000..4810db23f12
--- /dev/null
+++ b/regex/regerror.c
@@ -0,0 +1,120 @@
+#include <global.h>
+#include <m_string.h>
+#include <m_ctype.h>
+#include <regex.h>
+
+#include "utils.h"
+#include "regerror.ih"
+
+/*
+ = #define REG_NOMATCH 1
+ = #define REG_BADPAT 2
+ = #define REG_ECOLLATE 3
+ = #define REG_ECTYPE 4
+ = #define REG_EESCAPE 5
+ = #define REG_ESUBREG 6
+ = #define REG_EBRACK 7
+ = #define REG_EPAREN 8
+ = #define REG_EBRACE 9
+ = #define REG_BADBR 10
+ = #define REG_ERANGE 11
+ = #define REG_ESPACE 12
+ = #define REG_BADRPT 13
+ = #define REG_EMPTY 14
+ = #define REG_ASSERT 15
+ = #define REG_INVARG 16
+ = #define REG_ATOI 255 // convert name to number (!)
+ = #define REG_ITOA 0400 // convert number to name (!)
+ */
+static struct rerr {
+ int code;
+ char *name;
+ char *explain;
+} rerrs[] = {
+ REG_NOMATCH, "REG_NOMATCH", "regexec() failed to match",
+ REG_BADPAT, "REG_BADPAT", "invalid regular expression",
+ REG_ECOLLATE, "REG_ECOLLATE", "invalid collating element",
+ REG_ECTYPE, "REG_ECTYPE", "invalid character class",
+ REG_EESCAPE, "REG_EESCAPE", "trailing backslash (\\)",
+ REG_ESUBREG, "REG_ESUBREG", "invalid backreference number",
+ REG_EBRACK, "REG_EBRACK", "brackets ([ ]) not balanced",
+ REG_EPAREN, "REG_EPAREN", "parentheses not balanced",
+ REG_EBRACE, "REG_EBRACE", "braces not balanced",
+ REG_BADBR, "REG_BADBR", "invalid repetition count(s)",
+ REG_ERANGE, "REG_ERANGE", "invalid character range",
+ REG_ESPACE, "REG_ESPACE", "out of memory",
+ REG_BADRPT, "REG_BADRPT", "repetition-operator operand invalid",
+ REG_EMPTY, "REG_EMPTY", "empty (sub)expression",
+ REG_ASSERT, "REG_ASSERT", "\"can't happen\" -- you found a bug",
+ REG_INVARG, "REG_INVARG", "invalid argument to regex routine",
+ 0, "", "*** unknown regexp error code ***",
+};
+
+/*
+ - regerror - the interface to error numbers
+ = extern size_t regerror(int, const regex_t *, char *, size_t);
+ */
+/* ARGSUSED */
+size_t
+regerror(errcode, preg, errbuf, errbuf_size)
+int errcode;
+const regex_t *preg;
+char *errbuf;
+size_t errbuf_size;
+{
+ register struct rerr *r;
+ register size_t len;
+ register int target = errcode &~ REG_ITOA;
+ register char *s;
+ char convbuf[50];
+
+ if (errcode == REG_ATOI)
+ s = regatoi(preg, convbuf);
+ else {
+ for (r = rerrs; r->code != 0; r++)
+ if (r->code == target)
+ break;
+
+ if (errcode&REG_ITOA) {
+ if (r->code != 0)
+ (void) strcpy(convbuf, r->name);
+ else
+ sprintf(convbuf, "REG_0x%x", target);
+ assert(strlen(convbuf) < sizeof(convbuf));
+ s = convbuf;
+ } else
+ s = r->explain;
+ }
+
+ len = strlen(s) + 1;
+ if (errbuf_size > 0) {
+ if (errbuf_size > len)
+ (void) strcpy(errbuf, s);
+ else {
+ (void) strncpy(errbuf, s, errbuf_size-1);
+ errbuf[errbuf_size-1] = '\0';
+ }
+ }
+
+ return(len);
+}
+
+/*
+ - regatoi - internal routine to implement REG_ATOI
+ == static char *regatoi(const regex_t *preg, char *localbuf);
+ */
+static char *
+regatoi(preg, localbuf)
+const regex_t *preg;
+char *localbuf;
+{
+ register struct rerr *r;
+ for (r = rerrs; r->code != 0; r++)
+ if (strcmp(r->name, preg->re_endp) == 0)
+ break;
+ if (r->code == 0)
+ return("0");
+
+ sprintf(localbuf, "%d", r->code);
+ return(localbuf);
+}
diff --git a/regex/regerror.ih b/regex/regerror.ih
new file mode 100644
index 00000000000..2cb668c24f0
--- /dev/null
+++ b/regex/regerror.ih
@@ -0,0 +1,12 @@
+/* ========= begin header generated by ./mkh ========= */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* === regerror.c === */
+static char *regatoi(const regex_t *preg, char *localbuf);
+
+#ifdef __cplusplus
+}
+#endif
+/* ========= end header generated by ./mkh ========= */
diff --git a/regex/regex.3 b/regex/regex.3
new file mode 100644
index 00000000000..100c8a7f71c
--- /dev/null
+++ b/regex/regex.3
@@ -0,0 +1,502 @@
+.TH REGEX 3 "17 May 1993"
+.BY "Henry Spencer"
+.de ZR
+.\" one other place knows this name: the SEE ALSO section
+.IR regex (7) \\$1
+..
+.SH NAME
+regcomp, regexec, regerror, regfree \- regular-expression library
+.SH SYNOPSIS
+.ft B
+.\".na
+#include <sys/types.h>
+.br
+#include <regex.h>
+.HP 10
+int regcomp(regex_t\ *preg, const\ char\ *pattern, int\ cflags);
+.HP
+int\ regexec(const\ regex_t\ *preg, const\ char\ *string,
+size_t\ nmatch, regmatch_t\ pmatch[], int\ eflags);
+.HP
+size_t\ regerror(int\ errcode, const\ regex_t\ *preg,
+char\ *errbuf, size_t\ errbuf_size);
+.HP
+void\ regfree(regex_t\ *preg);
+.\".ad
+.ft
+.SH DESCRIPTION
+These routines implement POSIX 1003.2 regular expressions (``RE''s);
+see
+.ZR .
+.I Regcomp
+compiles an RE written as a string into an internal form,
+.I regexec
+matches that internal form against a string and reports results,
+.I regerror
+transforms error codes from either into human-readable messages,
+and
+.I regfree
+frees any dynamically-allocated storage used by the internal form
+of an RE.
+.PP
+The header
+.I <regex.h>
+declares two structure types,
+.I regex_t
+and
+.IR regmatch_t ,
+the former for compiled internal forms and the latter for match reporting.
+It also declares the four functions,
+a type
+.IR regoff_t ,
+and a number of constants with names starting with ``REG_''.
+.PP
+.I Regcomp
+compiles the regular expression contained in the
+.I pattern
+string,
+subject to the flags in
+.IR cflags ,
+and places the results in the
+.I regex_t
+structure pointed to by
+.IR preg .
+.I Cflags
+is the bitwise OR of zero or more of the following flags:
+.IP REG_EXTENDED \w'REG_EXTENDED'u+2n
+Compile modern (``extended'') REs,
+rather than the obsolete (``basic'') REs that
+are the default.
+.IP REG_BASIC
+This is a synonym for 0,
+provided as a counterpart to REG_EXTENDED to improve readability.
+.IP REG_NOSPEC
+Compile with recognition of all special characters turned off.
+All characters are thus considered ordinary,
+so the ``RE'' is a literal string.
+This is an extension,
+compatible with but not specified by POSIX 1003.2,
+and should be used with
+caution in software intended to be portable to other systems.
+REG_EXTENDED and REG_NOSPEC may not be used
+in the same call to
+.IR regcomp .
+.IP REG_ICASE
+Compile for matching that ignores upper/lower case distinctions.
+See
+.ZR .
+.IP REG_NOSUB
+Compile for matching that need only report success or failure,
+not what was matched.
+.IP REG_NEWLINE
+Compile for newline-sensitive matching.
+By default, newline is a completely ordinary character with no special
+meaning in either REs or strings.
+With this flag,
+`[^' bracket expressions and `.' never match newline,
+a `^' anchor matches the null string after any newline in the string
+in addition to its normal function,
+and the `$' anchor matches the null string before any newline in the
+string in addition to its normal function.
+.IP REG_PEND
+The regular expression ends,
+not at the first NUL,
+but just before the character pointed to by the
+.I re_endp
+member of the structure pointed to by
+.IR preg .
+The
+.I re_endp
+member is of type
+.IR const\ char\ * .
+This flag permits inclusion of NULs in the RE;
+they are considered ordinary characters.
+This is an extension,
+compatible with but not specified by POSIX 1003.2,
+and should be used with
+caution in software intended to be portable to other systems.
+.PP
+When successful,
+.I regcomp
+returns 0 and fills in the structure pointed to by
+.IR preg .
+One member of that structure
+(other than
+.IR re_endp )
+is publicized:
+.IR re_nsub ,
+of type
+.IR size_t ,
+contains the number of parenthesized subexpressions within the RE
+(except that the value of this member is undefined if the
+REG_NOSUB flag was used).
+If
+.I regcomp
+fails, it returns a non-zero error code;
+see DIAGNOSTICS.
+.PP
+.I Regexec
+matches the compiled RE pointed to by
+.I preg
+against the
+.IR string ,
+subject to the flags in
+.IR eflags ,
+and reports results using
+.IR nmatch ,
+.IR pmatch ,
+and the returned value.
+The RE must have been compiled by a previous invocation of
+.IR regcomp .
+The compiled form is not altered during execution of
+.IR regexec ,
+so a single compiled RE can be used simultaneously by multiple threads.
+.PP
+By default,
+the NUL-terminated string pointed to by
+.I string
+is considered to be the text of an entire line, minus any terminating
+newline.
+The
+.I eflags
+argument is the bitwise OR of zero or more of the following flags:
+.IP REG_NOTBOL \w'REG_STARTEND'u+2n
+The first character of
+the string
+is not the beginning of a line, so the `^' anchor should not match before it.
+This does not affect the behavior of newlines under REG_NEWLINE.
+.IP REG_NOTEOL
+The NUL terminating
+the string
+does not end a line, so the `$' anchor should not match before it.
+This does not affect the behavior of newlines under REG_NEWLINE.
+.IP REG_STARTEND
+The string is considered to start at
+\fIstring\fR\ + \fIpmatch\fR[0].\fIrm_so\fR
+and to have a terminating NUL located at
+\fIstring\fR\ + \fIpmatch\fR[0].\fIrm_eo\fR
+(there need not actually be a NUL at that location),
+regardless of the value of
+.IR nmatch .
+See below for the definition of
+.IR pmatch
+and
+.IR nmatch .
+This is an extension,
+compatible with but not specified by POSIX 1003.2,
+and should be used with
+caution in software intended to be portable to other systems.
+Note that a non-zero \fIrm_so\fR does not imply REG_NOTBOL;
+REG_STARTEND affects only the location of the string,
+not how it is matched.
+.PP
+See
+.ZR
+for a discussion of what is matched in situations where an RE or a
+portion thereof could match any of several substrings of
+.IR string .
+.PP
+Normally,
+.I regexec
+returns 0 for success and the non-zero code REG_NOMATCH for failure.
+Other non-zero error codes may be returned in exceptional situations;
+see DIAGNOSTICS.
+.PP
+If REG_NOSUB was specified in the compilation of the RE,
+or if
+.I nmatch
+is 0,
+.I regexec
+ignores the
+.I pmatch
+argument (but see below for the case where REG_STARTEND is specified).
+Otherwise,
+.I pmatch
+points to an array of
+.I nmatch
+structures of type
+.IR regmatch_t .
+Such a structure has at least the members
+.I rm_so
+and
+.IR rm_eo ,
+both of type
+.I regoff_t
+(a signed arithmetic type at least as large as an
+.I off_t
+and a
+.IR ssize_t ),
+containing respectively the offset of the first character of a substring
+and the offset of the first character after the end of the substring.
+Offsets are measured from the beginning of the
+.I string
+argument given to
+.IR regexec .
+An empty substring is denoted by equal offsets,
+both indicating the character following the empty substring.
+.PP
+The 0th member of the
+.I pmatch
+array is filled in to indicate what substring of
+.I string
+was matched by the entire RE.
+Remaining members report what substring was matched by parenthesized
+subexpressions within the RE;
+member
+.I i
+reports subexpression
+.IR i ,
+with subexpressions counted (starting at 1) by the order of their opening
+parentheses in the RE, left to right.
+Unused entries in the array\(emcorresponding either to subexpressions that
+did not participate in the match at all, or to subexpressions that do not
+exist in the RE (that is, \fIi\fR\ > \fIpreg\fR\->\fIre_nsub\fR)\(emhave both
+.I rm_so
+and
+.I rm_eo
+set to \-1.
+If a subexpression participated in the match several times,
+the reported substring is the last one it matched.
+(Note, as an example in particular, that when the RE `(b*)+' matches `bbb',
+the parenthesized subexpression matches each of the three `b's and then
+an infinite number of empty strings following the last `b',
+so the reported substring is one of the empties.)
+.PP
+If REG_STARTEND is specified,
+.I pmatch
+must point to at least one
+.I regmatch_t
+(even if
+.I nmatch
+is 0 or REG_NOSUB was specified),
+to hold the input offsets for REG_STARTEND.
+Use for output is still entirely controlled by
+.IR nmatch ;
+if
+.I nmatch
+is 0 or REG_NOSUB was specified,
+the value of
+.IR pmatch [0]
+will not be changed by a successful
+.IR regexec .
+.PP
+.I Regerror
+maps a non-zero
+.I errcode
+from either
+.I regcomp
+or
+.I regexec
+to a human-readable, printable message.
+If
+.I preg
+is non-NULL,
+the error code should have arisen from use of
+the
+.I regex_t
+pointed to by
+.IR preg ,
+and if the error code came from
+.IR regcomp ,
+it should have been the result from the most recent
+.I regcomp
+using that
+.IR regex_t .
+.RI ( Regerror
+may be able to supply a more detailed message using information
+from the
+.IR regex_t .)
+.I Regerror
+places the NUL-terminated message into the buffer pointed to by
+.IR errbuf ,
+limiting the length (including the NUL) to at most
+.I errbuf_size
+bytes.
+If the whole message won't fit,
+as much of it as will fit before the terminating NUL is supplied.
+In any case,
+the returned value is the size of buffer needed to hold the whole
+message (including terminating NUL).
+If
+.I errbuf_size
+is 0,
+.I errbuf
+is ignored but the return value is still correct.
+.PP
+If the
+.I errcode
+given to
+.I regerror
+is first ORed with REG_ITOA,
+the ``message'' that results is the printable name of the error code,
+e.g. ``REG_NOMATCH'',
+rather than an explanation thereof.
+If
+.I errcode
+is REG_ATOI,
+then
+.I preg
+shall be non-NULL and the
+.I re_endp
+member of the structure it points to
+must point to the printable name of an error code;
+in this case, the result in
+.I errbuf
+is the decimal digits of
+the numeric value of the error code
+(0 if the name is not recognized).
+REG_ITOA and REG_ATOI are intended primarily as debugging facilities;
+they are extensions,
+compatible with but not specified by POSIX 1003.2,
+and should be used with
+caution in software intended to be portable to other systems.
+Be warned also that they are considered experimental and changes are possible.
+.PP
+.I Regfree
+frees any dynamically-allocated storage associated with the compiled RE
+pointed to by
+.IR preg .
+The remaining
+.I regex_t
+is no longer a valid compiled RE
+and the effect of supplying it to
+.I regexec
+or
+.I regerror
+is undefined.
+.PP
+None of these functions references global variables except for tables
+of constants;
+all are safe for use from multiple threads if the arguments are safe.
+.SH IMPLEMENTATION CHOICES
+There are a number of decisions that 1003.2 leaves up to the implementor,
+either by explicitly saying ``undefined'' or by virtue of them being
+forbidden by the RE grammar.
+This implementation treats them as follows.
+.PP
+See
+.ZR
+for a discussion of the definition of case-independent matching.
+.PP
+There is no particular limit on the length of REs,
+except insofar as memory is limited.
+Memory usage is approximately linear in RE size, and largely insensitive
+to RE complexity, except for bounded repetitions.
+See BUGS for one short RE using them
+that will run almost any system out of memory.
+.PP
+A backslashed character other than one specifically given a magic meaning
+by 1003.2 (such magic meanings occur only in obsolete [``basic''] REs)
+is taken as an ordinary character.
+.PP
+Any unmatched [ is a REG_EBRACK error.
+.PP
+Equivalence classes cannot begin or end bracket-expression ranges.
+The endpoint of one range cannot begin another.
+.PP
+RE_DUP_MAX, the limit on repetition counts in bounded repetitions, is 255.
+.PP
+A repetition operator (?, *, +, or bounds) cannot follow another
+repetition operator.
+A repetition operator cannot begin an expression or subexpression
+or follow `^' or `|'.
+.PP
+`|' cannot appear first or last in a (sub)expression or after another `|',
+i.e. an operand of `|' cannot be an empty subexpression.
+An empty parenthesized subexpression, `()', is legal and matches an
+empty (sub)string.
+An empty string is not a legal RE.
+.PP
+A `{' followed by a digit is considered the beginning of bounds for a
+bounded repetition, which must then follow the syntax for bounds.
+A `{' \fInot\fR followed by a digit is considered an ordinary character.
+.PP
+`^' and `$' beginning and ending subexpressions in obsolete (``basic'')
+REs are anchors, not ordinary characters.
+.SH SEE ALSO
+grep(1), regex(7)
+.PP
+POSIX 1003.2, sections 2.8 (Regular Expression Notation)
+and
+B.5 (C Binding for Regular Expression Matching).
+.SH DIAGNOSTICS
+Non-zero error codes from
+.I regcomp
+and
+.I regexec
+include the following:
+.PP
+.nf
+.ta \w'REG_ECOLLATE'u+3n
+REG_NOMATCH regexec() failed to match
+REG_BADPAT invalid regular expression
+REG_ECOLLATE invalid collating element
+REG_ECTYPE invalid character class
+REG_EESCAPE \e applied to unescapable character
+REG_ESUBREG invalid backreference number
+REG_EBRACK brackets [ ] not balanced
+REG_EPAREN parentheses ( ) not balanced
+REG_EBRACE braces { } not balanced
+REG_BADBR invalid repetition count(s) in { }
+REG_ERANGE invalid character range in [ ]
+REG_ESPACE ran out of memory
+REG_BADRPT ?, *, or + operand invalid
+REG_EMPTY empty (sub)expression
+REG_ASSERT ``can't happen''\(emyou found a bug
+REG_INVARG invalid argument, e.g. negative-length string
+.fi
+.SH HISTORY
+Written by Henry Spencer at University of Toronto,
+henry@zoo.toronto.edu.
+.SH BUGS
+This is an alpha release with known defects.
+Please report problems.
+.PP
+There is one known functionality bug.
+The implementation of internationalization is incomplete:
+the locale is always assumed to be the default one of 1003.2,
+and only the collating elements etc. of that locale are available.
+.PP
+The back-reference code is subtle and doubts linger about its correctness
+in complex cases.
+.PP
+.I Regexec
+performance is poor.
+This will improve with later releases.
+.I Nmatch
+exceeding 0 is expensive;
+.I nmatch
+exceeding 1 is worse.
+.I Regexec
+is largely insensitive to RE complexity \fIexcept\fR that back
+references are massively expensive.
+RE length does matter; in particular, there is a strong speed bonus
+for keeping RE length under about 30 characters,
+with most special characters counting roughly double.
+.PP
+.I Regcomp
+implements bounded repetitions by macro expansion,
+which is costly in time and space if counts are large
+or bounded repetitions are nested.
+An RE like, say,
+`((((a{1,100}){1,100}){1,100}){1,100}){1,100}'
+will (eventually) run almost any existing machine out of swap space.
+.PP
+There are suspected problems with response to obscure error conditions.
+Notably,
+certain kinds of internal overflow,
+produced only by truly enormous REs or by multiply nested bounded repetitions,
+are probably not handled well.
+.PP
+Due to a mistake in 1003.2, things like `a)b' are legal REs because `)' is
+a special character only in the presence of a previous unmatched `('.
+This can't be fixed until the spec is fixed.
+.PP
+The standard's definition of back references is vague.
+For example, does
+`a\e(\e(b\e)*\e2\e)*d' match `abbbd'?
+Until the standard is clarified,
+behavior in such cases should not be relied on.
+.PP
+The implementation of word-boundary matching is a bit of a kludge,
+and bugs may lurk in combinations of word-boundary matching and anchoring.
diff --git a/regex/regex.7 b/regex/regex.7
new file mode 100644
index 00000000000..d89012bda1d
--- /dev/null
+++ b/regex/regex.7
@@ -0,0 +1,233 @@
+.TH REGEX 7 "7 Feb 1994"
+.BY "Henry Spencer"
+.SH NAME
+regex \- POSIX 1003.2 regular expressions
+.SH DESCRIPTION
+Regular expressions (``RE''s),
+as defined in POSIX 1003.2, come in two forms:
+modern REs (roughly those of
+.IR egrep ;
+1003.2 calls these ``extended'' REs)
+and obsolete REs (roughly those of
+.IR ed ;
+1003.2 ``basic'' REs).
+Obsolete REs mostly exist for backward compatibility in some old programs;
+they will be discussed at the end.
+1003.2 leaves some aspects of RE syntax and semantics open;
+`\(dg' marks decisions on these aspects that
+may not be fully portable to other 1003.2 implementations.
+.PP
+A (modern) RE is one\(dg or more non-empty\(dg \fIbranches\fR,
+separated by `|'.
+It matches anything that matches one of the branches.
+.PP
+A branch is one\(dg or more \fIpieces\fR, concatenated.
+It matches a match for the first, followed by a match for the second, etc.
+.PP
+A piece is an \fIatom\fR possibly followed
+by a single\(dg `*', `+', `?', or \fIbound\fR.
+An atom followed by `*' matches a sequence of 0 or more matches of the atom.
+An atom followed by `+' matches a sequence of 1 or more matches of the atom.
+An atom followed by `?' matches a sequence of 0 or 1 matches of the atom.
+.PP
+A \fIbound\fR is `{' followed by an unsigned decimal integer,
+possibly followed by `,'
+possibly followed by another unsigned decimal integer,
+always followed by `}'.
+The integers must lie between 0 and RE_DUP_MAX (255\(dg) inclusive,
+and if there are two of them, the first may not exceed the second.
+An atom followed by a bound containing one integer \fIi\fR
+and no comma matches
+a sequence of exactly \fIi\fR matches of the atom.
+An atom followed by a bound
+containing one integer \fIi\fR and a comma matches
+a sequence of \fIi\fR or more matches of the atom.
+An atom followed by a bound
+containing two integers \fIi\fR and \fIj\fR matches
+a sequence of \fIi\fR through \fIj\fR (inclusive) matches of the atom.
+.PP
+An atom is a regular expression enclosed in `()' (matching a match for the
+regular expression),
+an empty set of `()' (matching the null string)\(dg,
+a \fIbracket expression\fR (see below), `.'
+(matching any single character), `^' (matching the null string at the
+beginning of a line), `$' (matching the null string at the
+end of a line), a `\e' followed by one of the characters
+`^.[$()|*+?{\e'
+(matching that character taken as an ordinary character),
+a `\e' followed by any other character\(dg
+(matching that character taken as an ordinary character,
+as if the `\e' had not been present\(dg),
+or a single character with no other significance (matching that character).
+A `{' followed by a character other than a digit is an ordinary
+character, not the beginning of a bound\(dg.
+It is illegal to end an RE with `\e'.
+.PP
+A \fIbracket expression\fR is a list of characters enclosed in `[]'.
+It normally matches any single character from the list (but see below).
+If the list begins with `^',
+it matches any single character
+(but see below) \fInot\fR from the rest of the list.
+If two characters in the list are separated by `\-', this is shorthand
+for the full \fIrange\fR of characters between those two (inclusive) in the
+collating sequence,
+e.g. `[0-9]' in ASCII matches any decimal digit.
+It is illegal\(dg for two ranges to share an
+endpoint, e.g. `a-c-e'.
+Ranges are very collating-sequence-dependent,
+and portable programs should avoid relying on them.
+.PP
+To include a literal `]' in the list, make it the first character
+(following a possible `^').
+To include a literal `\-', make it the first or last character,
+or the second endpoint of a range.
+To use a literal `\-' as the first endpoint of a range,
+enclose it in `[.' and `.]' to make it a collating element (see below).
+With the exception of these and some combinations using `[' (see next
+paragraphs), all other special characters, including `\e', lose their
+special significance within a bracket expression.
+.PP
+Within a bracket expression, a collating element (a character,
+a multi-character sequence that collates as if it were a single character,
+or a collating-sequence name for either)
+enclosed in `[.' and `.]' stands for the
+sequence of characters of that collating element.
+The sequence is a single element of the bracket expression's list.
+A bracket expression containing a multi-character collating element
+can thus match more than one character,
+e.g. if the collating sequence includes a `ch' collating element,
+then the RE `[[.ch.]]*c' matches the first five characters
+of `chchcc'.
+.PP
+Within a bracket expression, a collating element enclosed in `[=' and
+`=]' is an equivalence class, standing for the sequences of characters
+of all collating elements equivalent to that one, including itself.
+(If there are no other equivalent collating elements,
+the treatment is as if the enclosing delimiters were `[.' and `.]'.)
+For example, if o and \o'o^' are the members of an equivalence class,
+then `[[=o=]]', `[[=\o'o^'=]]', and `[o\o'o^']' are all synonymous.
+An equivalence class may not\(dg be an endpoint
+of a range.
+.PP
+Within a bracket expression, the name of a \fIcharacter class\fR enclosed
+in `[:' and `:]' stands for the list of all characters belonging to that
+class.
+Standard character class names are:
+.PP
+.RS
+.nf
+.ta 3c 6c 9c
+alnum digit punct
+alpha graph space
+blank lower upper
+cntrl print xdigit
+.fi
+.RE
+.PP
+These stand for the character classes defined in
+.IR ctype (3).
+A locale may provide others.
+A character class may not be used as an endpoint of a range.
+.PP
+There are two special cases\(dg of bracket expressions:
+the bracket expressions `[[:<:]]' and `[[:>:]]' match the null string at
+the beginning and end of a word respectively.
+A word is defined as a sequence of
+word characters
+which is neither preceded nor followed by
+word characters.
+A word character is an
+.I alnum
+character (as defined by
+.IR ctype (3))
+or an underscore.
+This is an extension,
+compatible with but not specified by POSIX 1003.2,
+and should be used with
+caution in software intended to be portable to other systems.
+.PP
+In the event that an RE could match more than one substring of a given
+string,
+the RE matches the one starting earliest in the string.
+If the RE could match more than one substring starting at that point,
+it matches the longest.
+Subexpressions also match the longest possible substrings, subject to
+the constraint that the whole match be as long as possible,
+with subexpressions starting earlier in the RE taking priority over
+ones starting later.
+Note that higher-level subexpressions thus take priority over
+their lower-level component subexpressions.
+.PP
+Match lengths are measured in characters, not collating elements.
+A null string is considered longer than no match at all.
+For example,
+`bb*' matches the three middle characters of `abbbc',
+`(wee|week)(knights|nights)' matches all ten characters of `weeknights',
+when `(.*).*' is matched against `abc' the parenthesized subexpression
+matches all three characters, and
+when `(a*)*' is matched against `bc' both the whole RE and the parenthesized
+subexpression match the null string.
+.PP
+If case-independent matching is specified,
+the effect is much as if all case distinctions had vanished from the
+alphabet.
+When an alphabetic that exists in multiple cases appears as an
+ordinary character outside a bracket expression, it is effectively
+transformed into a bracket expression containing both cases,
+e.g. `x' becomes `[xX]'.
+When it appears inside a bracket expression, all case counterparts
+of it are added to the bracket expression, so that (e.g.) `[x]'
+becomes `[xX]' and `[^x]' becomes `[^xX]'.
+.PP
+No particular limit is imposed on the length of REs\(dg.
+Programs intended to be portable should not employ REs longer
+than 256 bytes,
+as an implementation can refuse to accept such REs and remain
+POSIX-compliant.
+.PP
+Obsolete (``basic'') regular expressions differ in several respects.
+`|', `+', and `?' are ordinary characters and there is no equivalent
+for their functionality.
+The delimiters for bounds are `\e{' and `\e}',
+with `{' and `}' by themselves ordinary characters.
+The parentheses for nested subexpressions are `\e(' and `\e)',
+with `(' and `)' by themselves ordinary characters.
+`^' is an ordinary character except at the beginning of the
+RE or\(dg the beginning of a parenthesized subexpression,
+`$' is an ordinary character except at the end of the
+RE or\(dg the end of a parenthesized subexpression,
+and `*' is an ordinary character if it appears at the beginning of the
+RE or the beginning of a parenthesized subexpression
+(after a possible leading `^').
+Finally, there is one new type of atom, a \fIback reference\fR:
+`\e' followed by a non-zero decimal digit \fId\fR
+matches the same sequence of characters
+matched by the \fId\fRth parenthesized subexpression
+(numbering subexpressions by the positions of their opening parentheses,
+left to right),
+so that (e.g.) `\e([bc]\e)\e1' matches `bb' or `cc' but not `bc'.
+.SH SEE ALSO
+regex(3)
+.PP
+POSIX 1003.2, section 2.8 (Regular Expression Notation).
+.SH BUGS
+Having two kinds of REs is a botch.
+.PP
+The current 1003.2 spec says that `)' is an ordinary character in
+the absence of an unmatched `(';
+this was an unintentional result of a wording error,
+and change is likely.
+Avoid relying on it.
+.PP
+Back references are a dreadful botch,
+posing major problems for efficient implementations.
+They are also somewhat vaguely defined
+(does
+`a\e(\e(b\e)*\e2\e)*d' match `abbbd'?).
+Avoid using them.
+.PP
+1003.2's specification of case-independent matching is vague.
+The ``one case implies all cases'' definition given above
+is current consensus among implementors as to the right interpretation.
+.PP
+The syntax for word boundaries is incredibly ugly.
diff --git a/regex/regex.h b/regex/regex.h
new file mode 100644
index 00000000000..fb2cd29ea46
--- /dev/null
+++ b/regex/regex.h
@@ -0,0 +1,79 @@
+#ifndef _REGEX_H_
+#define _REGEX_H_ /* never again */
+/* ========= begin header generated by ./mkh ========= */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* === regex2.h === */
+typedef off_t regoff_t;
+struct re_guts; /* none of your business :-) */
+typedef struct {
+ int re_magic;
+ size_t re_nsub; /* number of parenthesized subexpressions */
+ const char *re_endp; /* end pointer for REG_PEND */
+ struct re_guts *re_g; /* none of your business :-) */
+} regex_t;
+typedef struct {
+ regoff_t rm_so; /* start of match */
+ regoff_t rm_eo; /* end of match */
+} regmatch_t;
+
+
+/* === regcomp.c === */
+extern int regcomp(regex_t *, const char *, int);
+#define REG_BASIC 0000
+#define REG_EXTENDED 0001
+#define REG_ICASE 0002
+#define REG_NOSUB 0004
+#define REG_NEWLINE 0010
+#define REG_NOSPEC 0020
+#define REG_PEND 0040
+#define REG_DUMP 0200
+
+
+/* === regerror.c === */
+#define REG_NOMATCH 1
+#define REG_BADPAT 2
+#define REG_ECOLLATE 3
+#define REG_ECTYPE 4
+#define REG_EESCAPE 5
+#define REG_ESUBREG 6
+#define REG_EBRACK 7
+#define REG_EPAREN 8
+#define REG_EBRACE 9
+#define REG_BADBR 10
+#define REG_ERANGE 11
+#define REG_ESPACE 12
+#define REG_BADRPT 13
+#define REG_EMPTY 14
+#define REG_ASSERT 15
+#define REG_INVARG 16
+#define REG_ATOI 255 /* convert name to number (!) */
+#define REG_ITOA 0400 /* convert number to name (!) */
+extern size_t regerror(int, const regex_t *, char *, size_t);
+
+
+/* === regexec.c === */
+extern int regexec(const regex_t *, const char *, size_t, regmatch_t [], int);
+#define REG_NOTBOL 00001
+#define REG_NOTEOL 00002
+#define REG_STARTEND 00004
+#define REG_TRACE 00400 /* tracing of execution */
+#define REG_LARGE 01000 /* force large representation */
+#define REG_BACKR 02000 /* force use of backref code */
+
+
+/* === regfree.c === */
+extern void regfree(regex_t *);
+
+/* === reginit.c === */
+
+extern void regex_init(void); /* Should be called for multithread progs */
+extern void regex_end(void); /* If one wants a clean end */
+
+#ifdef __cplusplus
+}
+#endif
+/* ========= end header generated by ./mkh ========= */
+#endif
diff --git a/regex/regex2.h b/regex/regex2.h
new file mode 100644
index 00000000000..2023716eb4a
--- /dev/null
+++ b/regex/regex2.h
@@ -0,0 +1,145 @@
+/*
+ * First, the stuff that ends up in the outside-world include file
+ = typedef off_t regoff_t;
+ = typedef struct {
+ = int re_magic;
+ = size_t re_nsub; // number of parenthesized subexpressions
+ = const char *re_endp; // end pointer for REG_PEND
+ = struct re_guts *re_g; // none of your business :-)
+ = } regex_t;
+ = typedef struct {
+ = regoff_t rm_so; // start of match
+ = regoff_t rm_eo; // end of match
+ = } regmatch_t;
+ */
+/*
+ * internals of regex_t
+ */
+#ifndef __regex2_h__
+#define __regex2_h__
+
+#define MAGIC1 ((('r'^0200)<<8) | 'e')
+
+/*
+ * The internal representation is a *strip*, a sequence of
+ * operators ending with an endmarker. (Some terminology etc. is a
+ * historical relic of earlier versions which used multiple strips.)
+ * Certain oddities in the representation are there to permit running
+ * the machinery backwards; in particular, any deviation from sequential
+ * flow must be marked at both its source and its destination. Some
+ * fine points:
+ *
+ * - OPLUS_ and O_PLUS are *inside* the loop they create.
+ * - OQUEST_ and O_QUEST are *outside* the bypass they create.
+ * - OCH_ and O_CH are *outside* the multi-way branch they create, while
+ * OOR1 and OOR2 are respectively the end and the beginning of one of
+ * the branches. Note that there is an implicit OOR2 following OCH_
+ * and an implicit OOR1 preceding O_CH.
+ *
+ * In state representations, an operator's bit is on to signify a state
+ * immediately *preceding* "execution" of that operator.
+ */
+typedef unsigned long sop; /* strip operator */
+typedef long sopno;
+#define OPRMASK 0xf8000000
+#define OPDMASK 0x07ffffff
+#define OPSHIFT ((unsigned long)27)
+#define OP(n) ((unsigned long) ((n)&OPRMASK))
+#define OPND(n) ((unsigned long) ((n)&OPDMASK))
+#define SOP(op, opnd) (unsigned long) ((op)|(opnd))
+#define OSHIFT(A) ((unsigned long) (A) << OPSHIFT)
+/* operators meaning operand */
+/* (back, fwd are offsets) */
+#define OEND OSHIFT(1) /* endmarker - */
+#define OCHAR OSHIFT(2) /* character unsigned char */
+#define OBOL OSHIFT(3) /* left anchor - */
+#define OEOL OSHIFT(4) /* right anchor - */
+#define OANY OSHIFT(5) /* . - */
+#define OANYOF OSHIFT(6) /* [...] set number */
+#define OBACK_ OSHIFT(7) /* begin \d paren number */
+#define O_BACK OSHIFT(8) /* end \d paren number */
+#define OPLUS_ OSHIFT(9) /* + prefix fwd to suffix */
+#define O_PLUS OSHIFT(10) /* + suffix back to prefix */
+#define OQUEST_ OSHIFT(11) /* ? prefix fwd to suffix */
+#define O_QUEST OSHIFT(12) /* ? suffix back to prefix */
+#define OLPAREN OSHIFT(13) /* ( fwd to ) */
+#define ORPAREN OSHIFT(14) /* ) back to ( */
+#define OCH_ OSHIFT(15) /* begin choice fwd to OOR2 */
+#define OOR1 OSHIFT(16) /* | pt. 1 back to OOR1 or OCH_ */
+#define OOR2 OSHIFT(17) /* | pt. 2 fwd to OOR2 or O_CH */
+#define O_CH OSHIFT(18) /* end choice back to OOR1 */
+#define OBOW OSHIFT(19) /* begin word - */
+#define OEOW OSHIFT(20) /* end word - */
+
+/*
+ * Structure for [] character-set representation. Character sets are
+ * done as bit vectors, grouped 8 to a byte vector for compactness.
+ * The individual set therefore has both a pointer to the byte vector
+ * and a mask to pick out the relevant bit of each byte. A hash code
+ * simplifies testing whether two sets could be identical.
+ *
+ * This will get trickier for multicharacter collating elements. As
+ * preliminary hooks for dealing with such things, we also carry along
+ * a string of multi-character elements, and decide the size of the
+ * vectors at run time.
+ */
+#ifdef __WIN__
+typedef unsigned char uch ;
+#endif
+
+typedef struct {
+ uch *ptr; /* -> uch [csetsize] */
+ uch mask; /* bit within array */
+ uch hash; /* hash code */
+ size_t smultis;
+ char *multis; /* -> char[smulti] ab\0cd\0ef\0\0 */
+} cset;
+/* note that CHadd and CHsub are unsafe, and CHIN doesn't yield 0/1 */
+#define CHadd(cs, c) ((cs)->ptr[(uch)(c)] |= (cs)->mask, (cs)->hash += (c))
+#define CHsub(cs, c) ((cs)->ptr[(uch)(c)] &= ~(cs)->mask, (cs)->hash -= (c))
+#define CHIN(cs, c) ((cs)->ptr[(uch)(c)] & (cs)->mask)
+#define MCadd(p, cs, cp) mcadd(p, cs, cp) /* regcomp() internal fns */
+#define MCsub(p, cs, cp) mcsub(p, cs, cp)
+#define MCin(p, cs, cp) mcin(p, cs, cp)
+
+/* stuff for character categories */
+typedef unsigned char cat_t;
+
+/*
+ * main compiled-expression structure
+ */
+struct re_guts {
+ int magic;
+# define MAGIC2 ((('R'^0200)<<8)|'E')
+ sop *strip; /* malloced area for strip */
+ int csetsize; /* number of bits in a cset vector */
+ int ncsets; /* number of csets in use */
+ cset *sets; /* -> cset [ncsets] */
+ uch *setbits; /* -> uch[csetsize][ncsets/CHAR_BIT] */
+ int cflags; /* copy of regcomp() cflags argument */
+ sopno nstates; /* = number of sops */
+ sopno firststate; /* the initial OEND (normally 0) */
+ sopno laststate; /* the final OEND */
+ int iflags; /* internal flags */
+# define USEBOL 01 /* used ^ */
+# define USEEOL 02 /* used $ */
+# define BAD 04 /* something wrong */
+ int nbol; /* number of ^ used */
+ int neol; /* number of $ used */
+ int ncategories; /* how many character categories */
+ cat_t *categories; /* ->catspace[-CHAR_MIN] */
+ char *must; /* match must contain this string */
+ int mlen; /* length of must */
+ size_t nsub; /* copy of re_nsub */
+ int backrefs; /* does it use back references? */
+ sopno nplus; /* how deep does it nest +s? */
+ /* catspace must be last */
+ cat_t catspace[1]; /* actually [NC] */
+};
+
+/* misc utilities */
+#undef OUT /* May be defined in windows */
+#define OUT (CHAR_MAX+1) /* a non-character value */
+#define ISWORD(c) (isalnum(c) || (c) == '_')
+
+#endif /* __regex2_h__ */
diff --git a/regex/regexec.c b/regex/regexec.c
new file mode 100644
index 00000000000..c52a79fd8f5
--- /dev/null
+++ b/regex/regexec.c
@@ -0,0 +1,139 @@
+/*
+ * the outer shell of regexec()
+ *
+ * This file includes engine.c *twice*, after muchos fiddling with the
+ * macros that code uses. This lets the same code operate on two different
+ * representations for state sets.
+ */
+#include <global.h>
+#include <m_string.h>
+#include <m_ctype.h>
+#include <regex.h>
+#ifdef __WIN__
+#include <limits.h>
+#endif
+
+#include "utils.h"
+#include "regex2.h"
+
+static int nope = 0; /* for use in asserts; shuts lint up */
+
+/* macros for manipulating states, small version */
+#define states long
+#define states1 states /* for later use in regexec() decision */
+#define CLEAR(v) ((v) = 0)
+#define SET0(v, n) ((v) &= ~(1 << (n)))
+#define SET1(v, n) ((v) |= 1 << (n))
+#define ISSET(v, n) ((v) & (1 << (n)))
+#define ASSIGN(d, s) ((d) = (s))
+#define EQ(a, b) ((a) == (b))
+#define STATEVARS int dummy /* dummy version */
+#define STATESETUP(m, n) /* nothing */
+#define STATETEARDOWN(m) /* nothing */
+#define SETUP(v) ((v) = 0)
+#define onestate int
+#define INIT(o, n) ((o) = (unsigned)1 << (n))
+#define INC(o) ((o) <<= 1)
+#define ISSTATEIN(v, o) ((v) & (o))
+/* some abbreviations; note that some of these know variable names! */
+/* do "if I'm here, I can also be there" etc without branches */
+#define FWD(dst, src, n) ((dst) |= ((unsigned)(src)&(here)) << (n))
+#define BACK(dst, src, n) ((dst) |= ((unsigned)(src)&(here)) >> (n))
+#define ISSETBACK(v, n) ((v) & ((unsigned)here >> (n)))
+/* function names */
+#define SNAMES /* engine.c looks after details */
+
+#include "engine.c"
+
+/* now undo things */
+#undef states
+#undef CLEAR
+#undef SET0
+#undef SET1
+#undef ISSET
+#undef ASSIGN
+#undef EQ
+#undef STATEVARS
+#undef STATESETUP
+#undef STATETEARDOWN
+#undef SETUP
+#undef onestate
+#undef INIT
+#undef INC
+#undef ISSTATEIN
+#undef FWD
+#undef BACK
+#undef ISSETBACK
+#undef SNAMES
+
+/* macros for manipulating states, large version */
+#define states char *
+#define CLEAR(v) memset(v, 0, m->g->nstates)
+#define SET0(v, n) ((v)[n] = 0)
+#define SET1(v, n) ((v)[n] = 1)
+#define ISSET(v, n) ((v)[n])
+#define ASSIGN(d, s) memcpy(d, s, m->g->nstates)
+#define EQ(a, b) (memcmp(a, b, m->g->nstates) == 0)
+#define STATEVARS int vn; char *space
+#define STATESETUP(m, nv) { (m)->space = malloc((nv)*(m)->g->nstates); \
+ if ((m)->space == NULL) return(REG_ESPACE); \
+ (m)->vn = 0; }
+#define STATETEARDOWN(m) { free((m)->space); }
+#define SETUP(v) ((v) = &m->space[m->vn++ * m->g->nstates])
+#define onestate int
+#define INIT(o, n) ((o) = (n))
+#define INC(o) ((o)++)
+#define ISSTATEIN(v, o) ((v)[o])
+/* some abbreviations; note that some of these know variable names! */
+/* do "if I'm here, I can also be there" etc without branches */
+#define FWD(dst, src, n) ((dst)[here+(n)] |= (src)[here])
+#define BACK(dst, src, n) ((dst)[here-(n)] |= (src)[here])
+#define ISSETBACK(v, n) ((v)[here - (n)])
+/* function names */
+#define LNAMES /* flag */
+
+#include "engine.c"
+
+/*
+ - regexec - interface for matching
+ = extern int regexec(const regex_t *, const char *, size_t, \
+ = regmatch_t [], int);
+ = #define REG_NOTBOL 00001
+ = #define REG_NOTEOL 00002
+ = #define REG_STARTEND 00004
+ = #define REG_TRACE 00400 // tracing of execution
+ = #define REG_LARGE 01000 // force large representation
+ = #define REG_BACKR 02000 // force use of backref code
+ *
+ * We put this here so we can exploit knowledge of the state representation
+ * when choosing which matcher to call. Also, by this point the matchers
+ * have been prototyped.
+ */
+int /* 0 success, REG_NOMATCH failure */
+regexec(preg, str, nmatch, pmatch, eflags)
+const regex_t *preg;
+const char *str;
+size_t nmatch;
+regmatch_t pmatch[];
+int eflags;
+{
+ register struct re_guts *g = preg->re_g;
+#ifdef REDEBUG
+# define GOODFLAGS(f) (f)
+#else
+# define GOODFLAGS(f) ((f)&(REG_NOTBOL|REG_NOTEOL|REG_STARTEND))
+#endif
+
+ if (preg->re_magic != MAGIC1 || g->magic != MAGIC2)
+ return(REG_BADPAT);
+ assert(!(g->iflags&BAD));
+ if (g->iflags&BAD) /* backstop for no-debug case */
+ return(REG_BADPAT);
+ eflags = GOODFLAGS(eflags);
+
+ if ((size_t) g->nstates <= CHAR_BIT*sizeof(states1) &&
+ !(eflags&REG_LARGE))
+ return(smatcher(g, (char *)str, nmatch, pmatch, eflags));
+ else
+ return(lmatcher(g, (char *)str, nmatch, pmatch, eflags));
+}
diff --git a/regex/regexp.c b/regex/regexp.c
new file mode 100644
index 00000000000..706208a6b25
--- /dev/null
+++ b/regex/regexp.c
@@ -0,0 +1,1348 @@
+/*
+ *
+ * regexp.c - regular expression matching
+ *
+ * DESCRIPTION
+ *
+ * Underneath the reformatting and comment blocks which were added to
+ * make it consistent with the rest of the code, you will find a
+ * modified version of Henry Specer's regular expression library.
+ * Henry's functions were modified to provide the minimal regular
+ * expression matching, as required by P1003. Henry's code was
+ * copyrighted, and copy of the copyright message and restrictions
+ * are provided, verbatim, below:
+ *
+ * Copyright (c) 1986 by University of Toronto.
+ * Written by Henry Spencer. Not derived from licensed software.
+ *
+ * Permission is granted to anyone to use this software for any
+ * purpose on any computer system, and to redistribute it freely,
+ * subject to the following restrictions:
+ *
+ * 1. The author is not responsible for the consequences of use of
+ * this software, no matter how awful, even if they arise
+ * from defects in it.
+ *
+ * 2. The origin of this software must not be misrepresented, either
+ * by explicit claim or by omission.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not
+ * be misrepresented as being the original software.
+ *
+ *
+ * This version modified by Ian Phillipps to return pointer to terminating
+ * NUL on substitution string. [ Temp mail address ex-igp@camcon.co.uk ]
+ *
+ * Altered by amylaar to support excompatible option and the
+ * operators \< and >\ . ( 7.Sep. 1991 )
+ *
+ * regsub altered by amylaar to take an additional parameter specifying
+ * maximum number of bytes that can be written to the memory region
+ * pointed to by dest
+ *
+ * Also altered by Fredrik Hubinette to handle the + operator and
+ * eight-bit chars. Mars 22 1996
+ *
+ *
+ * Beware that some of this code is subtly aware of the way operator
+ * precedence is structured in regular expressions. Serious changes in
+ * regular-expression syntax might require a total rethink.
+ *
+ * AUTHORS
+ *
+ * Mark H. Colburn, NAPS International (mark@jhereg.mn.org)
+ * Henry Spencer, University of Torronto (henry@utzoo.edu)
+ *
+ * Sponsored by The USENIX Association for public distribution.
+ *
+ */
+
+/* Headers */
+#include "global.h"
+#include <ctype.h>
+#include "regexp.h"
+#ifdef __WIN__
+#include <string.h>
+#else
+#include "memory.h"
+#include "error.h"
+#endif
+
+/*
+ * The "internal use only" fields in regexp.h are present to pass info from
+ * compile to execute that permits the execute phase to run lots faster on
+ * simple cases. They are:
+ *
+ * regstart char that must begin a match; '\0' if none obvious
+ * reganch is the match anchored (at beginning-of-line only)?
+ * regmust string (pointer into program) that match must include, or NULL
+ * regmlen length of regmust string
+ *
+ * Regstart and reganch permit very fast decisions on suitable starting points
+ * for a match, cutting down the work a lot. Regmust permits fast rejection
+ * of lines that cannot possibly match. The regmust tests are costly enough
+ * that regcomp() supplies a regmust only if the r.e. contains something
+ * potentially expensive (at present, the only such thing detected is * or +
+ * at the start of the r.e., which can involve a lot of backup). Regmlen is
+ * supplied because the test in regexec() needs it and regcomp() is computing
+ * it anyway.
+ */
+
+/*
+ * Structure for regexp "program". This is essentially a linear encoding
+ * of a nondeterministic finite-state machine (aka syntax charts or
+ * "railroad normal form" in parsing technology). Each node is an opcode
+ * plus a "nxt" pointer, possibly plus an operand. "Nxt" pointers of
+ * all nodes except BRANCH implement concatenation; a "nxt" pointer with
+ * a BRANCH on both ends of it is connecting two alternatives. (Here we
+ * have one of the subtle syntax dependencies: an individual BRANCH (as
+ * opposed to a collection of them) is never concatenated with anything
+ * because of operator precedence.) The operand of some types of node is
+ * a literal string; for others, it is a node leading into a sub-FSM. In
+ * particular, the operand of a BRANCH node is the first node of the branch.
+ * (NB this is *not* a tree structure: the tail of the branch connects
+ * to the thing following the set of BRANCHes.) The opcodes are:
+ */
+
+/* definition number opnd? meaning */
+#define END 0 /* no End of program. */
+#define BOL 1 /* no Match "" at beginning of line. */
+#define EOL 2 /* no Match "" at end of line. */
+#define ANY 3 /* no Match any one character. */
+#define ANYOF 4 /* str Match any character in this string. */
+#define ANYBUT 5 /* str Match any character not in this
+ * string. */
+#define BRANCH 6 /* node Match this alternative, or the
+ * nxt... */
+#define BACK 7 /* no Match "", "nxt" ptr points backward. */
+#define EXACTLY 8 /* str Match this string. */
+#define NOTHING 9 /* no Match empty string. */
+#define STAR 10 /* node Match this (simple) thing 0 or more
+ * times. */
+#define WORDSTART 11 /* node matching a start of a word */
+#define WORDEND 12 /* node matching an end of a word */
+#define OPEN 20 /* no Mark this point in input as start of
+ * #n. */
+ /* OPEN+1 is number 1, etc. */
+#define CLOSE 30 /* no Analogous to OPEN. */
+
+/*
+ * Opcode notes:
+ *
+ * BRANCH The set of branches constituting a single choice are hooked
+ * together with their "nxt" pointers, since precedence prevents
+ * anything being concatenated to any individual branch. The
+ * "nxt" pointer of the last BRANCH in a choice points to the
+ * thing following the whole choice. This is also where the
+ * final "nxt" pointer of each individual branch points; each
+ * branch starts with the operand node of a BRANCH node.
+ *
+ * BACK Normal "nxt" pointers all implicitly point forward; BACK
+ * exists to make loop structures possible.
+ *
+ * STAR complex '*', are implemented as circular BRANCH structures
+ * using BACK. Simple cases (one character per match) are
+ * implemented with STAR for speed and to minimize recursive
+ * plunges.
+ *
+ * OPEN,CLOSE ...are numbered at compile time.
+ */
+
+/*
+ * A node is one char of opcode followed by two chars of "nxt" pointer.
+ * "Nxt" pointers are stored as two 8-bit pieces, high order first. The
+ * value is a positive offset from the opcode of the node containing it.
+ * An operand, if any, simply follows the node. (Note that much of the
+ * code generation knows about this implicit relationship.)
+ *
+ * Using two bytes for the "nxt" pointer is vast overkill for most things,
+ * but allows patterns to get big without disasters.
+ */
+#define OP(p) (*(p))
+#define NEXT(p) (((*((p)+1)&0377)<<8) + (*((p)+2)&0377))
+#define OPERAND(p) ((p) + 3)
+
+/*
+ * The first byte of the regexp internal "program" is actually this magic
+ * number; the start node begins in the second byte.
+ */
+#define MAGIC 0234
+
+/*
+ * Utility definitions.
+ */
+
+#ifdef __WIN__
+#define error(X,Y) fprintf(stderr, X, Y)
+#endif
+#define regerror(X) error("Regexp: %s\n",X);
+#define SPECIAL 0x100
+#define LBRAC ('('|SPECIAL)
+#define RBRAC (')'|SPECIAL)
+#define ASTERIX ('*'|SPECIAL)
+#define PLUS ('+'|SPECIAL)
+#define OR_OP ('|'|SPECIAL)
+#define DOLLAR ('$'|SPECIAL)
+#define DOT ('.'|SPECIAL)
+#define CARET ('^'|SPECIAL)
+#define LSQBRAC ('['|SPECIAL)
+#define RSQBRAC (']'|SPECIAL)
+#define LSHBRAC ('<'|SPECIAL)
+#define RSHBRAC ('>'|SPECIAL)
+#define FAIL(m) { regerror(m); return(NULL); }
+#define ISMULT(c) ((c) == ASTERIX || (c)==PLUS)
+#define META "^$.[()|*+\\"
+#ifndef CHARBITS
+#define CHARBITS 0xff
+#define UCHARAT(p) ((int)*(unsigned char *)(p))
+#else
+#define UCHARAT(p) ((int)*(p)&CHARBITS)
+#endif
+#define ISWORDPART(c) ( isalnum(c) || (c) == '_' )
+
+/*
+ * Flags to be passed up and down.
+ */
+#define HASWIDTH 01 /* Known never to match null string. */
+#define SIMPLE 02 /* Simple enough to be STAR operand. */
+#define SPSTART 04 /* Starts with * */
+#define WORST 0 /* Worst case. */
+#ifdef __WIN__
+#define STRCHR(A,B) strchr(A,B)
+#endif
+
+/*
+ * Global work variables for regcomp().
+ */
+static short *regparse; /* Input-scan pointer. */
+static int regnpar; /* () count. */
+static char regdummy;
+static char *regcode; /* Code-emit pointer; &regdummy = don't. */
+static long regsize; /* Code size. */
+
+/*
+ * Forward declarations for regcomp()'s friends.
+ */
+#ifndef STATIC
+#define STATIC static
+#endif
+STATIC char *reg();
+STATIC char *regbranch();
+STATIC char *regpiece();
+STATIC char *regatom();
+STATIC char *regnode();
+STATIC char *regnext();
+STATIC void regc();
+STATIC void reginsert();
+STATIC void regtail();
+STATIC void regoptail();
+
+/*
+ - regcomp - compile a regular expression into internal code
+ *
+ * We can't allocate space until we know how big the compiled form will be,
+ * but we can't compile it (and thus know how big it is) until we've got a
+ * place to put the code. So we cheat: we compile it twice, once with code
+ * generation turned off and size counting turned on, and once "for real".
+ * This also means that we don't allocate space until we are sure that the
+ * thing really will compile successfully, and we never have to move the
+ * code and thus invalidate pointers into it. (Note that it has to be in
+ * one piece because free() must be able to free it all.)
+ *
+ * Beware that the optimization-preparation code in here knows about some
+ * of the structure of the compiled regexp.
+ */
+regexp *regcomp(exp,excompat)
+char *exp;
+int excompat; /* \( \) operators like in unix ex */
+{
+ register regexp *r;
+ register char *scan;
+ register char *longest;
+ register int len;
+ int flags;
+ short *exp2,*dest,c;
+
+ if (exp == (char *)NULL)
+ FAIL("NULL argument");
+
+ exp2=(short*)malloc( (strlen(exp)+1) * (sizeof(short[8])/sizeof(char[8])) );
+ for ( scan=exp,dest=exp2;( c= UCHARAT(scan++)); ) {
+ switch (c) {
+ case '(':
+ case ')':
+ *dest++ = excompat ? c : c | SPECIAL;
+ break;
+ case '.':
+ case '*':
+ case '+':
+ case '|':
+ case '$':
+ case '^':
+ case '[':
+ case ']':
+ *dest++ = c | SPECIAL;
+ break;
+ case '\\':
+ switch ( c = *scan++ ) {
+ case '(':
+ case ')':
+ *dest++ = excompat ? c | SPECIAL : c;
+ break;
+ case '<':
+ case '>':
+ *dest++ = c | SPECIAL;
+ break;
+ case '{':
+ case '}':
+ FAIL("sorry, unimplemented operator");
+ case 'b': *dest++ = '\b'; break;
+ case 't': *dest++ = '\t'; break;
+ case 'r': *dest++ = '\r'; break;
+ default:
+ *dest++ = c;
+ }
+ break;
+ default:
+ *dest++ = c;
+ }
+ }
+ *dest=0;
+ /* First pass: determine size, legality. */
+ regparse = exp2;
+ regnpar = 1;
+ regsize = 0L;
+ regcode = &regdummy;
+ regc(MAGIC);
+ if (reg(0, &flags) == (char *)NULL)
+ return ((regexp *)NULL);
+
+ /* Small enough for pointer-storage convention? */
+ if (regsize >= 32767L) /* Probably could be 65535L. */
+ FAIL("regexp too big");
+
+ /* Allocate space. */
+ r = (regexp *) malloc(sizeof(regexp) + (unsigned) regsize);
+ if (r == (regexp *) NULL)
+ FAIL("out of space");
+ (void) bzero(r, sizeof(regexp) + (unsigned)regsize);
+
+ /* Second pass: emit code. */
+ regparse = exp2;
+ regnpar = 1;
+ regcode = r->program;
+ regc(MAGIC);
+ if (reg(0, &flags) == NULL)
+ return ((regexp *) NULL);
+
+ /* Dig out information for optimizations. */
+ r->regstart = '\0'; /* Worst-case defaults. */
+ r->reganch = 0;
+ r->regmust = NULL;
+ r->regmlen = 0;
+ scan = r->program + 1; /* First BRANCH. */
+ if (OP(regnext(scan)) == END) { /* Only one top-level choice. */
+ scan = OPERAND(scan);
+
+ /* Starting-point info. */
+ if (OP(scan) == EXACTLY)
+ r->regstart = *OPERAND(scan);
+ else if (OP(scan) == BOL)
+ r->reganch++;
+
+ /*
+ * If there's something expensive in the r.e., find the longest
+ * literal string that must appear and make it the regmust. Resolve
+ * ties in favor of later strings, since the regstart check works
+ * with the beginning of the r.e. and avoiding duplication
+ * strengthens checking. Not a strong reason, but sufficient in the
+ * absence of others.
+ */
+ if (flags & SPSTART) {
+ longest = NULL;
+ len = 0;
+ for (; scan != NULL; scan = regnext(scan))
+ if (OP(scan) == EXACTLY &&
+ (int)strlen(OPERAND(scan)) >= len) {
+ longest = OPERAND(scan);
+ len = strlen(OPERAND(scan));
+ }
+ r->regmust = longest;
+ r->regmlen = len;
+ }
+ }
+ free((char*)exp2);
+ return (r);
+}
+
+/*
+ - reg - regular expression, i.e. main body or parenthesized thing
+ *
+ * Caller must absorb opening parenthesis.
+ *
+ * Combining parenthesis handling with the base level of regular expression
+ * is a trifle forced, but the need to tie the tails of the branches to what
+ * follows makes it hard to avoid.
+ */
+static char *reg(paren, flagp)
+int paren; /* Parenthesized? */
+int *flagp;
+{
+ register char *ret;
+ register char *br;
+ register char *ender;
+ register int parno=0; /* make gcc happy */
+ int flags;
+
+ *flagp = HASWIDTH; /* Tentatively. */
+
+ /* Make an OPEN node, if parenthesized. */
+ if (paren) {
+ if (regnpar >= NSUBEXP)
+ FAIL("too many ()");
+ parno = regnpar;
+ regnpar++;
+ ret = regnode(OPEN + parno);
+ } else
+ ret = (char *)NULL;
+
+ /* Pick up the branches, linking them together. */
+ br = regbranch(&flags);
+ if (br == (char *)NULL)
+ return ((char *)NULL);
+ if (ret != (char *)NULL)
+ regtail(ret, br); /* OPEN -> first. */
+ else
+ ret = br;
+ if (!(flags & HASWIDTH))
+ *flagp &= ~HASWIDTH;
+ *flagp |= flags & SPSTART;
+ while (*regparse == OR_OP) {
+ regparse++;
+ br = regbranch(&flags);
+ if (br == (char *)NULL)
+ return ((char *)NULL);
+ regtail(ret, br); /* BRANCH -> BRANCH. */
+ if (!(flags & HASWIDTH))
+ *flagp &= ~HASWIDTH;
+ *flagp |= flags & SPSTART;
+ }
+
+ /* Make a closing node, and hook it on the end. */
+ ender = regnode((paren) ? CLOSE + parno : END);
+ regtail(ret, ender);
+
+ /* Hook the tails of the branches to the closing node. */
+ for (br = ret; br != (char *)NULL; br = regnext(br))
+ regoptail(br, ender);
+
+ /* Check for proper termination. */
+ if (paren && *regparse++ != RBRAC) {
+ FAIL("unmatched ()");
+ } else if (!paren && *regparse != '\0') {
+ if (*regparse == RBRAC) {
+ FAIL("unmatched ()");
+ } else
+ FAIL("junk on end");/* "Can't happen". */
+ /* NOTREACHED */
+ }
+ return (ret);
+}
+
+/*
+ - regbranch - one alternative of an | operator
+ *
+ * Implements the concatenation operator.
+ */
+static char *regbranch(flagp)
+int *flagp;
+{
+ register char *ret;
+ register char *chain;
+ register char *latest;
+ int flags;
+
+ *flagp = WORST; /* Tentatively. */
+
+ ret = regnode(BRANCH);
+ chain = (char *)NULL;
+ while (*regparse != '\0' && *regparse != OR_OP && *regparse != RBRAC) {
+ latest = regpiece(&flags);
+ if (latest == (char *)NULL)
+ return ((char *)NULL);
+ *flagp |= flags & HASWIDTH;
+ if (chain == (char *)NULL) /* First piece. */
+ *flagp |= flags & SPSTART;
+ else
+ regtail(chain, latest);
+ chain = latest;
+ }
+ if (chain == (char *)NULL) /* Loop ran zero times. */
+ regnode(NOTHING);
+
+ return (ret);
+}
+
+/*
+ - regpiece - something followed by possible [*]
+ *
+ * Note that the branching code sequence used for * is somewhat optimized:
+ * they use the same NOTHING node as both the endmarker for their branch
+ * list and the body of the last branch. It might seem that this node could
+ * be dispensed with entirely, but the endmarker role is not redundant.
+ */
+static char *regpiece(flagp)
+int *flagp;
+{
+ register char *ret;
+ register short op;
+ /* register char *nxt; */
+ int flags;
+
+ ret = regatom(&flags);
+ if (ret == (char *)NULL)
+ return ((char *)NULL);
+
+ op = *regparse;
+ if (!ISMULT(op)) {
+ *flagp = flags;
+ return (ret);
+ }
+ if (!(flags & HASWIDTH))
+ FAIL("* or + operand could be empty");
+ *flagp = (WORST | SPSTART);
+
+ if(op == ASTERIX)
+ {
+ if (flags & SIMPLE)
+ {
+ reginsert(STAR, ret);
+ }
+ else
+ {
+ /* Emit x* as (x&|), where & means "self". */
+ reginsert(BRANCH, ret); /* Either x */
+ regoptail(ret, regnode(BACK)); /* and loop */
+ regoptail(ret, ret); /* back */
+ regtail(ret, regnode(BRANCH)); /* or */
+ regtail(ret, regnode(NOTHING)); /* null. */
+ }
+ }
+ else if(op == PLUS)
+ {
+ /* Emit a+ as (a&) where & means "self" /Fredrik Hubinette */
+ char *tmp;
+ tmp=regnode(BACK);
+ reginsert(BRANCH, tmp);
+ regtail(ret, tmp);
+ regoptail(tmp, ret);
+ regtail(ret, regnode(BRANCH));
+ regtail(ret, regnode(NOTHING));
+ }
+
+ regparse++;
+ if (ISMULT(*regparse))
+ FAIL("nested * or +");
+
+ return (ret);
+}
+
+
+/*
+ - regatom - the lowest level
+ *
+ * Optimization: gobbles an entire sequence of ordinary characters so that
+ * it can turn them into a single node, which is smaller to store and
+ * faster to run.
+ */
+static char *regatom(flagp)
+int *flagp;
+{
+ register char *ret;
+ int flags;
+
+ *flagp = WORST; /* Tentatively. */
+
+ switch (*regparse++) {
+ case CARET:
+ ret = regnode(BOL);
+ break;
+ case DOLLAR:
+ ret = regnode(EOL);
+ break;
+ case DOT:
+ ret = regnode(ANY);
+ *flagp |= HASWIDTH | SIMPLE;
+ break;
+ case LSHBRAC:
+ ret = regnode(WORDSTART);
+ break;
+ case RSHBRAC:
+ ret = regnode(WORDEND);
+ break;
+ case LSQBRAC:{
+ register int class;
+ register int classend;
+
+ if (*regparse == CARET) { /* Complement of range. */
+ ret = regnode(ANYBUT);
+ regparse++;
+ } else
+ ret = regnode(ANYOF);
+ if (*regparse == RSQBRAC || *regparse == '-')
+ regc(*regparse++);
+ while (*regparse != '\0' && *regparse != RSQBRAC) {
+ if (*regparse == '-') {
+ regparse++;
+ if (*regparse == RSQBRAC || *regparse == '\0')
+ regc('-');
+ else {
+ class = (CHARBITS & *(regparse - 2)) + 1;
+ classend = (CHARBITS & *(regparse));
+ if (class > classend + 1)
+ FAIL("invalid [] range");
+ for (; class <= classend; class++)
+ regc(class);
+ regparse++;
+ }
+ } else
+ regc(*regparse++);
+ }
+ regc('\0');
+ if (*regparse != RSQBRAC)
+ FAIL("unmatched []");
+ regparse++;
+ *flagp |= HASWIDTH | SIMPLE;
+ }
+ break;
+ case LBRAC:
+ ret = reg(1, &flags);
+ if (ret == (char *)NULL)
+ return ((char *)NULL);
+ *flagp |= flags & (HASWIDTH | SPSTART);
+ break;
+ case '\0':
+ case OR_OP:
+ case RBRAC:
+ FAIL("internal urp"); /* Supposed to be caught earlier. */
+
+ case ASTERIX:
+ FAIL("* follows nothing\n");
+
+ default:{
+ register int len;
+ register short ender;
+
+ regparse--;
+ for (len=0; regparse[len] &&
+ !(regparse[len]&SPECIAL) && regparse[len] != RSQBRAC; len++) ;
+ if (len <= 0)
+ {
+ FAIL("internal disaster");
+ }
+ ender = *(regparse + len);
+ if (len > 1 && ISMULT(ender))
+ len--; /* Back off clear of * operand. */
+ *flagp |= HASWIDTH;
+ if (len == 1)
+ *flagp |= SIMPLE;
+ ret = regnode(EXACTLY);
+ while (len > 0) {
+ regc(*regparse++);
+ len--;
+ }
+ regc('\0');
+ }
+ break;
+ }
+
+ return (ret);
+}
+
+/*
+ - regnode - emit a node
+ */
+static char *regnode(op)
+char op;
+{
+ register char *ret;
+ register char *ptr;
+
+ ret = regcode;
+ if (ret == &regdummy) {
+ regsize += 3;
+ return (ret);
+ }
+ ptr = ret;
+ *ptr++ = op;
+ *ptr++ = '\0'; /* Null "nxt" pointer. */
+ *ptr++ = '\0';
+ regcode = ptr;
+
+ return (ret);
+}
+
+/*
+ - regc - emit (if appropriate) a byte of code
+ */
+static void regc(b)
+char b;
+{
+ if (regcode != &regdummy)
+ *regcode++ = b;
+ else
+ regsize++;
+}
+
+/*
+ - reginsert - insert an operator in front of already-emitted operand
+ *
+ * Means relocating the operand.
+ */
+static void reginsert(op, opnd)
+char op;
+char *opnd;
+{
+ register char *src;
+ register char *dst;
+ register char *place;
+
+ if (regcode == &regdummy) {
+ regsize += 3;
+ return;
+ }
+ src = regcode;
+ regcode += 3;
+ dst = regcode;
+ while (src > opnd)
+ *--dst = *--src;
+
+ place = opnd; /* Op node, where operand used to be. */
+ *place++ = op;
+ *place++ = '\0';
+ *place++ = '\0';
+}
+
+/*
+ - regtail - set the next-pointer at the end of a node chain
+ */
+static void regtail(p, val)
+char *p;
+char *val;
+{
+ register char *scan;
+ register char *temp;
+ register int offset;
+
+ if (p == &regdummy)
+ return;
+
+ /* Find last node. */
+ scan = p;
+ for (;;) {
+ temp = regnext(scan);
+ if (temp == (char *)NULL)
+ break;
+ scan = temp;
+ }
+
+ if (OP(scan) == BACK)
+ offset = scan - val;
+ else
+ offset = val - scan;
+ *(scan + 1) = (offset >> 8) & 0377;
+ *(scan + 2) = offset & 0377;
+}
+
+/*
+ - regoptail - regtail on operand of first argument; nop if operandless
+ */
+static void regoptail(p, val)
+char *p;
+char *val;
+{
+ /* "Operandless" and "op != BRANCH" are synonymous in practice. */
+ if (p == (char *)NULL || p == &regdummy || OP(p) != BRANCH)
+ return;
+ regtail(OPERAND(p), val);
+}
+
+/*
+ * regexec and friends
+ */
+
+/*
+ * Global work variables for regexec().
+ */
+static char *reginput; /* String-input pointer. */
+static char *regbol; /* Beginning of input, for ^ check. */
+static char **regstartp; /* Pointer to startp array. */
+static char **regendp; /* Ditto for endp. */
+
+/*
+ * Forwards.
+ */
+STATIC int regtry();
+STATIC int regmatch();
+STATIC int regrepeat();
+
+#ifdef DEBUG
+int regnarrate = 0;
+void regdump();
+STATIC char *regprop();
+#endif
+
+/*
+ - regexec - match a regexp against a string
+ */
+int regexec(prog, string)
+register regexp *prog;
+register char *string;
+{
+ register char *s;
+
+ /* Be paranoid... */
+ if (prog == (regexp *)NULL || string == (char *)NULL) {
+ regerror("NULL parameter");
+ return (0);
+ }
+ /* Check validity of program. */
+ if (UCHARAT(prog->program) != MAGIC) {
+ regerror("corrupted program");
+ return (0);
+ }
+ /* If there is a "must appear" string, look for it. */
+ if (prog->regmust != (char *)NULL) {
+ s = string;
+ while ((s = STRCHR(s, prog->regmust[0])) != (char *)NULL) {
+ if (strncmp(s, prog->regmust, prog->regmlen) == 0)
+ break; /* Found it. */
+ s++;
+ }
+ if (s == (char *)NULL) /* Not present. */
+ return (0);
+ }
+ /* Mark beginning of line for ^ . */
+ regbol = string;
+
+ /* Simplest case: anchored match need be tried only once. */
+ if (prog->reganch)
+ return (regtry(prog, string));
+
+ /* Messy cases: unanchored match. */
+ s = string;
+ if (prog->regstart != '\0')
+ /* We know what char it must start with. */
+ while ((s = STRCHR(s, prog->regstart)) != (char *)NULL) {
+ if (regtry(prog, s))
+ return (1);
+ s++;
+ }
+ else
+ /* We don't -- general case. */
+ do {
+ if (regtry(prog, s))
+ return (1);
+ } while (*s++ != '\0');
+
+ /* Failure. */
+ return (0);
+}
+
+/*
+ - regtry - try match at specific point
+ */
+
+static int regtry(regexp *prog, char *string)
+{
+ register int i;
+ register char **sp;
+ register char **ep;
+
+ reginput = string;
+ regstartp = prog->startp;
+ regendp = prog->endp;
+
+ sp = prog->startp;
+ ep = prog->endp;
+ for (i = NSUBEXP; i > 0; i--) {
+ *sp++ = (char *)NULL;
+ *ep++ = (char *)NULL;
+ }
+ if (regmatch(prog->program + 1)) {
+ prog->startp[0] = string;
+ prog->endp[0] = reginput;
+ return (1);
+ } else
+ return (0);
+}
+
+/*
+ - regmatch - main matching routine
+ *
+ * Conceptually the strategy is simple: check to see whether the current
+ * node matches, call self recursively to see whether the rest matches,
+ * and then act accordingly. In practice we make some effort to avoid
+ * recursion, in particular by going through "ordinary" nodes (that don't
+ * need to know whether the rest of the match failed) by a loop instead of
+ * by recursion.
+ */
+
+static int regmatch(char *prog)
+{
+ register char *scan; /* Current node. */
+ char *nxt; /* nxt node. */
+
+ scan = prog;
+#ifdef DEBUG
+ if (scan != (char *)NULL && regnarrate)
+ fprintf(stderr, "%s(\n", regprop(scan));
+#endif
+ while (scan != (char *)NULL) {
+#ifdef DEBUG
+ if (regnarrate)
+ fprintf(stderr, "%s...\n", regprop(scan));
+#endif
+ nxt = regnext(scan);
+
+ switch (OP(scan)) {
+ case BOL:
+ if (reginput != regbol)
+ return (0);
+ break;
+ case EOL:
+ if (*reginput != '\0')
+ return (0);
+ break;
+ case ANY:
+ if (*reginput == '\0')
+ return (0);
+ reginput++;
+ break;
+ case WORDSTART:
+ if (reginput == regbol)
+ break;
+ if (*reginput == '\0' ||
+ ISWORDPART( *(reginput-1) ) || !ISWORDPART( *reginput ) )
+ return (0);
+ break;
+ case WORDEND:
+ if (*reginput == '\0')
+ break;
+ if ( reginput == regbol ||
+ !ISWORDPART( *(reginput-1) ) || ISWORDPART( *reginput ) )
+ return (0);
+ break;
+ case EXACTLY:{
+ register int len;
+ register char *opnd;
+
+ opnd = OPERAND(scan);
+ /* Inline the first character, for speed. */
+ if (*opnd != *reginput)
+ return (0);
+ len = strlen(opnd);
+ if (len > 1 && strncmp(opnd, reginput, len) != 0)
+ return (0);
+ reginput += len;
+ }
+ break;
+ case ANYOF:
+ if (*reginput == '\0' ||
+ STRCHR(OPERAND(scan), *reginput) == (char *)NULL)
+ return (0);
+ reginput++;
+ break;
+ case ANYBUT:
+ if (*reginput == '\0' ||
+ STRCHR(OPERAND(scan), *reginput) != (char *)NULL)
+ return (0);
+ reginput++;
+ break;
+ case NOTHING:
+ break;
+ case BACK:
+ break;
+ case OPEN + 1:
+ case OPEN + 2:
+ case OPEN + 3:
+ case OPEN + 4:
+ case OPEN + 5:
+ case OPEN + 6:
+ case OPEN + 7:
+ case OPEN + 8:
+ case OPEN + 9:{
+ register int no;
+ register char *save;
+
+ no = OP(scan) - OPEN;
+ save = reginput;
+
+ if (regmatch(nxt)) {
+ /*
+ * Don't set startp if some later invocation of the same
+ * parentheses already has.
+ */
+ if (regstartp[no] == (char *)NULL)
+ regstartp[no] = save;
+ return (1);
+ } else
+ return (0);
+ }
+
+ case CLOSE + 1:
+ case CLOSE + 2:
+ case CLOSE + 3:
+ case CLOSE + 4:
+ case CLOSE + 5:
+ case CLOSE + 6:
+ case CLOSE + 7:
+ case CLOSE + 8:
+ case CLOSE + 9:{
+ register int no;
+ register char *save;
+
+ no = OP(scan) - CLOSE;
+ save = reginput;
+
+ if (regmatch(nxt)) {
+ /*
+ * Don't set endp if some later invocation of the same
+ * parentheses already has.
+ */
+ if (regendp[no] == (char *)NULL)
+ regendp[no] = save;
+ return (1);
+ } else
+ return (0);
+ }
+
+ case BRANCH:{
+ register char *save;
+
+ if (OP(nxt) != BRANCH) /* No choice. */
+ nxt = OPERAND(scan); /* Avoid recursion. */
+ else {
+ do {
+ save = reginput;
+ if (regmatch(OPERAND(scan)))
+ return (1);
+ reginput = save;
+ scan = regnext(scan);
+ } while (scan != (char *)NULL && OP(scan) == BRANCH);
+ return (0);
+ /* NOTREACHED */
+ }
+ }
+ break;
+ case STAR:{
+ register char nextch;
+ register int no;
+ register char *save;
+ register int minimum;
+
+ /*
+ * Lookahead to avoid useless match attempts when we know
+ * what character comes next.
+ */
+ nextch = '\0';
+ if (OP(nxt) == EXACTLY)
+ nextch = *OPERAND(nxt);
+ minimum = (OP(scan) == STAR) ? 0 : 1;
+ save = reginput;
+ no = regrepeat(OPERAND(scan));
+ while (no >= minimum) {
+ /* If it could work, try it. */
+ if (nextch == '\0' || *reginput == nextch)
+ if (regmatch(nxt))
+ return (1);
+ /* Couldn't or didn't -- back up. */
+ no--;
+ reginput = save + no;
+ }
+ return (0);
+ }
+
+ case END:
+ return (1); /* Success! */
+
+ default:
+ regerror("memory corruption");
+ return (0);
+
+ }
+
+ scan = nxt;
+ }
+
+ /*
+ * We get here only if there's trouble -- normally "case END" is the
+ * terminating point.
+ */
+ regerror("corrupted pointers");
+ return (0);
+}
+
+/*
+ - regrepeat - repeatedly match something simple, report how many
+ */
+
+static int regrepeat(char *p)
+{
+ register int count = 0;
+ register char *scan;
+ register char *opnd;
+
+ scan = reginput;
+ opnd = OPERAND(p);
+ switch (OP(p)) {
+ case ANY:
+ count = strlen(scan);
+ scan += count;
+ break;
+ case EXACTLY:
+ while (*opnd == *scan) {
+ count++;
+ scan++;
+ }
+ break;
+ case ANYOF:
+ while (*scan != '\0' && STRCHR(opnd, *scan) != (char *)NULL) {
+ count++;
+ scan++;
+ }
+ break;
+ case ANYBUT:
+ while (*scan != '\0' && STRCHR(opnd, *scan) == (char *)NULL) {
+ count++;
+ scan++;
+ }
+ break;
+ default: /* Oh dear. Called inappropriately. */
+ regerror("internal foulup");
+ count = 0; /* Best compromise. */
+ break;
+ }
+ reginput = scan;
+
+ return (count);
+}
+
+
+/*
+ - regnext - dig the "nxt" pointer out of a node
+ */
+
+static char *regnext(register char *p)
+{
+ register int offset;
+
+ if (p == &regdummy)
+ return ((char *)NULL);
+
+ offset = NEXT(p);
+ if (offset == 0)
+ return ((char *)NULL);
+
+ if (OP(p) == BACK)
+ return (p - offset);
+ else
+ return (p + offset);
+}
+
+#ifdef DEBUG
+
+STATIC char *regprop();
+
+/*
+ - regdump - dump a regexp onto stdout in vaguely comprehensible form
+ */
+void regdump(regexp *r)
+{
+ register char *s;
+ register char op = EXACTLY; /* Arbitrary non-END op. */
+ register char *nxt;
+
+ s = r->program + 1;
+ while (op != END) { /* While that wasn't END last time... */
+ op = OP(s);
+ printf("%2ld%s", (long)(s - r->program), regprop(s)); /* Where, what. */
+ nxt = regnext(s);
+ if (nxt == (char *)NULL) /* nxt ptr. */
+ printf("(0)");
+ else
+ printf("(%ld)", (long)( (s - r->program) + (nxt - s)));
+ s += 3;
+ if (op == ANYOF || op == ANYBUT || op == EXACTLY) {
+ /* Literal string, where present. */
+ while (*s != '\0') {
+ putchar(*s);
+ s++;
+ }
+ s++;
+ }
+ putchar('\n');
+ }
+
+ /* Header fields of interest. */
+ if (r->regstart != '\0')
+ printf("start `%c' ", r->regstart);
+ if (r->reganch)
+ printf("anchored ");
+ if (r->regmust != (char *)NULL)
+ printf("must have \"%s\"", r->regmust);
+ printf("\n");
+}
+
+/*
+ - regprop - printable representation of opcode
+ */
+
+static char *regprop(char *op)
+{
+ register char *p;
+ static char buf[50];
+
+ strcpy(buf, ":");
+
+ switch (OP(op)) {
+ case BOL:
+ p = "BOL";
+ break;
+ case EOL:
+ p = "EOL";
+ break;
+ case ANY:
+ p = "ANY";
+ break;
+ case ANYOF:
+ p = "ANYOF";
+ break;
+ case ANYBUT:
+ p = "ANYBUT";
+ break;
+ case BRANCH:
+ p = "BRANCH";
+ break;
+ case EXACTLY:
+ p = "EXACTLY";
+ break;
+ case NOTHING:
+ p = "NOTHING";
+ break;
+ case BACK:
+ p = "BACK";
+ break;
+ case END:
+ p = "END";
+ break;
+ case OPEN + 1:
+ case OPEN + 2:
+ case OPEN + 3:
+ case OPEN + 4:
+ case OPEN + 5:
+ case OPEN + 6:
+ case OPEN + 7:
+ case OPEN + 8:
+ case OPEN + 9:
+ sprintf(buf + strlen(buf), "OPEN%d", OP(op) - OPEN);
+ p = (char *)NULL;
+ break;
+ case CLOSE + 1:
+ case CLOSE + 2:
+ case CLOSE + 3:
+ case CLOSE + 4:
+ case CLOSE + 5:
+ case CLOSE + 6:
+ case CLOSE + 7:
+ case CLOSE + 8:
+ case CLOSE + 9:
+ sprintf(buf + strlen(buf), "CLOSE%d", OP(op) - CLOSE);
+ p = (char *)NULL;
+ break;
+ case STAR:
+ p = "STAR";
+ break;
+ default:
+ regerror("corrupted opcode");
+ p=(char *)NULL;
+ break;
+ }
+ if (p != (char *)NULL)
+ strcat(buf, p);
+ return (buf);
+}
+#endif
+
+/*
+ - regsub - perform substitutions after a regexp match
+ */
+
+char *regsub(regexp *prog, char *source, char *dest, int n)
+{
+ register char *src;
+ register char *dst;
+ register char c;
+ register int no;
+ register int len;
+ extern char *strncpy();
+
+ if (prog == (regexp *)NULL ||
+ source == (char *)NULL || dest == (char *)NULL) {
+ regerror("NULL parm to regsub");
+ return NULL;
+ }
+ if (UCHARAT(prog->program) != MAGIC) {
+ regerror("damaged regexp fed to regsub");
+ return NULL;
+ }
+ src = source;
+ dst = dest;
+ while ((c = *src++) != '\0') {
+ if (c == '&')
+ no = 0;
+ else if (c == '\\' && '0' <= *src && *src <= '9')
+ no = *src++ - '0';
+ else
+ no = -1;
+
+ if (no < 0) { /* Ordinary character. */
+ if (c == '\\' && (*src == '\\' || *src == '&'))
+ c = *src++;
+ if (--n < 0) { /* amylaar */
+ regerror("line too long");
+ return NULL;
+ }
+ *dst++ = c;
+ } else if (prog->startp[no] != (char *)NULL &&
+ prog->endp[no] != (char *)NULL) {
+ len = prog->endp[no] - prog->startp[no];
+ if ( (n-=len) < 0 ) { /* amylaar */
+ regerror("line too long");
+ return NULL;
+ }
+ strncpy(dst, prog->startp[no], len);
+ dst += len;
+ if (len != 0 && *(dst - 1) == '\0') { /* strncpy hit NUL. */
+ regerror("damaged match string");
+ return NULL;
+ }
+ }
+ }
+ if (--n < 0) { /* amylaar */
+ regerror("line too long");
+ return NULL;
+ }
+ *dst = '\0';
+ return dst;
+}
+
+
+#if 0 /* Use the local regerror() in ed.c */
+
+void regerror(char *s)
+{
+ fprintf(stderr, "regexp(3): %s", s);
+ exit(1);
+}
+#endif /* 0 */
diff --git a/regex/regfree.c b/regex/regfree.c
new file mode 100644
index 00000000000..a0dd8087a45
--- /dev/null
+++ b/regex/regfree.c
@@ -0,0 +1,38 @@
+#include <global.h>
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <regex.h>
+
+#include "utils.h"
+#include "regex2.h"
+
+/*
+ - regfree - free everything
+ = extern void regfree(regex_t *);
+ */
+void
+regfree(preg)
+regex_t *preg;
+{
+ register struct re_guts *g;
+
+ if (preg->re_magic != MAGIC1) /* oops */
+ return; /* nice to complain, but hard */
+
+ g = preg->re_g;
+ if (g == NULL || g->magic != MAGIC2) /* oops again */
+ return;
+ preg->re_magic = 0; /* mark it invalid */
+ g->magic = 0; /* mark it invalid */
+
+ if (g->strip != NULL)
+ free((char *)g->strip);
+ if (g->sets != NULL)
+ free((char *)g->sets);
+ if (g->setbits != NULL)
+ free((char *)g->setbits);
+ if (g->must != NULL)
+ free(g->must);
+ free((char *)g);
+}
diff --git a/regex/reginit.c b/regex/reginit.c
new file mode 100644
index 00000000000..b5815e7d01c
--- /dev/null
+++ b/regex/reginit.c
@@ -0,0 +1,71 @@
+/* Init cclasses array from ctypes */
+
+#include <global.h>
+#include <m_ctype.h>
+#include <m_string.h>
+#include "cclass.h"
+
+static bool regex_inited=0;
+
+void regex_init()
+{
+ char buff[CCLASS_LAST][256];
+ int count[CCLASS_LAST];
+ uint i;
+
+ if (!regex_inited)
+ {
+ regex_inited=1;
+ bzero((gptr) &count,sizeof(count));
+
+ for (i=1 ; i<= 255; i++)
+ {
+ if (isalnum(i))
+ buff[CCLASS_ALNUM][count[CCLASS_ALNUM]++]=(char) i;
+ if (isalpha(i))
+ buff[CCLASS_ALPHA][count[CCLASS_ALPHA]++]=(char) i;
+ if (iscntrl(i))
+ buff[CCLASS_CNTRL][count[CCLASS_CNTRL]++]=(char) i;
+ if (isdigit(i))
+ buff[CCLASS_DIGIT][count[CCLASS_DIGIT]++]=(char) i;
+ if (isgraph(i))
+ buff[CCLASS_GRAPH][count[CCLASS_GRAPH]++]=(char) i;
+ if (islower(i))
+ buff[CCLASS_LOWER][count[CCLASS_LOWER]++]=(char) i;
+ if (isprint(i))
+ buff[CCLASS_PRINT][count[CCLASS_PRINT]++]=(char) i;
+ if (ispunct(i))
+ buff[CCLASS_PUNCT][count[CCLASS_PUNCT]++]=(char) i;
+ if (isspace(i))
+ buff[CCLASS_SPACE][count[CCLASS_SPACE]++]=(char) i;
+ if (isupper(i))
+ buff[CCLASS_UPPER][count[CCLASS_UPPER]++]=(char) i;
+ if (isxdigit(i))
+ buff[CCLASS_XDIGIT][count[CCLASS_XDIGIT]++]=(char) i;
+ }
+ buff[CCLASS_BLANK][0]=' ';
+ buff[CCLASS_BLANK][1]='\t';
+ count[CCLASS_BLANK]=2;
+ for (i=0; i < CCLASS_LAST ; i++)
+ {
+ char *tmp=(char*) malloc(count[i]+1);
+ memcpy(tmp,buff[i],count[i]*sizeof(char));
+ tmp[count[i]]=0;
+ cclasses[i].chars=tmp;
+ }
+ }
+ return;
+}
+
+void regex_end()
+{
+ if (regex_inited)
+ {
+ int i;
+ for (i=0; i < CCLASS_LAST ; i++)
+ free(cclasses[i].chars);
+ regex_inited=0;
+ }
+}
+
+
diff --git a/regex/split.c b/regex/split.c
new file mode 100644
index 00000000000..188bdb775b9
--- /dev/null
+++ b/regex/split.c
@@ -0,0 +1,316 @@
+#include <stdio.h>
+#include <string.h>
+
+/*
+ - split - divide a string into fields, like awk split()
+ = int split(char *string, char *fields[], int nfields, char *sep);
+ */
+int /* number of fields, including overflow */
+split(string, fields, nfields, sep)
+char *string;
+char *fields[]; /* list is not NULL-terminated */
+int nfields; /* number of entries available in fields[] */
+char *sep; /* "" white, "c" single char, "ab" [ab]+ */
+{
+ register char *p = string;
+ register char c; /* latest character */
+ register char sepc = sep[0];
+ register char sepc2;
+ register int fn;
+ register char **fp = fields;
+ register char *sepp;
+ register int trimtrail;
+
+ /* white space */
+ if (sepc == '\0') {
+ while ((c = *p++) == ' ' || c == '\t')
+ continue;
+ p--;
+ trimtrail = 1;
+ sep = " \t"; /* note, code below knows this is 2 long */
+ sepc = ' ';
+ } else
+ trimtrail = 0;
+ sepc2 = sep[1]; /* now we can safely pick this up */
+
+ /* catch empties */
+ if (*p == '\0')
+ return(0);
+
+ /* single separator */
+ if (sepc2 == '\0') {
+ fn = nfields;
+ for (;;) {
+ *fp++ = p;
+ fn--;
+ if (fn == 0)
+ break;
+ while ((c = *p++) != sepc)
+ if (c == '\0')
+ return(nfields - fn);
+ *(p-1) = '\0';
+ }
+ /* we have overflowed the fields vector -- just count them */
+ fn = nfields;
+ for (;;) {
+ while ((c = *p++) != sepc)
+ if (c == '\0')
+ return(fn);
+ fn++;
+ }
+ /* not reached */
+ }
+
+ /* two separators */
+ if (sep[2] == '\0') {
+ fn = nfields;
+ for (;;) {
+ *fp++ = p;
+ fn--;
+ while ((c = *p++) != sepc && c != sepc2)
+ if (c == '\0') {
+ if (trimtrail && **(fp-1) == '\0')
+ fn++;
+ return(nfields - fn);
+ }
+ if (fn == 0)
+ break;
+ *(p-1) = '\0';
+ while ((c = *p++) == sepc || c == sepc2)
+ continue;
+ p--;
+ }
+ /* we have overflowed the fields vector -- just count them */
+ fn = nfields;
+ while (c != '\0') {
+ while ((c = *p++) == sepc || c == sepc2)
+ continue;
+ p--;
+ fn++;
+ while ((c = *p++) != '\0' && c != sepc && c != sepc2)
+ continue;
+ }
+ /* might have to trim trailing white space */
+ if (trimtrail) {
+ p--;
+ while ((c = *--p) == sepc || c == sepc2)
+ continue;
+ p++;
+ if (*p != '\0') {
+ if (fn == nfields+1)
+ *p = '\0';
+ fn--;
+ }
+ }
+ return(fn);
+ }
+
+ /* n separators */
+ fn = 0;
+ for (;;) {
+ if (fn < nfields)
+ *fp++ = p;
+ fn++;
+ for (;;) {
+ c = *p++;
+ if (c == '\0')
+ return(fn);
+ sepp = sep;
+ while ((sepc = *sepp++) != '\0' && sepc != c)
+ continue;
+ if (sepc != '\0') /* it was a separator */
+ break;
+ }
+ if (fn < nfields)
+ *(p-1) = '\0';
+ for (;;) {
+ c = *p++;
+ sepp = sep;
+ while ((sepc = *sepp++) != '\0' && sepc != c)
+ continue;
+ if (sepc == '\0') /* it wasn't a separator */
+ break;
+ }
+ p--;
+ }
+
+ /* not reached */
+}
+
+#ifdef TEST_SPLIT
+
+
+/*
+ * test program
+ * pgm runs regression
+ * pgm sep splits stdin lines by sep
+ * pgm str sep splits str by sep
+ * pgm str sep n splits str by sep n times
+ */
+int
+main(argc, argv)
+int argc;
+char *argv[];
+{
+ char buf[512];
+ register int n;
+# define MNF 10
+ char *fields[MNF];
+
+ if (argc > 4)
+ for (n = atoi(argv[3]); n > 0; n--) {
+ (void) strcpy(buf, argv[1]);
+ }
+ else if (argc > 3)
+ for (n = atoi(argv[3]); n > 0; n--) {
+ (void) strcpy(buf, argv[1]);
+ (void) split(buf, fields, MNF, argv[2]);
+ }
+ else if (argc > 2)
+ dosplit(argv[1], argv[2]);
+ else if (argc > 1)
+ while (fgets(buf, sizeof(buf), stdin) != NULL) {
+ buf[strlen(buf)-1] = '\0'; /* stomp newline */
+ dosplit(buf, argv[1]);
+ }
+ else
+ regress();
+
+ exit(0);
+}
+
+dosplit(string, seps)
+char *string;
+char *seps;
+{
+# define NF 5
+ char *fields[NF];
+ register int nf;
+
+ nf = split(string, fields, NF, seps);
+ print(nf, NF, fields);
+}
+
+print(nf, nfp, fields)
+int nf;
+int nfp;
+char *fields[];
+{
+ register int fn;
+ register int bound;
+
+ bound = (nf > nfp) ? nfp : nf;
+ printf("%d:\t", nf);
+ for (fn = 0; fn < bound; fn++)
+ printf("\"%s\"%s", fields[fn], (fn+1 < nf) ? ", " : "\n");
+}
+
+#define RNF 5 /* some table entries know this */
+struct {
+ char *str;
+ char *seps;
+ int nf;
+ char *fi[RNF];
+} tests[] = {
+ "", " ", 0, { "" },
+ " ", " ", 2, { "", "" },
+ "x", " ", 1, { "x" },
+ "xy", " ", 1, { "xy" },
+ "x y", " ", 2, { "x", "y" },
+ "abc def g ", " ", 5, { "abc", "def", "", "g", "" },
+ " a bcd", " ", 4, { "", "", "a", "bcd" },
+ "a b c d e f", " ", 6, { "a", "b", "c", "d", "e f" },
+ " a b c d ", " ", 6, { "", "a", "b", "c", "d " },
+
+ "", " _", 0, { "" },
+ " ", " _", 2, { "", "" },
+ "x", " _", 1, { "x" },
+ "x y", " _", 2, { "x", "y" },
+ "ab _ cd", " _", 2, { "ab", "cd" },
+ " a_b c ", " _", 5, { "", "a", "b", "c", "" },
+ "a b c_d e f", " _", 6, { "a", "b", "c", "d", "e f" },
+ " a b c d ", " _", 6, { "", "a", "b", "c", "d " },
+
+ "", " _~", 0, { "" },
+ " ", " _~", 2, { "", "" },
+ "x", " _~", 1, { "x" },
+ "x y", " _~", 2, { "x", "y" },
+ "ab _~ cd", " _~", 2, { "ab", "cd" },
+ " a_b c~", " _~", 5, { "", "a", "b", "c", "" },
+ "a b_c d~e f", " _~", 6, { "a", "b", "c", "d", "e f" },
+ "~a b c d ", " _~", 6, { "", "a", "b", "c", "d " },
+
+ "", " _~-", 0, { "" },
+ " ", " _~-", 2, { "", "" },
+ "x", " _~-", 1, { "x" },
+ "x y", " _~-", 2, { "x", "y" },
+ "ab _~- cd", " _~-", 2, { "ab", "cd" },
+ " a_b c~", " _~-", 5, { "", "a", "b", "c", "" },
+ "a b_c-d~e f", " _~-", 6, { "a", "b", "c", "d", "e f" },
+ "~a-b c d ", " _~-", 6, { "", "a", "b", "c", "d " },
+
+ "", " ", 0, { "" },
+ " ", " ", 2, { "", "" },
+ "x", " ", 1, { "x" },
+ "xy", " ", 1, { "xy" },
+ "x y", " ", 2, { "x", "y" },
+ "abc def g ", " ", 4, { "abc", "def", "g", "" },
+ " a bcd", " ", 3, { "", "a", "bcd" },
+ "a b c d e f", " ", 6, { "a", "b", "c", "d", "e f" },
+ " a b c d ", " ", 6, { "", "a", "b", "c", "d " },
+
+ "", "", 0, { "" },
+ " ", "", 0, { "" },
+ "x", "", 1, { "x" },
+ "xy", "", 1, { "xy" },
+ "x y", "", 2, { "x", "y" },
+ "abc def g ", "", 3, { "abc", "def", "g" },
+ "\t a bcd", "", 2, { "a", "bcd" },
+ " a \tb\t c ", "", 3, { "a", "b", "c" },
+ "a b c d e ", "", 5, { "a", "b", "c", "d", "e" },
+ "a b\tc d e f", "", 6, { "a", "b", "c", "d", "e f" },
+ " a b c d e f ", "", 6, { "a", "b", "c", "d", "e f " },
+
+ NULL, NULL, 0, { NULL },
+};
+
+regress()
+{
+ char buf[512];
+ register int n;
+ char *fields[RNF+1];
+ register int nf;
+ register int i;
+ register int printit;
+ register char *f;
+
+ for (n = 0; tests[n].str != NULL; n++) {
+ (void) strcpy(buf, tests[n].str);
+ fields[RNF] = NULL;
+ nf = split(buf, fields, RNF, tests[n].seps);
+ printit = 0;
+ if (nf != tests[n].nf) {
+ printf("split `%s' by `%s' gave %d fields, not %d\n",
+ tests[n].str, tests[n].seps, nf, tests[n].nf);
+ printit = 1;
+ } else if (fields[RNF] != NULL) {
+ printf("split() went beyond array end\n");
+ printit = 1;
+ } else {
+ for (i = 0; i < nf && i < RNF; i++) {
+ f = fields[i];
+ if (f == NULL)
+ f = "(NULL)";
+ if (strcmp(f, tests[n].fi[i]) != 0) {
+ printf("split `%s' by `%s', field %d is `%s', not `%s'\n",
+ tests[n].str, tests[n].seps,
+ i, fields[i], tests[n].fi[i]);
+ printit = 1;
+ }
+ }
+ }
+ if (printit)
+ print(nf, RNF, fields);
+ }
+}
+#endif
diff --git a/regex/tests b/regex/tests
new file mode 100644
index 00000000000..2886449d519
--- /dev/null
+++ b/regex/tests
@@ -0,0 +1,474 @@
+# regular expression test set
+# Lines are at least three fields, separated by one or more tabs. "" stands
+# for an empty field. First field is an RE. Second field is flags. If
+# C flag given, regcomp() is expected to fail, and the third field is the
+# error name (minus the leading REG_).
+#
+# Otherwise it is expected to succeed, and the third field is the string to
+# try matching it against. If there is no fourth field, the match is
+# expected to fail. If there is a fourth field, it is the substring that
+# the RE is expected to match. If there is a fifth field, it is a comma-
+# separated list of what the subexpressions should match, with - indicating
+# no match for that one. In both the fourth and fifth fields, a (sub)field
+# starting with @ indicates that the (sub)expression is expected to match
+# a null string followed by the stuff after the @; this provides a way to
+# test where null strings match. The character `N' in REs and strings
+# is newline, `S' is space, `T' is tab, `Z' is NUL.
+#
+# The full list of flags:
+# - placeholder, does nothing
+# b RE is a BRE, not an ERE
+# & try it as both an ERE and a BRE
+# C regcomp() error expected, third field is error name
+# i REG_ICASE
+# m ("mundane") REG_NOSPEC
+# s REG_NOSUB (not really testable)
+# n REG_NEWLINE
+# ^ REG_NOTBOL
+# $ REG_NOTEOL
+# # REG_STARTEND (see below)
+# p REG_PEND
+#
+# For REG_STARTEND, the start/end offsets are those of the substring
+# enclosed in ().
+
+# basics
+a & a a
+abc & abc abc
+abc|de - abc abc
+a|b|c - abc a
+
+# parentheses and perversions thereof
+a(b)c - abc abc
+a\(b\)c b abc abc
+a( C EPAREN
+a( b a( a(
+a\( - a( a(
+a\( bC EPAREN
+a\(b bC EPAREN
+a(b C EPAREN
+a(b b a(b a(b
+# gag me with a right parenthesis -- 1003.2 goofed here (my fault, partly)
+a) - a) a)
+) - ) )
+# end gagging (in a just world, those *should* give EPAREN)
+a) b a) a)
+a\) bC EPAREN
+\) bC EPAREN
+a()b - ab ab
+a\(\)b b ab ab
+
+# anchoring and REG_NEWLINE
+^abc$ & abc abc
+a^b - a^b
+a^b b a^b a^b
+a$b - a$b
+a$b b a$b a$b
+^ & abc @abc
+$ & abc @
+^$ & "" @
+$^ - "" @
+\($\)\(^\) b "" @
+# stop retching, those are legitimate (although disgusting)
+^^ - "" @
+$$ - "" @
+b$ & abNc
+b$ &n abNc b
+^b$ & aNbNc
+^b$ &n aNbNc b
+^$ &n aNNb @Nb
+^$ n abc
+^$ n abcN @
+$^ n aNNb @Nb
+\($\)\(^\) bn aNNb @Nb
+^^ n^ aNNb @Nb
+$$ n aNNb @NN
+^a ^ a
+a$ $ a
+^a ^n aNb
+^b ^n aNb b
+a$ $n bNa
+b$ $n bNa b
+a*(^b$)c* - b b
+a*\(^b$\)c* b b b
+
+# certain syntax errors and non-errors
+| C EMPTY
+| b | |
+* C BADRPT
+* b * *
++ C BADRPT
+? C BADRPT
+"" &C EMPTY
+() - abc @abc
+\(\) b abc @abc
+a||b C EMPTY
+|ab C EMPTY
+ab| C EMPTY
+(|a)b C EMPTY
+(a|)b C EMPTY
+(*a) C BADRPT
+(+a) C BADRPT
+(?a) C BADRPT
+({1}a) C BADRPT
+\(\{1\}a\) bC BADRPT
+(a|*b) C BADRPT
+(a|+b) C BADRPT
+(a|?b) C BADRPT
+(a|{1}b) C BADRPT
+^* C BADRPT
+^* b * *
+^+ C BADRPT
+^? C BADRPT
+^{1} C BADRPT
+^\{1\} bC BADRPT
+
+# metacharacters, backslashes
+a.c & abc abc
+a[bc]d & abd abd
+a\*c & a*c a*c
+a\\b & a\b a\b
+a\\\*b & a\*b a\*b
+a\bc & abc abc
+a\ &C EESCAPE
+a\\bc & a\bc a\bc
+\{ bC BADRPT
+a\[b & a[b a[b
+a[b &C EBRACK
+# trailing $ is a peculiar special case for the BRE code
+a$ & a a
+a$ & a$
+a\$ & a
+a\$ & a$ a$
+a\\$ & a
+a\\$ & a$
+a\\$ & a\$
+a\\$ & a\ a\
+
+# back references, ugh
+a\(b\)\2c bC ESUBREG
+a\(b\1\)c bC ESUBREG
+a\(b*\)c\1d b abbcbbd abbcbbd bb
+a\(b*\)c\1d b abbcbd
+a\(b*\)c\1d b abbcbbbd
+^\(.\)\1 b abc
+a\([bc]\)\1d b abcdabbd abbd b
+a\(\([bc]\)\2\)*d b abbccd abbccd
+a\(\([bc]\)\2\)*d b abbcbd
+# actually, this next one probably ought to fail, but the spec is unclear
+a\(\(b\)*\2\)*d b abbbd abbbd
+# here is a case that no NFA implementation does right
+\(ab*\)[ab]*\1 b ababaaa ababaaa a
+# check out normal matching in the presence of back refs
+\(a\)\1bcd b aabcd aabcd
+\(a\)\1bc*d b aabcd aabcd
+\(a\)\1bc*d b aabd aabd
+\(a\)\1bc*d b aabcccd aabcccd
+\(a\)\1bc*[ce]d b aabcccd aabcccd
+^\(a\)\1b\(c\)*cd$ b aabcccd aabcccd
+
+# ordinary repetitions
+ab*c & abc abc
+ab+c - abc abc
+ab?c - abc abc
+a\(*\)b b a*b a*b
+a\(**\)b b ab ab
+a\(***\)b bC BADRPT
+*a b *a *a
+**a b a a
+***a bC BADRPT
+
+# the dreaded bounded repetitions
+{ & { {
+{abc & {abc {abc
+{1 C BADRPT
+{1} C BADRPT
+a{b & a{b a{b
+a{1}b - ab ab
+a\{1\}b b ab ab
+a{1,}b - ab ab
+a\{1,\}b b ab ab
+a{1,2}b - aab aab
+a\{1,2\}b b aab aab
+a{1 C EBRACE
+a\{1 bC EBRACE
+a{1a C EBRACE
+a\{1a bC EBRACE
+a{1a} C BADBR
+a\{1a\} bC BADBR
+a{,2} - a{,2} a{,2}
+a\{,2\} bC BADBR
+a{,} - a{,} a{,}
+a\{,\} bC BADBR
+a{1,x} C BADBR
+a\{1,x\} bC BADBR
+a{1,x C EBRACE
+a\{1,x bC EBRACE
+a{300} C BADBR
+a\{300\} bC BADBR
+a{1,0} C BADBR
+a\{1,0\} bC BADBR
+ab{0,0}c - abcac ac
+ab\{0,0\}c b abcac ac
+ab{0,1}c - abcac abc
+ab\{0,1\}c b abcac abc
+ab{0,3}c - abbcac abbc
+ab\{0,3\}c b abbcac abbc
+ab{1,1}c - acabc abc
+ab\{1,1\}c b acabc abc
+ab{1,3}c - acabc abc
+ab\{1,3\}c b acabc abc
+ab{2,2}c - abcabbc abbc
+ab\{2,2\}c b abcabbc abbc
+ab{2,4}c - abcabbc abbc
+ab\{2,4\}c b abcabbc abbc
+((a{1,10}){1,10}){1,10} - a a a,a
+
+# multiple repetitions
+a** &C BADRPT
+a++ C BADRPT
+a?? C BADRPT
+a*+ C BADRPT
+a*? C BADRPT
+a+* C BADRPT
+a+? C BADRPT
+a?* C BADRPT
+a?+ C BADRPT
+a{1}{1} C BADRPT
+a*{1} C BADRPT
+a+{1} C BADRPT
+a?{1} C BADRPT
+a{1}* C BADRPT
+a{1}+ C BADRPT
+a{1}? C BADRPT
+a*{b} - a{b} a{b}
+a\{1\}\{1\} bC BADRPT
+a*\{1\} bC BADRPT
+a\{1\}* bC BADRPT
+
+# brackets, and numerous perversions thereof
+a[b]c & abc abc
+a[ab]c & abc abc
+a[^ab]c & adc adc
+a[]b]c & a]c a]c
+a[[b]c & a[c a[c
+a[-b]c & a-c a-c
+a[^]b]c & adc adc
+a[^-b]c & adc adc
+a[b-]c & a-c a-c
+a[b &C EBRACK
+a[] &C EBRACK
+a[1-3]c & a2c a2c
+a[3-1]c &C ERANGE
+a[1-3-5]c &C ERANGE
+a[[.-.]--]c & a-c a-c
+a[1- &C ERANGE
+a[[. &C EBRACK
+a[[.x &C EBRACK
+a[[.x. &C EBRACK
+a[[.x.] &C EBRACK
+a[[.x.]] & ax ax
+a[[.x,.]] &C ECOLLATE
+a[[.one.]]b & a1b a1b
+a[[.notdef.]]b &C ECOLLATE
+a[[.].]]b & a]b a]b
+a[[:notdef:]]c &C ECTYPE
+a[[: &C EBRACK
+a[[:alpha &C EBRACK
+a[[:alpha:] &C EBRACK
+a[[:alpha,:] &C ECTYPE
+a[[:]:]]b &C ECTYPE
+a[[:-:]]b &C ECTYPE
+a[[:alph:]] &C ECTYPE
+a[[:alphabet:]] &C ECTYPE
+[[:alnum:]]+ - -%@aÄX- aÄX
+[[:alpha:]]+ - -%@aX0- aX
+[[:blank:]]+ - aSSTb SST
+[[:cntrl:]]+ - aNTb NT
+[[:digit:]]+ - a019b 019
+[[:graph:]]+ - Sa%bS a%b
+[[:lower:]]+ - AabC ab
+[[:print:]]+ - NaSbN aSb
+[[:punct:]]+ - S%-&T %-&
+[[:space:]]+ - aSNTb SNT
+[[:upper:]]+ - aBCd BC
+[[:xdigit:]]+ - p0f3Cq 0f3C
+a[[=b=]]c & abc abc
+a[[= &C EBRACK
+a[[=b &C EBRACK
+a[[=b= &C EBRACK
+a[[=b=] &C EBRACK
+a[[=b,=]] &C ECOLLATE
+a[[=one=]]b & a1b a1b
+
+# complexities
+a(((b)))c - abc abc
+a(b|(c))d - abd abd
+a(b*|c)d - abbd abbd
+# just gotta have one DFA-buster, of course
+a[ab]{20} - aaaaabaaaabaaaabaaaab aaaaabaaaabaaaabaaaab
+# and an inline expansion in case somebody gets tricky
+a[ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab] - aaaaabaaaabaaaabaaaab aaaaabaaaabaaaabaaaab
+# and in case somebody just slips in an NFA...
+a[ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab](wee|week)(knights|night) - aaaaabaaaabaaaabaaaabweeknights aaaaabaaaabaaaabaaaabweeknights
+# fish for anomalies as the number of states passes 32
+12345678901234567890123456789 - a12345678901234567890123456789b 12345678901234567890123456789
+123456789012345678901234567890 - a123456789012345678901234567890b 123456789012345678901234567890
+1234567890123456789012345678901 - a1234567890123456789012345678901b 1234567890123456789012345678901
+12345678901234567890123456789012 - a12345678901234567890123456789012b 12345678901234567890123456789012
+123456789012345678901234567890123 - a123456789012345678901234567890123b 123456789012345678901234567890123
+# and one really big one, beyond any plausible word width
+1234567890123456789012345678901234567890123456789012345678901234567890 - a1234567890123456789012345678901234567890123456789012345678901234567890b 1234567890123456789012345678901234567890123456789012345678901234567890
+# fish for problems as brackets go past 8
+[ab][cd][ef][gh][ij][kl][mn] - xacegikmoq acegikm
+[ab][cd][ef][gh][ij][kl][mn][op] - xacegikmoq acegikmo
+[ab][cd][ef][gh][ij][kl][mn][op][qr] - xacegikmoqy acegikmoq
+[ab][cd][ef][gh][ij][kl][mn][op][q] - xacegikmoqy acegikmoq
+
+# subtleties of matching
+abc & xabcy abc
+a\(b\)?c\1d b acd
+aBc i Abc Abc
+a[Bc]*d i abBCcd abBCcd
+0[[:upper:]]1 &i 0a1 0a1
+0[[:lower:]]1 &i 0A1 0A1
+a[^b]c &i abc
+a[^b]c &i aBc
+a[^b]c &i adc adc
+[a]b[c] - abc abc
+[a]b[a] - aba aba
+[abc]b[abc] - abc abc
+[abc]b[abd] - abd abd
+a(b?c)+d - accd accd
+(wee|week)(knights|night) - weeknights weeknights
+(we|wee|week|frob)(knights|night|day) - weeknights weeknights
+a[bc]d - xyzaaabcaababdacd abd
+a[ab]c - aaabc abc
+abc s abc abc
+a* & b @b
+
+# Let's have some fun -- try to match a C comment.
+# first the obvious, which looks okay at first glance...
+/\*.*\*/ - /*x*/ /*x*/
+# but...
+/\*.*\*/ - /*x*/y/*z*/ /*x*/y/*z*/
+# okay, we must not match */ inside; try to do that...
+/\*([^*]|\*[^/])*\*/ - /*x*/ /*x*/
+/\*([^*]|\*[^/])*\*/ - /*x*/y/*z*/ /*x*/
+# but...
+/\*([^*]|\*[^/])*\*/ - /*x**/y/*z*/ /*x**/y/*z*/
+# and a still fancier version, which does it right (I think)...
+/\*([^*]|\*+[^*/])*\*+/ - /*x*/ /*x*/
+/\*([^*]|\*+[^*/])*\*+/ - /*x*/y/*z*/ /*x*/
+/\*([^*]|\*+[^*/])*\*+/ - /*x**/y/*z*/ /*x**/
+/\*([^*]|\*+[^*/])*\*+/ - /*x****/y/*z*/ /*x****/
+/\*([^*]|\*+[^*/])*\*+/ - /*x**x*/y/*z*/ /*x**x*/
+/\*([^*]|\*+[^*/])*\*+/ - /*x***x/y/*z*/ /*x***x/y/*z*/
+
+# subexpressions
+a(b)(c)d - abcd abcd b,c
+a(((b)))c - abc abc b,b,b
+a(b|(c))d - abd abd b,-
+a(b*|c|e)d - abbd abbd bb
+a(b*|c|e)d - acd acd c
+a(b*|c|e)d - ad ad @d
+a(b?)c - abc abc b
+a(b?)c - ac ac @c
+a(b+)c - abc abc b
+a(b+)c - abbbc abbbc bbb
+a(b*)c - ac ac @c
+(a|ab)(bc([de]+)f|cde) - abcdef abcdef a,bcdef,de
+# the regression tester only asks for 9 subexpressions
+a(b)(c)(d)(e)(f)(g)(h)(i)(j)k - abcdefghijk abcdefghijk b,c,d,e,f,g,h,i,j
+a(b)(c)(d)(e)(f)(g)(h)(i)(j)(k)l - abcdefghijkl abcdefghijkl b,c,d,e,f,g,h,i,j,k
+a([bc]?)c - abc abc b
+a([bc]?)c - ac ac @c
+a([bc]+)c - abc abc b
+a([bc]+)c - abcc abcc bc
+a([bc]+)bc - abcbc abcbc bc
+a(bb+|b)b - abb abb b
+a(bbb+|bb+|b)b - abb abb b
+a(bbb+|bb+|b)b - abbb abbb bb
+a(bbb+|bb+|b)bb - abbb abbb b
+(.*).* - abcdef abcdef abcdef
+(a*)* - bc @b @b
+
+# do we get the right subexpression when it is used more than once?
+a(b|c)*d - ad ad -
+a(b|c)*d - abcd abcd c
+a(b|c)+d - abd abd b
+a(b|c)+d - abcd abcd c
+a(b|c?)+d - ad ad @d
+a(b|c?)+d - abcd abcd @d
+a(b|c){0,0}d - ad ad -
+a(b|c){0,1}d - ad ad -
+a(b|c){0,1}d - abd abd b
+a(b|c){0,2}d - ad ad -
+a(b|c){0,2}d - abcd abcd c
+a(b|c){0,}d - ad ad -
+a(b|c){0,}d - abcd abcd c
+a(b|c){1,1}d - abd abd b
+a(b|c){1,1}d - acd acd c
+a(b|c){1,2}d - abd abd b
+a(b|c){1,2}d - abcd abcd c
+a(b|c){1,}d - abd abd b
+a(b|c){1,}d - abcd abcd c
+a(b|c){2,2}d - acbd acbd b
+a(b|c){2,2}d - abcd abcd c
+a(b|c){2,4}d - abcd abcd c
+a(b|c){2,4}d - abcbd abcbd b
+a(b|c){2,4}d - abcbcd abcbcd c
+a(b|c){2,}d - abcd abcd c
+a(b|c){2,}d - abcbd abcbd b
+a(b+|((c)*))+d - abd abd @d,@d,-
+a(b+|((c)*))+d - abcd abcd @d,@d,-
+
+# check out the STARTEND option
+[abc] &# a(b)c b
+[abc] &# a(d)c
+[abc] &# a(bc)d b
+[abc] &# a(dc)d c
+. &# a()c
+b.*c &# b(bc)c bc
+b.* &# b(bc)c bc
+.*c &# b(bc)c bc
+
+# plain strings, with the NOSPEC flag
+abc m abc abc
+abc m xabcy abc
+abc m xyz
+a*b m aba*b a*b
+a*b m ab
+"" mC EMPTY
+
+# cases involving NULs
+aZb & a a
+aZb &p a
+aZb &p# (aZb) aZb
+aZ*b &p# (ab) ab
+a.b &# (aZb) aZb
+a.* &# (aZb)c aZb
+
+# word boundaries (ick)
+[[:<:]]a & a a
+[[:<:]]a & ba
+[[:<:]]a & -a a
+a[[:>:]] & a a
+a[[:>:]] & ab
+a[[:>:]] & a- a
+[[:<:]]a.c[[:>:]] & axcd-dayc-dazce-abc abc
+[[:<:]]a.c[[:>:]] & axcd-dayc-dazce-abc-q abc
+[[:<:]]a.c[[:>:]] & axc-dayc-dazce-abc axc
+[[:<:]]b.c[[:>:]] & a_bxc-byc_d-bzc-q bzc
+[[:<:]].x..[[:>:]] & y_xa_-_xb_y-_xc_-axdc _xc_
+[[:<:]]a_b[[:>:]] & x_a_b
+
+# past problems, and suspected problems
+(A[1])|(A[2])|(A[3])|(A[4])|(A[5])|(A[6])|(A[7])|(A[8])|(A[9])|(A[A]) - A1 A1
+abcdefghijklmnop i abcdefghijklmnop abcdefghijklmnop
+abcdefghijklmnopqrstuv i abcdefghijklmnopqrstuv abcdefghijklmnopqrstuv
+(ALAK)|(ALT[AB])|(CC[123]1)|(CM[123]1)|(GAMC)|(LC[23][EO ])|(SEM[1234])|(SL[ES][12])|(SLWW)|(SLF )|(SLDT)|(VWH[12])|(WH[34][EW])|(WP1[ESN]) - CC11 CC11
+CC[13]1|a{21}[23][EO][123][Es][12]a{15}aa[34][EW]aaaaaaa[X]a - CC11 CC11
+Char \([a-z0-9_]*\)\[.* b Char xyz[k Char xyz[k xyz
+a?b - ab ab
+-\{0,1\}[0-9]*$ b -5 -5
diff --git a/regex/utils.h b/regex/utils.h
new file mode 100644
index 00000000000..8f85b705bb5
--- /dev/null
+++ b/regex/utils.h
@@ -0,0 +1,22 @@
+/* utility definitions */
+#ifdef _POSIX2_RE_DUP_MAX
+#define DUPMAX _POSIX2_RE_DUP_MAX /* xxx is this right? */
+#else
+#define DUPMAX 255
+#endif
+#define RE_INFINITY (DUPMAX + 1)
+#define NC (CHAR_MAX - CHAR_MIN + 1)
+typedef unsigned char uch;
+
+/* switch off assertions (if not already off) if no REDEBUG */
+#ifndef REDEBUG
+#ifndef NDEBUG
+#define NDEBUG /* no assertions please */
+#endif
+#endif
+#include <assert.h>
+
+/* for old systems with bcopy() but no memmove() */
+#ifdef USEBCOPY
+#define memmove(d, s, c) bcopy(s, d, c)
+#endif
diff --git a/repl-tests/include/master-slave.inc b/repl-tests/include/master-slave.inc
new file mode 100644
index 00000000000..ad2dea1f520
--- /dev/null
+++ b/repl-tests/include/master-slave.inc
@@ -0,0 +1,2 @@
+connect (slave,localhost,root,,test,0,/var/lib/mysql/mysql.sock);
+connect (master,sarochka,admin,,test,0,0);
diff --git a/repl-tests/test-dump/run.test b/repl-tests/test-dump/run.test
new file mode 100644
index 00000000000..612db3fc6cf
--- /dev/null
+++ b/repl-tests/test-dump/run.test
@@ -0,0 +1,17 @@
+source ../include/master-slave.inc;
+connection master;
+use test;
+drop table if exists words;
+create table words (word char(20) not null, index(word));
+load data infile '/usr/dict/words' into table words;
+drop table if exists words1;
+create table words1 (word char(20) not null);
+load data infile '/usr/dict/words' into table words1;
+connection slave;
+use test;
+drop table if exists words;
+load table words from master;
+drop table if exists words1;
+load table words1 from master;
+@table-dump-check.master check table words;
+@table-dump-select.master select count(*) from words1;
diff --git a/repl-tests/test-dump/table-dump-check.master b/repl-tests/test-dump/table-dump-check.master
new file mode 100644
index 00000000000..4061fdb4a0d
--- /dev/null
+++ b/repl-tests/test-dump/table-dump-check.master
@@ -0,0 +1,2 @@
+Table Op Msg_type Msg_text
+test.words check status OK
diff --git a/repl-tests/test-dump/table-dump-select.master b/repl-tests/test-dump/table-dump-select.master
new file mode 100644
index 00000000000..ae93d31c066
--- /dev/null
+++ b/repl-tests/test-dump/table-dump-select.master
@@ -0,0 +1,2 @@
+count(*)
+45402
diff --git a/repl-tests/test-repl-ts/repl-timestamp.master b/repl-tests/test-repl-ts/repl-timestamp.master
new file mode 100644
index 00000000000..c3e4a2326d0
--- /dev/null
+++ b/repl-tests/test-repl-ts/repl-timestamp.master
@@ -0,0 +1,2 @@
+unix_timestamp(t)
+200006
diff --git a/repl-tests/test-repl-ts/run.test b/repl-tests/test-repl-ts/run.test
new file mode 100644
index 00000000000..8e5abbd4a3e
--- /dev/null
+++ b/repl-tests/test-repl-ts/run.test
@@ -0,0 +1,17 @@
+#! ../client/mysql-test
+# tests if the replicaion preserves timestamp properly
+
+source ../include/master-slave.inc;
+connection master;
+set timestamp=200006;
+drop table if exists foo;
+create table foo(t timestamp not null,a char(1));
+insert into foo ( a) values ('F');
+@repl-timestamp.master select unix_timestamp(t) from foo;
+sleep 3;
+connection slave;
+drop table if exists foo;
+load table foo from master;
+@repl-timestamp.master select unix_timestamp(t) from foo;
+
+
diff --git a/repl-tests/test-repl/foo-dump-master.master b/repl-tests/test-repl/foo-dump-master.master
new file mode 100644
index 00000000000..982e0523cfb
--- /dev/null
+++ b/repl-tests/test-repl/foo-dump-master.master
@@ -0,0 +1,3 @@
+n
+1
+2
diff --git a/repl-tests/test-repl/foo-dump-slave.master b/repl-tests/test-repl/foo-dump-slave.master
new file mode 100644
index 00000000000..982e0523cfb
--- /dev/null
+++ b/repl-tests/test-repl/foo-dump-slave.master
@@ -0,0 +1,3 @@
+n
+1
+2
diff --git a/repl-tests/test-repl/run.test b/repl-tests/test-repl/run.test
new file mode 100755
index 00000000000..79eb2281b85
--- /dev/null
+++ b/repl-tests/test-repl/run.test
@@ -0,0 +1,24 @@
+source ../include/master-slave.inc;
+connection slave;
+!slave stop;
+connection master;
+flush master;
+connection slave;
+flush slave;
+!slave start;
+sleep 3;
+connection master;
+use test;
+drop table if exists words;
+create table words (word char(20) not null, index(word));
+load data infile '/usr/dict/words' into table words;
+drop table if exists foo;
+create table foo(n int);
+insert into foo values(1),(2);
+@foo-dump-master.master select * from foo;
+@sum-wlen-master.master select sum(length(word)) from words;
+connection slave;
+sleep 5;
+use test;
+@sum-wlen-slave.master select sum(length(word)) from words;
+@foo-dump-slave.master select * from foo;
diff --git a/repl-tests/test-repl/sum-wlen-master.master b/repl-tests/test-repl/sum-wlen-master.master
new file mode 100644
index 00000000000..e749ab4840a
--- /dev/null
+++ b/repl-tests/test-repl/sum-wlen-master.master
@@ -0,0 +1,2 @@
+sum(length(word))
+363634
diff --git a/repl-tests/test-repl/sum-wlen-slave.master b/repl-tests/test-repl/sum-wlen-slave.master
new file mode 100644
index 00000000000..e749ab4840a
--- /dev/null
+++ b/repl-tests/test-repl/sum-wlen-slave.master
@@ -0,0 +1,2 @@
+sum(length(word))
+363634
diff --git a/scripts/.cvsignore b/scripts/.cvsignore
new file mode 100644
index 00000000000..b8444752a0d
--- /dev/null
+++ b/scripts/.cvsignore
@@ -0,0 +1,15 @@
+Makefile
+Makefile.in
+make_binary_distribution
+msql2mysql
+mysql_config
+mysql_convert_table_format
+mysql_find_rows
+mysql_fix_privilege_tables
+mysql_install_db
+mysql_setpermission
+mysql_zap
+mysqlaccess
+mysqlbug
+mysqlhotcopy
+safe_mysqld
diff --git a/scripts/Makefile.am b/scripts/Makefile.am
new file mode 100644
index 00000000000..e2e37996c90
--- /dev/null
+++ b/scripts/Makefile.am
@@ -0,0 +1,104 @@
+# Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; 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
+
+bin_SCRIPTS = @server_scripts@ \
+ msql2mysql \
+ mysql_config \
+ mysql_fix_privilege_tables \
+ mysql_setpermission \
+ mysql_zap \
+ mysqlaccess \
+ mysqlbug \
+ mysql_convert_table_format \
+ mysql_find_rows \
+ mysqlhotcopy
+
+EXTRA_SCRIPTS = make_binary_distribution.sh \
+ msql2mysql.sh \
+ mysql_config.sh \
+ mysql_fix_privilege_tables.sh \
+ mysql_install_db.sh \
+ mysql_setpermission.sh \
+ mysql_zap.sh \
+ mysqlaccess.sh \
+ mysqlbug.sh \
+ mysql_convert_table_format.sh \
+ mysql_find_rows.sh \
+ mysqlhotcopy.sh \
+ safe_mysqld.sh
+
+EXTRA_DIST = $(EXTRA_SCRIPTS) \
+ mysqlaccess.conf \
+ mysqlbug
+
+pkgdata_DATA = make_binary_distribution
+
+# mysqlbug should be distributed built so that people can report build
+# failures with it.
+CLEANFILES = @server_scripts@ \
+ make_binary_distribution \
+ msql2mysql \
+ mysql_fix_privilege_tables \
+ mysql_setpermission \
+ mysql_zap \
+ mysqlaccess \
+ mysql_convert_table_format \
+ mysql_find_rows
+
+SUPERCLEANFILES = mysqlbug
+
+# We want the right version and configure comand line in mysqlbug
+mysqlbug: ${top_builddir}/config.status ${top_builddir}/config.cache mysqlbug.sh
+
+SUFFIXES = .sh
+
+.sh:
+ @RM@ -f $@ $@-t
+ @SED@ \
+ -e 's!@''bindir''@!$(bindir)!g' \
+ -e 's!@''scriptdir''@!$(bindir)!g' \
+ -e 's!@''prefix''@!$(prefix)!g' \
+ -e 's!@''datadir''@!$(datadir)!g' \
+ -e 's!@''localstatedir''@!$(localstatedir)!g' \
+ -e 's!@''libexecdir''@!$(libexecdir)!g' \
+ -e 's!@''pkglibdir''@!$(pkglibdir)!g' \
+ -e 's!@''pkgincludedir''@!$(pkgincludedir)!g' \
+ -e 's!@''CC''@!@CC@!'\
+ -e 's!@''CXX''@!@CXX@!'\
+ -e 's!@''GXX''@!@GXX@!'\
+ -e 's!@''PERL''@!@PERL@!' \
+ -e 's!@''CFLAGS''@!@SAVE_CFLAGS@!'\
+ -e 's!@''CXXFLAGS''@!@SAVE_CXXFLAGS@!'\
+ -e 's!@''LDFLAGS''@!@SAVE_LDFLAGS@!'\
+ -e 's!@''CLIENT_LIBS''@!@CLIENT_LIBS@!' \
+ -e 's!@''VERSION''@!@VERSION@!' \
+ -e 's!@''COMPILATION_COMMENT''@!@COMPILATION_COMMENT@!' \
+ -e 's!@''MACHINE_TYPE''@!@MACHINE_TYPE@!' \
+ -e 's!@''HOSTNAME''@!@HOSTNAME@!' \
+ -e 's!@''SYSTEM_TYPE''@!@SYSTEM_TYPE@!' \
+ -e 's!@''CHECK_PID''@!@CHECK_PID@!' \
+ -e 's!@''FIND_PROC''@!@FIND_PROC@!' \
+ -e 's!@''MYSQLD_DEFAULT_SWITCHES''@!@MYSQLD_DEFAULT_SWITCHES@!' \
+ -e 's!@''MYSQL_UNIX_ADDR''@!@MYSQL_UNIX_ADDR@!' \
+ -e 's!@''MYSQL_TCP_PORT''@!@MYSQL_TCP_PORT@!' \
+ -e 's!@''IS_LINUX''@!@IS_LINUX@!' \
+ -e "s!@""CONF_COMMAND""@!@CONF_COMMAND@!" \
+ -e 's!@''MYSQLD_USER''@!@MYSQLD_USER@!' \
+ $< > $@-t
+ @CHMOD@ +x $@-t
+ @MV@ $@-t $@
diff --git a/scripts/make_binary_distribution.sh b/scripts/make_binary_distribution.sh
new file mode 100755
index 00000000000..65d259a5307
--- /dev/null
+++ b/scripts/make_binary_distribution.sh
@@ -0,0 +1,131 @@
+#!/bin/sh
+# The default path should be /usr/local
+
+# Get some info from configure
+# chmod +x ./scripts/setsomevars
+
+machine=@MACHINE_TYPE@
+system=@SYSTEM_TYPE@
+version=@VERSION@
+export machine system version
+SOURCE=`pwd`
+
+# Save temporary distribution here (must be full path)
+TMP=/tmp
+if test $# -gt 0
+then
+ TMP=$1
+fi
+
+#make
+
+# This should really be integrated with automake and not duplicate the
+# installation list.
+
+BASE=$TMP/my_dist
+mkdir $BASE $BASE/bin $BASE/data $BASE/data/mysql $BASE/data/test \
+ $BASE/include $BASE/lib $BASE/support-files $BASE/share $BASE/share/mysql \
+ $BASE/tests $BASE/scripts $BASE/sql-bench
+
+chmod o-rwx $BASE/data $BASE/data/*
+
+for i in sql/ChangeLog COPYING COPYING.LIB README Docs/INSTALL-BINARY \
+ Docs/manual.html Docs/manual.txt Docs/manual_toc.html
+do
+ cp -p $i $BASE
+done
+
+for i in extra/comp_err extra/replace extra/perror extra/resolveip \
+ extra/my_print_defaults isam/isamchk isam/pack_isam myisam/myisamchk myisam/myisampack sql/mysqld sql/mysqlbinlog \
+ client/mysql sql/mysqld client/mysqlshow client/mysqladmin client/mysqldump client/mysqlimport client/mysql-test \
+ client/.libs/mysql client/.libs/mysqlshow client/.libs/mysqladmin client/.libs/mysqldump client/.libs/mysqlimport client/.libs/mysql-test
+do
+ cp -p $i $BASE/bin
+done
+
+cp -p config.h include/* $BASE/include
+rm $BASE/include/Makefile*; rm $BASE/include/*.in
+
+cp -p tests/*.res tests/*.tst tests/*.pl $BASE/tests
+cp -p support-files/* $BASE/support-files
+cp -p libmysql/.libs/libmysqlclient.a libmysql/.libs/libmysqlclient.so* libmysql/libmysqlclient.* mysys/libmysys.a strings/libmystrings.a dbug/libdbug.a $BASE/lib
+cp -r -p sql/share/* $BASE/share/mysql; rm -f $BASE/share/mysql/Makefile* $BASE/share/mysql/*/*.OLD $BASE/share/CVS $BASE/share/*/CVS
+
+cp -p scripts/* $BASE/bin
+rm -f $BASE/bin/Makefile* $BASE/bin/*.in $BASE/bin/*.sh $BASE/bin/mysql_install_db $BASE/bin/make_binary_distribution $BASE/bin/setsomevars $BASE/support-files/Makefile* $BASE/support-files/*.sh
+
+$BASE/bin/replace \@localstatedir\@ ./data \@bindir\@ ./bin \@scriptdir\@ ./bin \@libexecdir\@ ./bin \@prefix\@ . < $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
+
+mv $BASE/support-files/binary-configure $BASE/configure
+chmod a+x $BASE/bin/* $BASE/scripts/* $BASE/support-files/mysql-* $BASE/configure
+cp -r -p sql-bench/* $BASE/sql-bench
+rm -f $BASE/sql-bench/*.sh $BASE/sql-bench/Makefile* $BASE/lib/*.la
+
+# Change the distribution to a long descreptive name
+NEW_NAME=mysql-$version-$system-$machine
+BASE2=$TMP/$NEW_NAME
+rm -rf $BASE2
+mv $BASE $BASE2
+BASE=$BASE2
+#
+# If we are compiling with gcc, copy libgcc.a to the distribution as libmygcc.a
+#
+
+if test "@GXX@" = "yes"
+then
+ cd $BASE/lib
+ gcclib=`@CC@ --print-libgcc-file`
+ if test $? -ne 0
+ then
+ print "Warning: Couldn't find libgcc.a!"
+ else
+ cp -p $gcclib libmygcc.a
+ fi
+ cd $SOURCE
+fi
+
+# This is needed to prefere gnu tar instead of tar because tar can't
+# always handle long filenames
+
+PATH_DIRS=`echo $PATH | sed -e 's/^:/. /' -e 's/:$/ ./' -e 's/::/ . /g' -e 's/:/ /g' `
+which_1 ()
+{
+ for cmd
+ do
+ for d in $PATH_DIRS
+ do
+ for file in $d/$cmd
+ do
+ if test -x $file -a ! -d $file
+ then
+ echo $file
+ exit 0
+ fi
+ done
+ done
+ done
+ exit 1
+}
+
+#
+# Create the result tar file
+#
+
+tar=`which_1 gtar`
+if test "$?" = "1" -o "$tar" = ""
+then
+ tar=tar
+fi
+
+echo "Using $tar to create archive"
+cd $TMP
+$tar cvf $SOURCE/$NEW_NAME.tar $NEW_NAME
+cd $SOURCE
+echo "Compressing archive"
+gzip -9 $NEW_NAME.tar
+echo "Removing temporary directory"
+rm -rf $BASE
+
+echo "$NEW_NAME.tar.gz created"
diff --git a/scripts/msql2mysql.sh b/scripts/msql2mysql.sh
new file mode 100644
index 00000000000..89a1fcea959
--- /dev/null
+++ b/scripts/msql2mysql.sh
@@ -0,0 +1,16 @@
+#!/bin/sh
+# Copyright (C) 1979-1996 TcX AB & Monty Program KB & Detron HB
+#
+# This software is distributed with NO WARRANTY OF ANY KIND. No author or
+# distributor accepts any responsibility for the consequences of using it, or
+# for whether it serves any particular purpose or works at all, unless he or
+# she says so in writing. Refer to the Free Public License (the "License")
+# for full details.
+#
+# Every copy of this file must include a copy of the License, normally in a
+# plain ASCII text file named PUBLIC. The License grants you the right to
+# copy, modify and redistribute this file, but only under certain conditions
+# described in the License. Among other things, the License requires that
+# the copyright notice and this notice be preserved on all copies.
+
+@bindir@/replace msqlConnect mysql_connect msqlListDBs mysql_list_dbs msqlNumRows mysql_num_rows msqlFetchRow mysql_fetch_row msqlFetchField mysql_fetch_field msqlFreeResult mysql_free_result msqlListFields mysql_list_fields msqlListTables mysql_list_tables msqlErrMsg 'mysql_error(mysql)' msqlStoreResult mysql_store_result msqlQuery mysql_query msqlField mysql_field msqlSelect mysql_select msqlSelectDB mysql_select_db msqlNumFields mysql_num_fields msqlClose mysql_close msqlDataSeek mysql_data_seek m_field MYSQL_FIELD m_result MYSQL_RES m_row MYSQL_ROW msql mysql mSQL mySQL MSQL MYSQL msqlCreateDB mysql_create_db msqlDropDB mysql_drop_db msqlFieldSeek mysql_field_seek -- $*
diff --git a/scripts/mysql_config.sh b/scripts/mysql_config.sh
new file mode 100644
index 00000000000..09f81c70a1f
--- /dev/null
+++ b/scripts/mysql_config.sh
@@ -0,0 +1,74 @@
+#!/bin/sh
+# Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public 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 script reports various configuration settings that may be needed
+# when using the MySQL client library.
+
+ldata='@localstatedir@'
+execdir='@libexecdir@'
+bindir='@bindir@'
+pkglibdir='@pkglibdir@'
+pkgincludedir='@pkgincludedir@'
+version='@VERSION@'
+socket='@MYSQL_UNIX_ADDR@'
+port='@MYSQL_TCP_PORT@'
+ldflags='@LDFLAGS@'
+client_libs='@CLIENT_LIBS@'
+
+libs="$ldflags -L'$pkglibdir' -lmysqlclient $client_libs"
+cflags="-I'$pkgincludedir'"
+
+usage () {
+ cat <<EOF
+Usage: $0 [OPTIONS]
+Options:
+ --cflags [$cflags]
+ --libs [$libs]
+ --socket [$socket]
+ --port [$port]
+ --version [$version]
+EOF
+ exit 1
+}
+
+if ! test $# -gt 0; then usage; fi
+
+while test $# -gt 0; do
+ case $1 in
+ --cflags) echo "$cflags" ;;
+ --libs) echo "$libs" ;;
+ --socket) echo "$socket" ;;
+ --port) echo "$port" ;;
+ --version) echo "$version" ;;
+ *) usage ;;
+ esac
+
+ shift
+done
+
+#echo "ldata: '"$ldata"'"
+#echo "execdir: '"$execdir"'"
+#echo "bindir: '"$bindir"'"
+#echo "pkglibdir: '"$pkglibdir"'"
+#echo "pkgincludedir: '"$pkgincludedir"'"
+#echo "version: '"$version"'"
+#echo "socket: '"$socket"'"
+#echo "port: '"$port"'"
+#echo "ldflags: '"$ldflags"'"
+#echo "client_libs: '"$client_libs"'"
+
+exit 0
diff --git a/scripts/mysql_convert_table_format.sh b/scripts/mysql_convert_table_format.sh
new file mode 100755
index 00000000000..69eede94786
--- /dev/null
+++ b/scripts/mysql_convert_table_format.sh
@@ -0,0 +1,114 @@
+#!@PERL@
+
+# Convert given tables in a database to MYISAM
+
+use DBI;
+use Getopt::Long;
+
+$opt_help=$opt_version=$opt_verbose=$opt_force=0;
+$opt_user=$opt_database=$opt_password=undef;
+$opt_host="localhost";
+$opt_type="MYISAM";
+$exit_status=0;
+
+GetOptions("force","help","host=s","password=s","user=s","type=s","verbose","version") ||
+ usage(0);
+usage($opt_version) if ($#ARGV < 0 || $opt_help || $opt_version);
+$opt_database=shift(@ARGV);
+
+if (uc($opt_type) eq "HEAP")
+{
+ print "Converting to type HEAP would delete your tables; aborting\n";
+ exit(1);
+}
+
+$dbh = DBI->connect("DBI:mysql:$opt_database:$opt_host",
+ $opt_user,
+ $opt_password,
+ { PrintError => 0})
+ || die "Can't connect to database $opt_database: $DBI::errstr\n";
+
+if ($#ARGV < 0)
+{
+ # Fetch all table names from the database
+ my ($sth,$row);
+ $sth=$dbh->prepare("show tables");
+ $sth->execute || die "Can't get tables from $opt_database; $DBI::errstr\n";
+ while (($row = $sth->fetchrow_arrayref))
+ {
+ push(@ARGV,$row->[0]);
+ }
+ $sth->finish;
+}
+
+print "Converting tables:\n" if ($opt_verbose);
+foreach $table (@ARGV)
+{
+ my ($sth,$row);
+
+ # Check if table is already converted
+ $sth=$dbh->prepare("show table status like '$table'");
+ if ($sth->execute && ($row = $sth->fetchrow_arrayref))
+ {
+ if (uc($row->[1]) eq uc($opt_type))
+ {
+ print "$table is alread of type $opt_type; Ignored\n";
+ next;
+ }
+ }
+ print "converting $table\n" if ($opt_verbose);
+ if (!$dbh->do("ALTER TABLE $table type=$opt_type"))
+ {
+ print STDERR "Can't convert $table: Error $DBI::errstr\n";
+ exit(1) if (!$opt_force);
+ $exit_status=1;
+ }
+}
+
+$dbh->disconnect;
+exit($exit_status);
+
+
+sub usage
+{
+ my($version)=shift;
+ print "$0 version 1.1\n";
+ exit(0) if ($version);
+
+ print <<EOF;
+
+Conversion of a MySQL tables to other table types.
+
+ Usage: $0 database [tables]
+ If no tables has been specifed, all tables in the database will be converted.
+
+ The following options are available:
+
+--force
+ Continue even if there is some error.
+
+--help or --Information
+ Shows this help
+
+--host='host name' (Default $opt_host)
+ Host name where the database server is located.
+
+--password='password'
+ Password for the current user.
+
+--type='table-type'
+ Converts tables to the given table type (Default: $opt_type)
+ MySQL 3.23 supports at least the BDB, ISAM and MYISAM types.
+
+--user='user_name'
+ User name to log into the SQL server.
+
+--verbose
+ This is a test specific option that is only used when debugging a test.
+ Print more information about what is going on.
+
+--version
+ Shows the version of this program.
+EOF
+ exit(1);
+}
diff --git a/scripts/mysql_find_rows.sh b/scripts/mysql_find_rows.sh
new file mode 100755
index 00000000000..3d7bad3323e
--- /dev/null
+++ b/scripts/mysql_find_rows.sh
@@ -0,0 +1,148 @@
+#!@PERL@
+
+$version="1.02";
+
+use Getopt::Long;
+
+$opt_help=$opt_Information=$opt_skip_use_db=0;
+$opt_regexp=$opt_dbregexp=".*";
+$opt_start_row=1; $opt_rows=9999999999;
+
+GetOptions("Information","help","regexp=s","start_row=i","rows=i",
+ "dbregexp=s", "skip-use-db")
+ || usage();
+usage() if ($opt_help || $opt_Information);
+
+$query=$search=$database=$set=""; $eoq=0;
+while (<>)
+{
+ next if (length($query) == 0 && /^\#/); # Skipp comments
+ $query.=search($_);
+ if ($eoq)
+ {
+ if ($query =~ /^use /i || $query =~ /^SET / ||
+ ($query =~ /$opt_regexp/o && $database =~ /$opt_dbregexp/o))
+ {
+ if ($opt_skip_use_db && $query =~ /^use /i)
+ {
+ $query="";
+ next;
+ }
+ if ($opt_start_row <= 1)
+ {
+ if ($database)
+ {
+ print $database, $set;
+ $database=$set="";
+ }
+ print $query;
+ last if (--$opt_rows == 0);
+ }
+ else
+ {
+ $opt_start_row--;
+ if ($query =~ /^use /)
+ {
+ $database=$query;
+ $set="";
+ }
+ elsif ($query =~ /^SET/)
+ {
+ $set=$query;
+ }
+ else
+ {
+ $set="";
+ }
+ }
+ }
+ $query=""; $search=""; $eoq=0;
+ }
+}
+
+exit 0;
+
+sub search
+{
+ my($row)=shift;
+ my($i);
+
+ for ($i=0 ; $i < length($row) ; $i++)
+ {
+ if (length($search))
+ {
+ if (length($search) > 1)
+ { # Comment
+ next if (substr($row,$i,length($search)) ne $search);
+ $i+=length($search)-1;
+ $search="";
+ }
+ elsif (substr($row,$i,1) eq '\\') # Escaped char in string
+ {
+ $i++;
+ }
+ elsif (substr($row,$i,1) eq $search)
+ {
+ if (substr($row,$i+1,1) eq $search) # Double " or '
+ {
+ $i++;
+ }
+ else
+ {
+ $search="";
+ }
+ }
+ next;
+ }
+ if (substr($row,$i,2) eq '/*') # Comment
+ {
+ $search="*/";
+ $i++;
+ }
+ elsif (substr($row,$i,1) eq "'" || substr($row,$i,1) eq '"')
+ {
+ $search=substr($row,$i,1);
+ }
+ }
+ $eoq=1 if (!length($search) && $row =~ /;\s*$/);
+ return $row;
+}
+
+
+sub usage
+{
+ print <<EOF;
+$0 Ver $version
+
+TCX Datakonsult AB, by Monty.
+This software comes with NO WARRANTY: see the file PUBLIC for details.
+
+Prints all SQL queries that matches a regexp or contains a 'use
+database' or 'set ..' command to stdout. A SQL query may contain
+newlines. This is useful to find things in a MySQL update log.
+
+$0 takes the following options:
+
+--help or --Information
+ Shows this help
+
+--regexp=#
+ Print queries that matches this.
+
+--start_row=#
+ Start output from this row (first row = 1)
+
+--skip-use-db
+ Don\'t include \'use database\' commands in the output.
+
+--rows=#
+ Quit after this many rows.
+
+Example:
+
+$0 --regexp "problem_table" < update.log
+
+$0 --regexp "problem_table" update-log.1 update-log.2
+EOF
+ exit(0);
+}
diff --git a/scripts/mysql_fix_privilege_tables.sh b/scripts/mysql_fix_privilege_tables.sh
new file mode 100644
index 00000000000..8e9ef509d66
--- /dev/null
+++ b/scripts/mysql_fix_privilege_tables.sh
@@ -0,0 +1,110 @@
+#!/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 or"
+echo "want to use the more secure passwords."
+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' or"
+echo "'Table 'func' already exists'. You can safely ignore these!"
+
+@bindir@/mysql -f --user=root --password="$root_password" --host="$host" mysql <<END_OF_DATA
+alter table user change password password char(16) NOT NULL;
+alter table user add File_priv enum('N','Y') NOT NULL;
+CREATE TABLE func (
+ name char(64) DEFAULT '' NOT NULL,
+ ret tinyint(1) DEFAULT '0' NOT NULL,
+ dl char(128) DEFAULT '' NOT NULL,
+ type enum ('function','aggregate') NOT NULL,
+ PRIMARY KEY (name)
+);
+END_OF_DATA
+echo ""
+
+# Add the new grant colums
+
+echo "Creating Grant Alter and Index privileges if they don't exists"
+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 Grant_priv enum('N','Y') NOT NULL,add References_priv enum('N','Y') NOT NULL,add Index_priv enum('N','Y') NOT NULL,add Alter_priv enum('N','Y') NOT NULL;
+alter table host add Grant_priv enum('N','Y') NOT NULL,add References_priv enum('N','Y') NOT NULL,add Index_priv enum('N','Y') NOT NULL,add Alter_priv enum('N','Y') NOT NULL;
+alter table db add Grant_priv enum('N','Y') NOT NULL,add References_priv enum('N','Y') NOT NULL,add Index_priv enum('N','Y') NOT NULL,add Alter_priv enum('N','Y') NOT NULL;
+END_OF_DATA
+res=$?
+echo ""
+
+# If the new grant columns didn't exists, copy File -> Grant
+# and Create -> Alter, Index, References
+
+if test $res = 0
+then
+ echo "Setting default privileges for the new grant, index and alter privileges"
+ @bindir@/mysql --user=root --password="$root_password" --host="$host" mysql <<END_OF_DATA
+ UPDATE user SET Grant_priv=File_priv,References_priv=Create_priv,Index_priv=Create_priv,Alter_priv=Create_priv;
+ UPDATE db SET References_priv=Create_priv,Index_priv=Create_priv,Alter_priv=Create_priv;
+ UPDATE host SET References_priv=Create_priv,Index_priv=Create_priv,Alter_priv=Create_priv;
+END_OF_DATA
+ echo ""
+fi
+
+#
+# Create tables_priv and columns_priv if they don't exists
+#
+
+echo "Creating the new table and column privilege tables"
+
+@bindir@/mysql -f --user=root --password="$root_password" --host="$host" mysql <<END_OF_DATA
+CREATE TABLE tables_priv (
+ Host char(60) DEFAULT '' NOT NULL,
+ Db char(60) DEFAULT '' NOT NULL,
+ User char(16) DEFAULT '' NOT NULL,
+ Table_name char(60) DEFAULT '' NOT NULL,
+ Grantor char(77) DEFAULT '' NOT NULL,
+ Timestamp timestamp(14),
+ Table_priv set('Select','Insert','Update','Delete','Create','Drop','Grant','References','Index','Alter') DEFAULT '' NOT NULL,
+ Column_priv set('Select','Insert','Update','References') DEFAULT '' NOT NULL,
+ PRIMARY KEY (Host,Db,User,Table_name)
+);
+CREATE TABLE columns_priv (
+ Host char(60) DEFAULT '' NOT NULL,
+ Db char(60) DEFAULT '' NOT NULL,
+ User char(16) DEFAULT '' NOT NULL,
+ Table_name char(60) DEFAULT '' NOT NULL,
+ Column_name char(59) DEFAULT '' NOT NULL,
+ Timestamp timestamp(14),
+ Column_priv set('Select','Insert','Update','References') DEFAULT '' NOT NULL,
+ PRIMARY KEY (Host,Db,User,Table_name,Column_name)
+);
+END_OF_DATA
+
+#
+# Name change of Type -> Column_priv from MySQL 3.22.12
+#
+
+echo "Changing name of columns_priv.Type -> columns_priv.Column_priv"
+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
+
+#
+# Add the new 'type' column to the func table.
+#
+
+echo "Fixing the func table"
+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
diff --git a/scripts/mysql_install_db.sh b/scripts/mysql_install_db.sh
new file mode 100644
index 00000000000..9cd4af94042
--- /dev/null
+++ b/scripts/mysql_install_db.sh
@@ -0,0 +1,342 @@
+#!/bin/sh
+# Copyright (C) 1997, 1998, 1999 TCX DataKonsult AB & Monty Program KB & Detron HB
+# For a more info consult the file COPYRIGHT distributed with this file
+
+# This scripts creates the privilege tables db, host, user, tables_priv,
+# columns_priv in the mysql database, as well as the func table.
+#
+# All arguments (exept -IN-RPM as a first argument) to this script are
+# passed to mysqld
+
+ldata=@localstatedir@
+execdir=@libexecdir@
+bindir=@bindir@
+force=0
+IN_RPM=0
+defaults=
+
+# Are we doing an rpm install?
+if test "$1" = "-IN-RPM"; then IN_RPM=1; shift; fi
+if test "$1" = "--force"; then force=1; shift; fi
+
+# Get mysqld/safe_mysqld options from /etc/my.cnf or ~/.my.cnf
+case "$1" in
+ --no-defaults) defaults="$1"; conf=/nonexistent; shift ;;
+ --defaults-file=*) defaults="$1"; conf=`echo "$1"|sed 's;^--defaults-file=;;'`; shift ;;
+ *)
+ if test -w /
+ then
+ conf=/etc/my.cnf
+ else
+ conf=$HOME/.my.cnf
+ fi
+ ;;
+esac
+
+if test -f "$conf"
+then
+ if grep "^datadir" $conf >/dev/null
+ then
+ ldata=`grep "^datadir" $conf | sed 's;^[^=]*=[ \t]*;;' | sed 's;[ \t]$;;'`
+ fi
+ if grep "^execdir" $conf >/dev/null
+ then
+ execdir=`grep "^execdir" $conf | sed 's;^[^=]*=[ \t]*;;' | sed 's;[ \t]$;;'`
+ fi
+ if grep "^bindir" $conf >/dev/null
+ then
+ bindir=`grep "^bindir" $conf | sed 's;^[^=]*=[ \t]*;;' | sed 's;[ \t]$;;'`
+ fi
+ if grep "^user" $conf >/dev/null
+ then
+ user=`grep "^user" $conf | sed 's;^[^=]*=[ \t]*;;' | sed 's;[ \t]$;;'`
+ fi
+fi
+
+for arg
+do
+ case "$arg" in
+ --basedir=*) basedir=`echo "$arg"|sed 's;^--basedir=;;'`; bindir="$basedir/bin"; execdir="$basedir/libexec" ;;
+ --datadir=*) ldata=`echo "$arg"|sed 's;^--datadir=;;'` ;;
+ --user=*) user=`echo "$arg"|sed 's;^--user=;;'` ;;
+ esac
+done
+
+mdata=$ldata/mysql
+
+if test ! -x $execdir/mysqld
+then
+ if test "$IN_RPM" -eq 1
+ then
+ echo "FATAL ERROR $execdir/mysqld not found!"
+ exit 1
+ else
+ echo "Didn't find $execdir/mysqld"
+ echo "You should do a 'make install' before executing this script"
+ exit 1
+ fi
+fi
+
+# On IRIX hostname is in /usr/bsd so add this to the path
+PATH=$PATH:/usr/bsd
+hostname=`hostname` # Install this too in the user table
+
+# Check if hostname is valid
+if test "$IN_RPM" -eq 0 -a $force -eq 0
+then
+ resolved=`$bindir/resolveip $hostname 2>&1`
+ if [ $? -ne 0 ]
+ then
+ resolved=`$bindir/resolveip localhost 2>&1`
+ if [ $? -eq 0 ]
+ then
+ echo "Sorry, the host '$hostname' could not be looked up."
+ echo "Please configure the 'hostname' command to return a correct hostname."
+ echo "If you want to solve this at a later stage, restart this script with"
+ echo "the --force option"
+ exit 1
+ fi
+ echo "WARNING: Your libc libraries are not 100 % compatible with this MySQL version"
+ echo "mysqld should work normally with the exception that host name resolving"
+ echo "will not work. This means that you should use IP addresses instead"
+ echo "of hostnames when specifying MySQL privileges !"
+ fi
+fi
+
+# Create database directories mysql & test
+if test "$IN_RPM" -eq 0
+then
+ if test ! -d $ldata; then mkdir $ldata; chmod 700 $ldata ; fi
+ if test ! -d $ldata/mysql; then mkdir $ldata/mysql; chmod 700 $ldata/mysql ; fi
+ if test ! -d $ldata/test; then mkdir $ldata/test; chmod 700 $ldata/test ; fi
+ if test -w / -a ! -z "$user"; then
+ chown $user $ldata $ldata/mysql $ldata/test;
+ fi
+fi
+
+# Initialize variables
+c_d="" i_d=""
+c_h="" i_h=""
+c_u="" i_u=""
+c_f="" i_f=""
+c_t="" c_c=""
+
+# Check for old tables
+if test ! -f $mdata/db.frm
+then
+ echo "Creating db table"
+
+ # mysqld --bootstrap wants one command/line
+ c_d="$c_d CREATE TABLE db ("
+ c_d="$c_d Host char(60) DEFAULT '' NOT NULL,"
+ c_d="$c_d Db char(64) DEFAULT '' NOT NULL,"
+ c_d="$c_d User char(16) DEFAULT '' NOT NULL,"
+ c_d="$c_d Select_priv enum('N','Y') DEFAULT 'N' NOT NULL,"
+ c_d="$c_d Insert_priv enum('N','Y') DEFAULT 'N' NOT NULL,"
+ c_d="$c_d Update_priv enum('N','Y') DEFAULT 'N' NOT NULL,"
+ c_d="$c_d Delete_priv enum('N','Y') DEFAULT 'N' NOT NULL,"
+ c_d="$c_d Create_priv enum('N','Y') DEFAULT 'N' NOT NULL,"
+ c_d="$c_d Drop_priv enum('N','Y') DEFAULT 'N' NOT NULL,"
+ c_d="$c_d Grant_priv enum('N','Y') DEFAULT 'N' NOT NULL,"
+ c_d="$c_d References_priv enum('N','Y') DEFAULT 'N' NOT NULL,"
+ c_d="$c_d Index_priv enum('N','Y') DEFAULT 'N' NOT NULL,"
+ c_d="$c_d Alter_priv enum('N','Y') DEFAULT 'N' NOT NULL,"
+ c_d="$c_d PRIMARY KEY Host (Host,Db,User),"
+ c_d="$c_d KEY User (User)"
+ c_d="$c_d )"
+ c_d="$c_d comment='Database privileges';"
+
+ i_d="INSERT INTO db VALUES ('%','test','','Y','Y','Y','Y','Y','Y','N','Y','Y','Y');
+ INSERT INTO db VALUES ('%','test\_%','','Y','Y','Y','Y','Y','Y','N','Y','Y','Y');"
+fi
+
+if test ! -f $mdata/host.frm
+then
+ echo "Creating host table"
+
+ c_h="$c_h CREATE TABLE host ("
+ c_h="$c_h Host char(60) DEFAULT '' NOT NULL,"
+ c_h="$c_h Db char(64) DEFAULT '' NOT NULL,"
+ c_h="$c_h Select_priv enum('N','Y') DEFAULT 'N' NOT NULL,"
+ c_h="$c_h Insert_priv enum('N','Y') DEFAULT 'N' NOT NULL,"
+ c_h="$c_h Update_priv enum('N','Y') DEFAULT 'N' NOT NULL,"
+ c_h="$c_h Delete_priv enum('N','Y') DEFAULT 'N' NOT NULL,"
+ c_h="$c_h Create_priv enum('N','Y') DEFAULT 'N' NOT NULL,"
+ c_h="$c_h Drop_priv enum('N','Y') DEFAULT 'N' NOT NULL,"
+ c_h="$c_h Grant_priv enum('N','Y') DEFAULT 'N' NOT NULL,"
+ c_h="$c_h References_priv enum('N','Y') DEFAULT 'N' NOT NULL,"
+ c_h="$c_h Index_priv enum('N','Y') DEFAULT 'N' NOT NULL,"
+ c_h="$c_h Alter_priv enum('N','Y') DEFAULT 'N' NOT NULL,"
+ c_h="$c_h PRIMARY KEY Host (Host,Db)"
+ c_h="$c_h )"
+ c_h="$c_h comment='Host privileges; Merged with database privileges';"
+fi
+
+if test ! -f $mdata/user.frm
+then
+ echo "Creating user table"
+
+ c_u="$c_u CREATE TABLE user ("
+ c_u="$c_u Host char(60) DEFAULT '' NOT NULL,"
+ c_u="$c_u User char(16) DEFAULT '' NOT NULL,"
+ c_u="$c_u Password char(16) DEFAULT '' NOT NULL,"
+ c_u="$c_u Select_priv enum('N','Y') DEFAULT 'N' NOT NULL,"
+ c_u="$c_u Insert_priv enum('N','Y') DEFAULT 'N' NOT NULL,"
+ c_u="$c_u Update_priv enum('N','Y') DEFAULT 'N' NOT NULL,"
+ c_u="$c_u Delete_priv enum('N','Y') DEFAULT 'N' NOT NULL,"
+ c_u="$c_u Create_priv enum('N','Y') DEFAULT 'N' NOT NULL,"
+ c_u="$c_u Drop_priv enum('N','Y') DEFAULT 'N' NOT NULL,"
+ c_u="$c_u Reload_priv enum('N','Y') DEFAULT 'N' NOT NULL,"
+ c_u="$c_u Shutdown_priv enum('N','Y') DEFAULT 'N' NOT NULL,"
+ c_u="$c_u Process_priv enum('N','Y') DEFAULT 'N' NOT NULL,"
+ c_u="$c_u File_priv enum('N','Y') DEFAULT 'N' NOT NULL,"
+ c_u="$c_u Grant_priv enum('N','Y') DEFAULT 'N' NOT NULL,"
+ 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 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 ('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');
+
+ 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');"
+fi
+
+if test ! -f $mdata/func.frm
+then
+ echo "Creating func table"
+
+ c_f="$c_f CREATE TABLE func ("
+ c_f="$c_f name char(64) DEFAULT '' NOT NULL,"
+ c_f="$c_f ret tinyint(1) DEFAULT '0' NOT NULL,"
+ c_f="$c_f dl char(128) DEFAULT '' NOT NULL,"
+ c_f="$c_f type enum ('function','aggregate') NOT NULL,"
+ c_f="$c_f PRIMARY KEY (name)"
+ c_f="$c_f )"
+ c_f="$c_f comment='User defined functions';"
+fi
+
+if test ! -f $mdata/tables_priv.frm
+then
+ echo "Creating tables_priv table"
+
+ c_t="$c_t CREATE TABLE tables_priv ("
+ c_t="$c_t Host char(60) DEFAULT '' NOT NULL,"
+ c_t="$c_t Db char(64) DEFAULT '' NOT NULL,"
+ c_t="$c_t User char(16) DEFAULT '' NOT NULL,"
+ c_t="$c_t Table_name char(60) DEFAULT '' NOT NULL,"
+ c_t="$c_t Grantor char(77) DEFAULT '' NOT NULL,"
+ c_t="$c_t Timestamp timestamp(14),"
+ c_t="$c_t Table_priv set('Select','Insert','Update','Delete','Create','Drop','Grant','References','Index','Alter') DEFAULT '' NOT NULL,"
+ c_t="$c_t Column_priv set('Select','Insert','Update','References') DEFAULT '' NOT NULL,"
+ c_t="$c_t PRIMARY KEY (Host,Db,User,Table_name),"
+ c_t="$c_t KEY Grantor (Grantor)"
+ c_t="$c_t )"
+ c_t="$c_t comment='Table privileges';"
+fi
+
+if test ! -f $mdata/columns_priv.frm
+then
+ echo "Creating columns_priv table"
+
+ c_c="$c_c CREATE TABLE columns_priv ("
+ c_c="$c_c Host char(60) DEFAULT '' NOT NULL,"
+ c_c="$c_c Db char(64) DEFAULT '' NOT NULL,"
+ c_c="$c_c User char(16) DEFAULT '' NOT NULL,"
+ c_c="$c_c Table_name char(64) DEFAULT '' NOT NULL,"
+ c_c="$c_c Column_name char(64) DEFAULT '' NOT NULL,"
+ c_c="$c_c Timestamp timestamp(14),"
+ c_c="$c_c Column_priv set('Select','Insert','Update','References') DEFAULT '' NOT NULL,"
+ c_c="$c_c PRIMARY KEY (Host,Db,User,Table_name,Column_name)"
+ c_c="$c_c )"
+ c_c="$c_c comment='Column privileges';"
+fi
+
+ if $execdir/mysqld $defaults --bootstrap --skip-grant-tables \
+ --basedir=@prefix@ --datadir=$ldata "$@" << END_OF_DATA
+use mysql;
+$c_d
+$i_d
+
+$c_h
+$i_h
+
+$c_u
+$i_u
+
+$c_f
+$i_f
+
+$c_t
+$c_c
+END_OF_DATA
+then
+ echo ""
+ if test "$IN_RPM" -eq 0
+ then
+ echo "To start mysqld at boot time you have to copy support-files/mysql.server"
+ echo "to the right place for your system"
+ echo
+ 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 "See the manual for more instructions."
+ #
+ # Print message about upgrading unless we have created a new db table.
+ if test -z "$c_d"
+ then
+ echo
+ echo "NOTE: If you are upgrading from a MySQL <= 3.22.10 you should run"
+ echo "the $bindir/mysql_fix_privilege_tables. Otherwise you will not be"
+ echo "able to use the new GRANT command!"
+ fi
+ echo
+ if test -z "$IN_RPM"
+ then
+ echo "You can start the MySQL demon with:"
+ echo "cd @prefix@ ; $bindir/safe_mysqld &"
+ echo
+ echo "You can test the MySQL demon with the benchmarks in the 'sql-bench' directory:"
+ echo "cd sql-bench ; run-all-tests"
+ echo
+ fi
+ echo "Please report any problems with the @scriptdir@/mysqlbug script!"
+ echo
+ echo "The latest information about MySQL is available on the web at"
+ echo "http://www.mysql.com"
+ echo "Support MySQL by buying support/licenses at http://www.mysql.com/license.htmy."
+ echo
+ exit 0
+else
+ echo "Installation of grant tables failed!"
+ echo
+ echo "Examine the logs in $ldata for more information."
+ echo "You can also try to start the mysqld demon with:"
+ echo "$execdir/mysqld --skip-grant &"
+ echo "You can use the command line tool"
+ echo "$bindir/mysql to connect to the mysql"
+ echo "database and look at the grant tables:"
+ echo
+ echo "shell> $bindir/mysql -u root mysql"
+ echo "mysql> show tables"
+ echo
+ echo "Try 'mysqld --help' if you have problems with paths. Using --log"
+ echo "gives you a log in $ldata that may be helpful."
+ echo
+ echo "The latest information about MySQL is available on the web at"
+ echo "http://www.mysql.com"
+ echo "Please consult the MySQL manual section: 'Problems running mysql_install_db',"
+ echo "and the manual section that describes problems on your OS."
+ echo "Another information source is the MySQL email archive."
+ echo "Please check all of the above before mailing us!"
+ echo "And if you do mail us, you MUST use the @scriptdir@/mysqlbug script!"
+ exit 1
+fi
diff --git a/scripts/mysql_setpermission.sh b/scripts/mysql_setpermission.sh
new file mode 100755
index 00000000000..43bf8a14c06
--- /dev/null
+++ b/scripts/mysql_setpermission.sh
@@ -0,0 +1,669 @@
+#!@PERL@
+## Emacs, this is -*- perl -*- mode? :-)
+##
+## Permission setter for MySQL
+##
+## mady by Luuk de Boer (luuk@wxs.nl) 1998.
+## it's made under GPL ...:-))
+##
+##
+############################################################################
+## History
+##
+## 1.0 first start of the program
+## 1.1 some changes from monty and after that
+## initial release in mysql 3.22.10 (nov 1998)
+## 1.2 begin screen now in a loop + quit is using 0 instead of 9
+## after ideas of Paul DuBois.
+## 1.2a Add Grant, References, Index and Alter privilege handling (Monty)
+
+#### TODO
+#
+# empty ... suggestions ... mail them to me ...
+
+
+$version="1.2";
+
+use DBI;
+use Getopt::Long;
+use strict;
+use vars qw($dbh $hostname $opt_user $opt_password $opt_help $opt_host
+ $opt_socket $opt_port $host $version);
+
+
+$dbh=$host=$opt_user= $opt_password= $opt_help= $opt_host= $opt_socket= "";
+$opt_port=0;
+
+read_my_cnf(); # Read options from ~/.my.cnf
+
+GetOptions("user=s","password=s","help","host=s","socket=s","port=i");
+
+usage() if ($opt_help); # the help function
+
+if ($opt_host eq '')
+{
+ $hostname = "localhost";
+}
+else
+{
+ $hostname = $opt_host;
+}
+
+# ask for a password if no password is set already
+if ($opt_password eq '')
+{
+ system "stty -echo";
+ print "Password for user $opt_user to connect to MySQL: ";
+ $opt_password = <STDIN>;
+ chomp($opt_password);
+ system "stty echo";
+ print "\n";
+}
+
+
+# make the connection to MySQL
+$dbh= DBI->connect("DBI:mysql:mysql:host=$hostname:port=$opt_port:mysql_socket=$opt_socket",$opt_user,$opt_password, {PrintError => 0}) ||
+ die("Can't make a connection to the mysql server.\n The error: $DBI::errstr");
+
+# the start of the program
+&q1();
+exit(0); # the end...
+
+#####
+# below all subroutines of the program
+#####
+
+###
+# the beginning of the program
+###
+sub q1 { # first question ...
+ my ($answer,$end);
+ while (! $end) {
+ print "#"x70;
+ print "\n";
+ print "## Welcome to the permission setter $version for MySQL.\n";
+ print "## made by Luuk de Boer\n";
+ print "#"x70;
+ print "\n";
+ print "What would you like to do:\n";
+ print " 1. Set password for a user.\n";
+ print " 2. Add a database + user privilege for that database.\n";
+ print " - user can do all except all admin functions\n";
+ print " 3. Add user privilege for an existing database.\n";
+ print " - user can do all except all admin functions\n";
+ print " 4. Add user privilege for an existing database.\n";
+ print " - user can do all except all admin functions + no create/drop\n";
+ print " 5. Add user privilege for an existing database.\n";
+ print " - user can do only selects (no update/delete/insert etc.)\n";
+ print " 0. exit this program\n";
+ print "\nMake your choice [1,2,3,4,5,0]: ";
+ while (<STDIN>) {
+ $answer = $_;
+ chomp($answer);
+ if ($answer =~ /1|2|3|4|5|0/) {
+ &setpwd if ($answer == 1);
+ &addall($answer) if ($answer =~ /^[2345]$/);
+ if ($answer == 0) {
+ print "Sorry, hope we can help you next time \n\n";
+ $end = 1;
+ }
+ } else {
+ print "Your answer was $answer\n";
+ print "and that's wrong .... Try again\n";
+ }
+ last;
+ }
+ }
+}
+
+###
+# set a password for a user
+###
+sub setpwd
+{
+ my ($user,$pass,$host);
+ print "\n\nSetting a (new) password for a user.\n";
+
+ $user = user();
+ $pass = newpass($user);
+ $host = hosts($user);
+
+ print "#"x70;
+ print "\n\n";
+ print "That was it ... here is an overview of what you gave to me:\n";
+ print "The username : $user\n";
+# print "The password : $pass\n";
+ print "The host : $host\n";
+ print "#"x70;
+ print "\n\n";
+ print "Are you pretty sure you would like to implement this [yes/no]: ";
+ my $no = <STDIN>;
+ chomp($no);
+ if ($no =~ /n/i)
+ {
+ print "Okay .. that was it then ... See ya\n\n";
+ return(0);
+ }
+ else
+ {
+ print "Okay ... let's go then ...\n\n";
+ }
+ $user = $dbh->quote($user);
+ $host = $dbh->quote($host);
+ if ($pass eq '')
+ {
+ $pass = "''";
+ }
+ else
+ {
+ $pass = "PASSWORD(". $dbh->quote($pass) . ")";
+ }
+ my $sth = $dbh->prepare("update user set Password=$pass where User = $user and Host = $host") || die $dbh->errstr;
+ $sth->execute || die $dbh->errstr;
+ $sth->finish;
+ print "The password is set for user $user.\n\n";
+
+}
+
+###
+# all things which will be added are done here
+###
+sub addall
+{
+ my ($todo) = @_;
+ my ($answer,$good,$db,$user,$pass,$host,$priv);
+
+ if ($todo == 2)
+ {
+ $db = newdatabase();
+ }
+ else
+ {
+ $db = database();
+ }
+
+ $user = newuser();
+ $pass = newpass();
+ $host = newhosts();
+
+ print "#"x70;
+ print "\n\n";
+ print "That was it ... here is an overview of what you gave to me:\n";
+ print "The database name : $db\n";
+ print "The username : $user\n";
+# print "The password : $pass\n";
+ print "The host(s) : $host\n";
+ print "#"x70;
+ print "\n\n";
+ print "Are you pretty sure you would like to implement this [yes/no]: ";
+ my $no = <STDIN>;
+ chomp($no);
+ if ($no =~ /n/i)
+ {
+ print "Okay .. that was it then ... See ya\n\n";
+ return(0);
+ }
+ else
+ {
+ print "Okay ... let's go then ...\n\n";
+ }
+
+ if ($todo == 2)
+ {
+ # create the database
+ my $sth = $dbh->do("create database $db") || $dbh->errstr;
+ }
+
+ # select the privilege ....
+ if (($todo == 2) || ($todo == 3))
+ {
+ $priv = "'Y','Y','Y','Y','Y','Y','Y','Y','Y','Y'";
+ }
+ elsif ($todo == 4)
+ {
+ $priv = "'Y','Y','Y','Y','N','N','N','Y','Y','Y'";
+ }
+ elsif ($todo == 5)
+ {
+ $priv = "'Y','N','N','N','N','N','N','N','N','N'";
+ }
+ else
+ {
+ print "Sorry, choice number $todo isn't known inside the program .. See ya\n";
+ quit();
+ }
+
+ my @hosts = split(/,/,$host);
+ $user = $dbh->quote($user);
+ $db = $dbh->quote($db);
+ if ($pass eq '')
+ {
+ $pass = "''";
+ }
+ else
+ {
+ $pass = "PASSWORD(". $dbh->quote($pass) . ")";
+ }
+ foreach my $key (@hosts)
+ {
+ my $key1 = $dbh->quote($key);
+ my $sth = $dbh->prepare("select Host,User from user where Host = $key1 and User = $user") || die $dbh->errstr;
+ $sth->execute || die $dbh->errstr;
+ my @r = $sth->fetchrow_array;
+ if ($r[0])
+ {
+ print "WARNING WARNING SKIPPING CREATE FOR USER $user AND HOST $key\n";
+ print "Reason: entry already exists in the user table.\n";
+ }
+ else
+ {
+ $sth = $dbh->prepare("insert into user (Host,User,Password) values($key1,$user,$pass)") || die $dbh->errstr;
+ $sth->execute || die $dbh->errstr;
+ $sth->finish;
+ }
+ $sth = $dbh->prepare("INSERT INTO db (Host,Db,User,Select_priv,Insert_priv,Update_priv,Delete_priv,Create_priv,Drop_priv,Grant_priv,References_priv,Index_priv,Alter_priv) VALUES ($key1,$db,$user,$priv)") || die $dbh->errstr;
+ $sth->execute || die $dbh->errstr;
+ $sth->finish;
+ }
+ $dbh->do("flush privileges") || print "Can't load privileges\n";
+ print "Everything is inserted and mysql privileges have been reloaded.\n\n";
+}
+
+###
+# ask for a new database name
+###
+sub newdatabase
+{
+ my ($answer,$good,$db);
+ print "\n\nWhich database would you like to add: ";
+ while (<STDIN>)
+ {
+ $answer = $_;
+ $good = 0;
+ chomp($answer);
+ if ($answer)
+ {
+ my $sth = $dbh->prepare("show databases") || die $dbh->errstr;
+ $sth->execute || die $dbh->errstr;
+ while (my @r = $sth->fetchrow_array)
+ {
+ if ($r[0] eq $answer)
+ {
+ print "\n\nSorry, this database name is already in use; try something else: ";
+ $good = 1;
+ }
+ }
+ }
+ else
+ {
+ print "You must type something ...\nTry again: ";
+ next;
+ }
+ last if ($good == 0);
+ }
+ $db = $answer;
+ print "The new database $db will be created\n";
+ return($db);
+}
+
+###
+# select a database
+###
+sub database
+{
+ my ($answer,$good,$db);
+ print "\n\nWhich database would you like to select: \n";
+ print "You can choose from: \n";
+ my $sth = $dbh->prepare("show databases") || die $dbh->errstr;
+ $sth->execute || die $dbh->errstr;
+ while (my @r = $sth->fetchrow_array)
+ {
+ print " - $r[0] \n";
+ }
+ print "Which database will it be (case sensitive): ";
+ while (<STDIN>)
+ {
+ $answer = $_;
+ $good = 0;
+ chomp($answer);
+ if ($answer)
+ {
+ my $sth = $dbh->prepare("show databases") || die $dbh->errstr;
+ $sth->execute || die $dbh->errstr;
+ while (my @r = $sth->fetchrow_array)
+ {
+ if ($r[0] eq $answer)
+ {
+ $good = 1;
+ $db = $r[0];
+ last;
+ }
+ }
+ }
+ else
+ {
+ print "You must type something ...\nTry again: ";
+ next;
+ }
+ if ($good == 1)
+ {
+ last;
+ }
+ else
+ {
+ print "You must select one from the list.\nTry again: ";
+ next;
+ }
+ }
+ print "The database $db will be used.\n";
+ return($db);
+}
+
+###
+# ask for a new username
+###
+sub newuser
+{
+ my ($answer,$user);
+
+ print "\nWhat username is to be created: ";
+ while(<STDIN>)
+ {
+ $answer = $_;
+ chomp($answer);
+ if ($answer)
+ {
+ $user = $answer;
+ }
+ else
+ {
+ print "You must type something ...\nTry again: ";
+ next;
+ }
+ last;
+ }
+ print "Username = $user\n";
+ return($user);
+}
+
+###
+# ask for a user which is already in the user table
+###
+sub user
+{
+ my ($answer,$user);
+
+ print "\nFor which user do you want to specify a password: ";
+ while(<STDIN>)
+ {
+ $answer = $_;
+ chomp($answer);
+ if ($answer)
+ {
+ my $sth = $dbh->prepare("select User from user where User = '$answer'") || die $dbh->errstr;
+ $sth->execute || die $dbh->errstr;
+ my @r = $sth->fetchrow_array;
+ if ($r[0])
+ {
+ $user = $r[0];
+ }
+ else
+ {
+ print "Sorry, user $answer isn't known in the user table.\nTry again: ";
+ next;
+ }
+ }
+ else
+ {
+ print "You must type something ...\nTry again: ";
+ next;
+ }
+ last;
+ }
+ print "Username = $user\n";
+ return($user);
+}
+
+###
+# ask for a new password
+###
+sub newpass
+{
+ my ($user) = @_;
+ my ($answer,$good,$pass,$yes);
+
+ print "Would you like to set a password for $user [y/n]: ";
+ $yes = <STDIN>;
+ chomp($yes);
+ if ($yes =~ /y/)
+ {
+ system "stty -echo";
+ print "What password do you want to specify for $user: ";
+ while(<STDIN>)
+ {
+ $answer = $_;
+ chomp($answer);
+ system "stty echo";
+ print "\n";
+ if ($answer)
+ {
+ system "stty -echo";
+ print "Type the password again: ";
+ my $second = <STDIN>;
+ chomp($second);
+ system "stty echo";
+ print "\n";
+ if ($answer ne $second)
+ {
+ print "Passwords aren't the same; we begin from scratch again.\n";
+ system "stty -echo";
+ print "Password please: ";
+ next;
+ }
+ else
+ {
+ $pass = $answer;
+ }
+ }
+ else
+ {
+ print "You must type something ...\nTry again: ";
+ next;
+ }
+ last;
+ }
+# print "The password for $user is $pass.\n";
+ }
+ else
+ {
+ print "We won't set a password so the user doesn't have to use it\n";
+ $pass = "";
+ }
+ return($pass);
+}
+
+###
+# ask for new hosts
+###
+sub newhosts
+{
+ my ($answer,$good,$host);
+
+ print "We now need to know from what host(s) the user will connect.\n";
+ print "Keep in mind that % means 'from any host' ...\n";
+ print "The host please: ";
+ while(<STDIN>)
+ {
+ $answer = $_;
+ chomp($answer);
+ if ($answer)
+ {
+ $host .= ",$answer";
+ print "Would you like to add another host [yes/no]: ";
+ my $yes = <STDIN>;
+ chomp($yes);
+ if ($yes =~ /y/i)
+ {
+ print "Okay, give us the host please: ";
+ next;
+ }
+ else
+ {
+ print "Okay we keep it with this ...\n";
+ }
+ }
+ else
+ {
+ print "You must type something ...\nTry again: ";
+ next;
+ }
+ last;
+ }
+ $host =~ s/^,//;
+ print "The following host(s) will be used: $host.\n";
+ return($host);
+}
+
+###
+# ask for a host which is already in the user table
+###
+sub hosts
+{
+ my ($user) = @_;
+ my ($answer,$good,$host);
+
+ print "We now need to know which host for $user we have to change.\n";
+ print "Choose from the following hosts: \n";
+ $user = $dbh->quote($user);
+ my $sth = $dbh->prepare("select Host,User from user where User = $user") || die $dbh->errstr;
+ $sth->execute || die $dbh->errstr;
+ while (my @r = $sth->fetchrow_array)
+ {
+ print " - $r[0] \n";
+ }
+ print "The host please (case sensitive): ";
+ while(<STDIN>)
+ {
+ $answer = $_;
+ chomp($answer);
+ if ($answer)
+ {
+ $sth = $dbh->prepare("select Host,User from user where Host = '$answer' and User = $user") || die $dbh->errstr;
+ $sth->execute || die $dbh->errstr;
+ my @r = $sth->fetchrow_array;
+ if ($r[0])
+ {
+ $host = $answer;
+ last;
+ }
+ else
+ {
+ print "You have to select a host from the list ...\nTry again: ";
+ next;
+ }
+ }
+ else
+ {
+ print "You have to type something ...\nTry again: ";
+ next;
+ }
+ last;
+ }
+ print "The following host will be used: $host.\n";
+ return($host);
+}
+
+###
+# a nice quit (first disconnect and then exit
+###
+sub quit
+{
+ $dbh->disconnect;
+ exit(0);
+}
+
+###
+# Read variables password, port and socket from .my.cnf under the client
+# or perl groups
+###
+
+sub read_my_cnf
+{
+ open(TMP,$ENV{'HOME'} . "/.my.cnf") || return 1;
+ while (<TMP>)
+ {
+ if (/^\[(client|perl)\]/i)
+ {
+ while ((defined($_=<TMP>)) && !/^\[\w+\]/)
+ {
+ print $_;
+ if (/^host\s*=\s*(\S+)/i)
+ {
+ $opt_host = $1;
+ }
+ elsif (/^user\s*=\s*(\S+)/i)
+ {
+ $opt_user = $1;
+ }
+ elsif (/^password\s*=\s*(\S+)/i)
+ {
+ $opt_password = $1;
+ }
+ elsif (/^port\s*=\s*(\S+)/i)
+ {
+ $opt_port = $1;
+ }
+ elsif (/^socket\s*=\s*(\S+)/i)
+ {
+ $opt_socket = $1;
+ }
+ }
+ }
+ }
+ close(TMP);
+}
+
+###
+# the help text
+###
+sub usage
+{
+ print <<EOL;
+----------------------------------------------------------------------
+ The permission setter for MySQL.
+ version: $version
+
+ made by: Luuk de Boer <luuk\@wxs.nl>
+----------------------------------------------------------------------
+
+The permission setter is a little program which can help you add users
+or databases or change passwords in MySQL. Keep in mind that we don't
+check permissions which already been set in MySQL. So if you can't
+connect to MySQL using the permission you just added, take a look at
+the permissions which have already been set in MySQL.
+
+The permission setter first reads your .my.cnf file in your Home
+directory if it exists.
+
+Options for the permission setter:
+
+--help : print this help message and exit.
+
+The options shown below are used for making the connection to the MySQL
+server. Keep in mind that the permissions for the user specified via
+these options must be sufficient to add users / create databases / set
+passwords.
+
+--user : is the username to connect with.
+--password : the password of the username.
+--host : the host to connect to.
+--socket : the socket to connect to.
+--port : the port number of the host to connect to.
+
+If you don't give a password and no password is set in your .my.cnf
+file, then the permission setter will ask for a password.
+
+
+EOL
+exit(0);
+}
diff --git a/scripts/mysql_zap.sh b/scripts/mysql_zap.sh
new file mode 100755
index 00000000000..b94bbb80ca7
--- /dev/null
+++ b/scripts/mysql_zap.sh
@@ -0,0 +1,156 @@
+#!@PERL@
+# This is a utility for MySQL. It is not needed by any standard part
+# of MySQL.
+
+# Usage: mysql_zap [-signal] [-f] [-t] pattern
+
+# Configuration parameters.
+
+$sig = ""; # Default to try all signals
+$ans = "y";
+$opt_f= 0;
+$opt_t= 0;
+$opt_a = "";
+
+$BSD = -f '/vmunix' || $ENV{"OS"} eq "SunOS4";
+$LINUX = $^O eq 'linux';
+$pscmd = $BSD ? "/bin/ps -auxww" : $LINUX ? "/bin/ps axuw" : "/bin/ps -ef";
+
+open(TTYIN, "</dev/tty") || die "can't read /dev/tty: $!";
+open(TTYOUT, ">/dev/tty") || die "can't write /dev/tty: $!";
+select(TTYOUT);
+$| = 1;
+select(STDOUT);
+$SIG{'INT'} = 'cleanup';
+
+while ($#ARGV >= $[ && $ARGV[0] =~ /^-/) {
+ if ($ARGV[0] =~ /(ZERO|HUP|INT|QUIT|ILL|TRAP|ABRT|EMT|FPE|KILL|BUS|SEGV|SYS|PIPE|ALRM|TERM|URG|STOP|TSTP|CONT|CLD|TTIN|TTOU|IO|XCPU|XFSZ|VTALRM|PROF|WINCH|LOST|USR1|USR2)/ || $ARGV[0] =~ /-(\d+)$/) {
+ $sig = $1;
+ } elsif ($ARGV[0] eq "-f") {
+ $opt_f=1;
+ } elsif ($ARGV[0] eq "-t") {
+ $opt_t=1;
+ $ans = "n";
+ }
+ elsif ($ARGV[0] eq "-a")
+ {
+ $opt_a = 1;
+ }
+ elsif ($ARGV[0] eq "-?" || $ARGV[0] eq "-I")
+ {
+ &usage;
+ }
+ else {
+ print STDERR "$0: illegal argument $ARGV[0] ignored\n";
+ }
+ shift;
+}
+
+&usage if $#ARGV < 0;
+
+if (!$opt_f)
+{
+ if ($BSD) {
+ system "stty cbreak </dev/tty >/dev/tty 2>&1";
+ }
+ else {
+ system "stty", 'cbreak',
+ system "stty", 'eol', '^A';
+ }
+}
+
+open(PS, "$pscmd|") || die "can't run $pscmd: $!";
+$title = <PS>;
+print TTYOUT $title;
+
+# Catch any errors with eval. A bad pattern, for instance.
+eval <<'EOF';
+process: while ($cand = <PS>)
+{
+ chop($cand);
+ ($user, $pid) = split(' ', $cand);
+ next if $pid == $$;
+ $found = !@ARGV;
+ if ($opt_a) { $found = 1; }
+ foreach $pat (@ARGV)
+ {
+ if ($opt_a)
+ {
+ if (! ($cand =~ $pat))
+ {
+ next process;
+ }
+ }
+ else
+ {
+ $found = 1 if $cand =~ $pat;
+ }
+ }
+ next if (!$found);
+ if (! $opt_f && ! $opt_t)
+ {
+ print TTYOUT "$cand? ";
+ read(TTYIN, $ans, 1);
+ print TTYOUT "\n" if ($ans ne "\n");
+ }
+ else
+ {
+ print TTYOUT "$cand\n";
+ }
+ if ($ans =~ /^y/i) { &killpid($sig, $pid); }
+ if ($ans =~ /^q/i) { last; }
+}
+EOF
+
+&cleanup;
+
+
+sub usage {
+ print <<EOF;
+Usage: $0 [-signal] [-?Ift] pattern
+Options: -I or -? "info" -f "force" -t "test".
+
+Version 1.0
+Kill processes with matches pattern.
+If -f isn't given, ask user for confirmation for each process to kill.
+If signal isn't given, try first with signal 15 and after that with signal 9.
+If -t is given the processes is only shown on stdout.
+EOF
+ exit(1);
+}
+
+sub cleanup {
+ if ($BSD) {
+ system "stty -cbreak </dev/tty >/dev/tty 2>&1";
+ }
+ else {
+ system "stty", 'icanon';
+ system "stty", 'eol', '^@';
+ }
+ print "\n";
+ exit;
+}
+
+sub killpid {
+ local($signal,$pid) = @_;
+ if ($signal)
+ {
+ kill $signal,$pid;
+ }
+ else
+ {
+ print "kill -15\n";
+ kill 15, $pid;
+ for (1..5) {
+ sleep 2;
+ return if kill(0, $pid) == 0;
+ }
+ print "kill -9\n";
+ kill 9, $pid;
+ for (1..5) {
+ sleep 2;
+ return if kill(0, $pid) == 0;
+ }
+ print "$pid will not die!\n";
+ }
+}
diff --git a/scripts/mysqlaccess.conf b/scripts/mysqlaccess.conf
new file mode 100755
index 00000000000..faf47da5f6c
--- /dev/null
+++ b/scripts/mysqlaccess.conf
@@ -0,0 +1,45 @@
+# ------------------------------------------------------------------------- #
+# MySQLaccess version 2.0p2 #
+# (c) Yves.Carlier@rug.ac.be, 1997 #
+# #
+# *** Configuration file *** #
+# #
+# -Default values read by mysqlaccess during initialisation. #
+# This file is looked for in #
+# 1) the current directory #
+# 2) /etc/ #
+# -Options given on the command-line override the values given in here #
+# -Given options can't be overruled by empty/blanc options!! #
+# ------------------------------------------------------------------------- #
+
+
+# ----------------#
+# Global settings #
+# --------------- #
+ #$Param{'host'} = '';
+ $Param{'user'} = 'nobody';
+ $Param{'db'} = 'test';
+ $Param{'password'} = 'foobar';
+ $Param{'debug'} = 0;
+
+# --------------------------#
+# Settings for Command-line #
+# ------------------------- #
+if ($CMD) {
+ $Param{'superuser'} = 'root';
+ $Param{'rhost'} = 'localhost';
+ $Param{'spassword'} = '';
+ $Param{'brief'} = 1;
+}
+
+# ---------------------#
+# Settings for CGI-BIN #
+# -------------------- #
+if ($CGI) {
+ $Param{'superuser'} = 'root';
+ $Param{'rhost'} = 'localhost';
+ $Param{'spassword'} = '';
+ $Param{'table'} = 1;
+}
+
+1; #to make require happy
diff --git a/scripts/mysqlaccess.sh b/scripts/mysqlaccess.sh
new file mode 100755
index 00000000000..dfc88ecad98
--- /dev/null
+++ b/scripts/mysqlaccess.sh
@@ -0,0 +1,3248 @@
+#!@PERL@
+# ****************************
+package MySQLaccess;
+#use strict;
+use POSIX qw(tmpnam);
+use Fcntl;
+
+BEGIN {
+ # ****************************
+ # static information...
+ $VERSION = "2.05, 17 Feb 2000";
+ $0 =~ m%/([^/]+)$%o;
+ $script = $1;
+ $script = 'MySQLAccess' unless $script;
+ $script_conf = "$script.conf";
+ $script_log = "~/$script.log";
+
+ # ****************************
+ # information on MySQL
+ $MYSQL = '@bindir@/mysql'; # path to mysql executable
+ $SERVER = '3.21';
+ $MYSQL_OPT = ' --batch --unbuffered';
+ $ACCESS_DB = 'mysql'; # name of DB with grant-tables
+ $ACCESS_H = 'host'; #
+ $ACCESS_U = 'user'; #
+ $ACCESS_D = 'db'; #
+ # Add/Edit privileges
+ $ACCESS_H_TMP = 'host_tmp';
+ $ACCESS_U_TMP = 'user_tmp';
+ $ACCESS_D_TMP = 'db_tmp';
+ $ACCESS_H_BCK = 'host_backup';
+ $ACCESS_U_BCK = 'user_backup';
+ $ACCESS_D_BCK = 'db_backup';
+ $DIFF = '/usr/bin/diff';
+ $TMP_PATH = '/tmp'; #path to writable tmp-directory
+ $MYSQLDUMP = '@bindir@/mysqldump';
+ #path to mysqldump executable
+
+ $MYSQLADMIN= 'http://foobar.com/MySQLadmin';
+ #URL of CGI for manipulating
+ #the temporary grant-tables
+}
+
+END {
+ unlink $MYSQL_CNF if defined $MYSQL_CNF and not $DEBUG;
+}
+
+$INFO = <<"_INFO";
+--------------------------------------------------------------------------
+ mysqlaccess (Version $VERSION)
+ ~~~~~~~~~~~
+ Copyright (C) 1997,1998 Yves.Carlier\@rug.ac.be
+ University of Ghent (RUG), Belgium
+ Administratieve Informatieverwerking (AIV)
+
+ report the access-privileges for a USER from a HOST to a DB
+
+ Many thanks go to <monty\@mysql.com> and <psmith\@BayNetworks.COM>
+ for their suggestions, debugging and patches.
+
+ use `$script -?' to get more information on available options.
+
+ From version 2.0x, $script can also be used through a WEB-browser
+ if it is ran as a CGI-script. (See the release-notes)
+
+--------------------------------------------------------------------------
+_INFO
+
+$OPTIONS = <<_OPTIONS;
+
+Usage: $script [host [user [db]]] OPTIONS
+
+ -?, --help display this helpscreen and exit
+ -v, --version print information on the program `$script'
+
+ -u, --user=# username for logging in to the db
+ -p, --password=# validate password for user
+ -h, --host=# name or IP-number of the host
+ -d, --db=# name of the database
+
+ -U, --superuser=# connect as superuser
+ -P, --spassword=# password for superuser
+ -H, --rhost=# remote MySQL-server to connect to
+ --old_server connect to old MySQL-server (before v3.21) which
+ does not yet know how to handle full where clauses.
+
+ -b, --brief single-line tabular report
+ -t, --table report in table-format
+
+ --relnotes print release-notes
+ --plan print suggestions/ideas for future releases
+ --howto some examples of how to run `$script'
+ --debug=N enter debuglevel N (0..3)
+
+ --copy reload temporary grant-tables from original ones
+ --preview show differences in privileges after making
+ changes in (temporary) grant-tables
+ --commit copy grant-rules from temporary tables to grant-tables
+ (!don't forget to do an mysqladmin reload)
+ --rollback undo the last changes to the grant-tables.
+
+ Note:
+ + At least the user and the db must be given (even with wildcards)
+ + If no host is given, `localhost' is assumed
+ + Wilcards (*,?,%,_) are allowed for host, user and db, but be sure
+ to escape them from your shell!! (ie type \\* or '*')
+_OPTIONS
+
+$RELEASE = <<'_RELEASE';
+
+Release Notes:
+-------------
+ 0.1-beta1: internal
+ - first trial.
+
+ 0.1-beta2: (1997-02-27)
+ - complete rewrite of the granting-rules, based on the documentation
+ found in de FAQ.
+ - IP-number and name for a host are equiv.
+
+ 0.1-beta3: (1997-03-10)
+ - more information
+ - 'localhost' and the name/ip of the local machine are now equiv.
+
+ 0.1-beta4: (1997-03-11)
+ - inform the user if he has not enough priv. to read the mysql db
+
+ 1.0-beta1: (1997-03-12)
+ suggestions by Monty:
+ - connect as superuser with superpassword.
+ - mysqlaccess could also notice if all tables are empty. This means
+ that all user have full access!
+ - It would be nice if one could optionally start mysqlaccess without
+ any options just the arguments 'user db' or 'host user db', where
+ host is 'localhost' if one uses only two arguments.
+
+ 1.0-beta2: (1997-03-14)
+ - bugfix: translation to reg.expr of \_ and \%.
+ - bugfix: error in matching regular expression and string given
+ by user which resulted in
+ 'test_123' being matched with 'test'
+
+ 1.0-beta3: (1997-03-14)
+ - bugfix: the user-field should not be treated as a sql-regexpr,
+ but as a plain string.
+ - bugfix: the host-table should not be used if the host isn't empty in db
+ or if the host isn't emty in user
+ (Monty)
+
+ 1.0-beta4: (1997-03-14)
+ - bugfix: in an expression "$i = $j or $k", the '=' binds tighter than the or
+ which results in problems...
+ (by Monty)
+ - running mysqlaccess with "perl -w" gives less warnings... ;-)
+
+ 1.0-beta5: (1997-04-04)
+ - bugfix: The table sorting was only being applied to the "user" table; all
+ the tables need to be sorted. Rewrote the sort algorithm, and
+ the table walk algorithm (no temp file anymore), and various
+ other cleanups. I believe the access calculation is 100% correct.
+ (by Paul D. Smith <psmith\@baynetworks.com>)
+ - Allow the debug level to be set on the cmd line with --debug=N.
+ (by Paul D. Smith <psmith\@baynetworks.com>)
+ - More -w cleanups; should be totally -w-clean.
+ (by Paul D. Smith <psmith\@baynetworks.com>)
+
+ 1.1-beta1: (1997-04-xx)
+ 1.1-beta2: (1997-04-11)
+ - new options:
+ --all_users : report access-rights for all possible users
+ --all_dbs : report access-rights for all possible dbs
+ --all_hosts : report access-rights for all possible hosts
+ --brief : as brief as possible, don't mention notes,warnings and rules
+ --password : validate password for user
+ - layout: long messages are wrapped on the report.
+ - functionality:
+ more descriptive notes and warnings
+ wildcards (*,?) are allowed in the user,host and db options
+ setting xxxx=* is equiv to using option --all_xxxx
+ note: make sure you escape your wildcards, so they don't get
+ interpreted by the shell. use \* or '*'
+ - bugfix: Fieldnames which should be skipped on the output can now have
+ a first capital letter.
+ - bugfix: any option with a '.' (eg ip-number) was interpreted as
+ a wildcard-expression.
+ - bugfix: When no entry was found in the db-table, the default accessrights are
+ N, instead of the faulty Y in a previous version.
+
+ 1.1-beta-3 : (1997-04-xx)
+ 1.1-beta-4 : (1997-04-xx)
+ 1.1-beta-5 : (1997-04-xx)
+ 1.1 : (1997-04-28)
+ - new options:
+ --rhost : name of mysql-server to connect to
+ --plan : print suggestions/ideas for future releases
+ --relnotes : display release-notes
+ --howto : display examples on how to use mysqlaccess
+ --brief : single-line tabular output
+ - functionality/bugfix:
+ * removed options --all_users,--all_dbs,--all_hosts, which
+ were redundant with the wildcard-expressions for the corresponding
+ options. They made the processing of the commandline too painful
+ and confusing ;-)
+ (suggested by psmith)
+ * redefined the option --brief, which now gives a single-line
+ tabular output
+ * Now we check if the right version of the mysql-client is used,
+ since we might use an option not yet implemented in an
+ older version (--unbuffered, since 3.0.18)
+ Also the error-messages the mysql-client reports are
+ better interpreted ;-)
+ * Wildcards can now be given following the SQL-expression
+ (%,_) and the Regular-expression (*,?) syntax.
+ - speed: we now open a bidirectional pipe to the mysql-client, and keep
+ it open throughout the whole run. Queries are written to,
+ and the answers read from the pipe.
+ (suggested by monty)
+ - bugfixes:
+ * the Rules were not properly reset over iterations
+ * when in different tables the field-names were not identical,
+ eg. Select_priv and select_priv, they were considered as
+ definitions of 2 different access-rights.
+ * the IP-number of a host with a name containing wildcards should
+ not be searched for in Name2IP and IP2Name.
+ * various other small things, pointed out by <monty> and <psmith>
+
+ 1.2 : (1997-05-13)
+ - bugfix:
+ * Fixed bug in acl with anonymous user: Now if one gets accepted by the
+ user table as a empty user name, the user name is set to '' when
+ checking against the 'db' and 'host' tables. (Bug fixed in MySQL3.20.19)
+
+ 1.2-1 : (1997-xx-xx)
+ - bugfix:
+ * hashes should be initialized with () instead of {} <psmith>
+ * "my" variable $name masks earlier declaration in same scope,
+ using perl 5.004 <????>
+
+ 1.2-2 : (1997-06-10)
+
+ 2.0p1-3 : (1997-10-xx)
+ - new
+ * packages
+ * log-file for debug-output : /tmp/mysqlaccess.log
+ * default values are read from a configuration file $script.conf
+ first this file is looked for in the current directory; if not
+ found it is looked for in /etc/
+ Note that when default-values are given, these can't get overriden
+ by empty (blanc) values!
+ * CGI-BIN version with HTML and forms interface. Simply place the
+ script in an ScriptAliased directory, make the configuration file
+ available in the that directory or in /etc, and point your browser
+ to the right URL.
+ * copy the grant-rules to temporary tables, where you are safe to
+ play with them.
+ * preview changes in privileges after changing grant-rules,
+ before taking them into production
+ * copy the new grant-rules from the temporary tables back to the
+ grant-tables.
+ * Undo all changes made in the grant-tables (1-level undo).
+ -new options:
+ * --table : as opposite of the --brief option.
+ * --copy : (re)load temporary grant-tables from original ones.
+ * --preview : preview changes in privileges after changing
+ some or more entries in the grant-tables.
+ * --commit : copy grant-rules from temporary tables to grant-tables
+ (!don't forget to do an mysqladmin reload)
+ * --rollback: undo the last changes to the grant-tables.
+
+ - bugfix:
+ * if the table db is empty, mysqlaccess freezed
+ (by X Zhu <X.Zhu@Bradford.ac.uk>)
+
+ 2.0 : (1997-10-09)
+ - fixed some "-w" warnings.
+ - complain when certain programs and paths can't be found.
+
+ 2.01 : (1997-12-12)
+ - bugfix:
+ * rules for db-table where not calculated and reported correctly.
+ 2.02 : (1998-01-xx)
+ - bugfix:
+ * Privileges of the user-table were not AND-ed properly with the
+ other privileges. (reported by monty)
+ - new option:
+ * --old_server: mysqlaccess will now use a full where clause when
+ retrieving information from the MySQL-server. If
+ you are connecting to an old server (before v3.21)
+ use the option --old_server.
+ 2.03 : (1998-02-27)
+ - bugfix:
+ * in Host::MatchTemplate: incorrect match if host-field was left empty.
+
+ 2.04-alpha1 : (2000-02-11)
+ Closes vulnerability due to former implementation requiring passwords
+ to be passed on the command line.
+ - functionality
+ Option values for --password -p -spassword -P may now be omitted from
+ command line, in which case the values will be prompted for.
+ (fix supplied by Steve Harvey <sgh@vex.net>)
+
+ 2.05: (2000-02-17) Monty
+ Moved the log file from /tmp to ~
+
+_RELEASE
+
+$TODO = <<_TODO;
+
+ Plans:
+ -----
+ -a full where clause is use now. How can we handle older servers?
+ -add some more functionality for DNS.
+ -select the warnings more carefuly.
+ >> I think that the warnings should either be enhanced to _really_
+ >> understand and report real problems accurately, or restricted to
+ >> only printing things that it knows with 100% certainty. <psmith)
+ >> Why do I have both '%' and 'any_other_host' in there? Isn't that
+ >> the same thing? I think it's because I have an actual host '%' in
+ >> one of my tables. Probably the script should catch that and not
+ >> duplicate output. <psmith>
+
+_TODO
+
+# From the FAQ: the Grant-algorithm
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+# The host table is mainly to maintain a list of "secure" servers.
+# At TCX hosts contain a list of all machines on local network. These are granted
+# all privileges.
+# Technically the user grant is calculated by:
+#
+# 1.First sort all entries by host by putting host without wildcards first,
+# after this host with wildcards and entries with host = ".
+# Under each host sort user by the same criterias.
+# 2.Get grant for user from the "db" table.
+# 3.If hostname is "empty" for the found entry, AND the privileges with
+# the privileges for the host in "host" table.
+# (Remove all which is not "Y" in both)
+# 4.OR (add) the privileges for the user from the "user" table.
+# (add all privileges which is "Y" in "user")
+#
+# When matching, use the first found match.
+#
+# -----------------------------------------------------------------------------------
+
+$HOWTO = <<_HOWTO;
+
+Examples of how to call $script:
+~~~~~~~~
+1)Calling $script with 2 arguments:
+
+ \$ $script root mysql
+ ->report rights of user root logged on at the local host in db mysql
+
+ Access-rights
+ for USER 'root', from HOST 'localhost', to DB 'mysql'
+ +-----------------+---+ +-----------------+---+
+ | select_priv | Y | | drop_priv | Y |
+ | insert_priv | Y | | reload_priv | Y |
+ | update_priv | Y | | shutdown_priv | Y |
+ | delete_priv | Y | | process_priv | Y |
+ | create_priv | Y | | file_priv | Y |
+ +-----------------+---+ +-----------------+---+
+ BEWARE: Everybody can access your DB as user 'root'
+ : WITHOUT supplying a password. Be very careful about it!!
+
+ The following rules are used:
+ db : 'No matching rule'
+ host : 'Not processed: host-field is not empty in db-table.'
+ user : 'localhost','root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y'
+
+2)Calling $script with 3 arguments:
+
+ \$ $script foo.bar nobody Foo
+ ->report rights of user root logged in at machine foobar to db Foo
+
+ Access-rights
+ for USER 'nobody', from HOST 'foo.bar', to DB 'Foo'
+ +-----------------+---+ +-----------------+---+
+ | select_priv | Y | | drop_priv | N |
+ | insert_priv | Y | | reload_priv | N |
+ | update_priv | Y | | shutdown_priv | N |
+ | delete_priv | Y | | process_priv | N |
+ | create_priv | N | | file_priv | N |
+ +-----------------+---+ +-----------------+---+
+ BEWARE: Everybody can access your DB as user 'nobody'
+ : WITHOUT supplying a password. Be very careful about it!!
+
+ The following rules are used:
+ db : 'foo.bar','Foo','nobody','Y','Y','Y','N','N','N'
+ host : 'Not processed: host-field is not empty in db-table.'
+ user : 'foo.bar','nobody','','N','N','N','Y','N','N','N','N','N','N'
+
+3)Using wildcards:
+
+ \$ $script \\* nobody Foo --brief
+ ->report access-rights of user nobody from all machines to db Foo,
+ and use a matrix-report.
+
+ Sel Ins Upd Del Crea Drop Reld Shut Proc File Host,User,DB
+ ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- --------------------
+ Y Y Y Y N N N N N N localhost,nobody,Foo
+ N N N N N N N N N N %,nobody,Foo
+ N N N N N N N N N N any_other_host,nobody,Foo
+
+_HOWTO
+
+
+# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ #
+# START OF THE PROGRAM #
+# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ #
+
+use Getopt::Long;
+use Sys::Hostname;
+use IPC::Open3;
+#use CGI; #moved to use of CGI by monty
+
+
+# ****************************
+# debugging flag
+# can be set to 0,1,2,3
+# a higher value gives more info
+# ! this can also be set on the command-line
+ $DEBUG = 0;
+
+# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++>8
+# Normaly nothing should be changed beneeth this line
+
+
+# ****************************
+# no caching on STDOUT
+ $|=1;
+
+ $MYSQL_CNF = POSIX::tmpnam();
+ %MYSQL_CNF = (client => { },
+ mysql => { },
+ mysqldump => { },
+ );
+
+
+
+$NEW_USER = 'ANY_NEW_USER';
+$NEW_DB = 'ANY_NEW_DB' ;
+
+
+# %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #
+# mysqlaccess: #
+# ~~~~~~~~~~~ #
+# Lets get to it, #
+# and start the program by processing the parameters #
+# %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #
+
+($CMD,$CGI) = GetMode();
+
+# ****************************
+# the copyright message should
+# always be printed (once)
+MySQLaccess::Report::Print_Header();
+
+# *****************************
+# Read configuration-file
+ MySQLaccess::Debug::Print(1, "Reading configuration file...");
+ if (-f "./$script_conf") {
+ require "./$script_conf";
+ }
+ elsif (-f "/etc/$script_conf") {
+ require "/etc/$script_conf";
+ }
+
+# ****************************
+# Read in all parameters
+if ($MySQLaccess::CMD) { #command-line version
+ # ----------------------------
+ # Get options from commandline
+ $Getopt::Long::ignorecase=0; #case sensitive options
+ if ( grep(/\-\?/,@ARGV) ) { MySQLaccess::Report::Print_Usage(); exit 0; }
+ GetOptions("help" => \$Param{'help'}
+ ,"host|h=s" => \$Param{'host'}
+ ,"user|u=s" => \$Param{'user'}
+ ,"password|p:s" => \$Param{'password'}
+ ,"db|d=s" => \$Param{'db'}
+ ,"superuser|U=s" => \$Param{'superuser'}
+ ,"spassword|P:s" => \$Param{'spassword'}
+ ,"rhost|H=s" => \$Param{'rhost'}
+ ,"old_server" => \$Param{'old_server'}
+ ,"debug=i" => \$Param{'DEBUG'}
+ ,"brief|b" => \$Param{'brief'}
+ ,"table|t" => \$Param{'table'}
+ ,"relnotes" => \$Param{'relnotes'}
+ ,"plan" => \$Param{'plan'}
+ ,"howto" => \$Param{'howto'}
+ ,"version|v" => \$Param{'version'}
+ ,"preview" => \$Param{'preview'}
+ ,"copy" => \$Param{'copy'}
+ ,"commit" => \$Param{'commit'}
+ ,'rollback' => \$Param{'rollback'}
+ );
+
+ # -----------------------------
+ # set DEBUG
+ $DEBUG = $Param{'DEBUG'} if ($Param{'DEBUG'}>=$DEBUG);
+
+ # -----------------------------
+ # check for things which aren't
+ # declared as options:
+ # 2 arguments: (user,db) -> ('localhost','user','db')
+ if ($#ARGV == 1) {
+ MySQLaccess::Debug::Print(2,"$script called with 2 arguments:");
+ $Param{'host'} = $Param{'host'} || 'localhost';
+ $Param{'user'} = $ARGV[0] || $Param{'user'};
+ $Param{'db'} = $ARGV[1] || $Param{'db'};
+ }
+ # 3 arguments: (host,user,db)
+ if ($#ARGV == 2) {
+ MySQLaccess::Debug::Print(2,"$script called with 3 arguments:");
+ $Param{'host'} = $ARGV[0] || $Param{'host'};
+ $Param{'user'} = $ARGV[1] || $Param{'user'};
+ $Param{'db'} = $ARGV[2] || $Param{'db'};
+ }
+
+ # -------------------------------------
+ # prompt for user password if requested
+ if ( defined($Param{'password'}) && length($Param{'password'}) == 0 ) {
+ $Param{'password'} = PromptPass(
+ "Password for MySQL user $Param{'user'}: ");
+ }
+}
+if ($MySQLaccess::CGI) { #CGI-version
+ use CGI;
+ $Q = new CGI;
+ $Param{'help'} = $Q->param('help') ;
+ $Param{'host'} = $Q->param('host') || $Q->param('h') || $Param{'host'};
+ $Param{'user'} = $Q->param('user') || $Q->param('u') || $Param{'user'};
+ $Param{'db'} = $Q->param('db') || $Q->param('d') || $Param{'db'};
+ $Param{'password'} = $Q->param('password') || $Q->param('p') || $Param{'password'};
+ $Param{'superuser'} = $Q->param('superuser') || $Q->param('U') || $Param{'superuser'};
+ $Param{'spassword'} = $Q->param('spassword') || $Q->param('P') || $Param{'spassword'};
+ $Param{'rhost'} = $Q->param('rhost') || $Q->param('H') || $Param{'rhost'};
+ $Param{'old_server'}= $Q->param('old_server')|| $Param{'old_server'};
+ $Param{'debug'} = $Q->param('debug') || $Param{'debug'};
+ $Param{'brief'} = $Q->param('brief') || $Param{'brief'};
+ $Param{'table'} = $Q->param('table') || $Param{'table'};
+ $Param{'relnotes'} = $Q->param('relnotes');
+ $Param{'plan'} = $Q->param('plan');
+ $Param{'howto'} = $Q->param('howto');
+ $Param{'version'} = $Q->param('version') ? $Q->param('version') : $Q->param('v');
+ $Param{'edit'} = $Q->param('edit');
+ $Param{'preview'} = $Q->param('preview');
+ $Param{'copy'} = $Q->param('copy');
+ $Param{'commit'} = $Q->param('commit');
+ $Param{'rollback'} = $Q->param('rollback');
+ # -----------------------------
+ # set DEBUG
+ $DEBUG = $Q->param('debug') if ($Q->param('debug')>=$DEBUG);
+}
+
+# ----------------------
+# brief and table-format
+# exclude each-other
+# table-format is prefered
+if (defined($Param{'table'})) { undef($Param{'brief'}); }
+if (defined($Param{'preview'}) or
+ defined($Param{'copy'}) or
+ defined($Param{'commit'}) or
+ defined($Param{'rollback'}) ) { $Param{'edit'}='on'; }
+
+
+# ----------------------
+# if no host is given
+# assume we mean 'localhost'
+if (!defined($Param{'host'})) { $Param{'host'}='localhost'; }
+
+# ----------------------
+# perform some checks
+# -> eliminate 'broken pipe' error
+push(@MySQLaccess::Grant::Error,'not_found_mysql') if !(-x $MYSQL);
+push(@MySQLaccess::Grant::Error,'not_found_diff') if !(-x $DIFF);
+push(@MySQLaccess::Grant::Error,'not_found_mysqldump') if !(-x $MYSQLDUMP);
+push(@MySQLaccess::Grant::Error,'not_found_tmp') if !(-d $TMP_PATH);
+push(@MySQLaccess::Grant::Error,'write_err_tmp') if !(-w $TMP_PATH);
+if (@MySQLaccess::Grant::Error) {
+ MySQLaccess::Report::Print_Error_Messages() ;
+ exit 0;
+}
+
+#-----------------------
+# get info/help if necc.
+$print_usage=1;
+if ( defined($Param{'version'}) ) {
+ MySQLaccess::Report::Print_Version();
+ $print_usage=0;
+ MySQLaccess::Report::Print_Footer();
+ MySQLaccess::DB::CloseConnection();
+ exit 0;
+# exit 0;
+}
+if ( defined($Param{'relnotes'}) ) {
+ MySQLaccess::Report::Print_Relnotes();
+ $print_usage=0;
+ MySQLaccess::Report::Print_Footer();
+ MySQLaccess::DB::CloseConnection();
+ exit 0;
+# exit 0;
+}
+if ( defined($Param{'plan'}) ) {
+ MySQLaccess::Report::Print_Plans();
+ $print_usage=0;
+ MySQLaccess::Report::Print_Footer();
+ MySQLaccess::DB::CloseConnection();
+ exit 0;
+# exit 0;
+}
+if ( defined($Param{'howto'}) ) {
+ MySQLaccess::Report::Print_HowTo();
+ $print_usage=0;
+ MySQLaccess::Report::Print_Footer();
+ MySQLaccess::DB::CloseConnection();
+ exit 0;
+# exit 0;
+}
+
+# -----------------------------
+# generate a help-screen in CMD-mode
+# or a blanc form in CGI-mode
+if ( defined($Param{'help'})
+ or !defined($Param{'user'})
+ or !defined($Param{'host'})
+ or !defined($Param{'db'})
+ ) {
+ push(@MySQLaccess::Grant::Error,'user_required') unless defined($Param{'user'});
+ push(@MySQLaccess::Grant::Error,'db_required') unless defined($Param{'db'});
+ push(@MySQLaccess::Grant::Error,'host_required') unless defined($Param{'host'});
+ MySQLaccess::Report::Print_Usage() if $print_usage;
+ exit 0;
+}
+
+
+# ----------------------------
+# get hostname and local-ip
+# for localhost
+$localhost = MySQLaccess::Host::LocalHost();
+$local_ip = MySQLaccess::Host::Name2IP($localhost);
+$MySQLaccess::Host::localhost = MySQLaccess::Host::LocalHost();
+$MySQLaccess::Host::local_ip = MySQLaccess::Host::Name2IP($localhost);
+MySQLaccess::Debug::Print(3, "localhost name=$localhost, ip=$local_ip");
+
+#-----------------------------------
+# version of MySQL-server to connect
+# to determine use of full where clause
+$MySQLaccess::Host::SERVER = $Param{'old_server'} ? '3.20' : $SERVER;
+
+#---------------------------------
+# create the config file for mysql and mysqldump
+# to avoid passing authentication info on the command line
+#
+MergeConfigFiles();
+die "Unsafe config file found: $unsafeConfig\n" if $unsafeConfig;
+if (defined($Param{'superuser'})) {
+ $MYSQL_CNF{'mysql'}{'user'} = $Param{'superuser'};
+ $MYSQL_CNF{'mysqldump'}{'user'} = $Param{'superuser'};
+}
+if (defined($Param{'spassword'})) {
+ if ( $CMD && length($Param{'spassword'}) == 0 ) {
+ $Param{'spassword'} =
+ PromptPass("Password for MySQL superuser $Param{'superuser'}: ");
+ }
+ if ( length($Param{'spassword'}) > 0 ) {
+ $MYSQL_CNF{'mysql'}{'password'} = $Param{'spassword'};
+ $MYSQL_CNF{'mysqldump'}{'password'} = $Param{'spassword'};
+ }
+}
+WriteTempConfigFile();
+
+#---------------------------------
+# Inform user if he has not enough
+# privileges to read the access-db
+if ( $nerror=MySQLaccess::DB::OpenConnection() ) {
+ MySQLaccess::Report::Print_Error_Access($nerror);
+ exit 0;
+}
+
+# -----------------------
+# Read MySQL ACL-files
+if ($nerror=MySQLaccess::Grant::ReadTables()) {
+ MySQLaccess::Report::Print_Error_Access($nerror);
+ exit 0;
+};
+if ($Param{'edit'} and $nerror=MySQLaccess::Grant::ReadTables('tmp')) {
+ MySQLaccess::Report::Print_Error_Access($nerror);
+ exit 0;
+}
+
+#---------------------------------
+# reload temporay grant-tables
+# with data from original ones
+if ( defined($Param{'copy'}) ) {
+ $nerror=MySQLaccess::DB::LoadTmpTables();
+ if ($nerror) {
+ MySQLaccess::Report::Print_Error_Access($nerror);
+ exit 0;
+ }
+ my $msg = "The grant-rules are copied from the grant-tables to\n"
+ . "the temporary tables.";
+ MySQLaccess::Report::Print_Message([$msg]);
+# MySQLaccess::Report::Print_Footer();
+# MySQLaccess::DB::CloseConnection();
+# exit 0;
+}
+
+
+#---------------------------------
+# preview result of changes in the
+# grant-tables
+if ( defined($Param{'preview'}) ) {
+ $aref=MySQLaccess::Grant::Diff_Privileges();
+ MySQLaccess::Report::Print_Diff_ACL($aref);
+# MySQLaccess::Report::Print_Footer();
+# MySQLaccess::DB::CloseConnection();
+# exit 0;
+}
+
+
+#---------------------------------
+# reload grant-tables
+# with data from temporary tables
+if ( defined($Param{'commit'}) ) {
+ if ($nerror = MySQLaccess::DB::CommitGrantTables()) {
+ MySQLaccess::Report::Print_Error_Access($nerror);
+ exit 0;
+ }
+ my $msg = "The grant-rules have been copied from the temporary tables\n"
+ . "to the grant-tables.";
+ my $msg1= "Don't forget to do an 'mysqladmin reload' before these\n"
+ . "changes take effect.";
+ my $msg2= "A backup-version of your original grant-rules are saved in the\n"
+ . "backup-tables, so you can always perform a 1-level rollback.";
+ MySQLaccess::Report::Print_Message([$msg,$msg1,$msg2]);
+# MySQLaccess::Report::Print_Footer();
+# MySQLaccess::DB::CloseConnection();
+# exit 0;
+}
+
+#---------------------------------
+# restore previous grant-rules
+# with data from backup tables
+if ( defined($Param{'rollback'}) ) {
+ if ($nerror = MySQLaccess::DB::RollbackGrantTables()) {
+ MySQLaccess::Report::Print_Error_Access($nerror);
+ exit 0;
+ }
+ my $msg = "The old grant-rules have been copied back from the backup tables\n"
+ . "to the grant-tables.";
+ my $msg1= "Don't forget to do an 'mysqladmin reload' before these\n"
+ . "changes take effect.";
+ MySQLaccess::Report::Print_Message([$msg,$msg1]);
+# MySQLaccess::Report::Print_Footer();
+# MySQLaccess::DB::CloseConnection();
+# exit 0;
+}
+#----------------------------------
+# show edit-taskbar
+if ( defined($Param{'edit'})) {
+ if ($MySQLaccess::CGI ) {
+ MySQLaccess::Report::Print_Edit();
+ $print_usage=0;
+ MySQLaccess::Report::Print_Footer();
+ MySQLaccess::DB::CloseConnection();
+ exit 0;
+ }
+ else {
+ MySQLaccess::Report::Print_Edit();
+ $print_usage=0;
+ MySQLaccess::Report::Print_Footer();
+ MySQLaccess::DB::CloseConnection();
+ exit 0;
+ }
+}
+
+
+# -----------------------------
+# Build list of users,dbs,hosts
+# to process...
+@all_dbs = @{MySQLaccess::DB::Get_All_dbs($Param{'db'})};
+@all_users = @{MySQLaccess::DB::Get_All_users($Param{'user'})};
+@all_hosts = @{MySQLaccess::DB::Get_All_hosts($Param{'host'})};
+#if EDIT-mode
+#@all_dbs_tmp = @{MySQLaccess::DB::Get_All_dbs($Param{'db'},'tmp')};
+#@all_users_tmp = @{MySQLaccess::DB::Get_All_users($Param{'user'},'tmp')};
+#@all_hosts_tmp = @{MySQLaccess::DB::Get_All_hosts($Param{'host'},'tmp')};
+
+# -----------------------------
+# Report access-rights for each
+# tuple (host,user,db)
+#$headers=0;
+my %Access = ();
+foreach $host (@all_hosts) {
+ foreach $user (@all_users) {
+ foreach $db (@all_dbs) {
+ MySQLaccess::Grant::Initialize();
+ %Access = MySQLaccess::Grant::Get_Access_Rights($host,$user,$db);
+ MySQLaccess::Report::Print_Access_rights($host,$user,$db,\%Access);
+ }
+ }
+}
+
+# -----------------------------
+# End script
+MySQLaccess::Report::Print_Footer();
+MySQLaccess::DB::CloseConnection();
+exit 0;
+
+#############################################################
+# FUNCTIONS #
+###############
+sub GetMode {
+ my $cmd=0;
+ my $cgi=0;
+ if (defined($ENV{'HTTP_HOST'})) { $cmd=0; $cgi=1; }
+ else { $cmd=1; $cgi=0; }
+ return ($cmd,$cgi);
+}
+
+# ================================
+# sub PromptPass
+# prompt tty for a password
+# ================================
+sub PromptPass {
+ my ($prompt) = @_;
+ my $password;
+ $ENV{PATH} = "/bin:/usr/bin";
+ $ENV{IFS} = " \t\n";
+ $ENV{SHELL} = "/bin/sh";
+ system "stty -echo";
+ print $prompt;
+ chomp($password = <STDIN>);
+ print "\n";
+ system "stty echo";
+ $password;
+}
+
+# =================================
+# sub CheckUnsafeFile
+# tell if a config file containing a password is unsafe
+# =================================
+sub CheckUnsafeFile {
+ my ($fname) = @_;
+ my ($dev, $ino, $mode, $nlink,
+ $uid, $gid, $rdev, $size,
+ $atime, $mtime, $ctime, $blksize, $blocks) = stat($fname);
+
+ if ( $uid != $< ) { # unsafe if owned by other than current user
+ return 1;
+ }
+ if ( $mode & 066 ) { # unsafe if accessible by other
+ return 1;
+ }
+ $fname =~ s#/[^/]+$##;
+ if ( (length $fname) > 0 ) {
+ return CheckUnsafeDir($fname);
+ }
+ return 0;
+}
+
+# =================================
+# sub CheckUnsafeDir
+# tell if a directory is unsafe
+# =================================
+sub CheckUnsafeDir {
+ my ($fname) = @_;
+ my ($dev, $ino, $mode, $nlink,
+ $uid, $gid, $rdev, $size,
+ $atime, $mtime, $ctime, $blksize, $blocks) = stat($fname);
+
+ # not owned by me or root
+ if ( ($uid != $<) && ($uid != 0) ) {
+ return 1;
+ }
+ if ( $mode & 022 ) { # unsafe if writable by other
+ return 1 unless $mode & 01000; # but sticky bit ok
+ }
+ $fname =~ s#/[^/]+$##;
+ if ( (length $fname) > 0 ) {
+ return CheckUnsafeDir($fname);
+ }
+ return 0;
+}
+
+# =================================
+# sub MergeConfigFile
+# merge data from .cnf file
+# =================================
+sub MergeConfigFile {
+ my ($fname) = @_;
+ my ($group, $item, $value);
+ if ( open CNF, $fname ) {
+ while (<CNF>) {
+ s/^\s+//;
+ next if /^[#;]/;
+ if ( /\[\s*(\w+)\s*]/ ) {
+ $group = $1;
+ $group =~ tr/A-Z/a-z/;
+ if ( !exists $MYSQL_CNF{$group} ) {
+ undef $group;
+ }
+ } elsif ( defined $group ) {
+ ($item, $value) = /((?:\w|-)+)\s*=\s*(\S+)/;
+ # don't unquote backslashes as we just write it back out
+ if ( defined $item ) {
+ if ( $item =~ /^password$/ ) {
+ if ( CheckUnsafeFile($fname) ) {
+ $unsafeConfig = $fname;
+ }
+ }
+ if ( $group eq 'client' ) {
+ $MYSQL_CNF{'mysql'}{$item} = $value;
+ $MYSQL_CNF{'mysqldump'}{$item} = $value;
+ } else {
+ $MYSQL_CNF{$group}{$item} = $value;
+ }
+ }
+ }
+ }
+ close(CNF);
+ }
+}
+
+# =================================
+# sub MergeConfigFiles
+# merge options from config files
+# NOTE: really should do two separate merges for each
+# client to exactly duplicate order of resulting argument lists
+# =================================
+sub MergeConfigFiles {
+ my ($name,$pass,$uid,$gid,$quota,$comment,$gcos,$dir,$shell) = getpwuid $<;
+ MergeConfigFile("/etc/my.cnf");
+ MergeConfigFile("$dir/.my.cnf");
+}
+
+# =================================
+# sub WriteTempConfigFile
+# write
+# =================================
+sub WriteTempConfigFile {
+ sysopen CNFFILE, $MYSQL_CNF, O_RDWR|O_CREAT|O_EXCL, 0700
+ or die "sysopen $MYSQL_CNF: $!";
+
+ # groups may be in any order, generic groups such as [client] assumed
+ # here to be empty
+ foreach $group (keys %MYSQL_CNF) {
+ print CNFFILE "[$group]\n";
+ foreach $item (keys %{$MYSQL_CNF{$group}}) {
+ if ( defined $MYSQL_CNF{$group}{$item} ) {
+ print CNFFILE "$item=$MYSQL_CNF{$group}{$item}\n";
+ } else {
+ print CNFFILE "$item\n";
+ }
+ }
+ print CNFFILE "\n";
+ }
+ close(CNFFILE);
+}
+
+######################################################################
+package MySQLaccess::DB;
+###########
+BEGIN {
+ $DEBUG = 2;
+ $DEBUG = $MySQLaccess::DEBUG unless ($DEBUG);
+ # Error-messages from the MySQL client
+ %ACCESS_ERR= ('Access_denied' => 'Access denied'
+ ,'Dbaccess_denied' => 'Access to database denied'
+ ,'Unrecognized_option' => 'unrecognized option'
+ ,'Unknown_table' => "Can't find file:"
+ ,'unknown_error' => '^ERROR:'
+ );
+}
+# ######################################
+# Connecting to the MYSQL DB
+# ======================================
+# sub OpenConnection
+# Open an connection to the mysql-db
+# questions to MYSQL_Q
+# answers from MYSQL_A
+# ======================================
+sub OpenConnection {
+ my $pid;
+ MySQLaccess::Debug::Print(2,"OpenConnection:");
+
+ # check path to mysql-client executable
+ if (! -f $MySQLaccess::MYSQL) {
+ if ($MySQLaccess::CMD) { die "Could not find MySQL-client '$MySQLaccess::MYSQL'"; }
+ if ($MySQLaccess::CGI) {
+ print "<center>\n<font color=Red>\n";
+ print "ERROR: Could not find MySQL-client '$MySQLaccess::MYSQL'";
+ print "</center>\n</font>\n";
+ exit 0;
+ }
+ }
+
+ # path to mysql executable
+ my $connect = "$MySQLaccess::MYSQL --defaults-file=$MySQLaccess::MYSQL_CNF";
+ $connect .= " $MySQLaccess::MYSQL_OPT";
+ # superuser, spassword transmitted via defaults-file
+ if (defined($MySQLaccess::Param{'rhost'})) { $connect .= " --host=$MySQLaccess::Param{'rhost'}"; }
+ # other options??
+
+ # grant-database
+ $connect .= " $MySQLaccess::ACCESS_DB";
+
+ # open connection (not using /bin/sh -c)
+ MySQLaccess::Debug::Print(2,"Connecting to: $connect");
+ $pid=IPC::Open3::open3(\*MYSQL_Q,\*MYSQL_A,"",split /\s+/,$connect);
+ MySQLaccess::Debug::Print(2,"PID of open pipe: $pid");
+
+ # check connection
+ print MYSQL_Q "select 'ok';\n";
+ $answer = <MYSQL_A>; #answer from mysql
+ MySQLaccess::Debug::Print(2,"Answer: $answer\n");
+ foreach $nerror (sort(keys(%ACCESS_ERR))) {
+ MySQLaccess::Debug::Print(3,"check answer for error $ACCESS_ERR{$nerror}");
+ if (grep(/$ACCESS_ERR{$nerror}/i,$answer)) {
+ MySQLaccess::Debug::Print(2,"Answer contain error [$nerror]");
+ return $nerror;
+ }
+ }
+
+if (0) {
+ # check server-version
+ print MYSQL_Q "select 'ok';\n";
+ $answer = <MYSQL_A>; #answer from mysql
+ MySQLaccess::Debug::Print(2,"Answer: $answer\n");
+ foreach $nerror (sort(keys(%ACCESS_ERR))) {
+ MySQLaccess::Debug::Print(3,"check answer for error $ACCESS_ERR{$nerror}");
+ if (grep(/$ACCESS_ERR{$nerror}/i,$answer)) {
+ MySQLaccess::Debug::Print(2,"Answer contain error [$nerror]");
+ return $nerror;
+ }
+ }
+}
+
+ my $skip=<MYSQL_A>;
+ return 0;
+}
+
+# ======================================
+# sub CloseConnection
+# Close the connection to the mysql-db
+# ======================================
+sub CloseConnection {
+ close MYSQL_Q;
+ close MYSQL_A;
+}
+
+# ===========================================================
+# sub CreateTable($table)
+# Create temporary/backup table
+# ===========================================================
+sub CreateTable {
+ my $pid;
+ my ($table,$force) = @_;
+ my %tables = ( $MySQLaccess::ACCESS_U_TMP => $MySQLaccess::ACCESS_U,
+ $MySQLaccess::ACCESS_H_TMP => $MySQLaccess::ACCESS_H,
+ $MySQLaccess::ACCESS_D_TMP => $MySQLaccess::ACCESS_D,
+ $MySQLaccess::ACCESS_U_BCK => $MySQLaccess::ACCESS_U,
+ $MySQLaccess::ACCESS_H_BCK => $MySQLaccess::ACCESS_H,
+ $MySQLaccess::ACCESS_D_BCK => $MySQLaccess::ACCESS_D,
+ $MySQLaccess::ACCESS_U => $MySQLaccess::ACCESS_U_BCK,
+ $MySQLaccess::ACCESS_H => $MySQLaccess::ACCESS_H_BCK,
+ $MySQLaccess::ACCESS_D => $MySQLaccess::ACCESS_D_BCK,
+ );
+ my $tbl;
+ my $query="";
+ my $delim;
+ my $skip;
+ my $create;
+ my @known_tables=();
+
+# print STDERR "CreateTable($table)\n";
+ MySQLaccess::Debug::Print(1,"CreateTable($table):");
+
+ ## error-handling
+ return 'Unknown_table' unless defined($tables{$table});
+
+ ## build list of known/existing tables;
+ ## if 'force' existing table is dropped first
+ if (defined($force) and $force) {
+ @known_tables = Show_Tables();
+ if (grep(/^$table$/,@known_tables)) {
+ $query = "DROP TABLE $table;";
+ }
+ }
+
+ ## path to mysqldump executable
+ my $connect = $MySQLaccess::MYSQLDUMP;
+ $connect .= " --defaults-file=$MySQLaccess::MYSQL_CNF --no-data";
+ # superuser, spassword transmitted via defaults-file
+ if (defined($MySQLaccess::Param{'rhost'})) { $connect .= " --host=$MySQLaccess::Param{'rhost'}"; }
+ $connect .= " $MySQLaccess::ACCESS_DB";
+ $connect .= " $tables{$table}";
+
+
+ ## get creation-data for original table
+ $create = '';
+ my $mysqldump = $connect;
+ $mysqldump =~ s/ \$TABLE / $tbl /;
+
+ # open connection (not using /bin/sh -c)
+ MySQLaccess::Debug::Print(2,"Connecting to: $connect");
+ $pid=IPC::Open3::open3(\*DONTCARE,\*CREATE,"",split /\s+/,$mysqldump);
+ MySQLaccess::Debug::Print(2,"PID of open pipe: $pid");
+ #open(CREATE,"$mysqldump");
+ @create = <CREATE>;
+ $create = "@create";
+ foreach $nerror (sort(keys(%ACCESS_ERR))) {
+ MySQLaccess::Debug::Print(3,"check answer for error $ACCESS_ERR{$nerror}");
+ if (grep(/$ACCESS_ERR{$nerror}/i,$create)) {
+ MySQLaccess::Debug::Print(2,"Answer contain error [$nerror]");
+ return $nerror;
+ }
+ }
+ close(CREATE);
+ close(DONTCARE);
+
+ ## manipulate result for creation-data for temporary table
+ $create =~ s/CREATE TABLE $tables{$table} \(/CREATE TABLE $table \(/;
+
+ ## recreate temporary table
+ $query .= "$create\n";
+ $query .= "select 'ok';";
+
+ ## execute query
+ print MYSQL_Q "$query\n";
+# print STDERR $query;
+
+ $answer = <MYSQL_A>; #answer from mysql
+# print STDERR "A>",$answer;
+ MySQLaccess::Debug::Print(2,"Answer: $answer\n");
+ foreach $nerror (sort(keys(%ACCESS_ERR))) {
+# print STDERR "->$nerror?";
+ MySQLaccess::Debug::Print(3,"check answer for error $ACCESS_ERR{$nerror}");
+ if (grep(/$ACCESS_ERR{$nerror}/i,$answer)) {
+# print STDERR "Yes!";
+ MySQLaccess::Debug::Print(2,"Answer contain error [$nerror]");
+ return $nerror;
+ }
+ }
+
+ $delim = <MYSQL_A>; # read header
+ if ($delim ne "ok\n") {
+ while (($line=<MYSQL_A>) ne "ok\n")
+ { MySQLaccess::Debug::Print(3," A> $line"); }
+ $skip = <MYSQL_A>; # skip result 'ok'
+ }
+# print STDERR "CreateTable done\n";
+ return 0;
+}
+
+
+# ===========================================================
+# sub CopyTable()
+# Copy the structure and the data of a table to another table
+# ===========================================================
+sub CopyTable {
+ my ($from,$to,$force) = @_;
+ my @known_tables = Show_Tables();
+ my $query = "";
+ my $nerror= 0;
+ my $skip;
+
+# print STDERR "CopyTable($from,$to)\n";
+ MySQLaccess::Debug::Print(1,"MySQLaccess::DB::CopyTable($from,$to)");
+
+ ## error-handling
+ if (!grep(/^$from$/,@known_tables)) { return 'Unknown_table'; }
+
+ ## copy structure
+ ## if forced
+ if (defined($force) and $force) {
+ return $nerror if ($nerror=CreateTable($to,$force));
+# print STDERR "Structure copied\n";
+ }
+
+ ## copy data
+ $query .= "DELETE FROM $to;";
+ $query .= "INSERT INTO $to SELECT * FROM $from;";
+ $query .= "SELECT 'ok';\n";
+ MySQLaccess::Debug::Print(2,"Query: $query");
+
+ ## execute query
+ print MYSQL_Q "$query\n";
+# print STDERR $query;
+
+ ## check for errors...
+ my $answer = <MYSQL_A>; #answer from mysql
+# print STDERR $answer;
+ MySQLaccess::Debug::Print(2,"Answer: $answer\n");
+ foreach $nerror (sort(keys(%ACCESS_ERR))) {
+ MySQLaccess::Debug::Print(3,"check answer for error $ACCESS_ERR{$nerror}");
+ if (grep(/$ACCESS_ERR{$nerror}/i,$answer)) {
+ MySQLaccess::Debug::Print(2,"Answer contain error [$nerror]");
+ return $nerror;
+ }
+ }
+
+ my $delim = <MYSQL_A>; # read header
+# print STDERR $delim;
+ if ($delim ne "ok\n") {
+ while (($line=<MYSQL_A>) ne "ok\n")
+ { MySQLaccess::Debug::Print(3," A> $line"); }
+ $skip = <MYSQL_A>; # skip result 'ok'
+ }
+
+ return 0;
+}
+
+# ===========================================================
+# sub LoadTmpTables()
+# (Re)load temporary tables with entries of ACL-tables
+# ===========================================================
+sub LoadTmpTables {
+ my %tables = ( $MySQLaccess::ACCESS_U => $MySQLaccess::ACCESS_U_TMP,
+ $MySQLaccess::ACCESS_H => $MySQLaccess::ACCESS_H_TMP,
+ $MySQLaccess::ACCESS_D => $MySQLaccess::ACCESS_D_TMP,
+ );
+ my $tbl;
+ my $nerror;
+
+# print STDERR "LoadTmpTables:\n";
+ MySQLaccess::Debug::Print(1,"LoadTmpTables():");
+ foreach $tbl (keys(%tables)) {
+# print STDERR "$tbl -> $tables{$tbl}\n";
+ MySQLaccess::Debug::Print(2,"Loading table $tbl -> $tables{$tbl}.");
+ return $nerror if ($nerror=CopyTable($tbl,$tables{$tbl},'force'));
+ }
+ return 0;
+}
+
+# ===========================================================
+# sub BackupGrantTables()
+# Make a backup of the original grant-tables
+# ===========================================================
+sub BackupGrantTables {
+ my %tables = ( $MySQLaccess::ACCESS_U => $MySQLaccess::ACCESS_U_BCK,
+ $MySQLaccess::ACCESS_H => $MySQLaccess::ACCESS_H_BCK,
+ $MySQLaccess::ACCESS_D => $MySQLaccess::ACCESS_D_BCK,
+ );
+ my $tbl;
+ my $nerror;
+
+# print STDERR "BackupGrantTables:\n";
+ MySQLaccess::Debug::Print(1,"BackupGrantTables():");
+ foreach $tbl (keys(%tables)) {
+# print STDERR "$tbl -> $tables{$tbl}\n";
+ MySQLaccess::Debug::Print(2,"Backup table $tbl -> $tables{$tbl}.");
+ return $nerror if ($nerror=CopyTable($tbl,$tables{$tbl},'force'));
+ }
+ return 0;
+}
+
+# ===========================================================
+# sub RollbackGrantTables()
+# Rollback the backup of the grant-tables
+# ===========================================================
+sub RollbackGrantTables {
+ my %tables = ( $MySQLaccess::ACCESS_U_BCK => $MySQLaccess::ACCESS_U,
+ $MySQLaccess::ACCESS_H_BCK => $MySQLaccess::ACCESS_H,
+ $MySQLaccess::ACCESS_D_BCK => $MySQLaccess::ACCESS_D,
+ );
+ my $tbl;
+ my $nerror;
+
+# print STDERR "RollbackGrantTables:\n";
+ MySQLaccess::Debug::Print(1,"RollbackGrantTables():");
+ foreach $tbl (keys(%tables)) {
+# print STDERR "$tbl -> $tables{$tbl}\n";
+ MySQLaccess::Debug::Print(2,"Rollback table $tbl -> $tables{$tbl}.");
+ return $nerror if ($nerror=CopyTable($tbl,$tables{$tbl},'force'));
+ }
+ return 0;
+}
+
+
+# ===========================================================
+# sub CommitGrantTables()
+# Copy grant-rules from temporary tables to the ACL-tables
+# ===========================================================
+sub CommitGrantTables {
+ my %tables = ( $MySQLaccess::ACCESS_U => $MySQLaccess::ACCESS_U_TMP,
+ $MySQLaccess::ACCESS_H => $MySQLaccess::ACCESS_H_TMP,
+ $MySQLaccess::ACCESS_D => $MySQLaccess::ACCESS_D_TMP,
+ );
+ my $tbl;
+ my $query;
+ my $delim;
+ my $skip;
+ my $create;
+
+ print STDERR "CommitGrantTables()\n";
+ MySQLaccess::Debug::Print(1,"CommitGrantTables():");
+
+ ## Make backup of original grant-tables
+ MySQLaccess::Debug::Print(2,"Making backup of original grant-tables...");
+ BackupGrantTables();
+
+ ## Copy data from temporay tables to grant-tables
+ foreach $tbl (keys(%tables)) {
+ print STDERR "$tbl -> $tables{$tbl}\n";
+ MySQLaccess::Debug::Print(2,"Loading data $tables{$tbl} -> $tbl.");
+ return $nerror if ($nerror=CopyTable($tables{$tbl},$tbl));
+ }
+ return 0;
+}
+
+
+# ===========================================================
+# sub Show_Fields($table):
+# return (a reference to) a hash which holds the names
+# of all relevant grant-fields, with their index in the record,
+# and (a reference to) an array which holds the fieldnames.
+# ===========================================================
+sub Show_Fields {
+ my ($table) = @_;
+ my %skip = ('host' => [0,1]
+ ,'user' => [0,1,2]
+ ,'db' => [0,1,2]
+ );
+ my %Struct = ();
+ my @Struct = ();
+ my $query = "show fields from $table;select 'ok';\n";
+ my $i=0;
+ my $line;
+
+#print STDERR $query;
+ MySQLaccess::Debug::Print(1,"Show_Fields($table):");
+ MySQLaccess::Debug::Print(2,"SQL: $query");
+
+ print MYSQL_Q "$query";
+ my $skip = <MYSQL_A>; #skip header
+ while (($line=<MYSQL_A>) ne "ok\n")
+ {
+#print STDERR ">",$line;
+ chop($line);
+ MySQLaccess::Debug::Print(2," $table>: $line");
+ my ($field,$type,$null,$key,$default,$extra) = split(' ',$line);
+ $field = ucfirst($field);
+ MySQLaccess::Debug::Print(3, " <split: $field - $type - $null - $key - $default - $extra");
+ if (! grep(/$i/,@{$skip{$table}}) ){
+ $Struct{$field} = $i; #hash
+ push(@Struct,$field); #array
+ MySQLaccess::Debug::Print(3," ==> added column[$i]: $field ($Struct{$field})");
+ }
+ else {
+ MySQLaccess::Debug::Print(3," ==> skipped column[$i], value=[$field]");
+ }
+ $i++;
+ }
+
+ $skip=<MYSQL_A>; # Get ok row (found already ok header)
+
+ MySQLaccess::Debug::Print(2, "Array:");
+ foreach $field (@Struct) { MySQLaccess::Debug::Print(2,"+ $field"); }
+ MySQLaccess::Debug::Print(2,"Hash:");
+ foreach $field (keys(%Struct)) { MySQLaccess::Debug::Print(2,"+ $field -> $Struct{$field}"); }
+
+ return (\%Struct,\@Struct);
+}
+
+# ===========================================================
+# sub Show_Tables():
+# return (a reference to) an array which holds all
+# known tables.
+# ===========================================================
+sub Show_Tables {
+ my @Tables = ();
+ my $query = "show tables;select 'ok';\n";
+ my $i=0;
+ my $line;
+
+ MySQLaccess::Debug::Print(1,"Show_Tables():");
+ MySQLaccess::Debug::Print(2,"SQL: $query");
+
+ print MYSQL_Q "$query";
+ my $skip = <MYSQL_A>; #skip header
+ while (($line=<MYSQL_A>) ne "ok\n")
+ {
+ chop($line);
+ push(@Tables,$line); #array
+ MySQLaccess::Debug::Print(3," ==> added table: $line");
+ }
+
+ $skip=<MYSQL_A>; # Get ok row (found already ok header)
+
+ MySQLaccess::Debug::Print(2, "Array:");
+ foreach $tbl (@Tables) { MySQLaccess::Debug::Print(2,"+ $tbl"); }
+
+ return @Tables;
+}
+
+# ======================================
+# sub Validate_Password($passwd,$host,$user,$encpw)
+# Validate the given password
+# for user '$user'
+# connecting from host '$host'
+# ======================================
+sub Validate_Password {
+ my ($password,$host,$user,$encpw) = @_;
+ my $valid=0;
+
+ MySQLaccess::Debug::Print(1,"Validate_Password($password,$host,$user,$encpw)");
+ my $sql = "select host,user,password from user having "
+ ."host='$host' and user='$user' and password='$encpw' "
+ ."and password=PASSWORD('$password');\n";
+ $sql .= "select 'ok';\n";
+ MySQLaccess::Debug::Print(2,"SQL = $sql");
+ print MYSQL_Q "$sql";
+
+ # if password is valid, at least 1 row returns before we read 'ok'
+ while ( ($line=<MYSQL_A>) ne "ok\n") {
+ MySQLaccess::Debug::Print(2," A> $line");
+ $valid = defined($line);
+ }
+ my $skip = <MYSQL_A>; # read 'ok'
+
+ return $valid;
+}
+
+
+# ==========================================================
+# sub Sort_fields: (rewritten by psmith)
+# Build the query for an ordered list of entries
+# ==========================================================
+sub Sort_fields {
+ my ($start, $end, $sofar, $this, @rest) = (@_);
+ my @where = ("((FIELD not like '\\%') AND (FIELD <> ''))",
+ "((FIELD like '%\\%%') OR (FIELD like '%\\_%'))",
+ "(FIELD = '')");
+ my $res = '';
+
+ $this or return ("$start $sofar $end");
+
+ $sofar .= ' AND ' if $sofar;
+
+ foreach $w (@where) {
+ my $f = $w;
+ $f =~ s/FIELD/$this/g;
+
+ $res .= Sort_fields($start, $end, "$sofar$f", @rest);
+ }
+
+ return ($res);
+}
+
+# ===========================================================
+# sub Sort_table: (rewritten by psmith)
+# return all entries in the given table,
+# in an ordered fashion
+# ===========================================================
+sub Sort_table {
+ my ($tbl, @order) = @_;
+ my @res=();
+
+ # as long as there's no full where clause (Distrib 3.20)...
+ # use having :-(
+ # NOTE: this clause WILL NOT work on 3.21, because of the
+ # order of 'ORDER BY' and 'HAVING'
+ my $start = "SELECT *,UCASE(host) as ucase_host FROM $tbl ";
+ $start .= 'ORDER BY ' . join(',', @order) ." HAVING ";
+ my $end = ";\n";
+
+ # server version 3.21 has a full where clause :-)
+ if ($MySQLaccess::Host::SERVER >= '3.21') {
+print "+++USING FULL WHERE CLAUSE+++\n";
+ $start = "SELECT *,UCASE(host) as ucase_host FROM $tbl WHERE ";
+ $end = ' ORDER BY ' . join(',', @order) . ";\n";
+ }
+
+ MySQLaccess::Debug::Print(1,"Sort_table():");
+ MySQLaccess::Debug::Print(2,"Sorting table $tbl by `@order'");
+
+ my $tmp;
+ foreach $tmp (@order)
+ {
+ $tmp="UCASE(host)" if ($tmp eq "ucase_host");
+ }
+ my $query = Sort_fields($start, $end, '', @order);
+ $query .= "select 'ok';\n";
+ MySQLaccess::Debug::Print(2,"Query: $query");
+
+ print MYSQL_Q "$query\n";
+
+ my $delim = <MYSQL_A>; # read header
+ MySQLaccess::Debug::Print(3," A> $delim");
+ if ($delim ne "ok\n") {
+ if ($delim =~ /^ERROR/) {
+ push(@MySQLaccess::Grant::Error,'use_old_server');
+ MySQLaccess::Report::Print_Error_Messages() ;
+ exit 1;
+ }
+ while (($line=<MYSQL_A>) ne "ok\n")
+ {
+ MySQLaccess::Debug::Print(3," A> $line");
+ push(@res,$line);
+ }
+ }
+ my $skip = <MYSQL_A>; # skip result 'ok'
+
+ # remove columnheaders from output
+ @res = grep(!/^\Q$delim\E$/, @res);
+ # remove trailing \n from each returned record
+ chomp(@res);
+ # each record has 1 field to much : ucase_host
+ @res = grep { /(.*)\t.*$/; $_ = $1; } @res;
+
+ MySQLaccess::Debug::Print(2,"Result of sorted table $tbl:");
+ foreach $line (@res) { MySQLaccess::Debug::Print(2," >>$line"); }
+ return @res;
+}
+
+# ===========================================================
+# sub Get_All_db(template):
+# return all db the grant-tables are working on,
+# which conform to the template
+# ===========================================================
+sub Get_All_dbs {
+ my ($template,$tmp) = @_;
+ my @db=();
+ my $aref;
+
+ # working with temporary tables or production tables
+ if (defined($tmp) and $tmp) {
+ $aref = \@MySQLaccess::Grant::sorted_db_tmp_table ;
+ }
+ else {
+ $aref = \@MySQLaccess::Grant::sorted_db_table;
+ }
+
+ MySQLaccess::Debug::Print(1," template=[$template]");
+
+ # get all db for which access-rights can be calculated,
+ # which conform to the template.
+ # !! these db's don't have to exist yet, so it's not
+ # enough to look which db already exist on the system
+ $reg_expr = $template;
+ if ($template =~ /[\*\?]/) {
+ $reg_expr =~ tr/*?/%_/;
+ #$reg_expr = MySQLaccess::Wildcards::Wild2Reg($template);
+ }
+ $reg_expr = MySQLaccess::Wildcards::SQL2Reg("$reg_expr");
+
+ if ( ! ($template =~ /[\*\?%_]/) ) {
+ push(@db,$template);
+ return \@db;
+ }
+
+ MySQLaccess::Debug::Print(2,"#Reading db-table...");
+ foreach $record (@{$aref}) { #MySQLaccess::Grant::sorted_db_table) {
+ my @record=split(/\t/,$record);
+ my $db = $record[1];
+ MySQLaccess::Debug::Print(2,"> $db ");
+ if ( (!grep(/$db/i,@db)) and ($db =~/$reg_expr/i) ) {
+ push(@db,$db);
+ MySQLaccess::Debug::Print(2,"added");
+ }
+ else {
+ MySQLaccess::Debug::Print(2,"skipped");
+ }
+ }
+ # if no rule is found for a certain db in the db-table,
+ # the rights of the user are used, so we should inform
+ # the user for
+ if (!grep(/^%$/,@db)) { push(@db,"$MySQLaccess::NEW_DB"); }
+ return \@db;
+}
+
+# ===========================================================
+# sub Get_All_users(template):
+# return all users the grant-tables are working on,
+# which conform to the template
+# ===========================================================
+sub Get_All_users {
+ ($template,$tmp) = @_; # nog verder uitwerken!!!
+ my @user=();
+ my $aref;
+
+ # working with temporary tables or production tables
+ if (defined($tmp) and $tmp) {
+ $aref = \@MySQLaccess::Grant::sorted_user_tmp_table ;
+ }
+ else {
+ $aref = \@MySQLaccess::Grant::sorted_user_table;
+ }
+
+ MySQLaccess::Debug::Print(1,"Debug Get_All_users:");
+ # get all db for which access-rights can be calculated.
+ # !! these db's don't have to exist yet, so it's not
+ # enough to look which db already exist on the system
+ $reg_expr = $template;
+ if ($template =~ /[\*\?]/) {
+ $reg_expr =~ tr/*?/%_/;
+ #$reg_expr = MySQLaccess::Wildcards::Wild2Reg($template);
+ }
+ $reg_expr = MySQLaccess::Wildcards::SQL2Reg("$reg_expr");
+
+ if ( ! ($template =~ /[\*\?%_]/) ) {
+ push(@user,$template);
+ return \@user;
+ }
+
+ MySQLaccess::Debug::Print(2,"#Reading user-table...");
+ foreach $record (@{$aref}) { #MySQLaccess::Grant::sorted_user_table) {
+ my @record=split(/\t/,$record);
+ my $user = $record[1];
+ MySQLaccess::Debug::Print(2,"> $user ");
+ if ( (!grep(/$user/,@user)) and ($user=~/$reg_expr/)) {
+ push(@user,$user);
+ MySQLaccess::Debug::Print(2, "added");
+ }
+ else {
+ MySQLaccess::Debug::Print(2, "skipped");
+ }
+ }
+ # Any user means also:
+ # - the 'empty' user, ie without supplying a username
+ # - any user still to be defined/created
+ #push(@user,''); #without_suplying_a_username
+ push(@user,"$MySQLaccess::NEW_USER");
+ #push(@Warnings,'minimum_priv');
+ return \@user;
+}
+
+# ===========================================================
+# sub Get_All_hosts(template):
+# return all hosts the grant-tables are working on,
+# which conform to the template
+# ===========================================================
+sub Get_All_hosts {
+ my ($template,$tmp) = @_;
+ my @host=();
+ my $aref;
+ my $aref1;
+
+ # working with temporary tables or production tables
+ if (defined($tmp) and $tmp) {
+ $aref = \@MySQLaccess::Grant::sorted_host_tmp_table ;
+ $aref1= \@MySQLaccess::Grant::sorted_db_tmp_table ;
+ }
+ else {
+ $aref = \@MySQLaccess::Grant::sorted_host_table;
+ $aref1= \@MySQLaccess::Grant::sorted_db_table ;
+ }
+
+ MySQLaccess::Debug::Print(1, "Debug Get_All_hosts:");
+ # get all db for which access-rights can be calculated.
+ # !! these db's don't have to exist yet, so it's not
+ # enough to look which db already exist on the system
+ $reg_expr = $template;
+ if ($template =~ /[\*\?]/) {
+ $reg_expr =~ tr/*?/%_/;
+ #$reg_expr = MySQLaccess::Wildcards::Wild2Reg($template);
+ }
+ $reg_expr = MySQLaccess::Wildcards::SQL2Reg("$reg_expr");
+
+ if ( ! ($template =~ /[\*\?%_]/) ) {
+ push(@host,$template);
+ return \@host;
+ }
+
+ MySQLaccess::Debug::Print(1, "#Reading db-table...");
+ foreach $record (@{$aref1}) { #MySQLaccess::Grant::sorted_db_table) {
+ my @record=split(/\t/,$record);
+ my $host = $record[0];
+ MySQLaccess::Debug::Print(2, "> $host ");
+ if (! grep(/$host/i,@host)) {
+ push(@host,$host);
+ MySQLaccess::Debug::Print(2, "added");
+ }
+ else {
+ MySQLaccess::Debug::Print(2, "skipped");
+ }
+ }
+ MySQLaccess::Debug::Print(1, "#Reading host-table...");
+ foreach $record (@{$aref}) {
+ my @record=split(/\t/,$record);
+ my $host = $record[0];
+ MySQLaccess::Debug::Print(2, "> $host ");
+ if ( (!grep(/$host/,@host)) and ($host=~/$reg_expr/)) {
+ push(@host,$host);
+ MySQLaccess::Debug::Print(2, "added");
+ }
+ else {
+ MySQLaccess::Debug::Print(2, "skipped");
+ }
+ }
+ # DOUBT:
+ #print "#Reading user-table...\n" if ($DEBUG>1);
+ #foreach $record (@MySQLaccess::Grant::sorted_user_table) {
+ # my @record=split(/\t/,$record);
+ # my $host = $record[0];
+ # print "> $host " if ($DEBUG>2);
+ # if ( (!grep(/$host/,@host)) and ($host=~/$reg_expr/)) {
+ # push(@host,$host);
+ # print "added\n" if ($DEBUG>2);
+ # }
+ # else {
+ # print "skipped\n" if ($DEBUG>2);
+ # }
+ #}
+ # Any host also means:
+ # - any host still to be defined/created
+ #push(@host,"any_other_host");
+
+ @host = sort(@host);
+ return \@host;
+}
+
+
+##########################################################################
+package MySQLaccess::Grant;
+##############
+BEGIN {
+ $DEBUG = 0;
+ $DEBUG = $MySQLaccess::DEBUG unless ($DEBUG);
+}
+
+
+
+# ===========================================================
+# sub Diff_Privileges()
+# Calculate diff between temporary and original grant-tables
+# ===========================================================
+sub Diff_Privileges {
+ my @before=();
+ my @after =();
+ my @diffs =();
+
+ # -----------------------------
+ # Build list of users,dbs,hosts
+ # to process...
+ my @all_dbs = @{MySQLaccess::DB::Get_All_dbs('*')};
+ my @all_users = @{MySQLaccess::DB::Get_All_users('*')};
+ my @all_hosts = @{MySQLaccess::DB::Get_All_hosts('*')};
+ #if EDIT-mode
+ my @all_dbs_tmp = @{MySQLaccess::DB::Get_All_dbs('*','tmp')};
+ my @all_users_tmp = @{MySQLaccess::DB::Get_All_users('*','tmp')};
+ my @all_hosts_tmp = @{MySQLaccess::DB::Get_All_hosts('*','tmp')};
+
+
+ my %Access;
+ # ------------------------------------
+ # Build list of priv. for grant-tables
+ foreach $host (@all_hosts) {
+ foreach $user (@all_users) {
+ foreach $db (@all_dbs) {
+ MySQLaccess::Grant::Initialize();
+ %Access = MySQLaccess::Grant::Get_Access_Rights($host,$user,$db);
+ push(@before,MySQLaccess::Report::Raw_Report($host,$user,$db,\%Access));
+ }
+ }
+ }
+
+ # ----------------------------------
+ # Build list of priv. for tmp-tables
+ foreach $host (@all_hosts_tmp) {
+ foreach $user (@all_users_tmp) {
+ foreach $db (@all_dbs_tmp) {
+ MySQLaccess::Grant::Initialize('tmp');
+ %Access = MySQLaccess::Grant::Get_Access_Rights($host,$user,$db,'tmp');
+ push(@after,MySQLaccess::Report::Raw_Report($host,$user,$db,\%Access));
+ }
+ }
+ }
+
+ # ----------------------------------
+ # Write results to temp-file to make
+ # DIFF
+ @before = sort(@before);
+ @after = sort(@after);
+
+ $before = "$MySQLaccess::TMP_PATH/$MySQLaccess::script.before.$$";
+ $after = "$MySQLaccess::TMP_PATH/$MySQLaccess::script.after.$$";
+ #$after = "/tmp/t0";
+ open(BEFORE,"> $before") ||
+ push(@MySQLaccess::Report::Errors,"Can't open temporary file $before for writing");
+ open(AFTER,"> $after") ||
+ push(@MySQLaccess::Report::Errors,"Can't open temporary file $after for writing");
+ print BEFORE join("\n",@before);
+ print AFTER join("\n",@after);
+ close(BEFORE);
+ close(AFTER);
+
+ # ----------------------------------
+ # compute difference
+ my $cmd="$MySQLaccess::DIFF $before $after |";
+ open(DIFF,"$cmd");
+ @diffs = <DIFF>;
+ @diffs = grep(/[<>]/,@diffs);
+ chomp(@diffs);
+ close(DIFF);
+
+ # ----------------------------------
+ # cleanup temp. files
+ unlink(BEFORE);
+ unlink(AFTER);
+
+ return \@diffs;
+}
+
+# ===========================================================
+# sub Initialize()
+#
+# ===========================================================
+sub Initialize {
+ %MySQLaccess::Grant::Access = %{Default_Access_Rights()};
+ @MySQLaccess::Grant::Errors = ();
+ @MySQLaccess::Grant::Warnings = ();
+ @MySQLaccess::Grant::Notes = ();
+ # -----
+ # rules
+ $MySQLaccess::Grant::Rules{'user'} = 'no_rule_found';
+ $MySQLaccess::Grant::Rules{'db'} = 'no_rule_found';
+ $MySQLaccess::Grant::Rules{'host'} = 'no_equiv_host';
+ $MySQLaccess::Grant::full_access = 1;
+
+ $MySQLaccess::Grant::process_host_table = 0;
+ return 1;
+}
+
+# ===========================================================
+# sub ReadTables()
+#
+# ===========================================================
+sub ReadTables {
+ my ($tmp) = @_;
+ my ($HOST,$DB,$USER);
+ my @tables;
+
+ # build list of available tables
+ @tables = MySQLaccess::DB::Show_Tables();
+
+ # reading production grant-tables or temporary tables?
+ $tmp = (defined($tmp) and $tmp) ? 1 : 0;
+ if ($tmp) { #reading temporary tables
+ $HOST=$MySQLaccess::ACCESS_H_TMP;
+ $DB =$MySQLaccess::ACCESS_D_TMP;
+ $USER=$MySQLaccess::ACCESS_U_TMP;
+
+ # ----------------------------
+ # do tables exist?
+ if (!grep(/$HOST/,@tables)) { MySQLaccess::DB::CreateTable($HOST); }
+ if (!grep(/$USER/,@tables)) { MySQLaccess::DB::CreateTable($USER); }
+ if (!grep(/$DB/,@tables)) { MySQLaccess::DB::CreateTable($DB); }
+
+ MySQLaccess::Debug::Print(1,"Finding fields in tmp-ACL files:");
+ # -----------------------------
+ # Get record-layout
+ my ($h1,$h2) = MySQLaccess::DB::Show_Fields($HOST);
+ my ($d1,$d2) = MySQLaccess::DB::Show_Fields($DB);
+ my ($u1,$u2) = MySQLaccess::DB::Show_Fields($USER);
+ %MySQLaccess::Grant::H_tmp = %{$h1}; @MySQLaccess::Grant::H_tmp = @{$h2};
+ %MySQLaccess::Grant::D_tmp = %{$d1}; @MySQLaccess::Grant::D_tmp = @{$d2};
+ %MySQLaccess::Grant::U_tmp = %{$u1}; @MySQLaccess::Grant::U_tmp = @{$u2};
+
+# @MySQLaccess::Grant::Privileges_tmp=@{Make_Privlist()};
+#
+ MySQLaccess::Debug::Print(1, "Reading sorted temp-tables:");
+ @MySQLaccess::Grant::sorted_db_tmp_table = MySQLaccess::DB::Sort_table($DB, 'ucase_host', 'user', 'db');
+ @MySQLaccess::Grant::sorted_host_tmp_table= MySQLaccess::DB::Sort_table($HOST, 'ucase_host', 'db');
+ @MySQLaccess::Grant::sorted_user_tmp_table= defined($MySQLaccess::Param{'password'}) ?
+ MySQLaccess::DB::Sort_table($USER, 'ucase_host', 'user', 'password'):
+ MySQLaccess::DB::Sort_table($USER, 'ucase_host', 'user');
+ }
+ else { #reading production grant-tables
+ $HOST=$MySQLaccess::ACCESS_H;
+ $DB =$MySQLaccess::ACCESS_D;
+ $USER=$MySQLaccess::ACCESS_U;
+
+ MySQLaccess::Debug::Print(1,"Finding fields in ACL files:");
+ # -----------------------------
+ # Get record-layout
+ my ($h1,$h2) = MySQLaccess::DB::Show_Fields($HOST);
+ my ($d1,$d2) = MySQLaccess::DB::Show_Fields($DB);
+ my ($u1,$u2) = MySQLaccess::DB::Show_Fields($USER);
+ %MySQLaccess::Grant::H = %{$h1}; @MySQLaccess::Grant::H = @{$h2};
+ %MySQLaccess::Grant::D = %{$d1}; @MySQLaccess::Grant::D = @{$d2};
+ %MySQLaccess::Grant::U = %{$u1}; @MySQLaccess::Grant::U = @{$u2};
+
+ @MySQLaccess::Grant::Privileges=@{Make_Privlist()};
+
+ MySQLaccess::Debug::Print(1, "Reading sorted tables:");
+ @MySQLaccess::Grant::sorted_db_table = MySQLaccess::DB::Sort_table($DB, 'ucase_host', 'user', 'db');
+ @MySQLaccess::Grant::sorted_host_table= MySQLaccess::DB::Sort_table($HOST, 'ucase_host', 'db');
+ @MySQLaccess::Grant::sorted_user_table= defined($MySQLaccess::Param{'password'}) ?
+ MySQLaccess::DB::Sort_table($USER, 'ucase_host', 'user', 'password'):
+ MySQLaccess::DB::Sort_table($USER, 'ucase_host', 'user');
+ }
+
+ return 0;
+}
+
+# ===========================================================
+# sub Get_Access_Rights(host,user,db)
+# report the access_rights for the tuple ($host,$user,$db).
+# ===========================================================
+sub Get_Access_Rights {
+ local ($host,$user,$db,$tmp) = @_;
+
+ my $aref_user;
+ my $aref_host;
+ my $aref_db;
+ # working with temporary tables or production tables
+ if (defined($tmp) and $tmp) {
+ $aref_user = \@MySQLaccess::Grant::sorted_user_tmp_table;
+ $aref_host = \@MySQLaccess::Grant::sorted_host_tmp_table;
+ $aref_db = \@MySQLaccess::Grant::sorted_db_tmp_table;
+ }
+ else {
+ $aref_user = \@MySQLaccess::Grant::sorted_user_table;
+ $aref_host = \@MySQLaccess::Grant::sorted_host_table;
+ $aref_db = \@MySQLaccess::Grant::sorted_db_table;
+ }
+
+
+ my ($refrecord,$refgrant);
+ my ($_host_,$_user_,$encpw_);
+ my %_Access_;
+
+ MySQLaccess::Debug::Print(1, "for ($host,$user,$db):");
+
+ # ******************************************************************************
+ # Create default access-rights
+ # default access-rights are no access at all!!
+
+
+ # ******************************************************************************
+ # get hostname for IP-address
+ # get IP-address for hostname
+ local $host_name = MySQLaccess::Host::IP2Name($host);
+ local $host_ip = MySQLaccess::Host::Name2IP($host);
+
+ MySQLaccess::Debug::Print(3,"host=$host, hostname=$host_name, host-ip =$host_ip");
+ MySQLaccess::Debug::Print(3,"user=$user");
+ MySQLaccess::Debug::Print(3,"db =$db");
+
+ # ***********************************************************************
+ # retrieve information on USER
+ # check all records in mysql::user for matches with the tuple (host,user)
+ # ***********************************************************************
+ # 4.OR (add) the privileges for the user from the "user" table.
+ # (add all privileges which is "Y" in "user")
+ ($refrecord,$refgrant) = Get_grant_from_user($host,$user,$aref_user);
+ ($_host_,$_user_,$encpw_) = @{$refrecord};
+ %_access_ = %{$refgrant};
+
+ foreach $field (keys(%U)) { ##only priv. set in user-table
+ $MySQLaccess::Grant::Access{$field} = ($MySQLaccess::Grant::Access{$field} or $_access_{$field});
+ }
+
+ if ($_user_ eq $MySQLaccess::NEW_USER) {
+ push(@Warnings,'minimum_priv');
+ }
+ if ($_user_ ne $user) {
+ $user=$_user_;
+ push(@Warnings,'anonymous_access');
+ }
+
+ # *******************************************************
+ # Validate password if this has been asked to do
+ # *******************************************************
+ if (defined($password)) {
+ $valid = Validate_Password($password,$_host_,$_user_,$_encpw_,$aref_user);
+ if (!$valid) { push(@Errors,'invalid_password'); }
+ else { push(@Notes,'valid_password'); }
+ }
+
+ # ******************************************************************************
+ # retrieve information on DB
+ # check all records in mysql::db for matches with the triple (host,db,user)
+ # first match is used.
+ # ******************************************************************************
+ # 2.Get grant for user from the "db" table.
+
+ ($refrecord,$refgrant)=Get_grant_from_db($host,$db,$user,$aref_db); #set process_host_table
+ ($_host_,$_user_,$encpw_) = @{$refrecord};
+ %_access_ = %{$refgrant};
+
+ foreach $field (keys(%D)) { ##only priv. set in db-table
+ $MySQLaccess::Grant::Access{$field} = ($MySQLaccess::Grant::Access{$field} or $_access_{$field});
+ }
+
+ # ***********************************************************************
+ # retrieve information on HOST
+ # check all records in mysql::host for matches with the tuple (host,db)
+ #
+ # ' The host table is mainly to maintain a list of "secure" servers. '
+ # ***********************************************************************
+ # 3.If hostname is "empty" for the found entry, AND the privileges with
+ # the privileges for the host in "host" table.
+ # (Remove all which is not "Y" in both)
+
+ if ($MySQLaccess::Grant::process_host_table) {
+ ($refrecord,$refgrant)=Get_grant_from_host($host,$db,$aref_host);
+ ($_host_,$_user_,$encpw_) = @{$refrecord};
+ %_access_ = %{$refgrant};
+
+ foreach $field (keys(%H)) { ##only priv. set in host-table
+ $MySQLaccess::Grant::Access{$field} = ($MySQLaccess::Grant::Access{$field} and $_access_{$field});
+ }
+ }
+
+ MySQLaccess::Debug::Print(1,"done for ($host,$user,$db)");
+ return %MySQLaccess::Grant::Access;
+}
+
+# ####################################
+# FINDING THE RIGHT GRANT-RULE
+# ==========================================================
+# sub Get_grant_from_user:
+# ==========================================================
+sub Get_grant_from_user {
+ my ($host,$user,$aref) = @_;
+
+ MySQLaccess::Debug::Print(1, "");
+ MySQLaccess::Debug::Print(1, "(host=$host,user=$user)");
+
+ my %Access_user = %{Default_Access_Rights()};
+
+ my $rule_found=0;
+ my @record = ();
+ my $record;
+
+ foreach $record (@{$aref}) {
+ $MySQLaccess::Grant::full_access=0;
+ MySQLaccess::Debug::Print(3, "Record= $record");
+ @record=split(/\t/,$record);
+
+ # check host and db
+ # with possible wildcards in field
+ # replace mysql-wildcards by reg-wildcards
+ my $host_tpl = MySQLaccess::Wildcards::SQL2Reg($record[0]);
+ my $user_tpl = $record[1]; #user field isn't pattern-matched!!
+ my $passwd = $record[2];
+
+ MySQLaccess::Debug::Print(3, "=>host_tpl : read=$record[0] -> converted=$host_tpl");
+ MySQLaccess::Debug::Print(3, "=>user_tpl : read=$record[1] -> $user_tpl");
+ MySQLaccess::Debug::Print(3, "=>password : read=$record[2] -> $passwd");
+
+
+ if ( MySQLaccess::Host::MatchTemplate($host,$host_tpl) and
+ MySQLaccess::Wildcards::MatchTemplate($user_tpl,$user)
+ )
+ {
+ MySQLaccess::Debug::Print(2, "FOUND!!");
+ if ($passwd eq '') { push(@Warnings,'insecure_user'); }
+ else { push(@Notes,'password_required'); }
+
+ foreach $field (keys(%U)) {
+ $Access_user{$field} = $MySQLaccess::Report::Answer{$record[$U{$field}]};
+ }
+ #print "\n" if $DEBUG;
+ $MySQLaccess::Grant::Rules{'user'} = $record;
+ $rule_found=1;
+ last;
+ }
+ }
+
+ # -------------------------------
+ # setting privileges to user-priv
+ MySQLaccess::Debug::Print(2, "Rights after parsing user-table..:");
+ if (! $rule_found ) {
+ @record=();
+ MySQLaccess::Debug::Print(2, "NO record found in the user-table!!");
+ }
+ else {
+ MySQLaccess::Debug::Print(2, "Selected record=@record");
+ MySQLaccess::Debug::Print(2, "<=?=> $record");
+ }
+
+ MySQLaccess::Debug::Print(1, "returning @record");
+
+ return (\@record,\%Access_user); #matching record in user-table
+}
+
+# ==========================================================
+# sub Get_grant_from_db:
+# ==========================================================
+sub Get_grant_from_db {
+ my ($host,$db,$user,$aref) = @_;
+
+ MySQLaccess::Debug::Print(1, "(host=$host,user=$user,db=$db)");
+
+ my %Access_db = %{Default_Access_Rights()};
+ my $rule_found=0;
+
+ foreach $record (@{$aref}) {
+ $full_access=0;
+ MySQLaccess::Debug::Print(2, "Read db: $record");
+ @record=split(/\t/,$record);
+
+ # check host and db
+ # with possible wildcards in field
+ # replace mysql-wildcards by reg-wildcards
+ my $host_tpl = MySQLaccess::Wildcards::SQL2Reg($record[0]);
+ my $db_tpl = MySQLaccess::Wildcards::SQL2Reg($record[1]);
+ my $user_tpl = $record[2]; #user field isn't pattern matched!!
+ MySQLaccess::Debug::Print(3, "=>host_tpl : read=$record[0] -> converted=$host_tpl");
+ MySQLaccess::Debug::Print(3, "=>db_tpl : read=$record[1] -> $db_tpl");
+ MySQLaccess::Debug::Print(3, "=>user_tpl : read=$record[2] -> $user_tpl");
+
+ if ( ( MySQLaccess::Host::Is_localhost($host_tpl)
+ or MySQLaccess::Wildcards::MatchTemplate($host_tpl,$host_name)
+ or MySQLaccess::Wildcards::MatchTemplate($host_tpl,$host_ip) )
+ and ( MySQLaccess::Wildcards::MatchTemplate($db_tpl,$db) )
+ and ( MySQLaccess::Wildcards::MatchTemplate($user_tpl,$user) ) ) {
+
+ $MySQLaccess::Grant::process_host_table = ($record[0] eq '');
+
+ if ($user_tpl eq '') { push(@Warnings,'public_database'); }
+
+ foreach $field (keys(%D)) {
+ $Access_db{$field} = $MySQLaccess::Report::Answer{$record[$D{$field}]};
+ }
+ $rule_found=1;
+ $MySQLaccess::Grant::Rules{'db'} = $record;
+ last;
+ }
+ }
+
+ # -------------------------------
+ # setting privileges to db-priv
+ MySQLaccess::Debug::Print(2, "Rights after parsing db-table..:");
+ if (! $rule_found ) {
+ MySQLaccess::Debug::Print(2, "NO rule found in db-table => no access granted!!");
+ }
+
+ return (\@record,\%Access_db);
+}
+
+# ==========================================================
+# sub Get_grant_from_host:
+# ==========================================================
+sub Get_grant_from_host {
+ my ($host,$db,$aref) = @_;
+
+ MySQLaccess::Debug::Print(1, "Get_grant_from_host()");
+
+ my %Access_host = %{Default_Access_Rights()};
+
+ # the host-table doesn't have to be processed if the host-field
+ # in the db-table isn't empty
+ if (!$MySQLaccess::Grant::process_host_table) {
+ MySQLaccess::Debug::Print(2, ">> Host-table doesn't have to be processed!!");
+ $MySQLaccess::Grant::Rules{'host'} = 'no_equiv_host';
+ return ([],\%Access_host);
+ }
+
+ my $rule_found=0;
+ my @record = ();
+
+ foreach $record (@{$aref}) {
+ $full_access=0;
+ MySQLaccess::Debug::Print(2, "host: $record");
+ @record=split(/\t/,$record);
+
+ # check host and db
+ # with possible wildcards in field
+ # replace mysql-wildcards by reg-wildcards
+ my $host_tpl = MySQLaccess::Wildcards::SQL2Reg($record[0]);
+ my $db_tpl = MySQLaccess::Wildcards::SQL2Reg($record[1]);
+ MySQLaccess::Debug::Print(3, "=>host_tpl : $record[0] -> $host_tpl");
+ MySQLaccess::Debug::Print(3, "=>db_tpl : $record[1] -> $db_tpl");
+
+ if ( ( MySQLaccess::Host::Is_localhost($host_tpl)
+ or MySQLaccess::Wildcards::MatchTemplate($host_tpl,$host_name)
+ or MySQLaccess::Wildcards::MatchTemplate($host_tpl,$host_ip) )
+ and ( MySQLaccess::Wildcards::MatchTemplate($db_tpl,$db) ) ) {
+
+ $MySQLaccess::Grant::Rules{'host'} = $record;
+ $rule_found=1;
+ foreach $field (keys(%H)) {
+ $Access_host{$field} = $MySQLaccess::Report::Answer{$record[$H{$field}]};
+ }
+ last;
+ }
+ }
+
+ # -------------------------------
+ # setting privileges to host-priv
+ MySQLaccess::Debug::Print(2, "Rights after parsing host-table..:");
+ if (! $rule_found ) {
+ @record=();
+ MySQLaccess::Debug::Print(2, "NO restrictions found in the host-table!!");
+ }
+
+ # --------------------------------
+ # debugging access-rights in db
+
+ return (\@record,\%Access_host); #matching record in host-table
+}
+
+
+
+# ===========================================================
+# sub Default_Access_Rights():
+# return (a reference to) a hash which holds all default
+# priviliges currently defined in the grant-tables.
+# ===========================================================
+sub Default_Access_Rights {
+ my %right = ();
+
+ MySQLaccess::Debug::Print(2, "Debug Default_Access_Rights():");
+ # add entry for all fields in the HOST-table
+ foreach $field (keys(%MySQLaccess::Grant::H)) {
+ $right{$field}='0' unless (defined($right{$field}));
+ }
+ # add entry for all fields in the DB-table
+ foreach $field (keys(%MySQLaccess::Grant::D)) {
+ $right{$field}='0' unless (defined($right{$field}));
+ }
+ # add entry for all fields in the USER-table
+ foreach $field (keys(%MySQLaccess::Grant::U)) {
+ $right{$field}='0' unless (defined($right{$field}));
+ }
+ # --------------
+ # debugging info
+ foreach $field (keys(%right)) { MySQLaccess::Debug::Print(3, sprintf("> %15s : %1s",$field,$right{$field})); }
+
+ return \%right;
+}
+
+# ======================================
+# sub Make_Privlist
+# Make an ordered list of the privileges
+# that should be reported
+# ======================================
+sub Make_Privlist {
+ # layout:
+ #'select_priv', 'create_priv',
+ #'insert_priv', 'drop_priv',
+ #'update_priv', 'reload_priv',
+ #'delete_priv', 'process_priv',
+ #'file_priv', 'shutdown_priv');
+ my $right;
+ my @privlist=();
+ foreach $right (@U) {
+ if (! grep(/$right/,@privlist)) { push(@privlist,$right); }
+ };
+ foreach $right (@D) {
+ if (! grep(/$right/,@privlist)) { push(@privlist,$right); }
+ };
+ foreach $right (@H) {
+ if (! grep(/$right/,@privlist)) { push(@privlist,$right); }
+ };
+# print "Privileges:\n";
+# foreach $field (@privlist) { print " > $field\n"; }
+ return \@privlist;
+}
+
+
+
+########################################################################
+package MySQLaccess::Report;
+use Exporter ();
+@EXPORT = qw(&Print_Header());
+BEGIN {
+ $FORM = $ENV{'SCRIPT_NAME'};
+ $DEBUG = 0;
+ $DEBUG = $MySQLaccess::DEBUG unless ($DEBUG);
+
+ # translation-table for poss. answers
+ %Answer = ('Y' => 1 , 'N' => 0
+ , 1 => 'Y', 0 => 'N'
+ ,'?' => '?', '' => '?'
+ );
+ $headers = 0;
+ $separator = 0;
+
+# ****************************
+# Notes and warnings
+%MESSAGES = (
+ 'insecure_user'
+ => "Everybody can access your DB as user `\$user' from host `\$host'\n"
+ ."WITHOUT supplying a password.\n"
+ ."Be very careful about it!!"
+ ,'password_required'
+ => "A password is required for user `\$user' :-("
+ ,'invalid_password'
+ => "The password '\$password' for user `\$user' is invalid :-P"
+ , 'valid_password'
+ => "You supplied the right password for user `\$user' :-)"
+ ,'public_database'
+ => "Any user with the appropriate permissions has access to your DB!\n"
+ ."Check your users!"
+ ,'full_access'
+ => "All grant-tables are empty, which gives full access to ALL users !!"
+ ,'no_rule_found'
+ => "No matching rule"
+ ,'no_equiv_host'
+ => "Not processed: host-field is not empty in db-table."
+ ,'least_priv'
+ => "If the final priveliges of the user are more then you gave the user,\n"
+ ."check the priveliges in the db-table `\$db'."
+ ,'minimum_priv'
+ => "The privileges for any new user are AT LEAST\n"
+ ."the ones shown in the table above,\n"
+ ."since these are the privileges of the db `\$db'.\n"
+ ,'not_found_mysql'
+ => "The MySQL client program <$MySQLaccess::MYSQL> could not be found.\n"
+ ."+ Check your path, or\n"
+ ."+ edit the source of this script to point \$MYSQL to the mysql client.\n"
+ ,'not_found_mysqldump'
+ => "The MySQL dump program <$MySQLaccess::MYSQLDUMP> could not be found.\n"
+ ."+ Check your path, or\n"
+ ."+ edit the source of this script to point \$MYSQLDUMP to the mysqldump program.\n"
+ ,'not_found_diff'
+ => "The diff program <$MySQLaccess::DIFF> could not be found.\n"
+ ."+ Check your path, or\n"
+ ."+ edit the source of this script to point \$DIFF to the diff program.\n"
+ ,'not_found_tmp'
+ => "The temporary directory <$MySQLaccess::TMP_PATH> could not be found.\n"
+ ."+ create this directory (writeable!), or\n"
+ ."+ edit the source of this script to point \$TMP_PATH to the right directory.\n"
+ ,'write_err_tmp'
+ => "The temporary directory <$MySQLaccess::TMP_PATH> is not writable.\n"
+ ."+ make this directory writeable!, or\n"
+ ."+ edit the source of this script to point \$TMP_PATH to another directory.\n"
+ ,'Unrecognized_option'
+ => "Sorry,\n"
+ ."You are using an old version of the mysql-program,\n"
+ ."which does not yet implement a neccessary option.\n"
+ ."\n"
+ ."You need at least Version 6.2 of the mysql-client,\n"
+ ."which was build in MySQL v3.0.18, to use this version\n"
+ ."of `$MySQLaccess::script'."
+ ,'Access_denied'
+ => "Sorry,\n"
+ ."An error occured when trying to connect to the database\n"
+ ."with the grant-tables:\n"
+ ."* Maybe YOU do not have READ-access to this database?\n"
+ ."* If you used the -U option, you may have supplied an invalid username?\n"
+ ." for the superuser?\n"
+ ."* If you used the -U option, it may be possible you have to supply\n"
+ ." a superuser-password to, with the -P option?\n"
+ ."* If you used the -P option, you may have supplied an invalid password?\n"
+ ,'Dbaccess_denied'
+ => "Sorry,\n"
+ ."An error occured when trying to connect to the database\n"
+ ."with the grant-tables. (dbaccess denied)\n"
+ ,'Unknown_tmp_table'
+ => "Sorry,\n"
+ ."An error occured when trying to work with the temporary tables in the database\n"
+ ."with the grant-tables. (One of the temporary tables does not exist)\n"
+ ,'Unknown_table'
+ => "Sorry,\n"
+ ."An error occured when trying to work with some tables in the database\n"
+ ."with the grant-tables. (table does not exist)\n"
+ ,'use_old_server'
+ => "Sorry,\n"
+ ."An error occured when executing an SQL statement.\n"
+ ."You might consider altering the use of the parameter `--old_server' when \n"
+ ."calling `$MySQLaccess::script'."
+ ,'unknown_error'
+ => "Sorry,\n"
+ ."An error occured when trying to connect to the database\n"
+ ."with the grant-tables. (unknown error)\n"
+ ,'anonymous_access'
+ => "Accessing the db as an anonymous user.\n"
+ ."Your username has no relevance\n"
+ ,'user_required'
+ => "You have to supply a userid."
+ ,'db_required'
+ => "You have to supply the name of a database."
+ ,'host_required'
+ => "You have to supply the name of a host."
+ );
+
+
+}
+# =====================================
+# sub Print_Header:
+# print header info
+# =====================================
+sub Print_Header {
+ if ($MySQLaccess::CMD) { #command-line mode
+ print "$MySQLaccess::script Version $MySQLaccess::VERSION\n"
+ ."By RUG-AIV, by Yves Carlier (Yves.Carlier\@rug.ac.be)\n"
+ ."Changes by Steve Harvey (sgh\@vex.net)\n"
+ ."This software comes with ABSOLUTELY NO WARRANTY.\n";
+ }
+ if ($MySQLaccess::CGI) { #CGI-BIN mode
+ print "content-type: text/html\n\n"
+ . "<HTML>\n"
+ ."<HEAD>\n"
+ ."<TITLE>MySQLaccess</TITLE>\n"
+ ."</HEAD>\n"
+ ."<BODY>\n"
+ ."<H1>$MySQLaccess::script Version $MySQLaccess::VERSION</H1>\n"
+ ."<CENTER>\n<ADDRESS>\n"
+ ."By RUG-AIV, by Yves Carlier (<a href=mailto:Yves.Carlier\@rug.ac.be>Yves.Carlier\@rug.ac.be</a>)<BR>\n"
+ ."Changes by Steve Harvey (<a href=mailto:sgh\@vex.net>sgh\@vex.net</a>)<BR>\n"
+ ."This software comes with ABSOLUTELY NO WARRANTY.<BR>\n"
+ ."</ADDRESS>\n</CENTER>\n"
+ ."<HR>\n";
+ Print_Taskbar();
+ print "<HR>\n";
+ }
+ return 1;
+}
+
+# =====================================
+# sub Print_Footer:
+# print footer info
+# =====================================
+sub Print_Footer {
+ if ($MySQLaccess::CMD) { #command-line mode
+ print "\n"
+ ."BUGs can be reported by email to Yves.Carlier\@rug.ac.be\n";
+ }
+ if ($MySQLaccess::CGI) { #CGI-BIN mode
+ if ($MySQLaccess::Param{'brief'}) {
+ print "</table>\n"; #close table in brief-output
+ }
+ print "<HR>\n"
+ ."<ADDRESS>\n"
+ ."BUGs can be reported by email to <a href=mailto:Yves.Carlier\@rug.ac.be>Yves.Carlier\@rug.ac.be</a><BR>\n"
+# ."Don't forget to mention the version $VERSION!<BR>\n"
+ ."</ADDRESS>\n"
+ ."</BODY>\n"
+ ."</HTML>\n";
+ }
+ return 1;
+}
+
+# =====================================
+# sub Print_Taskbar:
+# print taskbar on STDOUT
+# =====================================
+sub Print_Taskbar {
+ print "<CENTER>\n"
+ ."[<a href=$FORM?relnotes=on>Release&nbsp;Notes</a>] \n"
+ ."[<a href=$FORM?version=on>Version</a>] \n"
+ ."[<a href=$FORM?plan=on>Future&nbsp;Plans</a>] \n"
+ ."[<a href=$FORM?howto=on>Examples</a>] \n"
+ ."[<a href=$FORM?help=on>New check</a>] \n"
+ ."[<a href=$FORM?edit=on>Change/edit ACL</a>] \n"
+ ."</CENTER>\n";
+ return 1;
+}
+
+# =====================================
+# sub Print_Form:
+# print CGI-form
+# =====================================
+sub Print_Form {
+print <<EOForm;
+<center>
+<!-- Quering -->
+<FORM method=POST action=$FORM>
+
+<table border width="100%" >
+<tr>
+ <th>MySQL server</th>
+ <th>User information</th>
+ <th>Reports</th>
+ </tr>
+
+<tr>
+ <td valign=top>
+ <table>
+ <tr>
+ <td halign=right><b>Host</b><br><font size=-2>(Host on which MySQL-server resides.)</font></td>
+ <td valign=top><INPUT name=rhost type=text size=15 maxlength=15 value="$MySQLaccess::Param{'rhost'}"></td>
+ </tr>
+ <tr>
+ <td halign=right><b>Superuser</b><br><font size=-2>(User which has <font color="Red">read-access</font> to grant-tables.)</font></td>
+ <td valign=top><INPUT name=superuser type=text size=15 maxlength=15 value="$MySQLaccess::Param{'superuser'}"></td>
+ </tr>
+ <tr>
+ <td halign=right><b>Password</b><br><font size=-2>(of Superuser.)</font></td>
+ <td valign=top><INPUT name=spassword type=password size=15 maxlength=15 value="$MySQLaccess::Param{'spassword'}"></td>
+ </tr>
+ </table>
+ </td>
+
+ <td valign=top>
+ <table>
+ <tr>
+ <td halign=right><b><font color=Red>User</font></b><br><font size=-2>(Userid used to connect to MySQL-database.)</font></td>
+ <td halign=top><INPUT name=user type=text size=15 maxlength=15 value="$MySQLaccess::Param{'user'}"></td>
+ </tr>
+ <tr>
+ <td halign=right><b>Password</b><br><font size=-2>(Password user has to give to get access to MySQL-database.)</font></td>
+ <td valign=top><INPUT name=password type=password size=15 maxlength=15 value="$MySQLaccess::Param{'password'}"></td>
+ </tr>
+ <tr>
+ <td halign=right><b><font color=Red>Database</font></b><br><font size=-2>(Name of MySQL-database user tries to connect to.</font><br><font size=-2>Wildcards <font color="Green">(*,?,%,_)</font> are allowed.)</font></td>
+ <td valign=top><INPUT name=db type=text size=15 maxlength=15 value="$MySQLaccess::Param{'db'}"></td>
+ </tr>
+ <tr>
+ <td halign=right><b>Host</b><br><font size=-2>(Host from where the user is trying to connect to MySQL-database.</font><br><font size=-2>Wildcards <font color="Green">(*,?,%,_)</font> are allowed.)</font></td>
+ <td valign=top><INPUT name=host type=text size=15 maxlength=15 value="$MySQLaccess::Param{'host'}"></td>
+ </tr>
+ </table>
+ </td>
+
+ <td valign=center>
+ <table cellspacing=5 cellpadding=2 cols=1 height="100%">
+ <tr align=center>
+ <td halign=right><INPUT type=submit name=brief value="Brief"><br>
+ <INPUT type=submit name=table value="Tabular"></td>
+ </tr>
+ <tr align=center>
+ <td></td>
+ </tr>
+ <tr align=center>
+ <td halign=right><INPUT type=reset value="Clear"></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+
+</table>
+</form>
+
+
+</BODY>
+</HTML>
+EOForm
+ return 1;
+}
+
+# =====================================
+# sub Print_Usage:
+# print some information on STDOUT
+# =====================================
+sub Print_Usage {
+ Print_Error_Messages();
+ if ($MySQLaccess::CMD) { #command-line mode
+ Print_Options();
+ }
+ if ($MySQLaccess::CGI) { #CGI-BIN mode
+ Print_Form();
+ }
+ return 1;
+}
+
+# ======================================
+# sub Print_Version:
+# ======================================
+sub Print_Version {
+ if ($MySQLaccess::CMD) {
+ print $MySQLaccess::INFO;
+ }
+ if ($MySQLaccess::CGI) {
+ print "<PRE>\n";
+ print $MySQLaccess::INFO;
+ print "</PRE>\n";
+ }
+ return 1;
+}
+
+# ======================================
+# sub Print_Relnotes:
+# ======================================
+sub Print_Relnotes {
+ if ($MySQLaccess::CMD) {
+ print $MySQLaccess::RELEASE;
+ }
+ if ($MySQLaccess::CGI) {
+ print "<PRE>\n";
+ print $MySQLaccess::RELEASE;
+ print "</PRE>\n";
+ }
+ return 1;
+}
+
+# ======================================
+# sub Print_Plans:
+# ======================================
+sub Print_Plans {
+ if ($MySQLaccess::CMD) {
+ print $MySQLaccess::TODO;
+ }
+ if ($MySQLaccess::CGI) {
+ print "<PRE>\n";
+ print $MySQLaccess::TODO;
+ print "</PRE>\n";
+ }
+ return 1;
+}
+
+# ======================================
+# sub Print_HowTo:
+# ======================================
+sub Print_HowTo {
+ if ($MySQLaccess::CMD) {
+ print $MySQLaccess::HOWTO;
+ }
+ if ($MySQLaccess::CGI) {
+ print "<PRE>\n";
+ print $MySQLaccess::HOWTO;
+ print "</PRE>\n";
+ }
+ return 1;
+}
+
+# ======================================
+# sub Print_Options:
+# ======================================
+sub Print_Options {
+ if ($MySQLaccess::CGI) { print "<PRE>\n"; }
+ print $MySQLaccess::OPTIONS;
+ if ($MySQLaccess::CGI) { print "</PRE>\n"; }
+ return 1;
+}
+
+# ======================================
+# sub Print_Error_Access:
+# ======================================
+sub Print_Error_Access {
+ my ($error) = @_;
+ print "\n";
+ if ($MySQLaccess::CGI) { print "<font color=Red>\n<PRE>\n"; }
+ print $MESSAGES{$error};
+ if ($MySQLaccess::CGI) { print "</PRE>\n</font>\n"; }
+ print "\n";
+ return 1;
+}
+
+# ======================================
+# sub Print_Error_Messages:
+# ======================================
+sub Print_Error_Messages {
+# my ($error) = @_;
+ print "\n";
+ if ($MySQLaccess::CGI) { print "<font color=Red>\n<center>\n"; }
+ foreach $error (@MySQLaccess::Grant::Error) {
+ print $MESSAGES{$error};
+ print $MySQLaccess::CGI ? "<br>\n" : "\n";
+ }
+ if ($MySQLaccess::CGI) { print "</center>\n</font>\n"; }
+ print "\n";
+ return 1;
+}
+
+# ======================================
+# sub Print_Message:
+# ======================================
+sub Print_Message {
+ my ($aref) = @_;
+ my @messages = @{$aref};
+ print "\n";
+ if ($MySQLaccess::CGI) { print "<font color=DarkGreen>\n<center>\n"; }
+ foreach $msg (@messages) {
+ print $msg;
+ print $MySQLaccess::CGI ? "<br>\n" : "\n";
+ }
+ if ($MySQLaccess::CGI) { print "</center>\n</font>\n"; }
+ print "\n";
+ return 1;
+}
+
+# ======================================
+# sub Print_Edit:
+# ======================================
+sub Print_Edit {
+ print "\n";
+ if (!$MySQLaccess::CGI) {
+ print "Note: Editing the temporary tables is NOT supported in CMD-line mode!\n";
+ return 0;
+ }
+ print "<CENTER>\n"
+ ."<form action=$FORM method=GET>\n"
+ ."<table width=90% border>\n"
+ ."<tr>\n"
+ ." <td><input type=checkbox name=copy value=on> Copy grant-rules to temporary tables<br></td>\n"
+ ." <td rowspan=5 align=center valign=center><input type=submit value=Go></td>\n"
+ ."</tr>\n"
+ ."<tr>\n"
+ ." <td> Edit temporary tables with external application:<br>"
+ ." <a href=\"$MySQLaccess::MYSQLADMIN\">$MySQLaccess::MYSQLADMIN</a></td>\n"
+ ."</tr>\n"
+ ."<tr>\n"
+ ." <td><input type=checkbox name=preview value=on> Preview changes made in temporary tables</td>\n"
+ ."</tr>\n"
+ ."<tr>\n"
+ ." <td><input type=checkbox name=commit value=on> Make changes permanent</td>\n"
+ ."</tr>\n"
+ ."<tr>\n"
+ ." <td><input type=checkbox name=rollback value=on> Restore previous grand-rules</td>\n"
+ ."</tr>\n"
+ ."<tr>\n"
+ ." <td colspan=2 align=center><font size=-2 color=Red>You need write,delete and drop-privileges to perform the above actions</font></td>\n"
+ ."</tr>\n"
+ ."</table>\n"
+ ."</form>\n"
+ ."</CENTER>\n";
+
+ return 1;
+}
+
+
+# ======================================
+# sub Print_Access_rights:
+# print the access-rights on STDOUT
+# ======================================
+sub Print_Access_rights {
+ my ($host,$user,$db,$refhash) = @_;
+
+ if (defined($MySQLaccess::Param{'brief'})) {
+# if ($MySQLaccess::CGI) { print "<PRE>\n"; }
+ Matrix_Report($host,$user,$db,$refhash);
+# if ($MySQLaccess::CGI) { print "</PRE>\n"; }
+ }
+ else {
+ Tabular_Report($host,$user,$db,$refhash);
+ $MySQLaccess::Report::separator = $MySQLaccess::CGI ? "<hr>" : "-"x80;
+ }
+ return 1;
+}
+
+# ======================================
+# sub Print_Diff_ACL:
+# print the diff. in the grants before and after
+# ======================================
+sub Print_Diff_ACL {
+ my ($aref) = @_;
+ my @diffs = @{$aref};
+ my %block = ( '<' => 'Before',
+ '>' => 'After',
+ );
+ my %color = ( '<' => 'Green',
+ '>' => 'Red',
+ );
+ my $curblock = '';
+
+ # -----------------------------
+ # create column-headers
+ foreach $field (@MySQLaccess::Grant::Privileges) {
+ push(@headers,substr($field,0,4));
+ }
+
+ if ($MySQLaccess::CMD) {
+ print "\n";
+ print "Differences in access-rights BEFORE and AFTER changes in grant-tables\n";
+# print "---------------------------------------------------------------------\n";
+ my $line1="";
+ my $line2="";
+ $line1 .= sprintf("| %-30s|",'Host,User,DB');
+ $line2 .= sprintf("+-%-30s+",'-' x 30);
+ foreach $header (@headers) {
+ $line1 .= sprintf("%-4s|",$header);
+ $line2 .= sprintf("%s+",'----');
+ }
+ print "$line2\n";
+ print "$line1\n";
+ print "$line2\n";
+
+ $format = "format STDOUT = \n"
+ . "^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< " . " @|||" x 10 ."\n"
+ . '$host_user_db,@priv' . "\n"
+ . ".\n";
+#print $format;
+ eval $format;
+ }
+ if ($MySQLaccess::CGI) {
+ print "<table border width=100%>\n";
+ print "<tr>\n";
+ print "<th colspan=11>";
+ print "Differences in access-rights <font color=$color{'<'}>BEFORE</font> "
+ ."and <font color=$color{'>'}>AFTER</font> changes to grant-tables</font>\n";
+ print "</th>";
+ print "</tr>\n";
+ print "<tr>\n";
+ $line1 .= sprintf("<th>%-20s</th>",'Host, User, DB');
+ foreach $header (@headers) {
+ $line1 .= sprintf("<th>%-4s</th>",$header);
+ }
+ print "$line1</tr>\n";
+ }
+
+ foreach $line (@diffs) {
+ $type = substr($line,0,1);
+ $line = substr($line,1);
+ ($host,$user,$db,@priv) = split(/,/,$line);
+ if ($MySQLaccess::CMD) {
+ if ($type ne $curblock) {
+ $curblock = $type;
+ print $block{$curblock},":\n";
+ }
+ #print "$line\n";
+ write;
+ }
+ if ($MySQLaccess::CGI) {
+ if ($type ne $curblock) {
+ $curblock = $type;
+ print "<tr><td><b>$block{$curblock}<b></td></tr>\n";
+ }
+ $line1="<td><font color=$color{$type}>$host, $user, $db</font></td>";
+ foreach $field (@priv) {
+ $line1 .= sprintf("<td align=center><font color=$color{$type}>%-4s</font></td>",$field);
+ }
+ print "<tr>$line1</tr>\n";
+ }
+ }
+ print "\n";
+ if ($MySQLaccess::CMD) {
+ print "---------------------------------------------------------------------\n";
+ }
+ if ($MySQLaccess::CGI) {
+ print "</table><br>";
+ }
+
+
+ return 1;
+}
+
+# ======================================
+# sub Tabular_Report
+# Tabular report,
+# suitable for 1 triple (host,db,user)
+# ======================================
+sub Tabular_Report {
+ my ($host,$user,$db,$a) = @_;
+ my $column=2;
+
+ # -----------------------------
+ # separator
+ if ($MySQLaccess::Report::separator) { print "$MySQLaccess::Report::separator\n"; }
+
+ # -----------------------------
+ # print table of access-rights
+ my $rows = int(@MySQLaccess::Grant::Privileges/2); #round up
+ my @table=();
+ $j=0;
+ for $i (0 .. $rows-1) {
+ $table[$j]=$MySQLaccess::Grant::Privileges[$i];
+ $j = $j+2;
+ }
+ $j=1;
+ for $i ($rows .. $#MySQLaccess::Grant::Privileges) {
+ $table[$j]=$MySQLaccess::Grant::Privileges[$i];
+ $j = $j+2;
+ }
+ if ($MySQLaccess::CMD) {
+ print "\n";
+ print "Access-rights\n";
+ print "for USER '$user', from HOST '$host', to DB '$db'\n";
+ }
+ if ($MySQLaccess::CGI) {
+ print "<table border width=100%>\n";
+ print "<tr>\n";
+ }
+ if ($MySQLaccess::CGI) {
+ print "<th colspan=5>";
+ print "<font color=Red>Access-rights</font>\n";
+ print "for USER '<font color=Green>$user</font>', from HOST '<font color=Green>$host</font>', to DB '<font color=Green>$db</font>'\n";
+ print "</th>";
+ print "</tr>\n";
+ print "<tr>\n";
+ }
+ if ($MySQLaccess::CMD) {
+ print "\t+-----------------+---+\t+-----------------+---+";
+ }
+ foreach $field (@table) {
+ if ($MySQLaccess::CMD) {
+ if ($column==2) { print "\n\t"; $column=1;}
+ else { print "\t"; $column=2;}
+ printf "| %-15s | %s |",$field,$Answer{$a->{$field}};
+ }
+ if ($MySQLaccess::CGI) {
+ if ($column==2) { print "</tr>\n<tr>\n"; $column=1;}
+ else { print "<td width=10%></td>"; $column=2;}
+ printf " <td width=35%><b>%-15s</b></td><td width=10%>%s</td>\n",$field,$Answer{$a->{$field}};
+ }
+ }
+ print "\n";
+ if ($MySQLaccess::CMD) {
+ print "\t+-----------------+---+\t+-----------------+---+\n";
+ }
+ if ($MySQLaccess::CGI) {
+ print "</tr>\n</table><br>";
+ }
+
+ # ---------------
+ # print notes:
+ foreach $note (@MySQLaccess::Grant::Notes) {
+ my $message = $MESSAGES{$note};
+ $message =~ s/\$user/$user/g;
+ $message =~ s/\$db/$db/g;
+ $message =~ s/\$host/$host/g;
+ $message =~ s/\$password/$password/g;
+ $PREFIX='NOTE';
+ if ($MySQLaccess::CMD) {
+ my @lines = split(/\n/,$message);
+ foreach $line (@lines) {
+ print "$PREFIX:\t $line\n";
+ $PREFIX=' ';
+ }
+ }
+ if ($MySQLaccess::CGI) {
+ print "<b>$PREFIX:</b> $message<br>\n";
+ }
+ }
+
+ # ---------------
+ # print warnings:
+ foreach $warning (@MySQLaccess::Grant::Warnings) {
+ my $message = $MESSAGES{$warning};
+ $message =~ s/\$user/$user/g;
+ $message =~ s/\$db/$db/g;
+ $message =~ s/\$host/$host/g;
+ $message =~ s/\$password/$password/g;
+ $PREFIX='BEWARE';
+ if ($MySQLaccess::CMD) {
+ my @lines = split(/\n/,$message);
+ foreach $line (@lines) {
+ print "$PREFIX:\t $line\n";
+ $PREFIX=' ';
+ }
+ }
+ if ($MySQLaccess::CGI) {
+ print "<b>$PREFIX:</b> $message<br>\n";
+ }
+ }
+
+ # ---------------
+ # print errors:
+ foreach $error (@MySQLaccess::Grant::Errors) {
+ my $message = $MESSAGES{$error};
+ $message =~ s/\$user/$user/g;
+ $message =~ s/\$db/$db/g;
+ $message =~ s/\$host/$host/g;
+ $message =~ s/\$password/$password/g;
+ $PREFIX='ERROR';
+ if ($MySQLaccess::CMD) {
+ my @lines = split(/\n/,$message);
+ foreach $line (@lines) {
+ print "$PREFIX:\t $line\n";
+ $PREFIX=' ';
+ }
+ }
+ if ($MySQLaccess::CGI) {
+ print "<b>$PREFIX:</b> $message<br>\n";
+ }
+ }
+
+ # ---------------
+ # inform if there are no rules ==> full access for everyone.
+ if ($MySQLaccess::Grant::full_access) { print "$MESSAGES{'full_access'}\n"; }
+
+ # ---------------
+ # print the rules used
+ print "\n";
+ if ($MySQLaccess::CMD) {
+ print "The following rules are used:\n";
+ foreach $field (sort(keys(%MySQLaccess::Grant::Rules))) {
+ my $rule = (defined($MESSAGES{$MySQLaccess::Grant::Rules{$field}}) ? $MESSAGES{$MySQLaccess::Grant::Rules{$field}} : $MySQLaccess::Grant::Rules{$field});
+ $rule =~ s/\t/','/g;
+ printf " %-5s : '%s'\n",$field,$rule;
+ }
+ }
+ if ($MySQLaccess::CGI) {
+ print "<br>\n";
+ print "<table border width=100%>\n";
+ print "<tr><th colspan=2>The following rules are used:</th></tr>\n";
+ foreach $field (sort(keys(%MySQLaccess::Grant::Rules))) {
+ my $rule = (defined($MESSAGES{$MySQLaccess::Grant::Rules{$field}}) ? $MESSAGES{$MySQLaccess::Grant::Rules{$field}} : $MySQLaccess::Grant::Rules{$field});
+ $rule =~ s/\t/','/g;
+ printf "<tr><th>%-5s</th><td>'%s'</td></tr>\n",$field,$rule;
+ }
+ print "</table>\n";
+ }
+
+ return 1;
+}
+
+# ======================================
+# sub Matrix_Report:
+# single-line output foreach triple,
+# no notes,warnings,...
+# ======================================
+sub Matrix_Report {
+ my ($host,$user,$db,$a) = @_;
+ my @headers = ();
+
+ if (! $headers) {
+ # -----------------------------
+ # create column-headers
+ foreach $field (@MySQLaccess::Grant::Privileges) {
+ push(@headers,substr($field,0,4));
+ }
+
+ # -----------------------------
+ # print column-headers
+ print "\n";
+ if ($MySQLaccess::CMD) {
+ my $line1="";
+ my $line2="";
+ foreach $header (@headers) {
+ $line1 .= sprintf("%-4s ",$header);
+ $line2 .= sprintf("%s ",'----');
+ }
+ $line1 .= sprintf("| %-20s",'Host,User,DB');
+ $line2 .= sprintf("+ %-20s",'-' x 20);
+ print "$line1\n";
+ print "$line2\n";
+ }
+ if ($MySQLaccess::CGI) {
+ print "<table width=100% border>\n";
+ my $line1="<tr>";
+ foreach $header (@headers) {
+ $line1 .= sprintf("<th>%-4s</th>",$header);
+ }
+ $line1 .= sprintf("<th>%-20s</th>",'Host, User, DB');
+ print "$line1</tr>\n";
+ }
+
+ # ----------------------------
+ # column-headers should only be
+ # printed once.
+ $MySQLaccess::Report::headers=1;
+ }
+
+ # ------------------------
+ # print access-information
+ if ($MySQLaccess::CMD) {
+ foreach $field (@MySQLaccess::Grant::Privileges) {
+ printf " %-2s ",$Answer{$a->{$field}};
+ }
+ printf "| %-20s",join(',',$host,$user,$db);
+ print "\n";
+ }
+ if ($MySQLaccess::CGI) {
+ print "<tr>";
+ foreach $field (@MySQLaccess::Grant::Privileges) {
+ printf "<td align=center>%-2s</td>",$Answer{$a->{$field}};
+ }
+ printf "<td><b>%-20s</b></td>",join(', ',$host,$user,$db);
+ print "</tr>\n";
+ }
+
+ return 1;
+}
+
+
+# ======================================
+# sub Raw_Report:
+# single-line output foreach triple,
+# no notes,warnings,...
+# ======================================
+sub Raw_Report {
+ my ($host,$user,$db,$a) = @_;
+ my @headers = ();
+ my $string = "";
+
+ # ------------------------
+ # print access-information
+ $string = "$host,$user,$db,";
+ foreach $field (@MySQLaccess::Grant::Privileges) {
+ $string .= $Answer{$a->{$field}} . ",";
+ }
+ return $string;
+}
+
+
+#######################################################################
+package MySQLaccess::Wildcards;
+BEGIN {
+ $DEBUG = 0;
+ $DEBUG = $MySQLaccess::DEBUG unless ($DEBUG);
+}
+# ############################################
+# SQL, WILDCARDS and REGULAR EXPRESSIONS
+# ============================================
+# translage SQL-expressions to Reg-expressions
+# ============================================
+sub SQL2Reg {
+ my ($expr) = @_;
+ my $expr_o = $expr;
+ $expr =~ s/\./\\./g;
+ $expr =~ s/\\%/\002/g;
+ $expr =~ s/%/.*/g;
+ $expr =~ s/\002/%/g;
+ $expr =~ s/\\_/\002/g;
+ $expr =~ s/_/.+/g;
+ $expr =~ s/\002/_/g;
+ MySQLaccess::Debug::Print(2,"$expr_o --> $expr");
+ return $expr;
+}
+
+# translage WILDcards to Reg-expressions
+# ============================================
+sub Wild2Reg {
+ my ($expr) = @_;
+ my $expr_o = $expr;
+ $expr =~ s/\./\\./g;
+ $expr =~ s/\\\*/\002/g;
+ $expr =~ s/\*/.*/g;
+ $expr =~ s/\002/*/g;
+ $expr =~ s/\\\?/\002/g;
+ $expr =~ s/\?/.+/g;
+ $expr =~ s/\002/?/g;
+ MySQLaccess::Debug::Print(2,"$expr_o --> $expr");
+ return $expr;
+}
+
+# =============================================
+# match a given string with a template
+# =============================================
+sub MatchTemplate {
+ my ($tpl,$string) = @_;
+ my $match=0;
+ if ($string=~ /^$tpl$/ or $tpl eq '') { $match=1; }
+ else { $match=0;}
+ MySQLaccess::Debug::Print(2,"($tpl,$string) --> $match");
+ return $match;
+}
+
+#######################################################################
+package MySQLaccess::Host;
+BEGIN {
+ $localhost = undef;
+ $DEBUG = 2;
+ $DEBUG = $MySQLaccess::DEBUG unless ($DEBUG);
+}
+# ======================================
+# sub IP2Name
+# return the Name with the corr. IP-nmbr
+# (no aliases yet!!)
+# ======================================
+sub IP2Name {
+ my ($ip) = @_;
+ my $ip_o = $ip;
+ if ($ip !~ /([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)/o) {
+ MySQLaccess::Debug::Print(3,"'$ip' is not an ip-number, returning IP=$ip");
+ return $ip;
+ }
+ MySQLaccess::Debug::Print(4,"IP=$ip split up => $1.$2.$3.$4");
+ $ip = pack "C4",$1,$2,$3,$4;
+ MySQLaccess::Debug::Print(4,"IP packed -> >>$ip<<\n");
+ my ($name,$aliases,$addrtype,$length,@addrs) = gethostbyaddr($ip, AF_INET);
+ MySQLaccess::Debug::Print(3,"IP=$ip_o => hostname=$name");
+ MySQLaccess::Debug::Print(4,"aliases=$aliases");
+ MySQLaccess::Debug::Print(4,"addrtype=$addrtype - length=$length");
+ return ($name || $ip);
+ #return ($name || undef);
+}
+
+# ======================================
+# sub Name2IP
+# return the IP-number of the host
+# ======================================
+sub Name2IP {
+ my ($name) = @_;
+ if ($name =~ /[%_]/) {
+ MySQLaccess::Debug::Print(3,"'$name' contains SQL-wildcards, returning name=$name");
+ return $name;
+ }
+ my ($_name,$aliases,$addrtype,$length,@addrs) = gethostbyname($name);
+ my ($a,$b,$c,$d) = unpack('C4',$addrs[0]);
+ my $ip = "$a.$b.$c.$d";
+ MySQLaccess::Debug::Print(3,"hostname=$name => IP=$ip");
+ MySQLaccess::Debug::Print(4,"aliases=$aliases");
+ MySQLaccess::Debug::Print(4,"addrtype=$addrtype - length=$length");
+ #if ($ip ne "") { return "$ip"; }
+ #else { return undef; }
+ return ($ip || $name);
+}
+
+# ========================================
+# sub LocalHost
+# some special action has to be taken for
+# the localhost
+# ========================================
+sub LocalHost {
+ if (!defined($MySQLaccess::Host::localhost)) {
+ $MySQLaccess::Host::localhost = Sys::Hostname::hostname();
+ MySQLaccess::Debug::Print(3,"Setting package variable \$localhost=$MySQLaccess::Host::localhost");
+ }
+ my $host = $localhost;
+ MySQLaccess::Debug::Print(3,"localhost = $host");
+ return $host;
+}
+
+# ========================================
+# check if the given hostname (or ip)
+# corresponds with the localhost
+# ========================================
+sub Is_localhost {
+ my ($host_tpl) = @_;
+ my $isit = 0;
+ if (($MySQLaccess::host_name eq $localhost) or ($MySQLaccess::host_ip eq $local_ip)) {
+ MySQLaccess::Debug::Print(2,"Checking for localhost");
+ MySQLaccess::Debug::Print(3,"because ($MySQLaccess::host_name EQ $localhost) AND ($MySQLaccess::host_ip EQ $local_ip)");
+ $isit = ( 'localhost' =~ /$host_tpl/ ) ? 1 : 0;
+ MySQLaccess::Debug::Print(3," 'localhost' =?= $host_tpl -> $isit");
+ return $isit;
+ }
+ else {
+ MySQLaccess::Debug::Print(4,"Not checking for localhost");
+ MySQLaccess::Debug::Print(4,"because ($MySQLaccess::host_name != $localhost) AND ($MySQLaccess::host_ip != $local_ip)");
+ return 0;
+ }
+}
+
+
+# =========================================
+# check if host (IP or name) can be matched
+# on the template.
+# =========================================
+sub MatchTemplate {
+ my ($host,$tpl) = @_;
+ my $match = 0;
+
+ MySQLaccess::Debug::Print(1, "($host) =?= ($tpl)");
+
+ my $host_name = IP2Name($host);
+ my $host_ip = Name2IP($host);
+
+ MySQLaccess::Debug::Print(2, "name=$host_name ; ip=$host_ip");
+ $match = (MySQLaccess::Wildcards::MatchTemplate($tpl,$host_name) or
+ MySQLaccess::Wildcards::MatchTemplate($tpl,$host_ip));
+
+ MySQLaccess::Debug::Print(2, "($host_name,$host_ip) =?= ($tpl): $ncount");
+
+ return $match;
+}
+
+########################################################################
+package MySQLaccess::Debug;
+BEGIN {
+ my $dbg_file = "$MySQLaccess::script_log";
+ open(DEBUG,"> $dbg_file") or warn "Could not open outputfile $dbg_file for debugging-info\n";
+ select DEBUG;
+ $| = 1;
+ select STDOUT;
+}
+# =========================================
+# Print debugging information on STDERR
+# =========================================
+sub Print {
+ my ($level,$mesg) = @_;
+ my ($pack,$file,$line,$subname,$hasargs,$wantarray) = caller(1);
+ my ($PACK) = split('::',$subname);
+ my $DEBUG = ${$PACK."::DEBUG"} ? ${$PACK."::DEBUG"} : $MySQLaccess::DEBUG ;
+ my ($sec,$min,$hour) = localtime();
+ print DEBUG "[$hour:$min:$sec $subname] $mesg\n" if ($DEBUG>=$level);
+}
+
diff --git a/scripts/mysqlbug.sh b/scripts/mysqlbug.sh
new file mode 100755
index 00000000000..77744777c1c
--- /dev/null
+++ b/scripts/mysqlbug.sh
@@ -0,0 +1,380 @@
+#!/bin/sh
+# Create a bug report and mail it to the mysql mailing list
+# Based on glibc bug reporting script.
+
+echo "Finding system information for a MySQL bug report"
+
+VERSION="@VERSION@"
+COMPILATION_COMMENT="@COMPILATION_COMMENT@"
+BUGmysql="mysql@lists.mysql.com"
+# This is set by configure
+COMP_ENV_INFO="CC='@CC@' CFLAGS='@CFLAGS@' CXX='@CXX@' CXXFLAGS='@CXXFLAGS@' LDFLAGS='@LDFLAGS@'"
+CONFIGURE_LINE="@CONF_COMMAND@"
+
+LIBC_INFO=""
+for pat in /lib/libc.* /lib/libc-* /usr/lib/libc.* /usr/lib/libc-*
+do
+ TMP=`ls -l $pat 2>/dev/null`
+ if test $? = 0
+ then
+ LIBC_INFO="$LIBC_INFO
+$TMP"
+ fi
+done
+
+PATH=../client:$PATH:/bin:/usr/bin:/usr/local/bin
+export PATH
+
+BUGADDR=${1-$BUGmysql}
+ENVIRONMENT=`uname -a`
+
+: ${USER=${LOGNAME-`whoami`}}
+
+COMMAND=`echo $0|sed 's%.*/\([^/]*\)%\1%'`
+
+# Try to create a secure tmpfile
+umask 077
+TEMPDIR=/tmp/mysqlbug-$$
+mkdir $TEMPDIR || (echo "can not create directory in /tmp, aborting"; exit 1;)
+TEMP=${TEMPDIR}/mysqlbug
+
+trap 'rm -f $TEMP $TEMP.x; rmdir $TEMPDIR; exit 1' 1 2 3 13 15
+trap 'rm -f $TEMP $TEMP.x; rmdir $TEMPDIR' 0
+
+# How to read the passwd database.
+PASSWD="cat /etc/passwd"
+
+if test -f /usr/lib/sendmail
+then
+ MAIL_AGENT="/usr/lib/sendmail -oi -t"
+elif test -f /usr/sbin/sendmail
+then
+ MAIL_AGENT="/usr/sbin/sendmail -oi -t"
+else
+ MAIL_AGENT="rmail $BUGmysql"
+fi
+
+# Figure out how to echo a string without a trailing newline
+N=`echo 'hi there\c'`
+case "$N" in
+ *c) ECHON1='echo -n' ECHON2= ;;
+ *) ECHON1=echo ECHON2='\c' ;;
+esac
+
+# Find out the name of the originator of this PR.
+if test -n "$NAME"
+then
+ ORIGINATOR="$NAME"
+elif test -f $HOME/.fullname
+then
+ ORIGINATOR="`sed -e '1q' $HOME/.fullname`"
+else
+ # Must use temp file due to incompatibilities in quoting behavior
+ # and to protect shell metacharacters in the expansion of $LOGNAME
+ $PASSWD | grep "^$LOGNAME:" | awk -F: '{print $5}' | sed -e 's/,.*//' > $TEMP
+ ORIGINATOR="`cat $TEMP`"
+ rm -f $TEMP
+fi
+
+if test -n "$ORGANIZATION"
+then
+ if test -f "$ORGANIZATION"
+ then
+ ORGANIZATION="`cat $ORGANIZATION`"
+ fi
+else
+ if test -f $HOME/.organization
+ then
+ ORGANIZATION="`cat $HOME/.organization`"
+ elif test -f $HOME/.signature
+ then
+ ORGANIZATION=`sed -e "s/^/ /" $HOME/.signature; echo ">"`
+ fi
+fi
+
+PATH_DIRS=`echo $PATH | sed -e 's/^:/. /' -e 's/:$/ ./' -e 's/::/ . /g' -e 's/:/ /g' `
+
+which_1 ()
+{
+ for cmd
+ do
+ # Absolute path ?.
+ if expr "x$cmd" : "x/" > /dev/null
+ then
+ echo "$cmd"
+ exit 0
+ else
+ for d in $PATH_DIRS
+ do
+ file="$d/$cmd"
+ if test -x "$file" -a ! -d "$file"
+ then
+ echo "$file"
+ exit 0
+ fi
+ done
+ fi
+ done
+ exit 1
+}
+
+change_editor ()
+{
+ echo "You can change editor by setting the environment variable VISUAL."
+ echo "If your shell is a bourne shell (sh) do"
+ echo "VISUAL=your_editors_name; export VISUAL"
+ echo "If your shell is a C shell (csh) do"
+ echo "setenv VISUAL your_editors_name"
+}
+
+# If they don't have a preferred editor set, then use emacs
+if test -z "$VISUAL"
+then
+ if test -z "$EDITOR"
+ then
+ EDIT=emacs
+ else
+ EDIT="$EDITOR"
+ fi
+else
+ EDIT="$VISUAL"
+fi
+
+#which_1 $EDIT
+used_editor=`which_1 $EDIT`
+
+echo "test -x $used_editor"
+if test -x "$used_editor"
+then
+ echo "Using editor $used_editor";
+ change_editor
+ sleep 2
+else
+ echo "Could not find a text editor. (tried $EDIT)"
+ change_editor
+ exit 1
+fi
+
+# Find out some information.
+SYSTEM=`( test -f /bin/uname && /bin/uname -a ) || \
+ ( test -f /usr/bin/uname && /usr/bin/uname -a ) || echo ""`
+ARCH=`test -f /bin/arch && /bin/arch`
+MACHINE=`test -f /bin/machine && /bin/machine`
+FILE_PATHS=
+
+for cmd in perl make gmake gcc cc
+do
+ file=`which_1 $cmd`
+ if test $? = 0
+ then
+ if test $cmd = "gcc"
+ then
+ GCC_INFO=`$file -v 2>&1`
+ elif test $cmd = "perl"
+ then
+ PERL_INFO=`$file -v | grep -i version 2>&1`
+ fi
+ FILE_PATHS="$FILE_PATHS $file"
+ fi
+done
+
+admin=`which_1 mysqladmin`
+MYSQL_SERVER=
+if test -x "$admin"
+then
+ MYSQL_SERVER=`$admin version 2> /dev/null`
+ if test "$?" = "1"
+ then
+ MYSQL_SERVER=""
+ fi
+fi
+
+SUBJECT_C="[50 character or so descriptive subject here (for reference)]"
+ORGANIZATION_C='<organization of PR author (multiple lines)>'
+LICENCE_C='[none | licence | email support | extended email support ]'
+SYNOPSIS_C='<synopsis of the problem (one line)>'
+SEVERITY_C='<[ non-critical | serious | critical ] (one line)>'
+PRIORITY_C='<[ low | medium | high ] (one line)>'
+CLASS_C='<[ sw-bug | doc-bug | change-request | support ] (one line)>'
+RELEASE_C='<release number or tag (one line)>'
+ENVIRONMENT_C='<machine, os, target, libraries (multiple lines)>'
+DESCRIPTION_C='<precise description of the problem (multiple lines)>'
+HOW_TO_REPEAT_C='<code/input/activities to reproduce the problem (multiple lines)>'
+FIX_C='<how to correct or work around the problem, if known (multiple lines)>'
+
+
+cat > $TEMP <<EOF
+SEND-PR: -*- send-pr -*-
+SEND-PR: Lines starting with \`SEND-PR' will be removed automatically, as
+SEND-PR: will all comments (text enclosed in \`<' and \`>').
+SEND-PR:
+From: ${USER}
+To: ${BUGADDR}
+Subject: $SUBJECT_C
+
+>Description:
+ $DESCRIPTION_C
+>How-To-Repeat:
+ $HOW_TO_REPEAT_C
+>Fix:
+ $FIX_C
+
+>Submitter-Id: <submitter ID>
+>Originator: ${ORIGINATOR}
+>Organization:
+${ORGANIZATION- $ORGANIZATION_C}
+>MySQL support: $LICENCE_C
+>Synopsis: $SYNOPSIS_C
+>Severity: $SEVERITY_C
+>Priority: $PRIORITY_C
+>Category: mysql
+>Class: $CLASS_C
+>Release: mysql-${VERSION} ($COMPILATION_COMMENT)
+`test -n "$MYSQL_SERVER" && echo ">Server: $MYSQL_SERVER"`
+>Environment:
+ $ENVIRONMENT_C
+`test -n "$SYSTEM" && echo "System: $SYSTEM"`
+`test -n "$ARCH" && echo "Architecture: $ARCH"`
+`test -n "$MACHINE" && echo "Machine: $MACHINE"`
+`test -n "$FILE_PATHS" && echo "Some paths: $FILE_PATHS"`
+`test -n "$GCC_INFO" && echo "GCC: $GCC_INFO"`
+`test -n "$COMP_ENV_INFO" && echo "Compilation info: $COMP_ENV_INFO"`
+`test -n "$LIBC_INFO" && echo "LIBC: $LIBC_INFO"`
+`test -n "$CONFIGURE_LINE" && echo "Configure command: $CONFIGURE_LINE"`
+`test -n "$PERL_INFO" && echo "Perl: $PERL_INFO"`
+EOF
+
+chmod u+w $TEMP
+cp $TEMP $TEMP.x
+
+eval $EDIT $TEMP
+
+if cmp -s $TEMP $TEMP.x
+then
+ echo "File not changed, no bug report submitted."
+ cp $TEMP /tmp/failed-mysql-bugreport
+ echo "The raw bug report exists in /tmp/failed-mysql-bugreport"
+ echo "If you use this remember that the first lines of the report now is a lie.."
+ exit 1
+fi
+
+#
+# Check the enumeration fields
+
+# This is a "sed-subroutine" with one keyword parameter
+# (with workaround for Sun sed bug)
+#
+SED_CMD='
+/$PATTERN/{
+s|||
+s|<.*>||
+s|^[ ]*||
+s|[ ]*$||
+p
+q
+}'
+
+
+while :; do
+ CNT=0
+
+ #
+ # 1) Severity
+ #
+ PATTERN=">Severity:"
+ SEVERITY=`eval sed -n -e "\"$SED_CMD\"" $TEMP`
+ case "$SEVERITY" in
+ ""|non-critical|serious|critical) CNT=`expr $CNT + 1` ;;
+ *) echo "$COMMAND: \`$SEVERITY' is not a valid value for \`Severity'."
+ esac
+ #
+ # 2) Priority
+ #
+ PATTERN=">Priority:"
+ PRIORITY=`eval sed -n -e "\"$SED_CMD\"" $TEMP`
+ case "$PRIORITY" in
+ ""|low|medium|high) CNT=`expr $CNT + 1` ;;
+ *) echo "$COMMAND: \`$PRIORITY' is not a valid value for \`Priority'."
+ esac
+ #
+ # 3) Class
+ #
+ PATTERN=">Class:"
+ CLASS=`eval sed -n -e "\"$SED_CMD\"" $TEMP`
+ case "$CLASS" in
+ ""|sw-bug|doc-bug|change-request|support) CNT=`expr $CNT + 1` ;;
+ *) echo "$COMMAND: \`$CLASS' is not a valid value for \`Class'."
+ esac
+
+ #
+ # 4) Synopsis
+ #
+ VALUE=`grep "^>Synopsis:" $TEMP | sed 's/>Synopsis:[ ]*//'`
+ case "$VALUE" in
+ "$SYNOPSIS_C") echo "$COMMAND: \`$VALUE' is not a valid value for \`Synopsis'." ;;
+ *) CNT=`expr $CNT + 1`
+ esac
+
+ test $CNT -lt 4 &&
+ echo "Errors were found with the problem report."
+
+
+ # Check if subject of mail was changed, if not, use Synopsis field
+ #
+ subject=`grep "^Subject" $TEMP| sed 's/^Subject:[ ]*//'`
+ if [ X"$subject" = X"$SUBJECT_C" -o X"$subject" = X"$SYNOPSIS_C" ]; then
+ subject=`grep Synopsis $TEMP | sed 's/>Synopsis:[ ]*//'`
+ sed "s/^Subject:[ ]*.*/Subject: $subject/" $TEMP > $TEMP.tmp
+ mv -f $TEMP.tmp $TEMP
+ fi
+
+ while :; do
+ $ECHON1 "a)bort, e)dit or s)end? $ECHON2"
+ read input
+ case "$input" in
+ a*)
+ echo "$COMMAND: problem report saved in $HOME/dead.mysqlbug."
+ cat $TEMP >> $HOME/dead.mysqlbug
+ xs=1; exit
+ ;;
+ e*)
+ eval $EDIT $TEMP
+ continue 2
+ ;;
+ s*)
+ break 2
+ ;;
+ esac
+ done
+done
+#
+# Remove comments and send the problem report
+# (we have to use patterns, where the comment contains regex chars)
+#
+# /^>Originator:/s;$ORIGINATOR;;
+sed -e "
+/^SEND-PR:/d
+/^>Organization:/,/^>[A-Za-z-]*:/s;$ORGANIZATION_C;;
+/^>Confidential:/s;<.*>;;
+/^>Synopsis:/s;$SYNOPSIS_C;;
+/^>Severity:/s;<.*>;;
+/^>Priority:/s;<.*>;;
+/^>Class:/s;<.*>;;
+/^>Release:/,/^>[A-Za-z-]*:/s;$RELEASE_C;;
+/^>Environment:/,/^>[A-Za-z-]*:/s;$ENVIRONMENT_C;;
+/^>Description:/,/^>[A-Za-z-]*:/s;$DESCRIPTION_C;;
+/^>How-To-Repeat:/,/^>[A-Za-z-]*:/s;$HOW_TO_REPEAT_C;;
+/^>Fix:/,/^>[A-Za-z-]*:/s;$FIX_C;;
+" $TEMP > $TEMP.x
+
+if $MAIL_AGENT < $TEMP.x
+then
+ echo "$COMMAND: problem report sent"
+ xs=0; exit
+else
+ echo "$COMMAND: mysterious mail failure, report not sent."
+ echo "$COMMAND: problem report saved in $HOME/dead.mysqlbug."
+ cat $TEMP >> $HOME/dead.mysqlbug
+fi
+
+exit 0
diff --git a/scripts/mysqlhotcopy.sh b/scripts/mysqlhotcopy.sh
new file mode 100755
index 00000000000..85a92c6ea88
--- /dev/null
+++ b/scripts/mysqlhotcopy.sh
@@ -0,0 +1,591 @@
+#!@PERL@
+
+use strict;
+use Getopt::Long;
+use Data::Dumper;
+use File::Basename;
+use File::Path;
+use DBI;
+
+=head1 NAME
+
+mysqlhotcopy - fast on-line hot-backup utility for local MySQL databases
+
+=head1 SYNOPSIS
+
+ mysqlhotcopy db_name
+
+ mysqlhotcopy --suffix=_copy db_name_1 ... db_name_n
+
+ mysqlhotcopy db_name_1 ... db_name_n /path/to/new_directory
+
+WARNING: THIS IS VERY MUCH A FIRST-CUT ALPHA. Comments/patches welcome.
+
+=cut
+
+# Documentation continued at end of file
+
+my $VERSION = sprintf("%d.%02d", q$Revision$ =~ /(\d+)\.(\d+)/o);
+
+my $OPTIONS = <<"_OPTIONS";
+
+Usage: $0 db_name new_db_name
+
+ -?, --help display this helpscreen and exit
+ -u, --user=# user for database login if not current user
+ -p, --password=# password to use when connecting to server
+ -P, --port=# port to use when connecting to local server
+ -S, --socket=# socket to use when connecting to local server
+
+ --allowold don't abort if target already exists (rename it _old)
+ --keepold don't delete previous (now renamed) target when done
+ --noindices don't copy index files
+ --method=# method for copy (only "cp" currently supported)
+
+ -q, --quiet be silent except for errors
+ --debug enable debug
+ -n, --dryrun report actions without doing them
+
+ --regexp=# copy all databases with names matching regexp
+ --suffix=# suffix for names of copied databases
+ --checkpoint=# insert checkpoint entry into specified db.table
+ --flushlog flush logs once all tables are locked
+_OPTIONS
+
+sub usage {
+ die @_, $OPTIONS;
+}
+
+my %opt = (
+ user => getpwuid($>),
+ indices => 1, # for safety
+ allowold => 0, # for safety
+ keepold => 0,
+ method => "cp",
+ flushlog => 0,
+);
+Getopt::Long::Configure(qw(no_ignore_case)); # disambuguate -p and -P
+GetOptions( \%opt,
+ "help",
+ "user|u=s",
+ "password|p=s",
+ "port|P=s",
+ "socket|S=s",
+ "allowold!",
+ "keepold!",
+ "indices!",
+ "method=s",
+ "debug",
+ "quiet|q",
+ "mv!",
+ "regexp=s",
+ "suffix=s",
+ "checkpoint=s",
+ "flushlog",
+ "dryrun|n",
+) or usage("Invalid option");
+
+# @db_desc
+# ==========
+# a list of hash-refs containing:
+#
+# 'src' - name of the db to copy
+# 'target' - destination directory of the copy
+# 'tables' - array-ref to list of tables in the db
+# 'files' - array-ref to list of files to be copied
+#
+
+my @db_desc = ();
+my $tgt_name = undef;
+
+if ( $opt{regexp} || $opt{suffix} || @ARGV > 2 ) {
+ $tgt_name = pop @ARGV unless ( exists $opt{suffix} );
+ @db_desc = map { { 'src' => $_ } } @ARGV;
+}
+else {
+ usage("Database name to hotcopy not specified") unless ( @ARGV );
+
+ @db_desc = ( { 'src' => $ARGV[0] } );
+ if ( @ARGV == 2 ) {
+ $tgt_name = $ARGV[1];
+ }
+ else {
+ $opt{suffix} = "_copy";
+ }
+}
+
+my $mysqld_help;
+my %mysqld_vars;
+my $start_time = time;
+$0 = $1 if $0 =~ m:/([^/]+)$:;
+$opt{quiet} = 0 if $opt{debug};
+$opt{allowold} = 1 if $opt{keepold};
+
+# --- connect to the database ---
+my $dsn = ";host=localhost";
+$dsn .= ";port=$opt{port}" if $opt{port};
+$dsn .= ";mysql_socket=$opt{socket}" if $opt{socket};
+
+my $dbh = DBI->connect("dbi:mysql:$dsn", $opt{user}, $opt{password}, {
+ RaiseError => 1,
+ PrintError => 0,
+ AutoCommit => 1,
+});
+
+# --- check that checkpoint table exists if specified ---
+if ( $opt{checkpoint} ) {
+ eval { $dbh->do( qq{ select time_stamp, src, dest, msg
+ from $opt{checkpoint} where 1 != 1} );
+ };
+
+ die "Error accessing Checkpoint table ($opt{checkpoint}): $@"
+ if ( $@ );
+}
+
+# --- get variables from database ---
+my $sth_vars = $dbh->prepare("show variables");
+$sth_vars->execute;
+while ( my ($var,$value) = $sth_vars->fetchrow_array ) {
+ $mysqld_vars{ $var } = $value;
+}
+my $datadir = $mysqld_vars{datadir}
+ || die "datadir not in mysqld variables";
+$datadir =~ s:/$::;
+
+
+# --- get target path ---
+my $tgt_dirname;
+if ($tgt_name =~ m:^\w+$:) {
+ $tgt_dirname = "$datadir/$tgt_name";
+}
+elsif ($tgt_name =~ m:/: || $tgt_name eq '.') {
+ $tgt_dirname = $tgt_name;
+}
+elsif ( $opt{suffix} ) {
+ print "copy suffix $opt{suffix}\n" unless $opt{quiet};
+}
+else {
+ die "Target '$tgt_name' doesn't look like a database name or directory path.\n";
+}
+
+# --- resolve database names from regexp ---
+if ( defined $opt{regexp} ) {
+ my $sth_dbs = $dbh->prepare("show databases");
+ $sth_dbs->execute;
+ while ( my ($db_name) = $sth_dbs->fetchrow_array ) {
+ push @db_desc, { 'src' => $db_name } if ( $db_name =~ m/$opt{regexp}/o );
+ }
+}
+
+# --- get list of tables to hotcopy ---
+
+my $hc_locks = "";
+my $num_tables = 0;
+my $num_files = 0;
+
+foreach my $rdb ( @db_desc ) {
+ my $db = $rdb->{src};
+ eval { $dbh->do( "use $db" ); };
+ die "Database '$db' not accessible: $@" if ( $@ );
+ my @dbh_tables = $dbh->func( '_ListTables' );
+
+ my $db_dir = "$datadir/$db";
+ opendir(DBDIR, $db_dir )
+ or die "Cannot open dir '$db_dir': $!";
+
+ my @db_files = grep { /.+\.\w+$/ } readdir(DBDIR)
+ or warn "'$db' is an empty database\n";
+
+ closedir( DBDIR );
+
+ unless ($opt{indices}) {
+ @db_files = grep { not /\.(ISM|MYI)$/ } @db_files;
+ }
+
+ $rdb->{files} = [ @db_files ];
+ my @hc_tables = map { "$db.$_" } @dbh_tables;
+ $rdb->{tables} = [ @hc_tables ];
+
+ $hc_locks .= ", " if ( length $hc_locks && @hc_tables );
+ $hc_locks .= join ", ", map { "$_ READ" } @hc_tables;
+
+ $num_tables += scalar @hc_tables;
+ $num_files += scalar @{$rdb->{files}};
+}
+
+# --- resolve targets for copies ---
+
+my @targets = ();
+
+if (length $tgt_name ) {
+ # explicit destination directory specified
+
+ # GNU `cp -r` error message
+ die "copying multiple databases, but last argument ($tgt_name) is not a directory\n"
+ if ( @db_desc > 1 && !(-e $tgt_name && -d $tgt_name ) );
+
+ foreach my $rdb ( @db_desc ) {
+ $rdb->{target} = "$tgt_name/$rdb->{src}";
+ }
+}
+else {
+ die "Error: expected \$opt{suffix} to exist" unless ( exists $opt{suffix} );
+
+ foreach my $rdb ( @db_desc ) {
+ $rdb->{target} = "$datadir/$rdb->{src}$opt{suffix}";
+ }
+}
+
+print Dumper( \@db_desc ) if ( $opt{debug} );
+
+# --- bail out if all specified databases are empty ---
+
+die "No tables to hot-copy" unless ( length $hc_locks );
+
+# --- create target directories ---
+
+my @existing = ();
+foreach my $rdb ( @db_desc ) {
+ push @existing, $rdb->{target} if ( -d $rdb->{target} );
+}
+
+die "Can't hotcopy to '", join( "','", @existing ), "' because already exist and --allowold option not given.\n"
+ if ( @existing && !$opt{allowold} );
+
+retire_directory( @existing ) if ( @existing );
+
+foreach my $rdb ( @db_desc ) {
+ my $tgt_dirpath = $rdb->{target};
+ if ( $opt{dryrun} ) {
+ print "mkdir $tgt_dirpath, 0750\n";
+ }
+ else {
+ mkdir($tgt_dirpath, 0750)
+ or die "Can't create '$tgt_dirpath': $!\n";
+ }
+}
+
+##############################
+# --- PERFORM THE HOT-COPY ---
+#
+# Note that we try to keep the time between the LOCK and the UNLOCK
+# as short as possible, and only start when we know that we should
+# be able to complete without error.
+
+# read lock all the tables we'll be copying
+# in order to get a consistent snapshot of the database
+
+if ( $opt{checkpoint} ) {
+ # convert existing READ lock on checkpoint table into WRITE lock
+ unless ( $hc_locks =~ s/$opt{checkpoint}\s+READ/$opt{checkpoint} WRITE/ ) {
+ $hc_locks .= ", $opt{checkpoint} WRITE";
+ }
+}
+
+my $hc_started = time; # count from time lock is granted
+
+if ( $opt{dryrun} ) {
+ print "LOCK TABLES $hc_locks\n";
+ print "FLUSH TABLES\n";
+ print "FLUSH LOGS\n" if ( $opt{flushlog} );
+}
+else {
+ my $start = time;
+ $dbh->do("LOCK TABLES $hc_locks");
+ printf "Locked $num_tables tables in %d seconds.\n", time-$start unless $opt{quiet};
+ $hc_started = time; # count from time lock is granted
+
+ # flush tables to make on-disk copy uptodate
+ $start = time;
+ $dbh->do("FLUSH TABLES");
+ printf "Flushed tables in %d seconds.\n", time-$start unless $opt{quiet};
+ $dbh->do( "FLUSH LOGS" ) if ( $opt{flushlog} );
+}
+
+my @failed = ();
+
+foreach my $rdb ( @db_desc ) {
+ my @files = map { "$datadir/$rdb->{src}/$_" } @{$rdb->{files}};
+ next unless @files;
+ eval { copy_files($opt{method}, \@files, $rdb->{target} ); };
+
+ push @failed, "$rdb->{src} -> $rdb->{target} failed: $@"
+ if ( $@ );
+
+ if ( $opt{checkpoint} ) {
+ my $msg = ( $@ ) ? "Failed: $@" : "Succeeded";
+
+ eval {
+ $dbh->do( qq{ insert into $opt{checkpoint} (src, dest, msg)
+ VALUES ( '$rdb->{src}', '$rdb->{target}', '$msg' )
+ } );
+ };
+
+ if ( $@ ) {
+ warn "Failed to update checkpoint table: $@\n";
+ }
+ }
+}
+
+if ( $opt{dryrun} ) {
+ print "UNLOCK TABLES\n";
+ if ( @existing && !$opt{keepold} ) {
+ my @oldies = map { $_ . '_old' } @existing;
+ print "rm -rf @oldies\n"
+ }
+ $dbh->disconnect();
+ exit(0);
+}
+else {
+ $dbh->do("UNLOCK TABLES");
+}
+
+my $hc_dur = time - $hc_started;
+printf "Unlocked tables.\n" unless $opt{quiet};
+
+#
+# --- HOT-COPY COMPLETE ---
+###########################
+
+$dbh->disconnect;
+
+if ( @failed ) {
+ # hotcopy failed - cleanup
+ # delete any @targets
+ # rename _old copy back to original
+
+ print "Deleting @targets \n" if $opt{debug};
+ rmtree([@targets]);
+ if (@existing) {
+ print "Restoring @existing from back-up\n" if $opt{debug};
+ foreach my $dir ( @existing ) {
+ rename("${dir}_old", $dir )
+ or warn "Can't rename ${dir}_old to $dir: $!\n";
+ }
+ }
+
+ die join( "\n", @failed );
+}
+else {
+ # hotcopy worked
+ # delete _old unless $opt{keepold}
+
+ if ( @existing && !$opt{keepold} ) {
+ my @oldies = map { $_ . '_old' } @existing;
+ print "Deleting previous copy in @oldies\n" if $opt{debug};
+ rmtree([@oldies]);
+ }
+
+ printf "$0 copied %d tables (%d files) in %d second%s (%d seconds overall).\n",
+ $num_tables, $num_files,
+ $hc_dur, ($hc_dur==1)?"":"s", time - $start_time
+ unless $opt{quiet};
+}
+
+exit 0;
+
+
+# ---
+
+sub copy_files {
+ my ($method, $files, $target) = @_;
+ my @cmd;
+ print "Copying ".@$files." files...\n" unless $opt{quiet};
+ if ($method =~ /^s?cp\b/) { # cp or scp with optional flags
+ @cmd = ($method);
+ # add option to preserve mod time etc of copied files
+ # not critical, but nice to have
+ push @cmd, "-p" if $^O =~ m/^(solaris|linux)$/;
+ # add files to copy and the destination directory
+ push @cmd, @$files, $target;
+ }
+ else {
+ die "Can't use unsupported method '$method'\n";
+ }
+
+ if ( $opt{dryrun} ) {
+ print "@cmd\n";
+ next;
+ }
+
+ print "Executing '@cmd'\n" if $opt{debug};
+ my $cp_status = system @cmd;
+ if ($cp_status != 0) {
+ die "Error: @cmd failed ($cp_status) while copying files.\n";
+ }
+}
+
+sub retire_directory {
+ my ( @dir ) = @_;
+
+ foreach my $dir ( @dir ) {
+ my $tgt_oldpath = $dir . '_old';
+ if ( $opt{dryrun} ) {
+ print "rmtree $tgt_oldpath\n" if ( -d $tgt_oldpath );
+ print "rename $dir, $tgt_oldpath\n";
+ next;
+ }
+
+ if ( -d $tgt_oldpath ) {
+ print "Deleting previous 'old' hotcopy directory ('$tgt_oldpath')\n" unless $opt{quiet};
+ rmtree([$tgt_oldpath])
+ }
+ rename($dir, $tgt_oldpath)
+ or die "Can't rename $dir=>$tgt_oldpath: $!\n";
+ print "Existing hotcopy directory renamed to '$tgt_oldpath'\n" unless $opt{quiet};
+ }
+}
+
+__END__
+
+=head1 DESCRIPTION
+
+mysqlhotcopy is designed to make stable copies of live MySQL databases.
+
+Here "live" means that the database server is running and the database
+may be in active use. And "stable" means that the copy will not have
+any corruptions that could occur if the table files were simply copied
+without first being locked and flushed from within the server.
+
+=head1 OPTIONS
+
+=over 4
+
+=item --checkpoint checkpoint-table
+
+As each database is copied, an entry is written to the specified
+checkpoint-table. This has the happy side-effect of updating the
+MySQL update-log (if it is switched on) giving a good indication of
+where roll-forward should begin for backup+rollforward schemes.
+
+The name of the checkpoint table should be supplied in database.table format.
+The checkpoint-table must contain at least the following fields:
+
+=over 4
+
+ time_stamp timestamp not null
+ src varchar(32)
+ dest varchar(60)
+ msg varchar(255)
+
+=back
+
+=item --suffix suffix
+
+Each database is copied back into the originating datadir under
+a new name. The new name is the original name with the suffix
+appended.
+
+If only a single db_name is supplied and the --suffix flag is not
+supplied, then "--suffix=_copy" is assumed.
+
+=item --allowold
+
+Move any existing version of the destination to a backup directory for
+the duration of the copy. If the copy successfully completes, the backup
+directory is deleted - unless the --keepold flag is set. If the copy fails,
+the backup directory is restored.
+
+The backup directory name is the original name with "_old" appended.
+Any existing versions of the backup directory are deleted.
+
+=item --keepold
+
+Behaves as for the --allowold, with the additional feature
+of keeping the backup directory after the copy successfully completes.
+
+=item --flushlog
+
+Rotate the log files by executing "FLUSH LOGS" after all tables are
+locked, and before they are copied.
+
+=item --regexp pattern
+
+Copy all databases with names matching the pattern.
+
+=item -?, --help
+
+Display helpscreen and exit
+
+=item -u, --user=#
+
+user for database login if not current user
+
+=item -p, --password=#
+
+password to use when connecting to server
+
+=item -P, --port=#
+
+port to use when connecting to local server
+
+=item -S, --socket=#
+
+UNIX domain socket to use when connecting to local server
+
+=item --noindices
+
+don't copy index files
+
+=item --method=#
+
+method for copy (only "cp" currently supported)
+
+=item -q, --quiet
+
+be silent except for errors
+
+=item --debug
+
+Debug messages are displayed
+
+=item -n, --dryrun
+
+Display commands without actually doing them
+
+=back
+
+=head1 WARRANTY
+
+This software is free and comes without warranty of any kind. You
+should never trust backup software without studying the code yourself.
+Study the code inside this script and only rely on it if I<you> believe
+that it does the right thing for you.
+
+Patches adding bug fixes, documentation and new features are welcome.
+
+=head1 TO DO
+
+Allow a list of tables (or regex) to be given on the command line to
+enable a logically-related subset of the tables to be hot-copied
+rather than force the whole db to be copied in one go.
+
+Extend the above to allow multiple subsets of tables to be specified
+on the command line:
+
+ mysqlhotcopy db newdb t1 t2 /^foo_/ : t3 /^bar_/ : +
+
+where ":" delimits the subsets, the /^foo_/ indicates all tables
+with names begining with "foo_" and the "+" indicates all tables
+not copied by the previous subsets.
+
+Add option to lock each table in turn for people who don't need
+cross-table integrity.
+
+Add option to FLUSH STATUS just before UNLOCK TABLES.
+
+Add support for other copy methods (eg tar to single file?).
+
+Add support for forthcoming MySQL ``RAID'' table subdirectory layouts.
+
+Add option to only copy the first 65KB of index files. That simplifies
+recovery (recovery with no index file at all is complicated).
+
+=head1 AUTHOR
+
+Tim Bunce
+
+Martin Waite - added checkpoint, flushlog, regexp and dryrun options
+
+Ralph Corderoy - Added synonyms for commands
+=cut
diff --git a/scripts/safe_mysqld-watch.sh b/scripts/safe_mysqld-watch.sh
new file mode 100755
index 00000000000..0111a41969c
--- /dev/null
+++ b/scripts/safe_mysqld-watch.sh
@@ -0,0 +1,149 @@
+#!/bin/sh
+# Copyright Abandoned 1996 TCX DataKonsult AB & Monty Program KB & Detron HB
+# This file is public domain and comes with NO WARRANTY of any kind
+#
+# scripts to start the MySQL demon and restart it if it dies unexpectedly
+#
+# This should be executed in the MySQL base directory if you are using a
+# 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
+
+# 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 \
+ -x ./bin/mysqld
+then
+ MY_BASEDIR_VERSION=`pwd` # Where bin, share and data is
+ DATADIR=$MY_BASEDIR_VERSION/data # Where the databases are
+ ledir=$MY_BASEDIR_VERSION/bin # Where mysqld are
+# Check if this is a 'moved install directory'
+elif test -f ./var/mysql/db.frm -a -f ./share/mysql/english/errmsg.sys -a \
+ -x ./libexec/mysqld
+then
+ MY_BASEDIR_VERSION=`pwd` # Where libexec, share and var is
+ DATADIR=$MY_BASEDIR_VERSION/var # Where the databases are
+ ledir=$MY_BASEDIR_VERSION/libexec # Where mysqld are
+else
+ MY_BASEDIR_VERSION=/usr/local/mysql
+ DATADIR=/usr/local/mysql/var
+ ledir=/usr/local/mysql/libexec
+fi
+
+pidfile=$DATADIR/`/bin/hostname`.pid
+log=$DATADIR/`/bin/hostname`.log
+err=$DATADIR/`/bin/hostname`.err
+lockfile=$DATADIR/`/bin/hostname`.lock
+
+#
+# If there exists an old pid file, check if the demon is already running
+# Note: The switches to 'ps' may depend on your operating system
+
+if test -f $pidfile
+then
+ PID=`cat $pidfile`
+ if /bin/kill -0 $PID
+ then
+ if /bin/ps -p $PID | grep mysqld > /dev/null
+ then # The pid contains a mysqld process
+ echo "A mysqld process already exists"
+ echo "A mysqld process already exists at " `date` >> $log
+ exit 1;
+ fi
+ fi
+ rm -f $pidfile
+ if test -f $pidfile
+ then
+ echo "Fatal error: Can't remove the pid file: $pidfile"
+ echo "Fatal error: Can't remove the pid file: $pidfile at " `date` >> $log
+ echo "Please remove it manually and start $0 again"
+ echo "mysqld demon not started"
+ exit 1;
+ fi
+fi
+
+echo "Starting mysqld demon with databases from $DATADIR"
+
+#Default communication ports
+#MYSQL_TCP_PORT=3306
+if test -z "$MYSQL_UNIX_PORT"
+then
+ MYSQL_UNIX_PORT="/tmp/mysql.sock"
+ export MYSQL_UNIX_PORT
+fi
+#export MYSQL_TCP_PORT
+
+# Does this work on all systems?
+#if type ulimit | grep "shell builtin" > /dev/null
+#then
+# ulimit -n 256 > /dev/null 2>&1 # Fix for BSD and FreeBSD systems
+#fi
+
+echo "mysqld started on " `date` >> $log
+bin/zap -f $lockfile < /dev/null > /dev/null 2>&1
+rm -f $lockfile
+$MY_BASEDIR_VERSION/bin/watchdog_mysqld $lockfile $pidfile $MY_BASEDIR_VERSION/bin $DATADIR 3 10 >> $err 2>&1 &
+restart_pid=$!
+
+while true
+do
+ rm -f $MYSQL_UNIX_PORT $pidfile # Some extra safety
+ lockfile -1 -r10 $lockfile >/dev/null 2>&1
+ if test "$#" -eq 0
+ then
+ nohup $ledir/mysqld --basedir=$MY_BASEDIR_VERSION --datadir=$DATADIR \
+ --skip-locking >> $err 2>&1 &
+ else
+ nohup $ledir/mysqld --basedir=$MY_BASEDIR_VERSION --datadir=$DATADIR \
+ --skip-locking "$@" >> $err 2>&1 &
+ fi
+ pid=$!
+ rm -f $lockfile
+ wait $pid;
+
+ lockfile -1 -r10 $lockfile >/dev/null 2>&1
+ rm -f $lockfile
+ if test ! -f $pidfile # This is removed if normal shutdown
+ then
+ break;
+ fi
+ if true
+ then
+ # Test if one proces was hanging.
+ # This is only a fix for Linux (running as base 3 mysqld processes)
+ # but should work for the rest of the servers.
+ # The only thing is ps x => redhat 5 gives warnings when using ps -x.
+ # kill -9 is used or the proces won't react on the kill.
+ numofproces=`ps x | grep -v "grep" | grep -c $ledir/mysqld`
+ echo -e "\nNumber of processes running now: $numofproces" | tee -a $log
+ I=1
+ while test "$I" -le "$numofproces"
+ do
+ PROC=`ps x | grep $ledir/mysqld | grep -v "grep" | tail -1`
+ for T in $PROC
+ do
+ break
+ done
+ # echo "TEST $I - $T **"
+ if kill -9 $T
+ then
+ echo "mysqld proces hanging, pid $T - killed" | tee -a $log
+ else
+ break
+ fi
+ I=`expr $I + 1`
+ done
+ fi
+ echo "mysqld restarted" | tee -a $log
+ # Check all tables and repair any wrong tables.
+ $MY_BASEDIR_VERSION/bin/isamchk -sf $DATADIR/*/*.ISM >> $err 2>&1
+done
+if test $restart_pid -gt 0
+then
+ kill $restart_pid > /dev/null 2>&1
+ sleep 1;
+ kill -9 $restart_pid > /dev/null 2>&1
+fi
+
+echo -n "mysqld ended on " `date` >> $log
+echo "mysqld demon ended"
diff --git a/scripts/safe_mysqld.sh b/scripts/safe_mysqld.sh
new file mode 100755
index 00000000000..b2965bced90
--- /dev/null
+++ b/scripts/safe_mysqld.sh
@@ -0,0 +1,188 @@
+#!/bin/sh
+# Copyright Abandoned 1996 TCX DataKonsult AB & Monty Program KB & Detron HB
+# This file is public domain and comes with NO WARRANTY of any kind
+#
+# scripts to start the MySQL daemon and restart it if it dies unexpectedly
+#
+# This should be executed in the MySQL base directory if you are using a
+# 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
+
+trap '' 1 2 3 15 # we shouldn't let anyone kill us
+
+defaults=
+case "$1" in
+ --no-defaults|--defaults-file=*)
+ defaults="$1"; shift
+ ;;
+esac
+
+# Parse arguments to see if caller wants the pid_file somewhere else.
+parse_arguments() {
+ for arg; do
+ case $arg in
+ --datadir=*) DATADIR=`echo "$arg" | sed -e "s;--datadir=;;"` ;;
+ --pid-file=*) pid_file=`echo "$arg" | sed -e "s;--pid-file=;;"` ;;
+ --socket=*) MYSQL_UNIX_PORT=`echo "$arg" | sed -e "s;--socket=;;"` ;;
+ --log=*) log=`echo "$arg" | sed -e "s;--log=;;"` ;;
+ --err-log=*) err_log=`echo "$arg" | sed -e "s;--err-log=;;"` ;;
+ --basedir=*) MY_BASEDIR_VERSION=`echo "$arg" | sed -e "s;--basedir=;;"` ;;
+ --ledir=*) ledir=`echo "$arg" | sed -e "s;--ledir=;;"` ;;
+ --user=*) user=`echo "$arg" | sed -e "s;--user=;;"` ;;
+ esac
+ done
+}
+
+MY_PWD=`pwd`
+# Check if we are starting this relative (for the binary release)
+if test -d $MY_PWD/data/mysql -a -f ./share/mysql/english/errmsg.sys -a \
+ -x ./bin/mysqld
+then
+ MY_BASEDIR_VERSION=$MY_PWD # Where bin, share and data are
+ ledir=$MY_BASEDIR_VERSION/bin # Where mysqld is
+ DATADIR=$MY_BASEDIR_VERSION/data
+# Check if this is a 'moved install directory'
+elif test -f ./var/mysql/db.frm -a -f ./share/mysql/english/errmsg.sys -a \
+ -x ./libexec/mysqld
+then
+ MY_BASEDIR_VERSION=$MY_PWD # Where libexec, share and var are
+ ledir=$MY_BASEDIR_VERSION/libexec # Where mysqld is
+ DATADIR=$MY_BASEDIR_VERSION/var
+else
+ MY_BASEDIR_VERSION=@prefix@
+ DATADIR=@localstatedir@
+ ledir=@libexecdir@
+fi
+
+pid_file=$DATADIR/`/bin/hostname`.pid
+MYSQL_UNIX_PORT=@MYSQL_UNIX_ADDR@
+MYSQL_TCP_PORT=@MYSQL_TCP_PORT@
+log=$DATADIR/`/bin/hostname`.log
+err_log=$DATADIR/`/bin/hostname`.err
+user=@MYSQLD_USER@
+
+# Get first arguments from the my.cfg file, groups [mysqld] and [safe_mysqld]
+# and then merge with the command line arguments
+if test -x ./bin/my_print_defaults; then
+ print_defaults="./bin/my_print_defaults"
+elif test -x @bindir@/my_print_defaults; then
+ print_defaults="@bindir@/my_print_defaults"
+elif test -x @bindir@/mysql_print_defaults; then
+ print_defaults="@bindir@/mysql_print_defaults"
+else
+ print_defaults="my_print_defaults"
+fi
+parse_arguments `$print_defaults $defaults mysqld safe_mysqld`
+parse_arguments "$@"
+
+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".
+ exit 1;
+fi
+
+
+NOHUP_NICENESS=`nohup nice`
+if [ "x$NOHUP_NICENESS" = "x0" ] || ! nice --1 nice >/dev/null 2>&1 ; then
+ NOHUP_NICENESS="nohup"
+else
+ NOHUP_NICENESS="nice --$NOHUP_NICENESS nohup"
+fi
+
+
+export MYSQL_UNIX_PORT
+#export MYSQL_TCP_PORT
+touch $err_log; chown $user $err_log
+
+#
+# If there exists an old pid file, check if the daemon is already running
+# Note: The switches to 'ps' may depend on your operating system
+if test -f $pid_file
+then
+ PID=`cat $pid_file`
+ if @CHECK_PID@
+ then
+ if @FIND_PROC@
+ then # The pid contains a mysqld process
+ echo "A mysqld process already exists"
+ echo "A mysqld process already exists at " `date` >> $err_log
+ exit 1;
+ fi
+ fi
+ rm -f $pid_file
+ if test -f $pid_file
+ then
+ echo "Fatal error: Can't remove the pid file: $pid_file"
+ echo "Fatal error: Can't remove the pid file: $pid_file at " `date` >> $err_log
+ echo "Please remove it manually and start $0 again"
+ echo "mysqld daemon not started"
+ exit 1;
+ fi
+fi
+
+#
+# Uncomment the following lines if you want all tables to be automaticly
+# checked and repaired at start
+#
+# echo "Checking tables in $DATADIR"
+# $MY_BASEDIR_VERSION/bin/myisamchk --silent --force --fast --medium-check $DATADIR/*/*.MYI
+# $MY_BASEDIR_VERSION/bin/isamchk --silent --force $DATADIR/*/*.ISM
+
+echo "Starting mysqld daemon with databases from $DATADIR"
+
+# Does this work on all systems?
+#if type ulimit | grep "shell builtin" > /dev/null
+#then
+# ulimit -n 256 > /dev/null 2>&1 # Fix for BSD and FreeBSD systems
+#fi
+
+echo "`date +'%y%m%d %H:%M:%S mysqld started'`" >> $err_log
+while true
+do
+ rm -f $MYSQL_UNIX_PORT $pid_file # Some extra safety
+ if test "$#" -eq 0
+ then
+ (trap "" 1 ; exec $NOHUP_NICENESS $ledir/mysqld --basedir=$MY_BASEDIR_VERSION --datadir=$DATADIR --user=$user --pid-file=$pid_file @MYSQLD_DEFAULT_SWITCHES@ >> $err_log 2>&1 )
+ else
+ (trap "" ; exec $NOHUP_NICENESS $ledir/mysqld --basedir=$MY_BASEDIR_VERSION --datadir=$DATADIR --user=$user --pid-file=$pid_file @MYSQLD_DEFAULT_SWITCHES@ "$@" >> $err_log 2>&1 )
+ fi
+ if test ! -f $pid_file # This is removed if normal shutdown
+ then
+ break;
+ fi
+ if @IS_LINUX@
+ then
+ # Test if one process was hanging.
+ # This is only a fix for Linux (running as base 3 mysqld processes)
+ # but should work for the rest of the servers.
+ # The only thing is ps x => redhat 5 gives warnings when using ps -x.
+ # kill -9 is used or the process won't react on the kill.
+ numofproces=`ps xa | grep -v "grep" | grep -c $ledir/mysqld`
+ echo -e "\nNumber of processes running now: $numofproces" | tee -a $err_log
+ I=1
+ while test "$I" -le "$numofproces"
+ do
+ PROC=`ps xa | grep $ledir/mysqld | grep -v "grep" | tail -1`
+ for T in $PROC
+ do
+ break
+ done
+ # echo "TEST $I - $T **"
+ if kill -9 $T
+ then
+ echo "mysqld process hanging, pid $T - killed" | tee -a $err_log
+ else
+ break
+ fi
+ I=`expr $I + 1`
+ done
+ fi
+ echo "`date +'%y%m%d %H:%M:%S mysqld restarted'`" | tee -a $err_log
+done
+
+echo -e "`date +'%y%m%d %H:%M:%S mysqld ended\n'`" | tee -a $err_log
diff --git a/sql-bench/.cvsignore b/sql-bench/.cvsignore
new file mode 100644
index 00000000000..208e8ca321c
--- /dev/null
+++ b/sql-bench/.cvsignore
@@ -0,0 +1,18 @@
+Makefile
+Makefile.in
+bench-init.pl
+compare-results
+copy-db
+crash-me
+fix-perl-ref
+output
+run-all-tests
+server-cfg
+test-ATIS
+test-alter-table
+test-big-tables
+test-connect
+test-create
+test-insert
+test-select
+test-wisconsin
diff --git a/sql-bench/ChangeLog b/sql-bench/ChangeLog
new file mode 100644
index 00000000000..ca7fb34ce97
--- /dev/null
+++ b/sql-bench/ChangeLog
@@ -0,0 +1,16 @@
+2000-05-19 Michael Widenius <monty@tik.pp.sci.fi>
+
+* Added a lot of COUNT(DISTINCT ...) tests.
+
+1998-08-16 Michael Widenius <monty@monty.pp.sci.fi>
+
+* The insert test generates now a table with 300,000 rows.
+ The insert test table is now 3 columns instead of one to make it
+ 'a bit more realistic'.
+* New option --small to run a small version of some tests.
+* Added a lot of min(), max() and count() tests.
+* Changed some tests to make them harder on MySQL 3.22.5
+ (The new key optimization made the old test not completely fair against
+ other databases that doesn't do this)
+* Added new test categories (order_by_on_key, min_max, min_max_on_key)
+* Added
diff --git a/sql-bench/Data/ATIS/aircraft.txt b/sql-bench/Data/ATIS/aircraft.txt
new file mode 100644
index 00000000000..a8d91c391c4
--- /dev/null
+++ b/sql-bench/Data/ATIS/aircraft.txt
@@ -0,0 +1,135 @@
+'ATR','AEROSPATIALE/AERITALIA (ALL SERIES)',2,'TURBOPROP','NO',80.58,73.83,32446,49,10603,277,0,'YES'
+'SSC','AEROSPATIALE-BRITISH AEROSPACE (BAC) CONCORDE',4,'JET','NO',83.83,203.75,400000,128,25000,1400,3800,'YES'
+'CRV','AEROSPATIALE CARAVELLE (ALL SERIES)',2,'JET','NO',112.50,118.83,127870,140,29100,512,2150,'YES'
+'ND2','AEROSPATIALE N 262/FRAKES MOHAWK 298',2,'TURBOPROP','NO',71.83,63.25,23370,27,5810,240,500,'YES'
+'NDH','AEROSPATIALE SA 365 DAUPHIN 2',1,'HELICOPTER','NO',0.00,43.50,6615,14,0,196,423,'NO'
+'AGH','AGUSTA A 109 A',2,'HELICOPTER','NO',36.08,35.14,5402,6,0,165,351,'NO'
+'AB3','AIRBUS INDUSTRIE (ALL SERIES)',2,'JET','YES',147.08,175.91,313060,345,68000,576,2100,'YES'
+'AN2','ANTONOV AN22 FREIGHTER',4,'TURBOPROP','YES',211.29,189.62,551156,28,99280,375,3107,''
+'AN4','ANTONOV AN24',2,'TURBOPROP','NO',95.83,77.25,42997,50,8150,295,807,'NO'
+'AN6','ANTONOV AN26 FREIGHTER',2,'TURBOPROP','NO',95.79,77.20,49297,50,0,280,342,''
+'BEC','BEECHCRAFT (ALL SERIES)',2,'TURBOPROP','NO',0.00,0.00,0,0,0,0,0,'NO'
+'BEB','BEECHCRAFT BARON',2,'PROPELLER','NO',37.83,28.00,5120,6,1965,225,1085,'NO'
+'BEQ','BEECHCRAFT QUEEN AIR',2,'PROPELLER','NO',50.25,35.50,8800,11,3578,214,1185,'NO'
+'BEO','BEECHCRAFT TWIN BONANZA',2,'PROPELLER','NO',45.95,31.50,6300,5,2230,201,1110,'NO'
+'BE8','BEECHCRAFT 18/VOLPAR TURBO 18',2,'PROPELLER','NO',49.66,35.25,9900,15,4055,256,1515,'NO'
+'BE9','BEECHCRAFT C99 AIRLINER',2,'TURBOPROP','NO',45.66,44.50,10900,15,5123,280,1150,'NO'
+'BH2','BELL (ALL SERIES)',1,'HELICOPTER','NO',33.25,39.08,3200,4,860,140,341,'NO'
+'DHP','BOEING CANADA DHC-2 BEAVER',1,'PROPELLER','NO',48.00,30.25,5100,10,1800,143,733,''
+'DHB','BOEING CANADA DHC-2 TURBO BEAVER',1,'TURBOPROP','NO',48.00,35.25,5370,10,1800,157,750,'NO'
+'DHO','BOEING CANADA DHC-3 OTTER',1,'PROPELLER','NO',58.00,41.83,8000,10,2100,132,960,'NO'
+'DHT','BOEING CANADA DHC-6 TWIN OTTER',2,'TURBOPROP','NO',65.00,51.75,12500,20,4420,209,745,'NO'
+'DH7','BOEING CANADA DHC-7 DASH-7 PASSENGER',4,'TURBOPROP','NO',93.00,80.58,43000,50,15000,275,850,'YES'
+'DH8','BOEING CANADA DHC-8 DASH-8 (ALL SERIES)',2,'TURBOPROP','NO',84.00,75.00,0,32,0,300,691,''
+'707','BOEING 707 PASSENGER (ALL SERIES)',4,'JET','NO',130.83,145.08,258000,181,52000,615,6325,'YES'
+'70M','BOEING 707-320C MIXED CONFIGURATION',4,'JET','NO',145.75,152.91,336000,145,83447,615,5750,'YES'
+'727','BOEING 727 PASSENGER (ALL SERIES)',3,'JET','NO',108.00,133.16,170000,131,35900,622,3000,'YES'
+'72M','BOEING 727-100C/100QC MIXED CONFIGURATION',3,'JET','NO',108.00,133.16,160000,96,30500,600,0,'YES'
+'72S','BOEING 727-200 (ALL SERIES)',3,'JET','NO',108.00,153.16,191000,145,40670,622,2400,'YES'
+'737','BOEING 737 PASSENGER (ALL SERIES)',2,'JET','NO',93.00,94.00,111000,138,29093,577,1300,'YES'
+'73M','BOEING 737-200C/200QC MIXED CONFIGURATION',2,'JET','NO',93.00,100.16,125000,130,33561,573,1800,'YES'
+'73S','BOEING 737 PASSENGER (ALL 200/200C SERIES)',2,'JET','NO',93.00,100.16,120000,130,34050,577,2300,'YES'
+'733','BOEING 737-300',2,'JET','NO',94.75,105.58,135000,138,35500,550,2500,'YES'
+'74M','BOEING 747 MIXED CONFIGURATION (ALL SERIES)',4,'JET','YES',195.66,231.83,78500,238,165710,600,5500,'YES'
+'747','BOEING 747 PASSENGER (ALL SERIES)',4,'JET','YES',195.66,321.83,833000,452,134000,557,7500,'YES'
+'74L','BOEING 747SP',4,'JET','YES',195.66,184.75,700000,430,98000,564,6730,'YES'
+'757','BOEING 757-200 PASSENGER',2,'JET','NO',124.50,155.25,220000,224,38940,560,2440,'YES'
+'767','BOEING 767 (ALL SERIES)',2,'JET','YES',156.08,159.16,312000,290,69000,550,4500,'YES'
+'B11','BRITISH AEROSPACE (BAC) ONE-ELEVEN (ALL SERIES)',2,'JET','NO',88.50,93.50,78500,79,17600,550,1430,'YES'
+'VGP','BRITISH AEROSPACE (BAC-VICKERS) VANGUARD PASSENGER',4,'TURBOPROP','NO',118.00,122.87,146500,139,21500,405,2910,'YES'
+'VCV','BRITISH AEROSPACE (BAC-VICKERS) VISCOUNT (ALL SERIES)',4,'TURBOPROP','NO',93.70,85.66,72500,75,14500,352,1725,'YES'
+'HPH','BRITISH AEROSPACE (HANDLEY PAGE) HERALD',2,'TURBOPROP','NO',113.00,96.83,82000,74,12000,266,3150,'YES'
+'HPJ','BRITISH AEROSPACE (HANDLEY PAGE) JETSTREAM 1/200',2,'TURBOPROP','NO',52.00,47.08,12550,18,4100,250,1440,'YES'
+'DHH','BRITISH AEROSPACE (HAWKER SIDDELEY) HERON',4,'PROPELLER','NO',71.50,48.50,13500,17,2100,195,0,'NO'
+'TRD','BRITISH AEROSPACE (HAWKER SIDDELEY) TRIDENT (ALL SERIES)',3,'JET','NO',95.00,114.75,135500,103,24500,606,2700,'YES'
+'HS7','BRITISH AEROSPACE (HAWKER SIDDELEY) 748 PASSENGER',2,'TURBOPROP','NO',98.50,67.00,46500,56,11363,275,850,'YES'
+'J31','BRITISH AEROSPACE JETSTREAM 31',2,'TURBOPROP','NO',52.00,47.12,12566,18,0,282,1380,'YES'
+'141','BRITISH AEROSPACE 146-100',4,'JET','NO',86.41,85.83,74600,88,17277,460,1450,'YES'
+'142','BRITISH AEROSPACE 146-200 PASSENGER',4,'JET','NO',86.41,93.66,89500,100,21000,460,1450,'YES'
+'BNI','BRITTEN-NORMAN BN-2A/B ISLANDER/BN-2T TURBINE ISLANDER',2,'PROPELLER','NO',49.00,35.66,6300,10,2000,260,425,'NO'
+'BNT','BRITTEN-NORMAN BN-2A MK III TRISLANDER',3,'PROPELLER','NO',53.00,43.75,9350,18,4000,180,0,'NO'
+'CS2','CASA C-212/NUSANTARA NC-212 AVIOCAR',2,'TURBOPROP','NO',62.50,45.83,16427,28,6077,230,1400,'NO'
+'CNA','CESSNA (ALL SERIES)',1,'TURBOPROP','NO',0.00,0.00,0,0,0,0,0,'NO'
+'CN2','CESSNA STATIONAIR/TURBO STATIONAIR 6',1,'PROPELLER','NO',35.83,28.00,3600,7,1792,169,702,'NO'
+'CNT','CESSNA STATIONAIR 207/TURBO STATIONAIR 7/8',1,'PROPELLER','NO',35.83,31.75,3800,7,1729,185,581,'NO'
+'CN4','CESSNA 402/402 UTILILINER',2,'PROPELLER','NO',39.91,36.08,6300,8,2436,239,562,'NO'
+'CVR','CONVAIR (ALL SERIES)',2,'TURBOPROP','NO',105.33,79.16,54600,56,11200,350,1100,'YES'
+'CWC','CURTISS C-46 COMMANDO',2,'PROPELLER','NO',108.08,76.33,40000,60,12000,220,1600,'NO'
+'DAM','DASSAULT-BREGUET MERCURE',2,'JET','NO',100.25,114.25,120150,0,32850,574,1094,'YES'
+'DOS','DORNIER DO 28',2,'PROPELLER','NO',51.02,37.02,8852,15,3000,160,708,''
+'DO8','DORNIER 228 (ALL SERIES)',2,'TURBOPROP','NO',55.58,49.25,12570,19,6000,231,1065,'NO'
+'EMB','EMBRAER EMP-110 BANDEIRANTE',2,'TURBOPROP','NO',50.16,49.41,12500,19,5000,262,900,'NO'
+'EM2','EMBRAER EMP-120 BRASILIA',2,'TURBOPROP','NO',64.89,64.70,12295,30,0,288,628,'YES'
+'FK7','FAIRCHILD INDUSTRIES FH-227',2,'TURBOPROP','NO',95.16,83.08,43500,52,11500,294,1520,'YES'
+'SWM','FAIRCHILD (SWEARINGEN) METRO/MERLIN',2,'TURBOPROP','NO',46.25,59.33,12500,19,3950,294,2139,'YES'
+'F27','FOKKER F27 FRIENDSHIP/FAIRCHILD (ALL SERIES)',2,'TURBOPROP','NO',95.16,82.16,45000,56,13500,265,1450,'YES'
+'F28','FOKKER F28 FELLOWSHIP (ALL SERIES)',2,'JET','NO',82.25,96.16,73000,85,19623,523,1055,'YES'
+'CD2','GOVERNMENT AIRCRAFT FACTORIES N22B/N24A NOMAD',2,'TURBOPROP','NO',54.00,43.00,8500,16,3000,165,850,'NO'
+'GRA','GRUMMAN G-111 ALBATROSS G-111',2,'AMPHIBIAN','NO',96.66,61.25,31000,28,7965,160,1500,'NO'
+'GRG','GRUMMAN G-21 GOOSE',2,'AMPHIBIAN','NO',49.00,38.33,8000,10,2000,160,825,'NO'
+'GRM','GRUMMAN G-73 MALLARD',2,'AMPHIBIAN','NO',66.66,48.33,12750,10,1950,180,1245,'NO'
+'GRS','GULFSTREAM AEROSPACE (GRUMMAN) GULFSTREAM 1/1-C',2,'TURBOPROP','NO',78.33,63.75,36000,37,4300,345,2300,'YES'
+'IL4','ILYUSHIN IL14',2,'PROPELLER','NO',104.00,69.91,36380,24,4800,224,1250,'NO'
+'IL8','ILYUSHIN IL18',4,'TURBOPROP','NO',122.70,117.79,119000,125,30860,403,1860,'YES'
+'IL6','ILYUSHIN IL62/62M',4,'JET','NO',141.29,174.16,347224,186,50706,528,5716,'YES'
+'ILW','ILYUSHIN IL86',4,'JET','YES',157.68,197.54,454152,350,0,575,0,'YES'
+'LOM','LOCKHEED L188 ELECTRA MIXED CONFIGURATION',4,'TURBOPROP','NO',99.00,104.50,116000,0,0,390,2200,''
+'LOE','LOCKHEED L188 ELECTRA PASSENGER',4,'TURBOPROP','NO',99.00,104.54,116000,104,22000,405,2750,'YES'
+'L10','LOCKHEED L1011 (ALL SERIES)',3,'JET','YES',155.25,177.58,430000,400,95500,615,3450,'YES'
+'L15','LOCKHEED L1011-500 TRISTAR',3,'JET','YES',155.33,164.20,496000,330,115000,580,5998,'YES'
+'MR4','MARTIN 404',2,'PROPELLER','NO',93.25,74.58,44900,44,9500,255,900,'YES'
+'DC3','MCDONNELL DOUGLAS DC3/C47 DAKOTA PASSENGER',2,'PROPELLER','NO',95.00,64.50,25200,30,7380,207,1330,'NO'
+'DC4','MCDONNELL DOUGLAS DOUGLAS DC4/C-54 SKYMASTER PASSENGER',4,'PROPELLER','NO',117.50,93.91,73800,80,11440,230,2750,'NO'
+'DC6','MCDONNELL DOUGLAS DC6 (ALL SERIES)',4,'PROPELLER','NO',117.50,101.50,93200,80,12310,309,3070,'YES'
+'D8M','MCDONNELL DOUGLAS DC8 MIXED CONFIGURATION (ALL SEIRES)',4,'JET','NO',142.33,187.41,325000,259,66665,600,3700,'YES'
+'DC8','MCDONNELL DOUGLAS DC8 PASSENGER (ALL 20-50 SERIES)',4,'JET','NO',142.25,150.41,315000,176,34000,544,7010,'YES'
+'D8S','MCDONNELL DOUGLAS DC8 (ALL 60/70 SERIES)',4,'JET','NO',142.25,187.33,325000,259,66665,580,7150,'YES'
+'DC9','MCDONNELL DOUGLAS DC9 (ALL 10 & 20 SERIES)',2,'JET','NO',93.25,104.33,98000,90,20850,593,2200,'YES'
+'D95','MCDONNELL DOUGLAS DC9-50',2,'JET','NO',93.25,133.41,12200,139,32615,593,2550,'YES'
+'D10','MCDONNELL DOUGLAS DC10 (ALL SERIES)',3,'JET','YES',155.25,182.25,455000,380,98490,608,6350,'YES'
+'M80','MCDONNELL DOUGLAS (MD-80 SERIES)',2,'JET','NO',107.83,147.83,140000,172,0,579,3060,'YES'
+'MIH','MIL MI-8',2,'HELICOPTER','NO',50.20,108.85,26455,28,0,140,311,''
+'MU2','MITSUBISHI MU2/MARQUISE/SOLITARE',2,'TURBOPROP','NO',39.16,39.41,11575,8,0,347,1606,''
+'YS1','NAMC YS-11',2,'TURBOPROP','NO',105.00,86.25,51800,60,12550,292,1980,'YES'
+'PN6','PARTENAVIA P.68 VICTOR',2,'PROPELLER','NO',39.37,31.33,4387,7,0,185,1312,''
+'PL6','PILATUS PC-6 TURBO-PORTER',1,'TURBOPROP','NO',49.66,35.75,4850,0,0,151,644,''
+'PA6','PIPER AEROSTAR',2,'TURBOPROP','NO',34.16,54.75,5500,6,240,250,1400,'YES'
+'PAZ','PIPER APACHE/AZTEC',2,'PROPELLER','NO',37.33,31.16,5200,6,2151,206,1519,'NO'
+'PAC','PIPER CHEROKEE',1,'PROPELLER','NO',32.83,27.66,3400,7,1544,167,856,'NO'
+'PAH','PIPER NAVAJO/MOHAVE/CHIEFTAIN',2,'PROPELLER','NO',40.50,34.50,7000,8,0,254,1019,'NO'
+'PAS','PIPER SENECA',2,'PROPELLER','NO',38.91,28.50,4570,7,1747,219,1036,'NO'
+'PA1','PIPER T-1020/1040',2,'TURBOPROP','NO',41.08,36.66,9000,9,3800,250,900,'NO'
+'ACD','ROCKWELL COMMANDER (ALL SERIES)',2,'PROPELLER','NO',49.50,35.08,6750,7,2750,205,1220,'YES'
+'SF3','SAAB-FAIRCHILD 340',2,'TURBOPROP','NO',70.33,63.75,25020,34,0,300,920,'YES'
+'SA2','SAUNDERS ST-27',2,'TURBOPROP','NO',71.50,59.00,13500,23,0,230,0,'NO'
+'SHP','SHORTS SKYLINER',2,'TURBOPROP','NO',64.91,40.00,12500,19,4600,188,694,'YES'
+'SHS','SHORTS SKYVAN',2,'TURBOPROP','NO',64.91,40.08,12500,19,0,188,694,''
+'SH3','SHORTS 330 PASSENGER',2,'TURBOPROP','NO',74.66,58.00,22000,30,7500,218,1137,'NO'
+'SH6','SHORTS 360',2,'TURBOPROP','NO',74.83,70.83,26000,36,7500,244,1151,'NO'
+'S58','SIKORSKY S58T',1,'HELICOPTER','NO',56.00,47.25,13000,16,0,127,278,'NO'
+'S61','SIKORSKY S61',2,'HELICOPTER','NO',62.00,72.00,20500,30,5500,139,282,'NO'
+'TU3','TUPOLEV TU134',2,'JET','NO',95.16,112.71,98100,72,14300,546,1490,'YES'
+'TU5','TUPOLEV TU154',3,'JET','NO',123.20,157.14,198410,164,44090,605,3280,'YES'
+'WLH','WESTLAND 30',2,'HELICOPTER','NO',43.66,52.16,12350,21,0,0,100,''
+'YK4','YAKOVLEV YAK-40',3,'JET','NO',82.08,66.75,35270,40,5070,342,1240,'YES'
+'YK2','YAKOVLEV YAK-42',3,'JET','NO',112.20,119.35,114640,120,2000,510,621,'YES'
+'100','FOKKER 100',0,'JET','',0.00,0.00,0,0,0,0,0,''
+'146','BRITISH AEROSPACE 146 (ALL SERIES)',0,'JET','',0.00,0.00,0,0,0,0,0,''
+'310','AIRBUS INDUSTRIE A310 (ALL SERIES)',0,'JET','',0.00,0.00,0,0,0,0,0,''
+'320','AIRBUS INDUSTRIE A320 (ALL SERIES)',0,'JET','',0.00,0.00,0,0,0,0,0,''
+'734','BOEING 737-400',0,'JET','',0.00,0.00,0,0,0,0,0,''
+'743','BOEING 737-300 PASSENGER',0,'JET','',0.00,0.00,0,0,0,0,0,''
+'744','BOEING 747-400 PASSENGER',0,'JET','',0.00,0.00,0,0,0,0,0,''
+'74E','BOEING 747-400 MIXED CONFIGURATION',0,'JET','',0.00,0.00,0,0,0,0,0,''
+'763','BOEING 767-300/300ER',0,'JET','',0.00,0.00,0,0,0,0,0,''
+'BE1','BEECHCRAFT 1900',0,'TURBOPROP','',0.00,0.00,0,0,0,0,0,''
+'BUS','BUS',0,'','',0.00,0.00,0,0,0,0,0,''
+'CNJ','CESSNA CITATION',0,'JET','',0.00,0.00,0,0,0,0,0,''
+'D3M','DOUGLAS DC3/C-47 DAKOTA MIXED CONFIGURATION',0,'PROPELLER','',0.00,0.00,0,0,0,0,0,''
+'D9S','MCDONNELL DOUGLAS DC9 (ALL 30/40/50 & 80 SERIES)',0,'JET','',0.00,0.00,0,0,0,0,0,''
+'DHM','BOEING CANADA DHC-7 DASH 7 MIXED CONFIGURATION',0,'TURBOPROP','',0.00,0.00,0,0,0,0,0,''
+'LMO','LIMOSINE',0,'','',0.00,0.00,0,0,0,0,0,''
+'M87','MCDONNELL DOUGLAS MD-87',0,'JET','',0.00,0.00,0,0,0,0,0,''
+'NDE','AEROSPATIALE AS 350 ECUREUIL/AS 355 ECUREUIL 2',1,'TURBOPROP','',0.00,0.00,0,0,0,0,0,''
+'PAG','PIPER (ALL SERIES)',0,'PROPELLER','',0.00,0.00,0,0,0,0,0,''
+'S76','SIKORSKY S76',1,'TURBOPROP','',0.00,0.00,0,0,0,0,0,''
diff --git a/sql-bench/Data/ATIS/airline.txt b/sql-bench/Data/ATIS/airline.txt
new file mode 100644
index 00000000000..7e825a5c596
--- /dev/null
+++ b/sql-bench/Data/ATIS/airline.txt
@@ -0,0 +1,314 @@
+'AA','AMERICAN AIRLINES',''
+'AC','AIR CANADA',''
+'AD','EXEC EXPRESS II,INC.',''
+'AF','AIR FRANCE',''
+'AG','ATLANTIC AIRWAYS LIMITED',''
+'AM','AEROMEXICO - AEROVIAS DE MEXICO S.A. DE C.V.',''
+'AP','ASPEN AIRWAYS,INC.',''
+'AQ','ALOHA AIRLINES INC.',''
+'AR','AEROLINEAS ARGENTINAS',''
+'AS','ALASKA AIRLINES',''
+'AT','ROYAL AIR MAROC',''
+'AV','AVIANCA',''
+'AY','FINNAIR',''
+'AZ','ALITALIA',''
+'BA','BRITISH AIRWAYS',''
+'BE','ENTERPRISE AIRLINES,INC.',''
+'BF','MARKAIR,INC.',''
+'BK','CHALKS/PARADISE ISLAND AIRLINES',''
+'BL','AIR BVI,LTD.',''
+'BW','BWIA INTERNATIONAL',''
+'CA','CAAC',''
+'CD','TRANS-PROVINCIAL AIRLINES LTD.',''
+'CH','BEMIDJI AIRLINES',''
+'CI','CHINA AIRLINES LTD.',''
+'CO','CONTINENTAL AIRLINES',''
+'CP','CANADIAN AIRLINES INTERNATIONAL LTD.',''
+'CS','AIR TORONTO',''
+'CT','MIDCONTINENT AIRLINES INC.',''
+'CU','CUBANA AIRLINES',''
+'CX','CATHAY PACIFIC AIRWAYS LTD.',''
+'DD','COMMAND AIRWAYS,INC.',''
+'DE','PRIME AIR,INC.',''
+'DF','AERO COACH AVIATION INTERNATIONAL,INC.',''
+'DL','DELTA AIR LINES,INC.',''
+'DO','DOMINICANA DE AVIACION',''
+'DQ','COASTAL AIR TRANSPORT',''
+'DV','NANTUCKET AIRLINES',''
+'EA','EASTERN AIR LINES,INC.',''
+'ED','CCAIR INC.',''
+'EI','AER LINGUS P.L.C.',''
+'EJ','NEW ENGLAND AIRLINES,INC.',''
+'EM','EMPIRE AIRWAYS',''
+'EU','EMPRESA ECUATORIANA DE AVIACION',''
+'EV','ATLANTIC SOUTHEAST AIRLINES,INC.',''
+'FC','CHAPARRAL AIRLINES,INC.',''
+'FH','MALL AIRWAYS INC.',''
+'FI','ICELANDAIR',''
+'FK','FLAMENCO AIRWAYS,INC.',''
+'FN','SFO HEICOPTER AIRLINES,INC.',''
+'FQ','AIR ARUBA',''
+'FX','EXPRESS AIR,INC.',''
+'FY','METROFLIGHT AIRLINES',''
+'GA','GARUDA INDONESIAN AIRWAYS',''
+'GM','AIR AMERICA',''
+'GQ','BIG SKY AIRLINES',''
+'GS','BAS AIRLINES',''
+'GU','AVIATECA S.A.',''
+'HA','HAWAIIAN AIR LINES',''
+'HD','NEW YORK HELICOPTER CORPORATION',''
+'HE','KEYSTONE AIR SERVICE LTD.',''
+'HG','HARBOR AIRLINES,INC',''
+'HI','GRAND CANYON HELICOPTERS',''
+'HP','AMERICA WEST AIRLINES,INC.',''
+'HQ','BUSINESS EXPRESS',''
+'HY','METRO AIRLINES',''
+'IB','IBERIA',''
+'IF','INTERFUG',''
+'IH','CHANNEL FLYING,INC.','SERVICE TEMPORARILY SUSPENDED'
+'IN','EAST HAMPTON AIRE',''
+'IU','HELITRANS AIR SERVICE,INC.',''
+'JB','HELIJET AIRWAYS',''
+'JC','ROCKY MOUNTAIN AIRWAYS',''
+'JF','L.A.B. FYING SERVICE,INC.','CARRIER PERFORMS SEASONAL SERVICE ONLY'
+'JI','JET EXPRESS',''
+'JL','JAPAN AIRLINES',''
+'JM','AIR JAMAICA LIMITED',''
+'JO','HOLIDAY AIRLINES,INC.',''
+'JQ','TRANS-JAMAICAN AIRLINES LTD.',''
+'JR','AERO CALIFORNIA',''
+'JT','IOWA AIRWAYS,INC.',''
+'JU','YUGOSLAV AIRLINES (JAT)',''
+'JV','BEARSKIN LAKE AIR SERVICE LIMITED',''
+'KE','KOREAN AIR',''
+'KI','TIME AIR LTD.',''
+'KL','KLM-ROYAL DUTCH AIRLINES',''
+'KS','PENINSULA AIRWAYS,INC.',''
+'KW','CARNIVAL AIR LINES',''
+'KX','CAYMAN AIRWAYS,LTD.',''
+'LA','LAN CHILE S.A.',''
+'LH','LUFTHANSA GERMAN AIRLINES',''
+'LI','LIAT (1974) LTD.',''
+'LM','ALM-ANTILLEAN AIRLINES',''
+'LR','LACSA',''
+'LS','ILIAMNA AIR TAXI,INC.',''
+'LV','LAV-LINEA AEROPOSTAL VENEZOLANA',''
+'LW','AIR NEVADA',''
+'LY','EL AL ISRAEL AIRLINES',''
+'MG','MGM GRAND AIR,INC.',''
+'MH','MALAYSIAN AIRLINE SYSTEM',''
+'ML','MIDWAY AIRLINES,INC.',''
+'MO','CALM AIR INTERNATIONAL LTD.',''
+'MQ','SIMMONS AIRLINES',''
+'MX','MEXICANA DE AVIACION',''
+'NA','EXECUTIVE AIR CHARTER',''
+'ND','INTAIR',''
+'NN','C.A.A.A.-AIR MARTINIQUE',''
+'NQ','CUMBERLAND AIRLINES',''
+'NR','NORONTAIR',''
+'NV','NORTHWEST TERRITORIAL AIRWAYS,LTD.',''
+'NW','NORTHWEST AIRLINES,INC.',''
+'OA','OLYMPIC AIRWAYS',''
+'OB','TEMPUS AIR LTD.','CARRIER PERFORMS SEASONAL SERVICE ONLY'
+'OE','WESTAIR AIRLINES',''
+'OG','AIR GUADELOUPE',''
+'OH','COMAIR,INC.','NATL AIR TRANSPORTATION ASSOC,INC.'
+'OJ','AIR ST.-BARTHELEMY',''
+'OK','CZECHOSLOVAK AIRLINES',''
+'OO','SKY WEST AIRLINES',''
+'OQ','AEROLIBERTAD S.A. DE C.V.',''
+'OT','EVERGREEN ALASKA',''
+'OU','CITY EXPRESS',''
+'OY','SUNAIRE',''
+'PA','PAN AMERICAN WORLD AIRWAYS,INC.',''
+'PD','PEM AIR LIMITED',''
+'PK','PAKISTAN INTERNATIONAL AIRLINES',''
+'PN','COASTAL AIRWAYS',''
+'PQ','HOLIDAY AIRWAYS','SERVICE TEMPORARILY SUSPENDED'
+'PR','PHILIPPINE AIRLINES,INC.',''
+'PS','CENTRAL STATES AIRLINES,INC.',''
+'PT','PBA-PROVINCETOWN-BOSTON AIRLINE,INC.',''
+'PV','PANORAMA AIR',''
+'PY','SURINAM AIRWAYS LTD.',''
+'QA','AERO CARIBE',''
+'QB','INTER-QUEBEC',''
+'QD','GRAND AIRWAYS,INC.',''
+'QF','QANTAS AIRWAYS LTD.',''
+'QO','BAR HARBOR AIRLINES',''
+'QQ','DRUMMOND ISLAND AIR','CARRIER PERFORMS SEASONAL SERVICE ONLY'
+'QR','AIR SATELLITE,INC.',''
+'QS','PROPHETER AVIATION',''
+'QW','TURKS AND CAICOS NATIONAL AIRLINE',''
+'QX','HORIZON AIR',''
+'QY','AERO VIRGIN ISLANDS CORP',''
+'RG','VARIG,S.A.',''
+'RH','REGAL BAHAMAS INTERNATIONAL AIRLINES',''
+'RJ','ROYAL JORDANIAN',''
+'RM','WINGS WEST AIRLINE,INC.',''
+'RP','PRECISION AIRLINES',''
+'RV','REEVE ALEUTIAN AIRWAYS,INC.',''
+'SE','WINGS OF ALASKA',''
+'SK','SCANDINAVIAN AIRLINES SYSTEM',''
+'SN','SABENA BELGIAN WORLD AIRLINES',''
+'SQ','SINGAPORE AIRLINES',''
+'SR','SWISSAIR',''
+'SS','METRO AIRLINES NORTHEAST INC.',''
+'SU','AEROFLOT-SOVIET AIRLINES',''
+'SV','SAUDI ARABIAN AIRLINES',''
+'SX','CHRISTMAN AIR SYSTEM',''
+'TB','TRUMP SHUTTLE,INC.',''
+'TE','AIR NEW ZEALAND-INTERNATIONAL',''
+'TG','THAI AIRWAYS INTERNATIONAL,LTD.',''
+'TO','ALKAN AIR LTD.',''
+'TP','TAP AIR PORTUGAL',''
+'TV','HAITI TRANS AIR S.A.',''
+'TW','TRANS WORLD AIRLINES,INC.',''
+'TZ','AMERICAN TRANS AIR',''
+'UA','UNITED AIRLINES',''
+'UC','LADECO-LINEA AEREA DEL COBRE',''
+'UE','AIR LA',''
+'UJ','AIR SEDONA',''
+'UO','DIRECT AIR,INC.','NATL AIR TRANSPORTATION ASSOC,INC.'
+'UP','BAHAMASAIR',''
+'US','USAIR',''
+'UT','U.T.A. - UNION DE TRANSPORTS AERIENS',''
+'UW','PERIMETER AIRLINES (INLAND) LTD.',''
+'VA','VIASA',''
+'VI','VIEQUES AIR LINK,INC.',''
+'VW','TRANSPORTES AEROMAR,S.A. DE C.V.',''
+'WD','WARDAIR',''
+'WJ','LABRADOR AIRWAYS,LTD.',''
+'WM','WINDWARD ISLAND AIRWAYS INTERNATIONAL N.V.',''
+'WN','SOUTHWEST AIRLINES',''
+'WP','ALOHA ISLANDAIR,INC.',''
+'WQ','WINGS AIRWAYS','NATL AIR TRANSPORTATION ASSOC,INC.'
+'WS','WESTATES AIRLINES','SERVICE TEMPORARILY SUSPENDED'
+'WV','MIDWEST AVIATION',''
+'XE','SOUTHCENTRAL AIR,INC.',''
+'XJ','MESABA AVIATION',''
+'XK','RESORT COMMUTER,INC.',''
+'XQ','ACTION AIRLINES',''
+'XV','PRESIDENTIAL AIRWAYS,INC.',''
+'XW','WALKER\'S INTERNATIONAL',''
+'XY','RYAN AIR,INC.',''
+'YE','GRAND CANYON AIRLINES,INC.','CARRIER PERFORMS SEASONAL SERVICE ONLY'
+'YI','AIR SUNSHINE INC.','NATL AIR TRANSPORTATION ASSOC,INC.'
+'YL','LONG ISLAND AIRLINES',''
+'YN','AIR CREEBEC INC.',''
+'YR','SCENIC AIRLINES INC.','NATL AIR TRANSPORTATION ASSOC,INC.'
+'YS','SAN JUAN AIRLINES',''
+'YU','AEROLINEAS DOMINICANAS,S.A. - DOMINAIR',''
+'YV','MESA AIRLINES',''
+'YW','STATESWEST AIRLINES,INC.',''
+'YX','MIDWEST EXPRESS AIRLINES,INC.',''
+'ZD','ROSS AVIATION,INC.','NATL AIR TRANSPORTATION ASSOC,INC'
+'ZE','AIR CARIBE INTERNATIONAL,INC.',''
+'ZK','GREAT LAKES AVIATION,LTD.',''
+'ZO','MOHAWK AIRLINES',''
+'ZP','VIRGIN AIR,INC.',''
+'ZS','HISPANIOLA AIRWAYS C. POR A.',''
+'ZV','AIR MIDWEST',''
+'ZW','AIR WISCONSIN',''
+'ZX','AIR BC,LTD.',''
+'2E','HERMENS/MARKAIR EXPRESS',''
+'2F','FRONTIER FLYING SERVICE',''
+'2P','PRAIRIE FLYING SERVICE (1976) LTD.',''
+'2Q','AQUILA AIR LTD',''
+'2V','NORTHEAST EXPRESS REGIONAL AIRLINES','NATL AIR TRANSPORTATION ASSOC,INC.'
+'2Z','SERVICIOS AEROS LITORAL S.A. DE C.V.',''
+'3A','ALLIANCE AIRLINES',''
+'3C','CAMAI AIR',''
+'3G','VIRGIN ISLANDS SEAPLANE SHUTTLE','SERVICE TEMPORARILY SUSPENDED'
+'3H','AIR INUIT (1985) LTD.',''
+'3L','AIR-LIFT ASSOCIATES,INC',''
+'3N','PAC AIR',''
+'3R','AIR MOLOKAI - TROPIC AIRLINES','SERVICE TEMPORARILY SUSPENDED'
+'3S','SHUSWAP AIR',''
+'3V','WAGLISLA AIR INC.',''
+'4A','AIRWAYS INTERNATIONAL,INC.',''
+'4B','OLSON AIR SERVICE,INC.',''
+'4E','TANANA AIR SERVICE',''
+'4F','FRONTIER AIR',''
+'4G','INLET AIRLINES,INC.',''
+'4K','KENN BOREK AIR LTD.',''
+'4L','AIR ALMA INC.',''
+'4N','AIR NORTH',''
+'4T','PACIFIC RIM AIRLINES LTD.',''
+'4V','VOYAGEUR AIRWAYS LTD.',''
+'4W','WRANGELL AIR SERVICE',''
+'4Y','YUTE AIR ALASKA,INC.','SERVICE TEMPORARILY SUSPENDED'
+'5A','ALPINE AVIATION,INC.',''
+'5B','BELLAIR INC.',''
+'5E','HUB EXPRESS,INC.',''
+'5K','KENMORE AIR HARBOR,INC.',''
+'5L','LAREDO AIR,INC.',''
+'5N','SEAGULL AIR SERVICE,INC.','SERVICE TEMPORARILY SUSPENDED'
+'5P','PTARMIGAN AIRWAYS LTD',''
+'5S','AIRSPEED AVIATION INC.',''
+'5T','AVIACION DEL NOROESTE',''
+'5U','SKAGWAY AIR SERVICE,INC.',''
+'5V','AVIAIR AVIATION (1984) LTD.',''
+'5W','CHARTAIR,INC.',''
+'6A','PANAMA AIRWAYS',''
+'6B','BAXTER AVIATION',''
+'6C','CAPE SMYTHE AIR SERVICE,INC.',''
+'6D','ALASKA ISLAND AIR,INC.',''
+'6E','BURRARD AIR LTD.',''
+'6G','LAS VEGAS AIRLINES',''
+'6J','SOUTHERN JERSEY AIRWAYS,INC.',''
+'6K','KEEWATIN AIR LIMITED',''
+'6L','AKLAK AIR LTD.',''
+'6M','40-MILE AIR,LTD.',''
+'6P','PROPAIR INC.',''
+'6Q','BARROW AIR,INC.',''
+'6S','KETCHIKAN AIR SERVICE,INC.',''
+'6T','TYEE AIRWAYS LIMITED',''
+'6V','AIR VEGAS,INC.',''
+'6W','WILDERNESS AIRLINE (1975) LTD.',''
+'7A','HAINES AIRWAYS,INC.',''
+'7D','TRUMP AIR',''
+'7F','FIRST AIR',''
+'7G','GULFSTREAM AIRLINES,INC.','NATL AIR TRANSPORTATION ASSOC,INC.'
+'7H','ERA AVIATION',''
+'7K','LARRY\'S FLYING SERVICE,INC',''
+'7L','LAKE UNION AIR SERVICE',''
+'7N','NORTHLAND AIR MANITOBA LIMITED',''
+'7Q','CALIFORNIA AIR SHUTTLE',''
+'7R','GCS AIR SERVICE,INC.',''
+'7T','TRANS COTE INC.',''
+'7V','ALPHA AIR',''
+'7W','AIR SASK AVIATION',''
+'8B','BAKER AVIATION,INC.',''
+'8D','SKYLINK AIRLINES','SERVICE TEMPORARILY SUSPENDED'
+'8E','BERING AIR,INC.',''
+'8F','WILBUR\'S INC.',''
+'8G','GP EXPRESS AIRLINES,INC.',''
+'8H','HARBOR AIR SERVICE',''
+'8K','AIR MUSKOKA',''
+'8L','SERVICIO AEREO LEO LOPEZ',''
+'8M','APEX AIRLINES',''
+'8N','NASHVILLE EAGLE,INC.',''
+'8P','POCONO AIRLINES',''
+'8R','WRA,INC.',''
+'8T','TRI AIR,INC.','SERVICE TEMPORARILY SUSPENDED'
+'8V','WRIGHT AIR SERVICE,INC.',''
+'9A','AIR ATLANTIC LTD.',''
+'9C','ICARUS FLYING SERVICE,LTD.',''
+'9D','DELTA AIR CHARTER LTD.',''
+'9E','EXPRESS AIRLINES I,INC.',''
+'9F','SKYCRAFT AIR TRANSPORT INC.',''
+'9K','CAPE AIR',''
+'9M','CENTRAL MOUNTAIN AIR LTD.',''
+'9N','TRANS STATES AIRLINES,INC.',''
+'9Q','TAQUAN AIR SERVICE,INC.',''
+'9S','SABOURIN LAKE AIRWAYS LTD.',''
+'9V','AIR SCHEFFERVILLE','CARRIER PERFORMS SEASONAL SERVICE ONLY'
+'GD','AIR SOUTH,INC.','NATL AIR TRANSPORTATION ASSOC,INC.'
+'VL','SUN PACIFIC AIRLINES,INC.',''
+'3D','EDGARTOWN AIR,INC.',''
+'4Q','TRANS NORTH AVIATION,LTD.','CARRIER PERFORMS SEASONAL SERVICE ONLY'
+'4R','RAVEN AIR,INC.',''
+'4X','L\'EXPRESS AIRLINES',''
+'5C','CONQUEST AIRLINES CORP.',''
+'7C','SIERRA VISTA AVIATION','SERVICE TEMPORARILY SUSPENDED'
+'MC','MILITARY AIRLIFT COMMAND (MAC)-U.S. DEPARTMENT OF THE AIR FORCE',''
diff --git a/sql-bench/Data/ATIS/airport.txt b/sql-bench/Data/ATIS/airport.txt
new file mode 100644
index 00000000000..9da49b2b2f0
--- /dev/null
+++ b/sql-bench/Data/ATIS/airport.txt
@@ -0,0 +1,9 @@
+'ATL','WILLIAM B. HARTSFIELD','ATLANTA,GEORGIA','GA','USA','EST'
+'BOS','LOGAN INTERNATIONAL','BOSTON,MASSACHUSETTS','MA','USA','EST'
+'BWI','BALTIMORE/WASHINGTON INTERNATIONAL','BALTIMORE,MARYLAND','MD','USA','EST'
+'DEN','STAPLETON INTERNATIONAL','DENVER,COLORADO','CO','USA','MST'
+'DFW','DALLAS/FORT WORTH INTERNATIONAL','DALLAS/FT. WORTH,TEXAS','TX','USA','CST'
+'OAK','METROPOLITAN OAKLAND INTERNATIONAL','OAKLAND,CALIFORNIA','CA','USA','PST'
+'PHL','PHILADELPHIA INTERNATIONAL','PHILADELPHIA PA/WILM\'TON,DE','PA','USA','EST'
+'PIT','GREATER PITTSBURGH','PITTSBURGH,PENNSYLVANIA','PA','USA','EST'
+'SFO','SAN FRANCISCO INTERNATIONAL','SAN FRANCISCO,CALIFORNIA','CA','USA','PST'
diff --git a/sql-bench/Data/ATIS/airport_service.txt b/sql-bench/Data/ATIS/airport_service.txt
new file mode 100644
index 00000000000..c38aa186db3
--- /dev/null
+++ b/sql-bench/Data/ATIS/airport_service.txt
@@ -0,0 +1,14 @@
+'MATL','ATL',9.0,'S',45
+'BBOS','BOS',3.0,'NE',30
+'DDFW','DFW',13.0,'NW',70
+'FDFW','DFW',17.0,'E',55
+'DDEN','DEN',6.5,'NE',30
+'PPHL','PHL',7.0,'SW',35
+'PPIT','PIT',17.0,'W',55
+'OOAK','OAK',10.0,'SE',15
+'OOAK','SFO',24.0,'SW',60
+'SSFO','SFO',8.0,'SE',30
+'SSFO','OAK',18.0,'SE',60
+'WWAS','BWI',32.0,'NE',50
+'BBWI','BWI',10.0,'S',25
+'','',0.0,'',0
diff --git a/sql-bench/Data/ATIS/city.txt b/sql-bench/Data/ATIS/city.txt
new file mode 100644
index 00000000000..eb826a37283
--- /dev/null
+++ b/sql-bench/Data/ATIS/city.txt
@@ -0,0 +1,11 @@
+'MATL','ATLANTA','GA','USA','EST'
+'BBOS','BOSTON','MA','USA','EST'
+'DDFW','DALLAS','TX','USA','CST'
+'FDFW','FORT WORTH','TX','USA','CST'
+'DDEN','DENVER','CO','USA','MST'
+'PPHL','PHILADELPHIA','PA','USA','EST'
+'PPIT','PITTSBURGH','PA','USA','EST'
+'SSFO','SAN FRANCISCO','CA','USA','PST'
+'OOAK','OAKLAND','CA','USA','PST'
+'WWAS','WASHINGTON','DC','USA','EST'
+'BBWI','BALTIMORE','MD','USA','EST'
diff --git a/sql-bench/Data/ATIS/class_of_service.txt b/sql-bench/Data/ATIS/class_of_service.txt
new file mode 100644
index 00000000000..ab9b9c48192
--- /dev/null
+++ b/sql-bench/Data/ATIS/class_of_service.txt
@@ -0,0 +1,27 @@
+'R',1,'SUPERSONIC AIRCRAFT'
+'P',2,'FIRST CLASS PREMIUM'
+'F',3,'FIRST CLASS'
+'A',4,'FIRST CLASS DISCOUNTED'
+'J',5,'BUSINESS CLASS PREMIUM'
+'C',6,'BUSINESS CLASS'
+'D',7,'BUSINESS CLASS DISCOUNTED'
+'S',8,'STANDARD CLASS'
+'W',9,'COACH ECONOMY CLASS PREMIUM'
+'FN',10,'FIRST CLASS NIGHT SERVICE'
+'Y',11,'COACH ECONOMY CLASS'
+'CN',12,'BUSINESS CLASS NIGHT SERVICE'
+'YN',13,'COACH ECONOMY CLASS NIGHT SERVICE'
+'B',14,'COACH ECONOMY CLASS DISCOUNTED'
+'H',15,'COACH ECONOMY CLASS DISCOUNTED'
+'Q',16,'COACH ECONOMY CLASS DISCOUNTED'
+'M',17,'COACH ECONOMY CLASS DISCOUNTED'
+'T',18,'COACH ECONOMY CLASS DISCOUNTED'
+'K',19,'THRIFT ECONOMY CLASS'
+'L',20,'THRIFT ECONOMY CLASS DISCOUNTED'
+'V',21,'THRIFT ECONOMY CLASS DISCOUNTED'
+'BN',22,'COACH ECONOMY CLASS DISCOUNTED NIGHT SERVICE'
+'QN',23,'COACH ECONOMY CLASS DISCOUNTED NIGHT SERVICE'
+'KN',24,'THRIFT ECONOMY CLASS DISCOUNTED NIGHT SERVICE'
+'VN',25,'THRIFT ECONOMY CLASS DISCOUNTED NIGHT SERVICE'
+'U',26,'SHUTTLE SERVICE (NO RESERVATION NEEDED - SEAT GUARANTEED)'
+'E',27,'SHUTTLE SERVICE (NO RESERVATION ALLOWED - SEAT TO BE CONFIRMED AT CHECK-IN)'
diff --git a/sql-bench/Data/ATIS/code_description.txt b/sql-bench/Data/ATIS/code_description.txt
new file mode 100644
index 00000000000..d832a21b019
--- /dev/null
+++ b/sql-bench/Data/ATIS/code_description.txt
@@ -0,0 +1,15 @@
+'-','A DASH IN A DAY CODE POSITION INDICATES NON-OPERATION ON THAT DAY'
+'AP','ADVANCE PURCHASE EXCURSION FARE'
+'CAD','CANADIAN DOLLARS'
+'EX','EXCURSION FARE'
+'H','HIGHEST LEVEL OF FARE HAVING MORE THAN ONE SEASONAL LEVEL'
+'J','THIRD LEVEL OF FARE HAVING MORE THAN THREE SEASONAL LEVELS'
+'K','SECOND LEVEL OF A FARE HAVING MORE THAN TWO SEASONAL LEVELS'
+'L','LOWEST LEVEL OF FARE HAVING MORE THAN ONE SEASONAL LEVEL'
+'MEP','MEXICAN PESOS'
+'O','SECOND LEVEL OF A FARE HAVING MORE THAN TWO SEASONAL LEVELS'
+'N','NIGHT SERVICE'
+'VU','VISIT USA FARE'
+'W','WHEN USED AS PART OF A FARE CLASS SUCH AS YW,INDICATES WEEKEND APPLICATION.'
+'X','WHEN USED AS PART OF A FARE CLASS SUCH AS YX,INDICATES WEEKDAY APPLICATION.'
+'U.S.','48 CONTIGUOUS STATES (NOT INCLUDING ALASKA AND HAWAII) UNLESS OTHERWISE NOTED.'
diff --git a/sql-bench/Data/ATIS/compound_class.txt b/sql-bench/Data/ATIS/compound_class.txt
new file mode 100644
index 00000000000..86c0df5b533
--- /dev/null
+++ b/sql-bench/Data/ATIS/compound_class.txt
@@ -0,0 +1,149 @@
+'A','A','FIRST','NO','NO','YES','NO','NONE','1234567'
+'AH','A','FIRST','NO','NO','YES','NO','HIGH','1234567'
+'AJ','A','FIRST','NO','NO','YES','NO','MID','1234567'
+'AL','A','FIRST','NO','NO','YES','NO','LOW','1234567'
+'B','B','COACH','NO','YES','YES','NO','NONE','1234567'
+'BH','B','COACH','NO','YES','YES','NO','HIGH','1234567'
+'BHW','B','COACH','NO','YES','YES','NO','HIGH','-----67'
+'BHX','B','COACH','NO','YES','YES','NO','HIGH','12345--'
+'BL','B','COACH','NO','YES','YES','NO','LOW','1234567'
+'BLW','B','COACH','NO','YES','YES','NO','LOW','-----67'
+'BLX','B','COACH','NO','YES','YES','NO','LOW','12345--'
+'BN','BN','COACH','NO','YES','YES','YES','NONE','1234567'
+'BO','B','COACH','NO','YES','YES','NO','MID','1234567'
+'BOW','B','COACH','NO','YES','YES','NO','MID','-----67'
+'BOX','B','COACH','NO','YES','YES','NO','MID','12345--'
+'BW','B','COACH','NO','YES','YES','NO','NONE','-----67'
+'BX','B','COACH','NO','YES','YES','NO','NONE','12345--'
+'C','C','BUSINESS','NO','NO','NO','NO','NONE','1234567'
+'CH','C','BUSINESS','NO','NO','NO','NO','HIGH','1234567'
+'CHW','C','BUSINESS','NO','NO','NO','NO','HIGH','-----67'
+'CHX','C','BUSINESS','NO','NO','NO','NO','HIGH','12345--'
+'CL','C','BUSINESS','NO','NO','NO','NO','LOW','1234567'
+'CLW','C','BUSINESS','NO','NO','NO','NO','LOW','-----67'
+'CLX','C','BUSINESS','NO','NO','NO','NO','LOW','12345--'
+'CN','CN','BUSINESS','NO','NO','NO','YES','NONE','1234567'
+'CO','C','BUSINESS','NO','NO','NO','NO','MID','1234567'
+'CW','C','BUSINESS','NO','NO','NO','NO','NONE','-----67'
+'CX','C','BUSINESS','NO','NO','NO','NO','NONE','12345--'
+'D','D','BUSINESS','NO','NO','YES','NO','NONE','1234567'
+'F','F','FIRST','NO','NO','NO','NO','NONE','1234567'
+'FH','F','FIRST','NO','NO','NO','NO','HIGH','1234567'
+'FHW','F','FIRST','NO','NO','NO','NO','HIGH','-----67'
+'FHX','F','FIRST','NO','NO','NO','NO','HIGH','12345--'
+'FL','F','FIRST','NO','NO','NO','NO','LOW','1234567'
+'FLW','F','FIRST','NO','NO','NO','NO','LOW','-----67'
+'FLX','F','FIRST','NO','NO','NO','NO','LOW','12345--'
+'FN','FN','FIRST','NO','NO','NO','YES','NONE','1234567'
+'FO','F','FIRST','NO','NO','NO','NO','MID','1234567'
+'FW','F','FIRST','NO','NO','NO','NO','NONE','-----67'
+'FX','F','FIRST','NO','NO','NO','NO','NONE','12345--'
+'H','H','COACH','NO','YES','YES','NO','NONE','1234567'
+'HH','H','COACH','NO','YES','YES','NO','HIGH','1234567'
+'HHW','H','COACH','NO','YES','YES','NO','HIGH','-----67'
+'HHX','H','COACH','NO','YES','YES','NO','HIGH','12345--'
+'HK','H','COACH','NO','YES','YES','NO','MID','1234567'
+'HKW','H','COACH','NO','YES','YES','NO','MID','-----67'
+'HKX','H','COACH','NO','YES','YES','NO','MID','12345--'
+'HL','H','COACH','NO','YES','YES','NO','LOW','1234567'
+'HLW','H','COACH','NO','YES','YES','NO','LOW','-----67'
+'HLX','H','COACH','NO','YES','YES','NO','LOW','12345--'
+'HO','H','COACH','NO','YES','YES','NO','MID','1234567'
+'HOW','H','COACH','NO','YES','YES','NO','MID','-----67'
+'HOX','H','COACH','NO','YES','YES','NO','MID','12345--'
+'HW','H','COACH','NO','YES','YES','NO','NONE','-----67'
+'HX','H','COACH','NO','YES','YES','NO','NONE','12345--'
+'J','J','BUSINESS','YES','NO','NO','NO','NONE','1234567'
+'JH','J','BUSINESS','YES','NO','NO','NO','HIGH','1234567'
+'JK','J','BUSINESS','YES','NO','NO','NO','MID','1234567'
+'JL','J','BUSINESS','YES','NO','NO','NO','LOW','1234567'
+'JO','J','BUSINESS','YES','NO','NO','NO','MID','1234567'
+'K','K','THRIFT','NO','YES','NO','NO','NONE','1234567'
+'KH','K','THRIFT','NO','YES','NO','NO','HIGH','1234567'
+'KHW','K','THRIFT','NO','YES','NO','NO','HIGH','-----67'
+'KHX','K','THRIFT','NO','YES','NO','NO','HIGH','12345--'
+'KL','K','THRIFT','NO','YES','NO','NO','LOW','1234567'
+'KLW','K','THRIFT','NO','YES','NO','NO','LOW','-----67'
+'KLX','K','THRIFT','NO','YES','NO','NO','LOW','12345--'
+'KN','KN','THRIFT','NO','YES','YES','YES','NONE','1234567'
+'KO','K','THRIFT','NO','YES','NO','NO','MID','1234567'
+'KW','K','THRIFT','NO','YES','NO','NO','NONE','-----67'
+'KX','K','THRIFT','NO','YES','NO','NO','NONE','12345--'
+'L','L','THRIFT','NO','YES','YES','NO','NONE','1234567'
+'LH','L','THRIFT','NO','YES','YES','NO','HIGH','1234567'
+'LHW','L','THRIFT','NO','YES','YES','NO','HIGH','-----67'
+'LHX','L','THRIFT','NO','YES','YES','NO','HIGH','12345--'
+'LL','L','THRIFT','NO','YES','YES','NO','LOW','1234567'
+'LLW','L','THRIFT','NO','YES','YES','NO','LOW','-----67'
+'LLX','L','THRIFT','NO','YES','YES','NO','LOW','12345--'
+'LO','L','THRIFT','NO','YES','YES','NO','MID','1234567'
+'LOW','L','THRIFT','NO','YES','YES','NO','MID','-----67'
+'LOX','L','THRIFT','NO','YES','YES','NO','MID','12345--'
+'LW','L','THRIFT','NO','YES','YES','NO','NONE','-----67'
+'LX','L','THRIFT','NO','YES','YES','NO','NONE','12345--'
+'M','M','COACH','NO','YES','YES','NO','NONE','1234567'
+'MH','M','COACH','NO','YES','YES','NO','HIGH','1234567'
+'MHW','M','COACH','NO','YES','YES','NO','HIGH','-----67'
+'MHX','M','COACH','NO','YES','YES','NO','HIGH','12345--'
+'MKW','M','COACH','NO','YES','YES','NO','MID','-----67'
+'MKX','M','COACH','NO','YES','YES','NO','MID','12345--'
+'ML','M','COACH','NO','YES','YES','NO','LOW','1234567'
+'MLW','M','COACH','NO','YES','YES','NO','LOW','-----67'
+'MLX','M','COACH','NO','YES','YES','NO','LOW','12345--'
+'MO','M','COACH','NO','YES','YES','NO','MID','1234567'
+'MOW','M','COACH','NO','YES','YES','NO','MID','-----67'
+'MOX','M','COACH','NO','YES','YES','NO','MID','12345--'
+'MW','M','COACH','NO','YES','YES','NO','NONE','-----67'
+'MX','M','COACH','NO','YES','YES','NO','NONE','12345--'
+'P','P','FIRST','YES','NO','NO','NO','NONE','1234567'
+'Q','Q','COACH','NO','YES','YES','NO','NONE','1234567'
+'QH','Q','COACH','NO','YES','YES','NO','HIGH','1234567'
+'QHW','Q','COACH','NO','YES','YES','NO','HIGH','-----67'
+'QHX','Q','COACH','NO','YES','YES','NO','HIGH','12345--'
+'QL','Q','COACH','NO','YES','YES','NO','LOW','1234567'
+'QLW','Q','COACH','NO','YES','YES','NO','LOW','-----67'
+'QLX','Q','COACH','NO','YES','YES','NO','LOW','12345--'
+'QN','QN','COACH','NO','YES','YES','YES','NONE','1234567'
+'QO','Q','COACH','NO','YES','YES','NO','MID','1234567'
+'QOW','Q','COACH','NO','YES','YES','NO','MID','-----67'
+'QOX','Q','COACH','NO','YES','YES','NO','MID','12345--'
+'QW','Q','COACH','NO','YES','YES','NO','NONE','-----67'
+'QX','Q','COACH','NO','YES','YES','NO','NONE','12345--'
+'R','R','SUPERSONIC','NO','NO','NO','NO','NONE','1234567'
+'S','S','STANDARD','NO','NO','NO','NO','NONE','1234567'
+'SH','S','STANDARD','NO','NO','NO','NO','HIGH','1234567'
+'SL','S','STANDARD','NO','NO','NO','NO','LOW','1234567'
+'T','T','COACH','NO','YES','YES','NO','NONE','1234567'
+'TH','T','COACH','NO','YES','YES','NO','HIGH','1234567'
+'TL','T','COACH','NO','YES','YES','NO','LOW','1234567'
+'TO','T','COACH','NO','YES','YES','NO','MID','1234567'
+'V','V','THRIFT','NO','YES','YES','NO','NONE','1234567'
+'VH','V','THRIFT','NO','YES','YES','NO','HIGH','1234567'
+'VHW','V','THRIFT','NO','YES','YES','NO','HIGH','-----67'
+'VHX','V','THRIFT','NO','YES','YES','NO','HIGH','12345--'
+'VK','V','THRIFT','NO','YES','YES','NO','MID','1234567'
+'VL','V','THRIFT','NO','YES','YES','NO','LOW','1234567'
+'VLW','V','THRIFT','NO','YES','YES','NO','LOW','-----67'
+'VLX','V','THRIFT','NO','YES','YES','NO','LOW','12345--'
+'VO','V','THRIFT','NO','YES','YES','NO','MID','1234567'
+'VOW','V','THRIFT','NO','YES','YES','NO','MID','-----67'
+'VOX','V','THRIFT','NO','YES','YES','NO','MID','12345--'
+'VW','V','THRIFT','NO','YES','YES','NO','NONE','-----67'
+'VX','V','THRIFT','NO','YES','YES','NO','NONE','12345--'
+'Y','Y','COACH','NO','YES','NO','NO','NONE','1234567'
+'YH','Y','COACH','NO','YES','NO','NO','HIGH','1234567'
+'YHW','Y','COACH','NO','YES','NO','NO','HIGH','-----67'
+'YHX','Y','COACH','NO','YES','NO','NO','HIGH','12345--'
+'YJ','Y','COACH','NO','YES','NO','NO','MID','1234567'
+'YJW','Y','COACH','NO','YES','NO','NO','MID','-----67'
+'YJX','Y','COACH','NO','YES','NO','NO','MID','12345--'
+'YK','Y','COACH','NO','YES','NO','NO','MID','1234567'
+'YL','Y','COACH','NO','YES','NO','NO','LOW','1234567'
+'YLW','Y','COACH','NO','YES','NO','NO','LOW','-----67'
+'YLX','Y','COACH','NO','YES','NO','NO','LOW','12345--'
+'YN','YN','COACH','NO','YES','NO','YES','NONE','1234567'
+'YO','Y','COACH','NO','YES','NO','NO','MID','1234567'
+'YOW','Y','COACH','NO','YES','NO','NO','MID','-----67'
+'YOX','Y','COACH','NO','YES','NO','NO','MID','12345--'
+'YW','Y','COACH','NO','YES','NO','NO','NONE','-----67'
+'YX','Y','COACH','NO','YES','NO','NO','NONE','12345--'
diff --git a/sql-bench/Data/ATIS/connect_leg.txt b/sql-bench/Data/ATIS/connect_leg.txt
new file mode 100644
index 00000000000..43f860bb779
--- /dev/null
+++ b/sql-bench/Data/ATIS/connect_leg.txt
@@ -0,0 +1,351 @@
+305276,1,106231
+305276,2,137225
+305277,1,106237
+305277,2,137231
+305280,1,106247
+305280,2,137237
+305416,1,112030
+305416,1,112031
+305416,2,112773
+305424,1,112033
+305424,2,112784
+305429,1,112040
+305429,2,112793
+305429,2,112794
+305435,1,112046
+305435,2,112806
+305436,1,112051
+305436,2,112808
+306026,1,133430
+306026,2,111891
+306031,1,133432
+306031,2,111896
+306304,1,144155
+306304,2,112766
+306307,1,144143
+306307,2,111891
+306309,1,144158
+306309,2,112784
+306314,1,144163
+306314,2,112793
+306314,2,112794
+306317,1,144167
+306317,2,112805
+306318,1,144150
+306318,2,111896
+306319,1,144169
+306319,2,112808
+308292,1,112766
+308292,2,101952
+308296,1,112773
+308296,2,101953
+308301,1,112784
+308301,2,101955
+308304,1,112793
+308304,1,112794
+308304,2,101958
+308320,1,112030
+308320,1,112031
+308320,2,112904
+308330,1,111892
+308330,2,101955
+308334,1,112040
+308334,2,112907
+308924,1,133432
+308924,2,111941
+309189,1,144060
+309189,2,101955
+309198,1,144163
+309198,2,112907
+309204,1,144150
+309204,2,111941
+312733,1,102767
+312733,2,137320
+312734,1,102771
+312734,2,137326
+312737,1,102777
+312737,2,137335
+313006,1,112805
+313006,2,101929
+313024,1,111886
+313024,2,101909
+313025,1,112030
+313025,1,112031
+313025,2,112866
+313025,2,112867
+313030,1,111888
+313030,2,101916
+313030,2,101917
+313034,1,112033
+313034,2,112870
+313037,1,111892
+313037,2,101922
+313041,1,112040
+313041,2,112873
+313048,1,111895
+313048,2,101929
+313867,1,133430
+313867,2,111928
+314256,1,144143
+314256,2,111928
+314259,1,144158
+314259,2,112870
+314263,1,144060
+314263,2,101922
+314268,1,144163
+314268,2,112873
+314269,1,144148
+314269,2,111931
+329933,1,107159
+329933,2,102144
+329937,1,107162
+329937,2,102150
+329941,1,107165
+329941,2,102166
+329944,1,107166
+329944,2,102177
+329947,1,107168
+329947,2,102191
+330865,1,133430
+330865,2,112034
+330867,1,133431
+330867,2,112043
+330870,1,133432
+330870,2,112049
+330947,1,137221
+330947,2,102144
+330956,1,137224
+330956,2,102150
+330962,1,137228
+330962,2,102166
+330964,1,137230
+330964,2,102173
+330967,1,137233
+330967,2,102177
+330971,1,137235
+330971,2,102190
+330974,1,137238
+330974,2,102191
+330977,1,138817
+330977,2,102144
+330981,1,138821
+330981,2,102150
+330984,1,138823
+330984,2,102166
+330989,1,138830
+330989,1,138831
+330989,2,102191
+331132,1,144143
+331132,2,112034
+331133,1,144148
+331133,2,112043
+331134,1,144150
+331134,2,112049
+333051,1,102136
+333051,1,102137
+333051,2,112992
+333054,1,102148
+333054,2,113000
+333059,1,102162
+333059,1,102163
+333059,2,113003
+333067,1,102190
+333067,2,113012
+333067,2,113013
+333086,1,107159
+333086,2,102122
+333091,1,107258
+333091,2,113000
+333099,1,107165
+333099,2,102127
+333110,1,107168
+333110,2,102135
+333153,1,105700
+333153,2,107255
+333158,1,105592
+333158,2,102127
+333168,1,105599
+333168,2,102135
+334183,1,137221
+334183,2,102122
+334190,1,137354
+334190,2,107255
+334198,1,137233
+334198,2,102133
+334202,1,137238
+334202,2,102135
+334210,1,138817
+334210,2,102122
+334218,1,138879
+334218,2,107255
+334222,1,138823
+334222,2,102127
+334230,1,138830
+334230,1,138831
+334230,2,102135
+393490,1,102125
+393490,2,112352
+393507,1,107254
+393507,2,112352
+393546,1,105794
+393546,2,112352
+393547,1,105795
+393547,2,112352
+393553,1,105799
+393553,2,112354
+393637,1,112991
+393637,2,112351
+393641,1,113004
+393641,2,112353
+393643,1,113008
+393643,2,112354
+393950,1,137407
+393950,2,112352
+393953,1,137412
+393953,2,112354
+402327,1,112766
+402327,2,102770
+402332,1,112773
+402332,2,102773
+402339,1,112784
+402339,2,102776
+402343,1,112790
+402343,2,102779
+402346,1,112793
+402346,1,112794
+402346,2,102782
+402350,1,112805
+402350,2,102784
+402376,1,112030
+402376,1,112031
+402376,2,113577
+402382,1,111888
+402382,2,102773
+402388,1,111892
+402388,2,102776
+402391,1,111939
+402391,2,107478
+402397,1,112046
+402397,2,113583
+402398,1,111895
+402398,2,102784
+403125,1,133430
+403125,2,112415
+403128,1,133431
+403128,2,112417
+403468,1,144143
+403468,2,112415
+403472,1,144158
+403472,2,113579
+403474,1,144060
+403474,2,102776
+403479,1,144148
+403479,2,112417
+403481,1,144062
+403481,1,144063
+403481,2,102782
+403485,1,144167
+403485,2,113583
+403486,1,144066
+403486,2,102784
+403488,1,144067
+403488,2,102766
+405211,1,112773
+405211,2,102800
+405214,1,112784
+405214,2,102802
+405214,2,102803
+405217,1,112793
+405217,1,112794
+405217,2,102807
+405219,1,112805
+405219,2,102809
+405235,1,111886
+405235,2,102795
+405236,1,111886
+405236,2,102796
+405241,1,111888
+405241,2,102800
+405250,1,111892
+405250,2,102802
+405250,2,102803
+405253,1,111939
+405253,2,107492
+405258,1,111895
+405258,2,102809
+405963,1,144060
+405963,2,102802
+405963,2,102803
+405970,1,144066
+405970,2,102809
+405971,1,144067
+405971,2,102796
+420730,1,102136
+420730,1,102137
+420730,2,113705
+420735,1,102148
+420735,2,113712
+420736,1,102125
+420736,2,112516
+420739,1,102162
+420739,1,102163
+420739,2,113715
+420745,1,102173
+420745,2,113719
+420747,1,102129
+420747,2,112526
+420751,1,102190
+420751,2,113721
+420782,1,107486
+420782,2,139353
+420783,1,107258
+420783,2,113712
+420785,1,107254
+420785,2,112516
+420791,1,107165
+420791,2,102929
+420792,1,107487
+420792,2,139355
+420798,1,107489
+420798,2,139356
+420887,1,105802
+420887,2,113712
+420888,1,105794
+420888,2,112516
+420893,1,105805
+420893,2,113715
+420894,1,106266
+420894,2,139355
+420903,1,105595
+420903,2,102932
+420911,1,105799
+420911,2,112526
+420912,1,105812
+420912,2,113721
+421176,1,112991
+421176,2,112513
+421177,1,112998
+421177,2,112516
+421179,1,113004
+421179,2,112524
+421180,1,113008
+421180,2,112526
+421181,1,113010
+421181,2,112527
+422233,1,137221
+422233,2,102923
+422233,2,102924
+422240,1,137415
+422240,2,113712
+422241,1,137407
+422241,2,112516
+422249,1,137228
+422249,2,102929
+422262,1,137412
+422262,2,112526
+422263,1,137423
+422263,2,113721
+422277,1,138821
+422277,2,102927
+422281,1,138823
+422281,2,102929
diff --git a/sql-bench/Data/ATIS/connection.txt b/sql-bench/Data/ATIS/connection.txt
new file mode 100644
index 00000000000..39d0bd75780
--- /dev/null
+++ b/sql-bench/Data/ATIS/connection.txt
@@ -0,0 +1,164 @@
+312733,'ATL','BOS',740,1127,'1234567',0,1,227
+312734,'ATL','BOS',1200,1548,'1234567',0,1,228
+312737,'ATL','BOS',1650,2053,'1234567',0,1,243
+333051,'ATL','DEN',630,910,'1234567',0,1,280
+333054,'ATL','DEN',1000,1245,'1234567',0,1,285
+333059,'ATL','DEN',1319,1554,'1234567',0,1,275
+333067,'ATL','DEN',2029,2320,'1234567',0,1,291
+393490,'ATL','OAK',1000,1339,'1234567',0,1,399
+420730,'ATL','SFO',630,955,'1234567',0,1,385
+420735,'ATL','SFO',1000,1325,'1234567',0,1,385
+420736,'ATL','SFO',1000,1336,'1234567',0,1,396
+420739,'ATL','SFO',1319,1650,'1234567',0,1,391
+420745,'ATL','SFO',1650,2050,'1234567',0,1,420
+420747,'ATL','SFO',1825,2214,'1234567',0,1,409
+420751,'ATL','SFO',2029,2350,'1234567',0,1,381
+305276,'BOS','ATL',705,1110,'1234567',0,1,245
+305277,'BOS','ATL',1125,1615,'1234567',0,1,290
+305280,'BOS','ATL',1645,2101,'1234567',0,1,256
+333153,'BOS','DEN',1000,1410,'1234567',0,1,370
+333158,'BOS','DEN',1156,1615,'1234567',0,1,379
+333168,'BOS','DEN',1850,2320,'1234567',0,1,390
+393546,'BOS','OAK',838,1339,'123456-',0,1,481
+393547,'BOS','OAK',840,1339,'------7',0,1,479
+393553,'BOS','OAK',1720,2205,'1234567',0,1,465
+420887,'BOS','SFO',805,1325,'1234567',0,1,500
+420888,'BOS','SFO',838,1336,'123456-',0,1,478
+420893,'BOS','SFO',1132,1650,'1234567',0,1,498
+420894,'BOS','SFO',1210,1652,'1234567',0,1,462
+420903,'BOS','SFO',1520,2115,'1234567',0,1,535
+420911,'BOS','SFO',1720,2214,'1234567',0,1,474
+420912,'BOS','SFO',1845,2350,'1234567',0,1,485
+333086,'BWI','DEN',550,955,'1234567',0,1,365
+333091,'BWI','DEN',845,1245,'1234567',0,1,360
+333099,'BWI','DEN',1230,1615,'1234567',0,1,345
+333110,'BWI','DEN',1945,2320,'1234567',0,1,335
+329933,'BWI','DFW',550,930,'1234567',0,1,280
+329937,'BWI','DFW',900,1250,'1234567',0,1,290
+329941,'BWI','DFW',1230,1620,'1234567',0,1,290
+329944,'BWI','DFW',1600,1955,'1234567',0,1,295
+329947,'BWI','DFW',1945,2321,'1234567',0,1,276
+393507,'BWI','OAK',915,1339,'1234567',0,1,444
+420782,'BWI','SFO',800,1217,'123456-',0,1,437
+420783,'BWI','SFO',845,1325,'1234567',0,1,460
+420785,'BWI','SFO',915,1336,'1234567',0,1,441
+420791,'BWI','SFO',1230,1730,'1234567',0,1,480
+420792,'BWI','SFO',1240,1652,'1234567',0,1,432
+420798,'BWI','SFO',1620,2022,'1234567',0,1,422
+305416,'DEN','ATL',620,1244,'1234567',0,1,264
+305424,'DEN','ATL',950,1606,'1234567',0,1,256
+305429,'DEN','ATL',1325,1943,'1234567',0,1,258
+305435,'DEN','ATL',1700,100,'1234567',0,1,360
+305436,'DEN','ATL',1955,230,'1234567',0,1,275
+313024,'DEN','BOS',55,855,'1234567',0,1,360
+313025,'DEN','BOS',620,1435,'1234567',0,1,375
+313030,'DEN','BOS',800,1550,'1234567',0,1,350
+313034,'DEN','BOS',950,1755,'1234567',0,1,365
+313037,'DEN','BOS',1055,1920,'1234567',0,1,385
+313041,'DEN','BOS',1325,2125,'1234567',0,1,360
+313048,'DEN','BOS',1815,153,'1234567',0,1,338
+308320,'DEN','BWI',620,1400,'1234567',0,1,340
+308330,'DEN','BWI',1055,1850,'1234567',0,1,355
+308334,'DEN','BWI',1325,2045,'1234567',0,1,320
+402376,'DEN','PHL',620,1350,'1234567',0,1,330
+402382,'DEN','PHL',800,1515,'1234567',0,1,315
+402388,'DEN','PHL',1055,1840,'1234567',0,1,345
+402391,'DEN','PHL',1455,2146,'12345-7',0,1,291
+402397,'DEN','PHL',1700,15,'1234567',0,1,315
+402398,'DEN','PHL',1815,130,'1234567',0,1,315
+405235,'DEN','PIT',55,803,'1234567',0,1,308
+405236,'DEN','PIT',55,1000,'1234567',0,1,425
+405241,'DEN','PIT',800,1510,'1234567',0,1,310
+405250,'DEN','PIT',1055,1845,'1234567',0,1,350
+405253,'DEN','PIT',1455,2202,'1234567',0,1,307
+405258,'DEN','PIT',1815,59,'1234567',0,1,284
+313006,'DFW','BOS',2010,153,'1234567',0,1,283
+308292,'DFW','BWI',625,1145,'1234567',0,1,260
+308296,'DFW','BWI',945,1510,'1234567',0,1,265
+308301,'DFW','BWI',1305,1850,'1234567',0,1,285
+308304,'DFW','BWI',1650,2230,'1234567',0,1,280
+393637,'DFW','OAK',700,1014,'123456-',0,1,314
+393641,'DFW','OAK',1547,1852,'1234567',0,1,305
+393643,'DFW','OAK',1850,2205,'12345-7',0,1,315
+402327,'DFW','PHL',625,1200,'1234567',0,1,275
+402332,'DFW','PHL',945,1515,'1234567',0,1,270
+402339,'DFW','PHL',1305,1840,'1234567',0,1,275
+402343,'DFW','PHL',1501,2045,'1234567',0,1,284
+402346,'DFW','PHL',1650,2220,'1234567',0,1,270
+402350,'DFW','PHL',2010,130,'1234567',0,1,260
+405211,'DFW','PIT',945,1510,'1234567',0,1,265
+405214,'DFW','PIT',1305,1845,'1234567',0,1,280
+405217,'DFW','PIT',1650,2205,'1234567',0,1,255
+405219,'DFW','PIT',2010,59,'1234567',0,1,229
+421176,'DFW','SFO',700,1006,'123456-',0,1,306
+421177,'DFW','SFO',1032,1336,'1234567',0,1,304
+421179,'DFW','SFO',1547,1912,'1234567',0,1,325
+421180,'DFW','SFO',1850,2214,'12345-7',0,1,324
+421181,'DFW','SFO',1940,2310,'1234567',0,1,330
+306026,'OAK','ATL',625,1537,'1234567',0,1,372
+306031,'OAK','ATL',1425,2330,'1234567',0,1,365
+313867,'OAK','BOS',625,1619,'1234567',0,1,414
+308924,'OAK','BWI',1425,2332,'1234567',0,1,367
+330865,'OAK','DFW',625,1312,'1234567',0,1,287
+330867,'OAK','DFW',1105,1753,'1234567',0,1,288
+330870,'OAK','DFW',1425,2122,'12345-7',0,1,297
+403125,'OAK','PHL',625,1553,'1234567',0,1,388
+403128,'OAK','PHL',1105,2041,'1234567',0,1,396
+334183,'PHL','DEN',540,955,'1234567',0,1,375
+334190,'PHL','DEN',840,1410,'123456-',0,1,450
+334198,'PHL','DEN',1600,2015,'1234567',0,1,375
+334202,'PHL','DEN',1935,2320,'1234567',0,1,345
+330947,'PHL','DFW',540,930,'1234567',0,1,290
+330956,'PHL','DFW',900,1250,'1234567',0,1,290
+330962,'PHL','DFW',1230,1620,'1234567',0,1,290
+330964,'PHL','DFW',1405,1805,'1234567',0,1,300
+330967,'PHL','DFW',1600,1955,'1234567',0,1,295
+330971,'PHL','DFW',1750,2140,'1234567',0,1,290
+330974,'PHL','DFW',1935,2321,'1234567',0,1,286
+393950,'PHL','OAK',905,1339,'1234567',0,1,454
+393953,'PHL','OAK',1753,2205,'1234567',0,1,432
+422233,'PHL','SFO',540,1110,'1234567',0,1,510
+422240,'PHL','SFO',830,1325,'1234567',0,1,475
+422241,'PHL','SFO',905,1336,'1234567',0,1,451
+422249,'PHL','SFO',1230,1730,'1234567',0,1,480
+422262,'PHL','SFO',1753,2214,'1234567',0,1,441
+422263,'PHL','SFO',1915,2350,'1234567',0,1,455
+334210,'PIT','DEN',600,955,'1234567',0,1,355
+334218,'PIT','DEN',1030,1410,'1234567',0,1,340
+334222,'PIT','DEN',1245,1615,'1234567',0,1,330
+334230,'PIT','DEN',1945,2320,'1234567',0,1,335
+330977,'PIT','DFW',600,930,'1234567',0,1,270
+330981,'PIT','DFW',910,1250,'1234567',0,1,280
+330984,'PIT','DFW',1245,1620,'1234567',0,1,275
+330989,'PIT','DFW',1945,2321,'1234567',0,1,276
+422277,'PIT','SFO',910,1410,'1234567',0,1,480
+422281,'PIT','SFO',1245,1730,'1234567',0,1,465
+306304,'SFO','ATL',20,917,'1234567',0,1,357
+306307,'SFO','ATL',620,1537,'1234567',0,1,377
+306309,'SFO','ATL',700,1606,'1234567',0,1,366
+306314,'SFO','ATL',1059,1943,'1234567',0,1,344
+306317,'SFO','ATL',1425,2258,'1234567',0,1,333
+306318,'SFO','ATL',1431,2330,'1234567',0,1,359
+306319,'SFO','ATL',1750,230,'1234567',0,1,340
+314256,'SFO','BOS',620,1619,'1234567',0,1,419
+314259,'SFO','BOS',700,1755,'1234567',0,1,475
+314263,'SFO','BOS',815,1920,'1234567',0,1,485
+314268,'SFO','BOS',1059,2125,'1234567',0,1,446
+314269,'SFO','BOS',1108,2056,'1234567',0,1,408
+309189,'SFO','BWI',815,1850,'1234567',0,1,455
+309198,'SFO','BWI',1059,2045,'1234567',0,1,406
+309204,'SFO','BWI',1431,2332,'1234567',0,1,361
+331132,'SFO','DFW',620,1312,'1234567',0,1,292
+331133,'SFO','DFW',1108,1753,'1234567',0,1,285
+331134,'SFO','DFW',1431,2122,'12345-7',0,1,291
+403468,'SFO','PHL',620,1553,'1234567',0,1,393
+403472,'SFO','PHL',700,1705,'1234567',0,1,425
+403474,'SFO','PHL',815,1840,'1234567',0,1,445
+403479,'SFO','PHL',1108,2041,'1234567',0,1,393
+403481,'SFO','PHL',1215,2220,'1234567',0,1,425
+403485,'SFO','PHL',1425,15,'1234567',0,1,410
+403486,'SFO','PHL',1530,130,'1234567',0,1,420
+403488,'SFO','PHL',2220,825,'1234567',0,1,425
+405963,'SFO','PIT',815,1845,'1234567',0,1,450
+405970,'SFO','PIT',1530,59,'1234567',0,1,389
+405971,'SFO','PIT',2220,1000,'1234567',0,1,520
diff --git a/sql-bench/Data/ATIS/date_day.txt b/sql-bench/Data/ATIS/date_day.txt
new file mode 100644
index 00000000000..b96ac310fde
--- /dev/null
+++ b/sql-bench/Data/ATIS/date_day.txt
@@ -0,0 +1,1826 @@
+"1","1","1990","MONDAY"
+"1","2","1990","TUESDAY"
+"1","3","1990","WEDNESDAY"
+"1","4","1990","THURSDAY"
+"1","5","1990","FRIDAY"
+"1","6","1990","SATURDAY"
+"1","7","1990","SUNDAY"
+"1","8","1990","MONDAY"
+"1","9","1990","TUESDAY"
+"1","10","1990","WEDNESDAY"
+"1","11","1990","THURSDAY"
+"1","12","1990","FRIDAY"
+"1","13","1990","SATURDAY"
+"1","14","1990","SUNDAY"
+"1","15","1990","MONDAY"
+"1","16","1990","TUESDAY"
+"1","17","1990","WEDNESDAY"
+"1","18","1990","THURSDAY"
+"1","19","1990","FRIDAY"
+"1","20","1990","SATURDAY"
+"1","21","1990","SUNDAY"
+"1","22","1990","MONDAY"
+"1","23","1990","TUESDAY"
+"1","24","1990","WEDNESDAY"
+"1","25","1990","THURSDAY"
+"1","26","1990","FRIDAY"
+"1","27","1990","SATURDAY"
+"1","28","1990","SUNDAY"
+"1","29","1990","MONDAY"
+"1","30","1990","TUESDAY"
+"1","31","1990","WEDNESDAY"
+"2","1","1990","THURSDAY"
+"2","2","1990","FRIDAY"
+"2","3","1990","SATURDAY"
+"2","4","1990","SUNDAY"
+"2","5","1990","MONDAY"
+"2","6","1990","TUESDAY"
+"2","7","1990","WEDNESDAY"
+"2","8","1990","THURSDAY"
+"2","9","1990","FRIDAY"
+"2","10","1990","SATURDAY"
+"2","11","1990","SUNDAY"
+"2","12","1990","MONDAY"
+"2","13","1990","TUESDAY"
+"2","14","1990","WEDNESDAY"
+"2","15","1990","THURSDAY"
+"2","16","1990","FRIDAY"
+"2","17","1990","SATURDAY"
+"2","18","1990","SUNDAY"
+"2","19","1990","MONDAY"
+"2","20","1990","TUESDAY"
+"2","21","1990","WEDNESDAY"
+"2","22","1990","THURSDAY"
+"2","23","1990","FRIDAY"
+"2","24","1990","SATURDAY"
+"2","25","1990","SUNDAY"
+"2","26","1990","MONDAY"
+"2","27","1990","TUESDAY"
+"2","28","1990","WEDNESDAY"
+"3","1","1990","THURSDAY"
+"3","2","1990","FRIDAY"
+"3","3","1990","SATURDAY"
+"3","4","1990","SUNDAY"
+"3","5","1990","MONDAY"
+"3","6","1990","TUESDAY"
+"3","7","1990","WEDNESDAY"
+"3","8","1990","THURSDAY"
+"3","9","1990","FRIDAY"
+"3","10","1990","SATURDAY"
+"3","11","1990","SUNDAY"
+"3","12","1990","MONDAY"
+"3","13","1990","TUESDAY"
+"3","14","1990","WEDNESDAY"
+"3","15","1990","THURSDAY"
+"3","16","1990","FRIDAY"
+"3","17","1990","SATURDAY"
+"3","18","1990","SUNDAY"
+"3","19","1990","MONDAY"
+"3","20","1990","TUESDAY"
+"3","21","1990","WEDNESDAY"
+"3","22","1990","THURSDAY"
+"3","23","1990","FRIDAY"
+"3","24","1990","SATURDAY"
+"3","25","1990","SUNDAY"
+"3","26","1990","MONDAY"
+"3","27","1990","TUESDAY"
+"3","28","1990","WEDNESDAY"
+"3","29","1990","THURSDAY"
+"3","30","1990","FRIDAY"
+"3","31","1990","SATURDAY"
+"4","1","1990","SUNDAY"
+"4","2","1990","MONDAY"
+"4","3","1990","TUESDAY"
+"4","4","1990","WEDNESDAY"
+"4","5","1990","THURSDAY"
+"4","6","1990","FRIDAY"
+"4","7","1990","SATURDAY"
+"4","8","1990","SUNDAY"
+"4","9","1990","MONDAY"
+"4","10","1990","TUESDAY"
+"4","11","1990","WEDNESDAY"
+"4","12","1990","THURSDAY"
+"4","13","1990","FRIDAY"
+"4","14","1990","SATURDAY"
+"4","15","1990","SUNDAY"
+"4","16","1990","MONDAY"
+"4","17","1990","TUESDAY"
+"4","18","1990","WEDNESDAY"
+"4","19","1990","THURSDAY"
+"4","20","1990","FRIDAY"
+"4","21","1990","SATURDAY"
+"4","22","1990","SUNDAY"
+"4","23","1990","MONDAY"
+"4","24","1990","TUESDAY"
+"4","25","1990","WEDNESDAY"
+"4","26","1990","THURSDAY"
+"4","27","1990","FRIDAY"
+"4","28","1990","SATURDAY"
+"4","29","1990","SUNDAY"
+"4","30","1990","MONDAY"
+"5","1","1990","TUESDAY"
+"5","2","1990","WEDNESDAY"
+"5","3","1990","THURSDAY"
+"5","4","1990","FRIDAY"
+"5","5","1990","SATURDAY"
+"5","6","1990","SUNDAY"
+"5","7","1990","MONDAY"
+"5","8","1990","TUESDAY"
+"5","9","1990","WEDNESDAY"
+"5","10","1990","THURSDAY"
+"5","11","1990","FRIDAY"
+"5","12","1990","SATURDAY"
+"5","13","1990","SUNDAY"
+"5","14","1990","MONDAY"
+"5","15","1990","TUESDAY"
+"5","16","1990","WEDNESDAY"
+"5","17","1990","THURSDAY"
+"5","18","1990","FRIDAY"
+"5","19","1990","SATURDAY"
+"5","20","1990","SUNDAY"
+"5","21","1990","MONDAY"
+"5","22","1990","TUESDAY"
+"5","23","1990","WEDNESDAY"
+"5","24","1990","THURSDAY"
+"5","25","1990","FRIDAY"
+"5","26","1990","SATURDAY"
+"5","27","1990","SUNDAY"
+"5","28","1990","MONDAY"
+"5","29","1990","TUESDAY"
+"5","30","1990","WEDNESDAY"
+"5","31","1990","THURSDAY"
+"6","1","1990","FRIDAY"
+"6","2","1990","SATURDAY"
+"6","3","1990","SUNDAY"
+"6","4","1990","MONDAY"
+"6","5","1990","TUESDAY"
+"6","6","1990","WEDNESDAY"
+"6","7","1990","THURSDAY"
+"6","8","1990","FRIDAY"
+"6","9","1990","SATURDAY"
+"6","10","1990","SUNDAY"
+"6","11","1990","MONDAY"
+"6","12","1990","TUESDAY"
+"6","13","1990","WEDNESDAY"
+"6","14","1990","THURSDAY"
+"6","15","1990","FRIDAY"
+"6","16","1990","SATURDAY"
+"6","17","1990","SUNDAY"
+"6","18","1990","MONDAY"
+"6","19","1990","TUESDAY"
+"6","20","1990","WEDNESDAY"
+"6","21","1990","THURSDAY"
+"6","22","1990","FRIDAY"
+"6","23","1990","SATURDAY"
+"6","24","1990","SUNDAY"
+"6","25","1990","MONDAY"
+"6","26","1990","TUESDAY"
+"6","27","1990","WEDNESDAY"
+"6","28","1990","THURSDAY"
+"6","29","1990","FRIDAY"
+"6","30","1990","SATURDAY"
+"7","1","1990","SUNDAY"
+"7","2","1990","MONDAY"
+"7","3","1990","TUESDAY"
+"7","4","1990","WEDNESDAY"
+"7","5","1990","THURSDAY"
+"7","6","1990","FRIDAY"
+"7","7","1990","SATURDAY"
+"7","8","1990","SUNDAY"
+"7","9","1990","MONDAY"
+"7","10","1990","TUESDAY"
+"7","11","1990","WEDNESDAY"
+"7","12","1990","THURSDAY"
+"7","13","1990","FRIDAY"
+"7","14","1990","SATURDAY"
+"7","15","1990","SUNDAY"
+"7","16","1990","MONDAY"
+"7","17","1990","TUESDAY"
+"7","18","1990","WEDNESDAY"
+"7","19","1990","THURSDAY"
+"7","20","1990","FRIDAY"
+"7","21","1990","SATURDAY"
+"7","22","1990","SUNDAY"
+"7","23","1990","MONDAY"
+"7","24","1990","TUESDAY"
+"7","25","1990","WEDNESDAY"
+"7","26","1990","THURSDAY"
+"7","27","1990","FRIDAY"
+"7","28","1990","SATURDAY"
+"7","29","1990","SUNDAY"
+"7","30","1990","MONDAY"
+"7","31","1990","TUESDAY"
+"8","1","1990","WEDNESDAY"
+"8","2","1990","THURSDAY"
+"8","3","1990","FRIDAY"
+"8","4","1990","SATURDAY"
+"8","5","1990","SUNDAY"
+"8","6","1990","MONDAY"
+"8","7","1990","TUESDAY"
+"8","8","1990","WEDNESDAY"
+"8","9","1990","THURSDAY"
+"8","10","1990","FRIDAY"
+"8","11","1990","SATURDAY"
+"8","12","1990","SUNDAY"
+"8","13","1990","MONDAY"
+"8","14","1990","TUESDAY"
+"8","15","1990","WEDNESDAY"
+"8","16","1990","THURSDAY"
+"8","17","1990","FRIDAY"
+"8","18","1990","SATURDAY"
+"8","19","1990","SUNDAY"
+"8","20","1990","MONDAY"
+"8","21","1990","TUESDAY"
+"8","22","1990","WEDNESDAY"
+"8","23","1990","THURSDAY"
+"8","24","1990","FRIDAY"
+"8","25","1990","SATURDAY"
+"8","26","1990","SUNDAY"
+"8","27","1990","MONDAY"
+"8","28","1990","TUESDAY"
+"8","29","1990","WEDNESDAY"
+"8","30","1990","THURSDAY"
+"8","31","1990","FRIDAY"
+"9","1","1990","SATURDAY"
+"9","2","1990","SUNDAY"
+"9","3","1990","MONDAY"
+"9","4","1990","TUESDAY"
+"9","5","1990","WEDNESDAY"
+"9","6","1990","THURSDAY"
+"9","7","1990","FRIDAY"
+"9","8","1990","SATURDAY"
+"9","9","1990","SUNDAY"
+"9","10","1990","MONDAY"
+"9","11","1990","TUESDAY"
+"9","12","1990","WEDNESDAY"
+"9","13","1990","THURSDAY"
+"9","14","1990","FRIDAY"
+"9","15","1990","SATURDAY"
+"9","16","1990","SUNDAY"
+"9","17","1990","MONDAY"
+"9","18","1990","TUESDAY"
+"9","19","1990","WEDNESDAY"
+"9","20","1990","THURSDAY"
+"9","21","1990","FRIDAY"
+"9","22","1990","SATURDAY"
+"9","23","1990","SUNDAY"
+"9","24","1990","MONDAY"
+"9","25","1990","TUESDAY"
+"9","26","1990","WEDNESDAY"
+"9","27","1990","THURSDAY"
+"9","28","1990","FRIDAY"
+"9","29","1990","SATURDAY"
+"9","30","1990","SUNDAY"
+"10","1","1990","MONDAY"
+"10","2","1990","TUESDAY"
+"10","3","1990","WEDNESDAY"
+"10","4","1990","THURSDAY"
+"10","5","1990","FRIDAY"
+"10","6","1990","SATURDAY"
+"10","7","1990","SUNDAY"
+"10","8","1990","MONDAY"
+"10","9","1990","TUESDAY"
+"10","10","1990","WEDNESDAY"
+"10","11","1990","THURSDAY"
+"10","12","1990","FRIDAY"
+"10","13","1990","SATURDAY"
+"10","14","1990","SUNDAY"
+"10","15","1990","MONDAY"
+"10","16","1990","TUESDAY"
+"10","17","1990","WEDNESDAY"
+"10","18","1990","THURSDAY"
+"10","19","1990","FRIDAY"
+"10","20","1990","SATURDAY"
+"10","21","1990","SUNDAY"
+"10","22","1990","MONDAY"
+"10","23","1990","TUESDAY"
+"10","24","1990","WEDNESDAY"
+"10","25","1990","THURSDAY"
+"10","26","1990","FRIDAY"
+"10","27","1990","SATURDAY"
+"10","28","1990","SUNDAY"
+"10","29","1990","MONDAY"
+"10","30","1990","TUESDAY"
+"10","31","1990","WEDNESDAY"
+"11","1","1990","THURSDAY"
+"11","2","1990","FRIDAY"
+"11","3","1990","SATURDAY"
+"11","4","1990","SUNDAY"
+"11","5","1990","MONDAY"
+"11","6","1990","TUESDAY"
+"11","7","1990","WEDNESDAY"
+"11","8","1990","THURSDAY"
+"11","9","1990","FRIDAY"
+"11","10","1990","SATURDAY"
+"11","11","1990","SUNDAY"
+"11","12","1990","MONDAY"
+"11","13","1990","TUESDAY"
+"11","14","1990","WEDNESDAY"
+"11","15","1990","THURSDAY"
+"11","16","1990","FRIDAY"
+"11","17","1990","SATURDAY"
+"11","18","1990","SUNDAY"
+"11","19","1990","MONDAY"
+"11","20","1990","TUESDAY"
+"11","21","1990","WEDNESDAY"
+"11","22","1990","THURSDAY"
+"11","23","1990","FRIDAY"
+"11","24","1990","SATURDAY"
+"11","25","1990","SUNDAY"
+"11","26","1990","MONDAY"
+"11","27","1990","TUESDAY"
+"11","28","1990","WEDNESDAY"
+"11","29","1990","THURSDAY"
+"11","30","1990","FRIDAY"
+"12","1","1990","SATURDAY"
+"12","2","1990","SUNDAY"
+"12","3","1990","MONDAY"
+"12","4","1990","TUESDAY"
+"12","5","1990","WEDNESDAY"
+"12","6","1990","THURSDAY"
+"12","7","1990","FRIDAY"
+"12","8","1990","SATURDAY"
+"12","9","1990","SUNDAY"
+"12","10","1990","MONDAY"
+"12","11","1990","TUESDAY"
+"12","12","1990","WEDNESDAY"
+"12","13","1990","THURSDAY"
+"12","14","1990","FRIDAY"
+"12","15","1990","SATURDAY"
+"12","16","1990","SUNDAY"
+"12","17","1990","MONDAY"
+"12","18","1990","TUESDAY"
+"12","19","1990","WEDNESDAY"
+"12","20","1990","THURSDAY"
+"12","21","1990","FRIDAY"
+"12","22","1990","SATURDAY"
+"12","23","1990","SUNDAY"
+"12","24","1990","MONDAY"
+"12","25","1990","TUESDAY"
+"12","26","1990","WEDNESDAY"
+"12","27","1990","THURSDAY"
+"12","28","1990","FRIDAY"
+"12","29","1990","SATURDAY"
+"12","30","1990","SUNDAY"
+"12","31","1990","MONDAY"
+"1","1","1991","TUESDAY"
+"1","2","1991","WEDNESDAY"
+"1","3","1991","THURSDAY"
+"1","4","1991","FRIDAY"
+"1","5","1991","SATURDAY"
+"1","6","1991","SUNDAY"
+"1","7","1991","MONDAY"
+"1","8","1991","TUESDAY"
+"1","9","1991","WEDNESDAY"
+"1","10","1991","THURSDAY"
+"1","11","1991","FRIDAY"
+"1","12","1991","SATURDAY"
+"1","13","1991","SUNDAY"
+"1","14","1991","MONDAY"
+"1","15","1991","TUESDAY"
+"1","16","1991","WEDNESDAY"
+"1","17","1991","THURSDAY"
+"1","18","1991","FRIDAY"
+"1","19","1991","SATURDAY"
+"1","20","1991","SUNDAY"
+"1","21","1991","MONDAY"
+"1","22","1991","TUESDAY"
+"1","23","1991","WEDNESDAY"
+"1","24","1991","THURSDAY"
+"1","25","1991","FRIDAY"
+"1","26","1991","SATURDAY"
+"1","27","1991","SUNDAY"
+"1","28","1991","MONDAY"
+"1","29","1991","TUESDAY"
+"1","30","1991","WEDNESDAY"
+"1","31","1991","THURSDAY"
+"2","1","1991","FRIDAY"
+"2","2","1991","SATURDAY"
+"2","3","1991","SUNDAY"
+"2","4","1991","MONDAY"
+"2","5","1991","TUESDAY"
+"2","6","1991","WEDNESDAY"
+"2","7","1991","THURSDAY"
+"2","8","1991","FRIDAY"
+"2","9","1991","SATURDAY"
+"2","10","1991","SUNDAY"
+"2","11","1991","MONDAY"
+"2","12","1991","TUESDAY"
+"2","13","1991","WEDNESDAY"
+"2","14","1991","THURSDAY"
+"2","15","1991","FRIDAY"
+"2","16","1991","SATURDAY"
+"2","17","1991","SUNDAY"
+"2","18","1991","MONDAY"
+"2","19","1991","TUESDAY"
+"2","20","1991","WEDNESDAY"
+"2","21","1991","THURSDAY"
+"2","22","1991","FRIDAY"
+"2","23","1991","SATURDAY"
+"2","24","1991","SUNDAY"
+"2","25","1991","MONDAY"
+"2","26","1991","TUESDAY"
+"2","27","1991","WEDNESDAY"
+"2","28","1991","THURSDAY"
+"3","1","1991","FRIDAY"
+"3","2","1991","SATURDAY"
+"3","3","1991","SUNDAY"
+"3","4","1991","MONDAY"
+"3","5","1991","TUESDAY"
+"3","6","1991","WEDNESDAY"
+"3","7","1991","THURSDAY"
+"3","8","1991","FRIDAY"
+"3","9","1991","SATURDAY"
+"3","10","1991","SUNDAY"
+"3","11","1991","MONDAY"
+"3","12","1991","TUESDAY"
+"3","13","1991","WEDNESDAY"
+"3","14","1991","THURSDAY"
+"3","15","1991","FRIDAY"
+"3","16","1991","SATURDAY"
+"3","17","1991","SUNDAY"
+"3","18","1991","MONDAY"
+"3","19","1991","TUESDAY"
+"3","20","1991","WEDNESDAY"
+"3","21","1991","THURSDAY"
+"3","22","1991","FRIDAY"
+"3","23","1991","SATURDAY"
+"3","24","1991","SUNDAY"
+"3","25","1991","MONDAY"
+"3","26","1991","TUESDAY"
+"3","27","1991","WEDNESDAY"
+"3","28","1991","THURSDAY"
+"3","29","1991","FRIDAY"
+"3","30","1991","SATURDAY"
+"3","31","1991","SUNDAY"
+"4","1","1991","MONDAY"
+"4","2","1991","TUESDAY"
+"4","3","1991","WEDNESDAY"
+"4","4","1991","THURSDAY"
+"4","5","1991","FRIDAY"
+"4","6","1991","SATURDAY"
+"4","7","1991","SUNDAY"
+"4","8","1991","MONDAY"
+"4","9","1991","TUESDAY"
+"4","10","1991","WEDNESDAY"
+"4","11","1991","THURSDAY"
+"4","12","1991","FRIDAY"
+"4","13","1991","SATURDAY"
+"4","14","1991","SUNDAY"
+"4","15","1991","MONDAY"
+"4","16","1991","TUESDAY"
+"4","17","1991","WEDNESDAY"
+"4","18","1991","THURSDAY"
+"4","19","1991","FRIDAY"
+"4","20","1991","SATURDAY"
+"4","21","1991","SUNDAY"
+"4","22","1991","MONDAY"
+"4","23","1991","TUESDAY"
+"4","24","1991","WEDNESDAY"
+"4","25","1991","THURSDAY"
+"4","26","1991","FRIDAY"
+"4","27","1991","SATURDAY"
+"4","28","1991","SUNDAY"
+"4","29","1991","MONDAY"
+"4","30","1991","TUESDAY"
+"5","1","1991","WEDNESDAY"
+"5","2","1991","THURSDAY"
+"5","3","1991","FRIDAY"
+"5","4","1991","SATURDAY"
+"5","5","1991","SUNDAY"
+"5","6","1991","MONDAY"
+"5","7","1991","TUESDAY"
+"5","8","1991","WEDNESDAY"
+"5","9","1991","THURSDAY"
+"5","10","1991","FRIDAY"
+"5","11","1991","SATURDAY"
+"5","12","1991","SUNDAY"
+"5","13","1991","MONDAY"
+"5","14","1991","TUESDAY"
+"5","15","1991","WEDNESDAY"
+"5","16","1991","THURSDAY"
+"5","17","1991","FRIDAY"
+"5","18","1991","SATURDAY"
+"5","19","1991","SUNDAY"
+"5","20","1991","MONDAY"
+"5","21","1991","TUESDAY"
+"5","22","1991","WEDNESDAY"
+"5","23","1991","THURSDAY"
+"5","24","1991","FRIDAY"
+"5","25","1991","SATURDAY"
+"5","26","1991","SUNDAY"
+"5","27","1991","MONDAY"
+"5","28","1991","TUESDAY"
+"5","29","1991","WEDNESDAY"
+"5","30","1991","THURSDAY"
+"5","31","1991","FRIDAY"
+"6","1","1991","SATURDAY"
+"6","2","1991","SUNDAY"
+"6","3","1991","MONDAY"
+"6","4","1991","TUESDAY"
+"6","5","1991","WEDNESDAY"
+"6","6","1991","THURSDAY"
+"6","7","1991","FRIDAY"
+"6","8","1991","SATURDAY"
+"6","9","1991","SUNDAY"
+"6","10","1991","MONDAY"
+"6","11","1991","TUESDAY"
+"6","12","1991","WEDNESDAY"
+"6","13","1991","THURSDAY"
+"6","14","1991","FRIDAY"
+"6","15","1991","SATURDAY"
+"6","16","1991","SUNDAY"
+"6","17","1991","MONDAY"
+"6","18","1991","TUESDAY"
+"6","19","1991","WEDNESDAY"
+"6","20","1991","THURSDAY"
+"6","21","1991","FRIDAY"
+"6","22","1991","SATURDAY"
+"6","23","1991","SUNDAY"
+"6","24","1991","MONDAY"
+"6","25","1991","TUESDAY"
+"6","26","1991","WEDNESDAY"
+"6","27","1991","THURSDAY"
+"6","28","1991","FRIDAY"
+"6","29","1991","SATURDAY"
+"6","30","1991","SUNDAY"
+"7","1","1991","MONDAY"
+"7","2","1991","TUESDAY"
+"7","3","1991","WEDNESDAY"
+"7","4","1991","THURSDAY"
+"7","5","1991","FRIDAY"
+"7","6","1991","SATURDAY"
+"7","7","1991","SUNDAY"
+"7","8","1991","MONDAY"
+"7","9","1991","TUESDAY"
+"7","10","1991","WEDNESDAY"
+"7","11","1991","THURSDAY"
+"7","12","1991","FRIDAY"
+"7","13","1991","SATURDAY"
+"7","14","1991","SUNDAY"
+"7","15","1991","MONDAY"
+"7","16","1991","TUESDAY"
+"7","17","1991","WEDNESDAY"
+"7","18","1991","THURSDAY"
+"7","19","1991","FRIDAY"
+"7","20","1991","SATURDAY"
+"7","21","1991","SUNDAY"
+"7","22","1991","MONDAY"
+"7","23","1991","TUESDAY"
+"7","24","1991","WEDNESDAY"
+"7","25","1991","THURSDAY"
+"7","26","1991","FRIDAY"
+"7","27","1991","SATURDAY"
+"7","28","1991","SUNDAY"
+"7","29","1991","MONDAY"
+"7","30","1991","TUESDAY"
+"7","31","1991","WEDNESDAY"
+"8","1","1991","THURSDAY"
+"8","2","1991","FRIDAY"
+"8","3","1991","SATURDAY"
+"8","4","1991","SUNDAY"
+"8","5","1991","MONDAY"
+"8","6","1991","TUESDAY"
+"8","7","1991","WEDNESDAY"
+"8","8","1991","THURSDAY"
+"8","9","1991","FRIDAY"
+"8","10","1991","SATURDAY"
+"8","11","1991","SUNDAY"
+"8","12","1991","MONDAY"
+"8","13","1991","TUESDAY"
+"8","14","1991","WEDNESDAY"
+"8","15","1991","THURSDAY"
+"8","16","1991","FRIDAY"
+"8","17","1991","SATURDAY"
+"8","18","1991","SUNDAY"
+"8","19","1991","MONDAY"
+"8","20","1991","TUESDAY"
+"8","21","1991","WEDNESDAY"
+"8","22","1991","THURSDAY"
+"8","23","1991","FRIDAY"
+"8","24","1991","SATURDAY"
+"8","25","1991","SUNDAY"
+"8","26","1991","MONDAY"
+"8","27","1991","TUESDAY"
+"8","28","1991","WEDNESDAY"
+"8","29","1991","THURSDAY"
+"8","30","1991","FRIDAY"
+"8","31","1991","SATURDAY"
+"9","1","1991","SUNDAY"
+"9","2","1991","MONDAY"
+"9","3","1991","TUESDAY"
+"9","4","1991","WEDNESDAY"
+"9","5","1991","THURSDAY"
+"9","6","1991","FRIDAY"
+"9","7","1991","SATURDAY"
+"9","8","1991","SUNDAY"
+"9","9","1991","MONDAY"
+"9","10","1991","TUESDAY"
+"9","11","1991","WEDNESDAY"
+"9","12","1991","THURSDAY"
+"9","13","1991","FRIDAY"
+"9","14","1991","SATURDAY"
+"9","15","1991","SUNDAY"
+"9","16","1991","MONDAY"
+"9","17","1991","TUESDAY"
+"9","18","1991","WEDNESDAY"
+"9","19","1991","THURSDAY"
+"9","20","1991","FRIDAY"
+"9","21","1991","SATURDAY"
+"9","22","1991","SUNDAY"
+"9","23","1991","MONDAY"
+"9","24","1991","TUESDAY"
+"9","25","1991","WEDNESDAY"
+"9","26","1991","THURSDAY"
+"9","27","1991","FRIDAY"
+"9","28","1991","SATURDAY"
+"9","29","1991","SUNDAY"
+"9","30","1991","MONDAY"
+"10","1","1991","TUESDAY"
+"10","2","1991","WEDNESDAY"
+"10","3","1991","THURSDAY"
+"10","4","1991","FRIDAY"
+"10","5","1991","SATURDAY"
+"10","6","1991","SUNDAY"
+"10","7","1991","MONDAY"
+"10","8","1991","TUESDAY"
+"10","9","1991","WEDNESDAY"
+"10","10","1991","THURSDAY"
+"10","11","1991","FRIDAY"
+"10","12","1991","SATURDAY"
+"10","13","1991","SUNDAY"
+"10","14","1991","MONDAY"
+"10","15","1991","TUESDAY"
+"10","16","1991","WEDNESDAY"
+"10","17","1991","THURSDAY"
+"10","18","1991","FRIDAY"
+"10","19","1991","SATURDAY"
+"10","20","1991","SUNDAY"
+"10","21","1991","MONDAY"
+"10","22","1991","TUESDAY"
+"10","23","1991","WEDNESDAY"
+"10","24","1991","THURSDAY"
+"10","25","1991","FRIDAY"
+"10","26","1991","SATURDAY"
+"10","27","1991","SUNDAY"
+"10","28","1991","MONDAY"
+"10","29","1991","TUESDAY"
+"10","30","1991","WEDNESDAY"
+"10","31","1991","THURSDAY"
+"11","1","1991","FRIDAY"
+"11","2","1991","SATURDAY"
+"11","3","1991","SUNDAY"
+"11","4","1991","MONDAY"
+"11","5","1991","TUESDAY"
+"11","6","1991","WEDNESDAY"
+"11","7","1991","THURSDAY"
+"11","8","1991","FRIDAY"
+"11","9","1991","SATURDAY"
+"11","10","1991","SUNDAY"
+"11","11","1991","MONDAY"
+"11","12","1991","TUESDAY"
+"11","13","1991","WEDNESDAY"
+"11","14","1991","THURSDAY"
+"11","15","1991","FRIDAY"
+"11","16","1991","SATURDAY"
+"11","17","1991","SUNDAY"
+"11","18","1991","MONDAY"
+"11","19","1991","TUESDAY"
+"11","20","1991","WEDNESDAY"
+"11","21","1991","THURSDAY"
+"11","22","1991","FRIDAY"
+"11","23","1991","SATURDAY"
+"11","24","1991","SUNDAY"
+"11","25","1991","MONDAY"
+"11","26","1991","TUESDAY"
+"11","27","1991","WEDNESDAY"
+"11","28","1991","THURSDAY"
+"11","29","1991","FRIDAY"
+"11","30","1991","SATURDAY"
+"12","1","1991","SUNDAY"
+"12","2","1991","MONDAY"
+"12","3","1991","TUESDAY"
+"12","4","1991","WEDNESDAY"
+"12","5","1991","THURSDAY"
+"12","6","1991","FRIDAY"
+"12","7","1991","SATURDAY"
+"12","8","1991","SUNDAY"
+"12","9","1991","MONDAY"
+"12","10","1991","TUESDAY"
+"12","11","1991","WEDNESDAY"
+"12","12","1991","THURSDAY"
+"12","13","1991","FRIDAY"
+"12","14","1991","SATURDAY"
+"12","15","1991","SUNDAY"
+"12","16","1991","MONDAY"
+"12","17","1991","TUESDAY"
+"12","18","1991","WEDNESDAY"
+"12","19","1991","THURSDAY"
+"12","20","1991","FRIDAY"
+"12","21","1991","SATURDAY"
+"12","22","1991","SUNDAY"
+"12","23","1991","MONDAY"
+"12","24","1991","TUESDAY"
+"12","25","1991","WEDNESDAY"
+"12","26","1991","THURSDAY"
+"12","27","1991","FRIDAY"
+"12","28","1991","SATURDAY"
+"12","29","1991","SUNDAY"
+"12","30","1991","MONDAY"
+"12","31","1991","TUESDAY"
+"1","1","1992","WEDNESDAY"
+"1","2","1992","THURSDAY"
+"1","3","1992","FRIDAY"
+"1","4","1992","SATURDAY"
+"1","5","1992","SUNDAY"
+"1","6","1992","MONDAY"
+"1","7","1992","TUESDAY"
+"1","8","1992","WEDNESDAY"
+"1","9","1992","THURSDAY"
+"1","10","1992","FRIDAY"
+"1","11","1992","SATURDAY"
+"1","12","1992","SUNDAY"
+"1","13","1992","MONDAY"
+"1","14","1992","TUESDAY"
+"1","15","1992","WEDNESDAY"
+"1","16","1992","THURSDAY"
+"1","17","1992","FRIDAY"
+"1","18","1992","SATURDAY"
+"1","19","1992","SUNDAY"
+"1","20","1992","MONDAY"
+"1","21","1992","TUESDAY"
+"1","22","1992","WEDNESDAY"
+"1","23","1992","THURSDAY"
+"1","24","1992","FRIDAY"
+"1","25","1992","SATURDAY"
+"1","26","1992","SUNDAY"
+"1","27","1992","MONDAY"
+"1","28","1992","TUESDAY"
+"1","29","1992","WEDNESDAY"
+"1","30","1992","THURSDAY"
+"1","31","1992","FRIDAY"
+"2","1","1992","SATURDAY"
+"2","2","1992","SUNDAY"
+"2","3","1992","MONDAY"
+"2","4","1992","TUESDAY"
+"2","5","1992","WEDNESDAY"
+"2","6","1992","THURSDAY"
+"2","7","1992","FRIDAY"
+"2","8","1992","SATURDAY"
+"2","9","1992","SUNDAY"
+"2","10","1992","MONDAY"
+"2","11","1992","TUESDAY"
+"2","12","1992","WEDNESDAY"
+"2","13","1992","THURSDAY"
+"2","14","1992","FRIDAY"
+"2","15","1992","SATURDAY"
+"2","16","1992","SUNDAY"
+"2","17","1992","MONDAY"
+"2","18","1992","TUESDAY"
+"2","19","1992","WEDNESDAY"
+"2","20","1992","THURSDAY"
+"2","21","1992","FRIDAY"
+"2","22","1992","SATURDAY"
+"2","23","1992","SUNDAY"
+"2","24","1992","MONDAY"
+"2","25","1992","TUESDAY"
+"2","26","1992","WEDNESDAY"
+"2","27","1992","THURSDAY"
+"2","28","1992","FRIDAY"
+"2","29","1992","SATURDAY"
+"3","1","1992","SUNDAY"
+"3","2","1992","MONDAY"
+"3","3","1992","TUESDAY"
+"3","4","1992","WEDNESDAY"
+"3","5","1992","THURSDAY"
+"3","6","1992","FRIDAY"
+"3","7","1992","SATURDAY"
+"3","8","1992","SUNDAY"
+"3","9","1992","MONDAY"
+"3","10","1992","TUESDAY"
+"3","11","1992","WEDNESDAY"
+"3","12","1992","THURSDAY"
+"3","13","1992","FRIDAY"
+"3","14","1992","SATURDAY"
+"3","15","1992","SUNDAY"
+"3","16","1992","MONDAY"
+"3","17","1992","TUESDAY"
+"3","18","1992","WEDNESDAY"
+"3","19","1992","THURSDAY"
+"3","20","1992","FRIDAY"
+"3","21","1992","SATURDAY"
+"3","22","1992","SUNDAY"
+"3","23","1992","MONDAY"
+"3","24","1992","TUESDAY"
+"3","25","1992","WEDNESDAY"
+"3","26","1992","THURSDAY"
+"3","27","1992","FRIDAY"
+"3","28","1992","SATURDAY"
+"3","29","1992","SUNDAY"
+"3","30","1992","MONDAY"
+"3","31","1992","TUESDAY"
+"4","1","1992","WEDNESDAY"
+"4","2","1992","THURSDAY"
+"4","3","1992","FRIDAY"
+"4","4","1992","SATURDAY"
+"4","5","1992","SUNDAY"
+"4","6","1992","MONDAY"
+"4","7","1992","TUESDAY"
+"4","8","1992","WEDNESDAY"
+"4","9","1992","THURSDAY"
+"4","10","1992","FRIDAY"
+"4","11","1992","SATURDAY"
+"4","12","1992","SUNDAY"
+"4","13","1992","MONDAY"
+"4","14","1992","TUESDAY"
+"4","15","1992","WEDNESDAY"
+"4","16","1992","THURSDAY"
+"4","17","1992","FRIDAY"
+"4","18","1992","SATURDAY"
+"4","19","1992","SUNDAY"
+"4","20","1992","MONDAY"
+"4","21","1992","TUESDAY"
+"4","22","1992","WEDNESDAY"
+"4","23","1992","THURSDAY"
+"4","24","1992","FRIDAY"
+"4","25","1992","SATURDAY"
+"4","26","1992","SUNDAY"
+"4","27","1992","MONDAY"
+"4","28","1992","TUESDAY"
+"4","29","1992","WEDNESDAY"
+"4","30","1992","THURSDAY"
+"5","1","1992","FRIDAY"
+"5","2","1992","SATURDAY"
+"5","3","1992","SUNDAY"
+"5","4","1992","MONDAY"
+"5","5","1992","TUESDAY"
+"5","6","1992","WEDNESDAY"
+"5","7","1992","THURSDAY"
+"5","8","1992","FRIDAY"
+"5","9","1992","SATURDAY"
+"5","10","1992","SUNDAY"
+"5","11","1992","MONDAY"
+"5","12","1992","TUESDAY"
+"5","13","1992","WEDNESDAY"
+"5","14","1992","THURSDAY"
+"5","15","1992","FRIDAY"
+"5","16","1992","SATURDAY"
+"5","17","1992","SUNDAY"
+"5","18","1992","MONDAY"
+"5","19","1992","TUESDAY"
+"5","20","1992","WEDNESDAY"
+"5","21","1992","THURSDAY"
+"5","22","1992","FRIDAY"
+"5","23","1992","SATURDAY"
+"5","24","1992","SUNDAY"
+"5","25","1992","MONDAY"
+"5","26","1992","TUESDAY"
+"5","27","1992","WEDNESDAY"
+"5","28","1992","THURSDAY"
+"5","29","1992","FRIDAY"
+"5","30","1992","SATURDAY"
+"5","31","1992","SUNDAY"
+"6","1","1992","MONDAY"
+"6","2","1992","TUESDAY"
+"6","3","1992","WEDNESDAY"
+"6","4","1992","THURSDAY"
+"6","5","1992","FRIDAY"
+"6","6","1992","SATURDAY"
+"6","7","1992","SUNDAY"
+"6","8","1992","MONDAY"
+"6","9","1992","TUESDAY"
+"6","10","1992","WEDNESDAY"
+"6","11","1992","THURSDAY"
+"6","12","1992","FRIDAY"
+"6","13","1992","SATURDAY"
+"6","14","1992","SUNDAY"
+"6","15","1992","MONDAY"
+"6","16","1992","TUESDAY"
+"6","17","1992","WEDNESDAY"
+"6","18","1992","THURSDAY"
+"6","19","1992","FRIDAY"
+"6","20","1992","SATURDAY"
+"6","21","1992","SUNDAY"
+"6","22","1992","MONDAY"
+"6","23","1992","TUESDAY"
+"6","24","1992","WEDNESDAY"
+"6","25","1992","THURSDAY"
+"6","26","1992","FRIDAY"
+"6","27","1992","SATURDAY"
+"6","28","1992","SUNDAY"
+"6","29","1992","MONDAY"
+"6","30","1992","TUESDAY"
+"7","1","1992","WEDNESDAY"
+"7","2","1992","THURSDAY"
+"7","3","1992","FRIDAY"
+"7","4","1992","SATURDAY"
+"7","5","1992","SUNDAY"
+"7","6","1992","MONDAY"
+"7","7","1992","TUESDAY"
+"7","8","1992","WEDNESDAY"
+"7","9","1992","THURSDAY"
+"7","10","1992","FRIDAY"
+"7","11","1992","SATURDAY"
+"7","12","1992","SUNDAY"
+"7","13","1992","MONDAY"
+"7","14","1992","TUESDAY"
+"7","15","1992","WEDNESDAY"
+"7","16","1992","THURSDAY"
+"7","17","1992","FRIDAY"
+"7","18","1992","SATURDAY"
+"7","19","1992","SUNDAY"
+"7","20","1992","MONDAY"
+"7","21","1992","TUESDAY"
+"7","22","1992","WEDNESDAY"
+"7","23","1992","THURSDAY"
+"7","24","1992","FRIDAY"
+"7","25","1992","SATURDAY"
+"7","26","1992","SUNDAY"
+"7","27","1992","MONDAY"
+"7","28","1992","TUESDAY"
+"7","29","1992","WEDNESDAY"
+"7","30","1992","THURSDAY"
+"7","31","1992","FRIDAY"
+"8","1","1992","SATURDAY"
+"8","2","1992","SUNDAY"
+"8","3","1992","MONDAY"
+"8","4","1992","TUESDAY"
+"8","5","1992","WEDNESDAY"
+"8","6","1992","THURSDAY"
+"8","7","1992","FRIDAY"
+"8","8","1992","SATURDAY"
+"8","9","1992","SUNDAY"
+"8","10","1992","MONDAY"
+"8","11","1992","TUESDAY"
+"8","12","1992","WEDNESDAY"
+"8","13","1992","THURSDAY"
+"8","14","1992","FRIDAY"
+"8","15","1992","SATURDAY"
+"8","16","1992","SUNDAY"
+"8","17","1992","MONDAY"
+"8","18","1992","TUESDAY"
+"8","19","1992","WEDNESDAY"
+"8","20","1992","THURSDAY"
+"8","21","1992","FRIDAY"
+"8","22","1992","SATURDAY"
+"8","23","1992","SUNDAY"
+"8","24","1992","MONDAY"
+"8","25","1992","TUESDAY"
+"8","26","1992","WEDNESDAY"
+"8","27","1992","THURSDAY"
+"8","28","1992","FRIDAY"
+"8","29","1992","SATURDAY"
+"8","30","1992","SUNDAY"
+"8","31","1992","MONDAY"
+"9","1","1992","TUESDAY"
+"9","2","1992","WEDNESDAY"
+"9","3","1992","THURSDAY"
+"9","4","1992","FRIDAY"
+"9","5","1992","SATURDAY"
+"9","6","1992","SUNDAY"
+"9","7","1992","MONDAY"
+"9","8","1992","TUESDAY"
+"9","9","1992","WEDNESDAY"
+"9","10","1992","THURSDAY"
+"9","11","1992","FRIDAY"
+"9","12","1992","SATURDAY"
+"9","13","1992","SUNDAY"
+"9","14","1992","MONDAY"
+"9","15","1992","TUESDAY"
+"9","16","1992","WEDNESDAY"
+"9","17","1992","THURSDAY"
+"9","18","1992","FRIDAY"
+"9","19","1992","SATURDAY"
+"9","20","1992","SUNDAY"
+"9","21","1992","MONDAY"
+"9","22","1992","TUESDAY"
+"9","23","1992","WEDNESDAY"
+"9","24","1992","THURSDAY"
+"9","25","1992","FRIDAY"
+"9","26","1992","SATURDAY"
+"9","27","1992","SUNDAY"
+"9","28","1992","MONDAY"
+"9","29","1992","TUESDAY"
+"9","30","1992","WEDNESDAY"
+"10","1","1992","THURSDAY"
+"10","2","1992","FRIDAY"
+"10","3","1992","SATURDAY"
+"10","4","1992","SUNDAY"
+"10","5","1992","MONDAY"
+"10","6","1992","TUESDAY"
+"10","7","1992","WEDNESDAY"
+"10","8","1992","THURSDAY"
+"10","9","1992","FRIDAY"
+"10","10","1992","SATURDAY"
+"10","11","1992","SUNDAY"
+"10","12","1992","MONDAY"
+"10","13","1992","TUESDAY"
+"10","14","1992","WEDNESDAY"
+"10","15","1992","THURSDAY"
+"10","16","1992","FRIDAY"
+"10","17","1992","SATURDAY"
+"10","18","1992","SUNDAY"
+"10","19","1992","MONDAY"
+"10","20","1992","TUESDAY"
+"10","21","1992","WEDNESDAY"
+"10","22","1992","THURSDAY"
+"10","23","1992","FRIDAY"
+"10","24","1992","SATURDAY"
+"10","25","1992","SUNDAY"
+"10","26","1992","MONDAY"
+"10","27","1992","TUESDAY"
+"10","28","1992","WEDNESDAY"
+"10","29","1992","THURSDAY"
+"10","30","1992","FRIDAY"
+"10","31","1992","SATURDAY"
+"11","1","1992","SUNDAY"
+"11","2","1992","MONDAY"
+"11","3","1992","TUESDAY"
+"11","4","1992","WEDNESDAY"
+"11","5","1992","THURSDAY"
+"11","6","1992","FRIDAY"
+"11","7","1992","SATURDAY"
+"11","8","1992","SUNDAY"
+"11","9","1992","MONDAY"
+"11","10","1992","TUESDAY"
+"11","11","1992","WEDNESDAY"
+"11","12","1992","THURSDAY"
+"11","13","1992","FRIDAY"
+"11","14","1992","SATURDAY"
+"11","15","1992","SUNDAY"
+"11","16","1992","MONDAY"
+"11","17","1992","TUESDAY"
+"11","18","1992","WEDNESDAY"
+"11","19","1992","THURSDAY"
+"11","20","1992","FRIDAY"
+"11","21","1992","SATURDAY"
+"11","22","1992","SUNDAY"
+"11","23","1992","MONDAY"
+"11","24","1992","TUESDAY"
+"11","25","1992","WEDNESDAY"
+"11","26","1992","THURSDAY"
+"11","27","1992","FRIDAY"
+"11","28","1992","SATURDAY"
+"11","29","1992","SUNDAY"
+"11","30","1992","MONDAY"
+"12","1","1992","TUESDAY"
+"12","2","1992","WEDNESDAY"
+"12","3","1992","THURSDAY"
+"12","4","1992","FRIDAY"
+"12","5","1992","SATURDAY"
+"12","6","1992","SUNDAY"
+"12","7","1992","MONDAY"
+"12","8","1992","TUESDAY"
+"12","9","1992","WEDNESDAY"
+"12","10","1992","THURSDAY"
+"12","11","1992","FRIDAY"
+"12","12","1992","SATURDAY"
+"12","13","1992","SUNDAY"
+"12","14","1992","MONDAY"
+"12","15","1992","TUESDAY"
+"12","16","1992","WEDNESDAY"
+"12","17","1992","THURSDAY"
+"12","18","1992","FRIDAY"
+"12","19","1992","SATURDAY"
+"12","20","1992","SUNDAY"
+"12","21","1992","MONDAY"
+"12","22","1992","TUESDAY"
+"12","23","1992","WEDNESDAY"
+"12","24","1992","THURSDAY"
+"12","25","1992","FRIDAY"
+"12","26","1992","SATURDAY"
+"12","27","1992","SUNDAY"
+"12","28","1992","MONDAY"
+"12","29","1992","TUESDAY"
+"12","30","1992","WEDNESDAY"
+"12","31","1992","THURSDAY"
+"1","1","1993","FRIDAY"
+"1","2","1993","SATURDAY"
+"1","3","1993","SUNDAY"
+"1","4","1993","MONDAY"
+"1","5","1993","TUESDAY"
+"1","6","1993","WEDNESDAY"
+"1","7","1993","THURSDAY"
+"1","8","1993","FRIDAY"
+"1","9","1993","SATURDAY"
+"1","10","1993","SUNDAY"
+"1","11","1993","MONDAY"
+"1","12","1993","TUESDAY"
+"1","13","1993","WEDNESDAY"
+"1","14","1993","THURSDAY"
+"1","15","1993","FRIDAY"
+"1","16","1993","SATURDAY"
+"1","17","1993","SUNDAY"
+"1","18","1993","MONDAY"
+"1","19","1993","TUESDAY"
+"1","20","1993","WEDNESDAY"
+"1","21","1993","THURSDAY"
+"1","22","1993","FRIDAY"
+"1","23","1993","SATURDAY"
+"1","24","1993","SUNDAY"
+"1","25","1993","MONDAY"
+"1","26","1993","TUESDAY"
+"1","27","1993","WEDNESDAY"
+"1","28","1993","THURSDAY"
+"1","29","1993","FRIDAY"
+"1","30","1993","SATURDAY"
+"1","31","1993","SUNDAY"
+"2","1","1993","MONDAY"
+"2","2","1993","TUESDAY"
+"2","3","1993","WEDNESDAY"
+"2","4","1993","THURSDAY"
+"2","5","1993","FRIDAY"
+"2","6","1993","SATURDAY"
+"2","7","1993","SUNDAY"
+"2","8","1993","MONDAY"
+"2","9","1993","TUESDAY"
+"2","10","1993","WEDNESDAY"
+"2","11","1993","THURSDAY"
+"2","12","1993","FRIDAY"
+"2","13","1993","SATURDAY"
+"2","14","1993","SUNDAY"
+"2","15","1993","MONDAY"
+"2","16","1993","TUESDAY"
+"2","17","1993","WEDNESDAY"
+"2","18","1993","THURSDAY"
+"2","19","1993","FRIDAY"
+"2","20","1993","SATURDAY"
+"2","21","1993","SUNDAY"
+"2","22","1993","MONDAY"
+"2","23","1993","TUESDAY"
+"2","24","1993","WEDNESDAY"
+"2","25","1993","THURSDAY"
+"2","26","1993","FRIDAY"
+"2","27","1993","SATURDAY"
+"2","28","1993","SUNDAY"
+"3","1","1993","MONDAY"
+"3","2","1993","TUESDAY"
+"3","3","1993","WEDNESDAY"
+"3","4","1993","THURSDAY"
+"3","5","1993","FRIDAY"
+"3","6","1993","SATURDAY"
+"3","7","1993","SUNDAY"
+"3","8","1993","MONDAY"
+"3","9","1993","TUESDAY"
+"3","10","1993","WEDNESDAY"
+"3","11","1993","THURSDAY"
+"3","12","1993","FRIDAY"
+"3","13","1993","SATURDAY"
+"3","14","1993","SUNDAY"
+"3","15","1993","MONDAY"
+"3","16","1993","TUESDAY"
+"3","17","1993","WEDNESDAY"
+"3","18","1993","THURSDAY"
+"3","19","1993","FRIDAY"
+"3","20","1993","SATURDAY"
+"3","21","1993","SUNDAY"
+"3","22","1993","MONDAY"
+"3","23","1993","TUESDAY"
+"3","24","1993","WEDNESDAY"
+"3","25","1993","THURSDAY"
+"3","26","1993","FRIDAY"
+"3","27","1993","SATURDAY"
+"3","28","1993","SUNDAY"
+"3","29","1993","MONDAY"
+"3","30","1993","TUESDAY"
+"3","31","1993","WEDNESDAY"
+"4","1","1993","THURSDAY"
+"4","2","1993","FRIDAY"
+"4","3","1993","SATURDAY"
+"4","4","1993","SUNDAY"
+"4","5","1993","MONDAY"
+"4","6","1993","TUESDAY"
+"4","7","1993","WEDNESDAY"
+"4","8","1993","THURSDAY"
+"4","9","1993","FRIDAY"
+"4","10","1993","SATURDAY"
+"4","11","1993","SUNDAY"
+"4","12","1993","MONDAY"
+"4","13","1993","TUESDAY"
+"4","14","1993","WEDNESDAY"
+"4","15","1993","THURSDAY"
+"4","16","1993","FRIDAY"
+"4","17","1993","SATURDAY"
+"4","18","1993","SUNDAY"
+"4","19","1993","MONDAY"
+"4","20","1993","TUESDAY"
+"4","21","1993","WEDNESDAY"
+"4","22","1993","THURSDAY"
+"4","23","1993","FRIDAY"
+"4","24","1993","SATURDAY"
+"4","25","1993","SUNDAY"
+"4","26","1993","MONDAY"
+"4","27","1993","TUESDAY"
+"4","28","1993","WEDNESDAY"
+"4","29","1993","THURSDAY"
+"4","30","1993","FRIDAY"
+"5","1","1993","SATURDAY"
+"5","2","1993","SUNDAY"
+"5","3","1993","MONDAY"
+"5","4","1993","TUESDAY"
+"5","5","1993","WEDNESDAY"
+"5","6","1993","THURSDAY"
+"5","7","1993","FRIDAY"
+"5","8","1993","SATURDAY"
+"5","9","1993","SUNDAY"
+"5","10","1993","MONDAY"
+"5","11","1993","TUESDAY"
+"5","12","1993","WEDNESDAY"
+"5","13","1993","THURSDAY"
+"5","14","1993","FRIDAY"
+"5","15","1993","SATURDAY"
+"5","16","1993","SUNDAY"
+"5","17","1993","MONDAY"
+"5","18","1993","TUESDAY"
+"5","19","1993","WEDNESDAY"
+"5","20","1993","THURSDAY"
+"5","21","1993","FRIDAY"
+"5","22","1993","SATURDAY"
+"5","23","1993","SUNDAY"
+"5","24","1993","MONDAY"
+"5","25","1993","TUESDAY"
+"5","26","1993","WEDNESDAY"
+"5","27","1993","THURSDAY"
+"5","28","1993","FRIDAY"
+"5","29","1993","SATURDAY"
+"5","30","1993","SUNDAY"
+"5","31","1993","MONDAY"
+"6","1","1993","TUESDAY"
+"6","2","1993","WEDNESDAY"
+"6","3","1993","THURSDAY"
+"6","4","1993","FRIDAY"
+"6","5","1993","SATURDAY"
+"6","6","1993","SUNDAY"
+"6","7","1993","MONDAY"
+"6","8","1993","TUESDAY"
+"6","9","1993","WEDNESDAY"
+"6","10","1993","THURSDAY"
+"6","11","1993","FRIDAY"
+"6","12","1993","SATURDAY"
+"6","13","1993","SUNDAY"
+"6","14","1993","MONDAY"
+"6","15","1993","TUESDAY"
+"6","16","1993","WEDNESDAY"
+"6","17","1993","THURSDAY"
+"6","18","1993","FRIDAY"
+"6","19","1993","SATURDAY"
+"6","20","1993","SUNDAY"
+"6","21","1993","MONDAY"
+"6","22","1993","TUESDAY"
+"6","23","1993","WEDNESDAY"
+"6","24","1993","THURSDAY"
+"6","25","1993","FRIDAY"
+"6","26","1993","SATURDAY"
+"6","27","1993","SUNDAY"
+"6","28","1993","MONDAY"
+"6","29","1993","TUESDAY"
+"6","30","1993","WEDNESDAY"
+"7","1","1993","THURSDAY"
+"7","2","1993","FRIDAY"
+"7","3","1993","SATURDAY"
+"7","4","1993","SUNDAY"
+"7","5","1993","MONDAY"
+"7","6","1993","TUESDAY"
+"7","7","1993","WEDNESDAY"
+"7","8","1993","THURSDAY"
+"7","9","1993","FRIDAY"
+"7","10","1993","SATURDAY"
+"7","11","1993","SUNDAY"
+"7","12","1993","MONDAY"
+"7","13","1993","TUESDAY"
+"7","14","1993","WEDNESDAY"
+"7","15","1993","THURSDAY"
+"7","16","1993","FRIDAY"
+"7","17","1993","SATURDAY"
+"7","18","1993","SUNDAY"
+"7","19","1993","MONDAY"
+"7","20","1993","TUESDAY"
+"7","21","1993","WEDNESDAY"
+"7","22","1993","THURSDAY"
+"7","23","1993","FRIDAY"
+"7","24","1993","SATURDAY"
+"7","25","1993","SUNDAY"
+"7","26","1993","MONDAY"
+"7","27","1993","TUESDAY"
+"7","28","1993","WEDNESDAY"
+"7","29","1993","THURSDAY"
+"7","30","1993","FRIDAY"
+"7","31","1993","SATURDAY"
+"8","1","1993","SUNDAY"
+"8","2","1993","MONDAY"
+"8","3","1993","TUESDAY"
+"8","4","1993","WEDNESDAY"
+"8","5","1993","THURSDAY"
+"8","6","1993","FRIDAY"
+"8","7","1993","SATURDAY"
+"8","8","1993","SUNDAY"
+"8","9","1993","MONDAY"
+"8","10","1993","TUESDAY"
+"8","11","1993","WEDNESDAY"
+"8","12","1993","THURSDAY"
+"8","13","1993","FRIDAY"
+"8","14","1993","SATURDAY"
+"8","15","1993","SUNDAY"
+"8","16","1993","MONDAY"
+"8","17","1993","TUESDAY"
+"8","18","1993","WEDNESDAY"
+"8","19","1993","THURSDAY"
+"8","20","1993","FRIDAY"
+"8","21","1993","SATURDAY"
+"8","22","1993","SUNDAY"
+"8","23","1993","MONDAY"
+"8","24","1993","TUESDAY"
+"8","25","1993","WEDNESDAY"
+"8","26","1993","THURSDAY"
+"8","27","1993","FRIDAY"
+"8","28","1993","SATURDAY"
+"8","29","1993","SUNDAY"
+"8","30","1993","MONDAY"
+"8","31","1993","TUESDAY"
+"9","1","1993","WEDNESDAY"
+"9","2","1993","THURSDAY"
+"9","3","1993","FRIDAY"
+"9","4","1993","SATURDAY"
+"9","5","1993","SUNDAY"
+"9","6","1993","MONDAY"
+"9","7","1993","TUESDAY"
+"9","8","1993","WEDNESDAY"
+"9","9","1993","THURSDAY"
+"9","10","1993","FRIDAY"
+"9","11","1993","SATURDAY"
+"9","12","1993","SUNDAY"
+"9","13","1993","MONDAY"
+"9","14","1993","TUESDAY"
+"9","15","1993","WEDNESDAY"
+"9","16","1993","THURSDAY"
+"9","17","1993","FRIDAY"
+"9","18","1993","SATURDAY"
+"9","19","1993","SUNDAY"
+"9","20","1993","MONDAY"
+"9","21","1993","TUESDAY"
+"9","22","1993","WEDNESDAY"
+"9","23","1993","THURSDAY"
+"9","24","1993","FRIDAY"
+"9","25","1993","SATURDAY"
+"9","26","1993","SUNDAY"
+"9","27","1993","MONDAY"
+"9","28","1993","TUESDAY"
+"9","29","1993","WEDNESDAY"
+"9","30","1993","THURSDAY"
+"10","1","1993","FRIDAY"
+"10","2","1993","SATURDAY"
+"10","3","1993","SUNDAY"
+"10","4","1993","MONDAY"
+"10","5","1993","TUESDAY"
+"10","6","1993","WEDNESDAY"
+"10","7","1993","THURSDAY"
+"10","8","1993","FRIDAY"
+"10","9","1993","SATURDAY"
+"10","10","1993","SUNDAY"
+"10","11","1993","MONDAY"
+"10","12","1993","TUESDAY"
+"10","13","1993","WEDNESDAY"
+"10","14","1993","THURSDAY"
+"10","15","1993","FRIDAY"
+"10","16","1993","SATURDAY"
+"10","17","1993","SUNDAY"
+"10","18","1993","MONDAY"
+"10","19","1993","TUESDAY"
+"10","20","1993","WEDNESDAY"
+"10","21","1993","THURSDAY"
+"10","22","1993","FRIDAY"
+"10","23","1993","SATURDAY"
+"10","24","1993","SUNDAY"
+"10","25","1993","MONDAY"
+"10","26","1993","TUESDAY"
+"10","27","1993","WEDNESDAY"
+"10","28","1993","THURSDAY"
+"10","29","1993","FRIDAY"
+"10","30","1993","SATURDAY"
+"10","31","1993","SUNDAY"
+"11","1","1993","MONDAY"
+"11","2","1993","TUESDAY"
+"11","3","1993","WEDNESDAY"
+"11","4","1993","THURSDAY"
+"11","5","1993","FRIDAY"
+"11","6","1993","SATURDAY"
+"11","7","1993","SUNDAY"
+"11","8","1993","MONDAY"
+"11","9","1993","TUESDAY"
+"11","10","1993","WEDNESDAY"
+"11","11","1993","THURSDAY"
+"11","12","1993","FRIDAY"
+"11","13","1993","SATURDAY"
+"11","14","1993","SUNDAY"
+"11","15","1993","MONDAY"
+"11","16","1993","TUESDAY"
+"11","17","1993","WEDNESDAY"
+"11","18","1993","THURSDAY"
+"11","19","1993","FRIDAY"
+"11","20","1993","SATURDAY"
+"11","21","1993","SUNDAY"
+"11","22","1993","MONDAY"
+"11","23","1993","TUESDAY"
+"11","24","1993","WEDNESDAY"
+"11","25","1993","THURSDAY"
+"11","26","1993","FRIDAY"
+"11","27","1993","SATURDAY"
+"11","28","1993","SUNDAY"
+"11","29","1993","MONDAY"
+"11","30","1993","TUESDAY"
+"12","1","1993","WEDNESDAY"
+"12","2","1993","THURSDAY"
+"12","3","1993","FRIDAY"
+"12","4","1993","SATURDAY"
+"12","5","1993","SUNDAY"
+"12","6","1993","MONDAY"
+"12","7","1993","TUESDAY"
+"12","8","1993","WEDNESDAY"
+"12","9","1993","THURSDAY"
+"12","10","1993","FRIDAY"
+"12","11","1993","SATURDAY"
+"12","12","1993","SUNDAY"
+"12","13","1993","MONDAY"
+"12","14","1993","TUESDAY"
+"12","15","1993","WEDNESDAY"
+"12","16","1993","THURSDAY"
+"12","17","1993","FRIDAY"
+"12","18","1993","SATURDAY"
+"12","19","1993","SUNDAY"
+"12","20","1993","MONDAY"
+"12","21","1993","TUESDAY"
+"12","22","1993","WEDNESDAY"
+"12","23","1993","THURSDAY"
+"12","24","1993","FRIDAY"
+"12","25","1993","SATURDAY"
+"12","26","1993","SUNDAY"
+"12","27","1993","MONDAY"
+"12","28","1993","TUESDAY"
+"12","29","1993","WEDNESDAY"
+"12","30","1993","THURSDAY"
+"12","31","1993","FRIDAY"
+"1","1","1994","SATURDAY"
+"1","2","1994","SUNDAY"
+"1","3","1994","MONDAY"
+"1","4","1994","TUESDAY"
+"1","5","1994","WEDNESDAY"
+"1","6","1994","THURSDAY"
+"1","7","1994","FRIDAY"
+"1","8","1994","SATURDAY"
+"1","9","1994","SUNDAY"
+"1","10","1994","MONDAY"
+"1","11","1994","TUESDAY"
+"1","12","1994","WEDNESDAY"
+"1","13","1994","THURSDAY"
+"1","14","1994","FRIDAY"
+"1","15","1994","SATURDAY"
+"1","16","1994","SUNDAY"
+"1","17","1994","MONDAY"
+"1","18","1994","TUESDAY"
+"1","19","1994","WEDNESDAY"
+"1","20","1994","THURSDAY"
+"1","21","1994","FRIDAY"
+"1","22","1994","SATURDAY"
+"1","23","1994","SUNDAY"
+"1","24","1994","MONDAY"
+"1","25","1994","TUESDAY"
+"1","26","1994","WEDNESDAY"
+"1","27","1994","THURSDAY"
+"1","28","1994","FRIDAY"
+"1","29","1994","SATURDAY"
+"1","30","1994","SUNDAY"
+"1","31","1994","MONDAY"
+"2","1","1994","TUESDAY"
+"2","2","1994","WEDNESDAY"
+"2","3","1994","THURSDAY"
+"2","4","1994","FRIDAY"
+"2","5","1994","SATURDAY"
+"2","6","1994","SUNDAY"
+"2","7","1994","MONDAY"
+"2","8","1994","TUESDAY"
+"2","9","1994","WEDNESDAY"
+"2","10","1994","THURSDAY"
+"2","11","1994","FRIDAY"
+"2","12","1994","SATURDAY"
+"2","13","1994","SUNDAY"
+"2","14","1994","MONDAY"
+"2","15","1994","TUESDAY"
+"2","16","1994","WEDNESDAY"
+"2","17","1994","THURSDAY"
+"2","18","1994","FRIDAY"
+"2","19","1994","SATURDAY"
+"2","20","1994","SUNDAY"
+"2","21","1994","MONDAY"
+"2","22","1994","TUESDAY"
+"2","23","1994","WEDNESDAY"
+"2","24","1994","THURSDAY"
+"2","25","1994","FRIDAY"
+"2","26","1994","SATURDAY"
+"2","27","1994","SUNDAY"
+"2","28","1994","MONDAY"
+"3","1","1994","TUESDAY"
+"3","2","1994","WEDNESDAY"
+"3","3","1994","THURSDAY"
+"3","4","1994","FRIDAY"
+"3","5","1994","SATURDAY"
+"3","6","1994","SUNDAY"
+"3","7","1994","MONDAY"
+"3","8","1994","TUESDAY"
+"3","9","1994","WEDNESDAY"
+"3","10","1994","THURSDAY"
+"3","11","1994","FRIDAY"
+"3","12","1994","SATURDAY"
+"3","13","1994","SUNDAY"
+"3","14","1994","MONDAY"
+"3","15","1994","TUESDAY"
+"3","16","1994","WEDNESDAY"
+"3","17","1994","THURSDAY"
+"3","18","1994","FRIDAY"
+"3","19","1994","SATURDAY"
+"3","20","1994","SUNDAY"
+"3","21","1994","MONDAY"
+"3","22","1994","TUESDAY"
+"3","23","1994","WEDNESDAY"
+"3","24","1994","THURSDAY"
+"3","25","1994","FRIDAY"
+"3","26","1994","SATURDAY"
+"3","27","1994","SUNDAY"
+"3","28","1994","MONDAY"
+"3","29","1994","TUESDAY"
+"3","30","1994","WEDNESDAY"
+"3","31","1994","THURSDAY"
+"4","1","1994","FRIDAY"
+"4","2","1994","SATURDAY"
+"4","3","1994","SUNDAY"
+"4","4","1994","MONDAY"
+"4","5","1994","TUESDAY"
+"4","6","1994","WEDNESDAY"
+"4","7","1994","THURSDAY"
+"4","8","1994","FRIDAY"
+"4","9","1994","SATURDAY"
+"4","10","1994","SUNDAY"
+"4","11","1994","MONDAY"
+"4","12","1994","TUESDAY"
+"4","13","1994","WEDNESDAY"
+"4","14","1994","THURSDAY"
+"4","15","1994","FRIDAY"
+"4","16","1994","SATURDAY"
+"4","17","1994","SUNDAY"
+"4","18","1994","MONDAY"
+"4","19","1994","TUESDAY"
+"4","20","1994","WEDNESDAY"
+"4","21","1994","THURSDAY"
+"4","22","1994","FRIDAY"
+"4","23","1994","SATURDAY"
+"4","24","1994","SUNDAY"
+"4","25","1994","MONDAY"
+"4","26","1994","TUESDAY"
+"4","27","1994","WEDNESDAY"
+"4","28","1994","THURSDAY"
+"4","29","1994","FRIDAY"
+"4","30","1994","SATURDAY"
+"5","1","1994","SUNDAY"
+"5","2","1994","MONDAY"
+"5","3","1994","TUESDAY"
+"5","4","1994","WEDNESDAY"
+"5","5","1994","THURSDAY"
+"5","6","1994","FRIDAY"
+"5","7","1994","SATURDAY"
+"5","8","1994","SUNDAY"
+"5","9","1994","MONDAY"
+"5","10","1994","TUESDAY"
+"5","11","1994","WEDNESDAY"
+"5","12","1994","THURSDAY"
+"5","13","1994","FRIDAY"
+"5","14","1994","SATURDAY"
+"5","15","1994","SUNDAY"
+"5","16","1994","MONDAY"
+"5","17","1994","TUESDAY"
+"5","18","1994","WEDNESDAY"
+"5","19","1994","THURSDAY"
+"5","20","1994","FRIDAY"
+"5","21","1994","SATURDAY"
+"5","22","1994","SUNDAY"
+"5","23","1994","MONDAY"
+"5","24","1994","TUESDAY"
+"5","25","1994","WEDNESDAY"
+"5","26","1994","THURSDAY"
+"5","27","1994","FRIDAY"
+"5","28","1994","SATURDAY"
+"5","29","1994","SUNDAY"
+"5","30","1994","MONDAY"
+"5","31","1994","TUESDAY"
+"6","1","1994","WEDNESDAY"
+"6","2","1994","THURSDAY"
+"6","3","1994","FRIDAY"
+"6","4","1994","SATURDAY"
+"6","5","1994","SUNDAY"
+"6","6","1994","MONDAY"
+"6","7","1994","TUESDAY"
+"6","8","1994","WEDNESDAY"
+"6","9","1994","THURSDAY"
+"6","10","1994","FRIDAY"
+"6","11","1994","SATURDAY"
+"6","12","1994","SUNDAY"
+"6","13","1994","MONDAY"
+"6","14","1994","TUESDAY"
+"6","15","1994","WEDNESDAY"
+"6","16","1994","THURSDAY"
+"6","17","1994","FRIDAY"
+"6","18","1994","SATURDAY"
+"6","19","1994","SUNDAY"
+"6","20","1994","MONDAY"
+"6","21","1994","TUESDAY"
+"6","22","1994","WEDNESDAY"
+"6","23","1994","THURSDAY"
+"6","24","1994","FRIDAY"
+"6","25","1994","SATURDAY"
+"6","26","1994","SUNDAY"
+"6","27","1994","MONDAY"
+"6","28","1994","TUESDAY"
+"6","29","1994","WEDNESDAY"
+"6","30","1994","THURSDAY"
+"7","1","1994","FRIDAY"
+"7","2","1994","SATURDAY"
+"7","3","1994","SUNDAY"
+"7","4","1994","MONDAY"
+"7","5","1994","TUESDAY"
+"7","6","1994","WEDNESDAY"
+"7","7","1994","THURSDAY"
+"7","8","1994","FRIDAY"
+"7","9","1994","SATURDAY"
+"7","10","1994","SUNDAY"
+"7","11","1994","MONDAY"
+"7","12","1994","TUESDAY"
+"7","13","1994","WEDNESDAY"
+"7","14","1994","THURSDAY"
+"7","15","1994","FRIDAY"
+"7","16","1994","SATURDAY"
+"7","17","1994","SUNDAY"
+"7","18","1994","MONDAY"
+"7","19","1994","TUESDAY"
+"7","20","1994","WEDNESDAY"
+"7","21","1994","THURSDAY"
+"7","22","1994","FRIDAY"
+"7","23","1994","SATURDAY"
+"7","24","1994","SUNDAY"
+"7","25","1994","MONDAY"
+"7","26","1994","TUESDAY"
+"7","27","1994","WEDNESDAY"
+"7","28","1994","THURSDAY"
+"7","29","1994","FRIDAY"
+"7","30","1994","SATURDAY"
+"7","31","1994","SUNDAY"
+"8","1","1994","MONDAY"
+"8","2","1994","TUESDAY"
+"8","3","1994","WEDNESDAY"
+"8","4","1994","THURSDAY"
+"8","5","1994","FRIDAY"
+"8","6","1994","SATURDAY"
+"8","7","1994","SUNDAY"
+"8","8","1994","MONDAY"
+"8","9","1994","TUESDAY"
+"8","10","1994","WEDNESDAY"
+"8","11","1994","THURSDAY"
+"8","12","1994","FRIDAY"
+"8","13","1994","SATURDAY"
+"8","14","1994","SUNDAY"
+"8","15","1994","MONDAY"
+"8","16","1994","TUESDAY"
+"8","17","1994","WEDNESDAY"
+"8","18","1994","THURSDAY"
+"8","19","1994","FRIDAY"
+"8","20","1994","SATURDAY"
+"8","21","1994","SUNDAY"
+"8","22","1994","MONDAY"
+"8","23","1994","TUESDAY"
+"8","24","1994","WEDNESDAY"
+"8","25","1994","THURSDAY"
+"8","26","1994","FRIDAY"
+"8","27","1994","SATURDAY"
+"8","28","1994","SUNDAY"
+"8","29","1994","MONDAY"
+"8","30","1994","TUESDAY"
+"8","31","1994","WEDNESDAY"
+"9","1","1994","THURSDAY"
+"9","2","1994","FRIDAY"
+"9","3","1994","SATURDAY"
+"9","4","1994","SUNDAY"
+"9","5","1994","MONDAY"
+"9","6","1994","TUESDAY"
+"9","7","1994","WEDNESDAY"
+"9","8","1994","THURSDAY"
+"9","9","1994","FRIDAY"
+"9","10","1994","SATURDAY"
+"9","11","1994","SUNDAY"
+"9","12","1994","MONDAY"
+"9","13","1994","TUESDAY"
+"9","14","1994","WEDNESDAY"
+"9","15","1994","THURSDAY"
+"9","16","1994","FRIDAY"
+"9","17","1994","SATURDAY"
+"9","18","1994","SUNDAY"
+"9","19","1994","MONDAY"
+"9","20","1994","TUESDAY"
+"9","21","1994","WEDNESDAY"
+"9","22","1994","THURSDAY"
+"9","23","1994","FRIDAY"
+"9","24","1994","SATURDAY"
+"9","25","1994","SUNDAY"
+"9","26","1994","MONDAY"
+"9","27","1994","TUESDAY"
+"9","28","1994","WEDNESDAY"
+"9","29","1994","THURSDAY"
+"9","30","1994","FRIDAY"
+"10","1","1994","SATURDAY"
+"10","2","1994","SUNDAY"
+"10","3","1994","MONDAY"
+"10","4","1994","TUESDAY"
+"10","5","1994","WEDNESDAY"
+"10","6","1994","THURSDAY"
+"10","7","1994","FRIDAY"
+"10","8","1994","SATURDAY"
+"10","9","1994","SUNDAY"
+"10","10","1994","MONDAY"
+"10","11","1994","TUESDAY"
+"10","12","1994","WEDNESDAY"
+"10","13","1994","THURSDAY"
+"10","14","1994","FRIDAY"
+"10","15","1994","SATURDAY"
+"10","16","1994","SUNDAY"
+"10","17","1994","MONDAY"
+"10","18","1994","TUESDAY"
+"10","19","1994","WEDNESDAY"
+"10","20","1994","THURSDAY"
+"10","21","1994","FRIDAY"
+"10","22","1994","SATURDAY"
+"10","23","1994","SUNDAY"
+"10","24","1994","MONDAY"
+"10","25","1994","TUESDAY"
+"10","26","1994","WEDNESDAY"
+"10","27","1994","THURSDAY"
+"10","28","1994","FRIDAY"
+"10","29","1994","SATURDAY"
+"10","30","1994","SUNDAY"
+"10","31","1994","MONDAY"
+"11","1","1994","TUESDAY"
+"11","2","1994","WEDNESDAY"
+"11","3","1994","THURSDAY"
+"11","4","1994","FRIDAY"
+"11","5","1994","SATURDAY"
+"11","6","1994","SUNDAY"
+"11","7","1994","MONDAY"
+"11","8","1994","TUESDAY"
+"11","9","1994","WEDNESDAY"
+"11","10","1994","THURSDAY"
+"11","11","1994","FRIDAY"
+"11","12","1994","SATURDAY"
+"11","13","1994","SUNDAY"
+"11","14","1994","MONDAY"
+"11","15","1994","TUESDAY"
+"11","16","1994","WEDNESDAY"
+"11","17","1994","THURSDAY"
+"11","18","1994","FRIDAY"
+"11","19","1994","SATURDAY"
+"11","20","1994","SUNDAY"
+"11","21","1994","MONDAY"
+"11","22","1994","TUESDAY"
+"11","23","1994","WEDNESDAY"
+"11","24","1994","THURSDAY"
+"11","25","1994","FRIDAY"
+"11","26","1994","SATURDAY"
+"11","27","1994","SUNDAY"
+"11","28","1994","MONDAY"
+"11","29","1994","TUESDAY"
+"11","30","1994","WEDNESDAY"
+"12","1","1994","THURSDAY"
+"12","2","1994","FRIDAY"
+"12","3","1994","SATURDAY"
+"12","4","1994","SUNDAY"
+"12","5","1994","MONDAY"
+"12","6","1994","TUESDAY"
+"12","7","1994","WEDNESDAY"
+"12","8","1994","THURSDAY"
+"12","9","1994","FRIDAY"
+"12","10","1994","SATURDAY"
+"12","11","1994","SUNDAY"
+"12","12","1994","MONDAY"
+"12","13","1994","TUESDAY"
+"12","14","1994","WEDNESDAY"
+"12","15","1994","THURSDAY"
+"12","16","1994","FRIDAY"
+"12","17","1994","SATURDAY"
+"12","18","1994","SUNDAY"
+"12","19","1994","MONDAY"
+"12","20","1994","TUESDAY"
+"12","21","1994","WEDNESDAY"
+"12","22","1994","THURSDAY"
+"12","23","1994","FRIDAY"
+"12","24","1994","SATURDAY"
+"12","25","1994","SUNDAY"
+"12","26","1994","MONDAY"
+"12","27","1994","TUESDAY"
+"12","28","1994","WEDNESDAY"
+"12","29","1994","THURSDAY"
+"12","30","1994","FRIDAY"
+"12","31","1994","SATURDAY"
diff --git a/sql-bench/Data/ATIS/day_name.txt b/sql-bench/Data/ATIS/day_name.txt
new file mode 100644
index 00000000000..eca77e3729f
--- /dev/null
+++ b/sql-bench/Data/ATIS/day_name.txt
@@ -0,0 +1,7 @@
+1,'MONDAY'
+2,'TUESDAY'
+3,'WEDNESDAY'
+4,'THURSDAY'
+5,'FRIDAY'
+6,'SATURDAY'
+7,'SUNDAY'
diff --git a/sql-bench/Data/ATIS/dual_carrier.txt b/sql-bench/Data/ATIS/dual_carrier.txt
new file mode 100644
index 00000000000..ecfc2e688b9
--- /dev/null
+++ b/sql-bench/Data/ATIS/dual_carrier.txt
@@ -0,0 +1,114 @@
+'AA','AA',3000,5799,'AMERICAN EAGLE'
+'AC','RJ',1001,1010,'AIR CANADA'
+'AC','CS',1100,1199,'AIR CANADA'
+'AC','GX',1200,1499,'AIR CANADA'
+'AC','ZX',1500,1799,'AIR CANADA'
+'AC','QK',1800,1899,'AIR CANADA'
+'AC','3J',1900,1949,'AIR CANADA'
+'AC','3J',1977,1981,'AIR CANADA'
+'AC','3J',1990,1999,'AIR CANADA'
+'AC','NV',1950,1976,'AIR CANADA'
+'AC','NV',1982,1989,'AIR CANADA'
+'AQ','WP',1000,1999,'ALOHA AIRLINES,INC'
+'AS','QX',2000,2199,'ALASKA AIRLINES COMMUTER SERVICE'
+'AS','QX',2260,2999,'ALASKA AIRLINES COMMUTER SERVICE'
+'AS','BF',2200,2259,'ALASKA AIRLINES COMMUTER SERVICE'
+'AS','BF',4000,4199,'ALASKA AIRLINES COMMUTER SERVICE'
+'AS','JF',4400,4499,'ALASKA AIRLINES COMMUTER SERVICE'
+'AS','KN',4500,4599,'ALASKA AIRLINES COMMUTER SERVICE'
+'AS','8E',4600,4699,'ALASKA AIRLINES COMMUTER SERVICE'
+'AS','7H',4800,4899,'ALASKA AIRLINES COMMUTER SERVICE'
+'BA','BE',8001,8002,'BRITISH AIRWAYS'
+'BA','BE',8004,8004,'BRITISH AIRWAYS'
+'BA','UA',8022,8022,'BRITISH AIRWAYS'
+'BA','UA',8154,8155,'BRITISH AIRWAYS'
+'BA','UA',8159,8159,'BRITISH AIRWAYS'
+'BA','UA',8235,8235,'BRITISH AIRWAYS'
+'BA','UA',8243,8243,'BRITISH AIRWAYS'
+'BA','UA',8246,8246,'BRITISH AIRWAYS'
+'BA','UA',8064,8064,'BRITISH AIRWAYS'
+'BA','UA',8269,8269,'BRITISH AIRWAYS'
+'BA','UA',8300,8300,'BRITISH AIRWAYS'
+'BF','2E',1100,1399,'MARKAIR,INC.'
+'BF','2E',1800,1899,'MARKAIR,INC.'
+'CO','CO',950,967,'CONTINENTAL AIRLINES/AIR MICRONESIA'
+'CO','CO',970,997,'CONTINENTAL AIRLINES/AIR MICRONESIA'
+'CO','CO',1880,1899,'CONTINENTAL AIRLINES/AIR MICRONESIA'
+'CO','CO',3300,3399,'CONTINENTAL AIRLINES/AIR MICRONESIA'
+'CO','SK',8900,8949,'CONTINENTAL AIRLINES/SAS SCANDINAVIAN AIRLINES SYSTEM'
+'CO','SK',9000,9125,'CONTINENTAL AIRLINES/SAS SCANDINAVIAN AIRLINES SYSTEM'
+'CO','SK',9370,9435,'CONTINENTAL AIRLINES/SAS SCANDINAVIAN AIRLINES SYSTEM'
+'CO','JC',2000,2499,'CONTINENTAL EXPRESS'
+'CO','RU',2500,2799,'CONTINENTAL EXPRESS'
+'CO','RU',3000,3025,'CONTINENTAL EXPRESS'
+'CO','RU',4400,4999,'CONTINENTAL EXPRESS'
+'CO','CO',2800,2999,'CONTINENTAL EXPRESS/RESORT EXPRESS'
+'CO','CO',3026,3099,'CONTINENTAL EXPRESS/HOME JAMES'
+'CO','CO',3100,3199,'CONTINENTAL EXPRESS/COLORADO MOUNTAIN EXPRESS'
+'CO','6J',3200,3299,'CONTINENTAL EXPRESS/SOUTHERN JERSEY AIRWAYS,INC.'
+'CO','QO',3400,3999,'CONTINENTAL EXPRESS/BAR HARBOR AIRLINES'
+'CP','SK',68,69,'CANADIAN AIRLINES INTERNATIONAL LTD. CANADIAN PARTNERS'
+'CP','LH',144,145,'CANADIAN AIRLINES INTERNATIONAL LTD. CANADIAN PARTNERS'
+'CP','WD',950,951,'CANADIAN AIRLINES INTERNATIONAL LTD. CANADIAN PARTNERS'
+'CP','WD',954,955,'CANADIAN AIRLINES INTERNATIONAL LTD. CANADIAN PARTNERS'
+'CP','WD',957,958,'CANADIAN AIRLINES INTERNATIONAL LTD. CANADIAN PARTNERS'
+'CP','WD',960,961,'CANADIAN AIRLINES INTERNATIONAL LTD. CANADIAN PARTNERS'
+'CP','WD',963,964,'CANADIAN AIRLINES INTERNATIONAL LTD. CANADIAN PARTNERS'
+'CP','WD',967,968,'CANADIAN AIRLINES INTERNATIONAL LTD. CANADIAN PARTNERS'
+'CP','WD',983,983,'CANADIAN AIRLINES INTERNATIONAL LTD. CANADIAN PARTNERS'
+'CP','WD',986,986,'CANADIAN AIRLINES INTERNATIONAL LTD. CANADIAN PARTNERS'
+'CP','WD',988,988,'CANADIAN AIRLINES INTERNATIONAL LTD. CANADIAN PARTNERS'
+'CP','WD',991,992,'CANADIAN AIRLINES INTERNATIONAL LTD. CANADIAN PARTNERS'
+'CP','WD',994,995,'CANADIAN AIRLINES INTERNATIONAL LTD. CANADIAN PARTNERS'
+'CP','PJ',1001,1010,'CANADIAN AIRLINES INTERNATIONAL LTD. CANADIAN PARTNERS'
+'CP','KI',1100,1272,'CANADIAN AIRLINES INTERNATIONAL LTD. CANADIAN PARTNERS'
+'CP','KI',1274,1274,'CANADIAN AIRLINES INTERNATIONAL LTD. CANADIAN PARTNERS'
+'CP','KI',1276,1276,'CANADIAN AIRLINES INTERNATIONAL LTD. CANADIAN PARTNERS'
+'CP','KI',1278,1283,'CANADIAN AIRLINES INTERNATIONAL LTD. CANADIAN PARTNERS'
+'CP','KI',1285,1288,'CANADIAN AIRLINES INTERNATIONAL LTD. CANADIAN PARTNERS'
+'CP','MO',1300,1359,'CANADIAN AIRLINES INTERNATIONAL LTD. CANADIAN PARTNERS'
+'CP','9A',1400,1499,'CANADIAN AIRLINES INTERNATIONAL LTD. CANADIAN PARTNERS'
+'CP','CP',1800,1999,'CANADIAN AIRLINES INTERNATIONAL LTD./ONTARIO EXPRESS LTD.'
+'DL','EV',2000,2999,'DELTA CONNECTION'
+'DL','OH',3000,3699,'DELTA CONNECTION'
+'DL','HQ',4300,4999,'DELTA CONNECTION'
+'DL','OO',5200,5999,'DELTA CONNECTION'
+'EA','LI',2300,2399,'EASTERN EXPRESS'
+'EA','HY',2900,3299,'EASTERN EXPRESS'
+'EA','QO',3700,3999,'EASTERN EXPRESS'
+'KL','UK',2843,2843,'KLM-ROYAL DUTCH AIRLINES'
+'KL','UK',2845,2845,'KLM-ROYAL DUTCH AIRLINES'
+'KL','UK',2847,2847,'KLM-ROYAL DUTCH AIRLINES'
+'ML','JT',1500,1550,'THE MIDWAY CONNECTION/IOWA AIRWAYS'
+'ML','ML',1600,1999,'THE MIDWAY CONNECTION/MIDWAY COMMUTER/FISCHER BROS. AVIATION'
+'ND','QR',240,259,'INTAIR'
+'ND','ND',940,959,'INTAIR/ALEXANDAIR,INC.'
+'NW','QX',2000,2399,'NORTHWEST AIRLINES'
+'NW','US',4000,4999,'NORTHWEST AIRLINES'
+'NW','9E',2500,2999,'NORTHWEST AIRLINK'
+'NW','XJ',3000,3399,'NORTHWEST AIRLINK'
+'NW','RP',3500,3799,'NORTHWEST AIRLINK'
+'NW','GQ',3800,3999,'NORTHWEST AIRLINK'
+'PA','RZ',270,271,'PAN AM EXPRESS,INC.'
+'PA','RZ',4500,4999,'PAN AM EXPRESS,INC.'
+'PA','MA',4072,4073,'PAN AMERICAN WORLD AIRWAYS,INC./MALEV-HUNGARIAN AIRLINES'
+'PA','JP',4076,4077,'PAN AMERICAN WORLD AIRWAYS,INC./ADRIA AIRWAYS'
+'QF','AA',301,302,'QANTAS AIRWAYS LTD.'
+'QK','QK',803,804,'AIR NOVA INC./NEWFOUNDLAND LABRADOR AIR TRANSPORT,LTD.'
+'QY','QY',600,615,'AERO VIRGIN ISLANDS CORP./TAINO AIRWAYS'
+'TW','US',8150,8155,'TRANS WORLD AIRLINES,INC.'
+'TW','US',8156,8199,'TRANS WORLD AIRLINES,INC.'
+'TW','9N',7000,7199,'TRANS WORLD EXPRESS,'
+'TW','ZV',7300,7499,'TRANS WORLD EXPRESS,'
+'TW','JI',7550,7569,'TRANS WORLD EXPRESS,'
+'TW','8P',7570,7699,'TRANS WORLD EXPRESS,'
+'TW','SS',7750,7949,'TRANS WORLD EXPRESS,'
+'UA','XV',2100,2349,'UNITED EXPRESS'
+'UA','NO',2375,2624,'UNITED EXPRESS'
+'UA','ZW',2640,3099,'UNITED EXPRESS'
+'UA','OE',3100,3569,'UNITED EXPRESS'
+'UA','AP',3640,3999,'UNITED EXPRESS'
+'US','US',3000,4999,'USAIR EXPRESS'
+'YX','YX',1000,1999,'MIDWEST EXPRESS CONNECTION/SKYWAY AIRLINES INC.'
+'2F','2F',526,529,'FRONTIER FLYING SERVICE/TATONDUK AIR SERVICE'
+'','',0,0,''
diff --git a/sql-bench/Data/ATIS/fare.txt b/sql-bench/Data/ATIS/fare.txt
new file mode 100644
index 00000000000..5585a29afce
--- /dev/null
+++ b/sql-bench/Data/ATIS/fare.txt
@@ -0,0 +1,534 @@
+'7100001','ATL','BOS','F','','',497.00,994.00
+'7100002','ATL','BOS','FN','','',348.00,696.00
+'7100003','ATL','BOS','Y','','',331.00,662.00
+'7100004','ATL','BOS','YN','','',266.00,532.00
+'7100005','ATL','BOS','K','','AP/57',0.00,388.00
+'7100006','ATL','BOS','KO','','AP/57',0.00,368.00
+'7100007','ATL','BOS','QW','','AP/57',0.00,268.00
+'7100008','ATL','BOS','QX','','AP/57',0.00,248.00
+'7100009','ATL','BOS','B','','VU/1',230.00,0.00
+'7100010','ATL','BOS','Y','','VU/1',226.00,0.00
+'7100011','ATL','BWI','F','','',428.00,856.00
+'7100012','ATL','BWI','FN','','',299.00,598.00
+'7100013','ATL','BWI','Y','','',286.00,572.00
+'7100014','ATL','BWI','YN','','',230.00,460.00
+'7100015','ATL','BWI','QW','','AP/57',0.00,248.00
+'7100016','ATL','BWI','QX','','AP/57',0.00,208.00
+'7100017','ATL','BWI','B','','VU/1',199.00,0.00
+'7100018','ATL','BWI','Y','','VU/1',196.00,0.00
+'7100019','ATL','DEN','F','UA','',685.00,1370.00
+'7100020','ATL','DEN','F','','',677.00,1354.00
+'7100021','ATL','DEN','FN','','',475.00,950.00
+'7100022','ATL','DEN','Y','UA','',457.00,914.00
+'7100023','ATL','DEN','Y','','',452.00,904.00
+'7100024','ATL','DEN','B','DL','',435.00,870.00
+'7100025','ATL','DEN','H','EA','',410.00,820.00
+'7100026','ATL','DEN','M','DL','',410.00,820.00
+'7100027','ATL','DEN','YN','','',361.00,722.00
+'7100028','ATL','DEN','MW','','AP/57',0.00,438.00
+'7100029','ATL','DEN','MX','','AP/57',0.00,378.00
+'7100030','ATL','DEN','QW','','AP/57',0.00,298.00
+'7100031','ATL','DEN','QX','','AP/57',0.00,238.00
+'7100032','ATL','DEN','B','','VU/1',314.00,0.00
+'7100033','ATL','DEN','Y','','VU/1',314.00,0.00
+'7100034','ATL','DEN','B','','AP/55',304.00,0.00
+'7100035','ATL','DEN','H','','AP/55',228.00,0.00
+'7100036','ATL','DFW','F','AA','',512.00,1024.00
+'7100037','ATL','DFW','F','DL','',504.00,1008.00
+'7100038','ATL','DFW','F','','',503.00,1006.00
+'7100039','ATL','DFW','FN','AA','',360.00,720.00
+'7100040','ATL','DFW','FN','','',352.00,704.00
+'7100041','ATL','DFW','Y','','',341.00,682.00
+'7100042','ATL','DFW','Y','DL','',336.00,672.00
+'7100043','ATL','DFW','YN','AA','',277.00,554.00
+'7100044','ATL','DFW','YN','','',272.00,544.00
+'7100045','ATL','DFW','QW','','AP/80',0.00,268.00
+'7100046','ATL','DFW','QX','','AP/80',0.00,228.00
+'7100047','ATL','DFW','B','','VU/1',233.00,0.00
+'7100048','ATL','DFW','Y','AA','VU/1',233.00,0.00
+'7100049','ATL','DFW','M','','VU/1',233.00,0.00
+'7100050','ATL','DFW','Y','','VU/1',222.00,0.00
+'7100051','ATL','OAK','F','UA','',843.00,1686.00
+'7100052','ATL','OAK','Y','UA','',557.00,1114.00
+'7100053','ATL','OAK','QW','','AP/80',0.00,398.00
+'7100054','ATL','OAK','QX','','AP/80',0.00,348.00
+'7100055','ATL','OAK','B','','AP/68',503.00,0.00
+'7100056','ATL','OAK','B','','VU/1',387.00,0.00
+'7100057','ATL','OAK','Y','','VU/1',376.00,0.00
+'7100058','ATL','PHL','F','US','',465.00,930.00
+'7100059','ATL','PHL','F','','',449.00,898.00
+'7100060','ATL','PHL','FN','','',314.00,628.00
+'7100061','ATL','PHL','Y','','',295.00,590.00
+'7100062','ATL','PHL','Y','US','',290.00,580.00
+'7100063','ATL','PHL','YN','','',243.00,486.00
+'7100064','ATL','PHL','KW','','AP/57',0.00,268.00
+'7100065','ATL','PHL','QW','','AP/80',0.00,268.00
+'7100066','ATL','PHL','QW','','AP/57',0.00,268.00
+'7100067','ATL','PHL','KX','','AP/57',0.00,228.00
+'7100068','ATL','PHL','QX','','AP/57',0.00,228.00
+'7100069','ATL','PHL','QX','','AP/80',0.00,228.00
+'7100070','ATL','PHL','B','','VU/1',205.00,0.00
+'7100071','ATL','PHL','Y','','VU/1',205.00,0.00
+'7100072','ATL','PIT','F','','',416.00,832.00
+'7100073','ATL','PIT','FN','','',291.00,582.00
+'7100074','ATL','PIT','Y','','',274.00,548.00
+'7100075','ATL','PIT','YN','','',217.00,434.00
+'7100076','ATL','PIT','KW','','AP/57',0.00,268.00
+'7100077','ATL','PIT','QW','','AP/57',0.00,248.00
+'7100078','ATL','PIT','KX','','AP/57',0.00,228.00
+'7100079','ATL','PIT','QX','','AP/57',0.00,208.00
+'7100080','ATL','PIT','B','','VU/1',190.00,0.00
+'7100081','ATL','PIT','Y','','VU/1',190.00,0.00
+'7100082','ATL','SFO','F','','',828.00,1656.00
+'7100083','ATL','SFO','Y','','',552.00,1104.00
+'7100084','ATL','SFO','QW','','AP/57',0.00,398.00
+'7100085','ATL','SFO','QX','','AP/57',0.00,358.00
+'7100086','ATL','SFO','K','','AP/68',435.00,0.00
+'7100087','ATL','SFO','Q','','AP/68',435.00,0.00
+'7100088','ATL','SFO','B','','VU/1',383.00,0.00
+'7100089','ATL','SFO','Y','','VU/1',376.00,0.00
+'7100090','BOS','ATL','F','','',497.00,994.00
+'7100091','BOS','ATL','FN','','',348.00,696.00
+'7100092','BOS','ATL','Y','','',331.00,662.00
+'7100093','BOS','ATL','YN','','',266.00,532.00
+'7100094','BOS','ATL','K','','AP/57',0.00,388.00
+'7100095','BOS','ATL','KO','','AP/57',0.00,368.00
+'7100096','BOS','ATL','QW','','AP/57',0.00,268.00
+'7100097','BOS','ATL','QX','','AP/57',0.00,248.00
+'7100098','BOS','ATL','B','','VU/1',230.00,0.00
+'7100099','BOS','ATL','Y','','VU/1',226.00,0.00
+'7100100','BOS','BWI','F','','',368.00,736.00
+'7100101','BOS','BWI','Y','','',161.00,322.00
+'7100102','BOS','BWI','Y','','VU/1',109.00,0.00
+'7100103','BOS','DEN','F','','',713.00,1426.00
+'7100104','BOS','DEN','Y','','',475.00,950.00
+'7100105','BOS','DEN','QW','','AP/80',0.00,378.00
+'7100106','BOS','DEN','QX','','AP/80',0.00,338.00
+'7100107','BOS','DEN','B','','VU/1',379.00,0.00
+'7100108','BOS','DEN','Y','','VU/1',326.00,0.00
+'7100109','BOS','DFW','F','AA','',773.00,1546.00
+'7100110','BOS','DFW','F','DL','',765.00,1530.00
+'7100111','BOS','DFW','Y','AA','',515.00,1030.00
+'7100112','BOS','DFW','Y','DL','',510.00,1020.00
+'7100113','BOS','DFW','B','','VU/1',354.00,0.00
+'7100114','BOS','DFW','Y','','VU/1',354.00,0.00
+'7100115','BOS','PHL','F','','',210.00,420.00
+'7100116','BOS','PHL','Y','DL','',147.00,294.00
+'7100117','BOS','PHL','B','DL','',140.00,280.00
+'7100118','BOS','PHL','K','','',140.00,280.00
+'7100119','BOS','PHL','Y','DL','',140.00,280.00
+'7100120','BOS','PHL','Y','','',140.00,280.00
+'7100121','BOS','PHL','B','','AP/75',0.00,270.00
+'7100122','BOS','PHL','B','DL','',129.00,258.00
+'7100123','BOS','PHL','B','US','',109.00,218.00
+'7100124','BOS','PHL','M','ML','',109.00,218.00
+'7100125','BOS','PHL','Q','','AP/27',0.00,188.00
+'7100126','BOS','PHL','B','','AP/44',129.00,0.00
+'7100127','BOS','PHL','B','','VU/1',102.00,0.00
+'7100128','BOS','PHL','Y','','VU/1',97.00,0.00
+'7100129','BOS','PIT','F','','',330.00,660.00
+'7100130','BOS','PIT','Y','','',240.00,480.00
+'7100131','BOS','PIT','Y','','VU/1',153.00,0.00
+'7100132','BOS','SFO','F','','',860.00,1720.00
+'7100133','BOS','SFO','F','AA','',852.00,1704.00
+'7100134','BOS','SFO','C','','',635.00,1270.00
+'7100135','BOS','SFO','Y','TW','',605.00,1210.00
+'7100136','BOS','SFO','Y','UA','',605.00,1210.00
+'7100137','BOS','SFO','Y','','',573.00,1146.00
+'7100138','BOS','SFO','B','AA','',508.00,1016.00
+'7100139','BOS','SFO','KW','','AP/57',0.00,418.00
+'7100140','BOS','SFO','QW','','AP/80',0.00,418.00
+'7100141','BOS','SFO','KX','','AP/57',0.00,378.00
+'7100142','BOS','SFO','QX','','AP/80',0.00,378.00
+'7100143','BOS','SFO','B','','VU/1',412.00,0.00
+'7100144','BOS','SFO','M','','VU/1',394.00,0.00
+'7100145','BOS','SFO','Y','','VU/1',394.00,0.00
+'7100146','BWI','ATL','F','','',428.00,856.00
+'7100147','BWI','ATL','FN','','',299.00,598.00
+'7100148','BWI','ATL','Y','','',286.00,572.00
+'7100149','BWI','ATL','YN','','',230.00,460.00
+'7100150','BWI','ATL','QW','','AP/57',0.00,248.00
+'7100151','BWI','ATL','QX','','AP/57',0.00,208.00
+'7100152','BWI','ATL','B','','VU/1',199.00,0.00
+'7100153','BWI','ATL','Y','','VU/1',196.00,0.00
+'7100154','BWI','BOS','F','','',368.00,736.00
+'7100155','BWI','BOS','Y','','',161.00,322.00
+'7100156','BWI','BOS','Y','','VU/1',109.00,0.00
+'7100157','BWI','DEN','F','US','',653.00,1306.00
+'7100158','BWI','DEN','F','','',645.00,1290.00
+'7100159','BWI','DEN','Y','UA','',424.00,848.00
+'7100160','BWI','DEN','Y','','',420.00,840.00
+'7100161','BWI','DEN','Q','US','',238.00,476.00
+'7100162','BWI','DEN','QW','','AP/80',0.00,306.00
+'7100163','BWI','DEN','QX','','AP/80',0.00,256.00
+'7100164','BWI','DEN','Y','','VU/1',280.00,0.00
+'7100165','BWI','DFW','F','AA','',630.00,1260.00
+'7100166','BWI','DFW','F','','',622.00,1244.00
+'7100167','BWI','DFW','Y','AA','',420.00,840.00
+'7100168','BWI','DFW','Y','','',415.00,830.00
+'7100169','BWI','DFW','B','','VU/1',288.00,0.00
+'7100170','BWI','DFW','Y','','VU/1',288.00,0.00
+'7100171','BWI','PHL','Y','','',165.00,330.00
+'7100172','BWI','PHL','M','','',106.00,212.00
+'7100173','BWI','PHL','Y','','VU/1',115.00,0.00
+'7100174','BWI','PIT','F','','',172.00,344.00
+'7100175','BWI','PIT','Y','','',119.00,238.00
+'7100176','BWI','PIT','Y','','VU/1',80.00,0.00
+'7100177','DEN','ATL','F','UA','',685.00,1370.00
+'7100178','DEN','ATL','F','','',677.00,1354.00
+'7100179','DEN','ATL','FN','','',475.00,950.00
+'7100180','DEN','ATL','Y','UA','',457.00,914.00
+'7100181','DEN','ATL','Y','','',452.00,904.00
+'7100182','DEN','ATL','B','DL','',435.00,870.00
+'7100183','DEN','ATL','H','','',410.00,820.00
+'7100184','DEN','ATL','M','DL','',410.00,820.00
+'7100185','DEN','ATL','YN','','',361.00,722.00
+'7100186','DEN','ATL','MW','','AP/57',0.00,438.00
+'7100187','DEN','ATL','MX','','AP/57',0.00,378.00
+'7100188','DEN','ATL','QW','','AP/57',0.00,298.00
+'7100189','DEN','ATL','QX','','AP/57',0.00,238.00
+'7100190','DEN','ATL','B','','VU/1',314.00,0.00
+'7100191','DEN','ATL','Y','','VU/1',314.00,0.00
+'7100192','DEN','ATL','B','','AP/55',304.00,0.00
+'7100193','DEN','BOS','F','','',713.00,1426.00
+'7100194','DEN','BOS','F','US','',705.00,1410.00
+'7100195','DEN','BOS','Y','','',475.00,950.00
+'7100196','DEN','BOS','Y','US','',470.00,940.00
+'7100197','DEN','BOS','B','US','',382.00,764.00
+'7100198','DEN','BOS','M','DL','',295.00,590.00
+'7100199','DEN','BOS','Q','US','',295.00,590.00
+'7100200','DEN','BOS','Q','DL','',238.00,476.00
+'7100201','DEN','BOS','KW','','AP/57',0.00,378.00
+'7100202','DEN','BOS','QW','','AP/80',0.00,378.00
+'7100203','DEN','BOS','KX','','AP/57',0.00,338.00
+'7100204','DEN','BOS','QX','','AP/80',0.00,338.00
+'7100205','DEN','BOS','B','','VU/1',379.00,0.00
+'7100206','DEN','BOS','Y','','VU/1',326.00,0.00
+'7100207','DEN','BWI','F','US','',653.00,1306.00
+'7100208','DEN','BWI','F','UA','',645.00,1290.00
+'7100209','DEN','BWI','Y','','',424.00,848.00
+'7100210','DEN','BWI','Y','US','',420.00,840.00
+'7100211','DEN','BWI','Q','US','',238.00,476.00
+'7100212','DEN','BWI','QW','','AP/80',0.00,306.00
+'7100213','DEN','BWI','QX','','AP/80',0.00,256.00
+'7100214','DEN','BWI','M','','VU/1',296.00,0.00
+'7100215','DEN','BWI','Y','','VU/1',280.00,0.00
+'7100216','DEN','DFW','F','','',489.00,978.00
+'7100217','DEN','DFW','F','DL','',481.00,962.00
+'7100218','DEN','DFW','FN','AA','',344.00,688.00
+'7100219','DEN','DFW','FN','','',336.00,672.00
+'7100220','DEN','DFW','Y','','',305.00,610.00
+'7100221','DEN','DFW','Y','DL','',300.00,600.00
+'7100222','DEN','DFW','YN','AA','',261.00,522.00
+'7100223','DEN','DFW','YN','','',256.00,512.00
+'7100224','DEN','DFW','QW','','AP/80',0.00,268.00
+'7100225','DEN','DFW','QX','','AP/80',0.00,228.00
+'7100226','DEN','DFW','B','','VU/1',208.00,0.00
+'7100227','DEN','DFW','Y','','VU/1',208.00,0.00
+'7100228','DEN','OAK','F','','',488.00,976.00
+'7100229','DEN','OAK','Y','','',325.00,650.00
+'7100230','DEN','OAK','QW','','AP/80',0.00,288.00
+'7100231','DEN','OAK','QX','','AP/80',0.00,248.00
+'7100232','DEN','OAK','Y','','VU/1',222.00,0.00
+'7100233','DEN','PHL','F','','',706.00,1412.00
+'7100234','DEN','PHL','Y','','',470.00,940.00
+'7100235','DEN','PHL','FN','','',441.00,882.00
+'7100236','DEN','PHL','YN','','',336.00,672.00
+'7100237','DEN','PHL','KW','','AP/57',0.00,488.00
+'7100238','DEN','PHL','KX','','AP/57',0.00,418.00
+'7100239','DEN','PHL','QW','','AP/80',0.00,348.00
+'7100240','DEN','PHL','QX','','AP/80',0.00,278.00
+'7100241','DEN','PHL','Y','','VU/1',323.00,0.00
+'7100242','DEN','PHL','B','','VU/1',297.00,0.00
+'7100243','DEN','PIT','F','','',647.00,1294.00
+'7100244','DEN','PIT','Y','','',412.00,824.00
+'7100245','DEN','PIT','Q','','',287.00,574.00
+'7100246','DEN','PIT','Y','','VU/1',285.00,0.00
+'7100247','DEN','SFO','F','','',488.00,976.00
+'7100248','DEN','SFO','Y','','',325.00,650.00
+'7100249','DEN','SFO','YN','','',325.00,650.00
+'7100250','DEN','SFO','QW','','AP/80',0.00,288.00
+'7100251','DEN','SFO','QX','','AP/80',0.00,248.00
+'7100252','DEN','SFO','B','','VU/1',222.00,0.00
+'7100253','DEN','SFO','Y','','VU/1',222.00,0.00
+'7100254','DFW','ATL','F','AA','',512.00,1024.00
+'7100255','DFW','ATL','F','DL','',504.00,1008.00
+'7100256','DFW','ATL','F','','',488.00,976.00
+'7100257','DFW','ATL','FN','AA','',360.00,720.00
+'7100258','DFW','ATL','FN','','',352.00,704.00
+'7100259','DFW','ATL','Y','AA','',341.00,682.00
+'7100260','DFW','ATL','Y','DL','',336.00,672.00
+'7100261','DFW','ATL','YN','AA','',277.00,554.00
+'7100262','DFW','ATL','YN','','',272.00,544.00
+'7100263','DFW','ATL','QW','','AP/80',0.00,268.00
+'7100264','DFW','ATL','QX','','AP/80',0.00,228.00
+'7100265','DFW','ATL','B','','VU/1',233.00,0.00
+'7100266','DFW','ATL','Y','AA','VU/1',233.00,0.00
+'7100267','DFW','ATL','Y','','VU/1',222.00,0.00
+'7100268','DFW','BOS','F','AA','',773.00,1546.00
+'7100269','DFW','BOS','F','','',765.00,1530.00
+'7100270','DFW','BOS','Y','AA','',515.00,1030.00
+'7100271','DFW','BOS','Y','DL','',510.00,1020.00
+'7100272','DFW','BOS','B','','VU/1',354.00,0.00
+'7100273','DFW','BOS','Y','AA','VU/1',354.00,0.00
+'7100274','DFW','BOS','Y','','VU/1',341.00,0.00
+'7100275','DFW','BWI','F','AA','',630.00,1260.00
+'7100276','DFW','BWI','F','','',622.00,1244.00
+'7100277','DFW','BWI','Y','AA','',420.00,840.00
+'7100278','DFW','BWI','Y','','',415.00,830.00
+'7100279','DFW','BWI','B','','VU/1',288.00,0.00
+'7100280','DFW','BWI','Y','','VU/1',288.00,0.00
+'7100281','DFW','DEN','F','','',489.00,978.00
+'7100282','DFW','DEN','F','DL','',481.00,962.00
+'7100283','DFW','DEN','FN','AA','',344.00,688.00
+'7100284','DFW','DEN','FN','','',336.00,672.00
+'7100285','DFW','DEN','Y','','',305.00,610.00
+'7100286','DFW','DEN','Y','DL','',300.00,600.00
+'7100287','DFW','DEN','YN','AA','',261.00,522.00
+'7100288','DFW','DEN','YN','','',256.00,512.00
+'7100289','DFW','DEN','QW','','AP/80',0.00,268.00
+'7100290','DFW','DEN','QX','','AP/80',0.00,228.00
+'7100291','DFW','DEN','B','','VU/1',208.00,0.00
+'7100292','DFW','DEN','Y','','VU/1',208.00,0.00
+'7100293','DFW','OAK','F','AA','',717.00,1434.00
+'7100294','DFW','OAK','F','','',646.00,1292.00
+'7100295','DFW','OAK','FN','','',504.00,1008.00
+'7100296','DFW','OAK','Y','AA','',478.00,956.00
+'7100297','DFW','OAK','Y','','',467.00,934.00
+'7100298','DFW','OAK','YN','','',386.00,772.00
+'7100299','DFW','OAK','QW','','AP/80',0.00,378.00
+'7100300','DFW','OAK','QX','','AP/80',0.00,338.00
+'7100301','DFW','OAK','Y','','VU/1',328.00,0.00
+'7100302','DFW','PHL','F','AA','',745.00,1490.00
+'7100303','DFW','PHL','F','','',737.00,1474.00
+'7100304','DFW','PHL','FN','','',516.00,1032.00
+'7100305','DFW','PHL','Y','AA','',496.00,992.00
+'7100306','DFW','PHL','Y','DL','',491.00,982.00
+'7100307','DFW','PHL','YN','','',396.00,792.00
+'7100308','DFW','PHL','B','','VU/1',341.00,0.00
+'7100309','DFW','PHL','Y','','VU/1',341.00,0.00
+'7100310','DFW','PIT','F','','',611.00,1222.00
+'7100311','DFW','PIT','Y','AA','',420.00,840.00
+'7100312','DFW','PIT','Y','AA','',380.00,760.00
+'7100313','DFW','PIT','Y','','',375.00,750.00
+'7100314','DFW','PIT','B','','VU/1',279.00,0.00
+'7100315','DFW','PIT','Y','','VU/1',260.00,0.00
+'7100316','DFW','SFO','F','','',717.00,1434.00
+'7100317','DFW','SFO','F','DL','',709.00,1418.00
+'7100318','DFW','SFO','FN','AA','',504.00,1008.00
+'7100319','DFW','SFO','FN','','',496.00,992.00
+'7100320','DFW','SFO','Y','','',478.00,956.00
+'7100321','DFW','SFO','Y','DL','',473.00,946.00
+'7100322','DFW','SFO','YN','AA','',386.00,772.00
+'7100323','DFW','SFO','YN','','',381.00,762.00
+'7100324','DFW','SFO','QW','','AP/80',0.00,378.00
+'7100325','DFW','SFO','QX','','AP/80',0.00,338.00
+'7100326','DFW','SFO','B','','VU/1',328.00,0.00
+'7100327','DFW','SFO','Y','','VU/1',328.00,0.00
+'7100328','OAK','BOS','F','','',836.00,1672.00
+'7100329','OAK','BOS','Y','','',557.00,1114.00
+'7100330','OAK','BOS','QW','','AP/80',0.00,418.00
+'7100331','OAK','BOS','QX','','AP/80',0.00,378.00
+'7100332','OAK','BOS','Y','','VU/1',394.00,0.00
+'7100333','OAK','DEN','F','','',488.00,976.00
+'7100334','OAK','DEN','Y','','',325.00,650.00
+'7100335','OAK','DEN','QW','','AP/80',0.00,288.00
+'7100336','OAK','DEN','QX','','AP/80',0.00,248.00
+'7100337','OAK','DEN','Y','','VU/1',222.00,0.00
+'7100338','OAK','DFW','F','','',717.00,1434.00
+'7100339','OAK','DFW','FN','','',504.00,1008.00
+'7100340','OAK','DFW','Y','','',478.00,956.00
+'7100341','OAK','DFW','YN','','',386.00,772.00
+'7100342','OAK','DFW','Y','','VU/1',328.00,0.00
+'7100343','OAK','PHL','F','AA','',877.00,1754.00
+'7100344','OAK','PHL','Y','AA','',584.00,1168.00
+'7100345','OAK','PHL','B','AA','',488.00,976.00
+'7100346','OAK','PHL','Y','','VU/1',402.00,0.00
+'7100347','OAK','SFO','Y','','',110.00,220.00
+'7100348','OAK','SFO','YN','','',54.00,108.00
+'7100349','OAK','SFO','Y','AA','VU/1',61.00,0.00
+'7100350','PHL','ATL','F','US','',465.00,930.00
+'7100351','PHL','ATL','F','','',449.00,898.00
+'7100352','PHL','ATL','FN','','',314.00,628.00
+'7100353','PHL','ATL','Y','DL','',295.00,590.00
+'7100354','PHL','ATL','Y','EA','',295.00,590.00
+'7100355','PHL','ATL','Y','','',290.00,580.00
+'7100356','PHL','ATL','YN','','',243.00,486.00
+'7100357','PHL','ATL','KW','','AP/57',0.00,268.00
+'7100358','PHL','ATL','QW','','AP/57',0.00,268.00
+'7100359','PHL','ATL','KX','','AP/57',0.00,228.00
+'7100360','PHL','ATL','QX','','AP/57',0.00,228.00
+'7100361','PHL','ATL','B','','VU/1',205.00,0.00
+'7100362','PHL','ATL','Y','','VU/1',205.00,0.00
+'7100363','PHL','BOS','F','','',210.00,420.00
+'7100364','PHL','BOS','FN','','',147.00,294.00
+'7100365','PHL','BOS','Y','DL','',147.00,294.00
+'7100366','PHL','BOS','B','DL','',140.00,280.00
+'7100367','PHL','BOS','K','','',140.00,280.00
+'7100368','PHL','BOS','Y','DL','',140.00,280.00
+'7100369','PHL','BOS','Y','','',140.00,280.00
+'7100370','PHL','BOS','B','','AP/75',0.00,270.00
+'7100371','PHL','BOS','B','DL','',129.00,258.00
+'7100372','PHL','BOS','YN','','',119.00,238.00
+'7100373','PHL','BOS','B','US','',109.00,218.00
+'7100374','PHL','BOS','M','ML','',109.00,218.00
+'7100375','PHL','BOS','Q','','AP/27',0.00,188.00
+'7100376','PHL','BOS','B','','AP/44',129.00,0.00
+'7100377','PHL','BOS','B','','VU/1',102.00,0.00
+'7100378','PHL','BOS','Y','','VU/1',97.00,0.00
+'7100379','PHL','BWI','Y','','',165.00,330.00
+'7100380','PHL','BWI','M','','',106.00,212.00
+'7100381','PHL','BWI','Y','','VU/1',115.00,0.00
+'7100382','PHL','DEN','F','','',706.00,1412.00
+'7100383','PHL','DEN','F','DL','',630.00,1260.00
+'7100384','PHL','DEN','Y','','',470.00,940.00
+'7100385','PHL','DEN','Y','DL','',420.00,840.00
+'7100386','PHL','DEN','KW','','AP/57',0.00,488.00
+'7100387','PHL','DEN','KX','','AP/57',0.00,418.00
+'7100388','PHL','DEN','QW','','AP/80',0.00,348.00
+'7100389','PHL','DEN','QX','','AP/80',0.00,278.00
+'7100390','PHL','DEN','Y','','VU/1',323.00,0.00
+'7100391','PHL','DEN','B','','VU/1',297.00,0.00
+'7100392','PHL','DFW','F','AA','',745.00,1490.00
+'7100393','PHL','DFW','F','','',737.00,1474.00
+'7100394','PHL','DFW','Y','AA','',496.00,992.00
+'7100395','PHL','DFW','Y','DL','',491.00,982.00
+'7100396','PHL','DFW','B','','VU/1',341.00,0.00
+'7100397','PHL','DFW','Y','AA','VU/1',341.00,0.00
+'7100398','PHL','DFW','M','','AP/68',284.00,0.00
+'7100399','PHL','DFW','Y','','VU/1',283.00,0.00
+'7100400','PHL','OAK','F','AA','',877.00,1754.00
+'7100401','PHL','OAK','Y','AA','',584.00,1168.00
+'7100402','PHL','OAK','B','AA','',488.00,976.00
+'7100403','PHL','OAK','Y','','VU/1',402.00,0.00
+'7100404','PHL','PIT','F','','',189.00,378.00
+'7100405','PHL','PIT','Y','','',131.00,262.00
+'7100406','PHL','PIT','Y','','VU/1',88.00,0.00
+'7100407','PHL','SFO','F','US','',995.00,1990.00
+'7100408','PHL','SFO','F','','',887.00,1774.00
+'7100409','PHL','SFO','Y','','',591.00,1182.00
+'7100410','PHL','SFO','Y','US','',586.00,1172.00
+'7100411','PHL','SFO','B','US','',483.00,966.00
+'7100412','PHL','SFO','QW','','AP/80',0.00,418.00
+'7100413','PHL','SFO','QX','','AP/80',0.00,378.00
+'7100414','PHL','SFO','B','','AP/55',488.00,0.00
+'7100415','PHL','SFO','B','','VU/1',407.00,0.00
+'7100416','PHL','SFO','M','','VU/1',407.00,0.00
+'7100417','PHL','SFO','Y','','VU/1',407.00,0.00
+'7100418','PHL','SFO','Y','US','VU/1',388.00,0.00
+'7100419','PIT','ATL','F','','',416.00,832.00
+'7100420','PIT','ATL','FN','','',291.00,582.00
+'7100421','PIT','ATL','Y','','',274.00,548.00
+'7100422','PIT','ATL','YN','','',217.00,434.00
+'7100423','PIT','ATL','KW','','AP/57',0.00,268.00
+'7100424','PIT','ATL','QW','','AP/57',0.00,248.00
+'7100425','PIT','ATL','KX','','AP/57',0.00,228.00
+'7100426','PIT','ATL','QX','','AP/57',0.00,208.00
+'7100427','PIT','ATL','B','','VU/1',190.00,0.00
+'7100428','PIT','ATL','Y','','VU/1',190.00,0.00
+'7100429','PIT','BOS','F','','',330.00,660.00
+'7100430','PIT','BOS','Y','','',240.00,480.00
+'7100431','PIT','BOS','Y','','VU/1',153.00,0.00
+'7100432','PIT','BWI','F','','',172.00,344.00
+'7100433','PIT','BWI','Y','','',119.00,238.00
+'7100434','PIT','BWI','Y','','VU/1',80.00,0.00
+'7100435','PIT','DEN','F','US','',647.00,1294.00
+'7100436','PIT','DEN','F','','',607.00,1214.00
+'7100437','PIT','DEN','Y','AA','',422.00,844.00
+'7100438','PIT','DEN','Y','','',412.00,824.00
+'7100439','PIT','DEN','Q','','',287.00,574.00
+'7100440','PIT','DEN','M','','',282.00,564.00
+'7100441','PIT','DEN','Y','AA','VU/1',299.00,0.00
+'7100442','PIT','DEN','Y','','VU/1',285.00,0.00
+'7100443','PIT','DFW','F','','',611.00,1222.00
+'7100444','PIT','DFW','Y','AA','',420.00,840.00
+'7100445','PIT','DFW','Y','AA','',380.00,760.00
+'7100446','PIT','DFW','Y','','',375.00,750.00
+'7100447','PIT','DFW','BW','','AP/57',0.00,428.00
+'7100448','PIT','DFW','BX','','AP/57',0.00,378.00
+'7100449','PIT','DFW','B','','VU/1',279.00,0.00
+'7100450','PIT','DFW','M','','VU/1',260.00,0.00
+'7100451','PIT','DFW','Y','','VU/1',260.00,0.00
+'7100452','PIT','PHL','F','','',189.00,378.00
+'7100453','PIT','PHL','Y','','',131.00,262.00
+'7100454','PIT','PHL','Y','','VU/1',88.00,0.00
+'7100455','PIT','SFO','F','US','',819.00,1638.00
+'7100456','PIT','SFO','Y','','',546.00,1092.00
+'7100457','PIT','SFO','QW','','AP/80',0.00,398.00
+'7100458','PIT','SFO','QX','','AP/80',0.00,358.00
+'7100459','PIT','SFO','Y','','VU/1',379.00,0.00
+'7100460','SFO','ATL','F','','',828.00,1656.00
+'7100461','SFO','ATL','F','AA','',821.00,1642.00
+'7100462','SFO','ATL','FN','','',580.00,1160.00
+'7100463','SFO','ATL','Y','','',552.00,1104.00
+'7100464','SFO','ATL','Y','AA','',547.00,1094.00
+'7100465','SFO','ATL','B','AA','',475.00,950.00
+'7100466','SFO','ATL','YN','EA','',445.00,890.00
+'7100467','SFO','ATL','YN','DL','',442.00,884.00
+'7100468','SFO','ATL','M','AA','',430.00,860.00
+'7100469','SFO','ATL','QW','','AP/57',0.00,398.00
+'7100470','SFO','ATL','QX','','AP/57',0.00,358.00
+'7100471','SFO','ATL','K','','AP/68',435.00,0.00
+'7100472','SFO','ATL','Q','','AP/68',435.00,0.00
+'7100473','SFO','ATL','B','','VU/1',383.00,0.00
+'7100474','SFO','ATL','Y','AA','VU/1',383.00,0.00
+'7100475','SFO','ATL','Y','','VU/1',376.00,0.00
+'7100476','SFO','BOS','F','US','',995.00,1990.00
+'7100477','SFO','BOS','F','DL','',890.00,1780.00
+'7100478','SFO','BOS','F','','',860.00,1720.00
+'7100479','SFO','BOS','C','','',635.00,1270.00
+'7100480','SFO','BOS','Y','TW','',605.00,1210.00
+'7100481','SFO','BOS','Y','UA','',605.00,1210.00
+'7100482','SFO','BOS','Y','DL','',593.00,1186.00
+'7100483','SFO','BOS','Y','','',573.00,1146.00
+'7100484','SFO','BOS','Y','US','',568.00,1136.00
+'7100485','SFO','BOS','B','AA','',508.00,1016.00
+'7100486','SFO','BOS','B','DL','',503.00,1006.00
+'7100487','SFO','BOS','B','US','',503.00,1006.00
+'7100488','SFO','BOS','KW','','AP/57',0.00,418.00
+'7100489','SFO','BOS','QW','','AP/80',0.00,418.00
+'7100490','SFO','BOS','KX','','AP/57',0.00,378.00
+'7100491','SFO','BOS','QX','','AP/80',0.00,378.00
+'7100492','SFO','BOS','B','','VU/1',412.00,0.00
+'7100493','SFO','BOS','M','','VU/1',394.00,0.00
+'7100494','SFO','BOS','Y','','VU/1',394.00,0.00
+'7100495','SFO','BWI','F','','',781.00,1562.00
+'7100496','SFO','BWI','Y','','',516.00,1032.00
+'7100497','SFO','BWI','B','','',449.00,898.00
+'7100498','SFO','BWI','Q','','',405.00,810.00
+'7100499','SFO','BWI','Y','','VU/1',358.00,0.00
+'7100500','SFO','DEN','F','','',488.00,976.00
+'7100501','SFO','DEN','Y','','',325.00,650.00
+'7100502','SFO','DEN','QW','','AP/80',0.00,288.00
+'7100503','SFO','DEN','QX','','AP/80',0.00,248.00
+'7100504','SFO','DEN','Y','','VU/1',222.00,0.00
+'7100505','SFO','DFW','F','','',717.00,1434.00
+'7100506','SFO','DFW','F','DL','',709.00,1418.00
+'7100507','SFO','DFW','FN','AA','',504.00,1008.00
+'7100508','SFO','DFW','FN','','',496.00,992.00
+'7100509','SFO','DFW','Y','','',478.00,956.00
+'7100510','SFO','DFW','Y','DL','',473.00,946.00
+'7100511','SFO','DFW','YN','AA','',386.00,772.00
+'7100512','SFO','DFW','YN','','',381.00,762.00
+'7100513','SFO','DFW','QW','','AP/80',0.00,378.00
+'7100514','SFO','DFW','QX','','AP/80',0.00,338.00
+'7100515','SFO','DFW','B','','VU/1',328.00,0.00
+'7100516','SFO','DFW','Y','','VU/1',328.00,0.00
+'7100517','SFO','OAK','Y','','',110.00,220.00
+'7100518','SFO','OAK','YN','','',54.00,108.00
+'7100519','SFO','OAK','Y','AA','VU/1',61.00,0.00
+'7100520','SFO','PHL','F','US','',995.00,1990.00
+'7100521','SFO','PHL','F','','',887.00,1774.00
+'7100522','SFO','PHL','Y','','',591.00,1182.00
+'7100523','SFO','PHL','Y','US','',586.00,1172.00
+'7100524','SFO','PHL','B','US','',483.00,966.00
+'7100525','SFO','PHL','QW','','AP/80',0.00,418.00
+'7100526','SFO','PHL','QX','','AP/80',0.00,378.00
+'7100527','SFO','PHL','B','','AP/55',488.00,0.00
+'7100528','SFO','PHL','B','','VU/1',407.00,0.00
+'7100529','SFO','PHL','M','','VU/1',407.00,0.00
+'7100530','SFO','PHL','Y','','VU/1',407.00,0.00
+'7100531','SFO','PHL','Y','US','VU/1',388.00,0.00
+'7100532','SFO','PIT','F','US','',819.00,1638.00
+'7100533','SFO','PIT','Y','','',546.00,1092.00
+'7100534','SFO','PIT','Y','','VU/1',379.00,0.00
diff --git a/sql-bench/Data/ATIS/flight.txt b/sql-bench/Data/ATIS/flight.txt
new file mode 100644
index 00000000000..9f68008518e
--- /dev/null
+++ b/sql-bench/Data/ATIS/flight.txt
@@ -0,0 +1,579 @@
+101908,'1234567','ATL','BOS',636,1000,'DL',296,'FNYNBNMQ','72S','B',1,'N',204
+101909,'1234567','ATL','BOS',641,855,'DL',314,'FNYNBNMQ','72S','B',0,'N',134
+101910,'1234567','ATL','BOS',755,1019,'EA',140,'FYHQK','D9S','B',0,'N',144
+101911,'1234567','ATL','BOS',920,1150,'EA',534,'FYHQK','D9S','B',0,'N',150
+101912,'1234567','ATL','BOS',959,1215,'DL',410,'FYBMQ','757','B',0,'N',136
+101913,'1234567','ATL','BOS',1010,1355,'DL',726,'FYBMQ','72S','S',1,'N',225
+101914,'1234567','ATL','BOS',1057,1320,'EA',640,'YHQKL','72S','L',0,'N',143
+101915,'1234567','ATL','BOS',1229,1456,'EA',142,'FYHQK','D9S','L',0,'N',147
+101916,'-----6-','ATL','BOS',1325,1550,'DL',110,'FYBMQ','767','L',0,'N',145
+101917,'12345-7','ATL','BOS',1325,1550,'DL',110,'FYBMQ','763','L',0,'N',145
+101918,'1234567','ATL','BOS',1426,1656,'EA',644,'FYHQK','D9S','S',0,'N',150
+101922,'1234567','ATL','BOS',1655,1920,'DL',134,'FYBMQ','L10','D',0,'N',145
+101923,'1234567','ATL','BOS',1800,2032,'EA',144,'FYHQK','757','D',0,'N',152
+101924,'1234567','ATL','BOS',1851,2219,'DL',106,'FYBMQ','M80','D',1,'N',208
+101925,'1234567','ATL','BOS',1855,2122,'DL',326,'FYBMQ','72S','D',0,'N',147
+101926,'1234567','ATL','BOS',1950,2220,'EA',148,'FYHQK','D9S','S',0,'N',150
+101927,'------7','ATL','BOS',2035,2255,'DL',166,'FYBMQ','L10','S/',0,'N',140
+101928,'123456-','ATL','BOS',2035,2255,'DL',116,'FYBMQ','L10','S/',0,'N',140
+101929,'1234567','ATL','BOS',2345,153,'DL',162,'FNYNBNMQ','757','',0,'N',128
+101951,'1234567','ATL','BWI',915,1055,'EA',202,'FYHQK','D9S','S',0,'N',100
+101952,'1234567','ATL','BWI',1002,1145,'DL',1204,'FYBMQ','M80','',0,'N',103
+101953,'1234567','ATL','BWI',1330,1510,'DL',662,'FYBMQ','M80','L',0,'N',100
+101954,'1234567','ATL','BWI',1423,1610,'EA',206,'FYHQK','D9S','',0,'N',107
+101955,'1234567','ATL','BWI',1704,1850,'DL',294,'FYBMQ','757','D',0,'N',106
+101956,'1234567','ATL','BWI',1800,1937,'EA',210,'FYHQK','D9S','D',0,'N',97
+101957,'1234567','ATL','BWI',1955,2140,'EA',212,'FYHQK','D9S','S',0,'N',105
+101958,'1234567','ATL','BWI',2048,2230,'DL',256,'FYBMQ','757','',0,'N',102
+101959,'1234567','ATL','BWI',2140,2318,'EA',208,'FNYNHQNK','72S','',0,'N',98
+102122,'1234567','ATL','DEN',840,955,'DL',445,'FYBMQ','757','B',0,'N',195
+102123,'1234567','ATL','DEN',934,1054,'EA',821,'FYHQK','72S','B',0,'N',200
+102125,'1234567','ATL','DEN',1000,1124,'UA',915,'FYBMQ','73S','S',0,'N',204
+102126,'1234567','ATL','DEN',1200,1305,'DL',257,'FYBMQ','72S','L',0,'N',185
+102127,'1234567','ATL','DEN',1510,1615,'DL',1083,'FYBMQ','72S','S',0,'N',185
+102128,'1234567','ATL','DEN',1755,1910,'EA',825,'FYHQK','72S','D',0,'N',195
+102129,'1234567','ATL','DEN',1825,1946,'UA',673,'FYBMQ','733','D',0,'N',201
+102133,'1234567','ATL','DEN',1900,2015,'DL',675,'FYBMQ','72S','D',0,'N',195
+102134,'1234567','ATL','DEN',2145,2308,'EA',823,'FNYNHQNK','757','S',0,'N',203
+102135,'1234567','ATL','DEN',2219,2320,'DL',229,'FNYNBNMQ','72S','',0,'N',181
+102136,'--34567','ATL','DFW',630,740,'DL',131,'FNYNBNMQ','L10','B',0,'N',130
+102137,'12-----','ATL','DFW',630,740,'DL',131,'FNYNBNMQ','763','B',0,'N',130
+102139,'1234567','ATL','DFW',730,849,'AA',1339,'FYBMV','M80','B',0,'N',139
+102144,'1234567','ATL','DFW',823,930,'DL',671,'FYBMQ','72S','B',0,'N',127
+102147,'1234567','ATL','DFW',901,1027,'AA',447,'FYBMV','M80','S',0,'N',146
+102148,'1234567','ATL','DFW',1000,1110,'DL',17,'FYBMQ','L15','S',0,'N',130
+102150,'1234567','ATL','DFW',1145,1250,'DL',545,'FYBMQ','72S','L',0,'N',125
+102162,'--34567','ATL','DFW',1319,1430,'DL',179,'FYBMQ','763','L',0,'N',131
+102163,'12-----','ATL','DFW',1319,1430,'DL',179,'FYBMQ','L10','L',0,'N',131
+102164,'1234567','ATL','DFW',1347,1505,'AA',237,'FYBMV','M80','S',0,'N',138
+102165,'-2-----','ATL','DFW',1415,1525,'LH',442,'FCBMK','74M','D',0,'N',130
+102166,'1234567','ATL','DFW',1510,1620,'DL',1145,'FYBMQ','757','S',0,'N',130
+102172,'1234567','ATL','DFW',1634,1759,'AA',351,'FYBMV','M80','S',0,'N',145
+102173,'1234567','ATL','DFW',1650,1805,'DL',82,'FYBMQ','L10','D',0,'N',135
+102177,'1234567','ATL','DFW',1840,1955,'DL',405,'FYBMQ','M80','D',0,'N',135
+102188,'1234567','ATL','DFW',1925,2050,'AA',1419,'FNYNBMV','M80','D',0,'N',145
+102190,'1234567','ATL','DFW',2029,2140,'DL',275,'FNYNBNMQ','763','',0,'N',131
+102191,'1234567','ATL','DFW',2213,2321,'DL',574,'FNYNBNMQ','M80','',0,'N',128
+102192,'12345-7','ATL','DFW',2335,40,'DL',1107,'FNYNBNMQ','D9S','',0,'N',125
+102674,'1234567','ATL','OAK',1825,2205,'UA',673,'FYBMQ','733','D',1,'N',400
+102766,'1234567','ATL','PHL',636,825,'DL',296,'FNYNBNMQ','72S','B',0,'N',109
+102767,'1234567','ATL','PHL',740,929,'US',258,'FYBHQ','D9S','B',0,'N',109
+102768,'1234567','ATL','PHL',805,956,'EA',124,'FYHQK','D9S','B',0,'N',111
+102769,'1234567','ATL','PHL',935,1125,'EA',126,'FYHQK','D9S','S',0,'N',110
+102770,'1234567','ATL','PHL',1010,1200,'DL',726,'FYBMQ','72S','',0,'N',110
+102771,'1234567','ATL','PHL',1200,1345,'US',29,'FYBHQ','733','L',0,'N',105
+102772,'1234567','ATL','PHL',1215,1415,'EA',610,'FYHQK','D9S','L',0,'N',120
+102773,'1234567','ATL','PHL',1322,1515,'DL',424,'FYBMQ','72S','L',0,'N',113
+102774,'1234567','ATL','PHL',1417,1607,'EA',324,'FYHQK','D9S','',0,'N',110
+102775,'1234567','ATL','PHL',1605,1800,'EA',602,'FYHQK','D9S','S',0,'N',115
+102776,'1234567','ATL','PHL',1649,1840,'DL',1206,'FYBMQ','767','D',0,'N',111
+102777,'1234567','ATL','PHL',1650,1835,'US',1786,'FYBHQ','73S','D',0,'N',105
+102778,'1234567','ATL','PHL',1802,1959,'EA',120,'FYHQK','D9S','D',0,'N',117
+102779,'1234567','ATL','PHL',1851,2045,'DL',106,'FYBMQ','M80','D',0,'N',114
+102781,'1234567','ATL','PHL',1957,2151,'EA',604,'FYHQK','D9S','S',0,'N',114
+102782,'1234567','ATL','PHL',2035,2220,'DL',250,'FYBMQ','72S','',0,'N',105
+102783,'1234567','ATL','PHL',2140,2335,'EA',128,'FNYNHQNK','D9S','',0,'N',115
+102784,'1234567','ATL','PHL',2350,130,'DL',1210,'FNYNBNMQ','757','',0,'N',100
+102795,'1234567','ATL','PIT',630,803,'US',339,'FYBHQ','D9S','B',0,'N',93
+102796,'1234567','ATL','PIT',831,1000,'DL',842,'FYBMQ','D9S','B',0,'N',89
+102797,'1234567','ATL','PIT',925,1100,'EA',302,'FYHQK','D9S','S',0,'N',95
+102798,'1234567','ATL','PIT',1105,1238,'US',248,'FYBHQ','D9S','L',0,'N',93
+102799,'1234567','ATL','PIT',1225,1405,'EA',308,'FYHQK','757','L',0,'N',100
+102800,'1234567','ATL','PIT',1340,1510,'DL',628,'FYBMQ','73S','',0,'N',90
+102801,'1234567','ATL','PIT',1540,1713,'US',508,'FYBHQ','D9S','L/S',0,'N',93
+102802,'-----67','ATL','PIT',1711,1845,'DL',1132,'FYBMQ','73S','D',0,'N',94
+102803,'12345--','ATL','PIT',1711,1845,'DL',1132,'FYBMQ','72S','D',0,'N',94
+102804,'1234567','ATL','PIT',1759,1933,'EA',310,'YHQKL','72S','D',0,'N',94
+102805,'1234567','ATL','PIT',1920,2056,'US',480,'FYBHQ','D9S','D',0,'N',96
+102806,'1234567','ATL','PIT',1959,2139,'EA',312,'FYHQK','757','S/',0,'N',100
+102807,'1234567','ATL','PIT',2030,2205,'DL',1076,'FYBMQ','73S','',0,'N',95
+102808,'1234567','ATL','PIT',2145,2313,'EA',314,'FNYNHQNK','D9S','',0,'N',88
+102809,'1234567','ATL','PIT',2334,59,'DL',311,'FNYNBNMQ','D9S','',0,'N',85
+102923,'------7','ATL','SFO',912,1110,'DL',137,'FYBMQ','767','B',0,'N',298
+102924,'123456-','ATL','SFO',912,1110,'DL',137,'FYBMQ','L10','B',0,'N',298
+102925,'1234567','ATL','SFO',930,1157,'EA',71,'FYHQK','757','B',0,'N',327
+102927,'1234567','ATL','SFO',1200,1410,'DL',977,'FYBMQ','757','L',0,'N',310
+102929,'1234567','ATL','SFO',1525,1730,'DL',97,'FYBMQ','763','D',0,'N',305
+102930,'1234567','ATL','SFO',1625,1844,'EA',73,'FYHQK','757','D',0,'N',319
+102932,'1234567','ATL','SFO',1855,2115,'DL',99,'FYBMQ','767','D',0,'N',320
+102933,'1234567','ATL','SFO',2010,2229,'EA',77,'FYHQK','757','D',0,'N',319
+105584,'1234567','BOS','ATL',630,913,'DL',225,'FYBMQ','M80','B',0,'N',163
+105586,'1234567','BOS','ATL',700,946,'EA',147,'FNYNHQNK','72S','B',0,'N',166
+105588,'1234567','BOS','ATL',815,1100,'DL',219,'FYBMQ','L10','B',0,'N',165
+105589,'1234567','BOS','ATL',832,1126,'EA',643,'FYHQK','D9S','B',0,'N',174
+105590,'1234567','BOS','ATL',955,1235,'DL',547,'FYBMQ','72S','B',0,'N',160
+105591,'1234567','BOS','ATL',1035,1327,'EA',145,'FYHQK','D9S','L',0,'N',172
+105592,'1234567','BOS','ATL',1156,1435,'DL',708,'FYBMQ','767','L',0,'N',159
+105593,'1234567','BOS','ATL',1240,1525,'EA',143,'FYHQK','D9S','L',0,'N',165
+105594,'1234567','BOS','ATL',1421,1709,'EA',645,'YHQKL','72S','S',0,'N',168
+105595,'1234567','BOS','ATL',1520,1804,'DL',975,'FYBMQ','757','S',0,'N',164
+105597,'1234567','BOS','ATL',1605,1900,'EA',141,'FYHQK','72S','D',0,'N',175
+105598,'1234567','BOS','ATL',1758,2049,'EA',149,'FYHQK','D9S','D',0,'N',171
+105599,'1234567','BOS','ATL',1850,2128,'DL',323,'FYBMQ','757','D',0,'N',158
+105601,'1234567','BOS','ATL',2024,2258,'DL',541,'FNYNBNMQ','L10','S',0,'N',154
+105698,'1234567','BOS','BWI',645,811,'US',369,'FYBHQ','733','B/S',0,'N',86
+105699,'1234567','BOS','BWI',930,1056,'US',511,'FYBHQ','733','S/',0,'N',86
+105700,'1234567','BOS','BWI',1000,1127,'US',437,'FYBHQ','M80','S/',0,'N',87
+105701,'1234567','BOS','BWI',1330,1451,'US',269,'FYBHQ','D9S','S',0,'N',81
+105702,'1234567','BOS','BWI',1505,1626,'US',428,'FYBHQ','D9S','',0,'N',81
+105703,'1234567','BOS','BWI',1745,1912,'US',1581,'FYBHQ','72S','S',0,'N',87
+105704,'1234567','BOS','BWI',1955,2122,'US',1609,'FYBHQ','73S','',0,'N',87
+105705,'12345-7','BOS','BWI',2140,2306,'US',76,'FYBHQ','733','',0,'N',86
+105794,'123456-','BOS','DEN',838,1110,'UA',201,'FYBMQ','D8S','B',0,'N',272
+105795,'------7','BOS','DEN',840,1112,'UA',343,'FYBMQ','D8S','B',0,'N',272
+105796,'1234567','BOS','DEN',855,1140,'CO',1209,'FYQHK','M80','B',0,'N',285
+105798,'1234567','BOS','DEN',1425,1732,'CO',1215,'FYQHK','733','S',0,'N',307
+105799,'1234567','BOS','DEN',1720,1949,'UA',281,'FYBMQ','D8S','D',0,'N',269
+105800,'12345-7','BOS','DEN',1740,2033,'CO',1765,'FYQHK','M80','D',0,'N',293
+105801,'1234567','BOS','DFW',653,1017,'AA',315,'FYBMV','D10','B',0,'N',264
+105802,'1234567','BOS','DFW',805,1110,'DL',831,'FYBMQ','757','B',0,'N',245
+105803,'1234567','BOS','DFW',830,1209,'AA',1099,'FYBMV','M80','B',0,'N',279
+105805,'1234567','BOS','DFW',1132,1430,'DL',169,'FYBMQ','757','L',0,'N',238
+105806,'1234567','BOS','DFW',1149,1520,'AA',813,'FYBMV','767','L',0,'N',271
+105807,'1234567','BOS','DFW',1428,1750,'AA',215,'FYBMV','D10','S',0,'N',262
+105808,'1234567','BOS','DFW',1445,1755,'DL',697,'FYBMQ','72S','S',0,'N',250
+105810,'1234567','BOS','DFW',1721,2144,'DL',589,'FYBMQ','72S','SD',1,'N',323
+105811,'1234567','BOS','DFW',1740,2100,'AA',155,'FYBMV','767','D',0,'N',260
+105812,'1234567','BOS','DFW',1845,2144,'DL',487,'FYBMQ','72S','D',0,'N',239
+106229,'123456-','BOS','PHL',630,750,'US',1800,'FYBHQ','734','S',0,'N',80
+106230,'1234567','BOS','PHL',700,820,'ML',455,'FYMHQ','D9S','B/S',0,'N',80
+106231,'1234567','BOS','PHL',705,817,'US',567,'FYBHQ','72S','S',0,'N',72
+106232,'1234567','BOS','PHL',817,940,'DL',891,'FYBMQ','72S','B/S',0,'N',83
+106234,'1234567','BOS','PHL',850,1010,'US',577,'FYBHQ','100','',0,'N',80
+106235,'123456-','BOS','PHL',910,1030,'ML',437,'FYMHQ','D9S','B/S',0,'N',80
+106236,'1234567','BOS','PHL',1030,1150,'US',569,'FYBHQ','733','',0,'N',80
+106237,'1234567','BOS','PHL',1125,1245,'US',359,'FYBHQ','733','',0,'N',80
+106238,'1234567','BOS','PHL',1142,1300,'DL',949,'FYBMQ','72S','S',0,'N',78
+106239,'1234567','BOS','PHL',1215,1335,'ML',425,'FYMHQ','D9S','L/S',0,'N',80
+106240,'-2-4--7','BOS','PHL',1325,1445,'LH',420,'FCBMK','D10','',0,'N',80
+106241,'1234567','BOS','PHL',1400,1520,'ML',439,'FYMHQ','D9S','',0,'N',80
+106242,'1234567','BOS','PHL',1414,1535,'DL',639,'FYBMQ','72S','',0,'N',81
+106245,'12345-7','BOS','PHL',1510,1629,'US',731,'FYBHQ','D9S','',0,'N',79
+106246,'1234567','BOS','PHL',1545,1704,'US',297,'FYBHQ','D9S','',0,'N',79
+106247,'1234567','BOS','PHL',1645,1808,'US',1664,'FYBHQ','733','',0,'N',83
+106248,'1234567','BOS','PHL',1721,1840,'DL',589,'FYBMQ','72S','S',0,'N',79
+106249,'1234567','BOS','PHL',1745,1905,'ML',413,'FYMHQ','D9S','D/S',0,'N',80
+106250,'12345-7','BOS','PHL',1805,1924,'US',101,'FYBHQ','D9S','',0,'N',79
+106251,'12345-7','BOS','PHL',1855,2015,'US',293,'FYBHQ','733','',0,'N',80
+106252,'12345-7','BOS','PHL',1900,2019,'ML',431,'FYMHQ','D9S','D/S',0,'N',79
+106253,'1234567','BOS','PHL',1950,2111,'US',411,'FYBHQ','M80','',0,'N',81
+106254,'1234567','BOS','PHL',2033,2150,'DL',339,'FYBMQ','72S','',0,'N',77
+106255,'12345-7','BOS','PHL',2145,2304,'US',307,'FYBHQ','D9S','',0,'N',79
+106262,'123456-','BOS','PIT',630,950,'US',1800,'FYBHQ','734','S',1,'N',200
+106263,'1234567','BOS','PIT',715,857,'US',476,'FYBHQ','72S','B',0,'N',102
+106264,'1234567','BOS','PIT',810,953,'US',65,'FYBHQ','D9S','B',0,'N',103
+106265,'1234567','BOS','PIT',1145,1333,'US',167,'FYBHQ','733','S',0,'N',108
+106266,'1234567','BOS','PIT',1210,1353,'US',81,'FYBHQ','M80','S',0,'N',103
+106267,'1234567','BOS','PIT',1520,1706,'US',148,'FYBHQ','73S','S/',0,'N',106
+106268,'1234567','BOS','PIT',1640,1823,'US',303,'FYBHQ','D9S','S/',0,'N',103
+106269,'1234567','BOS','PIT',1755,1941,'US',1652,'FYBHQ','73S','S',0,'N',106
+106270,'12345-7','BOS','PIT',1855,2207,'US',293,'FYBHQ','733','',1,'N',192
+106271,'12345-7','BOS','PIT',2105,2248,'US',345,'FYBHQ','M80','',0,'N',103
+106365,'1234567','BOS','SFO',800,1131,'UA',21,'FYBMQ','D10','B',0,'N',391
+106366,'------7','BOS','SFO',840,1336,'UA',343,'FYBMQ','D8S','BL',1,'N',476
+106373,'1234567','BOS','SFO',1149,1758,'AA',813,'FYBMV','767','LD',1,'N',549
+106375,'12345-7','BOS','SFO',1740,2310,'CO',1765,'FYQHK','M80','D',1,'N',510
+106376,'1234567','BOS','SFO',1745,2127,'UA',93,'FYBMQ','D8S','D',0,'N',402
+106377,'1234567','BOS','SFO',1810,2137,'TW',61,'FCYBQ','L10','D',0,'N',387
+107159,'1234567','BWI','ATL',550,739,'DL',995,'FNYNBNMQ','M80','B',0,'N',109
+107160,'1234567','BWI','ATL',640,835,'EA',207,'FNYNHQNK','72S','B',0,'N',115
+107161,'1234567','BWI','ATL',800,1001,'EA',203,'FYHQK','D9S','B',0,'N',121
+107162,'1234567','BWI','ATL',900,1050,'DL',125,'FYBMQ','757','S',0,'N',110
+107163,'1234567','BWI','ATL',940,1137,'EA',201,'FYHQK','D9S','S',0,'N',117
+107164,'1234567','BWI','ATL',1144,1335,'EA',205,'FYHQK','D9S','L',0,'N',111
+107165,'1234567','BWI','ATL',1230,1423,'DL',539,'FYBMQ','M80','L',0,'N',113
+107166,'1234567','BWI','ATL',1600,1750,'DL',1055,'FYBMQ','M80','S/',0,'N',110
+107167,'1234567','BWI','ATL',1659,1854,'EA',131,'FYHQK','D9S','D',0,'N',115
+107168,'1234567','BWI','ATL',1945,2128,'DL',469,'FYBMQ','757','',0,'N',103
+107193,'123456-','BWI','BOS',720,839,'US',1049,'FYBHQ','72S','B/S',0,'N',79
+107194,'1234567','BWI','BOS',905,1025,'US',600,'FYBHQ','733','S/',0,'N',80
+107195,'1234567','BWI','BOS',1010,1130,'US',1508,'FYBHQ','72S','S/',0,'N',80
+107196,'1234567','BWI','BOS',1310,1430,'US',324,'FYBHQ','73S','S',0,'N',80
+107197,'1234567','BWI','BOS',1630,1749,'US',1016,'FYBHQ','72S','',0,'N',79
+107198,'1234567','BWI','BOS',1745,1905,'US',1586,'FYBHQ','73S','S',0,'N',80
+107199,'1234567','BWI','BOS',2045,2205,'US',1750,'FYBHQ','734','',0,'N',80
+107200,'1234567','BWI','BOS',2110,2231,'US',368,'FYBHQ','733','',0,'N',81
+107253,'123456-','BWI','DEN',800,1135,'US',1402,'FYBHQ','733','SB',1,'N',335
+107254,'1234567','BWI','DEN',915,1110,'UA',277,'FYBMQ','72S','B',0,'N',235
+107255,'1234567','BWI','DEN',1205,1410,'US',2123,'FYBHQ','734','L',0,'N',245
+107256,'1234567','BWI','DEN',1745,1933,'UA',707,'FYBMQ','72S','D',0,'N',228
+107257,'1234567','BWI','DFW',745,1015,'AA',195,'FYBMV','M80','B',0,'N',210
+107258,'1234567','BWI','DFW',845,1100,'DL',1028,'FYBMQ','D9S','B',0,'N',195
+107259,'1234567','BWI','DFW',1245,1518,'AA',273,'FYBMV','72S','L',0,'N',213
+107260,'1234567','BWI','DFW',1505,1745,'AA',1179,'FYBMV','M80','S',0,'N',220
+107261,'1234567','BWI','DFW',1530,1800,'DL',743,'FYBMQ','73S','S',0,'N',210
+107264,'1234567','BWI','DFW',1852,2120,'AA',599,'FYBMV','72S','D',0,'N',208
+107470,'123456-','BWI','PHL',715,808,'US',3724,'YBHQM','SH3','',0,'Y',53
+107471,'1234567','BWI','PHL',1000,1053,'US',4518,'YBHQM','DH8','',0,'Y',53
+107472,'1234567','BWI','PHL',1205,1258,'US',3533,'YBHQM','SH6','',0,'Y',53
+107473,'1234567','BWI','PHL',1325,1415,'US',4393,'YBHQM','DH8','',0,'Y',50
+107474,'12345-7','BWI','PHL',1500,1543,'US',4386,'YBHQM','DH8','',0,'Y',43
+107475,'1234567','BWI','PHL',1640,1733,'US',3738,'YBHQM','SH3','',0,'Y',53
+107476,'12345-7','BWI','PHL',1930,2020,'US',3753,'YBHQM','SH3','',0,'Y',50
+107477,'12345-7','BWI','PHL',2010,2103,'US',3721,'YBHQM','SH6','',0,'Y',53
+107478,'12345-7','BWI','PHL',2053,2146,'US',3671,'YBHQM','SH6','',0,'Y',53
+107484,'123456-','BWI','PIT',700,758,'US',351,'FYBHQ','734','S',0,'N',58
+107485,'------7','BWI','PIT',715,815,'US',931,'FYBHQ','100','S',0,'N',60
+107486,'123456-','BWI','PIT',800,901,'US',1402,'FYBHQ','733','S',0,'N',61
+107487,'1234567','BWI','PIT',1240,1343,'US',1276,'FYBHQ','733','',0,'N',63
+107488,'------7','BWI','PIT',1300,1406,'US',977,'FYBHQ','F28','',0,'N',66
+107489,'1234567','BWI','PIT',1620,1720,'US',451,'FYBHQ','72S','',0,'N',60
+107490,'1234567','BWI','PIT',1710,1812,'US',189,'FYBHQ','D9S','',0,'N',62
+107491,'1234567','BWI','PIT',1825,1928,'US',1605,'FYBHQ','733','',0,'N',63
+107492,'1234567','BWI','PIT',2100,2202,'US',1216,'FYBHQ','73S','',0,'N',62
+111886,'1234567','DEN','ATL',55,527,'DL',296,'FNYNBNMQ','72S','',0,'N',152
+111887,'1234567','DEN','ATL',215,654,'EA',820,'FNYNHQNK','757','S',0,'N',159
+111888,'1234567','DEN','ATL',800,1235,'DL',402,'FYBMQ','72S','B',0,'N',155
+111889,'1234567','DEN','ATL',825,1315,'EA',822,'FYHQK','72S','B',0,'N',170
+111891,'1234567','DEN','ATL',1039,1537,'UA',408,'FYBMQ','733','L',0,'N',178
+111892,'1234567','DEN','ATL',1055,1541,'DL',317,'FYBMQ','757','L',0,'N',166
+111893,'1234567','DEN','ATL',1155,1645,'EA',824,'FYHQK','72S','L',0,'N',170
+111894,'1234567','DEN','ATL',1450,1925,'DL',704,'FYBMQ','757','D',0,'N',155
+111895,'1234567','DEN','ATL',1815,2250,'DL',1644,'FYBMQ','72S','D',0,'N',155
+111896,'1234567','DEN','ATL',1837,2330,'UA',886,'FYBMQ','73S','D',0,'N',173
+111924,'1234567','DEN','BOS',55,1000,'DL',296,'FNYNBNMQ','72S','B',2,'N',425
+111928,'1234567','DEN','BOS',1039,1619,'UA',352,'FYBMQ','D8S','L',0,'N',220
+111929,'1234567','DEN','BOS',1105,1700,'CO',1234,'FYQHK','M80','L',0,'N',235
+111930,'1234567','DEN','BOS',1455,2205,'US',1750,'FYBHQ','734','L',1,'N',310
+111931,'1234567','DEN','BOS',1520,2056,'UA',354,'FYBMQ','72S','D',0,'N',216
+111932,'1234567','DEN','BOS',1605,2145,'CO',1220,'FYQHK','M80','D',0,'N',220
+111933,'12345-7','DEN','BOS',1935,132,'CO',1270,'FYQHK','733','D',0,'N',237
+111937,'1234567','DEN','BWI',1045,1553,'UA',658,'FYBMQ','72S','L',0,'N',188
+111939,'1234567','DEN','BWI',1455,2010,'US',1750,'FYBHQ','734','L',0,'N',195
+111941,'1234567','DEN','BWI',1828,2332,'UA',302,'FYBMQ','72S','D',0,'N',184
+112028,'1234567','DEN','DFW',450,742,'AA',1412,'FNYNBMV','M80','',0,'N',112
+112029,'123456-','DEN','DFW',605,851,'UA',216,'FYBMQ','733','B',0,'N',106
+112030,'--34567','DEN','DFW',620,906,'DL',465,'FNYNBNMQ','M80','B',0,'N',106
+112031,'12-----','DEN','DFW',620,906,'DL',465,'FNYNBNMQ','72S','B',0,'N',106
+112032,'1234567','DEN','DFW',901,1210,'AA',912,'FYBMV','M80','S',0,'N',129
+112033,'1234567','DEN','DFW',950,1235,'DL',335,'FYBMQ','M80','S',0,'N',105
+112034,'1234567','DEN','DFW',1029,1312,'UA',438,'FYBMQ','727','L',0,'N',103
+112035,'1234567','DEN','DFW',1040,1343,'AA',464,'FYBMV','M80','S',0,'N',123
+112036,'1234567','DEN','DFW',1105,1353,'CO',1226,'FYQHK','72S','L',0,'N',108
+112037,'1234567','DEN','DFW',1210,1504,'AA',242,'FYBMV','M80','L',0,'N',114
+112038,'-----6-','DEN','DFW',1310,1555,'UA',888,'FYBMQ','727','S',0,'N',105
+112039,'12345-7','DEN','DFW',1310,1555,'UA',880,'FYBMQ','727','S',0,'N',105
+112041,'1234567','DEN','DFW',1325,1615,'CO',90,'FYQHK','72S','S',0,'N',110
+112040,'1234567','DEN','DFW',1325,1615,'DL',870,'FYBMQ','M80','L',0,'N',110
+112042,'1234567','DEN','DFW',1340,1628,'AA',50,'FYBMV','M80','',0,'N',108
+112043,'1234567','DEN','DFW',1507,1753,'UA',450,'FYBMQ','727','',0,'N',106
+112044,'1234567','DEN','DFW',1605,1905,'CO',1652,'FYQHK','M80','D',0,'N',120
+112045,'1234567','DEN','DFW',1613,1923,'AA',618,'FYBMV','72S','D',0,'N',130
+112046,'1234567','DEN','DFW',1700,1943,'DL',742,'FYBMQ','72S','D',0,'N',103
+112047,'1234567','DEN','DFW',1723,2006,'UA',714,'FYBMQ','72S','D',0,'N',103
+112048,'1234567','DEN','DFW',1808,2103,'AA',1486,'FYBMV','M80','D',0,'N',115
+112049,'12345-7','DEN','DFW',1835,2122,'UA',664,'FYBMQ','727','D',0,'N',107
+112050,'1234567','DEN','DFW',1925,2220,'CO',935,'FYQHK','733','S',0,'N',115
+112051,'1234567','DEN','DFW',1955,2240,'DL',661,'FNYNBNMQ','72S','S',0,'N',105
+112052,'1234567','DEN','DFW',2036,2327,'AA',1432,'FNYNBMV','M80','',0,'N',111
+112351,'1234567','DEN','OAK',840,1014,'UA',389,'FYBMQ','727','B',0,'N',154
+112352,'1234567','DEN','OAK',1208,1339,'UA',551,'FYBMQ','727','L',0,'N',151
+112353,'1234567','DEN','OAK',1715,1852,'UA',645,'FYBMQ','73S','D',0,'N',157
+112354,'1234567','DEN','OAK',2030,2205,'UA',673,'FYBMQ','733','',0,'N',155
+112413,'1234567','DEN','PHL',55,825,'DL',296,'FNYNBNMQ','72S','B',1,'N',330
+112415,'1234567','DEN','PHL',1033,1553,'UA',270,'FYBMQ','D8S','L',0,'N',200
+112416,'1234567','DEN','PHL',1120,1705,'CO',1602,'FYQHK','733','L',0,'N',225
+112417,'1234567','DEN','PHL',1524,2041,'UA',494,'FYBMQ','D10','D',0,'N',197
+112418,'1234567','DEN','PHL',1615,2146,'CO',784,'FYQHK','72S','D/S',0,'N',211
+112440,'1234567','DEN','PIT',730,1225,'US',1039,'FYBHQ','734','B',0,'N',175
+112441,'1234567','DEN','PIT',1035,1527,'US',1520,'FYBHQ','733','B',0,'N',172
+112442,'1234567','DEN','PIT',1605,2057,'US',1421,'FYBHQ','733','D',0,'N',172
+112513,'1234567','DEN','SFO',830,1006,'UA',819,'FCYBM','D10','B',0,'N',156
+112514,'1234567','DEN','SFO',840,1041,'CO',1679,'FYQHK','733','B',0,'N',181
+112515,'1234567','DEN','SFO',935,1110,'UA',315,'FYBMQ','72S','S',0,'N',155
+112516,'1234567','DEN','SFO',1200,1336,'UA',343,'FYBMQ','D8S','L',0,'N',156
+112519,'12345-7','DEN','SFO',1220,1416,'CO',1295,'FYQHK','733','L',0,'N',176
+112518,'-----6-','DEN','SFO',1220,1416,'CO',1291,'FYQHK','72S','L',0,'N',176
+112520,'1234567','DEN','SFO',1408,1535,'UA',773,'FYBMQ','727','S',0,'N',147
+112524,'1234567','DEN','SFO',1735,1912,'UA',207,'FYBMQ','757','D',0,'N',157
+112525,'1234567','DEN','SFO',1810,1947,'CO',511,'FYQHK','72S','D/S',0,'N',157
+112526,'1234567','DEN','SFO',2045,2214,'UA',297,'FYBMQ','72S','',0,'N',149
+112527,'1234567','DEN','SFO',2130,2310,'CO',1765,'FQYNHK','M80','',0,'N',160
+112766,'1234567','DFW','ATL',625,917,'DL',16,'FYBMQ','L15','B',0,'N',112
+112771,'1234567','DFW','ATL',658,950,'AA',864,'FNYNBMV','M80','B',0,'N',112
+112772,'1234567','DFW','ATL',800,1050,'DL',83,'FYBMQ','L10','B',0,'N',110
+112773,'1234567','DFW','ATL',945,1244,'DL',790,'FYBMQ','767','S',0,'N',119
+112777,'1234567','DFW','ATL',1140,1434,'DL',446,'FYBMQ','M80','L',0,'N',114
+112783,'1234567','DFW','ATL',1251,1549,'AA',504,'FYBMV','M80','L',0,'N',118
+112784,'1234567','DFW','ATL',1305,1606,'DL',796,'FYBMQ','763','L',0,'N',121
+112789,'1234567','DFW','ATL',1442,1746,'AA',482,'FYBMV','M80','S',0,'N',124
+112790,'1234567','DFW','ATL',1501,1753,'DL',688,'FYBMQ','763','S',0,'N',112
+112793,'--34567','DFW','ATL',1650,1943,'DL',748,'FYBMQ','L10','D',0,'N',113
+112794,'12-----','DFW','ATL',1650,1943,'DL',748,'FYBMQ','763','D',0,'N',113
+112797,'-2-----','DFW','ATL',1705,2005,'LH',443,'FCBMK','74M','D',0,'N',120
+112798,'1234567','DFW','ATL',1716,2016,'AA',222,'FYBMV','M80','D',0,'N',120
+112802,'1234567','DFW','ATL',1840,2133,'DL',832,'FYBMQ','M80','D',0,'N',113
+112804,'1234567','DFW','ATL',1958,2255,'AA',496,'FNYNBMV','M80','S/',0,'N',117
+112805,'1234567','DFW','ATL',2010,2258,'DL',1720,'FYBMQ','72S','S/',0,'N',108
+112806,'1234567','DFW','ATL',2215,100,'DL',1008,'FNYNBNMQ','D9S','',0,'N',105
+112807,'1234567','DFW','ATL',2257,151,'AA',628,'FNYNBMV','M80','',0,'N',114
+112808,'1234567','DFW','ATL',2345,230,'DL',1030,'FNYNBNMQ','M80','',0,'N',105
+112864,'1234567','DFW','BOS',641,1104,'AA',928,'FYBMV','767','B',0,'N',203
+112867,'12-----','DFW','BOS',1005,1435,'DL',694,'FYBMQ','72S','B',0,'N',210
+112866,'--34567','DFW','BOS',1005,1435,'DL',694,'FYBMQ','M80','B',0,'N',210
+112869,'1234567','DFW','BOS',1304,1730,'AA',28,'FYBMV','D10','L/S',0,'N',206
+112870,'1234567','DFW','BOS',1315,1755,'DL',128,'FYBMQ','757','L',0,'N',220
+112872,'1234567','DFW','BOS',1448,1925,'AA',634,'FYBMV','767','S',0,'N',217
+112873,'1234567','DFW','BOS',1705,2125,'DL',670,'FYBMQ','72S','D',0,'N',200
+112874,'1234567','DFW','BOS',1719,2152,'AA',154,'FYBMV','D10','D',0,'N',213
+112903,'1234567','DFW','BWI',822,1200,'AA',314,'FYBMV','72S','B',0,'N',158
+112904,'1234567','DFW','BWI',1020,1400,'DL',430,'FYBMQ','73S','L',0,'N',160
+112905,'1234567','DFW','BWI',1426,1807,'AA',600,'FYBMV','72S','S',0,'N',161
+112907,'1234567','DFW','BWI',1708,2045,'DL',605,'FYBMQ','M80','D',0,'N',157
+112908,'1234567','DFW','BWI',1717,2110,'AA',268,'FYBMV','M80','D',0,'N',173
+112909,'1234567','DFW','BWI',1957,2334,'AA',376,'FYBMV','72S','S',0,'N',157
+112989,'1234567','DFW','DEN',650,800,'CO',1149,'FYQHK','733','B',0,'N',130
+112990,'1234567','DFW','DEN',658,753,'AA',1443,'FYBMV','M80','B',0,'N',115
+112991,'123456-','DFW','DEN',700,753,'UA',953,'FYBMQ','72S','B',0,'N',113
+112992,'1234567','DFW','DEN',816,910,'DL',416,'FYBMQ','M80','B',0,'N',114
+112993,'1234567','DFW','DEN',822,932,'AA',445,'FYBMV','M80','B',0,'N',130
+112994,'1234567','DFW','DEN',830,921,'UA',985,'FYBMQ','727','B',0,'N',111
+112995,'1234567','DFW','DEN',941,1047,'AA',521,'FYBMV','M80','S',0,'N',126
+112996,'-----6-','DFW','DEN',1030,1130,'CO',1291,'FYQHK','72S','S',0,'N',120
+112997,'12345-7','DFW','DEN',1030,1130,'CO',215,'FYQHK','72S','S',0,'N',120
+112998,'1234567','DFW','DEN',1032,1125,'UA',551,'FYBMQ','727','S',0,'N',113
+112999,'1234567','DFW','DEN',1108,11,'AA',419,'FYBMV','M80','S',0,'N',123
+113000,'1234567','DFW','DEN',1151,1245,'DL',551,'FYBMQ','M80','L',0,'N',114
+113001,'1234567','DFW','DEN',1240,1333,'UA',773,'FYBMQ','727','L',0,'N',113
+113002,'1234567','DFW','DEN',1428,1528,'AA',1249,'FYBMV','72S','',0,'N',120
+113003,'1234567','DFW','DEN',1500,1554,'DL',309,'FYBMQ','72S','',0,'N',114
+113004,'1234567','DFW','DEN',1547,1646,'UA',725,'FYBMQ','733','',0,'N',119
+113005,'1234567','DFW','DEN',1607,1714,'AA',51,'FYBMV','M80','',0,'N',127
+113006,'1234567','DFW','DEN',1630,1729,'CO',469,'FYQHK','72S','',0,'N',119
+113007,'1234567','DFW','DEN',1835,1936,'AA',193,'FNYNBMV','M80','D',0,'N',121
+113008,'12345-7','DFW','DEN',1850,1951,'UA',475,'FYBMQ','733','D',0,'N',121
+113009,'1234567','DFW','DEN',1855,1950,'DL',807,'FYBMQ','72S','D',0,'N',115
+113010,'1234567','DFW','DEN',1940,2040,'CO',271,'FYQHK','M80','D/S',0,'N',120
+113011,'1234567','DFW','DEN',2153,2253,'AA',313,'FNYNBMV','M80','',0,'N',120
+113013,'1-----7','DFW','DEN',2225,2320,'DL',621,'FNYNBNMQ','72S','',0,'N',115
+113012,'-23456-','DFW','DEN',2225,2320,'DL',621,'FNYNBNMQ','M80','',0,'N',115
+113498,'1234567','DFW','OAK',943,1133,'AA',877,'FYBMV','M80','B',0,'N',230
+113499,'1234567','DFW','OAK',1032,1339,'UA',551,'FYBMQ','727','SL',1,'N',307
+113500,'1234567','DFW','OAK',1835,2023,'AA',459,'FYBMV','M80','D',0,'N',228
+113501,'1234567','DFW','OAK',2153,2343,'AA',367,'FNYNBMV','M80','',0,'N',230
+113576,'1234567','DFW','PHL',703,1106,'AA',124,'FYBMV','M80','B',0,'N',183
+113577,'1234567','DFW','PHL',950,1350,'DL',1006,'FYBMQ','73S','B',0,'N',180
+113578,'1234567','DFW','PHL',1303,1706,'AA',1010,'FYBMV','767','L/S',0,'N',183
+113579,'1234567','DFW','PHL',1310,1705,'DL',234,'FYBMQ','72S','L',0,'N',175
+113581,'1234567','DFW','PHL',1718,2130,'AA',586,'FYBMV','M80','D',0,'N',192
+113582,'1234567','DFW','PHL',1959,2358,'AA',1074,'FYBMV','M80','S/',0,'N',179
+113583,'1234567','DFW','PHL',2025,15,'DL',1546,'FNYNBNMQ','72S','S',0,'N',170
+113595,'1234567','DFW','PIT',825,1200,'AA',478,'FYBMV','M80','B',0,'N',155
+113596,'1234567','DFW','PIT',845,1214,'US',326,'FYBHQ','M80','B',0,'N',149
+113597,'1234567','DFW','PIT',1230,1559,'US',96,'FYBHQ','M80','L',0,'N',149
+113599,'1234567','DFW','PIT',1434,1804,'AA',296,'FYBMV','M80','S',0,'N',150
+113600,'1234567','DFW','PIT',1720,2059,'US',504,'FYBHQ','M80','D',0,'N',159
+113602,'1234567','DFW','PIT',1958,2328,'AA',144,'FYBMV','M80','S/',0,'N',150
+113705,'1234567','DFW','SFO',815,955,'DL',825,'FYBMQ','757','B',0,'N',220
+113706,'1234567','DFW','SFO',826,1013,'AA',203,'FYBMV','D10','B',0,'N',227
+113707,'1234567','DFW','SFO',935,1127,'UA',459,'FYBMQ','733','L',0,'N',232
+113709,'1234567','DFW','SFO',944,1147,'AA',125,'FYBMV','M80','B',0,'N',243
+113710,'-----6-','DFW','SFO',1030,1416,'CO',1291,'FYQHK','72S','SL',1,'N',346
+113711,'1234567','DFW','SFO',1107,59,'AA',295,'FYBMV','D10','L',0,'N',232
+113712,'1234567','DFW','SFO',1143,1325,'DL',149,'FYBMQ','767','L',0,'N',222
+113713,'1234567','DFW','SFO',1240,1535,'UA',773,'FYBMQ','727','LS',1,'N',295
+113715,'1234567','DFW','SFO',1510,1650,'DL',887,'FYBMQ','757','S',0,'N',220
+113716,'1234567','DFW','SFO',1604,1758,'AA',813,'FYBMV','767','D',0,'N',234
+113717,'1234567','DFW','SFO',1705,1858,'AA',1119,'FYBMV','767','D',0,'N',233
+113718,'1234567','DFW','SFO',1840,2029,'AA',71,'FYBMV','D10','D',0,'N',229
+113719,'1234567','DFW','SFO',1900,2050,'DL',139,'FYBMQ','757','D',0,'N',230
+113720,'1234567','DFW','SFO',2155,2341,'AA',37,'FNYNBMV','767','S',0,'N',226
+113721,'1234567','DFW','SFO',2214,2350,'DL',395,'FNYNBNMQ','757','S',0,'N',216
+133423,'1234567','OAK','BOS',1105,2056,'UA',354,'FYBMQ','72S','LD',1,'N',411
+133430,'1234567','OAK','DEN',625,949,'UA',982,'FYBMQ','733','B',0,'N',144
+133431,'1234567','OAK','DEN',1105,1417,'UA',354,'FYBMQ','72S','L',0,'N',132
+133432,'1234567','OAK','DEN',1425,1740,'UA',436,'FYBMQ','727','S',0,'N',135
+133433,'1234567','OAK','DEN',1930,2251,'UA',384,'FYBMQ','73S','S/',0,'N',141
+133434,'1234567','OAK','DFW',35,552,'AA',534,'FNYNBMV','M80','',0,'N',197
+133435,'1234567','OAK','DFW',640,1214,'AA',1086,'FYBMV','M80','B',0,'N',214
+133436,'1234567','OAK','DFW',1345,1912,'AA',1074,'FYBMV','M80','L',0,'N',207
+133516,'1234567','OAK','PHL',1345,2358,'AA',1074,'FYBMV','M80','LS/L',1,'N',433
+133567,'123456-','OAK','SFO',530,554,'AA',5112,'YNBMVQ','SWM','',0,'Y',24
+133568,'------7','OAK','SFO',735,759,'AA',5235,'YBMVQ','SWM','',0,'Y',24
+133569,'------7','OAK','SFO',1020,1055,'AA',5140,'YBMVQ','SWM','',0,'Y',35
+137221,'1234567','PHL','ATL',540,740,'DL',201,'FNYNBNMQ','72S','B',0,'N',120
+137222,'1234567','PHL','ATL',635,844,'EA',121,'FNYNHQNK','D9S','B',0,'N',129
+137223,'1234567','PHL','ATL',800,1004,'EA',601,'FYHQK','D9S','B',0,'N',124
+137224,'1234567','PHL','ATL',900,1104,'DL',803,'FYBMQ','757','S',0,'N',124
+137225,'1234567','PHL','ATL',900,1110,'US',667,'FYBHQ','733','B',0,'N',130
+137226,'1234567','PHL','ATL',930,1142,'EA',125,'FYHQK','D9S','S',0,'N',132
+137227,'1234567','PHL','ATL',1115,1320,'EA',123,'FYHQK','D9S','L',0,'N',125
+137228,'1234567','PHL','ATL',1230,1430,'DL',1083,'FYBMQ','72S','L',0,'N',120
+137229,'1234567','PHL','ATL',1304,1512,'EA',127,'FYHQK','D9S','L',0,'N',128
+137230,'1234567','PHL','ATL',1405,1605,'DL',429,'FYBMQ','72S','',0,'N',120
+137231,'1234567','PHL','ATL',1405,1615,'US',1623,'FYBHQ','73S','L/S',0,'N',130
+137232,'1234567','PHL','ATL',1500,1710,'EA',603,'FYHQK','D9S','S/',0,'N',130
+137233,'1234567','PHL','ATL',1600,1805,'DL',1507,'FYBMQ','72S','S',0,'N',125
+137234,'1234567','PHL','ATL',1700,1909,'EA',329,'FYHQK','D9S','D',0,'N',129
+137235,'1234567','PHL','ATL',1750,1950,'DL',101,'FYBMQ','72S','D',0,'N',120
+137236,'1234567','PHL','ATL',1850,2055,'EA',129,'FYHQK','D9S','D',0,'N',125
+137237,'1234567','PHL','ATL',1855,2101,'US',289,'FYBHQ','D9S','D',0,'N',126
+137238,'1234567','PHL','ATL',1935,2137,'DL',389,'FYBMQ','767','D',0,'N',122
+137315,'1234567','PHL','BOS',615,719,'DL',562,'FYBMQ','757','B/S',0,'N',64
+137316,'1234567','PHL','BOS',700,805,'US',292,'FYBHQ','733','S',0,'N',65
+137317,'123456-','PHL','BOS',700,820,'ML',436,'FYMHQ','D9S','B/S',0,'N',80
+137318,'1234567','PHL','BOS',800,907,'US',1557,'FYBHQ','73S','S',0,'N',67
+137319,'1234567','PHL','BOS',855,1000,'DL',296,'FYBMQ','72S','',0,'N',65
+137320,'1234567','PHL','BOS',1020,1127,'US',424,'FYBHQ','M80','',0,'N',67
+137321,'1234567','PHL','BOS',1020,1140,'ML',400,'FYMHQ','D9S','',0,'N',80
+137322,'1234567','PHL','BOS',1200,1315,'ML',438,'FYMHQ','D9S','L/S',0,'N',75
+137323,'1234567','PHL','BOS',1250,1355,'DL',726,'FYBMQ','72S','S',0,'N',65
+137324,'1234567','PHL','BOS',1325,1432,'US',122,'FYBHQ','D9S','',0,'N',67
+137326,'1234567','PHL','BOS',1440,1548,'US',404,'FYBHQ','72S','',0,'N',68
+137327,'1234567','PHL','BOS',1520,1627,'US',282,'FYBHQ','73S','',0,'N',67
+137328,'1234567','PHL','BOS',1540,1700,'ML',420,'FYMHQ','D9S','',0,'N',80
+137329,'1234567','PHL','BOS',1600,1707,'US',2,'FYBHQ','73S','',0,'N',67
+137330,'-2-4--7','PHL','BOS',1615,1730,'LH',421,'FCBMK','D10','',0,'N',75
+137331,'1234567','PHL','BOS',1650,1755,'DL',648,'FYBMQ','72S','S',0,'N',65
+137332,'12345-7','PHL','BOS',1700,1820,'ML',430,'FYMHQ','D9S','',0,'N',80
+137333,'1234567','PHL','BOS',1755,1902,'US',196,'FYBHQ','M80','',0,'N',67
+137334,'12345-7','PHL','BOS',1855,2002,'US',460,'FYBHQ','D9S','',0,'N',67
+137335,'1234567','PHL','BOS',1945,2053,'US',162,'FYBHQ','72S','',0,'N',68
+137336,'12345-7','PHL','BOS',2030,2137,'US',539,'FYBHQ','D9S','',0,'N',67
+137337,'1234567','PHL','BOS',2055,2215,'ML',432,'FYMHQ','D9S','',0,'N',80
+137338,'12345-7','PHL','BOS',2100,2207,'US',279,'FYBHQ','734','',0,'N',67
+137339,'1234567','PHL','BOS',2115,2219,'DL',106,'FNYNBNMQ','M80','',0,'N',64
+137353,'12345--','PHL','BWI',715,804,'US',3745,'YBHQM','SH3','',0,'Y',49
+137354,'123456-','PHL','BWI',840,929,'US',3725,'YBHQM','SH3','',0,'Y',49
+137355,'1234567','PHL','BWI',1100,1150,'US',3609,'YBHQM','SH6','',0,'Y',50
+137356,'1234567','PHL','BWI',1200,1250,'US',3765,'YBHQM','SH3','',0,'Y',50
+137357,'1234567','PHL','BWI',1335,1425,'US',4517,'YBHQM','DH8','',0,'Y',50
+137358,'1234567','PHL','BWI',1520,1620,'US',3749,'YBHQM','SH3','',0,'Y',60
+137359,'1234567','PHL','BWI',1854,1944,'US',3357,'YBHQM','J31','',0,'Y',50
+137360,'12345-7','PHL','BWI',2045,2135,'US',3753,'YBHQM','SH3','',0,'Y',50
+137361,'12345-7','PHL','BWI',2150,2240,'US',4400,'YBHQM','DH8','',0,'Y',50
+137407,'1234567','PHL','DEN',905,1107,'UA',131,'FYBMQ','D10','B',0,'N',242
+137408,'1234567','PHL','DEN',915,1138,'CO',781,'FYQHK','72S','B',0,'N',263
+137410,'1234567','PHL','DEN',1230,1615,'DL',1083,'FYBMQ','72S','LS',1,'N',345
+137412,'1234567','PHL','DEN',1753,1955,'UA',355,'FYBMQ','D8S','D',0,'N',242
+137413,'1234567','PHL','DEN',1800,2037,'CO',1631,'FYQHK','733','D',0,'N',277
+137414,'1234567','PHL','DFW',720,1014,'AA',487,'FYBMV','M80','B',0,'N',234
+137415,'1234567','PHL','DFW',830,1050,'DL',217,'FYBMQ','72S','B',0,'N',200
+137417,'1234567','PHL','DFW',1212,1502,'AA',883,'FYBMV','M80','L',0,'N',230
+137419,'1234567','PHL','DFW',1440,1710,'DL',1061,'FYBMQ','73S','S',0,'N',210
+137420,'1234567','PHL','DFW',1500,1747,'AA',459,'FYBMV','M80','S',0,'N',227
+137422,'1234567','PHL','DFW',1805,2047,'AA',573,'FYBMV','767','D',0,'N',222
+137423,'1234567','PHL','DFW',1915,2144,'DL',589,'FYBMQ','72S','D',0,'N',209
+137685,'1234567','PHL','OAK',1500,2023,'AA',459,'FYBMV','M80','SD',1,'N',503
+137732,'1234567','PHL','PIT',700,806,'US',71,'FYBHQ','733','B',0,'N',66
+137733,'1234567','PHL','PIT',740,847,'US',39,'FYBHQ','733','B',0,'N',67
+137734,'123456-','PHL','PIT',840,950,'US',1800,'FYBHQ','734','S/',0,'N',70
+137735,'1234567','PHL','PIT',1010,1115,'US',358,'FYBHQ','M80','S/',0,'N',65
+137736,'1234567','PHL','PIT',1235,1341,'US',37,'FYBHQ','733','S',0,'N',66
+137737,'1234567','PHL','PIT',1600,1706,'US',778,'FYBHQ','733','S/',0,'N',66
+137738,'1234567','PHL','PIT',1715,1822,'US',1580,'FYBHQ','734','S/',0,'N',67
+137739,'1234567','PHL','PIT',1810,1916,'US',772,'FYBHQ','72S','S',0,'N',66
+137740,'1234567','PHL','PIT',2100,2207,'US',293,'FYBHQ','733','',0,'N',67
+137811,'1234567','PHL','SFO',800,1121,'UA',143,'FYBMQ','767','B',0,'N',381
+137814,'1234567','PHL','SFO',1235,1652,'US',37,'FYBHQ','733','SL',1,'N',437
+137817,'1234567','PHL','SFO',1655,2005,'UA',101,'FYBMQ','D8S','D',0,'N',370
+138817,'1234567','PIT','ATL',600,739,'DL',357,'FNYNBNMQ','73S','B',0,'N',99
+138818,'1234567','PIT','ATL',645,825,'EA',303,'FYHQK','D9S','B',0,'N',100
+138819,'1234567','PIT','ATL',827,1004,'EA',301,'YHQKL','72S','B',0,'N',97
+138820,'1234567','PIT','ATL',845,1025,'US',573,'FYBHQ','D9S','B',0,'N',100
+138821,'1234567','PIT','ATL',910,1048,'DL',1059,'FYBMQ','D9S','S',0,'N',98
+138822,'1234567','PIT','ATL',1150,1329,'EA',307,'FYHQK','D9S','L',0,'N',99
+138823,'1234567','PIT','ATL',1245,1420,'DL',631,'FYBMQ','D9S','L',0,'N',95
+138824,'1234567','PIT','ATL',1320,1500,'US',18,'FYBHQ','D9S','L',0,'N',100
+138825,'1234567','PIT','ATL',1520,1701,'EA',311,'YHQKL','72S','S',0,'N',101
+138827,'1234567','PIT','ATL',1600,1735,'DL',709,'FYBMQ','73S','',0,'N',95
+138828,'1234567','PIT','ATL',1750,1930,'US',1103,'FYBHQ','733','D',0,'N',100
+138829,'1234567','PIT','ATL',1855,2035,'EA',327,'FYHQK','757','D',0,'N',100
+138830,'-----67','PIT','ATL',1945,2118,'DL',381,'FNYNBNMQ','73S','D',0,'N',93
+138831,'12345--','PIT','ATL',1945,2118,'DL',381,'FNYNBNMQ','72S','D',0,'N',93
+138832,'1234567','PIT','ATL',2025,2205,'US',412,'FYBHQ','D9S','D/S',0,'N',100
+138860,'1234567','PIT','BOS',710,839,'US',732,'FYBHQ','733','B',0,'N',89
+138861,'1234567','PIT','BOS',840,1006,'US',736,'FYBHQ','733','S/',0,'N',86
+138862,'1234567','PIT','BOS',1200,1328,'US',674,'FYBHQ','M80','S',0,'N',88
+138863,'1234567','PIT','BOS',1310,1440,'US',418,'FYBHQ','D9S','S',0,'N',90
+138864,'1234567','PIT','BOS',1355,1524,'US',794,'FYBHQ','D9S','S/',0,'N',89
+138865,'1234567','PIT','BOS',1640,1809,'US',14,'FYBHQ','733','S/',0,'N',89
+138866,'1234567','PIT','BOS',1800,2053,'US',162,'FYBHQ','72S','S',1,'N',173
+138867,'12345-7','PIT','BOS',1930,2058,'US',400,'FYBHQ','73S','S',0,'N',88
+138868,'1234567','PIT','BOS',2155,2322,'US',30,'FYBHQ','72S','',0,'N',87
+138878,'1234567','PIT','BWI',845,938,'US',446,'FYBHQ','72S','',0,'N',53
+138879,'1234567','PIT','BWI',1030,1129,'US',1801,'FYBHQ','734','',0,'N',59
+138880,'1234567','PIT','BWI',1400,1458,'US',538,'FYBHQ','D9S','',0,'N',58
+138881,'1234567','PIT','BWI',1525,1621,'US',1982,'FYBHQ','F28','',0,'N',56
+138882,'1234567','PIT','BWI',1640,1737,'US',2153,'FYBHQ','733','',0,'N',57
+138883,'-----6-','PIT','BWI',1810,1910,'US',975,'FYBHQ','F28','',0,'N',60
+138884,'1234567','PIT','BWI',2155,2252,'US',1793,'FYBHQ','733','',0,'N',57
+138963,'1234567','PIT','DEN',950,1135,'US',1402,'FYBHQ','733','B',0,'N',225
+138964,'1234567','PIT','DEN',1330,1510,'US',1417,'FYBHQ','733','L',0,'N',220
+138965,'1234567','PIT','DEN',1854,2253,'AA',313,'FYBMV','M80','D',1,'N',359
+138966,'1234567','PIT','DEN',2035,2226,'US',1742,'FYBHQ','734','D',0,'N',231
+138970,'1234567','PIT','DFW',640,852,'AA',493,'FYBMV','M80','B',0,'N',192
+138971,'1234567','PIT','DFW',940,1149,'US',7,'FYBHQ','M80','B',0,'N',189
+138973,'1234567','PIT','DFW',1301,1514,'AA',425,'FYBMV','M80','L/S',0,'N',193
+138974,'1234567','PIT','DFW',1430,1639,'US',503,'FYBHQ','M80','L',0,'N',189
+138976,'1234567','PIT','DFW',1854,2107,'AA',313,'FYBMV','M80','D',0,'N',193
+138977,'1234567','PIT','DFW',2020,2229,'US',19,'FYBHQ','M80','D',0,'N',189
+139264,'1234567','PIT','PHL',700,755,'US',771,'FYBHQ','72S','B',0,'N',55
+139265,'1234567','PIT','PHL',740,850,'US',620,'FYBHQ','733','B',0,'N',70
+139266,'1234567','PIT','PHL',850,958,'US',606,'FYBHQ','733','S/',0,'N',68
+139267,'1234567','PIT','PHL',1150,1251,'US',122,'FYBHQ','D9S','S',0,'N',61
+139268,'1234567','PIT','PHL',1325,1430,'US',198,'FYBHQ','733','S',0,'N',65
+139269,'1234567','PIT','PHL',1640,1745,'US',1438,'FYBHQ','733','S/',0,'N',65
+139270,'1234567','PIT','PHL',1800,1900,'US',162,'FYBHQ','72S','S',0,'N',60
+139271,'1234567','PIT','PHL',1955,2100,'US',166,'FYBHQ','733','',0,'N',65
+139272,'12345-7','PIT','PHL',2045,2145,'US',1984,'FYBHQ','73S','',0,'N',60
+139273,'1234567','PIT','PHL',2145,2250,'US',1678,'FYBHQ','734','',0,'N',65
+139353,'1234567','PIT','SFO',945,1217,'US',31,'FYBHQ','72S','B',0,'N',332
+139355,'1234567','PIT','SFO',1430,1652,'US',37,'FYBHQ','733','L',0,'N',322
+139356,'1234567','PIT','SFO',1750,2022,'US',33,'FYBHQ','733','D',0,'N',332
+139357,'1234567','PIT','SFO',2020,2250,'US',35,'FYBHQ','733','D',0,'N',330
+144059,'1234567','SFO','ATL',645,1549,'AA',504,'FYBMV','M80','BL',1,'N',364
+144060,'1234567','SFO','ATL',815,1540,'DL',98,'FYBMQ','763','B',0,'N',265
+144061,'1234567','SFO','ATL',900,1644,'EA',70,'FYHQK','757','B',0,'N',284
+144062,'------7','SFO','ATL',1215,1933,'DL',116,'FYBMQ','767','L',0,'N',258
+144063,'123456-','SFO','ATL',1215,1933,'DL',116,'FYBMQ','L10','L',0,'N',258
+144065,'1234567','SFO','ATL',1310,2041,'EA',72,'FYHQK','757','L',0,'N',271
+144066,'1234567','SFO','ATL',1530,2248,'DL',162,'FYBMQ','757','D',0,'N',258
+144067,'1234567','SFO','ATL',2220,540,'DL',156,'FNYNBNMQ','767','S',0,'N',260
+144069,'1234567','SFO','ATL',2340,657,'EA',74,'FNYNHQNK','757','S',0,'N',257
+144087,'1234567','SFO','BOS',30,1104,'AA',928,'FNYNBMV','767','B',1,'N',454
+144088,'1234567','SFO','BOS',650,1700,'CO',1234,'FYQHK','M80','BL',1,'N',430
+144089,'1234567','SFO','BOS',800,1627,'UA',92,'FYBMQ','D8S','B',0,'N',327
+144090,'1234567','SFO','BOS',825,1639,'TW',754,'FCYBQ','L10','B',0,'N',314
+144092,'123456-','SFO','BOS',1215,2255,'DL',116,'FYBMQ','L10','LS/L',1,'N',460
+144093,'1234567','SFO','BOS',1320,2322,'US',30,'FYBHQ','72S','L',1,'N',422
+144094,'1234567','SFO','BOS',1340,2202,'UA',20,'FYBMQ','D10','L',0,'N',322
+144095,'1234567','SFO','BOS',1530,153,'DL',162,'FYBMQ','757','D',1,'N',443
+144110,'1234567','SFO','BWI',755,1737,'US',2153,'FYBHQ','733','B',1,'N',402
+144143,'1234567','SFO','DEN',620,946,'UA',194,'FYBMQ','D10','B',0,'N',146
+144144,'1234567','SFO','DEN',650,1017,'CO',1234,'FYQHK','M80','B',0,'N',147
+144145,'-----6-','SFO','DEN',900,1223,'UA',888,'FYBMQ','727','B',0,'N',143
+144146,'12345--','SFO','DEN',900,1223,'UA',880,'FYBMQ','727','B',0,'N',143
+144147,'1234567','SFO','DEN',915,1244,'CO',64,'FYQHK','72S','B',0,'N',149
+144148,'1234567','SFO','DEN',1108,1428,'UA',820,'FCYBM','D10','L',0,'N',140
+144149,'1234567','SFO','DEN',1155,1523,'CO',1212,'FYQHK','733','L',0,'N',148
+144150,'1234567','SFO','DEN',1431,1753,'UA',178,'FYBMQ','D8S','S',0,'N',142
+144152,'12345-7','SFO','DEN',1520,1850,'CO',886,'FYQHK','733','S',0,'N',150
+144151,'-----6-','SFO','DEN',1520,1850,'CO',886,'FYQHK','72S','S',0,'N',150
+144153,'1234567','SFO','DEN',1825,2143,'UA',346,'FYBMQ','73S','D',0,'N',138
+144155,'1234567','SFO','DFW',20,522,'DL',374,'FNYNBNMQ','757','S',0,'N',182
+144156,'1234567','SFO','DFW',30,548,'AA',928,'FNYNBMV','767','',0,'N',198
+144157,'1234567','SFO','DFW',645,1204,'AA',504,'FYBMV','M80','B',0,'N',199
+144158,'1234567','SFO','DFW',700,1221,'DL',838,'FYBMQ','767','B',0,'N',201
+144159,'1234567','SFO','DFW',800,1315,'AA',70,'FYBMV','D10','B',0,'N',195
+144160,'-----6-','SFO','DFW',900,1555,'UA',888,'FYBMQ','727','BS',1,'N',295
+144161,'12345--','SFO','DFW',900,1555,'UA',880,'FYBMQ','727','BS',1,'N',295
+144162,'1234567','SFO','DFW',945,1503,'AA',986,'FYBMV','767','B',0,'N',198
+144163,'1234567','SFO','DFW',1059,1612,'DL',1014,'FYBMQ','757','L',0,'N',193
+144164,'1234567','SFO','DFW',1105,1622,'AA',288,'FYBMV','D10','L',0,'N',197
+144165,'1234567','SFO','DFW',1240,1808,'UA',478,'FYBMQ','733','L',0,'N',208
+144166,'1234567','SFO','DFW',1349,1910,'AA',404,'FYBMV','D10','L',0,'N',201
+144167,'1234567','SFO','DFW',1425,1937,'DL',180,'FYBMQ','767','L',0,'N',192
+144168,'1234567','SFO','DFW',1655,2215,'AA',264,'FYBMV','767','D',0,'N',200
+144169,'1234567','SFO','DFW',1750,2258,'DL',852,'FYBMQ','757','D',0,'N',188
+144477,'1234567','SFO','OAK',1250,1319,'AA',5302,'YBMVQ','SWM','',0,'Y',29
+144478,'-----6-','SFO','OAK',1749,1809,'AA',5130,'YBMVQ','SWM','',0,'Y',20
+144479,'-----6-','SFO','OAK',1831,1853,'AA',5111,'YBMVQ','SWM','',0,'Y',22
+144480,'12345-7','SFO','OAK',2221,2247,'AA',5104,'YNBMVQ','SWM','',0,'Y',26
+144541,'1234567','SFO','PHL',810,1608,'UA',130,'FYBMQ','D8S','B',0,'N',298
+144543,'1234567','SFO','PHL',1125,2100,'US',166,'FYBHQ','733','L',1,'N',395
+144547,'1234567','SFO','PHL',1330,2141,'UA',94,'FYBMQ','767','L',0,'N',311
+144572,'1234567','SFO','PIT',755,1534,'US',2153,'FYBHQ','733','B',0,'N',279
+144574,'1234567','SFO','PIT',1125,1856,'US',166,'FYBHQ','733','L',0,'N',271
+144575,'1234567','SFO','PIT',1320,2046,'US',30,'FYBHQ','72S','L',0,'N',266
+144576,'1234567','SFO','PIT',2355,726,'US',604,'FYBHQ','733','D',0,'N',271
diff --git a/sql-bench/Data/ATIS/flight_class.txt b/sql-bench/Data/ATIS/flight_class.txt
new file mode 100644
index 00000000000..fb8bd241f43
--- /dev/null
+++ b/sql-bench/Data/ATIS/flight_class.txt
@@ -0,0 +1,2895 @@
+101909,'FN'
+101909,'YN'
+101909,'BN'
+101909,'M'
+101909,'Q'
+101910,'F'
+101910,'Y'
+101910,'H'
+101910,'Q'
+101910,'K'
+101911,'F'
+101911,'Y'
+101911,'H'
+101911,'Q'
+101911,'K'
+101912,'F'
+101912,'Y'
+101912,'B'
+101912,'M'
+101912,'Q'
+101914,'Y'
+101914,'H'
+101914,'Q'
+101914,'K'
+101914,'L'
+101915,'F'
+101915,'Y'
+101915,'H'
+101915,'Q'
+101915,'K'
+101916,'F'
+101916,'Y'
+101916,'B'
+101916,'M'
+101916,'Q'
+101917,'F'
+101917,'Y'
+101917,'B'
+101917,'M'
+101917,'Q'
+101918,'F'
+101918,'Y'
+101918,'H'
+101918,'Q'
+101918,'K'
+101922,'F'
+101922,'Y'
+101922,'B'
+101922,'M'
+101922,'Q'
+101923,'F'
+101923,'Y'
+101923,'H'
+101923,'Q'
+101923,'K'
+101925,'F'
+101925,'Y'
+101925,'B'
+101925,'M'
+101925,'Q'
+101926,'F'
+101926,'Y'
+101926,'H'
+101926,'Q'
+101926,'K'
+101927,'F'
+101927,'Y'
+101927,'B'
+101927,'M'
+101927,'Q'
+101928,'F'
+101928,'Y'
+101928,'B'
+101928,'M'
+101928,'Q'
+101929,'FN'
+101929,'YN'
+101929,'BN'
+101929,'M'
+101929,'Q'
+101951,'F'
+101951,'Y'
+101951,'H'
+101951,'Q'
+101951,'K'
+101952,'F'
+101952,'Y'
+101952,'B'
+101952,'M'
+101952,'Q'
+101953,'F'
+101953,'Y'
+101953,'B'
+101953,'M'
+101953,'Q'
+101954,'F'
+101954,'Y'
+101954,'H'
+101954,'Q'
+101954,'K'
+101955,'F'
+101955,'Y'
+101955,'B'
+101955,'M'
+101955,'Q'
+101956,'F'
+101956,'Y'
+101956,'H'
+101956,'Q'
+101956,'K'
+101957,'F'
+101957,'Y'
+101957,'H'
+101957,'Q'
+101957,'K'
+101958,'F'
+101958,'Y'
+101958,'B'
+101958,'M'
+101958,'Q'
+101959,'FN'
+101959,'YN'
+101959,'H'
+101959,'QN'
+101959,'K'
+102122,'F'
+102122,'Y'
+102122,'B'
+102122,'M'
+102122,'Q'
+102123,'F'
+102123,'Y'
+102123,'H'
+102123,'Q'
+102123,'K'
+102125,'F'
+102125,'Y'
+102125,'B'
+102125,'M'
+102125,'Q'
+102126,'F'
+102126,'Y'
+102126,'B'
+102126,'M'
+102126,'Q'
+102127,'F'
+102127,'Y'
+102127,'B'
+102127,'M'
+102127,'Q'
+102128,'F'
+102128,'Y'
+102128,'H'
+102128,'Q'
+102128,'K'
+102129,'F'
+102129,'Y'
+102129,'B'
+102129,'M'
+102129,'Q'
+102133,'F'
+102133,'Y'
+102133,'B'
+102133,'M'
+102133,'Q'
+102134,'FN'
+102134,'YN'
+102134,'H'
+102134,'QN'
+102134,'K'
+102135,'FN'
+102135,'YN'
+102135,'BN'
+102135,'M'
+102135,'Q'
+102136,'FN'
+102136,'YN'
+102136,'BN'
+102136,'M'
+102136,'Q'
+102137,'FN'
+102137,'YN'
+102137,'BN'
+102137,'M'
+102137,'Q'
+102139,'F'
+102139,'Y'
+102139,'B'
+102139,'M'
+102139,'V'
+102144,'F'
+102144,'Y'
+102144,'B'
+102144,'M'
+102144,'Q'
+102147,'F'
+102147,'Y'
+102147,'B'
+102147,'M'
+102147,'V'
+102148,'F'
+102148,'Y'
+102148,'B'
+102148,'M'
+102148,'Q'
+102150,'F'
+102150,'Y'
+102150,'B'
+102150,'M'
+102150,'Q'
+102162,'F'
+102162,'Y'
+102162,'B'
+102162,'M'
+102162,'Q'
+102163,'F'
+102163,'Y'
+102163,'B'
+102163,'M'
+102163,'Q'
+102164,'F'
+102164,'Y'
+102164,'B'
+102164,'M'
+102164,'V'
+102165,'F'
+102165,'C'
+102165,'B'
+102165,'M'
+102165,'K'
+102166,'F'
+102166,'Y'
+102166,'B'
+102166,'M'
+102166,'Q'
+102172,'F'
+102172,'Y'
+102172,'B'
+102172,'M'
+102172,'V'
+102173,'F'
+102173,'Y'
+102173,'B'
+102173,'M'
+102173,'Q'
+102177,'F'
+102177,'Y'
+102177,'B'
+102177,'M'
+102177,'Q'
+102188,'FN'
+102188,'YN'
+102188,'B'
+102188,'M'
+102188,'V'
+102190,'FN'
+102190,'YN'
+102190,'BN'
+102190,'M'
+102190,'Q'
+102191,'FN'
+102191,'YN'
+102191,'BN'
+102191,'M'
+102191,'Q'
+102192,'FN'
+102192,'YN'
+102192,'BN'
+102192,'M'
+102192,'Q'
+102766,'FN'
+102766,'YN'
+102766,'BN'
+102766,'M'
+102766,'Q'
+102767,'F'
+102767,'Y'
+102767,'B'
+102767,'H'
+102767,'Q'
+102768,'F'
+102768,'Y'
+102768,'H'
+102768,'Q'
+102768,'K'
+102769,'F'
+102769,'Y'
+102769,'H'
+102769,'Q'
+102769,'K'
+102770,'F'
+102770,'Y'
+102770,'B'
+102770,'M'
+102770,'Q'
+102771,'F'
+102771,'Y'
+102771,'B'
+102771,'H'
+102771,'Q'
+102772,'F'
+102772,'Y'
+102772,'H'
+102772,'Q'
+102772,'K'
+102773,'F'
+102773,'Y'
+102773,'B'
+102773,'M'
+102773,'Q'
+102774,'F'
+102774,'Y'
+102774,'H'
+102774,'Q'
+102774,'K'
+102775,'F'
+102775,'Y'
+102775,'H'
+102775,'Q'
+102775,'K'
+102776,'F'
+102776,'Y'
+102776,'B'
+102776,'M'
+102776,'Q'
+102777,'F'
+102777,'Y'
+102777,'B'
+102777,'H'
+102777,'Q'
+102778,'F'
+102778,'Y'
+102778,'H'
+102778,'Q'
+102778,'K'
+102779,'F'
+102779,'Y'
+102779,'B'
+102779,'M'
+102779,'Q'
+102781,'F'
+102781,'Y'
+102781,'H'
+102781,'Q'
+102781,'K'
+102782,'F'
+102782,'Y'
+102782,'B'
+102782,'M'
+102782,'Q'
+102783,'FN'
+102783,'YN'
+102783,'H'
+102783,'QN'
+102783,'K'
+102784,'FN'
+102784,'YN'
+102784,'BN'
+102784,'M'
+102784,'Q'
+102795,'F'
+102795,'Y'
+102795,'B'
+102795,'H'
+102795,'Q'
+102796,'F'
+102796,'Y'
+102796,'B'
+102796,'M'
+102796,'Q'
+102797,'F'
+102797,'Y'
+102797,'H'
+102797,'Q'
+102797,'K'
+102798,'F'
+102798,'Y'
+102798,'B'
+102798,'H'
+102798,'Q'
+102799,'F'
+102799,'Y'
+102799,'H'
+102799,'Q'
+102799,'K'
+102800,'F'
+102800,'Y'
+102800,'B'
+102800,'M'
+102800,'Q'
+102801,'F'
+102801,'Y'
+102801,'B'
+102801,'H'
+102801,'Q'
+102802,'F'
+102802,'Y'
+102802,'B'
+102802,'M'
+102802,'Q'
+102803,'F'
+102803,'Y'
+102803,'B'
+102803,'M'
+102803,'Q'
+102804,'Y'
+102804,'H'
+102804,'Q'
+102804,'K'
+102804,'L'
+102805,'F'
+102805,'Y'
+102805,'B'
+102805,'H'
+102805,'Q'
+102806,'F'
+102806,'Y'
+102806,'H'
+102806,'Q'
+102806,'K'
+102807,'F'
+102807,'Y'
+102807,'B'
+102807,'M'
+102807,'Q'
+102808,'FN'
+102808,'YN'
+102808,'H'
+102808,'QN'
+102808,'K'
+102809,'FN'
+102809,'YN'
+102809,'BN'
+102809,'M'
+102809,'Q'
+102923,'F'
+102923,'Y'
+102923,'B'
+102923,'M'
+102923,'Q'
+102924,'F'
+102924,'Y'
+102924,'B'
+102924,'M'
+102924,'Q'
+102925,'F'
+102925,'Y'
+102925,'H'
+102925,'Q'
+102925,'K'
+102927,'F'
+102927,'Y'
+102927,'B'
+102927,'M'
+102927,'Q'
+102929,'F'
+102929,'Y'
+102929,'B'
+102929,'M'
+102929,'Q'
+102930,'F'
+102930,'Y'
+102930,'H'
+102930,'Q'
+102930,'K'
+102932,'F'
+102932,'Y'
+102932,'B'
+102932,'M'
+102932,'Q'
+102933,'F'
+102933,'Y'
+102933,'H'
+102933,'Q'
+102933,'K'
+105584,'F'
+105584,'Y'
+105584,'B'
+105584,'M'
+105584,'Q'
+105586,'FN'
+105586,'YN'
+105586,'H'
+105586,'QN'
+105586,'K'
+105588,'F'
+105588,'Y'
+105588,'B'
+105588,'M'
+105588,'Q'
+105589,'F'
+105589,'Y'
+105589,'H'
+105589,'Q'
+105589,'K'
+105590,'F'
+105590,'Y'
+105590,'B'
+105590,'M'
+105590,'Q'
+105591,'F'
+105591,'Y'
+105591,'H'
+105591,'Q'
+105591,'K'
+105592,'F'
+105592,'Y'
+105592,'B'
+105592,'M'
+105592,'Q'
+105593,'F'
+105593,'Y'
+105593,'H'
+105593,'Q'
+105593,'K'
+105594,'Y'
+105594,'H'
+105594,'Q'
+105594,'K'
+105594,'L'
+105595,'F'
+105595,'Y'
+105595,'B'
+105595,'M'
+105595,'Q'
+105597,'F'
+105597,'Y'
+105597,'H'
+105597,'Q'
+105597,'K'
+105598,'F'
+105598,'Y'
+105598,'H'
+105598,'Q'
+105598,'K'
+105599,'F'
+105599,'Y'
+105599,'B'
+105599,'M'
+105599,'Q'
+105601,'FN'
+105601,'YN'
+105601,'BN'
+105601,'M'
+105601,'Q'
+105698,'F'
+105698,'Y'
+105698,'B'
+105698,'H'
+105698,'Q'
+105699,'F'
+105699,'Y'
+105699,'B'
+105699,'H'
+105699,'Q'
+105700,'F'
+105700,'Y'
+105700,'B'
+105700,'H'
+105700,'Q'
+105701,'F'
+105701,'Y'
+105701,'B'
+105701,'H'
+105701,'Q'
+105702,'F'
+105702,'Y'
+105702,'B'
+105702,'H'
+105702,'Q'
+105703,'F'
+105703,'Y'
+105703,'B'
+105703,'H'
+105703,'Q'
+105704,'F'
+105704,'Y'
+105704,'B'
+105704,'H'
+105704,'Q'
+105705,'F'
+105705,'Y'
+105705,'B'
+105705,'H'
+105705,'Q'
+105794,'F'
+105794,'Y'
+105794,'B'
+105794,'M'
+105794,'Q'
+105795,'F'
+105795,'Y'
+105795,'B'
+105795,'M'
+105795,'Q'
+105796,'F'
+105796,'Y'
+105796,'Q'
+105796,'H'
+105796,'K'
+105798,'F'
+105798,'Y'
+105798,'Q'
+105798,'H'
+105798,'K'
+105799,'F'
+105799,'Y'
+105799,'B'
+105799,'M'
+105799,'Q'
+105800,'F'
+105800,'Y'
+105800,'Q'
+105800,'H'
+105800,'K'
+105801,'F'
+105801,'Y'
+105801,'B'
+105801,'M'
+105801,'V'
+105802,'F'
+105802,'Y'
+105802,'B'
+105802,'M'
+105802,'Q'
+105803,'F'
+105803,'Y'
+105803,'B'
+105803,'M'
+105803,'V'
+105805,'F'
+105805,'Y'
+105805,'B'
+105805,'M'
+105805,'Q'
+105806,'F'
+105806,'Y'
+105806,'B'
+105806,'M'
+105806,'V'
+105807,'F'
+105807,'Y'
+105807,'B'
+105807,'M'
+105807,'V'
+105808,'F'
+105808,'Y'
+105808,'B'
+105808,'M'
+105808,'Q'
+105811,'F'
+105811,'Y'
+105811,'B'
+105811,'M'
+105811,'V'
+105812,'F'
+105812,'Y'
+105812,'B'
+105812,'M'
+105812,'Q'
+106229,'F'
+106229,'Y'
+106229,'B'
+106229,'H'
+106229,'Q'
+106230,'F'
+106230,'Y'
+106230,'M'
+106230,'H'
+106230,'Q'
+106231,'F'
+106231,'Y'
+106231,'B'
+106231,'H'
+106231,'Q'
+106232,'F'
+106232,'Y'
+106232,'B'
+106232,'M'
+106232,'Q'
+106234,'F'
+106234,'Y'
+106234,'B'
+106234,'H'
+106234,'Q'
+106235,'F'
+106235,'Y'
+106235,'M'
+106235,'H'
+106235,'Q'
+106236,'F'
+106236,'Y'
+106236,'B'
+106236,'H'
+106236,'Q'
+106237,'F'
+106237,'Y'
+106237,'B'
+106237,'H'
+106237,'Q'
+106238,'F'
+106238,'Y'
+106238,'B'
+106238,'M'
+106238,'Q'
+106239,'F'
+106239,'Y'
+106239,'M'
+106239,'H'
+106239,'Q'
+106240,'F'
+106240,'C'
+106240,'B'
+106240,'M'
+106240,'K'
+106241,'F'
+106241,'Y'
+106241,'M'
+106241,'H'
+106241,'Q'
+106242,'F'
+106242,'Y'
+106242,'B'
+106242,'M'
+106242,'Q'
+106245,'F'
+106245,'Y'
+106245,'B'
+106245,'H'
+106245,'Q'
+106246,'F'
+106246,'Y'
+106246,'B'
+106246,'H'
+106246,'Q'
+106247,'F'
+106247,'Y'
+106247,'B'
+106247,'H'
+106247,'Q'
+106248,'F'
+106248,'Y'
+106248,'B'
+106248,'M'
+106248,'Q'
+106249,'F'
+106249,'Y'
+106249,'M'
+106249,'H'
+106249,'Q'
+106250,'F'
+106250,'Y'
+106250,'B'
+106250,'H'
+106250,'Q'
+106251,'F'
+106251,'Y'
+106251,'B'
+106251,'H'
+106251,'Q'
+106252,'F'
+106252,'Y'
+106252,'M'
+106252,'H'
+106252,'Q'
+106253,'F'
+106253,'Y'
+106253,'B'
+106253,'H'
+106253,'Q'
+106254,'F'
+106254,'Y'
+106254,'B'
+106254,'M'
+106254,'Q'
+106255,'F'
+106255,'Y'
+106255,'B'
+106255,'H'
+106255,'Q'
+106263,'F'
+106263,'Y'
+106263,'B'
+106263,'H'
+106263,'Q'
+106264,'F'
+106264,'Y'
+106264,'B'
+106264,'H'
+106264,'Q'
+106265,'F'
+106265,'Y'
+106265,'B'
+106265,'H'
+106265,'Q'
+106266,'F'
+106266,'Y'
+106266,'B'
+106266,'H'
+106266,'Q'
+106267,'F'
+106267,'Y'
+106267,'B'
+106267,'H'
+106267,'Q'
+106268,'F'
+106268,'Y'
+106268,'B'
+106268,'H'
+106268,'Q'
+106269,'F'
+106269,'Y'
+106269,'B'
+106269,'H'
+106269,'Q'
+106271,'F'
+106271,'Y'
+106271,'B'
+106271,'H'
+106271,'Q'
+106365,'F'
+106365,'Y'
+106365,'B'
+106365,'M'
+106365,'Q'
+106376,'F'
+106376,'Y'
+106376,'B'
+106376,'M'
+106376,'Q'
+106377,'F'
+106377,'C'
+106377,'Y'
+106377,'B'
+106377,'Q'
+107159,'FN'
+107159,'YN'
+107159,'BN'
+107159,'M'
+107159,'Q'
+107160,'FN'
+107160,'YN'
+107160,'H'
+107160,'QN'
+107160,'K'
+107161,'F'
+107161,'Y'
+107161,'H'
+107161,'Q'
+107161,'K'
+107162,'F'
+107162,'Y'
+107162,'B'
+107162,'M'
+107162,'Q'
+107163,'F'
+107163,'Y'
+107163,'H'
+107163,'Q'
+107163,'K'
+107164,'F'
+107164,'Y'
+107164,'H'
+107164,'Q'
+107164,'K'
+107165,'F'
+107165,'Y'
+107165,'B'
+107165,'M'
+107165,'Q'
+107166,'F'
+107166,'Y'
+107166,'B'
+107166,'M'
+107166,'Q'
+107167,'F'
+107167,'Y'
+107167,'H'
+107167,'Q'
+107167,'K'
+107168,'F'
+107168,'Y'
+107168,'B'
+107168,'M'
+107168,'Q'
+107193,'F'
+107193,'Y'
+107193,'B'
+107193,'H'
+107193,'Q'
+107194,'F'
+107194,'Y'
+107194,'B'
+107194,'H'
+107194,'Q'
+107195,'F'
+107195,'Y'
+107195,'B'
+107195,'H'
+107195,'Q'
+107196,'F'
+107196,'Y'
+107196,'B'
+107196,'H'
+107196,'Q'
+107197,'F'
+107197,'Y'
+107197,'B'
+107197,'H'
+107197,'Q'
+107198,'F'
+107198,'Y'
+107198,'B'
+107198,'H'
+107198,'Q'
+107199,'F'
+107199,'Y'
+107199,'B'
+107199,'H'
+107199,'Q'
+107200,'F'
+107200,'Y'
+107200,'B'
+107200,'H'
+107200,'Q'
+107254,'F'
+107254,'Y'
+107254,'B'
+107254,'M'
+107254,'Q'
+107255,'F'
+107255,'Y'
+107255,'B'
+107255,'H'
+107255,'Q'
+107256,'F'
+107256,'Y'
+107256,'B'
+107256,'M'
+107256,'Q'
+107257,'F'
+107257,'Y'
+107257,'B'
+107257,'M'
+107257,'V'
+107258,'F'
+107258,'Y'
+107258,'B'
+107258,'M'
+107258,'Q'
+107259,'F'
+107259,'Y'
+107259,'B'
+107259,'M'
+107259,'V'
+107260,'F'
+107260,'Y'
+107260,'B'
+107260,'M'
+107260,'V'
+107261,'F'
+107261,'Y'
+107261,'B'
+107261,'M'
+107261,'Q'
+107264,'F'
+107264,'Y'
+107264,'B'
+107264,'M'
+107264,'V'
+107470,'Y'
+107470,'B'
+107470,'H'
+107470,'Q'
+107470,'M'
+107471,'Y'
+107471,'B'
+107471,'H'
+107471,'Q'
+107471,'M'
+107472,'Y'
+107472,'B'
+107472,'H'
+107472,'Q'
+107472,'M'
+107473,'Y'
+107473,'B'
+107473,'H'
+107473,'Q'
+107473,'M'
+107474,'Y'
+107474,'B'
+107474,'H'
+107474,'Q'
+107474,'M'
+107475,'Y'
+107475,'B'
+107475,'H'
+107475,'Q'
+107475,'M'
+107476,'Y'
+107476,'B'
+107476,'H'
+107476,'Q'
+107476,'M'
+107477,'Y'
+107477,'B'
+107477,'H'
+107477,'Q'
+107477,'M'
+107478,'Y'
+107478,'B'
+107478,'H'
+107478,'Q'
+107478,'M'
+107484,'F'
+107484,'Y'
+107484,'B'
+107484,'H'
+107484,'Q'
+107485,'F'
+107485,'Y'
+107485,'B'
+107485,'H'
+107485,'Q'
+107486,'F'
+107486,'Y'
+107486,'B'
+107486,'H'
+107486,'Q'
+107487,'F'
+107487,'Y'
+107487,'B'
+107487,'H'
+107487,'Q'
+107488,'F'
+107488,'Y'
+107488,'B'
+107488,'H'
+107488,'Q'
+107489,'F'
+107489,'Y'
+107489,'B'
+107489,'H'
+107489,'Q'
+107490,'F'
+107490,'Y'
+107490,'B'
+107490,'H'
+107490,'Q'
+107491,'F'
+107491,'Y'
+107491,'B'
+107491,'H'
+107491,'Q'
+107492,'F'
+107492,'Y'
+107492,'B'
+107492,'H'
+107492,'Q'
+111886,'FN'
+111886,'YN'
+111886,'BN'
+111886,'M'
+111886,'Q'
+111887,'FN'
+111887,'YN'
+111887,'H'
+111887,'QN'
+111887,'K'
+111888,'F'
+111888,'Y'
+111888,'B'
+111888,'M'
+111888,'Q'
+111889,'F'
+111889,'Y'
+111889,'H'
+111889,'Q'
+111889,'K'
+111891,'F'
+111891,'Y'
+111891,'B'
+111891,'M'
+111891,'Q'
+111892,'F'
+111892,'Y'
+111892,'B'
+111892,'M'
+111892,'Q'
+111893,'F'
+111893,'Y'
+111893,'H'
+111893,'Q'
+111893,'K'
+111894,'F'
+111894,'Y'
+111894,'B'
+111894,'M'
+111894,'Q'
+111895,'F'
+111895,'Y'
+111895,'B'
+111895,'M'
+111895,'Q'
+111896,'F'
+111896,'Y'
+111896,'B'
+111896,'M'
+111896,'Q'
+111928,'F'
+111928,'Y'
+111928,'B'
+111928,'M'
+111928,'Q'
+111929,'F'
+111929,'Y'
+111929,'Q'
+111929,'H'
+111929,'K'
+111931,'F'
+111931,'Y'
+111931,'B'
+111931,'M'
+111931,'Q'
+111932,'F'
+111932,'Y'
+111932,'Q'
+111932,'H'
+111932,'K'
+111933,'F'
+111933,'Y'
+111933,'Q'
+111933,'H'
+111933,'K'
+111937,'F'
+111937,'Y'
+111937,'B'
+111937,'M'
+111937,'Q'
+111939,'F'
+111939,'Y'
+111939,'B'
+111939,'H'
+111939,'Q'
+111941,'F'
+111941,'Y'
+111941,'B'
+111941,'M'
+111941,'Q'
+112028,'FN'
+112028,'YN'
+112028,'B'
+112028,'M'
+112028,'V'
+112029,'F'
+112029,'Y'
+112029,'B'
+112029,'M'
+112029,'Q'
+112030,'FN'
+112030,'YN'
+112030,'BN'
+112030,'M'
+112030,'Q'
+112031,'FN'
+112031,'YN'
+112031,'BN'
+112031,'M'
+112031,'Q'
+112032,'F'
+112032,'Y'
+112032,'B'
+112032,'M'
+112032,'V'
+112033,'F'
+112033,'Y'
+112033,'B'
+112033,'M'
+112033,'Q'
+112034,'F'
+112034,'Y'
+112034,'B'
+112034,'M'
+112034,'Q'
+112035,'F'
+112035,'Y'
+112035,'B'
+112035,'M'
+112035,'V'
+112036,'F'
+112036,'Y'
+112036,'Q'
+112036,'H'
+112036,'K'
+112037,'F'
+112037,'Y'
+112037,'B'
+112037,'M'
+112037,'V'
+112038,'F'
+112038,'Y'
+112038,'B'
+112038,'M'
+112038,'Q'
+112039,'F'
+112039,'Y'
+112039,'B'
+112039,'M'
+112039,'Q'
+112040,'F'
+112040,'Y'
+112040,'B'
+112040,'M'
+112040,'Q'
+112041,'F'
+112041,'Y'
+112041,'Q'
+112041,'H'
+112041,'K'
+112042,'F'
+112042,'Y'
+112042,'B'
+112042,'M'
+112042,'V'
+112043,'F'
+112043,'Y'
+112043,'B'
+112043,'M'
+112043,'Q'
+112044,'F'
+112044,'Y'
+112044,'Q'
+112044,'H'
+112044,'K'
+112045,'F'
+112045,'Y'
+112045,'B'
+112045,'M'
+112045,'V'
+112046,'F'
+112046,'Y'
+112046,'B'
+112046,'M'
+112046,'Q'
+112047,'F'
+112047,'Y'
+112047,'B'
+112047,'M'
+112047,'Q'
+112048,'F'
+112048,'Y'
+112048,'B'
+112048,'M'
+112048,'V'
+112049,'F'
+112049,'Y'
+112049,'B'
+112049,'M'
+112049,'Q'
+112050,'F'
+112050,'Y'
+112050,'Q'
+112050,'H'
+112050,'K'
+112051,'FN'
+112051,'YN'
+112051,'BN'
+112051,'M'
+112051,'Q'
+112052,'FN'
+112052,'YN'
+112052,'B'
+112052,'M'
+112052,'V'
+112351,'F'
+112351,'Y'
+112351,'B'
+112351,'M'
+112351,'Q'
+112352,'F'
+112352,'Y'
+112352,'B'
+112352,'M'
+112352,'Q'
+112353,'F'
+112353,'Y'
+112353,'B'
+112353,'M'
+112353,'Q'
+112354,'F'
+112354,'Y'
+112354,'B'
+112354,'M'
+112354,'Q'
+112415,'F'
+112415,'Y'
+112415,'B'
+112415,'M'
+112415,'Q'
+112416,'F'
+112416,'Y'
+112416,'Q'
+112416,'H'
+112416,'K'
+112417,'F'
+112417,'Y'
+112417,'B'
+112417,'M'
+112417,'Q'
+112418,'F'
+112418,'Y'
+112418,'Q'
+112418,'H'
+112418,'K'
+112440,'F'
+112440,'Y'
+112440,'B'
+112440,'H'
+112440,'Q'
+112441,'F'
+112441,'Y'
+112441,'B'
+112441,'H'
+112441,'Q'
+112442,'F'
+112442,'Y'
+112442,'B'
+112442,'H'
+112442,'Q'
+112513,'F'
+112513,'C'
+112513,'Y'
+112513,'B'
+112513,'M'
+112514,'F'
+112514,'Y'
+112514,'Q'
+112514,'H'
+112514,'K'
+112515,'F'
+112515,'Y'
+112515,'B'
+112515,'M'
+112515,'Q'
+112516,'F'
+112516,'Y'
+112516,'B'
+112516,'M'
+112516,'Q'
+112518,'F'
+112518,'Y'
+112518,'Q'
+112518,'H'
+112518,'K'
+112519,'F'
+112519,'Y'
+112519,'Q'
+112519,'H'
+112519,'K'
+112520,'F'
+112520,'Y'
+112520,'B'
+112520,'M'
+112520,'Q'
+112524,'F'
+112524,'Y'
+112524,'B'
+112524,'M'
+112524,'Q'
+112525,'F'
+112525,'Y'
+112525,'Q'
+112525,'H'
+112525,'K'
+112526,'F'
+112526,'Y'
+112526,'B'
+112526,'M'
+112526,'Q'
+112527,'F'
+112527,'Q'
+112527,'YN'
+112527,'H'
+112527,'K'
+112766,'F'
+112766,'Y'
+112766,'B'
+112766,'M'
+112766,'Q'
+112771,'FN'
+112771,'YN'
+112771,'B'
+112771,'M'
+112771,'V'
+112772,'F'
+112772,'Y'
+112772,'B'
+112772,'M'
+112772,'Q'
+112773,'F'
+112773,'Y'
+112773,'B'
+112773,'M'
+112773,'Q'
+112777,'F'
+112777,'Y'
+112777,'B'
+112777,'M'
+112777,'Q'
+112783,'F'
+112783,'Y'
+112783,'B'
+112783,'M'
+112783,'V'
+112784,'F'
+112784,'Y'
+112784,'B'
+112784,'M'
+112784,'Q'
+112789,'F'
+112789,'Y'
+112789,'B'
+112789,'M'
+112789,'V'
+112790,'F'
+112790,'Y'
+112790,'B'
+112790,'M'
+112790,'Q'
+112793,'F'
+112793,'Y'
+112793,'B'
+112793,'M'
+112793,'Q'
+112794,'F'
+112794,'Y'
+112794,'B'
+112794,'M'
+112794,'Q'
+112797,'F'
+112797,'C'
+112797,'B'
+112797,'M'
+112797,'K'
+112798,'F'
+112798,'Y'
+112798,'B'
+112798,'M'
+112798,'V'
+112802,'F'
+112802,'Y'
+112802,'B'
+112802,'M'
+112802,'Q'
+112804,'FN'
+112804,'YN'
+112804,'B'
+112804,'M'
+112804,'V'
+112805,'F'
+112805,'Y'
+112805,'B'
+112805,'M'
+112805,'Q'
+112806,'FN'
+112806,'YN'
+112806,'BN'
+112806,'M'
+112806,'Q'
+112807,'FN'
+112807,'YN'
+112807,'B'
+112807,'M'
+112807,'V'
+112808,'FN'
+112808,'YN'
+112808,'BN'
+112808,'M'
+112808,'Q'
+112864,'F'
+112864,'Y'
+112864,'B'
+112864,'M'
+112864,'V'
+112866,'F'
+112866,'Y'
+112866,'B'
+112866,'M'
+112866,'Q'
+112867,'F'
+112867,'Y'
+112867,'B'
+112867,'M'
+112867,'Q'
+112869,'F'
+112869,'Y'
+112869,'B'
+112869,'M'
+112869,'V'
+112870,'F'
+112870,'Y'
+112870,'B'
+112870,'M'
+112870,'Q'
+112872,'F'
+112872,'Y'
+112872,'B'
+112872,'M'
+112872,'V'
+112873,'F'
+112873,'Y'
+112873,'B'
+112873,'M'
+112873,'Q'
+112874,'F'
+112874,'Y'
+112874,'B'
+112874,'M'
+112874,'V'
+112903,'F'
+112903,'Y'
+112903,'B'
+112903,'M'
+112903,'V'
+112904,'F'
+112904,'Y'
+112904,'B'
+112904,'M'
+112904,'Q'
+112905,'F'
+112905,'Y'
+112905,'B'
+112905,'M'
+112905,'V'
+112907,'F'
+112907,'Y'
+112907,'B'
+112907,'M'
+112907,'Q'
+112908,'F'
+112908,'Y'
+112908,'B'
+112908,'M'
+112908,'V'
+112909,'F'
+112909,'Y'
+112909,'B'
+112909,'M'
+112909,'V'
+112989,'F'
+112989,'Y'
+112989,'Q'
+112989,'H'
+112989,'K'
+112990,'F'
+112990,'Y'
+112990,'B'
+112990,'M'
+112990,'V'
+112991,'F'
+112991,'Y'
+112991,'B'
+112991,'M'
+112991,'Q'
+112992,'F'
+112992,'Y'
+112992,'B'
+112992,'M'
+112992,'Q'
+112993,'F'
+112993,'Y'
+112993,'B'
+112993,'M'
+112993,'V'
+112994,'F'
+112994,'Y'
+112994,'B'
+112994,'M'
+112994,'Q'
+112995,'F'
+112995,'Y'
+112995,'B'
+112995,'M'
+112995,'V'
+112996,'F'
+112996,'Y'
+112996,'Q'
+112996,'H'
+112996,'K'
+112997,'F'
+112997,'Y'
+112997,'Q'
+112997,'H'
+112997,'K'
+112998,'F'
+112998,'Y'
+112998,'B'
+112998,'M'
+112998,'Q'
+112999,'F'
+112999,'Y'
+112999,'B'
+112999,'M'
+112999,'V'
+113000,'F'
+113000,'Y'
+113000,'B'
+113000,'M'
+113000,'Q'
+113001,'F'
+113001,'Y'
+113001,'B'
+113001,'M'
+113001,'Q'
+113002,'F'
+113002,'Y'
+113002,'B'
+113002,'M'
+113002,'V'
+113003,'F'
+113003,'Y'
+113003,'B'
+113003,'M'
+113003,'Q'
+113004,'F'
+113004,'Y'
+113004,'B'
+113004,'M'
+113004,'Q'
+113005,'F'
+113005,'Y'
+113005,'B'
+113005,'M'
+113005,'V'
+113006,'F'
+113006,'Y'
+113006,'Q'
+113006,'H'
+113006,'K'
+113007,'FN'
+113007,'YN'
+113007,'B'
+113007,'M'
+113007,'V'
+113008,'F'
+113008,'Y'
+113008,'B'
+113008,'M'
+113008,'Q'
+113009,'F'
+113009,'Y'
+113009,'B'
+113009,'M'
+113009,'Q'
+113010,'F'
+113010,'Y'
+113010,'Q'
+113010,'H'
+113010,'K'
+113011,'FN'
+113011,'YN'
+113011,'B'
+113011,'M'
+113011,'V'
+113012,'FN'
+113012,'YN'
+113012,'BN'
+113012,'M'
+113012,'Q'
+113013,'FN'
+113013,'YN'
+113013,'BN'
+113013,'M'
+113013,'Q'
+113498,'F'
+113498,'Y'
+113498,'B'
+113498,'M'
+113498,'V'
+113500,'F'
+113500,'Y'
+113500,'B'
+113500,'M'
+113500,'V'
+113501,'FN'
+113501,'YN'
+113501,'B'
+113501,'M'
+113501,'V'
+113576,'F'
+113576,'Y'
+113576,'B'
+113576,'M'
+113576,'V'
+113577,'F'
+113577,'Y'
+113577,'B'
+113577,'M'
+113577,'Q'
+113578,'F'
+113578,'Y'
+113578,'B'
+113578,'M'
+113578,'V'
+113579,'F'
+113579,'Y'
+113579,'B'
+113579,'M'
+113579,'Q'
+113581,'F'
+113581,'Y'
+113581,'B'
+113581,'M'
+113581,'V'
+113582,'F'
+113582,'Y'
+113582,'B'
+113582,'M'
+113582,'V'
+113583,'FN'
+113583,'YN'
+113583,'BN'
+113583,'M'
+113583,'Q'
+113595,'F'
+113595,'Y'
+113595,'B'
+113595,'M'
+113595,'V'
+113596,'F'
+113596,'Y'
+113596,'B'
+113596,'H'
+113596,'Q'
+113597,'F'
+113597,'Y'
+113597,'B'
+113597,'H'
+113597,'Q'
+113599,'F'
+113599,'Y'
+113599,'B'
+113599,'M'
+113599,'V'
+113600,'F'
+113600,'Y'
+113600,'B'
+113600,'H'
+113600,'Q'
+113602,'F'
+113602,'Y'
+113602,'B'
+113602,'M'
+113602,'V'
+113705,'F'
+113705,'Y'
+113705,'B'
+113705,'M'
+113705,'Q'
+113706,'F'
+113706,'Y'
+113706,'B'
+113706,'M'
+113706,'V'
+113707,'F'
+113707,'Y'
+113707,'B'
+113707,'M'
+113707,'Q'
+113709,'F'
+113709,'Y'
+113709,'B'
+113709,'M'
+113709,'V'
+113711,'F'
+113711,'Y'
+113711,'B'
+113711,'M'
+113711,'V'
+113712,'F'
+113712,'Y'
+113712,'B'
+113712,'M'
+113712,'Q'
+113715,'F'
+113715,'Y'
+113715,'B'
+113715,'M'
+113715,'Q'
+113716,'F'
+113716,'Y'
+113716,'B'
+113716,'M'
+113716,'V'
+113717,'F'
+113717,'Y'
+113717,'B'
+113717,'M'
+113717,'V'
+113718,'F'
+113718,'Y'
+113718,'B'
+113718,'M'
+113718,'V'
+113719,'F'
+113719,'Y'
+113719,'B'
+113719,'M'
+113719,'Q'
+113720,'FN'
+113720,'YN'
+113720,'B'
+113720,'M'
+113720,'V'
+113721,'FN'
+113721,'YN'
+113721,'BN'
+113721,'M'
+113721,'Q'
+133430,'F'
+133430,'Y'
+133430,'B'
+133430,'M'
+133430,'Q'
+133431,'F'
+133431,'Y'
+133431,'B'
+133431,'M'
+133431,'Q'
+133432,'F'
+133432,'Y'
+133432,'B'
+133432,'M'
+133432,'Q'
+133433,'F'
+133433,'Y'
+133433,'B'
+133433,'M'
+133433,'Q'
+133434,'FN'
+133434,'YN'
+133434,'B'
+133434,'M'
+133434,'V'
+133435,'F'
+133435,'Y'
+133435,'B'
+133435,'M'
+133435,'V'
+133436,'F'
+133436,'Y'
+133436,'B'
+133436,'M'
+133436,'V'
+133567,'YN'
+133567,'B'
+133567,'M'
+133567,'V'
+133567,'Q'
+133568,'Y'
+133568,'B'
+133568,'M'
+133568,'V'
+133568,'Q'
+133569,'Y'
+133569,'B'
+133569,'M'
+133569,'V'
+133569,'Q'
+137221,'FN'
+137221,'YN'
+137221,'BN'
+137221,'M'
+137221,'Q'
+137222,'FN'
+137222,'YN'
+137222,'H'
+137222,'QN'
+137222,'K'
+137223,'F'
+137223,'Y'
+137223,'H'
+137223,'Q'
+137223,'K'
+137224,'F'
+137224,'Y'
+137224,'B'
+137224,'M'
+137224,'Q'
+137225,'F'
+137225,'Y'
+137225,'B'
+137225,'H'
+137225,'Q'
+137226,'F'
+137226,'Y'
+137226,'H'
+137226,'Q'
+137226,'K'
+137227,'F'
+137227,'Y'
+137227,'H'
+137227,'Q'
+137227,'K'
+137228,'F'
+137228,'Y'
+137228,'B'
+137228,'M'
+137228,'Q'
+137229,'F'
+137229,'Y'
+137229,'H'
+137229,'Q'
+137229,'K'
+137230,'F'
+137230,'Y'
+137230,'B'
+137230,'M'
+137230,'Q'
+137231,'F'
+137231,'Y'
+137231,'B'
+137231,'H'
+137231,'Q'
+137232,'F'
+137232,'Y'
+137232,'H'
+137232,'Q'
+137232,'K'
+137233,'F'
+137233,'Y'
+137233,'B'
+137233,'M'
+137233,'Q'
+137234,'F'
+137234,'Y'
+137234,'H'
+137234,'Q'
+137234,'K'
+137235,'F'
+137235,'Y'
+137235,'B'
+137235,'M'
+137235,'Q'
+137236,'F'
+137236,'Y'
+137236,'H'
+137236,'Q'
+137236,'K'
+137237,'F'
+137237,'Y'
+137237,'B'
+137237,'H'
+137237,'Q'
+137238,'F'
+137238,'Y'
+137238,'B'
+137238,'M'
+137238,'Q'
+137315,'F'
+137315,'Y'
+137315,'B'
+137315,'M'
+137315,'Q'
+137316,'F'
+137316,'Y'
+137316,'B'
+137316,'H'
+137316,'Q'
+137317,'F'
+137317,'Y'
+137317,'M'
+137317,'H'
+137317,'Q'
+137318,'F'
+137318,'Y'
+137318,'B'
+137318,'H'
+137318,'Q'
+137319,'F'
+137319,'Y'
+137319,'B'
+137319,'M'
+137319,'Q'
+137320,'F'
+137320,'Y'
+137320,'B'
+137320,'H'
+137320,'Q'
+137321,'F'
+137321,'Y'
+137321,'M'
+137321,'H'
+137321,'Q'
+137322,'F'
+137322,'Y'
+137322,'M'
+137322,'H'
+137322,'Q'
+137323,'F'
+137323,'Y'
+137323,'B'
+137323,'M'
+137323,'Q'
+137324,'F'
+137324,'Y'
+137324,'B'
+137324,'H'
+137324,'Q'
+137326,'F'
+137326,'Y'
+137326,'B'
+137326,'H'
+137326,'Q'
+137327,'F'
+137327,'Y'
+137327,'B'
+137327,'H'
+137327,'Q'
+137328,'F'
+137328,'Y'
+137328,'M'
+137328,'H'
+137328,'Q'
+137329,'F'
+137329,'Y'
+137329,'B'
+137329,'H'
+137329,'Q'
+137330,'F'
+137330,'C'
+137330,'B'
+137330,'M'
+137330,'K'
+137331,'F'
+137331,'Y'
+137331,'B'
+137331,'M'
+137331,'Q'
+137332,'F'
+137332,'Y'
+137332,'M'
+137332,'H'
+137332,'Q'
+137333,'F'
+137333,'Y'
+137333,'B'
+137333,'H'
+137333,'Q'
+137334,'F'
+137334,'Y'
+137334,'B'
+137334,'H'
+137334,'Q'
+137335,'F'
+137335,'Y'
+137335,'B'
+137335,'H'
+137335,'Q'
+137336,'F'
+137336,'Y'
+137336,'B'
+137336,'H'
+137336,'Q'
+137337,'F'
+137337,'Y'
+137337,'M'
+137337,'H'
+137337,'Q'
+137338,'F'
+137338,'Y'
+137338,'B'
+137338,'H'
+137338,'Q'
+137339,'FN'
+137339,'YN'
+137339,'BN'
+137339,'M'
+137339,'Q'
+137353,'Y'
+137353,'B'
+137353,'H'
+137353,'Q'
+137353,'M'
+137354,'Y'
+137354,'B'
+137354,'H'
+137354,'Q'
+137354,'M'
+137355,'Y'
+137355,'B'
+137355,'H'
+137355,'Q'
+137355,'M'
+137356,'Y'
+137356,'B'
+137356,'H'
+137356,'Q'
+137356,'M'
+137357,'Y'
+137357,'B'
+137357,'H'
+137357,'Q'
+137357,'M'
+137358,'Y'
+137358,'B'
+137358,'H'
+137358,'Q'
+137358,'M'
+137359,'Y'
+137359,'B'
+137359,'H'
+137359,'Q'
+137359,'M'
+137360,'Y'
+137360,'B'
+137360,'H'
+137360,'Q'
+137360,'M'
+137361,'Y'
+137361,'B'
+137361,'H'
+137361,'Q'
+137361,'M'
+137407,'F'
+137407,'Y'
+137407,'B'
+137407,'M'
+137407,'Q'
+137408,'F'
+137408,'Y'
+137408,'Q'
+137408,'H'
+137408,'K'
+137412,'F'
+137412,'Y'
+137412,'B'
+137412,'M'
+137412,'Q'
+137413,'F'
+137413,'Y'
+137413,'Q'
+137413,'H'
+137413,'K'
+137414,'F'
+137414,'Y'
+137414,'B'
+137414,'M'
+137414,'V'
+137415,'F'
+137415,'Y'
+137415,'B'
+137415,'M'
+137415,'Q'
+137417,'F'
+137417,'Y'
+137417,'B'
+137417,'M'
+137417,'V'
+137419,'F'
+137419,'Y'
+137419,'B'
+137419,'M'
+137419,'Q'
+137420,'F'
+137420,'Y'
+137420,'B'
+137420,'M'
+137420,'V'
+137422,'F'
+137422,'Y'
+137422,'B'
+137422,'M'
+137422,'V'
+137423,'F'
+137423,'Y'
+137423,'B'
+137423,'M'
+137423,'Q'
+137732,'F'
+137732,'Y'
+137732,'B'
+137732,'H'
+137732,'Q'
+137733,'F'
+137733,'Y'
+137733,'B'
+137733,'H'
+137733,'Q'
+137734,'F'
+137734,'Y'
+137734,'B'
+137734,'H'
+137734,'Q'
+137735,'F'
+137735,'Y'
+137735,'B'
+137735,'H'
+137735,'Q'
+137736,'F'
+137736,'Y'
+137736,'B'
+137736,'H'
+137736,'Q'
+137737,'F'
+137737,'Y'
+137737,'B'
+137737,'H'
+137737,'Q'
+137738,'F'
+137738,'Y'
+137738,'B'
+137738,'H'
+137738,'Q'
+137739,'F'
+137739,'Y'
+137739,'B'
+137739,'H'
+137739,'Q'
+137740,'F'
+137740,'Y'
+137740,'B'
+137740,'H'
+137740,'Q'
+137811,'F'
+137811,'Y'
+137811,'B'
+137811,'M'
+137811,'Q'
+137817,'F'
+137817,'Y'
+137817,'B'
+137817,'M'
+137817,'Q'
+138817,'FN'
+138817,'YN'
+138817,'BN'
+138817,'M'
+138817,'Q'
+138818,'F'
+138818,'Y'
+138818,'H'
+138818,'Q'
+138818,'K'
+138819,'Y'
+138819,'H'
+138819,'Q'
+138819,'K'
+138819,'L'
+138820,'F'
+138820,'Y'
+138820,'B'
+138820,'H'
+138820,'Q'
+138821,'F'
+138821,'Y'
+138821,'B'
+138821,'M'
+138821,'Q'
+138822,'F'
+138822,'Y'
+138822,'H'
+138822,'Q'
+138822,'K'
+138823,'F'
+138823,'Y'
+138823,'B'
+138823,'M'
+138823,'Q'
+138824,'F'
+138824,'Y'
+138824,'B'
+138824,'H'
+138824,'Q'
+138825,'Y'
+138825,'H'
+138825,'Q'
+138825,'K'
+138825,'L'
+138827,'F'
+138827,'Y'
+138827,'B'
+138827,'M'
+138827,'Q'
+138828,'F'
+138828,'Y'
+138828,'B'
+138828,'H'
+138828,'Q'
+138829,'F'
+138829,'Y'
+138829,'H'
+138829,'Q'
+138829,'K'
+138830,'FN'
+138830,'YN'
+138830,'BN'
+138830,'M'
+138830,'Q'
+138831,'FN'
+138831,'YN'
+138831,'BN'
+138831,'M'
+138831,'Q'
+138832,'F'
+138832,'Y'
+138832,'B'
+138832,'H'
+138832,'Q'
+138860,'F'
+138860,'Y'
+138860,'B'
+138860,'H'
+138860,'Q'
+138861,'F'
+138861,'Y'
+138861,'B'
+138861,'H'
+138861,'Q'
+138862,'F'
+138862,'Y'
+138862,'B'
+138862,'H'
+138862,'Q'
+138863,'F'
+138863,'Y'
+138863,'B'
+138863,'H'
+138863,'Q'
+138864,'F'
+138864,'Y'
+138864,'B'
+138864,'H'
+138864,'Q'
+138865,'F'
+138865,'Y'
+138865,'B'
+138865,'H'
+138865,'Q'
+138867,'F'
+138867,'Y'
+138867,'B'
+138867,'H'
+138867,'Q'
+138868,'F'
+138868,'Y'
+138868,'B'
+138868,'H'
+138868,'Q'
+138878,'F'
+138878,'Y'
+138878,'B'
+138878,'H'
+138878,'Q'
+138879,'F'
+138879,'Y'
+138879,'B'
+138879,'H'
+138879,'Q'
+138880,'F'
+138880,'Y'
+138880,'B'
+138880,'H'
+138880,'Q'
+138881,'F'
+138881,'Y'
+138881,'B'
+138881,'H'
+138881,'Q'
+138882,'F'
+138882,'Y'
+138882,'B'
+138882,'H'
+138882,'Q'
+138883,'F'
+138883,'Y'
+138883,'B'
+138883,'H'
+138883,'Q'
+138884,'F'
+138884,'Y'
+138884,'B'
+138884,'H'
+138884,'Q'
+138963,'F'
+138963,'Y'
+138963,'B'
+138963,'H'
+138963,'Q'
+138964,'F'
+138964,'Y'
+138964,'B'
+138964,'H'
+138964,'Q'
+138966,'F'
+138966,'Y'
+138966,'B'
+138966,'H'
+138966,'Q'
+138970,'F'
+138970,'Y'
+138970,'B'
+138970,'M'
+138970,'V'
+138971,'F'
+138971,'Y'
+138971,'B'
+138971,'H'
+138971,'Q'
+138973,'F'
+138973,'Y'
+138973,'B'
+138973,'M'
+138973,'V'
+138974,'F'
+138974,'Y'
+138974,'B'
+138974,'H'
+138974,'Q'
+138976,'F'
+138976,'Y'
+138976,'B'
+138976,'M'
+138976,'V'
+138977,'F'
+138977,'Y'
+138977,'B'
+138977,'H'
+138977,'Q'
+139264,'F'
+139264,'Y'
+139264,'B'
+139264,'H'
+139264,'Q'
+139265,'F'
+139265,'Y'
+139265,'B'
+139265,'H'
+139265,'Q'
+139266,'F'
+139266,'Y'
+139266,'B'
+139266,'H'
+139266,'Q'
+139267,'F'
+139267,'Y'
+139267,'B'
+139267,'H'
+139267,'Q'
+139268,'F'
+139268,'Y'
+139268,'B'
+139268,'H'
+139268,'Q'
+139269,'F'
+139269,'Y'
+139269,'B'
+139269,'H'
+139269,'Q'
+139270,'F'
+139270,'Y'
+139270,'B'
+139270,'H'
+139270,'Q'
+139271,'F'
+139271,'Y'
+139271,'B'
+139271,'H'
+139271,'Q'
+139272,'F'
+139272,'Y'
+139272,'B'
+139272,'H'
+139272,'Q'
+139273,'F'
+139273,'Y'
+139273,'B'
+139273,'H'
+139273,'Q'
+139353,'F'
+139353,'Y'
+139353,'B'
+139353,'H'
+139353,'Q'
+139355,'F'
+139355,'Y'
+139355,'B'
+139355,'H'
+139355,'Q'
+139356,'F'
+139356,'Y'
+139356,'B'
+139356,'H'
+139356,'Q'
+139357,'F'
+139357,'Y'
+139357,'B'
+139357,'H'
+139357,'Q'
+144060,'F'
+144060,'Y'
+144060,'B'
+144060,'M'
+144060,'Q'
+144061,'F'
+144061,'Y'
+144061,'H'
+144061,'Q'
+144061,'K'
+144062,'F'
+144062,'Y'
+144062,'B'
+144062,'M'
+144062,'Q'
+144063,'F'
+144063,'Y'
+144063,'B'
+144063,'M'
+144063,'Q'
+144065,'F'
+144065,'Y'
+144065,'H'
+144065,'Q'
+144065,'K'
+144066,'F'
+144066,'Y'
+144066,'B'
+144066,'M'
+144066,'Q'
+144067,'FN'
+144067,'YN'
+144067,'BN'
+144067,'M'
+144067,'Q'
+144069,'FN'
+144069,'YN'
+144069,'H'
+144069,'QN'
+144069,'K'
+144089,'F'
+144089,'Y'
+144089,'B'
+144089,'M'
+144089,'Q'
+144090,'F'
+144090,'C'
+144090,'Y'
+144090,'B'
+144090,'Q'
+144094,'F'
+144094,'Y'
+144094,'B'
+144094,'M'
+144094,'Q'
+144143,'F'
+144143,'Y'
+144143,'B'
+144143,'M'
+144143,'Q'
+144144,'F'
+144144,'Y'
+144144,'Q'
+144144,'H'
+144144,'K'
+144145,'F'
+144145,'Y'
+144145,'B'
+144145,'M'
+144145,'Q'
+144146,'F'
+144146,'Y'
+144146,'B'
+144146,'M'
+144146,'Q'
+144147,'F'
+144147,'Y'
+144147,'Q'
+144147,'H'
+144147,'K'
+144148,'F'
+144148,'C'
+144148,'Y'
+144148,'B'
+144148,'M'
+144149,'F'
+144149,'Y'
+144149,'Q'
+144149,'H'
+144149,'K'
+144150,'F'
+144150,'Y'
+144150,'B'
+144150,'M'
+144150,'Q'
+144151,'F'
+144151,'Y'
+144151,'Q'
+144151,'H'
+144151,'K'
+144152,'F'
+144152,'Y'
+144152,'Q'
+144152,'H'
+144152,'K'
+144153,'F'
+144153,'Y'
+144153,'B'
+144153,'M'
+144153,'Q'
+144155,'FN'
+144155,'YN'
+144155,'BN'
+144155,'M'
+144155,'Q'
+144156,'FN'
+144156,'YN'
+144156,'B'
+144156,'M'
+144156,'V'
+144157,'F'
+144157,'Y'
+144157,'B'
+144157,'M'
+144157,'V'
+144158,'F'
+144158,'Y'
+144158,'B'
+144158,'M'
+144158,'Q'
+144159,'F'
+144159,'Y'
+144159,'B'
+144159,'M'
+144159,'V'
+144162,'F'
+144162,'Y'
+144162,'B'
+144162,'M'
+144162,'V'
+144163,'F'
+144163,'Y'
+144163,'B'
+144163,'M'
+144163,'Q'
+144164,'F'
+144164,'Y'
+144164,'B'
+144164,'M'
+144164,'V'
+144165,'F'
+144165,'Y'
+144165,'B'
+144165,'M'
+144165,'Q'
+144166,'F'
+144166,'Y'
+144166,'B'
+144166,'M'
+144166,'V'
+144167,'F'
+144167,'Y'
+144167,'B'
+144167,'M'
+144167,'Q'
+144168,'F'
+144168,'Y'
+144168,'B'
+144168,'M'
+144168,'V'
+144169,'F'
+144169,'Y'
+144169,'B'
+144169,'M'
+144169,'Q'
+144477,'Y'
+144477,'B'
+144477,'M'
+144477,'V'
+144477,'Q'
+144478,'Y'
+144478,'B'
+144478,'M'
+144478,'V'
+144478,'Q'
+144479,'Y'
+144479,'B'
+144479,'M'
+144479,'V'
+144479,'Q'
+144480,'YN'
+144480,'B'
+144480,'M'
+144480,'V'
+144480,'Q'
+144541,'F'
+144541,'Y'
+144541,'B'
+144541,'M'
+144541,'Q'
+144547,'F'
+144547,'Y'
+144547,'B'
+144547,'M'
+144547,'Q'
+144572,'F'
+144572,'Y'
+144572,'B'
+144572,'H'
+144572,'Q'
+144574,'F'
+144574,'Y'
+144574,'B'
+144574,'H'
+144574,'Q'
+144575,'F'
+144575,'Y'
+144575,'B'
+144575,'H'
+144575,'Q'
+144576,'F'
+144576,'Y'
+144576,'B'
+144576,'H'
+144576,'Q'
+101908,'FN'
+101908,'YN'
+101908,'BN'
+101908,'M'
+101908,'Q'
+101913,'F'
+101913,'Y'
+101913,'B'
+101913,'M'
+101913,'Q'
+101924,'F'
+101924,'Y'
+101924,'B'
+101924,'M'
+101924,'Q'
+102674,'F'
+102674,'Y'
+102674,'B'
+102674,'M'
+102674,'Q'
+105810,'F'
+105810,'Y'
+105810,'B'
+105810,'M'
+105810,'Q'
+106262,'F'
+106262,'Y'
+106262,'B'
+106262,'H'
+106262,'Q'
+106270,'F'
+106270,'Y'
+106270,'B'
+106270,'H'
+106270,'Q'
+106366,'F'
+106366,'Y'
+106366,'B'
+106366,'M'
+106366,'Q'
+106373,'F'
+106373,'Y'
+106373,'B'
+106373,'M'
+106373,'V'
+106375,'F'
+106375,'Y'
+106375,'Q'
+106375,'H'
+106375,'K'
+107253,'F'
+107253,'Y'
+107253,'B'
+107253,'H'
+107253,'Q'
+111924,'FN'
+111924,'YN'
+111924,'BN'
+111924,'M'
+111924,'Q'
+111930,'F'
+111930,'Y'
+111930,'B'
+111930,'H'
+111930,'Q'
+112413,'FN'
+112413,'YN'
+112413,'BN'
+112413,'M'
+112413,'Q'
+113499,'F'
+113499,'Y'
+113499,'B'
+113499,'M'
+113499,'Q'
+113710,'F'
+113710,'Y'
+113710,'Q'
+113710,'H'
+113710,'K'
+113713,'F'
+113713,'Y'
+113713,'B'
+113713,'M'
+113713,'Q'
+133423,'F'
+133423,'Y'
+133423,'B'
+133423,'M'
+133423,'Q'
+133516,'F'
+133516,'Y'
+133516,'B'
+133516,'M'
+133516,'V'
+137410,'F'
+137410,'Y'
+137410,'B'
+137410,'M'
+137410,'Q'
+137685,'F'
+137685,'Y'
+137685,'B'
+137685,'M'
+137685,'V'
+137814,'F'
+137814,'Y'
+137814,'B'
+137814,'H'
+137814,'Q'
+138866,'F'
+138866,'Y'
+138866,'B'
+138866,'H'
+138866,'Q'
+138965,'F'
+138965,'Y'
+138965,'B'
+138965,'M'
+138965,'V'
+144059,'F'
+144059,'Y'
+144059,'B'
+144059,'M'
+144059,'V'
+144087,'FN'
+144087,'YN'
+144087,'B'
+144087,'M'
+144087,'V'
+144088,'F'
+144088,'Y'
+144088,'Q'
+144088,'H'
+144088,'K'
+144092,'F'
+144092,'Y'
+144092,'B'
+144092,'M'
+144092,'Q'
+144093,'F'
+144093,'Y'
+144093,'B'
+144093,'H'
+144093,'Q'
+144095,'F'
+144095,'Y'
+144095,'B'
+144095,'M'
+144095,'Q'
+144110,'F'
+144110,'Y'
+144110,'B'
+144110,'H'
+144110,'Q'
+144160,'F'
+144160,'Y'
+144160,'B'
+144160,'M'
+144160,'Q'
+144161,'F'
+144161,'Y'
+144161,'B'
+144161,'M'
+144161,'Q'
+144543,'F'
+144543,'Y'
+144543,'B'
+144543,'H'
+144543,'Q'
diff --git a/sql-bench/Data/ATIS/flight_day.txt b/sql-bench/Data/ATIS/flight_day.txt
new file mode 100644
index 00000000000..ef181d112c1
--- /dev/null
+++ b/sql-bench/Data/ATIS/flight_day.txt
@@ -0,0 +1,448 @@
+'1234567',1,'MONDAY'
+'1234567',2,'TUESDAY'
+'1234567',3,'WEDNESDAY'
+'1234567',4,'THURSDAY'
+'1234567',5,'FRIDAY'
+'1234567',6,'SATURDAY'
+'1234567',7,'SUNDAY'
+'-234567',2,'TUESDAY'
+'-234567',3,'WEDNESDAY'
+'-234567',4,'THURSDAY'
+'-234567',5,'FRIDAY'
+'-234567',6,'SATURDAY'
+'-234567',7,'SUNDAY'
+'1-34567',1,'MONDAY'
+'1-34567',3,'WEDNESDAY'
+'1-34567',4,'THURSDAY'
+'1-34567',5,'FRIDAY'
+'1-34567',6,'SATURDAY'
+'1-34567',7,'SUNDAY'
+'--34567',3,'WEDNESDAY'
+'--34567',4,'THURSDAY'
+'--34567',5,'FRIDAY'
+'--34567',6,'SATURDAY'
+'--34567',7,'SUNDAY'
+'12-4567',1,'MONDAY'
+'12-4567',2,'TUESDAY'
+'12-4567',4,'THURSDAY'
+'12-4567',5,'FRIDAY'
+'12-4567',6,'SATURDAY'
+'12-4567',7,'SUNDAY'
+'-2-4567',2,'TUESDAY'
+'-2-4567',4,'THURSDAY'
+'-2-4567',5,'FRIDAY'
+'-2-4567',6,'SATURDAY'
+'-2-4567',7,'SUNDAY'
+'1--4567',1,'MONDAY'
+'1--4567',4,'THURSDAY'
+'1--4567',5,'FRIDAY'
+'1--4567',6,'SATURDAY'
+'1--4567',7,'SUNDAY'
+'---4567',4,'THURSDAY'
+'---4567',5,'FRIDAY'
+'---4567',6,'SATURDAY'
+'---4567',7,'SUNDAY'
+'123-567',1,'MONDAY'
+'123-567',2,'TUESDAY'
+'123-567',3,'WEDNESDAY'
+'123-567',5,'FRIDAY'
+'123-567',6,'SATURDAY'
+'123-567',7,'SUNDAY'
+'-23-567',2,'TUESDAY'
+'-23-567',3,'WEDNESDAY'
+'-23-567',5,'FRIDAY'
+'-23-567',6,'SATURDAY'
+'-23-567',7,'SUNDAY'
+'1-3-567',1,'MONDAY'
+'1-3-567',3,'WEDNESDAY'
+'1-3-567',5,'FRIDAY'
+'1-3-567',6,'SATURDAY'
+'1-3-567',7,'SUNDAY'
+'--3-567',3,'WEDNESDAY'
+'--3-567',5,'FRIDAY'
+'--3-567',6,'SATURDAY'
+'--3-567',7,'SUNDAY'
+'12--567',1,'MONDAY'
+'12--567',2,'TUESDAY'
+'12--567',5,'FRIDAY'
+'12--567',6,'SATURDAY'
+'12--567',7,'SUNDAY'
+'-2--567',2,'TUESDAY'
+'-2--567',5,'FRIDAY'
+'-2--567',6,'SATURDAY'
+'-2--567',7,'SUNDAY'
+'1---567',1,'MONDAY'
+'1---567',5,'FRIDAY'
+'1---567',6,'SATURDAY'
+'1---567',7,'SUNDAY'
+'----567',5,'FRIDAY'
+'----567',6,'SATURDAY'
+'----567',7,'SUNDAY'
+'1234-67',1,'MONDAY'
+'1234-67',2,'TUESDAY'
+'1234-67',3,'WEDNESDAY'
+'1234-67',4,'THURSDAY'
+'1234-67',6,'SATURDAY'
+'1234-67',7,'SUNDAY'
+'-234-67',2,'TUESDAY'
+'-234-67',3,'WEDNESDAY'
+'-234-67',4,'THURSDAY'
+'-234-67',6,'SATURDAY'
+'-234-67',7,'SUNDAY'
+'1-34-67',1,'MONDAY'
+'1-34-67',3,'WEDNESDAY'
+'1-34-67',4,'THURSDAY'
+'1-34-67',6,'SATURDAY'
+'1-34-67',7,'SUNDAY'
+'--34-67',3,'WEDNESDAY'
+'--34-67',4,'THURSDAY'
+'--34-67',6,'SATURDAY'
+'--34-67',7,'SUNDAY'
+'12-4-67',1,'MONDAY'
+'12-4-67',2,'TUESDAY'
+'12-4-67',4,'THURSDAY'
+'12-4-67',6,'SATURDAY'
+'12-4-67',7,'SUNDAY'
+'-2-4-67',2,'TUESDAY'
+'-2-4-67',4,'THURSDAY'
+'-2-4-67',6,'SATURDAY'
+'-2-4-67',7,'SUNDAY'
+'1--4-67',1,'MONDAY'
+'1--4-67',4,'THURSDAY'
+'1--4-67',6,'SATURDAY'
+'1--4-67',7,'SUNDAY'
+'---4-67',4,'THURSDAY'
+'---4-67',6,'SATURDAY'
+'---4-67',7,'SUNDAY'
+'123--67',1,'MONDAY'
+'123--67',2,'TUESDAY'
+'123--67',3,'WEDNESDAY'
+'123--67',6,'SATURDAY'
+'123--67',7,'SUNDAY'
+'-23--67',2,'TUESDAY'
+'-23--67',3,'WEDNESDAY'
+'-23--67',6,'SATURDAY'
+'-23--67',7,'SUNDAY'
+'1-3--67',1,'MONDAY'
+'1-3--67',3,'WEDNESDAY'
+'1-3--67',6,'SATURDAY'
+'1-3--67',7,'SUNDAY'
+'--3--67',3,'WEDNESDAY'
+'--3--67',6,'SATURDAY'
+'--3--67',7,'SUNDAY'
+'12---67',1,'MONDAY'
+'12---67',2,'TUESDAY'
+'12---67',6,'SATURDAY'
+'12---67',7,'SUNDAY'
+'-2---67',2,'TUESDAY'
+'-2---67',6,'SATURDAY'
+'-2---67',7,'SUNDAY'
+'1----67',1,'MONDAY'
+'1----67',6,'SATURDAY'
+'1----67',7,'SUNDAY'
+'-----67',6,'SATURDAY'
+'-----67',7,'SUNDAY'
+'12345-7',1,'MONDAY'
+'12345-7',2,'TUESDAY'
+'12345-7',3,'WEDNESDAY'
+'12345-7',4,'THURSDAY'
+'12345-7',5,'FRIDAY'
+'12345-7',7,'SUNDAY'
+'-2345-7',2,'TUESDAY'
+'-2345-7',3,'WEDNESDAY'
+'-2345-7',4,'THURSDAY'
+'-2345-7',5,'FRIDAY'
+'-2345-7',7,'SUNDAY'
+'1-345-7',1,'MONDAY'
+'1-345-7',3,'WEDNESDAY'
+'1-345-7',4,'THURSDAY'
+'1-345-7',5,'FRIDAY'
+'1-345-7',7,'SUNDAY'
+'--345-7',3,'WEDNESDAY'
+'--345-7',4,'THURSDAY'
+'--345-7',5,'FRIDAY'
+'--345-7',7,'SUNDAY'
+'12-45-7',1,'MONDAY'
+'12-45-7',2,'TUESDAY'
+'12-45-7',4,'THURSDAY'
+'12-45-7',5,'FRIDAY'
+'12-45-7',7,'SUNDAY'
+'-2-45-7',2,'TUESDAY'
+'-2-45-7',4,'THURSDAY'
+'-2-45-7',5,'FRIDAY'
+'-2-45-7',7,'SUNDAY'
+'1--45-7',1,'MONDAY'
+'1--45-7',4,'THURSDAY'
+'1--45-7',5,'FRIDAY'
+'1--45-7',7,'SUNDAY'
+'---45-7',4,'THURSDAY'
+'---45-7',5,'FRIDAY'
+'---45-7',7,'SUNDAY'
+'123-5-7',1,'MONDAY'
+'123-5-7',2,'TUESDAY'
+'123-5-7',3,'WEDNESDAY'
+'123-5-7',5,'FRIDAY'
+'123-5-7',7,'SUNDAY'
+'-23-5-7',2,'TUESDAY'
+'-23-5-7',3,'WEDNESDAY'
+'-23-5-7',5,'FRIDAY'
+'-23-5-7',7,'SUNDAY'
+'1-3-5-7',1,'MONDAY'
+'1-3-5-7',3,'WEDNESDAY'
+'1-3-5-7',5,'FRIDAY'
+'1-3-5-7',7,'SUNDAY'
+'--3-5-7',3,'WEDNESDAY'
+'--3-5-7',5,'FRIDAY'
+'--3-5-7',7,'SUNDAY'
+'12--5-7',1,'MONDAY'
+'12--5-7',2,'TUESDAY'
+'12--5-7',5,'FRIDAY'
+'12--5-7',7,'SUNDAY'
+'-2--5-7',2,'TUESDAY'
+'-2--5-7',5,'FRIDAY'
+'-2--5-7',7,'SUNDAY'
+'1---5-7',1,'MONDAY'
+'1---5-7',5,'FRIDAY'
+'1---5-7',7,'SUNDAY'
+'----5-7',5,'FRIDAY'
+'----5-7',7,'SUNDAY'
+'1234--7',1,'MONDAY'
+'1234--7',2,'TUESDAY'
+'1234--7',3,'WEDNESDAY'
+'1234--7',4,'THURSDAY'
+'1234--7',7,'SUNDAY'
+'-234--7',2,'TUESDAY'
+'-234--7',3,'WEDNESDAY'
+'-234--7',4,'THURSDAY'
+'-234--7',7,'SUNDAY'
+'1-34--7',1,'MONDAY'
+'1-34--7',3,'WEDNESDAY'
+'1-34--7',4,'THURSDAY'
+'1-34--7',7,'SUNDAY'
+'--34--7',3,'WEDNESDAY'
+'--34--7',4,'THURSDAY'
+'--34--7',7,'SUNDAY'
+'12-4--7',1,'MONDAY'
+'12-4--7',2,'TUESDAY'
+'12-4--7',4,'THURSDAY'
+'12-4--7',7,'SUNDAY'
+'-2-4--7',2,'TUESDAY'
+'-2-4--7',4,'THURSDAY'
+'-2-4--7',7,'SUNDAY'
+'1--4--7',1,'MONDAY'
+'1--4--7',4,'THURSDAY'
+'1--4--7',7,'SUNDAY'
+'---4--7',4,'THURSDAY'
+'---4--7',7,'SUNDAY'
+'123---7',1,'MONDAY'
+'123---7',2,'TUESDAY'
+'123---7',3,'WEDNESDAY'
+'123---7',7,'SUNDAY'
+'-23---7',2,'TUESDAY'
+'-23---7',3,'WEDNESDAY'
+'-23---7',7,'SUNDAY'
+'1-3---7',1,'MONDAY'
+'1-3---7',3,'WEDNESDAY'
+'1-3---7',7,'SUNDAY'
+'--3---7',3,'WEDNESDAY'
+'--3---7',7,'SUNDAY'
+'12----7',1,'MONDAY'
+'12----7',2,'TUESDAY'
+'12----7',7,'SUNDAY'
+'-2----7',2,'TUESDAY'
+'-2----7',7,'SUNDAY'
+'1-----7',1,'MONDAY'
+'1-----7',7,'SUNDAY'
+'------7',7,'SUNDAY'
+'123456-',1,'MONDAY'
+'123456-',2,'TUESDAY'
+'123456-',3,'WEDNESDAY'
+'123456-',4,'THURSDAY'
+'123456-',5,'FRIDAY'
+'123456-',6,'SATURDAY'
+'-23456-',2,'TUESDAY'
+'-23456-',3,'WEDNESDAY'
+'-23456-',4,'THURSDAY'
+'-23456-',5,'FRIDAY'
+'-23456-',6,'SATURDAY'
+'1-3456-',1,'MONDAY'
+'1-3456-',3,'WEDNESDAY'
+'1-3456-',4,'THURSDAY'
+'1-3456-',5,'FRIDAY'
+'1-3456-',6,'SATURDAY'
+'--3456-',3,'WEDNESDAY'
+'--3456-',4,'THURSDAY'
+'--3456-',5,'FRIDAY'
+'--3456-',6,'SATURDAY'
+'12-456-',1,'MONDAY'
+'12-456-',2,'TUESDAY'
+'12-456-',4,'THURSDAY'
+'12-456-',5,'FRIDAY'
+'12-456-',6,'SATURDAY'
+'-2-456-',2,'TUESDAY'
+'-2-456-',4,'THURSDAY'
+'-2-456-',5,'FRIDAY'
+'-2-456-',6,'SATURDAY'
+'1--456-',1,'MONDAY'
+'1--456-',4,'THURSDAY'
+'1--456-',5,'FRIDAY'
+'1--456-',6,'SATURDAY'
+'---456-',4,'THURSDAY'
+'---456-',5,'FRIDAY'
+'---456-',6,'SATURDAY'
+'123-56-',1,'MONDAY'
+'123-56-',2,'TUESDAY'
+'123-56-',3,'WEDNESDAY'
+'123-56-',5,'FRIDAY'
+'123-56-',6,'SATURDAY'
+'-23-56-',2,'TUESDAY'
+'-23-56-',3,'WEDNESDAY'
+'-23-56-',5,'FRIDAY'
+'-23-56-',6,'SATURDAY'
+'1-3-56-',1,'MONDAY'
+'1-3-56-',3,'WEDNESDAY'
+'1-3-56-',5,'FRIDAY'
+'1-3-56-',6,'SATURDAY'
+'--3-56-',3,'WEDNESDAY'
+'--3-56-',5,'FRIDAY'
+'--3-56-',6,'SATURDAY'
+'12--56-',1,'MONDAY'
+'12--56-',2,'TUESDAY'
+'12--56-',5,'FRIDAY'
+'12--56-',6,'SATURDAY'
+'-2--56-',2,'TUESDAY'
+'-2--56-',5,'FRIDAY'
+'-2--56-',6,'SATURDAY'
+'1---56-',1,'MONDAY'
+'1---56-',5,'FRIDAY'
+'1---56-',6,'SATURDAY'
+'----56-',5,'FRIDAY'
+'----56-',6,'SATURDAY'
+'1234-6-',1,'MONDAY'
+'1234-6-',2,'TUESDAY'
+'1234-6-',3,'WEDNESDAY'
+'1234-6-',4,'THURSDAY'
+'1234-6-',6,'SATURDAY'
+'-234-6-',2,'TUESDAY'
+'-234-6-',3,'WEDNESDAY'
+'-234-6-',4,'THURSDAY'
+'-234-6-',6,'SATURDAY'
+'1-34-6-',1,'MONDAY'
+'1-34-6-',3,'WEDNESDAY'
+'1-34-6-',4,'THURSDAY'
+'1-34-6-',6,'SATURDAY'
+'--34-6-',3,'WEDNESDAY'
+'--34-6-',4,'THURSDAY'
+'--34-6-',6,'SATURDAY'
+'12-4-6-',1,'MONDAY'
+'12-4-6-',2,'TUESDAY'
+'12-4-6-',4,'THURSDAY'
+'12-4-6-',6,'SATURDAY'
+'-2-4-6-',2,'TUESDAY'
+'-2-4-6-',4,'THURSDAY'
+'-2-4-6-',6,'SATURDAY'
+'1--4-6-',1,'MONDAY'
+'1--4-6-',4,'THURSDAY'
+'1--4-6-',6,'SATURDAY'
+'---4-6-',4,'THURSDAY'
+'---4-6-',6,'SATURDAY'
+'123--6-',1,'MONDAY'
+'123--6-',2,'TUESDAY'
+'123--6-',3,'WEDNESDAY'
+'123--6-',6,'SATURDAY'
+'-23--6-',2,'TUESDAY'
+'-23--6-',3,'WEDNESDAY'
+'-23--6-',6,'SATURDAY'
+'1-3--6-',1,'MONDAY'
+'1-3--6-',3,'WEDNESDAY'
+'1-3--6-',6,'SATURDAY'
+'--3--6-',3,'WEDNESDAY'
+'--3--6-',6,'SATURDAY'
+'12---6-',1,'MONDAY'
+'12---6-',2,'TUESDAY'
+'12---6-',6,'SATURDAY'
+'-2---6-',2,'TUESDAY'
+'-2---6-',6,'SATURDAY'
+'1----6-',1,'MONDAY'
+'1----6-',6,'SATURDAY'
+'-----6-',6,'SATURDAY'
+'12345--',1,'MONDAY'
+'12345--',2,'TUESDAY'
+'12345--',3,'WEDNESDAY'
+'12345--',4,'THURSDAY'
+'12345--',5,'FRIDAY'
+'-2345--',2,'TUESDAY'
+'-2345--',3,'WEDNESDAY'
+'-2345--',4,'THURSDAY'
+'-2345--',5,'FRIDAY'
+'1-345--',1,'MONDAY'
+'1-345--',3,'WEDNESDAY'
+'1-345--',4,'THURSDAY'
+'1-345--',5,'FRIDAY'
+'--345--',3,'WEDNESDAY'
+'--345--',4,'THURSDAY'
+'--345--',5,'FRIDAY'
+'12-45--',1,'MONDAY'
+'12-45--',2,'TUESDAY'
+'12-45--',4,'THURSDAY'
+'12-45--',5,'FRIDAY'
+'-2-45--',2,'TUESDAY'
+'-2-45--',4,'THURSDAY'
+'-2-45--',5,'FRIDAY'
+'1--45--',1,'MONDAY'
+'1--45--',4,'THURSDAY'
+'1--45--',5,'FRIDAY'
+'---45--',4,'THURSDAY'
+'---45--',5,'FRIDAY'
+'123-5--',1,'MONDAY'
+'123-5--',2,'TUESDAY'
+'123-5--',3,'WEDNESDAY'
+'123-5--',5,'FRIDAY'
+'-23-5--',2,'TUESDAY'
+'-23-5--',3,'WEDNESDAY'
+'-23-5--',5,'FRIDAY'
+'1-3-5--',1,'MONDAY'
+'1-3-5--',3,'WEDNESDAY'
+'1-3-5--',5,'FRIDAY'
+'--3-5--',3,'WEDNESDAY'
+'--3-5--',5,'FRIDAY'
+'12--5--',1,'MONDAY'
+'12--5--',2,'TUESDAY'
+'12--5--',5,'FRIDAY'
+'-2--5--',2,'TUESDAY'
+'-2--5--',5,'FRIDAY'
+'1---5--',1,'MONDAY'
+'1---5--',5,'FRIDAY'
+'----5--',5,'FRIDAY'
+'1234---',1,'MONDAY'
+'1234---',2,'TUESDAY'
+'1234---',3,'WEDNESDAY'
+'1234---',4,'THURSDAY'
+'-234---',2,'TUESDAY'
+'-234---',3,'WEDNESDAY'
+'-234---',4,'THURSDAY'
+'1-34---',1,'MONDAY'
+'1-34---',3,'WEDNESDAY'
+'1-34---',4,'THURSDAY'
+'--34---',3,'WEDNESDAY'
+'--34---',4,'THURSDAY'
+'12-4---',1,'MONDAY'
+'12-4---',2,'TUESDAY'
+'12-4---',4,'THURSDAY'
+'-2-4---',2,'TUESDAY'
+'-2-4---',4,'THURSDAY'
+'1--4---',1,'MONDAY'
+'1--4---',4,'THURSDAY'
+'---4---',4,'THURSDAY'
+'123----',1,'MONDAY'
+'123----',2,'TUESDAY'
+'123----',3,'WEDNESDAY'
+'-23----',2,'TUESDAY'
+'-23----',3,'WEDNESDAY'
+'1-3----',1,'MONDAY'
+'1-3----',3,'WEDNESDAY'
+'--3----',3,'WEDNESDAY'
+'12-----',1,'MONDAY'
+'12-----',2,'TUESDAY'
+'-2-----',2,'TUESDAY'
+'1------',1,'MONDAY'
diff --git a/sql-bench/Data/ATIS/flight_fare.txt b/sql-bench/Data/ATIS/flight_fare.txt
new file mode 100644
index 00000000000..1ca85f9b9e9
--- /dev/null
+++ b/sql-bench/Data/ATIS/flight_fare.txt
@@ -0,0 +1,2998 @@
+101910,'7100001'
+101911,'7100001'
+101912,'7100001'
+101915,'7100001'
+101916,'7100001'
+101917,'7100001'
+101918,'7100001'
+101922,'7100001'
+101923,'7100001'
+101925,'7100001'
+101926,'7100001'
+101927,'7100001'
+101928,'7100001'
+101913,'7100001'
+101924,'7100001'
+101909,'7100002'
+101929,'7100002'
+101908,'7100002'
+101910,'7100003'
+101911,'7100003'
+101912,'7100003'
+101914,'7100003'
+101915,'7100003'
+101916,'7100003'
+101917,'7100003'
+101918,'7100003'
+101922,'7100003'
+101923,'7100003'
+101925,'7100003'
+101926,'7100003'
+101927,'7100003'
+101928,'7100003'
+101913,'7100003'
+101924,'7100003'
+101909,'7100004'
+101929,'7100004'
+101908,'7100004'
+101910,'7100005'
+101911,'7100005'
+101914,'7100005'
+101915,'7100005'
+101918,'7100005'
+101923,'7100005'
+101926,'7100005'
+101910,'7100006'
+101911,'7100006'
+101914,'7100006'
+101915,'7100006'
+101918,'7100006'
+101923,'7100006'
+101926,'7100006'
+101908,'7100007'
+101913,'7100007'
+101924,'7100007'
+101909,'7100007'
+101910,'7100007'
+101911,'7100007'
+101912,'7100007'
+101914,'7100007'
+101915,'7100007'
+101916,'7100007'
+101917,'7100007'
+101918,'7100007'
+101922,'7100007'
+101923,'7100007'
+101925,'7100007'
+101926,'7100007'
+101927,'7100007'
+101928,'7100007'
+101929,'7100007'
+101908,'7100008'
+101913,'7100008'
+101924,'7100008'
+101909,'7100008'
+101910,'7100008'
+101911,'7100008'
+101912,'7100008'
+101914,'7100008'
+101915,'7100008'
+101917,'7100008'
+101918,'7100008'
+101922,'7100008'
+101923,'7100008'
+101925,'7100008'
+101926,'7100008'
+101928,'7100008'
+101929,'7100008'
+101913,'7100009'
+101924,'7100009'
+101912,'7100009'
+101916,'7100009'
+101917,'7100009'
+101922,'7100009'
+101925,'7100009'
+101927,'7100009'
+101928,'7100009'
+101913,'7100010'
+101924,'7100010'
+101910,'7100010'
+101911,'7100010'
+101912,'7100010'
+101914,'7100010'
+101915,'7100010'
+101916,'7100010'
+101917,'7100010'
+101918,'7100010'
+101922,'7100010'
+101923,'7100010'
+101925,'7100010'
+101926,'7100010'
+101927,'7100010'
+101928,'7100010'
+101951,'7100011'
+101952,'7100011'
+101953,'7100011'
+101954,'7100011'
+101955,'7100011'
+101956,'7100011'
+101957,'7100011'
+101958,'7100011'
+101959,'7100012'
+101951,'7100013'
+101952,'7100013'
+101953,'7100013'
+101954,'7100013'
+101955,'7100013'
+101956,'7100013'
+101957,'7100013'
+101958,'7100013'
+101959,'7100014'
+101951,'7100015'
+101952,'7100015'
+101953,'7100015'
+101954,'7100015'
+101955,'7100015'
+101956,'7100015'
+101957,'7100015'
+101958,'7100015'
+101951,'7100016'
+101952,'7100016'
+101953,'7100016'
+101954,'7100016'
+101955,'7100016'
+101956,'7100016'
+101957,'7100016'
+101958,'7100016'
+101952,'7100017'
+101953,'7100017'
+101955,'7100017'
+101958,'7100017'
+101951,'7100018'
+101952,'7100018'
+101953,'7100018'
+101954,'7100018'
+101955,'7100018'
+101956,'7100018'
+101957,'7100018'
+101958,'7100018'
+102125,'7100019'
+102129,'7100019'
+102122,'7100020'
+102123,'7100020'
+102126,'7100020'
+102127,'7100020'
+102128,'7100020'
+102133,'7100020'
+102134,'7100021'
+102135,'7100021'
+102125,'7100022'
+102129,'7100022'
+102122,'7100023'
+102123,'7100023'
+102126,'7100023'
+102127,'7100023'
+102128,'7100023'
+102133,'7100023'
+102122,'7100024'
+102126,'7100024'
+102127,'7100024'
+102133,'7100024'
+102123,'7100025'
+102128,'7100025'
+102134,'7100025'
+102122,'7100026'
+102126,'7100026'
+102127,'7100026'
+102133,'7100026'
+102135,'7100026'
+102134,'7100027'
+102135,'7100027'
+102122,'7100028'
+102125,'7100028'
+102126,'7100028'
+102127,'7100028'
+102129,'7100028'
+102133,'7100028'
+102135,'7100028'
+102122,'7100029'
+102125,'7100029'
+102126,'7100029'
+102127,'7100029'
+102129,'7100029'
+102133,'7100029'
+102135,'7100029'
+102122,'7100030'
+102123,'7100030'
+102125,'7100030'
+102126,'7100030'
+102127,'7100030'
+102128,'7100030'
+102129,'7100030'
+102133,'7100030'
+102135,'7100030'
+102122,'7100031'
+102123,'7100031'
+102125,'7100031'
+102126,'7100031'
+102127,'7100031'
+102128,'7100031'
+102129,'7100031'
+102133,'7100031'
+102135,'7100031'
+102122,'7100032'
+102125,'7100032'
+102126,'7100032'
+102127,'7100032'
+102129,'7100032'
+102133,'7100032'
+102122,'7100033'
+102123,'7100033'
+102125,'7100033'
+102126,'7100033'
+102127,'7100033'
+102128,'7100033'
+102129,'7100033'
+102133,'7100033'
+102122,'7100034'
+102125,'7100034'
+102126,'7100034'
+102127,'7100034'
+102129,'7100034'
+102133,'7100034'
+102123,'7100035'
+102128,'7100035'
+102134,'7100035'
+102139,'7100036'
+102147,'7100036'
+102164,'7100036'
+102172,'7100036'
+102144,'7100037'
+102148,'7100037'
+102150,'7100037'
+102162,'7100037'
+102163,'7100037'
+102166,'7100037'
+102173,'7100037'
+102177,'7100037'
+102165,'7100038'
+102188,'7100039'
+102136,'7100040'
+102137,'7100040'
+102190,'7100040'
+102191,'7100040'
+102192,'7100040'
+102139,'7100041'
+102147,'7100041'
+102164,'7100041'
+102172,'7100041'
+102144,'7100042'
+102148,'7100042'
+102150,'7100042'
+102162,'7100042'
+102163,'7100042'
+102166,'7100042'
+102173,'7100042'
+102177,'7100042'
+102188,'7100043'
+102136,'7100044'
+102137,'7100044'
+102190,'7100044'
+102191,'7100044'
+102192,'7100044'
+102136,'7100045'
+102144,'7100045'
+102148,'7100045'
+102150,'7100045'
+102162,'7100045'
+102166,'7100045'
+102173,'7100045'
+102177,'7100045'
+102190,'7100045'
+102191,'7100045'
+102192,'7100045'
+102136,'7100046'
+102137,'7100046'
+102144,'7100046'
+102148,'7100046'
+102150,'7100046'
+102162,'7100046'
+102163,'7100046'
+102166,'7100046'
+102173,'7100046'
+102177,'7100046'
+102190,'7100046'
+102191,'7100046'
+102192,'7100046'
+102144,'7100047'
+102148,'7100047'
+102150,'7100047'
+102162,'7100047'
+102163,'7100047'
+102165,'7100047'
+102166,'7100047'
+102173,'7100047'
+102177,'7100047'
+102139,'7100048'
+102147,'7100048'
+102164,'7100048'
+102172,'7100048'
+102136,'7100049'
+102137,'7100049'
+102144,'7100049'
+102148,'7100049'
+102150,'7100049'
+102162,'7100049'
+102163,'7100049'
+102165,'7100049'
+102166,'7100049'
+102173,'7100049'
+102177,'7100049'
+102190,'7100049'
+102191,'7100049'
+102192,'7100049'
+102144,'7100050'
+102148,'7100050'
+102150,'7100050'
+102162,'7100050'
+102163,'7100050'
+102166,'7100050'
+102173,'7100050'
+102177,'7100050'
+102674,'7100051'
+102674,'7100052'
+102674,'7100053'
+102674,'7100054'
+102674,'7100055'
+102674,'7100056'
+102674,'7100057'
+102767,'7100058'
+102771,'7100058'
+102777,'7100058'
+102768,'7100059'
+102769,'7100059'
+102770,'7100059'
+102772,'7100059'
+102773,'7100059'
+102774,'7100059'
+102775,'7100059'
+102776,'7100059'
+102778,'7100059'
+102779,'7100059'
+102781,'7100059'
+102782,'7100059'
+102766,'7100060'
+102783,'7100060'
+102784,'7100060'
+102768,'7100061'
+102769,'7100061'
+102770,'7100061'
+102772,'7100061'
+102773,'7100061'
+102774,'7100061'
+102775,'7100061'
+102776,'7100061'
+102778,'7100061'
+102779,'7100061'
+102781,'7100061'
+102782,'7100061'
+102767,'7100062'
+102771,'7100062'
+102777,'7100062'
+102766,'7100063'
+102783,'7100063'
+102784,'7100063'
+102768,'7100064'
+102769,'7100064'
+102772,'7100064'
+102774,'7100064'
+102775,'7100064'
+102778,'7100064'
+102781,'7100064'
+102783,'7100064'
+102766,'7100065'
+102767,'7100065'
+102768,'7100065'
+102769,'7100065'
+102770,'7100065'
+102771,'7100065'
+102772,'7100065'
+102773,'7100065'
+102774,'7100065'
+102775,'7100065'
+102776,'7100065'
+102777,'7100065'
+102778,'7100065'
+102779,'7100065'
+102781,'7100065'
+102782,'7100065'
+102784,'7100065'
+102766,'7100066'
+102767,'7100066'
+102768,'7100066'
+102769,'7100066'
+102770,'7100066'
+102771,'7100066'
+102772,'7100066'
+102773,'7100066'
+102774,'7100066'
+102775,'7100066'
+102776,'7100066'
+102777,'7100066'
+102778,'7100066'
+102779,'7100066'
+102781,'7100066'
+102782,'7100066'
+102784,'7100066'
+102768,'7100067'
+102769,'7100067'
+102772,'7100067'
+102774,'7100067'
+102775,'7100067'
+102778,'7100067'
+102781,'7100067'
+102783,'7100067'
+102766,'7100068'
+102767,'7100068'
+102768,'7100068'
+102769,'7100068'
+102770,'7100068'
+102771,'7100068'
+102772,'7100068'
+102773,'7100068'
+102774,'7100068'
+102775,'7100068'
+102776,'7100068'
+102777,'7100068'
+102778,'7100068'
+102779,'7100068'
+102781,'7100068'
+102782,'7100068'
+102784,'7100068'
+102766,'7100069'
+102767,'7100069'
+102768,'7100069'
+102769,'7100069'
+102770,'7100069'
+102771,'7100069'
+102772,'7100069'
+102773,'7100069'
+102774,'7100069'
+102775,'7100069'
+102776,'7100069'
+102777,'7100069'
+102778,'7100069'
+102779,'7100069'
+102781,'7100069'
+102782,'7100069'
+102784,'7100069'
+102767,'7100070'
+102770,'7100070'
+102771,'7100070'
+102773,'7100070'
+102776,'7100070'
+102777,'7100070'
+102779,'7100070'
+102782,'7100070'
+102767,'7100071'
+102768,'7100071'
+102769,'7100071'
+102770,'7100071'
+102771,'7100071'
+102772,'7100071'
+102773,'7100071'
+102774,'7100071'
+102775,'7100071'
+102776,'7100071'
+102777,'7100071'
+102778,'7100071'
+102779,'7100071'
+102781,'7100071'
+102782,'7100071'
+102795,'7100072'
+102796,'7100072'
+102797,'7100072'
+102798,'7100072'
+102799,'7100072'
+102800,'7100072'
+102801,'7100072'
+102802,'7100072'
+102803,'7100072'
+102805,'7100072'
+102806,'7100072'
+102807,'7100072'
+102808,'7100073'
+102809,'7100073'
+102795,'7100074'
+102796,'7100074'
+102797,'7100074'
+102798,'7100074'
+102799,'7100074'
+102800,'7100074'
+102801,'7100074'
+102802,'7100074'
+102803,'7100074'
+102804,'7100074'
+102805,'7100074'
+102806,'7100074'
+102807,'7100074'
+102808,'7100075'
+102809,'7100075'
+102797,'7100076'
+102799,'7100076'
+102804,'7100076'
+102806,'7100076'
+102808,'7100076'
+102795,'7100077'
+102796,'7100077'
+102797,'7100077'
+102798,'7100077'
+102799,'7100077'
+102800,'7100077'
+102801,'7100077'
+102802,'7100077'
+102804,'7100077'
+102805,'7100077'
+102806,'7100077'
+102807,'7100077'
+102809,'7100077'
+102797,'7100078'
+102799,'7100078'
+102804,'7100078'
+102806,'7100078'
+102808,'7100078'
+102795,'7100079'
+102796,'7100079'
+102797,'7100079'
+102798,'7100079'
+102799,'7100079'
+102800,'7100079'
+102801,'7100079'
+102803,'7100079'
+102804,'7100079'
+102805,'7100079'
+102806,'7100079'
+102807,'7100079'
+102809,'7100079'
+102795,'7100080'
+102796,'7100080'
+102798,'7100080'
+102800,'7100080'
+102801,'7100080'
+102802,'7100080'
+102803,'7100080'
+102805,'7100080'
+102807,'7100080'
+102795,'7100081'
+102796,'7100081'
+102797,'7100081'
+102798,'7100081'
+102799,'7100081'
+102800,'7100081'
+102801,'7100081'
+102802,'7100081'
+102803,'7100081'
+102804,'7100081'
+102805,'7100081'
+102806,'7100081'
+102807,'7100081'
+102923,'7100082'
+102924,'7100082'
+102925,'7100082'
+102927,'7100082'
+102929,'7100082'
+102930,'7100082'
+102932,'7100082'
+102933,'7100082'
+102923,'7100083'
+102924,'7100083'
+102925,'7100083'
+102927,'7100083'
+102929,'7100083'
+102930,'7100083'
+102932,'7100083'
+102933,'7100083'
+102923,'7100084'
+102924,'7100084'
+102925,'7100084'
+102927,'7100084'
+102929,'7100084'
+102930,'7100084'
+102932,'7100084'
+102933,'7100084'
+102924,'7100085'
+102925,'7100085'
+102927,'7100085'
+102929,'7100085'
+102930,'7100085'
+102932,'7100085'
+102933,'7100085'
+102925,'7100086'
+102930,'7100086'
+102933,'7100086'
+102923,'7100087'
+102924,'7100087'
+102925,'7100087'
+102927,'7100087'
+102929,'7100087'
+102930,'7100087'
+102932,'7100087'
+102933,'7100087'
+102923,'7100088'
+102924,'7100088'
+102927,'7100088'
+102929,'7100088'
+102932,'7100088'
+102923,'7100089'
+102924,'7100089'
+102925,'7100089'
+102927,'7100089'
+102929,'7100089'
+102930,'7100089'
+102932,'7100089'
+102933,'7100089'
+105584,'7100090'
+105588,'7100090'
+105589,'7100090'
+105590,'7100090'
+105591,'7100090'
+105592,'7100090'
+105593,'7100090'
+105595,'7100090'
+105597,'7100090'
+105598,'7100090'
+105599,'7100090'
+105586,'7100091'
+105601,'7100091'
+105584,'7100092'
+105588,'7100092'
+105589,'7100092'
+105590,'7100092'
+105591,'7100092'
+105592,'7100092'
+105593,'7100092'
+105594,'7100092'
+105595,'7100092'
+105597,'7100092'
+105598,'7100092'
+105599,'7100092'
+105586,'7100093'
+105601,'7100093'
+105586,'7100094'
+105589,'7100094'
+105591,'7100094'
+105593,'7100094'
+105594,'7100094'
+105597,'7100094'
+105598,'7100094'
+105586,'7100095'
+105589,'7100095'
+105591,'7100095'
+105593,'7100095'
+105594,'7100095'
+105597,'7100095'
+105598,'7100095'
+105584,'7100096'
+105588,'7100096'
+105589,'7100096'
+105590,'7100096'
+105591,'7100096'
+105592,'7100096'
+105593,'7100096'
+105594,'7100096'
+105595,'7100096'
+105597,'7100096'
+105598,'7100096'
+105599,'7100096'
+105601,'7100096'
+105584,'7100097'
+105588,'7100097'
+105589,'7100097'
+105590,'7100097'
+105591,'7100097'
+105592,'7100097'
+105593,'7100097'
+105594,'7100097'
+105595,'7100097'
+105597,'7100097'
+105598,'7100097'
+105599,'7100097'
+105601,'7100097'
+105584,'7100098'
+105588,'7100098'
+105590,'7100098'
+105592,'7100098'
+105595,'7100098'
+105599,'7100098'
+105584,'7100099'
+105588,'7100099'
+105589,'7100099'
+105590,'7100099'
+105591,'7100099'
+105592,'7100099'
+105593,'7100099'
+105594,'7100099'
+105595,'7100099'
+105597,'7100099'
+105598,'7100099'
+105599,'7100099'
+105698,'7100100'
+105699,'7100100'
+105700,'7100100'
+105701,'7100100'
+105702,'7100100'
+105703,'7100100'
+105704,'7100100'
+105705,'7100100'
+105698,'7100101'
+105699,'7100101'
+105700,'7100101'
+105701,'7100101'
+105702,'7100101'
+105703,'7100101'
+105704,'7100101'
+105705,'7100101'
+105698,'7100102'
+105699,'7100102'
+105700,'7100102'
+105701,'7100102'
+105702,'7100102'
+105703,'7100102'
+105704,'7100102'
+105705,'7100102'
+105794,'7100103'
+105795,'7100103'
+105796,'7100103'
+105798,'7100103'
+105799,'7100103'
+105800,'7100103'
+105794,'7100104'
+105795,'7100104'
+105796,'7100104'
+105798,'7100104'
+105799,'7100104'
+105800,'7100104'
+105794,'7100105'
+105795,'7100105'
+105796,'7100105'
+105798,'7100105'
+105799,'7100105'
+105800,'7100105'
+105794,'7100106'
+105796,'7100106'
+105798,'7100106'
+105799,'7100106'
+105800,'7100106'
+105794,'7100107'
+105795,'7100107'
+105799,'7100107'
+105794,'7100108'
+105795,'7100108'
+105796,'7100108'
+105798,'7100108'
+105799,'7100108'
+105800,'7100108'
+105801,'7100109'
+105803,'7100109'
+105806,'7100109'
+105807,'7100109'
+105811,'7100109'
+105802,'7100110'
+105805,'7100110'
+105808,'7100110'
+105812,'7100110'
+105810,'7100110'
+105801,'7100111'
+105803,'7100111'
+105806,'7100111'
+105807,'7100111'
+105811,'7100111'
+105802,'7100112'
+105805,'7100112'
+105808,'7100112'
+105812,'7100112'
+105810,'7100112'
+105810,'7100113'
+105801,'7100113'
+105802,'7100113'
+105803,'7100113'
+105805,'7100113'
+105806,'7100113'
+105807,'7100113'
+105808,'7100113'
+105811,'7100113'
+105812,'7100113'
+105810,'7100114'
+105801,'7100114'
+105802,'7100114'
+105803,'7100114'
+105805,'7100114'
+105806,'7100114'
+105807,'7100114'
+105808,'7100114'
+105811,'7100114'
+105812,'7100114'
+106229,'7100115'
+106230,'7100115'
+106231,'7100115'
+106232,'7100115'
+106234,'7100115'
+106235,'7100115'
+106236,'7100115'
+106237,'7100115'
+106238,'7100115'
+106239,'7100115'
+106240,'7100115'
+106241,'7100115'
+106242,'7100115'
+106245,'7100115'
+106246,'7100115'
+106247,'7100115'
+106248,'7100115'
+106249,'7100115'
+106250,'7100115'
+106251,'7100115'
+106252,'7100115'
+106253,'7100115'
+106254,'7100115'
+106255,'7100115'
+106232,'7100116'
+106238,'7100116'
+106242,'7100116'
+106248,'7100116'
+106254,'7100116'
+106232,'7100117'
+106238,'7100117'
+106242,'7100117'
+106248,'7100117'
+106254,'7100117'
+106240,'7100118'
+106232,'7100119'
+106238,'7100119'
+106242,'7100119'
+106248,'7100119'
+106254,'7100119'
+106229,'7100120'
+106230,'7100120'
+106231,'7100120'
+106234,'7100120'
+106235,'7100120'
+106236,'7100120'
+106237,'7100120'
+106239,'7100120'
+106241,'7100120'
+106245,'7100120'
+106246,'7100120'
+106247,'7100120'
+106249,'7100120'
+106250,'7100120'
+106251,'7100120'
+106252,'7100120'
+106253,'7100120'
+106255,'7100120'
+106229,'7100121'
+106231,'7100121'
+106232,'7100121'
+106234,'7100121'
+106236,'7100121'
+106237,'7100121'
+106238,'7100121'
+106240,'7100121'
+106242,'7100121'
+106245,'7100121'
+106246,'7100121'
+106247,'7100121'
+106248,'7100121'
+106250,'7100121'
+106251,'7100121'
+106253,'7100121'
+106254,'7100121'
+106255,'7100121'
+106232,'7100122'
+106238,'7100122'
+106242,'7100122'
+106248,'7100122'
+106254,'7100122'
+106229,'7100123'
+106231,'7100123'
+106234,'7100123'
+106236,'7100123'
+106237,'7100123'
+106245,'7100123'
+106246,'7100123'
+106247,'7100123'
+106250,'7100123'
+106251,'7100123'
+106253,'7100123'
+106255,'7100123'
+106230,'7100124'
+106235,'7100124'
+106239,'7100124'
+106241,'7100124'
+106249,'7100124'
+106252,'7100124'
+106229,'7100125'
+106230,'7100125'
+106231,'7100125'
+106232,'7100125'
+106234,'7100125'
+106235,'7100125'
+106236,'7100125'
+106237,'7100125'
+106238,'7100125'
+106239,'7100125'
+106241,'7100125'
+106242,'7100125'
+106245,'7100125'
+106246,'7100125'
+106247,'7100125'
+106248,'7100125'
+106249,'7100125'
+106250,'7100125'
+106251,'7100125'
+106252,'7100125'
+106253,'7100125'
+106254,'7100125'
+106255,'7100125'
+106229,'7100126'
+106231,'7100126'
+106232,'7100126'
+106234,'7100126'
+106236,'7100126'
+106237,'7100126'
+106238,'7100126'
+106240,'7100126'
+106242,'7100126'
+106245,'7100126'
+106246,'7100126'
+106247,'7100126'
+106248,'7100126'
+106250,'7100126'
+106251,'7100126'
+106253,'7100126'
+106254,'7100126'
+106255,'7100126'
+106229,'7100127'
+106231,'7100127'
+106232,'7100127'
+106234,'7100127'
+106236,'7100127'
+106237,'7100127'
+106238,'7100127'
+106240,'7100127'
+106242,'7100127'
+106245,'7100127'
+106246,'7100127'
+106247,'7100127'
+106248,'7100127'
+106250,'7100127'
+106251,'7100127'
+106253,'7100127'
+106254,'7100127'
+106255,'7100127'
+106229,'7100128'
+106230,'7100128'
+106231,'7100128'
+106232,'7100128'
+106234,'7100128'
+106235,'7100128'
+106236,'7100128'
+106237,'7100128'
+106238,'7100128'
+106239,'7100128'
+106241,'7100128'
+106242,'7100128'
+106245,'7100128'
+106246,'7100128'
+106247,'7100128'
+106248,'7100128'
+106249,'7100128'
+106250,'7100128'
+106251,'7100128'
+106252,'7100128'
+106253,'7100128'
+106254,'7100128'
+106255,'7100128'
+106263,'7100129'
+106264,'7100129'
+106265,'7100129'
+106266,'7100129'
+106267,'7100129'
+106268,'7100129'
+106269,'7100129'
+106271,'7100129'
+106262,'7100129'
+106270,'7100129'
+106263,'7100130'
+106264,'7100130'
+106265,'7100130'
+106266,'7100130'
+106267,'7100130'
+106268,'7100130'
+106269,'7100130'
+106271,'7100130'
+106262,'7100130'
+106270,'7100130'
+106262,'7100131'
+106270,'7100131'
+106263,'7100131'
+106264,'7100131'
+106265,'7100131'
+106266,'7100131'
+106267,'7100131'
+106268,'7100131'
+106269,'7100131'
+106271,'7100131'
+106365,'7100132'
+106376,'7100132'
+106377,'7100132'
+106366,'7100132'
+106375,'7100132'
+106373,'7100133'
+106377,'7100134'
+106377,'7100135'
+106365,'7100136'
+106376,'7100136'
+106366,'7100136'
+106373,'7100137'
+106375,'7100137'
+106373,'7100138'
+106375,'7100139'
+106366,'7100140'
+106375,'7100140'
+106365,'7100140'
+106376,'7100140'
+106377,'7100140'
+106375,'7100141'
+106375,'7100142'
+106365,'7100142'
+106376,'7100142'
+106377,'7100142'
+106366,'7100143'
+106373,'7100143'
+106365,'7100143'
+106376,'7100143'
+106377,'7100143'
+106366,'7100144'
+106373,'7100144'
+106365,'7100144'
+106376,'7100144'
+106366,'7100145'
+106373,'7100145'
+106375,'7100145'
+106365,'7100145'
+106376,'7100145'
+106377,'7100145'
+107161,'7100146'
+107162,'7100146'
+107163,'7100146'
+107164,'7100146'
+107165,'7100146'
+107166,'7100146'
+107167,'7100146'
+107168,'7100146'
+107159,'7100147'
+107160,'7100147'
+107161,'7100148'
+107162,'7100148'
+107163,'7100148'
+107164,'7100148'
+107165,'7100148'
+107166,'7100148'
+107167,'7100148'
+107168,'7100148'
+107159,'7100149'
+107160,'7100149'
+107159,'7100150'
+107161,'7100150'
+107162,'7100150'
+107163,'7100150'
+107164,'7100150'
+107165,'7100150'
+107166,'7100150'
+107167,'7100150'
+107168,'7100150'
+107159,'7100151'
+107161,'7100151'
+107162,'7100151'
+107163,'7100151'
+107164,'7100151'
+107165,'7100151'
+107166,'7100151'
+107167,'7100151'
+107168,'7100151'
+107162,'7100152'
+107165,'7100152'
+107166,'7100152'
+107168,'7100152'
+107161,'7100153'
+107162,'7100153'
+107163,'7100153'
+107164,'7100153'
+107165,'7100153'
+107166,'7100153'
+107167,'7100153'
+107168,'7100153'
+107193,'7100154'
+107194,'7100154'
+107195,'7100154'
+107196,'7100154'
+107197,'7100154'
+107198,'7100154'
+107199,'7100154'
+107200,'7100154'
+107193,'7100155'
+107194,'7100155'
+107195,'7100155'
+107196,'7100155'
+107197,'7100155'
+107198,'7100155'
+107199,'7100155'
+107200,'7100155'
+107193,'7100156'
+107194,'7100156'
+107195,'7100156'
+107196,'7100156'
+107197,'7100156'
+107198,'7100156'
+107199,'7100156'
+107200,'7100156'
+107255,'7100157'
+107253,'7100157'
+107254,'7100158'
+107256,'7100158'
+107254,'7100159'
+107256,'7100159'
+107255,'7100160'
+107253,'7100160'
+107255,'7100161'
+107253,'7100161'
+107253,'7100162'
+107254,'7100162'
+107255,'7100162'
+107256,'7100162'
+107253,'7100163'
+107254,'7100163'
+107255,'7100163'
+107256,'7100163'
+107253,'7100164'
+107254,'7100164'
+107255,'7100164'
+107256,'7100164'
+107257,'7100165'
+107259,'7100165'
+107260,'7100165'
+107264,'7100165'
+107258,'7100166'
+107261,'7100166'
+107257,'7100167'
+107259,'7100167'
+107260,'7100167'
+107264,'7100167'
+107258,'7100168'
+107261,'7100168'
+107257,'7100169'
+107258,'7100169'
+107259,'7100169'
+107260,'7100169'
+107261,'7100169'
+107264,'7100169'
+107257,'7100170'
+107258,'7100170'
+107259,'7100170'
+107260,'7100170'
+107261,'7100170'
+107264,'7100170'
+107470,'7100171'
+107471,'7100171'
+107472,'7100171'
+107473,'7100171'
+107474,'7100171'
+107475,'7100171'
+107476,'7100171'
+107477,'7100171'
+107478,'7100171'
+107470,'7100172'
+107471,'7100172'
+107472,'7100172'
+107473,'7100172'
+107474,'7100172'
+107475,'7100172'
+107476,'7100172'
+107477,'7100172'
+107478,'7100172'
+107470,'7100173'
+107471,'7100173'
+107472,'7100173'
+107473,'7100173'
+107474,'7100173'
+107475,'7100173'
+107476,'7100173'
+107477,'7100173'
+107478,'7100173'
+107484,'7100174'
+107485,'7100174'
+107486,'7100174'
+107487,'7100174'
+107488,'7100174'
+107489,'7100174'
+107490,'7100174'
+107491,'7100174'
+107492,'7100174'
+107484,'7100175'
+107485,'7100175'
+107486,'7100175'
+107487,'7100175'
+107488,'7100175'
+107489,'7100175'
+107490,'7100175'
+107491,'7100175'
+107492,'7100175'
+107484,'7100176'
+107485,'7100176'
+107486,'7100176'
+107487,'7100176'
+107488,'7100176'
+107489,'7100176'
+107490,'7100176'
+107491,'7100176'
+107492,'7100176'
+111891,'7100177'
+111896,'7100177'
+111888,'7100178'
+111889,'7100178'
+111892,'7100178'
+111893,'7100178'
+111894,'7100178'
+111895,'7100178'
+111886,'7100179'
+111887,'7100179'
+111891,'7100180'
+111896,'7100180'
+111888,'7100181'
+111889,'7100181'
+111892,'7100181'
+111893,'7100181'
+111894,'7100181'
+111895,'7100181'
+111888,'7100182'
+111892,'7100182'
+111894,'7100182'
+111895,'7100182'
+111887,'7100183'
+111889,'7100183'
+111893,'7100183'
+111886,'7100184'
+111888,'7100184'
+111892,'7100184'
+111894,'7100184'
+111895,'7100184'
+111886,'7100185'
+111887,'7100185'
+111886,'7100186'
+111888,'7100186'
+111891,'7100186'
+111892,'7100186'
+111894,'7100186'
+111895,'7100186'
+111896,'7100186'
+111886,'7100187'
+111888,'7100187'
+111891,'7100187'
+111892,'7100187'
+111894,'7100187'
+111895,'7100187'
+111896,'7100187'
+111886,'7100188'
+111888,'7100188'
+111889,'7100188'
+111891,'7100188'
+111892,'7100188'
+111893,'7100188'
+111894,'7100188'
+111895,'7100188'
+111896,'7100188'
+111886,'7100189'
+111888,'7100189'
+111889,'7100189'
+111891,'7100189'
+111892,'7100189'
+111893,'7100189'
+111894,'7100189'
+111895,'7100189'
+111896,'7100189'
+111888,'7100190'
+111891,'7100190'
+111892,'7100190'
+111894,'7100190'
+111895,'7100190'
+111896,'7100190'
+111888,'7100191'
+111889,'7100191'
+111891,'7100191'
+111892,'7100191'
+111893,'7100191'
+111894,'7100191'
+111895,'7100191'
+111896,'7100191'
+111888,'7100192'
+111891,'7100192'
+111892,'7100192'
+111894,'7100192'
+111895,'7100192'
+111896,'7100192'
+111928,'7100193'
+111929,'7100193'
+111931,'7100193'
+111932,'7100193'
+111933,'7100193'
+111930,'7100194'
+111928,'7100195'
+111929,'7100195'
+111931,'7100195'
+111932,'7100195'
+111933,'7100195'
+111930,'7100196'
+111930,'7100197'
+111924,'7100198'
+111930,'7100199'
+111924,'7100200'
+111929,'7100201'
+111932,'7100201'
+111933,'7100201'
+111924,'7100202'
+111930,'7100202'
+111928,'7100202'
+111929,'7100202'
+111931,'7100202'
+111932,'7100202'
+111933,'7100202'
+111929,'7100203'
+111932,'7100203'
+111933,'7100203'
+111924,'7100204'
+111930,'7100204'
+111928,'7100204'
+111929,'7100204'
+111931,'7100204'
+111932,'7100204'
+111933,'7100204'
+111930,'7100205'
+111928,'7100205'
+111931,'7100205'
+111930,'7100206'
+111928,'7100206'
+111929,'7100206'
+111931,'7100206'
+111932,'7100206'
+111933,'7100206'
+111939,'7100207'
+111937,'7100208'
+111941,'7100208'
+111937,'7100209'
+111941,'7100209'
+111939,'7100210'
+111939,'7100211'
+111937,'7100212'
+111939,'7100212'
+111941,'7100212'
+111937,'7100213'
+111939,'7100213'
+111941,'7100213'
+111937,'7100214'
+111941,'7100214'
+111937,'7100215'
+111939,'7100215'
+111941,'7100215'
+112029,'7100216'
+112032,'7100216'
+112034,'7100216'
+112035,'7100216'
+112036,'7100216'
+112037,'7100216'
+112038,'7100216'
+112039,'7100216'
+112041,'7100216'
+112042,'7100216'
+112043,'7100216'
+112044,'7100216'
+112045,'7100216'
+112047,'7100216'
+112048,'7100216'
+112049,'7100216'
+112050,'7100216'
+112033,'7100217'
+112040,'7100217'
+112046,'7100217'
+112028,'7100218'
+112052,'7100218'
+112030,'7100219'
+112031,'7100219'
+112051,'7100219'
+112029,'7100220'
+112032,'7100220'
+112034,'7100220'
+112035,'7100220'
+112036,'7100220'
+112037,'7100220'
+112038,'7100220'
+112039,'7100220'
+112041,'7100220'
+112042,'7100220'
+112043,'7100220'
+112044,'7100220'
+112045,'7100220'
+112047,'7100220'
+112048,'7100220'
+112049,'7100220'
+112050,'7100220'
+112033,'7100221'
+112040,'7100221'
+112046,'7100221'
+112028,'7100222'
+112052,'7100222'
+112030,'7100223'
+112031,'7100223'
+112051,'7100223'
+112029,'7100224'
+112030,'7100224'
+112033,'7100224'
+112034,'7100224'
+112036,'7100224'
+112038,'7100224'
+112039,'7100224'
+112040,'7100224'
+112041,'7100224'
+112043,'7100224'
+112044,'7100224'
+112046,'7100224'
+112047,'7100224'
+112049,'7100224'
+112050,'7100224'
+112051,'7100224'
+112029,'7100225'
+112030,'7100225'
+112031,'7100225'
+112033,'7100225'
+112034,'7100225'
+112036,'7100225'
+112039,'7100225'
+112040,'7100225'
+112041,'7100225'
+112043,'7100225'
+112044,'7100225'
+112046,'7100225'
+112047,'7100225'
+112049,'7100225'
+112050,'7100225'
+112051,'7100225'
+112028,'7100226'
+112029,'7100226'
+112032,'7100226'
+112033,'7100226'
+112034,'7100226'
+112035,'7100226'
+112037,'7100226'
+112038,'7100226'
+112039,'7100226'
+112040,'7100226'
+112042,'7100226'
+112043,'7100226'
+112045,'7100226'
+112046,'7100226'
+112047,'7100226'
+112048,'7100226'
+112049,'7100226'
+112052,'7100226'
+112029,'7100227'
+112032,'7100227'
+112033,'7100227'
+112034,'7100227'
+112035,'7100227'
+112036,'7100227'
+112037,'7100227'
+112038,'7100227'
+112039,'7100227'
+112040,'7100227'
+112041,'7100227'
+112042,'7100227'
+112043,'7100227'
+112044,'7100227'
+112045,'7100227'
+112046,'7100227'
+112047,'7100227'
+112048,'7100227'
+112049,'7100227'
+112050,'7100227'
+112351,'7100228'
+112352,'7100228'
+112353,'7100228'
+112354,'7100228'
+112351,'7100229'
+112352,'7100229'
+112353,'7100229'
+112354,'7100229'
+112351,'7100230'
+112352,'7100230'
+112353,'7100230'
+112354,'7100230'
+112351,'7100231'
+112352,'7100231'
+112353,'7100231'
+112354,'7100231'
+112351,'7100232'
+112352,'7100232'
+112353,'7100232'
+112354,'7100232'
+112415,'7100233'
+112416,'7100233'
+112417,'7100233'
+112418,'7100233'
+112415,'7100234'
+112416,'7100234'
+112417,'7100234'
+112418,'7100234'
+112413,'7100235'
+112413,'7100236'
+112416,'7100237'
+112418,'7100237'
+112416,'7100238'
+112418,'7100238'
+112413,'7100239'
+112415,'7100239'
+112416,'7100239'
+112417,'7100239'
+112418,'7100239'
+112413,'7100240'
+112415,'7100240'
+112416,'7100240'
+112417,'7100240'
+112418,'7100240'
+112415,'7100241'
+112416,'7100241'
+112417,'7100241'
+112418,'7100241'
+112415,'7100242'
+112417,'7100242'
+112440,'7100243'
+112441,'7100243'
+112442,'7100243'
+112440,'7100244'
+112441,'7100244'
+112442,'7100244'
+112440,'7100245'
+112441,'7100245'
+112442,'7100245'
+112440,'7100246'
+112441,'7100246'
+112442,'7100246'
+112513,'7100247'
+112514,'7100247'
+112515,'7100247'
+112516,'7100247'
+112518,'7100247'
+112519,'7100247'
+112520,'7100247'
+112524,'7100247'
+112525,'7100247'
+112526,'7100247'
+112527,'7100247'
+112513,'7100248'
+112514,'7100248'
+112515,'7100248'
+112516,'7100248'
+112518,'7100248'
+112519,'7100248'
+112520,'7100248'
+112524,'7100248'
+112525,'7100248'
+112526,'7100248'
+112527,'7100249'
+112514,'7100250'
+112515,'7100250'
+112516,'7100250'
+112518,'7100250'
+112519,'7100250'
+112520,'7100250'
+112524,'7100250'
+112525,'7100250'
+112526,'7100250'
+112527,'7100250'
+112514,'7100251'
+112515,'7100251'
+112516,'7100251'
+112519,'7100251'
+112520,'7100251'
+112524,'7100251'
+112525,'7100251'
+112526,'7100251'
+112527,'7100251'
+112513,'7100252'
+112515,'7100252'
+112516,'7100252'
+112520,'7100252'
+112524,'7100252'
+112526,'7100252'
+112513,'7100253'
+112514,'7100253'
+112515,'7100253'
+112516,'7100253'
+112518,'7100253'
+112519,'7100253'
+112520,'7100253'
+112524,'7100253'
+112525,'7100253'
+112526,'7100253'
+112783,'7100254'
+112789,'7100254'
+112798,'7100254'
+112766,'7100255'
+112772,'7100255'
+112773,'7100255'
+112777,'7100255'
+112784,'7100255'
+112790,'7100255'
+112793,'7100255'
+112794,'7100255'
+112802,'7100255'
+112805,'7100255'
+112797,'7100256'
+112771,'7100257'
+112804,'7100257'
+112807,'7100257'
+112806,'7100258'
+112808,'7100258'
+112783,'7100259'
+112789,'7100259'
+112798,'7100259'
+112766,'7100260'
+112772,'7100260'
+112773,'7100260'
+112777,'7100260'
+112784,'7100260'
+112790,'7100260'
+112793,'7100260'
+112794,'7100260'
+112802,'7100260'
+112805,'7100260'
+112771,'7100261'
+112804,'7100261'
+112807,'7100261'
+112806,'7100262'
+112808,'7100262'
+112766,'7100263'
+112772,'7100263'
+112773,'7100263'
+112777,'7100263'
+112784,'7100263'
+112790,'7100263'
+112793,'7100263'
+112802,'7100263'
+112805,'7100263'
+112806,'7100263'
+112808,'7100263'
+112766,'7100264'
+112772,'7100264'
+112773,'7100264'
+112777,'7100264'
+112784,'7100264'
+112790,'7100264'
+112793,'7100264'
+112794,'7100264'
+112802,'7100264'
+112805,'7100264'
+112806,'7100264'
+112808,'7100264'
+112766,'7100265'
+112772,'7100265'
+112773,'7100265'
+112777,'7100265'
+112784,'7100265'
+112790,'7100265'
+112793,'7100265'
+112794,'7100265'
+112797,'7100265'
+112802,'7100265'
+112805,'7100265'
+112783,'7100266'
+112789,'7100266'
+112798,'7100266'
+112766,'7100267'
+112772,'7100267'
+112773,'7100267'
+112777,'7100267'
+112784,'7100267'
+112790,'7100267'
+112793,'7100267'
+112794,'7100267'
+112802,'7100267'
+112805,'7100267'
+112864,'7100268'
+112869,'7100268'
+112872,'7100268'
+112874,'7100268'
+112866,'7100269'
+112867,'7100269'
+112870,'7100269'
+112873,'7100269'
+112864,'7100270'
+112869,'7100270'
+112872,'7100270'
+112874,'7100270'
+112866,'7100271'
+112867,'7100271'
+112870,'7100271'
+112873,'7100271'
+112866,'7100272'
+112867,'7100272'
+112870,'7100272'
+112873,'7100272'
+112864,'7100273'
+112869,'7100273'
+112872,'7100273'
+112874,'7100273'
+112866,'7100274'
+112867,'7100274'
+112870,'7100274'
+112873,'7100274'
+112903,'7100275'
+112905,'7100275'
+112908,'7100275'
+112909,'7100275'
+112904,'7100276'
+112907,'7100276'
+112903,'7100277'
+112905,'7100277'
+112908,'7100277'
+112909,'7100277'
+112904,'7100278'
+112907,'7100278'
+112903,'7100279'
+112904,'7100279'
+112905,'7100279'
+112907,'7100279'
+112908,'7100279'
+112909,'7100279'
+112903,'7100280'
+112904,'7100280'
+112905,'7100280'
+112907,'7100280'
+112908,'7100280'
+112909,'7100280'
+112989,'7100281'
+112990,'7100281'
+112991,'7100281'
+112993,'7100281'
+112994,'7100281'
+112995,'7100281'
+112996,'7100281'
+112997,'7100281'
+112998,'7100281'
+112999,'7100281'
+113001,'7100281'
+113002,'7100281'
+113004,'7100281'
+113005,'7100281'
+113006,'7100281'
+113008,'7100281'
+113010,'7100281'
+112992,'7100282'
+113000,'7100282'
+113003,'7100282'
+113009,'7100282'
+113007,'7100283'
+113011,'7100283'
+113012,'7100284'
+113013,'7100284'
+112989,'7100285'
+112990,'7100285'
+112991,'7100285'
+112993,'7100285'
+112994,'7100285'
+112995,'7100285'
+112996,'7100285'
+112997,'7100285'
+112998,'7100285'
+112999,'7100285'
+113001,'7100285'
+113002,'7100285'
+113004,'7100285'
+113005,'7100285'
+113006,'7100285'
+113008,'7100285'
+113010,'7100285'
+112992,'7100286'
+113000,'7100286'
+113003,'7100286'
+113009,'7100286'
+113007,'7100287'
+113011,'7100287'
+113012,'7100288'
+113013,'7100288'
+112989,'7100289'
+112991,'7100289'
+112992,'7100289'
+112994,'7100289'
+112996,'7100289'
+112997,'7100289'
+112998,'7100289'
+113000,'7100289'
+113001,'7100289'
+113003,'7100289'
+113004,'7100289'
+113006,'7100289'
+113008,'7100289'
+113009,'7100289'
+113010,'7100289'
+113012,'7100289'
+113013,'7100289'
+112989,'7100290'
+112991,'7100290'
+112992,'7100290'
+112994,'7100290'
+112997,'7100290'
+112998,'7100290'
+113000,'7100290'
+113001,'7100290'
+113003,'7100290'
+113004,'7100290'
+113006,'7100290'
+113008,'7100290'
+113009,'7100290'
+113010,'7100290'
+113012,'7100290'
+113013,'7100290'
+112990,'7100291'
+112991,'7100291'
+112992,'7100291'
+112993,'7100291'
+112994,'7100291'
+112995,'7100291'
+112998,'7100291'
+112999,'7100291'
+113000,'7100291'
+113001,'7100291'
+113002,'7100291'
+113003,'7100291'
+113004,'7100291'
+113005,'7100291'
+113007,'7100291'
+113008,'7100291'
+113009,'7100291'
+113011,'7100291'
+112989,'7100292'
+112990,'7100292'
+112991,'7100292'
+112992,'7100292'
+112993,'7100292'
+112994,'7100292'
+112995,'7100292'
+112996,'7100292'
+112997,'7100292'
+112998,'7100292'
+112999,'7100292'
+113000,'7100292'
+113001,'7100292'
+113002,'7100292'
+113003,'7100292'
+113004,'7100292'
+113005,'7100292'
+113006,'7100292'
+113008,'7100292'
+113009,'7100292'
+113010,'7100292'
+113498,'7100293'
+113500,'7100293'
+113499,'7100294'
+113501,'7100295'
+113498,'7100296'
+113500,'7100296'
+113499,'7100297'
+113501,'7100298'
+113499,'7100299'
+113499,'7100300'
+113499,'7100301'
+113498,'7100301'
+113500,'7100301'
+113576,'7100302'
+113578,'7100302'
+113581,'7100302'
+113582,'7100302'
+113577,'7100303'
+113579,'7100303'
+113583,'7100304'
+113576,'7100305'
+113578,'7100305'
+113581,'7100305'
+113582,'7100305'
+113577,'7100306'
+113579,'7100306'
+113583,'7100307'
+113576,'7100308'
+113577,'7100308'
+113578,'7100308'
+113579,'7100308'
+113581,'7100308'
+113582,'7100308'
+113577,'7100309'
+113578,'7100309'
+113579,'7100309'
+113581,'7100309'
+113582,'7100309'
+113576,'7100309'
+113595,'7100310'
+113596,'7100310'
+113597,'7100310'
+113599,'7100310'
+113600,'7100310'
+113602,'7100310'
+113595,'7100311'
+113599,'7100311'
+113602,'7100311'
+113595,'7100312'
+113599,'7100312'
+113602,'7100312'
+113596,'7100313'
+113597,'7100313'
+113600,'7100313'
+113595,'7100314'
+113596,'7100314'
+113597,'7100314'
+113599,'7100314'
+113600,'7100314'
+113602,'7100314'
+113595,'7100315'
+113596,'7100315'
+113597,'7100315'
+113599,'7100315'
+113600,'7100315'
+113602,'7100315'
+113706,'7100316'
+113707,'7100316'
+113709,'7100316'
+113711,'7100316'
+113716,'7100316'
+113717,'7100316'
+113718,'7100316'
+113710,'7100316'
+113713,'7100316'
+113705,'7100317'
+113712,'7100317'
+113715,'7100317'
+113719,'7100317'
+113720,'7100318'
+113721,'7100319'
+113706,'7100320'
+113707,'7100320'
+113709,'7100320'
+113711,'7100320'
+113716,'7100320'
+113717,'7100320'
+113718,'7100320'
+113710,'7100320'
+113713,'7100320'
+113705,'7100321'
+113712,'7100321'
+113715,'7100321'
+113719,'7100321'
+113720,'7100322'
+113721,'7100323'
+113705,'7100324'
+113707,'7100324'
+113712,'7100324'
+113715,'7100324'
+113719,'7100324'
+113721,'7100324'
+113710,'7100324'
+113713,'7100324'
+113705,'7100325'
+113707,'7100325'
+113712,'7100325'
+113715,'7100325'
+113719,'7100325'
+113721,'7100325'
+113713,'7100325'
+113705,'7100326'
+113706,'7100326'
+113707,'7100326'
+113709,'7100326'
+113711,'7100326'
+113712,'7100326'
+113715,'7100326'
+113716,'7100326'
+113717,'7100326'
+113718,'7100326'
+113719,'7100326'
+113720,'7100326'
+113713,'7100326'
+113705,'7100327'
+113706,'7100327'
+113707,'7100327'
+113709,'7100327'
+113711,'7100327'
+113712,'7100327'
+113715,'7100327'
+113716,'7100327'
+113717,'7100327'
+113718,'7100327'
+113719,'7100327'
+113710,'7100327'
+113713,'7100327'
+133423,'7100328'
+133423,'7100329'
+133423,'7100330'
+133423,'7100331'
+133423,'7100332'
+133430,'7100333'
+133431,'7100333'
+133432,'7100333'
+133433,'7100333'
+133430,'7100334'
+133431,'7100334'
+133432,'7100334'
+133433,'7100334'
+133430,'7100335'
+133431,'7100335'
+133432,'7100335'
+133433,'7100335'
+133430,'7100336'
+133431,'7100336'
+133432,'7100336'
+133433,'7100336'
+133430,'7100337'
+133431,'7100337'
+133432,'7100337'
+133433,'7100337'
+133435,'7100338'
+133436,'7100338'
+133434,'7100339'
+133435,'7100340'
+133436,'7100340'
+133434,'7100341'
+133435,'7100342'
+133436,'7100342'
+133516,'7100343'
+133516,'7100344'
+133516,'7100345'
+133516,'7100346'
+133568,'7100347'
+133569,'7100347'
+133567,'7100348'
+133568,'7100349'
+133569,'7100349'
+137225,'7100350'
+137231,'7100350'
+137237,'7100350'
+137223,'7100351'
+137224,'7100351'
+137226,'7100351'
+137227,'7100351'
+137228,'7100351'
+137229,'7100351'
+137230,'7100351'
+137232,'7100351'
+137233,'7100351'
+137234,'7100351'
+137235,'7100351'
+137236,'7100351'
+137238,'7100351'
+137221,'7100352'
+137222,'7100352'
+137224,'7100353'
+137228,'7100353'
+137230,'7100353'
+137233,'7100353'
+137235,'7100353'
+137238,'7100353'
+137223,'7100354'
+137226,'7100354'
+137227,'7100354'
+137229,'7100354'
+137232,'7100354'
+137234,'7100354'
+137236,'7100354'
+137225,'7100355'
+137231,'7100355'
+137237,'7100355'
+137221,'7100356'
+137222,'7100356'
+137222,'7100357'
+137223,'7100357'
+137226,'7100357'
+137227,'7100357'
+137229,'7100357'
+137232,'7100357'
+137234,'7100357'
+137236,'7100357'
+137221,'7100358'
+137223,'7100358'
+137224,'7100358'
+137225,'7100358'
+137226,'7100358'
+137227,'7100358'
+137228,'7100358'
+137229,'7100358'
+137230,'7100358'
+137231,'7100358'
+137232,'7100358'
+137233,'7100358'
+137234,'7100358'
+137235,'7100358'
+137236,'7100358'
+137237,'7100358'
+137238,'7100358'
+137222,'7100359'
+137223,'7100359'
+137226,'7100359'
+137227,'7100359'
+137229,'7100359'
+137232,'7100359'
+137234,'7100359'
+137236,'7100359'
+137221,'7100360'
+137223,'7100360'
+137224,'7100360'
+137225,'7100360'
+137226,'7100360'
+137227,'7100360'
+137228,'7100360'
+137229,'7100360'
+137230,'7100360'
+137231,'7100360'
+137232,'7100360'
+137233,'7100360'
+137234,'7100360'
+137235,'7100360'
+137236,'7100360'
+137237,'7100360'
+137238,'7100360'
+137224,'7100361'
+137225,'7100361'
+137228,'7100361'
+137230,'7100361'
+137231,'7100361'
+137233,'7100361'
+137235,'7100361'
+137237,'7100361'
+137238,'7100361'
+137223,'7100362'
+137224,'7100362'
+137225,'7100362'
+137226,'7100362'
+137227,'7100362'
+137228,'7100362'
+137229,'7100362'
+137230,'7100362'
+137231,'7100362'
+137232,'7100362'
+137233,'7100362'
+137234,'7100362'
+137235,'7100362'
+137236,'7100362'
+137237,'7100362'
+137238,'7100362'
+137315,'7100363'
+137316,'7100363'
+137317,'7100363'
+137318,'7100363'
+137319,'7100363'
+137320,'7100363'
+137321,'7100363'
+137322,'7100363'
+137323,'7100363'
+137324,'7100363'
+137326,'7100363'
+137327,'7100363'
+137328,'7100363'
+137329,'7100363'
+137330,'7100363'
+137331,'7100363'
+137332,'7100363'
+137333,'7100363'
+137334,'7100363'
+137335,'7100363'
+137336,'7100363'
+137337,'7100363'
+137338,'7100363'
+137339,'7100364'
+137315,'7100365'
+137319,'7100365'
+137323,'7100365'
+137331,'7100365'
+137315,'7100366'
+137319,'7100366'
+137323,'7100366'
+137331,'7100366'
+137330,'7100367'
+137315,'7100368'
+137319,'7100368'
+137323,'7100368'
+137331,'7100368'
+137316,'7100369'
+137317,'7100369'
+137318,'7100369'
+137320,'7100369'
+137321,'7100369'
+137322,'7100369'
+137324,'7100369'
+137326,'7100369'
+137327,'7100369'
+137328,'7100369'
+137329,'7100369'
+137332,'7100369'
+137333,'7100369'
+137334,'7100369'
+137335,'7100369'
+137336,'7100369'
+137337,'7100369'
+137338,'7100369'
+137315,'7100370'
+137316,'7100370'
+137318,'7100370'
+137319,'7100370'
+137320,'7100370'
+137323,'7100370'
+137324,'7100370'
+137326,'7100370'
+137327,'7100370'
+137329,'7100370'
+137330,'7100370'
+137331,'7100370'
+137333,'7100370'
+137334,'7100370'
+137335,'7100370'
+137336,'7100370'
+137338,'7100370'
+137315,'7100371'
+137319,'7100371'
+137323,'7100371'
+137331,'7100371'
+137339,'7100372'
+137316,'7100373'
+137318,'7100373'
+137320,'7100373'
+137324,'7100373'
+137326,'7100373'
+137327,'7100373'
+137329,'7100373'
+137333,'7100373'
+137334,'7100373'
+137335,'7100373'
+137336,'7100373'
+137338,'7100373'
+137317,'7100374'
+137321,'7100374'
+137322,'7100374'
+137328,'7100374'
+137332,'7100374'
+137337,'7100374'
+137315,'7100375'
+137316,'7100375'
+137317,'7100375'
+137318,'7100375'
+137319,'7100375'
+137320,'7100375'
+137321,'7100375'
+137322,'7100375'
+137323,'7100375'
+137324,'7100375'
+137326,'7100375'
+137327,'7100375'
+137328,'7100375'
+137329,'7100375'
+137331,'7100375'
+137332,'7100375'
+137333,'7100375'
+137334,'7100375'
+137335,'7100375'
+137336,'7100375'
+137337,'7100375'
+137338,'7100375'
+137339,'7100375'
+137315,'7100376'
+137316,'7100376'
+137318,'7100376'
+137319,'7100376'
+137320,'7100376'
+137323,'7100376'
+137324,'7100376'
+137326,'7100376'
+137327,'7100376'
+137329,'7100376'
+137330,'7100376'
+137331,'7100376'
+137333,'7100376'
+137334,'7100376'
+137335,'7100376'
+137336,'7100376'
+137338,'7100376'
+137315,'7100377'
+137316,'7100377'
+137318,'7100377'
+137319,'7100377'
+137320,'7100377'
+137323,'7100377'
+137324,'7100377'
+137326,'7100377'
+137327,'7100377'
+137329,'7100377'
+137330,'7100377'
+137331,'7100377'
+137333,'7100377'
+137334,'7100377'
+137335,'7100377'
+137336,'7100377'
+137338,'7100377'
+137315,'7100378'
+137316,'7100378'
+137317,'7100378'
+137318,'7100378'
+137319,'7100378'
+137320,'7100378'
+137321,'7100378'
+137322,'7100378'
+137323,'7100378'
+137324,'7100378'
+137326,'7100378'
+137327,'7100378'
+137328,'7100378'
+137329,'7100378'
+137331,'7100378'
+137332,'7100378'
+137333,'7100378'
+137334,'7100378'
+137335,'7100378'
+137336,'7100378'
+137337,'7100378'
+137338,'7100378'
+137353,'7100379'
+137354,'7100379'
+137355,'7100379'
+137356,'7100379'
+137357,'7100379'
+137358,'7100379'
+137359,'7100379'
+137360,'7100379'
+137361,'7100379'
+137353,'7100380'
+137354,'7100380'
+137355,'7100380'
+137356,'7100380'
+137357,'7100380'
+137358,'7100380'
+137359,'7100380'
+137360,'7100380'
+137361,'7100380'
+137353,'7100381'
+137354,'7100381'
+137355,'7100381'
+137356,'7100381'
+137357,'7100381'
+137358,'7100381'
+137359,'7100381'
+137360,'7100381'
+137361,'7100381'
+137407,'7100382'
+137408,'7100382'
+137412,'7100382'
+137413,'7100382'
+137410,'7100383'
+137407,'7100384'
+137408,'7100384'
+137412,'7100384'
+137413,'7100384'
+137410,'7100385'
+137408,'7100386'
+137413,'7100386'
+137408,'7100387'
+137413,'7100387'
+137407,'7100388'
+137408,'7100388'
+137412,'7100388'
+137413,'7100388'
+137410,'7100388'
+137407,'7100389'
+137408,'7100389'
+137412,'7100389'
+137413,'7100389'
+137410,'7100389'
+137407,'7100390'
+137408,'7100390'
+137412,'7100390'
+137413,'7100390'
+137410,'7100390'
+137407,'7100391'
+137412,'7100391'
+137410,'7100391'
+137414,'7100392'
+137417,'7100392'
+137420,'7100392'
+137422,'7100392'
+137415,'7100393'
+137419,'7100393'
+137423,'7100393'
+137414,'7100394'
+137417,'7100394'
+137420,'7100394'
+137422,'7100394'
+137415,'7100395'
+137419,'7100395'
+137423,'7100395'
+137415,'7100396'
+137419,'7100396'
+137423,'7100396'
+137414,'7100397'
+137417,'7100397'
+137420,'7100397'
+137422,'7100397'
+137415,'7100398'
+137419,'7100398'
+137423,'7100398'
+137415,'7100399'
+137419,'7100399'
+137423,'7100399'
+137685,'7100400'
+137685,'7100401'
+137685,'7100402'
+137685,'7100403'
+137732,'7100404'
+137733,'7100404'
+137734,'7100404'
+137735,'7100404'
+137736,'7100404'
+137737,'7100404'
+137738,'7100404'
+137739,'7100404'
+137740,'7100404'
+137732,'7100405'
+137733,'7100405'
+137734,'7100405'
+137735,'7100405'
+137736,'7100405'
+137737,'7100405'
+137738,'7100405'
+137739,'7100405'
+137740,'7100405'
+137732,'7100406'
+137733,'7100406'
+137734,'7100406'
+137735,'7100406'
+137736,'7100406'
+137737,'7100406'
+137738,'7100406'
+137739,'7100406'
+137740,'7100406'
+137814,'7100407'
+137811,'7100408'
+137817,'7100408'
+137811,'7100409'
+137817,'7100409'
+137814,'7100410'
+137814,'7100411'
+137811,'7100412'
+137817,'7100412'
+137811,'7100413'
+137817,'7100413'
+137811,'7100414'
+137817,'7100414'
+137811,'7100415'
+137817,'7100415'
+137811,'7100416'
+137817,'7100416'
+137811,'7100417'
+137817,'7100417'
+137814,'7100418'
+138818,'7100419'
+138820,'7100419'
+138821,'7100419'
+138822,'7100419'
+138823,'7100419'
+138824,'7100419'
+138827,'7100419'
+138828,'7100419'
+138829,'7100419'
+138832,'7100419'
+138817,'7100420'
+138830,'7100420'
+138831,'7100420'
+138818,'7100421'
+138819,'7100421'
+138820,'7100421'
+138821,'7100421'
+138822,'7100421'
+138823,'7100421'
+138824,'7100421'
+138825,'7100421'
+138827,'7100421'
+138828,'7100421'
+138829,'7100421'
+138832,'7100421'
+138817,'7100422'
+138830,'7100422'
+138831,'7100422'
+138818,'7100423'
+138819,'7100423'
+138822,'7100423'
+138825,'7100423'
+138829,'7100423'
+138817,'7100424'
+138818,'7100424'
+138819,'7100424'
+138820,'7100424'
+138821,'7100424'
+138822,'7100424'
+138823,'7100424'
+138824,'7100424'
+138825,'7100424'
+138827,'7100424'
+138828,'7100424'
+138829,'7100424'
+138830,'7100424'
+138832,'7100424'
+138818,'7100425'
+138819,'7100425'
+138822,'7100425'
+138825,'7100425'
+138829,'7100425'
+138817,'7100426'
+138818,'7100426'
+138819,'7100426'
+138820,'7100426'
+138821,'7100426'
+138822,'7100426'
+138823,'7100426'
+138824,'7100426'
+138825,'7100426'
+138827,'7100426'
+138828,'7100426'
+138829,'7100426'
+138831,'7100426'
+138832,'7100426'
+138820,'7100427'
+138821,'7100427'
+138823,'7100427'
+138824,'7100427'
+138827,'7100427'
+138828,'7100427'
+138832,'7100427'
+138818,'7100428'
+138819,'7100428'
+138820,'7100428'
+138821,'7100428'
+138822,'7100428'
+138823,'7100428'
+138824,'7100428'
+138825,'7100428'
+138827,'7100428'
+138828,'7100428'
+138829,'7100428'
+138832,'7100428'
+138860,'7100429'
+138861,'7100429'
+138862,'7100429'
+138863,'7100429'
+138864,'7100429'
+138865,'7100429'
+138867,'7100429'
+138868,'7100429'
+138866,'7100429'
+138860,'7100430'
+138861,'7100430'
+138862,'7100430'
+138863,'7100430'
+138864,'7100430'
+138865,'7100430'
+138867,'7100430'
+138868,'7100430'
+138866,'7100430'
+138860,'7100431'
+138861,'7100431'
+138862,'7100431'
+138863,'7100431'
+138864,'7100431'
+138865,'7100431'
+138867,'7100431'
+138868,'7100431'
+138866,'7100431'
+138878,'7100432'
+138879,'7100432'
+138880,'7100432'
+138881,'7100432'
+138882,'7100432'
+138883,'7100432'
+138884,'7100432'
+138878,'7100433'
+138879,'7100433'
+138880,'7100433'
+138881,'7100433'
+138882,'7100433'
+138883,'7100433'
+138884,'7100433'
+138878,'7100434'
+138879,'7100434'
+138880,'7100434'
+138881,'7100434'
+138882,'7100434'
+138883,'7100434'
+138884,'7100434'
+138963,'7100435'
+138964,'7100435'
+138966,'7100435'
+138965,'7100436'
+138965,'7100437'
+138963,'7100438'
+138964,'7100438'
+138966,'7100438'
+138963,'7100439'
+138964,'7100439'
+138966,'7100439'
+138965,'7100440'
+138965,'7100441'
+138963,'7100442'
+138964,'7100442'
+138966,'7100442'
+138970,'7100443'
+138971,'7100443'
+138973,'7100443'
+138974,'7100443'
+138976,'7100443'
+138977,'7100443'
+138970,'7100444'
+138973,'7100444'
+138976,'7100444'
+138970,'7100445'
+138973,'7100445'
+138976,'7100445'
+138971,'7100446'
+138974,'7100446'
+138977,'7100446'
+138970,'7100447'
+138971,'7100447'
+138973,'7100447'
+138974,'7100447'
+138976,'7100447'
+138977,'7100447'
+138970,'7100448'
+138971,'7100448'
+138973,'7100448'
+138974,'7100448'
+138976,'7100448'
+138977,'7100448'
+138970,'7100449'
+138971,'7100449'
+138973,'7100449'
+138974,'7100449'
+138976,'7100449'
+138977,'7100449'
+138970,'7100450'
+138973,'7100450'
+138976,'7100450'
+138970,'7100451'
+138971,'7100451'
+138973,'7100451'
+138974,'7100451'
+138976,'7100451'
+138977,'7100451'
+139264,'7100452'
+139265,'7100452'
+139266,'7100452'
+139267,'7100452'
+139268,'7100452'
+139269,'7100452'
+139270,'7100452'
+139271,'7100452'
+139272,'7100452'
+139273,'7100452'
+139264,'7100453'
+139265,'7100453'
+139266,'7100453'
+139267,'7100453'
+139268,'7100453'
+139269,'7100453'
+139270,'7100453'
+139271,'7100453'
+139272,'7100453'
+139273,'7100453'
+139264,'7100454'
+139265,'7100454'
+139266,'7100454'
+139267,'7100454'
+139268,'7100454'
+139269,'7100454'
+139270,'7100454'
+139271,'7100454'
+139272,'7100454'
+139273,'7100454'
+139353,'7100455'
+139355,'7100455'
+139356,'7100455'
+139357,'7100455'
+139353,'7100456'
+139355,'7100456'
+139356,'7100456'
+139357,'7100456'
+139353,'7100457'
+139355,'7100457'
+139356,'7100457'
+139357,'7100457'
+139353,'7100458'
+139355,'7100458'
+139356,'7100458'
+139357,'7100458'
+139353,'7100459'
+139355,'7100459'
+139356,'7100459'
+139357,'7100459'
+144060,'7100460'
+144061,'7100460'
+144062,'7100460'
+144063,'7100460'
+144065,'7100460'
+144066,'7100460'
+144059,'7100461'
+144067,'7100462'
+144069,'7100462'
+144060,'7100463'
+144061,'7100463'
+144062,'7100463'
+144063,'7100463'
+144065,'7100463'
+144066,'7100463'
+144059,'7100464'
+144059,'7100465'
+144069,'7100466'
+144067,'7100467'
+144059,'7100468'
+144060,'7100469'
+144061,'7100469'
+144062,'7100469'
+144063,'7100469'
+144065,'7100469'
+144066,'7100469'
+144067,'7100469'
+144060,'7100470'
+144061,'7100470'
+144063,'7100470'
+144065,'7100470'
+144066,'7100470'
+144067,'7100470'
+144061,'7100471'
+144065,'7100471'
+144069,'7100471'
+144060,'7100472'
+144061,'7100472'
+144062,'7100472'
+144063,'7100472'
+144065,'7100472'
+144066,'7100472'
+144067,'7100472'
+144060,'7100473'
+144062,'7100473'
+144063,'7100473'
+144066,'7100473'
+144059,'7100474'
+144060,'7100475'
+144061,'7100475'
+144062,'7100475'
+144063,'7100475'
+144065,'7100475'
+144066,'7100475'
+144093,'7100476'
+144092,'7100477'
+144095,'7100477'
+144089,'7100478'
+144090,'7100478'
+144094,'7100478'
+144088,'7100478'
+144090,'7100479'
+144090,'7100480'
+144089,'7100481'
+144094,'7100481'
+144092,'7100482'
+144095,'7100482'
+144088,'7100483'
+144093,'7100484'
+144087,'7100485'
+144092,'7100486'
+144095,'7100486'
+144093,'7100487'
+144088,'7100488'
+144089,'7100489'
+144090,'7100489'
+144094,'7100489'
+144088,'7100489'
+144092,'7100489'
+144093,'7100489'
+144095,'7100489'
+144088,'7100490'
+144089,'7100491'
+144090,'7100491'
+144094,'7100491'
+144088,'7100491'
+144092,'7100491'
+144093,'7100491'
+144095,'7100491'
+144089,'7100492'
+144090,'7100492'
+144094,'7100492'
+144087,'7100492'
+144092,'7100492'
+144093,'7100492'
+144095,'7100492'
+144089,'7100493'
+144094,'7100493'
+144087,'7100493'
+144092,'7100493'
+144095,'7100493'
+144089,'7100494'
+144090,'7100494'
+144094,'7100494'
+144088,'7100494'
+144092,'7100494'
+144093,'7100494'
+144095,'7100494'
+144110,'7100495'
+144110,'7100496'
+144110,'7100497'
+144110,'7100498'
+144110,'7100499'
+144143,'7100500'
+144144,'7100500'
+144145,'7100500'
+144146,'7100500'
+144147,'7100500'
+144148,'7100500'
+144149,'7100500'
+144150,'7100500'
+144151,'7100500'
+144152,'7100500'
+144153,'7100500'
+144143,'7100501'
+144144,'7100501'
+144145,'7100501'
+144146,'7100501'
+144147,'7100501'
+144148,'7100501'
+144149,'7100501'
+144150,'7100501'
+144151,'7100501'
+144152,'7100501'
+144153,'7100501'
+144143,'7100502'
+144144,'7100502'
+144145,'7100502'
+144147,'7100502'
+144149,'7100502'
+144150,'7100502'
+144151,'7100502'
+144152,'7100502'
+144153,'7100502'
+144143,'7100503'
+144144,'7100503'
+144146,'7100503'
+144147,'7100503'
+144149,'7100503'
+144150,'7100503'
+144152,'7100503'
+144153,'7100503'
+144143,'7100504'
+144144,'7100504'
+144145,'7100504'
+144146,'7100504'
+144147,'7100504'
+144148,'7100504'
+144149,'7100504'
+144150,'7100504'
+144151,'7100504'
+144152,'7100504'
+144153,'7100504'
+144157,'7100505'
+144159,'7100505'
+144162,'7100505'
+144164,'7100505'
+144165,'7100505'
+144166,'7100505'
+144168,'7100505'
+144160,'7100505'
+144161,'7100505'
+144158,'7100506'
+144163,'7100506'
+144167,'7100506'
+144169,'7100506'
+144156,'7100507'
+144155,'7100508'
+144157,'7100509'
+144159,'7100509'
+144162,'7100509'
+144164,'7100509'
+144165,'7100509'
+144166,'7100509'
+144168,'7100509'
+144160,'7100509'
+144161,'7100509'
+144158,'7100510'
+144163,'7100510'
+144167,'7100510'
+144169,'7100510'
+144156,'7100511'
+144155,'7100512'
+144155,'7100513'
+144158,'7100513'
+144163,'7100513'
+144165,'7100513'
+144167,'7100513'
+144169,'7100513'
+144160,'7100513'
+144155,'7100514'
+144158,'7100514'
+144163,'7100514'
+144165,'7100514'
+144167,'7100514'
+144169,'7100514'
+144161,'7100514'
+144156,'7100515'
+144157,'7100515'
+144158,'7100515'
+144159,'7100515'
+144162,'7100515'
+144163,'7100515'
+144164,'7100515'
+144165,'7100515'
+144166,'7100515'
+144167,'7100515'
+144168,'7100515'
+144169,'7100515'
+144160,'7100515'
+144161,'7100515'
+144157,'7100516'
+144158,'7100516'
+144159,'7100516'
+144162,'7100516'
+144163,'7100516'
+144164,'7100516'
+144165,'7100516'
+144166,'7100516'
+144167,'7100516'
+144168,'7100516'
+144169,'7100516'
+144160,'7100516'
+144161,'7100516'
+144477,'7100517'
+144478,'7100517'
+144479,'7100517'
+144480,'7100518'
+144477,'7100519'
+144478,'7100519'
+144479,'7100519'
+144543,'7100520'
+144541,'7100521'
+144547,'7100521'
+144541,'7100522'
+144547,'7100522'
+144543,'7100523'
+144543,'7100524'
+144541,'7100525'
+144547,'7100525'
+144541,'7100526'
+144547,'7100526'
+144541,'7100527'
+144547,'7100527'
+144541,'7100528'
+144547,'7100528'
+144541,'7100529'
+144547,'7100529'
+144541,'7100530'
+144547,'7100530'
+144543,'7100531'
+144572,'7100532'
+144574,'7100532'
+144575,'7100532'
+144576,'7100532'
+144572,'7100533'
+144574,'7100533'
+144575,'7100533'
+144576,'7100533'
+144572,'7100534'
+144574,'7100534'
+144575,'7100534'
+144576,'7100534'
diff --git a/sql-bench/Data/ATIS/food_service.txt b/sql-bench/Data/ATIS/food_service.txt
new file mode 100644
index 00000000000..7297e244cc9
--- /dev/null
+++ b/sql-bench/Data/ATIS/food_service.txt
@@ -0,0 +1,121 @@
+'B',1,'FIRST','BREAKFAST'
+'B',1,'COACH','BREAKFAST'
+'B/',1,'FIRST','BREAKFAST'
+'B/S',1,'FIRST','BREAKFAST'
+'B/S',1,'COACH','SNACK'
+'BD',1,'FIRST','BREAKFAST'
+'BD',2,'FIRST','DINNER'
+'BD',1,'COACH','BREAKFAST'
+'BD',2,'COACH','DINNER'
+'BDS',1,'FIRST','BREAKFAST'
+'BDS',2,'FIRST','DINNER'
+'BDS',3,'FIRST','SNACK'
+'BDS',1,'COACH','BREAKFAST'
+'BDS',2,'COACH','DINNER'
+'BDS',3,'COACH','SNACK'
+'BL',1,'FIRST','BREAKFAST'
+'BL',2,'FIRST','LUNCH'
+'BL',1,'COACH','BREAKFAST'
+'BL',2,'COACH','LUNCH'
+'BLD',1,'FIRST','BREAKFAST'
+'BLD',2,'FIRST','LUNCH'
+'BLD',3,'FIRST','DINNER'
+'BLD',1,'COACH','BREAKFAST'
+'BLD',2,'COACH','LUNCH'
+'BLD',3,'COACH','DINNER'
+'BLS',1,'FIRST','BREAKFAST'
+'BLS',2,'FIRST','LUNCH'
+'BLS',3,'FIRST','SNACK'
+'BLS',1,'COACH','BREAKFAST'
+'BLS',2,'COACH','LUNCH'
+'BLS',3,'COACH','SNACK'
+'BS',1,'FIRST','BREAKFAST'
+'BS',2,'FIRST','SNACK'
+'BS',1,'COACH','BREAKFAST'
+'BS',2,'COACH','SNACK'
+'BSD',1,'FIRST','BREAKFAST'
+'BSD',2,'FIRST','SNACK'
+'BSD',3,'FIRST','DINNER'
+'BSD',1,'COACH','BREAKFAST'
+'BSD',2,'COACH','SNACK'
+'BSD',3,'COACH','DINNER'
+'BSL',1,'FIRST','BREAKFAST'
+'BSL',2,'FIRST','SNACK'
+'BSL',3,'FIRST','LUNCH'
+'BSL',1,'COACH','BREAKFAST'
+'BSL',2,'COACH','SNACK'
+'BSL',3,'COACH','LUNCH'
+'D',1,'FIRST','DINNER'
+'D',2,'COACH','DINNER'
+'D/',1,'FIRST','DINNER'
+'D/S',1,'FIRST','DINNER'
+'D/S',1,'COACH','SNACK'
+'DB',1,'FIRST','DINNER'
+'DB',2,'FIRST','BREAKFAST'
+'DB',1,'COACH','DINNER'
+'DB',2,'COACH','BREAKFAST'
+'DS',1,'FIRST','DINNER'
+'DS',2,'FIRST','SNACK'
+'DS',1,'COACH','DINNER'
+'DS',2,'COACH','SNACK'
+'L',1,'FIRST','LUNCH'
+'L',1,'COACH','LUNCH'
+'L/',1,'FIRST','LUNCH'
+'L/S',1,'FIRST','LUNCH'
+'L/S',1,'COACH','SNACK'
+'LD',1,'FIRST','LUNCH'
+'LD',2,'FIRST','DINNER'
+'LD',1,'COACH','LUNCH'
+'LD',2,'COACH','DINNER'
+'LDS',1,'FIRST','LUNCH'
+'LDS',2,'FIRST','DINNER'
+'LDS',3,'FIRST','SNACK'
+'LDS',1,'COACH','LUNCH'
+'LDS',2,'COACH','DINNER'
+'LDS',3,'COACH','SNACK'
+'LS',1,'FIRST','LUNCH'
+'LS',2,'FIRST','SNACK'
+'LS',1,'COACH','LUNCH'
+'LS',2,'COACH','SNACK'
+'LS/L',1,'FIRST','LUNCH'
+'LS/L',2,'FIRST','SNACK'
+'LS/L',1,'COACH','LUNCH'
+'LSD',1,'FIRST','LUNCH'
+'LSD',2,'FIRST','SNACK'
+'LSD',3,'FIRST','DINNER'
+'LSD',1,'COACH','LUNCH'
+'LSD',2,'COACH','SNACK'
+'LSD',3,'COACH','DINNER'
+'S',1,'FIRST','SNACK'
+'S',1,'COACH','SNACK'
+'S/',1,'FIRST','SNACK'
+'SB',1,'FIRST','SNACK'
+'SB',2,'FIRST','BREAKFAST'
+'SB',1,'COACH','SNACK'
+'SB',2,'COACH','BREAKFAST'
+'SBD',1,'FIRST','SNACK'
+'SBD',2,'FIRST','BREAKFAST'
+'SBD',3,'FIRST','DINNER'
+'SBD',1,'COACH','SNACK'
+'SBD',2,'COACH','BREAKFAST'
+'SBD',3,'COACH','DINNER'
+'SBL',1,'FIRST','SNACK'
+'SBL',2,'FIRST','BREAKFAST'
+'SBL',3,'FIRST','LUNCH'
+'SBL',1,'COACH','SNACK'
+'SBL',2,'COACH','BREAKFAST'
+'SBL',3,'COACH','LUNCH'
+'SD',1,'FIRST','SNACK'
+'SD',2,'FIRST','DINNER'
+'SD',1,'COACH','SNACK'
+'SD',2,'COACH','DINNER'
+'SL',1,'FIRST','SNACK'
+'SL',2,'FIRST','LUNCH'
+'SL',1,'COACH','SNACK'
+'SL',2,'COACH','LUNCH'
+'SLD',1,'FIRST','SNACK'
+'SLD',2,'FIRST','LUNCH'
+'SLD',3,'FIRST','DINNER'
+'SLD',1,'COACH','SNACK'
+'SLD',2,'COACH','LUNCH'
+'SLD',3,'COACH','DINNER'
diff --git a/sql-bench/Data/ATIS/ground_service.txt b/sql-bench/Data/ATIS/ground_service.txt
new file mode 100644
index 00000000000..02f18757fed
--- /dev/null
+++ b/sql-bench/Data/ATIS/ground_service.txt
@@ -0,0 +1,33 @@
+'MATL','ATL','L',9.00
+'MATL','ATL','R',0.00
+'MATL','ATL','A',0.00
+'BBOS','BOS','L',5.00
+'BBOS','BOS','R',0.00
+'BBOS','BOS','A',0.00
+'DDFW','DFW','R',0.00
+'DDFW','DFW','L',6.00
+'FDFW','DFW','L',6.00
+'FDFW','DFW','R',0.00
+'DDEN','DEN','L',5.00
+'DDEN','DEN','R',0.00
+'DDEN','DEN','A',0.00
+'PPHL','PHL','L',4.75
+'PPHL','PHL','R',0.00
+'PPHL','PHL','A',0.00
+'PPIT','PIT','L',7.50
+'PPIT','PIT','R',0.00
+'PPIT','PIT','A',0.00
+'OOAK','OAK','L',3.50
+'OOAK','OAK','R',0.00
+'OOAK','SFO','L',6.00
+'OOAK','SFO','R',0.00
+'OOAK','SFO','A',0.00
+'SSFO','SFO','L',4.00
+'SSFO','SFO','R',0.00
+'SSFO','SFO','A',0.00
+'SSFO','OAK','L',5.00
+'WWAS','BWI','L',12.00
+'BBWI','BWI','L',5.00
+'BBWI','BWI','R',0.00
+'BBWI','BWI','A',0.00
+'','','',0.00
diff --git a/sql-bench/Data/ATIS/month_name.txt b/sql-bench/Data/ATIS/month_name.txt
new file mode 100644
index 00000000000..947735f18b4
--- /dev/null
+++ b/sql-bench/Data/ATIS/month_name.txt
@@ -0,0 +1,12 @@
+1,'JANUARY'
+2,'FEBRUARY'
+3,'MARCH'
+4,'APRIL'
+5,'MAY'
+6,'JUNE'
+7,'JULY'
+8,'AUGUST'
+9,'SEPTEMBER'
+10,'OCTOBER'
+11,'NOVEMBER'
+12,'DECEMBER'
diff --git a/sql-bench/Data/ATIS/restrict_carrier.txt b/sql-bench/Data/ATIS/restrict_carrier.txt
new file mode 100644
index 00000000000..814fc9ce034
--- /dev/null
+++ b/sql-bench/Data/ATIS/restrict_carrier.txt
@@ -0,0 +1,612 @@
+'AP/1','AA'
+'AP/2','AA'
+'AP/2','AF'
+'AP/2','AM'
+'AP/2','EA'
+'AP/2','KX'
+'AP/2','MX'
+'AP/2','NW'
+'AP/4','AA'
+'AP/4','AC'
+'AP/4','AS'
+'AP/4','BW'
+'AP/4','CO'
+'AP/4','DL'
+'AP/4','EA'
+'AP/4','KW'
+'AP/4','LI'
+'AP/4','MX'
+'AP/4','PA'
+'AP/4','TW'
+'AP/6','AC'
+'AP/6','BA'
+'AP/6','CB'
+'AP/6','EA'
+'AP/6','ND'
+'AP/6','NW'
+'AP/6','OU'
+'AP/6','PA'
+'AP/6','US'
+'AP/6','WD'
+'AP/10','AA'
+'AP/10','AC'
+'AP/10','AM'
+'AP/10','CO'
+'AP/10','DL'
+'AP/10','EA'
+'AP/10','FH'
+'AP/10','NW'
+'AP/10','RP'
+'AP/10','TW'
+'AP/10','UA'
+'AP/10','US'
+'AP/12','AA'
+'AP/12','CO'
+'AP/12','DL'
+'AP/12','EA'
+'AP/12','JM'
+'AP/12','ML'
+'AP/12','MX'
+'AP/12','PA'
+'AP/12','TW'
+'AP/12','US'
+'AP/13','AA'
+'AP/13','JM'
+'AP/14','AA'
+'AP/14','EA'
+'AP/14','KX'
+'AP/14','NW'
+'AP/14','PA'
+'AP/16','AC'
+'AP/16','CX'
+'AP/16','DL'
+'AP/16','EA'
+'AP/16','SN'
+'AP/16','TW'
+'AP/16','UA'
+'AP/17','AA'
+'AP/18','CP'
+'AP/18','MX'
+'AP/19','AC'
+'AP/19','BW'
+'AP/19','CU'
+'AP/19','EA'
+'AP/19','JM'
+'AP/20','AA'
+'AP/20','AC'
+'AP/20','AS'
+'AP/20','CO'
+'AP/20','CP'
+'AP/20','DL'
+'AP/20','EA'
+'AP/20','FH'
+'AP/20','HP'
+'AP/20','LH'
+'AP/20','ND'
+'AP/20','NR'
+'AP/20','NW'
+'AP/20','NX'
+'AP/20','OU'
+'AP/20','QB'
+'AP/20','TG'
+'AP/20','UA'
+'AP/20','US'
+'AP/20','WD'
+'AP/20','YN'
+'AP/20','4F'
+'AP/20','4V'
+'AP/20','7F'
+'AP/20','8D'
+'AP/21','AA'
+'AP/21','AC'
+'AP/21','EA'
+'AP/21','KX'
+'AP/21','NW'
+'AP/25','AA'
+'AP/25','AS'
+'AP/25','EA'
+'AP/25','LR'
+'AP/25','MX'
+'AP/25','PA'
+'AP/27','AA'
+'AP/27','CO'
+'AP/27','DL'
+'AP/27','EA'
+'AP/27','HP'
+'AP/27','ML'
+'AP/27','NW'
+'AP/27','PA'
+'AP/27','TW'
+'AP/27','UA'
+'AP/27','US'
+'AP/27','WN'
+'AP/32','AA'
+'AP/32','AC'
+'AP/32','BA'
+'AP/32','CP'
+'AP/32','NW'
+'AP/33','LM'
+'AP/35','AA'
+'AP/35','AC'
+'AP/35','AS'
+'AP/35','CO'
+'AP/35','DF'
+'AP/35','EA'
+'AP/35','HA'
+'AP/35','HP'
+'AP/35','LM'
+'AP/35','ND'
+'AP/35','NW'
+'AP/35','PA'
+'AP/35','TW'
+'AP/35','UA'
+'AP/35','WD'
+'AP/43','AA'
+'AP/43','DF'
+'AP/43','UA'
+'AP/43','US'
+'AP/44','AA'
+'AP/44','AC'
+'AP/44','AD'
+'AP/44','AS'
+'AP/44','BE'
+'AP/44','CO'
+'AP/44','DF'
+'AP/44','DL'
+'AP/44','EA'
+'AP/44','FH'
+'AP/44','HP'
+'AP/44','IN'
+'AP/44','IT'
+'AP/44','KS'
+'AP/44','ML'
+'AP/44','NW'
+'AP/44','PA'
+'AP/44','TW'
+'AP/44','UA'
+'AP/44','UO'
+'AP/44','US'
+'AP/44','WN'
+'AP/44','YN'
+'AP/44','YV'
+'AP/44','YW'
+'AP/44','YX'
+'AP/44','ZO'
+'AP/44','ZK'
+'AP/44','3S'
+'AP/44','5A'
+'AP/44','5C'
+'AP/44','7F'
+'AP/44','7V'
+'AP/44','8G'
+'AP/47','AA'
+'AP/47','DO'
+'AP/48','AA'
+'AP/48','AC'
+'AP/48','BL'
+'AP/48','BW'
+'AP/48','CO'
+'AP/48','CP'
+'AP/48','DL'
+'AP/48','EA'
+'AP/48','IV'
+'AP/48','KW'
+'AP/48','KX'
+'AP/48','ML'
+'AP/48','MX'
+'AP/48','NR'
+'AP/48','NW'
+'AP/48','PA'
+'AP/48','PD'
+'AP/48','TW'
+'AP/48','UA'
+'AP/48','YV'
+'AP/48','8D'
+'AP/55','AA'
+'AP/55','AC'
+'AP/55','AS'
+'AP/55','CH'
+'AP/55','CO'
+'AP/55','CP'
+'AP/55','CT'
+'AP/55','DL'
+'AP/55','EA'
+'AP/55','GM'
+'AP/55','HA'
+'AP/55','HP'
+'AP/55','ML'
+'AP/55','ND'
+'AP/55','NR'
+'AP/55','NW'
+'AP/55','OD'
+'AP/55','PA'
+'AP/55','RP'
+'AP/55','TW'
+'AP/55','UA'
+'AP/55','UE'
+'AP/55','US'
+'AP/55','WD'
+'AP/55','YW'
+'AP/55','YX'
+'AP/55','YK'
+'AP/55','ZV'
+'AP/55','2V'
+'AP/55','3N'
+'AP/55','4N'
+'AP/55','4W'
+'AP/55','5A'
+'AP/55','5C'
+'AP/55','5L'
+'AP/55','8D'
+'AP/56','AA'
+'AP/56','DL'
+'AP/56','GM'
+'AP/56','HA'
+'AP/56','HP'
+'AP/56','PA'
+'AP/56','TW'
+'AP/56','UA'
+'AP/56','WD'
+'AP/57','AA'
+'AP/57','AC'
+'AP/57','AS'
+'AP/57','BE'
+'AP/57','CO'
+'AP/57','CP'
+'AP/57','CT'
+'AP/57','DL'
+'AP/57','EA'
+'AP/57','HP'
+'AP/57','ML'
+'AP/57','ND'
+'AP/57','NW'
+'AP/57','PA'
+'AP/57','PD'
+'AP/57','PS'
+'AP/57','TW'
+'AP/57','UA'
+'AP/57','US'
+'AP/57','YV'
+'AP/57','YW'
+'AP/57','YX'
+'AP/57','ZV'
+'AP/57','2P'
+'AP/57','2V'
+'AP/57','3N'
+'AP/57','4N'
+'AP/57','4X'
+'AP/57','8G'
+'AP/58','AS'
+'AP/58','EA'
+'AP/58','7H'
+'AP/59','DL'
+'AP/59','JN'
+'AP/60','AC'
+'AP/60','EA'
+'AP/60','NW'
+'AP/60','UA'
+'AP/60','US'
+'AP/61','CO'
+'AP/61','FY'
+'AP/61','JR'
+'AP/61','2V'
+'AP/68','AA'
+'AP/68','AD'
+'AP/68','AM'
+'AP/68','AS'
+'AP/68','BE'
+'AP/68','CO'
+'AP/68','CP'
+'AP/68','CT'
+'AP/68','DF'
+'AP/68','DL'
+'AP/68','EA'
+'AP/68','EM'
+'AP/68','HP'
+'AP/68','IN'
+'AP/68','ML'
+'AP/68','MX'
+'AP/68','NW'
+'AP/68','OU'
+'AP/68','PA'
+'AP/68','QQ'
+'AP/68','QS'
+'AP/68','RP'
+'AP/68','TW'
+'AP/68','UA'
+'AP/68','US'
+'AP/68','YN'
+'AP/68','YV'
+'AP/68','YW'
+'AP/68','YX'
+'AP/68','ZE'
+'AP/68','ZK'
+'AP/68','3N'
+'AP/68','5C'
+'AP/68','7L'
+'AP/70','AC'
+'AP/70','BW'
+'AP/70','EA'
+'AP/70','PA'
+'AP/73','AA'
+'AP/73','DL'
+'AP/73','EA'
+'AP/73','ML'
+'AP/73','PA'
+'AP/73','TW'
+'AP/75','AA'
+'AP/75','AC'
+'AP/75','AS'
+'AP/75','CH'
+'AP/75','CO'
+'AP/75','CP'
+'AP/75','DL'
+'AP/75','EA'
+'AP/75','HP'
+'AP/75','JV'
+'AP/75','KS'
+'AP/75','LH'
+'AP/75','ML'
+'AP/75','MX'
+'AP/75','ND'
+'AP/75','NW'
+'AP/75','OU'
+'AP/75','PA'
+'AP/75','RP'
+'AP/75','RV'
+'AP/75','TW'
+'AP/75','UA'
+'AP/75','US'
+'AP/75','WD'
+'AP/75','XE'
+'AP/75','YN'
+'AP/75','YV'
+'AP/75','ZO'
+'AP/75','7F'
+'AP/75','8D'
+'AP/76','MX'
+'AP/76','NW'
+'AP/80','AA'
+'AP/80','AC'
+'AP/80','AR'
+'AP/80','AS'
+'AP/80','BA'
+'AP/80','CO'
+'AP/80','CP'
+'AP/80','DL'
+'AP/80','EA'
+'AP/80','HP'
+'AP/80','JB'
+'AP/80','JL'
+'AP/80','JV'
+'AP/80','LA'
+'AP/80','LH'
+'AP/80','ND'
+'AP/80','NW'
+'AP/80','PA'
+'AP/80','TG'
+'AP/80','UA'
+'AP/80','US'
+'AP/80','UW'
+'AP/80','WD'
+'AP/80','YN'
+'AP/80','4V'
+'AP/80','7E'
+'AP/80','8D'
+'AP/87','AC'
+'AP/94','AA'
+'AP/94','AC'
+'AP/94','EA'
+'AP/94','LM'
+'AP/94','NW'
+'EX/1','AR'
+'EX/1','IB'
+'EX/2','AB'
+'EX/2','BW'
+'EX/2','FQ'
+'EX/2','MX'
+'EX/2','UA'
+'EX/2','UP'
+'EX/3','AA'
+'EX/3','CO'
+'EX/3','DL'
+'EX/3','EA'
+'EX/3','HP'
+'EX/3','PA'
+'EX/3','US'
+'EX/5','LR'
+'EX/9','AA'
+'EX/9','AC'
+'EX/9','AM'
+'EX/9','BA'
+'EX/9','CO'
+'EX/9','EA'
+'EX/9','FQ'
+'EX/9','HP'
+'EX/9','PA'
+'EX/9','TV'
+'EX/11','AA'
+'EX/11','AM'
+'EX/11','CO'
+'EX/11','CP'
+'EX/11','CX'
+'EX/11','DL'
+'EX/11','JT'
+'EX/11','LA'
+'EX/11','MX'
+'EX/11','NW'
+'EX/11','PA'
+'EX/11','UA'
+'EX/12','AS'
+'EX/12','CP'
+'EX/12','CX'
+'EX/13','AC'
+'EX/13','AS'
+'EX/13','BF'
+'EX/13','BW'
+'EX/13','DL'
+'EX/13','KS'
+'EX/13','LM'
+'EX/13','ML'
+'EX/13','YV'
+'EX/13','ZV'
+'EX/13','7H'
+'EX/14','AA'
+'EX/14','AS'
+'EX/14','BE'
+'EX/14','CO'
+'EX/14','CP'
+'EX/14','DL'
+'EX/14','EA'
+'EX/14','IN'
+'EX/14','ML'
+'EX/14','NW'
+'EX/14','PA'
+'EX/14','PD'
+'EX/14','TW'
+'EX/14','UA'
+'EX/14','US'
+'EX/14','WN'
+'EX/14','YW'
+'EX/14','ZV'
+'EX/14','2V'
+'EX/14','4N'
+'EX/14','4X'
+'EX/14','7F'
+'EX/14','8D'
+'EX/15','AC'
+'EX/15','BW'
+'EX/15','CU'
+'EX/15','HP'
+'EX/15','JM'
+'EX/17','AA'
+'EX/17','AM'
+'EX/17','AS'
+'EX/17','DL'
+'EX/17','EA'
+'EX/17','JL'
+'EX/17','LH'
+'EX/17','PA'
+'EX/17','UA'
+'EX/19','BW'
+'EX/19','KX'
+'EX/20','AA'
+'EX/20','CO'
+'EX/20','DL'
+'EX/20','HE'
+'EX/20','JM'
+'EX/20','ML'
+'EX/20','MX'
+'EX/20','NW'
+'EX/20','PA'
+'EX/20','UA'
+'EX/20','8R'
+'EX/21','AA'
+'EX/21','JM'
+'EX/25','AA'
+'EX/25','MX'
+'EX/29','AA'
+'EX/29','AM'
+'EX/29','CO'
+'EX/29','EA'
+'EX/29','LH'
+'EX/32','AA'
+'EX/32','EA'
+'EX/32','JM'
+'EX/33','AA'
+'EX/33','JM'
+'EX/33','LI'
+'EX/33','UA'
+'EX/33','5T'
+'EX/34','EA'
+'EX/34','IN'
+'EX/34','JM'
+'EX/34','KW'
+'EX/34','UE'
+'EX/34','UP'
+'EX/34','YV'
+'EX/34','YL'
+'EX/36','AA'
+'EX/36','AC'
+'EX/36','CO'
+'EX/36','CP'
+'EX/36','LI'
+'EX/36','OU'
+'EX/36','US'
+'EX/38','AA'
+'EX/38','EA'
+'EX/38','JM'
+'EX/38','KX'
+'EX/43','AA'
+'EX/43','AS'
+'EX/43','CO'
+'EX/43','CT'
+'EX/43','DL'
+'EX/43','EA'
+'EX/43','HP'
+'EX/43','MX'
+'EX/43','NW'
+'EX/43','OG'
+'EX/43','PA'
+'EX/43','TW'
+'EX/43','UA'
+'EX/43','US'
+'EX/45','NW'
+'EX/47','AA'
+'EX/47','CO'
+'EX/47','DL'
+'EX/47','EA'
+'EX/47','JM'
+'EX/47','JR'
+'EX/47','ML'
+'EX/47','NW'
+'EX/47','OG'
+'EX/47','PA'
+'EX/47','TW'
+'EX/47','US'
+'EX/48','AC'
+'EX/48','AF'
+'EX/48','CO'
+'EX/48','CP'
+'EX/48','DL'
+'EX/48','JM'
+'EX/48','KW'
+'EX/48','MX'
+'EX/48','PA'
+'EX/48','SN'
+'EX/55','AA'
+'EX/55','AF'
+'EX/55','BW'
+'EX/55','CO'
+'EX/55','DO'
+'EX/55','EA'
+'EX/55','JM'
+'EX/55','KX'
+'EX/55','LI'
+'EX/55','LM'
+'EX/55','NW'
+'EX/55','PA'
+'EX/55','PY'
+'EX/55','TW'
+'EX/55','UP'
+'EX/55','2V'
+'VU/1','AA'
+'VU/1','AC'
+'VU/1','AQ'
+'VU/1','AS'
+'VU/1','CP'
+'VU/1','CT'
+'VU/1','CX'
+'VU/1','DL'
+'VU/1','EA'
+'VU/1','HP'
+'VU/1','LW'
+'VU/1','ND'
+'VU/1','NW'
+'VU/1','PA'
+'VU/1','TB'
+'VU/1','TW'
+'VU/1','UA'
+'VU/1','US'
+'VU/1','YR'
+'VU/1','6G'
diff --git a/sql-bench/Data/ATIS/restrict_class.txt b/sql-bench/Data/ATIS/restrict_class.txt
new file mode 100644
index 00000000000..1e1ac71178c
--- /dev/null
+++ b/sql-bench/Data/ATIS/restrict_class.txt
@@ -0,0 +1,4 @@
+'AP/2','B7NR'
+'AP/2','BW7NR'
+'AP/2','BWE14'
+'AP/2','YAP14'
diff --git a/sql-bench/Data/ATIS/restriction.txt b/sql-bench/Data/ATIS/restriction.txt
new file mode 100644
index 00000000000..e72af1c16b6
--- /dev/null
+++ b/sql-bench/Data/ATIS/restriction.txt
@@ -0,0 +1,65 @@
+'AP/1','FOR TRAVEL ORIGINATING AND TERMINATING IN HAWAII','CHILDREN\'S FARES,SALES AGENTS,TOUR CONDUCTORS',7,'Y',3,150
+'AP/2','FOR TRAVEL BETWEEN UNITED STATES AND CARIBBEAN','TOUR CONDUCTORS',7,'N',3,14
+'AP/4','FOR TRAVEL BETWEEN UNITED STATES AND MEXICO','CHILDREN\'S FARES,SALES AGENTS',7,'Y',3,21
+'AP/6','FOR TRAVEL TO/FROM CANADA','CHILDREN\'S FARES,FAMILY FARES,TOUR CONDUCTORS,VISIT USA FARES',7,'Y',3,30
+'AP/10','FOR TRAVEL TO/FROM INTERMEDIATE POINTS','CONTACT CARRIER',30,'Y',3,21
+'AP/12','FOR TRAVEL BETWEEN UNITED STATES AND CARIBBEAN','CONTACT CARRIER',14,'N',3,21
+'AP/13','TRAVEL BETWEEN U.S. AND CANADA,AND POINTS IN CARIBBEAN','CONTACT CARRIER',3,'Y',0,180
+'AP/14','TRAVEL BETWEEN POINTS NAMED AND ARE NOT APPLICABLE TO/FROM INTERMEDIATE POINTS','CONTACT CARRIER',3,'Y',1,3
+'AP/16','FARES ARE NOT APPLICABLE TO/FROM INTERMEDIATE POINTS','CONTACT CARRIER',14,'Y',3,21
+'AP/17','ROUND TRIP TRAVEL BETWEEN U.S. AND MEXICO','SALES AGENTS (VIA AA TOUR CONDUCTORS)',7,'N',3,30
+'AP/18','ROUND TRIP TRAVEL BETWEEN CANADA AND MEXICO','FAMILY FARES,SALES AGENTS,TOUR CONDUCTORS',7,'N',7,180
+'AP/19','RND TRIP BETWEEN CANADA AND CARIBBEAN. NOT APPLICABLE TO/FROM INTERMEDIATE PNTS','CHILDREN\'S FARES,SALES AGENT,TOUR CONDUCTORS',7,'N',7,30
+'AP/20','ROUND TRIP EXCURSION FARES,NOT APPLICABLE TO/FROM INTERMEDIATE POINTS','CHILDREN\S FARES,FAMILY FARES,TOUR CONDUCTORS',14,'Y',3,180
+'AP/21','TRAVEL TO/FROM U.S.A. AND CANADA,NOT APPLICABLE TO/FROM INTERMEDIATE POINTS','SALES AGENTS,TOUR CONDUCTORS',14,'N',7,7
+'AP/25','FARES DO NOT APPLY TO/FROM INTERMEDIATE POINTS ON THE ROUTING','SALES AGENTS,TOUR CONDUCTORS',7,'Y',3,60
+'AP/27','FARES NOT APPLICABLE TO/FROM INTERMEDIATE POINTS','CONTACT CARRIER',7,'Y',0,180
+'AP/32','ROUND TRIP CHARTER TO HAWAII. FARES NOT APPLICABLE TO/FROM INTERMEDIATE POINTS','CHILDREN\'S AND FAMILY FARES,HAWAII COMMON FARE,SALES AGENTS,TOUR CONDUCTORS',7,'Y',3,30
+'AP/33','ROUND TRIP BETWEEN U.S. AND CARIBBEAN','CHILDREN\'S FARE,SALES AGENTS,TOUR CONDUCTORS',14,'Y',6,21
+'AP/35','FARES NOT APPLICABLE TO/FROM INTERMEDIATE POINTS','SALES AGENTS,TOUR CONDUCTORS',7,'Y',0,30
+'AP/43','FARES NOT APPLICABLE TO/FROM INTERMEDIATE POINTS','CHILDREN\'S FARE,SALES AGENTS,TOUR CONDUCTORS',14,'N',3,3
+'AP/44','ONE_WAY TRAVEL,DURING PEAK/NON-PEAK HOURS','CONTACT CARRIER',4,'Y',0,0
+'AP/47','ROUND TRIP TRAVEL','CONTACT CARRIER',14,'Y',7,30
+'AP/48','FARES NOT APPLICABLE TO/FROM INTERMEDIATE POINTS','SALES AGENTS,TOUR CONDUCTORS,VISIT USA FARES,CHILDREN\'S FARES',7,'Y',0,0
+'AP/55','MAY COMBINE FARES (EXCEPT VIA DELTA AIRLINES) SEATS LIMITED VIA UNITED AIRLINES','CONTACT CARRIER',3,'N',0,0
+'AP/56','SEATS ARE LIMITED','CONTACT CARRIERS',7,'Y',3,45
+'AP/57','FARES NOT APPLICABLE TO/FROM INTERMEDIATE POINTS','CHILDREN\'S FARES,SALES AGENTS,TOUR CONDUCTORS',7,'Y',3,180
+'AP/58','FARES NOT APPLICABLE TO/FROM INTERMEDIATE POINTS','CHILDREN\'S FARES,SALES AGENTS,TOUR CONDUCTORS',7,'Y',3,330
+'AP/59','FARES NOT APPLICABLE TO/FROM INTERMEDIATE POINTS','CHILDREN\'S FARES,SALES AGENTS,TOUR CONDUCTORS',14,'N',7,30
+'AP/60','ROUND TRIP TRAVEL BETWEEN U.S. AND CANADA','CHILDREN\'S FARES,SALES AGENTS,TOUR CONDUCTORS',7,'N',3,365
+'AP/61','FARES MAYBE COMBINED','CHILDREN\'S FARES,SALES AGENTS,TOUR CONDUCTORS',7,'Y',0,60
+'AP/68','FARES NOT APPLICABLE TO/FROM INTERMEDIATE POINTS','CONTACT CARRIER',7,'Y',0,0
+'AP/70','ROUND TRIP TRAVEL. FARES NOT APPLICABLE TO/FROM INTERMEDIATE POINTS','SALES AGENTS,TOUR CONDUCTORS,VISIT U.S.A. FARES,CHILDREN\'S FARES',14,'Y',7,14
+'AP/73','FARES NOT APPLICABLE TO/FROM INTERMEDIATE POINTS','CONTACT CARRIER',7,'N',0,30
+'AP/75','FARES NOT APPLICABLE TO/FROM INTERMEDIATE POINTS','SALES AGENTS,TOUR CONDUCTORS,VISIT U.S.A. FARES,CHILDREN\'S FARES',7,'Y',3,60
+'AP/76','ROUND TRIP TRAVEL BETWEEN U.S. AND JAMAICA','SALES AGENTS,TOUR CONDUCTORS',7,'N',0,14
+'AP/80','FARES APPLY TO/FROM INTERMEDIATE POINTS','CHILDREN\'S FARES,FAMILY FARES,SALES AGENTS,TOUR CONDUCTORS',14,'N',3,30
+'AP/87','FARES APPLY TO ROUND TRIP TRAVEL','CONTACT CARRIER',14,'Y',7,21
+'AP/94','FOR ROUND TRIP TRAVEL. FARES NOT APPLICABLE TO/FROM INTERMEDIATE POINTS','CHILDREN\'S FARES,SALES AGENTS,TOUR CONDUCTORS',7,'Y',7,21
+'EX/1','FOR CIRCLE TRIP TRAVEL','CHILDREN\'S FARES,SALES AGENTS',0,'Y',5,60
+'EX/2','ECONOMY CLASS EXCURSION FARES','SALES AGENTS,TOUR CONDUCTORS',0,'Y',0,21
+'EX/3','FARES NOT APPLICABLE TO/FROM INTERMEDIATE POINTS','CONTACT CARRIER',0,'Y',2,45
+'EX/5','FOR ROUND TRIP TRAVEL','CONTACT CARRIER',0,'N',5,30
+'EX/9','FARES DO NOT APPLY TO/FROM INTERMEDIATE POINTS','CHILDREN\'S FARES,SALES AGENTS,TOUR CONDUCTORS',0,'N',0,30
+'EX/11','FARES MAY BE COMBINED','CONTACT CARRIER',0,'Y',0,60
+'EX/12','FARES NOT APPLICABLE TO/FROM INTERMEDIATE POINTS','CHILDREN\'S FARES',0,'Y',3,180
+'EX/13','FARES NOT APPLICABLE TO/FROM INTERMEDIATE POINTS','CHILDREN\'S FARES,FAMILY FARES,SALES AGENTS,TOUR CONDUCTORS',0,'Y',0,3
+'EX/14','FARES MAY BE COMBINED','CONTACT CARRIER',0,'N',3,330
+'EX/15','ROUND TRIP TRAVEL BETWEEN CANADA AND CARIBBEAN','CONTACT CARRIER',0,'Y',7,45
+'EX/17','ROUND TRIP EXCURSION FARES','SALES AGENTS,TOUR CONDUCTORS',0,'N',0,180
+'EX/19','ROUND TRIP EXCURSION FARES BETWEEN CANADA AND CARIBBEAN','CONTACT CARRIER',0,'Y',7,7
+'EX/20','ROUND TRIP EXCURSION FARES','CONTACT CARRIER',0,'Y',0,14
+'EX/21','TRAVEL BETWEEN THE U.S.A. AND CARIBBEAN','SALES AGENTS,TOUR CONDUCTORS',0,'N',0,7
+'EX/25','VIA AA,ROUND TRIP TRAVEL BETWEEN SAN JUAN AND ACAPULCO/MEXICO CITY','SALES AGENTS,TOUR CONDUCTORS',0,'Y',3,14
+'EX/29','ROUND TRIP TRAVEL BETWEEN U.S.,CARIBBEAN,AND MEXICO','CHILDREN\'S FARES',0,'Y',0,21
+'EX/32','TRAVEL ORIGINATING IN JAMAICA','SALES AGENTS,TOUR CONDUCTORS',0,'N',0,365
+'EX/33','ROUND TRIP TRAVEL TO JAMAICA/CARIBBEAN','CHILDREN\'S FARES,TOUR CONDUCTORS',0,'N',0,21
+'EX/34','ONE DAY AWAY ROUND TRIP FARES','SALES AGENTS,TOUR CONDUCTORS',0,'N',1,1
+'EX/36','ROUND TRIP TRAVEL. NOT APPLICABLE TO/FROM INTERMEDIATE POINTS','CHILDREN\'S FARES,FAMILY FARES,TOUR CONDUCTORS',0,'Y',1,2
+'EX/38','SAME DAY FARES (VIA EASTERN AIRLINES)','SALES AGENTS,TOUR CONDUCTORS',0,'N',1,1
+'EX/43','ROUND TRIP EXCURSION FARES','CONTACT CARRIER',0,'Y',0,365
+'EX/45','VIA AMERICAN AIRLINES ROUND TRIP TRAVEL BETWEEN KINGSTON/MONTEGO BAY','CHILDREN\'S FARES,SALES AGENTS,TOUR CONDUCTORS',0,'N',3,21
+'EX/47','ROUND TRIP TRAVEL BETWEEN U.S.,CANADA,AND CARIBBEAN','CONTACT CARRIER',0,'Y',3,21
+'EX/48','WEEKEND EXCURSION FARE','CHILDREN\'S FARE,FAMILY FARES,SALES AGENTS,TOUR CONDUCTORS',0,'N',7,365
+'EX/55','FARES MAY BE COMBINED','SALES AGENTS',0,'Y',3,21
+'VU/1','VISIT USA: INTERNATIONAL TRAVEL BEGINNING AND ENDING OUTSIDE U.S.','SALES AGENTS',0,'Y',3,21
diff --git a/sql-bench/Data/ATIS/state.txt b/sql-bench/Data/ATIS/state.txt
new file mode 100644
index 00000000000..9c113450b27
--- /dev/null
+++ b/sql-bench/Data/ATIS/state.txt
@@ -0,0 +1,63 @@
+'AB','ALBERTA','CANADA'
+'AK','ALASKA','USA'
+'AL','ALABAMA','USA'
+'AR','ARKANSAS','USA'
+'AZ','ARIZONA','USA'
+'BC','BRITISH COLUMBIA','CANADA'
+'CA','CALIFORNIA','USA'
+'CO','COLORADO','USA'
+'CT','CONNECTICUT','USA'
+'DC','DISTRICT OF COLUMBIA','USA'
+'DE','DELAWARE','USA'
+'FL','FLORIDA','USA'
+'GA','GEORGIA','USA'
+'HI','HAWAII','USA'
+'IA','IOWA','USA'
+'ID','IDAHO','USA'
+'IL','ILLINOIS','USA'
+'IN','INDIANA','USA'
+'KS','KANSAS','USA'
+'KY','KENTUCKY','USA'
+'LA','LOUISIANA','USA'
+'MA','MASSACHUSETTS','USA'
+'MB','MANITOBA','CANADA'
+'MD','MARYLAND','USA'
+'ME','MAINE','USA'
+'MI','MICHIGAN','USA'
+'MN','MINNESOTA','USA'
+'MO','MISSOURI','USA'
+'MS','MISSISSIPPI','USA'
+'MT','MONTANA','USA'
+'NB','NEW BRUNSWICK','CANADA'
+'NC','NORTH CAROLINA','USA'
+'ND','NORTH DAKOTA','USA'
+'NE','NEBRASKA','USA'
+'NF','NEWFOUNDLAND','CANADA'
+'NH','NEW HAMPSHIRE','USA'
+'NJ','NEW JERSEY','USA'
+'NM','NEW MEXICO','USA'
+'NS','NOVA SCOTIA','CANADA'
+'NT','NORTHWEST TERRITORIES','CANADA'
+'NV','NEVADA','USA'
+'NY','NEW YORK','USA'
+'OH','OHIO','USA'
+'OK','OKLAHOMA','USA'
+'ON','ONTARIO','CANADA'
+'OR','OREGON','USA'
+'PA','PENNSYLVANIA','USA'
+'PE','PRINCE EDWARD ISLAND','CANADA'
+'PQ','QUEBEC','CANADA'
+'RI','RHODE ISLAND','USA'
+'SC','SOUTH CAROLINA','USA'
+'SD','SOUTH DAKOTA','USA'
+'SK','SASKATCHEWAN','CANADA'
+'TN','TENNESSEE','USA'
+'TX','TEXAS','USA'
+'UT','UTAH','USA'
+'VA','VIRGINIA','USA'
+'VT','VERMONT','USA'
+'WA','WASHINGTON','USA'
+'WI','WISCONSIN','USA'
+'WV','WEST VIRGINIA','USA'
+'WY','WYOMING','USA'
+'YT','YUKON TERRITORY','CANADA'
diff --git a/sql-bench/Data/ATIS/stop.txt b/sql-bench/Data/ATIS/stop.txt
new file mode 100644
index 00000000000..c731f82f3ff
--- /dev/null
+++ b/sql-bench/Data/ATIS/stop.txt
@@ -0,0 +1,69 @@
+101908,1,102766
+101908,2,137319
+101913,1,102770
+101913,2,137323
+101924,1,102779
+101924,2,137339
+102674,1,102129
+102674,2,112354
+105810,1,106248
+105810,2,137423
+106262,1,106229
+106262,2,137734
+106270,1,106251
+106270,2,137740
+106366,1,105795
+106366,2,112516
+106373,1,105806
+106373,2,113716
+106375,1,105800
+106375,2,112527
+107253,1,107486
+107253,2,138963
+111924,1,111886
+111924,2,102766
+111924,3,137319
+111930,1,111939
+111930,2,107199
+112413,1,111886
+112413,2,102766
+113499,1,112998
+113499,2,112352
+113710,1,112996
+113710,2,112518
+113713,1,113001
+113713,2,112520
+133423,1,133431
+133423,2,111931
+133516,1,133436
+133516,2,113582
+137410,1,137228
+137410,2,102127
+137685,1,137420
+137685,2,113500
+137814,1,137736
+137814,2,139355
+138866,1,139270
+138866,2,137335
+138965,1,138976
+138965,2,113011
+144059,1,144157
+144059,2,112783
+144087,1,144156
+144087,2,112864
+144088,1,144144
+144088,2,111929
+144092,1,144063
+144092,2,101928
+144093,1,144575
+144093,2,138868
+144095,1,144066
+144095,2,101929
+144110,1,144572
+144110,2,138882
+144160,1,144145
+144160,2,112038
+144161,1,144146
+144161,2,112039
+144543,1,144574
+144543,2,139271
diff --git a/sql-bench/Data/ATIS/stop1.txt b/sql-bench/Data/ATIS/stop1.txt
new file mode 100644
index 00000000000..c731f82f3ff
--- /dev/null
+++ b/sql-bench/Data/ATIS/stop1.txt
@@ -0,0 +1,69 @@
+101908,1,102766
+101908,2,137319
+101913,1,102770
+101913,2,137323
+101924,1,102779
+101924,2,137339
+102674,1,102129
+102674,2,112354
+105810,1,106248
+105810,2,137423
+106262,1,106229
+106262,2,137734
+106270,1,106251
+106270,2,137740
+106366,1,105795
+106366,2,112516
+106373,1,105806
+106373,2,113716
+106375,1,105800
+106375,2,112527
+107253,1,107486
+107253,2,138963
+111924,1,111886
+111924,2,102766
+111924,3,137319
+111930,1,111939
+111930,2,107199
+112413,1,111886
+112413,2,102766
+113499,1,112998
+113499,2,112352
+113710,1,112996
+113710,2,112518
+113713,1,113001
+113713,2,112520
+133423,1,133431
+133423,2,111931
+133516,1,133436
+133516,2,113582
+137410,1,137228
+137410,2,102127
+137685,1,137420
+137685,2,113500
+137814,1,137736
+137814,2,139355
+138866,1,139270
+138866,2,137335
+138965,1,138976
+138965,2,113011
+144059,1,144157
+144059,2,112783
+144087,1,144156
+144087,2,112864
+144088,1,144144
+144088,2,111929
+144092,1,144063
+144092,2,101928
+144093,1,144575
+144093,2,138868
+144095,1,144066
+144095,2,101929
+144110,1,144572
+144110,2,138882
+144160,1,144145
+144160,2,112038
+144161,1,144146
+144161,2,112039
+144543,1,144574
+144543,2,139271
diff --git a/sql-bench/Data/ATIS/time_interval.txt b/sql-bench/Data/ATIS/time_interval.txt
new file mode 100644
index 00000000000..f645dedbf34
--- /dev/null
+++ b/sql-bench/Data/ATIS/time_interval.txt
@@ -0,0 +1,12 @@
+'morning',0000,1200
+'afternoon',1200,1800
+'evening',1800,2000
+'day',600,1800
+'night',1800,2400
+'night',000,600
+'early morning',0000,800
+'mid-morning',800,1000
+'late morning',1000,1200
+'early afternoon',1200,1400
+'mid-afternoon',1400,1600
+'late afternoon',1600,1800
diff --git a/sql-bench/Data/ATIS/time_zone.txt b/sql-bench/Data/ATIS/time_zone.txt
new file mode 100644
index 00000000000..1cc3dc488d0
--- /dev/null
+++ b/sql-bench/Data/ATIS/time_zone.txt
@@ -0,0 +1,9 @@
+'HST','HAWAII/ALEUTIAN STANDARD TIME'
+'AST','ALASKA STANDARD TIME'
+'YST','YUKON STANDARD TIME'
+'PST','PACIFIC STANDARD TIME'
+'MST','MOUNTAIN STANDARD TIME'
+'CST','CENTRAL STANDARD TIME'
+'EST','EASTERN STANDARD TIME'
+'AST','ATLANTIC STANDARD TIME'
+'NST','NEWFOUNDLAND STANDARD TIME'
diff --git a/sql-bench/Data/ATIS/transport.txt b/sql-bench/Data/ATIS/transport.txt
new file mode 100644
index 00000000000..3c3faf6a4bd
--- /dev/null
+++ b/sql-bench/Data/ATIS/transport.txt
@@ -0,0 +1,4 @@
+'L','LIMOUSINE'
+'T','TAXI'
+'R','RENTAL CAR'
+'A','AIR TAXI OPERATION'
diff --git a/sql-bench/Data/Wisconsin/onek.data b/sql-bench/Data/Wisconsin/onek.data
new file mode 100644
index 00000000000..4afe4483ceb
--- /dev/null
+++ b/sql-bench/Data/Wisconsin/onek.data
@@ -0,0 +1,1000 @@
+147,0,1,3,7,7,7,47,147,147,147,14,15,'RFAAAA','AAAAAA','AAAAxx'
+931,1,1,3,1,11,1,31,131,431,931,2,3,'VJAAAA','BAAAAA','HHHHxx'
+714,2,0,2,4,14,4,14,114,214,714,8,9,'MBAAAA','CAAAAA','OOOOxx'
+711,3,1,3,1,11,1,11,111,211,711,2,3,'JBAAAA','DAAAAA','VVVVxx'
+883,4,1,3,3,3,3,83,83,383,883,6,7,'ZHAAAA','EAAAAA','AAAAxx'
+439,5,1,3,9,19,9,39,39,439,439,18,19,'XQAAAA','FAAAAA','HHHHxx'
+670,6,0,2,0,10,0,70,70,170,670,0,1,'UZAAAA','GAAAAA','OOOOxx'
+543,7,1,3,3,3,3,43,143,43,543,6,7,'XUAAAA','HAAAAA','VVVVxx'
+425,8,1,1,5,5,5,25,25,425,425,10,11,'JQAAAA','IAAAAA','AAAAxx'
+800,9,0,0,0,0,0,0,0,300,800,0,1,'UEAAAA','JAAAAA','HHHHxx'
+489,10,1,1,9,9,9,89,89,489,489,18,19,'VSAAAA','KAAAAA','OOOOxx'
+494,11,0,2,4,14,4,94,94,494,494,8,9,'ATAAAA','LAAAAA','VVVVxx'
+880,12,0,0,0,0,0,80,80,380,880,0,1,'WHAAAA','MAAAAA','AAAAxx'
+611,13,1,3,1,11,1,11,11,111,611,2,3,'NXAAAA','NAAAAA','HHHHxx'
+226,14,0,2,6,6,6,26,26,226,226,12,13,'SIAAAA','OAAAAA','OOOOxx'
+774,15,0,2,4,14,4,74,174,274,774,8,9,'UDAAAA','PAAAAA','VVVVxx'
+298,16,0,2,8,18,8,98,98,298,298,16,17,'MLAAAA','QAAAAA','AAAAxx'
+682,17,0,2,2,2,2,82,82,182,682,4,5,'GAAAAA','RAAAAA','HHHHxx'
+864,18,0,0,4,4,4,64,64,364,864,8,9,'GHAAAA','SAAAAA','OOOOxx'
+183,19,1,3,3,3,3,83,183,183,183,6,7,'BHAAAA','TAAAAA','VVVVxx'
+885,20,1,1,5,5,5,85,85,385,885,10,11,'BIAAAA','UAAAAA','AAAAxx'
+997,21,1,1,7,17,7,97,197,497,997,14,15,'JMAAAA','VAAAAA','HHHHxx'
+966,22,0,2,6,6,6,66,166,466,966,12,13,'ELAAAA','WAAAAA','OOOOxx'
+389,23,1,1,9,9,9,89,189,389,389,18,19,'ZOAAAA','XAAAAA','VVVVxx'
+846,24,0,2,6,6,6,46,46,346,846,12,13,'OGAAAA','YAAAAA','AAAAxx'
+206,25,0,2,6,6,6,6,6,206,206,12,13,'YHAAAA','ZAAAAA','HHHHxx'
+239,26,1,3,9,19,9,39,39,239,239,18,19,'FJAAAA','ABAAAA','OOOOxx'
+365,27,1,1,5,5,5,65,165,365,365,10,11,'BOAAAA','BBAAAA','VVVVxx'
+204,28,0,0,4,4,4,4,4,204,204,8,9,'WHAAAA','CBAAAA','AAAAxx'
+690,29,0,2,0,10,0,90,90,190,690,0,1,'OAAAAA','DBAAAA','HHHHxx'
+69,30,1,1,9,9,9,69,69,69,69,18,19,'RCAAAA','EBAAAA','OOOOxx'
+358,31,0,2,8,18,8,58,158,358,358,16,17,'UNAAAA','FBAAAA','VVVVxx'
+269,32,1,1,9,9,9,69,69,269,269,18,19,'JKAAAA','GBAAAA','AAAAxx'
+663,33,1,3,3,3,3,63,63,163,663,6,7,'NZAAAA','HBAAAA','HHHHxx'
+608,34,0,0,8,8,8,8,8,108,608,16,17,'KXAAAA','IBAAAA','OOOOxx'
+398,35,0,2,8,18,8,98,198,398,398,16,17,'IPAAAA','JBAAAA','VVVVxx'
+330,36,0,2,0,10,0,30,130,330,330,0,1,'SMAAAA','KBAAAA','AAAAxx'
+529,37,1,1,9,9,9,29,129,29,529,18,19,'JUAAAA','LBAAAA','HHHHxx'
+555,38,1,3,5,15,5,55,155,55,555,10,11,'JVAAAA','MBAAAA','OOOOxx'
+746,39,0,2,6,6,6,46,146,246,746,12,13,'SCAAAA','NBAAAA','VVVVxx'
+558,40,0,2,8,18,8,58,158,58,558,16,17,'MVAAAA','OBAAAA','AAAAxx'
+574,41,0,2,4,14,4,74,174,74,574,8,9,'CWAAAA','PBAAAA','HHHHxx'
+343,42,1,3,3,3,3,43,143,343,343,6,7,'FNAAAA','QBAAAA','OOOOxx'
+120,43,0,0,0,0,0,20,120,120,120,0,1,'QEAAAA','RBAAAA','VVVVxx'
+461,44,1,1,1,1,1,61,61,461,461,2,3,'TRAAAA','SBAAAA','AAAAxx'
+754,45,0,2,4,14,4,54,154,254,754,8,9,'ADAAAA','TBAAAA','HHHHxx'
+772,46,0,0,2,12,2,72,172,272,772,4,5,'SDAAAA','UBAAAA','OOOOxx'
+749,47,1,1,9,9,9,49,149,249,749,18,19,'VCAAAA','VBAAAA','VVVVxx'
+386,48,0,2,6,6,6,86,186,386,386,12,13,'WOAAAA','WBAAAA','AAAAxx'
+9,49,1,1,9,9,9,9,9,9,9,18,19,'JAAAAA','XBAAAA','HHHHxx'
+771,50,1,3,1,11,1,71,171,271,771,2,3,'RDAAAA','YBAAAA','OOOOxx'
+470,51,0,2,0,10,0,70,70,470,470,0,1,'CSAAAA','ZBAAAA','VVVVxx'
+238,52,0,2,8,18,8,38,38,238,238,16,17,'EJAAAA','ACAAAA','AAAAxx'
+86,53,0,2,6,6,6,86,86,86,86,12,13,'IDAAAA','BCAAAA','HHHHxx'
+56,54,0,0,6,16,6,56,56,56,56,12,13,'ECAAAA','CCAAAA','OOOOxx'
+767,55,1,3,7,7,7,67,167,267,767,14,15,'NDAAAA','DCAAAA','VVVVxx'
+363,56,1,3,3,3,3,63,163,363,363,6,7,'ZNAAAA','ECAAAA','AAAAxx'
+655,57,1,3,5,15,5,55,55,155,655,10,11,'FZAAAA','FCAAAA','HHHHxx'
+394,58,0,2,4,14,4,94,194,394,394,8,9,'EPAAAA','GCAAAA','OOOOxx'
+223,59,1,3,3,3,3,23,23,223,223,6,7,'PIAAAA','HCAAAA','VVVVxx'
+946,60,0,2,6,6,6,46,146,446,946,12,13,'KKAAAA','ICAAAA','AAAAxx'
+863,61,1,3,3,3,3,63,63,363,863,6,7,'FHAAAA','JCAAAA','HHHHxx'
+913,62,1,1,3,13,3,13,113,413,913,6,7,'DJAAAA','KCAAAA','OOOOxx'
+737,63,1,1,7,17,7,37,137,237,737,14,15,'JCAAAA','LCAAAA','VVVVxx'
+65,64,1,1,5,5,5,65,65,65,65,10,11,'NCAAAA','MCAAAA','AAAAxx'
+251,65,1,3,1,11,1,51,51,251,251,2,3,'RJAAAA','NCAAAA','HHHHxx'
+686,66,0,2,6,6,6,86,86,186,686,12,13,'KAAAAA','OCAAAA','OOOOxx'
+971,67,1,3,1,11,1,71,171,471,971,2,3,'JLAAAA','PCAAAA','VVVVxx'
+775,68,1,3,5,15,5,75,175,275,775,10,11,'VDAAAA','QCAAAA','AAAAxx'
+577,69,1,1,7,17,7,77,177,77,577,14,15,'FWAAAA','RCAAAA','HHHHxx'
+830,70,0,2,0,10,0,30,30,330,830,0,1,'YFAAAA','SCAAAA','OOOOxx'
+787,71,1,3,7,7,7,87,187,287,787,14,15,'HEAAAA','TCAAAA','VVVVxx'
+898,72,0,2,8,18,8,98,98,398,898,16,17,'OIAAAA','UCAAAA','AAAAxx'
+588,73,0,0,8,8,8,88,188,88,588,16,17,'QWAAAA','VCAAAA','HHHHxx'
+872,74,0,0,2,12,2,72,72,372,872,4,5,'OHAAAA','WCAAAA','OOOOxx'
+397,75,1,1,7,17,7,97,197,397,397,14,15,'HPAAAA','XCAAAA','VVVVxx'
+51,76,1,3,1,11,1,51,51,51,51,2,3,'ZBAAAA','YCAAAA','AAAAxx'
+381,77,1,1,1,1,1,81,181,381,381,2,3,'ROAAAA','ZCAAAA','HHHHxx'
+632,78,0,0,2,12,2,32,32,132,632,4,5,'IYAAAA','ADAAAA','OOOOxx'
+31,79,1,3,1,11,1,31,31,31,31,2,3,'FBAAAA','BDAAAA','VVVVxx'
+855,80,1,3,5,15,5,55,55,355,855,10,11,'XGAAAA','CDAAAA','AAAAxx'
+699,81,1,3,9,19,9,99,99,199,699,18,19,'XAAAAA','DDAAAA','HHHHxx'
+562,82,0,2,2,2,2,62,162,62,562,4,5,'QVAAAA','EDAAAA','OOOOxx'
+681,83,1,1,1,1,1,81,81,181,681,2,3,'FAAAAA','FDAAAA','VVVVxx'
+585,84,1,1,5,5,5,85,185,85,585,10,11,'NWAAAA','GDAAAA','AAAAxx'
+35,85,1,3,5,15,5,35,35,35,35,10,11,'JBAAAA','HDAAAA','HHHHxx'
+962,86,0,2,2,2,2,62,162,462,962,4,5,'ALAAAA','IDAAAA','OOOOxx'
+282,87,0,2,2,2,2,82,82,282,282,4,5,'WKAAAA','JDAAAA','VVVVxx'
+254,88,0,2,4,14,4,54,54,254,254,8,9,'UJAAAA','KDAAAA','AAAAxx'
+514,89,0,2,4,14,4,14,114,14,514,8,9,'UTAAAA','LDAAAA','HHHHxx'
+406,90,0,2,6,6,6,6,6,406,406,12,13,'QPAAAA','MDAAAA','OOOOxx'
+544,91,0,0,4,4,4,44,144,44,544,8,9,'YUAAAA','NDAAAA','VVVVxx'
+704,92,0,0,4,4,4,4,104,204,704,8,9,'CBAAAA','ODAAAA','AAAAxx'
+948,93,0,0,8,8,8,48,148,448,948,16,17,'MKAAAA','PDAAAA','HHHHxx'
+412,94,0,0,2,12,2,12,12,412,412,4,5,'WPAAAA','QDAAAA','OOOOxx'
+200,95,0,0,0,0,0,0,0,200,200,0,1,'SHAAAA','RDAAAA','VVVVxx'
+583,96,1,3,3,3,3,83,183,83,583,6,7,'LWAAAA','SDAAAA','AAAAxx'
+486,97,0,2,6,6,6,86,86,486,486,12,13,'SSAAAA','TDAAAA','HHHHxx'
+666,98,0,2,6,6,6,66,66,166,666,12,13,'QZAAAA','UDAAAA','OOOOxx'
+436,99,0,0,6,16,6,36,36,436,436,12,13,'UQAAAA','VDAAAA','VVVVxx'
+842,100,0,2,2,2,2,42,42,342,842,4,5,'KGAAAA','WDAAAA','AAAAxx'
+99,101,1,3,9,19,9,99,99,99,99,18,19,'VDAAAA','XDAAAA','HHHHxx'
+656,102,0,0,6,16,6,56,56,156,656,12,13,'GZAAAA','YDAAAA','OOOOxx'
+673,103,1,1,3,13,3,73,73,173,673,6,7,'XZAAAA','ZDAAAA','VVVVxx'
+371,104,1,3,1,11,1,71,171,371,371,2,3,'HOAAAA','AEAAAA','AAAAxx'
+869,105,1,1,9,9,9,69,69,369,869,18,19,'LHAAAA','BEAAAA','HHHHxx'
+569,106,1,1,9,9,9,69,169,69,569,18,19,'XVAAAA','CEAAAA','OOOOxx'
+616,107,0,0,6,16,6,16,16,116,616,12,13,'SXAAAA','DEAAAA','VVVVxx'
+612,108,0,0,2,12,2,12,12,112,612,4,5,'OXAAAA','EEAAAA','AAAAxx'
+505,109,1,1,5,5,5,5,105,5,505,10,11,'LTAAAA','FEAAAA','HHHHxx'
+922,110,0,2,2,2,2,22,122,422,922,4,5,'MJAAAA','GEAAAA','OOOOxx'
+221,111,1,1,1,1,1,21,21,221,221,2,3,'NIAAAA','HEAAAA','VVVVxx'
+388,112,0,0,8,8,8,88,188,388,388,16,17,'YOAAAA','IEAAAA','AAAAxx'
+567,113,1,3,7,7,7,67,167,67,567,14,15,'VVAAAA','JEAAAA','HHHHxx'
+58,114,0,2,8,18,8,58,58,58,58,16,17,'GCAAAA','KEAAAA','OOOOxx'
+316,115,0,0,6,16,6,16,116,316,316,12,13,'EMAAAA','LEAAAA','VVVVxx'
+659,116,1,3,9,19,9,59,59,159,659,18,19,'JZAAAA','MEAAAA','AAAAxx'
+501,117,1,1,1,1,1,1,101,1,501,2,3,'HTAAAA','NEAAAA','HHHHxx'
+815,118,1,3,5,15,5,15,15,315,815,10,11,'JFAAAA','OEAAAA','OOOOxx'
+638,119,0,2,8,18,8,38,38,138,638,16,17,'OYAAAA','PEAAAA','VVVVxx'
+696,120,0,0,6,16,6,96,96,196,696,12,13,'UAAAAA','QEAAAA','AAAAxx'
+734,121,0,2,4,14,4,34,134,234,734,8,9,'GCAAAA','REAAAA','HHHHxx'
+237,122,1,1,7,17,7,37,37,237,237,14,15,'DJAAAA','SEAAAA','OOOOxx'
+816,123,0,0,6,16,6,16,16,316,816,12,13,'KFAAAA','TEAAAA','VVVVxx'
+917,124,1,1,7,17,7,17,117,417,917,14,15,'HJAAAA','UEAAAA','AAAAxx'
+844,125,0,0,4,4,4,44,44,344,844,8,9,'MGAAAA','VEAAAA','HHHHxx'
+657,126,1,1,7,17,7,57,57,157,657,14,15,'HZAAAA','WEAAAA','OOOOxx'
+952,127,0,0,2,12,2,52,152,452,952,4,5,'QKAAAA','XEAAAA','VVVVxx'
+519,128,1,3,9,19,9,19,119,19,519,18,19,'ZTAAAA','YEAAAA','AAAAxx'
+792,129,0,0,2,12,2,92,192,292,792,4,5,'MEAAAA','ZEAAAA','HHHHxx'
+275,130,1,3,5,15,5,75,75,275,275,10,11,'PKAAAA','AFAAAA','OOOOxx'
+319,131,1,3,9,19,9,19,119,319,319,18,19,'HMAAAA','BFAAAA','VVVVxx'
+487,132,1,3,7,7,7,87,87,487,487,14,15,'TSAAAA','CFAAAA','AAAAxx'
+945,133,1,1,5,5,5,45,145,445,945,10,11,'JKAAAA','DFAAAA','HHHHxx'
+584,134,0,0,4,4,4,84,184,84,584,8,9,'MWAAAA','EFAAAA','OOOOxx'
+765,135,1,1,5,5,5,65,165,265,765,10,11,'LDAAAA','FFAAAA','VVVVxx'
+814,136,0,2,4,14,4,14,14,314,814,8,9,'IFAAAA','GFAAAA','AAAAxx'
+359,137,1,3,9,19,9,59,159,359,359,18,19,'VNAAAA','HFAAAA','HHHHxx'
+548,138,0,0,8,8,8,48,148,48,548,16,17,'CVAAAA','IFAAAA','OOOOxx'
+811,139,1,3,1,11,1,11,11,311,811,2,3,'FFAAAA','JFAAAA','VVVVxx'
+531,140,1,3,1,11,1,31,131,31,531,2,3,'LUAAAA','KFAAAA','AAAAxx'
+104,141,0,0,4,4,4,4,104,104,104,8,9,'AEAAAA','LFAAAA','HHHHxx'
+33,142,1,1,3,13,3,33,33,33,33,6,7,'HBAAAA','MFAAAA','OOOOxx'
+404,143,0,0,4,4,4,4,4,404,404,8,9,'OPAAAA','NFAAAA','VVVVxx'
+995,144,1,3,5,15,5,95,195,495,995,10,11,'HMAAAA','OFAAAA','AAAAxx'
+408,145,0,0,8,8,8,8,8,408,408,16,17,'SPAAAA','PFAAAA','HHHHxx'
+93,146,1,1,3,13,3,93,93,93,93,6,7,'PDAAAA','QFAAAA','OOOOxx'
+794,147,0,2,4,14,4,94,194,294,794,8,9,'OEAAAA','RFAAAA','VVVVxx'
+833,148,1,1,3,13,3,33,33,333,833,6,7,'BGAAAA','SFAAAA','AAAAxx'
+615,149,1,3,5,15,5,15,15,115,615,10,11,'RXAAAA','TFAAAA','HHHHxx'
+333,150,1,1,3,13,3,33,133,333,333,6,7,'VMAAAA','UFAAAA','OOOOxx'
+357,151,1,1,7,17,7,57,157,357,357,14,15,'TNAAAA','VFAAAA','VVVVxx'
+999,152,1,3,9,19,9,99,199,499,999,18,19,'LMAAAA','WFAAAA','AAAAxx'
+515,153,1,3,5,15,5,15,115,15,515,10,11,'VTAAAA','XFAAAA','HHHHxx'
+685,154,1,1,5,5,5,85,85,185,685,10,11,'JAAAAA','YFAAAA','OOOOxx'
+692,155,0,0,2,12,2,92,92,192,692,4,5,'QAAAAA','ZFAAAA','VVVVxx'
+627,156,1,3,7,7,7,27,27,127,627,14,15,'DYAAAA','AGAAAA','AAAAxx'
+654,157,0,2,4,14,4,54,54,154,654,8,9,'EZAAAA','BGAAAA','HHHHxx'
+115,158,1,3,5,15,5,15,115,115,115,10,11,'LEAAAA','CGAAAA','OOOOxx'
+75,159,1,3,5,15,5,75,75,75,75,10,11,'XCAAAA','DGAAAA','VVVVxx'
+14,160,0,2,4,14,4,14,14,14,14,8,9,'OAAAAA','EGAAAA','AAAAxx'
+148,161,0,0,8,8,8,48,148,148,148,16,17,'SFAAAA','FGAAAA','HHHHxx'
+201,162,1,1,1,1,1,1,1,201,201,2,3,'THAAAA','GGAAAA','OOOOxx'
+862,163,0,2,2,2,2,62,62,362,862,4,5,'EHAAAA','HGAAAA','VVVVxx'
+634,164,0,2,4,14,4,34,34,134,634,8,9,'KYAAAA','IGAAAA','AAAAxx'
+589,165,1,1,9,9,9,89,189,89,589,18,19,'RWAAAA','JGAAAA','HHHHxx'
+142,166,0,2,2,2,2,42,142,142,142,4,5,'MFAAAA','KGAAAA','OOOOxx'
+545,167,1,1,5,5,5,45,145,45,545,10,11,'ZUAAAA','LGAAAA','VVVVxx'
+983,168,1,3,3,3,3,83,183,483,983,6,7,'VLAAAA','MGAAAA','AAAAxx'
+87,169,1,3,7,7,7,87,87,87,87,14,15,'JDAAAA','NGAAAA','HHHHxx'
+335,170,1,3,5,15,5,35,135,335,335,10,11,'XMAAAA','OGAAAA','OOOOxx'
+915,171,1,3,5,15,5,15,115,415,915,10,11,'FJAAAA','PGAAAA','VVVVxx'
+286,172,0,2,6,6,6,86,86,286,286,12,13,'ALAAAA','QGAAAA','AAAAxx'
+361,173,1,1,1,1,1,61,161,361,361,2,3,'XNAAAA','RGAAAA','HHHHxx'
+97,174,1,1,7,17,7,97,97,97,97,14,15,'TDAAAA','SGAAAA','OOOOxx'
+98,175,0,2,8,18,8,98,98,98,98,16,17,'UDAAAA','TGAAAA','VVVVxx'
+377,176,1,1,7,17,7,77,177,377,377,14,15,'NOAAAA','UGAAAA','AAAAxx'
+525,177,1,1,5,5,5,25,125,25,525,10,11,'FUAAAA','VGAAAA','HHHHxx'
+448,178,0,0,8,8,8,48,48,448,448,16,17,'GRAAAA','WGAAAA','OOOOxx'
+154,179,0,2,4,14,4,54,154,154,154,8,9,'YFAAAA','XGAAAA','VVVVxx'
+866,180,0,2,6,6,6,66,66,366,866,12,13,'IHAAAA','YGAAAA','AAAAxx'
+741,181,1,1,1,1,1,41,141,241,741,2,3,'NCAAAA','ZGAAAA','HHHHxx'
+172,182,0,0,2,12,2,72,172,172,172,4,5,'QGAAAA','AHAAAA','OOOOxx'
+843,183,1,3,3,3,3,43,43,343,843,6,7,'LGAAAA','BHAAAA','VVVVxx'
+378,184,0,2,8,18,8,78,178,378,378,16,17,'OOAAAA','CHAAAA','AAAAxx'
+804,185,0,0,4,4,4,4,4,304,804,8,9,'YEAAAA','DHAAAA','HHHHxx'
+596,186,0,0,6,16,6,96,196,96,596,12,13,'YWAAAA','EHAAAA','OOOOxx'
+77,187,1,1,7,17,7,77,77,77,77,14,15,'ZCAAAA','FHAAAA','VVVVxx'
+572,188,0,0,2,12,2,72,172,72,572,4,5,'AWAAAA','GHAAAA','AAAAxx'
+444,189,0,0,4,4,4,44,44,444,444,8,9,'CRAAAA','HHAAAA','HHHHxx'
+47,190,1,3,7,7,7,47,47,47,47,14,15,'VBAAAA','IHAAAA','OOOOxx'
+274,191,0,2,4,14,4,74,74,274,274,8,9,'OKAAAA','JHAAAA','VVVVxx'
+40,192,0,0,0,0,0,40,40,40,40,0,1,'OBAAAA','KHAAAA','AAAAxx'
+339,193,1,3,9,19,9,39,139,339,339,18,19,'BNAAAA','LHAAAA','HHHHxx'
+13,194,1,1,3,13,3,13,13,13,13,6,7,'NAAAAA','MHAAAA','OOOOxx'
+878,195,0,2,8,18,8,78,78,378,878,16,17,'UHAAAA','NHAAAA','VVVVxx'
+53,196,1,1,3,13,3,53,53,53,53,6,7,'BCAAAA','OHAAAA','AAAAxx'
+939,197,1,3,9,19,9,39,139,439,939,18,19,'DKAAAA','PHAAAA','HHHHxx'
+928,198,0,0,8,8,8,28,128,428,928,16,17,'SJAAAA','QHAAAA','OOOOxx'
+886,199,0,2,6,6,6,86,86,386,886,12,13,'CIAAAA','RHAAAA','VVVVxx'
+267,200,1,3,7,7,7,67,67,267,267,14,15,'HKAAAA','SHAAAA','AAAAxx'
+105,201,1,1,5,5,5,5,105,105,105,10,11,'BEAAAA','THAAAA','HHHHxx'
+312,202,0,0,2,12,2,12,112,312,312,4,5,'AMAAAA','UHAAAA','OOOOxx'
+552,203,0,0,2,12,2,52,152,52,552,4,5,'GVAAAA','VHAAAA','VVVVxx'
+918,204,0,2,8,18,8,18,118,418,918,16,17,'IJAAAA','WHAAAA','AAAAxx'
+114,205,0,2,4,14,4,14,114,114,114,8,9,'KEAAAA','XHAAAA','HHHHxx'
+805,206,1,1,5,5,5,5,5,305,805,10,11,'ZEAAAA','YHAAAA','OOOOxx'
+875,207,1,3,5,15,5,75,75,375,875,10,11,'RHAAAA','ZHAAAA','VVVVxx'
+225,208,1,1,5,5,5,25,25,225,225,10,11,'RIAAAA','AIAAAA','AAAAxx'
+495,209,1,3,5,15,5,95,95,495,495,10,11,'BTAAAA','BIAAAA','HHHHxx'
+150,210,0,2,0,10,0,50,150,150,150,0,1,'UFAAAA','CIAAAA','OOOOxx'
+759,211,1,3,9,19,9,59,159,259,759,18,19,'FDAAAA','DIAAAA','VVVVxx'
+149,212,1,1,9,9,9,49,149,149,149,18,19,'TFAAAA','EIAAAA','AAAAxx'
+480,213,0,0,0,0,0,80,80,480,480,0,1,'MSAAAA','FIAAAA','HHHHxx'
+1,214,1,1,1,1,1,1,1,1,1,2,3,'BAAAAA','GIAAAA','OOOOxx'
+557,215,1,1,7,17,7,57,157,57,557,14,15,'LVAAAA','HIAAAA','VVVVxx'
+295,216,1,3,5,15,5,95,95,295,295,10,11,'JLAAAA','IIAAAA','AAAAxx'
+854,217,0,2,4,14,4,54,54,354,854,8,9,'WGAAAA','JIAAAA','HHHHxx'
+420,218,0,0,0,0,0,20,20,420,420,0,1,'EQAAAA','KIAAAA','OOOOxx'
+414,219,0,2,4,14,4,14,14,414,414,8,9,'YPAAAA','LIAAAA','VVVVxx'
+758,220,0,2,8,18,8,58,158,258,758,16,17,'EDAAAA','MIAAAA','AAAAxx'
+879,221,1,3,9,19,9,79,79,379,879,18,19,'VHAAAA','NIAAAA','HHHHxx'
+332,222,0,0,2,12,2,32,132,332,332,4,5,'UMAAAA','OIAAAA','OOOOxx'
+78,223,0,2,8,18,8,78,78,78,78,16,17,'ADAAAA','PIAAAA','VVVVxx'
+851,224,1,3,1,11,1,51,51,351,851,2,3,'TGAAAA','QIAAAA','AAAAxx'
+592,225,0,0,2,12,2,92,192,92,592,4,5,'UWAAAA','RIAAAA','HHHHxx'
+979,226,1,3,9,19,9,79,179,479,979,18,19,'RLAAAA','SIAAAA','OOOOxx'
+989,227,1,1,9,9,9,89,189,489,989,18,19,'BMAAAA','TIAAAA','VVVVxx'
+752,228,0,0,2,12,2,52,152,252,752,4,5,'YCAAAA','UIAAAA','AAAAxx'
+214,229,0,2,4,14,4,14,14,214,214,8,9,'GIAAAA','VIAAAA','HHHHxx'
+453,230,1,1,3,13,3,53,53,453,453,6,7,'LRAAAA','WIAAAA','OOOOxx'
+540,231,0,0,0,0,0,40,140,40,540,0,1,'UUAAAA','XIAAAA','VVVVxx'
+597,232,1,1,7,17,7,97,197,97,597,14,15,'ZWAAAA','YIAAAA','AAAAxx'
+356,233,0,0,6,16,6,56,156,356,356,12,13,'SNAAAA','ZIAAAA','HHHHxx'
+720,234,0,0,0,0,0,20,120,220,720,0,1,'SBAAAA','AJAAAA','OOOOxx'
+367,235,1,3,7,7,7,67,167,367,367,14,15,'DOAAAA','BJAAAA','VVVVxx'
+762,236,0,2,2,2,2,62,162,262,762,4,5,'IDAAAA','CJAAAA','AAAAxx'
+986,237,0,2,6,6,6,86,186,486,986,12,13,'YLAAAA','DJAAAA','HHHHxx'
+924,238,0,0,4,4,4,24,124,424,924,8,9,'OJAAAA','EJAAAA','OOOOxx'
+779,239,1,3,9,19,9,79,179,279,779,18,19,'ZDAAAA','FJAAAA','VVVVxx'
+684,240,0,0,4,4,4,84,84,184,684,8,9,'IAAAAA','GJAAAA','AAAAxx'
+413,241,1,1,3,13,3,13,13,413,413,6,7,'XPAAAA','HJAAAA','HHHHxx'
+479,242,1,3,9,19,9,79,79,479,479,18,19,'LSAAAA','IJAAAA','OOOOxx'
+731,243,1,3,1,11,1,31,131,231,731,2,3,'DCAAAA','JJAAAA','VVVVxx'
+409,244,1,1,9,9,9,9,9,409,409,18,19,'TPAAAA','KJAAAA','AAAAxx'
+372,245,0,0,2,12,2,72,172,372,372,4,5,'IOAAAA','LJAAAA','HHHHxx'
+139,246,1,3,9,19,9,39,139,139,139,18,19,'JFAAAA','MJAAAA','OOOOxx'
+717,247,1,1,7,17,7,17,117,217,717,14,15,'PBAAAA','NJAAAA','VVVVxx'
+539,248,1,3,9,19,9,39,139,39,539,18,19,'TUAAAA','OJAAAA','AAAAxx'
+318,249,0,2,8,18,8,18,118,318,318,16,17,'GMAAAA','PJAAAA','HHHHxx'
+208,250,0,0,8,8,8,8,8,208,208,16,17,'AIAAAA','QJAAAA','OOOOxx'
+797,251,1,1,7,17,7,97,197,297,797,14,15,'REAAAA','RJAAAA','VVVVxx'
+661,252,1,1,1,1,1,61,61,161,661,2,3,'LZAAAA','SJAAAA','AAAAxx'
+50,253,0,2,0,10,0,50,50,50,50,0,1,'YBAAAA','TJAAAA','HHHHxx'
+102,254,0,2,2,2,2,2,102,102,102,4,5,'YDAAAA','UJAAAA','OOOOxx'
+484,255,0,0,4,4,4,84,84,484,484,8,9,'QSAAAA','VJAAAA','VVVVxx'
+108,256,0,0,8,8,8,8,108,108,108,16,17,'EEAAAA','WJAAAA','AAAAxx'
+140,257,0,0,0,0,0,40,140,140,140,0,1,'KFAAAA','XJAAAA','HHHHxx'
+996,258,0,0,6,16,6,96,196,496,996,12,13,'IMAAAA','YJAAAA','OOOOxx'
+687,259,1,3,7,7,7,87,87,187,687,14,15,'LAAAAA','ZJAAAA','VVVVxx'
+241,260,1,1,1,1,1,41,41,241,241,2,3,'HJAAAA','AKAAAA','AAAAxx'
+923,261,1,3,3,3,3,23,123,423,923,6,7,'NJAAAA','BKAAAA','HHHHxx'
+500,262,0,0,0,0,0,0,100,0,500,0,1,'GTAAAA','CKAAAA','OOOOxx'
+536,263,0,0,6,16,6,36,136,36,536,12,13,'QUAAAA','DKAAAA','VVVVxx'
+490,264,0,2,0,10,0,90,90,490,490,0,1,'WSAAAA','EKAAAA','AAAAxx'
+773,265,1,1,3,13,3,73,173,273,773,6,7,'TDAAAA','FKAAAA','HHHHxx'
+19,266,1,3,9,19,9,19,19,19,19,18,19,'TAAAAA','GKAAAA','OOOOxx'
+534,267,0,2,4,14,4,34,134,34,534,8,9,'OUAAAA','HKAAAA','VVVVxx'
+941,268,1,1,1,1,1,41,141,441,941,2,3,'FKAAAA','IKAAAA','AAAAxx'
+477,269,1,1,7,17,7,77,77,477,477,14,15,'JSAAAA','JKAAAA','HHHHxx'
+173,270,1,1,3,13,3,73,173,173,173,6,7,'RGAAAA','KKAAAA','OOOOxx'
+113,271,1,1,3,13,3,13,113,113,113,6,7,'JEAAAA','LKAAAA','VVVVxx'
+526,272,0,2,6,6,6,26,126,26,526,12,13,'GUAAAA','MKAAAA','AAAAxx'
+727,273,1,3,7,7,7,27,127,227,727,14,15,'ZBAAAA','NKAAAA','HHHHxx'
+302,274,0,2,2,2,2,2,102,302,302,4,5,'QLAAAA','OKAAAA','OOOOxx'
+789,275,1,1,9,9,9,89,189,289,789,18,19,'JEAAAA','PKAAAA','VVVVxx'
+447,276,1,3,7,7,7,47,47,447,447,14,15,'FRAAAA','QKAAAA','AAAAxx'
+884,277,0,0,4,4,4,84,84,384,884,8,9,'AIAAAA','RKAAAA','HHHHxx'
+718,278,0,2,8,18,8,18,118,218,718,16,17,'QBAAAA','SKAAAA','OOOOxx'
+818,279,0,2,8,18,8,18,18,318,818,16,17,'MFAAAA','TKAAAA','VVVVxx'
+466,280,0,2,6,6,6,66,66,466,466,12,13,'YRAAAA','UKAAAA','AAAAxx'
+131,281,1,3,1,11,1,31,131,131,131,2,3,'BFAAAA','VKAAAA','HHHHxx'
+503,282,1,3,3,3,3,3,103,3,503,6,7,'JTAAAA','WKAAAA','OOOOxx'
+364,283,0,0,4,4,4,64,164,364,364,8,9,'AOAAAA','XKAAAA','VVVVxx'
+934,284,0,2,4,14,4,34,134,434,934,8,9,'YJAAAA','YKAAAA','AAAAxx'
+542,285,0,2,2,2,2,42,142,42,542,4,5,'WUAAAA','ZKAAAA','HHHHxx'
+146,286,0,2,6,6,6,46,146,146,146,12,13,'QFAAAA','ALAAAA','OOOOxx'
+652,287,0,0,2,12,2,52,52,152,652,4,5,'CZAAAA','BLAAAA','VVVVxx'
+566,288,0,2,6,6,6,66,166,66,566,12,13,'UVAAAA','CLAAAA','AAAAxx'
+788,289,0,0,8,8,8,88,188,288,788,16,17,'IEAAAA','DLAAAA','HHHHxx'
+168,290,0,0,8,8,8,68,168,168,168,16,17,'MGAAAA','ELAAAA','OOOOxx'
+736,291,0,0,6,16,6,36,136,236,736,12,13,'ICAAAA','FLAAAA','VVVVxx'
+795,292,1,3,5,15,5,95,195,295,795,10,11,'PEAAAA','GLAAAA','AAAAxx'
+103,293,1,3,3,3,3,3,103,103,103,6,7,'ZDAAAA','HLAAAA','HHHHxx'
+763,294,1,3,3,3,3,63,163,263,763,6,7,'JDAAAA','ILAAAA','OOOOxx'
+256,295,0,0,6,16,6,56,56,256,256,12,13,'WJAAAA','JLAAAA','VVVVxx'
+63,296,1,3,3,3,3,63,63,63,63,6,7,'LCAAAA','KLAAAA','AAAAxx'
+702,297,0,2,2,2,2,2,102,202,702,4,5,'ABAAAA','LLAAAA','HHHHxx'
+390,298,0,2,0,10,0,90,190,390,390,0,1,'APAAAA','MLAAAA','OOOOxx'
+116,299,0,0,6,16,6,16,116,116,116,12,13,'MEAAAA','NLAAAA','VVVVxx'
+354,300,0,2,4,14,4,54,154,354,354,8,9,'QNAAAA','OLAAAA','AAAAxx'
+162,301,0,2,2,2,2,62,162,162,162,4,5,'GGAAAA','PLAAAA','HHHHxx'
+71,302,1,3,1,11,1,71,71,71,71,2,3,'TCAAAA','QLAAAA','OOOOxx'
+916,303,0,0,6,16,6,16,116,416,916,12,13,'GJAAAA','RLAAAA','VVVVxx'
+565,304,1,1,5,5,5,65,165,65,565,10,11,'TVAAAA','SLAAAA','AAAAxx'
+509,305,1,1,9,9,9,9,109,9,509,18,19,'PTAAAA','TLAAAA','HHHHxx'
+20,306,0,0,0,0,0,20,20,20,20,0,1,'UAAAAA','ULAAAA','OOOOxx'
+813,307,1,1,3,13,3,13,13,313,813,6,7,'HFAAAA','VLAAAA','VVVVxx'
+80,308,0,0,0,0,0,80,80,80,80,0,1,'CDAAAA','WLAAAA','AAAAxx'
+400,309,0,0,0,0,0,0,0,400,400,0,1,'KPAAAA','XLAAAA','HHHHxx'
+888,310,0,0,8,8,8,88,88,388,888,16,17,'EIAAAA','YLAAAA','OOOOxx'
+825,311,1,1,5,5,5,25,25,325,825,10,11,'TFAAAA','ZLAAAA','VVVVxx'
+401,312,1,1,1,1,1,1,1,401,401,2,3,'LPAAAA','AMAAAA','AAAAxx'
+158,313,0,2,8,18,8,58,158,158,158,16,17,'CGAAAA','BMAAAA','HHHHxx'
+973,314,1,1,3,13,3,73,173,473,973,6,7,'LLAAAA','CMAAAA','OOOOxx'
+324,315,0,0,4,4,4,24,124,324,324,8,9,'MMAAAA','DMAAAA','VVVVxx'
+873,316,1,1,3,13,3,73,73,373,873,6,7,'PHAAAA','EMAAAA','AAAAxx'
+676,317,0,0,6,16,6,76,76,176,676,12,13,'AAAAAA','FMAAAA','HHHHxx'
+199,318,1,3,9,19,9,99,199,199,199,18,19,'RHAAAA','GMAAAA','OOOOxx'
+304,319,0,0,4,4,4,4,104,304,304,8,9,'SLAAAA','HMAAAA','VVVVxx'
+338,320,0,2,8,18,8,38,138,338,338,16,17,'ANAAAA','IMAAAA','AAAAxx'
+743,321,1,3,3,3,3,43,143,243,743,6,7,'PCAAAA','JMAAAA','HHHHxx'
+730,322,0,2,0,10,0,30,130,230,730,0,1,'CCAAAA','KMAAAA','OOOOxx'
+130,323,0,2,0,10,0,30,130,130,130,0,1,'AFAAAA','LMAAAA','VVVVxx'
+224,324,0,0,4,4,4,24,24,224,224,8,9,'QIAAAA','MMAAAA','AAAAxx'
+216,325,0,0,6,16,6,16,16,216,216,12,13,'IIAAAA','NMAAAA','HHHHxx'
+2,326,0,2,2,2,2,2,2,2,2,4,5,'CAAAAA','OMAAAA','OOOOxx'
+836,327,0,0,6,16,6,36,36,336,836,12,13,'EGAAAA','PMAAAA','VVVVxx'
+443,328,1,3,3,3,3,43,43,443,443,6,7,'BRAAAA','QMAAAA','AAAAxx'
+777,329,1,1,7,17,7,77,177,277,777,14,15,'XDAAAA','RMAAAA','HHHHxx'
+126,330,0,2,6,6,6,26,126,126,126,12,13,'WEAAAA','SMAAAA','OOOOxx'
+117,331,1,1,7,17,7,17,117,117,117,14,15,'NEAAAA','TMAAAA','VVVVxx'
+633,332,1,1,3,13,3,33,33,133,633,6,7,'JYAAAA','UMAAAA','AAAAxx'
+310,333,0,2,0,10,0,10,110,310,310,0,1,'YLAAAA','VMAAAA','HHHHxx'
+622,334,0,2,2,2,2,22,22,122,622,4,5,'YXAAAA','WMAAAA','OOOOxx'
+268,335,0,0,8,8,8,68,68,268,268,16,17,'IKAAAA','XMAAAA','VVVVxx'
+384,336,0,0,4,4,4,84,184,384,384,8,9,'UOAAAA','YMAAAA','AAAAxx'
+460,337,0,0,0,0,0,60,60,460,460,0,1,'SRAAAA','ZMAAAA','HHHHxx'
+475,338,1,3,5,15,5,75,75,475,475,10,11,'HSAAAA','ANAAAA','OOOOxx'
+624,339,0,0,4,4,4,24,24,124,624,8,9,'AYAAAA','BNAAAA','VVVVxx'
+826,340,0,2,6,6,6,26,26,326,826,12,13,'UFAAAA','CNAAAA','AAAAxx'
+680,341,0,0,0,0,0,80,80,180,680,0,1,'EAAAAA','DNAAAA','HHHHxx'
+306,342,0,2,6,6,6,6,106,306,306,12,13,'ULAAAA','ENAAAA','OOOOxx'
+896,343,0,0,6,16,6,96,96,396,896,12,13,'MIAAAA','FNAAAA','VVVVxx'
+30,344,0,2,0,10,0,30,30,30,30,0,1,'EBAAAA','GNAAAA','AAAAxx'
+576,345,0,0,6,16,6,76,176,76,576,12,13,'EWAAAA','HNAAAA','HHHHxx'
+551,346,1,3,1,11,1,51,151,51,551,2,3,'FVAAAA','INAAAA','OOOOxx'
+639,347,1,3,9,19,9,39,39,139,639,18,19,'PYAAAA','JNAAAA','VVVVxx'
+975,348,1,3,5,15,5,75,175,475,975,10,11,'NLAAAA','KNAAAA','AAAAxx'
+882,349,0,2,2,2,2,82,82,382,882,4,5,'YHAAAA','LNAAAA','HHHHxx'
+160,350,0,0,0,0,0,60,160,160,160,0,1,'EGAAAA','MNAAAA','OOOOxx'
+522,351,0,2,2,2,2,22,122,22,522,4,5,'CUAAAA','NNAAAA','VVVVxx'
+620,352,0,0,0,0,0,20,20,120,620,0,1,'WXAAAA','ONAAAA','AAAAxx'
+719,353,1,3,9,19,9,19,119,219,719,18,19,'RBAAAA','PNAAAA','HHHHxx'
+88,354,0,0,8,8,8,88,88,88,88,16,17,'KDAAAA','QNAAAA','OOOOxx'
+614,355,0,2,4,14,4,14,14,114,614,8,9,'QXAAAA','RNAAAA','VVVVxx'
+54,356,0,2,4,14,4,54,54,54,54,8,9,'CCAAAA','SNAAAA','AAAAxx'
+209,357,1,1,9,9,9,9,9,209,209,18,19,'BIAAAA','TNAAAA','HHHHxx'
+67,358,1,3,7,7,7,67,67,67,67,14,15,'PCAAAA','UNAAAA','OOOOxx'
+809,359,1,1,9,9,9,9,9,309,809,18,19,'DFAAAA','VNAAAA','VVVVxx'
+982,360,0,2,2,2,2,82,182,482,982,4,5,'ULAAAA','WNAAAA','AAAAxx'
+817,361,1,1,7,17,7,17,17,317,817,14,15,'LFAAAA','XNAAAA','HHHHxx'
+187,362,1,3,7,7,7,87,187,187,187,14,15,'FHAAAA','YNAAAA','OOOOxx'
+992,363,0,0,2,12,2,92,192,492,992,4,5,'EMAAAA','ZNAAAA','VVVVxx'
+580,364,0,0,0,0,0,80,180,80,580,0,1,'IWAAAA','AOAAAA','AAAAxx'
+658,365,0,2,8,18,8,58,58,158,658,16,17,'IZAAAA','BOAAAA','HHHHxx'
+222,366,0,2,2,2,2,22,22,222,222,4,5,'OIAAAA','COAAAA','OOOOxx'
+667,367,1,3,7,7,7,67,67,167,667,14,15,'RZAAAA','DOAAAA','VVVVxx'
+715,368,1,3,5,15,5,15,115,215,715,10,11,'NBAAAA','EOAAAA','AAAAxx'
+990,369,0,2,0,10,0,90,190,490,990,0,1,'CMAAAA','FOAAAA','HHHHxx'
+22,370,0,2,2,2,2,22,22,22,22,4,5,'WAAAAA','GOAAAA','OOOOxx'
+362,371,0,2,2,2,2,62,162,362,362,4,5,'YNAAAA','HOAAAA','VVVVxx'
+376,372,0,0,6,16,6,76,176,376,376,12,13,'MOAAAA','IOAAAA','AAAAxx'
+246,373,0,2,6,6,6,46,46,246,246,12,13,'MJAAAA','JOAAAA','HHHHxx'
+300,374,0,0,0,0,0,0,100,300,300,0,1,'OLAAAA','KOAAAA','OOOOxx'
+231,375,1,3,1,11,1,31,31,231,231,2,3,'XIAAAA','LOAAAA','VVVVxx'
+151,376,1,3,1,11,1,51,151,151,151,2,3,'VFAAAA','MOAAAA','AAAAxx'
+29,377,1,1,9,9,9,29,29,29,29,18,19,'DBAAAA','NOAAAA','HHHHxx'
+297,378,1,1,7,17,7,97,97,297,297,14,15,'LLAAAA','OOAAAA','OOOOxx'
+403,379,1,3,3,3,3,3,3,403,403,6,7,'NPAAAA','POAAAA','VVVVxx'
+716,380,0,0,6,16,6,16,116,216,716,12,13,'OBAAAA','QOAAAA','AAAAxx'
+260,381,0,0,0,0,0,60,60,260,260,0,1,'AKAAAA','ROAAAA','HHHHxx'
+170,382,0,2,0,10,0,70,170,170,170,0,1,'OGAAAA','SOAAAA','OOOOxx'
+285,383,1,1,5,5,5,85,85,285,285,10,11,'ZKAAAA','TOAAAA','VVVVxx'
+82,384,0,2,2,2,2,82,82,82,82,4,5,'EDAAAA','UOAAAA','AAAAxx'
+958,385,0,2,8,18,8,58,158,458,958,16,17,'WKAAAA','VOAAAA','HHHHxx'
+175,386,1,3,5,15,5,75,175,175,175,10,11,'TGAAAA','WOAAAA','OOOOxx'
+671,387,1,3,1,11,1,71,71,171,671,2,3,'VZAAAA','XOAAAA','VVVVxx'
+822,388,0,2,2,2,2,22,22,322,822,4,5,'QFAAAA','YOAAAA','AAAAxx'
+573,389,1,1,3,13,3,73,173,73,573,6,7,'BWAAAA','ZOAAAA','HHHHxx'
+723,390,1,3,3,3,3,23,123,223,723,6,7,'VBAAAA','APAAAA','OOOOxx'
+195,391,1,3,5,15,5,95,195,195,195,10,11,'NHAAAA','BPAAAA','VVVVxx'
+197,392,1,1,7,17,7,97,197,197,197,14,15,'PHAAAA','CPAAAA','AAAAxx'
+755,393,1,3,5,15,5,55,155,255,755,10,11,'BDAAAA','DPAAAA','HHHHxx'
+42,394,0,2,2,2,2,42,42,42,42,4,5,'QBAAAA','EPAAAA','OOOOxx'
+897,395,1,1,7,17,7,97,97,397,897,14,15,'NIAAAA','FPAAAA','VVVVxx'
+309,396,1,1,9,9,9,9,109,309,309,18,19,'XLAAAA','GPAAAA','AAAAxx'
+724,397,0,0,4,4,4,24,124,224,724,8,9,'WBAAAA','HPAAAA','HHHHxx'
+474,398,0,2,4,14,4,74,74,474,474,8,9,'GSAAAA','IPAAAA','OOOOxx'
+345,399,1,1,5,5,5,45,145,345,345,10,11,'HNAAAA','JPAAAA','VVVVxx'
+678,400,0,2,8,18,8,78,78,178,678,16,17,'CAAAAA','KPAAAA','AAAAxx'
+757,401,1,1,7,17,7,57,157,257,757,14,15,'DDAAAA','LPAAAA','HHHHxx'
+600,402,0,0,0,0,0,0,0,100,600,0,1,'CXAAAA','MPAAAA','OOOOxx'
+184,403,0,0,4,4,4,84,184,184,184,8,9,'CHAAAA','NPAAAA','VVVVxx'
+155,404,1,3,5,15,5,55,155,155,155,10,11,'ZFAAAA','OPAAAA','AAAAxx'
+136,405,0,0,6,16,6,36,136,136,136,12,13,'GFAAAA','PPAAAA','HHHHxx'
+889,406,1,1,9,9,9,89,89,389,889,18,19,'FIAAAA','QPAAAA','OOOOxx'
+95,407,1,3,5,15,5,95,95,95,95,10,11,'RDAAAA','RPAAAA','VVVVxx'
+549,408,1,1,9,9,9,49,149,49,549,18,19,'DVAAAA','SPAAAA','AAAAxx'
+81,409,1,1,1,1,1,81,81,81,81,2,3,'DDAAAA','TPAAAA','HHHHxx'
+679,410,1,3,9,19,9,79,79,179,679,18,19,'DAAAAA','UPAAAA','OOOOxx'
+27,411,1,3,7,7,7,27,27,27,27,14,15,'BBAAAA','VPAAAA','VVVVxx'
+748,412,0,0,8,8,8,48,148,248,748,16,17,'UCAAAA','WPAAAA','AAAAxx'
+107,413,1,3,7,7,7,7,107,107,107,14,15,'DEAAAA','XPAAAA','HHHHxx'
+870,414,0,2,0,10,0,70,70,370,870,0,1,'MHAAAA','YPAAAA','OOOOxx'
+848,415,0,0,8,8,8,48,48,348,848,16,17,'QGAAAA','ZPAAAA','VVVVxx'
+764,416,0,0,4,4,4,64,164,264,764,8,9,'KDAAAA','AQAAAA','AAAAxx'
+535,417,1,3,5,15,5,35,135,35,535,10,11,'PUAAAA','BQAAAA','HHHHxx'
+211,418,1,3,1,11,1,11,11,211,211,2,3,'DIAAAA','CQAAAA','OOOOxx'
+625,419,1,1,5,5,5,25,25,125,625,10,11,'BYAAAA','DQAAAA','VVVVxx'
+96,420,0,0,6,16,6,96,96,96,96,12,13,'SDAAAA','EQAAAA','AAAAxx'
+828,421,0,0,8,8,8,28,28,328,828,16,17,'WFAAAA','FQAAAA','HHHHxx'
+229,422,1,1,9,9,9,29,29,229,229,18,19,'VIAAAA','GQAAAA','OOOOxx'
+602,423,0,2,2,2,2,2,2,102,602,4,5,'EXAAAA','HQAAAA','VVVVxx'
+742,424,0,2,2,2,2,42,142,242,742,4,5,'OCAAAA','IQAAAA','AAAAxx'
+451,425,1,3,1,11,1,51,51,451,451,2,3,'JRAAAA','JQAAAA','HHHHxx'
+991,426,1,3,1,11,1,91,191,491,991,2,3,'DMAAAA','KQAAAA','OOOOxx'
+301,427,1,1,1,1,1,1,101,301,301,2,3,'PLAAAA','LQAAAA','VVVVxx'
+510,428,0,2,0,10,0,10,110,10,510,0,1,'QTAAAA','MQAAAA','AAAAxx'
+299,429,1,3,9,19,9,99,99,299,299,18,19,'NLAAAA','NQAAAA','HHHHxx'
+961,430,1,1,1,1,1,61,161,461,961,2,3,'ZKAAAA','OQAAAA','OOOOxx'
+3,431,1,3,3,3,3,3,3,3,3,6,7,'DAAAAA','PQAAAA','VVVVxx'
+106,432,0,2,6,6,6,6,106,106,106,12,13,'CEAAAA','QQAAAA','AAAAxx'
+591,433,1,3,1,11,1,91,191,91,591,2,3,'TWAAAA','RQAAAA','HHHHxx'
+700,434,0,0,0,0,0,0,100,200,700,0,1,'YAAAAA','SQAAAA','OOOOxx'
+841,435,1,1,1,1,1,41,41,341,841,2,3,'JGAAAA','TQAAAA','VVVVxx'
+829,436,1,1,9,9,9,29,29,329,829,18,19,'XFAAAA','UQAAAA','AAAAxx'
+508,437,0,0,8,8,8,8,108,8,508,16,17,'OTAAAA','VQAAAA','HHHHxx'
+750,438,0,2,0,10,0,50,150,250,750,0,1,'WCAAAA','WQAAAA','OOOOxx'
+665,439,1,1,5,5,5,65,65,165,665,10,11,'PZAAAA','XQAAAA','VVVVxx'
+157,440,1,1,7,17,7,57,157,157,157,14,15,'BGAAAA','YQAAAA','AAAAxx'
+694,441,0,2,4,14,4,94,94,194,694,8,9,'SAAAAA','ZQAAAA','HHHHxx'
+176,442,0,0,6,16,6,76,176,176,176,12,13,'UGAAAA','ARAAAA','OOOOxx'
+950,443,0,2,0,10,0,50,150,450,950,0,1,'OKAAAA','BRAAAA','VVVVxx'
+970,444,0,2,0,10,0,70,170,470,970,0,1,'ILAAAA','CRAAAA','AAAAxx'
+496,445,0,0,6,16,6,96,96,496,496,12,13,'CTAAAA','DRAAAA','HHHHxx'
+429,446,1,1,9,9,9,29,29,429,429,18,19,'NQAAAA','ERAAAA','OOOOxx'
+907,447,1,3,7,7,7,7,107,407,907,14,15,'XIAAAA','FRAAAA','VVVVxx'
+72,448,0,0,2,12,2,72,72,72,72,4,5,'UCAAAA','GRAAAA','AAAAxx'
+186,449,0,2,6,6,6,86,186,186,186,12,13,'EHAAAA','HRAAAA','HHHHxx'
+713,450,1,1,3,13,3,13,113,213,713,6,7,'LBAAAA','IRAAAA','OOOOxx'
+432,451,0,0,2,12,2,32,32,432,432,4,5,'QQAAAA','JRAAAA','VVVVxx'
+735,452,1,3,5,15,5,35,135,235,735,10,11,'HCAAAA','KRAAAA','AAAAxx'
+516,453,0,0,6,16,6,16,116,16,516,12,13,'WTAAAA','LRAAAA','HHHHxx'
+964,454,0,0,4,4,4,64,164,464,964,8,9,'CLAAAA','MRAAAA','OOOOxx'
+840,455,0,0,0,0,0,40,40,340,840,0,1,'IGAAAA','NRAAAA','VVVVxx'
+550,456,0,2,0,10,0,50,150,50,550,0,1,'EVAAAA','ORAAAA','AAAAxx'
+360,457,0,0,0,0,0,60,160,360,360,0,1,'WNAAAA','PRAAAA','HHHHxx'
+827,458,1,3,7,7,7,27,27,327,827,14,15,'VFAAAA','QRAAAA','OOOOxx'
+959,459,1,3,9,19,9,59,159,459,959,18,19,'XKAAAA','RRAAAA','VVVVxx'
+454,460,0,2,4,14,4,54,54,454,454,8,9,'MRAAAA','SRAAAA','AAAAxx'
+819,461,1,3,9,19,9,19,19,319,819,18,19,'NFAAAA','TRAAAA','HHHHxx'
+745,462,1,1,5,5,5,45,145,245,745,10,11,'RCAAAA','URAAAA','OOOOxx'
+279,463,1,3,9,19,9,79,79,279,279,18,19,'TKAAAA','VRAAAA','VVVVxx'
+426,464,0,2,6,6,6,26,26,426,426,12,13,'KQAAAA','WRAAAA','AAAAxx'
+70,465,0,2,0,10,0,70,70,70,70,0,1,'SCAAAA','XRAAAA','HHHHxx'
+637,466,1,1,7,17,7,37,37,137,637,14,15,'NYAAAA','YRAAAA','OOOOxx'
+417,467,1,1,7,17,7,17,17,417,417,14,15,'BQAAAA','ZRAAAA','VVVVxx'
+586,468,0,2,6,6,6,86,186,86,586,12,13,'OWAAAA','ASAAAA','AAAAxx'
+314,469,0,2,4,14,4,14,114,314,314,8,9,'CMAAAA','BSAAAA','HHHHxx'
+101,470,1,1,1,1,1,1,101,101,101,2,3,'XDAAAA','CSAAAA','OOOOxx'
+205,471,1,1,5,5,5,5,5,205,205,10,11,'XHAAAA','DSAAAA','VVVVxx'
+969,472,1,1,9,9,9,69,169,469,969,18,19,'HLAAAA','ESAAAA','AAAAxx'
+217,473,1,1,7,17,7,17,17,217,217,14,15,'JIAAAA','FSAAAA','HHHHxx'
+281,474,1,1,1,1,1,81,81,281,281,2,3,'VKAAAA','GSAAAA','OOOOxx'
+984,475,0,0,4,4,4,84,184,484,984,8,9,'WLAAAA','HSAAAA','VVVVxx'
+366,476,0,2,6,6,6,66,166,366,366,12,13,'COAAAA','ISAAAA','AAAAxx'
+483,477,1,3,3,3,3,83,83,483,483,6,7,'PSAAAA','JSAAAA','HHHHxx'
+838,478,0,2,8,18,8,38,38,338,838,16,17,'GGAAAA','KSAAAA','OOOOxx'
+64,479,0,0,4,4,4,64,64,64,64,8,9,'MCAAAA','LSAAAA','VVVVxx'
+981,480,1,1,1,1,1,81,181,481,981,2,3,'TLAAAA','MSAAAA','AAAAxx'
+538,481,0,2,8,18,8,38,138,38,538,16,17,'SUAAAA','NSAAAA','HHHHxx'
+39,482,1,3,9,19,9,39,39,39,39,18,19,'NBAAAA','OSAAAA','OOOOxx'
+60,483,0,0,0,0,0,60,60,60,60,0,1,'ICAAAA','PSAAAA','VVVVxx'
+874,484,0,2,4,14,4,74,74,374,874,8,9,'QHAAAA','QSAAAA','AAAAxx'
+955,485,1,3,5,15,5,55,155,455,955,10,11,'TKAAAA','RSAAAA','HHHHxx'
+347,486,1,3,7,7,7,47,147,347,347,14,15,'JNAAAA','SSAAAA','OOOOxx'
+227,487,1,3,7,7,7,27,27,227,227,14,15,'TIAAAA','TSAAAA','VVVVxx'
+44,488,0,0,4,4,4,44,44,44,44,8,9,'SBAAAA','USAAAA','AAAAxx'
+446,489,0,2,6,6,6,46,46,446,446,12,13,'ERAAAA','VSAAAA','HHHHxx'
+605,490,1,1,5,5,5,5,5,105,605,10,11,'HXAAAA','WSAAAA','OOOOxx'
+570,491,0,2,0,10,0,70,170,70,570,0,1,'YVAAAA','XSAAAA','VVVVxx'
+895,492,1,3,5,15,5,95,95,395,895,10,11,'LIAAAA','YSAAAA','AAAAxx'
+760,493,0,0,0,0,0,60,160,260,760,0,1,'GDAAAA','ZSAAAA','HHHHxx'
+428,494,0,0,8,8,8,28,28,428,428,16,17,'MQAAAA','ATAAAA','OOOOxx'
+628,495,0,0,8,8,8,28,28,128,628,16,17,'EYAAAA','BTAAAA','VVVVxx'
+933,496,1,1,3,13,3,33,133,433,933,6,7,'XJAAAA','CTAAAA','AAAAxx'
+263,497,1,3,3,3,3,63,63,263,263,6,7,'DKAAAA','DTAAAA','HHHHxx'
+729,498,1,1,9,9,9,29,129,229,729,18,19,'BCAAAA','ETAAAA','OOOOxx'
+860,499,0,0,0,0,0,60,60,360,860,0,1,'CHAAAA','FTAAAA','VVVVxx'
+76,500,0,0,6,16,6,76,76,76,76,12,13,'YCAAAA','GTAAAA','AAAAxx'
+293,501,1,1,3,13,3,93,93,293,293,6,7,'HLAAAA','HTAAAA','HHHHxx'
+296,502,0,0,6,16,6,96,96,296,296,12,13,'KLAAAA','ITAAAA','OOOOxx'
+124,503,0,0,4,4,4,24,124,124,124,8,9,'UEAAAA','JTAAAA','VVVVxx'
+568,504,0,0,8,8,8,68,168,68,568,16,17,'WVAAAA','KTAAAA','AAAAxx'
+337,505,1,1,7,17,7,37,137,337,337,14,15,'ZMAAAA','LTAAAA','HHHHxx'
+464,506,0,0,4,4,4,64,64,464,464,8,9,'WRAAAA','MTAAAA','OOOOxx'
+582,507,0,2,2,2,2,82,182,82,582,4,5,'KWAAAA','NTAAAA','VVVVxx'
+207,508,1,3,7,7,7,7,7,207,207,14,15,'ZHAAAA','OTAAAA','AAAAxx'
+518,509,0,2,8,18,8,18,118,18,518,16,17,'YTAAAA','PTAAAA','HHHHxx'
+513,510,1,1,3,13,3,13,113,13,513,6,7,'TTAAAA','QTAAAA','OOOOxx'
+127,511,1,3,7,7,7,27,127,127,127,14,15,'XEAAAA','RTAAAA','VVVVxx'
+396,512,0,0,6,16,6,96,196,396,396,12,13,'GPAAAA','STAAAA','AAAAxx'
+781,513,1,1,1,1,1,81,181,281,781,2,3,'BEAAAA','TTAAAA','HHHHxx'
+233,514,1,1,3,13,3,33,33,233,233,6,7,'ZIAAAA','UTAAAA','OOOOxx'
+709,515,1,1,9,9,9,9,109,209,709,18,19,'HBAAAA','VTAAAA','VVVVxx'
+325,516,1,1,5,5,5,25,125,325,325,10,11,'NMAAAA','WTAAAA','AAAAxx'
+143,517,1,3,3,3,3,43,143,143,143,6,7,'NFAAAA','XTAAAA','HHHHxx'
+824,518,0,0,4,4,4,24,24,324,824,8,9,'SFAAAA','YTAAAA','OOOOxx'
+122,519,0,2,2,2,2,22,122,122,122,4,5,'SEAAAA','ZTAAAA','VVVVxx'
+10,520,0,2,0,10,0,10,10,10,10,0,1,'KAAAAA','AUAAAA','AAAAxx'
+41,521,1,1,1,1,1,41,41,41,41,2,3,'PBAAAA','BUAAAA','HHHHxx'
+618,522,0,2,8,18,8,18,18,118,618,16,17,'UXAAAA','CUAAAA','OOOOxx'
+161,523,1,1,1,1,1,61,161,161,161,2,3,'FGAAAA','DUAAAA','VVVVxx'
+801,524,1,1,1,1,1,1,1,301,801,2,3,'VEAAAA','EUAAAA','AAAAxx'
+768,525,0,0,8,8,8,68,168,268,768,16,17,'ODAAAA','FUAAAA','HHHHxx'
+642,526,0,2,2,2,2,42,42,142,642,4,5,'SYAAAA','GUAAAA','OOOOxx'
+803,527,1,3,3,3,3,3,3,303,803,6,7,'XEAAAA','HUAAAA','VVVVxx'
+317,528,1,1,7,17,7,17,117,317,317,14,15,'FMAAAA','IUAAAA','AAAAxx'
+938,529,0,2,8,18,8,38,138,438,938,16,17,'CKAAAA','JUAAAA','HHHHxx'
+649,530,1,1,9,9,9,49,49,149,649,18,19,'ZYAAAA','KUAAAA','OOOOxx'
+738,531,0,2,8,18,8,38,138,238,738,16,17,'KCAAAA','LUAAAA','VVVVxx'
+344,532,0,0,4,4,4,44,144,344,344,8,9,'GNAAAA','MUAAAA','AAAAxx'
+399,533,1,3,9,19,9,99,199,399,399,18,19,'JPAAAA','NUAAAA','HHHHxx'
+609,534,1,1,9,9,9,9,9,109,609,18,19,'LXAAAA','OUAAAA','OOOOxx'
+677,535,1,1,7,17,7,77,77,177,677,14,15,'BAAAAA','PUAAAA','VVVVxx'
+478,536,0,2,8,18,8,78,78,478,478,16,17,'KSAAAA','QUAAAA','AAAAxx'
+452,537,0,0,2,12,2,52,52,452,452,4,5,'KRAAAA','RUAAAA','HHHHxx'
+261,538,1,1,1,1,1,61,61,261,261,2,3,'BKAAAA','SUAAAA','OOOOxx'
+449,539,1,1,9,9,9,49,49,449,449,18,19,'HRAAAA','TUAAAA','VVVVxx'
+433,540,1,1,3,13,3,33,33,433,433,6,7,'RQAAAA','UUAAAA','AAAAxx'
+5,541,1,1,5,5,5,5,5,5,5,10,11,'FAAAAA','VUAAAA','HHHHxx'
+664,542,0,0,4,4,4,64,64,164,664,8,9,'OZAAAA','WUAAAA','OOOOxx'
+887,543,1,3,7,7,7,87,87,387,887,14,15,'DIAAAA','XUAAAA','VVVVxx'
+546,544,0,2,6,6,6,46,146,46,546,12,13,'AVAAAA','YUAAAA','AAAAxx'
+253,545,1,1,3,13,3,53,53,253,253,6,7,'TJAAAA','ZUAAAA','HHHHxx'
+235,546,1,3,5,15,5,35,35,235,235,10,11,'BJAAAA','AVAAAA','OOOOxx'
+258,547,0,2,8,18,8,58,58,258,258,16,17,'YJAAAA','BVAAAA','VVVVxx'
+621,548,1,1,1,1,1,21,21,121,621,2,3,'XXAAAA','CVAAAA','AAAAxx'
+998,549,0,2,8,18,8,98,198,498,998,16,17,'KMAAAA','DVAAAA','HHHHxx'
+236,550,0,0,6,16,6,36,36,236,236,12,13,'CJAAAA','EVAAAA','OOOOxx'
+537,551,1,1,7,17,7,37,137,37,537,14,15,'RUAAAA','FVAAAA','VVVVxx'
+769,552,1,1,9,9,9,69,169,269,769,18,19,'PDAAAA','GVAAAA','AAAAxx'
+921,553,1,1,1,1,1,21,121,421,921,2,3,'LJAAAA','HVAAAA','HHHHxx'
+951,554,1,3,1,11,1,51,151,451,951,2,3,'PKAAAA','IVAAAA','OOOOxx'
+240,555,0,0,0,0,0,40,40,240,240,0,1,'GJAAAA','JVAAAA','VVVVxx'
+644,556,0,0,4,4,4,44,44,144,644,8,9,'UYAAAA','KVAAAA','AAAAxx'
+352,557,0,0,2,12,2,52,152,352,352,4,5,'ONAAAA','LVAAAA','HHHHxx'
+613,558,1,1,3,13,3,13,13,113,613,6,7,'PXAAAA','MVAAAA','OOOOxx'
+784,559,0,0,4,4,4,84,184,284,784,8,9,'EEAAAA','NVAAAA','VVVVxx'
+61,560,1,1,1,1,1,61,61,61,61,2,3,'JCAAAA','OVAAAA','AAAAxx'
+144,561,0,0,4,4,4,44,144,144,144,8,9,'OFAAAA','PVAAAA','HHHHxx'
+94,562,0,2,4,14,4,94,94,94,94,8,9,'QDAAAA','QVAAAA','OOOOxx'
+270,563,0,2,0,10,0,70,70,270,270,0,1,'KKAAAA','RVAAAA','VVVVxx'
+942,564,0,2,2,2,2,42,142,442,942,4,5,'GKAAAA','SVAAAA','AAAAxx'
+756,565,0,0,6,16,6,56,156,256,756,12,13,'CDAAAA','TVAAAA','HHHHxx'
+321,566,1,1,1,1,1,21,121,321,321,2,3,'JMAAAA','UVAAAA','OOOOxx'
+36,567,0,0,6,16,6,36,36,36,36,12,13,'KBAAAA','VVAAAA','VVVVxx'
+232,568,0,0,2,12,2,32,32,232,232,4,5,'YIAAAA','WVAAAA','AAAAxx'
+430,569,0,2,0,10,0,30,30,430,430,0,1,'OQAAAA','XVAAAA','HHHHxx'
+177,570,1,1,7,17,7,77,177,177,177,14,15,'VGAAAA','YVAAAA','OOOOxx'
+220,571,0,0,0,0,0,20,20,220,220,0,1,'MIAAAA','ZVAAAA','VVVVxx'
+109,572,1,1,9,9,9,9,109,109,109,18,19,'FEAAAA','AWAAAA','AAAAxx'
+419,573,1,3,9,19,9,19,19,419,419,18,19,'DQAAAA','BWAAAA','HHHHxx'
+135,574,1,3,5,15,5,35,135,135,135,10,11,'FFAAAA','CWAAAA','OOOOxx'
+610,575,0,2,0,10,0,10,10,110,610,0,1,'MXAAAA','DWAAAA','VVVVxx'
+956,576,0,0,6,16,6,56,156,456,956,12,13,'UKAAAA','EWAAAA','AAAAxx'
+626,577,0,2,6,6,6,26,26,126,626,12,13,'CYAAAA','FWAAAA','HHHHxx'
+375,578,1,3,5,15,5,75,175,375,375,10,11,'LOAAAA','GWAAAA','OOOOxx'
+976,579,0,0,6,16,6,76,176,476,976,12,13,'OLAAAA','HWAAAA','VVVVxx'
+152,580,0,0,2,12,2,52,152,152,152,4,5,'WFAAAA','IWAAAA','AAAAxx'
+308,581,0,0,8,8,8,8,108,308,308,16,17,'WLAAAA','JWAAAA','HHHHxx'
+445,582,1,1,5,5,5,45,45,445,445,10,11,'DRAAAA','KWAAAA','OOOOxx'
+326,583,0,2,6,6,6,26,126,326,326,12,13,'OMAAAA','LWAAAA','VVVVxx'
+422,584,0,2,2,2,2,22,22,422,422,4,5,'GQAAAA','MWAAAA','AAAAxx'
+972,585,0,0,2,12,2,72,172,472,972,4,5,'KLAAAA','NWAAAA','HHHHxx'
+45,586,1,1,5,5,5,45,45,45,45,10,11,'TBAAAA','OWAAAA','OOOOxx'
+725,587,1,1,5,5,5,25,125,225,725,10,11,'XBAAAA','PWAAAA','VVVVxx'
+753,588,1,1,3,13,3,53,153,253,753,6,7,'ZCAAAA','QWAAAA','AAAAxx'
+493,589,1,1,3,13,3,93,93,493,493,6,7,'ZSAAAA','RWAAAA','HHHHxx'
+601,590,1,1,1,1,1,1,1,101,601,2,3,'DXAAAA','SWAAAA','OOOOxx'
+463,591,1,3,3,3,3,63,63,463,463,6,7,'VRAAAA','TWAAAA','VVVVxx'
+303,592,1,3,3,3,3,3,103,303,303,6,7,'RLAAAA','UWAAAA','AAAAxx'
+59,593,1,3,9,19,9,59,59,59,59,18,19,'HCAAAA','VWAAAA','HHHHxx'
+595,594,1,3,5,15,5,95,195,95,595,10,11,'XWAAAA','WWAAAA','OOOOxx'
+807,595,1,3,7,7,7,7,7,307,807,14,15,'BFAAAA','XWAAAA','VVVVxx'
+424,596,0,0,4,4,4,24,24,424,424,8,9,'IQAAAA','YWAAAA','AAAAxx'
+521,597,1,1,1,1,1,21,121,21,521,2,3,'BUAAAA','ZWAAAA','HHHHxx'
+341,598,1,1,1,1,1,41,141,341,341,2,3,'DNAAAA','AXAAAA','OOOOxx'
+571,599,1,3,1,11,1,71,171,71,571,2,3,'ZVAAAA','BXAAAA','VVVVxx'
+165,600,1,1,5,5,5,65,165,165,165,10,11,'JGAAAA','CXAAAA','AAAAxx'
+908,601,0,0,8,8,8,8,108,408,908,16,17,'YIAAAA','DXAAAA','HHHHxx'
+351,602,1,3,1,11,1,51,151,351,351,2,3,'NNAAAA','EXAAAA','OOOOxx'
+334,603,0,2,4,14,4,34,134,334,334,8,9,'WMAAAA','FXAAAA','VVVVxx'
+636,604,0,0,6,16,6,36,36,136,636,12,13,'MYAAAA','GXAAAA','AAAAxx'
+138,605,0,2,8,18,8,38,138,138,138,16,17,'IFAAAA','HXAAAA','HHHHxx'
+438,606,0,2,8,18,8,38,38,438,438,16,17,'WQAAAA','IXAAAA','OOOOxx'
+391,607,1,3,1,11,1,91,191,391,391,2,3,'BPAAAA','JXAAAA','VVVVxx'
+395,608,1,3,5,15,5,95,195,395,395,10,11,'FPAAAA','KXAAAA','AAAAxx'
+502,609,0,2,2,2,2,2,102,2,502,4,5,'ITAAAA','LXAAAA','HHHHxx'
+85,610,1,1,5,5,5,85,85,85,85,10,11,'HDAAAA','MXAAAA','OOOOxx'
+786,611,0,2,6,6,6,86,186,286,786,12,13,'GEAAAA','NXAAAA','VVVVxx'
+619,612,1,3,9,19,9,19,19,119,619,18,19,'VXAAAA','OXAAAA','AAAAxx'
+440,613,0,0,0,0,0,40,40,440,440,0,1,'YQAAAA','PXAAAA','HHHHxx'
+949,614,1,1,9,9,9,49,149,449,949,18,19,'NKAAAA','QXAAAA','OOOOxx'
+691,615,1,3,1,11,1,91,91,191,691,2,3,'PAAAAA','RXAAAA','VVVVxx'
+348,616,0,0,8,8,8,48,148,348,348,16,17,'KNAAAA','SXAAAA','AAAAxx'
+506,617,0,2,6,6,6,6,106,6,506,12,13,'MTAAAA','TXAAAA','HHHHxx'
+192,618,0,0,2,12,2,92,192,192,192,4,5,'KHAAAA','UXAAAA','OOOOxx'
+369,619,1,1,9,9,9,69,169,369,369,18,19,'FOAAAA','VXAAAA','VVVVxx'
+311,620,1,3,1,11,1,11,111,311,311,2,3,'ZLAAAA','WXAAAA','AAAAxx'
+273,621,1,1,3,13,3,73,73,273,273,6,7,'NKAAAA','XXAAAA','HHHHxx'
+770,622,0,2,0,10,0,70,170,270,770,0,1,'QDAAAA','YXAAAA','OOOOxx'
+191,623,1,3,1,11,1,91,191,191,191,2,3,'JHAAAA','ZXAAAA','VVVVxx'
+90,624,0,2,0,10,0,90,90,90,90,0,1,'MDAAAA','AYAAAA','AAAAxx'
+163,625,1,3,3,3,3,63,163,163,163,6,7,'HGAAAA','BYAAAA','HHHHxx'
+350,626,0,2,0,10,0,50,150,350,350,0,1,'MNAAAA','CYAAAA','OOOOxx'
+55,627,1,3,5,15,5,55,55,55,55,10,11,'DCAAAA','DYAAAA','VVVVxx'
+488,628,0,0,8,8,8,88,88,488,488,16,17,'USAAAA','EYAAAA','AAAAxx'
+215,629,1,3,5,15,5,15,15,215,215,10,11,'HIAAAA','FYAAAA','HHHHxx'
+732,630,0,0,2,12,2,32,132,232,732,4,5,'ECAAAA','GYAAAA','OOOOxx'
+688,631,0,0,8,8,8,88,88,188,688,16,17,'MAAAAA','HYAAAA','VVVVxx'
+520,632,0,0,0,0,0,20,120,20,520,0,1,'AUAAAA','IYAAAA','AAAAxx'
+62,633,0,2,2,2,2,62,62,62,62,4,5,'KCAAAA','JYAAAA','HHHHxx'
+423,634,1,3,3,3,3,23,23,423,423,6,7,'HQAAAA','KYAAAA','OOOOxx'
+242,635,0,2,2,2,2,42,42,242,242,4,5,'IJAAAA','LYAAAA','VVVVxx'
+193,636,1,1,3,13,3,93,193,193,193,6,7,'LHAAAA','MYAAAA','AAAAxx'
+648,637,0,0,8,8,8,48,48,148,648,16,17,'YYAAAA','NYAAAA','HHHHxx'
+459,638,1,3,9,19,9,59,59,459,459,18,19,'RRAAAA','OYAAAA','OOOOxx'
+196,639,0,0,6,16,6,96,196,196,196,12,13,'OHAAAA','PYAAAA','VVVVxx'
+476,640,0,0,6,16,6,76,76,476,476,12,13,'ISAAAA','QYAAAA','AAAAxx'
+903,641,1,3,3,3,3,3,103,403,903,6,7,'TIAAAA','RYAAAA','HHHHxx'
+974,642,0,2,4,14,4,74,174,474,974,8,9,'MLAAAA','SYAAAA','OOOOxx'
+603,643,1,3,3,3,3,3,3,103,603,6,7,'FXAAAA','TYAAAA','VVVVxx'
+12,644,0,0,2,12,2,12,12,12,12,4,5,'MAAAAA','UYAAAA','AAAAxx'
+599,645,1,3,9,19,9,99,199,99,599,18,19,'BXAAAA','VYAAAA','HHHHxx'
+914,646,0,2,4,14,4,14,114,414,914,8,9,'EJAAAA','WYAAAA','OOOOxx'
+7,647,1,3,7,7,7,7,7,7,7,14,15,'HAAAAA','XYAAAA','VVVVxx'
+213,648,1,1,3,13,3,13,13,213,213,6,7,'FIAAAA','YYAAAA','AAAAxx'
+174,649,0,2,4,14,4,74,174,174,174,8,9,'SGAAAA','ZYAAAA','HHHHxx'
+392,650,0,0,2,12,2,92,192,392,392,4,5,'CPAAAA','AZAAAA','OOOOxx'
+674,651,0,2,4,14,4,74,74,174,674,8,9,'YZAAAA','BZAAAA','VVVVxx'
+650,652,0,2,0,10,0,50,50,150,650,0,1,'AZAAAA','CZAAAA','AAAAxx'
+8,653,0,0,8,8,8,8,8,8,8,16,17,'IAAAAA','DZAAAA','HHHHxx'
+492,654,0,0,2,12,2,92,92,492,492,4,5,'YSAAAA','EZAAAA','OOOOxx'
+322,655,0,2,2,2,2,22,122,322,322,4,5,'KMAAAA','FZAAAA','VVVVxx'
+315,656,1,3,5,15,5,15,115,315,315,10,11,'DMAAAA','GZAAAA','AAAAxx'
+380,657,0,0,0,0,0,80,180,380,380,0,1,'QOAAAA','HZAAAA','HHHHxx'
+353,658,1,1,3,13,3,53,153,353,353,6,7,'PNAAAA','IZAAAA','OOOOxx'
+892,659,0,0,2,12,2,92,92,392,892,4,5,'IIAAAA','JZAAAA','VVVVxx'
+932,660,0,0,2,12,2,32,132,432,932,4,5,'WJAAAA','KZAAAA','AAAAxx'
+993,661,1,1,3,13,3,93,193,493,993,6,7,'FMAAAA','LZAAAA','HHHHxx'
+859,662,1,3,9,19,9,59,59,359,859,18,19,'BHAAAA','MZAAAA','OOOOxx'
+806,663,0,2,6,6,6,6,6,306,806,12,13,'AFAAAA','NZAAAA','VVVVxx'
+145,664,1,1,5,5,5,45,145,145,145,10,11,'PFAAAA','OZAAAA','AAAAxx'
+373,665,1,1,3,13,3,73,173,373,373,6,7,'JOAAAA','PZAAAA','HHHHxx'
+418,666,0,2,8,18,8,18,18,418,418,16,17,'CQAAAA','QZAAAA','OOOOxx'
+865,667,1,1,5,5,5,65,65,365,865,10,11,'HHAAAA','RZAAAA','VVVVxx'
+462,668,0,2,2,2,2,62,62,462,462,4,5,'URAAAA','SZAAAA','AAAAxx'
+24,669,0,0,4,4,4,24,24,24,24,8,9,'YAAAAA','TZAAAA','HHHHxx'
+920,670,0,0,0,0,0,20,120,420,920,0,1,'KJAAAA','UZAAAA','OOOOxx'
+672,671,0,0,2,12,2,72,72,172,672,4,5,'WZAAAA','VZAAAA','VVVVxx'
+92,672,0,0,2,12,2,92,92,92,92,4,5,'ODAAAA','WZAAAA','AAAAxx'
+721,673,1,1,1,1,1,21,121,221,721,2,3,'TBAAAA','XZAAAA','HHHHxx'
+646,674,0,2,6,6,6,46,46,146,646,12,13,'WYAAAA','YZAAAA','OOOOxx'
+910,675,0,2,0,10,0,10,110,410,910,0,1,'AJAAAA','ZZAAAA','VVVVxx'
+909,676,1,1,9,9,9,9,109,409,909,18,19,'ZIAAAA','AABAAA','AAAAxx'
+630,677,0,2,0,10,0,30,30,130,630,0,1,'GYAAAA','BABAAA','HHHHxx'
+482,678,0,2,2,2,2,82,82,482,482,4,5,'OSAAAA','CABAAA','OOOOxx'
+559,679,1,3,9,19,9,59,159,59,559,18,19,'NVAAAA','DABAAA','VVVVxx'
+853,680,1,1,3,13,3,53,53,353,853,6,7,'VGAAAA','EABAAA','AAAAxx'
+141,681,1,1,1,1,1,41,141,141,141,2,3,'LFAAAA','FABAAA','HHHHxx'
+266,682,0,2,6,6,6,66,66,266,266,12,13,'GKAAAA','GABAAA','OOOOxx'
+835,683,1,3,5,15,5,35,35,335,835,10,11,'DGAAAA','HABAAA','VVVVxx'
+164,684,0,0,4,4,4,64,164,164,164,8,9,'IGAAAA','IABAAA','AAAAxx'
+629,685,1,1,9,9,9,29,29,129,629,18,19,'FYAAAA','JABAAA','HHHHxx'
+203,686,1,3,3,3,3,3,3,203,203,6,7,'VHAAAA','KABAAA','OOOOxx'
+411,687,1,3,1,11,1,11,11,411,411,2,3,'VPAAAA','LABAAA','VVVVxx'
+930,688,0,2,0,10,0,30,130,430,930,0,1,'UJAAAA','MABAAA','AAAAxx'
+435,689,1,3,5,15,5,35,35,435,435,10,11,'TQAAAA','NABAAA','HHHHxx'
+563,690,1,3,3,3,3,63,163,63,563,6,7,'RVAAAA','OABAAA','OOOOxx'
+960,691,0,0,0,0,0,60,160,460,960,0,1,'YKAAAA','PABAAA','VVVVxx'
+733,692,1,1,3,13,3,33,133,233,733,6,7,'FCAAAA','QABAAA','AAAAxx'
+967,693,1,3,7,7,7,67,167,467,967,14,15,'FLAAAA','RABAAA','HHHHxx'
+668,694,0,0,8,8,8,68,68,168,668,16,17,'SZAAAA','SABAAA','OOOOxx'
+994,695,0,2,4,14,4,94,194,494,994,8,9,'GMAAAA','TABAAA','VVVVxx'
+129,696,1,1,9,9,9,29,129,129,129,18,19,'ZEAAAA','UABAAA','AAAAxx'
+954,697,0,2,4,14,4,54,154,454,954,8,9,'SKAAAA','VABAAA','HHHHxx'
+68,698,0,0,8,8,8,68,68,68,68,16,17,'QCAAAA','WABAAA','OOOOxx'
+79,699,1,3,9,19,9,79,79,79,79,18,19,'BDAAAA','XABAAA','VVVVxx'
+121,700,1,1,1,1,1,21,121,121,121,2,3,'REAAAA','YABAAA','AAAAxx'
+740,701,0,0,0,0,0,40,140,240,740,0,1,'MCAAAA','ZABAAA','HHHHxx'
+902,702,0,2,2,2,2,2,102,402,902,4,5,'SIAAAA','ABBAAA','OOOOxx'
+695,703,1,3,5,15,5,95,95,195,695,10,11,'TAAAAA','BBBAAA','VVVVxx'
+455,704,1,3,5,15,5,55,55,455,455,10,11,'NRAAAA','CBBAAA','AAAAxx'
+89,705,1,1,9,9,9,89,89,89,89,18,19,'LDAAAA','DBBAAA','HHHHxx'
+893,706,1,1,3,13,3,93,93,393,893,6,7,'JIAAAA','EBBAAA','OOOOxx'
+202,707,0,2,2,2,2,2,2,202,202,4,5,'UHAAAA','FBBAAA','VVVVxx'
+132,708,0,0,2,12,2,32,132,132,132,4,5,'CFAAAA','GBBAAA','AAAAxx'
+782,709,0,2,2,2,2,82,182,282,782,4,5,'CEAAAA','HBBAAA','HHHHxx'
+512,710,0,0,2,12,2,12,112,12,512,4,5,'STAAAA','IBBAAA','OOOOxx'
+857,711,1,1,7,17,7,57,57,357,857,14,15,'ZGAAAA','JBBAAA','VVVVxx'
+248,712,0,0,8,8,8,48,48,248,248,16,17,'OJAAAA','KBBAAA','AAAAxx'
+858,713,0,2,8,18,8,58,58,358,858,16,17,'AHAAAA','LBBAAA','HHHHxx'
+527,714,1,3,7,7,7,27,127,27,527,14,15,'HUAAAA','MBBAAA','OOOOxx'
+450,715,0,2,0,10,0,50,50,450,450,0,1,'IRAAAA','NBBAAA','VVVVxx'
+712,716,0,0,2,12,2,12,112,212,712,4,5,'KBAAAA','OBBAAA','AAAAxx'
+153,717,1,1,3,13,3,53,153,153,153,6,7,'XFAAAA','PBBAAA','HHHHxx'
+587,718,1,3,7,7,7,87,187,87,587,14,15,'PWAAAA','QBBAAA','OOOOxx'
+593,719,1,1,3,13,3,93,193,93,593,6,7,'VWAAAA','RBBAAA','VVVVxx'
+249,720,1,1,9,9,9,49,49,249,249,18,19,'PJAAAA','SBBAAA','AAAAxx'
+128,721,0,0,8,8,8,28,128,128,128,16,17,'YEAAAA','TBBAAA','HHHHxx'
+675,722,1,3,5,15,5,75,75,175,675,10,11,'ZZAAAA','UBBAAA','OOOOxx'
+929,723,1,1,9,9,9,29,129,429,929,18,19,'TJAAAA','VBBAAA','VVVVxx'
+156,724,0,0,6,16,6,56,156,156,156,12,13,'AGAAAA','WBBAAA','AAAAxx'
+415,725,1,3,5,15,5,15,15,415,415,10,11,'ZPAAAA','XBBAAA','HHHHxx'
+28,726,0,0,8,8,8,28,28,28,28,16,17,'CBAAAA','YBBAAA','OOOOxx'
+18,727,0,2,8,18,8,18,18,18,18,16,17,'SAAAAA','ZBBAAA','VVVVxx'
+255,728,1,3,5,15,5,55,55,255,255,10,11,'VJAAAA','ACBAAA','AAAAxx'
+793,729,1,1,3,13,3,93,193,293,793,6,7,'NEAAAA','BCBAAA','HHHHxx'
+554,730,0,2,4,14,4,54,154,54,554,8,9,'IVAAAA','CCBAAA','OOOOxx'
+467,731,1,3,7,7,7,67,67,467,467,14,15,'ZRAAAA','DCBAAA','VVVVxx'
+410,732,0,2,0,10,0,10,10,410,410,0,1,'UPAAAA','ECBAAA','AAAAxx'
+651,733,1,3,1,11,1,51,51,151,651,2,3,'BZAAAA','FCBAAA','HHHHxx'
+287,734,1,3,7,7,7,87,87,287,287,14,15,'BLAAAA','GCBAAA','OOOOxx'
+640,735,0,0,0,0,0,40,40,140,640,0,1,'QYAAAA','HCBAAA','VVVVxx'
+245,736,1,1,5,5,5,45,45,245,245,10,11,'LJAAAA','ICBAAA','AAAAxx'
+21,737,1,1,1,1,1,21,21,21,21,2,3,'VAAAAA','JCBAAA','HHHHxx'
+83,738,1,3,3,3,3,83,83,83,83,6,7,'FDAAAA','KCBAAA','OOOOxx'
+228,739,0,0,8,8,8,28,28,228,228,16,17,'UIAAAA','LCBAAA','VVVVxx'
+323,740,1,3,3,3,3,23,123,323,323,6,7,'LMAAAA','MCBAAA','AAAAxx'
+594,741,0,2,4,14,4,94,194,94,594,8,9,'WWAAAA','NCBAAA','HHHHxx'
+528,742,0,0,8,8,8,28,128,28,528,16,17,'IUAAAA','OCBAAA','OOOOxx'
+276,743,0,0,6,16,6,76,76,276,276,12,13,'QKAAAA','PCBAAA','VVVVxx'
+598,744,0,2,8,18,8,98,198,98,598,16,17,'AXAAAA','QCBAAA','AAAAxx'
+635,745,1,3,5,15,5,35,35,135,635,10,11,'LYAAAA','RCBAAA','HHHHxx'
+868,746,0,0,8,8,8,68,68,368,868,16,17,'KHAAAA','SCBAAA','OOOOxx'
+290,747,0,2,0,10,0,90,90,290,290,0,1,'ELAAAA','TCBAAA','VVVVxx'
+468,748,0,0,8,8,8,68,68,468,468,16,17,'ASAAAA','UCBAAA','AAAAxx'
+689,749,1,1,9,9,9,89,89,189,689,18,19,'NAAAAA','VCBAAA','HHHHxx'
+799,750,1,3,9,19,9,99,199,299,799,18,19,'TEAAAA','WCBAAA','OOOOxx'
+210,751,0,2,0,10,0,10,10,210,210,0,1,'CIAAAA','XCBAAA','VVVVxx'
+346,752,0,2,6,6,6,46,146,346,346,12,13,'INAAAA','YCBAAA','AAAAxx'
+957,753,1,1,7,17,7,57,157,457,957,14,15,'VKAAAA','ZCBAAA','HHHHxx'
+905,754,1,1,5,5,5,5,105,405,905,10,11,'VIAAAA','ADBAAA','OOOOxx'
+523,755,1,3,3,3,3,23,123,23,523,6,7,'DUAAAA','BDBAAA','VVVVxx'
+899,756,1,3,9,19,9,99,99,399,899,18,19,'PIAAAA','CDBAAA','AAAAxx'
+867,757,1,3,7,7,7,67,67,367,867,14,15,'JHAAAA','DDBAAA','HHHHxx'
+11,758,1,3,1,11,1,11,11,11,11,2,3,'LAAAAA','EDBAAA','OOOOxx'
+320,759,0,0,0,0,0,20,120,320,320,0,1,'IMAAAA','FDBAAA','VVVVxx'
+766,760,0,2,6,6,6,66,166,266,766,12,13,'MDAAAA','GDBAAA','AAAAxx'
+84,761,0,0,4,4,4,84,84,84,84,8,9,'GDAAAA','HDBAAA','HHHHxx'
+507,762,1,3,7,7,7,7,107,7,507,14,15,'NTAAAA','IDBAAA','OOOOxx'
+471,763,1,3,1,11,1,71,71,471,471,2,3,'DSAAAA','JDBAAA','VVVVxx'
+517,764,1,1,7,17,7,17,117,17,517,14,15,'XTAAAA','KDBAAA','AAAAxx'
+234,765,0,2,4,14,4,34,34,234,234,8,9,'AJAAAA','LDBAAA','HHHHxx'
+988,766,0,0,8,8,8,88,188,488,988,16,17,'AMAAAA','MDBAAA','OOOOxx'
+473,767,1,1,3,13,3,73,73,473,473,6,7,'FSAAAA','NDBAAA','VVVVxx'
+66,768,0,2,6,6,6,66,66,66,66,12,13,'OCAAAA','ODBAAA','AAAAxx'
+530,769,0,2,0,10,0,30,130,30,530,0,1,'KUAAAA','PDBAAA','HHHHxx'
+834,770,0,2,4,14,4,34,34,334,834,8,9,'CGAAAA','QDBAAA','OOOOxx'
+894,771,0,2,4,14,4,94,94,394,894,8,9,'KIAAAA','RDBAAA','VVVVxx'
+481,772,1,1,1,1,1,81,81,481,481,2,3,'NSAAAA','SDBAAA','AAAAxx'
+280,773,0,0,0,0,0,80,80,280,280,0,1,'UKAAAA','TDBAAA','HHHHxx'
+705,774,1,1,5,5,5,5,105,205,705,10,11,'DBAAAA','UDBAAA','OOOOxx'
+218,775,0,2,8,18,8,18,18,218,218,16,17,'KIAAAA','VDBAAA','VVVVxx'
+560,776,0,0,0,0,0,60,160,60,560,0,1,'OVAAAA','WDBAAA','AAAAxx'
+123,777,1,3,3,3,3,23,123,123,123,6,7,'TEAAAA','XDBAAA','HHHHxx'
+289,778,1,1,9,9,9,89,89,289,289,18,19,'DLAAAA','YDBAAA','OOOOxx'
+189,779,1,1,9,9,9,89,189,189,189,18,19,'HHAAAA','ZDBAAA','VVVVxx'
+541,780,1,1,1,1,1,41,141,41,541,2,3,'VUAAAA','AEBAAA','AAAAxx'
+876,781,0,0,6,16,6,76,76,376,876,12,13,'SHAAAA','BEBAAA','HHHHxx'
+504,782,0,0,4,4,4,4,104,4,504,8,9,'KTAAAA','CEBAAA','OOOOxx'
+643,783,1,3,3,3,3,43,43,143,643,6,7,'TYAAAA','DEBAAA','VVVVxx'
+73,784,1,1,3,13,3,73,73,73,73,6,7,'VCAAAA','EEBAAA','AAAAxx'
+465,785,1,1,5,5,5,65,65,465,465,10,11,'XRAAAA','FEBAAA','HHHHxx'
+861,786,1,1,1,1,1,61,61,361,861,2,3,'DHAAAA','GEBAAA','OOOOxx'
+355,787,1,3,5,15,5,55,155,355,355,10,11,'RNAAAA','HEBAAA','VVVVxx'
+441,788,1,1,1,1,1,41,41,441,441,2,3,'ZQAAAA','IEBAAA','AAAAxx'
+219,789,1,3,9,19,9,19,19,219,219,18,19,'LIAAAA','JEBAAA','HHHHxx'
+839,790,1,3,9,19,9,39,39,339,839,18,19,'HGAAAA','KEBAAA','OOOOxx'
+271,791,1,3,1,11,1,71,71,271,271,2,3,'LKAAAA','LEBAAA','VVVVxx'
+212,792,0,0,2,12,2,12,12,212,212,4,5,'EIAAAA','MEBAAA','AAAAxx'
+904,793,0,0,4,4,4,4,104,404,904,8,9,'UIAAAA','NEBAAA','HHHHxx'
+244,794,0,0,4,4,4,44,44,244,244,8,9,'KJAAAA','OEBAAA','OOOOxx'
+751,795,1,3,1,11,1,51,151,251,751,2,3,'XCAAAA','PEBAAA','VVVVxx'
+944,796,0,0,4,4,4,44,144,444,944,8,9,'IKAAAA','QEBAAA','AAAAxx'
+305,797,1,1,5,5,5,5,105,305,305,10,11,'TLAAAA','REBAAA','HHHHxx'
+617,798,1,1,7,17,7,17,17,117,617,14,15,'TXAAAA','SEBAAA','OOOOxx'
+891,799,1,3,1,11,1,91,91,391,891,2,3,'HIAAAA','TEBAAA','VVVVxx'
+653,800,1,1,3,13,3,53,53,153,653,6,7,'DZAAAA','UEBAAA','AAAAxx'
+845,801,1,1,5,5,5,45,45,345,845,10,11,'NGAAAA','VEBAAA','HHHHxx'
+936,802,0,0,6,16,6,36,136,436,936,12,13,'AKAAAA','WEBAAA','OOOOxx'
+91,803,1,3,1,11,1,91,91,91,91,2,3,'NDAAAA','XEBAAA','VVVVxx'
+442,804,0,2,2,2,2,42,42,442,442,4,5,'ARAAAA','YEBAAA','AAAAxx'
+498,805,0,2,8,18,8,98,98,498,498,16,17,'ETAAAA','ZEBAAA','HHHHxx'
+987,806,1,3,7,7,7,87,187,487,987,14,15,'ZLAAAA','AFBAAA','OOOOxx'
+194,807,0,2,4,14,4,94,194,194,194,8,9,'MHAAAA','BFBAAA','VVVVxx'
+927,808,1,3,7,7,7,27,127,427,927,14,15,'RJAAAA','CFBAAA','AAAAxx'
+607,809,1,3,7,7,7,7,7,107,607,14,15,'JXAAAA','DFBAAA','HHHHxx'
+119,810,1,3,9,19,9,19,119,119,119,18,19,'PEAAAA','EFBAAA','OOOOxx'
+182,811,0,2,2,2,2,82,182,182,182,4,5,'AHAAAA','FFBAAA','VVVVxx'
+606,812,0,2,6,6,6,6,6,106,606,12,13,'IXAAAA','GFBAAA','AAAAxx'
+849,813,1,1,9,9,9,49,49,349,849,18,19,'RGAAAA','HFBAAA','HHHHxx'
+34,814,0,2,4,14,4,34,34,34,34,8,9,'IBAAAA','IFBAAA','OOOOxx'
+683,815,1,3,3,3,3,83,83,183,683,6,7,'HAAAAA','JFBAAA','VVVVxx'
+134,816,0,2,4,14,4,34,134,134,134,8,9,'EFAAAA','KFBAAA','AAAAxx'
+331,817,1,3,1,11,1,31,131,331,331,2,3,'TMAAAA','LFBAAA','HHHHxx'
+808,818,0,0,8,8,8,8,8,308,808,16,17,'CFAAAA','MFBAAA','OOOOxx'
+703,819,1,3,3,3,3,3,103,203,703,6,7,'BBAAAA','NFBAAA','VVVVxx'
+669,820,1,1,9,9,9,69,69,169,669,18,19,'TZAAAA','OFBAAA','AAAAxx'
+264,821,0,0,4,4,4,64,64,264,264,8,9,'EKAAAA','PFBAAA','HHHHxx'
+277,822,1,1,7,17,7,77,77,277,277,14,15,'RKAAAA','QFBAAA','OOOOxx'
+877,823,1,1,7,17,7,77,77,377,877,14,15,'THAAAA','RFBAAA','VVVVxx'
+783,824,1,3,3,3,3,83,183,283,783,6,7,'DEAAAA','SFBAAA','AAAAxx'
+791,825,1,3,1,11,1,91,191,291,791,2,3,'LEAAAA','TFBAAA','HHHHxx'
+171,826,1,3,1,11,1,71,171,171,171,2,3,'PGAAAA','UFBAAA','OOOOxx'
+564,827,0,0,4,4,4,64,164,64,564,8,9,'SVAAAA','VFBAAA','VVVVxx'
+230,828,0,2,0,10,0,30,30,230,230,0,1,'WIAAAA','WFBAAA','AAAAxx'
+881,829,1,1,1,1,1,81,81,381,881,2,3,'XHAAAA','XFBAAA','HHHHxx'
+890,830,0,2,0,10,0,90,90,390,890,0,1,'GIAAAA','YFBAAA','OOOOxx'
+374,831,0,2,4,14,4,74,174,374,374,8,9,'KOAAAA','ZFBAAA','VVVVxx'
+697,832,1,1,7,17,7,97,97,197,697,14,15,'VAAAAA','AGBAAA','AAAAxx'
+4,833,0,0,4,4,4,4,4,4,4,8,9,'EAAAAA','BGBAAA','HHHHxx'
+385,834,1,1,5,5,5,85,185,385,385,10,11,'VOAAAA','CGBAAA','OOOOxx'
+739,835,1,3,9,19,9,39,139,239,739,18,19,'LCAAAA','DGBAAA','VVVVxx'
+623,836,1,3,3,3,3,23,23,123,623,6,7,'ZXAAAA','EGBAAA','AAAAxx'
+547,837,1,3,7,7,7,47,147,47,547,14,15,'BVAAAA','FGBAAA','HHHHxx'
+532,838,0,0,2,12,2,32,132,32,532,4,5,'MUAAAA','GGBAAA','OOOOxx'
+383,839,1,3,3,3,3,83,183,383,383,6,7,'TOAAAA','HGBAAA','VVVVxx'
+181,840,1,1,1,1,1,81,181,181,181,2,3,'ZGAAAA','IGBAAA','AAAAxx'
+327,841,1,3,7,7,7,27,127,327,327,14,15,'PMAAAA','JGBAAA','HHHHxx'
+701,842,1,1,1,1,1,1,101,201,701,2,3,'ZAAAAA','KGBAAA','OOOOxx'
+111,843,1,3,1,11,1,11,111,111,111,2,3,'HEAAAA','LGBAAA','VVVVxx'
+977,844,1,1,7,17,7,77,177,477,977,14,15,'PLAAAA','MGBAAA','AAAAxx'
+431,845,1,3,1,11,1,31,31,431,431,2,3,'PQAAAA','NGBAAA','HHHHxx'
+456,846,0,0,6,16,6,56,56,456,456,12,13,'ORAAAA','OGBAAA','OOOOxx'
+368,847,0,0,8,8,8,68,168,368,368,16,17,'EOAAAA','PGBAAA','VVVVxx'
+32,848,0,0,2,12,2,32,32,32,32,4,5,'GBAAAA','QGBAAA','AAAAxx'
+125,849,1,1,5,5,5,25,125,125,125,10,11,'VEAAAA','RGBAAA','HHHHxx'
+847,850,1,3,7,7,7,47,47,347,847,14,15,'PGAAAA','SGBAAA','OOOOxx'
+485,851,1,1,5,5,5,85,85,485,485,10,11,'RSAAAA','TGBAAA','VVVVxx'
+387,852,1,3,7,7,7,87,187,387,387,14,15,'XOAAAA','UGBAAA','AAAAxx'
+288,853,0,0,8,8,8,88,88,288,288,16,17,'CLAAAA','VGBAAA','HHHHxx'
+919,854,1,3,9,19,9,19,119,419,919,18,19,'JJAAAA','WGBAAA','OOOOxx'
+393,855,1,1,3,13,3,93,193,393,393,6,7,'DPAAAA','XGBAAA','VVVVxx'
+953,856,1,1,3,13,3,53,153,453,953,6,7,'RKAAAA','YGBAAA','AAAAxx'
+798,857,0,2,8,18,8,98,198,298,798,16,17,'SEAAAA','ZGBAAA','HHHHxx'
+940,858,0,0,0,0,0,40,140,440,940,0,1,'EKAAAA','AHBAAA','OOOOxx'
+198,859,0,2,8,18,8,98,198,198,198,16,17,'QHAAAA','BHBAAA','VVVVxx'
+25,860,1,1,5,5,5,25,25,25,25,10,11,'ZAAAAA','CHBAAA','AAAAxx'
+190,861,0,2,0,10,0,90,190,190,190,0,1,'IHAAAA','DHBAAA','HHHHxx'
+820,862,0,0,0,0,0,20,20,320,820,0,1,'OFAAAA','EHBAAA','OOOOxx'
+15,863,1,3,5,15,5,15,15,15,15,10,11,'PAAAAA','FHBAAA','VVVVxx'
+427,864,1,3,7,7,7,27,27,427,427,14,15,'LQAAAA','GHBAAA','AAAAxx'
+349,865,1,1,9,9,9,49,149,349,349,18,19,'LNAAAA','HHBAAA','HHHHxx'
+785,866,1,1,5,5,5,85,185,285,785,10,11,'FEAAAA','IHBAAA','OOOOxx'
+340,867,0,0,0,0,0,40,140,340,340,0,1,'CNAAAA','JHBAAA','VVVVxx'
+292,868,0,0,2,12,2,92,92,292,292,4,5,'GLAAAA','KHBAAA','AAAAxx'
+17,869,1,1,7,17,7,17,17,17,17,14,15,'RAAAAA','LHBAAA','HHHHxx'
+985,870,1,1,5,5,5,85,185,485,985,10,11,'XLAAAA','MHBAAA','OOOOxx'
+645,871,1,1,5,5,5,45,45,145,645,10,11,'VYAAAA','NHBAAA','VVVVxx'
+631,872,1,3,1,11,1,31,31,131,631,2,3,'HYAAAA','OHBAAA','AAAAxx'
+761,873,1,1,1,1,1,61,161,261,761,2,3,'HDAAAA','PHBAAA','HHHHxx'
+707,874,1,3,7,7,7,7,107,207,707,14,15,'FBAAAA','QHBAAA','OOOOxx'
+776,875,0,0,6,16,6,76,176,276,776,12,13,'WDAAAA','RHBAAA','VVVVxx'
+856,876,0,0,6,16,6,56,56,356,856,12,13,'YGAAAA','SHBAAA','AAAAxx'
+978,877,0,2,8,18,8,78,178,478,978,16,17,'QLAAAA','THBAAA','HHHHxx'
+710,878,0,2,0,10,0,10,110,210,710,0,1,'IBAAAA','UHBAAA','OOOOxx'
+604,879,0,0,4,4,4,4,4,104,604,8,9,'GXAAAA','VHBAAA','VVVVxx'
+291,880,1,3,1,11,1,91,91,291,291,2,3,'FLAAAA','WHBAAA','AAAAxx'
+747,881,1,3,7,7,7,47,147,247,747,14,15,'TCAAAA','XHBAAA','HHHHxx'
+837,882,1,1,7,17,7,37,37,337,837,14,15,'FGAAAA','YHBAAA','OOOOxx'
+722,883,0,2,2,2,2,22,122,222,722,4,5,'UBAAAA','ZHBAAA','VVVVxx'
+925,884,1,1,5,5,5,25,125,425,925,10,11,'PJAAAA','AIBAAA','AAAAxx'
+49,885,1,1,9,9,9,49,49,49,49,18,19,'XBAAAA','BIBAAA','HHHHxx'
+832,886,0,0,2,12,2,32,32,332,832,4,5,'AGAAAA','CIBAAA','OOOOxx'
+336,887,0,0,6,16,6,36,136,336,336,12,13,'YMAAAA','DIBAAA','VVVVxx'
+185,888,1,1,5,5,5,85,185,185,185,10,11,'DHAAAA','EIBAAA','AAAAxx'
+434,889,0,2,4,14,4,34,34,434,434,8,9,'SQAAAA','FIBAAA','HHHHxx'
+284,890,0,0,4,4,4,84,84,284,284,8,9,'YKAAAA','GIBAAA','OOOOxx'
+812,891,0,0,2,12,2,12,12,312,812,4,5,'GFAAAA','HIBAAA','VVVVxx'
+810,892,0,2,0,10,0,10,10,310,810,0,1,'EFAAAA','IIBAAA','AAAAxx'
+252,893,0,0,2,12,2,52,52,252,252,4,5,'SJAAAA','JIBAAA','HHHHxx'
+965,894,1,1,5,5,5,65,165,465,965,10,11,'DLAAAA','KIBAAA','OOOOxx'
+110,895,0,2,0,10,0,10,110,110,110,0,1,'GEAAAA','LIBAAA','VVVVxx'
+698,896,0,2,8,18,8,98,98,198,698,16,17,'WAAAAA','MIBAAA','AAAAxx'
+283,897,1,3,3,3,3,83,83,283,283,6,7,'XKAAAA','NIBAAA','HHHHxx'
+533,898,1,1,3,13,3,33,133,33,533,6,7,'NUAAAA','OIBAAA','OOOOxx'
+662,899,0,2,2,2,2,62,62,162,662,4,5,'MZAAAA','PIBAAA','VVVVxx'
+329,900,1,1,9,9,9,29,129,329,329,18,19,'RMAAAA','QIBAAA','AAAAxx'
+250,901,0,2,0,10,0,50,50,250,250,0,1,'QJAAAA','RIBAAA','HHHHxx'
+407,902,1,3,7,7,7,7,7,407,407,14,15,'RPAAAA','SIBAAA','OOOOxx'
+823,903,1,3,3,3,3,23,23,323,823,6,7,'RFAAAA','TIBAAA','VVVVxx'
+852,904,0,0,2,12,2,52,52,352,852,4,5,'UGAAAA','UIBAAA','AAAAxx'
+871,905,1,3,1,11,1,71,71,371,871,2,3,'NHAAAA','VIBAAA','HHHHxx'
+118,906,0,2,8,18,8,18,118,118,118,16,17,'OEAAAA','WIBAAA','OOOOxx'
+912,907,0,0,2,12,2,12,112,412,912,4,5,'CJAAAA','XIBAAA','VVVVxx'
+458,908,0,2,8,18,8,58,58,458,458,16,17,'QRAAAA','YIBAAA','AAAAxx'
+926,909,0,2,6,6,6,26,126,426,926,12,13,'QJAAAA','ZIBAAA','HHHHxx'
+328,910,0,0,8,8,8,28,128,328,328,16,17,'QMAAAA','AJBAAA','OOOOxx'
+980,911,0,0,0,0,0,80,180,480,980,0,1,'SLAAAA','BJBAAA','VVVVxx'
+259,912,1,3,9,19,9,59,59,259,259,18,19,'ZJAAAA','CJBAAA','AAAAxx'
+900,913,0,0,0,0,0,0,100,400,900,0,1,'QIAAAA','DJBAAA','HHHHxx'
+137,914,1,1,7,17,7,37,137,137,137,14,15,'HFAAAA','EJBAAA','OOOOxx'
+159,915,1,3,9,19,9,59,159,159,159,18,19,'DGAAAA','FJBAAA','VVVVxx'
+243,916,1,3,3,3,3,43,43,243,243,6,7,'JJAAAA','GJBAAA','AAAAxx'
+472,917,0,0,2,12,2,72,72,472,472,4,5,'ESAAAA','HJBAAA','HHHHxx'
+796,918,0,0,6,16,6,96,196,296,796,12,13,'QEAAAA','IJBAAA','OOOOxx'
+382,919,0,2,2,2,2,82,182,382,382,4,5,'SOAAAA','JJBAAA','VVVVxx'
+911,920,1,3,1,11,1,11,111,411,911,2,3,'BJAAAA','KJBAAA','AAAAxx'
+179,921,1,3,9,19,9,79,179,179,179,18,19,'XGAAAA','LJBAAA','HHHHxx'
+778,922,0,2,8,18,8,78,178,278,778,16,17,'YDAAAA','MJBAAA','OOOOxx'
+405,923,1,1,5,5,5,5,5,405,405,10,11,'PPAAAA','NJBAAA','VVVVxx'
+265,924,1,1,5,5,5,65,65,265,265,10,11,'FKAAAA','OJBAAA','AAAAxx'
+556,925,0,0,6,16,6,56,156,56,556,12,13,'KVAAAA','PJBAAA','HHHHxx'
+16,926,0,0,6,16,6,16,16,16,16,12,13,'QAAAAA','QJBAAA','OOOOxx'
+706,927,0,2,6,6,6,6,106,206,706,12,13,'EBAAAA','RJBAAA','VVVVxx'
+497,928,1,1,7,17,7,97,97,497,497,14,15,'DTAAAA','SJBAAA','AAAAxx'
+708,929,0,0,8,8,8,8,108,208,708,16,17,'GBAAAA','TJBAAA','HHHHxx'
+46,930,0,2,6,6,6,46,46,46,46,12,13,'UBAAAA','UJBAAA','OOOOxx'
+901,931,1,1,1,1,1,1,101,401,901,2,3,'RIAAAA','VJBAAA','VVVVxx'
+416,932,0,0,6,16,6,16,16,416,416,12,13,'AQAAAA','WJBAAA','AAAAxx'
+307,933,1,3,7,7,7,7,107,307,307,14,15,'VLAAAA','XJBAAA','HHHHxx'
+166,934,0,2,6,6,6,66,166,166,166,12,13,'KGAAAA','YJBAAA','OOOOxx'
+178,935,0,2,8,18,8,78,178,178,178,16,17,'WGAAAA','ZJBAAA','VVVVxx'
+499,936,1,3,9,19,9,99,99,499,499,18,19,'FTAAAA','AKBAAA','AAAAxx'
+257,937,1,1,7,17,7,57,57,257,257,14,15,'XJAAAA','BKBAAA','HHHHxx'
+342,938,0,2,2,2,2,42,142,342,342,4,5,'ENAAAA','CKBAAA','OOOOxx'
+850,939,0,2,0,10,0,50,50,350,850,0,1,'SGAAAA','DKBAAA','VVVVxx'
+313,940,1,1,3,13,3,13,113,313,313,6,7,'BMAAAA','EKBAAA','AAAAxx'
+831,941,1,3,1,11,1,31,31,331,831,2,3,'ZFAAAA','FKBAAA','HHHHxx'
+57,942,1,1,7,17,7,57,57,57,57,14,15,'FCAAAA','GKBAAA','OOOOxx'
+37,943,1,1,7,17,7,37,37,37,37,14,15,'LBAAAA','HKBAAA','VVVVxx'
+511,944,1,3,1,11,1,11,111,11,511,2,3,'RTAAAA','IKBAAA','AAAAxx'
+578,945,0,2,8,18,8,78,178,78,578,16,17,'GWAAAA','JKBAAA','HHHHxx'
+100,946,0,0,0,0,0,0,100,100,100,0,1,'WDAAAA','KKBAAA','OOOOxx'
+935,947,1,3,5,15,5,35,135,435,935,10,11,'ZJAAAA','LKBAAA','VVVVxx'
+821,948,1,1,1,1,1,21,21,321,821,2,3,'PFAAAA','MKBAAA','AAAAxx'
+294,949,0,2,4,14,4,94,94,294,294,8,9,'ILAAAA','NKBAAA','HHHHxx'
+575,950,1,3,5,15,5,75,175,75,575,10,11,'DWAAAA','OKBAAA','OOOOxx'
+272,951,0,0,2,12,2,72,72,272,272,4,5,'MKAAAA','PKBAAA','VVVVxx'
+491,952,1,3,1,11,1,91,91,491,491,2,3,'XSAAAA','QKBAAA','AAAAxx'
+43,953,1,3,3,3,3,43,43,43,43,6,7,'RBAAAA','RKBAAA','HHHHxx'
+167,954,1,3,7,7,7,67,167,167,167,14,15,'LGAAAA','SKBAAA','OOOOxx'
+457,955,1,1,7,17,7,57,57,457,457,14,15,'PRAAAA','TKBAAA','VVVVxx'
+647,956,1,3,7,7,7,47,47,147,647,14,15,'XYAAAA','UKBAAA','AAAAxx'
+180,957,0,0,0,0,0,80,180,180,180,0,1,'YGAAAA','VKBAAA','HHHHxx'
+48,958,0,0,8,8,8,48,48,48,48,16,17,'WBAAAA','WKBAAA','OOOOxx'
+553,959,1,1,3,13,3,53,153,53,553,6,7,'HVAAAA','XKBAAA','VVVVxx'
+188,960,0,0,8,8,8,88,188,188,188,16,17,'GHAAAA','YKBAAA','AAAAxx'
+262,961,0,2,2,2,2,62,62,262,262,4,5,'CKAAAA','ZKBAAA','HHHHxx'
+728,962,0,0,8,8,8,28,128,228,728,16,17,'ACAAAA','ALBAAA','OOOOxx'
+581,963,1,1,1,1,1,81,181,81,581,2,3,'JWAAAA','BLBAAA','VVVVxx'
+937,964,1,1,7,17,7,37,137,437,937,14,15,'BKAAAA','CLBAAA','AAAAxx'
+370,965,0,2,0,10,0,70,170,370,370,0,1,'GOAAAA','DLBAAA','HHHHxx'
+590,966,0,2,0,10,0,90,190,90,590,0,1,'SWAAAA','ELBAAA','OOOOxx'
+421,967,1,1,1,1,1,21,21,421,421,2,3,'FQAAAA','FLBAAA','VVVVxx'
+693,968,1,1,3,13,3,93,93,193,693,6,7,'RAAAAA','GLBAAA','AAAAxx'
+906,969,0,2,6,6,6,6,106,406,906,12,13,'WIAAAA','HLBAAA','HHHHxx'
+802,970,0,2,2,2,2,2,2,302,802,4,5,'WEAAAA','ILBAAA','OOOOxx'
+38,971,0,2,8,18,8,38,38,38,38,16,17,'MBAAAA','JLBAAA','VVVVxx'
+790,972,0,2,0,10,0,90,190,290,790,0,1,'KEAAAA','KLBAAA','AAAAxx'
+726,973,0,2,6,6,6,26,126,226,726,12,13,'YBAAAA','LLBAAA','HHHHxx'
+23,974,1,3,3,3,3,23,23,23,23,6,7,'XAAAAA','MLBAAA','OOOOxx'
+641,975,1,1,1,1,1,41,41,141,641,2,3,'RYAAAA','NLBAAA','VVVVxx'
+524,976,0,0,4,4,4,24,124,24,524,8,9,'EUAAAA','OLBAAA','AAAAxx'
+169,977,1,1,9,9,9,69,169,169,169,18,19,'NGAAAA','PLBAAA','HHHHxx'
+6,978,0,2,6,6,6,6,6,6,6,12,13,'GAAAAA','QLBAAA','OOOOxx'
+943,979,1,3,3,3,3,43,143,443,943,6,7,'HKAAAA','RLBAAA','VVVVxx'
+26,980,0,2,6,6,6,26,26,26,26,12,13,'ABAAAA','SLBAAA','AAAAxx'
+469,981,1,1,9,9,9,69,69,469,469,18,19,'BSAAAA','TLBAAA','HHHHxx'
+968,982,0,0,8,8,8,68,168,468,968,16,17,'GLAAAA','ULBAAA','OOOOxx'
+947,983,1,3,7,7,7,47,147,447,947,14,15,'LKAAAA','VLBAAA','VVVVxx'
+133,984,1,1,3,13,3,33,133,133,133,6,7,'DFAAAA','WLBAAA','AAAAxx'
+52,985,0,0,2,12,2,52,52,52,52,4,5,'ACAAAA','XLBAAA','HHHHxx'
+660,986,0,0,0,0,0,60,60,160,660,0,1,'KZAAAA','YLBAAA','OOOOxx'
+780,987,0,0,0,0,0,80,180,280,780,0,1,'AEAAAA','ZLBAAA','VVVVxx'
+963,988,1,3,3,3,3,63,163,463,963,6,7,'BLAAAA','AMBAAA','AAAAxx'
+561,989,1,1,1,1,1,61,161,61,561,2,3,'PVAAAA','BMBAAA','HHHHxx'
+402,990,0,2,2,2,2,2,2,402,402,4,5,'MPAAAA','CMBAAA','OOOOxx'
+437,991,1,1,7,17,7,37,37,437,437,14,15,'VQAAAA','DMBAAA','VVVVxx'
+112,992,0,0,2,12,2,12,112,112,112,4,5,'IEAAAA','EMBAAA','AAAAxx'
+247,993,1,3,7,7,7,47,47,247,247,14,15,'NJAAAA','FMBAAA','HHHHxx'
+579,994,1,3,9,19,9,79,179,79,579,18,19,'HWAAAA','GMBAAA','OOOOxx'
+379,995,1,3,9,19,9,79,179,379,379,18,19,'POAAAA','HMBAAA','VVVVxx'
+74,996,0,2,4,14,4,74,74,74,74,8,9,'WCAAAA','IMBAAA','AAAAxx'
+744,997,0,0,4,4,4,44,144,244,744,8,9,'QCAAAA','JMBAAA','HHHHxx'
+0,998,0,0,0,0,0,0,0,0,0,0,1,'AAAAAA','KMBAAA','OOOOxx'
+278,999,0,2,8,18,8,78,78,278,278,16,17,'SKAAAA','LMBAAA','VVVVxx'
diff --git a/sql-bench/Data/Wisconsin/tenk.data b/sql-bench/Data/Wisconsin/tenk.data
new file mode 100644
index 00000000000..e9d200a0a8b
--- /dev/null
+++ b/sql-bench/Data/Wisconsin/tenk.data
@@ -0,0 +1,10000 @@
+8800,0,0,0,0,0,0,800,800,3800,8800,0,1,'MAAAAA','AAAAAA','AAAAxx'
+1891,1,1,3,1,11,91,891,1891,1891,1891,182,183,'TUAAAA','BAAAAA','HHHHxx'
+3420,2,0,0,0,0,20,420,1420,3420,3420,40,41,'OBAAAA','CAAAAA','OOOOxx'
+9850,3,0,2,0,10,50,850,1850,4850,9850,100,101,'WOAAAA','DAAAAA','VVVVxx'
+7164,4,0,0,4,4,64,164,1164,2164,7164,128,129,'OPAAAA','EAAAAA','AAAAxx'
+8009,5,1,1,9,9,9,9,9,3009,8009,18,19,'BWAAAA','FAAAAA','HHHHxx'
+5057,6,1,1,7,17,57,57,1057,57,5057,114,115,'NMAAAA','GAAAAA','OOOOxx'
+6701,7,1,1,1,1,1,701,701,1701,6701,2,3,'TXAAAA','HAAAAA','VVVVxx'
+4321,8,1,1,1,1,21,321,321,4321,4321,42,43,'FKAAAA','IAAAAA','AAAAxx'
+3043,9,1,3,3,3,43,43,1043,3043,3043,86,87,'BNAAAA','JAAAAA','HHHHxx'
+1314,10,0,2,4,14,14,314,1314,1314,1314,28,29,'OYAAAA','KAAAAA','OOOOxx'
+1504,11,0,0,4,4,4,504,1504,1504,1504,8,9,'WFAAAA','LAAAAA','VVVVxx'
+5222,12,0,2,2,2,22,222,1222,222,5222,44,45,'WSAAAA','MAAAAA','AAAAxx'
+6243,13,1,3,3,3,43,243,243,1243,6243,86,87,'DGAAAA','NAAAAA','HHHHxx'
+5471,14,1,3,1,11,71,471,1471,471,5471,142,143,'LCAAAA','OAAAAA','OOOOxx'
+5006,15,0,2,6,6,6,6,1006,6,5006,12,13,'OKAAAA','PAAAAA','VVVVxx'
+5387,16,1,3,7,7,87,387,1387,387,5387,174,175,'FZAAAA','QAAAAA','AAAAxx'
+5785,17,1,1,5,5,85,785,1785,785,5785,170,171,'NOAAAA','RAAAAA','HHHHxx'
+6621,18,1,1,1,1,21,621,621,1621,6621,42,43,'RUAAAA','SAAAAA','OOOOxx'
+6969,19,1,1,9,9,69,969,969,1969,6969,138,139,'BIAAAA','TAAAAA','VVVVxx'
+9460,20,0,0,0,0,60,460,1460,4460,9460,120,121,'WZAAAA','UAAAAA','AAAAxx'
+59,21,1,3,9,19,59,59,59,59,59,118,119,'HCAAAA','VAAAAA','HHHHxx'
+8020,22,0,0,0,0,20,20,20,3020,8020,40,41,'MWAAAA','WAAAAA','OOOOxx'
+7695,23,1,3,5,15,95,695,1695,2695,7695,190,191,'ZJAAAA','XAAAAA','VVVVxx'
+3442,24,0,2,2,2,42,442,1442,3442,3442,84,85,'KCAAAA','YAAAAA','AAAAxx'
+5119,25,1,3,9,19,19,119,1119,119,5119,38,39,'XOAAAA','ZAAAAA','HHHHxx'
+646,26,0,2,6,6,46,646,646,646,646,92,93,'WYAAAA','ABAAAA','OOOOxx'
+9605,27,1,1,5,5,5,605,1605,4605,9605,10,11,'LFAAAA','BBAAAA','VVVVxx'
+263,28,1,3,3,3,63,263,263,263,263,126,127,'DKAAAA','CBAAAA','AAAAxx'
+3269,29,1,1,9,9,69,269,1269,3269,3269,138,139,'TVAAAA','DBAAAA','HHHHxx'
+1839,30,1,3,9,19,39,839,1839,1839,1839,78,79,'TSAAAA','EBAAAA','OOOOxx'
+9144,31,0,0,4,4,44,144,1144,4144,9144,88,89,'SNAAAA','FBAAAA','VVVVxx'
+2513,32,1,1,3,13,13,513,513,2513,2513,26,27,'RSAAAA','GBAAAA','AAAAxx'
+8850,33,0,2,0,10,50,850,850,3850,8850,100,101,'KCAAAA','HBAAAA','HHHHxx'
+236,34,0,0,6,16,36,236,236,236,236,72,73,'CJAAAA','IBAAAA','OOOOxx'
+3162,35,0,2,2,2,62,162,1162,3162,3162,124,125,'QRAAAA','JBAAAA','VVVVxx'
+4380,36,0,0,0,0,80,380,380,4380,4380,160,161,'MMAAAA','KBAAAA','AAAAxx'
+8095,37,1,3,5,15,95,95,95,3095,8095,190,191,'JZAAAA','LBAAAA','HHHHxx'
+209,38,1,1,9,9,9,209,209,209,209,18,19,'BIAAAA','MBAAAA','OOOOxx'
+3055,39,1,3,5,15,55,55,1055,3055,3055,110,111,'NNAAAA','NBAAAA','VVVVxx'
+6921,40,1,1,1,1,21,921,921,1921,6921,42,43,'FGAAAA','OBAAAA','AAAAxx'
+7046,41,0,2,6,6,46,46,1046,2046,7046,92,93,'ALAAAA','PBAAAA','HHHHxx'
+7912,42,0,0,2,12,12,912,1912,2912,7912,24,25,'ISAAAA','QBAAAA','OOOOxx'
+7267,43,1,3,7,7,67,267,1267,2267,7267,134,135,'NTAAAA','RBAAAA','VVVVxx'
+3599,44,1,3,9,19,99,599,1599,3599,3599,198,199,'LIAAAA','SBAAAA','AAAAxx'
+923,45,1,3,3,3,23,923,923,923,923,46,47,'NJAAAA','TBAAAA','HHHHxx'
+1437,46,1,1,7,17,37,437,1437,1437,1437,74,75,'HDAAAA','UBAAAA','OOOOxx'
+6439,47,1,3,9,19,39,439,439,1439,6439,78,79,'RNAAAA','VBAAAA','VVVVxx'
+6989,48,1,1,9,9,89,989,989,1989,6989,178,179,'VIAAAA','WBAAAA','AAAAxx'
+8798,49,0,2,8,18,98,798,798,3798,8798,196,197,'KAAAAA','XBAAAA','HHHHxx'
+5960,50,0,0,0,0,60,960,1960,960,5960,120,121,'GVAAAA','YBAAAA','OOOOxx'
+5832,51,0,0,2,12,32,832,1832,832,5832,64,65,'IQAAAA','ZBAAAA','VVVVxx'
+6066,52,0,2,6,6,66,66,66,1066,6066,132,133,'IZAAAA','ACAAAA','AAAAxx'
+322,53,0,2,2,2,22,322,322,322,322,44,45,'KMAAAA','BCAAAA','HHHHxx'
+8321,54,1,1,1,1,21,321,321,3321,8321,42,43,'BIAAAA','CCAAAA','OOOOxx'
+734,55,0,2,4,14,34,734,734,734,734,68,69,'GCAAAA','DCAAAA','VVVVxx'
+688,56,0,0,8,8,88,688,688,688,688,176,177,'MAAAAA','ECAAAA','AAAAxx'
+4212,57,0,0,2,12,12,212,212,4212,4212,24,25,'AGAAAA','FCAAAA','HHHHxx'
+9653,58,1,1,3,13,53,653,1653,4653,9653,106,107,'HHAAAA','GCAAAA','OOOOxx'
+2677,59,1,1,7,17,77,677,677,2677,2677,154,155,'ZYAAAA','HCAAAA','VVVVxx'
+5423,60,1,3,3,3,23,423,1423,423,5423,46,47,'PAAAAA','ICAAAA','AAAAxx'
+2592,61,0,0,2,12,92,592,592,2592,2592,184,185,'SVAAAA','JCAAAA','HHHHxx'
+3233,62,1,1,3,13,33,233,1233,3233,3233,66,67,'JUAAAA','KCAAAA','OOOOxx'
+5032,63,0,0,2,12,32,32,1032,32,5032,64,65,'OLAAAA','LCAAAA','VVVVxx'
+2525,64,1,1,5,5,25,525,525,2525,2525,50,51,'DTAAAA','MCAAAA','AAAAxx'
+4450,65,0,2,0,10,50,450,450,4450,4450,100,101,'EPAAAA','NCAAAA','HHHHxx'
+5778,66,0,2,8,18,78,778,1778,778,5778,156,157,'GOAAAA','OCAAAA','OOOOxx'
+5852,67,0,0,2,12,52,852,1852,852,5852,104,105,'CRAAAA','PCAAAA','VVVVxx'
+5404,68,0,0,4,4,4,404,1404,404,5404,8,9,'WZAAAA','QCAAAA','AAAAxx'
+6223,69,1,3,3,3,23,223,223,1223,6223,46,47,'JFAAAA','RCAAAA','HHHHxx'
+6133,70,1,1,3,13,33,133,133,1133,6133,66,67,'XBAAAA','SCAAAA','OOOOxx'
+9112,71,0,0,2,12,12,112,1112,4112,9112,24,25,'MMAAAA','TCAAAA','VVVVxx'
+7575,72,1,3,5,15,75,575,1575,2575,7575,150,151,'JFAAAA','UCAAAA','AAAAxx'
+7414,73,0,2,4,14,14,414,1414,2414,7414,28,29,'EZAAAA','VCAAAA','HHHHxx'
+9741,74,1,1,1,1,41,741,1741,4741,9741,82,83,'RKAAAA','WCAAAA','OOOOxx'
+3767,75,1,3,7,7,67,767,1767,3767,3767,134,135,'XOAAAA','XCAAAA','VVVVxx'
+9372,76,0,0,2,12,72,372,1372,4372,9372,144,145,'MWAAAA','YCAAAA','AAAAxx'
+8976,77,0,0,6,16,76,976,976,3976,8976,152,153,'GHAAAA','ZCAAAA','HHHHxx'
+4071,78,1,3,1,11,71,71,71,4071,4071,142,143,'PAAAAA','ADAAAA','OOOOxx'
+1311,79,1,3,1,11,11,311,1311,1311,1311,22,23,'LYAAAA','BDAAAA','VVVVxx'
+2604,80,0,0,4,4,4,604,604,2604,2604,8,9,'EWAAAA','CDAAAA','AAAAxx'
+8840,81,0,0,0,0,40,840,840,3840,8840,80,81,'ACAAAA','DDAAAA','HHHHxx'
+567,82,1,3,7,7,67,567,567,567,567,134,135,'VVAAAA','EDAAAA','OOOOxx'
+5215,83,1,3,5,15,15,215,1215,215,5215,30,31,'PSAAAA','FDAAAA','VVVVxx'
+5474,84,0,2,4,14,74,474,1474,474,5474,148,149,'OCAAAA','GDAAAA','AAAAxx'
+3906,85,0,2,6,6,6,906,1906,3906,3906,12,13,'GUAAAA','HDAAAA','HHHHxx'
+1769,86,1,1,9,9,69,769,1769,1769,1769,138,139,'BQAAAA','IDAAAA','OOOOxx'
+1454,87,0,2,4,14,54,454,1454,1454,1454,108,109,'YDAAAA','JDAAAA','VVVVxx'
+6877,88,1,1,7,17,77,877,877,1877,6877,154,155,'NEAAAA','KDAAAA','AAAAxx'
+6501,89,1,1,1,1,1,501,501,1501,6501,2,3,'BQAAAA','LDAAAA','HHHHxx'
+934,90,0,2,4,14,34,934,934,934,934,68,69,'YJAAAA','MDAAAA','OOOOxx'
+4075,91,1,3,5,15,75,75,75,4075,4075,150,151,'TAAAAA','NDAAAA','VVVVxx'
+3180,92,0,0,0,0,80,180,1180,3180,3180,160,161,'ISAAAA','ODAAAA','AAAAxx'
+7787,93,1,3,7,7,87,787,1787,2787,7787,174,175,'NNAAAA','PDAAAA','HHHHxx'
+6401,94,1,1,1,1,1,401,401,1401,6401,2,3,'FMAAAA','QDAAAA','OOOOxx'
+4244,95,0,0,4,4,44,244,244,4244,4244,88,89,'GHAAAA','RDAAAA','VVVVxx'
+4591,96,1,3,1,11,91,591,591,4591,4591,182,183,'PUAAAA','SDAAAA','AAAAxx'
+4113,97,1,1,3,13,13,113,113,4113,4113,26,27,'FCAAAA','TDAAAA','HHHHxx'
+5925,98,1,1,5,5,25,925,1925,925,5925,50,51,'XTAAAA','UDAAAA','OOOOxx'
+1987,99,1,3,7,7,87,987,1987,1987,1987,174,175,'LYAAAA','VDAAAA','VVVVxx'
+8248,100,0,0,8,8,48,248,248,3248,8248,96,97,'GFAAAA','WDAAAA','AAAAxx'
+4151,101,1,3,1,11,51,151,151,4151,4151,102,103,'RDAAAA','XDAAAA','HHHHxx'
+8670,102,0,2,0,10,70,670,670,3670,8670,140,141,'MVAAAA','YDAAAA','OOOOxx'
+6194,103,0,2,4,14,94,194,194,1194,6194,188,189,'GEAAAA','ZDAAAA','VVVVxx'
+88,104,0,0,8,8,88,88,88,88,88,176,177,'KDAAAA','AEAAAA','AAAAxx'
+4058,105,0,2,8,18,58,58,58,4058,4058,116,117,'CAAAAA','BEAAAA','HHHHxx'
+2742,106,0,2,2,2,42,742,742,2742,2742,84,85,'MBAAAA','CEAAAA','OOOOxx'
+8275,107,1,3,5,15,75,275,275,3275,8275,150,151,'HGAAAA','DEAAAA','VVVVxx'
+4258,108,0,2,8,18,58,258,258,4258,4258,116,117,'UHAAAA','EEAAAA','AAAAxx'
+6129,109,1,1,9,9,29,129,129,1129,6129,58,59,'TBAAAA','FEAAAA','HHHHxx'
+7243,110,1,3,3,3,43,243,1243,2243,7243,86,87,'PSAAAA','GEAAAA','OOOOxx'
+2392,111,0,0,2,12,92,392,392,2392,2392,184,185,'AOAAAA','HEAAAA','VVVVxx'
+9853,112,1,1,3,13,53,853,1853,4853,9853,106,107,'ZOAAAA','IEAAAA','AAAAxx'
+6064,113,0,0,4,4,64,64,64,1064,6064,128,129,'GZAAAA','JEAAAA','HHHHxx'
+4391,114,1,3,1,11,91,391,391,4391,4391,182,183,'XMAAAA','KEAAAA','OOOOxx'
+726,115,0,2,6,6,26,726,726,726,726,52,53,'YBAAAA','LEAAAA','VVVVxx'
+6957,116,1,1,7,17,57,957,957,1957,6957,114,115,'PHAAAA','MEAAAA','AAAAxx'
+3853,117,1,1,3,13,53,853,1853,3853,3853,106,107,'FSAAAA','NEAAAA','HHHHxx'
+4524,118,0,0,4,4,24,524,524,4524,4524,48,49,'ASAAAA','OEAAAA','OOOOxx'
+5330,119,0,2,0,10,30,330,1330,330,5330,60,61,'AXAAAA','PEAAAA','VVVVxx'
+6671,120,1,3,1,11,71,671,671,1671,6671,142,143,'PWAAAA','QEAAAA','AAAAxx'
+5314,121,0,2,4,14,14,314,1314,314,5314,28,29,'KWAAAA','REAAAA','HHHHxx'
+9202,122,0,2,2,2,2,202,1202,4202,9202,4,5,'YPAAAA','SEAAAA','OOOOxx'
+4596,123,0,0,6,16,96,596,596,4596,4596,192,193,'UUAAAA','TEAAAA','VVVVxx'
+8951,124,1,3,1,11,51,951,951,3951,8951,102,103,'HGAAAA','UEAAAA','AAAAxx'
+9902,125,0,2,2,2,2,902,1902,4902,9902,4,5,'WQAAAA','VEAAAA','HHHHxx'
+1440,126,0,0,0,0,40,440,1440,1440,1440,80,81,'KDAAAA','WEAAAA','OOOOxx'
+5339,127,1,3,9,19,39,339,1339,339,5339,78,79,'JXAAAA','XEAAAA','VVVVxx'
+3371,128,1,3,1,11,71,371,1371,3371,3371,142,143,'RZAAAA','YEAAAA','AAAAxx'
+4467,129,1,3,7,7,67,467,467,4467,4467,134,135,'VPAAAA','ZEAAAA','HHHHxx'
+6216,130,0,0,6,16,16,216,216,1216,6216,32,33,'CFAAAA','AFAAAA','OOOOxx'
+5364,131,0,0,4,4,64,364,1364,364,5364,128,129,'IYAAAA','BFAAAA','VVVVxx'
+7547,132,1,3,7,7,47,547,1547,2547,7547,94,95,'HEAAAA','CFAAAA','AAAAxx'
+4338,133,0,2,8,18,38,338,338,4338,4338,76,77,'WKAAAA','DFAAAA','HHHHxx'
+3481,134,1,1,1,1,81,481,1481,3481,3481,162,163,'XDAAAA','EFAAAA','OOOOxx'
+826,135,0,2,6,6,26,826,826,826,826,52,53,'UFAAAA','FFAAAA','VVVVxx'
+3647,136,1,3,7,7,47,647,1647,3647,3647,94,95,'HKAAAA','GFAAAA','AAAAxx'
+3337,137,1,1,7,17,37,337,1337,3337,3337,74,75,'JYAAAA','HFAAAA','HHHHxx'
+3591,138,1,3,1,11,91,591,1591,3591,3591,182,183,'DIAAAA','IFAAAA','OOOOxx'
+7192,139,0,0,2,12,92,192,1192,2192,7192,184,185,'QQAAAA','JFAAAA','VVVVxx'
+1078,140,0,2,8,18,78,78,1078,1078,1078,156,157,'MPAAAA','KFAAAA','AAAAxx'
+1310,141,0,2,0,10,10,310,1310,1310,1310,20,21,'KYAAAA','LFAAAA','HHHHxx'
+9642,142,0,2,2,2,42,642,1642,4642,9642,84,85,'WGAAAA','MFAAAA','OOOOxx'
+39,143,1,3,9,19,39,39,39,39,39,78,79,'NBAAAA','NFAAAA','VVVVxx'
+8682,144,0,2,2,2,82,682,682,3682,8682,164,165,'YVAAAA','OFAAAA','AAAAxx'
+1794,145,0,2,4,14,94,794,1794,1794,1794,188,189,'ARAAAA','PFAAAA','HHHHxx'
+5630,146,0,2,0,10,30,630,1630,630,5630,60,61,'OIAAAA','QFAAAA','OOOOxx'
+6748,147,0,0,8,8,48,748,748,1748,6748,96,97,'OZAAAA','RFAAAA','VVVVxx'
+3766,148,0,2,6,6,66,766,1766,3766,3766,132,133,'WOAAAA','SFAAAA','AAAAxx'
+6403,149,1,3,3,3,3,403,403,1403,6403,6,7,'HMAAAA','TFAAAA','HHHHxx'
+175,150,1,3,5,15,75,175,175,175,175,150,151,'TGAAAA','UFAAAA','OOOOxx'
+2179,151,1,3,9,19,79,179,179,2179,2179,158,159,'VFAAAA','VFAAAA','VVVVxx'
+7897,152,1,1,7,17,97,897,1897,2897,7897,194,195,'TRAAAA','WFAAAA','AAAAxx'
+2760,153,0,0,0,0,60,760,760,2760,2760,120,121,'ECAAAA','XFAAAA','HHHHxx'
+1675,154,1,3,5,15,75,675,1675,1675,1675,150,151,'LMAAAA','YFAAAA','OOOOxx'
+2564,155,0,0,4,4,64,564,564,2564,2564,128,129,'QUAAAA','ZFAAAA','VVVVxx'
+157,156,1,1,7,17,57,157,157,157,157,114,115,'BGAAAA','AGAAAA','AAAAxx'
+8779,157,1,3,9,19,79,779,779,3779,8779,158,159,'RZAAAA','BGAAAA','HHHHxx'
+9591,158,1,3,1,11,91,591,1591,4591,9591,182,183,'XEAAAA','CGAAAA','OOOOxx'
+8732,159,0,0,2,12,32,732,732,3732,8732,64,65,'WXAAAA','DGAAAA','VVVVxx'
+139,160,1,3,9,19,39,139,139,139,139,78,79,'JFAAAA','EGAAAA','AAAAxx'
+5372,161,0,0,2,12,72,372,1372,372,5372,144,145,'QYAAAA','FGAAAA','HHHHxx'
+1278,162,0,2,8,18,78,278,1278,1278,1278,156,157,'EXAAAA','GGAAAA','OOOOxx'
+4697,163,1,1,7,17,97,697,697,4697,4697,194,195,'RYAAAA','HGAAAA','VVVVxx'
+8610,164,0,2,0,10,10,610,610,3610,8610,20,21,'ETAAAA','IGAAAA','AAAAxx'
+8180,165,0,0,0,0,80,180,180,3180,8180,160,161,'QCAAAA','JGAAAA','HHHHxx'
+2399,166,1,3,9,19,99,399,399,2399,2399,198,199,'HOAAAA','KGAAAA','OOOOxx'
+615,167,1,3,5,15,15,615,615,615,615,30,31,'RXAAAA','LGAAAA','VVVVxx'
+7629,168,1,1,9,9,29,629,1629,2629,7629,58,59,'LHAAAA','MGAAAA','AAAAxx'
+7628,169,0,0,8,8,28,628,1628,2628,7628,56,57,'KHAAAA','NGAAAA','HHHHxx'
+4659,170,1,3,9,19,59,659,659,4659,4659,118,119,'FXAAAA','OGAAAA','OOOOxx'
+5865,171,1,1,5,5,65,865,1865,865,5865,130,131,'PRAAAA','PGAAAA','VVVVxx'
+3973,172,1,1,3,13,73,973,1973,3973,3973,146,147,'VWAAAA','QGAAAA','AAAAxx'
+552,173,0,0,2,12,52,552,552,552,552,104,105,'GVAAAA','RGAAAA','HHHHxx'
+708,174,0,0,8,8,8,708,708,708,708,16,17,'GBAAAA','SGAAAA','OOOOxx'
+3550,175,0,2,0,10,50,550,1550,3550,3550,100,101,'OGAAAA','TGAAAA','VVVVxx'
+5547,176,1,3,7,7,47,547,1547,547,5547,94,95,'JFAAAA','UGAAAA','AAAAxx'
+489,177,1,1,9,9,89,489,489,489,489,178,179,'VSAAAA','VGAAAA','HHHHxx'
+3794,178,0,2,4,14,94,794,1794,3794,3794,188,189,'YPAAAA','WGAAAA','OOOOxx'
+9479,179,1,3,9,19,79,479,1479,4479,9479,158,159,'PAAAAA','XGAAAA','VVVVxx'
+6435,180,1,3,5,15,35,435,435,1435,6435,70,71,'NNAAAA','YGAAAA','AAAAxx'
+5120,181,0,0,0,0,20,120,1120,120,5120,40,41,'YOAAAA','ZGAAAA','HHHHxx'
+3615,182,1,3,5,15,15,615,1615,3615,3615,30,31,'BJAAAA','AHAAAA','OOOOxx'
+8399,183,1,3,9,19,99,399,399,3399,8399,198,199,'BLAAAA','BHAAAA','VVVVxx'
+2155,184,1,3,5,15,55,155,155,2155,2155,110,111,'XEAAAA','CHAAAA','AAAAxx'
+6690,185,0,2,0,10,90,690,690,1690,6690,180,181,'IXAAAA','DHAAAA','HHHHxx'
+1683,186,1,3,3,3,83,683,1683,1683,1683,166,167,'TMAAAA','EHAAAA','OOOOxx'
+6302,187,0,2,2,2,2,302,302,1302,6302,4,5,'KIAAAA','FHAAAA','VVVVxx'
+516,188,0,0,6,16,16,516,516,516,516,32,33,'WTAAAA','GHAAAA','AAAAxx'
+3901,189,1,1,1,1,1,901,1901,3901,3901,2,3,'BUAAAA','HHAAAA','HHHHxx'
+6938,190,0,2,8,18,38,938,938,1938,6938,76,77,'WGAAAA','IHAAAA','OOOOxx'
+7484,191,0,0,4,4,84,484,1484,2484,7484,168,169,'WBAAAA','JHAAAA','VVVVxx'
+7424,192,0,0,4,4,24,424,1424,2424,7424,48,49,'OZAAAA','KHAAAA','AAAAxx'
+9410,193,0,2,0,10,10,410,1410,4410,9410,20,21,'YXAAAA','LHAAAA','HHHHxx'
+1714,194,0,2,4,14,14,714,1714,1714,1714,28,29,'YNAAAA','MHAAAA','OOOOxx'
+8278,195,0,2,8,18,78,278,278,3278,8278,156,157,'KGAAAA','NHAAAA','VVVVxx'
+3158,196,0,2,8,18,58,158,1158,3158,3158,116,117,'MRAAAA','OHAAAA','AAAAxx'
+2511,197,1,3,1,11,11,511,511,2511,2511,22,23,'PSAAAA','PHAAAA','HHHHxx'
+2912,198,0,0,2,12,12,912,912,2912,2912,24,25,'AIAAAA','QHAAAA','OOOOxx'
+2648,199,0,0,8,8,48,648,648,2648,2648,96,97,'WXAAAA','RHAAAA','VVVVxx'
+9385,200,1,1,5,5,85,385,1385,4385,9385,170,171,'ZWAAAA','SHAAAA','AAAAxx'
+7545,201,1,1,5,5,45,545,1545,2545,7545,90,91,'FEAAAA','THAAAA','HHHHxx'
+8407,202,1,3,7,7,7,407,407,3407,8407,14,15,'JLAAAA','UHAAAA','OOOOxx'
+5893,203,1,1,3,13,93,893,1893,893,5893,186,187,'RSAAAA','VHAAAA','VVVVxx'
+7049,204,1,1,9,9,49,49,1049,2049,7049,98,99,'DLAAAA','WHAAAA','AAAAxx'
+6812,205,0,0,2,12,12,812,812,1812,6812,24,25,'ACAAAA','XHAAAA','HHHHxx'
+3649,206,1,1,9,9,49,649,1649,3649,3649,98,99,'JKAAAA','YHAAAA','OOOOxx'
+9275,207,1,3,5,15,75,275,1275,4275,9275,150,151,'TSAAAA','ZHAAAA','VVVVxx'
+1179,208,1,3,9,19,79,179,1179,1179,1179,158,159,'JTAAAA','AIAAAA','AAAAxx'
+969,209,1,1,9,9,69,969,969,969,969,138,139,'HLAAAA','BIAAAA','HHHHxx'
+7920,210,0,0,0,0,20,920,1920,2920,7920,40,41,'QSAAAA','CIAAAA','OOOOxx'
+998,211,0,2,8,18,98,998,998,998,998,196,197,'KMAAAA','DIAAAA','VVVVxx'
+3958,212,0,2,8,18,58,958,1958,3958,3958,116,117,'GWAAAA','EIAAAA','AAAAxx'
+6052,213,0,0,2,12,52,52,52,1052,6052,104,105,'UYAAAA','FIAAAA','HHHHxx'
+8791,214,1,3,1,11,91,791,791,3791,8791,182,183,'DAAAAA','GIAAAA','OOOOxx'
+5191,215,1,3,1,11,91,191,1191,191,5191,182,183,'RRAAAA','HIAAAA','VVVVxx'
+4267,216,1,3,7,7,67,267,267,4267,4267,134,135,'DIAAAA','IIAAAA','AAAAxx'
+2829,217,1,1,9,9,29,829,829,2829,2829,58,59,'VEAAAA','JIAAAA','HHHHxx'
+6396,218,0,0,6,16,96,396,396,1396,6396,192,193,'AMAAAA','KIAAAA','OOOOxx'
+9413,219,1,1,3,13,13,413,1413,4413,9413,26,27,'BYAAAA','LIAAAA','VVVVxx'
+614,220,0,2,4,14,14,614,614,614,614,28,29,'QXAAAA','MIAAAA','AAAAxx'
+4660,221,0,0,0,0,60,660,660,4660,4660,120,121,'GXAAAA','NIAAAA','HHHHxx'
+8834,222,0,2,4,14,34,834,834,3834,8834,68,69,'UBAAAA','OIAAAA','OOOOxx'
+2767,223,1,3,7,7,67,767,767,2767,2767,134,135,'LCAAAA','PIAAAA','VVVVxx'
+2444,224,0,0,4,4,44,444,444,2444,2444,88,89,'AQAAAA','QIAAAA','AAAAxx'
+4129,225,1,1,9,9,29,129,129,4129,4129,58,59,'VCAAAA','RIAAAA','HHHHxx'
+3394,226,0,2,4,14,94,394,1394,3394,3394,188,189,'OAAAAA','SIAAAA','OOOOxx'
+2705,227,1,1,5,5,5,705,705,2705,2705,10,11,'BAAAAA','TIAAAA','VVVVxx'
+8499,228,1,3,9,19,99,499,499,3499,8499,198,199,'XOAAAA','UIAAAA','AAAAxx'
+8852,229,0,0,2,12,52,852,852,3852,8852,104,105,'MCAAAA','VIAAAA','HHHHxx'
+6174,230,0,2,4,14,74,174,174,1174,6174,148,149,'MDAAAA','WIAAAA','OOOOxx'
+750,231,0,2,0,10,50,750,750,750,750,100,101,'WCAAAA','XIAAAA','VVVVxx'
+8164,232,0,0,4,4,64,164,164,3164,8164,128,129,'ACAAAA','YIAAAA','AAAAxx'
+4930,233,0,2,0,10,30,930,930,4930,4930,60,61,'QHAAAA','ZIAAAA','HHHHxx'
+9904,234,0,0,4,4,4,904,1904,4904,9904,8,9,'YQAAAA','AJAAAA','OOOOxx'
+7378,235,0,2,8,18,78,378,1378,2378,7378,156,157,'UXAAAA','BJAAAA','VVVVxx'
+2927,236,1,3,7,7,27,927,927,2927,2927,54,55,'PIAAAA','CJAAAA','AAAAxx'
+7155,237,1,3,5,15,55,155,1155,2155,7155,110,111,'FPAAAA','DJAAAA','HHHHxx'
+1302,238,0,2,2,2,2,302,1302,1302,1302,4,5,'CYAAAA','EJAAAA','OOOOxx'
+5904,239,0,0,4,4,4,904,1904,904,5904,8,9,'CTAAAA','FJAAAA','VVVVxx'
+9687,240,1,3,7,7,87,687,1687,4687,9687,174,175,'PIAAAA','GJAAAA','AAAAxx'
+3553,241,1,1,3,13,53,553,1553,3553,3553,106,107,'RGAAAA','HJAAAA','HHHHxx'
+4447,242,1,3,7,7,47,447,447,4447,4447,94,95,'BPAAAA','IJAAAA','OOOOxx'
+6878,243,0,2,8,18,78,878,878,1878,6878,156,157,'OEAAAA','JJAAAA','VVVVxx'
+9470,244,0,2,0,10,70,470,1470,4470,9470,140,141,'GAAAAA','KJAAAA','AAAAxx'
+9735,245,1,3,5,15,35,735,1735,4735,9735,70,71,'LKAAAA','LJAAAA','HHHHxx'
+5967,246,1,3,7,7,67,967,1967,967,5967,134,135,'NVAAAA','MJAAAA','OOOOxx'
+6601,247,1,1,1,1,1,601,601,1601,6601,2,3,'XTAAAA','NJAAAA','VVVVxx'
+7631,248,1,3,1,11,31,631,1631,2631,7631,62,63,'NHAAAA','OJAAAA','AAAAxx'
+3559,249,1,3,9,19,59,559,1559,3559,3559,118,119,'XGAAAA','PJAAAA','HHHHxx'
+2247,250,1,3,7,7,47,247,247,2247,2247,94,95,'LIAAAA','QJAAAA','OOOOxx'
+9649,251,1,1,9,9,49,649,1649,4649,9649,98,99,'DHAAAA','RJAAAA','VVVVxx'
+808,252,0,0,8,8,8,808,808,808,808,16,17,'CFAAAA','SJAAAA','AAAAxx'
+240,253,0,0,0,0,40,240,240,240,240,80,81,'GJAAAA','TJAAAA','HHHHxx'
+5031,254,1,3,1,11,31,31,1031,31,5031,62,63,'NLAAAA','UJAAAA','OOOOxx'
+9563,255,1,3,3,3,63,563,1563,4563,9563,126,127,'VDAAAA','VJAAAA','VVVVxx'
+5656,256,0,0,6,16,56,656,1656,656,5656,112,113,'OJAAAA','WJAAAA','AAAAxx'
+3886,257,0,2,6,6,86,886,1886,3886,3886,172,173,'MTAAAA','XJAAAA','HHHHxx'
+2431,258,1,3,1,11,31,431,431,2431,2431,62,63,'NPAAAA','YJAAAA','OOOOxx'
+5560,259,0,0,0,0,60,560,1560,560,5560,120,121,'WFAAAA','ZJAAAA','VVVVxx'
+9065,260,1,1,5,5,65,65,1065,4065,9065,130,131,'RKAAAA','AKAAAA','AAAAxx'
+8130,261,0,2,0,10,30,130,130,3130,8130,60,61,'SAAAAA','BKAAAA','HHHHxx'
+4054,262,0,2,4,14,54,54,54,4054,4054,108,109,'YZAAAA','CKAAAA','OOOOxx'
+873,263,1,1,3,13,73,873,873,873,873,146,147,'PHAAAA','DKAAAA','VVVVxx'
+3092,264,0,0,2,12,92,92,1092,3092,3092,184,185,'YOAAAA','EKAAAA','AAAAxx'
+6697,265,1,1,7,17,97,697,697,1697,6697,194,195,'PXAAAA','FKAAAA','HHHHxx'
+2452,266,0,0,2,12,52,452,452,2452,2452,104,105,'IQAAAA','GKAAAA','OOOOxx'
+7867,267,1,3,7,7,67,867,1867,2867,7867,134,135,'PQAAAA','HKAAAA','VVVVxx'
+3753,268,1,1,3,13,53,753,1753,3753,3753,106,107,'JOAAAA','IKAAAA','AAAAxx'
+7834,269,0,2,4,14,34,834,1834,2834,7834,68,69,'IPAAAA','JKAAAA','HHHHxx'
+5846,270,0,2,6,6,46,846,1846,846,5846,92,93,'WQAAAA','KKAAAA','OOOOxx'
+7604,271,0,0,4,4,4,604,1604,2604,7604,8,9,'MGAAAA','LKAAAA','VVVVxx'
+3452,272,0,0,2,12,52,452,1452,3452,3452,104,105,'UCAAAA','MKAAAA','AAAAxx'
+4788,273,0,0,8,8,88,788,788,4788,4788,176,177,'ECAAAA','NKAAAA','HHHHxx'
+8600,274,0,0,0,0,0,600,600,3600,8600,0,1,'USAAAA','OKAAAA','OOOOxx'
+8511,275,1,3,1,11,11,511,511,3511,8511,22,23,'JPAAAA','PKAAAA','VVVVxx'
+4452,276,0,0,2,12,52,452,452,4452,4452,104,105,'GPAAAA','QKAAAA','AAAAxx'
+1709,277,1,1,9,9,9,709,1709,1709,1709,18,19,'TNAAAA','RKAAAA','HHHHxx'
+3440,278,0,0,0,0,40,440,1440,3440,3440,80,81,'ICAAAA','SKAAAA','OOOOxx'
+9188,279,0,0,8,8,88,188,1188,4188,9188,176,177,'KPAAAA','TKAAAA','VVVVxx'
+3058,280,0,2,8,18,58,58,1058,3058,3058,116,117,'QNAAAA','UKAAAA','AAAAxx'
+5821,281,1,1,1,1,21,821,1821,821,5821,42,43,'XPAAAA','VKAAAA','HHHHxx'
+3428,282,0,0,8,8,28,428,1428,3428,3428,56,57,'WBAAAA','WKAAAA','OOOOxx'
+3581,283,1,1,1,1,81,581,1581,3581,3581,162,163,'THAAAA','XKAAAA','VVVVxx'
+7523,284,1,3,3,3,23,523,1523,2523,7523,46,47,'JDAAAA','YKAAAA','AAAAxx'
+3131,285,1,3,1,11,31,131,1131,3131,3131,62,63,'LQAAAA','ZKAAAA','HHHHxx'
+2404,286,0,0,4,4,4,404,404,2404,2404,8,9,'MOAAAA','ALAAAA','OOOOxx'
+5453,287,1,1,3,13,53,453,1453,453,5453,106,107,'TBAAAA','BLAAAA','VVVVxx'
+1599,288,1,3,9,19,99,599,1599,1599,1599,198,199,'NJAAAA','CLAAAA','AAAAxx'
+7081,289,1,1,1,1,81,81,1081,2081,7081,162,163,'JMAAAA','DLAAAA','HHHHxx'
+1750,290,0,2,0,10,50,750,1750,1750,1750,100,101,'IPAAAA','ELAAAA','OOOOxx'
+5085,291,1,1,5,5,85,85,1085,85,5085,170,171,'PNAAAA','FLAAAA','VVVVxx'
+9777,292,1,1,7,17,77,777,1777,4777,9777,154,155,'BMAAAA','GLAAAA','AAAAxx'
+574,293,0,2,4,14,74,574,574,574,574,148,149,'CWAAAA','HLAAAA','HHHHxx'
+5984,294,0,0,4,4,84,984,1984,984,5984,168,169,'EWAAAA','ILAAAA','OOOOxx'
+7039,295,1,3,9,19,39,39,1039,2039,7039,78,79,'TKAAAA','JLAAAA','VVVVxx'
+7143,296,1,3,3,3,43,143,1143,2143,7143,86,87,'TOAAAA','KLAAAA','AAAAxx'
+5702,297,0,2,2,2,2,702,1702,702,5702,4,5,'ILAAAA','LLAAAA','HHHHxx'
+362,298,0,2,2,2,62,362,362,362,362,124,125,'YNAAAA','MLAAAA','OOOOxx'
+6997,299,1,1,7,17,97,997,997,1997,6997,194,195,'DJAAAA','NLAAAA','VVVVxx'
+2529,300,1,1,9,9,29,529,529,2529,2529,58,59,'HTAAAA','OLAAAA','AAAAxx'
+6319,301,1,3,9,19,19,319,319,1319,6319,38,39,'BJAAAA','PLAAAA','HHHHxx'
+954,302,0,2,4,14,54,954,954,954,954,108,109,'SKAAAA','QLAAAA','OOOOxx'
+3413,303,1,1,3,13,13,413,1413,3413,3413,26,27,'HBAAAA','RLAAAA','VVVVxx'
+9081,304,1,1,1,1,81,81,1081,4081,9081,162,163,'HLAAAA','SLAAAA','AAAAxx'
+5599,305,1,3,9,19,99,599,1599,599,5599,198,199,'JHAAAA','TLAAAA','HHHHxx'
+4772,306,0,0,2,12,72,772,772,4772,4772,144,145,'OBAAAA','ULAAAA','OOOOxx'
+1124,307,0,0,4,4,24,124,1124,1124,1124,48,49,'GRAAAA','VLAAAA','VVVVxx'
+7793,308,1,1,3,13,93,793,1793,2793,7793,186,187,'TNAAAA','WLAAAA','AAAAxx'
+4201,309,1,1,1,1,1,201,201,4201,4201,2,3,'PFAAAA','XLAAAA','HHHHxx'
+7015,310,1,3,5,15,15,15,1015,2015,7015,30,31,'VJAAAA','YLAAAA','OOOOxx'
+5936,311,0,0,6,16,36,936,1936,936,5936,72,73,'IUAAAA','ZLAAAA','VVVVxx'
+4625,312,1,1,5,5,25,625,625,4625,4625,50,51,'XVAAAA','AMAAAA','AAAAxx'
+4989,313,1,1,9,9,89,989,989,4989,4989,178,179,'XJAAAA','BMAAAA','HHHHxx'
+4949,314,1,1,9,9,49,949,949,4949,4949,98,99,'JIAAAA','CMAAAA','OOOOxx'
+6273,315,1,1,3,13,73,273,273,1273,6273,146,147,'HHAAAA','DMAAAA','VVVVxx'
+4478,316,0,2,8,18,78,478,478,4478,4478,156,157,'GQAAAA','EMAAAA','AAAAxx'
+8854,317,0,2,4,14,54,854,854,3854,8854,108,109,'OCAAAA','FMAAAA','HHHHxx'
+2105,318,1,1,5,5,5,105,105,2105,2105,10,11,'ZCAAAA','GMAAAA','OOOOxx'
+8345,319,1,1,5,5,45,345,345,3345,8345,90,91,'ZIAAAA','HMAAAA','VVVVxx'
+1941,320,1,1,1,1,41,941,1941,1941,1941,82,83,'RWAAAA','IMAAAA','AAAAxx'
+1765,321,1,1,5,5,65,765,1765,1765,1765,130,131,'XPAAAA','JMAAAA','HHHHxx'
+9592,322,0,0,2,12,92,592,1592,4592,9592,184,185,'YEAAAA','KMAAAA','OOOOxx'
+1694,323,0,2,4,14,94,694,1694,1694,1694,188,189,'ENAAAA','LMAAAA','VVVVxx'
+8940,324,0,0,0,0,40,940,940,3940,8940,80,81,'WFAAAA','MMAAAA','AAAAxx'
+7264,325,0,0,4,4,64,264,1264,2264,7264,128,129,'KTAAAA','NMAAAA','HHHHxx'
+4699,326,1,3,9,19,99,699,699,4699,4699,198,199,'TYAAAA','OMAAAA','OOOOxx'
+4541,327,1,1,1,1,41,541,541,4541,4541,82,83,'RSAAAA','PMAAAA','VVVVxx'
+5768,328,0,0,8,8,68,768,1768,768,5768,136,137,'WNAAAA','QMAAAA','AAAAxx'
+6183,329,1,3,3,3,83,183,183,1183,6183,166,167,'VDAAAA','RMAAAA','HHHHxx'
+7457,330,1,1,7,17,57,457,1457,2457,7457,114,115,'VAAAAA','SMAAAA','OOOOxx'
+7317,331,1,1,7,17,17,317,1317,2317,7317,34,35,'LVAAAA','TMAAAA','VVVVxx'
+1944,332,0,0,4,4,44,944,1944,1944,1944,88,89,'UWAAAA','UMAAAA','AAAAxx'
+665,333,1,1,5,5,65,665,665,665,665,130,131,'PZAAAA','VMAAAA','HHHHxx'
+5974,334,0,2,4,14,74,974,1974,974,5974,148,149,'UVAAAA','WMAAAA','OOOOxx'
+7370,335,0,2,0,10,70,370,1370,2370,7370,140,141,'MXAAAA','XMAAAA','VVVVxx'
+9196,336,0,0,6,16,96,196,1196,4196,9196,192,193,'SPAAAA','YMAAAA','AAAAxx'
+6796,337,0,0,6,16,96,796,796,1796,6796,192,193,'KBAAAA','ZMAAAA','HHHHxx'
+6180,338,0,0,0,0,80,180,180,1180,6180,160,161,'SDAAAA','ANAAAA','OOOOxx'
+8557,339,1,1,7,17,57,557,557,3557,8557,114,115,'DRAAAA','BNAAAA','VVVVxx'
+928,340,0,0,8,8,28,928,928,928,928,56,57,'SJAAAA','CNAAAA','AAAAxx'
+6275,341,1,3,5,15,75,275,275,1275,6275,150,151,'JHAAAA','DNAAAA','HHHHxx'
+409,342,1,1,9,9,9,409,409,409,409,18,19,'TPAAAA','ENAAAA','OOOOxx'
+6442,343,0,2,2,2,42,442,442,1442,6442,84,85,'UNAAAA','FNAAAA','VVVVxx'
+5889,344,1,1,9,9,89,889,1889,889,5889,178,179,'NSAAAA','GNAAAA','AAAAxx'
+5180,345,0,0,0,0,80,180,1180,180,5180,160,161,'GRAAAA','HNAAAA','HHHHxx'
+1629,346,1,1,9,9,29,629,1629,1629,1629,58,59,'RKAAAA','INAAAA','OOOOxx'
+6088,347,0,0,8,8,88,88,88,1088,6088,176,177,'EAAAAA','JNAAAA','VVVVxx'
+5598,348,0,2,8,18,98,598,1598,598,5598,196,197,'IHAAAA','KNAAAA','AAAAxx'
+1803,349,1,3,3,3,3,803,1803,1803,1803,6,7,'JRAAAA','LNAAAA','HHHHxx'
+2330,350,0,2,0,10,30,330,330,2330,2330,60,61,'QLAAAA','MNAAAA','OOOOxx'
+5901,351,1,1,1,1,1,901,1901,901,5901,2,3,'ZSAAAA','NNAAAA','VVVVxx'
+780,352,0,0,0,0,80,780,780,780,780,160,161,'AEAAAA','ONAAAA','AAAAxx'
+7171,353,1,3,1,11,71,171,1171,2171,7171,142,143,'VPAAAA','PNAAAA','HHHHxx'
+8778,354,0,2,8,18,78,778,778,3778,8778,156,157,'QZAAAA','QNAAAA','OOOOxx'
+6622,355,0,2,2,2,22,622,622,1622,6622,44,45,'SUAAAA','RNAAAA','VVVVxx'
+9938,356,0,2,8,18,38,938,1938,4938,9938,76,77,'GSAAAA','SNAAAA','AAAAxx'
+8254,357,0,2,4,14,54,254,254,3254,8254,108,109,'MFAAAA','TNAAAA','HHHHxx'
+1951,358,1,3,1,11,51,951,1951,1951,1951,102,103,'BXAAAA','UNAAAA','OOOOxx'
+1434,359,0,2,4,14,34,434,1434,1434,1434,68,69,'EDAAAA','VNAAAA','VVVVxx'
+7539,360,1,3,9,19,39,539,1539,2539,7539,78,79,'ZDAAAA','WNAAAA','AAAAxx'
+600,361,0,0,0,0,0,600,600,600,600,0,1,'CXAAAA','XNAAAA','HHHHxx'
+3122,362,0,2,2,2,22,122,1122,3122,3122,44,45,'CQAAAA','YNAAAA','OOOOxx'
+5704,363,0,0,4,4,4,704,1704,704,5704,8,9,'KLAAAA','ZNAAAA','VVVVxx'
+6300,364,0,0,0,0,0,300,300,1300,6300,0,1,'IIAAAA','AOAAAA','AAAAxx'
+4585,365,1,1,5,5,85,585,585,4585,4585,170,171,'JUAAAA','BOAAAA','HHHHxx'
+6313,366,1,1,3,13,13,313,313,1313,6313,26,27,'VIAAAA','COAAAA','OOOOxx'
+3154,367,0,2,4,14,54,154,1154,3154,3154,108,109,'IRAAAA','DOAAAA','VVVVxx'
+642,368,0,2,2,2,42,642,642,642,642,84,85,'SYAAAA','EOAAAA','AAAAxx'
+7736,369,0,0,6,16,36,736,1736,2736,7736,72,73,'OLAAAA','FOAAAA','HHHHxx'
+5087,370,1,3,7,7,87,87,1087,87,5087,174,175,'RNAAAA','GOAAAA','OOOOxx'
+5708,371,0,0,8,8,8,708,1708,708,5708,16,17,'OLAAAA','HOAAAA','VVVVxx'
+8169,372,1,1,9,9,69,169,169,3169,8169,138,139,'FCAAAA','IOAAAA','AAAAxx'
+9768,373,0,0,8,8,68,768,1768,4768,9768,136,137,'SLAAAA','JOAAAA','HHHHxx'
+3874,374,0,2,4,14,74,874,1874,3874,3874,148,149,'ATAAAA','KOAAAA','OOOOxx'
+6831,375,1,3,1,11,31,831,831,1831,6831,62,63,'TCAAAA','LOAAAA','VVVVxx'
+18,376,0,2,8,18,18,18,18,18,18,36,37,'SAAAAA','MOAAAA','AAAAxx'
+6375,377,1,3,5,15,75,375,375,1375,6375,150,151,'FLAAAA','NOAAAA','HHHHxx'
+7106,378,0,2,6,6,6,106,1106,2106,7106,12,13,'INAAAA','OOAAAA','OOOOxx'
+5926,379,0,2,6,6,26,926,1926,926,5926,52,53,'YTAAAA','POAAAA','VVVVxx'
+4956,380,0,0,6,16,56,956,956,4956,4956,112,113,'QIAAAA','QOAAAA','AAAAxx'
+7042,381,0,2,2,2,42,42,1042,2042,7042,84,85,'WKAAAA','ROAAAA','HHHHxx'
+6043,382,1,3,3,3,43,43,43,1043,6043,86,87,'LYAAAA','SOAAAA','OOOOxx'
+2084,383,0,0,4,4,84,84,84,2084,2084,168,169,'ECAAAA','TOAAAA','VVVVxx'
+6038,384,0,2,8,18,38,38,38,1038,6038,76,77,'GYAAAA','UOAAAA','AAAAxx'
+7253,385,1,1,3,13,53,253,1253,2253,7253,106,107,'ZSAAAA','VOAAAA','HHHHxx'
+2061,386,1,1,1,1,61,61,61,2061,2061,122,123,'HBAAAA','WOAAAA','OOOOxx'
+7800,387,0,0,0,0,0,800,1800,2800,7800,0,1,'AOAAAA','XOAAAA','VVVVxx'
+4970,388,0,2,0,10,70,970,970,4970,4970,140,141,'EJAAAA','YOAAAA','AAAAxx'
+8580,389,0,0,0,0,80,580,580,3580,8580,160,161,'ASAAAA','ZOAAAA','HHHHxx'
+9173,390,1,1,3,13,73,173,1173,4173,9173,146,147,'VOAAAA','APAAAA','OOOOxx'
+8558,391,0,2,8,18,58,558,558,3558,8558,116,117,'ERAAAA','BPAAAA','VVVVxx'
+3897,392,1,1,7,17,97,897,1897,3897,3897,194,195,'XTAAAA','CPAAAA','AAAAxx'
+5069,393,1,1,9,9,69,69,1069,69,5069,138,139,'ZMAAAA','DPAAAA','HHHHxx'
+2301,394,1,1,1,1,1,301,301,2301,2301,2,3,'NKAAAA','EPAAAA','OOOOxx'
+9863,395,1,3,3,3,63,863,1863,4863,9863,126,127,'JPAAAA','FPAAAA','VVVVxx'
+5733,396,1,1,3,13,33,733,1733,733,5733,66,67,'NMAAAA','GPAAAA','AAAAxx'
+2338,397,0,2,8,18,38,338,338,2338,2338,76,77,'YLAAAA','HPAAAA','HHHHxx'
+9639,398,1,3,9,19,39,639,1639,4639,9639,78,79,'TGAAAA','IPAAAA','OOOOxx'
+1139,399,1,3,9,19,39,139,1139,1139,1139,78,79,'VRAAAA','JPAAAA','VVVVxx'
+2293,400,1,1,3,13,93,293,293,2293,2293,186,187,'FKAAAA','KPAAAA','AAAAxx'
+6125,401,1,1,5,5,25,125,125,1125,6125,50,51,'PBAAAA','LPAAAA','HHHHxx'
+5374,402,0,2,4,14,74,374,1374,374,5374,148,149,'SYAAAA','MPAAAA','OOOOxx'
+7216,403,0,0,6,16,16,216,1216,2216,7216,32,33,'ORAAAA','NPAAAA','VVVVxx'
+2285,404,1,1,5,5,85,285,285,2285,2285,170,171,'XJAAAA','OPAAAA','AAAAxx'
+2387,405,1,3,7,7,87,387,387,2387,2387,174,175,'VNAAAA','PPAAAA','HHHHxx'
+5015,406,1,3,5,15,15,15,1015,15,5015,30,31,'XKAAAA','QPAAAA','OOOOxx'
+2087,407,1,3,7,7,87,87,87,2087,2087,174,175,'HCAAAA','RPAAAA','VVVVxx'
+4938,408,0,2,8,18,38,938,938,4938,4938,76,77,'YHAAAA','SPAAAA','AAAAxx'
+3635,409,1,3,5,15,35,635,1635,3635,3635,70,71,'VJAAAA','TPAAAA','HHHHxx'
+7737,410,1,1,7,17,37,737,1737,2737,7737,74,75,'PLAAAA','UPAAAA','OOOOxx'
+8056,411,0,0,6,16,56,56,56,3056,8056,112,113,'WXAAAA','VPAAAA','VVVVxx'
+4502,412,0,2,2,2,2,502,502,4502,4502,4,5,'ERAAAA','WPAAAA','AAAAxx'
+54,413,0,2,4,14,54,54,54,54,54,108,109,'CCAAAA','XPAAAA','HHHHxx'
+3182,414,0,2,2,2,82,182,1182,3182,3182,164,165,'KSAAAA','YPAAAA','OOOOxx'
+3718,415,0,2,8,18,18,718,1718,3718,3718,36,37,'ANAAAA','ZPAAAA','VVVVxx'
+3989,416,1,1,9,9,89,989,1989,3989,3989,178,179,'LXAAAA','AQAAAA','AAAAxx'
+8028,417,0,0,8,8,28,28,28,3028,8028,56,57,'UWAAAA','BQAAAA','HHHHxx'
+1426,418,0,2,6,6,26,426,1426,1426,1426,52,53,'WCAAAA','CQAAAA','OOOOxx'
+3801,419,1,1,1,1,1,801,1801,3801,3801,2,3,'FQAAAA','DQAAAA','VVVVxx'
+241,420,1,1,1,1,41,241,241,241,241,82,83,'HJAAAA','EQAAAA','AAAAxx'
+8000,421,0,0,0,0,0,0,0,3000,8000,0,1,'SVAAAA','FQAAAA','HHHHxx'
+8357,422,1,1,7,17,57,357,357,3357,8357,114,115,'LJAAAA','GQAAAA','OOOOxx'
+7548,423,0,0,8,8,48,548,1548,2548,7548,96,97,'IEAAAA','HQAAAA','VVVVxx'
+7307,424,1,3,7,7,7,307,1307,2307,7307,14,15,'BVAAAA','IQAAAA','AAAAxx'
+2275,425,1,3,5,15,75,275,275,2275,2275,150,151,'NJAAAA','JQAAAA','HHHHxx'
+2718,426,0,2,8,18,18,718,718,2718,2718,36,37,'OAAAAA','KQAAAA','OOOOxx'
+7068,427,0,0,8,8,68,68,1068,2068,7068,136,137,'WLAAAA','LQAAAA','VVVVxx'
+3181,428,1,1,1,1,81,181,1181,3181,3181,162,163,'JSAAAA','MQAAAA','AAAAxx'
+749,429,1,1,9,9,49,749,749,749,749,98,99,'VCAAAA','NQAAAA','HHHHxx'
+5195,430,1,3,5,15,95,195,1195,195,5195,190,191,'VRAAAA','OQAAAA','OOOOxx'
+6136,431,0,0,6,16,36,136,136,1136,6136,72,73,'ACAAAA','PQAAAA','VVVVxx'
+8012,432,0,0,2,12,12,12,12,3012,8012,24,25,'EWAAAA','QQAAAA','AAAAxx'
+3957,433,1,1,7,17,57,957,1957,3957,3957,114,115,'FWAAAA','RQAAAA','HHHHxx'
+3083,434,1,3,3,3,83,83,1083,3083,3083,166,167,'POAAAA','SQAAAA','OOOOxx'
+9997,435,1,1,7,17,97,997,1997,4997,9997,194,195,'NUAAAA','TQAAAA','VVVVxx'
+3299,436,1,3,9,19,99,299,1299,3299,3299,198,199,'XWAAAA','UQAAAA','AAAAxx'
+846,437,0,2,6,6,46,846,846,846,846,92,93,'OGAAAA','VQAAAA','HHHHxx'
+2985,438,1,1,5,5,85,985,985,2985,2985,170,171,'VKAAAA','WQAAAA','OOOOxx'
+9238,439,0,2,8,18,38,238,1238,4238,9238,76,77,'IRAAAA','XQAAAA','VVVVxx'
+1403,440,1,3,3,3,3,403,1403,1403,1403,6,7,'ZBAAAA','YQAAAA','AAAAxx'
+5563,441,1,3,3,3,63,563,1563,563,5563,126,127,'ZFAAAA','ZQAAAA','HHHHxx'
+7965,442,1,1,5,5,65,965,1965,2965,7965,130,131,'JUAAAA','ARAAAA','OOOOxx'
+4512,443,0,0,2,12,12,512,512,4512,4512,24,25,'ORAAAA','BRAAAA','VVVVxx'
+9730,444,0,2,0,10,30,730,1730,4730,9730,60,61,'GKAAAA','CRAAAA','AAAAxx'
+1129,445,1,1,9,9,29,129,1129,1129,1129,58,59,'LRAAAA','DRAAAA','HHHHxx'
+2624,446,0,0,4,4,24,624,624,2624,2624,48,49,'YWAAAA','ERAAAA','OOOOxx'
+8178,447,0,2,8,18,78,178,178,3178,8178,156,157,'OCAAAA','FRAAAA','VVVVxx'
+6468,448,0,0,8,8,68,468,468,1468,6468,136,137,'UOAAAA','GRAAAA','AAAAxx'
+3027,449,1,3,7,7,27,27,1027,3027,3027,54,55,'LMAAAA','HRAAAA','HHHHxx'
+3845,450,1,1,5,5,45,845,1845,3845,3845,90,91,'XRAAAA','IRAAAA','OOOOxx'
+786,451,0,2,6,6,86,786,786,786,786,172,173,'GEAAAA','JRAAAA','VVVVxx'
+4971,452,1,3,1,11,71,971,971,4971,4971,142,143,'FJAAAA','KRAAAA','AAAAxx'
+1542,453,0,2,2,2,42,542,1542,1542,1542,84,85,'IHAAAA','LRAAAA','HHHHxx'
+7967,454,1,3,7,7,67,967,1967,2967,7967,134,135,'LUAAAA','MRAAAA','OOOOxx'
+443,455,1,3,3,3,43,443,443,443,443,86,87,'BRAAAA','NRAAAA','VVVVxx'
+7318,456,0,2,8,18,18,318,1318,2318,7318,36,37,'MVAAAA','ORAAAA','AAAAxx'
+4913,457,1,1,3,13,13,913,913,4913,4913,26,27,'ZGAAAA','PRAAAA','HHHHxx'
+9466,458,0,2,6,6,66,466,1466,4466,9466,132,133,'CAAAAA','QRAAAA','OOOOxx'
+7866,459,0,2,6,6,66,866,1866,2866,7866,132,133,'OQAAAA','RRAAAA','VVVVxx'
+784,460,0,0,4,4,84,784,784,784,784,168,169,'EEAAAA','SRAAAA','AAAAxx'
+9040,461,0,0,0,0,40,40,1040,4040,9040,80,81,'SJAAAA','TRAAAA','HHHHxx'
+3954,462,0,2,4,14,54,954,1954,3954,3954,108,109,'CWAAAA','URAAAA','OOOOxx'
+4183,463,1,3,3,3,83,183,183,4183,4183,166,167,'XEAAAA','VRAAAA','VVVVxx'
+3608,464,0,0,8,8,8,608,1608,3608,3608,16,17,'UIAAAA','WRAAAA','AAAAxx'
+7630,465,0,2,0,10,30,630,1630,2630,7630,60,61,'MHAAAA','XRAAAA','HHHHxx'
+590,466,0,2,0,10,90,590,590,590,590,180,181,'SWAAAA','YRAAAA','OOOOxx'
+3453,467,1,1,3,13,53,453,1453,3453,3453,106,107,'VCAAAA','ZRAAAA','VVVVxx'
+7757,468,1,1,7,17,57,757,1757,2757,7757,114,115,'JMAAAA','ASAAAA','AAAAxx'
+7394,469,0,2,4,14,94,394,1394,2394,7394,188,189,'KYAAAA','BSAAAA','HHHHxx'
+396,470,0,0,6,16,96,396,396,396,396,192,193,'GPAAAA','CSAAAA','OOOOxx'
+7873,471,1,1,3,13,73,873,1873,2873,7873,146,147,'VQAAAA','DSAAAA','VVVVxx'
+1553,472,1,1,3,13,53,553,1553,1553,1553,106,107,'THAAAA','ESAAAA','AAAAxx'
+598,473,0,2,8,18,98,598,598,598,598,196,197,'AXAAAA','FSAAAA','HHHHxx'
+7191,474,1,3,1,11,91,191,1191,2191,7191,182,183,'PQAAAA','GSAAAA','OOOOxx'
+8116,475,0,0,6,16,16,116,116,3116,8116,32,33,'EAAAAA','HSAAAA','VVVVxx'
+2516,476,0,0,6,16,16,516,516,2516,2516,32,33,'USAAAA','ISAAAA','AAAAxx'
+7750,477,0,2,0,10,50,750,1750,2750,7750,100,101,'CMAAAA','JSAAAA','HHHHxx'
+6625,478,1,1,5,5,25,625,625,1625,6625,50,51,'VUAAAA','KSAAAA','OOOOxx'
+8838,479,0,2,8,18,38,838,838,3838,8838,76,77,'YBAAAA','LSAAAA','VVVVxx'
+4636,480,0,0,6,16,36,636,636,4636,4636,72,73,'IWAAAA','MSAAAA','AAAAxx'
+7627,481,1,3,7,7,27,627,1627,2627,7627,54,55,'JHAAAA','NSAAAA','HHHHxx'
+1690,482,0,2,0,10,90,690,1690,1690,1690,180,181,'ANAAAA','OSAAAA','OOOOxx'
+7071,483,1,3,1,11,71,71,1071,2071,7071,142,143,'ZLAAAA','PSAAAA','VVVVxx'
+2081,484,1,1,1,1,81,81,81,2081,2081,162,163,'BCAAAA','QSAAAA','AAAAxx'
+7138,485,0,2,8,18,38,138,1138,2138,7138,76,77,'OOAAAA','RSAAAA','HHHHxx'
+864,486,0,0,4,4,64,864,864,864,864,128,129,'GHAAAA','SSAAAA','OOOOxx'
+6392,487,0,0,2,12,92,392,392,1392,6392,184,185,'WLAAAA','TSAAAA','VVVVxx'
+7544,488,0,0,4,4,44,544,1544,2544,7544,88,89,'EEAAAA','USAAAA','AAAAxx'
+5438,489,0,2,8,18,38,438,1438,438,5438,76,77,'EBAAAA','VSAAAA','HHHHxx'
+7099,490,1,3,9,19,99,99,1099,2099,7099,198,199,'BNAAAA','WSAAAA','OOOOxx'
+5157,491,1,1,7,17,57,157,1157,157,5157,114,115,'JQAAAA','XSAAAA','VVVVxx'
+3391,492,1,3,1,11,91,391,1391,3391,3391,182,183,'LAAAAA','YSAAAA','AAAAxx'
+3805,493,1,1,5,5,5,805,1805,3805,3805,10,11,'JQAAAA','ZSAAAA','HHHHxx'
+2110,494,0,2,0,10,10,110,110,2110,2110,20,21,'EDAAAA','ATAAAA','OOOOxx'
+3176,495,0,0,6,16,76,176,1176,3176,3176,152,153,'ESAAAA','BTAAAA','VVVVxx'
+5918,496,0,2,8,18,18,918,1918,918,5918,36,37,'QTAAAA','CTAAAA','AAAAxx'
+1218,497,0,2,8,18,18,218,1218,1218,1218,36,37,'WUAAAA','DTAAAA','HHHHxx'
+6683,498,1,3,3,3,83,683,683,1683,6683,166,167,'BXAAAA','ETAAAA','OOOOxx'
+914,499,0,2,4,14,14,914,914,914,914,28,29,'EJAAAA','FTAAAA','VVVVxx'
+4737,500,1,1,7,17,37,737,737,4737,4737,74,75,'FAAAAA','GTAAAA','AAAAxx'
+7286,501,0,2,6,6,86,286,1286,2286,7286,172,173,'GUAAAA','HTAAAA','HHHHxx'
+9975,502,1,3,5,15,75,975,1975,4975,9975,150,151,'RTAAAA','ITAAAA','OOOOxx'
+8030,503,0,2,0,10,30,30,30,3030,8030,60,61,'WWAAAA','JTAAAA','VVVVxx'
+7364,504,0,0,4,4,64,364,1364,2364,7364,128,129,'GXAAAA','KTAAAA','AAAAxx'
+1389,505,1,1,9,9,89,389,1389,1389,1389,178,179,'LBAAAA','LTAAAA','HHHHxx'
+4025,506,1,1,5,5,25,25,25,4025,4025,50,51,'VYAAAA','MTAAAA','OOOOxx'
+4835,507,1,3,5,15,35,835,835,4835,4835,70,71,'ZDAAAA','NTAAAA','VVVVxx'
+8045,508,1,1,5,5,45,45,45,3045,8045,90,91,'LXAAAA','OTAAAA','AAAAxx'
+1864,509,0,0,4,4,64,864,1864,1864,1864,128,129,'STAAAA','PTAAAA','HHHHxx'
+3313,510,1,1,3,13,13,313,1313,3313,3313,26,27,'LXAAAA','QTAAAA','OOOOxx'
+2384,511,0,0,4,4,84,384,384,2384,2384,168,169,'SNAAAA','RTAAAA','VVVVxx'
+6115,512,1,3,5,15,15,115,115,1115,6115,30,31,'FBAAAA','STAAAA','AAAAxx'
+5705,513,1,1,5,5,5,705,1705,705,5705,10,11,'LLAAAA','TTAAAA','HHHHxx'
+9269,514,1,1,9,9,69,269,1269,4269,9269,138,139,'NSAAAA','UTAAAA','OOOOxx'
+3379,515,1,3,9,19,79,379,1379,3379,3379,158,159,'ZZAAAA','VTAAAA','VVVVxx'
+8205,516,1,1,5,5,5,205,205,3205,8205,10,11,'PDAAAA','WTAAAA','AAAAxx'
+6575,517,1,3,5,15,75,575,575,1575,6575,150,151,'XSAAAA','XTAAAA','HHHHxx'
+486,518,0,2,6,6,86,486,486,486,486,172,173,'SSAAAA','YTAAAA','OOOOxx'
+4894,519,0,2,4,14,94,894,894,4894,4894,188,189,'GGAAAA','ZTAAAA','VVVVxx'
+3090,520,0,2,0,10,90,90,1090,3090,3090,180,181,'WOAAAA','AUAAAA','AAAAxx'
+759,521,1,3,9,19,59,759,759,759,759,118,119,'FDAAAA','BUAAAA','HHHHxx'
+4864,522,0,0,4,4,64,864,864,4864,4864,128,129,'CFAAAA','CUAAAA','OOOOxx'
+4083,523,1,3,3,3,83,83,83,4083,4083,166,167,'BBAAAA','DUAAAA','VVVVxx'
+6918,524,0,2,8,18,18,918,918,1918,6918,36,37,'CGAAAA','EUAAAA','AAAAxx'
+8146,525,0,2,6,6,46,146,146,3146,8146,92,93,'IBAAAA','FUAAAA','HHHHxx'
+1523,526,1,3,3,3,23,523,1523,1523,1523,46,47,'PGAAAA','GUAAAA','OOOOxx'
+1591,527,1,3,1,11,91,591,1591,1591,1591,182,183,'FJAAAA','HUAAAA','VVVVxx'
+3343,528,1,3,3,3,43,343,1343,3343,3343,86,87,'PYAAAA','IUAAAA','AAAAxx'
+1391,529,1,3,1,11,91,391,1391,1391,1391,182,183,'NBAAAA','JUAAAA','HHHHxx'
+9963,530,1,3,3,3,63,963,1963,4963,9963,126,127,'FTAAAA','KUAAAA','OOOOxx'
+2423,531,1,3,3,3,23,423,423,2423,2423,46,47,'FPAAAA','LUAAAA','VVVVxx'
+1822,532,0,2,2,2,22,822,1822,1822,1822,44,45,'CSAAAA','MUAAAA','AAAAxx'
+8706,533,0,2,6,6,6,706,706,3706,8706,12,13,'WWAAAA','NUAAAA','HHHHxx'
+3001,534,1,1,1,1,1,1,1001,3001,3001,2,3,'LLAAAA','OUAAAA','OOOOxx'
+6707,535,1,3,7,7,7,707,707,1707,6707,14,15,'ZXAAAA','PUAAAA','VVVVxx'
+2121,536,1,1,1,1,21,121,121,2121,2121,42,43,'PDAAAA','QUAAAA','AAAAxx'
+5814,537,0,2,4,14,14,814,1814,814,5814,28,29,'QPAAAA','RUAAAA','HHHHxx'
+2659,538,1,3,9,19,59,659,659,2659,2659,118,119,'HYAAAA','SUAAAA','OOOOxx'
+2016,539,0,0,6,16,16,16,16,2016,2016,32,33,'OZAAAA','TUAAAA','VVVVxx'
+4286,540,0,2,6,6,86,286,286,4286,4286,172,173,'WIAAAA','UUAAAA','AAAAxx'
+9205,541,1,1,5,5,5,205,1205,4205,9205,10,11,'BQAAAA','VUAAAA','HHHHxx'
+3496,542,0,0,6,16,96,496,1496,3496,3496,192,193,'MEAAAA','WUAAAA','OOOOxx'
+5333,543,1,1,3,13,33,333,1333,333,5333,66,67,'DXAAAA','XUAAAA','VVVVxx'
+5571,544,1,3,1,11,71,571,1571,571,5571,142,143,'HGAAAA','YUAAAA','AAAAxx'
+1696,545,0,0,6,16,96,696,1696,1696,1696,192,193,'GNAAAA','ZUAAAA','HHHHxx'
+4871,546,1,3,1,11,71,871,871,4871,4871,142,143,'JFAAAA','AVAAAA','OOOOxx'
+4852,547,0,0,2,12,52,852,852,4852,4852,104,105,'QEAAAA','BVAAAA','VVVVxx'
+8483,548,1,3,3,3,83,483,483,3483,8483,166,167,'HOAAAA','CVAAAA','AAAAxx'
+1376,549,0,0,6,16,76,376,1376,1376,1376,152,153,'YAAAAA','DVAAAA','HHHHxx'
+5456,550,0,0,6,16,56,456,1456,456,5456,112,113,'WBAAAA','EVAAAA','OOOOxx'
+499,551,1,3,9,19,99,499,499,499,499,198,199,'FTAAAA','FVAAAA','VVVVxx'
+3463,552,1,3,3,3,63,463,1463,3463,3463,126,127,'FDAAAA','GVAAAA','AAAAxx'
+7426,553,0,2,6,6,26,426,1426,2426,7426,52,53,'QZAAAA','HVAAAA','HHHHxx'
+5341,554,1,1,1,1,41,341,1341,341,5341,82,83,'LXAAAA','IVAAAA','OOOOxx'
+9309,555,1,1,9,9,9,309,1309,4309,9309,18,19,'BUAAAA','JVAAAA','VVVVxx'
+2055,556,1,3,5,15,55,55,55,2055,2055,110,111,'BBAAAA','KVAAAA','AAAAxx'
+2199,557,1,3,9,19,99,199,199,2199,2199,198,199,'PGAAAA','LVAAAA','HHHHxx'
+7235,558,1,3,5,15,35,235,1235,2235,7235,70,71,'HSAAAA','MVAAAA','OOOOxx'
+8661,559,1,1,1,1,61,661,661,3661,8661,122,123,'DVAAAA','NVAAAA','VVVVxx'
+9494,560,0,2,4,14,94,494,1494,4494,9494,188,189,'EBAAAA','OVAAAA','AAAAxx'
+935,561,1,3,5,15,35,935,935,935,935,70,71,'ZJAAAA','PVAAAA','HHHHxx'
+7044,562,0,0,4,4,44,44,1044,2044,7044,88,89,'YKAAAA','QVAAAA','OOOOxx'
+1974,563,0,2,4,14,74,974,1974,1974,1974,148,149,'YXAAAA','RVAAAA','VVVVxx'
+9679,564,1,3,9,19,79,679,1679,4679,9679,158,159,'HIAAAA','SVAAAA','AAAAxx'
+9822,565,0,2,2,2,22,822,1822,4822,9822,44,45,'UNAAAA','TVAAAA','HHHHxx'
+4088,566,0,0,8,8,88,88,88,4088,4088,176,177,'GBAAAA','UVAAAA','OOOOxx'
+1749,567,1,1,9,9,49,749,1749,1749,1749,98,99,'HPAAAA','VVAAAA','VVVVxx'
+2116,568,0,0,6,16,16,116,116,2116,2116,32,33,'KDAAAA','WVAAAA','AAAAxx'
+976,569,0,0,6,16,76,976,976,976,976,152,153,'OLAAAA','XVAAAA','HHHHxx'
+8689,570,1,1,9,9,89,689,689,3689,8689,178,179,'FWAAAA','YVAAAA','OOOOxx'
+2563,571,1,3,3,3,63,563,563,2563,2563,126,127,'PUAAAA','ZVAAAA','VVVVxx'
+7195,572,1,3,5,15,95,195,1195,2195,7195,190,191,'TQAAAA','AWAAAA','AAAAxx'
+9985,573,1,1,5,5,85,985,1985,4985,9985,170,171,'BUAAAA','BWAAAA','HHHHxx'
+7699,574,1,3,9,19,99,699,1699,2699,7699,198,199,'DKAAAA','CWAAAA','OOOOxx'
+5311,575,1,3,1,11,11,311,1311,311,5311,22,23,'HWAAAA','DWAAAA','VVVVxx'
+295,576,1,3,5,15,95,295,295,295,295,190,191,'JLAAAA','EWAAAA','AAAAxx'
+8214,577,0,2,4,14,14,214,214,3214,8214,28,29,'YDAAAA','FWAAAA','HHHHxx'
+3275,578,1,3,5,15,75,275,1275,3275,3275,150,151,'ZVAAAA','GWAAAA','OOOOxx'
+9646,579,0,2,6,6,46,646,1646,4646,9646,92,93,'AHAAAA','HWAAAA','VVVVxx'
+1908,580,0,0,8,8,8,908,1908,1908,1908,16,17,'KVAAAA','IWAAAA','AAAAxx'
+3858,581,0,2,8,18,58,858,1858,3858,3858,116,117,'KSAAAA','JWAAAA','HHHHxx'
+9362,582,0,2,2,2,62,362,1362,4362,9362,124,125,'CWAAAA','KWAAAA','OOOOxx'
+9307,583,1,3,7,7,7,307,1307,4307,9307,14,15,'ZTAAAA','LWAAAA','VVVVxx'
+6124,584,0,0,4,4,24,124,124,1124,6124,48,49,'OBAAAA','MWAAAA','AAAAxx'
+2405,585,1,1,5,5,5,405,405,2405,2405,10,11,'NOAAAA','NWAAAA','HHHHxx'
+8422,586,0,2,2,2,22,422,422,3422,8422,44,45,'YLAAAA','OWAAAA','OOOOxx'
+393,587,1,1,3,13,93,393,393,393,393,186,187,'DPAAAA','PWAAAA','VVVVxx'
+8973,588,1,1,3,13,73,973,973,3973,8973,146,147,'DHAAAA','QWAAAA','AAAAxx'
+5171,589,1,3,1,11,71,171,1171,171,5171,142,143,'XQAAAA','RWAAAA','HHHHxx'
+4929,590,1,1,9,9,29,929,929,4929,4929,58,59,'PHAAAA','SWAAAA','OOOOxx'
+6935,591,1,3,5,15,35,935,935,1935,6935,70,71,'TGAAAA','TWAAAA','VVVVxx'
+8584,592,0,0,4,4,84,584,584,3584,8584,168,169,'ESAAAA','UWAAAA','AAAAxx'
+1035,593,1,3,5,15,35,35,1035,1035,1035,70,71,'VNAAAA','VWAAAA','HHHHxx'
+3734,594,0,2,4,14,34,734,1734,3734,3734,68,69,'QNAAAA','WWAAAA','OOOOxx'
+1458,595,0,2,8,18,58,458,1458,1458,1458,116,117,'CEAAAA','XWAAAA','VVVVxx'
+8746,596,0,2,6,6,46,746,746,3746,8746,92,93,'KYAAAA','YWAAAA','AAAAxx'
+1677,597,1,1,7,17,77,677,1677,1677,1677,154,155,'NMAAAA','ZWAAAA','HHHHxx'
+8502,598,0,2,2,2,2,502,502,3502,8502,4,5,'APAAAA','AXAAAA','OOOOxx'
+7752,599,0,0,2,12,52,752,1752,2752,7752,104,105,'EMAAAA','BXAAAA','VVVVxx'
+2556,600,0,0,6,16,56,556,556,2556,2556,112,113,'IUAAAA','CXAAAA','AAAAxx'
+6426,601,0,2,6,6,26,426,426,1426,6426,52,53,'ENAAAA','DXAAAA','HHHHxx'
+8420,602,0,0,0,0,20,420,420,3420,8420,40,41,'WLAAAA','EXAAAA','OOOOxx'
+4462,603,0,2,2,2,62,462,462,4462,4462,124,125,'QPAAAA','FXAAAA','VVVVxx'
+1378,604,0,2,8,18,78,378,1378,1378,1378,156,157,'ABAAAA','GXAAAA','AAAAxx'
+1387,605,1,3,7,7,87,387,1387,1387,1387,174,175,'JBAAAA','HXAAAA','HHHHxx'
+8094,606,0,2,4,14,94,94,94,3094,8094,188,189,'IZAAAA','IXAAAA','OOOOxx'
+7247,607,1,3,7,7,47,247,1247,2247,7247,94,95,'TSAAAA','JXAAAA','VVVVxx'
+4261,608,1,1,1,1,61,261,261,4261,4261,122,123,'XHAAAA','KXAAAA','AAAAxx'
+5029,609,1,1,9,9,29,29,1029,29,5029,58,59,'LLAAAA','LXAAAA','HHHHxx'
+3625,610,1,1,5,5,25,625,1625,3625,3625,50,51,'LJAAAA','MXAAAA','OOOOxx'
+8068,611,0,0,8,8,68,68,68,3068,8068,136,137,'IYAAAA','NXAAAA','VVVVxx'
+102,612,0,2,2,2,2,102,102,102,102,4,5,'YDAAAA','OXAAAA','AAAAxx'
+5596,613,0,0,6,16,96,596,1596,596,5596,192,193,'GHAAAA','PXAAAA','HHHHxx'
+5872,614,0,0,2,12,72,872,1872,872,5872,144,145,'WRAAAA','QXAAAA','OOOOxx'
+4742,615,0,2,2,2,42,742,742,4742,4742,84,85,'KAAAAA','RXAAAA','VVVVxx'
+2117,616,1,1,7,17,17,117,117,2117,2117,34,35,'LDAAAA','SXAAAA','AAAAxx'
+3945,617,1,1,5,5,45,945,1945,3945,3945,90,91,'TVAAAA','TXAAAA','HHHHxx'
+7483,618,1,3,3,3,83,483,1483,2483,7483,166,167,'VBAAAA','UXAAAA','OOOOxx'
+4455,619,1,3,5,15,55,455,455,4455,4455,110,111,'JPAAAA','VXAAAA','VVVVxx'
+609,620,1,1,9,9,9,609,609,609,609,18,19,'LXAAAA','WXAAAA','AAAAxx'
+9829,621,1,1,9,9,29,829,1829,4829,9829,58,59,'BOAAAA','XXAAAA','HHHHxx'
+4857,622,1,1,7,17,57,857,857,4857,4857,114,115,'VEAAAA','YXAAAA','OOOOxx'
+3314,623,0,2,4,14,14,314,1314,3314,3314,28,29,'MXAAAA','ZXAAAA','VVVVxx'
+5353,624,1,1,3,13,53,353,1353,353,5353,106,107,'XXAAAA','AYAAAA','AAAAxx'
+4909,625,1,1,9,9,9,909,909,4909,4909,18,19,'VGAAAA','BYAAAA','HHHHxx'
+7597,626,1,1,7,17,97,597,1597,2597,7597,194,195,'FGAAAA','CYAAAA','OOOOxx'
+2683,627,1,3,3,3,83,683,683,2683,2683,166,167,'FZAAAA','DYAAAA','VVVVxx'
+3223,628,1,3,3,3,23,223,1223,3223,3223,46,47,'ZTAAAA','EYAAAA','AAAAxx'
+5363,629,1,3,3,3,63,363,1363,363,5363,126,127,'HYAAAA','FYAAAA','HHHHxx'
+4578,630,0,2,8,18,78,578,578,4578,4578,156,157,'CUAAAA','GYAAAA','OOOOxx'
+5544,631,0,0,4,4,44,544,1544,544,5544,88,89,'GFAAAA','HYAAAA','VVVVxx'
+1589,632,1,1,9,9,89,589,1589,1589,1589,178,179,'DJAAAA','IYAAAA','AAAAxx'
+7412,633,0,0,2,12,12,412,1412,2412,7412,24,25,'CZAAAA','JYAAAA','HHHHxx'
+3803,634,1,3,3,3,3,803,1803,3803,3803,6,7,'HQAAAA','KYAAAA','OOOOxx'
+6179,635,1,3,9,19,79,179,179,1179,6179,158,159,'RDAAAA','LYAAAA','VVVVxx'
+5588,636,0,0,8,8,88,588,1588,588,5588,176,177,'YGAAAA','MYAAAA','AAAAxx'
+2134,637,0,2,4,14,34,134,134,2134,2134,68,69,'CEAAAA','NYAAAA','HHHHxx'
+4383,638,1,3,3,3,83,383,383,4383,4383,166,167,'PMAAAA','OYAAAA','OOOOxx'
+6995,639,1,3,5,15,95,995,995,1995,6995,190,191,'BJAAAA','PYAAAA','VVVVxx'
+6598,640,0,2,8,18,98,598,598,1598,6598,196,197,'UTAAAA','QYAAAA','AAAAxx'
+8731,641,1,3,1,11,31,731,731,3731,8731,62,63,'VXAAAA','RYAAAA','HHHHxx'
+7177,642,1,1,7,17,77,177,1177,2177,7177,154,155,'BQAAAA','SYAAAA','OOOOxx'
+6578,643,0,2,8,18,78,578,578,1578,6578,156,157,'ATAAAA','TYAAAA','VVVVxx'
+9393,644,1,1,3,13,93,393,1393,4393,9393,186,187,'HXAAAA','UYAAAA','AAAAxx'
+1276,645,0,0,6,16,76,276,1276,1276,1276,152,153,'CXAAAA','VYAAAA','HHHHxx'
+8766,646,0,2,6,6,66,766,766,3766,8766,132,133,'EZAAAA','WYAAAA','OOOOxx'
+1015,647,1,3,5,15,15,15,1015,1015,1015,30,31,'BNAAAA','XYAAAA','VVVVxx'
+4396,648,0,0,6,16,96,396,396,4396,4396,192,193,'CNAAAA','YYAAAA','AAAAxx'
+5564,649,0,0,4,4,64,564,1564,564,5564,128,129,'AGAAAA','ZYAAAA','HHHHxx'
+927,650,1,3,7,7,27,927,927,927,927,54,55,'RJAAAA','AZAAAA','OOOOxx'
+3306,651,0,2,6,6,6,306,1306,3306,3306,12,13,'EXAAAA','BZAAAA','VVVVxx'
+1615,652,1,3,5,15,15,615,1615,1615,1615,30,31,'DKAAAA','CZAAAA','AAAAxx'
+4550,653,0,2,0,10,50,550,550,4550,4550,100,101,'ATAAAA','DZAAAA','HHHHxx'
+2468,654,0,0,8,8,68,468,468,2468,2468,136,137,'YQAAAA','EZAAAA','OOOOxx'
+5336,655,0,0,6,16,36,336,1336,336,5336,72,73,'GXAAAA','FZAAAA','VVVVxx'
+4471,656,1,3,1,11,71,471,471,4471,4471,142,143,'ZPAAAA','GZAAAA','AAAAxx'
+8085,657,1,1,5,5,85,85,85,3085,8085,170,171,'ZYAAAA','HZAAAA','HHHHxx'
+540,658,0,0,0,0,40,540,540,540,540,80,81,'UUAAAA','IZAAAA','OOOOxx'
+5108,659,0,0,8,8,8,108,1108,108,5108,16,17,'MOAAAA','JZAAAA','VVVVxx'
+8015,660,1,3,5,15,15,15,15,3015,8015,30,31,'HWAAAA','KZAAAA','AAAAxx'
+2857,661,1,1,7,17,57,857,857,2857,2857,114,115,'XFAAAA','LZAAAA','HHHHxx'
+9472,662,0,0,2,12,72,472,1472,4472,9472,144,145,'IAAAAA','MZAAAA','OOOOxx'
+5666,663,0,2,6,6,66,666,1666,666,5666,132,133,'YJAAAA','NZAAAA','VVVVxx'
+3555,664,1,3,5,15,55,555,1555,3555,3555,110,111,'TGAAAA','OZAAAA','AAAAxx'
+378,665,0,2,8,18,78,378,378,378,378,156,157,'OOAAAA','PZAAAA','HHHHxx'
+4466,666,0,2,6,6,66,466,466,4466,4466,132,133,'UPAAAA','QZAAAA','OOOOxx'
+3247,667,1,3,7,7,47,247,1247,3247,3247,94,95,'XUAAAA','RZAAAA','VVVVxx'
+6570,668,0,2,0,10,70,570,570,1570,6570,140,141,'SSAAAA','SZAAAA','AAAAxx'
+5655,669,1,3,5,15,55,655,1655,655,5655,110,111,'NJAAAA','TZAAAA','HHHHxx'
+917,670,1,1,7,17,17,917,917,917,917,34,35,'HJAAAA','UZAAAA','OOOOxx'
+3637,671,1,1,7,17,37,637,1637,3637,3637,74,75,'XJAAAA','VZAAAA','VVVVxx'
+3668,672,0,0,8,8,68,668,1668,3668,3668,136,137,'CLAAAA','WZAAAA','AAAAxx'
+5644,673,0,0,4,4,44,644,1644,644,5644,88,89,'CJAAAA','XZAAAA','HHHHxx'
+8286,674,0,2,6,6,86,286,286,3286,8286,172,173,'SGAAAA','YZAAAA','OOOOxx'
+6896,675,0,0,6,16,96,896,896,1896,6896,192,193,'GFAAAA','ZZAAAA','VVVVxx'
+2870,676,0,2,0,10,70,870,870,2870,2870,140,141,'KGAAAA','AABAAA','AAAAxx'
+8041,677,1,1,1,1,41,41,41,3041,8041,82,83,'HXAAAA','BABAAA','HHHHxx'
+8137,678,1,1,7,17,37,137,137,3137,8137,74,75,'ZAAAAA','CABAAA','OOOOxx'
+4823,679,1,3,3,3,23,823,823,4823,4823,46,47,'NDAAAA','DABAAA','VVVVxx'
+2438,680,0,2,8,18,38,438,438,2438,2438,76,77,'UPAAAA','EABAAA','AAAAxx'
+6329,681,1,1,9,9,29,329,329,1329,6329,58,59,'LJAAAA','FABAAA','HHHHxx'
+623,682,1,3,3,3,23,623,623,623,623,46,47,'ZXAAAA','GABAAA','OOOOxx'
+1360,683,0,0,0,0,60,360,1360,1360,1360,120,121,'IAAAAA','HABAAA','VVVVxx'
+7987,684,1,3,7,7,87,987,1987,2987,7987,174,175,'FVAAAA','IABAAA','AAAAxx'
+9788,685,0,0,8,8,88,788,1788,4788,9788,176,177,'MMAAAA','JABAAA','HHHHxx'
+3212,686,0,0,2,12,12,212,1212,3212,3212,24,25,'OTAAAA','KABAAA','OOOOxx'
+2725,687,1,1,5,5,25,725,725,2725,2725,50,51,'VAAAAA','LABAAA','VVVVxx'
+7837,688,1,1,7,17,37,837,1837,2837,7837,74,75,'LPAAAA','MABAAA','AAAAxx'
+4746,689,0,2,6,6,46,746,746,4746,4746,92,93,'OAAAAA','NABAAA','HHHHxx'
+3986,690,0,2,6,6,86,986,1986,3986,3986,172,173,'IXAAAA','OABAAA','OOOOxx'
+9128,691,0,0,8,8,28,128,1128,4128,9128,56,57,'CNAAAA','PABAAA','VVVVxx'
+5044,692,0,0,4,4,44,44,1044,44,5044,88,89,'AMAAAA','QABAAA','AAAAxx'
+8132,693,0,0,2,12,32,132,132,3132,8132,64,65,'UAAAAA','RABAAA','HHHHxx'
+9992,694,0,0,2,12,92,992,1992,4992,9992,184,185,'IUAAAA','SABAAA','OOOOxx'
+8468,695,0,0,8,8,68,468,468,3468,8468,136,137,'SNAAAA','TABAAA','VVVVxx'
+6876,696,0,0,6,16,76,876,876,1876,6876,152,153,'MEAAAA','UABAAA','AAAAxx'
+3532,697,0,0,2,12,32,532,1532,3532,3532,64,65,'WFAAAA','VABAAA','HHHHxx'
+2140,698,0,0,0,0,40,140,140,2140,2140,80,81,'IEAAAA','WABAAA','OOOOxx'
+2183,699,1,3,3,3,83,183,183,2183,2183,166,167,'ZFAAAA','XABAAA','VVVVxx'
+9766,700,0,2,6,6,66,766,1766,4766,9766,132,133,'QLAAAA','YABAAA','AAAAxx'
+7943,701,1,3,3,3,43,943,1943,2943,7943,86,87,'NTAAAA','ZABAAA','HHHHxx'
+9243,702,1,3,3,3,43,243,1243,4243,9243,86,87,'NRAAAA','ABBAAA','OOOOxx'
+6241,703,1,1,1,1,41,241,241,1241,6241,82,83,'BGAAAA','BBBAAA','VVVVxx'
+9540,704,0,0,0,0,40,540,1540,4540,9540,80,81,'YCAAAA','CBBAAA','AAAAxx'
+7418,705,0,2,8,18,18,418,1418,2418,7418,36,37,'IZAAAA','DBBAAA','HHHHxx'
+1603,706,1,3,3,3,3,603,1603,1603,1603,6,7,'RJAAAA','EBBAAA','OOOOxx'
+8950,707,0,2,0,10,50,950,950,3950,8950,100,101,'GGAAAA','FBBAAA','VVVVxx'
+6933,708,1,1,3,13,33,933,933,1933,6933,66,67,'RGAAAA','GBBAAA','AAAAxx'
+2646,709,0,2,6,6,46,646,646,2646,2646,92,93,'UXAAAA','HBBAAA','HHHHxx'
+3447,710,1,3,7,7,47,447,1447,3447,3447,94,95,'PCAAAA','IBBAAA','OOOOxx'
+9957,711,1,1,7,17,57,957,1957,4957,9957,114,115,'ZSAAAA','JBBAAA','VVVVxx'
+4623,712,1,3,3,3,23,623,623,4623,4623,46,47,'VVAAAA','KBBAAA','AAAAxx'
+9058,713,0,2,8,18,58,58,1058,4058,9058,116,117,'KKAAAA','LBBAAA','HHHHxx'
+7361,714,1,1,1,1,61,361,1361,2361,7361,122,123,'DXAAAA','MBBAAA','OOOOxx'
+2489,715,1,1,9,9,89,489,489,2489,2489,178,179,'TRAAAA','NBBAAA','VVVVxx'
+7643,716,1,3,3,3,43,643,1643,2643,7643,86,87,'ZHAAAA','OBBAAA','AAAAxx'
+9166,717,0,2,6,6,66,166,1166,4166,9166,132,133,'OOAAAA','PBBAAA','HHHHxx'
+7789,718,1,1,9,9,89,789,1789,2789,7789,178,179,'PNAAAA','QBBAAA','OOOOxx'
+2332,719,0,0,2,12,32,332,332,2332,2332,64,65,'SLAAAA','RBBAAA','VVVVxx'
+1832,720,0,0,2,12,32,832,1832,1832,1832,64,65,'MSAAAA','SBBAAA','AAAAxx'
+8375,721,1,3,5,15,75,375,375,3375,8375,150,151,'DKAAAA','TBBAAA','HHHHxx'
+948,722,0,0,8,8,48,948,948,948,948,96,97,'MKAAAA','UBBAAA','OOOOxx'
+5613,723,1,1,3,13,13,613,1613,613,5613,26,27,'XHAAAA','VBBAAA','VVVVxx'
+6310,724,0,2,0,10,10,310,310,1310,6310,20,21,'SIAAAA','WBBAAA','AAAAxx'
+4254,725,0,2,4,14,54,254,254,4254,4254,108,109,'QHAAAA','XBBAAA','HHHHxx'
+4260,726,0,0,0,0,60,260,260,4260,4260,120,121,'WHAAAA','YBBAAA','OOOOxx'
+2060,727,0,0,0,0,60,60,60,2060,2060,120,121,'GBAAAA','ZBBAAA','VVVVxx'
+4831,728,1,3,1,11,31,831,831,4831,4831,62,63,'VDAAAA','ACBAAA','AAAAxx'
+6176,729,0,0,6,16,76,176,176,1176,6176,152,153,'ODAAAA','BCBAAA','HHHHxx'
+6688,730,0,0,8,8,88,688,688,1688,6688,176,177,'GXAAAA','CCBAAA','OOOOxx'
+5752,731,0,0,2,12,52,752,1752,752,5752,104,105,'GNAAAA','DCBAAA','VVVVxx'
+8714,732,0,2,4,14,14,714,714,3714,8714,28,29,'EXAAAA','ECBAAA','AAAAxx'
+6739,733,1,3,9,19,39,739,739,1739,6739,78,79,'FZAAAA','FCBAAA','HHHHxx'
+7066,734,0,2,6,6,66,66,1066,2066,7066,132,133,'ULAAAA','GCBAAA','OOOOxx'
+7250,735,0,2,0,10,50,250,1250,2250,7250,100,101,'WSAAAA','HCBAAA','VVVVxx'
+3161,736,1,1,1,1,61,161,1161,3161,3161,122,123,'PRAAAA','ICBAAA','AAAAxx'
+1411,737,1,3,1,11,11,411,1411,1411,1411,22,23,'HCAAAA','JCBAAA','HHHHxx'
+9301,738,1,1,1,1,1,301,1301,4301,9301,2,3,'TTAAAA','KCBAAA','OOOOxx'
+8324,739,0,0,4,4,24,324,324,3324,8324,48,49,'EIAAAA','LCBAAA','VVVVxx'
+9641,740,1,1,1,1,41,641,1641,4641,9641,82,83,'VGAAAA','MCBAAA','AAAAxx'
+7077,741,1,1,7,17,77,77,1077,2077,7077,154,155,'FMAAAA','NCBAAA','HHHHxx'
+9888,742,0,0,8,8,88,888,1888,4888,9888,176,177,'IQAAAA','OCBAAA','OOOOxx'
+9909,743,1,1,9,9,9,909,1909,4909,9909,18,19,'DRAAAA','PCBAAA','VVVVxx'
+2209,744,1,1,9,9,9,209,209,2209,2209,18,19,'ZGAAAA','QCBAAA','AAAAxx'
+6904,745,0,0,4,4,4,904,904,1904,6904,8,9,'OFAAAA','RCBAAA','HHHHxx'
+6608,746,0,0,8,8,8,608,608,1608,6608,16,17,'EUAAAA','SCBAAA','OOOOxx'
+8400,747,0,0,0,0,0,400,400,3400,8400,0,1,'CLAAAA','TCBAAA','VVVVxx'
+5124,748,0,0,4,4,24,124,1124,124,5124,48,49,'CPAAAA','UCBAAA','AAAAxx'
+5484,749,0,0,4,4,84,484,1484,484,5484,168,169,'YCAAAA','VCBAAA','HHHHxx'
+3575,750,1,3,5,15,75,575,1575,3575,3575,150,151,'NHAAAA','WCBAAA','OOOOxx'
+9723,751,1,3,3,3,23,723,1723,4723,9723,46,47,'ZJAAAA','XCBAAA','VVVVxx'
+360,752,0,0,0,0,60,360,360,360,360,120,121,'WNAAAA','YCBAAA','AAAAxx'
+1059,753,1,3,9,19,59,59,1059,1059,1059,118,119,'TOAAAA','ZCBAAA','HHHHxx'
+4941,754,1,1,1,1,41,941,941,4941,4941,82,83,'BIAAAA','ADBAAA','OOOOxx'
+2535,755,1,3,5,15,35,535,535,2535,2535,70,71,'NTAAAA','BDBAAA','VVVVxx'
+4119,756,1,3,9,19,19,119,119,4119,4119,38,39,'LCAAAA','CDBAAA','AAAAxx'
+3725,757,1,1,5,5,25,725,1725,3725,3725,50,51,'HNAAAA','DDBAAA','HHHHxx'
+4758,758,0,2,8,18,58,758,758,4758,4758,116,117,'ABAAAA','EDBAAA','OOOOxx'
+9593,759,1,1,3,13,93,593,1593,4593,9593,186,187,'ZEAAAA','FDBAAA','VVVVxx'
+4663,760,1,3,3,3,63,663,663,4663,4663,126,127,'JXAAAA','GDBAAA','AAAAxx'
+7734,761,0,2,4,14,34,734,1734,2734,7734,68,69,'MLAAAA','HDBAAA','HHHHxx'
+9156,762,0,0,6,16,56,156,1156,4156,9156,112,113,'EOAAAA','IDBAAA','OOOOxx'
+8120,763,0,0,0,0,20,120,120,3120,8120,40,41,'IAAAAA','JDBAAA','VVVVxx'
+4385,764,1,1,5,5,85,385,385,4385,4385,170,171,'RMAAAA','KDBAAA','AAAAxx'
+2926,765,0,2,6,6,26,926,926,2926,2926,52,53,'OIAAAA','LDBAAA','HHHHxx'
+4186,766,0,2,6,6,86,186,186,4186,4186,172,173,'AFAAAA','MDBAAA','OOOOxx'
+2508,767,0,0,8,8,8,508,508,2508,2508,16,17,'MSAAAA','NDBAAA','VVVVxx'
+4012,768,0,0,2,12,12,12,12,4012,4012,24,25,'IYAAAA','ODBAAA','AAAAxx'
+6266,769,0,2,6,6,66,266,266,1266,6266,132,133,'AHAAAA','PDBAAA','HHHHxx'
+3709,770,1,1,9,9,9,709,1709,3709,3709,18,19,'RMAAAA','QDBAAA','OOOOxx'
+7289,771,1,1,9,9,89,289,1289,2289,7289,178,179,'JUAAAA','RDBAAA','VVVVxx'
+8875,772,1,3,5,15,75,875,875,3875,8875,150,151,'JDAAAA','SDBAAA','AAAAxx'
+4412,773,0,0,2,12,12,412,412,4412,4412,24,25,'SNAAAA','TDBAAA','HHHHxx'
+3033,774,1,1,3,13,33,33,1033,3033,3033,66,67,'RMAAAA','UDBAAA','OOOOxx'
+1645,775,1,1,5,5,45,645,1645,1645,1645,90,91,'HLAAAA','VDBAAA','VVVVxx'
+3557,776,1,1,7,17,57,557,1557,3557,3557,114,115,'VGAAAA','WDBAAA','AAAAxx'
+6316,777,0,0,6,16,16,316,316,1316,6316,32,33,'YIAAAA','XDBAAA','HHHHxx'
+2054,778,0,2,4,14,54,54,54,2054,2054,108,109,'ABAAAA','YDBAAA','OOOOxx'
+7031,779,1,3,1,11,31,31,1031,2031,7031,62,63,'LKAAAA','ZDBAAA','VVVVxx'
+3405,780,1,1,5,5,5,405,1405,3405,3405,10,11,'ZAAAAA','AEBAAA','AAAAxx'
+5343,781,1,3,3,3,43,343,1343,343,5343,86,87,'NXAAAA','BEBAAA','HHHHxx'
+5240,782,0,0,0,0,40,240,1240,240,5240,80,81,'OTAAAA','CEBAAA','OOOOxx'
+9650,783,0,2,0,10,50,650,1650,4650,9650,100,101,'EHAAAA','DEBAAA','VVVVxx'
+3777,784,1,1,7,17,77,777,1777,3777,3777,154,155,'HPAAAA','EEBAAA','AAAAxx'
+9041,785,1,1,1,1,41,41,1041,4041,9041,82,83,'TJAAAA','FEBAAA','HHHHxx'
+6923,786,1,3,3,3,23,923,923,1923,6923,46,47,'HGAAAA','GEBAAA','OOOOxx'
+2977,787,1,1,7,17,77,977,977,2977,2977,154,155,'NKAAAA','HEBAAA','VVVVxx'
+5500,788,0,0,0,0,0,500,1500,500,5500,0,1,'ODAAAA','IEBAAA','AAAAxx'
+1044,789,0,0,4,4,44,44,1044,1044,1044,88,89,'EOAAAA','JEBAAA','HHHHxx'
+434,790,0,2,4,14,34,434,434,434,434,68,69,'SQAAAA','KEBAAA','OOOOxx'
+611,791,1,3,1,11,11,611,611,611,611,22,23,'NXAAAA','LEBAAA','VVVVxx'
+5760,792,0,0,0,0,60,760,1760,760,5760,120,121,'ONAAAA','MEBAAA','AAAAxx'
+2445,793,1,1,5,5,45,445,445,2445,2445,90,91,'BQAAAA','NEBAAA','HHHHxx'
+7098,794,0,2,8,18,98,98,1098,2098,7098,196,197,'ANAAAA','OEBAAA','OOOOxx'
+2188,795,0,0,8,8,88,188,188,2188,2188,176,177,'EGAAAA','PEBAAA','VVVVxx'
+4597,796,1,1,7,17,97,597,597,4597,4597,194,195,'VUAAAA','QEBAAA','AAAAxx'
+1913,797,1,1,3,13,13,913,1913,1913,1913,26,27,'PVAAAA','REBAAA','HHHHxx'
+8696,798,0,0,6,16,96,696,696,3696,8696,192,193,'MWAAAA','SEBAAA','OOOOxx'
+3332,799,0,0,2,12,32,332,1332,3332,3332,64,65,'EYAAAA','TEBAAA','VVVVxx'
+8760,800,0,0,0,0,60,760,760,3760,8760,120,121,'YYAAAA','UEBAAA','AAAAxx'
+3215,801,1,3,5,15,15,215,1215,3215,3215,30,31,'RTAAAA','VEBAAA','HHHHxx'
+1625,802,1,1,5,5,25,625,1625,1625,1625,50,51,'NKAAAA','WEBAAA','OOOOxx'
+4219,803,1,3,9,19,19,219,219,4219,4219,38,39,'HGAAAA','XEBAAA','VVVVxx'
+415,804,1,3,5,15,15,415,415,415,415,30,31,'ZPAAAA','YEBAAA','AAAAxx'
+4242,805,0,2,2,2,42,242,242,4242,4242,84,85,'EHAAAA','ZEBAAA','HHHHxx'
+8660,806,0,0,0,0,60,660,660,3660,8660,120,121,'CVAAAA','AFBAAA','OOOOxx'
+6525,807,1,1,5,5,25,525,525,1525,6525,50,51,'ZQAAAA','BFBAAA','VVVVxx'
+2141,808,1,1,1,1,41,141,141,2141,2141,82,83,'JEAAAA','CFBAAA','AAAAxx'
+5152,809,0,0,2,12,52,152,1152,152,5152,104,105,'EQAAAA','DFBAAA','HHHHxx'
+8560,810,0,0,0,0,60,560,560,3560,8560,120,121,'GRAAAA','EFBAAA','OOOOxx'
+9835,811,1,3,5,15,35,835,1835,4835,9835,70,71,'HOAAAA','FFBAAA','VVVVxx'
+2657,812,1,1,7,17,57,657,657,2657,2657,114,115,'FYAAAA','GFBAAA','AAAAxx'
+6085,813,1,1,5,5,85,85,85,1085,6085,170,171,'BAAAAA','HFBAAA','HHHHxx'
+6698,814,0,2,8,18,98,698,698,1698,6698,196,197,'QXAAAA','IFBAAA','OOOOxx'
+5421,815,1,1,1,1,21,421,1421,421,5421,42,43,'NAAAAA','JFBAAA','VVVVxx'
+6661,816,1,1,1,1,61,661,661,1661,6661,122,123,'FWAAAA','KFBAAA','AAAAxx'
+5645,817,1,1,5,5,45,645,1645,645,5645,90,91,'DJAAAA','LFBAAA','HHHHxx'
+1248,818,0,0,8,8,48,248,1248,1248,1248,96,97,'AWAAAA','MFBAAA','OOOOxx'
+5690,819,0,2,0,10,90,690,1690,690,5690,180,181,'WKAAAA','NFBAAA','VVVVxx'
+4762,820,0,2,2,2,62,762,762,4762,4762,124,125,'EBAAAA','OFBAAA','AAAAxx'
+1455,821,1,3,5,15,55,455,1455,1455,1455,110,111,'ZDAAAA','PFBAAA','HHHHxx'
+9846,822,0,2,6,6,46,846,1846,4846,9846,92,93,'SOAAAA','QFBAAA','OOOOxx'
+5295,823,1,3,5,15,95,295,1295,295,5295,190,191,'RVAAAA','RFBAAA','VVVVxx'
+2826,824,0,2,6,6,26,826,826,2826,2826,52,53,'SEAAAA','SFBAAA','AAAAxx'
+7496,825,0,0,6,16,96,496,1496,2496,7496,192,193,'ICAAAA','TFBAAA','HHHHxx'
+3024,826,0,0,4,4,24,24,1024,3024,3024,48,49,'IMAAAA','UFBAAA','OOOOxx'
+4945,827,1,1,5,5,45,945,945,4945,4945,90,91,'FIAAAA','VFBAAA','VVVVxx'
+4404,828,0,0,4,4,4,404,404,4404,4404,8,9,'KNAAAA','WFBAAA','AAAAxx'
+9302,829,0,2,2,2,2,302,1302,4302,9302,4,5,'UTAAAA','XFBAAA','HHHHxx'
+1286,830,0,2,6,6,86,286,1286,1286,1286,172,173,'MXAAAA','YFBAAA','OOOOxx'
+8435,831,1,3,5,15,35,435,435,3435,8435,70,71,'LMAAAA','ZFBAAA','VVVVxx'
+8969,832,1,1,9,9,69,969,969,3969,8969,138,139,'ZGAAAA','AGBAAA','AAAAxx'
+3302,833,0,2,2,2,2,302,1302,3302,3302,4,5,'AXAAAA','BGBAAA','HHHHxx'
+9753,834,1,1,3,13,53,753,1753,4753,9753,106,107,'DLAAAA','CGBAAA','OOOOxx'
+9374,835,0,2,4,14,74,374,1374,4374,9374,148,149,'OWAAAA','DGBAAA','VVVVxx'
+4907,836,1,3,7,7,7,907,907,4907,4907,14,15,'TGAAAA','EGBAAA','AAAAxx'
+1659,837,1,3,9,19,59,659,1659,1659,1659,118,119,'VLAAAA','FGBAAA','HHHHxx'
+5095,838,1,3,5,15,95,95,1095,95,5095,190,191,'ZNAAAA','GGBAAA','OOOOxx'
+9446,839,0,2,6,6,46,446,1446,4446,9446,92,93,'IZAAAA','HGBAAA','VVVVxx'
+8528,840,0,0,8,8,28,528,528,3528,8528,56,57,'AQAAAA','IGBAAA','AAAAxx'
+4890,841,0,2,0,10,90,890,890,4890,4890,180,181,'CGAAAA','JGBAAA','HHHHxx'
+1221,842,1,1,1,1,21,221,1221,1221,1221,42,43,'ZUAAAA','KGBAAA','OOOOxx'
+5583,843,1,3,3,3,83,583,1583,583,5583,166,167,'TGAAAA','LGBAAA','VVVVxx'
+7303,844,1,3,3,3,3,303,1303,2303,7303,6,7,'XUAAAA','MGBAAA','AAAAxx'
+406,845,0,2,6,6,6,406,406,406,406,12,13,'QPAAAA','NGBAAA','HHHHxx'
+7542,846,0,2,2,2,42,542,1542,2542,7542,84,85,'CEAAAA','OGBAAA','OOOOxx'
+9507,847,1,3,7,7,7,507,1507,4507,9507,14,15,'RBAAAA','PGBAAA','VVVVxx'
+9511,848,1,3,1,11,11,511,1511,4511,9511,22,23,'VBAAAA','QGBAAA','AAAAxx'
+1373,849,1,1,3,13,73,373,1373,1373,1373,146,147,'VAAAAA','RGBAAA','HHHHxx'
+6556,850,0,0,6,16,56,556,556,1556,6556,112,113,'ESAAAA','SGBAAA','OOOOxx'
+4117,851,1,1,7,17,17,117,117,4117,4117,34,35,'JCAAAA','TGBAAA','VVVVxx'
+7794,852,0,2,4,14,94,794,1794,2794,7794,188,189,'UNAAAA','UGBAAA','AAAAxx'
+7170,853,0,2,0,10,70,170,1170,2170,7170,140,141,'UPAAAA','VGBAAA','HHHHxx'
+5809,854,1,1,9,9,9,809,1809,809,5809,18,19,'LPAAAA','WGBAAA','OOOOxx'
+7828,855,0,0,8,8,28,828,1828,2828,7828,56,57,'CPAAAA','XGBAAA','VVVVxx'
+8046,856,0,2,6,6,46,46,46,3046,8046,92,93,'MXAAAA','YGBAAA','AAAAxx'
+4833,857,1,1,3,13,33,833,833,4833,4833,66,67,'XDAAAA','ZGBAAA','HHHHxx'
+2107,858,1,3,7,7,7,107,107,2107,2107,14,15,'BDAAAA','AHBAAA','OOOOxx'
+4276,859,0,0,6,16,76,276,276,4276,4276,152,153,'MIAAAA','BHBAAA','VVVVxx'
+9536,860,0,0,6,16,36,536,1536,4536,9536,72,73,'UCAAAA','CHBAAA','AAAAxx'
+5549,861,1,1,9,9,49,549,1549,549,5549,98,99,'LFAAAA','DHBAAA','HHHHxx'
+6427,862,1,3,7,7,27,427,427,1427,6427,54,55,'FNAAAA','EHBAAA','OOOOxx'
+1382,863,0,2,2,2,82,382,1382,1382,1382,164,165,'EBAAAA','FHBAAA','VVVVxx'
+3256,864,0,0,6,16,56,256,1256,3256,3256,112,113,'GVAAAA','GHBAAA','AAAAxx'
+3270,865,0,2,0,10,70,270,1270,3270,3270,140,141,'UVAAAA','HHBAAA','HHHHxx'
+4808,866,0,0,8,8,8,808,808,4808,4808,16,17,'YCAAAA','IHBAAA','OOOOxx'
+7938,867,0,2,8,18,38,938,1938,2938,7938,76,77,'ITAAAA','JHBAAA','VVVVxx'
+4405,868,1,1,5,5,5,405,405,4405,4405,10,11,'LNAAAA','KHBAAA','AAAAxx'
+2264,869,0,0,4,4,64,264,264,2264,2264,128,129,'CJAAAA','LHBAAA','HHHHxx'
+80,870,0,0,0,0,80,80,80,80,80,160,161,'CDAAAA','MHBAAA','OOOOxx'
+320,871,0,0,0,0,20,320,320,320,320,40,41,'IMAAAA','NHBAAA','VVVVxx'
+2383,872,1,3,3,3,83,383,383,2383,2383,166,167,'RNAAAA','OHBAAA','AAAAxx'
+3146,873,0,2,6,6,46,146,1146,3146,3146,92,93,'ARAAAA','PHBAAA','HHHHxx'
+6911,874,1,3,1,11,11,911,911,1911,6911,22,23,'VFAAAA','QHBAAA','OOOOxx'
+7377,875,1,1,7,17,77,377,1377,2377,7377,154,155,'TXAAAA','RHBAAA','VVVVxx'
+9965,876,1,1,5,5,65,965,1965,4965,9965,130,131,'HTAAAA','SHBAAA','AAAAxx'
+8361,877,1,1,1,1,61,361,361,3361,8361,122,123,'PJAAAA','THBAAA','HHHHxx'
+9417,878,1,1,7,17,17,417,1417,4417,9417,34,35,'FYAAAA','UHBAAA','OOOOxx'
+2483,879,1,3,3,3,83,483,483,2483,2483,166,167,'NRAAAA','VHBAAA','VVVVxx'
+9843,880,1,3,3,3,43,843,1843,4843,9843,86,87,'POAAAA','WHBAAA','AAAAxx'
+6395,881,1,3,5,15,95,395,395,1395,6395,190,191,'ZLAAAA','XHBAAA','HHHHxx'
+6444,882,0,0,4,4,44,444,444,1444,6444,88,89,'WNAAAA','YHBAAA','OOOOxx'
+1820,883,0,0,0,0,20,820,1820,1820,1820,40,41,'ASAAAA','ZHBAAA','VVVVxx'
+2768,884,0,0,8,8,68,768,768,2768,2768,136,137,'MCAAAA','AIBAAA','AAAAxx'
+5413,885,1,1,3,13,13,413,1413,413,5413,26,27,'FAAAAA','BIBAAA','HHHHxx'
+2923,886,1,3,3,3,23,923,923,2923,2923,46,47,'LIAAAA','CIBAAA','OOOOxx'
+5286,887,0,2,6,6,86,286,1286,286,5286,172,173,'IVAAAA','DIBAAA','VVVVxx'
+6126,888,0,2,6,6,26,126,126,1126,6126,52,53,'QBAAAA','EIBAAA','AAAAxx'
+8343,889,1,3,3,3,43,343,343,3343,8343,86,87,'XIAAAA','FIBAAA','HHHHxx'
+6010,890,0,2,0,10,10,10,10,1010,6010,20,21,'EXAAAA','GIBAAA','OOOOxx'
+4177,891,1,1,7,17,77,177,177,4177,4177,154,155,'REAAAA','HIBAAA','VVVVxx'
+5808,892,0,0,8,8,8,808,1808,808,5808,16,17,'KPAAAA','IIBAAA','AAAAxx'
+4859,893,1,3,9,19,59,859,859,4859,4859,118,119,'XEAAAA','JIBAAA','HHHHxx'
+9252,894,0,0,2,12,52,252,1252,4252,9252,104,105,'WRAAAA','KIBAAA','OOOOxx'
+2941,895,1,1,1,1,41,941,941,2941,2941,82,83,'DJAAAA','LIBAAA','VVVVxx'
+8693,896,1,1,3,13,93,693,693,3693,8693,186,187,'JWAAAA','MIBAAA','AAAAxx'
+4432,897,0,0,2,12,32,432,432,4432,4432,64,65,'MOAAAA','NIBAAA','HHHHxx'
+2371,898,1,3,1,11,71,371,371,2371,2371,142,143,'FNAAAA','OIBAAA','OOOOxx'
+7546,899,0,2,6,6,46,546,1546,2546,7546,92,93,'GEAAAA','PIBAAA','VVVVxx'
+1369,900,1,1,9,9,69,369,1369,1369,1369,138,139,'RAAAAA','QIBAAA','AAAAxx'
+4687,901,1,3,7,7,87,687,687,4687,4687,174,175,'HYAAAA','RIBAAA','HHHHxx'
+8941,902,1,1,1,1,41,941,941,3941,8941,82,83,'XFAAAA','SIBAAA','OOOOxx'
+226,903,0,2,6,6,26,226,226,226,226,52,53,'SIAAAA','TIBAAA','VVVVxx'
+3493,904,1,1,3,13,93,493,1493,3493,3493,186,187,'JEAAAA','UIBAAA','AAAAxx'
+6433,905,1,1,3,13,33,433,433,1433,6433,66,67,'LNAAAA','VIBAAA','HHHHxx'
+9189,906,1,1,9,9,89,189,1189,4189,9189,178,179,'LPAAAA','WIBAAA','OOOOxx'
+6027,907,1,3,7,7,27,27,27,1027,6027,54,55,'VXAAAA','XIBAAA','VVVVxx'
+4615,908,1,3,5,15,15,615,615,4615,4615,30,31,'NVAAAA','YIBAAA','AAAAxx'
+5320,909,0,0,0,0,20,320,1320,320,5320,40,41,'QWAAAA','ZIBAAA','HHHHxx'
+7002,910,0,2,2,2,2,2,1002,2002,7002,4,5,'IJAAAA','AJBAAA','OOOOxx'
+7367,911,1,3,7,7,67,367,1367,2367,7367,134,135,'JXAAAA','BJBAAA','VVVVxx'
+289,912,1,1,9,9,89,289,289,289,289,178,179,'DLAAAA','CJBAAA','AAAAxx'
+407,913,1,3,7,7,7,407,407,407,407,14,15,'RPAAAA','DJBAAA','HHHHxx'
+504,914,0,0,4,4,4,504,504,504,504,8,9,'KTAAAA','EJBAAA','OOOOxx'
+8301,915,1,1,1,1,1,301,301,3301,8301,2,3,'HHAAAA','FJBAAA','VVVVxx'
+1396,916,0,0,6,16,96,396,1396,1396,1396,192,193,'SBAAAA','GJBAAA','AAAAxx'
+4794,917,0,2,4,14,94,794,794,4794,4794,188,189,'KCAAAA','HJBAAA','HHHHxx'
+6400,918,0,0,0,0,0,400,400,1400,6400,0,1,'EMAAAA','IJBAAA','OOOOxx'
+1275,919,1,3,5,15,75,275,1275,1275,1275,150,151,'BXAAAA','JJBAAA','VVVVxx'
+5797,920,1,1,7,17,97,797,1797,797,5797,194,195,'ZOAAAA','KJBAAA','AAAAxx'
+2221,921,1,1,1,1,21,221,221,2221,2221,42,43,'LHAAAA','LJBAAA','HHHHxx'
+2504,922,0,0,4,4,4,504,504,2504,2504,8,9,'ISAAAA','MJBAAA','OOOOxx'
+2143,923,1,3,3,3,43,143,143,2143,2143,86,87,'LEAAAA','NJBAAA','VVVVxx'
+1083,924,1,3,3,3,83,83,1083,1083,1083,166,167,'RPAAAA','OJBAAA','AAAAxx'
+6148,925,0,0,8,8,48,148,148,1148,6148,96,97,'MCAAAA','PJBAAA','HHHHxx'
+3612,926,0,0,2,12,12,612,1612,3612,3612,24,25,'YIAAAA','QJBAAA','OOOOxx'
+9499,927,1,3,9,19,99,499,1499,4499,9499,198,199,'JBAAAA','RJBAAA','VVVVxx'
+5773,928,1,1,3,13,73,773,1773,773,5773,146,147,'BOAAAA','SJBAAA','AAAAxx'
+1014,929,0,2,4,14,14,14,1014,1014,1014,28,29,'ANAAAA','TJBAAA','HHHHxx'
+1427,930,1,3,7,7,27,427,1427,1427,1427,54,55,'XCAAAA','UJBAAA','OOOOxx'
+6770,931,0,2,0,10,70,770,770,1770,6770,140,141,'KAAAAA','VJBAAA','VVVVxx'
+9042,932,0,2,2,2,42,42,1042,4042,9042,84,85,'UJAAAA','WJBAAA','AAAAxx'
+9892,933,0,0,2,12,92,892,1892,4892,9892,184,185,'MQAAAA','XJBAAA','HHHHxx'
+1771,934,1,3,1,11,71,771,1771,1771,1771,142,143,'DQAAAA','YJBAAA','OOOOxx'
+7392,935,0,0,2,12,92,392,1392,2392,7392,184,185,'IYAAAA','ZJBAAA','VVVVxx'
+4465,936,1,1,5,5,65,465,465,4465,4465,130,131,'TPAAAA','AKBAAA','AAAAxx'
+278,937,0,2,8,18,78,278,278,278,278,156,157,'SKAAAA','BKBAAA','HHHHxx'
+7776,938,0,0,6,16,76,776,1776,2776,7776,152,153,'CNAAAA','CKBAAA','OOOOxx'
+3763,939,1,3,3,3,63,763,1763,3763,3763,126,127,'TOAAAA','DKBAAA','VVVVxx'
+7503,940,1,3,3,3,3,503,1503,2503,7503,6,7,'PCAAAA','EKBAAA','AAAAxx'
+3793,941,1,1,3,13,93,793,1793,3793,3793,186,187,'XPAAAA','FKBAAA','HHHHxx'
+6510,942,0,2,0,10,10,510,510,1510,6510,20,21,'KQAAAA','GKBAAA','OOOOxx'
+7641,943,1,1,1,1,41,641,1641,2641,7641,82,83,'XHAAAA','HKBAAA','VVVVxx'
+3228,944,0,0,8,8,28,228,1228,3228,3228,56,57,'EUAAAA','IKBAAA','AAAAxx'
+194,945,0,2,4,14,94,194,194,194,194,188,189,'MHAAAA','JKBAAA','HHHHxx'
+8555,946,1,3,5,15,55,555,555,3555,8555,110,111,'BRAAAA','KKBAAA','OOOOxx'
+4997,947,1,1,7,17,97,997,997,4997,4997,194,195,'FKAAAA','LKBAAA','VVVVxx'
+8687,948,1,3,7,7,87,687,687,3687,8687,174,175,'DWAAAA','MKBAAA','AAAAxx'
+6632,949,0,0,2,12,32,632,632,1632,6632,64,65,'CVAAAA','NKBAAA','HHHHxx'
+9607,950,1,3,7,7,7,607,1607,4607,9607,14,15,'NFAAAA','OKBAAA','OOOOxx'
+6201,951,1,1,1,1,1,201,201,1201,6201,2,3,'NEAAAA','PKBAAA','VVVVxx'
+857,952,1,1,7,17,57,857,857,857,857,114,115,'ZGAAAA','QKBAAA','AAAAxx'
+5623,953,1,3,3,3,23,623,1623,623,5623,46,47,'HIAAAA','RKBAAA','HHHHxx'
+5979,954,1,3,9,19,79,979,1979,979,5979,158,159,'ZVAAAA','SKBAAA','OOOOxx'
+2201,955,1,1,1,1,1,201,201,2201,2201,2,3,'RGAAAA','TKBAAA','VVVVxx'
+3166,956,0,2,6,6,66,166,1166,3166,3166,132,133,'URAAAA','UKBAAA','AAAAxx'
+6249,957,1,1,9,9,49,249,249,1249,6249,98,99,'JGAAAA','VKBAAA','HHHHxx'
+3271,958,1,3,1,11,71,271,1271,3271,3271,142,143,'VVAAAA','WKBAAA','OOOOxx'
+7777,959,1,1,7,17,77,777,1777,2777,7777,154,155,'DNAAAA','XKBAAA','VVVVxx'
+6732,960,0,0,2,12,32,732,732,1732,6732,64,65,'YYAAAA','YKBAAA','AAAAxx'
+6297,961,1,1,7,17,97,297,297,1297,6297,194,195,'FIAAAA','ZKBAAA','HHHHxx'
+5685,962,1,1,5,5,85,685,1685,685,5685,170,171,'RKAAAA','ALBAAA','OOOOxx'
+9931,963,1,3,1,11,31,931,1931,4931,9931,62,63,'ZRAAAA','BLBAAA','VVVVxx'
+7485,964,1,1,5,5,85,485,1485,2485,7485,170,171,'XBAAAA','CLBAAA','AAAAxx'
+386,965,0,2,6,6,86,386,386,386,386,172,173,'WOAAAA','DLBAAA','HHHHxx'
+8204,966,0,0,4,4,4,204,204,3204,8204,8,9,'ODAAAA','ELBAAA','OOOOxx'
+3606,967,0,2,6,6,6,606,1606,3606,3606,12,13,'SIAAAA','FLBAAA','VVVVxx'
+1692,968,0,0,2,12,92,692,1692,1692,1692,184,185,'CNAAAA','GLBAAA','AAAAxx'
+3002,969,0,2,2,2,2,2,1002,3002,3002,4,5,'MLAAAA','HLBAAA','HHHHxx'
+9676,970,0,0,6,16,76,676,1676,4676,9676,152,153,'EIAAAA','ILBAAA','OOOOxx'
+915,971,1,3,5,15,15,915,915,915,915,30,31,'FJAAAA','JLBAAA','VVVVxx'
+7706,972,0,2,6,6,6,706,1706,2706,7706,12,13,'KKAAAA','KLBAAA','AAAAxx'
+6080,973,0,0,0,0,80,80,80,1080,6080,160,161,'WZAAAA','LLBAAA','HHHHxx'
+1860,974,0,0,0,0,60,860,1860,1860,1860,120,121,'OTAAAA','MLBAAA','OOOOxx'
+1444,975,0,0,4,4,44,444,1444,1444,1444,88,89,'ODAAAA','NLBAAA','VVVVxx'
+7208,976,0,0,8,8,8,208,1208,2208,7208,16,17,'GRAAAA','OLBAAA','AAAAxx'
+8554,977,0,2,4,14,54,554,554,3554,8554,108,109,'ARAAAA','PLBAAA','HHHHxx'
+2028,978,0,0,8,8,28,28,28,2028,2028,56,57,'AAAAAA','QLBAAA','OOOOxx'
+9893,979,1,1,3,13,93,893,1893,4893,9893,186,187,'NQAAAA','RLBAAA','VVVVxx'
+4740,980,0,0,0,0,40,740,740,4740,4740,80,81,'IAAAAA','SLBAAA','AAAAxx'
+6186,981,0,2,6,6,86,186,186,1186,6186,172,173,'YDAAAA','TLBAAA','HHHHxx'
+6357,982,1,1,7,17,57,357,357,1357,6357,114,115,'NKAAAA','ULBAAA','OOOOxx'
+3699,983,1,3,9,19,99,699,1699,3699,3699,198,199,'HMAAAA','VLBAAA','VVVVxx'
+7620,984,0,0,0,0,20,620,1620,2620,7620,40,41,'CHAAAA','WLBAAA','AAAAxx'
+921,985,1,1,1,1,21,921,921,921,921,42,43,'LJAAAA','XLBAAA','HHHHxx'
+5506,986,0,2,6,6,6,506,1506,506,5506,12,13,'UDAAAA','YLBAAA','OOOOxx'
+8851,987,1,3,1,11,51,851,851,3851,8851,102,103,'LCAAAA','ZLBAAA','VVVVxx'
+3205,988,1,1,5,5,5,205,1205,3205,3205,10,11,'HTAAAA','AMBAAA','AAAAxx'
+1956,989,0,0,6,16,56,956,1956,1956,1956,112,113,'GXAAAA','BMBAAA','HHHHxx'
+6272,990,0,0,2,12,72,272,272,1272,6272,144,145,'GHAAAA','CMBAAA','OOOOxx'
+1509,991,1,1,9,9,9,509,1509,1509,1509,18,19,'BGAAAA','DMBAAA','VVVVxx'
+53,992,1,1,3,13,53,53,53,53,53,106,107,'BCAAAA','EMBAAA','AAAAxx'
+213,993,1,1,3,13,13,213,213,213,213,26,27,'FIAAAA','FMBAAA','HHHHxx'
+4924,994,0,0,4,4,24,924,924,4924,4924,48,49,'KHAAAA','GMBAAA','OOOOxx'
+2097,995,1,1,7,17,97,97,97,2097,2097,194,195,'RCAAAA','HMBAAA','VVVVxx'
+4607,996,1,3,7,7,7,607,607,4607,4607,14,15,'FVAAAA','IMBAAA','AAAAxx'
+1582,997,0,2,2,2,82,582,1582,1582,1582,164,165,'WIAAAA','JMBAAA','HHHHxx'
+6643,998,1,3,3,3,43,643,643,1643,6643,86,87,'NVAAAA','KMBAAA','OOOOxx'
+2238,999,0,2,8,18,38,238,238,2238,2238,76,77,'CIAAAA','LMBAAA','VVVVxx'
+2942,1000,0,2,2,2,42,942,942,2942,2942,84,85,'EJAAAA','MMBAAA','AAAAxx'
+1655,1001,1,3,5,15,55,655,1655,1655,1655,110,111,'RLAAAA','NMBAAA','HHHHxx'
+3226,1002,0,2,6,6,26,226,1226,3226,3226,52,53,'CUAAAA','OMBAAA','OOOOxx'
+4263,1003,1,3,3,3,63,263,263,4263,4263,126,127,'ZHAAAA','PMBAAA','VVVVxx'
+960,1004,0,0,0,0,60,960,960,960,960,120,121,'YKAAAA','QMBAAA','AAAAxx'
+1213,1005,1,1,3,13,13,213,1213,1213,1213,26,27,'RUAAAA','RMBAAA','HHHHxx'
+1845,1006,1,1,5,5,45,845,1845,1845,1845,90,91,'ZSAAAA','SMBAAA','OOOOxx'
+6944,1007,0,0,4,4,44,944,944,1944,6944,88,89,'CHAAAA','TMBAAA','VVVVxx'
+5284,1008,0,0,4,4,84,284,1284,284,5284,168,169,'GVAAAA','UMBAAA','AAAAxx'
+188,1009,0,0,8,8,88,188,188,188,188,176,177,'GHAAAA','VMBAAA','HHHHxx'
+748,1010,0,0,8,8,48,748,748,748,748,96,97,'UCAAAA','WMBAAA','OOOOxx'
+2226,1011,0,2,6,6,26,226,226,2226,2226,52,53,'QHAAAA','XMBAAA','VVVVxx'
+7342,1012,0,2,2,2,42,342,1342,2342,7342,84,85,'KWAAAA','YMBAAA','AAAAxx'
+6120,1013,0,0,0,0,20,120,120,1120,6120,40,41,'KBAAAA','ZMBAAA','HHHHxx'
+536,1014,0,0,6,16,36,536,536,536,536,72,73,'QUAAAA','ANBAAA','OOOOxx'
+3239,1015,1,3,9,19,39,239,1239,3239,3239,78,79,'PUAAAA','BNBAAA','VVVVxx'
+2832,1016,0,0,2,12,32,832,832,2832,2832,64,65,'YEAAAA','CNBAAA','AAAAxx'
+5296,1017,0,0,6,16,96,296,1296,296,5296,192,193,'SVAAAA','DNBAAA','HHHHxx'
+5795,1018,1,3,5,15,95,795,1795,795,5795,190,191,'XOAAAA','ENBAAA','OOOOxx'
+6290,1019,0,2,0,10,90,290,290,1290,6290,180,181,'YHAAAA','FNBAAA','VVVVxx'
+4916,1020,0,0,6,16,16,916,916,4916,4916,32,33,'CHAAAA','GNBAAA','AAAAxx'
+8366,1021,0,2,6,6,66,366,366,3366,8366,132,133,'UJAAAA','HNBAAA','HHHHxx'
+4248,1022,0,0,8,8,48,248,248,4248,4248,96,97,'KHAAAA','INBAAA','OOOOxx'
+6460,1023,0,0,0,0,60,460,460,1460,6460,120,121,'MOAAAA','JNBAAA','VVVVxx'
+9296,1024,0,0,6,16,96,296,1296,4296,9296,192,193,'OTAAAA','KNBAAA','AAAAxx'
+3486,1025,0,2,6,6,86,486,1486,3486,3486,172,173,'CEAAAA','LNBAAA','HHHHxx'
+5664,1026,0,0,4,4,64,664,1664,664,5664,128,129,'WJAAAA','MNBAAA','OOOOxx'
+7624,1027,0,0,4,4,24,624,1624,2624,7624,48,49,'GHAAAA','NNBAAA','VVVVxx'
+2790,1028,0,2,0,10,90,790,790,2790,2790,180,181,'IDAAAA','ONBAAA','AAAAxx'
+682,1029,0,2,2,2,82,682,682,682,682,164,165,'GAAAAA','PNBAAA','HHHHxx'
+6412,1030,0,0,2,12,12,412,412,1412,6412,24,25,'QMAAAA','QNBAAA','OOOOxx'
+6882,1031,0,2,2,2,82,882,882,1882,6882,164,165,'SEAAAA','RNBAAA','VVVVxx'
+1332,1032,0,0,2,12,32,332,1332,1332,1332,64,65,'GZAAAA','SNBAAA','AAAAxx'
+4911,1033,1,3,1,11,11,911,911,4911,4911,22,23,'XGAAAA','TNBAAA','HHHHxx'
+3528,1034,0,0,8,8,28,528,1528,3528,3528,56,57,'SFAAAA','UNBAAA','OOOOxx'
+271,1035,1,3,1,11,71,271,271,271,271,142,143,'LKAAAA','VNBAAA','VVVVxx'
+7007,1036,1,3,7,7,7,7,1007,2007,7007,14,15,'NJAAAA','WNBAAA','AAAAxx'
+2198,1037,0,2,8,18,98,198,198,2198,2198,196,197,'OGAAAA','XNBAAA','HHHHxx'
+4266,1038,0,2,6,6,66,266,266,4266,4266,132,133,'CIAAAA','YNBAAA','OOOOxx'
+9867,1039,1,3,7,7,67,867,1867,4867,9867,134,135,'NPAAAA','ZNBAAA','VVVVxx'
+7602,1040,0,2,2,2,2,602,1602,2602,7602,4,5,'KGAAAA','AOBAAA','AAAAxx'
+7521,1041,1,1,1,1,21,521,1521,2521,7521,42,43,'HDAAAA','BOBAAA','HHHHxx'
+7200,1042,0,0,0,0,0,200,1200,2200,7200,0,1,'YQAAAA','COBAAA','OOOOxx'
+4816,1043,0,0,6,16,16,816,816,4816,4816,32,33,'GDAAAA','DOBAAA','VVVVxx'
+1669,1044,1,1,9,9,69,669,1669,1669,1669,138,139,'FMAAAA','EOBAAA','AAAAxx'
+4764,1045,0,0,4,4,64,764,764,4764,4764,128,129,'GBAAAA','FOBAAA','HHHHxx'
+7393,1046,1,1,3,13,93,393,1393,2393,7393,186,187,'JYAAAA','GOBAAA','OOOOxx'
+7434,1047,0,2,4,14,34,434,1434,2434,7434,68,69,'YZAAAA','HOBAAA','VVVVxx'
+9079,1048,1,3,9,19,79,79,1079,4079,9079,158,159,'FLAAAA','IOBAAA','AAAAxx'
+9668,1049,0,0,8,8,68,668,1668,4668,9668,136,137,'WHAAAA','JOBAAA','HHHHxx'
+7184,1050,0,0,4,4,84,184,1184,2184,7184,168,169,'IQAAAA','KOBAAA','OOOOxx'
+7347,1051,1,3,7,7,47,347,1347,2347,7347,94,95,'PWAAAA','LOBAAA','VVVVxx'
+951,1052,1,3,1,11,51,951,951,951,951,102,103,'PKAAAA','MOBAAA','AAAAxx'
+4513,1053,1,1,3,13,13,513,513,4513,4513,26,27,'PRAAAA','NOBAAA','HHHHxx'
+2692,1054,0,0,2,12,92,692,692,2692,2692,184,185,'OZAAAA','OOBAAA','OOOOxx'
+9930,1055,0,2,0,10,30,930,1930,4930,9930,60,61,'YRAAAA','POBAAA','VVVVxx'
+4516,1056,0,0,6,16,16,516,516,4516,4516,32,33,'SRAAAA','QOBAAA','AAAAxx'
+1592,1057,0,0,2,12,92,592,1592,1592,1592,184,185,'GJAAAA','ROBAAA','HHHHxx'
+6312,1058,0,0,2,12,12,312,312,1312,6312,24,25,'UIAAAA','SOBAAA','OOOOxx'
+185,1059,1,1,5,5,85,185,185,185,185,170,171,'DHAAAA','TOBAAA','VVVVxx'
+1848,1060,0,0,8,8,48,848,1848,1848,1848,96,97,'CTAAAA','UOBAAA','AAAAxx'
+5844,1061,0,0,4,4,44,844,1844,844,5844,88,89,'UQAAAA','VOBAAA','HHHHxx'
+1666,1062,0,2,6,6,66,666,1666,1666,1666,132,133,'CMAAAA','WOBAAA','OOOOxx'
+5864,1063,0,0,4,4,64,864,1864,864,5864,128,129,'ORAAAA','XOBAAA','VVVVxx'
+1004,1064,0,0,4,4,4,4,1004,1004,1004,8,9,'QMAAAA','YOBAAA','AAAAxx'
+1758,1065,0,2,8,18,58,758,1758,1758,1758,116,117,'QPAAAA','ZOBAAA','HHHHxx'
+8823,1066,1,3,3,3,23,823,823,3823,8823,46,47,'JBAAAA','APBAAA','OOOOxx'
+129,1067,1,1,9,9,29,129,129,129,129,58,59,'ZEAAAA','BPBAAA','VVVVxx'
+5703,1068,1,3,3,3,3,703,1703,703,5703,6,7,'JLAAAA','CPBAAA','AAAAxx'
+3331,1069,1,3,1,11,31,331,1331,3331,3331,62,63,'DYAAAA','DPBAAA','HHHHxx'
+5791,1070,1,3,1,11,91,791,1791,791,5791,182,183,'TOAAAA','EPBAAA','OOOOxx'
+4421,1071,1,1,1,1,21,421,421,4421,4421,42,43,'BOAAAA','FPBAAA','VVVVxx'
+9740,1072,0,0,0,0,40,740,1740,4740,9740,80,81,'QKAAAA','GPBAAA','AAAAxx'
+798,1073,0,2,8,18,98,798,798,798,798,196,197,'SEAAAA','HPBAAA','HHHHxx'
+571,1074,1,3,1,11,71,571,571,571,571,142,143,'ZVAAAA','IPBAAA','OOOOxx'
+7084,1075,0,0,4,4,84,84,1084,2084,7084,168,169,'MMAAAA','JPBAAA','VVVVxx'
+650,1076,0,2,0,10,50,650,650,650,650,100,101,'AZAAAA','KPBAAA','AAAAxx'
+1467,1077,1,3,7,7,67,467,1467,1467,1467,134,135,'LEAAAA','LPBAAA','HHHHxx'
+5446,1078,0,2,6,6,46,446,1446,446,5446,92,93,'MBAAAA','MPBAAA','OOOOxx'
+830,1079,0,2,0,10,30,830,830,830,830,60,61,'YFAAAA','NPBAAA','VVVVxx'
+5516,1080,0,0,6,16,16,516,1516,516,5516,32,33,'EEAAAA','OPBAAA','AAAAxx'
+8520,1081,0,0,0,0,20,520,520,3520,8520,40,41,'SPAAAA','PPBAAA','HHHHxx'
+1152,1082,0,0,2,12,52,152,1152,1152,1152,104,105,'ISAAAA','QPBAAA','OOOOxx'
+862,1083,0,2,2,2,62,862,862,862,862,124,125,'EHAAAA','RPBAAA','VVVVxx'
+454,1084,0,2,4,14,54,454,454,454,454,108,109,'MRAAAA','SPBAAA','AAAAxx'
+9956,1085,0,0,6,16,56,956,1956,4956,9956,112,113,'YSAAAA','TPBAAA','HHHHxx'
+1654,1086,0,2,4,14,54,654,1654,1654,1654,108,109,'QLAAAA','UPBAAA','OOOOxx'
+257,1087,1,1,7,17,57,257,257,257,257,114,115,'XJAAAA','VPBAAA','VVVVxx'
+5469,1088,1,1,9,9,69,469,1469,469,5469,138,139,'JCAAAA','WPBAAA','AAAAxx'
+9075,1089,1,3,5,15,75,75,1075,4075,9075,150,151,'BLAAAA','XPBAAA','HHHHxx'
+7799,1090,1,3,9,19,99,799,1799,2799,7799,198,199,'ZNAAAA','YPBAAA','OOOOxx'
+2001,1091,1,1,1,1,1,1,1,2001,2001,2,3,'ZYAAAA','ZPBAAA','VVVVxx'
+9786,1092,0,2,6,6,86,786,1786,4786,9786,172,173,'KMAAAA','AQBAAA','AAAAxx'
+7281,1093,1,1,1,1,81,281,1281,2281,7281,162,163,'BUAAAA','BQBAAA','HHHHxx'
+5137,1094,1,1,7,17,37,137,1137,137,5137,74,75,'PPAAAA','CQBAAA','OOOOxx'
+4053,1095,1,1,3,13,53,53,53,4053,4053,106,107,'XZAAAA','DQBAAA','VVVVxx'
+7911,1096,1,3,1,11,11,911,1911,2911,7911,22,23,'HSAAAA','EQBAAA','AAAAxx'
+4298,1097,0,2,8,18,98,298,298,4298,4298,196,197,'IJAAAA','FQBAAA','HHHHxx'
+4805,1098,1,1,5,5,5,805,805,4805,4805,10,11,'VCAAAA','GQBAAA','OOOOxx'
+9038,1099,0,2,8,18,38,38,1038,4038,9038,76,77,'QJAAAA','HQBAAA','VVVVxx'
+8023,1100,1,3,3,3,23,23,23,3023,8023,46,47,'PWAAAA','IQBAAA','AAAAxx'
+6595,1101,1,3,5,15,95,595,595,1595,6595,190,191,'RTAAAA','JQBAAA','HHHHxx'
+9831,1102,1,3,1,11,31,831,1831,4831,9831,62,63,'DOAAAA','KQBAAA','OOOOxx'
+788,1103,0,0,8,8,88,788,788,788,788,176,177,'IEAAAA','LQBAAA','VVVVxx'
+902,1104,0,2,2,2,2,902,902,902,902,4,5,'SIAAAA','MQBAAA','AAAAxx'
+9137,1105,1,1,7,17,37,137,1137,4137,9137,74,75,'LNAAAA','NQBAAA','HHHHxx'
+1744,1106,0,0,4,4,44,744,1744,1744,1744,88,89,'CPAAAA','OQBAAA','OOOOxx'
+7285,1107,1,1,5,5,85,285,1285,2285,7285,170,171,'FUAAAA','PQBAAA','VVVVxx'
+7006,1108,0,2,6,6,6,6,1006,2006,7006,12,13,'MJAAAA','QQBAAA','AAAAxx'
+9236,1109,0,0,6,16,36,236,1236,4236,9236,72,73,'GRAAAA','RQBAAA','HHHHxx'
+5472,1110,0,0,2,12,72,472,1472,472,5472,144,145,'MCAAAA','SQBAAA','OOOOxx'
+7975,1111,1,3,5,15,75,975,1975,2975,7975,150,151,'TUAAAA','TQBAAA','VVVVxx'
+4181,1112,1,1,1,1,81,181,181,4181,4181,162,163,'VEAAAA','UQBAAA','AAAAxx'
+7677,1113,1,1,7,17,77,677,1677,2677,7677,154,155,'HJAAAA','VQBAAA','HHHHxx'
+35,1114,1,3,5,15,35,35,35,35,35,70,71,'JBAAAA','WQBAAA','OOOOxx'
+6813,1115,1,1,3,13,13,813,813,1813,6813,26,27,'BCAAAA','XQBAAA','VVVVxx'
+6618,1116,0,2,8,18,18,618,618,1618,6618,36,37,'OUAAAA','YQBAAA','AAAAxx'
+8069,1117,1,1,9,9,69,69,69,3069,8069,138,139,'JYAAAA','ZQBAAA','HHHHxx'
+3071,1118,1,3,1,11,71,71,1071,3071,3071,142,143,'DOAAAA','ARBAAA','OOOOxx'
+4390,1119,0,2,0,10,90,390,390,4390,4390,180,181,'WMAAAA','BRBAAA','VVVVxx'
+7764,1120,0,0,4,4,64,764,1764,2764,7764,128,129,'QMAAAA','CRBAAA','AAAAxx'
+8163,1121,1,3,3,3,63,163,163,3163,8163,126,127,'ZBAAAA','DRBAAA','HHHHxx'
+1961,1122,1,1,1,1,61,961,1961,1961,1961,122,123,'LXAAAA','ERBAAA','OOOOxx'
+1103,1123,1,3,3,3,3,103,1103,1103,1103,6,7,'LQAAAA','FRBAAA','VVVVxx'
+5486,1124,0,2,6,6,86,486,1486,486,5486,172,173,'ADAAAA','GRBAAA','AAAAxx'
+9513,1125,1,1,3,13,13,513,1513,4513,9513,26,27,'XBAAAA','HRBAAA','HHHHxx'
+7311,1126,1,3,1,11,11,311,1311,2311,7311,22,23,'FVAAAA','IRBAAA','OOOOxx'
+4144,1127,0,0,4,4,44,144,144,4144,4144,88,89,'KDAAAA','JRBAAA','VVVVxx'
+7901,1128,1,1,1,1,1,901,1901,2901,7901,2,3,'XRAAAA','KRBAAA','AAAAxx'
+4629,1129,1,1,9,9,29,629,629,4629,4629,58,59,'BWAAAA','LRBAAA','HHHHxx'
+6858,1130,0,2,8,18,58,858,858,1858,6858,116,117,'UDAAAA','MRBAAA','OOOOxx'
+125,1131,1,1,5,5,25,125,125,125,125,50,51,'VEAAAA','NRBAAA','VVVVxx'
+3834,1132,0,2,4,14,34,834,1834,3834,3834,68,69,'MRAAAA','ORBAAA','AAAAxx'
+8155,1133,1,3,5,15,55,155,155,3155,8155,110,111,'RBAAAA','PRBAAA','HHHHxx'
+8230,1134,0,2,0,10,30,230,230,3230,8230,60,61,'OEAAAA','QRBAAA','OOOOxx'
+744,1135,0,0,4,4,44,744,744,744,744,88,89,'QCAAAA','RRBAAA','VVVVxx'
+357,1136,1,1,7,17,57,357,357,357,357,114,115,'TNAAAA','SRBAAA','AAAAxx'
+2159,1137,1,3,9,19,59,159,159,2159,2159,118,119,'BFAAAA','TRBAAA','HHHHxx'
+8559,1138,1,3,9,19,59,559,559,3559,8559,118,119,'FRAAAA','URBAAA','OOOOxx'
+6866,1139,0,2,6,6,66,866,866,1866,6866,132,133,'CEAAAA','VRBAAA','VVVVxx'
+3863,1140,1,3,3,3,63,863,1863,3863,3863,126,127,'PSAAAA','WRBAAA','AAAAxx'
+4193,1141,1,1,3,13,93,193,193,4193,4193,186,187,'HFAAAA','XRBAAA','HHHHxx'
+3277,1142,1,1,7,17,77,277,1277,3277,3277,154,155,'BWAAAA','YRBAAA','OOOOxx'
+5577,1143,1,1,7,17,77,577,1577,577,5577,154,155,'NGAAAA','ZRBAAA','VVVVxx'
+9503,1144,1,3,3,3,3,503,1503,4503,9503,6,7,'NBAAAA','ASBAAA','AAAAxx'
+7642,1145,0,2,2,2,42,642,1642,2642,7642,84,85,'YHAAAA','BSBAAA','HHHHxx'
+6197,1146,1,1,7,17,97,197,197,1197,6197,194,195,'JEAAAA','CSBAAA','OOOOxx'
+8995,1147,1,3,5,15,95,995,995,3995,8995,190,191,'ZHAAAA','DSBAAA','VVVVxx'
+440,1148,0,0,0,0,40,440,440,440,440,80,81,'YQAAAA','ESBAAA','AAAAxx'
+8418,1149,0,2,8,18,18,418,418,3418,8418,36,37,'ULAAAA','FSBAAA','HHHHxx'
+8531,1150,1,3,1,11,31,531,531,3531,8531,62,63,'DQAAAA','GSBAAA','OOOOxx'
+3790,1151,0,2,0,10,90,790,1790,3790,3790,180,181,'UPAAAA','HSBAAA','VVVVxx'
+7610,1152,0,2,0,10,10,610,1610,2610,7610,20,21,'SGAAAA','ISBAAA','AAAAxx'
+1252,1153,0,0,2,12,52,252,1252,1252,1252,104,105,'EWAAAA','JSBAAA','HHHHxx'
+7559,1154,1,3,9,19,59,559,1559,2559,7559,118,119,'TEAAAA','KSBAAA','OOOOxx'
+9945,1155,1,1,5,5,45,945,1945,4945,9945,90,91,'NSAAAA','LSBAAA','VVVVxx'
+9023,1156,1,3,3,3,23,23,1023,4023,9023,46,47,'BJAAAA','MSBAAA','AAAAxx'
+3516,1157,0,0,6,16,16,516,1516,3516,3516,32,33,'GFAAAA','NSBAAA','HHHHxx'
+4671,1158,1,3,1,11,71,671,671,4671,4671,142,143,'RXAAAA','OSBAAA','OOOOxx'
+1465,1159,1,1,5,5,65,465,1465,1465,1465,130,131,'JEAAAA','PSBAAA','VVVVxx'
+9515,1160,1,3,5,15,15,515,1515,4515,9515,30,31,'ZBAAAA','QSBAAA','AAAAxx'
+3242,1161,0,2,2,2,42,242,1242,3242,3242,84,85,'SUAAAA','RSBAAA','HHHHxx'
+1732,1162,0,0,2,12,32,732,1732,1732,1732,64,65,'QOAAAA','SSBAAA','OOOOxx'
+1678,1163,0,2,8,18,78,678,1678,1678,1678,156,157,'OMAAAA','TSBAAA','VVVVxx'
+1464,1164,0,0,4,4,64,464,1464,1464,1464,128,129,'IEAAAA','USBAAA','AAAAxx'
+6546,1165,0,2,6,6,46,546,546,1546,6546,92,93,'URAAAA','VSBAAA','HHHHxx'
+4448,1166,0,0,8,8,48,448,448,4448,4448,96,97,'CPAAAA','WSBAAA','OOOOxx'
+9847,1167,1,3,7,7,47,847,1847,4847,9847,94,95,'TOAAAA','XSBAAA','VVVVxx'
+8264,1168,0,0,4,4,64,264,264,3264,8264,128,129,'WFAAAA','YSBAAA','AAAAxx'
+1620,1169,0,0,0,0,20,620,1620,1620,1620,40,41,'IKAAAA','ZSBAAA','HHHHxx'
+9388,1170,0,0,8,8,88,388,1388,4388,9388,176,177,'CXAAAA','ATBAAA','OOOOxx'
+6445,1171,1,1,5,5,45,445,445,1445,6445,90,91,'XNAAAA','BTBAAA','VVVVxx'
+4789,1172,1,1,9,9,89,789,789,4789,4789,178,179,'FCAAAA','CTBAAA','AAAAxx'
+1562,1173,0,2,2,2,62,562,1562,1562,1562,124,125,'CIAAAA','DTBAAA','HHHHxx'
+7305,1174,1,1,5,5,5,305,1305,2305,7305,10,11,'ZUAAAA','ETBAAA','OOOOxx'
+6344,1175,0,0,4,4,44,344,344,1344,6344,88,89,'AKAAAA','FTBAAA','VVVVxx'
+5130,1176,0,2,0,10,30,130,1130,130,5130,60,61,'IPAAAA','GTBAAA','AAAAxx'
+3284,1177,0,0,4,4,84,284,1284,3284,3284,168,169,'IWAAAA','HTBAAA','HHHHxx'
+6346,1178,0,2,6,6,46,346,346,1346,6346,92,93,'CKAAAA','ITBAAA','OOOOxx'
+1061,1179,1,1,1,1,61,61,1061,1061,1061,122,123,'VOAAAA','JTBAAA','VVVVxx'
+872,1180,0,0,2,12,72,872,872,872,872,144,145,'OHAAAA','KTBAAA','AAAAxx'
+123,1181,1,3,3,3,23,123,123,123,123,46,47,'TEAAAA','LTBAAA','HHHHxx'
+7903,1182,1,3,3,3,3,903,1903,2903,7903,6,7,'ZRAAAA','MTBAAA','OOOOxx'
+560,1183,0,0,0,0,60,560,560,560,560,120,121,'OVAAAA','NTBAAA','VVVVxx'
+4446,1184,0,2,6,6,46,446,446,4446,4446,92,93,'APAAAA','OTBAAA','AAAAxx'
+3909,1185,1,1,9,9,9,909,1909,3909,3909,18,19,'JUAAAA','PTBAAA','HHHHxx'
+669,1186,1,1,9,9,69,669,669,669,669,138,139,'TZAAAA','QTBAAA','OOOOxx'
+7843,1187,1,3,3,3,43,843,1843,2843,7843,86,87,'RPAAAA','RTBAAA','VVVVxx'
+2546,1188,0,2,6,6,46,546,546,2546,2546,92,93,'YTAAAA','STBAAA','AAAAxx'
+6757,1189,1,1,7,17,57,757,757,1757,6757,114,115,'XZAAAA','TTBAAA','HHHHxx'
+466,1190,0,2,6,6,66,466,466,466,466,132,133,'YRAAAA','UTBAAA','OOOOxx'
+5556,1191,0,0,6,16,56,556,1556,556,5556,112,113,'SFAAAA','VTBAAA','VVVVxx'
+7196,1192,0,0,6,16,96,196,1196,2196,7196,192,193,'UQAAAA','WTBAAA','AAAAxx'
+2947,1193,1,3,7,7,47,947,947,2947,2947,94,95,'JJAAAA','XTBAAA','HHHHxx'
+6493,1194,1,1,3,13,93,493,493,1493,6493,186,187,'TPAAAA','YTBAAA','OOOOxx'
+7203,1195,1,3,3,3,3,203,1203,2203,7203,6,7,'BRAAAA','ZTBAAA','VVVVxx'
+3716,1196,0,0,6,16,16,716,1716,3716,3716,32,33,'YMAAAA','AUBAAA','AAAAxx'
+8058,1197,0,2,8,18,58,58,58,3058,8058,116,117,'YXAAAA','BUBAAA','HHHHxx'
+433,1198,1,1,3,13,33,433,433,433,433,66,67,'RQAAAA','CUBAAA','OOOOxx'
+7649,1199,1,1,9,9,49,649,1649,2649,7649,98,99,'FIAAAA','DUBAAA','VVVVxx'
+6966,1200,0,2,6,6,66,966,966,1966,6966,132,133,'YHAAAA','EUBAAA','AAAAxx'
+553,1201,1,1,3,13,53,553,553,553,553,106,107,'HVAAAA','FUBAAA','HHHHxx'
+3677,1202,1,1,7,17,77,677,1677,3677,3677,154,155,'LLAAAA','GUBAAA','OOOOxx'
+2344,1203,0,0,4,4,44,344,344,2344,2344,88,89,'EMAAAA','HUBAAA','VVVVxx'
+7439,1204,1,3,9,19,39,439,1439,2439,7439,78,79,'DAAAAA','IUBAAA','AAAAxx'
+3910,1205,0,2,0,10,10,910,1910,3910,3910,20,21,'KUAAAA','JUBAAA','HHHHxx'
+3638,1206,0,2,8,18,38,638,1638,3638,3638,76,77,'YJAAAA','KUBAAA','OOOOxx'
+6637,1207,1,1,7,17,37,637,637,1637,6637,74,75,'HVAAAA','LUBAAA','VVVVxx'
+4438,1208,0,2,8,18,38,438,438,4438,4438,76,77,'SOAAAA','MUBAAA','AAAAxx'
+171,1209,1,3,1,11,71,171,171,171,171,142,143,'PGAAAA','NUBAAA','HHHHxx'
+310,1210,0,2,0,10,10,310,310,310,310,20,21,'YLAAAA','OUBAAA','OOOOxx'
+2714,1211,0,2,4,14,14,714,714,2714,2714,28,29,'KAAAAA','PUBAAA','VVVVxx'
+5199,1212,1,3,9,19,99,199,1199,199,5199,198,199,'ZRAAAA','QUBAAA','AAAAxx'
+8005,1213,1,1,5,5,5,5,5,3005,8005,10,11,'XVAAAA','RUBAAA','HHHHxx'
+3188,1214,0,0,8,8,88,188,1188,3188,3188,176,177,'QSAAAA','SUBAAA','OOOOxx'
+1518,1215,0,2,8,18,18,518,1518,1518,1518,36,37,'KGAAAA','TUBAAA','VVVVxx'
+6760,1216,0,0,0,0,60,760,760,1760,6760,120,121,'AAAAAA','UUBAAA','AAAAxx'
+9373,1217,1,1,3,13,73,373,1373,4373,9373,146,147,'NWAAAA','VUBAAA','HHHHxx'
+1938,1218,0,2,8,18,38,938,1938,1938,1938,76,77,'OWAAAA','WUBAAA','OOOOxx'
+2865,1219,1,1,5,5,65,865,865,2865,2865,130,131,'FGAAAA','XUBAAA','VVVVxx'
+3203,1220,1,3,3,3,3,203,1203,3203,3203,6,7,'FTAAAA','YUBAAA','AAAAxx'
+6025,1221,1,1,5,5,25,25,25,1025,6025,50,51,'TXAAAA','ZUBAAA','HHHHxx'
+8684,1222,0,0,4,4,84,684,684,3684,8684,168,169,'AWAAAA','AVBAAA','OOOOxx'
+7732,1223,0,0,2,12,32,732,1732,2732,7732,64,65,'KLAAAA','BVBAAA','VVVVxx'
+3218,1224,0,2,8,18,18,218,1218,3218,3218,36,37,'UTAAAA','CVBAAA','AAAAxx'
+525,1225,1,1,5,5,25,525,525,525,525,50,51,'FUAAAA','DVBAAA','HHHHxx'
+601,1226,1,1,1,1,1,601,601,601,601,2,3,'DXAAAA','EVBAAA','OOOOxx'
+6091,1227,1,3,1,11,91,91,91,1091,6091,182,183,'HAAAAA','FVBAAA','VVVVxx'
+4498,1228,0,2,8,18,98,498,498,4498,4498,196,197,'ARAAAA','GVBAAA','AAAAxx'
+8192,1229,0,0,2,12,92,192,192,3192,8192,184,185,'CDAAAA','HVBAAA','HHHHxx'
+8006,1230,0,2,6,6,6,6,6,3006,8006,12,13,'YVAAAA','IVBAAA','OOOOxx'
+6157,1231,1,1,7,17,57,157,157,1157,6157,114,115,'VCAAAA','JVBAAA','VVVVxx'
+312,1232,0,0,2,12,12,312,312,312,312,24,25,'AMAAAA','KVBAAA','AAAAxx'
+8652,1233,0,0,2,12,52,652,652,3652,8652,104,105,'UUAAAA','LVBAAA','HHHHxx'
+2787,1234,1,3,7,7,87,787,787,2787,2787,174,175,'FDAAAA','MVBAAA','OOOOxx'
+1782,1235,0,2,2,2,82,782,1782,1782,1782,164,165,'OQAAAA','NVBAAA','VVVVxx'
+23,1236,1,3,3,3,23,23,23,23,23,46,47,'XAAAAA','OVBAAA','AAAAxx'
+1206,1237,0,2,6,6,6,206,1206,1206,1206,12,13,'KUAAAA','PVBAAA','HHHHxx'
+1076,1238,0,0,6,16,76,76,1076,1076,1076,152,153,'KPAAAA','QVBAAA','OOOOxx'
+5379,1239,1,3,9,19,79,379,1379,379,5379,158,159,'XYAAAA','RVBAAA','VVVVxx'
+2047,1240,1,3,7,7,47,47,47,2047,2047,94,95,'TAAAAA','SVBAAA','AAAAxx'
+6262,1241,0,2,2,2,62,262,262,1262,6262,124,125,'WGAAAA','TVBAAA','HHHHxx'
+1840,1242,0,0,0,0,40,840,1840,1840,1840,80,81,'USAAAA','UVBAAA','OOOOxx'
+2106,1243,0,2,6,6,6,106,106,2106,2106,12,13,'ADAAAA','VVBAAA','VVVVxx'
+1307,1244,1,3,7,7,7,307,1307,1307,1307,14,15,'HYAAAA','WVBAAA','AAAAxx'
+735,1245,1,3,5,15,35,735,735,735,735,70,71,'HCAAAA','XVBAAA','HHHHxx'
+3657,1246,1,1,7,17,57,657,1657,3657,3657,114,115,'RKAAAA','YVBAAA','OOOOxx'
+3006,1247,0,2,6,6,6,6,1006,3006,3006,12,13,'QLAAAA','ZVBAAA','VVVVxx'
+1538,1248,0,2,8,18,38,538,1538,1538,1538,76,77,'EHAAAA','AWBAAA','AAAAxx'
+6098,1249,0,2,8,18,98,98,98,1098,6098,196,197,'OAAAAA','BWBAAA','HHHHxx'
+5267,1250,1,3,7,7,67,267,1267,267,5267,134,135,'PUAAAA','CWBAAA','OOOOxx'
+9757,1251,1,1,7,17,57,757,1757,4757,9757,114,115,'HLAAAA','DWBAAA','VVVVxx'
+1236,1252,0,0,6,16,36,236,1236,1236,1236,72,73,'OVAAAA','EWBAAA','AAAAxx'
+83,1253,1,3,3,3,83,83,83,83,83,166,167,'FDAAAA','FWBAAA','HHHHxx'
+9227,1254,1,3,7,7,27,227,1227,4227,9227,54,55,'XQAAAA','GWBAAA','OOOOxx'
+8772,1255,0,0,2,12,72,772,772,3772,8772,144,145,'KZAAAA','HWBAAA','VVVVxx'
+8822,1256,0,2,2,2,22,822,822,3822,8822,44,45,'IBAAAA','IWBAAA','AAAAxx'
+7167,1257,1,3,7,7,67,167,1167,2167,7167,134,135,'RPAAAA','JWBAAA','HHHHxx'
+6909,1258,1,1,9,9,9,909,909,1909,6909,18,19,'TFAAAA','KWBAAA','OOOOxx'
+1439,1259,1,3,9,19,39,439,1439,1439,1439,78,79,'JDAAAA','LWBAAA','VVVVxx'
+2370,1260,0,2,0,10,70,370,370,2370,2370,140,141,'ENAAAA','MWBAAA','AAAAxx'
+4577,1261,1,1,7,17,77,577,577,4577,4577,154,155,'BUAAAA','NWBAAA','HHHHxx'
+2575,1262,1,3,5,15,75,575,575,2575,2575,150,151,'BVAAAA','OWBAAA','OOOOxx'
+2795,1263,1,3,5,15,95,795,795,2795,2795,190,191,'NDAAAA','PWBAAA','VVVVxx'
+5520,1264,0,0,0,0,20,520,1520,520,5520,40,41,'IEAAAA','QWBAAA','AAAAxx'
+382,1265,0,2,2,2,82,382,382,382,382,164,165,'SOAAAA','RWBAAA','HHHHxx'
+6335,1266,1,3,5,15,35,335,335,1335,6335,70,71,'RJAAAA','SWBAAA','OOOOxx'
+8430,1267,0,2,0,10,30,430,430,3430,8430,60,61,'GMAAAA','TWBAAA','VVVVxx'
+4131,1268,1,3,1,11,31,131,131,4131,4131,62,63,'XCAAAA','UWBAAA','AAAAxx'
+9332,1269,0,0,2,12,32,332,1332,4332,9332,64,65,'YUAAAA','VWBAAA','HHHHxx'
+293,1270,1,1,3,13,93,293,293,293,293,186,187,'HLAAAA','WWBAAA','OOOOxx'
+2276,1271,0,0,6,16,76,276,276,2276,2276,152,153,'OJAAAA','XWBAAA','VVVVxx'
+5687,1272,1,3,7,7,87,687,1687,687,5687,174,175,'TKAAAA','YWBAAA','AAAAxx'
+5862,1273,0,2,2,2,62,862,1862,862,5862,124,125,'MRAAAA','ZWBAAA','HHHHxx'
+5073,1274,1,1,3,13,73,73,1073,73,5073,146,147,'DNAAAA','AXBAAA','OOOOxx'
+4170,1275,0,2,0,10,70,170,170,4170,4170,140,141,'KEAAAA','BXBAAA','VVVVxx'
+5039,1276,1,3,9,19,39,39,1039,39,5039,78,79,'VLAAAA','CXBAAA','AAAAxx'
+3294,1277,0,2,4,14,94,294,1294,3294,3294,188,189,'SWAAAA','DXBAAA','HHHHxx'
+6015,1278,1,3,5,15,15,15,15,1015,6015,30,31,'JXAAAA','EXBAAA','OOOOxx'
+9015,1279,1,3,5,15,15,15,1015,4015,9015,30,31,'TIAAAA','FXBAAA','VVVVxx'
+9785,1280,1,1,5,5,85,785,1785,4785,9785,170,171,'JMAAAA','GXBAAA','AAAAxx'
+4312,1281,0,0,2,12,12,312,312,4312,4312,24,25,'WJAAAA','HXBAAA','HHHHxx'
+6343,1282,1,3,3,3,43,343,343,1343,6343,86,87,'ZJAAAA','IXBAAA','OOOOxx'
+2161,1283,1,1,1,1,61,161,161,2161,2161,122,123,'DFAAAA','JXBAAA','VVVVxx'
+4490,1284,0,2,0,10,90,490,490,4490,4490,180,181,'SQAAAA','KXBAAA','AAAAxx'
+4454,1285,0,2,4,14,54,454,454,4454,4454,108,109,'IPAAAA','LXBAAA','HHHHxx'
+7647,1286,1,3,7,7,47,647,1647,2647,7647,94,95,'DIAAAA','MXBAAA','OOOOxx'
+1028,1287,0,0,8,8,28,28,1028,1028,1028,56,57,'ONAAAA','NXBAAA','VVVVxx'
+2965,1288,1,1,5,5,65,965,965,2965,2965,130,131,'BKAAAA','OXBAAA','AAAAxx'
+9900,1289,0,0,0,0,0,900,1900,4900,9900,0,1,'UQAAAA','PXBAAA','HHHHxx'
+5509,1290,1,1,9,9,9,509,1509,509,5509,18,19,'XDAAAA','QXBAAA','OOOOxx'
+7751,1291,1,3,1,11,51,751,1751,2751,7751,102,103,'DMAAAA','RXBAAA','VVVVxx'
+9594,1292,0,2,4,14,94,594,1594,4594,9594,188,189,'AFAAAA','SXBAAA','AAAAxx'
+7632,1293,0,0,2,12,32,632,1632,2632,7632,64,65,'OHAAAA','TXBAAA','HHHHxx'
+6528,1294,0,0,8,8,28,528,528,1528,6528,56,57,'CRAAAA','UXBAAA','OOOOxx'
+1041,1295,1,1,1,1,41,41,1041,1041,1041,82,83,'BOAAAA','VXBAAA','VVVVxx'
+1534,1296,0,2,4,14,34,534,1534,1534,1534,68,69,'AHAAAA','WXBAAA','AAAAxx'
+4229,1297,1,1,9,9,29,229,229,4229,4229,58,59,'RGAAAA','XXBAAA','HHHHxx'
+84,1298,0,0,4,4,84,84,84,84,84,168,169,'GDAAAA','YXBAAA','OOOOxx'
+2189,1299,1,1,9,9,89,189,189,2189,2189,178,179,'FGAAAA','ZXBAAA','VVVVxx'
+7566,1300,0,2,6,6,66,566,1566,2566,7566,132,133,'AFAAAA','AYBAAA','AAAAxx'
+707,1301,1,3,7,7,7,707,707,707,707,14,15,'FBAAAA','BYBAAA','HHHHxx'
+581,1302,1,1,1,1,81,581,581,581,581,162,163,'JWAAAA','CYBAAA','OOOOxx'
+6753,1303,1,1,3,13,53,753,753,1753,6753,106,107,'TZAAAA','DYBAAA','VVVVxx'
+8604,1304,0,0,4,4,4,604,604,3604,8604,8,9,'YSAAAA','EYBAAA','AAAAxx'
+373,1305,1,1,3,13,73,373,373,373,373,146,147,'JOAAAA','FYBAAA','HHHHxx'
+9635,1306,1,3,5,15,35,635,1635,4635,9635,70,71,'PGAAAA','GYBAAA','OOOOxx'
+9277,1307,1,1,7,17,77,277,1277,4277,9277,154,155,'VSAAAA','HYBAAA','VVVVxx'
+7117,1308,1,1,7,17,17,117,1117,2117,7117,34,35,'TNAAAA','IYBAAA','AAAAxx'
+8564,1309,0,0,4,4,64,564,564,3564,8564,128,129,'KRAAAA','JYBAAA','HHHHxx'
+1697,1310,1,1,7,17,97,697,1697,1697,1697,194,195,'HNAAAA','KYBAAA','OOOOxx'
+7840,1311,0,0,0,0,40,840,1840,2840,7840,80,81,'OPAAAA','LYBAAA','VVVVxx'
+3646,1312,0,2,6,6,46,646,1646,3646,3646,92,93,'GKAAAA','MYBAAA','AAAAxx'
+368,1313,0,0,8,8,68,368,368,368,368,136,137,'EOAAAA','NYBAAA','HHHHxx'
+4797,1314,1,1,7,17,97,797,797,4797,4797,194,195,'NCAAAA','OYBAAA','OOOOxx'
+5300,1315,0,0,0,0,0,300,1300,300,5300,0,1,'WVAAAA','PYBAAA','VVVVxx'
+7664,1316,0,0,4,4,64,664,1664,2664,7664,128,129,'UIAAAA','QYBAAA','AAAAxx'
+1466,1317,0,2,6,6,66,466,1466,1466,1466,132,133,'KEAAAA','RYBAAA','HHHHxx'
+2477,1318,1,1,7,17,77,477,477,2477,2477,154,155,'HRAAAA','SYBAAA','OOOOxx'
+2036,1319,0,0,6,16,36,36,36,2036,2036,72,73,'IAAAAA','TYBAAA','VVVVxx'
+3624,1320,0,0,4,4,24,624,1624,3624,3624,48,49,'KJAAAA','UYBAAA','AAAAxx'
+5099,1321,1,3,9,19,99,99,1099,99,5099,198,199,'DOAAAA','VYBAAA','HHHHxx'
+1308,1322,0,0,8,8,8,308,1308,1308,1308,16,17,'IYAAAA','WYBAAA','OOOOxx'
+3704,1323,0,0,4,4,4,704,1704,3704,3704,8,9,'MMAAAA','XYBAAA','VVVVxx'
+2451,1324,1,3,1,11,51,451,451,2451,2451,102,103,'HQAAAA','YYBAAA','AAAAxx'
+4898,1325,0,2,8,18,98,898,898,4898,4898,196,197,'KGAAAA','ZYBAAA','HHHHxx'
+4959,1326,1,3,9,19,59,959,959,4959,4959,118,119,'TIAAAA','AZBAAA','OOOOxx'
+5942,1327,0,2,2,2,42,942,1942,942,5942,84,85,'OUAAAA','BZBAAA','VVVVxx'
+2425,1328,1,1,5,5,25,425,425,2425,2425,50,51,'HPAAAA','CZBAAA','AAAAxx'
+7760,1329,0,0,0,0,60,760,1760,2760,7760,120,121,'MMAAAA','DZBAAA','HHHHxx'
+6294,1330,0,2,4,14,94,294,294,1294,6294,188,189,'CIAAAA','EZBAAA','OOOOxx'
+6785,1331,1,1,5,5,85,785,785,1785,6785,170,171,'ZAAAAA','FZBAAA','VVVVxx'
+3542,1332,0,2,2,2,42,542,1542,3542,3542,84,85,'GGAAAA','GZBAAA','AAAAxx'
+1809,1333,1,1,9,9,9,809,1809,1809,1809,18,19,'PRAAAA','HZBAAA','HHHHxx'
+130,1334,0,2,0,10,30,130,130,130,130,60,61,'AFAAAA','IZBAAA','OOOOxx'
+8672,1335,0,0,2,12,72,672,672,3672,8672,144,145,'OVAAAA','JZBAAA','VVVVxx'
+2125,1336,1,1,5,5,25,125,125,2125,2125,50,51,'TDAAAA','KZBAAA','AAAAxx'
+7683,1337,1,3,3,3,83,683,1683,2683,7683,166,167,'NJAAAA','LZBAAA','HHHHxx'
+7842,1338,0,2,2,2,42,842,1842,2842,7842,84,85,'QPAAAA','MZBAAA','OOOOxx'
+9584,1339,0,0,4,4,84,584,1584,4584,9584,168,169,'QEAAAA','NZBAAA','VVVVxx'
+7963,1340,1,3,3,3,63,963,1963,2963,7963,126,127,'HUAAAA','OZBAAA','AAAAxx'
+8581,1341,1,1,1,1,81,581,581,3581,8581,162,163,'BSAAAA','PZBAAA','HHHHxx'
+2135,1342,1,3,5,15,35,135,135,2135,2135,70,71,'DEAAAA','QZBAAA','OOOOxx'
+7352,1343,0,0,2,12,52,352,1352,2352,7352,104,105,'UWAAAA','RZBAAA','VVVVxx'
+5789,1344,1,1,9,9,89,789,1789,789,5789,178,179,'ROAAAA','SZBAAA','AAAAxx'
+8490,1345,0,2,0,10,90,490,490,3490,8490,180,181,'OOAAAA','TZBAAA','HHHHxx'
+2145,1346,1,1,5,5,45,145,145,2145,2145,90,91,'NEAAAA','UZBAAA','OOOOxx'
+7021,1347,1,1,1,1,21,21,1021,2021,7021,42,43,'BKAAAA','VZBAAA','VVVVxx'
+3736,1348,0,0,6,16,36,736,1736,3736,3736,72,73,'SNAAAA','WZBAAA','AAAAxx'
+7396,1349,0,0,6,16,96,396,1396,2396,7396,192,193,'MYAAAA','XZBAAA','HHHHxx'
+6334,1350,0,2,4,14,34,334,334,1334,6334,68,69,'QJAAAA','YZBAAA','OOOOxx'
+5461,1351,1,1,1,1,61,461,1461,461,5461,122,123,'BCAAAA','ZZBAAA','VVVVxx'
+5337,1352,1,1,7,17,37,337,1337,337,5337,74,75,'HXAAAA','AACAAA','AAAAxx'
+7440,1353,0,0,0,0,40,440,1440,2440,7440,80,81,'EAAAAA','BACAAA','HHHHxx'
+6879,1354,1,3,9,19,79,879,879,1879,6879,158,159,'PEAAAA','CACAAA','OOOOxx'
+2432,1355,0,0,2,12,32,432,432,2432,2432,64,65,'OPAAAA','DACAAA','VVVVxx'
+8529,1356,1,1,9,9,29,529,529,3529,8529,58,59,'BQAAAA','EACAAA','AAAAxx'
+7859,1357,1,3,9,19,59,859,1859,2859,7859,118,119,'HQAAAA','FACAAA','HHHHxx'
+15,1358,1,3,5,15,15,15,15,15,15,30,31,'PAAAAA','GACAAA','OOOOxx'
+7475,1359,1,3,5,15,75,475,1475,2475,7475,150,151,'NBAAAA','HACAAA','VVVVxx'
+717,1360,1,1,7,17,17,717,717,717,717,34,35,'PBAAAA','IACAAA','AAAAxx'
+250,1361,0,2,0,10,50,250,250,250,250,100,101,'QJAAAA','JACAAA','HHHHxx'
+4700,1362,0,0,0,0,0,700,700,4700,4700,0,1,'UYAAAA','KACAAA','OOOOxx'
+7510,1363,0,2,0,10,10,510,1510,2510,7510,20,21,'WCAAAA','LACAAA','VVVVxx'
+4562,1364,0,2,2,2,62,562,562,4562,4562,124,125,'MTAAAA','MACAAA','AAAAxx'
+8075,1365,1,3,5,15,75,75,75,3075,8075,150,151,'PYAAAA','NACAAA','HHHHxx'
+871,1366,1,3,1,11,71,871,871,871,871,142,143,'NHAAAA','OACAAA','OOOOxx'
+7161,1367,1,1,1,1,61,161,1161,2161,7161,122,123,'LPAAAA','PACAAA','VVVVxx'
+9109,1368,1,1,9,9,9,109,1109,4109,9109,18,19,'JMAAAA','QACAAA','AAAAxx'
+8675,1369,1,3,5,15,75,675,675,3675,8675,150,151,'RVAAAA','RACAAA','HHHHxx'
+1025,1370,1,1,5,5,25,25,1025,1025,1025,50,51,'LNAAAA','SACAAA','OOOOxx'
+4065,1371,1,1,5,5,65,65,65,4065,4065,130,131,'JAAAAA','TACAAA','VVVVxx'
+3511,1372,1,3,1,11,11,511,1511,3511,3511,22,23,'BFAAAA','UACAAA','AAAAxx'
+9840,1373,0,0,0,0,40,840,1840,4840,9840,80,81,'MOAAAA','VACAAA','HHHHxx'
+7495,1374,1,3,5,15,95,495,1495,2495,7495,190,191,'HCAAAA','WACAAA','OOOOxx'
+55,1375,1,3,5,15,55,55,55,55,55,110,111,'DCAAAA','XACAAA','VVVVxx'
+6151,1376,1,3,1,11,51,151,151,1151,6151,102,103,'PCAAAA','YACAAA','AAAAxx'
+2512,1377,0,0,2,12,12,512,512,2512,2512,24,25,'QSAAAA','ZACAAA','HHHHxx'
+5881,1378,1,1,1,1,81,881,1881,881,5881,162,163,'FSAAAA','ABCAAA','OOOOxx'
+1442,1379,0,2,2,2,42,442,1442,1442,1442,84,85,'MDAAAA','BBCAAA','VVVVxx'
+1270,1380,0,2,0,10,70,270,1270,1270,1270,140,141,'WWAAAA','CBCAAA','AAAAxx'
+959,1381,1,3,9,19,59,959,959,959,959,118,119,'XKAAAA','DBCAAA','HHHHxx'
+8251,1382,1,3,1,11,51,251,251,3251,8251,102,103,'JFAAAA','EBCAAA','OOOOxx'
+3051,1383,1,3,1,11,51,51,1051,3051,3051,102,103,'JNAAAA','FBCAAA','VVVVxx'
+5052,1384,0,0,2,12,52,52,1052,52,5052,104,105,'IMAAAA','GBCAAA','AAAAxx'
+1863,1385,1,3,3,3,63,863,1863,1863,1863,126,127,'RTAAAA','HBCAAA','HHHHxx'
+344,1386,0,0,4,4,44,344,344,344,344,88,89,'GNAAAA','IBCAAA','OOOOxx'
+3590,1387,0,2,0,10,90,590,1590,3590,3590,180,181,'CIAAAA','JBCAAA','VVVVxx'
+4223,1388,1,3,3,3,23,223,223,4223,4223,46,47,'LGAAAA','KBCAAA','AAAAxx'
+2284,1389,0,0,4,4,84,284,284,2284,2284,168,169,'WJAAAA','LBCAAA','HHHHxx'
+9425,1390,1,1,5,5,25,425,1425,4425,9425,50,51,'NYAAAA','MBCAAA','OOOOxx'
+6221,1391,1,1,1,1,21,221,221,1221,6221,42,43,'HFAAAA','NBCAAA','VVVVxx'
+195,1392,1,3,5,15,95,195,195,195,195,190,191,'NHAAAA','OBCAAA','AAAAxx'
+1517,1393,1,1,7,17,17,517,1517,1517,1517,34,35,'JGAAAA','PBCAAA','HHHHxx'
+3791,1394,1,3,1,11,91,791,1791,3791,3791,182,183,'VPAAAA','QBCAAA','OOOOxx'
+572,1395,0,0,2,12,72,572,572,572,572,144,145,'AWAAAA','RBCAAA','VVVVxx'
+46,1396,0,2,6,6,46,46,46,46,46,92,93,'UBAAAA','SBCAAA','AAAAxx'
+9451,1397,1,3,1,11,51,451,1451,4451,9451,102,103,'NZAAAA','TBCAAA','HHHHxx'
+3359,1398,1,3,9,19,59,359,1359,3359,3359,118,119,'FZAAAA','UBCAAA','OOOOxx'
+8867,1399,1,3,7,7,67,867,867,3867,8867,134,135,'BDAAAA','VBCAAA','VVVVxx'
+674,1400,0,2,4,14,74,674,674,674,674,148,149,'YZAAAA','WBCAAA','AAAAxx'
+2674,1401,0,2,4,14,74,674,674,2674,2674,148,149,'WYAAAA','XBCAAA','HHHHxx'
+6523,1402,1,3,3,3,23,523,523,1523,6523,46,47,'XQAAAA','YBCAAA','OOOOxx'
+6210,1403,0,2,0,10,10,210,210,1210,6210,20,21,'WEAAAA','ZBCAAA','VVVVxx'
+7564,1404,0,0,4,4,64,564,1564,2564,7564,128,129,'YEAAAA','ACCAAA','AAAAxx'
+4776,1405,0,0,6,16,76,776,776,4776,4776,152,153,'SBAAAA','BCCAAA','HHHHxx'
+2993,1406,1,1,3,13,93,993,993,2993,2993,186,187,'DLAAAA','CCCAAA','OOOOxx'
+2969,1407,1,1,9,9,69,969,969,2969,2969,138,139,'FKAAAA','DCCAAA','VVVVxx'
+1762,1408,0,2,2,2,62,762,1762,1762,1762,124,125,'UPAAAA','ECCAAA','AAAAxx'
+685,1409,1,1,5,5,85,685,685,685,685,170,171,'JAAAAA','FCCAAA','HHHHxx'
+5312,1410,0,0,2,12,12,312,1312,312,5312,24,25,'IWAAAA','GCCAAA','OOOOxx'
+3264,1411,0,0,4,4,64,264,1264,3264,3264,128,129,'OVAAAA','HCCAAA','VVVVxx'
+7008,1412,0,0,8,8,8,8,1008,2008,7008,16,17,'OJAAAA','ICCAAA','AAAAxx'
+5167,1413,1,3,7,7,67,167,1167,167,5167,134,135,'TQAAAA','JCCAAA','HHHHxx'
+3060,1414,0,0,0,0,60,60,1060,3060,3060,120,121,'SNAAAA','KCCAAA','OOOOxx'
+1752,1415,0,0,2,12,52,752,1752,1752,1752,104,105,'KPAAAA','LCCAAA','VVVVxx'
+1016,1416,0,0,6,16,16,16,1016,1016,1016,32,33,'CNAAAA','MCCAAA','AAAAxx'
+7365,1417,1,1,5,5,65,365,1365,2365,7365,130,131,'HXAAAA','NCCAAA','HHHHxx'
+4358,1418,0,2,8,18,58,358,358,4358,4358,116,117,'QLAAAA','OCCAAA','OOOOxx'
+2819,1419,1,3,9,19,19,819,819,2819,2819,38,39,'LEAAAA','PCCAAA','VVVVxx'
+6727,1420,1,3,7,7,27,727,727,1727,6727,54,55,'TYAAAA','QCCAAA','AAAAxx'
+1459,1421,1,3,9,19,59,459,1459,1459,1459,118,119,'DEAAAA','RCCAAA','HHHHxx'
+1708,1422,0,0,8,8,8,708,1708,1708,1708,16,17,'SNAAAA','SCCAAA','OOOOxx'
+471,1423,1,3,1,11,71,471,471,471,471,142,143,'DSAAAA','TCCAAA','VVVVxx'
+387,1424,1,3,7,7,87,387,387,387,387,174,175,'XOAAAA','UCCAAA','AAAAxx'
+1166,1425,0,2,6,6,66,166,1166,1166,1166,132,133,'WSAAAA','VCCAAA','HHHHxx'
+2400,1426,0,0,0,0,0,400,400,2400,2400,0,1,'IOAAAA','WCCAAA','OOOOxx'
+3584,1427,0,0,4,4,84,584,1584,3584,3584,168,169,'WHAAAA','XCCAAA','VVVVxx'
+6423,1428,1,3,3,3,23,423,423,1423,6423,46,47,'BNAAAA','YCCAAA','AAAAxx'
+9520,1429,0,0,0,0,20,520,1520,4520,9520,40,41,'ECAAAA','ZCCAAA','HHHHxx'
+8080,1430,0,0,0,0,80,80,80,3080,8080,160,161,'UYAAAA','ADCAAA','OOOOxx'
+5709,1431,1,1,9,9,9,709,1709,709,5709,18,19,'PLAAAA','BDCAAA','VVVVxx'
+1131,1432,1,3,1,11,31,131,1131,1131,1131,62,63,'NRAAAA','CDCAAA','AAAAxx'
+8562,1433,0,2,2,2,62,562,562,3562,8562,124,125,'IRAAAA','DDCAAA','HHHHxx'
+5766,1434,0,2,6,6,66,766,1766,766,5766,132,133,'UNAAAA','EDCAAA','OOOOxx'
+245,1435,1,1,5,5,45,245,245,245,245,90,91,'LJAAAA','FDCAAA','VVVVxx'
+9869,1436,1,1,9,9,69,869,1869,4869,9869,138,139,'PPAAAA','GDCAAA','AAAAxx'
+3533,1437,1,1,3,13,33,533,1533,3533,3533,66,67,'XFAAAA','HDCAAA','HHHHxx'
+5109,1438,1,1,9,9,9,109,1109,109,5109,18,19,'NOAAAA','IDCAAA','OOOOxx'
+977,1439,1,1,7,17,77,977,977,977,977,154,155,'PLAAAA','JDCAAA','VVVVxx'
+1651,1440,1,3,1,11,51,651,1651,1651,1651,102,103,'NLAAAA','KDCAAA','AAAAxx'
+1357,1441,1,1,7,17,57,357,1357,1357,1357,114,115,'FAAAAA','LDCAAA','HHHHxx'
+9087,1442,1,3,7,7,87,87,1087,4087,9087,174,175,'NLAAAA','MDCAAA','OOOOxx'
+3399,1443,1,3,9,19,99,399,1399,3399,3399,198,199,'TAAAAA','NDCAAA','VVVVxx'
+7543,1444,1,3,3,3,43,543,1543,2543,7543,86,87,'DEAAAA','ODCAAA','AAAAxx'
+2469,1445,1,1,9,9,69,469,469,2469,2469,138,139,'ZQAAAA','PDCAAA','HHHHxx'
+8305,1446,1,1,5,5,5,305,305,3305,8305,10,11,'LHAAAA','QDCAAA','OOOOxx'
+3265,1447,1,1,5,5,65,265,1265,3265,3265,130,131,'PVAAAA','RDCAAA','VVVVxx'
+9977,1448,1,1,7,17,77,977,1977,4977,9977,154,155,'TTAAAA','SDCAAA','AAAAxx'
+3961,1449,1,1,1,1,61,961,1961,3961,3961,122,123,'JWAAAA','TDCAAA','HHHHxx'
+4952,1450,0,0,2,12,52,952,952,4952,4952,104,105,'MIAAAA','UDCAAA','OOOOxx'
+5173,1451,1,1,3,13,73,173,1173,173,5173,146,147,'ZQAAAA','VDCAAA','VVVVxx'
+860,1452,0,0,0,0,60,860,860,860,860,120,121,'CHAAAA','WDCAAA','AAAAxx'
+4523,1453,1,3,3,3,23,523,523,4523,4523,46,47,'ZRAAAA','XDCAAA','HHHHxx'
+2361,1454,1,1,1,1,61,361,361,2361,2361,122,123,'VMAAAA','YDCAAA','OOOOxx'
+7877,1455,1,1,7,17,77,877,1877,2877,7877,154,155,'ZQAAAA','ZDCAAA','VVVVxx'
+3422,1456,0,2,2,2,22,422,1422,3422,3422,44,45,'QBAAAA','AECAAA','AAAAxx'
+5781,1457,1,1,1,1,81,781,1781,781,5781,162,163,'JOAAAA','BECAAA','HHHHxx'
+4752,1458,0,0,2,12,52,752,752,4752,4752,104,105,'UAAAAA','CECAAA','OOOOxx'
+1786,1459,0,2,6,6,86,786,1786,1786,1786,172,173,'SQAAAA','DECAAA','VVVVxx'
+1892,1460,0,0,2,12,92,892,1892,1892,1892,184,185,'UUAAAA','EECAAA','AAAAxx'
+6389,1461,1,1,9,9,89,389,389,1389,6389,178,179,'TLAAAA','FECAAA','HHHHxx'
+8644,1462,0,0,4,4,44,644,644,3644,8644,88,89,'MUAAAA','GECAAA','OOOOxx'
+9056,1463,0,0,6,16,56,56,1056,4056,9056,112,113,'IKAAAA','HECAAA','VVVVxx'
+1423,1464,1,3,3,3,23,423,1423,1423,1423,46,47,'TCAAAA','IECAAA','AAAAxx'
+4901,1465,1,1,1,1,1,901,901,4901,4901,2,3,'NGAAAA','JECAAA','HHHHxx'
+3859,1466,1,3,9,19,59,859,1859,3859,3859,118,119,'LSAAAA','KECAAA','OOOOxx'
+2324,1467,0,0,4,4,24,324,324,2324,2324,48,49,'KLAAAA','LECAAA','VVVVxx'
+8101,1468,1,1,1,1,1,101,101,3101,8101,2,3,'PZAAAA','MECAAA','AAAAxx'
+8016,1469,0,0,6,16,16,16,16,3016,8016,32,33,'IWAAAA','NECAAA','HHHHxx'
+5826,1470,0,2,6,6,26,826,1826,826,5826,52,53,'CQAAAA','OECAAA','OOOOxx'
+8266,1471,0,2,6,6,66,266,266,3266,8266,132,133,'YFAAAA','PECAAA','VVVVxx'
+7558,1472,0,2,8,18,58,558,1558,2558,7558,116,117,'SEAAAA','QECAAA','AAAAxx'
+6976,1473,0,0,6,16,76,976,976,1976,6976,152,153,'IIAAAA','RECAAA','HHHHxx'
+222,1474,0,2,2,2,22,222,222,222,222,44,45,'OIAAAA','SECAAA','OOOOxx'
+1624,1475,0,0,4,4,24,624,1624,1624,1624,48,49,'MKAAAA','TECAAA','VVVVxx'
+1250,1476,0,2,0,10,50,250,1250,1250,1250,100,101,'CWAAAA','UECAAA','AAAAxx'
+1621,1477,1,1,1,1,21,621,1621,1621,1621,42,43,'JKAAAA','VECAAA','HHHHxx'
+2350,1478,0,2,0,10,50,350,350,2350,2350,100,101,'KMAAAA','WECAAA','OOOOxx'
+5239,1479,1,3,9,19,39,239,1239,239,5239,78,79,'NTAAAA','XECAAA','VVVVxx'
+6681,1480,1,1,1,1,81,681,681,1681,6681,162,163,'ZWAAAA','YECAAA','AAAAxx'
+4983,1481,1,3,3,3,83,983,983,4983,4983,166,167,'RJAAAA','ZECAAA','HHHHxx'
+7149,1482,1,1,9,9,49,149,1149,2149,7149,98,99,'ZOAAAA','AFCAAA','OOOOxx'
+3502,1483,0,2,2,2,2,502,1502,3502,3502,4,5,'SEAAAA','BFCAAA','VVVVxx'
+3133,1484,1,1,3,13,33,133,1133,3133,3133,66,67,'NQAAAA','CFCAAA','AAAAxx'
+8342,1485,0,2,2,2,42,342,342,3342,8342,84,85,'WIAAAA','DFCAAA','HHHHxx'
+3041,1486,1,1,1,1,41,41,1041,3041,3041,82,83,'ZMAAAA','EFCAAA','OOOOxx'
+5383,1487,1,3,3,3,83,383,1383,383,5383,166,167,'BZAAAA','FFCAAA','VVVVxx'
+3916,1488,0,0,6,16,16,916,1916,3916,3916,32,33,'QUAAAA','GFCAAA','AAAAxx'
+1438,1489,0,2,8,18,38,438,1438,1438,1438,76,77,'IDAAAA','HFCAAA','HHHHxx'
+9408,1490,0,0,8,8,8,408,1408,4408,9408,16,17,'WXAAAA','IFCAAA','OOOOxx'
+5783,1491,1,3,3,3,83,783,1783,783,5783,166,167,'LOAAAA','JFCAAA','VVVVxx'
+683,1492,1,3,3,3,83,683,683,683,683,166,167,'HAAAAA','KFCAAA','AAAAxx'
+9381,1493,1,1,1,1,81,381,1381,4381,9381,162,163,'VWAAAA','LFCAAA','HHHHxx'
+5676,1494,0,0,6,16,76,676,1676,676,5676,152,153,'IKAAAA','MFCAAA','OOOOxx'
+3224,1495,0,0,4,4,24,224,1224,3224,3224,48,49,'AUAAAA','NFCAAA','VVVVxx'
+8332,1496,0,0,2,12,32,332,332,3332,8332,64,65,'MIAAAA','OFCAAA','AAAAxx'
+3372,1497,0,0,2,12,72,372,1372,3372,3372,144,145,'SZAAAA','PFCAAA','HHHHxx'
+7436,1498,0,0,6,16,36,436,1436,2436,7436,72,73,'AAAAAA','QFCAAA','OOOOxx'
+5010,1499,0,2,0,10,10,10,1010,10,5010,20,21,'SKAAAA','RFCAAA','VVVVxx'
+7256,1500,0,0,6,16,56,256,1256,2256,7256,112,113,'CTAAAA','SFCAAA','AAAAxx'
+961,1501,1,1,1,1,61,961,961,961,961,122,123,'ZKAAAA','TFCAAA','HHHHxx'
+4182,1502,0,2,2,2,82,182,182,4182,4182,164,165,'WEAAAA','UFCAAA','OOOOxx'
+639,1503,1,3,9,19,39,639,639,639,639,78,79,'PYAAAA','VFCAAA','VVVVxx'
+8836,1504,0,0,6,16,36,836,836,3836,8836,72,73,'WBAAAA','WFCAAA','AAAAxx'
+8705,1505,1,1,5,5,5,705,705,3705,8705,10,11,'VWAAAA','XFCAAA','HHHHxx'
+32,1506,0,0,2,12,32,32,32,32,32,64,65,'GBAAAA','YFCAAA','OOOOxx'
+7913,1507,1,1,3,13,13,913,1913,2913,7913,26,27,'JSAAAA','ZFCAAA','VVVVxx'
+229,1508,1,1,9,9,29,229,229,229,229,58,59,'VIAAAA','AGCAAA','AAAAxx'
+2393,1509,1,1,3,13,93,393,393,2393,2393,186,187,'BOAAAA','BGCAAA','HHHHxx'
+2815,1510,1,3,5,15,15,815,815,2815,2815,30,31,'HEAAAA','CGCAAA','OOOOxx'
+4858,1511,0,2,8,18,58,858,858,4858,4858,116,117,'WEAAAA','DGCAAA','VVVVxx'
+6283,1512,1,3,3,3,83,283,283,1283,6283,166,167,'RHAAAA','EGCAAA','AAAAxx'
+4147,1513,1,3,7,7,47,147,147,4147,4147,94,95,'NDAAAA','FGCAAA','HHHHxx'
+6801,1514,1,1,1,1,1,801,801,1801,6801,2,3,'PBAAAA','GGCAAA','OOOOxx'
+1011,1515,1,3,1,11,11,11,1011,1011,1011,22,23,'XMAAAA','HGCAAA','VVVVxx'
+2527,1516,1,3,7,7,27,527,527,2527,2527,54,55,'FTAAAA','IGCAAA','AAAAxx'
+381,1517,1,1,1,1,81,381,381,381,381,162,163,'ROAAAA','JGCAAA','HHHHxx'
+3366,1518,0,2,6,6,66,366,1366,3366,3366,132,133,'MZAAAA','KGCAAA','OOOOxx'
+9636,1519,0,0,6,16,36,636,1636,4636,9636,72,73,'QGAAAA','LGCAAA','VVVVxx'
+2239,1520,1,3,9,19,39,239,239,2239,2239,78,79,'DIAAAA','MGCAAA','AAAAxx'
+5911,1521,1,3,1,11,11,911,1911,911,5911,22,23,'JTAAAA','NGCAAA','HHHHxx'
+449,1522,1,1,9,9,49,449,449,449,449,98,99,'HRAAAA','OGCAAA','OOOOxx'
+5118,1523,0,2,8,18,18,118,1118,118,5118,36,37,'WOAAAA','PGCAAA','VVVVxx'
+7684,1524,0,0,4,4,84,684,1684,2684,7684,168,169,'OJAAAA','QGCAAA','AAAAxx'
+804,1525,0,0,4,4,4,804,804,804,804,8,9,'YEAAAA','RGCAAA','HHHHxx'
+8378,1526,0,2,8,18,78,378,378,3378,8378,156,157,'GKAAAA','SGCAAA','OOOOxx'
+9855,1527,1,3,5,15,55,855,1855,4855,9855,110,111,'BPAAAA','TGCAAA','VVVVxx'
+1995,1528,1,3,5,15,95,995,1995,1995,1995,190,191,'TYAAAA','UGCAAA','AAAAxx'
+1979,1529,1,3,9,19,79,979,1979,1979,1979,158,159,'DYAAAA','VGCAAA','HHHHxx'
+4510,1530,0,2,0,10,10,510,510,4510,4510,20,21,'MRAAAA','WGCAAA','OOOOxx'
+3792,1531,0,0,2,12,92,792,1792,3792,3792,184,185,'WPAAAA','XGCAAA','VVVVxx'
+3541,1532,1,1,1,1,41,541,1541,3541,3541,82,83,'FGAAAA','YGCAAA','AAAAxx'
+8847,1533,1,3,7,7,47,847,847,3847,8847,94,95,'HCAAAA','ZGCAAA','HHHHxx'
+1336,1534,0,0,6,16,36,336,1336,1336,1336,72,73,'KZAAAA','AHCAAA','OOOOxx'
+6780,1535,0,0,0,0,80,780,780,1780,6780,160,161,'UAAAAA','BHCAAA','VVVVxx'
+8711,1536,1,3,1,11,11,711,711,3711,8711,22,23,'BXAAAA','CHCAAA','AAAAxx'
+7839,1537,1,3,9,19,39,839,1839,2839,7839,78,79,'NPAAAA','DHCAAA','HHHHxx'
+677,1538,1,1,7,17,77,677,677,677,677,154,155,'BAAAAA','EHCAAA','OOOOxx'
+1574,1539,0,2,4,14,74,574,1574,1574,1574,148,149,'OIAAAA','FHCAAA','VVVVxx'
+2905,1540,1,1,5,5,5,905,905,2905,2905,10,11,'THAAAA','GHCAAA','AAAAxx'
+1879,1541,1,3,9,19,79,879,1879,1879,1879,158,159,'HUAAAA','HHCAAA','HHHHxx'
+7820,1542,0,0,0,0,20,820,1820,2820,7820,40,41,'UOAAAA','IHCAAA','OOOOxx'
+4308,1543,0,0,8,8,8,308,308,4308,4308,16,17,'SJAAAA','JHCAAA','VVVVxx'
+4474,1544,0,2,4,14,74,474,474,4474,4474,148,149,'CQAAAA','KHCAAA','AAAAxx'
+6985,1545,1,1,5,5,85,985,985,1985,6985,170,171,'RIAAAA','LHCAAA','HHHHxx'
+6929,1546,1,1,9,9,29,929,929,1929,6929,58,59,'NGAAAA','MHCAAA','OOOOxx'
+777,1547,1,1,7,17,77,777,777,777,777,154,155,'XDAAAA','NHCAAA','VVVVxx'
+8271,1548,1,3,1,11,71,271,271,3271,8271,142,143,'DGAAAA','OHCAAA','AAAAxx'
+2389,1549,1,1,9,9,89,389,389,2389,2389,178,179,'XNAAAA','PHCAAA','HHHHxx'
+946,1550,0,2,6,6,46,946,946,946,946,92,93,'KKAAAA','QHCAAA','OOOOxx'
+9682,1551,0,2,2,2,82,682,1682,4682,9682,164,165,'KIAAAA','RHCAAA','VVVVxx'
+8722,1552,0,2,2,2,22,722,722,3722,8722,44,45,'MXAAAA','SHCAAA','AAAAxx'
+470,1553,0,2,0,10,70,470,470,470,470,140,141,'CSAAAA','THCAAA','HHHHxx'
+7425,1554,1,1,5,5,25,425,1425,2425,7425,50,51,'PZAAAA','UHCAAA','OOOOxx'
+2372,1555,0,0,2,12,72,372,372,2372,2372,144,145,'GNAAAA','VHCAAA','VVVVxx'
+508,1556,0,0,8,8,8,508,508,508,508,16,17,'OTAAAA','WHCAAA','AAAAxx'
+163,1557,1,3,3,3,63,163,163,163,163,126,127,'HGAAAA','XHCAAA','HHHHxx'
+6579,1558,1,3,9,19,79,579,579,1579,6579,158,159,'BTAAAA','YHCAAA','OOOOxx'
+2355,1559,1,3,5,15,55,355,355,2355,2355,110,111,'PMAAAA','ZHCAAA','VVVVxx'
+70,1560,0,2,0,10,70,70,70,70,70,140,141,'SCAAAA','AICAAA','AAAAxx'
+651,1561,1,3,1,11,51,651,651,651,651,102,103,'BZAAAA','BICAAA','HHHHxx'
+4436,1562,0,0,6,16,36,436,436,4436,4436,72,73,'QOAAAA','CICAAA','OOOOxx'
+4240,1563,0,0,0,0,40,240,240,4240,4240,80,81,'CHAAAA','DICAAA','VVVVxx'
+2722,1564,0,2,2,2,22,722,722,2722,2722,44,45,'SAAAAA','EICAAA','AAAAxx'
+8937,1565,1,1,7,17,37,937,937,3937,8937,74,75,'TFAAAA','FICAAA','HHHHxx'
+8364,1566,0,0,4,4,64,364,364,3364,8364,128,129,'SJAAAA','GICAAA','OOOOxx'
+8317,1567,1,1,7,17,17,317,317,3317,8317,34,35,'XHAAAA','HICAAA','VVVVxx'
+8872,1568,0,0,2,12,72,872,872,3872,8872,144,145,'GDAAAA','IICAAA','AAAAxx'
+5512,1569,0,0,2,12,12,512,1512,512,5512,24,25,'AEAAAA','JICAAA','HHHHxx'
+6651,1570,1,3,1,11,51,651,651,1651,6651,102,103,'VVAAAA','KICAAA','OOOOxx'
+5976,1571,0,0,6,16,76,976,1976,976,5976,152,153,'WVAAAA','LICAAA','VVVVxx'
+3301,1572,1,1,1,1,1,301,1301,3301,3301,2,3,'ZWAAAA','MICAAA','AAAAxx'
+6784,1573,0,0,4,4,84,784,784,1784,6784,168,169,'YAAAAA','NICAAA','HHHHxx'
+573,1574,1,1,3,13,73,573,573,573,573,146,147,'BWAAAA','OICAAA','OOOOxx'
+3015,1575,1,3,5,15,15,15,1015,3015,3015,30,31,'ZLAAAA','PICAAA','VVVVxx'
+8245,1576,1,1,5,5,45,245,245,3245,8245,90,91,'DFAAAA','QICAAA','AAAAxx'
+5251,1577,1,3,1,11,51,251,1251,251,5251,102,103,'ZTAAAA','RICAAA','HHHHxx'
+2281,1578,1,1,1,1,81,281,281,2281,2281,162,163,'TJAAAA','SICAAA','OOOOxx'
+518,1579,0,2,8,18,18,518,518,518,518,36,37,'YTAAAA','TICAAA','VVVVxx'
+9839,1580,1,3,9,19,39,839,1839,4839,9839,78,79,'LOAAAA','UICAAA','AAAAxx'
+4526,1581,0,2,6,6,26,526,526,4526,4526,52,53,'CSAAAA','VICAAA','HHHHxx'
+1261,1582,1,1,1,1,61,261,1261,1261,1261,122,123,'NWAAAA','WICAAA','OOOOxx'
+4259,1583,1,3,9,19,59,259,259,4259,4259,118,119,'VHAAAA','XICAAA','VVVVxx'
+9098,1584,0,2,8,18,98,98,1098,4098,9098,196,197,'YLAAAA','YICAAA','AAAAxx'
+6037,1585,1,1,7,17,37,37,37,1037,6037,74,75,'FYAAAA','ZICAAA','HHHHxx'
+4284,1586,0,0,4,4,84,284,284,4284,4284,168,169,'UIAAAA','AJCAAA','OOOOxx'
+3267,1587,1,3,7,7,67,267,1267,3267,3267,134,135,'RVAAAA','BJCAAA','VVVVxx'
+5908,1588,0,0,8,8,8,908,1908,908,5908,16,17,'GTAAAA','CJCAAA','AAAAxx'
+1549,1589,1,1,9,9,49,549,1549,1549,1549,98,99,'PHAAAA','DJCAAA','HHHHxx'
+8736,1590,0,0,6,16,36,736,736,3736,8736,72,73,'AYAAAA','EJCAAA','OOOOxx'
+2008,1591,0,0,8,8,8,8,8,2008,2008,16,17,'GZAAAA','FJCAAA','VVVVxx'
+548,1592,0,0,8,8,48,548,548,548,548,96,97,'CVAAAA','GJCAAA','AAAAxx'
+8846,1593,0,2,6,6,46,846,846,3846,8846,92,93,'GCAAAA','HJCAAA','HHHHxx'
+8374,1594,0,2,4,14,74,374,374,3374,8374,148,149,'CKAAAA','IJCAAA','OOOOxx'
+7986,1595,0,2,6,6,86,986,1986,2986,7986,172,173,'EVAAAA','JJCAAA','VVVVxx'
+6819,1596,1,3,9,19,19,819,819,1819,6819,38,39,'HCAAAA','KJCAAA','AAAAxx'
+4418,1597,0,2,8,18,18,418,418,4418,4418,36,37,'YNAAAA','LJCAAA','HHHHxx'
+833,1598,1,1,3,13,33,833,833,833,833,66,67,'BGAAAA','MJCAAA','OOOOxx'
+4416,1599,0,0,6,16,16,416,416,4416,4416,32,33,'WNAAAA','NJCAAA','VVVVxx'
+4902,1600,0,2,2,2,2,902,902,4902,4902,4,5,'OGAAAA','OJCAAA','AAAAxx'
+6828,1601,0,0,8,8,28,828,828,1828,6828,56,57,'QCAAAA','PJCAAA','HHHHxx'
+1118,1602,0,2,8,18,18,118,1118,1118,1118,36,37,'ARAAAA','QJCAAA','OOOOxx'
+9993,1603,1,1,3,13,93,993,1993,4993,9993,186,187,'JUAAAA','RJCAAA','VVVVxx'
+1430,1604,0,2,0,10,30,430,1430,1430,1430,60,61,'ADAAAA','SJCAAA','AAAAxx'
+5670,1605,0,2,0,10,70,670,1670,670,5670,140,141,'CKAAAA','TJCAAA','HHHHxx'
+5424,1606,0,0,4,4,24,424,1424,424,5424,48,49,'QAAAAA','UJCAAA','OOOOxx'
+5561,1607,1,1,1,1,61,561,1561,561,5561,122,123,'XFAAAA','VJCAAA','VVVVxx'
+2027,1608,1,3,7,7,27,27,27,2027,2027,54,55,'ZZAAAA','WJCAAA','AAAAxx'
+6924,1609,0,0,4,4,24,924,924,1924,6924,48,49,'IGAAAA','XJCAAA','HHHHxx'
+5946,1610,0,2,6,6,46,946,1946,946,5946,92,93,'SUAAAA','YJCAAA','OOOOxx'
+4294,1611,0,2,4,14,94,294,294,4294,4294,188,189,'EJAAAA','ZJCAAA','VVVVxx'
+2936,1612,0,0,6,16,36,936,936,2936,2936,72,73,'YIAAAA','AKCAAA','AAAAxx'
+3855,1613,1,3,5,15,55,855,1855,3855,3855,110,111,'HSAAAA','BKCAAA','HHHHxx'
+455,1614,1,3,5,15,55,455,455,455,455,110,111,'NRAAAA','CKCAAA','OOOOxx'
+2918,1615,0,2,8,18,18,918,918,2918,2918,36,37,'GIAAAA','DKCAAA','VVVVxx'
+448,1616,0,0,8,8,48,448,448,448,448,96,97,'GRAAAA','EKCAAA','AAAAxx'
+2149,1617,1,1,9,9,49,149,149,2149,2149,98,99,'REAAAA','FKCAAA','HHHHxx'
+8890,1618,0,2,0,10,90,890,890,3890,8890,180,181,'YDAAAA','GKCAAA','OOOOxx'
+8919,1619,1,3,9,19,19,919,919,3919,8919,38,39,'BFAAAA','HKCAAA','VVVVxx'
+4957,1620,1,1,7,17,57,957,957,4957,4957,114,115,'RIAAAA','IKCAAA','AAAAxx'
+4,1621,0,0,4,4,4,4,4,4,4,8,9,'EAAAAA','JKCAAA','HHHHxx'
+4837,1622,1,1,7,17,37,837,837,4837,4837,74,75,'BEAAAA','KKCAAA','OOOOxx'
+3976,1623,0,0,6,16,76,976,1976,3976,3976,152,153,'YWAAAA','LKCAAA','VVVVxx'
+9459,1624,1,3,9,19,59,459,1459,4459,9459,118,119,'VZAAAA','MKCAAA','AAAAxx'
+7097,1625,1,1,7,17,97,97,1097,2097,7097,194,195,'ZMAAAA','NKCAAA','HHHHxx'
+9226,1626,0,2,6,6,26,226,1226,4226,9226,52,53,'WQAAAA','OKCAAA','OOOOxx'
+5803,1627,1,3,3,3,3,803,1803,803,5803,6,7,'FPAAAA','PKCAAA','VVVVxx'
+21,1628,1,1,1,1,21,21,21,21,21,42,43,'VAAAAA','QKCAAA','AAAAxx'
+5275,1629,1,3,5,15,75,275,1275,275,5275,150,151,'XUAAAA','RKCAAA','HHHHxx'
+3488,1630,0,0,8,8,88,488,1488,3488,3488,176,177,'EEAAAA','SKCAAA','OOOOxx'
+1595,1631,1,3,5,15,95,595,1595,1595,1595,190,191,'JJAAAA','TKCAAA','VVVVxx'
+5212,1632,0,0,2,12,12,212,1212,212,5212,24,25,'MSAAAA','UKCAAA','AAAAxx'
+6574,1633,0,2,4,14,74,574,574,1574,6574,148,149,'WSAAAA','VKCAAA','HHHHxx'
+7524,1634,0,0,4,4,24,524,1524,2524,7524,48,49,'KDAAAA','WKCAAA','OOOOxx'
+6100,1635,0,0,0,0,0,100,100,1100,6100,0,1,'QAAAAA','XKCAAA','VVVVxx'
+1198,1636,0,2,8,18,98,198,1198,1198,1198,196,197,'CUAAAA','YKCAAA','AAAAxx'
+7345,1637,1,1,5,5,45,345,1345,2345,7345,90,91,'NWAAAA','ZKCAAA','HHHHxx'
+5020,1638,0,0,0,0,20,20,1020,20,5020,40,41,'CLAAAA','ALCAAA','OOOOxx'
+6925,1639,1,1,5,5,25,925,925,1925,6925,50,51,'JGAAAA','BLCAAA','VVVVxx'
+8915,1640,1,3,5,15,15,915,915,3915,8915,30,31,'XEAAAA','CLCAAA','AAAAxx'
+3088,1641,0,0,8,8,88,88,1088,3088,3088,176,177,'UOAAAA','DLCAAA','HHHHxx'
+4828,1642,0,0,8,8,28,828,828,4828,4828,56,57,'SDAAAA','ELCAAA','OOOOxx'
+7276,1643,0,0,6,16,76,276,1276,2276,7276,152,153,'WTAAAA','FLCAAA','VVVVxx'
+299,1644,1,3,9,19,99,299,299,299,299,198,199,'NLAAAA','GLCAAA','AAAAxx'
+76,1645,0,0,6,16,76,76,76,76,76,152,153,'YCAAAA','HLCAAA','HHHHxx'
+8458,1646,0,2,8,18,58,458,458,3458,8458,116,117,'INAAAA','ILCAAA','OOOOxx'
+7207,1647,1,3,7,7,7,207,1207,2207,7207,14,15,'FRAAAA','JLCAAA','VVVVxx'
+5585,1648,1,1,5,5,85,585,1585,585,5585,170,171,'VGAAAA','KLCAAA','AAAAxx'
+3234,1649,0,2,4,14,34,234,1234,3234,3234,68,69,'KUAAAA','LLCAAA','HHHHxx'
+8001,1650,1,1,1,1,1,1,1,3001,8001,2,3,'TVAAAA','MLCAAA','OOOOxx'
+1319,1651,1,3,9,19,19,319,1319,1319,1319,38,39,'TYAAAA','NLCAAA','VVVVxx'
+6342,1652,0,2,2,2,42,342,342,1342,6342,84,85,'YJAAAA','OLCAAA','AAAAxx'
+9199,1653,1,3,9,19,99,199,1199,4199,9199,198,199,'VPAAAA','PLCAAA','HHHHxx'
+5696,1654,0,0,6,16,96,696,1696,696,5696,192,193,'CLAAAA','QLCAAA','OOOOxx'
+2562,1655,0,2,2,2,62,562,562,2562,2562,124,125,'OUAAAA','RLCAAA','VVVVxx'
+4226,1656,0,2,6,6,26,226,226,4226,4226,52,53,'OGAAAA','SLCAAA','AAAAxx'
+1184,1657,0,0,4,4,84,184,1184,1184,1184,168,169,'OTAAAA','TLCAAA','HHHHxx'
+5807,1658,1,3,7,7,7,807,1807,807,5807,14,15,'JPAAAA','ULCAAA','OOOOxx'
+1890,1659,0,2,0,10,90,890,1890,1890,1890,180,181,'SUAAAA','VLCAAA','VVVVxx'
+451,1660,1,3,1,11,51,451,451,451,451,102,103,'JRAAAA','WLCAAA','AAAAxx'
+1049,1661,1,1,9,9,49,49,1049,1049,1049,98,99,'JOAAAA','XLCAAA','HHHHxx'
+5272,1662,0,0,2,12,72,272,1272,272,5272,144,145,'UUAAAA','YLCAAA','OOOOxx'
+4588,1663,0,0,8,8,88,588,588,4588,4588,176,177,'MUAAAA','ZLCAAA','VVVVxx'
+5213,1664,1,1,3,13,13,213,1213,213,5213,26,27,'NSAAAA','AMCAAA','AAAAxx'
+9543,1665,1,3,3,3,43,543,1543,4543,9543,86,87,'BDAAAA','BMCAAA','HHHHxx'
+6318,1666,0,2,8,18,18,318,318,1318,6318,36,37,'AJAAAA','CMCAAA','OOOOxx'
+7992,1667,0,0,2,12,92,992,1992,2992,7992,184,185,'KVAAAA','DMCAAA','VVVVxx'
+4619,1668,1,3,9,19,19,619,619,4619,4619,38,39,'RVAAAA','EMCAAA','AAAAxx'
+7189,1669,1,1,9,9,89,189,1189,2189,7189,178,179,'NQAAAA','FMCAAA','HHHHxx'
+2178,1670,0,2,8,18,78,178,178,2178,2178,156,157,'UFAAAA','GMCAAA','OOOOxx'
+4928,1671,0,0,8,8,28,928,928,4928,4928,56,57,'OHAAAA','HMCAAA','VVVVxx'
+3966,1672,0,2,6,6,66,966,1966,3966,3966,132,133,'OWAAAA','IMCAAA','AAAAxx'
+9790,1673,0,2,0,10,90,790,1790,4790,9790,180,181,'OMAAAA','JMCAAA','HHHHxx'
+9150,1674,0,2,0,10,50,150,1150,4150,9150,100,101,'YNAAAA','KMCAAA','OOOOxx'
+313,1675,1,1,3,13,13,313,313,313,313,26,27,'BMAAAA','LMCAAA','VVVVxx'
+1614,1676,0,2,4,14,14,614,1614,1614,1614,28,29,'CKAAAA','MMCAAA','AAAAxx'
+1581,1677,1,1,1,1,81,581,1581,1581,1581,162,163,'VIAAAA','NMCAAA','HHHHxx'
+3674,1678,0,2,4,14,74,674,1674,3674,3674,148,149,'ILAAAA','OMCAAA','OOOOxx'
+3444,1679,0,0,4,4,44,444,1444,3444,3444,88,89,'MCAAAA','PMCAAA','VVVVxx'
+1050,1680,0,2,0,10,50,50,1050,1050,1050,100,101,'KOAAAA','QMCAAA','AAAAxx'
+8241,1681,1,1,1,1,41,241,241,3241,8241,82,83,'ZEAAAA','RMCAAA','HHHHxx'
+3382,1682,0,2,2,2,82,382,1382,3382,3382,164,165,'CAAAAA','SMCAAA','OOOOxx'
+7105,1683,1,1,5,5,5,105,1105,2105,7105,10,11,'HNAAAA','TMCAAA','VVVVxx'
+2957,1684,1,1,7,17,57,957,957,2957,2957,114,115,'TJAAAA','UMCAAA','AAAAxx'
+6162,1685,0,2,2,2,62,162,162,1162,6162,124,125,'ADAAAA','VMCAAA','HHHHxx'
+5150,1686,0,2,0,10,50,150,1150,150,5150,100,101,'CQAAAA','WMCAAA','OOOOxx'
+2622,1687,0,2,2,2,22,622,622,2622,2622,44,45,'WWAAAA','XMCAAA','VVVVxx'
+2240,1688,0,0,0,0,40,240,240,2240,2240,80,81,'EIAAAA','YMCAAA','AAAAxx'
+8880,1689,0,0,0,0,80,880,880,3880,8880,160,161,'ODAAAA','ZMCAAA','HHHHxx'
+9250,1690,0,2,0,10,50,250,1250,4250,9250,100,101,'URAAAA','ANCAAA','OOOOxx'
+7010,1691,0,2,0,10,10,10,1010,2010,7010,20,21,'QJAAAA','BNCAAA','VVVVxx'
+1098,1692,0,2,8,18,98,98,1098,1098,1098,196,197,'GQAAAA','CNCAAA','AAAAxx'
+648,1693,0,0,8,8,48,648,648,648,648,96,97,'YYAAAA','DNCAAA','HHHHxx'
+5536,1694,0,0,6,16,36,536,1536,536,5536,72,73,'YEAAAA','ENCAAA','OOOOxx'
+7858,1695,0,2,8,18,58,858,1858,2858,7858,116,117,'GQAAAA','FNCAAA','VVVVxx'
+7053,1696,1,1,3,13,53,53,1053,2053,7053,106,107,'HLAAAA','GNCAAA','AAAAxx'
+8681,1697,1,1,1,1,81,681,681,3681,8681,162,163,'XVAAAA','HNCAAA','HHHHxx'
+8832,1698,0,0,2,12,32,832,832,3832,8832,64,65,'SBAAAA','INCAAA','OOOOxx'
+6836,1699,0,0,6,16,36,836,836,1836,6836,72,73,'YCAAAA','JNCAAA','VVVVxx'
+4856,1700,0,0,6,16,56,856,856,4856,4856,112,113,'UEAAAA','KNCAAA','AAAAxx'
+345,1701,1,1,5,5,45,345,345,345,345,90,91,'HNAAAA','LNCAAA','HHHHxx'
+6559,1702,1,3,9,19,59,559,559,1559,6559,118,119,'HSAAAA','MNCAAA','OOOOxx'
+3017,1703,1,1,7,17,17,17,1017,3017,3017,34,35,'BMAAAA','NNCAAA','VVVVxx'
+4176,1704,0,0,6,16,76,176,176,4176,4176,152,153,'QEAAAA','ONCAAA','AAAAxx'
+2839,1705,1,3,9,19,39,839,839,2839,2839,78,79,'FFAAAA','PNCAAA','HHHHxx'
+6065,1706,1,1,5,5,65,65,65,1065,6065,130,131,'HZAAAA','QNCAAA','OOOOxx'
+7360,1707,0,0,0,0,60,360,1360,2360,7360,120,121,'CXAAAA','RNCAAA','VVVVxx'
+9527,1708,1,3,7,7,27,527,1527,4527,9527,54,55,'LCAAAA','SNCAAA','AAAAxx'
+8849,1709,1,1,9,9,49,849,849,3849,8849,98,99,'JCAAAA','TNCAAA','HHHHxx'
+7274,1710,0,2,4,14,74,274,1274,2274,7274,148,149,'UTAAAA','UNCAAA','OOOOxx'
+4368,1711,0,0,8,8,68,368,368,4368,4368,136,137,'AMAAAA','VNCAAA','VVVVxx'
+2488,1712,0,0,8,8,88,488,488,2488,2488,176,177,'SRAAAA','WNCAAA','AAAAxx'
+4674,1713,0,2,4,14,74,674,674,4674,4674,148,149,'UXAAAA','XNCAAA','HHHHxx'
+365,1714,1,1,5,5,65,365,365,365,365,130,131,'BOAAAA','YNCAAA','OOOOxx'
+5897,1715,1,1,7,17,97,897,1897,897,5897,194,195,'VSAAAA','ZNCAAA','VVVVxx'
+8918,1716,0,2,8,18,18,918,918,3918,8918,36,37,'AFAAAA','AOCAAA','AAAAxx'
+1988,1717,0,0,8,8,88,988,1988,1988,1988,176,177,'MYAAAA','BOCAAA','HHHHxx'
+1210,1718,0,2,0,10,10,210,1210,1210,1210,20,21,'OUAAAA','COCAAA','OOOOxx'
+2945,1719,1,1,5,5,45,945,945,2945,2945,90,91,'HJAAAA','DOCAAA','VVVVxx'
+555,1720,1,3,5,15,55,555,555,555,555,110,111,'JVAAAA','EOCAAA','AAAAxx'
+9615,1721,1,3,5,15,15,615,1615,4615,9615,30,31,'VFAAAA','FOCAAA','HHHHxx'
+9939,1722,1,3,9,19,39,939,1939,4939,9939,78,79,'HSAAAA','GOCAAA','OOOOxx'
+1216,1723,0,0,6,16,16,216,1216,1216,1216,32,33,'UUAAAA','HOCAAA','VVVVxx'
+745,1724,1,1,5,5,45,745,745,745,745,90,91,'RCAAAA','IOCAAA','AAAAxx'
+3326,1725,0,2,6,6,26,326,1326,3326,3326,52,53,'YXAAAA','JOCAAA','HHHHxx'
+953,1726,1,1,3,13,53,953,953,953,953,106,107,'RKAAAA','KOCAAA','OOOOxx'
+444,1727,0,0,4,4,44,444,444,444,444,88,89,'CRAAAA','LOCAAA','VVVVxx'
+280,1728,0,0,0,0,80,280,280,280,280,160,161,'UKAAAA','MOCAAA','AAAAxx'
+3707,1729,1,3,7,7,7,707,1707,3707,3707,14,15,'PMAAAA','NOCAAA','HHHHxx'
+1351,1730,1,3,1,11,51,351,1351,1351,1351,102,103,'ZZAAAA','OOCAAA','OOOOxx'
+1280,1731,0,0,0,0,80,280,1280,1280,1280,160,161,'GXAAAA','POCAAA','VVVVxx'
+628,1732,0,0,8,8,28,628,628,628,628,56,57,'EYAAAA','QOCAAA','AAAAxx'
+6198,1733,0,2,8,18,98,198,198,1198,6198,196,197,'KEAAAA','ROCAAA','HHHHxx'
+1957,1734,1,1,7,17,57,957,1957,1957,1957,114,115,'HXAAAA','SOCAAA','OOOOxx'
+9241,1735,1,1,1,1,41,241,1241,4241,9241,82,83,'LRAAAA','TOCAAA','VVVVxx'
+303,1736,1,3,3,3,3,303,303,303,303,6,7,'RLAAAA','UOCAAA','AAAAxx'
+1945,1737,1,1,5,5,45,945,1945,1945,1945,90,91,'VWAAAA','VOCAAA','HHHHxx'
+3634,1738,0,2,4,14,34,634,1634,3634,3634,68,69,'UJAAAA','WOCAAA','OOOOxx'
+4768,1739,0,0,8,8,68,768,768,4768,4768,136,137,'KBAAAA','XOCAAA','VVVVxx'
+9262,1740,0,2,2,2,62,262,1262,4262,9262,124,125,'GSAAAA','YOCAAA','AAAAxx'
+2610,1741,0,2,0,10,10,610,610,2610,2610,20,21,'KWAAAA','ZOCAAA','HHHHxx'
+6640,1742,0,0,0,0,40,640,640,1640,6640,80,81,'KVAAAA','APCAAA','OOOOxx'
+3338,1743,0,2,8,18,38,338,1338,3338,3338,76,77,'KYAAAA','BPCAAA','VVVVxx'
+6560,1744,0,0,0,0,60,560,560,1560,6560,120,121,'ISAAAA','CPCAAA','AAAAxx'
+5986,1745,0,2,6,6,86,986,1986,986,5986,172,173,'GWAAAA','DPCAAA','HHHHxx'
+2970,1746,0,2,0,10,70,970,970,2970,2970,140,141,'GKAAAA','EPCAAA','OOOOxx'
+4731,1747,1,3,1,11,31,731,731,4731,4731,62,63,'ZZAAAA','FPCAAA','VVVVxx'
+9486,1748,0,2,6,6,86,486,1486,4486,9486,172,173,'WAAAAA','GPCAAA','AAAAxx'
+7204,1749,0,0,4,4,4,204,1204,2204,7204,8,9,'CRAAAA','HPCAAA','HHHHxx'
+6685,1750,1,1,5,5,85,685,685,1685,6685,170,171,'DXAAAA','IPCAAA','OOOOxx'
+6852,1751,0,0,2,12,52,852,852,1852,6852,104,105,'ODAAAA','JPCAAA','VVVVxx'
+2325,1752,1,1,5,5,25,325,325,2325,2325,50,51,'LLAAAA','KPCAAA','AAAAxx'
+1063,1753,1,3,3,3,63,63,1063,1063,1063,126,127,'XOAAAA','LPCAAA','HHHHxx'
+6810,1754,0,2,0,10,10,810,810,1810,6810,20,21,'YBAAAA','MPCAAA','OOOOxx'
+7718,1755,0,2,8,18,18,718,1718,2718,7718,36,37,'WKAAAA','NPCAAA','VVVVxx'
+1680,1756,0,0,0,0,80,680,1680,1680,1680,160,161,'QMAAAA','OPCAAA','AAAAxx'
+7402,1757,0,2,2,2,2,402,1402,2402,7402,4,5,'SYAAAA','PPCAAA','HHHHxx'
+4134,1758,0,2,4,14,34,134,134,4134,4134,68,69,'ADAAAA','QPCAAA','OOOOxx'
+8232,1759,0,0,2,12,32,232,232,3232,8232,64,65,'QEAAAA','RPCAAA','VVVVxx'
+6682,1760,0,2,2,2,82,682,682,1682,6682,164,165,'AXAAAA','SPCAAA','AAAAxx'
+7952,1761,0,0,2,12,52,952,1952,2952,7952,104,105,'WTAAAA','TPCAAA','HHHHxx'
+5943,1762,1,3,3,3,43,943,1943,943,5943,86,87,'PUAAAA','UPCAAA','OOOOxx'
+5394,1763,0,2,4,14,94,394,1394,394,5394,188,189,'MZAAAA','VPCAAA','VVVVxx'
+6554,1764,0,2,4,14,54,554,554,1554,6554,108,109,'CSAAAA','WPCAAA','AAAAxx'
+8186,1765,0,2,6,6,86,186,186,3186,8186,172,173,'WCAAAA','XPCAAA','HHHHxx'
+199,1766,1,3,9,19,99,199,199,199,199,198,199,'RHAAAA','YPCAAA','OOOOxx'
+3386,1767,0,2,6,6,86,386,1386,3386,3386,172,173,'GAAAAA','ZPCAAA','VVVVxx'
+8974,1768,0,2,4,14,74,974,974,3974,8974,148,149,'EHAAAA','AQCAAA','AAAAxx'
+8140,1769,0,0,0,0,40,140,140,3140,8140,80,81,'CBAAAA','BQCAAA','HHHHxx'
+3723,1770,1,3,3,3,23,723,1723,3723,3723,46,47,'FNAAAA','CQCAAA','OOOOxx'
+8827,1771,1,3,7,7,27,827,827,3827,8827,54,55,'NBAAAA','DQCAAA','VVVVxx'
+1998,1772,0,2,8,18,98,998,1998,1998,1998,196,197,'WYAAAA','EQCAAA','AAAAxx'
+879,1773,1,3,9,19,79,879,879,879,879,158,159,'VHAAAA','FQCAAA','HHHHxx'
+892,1774,0,0,2,12,92,892,892,892,892,184,185,'IIAAAA','GQCAAA','OOOOxx'
+9468,1775,0,0,8,8,68,468,1468,4468,9468,136,137,'EAAAAA','HQCAAA','VVVVxx'
+3797,1776,1,1,7,17,97,797,1797,3797,3797,194,195,'BQAAAA','IQCAAA','AAAAxx'
+8379,1777,1,3,9,19,79,379,379,3379,8379,158,159,'HKAAAA','JQCAAA','HHHHxx'
+2817,1778,1,1,7,17,17,817,817,2817,2817,34,35,'JEAAAA','KQCAAA','OOOOxx'
+789,1779,1,1,9,9,89,789,789,789,789,178,179,'JEAAAA','LQCAAA','VVVVxx'
+3871,1780,1,3,1,11,71,871,1871,3871,3871,142,143,'XSAAAA','MQCAAA','AAAAxx'
+7931,1781,1,3,1,11,31,931,1931,2931,7931,62,63,'BTAAAA','NQCAAA','HHHHxx'
+3636,1782,0,0,6,16,36,636,1636,3636,3636,72,73,'WJAAAA','OQCAAA','OOOOxx'
+699,1783,1,3,9,19,99,699,699,699,699,198,199,'XAAAAA','PQCAAA','VVVVxx'
+6850,1784,0,2,0,10,50,850,850,1850,6850,100,101,'MDAAAA','QQCAAA','AAAAxx'
+6394,1785,0,2,4,14,94,394,394,1394,6394,188,189,'YLAAAA','RQCAAA','HHHHxx'
+3475,1786,1,3,5,15,75,475,1475,3475,3475,150,151,'RDAAAA','SQCAAA','OOOOxx'
+3026,1787,0,2,6,6,26,26,1026,3026,3026,52,53,'KMAAAA','TQCAAA','VVVVxx'
+876,1788,0,0,6,16,76,876,876,876,876,152,153,'SHAAAA','UQCAAA','AAAAxx'
+1992,1789,0,0,2,12,92,992,1992,1992,1992,184,185,'QYAAAA','VQCAAA','HHHHxx'
+3079,1790,1,3,9,19,79,79,1079,3079,3079,158,159,'LOAAAA','WQCAAA','OOOOxx'
+8128,1791,0,0,8,8,28,128,128,3128,8128,56,57,'QAAAAA','XQCAAA','VVVVxx'
+8123,1792,1,3,3,3,23,123,123,3123,8123,46,47,'LAAAAA','YQCAAA','AAAAxx'
+3285,1793,1,1,5,5,85,285,1285,3285,3285,170,171,'JWAAAA','ZQCAAA','HHHHxx'
+9315,1794,1,3,5,15,15,315,1315,4315,9315,30,31,'HUAAAA','ARCAAA','OOOOxx'
+9862,1795,0,2,2,2,62,862,1862,4862,9862,124,125,'IPAAAA','BRCAAA','VVVVxx'
+2764,1796,0,0,4,4,64,764,764,2764,2764,128,129,'ICAAAA','CRCAAA','AAAAxx'
+3544,1797,0,0,4,4,44,544,1544,3544,3544,88,89,'IGAAAA','DRCAAA','HHHHxx'
+7747,1798,1,3,7,7,47,747,1747,2747,7747,94,95,'ZLAAAA','ERCAAA','OOOOxx'
+7725,1799,1,1,5,5,25,725,1725,2725,7725,50,51,'DLAAAA','FRCAAA','VVVVxx'
+2449,1800,1,1,9,9,49,449,449,2449,2449,98,99,'FQAAAA','GRCAAA','AAAAxx'
+8967,1801,1,3,7,7,67,967,967,3967,8967,134,135,'XGAAAA','HRCAAA','HHHHxx'
+7371,1802,1,3,1,11,71,371,1371,2371,7371,142,143,'NXAAAA','IRCAAA','OOOOxx'
+2158,1803,0,2,8,18,58,158,158,2158,2158,116,117,'AFAAAA','JRCAAA','VVVVxx'
+5590,1804,0,2,0,10,90,590,1590,590,5590,180,181,'AHAAAA','KRCAAA','AAAAxx'
+8072,1805,0,0,2,12,72,72,72,3072,8072,144,145,'MYAAAA','LRCAAA','HHHHxx'
+1971,1806,1,3,1,11,71,971,1971,1971,1971,142,143,'VXAAAA','MRCAAA','OOOOxx'
+772,1807,0,0,2,12,72,772,772,772,772,144,145,'SDAAAA','NRCAAA','VVVVxx'
+3433,1808,1,1,3,13,33,433,1433,3433,3433,66,67,'BCAAAA','ORCAAA','AAAAxx'
+8419,1809,1,3,9,19,19,419,419,3419,8419,38,39,'VLAAAA','PRCAAA','HHHHxx'
+1493,1810,1,1,3,13,93,493,1493,1493,1493,186,187,'LFAAAA','QRCAAA','OOOOxx'
+2584,1811,0,0,4,4,84,584,584,2584,2584,168,169,'KVAAAA','RRCAAA','VVVVxx'
+9502,1812,0,2,2,2,2,502,1502,4502,9502,4,5,'MBAAAA','SRCAAA','AAAAxx'
+4673,1813,1,1,3,13,73,673,673,4673,4673,146,147,'TXAAAA','TRCAAA','HHHHxx'
+7403,1814,1,3,3,3,3,403,1403,2403,7403,6,7,'TYAAAA','URCAAA','OOOOxx'
+7103,1815,1,3,3,3,3,103,1103,2103,7103,6,7,'FNAAAA','VRCAAA','VVVVxx'
+7026,1816,0,2,6,6,26,26,1026,2026,7026,52,53,'GKAAAA','WRCAAA','AAAAxx'
+8574,1817,0,2,4,14,74,574,574,3574,8574,148,149,'URAAAA','XRCAAA','HHHHxx'
+1366,1818,0,2,6,6,66,366,1366,1366,1366,132,133,'OAAAAA','YRCAAA','OOOOxx'
+5787,1819,1,3,7,7,87,787,1787,787,5787,174,175,'POAAAA','ZRCAAA','VVVVxx'
+2552,1820,0,0,2,12,52,552,552,2552,2552,104,105,'EUAAAA','ASCAAA','AAAAxx'
+4557,1821,1,1,7,17,57,557,557,4557,4557,114,115,'HTAAAA','BSCAAA','HHHHxx'
+3237,1822,1,1,7,17,37,237,1237,3237,3237,74,75,'NUAAAA','CSCAAA','OOOOxx'
+6901,1823,1,1,1,1,1,901,901,1901,6901,2,3,'LFAAAA','DSCAAA','VVVVxx'
+7708,1824,0,0,8,8,8,708,1708,2708,7708,16,17,'MKAAAA','ESCAAA','AAAAxx'
+2011,1825,1,3,1,11,11,11,11,2011,2011,22,23,'JZAAAA','FSCAAA','HHHHxx'
+9455,1826,1,3,5,15,55,455,1455,4455,9455,110,111,'RZAAAA','GSCAAA','OOOOxx'
+5228,1827,0,0,8,8,28,228,1228,228,5228,56,57,'CTAAAA','HSCAAA','VVVVxx'
+4043,1828,1,3,3,3,43,43,43,4043,4043,86,87,'NZAAAA','ISCAAA','AAAAxx'
+8242,1829,0,2,2,2,42,242,242,3242,8242,84,85,'AFAAAA','JSCAAA','HHHHxx'
+6351,1830,1,3,1,11,51,351,351,1351,6351,102,103,'HKAAAA','KSCAAA','OOOOxx'
+5899,1831,1,3,9,19,99,899,1899,899,5899,198,199,'XSAAAA','LSCAAA','VVVVxx'
+4849,1832,1,1,9,9,49,849,849,4849,4849,98,99,'NEAAAA','MSCAAA','AAAAxx'
+9583,1833,1,3,3,3,83,583,1583,4583,9583,166,167,'PEAAAA','NSCAAA','HHHHxx'
+4994,1834,0,2,4,14,94,994,994,4994,4994,188,189,'CKAAAA','OSCAAA','OOOOxx'
+9787,1835,1,3,7,7,87,787,1787,4787,9787,174,175,'LMAAAA','PSCAAA','VVVVxx'
+243,1836,1,3,3,3,43,243,243,243,243,86,87,'JJAAAA','QSCAAA','AAAAxx'
+3931,1837,1,3,1,11,31,931,1931,3931,3931,62,63,'FVAAAA','RSCAAA','HHHHxx'
+5945,1838,1,1,5,5,45,945,1945,945,5945,90,91,'RUAAAA','SSCAAA','OOOOxx'
+1325,1839,1,1,5,5,25,325,1325,1325,1325,50,51,'ZYAAAA','TSCAAA','VVVVxx'
+4142,1840,0,2,2,2,42,142,142,4142,4142,84,85,'IDAAAA','USCAAA','AAAAxx'
+1963,1841,1,3,3,3,63,963,1963,1963,1963,126,127,'NXAAAA','VSCAAA','HHHHxx'
+7041,1842,1,1,1,1,41,41,1041,2041,7041,82,83,'VKAAAA','WSCAAA','OOOOxx'
+3074,1843,0,2,4,14,74,74,1074,3074,3074,148,149,'GOAAAA','XSCAAA','VVVVxx'
+3290,1844,0,2,0,10,90,290,1290,3290,3290,180,181,'OWAAAA','YSCAAA','AAAAxx'
+4146,1845,0,2,6,6,46,146,146,4146,4146,92,93,'MDAAAA','ZSCAAA','HHHHxx'
+3832,1846,0,0,2,12,32,832,1832,3832,3832,64,65,'KRAAAA','ATCAAA','OOOOxx'
+2217,1847,1,1,7,17,17,217,217,2217,2217,34,35,'HHAAAA','BTCAAA','VVVVxx'
+635,1848,1,3,5,15,35,635,635,635,635,70,71,'LYAAAA','CTCAAA','AAAAxx'
+6967,1849,1,3,7,7,67,967,967,1967,6967,134,135,'ZHAAAA','DTCAAA','HHHHxx'
+3522,1850,0,2,2,2,22,522,1522,3522,3522,44,45,'MFAAAA','ETCAAA','OOOOxx'
+2471,1851,1,3,1,11,71,471,471,2471,2471,142,143,'BRAAAA','FTCAAA','VVVVxx'
+4236,1852,0,0,6,16,36,236,236,4236,4236,72,73,'YGAAAA','GTCAAA','AAAAxx'
+853,1853,1,1,3,13,53,853,853,853,853,106,107,'VGAAAA','HTCAAA','HHHHxx'
+3754,1854,0,2,4,14,54,754,1754,3754,3754,108,109,'KOAAAA','ITCAAA','OOOOxx'
+796,1855,0,0,6,16,96,796,796,796,796,192,193,'QEAAAA','JTCAAA','VVVVxx'
+4640,1856,0,0,0,0,40,640,640,4640,4640,80,81,'MWAAAA','KTCAAA','AAAAxx'
+9496,1857,0,0,6,16,96,496,1496,4496,9496,192,193,'GBAAAA','LTCAAA','HHHHxx'
+6873,1858,1,1,3,13,73,873,873,1873,6873,146,147,'JEAAAA','MTCAAA','OOOOxx'
+4632,1859,0,0,2,12,32,632,632,4632,4632,64,65,'EWAAAA','NTCAAA','VVVVxx'
+5758,1860,0,2,8,18,58,758,1758,758,5758,116,117,'MNAAAA','OTCAAA','AAAAxx'
+6514,1861,0,2,4,14,14,514,514,1514,6514,28,29,'OQAAAA','PTCAAA','HHHHxx'
+9510,1862,0,2,0,10,10,510,1510,4510,9510,20,21,'UBAAAA','QTCAAA','OOOOxx'
+8411,1863,1,3,1,11,11,411,411,3411,8411,22,23,'NLAAAA','RTCAAA','VVVVxx'
+7762,1864,0,2,2,2,62,762,1762,2762,7762,124,125,'OMAAAA','STCAAA','AAAAxx'
+2225,1865,1,1,5,5,25,225,225,2225,2225,50,51,'PHAAAA','TTCAAA','HHHHxx'
+4373,1866,1,1,3,13,73,373,373,4373,4373,146,147,'FMAAAA','UTCAAA','OOOOxx'
+7326,1867,0,2,6,6,26,326,1326,2326,7326,52,53,'UVAAAA','VTCAAA','VVVVxx'
+8651,1868,1,3,1,11,51,651,651,3651,8651,102,103,'TUAAAA','WTCAAA','AAAAxx'
+9825,1869,1,1,5,5,25,825,1825,4825,9825,50,51,'XNAAAA','XTCAAA','HHHHxx'
+2988,1870,0,0,8,8,88,988,988,2988,2988,176,177,'YKAAAA','YTCAAA','OOOOxx'
+8138,1871,0,2,8,18,38,138,138,3138,8138,76,77,'ABAAAA','ZTCAAA','VVVVxx'
+7792,1872,0,0,2,12,92,792,1792,2792,7792,184,185,'SNAAAA','AUCAAA','AAAAxx'
+1232,1873,0,0,2,12,32,232,1232,1232,1232,64,65,'KVAAAA','BUCAAA','HHHHxx'
+8221,1874,1,1,1,1,21,221,221,3221,8221,42,43,'FEAAAA','CUCAAA','OOOOxx'
+4044,1875,0,0,4,4,44,44,44,4044,4044,88,89,'OZAAAA','DUCAAA','VVVVxx'
+1204,1876,0,0,4,4,4,204,1204,1204,1204,8,9,'IUAAAA','EUCAAA','AAAAxx'
+5145,1877,1,1,5,5,45,145,1145,145,5145,90,91,'XPAAAA','FUCAAA','HHHHxx'
+7791,1878,1,3,1,11,91,791,1791,2791,7791,182,183,'RNAAAA','GUCAAA','OOOOxx'
+8270,1879,0,2,0,10,70,270,270,3270,8270,140,141,'CGAAAA','HUCAAA','VVVVxx'
+9427,1880,1,3,7,7,27,427,1427,4427,9427,54,55,'PYAAAA','IUCAAA','AAAAxx'
+2152,1881,0,0,2,12,52,152,152,2152,2152,104,105,'UEAAAA','JUCAAA','HHHHxx'
+7790,1882,0,2,0,10,90,790,1790,2790,7790,180,181,'QNAAAA','KUCAAA','OOOOxx'
+5301,1883,1,1,1,1,1,301,1301,301,5301,2,3,'XVAAAA','LUCAAA','VVVVxx'
+626,1884,0,2,6,6,26,626,626,626,626,52,53,'CYAAAA','MUCAAA','AAAAxx'
+260,1885,0,0,0,0,60,260,260,260,260,120,121,'AKAAAA','NUCAAA','HHHHxx'
+4369,1886,1,1,9,9,69,369,369,4369,4369,138,139,'BMAAAA','OUCAAA','OOOOxx'
+5457,1887,1,1,7,17,57,457,1457,457,5457,114,115,'XBAAAA','PUCAAA','VVVVxx'
+3468,1888,0,0,8,8,68,468,1468,3468,3468,136,137,'KDAAAA','QUCAAA','AAAAxx'
+2257,1889,1,1,7,17,57,257,257,2257,2257,114,115,'VIAAAA','RUCAAA','HHHHxx'
+9318,1890,0,2,8,18,18,318,1318,4318,9318,36,37,'KUAAAA','SUCAAA','OOOOxx'
+8762,1891,0,2,2,2,62,762,762,3762,8762,124,125,'AZAAAA','TUCAAA','VVVVxx'
+9153,1892,1,1,3,13,53,153,1153,4153,9153,106,107,'BOAAAA','UUCAAA','AAAAxx'
+9220,1893,0,0,0,0,20,220,1220,4220,9220,40,41,'QQAAAA','VUCAAA','HHHHxx'
+8003,1894,1,3,3,3,3,3,3,3003,8003,6,7,'VVAAAA','WUCAAA','OOOOxx'
+7257,1895,1,1,7,17,57,257,1257,2257,7257,114,115,'DTAAAA','XUCAAA','VVVVxx'
+3930,1896,0,2,0,10,30,930,1930,3930,3930,60,61,'EVAAAA','YUCAAA','AAAAxx'
+2976,1897,0,0,6,16,76,976,976,2976,2976,152,153,'MKAAAA','ZUCAAA','HHHHxx'
+2531,1898,1,3,1,11,31,531,531,2531,2531,62,63,'JTAAAA','AVCAAA','OOOOxx'
+2250,1899,0,2,0,10,50,250,250,2250,2250,100,101,'OIAAAA','BVCAAA','VVVVxx'
+8549,1900,1,1,9,9,49,549,549,3549,8549,98,99,'VQAAAA','CVCAAA','AAAAxx'
+7197,1901,1,1,7,17,97,197,1197,2197,7197,194,195,'VQAAAA','DVCAAA','HHHHxx'
+5916,1902,0,0,6,16,16,916,1916,916,5916,32,33,'OTAAAA','EVCAAA','OOOOxx'
+5287,1903,1,3,7,7,87,287,1287,287,5287,174,175,'JVAAAA','FVCAAA','VVVVxx'
+9095,1904,1,3,5,15,95,95,1095,4095,9095,190,191,'VLAAAA','GVCAAA','AAAAxx'
+7137,1905,1,1,7,17,37,137,1137,2137,7137,74,75,'NOAAAA','HVCAAA','HHHHxx'
+7902,1906,0,2,2,2,2,902,1902,2902,7902,4,5,'YRAAAA','IVCAAA','OOOOxx'
+7598,1907,0,2,8,18,98,598,1598,2598,7598,196,197,'GGAAAA','JVCAAA','VVVVxx'
+5652,1908,0,0,2,12,52,652,1652,652,5652,104,105,'KJAAAA','KVCAAA','AAAAxx'
+2017,1909,1,1,7,17,17,17,17,2017,2017,34,35,'PZAAAA','LVCAAA','HHHHxx'
+7255,1910,1,3,5,15,55,255,1255,2255,7255,110,111,'BTAAAA','MVCAAA','OOOOxx'
+7999,1911,1,3,9,19,99,999,1999,2999,7999,198,199,'RVAAAA','NVCAAA','VVVVxx'
+5388,1912,0,0,8,8,88,388,1388,388,5388,176,177,'GZAAAA','OVCAAA','AAAAxx'
+8754,1913,0,2,4,14,54,754,754,3754,8754,108,109,'SYAAAA','PVCAAA','HHHHxx'
+5415,1914,1,3,5,15,15,415,1415,415,5415,30,31,'HAAAAA','QVCAAA','OOOOxx'
+8861,1915,1,1,1,1,61,861,861,3861,8861,122,123,'VCAAAA','RVCAAA','VVVVxx'
+2874,1916,0,2,4,14,74,874,874,2874,2874,148,149,'OGAAAA','SVCAAA','AAAAxx'
+9910,1917,0,2,0,10,10,910,1910,4910,9910,20,21,'ERAAAA','TVCAAA','HHHHxx'
+5178,1918,0,2,8,18,78,178,1178,178,5178,156,157,'ERAAAA','UVCAAA','OOOOxx'
+5698,1919,0,2,8,18,98,698,1698,698,5698,196,197,'ELAAAA','VVCAAA','VVVVxx'
+8500,1920,0,0,0,0,0,500,500,3500,8500,0,1,'YOAAAA','WVCAAA','AAAAxx'
+1814,1921,0,2,4,14,14,814,1814,1814,1814,28,29,'URAAAA','XVCAAA','HHHHxx'
+4968,1922,0,0,8,8,68,968,968,4968,4968,136,137,'CJAAAA','YVCAAA','OOOOxx'
+2642,1923,0,2,2,2,42,642,642,2642,2642,84,85,'QXAAAA','ZVCAAA','VVVVxx'
+1578,1924,0,2,8,18,78,578,1578,1578,1578,156,157,'SIAAAA','AWCAAA','AAAAxx'
+4774,1925,0,2,4,14,74,774,774,4774,4774,148,149,'QBAAAA','BWCAAA','HHHHxx'
+7062,1926,0,2,2,2,62,62,1062,2062,7062,124,125,'QLAAAA','CWCAAA','OOOOxx'
+5381,1927,1,1,1,1,81,381,1381,381,5381,162,163,'ZYAAAA','DWCAAA','VVVVxx'
+7985,1928,1,1,5,5,85,985,1985,2985,7985,170,171,'DVAAAA','EWCAAA','AAAAxx'
+3850,1929,0,2,0,10,50,850,1850,3850,3850,100,101,'CSAAAA','FWCAAA','HHHHxx'
+5624,1930,0,0,4,4,24,624,1624,624,5624,48,49,'IIAAAA','GWCAAA','OOOOxx'
+8948,1931,0,0,8,8,48,948,948,3948,8948,96,97,'EGAAAA','HWCAAA','VVVVxx'
+995,1932,1,3,5,15,95,995,995,995,995,190,191,'HMAAAA','IWCAAA','AAAAxx'
+5058,1933,0,2,8,18,58,58,1058,58,5058,116,117,'OMAAAA','JWCAAA','HHHHxx'
+9670,1934,0,2,0,10,70,670,1670,4670,9670,140,141,'YHAAAA','KWCAAA','OOOOxx'
+3115,1935,1,3,5,15,15,115,1115,3115,3115,30,31,'VPAAAA','LWCAAA','VVVVxx'
+4935,1936,1,3,5,15,35,935,935,4935,4935,70,71,'VHAAAA','MWCAAA','AAAAxx'
+4735,1937,1,3,5,15,35,735,735,4735,4735,70,71,'DAAAAA','NWCAAA','HHHHxx'
+1348,1938,0,0,8,8,48,348,1348,1348,1348,96,97,'WZAAAA','OWCAAA','OOOOxx'
+2380,1939,0,0,0,0,80,380,380,2380,2380,160,161,'ONAAAA','PWCAAA','VVVVxx'
+4246,1940,0,2,6,6,46,246,246,4246,4246,92,93,'IHAAAA','QWCAAA','AAAAxx'
+522,1941,0,2,2,2,22,522,522,522,522,44,45,'CUAAAA','RWCAAA','HHHHxx'
+1701,1942,1,1,1,1,1,701,1701,1701,1701,2,3,'LNAAAA','SWCAAA','OOOOxx'
+9709,1943,1,1,9,9,9,709,1709,4709,9709,18,19,'LJAAAA','TWCAAA','VVVVxx'
+8829,1944,1,1,9,9,29,829,829,3829,8829,58,59,'PBAAAA','UWCAAA','AAAAxx'
+7936,1945,0,0,6,16,36,936,1936,2936,7936,72,73,'GTAAAA','VWCAAA','HHHHxx'
+8474,1946,0,2,4,14,74,474,474,3474,8474,148,149,'YNAAAA','WWCAAA','OOOOxx'
+4676,1947,0,0,6,16,76,676,676,4676,4676,152,153,'WXAAAA','XWCAAA','VVVVxx'
+6303,1948,1,3,3,3,3,303,303,1303,6303,6,7,'LIAAAA','YWCAAA','AAAAxx'
+3485,1949,1,1,5,5,85,485,1485,3485,3485,170,171,'BEAAAA','ZWCAAA','HHHHxx'
+2695,1950,1,3,5,15,95,695,695,2695,2695,190,191,'RZAAAA','AXCAAA','OOOOxx'
+8830,1951,0,2,0,10,30,830,830,3830,8830,60,61,'QBAAAA','BXCAAA','VVVVxx'
+898,1952,0,2,8,18,98,898,898,898,898,196,197,'OIAAAA','CXCAAA','AAAAxx'
+7268,1953,0,0,8,8,68,268,1268,2268,7268,136,137,'OTAAAA','DXCAAA','HHHHxx'
+6568,1954,0,0,8,8,68,568,568,1568,6568,136,137,'QSAAAA','EXCAAA','OOOOxx'
+9724,1955,0,0,4,4,24,724,1724,4724,9724,48,49,'AKAAAA','FXCAAA','VVVVxx'
+3329,1956,1,1,9,9,29,329,1329,3329,3329,58,59,'BYAAAA','GXCAAA','AAAAxx'
+9860,1957,0,0,0,0,60,860,1860,4860,9860,120,121,'GPAAAA','HXCAAA','HHHHxx'
+6833,1958,1,1,3,13,33,833,833,1833,6833,66,67,'VCAAAA','IXCAAA','OOOOxx'
+5956,1959,0,0,6,16,56,956,1956,956,5956,112,113,'CVAAAA','JXCAAA','VVVVxx'
+3963,1960,1,3,3,3,63,963,1963,3963,3963,126,127,'LWAAAA','KXCAAA','AAAAxx'
+883,1961,1,3,3,3,83,883,883,883,883,166,167,'ZHAAAA','LXCAAA','HHHHxx'
+2761,1962,1,1,1,1,61,761,761,2761,2761,122,123,'FCAAAA','MXCAAA','OOOOxx'
+4644,1963,0,0,4,4,44,644,644,4644,4644,88,89,'QWAAAA','NXCAAA','VVVVxx'
+1358,1964,0,2,8,18,58,358,1358,1358,1358,116,117,'GAAAAA','OXCAAA','AAAAxx'
+2049,1965,1,1,9,9,49,49,49,2049,2049,98,99,'VAAAAA','PXCAAA','HHHHxx'
+2193,1966,1,1,3,13,93,193,193,2193,2193,186,187,'JGAAAA','QXCAAA','OOOOxx'
+9435,1967,1,3,5,15,35,435,1435,4435,9435,70,71,'XYAAAA','RXCAAA','VVVVxx'
+5890,1968,0,2,0,10,90,890,1890,890,5890,180,181,'OSAAAA','SXCAAA','AAAAxx'
+8149,1969,1,1,9,9,49,149,149,3149,8149,98,99,'LBAAAA','TXCAAA','HHHHxx'
+423,1970,1,3,3,3,23,423,423,423,423,46,47,'HQAAAA','UXCAAA','OOOOxx'
+7980,1971,0,0,0,0,80,980,1980,2980,7980,160,161,'YUAAAA','VXCAAA','VVVVxx'
+9019,1972,1,3,9,19,19,19,1019,4019,9019,38,39,'XIAAAA','WXCAAA','AAAAxx'
+1647,1973,1,3,7,7,47,647,1647,1647,1647,94,95,'JLAAAA','XXCAAA','HHHHxx'
+9495,1974,1,3,5,15,95,495,1495,4495,9495,190,191,'FBAAAA','YXCAAA','OOOOxx'
+3904,1975,0,0,4,4,4,904,1904,3904,3904,8,9,'EUAAAA','ZXCAAA','VVVVxx'
+5838,1976,0,2,8,18,38,838,1838,838,5838,76,77,'OQAAAA','AYCAAA','AAAAxx'
+3866,1977,0,2,6,6,66,866,1866,3866,3866,132,133,'SSAAAA','BYCAAA','HHHHxx'
+3093,1978,1,1,3,13,93,93,1093,3093,3093,186,187,'ZOAAAA','CYCAAA','OOOOxx'
+9666,1979,0,2,6,6,66,666,1666,4666,9666,132,133,'UHAAAA','DYCAAA','VVVVxx'
+1246,1980,0,2,6,6,46,246,1246,1246,1246,92,93,'YVAAAA','EYCAAA','AAAAxx'
+9759,1981,1,3,9,19,59,759,1759,4759,9759,118,119,'JLAAAA','FYCAAA','HHHHxx'
+7174,1982,0,2,4,14,74,174,1174,2174,7174,148,149,'YPAAAA','GYCAAA','OOOOxx'
+7678,1983,0,2,8,18,78,678,1678,2678,7678,156,157,'IJAAAA','HYCAAA','VVVVxx'
+3004,1984,0,0,4,4,4,4,1004,3004,3004,8,9,'OLAAAA','IYCAAA','AAAAxx'
+5607,1985,1,3,7,7,7,607,1607,607,5607,14,15,'RHAAAA','JYCAAA','HHHHxx'
+8510,1986,0,2,0,10,10,510,510,3510,8510,20,21,'IPAAAA','KYCAAA','OOOOxx'
+1483,1987,1,3,3,3,83,483,1483,1483,1483,166,167,'BFAAAA','LYCAAA','VVVVxx'
+2915,1988,1,3,5,15,15,915,915,2915,2915,30,31,'DIAAAA','MYCAAA','AAAAxx'
+1548,1989,0,0,8,8,48,548,1548,1548,1548,96,97,'OHAAAA','NYCAAA','HHHHxx'
+5767,1990,1,3,7,7,67,767,1767,767,5767,134,135,'VNAAAA','OYCAAA','OOOOxx'
+3214,1991,0,2,4,14,14,214,1214,3214,3214,28,29,'QTAAAA','PYCAAA','VVVVxx'
+8663,1992,1,3,3,3,63,663,663,3663,8663,126,127,'FVAAAA','QYCAAA','AAAAxx'
+5425,1993,1,1,5,5,25,425,1425,425,5425,50,51,'RAAAAA','RYCAAA','HHHHxx'
+8530,1994,0,2,0,10,30,530,530,3530,8530,60,61,'CQAAAA','SYCAAA','OOOOxx'
+821,1995,1,1,1,1,21,821,821,821,821,42,43,'PFAAAA','TYCAAA','VVVVxx'
+8816,1996,0,0,6,16,16,816,816,3816,8816,32,33,'CBAAAA','UYCAAA','AAAAxx'
+9367,1997,1,3,7,7,67,367,1367,4367,9367,134,135,'HWAAAA','VYCAAA','HHHHxx'
+4138,1998,0,2,8,18,38,138,138,4138,4138,76,77,'EDAAAA','WYCAAA','OOOOxx'
+94,1999,0,2,4,14,94,94,94,94,94,188,189,'QDAAAA','XYCAAA','VVVVxx'
+1858,2000,0,2,8,18,58,858,1858,1858,1858,116,117,'MTAAAA','YYCAAA','AAAAxx'
+5513,2001,1,1,3,13,13,513,1513,513,5513,26,27,'BEAAAA','ZYCAAA','HHHHxx'
+9620,2002,0,0,0,0,20,620,1620,4620,9620,40,41,'AGAAAA','AZCAAA','OOOOxx'
+4770,2003,0,2,0,10,70,770,770,4770,4770,140,141,'MBAAAA','BZCAAA','VVVVxx'
+5193,2004,1,1,3,13,93,193,1193,193,5193,186,187,'TRAAAA','CZCAAA','AAAAxx'
+198,2005,0,2,8,18,98,198,198,198,198,196,197,'QHAAAA','DZCAAA','HHHHxx'
+417,2006,1,1,7,17,17,417,417,417,417,34,35,'BQAAAA','EZCAAA','OOOOxx'
+173,2007,1,1,3,13,73,173,173,173,173,146,147,'RGAAAA','FZCAAA','VVVVxx'
+6248,2008,0,0,8,8,48,248,248,1248,6248,96,97,'IGAAAA','GZCAAA','AAAAxx'
+302,2009,0,2,2,2,2,302,302,302,302,4,5,'QLAAAA','HZCAAA','HHHHxx'
+8983,2010,1,3,3,3,83,983,983,3983,8983,166,167,'NHAAAA','IZCAAA','OOOOxx'
+4840,2011,0,0,0,0,40,840,840,4840,4840,80,81,'EEAAAA','JZCAAA','VVVVxx'
+2876,2012,0,0,6,16,76,876,876,2876,2876,152,153,'QGAAAA','KZCAAA','AAAAxx'
+5841,2013,1,1,1,1,41,841,1841,841,5841,82,83,'RQAAAA','LZCAAA','HHHHxx'
+2766,2014,0,2,6,6,66,766,766,2766,2766,132,133,'KCAAAA','MZCAAA','OOOOxx'
+9482,2015,0,2,2,2,82,482,1482,4482,9482,164,165,'SAAAAA','NZCAAA','VVVVxx'
+5335,2016,1,3,5,15,35,335,1335,335,5335,70,71,'FXAAAA','OZCAAA','AAAAxx'
+1502,2017,0,2,2,2,2,502,1502,1502,1502,4,5,'UFAAAA','PZCAAA','HHHHxx'
+9291,2018,1,3,1,11,91,291,1291,4291,9291,182,183,'JTAAAA','QZCAAA','OOOOxx'
+8655,2019,1,3,5,15,55,655,655,3655,8655,110,111,'XUAAAA','RZCAAA','VVVVxx'
+1687,2020,1,3,7,7,87,687,1687,1687,1687,174,175,'XMAAAA','SZCAAA','AAAAxx'
+8171,2021,1,3,1,11,71,171,171,3171,8171,142,143,'HCAAAA','TZCAAA','HHHHxx'
+5699,2022,1,3,9,19,99,699,1699,699,5699,198,199,'FLAAAA','UZCAAA','OOOOxx'
+1462,2023,0,2,2,2,62,462,1462,1462,1462,124,125,'GEAAAA','VZCAAA','VVVVxx'
+608,2024,0,0,8,8,8,608,608,608,608,16,17,'KXAAAA','WZCAAA','AAAAxx'
+6860,2025,0,0,0,0,60,860,860,1860,6860,120,121,'WDAAAA','XZCAAA','HHHHxx'
+6063,2026,1,3,3,3,63,63,63,1063,6063,126,127,'FZAAAA','YZCAAA','OOOOxx'
+1422,2027,0,2,2,2,22,422,1422,1422,1422,44,45,'SCAAAA','ZZCAAA','VVVVxx'
+1932,2028,0,0,2,12,32,932,1932,1932,1932,64,65,'IWAAAA','AADAAA','AAAAxx'
+5065,2029,1,1,5,5,65,65,1065,65,5065,130,131,'VMAAAA','BADAAA','HHHHxx'
+432,2030,0,0,2,12,32,432,432,432,432,64,65,'QQAAAA','CADAAA','OOOOxx'
+4680,2031,0,0,0,0,80,680,680,4680,4680,160,161,'AYAAAA','DADAAA','VVVVxx'
+8172,2032,0,0,2,12,72,172,172,3172,8172,144,145,'ICAAAA','EADAAA','AAAAxx'
+8668,2033,0,0,8,8,68,668,668,3668,8668,136,137,'KVAAAA','FADAAA','HHHHxx'
+256,2034,0,0,6,16,56,256,256,256,256,112,113,'WJAAAA','GADAAA','OOOOxx'
+2500,2035,0,0,0,0,0,500,500,2500,2500,0,1,'ESAAAA','HADAAA','VVVVxx'
+274,2036,0,2,4,14,74,274,274,274,274,148,149,'OKAAAA','IADAAA','AAAAxx'
+5907,2037,1,3,7,7,7,907,1907,907,5907,14,15,'FTAAAA','JADAAA','HHHHxx'
+8587,2038,1,3,7,7,87,587,587,3587,8587,174,175,'HSAAAA','KADAAA','OOOOxx'
+9942,2039,0,2,2,2,42,942,1942,4942,9942,84,85,'KSAAAA','LADAAA','VVVVxx'
+116,2040,0,0,6,16,16,116,116,116,116,32,33,'MEAAAA','MADAAA','AAAAxx'
+7134,2041,0,2,4,14,34,134,1134,2134,7134,68,69,'KOAAAA','NADAAA','HHHHxx'
+9002,2042,0,2,2,2,2,2,1002,4002,9002,4,5,'GIAAAA','OADAAA','OOOOxx'
+1209,2043,1,1,9,9,9,209,1209,1209,1209,18,19,'NUAAAA','PADAAA','VVVVxx'
+9983,2044,1,3,3,3,83,983,1983,4983,9983,166,167,'ZTAAAA','QADAAA','AAAAxx'
+1761,2045,1,1,1,1,61,761,1761,1761,1761,122,123,'TPAAAA','RADAAA','HHHHxx'
+7723,2046,1,3,3,3,23,723,1723,2723,7723,46,47,'BLAAAA','SADAAA','OOOOxx'
+6518,2047,0,2,8,18,18,518,518,1518,6518,36,37,'SQAAAA','TADAAA','VVVVxx'
+1372,2048,0,0,2,12,72,372,1372,1372,1372,144,145,'UAAAAA','UADAAA','AAAAxx'
+3587,2049,1,3,7,7,87,587,1587,3587,3587,174,175,'ZHAAAA','VADAAA','HHHHxx'
+5323,2050,1,3,3,3,23,323,1323,323,5323,46,47,'TWAAAA','WADAAA','OOOOxx'
+5902,2051,0,2,2,2,2,902,1902,902,5902,4,5,'ATAAAA','XADAAA','VVVVxx'
+3749,2052,1,1,9,9,49,749,1749,3749,3749,98,99,'FOAAAA','YADAAA','AAAAxx'
+5965,2053,1,1,5,5,65,965,1965,965,5965,130,131,'LVAAAA','ZADAAA','HHHHxx'
+663,2054,1,3,3,3,63,663,663,663,663,126,127,'NZAAAA','ABDAAA','OOOOxx'
+36,2055,0,0,6,16,36,36,36,36,36,72,73,'KBAAAA','BBDAAA','VVVVxx'
+9782,2056,0,2,2,2,82,782,1782,4782,9782,164,165,'GMAAAA','CBDAAA','AAAAxx'
+5412,2057,0,0,2,12,12,412,1412,412,5412,24,25,'EAAAAA','DBDAAA','HHHHxx'
+9961,2058,1,1,1,1,61,961,1961,4961,9961,122,123,'DTAAAA','EBDAAA','OOOOxx'
+6492,2059,0,0,2,12,92,492,492,1492,6492,184,185,'SPAAAA','FBDAAA','VVVVxx'
+4234,2060,0,2,4,14,34,234,234,4234,4234,68,69,'WGAAAA','GBDAAA','AAAAxx'
+4922,2061,0,2,2,2,22,922,922,4922,4922,44,45,'IHAAAA','HBDAAA','HHHHxx'
+6166,2062,0,2,6,6,66,166,166,1166,6166,132,133,'EDAAAA','IBDAAA','OOOOxx'
+7019,2063,1,3,9,19,19,19,1019,2019,7019,38,39,'ZJAAAA','JBDAAA','VVVVxx'
+7805,2064,1,1,5,5,5,805,1805,2805,7805,10,11,'FOAAAA','KBDAAA','AAAAxx'
+9808,2065,0,0,8,8,8,808,1808,4808,9808,16,17,'GNAAAA','LBDAAA','HHHHxx'
+2550,2066,0,2,0,10,50,550,550,2550,2550,100,101,'CUAAAA','MBDAAA','OOOOxx'
+8626,2067,0,2,6,6,26,626,626,3626,8626,52,53,'UTAAAA','NBDAAA','VVVVxx'
+5649,2068,1,1,9,9,49,649,1649,649,5649,98,99,'HJAAAA','OBDAAA','AAAAxx'
+3117,2069,1,1,7,17,17,117,1117,3117,3117,34,35,'XPAAAA','PBDAAA','HHHHxx'
+866,2070,0,2,6,6,66,866,866,866,866,132,133,'IHAAAA','QBDAAA','OOOOxx'
+2323,2071,1,3,3,3,23,323,323,2323,2323,46,47,'JLAAAA','RBDAAA','VVVVxx'
+5132,2072,0,0,2,12,32,132,1132,132,5132,64,65,'KPAAAA','SBDAAA','AAAAxx'
+9222,2073,0,2,2,2,22,222,1222,4222,9222,44,45,'SQAAAA','TBDAAA','HHHHxx'
+3934,2074,0,2,4,14,34,934,1934,3934,3934,68,69,'IVAAAA','UBDAAA','OOOOxx'
+4845,2075,1,1,5,5,45,845,845,4845,4845,90,91,'JEAAAA','VBDAAA','VVVVxx'
+7714,2076,0,2,4,14,14,714,1714,2714,7714,28,29,'SKAAAA','WBDAAA','AAAAxx'
+9818,2077,0,2,8,18,18,818,1818,4818,9818,36,37,'QNAAAA','XBDAAA','HHHHxx'
+2219,2078,1,3,9,19,19,219,219,2219,2219,38,39,'JHAAAA','YBDAAA','OOOOxx'
+6573,2079,1,1,3,13,73,573,573,1573,6573,146,147,'VSAAAA','ZBDAAA','VVVVxx'
+4555,2080,1,3,5,15,55,555,555,4555,4555,110,111,'FTAAAA','ACDAAA','AAAAxx'
+7306,2081,0,2,6,6,6,306,1306,2306,7306,12,13,'AVAAAA','BCDAAA','HHHHxx'
+9313,2082,1,1,3,13,13,313,1313,4313,9313,26,27,'FUAAAA','CCDAAA','OOOOxx'
+3924,2083,0,0,4,4,24,924,1924,3924,3924,48,49,'YUAAAA','DCDAAA','VVVVxx'
+5176,2084,0,0,6,16,76,176,1176,176,5176,152,153,'CRAAAA','ECDAAA','AAAAxx'
+9767,2085,1,3,7,7,67,767,1767,4767,9767,134,135,'RLAAAA','FCDAAA','HHHHxx'
+905,2086,1,1,5,5,5,905,905,905,905,10,11,'VIAAAA','GCDAAA','OOOOxx'
+8037,2087,1,1,7,17,37,37,37,3037,8037,74,75,'DXAAAA','HCDAAA','VVVVxx'
+8133,2088,1,1,3,13,33,133,133,3133,8133,66,67,'VAAAAA','ICDAAA','AAAAxx'
+2954,2089,0,2,4,14,54,954,954,2954,2954,108,109,'QJAAAA','JCDAAA','HHHHxx'
+7262,2090,0,2,2,2,62,262,1262,2262,7262,124,125,'ITAAAA','KCDAAA','OOOOxx'
+8768,2091,0,0,8,8,68,768,768,3768,8768,136,137,'GZAAAA','LCDAAA','VVVVxx'
+6953,2092,1,1,3,13,53,953,953,1953,6953,106,107,'LHAAAA','MCDAAA','AAAAxx'
+1984,2093,0,0,4,4,84,984,1984,1984,1984,168,169,'IYAAAA','NCDAAA','HHHHxx'
+9348,2094,0,0,8,8,48,348,1348,4348,9348,96,97,'OVAAAA','OCDAAA','OOOOxx'
+7769,2095,1,1,9,9,69,769,1769,2769,7769,138,139,'VMAAAA','PCDAAA','VVVVxx'
+2994,2096,0,2,4,14,94,994,994,2994,2994,188,189,'ELAAAA','QCDAAA','AAAAxx'
+5938,2097,0,2,8,18,38,938,1938,938,5938,76,77,'KUAAAA','RCDAAA','HHHHxx'
+556,2098,0,0,6,16,56,556,556,556,556,112,113,'KVAAAA','SCDAAA','OOOOxx'
+2577,2099,1,1,7,17,77,577,577,2577,2577,154,155,'DVAAAA','TCDAAA','VVVVxx'
+8733,2100,1,1,3,13,33,733,733,3733,8733,66,67,'XXAAAA','UCDAAA','AAAAxx'
+3108,2101,0,0,8,8,8,108,1108,3108,3108,16,17,'OPAAAA','VCDAAA','HHHHxx'
+4166,2102,0,2,6,6,66,166,166,4166,4166,132,133,'GEAAAA','WCDAAA','OOOOxx'
+3170,2103,0,2,0,10,70,170,1170,3170,3170,140,141,'YRAAAA','XCDAAA','VVVVxx'
+8118,2104,0,2,8,18,18,118,118,3118,8118,36,37,'GAAAAA','YCDAAA','AAAAxx'
+8454,2105,0,2,4,14,54,454,454,3454,8454,108,109,'ENAAAA','ZCDAAA','HHHHxx'
+5338,2106,0,2,8,18,38,338,1338,338,5338,76,77,'IXAAAA','ADDAAA','OOOOxx'
+402,2107,0,2,2,2,2,402,402,402,402,4,5,'MPAAAA','BDDAAA','VVVVxx'
+5673,2108,1,1,3,13,73,673,1673,673,5673,146,147,'FKAAAA','CDDAAA','AAAAxx'
+4324,2109,0,0,4,4,24,324,324,4324,4324,48,49,'IKAAAA','DDDAAA','HHHHxx'
+1943,2110,1,3,3,3,43,943,1943,1943,1943,86,87,'TWAAAA','EDDAAA','OOOOxx'
+7703,2111,1,3,3,3,3,703,1703,2703,7703,6,7,'HKAAAA','FDDAAA','VVVVxx'
+7180,2112,0,0,0,0,80,180,1180,2180,7180,160,161,'EQAAAA','GDDAAA','AAAAxx'
+5478,2113,0,2,8,18,78,478,1478,478,5478,156,157,'SCAAAA','HDDAAA','HHHHxx'
+5775,2114,1,3,5,15,75,775,1775,775,5775,150,151,'DOAAAA','IDDAAA','OOOOxx'
+6952,2115,0,0,2,12,52,952,952,1952,6952,104,105,'KHAAAA','JDDAAA','VVVVxx'
+9022,2116,0,2,2,2,22,22,1022,4022,9022,44,45,'AJAAAA','KDDAAA','AAAAxx'
+547,2117,1,3,7,7,47,547,547,547,547,94,95,'BVAAAA','LDDAAA','HHHHxx'
+5877,2118,1,1,7,17,77,877,1877,877,5877,154,155,'BSAAAA','MDDAAA','OOOOxx'
+9580,2119,0,0,0,0,80,580,1580,4580,9580,160,161,'MEAAAA','NDDAAA','VVVVxx'
+6094,2120,0,2,4,14,94,94,94,1094,6094,188,189,'KAAAAA','ODDAAA','AAAAxx'
+3398,2121,0,2,8,18,98,398,1398,3398,3398,196,197,'SAAAAA','PDDAAA','HHHHxx'
+4574,2122,0,2,4,14,74,574,574,4574,4574,148,149,'YTAAAA','QDDAAA','OOOOxx'
+3675,2123,1,3,5,15,75,675,1675,3675,3675,150,151,'JLAAAA','RDDAAA','VVVVxx'
+6413,2124,1,1,3,13,13,413,413,1413,6413,26,27,'RMAAAA','SDDAAA','AAAAxx'
+9851,2125,1,3,1,11,51,851,1851,4851,9851,102,103,'XOAAAA','TDDAAA','HHHHxx'
+126,2126,0,2,6,6,26,126,126,126,126,52,53,'WEAAAA','UDDAAA','OOOOxx'
+6803,2127,1,3,3,3,3,803,803,1803,6803,6,7,'RBAAAA','VDDAAA','VVVVxx'
+6949,2128,1,1,9,9,49,949,949,1949,6949,98,99,'HHAAAA','WDDAAA','AAAAxx'
+115,2129,1,3,5,15,15,115,115,115,115,30,31,'LEAAAA','XDDAAA','HHHHxx'
+4165,2130,1,1,5,5,65,165,165,4165,4165,130,131,'FEAAAA','YDDAAA','OOOOxx'
+201,2131,1,1,1,1,1,201,201,201,201,2,3,'THAAAA','ZDDAAA','VVVVxx'
+9324,2132,0,0,4,4,24,324,1324,4324,9324,48,49,'QUAAAA','AEDAAA','AAAAxx'
+6562,2133,0,2,2,2,62,562,562,1562,6562,124,125,'KSAAAA','BEDAAA','HHHHxx'
+1917,2134,1,1,7,17,17,917,1917,1917,1917,34,35,'TVAAAA','CEDAAA','OOOOxx'
+558,2135,0,2,8,18,58,558,558,558,558,116,117,'MVAAAA','DEDAAA','VVVVxx'
+8515,2136,1,3,5,15,15,515,515,3515,8515,30,31,'NPAAAA','EEDAAA','AAAAxx'
+6321,2137,1,1,1,1,21,321,321,1321,6321,42,43,'DJAAAA','FEDAAA','HHHHxx'
+6892,2138,0,0,2,12,92,892,892,1892,6892,184,185,'CFAAAA','GEDAAA','OOOOxx'
+1001,2139,1,1,1,1,1,1,1001,1001,1001,2,3,'NMAAAA','HEDAAA','VVVVxx'
+2858,2140,0,2,8,18,58,858,858,2858,2858,116,117,'YFAAAA','IEDAAA','AAAAxx'
+2434,2141,0,2,4,14,34,434,434,2434,2434,68,69,'QPAAAA','JEDAAA','HHHHxx'
+4460,2142,0,0,0,0,60,460,460,4460,4460,120,121,'OPAAAA','KEDAAA','OOOOxx'
+5447,2143,1,3,7,7,47,447,1447,447,5447,94,95,'NBAAAA','LEDAAA','VVVVxx'
+3799,2144,1,3,9,19,99,799,1799,3799,3799,198,199,'DQAAAA','MEDAAA','AAAAxx'
+4310,2145,0,2,0,10,10,310,310,4310,4310,20,21,'UJAAAA','NEDAAA','HHHHxx'
+405,2146,1,1,5,5,5,405,405,405,405,10,11,'PPAAAA','OEDAAA','OOOOxx'
+4573,2147,1,1,3,13,73,573,573,4573,4573,146,147,'XTAAAA','PEDAAA','VVVVxx'
+706,2148,0,2,6,6,6,706,706,706,706,12,13,'EBAAAA','QEDAAA','AAAAxx'
+7619,2149,1,3,9,19,19,619,1619,2619,7619,38,39,'BHAAAA','REDAAA','HHHHxx'
+7959,2150,1,3,9,19,59,959,1959,2959,7959,118,119,'DUAAAA','SEDAAA','OOOOxx'
+6712,2151,0,0,2,12,12,712,712,1712,6712,24,25,'EYAAAA','TEDAAA','VVVVxx'
+6959,2152,1,3,9,19,59,959,959,1959,6959,118,119,'RHAAAA','UEDAAA','AAAAxx'
+9791,2153,1,3,1,11,91,791,1791,4791,9791,182,183,'PMAAAA','VEDAAA','HHHHxx'
+2112,2154,0,0,2,12,12,112,112,2112,2112,24,25,'GDAAAA','WEDAAA','OOOOxx'
+9114,2155,0,2,4,14,14,114,1114,4114,9114,28,29,'OMAAAA','XEDAAA','VVVVxx'
+3506,2156,0,2,6,6,6,506,1506,3506,3506,12,13,'WEAAAA','YEDAAA','AAAAxx'
+5002,2157,0,2,2,2,2,2,1002,2,5002,4,5,'KKAAAA','ZEDAAA','HHHHxx'
+3518,2158,0,2,8,18,18,518,1518,3518,3518,36,37,'IFAAAA','AFDAAA','OOOOxx'
+602,2159,0,2,2,2,2,602,602,602,602,4,5,'EXAAAA','BFDAAA','VVVVxx'
+9060,2160,0,0,0,0,60,60,1060,4060,9060,120,121,'MKAAAA','CFDAAA','AAAAxx'
+3292,2161,0,0,2,12,92,292,1292,3292,3292,184,185,'QWAAAA','DFDAAA','HHHHxx'
+77,2162,1,1,7,17,77,77,77,77,77,154,155,'ZCAAAA','EFDAAA','OOOOxx'
+1420,2163,0,0,0,0,20,420,1420,1420,1420,40,41,'QCAAAA','FFDAAA','VVVVxx'
+6001,2164,1,1,1,1,1,1,1,1001,6001,2,3,'VWAAAA','GFDAAA','AAAAxx'
+7477,2165,1,1,7,17,77,477,1477,2477,7477,154,155,'PBAAAA','HFDAAA','HHHHxx'
+6655,2166,1,3,5,15,55,655,655,1655,6655,110,111,'ZVAAAA','IFDAAA','OOOOxx'
+7845,2167,1,1,5,5,45,845,1845,2845,7845,90,91,'TPAAAA','JFDAAA','VVVVxx'
+8484,2168,0,0,4,4,84,484,484,3484,8484,168,169,'IOAAAA','KFDAAA','AAAAxx'
+4345,2169,1,1,5,5,45,345,345,4345,4345,90,91,'DLAAAA','LFDAAA','HHHHxx'
+4250,2170,0,2,0,10,50,250,250,4250,4250,100,101,'MHAAAA','MFDAAA','OOOOxx'
+2391,2171,1,3,1,11,91,391,391,2391,2391,182,183,'ZNAAAA','NFDAAA','VVVVxx'
+6884,2172,0,0,4,4,84,884,884,1884,6884,168,169,'UEAAAA','OFDAAA','AAAAxx'
+7270,2173,0,2,0,10,70,270,1270,2270,7270,140,141,'QTAAAA','PFDAAA','HHHHxx'
+2499,2174,1,3,9,19,99,499,499,2499,2499,198,199,'DSAAAA','QFDAAA','OOOOxx'
+7312,2175,0,0,2,12,12,312,1312,2312,7312,24,25,'GVAAAA','RFDAAA','VVVVxx'
+7113,2176,1,1,3,13,13,113,1113,2113,7113,26,27,'PNAAAA','SFDAAA','AAAAxx'
+6695,2177,1,3,5,15,95,695,695,1695,6695,190,191,'NXAAAA','TFDAAA','HHHHxx'
+6521,2178,1,1,1,1,21,521,521,1521,6521,42,43,'VQAAAA','UFDAAA','OOOOxx'
+272,2179,0,0,2,12,72,272,272,272,272,144,145,'MKAAAA','VFDAAA','VVVVxx'
+9976,2180,0,0,6,16,76,976,1976,4976,9976,152,153,'STAAAA','WFDAAA','AAAAxx'
+992,2181,0,0,2,12,92,992,992,992,992,184,185,'EMAAAA','XFDAAA','HHHHxx'
+6158,2182,0,2,8,18,58,158,158,1158,6158,116,117,'WCAAAA','YFDAAA','OOOOxx'
+3281,2183,1,1,1,1,81,281,1281,3281,3281,162,163,'FWAAAA','ZFDAAA','VVVVxx'
+7446,2184,0,2,6,6,46,446,1446,2446,7446,92,93,'KAAAAA','AGDAAA','AAAAxx'
+4679,2185,1,3,9,19,79,679,679,4679,4679,158,159,'ZXAAAA','BGDAAA','HHHHxx'
+5203,2186,1,3,3,3,3,203,1203,203,5203,6,7,'DSAAAA','CGDAAA','OOOOxx'
+9874,2187,0,2,4,14,74,874,1874,4874,9874,148,149,'UPAAAA','DGDAAA','VVVVxx'
+8371,2188,1,3,1,11,71,371,371,3371,8371,142,143,'ZJAAAA','EGDAAA','AAAAxx'
+9086,2189,0,2,6,6,86,86,1086,4086,9086,172,173,'MLAAAA','FGDAAA','HHHHxx'
+430,2190,0,2,0,10,30,430,430,430,430,60,61,'OQAAAA','GGDAAA','OOOOxx'
+8749,2191,1,1,9,9,49,749,749,3749,8749,98,99,'NYAAAA','HGDAAA','VVVVxx'
+577,2192,1,1,7,17,77,577,577,577,577,154,155,'FWAAAA','IGDAAA','AAAAxx'
+4884,2193,0,0,4,4,84,884,884,4884,4884,168,169,'WFAAAA','JGDAAA','HHHHxx'
+3421,2194,1,1,1,1,21,421,1421,3421,3421,42,43,'PBAAAA','KGDAAA','OOOOxx'
+2812,2195,0,0,2,12,12,812,812,2812,2812,24,25,'EEAAAA','LGDAAA','VVVVxx'
+5958,2196,0,2,8,18,58,958,1958,958,5958,116,117,'EVAAAA','MGDAAA','AAAAxx'
+9901,2197,1,1,1,1,1,901,1901,4901,9901,2,3,'VQAAAA','NGDAAA','HHHHxx'
+8478,2198,0,2,8,18,78,478,478,3478,8478,156,157,'COAAAA','OGDAAA','OOOOxx'
+6545,2199,1,1,5,5,45,545,545,1545,6545,90,91,'TRAAAA','PGDAAA','VVVVxx'
+1479,2200,1,3,9,19,79,479,1479,1479,1479,158,159,'XEAAAA','QGDAAA','AAAAxx'
+1046,2201,0,2,6,6,46,46,1046,1046,1046,92,93,'GOAAAA','RGDAAA','HHHHxx'
+6372,2202,0,0,2,12,72,372,372,1372,6372,144,145,'CLAAAA','SGDAAA','OOOOxx'
+8206,2203,0,2,6,6,6,206,206,3206,8206,12,13,'QDAAAA','TGDAAA','VVVVxx'
+9544,2204,0,0,4,4,44,544,1544,4544,9544,88,89,'CDAAAA','UGDAAA','AAAAxx'
+9287,2205,1,3,7,7,87,287,1287,4287,9287,174,175,'FTAAAA','VGDAAA','HHHHxx'
+6786,2206,0,2,6,6,86,786,786,1786,6786,172,173,'ABAAAA','WGDAAA','OOOOxx'
+6511,2207,1,3,1,11,11,511,511,1511,6511,22,23,'LQAAAA','XGDAAA','VVVVxx'
+603,2208,1,3,3,3,3,603,603,603,603,6,7,'FXAAAA','YGDAAA','AAAAxx'
+2022,2209,0,2,2,2,22,22,22,2022,2022,44,45,'UZAAAA','ZGDAAA','HHHHxx'
+2086,2210,0,2,6,6,86,86,86,2086,2086,172,173,'GCAAAA','AHDAAA','OOOOxx'
+1969,2211,1,1,9,9,69,969,1969,1969,1969,138,139,'TXAAAA','BHDAAA','VVVVxx'
+4841,2212,1,1,1,1,41,841,841,4841,4841,82,83,'FEAAAA','CHDAAA','AAAAxx'
+5845,2213,1,1,5,5,45,845,1845,845,5845,90,91,'VQAAAA','DHDAAA','HHHHxx'
+4635,2214,1,3,5,15,35,635,635,4635,4635,70,71,'HWAAAA','EHDAAA','OOOOxx'
+4658,2215,0,2,8,18,58,658,658,4658,4658,116,117,'EXAAAA','FHDAAA','VVVVxx'
+2896,2216,0,0,6,16,96,896,896,2896,2896,192,193,'KHAAAA','GHDAAA','AAAAxx'
+5179,2217,1,3,9,19,79,179,1179,179,5179,158,159,'FRAAAA','HHDAAA','HHHHxx'
+8667,2218,1,3,7,7,67,667,667,3667,8667,134,135,'JVAAAA','IHDAAA','OOOOxx'
+7294,2219,0,2,4,14,94,294,1294,2294,7294,188,189,'OUAAAA','JHDAAA','VVVVxx'
+3706,2220,0,2,6,6,6,706,1706,3706,3706,12,13,'OMAAAA','KHDAAA','AAAAxx'
+8389,2221,1,1,9,9,89,389,389,3389,8389,178,179,'RKAAAA','LHDAAA','HHHHxx'
+2486,2222,0,2,6,6,86,486,486,2486,2486,172,173,'QRAAAA','MHDAAA','OOOOxx'
+8743,2223,1,3,3,3,43,743,743,3743,8743,86,87,'HYAAAA','NHDAAA','VVVVxx'
+2777,2224,1,1,7,17,77,777,777,2777,2777,154,155,'VCAAAA','OHDAAA','AAAAxx'
+2113,2225,1,1,3,13,13,113,113,2113,2113,26,27,'HDAAAA','PHDAAA','HHHHxx'
+2076,2226,0,0,6,16,76,76,76,2076,2076,152,153,'WBAAAA','QHDAAA','OOOOxx'
+2300,2227,0,0,0,0,0,300,300,2300,2300,0,1,'MKAAAA','RHDAAA','VVVVxx'
+6894,2228,0,2,4,14,94,894,894,1894,6894,188,189,'EFAAAA','SHDAAA','AAAAxx'
+6939,2229,1,3,9,19,39,939,939,1939,6939,78,79,'XGAAAA','THDAAA','HHHHxx'
+446,2230,0,2,6,6,46,446,446,446,446,92,93,'ERAAAA','UHDAAA','OOOOxx'
+6218,2231,0,2,8,18,18,218,218,1218,6218,36,37,'EFAAAA','VHDAAA','VVVVxx'
+1295,2232,1,3,5,15,95,295,1295,1295,1295,190,191,'VXAAAA','WHDAAA','AAAAxx'
+5135,2233,1,3,5,15,35,135,1135,135,5135,70,71,'NPAAAA','XHDAAA','HHHHxx'
+8122,2234,0,2,2,2,22,122,122,3122,8122,44,45,'KAAAAA','YHDAAA','OOOOxx'
+316,2235,0,0,6,16,16,316,316,316,316,32,33,'EMAAAA','ZHDAAA','VVVVxx'
+514,2236,0,2,4,14,14,514,514,514,514,28,29,'UTAAAA','AIDAAA','AAAAxx'
+7970,2237,0,2,0,10,70,970,1970,2970,7970,140,141,'OUAAAA','BIDAAA','HHHHxx'
+9350,2238,0,2,0,10,50,350,1350,4350,9350,100,101,'QVAAAA','CIDAAA','OOOOxx'
+3700,2239,0,0,0,0,0,700,1700,3700,3700,0,1,'IMAAAA','DIDAAA','VVVVxx'
+582,2240,0,2,2,2,82,582,582,582,582,164,165,'KWAAAA','EIDAAA','AAAAxx'
+9722,2241,0,2,2,2,22,722,1722,4722,9722,44,45,'YJAAAA','FIDAAA','HHHHxx'
+7398,2242,0,2,8,18,98,398,1398,2398,7398,196,197,'OYAAAA','GIDAAA','OOOOxx'
+2265,2243,1,1,5,5,65,265,265,2265,2265,130,131,'DJAAAA','HIDAAA','VVVVxx'
+3049,2244,1,1,9,9,49,49,1049,3049,3049,98,99,'HNAAAA','IIDAAA','AAAAxx'
+9121,2245,1,1,1,1,21,121,1121,4121,9121,42,43,'VMAAAA','JIDAAA','HHHHxx'
+4275,2246,1,3,5,15,75,275,275,4275,4275,150,151,'LIAAAA','KIDAAA','OOOOxx'
+6567,2247,1,3,7,7,67,567,567,1567,6567,134,135,'PSAAAA','LIDAAA','VVVVxx'
+6755,2248,1,3,5,15,55,755,755,1755,6755,110,111,'VZAAAA','MIDAAA','AAAAxx'
+4535,2249,1,3,5,15,35,535,535,4535,4535,70,71,'LSAAAA','NIDAAA','HHHHxx'
+7968,2250,0,0,8,8,68,968,1968,2968,7968,136,137,'MUAAAA','OIDAAA','OOOOxx'
+3412,2251,0,0,2,12,12,412,1412,3412,3412,24,25,'GBAAAA','PIDAAA','VVVVxx'
+6112,2252,0,0,2,12,12,112,112,1112,6112,24,25,'CBAAAA','QIDAAA','AAAAxx'
+6805,2253,1,1,5,5,5,805,805,1805,6805,10,11,'TBAAAA','RIDAAA','HHHHxx'
+2880,2254,0,0,0,0,80,880,880,2880,2880,160,161,'UGAAAA','SIDAAA','OOOOxx'
+7710,2255,0,2,0,10,10,710,1710,2710,7710,20,21,'OKAAAA','TIDAAA','VVVVxx'
+7949,2256,1,1,9,9,49,949,1949,2949,7949,98,99,'TTAAAA','UIDAAA','AAAAxx'
+7043,2257,1,3,3,3,43,43,1043,2043,7043,86,87,'XKAAAA','VIDAAA','HHHHxx'
+9012,2258,0,0,2,12,12,12,1012,4012,9012,24,25,'QIAAAA','WIDAAA','OOOOxx'
+878,2259,0,2,8,18,78,878,878,878,878,156,157,'UHAAAA','XIDAAA','VVVVxx'
+7930,2260,0,2,0,10,30,930,1930,2930,7930,60,61,'ATAAAA','YIDAAA','AAAAxx'
+667,2261,1,3,7,7,67,667,667,667,667,134,135,'RZAAAA','ZIDAAA','HHHHxx'
+1905,2262,1,1,5,5,5,905,1905,1905,1905,10,11,'HVAAAA','AJDAAA','OOOOxx'
+4958,2263,0,2,8,18,58,958,958,4958,4958,116,117,'SIAAAA','BJDAAA','VVVVxx'
+2973,2264,1,1,3,13,73,973,973,2973,2973,146,147,'JKAAAA','CJDAAA','AAAAxx'
+3631,2265,1,3,1,11,31,631,1631,3631,3631,62,63,'RJAAAA','DJDAAA','HHHHxx'
+5868,2266,0,0,8,8,68,868,1868,868,5868,136,137,'SRAAAA','EJDAAA','OOOOxx'
+2873,2267,1,1,3,13,73,873,873,2873,2873,146,147,'NGAAAA','FJDAAA','VVVVxx'
+6941,2268,1,1,1,1,41,941,941,1941,6941,82,83,'ZGAAAA','GJDAAA','AAAAxx'
+6384,2269,0,0,4,4,84,384,384,1384,6384,168,169,'OLAAAA','HJDAAA','HHHHxx'
+3806,2270,0,2,6,6,6,806,1806,3806,3806,12,13,'KQAAAA','IJDAAA','OOOOxx'
+5079,2271,1,3,9,19,79,79,1079,79,5079,158,159,'JNAAAA','JJDAAA','VVVVxx'
+1970,2272,0,2,0,10,70,970,1970,1970,1970,140,141,'UXAAAA','KJDAAA','AAAAxx'
+7810,2273,0,2,0,10,10,810,1810,2810,7810,20,21,'KOAAAA','LJDAAA','HHHHxx'
+4639,2274,1,3,9,19,39,639,639,4639,4639,78,79,'LWAAAA','MJDAAA','OOOOxx'
+6527,2275,1,3,7,7,27,527,527,1527,6527,54,55,'BRAAAA','NJDAAA','VVVVxx'
+8079,2276,1,3,9,19,79,79,79,3079,8079,158,159,'TYAAAA','OJDAAA','AAAAxx'
+2740,2277,0,0,0,0,40,740,740,2740,2740,80,81,'KBAAAA','PJDAAA','HHHHxx'
+2337,2278,1,1,7,17,37,337,337,2337,2337,74,75,'XLAAAA','QJDAAA','OOOOxx'
+6670,2279,0,2,0,10,70,670,670,1670,6670,140,141,'OWAAAA','RJDAAA','VVVVxx'
+2345,2280,1,1,5,5,45,345,345,2345,2345,90,91,'FMAAAA','SJDAAA','AAAAxx'
+401,2281,1,1,1,1,1,401,401,401,401,2,3,'LPAAAA','TJDAAA','HHHHxx'
+2704,2282,0,0,4,4,4,704,704,2704,2704,8,9,'AAAAAA','UJDAAA','OOOOxx'
+5530,2283,0,2,0,10,30,530,1530,530,5530,60,61,'SEAAAA','VJDAAA','VVVVxx'
+51,2284,1,3,1,11,51,51,51,51,51,102,103,'ZBAAAA','WJDAAA','AAAAxx'
+4282,2285,0,2,2,2,82,282,282,4282,4282,164,165,'SIAAAA','XJDAAA','HHHHxx'
+7336,2286,0,0,6,16,36,336,1336,2336,7336,72,73,'EWAAAA','YJDAAA','OOOOxx'
+8320,2287,0,0,0,0,20,320,320,3320,8320,40,41,'AIAAAA','ZJDAAA','VVVVxx'
+7772,2288,0,0,2,12,72,772,1772,2772,7772,144,145,'YMAAAA','AKDAAA','AAAAxx'
+1894,2289,0,2,4,14,94,894,1894,1894,1894,188,189,'WUAAAA','BKDAAA','HHHHxx'
+2320,2290,0,0,0,0,20,320,320,2320,2320,40,41,'GLAAAA','CKDAAA','OOOOxx'
+6232,2291,0,0,2,12,32,232,232,1232,6232,64,65,'SFAAAA','DKDAAA','VVVVxx'
+2833,2292,1,1,3,13,33,833,833,2833,2833,66,67,'ZEAAAA','EKDAAA','AAAAxx'
+8265,2293,1,1,5,5,65,265,265,3265,8265,130,131,'XFAAAA','FKDAAA','HHHHxx'
+4589,2294,1,1,9,9,89,589,589,4589,4589,178,179,'NUAAAA','GKDAAA','OOOOxx'
+8182,2295,0,2,2,2,82,182,182,3182,8182,164,165,'SCAAAA','HKDAAA','VVVVxx'
+8337,2296,1,1,7,17,37,337,337,3337,8337,74,75,'RIAAAA','IKDAAA','AAAAxx'
+8210,2297,0,2,0,10,10,210,210,3210,8210,20,21,'UDAAAA','JKDAAA','HHHHxx'
+1406,2298,0,2,6,6,6,406,1406,1406,1406,12,13,'CCAAAA','KKDAAA','OOOOxx'
+4463,2299,1,3,3,3,63,463,463,4463,4463,126,127,'RPAAAA','LKDAAA','VVVVxx'
+4347,2300,1,3,7,7,47,347,347,4347,4347,94,95,'FLAAAA','MKDAAA','AAAAxx'
+181,2301,1,1,1,1,81,181,181,181,181,162,163,'ZGAAAA','NKDAAA','HHHHxx'
+9986,2302,0,2,6,6,86,986,1986,4986,9986,172,173,'CUAAAA','OKDAAA','OOOOxx'
+661,2303,1,1,1,1,61,661,661,661,661,122,123,'LZAAAA','PKDAAA','VVVVxx'
+4105,2304,1,1,5,5,5,105,105,4105,4105,10,11,'XBAAAA','QKDAAA','AAAAxx'
+2187,2305,1,3,7,7,87,187,187,2187,2187,174,175,'DGAAAA','RKDAAA','HHHHxx'
+1628,2306,0,0,8,8,28,628,1628,1628,1628,56,57,'QKAAAA','SKDAAA','OOOOxx'
+3119,2307,1,3,9,19,19,119,1119,3119,3119,38,39,'ZPAAAA','TKDAAA','VVVVxx'
+6804,2308,0,0,4,4,4,804,804,1804,6804,8,9,'SBAAAA','UKDAAA','AAAAxx'
+9918,2309,0,2,8,18,18,918,1918,4918,9918,36,37,'MRAAAA','VKDAAA','HHHHxx'
+8916,2310,0,0,6,16,16,916,916,3916,8916,32,33,'YEAAAA','WKDAAA','OOOOxx'
+6057,2311,1,1,7,17,57,57,57,1057,6057,114,115,'ZYAAAA','XKDAAA','VVVVxx'
+3622,2312,0,2,2,2,22,622,1622,3622,3622,44,45,'IJAAAA','YKDAAA','AAAAxx'
+9168,2313,0,0,8,8,68,168,1168,4168,9168,136,137,'QOAAAA','ZKDAAA','HHHHxx'
+3720,2314,0,0,0,0,20,720,1720,3720,3720,40,41,'CNAAAA','ALDAAA','OOOOxx'
+9927,2315,1,3,7,7,27,927,1927,4927,9927,54,55,'VRAAAA','BLDAAA','VVVVxx'
+5616,2316,0,0,6,16,16,616,1616,616,5616,32,33,'AIAAAA','CLDAAA','AAAAxx'
+5210,2317,0,2,0,10,10,210,1210,210,5210,20,21,'KSAAAA','DLDAAA','HHHHxx'
+636,2318,0,0,6,16,36,636,636,636,636,72,73,'MYAAAA','ELDAAA','OOOOxx'
+9936,2319,0,0,6,16,36,936,1936,4936,9936,72,73,'ESAAAA','FLDAAA','VVVVxx'
+2316,2320,0,0,6,16,16,316,316,2316,2316,32,33,'CLAAAA','GLDAAA','AAAAxx'
+4363,2321,1,3,3,3,63,363,363,4363,4363,126,127,'VLAAAA','HLDAAA','HHHHxx'
+7657,2322,1,1,7,17,57,657,1657,2657,7657,114,115,'NIAAAA','ILDAAA','OOOOxx'
+697,2323,1,1,7,17,97,697,697,697,697,194,195,'VAAAAA','JLDAAA','VVVVxx'
+912,2324,0,0,2,12,12,912,912,912,912,24,25,'CJAAAA','KLDAAA','AAAAxx'
+8806,2325,0,2,6,6,6,806,806,3806,8806,12,13,'SAAAAA','LLDAAA','HHHHxx'
+9698,2326,0,2,8,18,98,698,1698,4698,9698,196,197,'AJAAAA','MLDAAA','OOOOxx'
+6191,2327,1,3,1,11,91,191,191,1191,6191,182,183,'DEAAAA','NLDAAA','VVVVxx'
+1188,2328,0,0,8,8,88,188,1188,1188,1188,176,177,'STAAAA','OLDAAA','AAAAxx'
+7676,2329,0,0,6,16,76,676,1676,2676,7676,152,153,'GJAAAA','PLDAAA','HHHHxx'
+7073,2330,1,1,3,13,73,73,1073,2073,7073,146,147,'BMAAAA','QLDAAA','OOOOxx'
+8019,2331,1,3,9,19,19,19,19,3019,8019,38,39,'LWAAAA','RLDAAA','VVVVxx'
+4726,2332,0,2,6,6,26,726,726,4726,4726,52,53,'UZAAAA','SLDAAA','AAAAxx'
+4648,2333,0,0,8,8,48,648,648,4648,4648,96,97,'UWAAAA','TLDAAA','HHHHxx'
+3227,2334,1,3,7,7,27,227,1227,3227,3227,54,55,'DUAAAA','ULDAAA','OOOOxx'
+7232,2335,0,0,2,12,32,232,1232,2232,7232,64,65,'ESAAAA','VLDAAA','VVVVxx'
+9761,2336,1,1,1,1,61,761,1761,4761,9761,122,123,'LLAAAA','WLDAAA','AAAAxx'
+3105,2337,1,1,5,5,5,105,1105,3105,3105,10,11,'LPAAAA','XLDAAA','HHHHxx'
+5266,2338,0,2,6,6,66,266,1266,266,5266,132,133,'OUAAAA','YLDAAA','OOOOxx'
+6788,2339,0,0,8,8,88,788,788,1788,6788,176,177,'CBAAAA','ZLDAAA','VVVVxx'
+2442,2340,0,2,2,2,42,442,442,2442,2442,84,85,'YPAAAA','AMDAAA','AAAAxx'
+8198,2341,0,2,8,18,98,198,198,3198,8198,196,197,'IDAAAA','BMDAAA','HHHHxx'
+5806,2342,0,2,6,6,6,806,1806,806,5806,12,13,'IPAAAA','CMDAAA','OOOOxx'
+8928,2343,0,0,8,8,28,928,928,3928,8928,56,57,'KFAAAA','DMDAAA','VVVVxx'
+1657,2344,1,1,7,17,57,657,1657,1657,1657,114,115,'TLAAAA','EMDAAA','AAAAxx'
+9164,2345,0,0,4,4,64,164,1164,4164,9164,128,129,'MOAAAA','FMDAAA','HHHHxx'
+1851,2346,1,3,1,11,51,851,1851,1851,1851,102,103,'FTAAAA','GMDAAA','OOOOxx'
+4744,2347,0,0,4,4,44,744,744,4744,4744,88,89,'MAAAAA','HMDAAA','VVVVxx'
+8055,2348,1,3,5,15,55,55,55,3055,8055,110,111,'VXAAAA','IMDAAA','AAAAxx'
+1533,2349,1,1,3,13,33,533,1533,1533,1533,66,67,'ZGAAAA','JMDAAA','HHHHxx'
+1260,2350,0,0,0,0,60,260,1260,1260,1260,120,121,'MWAAAA','KMDAAA','OOOOxx'
+1290,2351,0,2,0,10,90,290,1290,1290,1290,180,181,'QXAAAA','LMDAAA','VVVVxx'
+297,2352,1,1,7,17,97,297,297,297,297,194,195,'LLAAAA','MMDAAA','AAAAxx'
+4145,2353,1,1,5,5,45,145,145,4145,4145,90,91,'LDAAAA','NMDAAA','HHHHxx'
+863,2354,1,3,3,3,63,863,863,863,863,126,127,'FHAAAA','OMDAAA','OOOOxx'
+3423,2355,1,3,3,3,23,423,1423,3423,3423,46,47,'RBAAAA','PMDAAA','VVVVxx'
+8750,2356,0,2,0,10,50,750,750,3750,8750,100,101,'OYAAAA','QMDAAA','AAAAxx'
+3546,2357,0,2,6,6,46,546,1546,3546,3546,92,93,'KGAAAA','RMDAAA','HHHHxx'
+3678,2358,0,2,8,18,78,678,1678,3678,3678,156,157,'MLAAAA','SMDAAA','OOOOxx'
+5313,2359,1,1,3,13,13,313,1313,313,5313,26,27,'JWAAAA','TMDAAA','VVVVxx'
+6233,2360,1,1,3,13,33,233,233,1233,6233,66,67,'TFAAAA','UMDAAA','AAAAxx'
+5802,2361,0,2,2,2,2,802,1802,802,5802,4,5,'EPAAAA','VMDAAA','HHHHxx'
+7059,2362,1,3,9,19,59,59,1059,2059,7059,118,119,'NLAAAA','WMDAAA','OOOOxx'
+6481,2363,1,1,1,1,81,481,481,1481,6481,162,163,'HPAAAA','XMDAAA','VVVVxx'
+1596,2364,0,0,6,16,96,596,1596,1596,1596,192,193,'KJAAAA','YMDAAA','AAAAxx'
+8181,2365,1,1,1,1,81,181,181,3181,8181,162,163,'RCAAAA','ZMDAAA','HHHHxx'
+5368,2366,0,0,8,8,68,368,1368,368,5368,136,137,'MYAAAA','ANDAAA','OOOOxx'
+9416,2367,0,0,6,16,16,416,1416,4416,9416,32,33,'EYAAAA','BNDAAA','VVVVxx'
+9521,2368,1,1,1,1,21,521,1521,4521,9521,42,43,'FCAAAA','CNDAAA','AAAAxx'
+1042,2369,0,2,2,2,42,42,1042,1042,1042,84,85,'COAAAA','DNDAAA','HHHHxx'
+4503,2370,1,3,3,3,3,503,503,4503,4503,6,7,'FRAAAA','ENDAAA','OOOOxx'
+3023,2371,1,3,3,3,23,23,1023,3023,3023,46,47,'HMAAAA','FNDAAA','VVVVxx'
+1976,2372,0,0,6,16,76,976,1976,1976,1976,152,153,'AYAAAA','GNDAAA','AAAAxx'
+5610,2373,0,2,0,10,10,610,1610,610,5610,20,21,'UHAAAA','HNDAAA','HHHHxx'
+7410,2374,0,2,0,10,10,410,1410,2410,7410,20,21,'AZAAAA','INDAAA','OOOOxx'
+7872,2375,0,0,2,12,72,872,1872,2872,7872,144,145,'UQAAAA','JNDAAA','VVVVxx'
+8591,2376,1,3,1,11,91,591,591,3591,8591,182,183,'LSAAAA','KNDAAA','AAAAxx'
+1804,2377,0,0,4,4,4,804,1804,1804,1804,8,9,'KRAAAA','LNDAAA','HHHHxx'
+5299,2378,1,3,9,19,99,299,1299,299,5299,198,199,'VVAAAA','MNDAAA','OOOOxx'
+4695,2379,1,3,5,15,95,695,695,4695,4695,190,191,'PYAAAA','NNDAAA','VVVVxx'
+2672,2380,0,0,2,12,72,672,672,2672,2672,144,145,'UYAAAA','ONDAAA','AAAAxx'
+585,2381,1,1,5,5,85,585,585,585,585,170,171,'NWAAAA','PNDAAA','HHHHxx'
+8622,2382,0,2,2,2,22,622,622,3622,8622,44,45,'QTAAAA','QNDAAA','OOOOxx'
+3780,2383,0,0,0,0,80,780,1780,3780,3780,160,161,'KPAAAA','RNDAAA','VVVVxx'
+7941,2384,1,1,1,1,41,941,1941,2941,7941,82,83,'LTAAAA','SNDAAA','AAAAxx'
+3305,2385,1,1,5,5,5,305,1305,3305,3305,10,11,'DXAAAA','TNDAAA','HHHHxx'
+8653,2386,1,1,3,13,53,653,653,3653,8653,106,107,'VUAAAA','UNDAAA','OOOOxx'
+5756,2387,0,0,6,16,56,756,1756,756,5756,112,113,'KNAAAA','VNDAAA','VVVVxx'
+576,2388,0,0,6,16,76,576,576,576,576,152,153,'EWAAAA','WNDAAA','AAAAxx'
+1915,2389,1,3,5,15,15,915,1915,1915,1915,30,31,'RVAAAA','XNDAAA','HHHHxx'
+4627,2390,1,3,7,7,27,627,627,4627,4627,54,55,'ZVAAAA','YNDAAA','OOOOxx'
+920,2391,0,0,0,0,20,920,920,920,920,40,41,'KJAAAA','ZNDAAA','VVVVxx'
+2537,2392,1,1,7,17,37,537,537,2537,2537,74,75,'PTAAAA','AODAAA','AAAAxx'
+50,2393,0,2,0,10,50,50,50,50,50,100,101,'YBAAAA','BODAAA','HHHHxx'
+1313,2394,1,1,3,13,13,313,1313,1313,1313,26,27,'NYAAAA','CODAAA','OOOOxx'
+8542,2395,0,2,2,2,42,542,542,3542,8542,84,85,'OQAAAA','DODAAA','VVVVxx'
+6428,2396,0,0,8,8,28,428,428,1428,6428,56,57,'GNAAAA','EODAAA','AAAAxx'
+4351,2397,1,3,1,11,51,351,351,4351,4351,102,103,'JLAAAA','FODAAA','HHHHxx'
+2050,2398,0,2,0,10,50,50,50,2050,2050,100,101,'WAAAAA','GODAAA','OOOOxx'
+5162,2399,0,2,2,2,62,162,1162,162,5162,124,125,'OQAAAA','HODAAA','VVVVxx'
+8229,2400,1,1,9,9,29,229,229,3229,8229,58,59,'NEAAAA','IODAAA','AAAAxx'
+7782,2401,0,2,2,2,82,782,1782,2782,7782,164,165,'INAAAA','JODAAA','HHHHxx'
+1563,2402,1,3,3,3,63,563,1563,1563,1563,126,127,'DIAAAA','KODAAA','OOOOxx'
+267,2403,1,3,7,7,67,267,267,267,267,134,135,'HKAAAA','LODAAA','VVVVxx'
+5138,2404,0,2,8,18,38,138,1138,138,5138,76,77,'QPAAAA','MODAAA','AAAAxx'
+7022,2405,0,2,2,2,22,22,1022,2022,7022,44,45,'CKAAAA','NODAAA','HHHHxx'
+6705,2406,1,1,5,5,5,705,705,1705,6705,10,11,'XXAAAA','OODAAA','OOOOxx'
+6190,2407,0,2,0,10,90,190,190,1190,6190,180,181,'CEAAAA','PODAAA','VVVVxx'
+8226,2408,0,2,6,6,26,226,226,3226,8226,52,53,'KEAAAA','QODAAA','AAAAxx'
+8882,2409,0,2,2,2,82,882,882,3882,8882,164,165,'QDAAAA','RODAAA','HHHHxx'
+5181,2410,1,1,1,1,81,181,1181,181,5181,162,163,'HRAAAA','SODAAA','OOOOxx'
+4598,2411,0,2,8,18,98,598,598,4598,4598,196,197,'WUAAAA','TODAAA','VVVVxx'
+4882,2412,0,2,2,2,82,882,882,4882,4882,164,165,'UFAAAA','UODAAA','AAAAxx'
+7490,2413,0,2,0,10,90,490,1490,2490,7490,180,181,'CCAAAA','VODAAA','HHHHxx'
+5224,2414,0,0,4,4,24,224,1224,224,5224,48,49,'YSAAAA','WODAAA','OOOOxx'
+2174,2415,0,2,4,14,74,174,174,2174,2174,148,149,'QFAAAA','XODAAA','VVVVxx'
+3059,2416,1,3,9,19,59,59,1059,3059,3059,118,119,'RNAAAA','YODAAA','AAAAxx'
+8790,2417,0,2,0,10,90,790,790,3790,8790,180,181,'CAAAAA','ZODAAA','HHHHxx'
+2222,2418,0,2,2,2,22,222,222,2222,2222,44,45,'MHAAAA','APDAAA','OOOOxx'
+5473,2419,1,1,3,13,73,473,1473,473,5473,146,147,'NCAAAA','BPDAAA','VVVVxx'
+937,2420,1,1,7,17,37,937,937,937,937,74,75,'BKAAAA','CPDAAA','AAAAxx'
+2975,2421,1,3,5,15,75,975,975,2975,2975,150,151,'LKAAAA','DPDAAA','HHHHxx'
+9569,2422,1,1,9,9,69,569,1569,4569,9569,138,139,'BEAAAA','EPDAAA','OOOOxx'
+3456,2423,0,0,6,16,56,456,1456,3456,3456,112,113,'YCAAAA','FPDAAA','VVVVxx'
+6657,2424,1,1,7,17,57,657,657,1657,6657,114,115,'BWAAAA','GPDAAA','AAAAxx'
+3776,2425,0,0,6,16,76,776,1776,3776,3776,152,153,'GPAAAA','HPDAAA','HHHHxx'
+6072,2426,0,0,2,12,72,72,72,1072,6072,144,145,'OZAAAA','IPDAAA','OOOOxx'
+8129,2427,1,1,9,9,29,129,129,3129,8129,58,59,'RAAAAA','JPDAAA','VVVVxx'
+1085,2428,1,1,5,5,85,85,1085,1085,1085,170,171,'TPAAAA','KPDAAA','AAAAxx'
+2079,2429,1,3,9,19,79,79,79,2079,2079,158,159,'ZBAAAA','LPDAAA','HHHHxx'
+1200,2430,0,0,0,0,0,200,1200,1200,1200,0,1,'EUAAAA','MPDAAA','OOOOxx'
+3276,2431,0,0,6,16,76,276,1276,3276,3276,152,153,'AWAAAA','NPDAAA','VVVVxx'
+2608,2432,0,0,8,8,8,608,608,2608,2608,16,17,'IWAAAA','OPDAAA','AAAAxx'
+702,2433,0,2,2,2,2,702,702,702,702,4,5,'ABAAAA','PPDAAA','HHHHxx'
+5750,2434,0,2,0,10,50,750,1750,750,5750,100,101,'ENAAAA','QPDAAA','OOOOxx'
+2776,2435,0,0,6,16,76,776,776,2776,2776,152,153,'UCAAAA','RPDAAA','VVVVxx'
+9151,2436,1,3,1,11,51,151,1151,4151,9151,102,103,'ZNAAAA','SPDAAA','AAAAxx'
+3282,2437,0,2,2,2,82,282,1282,3282,3282,164,165,'GWAAAA','TPDAAA','HHHHxx'
+408,2438,0,0,8,8,8,408,408,408,408,16,17,'SPAAAA','UPDAAA','OOOOxx'
+3473,2439,1,1,3,13,73,473,1473,3473,3473,146,147,'PDAAAA','VPDAAA','VVVVxx'
+7095,2440,1,3,5,15,95,95,1095,2095,7095,190,191,'XMAAAA','WPDAAA','AAAAxx'
+3288,2441,0,0,8,8,88,288,1288,3288,3288,176,177,'MWAAAA','XPDAAA','HHHHxx'
+8215,2442,1,3,5,15,15,215,215,3215,8215,30,31,'ZDAAAA','YPDAAA','OOOOxx'
+6244,2443,0,0,4,4,44,244,244,1244,6244,88,89,'EGAAAA','ZPDAAA','VVVVxx'
+8440,2444,0,0,0,0,40,440,440,3440,8440,80,81,'QMAAAA','AQDAAA','AAAAxx'
+3800,2445,0,0,0,0,0,800,1800,3800,3800,0,1,'EQAAAA','BQDAAA','HHHHxx'
+7279,2446,1,3,9,19,79,279,1279,2279,7279,158,159,'ZTAAAA','CQDAAA','OOOOxx'
+9206,2447,0,2,6,6,6,206,1206,4206,9206,12,13,'CQAAAA','DQDAAA','VVVVxx'
+6465,2448,1,1,5,5,65,465,465,1465,6465,130,131,'ROAAAA','EQDAAA','AAAAxx'
+4127,2449,1,3,7,7,27,127,127,4127,4127,54,55,'TCAAAA','FQDAAA','HHHHxx'
+7463,2450,1,3,3,3,63,463,1463,2463,7463,126,127,'BBAAAA','GQDAAA','OOOOxx'
+5117,2451,1,1,7,17,17,117,1117,117,5117,34,35,'VOAAAA','HQDAAA','VVVVxx'
+4715,2452,1,3,5,15,15,715,715,4715,4715,30,31,'JZAAAA','IQDAAA','AAAAxx'
+2010,2453,0,2,0,10,10,10,10,2010,2010,20,21,'IZAAAA','JQDAAA','HHHHxx'
+6486,2454,0,2,6,6,86,486,486,1486,6486,172,173,'MPAAAA','KQDAAA','OOOOxx'
+6434,2455,0,2,4,14,34,434,434,1434,6434,68,69,'MNAAAA','LQDAAA','VVVVxx'
+2151,2456,1,3,1,11,51,151,151,2151,2151,102,103,'TEAAAA','MQDAAA','AAAAxx'
+4821,2457,1,1,1,1,21,821,821,4821,4821,42,43,'LDAAAA','NQDAAA','HHHHxx'
+6507,2458,1,3,7,7,7,507,507,1507,6507,14,15,'HQAAAA','OQDAAA','OOOOxx'
+8741,2459,1,1,1,1,41,741,741,3741,8741,82,83,'FYAAAA','PQDAAA','VVVVxx'
+6846,2460,0,2,6,6,46,846,846,1846,6846,92,93,'IDAAAA','QQDAAA','AAAAxx'
+4525,2461,1,1,5,5,25,525,525,4525,4525,50,51,'BSAAAA','RQDAAA','HHHHxx'
+8299,2462,1,3,9,19,99,299,299,3299,8299,198,199,'FHAAAA','SQDAAA','OOOOxx'
+5465,2463,1,1,5,5,65,465,1465,465,5465,130,131,'FCAAAA','TQDAAA','VVVVxx'
+7206,2464,0,2,6,6,6,206,1206,2206,7206,12,13,'ERAAAA','UQDAAA','AAAAxx'
+2616,2465,0,0,6,16,16,616,616,2616,2616,32,33,'QWAAAA','VQDAAA','HHHHxx'
+4440,2466,0,0,0,0,40,440,440,4440,4440,80,81,'UOAAAA','WQDAAA','OOOOxx'
+6109,2467,1,1,9,9,9,109,109,1109,6109,18,19,'ZAAAAA','XQDAAA','VVVVxx'
+7905,2468,1,1,5,5,5,905,1905,2905,7905,10,11,'BSAAAA','YQDAAA','AAAAxx'
+6498,2469,0,2,8,18,98,498,498,1498,6498,196,197,'YPAAAA','ZQDAAA','HHHHxx'
+2034,2470,0,2,4,14,34,34,34,2034,2034,68,69,'GAAAAA','ARDAAA','OOOOxx'
+7693,2471,1,1,3,13,93,693,1693,2693,7693,186,187,'XJAAAA','BRDAAA','VVVVxx'
+7511,2472,1,3,1,11,11,511,1511,2511,7511,22,23,'XCAAAA','CRDAAA','AAAAxx'
+7531,2473,1,3,1,11,31,531,1531,2531,7531,62,63,'RDAAAA','DRDAAA','HHHHxx'
+6869,2474,1,1,9,9,69,869,869,1869,6869,138,139,'FEAAAA','ERDAAA','OOOOxx'
+2763,2475,1,3,3,3,63,763,763,2763,2763,126,127,'HCAAAA','FRDAAA','VVVVxx'
+575,2476,1,3,5,15,75,575,575,575,575,150,151,'DWAAAA','GRDAAA','AAAAxx'
+8953,2477,1,1,3,13,53,953,953,3953,8953,106,107,'JGAAAA','HRDAAA','HHHHxx'
+5833,2478,1,1,3,13,33,833,1833,833,5833,66,67,'JQAAAA','IRDAAA','OOOOxx'
+9035,2479,1,3,5,15,35,35,1035,4035,9035,70,71,'NJAAAA','JRDAAA','VVVVxx'
+9123,2480,1,3,3,3,23,123,1123,4123,9123,46,47,'XMAAAA','KRDAAA','AAAAxx'
+206,2481,0,2,6,6,6,206,206,206,206,12,13,'YHAAAA','LRDAAA','HHHHxx'
+4155,2482,1,3,5,15,55,155,155,4155,4155,110,111,'VDAAAA','MRDAAA','OOOOxx'
+532,2483,0,0,2,12,32,532,532,532,532,64,65,'MUAAAA','NRDAAA','VVVVxx'
+1370,2484,0,2,0,10,70,370,1370,1370,1370,140,141,'SAAAAA','ORDAAA','AAAAxx'
+7656,2485,0,0,6,16,56,656,1656,2656,7656,112,113,'MIAAAA','PRDAAA','HHHHxx'
+7735,2486,1,3,5,15,35,735,1735,2735,7735,70,71,'NLAAAA','QRDAAA','OOOOxx'
+2118,2487,0,2,8,18,18,118,118,2118,2118,36,37,'MDAAAA','RRDAAA','VVVVxx'
+6914,2488,0,2,4,14,14,914,914,1914,6914,28,29,'YFAAAA','SRDAAA','AAAAxx'
+6277,2489,1,1,7,17,77,277,277,1277,6277,154,155,'LHAAAA','TRDAAA','HHHHxx'
+6347,2490,1,3,7,7,47,347,347,1347,6347,94,95,'DKAAAA','URDAAA','OOOOxx'
+4030,2491,0,2,0,10,30,30,30,4030,4030,60,61,'AZAAAA','VRDAAA','VVVVxx'
+9673,2492,1,1,3,13,73,673,1673,4673,9673,146,147,'BIAAAA','WRDAAA','AAAAxx'
+2015,2493,1,3,5,15,15,15,15,2015,2015,30,31,'NZAAAA','XRDAAA','HHHHxx'
+1317,2494,1,1,7,17,17,317,1317,1317,1317,34,35,'RYAAAA','YRDAAA','OOOOxx'
+404,2495,0,0,4,4,4,404,404,404,404,8,9,'OPAAAA','ZRDAAA','VVVVxx'
+1604,2496,0,0,4,4,4,604,1604,1604,1604,8,9,'SJAAAA','ASDAAA','AAAAxx'
+1912,2497,0,0,2,12,12,912,1912,1912,1912,24,25,'OVAAAA','BSDAAA','HHHHxx'
+5727,2498,1,3,7,7,27,727,1727,727,5727,54,55,'HMAAAA','CSDAAA','OOOOxx'
+4538,2499,0,2,8,18,38,538,538,4538,4538,76,77,'OSAAAA','DSDAAA','VVVVxx'
+6868,2500,0,0,8,8,68,868,868,1868,6868,136,137,'EEAAAA','ESDAAA','AAAAxx'
+9801,2501,1,1,1,1,1,801,1801,4801,9801,2,3,'ZMAAAA','FSDAAA','HHHHxx'
+1781,2502,1,1,1,1,81,781,1781,1781,1781,162,163,'NQAAAA','GSDAAA','OOOOxx'
+7061,2503,1,1,1,1,61,61,1061,2061,7061,122,123,'PLAAAA','HSDAAA','VVVVxx'
+2412,2504,0,0,2,12,12,412,412,2412,2412,24,25,'UOAAAA','ISDAAA','AAAAxx'
+9191,2505,1,3,1,11,91,191,1191,4191,9191,182,183,'NPAAAA','JSDAAA','HHHHxx'
+1958,2506,0,2,8,18,58,958,1958,1958,1958,116,117,'IXAAAA','KSDAAA','OOOOxx'
+2203,2507,1,3,3,3,3,203,203,2203,2203,6,7,'TGAAAA','LSDAAA','VVVVxx'
+9104,2508,0,0,4,4,4,104,1104,4104,9104,8,9,'EMAAAA','MSDAAA','AAAAxx'
+3837,2509,1,1,7,17,37,837,1837,3837,3837,74,75,'PRAAAA','NSDAAA','HHHHxx'
+7055,2510,1,3,5,15,55,55,1055,2055,7055,110,111,'JLAAAA','OSDAAA','OOOOxx'
+4612,2511,0,0,2,12,12,612,612,4612,4612,24,25,'KVAAAA','PSDAAA','VVVVxx'
+6420,2512,0,0,0,0,20,420,420,1420,6420,40,41,'YMAAAA','QSDAAA','AAAAxx'
+613,2513,1,1,3,13,13,613,613,613,613,26,27,'PXAAAA','RSDAAA','HHHHxx'
+1691,2514,1,3,1,11,91,691,1691,1691,1691,182,183,'BNAAAA','SSDAAA','OOOOxx'
+33,2515,1,1,3,13,33,33,33,33,33,66,67,'HBAAAA','TSDAAA','VVVVxx'
+875,2516,1,3,5,15,75,875,875,875,875,150,151,'RHAAAA','USDAAA','AAAAxx'
+9030,2517,0,2,0,10,30,30,1030,4030,9030,60,61,'IJAAAA','VSDAAA','HHHHxx'
+4285,2518,1,1,5,5,85,285,285,4285,4285,170,171,'VIAAAA','WSDAAA','OOOOxx'
+6236,2519,0,0,6,16,36,236,236,1236,6236,72,73,'WFAAAA','XSDAAA','VVVVxx'
+4702,2520,0,2,2,2,2,702,702,4702,4702,4,5,'WYAAAA','YSDAAA','AAAAxx'
+3441,2521,1,1,1,1,41,441,1441,3441,3441,82,83,'JCAAAA','ZSDAAA','HHHHxx'
+2150,2522,0,2,0,10,50,150,150,2150,2150,100,101,'SEAAAA','ATDAAA','OOOOxx'
+1852,2523,0,0,2,12,52,852,1852,1852,1852,104,105,'GTAAAA','BTDAAA','VVVVxx'
+7713,2524,1,1,3,13,13,713,1713,2713,7713,26,27,'RKAAAA','CTDAAA','AAAAxx'
+6849,2525,1,1,9,9,49,849,849,1849,6849,98,99,'LDAAAA','DTDAAA','HHHHxx'
+3425,2526,1,1,5,5,25,425,1425,3425,3425,50,51,'TBAAAA','ETDAAA','OOOOxx'
+4681,2527,1,1,1,1,81,681,681,4681,4681,162,163,'BYAAAA','FTDAAA','VVVVxx'
+1134,2528,0,2,4,14,34,134,1134,1134,1134,68,69,'QRAAAA','GTDAAA','AAAAxx'
+7462,2529,0,2,2,2,62,462,1462,2462,7462,124,125,'ABAAAA','HTDAAA','HHHHxx'
+2148,2530,0,0,8,8,48,148,148,2148,2148,96,97,'QEAAAA','ITDAAA','OOOOxx'
+5921,2531,1,1,1,1,21,921,1921,921,5921,42,43,'TTAAAA','JTDAAA','VVVVxx'
+118,2532,0,2,8,18,18,118,118,118,118,36,37,'OEAAAA','KTDAAA','AAAAxx'
+3065,2533,1,1,5,5,65,65,1065,3065,3065,130,131,'XNAAAA','LTDAAA','HHHHxx'
+6590,2534,0,2,0,10,90,590,590,1590,6590,180,181,'MTAAAA','MTDAAA','OOOOxx'
+4993,2535,1,1,3,13,93,993,993,4993,4993,186,187,'BKAAAA','NTDAAA','VVVVxx'
+6818,2536,0,2,8,18,18,818,818,1818,6818,36,37,'GCAAAA','OTDAAA','AAAAxx'
+1449,2537,1,1,9,9,49,449,1449,1449,1449,98,99,'TDAAAA','PTDAAA','HHHHxx'
+2039,2538,1,3,9,19,39,39,39,2039,2039,78,79,'LAAAAA','QTDAAA','OOOOxx'
+2524,2539,0,0,4,4,24,524,524,2524,2524,48,49,'CTAAAA','RTDAAA','VVVVxx'
+1481,2540,1,1,1,1,81,481,1481,1481,1481,162,163,'ZEAAAA','STDAAA','AAAAxx'
+6984,2541,0,0,4,4,84,984,984,1984,6984,168,169,'QIAAAA','TTDAAA','HHHHxx'
+3960,2542,0,0,0,0,60,960,1960,3960,3960,120,121,'IWAAAA','UTDAAA','OOOOxx'
+1983,2543,1,3,3,3,83,983,1983,1983,1983,166,167,'HYAAAA','VTDAAA','VVVVxx'
+6379,2544,1,3,9,19,79,379,379,1379,6379,158,159,'JLAAAA','WTDAAA','AAAAxx'
+8975,2545,1,3,5,15,75,975,975,3975,8975,150,151,'FHAAAA','XTDAAA','HHHHxx'
+1102,2546,0,2,2,2,2,102,1102,1102,1102,4,5,'KQAAAA','YTDAAA','OOOOxx'
+2517,2547,1,1,7,17,17,517,517,2517,2517,34,35,'VSAAAA','ZTDAAA','VVVVxx'
+712,2548,0,0,2,12,12,712,712,712,712,24,25,'KBAAAA','AUDAAA','AAAAxx'
+5419,2549,1,3,9,19,19,419,1419,419,5419,38,39,'LAAAAA','BUDAAA','HHHHxx'
+723,2550,1,3,3,3,23,723,723,723,723,46,47,'VBAAAA','CUDAAA','OOOOxx'
+8057,2551,1,1,7,17,57,57,57,3057,8057,114,115,'XXAAAA','DUDAAA','VVVVxx'
+7471,2552,1,3,1,11,71,471,1471,2471,7471,142,143,'JBAAAA','EUDAAA','AAAAxx'
+8855,2553,1,3,5,15,55,855,855,3855,8855,110,111,'PCAAAA','FUDAAA','HHHHxx'
+5074,2554,0,2,4,14,74,74,1074,74,5074,148,149,'ENAAAA','GUDAAA','OOOOxx'
+7139,2555,1,3,9,19,39,139,1139,2139,7139,78,79,'POAAAA','HUDAAA','VVVVxx'
+3833,2556,1,1,3,13,33,833,1833,3833,3833,66,67,'LRAAAA','IUDAAA','AAAAxx'
+5186,2557,0,2,6,6,86,186,1186,186,5186,172,173,'MRAAAA','JUDAAA','HHHHxx'
+9436,2558,0,0,6,16,36,436,1436,4436,9436,72,73,'YYAAAA','KUDAAA','OOOOxx'
+8859,2559,1,3,9,19,59,859,859,3859,8859,118,119,'TCAAAA','LUDAAA','VVVVxx'
+6943,2560,1,3,3,3,43,943,943,1943,6943,86,87,'BHAAAA','MUDAAA','AAAAxx'
+2315,2561,1,3,5,15,15,315,315,2315,2315,30,31,'BLAAAA','NUDAAA','HHHHxx'
+1394,2562,0,2,4,14,94,394,1394,1394,1394,188,189,'QBAAAA','OUDAAA','OOOOxx'
+8863,2563,1,3,3,3,63,863,863,3863,8863,126,127,'XCAAAA','PUDAAA','VVVVxx'
+8812,2564,0,0,2,12,12,812,812,3812,8812,24,25,'YAAAAA','QUDAAA','AAAAxx'
+7498,2565,0,2,8,18,98,498,1498,2498,7498,196,197,'KCAAAA','RUDAAA','HHHHxx'
+8962,2566,0,2,2,2,62,962,962,3962,8962,124,125,'SGAAAA','SUDAAA','OOOOxx'
+2533,2567,1,1,3,13,33,533,533,2533,2533,66,67,'LTAAAA','TUDAAA','VVVVxx'
+8188,2568,0,0,8,8,88,188,188,3188,8188,176,177,'YCAAAA','UUDAAA','AAAAxx'
+6137,2569,1,1,7,17,37,137,137,1137,6137,74,75,'BCAAAA','VUDAAA','HHHHxx'
+974,2570,0,2,4,14,74,974,974,974,974,148,149,'MLAAAA','WUDAAA','OOOOxx'
+2751,2571,1,3,1,11,51,751,751,2751,2751,102,103,'VBAAAA','XUDAAA','VVVVxx'
+4975,2572,1,3,5,15,75,975,975,4975,4975,150,151,'JJAAAA','YUDAAA','AAAAxx'
+3411,2573,1,3,1,11,11,411,1411,3411,3411,22,23,'FBAAAA','ZUDAAA','HHHHxx'
+3143,2574,1,3,3,3,43,143,1143,3143,3143,86,87,'XQAAAA','AVDAAA','OOOOxx'
+8011,2575,1,3,1,11,11,11,11,3011,8011,22,23,'DWAAAA','BVDAAA','VVVVxx'
+988,2576,0,0,8,8,88,988,988,988,988,176,177,'AMAAAA','CVDAAA','AAAAxx'
+4289,2577,1,1,9,9,89,289,289,4289,4289,178,179,'ZIAAAA','DVDAAA','HHHHxx'
+8105,2578,1,1,5,5,5,105,105,3105,8105,10,11,'TZAAAA','EVDAAA','OOOOxx'
+9885,2579,1,1,5,5,85,885,1885,4885,9885,170,171,'FQAAAA','FVDAAA','VVVVxx'
+1002,2580,0,2,2,2,2,2,1002,1002,1002,4,5,'OMAAAA','GVDAAA','AAAAxx'
+5827,2581,1,3,7,7,27,827,1827,827,5827,54,55,'DQAAAA','HVDAAA','HHHHxx'
+1228,2582,0,0,8,8,28,228,1228,1228,1228,56,57,'GVAAAA','IVDAAA','OOOOxx'
+6352,2583,0,0,2,12,52,352,352,1352,6352,104,105,'IKAAAA','JVDAAA','VVVVxx'
+8868,2584,0,0,8,8,68,868,868,3868,8868,136,137,'CDAAAA','KVDAAA','AAAAxx'
+3643,2585,1,3,3,3,43,643,1643,3643,3643,86,87,'DKAAAA','LVDAAA','HHHHxx'
+1468,2586,0,0,8,8,68,468,1468,1468,1468,136,137,'MEAAAA','MVDAAA','OOOOxx'
+8415,2587,1,3,5,15,15,415,415,3415,8415,30,31,'RLAAAA','NVDAAA','VVVVxx'
+9631,2588,1,3,1,11,31,631,1631,4631,9631,62,63,'LGAAAA','OVDAAA','AAAAxx'
+7408,2589,0,0,8,8,8,408,1408,2408,7408,16,17,'YYAAAA','PVDAAA','HHHHxx'
+1934,2590,0,2,4,14,34,934,1934,1934,1934,68,69,'KWAAAA','QVDAAA','OOOOxx'
+996,2591,0,0,6,16,96,996,996,996,996,192,193,'IMAAAA','RVDAAA','VVVVxx'
+8027,2592,1,3,7,7,27,27,27,3027,8027,54,55,'TWAAAA','SVDAAA','AAAAxx'
+8464,2593,0,0,4,4,64,464,464,3464,8464,128,129,'ONAAAA','TVDAAA','HHHHxx'
+5007,2594,1,3,7,7,7,7,1007,7,5007,14,15,'PKAAAA','UVDAAA','OOOOxx'
+8356,2595,0,0,6,16,56,356,356,3356,8356,112,113,'KJAAAA','VVDAAA','VVVVxx'
+4579,2596,1,3,9,19,79,579,579,4579,4579,158,159,'DUAAAA','WVDAAA','AAAAxx'
+8513,2597,1,1,3,13,13,513,513,3513,8513,26,27,'LPAAAA','XVDAAA','HHHHxx'
+383,2598,1,3,3,3,83,383,383,383,383,166,167,'TOAAAA','YVDAAA','OOOOxx'
+9304,2599,0,0,4,4,4,304,1304,4304,9304,8,9,'WTAAAA','ZVDAAA','VVVVxx'
+7224,2600,0,0,4,4,24,224,1224,2224,7224,48,49,'WRAAAA','AWDAAA','AAAAxx'
+6023,2601,1,3,3,3,23,23,23,1023,6023,46,47,'RXAAAA','BWDAAA','HHHHxx'
+2746,2602,0,2,6,6,46,746,746,2746,2746,92,93,'QBAAAA','CWDAAA','OOOOxx'
+137,2603,1,1,7,17,37,137,137,137,137,74,75,'HFAAAA','DWDAAA','VVVVxx'
+9441,2604,1,1,1,1,41,441,1441,4441,9441,82,83,'DZAAAA','EWDAAA','AAAAxx'
+3690,2605,0,2,0,10,90,690,1690,3690,3690,180,181,'YLAAAA','FWDAAA','HHHHxx'
+913,2606,1,1,3,13,13,913,913,913,913,26,27,'DJAAAA','GWDAAA','OOOOxx'
+1768,2607,0,0,8,8,68,768,1768,1768,1768,136,137,'AQAAAA','HWDAAA','VVVVxx'
+8492,2608,0,0,2,12,92,492,492,3492,8492,184,185,'QOAAAA','IWDAAA','AAAAxx'
+8083,2609,1,3,3,3,83,83,83,3083,8083,166,167,'XYAAAA','JWDAAA','HHHHxx'
+4609,2610,1,1,9,9,9,609,609,4609,4609,18,19,'HVAAAA','KWDAAA','OOOOxx'
+7520,2611,0,0,0,0,20,520,1520,2520,7520,40,41,'GDAAAA','LWDAAA','VVVVxx'
+4231,2612,1,3,1,11,31,231,231,4231,4231,62,63,'TGAAAA','MWDAAA','AAAAxx'
+6022,2613,0,2,2,2,22,22,22,1022,6022,44,45,'QXAAAA','NWDAAA','HHHHxx'
+9784,2614,0,0,4,4,84,784,1784,4784,9784,168,169,'IMAAAA','OWDAAA','OOOOxx'
+1343,2615,1,3,3,3,43,343,1343,1343,1343,86,87,'RZAAAA','PWDAAA','VVVVxx'
+7549,2616,1,1,9,9,49,549,1549,2549,7549,98,99,'JEAAAA','QWDAAA','AAAAxx'
+269,2617,1,1,9,9,69,269,269,269,269,138,139,'JKAAAA','RWDAAA','HHHHxx'
+1069,2618,1,1,9,9,69,69,1069,1069,1069,138,139,'DPAAAA','SWDAAA','OOOOxx'
+4610,2619,0,2,0,10,10,610,610,4610,4610,20,21,'IVAAAA','TWDAAA','VVVVxx'
+482,2620,0,2,2,2,82,482,482,482,482,164,165,'OSAAAA','UWDAAA','AAAAxx'
+3025,2621,1,1,5,5,25,25,1025,3025,3025,50,51,'JMAAAA','VWDAAA','HHHHxx'
+7914,2622,0,2,4,14,14,914,1914,2914,7914,28,29,'KSAAAA','WWDAAA','OOOOxx'
+3198,2623,0,2,8,18,98,198,1198,3198,3198,196,197,'ATAAAA','XWDAAA','VVVVxx'
+1187,2624,1,3,7,7,87,187,1187,1187,1187,174,175,'RTAAAA','YWDAAA','AAAAxx'
+4707,2625,1,3,7,7,7,707,707,4707,4707,14,15,'BZAAAA','ZWDAAA','HHHHxx'
+8279,2626,1,3,9,19,79,279,279,3279,8279,158,159,'LGAAAA','AXDAAA','OOOOxx'
+6127,2627,1,3,7,7,27,127,127,1127,6127,54,55,'RBAAAA','BXDAAA','VVVVxx'
+1305,2628,1,1,5,5,5,305,1305,1305,1305,10,11,'FYAAAA','CXDAAA','AAAAxx'
+4804,2629,0,0,4,4,4,804,804,4804,4804,8,9,'UCAAAA','DXDAAA','HHHHxx'
+6069,2630,1,1,9,9,69,69,69,1069,6069,138,139,'LZAAAA','EXDAAA','OOOOxx'
+9229,2631,1,1,9,9,29,229,1229,4229,9229,58,59,'ZQAAAA','FXDAAA','VVVVxx'
+4703,2632,1,3,3,3,3,703,703,4703,4703,6,7,'XYAAAA','GXDAAA','AAAAxx'
+6410,2633,0,2,0,10,10,410,410,1410,6410,20,21,'OMAAAA','HXDAAA','HHHHxx'
+944,2634,0,0,4,4,44,944,944,944,944,88,89,'IKAAAA','IXDAAA','OOOOxx'
+3744,2635,0,0,4,4,44,744,1744,3744,3744,88,89,'AOAAAA','JXDAAA','VVVVxx'
+1127,2636,1,3,7,7,27,127,1127,1127,1127,54,55,'JRAAAA','KXDAAA','AAAAxx'
+6693,2637,1,1,3,13,93,693,693,1693,6693,186,187,'LXAAAA','LXDAAA','HHHHxx'
+583,2638,1,3,3,3,83,583,583,583,583,166,167,'LWAAAA','MXDAAA','OOOOxx'
+2684,2639,0,0,4,4,84,684,684,2684,2684,168,169,'GZAAAA','NXDAAA','VVVVxx'
+6192,2640,0,0,2,12,92,192,192,1192,6192,184,185,'EEAAAA','OXDAAA','AAAAxx'
+4157,2641,1,1,7,17,57,157,157,4157,4157,114,115,'XDAAAA','PXDAAA','HHHHxx'
+6470,2642,0,2,0,10,70,470,470,1470,6470,140,141,'WOAAAA','QXDAAA','OOOOxx'
+8965,2643,1,1,5,5,65,965,965,3965,8965,130,131,'VGAAAA','RXDAAA','VVVVxx'
+1433,2644,1,1,3,13,33,433,1433,1433,1433,66,67,'DDAAAA','SXDAAA','AAAAxx'
+4570,2645,0,2,0,10,70,570,570,4570,4570,140,141,'UTAAAA','TXDAAA','HHHHxx'
+1806,2646,0,2,6,6,6,806,1806,1806,1806,12,13,'MRAAAA','UXDAAA','OOOOxx'
+1230,2647,0,2,0,10,30,230,1230,1230,1230,60,61,'IVAAAA','VXDAAA','VVVVxx'
+2283,2648,1,3,3,3,83,283,283,2283,2283,166,167,'VJAAAA','WXDAAA','AAAAxx'
+6456,2649,0,0,6,16,56,456,456,1456,6456,112,113,'IOAAAA','XXDAAA','HHHHxx'
+7427,2650,1,3,7,7,27,427,1427,2427,7427,54,55,'RZAAAA','YXDAAA','OOOOxx'
+8310,2651,0,2,0,10,10,310,310,3310,8310,20,21,'QHAAAA','ZXDAAA','VVVVxx'
+8103,2652,1,3,3,3,3,103,103,3103,8103,6,7,'RZAAAA','AYDAAA','AAAAxx'
+3947,2653,1,3,7,7,47,947,1947,3947,3947,94,95,'VVAAAA','BYDAAA','HHHHxx'
+3414,2654,0,2,4,14,14,414,1414,3414,3414,28,29,'IBAAAA','CYDAAA','OOOOxx'
+2043,2655,1,3,3,3,43,43,43,2043,2043,86,87,'PAAAAA','DYDAAA','VVVVxx'
+4393,2656,1,1,3,13,93,393,393,4393,4393,186,187,'ZMAAAA','EYDAAA','AAAAxx'
+6664,2657,0,0,4,4,64,664,664,1664,6664,128,129,'IWAAAA','FYDAAA','HHHHxx'
+4545,2658,1,1,5,5,45,545,545,4545,4545,90,91,'VSAAAA','GYDAAA','OOOOxx'
+7637,2659,1,1,7,17,37,637,1637,2637,7637,74,75,'THAAAA','HYDAAA','VVVVxx'
+1359,2660,1,3,9,19,59,359,1359,1359,1359,118,119,'HAAAAA','IYDAAA','AAAAxx'
+5018,2661,0,2,8,18,18,18,1018,18,5018,36,37,'ALAAAA','JYDAAA','HHHHxx'
+987,2662,1,3,7,7,87,987,987,987,987,174,175,'ZLAAAA','KYDAAA','OOOOxx'
+1320,2663,0,0,0,0,20,320,1320,1320,1320,40,41,'UYAAAA','LYDAAA','VVVVxx'
+9311,2664,1,3,1,11,11,311,1311,4311,9311,22,23,'DUAAAA','MYDAAA','AAAAxx'
+7993,2665,1,1,3,13,93,993,1993,2993,7993,186,187,'LVAAAA','NYDAAA','HHHHxx'
+7588,2666,0,0,8,8,88,588,1588,2588,7588,176,177,'WFAAAA','OYDAAA','OOOOxx'
+5983,2667,1,3,3,3,83,983,1983,983,5983,166,167,'DWAAAA','PYDAAA','VVVVxx'
+4070,2668,0,2,0,10,70,70,70,4070,4070,140,141,'OAAAAA','QYDAAA','AAAAxx'
+8349,2669,1,1,9,9,49,349,349,3349,8349,98,99,'DJAAAA','RYDAAA','HHHHxx'
+3810,2670,0,2,0,10,10,810,1810,3810,3810,20,21,'OQAAAA','SYDAAA','OOOOxx'
+6948,2671,0,0,8,8,48,948,948,1948,6948,96,97,'GHAAAA','TYDAAA','VVVVxx'
+7153,2672,1,1,3,13,53,153,1153,2153,7153,106,107,'DPAAAA','UYDAAA','AAAAxx'
+5371,2673,1,3,1,11,71,371,1371,371,5371,142,143,'PYAAAA','VYDAAA','HHHHxx'
+8316,2674,0,0,6,16,16,316,316,3316,8316,32,33,'WHAAAA','WYDAAA','OOOOxx'
+5903,2675,1,3,3,3,3,903,1903,903,5903,6,7,'BTAAAA','XYDAAA','VVVVxx'
+6718,2676,0,2,8,18,18,718,718,1718,6718,36,37,'KYAAAA','YYDAAA','AAAAxx'
+4759,2677,1,3,9,19,59,759,759,4759,4759,118,119,'BBAAAA','ZYDAAA','HHHHxx'
+2555,2678,1,3,5,15,55,555,555,2555,2555,110,111,'HUAAAA','AZDAAA','OOOOxx'
+3457,2679,1,1,7,17,57,457,1457,3457,3457,114,115,'ZCAAAA','BZDAAA','VVVVxx'
+9626,2680,0,2,6,6,26,626,1626,4626,9626,52,53,'GGAAAA','CZDAAA','AAAAxx'
+2570,2681,0,2,0,10,70,570,570,2570,2570,140,141,'WUAAAA','DZDAAA','HHHHxx'
+7964,2682,0,0,4,4,64,964,1964,2964,7964,128,129,'IUAAAA','EZDAAA','OOOOxx'
+1543,2683,1,3,3,3,43,543,1543,1543,1543,86,87,'JHAAAA','FZDAAA','VVVVxx'
+929,2684,1,1,9,9,29,929,929,929,929,58,59,'TJAAAA','GZDAAA','AAAAxx'
+9244,2685,0,0,4,4,44,244,1244,4244,9244,88,89,'ORAAAA','HZDAAA','HHHHxx'
+9210,2686,0,2,0,10,10,210,1210,4210,9210,20,21,'GQAAAA','IZDAAA','OOOOxx'
+8334,2687,0,2,4,14,34,334,334,3334,8334,68,69,'OIAAAA','JZDAAA','VVVVxx'
+9310,2688,0,2,0,10,10,310,1310,4310,9310,20,21,'CUAAAA','KZDAAA','AAAAxx'
+5024,2689,0,0,4,4,24,24,1024,24,5024,48,49,'GLAAAA','LZDAAA','HHHHxx'
+8794,2690,0,2,4,14,94,794,794,3794,8794,188,189,'GAAAAA','MZDAAA','OOOOxx'
+4091,2691,1,3,1,11,91,91,91,4091,4091,182,183,'JBAAAA','NZDAAA','VVVVxx'
+649,2692,1,1,9,9,49,649,649,649,649,98,99,'ZYAAAA','OZDAAA','AAAAxx'
+8505,2693,1,1,5,5,5,505,505,3505,8505,10,11,'DPAAAA','PZDAAA','HHHHxx'
+6652,2694,0,0,2,12,52,652,652,1652,6652,104,105,'WVAAAA','QZDAAA','OOOOxx'
+8945,2695,1,1,5,5,45,945,945,3945,8945,90,91,'BGAAAA','RZDAAA','VVVVxx'
+2095,2696,1,3,5,15,95,95,95,2095,2095,190,191,'PCAAAA','SZDAAA','AAAAxx'
+8676,2697,0,0,6,16,76,676,676,3676,8676,152,153,'SVAAAA','TZDAAA','HHHHxx'
+3994,2698,0,2,4,14,94,994,1994,3994,3994,188,189,'QXAAAA','UZDAAA','OOOOxx'
+2859,2699,1,3,9,19,59,859,859,2859,2859,118,119,'ZFAAAA','VZDAAA','VVVVxx'
+5403,2700,1,3,3,3,3,403,1403,403,5403,6,7,'VZAAAA','WZDAAA','AAAAxx'
+3254,2701,0,2,4,14,54,254,1254,3254,3254,108,109,'EVAAAA','XZDAAA','HHHHxx'
+7339,2702,1,3,9,19,39,339,1339,2339,7339,78,79,'HWAAAA','YZDAAA','OOOOxx'
+7220,2703,0,0,0,0,20,220,1220,2220,7220,40,41,'SRAAAA','ZZDAAA','VVVVxx'
+4154,2704,0,2,4,14,54,154,154,4154,4154,108,109,'UDAAAA','AAEAAA','AAAAxx'
+7570,2705,0,2,0,10,70,570,1570,2570,7570,140,141,'EFAAAA','BAEAAA','HHHHxx'
+2576,2706,0,0,6,16,76,576,576,2576,2576,152,153,'CVAAAA','CAEAAA','OOOOxx'
+5764,2707,0,0,4,4,64,764,1764,764,5764,128,129,'SNAAAA','DAEAAA','VVVVxx'
+4314,2708,0,2,4,14,14,314,314,4314,4314,28,29,'YJAAAA','EAEAAA','AAAAxx'
+2274,2709,0,2,4,14,74,274,274,2274,2274,148,149,'MJAAAA','FAEAAA','HHHHxx'
+9756,2710,0,0,6,16,56,756,1756,4756,9756,112,113,'GLAAAA','GAEAAA','OOOOxx'
+8274,2711,0,2,4,14,74,274,274,3274,8274,148,149,'GGAAAA','HAEAAA','VVVVxx'
+1289,2712,1,1,9,9,89,289,1289,1289,1289,178,179,'PXAAAA','IAEAAA','AAAAxx'
+7335,2713,1,3,5,15,35,335,1335,2335,7335,70,71,'DWAAAA','JAEAAA','HHHHxx'
+5351,2714,1,3,1,11,51,351,1351,351,5351,102,103,'VXAAAA','KAEAAA','OOOOxx'
+8978,2715,0,2,8,18,78,978,978,3978,8978,156,157,'IHAAAA','LAEAAA','VVVVxx'
+2,2716,0,2,2,2,2,2,2,2,2,4,5,'CAAAAA','MAEAAA','AAAAxx'
+8906,2717,0,2,6,6,6,906,906,3906,8906,12,13,'OEAAAA','NAEAAA','HHHHxx'
+6388,2718,0,0,8,8,88,388,388,1388,6388,176,177,'SLAAAA','OAEAAA','OOOOxx'
+5675,2719,1,3,5,15,75,675,1675,675,5675,150,151,'HKAAAA','PAEAAA','VVVVxx'
+255,2720,1,3,5,15,55,255,255,255,255,110,111,'VJAAAA','QAEAAA','AAAAxx'
+9538,2721,0,2,8,18,38,538,1538,4538,9538,76,77,'WCAAAA','RAEAAA','HHHHxx'
+1480,2722,0,0,0,0,80,480,1480,1480,1480,160,161,'YEAAAA','SAEAAA','OOOOxx'
+4015,2723,1,3,5,15,15,15,15,4015,4015,30,31,'LYAAAA','TAEAAA','VVVVxx'
+5166,2724,0,2,6,6,66,166,1166,166,5166,132,133,'SQAAAA','UAEAAA','AAAAxx'
+91,2725,1,3,1,11,91,91,91,91,91,182,183,'NDAAAA','VAEAAA','HHHHxx'
+2958,2726,0,2,8,18,58,958,958,2958,2958,116,117,'UJAAAA','WAEAAA','OOOOxx'
+9131,2727,1,3,1,11,31,131,1131,4131,9131,62,63,'FNAAAA','XAEAAA','VVVVxx'
+3944,2728,0,0,4,4,44,944,1944,3944,3944,88,89,'SVAAAA','YAEAAA','AAAAxx'
+4514,2729,0,2,4,14,14,514,514,4514,4514,28,29,'QRAAAA','ZAEAAA','HHHHxx'
+5661,2730,1,1,1,1,61,661,1661,661,5661,122,123,'TJAAAA','ABEAAA','OOOOxx'
+8724,2731,0,0,4,4,24,724,724,3724,8724,48,49,'OXAAAA','BBEAAA','VVVVxx'
+6408,2732,0,0,8,8,8,408,408,1408,6408,16,17,'MMAAAA','CBEAAA','AAAAxx'
+5013,2733,1,1,3,13,13,13,1013,13,5013,26,27,'VKAAAA','DBEAAA','HHHHxx'
+6156,2734,0,0,6,16,56,156,156,1156,6156,112,113,'UCAAAA','EBEAAA','OOOOxx'
+7350,2735,0,2,0,10,50,350,1350,2350,7350,100,101,'SWAAAA','FBEAAA','VVVVxx'
+9858,2736,0,2,8,18,58,858,1858,4858,9858,116,117,'EPAAAA','GBEAAA','AAAAxx'
+895,2737,1,3,5,15,95,895,895,895,895,190,191,'LIAAAA','HBEAAA','HHHHxx'
+8368,2738,0,0,8,8,68,368,368,3368,8368,136,137,'WJAAAA','IBEAAA','OOOOxx'
+179,2739,1,3,9,19,79,179,179,179,179,158,159,'XGAAAA','JBEAAA','VVVVxx'
+4048,2740,0,0,8,8,48,48,48,4048,4048,96,97,'SZAAAA','KBEAAA','AAAAxx'
+3073,2741,1,1,3,13,73,73,1073,3073,3073,146,147,'FOAAAA','LBEAAA','HHHHxx'
+321,2742,1,1,1,1,21,321,321,321,321,42,43,'JMAAAA','MBEAAA','OOOOxx'
+5352,2743,0,0,2,12,52,352,1352,352,5352,104,105,'WXAAAA','NBEAAA','VVVVxx'
+1940,2744,0,0,0,0,40,940,1940,1940,1940,80,81,'QWAAAA','OBEAAA','AAAAxx'
+8803,2745,1,3,3,3,3,803,803,3803,8803,6,7,'PAAAAA','PBEAAA','HHHHxx'
+791,2746,1,3,1,11,91,791,791,791,791,182,183,'LEAAAA','QBEAAA','OOOOxx'
+9809,2747,1,1,9,9,9,809,1809,4809,9809,18,19,'HNAAAA','RBEAAA','VVVVxx'
+5519,2748,1,3,9,19,19,519,1519,519,5519,38,39,'HEAAAA','SBEAAA','AAAAxx'
+7420,2749,0,0,0,0,20,420,1420,2420,7420,40,41,'KZAAAA','TBEAAA','HHHHxx'
+7541,2750,1,1,1,1,41,541,1541,2541,7541,82,83,'BEAAAA','UBEAAA','OOOOxx'
+6538,2751,0,2,8,18,38,538,538,1538,6538,76,77,'MRAAAA','VBEAAA','VVVVxx'
+710,2752,0,2,0,10,10,710,710,710,710,20,21,'IBAAAA','WBEAAA','AAAAxx'
+9488,2753,0,0,8,8,88,488,1488,4488,9488,176,177,'YAAAAA','XBEAAA','HHHHxx'
+3135,2754,1,3,5,15,35,135,1135,3135,3135,70,71,'PQAAAA','YBEAAA','OOOOxx'
+4273,2755,1,1,3,13,73,273,273,4273,4273,146,147,'JIAAAA','ZBEAAA','VVVVxx'
+629,2756,1,1,9,9,29,629,629,629,629,58,59,'FYAAAA','ACEAAA','AAAAxx'
+9167,2757,1,3,7,7,67,167,1167,4167,9167,134,135,'POAAAA','BCEAAA','HHHHxx'
+751,2758,1,3,1,11,51,751,751,751,751,102,103,'XCAAAA','CCEAAA','OOOOxx'
+1126,2759,0,2,6,6,26,126,1126,1126,1126,52,53,'IRAAAA','DCEAAA','VVVVxx'
+3724,2760,0,0,4,4,24,724,1724,3724,3724,48,49,'GNAAAA','ECEAAA','AAAAxx'
+1789,2761,1,1,9,9,89,789,1789,1789,1789,178,179,'VQAAAA','FCEAAA','HHHHxx'
+792,2762,0,0,2,12,92,792,792,792,792,184,185,'MEAAAA','GCEAAA','OOOOxx'
+2771,2763,1,3,1,11,71,771,771,2771,2771,142,143,'PCAAAA','HCEAAA','VVVVxx'
+4313,2764,1,1,3,13,13,313,313,4313,4313,26,27,'XJAAAA','ICEAAA','AAAAxx'
+9312,2765,0,0,2,12,12,312,1312,4312,9312,24,25,'EUAAAA','JCEAAA','HHHHxx'
+955,2766,1,3,5,15,55,955,955,955,955,110,111,'TKAAAA','KCEAAA','OOOOxx'
+6382,2767,0,2,2,2,82,382,382,1382,6382,164,165,'MLAAAA','LCEAAA','VVVVxx'
+7875,2768,1,3,5,15,75,875,1875,2875,7875,150,151,'XQAAAA','MCEAAA','AAAAxx'
+7491,2769,1,3,1,11,91,491,1491,2491,7491,182,183,'DCAAAA','NCEAAA','HHHHxx'
+8193,2770,1,1,3,13,93,193,193,3193,8193,186,187,'DDAAAA','OCEAAA','OOOOxx'
+968,2771,0,0,8,8,68,968,968,968,968,136,137,'GLAAAA','PCEAAA','VVVVxx'
+4951,2772,1,3,1,11,51,951,951,4951,4951,102,103,'LIAAAA','QCEAAA','AAAAxx'
+2204,2773,0,0,4,4,4,204,204,2204,2204,8,9,'UGAAAA','RCEAAA','HHHHxx'
+2066,2774,0,2,6,6,66,66,66,2066,2066,132,133,'MBAAAA','SCEAAA','OOOOxx'
+2631,2775,1,3,1,11,31,631,631,2631,2631,62,63,'FXAAAA','TCEAAA','VVVVxx'
+8947,2776,1,3,7,7,47,947,947,3947,8947,94,95,'DGAAAA','UCEAAA','AAAAxx'
+8033,2777,1,1,3,13,33,33,33,3033,8033,66,67,'ZWAAAA','VCEAAA','HHHHxx'
+6264,2778,0,0,4,4,64,264,264,1264,6264,128,129,'YGAAAA','WCEAAA','OOOOxx'
+7778,2779,0,2,8,18,78,778,1778,2778,7778,156,157,'ENAAAA','XCEAAA','VVVVxx'
+9701,2780,1,1,1,1,1,701,1701,4701,9701,2,3,'DJAAAA','YCEAAA','AAAAxx'
+5091,2781,1,3,1,11,91,91,1091,91,5091,182,183,'VNAAAA','ZCEAAA','HHHHxx'
+7577,2782,1,1,7,17,77,577,1577,2577,7577,154,155,'LFAAAA','ADEAAA','OOOOxx'
+3345,2783,1,1,5,5,45,345,1345,3345,3345,90,91,'RYAAAA','BDEAAA','VVVVxx'
+7329,2784,1,1,9,9,29,329,1329,2329,7329,58,59,'XVAAAA','CDEAAA','AAAAxx'
+7551,2785,1,3,1,11,51,551,1551,2551,7551,102,103,'LEAAAA','DDEAAA','HHHHxx'
+6207,2786,1,3,7,7,7,207,207,1207,6207,14,15,'TEAAAA','EDEAAA','OOOOxx'
+8664,2787,0,0,4,4,64,664,664,3664,8664,128,129,'GVAAAA','FDEAAA','VVVVxx'
+8394,2788,0,2,4,14,94,394,394,3394,8394,188,189,'WKAAAA','GDEAAA','AAAAxx'
+7324,2789,0,0,4,4,24,324,1324,2324,7324,48,49,'SVAAAA','HDEAAA','HHHHxx'
+2713,2790,1,1,3,13,13,713,713,2713,2713,26,27,'JAAAAA','IDEAAA','OOOOxx'
+2230,2791,0,2,0,10,30,230,230,2230,2230,60,61,'UHAAAA','JDEAAA','VVVVxx'
+9211,2792,1,3,1,11,11,211,1211,4211,9211,22,23,'HQAAAA','KDEAAA','AAAAxx'
+1296,2793,0,0,6,16,96,296,1296,1296,1296,192,193,'WXAAAA','LDEAAA','HHHHxx'
+8104,2794,0,0,4,4,4,104,104,3104,8104,8,9,'SZAAAA','MDEAAA','OOOOxx'
+6916,2795,0,0,6,16,16,916,916,1916,6916,32,33,'AGAAAA','NDEAAA','VVVVxx'
+2208,2796,0,0,8,8,8,208,208,2208,2208,16,17,'YGAAAA','ODEAAA','AAAAxx'
+3935,2797,1,3,5,15,35,935,1935,3935,3935,70,71,'JVAAAA','PDEAAA','HHHHxx'
+7814,2798,0,2,4,14,14,814,1814,2814,7814,28,29,'OOAAAA','QDEAAA','OOOOxx'
+6508,2799,0,0,8,8,8,508,508,1508,6508,16,17,'IQAAAA','RDEAAA','VVVVxx'
+1703,2800,1,3,3,3,3,703,1703,1703,1703,6,7,'NNAAAA','SDEAAA','AAAAxx'
+5640,2801,0,0,0,0,40,640,1640,640,5640,80,81,'YIAAAA','TDEAAA','HHHHxx'
+6417,2802,1,1,7,17,17,417,417,1417,6417,34,35,'VMAAAA','UDEAAA','OOOOxx'
+1713,2803,1,1,3,13,13,713,1713,1713,1713,26,27,'XNAAAA','VDEAAA','VVVVxx'
+5309,2804,1,1,9,9,9,309,1309,309,5309,18,19,'FWAAAA','WDEAAA','AAAAxx'
+4364,2805,0,0,4,4,64,364,364,4364,4364,128,129,'WLAAAA','XDEAAA','HHHHxx'
+619,2806,1,3,9,19,19,619,619,619,619,38,39,'VXAAAA','YDEAAA','OOOOxx'
+9498,2807,0,2,8,18,98,498,1498,4498,9498,196,197,'IBAAAA','ZDEAAA','VVVVxx'
+2804,2808,0,0,4,4,4,804,804,2804,2804,8,9,'WDAAAA','AEEAAA','AAAAxx'
+2220,2809,0,0,0,0,20,220,220,2220,2220,40,41,'KHAAAA','BEEAAA','HHHHxx'
+9542,2810,0,2,2,2,42,542,1542,4542,9542,84,85,'ADAAAA','CEEAAA','OOOOxx'
+3349,2811,1,1,9,9,49,349,1349,3349,3349,98,99,'VYAAAA','DEEAAA','VVVVxx'
+9198,2812,0,2,8,18,98,198,1198,4198,9198,196,197,'UPAAAA','EEEAAA','AAAAxx'
+2727,2813,1,3,7,7,27,727,727,2727,2727,54,55,'XAAAAA','FEEAAA','HHHHxx'
+3768,2814,0,0,8,8,68,768,1768,3768,3768,136,137,'YOAAAA','GEEAAA','OOOOxx'
+2334,2815,0,2,4,14,34,334,334,2334,2334,68,69,'ULAAAA','HEEAAA','VVVVxx'
+7770,2816,0,2,0,10,70,770,1770,2770,7770,140,141,'WMAAAA','IEEAAA','AAAAxx'
+5963,2817,1,3,3,3,63,963,1963,963,5963,126,127,'JVAAAA','JEEAAA','HHHHxx'
+4732,2818,0,0,2,12,32,732,732,4732,4732,64,65,'AAAAAA','KEEAAA','OOOOxx'
+2448,2819,0,0,8,8,48,448,448,2448,2448,96,97,'EQAAAA','LEEAAA','VVVVxx'
+5998,2820,0,2,8,18,98,998,1998,998,5998,196,197,'SWAAAA','MEEAAA','AAAAxx'
+8577,2821,1,1,7,17,77,577,577,3577,8577,154,155,'XRAAAA','NEEAAA','HHHHxx'
+266,2822,0,2,6,6,66,266,266,266,266,132,133,'GKAAAA','OEEAAA','OOOOxx'
+2169,2823,1,1,9,9,69,169,169,2169,2169,138,139,'LFAAAA','PEEAAA','VVVVxx'
+8228,2824,0,0,8,8,28,228,228,3228,8228,56,57,'MEAAAA','QEEAAA','AAAAxx'
+4813,2825,1,1,3,13,13,813,813,4813,4813,26,27,'DDAAAA','REEAAA','HHHHxx'
+2769,2826,1,1,9,9,69,769,769,2769,2769,138,139,'NCAAAA','SEEAAA','OOOOxx'
+8382,2827,0,2,2,2,82,382,382,3382,8382,164,165,'KKAAAA','TEEAAA','VVVVxx'
+1717,2828,1,1,7,17,17,717,1717,1717,1717,34,35,'BOAAAA','UEEAAA','AAAAxx'
+7178,2829,0,2,8,18,78,178,1178,2178,7178,156,157,'CQAAAA','VEEAAA','HHHHxx'
+9547,2830,1,3,7,7,47,547,1547,4547,9547,94,95,'FDAAAA','WEEAAA','OOOOxx'
+8187,2831,1,3,7,7,87,187,187,3187,8187,174,175,'XCAAAA','XEEAAA','VVVVxx'
+3168,2832,0,0,8,8,68,168,1168,3168,3168,136,137,'WRAAAA','YEEAAA','AAAAxx'
+2180,2833,0,0,0,0,80,180,180,2180,2180,160,161,'WFAAAA','ZEEAAA','HHHHxx'
+859,2834,1,3,9,19,59,859,859,859,859,118,119,'BHAAAA','AFEAAA','OOOOxx'
+1554,2835,0,2,4,14,54,554,1554,1554,1554,108,109,'UHAAAA','BFEAAA','VVVVxx'
+3567,2836,1,3,7,7,67,567,1567,3567,3567,134,135,'FHAAAA','CFEAAA','AAAAxx'
+5985,2837,1,1,5,5,85,985,1985,985,5985,170,171,'FWAAAA','DFEAAA','HHHHxx'
+1,2838,1,1,1,1,1,1,1,1,1,2,3,'BAAAAA','EFEAAA','OOOOxx'
+5937,2839,1,1,7,17,37,937,1937,937,5937,74,75,'JUAAAA','FFEAAA','VVVVxx'
+7594,2840,0,2,4,14,94,594,1594,2594,7594,188,189,'CGAAAA','GFEAAA','AAAAxx'
+3783,2841,1,3,3,3,83,783,1783,3783,3783,166,167,'NPAAAA','HFEAAA','HHHHxx'
+6841,2842,1,1,1,1,41,841,841,1841,6841,82,83,'DDAAAA','IFEAAA','OOOOxx'
+9694,2843,0,2,4,14,94,694,1694,4694,9694,188,189,'WIAAAA','JFEAAA','VVVVxx'
+4322,2844,0,2,2,2,22,322,322,4322,4322,44,45,'GKAAAA','KFEAAA','AAAAxx'
+6012,2845,0,0,2,12,12,12,12,1012,6012,24,25,'GXAAAA','LFEAAA','HHHHxx'
+108,2846,0,0,8,8,8,108,108,108,108,16,17,'EEAAAA','MFEAAA','OOOOxx'
+3396,2847,0,0,6,16,96,396,1396,3396,3396,192,193,'QAAAAA','NFEAAA','VVVVxx'
+8643,2848,1,3,3,3,43,643,643,3643,8643,86,87,'LUAAAA','OFEAAA','AAAAxx'
+6087,2849,1,3,7,7,87,87,87,1087,6087,174,175,'DAAAAA','PFEAAA','HHHHxx'
+2629,2850,1,1,9,9,29,629,629,2629,2629,58,59,'DXAAAA','QFEAAA','OOOOxx'
+3009,2851,1,1,9,9,9,9,1009,3009,3009,18,19,'TLAAAA','RFEAAA','VVVVxx'
+438,2852,0,2,8,18,38,438,438,438,438,76,77,'WQAAAA','SFEAAA','AAAAxx'
+2480,2853,0,0,0,0,80,480,480,2480,2480,160,161,'KRAAAA','TFEAAA','HHHHxx'
+936,2854,0,0,6,16,36,936,936,936,936,72,73,'AKAAAA','UFEAAA','OOOOxx'
+6,2855,0,2,6,6,6,6,6,6,6,12,13,'GAAAAA','VFEAAA','VVVVxx'
+768,2856,0,0,8,8,68,768,768,768,768,136,137,'ODAAAA','WFEAAA','AAAAxx'
+1564,2857,0,0,4,4,64,564,1564,1564,1564,128,129,'EIAAAA','XFEAAA','HHHHxx'
+3236,2858,0,0,6,16,36,236,1236,3236,3236,72,73,'MUAAAA','YFEAAA','OOOOxx'
+3932,2859,0,0,2,12,32,932,1932,3932,3932,64,65,'GVAAAA','ZFEAAA','VVVVxx'
+8914,2860,0,2,4,14,14,914,914,3914,8914,28,29,'WEAAAA','AGEAAA','AAAAxx'
+119,2861,1,3,9,19,19,119,119,119,119,38,39,'PEAAAA','BGEAAA','HHHHxx'
+6034,2862,0,2,4,14,34,34,34,1034,6034,68,69,'CYAAAA','CGEAAA','OOOOxx'
+5384,2863,0,0,4,4,84,384,1384,384,5384,168,169,'CZAAAA','DGEAAA','VVVVxx'
+6885,2864,1,1,5,5,85,885,885,1885,6885,170,171,'VEAAAA','EGEAAA','AAAAxx'
+232,2865,0,0,2,12,32,232,232,232,232,64,65,'YIAAAA','FGEAAA','HHHHxx'
+1293,2866,1,1,3,13,93,293,1293,1293,1293,186,187,'TXAAAA','GGEAAA','OOOOxx'
+9204,2867,0,0,4,4,4,204,1204,4204,9204,8,9,'AQAAAA','HGEAAA','VVVVxx'
+527,2868,1,3,7,7,27,527,527,527,527,54,55,'HUAAAA','IGEAAA','AAAAxx'
+6539,2869,1,3,9,19,39,539,539,1539,6539,78,79,'NRAAAA','JGEAAA','HHHHxx'
+3679,2870,1,3,9,19,79,679,1679,3679,3679,158,159,'NLAAAA','KGEAAA','OOOOxx'
+8282,2871,0,2,2,2,82,282,282,3282,8282,164,165,'OGAAAA','LGEAAA','VVVVxx'
+5027,2872,1,3,7,7,27,27,1027,27,5027,54,55,'JLAAAA','MGEAAA','AAAAxx'
+7694,2873,0,2,4,14,94,694,1694,2694,7694,188,189,'YJAAAA','NGEAAA','HHHHxx'
+473,2874,1,1,3,13,73,473,473,473,473,146,147,'FSAAAA','OGEAAA','OOOOxx'
+6325,2875,1,1,5,5,25,325,325,1325,6325,50,51,'HJAAAA','PGEAAA','VVVVxx'
+8761,2876,1,1,1,1,61,761,761,3761,8761,122,123,'ZYAAAA','QGEAAA','AAAAxx'
+6184,2877,0,0,4,4,84,184,184,1184,6184,168,169,'WDAAAA','RGEAAA','HHHHxx'
+419,2878,1,3,9,19,19,419,419,419,419,38,39,'DQAAAA','SGEAAA','OOOOxx'
+6111,2879,1,3,1,11,11,111,111,1111,6111,22,23,'BBAAAA','TGEAAA','VVVVxx'
+3836,2880,0,0,6,16,36,836,1836,3836,3836,72,73,'ORAAAA','UGEAAA','AAAAxx'
+4086,2881,0,2,6,6,86,86,86,4086,4086,172,173,'EBAAAA','VGEAAA','HHHHxx'
+5818,2882,0,2,8,18,18,818,1818,818,5818,36,37,'UPAAAA','WGEAAA','OOOOxx'
+4528,2883,0,0,8,8,28,528,528,4528,4528,56,57,'ESAAAA','XGEAAA','VVVVxx'
+7199,2884,1,3,9,19,99,199,1199,2199,7199,198,199,'XQAAAA','YGEAAA','AAAAxx'
+1847,2885,1,3,7,7,47,847,1847,1847,1847,94,95,'BTAAAA','ZGEAAA','HHHHxx'
+2875,2886,1,3,5,15,75,875,875,2875,2875,150,151,'PGAAAA','AHEAAA','OOOOxx'
+2872,2887,0,0,2,12,72,872,872,2872,2872,144,145,'MGAAAA','BHEAAA','VVVVxx'
+3972,2888,0,0,2,12,72,972,1972,3972,3972,144,145,'UWAAAA','CHEAAA','AAAAxx'
+7590,2889,0,2,0,10,90,590,1590,2590,7590,180,181,'YFAAAA','DHEAAA','HHHHxx'
+1914,2890,0,2,4,14,14,914,1914,1914,1914,28,29,'QVAAAA','EHEAAA','OOOOxx'
+1658,2891,0,2,8,18,58,658,1658,1658,1658,116,117,'ULAAAA','FHEAAA','VVVVxx'
+2126,2892,0,2,6,6,26,126,126,2126,2126,52,53,'UDAAAA','GHEAAA','AAAAxx'
+645,2893,1,1,5,5,45,645,645,645,645,90,91,'VYAAAA','HHEAAA','HHHHxx'
+6636,2894,0,0,6,16,36,636,636,1636,6636,72,73,'GVAAAA','IHEAAA','OOOOxx'
+1469,2895,1,1,9,9,69,469,1469,1469,1469,138,139,'NEAAAA','JHEAAA','VVVVxx'
+1377,2896,1,1,7,17,77,377,1377,1377,1377,154,155,'ZAAAAA','KHEAAA','AAAAxx'
+8425,2897,1,1,5,5,25,425,425,3425,8425,50,51,'BMAAAA','LHEAAA','HHHHxx'
+9300,2898,0,0,0,0,0,300,1300,4300,9300,0,1,'STAAAA','MHEAAA','OOOOxx'
+5355,2899,1,3,5,15,55,355,1355,355,5355,110,111,'ZXAAAA','NHEAAA','VVVVxx'
+840,2900,0,0,0,0,40,840,840,840,840,80,81,'IGAAAA','OHEAAA','AAAAxx'
+5185,2901,1,1,5,5,85,185,1185,185,5185,170,171,'LRAAAA','PHEAAA','HHHHxx'
+6467,2902,1,3,7,7,67,467,467,1467,6467,134,135,'TOAAAA','QHEAAA','OOOOxx'
+58,2903,0,2,8,18,58,58,58,58,58,116,117,'GCAAAA','RHEAAA','VVVVxx'
+5051,2904,1,3,1,11,51,51,1051,51,5051,102,103,'HMAAAA','SHEAAA','AAAAxx'
+8901,2905,1,1,1,1,1,901,901,3901,8901,2,3,'JEAAAA','THEAAA','HHHHxx'
+1550,2906,0,2,0,10,50,550,1550,1550,1550,100,101,'QHAAAA','UHEAAA','OOOOxx'
+1698,2907,0,2,8,18,98,698,1698,1698,1698,196,197,'INAAAA','VHEAAA','VVVVxx'
+802,2908,0,2,2,2,2,802,802,802,802,4,5,'WEAAAA','WHEAAA','AAAAxx'
+2440,2909,0,0,0,0,40,440,440,2440,2440,80,81,'WPAAAA','XHEAAA','HHHHxx'
+2260,2910,0,0,0,0,60,260,260,2260,2260,120,121,'YIAAAA','YHEAAA','OOOOxx'
+8218,2911,0,2,8,18,18,218,218,3218,8218,36,37,'CEAAAA','ZHEAAA','VVVVxx'
+5144,2912,0,0,4,4,44,144,1144,144,5144,88,89,'WPAAAA','AIEAAA','AAAAxx'
+4822,2913,0,2,2,2,22,822,822,4822,4822,44,45,'MDAAAA','BIEAAA','HHHHxx'
+9476,2914,0,0,6,16,76,476,1476,4476,9476,152,153,'MAAAAA','CIEAAA','OOOOxx'
+7535,2915,1,3,5,15,35,535,1535,2535,7535,70,71,'VDAAAA','DIEAAA','VVVVxx'
+8738,2916,0,2,8,18,38,738,738,3738,8738,76,77,'CYAAAA','EIEAAA','AAAAxx'
+7946,2917,0,2,6,6,46,946,1946,2946,7946,92,93,'QTAAAA','FIEAAA','HHHHxx'
+8143,2918,1,3,3,3,43,143,143,3143,8143,86,87,'FBAAAA','GIEAAA','OOOOxx'
+2623,2919,1,3,3,3,23,623,623,2623,2623,46,47,'XWAAAA','HIEAAA','VVVVxx'
+5209,2920,1,1,9,9,9,209,1209,209,5209,18,19,'JSAAAA','IIEAAA','AAAAxx'
+7674,2921,0,2,4,14,74,674,1674,2674,7674,148,149,'EJAAAA','JIEAAA','HHHHxx'
+1135,2922,1,3,5,15,35,135,1135,1135,1135,70,71,'RRAAAA','KIEAAA','OOOOxx'
+424,2923,0,0,4,4,24,424,424,424,424,48,49,'IQAAAA','LIEAAA','VVVVxx'
+942,2924,0,2,2,2,42,942,942,942,942,84,85,'GKAAAA','MIEAAA','AAAAxx'
+7813,2925,1,1,3,13,13,813,1813,2813,7813,26,27,'NOAAAA','NIEAAA','HHHHxx'
+3539,2926,1,3,9,19,39,539,1539,3539,3539,78,79,'DGAAAA','OIEAAA','OOOOxx'
+2909,2927,1,1,9,9,9,909,909,2909,2909,18,19,'XHAAAA','PIEAAA','VVVVxx'
+3748,2928,0,0,8,8,48,748,1748,3748,3748,96,97,'EOAAAA','QIEAAA','AAAAxx'
+2996,2929,0,0,6,16,96,996,996,2996,2996,192,193,'GLAAAA','RIEAAA','HHHHxx'
+1869,2930,1,1,9,9,69,869,1869,1869,1869,138,139,'XTAAAA','SIEAAA','OOOOxx'
+8151,2931,1,3,1,11,51,151,151,3151,8151,102,103,'NBAAAA','TIEAAA','VVVVxx'
+6361,2932,1,1,1,1,61,361,361,1361,6361,122,123,'RKAAAA','UIEAAA','AAAAxx'
+5568,2933,0,0,8,8,68,568,1568,568,5568,136,137,'EGAAAA','VIEAAA','HHHHxx'
+2796,2934,0,0,6,16,96,796,796,2796,2796,192,193,'ODAAAA','WIEAAA','OOOOxx'
+8489,2935,1,1,9,9,89,489,489,3489,8489,178,179,'NOAAAA','XIEAAA','VVVVxx'
+9183,2936,1,3,3,3,83,183,1183,4183,9183,166,167,'FPAAAA','YIEAAA','AAAAxx'
+8227,2937,1,3,7,7,27,227,227,3227,8227,54,55,'LEAAAA','ZIEAAA','HHHHxx'
+1844,2938,0,0,4,4,44,844,1844,1844,1844,88,89,'YSAAAA','AJEAAA','OOOOxx'
+3975,2939,1,3,5,15,75,975,1975,3975,3975,150,151,'XWAAAA','BJEAAA','VVVVxx'
+6490,2940,0,2,0,10,90,490,490,1490,6490,180,181,'QPAAAA','CJEAAA','AAAAxx'
+8303,2941,1,3,3,3,3,303,303,3303,8303,6,7,'JHAAAA','DJEAAA','HHHHxx'
+7334,2942,0,2,4,14,34,334,1334,2334,7334,68,69,'CWAAAA','EJEAAA','OOOOxx'
+2382,2943,0,2,2,2,82,382,382,2382,2382,164,165,'QNAAAA','FJEAAA','VVVVxx'
+177,2944,1,1,7,17,77,177,177,177,177,154,155,'VGAAAA','GJEAAA','AAAAxx'
+8117,2945,1,1,7,17,17,117,117,3117,8117,34,35,'FAAAAA','HJEAAA','HHHHxx'
+5485,2946,1,1,5,5,85,485,1485,485,5485,170,171,'ZCAAAA','IJEAAA','OOOOxx'
+6544,2947,0,0,4,4,44,544,544,1544,6544,88,89,'SRAAAA','JJEAAA','VVVVxx'
+8517,2948,1,1,7,17,17,517,517,3517,8517,34,35,'PPAAAA','KJEAAA','AAAAxx'
+2252,2949,0,0,2,12,52,252,252,2252,2252,104,105,'QIAAAA','LJEAAA','HHHHxx'
+4480,2950,0,0,0,0,80,480,480,4480,4480,160,161,'IQAAAA','MJEAAA','OOOOxx'
+4785,2951,1,1,5,5,85,785,785,4785,4785,170,171,'BCAAAA','NJEAAA','VVVVxx'
+9700,2952,0,0,0,0,0,700,1700,4700,9700,0,1,'CJAAAA','OJEAAA','AAAAxx'
+2122,2953,0,2,2,2,22,122,122,2122,2122,44,45,'QDAAAA','PJEAAA','HHHHxx'
+8783,2954,1,3,3,3,83,783,783,3783,8783,166,167,'VZAAAA','QJEAAA','OOOOxx'
+1453,2955,1,1,3,13,53,453,1453,1453,1453,106,107,'XDAAAA','RJEAAA','VVVVxx'
+3908,2956,0,0,8,8,8,908,1908,3908,3908,16,17,'IUAAAA','SJEAAA','AAAAxx'
+7707,2957,1,3,7,7,7,707,1707,2707,7707,14,15,'LKAAAA','TJEAAA','HHHHxx'
+9049,2958,1,1,9,9,49,49,1049,4049,9049,98,99,'BKAAAA','UJEAAA','OOOOxx'
+654,2959,0,2,4,14,54,654,654,654,654,108,109,'EZAAAA','VJEAAA','VVVVxx'
+3336,2960,0,0,6,16,36,336,1336,3336,3336,72,73,'IYAAAA','WJEAAA','AAAAxx'
+622,2961,0,2,2,2,22,622,622,622,622,44,45,'YXAAAA','XJEAAA','HHHHxx'
+8398,2962,0,2,8,18,98,398,398,3398,8398,196,197,'ALAAAA','YJEAAA','OOOOxx'
+9193,2963,1,1,3,13,93,193,1193,4193,9193,186,187,'PPAAAA','ZJEAAA','VVVVxx'
+7896,2964,0,0,6,16,96,896,1896,2896,7896,192,193,'SRAAAA','AKEAAA','AAAAxx'
+9798,2965,0,2,8,18,98,798,1798,4798,9798,196,197,'WMAAAA','BKEAAA','HHHHxx'
+2881,2966,1,1,1,1,81,881,881,2881,2881,162,163,'VGAAAA','CKEAAA','OOOOxx'
+672,2967,0,0,2,12,72,672,672,672,672,144,145,'WZAAAA','DKEAAA','VVVVxx'
+6743,2968,1,3,3,3,43,743,743,1743,6743,86,87,'JZAAAA','EKEAAA','AAAAxx'
+8935,2969,1,3,5,15,35,935,935,3935,8935,70,71,'RFAAAA','FKEAAA','HHHHxx'
+2426,2970,0,2,6,6,26,426,426,2426,2426,52,53,'IPAAAA','GKEAAA','OOOOxx'
+722,2971,0,2,2,2,22,722,722,722,722,44,45,'UBAAAA','HKEAAA','VVVVxx'
+5088,2972,0,0,8,8,88,88,1088,88,5088,176,177,'SNAAAA','IKEAAA','AAAAxx'
+8677,2973,1,1,7,17,77,677,677,3677,8677,154,155,'TVAAAA','JKEAAA','HHHHxx'
+6963,2974,1,3,3,3,63,963,963,1963,6963,126,127,'VHAAAA','KKEAAA','OOOOxx'
+1653,2975,1,1,3,13,53,653,1653,1653,1653,106,107,'PLAAAA','LKEAAA','VVVVxx'
+7295,2976,1,3,5,15,95,295,1295,2295,7295,190,191,'PUAAAA','MKEAAA','AAAAxx'
+6675,2977,1,3,5,15,75,675,675,1675,6675,150,151,'TWAAAA','NKEAAA','HHHHxx'
+7183,2978,1,3,3,3,83,183,1183,2183,7183,166,167,'HQAAAA','OKEAAA','OOOOxx'
+4378,2979,0,2,8,18,78,378,378,4378,4378,156,157,'KMAAAA','PKEAAA','VVVVxx'
+2157,2980,1,1,7,17,57,157,157,2157,2157,114,115,'ZEAAAA','QKEAAA','AAAAxx'
+2621,2981,1,1,1,1,21,621,621,2621,2621,42,43,'VWAAAA','RKEAAA','HHHHxx'
+9278,2982,0,2,8,18,78,278,1278,4278,9278,156,157,'WSAAAA','SKEAAA','OOOOxx'
+79,2983,1,3,9,19,79,79,79,79,79,158,159,'BDAAAA','TKEAAA','VVVVxx'
+7358,2984,0,2,8,18,58,358,1358,2358,7358,116,117,'AXAAAA','UKEAAA','AAAAxx'
+3589,2985,1,1,9,9,89,589,1589,3589,3589,178,179,'BIAAAA','VKEAAA','HHHHxx'
+1254,2986,0,2,4,14,54,254,1254,1254,1254,108,109,'GWAAAA','WKEAAA','OOOOxx'
+3490,2987,0,2,0,10,90,490,1490,3490,3490,180,181,'GEAAAA','XKEAAA','VVVVxx'
+7533,2988,1,1,3,13,33,533,1533,2533,7533,66,67,'TDAAAA','YKEAAA','AAAAxx'
+2800,2989,0,0,0,0,0,800,800,2800,2800,0,1,'SDAAAA','ZKEAAA','HHHHxx'
+351,2990,1,3,1,11,51,351,351,351,351,102,103,'NNAAAA','ALEAAA','OOOOxx'
+4359,2991,1,3,9,19,59,359,359,4359,4359,118,119,'RLAAAA','BLEAAA','VVVVxx'
+5788,2992,0,0,8,8,88,788,1788,788,5788,176,177,'QOAAAA','CLEAAA','AAAAxx'
+5521,2993,1,1,1,1,21,521,1521,521,5521,42,43,'JEAAAA','DLEAAA','HHHHxx'
+3351,2994,1,3,1,11,51,351,1351,3351,3351,102,103,'XYAAAA','ELEAAA','OOOOxx'
+5129,2995,1,1,9,9,29,129,1129,129,5129,58,59,'HPAAAA','FLEAAA','VVVVxx'
+315,2996,1,3,5,15,15,315,315,315,315,30,31,'DMAAAA','GLEAAA','AAAAxx'
+7552,2997,0,0,2,12,52,552,1552,2552,7552,104,105,'MEAAAA','HLEAAA','HHHHxx'
+9176,2998,0,0,6,16,76,176,1176,4176,9176,152,153,'YOAAAA','ILEAAA','OOOOxx'
+7458,2999,0,2,8,18,58,458,1458,2458,7458,116,117,'WAAAAA','JLEAAA','VVVVxx'
+279,3000,1,3,9,19,79,279,279,279,279,158,159,'TKAAAA','KLEAAA','AAAAxx'
+738,3001,0,2,8,18,38,738,738,738,738,76,77,'KCAAAA','LLEAAA','HHHHxx'
+2557,3002,1,1,7,17,57,557,557,2557,2557,114,115,'JUAAAA','MLEAAA','OOOOxx'
+9395,3003,1,3,5,15,95,395,1395,4395,9395,190,191,'JXAAAA','NLEAAA','VVVVxx'
+7214,3004,0,2,4,14,14,214,1214,2214,7214,28,29,'MRAAAA','OLEAAA','AAAAxx'
+6354,3005,0,2,4,14,54,354,354,1354,6354,108,109,'KKAAAA','PLEAAA','HHHHxx'
+4799,3006,1,3,9,19,99,799,799,4799,4799,198,199,'PCAAAA','QLEAAA','OOOOxx'
+1231,3007,1,3,1,11,31,231,1231,1231,1231,62,63,'JVAAAA','RLEAAA','VVVVxx'
+5252,3008,0,0,2,12,52,252,1252,252,5252,104,105,'AUAAAA','SLEAAA','AAAAxx'
+5250,3009,0,2,0,10,50,250,1250,250,5250,100,101,'YTAAAA','TLEAAA','HHHHxx'
+9319,3010,1,3,9,19,19,319,1319,4319,9319,38,39,'LUAAAA','ULEAAA','OOOOxx'
+1724,3011,0,0,4,4,24,724,1724,1724,1724,48,49,'IOAAAA','VLEAAA','VVVVxx'
+7947,3012,1,3,7,7,47,947,1947,2947,7947,94,95,'RTAAAA','WLEAAA','AAAAxx'
+1105,3013,1,1,5,5,5,105,1105,1105,1105,10,11,'NQAAAA','XLEAAA','HHHHxx'
+1417,3014,1,1,7,17,17,417,1417,1417,1417,34,35,'NCAAAA','YLEAAA','OOOOxx'
+7101,3015,1,1,1,1,1,101,1101,2101,7101,2,3,'DNAAAA','ZLEAAA','VVVVxx'
+1088,3016,0,0,8,8,88,88,1088,1088,1088,176,177,'WPAAAA','AMEAAA','AAAAxx'
+979,3017,1,3,9,19,79,979,979,979,979,158,159,'RLAAAA','BMEAAA','HHHHxx'
+7589,3018,1,1,9,9,89,589,1589,2589,7589,178,179,'XFAAAA','CMEAAA','OOOOxx'
+8952,3019,0,0,2,12,52,952,952,3952,8952,104,105,'IGAAAA','DMEAAA','VVVVxx'
+2864,3020,0,0,4,4,64,864,864,2864,2864,128,129,'EGAAAA','EMEAAA','AAAAxx'
+234,3021,0,2,4,14,34,234,234,234,234,68,69,'AJAAAA','FMEAAA','HHHHxx'
+7231,3022,1,3,1,11,31,231,1231,2231,7231,62,63,'DSAAAA','GMEAAA','OOOOxx'
+6792,3023,0,0,2,12,92,792,792,1792,6792,184,185,'GBAAAA','HMEAAA','VVVVxx'
+4311,3024,1,3,1,11,11,311,311,4311,4311,22,23,'VJAAAA','IMEAAA','AAAAxx'
+3374,3025,0,2,4,14,74,374,1374,3374,3374,148,149,'UZAAAA','JMEAAA','HHHHxx'
+3367,3026,1,3,7,7,67,367,1367,3367,3367,134,135,'NZAAAA','KMEAAA','OOOOxx'
+2598,3027,0,2,8,18,98,598,598,2598,2598,196,197,'YVAAAA','LMEAAA','VVVVxx'
+1033,3028,1,1,3,13,33,33,1033,1033,1033,66,67,'TNAAAA','MMEAAA','AAAAxx'
+7803,3029,1,3,3,3,3,803,1803,2803,7803,6,7,'DOAAAA','NMEAAA','HHHHxx'
+3870,3030,0,2,0,10,70,870,1870,3870,3870,140,141,'WSAAAA','OMEAAA','OOOOxx'
+4962,3031,0,2,2,2,62,962,962,4962,4962,124,125,'WIAAAA','PMEAAA','VVVVxx'
+4842,3032,0,2,2,2,42,842,842,4842,4842,84,85,'GEAAAA','QMEAAA','AAAAxx'
+8814,3033,0,2,4,14,14,814,814,3814,8814,28,29,'ABAAAA','RMEAAA','HHHHxx'
+3429,3034,1,1,9,9,29,429,1429,3429,3429,58,59,'XBAAAA','SMEAAA','OOOOxx'
+6550,3035,0,2,0,10,50,550,550,1550,6550,100,101,'YRAAAA','TMEAAA','VVVVxx'
+6317,3036,1,1,7,17,17,317,317,1317,6317,34,35,'ZIAAAA','UMEAAA','AAAAxx'
+5023,3037,1,3,3,3,23,23,1023,23,5023,46,47,'FLAAAA','VMEAAA','HHHHxx'
+5825,3038,1,1,5,5,25,825,1825,825,5825,50,51,'BQAAAA','WMEAAA','OOOOxx'
+5297,3039,1,1,7,17,97,297,1297,297,5297,194,195,'TVAAAA','XMEAAA','VVVVxx'
+8764,3040,0,0,4,4,64,764,764,3764,8764,128,129,'CZAAAA','YMEAAA','AAAAxx'
+5084,3041,0,0,4,4,84,84,1084,84,5084,168,169,'ONAAAA','ZMEAAA','HHHHxx'
+6808,3042,0,0,8,8,8,808,808,1808,6808,16,17,'WBAAAA','ANEAAA','OOOOxx'
+1780,3043,0,0,0,0,80,780,1780,1780,1780,160,161,'MQAAAA','BNEAAA','VVVVxx'
+4092,3044,0,0,2,12,92,92,92,4092,4092,184,185,'KBAAAA','CNEAAA','AAAAxx'
+3618,3045,0,2,8,18,18,618,1618,3618,3618,36,37,'EJAAAA','DNEAAA','HHHHxx'
+7299,3046,1,3,9,19,99,299,1299,2299,7299,198,199,'TUAAAA','ENEAAA','OOOOxx'
+8544,3047,0,0,4,4,44,544,544,3544,8544,88,89,'QQAAAA','FNEAAA','VVVVxx'
+2359,3048,1,3,9,19,59,359,359,2359,2359,118,119,'TMAAAA','GNEAAA','AAAAxx'
+1939,3049,1,3,9,19,39,939,1939,1939,1939,78,79,'PWAAAA','HNEAAA','HHHHxx'
+5834,3050,0,2,4,14,34,834,1834,834,5834,68,69,'KQAAAA','INEAAA','OOOOxx'
+1997,3051,1,1,7,17,97,997,1997,1997,1997,194,195,'VYAAAA','JNEAAA','VVVVxx'
+7917,3052,1,1,7,17,17,917,1917,2917,7917,34,35,'NSAAAA','KNEAAA','AAAAxx'
+2098,3053,0,2,8,18,98,98,98,2098,2098,196,197,'SCAAAA','LNEAAA','HHHHxx'
+7576,3054,0,0,6,16,76,576,1576,2576,7576,152,153,'KFAAAA','MNEAAA','OOOOxx'
+376,3055,0,0,6,16,76,376,376,376,376,152,153,'MOAAAA','NNEAAA','VVVVxx'
+8535,3056,1,3,5,15,35,535,535,3535,8535,70,71,'HQAAAA','ONEAAA','AAAAxx'
+5659,3057,1,3,9,19,59,659,1659,659,5659,118,119,'RJAAAA','PNEAAA','HHHHxx'
+2786,3058,0,2,6,6,86,786,786,2786,2786,172,173,'EDAAAA','QNEAAA','OOOOxx'
+8820,3059,0,0,0,0,20,820,820,3820,8820,40,41,'GBAAAA','RNEAAA','VVVVxx'
+1229,3060,1,1,9,9,29,229,1229,1229,1229,58,59,'HVAAAA','SNEAAA','AAAAxx'
+9321,3061,1,1,1,1,21,321,1321,4321,9321,42,43,'NUAAAA','TNEAAA','HHHHxx'
+7662,3062,0,2,2,2,62,662,1662,2662,7662,124,125,'SIAAAA','UNEAAA','OOOOxx'
+5535,3063,1,3,5,15,35,535,1535,535,5535,70,71,'XEAAAA','VNEAAA','VVVVxx'
+4889,3064,1,1,9,9,89,889,889,4889,4889,178,179,'BGAAAA','WNEAAA','AAAAxx'
+8259,3065,1,3,9,19,59,259,259,3259,8259,118,119,'RFAAAA','XNEAAA','HHHHxx'
+6789,3066,1,1,9,9,89,789,789,1789,6789,178,179,'DBAAAA','YNEAAA','OOOOxx'
+5411,3067,1,3,1,11,11,411,1411,411,5411,22,23,'DAAAAA','ZNEAAA','VVVVxx'
+6992,3068,0,0,2,12,92,992,992,1992,6992,184,185,'YIAAAA','AOEAAA','AAAAxx'
+7698,3069,0,2,8,18,98,698,1698,2698,7698,196,197,'CKAAAA','BOEAAA','HHHHxx'
+2342,3070,0,2,2,2,42,342,342,2342,2342,84,85,'CMAAAA','COEAAA','OOOOxx'
+1501,3071,1,1,1,1,1,501,1501,1501,1501,2,3,'TFAAAA','DOEAAA','VVVVxx'
+6322,3072,0,2,2,2,22,322,322,1322,6322,44,45,'EJAAAA','EOEAAA','AAAAxx'
+9861,3073,1,1,1,1,61,861,1861,4861,9861,122,123,'HPAAAA','FOEAAA','HHHHxx'
+9802,3074,0,2,2,2,2,802,1802,4802,9802,4,5,'ANAAAA','GOEAAA','OOOOxx'
+4750,3075,0,2,0,10,50,750,750,4750,4750,100,101,'SAAAAA','HOEAAA','VVVVxx'
+5855,3076,1,3,5,15,55,855,1855,855,5855,110,111,'FRAAAA','IOEAAA','AAAAxx'
+4304,3077,0,0,4,4,4,304,304,4304,4304,8,9,'OJAAAA','JOEAAA','HHHHxx'
+2605,3078,1,1,5,5,5,605,605,2605,2605,10,11,'FWAAAA','KOEAAA','OOOOxx'
+1802,3079,0,2,2,2,2,802,1802,1802,1802,4,5,'IRAAAA','LOEAAA','VVVVxx'
+9368,3080,0,0,8,8,68,368,1368,4368,9368,136,137,'IWAAAA','MOEAAA','AAAAxx'
+7107,3081,1,3,7,7,7,107,1107,2107,7107,14,15,'JNAAAA','NOEAAA','HHHHxx'
+8895,3082,1,3,5,15,95,895,895,3895,8895,190,191,'DEAAAA','OOEAAA','OOOOxx'
+3750,3083,0,2,0,10,50,750,1750,3750,3750,100,101,'GOAAAA','POEAAA','VVVVxx'
+8934,3084,0,2,4,14,34,934,934,3934,8934,68,69,'QFAAAA','QOEAAA','AAAAxx'
+9464,3085,0,0,4,4,64,464,1464,4464,9464,128,129,'AAAAAA','ROEAAA','HHHHxx'
+1928,3086,0,0,8,8,28,928,1928,1928,1928,56,57,'EWAAAA','SOEAAA','OOOOxx'
+3196,3087,0,0,6,16,96,196,1196,3196,3196,192,193,'YSAAAA','TOEAAA','VVVVxx'
+5256,3088,0,0,6,16,56,256,1256,256,5256,112,113,'EUAAAA','UOEAAA','AAAAxx'
+7119,3089,1,3,9,19,19,119,1119,2119,7119,38,39,'VNAAAA','VOEAAA','HHHHxx'
+4495,3090,1,3,5,15,95,495,495,4495,4495,190,191,'XQAAAA','WOEAAA','OOOOxx'
+9292,3091,0,0,2,12,92,292,1292,4292,9292,184,185,'KTAAAA','XOEAAA','VVVVxx'
+1617,3092,1,1,7,17,17,617,1617,1617,1617,34,35,'FKAAAA','YOEAAA','AAAAxx'
+481,3093,1,1,1,1,81,481,481,481,481,162,163,'NSAAAA','ZOEAAA','HHHHxx'
+56,3094,0,0,6,16,56,56,56,56,56,112,113,'ECAAAA','APEAAA','OOOOxx'
+9120,3095,0,0,0,0,20,120,1120,4120,9120,40,41,'UMAAAA','BPEAAA','VVVVxx'
+1306,3096,0,2,6,6,6,306,1306,1306,1306,12,13,'GYAAAA','CPEAAA','AAAAxx'
+7773,3097,1,1,3,13,73,773,1773,2773,7773,146,147,'ZMAAAA','DPEAAA','HHHHxx'
+4863,3098,1,3,3,3,63,863,863,4863,4863,126,127,'BFAAAA','EPEAAA','OOOOxx'
+1114,3099,0,2,4,14,14,114,1114,1114,1114,28,29,'WQAAAA','FPEAAA','VVVVxx'
+8124,3100,0,0,4,4,24,124,124,3124,8124,48,49,'MAAAAA','GPEAAA','AAAAxx'
+6254,3101,0,2,4,14,54,254,254,1254,6254,108,109,'OGAAAA','HPEAAA','HHHHxx'
+8109,3102,1,1,9,9,9,109,109,3109,8109,18,19,'XZAAAA','IPEAAA','OOOOxx'
+1747,3103,1,3,7,7,47,747,1747,1747,1747,94,95,'FPAAAA','JPEAAA','VVVVxx'
+6185,3104,1,1,5,5,85,185,185,1185,6185,170,171,'XDAAAA','KPEAAA','AAAAxx'
+3388,3105,0,0,8,8,88,388,1388,3388,3388,176,177,'IAAAAA','LPEAAA','HHHHxx'
+4905,3106,1,1,5,5,5,905,905,4905,4905,10,11,'RGAAAA','MPEAAA','OOOOxx'
+5728,3107,0,0,8,8,28,728,1728,728,5728,56,57,'IMAAAA','NPEAAA','VVVVxx'
+7507,3108,1,3,7,7,7,507,1507,2507,7507,14,15,'TCAAAA','OPEAAA','AAAAxx'
+5662,3109,0,2,2,2,62,662,1662,662,5662,124,125,'UJAAAA','PPEAAA','HHHHxx'
+1686,3110,0,2,6,6,86,686,1686,1686,1686,172,173,'WMAAAA','QPEAAA','OOOOxx'
+5202,3111,0,2,2,2,2,202,1202,202,5202,4,5,'CSAAAA','RPEAAA','VVVVxx'
+6905,3112,1,1,5,5,5,905,905,1905,6905,10,11,'PFAAAA','SPEAAA','AAAAxx'
+9577,3113,1,1,7,17,77,577,1577,4577,9577,154,155,'JEAAAA','TPEAAA','HHHHxx'
+7194,3114,0,2,4,14,94,194,1194,2194,7194,188,189,'SQAAAA','UPEAAA','OOOOxx'
+7016,3115,0,0,6,16,16,16,1016,2016,7016,32,33,'WJAAAA','VPEAAA','VVVVxx'
+8905,3116,1,1,5,5,5,905,905,3905,8905,10,11,'NEAAAA','WPEAAA','AAAAxx'
+3419,3117,1,3,9,19,19,419,1419,3419,3419,38,39,'NBAAAA','XPEAAA','HHHHxx'
+6881,3118,1,1,1,1,81,881,881,1881,6881,162,163,'REAAAA','YPEAAA','OOOOxx'
+8370,3119,0,2,0,10,70,370,370,3370,8370,140,141,'YJAAAA','ZPEAAA','VVVVxx'
+6117,3120,1,1,7,17,17,117,117,1117,6117,34,35,'HBAAAA','AQEAAA','AAAAxx'
+1636,3121,0,0,6,16,36,636,1636,1636,1636,72,73,'YKAAAA','BQEAAA','HHHHxx'
+6857,3122,1,1,7,17,57,857,857,1857,6857,114,115,'TDAAAA','CQEAAA','OOOOxx'
+7163,3123,1,3,3,3,63,163,1163,2163,7163,126,127,'NPAAAA','DQEAAA','VVVVxx'
+5040,3124,0,0,0,0,40,40,1040,40,5040,80,81,'WLAAAA','EQEAAA','AAAAxx'
+6263,3125,1,3,3,3,63,263,263,1263,6263,126,127,'XGAAAA','FQEAAA','HHHHxx'
+4809,3126,1,1,9,9,9,809,809,4809,4809,18,19,'ZCAAAA','GQEAAA','OOOOxx'
+900,3127,0,0,0,0,0,900,900,900,900,0,1,'QIAAAA','HQEAAA','VVVVxx'
+3199,3128,1,3,9,19,99,199,1199,3199,3199,198,199,'BTAAAA','IQEAAA','AAAAxx'
+4156,3129,0,0,6,16,56,156,156,4156,4156,112,113,'WDAAAA','JQEAAA','HHHHxx'
+3501,3130,1,1,1,1,1,501,1501,3501,3501,2,3,'REAAAA','KQEAAA','OOOOxx'
+164,3131,0,0,4,4,64,164,164,164,164,128,129,'IGAAAA','LQEAAA','VVVVxx'
+9548,3132,0,0,8,8,48,548,1548,4548,9548,96,97,'GDAAAA','MQEAAA','AAAAxx'
+1149,3133,1,1,9,9,49,149,1149,1149,1149,98,99,'FSAAAA','NQEAAA','HHHHxx'
+1962,3134,0,2,2,2,62,962,1962,1962,1962,124,125,'MXAAAA','OQEAAA','OOOOxx'
+4072,3135,0,0,2,12,72,72,72,4072,4072,144,145,'QAAAAA','PQEAAA','VVVVxx'
+4280,3136,0,0,0,0,80,280,280,4280,4280,160,161,'QIAAAA','QQEAAA','AAAAxx'
+1398,3137,0,2,8,18,98,398,1398,1398,1398,196,197,'UBAAAA','RQEAAA','HHHHxx'
+725,3138,1,1,5,5,25,725,725,725,725,50,51,'XBAAAA','SQEAAA','OOOOxx'
+3988,3139,0,0,8,8,88,988,1988,3988,3988,176,177,'KXAAAA','TQEAAA','VVVVxx'
+5059,3140,1,3,9,19,59,59,1059,59,5059,118,119,'PMAAAA','UQEAAA','AAAAxx'
+2632,3141,0,0,2,12,32,632,632,2632,2632,64,65,'GXAAAA','VQEAAA','HHHHxx'
+1909,3142,1,1,9,9,9,909,1909,1909,1909,18,19,'LVAAAA','WQEAAA','OOOOxx'
+6827,3143,1,3,7,7,27,827,827,1827,6827,54,55,'PCAAAA','XQEAAA','VVVVxx'
+8156,3144,0,0,6,16,56,156,156,3156,8156,112,113,'SBAAAA','YQEAAA','AAAAxx'
+1192,3145,0,0,2,12,92,192,1192,1192,1192,184,185,'WTAAAA','ZQEAAA','HHHHxx'
+9545,3146,1,1,5,5,45,545,1545,4545,9545,90,91,'DDAAAA','AREAAA','OOOOxx'
+2249,3147,1,1,9,9,49,249,249,2249,2249,98,99,'NIAAAA','BREAAA','VVVVxx'
+5580,3148,0,0,0,0,80,580,1580,580,5580,160,161,'QGAAAA','CREAAA','AAAAxx'
+8403,3149,1,3,3,3,3,403,403,3403,8403,6,7,'FLAAAA','DREAAA','HHHHxx'
+4024,3150,0,0,4,4,24,24,24,4024,4024,48,49,'UYAAAA','EREAAA','OOOOxx'
+1866,3151,0,2,6,6,66,866,1866,1866,1866,132,133,'UTAAAA','FREAAA','VVVVxx'
+9251,3152,1,3,1,11,51,251,1251,4251,9251,102,103,'VRAAAA','GREAAA','AAAAxx'
+9979,3153,1,3,9,19,79,979,1979,4979,9979,158,159,'VTAAAA','HREAAA','HHHHxx'
+9899,3154,1,3,9,19,99,899,1899,4899,9899,198,199,'TQAAAA','IREAAA','OOOOxx'
+2540,3155,0,0,0,0,40,540,540,2540,2540,80,81,'STAAAA','JREAAA','VVVVxx'
+8957,3156,1,1,7,17,57,957,957,3957,8957,114,115,'NGAAAA','KREAAA','AAAAxx'
+7702,3157,0,2,2,2,2,702,1702,2702,7702,4,5,'GKAAAA','LREAAA','HHHHxx'
+4211,3158,1,3,1,11,11,211,211,4211,4211,22,23,'ZFAAAA','MREAAA','OOOOxx'
+6684,3159,0,0,4,4,84,684,684,1684,6684,168,169,'CXAAAA','NREAAA','VVVVxx'
+3883,3160,1,3,3,3,83,883,1883,3883,3883,166,167,'JTAAAA','OREAAA','AAAAxx'
+3531,3161,1,3,1,11,31,531,1531,3531,3531,62,63,'VFAAAA','PREAAA','HHHHxx'
+9178,3162,0,2,8,18,78,178,1178,4178,9178,156,157,'APAAAA','QREAAA','OOOOxx'
+3389,3163,1,1,9,9,89,389,1389,3389,3389,178,179,'JAAAAA','RREAAA','VVVVxx'
+7874,3164,0,2,4,14,74,874,1874,2874,7874,148,149,'WQAAAA','SREAAA','AAAAxx'
+4522,3165,0,2,2,2,22,522,522,4522,4522,44,45,'YRAAAA','TREAAA','HHHHxx'
+9399,3166,1,3,9,19,99,399,1399,4399,9399,198,199,'NXAAAA','UREAAA','OOOOxx'
+9083,3167,1,3,3,3,83,83,1083,4083,9083,166,167,'JLAAAA','VREAAA','VVVVxx'
+1530,3168,0,2,0,10,30,530,1530,1530,1530,60,61,'WGAAAA','WREAAA','AAAAxx'
+2360,3169,0,0,0,0,60,360,360,2360,2360,120,121,'UMAAAA','XREAAA','HHHHxx'
+4908,3170,0,0,8,8,8,908,908,4908,4908,16,17,'UGAAAA','YREAAA','OOOOxx'
+4628,3171,0,0,8,8,28,628,628,4628,4628,56,57,'AWAAAA','ZREAAA','VVVVxx'
+3889,3172,1,1,9,9,89,889,1889,3889,3889,178,179,'PTAAAA','ASEAAA','AAAAxx'
+1331,3173,1,3,1,11,31,331,1331,1331,1331,62,63,'FZAAAA','BSEAAA','HHHHxx'
+1942,3174,0,2,2,2,42,942,1942,1942,1942,84,85,'SWAAAA','CSEAAA','OOOOxx'
+4734,3175,0,2,4,14,34,734,734,4734,4734,68,69,'CAAAAA','DSEAAA','VVVVxx'
+8386,3176,0,2,6,6,86,386,386,3386,8386,172,173,'OKAAAA','ESEAAA','AAAAxx'
+3586,3177,0,2,6,6,86,586,1586,3586,3586,172,173,'YHAAAA','FSEAAA','HHHHxx'
+2354,3178,0,2,4,14,54,354,354,2354,2354,108,109,'OMAAAA','GSEAAA','OOOOxx'
+7108,3179,0,0,8,8,8,108,1108,2108,7108,16,17,'KNAAAA','HSEAAA','VVVVxx'
+1857,3180,1,1,7,17,57,857,1857,1857,1857,114,115,'LTAAAA','ISEAAA','AAAAxx'
+2544,3181,0,0,4,4,44,544,544,2544,2544,88,89,'WTAAAA','JSEAAA','HHHHxx'
+819,3182,1,3,9,19,19,819,819,819,819,38,39,'NFAAAA','KSEAAA','OOOOxx'
+2878,3183,0,2,8,18,78,878,878,2878,2878,156,157,'SGAAAA','LSEAAA','VVVVxx'
+1772,3184,0,0,2,12,72,772,1772,1772,1772,144,145,'EQAAAA','MSEAAA','AAAAxx'
+354,3185,0,2,4,14,54,354,354,354,354,108,109,'QNAAAA','NSEAAA','HHHHxx'
+3259,3186,1,3,9,19,59,259,1259,3259,3259,118,119,'JVAAAA','OSEAAA','OOOOxx'
+2170,3187,0,2,0,10,70,170,170,2170,2170,140,141,'MFAAAA','PSEAAA','VVVVxx'
+1190,3188,0,2,0,10,90,190,1190,1190,1190,180,181,'UTAAAA','QSEAAA','AAAAxx'
+3607,3189,1,3,7,7,7,607,1607,3607,3607,14,15,'TIAAAA','RSEAAA','HHHHxx'
+4661,3190,1,1,1,1,61,661,661,4661,4661,122,123,'HXAAAA','SSEAAA','OOOOxx'
+1796,3191,0,0,6,16,96,796,1796,1796,1796,192,193,'CRAAAA','TSEAAA','VVVVxx'
+1561,3192,1,1,1,1,61,561,1561,1561,1561,122,123,'BIAAAA','USEAAA','AAAAxx'
+4336,3193,0,0,6,16,36,336,336,4336,4336,72,73,'UKAAAA','VSEAAA','HHHHxx'
+7550,3194,0,2,0,10,50,550,1550,2550,7550,100,101,'KEAAAA','WSEAAA','OOOOxx'
+3238,3195,0,2,8,18,38,238,1238,3238,3238,76,77,'OUAAAA','XSEAAA','VVVVxx'
+9870,3196,0,2,0,10,70,870,1870,4870,9870,140,141,'QPAAAA','YSEAAA','AAAAxx'
+6502,3197,0,2,2,2,2,502,502,1502,6502,4,5,'CQAAAA','ZSEAAA','HHHHxx'
+3903,3198,1,3,3,3,3,903,1903,3903,3903,6,7,'DUAAAA','ATEAAA','OOOOxx'
+2869,3199,1,1,9,9,69,869,869,2869,2869,138,139,'JGAAAA','BTEAAA','VVVVxx'
+5072,3200,0,0,2,12,72,72,1072,72,5072,144,145,'CNAAAA','CTEAAA','AAAAxx'
+1201,3201,1,1,1,1,1,201,1201,1201,1201,2,3,'FUAAAA','DTEAAA','HHHHxx'
+6245,3202,1,1,5,5,45,245,245,1245,6245,90,91,'FGAAAA','ETEAAA','OOOOxx'
+1402,3203,0,2,2,2,2,402,1402,1402,1402,4,5,'YBAAAA','FTEAAA','VVVVxx'
+2594,3204,0,2,4,14,94,594,594,2594,2594,188,189,'UVAAAA','GTEAAA','AAAAxx'
+9171,3205,1,3,1,11,71,171,1171,4171,9171,142,143,'TOAAAA','HTEAAA','HHHHxx'
+2620,3206,0,0,0,0,20,620,620,2620,2620,40,41,'UWAAAA','ITEAAA','OOOOxx'
+6309,3207,1,1,9,9,9,309,309,1309,6309,18,19,'RIAAAA','JTEAAA','VVVVxx'
+1285,3208,1,1,5,5,85,285,1285,1285,1285,170,171,'LXAAAA','KTEAAA','AAAAxx'
+5466,3209,0,2,6,6,66,466,1466,466,5466,132,133,'GCAAAA','LTEAAA','HHHHxx'
+168,3210,0,0,8,8,68,168,168,168,168,136,137,'MGAAAA','MTEAAA','OOOOxx'
+1410,3211,0,2,0,10,10,410,1410,1410,1410,20,21,'GCAAAA','NTEAAA','VVVVxx'
+6332,3212,0,0,2,12,32,332,332,1332,6332,64,65,'OJAAAA','OTEAAA','AAAAxx'
+9530,3213,0,2,0,10,30,530,1530,4530,9530,60,61,'OCAAAA','PTEAAA','HHHHxx'
+7749,3214,1,1,9,9,49,749,1749,2749,7749,98,99,'BMAAAA','QTEAAA','OOOOxx'
+3656,3215,0,0,6,16,56,656,1656,3656,3656,112,113,'QKAAAA','RTEAAA','VVVVxx'
+37,3216,1,1,7,17,37,37,37,37,37,74,75,'LBAAAA','STEAAA','AAAAxx'
+2744,3217,0,0,4,4,44,744,744,2744,2744,88,89,'OBAAAA','TTEAAA','HHHHxx'
+4206,3218,0,2,6,6,6,206,206,4206,4206,12,13,'UFAAAA','UTEAAA','OOOOxx'
+1846,3219,0,2,6,6,46,846,1846,1846,1846,92,93,'ATAAAA','VTEAAA','VVVVxx'
+9913,3220,1,1,3,13,13,913,1913,4913,9913,26,27,'HRAAAA','WTEAAA','AAAAxx'
+4078,3221,0,2,8,18,78,78,78,4078,4078,156,157,'WAAAAA','XTEAAA','HHHHxx'
+2080,3222,0,0,0,0,80,80,80,2080,2080,160,161,'ACAAAA','YTEAAA','OOOOxx'
+4169,3223,1,1,9,9,69,169,169,4169,4169,138,139,'JEAAAA','ZTEAAA','VVVVxx'
+2070,3224,0,2,0,10,70,70,70,2070,2070,140,141,'QBAAAA','AUEAAA','AAAAxx'
+4500,3225,0,0,0,0,0,500,500,4500,4500,0,1,'CRAAAA','BUEAAA','HHHHxx'
+4123,3226,1,3,3,3,23,123,123,4123,4123,46,47,'PCAAAA','CUEAAA','OOOOxx'
+5594,3227,0,2,4,14,94,594,1594,594,5594,188,189,'EHAAAA','DUEAAA','VVVVxx'
+9941,3228,1,1,1,1,41,941,1941,4941,9941,82,83,'JSAAAA','EUEAAA','AAAAxx'
+7154,3229,0,2,4,14,54,154,1154,2154,7154,108,109,'EPAAAA','FUEAAA','HHHHxx'
+8340,3230,0,0,0,0,40,340,340,3340,8340,80,81,'UIAAAA','GUEAAA','OOOOxx'
+7110,3231,0,2,0,10,10,110,1110,2110,7110,20,21,'MNAAAA','HUEAAA','VVVVxx'
+7795,3232,1,3,5,15,95,795,1795,2795,7795,190,191,'VNAAAA','IUEAAA','AAAAxx'
+132,3233,0,0,2,12,32,132,132,132,132,64,65,'CFAAAA','JUEAAA','HHHHxx'
+4603,3234,1,3,3,3,3,603,603,4603,4603,6,7,'BVAAAA','KUEAAA','OOOOxx'
+9720,3235,0,0,0,0,20,720,1720,4720,9720,40,41,'WJAAAA','LUEAAA','VVVVxx'
+1460,3236,0,0,0,0,60,460,1460,1460,1460,120,121,'EEAAAA','MUEAAA','AAAAxx'
+4677,3237,1,1,7,17,77,677,677,4677,4677,154,155,'XXAAAA','NUEAAA','HHHHxx'
+9272,3238,0,0,2,12,72,272,1272,4272,9272,144,145,'QSAAAA','OUEAAA','OOOOxx'
+2279,3239,1,3,9,19,79,279,279,2279,2279,158,159,'RJAAAA','PUEAAA','VVVVxx'
+4587,3240,1,3,7,7,87,587,587,4587,4587,174,175,'LUAAAA','QUEAAA','AAAAxx'
+2244,3241,0,0,4,4,44,244,244,2244,2244,88,89,'IIAAAA','RUEAAA','HHHHxx'
+742,3242,0,2,2,2,42,742,742,742,742,84,85,'OCAAAA','SUEAAA','OOOOxx'
+4426,3243,0,2,6,6,26,426,426,4426,4426,52,53,'GOAAAA','TUEAAA','VVVVxx'
+4571,3244,1,3,1,11,71,571,571,4571,4571,142,143,'VTAAAA','UUEAAA','AAAAxx'
+4775,3245,1,3,5,15,75,775,775,4775,4775,150,151,'RBAAAA','VUEAAA','HHHHxx'
+24,3246,0,0,4,4,24,24,24,24,24,48,49,'YAAAAA','WUEAAA','OOOOxx'
+4175,3247,1,3,5,15,75,175,175,4175,4175,150,151,'PEAAAA','XUEAAA','VVVVxx'
+9877,3248,1,1,7,17,77,877,1877,4877,9877,154,155,'XPAAAA','YUEAAA','AAAAxx'
+7271,3249,1,3,1,11,71,271,1271,2271,7271,142,143,'RTAAAA','ZUEAAA','HHHHxx'
+5468,3250,0,0,8,8,68,468,1468,468,5468,136,137,'ICAAAA','AVEAAA','OOOOxx'
+6106,3251,0,2,6,6,6,106,106,1106,6106,12,13,'WAAAAA','BVEAAA','VVVVxx'
+9005,3252,1,1,5,5,5,5,1005,4005,9005,10,11,'JIAAAA','CVEAAA','AAAAxx'
+109,3253,1,1,9,9,9,109,109,109,109,18,19,'FEAAAA','DVEAAA','HHHHxx'
+6365,3254,1,1,5,5,65,365,365,1365,6365,130,131,'VKAAAA','EVEAAA','OOOOxx'
+7437,3255,1,1,7,17,37,437,1437,2437,7437,74,75,'BAAAAA','FVEAAA','VVVVxx'
+7979,3256,1,3,9,19,79,979,1979,2979,7979,158,159,'XUAAAA','GVEAAA','AAAAxx'
+6050,3257,0,2,0,10,50,50,50,1050,6050,100,101,'SYAAAA','HVEAAA','HHHHxx'
+2853,3258,1,1,3,13,53,853,853,2853,2853,106,107,'TFAAAA','IVEAAA','OOOOxx'
+7603,3259,1,3,3,3,3,603,1603,2603,7603,6,7,'LGAAAA','JVEAAA','VVVVxx'
+483,3260,1,3,3,3,83,483,483,483,483,166,167,'PSAAAA','KVEAAA','AAAAxx'
+5994,3261,0,2,4,14,94,994,1994,994,5994,188,189,'OWAAAA','LVEAAA','HHHHxx'
+6708,3262,0,0,8,8,8,708,708,1708,6708,16,17,'AYAAAA','MVEAAA','OOOOxx'
+5090,3263,0,2,0,10,90,90,1090,90,5090,180,181,'UNAAAA','NVEAAA','VVVVxx'
+4608,3264,0,0,8,8,8,608,608,4608,4608,16,17,'GVAAAA','OVEAAA','AAAAxx'
+4551,3265,1,3,1,11,51,551,551,4551,4551,102,103,'BTAAAA','PVEAAA','HHHHxx'
+5437,3266,1,1,7,17,37,437,1437,437,5437,74,75,'DBAAAA','QVEAAA','OOOOxx'
+4130,3267,0,2,0,10,30,130,130,4130,4130,60,61,'WCAAAA','RVEAAA','VVVVxx'
+6363,3268,1,3,3,3,63,363,363,1363,6363,126,127,'TKAAAA','SVEAAA','AAAAxx'
+1499,3269,1,3,9,19,99,499,1499,1499,1499,198,199,'RFAAAA','TVEAAA','HHHHxx'
+384,3270,0,0,4,4,84,384,384,384,384,168,169,'UOAAAA','UVEAAA','OOOOxx'
+2266,3271,0,2,6,6,66,266,266,2266,2266,132,133,'EJAAAA','VVEAAA','VVVVxx'
+6018,3272,0,2,8,18,18,18,18,1018,6018,36,37,'MXAAAA','WVEAAA','AAAAxx'
+7915,3273,1,3,5,15,15,915,1915,2915,7915,30,31,'LSAAAA','XVEAAA','HHHHxx'
+6167,3274,1,3,7,7,67,167,167,1167,6167,134,135,'FDAAAA','YVEAAA','OOOOxx'
+9988,3275,0,0,8,8,88,988,1988,4988,9988,176,177,'EUAAAA','ZVEAAA','VVVVxx'
+6599,3276,1,3,9,19,99,599,599,1599,6599,198,199,'VTAAAA','AWEAAA','AAAAxx'
+1693,3277,1,1,3,13,93,693,1693,1693,1693,186,187,'DNAAAA','BWEAAA','HHHHxx'
+5971,3278,1,3,1,11,71,971,1971,971,5971,142,143,'RVAAAA','CWEAAA','OOOOxx'
+8470,3279,0,2,0,10,70,470,470,3470,8470,140,141,'UNAAAA','DWEAAA','VVVVxx'
+2807,3280,1,3,7,7,7,807,807,2807,2807,14,15,'ZDAAAA','EWEAAA','AAAAxx'
+1120,3281,0,0,0,0,20,120,1120,1120,1120,40,41,'CRAAAA','FWEAAA','HHHHxx'
+5924,3282,0,0,4,4,24,924,1924,924,5924,48,49,'WTAAAA','GWEAAA','OOOOxx'
+9025,3283,1,1,5,5,25,25,1025,4025,9025,50,51,'DJAAAA','HWEAAA','VVVVxx'
+9454,3284,0,2,4,14,54,454,1454,4454,9454,108,109,'QZAAAA','IWEAAA','AAAAxx'
+2259,3285,1,3,9,19,59,259,259,2259,2259,118,119,'XIAAAA','JWEAAA','HHHHxx'
+5249,3286,1,1,9,9,49,249,1249,249,5249,98,99,'XTAAAA','KWEAAA','OOOOxx'
+6350,3287,0,2,0,10,50,350,350,1350,6350,100,101,'GKAAAA','LWEAAA','VVVVxx'
+2930,3288,0,2,0,10,30,930,930,2930,2930,60,61,'SIAAAA','MWEAAA','AAAAxx'
+6055,3289,1,3,5,15,55,55,55,1055,6055,110,111,'XYAAAA','NWEAAA','HHHHxx'
+7691,3290,1,3,1,11,91,691,1691,2691,7691,182,183,'VJAAAA','OWEAAA','OOOOxx'
+1573,3291,1,1,3,13,73,573,1573,1573,1573,146,147,'NIAAAA','PWEAAA','VVVVxx'
+9943,3292,1,3,3,3,43,943,1943,4943,9943,86,87,'LSAAAA','QWEAAA','AAAAxx'
+3085,3293,1,1,5,5,85,85,1085,3085,3085,170,171,'ROAAAA','RWEAAA','HHHHxx'
+5928,3294,0,0,8,8,28,928,1928,928,5928,56,57,'AUAAAA','SWEAAA','OOOOxx'
+887,3295,1,3,7,7,87,887,887,887,887,174,175,'DIAAAA','TWEAAA','VVVVxx'
+4630,3296,0,2,0,10,30,630,630,4630,4630,60,61,'CWAAAA','UWEAAA','AAAAxx'
+9827,3297,1,3,7,7,27,827,1827,4827,9827,54,55,'ZNAAAA','VWEAAA','HHHHxx'
+8926,3298,0,2,6,6,26,926,926,3926,8926,52,53,'IFAAAA','WWEAAA','OOOOxx'
+5726,3299,0,2,6,6,26,726,1726,726,5726,52,53,'GMAAAA','XWEAAA','VVVVxx'
+1569,3300,1,1,9,9,69,569,1569,1569,1569,138,139,'JIAAAA','YWEAAA','AAAAxx'
+8074,3301,0,2,4,14,74,74,74,3074,8074,148,149,'OYAAAA','ZWEAAA','HHHHxx'
+7909,3302,1,1,9,9,9,909,1909,2909,7909,18,19,'FSAAAA','AXEAAA','OOOOxx'
+8367,3303,1,3,7,7,67,367,367,3367,8367,134,135,'VJAAAA','BXEAAA','VVVVxx'
+7217,3304,1,1,7,17,17,217,1217,2217,7217,34,35,'PRAAAA','CXEAAA','AAAAxx'
+5254,3305,0,2,4,14,54,254,1254,254,5254,108,109,'CUAAAA','DXEAAA','HHHHxx'
+1181,3306,1,1,1,1,81,181,1181,1181,1181,162,163,'LTAAAA','EXEAAA','OOOOxx'
+6907,3307,1,3,7,7,7,907,907,1907,6907,14,15,'RFAAAA','FXEAAA','VVVVxx'
+5508,3308,0,0,8,8,8,508,1508,508,5508,16,17,'WDAAAA','GXEAAA','AAAAxx'
+4782,3309,0,2,2,2,82,782,782,4782,4782,164,165,'YBAAAA','HXEAAA','HHHHxx'
+793,3310,1,1,3,13,93,793,793,793,793,186,187,'NEAAAA','IXEAAA','OOOOxx'
+5740,3311,0,0,0,0,40,740,1740,740,5740,80,81,'UMAAAA','JXEAAA','VVVVxx'
+3107,3312,1,3,7,7,7,107,1107,3107,3107,14,15,'NPAAAA','KXEAAA','AAAAxx'
+1197,3313,1,1,7,17,97,197,1197,1197,1197,194,195,'BUAAAA','LXEAAA','HHHHxx'
+4376,3314,0,0,6,16,76,376,376,4376,4376,152,153,'IMAAAA','MXEAAA','OOOOxx'
+6226,3315,0,2,6,6,26,226,226,1226,6226,52,53,'MFAAAA','NXEAAA','VVVVxx'
+5033,3316,1,1,3,13,33,33,1033,33,5033,66,67,'PLAAAA','OXEAAA','AAAAxx'
+5494,3317,0,2,4,14,94,494,1494,494,5494,188,189,'IDAAAA','PXEAAA','HHHHxx'
+3244,3318,0,0,4,4,44,244,1244,3244,3244,88,89,'UUAAAA','QXEAAA','OOOOxx'
+7670,3319,0,2,0,10,70,670,1670,2670,7670,140,141,'AJAAAA','RXEAAA','VVVVxx'
+9273,3320,1,1,3,13,73,273,1273,4273,9273,146,147,'RSAAAA','SXEAAA','AAAAxx'
+5248,3321,0,0,8,8,48,248,1248,248,5248,96,97,'WTAAAA','TXEAAA','HHHHxx'
+3381,3322,1,1,1,1,81,381,1381,3381,3381,162,163,'BAAAAA','UXEAAA','OOOOxx'
+4136,3323,0,0,6,16,36,136,136,4136,4136,72,73,'CDAAAA','VXEAAA','VVVVxx'
+4163,3324,1,3,3,3,63,163,163,4163,4163,126,127,'DEAAAA','WXEAAA','AAAAxx'
+4270,3325,0,2,0,10,70,270,270,4270,4270,140,141,'GIAAAA','XXEAAA','HHHHxx'
+1729,3326,1,1,9,9,29,729,1729,1729,1729,58,59,'NOAAAA','YXEAAA','OOOOxx'
+2778,3327,0,2,8,18,78,778,778,2778,2778,156,157,'WCAAAA','ZXEAAA','VVVVxx'
+5082,3328,0,2,2,2,82,82,1082,82,5082,164,165,'MNAAAA','AYEAAA','AAAAxx'
+870,3329,0,2,0,10,70,870,870,870,870,140,141,'MHAAAA','BYEAAA','HHHHxx'
+4192,3330,0,0,2,12,92,192,192,4192,4192,184,185,'GFAAAA','CYEAAA','OOOOxx'
+308,3331,0,0,8,8,8,308,308,308,308,16,17,'WLAAAA','DYEAAA','VVVVxx'
+6783,3332,1,3,3,3,83,783,783,1783,6783,166,167,'XAAAAA','EYEAAA','AAAAxx'
+7611,3333,1,3,1,11,11,611,1611,2611,7611,22,23,'TGAAAA','FYEAAA','HHHHxx'
+4221,3334,1,1,1,1,21,221,221,4221,4221,42,43,'JGAAAA','GYEAAA','OOOOxx'
+6353,3335,1,1,3,13,53,353,353,1353,6353,106,107,'JKAAAA','HYEAAA','VVVVxx'
+1830,3336,0,2,0,10,30,830,1830,1830,1830,60,61,'KSAAAA','IYEAAA','AAAAxx'
+2437,3337,1,1,7,17,37,437,437,2437,2437,74,75,'TPAAAA','JYEAAA','HHHHxx'
+3360,3338,0,0,0,0,60,360,1360,3360,3360,120,121,'GZAAAA','KYEAAA','OOOOxx'
+1829,3339,1,1,9,9,29,829,1829,1829,1829,58,59,'JSAAAA','LYEAAA','VVVVxx'
+9475,3340,1,3,5,15,75,475,1475,4475,9475,150,151,'LAAAAA','MYEAAA','AAAAxx'
+4566,3341,0,2,6,6,66,566,566,4566,4566,132,133,'QTAAAA','NYEAAA','HHHHxx'
+9944,3342,0,0,4,4,44,944,1944,4944,9944,88,89,'MSAAAA','OYEAAA','OOOOxx'
+6054,3343,0,2,4,14,54,54,54,1054,6054,108,109,'WYAAAA','PYEAAA','VVVVxx'
+4722,3344,0,2,2,2,22,722,722,4722,4722,44,45,'QZAAAA','QYEAAA','AAAAxx'
+2779,3345,1,3,9,19,79,779,779,2779,2779,158,159,'XCAAAA','RYEAAA','HHHHxx'
+8051,3346,1,3,1,11,51,51,51,3051,8051,102,103,'RXAAAA','SYEAAA','OOOOxx'
+9671,3347,1,3,1,11,71,671,1671,4671,9671,142,143,'ZHAAAA','TYEAAA','VVVVxx'
+6084,3348,0,0,4,4,84,84,84,1084,6084,168,169,'AAAAAA','UYEAAA','AAAAxx'
+3729,3349,1,1,9,9,29,729,1729,3729,3729,58,59,'LNAAAA','VYEAAA','HHHHxx'
+6627,3350,1,3,7,7,27,627,627,1627,6627,54,55,'XUAAAA','WYEAAA','OOOOxx'
+4769,3351,1,1,9,9,69,769,769,4769,4769,138,139,'LBAAAA','XYEAAA','VVVVxx'
+2224,3352,0,0,4,4,24,224,224,2224,2224,48,49,'OHAAAA','YYEAAA','AAAAxx'
+1404,3353,0,0,4,4,4,404,1404,1404,1404,8,9,'ACAAAA','ZYEAAA','HHHHxx'
+8532,3354,0,0,2,12,32,532,532,3532,8532,64,65,'EQAAAA','AZEAAA','OOOOxx'
+6759,3355,1,3,9,19,59,759,759,1759,6759,118,119,'ZZAAAA','BZEAAA','VVVVxx'
+6404,3356,0,0,4,4,4,404,404,1404,6404,8,9,'IMAAAA','CZEAAA','AAAAxx'
+3144,3357,0,0,4,4,44,144,1144,3144,3144,88,89,'YQAAAA','DZEAAA','HHHHxx'
+973,3358,1,1,3,13,73,973,973,973,973,146,147,'LLAAAA','EZEAAA','OOOOxx'
+9789,3359,1,1,9,9,89,789,1789,4789,9789,178,179,'NMAAAA','FZEAAA','VVVVxx'
+6181,3360,1,1,1,1,81,181,181,1181,6181,162,163,'TDAAAA','GZEAAA','AAAAxx'
+1519,3361,1,3,9,19,19,519,1519,1519,1519,38,39,'LGAAAA','HZEAAA','HHHHxx'
+9729,3362,1,1,9,9,29,729,1729,4729,9729,58,59,'FKAAAA','IZEAAA','OOOOxx'
+8167,3363,1,3,7,7,67,167,167,3167,8167,134,135,'DCAAAA','JZEAAA','VVVVxx'
+3830,3364,0,2,0,10,30,830,1830,3830,3830,60,61,'IRAAAA','KZEAAA','AAAAxx'
+6286,3365,0,2,6,6,86,286,286,1286,6286,172,173,'UHAAAA','LZEAAA','HHHHxx'
+3047,3366,1,3,7,7,47,47,1047,3047,3047,94,95,'FNAAAA','MZEAAA','OOOOxx'
+3183,3367,1,3,3,3,83,183,1183,3183,3183,166,167,'LSAAAA','NZEAAA','VVVVxx'
+6687,3368,1,3,7,7,87,687,687,1687,6687,174,175,'FXAAAA','OZEAAA','AAAAxx'
+2783,3369,1,3,3,3,83,783,783,2783,2783,166,167,'BDAAAA','PZEAAA','HHHHxx'
+9920,3370,0,0,0,0,20,920,1920,4920,9920,40,41,'ORAAAA','QZEAAA','OOOOxx'
+4847,3371,1,3,7,7,47,847,847,4847,4847,94,95,'LEAAAA','RZEAAA','VVVVxx'
+3645,3372,1,1,5,5,45,645,1645,3645,3645,90,91,'FKAAAA','SZEAAA','AAAAxx'
+7406,3373,0,2,6,6,6,406,1406,2406,7406,12,13,'WYAAAA','TZEAAA','HHHHxx'
+6003,3374,1,3,3,3,3,3,3,1003,6003,6,7,'XWAAAA','UZEAAA','OOOOxx'
+3408,3375,0,0,8,8,8,408,1408,3408,3408,16,17,'CBAAAA','VZEAAA','VVVVxx'
+4243,3376,1,3,3,3,43,243,243,4243,4243,86,87,'FHAAAA','WZEAAA','AAAAxx'
+1622,3377,0,2,2,2,22,622,1622,1622,1622,44,45,'KKAAAA','XZEAAA','HHHHxx'
+5319,3378,1,3,9,19,19,319,1319,319,5319,38,39,'PWAAAA','YZEAAA','OOOOxx'
+4033,3379,1,1,3,13,33,33,33,4033,4033,66,67,'DZAAAA','ZZEAAA','VVVVxx'
+8573,3380,1,1,3,13,73,573,573,3573,8573,146,147,'TRAAAA','AAFAAA','AAAAxx'
+8404,3381,0,0,4,4,4,404,404,3404,8404,8,9,'GLAAAA','BAFAAA','HHHHxx'
+6993,3382,1,1,3,13,93,993,993,1993,6993,186,187,'ZIAAAA','CAFAAA','OOOOxx'
+660,3383,0,0,0,0,60,660,660,660,660,120,121,'KZAAAA','DAFAAA','VVVVxx'
+1136,3384,0,0,6,16,36,136,1136,1136,1136,72,73,'SRAAAA','EAFAAA','AAAAxx'
+3393,3385,1,1,3,13,93,393,1393,3393,3393,186,187,'NAAAAA','FAFAAA','HHHHxx'
+9743,3386,1,3,3,3,43,743,1743,4743,9743,86,87,'TKAAAA','GAFAAA','OOOOxx'
+9705,3387,1,1,5,5,5,705,1705,4705,9705,10,11,'HJAAAA','HAFAAA','VVVVxx'
+6960,3388,0,0,0,0,60,960,960,1960,6960,120,121,'SHAAAA','IAFAAA','AAAAxx'
+2753,3389,1,1,3,13,53,753,753,2753,2753,106,107,'XBAAAA','JAFAAA','HHHHxx'
+906,3390,0,2,6,6,6,906,906,906,906,12,13,'WIAAAA','KAFAAA','OOOOxx'
+999,3391,1,3,9,19,99,999,999,999,999,198,199,'LMAAAA','LAFAAA','VVVVxx'
+6927,3392,1,3,7,7,27,927,927,1927,6927,54,55,'LGAAAA','MAFAAA','AAAAxx'
+4846,3393,0,2,6,6,46,846,846,4846,4846,92,93,'KEAAAA','NAFAAA','HHHHxx'
+676,3394,0,0,6,16,76,676,676,676,676,152,153,'AAAAAA','OAFAAA','OOOOxx'
+8612,3395,0,0,2,12,12,612,612,3612,8612,24,25,'GTAAAA','PAFAAA','VVVVxx'
+4111,3396,1,3,1,11,11,111,111,4111,4111,22,23,'DCAAAA','QAFAAA','AAAAxx'
+9994,3397,0,2,4,14,94,994,1994,4994,9994,188,189,'KUAAAA','RAFAAA','HHHHxx'
+4399,3398,1,3,9,19,99,399,399,4399,4399,198,199,'FNAAAA','SAFAAA','OOOOxx'
+4464,3399,0,0,4,4,64,464,464,4464,4464,128,129,'SPAAAA','TAFAAA','VVVVxx'
+7316,3400,0,0,6,16,16,316,1316,2316,7316,32,33,'KVAAAA','UAFAAA','AAAAxx'
+8982,3401,0,2,2,2,82,982,982,3982,8982,164,165,'MHAAAA','VAFAAA','HHHHxx'
+1871,3402,1,3,1,11,71,871,1871,1871,1871,142,143,'ZTAAAA','WAFAAA','OOOOxx'
+4082,3403,0,2,2,2,82,82,82,4082,4082,164,165,'ABAAAA','XAFAAA','VVVVxx'
+3949,3404,1,1,9,9,49,949,1949,3949,3949,98,99,'XVAAAA','YAFAAA','AAAAxx'
+9352,3405,0,0,2,12,52,352,1352,4352,9352,104,105,'SVAAAA','ZAFAAA','HHHHxx'
+9638,3406,0,2,8,18,38,638,1638,4638,9638,76,77,'SGAAAA','ABFAAA','OOOOxx'
+8177,3407,1,1,7,17,77,177,177,3177,8177,154,155,'NCAAAA','BBFAAA','VVVVxx'
+3499,3408,1,3,9,19,99,499,1499,3499,3499,198,199,'PEAAAA','CBFAAA','AAAAxx'
+4233,3409,1,1,3,13,33,233,233,4233,4233,66,67,'VGAAAA','DBFAAA','HHHHxx'
+1953,3410,1,1,3,13,53,953,1953,1953,1953,106,107,'DXAAAA','EBFAAA','OOOOxx'
+7372,3411,0,0,2,12,72,372,1372,2372,7372,144,145,'OXAAAA','FBFAAA','VVVVxx'
+5127,3412,1,3,7,7,27,127,1127,127,5127,54,55,'FPAAAA','GBFAAA','AAAAxx'
+4384,3413,0,0,4,4,84,384,384,4384,4384,168,169,'QMAAAA','HBFAAA','HHHHxx'
+9964,3414,0,0,4,4,64,964,1964,4964,9964,128,129,'GTAAAA','IBFAAA','OOOOxx'
+5392,3415,0,0,2,12,92,392,1392,392,5392,184,185,'KZAAAA','JBFAAA','VVVVxx'
+616,3416,0,0,6,16,16,616,616,616,616,32,33,'SXAAAA','KBFAAA','AAAAxx'
+591,3417,1,3,1,11,91,591,591,591,591,182,183,'TWAAAA','LBFAAA','HHHHxx'
+6422,3418,0,2,2,2,22,422,422,1422,6422,44,45,'ANAAAA','MBFAAA','OOOOxx'
+6551,3419,1,3,1,11,51,551,551,1551,6551,102,103,'ZRAAAA','NBFAAA','VVVVxx'
+9286,3420,0,2,6,6,86,286,1286,4286,9286,172,173,'ETAAAA','OBFAAA','AAAAxx'
+3817,3421,1,1,7,17,17,817,1817,3817,3817,34,35,'VQAAAA','PBFAAA','HHHHxx'
+7717,3422,1,1,7,17,17,717,1717,2717,7717,34,35,'VKAAAA','QBFAAA','OOOOxx'
+8718,3423,0,2,8,18,18,718,718,3718,8718,36,37,'IXAAAA','RBFAAA','VVVVxx'
+8608,3424,0,0,8,8,8,608,608,3608,8608,16,17,'CTAAAA','SBFAAA','AAAAxx'
+2242,3425,0,2,2,2,42,242,242,2242,2242,84,85,'GIAAAA','TBFAAA','HHHHxx'
+4811,3426,1,3,1,11,11,811,811,4811,4811,22,23,'BDAAAA','UBFAAA','OOOOxx'
+6838,3427,0,2,8,18,38,838,838,1838,6838,76,77,'ADAAAA','VBFAAA','VVVVxx'
+787,3428,1,3,7,7,87,787,787,787,787,174,175,'HEAAAA','WBFAAA','AAAAxx'
+7940,3429,0,0,0,0,40,940,1940,2940,7940,80,81,'KTAAAA','XBFAAA','HHHHxx'
+336,3430,0,0,6,16,36,336,336,336,336,72,73,'YMAAAA','YBFAAA','OOOOxx'
+9859,3431,1,3,9,19,59,859,1859,4859,9859,118,119,'FPAAAA','ZBFAAA','VVVVxx'
+3864,3432,0,0,4,4,64,864,1864,3864,3864,128,129,'QSAAAA','ACFAAA','AAAAxx'
+7162,3433,0,2,2,2,62,162,1162,2162,7162,124,125,'MPAAAA','BCFAAA','HHHHxx'
+2071,3434,1,3,1,11,71,71,71,2071,2071,142,143,'RBAAAA','CCFAAA','OOOOxx'
+7469,3435,1,1,9,9,69,469,1469,2469,7469,138,139,'HBAAAA','DCFAAA','VVVVxx'
+2917,3436,1,1,7,17,17,917,917,2917,2917,34,35,'FIAAAA','ECFAAA','AAAAxx'
+7486,3437,0,2,6,6,86,486,1486,2486,7486,172,173,'YBAAAA','FCFAAA','HHHHxx'
+3355,3438,1,3,5,15,55,355,1355,3355,3355,110,111,'BZAAAA','GCFAAA','OOOOxx'
+6998,3439,0,2,8,18,98,998,998,1998,6998,196,197,'EJAAAA','HCFAAA','VVVVxx'
+5498,3440,0,2,8,18,98,498,1498,498,5498,196,197,'MDAAAA','ICFAAA','AAAAxx'
+5113,3441,1,1,3,13,13,113,1113,113,5113,26,27,'ROAAAA','JCFAAA','HHHHxx'
+2846,3442,0,2,6,6,46,846,846,2846,2846,92,93,'MFAAAA','KCFAAA','OOOOxx'
+6834,3443,0,2,4,14,34,834,834,1834,6834,68,69,'WCAAAA','LCFAAA','VVVVxx'
+8925,3444,1,1,5,5,25,925,925,3925,8925,50,51,'HFAAAA','MCFAAA','AAAAxx'
+2757,3445,1,1,7,17,57,757,757,2757,2757,114,115,'BCAAAA','NCFAAA','HHHHxx'
+2775,3446,1,3,5,15,75,775,775,2775,2775,150,151,'TCAAAA','OCFAAA','OOOOxx'
+6182,3447,0,2,2,2,82,182,182,1182,6182,164,165,'UDAAAA','PCFAAA','VVVVxx'
+4488,3448,0,0,8,8,88,488,488,4488,4488,176,177,'QQAAAA','QCFAAA','AAAAxx'
+8523,3449,1,3,3,3,23,523,523,3523,8523,46,47,'VPAAAA','RCFAAA','HHHHxx'
+52,3450,0,0,2,12,52,52,52,52,52,104,105,'ACAAAA','SCFAAA','OOOOxx'
+7251,3451,1,3,1,11,51,251,1251,2251,7251,102,103,'XSAAAA','TCFAAA','VVVVxx'
+6130,3452,0,2,0,10,30,130,130,1130,6130,60,61,'UBAAAA','UCFAAA','AAAAxx'
+205,3453,1,1,5,5,5,205,205,205,205,10,11,'XHAAAA','VCFAAA','HHHHxx'
+1186,3454,0,2,6,6,86,186,1186,1186,1186,172,173,'QTAAAA','WCFAAA','OOOOxx'
+1738,3455,0,2,8,18,38,738,1738,1738,1738,76,77,'WOAAAA','XCFAAA','VVVVxx'
+9485,3456,1,1,5,5,85,485,1485,4485,9485,170,171,'VAAAAA','YCFAAA','AAAAxx'
+4235,3457,1,3,5,15,35,235,235,4235,4235,70,71,'XGAAAA','ZCFAAA','HHHHxx'
+7891,3458,1,3,1,11,91,891,1891,2891,7891,182,183,'NRAAAA','ADFAAA','OOOOxx'
+4960,3459,0,0,0,0,60,960,960,4960,4960,120,121,'UIAAAA','BDFAAA','VVVVxx'
+8911,3460,1,3,1,11,11,911,911,3911,8911,22,23,'TEAAAA','CDFAAA','AAAAxx'
+1219,3461,1,3,9,19,19,219,1219,1219,1219,38,39,'XUAAAA','DDFAAA','HHHHxx'
+9652,3462,0,0,2,12,52,652,1652,4652,9652,104,105,'GHAAAA','EDFAAA','OOOOxx'
+9715,3463,1,3,5,15,15,715,1715,4715,9715,30,31,'RJAAAA','FDFAAA','VVVVxx'
+6629,3464,1,1,9,9,29,629,629,1629,6629,58,59,'ZUAAAA','GDFAAA','AAAAxx'
+700,3465,0,0,0,0,0,700,700,700,700,0,1,'YAAAAA','HDFAAA','HHHHxx'
+9819,3466,1,3,9,19,19,819,1819,4819,9819,38,39,'RNAAAA','IDFAAA','OOOOxx'
+5188,3467,0,0,8,8,88,188,1188,188,5188,176,177,'ORAAAA','JDFAAA','VVVVxx'
+5367,3468,1,3,7,7,67,367,1367,367,5367,134,135,'LYAAAA','KDFAAA','AAAAxx'
+6447,3469,1,3,7,7,47,447,447,1447,6447,94,95,'ZNAAAA','LDFAAA','HHHHxx'
+720,3470,0,0,0,0,20,720,720,720,720,40,41,'SBAAAA','MDFAAA','OOOOxx'
+9157,3471,1,1,7,17,57,157,1157,4157,9157,114,115,'FOAAAA','NDFAAA','VVVVxx'
+1082,3472,0,2,2,2,82,82,1082,1082,1082,164,165,'QPAAAA','ODFAAA','AAAAxx'
+3179,3473,1,3,9,19,79,179,1179,3179,3179,158,159,'HSAAAA','PDFAAA','HHHHxx'
+4818,3474,0,2,8,18,18,818,818,4818,4818,36,37,'IDAAAA','QDFAAA','OOOOxx'
+7607,3475,1,3,7,7,7,607,1607,2607,7607,14,15,'PGAAAA','RDFAAA','VVVVxx'
+2352,3476,0,0,2,12,52,352,352,2352,2352,104,105,'MMAAAA','SDFAAA','AAAAxx'
+1170,3477,0,2,0,10,70,170,1170,1170,1170,140,141,'ATAAAA','TDFAAA','HHHHxx'
+4269,3478,1,1,9,9,69,269,269,4269,4269,138,139,'FIAAAA','UDFAAA','OOOOxx'
+8767,3479,1,3,7,7,67,767,767,3767,8767,134,135,'FZAAAA','VDFAAA','VVVVxx'
+3984,3480,0,0,4,4,84,984,1984,3984,3984,168,169,'GXAAAA','WDFAAA','AAAAxx'
+3190,3481,0,2,0,10,90,190,1190,3190,3190,180,181,'SSAAAA','XDFAAA','HHHHxx'
+7456,3482,0,0,6,16,56,456,1456,2456,7456,112,113,'UAAAAA','YDFAAA','OOOOxx'
+4348,3483,0,0,8,8,48,348,348,4348,4348,96,97,'GLAAAA','ZDFAAA','VVVVxx'
+3150,3484,0,2,0,10,50,150,1150,3150,3150,100,101,'ERAAAA','AEFAAA','AAAAxx'
+8780,3485,0,0,0,0,80,780,780,3780,8780,160,161,'SZAAAA','BEFAAA','HHHHxx'
+2553,3486,1,1,3,13,53,553,553,2553,2553,106,107,'FUAAAA','CEFAAA','OOOOxx'
+7526,3487,0,2,6,6,26,526,1526,2526,7526,52,53,'MDAAAA','DEFAAA','VVVVxx'
+2031,3488,1,3,1,11,31,31,31,2031,2031,62,63,'DAAAAA','EEFAAA','AAAAxx'
+8793,3489,1,1,3,13,93,793,793,3793,8793,186,187,'FAAAAA','FEFAAA','HHHHxx'
+1122,3490,0,2,2,2,22,122,1122,1122,1122,44,45,'ERAAAA','GEFAAA','OOOOxx'
+1855,3491,1,3,5,15,55,855,1855,1855,1855,110,111,'JTAAAA','HEFAAA','VVVVxx'
+6613,3492,1,1,3,13,13,613,613,1613,6613,26,27,'JUAAAA','IEFAAA','AAAAxx'
+3231,3493,1,3,1,11,31,231,1231,3231,3231,62,63,'HUAAAA','JEFAAA','HHHHxx'
+9101,3494,1,1,1,1,1,101,1101,4101,9101,2,3,'BMAAAA','KEFAAA','OOOOxx'
+4937,3495,1,1,7,17,37,937,937,4937,4937,74,75,'XHAAAA','LEFAAA','VVVVxx'
+666,3496,0,2,6,6,66,666,666,666,666,132,133,'QZAAAA','MEFAAA','AAAAxx'
+8943,3497,1,3,3,3,43,943,943,3943,8943,86,87,'ZFAAAA','NEFAAA','HHHHxx'
+6164,3498,0,0,4,4,64,164,164,1164,6164,128,129,'CDAAAA','OEFAAA','OOOOxx'
+1081,3499,1,1,1,1,81,81,1081,1081,1081,162,163,'PPAAAA','PEFAAA','VVVVxx'
+210,3500,0,2,0,10,10,210,210,210,210,20,21,'CIAAAA','QEFAAA','AAAAxx'
+6024,3501,0,0,4,4,24,24,24,1024,6024,48,49,'SXAAAA','REFAAA','HHHHxx'
+5715,3502,1,3,5,15,15,715,1715,715,5715,30,31,'VLAAAA','SEFAAA','OOOOxx'
+8938,3503,0,2,8,18,38,938,938,3938,8938,76,77,'UFAAAA','TEFAAA','VVVVxx'
+1326,3504,0,2,6,6,26,326,1326,1326,1326,52,53,'AZAAAA','UEFAAA','AAAAxx'
+7111,3505,1,3,1,11,11,111,1111,2111,7111,22,23,'NNAAAA','VEFAAA','HHHHxx'
+757,3506,1,1,7,17,57,757,757,757,757,114,115,'DDAAAA','WEFAAA','OOOOxx'
+8933,3507,1,1,3,13,33,933,933,3933,8933,66,67,'PFAAAA','XEFAAA','VVVVxx'
+6495,3508,1,3,5,15,95,495,495,1495,6495,190,191,'VPAAAA','YEFAAA','AAAAxx'
+3134,3509,0,2,4,14,34,134,1134,3134,3134,68,69,'OQAAAA','ZEFAAA','HHHHxx'
+1304,3510,0,0,4,4,4,304,1304,1304,1304,8,9,'EYAAAA','AFFAAA','OOOOxx'
+1835,3511,1,3,5,15,35,835,1835,1835,1835,70,71,'PSAAAA','BFFAAA','VVVVxx'
+7275,3512,1,3,5,15,75,275,1275,2275,7275,150,151,'VTAAAA','CFFAAA','AAAAxx'
+7337,3513,1,1,7,17,37,337,1337,2337,7337,74,75,'FWAAAA','DFFAAA','HHHHxx'
+1282,3514,0,2,2,2,82,282,1282,1282,1282,164,165,'IXAAAA','EFFAAA','OOOOxx'
+6566,3515,0,2,6,6,66,566,566,1566,6566,132,133,'OSAAAA','FFFAAA','VVVVxx'
+3786,3516,0,2,6,6,86,786,1786,3786,3786,172,173,'QPAAAA','GFFAAA','AAAAxx'
+5741,3517,1,1,1,1,41,741,1741,741,5741,82,83,'VMAAAA','HFFAAA','HHHHxx'
+6076,3518,0,0,6,16,76,76,76,1076,6076,152,153,'SZAAAA','IFFAAA','OOOOxx'
+9998,3519,0,2,8,18,98,998,1998,4998,9998,196,197,'OUAAAA','JFFAAA','VVVVxx'
+6268,3520,0,0,8,8,68,268,268,1268,6268,136,137,'CHAAAA','KFFAAA','AAAAxx'
+9647,3521,1,3,7,7,47,647,1647,4647,9647,94,95,'BHAAAA','LFFAAA','HHHHxx'
+4877,3522,1,1,7,17,77,877,877,4877,4877,154,155,'PFAAAA','MFFAAA','OOOOxx'
+2652,3523,0,0,2,12,52,652,652,2652,2652,104,105,'AYAAAA','NFFAAA','VVVVxx'
+1247,3524,1,3,7,7,47,247,1247,1247,1247,94,95,'ZVAAAA','OFFAAA','AAAAxx'
+2721,3525,1,1,1,1,21,721,721,2721,2721,42,43,'RAAAAA','PFFAAA','HHHHxx'
+5968,3526,0,0,8,8,68,968,1968,968,5968,136,137,'OVAAAA','QFFAAA','OOOOxx'
+9570,3527,0,2,0,10,70,570,1570,4570,9570,140,141,'CEAAAA','RFFAAA','VVVVxx'
+6425,3528,1,1,5,5,25,425,425,1425,6425,50,51,'DNAAAA','SFFAAA','AAAAxx'
+5451,3529,1,3,1,11,51,451,1451,451,5451,102,103,'RBAAAA','TFFAAA','HHHHxx'
+5668,3530,0,0,8,8,68,668,1668,668,5668,136,137,'AKAAAA','UFFAAA','OOOOxx'
+9493,3531,1,1,3,13,93,493,1493,4493,9493,186,187,'DBAAAA','VFFAAA','VVVVxx'
+7973,3532,1,1,3,13,73,973,1973,2973,7973,146,147,'RUAAAA','WFFAAA','AAAAxx'
+8250,3533,0,2,0,10,50,250,250,3250,8250,100,101,'IFAAAA','XFFAAA','HHHHxx'
+82,3534,0,2,2,2,82,82,82,82,82,164,165,'EDAAAA','YFFAAA','OOOOxx'
+6258,3535,0,2,8,18,58,258,258,1258,6258,116,117,'SGAAAA','ZFFAAA','VVVVxx'
+9978,3536,0,2,8,18,78,978,1978,4978,9978,156,157,'UTAAAA','AGFAAA','AAAAxx'
+6930,3537,0,2,0,10,30,930,930,1930,6930,60,61,'OGAAAA','BGFAAA','HHHHxx'
+3746,3538,0,2,6,6,46,746,1746,3746,3746,92,93,'COAAAA','CGFAAA','OOOOxx'
+7065,3539,1,1,5,5,65,65,1065,2065,7065,130,131,'TLAAAA','DGFAAA','VVVVxx'
+4281,3540,1,1,1,1,81,281,281,4281,4281,162,163,'RIAAAA','EGFAAA','AAAAxx'
+4367,3541,1,3,7,7,67,367,367,4367,4367,134,135,'ZLAAAA','FGFAAA','HHHHxx'
+9526,3542,0,2,6,6,26,526,1526,4526,9526,52,53,'KCAAAA','GGFAAA','OOOOxx'
+5880,3543,0,0,0,0,80,880,1880,880,5880,160,161,'ESAAAA','HGFAAA','VVVVxx'
+8480,3544,0,0,0,0,80,480,480,3480,8480,160,161,'EOAAAA','IGFAAA','AAAAxx'
+2476,3545,0,0,6,16,76,476,476,2476,2476,152,153,'GRAAAA','JGFAAA','HHHHxx'
+9074,3546,0,2,4,14,74,74,1074,4074,9074,148,149,'ALAAAA','KGFAAA','OOOOxx'
+4830,3547,0,2,0,10,30,830,830,4830,4830,60,61,'UDAAAA','LGFAAA','VVVVxx'
+3207,3548,1,3,7,7,7,207,1207,3207,3207,14,15,'JTAAAA','MGFAAA','AAAAxx'
+7894,3549,0,2,4,14,94,894,1894,2894,7894,188,189,'QRAAAA','NGFAAA','HHHHxx'
+3860,3550,0,0,0,0,60,860,1860,3860,3860,120,121,'MSAAAA','OGFAAA','OOOOxx'
+5293,3551,1,1,3,13,93,293,1293,293,5293,186,187,'PVAAAA','PGFAAA','VVVVxx'
+6895,3552,1,3,5,15,95,895,895,1895,6895,190,191,'FFAAAA','QGFAAA','AAAAxx'
+9908,3553,0,0,8,8,8,908,1908,4908,9908,16,17,'CRAAAA','RGFAAA','HHHHxx'
+9247,3554,1,3,7,7,47,247,1247,4247,9247,94,95,'RRAAAA','SGFAAA','OOOOxx'
+8110,3555,0,2,0,10,10,110,110,3110,8110,20,21,'YZAAAA','TGFAAA','VVVVxx'
+4716,3556,0,0,6,16,16,716,716,4716,4716,32,33,'KZAAAA','UGFAAA','AAAAxx'
+4979,3557,1,3,9,19,79,979,979,4979,4979,158,159,'NJAAAA','VGFAAA','HHHHxx'
+5280,3558,0,0,0,0,80,280,1280,280,5280,160,161,'CVAAAA','WGFAAA','OOOOxx'
+8326,3559,0,2,6,6,26,326,326,3326,8326,52,53,'GIAAAA','XGFAAA','VVVVxx'
+5572,3560,0,0,2,12,72,572,1572,572,5572,144,145,'IGAAAA','YGFAAA','AAAAxx'
+4665,3561,1,1,5,5,65,665,665,4665,4665,130,131,'LXAAAA','ZGFAAA','HHHHxx'
+3665,3562,1,1,5,5,65,665,1665,3665,3665,130,131,'ZKAAAA','AHFAAA','OOOOxx'
+6744,3563,0,0,4,4,44,744,744,1744,6744,88,89,'KZAAAA','BHFAAA','VVVVxx'
+1897,3564,1,1,7,17,97,897,1897,1897,1897,194,195,'ZUAAAA','CHFAAA','AAAAxx'
+1220,3565,0,0,0,0,20,220,1220,1220,1220,40,41,'YUAAAA','DHFAAA','HHHHxx'
+2614,3566,0,2,4,14,14,614,614,2614,2614,28,29,'OWAAAA','EHFAAA','OOOOxx'
+8509,3567,1,1,9,9,9,509,509,3509,8509,18,19,'HPAAAA','FHFAAA','VVVVxx'
+8521,3568,1,1,1,1,21,521,521,3521,8521,42,43,'TPAAAA','GHFAAA','AAAAxx'
+4121,3569,1,1,1,1,21,121,121,4121,4121,42,43,'NCAAAA','HHFAAA','HHHHxx'
+9663,3570,1,3,3,3,63,663,1663,4663,9663,126,127,'RHAAAA','IHFAAA','OOOOxx'
+2346,3571,0,2,6,6,46,346,346,2346,2346,92,93,'GMAAAA','JHFAAA','VVVVxx'
+3370,3572,0,2,0,10,70,370,1370,3370,3370,140,141,'QZAAAA','KHFAAA','AAAAxx'
+1498,3573,0,2,8,18,98,498,1498,1498,1498,196,197,'QFAAAA','LHFAAA','HHHHxx'
+7422,3574,0,2,2,2,22,422,1422,2422,7422,44,45,'MZAAAA','MHFAAA','OOOOxx'
+3472,3575,0,0,2,12,72,472,1472,3472,3472,144,145,'ODAAAA','NHFAAA','VVVVxx'
+4126,3576,0,2,6,6,26,126,126,4126,4126,52,53,'SCAAAA','OHFAAA','AAAAxx'
+4494,3577,0,2,4,14,94,494,494,4494,4494,188,189,'WQAAAA','PHFAAA','HHHHxx'
+6323,3578,1,3,3,3,23,323,323,1323,6323,46,47,'FJAAAA','QHFAAA','OOOOxx'
+2823,3579,1,3,3,3,23,823,823,2823,2823,46,47,'PEAAAA','RHFAAA','VVVVxx'
+8596,3580,0,0,6,16,96,596,596,3596,8596,192,193,'QSAAAA','SHFAAA','AAAAxx'
+6642,3581,0,2,2,2,42,642,642,1642,6642,84,85,'MVAAAA','THFAAA','HHHHxx'
+9276,3582,0,0,6,16,76,276,1276,4276,9276,152,153,'USAAAA','UHFAAA','OOOOxx'
+4148,3583,0,0,8,8,48,148,148,4148,4148,96,97,'ODAAAA','VHFAAA','VVVVxx'
+9770,3584,0,2,0,10,70,770,1770,4770,9770,140,141,'ULAAAA','WHFAAA','AAAAxx'
+9812,3585,0,0,2,12,12,812,1812,4812,9812,24,25,'KNAAAA','XHFAAA','HHHHxx'
+4419,3586,1,3,9,19,19,419,419,4419,4419,38,39,'ZNAAAA','YHFAAA','OOOOxx'
+3802,3587,0,2,2,2,2,802,1802,3802,3802,4,5,'GQAAAA','ZHFAAA','VVVVxx'
+3210,3588,0,2,0,10,10,210,1210,3210,3210,20,21,'MTAAAA','AIFAAA','AAAAxx'
+6794,3589,0,2,4,14,94,794,794,1794,6794,188,189,'IBAAAA','BIFAAA','HHHHxx'
+242,3590,0,2,2,2,42,242,242,242,242,84,85,'IJAAAA','CIFAAA','OOOOxx'
+962,3591,0,2,2,2,62,962,962,962,962,124,125,'ALAAAA','DIFAAA','VVVVxx'
+7151,3592,1,3,1,11,51,151,1151,2151,7151,102,103,'BPAAAA','EIFAAA','AAAAxx'
+9440,3593,0,0,0,0,40,440,1440,4440,9440,80,81,'CZAAAA','FIFAAA','HHHHxx'
+721,3594,1,1,1,1,21,721,721,721,721,42,43,'TBAAAA','GIFAAA','OOOOxx'
+2119,3595,1,3,9,19,19,119,119,2119,2119,38,39,'NDAAAA','HIFAAA','VVVVxx'
+9883,3596,1,3,3,3,83,883,1883,4883,9883,166,167,'DQAAAA','IIFAAA','AAAAxx'
+5071,3597,1,3,1,11,71,71,1071,71,5071,142,143,'BNAAAA','JIFAAA','HHHHxx'
+8239,3598,1,3,9,19,39,239,239,3239,8239,78,79,'XEAAAA','KIFAAA','OOOOxx'
+7451,3599,1,3,1,11,51,451,1451,2451,7451,102,103,'PAAAAA','LIFAAA','VVVVxx'
+9517,3600,1,1,7,17,17,517,1517,4517,9517,34,35,'BCAAAA','MIFAAA','AAAAxx'
+9180,3601,0,0,0,0,80,180,1180,4180,9180,160,161,'CPAAAA','NIFAAA','HHHHxx'
+9327,3602,1,3,7,7,27,327,1327,4327,9327,54,55,'TUAAAA','OIFAAA','OOOOxx'
+5462,3603,0,2,2,2,62,462,1462,462,5462,124,125,'CCAAAA','PIFAAA','VVVVxx'
+8306,3604,0,2,6,6,6,306,306,3306,8306,12,13,'MHAAAA','QIFAAA','AAAAxx'
+6234,3605,0,2,4,14,34,234,234,1234,6234,68,69,'UFAAAA','RIFAAA','HHHHxx'
+8771,3606,1,3,1,11,71,771,771,3771,8771,142,143,'JZAAAA','SIFAAA','OOOOxx'
+5853,3607,1,1,3,13,53,853,1853,853,5853,106,107,'DRAAAA','TIFAAA','VVVVxx'
+8373,3608,1,1,3,13,73,373,373,3373,8373,146,147,'BKAAAA','UIFAAA','AAAAxx'
+5017,3609,1,1,7,17,17,17,1017,17,5017,34,35,'ZKAAAA','VIFAAA','HHHHxx'
+8025,3610,1,1,5,5,25,25,25,3025,8025,50,51,'RWAAAA','WIFAAA','OOOOxx'
+2526,3611,0,2,6,6,26,526,526,2526,2526,52,53,'ETAAAA','XIFAAA','VVVVxx'
+7419,3612,1,3,9,19,19,419,1419,2419,7419,38,39,'JZAAAA','YIFAAA','AAAAxx'
+4572,3613,0,0,2,12,72,572,572,4572,4572,144,145,'WTAAAA','ZIFAAA','HHHHxx'
+7744,3614,0,0,4,4,44,744,1744,2744,7744,88,89,'WLAAAA','AJFAAA','OOOOxx'
+8825,3615,1,1,5,5,25,825,825,3825,8825,50,51,'LBAAAA','BJFAAA','VVVVxx'
+6067,3616,1,3,7,7,67,67,67,1067,6067,134,135,'JZAAAA','CJFAAA','AAAAxx'
+3291,3617,1,3,1,11,91,291,1291,3291,3291,182,183,'PWAAAA','DJFAAA','HHHHxx'
+7115,3618,1,3,5,15,15,115,1115,2115,7115,30,31,'RNAAAA','EJFAAA','OOOOxx'
+2626,3619,0,2,6,6,26,626,626,2626,2626,52,53,'AXAAAA','FJFAAA','VVVVxx'
+4109,3620,1,1,9,9,9,109,109,4109,4109,18,19,'BCAAAA','GJFAAA','AAAAxx'
+4056,3621,0,0,6,16,56,56,56,4056,4056,112,113,'AAAAAA','HJFAAA','HHHHxx'
+6811,3622,1,3,1,11,11,811,811,1811,6811,22,23,'ZBAAAA','IJFAAA','OOOOxx'
+680,3623,0,0,0,0,80,680,680,680,680,160,161,'EAAAAA','JJFAAA','VVVVxx'
+474,3624,0,2,4,14,74,474,474,474,474,148,149,'GSAAAA','KJFAAA','AAAAxx'
+9294,3625,0,2,4,14,94,294,1294,4294,9294,188,189,'MTAAAA','LJFAAA','HHHHxx'
+7555,3626,1,3,5,15,55,555,1555,2555,7555,110,111,'PEAAAA','MJFAAA','OOOOxx'
+8076,3627,0,0,6,16,76,76,76,3076,8076,152,153,'QYAAAA','NJFAAA','VVVVxx'
+3840,3628,0,0,0,0,40,840,1840,3840,3840,80,81,'SRAAAA','OJFAAA','AAAAxx'
+5955,3629,1,3,5,15,55,955,1955,955,5955,110,111,'BVAAAA','PJFAAA','HHHHxx'
+994,3630,0,2,4,14,94,994,994,994,994,188,189,'GMAAAA','QJFAAA','OOOOxx'
+2089,3631,1,1,9,9,89,89,89,2089,2089,178,179,'JCAAAA','RJFAAA','VVVVxx'
+869,3632,1,1,9,9,69,869,869,869,869,138,139,'LHAAAA','SJFAAA','AAAAxx'
+1223,3633,1,3,3,3,23,223,1223,1223,1223,46,47,'BVAAAA','TJFAAA','HHHHxx'
+1514,3634,0,2,4,14,14,514,1514,1514,1514,28,29,'GGAAAA','UJFAAA','OOOOxx'
+4891,3635,1,3,1,11,91,891,891,4891,4891,182,183,'DGAAAA','VJFAAA','VVVVxx'
+4190,3636,0,2,0,10,90,190,190,4190,4190,180,181,'EFAAAA','WJFAAA','AAAAxx'
+4377,3637,1,1,7,17,77,377,377,4377,4377,154,155,'JMAAAA','XJFAAA','HHHHxx'
+9195,3638,1,3,5,15,95,195,1195,4195,9195,190,191,'RPAAAA','YJFAAA','OOOOxx'
+3827,3639,1,3,7,7,27,827,1827,3827,3827,54,55,'FRAAAA','ZJFAAA','VVVVxx'
+7386,3640,0,2,6,6,86,386,1386,2386,7386,172,173,'CYAAAA','AKFAAA','AAAAxx'
+6665,3641,1,1,5,5,65,665,665,1665,6665,130,131,'JWAAAA','BKFAAA','HHHHxx'
+7514,3642,0,2,4,14,14,514,1514,2514,7514,28,29,'ADAAAA','CKFAAA','OOOOxx'
+6431,3643,1,3,1,11,31,431,431,1431,6431,62,63,'JNAAAA','DKFAAA','VVVVxx'
+3251,3644,1,3,1,11,51,251,1251,3251,3251,102,103,'BVAAAA','EKFAAA','AAAAxx'
+8439,3645,1,3,9,19,39,439,439,3439,8439,78,79,'PMAAAA','FKFAAA','HHHHxx'
+831,3646,1,3,1,11,31,831,831,831,831,62,63,'ZFAAAA','GKFAAA','OOOOxx'
+8485,3647,1,1,5,5,85,485,485,3485,8485,170,171,'JOAAAA','HKFAAA','VVVVxx'
+7314,3648,0,2,4,14,14,314,1314,2314,7314,28,29,'IVAAAA','IKFAAA','AAAAxx'
+3044,3649,0,0,4,4,44,44,1044,3044,3044,88,89,'CNAAAA','JKFAAA','HHHHxx'
+4283,3650,1,3,3,3,83,283,283,4283,4283,166,167,'TIAAAA','KKFAAA','OOOOxx'
+298,3651,0,2,8,18,98,298,298,298,298,196,197,'MLAAAA','LKFAAA','VVVVxx'
+7114,3652,0,2,4,14,14,114,1114,2114,7114,28,29,'QNAAAA','MKFAAA','AAAAxx'
+9664,3653,0,0,4,4,64,664,1664,4664,9664,128,129,'SHAAAA','NKFAAA','HHHHxx'
+5315,3654,1,3,5,15,15,315,1315,315,5315,30,31,'LWAAAA','OKFAAA','OOOOxx'
+2164,3655,0,0,4,4,64,164,164,2164,2164,128,129,'GFAAAA','PKFAAA','VVVVxx'
+3390,3656,0,2,0,10,90,390,1390,3390,3390,180,181,'KAAAAA','QKFAAA','AAAAxx'
+836,3657,0,0,6,16,36,836,836,836,836,72,73,'EGAAAA','RKFAAA','HHHHxx'
+3316,3658,0,0,6,16,16,316,1316,3316,3316,32,33,'OXAAAA','SKFAAA','OOOOxx'
+1284,3659,0,0,4,4,84,284,1284,1284,1284,168,169,'KXAAAA','TKFAAA','VVVVxx'
+2497,3660,1,1,7,17,97,497,497,2497,2497,194,195,'BSAAAA','UKFAAA','AAAAxx'
+1374,3661,0,2,4,14,74,374,1374,1374,1374,148,149,'WAAAAA','VKFAAA','HHHHxx'
+9525,3662,1,1,5,5,25,525,1525,4525,9525,50,51,'JCAAAA','WKFAAA','OOOOxx'
+2911,3663,1,3,1,11,11,911,911,2911,2911,22,23,'ZHAAAA','XKFAAA','VVVVxx'
+9686,3664,0,2,6,6,86,686,1686,4686,9686,172,173,'OIAAAA','YKFAAA','AAAAxx'
+584,3665,0,0,4,4,84,584,584,584,584,168,169,'MWAAAA','ZKFAAA','HHHHxx'
+5653,3666,1,1,3,13,53,653,1653,653,5653,106,107,'LJAAAA','ALFAAA','OOOOxx'
+4986,3667,0,2,6,6,86,986,986,4986,4986,172,173,'UJAAAA','BLFAAA','VVVVxx'
+6049,3668,1,1,9,9,49,49,49,1049,6049,98,99,'RYAAAA','CLFAAA','AAAAxx'
+9891,3669,1,3,1,11,91,891,1891,4891,9891,182,183,'LQAAAA','DLFAAA','HHHHxx'
+8809,3670,1,1,9,9,9,809,809,3809,8809,18,19,'VAAAAA','ELFAAA','OOOOxx'
+8598,3671,0,2,8,18,98,598,598,3598,8598,196,197,'SSAAAA','FLFAAA','VVVVxx'
+2573,3672,1,1,3,13,73,573,573,2573,2573,146,147,'ZUAAAA','GLFAAA','AAAAxx'
+6864,3673,0,0,4,4,64,864,864,1864,6864,128,129,'AEAAAA','HLFAAA','HHHHxx'
+7932,3674,0,0,2,12,32,932,1932,2932,7932,64,65,'CTAAAA','ILFAAA','OOOOxx'
+6605,3675,1,1,5,5,5,605,605,1605,6605,10,11,'BUAAAA','JLFAAA','VVVVxx'
+9500,3676,0,0,0,0,0,500,1500,4500,9500,0,1,'KBAAAA','KLFAAA','AAAAxx'
+8742,3677,0,2,2,2,42,742,742,3742,8742,84,85,'GYAAAA','LLFAAA','HHHHxx'
+9815,3678,1,3,5,15,15,815,1815,4815,9815,30,31,'NNAAAA','MLFAAA','OOOOxx'
+3319,3679,1,3,9,19,19,319,1319,3319,3319,38,39,'RXAAAA','NLFAAA','VVVVxx'
+184,3680,0,0,4,4,84,184,184,184,184,168,169,'CHAAAA','OLFAAA','AAAAxx'
+8886,3681,0,2,6,6,86,886,886,3886,8886,172,173,'UDAAAA','PLFAAA','HHHHxx'
+7050,3682,0,2,0,10,50,50,1050,2050,7050,100,101,'ELAAAA','QLFAAA','OOOOxx'
+9781,3683,1,1,1,1,81,781,1781,4781,9781,162,163,'FMAAAA','RLFAAA','VVVVxx'
+2443,3684,1,3,3,3,43,443,443,2443,2443,86,87,'ZPAAAA','SLFAAA','AAAAxx'
+1160,3685,0,0,0,0,60,160,1160,1160,1160,120,121,'QSAAAA','TLFAAA','HHHHxx'
+4600,3686,0,0,0,0,0,600,600,4600,4600,0,1,'YUAAAA','ULFAAA','OOOOxx'
+813,3687,1,1,3,13,13,813,813,813,813,26,27,'HFAAAA','VLFAAA','VVVVxx'
+5078,3688,0,2,8,18,78,78,1078,78,5078,156,157,'INAAAA','WLFAAA','AAAAxx'
+9008,3689,0,0,8,8,8,8,1008,4008,9008,16,17,'MIAAAA','XLFAAA','HHHHxx'
+9016,3690,0,0,6,16,16,16,1016,4016,9016,32,33,'UIAAAA','YLFAAA','OOOOxx'
+2747,3691,1,3,7,7,47,747,747,2747,2747,94,95,'RBAAAA','ZLFAAA','VVVVxx'
+3106,3692,0,2,6,6,6,106,1106,3106,3106,12,13,'MPAAAA','AMFAAA','AAAAxx'
+8235,3693,1,3,5,15,35,235,235,3235,8235,70,71,'TEAAAA','BMFAAA','HHHHxx'
+5582,3694,0,2,2,2,82,582,1582,582,5582,164,165,'SGAAAA','CMFAAA','OOOOxx'
+4334,3695,0,2,4,14,34,334,334,4334,4334,68,69,'SKAAAA','DMFAAA','VVVVxx'
+1612,3696,0,0,2,12,12,612,1612,1612,1612,24,25,'AKAAAA','EMFAAA','AAAAxx'
+5650,3697,0,2,0,10,50,650,1650,650,5650,100,101,'IJAAAA','FMFAAA','HHHHxx'
+6086,3698,0,2,6,6,86,86,86,1086,6086,172,173,'CAAAAA','GMFAAA','OOOOxx'
+9667,3699,1,3,7,7,67,667,1667,4667,9667,134,135,'VHAAAA','HMFAAA','VVVVxx'
+4215,3700,1,3,5,15,15,215,215,4215,4215,30,31,'DGAAAA','IMFAAA','AAAAxx'
+8553,3701,1,1,3,13,53,553,553,3553,8553,106,107,'ZQAAAA','JMFAAA','HHHHxx'
+9066,3702,0,2,6,6,66,66,1066,4066,9066,132,133,'SKAAAA','KMFAAA','OOOOxx'
+1092,3703,0,0,2,12,92,92,1092,1092,1092,184,185,'AQAAAA','LMFAAA','VVVVxx'
+2848,3704,0,0,8,8,48,848,848,2848,2848,96,97,'OFAAAA','MMFAAA','AAAAxx'
+2765,3705,1,1,5,5,65,765,765,2765,2765,130,131,'JCAAAA','NMFAAA','HHHHxx'
+6513,3706,1,1,3,13,13,513,513,1513,6513,26,27,'NQAAAA','OMFAAA','OOOOxx'
+6541,3707,1,1,1,1,41,541,541,1541,6541,82,83,'PRAAAA','PMFAAA','VVVVxx'
+9617,3708,1,1,7,17,17,617,1617,4617,9617,34,35,'XFAAAA','QMFAAA','AAAAxx'
+5870,3709,0,2,0,10,70,870,1870,870,5870,140,141,'URAAAA','RMFAAA','HHHHxx'
+8811,3710,1,3,1,11,11,811,811,3811,8811,22,23,'XAAAAA','SMFAAA','OOOOxx'
+4529,3711,1,1,9,9,29,529,529,4529,4529,58,59,'FSAAAA','TMFAAA','VVVVxx'
+161,3712,1,1,1,1,61,161,161,161,161,122,123,'FGAAAA','UMFAAA','AAAAxx'
+641,3713,1,1,1,1,41,641,641,641,641,82,83,'RYAAAA','VMFAAA','HHHHxx'
+4767,3714,1,3,7,7,67,767,767,4767,4767,134,135,'JBAAAA','WMFAAA','OOOOxx'
+6293,3715,1,1,3,13,93,293,293,1293,6293,186,187,'BIAAAA','XMFAAA','VVVVxx'
+3816,3716,0,0,6,16,16,816,1816,3816,3816,32,33,'UQAAAA','YMFAAA','AAAAxx'
+4748,3717,0,0,8,8,48,748,748,4748,4748,96,97,'QAAAAA','ZMFAAA','HHHHxx'
+9924,3718,0,0,4,4,24,924,1924,4924,9924,48,49,'SRAAAA','ANFAAA','OOOOxx'
+6716,3719,0,0,6,16,16,716,716,1716,6716,32,33,'IYAAAA','BNFAAA','VVVVxx'
+8828,3720,0,0,8,8,28,828,828,3828,8828,56,57,'OBAAAA','CNFAAA','AAAAxx'
+4967,3721,1,3,7,7,67,967,967,4967,4967,134,135,'BJAAAA','DNFAAA','HHHHxx'
+9680,3722,0,0,0,0,80,680,1680,4680,9680,160,161,'IIAAAA','ENFAAA','OOOOxx'
+2784,3723,0,0,4,4,84,784,784,2784,2784,168,169,'CDAAAA','FNFAAA','VVVVxx'
+2882,3724,0,2,2,2,82,882,882,2882,2882,164,165,'WGAAAA','GNFAAA','AAAAxx'
+3641,3725,1,1,1,1,41,641,1641,3641,3641,82,83,'BKAAAA','HNFAAA','HHHHxx'
+5537,3726,1,1,7,17,37,537,1537,537,5537,74,75,'ZEAAAA','INFAAA','OOOOxx'
+820,3727,0,0,0,0,20,820,820,820,820,40,41,'OFAAAA','JNFAAA','VVVVxx'
+5847,3728,1,3,7,7,47,847,1847,847,5847,94,95,'XQAAAA','KNFAAA','AAAAxx'
+566,3729,0,2,6,6,66,566,566,566,566,132,133,'UVAAAA','LNFAAA','HHHHxx'
+2246,3730,0,2,6,6,46,246,246,2246,2246,92,93,'KIAAAA','MNFAAA','OOOOxx'
+6680,3731,0,0,0,0,80,680,680,1680,6680,160,161,'YWAAAA','NNFAAA','VVVVxx'
+2014,3732,0,2,4,14,14,14,14,2014,2014,28,29,'MZAAAA','ONFAAA','AAAAxx'
+8355,3733,1,3,5,15,55,355,355,3355,8355,110,111,'JJAAAA','PNFAAA','HHHHxx'
+1610,3734,0,2,0,10,10,610,1610,1610,1610,20,21,'YJAAAA','QNFAAA','OOOOxx'
+9719,3735,1,3,9,19,19,719,1719,4719,9719,38,39,'VJAAAA','RNFAAA','VVVVxx'
+8498,3736,0,2,8,18,98,498,498,3498,8498,196,197,'WOAAAA','SNFAAA','AAAAxx'
+5883,3737,1,3,3,3,83,883,1883,883,5883,166,167,'HSAAAA','TNFAAA','HHHHxx'
+7380,3738,0,0,0,0,80,380,1380,2380,7380,160,161,'WXAAAA','UNFAAA','OOOOxx'
+8865,3739,1,1,5,5,65,865,865,3865,8865,130,131,'ZCAAAA','VNFAAA','VVVVxx'
+4743,3740,1,3,3,3,43,743,743,4743,4743,86,87,'LAAAAA','WNFAAA','AAAAxx'
+5086,3741,0,2,6,6,86,86,1086,86,5086,172,173,'QNAAAA','XNFAAA','HHHHxx'
+2739,3742,1,3,9,19,39,739,739,2739,2739,78,79,'JBAAAA','YNFAAA','OOOOxx'
+9375,3743,1,3,5,15,75,375,1375,4375,9375,150,151,'PWAAAA','ZNFAAA','VVVVxx'
+7876,3744,0,0,6,16,76,876,1876,2876,7876,152,153,'YQAAAA','AOFAAA','AAAAxx'
+453,3745,1,1,3,13,53,453,453,453,453,106,107,'LRAAAA','BOFAAA','HHHHxx'
+6987,3746,1,3,7,7,87,987,987,1987,6987,174,175,'TIAAAA','COFAAA','OOOOxx'
+2860,3747,0,0,0,0,60,860,860,2860,2860,120,121,'AGAAAA','DOFAAA','VVVVxx'
+8372,3748,0,0,2,12,72,372,372,3372,8372,144,145,'AKAAAA','EOFAAA','AAAAxx'
+2048,3749,0,0,8,8,48,48,48,2048,2048,96,97,'UAAAAA','FOFAAA','HHHHxx'
+9231,3750,1,3,1,11,31,231,1231,4231,9231,62,63,'BRAAAA','GOFAAA','OOOOxx'
+634,3751,0,2,4,14,34,634,634,634,634,68,69,'KYAAAA','HOFAAA','VVVVxx'
+3998,3752,0,2,8,18,98,998,1998,3998,3998,196,197,'UXAAAA','IOFAAA','AAAAxx'
+4728,3753,0,0,8,8,28,728,728,4728,4728,56,57,'WZAAAA','JOFAAA','HHHHxx'
+579,3754,1,3,9,19,79,579,579,579,579,158,159,'HWAAAA','KOFAAA','OOOOxx'
+815,3755,1,3,5,15,15,815,815,815,815,30,31,'JFAAAA','LOFAAA','VVVVxx'
+1009,3756,1,1,9,9,9,9,1009,1009,1009,18,19,'VMAAAA','MOFAAA','AAAAxx'
+6596,3757,0,0,6,16,96,596,596,1596,6596,192,193,'STAAAA','NOFAAA','HHHHxx'
+2793,3758,1,1,3,13,93,793,793,2793,2793,186,187,'LDAAAA','OOFAAA','OOOOxx'
+9589,3759,1,1,9,9,89,589,1589,4589,9589,178,179,'VEAAAA','POFAAA','VVVVxx'
+2794,3760,0,2,4,14,94,794,794,2794,2794,188,189,'MDAAAA','QOFAAA','AAAAxx'
+2551,3761,1,3,1,11,51,551,551,2551,2551,102,103,'DUAAAA','ROFAAA','HHHHxx'
+1588,3762,0,0,8,8,88,588,1588,1588,1588,176,177,'CJAAAA','SOFAAA','OOOOxx'
+4443,3763,1,3,3,3,43,443,443,4443,4443,86,87,'XOAAAA','TOFAAA','VVVVxx'
+5009,3764,1,1,9,9,9,9,1009,9,5009,18,19,'RKAAAA','UOFAAA','AAAAxx'
+4287,3765,1,3,7,7,87,287,287,4287,4287,174,175,'XIAAAA','VOFAAA','HHHHxx'
+2167,3766,1,3,7,7,67,167,167,2167,2167,134,135,'JFAAAA','WOFAAA','OOOOxx'
+2290,3767,0,2,0,10,90,290,290,2290,2290,180,181,'CKAAAA','XOFAAA','VVVVxx'
+7225,3768,1,1,5,5,25,225,1225,2225,7225,50,51,'XRAAAA','YOFAAA','AAAAxx'
+8992,3769,0,0,2,12,92,992,992,3992,8992,184,185,'WHAAAA','ZOFAAA','HHHHxx'
+1540,3770,0,0,0,0,40,540,1540,1540,1540,80,81,'GHAAAA','APFAAA','OOOOxx'
+2029,3771,1,1,9,9,29,29,29,2029,2029,58,59,'BAAAAA','BPFAAA','VVVVxx'
+2855,3772,1,3,5,15,55,855,855,2855,2855,110,111,'VFAAAA','CPFAAA','AAAAxx'
+3534,3773,0,2,4,14,34,534,1534,3534,3534,68,69,'YFAAAA','DPFAAA','HHHHxx'
+8078,3774,0,2,8,18,78,78,78,3078,8078,156,157,'SYAAAA','EPFAAA','OOOOxx'
+9778,3775,0,2,8,18,78,778,1778,4778,9778,156,157,'CMAAAA','FPFAAA','VVVVxx'
+3543,3776,1,3,3,3,43,543,1543,3543,3543,86,87,'HGAAAA','GPFAAA','AAAAxx'
+4778,3777,0,2,8,18,78,778,778,4778,4778,156,157,'UBAAAA','HPFAAA','HHHHxx'
+8931,3778,1,3,1,11,31,931,931,3931,8931,62,63,'NFAAAA','IPFAAA','OOOOxx'
+557,3779,1,1,7,17,57,557,557,557,557,114,115,'LVAAAA','JPFAAA','VVVVxx'
+5546,3780,0,2,6,6,46,546,1546,546,5546,92,93,'IFAAAA','KPFAAA','AAAAxx'
+7527,3781,1,3,7,7,27,527,1527,2527,7527,54,55,'NDAAAA','LPFAAA','HHHHxx'
+5000,3782,0,0,0,0,0,0,1000,0,5000,0,1,'IKAAAA','MPFAAA','OOOOxx'
+7587,3783,1,3,7,7,87,587,1587,2587,7587,174,175,'VFAAAA','NPFAAA','VVVVxx'
+3014,3784,0,2,4,14,14,14,1014,3014,3014,28,29,'YLAAAA','OPFAAA','AAAAxx'
+5276,3785,0,0,6,16,76,276,1276,276,5276,152,153,'YUAAAA','PPFAAA','HHHHxx'
+6457,3786,1,1,7,17,57,457,457,1457,6457,114,115,'JOAAAA','QPFAAA','OOOOxx'
+389,3787,1,1,9,9,89,389,389,389,389,178,179,'ZOAAAA','RPFAAA','VVVVxx'
+7104,3788,0,0,4,4,4,104,1104,2104,7104,8,9,'GNAAAA','SPFAAA','AAAAxx'
+9995,3789,1,3,5,15,95,995,1995,4995,9995,190,191,'LUAAAA','TPFAAA','HHHHxx'
+7368,3790,0,0,8,8,68,368,1368,2368,7368,136,137,'KXAAAA','UPFAAA','OOOOxx'
+3258,3791,0,2,8,18,58,258,1258,3258,3258,116,117,'IVAAAA','VPFAAA','VVVVxx'
+9208,3792,0,0,8,8,8,208,1208,4208,9208,16,17,'EQAAAA','WPFAAA','AAAAxx'
+2396,3793,0,0,6,16,96,396,396,2396,2396,192,193,'EOAAAA','XPFAAA','HHHHxx'
+1715,3794,1,3,5,15,15,715,1715,1715,1715,30,31,'ZNAAAA','YPFAAA','OOOOxx'
+1240,3795,0,0,0,0,40,240,1240,1240,1240,80,81,'SVAAAA','ZPFAAA','VVVVxx'
+1952,3796,0,0,2,12,52,952,1952,1952,1952,104,105,'CXAAAA','AQFAAA','AAAAxx'
+4403,3797,1,3,3,3,3,403,403,4403,4403,6,7,'JNAAAA','BQFAAA','HHHHxx'
+6333,3798,1,1,3,13,33,333,333,1333,6333,66,67,'PJAAAA','CQFAAA','OOOOxx'
+2492,3799,0,0,2,12,92,492,492,2492,2492,184,185,'WRAAAA','DQFAAA','VVVVxx'
+6543,3800,1,3,3,3,43,543,543,1543,6543,86,87,'RRAAAA','EQFAAA','AAAAxx'
+5548,3801,0,0,8,8,48,548,1548,548,5548,96,97,'KFAAAA','FQFAAA','HHHHxx'
+3458,3802,0,2,8,18,58,458,1458,3458,3458,116,117,'ADAAAA','GQFAAA','OOOOxx'
+2588,3803,0,0,8,8,88,588,588,2588,2588,176,177,'OVAAAA','HQFAAA','VVVVxx'
+1364,3804,0,0,4,4,64,364,1364,1364,1364,128,129,'MAAAAA','IQFAAA','AAAAxx'
+9856,3805,0,0,6,16,56,856,1856,4856,9856,112,113,'CPAAAA','JQFAAA','HHHHxx'
+4964,3806,0,0,4,4,64,964,964,4964,4964,128,129,'YIAAAA','KQFAAA','OOOOxx'
+773,3807,1,1,3,13,73,773,773,773,773,146,147,'TDAAAA','LQFAAA','VVVVxx'
+6402,3808,0,2,2,2,2,402,402,1402,6402,4,5,'GMAAAA','MQFAAA','AAAAxx'
+7213,3809,1,1,3,13,13,213,1213,2213,7213,26,27,'LRAAAA','NQFAAA','HHHHxx'
+3385,3810,1,1,5,5,85,385,1385,3385,3385,170,171,'FAAAAA','OQFAAA','OOOOxx'
+6005,3811,1,1,5,5,5,5,5,1005,6005,10,11,'ZWAAAA','PQFAAA','VVVVxx'
+9346,3812,0,2,6,6,46,346,1346,4346,9346,92,93,'MVAAAA','QQFAAA','AAAAxx'
+1831,3813,1,3,1,11,31,831,1831,1831,1831,62,63,'LSAAAA','RQFAAA','HHHHxx'
+5406,3814,0,2,6,6,6,406,1406,406,5406,12,13,'YZAAAA','SQFAAA','OOOOxx'
+2154,3815,0,2,4,14,54,154,154,2154,2154,108,109,'WEAAAA','TQFAAA','VVVVxx'
+3721,3816,1,1,1,1,21,721,1721,3721,3721,42,43,'DNAAAA','UQFAAA','AAAAxx'
+2889,3817,1,1,9,9,89,889,889,2889,2889,178,179,'DHAAAA','VQFAAA','HHHHxx'
+4410,3818,0,2,0,10,10,410,410,4410,4410,20,21,'QNAAAA','WQFAAA','OOOOxx'
+7102,3819,0,2,2,2,2,102,1102,2102,7102,4,5,'ENAAAA','XQFAAA','VVVVxx'
+4057,3820,1,1,7,17,57,57,57,4057,4057,114,115,'BAAAAA','YQFAAA','AAAAxx'
+9780,3821,0,0,0,0,80,780,1780,4780,9780,160,161,'EMAAAA','ZQFAAA','HHHHxx'
+9481,3822,1,1,1,1,81,481,1481,4481,9481,162,163,'RAAAAA','ARFAAA','OOOOxx'
+2366,3823,0,2,6,6,66,366,366,2366,2366,132,133,'ANAAAA','BRFAAA','VVVVxx'
+2708,3824,0,0,8,8,8,708,708,2708,2708,16,17,'EAAAAA','CRFAAA','AAAAxx'
+7399,3825,1,3,9,19,99,399,1399,2399,7399,198,199,'PYAAAA','DRFAAA','HHHHxx'
+5234,3826,0,2,4,14,34,234,1234,234,5234,68,69,'ITAAAA','ERFAAA','OOOOxx'
+1843,3827,1,3,3,3,43,843,1843,1843,1843,86,87,'XSAAAA','FRFAAA','VVVVxx'
+1006,3828,0,2,6,6,6,6,1006,1006,1006,12,13,'SMAAAA','GRFAAA','AAAAxx'
+7696,3829,0,0,6,16,96,696,1696,2696,7696,192,193,'AKAAAA','HRFAAA','HHHHxx'
+6411,3830,1,3,1,11,11,411,411,1411,6411,22,23,'PMAAAA','IRFAAA','OOOOxx'
+3913,3831,1,1,3,13,13,913,1913,3913,3913,26,27,'NUAAAA','JRFAAA','VVVVxx'
+2538,3832,0,2,8,18,38,538,538,2538,2538,76,77,'QTAAAA','KRFAAA','AAAAxx'
+3019,3833,1,3,9,19,19,19,1019,3019,3019,38,39,'DMAAAA','LRFAAA','HHHHxx'
+107,3834,1,3,7,7,7,107,107,107,107,14,15,'DEAAAA','MRFAAA','OOOOxx'
+427,3835,1,3,7,7,27,427,427,427,427,54,55,'LQAAAA','NRFAAA','VVVVxx'
+9849,3836,1,1,9,9,49,849,1849,4849,9849,98,99,'VOAAAA','ORFAAA','AAAAxx'
+4195,3837,1,3,5,15,95,195,195,4195,4195,190,191,'JFAAAA','PRFAAA','HHHHxx'
+9215,3838,1,3,5,15,15,215,1215,4215,9215,30,31,'LQAAAA','QRFAAA','OOOOxx'
+3165,3839,1,1,5,5,65,165,1165,3165,3165,130,131,'TRAAAA','RRFAAA','VVVVxx'
+3280,3840,0,0,0,0,80,280,1280,3280,3280,160,161,'EWAAAA','SRFAAA','AAAAxx'
+4477,3841,1,1,7,17,77,477,477,4477,4477,154,155,'FQAAAA','TRFAAA','HHHHxx'
+5885,3842,1,1,5,5,85,885,1885,885,5885,170,171,'JSAAAA','URFAAA','OOOOxx'
+3311,3843,1,3,1,11,11,311,1311,3311,3311,22,23,'JXAAAA','VRFAAA','VVVVxx'
+6453,3844,1,1,3,13,53,453,453,1453,6453,106,107,'FOAAAA','WRFAAA','AAAAxx'
+8527,3845,1,3,7,7,27,527,527,3527,8527,54,55,'ZPAAAA','XRFAAA','HHHHxx'
+1921,3846,1,1,1,1,21,921,1921,1921,1921,42,43,'XVAAAA','YRFAAA','OOOOxx'
+2427,3847,1,3,7,7,27,427,427,2427,2427,54,55,'JPAAAA','ZRFAAA','VVVVxx'
+3691,3848,1,3,1,11,91,691,1691,3691,3691,182,183,'ZLAAAA','ASFAAA','AAAAxx'
+3882,3849,0,2,2,2,82,882,1882,3882,3882,164,165,'ITAAAA','BSFAAA','HHHHxx'
+562,3850,0,2,2,2,62,562,562,562,562,124,125,'QVAAAA','CSFAAA','OOOOxx'
+377,3851,1,1,7,17,77,377,377,377,377,154,155,'NOAAAA','DSFAAA','VVVVxx'
+1497,3852,1,1,7,17,97,497,1497,1497,1497,194,195,'PFAAAA','ESFAAA','AAAAxx'
+4453,3853,1,1,3,13,53,453,453,4453,4453,106,107,'HPAAAA','FSFAAA','HHHHxx'
+4678,3854,0,2,8,18,78,678,678,4678,4678,156,157,'YXAAAA','GSFAAA','OOOOxx'
+2234,3855,0,2,4,14,34,234,234,2234,2234,68,69,'YHAAAA','HSFAAA','VVVVxx'
+1073,3856,1,1,3,13,73,73,1073,1073,1073,146,147,'HPAAAA','ISFAAA','AAAAxx'
+6479,3857,1,3,9,19,79,479,479,1479,6479,158,159,'FPAAAA','JSFAAA','HHHHxx'
+5665,3858,1,1,5,5,65,665,1665,665,5665,130,131,'XJAAAA','KSFAAA','OOOOxx'
+586,3859,0,2,6,6,86,586,586,586,586,172,173,'OWAAAA','LSFAAA','VVVVxx'
+1584,3860,0,0,4,4,84,584,1584,1584,1584,168,169,'YIAAAA','MSFAAA','AAAAxx'
+2574,3861,0,2,4,14,74,574,574,2574,2574,148,149,'AVAAAA','NSFAAA','HHHHxx'
+9833,3862,1,1,3,13,33,833,1833,4833,9833,66,67,'FOAAAA','OSFAAA','OOOOxx'
+6726,3863,0,2,6,6,26,726,726,1726,6726,52,53,'SYAAAA','PSFAAA','VVVVxx'
+8497,3864,1,1,7,17,97,497,497,3497,8497,194,195,'VOAAAA','QSFAAA','AAAAxx'
+2914,3865,0,2,4,14,14,914,914,2914,2914,28,29,'CIAAAA','RSFAAA','HHHHxx'
+8586,3866,0,2,6,6,86,586,586,3586,8586,172,173,'GSAAAA','SSFAAA','OOOOxx'
+6973,3867,1,1,3,13,73,973,973,1973,6973,146,147,'FIAAAA','TSFAAA','VVVVxx'
+1322,3868,0,2,2,2,22,322,1322,1322,1322,44,45,'WYAAAA','USFAAA','AAAAxx'
+5242,3869,0,2,2,2,42,242,1242,242,5242,84,85,'QTAAAA','VSFAAA','HHHHxx'
+5581,3870,1,1,1,1,81,581,1581,581,5581,162,163,'RGAAAA','WSFAAA','OOOOxx'
+1365,3871,1,1,5,5,65,365,1365,1365,1365,130,131,'NAAAAA','XSFAAA','VVVVxx'
+2818,3872,0,2,8,18,18,818,818,2818,2818,36,37,'KEAAAA','YSFAAA','AAAAxx'
+3758,3873,0,2,8,18,58,758,1758,3758,3758,116,117,'OOAAAA','ZSFAAA','HHHHxx'
+2665,3874,1,1,5,5,65,665,665,2665,2665,130,131,'NYAAAA','ATFAAA','OOOOxx'
+9823,3875,1,3,3,3,23,823,1823,4823,9823,46,47,'VNAAAA','BTFAAA','VVVVxx'
+7057,3876,1,1,7,17,57,57,1057,2057,7057,114,115,'LLAAAA','CTFAAA','AAAAxx'
+543,3877,1,3,3,3,43,543,543,543,543,86,87,'XUAAAA','DTFAAA','HHHHxx'
+4008,3878,0,0,8,8,8,8,8,4008,4008,16,17,'EYAAAA','ETFAAA','OOOOxx'
+4397,3879,1,1,7,17,97,397,397,4397,4397,194,195,'DNAAAA','FTFAAA','VVVVxx'
+8533,3880,1,1,3,13,33,533,533,3533,8533,66,67,'FQAAAA','GTFAAA','AAAAxx'
+9728,3881,0,0,8,8,28,728,1728,4728,9728,56,57,'EKAAAA','HTFAAA','HHHHxx'
+5198,3882,0,2,8,18,98,198,1198,198,5198,196,197,'YRAAAA','ITFAAA','OOOOxx'
+5036,3883,0,0,6,16,36,36,1036,36,5036,72,73,'SLAAAA','JTFAAA','VVVVxx'
+4394,3884,0,2,4,14,94,394,394,4394,4394,188,189,'ANAAAA','KTFAAA','AAAAxx'
+9633,3885,1,1,3,13,33,633,1633,4633,9633,66,67,'NGAAAA','LTFAAA','HHHHxx'
+3339,3886,1,3,9,19,39,339,1339,3339,3339,78,79,'LYAAAA','MTFAAA','OOOOxx'
+9529,3887,1,1,9,9,29,529,1529,4529,9529,58,59,'NCAAAA','NTFAAA','VVVVxx'
+4780,3888,0,0,0,0,80,780,780,4780,4780,160,161,'WBAAAA','OTFAAA','AAAAxx'
+4862,3889,0,2,2,2,62,862,862,4862,4862,124,125,'AFAAAA','PTFAAA','HHHHxx'
+8152,3890,0,0,2,12,52,152,152,3152,8152,104,105,'OBAAAA','QTFAAA','OOOOxx'
+9330,3891,0,2,0,10,30,330,1330,4330,9330,60,61,'WUAAAA','RTFAAA','VVVVxx'
+4362,3892,0,2,2,2,62,362,362,4362,4362,124,125,'ULAAAA','STFAAA','AAAAxx'
+4688,3893,0,0,8,8,88,688,688,4688,4688,176,177,'IYAAAA','TTFAAA','HHHHxx'
+1903,3894,1,3,3,3,3,903,1903,1903,1903,6,7,'FVAAAA','UTFAAA','OOOOxx'
+9027,3895,1,3,7,7,27,27,1027,4027,9027,54,55,'FJAAAA','VTFAAA','VVVVxx'
+5385,3896,1,1,5,5,85,385,1385,385,5385,170,171,'DZAAAA','WTFAAA','AAAAxx'
+9854,3897,0,2,4,14,54,854,1854,4854,9854,108,109,'APAAAA','XTFAAA','HHHHxx'
+9033,3898,1,1,3,13,33,33,1033,4033,9033,66,67,'LJAAAA','YTFAAA','OOOOxx'
+3185,3899,1,1,5,5,85,185,1185,3185,3185,170,171,'NSAAAA','ZTFAAA','VVVVxx'
+2618,3900,0,2,8,18,18,618,618,2618,2618,36,37,'SWAAAA','AUFAAA','AAAAxx'
+371,3901,1,3,1,11,71,371,371,371,371,142,143,'HOAAAA','BUFAAA','HHHHxx'
+3697,3902,1,1,7,17,97,697,1697,3697,3697,194,195,'FMAAAA','CUFAAA','OOOOxx'
+1682,3903,0,2,2,2,82,682,1682,1682,1682,164,165,'SMAAAA','DUFAAA','VVVVxx'
+3333,3904,1,1,3,13,33,333,1333,3333,3333,66,67,'FYAAAA','EUFAAA','AAAAxx'
+1722,3905,0,2,2,2,22,722,1722,1722,1722,44,45,'GOAAAA','FUFAAA','HHHHxx'
+2009,3906,1,1,9,9,9,9,9,2009,2009,18,19,'HZAAAA','GUFAAA','OOOOxx'
+3517,3907,1,1,7,17,17,517,1517,3517,3517,34,35,'HFAAAA','HUFAAA','VVVVxx'
+7640,3908,0,0,0,0,40,640,1640,2640,7640,80,81,'WHAAAA','IUFAAA','AAAAxx'
+259,3909,1,3,9,19,59,259,259,259,259,118,119,'ZJAAAA','JUFAAA','HHHHxx'
+1400,3910,0,0,0,0,0,400,1400,1400,1400,0,1,'WBAAAA','KUFAAA','OOOOxx'
+6663,3911,1,3,3,3,63,663,663,1663,6663,126,127,'HWAAAA','LUFAAA','VVVVxx'
+1576,3912,0,0,6,16,76,576,1576,1576,1576,152,153,'QIAAAA','MUFAAA','AAAAxx'
+8843,3913,1,3,3,3,43,843,843,3843,8843,86,87,'DCAAAA','NUFAAA','HHHHxx'
+9474,3914,0,2,4,14,74,474,1474,4474,9474,148,149,'KAAAAA','OUFAAA','OOOOxx'
+1597,3915,1,1,7,17,97,597,1597,1597,1597,194,195,'LJAAAA','PUFAAA','VVVVxx'
+1143,3916,1,3,3,3,43,143,1143,1143,1143,86,87,'ZRAAAA','QUFAAA','AAAAxx'
+4162,3917,0,2,2,2,62,162,162,4162,4162,124,125,'CEAAAA','RUFAAA','HHHHxx'
+1301,3918,1,1,1,1,1,301,1301,1301,1301,2,3,'BYAAAA','SUFAAA','OOOOxx'
+2935,3919,1,3,5,15,35,935,935,2935,2935,70,71,'XIAAAA','TUFAAA','VVVVxx'
+886,3920,0,2,6,6,86,886,886,886,886,172,173,'CIAAAA','UUFAAA','AAAAxx'
+1661,3921,1,1,1,1,61,661,1661,1661,1661,122,123,'XLAAAA','VUFAAA','HHHHxx'
+1026,3922,0,2,6,6,26,26,1026,1026,1026,52,53,'MNAAAA','WUFAAA','OOOOxx'
+7034,3923,0,2,4,14,34,34,1034,2034,7034,68,69,'OKAAAA','XUFAAA','VVVVxx'
+2305,3924,1,1,5,5,5,305,305,2305,2305,10,11,'RKAAAA','YUFAAA','AAAAxx'
+1725,3925,1,1,5,5,25,725,1725,1725,1725,50,51,'JOAAAA','ZUFAAA','HHHHxx'
+909,3926,1,1,9,9,9,909,909,909,909,18,19,'ZIAAAA','AVFAAA','OOOOxx'
+9906,3927,0,2,6,6,6,906,1906,4906,9906,12,13,'ARAAAA','BVFAAA','VVVVxx'
+3309,3928,1,1,9,9,9,309,1309,3309,3309,18,19,'HXAAAA','CVFAAA','AAAAxx'
+515,3929,1,3,5,15,15,515,515,515,515,30,31,'VTAAAA','DVFAAA','HHHHxx'
+932,3930,0,0,2,12,32,932,932,932,932,64,65,'WJAAAA','EVFAAA','OOOOxx'
+8144,3931,0,0,4,4,44,144,144,3144,8144,88,89,'GBAAAA','FVFAAA','VVVVxx'
+5592,3932,0,0,2,12,92,592,1592,592,5592,184,185,'CHAAAA','GVFAAA','AAAAxx'
+4003,3933,1,3,3,3,3,3,3,4003,4003,6,7,'ZXAAAA','HVFAAA','HHHHxx'
+9566,3934,0,2,6,6,66,566,1566,4566,9566,132,133,'YDAAAA','IVFAAA','OOOOxx'
+4556,3935,0,0,6,16,56,556,556,4556,4556,112,113,'GTAAAA','JVFAAA','VVVVxx'
+268,3936,0,0,8,8,68,268,268,268,268,136,137,'IKAAAA','KVFAAA','AAAAxx'
+8107,3937,1,3,7,7,7,107,107,3107,8107,14,15,'VZAAAA','LVFAAA','HHHHxx'
+5816,3938,0,0,6,16,16,816,1816,816,5816,32,33,'SPAAAA','MVFAAA','OOOOxx'
+8597,3939,1,1,7,17,97,597,597,3597,8597,194,195,'RSAAAA','NVFAAA','VVVVxx'
+9611,3940,1,3,1,11,11,611,1611,4611,9611,22,23,'RFAAAA','OVFAAA','AAAAxx'
+8070,3941,0,2,0,10,70,70,70,3070,8070,140,141,'KYAAAA','PVFAAA','HHHHxx'
+6040,3942,0,0,0,0,40,40,40,1040,6040,80,81,'IYAAAA','QVFAAA','OOOOxx'
+3184,3943,0,0,4,4,84,184,1184,3184,3184,168,169,'MSAAAA','RVFAAA','VVVVxx'
+9656,3944,0,0,6,16,56,656,1656,4656,9656,112,113,'KHAAAA','SVFAAA','AAAAxx'
+1577,3945,1,1,7,17,77,577,1577,1577,1577,154,155,'RIAAAA','TVFAAA','HHHHxx'
+1805,3946,1,1,5,5,5,805,1805,1805,1805,10,11,'LRAAAA','UVFAAA','OOOOxx'
+8268,3947,0,0,8,8,68,268,268,3268,8268,136,137,'AGAAAA','VVFAAA','VVVVxx'
+3489,3948,1,1,9,9,89,489,1489,3489,3489,178,179,'FEAAAA','WVFAAA','AAAAxx'
+4564,3949,0,0,4,4,64,564,564,4564,4564,128,129,'OTAAAA','XVFAAA','HHHHxx'
+4006,3950,0,2,6,6,6,6,6,4006,4006,12,13,'CYAAAA','YVFAAA','OOOOxx'
+8466,3951,0,2,6,6,66,466,466,3466,8466,132,133,'QNAAAA','ZVFAAA','VVVVxx'
+938,3952,0,2,8,18,38,938,938,938,938,76,77,'CKAAAA','AWFAAA','AAAAxx'
+5944,3953,0,0,4,4,44,944,1944,944,5944,88,89,'QUAAAA','BWFAAA','HHHHxx'
+8363,3954,1,3,3,3,63,363,363,3363,8363,126,127,'RJAAAA','CWFAAA','OOOOxx'
+5348,3955,0,0,8,8,48,348,1348,348,5348,96,97,'SXAAAA','DWFAAA','VVVVxx'
+71,3956,1,3,1,11,71,71,71,71,71,142,143,'TCAAAA','EWFAAA','AAAAxx'
+3620,3957,0,0,0,0,20,620,1620,3620,3620,40,41,'GJAAAA','FWFAAA','HHHHxx'
+3230,3958,0,2,0,10,30,230,1230,3230,3230,60,61,'GUAAAA','GWFAAA','OOOOxx'
+6132,3959,0,0,2,12,32,132,132,1132,6132,64,65,'WBAAAA','HWFAAA','VVVVxx'
+6143,3960,1,3,3,3,43,143,143,1143,6143,86,87,'HCAAAA','IWFAAA','AAAAxx'
+8781,3961,1,1,1,1,81,781,781,3781,8781,162,163,'TZAAAA','JWFAAA','HHHHxx'
+5522,3962,0,2,2,2,22,522,1522,522,5522,44,45,'KEAAAA','KWFAAA','OOOOxx'
+6320,3963,0,0,0,0,20,320,320,1320,6320,40,41,'CJAAAA','LWFAAA','VVVVxx'
+3923,3964,1,3,3,3,23,923,1923,3923,3923,46,47,'XUAAAA','MWFAAA','AAAAxx'
+2207,3965,1,3,7,7,7,207,207,2207,2207,14,15,'XGAAAA','NWFAAA','HHHHxx'
+966,3966,0,2,6,6,66,966,966,966,966,132,133,'ELAAAA','OWFAAA','OOOOxx'
+9020,3967,0,0,0,0,20,20,1020,4020,9020,40,41,'YIAAAA','PWFAAA','VVVVxx'
+4616,3968,0,0,6,16,16,616,616,4616,4616,32,33,'OVAAAA','QWFAAA','AAAAxx'
+8289,3969,1,1,9,9,89,289,289,3289,8289,178,179,'VGAAAA','RWFAAA','HHHHxx'
+5796,3970,0,0,6,16,96,796,1796,796,5796,192,193,'YOAAAA','SWFAAA','OOOOxx'
+9259,3971,1,3,9,19,59,259,1259,4259,9259,118,119,'DSAAAA','TWFAAA','VVVVxx'
+3710,3972,0,2,0,10,10,710,1710,3710,3710,20,21,'SMAAAA','UWFAAA','AAAAxx'
+251,3973,1,3,1,11,51,251,251,251,251,102,103,'RJAAAA','VWFAAA','HHHHxx'
+7669,3974,1,1,9,9,69,669,1669,2669,7669,138,139,'ZIAAAA','WWFAAA','OOOOxx'
+6304,3975,0,0,4,4,4,304,304,1304,6304,8,9,'MIAAAA','XWFAAA','VVVVxx'
+6454,3976,0,2,4,14,54,454,454,1454,6454,108,109,'GOAAAA','YWFAAA','AAAAxx'
+1489,3977,1,1,9,9,89,489,1489,1489,1489,178,179,'HFAAAA','ZWFAAA','HHHHxx'
+715,3978,1,3,5,15,15,715,715,715,715,30,31,'NBAAAA','AXFAAA','OOOOxx'
+4319,3979,1,3,9,19,19,319,319,4319,4319,38,39,'DKAAAA','BXFAAA','VVVVxx'
+7112,3980,0,0,2,12,12,112,1112,2112,7112,24,25,'ONAAAA','CXFAAA','AAAAxx'
+3726,3981,0,2,6,6,26,726,1726,3726,3726,52,53,'INAAAA','DXFAAA','HHHHxx'
+7727,3982,1,3,7,7,27,727,1727,2727,7727,54,55,'FLAAAA','EXFAAA','OOOOxx'
+8387,3983,1,3,7,7,87,387,387,3387,8387,174,175,'PKAAAA','FXFAAA','VVVVxx'
+6555,3984,1,3,5,15,55,555,555,1555,6555,110,111,'DSAAAA','GXFAAA','AAAAxx'
+1148,3985,0,0,8,8,48,148,1148,1148,1148,96,97,'ESAAAA','HXFAAA','HHHHxx'
+9000,3986,0,0,0,0,0,0,1000,4000,9000,0,1,'EIAAAA','IXFAAA','OOOOxx'
+5278,3987,0,2,8,18,78,278,1278,278,5278,156,157,'AVAAAA','JXFAAA','VVVVxx'
+2388,3988,0,0,8,8,88,388,388,2388,2388,176,177,'WNAAAA','KXFAAA','AAAAxx'
+7984,3989,0,0,4,4,84,984,1984,2984,7984,168,169,'CVAAAA','LXFAAA','HHHHxx'
+881,3990,1,1,1,1,81,881,881,881,881,162,163,'XHAAAA','MXFAAA','OOOOxx'
+6830,3991,0,2,0,10,30,830,830,1830,6830,60,61,'SCAAAA','NXFAAA','VVVVxx'
+7056,3992,0,0,6,16,56,56,1056,2056,7056,112,113,'KLAAAA','OXFAAA','AAAAxx'
+7581,3993,1,1,1,1,81,581,1581,2581,7581,162,163,'PFAAAA','PXFAAA','HHHHxx'
+5214,3994,0,2,4,14,14,214,1214,214,5214,28,29,'OSAAAA','QXFAAA','OOOOxx'
+2505,3995,1,1,5,5,5,505,505,2505,2505,10,11,'JSAAAA','RXFAAA','VVVVxx'
+5112,3996,0,0,2,12,12,112,1112,112,5112,24,25,'QOAAAA','SXFAAA','AAAAxx'
+9884,3997,0,0,4,4,84,884,1884,4884,9884,168,169,'EQAAAA','TXFAAA','HHHHxx'
+8040,3998,0,0,0,0,40,40,40,3040,8040,80,81,'GXAAAA','UXFAAA','OOOOxx'
+7033,3999,1,1,3,13,33,33,1033,2033,7033,66,67,'NKAAAA','VXFAAA','VVVVxx'
+9343,4000,1,3,3,3,43,343,1343,4343,9343,86,87,'JVAAAA','WXFAAA','AAAAxx'
+2931,4001,1,3,1,11,31,931,931,2931,2931,62,63,'TIAAAA','XXFAAA','HHHHxx'
+9024,4002,0,0,4,4,24,24,1024,4024,9024,48,49,'CJAAAA','YXFAAA','OOOOxx'
+6485,4003,1,1,5,5,85,485,485,1485,6485,170,171,'LPAAAA','ZXFAAA','VVVVxx'
+3465,4004,1,1,5,5,65,465,1465,3465,3465,130,131,'HDAAAA','AYFAAA','AAAAxx'
+3357,4005,1,1,7,17,57,357,1357,3357,3357,114,115,'DZAAAA','BYFAAA','HHHHxx'
+2929,4006,1,1,9,9,29,929,929,2929,2929,58,59,'RIAAAA','CYFAAA','OOOOxx'
+3086,4007,0,2,6,6,86,86,1086,3086,3086,172,173,'SOAAAA','DYFAAA','VVVVxx'
+8897,4008,1,1,7,17,97,897,897,3897,8897,194,195,'FEAAAA','EYFAAA','AAAAxx'
+9688,4009,0,0,8,8,88,688,1688,4688,9688,176,177,'QIAAAA','FYFAAA','HHHHxx'
+6522,4010,0,2,2,2,22,522,522,1522,6522,44,45,'WQAAAA','GYFAAA','OOOOxx'
+3241,4011,1,1,1,1,41,241,1241,3241,3241,82,83,'RUAAAA','HYFAAA','VVVVxx'
+8770,4012,0,2,0,10,70,770,770,3770,8770,140,141,'IZAAAA','IYFAAA','AAAAxx'
+2884,4013,0,0,4,4,84,884,884,2884,2884,168,169,'YGAAAA','JYFAAA','HHHHxx'
+9579,4014,1,3,9,19,79,579,1579,4579,9579,158,159,'LEAAAA','KYFAAA','OOOOxx'
+3125,4015,1,1,5,5,25,125,1125,3125,3125,50,51,'FQAAAA','LYFAAA','VVVVxx'
+4604,4016,0,0,4,4,4,604,604,4604,4604,8,9,'CVAAAA','MYFAAA','AAAAxx'
+2682,4017,0,2,2,2,82,682,682,2682,2682,164,165,'EZAAAA','NYFAAA','HHHHxx'
+254,4018,0,2,4,14,54,254,254,254,254,108,109,'UJAAAA','OYFAAA','OOOOxx'
+6569,4019,1,1,9,9,69,569,569,1569,6569,138,139,'RSAAAA','PYFAAA','VVVVxx'
+2686,4020,0,2,6,6,86,686,686,2686,2686,172,173,'IZAAAA','QYFAAA','AAAAxx'
+2123,4021,1,3,3,3,23,123,123,2123,2123,46,47,'RDAAAA','RYFAAA','HHHHxx'
+1745,4022,1,1,5,5,45,745,1745,1745,1745,90,91,'DPAAAA','SYFAAA','OOOOxx'
+247,4023,1,3,7,7,47,247,247,247,247,94,95,'NJAAAA','TYFAAA','VVVVxx'
+5800,4024,0,0,0,0,0,800,1800,800,5800,0,1,'CPAAAA','UYFAAA','AAAAxx'
+1121,4025,1,1,1,1,21,121,1121,1121,1121,42,43,'DRAAAA','VYFAAA','HHHHxx'
+8893,4026,1,1,3,13,93,893,893,3893,8893,186,187,'BEAAAA','WYFAAA','OOOOxx'
+7819,4027,1,3,9,19,19,819,1819,2819,7819,38,39,'TOAAAA','XYFAAA','VVVVxx'
+1339,4028,1,3,9,19,39,339,1339,1339,1339,78,79,'NZAAAA','YYFAAA','AAAAxx'
+5680,4029,0,0,0,0,80,680,1680,680,5680,160,161,'MKAAAA','ZYFAAA','HHHHxx'
+5093,4030,1,1,3,13,93,93,1093,93,5093,186,187,'XNAAAA','AZFAAA','OOOOxx'
+3508,4031,0,0,8,8,8,508,1508,3508,3508,16,17,'YEAAAA','BZFAAA','VVVVxx'
+933,4032,1,1,3,13,33,933,933,933,933,66,67,'XJAAAA','CZFAAA','AAAAxx'
+1106,4033,0,2,6,6,6,106,1106,1106,1106,12,13,'OQAAAA','DZFAAA','HHHHxx'
+4386,4034,0,2,6,6,86,386,386,4386,4386,172,173,'SMAAAA','EZFAAA','OOOOxx'
+5895,4035,1,3,5,15,95,895,1895,895,5895,190,191,'TSAAAA','FZFAAA','VVVVxx'
+2980,4036,0,0,0,0,80,980,980,2980,2980,160,161,'QKAAAA','GZFAAA','AAAAxx'
+4400,4037,0,0,0,0,0,400,400,4400,4400,0,1,'GNAAAA','HZFAAA','HHHHxx'
+7433,4038,1,1,3,13,33,433,1433,2433,7433,66,67,'XZAAAA','IZFAAA','OOOOxx'
+6110,4039,0,2,0,10,10,110,110,1110,6110,20,21,'ABAAAA','JZFAAA','VVVVxx'
+867,4040,1,3,7,7,67,867,867,867,867,134,135,'JHAAAA','KZFAAA','AAAAxx'
+5292,4041,0,0,2,12,92,292,1292,292,5292,184,185,'OVAAAA','LZFAAA','HHHHxx'
+3926,4042,0,2,6,6,26,926,1926,3926,3926,52,53,'AVAAAA','MZFAAA','OOOOxx'
+1107,4043,1,3,7,7,7,107,1107,1107,1107,14,15,'PQAAAA','NZFAAA','VVVVxx'
+7355,4044,1,3,5,15,55,355,1355,2355,7355,110,111,'XWAAAA','OZFAAA','AAAAxx'
+4689,4045,1,1,9,9,89,689,689,4689,4689,178,179,'JYAAAA','PZFAAA','HHHHxx'
+4872,4046,0,0,2,12,72,872,872,4872,4872,144,145,'KFAAAA','QZFAAA','OOOOxx'
+7821,4047,1,1,1,1,21,821,1821,2821,7821,42,43,'VOAAAA','RZFAAA','VVVVxx'
+7277,4048,1,1,7,17,77,277,1277,2277,7277,154,155,'XTAAAA','SZFAAA','AAAAxx'
+3268,4049,0,0,8,8,68,268,1268,3268,3268,136,137,'SVAAAA','TZFAAA','HHHHxx'
+8877,4050,1,1,7,17,77,877,877,3877,8877,154,155,'LDAAAA','UZFAAA','OOOOxx'
+343,4051,1,3,3,3,43,343,343,343,343,86,87,'FNAAAA','VZFAAA','VVVVxx'
+621,4052,1,1,1,1,21,621,621,621,621,42,43,'XXAAAA','WZFAAA','AAAAxx'
+5429,4053,1,1,9,9,29,429,1429,429,5429,58,59,'VAAAAA','XZFAAA','HHHHxx'
+392,4054,0,0,2,12,92,392,392,392,392,184,185,'CPAAAA','YZFAAA','OOOOxx'
+6004,4055,0,0,4,4,4,4,4,1004,6004,8,9,'YWAAAA','ZZFAAA','VVVVxx'
+6377,4056,1,1,7,17,77,377,377,1377,6377,154,155,'HLAAAA','AAGAAA','AAAAxx'
+3037,4057,1,1,7,17,37,37,1037,3037,3037,74,75,'VMAAAA','BAGAAA','HHHHxx'
+3514,4058,0,2,4,14,14,514,1514,3514,3514,28,29,'EFAAAA','CAGAAA','OOOOxx'
+8740,4059,0,0,0,0,40,740,740,3740,8740,80,81,'EYAAAA','DAGAAA','VVVVxx'
+3877,4060,1,1,7,17,77,877,1877,3877,3877,154,155,'DTAAAA','EAGAAA','AAAAxx'
+5731,4061,1,3,1,11,31,731,1731,731,5731,62,63,'LMAAAA','FAGAAA','HHHHxx'
+6407,4062,1,3,7,7,7,407,407,1407,6407,14,15,'LMAAAA','GAGAAA','OOOOxx'
+2044,4063,0,0,4,4,44,44,44,2044,2044,88,89,'QAAAAA','HAGAAA','VVVVxx'
+7362,4064,0,2,2,2,62,362,1362,2362,7362,124,125,'EXAAAA','IAGAAA','AAAAxx'
+5458,4065,0,2,8,18,58,458,1458,458,5458,116,117,'YBAAAA','JAGAAA','HHHHxx'
+6437,4066,1,1,7,17,37,437,437,1437,6437,74,75,'PNAAAA','KAGAAA','OOOOxx'
+1051,4067,1,3,1,11,51,51,1051,1051,1051,102,103,'LOAAAA','LAGAAA','VVVVxx'
+1203,4068,1,3,3,3,3,203,1203,1203,1203,6,7,'HUAAAA','MAGAAA','AAAAxx'
+2176,4069,0,0,6,16,76,176,176,2176,2176,152,153,'SFAAAA','NAGAAA','HHHHxx'
+8997,4070,1,1,7,17,97,997,997,3997,8997,194,195,'BIAAAA','OAGAAA','OOOOxx'
+6378,4071,0,2,8,18,78,378,378,1378,6378,156,157,'ILAAAA','PAGAAA','VVVVxx'
+6006,4072,0,2,6,6,6,6,6,1006,6006,12,13,'AXAAAA','QAGAAA','AAAAxx'
+2308,4073,0,0,8,8,8,308,308,2308,2308,16,17,'UKAAAA','RAGAAA','HHHHxx'
+625,4074,1,1,5,5,25,625,625,625,625,50,51,'BYAAAA','SAGAAA','OOOOxx'
+7298,4075,0,2,8,18,98,298,1298,2298,7298,196,197,'SUAAAA','TAGAAA','VVVVxx'
+5575,4076,1,3,5,15,75,575,1575,575,5575,150,151,'LGAAAA','UAGAAA','AAAAxx'
+3565,4077,1,1,5,5,65,565,1565,3565,3565,130,131,'DHAAAA','VAGAAA','HHHHxx'
+47,4078,1,3,7,7,47,47,47,47,47,94,95,'VBAAAA','WAGAAA','OOOOxx'
+2413,4079,1,1,3,13,13,413,413,2413,2413,26,27,'VOAAAA','XAGAAA','VVVVxx'
+2153,4080,1,1,3,13,53,153,153,2153,2153,106,107,'VEAAAA','YAGAAA','AAAAxx'
+752,4081,0,0,2,12,52,752,752,752,752,104,105,'YCAAAA','ZAGAAA','HHHHxx'
+4095,4082,1,3,5,15,95,95,95,4095,4095,190,191,'NBAAAA','ABGAAA','OOOOxx'
+2518,4083,0,2,8,18,18,518,518,2518,2518,36,37,'WSAAAA','BBGAAA','VVVVxx'
+3681,4084,1,1,1,1,81,681,1681,3681,3681,162,163,'PLAAAA','CBGAAA','AAAAxx'
+4213,4085,1,1,3,13,13,213,213,4213,4213,26,27,'BGAAAA','DBGAAA','HHHHxx'
+2615,4086,1,3,5,15,15,615,615,2615,2615,30,31,'PWAAAA','EBGAAA','OOOOxx'
+1471,4087,1,3,1,11,71,471,1471,1471,1471,142,143,'PEAAAA','FBGAAA','VVVVxx'
+7315,4088,1,3,5,15,15,315,1315,2315,7315,30,31,'JVAAAA','GBGAAA','AAAAxx'
+6013,4089,1,1,3,13,13,13,13,1013,6013,26,27,'HXAAAA','HBGAAA','HHHHxx'
+3077,4090,1,1,7,17,77,77,1077,3077,3077,154,155,'JOAAAA','IBGAAA','OOOOxx'
+2190,4091,0,2,0,10,90,190,190,2190,2190,180,181,'GGAAAA','JBGAAA','VVVVxx'
+528,4092,0,0,8,8,28,528,528,528,528,56,57,'IUAAAA','KBGAAA','AAAAxx'
+9508,4093,0,0,8,8,8,508,1508,4508,9508,16,17,'SBAAAA','LBGAAA','HHHHxx'
+2473,4094,1,1,3,13,73,473,473,2473,2473,146,147,'DRAAAA','MBGAAA','OOOOxx'
+167,4095,1,3,7,7,67,167,167,167,167,134,135,'LGAAAA','NBGAAA','VVVVxx'
+8448,4096,0,0,8,8,48,448,448,3448,8448,96,97,'YMAAAA','OBGAAA','AAAAxx'
+7538,4097,0,2,8,18,38,538,1538,2538,7538,76,77,'YDAAAA','PBGAAA','HHHHxx'
+7638,4098,0,2,8,18,38,638,1638,2638,7638,76,77,'UHAAAA','QBGAAA','OOOOxx'
+4328,4099,0,0,8,8,28,328,328,4328,4328,56,57,'MKAAAA','RBGAAA','VVVVxx'
+3812,4100,0,0,2,12,12,812,1812,3812,3812,24,25,'QQAAAA','SBGAAA','AAAAxx'
+2879,4101,1,3,9,19,79,879,879,2879,2879,158,159,'TGAAAA','TBGAAA','HHHHxx'
+4741,4102,1,1,1,1,41,741,741,4741,4741,82,83,'JAAAAA','UBGAAA','OOOOxx'
+9155,4103,1,3,5,15,55,155,1155,4155,9155,110,111,'DOAAAA','VBGAAA','VVVVxx'
+5151,4104,1,3,1,11,51,151,1151,151,5151,102,103,'DQAAAA','WBGAAA','AAAAxx'
+5591,4105,1,3,1,11,91,591,1591,591,5591,182,183,'BHAAAA','XBGAAA','HHHHxx'
+1034,4106,0,2,4,14,34,34,1034,1034,1034,68,69,'UNAAAA','YBGAAA','OOOOxx'
+765,4107,1,1,5,5,65,765,765,765,765,130,131,'LDAAAA','ZBGAAA','VVVVxx'
+2664,4108,0,0,4,4,64,664,664,2664,2664,128,129,'MYAAAA','ACGAAA','AAAAxx'
+6854,4109,0,2,4,14,54,854,854,1854,6854,108,109,'QDAAAA','BCGAAA','HHHHxx'
+8263,4110,1,3,3,3,63,263,263,3263,8263,126,127,'VFAAAA','CCGAAA','OOOOxx'
+8658,4111,0,2,8,18,58,658,658,3658,8658,116,117,'AVAAAA','DCGAAA','VVVVxx'
+587,4112,1,3,7,7,87,587,587,587,587,174,175,'PWAAAA','ECGAAA','AAAAxx'
+4553,4113,1,1,3,13,53,553,553,4553,4553,106,107,'DTAAAA','FCGAAA','HHHHxx'
+1368,4114,0,0,8,8,68,368,1368,1368,1368,136,137,'QAAAAA','GCGAAA','OOOOxx'
+1718,4115,0,2,8,18,18,718,1718,1718,1718,36,37,'COAAAA','HCGAAA','VVVVxx'
+140,4116,0,0,0,0,40,140,140,140,140,80,81,'KFAAAA','ICGAAA','AAAAxx'
+8341,4117,1,1,1,1,41,341,341,3341,8341,82,83,'VIAAAA','JCGAAA','HHHHxx'
+72,4118,0,0,2,12,72,72,72,72,72,144,145,'UCAAAA','KCGAAA','OOOOxx'
+6589,4119,1,1,9,9,89,589,589,1589,6589,178,179,'LTAAAA','LCGAAA','VVVVxx'
+2024,4120,0,0,4,4,24,24,24,2024,2024,48,49,'WZAAAA','MCGAAA','AAAAxx'
+8024,4121,0,0,4,4,24,24,24,3024,8024,48,49,'QWAAAA','NCGAAA','HHHHxx'
+9564,4122,0,0,4,4,64,564,1564,4564,9564,128,129,'WDAAAA','OCGAAA','OOOOxx'
+8625,4123,1,1,5,5,25,625,625,3625,8625,50,51,'TTAAAA','PCGAAA','VVVVxx'
+2680,4124,0,0,0,0,80,680,680,2680,2680,160,161,'CZAAAA','QCGAAA','AAAAxx'
+4323,4125,1,3,3,3,23,323,323,4323,4323,46,47,'HKAAAA','RCGAAA','HHHHxx'
+8981,4126,1,1,1,1,81,981,981,3981,8981,162,163,'LHAAAA','SCGAAA','OOOOxx'
+8909,4127,1,1,9,9,9,909,909,3909,8909,18,19,'REAAAA','TCGAAA','VVVVxx'
+5288,4128,0,0,8,8,88,288,1288,288,5288,176,177,'KVAAAA','UCGAAA','AAAAxx'
+2057,4129,1,1,7,17,57,57,57,2057,2057,114,115,'DBAAAA','VCGAAA','HHHHxx'
+5931,4130,1,3,1,11,31,931,1931,931,5931,62,63,'DUAAAA','WCGAAA','OOOOxx'
+9794,4131,0,2,4,14,94,794,1794,4794,9794,188,189,'SMAAAA','XCGAAA','VVVVxx'
+1012,4132,0,0,2,12,12,12,1012,1012,1012,24,25,'YMAAAA','YCGAAA','AAAAxx'
+5496,4133,0,0,6,16,96,496,1496,496,5496,192,193,'KDAAAA','ZCGAAA','HHHHxx'
+9182,4134,0,2,2,2,82,182,1182,4182,9182,164,165,'EPAAAA','ADGAAA','OOOOxx'
+5258,4135,0,2,8,18,58,258,1258,258,5258,116,117,'GUAAAA','BDGAAA','VVVVxx'
+3050,4136,0,2,0,10,50,50,1050,3050,3050,100,101,'INAAAA','CDGAAA','AAAAxx'
+2083,4137,1,3,3,3,83,83,83,2083,2083,166,167,'DCAAAA','DDGAAA','HHHHxx'
+3069,4138,1,1,9,9,69,69,1069,3069,3069,138,139,'BOAAAA','EDGAAA','OOOOxx'
+8459,4139,1,3,9,19,59,459,459,3459,8459,118,119,'JNAAAA','FDGAAA','VVVVxx'
+169,4140,1,1,9,9,69,169,169,169,169,138,139,'NGAAAA','GDGAAA','AAAAxx'
+4379,4141,1,3,9,19,79,379,379,4379,4379,158,159,'LMAAAA','HDGAAA','HHHHxx'
+5126,4142,0,2,6,6,26,126,1126,126,5126,52,53,'EPAAAA','IDGAAA','OOOOxx'
+1415,4143,1,3,5,15,15,415,1415,1415,1415,30,31,'LCAAAA','JDGAAA','VVVVxx'
+1163,4144,1,3,3,3,63,163,1163,1163,1163,126,127,'TSAAAA','KDGAAA','AAAAxx'
+3500,4145,0,0,0,0,0,500,1500,3500,3500,0,1,'QEAAAA','LDGAAA','HHHHxx'
+7202,4146,0,2,2,2,2,202,1202,2202,7202,4,5,'ARAAAA','MDGAAA','OOOOxx'
+747,4147,1,3,7,7,47,747,747,747,747,94,95,'TCAAAA','NDGAAA','VVVVxx'
+9264,4148,0,0,4,4,64,264,1264,4264,9264,128,129,'ISAAAA','ODGAAA','AAAAxx'
+8548,4149,0,0,8,8,48,548,548,3548,8548,96,97,'UQAAAA','PDGAAA','HHHHxx'
+4228,4150,0,0,8,8,28,228,228,4228,4228,56,57,'QGAAAA','QDGAAA','OOOOxx'
+7122,4151,0,2,2,2,22,122,1122,2122,7122,44,45,'YNAAAA','RDGAAA','VVVVxx'
+3395,4152,1,3,5,15,95,395,1395,3395,3395,190,191,'PAAAAA','SDGAAA','AAAAxx'
+5674,4153,0,2,4,14,74,674,1674,674,5674,148,149,'GKAAAA','TDGAAA','HHHHxx'
+7293,4154,1,1,3,13,93,293,1293,2293,7293,186,187,'NUAAAA','UDGAAA','OOOOxx'
+737,4155,1,1,7,17,37,737,737,737,737,74,75,'JCAAAA','VDGAAA','VVVVxx'
+9595,4156,1,3,5,15,95,595,1595,4595,9595,190,191,'BFAAAA','WDGAAA','AAAAxx'
+594,4157,0,2,4,14,94,594,594,594,594,188,189,'WWAAAA','XDGAAA','HHHHxx'
+5322,4158,0,2,2,2,22,322,1322,322,5322,44,45,'SWAAAA','YDGAAA','OOOOxx'
+2933,4159,1,1,3,13,33,933,933,2933,2933,66,67,'VIAAAA','ZDGAAA','VVVVxx'
+4955,4160,1,3,5,15,55,955,955,4955,4955,110,111,'PIAAAA','AEGAAA','AAAAxx'
+4073,4161,1,1,3,13,73,73,73,4073,4073,146,147,'RAAAAA','BEGAAA','HHHHxx'
+7249,4162,1,1,9,9,49,249,1249,2249,7249,98,99,'VSAAAA','CEGAAA','OOOOxx'
+192,4163,0,0,2,12,92,192,192,192,192,184,185,'KHAAAA','DEGAAA','VVVVxx'
+2617,4164,1,1,7,17,17,617,617,2617,2617,34,35,'RWAAAA','EEGAAA','AAAAxx'
+7409,4165,1,1,9,9,9,409,1409,2409,7409,18,19,'ZYAAAA','FEGAAA','HHHHxx'
+4903,4166,1,3,3,3,3,903,903,4903,4903,6,7,'PGAAAA','GEGAAA','OOOOxx'
+9797,4167,1,1,7,17,97,797,1797,4797,9797,194,195,'VMAAAA','HEGAAA','VVVVxx'
+9919,4168,1,3,9,19,19,919,1919,4919,9919,38,39,'NRAAAA','IEGAAA','AAAAxx'
+1878,4169,0,2,8,18,78,878,1878,1878,1878,156,157,'GUAAAA','JEGAAA','HHHHxx'
+4851,4170,1,3,1,11,51,851,851,4851,4851,102,103,'PEAAAA','KEGAAA','OOOOxx'
+5514,4171,0,2,4,14,14,514,1514,514,5514,28,29,'CEAAAA','LEGAAA','VVVVxx'
+2582,4172,0,2,2,2,82,582,582,2582,2582,164,165,'IVAAAA','MEGAAA','AAAAxx'
+3564,4173,0,0,4,4,64,564,1564,3564,3564,128,129,'CHAAAA','NEGAAA','HHHHxx'
+7085,4174,1,1,5,5,85,85,1085,2085,7085,170,171,'NMAAAA','OEGAAA','OOOOxx'
+3619,4175,1,3,9,19,19,619,1619,3619,3619,38,39,'FJAAAA','PEGAAA','VVVVxx'
+261,4176,1,1,1,1,61,261,261,261,261,122,123,'BKAAAA','QEGAAA','AAAAxx'
+7338,4177,0,2,8,18,38,338,1338,2338,7338,76,77,'GWAAAA','REGAAA','HHHHxx'
+4251,4178,1,3,1,11,51,251,251,4251,4251,102,103,'NHAAAA','SEGAAA','OOOOxx'
+5360,4179,0,0,0,0,60,360,1360,360,5360,120,121,'EYAAAA','TEGAAA','VVVVxx'
+5678,4180,0,2,8,18,78,678,1678,678,5678,156,157,'KKAAAA','UEGAAA','AAAAxx'
+9162,4181,0,2,2,2,62,162,1162,4162,9162,124,125,'KOAAAA','VEGAAA','HHHHxx'
+5920,4182,0,0,0,0,20,920,1920,920,5920,40,41,'STAAAA','WEGAAA','OOOOxx'
+7156,4183,0,0,6,16,56,156,1156,2156,7156,112,113,'GPAAAA','XEGAAA','VVVVxx'
+4271,4184,1,3,1,11,71,271,271,4271,4271,142,143,'HIAAAA','YEGAAA','AAAAxx'
+4698,4185,0,2,8,18,98,698,698,4698,4698,196,197,'SYAAAA','ZEGAAA','HHHHxx'
+1572,4186,0,0,2,12,72,572,1572,1572,1572,144,145,'MIAAAA','AFGAAA','OOOOxx'
+6974,4187,0,2,4,14,74,974,974,1974,6974,148,149,'GIAAAA','BFGAAA','VVVVxx'
+4291,4188,1,3,1,11,91,291,291,4291,4291,182,183,'BJAAAA','CFGAAA','AAAAxx'
+4036,4189,0,0,6,16,36,36,36,4036,4036,72,73,'GZAAAA','DFGAAA','HHHHxx'
+7473,4190,1,1,3,13,73,473,1473,2473,7473,146,147,'LBAAAA','EFGAAA','OOOOxx'
+4786,4191,0,2,6,6,86,786,786,4786,4786,172,173,'CCAAAA','FFGAAA','VVVVxx'
+2662,4192,0,2,2,2,62,662,662,2662,2662,124,125,'KYAAAA','GFGAAA','AAAAxx'
+916,4193,0,0,6,16,16,916,916,916,916,32,33,'GJAAAA','HFGAAA','HHHHxx'
+668,4194,0,0,8,8,68,668,668,668,668,136,137,'SZAAAA','IFGAAA','OOOOxx'
+4874,4195,0,2,4,14,74,874,874,4874,4874,148,149,'MFAAAA','JFGAAA','VVVVxx'
+3752,4196,0,0,2,12,52,752,1752,3752,3752,104,105,'IOAAAA','KFGAAA','AAAAxx'
+4865,4197,1,1,5,5,65,865,865,4865,4865,130,131,'DFAAAA','LFGAAA','HHHHxx'
+7052,4198,0,0,2,12,52,52,1052,2052,7052,104,105,'GLAAAA','MFGAAA','OOOOxx'
+5712,4199,0,0,2,12,12,712,1712,712,5712,24,25,'SLAAAA','NFGAAA','VVVVxx'
+31,4200,1,3,1,11,31,31,31,31,31,62,63,'FBAAAA','OFGAAA','AAAAxx'
+4944,4201,0,0,4,4,44,944,944,4944,4944,88,89,'EIAAAA','PFGAAA','HHHHxx'
+1435,4202,1,3,5,15,35,435,1435,1435,1435,70,71,'FDAAAA','QFGAAA','OOOOxx'
+501,4203,1,1,1,1,1,501,501,501,501,2,3,'HTAAAA','RFGAAA','VVVVxx'
+9401,4204,1,1,1,1,1,401,1401,4401,9401,2,3,'PXAAAA','SFGAAA','AAAAxx'
+5014,4205,0,2,4,14,14,14,1014,14,5014,28,29,'WKAAAA','TFGAAA','HHHHxx'
+9125,4206,1,1,5,5,25,125,1125,4125,9125,50,51,'ZMAAAA','UFGAAA','OOOOxx'
+6144,4207,0,0,4,4,44,144,144,1144,6144,88,89,'ICAAAA','VFGAAA','VVVVxx'
+1743,4208,1,3,3,3,43,743,1743,1743,1743,86,87,'BPAAAA','WFGAAA','AAAAxx'
+4316,4209,0,0,6,16,16,316,316,4316,4316,32,33,'AKAAAA','XFGAAA','HHHHxx'
+8212,4210,0,0,2,12,12,212,212,3212,8212,24,25,'WDAAAA','YFGAAA','OOOOxx'
+7344,4211,0,0,4,4,44,344,1344,2344,7344,88,89,'MWAAAA','ZFGAAA','VVVVxx'
+2051,4212,1,3,1,11,51,51,51,2051,2051,102,103,'XAAAAA','AGGAAA','AAAAxx'
+8131,4213,1,3,1,11,31,131,131,3131,8131,62,63,'TAAAAA','BGGAAA','HHHHxx'
+7023,4214,1,3,3,3,23,23,1023,2023,7023,46,47,'DKAAAA','CGGAAA','OOOOxx'
+9674,4215,0,2,4,14,74,674,1674,4674,9674,148,149,'CIAAAA','DGGAAA','VVVVxx'
+4984,4216,0,0,4,4,84,984,984,4984,4984,168,169,'SJAAAA','EGGAAA','AAAAxx'
+111,4217,1,3,1,11,11,111,111,111,111,22,23,'HEAAAA','FGGAAA','HHHHxx'
+2296,4218,0,0,6,16,96,296,296,2296,2296,192,193,'IKAAAA','GGGAAA','OOOOxx'
+5025,4219,1,1,5,5,25,25,1025,25,5025,50,51,'HLAAAA','HGGAAA','VVVVxx'
+1756,4220,0,0,6,16,56,756,1756,1756,1756,112,113,'OPAAAA','IGGAAA','AAAAxx'
+2885,4221,1,1,5,5,85,885,885,2885,2885,170,171,'ZGAAAA','JGGAAA','HHHHxx'
+2541,4222,1,1,1,1,41,541,541,2541,2541,82,83,'TTAAAA','KGGAAA','OOOOxx'
+1919,4223,1,3,9,19,19,919,1919,1919,1919,38,39,'VVAAAA','LGGAAA','VVVVxx'
+6496,4224,0,0,6,16,96,496,496,1496,6496,192,193,'WPAAAA','MGGAAA','AAAAxx'
+6103,4225,1,3,3,3,3,103,103,1103,6103,6,7,'TAAAAA','NGGAAA','HHHHxx'
+98,4226,0,2,8,18,98,98,98,98,98,196,197,'UDAAAA','OGGAAA','OOOOxx'
+3727,4227,1,3,7,7,27,727,1727,3727,3727,54,55,'JNAAAA','PGGAAA','VVVVxx'
+689,4228,1,1,9,9,89,689,689,689,689,178,179,'NAAAAA','QGGAAA','AAAAxx'
+7181,4229,1,1,1,1,81,181,1181,2181,7181,162,163,'FQAAAA','RGGAAA','HHHHxx'
+8447,4230,1,3,7,7,47,447,447,3447,8447,94,95,'XMAAAA','SGGAAA','OOOOxx'
+4569,4231,1,1,9,9,69,569,569,4569,4569,138,139,'TTAAAA','TGGAAA','VVVVxx'
+8844,4232,0,0,4,4,44,844,844,3844,8844,88,89,'ECAAAA','UGGAAA','AAAAxx'
+2436,4233,0,0,6,16,36,436,436,2436,2436,72,73,'SPAAAA','VGGAAA','HHHHxx'
+391,4234,1,3,1,11,91,391,391,391,391,182,183,'BPAAAA','WGGAAA','OOOOxx'
+3035,4235,1,3,5,15,35,35,1035,3035,3035,70,71,'TMAAAA','XGGAAA','VVVVxx'
+7583,4236,1,3,3,3,83,583,1583,2583,7583,166,167,'RFAAAA','YGGAAA','AAAAxx'
+1145,4237,1,1,5,5,45,145,1145,1145,1145,90,91,'BSAAAA','ZGGAAA','HHHHxx'
+93,4238,1,1,3,13,93,93,93,93,93,186,187,'PDAAAA','AHGAAA','OOOOxx'
+8896,4239,0,0,6,16,96,896,896,3896,8896,192,193,'EEAAAA','BHGAAA','VVVVxx'
+6719,4240,1,3,9,19,19,719,719,1719,6719,38,39,'LYAAAA','CHGAAA','AAAAxx'
+7728,4241,0,0,8,8,28,728,1728,2728,7728,56,57,'GLAAAA','DHGAAA','HHHHxx'
+1349,4242,1,1,9,9,49,349,1349,1349,1349,98,99,'XZAAAA','EHGAAA','OOOOxx'
+5349,4243,1,1,9,9,49,349,1349,349,5349,98,99,'TXAAAA','FHGAAA','VVVVxx'
+3040,4244,0,0,0,0,40,40,1040,3040,3040,80,81,'YMAAAA','GHGAAA','AAAAxx'
+2414,4245,0,2,4,14,14,414,414,2414,2414,28,29,'WOAAAA','HHGAAA','HHHHxx'
+5122,4246,0,2,2,2,22,122,1122,122,5122,44,45,'APAAAA','IHGAAA','OOOOxx'
+9553,4247,1,1,3,13,53,553,1553,4553,9553,106,107,'LDAAAA','JHGAAA','VVVVxx'
+5987,4248,1,3,7,7,87,987,1987,987,5987,174,175,'HWAAAA','KHGAAA','AAAAxx'
+5939,4249,1,3,9,19,39,939,1939,939,5939,78,79,'LUAAAA','LHGAAA','HHHHxx'
+3525,4250,1,1,5,5,25,525,1525,3525,3525,50,51,'PFAAAA','MHGAAA','OOOOxx'
+1371,4251,1,3,1,11,71,371,1371,1371,1371,142,143,'TAAAAA','NHGAAA','VVVVxx'
+618,4252,0,2,8,18,18,618,618,618,618,36,37,'UXAAAA','OHGAAA','AAAAxx'
+6529,4253,1,1,9,9,29,529,529,1529,6529,58,59,'DRAAAA','PHGAAA','HHHHxx'
+4010,4254,0,2,0,10,10,10,10,4010,4010,20,21,'GYAAAA','QHGAAA','OOOOxx'
+328,4255,0,0,8,8,28,328,328,328,328,56,57,'QMAAAA','RHGAAA','VVVVxx'
+6121,4256,1,1,1,1,21,121,121,1121,6121,42,43,'LBAAAA','SHGAAA','AAAAxx'
+3505,4257,1,1,5,5,5,505,1505,3505,3505,10,11,'VEAAAA','THGAAA','HHHHxx'
+2033,4258,1,1,3,13,33,33,33,2033,2033,66,67,'FAAAAA','UHGAAA','OOOOxx'
+4724,4259,0,0,4,4,24,724,724,4724,4724,48,49,'SZAAAA','VHGAAA','VVVVxx'
+8717,4260,1,1,7,17,17,717,717,3717,8717,34,35,'HXAAAA','WHGAAA','AAAAxx'
+5639,4261,1,3,9,19,39,639,1639,639,5639,78,79,'XIAAAA','XHGAAA','HHHHxx'
+3448,4262,0,0,8,8,48,448,1448,3448,3448,96,97,'QCAAAA','YHGAAA','OOOOxx'
+2919,4263,1,3,9,19,19,919,919,2919,2919,38,39,'HIAAAA','ZHGAAA','VVVVxx'
+3417,4264,1,1,7,17,17,417,1417,3417,3417,34,35,'LBAAAA','AIGAAA','AAAAxx'
+943,4265,1,3,3,3,43,943,943,943,943,86,87,'HKAAAA','BIGAAA','HHHHxx'
+775,4266,1,3,5,15,75,775,775,775,775,150,151,'VDAAAA','CIGAAA','OOOOxx'
+2333,4267,1,1,3,13,33,333,333,2333,2333,66,67,'TLAAAA','DIGAAA','VVVVxx'
+4801,4268,1,1,1,1,1,801,801,4801,4801,2,3,'RCAAAA','EIGAAA','AAAAxx'
+7169,4269,1,1,9,9,69,169,1169,2169,7169,138,139,'TPAAAA','FIGAAA','HHHHxx'
+2840,4270,0,0,0,0,40,840,840,2840,2840,80,81,'GFAAAA','GIGAAA','OOOOxx'
+9034,4271,0,2,4,14,34,34,1034,4034,9034,68,69,'MJAAAA','HIGAAA','VVVVxx'
+6154,4272,0,2,4,14,54,154,154,1154,6154,108,109,'SCAAAA','IIGAAA','AAAAxx'
+1412,4273,0,0,2,12,12,412,1412,1412,1412,24,25,'ICAAAA','JIGAAA','HHHHxx'
+2263,4274,1,3,3,3,63,263,263,2263,2263,126,127,'BJAAAA','KIGAAA','OOOOxx'
+7118,4275,0,2,8,18,18,118,1118,2118,7118,36,37,'UNAAAA','LIGAAA','VVVVxx'
+1526,4276,0,2,6,6,26,526,1526,1526,1526,52,53,'SGAAAA','MIGAAA','AAAAxx'
+491,4277,1,3,1,11,91,491,491,491,491,182,183,'XSAAAA','NIGAAA','HHHHxx'
+9732,4278,0,0,2,12,32,732,1732,4732,9732,64,65,'IKAAAA','OIGAAA','OOOOxx'
+7067,4279,1,3,7,7,67,67,1067,2067,7067,134,135,'VLAAAA','PIGAAA','VVVVxx'
+212,4280,0,0,2,12,12,212,212,212,212,24,25,'EIAAAA','QIGAAA','AAAAxx'
+1955,4281,1,3,5,15,55,955,1955,1955,1955,110,111,'FXAAAA','RIGAAA','HHHHxx'
+3303,4282,1,3,3,3,3,303,1303,3303,3303,6,7,'BXAAAA','SIGAAA','OOOOxx'
+2715,4283,1,3,5,15,15,715,715,2715,2715,30,31,'LAAAAA','TIGAAA','VVVVxx'
+8168,4284,0,0,8,8,68,168,168,3168,8168,136,137,'ECAAAA','UIGAAA','AAAAxx'
+6799,4285,1,3,9,19,99,799,799,1799,6799,198,199,'NBAAAA','VIGAAA','HHHHxx'
+5080,4286,0,0,0,0,80,80,1080,80,5080,160,161,'KNAAAA','WIGAAA','OOOOxx'
+4939,4287,1,3,9,19,39,939,939,4939,4939,78,79,'ZHAAAA','XIGAAA','VVVVxx'
+6604,4288,0,0,4,4,4,604,604,1604,6604,8,9,'AUAAAA','YIGAAA','AAAAxx'
+6531,4289,1,3,1,11,31,531,531,1531,6531,62,63,'FRAAAA','ZIGAAA','HHHHxx'
+9948,4290,0,0,8,8,48,948,1948,4948,9948,96,97,'QSAAAA','AJGAAA','OOOOxx'
+7923,4291,1,3,3,3,23,923,1923,2923,7923,46,47,'TSAAAA','BJGAAA','VVVVxx'
+9905,4292,1,1,5,5,5,905,1905,4905,9905,10,11,'ZQAAAA','CJGAAA','AAAAxx'
+340,4293,0,0,0,0,40,340,340,340,340,80,81,'CNAAAA','DJGAAA','HHHHxx'
+1721,4294,1,1,1,1,21,721,1721,1721,1721,42,43,'FOAAAA','EJGAAA','OOOOxx'
+9047,4295,1,3,7,7,47,47,1047,4047,9047,94,95,'ZJAAAA','FJGAAA','VVVVxx'
+4723,4296,1,3,3,3,23,723,723,4723,4723,46,47,'RZAAAA','GJGAAA','AAAAxx'
+5748,4297,0,0,8,8,48,748,1748,748,5748,96,97,'CNAAAA','HJGAAA','HHHHxx'
+6845,4298,1,1,5,5,45,845,845,1845,6845,90,91,'HDAAAA','IJGAAA','OOOOxx'
+1556,4299,0,0,6,16,56,556,1556,1556,1556,112,113,'WHAAAA','JJGAAA','VVVVxx'
+9505,4300,1,1,5,5,5,505,1505,4505,9505,10,11,'PBAAAA','KJGAAA','AAAAxx'
+3573,4301,1,1,3,13,73,573,1573,3573,3573,146,147,'LHAAAA','LJGAAA','HHHHxx'
+3785,4302,1,1,5,5,85,785,1785,3785,3785,170,171,'PPAAAA','MJGAAA','OOOOxx'
+2772,4303,0,0,2,12,72,772,772,2772,2772,144,145,'QCAAAA','NJGAAA','VVVVxx'
+7282,4304,0,2,2,2,82,282,1282,2282,7282,164,165,'CUAAAA','OJGAAA','AAAAxx'
+8106,4305,0,2,6,6,6,106,106,3106,8106,12,13,'UZAAAA','PJGAAA','HHHHxx'
+2847,4306,1,3,7,7,47,847,847,2847,2847,94,95,'NFAAAA','QJGAAA','OOOOxx'
+9803,4307,1,3,3,3,3,803,1803,4803,9803,6,7,'BNAAAA','RJGAAA','VVVVxx'
+7719,4308,1,3,9,19,19,719,1719,2719,7719,38,39,'XKAAAA','SJGAAA','AAAAxx'
+4649,4309,1,1,9,9,49,649,649,4649,4649,98,99,'VWAAAA','TJGAAA','HHHHxx'
+6196,4310,0,0,6,16,96,196,196,1196,6196,192,193,'IEAAAA','UJGAAA','OOOOxx'
+6026,4311,0,2,6,6,26,26,26,1026,6026,52,53,'UXAAAA','VJGAAA','VVVVxx'
+1646,4312,0,2,6,6,46,646,1646,1646,1646,92,93,'ILAAAA','WJGAAA','AAAAxx'
+6526,4313,0,2,6,6,26,526,526,1526,6526,52,53,'ARAAAA','XJGAAA','HHHHxx'
+5110,4314,0,2,0,10,10,110,1110,110,5110,20,21,'OOAAAA','YJGAAA','OOOOxx'
+3946,4315,0,2,6,6,46,946,1946,3946,3946,92,93,'UVAAAA','ZJGAAA','VVVVxx'
+445,4316,1,1,5,5,45,445,445,445,445,90,91,'DRAAAA','AKGAAA','AAAAxx'
+3249,4317,1,1,9,9,49,249,1249,3249,3249,98,99,'ZUAAAA','BKGAAA','HHHHxx'
+2501,4318,1,1,1,1,1,501,501,2501,2501,2,3,'FSAAAA','CKGAAA','OOOOxx'
+3243,4319,1,3,3,3,43,243,1243,3243,3243,86,87,'TUAAAA','DKGAAA','VVVVxx'
+4701,4320,1,1,1,1,1,701,701,4701,4701,2,3,'VYAAAA','EKGAAA','AAAAxx'
+472,4321,0,0,2,12,72,472,472,472,472,144,145,'ESAAAA','FKGAAA','HHHHxx'
+3356,4322,0,0,6,16,56,356,1356,3356,3356,112,113,'CZAAAA','GKGAAA','OOOOxx'
+9967,4323,1,3,7,7,67,967,1967,4967,9967,134,135,'JTAAAA','HKGAAA','VVVVxx'
+4292,4324,0,0,2,12,92,292,292,4292,4292,184,185,'CJAAAA','IKGAAA','AAAAxx'
+7005,4325,1,1,5,5,5,5,1005,2005,7005,10,11,'LJAAAA','JKGAAA','HHHHxx'
+6267,4326,1,3,7,7,67,267,267,1267,6267,134,135,'BHAAAA','KKGAAA','OOOOxx'
+6678,4327,0,2,8,18,78,678,678,1678,6678,156,157,'WWAAAA','LKGAAA','VVVVxx'
+6083,4328,1,3,3,3,83,83,83,1083,6083,166,167,'ZZAAAA','MKGAAA','AAAAxx'
+760,4329,0,0,0,0,60,760,760,760,760,120,121,'GDAAAA','NKGAAA','HHHHxx'
+7833,4330,1,1,3,13,33,833,1833,2833,7833,66,67,'HPAAAA','OKGAAA','OOOOxx'
+2877,4331,1,1,7,17,77,877,877,2877,2877,154,155,'RGAAAA','PKGAAA','VVVVxx'
+8810,4332,0,2,0,10,10,810,810,3810,8810,20,21,'WAAAAA','QKGAAA','AAAAxx'
+1560,4333,0,0,0,0,60,560,1560,1560,1560,120,121,'AIAAAA','RKGAAA','HHHHxx'
+1367,4334,1,3,7,7,67,367,1367,1367,1367,134,135,'PAAAAA','SKGAAA','OOOOxx'
+8756,4335,0,0,6,16,56,756,756,3756,8756,112,113,'UYAAAA','TKGAAA','VVVVxx'
+1346,4336,0,2,6,6,46,346,1346,1346,1346,92,93,'UZAAAA','UKGAAA','AAAAxx'
+6449,4337,1,1,9,9,49,449,449,1449,6449,98,99,'BOAAAA','VKGAAA','HHHHxx'
+6658,4338,0,2,8,18,58,658,658,1658,6658,116,117,'CWAAAA','WKGAAA','OOOOxx'
+6745,4339,1,1,5,5,45,745,745,1745,6745,90,91,'LZAAAA','XKGAAA','VVVVxx'
+4866,4340,0,2,6,6,66,866,866,4866,4866,132,133,'EFAAAA','YKGAAA','AAAAxx'
+14,4341,0,2,4,14,14,14,14,14,14,28,29,'OAAAAA','ZKGAAA','HHHHxx'
+4506,4342,0,2,6,6,6,506,506,4506,4506,12,13,'IRAAAA','ALGAAA','OOOOxx'
+1923,4343,1,3,3,3,23,923,1923,1923,1923,46,47,'ZVAAAA','BLGAAA','VVVVxx'
+8365,4344,1,1,5,5,65,365,365,3365,8365,130,131,'TJAAAA','CLGAAA','AAAAxx'
+1279,4345,1,3,9,19,79,279,1279,1279,1279,158,159,'FXAAAA','DLGAAA','HHHHxx'
+7666,4346,0,2,6,6,66,666,1666,2666,7666,132,133,'WIAAAA','ELGAAA','OOOOxx'
+7404,4347,0,0,4,4,4,404,1404,2404,7404,8,9,'UYAAAA','FLGAAA','VVVVxx'
+65,4348,1,1,5,5,65,65,65,65,65,130,131,'NCAAAA','GLGAAA','AAAAxx'
+5820,4349,0,0,0,0,20,820,1820,820,5820,40,41,'WPAAAA','HLGAAA','HHHHxx'
+459,4350,1,3,9,19,59,459,459,459,459,118,119,'RRAAAA','ILGAAA','OOOOxx'
+4787,4351,1,3,7,7,87,787,787,4787,4787,174,175,'DCAAAA','JLGAAA','VVVVxx'
+5631,4352,1,3,1,11,31,631,1631,631,5631,62,63,'PIAAAA','KLGAAA','AAAAxx'
+9717,4353,1,1,7,17,17,717,1717,4717,9717,34,35,'TJAAAA','LLGAAA','HHHHxx'
+2560,4354,0,0,0,0,60,560,560,2560,2560,120,121,'MUAAAA','MLGAAA','OOOOxx'
+8295,4355,1,3,5,15,95,295,295,3295,8295,190,191,'BHAAAA','NLGAAA','VVVVxx'
+3596,4356,0,0,6,16,96,596,1596,3596,3596,192,193,'IIAAAA','OLGAAA','AAAAxx'
+2023,4357,1,3,3,3,23,23,23,2023,2023,46,47,'VZAAAA','PLGAAA','HHHHxx'
+5055,4358,1,3,5,15,55,55,1055,55,5055,110,111,'LMAAAA','QLGAAA','OOOOxx'
+763,4359,1,3,3,3,63,763,763,763,763,126,127,'JDAAAA','RLGAAA','VVVVxx'
+6733,4360,1,1,3,13,33,733,733,1733,6733,66,67,'ZYAAAA','SLGAAA','AAAAxx'
+9266,4361,0,2,6,6,66,266,1266,4266,9266,132,133,'KSAAAA','TLGAAA','HHHHxx'
+4479,4362,1,3,9,19,79,479,479,4479,4479,158,159,'HQAAAA','ULGAAA','OOOOxx'
+1816,4363,0,0,6,16,16,816,1816,1816,1816,32,33,'WRAAAA','VLGAAA','VVVVxx'
+899,4364,1,3,9,19,99,899,899,899,899,198,199,'PIAAAA','WLGAAA','AAAAxx'
+230,4365,0,2,0,10,30,230,230,230,230,60,61,'WIAAAA','XLGAAA','HHHHxx'
+5362,4366,0,2,2,2,62,362,1362,362,5362,124,125,'GYAAAA','YLGAAA','OOOOxx'
+1609,4367,1,1,9,9,9,609,1609,1609,1609,18,19,'XJAAAA','ZLGAAA','VVVVxx'
+6750,4368,0,2,0,10,50,750,750,1750,6750,100,101,'QZAAAA','AMGAAA','AAAAxx'
+9704,4369,0,0,4,4,4,704,1704,4704,9704,8,9,'GJAAAA','BMGAAA','HHHHxx'
+3991,4370,1,3,1,11,91,991,1991,3991,3991,182,183,'NXAAAA','CMGAAA','OOOOxx'
+3959,4371,1,3,9,19,59,959,1959,3959,3959,118,119,'HWAAAA','DMGAAA','VVVVxx'
+9021,4372,1,1,1,1,21,21,1021,4021,9021,42,43,'ZIAAAA','EMGAAA','AAAAxx'
+7585,4373,1,1,5,5,85,585,1585,2585,7585,170,171,'TFAAAA','FMGAAA','HHHHxx'
+7083,4374,1,3,3,3,83,83,1083,2083,7083,166,167,'LMAAAA','GMGAAA','OOOOxx'
+7688,4375,0,0,8,8,88,688,1688,2688,7688,176,177,'SJAAAA','HMGAAA','VVVVxx'
+2673,4376,1,1,3,13,73,673,673,2673,2673,146,147,'VYAAAA','IMGAAA','AAAAxx'
+3554,4377,0,2,4,14,54,554,1554,3554,3554,108,109,'SGAAAA','JMGAAA','HHHHxx'
+7416,4378,0,0,6,16,16,416,1416,2416,7416,32,33,'GZAAAA','KMGAAA','OOOOxx'
+5672,4379,0,0,2,12,72,672,1672,672,5672,144,145,'EKAAAA','LMGAAA','VVVVxx'
+1355,4380,1,3,5,15,55,355,1355,1355,1355,110,111,'DAAAAA','MMGAAA','AAAAxx'
+3149,4381,1,1,9,9,49,149,1149,3149,3149,98,99,'DRAAAA','NMGAAA','HHHHxx'
+5811,4382,1,3,1,11,11,811,1811,811,5811,22,23,'NPAAAA','OMGAAA','OOOOxx'
+3759,4383,1,3,9,19,59,759,1759,3759,3759,118,119,'POAAAA','PMGAAA','VVVVxx'
+5634,4384,0,2,4,14,34,634,1634,634,5634,68,69,'SIAAAA','QMGAAA','AAAAxx'
+8617,4385,1,1,7,17,17,617,617,3617,8617,34,35,'LTAAAA','RMGAAA','HHHHxx'
+8949,4386,1,1,9,9,49,949,949,3949,8949,98,99,'FGAAAA','SMGAAA','OOOOxx'
+3964,4387,0,0,4,4,64,964,1964,3964,3964,128,129,'MWAAAA','TMGAAA','VVVVxx'
+3852,4388,0,0,2,12,52,852,1852,3852,3852,104,105,'ESAAAA','UMGAAA','AAAAxx'
+1555,4389,1,3,5,15,55,555,1555,1555,1555,110,111,'VHAAAA','VMGAAA','HHHHxx'
+6536,4390,0,0,6,16,36,536,536,1536,6536,72,73,'KRAAAA','WMGAAA','OOOOxx'
+4779,4391,1,3,9,19,79,779,779,4779,4779,158,159,'VBAAAA','XMGAAA','VVVVxx'
+1893,4392,1,1,3,13,93,893,1893,1893,1893,186,187,'VUAAAA','YMGAAA','AAAAxx'
+9358,4393,0,2,8,18,58,358,1358,4358,9358,116,117,'YVAAAA','ZMGAAA','HHHHxx'
+7438,4394,0,2,8,18,38,438,1438,2438,7438,76,77,'CAAAAA','ANGAAA','OOOOxx'
+941,4395,1,1,1,1,41,941,941,941,941,82,83,'FKAAAA','BNGAAA','VVVVxx'
+4844,4396,0,0,4,4,44,844,844,4844,4844,88,89,'IEAAAA','CNGAAA','AAAAxx'
+4745,4397,1,1,5,5,45,745,745,4745,4745,90,91,'NAAAAA','DNGAAA','HHHHxx'
+1017,4398,1,1,7,17,17,17,1017,1017,1017,34,35,'DNAAAA','ENGAAA','OOOOxx'
+327,4399,1,3,7,7,27,327,327,327,327,54,55,'PMAAAA','FNGAAA','VVVVxx'
+3152,4400,0,0,2,12,52,152,1152,3152,3152,104,105,'GRAAAA','GNGAAA','AAAAxx'
+4711,4401,1,3,1,11,11,711,711,4711,4711,22,23,'FZAAAA','HNGAAA','HHHHxx'
+141,4402,1,1,1,1,41,141,141,141,141,82,83,'LFAAAA','INGAAA','OOOOxx'
+1303,4403,1,3,3,3,3,303,1303,1303,1303,6,7,'DYAAAA','JNGAAA','VVVVxx'
+8873,4404,1,1,3,13,73,873,873,3873,8873,146,147,'HDAAAA','KNGAAA','AAAAxx'
+8481,4405,1,1,1,1,81,481,481,3481,8481,162,163,'FOAAAA','LNGAAA','HHHHxx'
+5445,4406,1,1,5,5,45,445,1445,445,5445,90,91,'LBAAAA','MNGAAA','OOOOxx'
+7868,4407,0,0,8,8,68,868,1868,2868,7868,136,137,'QQAAAA','NNGAAA','VVVVxx'
+6722,4408,0,2,2,2,22,722,722,1722,6722,44,45,'OYAAAA','ONGAAA','AAAAxx'
+6628,4409,0,0,8,8,28,628,628,1628,6628,56,57,'YUAAAA','PNGAAA','HHHHxx'
+7738,4410,0,2,8,18,38,738,1738,2738,7738,76,77,'QLAAAA','QNGAAA','OOOOxx'
+1018,4411,0,2,8,18,18,18,1018,1018,1018,36,37,'ENAAAA','RNGAAA','VVVVxx'
+3296,4412,0,0,6,16,96,296,1296,3296,3296,192,193,'UWAAAA','SNGAAA','AAAAxx'
+1946,4413,0,2,6,6,46,946,1946,1946,1946,92,93,'WWAAAA','TNGAAA','HHHHxx'
+6603,4414,1,3,3,3,3,603,603,1603,6603,6,7,'ZTAAAA','UNGAAA','OOOOxx'
+3562,4415,0,2,2,2,62,562,1562,3562,3562,124,125,'AHAAAA','VNGAAA','VVVVxx'
+1147,4416,1,3,7,7,47,147,1147,1147,1147,94,95,'DSAAAA','WNGAAA','AAAAxx'
+6031,4417,1,3,1,11,31,31,31,1031,6031,62,63,'ZXAAAA','XNGAAA','HHHHxx'
+6484,4418,0,0,4,4,84,484,484,1484,6484,168,169,'KPAAAA','YNGAAA','OOOOxx'
+496,4419,0,0,6,16,96,496,496,496,496,192,193,'CTAAAA','ZNGAAA','VVVVxx'
+4563,4420,1,3,3,3,63,563,563,4563,4563,126,127,'NTAAAA','AOGAAA','AAAAxx'
+1037,4421,1,1,7,17,37,37,1037,1037,1037,74,75,'XNAAAA','BOGAAA','HHHHxx'
+9672,4422,0,0,2,12,72,672,1672,4672,9672,144,145,'AIAAAA','COGAAA','OOOOxx'
+9053,4423,1,1,3,13,53,53,1053,4053,9053,106,107,'FKAAAA','DOGAAA','VVVVxx'
+2523,4424,1,3,3,3,23,523,523,2523,2523,46,47,'BTAAAA','EOGAAA','AAAAxx'
+8519,4425,1,3,9,19,19,519,519,3519,8519,38,39,'RPAAAA','FOGAAA','HHHHxx'
+8190,4426,0,2,0,10,90,190,190,3190,8190,180,181,'ADAAAA','GOGAAA','OOOOxx'
+2068,4427,0,0,8,8,68,68,68,2068,2068,136,137,'OBAAAA','HOGAAA','VVVVxx'
+8569,4428,1,1,9,9,69,569,569,3569,8569,138,139,'PRAAAA','IOGAAA','AAAAxx'
+6535,4429,1,3,5,15,35,535,535,1535,6535,70,71,'JRAAAA','JOGAAA','HHHHxx'
+1810,4430,0,2,0,10,10,810,1810,1810,1810,20,21,'QRAAAA','KOGAAA','OOOOxx'
+3099,4431,1,3,9,19,99,99,1099,3099,3099,198,199,'FPAAAA','LOGAAA','VVVVxx'
+7466,4432,0,2,6,6,66,466,1466,2466,7466,132,133,'EBAAAA','MOGAAA','AAAAxx'
+4017,4433,1,1,7,17,17,17,17,4017,4017,34,35,'NYAAAA','NOGAAA','HHHHxx'
+1097,4434,1,1,7,17,97,97,1097,1097,1097,194,195,'FQAAAA','OOGAAA','OOOOxx'
+7686,4435,0,2,6,6,86,686,1686,2686,7686,172,173,'QJAAAA','POGAAA','VVVVxx'
+6742,4436,0,2,2,2,42,742,742,1742,6742,84,85,'IZAAAA','QOGAAA','AAAAxx'
+5966,4437,0,2,6,6,66,966,1966,966,5966,132,133,'MVAAAA','ROGAAA','HHHHxx'
+3632,4438,0,0,2,12,32,632,1632,3632,3632,64,65,'SJAAAA','SOGAAA','OOOOxx'
+8837,4439,1,1,7,17,37,837,837,3837,8837,74,75,'XBAAAA','TOGAAA','VVVVxx'
+1667,4440,1,3,7,7,67,667,1667,1667,1667,134,135,'DMAAAA','UOGAAA','AAAAxx'
+8833,4441,1,1,3,13,33,833,833,3833,8833,66,67,'TBAAAA','VOGAAA','HHHHxx'
+9805,4442,1,1,5,5,5,805,1805,4805,9805,10,11,'DNAAAA','WOGAAA','OOOOxx'
+3650,4443,0,2,0,10,50,650,1650,3650,3650,100,101,'KKAAAA','XOGAAA','VVVVxx'
+2237,4444,1,1,7,17,37,237,237,2237,2237,74,75,'BIAAAA','YOGAAA','AAAAxx'
+9980,4445,0,0,0,0,80,980,1980,4980,9980,160,161,'WTAAAA','ZOGAAA','HHHHxx'
+2861,4446,1,1,1,1,61,861,861,2861,2861,122,123,'BGAAAA','APGAAA','OOOOxx'
+1334,4447,0,2,4,14,34,334,1334,1334,1334,68,69,'IZAAAA','BPGAAA','VVVVxx'
+842,4448,0,2,2,2,42,842,842,842,842,84,85,'KGAAAA','CPGAAA','AAAAxx'
+1116,4449,0,0,6,16,16,116,1116,1116,1116,32,33,'YQAAAA','DPGAAA','HHHHxx'
+4055,4450,1,3,5,15,55,55,55,4055,4055,110,111,'ZZAAAA','EPGAAA','OOOOxx'
+3842,4451,0,2,2,2,42,842,1842,3842,3842,84,85,'URAAAA','FPGAAA','VVVVxx'
+1886,4452,0,2,6,6,86,886,1886,1886,1886,172,173,'OUAAAA','GPGAAA','AAAAxx'
+8589,4453,1,1,9,9,89,589,589,3589,8589,178,179,'JSAAAA','HPGAAA','HHHHxx'
+5873,4454,1,1,3,13,73,873,1873,873,5873,146,147,'XRAAAA','IPGAAA','OOOOxx'
+7711,4455,1,3,1,11,11,711,1711,2711,7711,22,23,'PKAAAA','JPGAAA','VVVVxx'
+911,4456,1,3,1,11,11,911,911,911,911,22,23,'BJAAAA','KPGAAA','AAAAxx'
+5837,4457,1,1,7,17,37,837,1837,837,5837,74,75,'NQAAAA','LPGAAA','HHHHxx'
+897,4458,1,1,7,17,97,897,897,897,897,194,195,'NIAAAA','MPGAAA','OOOOxx'
+4299,4459,1,3,9,19,99,299,299,4299,4299,198,199,'JJAAAA','NPGAAA','VVVVxx'
+7774,4460,0,2,4,14,74,774,1774,2774,7774,148,149,'ANAAAA','OPGAAA','AAAAxx'
+7832,4461,0,0,2,12,32,832,1832,2832,7832,64,65,'GPAAAA','PPGAAA','HHHHxx'
+9915,4462,1,3,5,15,15,915,1915,4915,9915,30,31,'JRAAAA','QPGAAA','OOOOxx'
+9,4463,1,1,9,9,9,9,9,9,9,18,19,'JAAAAA','RPGAAA','VVVVxx'
+9675,4464,1,3,5,15,75,675,1675,4675,9675,150,151,'DIAAAA','SPGAAA','AAAAxx'
+7953,4465,1,1,3,13,53,953,1953,2953,7953,106,107,'XTAAAA','TPGAAA','HHHHxx'
+8912,4466,0,0,2,12,12,912,912,3912,8912,24,25,'UEAAAA','UPGAAA','OOOOxx'
+4188,4467,0,0,8,8,88,188,188,4188,4188,176,177,'CFAAAA','VPGAAA','VVVVxx'
+8446,4468,0,2,6,6,46,446,446,3446,8446,92,93,'WMAAAA','WPGAAA','AAAAxx'
+1600,4469,0,0,0,0,0,600,1600,1600,1600,0,1,'OJAAAA','XPGAAA','HHHHxx'
+43,4470,1,3,3,3,43,43,43,43,43,86,87,'RBAAAA','YPGAAA','OOOOxx'
+544,4471,0,0,4,4,44,544,544,544,544,88,89,'YUAAAA','ZPGAAA','VVVVxx'
+6977,4472,1,1,7,17,77,977,977,1977,6977,154,155,'JIAAAA','AQGAAA','AAAAxx'
+3191,4473,1,3,1,11,91,191,1191,3191,3191,182,183,'TSAAAA','BQGAAA','HHHHxx'
+418,4474,0,2,8,18,18,418,418,418,418,36,37,'CQAAAA','CQGAAA','OOOOxx'
+3142,4475,0,2,2,2,42,142,1142,3142,3142,84,85,'WQAAAA','DQGAAA','VVVVxx'
+5042,4476,0,2,2,2,42,42,1042,42,5042,84,85,'YLAAAA','EQGAAA','AAAAxx'
+2194,4477,0,2,4,14,94,194,194,2194,2194,188,189,'KGAAAA','FQGAAA','HHHHxx'
+2397,4478,1,1,7,17,97,397,397,2397,2397,194,195,'FOAAAA','GQGAAA','OOOOxx'
+4684,4479,0,0,4,4,84,684,684,4684,4684,168,169,'EYAAAA','HQGAAA','VVVVxx'
+34,4480,0,2,4,14,34,34,34,34,34,68,69,'IBAAAA','IQGAAA','AAAAxx'
+3844,4481,0,0,4,4,44,844,1844,3844,3844,88,89,'WRAAAA','JQGAAA','HHHHxx'
+7824,4482,0,0,4,4,24,824,1824,2824,7824,48,49,'YOAAAA','KQGAAA','OOOOxx'
+6177,4483,1,1,7,17,77,177,177,1177,6177,154,155,'PDAAAA','LQGAAA','VVVVxx'
+9657,4484,1,1,7,17,57,657,1657,4657,9657,114,115,'LHAAAA','MQGAAA','AAAAxx'
+4546,4485,0,2,6,6,46,546,546,4546,4546,92,93,'WSAAAA','NQGAAA','HHHHxx'
+599,4486,1,3,9,19,99,599,599,599,599,198,199,'BXAAAA','OQGAAA','OOOOxx'
+153,4487,1,1,3,13,53,153,153,153,153,106,107,'XFAAAA','PQGAAA','VVVVxx'
+6910,4488,0,2,0,10,10,910,910,1910,6910,20,21,'UFAAAA','QQGAAA','AAAAxx'
+4408,4489,0,0,8,8,8,408,408,4408,4408,16,17,'ONAAAA','RQGAAA','HHHHxx'
+1164,4490,0,0,4,4,64,164,1164,1164,1164,128,129,'USAAAA','SQGAAA','OOOOxx'
+6469,4491,1,1,9,9,69,469,469,1469,6469,138,139,'VOAAAA','TQGAAA','VVVVxx'
+5996,4492,0,0,6,16,96,996,1996,996,5996,192,193,'QWAAAA','UQGAAA','AAAAxx'
+2639,4493,1,3,9,19,39,639,639,2639,2639,78,79,'NXAAAA','VQGAAA','HHHHxx'
+2678,4494,0,2,8,18,78,678,678,2678,2678,156,157,'AZAAAA','WQGAAA','OOOOxx'
+8392,4495,0,0,2,12,92,392,392,3392,8392,184,185,'UKAAAA','XQGAAA','VVVVxx'
+1386,4496,0,2,6,6,86,386,1386,1386,1386,172,173,'IBAAAA','YQGAAA','AAAAxx'
+5125,4497,1,1,5,5,25,125,1125,125,5125,50,51,'DPAAAA','ZQGAAA','HHHHxx'
+8453,4498,1,1,3,13,53,453,453,3453,8453,106,107,'DNAAAA','ARGAAA','OOOOxx'
+2369,4499,1,1,9,9,69,369,369,2369,2369,138,139,'DNAAAA','BRGAAA','VVVVxx'
+1608,4500,0,0,8,8,8,608,1608,1608,1608,16,17,'WJAAAA','CRGAAA','AAAAxx'
+3781,4501,1,1,1,1,81,781,1781,3781,3781,162,163,'LPAAAA','DRGAAA','HHHHxx'
+903,4502,1,3,3,3,3,903,903,903,903,6,7,'TIAAAA','ERGAAA','OOOOxx'
+2099,4503,1,3,9,19,99,99,99,2099,2099,198,199,'TCAAAA','FRGAAA','VVVVxx'
+538,4504,0,2,8,18,38,538,538,538,538,76,77,'SUAAAA','GRGAAA','AAAAxx'
+9177,4505,1,1,7,17,77,177,1177,4177,9177,154,155,'ZOAAAA','HRGAAA','HHHHxx'
+420,4506,0,0,0,0,20,420,420,420,420,40,41,'EQAAAA','IRGAAA','OOOOxx'
+9080,4507,0,0,0,0,80,80,1080,4080,9080,160,161,'GLAAAA','JRGAAA','VVVVxx'
+2630,4508,0,2,0,10,30,630,630,2630,2630,60,61,'EXAAAA','KRGAAA','AAAAxx'
+5978,4509,0,2,8,18,78,978,1978,978,5978,156,157,'YVAAAA','LRGAAA','HHHHxx'
+9239,4510,1,3,9,19,39,239,1239,4239,9239,78,79,'JRAAAA','MRGAAA','OOOOxx'
+4372,4511,0,0,2,12,72,372,372,4372,4372,144,145,'EMAAAA','NRGAAA','VVVVxx'
+4357,4512,1,1,7,17,57,357,357,4357,4357,114,115,'PLAAAA','ORGAAA','AAAAxx'
+9857,4513,1,1,7,17,57,857,1857,4857,9857,114,115,'DPAAAA','PRGAAA','HHHHxx'
+7933,4514,1,1,3,13,33,933,1933,2933,7933,66,67,'DTAAAA','QRGAAA','OOOOxx'
+9574,4515,0,2,4,14,74,574,1574,4574,9574,148,149,'GEAAAA','RRGAAA','VVVVxx'
+8294,4516,0,2,4,14,94,294,294,3294,8294,188,189,'AHAAAA','SRGAAA','AAAAxx'
+627,4517,1,3,7,7,27,627,627,627,627,54,55,'DYAAAA','TRGAAA','HHHHxx'
+3229,4518,1,1,9,9,29,229,1229,3229,3229,58,59,'FUAAAA','URGAAA','OOOOxx'
+3163,4519,1,3,3,3,63,163,1163,3163,3163,126,127,'RRAAAA','VRGAAA','VVVVxx'
+7349,4520,1,1,9,9,49,349,1349,2349,7349,98,99,'RWAAAA','WRGAAA','AAAAxx'
+6889,4521,1,1,9,9,89,889,889,1889,6889,178,179,'ZEAAAA','XRGAAA','HHHHxx'
+2101,4522,1,1,1,1,1,101,101,2101,2101,2,3,'VCAAAA','YRGAAA','OOOOxx'
+6476,4523,0,0,6,16,76,476,476,1476,6476,152,153,'CPAAAA','ZRGAAA','VVVVxx'
+6765,4524,1,1,5,5,65,765,765,1765,6765,130,131,'FAAAAA','ASGAAA','AAAAxx'
+4204,4525,0,0,4,4,4,204,204,4204,4204,8,9,'SFAAAA','BSGAAA','HHHHxx'
+5915,4526,1,3,5,15,15,915,1915,915,5915,30,31,'NTAAAA','CSGAAA','OOOOxx'
+2318,4527,0,2,8,18,18,318,318,2318,2318,36,37,'ELAAAA','DSGAAA','VVVVxx'
+294,4528,0,2,4,14,94,294,294,294,294,188,189,'ILAAAA','ESGAAA','AAAAxx'
+5245,4529,1,1,5,5,45,245,1245,245,5245,90,91,'TTAAAA','FSGAAA','HHHHxx'
+4481,4530,1,1,1,1,81,481,481,4481,4481,162,163,'JQAAAA','GSGAAA','OOOOxx'
+7754,4531,0,2,4,14,54,754,1754,2754,7754,108,109,'GMAAAA','HSGAAA','VVVVxx'
+8494,4532,0,2,4,14,94,494,494,3494,8494,188,189,'SOAAAA','ISGAAA','AAAAxx'
+4014,4533,0,2,4,14,14,14,14,4014,4014,28,29,'KYAAAA','JSGAAA','HHHHxx'
+2197,4534,1,1,7,17,97,197,197,2197,2197,194,195,'NGAAAA','KSGAAA','OOOOxx'
+1297,4535,1,1,7,17,97,297,1297,1297,1297,194,195,'XXAAAA','LSGAAA','VVVVxx'
+1066,4536,0,2,6,6,66,66,1066,1066,1066,132,133,'APAAAA','MSGAAA','AAAAxx'
+5710,4537,0,2,0,10,10,710,1710,710,5710,20,21,'QLAAAA','NSGAAA','HHHHxx'
+4100,4538,0,0,0,0,0,100,100,4100,4100,0,1,'SBAAAA','OSGAAA','OOOOxx'
+7356,4539,0,0,6,16,56,356,1356,2356,7356,112,113,'YWAAAA','PSGAAA','VVVVxx'
+7658,4540,0,2,8,18,58,658,1658,2658,7658,116,117,'OIAAAA','QSGAAA','AAAAxx'
+3666,4541,0,2,6,6,66,666,1666,3666,3666,132,133,'ALAAAA','RSGAAA','HHHHxx'
+9713,4542,1,1,3,13,13,713,1713,4713,9713,26,27,'PJAAAA','SSGAAA','OOOOxx'
+691,4543,1,3,1,11,91,691,691,691,691,182,183,'PAAAAA','TSGAAA','VVVVxx'
+3112,4544,0,0,2,12,12,112,1112,3112,3112,24,25,'SPAAAA','USGAAA','AAAAxx'
+6035,4545,1,3,5,15,35,35,35,1035,6035,70,71,'DYAAAA','VSGAAA','HHHHxx'
+8353,4546,1,1,3,13,53,353,353,3353,8353,106,107,'HJAAAA','WSGAAA','OOOOxx'
+5679,4547,1,3,9,19,79,679,1679,679,5679,158,159,'LKAAAA','XSGAAA','VVVVxx'
+2124,4548,0,0,4,4,24,124,124,2124,2124,48,49,'SDAAAA','YSGAAA','AAAAxx'
+4714,4549,0,2,4,14,14,714,714,4714,4714,28,29,'IZAAAA','ZSGAAA','HHHHxx'
+9048,4550,0,0,8,8,48,48,1048,4048,9048,96,97,'AKAAAA','ATGAAA','OOOOxx'
+7692,4551,0,0,2,12,92,692,1692,2692,7692,184,185,'WJAAAA','BTGAAA','VVVVxx'
+4542,4552,0,2,2,2,42,542,542,4542,4542,84,85,'SSAAAA','CTGAAA','AAAAxx'
+8737,4553,1,1,7,17,37,737,737,3737,8737,74,75,'BYAAAA','DTGAAA','HHHHxx'
+4977,4554,1,1,7,17,77,977,977,4977,4977,154,155,'LJAAAA','ETGAAA','OOOOxx'
+9349,4555,1,1,9,9,49,349,1349,4349,9349,98,99,'PVAAAA','FTGAAA','VVVVxx'
+731,4556,1,3,1,11,31,731,731,731,731,62,63,'DCAAAA','GTGAAA','AAAAxx'
+1788,4557,0,0,8,8,88,788,1788,1788,1788,176,177,'UQAAAA','HTGAAA','HHHHxx'
+7830,4558,0,2,0,10,30,830,1830,2830,7830,60,61,'EPAAAA','ITGAAA','OOOOxx'
+3977,4559,1,1,7,17,77,977,1977,3977,3977,154,155,'ZWAAAA','JTGAAA','VVVVxx'
+2421,4560,1,1,1,1,21,421,421,2421,2421,42,43,'DPAAAA','KTGAAA','AAAAxx'
+5891,4561,1,3,1,11,91,891,1891,891,5891,182,183,'PSAAAA','LTGAAA','HHHHxx'
+1111,4562,1,3,1,11,11,111,1111,1111,1111,22,23,'TQAAAA','MTGAAA','OOOOxx'
+9224,4563,0,0,4,4,24,224,1224,4224,9224,48,49,'UQAAAA','NTGAAA','VVVVxx'
+9872,4564,0,0,2,12,72,872,1872,4872,9872,144,145,'SPAAAA','OTGAAA','AAAAxx'
+2433,4565,1,1,3,13,33,433,433,2433,2433,66,67,'PPAAAA','PTGAAA','HHHHxx'
+1491,4566,1,3,1,11,91,491,1491,1491,1491,182,183,'JFAAAA','QTGAAA','OOOOxx'
+6653,4567,1,1,3,13,53,653,653,1653,6653,106,107,'XVAAAA','RTGAAA','VVVVxx'
+1907,4568,1,3,7,7,7,907,1907,1907,1907,14,15,'JVAAAA','STGAAA','AAAAxx'
+889,4569,1,1,9,9,89,889,889,889,889,178,179,'FIAAAA','TTGAAA','HHHHxx'
+561,4570,1,1,1,1,61,561,561,561,561,122,123,'PVAAAA','UTGAAA','OOOOxx'
+7415,4571,1,3,5,15,15,415,1415,2415,7415,30,31,'FZAAAA','VTGAAA','VVVVxx'
+2703,4572,1,3,3,3,3,703,703,2703,2703,6,7,'ZZAAAA','WTGAAA','AAAAxx'
+2561,4573,1,1,1,1,61,561,561,2561,2561,122,123,'NUAAAA','XTGAAA','HHHHxx'
+1257,4574,1,1,7,17,57,257,1257,1257,1257,114,115,'JWAAAA','YTGAAA','OOOOxx'
+2390,4575,0,2,0,10,90,390,390,2390,2390,180,181,'YNAAAA','ZTGAAA','VVVVxx'
+3915,4576,1,3,5,15,15,915,1915,3915,3915,30,31,'PUAAAA','AUGAAA','AAAAxx'
+8476,4577,0,0,6,16,76,476,476,3476,8476,152,153,'AOAAAA','BUGAAA','HHHHxx'
+607,4578,1,3,7,7,7,607,607,607,607,14,15,'JXAAAA','CUGAAA','OOOOxx'
+3891,4579,1,3,1,11,91,891,1891,3891,3891,182,183,'RTAAAA','DUGAAA','VVVVxx'
+7269,4580,1,1,9,9,69,269,1269,2269,7269,138,139,'PTAAAA','EUGAAA','AAAAxx'
+9537,4581,1,1,7,17,37,537,1537,4537,9537,74,75,'VCAAAA','FUGAAA','HHHHxx'
+8518,4582,0,2,8,18,18,518,518,3518,8518,36,37,'QPAAAA','GUGAAA','OOOOxx'
+5221,4583,1,1,1,1,21,221,1221,221,5221,42,43,'VSAAAA','HUGAAA','VVVVxx'
+3274,4584,0,2,4,14,74,274,1274,3274,3274,148,149,'YVAAAA','IUGAAA','AAAAxx'
+6677,4585,1,1,7,17,77,677,677,1677,6677,154,155,'VWAAAA','JUGAAA','HHHHxx'
+3114,4586,0,2,4,14,14,114,1114,3114,3114,28,29,'UPAAAA','KUGAAA','OOOOxx'
+1966,4587,0,2,6,6,66,966,1966,1966,1966,132,133,'QXAAAA','LUGAAA','VVVVxx'
+5941,4588,1,1,1,1,41,941,1941,941,5941,82,83,'NUAAAA','MUGAAA','AAAAxx'
+9463,4589,1,3,3,3,63,463,1463,4463,9463,126,127,'ZZAAAA','NUGAAA','HHHHxx'
+8966,4590,0,2,6,6,66,966,966,3966,8966,132,133,'WGAAAA','OUGAAA','OOOOxx'
+4402,4591,0,2,2,2,2,402,402,4402,4402,4,5,'INAAAA','PUGAAA','VVVVxx'
+3364,4592,0,0,4,4,64,364,1364,3364,3364,128,129,'KZAAAA','QUGAAA','AAAAxx'
+3698,4593,0,2,8,18,98,698,1698,3698,3698,196,197,'GMAAAA','RUGAAA','HHHHxx'
+4651,4594,1,3,1,11,51,651,651,4651,4651,102,103,'XWAAAA','SUGAAA','OOOOxx'
+2127,4595,1,3,7,7,27,127,127,2127,2127,54,55,'VDAAAA','TUGAAA','VVVVxx'
+3614,4596,0,2,4,14,14,614,1614,3614,3614,28,29,'AJAAAA','UUGAAA','AAAAxx'
+5430,4597,0,2,0,10,30,430,1430,430,5430,60,61,'WAAAAA','VUGAAA','HHHHxx'
+3361,4598,1,1,1,1,61,361,1361,3361,3361,122,123,'HZAAAA','WUGAAA','OOOOxx'
+4798,4599,0,2,8,18,98,798,798,4798,4798,196,197,'OCAAAA','XUGAAA','VVVVxx'
+8269,4600,1,1,9,9,69,269,269,3269,8269,138,139,'BGAAAA','YUGAAA','AAAAxx'
+6458,4601,0,2,8,18,58,458,458,1458,6458,116,117,'KOAAAA','ZUGAAA','HHHHxx'
+3358,4602,0,2,8,18,58,358,1358,3358,3358,116,117,'EZAAAA','AVGAAA','OOOOxx'
+5898,4603,0,2,8,18,98,898,1898,898,5898,196,197,'WSAAAA','BVGAAA','VVVVxx'
+1880,4604,0,0,0,0,80,880,1880,1880,1880,160,161,'IUAAAA','CVGAAA','AAAAxx'
+782,4605,0,2,2,2,82,782,782,782,782,164,165,'CEAAAA','DVGAAA','HHHHxx'
+3102,4606,0,2,2,2,2,102,1102,3102,3102,4,5,'IPAAAA','EVGAAA','OOOOxx'
+6366,4607,0,2,6,6,66,366,366,1366,6366,132,133,'WKAAAA','FVGAAA','VVVVxx'
+399,4608,1,3,9,19,99,399,399,399,399,198,199,'JPAAAA','GVGAAA','AAAAxx'
+6773,4609,1,1,3,13,73,773,773,1773,6773,146,147,'NAAAAA','HVGAAA','HHHHxx'
+7942,4610,0,2,2,2,42,942,1942,2942,7942,84,85,'MTAAAA','IVGAAA','OOOOxx'
+6274,4611,0,2,4,14,74,274,274,1274,6274,148,149,'IHAAAA','JVGAAA','VVVVxx'
+7447,4612,1,3,7,7,47,447,1447,2447,7447,94,95,'LAAAAA','KVGAAA','AAAAxx'
+7648,4613,0,0,8,8,48,648,1648,2648,7648,96,97,'EIAAAA','LVGAAA','HHHHxx'
+3997,4614,1,1,7,17,97,997,1997,3997,3997,194,195,'TXAAAA','MVGAAA','OOOOxx'
+1759,4615,1,3,9,19,59,759,1759,1759,1759,118,119,'RPAAAA','NVGAAA','VVVVxx'
+1785,4616,1,1,5,5,85,785,1785,1785,1785,170,171,'RQAAAA','OVGAAA','AAAAxx'
+8930,4617,0,2,0,10,30,930,930,3930,8930,60,61,'MFAAAA','PVGAAA','HHHHxx'
+7595,4618,1,3,5,15,95,595,1595,2595,7595,190,191,'DGAAAA','QVGAAA','OOOOxx'
+6752,4619,0,0,2,12,52,752,752,1752,6752,104,105,'SZAAAA','RVGAAA','VVVVxx'
+5635,4620,1,3,5,15,35,635,1635,635,5635,70,71,'TIAAAA','SVGAAA','AAAAxx'
+1579,4621,1,3,9,19,79,579,1579,1579,1579,158,159,'TIAAAA','TVGAAA','HHHHxx'
+7743,4622,1,3,3,3,43,743,1743,2743,7743,86,87,'VLAAAA','UVGAAA','OOOOxx'
+5856,4623,0,0,6,16,56,856,1856,856,5856,112,113,'GRAAAA','VVGAAA','VVVVxx'
+7273,4624,1,1,3,13,73,273,1273,2273,7273,146,147,'TTAAAA','WVGAAA','AAAAxx'
+1399,4625,1,3,9,19,99,399,1399,1399,1399,198,199,'VBAAAA','XVGAAA','HHHHxx'
+3694,4626,0,2,4,14,94,694,1694,3694,3694,188,189,'CMAAAA','YVGAAA','OOOOxx'
+2782,4627,0,2,2,2,82,782,782,2782,2782,164,165,'ADAAAA','ZVGAAA','VVVVxx'
+6951,4628,1,3,1,11,51,951,951,1951,6951,102,103,'JHAAAA','AWGAAA','AAAAxx'
+6053,4629,1,1,3,13,53,53,53,1053,6053,106,107,'VYAAAA','BWGAAA','HHHHxx'
+1753,4630,1,1,3,13,53,753,1753,1753,1753,106,107,'LPAAAA','CWGAAA','OOOOxx'
+3985,4631,1,1,5,5,85,985,1985,3985,3985,170,171,'HXAAAA','DWGAAA','VVVVxx'
+6159,4632,1,3,9,19,59,159,159,1159,6159,118,119,'XCAAAA','EWGAAA','AAAAxx'
+6250,4633,0,2,0,10,50,250,250,1250,6250,100,101,'KGAAAA','FWGAAA','HHHHxx'
+6240,4634,0,0,0,0,40,240,240,1240,6240,80,81,'AGAAAA','GWGAAA','OOOOxx'
+6571,4635,1,3,1,11,71,571,571,1571,6571,142,143,'TSAAAA','HWGAAA','VVVVxx'
+8624,4636,0,0,4,4,24,624,624,3624,8624,48,49,'STAAAA','IWGAAA','AAAAxx'
+9718,4637,0,2,8,18,18,718,1718,4718,9718,36,37,'UJAAAA','JWGAAA','HHHHxx'
+5529,4638,1,1,9,9,29,529,1529,529,5529,58,59,'REAAAA','KWGAAA','OOOOxx'
+7089,4639,1,1,9,9,89,89,1089,2089,7089,178,179,'RMAAAA','LWGAAA','VVVVxx'
+5488,4640,0,0,8,8,88,488,1488,488,5488,176,177,'CDAAAA','MWGAAA','AAAAxx'
+5444,4641,0,0,4,4,44,444,1444,444,5444,88,89,'KBAAAA','NWGAAA','HHHHxx'
+4899,4642,1,3,9,19,99,899,899,4899,4899,198,199,'LGAAAA','OWGAAA','OOOOxx'
+7928,4643,0,0,8,8,28,928,1928,2928,7928,56,57,'YSAAAA','PWGAAA','VVVVxx'
+4736,4644,0,0,6,16,36,736,736,4736,4736,72,73,'EAAAAA','QWGAAA','AAAAxx'
+4317,4645,1,1,7,17,17,317,317,4317,4317,34,35,'BKAAAA','RWGAAA','HHHHxx'
+1174,4646,0,2,4,14,74,174,1174,1174,1174,148,149,'ETAAAA','SWGAAA','OOOOxx'
+6138,4647,0,2,8,18,38,138,138,1138,6138,76,77,'CCAAAA','TWGAAA','VVVVxx'
+3943,4648,1,3,3,3,43,943,1943,3943,3943,86,87,'RVAAAA','UWGAAA','AAAAxx'
+1545,4649,1,1,5,5,45,545,1545,1545,1545,90,91,'LHAAAA','VWGAAA','HHHHxx'
+6867,4650,1,3,7,7,67,867,867,1867,6867,134,135,'DEAAAA','WWGAAA','OOOOxx'
+6832,4651,0,0,2,12,32,832,832,1832,6832,64,65,'UCAAAA','XWGAAA','VVVVxx'
+2987,4652,1,3,7,7,87,987,987,2987,2987,174,175,'XKAAAA','YWGAAA','AAAAxx'
+5169,4653,1,1,9,9,69,169,1169,169,5169,138,139,'VQAAAA','ZWGAAA','HHHHxx'
+8998,4654,0,2,8,18,98,998,998,3998,8998,196,197,'CIAAAA','AXGAAA','OOOOxx'
+9347,4655,1,3,7,7,47,347,1347,4347,9347,94,95,'NVAAAA','BXGAAA','VVVVxx'
+4800,4656,0,0,0,0,0,800,800,4800,4800,0,1,'QCAAAA','CXGAAA','AAAAxx'
+4200,4657,0,0,0,0,0,200,200,4200,4200,0,1,'OFAAAA','DXGAAA','HHHHxx'
+4046,4658,0,2,6,6,46,46,46,4046,4046,92,93,'QZAAAA','EXGAAA','OOOOxx'
+7142,4659,0,2,2,2,42,142,1142,2142,7142,84,85,'SOAAAA','FXGAAA','VVVVxx'
+2733,4660,1,1,3,13,33,733,733,2733,2733,66,67,'DBAAAA','GXGAAA','AAAAxx'
+1568,4661,0,0,8,8,68,568,1568,1568,1568,136,137,'IIAAAA','HXGAAA','HHHHxx'
+5105,4662,1,1,5,5,5,105,1105,105,5105,10,11,'JOAAAA','IXGAAA','OOOOxx'
+9115,4663,1,3,5,15,15,115,1115,4115,9115,30,31,'PMAAAA','JXGAAA','VVVVxx'
+6475,4664,1,3,5,15,75,475,475,1475,6475,150,151,'BPAAAA','KXGAAA','AAAAxx'
+3796,4665,0,0,6,16,96,796,1796,3796,3796,192,193,'AQAAAA','LXGAAA','HHHHxx'
+5410,4666,0,2,0,10,10,410,1410,410,5410,20,21,'CAAAAA','MXGAAA','OOOOxx'
+4023,4667,1,3,3,3,23,23,23,4023,4023,46,47,'TYAAAA','NXGAAA','VVVVxx'
+8904,4668,0,0,4,4,4,904,904,3904,8904,8,9,'MEAAAA','OXGAAA','AAAAxx'
+450,4669,0,2,0,10,50,450,450,450,450,100,101,'IRAAAA','PXGAAA','HHHHxx'
+8087,4670,1,3,7,7,87,87,87,3087,8087,174,175,'BZAAAA','QXGAAA','OOOOxx'
+6478,4671,0,2,8,18,78,478,478,1478,6478,156,157,'EPAAAA','RXGAAA','VVVVxx'
+2696,4672,0,0,6,16,96,696,696,2696,2696,192,193,'SZAAAA','SXGAAA','AAAAxx'
+1792,4673,0,0,2,12,92,792,1792,1792,1792,184,185,'YQAAAA','TXGAAA','HHHHxx'
+9699,4674,1,3,9,19,99,699,1699,4699,9699,198,199,'BJAAAA','UXGAAA','OOOOxx'
+9160,4675,0,0,0,0,60,160,1160,4160,9160,120,121,'IOAAAA','VXGAAA','VVVVxx'
+9989,4676,1,1,9,9,89,989,1989,4989,9989,178,179,'FUAAAA','WXGAAA','AAAAxx'
+9568,4677,0,0,8,8,68,568,1568,4568,9568,136,137,'AEAAAA','XXGAAA','HHHHxx'
+487,4678,1,3,7,7,87,487,487,487,487,174,175,'TSAAAA','YXGAAA','OOOOxx'
+7863,4679,1,3,3,3,63,863,1863,2863,7863,126,127,'LQAAAA','ZXGAAA','VVVVxx'
+1884,4680,0,0,4,4,84,884,1884,1884,1884,168,169,'MUAAAA','AYGAAA','AAAAxx'
+2651,4681,1,3,1,11,51,651,651,2651,2651,102,103,'ZXAAAA','BYGAAA','HHHHxx'
+8285,4682,1,1,5,5,85,285,285,3285,8285,170,171,'RGAAAA','CYGAAA','OOOOxx'
+3927,4683,1,3,7,7,27,927,1927,3927,3927,54,55,'BVAAAA','DYGAAA','VVVVxx'
+4076,4684,0,0,6,16,76,76,76,4076,4076,152,153,'UAAAAA','EYGAAA','AAAAxx'
+6149,4685,1,1,9,9,49,149,149,1149,6149,98,99,'NCAAAA','FYGAAA','HHHHxx'
+6581,4686,1,1,1,1,81,581,581,1581,6581,162,163,'DTAAAA','GYGAAA','OOOOxx'
+8293,4687,1,1,3,13,93,293,293,3293,8293,186,187,'ZGAAAA','HYGAAA','VVVVxx'
+7665,4688,1,1,5,5,65,665,1665,2665,7665,130,131,'VIAAAA','IYGAAA','AAAAxx'
+4435,4689,1,3,5,15,35,435,435,4435,4435,70,71,'POAAAA','JYGAAA','HHHHxx'
+1271,4690,1,3,1,11,71,271,1271,1271,1271,142,143,'XWAAAA','KYGAAA','OOOOxx'
+3928,4691,0,0,8,8,28,928,1928,3928,3928,56,57,'CVAAAA','LYGAAA','VVVVxx'
+7045,4692,1,1,5,5,45,45,1045,2045,7045,90,91,'ZKAAAA','MYGAAA','AAAAxx'
+4943,4693,1,3,3,3,43,943,943,4943,4943,86,87,'DIAAAA','NYGAAA','HHHHxx'
+8473,4694,1,1,3,13,73,473,473,3473,8473,146,147,'XNAAAA','OYGAAA','OOOOxx'
+1707,4695,1,3,7,7,7,707,1707,1707,1707,14,15,'RNAAAA','PYGAAA','VVVVxx'
+7509,4696,1,1,9,9,9,509,1509,2509,7509,18,19,'VCAAAA','QYGAAA','AAAAxx'
+1593,4697,1,1,3,13,93,593,1593,1593,1593,186,187,'HJAAAA','RYGAAA','HHHHxx'
+9281,4698,1,1,1,1,81,281,1281,4281,9281,162,163,'ZSAAAA','SYGAAA','OOOOxx'
+8986,4699,0,2,6,6,86,986,986,3986,8986,172,173,'QHAAAA','TYGAAA','VVVVxx'
+3740,4700,0,0,0,0,40,740,1740,3740,3740,80,81,'WNAAAA','UYGAAA','AAAAxx'
+9265,4701,1,1,5,5,65,265,1265,4265,9265,130,131,'JSAAAA','VYGAAA','HHHHxx'
+1510,4702,0,2,0,10,10,510,1510,1510,1510,20,21,'CGAAAA','WYGAAA','OOOOxx'
+3022,4703,0,2,2,2,22,22,1022,3022,3022,44,45,'GMAAAA','XYGAAA','VVVVxx'
+9014,4704,0,2,4,14,14,14,1014,4014,9014,28,29,'SIAAAA','YYGAAA','AAAAxx'
+6816,4705,0,0,6,16,16,816,816,1816,6816,32,33,'ECAAAA','ZYGAAA','HHHHxx'
+5518,4706,0,2,8,18,18,518,1518,518,5518,36,37,'GEAAAA','AZGAAA','OOOOxx'
+4451,4707,1,3,1,11,51,451,451,4451,4451,102,103,'FPAAAA','BZGAAA','VVVVxx'
+8747,4708,1,3,7,7,47,747,747,3747,8747,94,95,'LYAAAA','CZGAAA','AAAAxx'
+4646,4709,0,2,6,6,46,646,646,4646,4646,92,93,'SWAAAA','DZGAAA','HHHHxx'
+7296,4710,0,0,6,16,96,296,1296,2296,7296,192,193,'QUAAAA','EZGAAA','OOOOxx'
+9644,4711,0,0,4,4,44,644,1644,4644,9644,88,89,'YGAAAA','FZGAAA','VVVVxx'
+5977,4712,1,1,7,17,77,977,1977,977,5977,154,155,'XVAAAA','GZGAAA','AAAAxx'
+6270,4713,0,2,0,10,70,270,270,1270,6270,140,141,'EHAAAA','HZGAAA','HHHHxx'
+5578,4714,0,2,8,18,78,578,1578,578,5578,156,157,'OGAAAA','IZGAAA','OOOOxx'
+2465,4715,1,1,5,5,65,465,465,2465,2465,130,131,'VQAAAA','JZGAAA','VVVVxx'
+6436,4716,0,0,6,16,36,436,436,1436,6436,72,73,'ONAAAA','KZGAAA','AAAAxx'
+8089,4717,1,1,9,9,89,89,89,3089,8089,178,179,'DZAAAA','LZGAAA','HHHHxx'
+2409,4718,1,1,9,9,9,409,409,2409,2409,18,19,'ROAAAA','MZGAAA','OOOOxx'
+284,4719,0,0,4,4,84,284,284,284,284,168,169,'YKAAAA','NZGAAA','VVVVxx'
+5576,4720,0,0,6,16,76,576,1576,576,5576,152,153,'MGAAAA','OZGAAA','AAAAxx'
+6534,4721,0,2,4,14,34,534,534,1534,6534,68,69,'IRAAAA','PZGAAA','HHHHxx'
+8848,4722,0,0,8,8,48,848,848,3848,8848,96,97,'ICAAAA','QZGAAA','OOOOxx'
+4305,4723,1,1,5,5,5,305,305,4305,4305,10,11,'PJAAAA','RZGAAA','VVVVxx'
+5574,4724,0,2,4,14,74,574,1574,574,5574,148,149,'KGAAAA','SZGAAA','AAAAxx'
+596,4725,0,0,6,16,96,596,596,596,596,192,193,'YWAAAA','TZGAAA','HHHHxx'
+1253,4726,1,1,3,13,53,253,1253,1253,1253,106,107,'FWAAAA','UZGAAA','OOOOxx'
+521,4727,1,1,1,1,21,521,521,521,521,42,43,'BUAAAA','VZGAAA','VVVVxx'
+8739,4728,1,3,9,19,39,739,739,3739,8739,78,79,'DYAAAA','WZGAAA','AAAAxx'
+908,4729,0,0,8,8,8,908,908,908,908,16,17,'YIAAAA','XZGAAA','HHHHxx'
+6937,4730,1,1,7,17,37,937,937,1937,6937,74,75,'VGAAAA','YZGAAA','OOOOxx'
+4515,4731,1,3,5,15,15,515,515,4515,4515,30,31,'RRAAAA','ZZGAAA','VVVVxx'
+8630,4732,0,2,0,10,30,630,630,3630,8630,60,61,'YTAAAA','AAHAAA','AAAAxx'
+7518,4733,0,2,8,18,18,518,1518,2518,7518,36,37,'EDAAAA','BAHAAA','HHHHxx'
+8300,4734,0,0,0,0,0,300,300,3300,8300,0,1,'GHAAAA','CAHAAA','OOOOxx'
+8434,4735,0,2,4,14,34,434,434,3434,8434,68,69,'KMAAAA','DAHAAA','VVVVxx'
+6000,4736,0,0,0,0,0,0,0,1000,6000,0,1,'UWAAAA','EAHAAA','AAAAxx'
+4508,4737,0,0,8,8,8,508,508,4508,4508,16,17,'KRAAAA','FAHAAA','HHHHxx'
+7861,4738,1,1,1,1,61,861,1861,2861,7861,122,123,'JQAAAA','GAHAAA','OOOOxx'
+5953,4739,1,1,3,13,53,953,1953,953,5953,106,107,'ZUAAAA','HAHAAA','VVVVxx'
+5063,4740,1,3,3,3,63,63,1063,63,5063,126,127,'TMAAAA','IAHAAA','AAAAxx'
+4501,4741,1,1,1,1,1,501,501,4501,4501,2,3,'DRAAAA','JAHAAA','HHHHxx'
+7092,4742,0,0,2,12,92,92,1092,2092,7092,184,185,'UMAAAA','KAHAAA','OOOOxx'
+4388,4743,0,0,8,8,88,388,388,4388,4388,176,177,'UMAAAA','LAHAAA','VVVVxx'
+1826,4744,0,2,6,6,26,826,1826,1826,1826,52,53,'GSAAAA','MAHAAA','AAAAxx'
+568,4745,0,0,8,8,68,568,568,568,568,136,137,'WVAAAA','NAHAAA','HHHHxx'
+8184,4746,0,0,4,4,84,184,184,3184,8184,168,169,'UCAAAA','OAHAAA','OOOOxx'
+4268,4747,0,0,8,8,68,268,268,4268,4268,136,137,'EIAAAA','PAHAAA','VVVVxx'
+5798,4748,0,2,8,18,98,798,1798,798,5798,196,197,'APAAAA','QAHAAA','AAAAxx'
+5190,4749,0,2,0,10,90,190,1190,190,5190,180,181,'QRAAAA','RAHAAA','HHHHxx'
+1298,4750,0,2,8,18,98,298,1298,1298,1298,196,197,'YXAAAA','SAHAAA','OOOOxx'
+4035,4751,1,3,5,15,35,35,35,4035,4035,70,71,'FZAAAA','TAHAAA','VVVVxx'
+4504,4752,0,0,4,4,4,504,504,4504,4504,8,9,'GRAAAA','UAHAAA','AAAAxx'
+5992,4753,0,0,2,12,92,992,1992,992,5992,184,185,'MWAAAA','VAHAAA','HHHHxx'
+770,4754,0,2,0,10,70,770,770,770,770,140,141,'QDAAAA','WAHAAA','OOOOxx'
+7502,4755,0,2,2,2,2,502,1502,2502,7502,4,5,'OCAAAA','XAHAAA','VVVVxx'
+824,4756,0,0,4,4,24,824,824,824,824,48,49,'SFAAAA','YAHAAA','AAAAxx'
+7716,4757,0,0,6,16,16,716,1716,2716,7716,32,33,'UKAAAA','ZAHAAA','HHHHxx'
+5749,4758,1,1,9,9,49,749,1749,749,5749,98,99,'DNAAAA','ABHAAA','OOOOxx'
+9814,4759,0,2,4,14,14,814,1814,4814,9814,28,29,'MNAAAA','BBHAAA','VVVVxx'
+350,4760,0,2,0,10,50,350,350,350,350,100,101,'MNAAAA','CBHAAA','AAAAxx'
+1390,4761,0,2,0,10,90,390,1390,1390,1390,180,181,'MBAAAA','DBHAAA','HHHHxx'
+6994,4762,0,2,4,14,94,994,994,1994,6994,188,189,'AJAAAA','EBHAAA','OOOOxx'
+3629,4763,1,1,9,9,29,629,1629,3629,3629,58,59,'PJAAAA','FBHAAA','VVVVxx'
+9937,4764,1,1,7,17,37,937,1937,4937,9937,74,75,'FSAAAA','GBHAAA','AAAAxx'
+5285,4765,1,1,5,5,85,285,1285,285,5285,170,171,'HVAAAA','HBHAAA','HHHHxx'
+3157,4766,1,1,7,17,57,157,1157,3157,3157,114,115,'LRAAAA','IBHAAA','OOOOxx'
+9549,4767,1,1,9,9,49,549,1549,4549,9549,98,99,'HDAAAA','JBHAAA','VVVVxx'
+4118,4768,0,2,8,18,18,118,118,4118,4118,36,37,'KCAAAA','KBHAAA','AAAAxx'
+756,4769,0,0,6,16,56,756,756,756,756,112,113,'CDAAAA','LBHAAA','HHHHxx'
+5964,4770,0,0,4,4,64,964,1964,964,5964,128,129,'KVAAAA','MBHAAA','OOOOxx'
+7701,4771,1,1,1,1,1,701,1701,2701,7701,2,3,'FKAAAA','NBHAAA','VVVVxx'
+1242,4772,0,2,2,2,42,242,1242,1242,1242,84,85,'UVAAAA','OBHAAA','AAAAxx'
+7890,4773,0,2,0,10,90,890,1890,2890,7890,180,181,'MRAAAA','PBHAAA','HHHHxx'
+1991,4774,1,3,1,11,91,991,1991,1991,1991,182,183,'PYAAAA','QBHAAA','OOOOxx'
+110,4775,0,2,0,10,10,110,110,110,110,20,21,'GEAAAA','RBHAAA','VVVVxx'
+9334,4776,0,2,4,14,34,334,1334,4334,9334,68,69,'AVAAAA','SBHAAA','AAAAxx'
+6231,4777,1,3,1,11,31,231,231,1231,6231,62,63,'RFAAAA','TBHAAA','HHHHxx'
+9871,4778,1,3,1,11,71,871,1871,4871,9871,142,143,'RPAAAA','UBHAAA','OOOOxx'
+9471,4779,1,3,1,11,71,471,1471,4471,9471,142,143,'HAAAAA','VBHAAA','VVVVxx'
+2697,4780,1,1,7,17,97,697,697,2697,2697,194,195,'TZAAAA','WBHAAA','AAAAxx'
+4761,4781,1,1,1,1,61,761,761,4761,4761,122,123,'DBAAAA','XBHAAA','HHHHxx'
+8493,4782,1,1,3,13,93,493,493,3493,8493,186,187,'ROAAAA','YBHAAA','OOOOxx'
+1045,4783,1,1,5,5,45,45,1045,1045,1045,90,91,'FOAAAA','ZBHAAA','VVVVxx'
+3403,4784,1,3,3,3,3,403,1403,3403,3403,6,7,'XAAAAA','ACHAAA','AAAAxx'
+9412,4785,0,0,2,12,12,412,1412,4412,9412,24,25,'AYAAAA','BCHAAA','HHHHxx'
+7652,4786,0,0,2,12,52,652,1652,2652,7652,104,105,'IIAAAA','CCHAAA','OOOOxx'
+5866,4787,0,2,6,6,66,866,1866,866,5866,132,133,'QRAAAA','DCHAAA','VVVVxx'
+6942,4788,0,2,2,2,42,942,942,1942,6942,84,85,'AHAAAA','ECHAAA','AAAAxx'
+9353,4789,1,1,3,13,53,353,1353,4353,9353,106,107,'TVAAAA','FCHAAA','HHHHxx'
+2600,4790,0,0,0,0,0,600,600,2600,2600,0,1,'AWAAAA','GCHAAA','OOOOxx'
+6971,4791,1,3,1,11,71,971,971,1971,6971,142,143,'DIAAAA','HCHAAA','VVVVxx'
+5391,4792,1,3,1,11,91,391,1391,391,5391,182,183,'JZAAAA','ICHAAA','AAAAxx'
+7654,4793,0,2,4,14,54,654,1654,2654,7654,108,109,'KIAAAA','JCHAAA','HHHHxx'
+1797,4794,1,1,7,17,97,797,1797,1797,1797,194,195,'DRAAAA','KCHAAA','OOOOxx'
+4530,4795,0,2,0,10,30,530,530,4530,4530,60,61,'GSAAAA','LCHAAA','VVVVxx'
+3130,4796,0,2,0,10,30,130,1130,3130,3130,60,61,'KQAAAA','MCHAAA','AAAAxx'
+9442,4797,0,2,2,2,42,442,1442,4442,9442,84,85,'EZAAAA','NCHAAA','HHHHxx'
+6659,4798,1,3,9,19,59,659,659,1659,6659,118,119,'DWAAAA','OCHAAA','OOOOxx'
+9714,4799,0,2,4,14,14,714,1714,4714,9714,28,29,'QJAAAA','PCHAAA','VVVVxx'
+3660,4800,0,0,0,0,60,660,1660,3660,3660,120,121,'UKAAAA','QCHAAA','AAAAxx'
+1906,4801,0,2,6,6,6,906,1906,1906,1906,12,13,'IVAAAA','RCHAAA','HHHHxx'
+7927,4802,1,3,7,7,27,927,1927,2927,7927,54,55,'XSAAAA','SCHAAA','OOOOxx'
+1767,4803,1,3,7,7,67,767,1767,1767,1767,134,135,'ZPAAAA','TCHAAA','VVVVxx'
+5523,4804,1,3,3,3,23,523,1523,523,5523,46,47,'LEAAAA','UCHAAA','AAAAxx'
+9289,4805,1,1,9,9,89,289,1289,4289,9289,178,179,'HTAAAA','VCHAAA','HHHHxx'
+2717,4806,1,1,7,17,17,717,717,2717,2717,34,35,'NAAAAA','WCHAAA','OOOOxx'
+4099,4807,1,3,9,19,99,99,99,4099,4099,198,199,'RBAAAA','XCHAAA','VVVVxx'
+4387,4808,1,3,7,7,87,387,387,4387,4387,174,175,'TMAAAA','YCHAAA','AAAAxx'
+8864,4809,0,0,4,4,64,864,864,3864,8864,128,129,'YCAAAA','ZCHAAA','HHHHxx'
+1774,4810,0,2,4,14,74,774,1774,1774,1774,148,149,'GQAAAA','ADHAAA','OOOOxx'
+6292,4811,0,0,2,12,92,292,292,1292,6292,184,185,'AIAAAA','BDHAAA','VVVVxx'
+847,4812,1,3,7,7,47,847,847,847,847,94,95,'PGAAAA','CDHAAA','AAAAxx'
+5954,4813,0,2,4,14,54,954,1954,954,5954,108,109,'AVAAAA','DDHAAA','HHHHxx'
+8032,4814,0,0,2,12,32,32,32,3032,8032,64,65,'YWAAAA','EDHAAA','OOOOxx'
+3295,4815,1,3,5,15,95,295,1295,3295,3295,190,191,'TWAAAA','FDHAAA','VVVVxx'
+8984,4816,0,0,4,4,84,984,984,3984,8984,168,169,'OHAAAA','GDHAAA','AAAAxx'
+7809,4817,1,1,9,9,9,809,1809,2809,7809,18,19,'JOAAAA','HDHAAA','HHHHxx'
+1670,4818,0,2,0,10,70,670,1670,1670,1670,140,141,'GMAAAA','IDHAAA','OOOOxx'
+7733,4819,1,1,3,13,33,733,1733,2733,7733,66,67,'LLAAAA','JDHAAA','VVVVxx'
+6187,4820,1,3,7,7,87,187,187,1187,6187,174,175,'ZDAAAA','KDHAAA','AAAAxx'
+9326,4821,0,2,6,6,26,326,1326,4326,9326,52,53,'SUAAAA','LDHAAA','HHHHxx'
+2493,4822,1,1,3,13,93,493,493,2493,2493,186,187,'XRAAAA','MDHAAA','OOOOxx'
+9512,4823,0,0,2,12,12,512,1512,4512,9512,24,25,'WBAAAA','NDHAAA','VVVVxx'
+4342,4824,0,2,2,2,42,342,342,4342,4342,84,85,'ALAAAA','ODHAAA','AAAAxx'
+5350,4825,0,2,0,10,50,350,1350,350,5350,100,101,'UXAAAA','PDHAAA','HHHHxx'
+6009,4826,1,1,9,9,9,9,9,1009,6009,18,19,'DXAAAA','QDHAAA','OOOOxx'
+1208,4827,0,0,8,8,8,208,1208,1208,1208,16,17,'MUAAAA','RDHAAA','VVVVxx'
+7014,4828,0,2,4,14,14,14,1014,2014,7014,28,29,'UJAAAA','SDHAAA','AAAAxx'
+2967,4829,1,3,7,7,67,967,967,2967,2967,134,135,'DKAAAA','TDHAAA','HHHHxx'
+5831,4830,1,3,1,11,31,831,1831,831,5831,62,63,'HQAAAA','UDHAAA','OOOOxx'
+3097,4831,1,1,7,17,97,97,1097,3097,3097,194,195,'DPAAAA','VDHAAA','VVVVxx'
+1528,4832,0,0,8,8,28,528,1528,1528,1528,56,57,'UGAAAA','WDHAAA','AAAAxx'
+6429,4833,1,1,9,9,29,429,429,1429,6429,58,59,'HNAAAA','XDHAAA','HHHHxx'
+7320,4834,0,0,0,0,20,320,1320,2320,7320,40,41,'OVAAAA','YDHAAA','OOOOxx'
+844,4835,0,0,4,4,44,844,844,844,844,88,89,'MGAAAA','ZDHAAA','VVVVxx'
+7054,4836,0,2,4,14,54,54,1054,2054,7054,108,109,'ILAAAA','AEHAAA','AAAAxx'
+1643,4837,1,3,3,3,43,643,1643,1643,1643,86,87,'FLAAAA','BEHAAA','HHHHxx'
+7626,4838,0,2,6,6,26,626,1626,2626,7626,52,53,'IHAAAA','CEHAAA','OOOOxx'
+8728,4839,0,0,8,8,28,728,728,3728,8728,56,57,'SXAAAA','DEHAAA','VVVVxx'
+8277,4840,1,1,7,17,77,277,277,3277,8277,154,155,'JGAAAA','EEHAAA','AAAAxx'
+189,4841,1,1,9,9,89,189,189,189,189,178,179,'HHAAAA','FEHAAA','HHHHxx'
+3717,4842,1,1,7,17,17,717,1717,3717,3717,34,35,'ZMAAAA','GEHAAA','OOOOxx'
+1020,4843,0,0,0,0,20,20,1020,1020,1020,40,41,'GNAAAA','HEHAAA','VVVVxx'
+9234,4844,0,2,4,14,34,234,1234,4234,9234,68,69,'ERAAAA','IEHAAA','AAAAxx'
+9541,4845,1,1,1,1,41,541,1541,4541,9541,82,83,'ZCAAAA','JEHAAA','HHHHxx'
+380,4846,0,0,0,0,80,380,380,380,380,160,161,'QOAAAA','KEHAAA','OOOOxx'
+397,4847,1,1,7,17,97,397,397,397,397,194,195,'HPAAAA','LEHAAA','VVVVxx'
+835,4848,1,3,5,15,35,835,835,835,835,70,71,'DGAAAA','MEHAAA','AAAAxx'
+347,4849,1,3,7,7,47,347,347,347,347,94,95,'JNAAAA','NEHAAA','HHHHxx'
+2490,4850,0,2,0,10,90,490,490,2490,2490,180,181,'URAAAA','OEHAAA','OOOOxx'
+605,4851,1,1,5,5,5,605,605,605,605,10,11,'HXAAAA','PEHAAA','VVVVxx'
+7960,4852,0,0,0,0,60,960,1960,2960,7960,120,121,'EUAAAA','QEHAAA','AAAAxx'
+9681,4853,1,1,1,1,81,681,1681,4681,9681,162,163,'JIAAAA','REHAAA','HHHHxx'
+5753,4854,1,1,3,13,53,753,1753,753,5753,106,107,'HNAAAA','SEHAAA','OOOOxx'
+1676,4855,0,0,6,16,76,676,1676,1676,1676,152,153,'MMAAAA','TEHAAA','VVVVxx'
+5533,4856,1,1,3,13,33,533,1533,533,5533,66,67,'VEAAAA','UEHAAA','AAAAxx'
+8958,4857,0,2,8,18,58,958,958,3958,8958,116,117,'OGAAAA','VEHAAA','HHHHxx'
+664,4858,0,0,4,4,64,664,664,664,664,128,129,'OZAAAA','WEHAAA','OOOOxx'
+3005,4859,1,1,5,5,5,5,1005,3005,3005,10,11,'PLAAAA','XEHAAA','VVVVxx'
+8576,4860,0,0,6,16,76,576,576,3576,8576,152,153,'WRAAAA','YEHAAA','AAAAxx'
+7304,4861,0,0,4,4,4,304,1304,2304,7304,8,9,'YUAAAA','ZEHAAA','HHHHxx'
+3375,4862,1,3,5,15,75,375,1375,3375,3375,150,151,'VZAAAA','AFHAAA','OOOOxx'
+6336,4863,0,0,6,16,36,336,336,1336,6336,72,73,'SJAAAA','BFHAAA','VVVVxx'
+1392,4864,0,0,2,12,92,392,1392,1392,1392,184,185,'OBAAAA','CFHAAA','AAAAxx'
+2925,4865,1,1,5,5,25,925,925,2925,2925,50,51,'NIAAAA','DFHAAA','HHHHxx'
+1217,4866,1,1,7,17,17,217,1217,1217,1217,34,35,'VUAAAA','EFHAAA','OOOOxx'
+3714,4867,0,2,4,14,14,714,1714,3714,3714,28,29,'WMAAAA','FFHAAA','VVVVxx'
+2120,4868,0,0,0,0,20,120,120,2120,2120,40,41,'ODAAAA','GFHAAA','AAAAxx'
+2845,4869,1,1,5,5,45,845,845,2845,2845,90,91,'LFAAAA','HFHAAA','HHHHxx'
+3865,4870,1,1,5,5,65,865,1865,3865,3865,130,131,'RSAAAA','IFHAAA','OOOOxx'
+124,4871,0,0,4,4,24,124,124,124,124,48,49,'UEAAAA','JFHAAA','VVVVxx'
+865,4872,1,1,5,5,65,865,865,865,865,130,131,'HHAAAA','KFHAAA','AAAAxx'
+9361,4873,1,1,1,1,61,361,1361,4361,9361,122,123,'BWAAAA','LFHAAA','HHHHxx'
+6338,4874,0,2,8,18,38,338,338,1338,6338,76,77,'UJAAAA','MFHAAA','OOOOxx'
+7330,4875,0,2,0,10,30,330,1330,2330,7330,60,61,'YVAAAA','NFHAAA','VVVVxx'
+513,4876,1,1,3,13,13,513,513,513,513,26,27,'TTAAAA','OFHAAA','AAAAxx'
+5001,4877,1,1,1,1,1,1,1001,1,5001,2,3,'JKAAAA','PFHAAA','HHHHxx'
+549,4878,1,1,9,9,49,549,549,549,549,98,99,'DVAAAA','QFHAAA','OOOOxx'
+1808,4879,0,0,8,8,8,808,1808,1808,1808,16,17,'ORAAAA','RFHAAA','VVVVxx'
+7168,4880,0,0,8,8,68,168,1168,2168,7168,136,137,'SPAAAA','SFHAAA','AAAAxx'
+9878,4881,0,2,8,18,78,878,1878,4878,9878,156,157,'YPAAAA','TFHAAA','HHHHxx'
+233,4882,1,1,3,13,33,233,233,233,233,66,67,'ZIAAAA','UFHAAA','OOOOxx'
+4262,4883,0,2,2,2,62,262,262,4262,4262,124,125,'YHAAAA','VFHAAA','VVVVxx'
+7998,4884,0,2,8,18,98,998,1998,2998,7998,196,197,'QVAAAA','WFHAAA','AAAAxx'
+2419,4885,1,3,9,19,19,419,419,2419,2419,38,39,'BPAAAA','XFHAAA','HHHHxx'
+9960,4886,0,0,0,0,60,960,1960,4960,9960,120,121,'CTAAAA','YFHAAA','OOOOxx'
+3523,4887,1,3,3,3,23,523,1523,3523,3523,46,47,'NFAAAA','ZFHAAA','VVVVxx'
+5440,4888,0,0,0,0,40,440,1440,440,5440,80,81,'GBAAAA','AGHAAA','AAAAxx'
+3030,4889,0,2,0,10,30,30,1030,3030,3030,60,61,'OMAAAA','BGHAAA','HHHHxx'
+2745,4890,1,1,5,5,45,745,745,2745,2745,90,91,'PBAAAA','CGHAAA','OOOOxx'
+7175,4891,1,3,5,15,75,175,1175,2175,7175,150,151,'ZPAAAA','DGHAAA','VVVVxx'
+640,4892,0,0,0,0,40,640,640,640,640,80,81,'QYAAAA','EGHAAA','AAAAxx'
+1798,4893,0,2,8,18,98,798,1798,1798,1798,196,197,'ERAAAA','FGHAAA','HHHHxx'
+7499,4894,1,3,9,19,99,499,1499,2499,7499,198,199,'LCAAAA','GGHAAA','OOOOxx'
+1924,4895,0,0,4,4,24,924,1924,1924,1924,48,49,'AWAAAA','HGHAAA','VVVVxx'
+1327,4896,1,3,7,7,27,327,1327,1327,1327,54,55,'BZAAAA','IGHAAA','AAAAxx'
+73,4897,1,1,3,13,73,73,73,73,73,146,147,'VCAAAA','JGHAAA','HHHHxx'
+9558,4898,0,2,8,18,58,558,1558,4558,9558,116,117,'QDAAAA','KGHAAA','OOOOxx'
+818,4899,0,2,8,18,18,818,818,818,818,36,37,'MFAAAA','LGHAAA','VVVVxx'
+9916,4900,0,0,6,16,16,916,1916,4916,9916,32,33,'KRAAAA','MGHAAA','AAAAxx'
+2978,4901,0,2,8,18,78,978,978,2978,2978,156,157,'OKAAAA','NGHAAA','HHHHxx'
+8469,4902,1,1,9,9,69,469,469,3469,8469,138,139,'TNAAAA','OGHAAA','OOOOxx'
+9845,4903,1,1,5,5,45,845,1845,4845,9845,90,91,'ROAAAA','PGHAAA','VVVVxx'
+2326,4904,0,2,6,6,26,326,326,2326,2326,52,53,'MLAAAA','QGHAAA','AAAAxx'
+4032,4905,0,0,2,12,32,32,32,4032,4032,64,65,'CZAAAA','RGHAAA','HHHHxx'
+5604,4906,0,0,4,4,4,604,1604,604,5604,8,9,'OHAAAA','SGHAAA','OOOOxx'
+9610,4907,0,2,0,10,10,610,1610,4610,9610,20,21,'QFAAAA','TGHAAA','VVVVxx'
+5101,4908,1,1,1,1,1,101,1101,101,5101,2,3,'FOAAAA','UGHAAA','AAAAxx'
+7246,4909,0,2,6,6,46,246,1246,2246,7246,92,93,'SSAAAA','VGHAAA','HHHHxx'
+1292,4910,0,0,2,12,92,292,1292,1292,1292,184,185,'SXAAAA','WGHAAA','OOOOxx'
+6235,4911,1,3,5,15,35,235,235,1235,6235,70,71,'VFAAAA','XGHAAA','VVVVxx'
+1733,4912,1,1,3,13,33,733,1733,1733,1733,66,67,'ROAAAA','YGHAAA','AAAAxx'
+4647,4913,1,3,7,7,47,647,647,4647,4647,94,95,'TWAAAA','ZGHAAA','HHHHxx'
+258,4914,0,2,8,18,58,258,258,258,258,116,117,'YJAAAA','AHHAAA','OOOOxx'
+8438,4915,0,2,8,18,38,438,438,3438,8438,76,77,'OMAAAA','BHHAAA','VVVVxx'
+7869,4916,1,1,9,9,69,869,1869,2869,7869,138,139,'RQAAAA','CHHAAA','AAAAxx'
+9691,4917,1,3,1,11,91,691,1691,4691,9691,182,183,'TIAAAA','DHHAAA','HHHHxx'
+5422,4918,0,2,2,2,22,422,1422,422,5422,44,45,'OAAAAA','EHHAAA','OOOOxx'
+9630,4919,0,2,0,10,30,630,1630,4630,9630,60,61,'KGAAAA','FHHAAA','VVVVxx'
+4439,4920,1,3,9,19,39,439,439,4439,4439,78,79,'TOAAAA','GHHAAA','AAAAxx'
+3140,4921,0,0,0,0,40,140,1140,3140,3140,80,81,'UQAAAA','HHHAAA','HHHHxx'
+9111,4922,1,3,1,11,11,111,1111,4111,9111,22,23,'LMAAAA','IHHAAA','OOOOxx'
+4606,4923,0,2,6,6,6,606,606,4606,4606,12,13,'EVAAAA','JHHAAA','VVVVxx'
+8620,4924,0,0,0,0,20,620,620,3620,8620,40,41,'OTAAAA','KHHAAA','AAAAxx'
+7849,4925,1,1,9,9,49,849,1849,2849,7849,98,99,'XPAAAA','LHHAAA','HHHHxx'
+346,4926,0,2,6,6,46,346,346,346,346,92,93,'INAAAA','MHHAAA','OOOOxx'
+9528,4927,0,0,8,8,28,528,1528,4528,9528,56,57,'MCAAAA','NHHAAA','VVVVxx'
+1811,4928,1,3,1,11,11,811,1811,1811,1811,22,23,'RRAAAA','OHHAAA','AAAAxx'
+6068,4929,0,0,8,8,68,68,68,1068,6068,136,137,'KZAAAA','PHHAAA','HHHHxx'
+6260,4930,0,0,0,0,60,260,260,1260,6260,120,121,'UGAAAA','QHHAAA','OOOOxx'
+5909,4931,1,1,9,9,9,909,1909,909,5909,18,19,'HTAAAA','RHHAAA','VVVVxx'
+4518,4932,0,2,8,18,18,518,518,4518,4518,36,37,'URAAAA','SHHAAA','AAAAxx'
+7530,4933,0,2,0,10,30,530,1530,2530,7530,60,61,'QDAAAA','THHAAA','HHHHxx'
+3900,4934,0,0,0,0,0,900,1900,3900,3900,0,1,'AUAAAA','UHHAAA','OOOOxx'
+3969,4935,1,1,9,9,69,969,1969,3969,3969,138,139,'RWAAAA','VHHAAA','VVVVxx'
+8690,4936,0,2,0,10,90,690,690,3690,8690,180,181,'GWAAAA','WHHAAA','AAAAxx'
+5532,4937,0,0,2,12,32,532,1532,532,5532,64,65,'UEAAAA','XHHAAA','HHHHxx'
+5989,4938,1,1,9,9,89,989,1989,989,5989,178,179,'JWAAAA','YHHAAA','OOOOxx'
+1870,4939,0,2,0,10,70,870,1870,1870,1870,140,141,'YTAAAA','ZHHAAA','VVVVxx'
+1113,4940,1,1,3,13,13,113,1113,1113,1113,26,27,'VQAAAA','AIHAAA','AAAAxx'
+5155,4941,1,3,5,15,55,155,1155,155,5155,110,111,'HQAAAA','BIHAAA','HHHHxx'
+7460,4942,0,0,0,0,60,460,1460,2460,7460,120,121,'YAAAAA','CIHAAA','OOOOxx'
+6217,4943,1,1,7,17,17,217,217,1217,6217,34,35,'DFAAAA','DIHAAA','VVVVxx'
+8333,4944,1,1,3,13,33,333,333,3333,8333,66,67,'NIAAAA','EIHAAA','AAAAxx'
+6341,4945,1,1,1,1,41,341,341,1341,6341,82,83,'XJAAAA','FIHAAA','HHHHxx'
+6230,4946,0,2,0,10,30,230,230,1230,6230,60,61,'QFAAAA','GIHAAA','OOOOxx'
+6902,4947,0,2,2,2,2,902,902,1902,6902,4,5,'MFAAAA','HIHAAA','VVVVxx'
+670,4948,0,2,0,10,70,670,670,670,670,140,141,'UZAAAA','IIHAAA','AAAAxx'
+805,4949,1,1,5,5,5,805,805,805,805,10,11,'ZEAAAA','JIHAAA','HHHHxx'
+1340,4950,0,0,0,0,40,340,1340,1340,1340,80,81,'OZAAAA','KIHAAA','OOOOxx'
+8649,4951,1,1,9,9,49,649,649,3649,8649,98,99,'RUAAAA','LIHAAA','VVVVxx'
+3887,4952,1,3,7,7,87,887,1887,3887,3887,174,175,'NTAAAA','MIHAAA','AAAAxx'
+5400,4953,0,0,0,0,0,400,1400,400,5400,0,1,'SZAAAA','NIHAAA','HHHHxx'
+4354,4954,0,2,4,14,54,354,354,4354,4354,108,109,'MLAAAA','OIHAAA','OOOOxx'
+950,4955,0,2,0,10,50,950,950,950,950,100,101,'OKAAAA','PIHAAA','VVVVxx'
+1544,4956,0,0,4,4,44,544,1544,1544,1544,88,89,'KHAAAA','QIHAAA','AAAAxx'
+3898,4957,0,2,8,18,98,898,1898,3898,3898,196,197,'YTAAAA','RIHAAA','HHHHxx'
+8038,4958,0,2,8,18,38,38,38,3038,8038,76,77,'EXAAAA','SIHAAA','OOOOxx'
+1095,4959,1,3,5,15,95,95,1095,1095,1095,190,191,'DQAAAA','TIHAAA','VVVVxx'
+1748,4960,0,0,8,8,48,748,1748,1748,1748,96,97,'GPAAAA','UIHAAA','AAAAxx'
+9154,4961,0,2,4,14,54,154,1154,4154,9154,108,109,'COAAAA','VIHAAA','HHHHxx'
+2182,4962,0,2,2,2,82,182,182,2182,2182,164,165,'YFAAAA','WIHAAA','OOOOxx'
+6797,4963,1,1,7,17,97,797,797,1797,6797,194,195,'LBAAAA','XIHAAA','VVVVxx'
+9149,4964,1,1,9,9,49,149,1149,4149,9149,98,99,'XNAAAA','YIHAAA','AAAAxx'
+7351,4965,1,3,1,11,51,351,1351,2351,7351,102,103,'TWAAAA','ZIHAAA','HHHHxx'
+2820,4966,0,0,0,0,20,820,820,2820,2820,40,41,'MEAAAA','AJHAAA','OOOOxx'
+9696,4967,0,0,6,16,96,696,1696,4696,9696,192,193,'YIAAAA','BJHAAA','VVVVxx'
+253,4968,1,1,3,13,53,253,253,253,253,106,107,'TJAAAA','CJHAAA','AAAAxx'
+3600,4969,0,0,0,0,0,600,1600,3600,3600,0,1,'MIAAAA','DJHAAA','HHHHxx'
+3892,4970,0,0,2,12,92,892,1892,3892,3892,184,185,'STAAAA','EJHAAA','OOOOxx'
+231,4971,1,3,1,11,31,231,231,231,231,62,63,'XIAAAA','FJHAAA','VVVVxx'
+8331,4972,1,3,1,11,31,331,331,3331,8331,62,63,'LIAAAA','GJHAAA','AAAAxx'
+403,4973,1,3,3,3,3,403,403,403,403,6,7,'NPAAAA','HJHAAA','HHHHxx'
+8642,4974,0,2,2,2,42,642,642,3642,8642,84,85,'KUAAAA','IJHAAA','OOOOxx'
+3118,4975,0,2,8,18,18,118,1118,3118,3118,36,37,'YPAAAA','JJHAAA','VVVVxx'
+3835,4976,1,3,5,15,35,835,1835,3835,3835,70,71,'NRAAAA','KJHAAA','AAAAxx'
+1117,4977,1,1,7,17,17,117,1117,1117,1117,34,35,'ZQAAAA','LJHAAA','HHHHxx'
+7024,4978,0,0,4,4,24,24,1024,2024,7024,48,49,'EKAAAA','MJHAAA','OOOOxx'
+2636,4979,0,0,6,16,36,636,636,2636,2636,72,73,'KXAAAA','NJHAAA','VVVVxx'
+3778,4980,0,2,8,18,78,778,1778,3778,3778,156,157,'IPAAAA','OJHAAA','AAAAxx'
+2003,4981,1,3,3,3,3,3,3,2003,2003,6,7,'BZAAAA','PJHAAA','HHHHxx'
+5717,4982,1,1,7,17,17,717,1717,717,5717,34,35,'XLAAAA','QJHAAA','OOOOxx'
+4869,4983,1,1,9,9,69,869,869,4869,4869,138,139,'HFAAAA','RJHAAA','VVVVxx'
+8921,4984,1,1,1,1,21,921,921,3921,8921,42,43,'DFAAAA','SJHAAA','AAAAxx'
+888,4985,0,0,8,8,88,888,888,888,888,176,177,'EIAAAA','TJHAAA','HHHHxx'
+7599,4986,1,3,9,19,99,599,1599,2599,7599,198,199,'HGAAAA','UJHAAA','OOOOxx'
+8621,4987,1,1,1,1,21,621,621,3621,8621,42,43,'PTAAAA','VJHAAA','VVVVxx'
+811,4988,1,3,1,11,11,811,811,811,811,22,23,'FFAAAA','WJHAAA','AAAAxx'
+9147,4989,1,3,7,7,47,147,1147,4147,9147,94,95,'VNAAAA','XJHAAA','HHHHxx'
+1413,4990,1,1,3,13,13,413,1413,1413,1413,26,27,'JCAAAA','YJHAAA','OOOOxx'
+5232,4991,0,0,2,12,32,232,1232,232,5232,64,65,'GTAAAA','ZJHAAA','VVVVxx'
+5912,4992,0,0,2,12,12,912,1912,912,5912,24,25,'KTAAAA','AKHAAA','AAAAxx'
+3418,4993,0,2,8,18,18,418,1418,3418,3418,36,37,'MBAAAA','BKHAAA','HHHHxx'
+3912,4994,0,0,2,12,12,912,1912,3912,3912,24,25,'MUAAAA','CKHAAA','OOOOxx'
+9576,4995,0,0,6,16,76,576,1576,4576,9576,152,153,'IEAAAA','DKHAAA','VVVVxx'
+4225,4996,1,1,5,5,25,225,225,4225,4225,50,51,'NGAAAA','EKHAAA','AAAAxx'
+8222,4997,0,2,2,2,22,222,222,3222,8222,44,45,'GEAAAA','FKHAAA','HHHHxx'
+7013,4998,1,1,3,13,13,13,1013,2013,7013,26,27,'TJAAAA','GKHAAA','OOOOxx'
+7037,4999,1,1,7,17,37,37,1037,2037,7037,74,75,'RKAAAA','HKHAAA','VVVVxx'
+1205,5000,1,1,5,5,5,205,1205,1205,1205,10,11,'JUAAAA','IKHAAA','AAAAxx'
+8114,5001,0,2,4,14,14,114,114,3114,8114,28,29,'CAAAAA','JKHAAA','HHHHxx'
+6585,5002,1,1,5,5,85,585,585,1585,6585,170,171,'HTAAAA','KKHAAA','OOOOxx'
+155,5003,1,3,5,15,55,155,155,155,155,110,111,'ZFAAAA','LKHAAA','VVVVxx'
+2841,5004,1,1,1,1,41,841,841,2841,2841,82,83,'HFAAAA','MKHAAA','AAAAxx'
+1996,5005,0,0,6,16,96,996,1996,1996,1996,192,193,'UYAAAA','NKHAAA','HHHHxx'
+4948,5006,0,0,8,8,48,948,948,4948,4948,96,97,'IIAAAA','OKHAAA','OOOOxx'
+3304,5007,0,0,4,4,4,304,1304,3304,3304,8,9,'CXAAAA','PKHAAA','VVVVxx'
+5684,5008,0,0,4,4,84,684,1684,684,5684,168,169,'QKAAAA','QKHAAA','AAAAxx'
+6962,5009,0,2,2,2,62,962,962,1962,6962,124,125,'UHAAAA','RKHAAA','HHHHxx'
+8691,5010,1,3,1,11,91,691,691,3691,8691,182,183,'HWAAAA','SKHAAA','OOOOxx'
+8501,5011,1,1,1,1,1,501,501,3501,8501,2,3,'ZOAAAA','TKHAAA','VVVVxx'
+4783,5012,1,3,3,3,83,783,783,4783,4783,166,167,'ZBAAAA','UKHAAA','AAAAxx'
+3762,5013,0,2,2,2,62,762,1762,3762,3762,124,125,'SOAAAA','VKHAAA','HHHHxx'
+4534,5014,0,2,4,14,34,534,534,4534,4534,68,69,'KSAAAA','WKHAAA','OOOOxx'
+4999,5015,1,3,9,19,99,999,999,4999,4999,198,199,'HKAAAA','XKHAAA','VVVVxx'
+4618,5016,0,2,8,18,18,618,618,4618,4618,36,37,'QVAAAA','YKHAAA','AAAAxx'
+4220,5017,0,0,0,0,20,220,220,4220,4220,40,41,'IGAAAA','ZKHAAA','HHHHxx'
+3384,5018,0,0,4,4,84,384,1384,3384,3384,168,169,'EAAAAA','ALHAAA','OOOOxx'
+3036,5019,0,0,6,16,36,36,1036,3036,3036,72,73,'UMAAAA','BLHAAA','VVVVxx'
+545,5020,1,1,5,5,45,545,545,545,545,90,91,'ZUAAAA','CLHAAA','AAAAxx'
+9946,5021,0,2,6,6,46,946,1946,4946,9946,92,93,'OSAAAA','DLHAAA','HHHHxx'
+1985,5022,1,1,5,5,85,985,1985,1985,1985,170,171,'JYAAAA','ELHAAA','OOOOxx'
+2310,5023,0,2,0,10,10,310,310,2310,2310,20,21,'WKAAAA','FLHAAA','VVVVxx'
+6563,5024,1,3,3,3,63,563,563,1563,6563,126,127,'LSAAAA','GLHAAA','AAAAxx'
+4886,5025,0,2,6,6,86,886,886,4886,4886,172,173,'YFAAAA','HLHAAA','HHHHxx'
+9359,5026,1,3,9,19,59,359,1359,4359,9359,118,119,'ZVAAAA','ILHAAA','OOOOxx'
+400,5027,0,0,0,0,0,400,400,400,400,0,1,'KPAAAA','JLHAAA','VVVVxx'
+9742,5028,0,2,2,2,42,742,1742,4742,9742,84,85,'SKAAAA','KLHAAA','AAAAxx'
+6736,5029,0,0,6,16,36,736,736,1736,6736,72,73,'CZAAAA','LLHAAA','HHHHxx'
+8166,5030,0,2,6,6,66,166,166,3166,8166,132,133,'CCAAAA','MLHAAA','OOOOxx'
+861,5031,1,1,1,1,61,861,861,861,861,122,123,'DHAAAA','NLHAAA','VVVVxx'
+7492,5032,0,0,2,12,92,492,1492,2492,7492,184,185,'ECAAAA','OLHAAA','AAAAxx'
+1155,5033,1,3,5,15,55,155,1155,1155,1155,110,111,'LSAAAA','PLHAAA','HHHHxx'
+9769,5034,1,1,9,9,69,769,1769,4769,9769,138,139,'TLAAAA','QLHAAA','OOOOxx'
+6843,5035,1,3,3,3,43,843,843,1843,6843,86,87,'FDAAAA','RLHAAA','VVVVxx'
+5625,5036,1,1,5,5,25,625,1625,625,5625,50,51,'JIAAAA','SLHAAA','AAAAxx'
+1910,5037,0,2,0,10,10,910,1910,1910,1910,20,21,'MVAAAA','TLHAAA','HHHHxx'
+9796,5038,0,0,6,16,96,796,1796,4796,9796,192,193,'UMAAAA','ULHAAA','OOOOxx'
+6950,5039,0,2,0,10,50,950,950,1950,6950,100,101,'IHAAAA','VLHAAA','VVVVxx'
+3084,5040,0,0,4,4,84,84,1084,3084,3084,168,169,'QOAAAA','WLHAAA','AAAAxx'
+2959,5041,1,3,9,19,59,959,959,2959,2959,118,119,'VJAAAA','XLHAAA','HHHHxx'
+2093,5042,1,1,3,13,93,93,93,2093,2093,186,187,'NCAAAA','YLHAAA','OOOOxx'
+2738,5043,0,2,8,18,38,738,738,2738,2738,76,77,'IBAAAA','ZLHAAA','VVVVxx'
+6406,5044,0,2,6,6,6,406,406,1406,6406,12,13,'KMAAAA','AMHAAA','AAAAxx'
+9082,5045,0,2,2,2,82,82,1082,4082,9082,164,165,'ILAAAA','BMHAAA','HHHHxx'
+8568,5046,0,0,8,8,68,568,568,3568,8568,136,137,'ORAAAA','CMHAAA','OOOOxx'
+3566,5047,0,2,6,6,66,566,1566,3566,3566,132,133,'EHAAAA','DMHAAA','VVVVxx'
+3016,5048,0,0,6,16,16,16,1016,3016,3016,32,33,'AMAAAA','EMHAAA','AAAAxx'
+1207,5049,1,3,7,7,7,207,1207,1207,1207,14,15,'LUAAAA','FMHAAA','HHHHxx'
+4045,5050,1,1,5,5,45,45,45,4045,4045,90,91,'PZAAAA','GMHAAA','OOOOxx'
+4173,5051,1,1,3,13,73,173,173,4173,4173,146,147,'NEAAAA','HMHAAA','VVVVxx'
+3939,5052,1,3,9,19,39,939,1939,3939,3939,78,79,'NVAAAA','IMHAAA','AAAAxx'
+9683,5053,1,3,3,3,83,683,1683,4683,9683,166,167,'LIAAAA','JMHAAA','HHHHxx'
+1684,5054,0,0,4,4,84,684,1684,1684,1684,168,169,'UMAAAA','KMHAAA','OOOOxx'
+9271,5055,1,3,1,11,71,271,1271,4271,9271,142,143,'PSAAAA','LMHAAA','VVVVxx'
+9317,5056,1,1,7,17,17,317,1317,4317,9317,34,35,'JUAAAA','MMHAAA','AAAAxx'
+5793,5057,1,1,3,13,93,793,1793,793,5793,186,187,'VOAAAA','NMHAAA','HHHHxx'
+352,5058,0,0,2,12,52,352,352,352,352,104,105,'ONAAAA','OMHAAA','OOOOxx'
+7328,5059,0,0,8,8,28,328,1328,2328,7328,56,57,'WVAAAA','PMHAAA','VVVVxx'
+4582,5060,0,2,2,2,82,582,582,4582,4582,164,165,'GUAAAA','QMHAAA','AAAAxx'
+7413,5061,1,1,3,13,13,413,1413,2413,7413,26,27,'DZAAAA','RMHAAA','HHHHxx'
+6772,5062,0,0,2,12,72,772,772,1772,6772,144,145,'MAAAAA','SMHAAA','OOOOxx'
+4973,5063,1,1,3,13,73,973,973,4973,4973,146,147,'HJAAAA','TMHAAA','VVVVxx'
+7480,5064,0,0,0,0,80,480,1480,2480,7480,160,161,'SBAAAA','UMHAAA','AAAAxx'
+5555,5065,1,3,5,15,55,555,1555,555,5555,110,111,'RFAAAA','VMHAAA','HHHHxx'
+4227,5066,1,3,7,7,27,227,227,4227,4227,54,55,'PGAAAA','WMHAAA','OOOOxx'
+4153,5067,1,1,3,13,53,153,153,4153,4153,106,107,'TDAAAA','XMHAAA','VVVVxx'
+4601,5068,1,1,1,1,1,601,601,4601,4601,2,3,'ZUAAAA','YMHAAA','AAAAxx'
+3782,5069,0,2,2,2,82,782,1782,3782,3782,164,165,'MPAAAA','ZMHAAA','HHHHxx'
+3872,5070,0,0,2,12,72,872,1872,3872,3872,144,145,'YSAAAA','ANHAAA','OOOOxx'
+893,5071,1,1,3,13,93,893,893,893,893,186,187,'JIAAAA','BNHAAA','VVVVxx'
+2430,5072,0,2,0,10,30,430,430,2430,2430,60,61,'MPAAAA','CNHAAA','AAAAxx'
+2591,5073,1,3,1,11,91,591,591,2591,2591,182,183,'RVAAAA','DNHAAA','HHHHxx'
+264,5074,0,0,4,4,64,264,264,264,264,128,129,'EKAAAA','ENHAAA','OOOOxx'
+6238,5075,0,2,8,18,38,238,238,1238,6238,76,77,'YFAAAA','FNHAAA','VVVVxx'
+633,5076,1,1,3,13,33,633,633,633,633,66,67,'JYAAAA','GNHAAA','AAAAxx'
+1029,5077,1,1,9,9,29,29,1029,1029,1029,58,59,'PNAAAA','HNHAAA','HHHHxx'
+5934,5078,0,2,4,14,34,934,1934,934,5934,68,69,'GUAAAA','INHAAA','OOOOxx'
+8694,5079,0,2,4,14,94,694,694,3694,8694,188,189,'KWAAAA','JNHAAA','VVVVxx'
+7401,5080,1,1,1,1,1,401,1401,2401,7401,2,3,'RYAAAA','KNHAAA','AAAAxx'
+1165,5081,1,1,5,5,65,165,1165,1165,1165,130,131,'VSAAAA','LNHAAA','HHHHxx'
+9438,5082,0,2,8,18,38,438,1438,4438,9438,76,77,'AZAAAA','MNHAAA','OOOOxx'
+4790,5083,0,2,0,10,90,790,790,4790,4790,180,181,'GCAAAA','NNHAAA','VVVVxx'
+4531,5084,1,3,1,11,31,531,531,4531,4531,62,63,'HSAAAA','ONHAAA','AAAAxx'
+6099,5085,1,3,9,19,99,99,99,1099,6099,198,199,'PAAAAA','PNHAAA','HHHHxx'
+8236,5086,0,0,6,16,36,236,236,3236,8236,72,73,'UEAAAA','QNHAAA','OOOOxx'
+8551,5087,1,3,1,11,51,551,551,3551,8551,102,103,'XQAAAA','RNHAAA','VVVVxx'
+3128,5088,0,0,8,8,28,128,1128,3128,3128,56,57,'IQAAAA','SNHAAA','AAAAxx'
+3504,5089,0,0,4,4,4,504,1504,3504,3504,8,9,'UEAAAA','TNHAAA','HHHHxx'
+9071,5090,1,3,1,11,71,71,1071,4071,9071,142,143,'XKAAAA','UNHAAA','OOOOxx'
+5930,5091,0,2,0,10,30,930,1930,930,5930,60,61,'CUAAAA','VNHAAA','VVVVxx'
+6825,5092,1,1,5,5,25,825,825,1825,6825,50,51,'NCAAAA','WNHAAA','AAAAxx'
+2218,5093,0,2,8,18,18,218,218,2218,2218,36,37,'IHAAAA','XNHAAA','HHHHxx'
+3604,5094,0,0,4,4,4,604,1604,3604,3604,8,9,'QIAAAA','YNHAAA','OOOOxx'
+5761,5095,1,1,1,1,61,761,1761,761,5761,122,123,'PNAAAA','ZNHAAA','VVVVxx'
+5414,5096,0,2,4,14,14,414,1414,414,5414,28,29,'GAAAAA','AOHAAA','AAAAxx'
+5892,5097,0,0,2,12,92,892,1892,892,5892,184,185,'QSAAAA','BOHAAA','HHHHxx'
+4080,5098,0,0,0,0,80,80,80,4080,4080,160,161,'YAAAAA','COHAAA','OOOOxx'
+8018,5099,0,2,8,18,18,18,18,3018,8018,36,37,'KWAAAA','DOHAAA','VVVVxx'
+1757,5100,1,1,7,17,57,757,1757,1757,1757,114,115,'PPAAAA','EOHAAA','AAAAxx'
+5854,5101,0,2,4,14,54,854,1854,854,5854,108,109,'ERAAAA','FOHAAA','HHHHxx'
+1335,5102,1,3,5,15,35,335,1335,1335,1335,70,71,'JZAAAA','GOHAAA','OOOOxx'
+3811,5103,1,3,1,11,11,811,1811,3811,3811,22,23,'PQAAAA','HOHAAA','VVVVxx'
+9917,5104,1,1,7,17,17,917,1917,4917,9917,34,35,'LRAAAA','IOHAAA','AAAAxx'
+5947,5105,1,3,7,7,47,947,1947,947,5947,94,95,'TUAAAA','JOHAAA','HHHHxx'
+7263,5106,1,3,3,3,63,263,1263,2263,7263,126,127,'JTAAAA','KOHAAA','OOOOxx'
+1730,5107,0,2,0,10,30,730,1730,1730,1730,60,61,'OOAAAA','LOHAAA','VVVVxx'
+5747,5108,1,3,7,7,47,747,1747,747,5747,94,95,'BNAAAA','MOHAAA','AAAAxx'
+3876,5109,0,0,6,16,76,876,1876,3876,3876,152,153,'CTAAAA','NOHAAA','HHHHxx'
+2762,5110,0,2,2,2,62,762,762,2762,2762,124,125,'GCAAAA','OOHAAA','OOOOxx'
+7613,5111,1,1,3,13,13,613,1613,2613,7613,26,27,'VGAAAA','POHAAA','VVVVxx'
+152,5112,0,0,2,12,52,152,152,152,152,104,105,'WFAAAA','QOHAAA','AAAAxx'
+3941,5113,1,1,1,1,41,941,1941,3941,3941,82,83,'PVAAAA','ROHAAA','HHHHxx'
+5614,5114,0,2,4,14,14,614,1614,614,5614,28,29,'YHAAAA','SOHAAA','OOOOxx'
+9279,5115,1,3,9,19,79,279,1279,4279,9279,158,159,'XSAAAA','TOHAAA','VVVVxx'
+3048,5116,0,0,8,8,48,48,1048,3048,3048,96,97,'GNAAAA','UOHAAA','AAAAxx'
+6152,5117,0,0,2,12,52,152,152,1152,6152,104,105,'QCAAAA','VOHAAA','HHHHxx'
+5481,5118,1,1,1,1,81,481,1481,481,5481,162,163,'VCAAAA','WOHAAA','OOOOxx'
+4675,5119,1,3,5,15,75,675,675,4675,4675,150,151,'VXAAAA','XOHAAA','VVVVxx'
+3334,5120,0,2,4,14,34,334,1334,3334,3334,68,69,'GYAAAA','YOHAAA','AAAAxx'
+4691,5121,1,3,1,11,91,691,691,4691,4691,182,183,'LYAAAA','ZOHAAA','HHHHxx'
+803,5122,1,3,3,3,3,803,803,803,803,6,7,'XEAAAA','APHAAA','OOOOxx'
+5409,5123,1,1,9,9,9,409,1409,409,5409,18,19,'BAAAAA','BPHAAA','VVVVxx'
+1054,5124,0,2,4,14,54,54,1054,1054,1054,108,109,'OOAAAA','CPHAAA','AAAAxx'
+103,5125,1,3,3,3,3,103,103,103,103,6,7,'ZDAAAA','DPHAAA','HHHHxx'
+8565,5126,1,1,5,5,65,565,565,3565,8565,130,131,'LRAAAA','EPHAAA','OOOOxx'
+4666,5127,0,2,6,6,66,666,666,4666,4666,132,133,'MXAAAA','FPHAAA','VVVVxx'
+6634,5128,0,2,4,14,34,634,634,1634,6634,68,69,'EVAAAA','GPHAAA','AAAAxx'
+5538,5129,0,2,8,18,38,538,1538,538,5538,76,77,'AFAAAA','HPHAAA','HHHHxx'
+3789,5130,1,1,9,9,89,789,1789,3789,3789,178,179,'TPAAAA','IPHAAA','OOOOxx'
+4641,5131,1,1,1,1,41,641,641,4641,4641,82,83,'NWAAAA','JPHAAA','VVVVxx'
+2458,5132,0,2,8,18,58,458,458,2458,2458,116,117,'OQAAAA','KPHAAA','AAAAxx'
+5667,5133,1,3,7,7,67,667,1667,667,5667,134,135,'ZJAAAA','LPHAAA','HHHHxx'
+6524,5134,0,0,4,4,24,524,524,1524,6524,48,49,'YQAAAA','MPHAAA','OOOOxx'
+9179,5135,1,3,9,19,79,179,1179,4179,9179,158,159,'BPAAAA','NPHAAA','VVVVxx'
+6358,5136,0,2,8,18,58,358,358,1358,6358,116,117,'OKAAAA','OPHAAA','AAAAxx'
+6668,5137,0,0,8,8,68,668,668,1668,6668,136,137,'MWAAAA','PPHAAA','HHHHxx'
+6414,5138,0,2,4,14,14,414,414,1414,6414,28,29,'SMAAAA','QPHAAA','OOOOxx'
+2813,5139,1,1,3,13,13,813,813,2813,2813,26,27,'FEAAAA','RPHAAA','VVVVxx'
+8927,5140,1,3,7,7,27,927,927,3927,8927,54,55,'JFAAAA','SPHAAA','AAAAxx'
+8695,5141,1,3,5,15,95,695,695,3695,8695,190,191,'LWAAAA','TPHAAA','HHHHxx'
+363,5142,1,3,3,3,63,363,363,363,363,126,127,'ZNAAAA','UPHAAA','OOOOxx'
+9966,5143,0,2,6,6,66,966,1966,4966,9966,132,133,'ITAAAA','VPHAAA','VVVVxx'
+1323,5144,1,3,3,3,23,323,1323,1323,1323,46,47,'XYAAAA','WPHAAA','AAAAxx'
+8211,5145,1,3,1,11,11,211,211,3211,8211,22,23,'VDAAAA','XPHAAA','HHHHxx'
+4375,5146,1,3,5,15,75,375,375,4375,4375,150,151,'HMAAAA','YPHAAA','OOOOxx'
+3257,5147,1,1,7,17,57,257,1257,3257,3257,114,115,'HVAAAA','ZPHAAA','VVVVxx'
+6239,5148,1,3,9,19,39,239,239,1239,6239,78,79,'ZFAAAA','AQHAAA','AAAAxx'
+3602,5149,0,2,2,2,2,602,1602,3602,3602,4,5,'OIAAAA','BQHAAA','HHHHxx'
+9830,5150,0,2,0,10,30,830,1830,4830,9830,60,61,'COAAAA','CQHAAA','OOOOxx'
+7826,5151,0,2,6,6,26,826,1826,2826,7826,52,53,'APAAAA','DQHAAA','VVVVxx'
+2108,5152,0,0,8,8,8,108,108,2108,2108,16,17,'CDAAAA','EQHAAA','AAAAxx'
+7245,5153,1,1,5,5,45,245,1245,2245,7245,90,91,'RSAAAA','FQHAAA','HHHHxx'
+8330,5154,0,2,0,10,30,330,330,3330,8330,60,61,'KIAAAA','GQHAAA','OOOOxx'
+7441,5155,1,1,1,1,41,441,1441,2441,7441,82,83,'FAAAAA','HQHAAA','VVVVxx'
+9848,5156,0,0,8,8,48,848,1848,4848,9848,96,97,'UOAAAA','IQHAAA','AAAAxx'
+1226,5157,0,2,6,6,26,226,1226,1226,1226,52,53,'EVAAAA','JQHAAA','HHHHxx'
+414,5158,0,2,4,14,14,414,414,414,414,28,29,'YPAAAA','KQHAAA','OOOOxx'
+1273,5159,1,1,3,13,73,273,1273,1273,1273,146,147,'ZWAAAA','LQHAAA','VVVVxx'
+9866,5160,0,2,6,6,66,866,1866,4866,9866,132,133,'MPAAAA','MQHAAA','AAAAxx'
+4633,5161,1,1,3,13,33,633,633,4633,4633,66,67,'FWAAAA','NQHAAA','HHHHxx'
+8727,5162,1,3,7,7,27,727,727,3727,8727,54,55,'RXAAAA','OQHAAA','OOOOxx'
+5308,5163,0,0,8,8,8,308,1308,308,5308,16,17,'EWAAAA','PQHAAA','VVVVxx'
+1395,5164,1,3,5,15,95,395,1395,1395,1395,190,191,'RBAAAA','QQHAAA','AAAAxx'
+1825,5165,1,1,5,5,25,825,1825,1825,1825,50,51,'FSAAAA','RQHAAA','HHHHxx'
+7606,5166,0,2,6,6,6,606,1606,2606,7606,12,13,'OGAAAA','SQHAAA','OOOOxx'
+9390,5167,0,2,0,10,90,390,1390,4390,9390,180,181,'EXAAAA','TQHAAA','VVVVxx'
+2376,5168,0,0,6,16,76,376,376,2376,2376,152,153,'KNAAAA','UQHAAA','AAAAxx'
+2377,5169,1,1,7,17,77,377,377,2377,2377,154,155,'LNAAAA','VQHAAA','HHHHxx'
+5346,5170,0,2,6,6,46,346,1346,346,5346,92,93,'QXAAAA','WQHAAA','OOOOxx'
+4140,5171,0,0,0,0,40,140,140,4140,4140,80,81,'GDAAAA','XQHAAA','VVVVxx'
+6032,5172,0,0,2,12,32,32,32,1032,6032,64,65,'AYAAAA','YQHAAA','AAAAxx'
+9453,5173,1,1,3,13,53,453,1453,4453,9453,106,107,'PZAAAA','ZQHAAA','HHHHxx'
+9297,5174,1,1,7,17,97,297,1297,4297,9297,194,195,'PTAAAA','ARHAAA','OOOOxx'
+6455,5175,1,3,5,15,55,455,455,1455,6455,110,111,'HOAAAA','BRHAAA','VVVVxx'
+4458,5176,0,2,8,18,58,458,458,4458,4458,116,117,'MPAAAA','CRHAAA','AAAAxx'
+9516,5177,0,0,6,16,16,516,1516,4516,9516,32,33,'ACAAAA','DRHAAA','HHHHxx'
+6211,5178,1,3,1,11,11,211,211,1211,6211,22,23,'XEAAAA','ERHAAA','OOOOxx'
+526,5179,0,2,6,6,26,526,526,526,526,52,53,'GUAAAA','FRHAAA','VVVVxx'
+3570,5180,0,2,0,10,70,570,1570,3570,3570,140,141,'IHAAAA','GRHAAA','AAAAxx'
+4885,5181,1,1,5,5,85,885,885,4885,4885,170,171,'XFAAAA','HRHAAA','HHHHxx'
+6390,5182,0,2,0,10,90,390,390,1390,6390,180,181,'ULAAAA','IRHAAA','OOOOxx'
+1606,5183,0,2,6,6,6,606,1606,1606,1606,12,13,'UJAAAA','JRHAAA','VVVVxx'
+7850,5184,0,2,0,10,50,850,1850,2850,7850,100,101,'YPAAAA','KRHAAA','AAAAxx'
+3315,5185,1,3,5,15,15,315,1315,3315,3315,30,31,'NXAAAA','LRHAAA','HHHHxx'
+8322,5186,0,2,2,2,22,322,322,3322,8322,44,45,'CIAAAA','MRHAAA','OOOOxx'
+3703,5187,1,3,3,3,3,703,1703,3703,3703,6,7,'LMAAAA','NRHAAA','VVVVxx'
+9489,5188,1,1,9,9,89,489,1489,4489,9489,178,179,'ZAAAAA','ORHAAA','AAAAxx'
+6104,5189,0,0,4,4,4,104,104,1104,6104,8,9,'UAAAAA','PRHAAA','HHHHxx'
+3067,5190,1,3,7,7,67,67,1067,3067,3067,134,135,'ZNAAAA','QRHAAA','OOOOxx'
+2521,5191,1,1,1,1,21,521,521,2521,2521,42,43,'ZSAAAA','RRHAAA','VVVVxx'
+2581,5192,1,1,1,1,81,581,581,2581,2581,162,163,'HVAAAA','SRHAAA','AAAAxx'
+595,5193,1,3,5,15,95,595,595,595,595,190,191,'XWAAAA','TRHAAA','HHHHxx'
+8291,5194,1,3,1,11,91,291,291,3291,8291,182,183,'XGAAAA','URHAAA','OOOOxx'
+1727,5195,1,3,7,7,27,727,1727,1727,1727,54,55,'LOAAAA','VRHAAA','VVVVxx'
+6847,5196,1,3,7,7,47,847,847,1847,6847,94,95,'JDAAAA','WRHAAA','AAAAxx'
+7494,5197,0,2,4,14,94,494,1494,2494,7494,188,189,'GCAAAA','XRHAAA','HHHHxx'
+7093,5198,1,1,3,13,93,93,1093,2093,7093,186,187,'VMAAAA','YRHAAA','OOOOxx'
+7357,5199,1,1,7,17,57,357,1357,2357,7357,114,115,'ZWAAAA','ZRHAAA','VVVVxx'
+620,5200,0,0,0,0,20,620,620,620,620,40,41,'WXAAAA','ASHAAA','AAAAxx'
+2460,5201,0,0,0,0,60,460,460,2460,2460,120,121,'QQAAAA','BSHAAA','HHHHxx'
+1598,5202,0,2,8,18,98,598,1598,1598,1598,196,197,'MJAAAA','CSHAAA','OOOOxx'
+4112,5203,0,0,2,12,12,112,112,4112,4112,24,25,'ECAAAA','DSHAAA','VVVVxx'
+2956,5204,0,0,6,16,56,956,956,2956,2956,112,113,'SJAAAA','ESHAAA','AAAAxx'
+3193,5205,1,1,3,13,93,193,1193,3193,3193,186,187,'VSAAAA','FSHAAA','HHHHxx'
+6356,5206,0,0,6,16,56,356,356,1356,6356,112,113,'MKAAAA','GSHAAA','OOOOxx'
+730,5207,0,2,0,10,30,730,730,730,730,60,61,'CCAAAA','HSHAAA','VVVVxx'
+8826,5208,0,2,6,6,26,826,826,3826,8826,52,53,'MBAAAA','ISHAAA','AAAAxx'
+9036,5209,0,0,6,16,36,36,1036,4036,9036,72,73,'OJAAAA','JSHAAA','HHHHxx'
+2085,5210,1,1,5,5,85,85,85,2085,2085,170,171,'FCAAAA','KSHAAA','OOOOxx'
+9007,5211,1,3,7,7,7,7,1007,4007,9007,14,15,'LIAAAA','LSHAAA','VVVVxx'
+6047,5212,1,3,7,7,47,47,47,1047,6047,94,95,'PYAAAA','MSHAAA','AAAAxx'
+3953,5213,1,1,3,13,53,953,1953,3953,3953,106,107,'BWAAAA','NSHAAA','HHHHxx'
+1214,5214,0,2,4,14,14,214,1214,1214,1214,28,29,'SUAAAA','OSHAAA','OOOOxx'
+4814,5215,0,2,4,14,14,814,814,4814,4814,28,29,'EDAAAA','PSHAAA','VVVVxx'
+5738,5216,0,2,8,18,38,738,1738,738,5738,76,77,'SMAAAA','QSHAAA','AAAAxx'
+7176,5217,0,0,6,16,76,176,1176,2176,7176,152,153,'AQAAAA','RSHAAA','HHHHxx'
+3609,5218,1,1,9,9,9,609,1609,3609,3609,18,19,'VIAAAA','SSHAAA','OOOOxx'
+592,5219,0,0,2,12,92,592,592,592,592,184,185,'UWAAAA','TSHAAA','VVVVxx'
+9391,5220,1,3,1,11,91,391,1391,4391,9391,182,183,'FXAAAA','USHAAA','AAAAxx'
+5345,5221,1,1,5,5,45,345,1345,345,5345,90,91,'PXAAAA','VSHAAA','HHHHxx'
+1171,5222,1,3,1,11,71,171,1171,1171,1171,142,143,'BTAAAA','WSHAAA','OOOOxx'
+7238,5223,0,2,8,18,38,238,1238,2238,7238,76,77,'KSAAAA','XSHAAA','VVVVxx'
+7561,5224,1,1,1,1,61,561,1561,2561,7561,122,123,'VEAAAA','YSHAAA','AAAAxx'
+5876,5225,0,0,6,16,76,876,1876,876,5876,152,153,'ASAAAA','ZSHAAA','HHHHxx'
+6611,5226,1,3,1,11,11,611,611,1611,6611,22,23,'HUAAAA','ATHAAA','OOOOxx'
+7300,5227,0,0,0,0,0,300,1300,2300,7300,0,1,'UUAAAA','BTHAAA','VVVVxx'
+1506,5228,0,2,6,6,6,506,1506,1506,1506,12,13,'YFAAAA','CTHAAA','AAAAxx'
+1153,5229,1,1,3,13,53,153,1153,1153,1153,106,107,'JSAAAA','DTHAAA','HHHHxx'
+3831,5230,1,3,1,11,31,831,1831,3831,3831,62,63,'JRAAAA','ETHAAA','OOOOxx'
+9255,5231,1,3,5,15,55,255,1255,4255,9255,110,111,'ZRAAAA','FTHAAA','VVVVxx'
+1841,5232,1,1,1,1,41,841,1841,1841,1841,82,83,'VSAAAA','GTHAAA','AAAAxx'
+5075,5233,1,3,5,15,75,75,1075,75,5075,150,151,'FNAAAA','HTHAAA','HHHHxx'
+101,5234,1,1,1,1,1,101,101,101,101,2,3,'XDAAAA','ITHAAA','OOOOxx'
+2627,5235,1,3,7,7,27,627,627,2627,2627,54,55,'BXAAAA','JTHAAA','VVVVxx'
+7078,5236,0,2,8,18,78,78,1078,2078,7078,156,157,'GMAAAA','KTHAAA','AAAAxx'
+2850,5237,0,2,0,10,50,850,850,2850,2850,100,101,'QFAAAA','LTHAAA','HHHHxx'
+8703,5238,1,3,3,3,3,703,703,3703,8703,6,7,'TWAAAA','MTHAAA','OOOOxx'
+4101,5239,1,1,1,1,1,101,101,4101,4101,2,3,'TBAAAA','NTHAAA','VVVVxx'
+318,5240,0,2,8,18,18,318,318,318,318,36,37,'GMAAAA','OTHAAA','AAAAxx'
+6452,5241,0,0,2,12,52,452,452,1452,6452,104,105,'EOAAAA','PTHAAA','HHHHxx'
+5558,5242,0,2,8,18,58,558,1558,558,5558,116,117,'UFAAAA','QTHAAA','OOOOxx'
+3127,5243,1,3,7,7,27,127,1127,3127,3127,54,55,'HQAAAA','RTHAAA','VVVVxx'
+535,5244,1,3,5,15,35,535,535,535,535,70,71,'PUAAAA','STHAAA','AAAAxx'
+270,5245,0,2,0,10,70,270,270,270,270,140,141,'KKAAAA','TTHAAA','HHHHxx'
+4038,5246,0,2,8,18,38,38,38,4038,4038,76,77,'IZAAAA','UTHAAA','OOOOxx'
+3404,5247,0,0,4,4,4,404,1404,3404,3404,8,9,'YAAAAA','VTHAAA','VVVVxx'
+2374,5248,0,2,4,14,74,374,374,2374,2374,148,149,'INAAAA','WTHAAA','AAAAxx'
+6446,5249,0,2,6,6,46,446,446,1446,6446,92,93,'YNAAAA','XTHAAA','HHHHxx'
+7758,5250,0,2,8,18,58,758,1758,2758,7758,116,117,'KMAAAA','YTHAAA','OOOOxx'
+356,5251,0,0,6,16,56,356,356,356,356,112,113,'SNAAAA','ZTHAAA','VVVVxx'
+9197,5252,1,1,7,17,97,197,1197,4197,9197,194,195,'TPAAAA','AUHAAA','AAAAxx'
+9765,5253,1,1,5,5,65,765,1765,4765,9765,130,131,'PLAAAA','BUHAAA','HHHHxx'
+4974,5254,0,2,4,14,74,974,974,4974,4974,148,149,'IJAAAA','CUHAAA','OOOOxx'
+442,5255,0,2,2,2,42,442,442,442,442,84,85,'ARAAAA','DUHAAA','VVVVxx'
+4349,5256,1,1,9,9,49,349,349,4349,4349,98,99,'HLAAAA','EUHAAA','AAAAxx'
+6119,5257,1,3,9,19,19,119,119,1119,6119,38,39,'JBAAAA','FUHAAA','HHHHxx'
+7574,5258,0,2,4,14,74,574,1574,2574,7574,148,149,'IFAAAA','GUHAAA','OOOOxx'
+4445,5259,1,1,5,5,45,445,445,4445,4445,90,91,'ZOAAAA','HUHAAA','VVVVxx'
+940,5260,0,0,0,0,40,940,940,940,940,80,81,'EKAAAA','IUHAAA','AAAAxx'
+1875,5261,1,3,5,15,75,875,1875,1875,1875,150,151,'DUAAAA','JUHAAA','HHHHxx'
+5951,5262,1,3,1,11,51,951,1951,951,5951,102,103,'XUAAAA','KUHAAA','OOOOxx'
+9132,5263,0,0,2,12,32,132,1132,4132,9132,64,65,'GNAAAA','LUHAAA','VVVVxx'
+6913,5264,1,1,3,13,13,913,913,1913,6913,26,27,'XFAAAA','MUHAAA','AAAAxx'
+3308,5265,0,0,8,8,8,308,1308,3308,3308,16,17,'GXAAAA','NUHAAA','HHHHxx'
+7553,5266,1,1,3,13,53,553,1553,2553,7553,106,107,'NEAAAA','OUHAAA','OOOOxx'
+2138,5267,0,2,8,18,38,138,138,2138,2138,76,77,'GEAAAA','PUHAAA','VVVVxx'
+6252,5268,0,0,2,12,52,252,252,1252,6252,104,105,'MGAAAA','QUHAAA','AAAAxx'
+2171,5269,1,3,1,11,71,171,171,2171,2171,142,143,'NFAAAA','RUHAAA','HHHHxx'
+4159,5270,1,3,9,19,59,159,159,4159,4159,118,119,'ZDAAAA','SUHAAA','OOOOxx'
+2401,5271,1,1,1,1,1,401,401,2401,2401,2,3,'JOAAAA','TUHAAA','VVVVxx'
+6553,5272,1,1,3,13,53,553,553,1553,6553,106,107,'BSAAAA','UUHAAA','AAAAxx'
+5217,5273,1,1,7,17,17,217,1217,217,5217,34,35,'RSAAAA','VUHAAA','HHHHxx'
+1405,5274,1,1,5,5,5,405,1405,1405,1405,10,11,'BCAAAA','WUHAAA','OOOOxx'
+1494,5275,0,2,4,14,94,494,1494,1494,1494,188,189,'MFAAAA','XUHAAA','VVVVxx'
+5553,5276,1,1,3,13,53,553,1553,553,5553,106,107,'PFAAAA','YUHAAA','AAAAxx'
+8296,5277,0,0,6,16,96,296,296,3296,8296,192,193,'CHAAAA','ZUHAAA','HHHHxx'
+6565,5278,1,1,5,5,65,565,565,1565,6565,130,131,'NSAAAA','AVHAAA','OOOOxx'
+817,5279,1,1,7,17,17,817,817,817,817,34,35,'LFAAAA','BVHAAA','VVVVxx'
+6947,5280,1,3,7,7,47,947,947,1947,6947,94,95,'FHAAAA','CVHAAA','AAAAxx'
+4184,5281,0,0,4,4,84,184,184,4184,4184,168,169,'YEAAAA','DVHAAA','HHHHxx'
+6577,5282,1,1,7,17,77,577,577,1577,6577,154,155,'ZSAAAA','EVHAAA','OOOOxx'
+6424,5283,0,0,4,4,24,424,424,1424,6424,48,49,'CNAAAA','FVHAAA','VVVVxx'
+2482,5284,0,2,2,2,82,482,482,2482,2482,164,165,'MRAAAA','GVHAAA','AAAAxx'
+6874,5285,0,2,4,14,74,874,874,1874,6874,148,149,'KEAAAA','HVHAAA','HHHHxx'
+7601,5286,1,1,1,1,1,601,1601,2601,7601,2,3,'JGAAAA','IVHAAA','OOOOxx'
+4552,5287,0,0,2,12,52,552,552,4552,4552,104,105,'CTAAAA','JVHAAA','VVVVxx'
+8406,5288,0,2,6,6,6,406,406,3406,8406,12,13,'ILAAAA','KVHAAA','AAAAxx'
+2924,5289,0,0,4,4,24,924,924,2924,2924,48,49,'MIAAAA','LVHAAA','HHHHxx'
+8255,5290,1,3,5,15,55,255,255,3255,8255,110,111,'NFAAAA','MVHAAA','OOOOxx'
+4920,5291,0,0,0,0,20,920,920,4920,4920,40,41,'GHAAAA','NVHAAA','VVVVxx'
+228,5292,0,0,8,8,28,228,228,228,228,56,57,'UIAAAA','OVHAAA','AAAAxx'
+9431,5293,1,3,1,11,31,431,1431,4431,9431,62,63,'TYAAAA','PVHAAA','HHHHxx'
+4021,5294,1,1,1,1,21,21,21,4021,4021,42,43,'RYAAAA','QVHAAA','OOOOxx'
+2966,5295,0,2,6,6,66,966,966,2966,2966,132,133,'CKAAAA','RVHAAA','VVVVxx'
+2862,5296,0,2,2,2,62,862,862,2862,2862,124,125,'CGAAAA','SVHAAA','AAAAxx'
+4303,5297,1,3,3,3,3,303,303,4303,4303,6,7,'NJAAAA','TVHAAA','HHHHxx'
+9643,5298,1,3,3,3,43,643,1643,4643,9643,86,87,'XGAAAA','UVHAAA','OOOOxx'
+3008,5299,0,0,8,8,8,8,1008,3008,3008,16,17,'SLAAAA','VVHAAA','VVVVxx'
+7476,5300,0,0,6,16,76,476,1476,2476,7476,152,153,'OBAAAA','WVHAAA','AAAAxx'
+3686,5301,0,2,6,6,86,686,1686,3686,3686,172,173,'ULAAAA','XVHAAA','HHHHxx'
+9051,5302,1,3,1,11,51,51,1051,4051,9051,102,103,'DKAAAA','YVHAAA','OOOOxx'
+6592,5303,0,0,2,12,92,592,592,1592,6592,184,185,'OTAAAA','ZVHAAA','VVVVxx'
+924,5304,0,0,4,4,24,924,924,924,924,48,49,'OJAAAA','AWHAAA','AAAAxx'
+4406,5305,0,2,6,6,6,406,406,4406,4406,12,13,'MNAAAA','BWHAAA','HHHHxx'
+5233,5306,1,1,3,13,33,233,1233,233,5233,66,67,'HTAAAA','CWHAAA','OOOOxx'
+8881,5307,1,1,1,1,81,881,881,3881,8881,162,163,'PDAAAA','DWHAAA','VVVVxx'
+2212,5308,0,0,2,12,12,212,212,2212,2212,24,25,'CHAAAA','EWHAAA','AAAAxx'
+5804,5309,0,0,4,4,4,804,1804,804,5804,8,9,'GPAAAA','FWHAAA','HHHHxx'
+2990,5310,0,2,0,10,90,990,990,2990,2990,180,181,'ALAAAA','GWHAAA','OOOOxx'
+4069,5311,1,1,9,9,69,69,69,4069,4069,138,139,'NAAAAA','HWHAAA','VVVVxx'
+5380,5312,0,0,0,0,80,380,1380,380,5380,160,161,'YYAAAA','IWHAAA','AAAAxx'
+5016,5313,0,0,6,16,16,16,1016,16,5016,32,33,'YKAAAA','JWHAAA','HHHHxx'
+5056,5314,0,0,6,16,56,56,1056,56,5056,112,113,'MMAAAA','KWHAAA','OOOOxx'
+3732,5315,0,0,2,12,32,732,1732,3732,3732,64,65,'ONAAAA','LWHAAA','VVVVxx'
+5527,5316,1,3,7,7,27,527,1527,527,5527,54,55,'PEAAAA','MWHAAA','AAAAxx'
+1151,5317,1,3,1,11,51,151,1151,1151,1151,102,103,'HSAAAA','NWHAAA','HHHHxx'
+7900,5318,0,0,0,0,0,900,1900,2900,7900,0,1,'WRAAAA','OWHAAA','OOOOxx'
+1660,5319,0,0,0,0,60,660,1660,1660,1660,120,121,'WLAAAA','PWHAAA','VVVVxx'
+8064,5320,0,0,4,4,64,64,64,3064,8064,128,129,'EYAAAA','QWHAAA','AAAAxx'
+8240,5321,0,0,0,0,40,240,240,3240,8240,80,81,'YEAAAA','RWHAAA','HHHHxx'
+413,5322,1,1,3,13,13,413,413,413,413,26,27,'XPAAAA','SWHAAA','OOOOxx'
+8311,5323,1,3,1,11,11,311,311,3311,8311,22,23,'RHAAAA','TWHAAA','VVVVxx'
+1065,5324,1,1,5,5,65,65,1065,1065,1065,130,131,'ZOAAAA','UWHAAA','AAAAxx'
+2741,5325,1,1,1,1,41,741,741,2741,2741,82,83,'LBAAAA','VWHAAA','HHHHxx'
+5306,5326,0,2,6,6,6,306,1306,306,5306,12,13,'CWAAAA','WWHAAA','OOOOxx'
+5464,5327,0,0,4,4,64,464,1464,464,5464,128,129,'ECAAAA','XWHAAA','VVVVxx'
+4237,5328,1,1,7,17,37,237,237,4237,4237,74,75,'ZGAAAA','YWHAAA','AAAAxx'
+3822,5329,0,2,2,2,22,822,1822,3822,3822,44,45,'ARAAAA','ZWHAAA','HHHHxx'
+2548,5330,0,0,8,8,48,548,548,2548,2548,96,97,'AUAAAA','AXHAAA','OOOOxx'
+2688,5331,0,0,8,8,88,688,688,2688,2688,176,177,'KZAAAA','BXHAAA','VVVVxx'
+8061,5332,1,1,1,1,61,61,61,3061,8061,122,123,'BYAAAA','CXHAAA','AAAAxx'
+9340,5333,0,0,0,0,40,340,1340,4340,9340,80,81,'GVAAAA','DXHAAA','HHHHxx'
+4031,5334,1,3,1,11,31,31,31,4031,4031,62,63,'BZAAAA','EXHAAA','OOOOxx'
+2635,5335,1,3,5,15,35,635,635,2635,2635,70,71,'JXAAAA','FXHAAA','VVVVxx'
+809,5336,1,1,9,9,9,809,809,809,809,18,19,'DFAAAA','GXHAAA','AAAAxx'
+3209,5337,1,1,9,9,9,209,1209,3209,3209,18,19,'LTAAAA','HXHAAA','HHHHxx'
+3825,5338,1,1,5,5,25,825,1825,3825,3825,50,51,'DRAAAA','IXHAAA','OOOOxx'
+1448,5339,0,0,8,8,48,448,1448,1448,1448,96,97,'SDAAAA','JXHAAA','VVVVxx'
+9077,5340,1,1,7,17,77,77,1077,4077,9077,154,155,'DLAAAA','KXHAAA','AAAAxx'
+3730,5341,0,2,0,10,30,730,1730,3730,3730,60,61,'MNAAAA','LXHAAA','HHHHxx'
+9596,5342,0,0,6,16,96,596,1596,4596,9596,192,193,'CFAAAA','MXHAAA','OOOOxx'
+3563,5343,1,3,3,3,63,563,1563,3563,3563,126,127,'BHAAAA','NXHAAA','VVVVxx'
+4116,5344,0,0,6,16,16,116,116,4116,4116,32,33,'ICAAAA','OXHAAA','AAAAxx'
+4825,5345,1,1,5,5,25,825,825,4825,4825,50,51,'PDAAAA','PXHAAA','HHHHxx'
+8376,5346,0,0,6,16,76,376,376,3376,8376,152,153,'EKAAAA','QXHAAA','OOOOxx'
+3917,5347,1,1,7,17,17,917,1917,3917,3917,34,35,'RUAAAA','RXHAAA','VVVVxx'
+4407,5348,1,3,7,7,7,407,407,4407,4407,14,15,'NNAAAA','SXHAAA','AAAAxx'
+8202,5349,0,2,2,2,2,202,202,3202,8202,4,5,'MDAAAA','TXHAAA','HHHHxx'
+7675,5350,1,3,5,15,75,675,1675,2675,7675,150,151,'FJAAAA','UXHAAA','OOOOxx'
+4104,5351,0,0,4,4,4,104,104,4104,4104,8,9,'WBAAAA','VXHAAA','VVVVxx'
+9225,5352,1,1,5,5,25,225,1225,4225,9225,50,51,'VQAAAA','WXHAAA','AAAAxx'
+2834,5353,0,2,4,14,34,834,834,2834,2834,68,69,'AFAAAA','XXHAAA','HHHHxx'
+1227,5354,1,3,7,7,27,227,1227,1227,1227,54,55,'FVAAAA','YXHAAA','OOOOxx'
+3383,5355,1,3,3,3,83,383,1383,3383,3383,166,167,'DAAAAA','ZXHAAA','VVVVxx'
+67,5356,1,3,7,7,67,67,67,67,67,134,135,'PCAAAA','AYHAAA','AAAAxx'
+1751,5357,1,3,1,11,51,751,1751,1751,1751,102,103,'JPAAAA','BYHAAA','HHHHxx'
+8054,5358,0,2,4,14,54,54,54,3054,8054,108,109,'UXAAAA','CYHAAA','OOOOxx'
+8571,5359,1,3,1,11,71,571,571,3571,8571,142,143,'RRAAAA','DYHAAA','VVVVxx'
+2466,5360,0,2,6,6,66,466,466,2466,2466,132,133,'WQAAAA','EYHAAA','AAAAxx'
+9405,5361,1,1,5,5,5,405,1405,4405,9405,10,11,'TXAAAA','FYHAAA','HHHHxx'
+6883,5362,1,3,3,3,83,883,883,1883,6883,166,167,'TEAAAA','GYHAAA','OOOOxx'
+4301,5363,1,1,1,1,1,301,301,4301,4301,2,3,'LJAAAA','HYHAAA','VVVVxx'
+3705,5364,1,1,5,5,5,705,1705,3705,3705,10,11,'NMAAAA','IYHAAA','AAAAxx'
+5420,5365,0,0,0,0,20,420,1420,420,5420,40,41,'MAAAAA','JYHAAA','HHHHxx'
+3692,5366,0,0,2,12,92,692,1692,3692,3692,184,185,'AMAAAA','KYHAAA','OOOOxx'
+6851,5367,1,3,1,11,51,851,851,1851,6851,102,103,'NDAAAA','LYHAAA','VVVVxx'
+9363,5368,1,3,3,3,63,363,1363,4363,9363,126,127,'DWAAAA','MYHAAA','AAAAxx'
+2269,5369,1,1,9,9,69,269,269,2269,2269,138,139,'HJAAAA','NYHAAA','HHHHxx'
+4918,5370,0,2,8,18,18,918,918,4918,4918,36,37,'EHAAAA','OYHAAA','OOOOxx'
+4297,5371,1,1,7,17,97,297,297,4297,4297,194,195,'HJAAAA','PYHAAA','VVVVxx'
+1836,5372,0,0,6,16,36,836,1836,1836,1836,72,73,'QSAAAA','QYHAAA','AAAAxx'
+237,5373,1,1,7,17,37,237,237,237,237,74,75,'DJAAAA','RYHAAA','HHHHxx'
+6131,5374,1,3,1,11,31,131,131,1131,6131,62,63,'VBAAAA','SYHAAA','OOOOxx'
+3174,5375,0,2,4,14,74,174,1174,3174,3174,148,149,'CSAAAA','TYHAAA','VVVVxx'
+9987,5376,1,3,7,7,87,987,1987,4987,9987,174,175,'DUAAAA','UYHAAA','AAAAxx'
+3630,5377,0,2,0,10,30,630,1630,3630,3630,60,61,'QJAAAA','VYHAAA','HHHHxx'
+2899,5378,1,3,9,19,99,899,899,2899,2899,198,199,'NHAAAA','WYHAAA','OOOOxx'
+4079,5379,1,3,9,19,79,79,79,4079,4079,158,159,'XAAAAA','XYHAAA','VVVVxx'
+5049,5380,1,1,9,9,49,49,1049,49,5049,98,99,'FMAAAA','YYHAAA','AAAAxx'
+2963,5381,1,3,3,3,63,963,963,2963,2963,126,127,'ZJAAAA','ZYHAAA','HHHHxx'
+3962,5382,0,2,2,2,62,962,1962,3962,3962,124,125,'KWAAAA','AZHAAA','OOOOxx'
+7921,5383,1,1,1,1,21,921,1921,2921,7921,42,43,'RSAAAA','BZHAAA','VVVVxx'
+3967,5384,1,3,7,7,67,967,1967,3967,3967,134,135,'PWAAAA','CZHAAA','AAAAxx'
+2752,5385,0,0,2,12,52,752,752,2752,2752,104,105,'WBAAAA','DZHAAA','HHHHxx'
+7944,5386,0,0,4,4,44,944,1944,2944,7944,88,89,'OTAAAA','EZHAAA','OOOOxx'
+2205,5387,1,1,5,5,5,205,205,2205,2205,10,11,'VGAAAA','FZHAAA','VVVVxx'
+5035,5388,1,3,5,15,35,35,1035,35,5035,70,71,'RLAAAA','GZHAAA','AAAAxx'
+1425,5389,1,1,5,5,25,425,1425,1425,1425,50,51,'VCAAAA','HZHAAA','HHHHxx'
+832,5390,0,0,2,12,32,832,832,832,832,64,65,'AGAAAA','IZHAAA','OOOOxx'
+1447,5391,1,3,7,7,47,447,1447,1447,1447,94,95,'RDAAAA','JZHAAA','VVVVxx'
+6108,5392,0,0,8,8,8,108,108,1108,6108,16,17,'YAAAAA','KZHAAA','AAAAxx'
+4936,5393,0,0,6,16,36,936,936,4936,4936,72,73,'WHAAAA','LZHAAA','HHHHxx'
+7704,5394,0,0,4,4,4,704,1704,2704,7704,8,9,'IKAAAA','MZHAAA','OOOOxx'
+142,5395,0,2,2,2,42,142,142,142,142,84,85,'MFAAAA','NZHAAA','VVVVxx'
+4272,5396,0,0,2,12,72,272,272,4272,4272,144,145,'IIAAAA','OZHAAA','AAAAxx'
+7667,5397,1,3,7,7,67,667,1667,2667,7667,134,135,'XIAAAA','PZHAAA','HHHHxx'
+366,5398,0,2,6,6,66,366,366,366,366,132,133,'COAAAA','QZHAAA','OOOOxx'
+8866,5399,0,2,6,6,66,866,866,3866,8866,132,133,'ADAAAA','RZHAAA','VVVVxx'
+7712,5400,0,0,2,12,12,712,1712,2712,7712,24,25,'QKAAAA','SZHAAA','AAAAxx'
+3880,5401,0,0,0,0,80,880,1880,3880,3880,160,161,'GTAAAA','TZHAAA','HHHHxx'
+4631,5402,1,3,1,11,31,631,631,4631,4631,62,63,'DWAAAA','UZHAAA','OOOOxx'
+2789,5403,1,1,9,9,89,789,789,2789,2789,178,179,'HDAAAA','VZHAAA','VVVVxx'
+7720,5404,0,0,0,0,20,720,1720,2720,7720,40,41,'YKAAAA','WZHAAA','AAAAxx'
+7618,5405,0,2,8,18,18,618,1618,2618,7618,36,37,'AHAAAA','XZHAAA','HHHHxx'
+4990,5406,0,2,0,10,90,990,990,4990,4990,180,181,'YJAAAA','YZHAAA','OOOOxx'
+7918,5407,0,2,8,18,18,918,1918,2918,7918,36,37,'OSAAAA','ZZHAAA','VVVVxx'
+5067,5408,1,3,7,7,67,67,1067,67,5067,134,135,'XMAAAA','AAIAAA','AAAAxx'
+6370,5409,0,2,0,10,70,370,370,1370,6370,140,141,'ALAAAA','BAIAAA','HHHHxx'
+2268,5410,0,0,8,8,68,268,268,2268,2268,136,137,'GJAAAA','CAIAAA','OOOOxx'
+1949,5411,1,1,9,9,49,949,1949,1949,1949,98,99,'ZWAAAA','DAIAAA','VVVVxx'
+5503,5412,1,3,3,3,3,503,1503,503,5503,6,7,'RDAAAA','EAIAAA','AAAAxx'
+9951,5413,1,3,1,11,51,951,1951,4951,9951,102,103,'TSAAAA','FAIAAA','HHHHxx'
+6823,5414,1,3,3,3,23,823,823,1823,6823,46,47,'LCAAAA','GAIAAA','OOOOxx'
+6287,5415,1,3,7,7,87,287,287,1287,6287,174,175,'VHAAAA','HAIAAA','VVVVxx'
+6016,5416,0,0,6,16,16,16,16,1016,6016,32,33,'KXAAAA','IAIAAA','AAAAxx'
+1977,5417,1,1,7,17,77,977,1977,1977,1977,154,155,'BYAAAA','JAIAAA','HHHHxx'
+8579,5418,1,3,9,19,79,579,579,3579,8579,158,159,'ZRAAAA','KAIAAA','OOOOxx'
+6204,5419,0,0,4,4,4,204,204,1204,6204,8,9,'QEAAAA','LAIAAA','VVVVxx'
+9764,5420,0,0,4,4,64,764,1764,4764,9764,128,129,'OLAAAA','MAIAAA','AAAAxx'
+2005,5421,1,1,5,5,5,5,5,2005,2005,10,11,'DZAAAA','NAIAAA','HHHHxx'
+1648,5422,0,0,8,8,48,648,1648,1648,1648,96,97,'KLAAAA','OAIAAA','OOOOxx'
+2457,5423,1,1,7,17,57,457,457,2457,2457,114,115,'NQAAAA','PAIAAA','VVVVxx'
+2698,5424,0,2,8,18,98,698,698,2698,2698,196,197,'UZAAAA','QAIAAA','AAAAxx'
+7730,5425,0,2,0,10,30,730,1730,2730,7730,60,61,'ILAAAA','RAIAAA','HHHHxx'
+7287,5426,1,3,7,7,87,287,1287,2287,7287,174,175,'HUAAAA','SAIAAA','OOOOxx'
+2937,5427,1,1,7,17,37,937,937,2937,2937,74,75,'ZIAAAA','TAIAAA','VVVVxx'
+6824,5428,0,0,4,4,24,824,824,1824,6824,48,49,'MCAAAA','UAIAAA','AAAAxx'
+9256,5429,0,0,6,16,56,256,1256,4256,9256,112,113,'ASAAAA','VAIAAA','HHHHxx'
+4810,5430,0,2,0,10,10,810,810,4810,4810,20,21,'ADAAAA','WAIAAA','OOOOxx'
+3869,5431,1,1,9,9,69,869,1869,3869,3869,138,139,'VSAAAA','XAIAAA','VVVVxx'
+1993,5432,1,1,3,13,93,993,1993,1993,1993,186,187,'RYAAAA','YAIAAA','AAAAxx'
+6048,5433,0,0,8,8,48,48,48,1048,6048,96,97,'QYAAAA','ZAIAAA','HHHHxx'
+6922,5434,0,2,2,2,22,922,922,1922,6922,44,45,'GGAAAA','ABIAAA','OOOOxx'
+8,5435,0,0,8,8,8,8,8,8,8,16,17,'IAAAAA','BBIAAA','VVVVxx'
+6706,5436,0,2,6,6,6,706,706,1706,6706,12,13,'YXAAAA','CBIAAA','AAAAxx'
+9159,5437,1,3,9,19,59,159,1159,4159,9159,118,119,'HOAAAA','DBIAAA','HHHHxx'
+7020,5438,0,0,0,0,20,20,1020,2020,7020,40,41,'AKAAAA','EBIAAA','OOOOxx'
+767,5439,1,3,7,7,67,767,767,767,767,134,135,'NDAAAA','FBIAAA','VVVVxx'
+8602,5440,0,2,2,2,2,602,602,3602,8602,4,5,'WSAAAA','GBIAAA','AAAAxx'
+4442,5441,0,2,2,2,42,442,442,4442,4442,84,85,'WOAAAA','HBIAAA','HHHHxx'
+2040,5442,0,0,0,0,40,40,40,2040,2040,80,81,'MAAAAA','IBIAAA','OOOOxx'
+5493,5443,1,1,3,13,93,493,1493,493,5493,186,187,'HDAAAA','JBIAAA','VVVVxx'
+275,5444,1,3,5,15,75,275,275,275,275,150,151,'PKAAAA','KBIAAA','AAAAxx'
+8876,5445,0,0,6,16,76,876,876,3876,8876,152,153,'KDAAAA','LBIAAA','HHHHxx'
+7381,5446,1,1,1,1,81,381,1381,2381,7381,162,163,'XXAAAA','MBIAAA','OOOOxx'
+1827,5447,1,3,7,7,27,827,1827,1827,1827,54,55,'HSAAAA','NBIAAA','VVVVxx'
+3537,5448,1,1,7,17,37,537,1537,3537,3537,74,75,'BGAAAA','OBIAAA','AAAAxx'
+6978,5449,0,2,8,18,78,978,978,1978,6978,156,157,'KIAAAA','PBIAAA','HHHHxx'
+6160,5450,0,0,0,0,60,160,160,1160,6160,120,121,'YCAAAA','QBIAAA','OOOOxx'
+9219,5451,1,3,9,19,19,219,1219,4219,9219,38,39,'PQAAAA','RBIAAA','VVVVxx'
+5034,5452,0,2,4,14,34,34,1034,34,5034,68,69,'QLAAAA','SBIAAA','AAAAxx'
+8463,5453,1,3,3,3,63,463,463,3463,8463,126,127,'NNAAAA','TBIAAA','HHHHxx'
+2038,5454,0,2,8,18,38,38,38,2038,2038,76,77,'KAAAAA','UBIAAA','OOOOxx'
+9562,5455,0,2,2,2,62,562,1562,4562,9562,124,125,'UDAAAA','VBIAAA','VVVVxx'
+2687,5456,1,3,7,7,87,687,687,2687,2687,174,175,'JZAAAA','WBIAAA','AAAAxx'
+5092,5457,0,0,2,12,92,92,1092,92,5092,184,185,'WNAAAA','XBIAAA','HHHHxx'
+539,5458,1,3,9,19,39,539,539,539,539,78,79,'TUAAAA','YBIAAA','OOOOxx'
+2139,5459,1,3,9,19,39,139,139,2139,2139,78,79,'HEAAAA','ZBIAAA','VVVVxx'
+9221,5460,1,1,1,1,21,221,1221,4221,9221,42,43,'RQAAAA','ACIAAA','AAAAxx'
+965,5461,1,1,5,5,65,965,965,965,965,130,131,'DLAAAA','BCIAAA','HHHHxx'
+6051,5462,1,3,1,11,51,51,51,1051,6051,102,103,'TYAAAA','CCIAAA','OOOOxx'
+5822,5463,0,2,2,2,22,822,1822,822,5822,44,45,'YPAAAA','DCIAAA','VVVVxx'
+6397,5464,1,1,7,17,97,397,397,1397,6397,194,195,'BMAAAA','ECIAAA','AAAAxx'
+2375,5465,1,3,5,15,75,375,375,2375,2375,150,151,'JNAAAA','FCIAAA','HHHHxx'
+9415,5466,1,3,5,15,15,415,1415,4415,9415,30,31,'DYAAAA','GCIAAA','OOOOxx'
+6552,5467,0,0,2,12,52,552,552,1552,6552,104,105,'ASAAAA','HCIAAA','VVVVxx'
+2248,5468,0,0,8,8,48,248,248,2248,2248,96,97,'MIAAAA','ICIAAA','AAAAxx'
+2611,5469,1,3,1,11,11,611,611,2611,2611,22,23,'LWAAAA','JCIAAA','HHHHxx'
+9609,5470,1,1,9,9,9,609,1609,4609,9609,18,19,'PFAAAA','KCIAAA','OOOOxx'
+2132,5471,0,0,2,12,32,132,132,2132,2132,64,65,'AEAAAA','LCIAAA','VVVVxx'
+8452,5472,0,0,2,12,52,452,452,3452,8452,104,105,'CNAAAA','MCIAAA','AAAAxx'
+9407,5473,1,3,7,7,7,407,1407,4407,9407,14,15,'VXAAAA','NCIAAA','HHHHxx'
+2814,5474,0,2,4,14,14,814,814,2814,2814,28,29,'GEAAAA','OCIAAA','OOOOxx'
+1889,5475,1,1,9,9,89,889,1889,1889,1889,178,179,'RUAAAA','PCIAAA','VVVVxx'
+7489,5476,1,1,9,9,89,489,1489,2489,7489,178,179,'BCAAAA','QCIAAA','AAAAxx'
+2255,5477,1,3,5,15,55,255,255,2255,2255,110,111,'TIAAAA','RCIAAA','HHHHxx'
+3380,5478,0,0,0,0,80,380,1380,3380,3380,160,161,'AAAAAA','SCIAAA','OOOOxx'
+1167,5479,1,3,7,7,67,167,1167,1167,1167,134,135,'XSAAAA','TCIAAA','VVVVxx'
+5369,5480,1,1,9,9,69,369,1369,369,5369,138,139,'NYAAAA','UCIAAA','AAAAxx'
+2378,5481,0,2,8,18,78,378,378,2378,2378,156,157,'MNAAAA','VCIAAA','HHHHxx'
+8315,5482,1,3,5,15,15,315,315,3315,8315,30,31,'VHAAAA','WCIAAA','OOOOxx'
+2934,5483,0,2,4,14,34,934,934,2934,2934,68,69,'WIAAAA','XCIAAA','VVVVxx'
+7924,5484,0,0,4,4,24,924,1924,2924,7924,48,49,'USAAAA','YCIAAA','AAAAxx'
+2867,5485,1,3,7,7,67,867,867,2867,2867,134,135,'HGAAAA','ZCIAAA','HHHHxx'
+9141,5486,1,1,1,1,41,141,1141,4141,9141,82,83,'PNAAAA','ADIAAA','OOOOxx'
+3613,5487,1,1,3,13,13,613,1613,3613,3613,26,27,'ZIAAAA','BDIAAA','VVVVxx'
+2461,5488,1,1,1,1,61,461,461,2461,2461,122,123,'RQAAAA','CDIAAA','AAAAxx'
+4567,5489,1,3,7,7,67,567,567,4567,4567,134,135,'RTAAAA','DDIAAA','HHHHxx'
+2906,5490,0,2,6,6,6,906,906,2906,2906,12,13,'UHAAAA','EDIAAA','OOOOxx'
+4848,5491,0,0,8,8,48,848,848,4848,4848,96,97,'MEAAAA','FDIAAA','VVVVxx'
+6614,5492,0,2,4,14,14,614,614,1614,6614,28,29,'KUAAAA','GDIAAA','AAAAxx'
+6200,5493,0,0,0,0,0,200,200,1200,6200,0,1,'MEAAAA','HDIAAA','HHHHxx'
+7895,5494,1,3,5,15,95,895,1895,2895,7895,190,191,'RRAAAA','IDIAAA','OOOOxx'
+6829,5495,1,1,9,9,29,829,829,1829,6829,58,59,'RCAAAA','JDIAAA','VVVVxx'
+4087,5496,1,3,7,7,87,87,87,4087,4087,174,175,'FBAAAA','KDIAAA','AAAAxx'
+8787,5497,1,3,7,7,87,787,787,3787,8787,174,175,'ZZAAAA','LDIAAA','HHHHxx'
+3322,5498,0,2,2,2,22,322,1322,3322,3322,44,45,'UXAAAA','MDIAAA','OOOOxx'
+9091,5499,1,3,1,11,91,91,1091,4091,9091,182,183,'RLAAAA','NDIAAA','VVVVxx'
+5268,5500,0,0,8,8,68,268,1268,268,5268,136,137,'QUAAAA','ODIAAA','AAAAxx'
+2719,5501,1,3,9,19,19,719,719,2719,2719,38,39,'PAAAAA','PDIAAA','HHHHxx'
+30,5502,0,2,0,10,30,30,30,30,30,60,61,'EBAAAA','QDIAAA','OOOOxx'
+1975,5503,1,3,5,15,75,975,1975,1975,1975,150,151,'ZXAAAA','RDIAAA','VVVVxx'
+2641,5504,1,1,1,1,41,641,641,2641,2641,82,83,'PXAAAA','SDIAAA','AAAAxx'
+8616,5505,0,0,6,16,16,616,616,3616,8616,32,33,'KTAAAA','TDIAAA','HHHHxx'
+5980,5506,0,0,0,0,80,980,1980,980,5980,160,161,'AWAAAA','UDIAAA','OOOOxx'
+5170,5507,0,2,0,10,70,170,1170,170,5170,140,141,'WQAAAA','VDIAAA','VVVVxx'
+1960,5508,0,0,0,0,60,960,1960,1960,1960,120,121,'KXAAAA','WDIAAA','AAAAxx'
+8141,5509,1,1,1,1,41,141,141,3141,8141,82,83,'DBAAAA','XDIAAA','HHHHxx'
+6692,5510,0,0,2,12,92,692,692,1692,6692,184,185,'KXAAAA','YDIAAA','OOOOxx'
+7621,5511,1,1,1,1,21,621,1621,2621,7621,42,43,'DHAAAA','ZDIAAA','VVVVxx'
+3890,5512,0,2,0,10,90,890,1890,3890,3890,180,181,'QTAAAA','AEIAAA','AAAAxx'
+4300,5513,0,0,0,0,0,300,300,4300,4300,0,1,'KJAAAA','BEIAAA','HHHHxx'
+736,5514,0,0,6,16,36,736,736,736,736,72,73,'ICAAAA','CEIAAA','OOOOxx'
+6626,5515,0,2,6,6,26,626,626,1626,6626,52,53,'WUAAAA','DEIAAA','VVVVxx'
+1800,5516,0,0,0,0,0,800,1800,1800,1800,0,1,'GRAAAA','EEIAAA','AAAAxx'
+3430,5517,0,2,0,10,30,430,1430,3430,3430,60,61,'YBAAAA','FEIAAA','HHHHxx'
+9519,5518,1,3,9,19,19,519,1519,4519,9519,38,39,'DCAAAA','GEIAAA','OOOOxx'
+5111,5519,1,3,1,11,11,111,1111,111,5111,22,23,'POAAAA','HEIAAA','VVVVxx'
+6915,5520,1,3,5,15,15,915,915,1915,6915,30,31,'ZFAAAA','IEIAAA','AAAAxx'
+9246,5521,0,2,6,6,46,246,1246,4246,9246,92,93,'QRAAAA','JEIAAA','HHHHxx'
+5141,5522,1,1,1,1,41,141,1141,141,5141,82,83,'TPAAAA','KEIAAA','OOOOxx'
+5922,5523,0,2,2,2,22,922,1922,922,5922,44,45,'UTAAAA','LEIAAA','VVVVxx'
+3087,5524,1,3,7,7,87,87,1087,3087,3087,174,175,'TOAAAA','MEIAAA','AAAAxx'
+1859,5525,1,3,9,19,59,859,1859,1859,1859,118,119,'NTAAAA','NEIAAA','HHHHxx'
+8482,5526,0,2,2,2,82,482,482,3482,8482,164,165,'GOAAAA','OEIAAA','OOOOxx'
+8414,5527,0,2,4,14,14,414,414,3414,8414,28,29,'QLAAAA','PEIAAA','VVVVxx'
+6662,5528,0,2,2,2,62,662,662,1662,6662,124,125,'GWAAAA','QEIAAA','AAAAxx'
+8614,5529,0,2,4,14,14,614,614,3614,8614,28,29,'ITAAAA','REIAAA','HHHHxx'
+42,5530,0,2,2,2,42,42,42,42,42,84,85,'QBAAAA','SEIAAA','OOOOxx'
+7582,5531,0,2,2,2,82,582,1582,2582,7582,164,165,'QFAAAA','TEIAAA','VVVVxx'
+8183,5532,1,3,3,3,83,183,183,3183,8183,166,167,'TCAAAA','UEIAAA','AAAAxx'
+1299,5533,1,3,9,19,99,299,1299,1299,1299,198,199,'ZXAAAA','VEIAAA','HHHHxx'
+7004,5534,0,0,4,4,4,4,1004,2004,7004,8,9,'KJAAAA','WEIAAA','OOOOxx'
+3298,5535,0,2,8,18,98,298,1298,3298,3298,196,197,'WWAAAA','XEIAAA','VVVVxx'
+7884,5536,0,0,4,4,84,884,1884,2884,7884,168,169,'GRAAAA','YEIAAA','AAAAxx'
+4191,5537,1,3,1,11,91,191,191,4191,4191,182,183,'FFAAAA','ZEIAAA','HHHHxx'
+7346,5538,0,2,6,6,46,346,1346,2346,7346,92,93,'OWAAAA','AFIAAA','OOOOxx'
+7989,5539,1,1,9,9,89,989,1989,2989,7989,178,179,'HVAAAA','BFIAAA','VVVVxx'
+5719,5540,1,3,9,19,19,719,1719,719,5719,38,39,'ZLAAAA','CFIAAA','AAAAxx'
+800,5541,0,0,0,0,0,800,800,800,800,0,1,'UEAAAA','DFIAAA','HHHHxx'
+6509,5542,1,1,9,9,9,509,509,1509,6509,18,19,'JQAAAA','EFIAAA','OOOOxx'
+4672,5543,0,0,2,12,72,672,672,4672,4672,144,145,'SXAAAA','FFIAAA','VVVVxx'
+4434,5544,0,2,4,14,34,434,434,4434,4434,68,69,'OOAAAA','GFIAAA','AAAAxx'
+8309,5545,1,1,9,9,9,309,309,3309,8309,18,19,'PHAAAA','HFIAAA','HHHHxx'
+5134,5546,0,2,4,14,34,134,1134,134,5134,68,69,'MPAAAA','IFIAAA','OOOOxx'
+5153,5547,1,1,3,13,53,153,1153,153,5153,106,107,'FQAAAA','JFIAAA','VVVVxx'
+1522,5548,0,2,2,2,22,522,1522,1522,1522,44,45,'OGAAAA','KFIAAA','AAAAxx'
+8629,5549,1,1,9,9,29,629,629,3629,8629,58,59,'XTAAAA','LFIAAA','HHHHxx'
+4549,5550,1,1,9,9,49,549,549,4549,4549,98,99,'ZSAAAA','MFIAAA','OOOOxx'
+9506,5551,0,2,6,6,6,506,1506,4506,9506,12,13,'QBAAAA','NFIAAA','VVVVxx'
+6542,5552,0,2,2,2,42,542,542,1542,6542,84,85,'QRAAAA','OFIAAA','AAAAxx'
+2579,5553,1,3,9,19,79,579,579,2579,2579,158,159,'FVAAAA','PFIAAA','HHHHxx'
+4664,5554,0,0,4,4,64,664,664,4664,4664,128,129,'KXAAAA','QFIAAA','OOOOxx'
+696,5555,0,0,6,16,96,696,696,696,696,192,193,'UAAAAA','RFIAAA','VVVVxx'
+7950,5556,0,2,0,10,50,950,1950,2950,7950,100,101,'UTAAAA','SFIAAA','AAAAxx'
+5,5557,1,1,5,5,5,5,5,5,5,10,11,'FAAAAA','TFIAAA','HHHHxx'
+7806,5558,0,2,6,6,6,806,1806,2806,7806,12,13,'GOAAAA','UFIAAA','OOOOxx'
+2770,5559,0,2,0,10,70,770,770,2770,2770,140,141,'OCAAAA','VFIAAA','VVVVxx'
+1344,5560,0,0,4,4,44,344,1344,1344,1344,88,89,'SZAAAA','WFIAAA','AAAAxx'
+511,5561,1,3,1,11,11,511,511,511,511,22,23,'RTAAAA','XFIAAA','HHHHxx'
+9070,5562,0,2,0,10,70,70,1070,4070,9070,140,141,'WKAAAA','YFIAAA','OOOOxx'
+2961,5563,1,1,1,1,61,961,961,2961,2961,122,123,'XJAAAA','ZFIAAA','VVVVxx'
+8031,5564,1,3,1,11,31,31,31,3031,8031,62,63,'XWAAAA','AGIAAA','AAAAxx'
+326,5565,0,2,6,6,26,326,326,326,326,52,53,'OMAAAA','BGIAAA','HHHHxx'
+183,5566,1,3,3,3,83,183,183,183,183,166,167,'BHAAAA','CGIAAA','OOOOxx'
+5917,5567,1,1,7,17,17,917,1917,917,5917,34,35,'PTAAAA','DGIAAA','VVVVxx'
+8256,5568,0,0,6,16,56,256,256,3256,8256,112,113,'OFAAAA','EGIAAA','AAAAxx'
+7889,5569,1,1,9,9,89,889,1889,2889,7889,178,179,'LRAAAA','FGIAAA','HHHHxx'
+9029,5570,1,1,9,9,29,29,1029,4029,9029,58,59,'HJAAAA','GGIAAA','OOOOxx'
+1316,5571,0,0,6,16,16,316,1316,1316,1316,32,33,'QYAAAA','HGIAAA','VVVVxx'
+7442,5572,0,2,2,2,42,442,1442,2442,7442,84,85,'GAAAAA','IGIAAA','AAAAxx'
+2810,5573,0,2,0,10,10,810,810,2810,2810,20,21,'CEAAAA','JGIAAA','HHHHxx'
+20,5574,0,0,0,0,20,20,20,20,20,40,41,'UAAAAA','KGIAAA','OOOOxx'
+2306,5575,0,2,6,6,6,306,306,2306,2306,12,13,'SKAAAA','LGIAAA','VVVVxx'
+4694,5576,0,2,4,14,94,694,694,4694,4694,188,189,'OYAAAA','MGIAAA','AAAAxx'
+9710,5577,0,2,0,10,10,710,1710,4710,9710,20,21,'MJAAAA','NGIAAA','HHHHxx'
+1791,5578,1,3,1,11,91,791,1791,1791,1791,182,183,'XQAAAA','OGIAAA','OOOOxx'
+6730,5579,0,2,0,10,30,730,730,1730,6730,60,61,'WYAAAA','PGIAAA','VVVVxx'
+359,5580,1,3,9,19,59,359,359,359,359,118,119,'VNAAAA','QGIAAA','AAAAxx'
+8097,5581,1,1,7,17,97,97,97,3097,8097,194,195,'LZAAAA','RGIAAA','HHHHxx'
+6147,5582,1,3,7,7,47,147,147,1147,6147,94,95,'LCAAAA','SGIAAA','OOOOxx'
+643,5583,1,3,3,3,43,643,643,643,643,86,87,'TYAAAA','TGIAAA','VVVVxx'
+698,5584,0,2,8,18,98,698,698,698,698,196,197,'WAAAAA','UGIAAA','AAAAxx'
+3881,5585,1,1,1,1,81,881,1881,3881,3881,162,163,'HTAAAA','VGIAAA','HHHHxx'
+7600,5586,0,0,0,0,0,600,1600,2600,7600,0,1,'IGAAAA','WGIAAA','OOOOxx'
+1583,5587,1,3,3,3,83,583,1583,1583,1583,166,167,'XIAAAA','XGIAAA','VVVVxx'
+9612,5588,0,0,2,12,12,612,1612,4612,9612,24,25,'SFAAAA','YGIAAA','AAAAxx'
+1032,5589,0,0,2,12,32,32,1032,1032,1032,64,65,'SNAAAA','ZGIAAA','HHHHxx'
+4834,5590,0,2,4,14,34,834,834,4834,4834,68,69,'YDAAAA','AHIAAA','OOOOxx'
+5076,5591,0,0,6,16,76,76,1076,76,5076,152,153,'GNAAAA','BHIAAA','VVVVxx'
+3070,5592,0,2,0,10,70,70,1070,3070,3070,140,141,'COAAAA','CHIAAA','AAAAxx'
+1421,5593,1,1,1,1,21,421,1421,1421,1421,42,43,'RCAAAA','DHIAAA','HHHHxx'
+8970,5594,0,2,0,10,70,970,970,3970,8970,140,141,'AHAAAA','EHIAAA','OOOOxx'
+6271,5595,1,3,1,11,71,271,271,1271,6271,142,143,'FHAAAA','FHIAAA','VVVVxx'
+8547,5596,1,3,7,7,47,547,547,3547,8547,94,95,'TQAAAA','GHIAAA','AAAAxx'
+1259,5597,1,3,9,19,59,259,1259,1259,1259,118,119,'LWAAAA','HHIAAA','HHHHxx'
+8328,5598,0,0,8,8,28,328,328,3328,8328,56,57,'IIAAAA','IHIAAA','OOOOxx'
+1503,5599,1,3,3,3,3,503,1503,1503,1503,6,7,'VFAAAA','JHIAAA','VVVVxx'
+2253,5600,1,1,3,13,53,253,253,2253,2253,106,107,'RIAAAA','KHIAAA','AAAAxx'
+7449,5601,1,1,9,9,49,449,1449,2449,7449,98,99,'NAAAAA','LHIAAA','HHHHxx'
+3579,5602,1,3,9,19,79,579,1579,3579,3579,158,159,'RHAAAA','MHIAAA','OOOOxx'
+1585,5603,1,1,5,5,85,585,1585,1585,1585,170,171,'ZIAAAA','NHIAAA','VVVVxx'
+5543,5604,1,3,3,3,43,543,1543,543,5543,86,87,'FFAAAA','OHIAAA','AAAAxx'
+8627,5605,1,3,7,7,27,627,627,3627,8627,54,55,'VTAAAA','PHIAAA','HHHHxx'
+8618,5606,0,2,8,18,18,618,618,3618,8618,36,37,'MTAAAA','QHIAAA','OOOOxx'
+1911,5607,1,3,1,11,11,911,1911,1911,1911,22,23,'NVAAAA','RHIAAA','VVVVxx'
+2758,5608,0,2,8,18,58,758,758,2758,2758,116,117,'CCAAAA','SHIAAA','AAAAxx'
+5744,5609,0,0,4,4,44,744,1744,744,5744,88,89,'YMAAAA','THIAAA','HHHHxx'
+4976,5610,0,0,6,16,76,976,976,4976,4976,152,153,'KJAAAA','UHIAAA','OOOOxx'
+6380,5611,0,0,0,0,80,380,380,1380,6380,160,161,'KLAAAA','VHIAAA','VVVVxx'
+1937,5612,1,1,7,17,37,937,1937,1937,1937,74,75,'NWAAAA','WHIAAA','AAAAxx'
+9903,5613,1,3,3,3,3,903,1903,4903,9903,6,7,'XQAAAA','XHIAAA','HHHHxx'
+4409,5614,1,1,9,9,9,409,409,4409,4409,18,19,'PNAAAA','YHIAAA','OOOOxx'
+4133,5615,1,1,3,13,33,133,133,4133,4133,66,67,'ZCAAAA','ZHIAAA','VVVVxx'
+5263,5616,1,3,3,3,63,263,1263,263,5263,126,127,'LUAAAA','AIIAAA','AAAAxx'
+7888,5617,0,0,8,8,88,888,1888,2888,7888,176,177,'KRAAAA','BIIAAA','HHHHxx'
+6060,5618,0,0,0,0,60,60,60,1060,6060,120,121,'CZAAAA','CIIAAA','OOOOxx'
+2522,5619,0,2,2,2,22,522,522,2522,2522,44,45,'ATAAAA','DIIAAA','VVVVxx'
+5550,5620,0,2,0,10,50,550,1550,550,5550,100,101,'MFAAAA','EIIAAA','AAAAxx'
+9396,5621,0,0,6,16,96,396,1396,4396,9396,192,193,'KXAAAA','FIIAAA','HHHHxx'
+176,5622,0,0,6,16,76,176,176,176,176,152,153,'UGAAAA','GIIAAA','OOOOxx'
+5148,5623,0,0,8,8,48,148,1148,148,5148,96,97,'AQAAAA','HIIAAA','VVVVxx'
+6691,5624,1,3,1,11,91,691,691,1691,6691,182,183,'JXAAAA','IIIAAA','AAAAxx'
+4652,5625,0,0,2,12,52,652,652,4652,4652,104,105,'YWAAAA','JIIAAA','HHHHxx'
+5096,5626,0,0,6,16,96,96,1096,96,5096,192,193,'AOAAAA','KIIAAA','OOOOxx'
+2408,5627,0,0,8,8,8,408,408,2408,2408,16,17,'QOAAAA','LIIAAA','VVVVxx'
+7322,5628,0,2,2,2,22,322,1322,2322,7322,44,45,'QVAAAA','MIIAAA','AAAAxx'
+6782,5629,0,2,2,2,82,782,782,1782,6782,164,165,'WAAAAA','NIIAAA','HHHHxx'
+4642,5630,0,2,2,2,42,642,642,4642,4642,84,85,'OWAAAA','OIIAAA','OOOOxx'
+5427,5631,1,3,7,7,27,427,1427,427,5427,54,55,'TAAAAA','PIIAAA','VVVVxx'
+4461,5632,1,1,1,1,61,461,461,4461,4461,122,123,'PPAAAA','QIIAAA','AAAAxx'
+8416,5633,0,0,6,16,16,416,416,3416,8416,32,33,'SLAAAA','RIIAAA','HHHHxx'
+2593,5634,1,1,3,13,93,593,593,2593,2593,186,187,'TVAAAA','SIIAAA','OOOOxx'
+6202,5635,0,2,2,2,2,202,202,1202,6202,4,5,'OEAAAA','TIIAAA','VVVVxx'
+3826,5636,0,2,6,6,26,826,1826,3826,3826,52,53,'ERAAAA','UIIAAA','AAAAxx'
+4417,5637,1,1,7,17,17,417,417,4417,4417,34,35,'XNAAAA','VIIAAA','HHHHxx'
+7871,5638,1,3,1,11,71,871,1871,2871,7871,142,143,'TQAAAA','WIIAAA','OOOOxx'
+5622,5639,0,2,2,2,22,622,1622,622,5622,44,45,'GIAAAA','XIIAAA','VVVVxx'
+3010,5640,0,2,0,10,10,10,1010,3010,3010,20,21,'ULAAAA','YIIAAA','AAAAxx'
+3407,5641,1,3,7,7,7,407,1407,3407,3407,14,15,'BBAAAA','ZIIAAA','HHHHxx'
+1274,5642,0,2,4,14,74,274,1274,1274,1274,148,149,'AXAAAA','AJIAAA','OOOOxx'
+2828,5643,0,0,8,8,28,828,828,2828,2828,56,57,'UEAAAA','BJIAAA','VVVVxx'
+3427,5644,1,3,7,7,27,427,1427,3427,3427,54,55,'VBAAAA','CJIAAA','AAAAxx'
+612,5645,0,0,2,12,12,612,612,612,612,24,25,'OXAAAA','DJIAAA','HHHHxx'
+8729,5646,1,1,9,9,29,729,729,3729,8729,58,59,'TXAAAA','EJIAAA','OOOOxx'
+1239,5647,1,3,9,19,39,239,1239,1239,1239,78,79,'RVAAAA','FJIAAA','VVVVxx'
+8990,5648,0,2,0,10,90,990,990,3990,8990,180,181,'UHAAAA','GJIAAA','AAAAxx'
+5609,5649,1,1,9,9,9,609,1609,609,5609,18,19,'THAAAA','HJIAAA','HHHHxx'
+4441,5650,1,1,1,1,41,441,441,4441,4441,82,83,'VOAAAA','IJIAAA','OOOOxx'
+9078,5651,0,2,8,18,78,78,1078,4078,9078,156,157,'ELAAAA','JJIAAA','VVVVxx'
+6699,5652,1,3,9,19,99,699,699,1699,6699,198,199,'RXAAAA','KJIAAA','AAAAxx'
+8390,5653,0,2,0,10,90,390,390,3390,8390,180,181,'SKAAAA','LJIAAA','HHHHxx'
+5455,5654,1,3,5,15,55,455,1455,455,5455,110,111,'VBAAAA','MJIAAA','OOOOxx'
+7537,5655,1,1,7,17,37,537,1537,2537,7537,74,75,'XDAAAA','NJIAAA','VVVVxx'
+4669,5656,1,1,9,9,69,669,669,4669,4669,138,139,'PXAAAA','OJIAAA','AAAAxx'
+5534,5657,0,2,4,14,34,534,1534,534,5534,68,69,'WEAAAA','PJIAAA','HHHHxx'
+1920,5658,0,0,0,0,20,920,1920,1920,1920,40,41,'WVAAAA','QJIAAA','OOOOxx'
+9465,5659,1,1,5,5,65,465,1465,4465,9465,130,131,'BAAAAA','RJIAAA','VVVVxx'
+4897,5660,1,1,7,17,97,897,897,4897,4897,194,195,'JGAAAA','SJIAAA','AAAAxx'
+1990,5661,0,2,0,10,90,990,1990,1990,1990,180,181,'OYAAAA','TJIAAA','HHHHxx'
+7148,5662,0,0,8,8,48,148,1148,2148,7148,96,97,'YOAAAA','UJIAAA','OOOOxx'
+533,5663,1,1,3,13,33,533,533,533,533,66,67,'NUAAAA','VJIAAA','VVVVxx'
+4339,5664,1,3,9,19,39,339,339,4339,4339,78,79,'XKAAAA','WJIAAA','AAAAxx'
+6450,5665,0,2,0,10,50,450,450,1450,6450,100,101,'COAAAA','XJIAAA','HHHHxx'
+9627,5666,1,3,7,7,27,627,1627,4627,9627,54,55,'HGAAAA','YJIAAA','OOOOxx'
+5539,5667,1,3,9,19,39,539,1539,539,5539,78,79,'BFAAAA','ZJIAAA','VVVVxx'
+6758,5668,0,2,8,18,58,758,758,1758,6758,116,117,'YZAAAA','AKIAAA','AAAAxx'
+3435,5669,1,3,5,15,35,435,1435,3435,3435,70,71,'DCAAAA','BKIAAA','HHHHxx'
+4350,5670,0,2,0,10,50,350,350,4350,4350,100,101,'ILAAAA','CKIAAA','OOOOxx'
+9088,5671,0,0,8,8,88,88,1088,4088,9088,176,177,'OLAAAA','DKIAAA','VVVVxx'
+6368,5672,0,0,8,8,68,368,368,1368,6368,136,137,'YKAAAA','EKIAAA','AAAAxx'
+6337,5673,1,1,7,17,37,337,337,1337,6337,74,75,'TJAAAA','FKIAAA','HHHHxx'
+4361,5674,1,1,1,1,61,361,361,4361,4361,122,123,'TLAAAA','GKIAAA','OOOOxx'
+1719,5675,1,3,9,19,19,719,1719,1719,1719,38,39,'DOAAAA','HKIAAA','VVVVxx'
+3109,5676,1,1,9,9,9,109,1109,3109,3109,18,19,'PPAAAA','IKIAAA','AAAAxx'
+7135,5677,1,3,5,15,35,135,1135,2135,7135,70,71,'LOAAAA','JKIAAA','HHHHxx'
+1964,5678,0,0,4,4,64,964,1964,1964,1964,128,129,'OXAAAA','KKIAAA','OOOOxx'
+3,5679,1,3,3,3,3,3,3,3,3,6,7,'DAAAAA','LKIAAA','VVVVxx'
+1868,5680,0,0,8,8,68,868,1868,1868,1868,136,137,'WTAAAA','MKIAAA','AAAAxx'
+5182,5681,0,2,2,2,82,182,1182,182,5182,164,165,'IRAAAA','NKIAAA','HHHHxx'
+7567,5682,1,3,7,7,67,567,1567,2567,7567,134,135,'BFAAAA','OKIAAA','OOOOxx'
+3676,5683,0,0,6,16,76,676,1676,3676,3676,152,153,'KLAAAA','PKIAAA','VVVVxx'
+9382,5684,0,2,2,2,82,382,1382,4382,9382,164,165,'WWAAAA','QKIAAA','AAAAxx'
+8645,5685,1,1,5,5,45,645,645,3645,8645,90,91,'NUAAAA','RKIAAA','HHHHxx'
+2018,5686,0,2,8,18,18,18,18,2018,2018,36,37,'QZAAAA','SKIAAA','OOOOxx'
+217,5687,1,1,7,17,17,217,217,217,217,34,35,'JIAAAA','TKIAAA','VVVVxx'
+6793,5688,1,1,3,13,93,793,793,1793,6793,186,187,'HBAAAA','UKIAAA','AAAAxx'
+7280,5689,0,0,0,0,80,280,1280,2280,7280,160,161,'AUAAAA','VKIAAA','HHHHxx'
+2168,5690,0,0,8,8,68,168,168,2168,2168,136,137,'KFAAAA','WKIAAA','OOOOxx'
+5259,5691,1,3,9,19,59,259,1259,259,5259,118,119,'HUAAAA','XKIAAA','VVVVxx'
+6019,5692,1,3,9,19,19,19,19,1019,6019,38,39,'NXAAAA','YKIAAA','AAAAxx'
+877,5693,1,1,7,17,77,877,877,877,877,154,155,'THAAAA','ZKIAAA','HHHHxx'
+4961,5694,1,1,1,1,61,961,961,4961,4961,122,123,'VIAAAA','ALIAAA','OOOOxx'
+1873,5695,1,1,3,13,73,873,1873,1873,1873,146,147,'BUAAAA','BLIAAA','VVVVxx'
+13,5696,1,1,3,13,13,13,13,13,13,26,27,'NAAAAA','CLIAAA','AAAAxx'
+1537,5697,1,1,7,17,37,537,1537,1537,1537,74,75,'DHAAAA','DLIAAA','HHHHxx'
+3129,5698,1,1,9,9,29,129,1129,3129,3129,58,59,'JQAAAA','ELIAAA','OOOOxx'
+6473,5699,1,1,3,13,73,473,473,1473,6473,146,147,'ZOAAAA','FLIAAA','VVVVxx'
+7865,5700,1,1,5,5,65,865,1865,2865,7865,130,131,'NQAAAA','GLIAAA','AAAAxx'
+7822,5701,0,2,2,2,22,822,1822,2822,7822,44,45,'WOAAAA','HLIAAA','HHHHxx'
+239,5702,1,3,9,19,39,239,239,239,239,78,79,'FJAAAA','ILIAAA','OOOOxx'
+2062,5703,0,2,2,2,62,62,62,2062,2062,124,125,'IBAAAA','JLIAAA','VVVVxx'
+762,5704,0,2,2,2,62,762,762,762,762,124,125,'IDAAAA','KLIAAA','AAAAxx'
+3764,5705,0,0,4,4,64,764,1764,3764,3764,128,129,'UOAAAA','LLIAAA','HHHHxx'
+465,5706,1,1,5,5,65,465,465,465,465,130,131,'XRAAAA','MLIAAA','OOOOxx'
+2587,5707,1,3,7,7,87,587,587,2587,2587,174,175,'NVAAAA','NLIAAA','VVVVxx'
+8402,5708,0,2,2,2,2,402,402,3402,8402,4,5,'ELAAAA','OLIAAA','AAAAxx'
+1055,5709,1,3,5,15,55,55,1055,1055,1055,110,111,'POAAAA','PLIAAA','HHHHxx'
+3072,5710,0,0,2,12,72,72,1072,3072,3072,144,145,'EOAAAA','QLIAAA','OOOOxx'
+7359,5711,1,3,9,19,59,359,1359,2359,7359,118,119,'BXAAAA','RLIAAA','VVVVxx'
+6558,5712,0,2,8,18,58,558,558,1558,6558,116,117,'GSAAAA','SLIAAA','AAAAxx'
+48,5713,0,0,8,8,48,48,48,48,48,96,97,'WBAAAA','TLIAAA','HHHHxx'
+5382,5714,0,2,2,2,82,382,1382,382,5382,164,165,'AZAAAA','ULIAAA','OOOOxx'
+947,5715,1,3,7,7,47,947,947,947,947,94,95,'LKAAAA','VLIAAA','VVVVxx'
+2644,5716,0,0,4,4,44,644,644,2644,2644,88,89,'SXAAAA','WLIAAA','AAAAxx'
+7516,5717,0,0,6,16,16,516,1516,2516,7516,32,33,'CDAAAA','XLIAAA','HHHHxx'
+2362,5718,0,2,2,2,62,362,362,2362,2362,124,125,'WMAAAA','YLIAAA','OOOOxx'
+839,5719,1,3,9,19,39,839,839,839,839,78,79,'HGAAAA','ZLIAAA','VVVVxx'
+2216,5720,0,0,6,16,16,216,216,2216,2216,32,33,'GHAAAA','AMIAAA','AAAAxx'
+7673,5721,1,1,3,13,73,673,1673,2673,7673,146,147,'DJAAAA','BMIAAA','HHHHxx'
+8173,5722,1,1,3,13,73,173,173,3173,8173,146,147,'JCAAAA','CMIAAA','OOOOxx'
+1630,5723,0,2,0,10,30,630,1630,1630,1630,60,61,'SKAAAA','DMIAAA','VVVVxx'
+9057,5724,1,1,7,17,57,57,1057,4057,9057,114,115,'JKAAAA','EMIAAA','AAAAxx'
+4392,5725,0,0,2,12,92,392,392,4392,4392,184,185,'YMAAAA','FMIAAA','HHHHxx'
+3695,5726,1,3,5,15,95,695,1695,3695,3695,190,191,'DMAAAA','GMIAAA','OOOOxx'
+5751,5727,1,3,1,11,51,751,1751,751,5751,102,103,'FNAAAA','HMIAAA','VVVVxx'
+5745,5728,1,1,5,5,45,745,1745,745,5745,90,91,'ZMAAAA','IMIAAA','AAAAxx'
+7945,5729,1,1,5,5,45,945,1945,2945,7945,90,91,'PTAAAA','JMIAAA','HHHHxx'
+5174,5730,0,2,4,14,74,174,1174,174,5174,148,149,'ARAAAA','KMIAAA','OOOOxx'
+3829,5731,1,1,9,9,29,829,1829,3829,3829,58,59,'HRAAAA','LMIAAA','VVVVxx'
+3317,5732,1,1,7,17,17,317,1317,3317,3317,34,35,'PXAAAA','MMIAAA','AAAAxx'
+4253,5733,1,1,3,13,53,253,253,4253,4253,106,107,'PHAAAA','NMIAAA','HHHHxx'
+1291,5734,1,3,1,11,91,291,1291,1291,1291,182,183,'RXAAAA','OMIAAA','OOOOxx'
+3266,5735,0,2,6,6,66,266,1266,3266,3266,132,133,'QVAAAA','PMIAAA','VVVVxx'
+2939,5736,1,3,9,19,39,939,939,2939,2939,78,79,'BJAAAA','QMIAAA','AAAAxx'
+2755,5737,1,3,5,15,55,755,755,2755,2755,110,111,'ZBAAAA','RMIAAA','HHHHxx'
+6844,5738,0,0,4,4,44,844,844,1844,6844,88,89,'GDAAAA','SMIAAA','OOOOxx'
+8594,5739,0,2,4,14,94,594,594,3594,8594,188,189,'OSAAAA','TMIAAA','VVVVxx'
+704,5740,0,0,4,4,4,704,704,704,704,8,9,'CBAAAA','UMIAAA','AAAAxx'
+1681,5741,1,1,1,1,81,681,1681,1681,1681,162,163,'RMAAAA','VMIAAA','HHHHxx'
+364,5742,0,0,4,4,64,364,364,364,364,128,129,'AOAAAA','WMIAAA','OOOOxx'
+2928,5743,0,0,8,8,28,928,928,2928,2928,56,57,'QIAAAA','XMIAAA','VVVVxx'
+117,5744,1,1,7,17,17,117,117,117,117,34,35,'NEAAAA','YMIAAA','AAAAxx'
+96,5745,0,0,6,16,96,96,96,96,96,192,193,'SDAAAA','ZMIAAA','HHHHxx'
+7796,5746,0,0,6,16,96,796,1796,2796,7796,192,193,'WNAAAA','ANIAAA','OOOOxx'
+3101,5747,1,1,1,1,1,101,1101,3101,3101,2,3,'HPAAAA','BNIAAA','VVVVxx'
+3397,5748,1,1,7,17,97,397,1397,3397,3397,194,195,'RAAAAA','CNIAAA','AAAAxx'
+1605,5749,1,1,5,5,5,605,1605,1605,1605,10,11,'TJAAAA','DNIAAA','HHHHxx'
+4881,5750,1,1,1,1,81,881,881,4881,4881,162,163,'TFAAAA','ENIAAA','OOOOxx'
+4521,5751,1,1,1,1,21,521,521,4521,4521,42,43,'XRAAAA','FNIAAA','VVVVxx'
+6430,5752,0,2,0,10,30,430,430,1430,6430,60,61,'INAAAA','GNIAAA','AAAAxx'
+282,5753,0,2,2,2,82,282,282,282,282,164,165,'WKAAAA','HNIAAA','HHHHxx'
+9645,5754,1,1,5,5,45,645,1645,4645,9645,90,91,'ZGAAAA','INIAAA','OOOOxx'
+8946,5755,0,2,6,6,46,946,946,3946,8946,92,93,'CGAAAA','JNIAAA','VVVVxx'
+5064,5756,0,0,4,4,64,64,1064,64,5064,128,129,'UMAAAA','KNIAAA','AAAAxx'
+7470,5757,0,2,0,10,70,470,1470,2470,7470,140,141,'IBAAAA','LNIAAA','HHHHxx'
+5886,5758,0,2,6,6,86,886,1886,886,5886,172,173,'KSAAAA','MNIAAA','OOOOxx'
+6280,5759,0,0,0,0,80,280,280,1280,6280,160,161,'OHAAAA','NNIAAA','VVVVxx'
+5247,5760,1,3,7,7,47,247,1247,247,5247,94,95,'VTAAAA','ONIAAA','AAAAxx'
+412,5761,0,0,2,12,12,412,412,412,412,24,25,'WPAAAA','PNIAAA','HHHHxx'
+5342,5762,0,2,2,2,42,342,1342,342,5342,84,85,'MXAAAA','QNIAAA','OOOOxx'
+2271,5763,1,3,1,11,71,271,271,2271,2271,142,143,'JJAAAA','RNIAAA','VVVVxx'
+849,5764,1,1,9,9,49,849,849,849,849,98,99,'RGAAAA','SNIAAA','AAAAxx'
+1885,5765,1,1,5,5,85,885,1885,1885,1885,170,171,'NUAAAA','TNIAAA','HHHHxx'
+5620,5766,0,0,0,0,20,620,1620,620,5620,40,41,'EIAAAA','UNIAAA','OOOOxx'
+7079,5767,1,3,9,19,79,79,1079,2079,7079,158,159,'HMAAAA','VNIAAA','VVVVxx'
+5819,5768,1,3,9,19,19,819,1819,819,5819,38,39,'VPAAAA','WNIAAA','AAAAxx'
+7497,5769,1,1,7,17,97,497,1497,2497,7497,194,195,'JCAAAA','XNIAAA','HHHHxx'
+5993,5770,1,1,3,13,93,993,1993,993,5993,186,187,'NWAAAA','YNIAAA','OOOOxx'
+3739,5771,1,3,9,19,39,739,1739,3739,3739,78,79,'VNAAAA','ZNIAAA','VVVVxx'
+6296,5772,0,0,6,16,96,296,296,1296,6296,192,193,'EIAAAA','AOIAAA','AAAAxx'
+2716,5773,0,0,6,16,16,716,716,2716,2716,32,33,'MAAAAA','BOIAAA','HHHHxx'
+1130,5774,0,2,0,10,30,130,1130,1130,1130,60,61,'MRAAAA','COIAAA','OOOOxx'
+5593,5775,1,1,3,13,93,593,1593,593,5593,186,187,'DHAAAA','DOIAAA','VVVVxx'
+6972,5776,0,0,2,12,72,972,972,1972,6972,144,145,'EIAAAA','EOIAAA','AAAAxx'
+8360,5777,0,0,0,0,60,360,360,3360,8360,120,121,'OJAAAA','FOIAAA','HHHHxx'
+6448,5778,0,0,8,8,48,448,448,1448,6448,96,97,'AOAAAA','GOIAAA','OOOOxx'
+3689,5779,1,1,9,9,89,689,1689,3689,3689,178,179,'XLAAAA','HOIAAA','VVVVxx'
+7951,5780,1,3,1,11,51,951,1951,2951,7951,102,103,'VTAAAA','IOIAAA','AAAAxx'
+2974,5781,0,2,4,14,74,974,974,2974,2974,148,149,'KKAAAA','JOIAAA','HHHHxx'
+6600,5782,0,0,0,0,0,600,600,1600,6600,0,1,'WTAAAA','KOIAAA','OOOOxx'
+4662,5783,0,2,2,2,62,662,662,4662,4662,124,125,'IXAAAA','LOIAAA','VVVVxx'
+4765,5784,1,1,5,5,65,765,765,4765,4765,130,131,'HBAAAA','MOIAAA','AAAAxx'
+355,5785,1,3,5,15,55,355,355,355,355,110,111,'RNAAAA','NOIAAA','HHHHxx'
+6228,5786,0,0,8,8,28,228,228,1228,6228,56,57,'OFAAAA','OOIAAA','OOOOxx'
+964,5787,0,0,4,4,64,964,964,964,964,128,129,'CLAAAA','POIAAA','VVVVxx'
+3082,5788,0,2,2,2,82,82,1082,3082,3082,164,165,'OOAAAA','QOIAAA','AAAAxx'
+7028,5789,0,0,8,8,28,28,1028,2028,7028,56,57,'IKAAAA','ROIAAA','HHHHxx'
+4505,5790,1,1,5,5,5,505,505,4505,4505,10,11,'HRAAAA','SOIAAA','OOOOxx'
+8961,5791,1,1,1,1,61,961,961,3961,8961,122,123,'RGAAAA','TOIAAA','VVVVxx'
+9571,5792,1,3,1,11,71,571,1571,4571,9571,142,143,'DEAAAA','UOIAAA','AAAAxx'
+9394,5793,0,2,4,14,94,394,1394,4394,9394,188,189,'IXAAAA','VOIAAA','HHHHxx'
+4245,5794,1,1,5,5,45,245,245,4245,4245,90,91,'HHAAAA','WOIAAA','OOOOxx'
+7560,5795,0,0,0,0,60,560,1560,2560,7560,120,121,'UEAAAA','XOIAAA','VVVVxx'
+2907,5796,1,3,7,7,7,907,907,2907,2907,14,15,'VHAAAA','YOIAAA','AAAAxx'
+7817,5797,1,1,7,17,17,817,1817,2817,7817,34,35,'ROAAAA','ZOIAAA','HHHHxx'
+5408,5798,0,0,8,8,8,408,1408,408,5408,16,17,'AAAAAA','APIAAA','OOOOxx'
+8092,5799,0,0,2,12,92,92,92,3092,8092,184,185,'GZAAAA','BPIAAA','VVVVxx'
+1309,5800,1,1,9,9,9,309,1309,1309,1309,18,19,'JYAAAA','CPIAAA','AAAAxx'
+6673,5801,1,1,3,13,73,673,673,1673,6673,146,147,'RWAAAA','DPIAAA','HHHHxx'
+1245,5802,1,1,5,5,45,245,1245,1245,1245,90,91,'XVAAAA','EPIAAA','OOOOxx'
+6790,5803,0,2,0,10,90,790,790,1790,6790,180,181,'EBAAAA','FPIAAA','VVVVxx'
+8380,5804,0,0,0,0,80,380,380,3380,8380,160,161,'IKAAAA','GPIAAA','AAAAxx'
+5786,5805,0,2,6,6,86,786,1786,786,5786,172,173,'OOAAAA','HPIAAA','HHHHxx'
+9590,5806,0,2,0,10,90,590,1590,4590,9590,180,181,'WEAAAA','IPIAAA','OOOOxx'
+5763,5807,1,3,3,3,63,763,1763,763,5763,126,127,'RNAAAA','JPIAAA','VVVVxx'
+1345,5808,1,1,5,5,45,345,1345,1345,1345,90,91,'TZAAAA','KPIAAA','AAAAxx'
+3480,5809,0,0,0,0,80,480,1480,3480,3480,160,161,'WDAAAA','LPIAAA','HHHHxx'
+7864,5810,0,0,4,4,64,864,1864,2864,7864,128,129,'MQAAAA','MPIAAA','OOOOxx'
+4853,5811,1,1,3,13,53,853,853,4853,4853,106,107,'REAAAA','NPIAAA','VVVVxx'
+1445,5812,1,1,5,5,45,445,1445,1445,1445,90,91,'PDAAAA','OPIAAA','AAAAxx'
+170,5813,0,2,0,10,70,170,170,170,170,140,141,'OGAAAA','PPIAAA','HHHHxx'
+7348,5814,0,0,8,8,48,348,1348,2348,7348,96,97,'QWAAAA','QPIAAA','OOOOxx'
+3920,5815,0,0,0,0,20,920,1920,3920,3920,40,41,'UUAAAA','RPIAAA','VVVVxx'
+3307,5816,1,3,7,7,7,307,1307,3307,3307,14,15,'FXAAAA','SPIAAA','AAAAxx'
+4584,5817,0,0,4,4,84,584,584,4584,4584,168,169,'IUAAAA','TPIAAA','HHHHxx'
+3344,5818,0,0,4,4,44,344,1344,3344,3344,88,89,'QYAAAA','UPIAAA','OOOOxx'
+4360,5819,0,0,0,0,60,360,360,4360,4360,120,121,'SLAAAA','VPIAAA','VVVVxx'
+8757,5820,1,1,7,17,57,757,757,3757,8757,114,115,'VYAAAA','WPIAAA','AAAAxx'
+4315,5821,1,3,5,15,15,315,315,4315,4315,30,31,'ZJAAAA','XPIAAA','HHHHxx'
+5243,5822,1,3,3,3,43,243,1243,243,5243,86,87,'RTAAAA','YPIAAA','OOOOxx'
+8550,5823,0,2,0,10,50,550,550,3550,8550,100,101,'WQAAAA','ZPIAAA','VVVVxx'
+159,5824,1,3,9,19,59,159,159,159,159,118,119,'DGAAAA','AQIAAA','AAAAxx'
+4710,5825,0,2,0,10,10,710,710,4710,4710,20,21,'EZAAAA','BQIAAA','HHHHxx'
+7179,5826,1,3,9,19,79,179,1179,2179,7179,158,159,'DQAAAA','CQIAAA','OOOOxx'
+2509,5827,1,1,9,9,9,509,509,2509,2509,18,19,'NSAAAA','DQIAAA','VVVVxx'
+6981,5828,1,1,1,1,81,981,981,1981,6981,162,163,'NIAAAA','EQIAAA','AAAAxx'
+5060,5829,0,0,0,0,60,60,1060,60,5060,120,121,'QMAAAA','FQIAAA','HHHHxx'
+5601,5830,1,1,1,1,1,601,1601,601,5601,2,3,'LHAAAA','GQIAAA','OOOOxx'
+703,5831,1,3,3,3,3,703,703,703,703,6,7,'BBAAAA','HQIAAA','VVVVxx'
+8719,5832,1,3,9,19,19,719,719,3719,8719,38,39,'JXAAAA','IQIAAA','AAAAxx'
+1570,5833,0,2,0,10,70,570,1570,1570,1570,140,141,'KIAAAA','JQIAAA','HHHHxx'
+1036,5834,0,0,6,16,36,36,1036,1036,1036,72,73,'WNAAAA','KQIAAA','OOOOxx'
+6703,5835,1,3,3,3,3,703,703,1703,6703,6,7,'VXAAAA','LQIAAA','VVVVxx'
+252,5836,0,0,2,12,52,252,252,252,252,104,105,'SJAAAA','MQIAAA','AAAAxx'
+631,5837,1,3,1,11,31,631,631,631,631,62,63,'HYAAAA','NQIAAA','HHHHxx'
+5098,5838,0,2,8,18,98,98,1098,98,5098,196,197,'COAAAA','OQIAAA','OOOOxx'
+8346,5839,0,2,6,6,46,346,346,3346,8346,92,93,'AJAAAA','PQIAAA','VVVVxx'
+4910,5840,0,2,0,10,10,910,910,4910,4910,20,21,'WGAAAA','QQIAAA','AAAAxx'
+559,5841,1,3,9,19,59,559,559,559,559,118,119,'NVAAAA','RQIAAA','HHHHxx'
+1477,5842,1,1,7,17,77,477,1477,1477,1477,154,155,'VEAAAA','SQIAAA','OOOOxx'
+5115,5843,1,3,5,15,15,115,1115,115,5115,30,31,'TOAAAA','TQIAAA','VVVVxx'
+8784,5844,0,0,4,4,84,784,784,3784,8784,168,169,'WZAAAA','UQIAAA','AAAAxx'
+4422,5845,0,2,2,2,22,422,422,4422,4422,44,45,'COAAAA','VQIAAA','HHHHxx'
+2702,5846,0,2,2,2,2,702,702,2702,2702,4,5,'YZAAAA','WQIAAA','OOOOxx'
+9599,5847,1,3,9,19,99,599,1599,4599,9599,198,199,'FFAAAA','XQIAAA','VVVVxx'
+2463,5848,1,3,3,3,63,463,463,2463,2463,126,127,'TQAAAA','YQIAAA','AAAAxx'
+498,5849,0,2,8,18,98,498,498,498,498,196,197,'ETAAAA','ZQIAAA','HHHHxx'
+494,5850,0,2,4,14,94,494,494,494,494,188,189,'ATAAAA','ARIAAA','OOOOxx'
+8632,5851,0,0,2,12,32,632,632,3632,8632,64,65,'AUAAAA','BRIAAA','VVVVxx'
+3449,5852,1,1,9,9,49,449,1449,3449,3449,98,99,'RCAAAA','CRIAAA','AAAAxx'
+5888,5853,0,0,8,8,88,888,1888,888,5888,176,177,'MSAAAA','DRIAAA','HHHHxx'
+2211,5854,1,3,1,11,11,211,211,2211,2211,22,23,'BHAAAA','ERIAAA','OOOOxx'
+2835,5855,1,3,5,15,35,835,835,2835,2835,70,71,'BFAAAA','FRIAAA','VVVVxx'
+4196,5856,0,0,6,16,96,196,196,4196,4196,192,193,'KFAAAA','GRIAAA','AAAAxx'
+2177,5857,1,1,7,17,77,177,177,2177,2177,154,155,'TFAAAA','HRIAAA','HHHHxx'
+1959,5858,1,3,9,19,59,959,1959,1959,1959,118,119,'JXAAAA','IRIAAA','OOOOxx'
+5172,5859,0,0,2,12,72,172,1172,172,5172,144,145,'YQAAAA','JRIAAA','VVVVxx'
+7898,5860,0,2,8,18,98,898,1898,2898,7898,196,197,'URAAAA','KRIAAA','AAAAxx'
+5729,5861,1,1,9,9,29,729,1729,729,5729,58,59,'JMAAAA','LRIAAA','HHHHxx'
+469,5862,1,1,9,9,69,469,469,469,469,138,139,'BSAAAA','MRIAAA','OOOOxx'
+4456,5863,0,0,6,16,56,456,456,4456,4456,112,113,'KPAAAA','NRIAAA','VVVVxx'
+3578,5864,0,2,8,18,78,578,1578,3578,3578,156,157,'QHAAAA','ORIAAA','AAAAxx'
+8623,5865,1,3,3,3,23,623,623,3623,8623,46,47,'RTAAAA','PRIAAA','HHHHxx'
+6749,5866,1,1,9,9,49,749,749,1749,6749,98,99,'PZAAAA','QRIAAA','OOOOxx'
+6735,5867,1,3,5,15,35,735,735,1735,6735,70,71,'BZAAAA','RRIAAA','VVVVxx'
+5197,5868,1,1,7,17,97,197,1197,197,5197,194,195,'XRAAAA','SRIAAA','AAAAxx'
+2067,5869,1,3,7,7,67,67,67,2067,2067,134,135,'NBAAAA','TRIAAA','HHHHxx'
+5600,5870,0,0,0,0,0,600,1600,600,5600,0,1,'KHAAAA','URIAAA','OOOOxx'
+7741,5871,1,1,1,1,41,741,1741,2741,7741,82,83,'TLAAAA','VRIAAA','VVVVxx'
+9925,5872,1,1,5,5,25,925,1925,4925,9925,50,51,'TRAAAA','WRIAAA','AAAAxx'
+9685,5873,1,1,5,5,85,685,1685,4685,9685,170,171,'NIAAAA','XRIAAA','HHHHxx'
+7622,5874,0,2,2,2,22,622,1622,2622,7622,44,45,'EHAAAA','YRIAAA','OOOOxx'
+6859,5875,1,3,9,19,59,859,859,1859,6859,118,119,'VDAAAA','ZRIAAA','VVVVxx'
+3094,5876,0,2,4,14,94,94,1094,3094,3094,188,189,'APAAAA','ASIAAA','AAAAxx'
+2628,5877,0,0,8,8,28,628,628,2628,2628,56,57,'CXAAAA','BSIAAA','HHHHxx'
+40,5878,0,0,0,0,40,40,40,40,40,80,81,'OBAAAA','CSIAAA','OOOOxx'
+1644,5879,0,0,4,4,44,644,1644,1644,1644,88,89,'GLAAAA','DSIAAA','VVVVxx'
+588,5880,0,0,8,8,88,588,588,588,588,176,177,'QWAAAA','ESIAAA','AAAAxx'
+7522,5881,0,2,2,2,22,522,1522,2522,7522,44,45,'IDAAAA','FSIAAA','HHHHxx'
+162,5882,0,2,2,2,62,162,162,162,162,124,125,'GGAAAA','GSIAAA','OOOOxx'
+3610,5883,0,2,0,10,10,610,1610,3610,3610,20,21,'WIAAAA','HSIAAA','VVVVxx'
+3561,5884,1,1,1,1,61,561,1561,3561,3561,122,123,'ZGAAAA','ISIAAA','AAAAxx'
+8185,5885,1,1,5,5,85,185,185,3185,8185,170,171,'VCAAAA','JSIAAA','HHHHxx'
+7237,5886,1,1,7,17,37,237,1237,2237,7237,74,75,'JSAAAA','KSIAAA','OOOOxx'
+4592,5887,0,0,2,12,92,592,592,4592,4592,184,185,'QUAAAA','LSIAAA','VVVVxx'
+7082,5888,0,2,2,2,82,82,1082,2082,7082,164,165,'KMAAAA','MSIAAA','AAAAxx'
+4719,5889,1,3,9,19,19,719,719,4719,4719,38,39,'NZAAAA','NSIAAA','HHHHxx'
+3879,5890,1,3,9,19,79,879,1879,3879,3879,158,159,'FTAAAA','OSIAAA','OOOOxx'
+1662,5891,0,2,2,2,62,662,1662,1662,1662,124,125,'YLAAAA','PSIAAA','VVVVxx'
+3995,5892,1,3,5,15,95,995,1995,3995,3995,190,191,'RXAAAA','QSIAAA','AAAAxx'
+5828,5893,0,0,8,8,28,828,1828,828,5828,56,57,'EQAAAA','RSIAAA','HHHHxx'
+4197,5894,1,1,7,17,97,197,197,4197,4197,194,195,'LFAAAA','SSIAAA','OOOOxx'
+5146,5895,0,2,6,6,46,146,1146,146,5146,92,93,'YPAAAA','TSIAAA','VVVVxx'
+753,5896,1,1,3,13,53,753,753,753,753,106,107,'ZCAAAA','USIAAA','AAAAxx'
+7064,5897,0,0,4,4,64,64,1064,2064,7064,128,129,'SLAAAA','VSIAAA','HHHHxx'
+1312,5898,0,0,2,12,12,312,1312,1312,1312,24,25,'MYAAAA','WSIAAA','OOOOxx'
+5573,5899,1,1,3,13,73,573,1573,573,5573,146,147,'JGAAAA','XSIAAA','VVVVxx'
+7634,5900,0,2,4,14,34,634,1634,2634,7634,68,69,'QHAAAA','YSIAAA','AAAAxx'
+2459,5901,1,3,9,19,59,459,459,2459,2459,118,119,'PQAAAA','ZSIAAA','HHHHxx'
+8636,5902,0,0,6,16,36,636,636,3636,8636,72,73,'EUAAAA','ATIAAA','OOOOxx'
+5318,5903,0,2,8,18,18,318,1318,318,5318,36,37,'OWAAAA','BTIAAA','VVVVxx'
+1064,5904,0,0,4,4,64,64,1064,1064,1064,128,129,'YOAAAA','CTIAAA','AAAAxx'
+9779,5905,1,3,9,19,79,779,1779,4779,9779,158,159,'DMAAAA','DTIAAA','HHHHxx'
+6512,5906,0,0,2,12,12,512,512,1512,6512,24,25,'MQAAAA','ETIAAA','OOOOxx'
+3572,5907,0,0,2,12,72,572,1572,3572,3572,144,145,'KHAAAA','FTIAAA','VVVVxx'
+816,5908,0,0,6,16,16,816,816,816,816,32,33,'KFAAAA','GTIAAA','AAAAxx'
+3978,5909,0,2,8,18,78,978,1978,3978,3978,156,157,'AXAAAA','HTIAAA','HHHHxx'
+5390,5910,0,2,0,10,90,390,1390,390,5390,180,181,'IZAAAA','ITIAAA','OOOOxx'
+4685,5911,1,1,5,5,85,685,685,4685,4685,170,171,'FYAAAA','JTIAAA','VVVVxx'
+3003,5912,1,3,3,3,3,3,1003,3003,3003,6,7,'NLAAAA','KTIAAA','AAAAxx'
+2638,5913,0,2,8,18,38,638,638,2638,2638,76,77,'MXAAAA','LTIAAA','HHHHxx'
+9716,5914,0,0,6,16,16,716,1716,4716,9716,32,33,'SJAAAA','MTIAAA','OOOOxx'
+9598,5915,0,2,8,18,98,598,1598,4598,9598,196,197,'EFAAAA','NTIAAA','VVVVxx'
+9501,5916,1,1,1,1,1,501,1501,4501,9501,2,3,'LBAAAA','OTIAAA','AAAAxx'
+1704,5917,0,0,4,4,4,704,1704,1704,1704,8,9,'ONAAAA','PTIAAA','HHHHxx'
+8609,5918,1,1,9,9,9,609,609,3609,8609,18,19,'DTAAAA','QTIAAA','OOOOxx'
+5211,5919,1,3,1,11,11,211,1211,211,5211,22,23,'LSAAAA','RTIAAA','VVVVxx'
+3605,5920,1,1,5,5,5,605,1605,3605,3605,10,11,'RIAAAA','STIAAA','AAAAxx'
+8730,5921,0,2,0,10,30,730,730,3730,8730,60,61,'UXAAAA','TTIAAA','HHHHxx'
+4208,5922,0,0,8,8,8,208,208,4208,4208,16,17,'WFAAAA','UTIAAA','OOOOxx'
+7784,5923,0,0,4,4,84,784,1784,2784,7784,168,169,'KNAAAA','VTIAAA','VVVVxx'
+7501,5924,1,1,1,1,1,501,1501,2501,7501,2,3,'NCAAAA','WTIAAA','AAAAxx'
+7862,5925,0,2,2,2,62,862,1862,2862,7862,124,125,'KQAAAA','XTIAAA','HHHHxx'
+8922,5926,0,2,2,2,22,922,922,3922,8922,44,45,'EFAAAA','YTIAAA','OOOOxx'
+3857,5927,1,1,7,17,57,857,1857,3857,3857,114,115,'JSAAAA','ZTIAAA','VVVVxx'
+6393,5928,1,1,3,13,93,393,393,1393,6393,186,187,'XLAAAA','AUIAAA','AAAAxx'
+506,5929,0,2,6,6,6,506,506,506,506,12,13,'MTAAAA','BUIAAA','HHHHxx'
+4232,5930,0,0,2,12,32,232,232,4232,4232,64,65,'UGAAAA','CUIAAA','OOOOxx'
+8991,5931,1,3,1,11,91,991,991,3991,8991,182,183,'VHAAAA','DUIAAA','VVVVxx'
+8578,5932,0,2,8,18,78,578,578,3578,8578,156,157,'YRAAAA','EUIAAA','AAAAxx'
+3235,5933,1,3,5,15,35,235,1235,3235,3235,70,71,'LUAAAA','FUIAAA','HHHHxx'
+963,5934,1,3,3,3,63,963,963,963,963,126,127,'BLAAAA','GUIAAA','OOOOxx'
+113,5935,1,1,3,13,13,113,113,113,113,26,27,'JEAAAA','HUIAAA','VVVVxx'
+8234,5936,0,2,4,14,34,234,234,3234,8234,68,69,'SEAAAA','IUIAAA','AAAAxx'
+2613,5937,1,1,3,13,13,613,613,2613,2613,26,27,'NWAAAA','JUIAAA','HHHHxx'
+5540,5938,0,0,0,0,40,540,1540,540,5540,80,81,'CFAAAA','KUIAAA','OOOOxx'
+9727,5939,1,3,7,7,27,727,1727,4727,9727,54,55,'DKAAAA','LUIAAA','VVVVxx'
+2229,5940,1,1,9,9,29,229,229,2229,2229,58,59,'THAAAA','MUIAAA','AAAAxx'
+6242,5941,0,2,2,2,42,242,242,1242,6242,84,85,'CGAAAA','NUIAAA','HHHHxx'
+2502,5942,0,2,2,2,2,502,502,2502,2502,4,5,'GSAAAA','OUIAAA','OOOOxx'
+6212,5943,0,0,2,12,12,212,212,1212,6212,24,25,'YEAAAA','PUIAAA','VVVVxx'
+3495,5944,1,3,5,15,95,495,1495,3495,3495,190,191,'LEAAAA','QUIAAA','AAAAxx'
+2364,5945,0,0,4,4,64,364,364,2364,2364,128,129,'YMAAAA','RUIAAA','HHHHxx'
+6777,5946,1,1,7,17,77,777,777,1777,6777,154,155,'RAAAAA','SUIAAA','OOOOxx'
+9811,5947,1,3,1,11,11,811,1811,4811,9811,22,23,'JNAAAA','TUIAAA','VVVVxx'
+1450,5948,0,2,0,10,50,450,1450,1450,1450,100,101,'UDAAAA','UUIAAA','AAAAxx'
+5008,5949,0,0,8,8,8,8,1008,8,5008,16,17,'QKAAAA','VUIAAA','HHHHxx'
+1318,5950,0,2,8,18,18,318,1318,1318,1318,36,37,'SYAAAA','WUIAAA','OOOOxx'
+3373,5951,1,1,3,13,73,373,1373,3373,3373,146,147,'TZAAAA','XUIAAA','VVVVxx'
+398,5952,0,2,8,18,98,398,398,398,398,196,197,'IPAAAA','YUIAAA','AAAAxx'
+3804,5953,0,0,4,4,4,804,1804,3804,3804,8,9,'IQAAAA','ZUIAAA','HHHHxx'
+9148,5954,0,0,8,8,48,148,1148,4148,9148,96,97,'WNAAAA','AVIAAA','OOOOxx'
+4382,5955,0,2,2,2,82,382,382,4382,4382,164,165,'OMAAAA','BVIAAA','VVVVxx'
+4026,5956,0,2,6,6,26,26,26,4026,4026,52,53,'WYAAAA','CVIAAA','AAAAxx'
+7804,5957,0,0,4,4,4,804,1804,2804,7804,8,9,'EOAAAA','DVIAAA','HHHHxx'
+6839,5958,1,3,9,19,39,839,839,1839,6839,78,79,'BDAAAA','EVIAAA','OOOOxx'
+3756,5959,0,0,6,16,56,756,1756,3756,3756,112,113,'MOAAAA','FVIAAA','VVVVxx'
+6734,5960,0,2,4,14,34,734,734,1734,6734,68,69,'AZAAAA','GVIAAA','AAAAxx'
+2228,5961,0,0,8,8,28,228,228,2228,2228,56,57,'SHAAAA','HVIAAA','HHHHxx'
+3273,5962,1,1,3,13,73,273,1273,3273,3273,146,147,'XVAAAA','IVIAAA','OOOOxx'
+3708,5963,0,0,8,8,8,708,1708,3708,3708,16,17,'QMAAAA','JVIAAA','VVVVxx'
+4320,5964,0,0,0,0,20,320,320,4320,4320,40,41,'EKAAAA','KVIAAA','AAAAxx'
+74,5965,0,2,4,14,74,74,74,74,74,148,149,'WCAAAA','LVIAAA','HHHHxx'
+2520,5966,0,0,0,0,20,520,520,2520,2520,40,41,'YSAAAA','MVIAAA','OOOOxx'
+9619,5967,1,3,9,19,19,619,1619,4619,9619,38,39,'ZFAAAA','NVIAAA','VVVVxx'
+1801,5968,1,1,1,1,1,801,1801,1801,1801,2,3,'HRAAAA','OVIAAA','AAAAxx'
+6399,5969,1,3,9,19,99,399,399,1399,6399,198,199,'DMAAAA','PVIAAA','HHHHxx'
+8313,5970,1,1,3,13,13,313,313,3313,8313,26,27,'THAAAA','QVIAAA','OOOOxx'
+7003,5971,1,3,3,3,3,3,1003,2003,7003,6,7,'JJAAAA','RVIAAA','VVVVxx'
+329,5972,1,1,9,9,29,329,329,329,329,58,59,'RMAAAA','SVIAAA','AAAAxx'
+9090,5973,0,2,0,10,90,90,1090,4090,9090,180,181,'QLAAAA','TVIAAA','HHHHxx'
+2299,5974,1,3,9,19,99,299,299,2299,2299,198,199,'LKAAAA','UVIAAA','OOOOxx'
+3925,5975,1,1,5,5,25,925,1925,3925,3925,50,51,'ZUAAAA','VVIAAA','VVVVxx'
+8145,5976,1,1,5,5,45,145,145,3145,8145,90,91,'HBAAAA','WVIAAA','AAAAxx'
+8561,5977,1,1,1,1,61,561,561,3561,8561,122,123,'HRAAAA','XVIAAA','HHHHxx'
+2797,5978,1,1,7,17,97,797,797,2797,2797,194,195,'PDAAAA','YVIAAA','OOOOxx'
+1451,5979,1,3,1,11,51,451,1451,1451,1451,102,103,'VDAAAA','ZVIAAA','VVVVxx'
+7977,5980,1,1,7,17,77,977,1977,2977,7977,154,155,'VUAAAA','AWIAAA','AAAAxx'
+112,5981,0,0,2,12,12,112,112,112,112,24,25,'IEAAAA','BWIAAA','HHHHxx'
+5265,5982,1,1,5,5,65,265,1265,265,5265,130,131,'NUAAAA','CWIAAA','OOOOxx'
+3819,5983,1,3,9,19,19,819,1819,3819,3819,38,39,'XQAAAA','DWIAAA','VVVVxx'
+3648,5984,0,0,8,8,48,648,1648,3648,3648,96,97,'IKAAAA','EWIAAA','AAAAxx'
+6306,5985,0,2,6,6,6,306,306,1306,6306,12,13,'OIAAAA','FWIAAA','HHHHxx'
+2385,5986,1,1,5,5,85,385,385,2385,2385,170,171,'TNAAAA','GWIAAA','OOOOxx'
+9084,5987,0,0,4,4,84,84,1084,4084,9084,168,169,'KLAAAA','HWIAAA','VVVVxx'
+4499,5988,1,3,9,19,99,499,499,4499,4499,198,199,'BRAAAA','IWIAAA','AAAAxx'
+1154,5989,0,2,4,14,54,154,1154,1154,1154,108,109,'KSAAAA','JWIAAA','HHHHxx'
+6800,5990,0,0,0,0,0,800,800,1800,6800,0,1,'OBAAAA','KWIAAA','OOOOxx'
+8049,5991,1,1,9,9,49,49,49,3049,8049,98,99,'PXAAAA','LWIAAA','VVVVxx'
+3733,5992,1,1,3,13,33,733,1733,3733,3733,66,67,'PNAAAA','MWIAAA','AAAAxx'
+8496,5993,0,0,6,16,96,496,496,3496,8496,192,193,'UOAAAA','NWIAAA','HHHHxx'
+9952,5994,0,0,2,12,52,952,1952,4952,9952,104,105,'USAAAA','OWIAAA','OOOOxx'
+9792,5995,0,0,2,12,92,792,1792,4792,9792,184,185,'QMAAAA','PWIAAA','VVVVxx'
+5081,5996,1,1,1,1,81,81,1081,81,5081,162,163,'LNAAAA','QWIAAA','AAAAxx'
+7908,5997,0,0,8,8,8,908,1908,2908,7908,16,17,'ESAAAA','RWIAAA','HHHHxx'
+5398,5998,0,2,8,18,98,398,1398,398,5398,196,197,'QZAAAA','SWIAAA','OOOOxx'
+8423,5999,1,3,3,3,23,423,423,3423,8423,46,47,'ZLAAAA','TWIAAA','VVVVxx'
+3362,6000,0,2,2,2,62,362,1362,3362,3362,124,125,'IZAAAA','UWIAAA','AAAAxx'
+7767,6001,1,3,7,7,67,767,1767,2767,7767,134,135,'TMAAAA','VWIAAA','HHHHxx'
+7063,6002,1,3,3,3,63,63,1063,2063,7063,126,127,'RLAAAA','WWIAAA','OOOOxx'
+8350,6003,0,2,0,10,50,350,350,3350,8350,100,101,'EJAAAA','XWIAAA','VVVVxx'
+6779,6004,1,3,9,19,79,779,779,1779,6779,158,159,'TAAAAA','YWIAAA','AAAAxx'
+5742,6005,0,2,2,2,42,742,1742,742,5742,84,85,'WMAAAA','ZWIAAA','HHHHxx'
+9045,6006,1,1,5,5,45,45,1045,4045,9045,90,91,'XJAAAA','AXIAAA','OOOOxx'
+8792,6007,0,0,2,12,92,792,792,3792,8792,184,185,'EAAAAA','BXIAAA','VVVVxx'
+8160,6008,0,0,0,0,60,160,160,3160,8160,120,121,'WBAAAA','CXIAAA','AAAAxx'
+3061,6009,1,1,1,1,61,61,1061,3061,3061,122,123,'TNAAAA','DXIAAA','HHHHxx'
+4721,6010,1,1,1,1,21,721,721,4721,4721,42,43,'PZAAAA','EXIAAA','OOOOxx'
+9817,6011,1,1,7,17,17,817,1817,4817,9817,34,35,'PNAAAA','FXIAAA','VVVVxx'
+9257,6012,1,1,7,17,57,257,1257,4257,9257,114,115,'BSAAAA','GXIAAA','AAAAxx'
+7779,6013,1,3,9,19,79,779,1779,2779,7779,158,159,'FNAAAA','HXIAAA','HHHHxx'
+2663,6014,1,3,3,3,63,663,663,2663,2663,126,127,'LYAAAA','IXIAAA','OOOOxx'
+3885,6015,1,1,5,5,85,885,1885,3885,3885,170,171,'LTAAAA','JXIAAA','VVVVxx'
+9469,6016,1,1,9,9,69,469,1469,4469,9469,138,139,'FAAAAA','KXIAAA','AAAAxx'
+6766,6017,0,2,6,6,66,766,766,1766,6766,132,133,'GAAAAA','LXIAAA','HHHHxx'
+7173,6018,1,1,3,13,73,173,1173,2173,7173,146,147,'XPAAAA','MXIAAA','OOOOxx'
+4709,6019,1,1,9,9,9,709,709,4709,4709,18,19,'DZAAAA','NXIAAA','VVVVxx'
+4210,6020,0,2,0,10,10,210,210,4210,4210,20,21,'YFAAAA','OXIAAA','AAAAxx'
+3715,6021,1,3,5,15,15,715,1715,3715,3715,30,31,'XMAAAA','PXIAAA','HHHHxx'
+5089,6022,1,1,9,9,89,89,1089,89,5089,178,179,'TNAAAA','QXIAAA','OOOOxx'
+1639,6023,1,3,9,19,39,639,1639,1639,1639,78,79,'BLAAAA','RXIAAA','VVVVxx'
+5757,6024,1,1,7,17,57,757,1757,757,5757,114,115,'LNAAAA','SXIAAA','AAAAxx'
+3545,6025,1,1,5,5,45,545,1545,3545,3545,90,91,'JGAAAA','TXIAAA','HHHHxx'
+709,6026,1,1,9,9,9,709,709,709,709,18,19,'HBAAAA','UXIAAA','OOOOxx'
+6519,6027,1,3,9,19,19,519,519,1519,6519,38,39,'TQAAAA','VXIAAA','VVVVxx'
+4341,6028,1,1,1,1,41,341,341,4341,4341,82,83,'ZKAAAA','WXIAAA','AAAAxx'
+2381,6029,1,1,1,1,81,381,381,2381,2381,162,163,'PNAAAA','XXIAAA','HHHHxx'
+7215,6030,1,3,5,15,15,215,1215,2215,7215,30,31,'NRAAAA','YXIAAA','OOOOxx'
+9323,6031,1,3,3,3,23,323,1323,4323,9323,46,47,'PUAAAA','ZXIAAA','VVVVxx'
+3593,6032,1,1,3,13,93,593,1593,3593,3593,186,187,'FIAAAA','AYIAAA','AAAAxx'
+3123,6033,1,3,3,3,23,123,1123,3123,3123,46,47,'DQAAAA','BYIAAA','HHHHxx'
+8673,6034,1,1,3,13,73,673,673,3673,8673,146,147,'PVAAAA','CYIAAA','OOOOxx'
+5094,6035,0,2,4,14,94,94,1094,94,5094,188,189,'YNAAAA','DYIAAA','VVVVxx'
+6477,6036,1,1,7,17,77,477,477,1477,6477,154,155,'DPAAAA','EYIAAA','AAAAxx'
+9734,6037,0,2,4,14,34,734,1734,4734,9734,68,69,'KKAAAA','FYIAAA','HHHHxx'
+2998,6038,0,2,8,18,98,998,998,2998,2998,196,197,'ILAAAA','GYIAAA','OOOOxx'
+7807,6039,1,3,7,7,7,807,1807,2807,7807,14,15,'HOAAAA','HYIAAA','VVVVxx'
+5739,6040,1,3,9,19,39,739,1739,739,5739,78,79,'TMAAAA','IYIAAA','AAAAxx'
+138,6041,0,2,8,18,38,138,138,138,138,76,77,'IFAAAA','JYIAAA','HHHHxx'
+2403,6042,1,3,3,3,3,403,403,2403,2403,6,7,'LOAAAA','KYIAAA','OOOOxx'
+2484,6043,0,0,4,4,84,484,484,2484,2484,168,169,'ORAAAA','LYIAAA','VVVVxx'
+2805,6044,1,1,5,5,5,805,805,2805,2805,10,11,'XDAAAA','MYIAAA','AAAAxx'
+5189,6045,1,1,9,9,89,189,1189,189,5189,178,179,'PRAAAA','NYIAAA','HHHHxx'
+8336,6046,0,0,6,16,36,336,336,3336,8336,72,73,'QIAAAA','OYIAAA','OOOOxx'
+5241,6047,1,1,1,1,41,241,1241,241,5241,82,83,'PTAAAA','PYIAAA','VVVVxx'
+2612,6048,0,0,2,12,12,612,612,2612,2612,24,25,'MWAAAA','QYIAAA','AAAAxx'
+2571,6049,1,3,1,11,71,571,571,2571,2571,142,143,'XUAAAA','RYIAAA','HHHHxx'
+926,6050,0,2,6,6,26,926,926,926,926,52,53,'QJAAAA','SYIAAA','OOOOxx'
+337,6051,1,1,7,17,37,337,337,337,337,74,75,'ZMAAAA','TYIAAA','VVVVxx'
+2821,6052,1,1,1,1,21,821,821,2821,2821,42,43,'NEAAAA','UYIAAA','AAAAxx'
+2658,6053,0,2,8,18,58,658,658,2658,2658,116,117,'GYAAAA','VYIAAA','HHHHxx'
+9054,6054,0,2,4,14,54,54,1054,4054,9054,108,109,'GKAAAA','WYIAAA','OOOOxx'
+5492,6055,0,0,2,12,92,492,1492,492,5492,184,185,'GDAAAA','XYIAAA','VVVVxx'
+7313,6056,1,1,3,13,13,313,1313,2313,7313,26,27,'HVAAAA','YYIAAA','AAAAxx'
+75,6057,1,3,5,15,75,75,75,75,75,150,151,'XCAAAA','ZYIAAA','HHHHxx'
+5489,6058,1,1,9,9,89,489,1489,489,5489,178,179,'DDAAAA','AZIAAA','OOOOxx'
+8413,6059,1,1,3,13,13,413,413,3413,8413,26,27,'PLAAAA','BZIAAA','VVVVxx'
+3693,6060,1,1,3,13,93,693,1693,3693,3693,186,187,'BMAAAA','CZIAAA','AAAAxx'
+9820,6061,0,0,0,0,20,820,1820,4820,9820,40,41,'SNAAAA','DZIAAA','HHHHxx'
+8157,6062,1,1,7,17,57,157,157,3157,8157,114,115,'TBAAAA','EZIAAA','OOOOxx'
+4161,6063,1,1,1,1,61,161,161,4161,4161,122,123,'BEAAAA','FZIAAA','VVVVxx'
+8339,6064,1,3,9,19,39,339,339,3339,8339,78,79,'TIAAAA','GZIAAA','AAAAxx'
+4141,6065,1,1,1,1,41,141,141,4141,4141,82,83,'HDAAAA','HZIAAA','HHHHxx'
+9001,6066,1,1,1,1,1,1,1001,4001,9001,2,3,'FIAAAA','IZIAAA','OOOOxx'
+8247,6067,1,3,7,7,47,247,247,3247,8247,94,95,'FFAAAA','JZIAAA','VVVVxx'
+1182,6068,0,2,2,2,82,182,1182,1182,1182,164,165,'MTAAAA','KZIAAA','AAAAxx'
+9876,6069,0,0,6,16,76,876,1876,4876,9876,152,153,'WPAAAA','LZIAAA','HHHHxx'
+4302,6070,0,2,2,2,2,302,302,4302,4302,4,5,'MJAAAA','MZIAAA','OOOOxx'
+6674,6071,0,2,4,14,74,674,674,1674,6674,148,149,'SWAAAA','NZIAAA','VVVVxx'
+4214,6072,0,2,4,14,14,214,214,4214,4214,28,29,'CGAAAA','OZIAAA','AAAAxx'
+5584,6073,0,0,4,4,84,584,1584,584,5584,168,169,'UGAAAA','PZIAAA','HHHHxx'
+265,6074,1,1,5,5,65,265,265,265,265,130,131,'FKAAAA','QZIAAA','OOOOxx'
+9207,6075,1,3,7,7,7,207,1207,4207,9207,14,15,'DQAAAA','RZIAAA','VVVVxx'
+9434,6076,0,2,4,14,34,434,1434,4434,9434,68,69,'WYAAAA','SZIAAA','AAAAxx'
+2921,6077,1,1,1,1,21,921,921,2921,2921,42,43,'JIAAAA','TZIAAA','HHHHxx'
+9355,6078,1,3,5,15,55,355,1355,4355,9355,110,111,'VVAAAA','UZIAAA','OOOOxx'
+8538,6079,0,2,8,18,38,538,538,3538,8538,76,77,'KQAAAA','VZIAAA','VVVVxx'
+4559,6080,1,3,9,19,59,559,559,4559,4559,118,119,'JTAAAA','WZIAAA','AAAAxx'
+9175,6081,1,3,5,15,75,175,1175,4175,9175,150,151,'XOAAAA','XZIAAA','HHHHxx'
+4489,6082,1,1,9,9,89,489,489,4489,4489,178,179,'RQAAAA','YZIAAA','OOOOxx'
+1485,6083,1,1,5,5,85,485,1485,1485,1485,170,171,'DFAAAA','ZZIAAA','VVVVxx'
+8853,6084,1,1,3,13,53,853,853,3853,8853,106,107,'NCAAAA','AAJAAA','AAAAxx'
+9143,6085,1,3,3,3,43,143,1143,4143,9143,86,87,'RNAAAA','BAJAAA','HHHHxx'
+9551,6086,1,3,1,11,51,551,1551,4551,9551,102,103,'JDAAAA','CAJAAA','OOOOxx'
+49,6087,1,1,9,9,49,49,49,49,49,98,99,'XBAAAA','DAJAAA','VVVVxx'
+8351,6088,1,3,1,11,51,351,351,3351,8351,102,103,'FJAAAA','EAJAAA','AAAAxx'
+9748,6089,0,0,8,8,48,748,1748,4748,9748,96,97,'YKAAAA','FAJAAA','HHHHxx'
+4536,6090,0,0,6,16,36,536,536,4536,4536,72,73,'MSAAAA','GAJAAA','OOOOxx'
+930,6091,0,2,0,10,30,930,930,930,930,60,61,'UJAAAA','HAJAAA','VVVVxx'
+2206,6092,0,2,6,6,6,206,206,2206,2206,12,13,'WGAAAA','IAJAAA','AAAAxx'
+8004,6093,0,0,4,4,4,4,4,3004,8004,8,9,'WVAAAA','JAJAAA','HHHHxx'
+219,6094,1,3,9,19,19,219,219,219,219,38,39,'LIAAAA','KAJAAA','OOOOxx'
+2724,6095,0,0,4,4,24,724,724,2724,2724,48,49,'UAAAAA','LAJAAA','VVVVxx'
+4868,6096,0,0,8,8,68,868,868,4868,4868,136,137,'GFAAAA','MAJAAA','AAAAxx'
+5952,6097,0,0,2,12,52,952,1952,952,5952,104,105,'YUAAAA','NAJAAA','HHHHxx'
+2094,6098,0,2,4,14,94,94,94,2094,2094,188,189,'OCAAAA','OAJAAA','OOOOxx'
+5707,6099,1,3,7,7,7,707,1707,707,5707,14,15,'NLAAAA','PAJAAA','VVVVxx'
+5200,6100,0,0,0,0,0,200,1200,200,5200,0,1,'ASAAAA','QAJAAA','AAAAxx'
+967,6101,1,3,7,7,67,967,967,967,967,134,135,'FLAAAA','RAJAAA','HHHHxx'
+1982,6102,0,2,2,2,82,982,1982,1982,1982,164,165,'GYAAAA','SAJAAA','OOOOxx'
+3410,6103,0,2,0,10,10,410,1410,3410,3410,20,21,'EBAAAA','TAJAAA','VVVVxx'
+174,6104,0,2,4,14,74,174,174,174,174,148,149,'SGAAAA','UAJAAA','AAAAxx'
+9217,6105,1,1,7,17,17,217,1217,4217,9217,34,35,'NQAAAA','VAJAAA','HHHHxx'
+9103,6106,1,3,3,3,3,103,1103,4103,9103,6,7,'DMAAAA','WAJAAA','OOOOxx'
+868,6107,0,0,8,8,68,868,868,868,868,136,137,'KHAAAA','XAJAAA','VVVVxx'
+8261,6108,1,1,1,1,61,261,261,3261,8261,122,123,'TFAAAA','YAJAAA','AAAAxx'
+2720,6109,0,0,0,0,20,720,720,2720,2720,40,41,'QAAAAA','ZAJAAA','HHHHxx'
+2999,6110,1,3,9,19,99,999,999,2999,2999,198,199,'JLAAAA','ABJAAA','OOOOxx'
+769,6111,1,1,9,9,69,769,769,769,769,138,139,'PDAAAA','BBJAAA','VVVVxx'
+4533,6112,1,1,3,13,33,533,533,4533,4533,66,67,'JSAAAA','CBJAAA','AAAAxx'
+2030,6113,0,2,0,10,30,30,30,2030,2030,60,61,'CAAAAA','DBJAAA','HHHHxx'
+5824,6114,0,0,4,4,24,824,1824,824,5824,48,49,'AQAAAA','EBJAAA','OOOOxx'
+2328,6115,0,0,8,8,28,328,328,2328,2328,56,57,'OLAAAA','FBJAAA','VVVVxx'
+9970,6116,0,2,0,10,70,970,1970,4970,9970,140,141,'MTAAAA','GBJAAA','AAAAxx'
+3192,6117,0,0,2,12,92,192,1192,3192,3192,184,185,'USAAAA','HBJAAA','HHHHxx'
+3387,6118,1,3,7,7,87,387,1387,3387,3387,174,175,'HAAAAA','IBJAAA','OOOOxx'
+1936,6119,0,0,6,16,36,936,1936,1936,1936,72,73,'MWAAAA','JBJAAA','VVVVxx'
+6934,6120,0,2,4,14,34,934,934,1934,6934,68,69,'SGAAAA','KBJAAA','AAAAxx'
+5615,6121,1,3,5,15,15,615,1615,615,5615,30,31,'ZHAAAA','LBJAAA','HHHHxx'
+2241,6122,1,1,1,1,41,241,241,2241,2241,82,83,'FIAAAA','MBJAAA','OOOOxx'
+1842,6123,0,2,2,2,42,842,1842,1842,1842,84,85,'WSAAAA','NBJAAA','VVVVxx'
+8044,6124,0,0,4,4,44,44,44,3044,8044,88,89,'KXAAAA','OBJAAA','AAAAxx'
+8902,6125,0,2,2,2,2,902,902,3902,8902,4,5,'KEAAAA','PBJAAA','HHHHxx'
+4519,6126,1,3,9,19,19,519,519,4519,4519,38,39,'VRAAAA','QBJAAA','OOOOxx'
+492,6127,0,0,2,12,92,492,492,492,492,184,185,'YSAAAA','RBJAAA','VVVVxx'
+2694,6128,0,2,4,14,94,694,694,2694,2694,188,189,'QZAAAA','SBJAAA','AAAAxx'
+5861,6129,1,1,1,1,61,861,1861,861,5861,122,123,'LRAAAA','TBJAAA','HHHHxx'
+2104,6130,0,0,4,4,4,104,104,2104,2104,8,9,'YCAAAA','UBJAAA','OOOOxx'
+5376,6131,0,0,6,16,76,376,1376,376,5376,152,153,'UYAAAA','VBJAAA','VVVVxx'
+3147,6132,1,3,7,7,47,147,1147,3147,3147,94,95,'BRAAAA','WBJAAA','AAAAxx'
+9880,6133,0,0,0,0,80,880,1880,4880,9880,160,161,'AQAAAA','XBJAAA','HHHHxx'
+6171,6134,1,3,1,11,71,171,171,1171,6171,142,143,'JDAAAA','YBJAAA','OOOOxx'
+1850,6135,0,2,0,10,50,850,1850,1850,1850,100,101,'ETAAAA','ZBJAAA','VVVVxx'
+1775,6136,1,3,5,15,75,775,1775,1775,1775,150,151,'HQAAAA','ACJAAA','AAAAxx'
+9261,6137,1,1,1,1,61,261,1261,4261,9261,122,123,'FSAAAA','BCJAAA','HHHHxx'
+9648,6138,0,0,8,8,48,648,1648,4648,9648,96,97,'CHAAAA','CCJAAA','OOOOxx'
+7846,6139,0,2,6,6,46,846,1846,2846,7846,92,93,'UPAAAA','DCJAAA','VVVVxx'
+1446,6140,0,2,6,6,46,446,1446,1446,1446,92,93,'QDAAAA','ECJAAA','AAAAxx'
+3139,6141,1,3,9,19,39,139,1139,3139,3139,78,79,'TQAAAA','FCJAAA','HHHHxx'
+6142,6142,0,2,2,2,42,142,142,1142,6142,84,85,'GCAAAA','GCJAAA','OOOOxx'
+5812,6143,0,0,2,12,12,812,1812,812,5812,24,25,'OPAAAA','HCJAAA','VVVVxx'
+6728,6144,0,0,8,8,28,728,728,1728,6728,56,57,'UYAAAA','ICJAAA','AAAAxx'
+4428,6145,0,0,8,8,28,428,428,4428,4428,56,57,'IOAAAA','JCJAAA','HHHHxx'
+502,6146,0,2,2,2,2,502,502,502,502,4,5,'ITAAAA','KCJAAA','OOOOxx'
+2363,6147,1,3,3,3,63,363,363,2363,2363,126,127,'XMAAAA','LCJAAA','VVVVxx'
+3808,6148,0,0,8,8,8,808,1808,3808,3808,16,17,'MQAAAA','MCJAAA','AAAAxx'
+1010,6149,0,2,0,10,10,10,1010,1010,1010,20,21,'WMAAAA','NCJAAA','HHHHxx'
+9565,6150,1,1,5,5,65,565,1565,4565,9565,130,131,'XDAAAA','OCJAAA','OOOOxx'
+1587,6151,1,3,7,7,87,587,1587,1587,1587,174,175,'BJAAAA','PCJAAA','VVVVxx'
+1474,6152,0,2,4,14,74,474,1474,1474,1474,148,149,'SEAAAA','QCJAAA','AAAAxx'
+6215,6153,1,3,5,15,15,215,215,1215,6215,30,31,'BFAAAA','RCJAAA','HHHHxx'
+2395,6154,1,3,5,15,95,395,395,2395,2395,190,191,'DOAAAA','SCJAAA','OOOOxx'
+8753,6155,1,1,3,13,53,753,753,3753,8753,106,107,'RYAAAA','TCJAAA','VVVVxx'
+2446,6156,0,2,6,6,46,446,446,2446,2446,92,93,'CQAAAA','UCJAAA','AAAAxx'
+60,6157,0,0,0,0,60,60,60,60,60,120,121,'ICAAAA','VCJAAA','HHHHxx'
+982,6158,0,2,2,2,82,982,982,982,982,164,165,'ULAAAA','WCJAAA','OOOOxx'
+6489,6159,1,1,9,9,89,489,489,1489,6489,178,179,'PPAAAA','XCJAAA','VVVVxx'
+5334,6160,0,2,4,14,34,334,1334,334,5334,68,69,'EXAAAA','YCJAAA','AAAAxx'
+8540,6161,0,0,0,0,40,540,540,3540,8540,80,81,'MQAAAA','ZCJAAA','HHHHxx'
+490,6162,0,2,0,10,90,490,490,490,490,180,181,'WSAAAA','ADJAAA','OOOOxx'
+6763,6163,1,3,3,3,63,763,763,1763,6763,126,127,'DAAAAA','BDJAAA','VVVVxx'
+8273,6164,1,1,3,13,73,273,273,3273,8273,146,147,'FGAAAA','CDJAAA','AAAAxx'
+8327,6165,1,3,7,7,27,327,327,3327,8327,54,55,'HIAAAA','DDJAAA','HHHHxx'
+8541,6166,1,1,1,1,41,541,541,3541,8541,82,83,'NQAAAA','EDJAAA','OOOOxx'
+3459,6167,1,3,9,19,59,459,1459,3459,3459,118,119,'BDAAAA','FDJAAA','VVVVxx'
+5557,6168,1,1,7,17,57,557,1557,557,5557,114,115,'TFAAAA','GDJAAA','AAAAxx'
+158,6169,0,2,8,18,58,158,158,158,158,116,117,'CGAAAA','HDJAAA','HHHHxx'
+1741,6170,1,1,1,1,41,741,1741,1741,1741,82,83,'ZOAAAA','IDJAAA','OOOOxx'
+8385,6171,1,1,5,5,85,385,385,3385,8385,170,171,'NKAAAA','JDJAAA','VVVVxx'
+617,6172,1,1,7,17,17,617,617,617,617,34,35,'TXAAAA','KDJAAA','AAAAxx'
+3560,6173,0,0,0,0,60,560,1560,3560,3560,120,121,'YGAAAA','LDJAAA','HHHHxx'
+5216,6174,0,0,6,16,16,216,1216,216,5216,32,33,'QSAAAA','MDJAAA','OOOOxx'
+8443,6175,1,3,3,3,43,443,443,3443,8443,86,87,'TMAAAA','NDJAAA','VVVVxx'
+2700,6176,0,0,0,0,0,700,700,2700,2700,0,1,'WZAAAA','ODJAAA','AAAAxx'
+3661,6177,1,1,1,1,61,661,1661,3661,3661,122,123,'VKAAAA','PDJAAA','HHHHxx'
+4875,6178,1,3,5,15,75,875,875,4875,4875,150,151,'NFAAAA','QDJAAA','OOOOxx'
+6721,6179,1,1,1,1,21,721,721,1721,6721,42,43,'NYAAAA','RDJAAA','VVVVxx'
+3659,6180,1,3,9,19,59,659,1659,3659,3659,118,119,'TKAAAA','SDJAAA','AAAAxx'
+8944,6181,0,0,4,4,44,944,944,3944,8944,88,89,'AGAAAA','TDJAAA','HHHHxx'
+9133,6182,1,1,3,13,33,133,1133,4133,9133,66,67,'HNAAAA','UDJAAA','OOOOxx'
+9882,6183,0,2,2,2,82,882,1882,4882,9882,164,165,'CQAAAA','VDJAAA','VVVVxx'
+2102,6184,0,2,2,2,2,102,102,2102,2102,4,5,'WCAAAA','WDJAAA','AAAAxx'
+9445,6185,1,1,5,5,45,445,1445,4445,9445,90,91,'HZAAAA','XDJAAA','HHHHxx'
+5559,6186,1,3,9,19,59,559,1559,559,5559,118,119,'VFAAAA','YDJAAA','OOOOxx'
+6096,6187,0,0,6,16,96,96,96,1096,6096,192,193,'MAAAAA','ZDJAAA','VVVVxx'
+9336,6188,0,0,6,16,36,336,1336,4336,9336,72,73,'CVAAAA','AEJAAA','AAAAxx'
+2162,6189,0,2,2,2,62,162,162,2162,2162,124,125,'EFAAAA','BEJAAA','HHHHxx'
+7459,6190,1,3,9,19,59,459,1459,2459,7459,118,119,'XAAAAA','CEJAAA','OOOOxx'
+3248,6191,0,0,8,8,48,248,1248,3248,3248,96,97,'YUAAAA','DEJAAA','VVVVxx'
+9539,6192,1,3,9,19,39,539,1539,4539,9539,78,79,'XCAAAA','EEJAAA','AAAAxx'
+4449,6193,1,1,9,9,49,449,449,4449,4449,98,99,'DPAAAA','FEJAAA','HHHHxx'
+2809,6194,1,1,9,9,9,809,809,2809,2809,18,19,'BEAAAA','GEJAAA','OOOOxx'
+7058,6195,0,2,8,18,58,58,1058,2058,7058,116,117,'MLAAAA','HEJAAA','VVVVxx'
+3512,6196,0,0,2,12,12,512,1512,3512,3512,24,25,'CFAAAA','IEJAAA','AAAAxx'
+2802,6197,0,2,2,2,2,802,802,2802,2802,4,5,'UDAAAA','JEJAAA','HHHHxx'
+6289,6198,1,1,9,9,89,289,289,1289,6289,178,179,'XHAAAA','KEJAAA','OOOOxx'
+1947,6199,1,3,7,7,47,947,1947,1947,1947,94,95,'XWAAAA','LEJAAA','VVVVxx'
+9572,6200,0,0,2,12,72,572,1572,4572,9572,144,145,'EEAAAA','MEJAAA','AAAAxx'
+2356,6201,0,0,6,16,56,356,356,2356,2356,112,113,'QMAAAA','NEJAAA','HHHHxx'
+3039,6202,1,3,9,19,39,39,1039,3039,3039,78,79,'XMAAAA','OEJAAA','OOOOxx'
+9452,6203,0,0,2,12,52,452,1452,4452,9452,104,105,'OZAAAA','PEJAAA','VVVVxx'
+6328,6204,0,0,8,8,28,328,328,1328,6328,56,57,'KJAAAA','QEJAAA','AAAAxx'
+7661,6205,1,1,1,1,61,661,1661,2661,7661,122,123,'RIAAAA','REJAAA','HHHHxx'
+2566,6206,0,2,6,6,66,566,566,2566,2566,132,133,'SUAAAA','SEJAAA','OOOOxx'
+6095,6207,1,3,5,15,95,95,95,1095,6095,190,191,'LAAAAA','TEJAAA','VVVVxx'
+6367,6208,1,3,7,7,67,367,367,1367,6367,134,135,'XKAAAA','UEJAAA','AAAAxx'
+3368,6209,0,0,8,8,68,368,1368,3368,3368,136,137,'OZAAAA','VEJAAA','HHHHxx'
+5567,6210,1,3,7,7,67,567,1567,567,5567,134,135,'DGAAAA','WEJAAA','OOOOxx'
+9834,6211,0,2,4,14,34,834,1834,4834,9834,68,69,'GOAAAA','XEJAAA','VVVVxx'
+9695,6212,1,3,5,15,95,695,1695,4695,9695,190,191,'XIAAAA','YEJAAA','AAAAxx'
+7291,6213,1,3,1,11,91,291,1291,2291,7291,182,183,'LUAAAA','ZEJAAA','HHHHxx'
+4806,6214,0,2,6,6,6,806,806,4806,4806,12,13,'WCAAAA','AFJAAA','OOOOxx'
+2000,6215,0,0,0,0,0,0,0,2000,2000,0,1,'YYAAAA','BFJAAA','VVVVxx'
+6817,6216,1,1,7,17,17,817,817,1817,6817,34,35,'FCAAAA','CFJAAA','AAAAxx'
+8487,6217,1,3,7,7,87,487,487,3487,8487,174,175,'LOAAAA','DFJAAA','HHHHxx'
+3245,6218,1,1,5,5,45,245,1245,3245,3245,90,91,'VUAAAA','EFJAAA','OOOOxx'
+632,6219,0,0,2,12,32,632,632,632,632,64,65,'IYAAAA','FFJAAA','VVVVxx'
+8067,6220,1,3,7,7,67,67,67,3067,8067,134,135,'HYAAAA','GFJAAA','AAAAxx'
+7140,6221,0,0,0,0,40,140,1140,2140,7140,80,81,'QOAAAA','HFJAAA','HHHHxx'
+6802,6222,0,2,2,2,2,802,802,1802,6802,4,5,'QBAAAA','IFJAAA','OOOOxx'
+3980,6223,0,0,0,0,80,980,1980,3980,3980,160,161,'CXAAAA','JFJAAA','VVVVxx'
+1321,6224,1,1,1,1,21,321,1321,1321,1321,42,43,'VYAAAA','KFJAAA','AAAAxx'
+2273,6225,1,1,3,13,73,273,273,2273,2273,146,147,'LJAAAA','LFJAAA','HHHHxx'
+6787,6226,1,3,7,7,87,787,787,1787,6787,174,175,'BBAAAA','MFJAAA','OOOOxx'
+9480,6227,0,0,0,0,80,480,1480,4480,9480,160,161,'QAAAAA','NFJAAA','VVVVxx'
+9404,6228,0,0,4,4,4,404,1404,4404,9404,8,9,'SXAAAA','OFJAAA','AAAAxx'
+3914,6229,0,2,4,14,14,914,1914,3914,3914,28,29,'OUAAAA','PFJAAA','HHHHxx'
+5507,6230,1,3,7,7,7,507,1507,507,5507,14,15,'VDAAAA','QFJAAA','OOOOxx'
+1813,6231,1,1,3,13,13,813,1813,1813,1813,26,27,'TRAAAA','RFJAAA','VVVVxx'
+1999,6232,1,3,9,19,99,999,1999,1999,1999,198,199,'XYAAAA','SFJAAA','AAAAxx'
+3848,6233,0,0,8,8,48,848,1848,3848,3848,96,97,'ASAAAA','TFJAAA','HHHHxx'
+9693,6234,1,1,3,13,93,693,1693,4693,9693,186,187,'VIAAAA','UFJAAA','OOOOxx'
+1353,6235,1,1,3,13,53,353,1353,1353,1353,106,107,'BAAAAA','VFJAAA','VVVVxx'
+7218,6236,0,2,8,18,18,218,1218,2218,7218,36,37,'QRAAAA','WFJAAA','AAAAxx'
+8223,6237,1,3,3,3,23,223,223,3223,8223,46,47,'HEAAAA','XFJAAA','HHHHxx'
+9982,6238,0,2,2,2,82,982,1982,4982,9982,164,165,'YTAAAA','YFJAAA','OOOOxx'
+8799,6239,1,3,9,19,99,799,799,3799,8799,198,199,'LAAAAA','ZFJAAA','VVVVxx'
+8929,6240,1,1,9,9,29,929,929,3929,8929,58,59,'LFAAAA','AGJAAA','AAAAxx'
+4626,6241,0,2,6,6,26,626,626,4626,4626,52,53,'YVAAAA','BGJAAA','HHHHxx'
+7958,6242,0,2,8,18,58,958,1958,2958,7958,116,117,'CUAAAA','CGJAAA','OOOOxx'
+3743,6243,1,3,3,3,43,743,1743,3743,3743,86,87,'ZNAAAA','DGJAAA','VVVVxx'
+8165,6244,1,1,5,5,65,165,165,3165,8165,130,131,'BCAAAA','EGJAAA','AAAAxx'
+7899,6245,1,3,9,19,99,899,1899,2899,7899,198,199,'VRAAAA','FGJAAA','HHHHxx'
+8698,6246,0,2,8,18,98,698,698,3698,8698,196,197,'OWAAAA','GGJAAA','OOOOxx'
+9270,6247,0,2,0,10,70,270,1270,4270,9270,140,141,'OSAAAA','HGJAAA','VVVVxx'
+6348,6248,0,0,8,8,48,348,348,1348,6348,96,97,'EKAAAA','IGJAAA','AAAAxx'
+6999,6249,1,3,9,19,99,999,999,1999,6999,198,199,'FJAAAA','JGJAAA','HHHHxx'
+8467,6250,1,3,7,7,67,467,467,3467,8467,134,135,'RNAAAA','KGJAAA','OOOOxx'
+3907,6251,1,3,7,7,7,907,1907,3907,3907,14,15,'HUAAAA','LGJAAA','VVVVxx'
+4738,6252,0,2,8,18,38,738,738,4738,4738,76,77,'GAAAAA','MGJAAA','AAAAxx'
+248,6253,0,0,8,8,48,248,248,248,248,96,97,'OJAAAA','NGJAAA','HHHHxx'
+8769,6254,1,1,9,9,69,769,769,3769,8769,138,139,'HZAAAA','OGJAAA','OOOOxx'
+9922,6255,0,2,2,2,22,922,1922,4922,9922,44,45,'QRAAAA','PGJAAA','VVVVxx'
+778,6256,0,2,8,18,78,778,778,778,778,156,157,'YDAAAA','QGJAAA','AAAAxx'
+1233,6257,1,1,3,13,33,233,1233,1233,1233,66,67,'LVAAAA','RGJAAA','HHHHxx'
+1183,6258,1,3,3,3,83,183,1183,1183,1183,166,167,'NTAAAA','SGJAAA','OOOOxx'
+2838,6259,0,2,8,18,38,838,838,2838,2838,76,77,'EFAAAA','TGJAAA','VVVVxx'
+3096,6260,0,0,6,16,96,96,1096,3096,3096,192,193,'CPAAAA','UGJAAA','AAAAxx'
+8566,6261,0,2,6,6,66,566,566,3566,8566,132,133,'MRAAAA','VGJAAA','HHHHxx'
+7635,6262,1,3,5,15,35,635,1635,2635,7635,70,71,'RHAAAA','WGJAAA','OOOOxx'
+5428,6263,0,0,8,8,28,428,1428,428,5428,56,57,'UAAAAA','XGJAAA','VVVVxx'
+7430,6264,0,2,0,10,30,430,1430,2430,7430,60,61,'UZAAAA','YGJAAA','AAAAxx'
+7210,6265,0,2,0,10,10,210,1210,2210,7210,20,21,'IRAAAA','ZGJAAA','HHHHxx'
+4485,6266,1,1,5,5,85,485,485,4485,4485,170,171,'NQAAAA','AHJAAA','OOOOxx'
+9623,6267,1,3,3,3,23,623,1623,4623,9623,46,47,'DGAAAA','BHJAAA','VVVVxx'
+3670,6268,0,2,0,10,70,670,1670,3670,3670,140,141,'ELAAAA','CHJAAA','AAAAxx'
+1575,6269,1,3,5,15,75,575,1575,1575,1575,150,151,'PIAAAA','DHJAAA','HHHHxx'
+5874,6270,0,2,4,14,74,874,1874,874,5874,148,149,'YRAAAA','EHJAAA','OOOOxx'
+673,6271,1,1,3,13,73,673,673,673,673,146,147,'XZAAAA','FHJAAA','VVVVxx'
+9712,6272,0,0,2,12,12,712,1712,4712,9712,24,25,'OJAAAA','GHJAAA','AAAAxx'
+7729,6273,1,1,9,9,29,729,1729,2729,7729,58,59,'HLAAAA','HHJAAA','HHHHxx'
+4318,6274,0,2,8,18,18,318,318,4318,4318,36,37,'CKAAAA','IHJAAA','OOOOxx'
+4143,6275,1,3,3,3,43,143,143,4143,4143,86,87,'JDAAAA','JHJAAA','VVVVxx'
+4932,6276,0,0,2,12,32,932,932,4932,4932,64,65,'SHAAAA','KHJAAA','AAAAxx'
+5835,6277,1,3,5,15,35,835,1835,835,5835,70,71,'LQAAAA','LHJAAA','HHHHxx'
+4966,6278,0,2,6,6,66,966,966,4966,4966,132,133,'AJAAAA','MHJAAA','OOOOxx'
+6711,6279,1,3,1,11,11,711,711,1711,6711,22,23,'DYAAAA','NHJAAA','VVVVxx'
+3990,6280,0,2,0,10,90,990,1990,3990,3990,180,181,'MXAAAA','OHJAAA','AAAAxx'
+990,6281,0,2,0,10,90,990,990,990,990,180,181,'CMAAAA','PHJAAA','HHHHxx'
+220,6282,0,0,0,0,20,220,220,220,220,40,41,'MIAAAA','QHJAAA','OOOOxx'
+5693,6283,1,1,3,13,93,693,1693,693,5693,186,187,'ZKAAAA','RHJAAA','VVVVxx'
+3662,6284,0,2,2,2,62,662,1662,3662,3662,124,125,'WKAAAA','SHJAAA','AAAAxx'
+7844,6285,0,0,4,4,44,844,1844,2844,7844,88,89,'SPAAAA','THJAAA','HHHHxx'
+5515,6286,1,3,5,15,15,515,1515,515,5515,30,31,'DEAAAA','UHJAAA','OOOOxx'
+5551,6287,1,3,1,11,51,551,1551,551,5551,102,103,'NFAAAA','VHJAAA','VVVVxx'
+2358,6288,0,2,8,18,58,358,358,2358,2358,116,117,'SMAAAA','WHJAAA','AAAAxx'
+8977,6289,1,1,7,17,77,977,977,3977,8977,154,155,'HHAAAA','XHJAAA','HHHHxx'
+7040,6290,0,0,0,0,40,40,1040,2040,7040,80,81,'UKAAAA','YHJAAA','OOOOxx'
+105,6291,1,1,5,5,5,105,105,105,105,10,11,'BEAAAA','ZHJAAA','VVVVxx'
+4496,6292,0,0,6,16,96,496,496,4496,4496,192,193,'YQAAAA','AIJAAA','AAAAxx'
+2254,6293,0,2,4,14,54,254,254,2254,2254,108,109,'SIAAAA','BIJAAA','HHHHxx'
+411,6294,1,3,1,11,11,411,411,411,411,22,23,'VPAAAA','CIJAAA','OOOOxx'
+2373,6295,1,1,3,13,73,373,373,2373,2373,146,147,'HNAAAA','DIJAAA','VVVVxx'
+3477,6296,1,1,7,17,77,477,1477,3477,3477,154,155,'TDAAAA','EIJAAA','AAAAxx'
+8964,6297,0,0,4,4,64,964,964,3964,8964,128,129,'UGAAAA','FIJAAA','HHHHxx'
+8471,6298,1,3,1,11,71,471,471,3471,8471,142,143,'VNAAAA','GIJAAA','OOOOxx'
+5776,6299,0,0,6,16,76,776,1776,776,5776,152,153,'EOAAAA','HIJAAA','VVVVxx'
+9921,6300,1,1,1,1,21,921,1921,4921,9921,42,43,'PRAAAA','IIJAAA','AAAAxx'
+7816,6301,0,0,6,16,16,816,1816,2816,7816,32,33,'QOAAAA','JIJAAA','HHHHxx'
+2439,6302,1,3,9,19,39,439,439,2439,2439,78,79,'VPAAAA','KIJAAA','OOOOxx'
+9298,6303,0,2,8,18,98,298,1298,4298,9298,196,197,'QTAAAA','LIJAAA','VVVVxx'
+9424,6304,0,0,4,4,24,424,1424,4424,9424,48,49,'MYAAAA','MIJAAA','AAAAxx'
+3252,6305,0,0,2,12,52,252,1252,3252,3252,104,105,'CVAAAA','NIJAAA','HHHHxx'
+1401,6306,1,1,1,1,1,401,1401,1401,1401,2,3,'XBAAAA','OIJAAA','OOOOxx'
+9632,6307,0,0,2,12,32,632,1632,4632,9632,64,65,'MGAAAA','PIJAAA','VVVVxx'
+370,6308,0,2,0,10,70,370,370,370,370,140,141,'GOAAAA','QIJAAA','AAAAxx'
+728,6309,0,0,8,8,28,728,728,728,728,56,57,'ACAAAA','RIJAAA','HHHHxx'
+2888,6310,0,0,8,8,88,888,888,2888,2888,176,177,'CHAAAA','SIJAAA','OOOOxx'
+1441,6311,1,1,1,1,41,441,1441,1441,1441,82,83,'LDAAAA','TIJAAA','VVVVxx'
+8308,6312,0,0,8,8,8,308,308,3308,8308,16,17,'OHAAAA','UIJAAA','AAAAxx'
+2165,6313,1,1,5,5,65,165,165,2165,2165,130,131,'HFAAAA','VIJAAA','HHHHxx'
+6359,6314,1,3,9,19,59,359,359,1359,6359,118,119,'PKAAAA','WIJAAA','OOOOxx'
+9637,6315,1,1,7,17,37,637,1637,4637,9637,74,75,'RGAAAA','XIJAAA','VVVVxx'
+5208,6316,0,0,8,8,8,208,1208,208,5208,16,17,'ISAAAA','YIJAAA','AAAAxx'
+4705,6317,1,1,5,5,5,705,705,4705,4705,10,11,'ZYAAAA','ZIJAAA','HHHHxx'
+2341,6318,1,1,1,1,41,341,341,2341,2341,82,83,'BMAAAA','AJJAAA','OOOOxx'
+8539,6319,1,3,9,19,39,539,539,3539,8539,78,79,'LQAAAA','BJJAAA','VVVVxx'
+7528,6320,0,0,8,8,28,528,1528,2528,7528,56,57,'ODAAAA','CJJAAA','AAAAxx'
+7969,6321,1,1,9,9,69,969,1969,2969,7969,138,139,'NUAAAA','DJJAAA','HHHHxx'
+6381,6322,1,1,1,1,81,381,381,1381,6381,162,163,'LLAAAA','EJJAAA','OOOOxx'
+4906,6323,0,2,6,6,6,906,906,4906,4906,12,13,'SGAAAA','FJJAAA','VVVVxx'
+8697,6324,1,1,7,17,97,697,697,3697,8697,194,195,'NWAAAA','GJJAAA','AAAAxx'
+6301,6325,1,1,1,1,1,301,301,1301,6301,2,3,'JIAAAA','HJJAAA','HHHHxx'
+7554,6326,0,2,4,14,54,554,1554,2554,7554,108,109,'OEAAAA','IJJAAA','OOOOxx'
+5107,6327,1,3,7,7,7,107,1107,107,5107,14,15,'LOAAAA','JJJAAA','VVVVxx'
+5046,6328,0,2,6,6,46,46,1046,46,5046,92,93,'CMAAAA','KJJAAA','AAAAxx'
+4063,6329,1,3,3,3,63,63,63,4063,4063,126,127,'HAAAAA','LJJAAA','HHHHxx'
+7580,6330,0,0,0,0,80,580,1580,2580,7580,160,161,'OFAAAA','MJJAAA','OOOOxx'
+2245,6331,1,1,5,5,45,245,245,2245,2245,90,91,'JIAAAA','NJJAAA','VVVVxx'
+3711,6332,1,3,1,11,11,711,1711,3711,3711,22,23,'TMAAAA','OJJAAA','AAAAxx'
+3220,6333,0,0,0,0,20,220,1220,3220,3220,40,41,'WTAAAA','PJJAAA','HHHHxx'
+6463,6334,1,3,3,3,63,463,463,1463,6463,126,127,'POAAAA','QJJAAA','OOOOxx'
+8196,6335,0,0,6,16,96,196,196,3196,8196,192,193,'GDAAAA','RJJAAA','VVVVxx'
+9875,6336,1,3,5,15,75,875,1875,4875,9875,150,151,'VPAAAA','SJJAAA','AAAAxx'
+1333,6337,1,1,3,13,33,333,1333,1333,1333,66,67,'HZAAAA','TJJAAA','HHHHxx'
+7880,6338,0,0,0,0,80,880,1880,2880,7880,160,161,'CRAAAA','UJJAAA','OOOOxx'
+2322,6339,0,2,2,2,22,322,322,2322,2322,44,45,'ILAAAA','VJJAAA','VVVVxx'
+2163,6340,1,3,3,3,63,163,163,2163,2163,126,127,'FFAAAA','WJJAAA','AAAAxx'
+421,6341,1,1,1,1,21,421,421,421,421,42,43,'FQAAAA','XJJAAA','HHHHxx'
+2042,6342,0,2,2,2,42,42,42,2042,2042,84,85,'OAAAAA','YJJAAA','OOOOxx'
+1424,6343,0,0,4,4,24,424,1424,1424,1424,48,49,'UCAAAA','ZJJAAA','VVVVxx'
+7870,6344,0,2,0,10,70,870,1870,2870,7870,140,141,'SQAAAA','AKJAAA','AAAAxx'
+2653,6345,1,1,3,13,53,653,653,2653,2653,106,107,'BYAAAA','BKJAAA','HHHHxx'
+4216,6346,0,0,6,16,16,216,216,4216,4216,32,33,'EGAAAA','CKJAAA','OOOOxx'
+1515,6347,1,3,5,15,15,515,1515,1515,1515,30,31,'HGAAAA','DKJAAA','VVVVxx'
+7860,6348,0,0,0,0,60,860,1860,2860,7860,120,121,'IQAAAA','EKJAAA','AAAAxx'
+2984,6349,0,0,4,4,84,984,984,2984,2984,168,169,'UKAAAA','FKJAAA','HHHHxx'
+6269,6350,1,1,9,9,69,269,269,1269,6269,138,139,'DHAAAA','GKJAAA','OOOOxx'
+2609,6351,1,1,9,9,9,609,609,2609,2609,18,19,'JWAAAA','HKJAAA','VVVVxx'
+3671,6352,1,3,1,11,71,671,1671,3671,3671,142,143,'FLAAAA','IKJAAA','AAAAxx'
+4544,6353,0,0,4,4,44,544,544,4544,4544,88,89,'USAAAA','JKJAAA','HHHHxx'
+4668,6354,0,0,8,8,68,668,668,4668,4668,136,137,'OXAAAA','KKJAAA','OOOOxx'
+2565,6355,1,1,5,5,65,565,565,2565,2565,130,131,'RUAAAA','LKJAAA','VVVVxx'
+3126,6356,0,2,6,6,26,126,1126,3126,3126,52,53,'GQAAAA','MKJAAA','AAAAxx'
+7573,6357,1,1,3,13,73,573,1573,2573,7573,146,147,'HFAAAA','NKJAAA','HHHHxx'
+1476,6358,0,0,6,16,76,476,1476,1476,1476,152,153,'UEAAAA','OKJAAA','OOOOxx'
+2146,6359,0,2,6,6,46,146,146,2146,2146,92,93,'OEAAAA','PKJAAA','VVVVxx'
+9990,6360,0,2,0,10,90,990,1990,4990,9990,180,181,'GUAAAA','QKJAAA','AAAAxx'
+2530,6361,0,2,0,10,30,530,530,2530,2530,60,61,'ITAAAA','RKJAAA','HHHHxx'
+9288,6362,0,0,8,8,88,288,1288,4288,9288,176,177,'GTAAAA','SKJAAA','OOOOxx'
+9755,6363,1,3,5,15,55,755,1755,4755,9755,110,111,'FLAAAA','TKJAAA','VVVVxx'
+5305,6364,1,1,5,5,5,305,1305,305,5305,10,11,'BWAAAA','UKJAAA','AAAAxx'
+2495,6365,1,3,5,15,95,495,495,2495,2495,190,191,'ZRAAAA','VKJAAA','HHHHxx'
+5443,6366,1,3,3,3,43,443,1443,443,5443,86,87,'JBAAAA','WKJAAA','OOOOxx'
+1930,6367,0,2,0,10,30,930,1930,1930,1930,60,61,'GWAAAA','XKJAAA','VVVVxx'
+9134,6368,0,2,4,14,34,134,1134,4134,9134,68,69,'INAAAA','YKJAAA','AAAAxx'
+2844,6369,0,0,4,4,44,844,844,2844,2844,88,89,'KFAAAA','ZKJAAA','HHHHxx'
+896,6370,0,0,6,16,96,896,896,896,896,192,193,'MIAAAA','ALJAAA','OOOOxx'
+1330,6371,0,2,0,10,30,330,1330,1330,1330,60,61,'EZAAAA','BLJAAA','VVVVxx'
+8980,6372,0,0,0,0,80,980,980,3980,8980,160,161,'KHAAAA','CLJAAA','AAAAxx'
+5940,6373,0,0,0,0,40,940,1940,940,5940,80,81,'MUAAAA','DLJAAA','HHHHxx'
+6494,6374,0,2,4,14,94,494,494,1494,6494,188,189,'UPAAAA','ELJAAA','OOOOxx'
+165,6375,1,1,5,5,65,165,165,165,165,130,131,'JGAAAA','FLJAAA','VVVVxx'
+2510,6376,0,2,0,10,10,510,510,2510,2510,20,21,'OSAAAA','GLJAAA','AAAAxx'
+9950,6377,0,2,0,10,50,950,1950,4950,9950,100,101,'SSAAAA','HLJAAA','HHHHxx'
+3854,6378,0,2,4,14,54,854,1854,3854,3854,108,109,'GSAAAA','ILJAAA','OOOOxx'
+7493,6379,1,1,3,13,93,493,1493,2493,7493,186,187,'FCAAAA','JLJAAA','VVVVxx'
+4124,6380,0,0,4,4,24,124,124,4124,4124,48,49,'QCAAAA','KLJAAA','AAAAxx'
+8563,6381,1,3,3,3,63,563,563,3563,8563,126,127,'JRAAAA','LLJAAA','HHHHxx'
+8735,6382,1,3,5,15,35,735,735,3735,8735,70,71,'ZXAAAA','MLJAAA','OOOOxx'
+9046,6383,0,2,6,6,46,46,1046,4046,9046,92,93,'YJAAAA','NLJAAA','VVVVxx'
+1754,6384,0,2,4,14,54,754,1754,1754,1754,108,109,'MPAAAA','OLJAAA','AAAAxx'
+6954,6385,0,2,4,14,54,954,954,1954,6954,108,109,'MHAAAA','PLJAAA','HHHHxx'
+4953,6386,1,1,3,13,53,953,953,4953,4953,106,107,'NIAAAA','QLJAAA','OOOOxx'
+8142,6387,0,2,2,2,42,142,142,3142,8142,84,85,'EBAAAA','RLJAAA','VVVVxx'
+9661,6388,1,1,1,1,61,661,1661,4661,9661,122,123,'PHAAAA','SLJAAA','AAAAxx'
+6415,6389,1,3,5,15,15,415,415,1415,6415,30,31,'TMAAAA','TLJAAA','HHHHxx'
+5782,6390,0,2,2,2,82,782,1782,782,5782,164,165,'KOAAAA','ULJAAA','OOOOxx'
+7721,6391,1,1,1,1,21,721,1721,2721,7721,42,43,'ZKAAAA','VLJAAA','VVVVxx'
+580,6392,0,0,0,0,80,580,580,580,580,160,161,'IWAAAA','WLJAAA','AAAAxx'
+3784,6393,0,0,4,4,84,784,1784,3784,3784,168,169,'OPAAAA','XLJAAA','HHHHxx'
+9810,6394,0,2,0,10,10,810,1810,4810,9810,20,21,'INAAAA','YLJAAA','OOOOxx'
+8488,6395,0,0,8,8,88,488,488,3488,8488,176,177,'MOAAAA','ZLJAAA','VVVVxx'
+6214,6396,0,2,4,14,14,214,214,1214,6214,28,29,'AFAAAA','AMJAAA','AAAAxx'
+9433,6397,1,1,3,13,33,433,1433,4433,9433,66,67,'VYAAAA','BMJAAA','HHHHxx'
+9959,6398,1,3,9,19,59,959,1959,4959,9959,118,119,'BTAAAA','CMJAAA','OOOOxx'
+554,6399,0,2,4,14,54,554,554,554,554,108,109,'IVAAAA','DMJAAA','VVVVxx'
+6646,6400,0,2,6,6,46,646,646,1646,6646,92,93,'QVAAAA','EMJAAA','AAAAxx'
+1138,6401,0,2,8,18,38,138,1138,1138,1138,76,77,'URAAAA','FMJAAA','HHHHxx'
+9331,6402,1,3,1,11,31,331,1331,4331,9331,62,63,'XUAAAA','GMJAAA','OOOOxx'
+7331,6403,1,3,1,11,31,331,1331,2331,7331,62,63,'ZVAAAA','HMJAAA','VVVVxx'
+3482,6404,0,2,2,2,82,482,1482,3482,3482,164,165,'YDAAAA','IMJAAA','AAAAxx'
+3795,6405,1,3,5,15,95,795,1795,3795,3795,190,191,'ZPAAAA','JMJAAA','HHHHxx'
+2441,6406,1,1,1,1,41,441,441,2441,2441,82,83,'XPAAAA','KMJAAA','OOOOxx'
+5229,6407,1,1,9,9,29,229,1229,229,5229,58,59,'DTAAAA','LMJAAA','VVVVxx'
+7012,6408,0,0,2,12,12,12,1012,2012,7012,24,25,'SJAAAA','MMJAAA','AAAAxx'
+7036,6409,0,0,6,16,36,36,1036,2036,7036,72,73,'QKAAAA','NMJAAA','HHHHxx'
+8243,6410,1,3,3,3,43,243,243,3243,8243,86,87,'BFAAAA','OMJAAA','OOOOxx'
+9320,6411,0,0,0,0,20,320,1320,4320,9320,40,41,'MUAAAA','PMJAAA','VVVVxx'
+4693,6412,1,1,3,13,93,693,693,4693,4693,186,187,'NYAAAA','QMJAAA','AAAAxx'
+6741,6413,1,1,1,1,41,741,741,1741,6741,82,83,'HZAAAA','RMJAAA','HHHHxx'
+2997,6414,1,1,7,17,97,997,997,2997,2997,194,195,'HLAAAA','SMJAAA','OOOOxx'
+4838,6415,0,2,8,18,38,838,838,4838,4838,76,77,'CEAAAA','TMJAAA','VVVVxx'
+6945,6416,1,1,5,5,45,945,945,1945,6945,90,91,'DHAAAA','UMJAAA','AAAAxx'
+8253,6417,1,1,3,13,53,253,253,3253,8253,106,107,'LFAAAA','VMJAAA','HHHHxx'
+8989,6418,1,1,9,9,89,989,989,3989,8989,178,179,'THAAAA','WMJAAA','OOOOxx'
+2640,6419,0,0,0,0,40,640,640,2640,2640,80,81,'OXAAAA','XMJAAA','VVVVxx'
+5647,6420,1,3,7,7,47,647,1647,647,5647,94,95,'FJAAAA','YMJAAA','AAAAxx'
+7186,6421,0,2,6,6,86,186,1186,2186,7186,172,173,'KQAAAA','ZMJAAA','HHHHxx'
+3278,6422,0,2,8,18,78,278,1278,3278,3278,156,157,'CWAAAA','ANJAAA','OOOOxx'
+8546,6423,0,2,6,6,46,546,546,3546,8546,92,93,'SQAAAA','BNJAAA','VVVVxx'
+8297,6424,1,1,7,17,97,297,297,3297,8297,194,195,'DHAAAA','CNJAAA','AAAAxx'
+9534,6425,0,2,4,14,34,534,1534,4534,9534,68,69,'SCAAAA','DNJAAA','HHHHxx'
+9618,6426,0,2,8,18,18,618,1618,4618,9618,36,37,'YFAAAA','ENJAAA','OOOOxx'
+8839,6427,1,3,9,19,39,839,839,3839,8839,78,79,'ZBAAAA','FNJAAA','VVVVxx'
+7605,6428,1,1,5,5,5,605,1605,2605,7605,10,11,'NGAAAA','GNJAAA','AAAAxx'
+6421,6429,1,1,1,1,21,421,421,1421,6421,42,43,'ZMAAAA','HNJAAA','HHHHxx'
+3582,6430,0,2,2,2,82,582,1582,3582,3582,164,165,'UHAAAA','INJAAA','OOOOxx'
+485,6431,1,1,5,5,85,485,485,485,485,170,171,'RSAAAA','JNJAAA','VVVVxx'
+1925,6432,1,1,5,5,25,925,1925,1925,1925,50,51,'BWAAAA','KNJAAA','AAAAxx'
+4296,6433,0,0,6,16,96,296,296,4296,4296,192,193,'GJAAAA','LNJAAA','HHHHxx'
+8874,6434,0,2,4,14,74,874,874,3874,8874,148,149,'IDAAAA','MNJAAA','OOOOxx'
+1443,6435,1,3,3,3,43,443,1443,1443,1443,86,87,'NDAAAA','NNJAAA','VVVVxx'
+4239,6436,1,3,9,19,39,239,239,4239,4239,78,79,'BHAAAA','ONJAAA','AAAAxx'
+9760,6437,0,0,0,0,60,760,1760,4760,9760,120,121,'KLAAAA','PNJAAA','HHHHxx'
+136,6438,0,0,6,16,36,136,136,136,136,72,73,'GFAAAA','QNJAAA','OOOOxx'
+6472,6439,0,0,2,12,72,472,472,1472,6472,144,145,'YOAAAA','RNJAAA','VVVVxx'
+4896,6440,0,0,6,16,96,896,896,4896,4896,192,193,'IGAAAA','SNJAAA','AAAAxx'
+9028,6441,0,0,8,8,28,28,1028,4028,9028,56,57,'GJAAAA','TNJAAA','HHHHxx'
+8354,6442,0,2,4,14,54,354,354,3354,8354,108,109,'IJAAAA','UNJAAA','OOOOxx'
+8648,6443,0,0,8,8,48,648,648,3648,8648,96,97,'QUAAAA','VNJAAA','VVVVxx'
+918,6444,0,2,8,18,18,918,918,918,918,36,37,'IJAAAA','WNJAAA','AAAAxx'
+6606,6445,0,2,6,6,6,606,606,1606,6606,12,13,'CUAAAA','XNJAAA','HHHHxx'
+2462,6446,0,2,2,2,62,462,462,2462,2462,124,125,'SQAAAA','YNJAAA','OOOOxx'
+7536,6447,0,0,6,16,36,536,1536,2536,7536,72,73,'WDAAAA','ZNJAAA','VVVVxx'
+1700,6448,0,0,0,0,0,700,1700,1700,1700,0,1,'KNAAAA','AOJAAA','AAAAxx'
+6740,6449,0,0,0,0,40,740,740,1740,6740,80,81,'GZAAAA','BOJAAA','HHHHxx'
+28,6450,0,0,8,8,28,28,28,28,28,56,57,'CBAAAA','COJAAA','OOOOxx'
+6044,6451,0,0,4,4,44,44,44,1044,6044,88,89,'MYAAAA','DOJAAA','VVVVxx'
+5053,6452,1,1,3,13,53,53,1053,53,5053,106,107,'JMAAAA','EOJAAA','AAAAxx'
+4832,6453,0,0,2,12,32,832,832,4832,4832,64,65,'WDAAAA','FOJAAA','HHHHxx'
+9145,6454,1,1,5,5,45,145,1145,4145,9145,90,91,'TNAAAA','GOJAAA','OOOOxx'
+5482,6455,0,2,2,2,82,482,1482,482,5482,164,165,'WCAAAA','HOJAAA','VVVVxx'
+7644,6456,0,0,4,4,44,644,1644,2644,7644,88,89,'AIAAAA','IOJAAA','AAAAxx'
+2128,6457,0,0,8,8,28,128,128,2128,2128,56,57,'WDAAAA','JOJAAA','HHHHxx'
+6583,6458,1,3,3,3,83,583,583,1583,6583,166,167,'FTAAAA','KOJAAA','OOOOxx'
+4224,6459,0,0,4,4,24,224,224,4224,4224,48,49,'MGAAAA','LOJAAA','VVVVxx'
+5253,6460,1,1,3,13,53,253,1253,253,5253,106,107,'BUAAAA','MOJAAA','AAAAxx'
+8219,6461,1,3,9,19,19,219,219,3219,8219,38,39,'DEAAAA','NOJAAA','HHHHxx'
+8113,6462,1,1,3,13,13,113,113,3113,8113,26,27,'BAAAAA','OOJAAA','OOOOxx'
+3616,6463,0,0,6,16,16,616,1616,3616,3616,32,33,'CJAAAA','POJAAA','VVVVxx'
+1361,6464,1,1,1,1,61,361,1361,1361,1361,122,123,'JAAAAA','QOJAAA','AAAAxx'
+949,6465,1,1,9,9,49,949,949,949,949,98,99,'NKAAAA','ROJAAA','HHHHxx'
+8582,6466,0,2,2,2,82,582,582,3582,8582,164,165,'CSAAAA','SOJAAA','OOOOxx'
+5104,6467,0,0,4,4,4,104,1104,104,5104,8,9,'IOAAAA','TOJAAA','VVVVxx'
+6146,6468,0,2,6,6,46,146,146,1146,6146,92,93,'KCAAAA','UOJAAA','AAAAxx'
+7681,6469,1,1,1,1,81,681,1681,2681,7681,162,163,'LJAAAA','VOJAAA','HHHHxx'
+1904,6470,0,0,4,4,4,904,1904,1904,1904,8,9,'GVAAAA','WOJAAA','OOOOxx'
+1989,6471,1,1,9,9,89,989,1989,1989,1989,178,179,'NYAAAA','XOJAAA','VVVVxx'
+4179,6472,1,3,9,19,79,179,179,4179,4179,158,159,'TEAAAA','YOJAAA','AAAAxx'
+1739,6473,1,3,9,19,39,739,1739,1739,1739,78,79,'XOAAAA','ZOJAAA','HHHHxx'
+2447,6474,1,3,7,7,47,447,447,2447,2447,94,95,'DQAAAA','APJAAA','OOOOxx'
+3029,6475,1,1,9,9,29,29,1029,3029,3029,58,59,'NMAAAA','BPJAAA','VVVVxx'
+9783,6476,1,3,3,3,83,783,1783,4783,9783,166,167,'HMAAAA','CPJAAA','AAAAxx'
+8381,6477,1,1,1,1,81,381,381,3381,8381,162,163,'JKAAAA','DPJAAA','HHHHxx'
+8755,6478,1,3,5,15,55,755,755,3755,8755,110,111,'TYAAAA','EPJAAA','OOOOxx'
+8384,6479,0,0,4,4,84,384,384,3384,8384,168,169,'MKAAAA','FPJAAA','VVVVxx'
+7655,6480,1,3,5,15,55,655,1655,2655,7655,110,111,'LIAAAA','GPJAAA','AAAAxx'
+4766,6481,0,2,6,6,66,766,766,4766,4766,132,133,'IBAAAA','HPJAAA','HHHHxx'
+3324,6482,0,0,4,4,24,324,1324,3324,3324,48,49,'WXAAAA','IPJAAA','OOOOxx'
+5022,6483,0,2,2,2,22,22,1022,22,5022,44,45,'ELAAAA','JPJAAA','VVVVxx'
+2856,6484,0,0,6,16,56,856,856,2856,2856,112,113,'WFAAAA','KPJAAA','AAAAxx'
+6503,6485,1,3,3,3,3,503,503,1503,6503,6,7,'DQAAAA','LPJAAA','HHHHxx'
+6872,6486,0,0,2,12,72,872,872,1872,6872,144,145,'IEAAAA','MPJAAA','OOOOxx'
+1663,6487,1,3,3,3,63,663,1663,1663,1663,126,127,'ZLAAAA','NPJAAA','VVVVxx'
+6964,6488,0,0,4,4,64,964,964,1964,6964,128,129,'WHAAAA','OPJAAA','AAAAxx'
+4622,6489,0,2,2,2,22,622,622,4622,4622,44,45,'UVAAAA','PPJAAA','HHHHxx'
+6089,6490,1,1,9,9,89,89,89,1089,6089,178,179,'FAAAAA','QPJAAA','OOOOxx'
+8567,6491,1,3,7,7,67,567,567,3567,8567,134,135,'NRAAAA','RPJAAA','VVVVxx'
+597,6492,1,1,7,17,97,597,597,597,597,194,195,'ZWAAAA','SPJAAA','AAAAxx'
+4222,6493,0,2,2,2,22,222,222,4222,4222,44,45,'KGAAAA','TPJAAA','HHHHxx'
+9322,6494,0,2,2,2,22,322,1322,4322,9322,44,45,'OUAAAA','UPJAAA','OOOOxx'
+624,6495,0,0,4,4,24,624,624,624,624,48,49,'AYAAAA','VPJAAA','VVVVxx'
+4329,6496,1,1,9,9,29,329,329,4329,4329,58,59,'NKAAAA','WPJAAA','AAAAxx'
+6781,6497,1,1,1,1,81,781,781,1781,6781,162,163,'VAAAAA','XPJAAA','HHHHxx'
+1673,6498,1,1,3,13,73,673,1673,1673,1673,146,147,'JMAAAA','YPJAAA','OOOOxx'
+6633,6499,1,1,3,13,33,633,633,1633,6633,66,67,'DVAAAA','ZPJAAA','VVVVxx'
+2569,6500,1,1,9,9,69,569,569,2569,2569,138,139,'VUAAAA','AQJAAA','AAAAxx'
+4995,6501,1,3,5,15,95,995,995,4995,4995,190,191,'DKAAAA','BQJAAA','HHHHxx'
+2749,6502,1,1,9,9,49,749,749,2749,2749,98,99,'TBAAAA','CQJAAA','OOOOxx'
+9044,6503,0,0,4,4,44,44,1044,4044,9044,88,89,'WJAAAA','DQJAAA','VVVVxx'
+5823,6504,1,3,3,3,23,823,1823,823,5823,46,47,'ZPAAAA','EQJAAA','AAAAxx'
+9366,6505,0,2,6,6,66,366,1366,4366,9366,132,133,'GWAAAA','FQJAAA','HHHHxx'
+1169,6506,1,1,9,9,69,169,1169,1169,1169,138,139,'ZSAAAA','GQJAAA','OOOOxx'
+1300,6507,0,0,0,0,0,300,1300,1300,1300,0,1,'AYAAAA','HQJAAA','VVVVxx'
+9973,6508,1,1,3,13,73,973,1973,4973,9973,146,147,'PTAAAA','IQJAAA','AAAAxx'
+2092,6509,0,0,2,12,92,92,92,2092,2092,184,185,'MCAAAA','JQJAAA','HHHHxx'
+9776,6510,0,0,6,16,76,776,1776,4776,9776,152,153,'AMAAAA','KQJAAA','OOOOxx'
+7612,6511,0,0,2,12,12,612,1612,2612,7612,24,25,'UGAAAA','LQJAAA','VVVVxx'
+7190,6512,0,2,0,10,90,190,1190,2190,7190,180,181,'OQAAAA','MQJAAA','AAAAxx'
+5147,6513,1,3,7,7,47,147,1147,147,5147,94,95,'ZPAAAA','NQJAAA','HHHHxx'
+3722,6514,0,2,2,2,22,722,1722,3722,3722,44,45,'ENAAAA','OQJAAA','OOOOxx'
+5858,6515,0,2,8,18,58,858,1858,858,5858,116,117,'IRAAAA','PQJAAA','VVVVxx'
+3204,6516,0,0,4,4,4,204,1204,3204,3204,8,9,'GTAAAA','QQJAAA','AAAAxx'
+8994,6517,0,2,4,14,94,994,994,3994,8994,188,189,'YHAAAA','RQJAAA','HHHHxx'
+7478,6518,0,2,8,18,78,478,1478,2478,7478,156,157,'QBAAAA','SQJAAA','OOOOxx'
+9624,6519,0,0,4,4,24,624,1624,4624,9624,48,49,'EGAAAA','TQJAAA','VVVVxx'
+6639,6520,1,3,9,19,39,639,639,1639,6639,78,79,'JVAAAA','UQJAAA','AAAAxx'
+369,6521,1,1,9,9,69,369,369,369,369,138,139,'FOAAAA','VQJAAA','HHHHxx'
+7766,6522,0,2,6,6,66,766,1766,2766,7766,132,133,'SMAAAA','WQJAAA','OOOOxx'
+4094,6523,0,2,4,14,94,94,94,4094,4094,188,189,'MBAAAA','XQJAAA','VVVVxx'
+9556,6524,0,0,6,16,56,556,1556,4556,9556,112,113,'ODAAAA','YQJAAA','AAAAxx'
+4887,6525,1,3,7,7,87,887,887,4887,4887,174,175,'ZFAAAA','ZQJAAA','HHHHxx'
+2321,6526,1,1,1,1,21,321,321,2321,2321,42,43,'HLAAAA','ARJAAA','OOOOxx'
+9201,6527,1,1,1,1,1,201,1201,4201,9201,2,3,'XPAAAA','BRJAAA','VVVVxx'
+1627,6528,1,3,7,7,27,627,1627,1627,1627,54,55,'PKAAAA','CRJAAA','AAAAxx'
+150,6529,0,2,0,10,50,150,150,150,150,100,101,'UFAAAA','DRJAAA','HHHHxx'
+8010,6530,0,2,0,10,10,10,10,3010,8010,20,21,'CWAAAA','ERJAAA','OOOOxx'
+8026,6531,0,2,6,6,26,26,26,3026,8026,52,53,'SWAAAA','FRJAAA','VVVVxx'
+5495,6532,1,3,5,15,95,495,1495,495,5495,190,191,'JDAAAA','GRJAAA','AAAAxx'
+6213,6533,1,1,3,13,13,213,213,1213,6213,26,27,'ZEAAAA','HRJAAA','HHHHxx'
+6464,6534,0,0,4,4,64,464,464,1464,6464,128,129,'QOAAAA','IRJAAA','OOOOxx'
+1158,6535,0,2,8,18,58,158,1158,1158,1158,116,117,'OSAAAA','JRJAAA','VVVVxx'
+8669,6536,1,1,9,9,69,669,669,3669,8669,138,139,'LVAAAA','KRJAAA','AAAAxx'
+3225,6537,1,1,5,5,25,225,1225,3225,3225,50,51,'BUAAAA','LRJAAA','HHHHxx'
+1294,6538,0,2,4,14,94,294,1294,1294,1294,188,189,'UXAAAA','MRJAAA','OOOOxx'
+2166,6539,0,2,6,6,66,166,166,2166,2166,132,133,'IFAAAA','NRJAAA','VVVVxx'
+9328,6540,0,0,8,8,28,328,1328,4328,9328,56,57,'UUAAAA','ORJAAA','AAAAxx'
+8431,6541,1,3,1,11,31,431,431,3431,8431,62,63,'HMAAAA','PRJAAA','HHHHxx'
+7100,6542,0,0,0,0,0,100,1100,2100,7100,0,1,'CNAAAA','QRJAAA','OOOOxx'
+8126,6543,0,2,6,6,26,126,126,3126,8126,52,53,'OAAAAA','RRJAAA','VVVVxx'
+2185,6544,1,1,5,5,85,185,185,2185,2185,170,171,'BGAAAA','SRJAAA','AAAAxx'
+5697,6545,1,1,7,17,97,697,1697,697,5697,194,195,'DLAAAA','TRJAAA','HHHHxx'
+5531,6546,1,3,1,11,31,531,1531,531,5531,62,63,'TEAAAA','URJAAA','OOOOxx'
+3020,6547,0,0,0,0,20,20,1020,3020,3020,40,41,'EMAAAA','VRJAAA','VVVVxx'
+3076,6548,0,0,6,16,76,76,1076,3076,3076,152,153,'IOAAAA','WRJAAA','AAAAxx'
+9228,6549,0,0,8,8,28,228,1228,4228,9228,56,57,'YQAAAA','XRJAAA','HHHHxx'
+1734,6550,0,2,4,14,34,734,1734,1734,1734,68,69,'SOAAAA','YRJAAA','OOOOxx'
+7616,6551,0,0,6,16,16,616,1616,2616,7616,32,33,'YGAAAA','ZRJAAA','VVVVxx'
+9059,6552,1,3,9,19,59,59,1059,4059,9059,118,119,'LKAAAA','ASJAAA','AAAAxx'
+323,6553,1,3,3,3,23,323,323,323,323,46,47,'LMAAAA','BSJAAA','HHHHxx'
+1283,6554,1,3,3,3,83,283,1283,1283,1283,166,167,'JXAAAA','CSJAAA','OOOOxx'
+9535,6555,1,3,5,15,35,535,1535,4535,9535,70,71,'TCAAAA','DSJAAA','VVVVxx'
+2580,6556,0,0,0,0,80,580,580,2580,2580,160,161,'GVAAAA','ESJAAA','AAAAxx'
+7633,6557,1,1,3,13,33,633,1633,2633,7633,66,67,'PHAAAA','FSJAAA','HHHHxx'
+9497,6558,1,1,7,17,97,497,1497,4497,9497,194,195,'HBAAAA','GSJAAA','OOOOxx'
+9842,6559,0,2,2,2,42,842,1842,4842,9842,84,85,'OOAAAA','HSJAAA','VVVVxx'
+3426,6560,0,2,6,6,26,426,1426,3426,3426,52,53,'UBAAAA','ISJAAA','AAAAxx'
+7650,6561,0,2,0,10,50,650,1650,2650,7650,100,101,'GIAAAA','JSJAAA','HHHHxx'
+9935,6562,1,3,5,15,35,935,1935,4935,9935,70,71,'DSAAAA','KSJAAA','OOOOxx'
+9354,6563,0,2,4,14,54,354,1354,4354,9354,108,109,'UVAAAA','LSJAAA','VVVVxx'
+5569,6564,1,1,9,9,69,569,1569,569,5569,138,139,'FGAAAA','MSJAAA','AAAAxx'
+5765,6565,1,1,5,5,65,765,1765,765,5765,130,131,'TNAAAA','NSJAAA','HHHHxx'
+7283,6566,1,3,3,3,83,283,1283,2283,7283,166,167,'DUAAAA','OSJAAA','OOOOxx'
+1068,6567,0,0,8,8,68,68,1068,1068,1068,136,137,'CPAAAA','PSJAAA','VVVVxx'
+1641,6568,1,1,1,1,41,641,1641,1641,1641,82,83,'DLAAAA','QSJAAA','AAAAxx'
+1688,6569,0,0,8,8,88,688,1688,1688,1688,176,177,'YMAAAA','RSJAAA','HHHHxx'
+1133,6570,1,1,3,13,33,133,1133,1133,1133,66,67,'PRAAAA','SSJAAA','OOOOxx'
+4493,6571,1,1,3,13,93,493,493,4493,4493,186,187,'VQAAAA','TSJAAA','VVVVxx'
+3354,6572,0,2,4,14,54,354,1354,3354,3354,108,109,'AZAAAA','USJAAA','AAAAxx'
+4029,6573,1,1,9,9,29,29,29,4029,4029,58,59,'ZYAAAA','VSJAAA','HHHHxx'
+6704,6574,0,0,4,4,4,704,704,1704,6704,8,9,'WXAAAA','WSJAAA','OOOOxx'
+3221,6575,1,1,1,1,21,221,1221,3221,3221,42,43,'XTAAAA','XSJAAA','VVVVxx'
+9432,6576,0,0,2,12,32,432,1432,4432,9432,64,65,'UYAAAA','YSJAAA','AAAAxx'
+6990,6577,0,2,0,10,90,990,990,1990,6990,180,181,'WIAAAA','ZSJAAA','HHHHxx'
+1760,6578,0,0,0,0,60,760,1760,1760,1760,120,121,'SPAAAA','ATJAAA','OOOOxx'
+4754,6579,0,2,4,14,54,754,754,4754,4754,108,109,'WAAAAA','BTJAAA','VVVVxx'
+7724,6580,0,0,4,4,24,724,1724,2724,7724,48,49,'CLAAAA','CTJAAA','AAAAxx'
+9487,6581,1,3,7,7,87,487,1487,4487,9487,174,175,'XAAAAA','DTJAAA','HHHHxx'
+166,6582,0,2,6,6,66,166,166,166,166,132,133,'KGAAAA','ETJAAA','OOOOxx'
+5479,6583,1,3,9,19,79,479,1479,479,5479,158,159,'TCAAAA','FTJAAA','VVVVxx'
+8744,6584,0,0,4,4,44,744,744,3744,8744,88,89,'IYAAAA','GTJAAA','AAAAxx'
+5746,6585,0,2,6,6,46,746,1746,746,5746,92,93,'ANAAAA','HTJAAA','HHHHxx'
+907,6586,1,3,7,7,7,907,907,907,907,14,15,'XIAAAA','ITJAAA','OOOOxx'
+3968,6587,0,0,8,8,68,968,1968,3968,3968,136,137,'QWAAAA','JTJAAA','VVVVxx'
+5721,6588,1,1,1,1,21,721,1721,721,5721,42,43,'BMAAAA','KTJAAA','AAAAxx'
+6738,6589,0,2,8,18,38,738,738,1738,6738,76,77,'EZAAAA','LTJAAA','HHHHxx'
+4097,6590,1,1,7,17,97,97,97,4097,4097,194,195,'PBAAAA','MTJAAA','OOOOxx'
+8456,6591,0,0,6,16,56,456,456,3456,8456,112,113,'GNAAAA','NTJAAA','VVVVxx'
+1269,6592,1,1,9,9,69,269,1269,1269,1269,138,139,'VWAAAA','OTJAAA','AAAAxx'
+7997,6593,1,1,7,17,97,997,1997,2997,7997,194,195,'PVAAAA','PTJAAA','HHHHxx'
+9457,6594,1,1,7,17,57,457,1457,4457,9457,114,115,'TZAAAA','QTJAAA','OOOOxx'
+1159,6595,1,3,9,19,59,159,1159,1159,1159,118,119,'PSAAAA','RTJAAA','VVVVxx'
+1631,6596,1,3,1,11,31,631,1631,1631,1631,62,63,'TKAAAA','STJAAA','AAAAxx'
+2019,6597,1,3,9,19,19,19,19,2019,2019,38,39,'RZAAAA','TTJAAA','HHHHxx'
+3186,6598,0,2,6,6,86,186,1186,3186,3186,172,173,'OSAAAA','UTJAAA','OOOOxx'
+5587,6599,1,3,7,7,87,587,1587,587,5587,174,175,'XGAAAA','VTJAAA','VVVVxx'
+9172,6600,0,0,2,12,72,172,1172,4172,9172,144,145,'UOAAAA','WTJAAA','AAAAxx'
+5589,6601,1,1,9,9,89,589,1589,589,5589,178,179,'ZGAAAA','XTJAAA','HHHHxx'
+5103,6602,1,3,3,3,3,103,1103,103,5103,6,7,'HOAAAA','YTJAAA','OOOOxx'
+3177,6603,1,1,7,17,77,177,1177,3177,3177,154,155,'FSAAAA','ZTJAAA','VVVVxx'
+8887,6604,1,3,7,7,87,887,887,3887,8887,174,175,'VDAAAA','AUJAAA','AAAAxx'
+12,6605,0,0,2,12,12,12,12,12,12,24,25,'MAAAAA','BUJAAA','HHHHxx'
+8575,6606,1,3,5,15,75,575,575,3575,8575,150,151,'VRAAAA','CUJAAA','OOOOxx'
+4335,6607,1,3,5,15,35,335,335,4335,4335,70,71,'TKAAAA','DUJAAA','VVVVxx'
+4581,6608,1,1,1,1,81,581,581,4581,4581,162,163,'FUAAAA','EUJAAA','AAAAxx'
+4444,6609,0,0,4,4,44,444,444,4444,4444,88,89,'YOAAAA','FUJAAA','HHHHxx'
+7978,6610,0,2,8,18,78,978,1978,2978,7978,156,157,'WUAAAA','GUJAAA','OOOOxx'
+3081,6611,1,1,1,1,81,81,1081,3081,3081,162,163,'NOAAAA','HUJAAA','VVVVxx'
+4059,6612,1,3,9,19,59,59,59,4059,4059,118,119,'DAAAAA','IUJAAA','AAAAxx'
+5711,6613,1,3,1,11,11,711,1711,711,5711,22,23,'RLAAAA','JUJAAA','HHHHxx'
+7069,6614,1,1,9,9,69,69,1069,2069,7069,138,139,'XLAAAA','KUJAAA','OOOOxx'
+6150,6615,0,2,0,10,50,150,150,1150,6150,100,101,'OCAAAA','LUJAAA','VVVVxx'
+9550,6616,0,2,0,10,50,550,1550,4550,9550,100,101,'IDAAAA','MUJAAA','AAAAxx'
+7087,6617,1,3,7,7,87,87,1087,2087,7087,174,175,'PMAAAA','NUJAAA','HHHHxx'
+9557,6618,1,1,7,17,57,557,1557,4557,9557,114,115,'PDAAAA','OUJAAA','OOOOxx'
+7856,6619,0,0,6,16,56,856,1856,2856,7856,112,113,'EQAAAA','PUJAAA','VVVVxx'
+1115,6620,1,3,5,15,15,115,1115,1115,1115,30,31,'XQAAAA','QUJAAA','AAAAxx'
+1086,6621,0,2,6,6,86,86,1086,1086,1086,172,173,'UPAAAA','RUJAAA','HHHHxx'
+5048,6622,0,0,8,8,48,48,1048,48,5048,96,97,'EMAAAA','SUJAAA','OOOOxx'
+5168,6623,0,0,8,8,68,168,1168,168,5168,136,137,'UQAAAA','TUJAAA','VVVVxx'
+6029,6624,1,1,9,9,29,29,29,1029,6029,58,59,'XXAAAA','UUJAAA','AAAAxx'
+546,6625,0,2,6,6,46,546,546,546,546,92,93,'AVAAAA','VUJAAA','HHHHxx'
+2908,6626,0,0,8,8,8,908,908,2908,2908,16,17,'WHAAAA','WUJAAA','OOOOxx'
+779,6627,1,3,9,19,79,779,779,779,779,158,159,'ZDAAAA','XUJAAA','VVVVxx'
+4202,6628,0,2,2,2,2,202,202,4202,4202,4,5,'QFAAAA','YUJAAA','AAAAxx'
+9984,6629,0,0,4,4,84,984,1984,4984,9984,168,169,'AUAAAA','ZUJAAA','HHHHxx'
+4730,6630,0,2,0,10,30,730,730,4730,4730,60,61,'YZAAAA','AVJAAA','OOOOxx'
+6517,6631,1,1,7,17,17,517,517,1517,6517,34,35,'RQAAAA','BVJAAA','VVVVxx'
+8410,6632,0,2,0,10,10,410,410,3410,8410,20,21,'MLAAAA','CVJAAA','AAAAxx'
+4793,6633,1,1,3,13,93,793,793,4793,4793,186,187,'JCAAAA','DVJAAA','HHHHxx'
+3431,6634,1,3,1,11,31,431,1431,3431,3431,62,63,'ZBAAAA','EVJAAA','OOOOxx'
+2481,6635,1,1,1,1,81,481,481,2481,2481,162,163,'LRAAAA','FVJAAA','VVVVxx'
+3905,6636,1,1,5,5,5,905,1905,3905,3905,10,11,'FUAAAA','GVJAAA','AAAAxx'
+8807,6637,1,3,7,7,7,807,807,3807,8807,14,15,'TAAAAA','HVJAAA','HHHHxx'
+2660,6638,0,0,0,0,60,660,660,2660,2660,120,121,'IYAAAA','IVJAAA','OOOOxx'
+4985,6639,1,1,5,5,85,985,985,4985,4985,170,171,'TJAAAA','JVJAAA','VVVVxx'
+3080,6640,0,0,0,0,80,80,1080,3080,3080,160,161,'MOAAAA','KVJAAA','AAAAxx'
+1090,6641,0,2,0,10,90,90,1090,1090,1090,180,181,'YPAAAA','LVJAAA','HHHHxx'
+6917,6642,1,1,7,17,17,917,917,1917,6917,34,35,'BGAAAA','MVJAAA','OOOOxx'
+5177,6643,1,1,7,17,77,177,1177,177,5177,154,155,'DRAAAA','NVJAAA','VVVVxx'
+2729,6644,1,1,9,9,29,729,729,2729,2729,58,59,'ZAAAAA','OVJAAA','AAAAxx'
+9706,6645,0,2,6,6,6,706,1706,4706,9706,12,13,'IJAAAA','PVJAAA','HHHHxx'
+9929,6646,1,1,9,9,29,929,1929,4929,9929,58,59,'XRAAAA','QVJAAA','OOOOxx'
+1547,6647,1,3,7,7,47,547,1547,1547,1547,94,95,'NHAAAA','RVJAAA','VVVVxx'
+2798,6648,0,2,8,18,98,798,798,2798,2798,196,197,'QDAAAA','SVJAAA','AAAAxx'
+4420,6649,0,0,0,0,20,420,420,4420,4420,40,41,'AOAAAA','TVJAAA','HHHHxx'
+6771,6650,1,3,1,11,71,771,771,1771,6771,142,143,'LAAAAA','UVJAAA','OOOOxx'
+2004,6651,0,0,4,4,4,4,4,2004,2004,8,9,'CZAAAA','VVJAAA','VVVVxx'
+8686,6652,0,2,6,6,86,686,686,3686,8686,172,173,'CWAAAA','WVJAAA','AAAAxx'
+3663,6653,1,3,3,3,63,663,1663,3663,3663,126,127,'XKAAAA','XVJAAA','HHHHxx'
+806,6654,0,2,6,6,6,806,806,806,806,12,13,'AFAAAA','YVJAAA','OOOOxx'
+4309,6655,1,1,9,9,9,309,309,4309,4309,18,19,'TJAAAA','ZVJAAA','VVVVxx'
+7443,6656,1,3,3,3,43,443,1443,2443,7443,86,87,'HAAAAA','AWJAAA','AAAAxx'
+5779,6657,1,3,9,19,79,779,1779,779,5779,158,159,'HOAAAA','BWJAAA','HHHHxx'
+8821,6658,1,1,1,1,21,821,821,3821,8821,42,43,'HBAAAA','CWJAAA','OOOOxx'
+4198,6659,0,2,8,18,98,198,198,4198,4198,196,197,'MFAAAA','DWJAAA','VVVVxx'
+8115,6660,1,3,5,15,15,115,115,3115,8115,30,31,'DAAAAA','EWJAAA','AAAAxx'
+9554,6661,0,2,4,14,54,554,1554,4554,9554,108,109,'MDAAAA','FWJAAA','HHHHxx'
+8956,6662,0,0,6,16,56,956,956,3956,8956,112,113,'MGAAAA','GWJAAA','OOOOxx'
+4733,6663,1,1,3,13,33,733,733,4733,4733,66,67,'BAAAAA','HWJAAA','VVVVxx'
+5417,6664,1,1,7,17,17,417,1417,417,5417,34,35,'JAAAAA','IWJAAA','AAAAxx'
+4792,6665,0,0,2,12,92,792,792,4792,4792,184,185,'ICAAAA','JWJAAA','HHHHxx'
+462,6666,0,2,2,2,62,462,462,462,462,124,125,'URAAAA','KWJAAA','OOOOxx'
+3687,6667,1,3,7,7,87,687,1687,3687,3687,174,175,'VLAAAA','LWJAAA','VVVVxx'
+2013,6668,1,1,3,13,13,13,13,2013,2013,26,27,'LZAAAA','MWJAAA','AAAAxx'
+5386,6669,0,2,6,6,86,386,1386,386,5386,172,173,'EZAAAA','NWJAAA','HHHHxx'
+2816,6670,0,0,6,16,16,816,816,2816,2816,32,33,'IEAAAA','OWJAAA','OOOOxx'
+7827,6671,1,3,7,7,27,827,1827,2827,7827,54,55,'BPAAAA','PWJAAA','VVVVxx'
+5077,6672,1,1,7,17,77,77,1077,77,5077,154,155,'HNAAAA','QWJAAA','AAAAxx'
+6039,6673,1,3,9,19,39,39,39,1039,6039,78,79,'HYAAAA','RWJAAA','HHHHxx'
+215,6674,1,3,5,15,15,215,215,215,215,30,31,'HIAAAA','SWJAAA','OOOOxx'
+855,6675,1,3,5,15,55,855,855,855,855,110,111,'XGAAAA','TWJAAA','VVVVxx'
+9692,6676,0,0,2,12,92,692,1692,4692,9692,184,185,'UIAAAA','UWJAAA','AAAAxx'
+8391,6677,1,3,1,11,91,391,391,3391,8391,182,183,'TKAAAA','VWJAAA','HHHHxx'
+8424,6678,0,0,4,4,24,424,424,3424,8424,48,49,'AMAAAA','WWJAAA','OOOOxx'
+6331,6679,1,3,1,11,31,331,331,1331,6331,62,63,'NJAAAA','XWJAAA','VVVVxx'
+6561,6680,1,1,1,1,61,561,561,1561,6561,122,123,'JSAAAA','YWJAAA','AAAAxx'
+8955,6681,1,3,5,15,55,955,955,3955,8955,110,111,'LGAAAA','ZWJAAA','HHHHxx'
+1764,6682,0,0,4,4,64,764,1764,1764,1764,128,129,'WPAAAA','AXJAAA','OOOOxx'
+6623,6683,1,3,3,3,23,623,623,1623,6623,46,47,'TUAAAA','BXJAAA','VVVVxx'
+2900,6684,0,0,0,0,0,900,900,2900,2900,0,1,'OHAAAA','CXJAAA','AAAAxx'
+7048,6685,0,0,8,8,48,48,1048,2048,7048,96,97,'CLAAAA','DXJAAA','HHHHxx'
+3843,6686,1,3,3,3,43,843,1843,3843,3843,86,87,'VRAAAA','EXJAAA','OOOOxx'
+4855,6687,1,3,5,15,55,855,855,4855,4855,110,111,'TEAAAA','FXJAAA','VVVVxx'
+7383,6688,1,3,3,3,83,383,1383,2383,7383,166,167,'ZXAAAA','GXJAAA','AAAAxx'
+7765,6689,1,1,5,5,65,765,1765,2765,7765,130,131,'RMAAAA','HXJAAA','HHHHxx'
+1125,6690,1,1,5,5,25,125,1125,1125,1125,50,51,'HRAAAA','IXJAAA','OOOOxx'
+755,6691,1,3,5,15,55,755,755,755,755,110,111,'BDAAAA','JXJAAA','VVVVxx'
+2995,6692,1,3,5,15,95,995,995,2995,2995,190,191,'FLAAAA','KXJAAA','AAAAxx'
+8907,6693,1,3,7,7,7,907,907,3907,8907,14,15,'PEAAAA','LXJAAA','HHHHxx'
+9357,6694,1,1,7,17,57,357,1357,4357,9357,114,115,'XVAAAA','MXJAAA','OOOOxx'
+4469,6695,1,1,9,9,69,469,469,4469,4469,138,139,'XPAAAA','NXJAAA','VVVVxx'
+2147,6696,1,3,7,7,47,147,147,2147,2147,94,95,'PEAAAA','OXJAAA','AAAAxx'
+2952,6697,0,0,2,12,52,952,952,2952,2952,104,105,'OJAAAA','PXJAAA','HHHHxx'
+1324,6698,0,0,4,4,24,324,1324,1324,1324,48,49,'YYAAAA','QXJAAA','OOOOxx'
+1173,6699,1,1,3,13,73,173,1173,1173,1173,146,147,'DTAAAA','RXJAAA','VVVVxx'
+3169,6700,1,1,9,9,69,169,1169,3169,3169,138,139,'XRAAAA','SXJAAA','AAAAxx'
+5149,6701,1,1,9,9,49,149,1149,149,5149,98,99,'BQAAAA','TXJAAA','HHHHxx'
+9660,6702,0,0,0,0,60,660,1660,4660,9660,120,121,'OHAAAA','UXJAAA','OOOOxx'
+3446,6703,0,2,6,6,46,446,1446,3446,3446,92,93,'OCAAAA','VXJAAA','VVVVxx'
+6988,6704,0,0,8,8,88,988,988,1988,6988,176,177,'UIAAAA','WXJAAA','AAAAxx'
+5829,6705,1,1,9,9,29,829,1829,829,5829,58,59,'FQAAAA','XXJAAA','HHHHxx'
+7166,6706,0,2,6,6,66,166,1166,2166,7166,132,133,'QPAAAA','YXJAAA','OOOOxx'
+3940,6707,0,0,0,0,40,940,1940,3940,3940,80,81,'OVAAAA','ZXJAAA','VVVVxx'
+2645,6708,1,1,5,5,45,645,645,2645,2645,90,91,'TXAAAA','AYJAAA','AAAAxx'
+478,6709,0,2,8,18,78,478,478,478,478,156,157,'KSAAAA','BYJAAA','HHHHxx'
+1156,6710,0,0,6,16,56,156,1156,1156,1156,112,113,'MSAAAA','CYJAAA','OOOOxx'
+2731,6711,1,3,1,11,31,731,731,2731,2731,62,63,'BBAAAA','DYJAAA','VVVVxx'
+5637,6712,1,1,7,17,37,637,1637,637,5637,74,75,'VIAAAA','EYJAAA','AAAAxx'
+7517,6713,1,1,7,17,17,517,1517,2517,7517,34,35,'DDAAAA','FYJAAA','HHHHxx'
+5331,6714,1,3,1,11,31,331,1331,331,5331,62,63,'BXAAAA','GYJAAA','OOOOxx'
+9640,6715,0,0,0,0,40,640,1640,4640,9640,80,81,'UGAAAA','HYJAAA','VVVVxx'
+4108,6716,0,0,8,8,8,108,108,4108,4108,16,17,'ACAAAA','IYJAAA','AAAAxx'
+1087,6717,1,3,7,7,87,87,1087,1087,1087,174,175,'VPAAAA','JYJAAA','HHHHxx'
+8017,6718,1,1,7,17,17,17,17,3017,8017,34,35,'JWAAAA','KYJAAA','OOOOxx'
+8795,6719,1,3,5,15,95,795,795,3795,8795,190,191,'HAAAAA','LYJAAA','VVVVxx'
+7060,6720,0,0,0,0,60,60,1060,2060,7060,120,121,'OLAAAA','MYJAAA','AAAAxx'
+9450,6721,0,2,0,10,50,450,1450,4450,9450,100,101,'MZAAAA','NYJAAA','HHHHxx'
+390,6722,0,2,0,10,90,390,390,390,390,180,181,'APAAAA','OYJAAA','OOOOxx'
+66,6723,0,2,6,6,66,66,66,66,66,132,133,'OCAAAA','PYJAAA','VVVVxx'
+8789,6724,1,1,9,9,89,789,789,3789,8789,178,179,'BAAAAA','QYJAAA','AAAAxx'
+9260,6725,0,0,0,0,60,260,1260,4260,9260,120,121,'ESAAAA','RYJAAA','HHHHxx'
+6679,6726,1,3,9,19,79,679,679,1679,6679,158,159,'XWAAAA','SYJAAA','OOOOxx'
+9052,6727,0,0,2,12,52,52,1052,4052,9052,104,105,'EKAAAA','TYJAAA','VVVVxx'
+9561,6728,1,1,1,1,61,561,1561,4561,9561,122,123,'TDAAAA','UYJAAA','AAAAxx'
+9725,6729,1,1,5,5,25,725,1725,4725,9725,50,51,'BKAAAA','VYJAAA','HHHHxx'
+6298,6730,0,2,8,18,98,298,298,1298,6298,196,197,'GIAAAA','WYJAAA','OOOOxx'
+8654,6731,0,2,4,14,54,654,654,3654,8654,108,109,'WUAAAA','XYJAAA','VVVVxx'
+8725,6732,1,1,5,5,25,725,725,3725,8725,50,51,'PXAAAA','YYJAAA','AAAAxx'
+9377,6733,1,1,7,17,77,377,1377,4377,9377,154,155,'RWAAAA','ZYJAAA','HHHHxx'
+3807,6734,1,3,7,7,7,807,1807,3807,3807,14,15,'LQAAAA','AZJAAA','OOOOxx'
+8048,6735,0,0,8,8,48,48,48,3048,8048,96,97,'OXAAAA','BZJAAA','VVVVxx'
+764,6736,0,0,4,4,64,764,764,764,764,128,129,'KDAAAA','CZJAAA','AAAAxx'
+9702,6737,0,2,2,2,2,702,1702,4702,9702,4,5,'EJAAAA','DZJAAA','HHHHxx'
+8060,6738,0,0,0,0,60,60,60,3060,8060,120,121,'AYAAAA','EZJAAA','OOOOxx'
+6371,6739,1,3,1,11,71,371,371,1371,6371,142,143,'BLAAAA','FZJAAA','VVVVxx'
+5237,6740,1,1,7,17,37,237,1237,237,5237,74,75,'LTAAAA','GZJAAA','AAAAxx'
+743,6741,1,3,3,3,43,743,743,743,743,86,87,'PCAAAA','HZJAAA','HHHHxx'
+7395,6742,1,3,5,15,95,395,1395,2395,7395,190,191,'LYAAAA','IZJAAA','OOOOxx'
+3365,6743,1,1,5,5,65,365,1365,3365,3365,130,131,'LZAAAA','JZJAAA','VVVVxx'
+6667,6744,1,3,7,7,67,667,667,1667,6667,134,135,'LWAAAA','KZJAAA','AAAAxx'
+3445,6745,1,1,5,5,45,445,1445,3445,3445,90,91,'NCAAAA','LZJAAA','HHHHxx'
+4019,6746,1,3,9,19,19,19,19,4019,4019,38,39,'PYAAAA','MZJAAA','OOOOxx'
+7035,6747,1,3,5,15,35,35,1035,2035,7035,70,71,'PKAAAA','NZJAAA','VVVVxx'
+5274,6748,0,2,4,14,74,274,1274,274,5274,148,149,'WUAAAA','OZJAAA','AAAAxx'
+519,6749,1,3,9,19,19,519,519,519,519,38,39,'ZTAAAA','PZJAAA','HHHHxx'
+2801,6750,1,1,1,1,1,801,801,2801,2801,2,3,'TDAAAA','QZJAAA','OOOOxx'
+3320,6751,0,0,0,0,20,320,1320,3320,3320,40,41,'SXAAAA','RZJAAA','VVVVxx'
+3153,6752,1,1,3,13,53,153,1153,3153,3153,106,107,'HRAAAA','SZJAAA','AAAAxx'
+7680,6753,0,0,0,0,80,680,1680,2680,7680,160,161,'KJAAAA','TZJAAA','HHHHxx'
+8942,6754,0,2,2,2,42,942,942,3942,8942,84,85,'YFAAAA','UZJAAA','OOOOxx'
+3195,6755,1,3,5,15,95,195,1195,3195,3195,190,191,'XSAAAA','VZJAAA','VVVVxx'
+2287,6756,1,3,7,7,87,287,287,2287,2287,174,175,'ZJAAAA','WZJAAA','AAAAxx'
+8325,6757,1,1,5,5,25,325,325,3325,8325,50,51,'FIAAAA','XZJAAA','HHHHxx'
+2603,6758,1,3,3,3,3,603,603,2603,2603,6,7,'DWAAAA','YZJAAA','OOOOxx'
+5871,6759,1,3,1,11,71,871,1871,871,5871,142,143,'VRAAAA','ZZJAAA','VVVVxx'
+1773,6760,1,1,3,13,73,773,1773,1773,1773,146,147,'FQAAAA','AAKAAA','AAAAxx'
+3323,6761,1,3,3,3,23,323,1323,3323,3323,46,47,'VXAAAA','BAKAAA','HHHHxx'
+2053,6762,1,1,3,13,53,53,53,2053,2053,106,107,'ZAAAAA','CAKAAA','OOOOxx'
+4062,6763,0,2,2,2,62,62,62,4062,4062,124,125,'GAAAAA','DAKAAA','VVVVxx'
+4611,6764,1,3,1,11,11,611,611,4611,4611,22,23,'JVAAAA','EAKAAA','AAAAxx'
+3451,6765,1,3,1,11,51,451,1451,3451,3451,102,103,'TCAAAA','FAKAAA','HHHHxx'
+1819,6766,1,3,9,19,19,819,1819,1819,1819,38,39,'ZRAAAA','GAKAAA','OOOOxx'
+9806,6767,0,2,6,6,6,806,1806,4806,9806,12,13,'ENAAAA','HAKAAA','VVVVxx'
+6619,6768,1,3,9,19,19,619,619,1619,6619,38,39,'PUAAAA','IAKAAA','AAAAxx'
+1031,6769,1,3,1,11,31,31,1031,1031,1031,62,63,'RNAAAA','JAKAAA','HHHHxx'
+1865,6770,1,1,5,5,65,865,1865,1865,1865,130,131,'TTAAAA','KAKAAA','OOOOxx'
+6282,6771,0,2,2,2,82,282,282,1282,6282,164,165,'QHAAAA','LAKAAA','VVVVxx'
+1178,6772,0,2,8,18,78,178,1178,1178,1178,156,157,'ITAAAA','MAKAAA','AAAAxx'
+8007,6773,1,3,7,7,7,7,7,3007,8007,14,15,'ZVAAAA','NAKAAA','HHHHxx'
+9126,6774,0,2,6,6,26,126,1126,4126,9126,52,53,'ANAAAA','OAKAAA','OOOOxx'
+9113,6775,1,1,3,13,13,113,1113,4113,9113,26,27,'NMAAAA','PAKAAA','VVVVxx'
+537,6776,1,1,7,17,37,537,537,537,537,74,75,'RUAAAA','QAKAAA','AAAAxx'
+6208,6777,0,0,8,8,8,208,208,1208,6208,16,17,'UEAAAA','RAKAAA','HHHHxx'
+1626,6778,0,2,6,6,26,626,1626,1626,1626,52,53,'OKAAAA','SAKAAA','OOOOxx'
+7188,6779,0,0,8,8,88,188,1188,2188,7188,176,177,'MQAAAA','TAKAAA','VVVVxx'
+9216,6780,0,0,6,16,16,216,1216,4216,9216,32,33,'MQAAAA','UAKAAA','AAAAxx'
+6134,6781,0,2,4,14,34,134,134,1134,6134,68,69,'YBAAAA','VAKAAA','HHHHxx'
+2074,6782,0,2,4,14,74,74,74,2074,2074,148,149,'UBAAAA','WAKAAA','OOOOxx'
+6369,6783,1,1,9,9,69,369,369,1369,6369,138,139,'ZKAAAA','XAKAAA','VVVVxx'
+9306,6784,0,2,6,6,6,306,1306,4306,9306,12,13,'YTAAAA','YAKAAA','AAAAxx'
+3155,6785,1,3,5,15,55,155,1155,3155,3155,110,111,'JRAAAA','ZAKAAA','HHHHxx'
+3611,6786,1,3,1,11,11,611,1611,3611,3611,22,23,'XIAAAA','ABKAAA','OOOOxx'
+6530,6787,0,2,0,10,30,530,530,1530,6530,60,61,'ERAAAA','BBKAAA','VVVVxx'
+6979,6788,1,3,9,19,79,979,979,1979,6979,158,159,'LIAAAA','CBKAAA','AAAAxx'
+9129,6789,1,1,9,9,29,129,1129,4129,9129,58,59,'DNAAAA','DBKAAA','HHHHxx'
+8013,6790,1,1,3,13,13,13,13,3013,8013,26,27,'FWAAAA','EBKAAA','OOOOxx'
+6926,6791,0,2,6,6,26,926,926,1926,6926,52,53,'KGAAAA','FBKAAA','VVVVxx'
+1877,6792,1,1,7,17,77,877,1877,1877,1877,154,155,'FUAAAA','GBKAAA','AAAAxx'
+1882,6793,0,2,2,2,82,882,1882,1882,1882,164,165,'KUAAAA','HBKAAA','HHHHxx'
+6720,6794,0,0,0,0,20,720,720,1720,6720,40,41,'MYAAAA','IBKAAA','OOOOxx'
+690,6795,0,2,0,10,90,690,690,690,690,180,181,'OAAAAA','JBKAAA','VVVVxx'
+143,6796,1,3,3,3,43,143,143,143,143,86,87,'NFAAAA','KBKAAA','AAAAxx'
+7241,6797,1,1,1,1,41,241,1241,2241,7241,82,83,'NSAAAA','LBKAAA','HHHHxx'
+6461,6798,1,1,1,1,61,461,461,1461,6461,122,123,'NOAAAA','MBKAAA','OOOOxx'
+2258,6799,0,2,8,18,58,258,258,2258,2258,116,117,'WIAAAA','NBKAAA','VVVVxx'
+2280,6800,0,0,0,0,80,280,280,2280,2280,160,161,'SJAAAA','OBKAAA','AAAAxx'
+7556,6801,0,0,6,16,56,556,1556,2556,7556,112,113,'QEAAAA','PBKAAA','HHHHxx'
+1038,6802,0,2,8,18,38,38,1038,1038,1038,76,77,'YNAAAA','QBKAAA','OOOOxx'
+2634,6803,0,2,4,14,34,634,634,2634,2634,68,69,'IXAAAA','RBKAAA','VVVVxx'
+7847,6804,1,3,7,7,47,847,1847,2847,7847,94,95,'VPAAAA','SBKAAA','AAAAxx'
+4415,6805,1,3,5,15,15,415,415,4415,4415,30,31,'VNAAAA','TBKAAA','HHHHxx'
+1933,6806,1,1,3,13,33,933,1933,1933,1933,66,67,'JWAAAA','UBKAAA','OOOOxx'
+8034,6807,0,2,4,14,34,34,34,3034,8034,68,69,'AXAAAA','VBKAAA','VVVVxx'
+9233,6808,1,1,3,13,33,233,1233,4233,9233,66,67,'DRAAAA','WBKAAA','AAAAxx'
+6572,6809,0,0,2,12,72,572,572,1572,6572,144,145,'USAAAA','XBKAAA','HHHHxx'
+1586,6810,0,2,6,6,86,586,1586,1586,1586,172,173,'AJAAAA','YBKAAA','OOOOxx'
+8512,6811,0,0,2,12,12,512,512,3512,8512,24,25,'KPAAAA','ZBKAAA','VVVVxx'
+7421,6812,1,1,1,1,21,421,1421,2421,7421,42,43,'LZAAAA','ACKAAA','AAAAxx'
+503,6813,1,3,3,3,3,503,503,503,503,6,7,'JTAAAA','BCKAAA','HHHHxx'
+5332,6814,0,0,2,12,32,332,1332,332,5332,64,65,'CXAAAA','CCKAAA','OOOOxx'
+2602,6815,0,2,2,2,2,602,602,2602,2602,4,5,'CWAAAA','DCKAAA','VVVVxx'
+2902,6816,0,2,2,2,2,902,902,2902,2902,4,5,'QHAAAA','ECKAAA','AAAAxx'
+2979,6817,1,3,9,19,79,979,979,2979,2979,158,159,'PKAAAA','FCKAAA','HHHHxx'
+1431,6818,1,3,1,11,31,431,1431,1431,1431,62,63,'BDAAAA','GCKAAA','OOOOxx'
+8639,6819,1,3,9,19,39,639,639,3639,8639,78,79,'HUAAAA','HCKAAA','VVVVxx'
+4218,6820,0,2,8,18,18,218,218,4218,4218,36,37,'GGAAAA','ICKAAA','AAAAxx'
+7453,6821,1,1,3,13,53,453,1453,2453,7453,106,107,'RAAAAA','JCKAAA','HHHHxx'
+5448,6822,0,0,8,8,48,448,1448,448,5448,96,97,'OBAAAA','KCKAAA','OOOOxx'
+6768,6823,0,0,8,8,68,768,768,1768,6768,136,137,'IAAAAA','LCKAAA','VVVVxx'
+3104,6824,0,0,4,4,4,104,1104,3104,3104,8,9,'KPAAAA','MCKAAA','AAAAxx'
+2297,6825,1,1,7,17,97,297,297,2297,2297,194,195,'JKAAAA','NCKAAA','HHHHxx'
+7994,6826,0,2,4,14,94,994,1994,2994,7994,188,189,'MVAAAA','OCKAAA','OOOOxx'
+550,6827,0,2,0,10,50,550,550,550,550,100,101,'EVAAAA','PCKAAA','VVVVxx'
+4777,6828,1,1,7,17,77,777,777,4777,4777,154,155,'TBAAAA','QCKAAA','AAAAxx'
+5962,6829,0,2,2,2,62,962,1962,962,5962,124,125,'IVAAAA','RCKAAA','HHHHxx'
+1763,6830,1,3,3,3,63,763,1763,1763,1763,126,127,'VPAAAA','SCKAAA','OOOOxx'
+3654,6831,0,2,4,14,54,654,1654,3654,3654,108,109,'OKAAAA','TCKAAA','VVVVxx'
+4106,6832,0,2,6,6,6,106,106,4106,4106,12,13,'YBAAAA','UCKAAA','AAAAxx'
+5156,6833,0,0,6,16,56,156,1156,156,5156,112,113,'IQAAAA','VCKAAA','HHHHxx'
+422,6834,0,2,2,2,22,422,422,422,422,44,45,'GQAAAA','WCKAAA','OOOOxx'
+5011,6835,1,3,1,11,11,11,1011,11,5011,22,23,'TKAAAA','XCKAAA','VVVVxx'
+218,6836,0,2,8,18,18,218,218,218,218,36,37,'KIAAAA','YCKAAA','AAAAxx'
+9762,6837,0,2,2,2,62,762,1762,4762,9762,124,125,'MLAAAA','ZCKAAA','HHHHxx'
+6074,6838,0,2,4,14,74,74,74,1074,6074,148,149,'QZAAAA','ADKAAA','OOOOxx'
+4060,6839,0,0,0,0,60,60,60,4060,4060,120,121,'EAAAAA','BDKAAA','VVVVxx'
+8680,6840,0,0,0,0,80,680,680,3680,8680,160,161,'WVAAAA','CDKAAA','AAAAxx'
+5863,6841,1,3,3,3,63,863,1863,863,5863,126,127,'NRAAAA','DDKAAA','HHHHxx'
+8042,6842,0,2,2,2,42,42,42,3042,8042,84,85,'IXAAAA','EDKAAA','OOOOxx'
+2964,6843,0,0,4,4,64,964,964,2964,2964,128,129,'AKAAAA','FDKAAA','VVVVxx'
+6931,6844,1,3,1,11,31,931,931,1931,6931,62,63,'PGAAAA','GDKAAA','AAAAxx'
+6715,6845,1,3,5,15,15,715,715,1715,6715,30,31,'HYAAAA','HDKAAA','HHHHxx'
+5859,6846,1,3,9,19,59,859,1859,859,5859,118,119,'JRAAAA','IDKAAA','OOOOxx'
+6173,6847,1,1,3,13,73,173,173,1173,6173,146,147,'LDAAAA','JDKAAA','VVVVxx'
+7788,6848,0,0,8,8,88,788,1788,2788,7788,176,177,'ONAAAA','KDKAAA','AAAAxx'
+9370,6849,0,2,0,10,70,370,1370,4370,9370,140,141,'KWAAAA','LDKAAA','HHHHxx'
+3038,6850,0,2,8,18,38,38,1038,3038,3038,76,77,'WMAAAA','MDKAAA','OOOOxx'
+6483,6851,1,3,3,3,83,483,483,1483,6483,166,167,'JPAAAA','NDKAAA','VVVVxx'
+7534,6852,0,2,4,14,34,534,1534,2534,7534,68,69,'UDAAAA','ODKAAA','AAAAxx'
+5769,6853,1,1,9,9,69,769,1769,769,5769,138,139,'XNAAAA','PDKAAA','HHHHxx'
+9152,6854,0,0,2,12,52,152,1152,4152,9152,104,105,'AOAAAA','QDKAAA','OOOOxx'
+6251,6855,1,3,1,11,51,251,251,1251,6251,102,103,'LGAAAA','RDKAAA','VVVVxx'
+9209,6856,1,1,9,9,9,209,1209,4209,9209,18,19,'FQAAAA','SDKAAA','AAAAxx'
+5365,6857,1,1,5,5,65,365,1365,365,5365,130,131,'JYAAAA','TDKAAA','HHHHxx'
+509,6858,1,1,9,9,9,509,509,509,509,18,19,'PTAAAA','UDKAAA','OOOOxx'
+3132,6859,0,0,2,12,32,132,1132,3132,3132,64,65,'MQAAAA','VDKAAA','VVVVxx'
+5373,6860,1,1,3,13,73,373,1373,373,5373,146,147,'RYAAAA','WDKAAA','AAAAxx'
+4247,6861,1,3,7,7,47,247,247,4247,4247,94,95,'JHAAAA','XDKAAA','HHHHxx'
+3491,6862,1,3,1,11,91,491,1491,3491,3491,182,183,'HEAAAA','YDKAAA','OOOOxx'
+495,6863,1,3,5,15,95,495,495,495,495,190,191,'BTAAAA','ZDKAAA','VVVVxx'
+1594,6864,0,2,4,14,94,594,1594,1594,1594,188,189,'IJAAAA','AEKAAA','AAAAxx'
+2243,6865,1,3,3,3,43,243,243,2243,2243,86,87,'HIAAAA','BEKAAA','HHHHxx'
+7780,6866,0,0,0,0,80,780,1780,2780,7780,160,161,'GNAAAA','CEKAAA','OOOOxx'
+5632,6867,0,0,2,12,32,632,1632,632,5632,64,65,'QIAAAA','DEKAAA','VVVVxx'
+2679,6868,1,3,9,19,79,679,679,2679,2679,158,159,'BZAAAA','EEKAAA','AAAAxx'
+1354,6869,0,2,4,14,54,354,1354,1354,1354,108,109,'CAAAAA','FEKAAA','HHHHxx'
+180,6870,0,0,0,0,80,180,180,180,180,160,161,'YGAAAA','GEKAAA','OOOOxx'
+7017,6871,1,1,7,17,17,17,1017,2017,7017,34,35,'XJAAAA','HEKAAA','VVVVxx'
+1867,6872,1,3,7,7,67,867,1867,1867,1867,134,135,'VTAAAA','IEKAAA','AAAAxx'
+2213,6873,1,1,3,13,13,213,213,2213,2213,26,27,'DHAAAA','JEKAAA','HHHHxx'
+8773,6874,1,1,3,13,73,773,773,3773,8773,146,147,'LZAAAA','KEKAAA','OOOOxx'
+1784,6875,0,0,4,4,84,784,1784,1784,1784,168,169,'QQAAAA','LEKAAA','VVVVxx'
+5961,6876,1,1,1,1,61,961,1961,961,5961,122,123,'HVAAAA','MEKAAA','AAAAxx'
+8801,6877,1,1,1,1,1,801,801,3801,8801,2,3,'NAAAAA','NEKAAA','HHHHxx'
+4860,6878,0,0,0,0,60,860,860,4860,4860,120,121,'YEAAAA','OEKAAA','OOOOxx'
+2214,6879,0,2,4,14,14,214,214,2214,2214,28,29,'EHAAAA','PEKAAA','VVVVxx'
+1735,6880,1,3,5,15,35,735,1735,1735,1735,70,71,'TOAAAA','QEKAAA','AAAAxx'
+578,6881,0,2,8,18,78,578,578,578,578,156,157,'GWAAAA','REKAAA','HHHHxx'
+7853,6882,1,1,3,13,53,853,1853,2853,7853,106,107,'BQAAAA','SEKAAA','OOOOxx'
+2215,6883,1,3,5,15,15,215,215,2215,2215,30,31,'FHAAAA','TEKAAA','VVVVxx'
+4704,6884,0,0,4,4,4,704,704,4704,4704,8,9,'YYAAAA','UEKAAA','AAAAxx'
+9379,6885,1,3,9,19,79,379,1379,4379,9379,158,159,'TWAAAA','VEKAAA','HHHHxx'
+9745,6886,1,1,5,5,45,745,1745,4745,9745,90,91,'VKAAAA','WEKAAA','OOOOxx'
+5636,6887,0,0,6,16,36,636,1636,636,5636,72,73,'UIAAAA','XEKAAA','VVVVxx'
+4548,6888,0,0,8,8,48,548,548,4548,4548,96,97,'YSAAAA','YEKAAA','AAAAxx'
+6537,6889,1,1,7,17,37,537,537,1537,6537,74,75,'LRAAAA','ZEKAAA','HHHHxx'
+7748,6890,0,0,8,8,48,748,1748,2748,7748,96,97,'AMAAAA','AFKAAA','OOOOxx'
+687,6891,1,3,7,7,87,687,687,687,687,174,175,'LAAAAA','BFKAAA','VVVVxx'
+1243,6892,1,3,3,3,43,243,1243,1243,1243,86,87,'VVAAAA','CFKAAA','AAAAxx'
+852,6893,0,0,2,12,52,852,852,852,852,104,105,'UGAAAA','DFKAAA','HHHHxx'
+785,6894,1,1,5,5,85,785,785,785,785,170,171,'FEAAAA','EFKAAA','OOOOxx'
+2002,6895,0,2,2,2,2,2,2,2002,2002,4,5,'AZAAAA','FFKAAA','VVVVxx'
+2748,6896,0,0,8,8,48,748,748,2748,2748,96,97,'SBAAAA','GFKAAA','AAAAxx'
+6075,6897,1,3,5,15,75,75,75,1075,6075,150,151,'RZAAAA','HFKAAA','HHHHxx'
+7029,6898,1,1,9,9,29,29,1029,2029,7029,58,59,'JKAAAA','IFKAAA','OOOOxx'
+7474,6899,0,2,4,14,74,474,1474,2474,7474,148,149,'MBAAAA','JFKAAA','VVVVxx'
+7755,6900,1,3,5,15,55,755,1755,2755,7755,110,111,'HMAAAA','KFKAAA','AAAAxx'
+1456,6901,0,0,6,16,56,456,1456,1456,1456,112,113,'AEAAAA','LFKAAA','HHHHxx'
+2808,6902,0,0,8,8,8,808,808,2808,2808,16,17,'AEAAAA','MFKAAA','OOOOxx'
+4089,6903,1,1,9,9,89,89,89,4089,4089,178,179,'HBAAAA','NFKAAA','VVVVxx'
+4718,6904,0,2,8,18,18,718,718,4718,4718,36,37,'MZAAAA','OFKAAA','AAAAxx'
+910,6905,0,2,0,10,10,910,910,910,910,20,21,'AJAAAA','PFKAAA','HHHHxx'
+2868,6906,0,0,8,8,68,868,868,2868,2868,136,137,'IGAAAA','QFKAAA','OOOOxx'
+2103,6907,1,3,3,3,3,103,103,2103,2103,6,7,'XCAAAA','RFKAAA','VVVVxx'
+2407,6908,1,3,7,7,7,407,407,2407,2407,14,15,'POAAAA','SFKAAA','AAAAxx'
+4353,6909,1,1,3,13,53,353,353,4353,4353,106,107,'LLAAAA','TFKAAA','HHHHxx'
+7988,6910,0,0,8,8,88,988,1988,2988,7988,176,177,'GVAAAA','UFKAAA','OOOOxx'
+2750,6911,0,2,0,10,50,750,750,2750,2750,100,101,'UBAAAA','VFKAAA','VVVVxx'
+2006,6912,0,2,6,6,6,6,6,2006,2006,12,13,'EZAAAA','WFKAAA','AAAAxx'
+4617,6913,1,1,7,17,17,617,617,4617,4617,34,35,'PVAAAA','XFKAAA','HHHHxx'
+1251,6914,1,3,1,11,51,251,1251,1251,1251,102,103,'DWAAAA','YFKAAA','OOOOxx'
+4590,6915,0,2,0,10,90,590,590,4590,4590,180,181,'OUAAAA','ZFKAAA','VVVVxx'
+1144,6916,0,0,4,4,44,144,1144,1144,1144,88,89,'ASAAAA','AGKAAA','AAAAxx'
+7131,6917,1,3,1,11,31,131,1131,2131,7131,62,63,'HOAAAA','BGKAAA','HHHHxx'
+95,6918,1,3,5,15,95,95,95,95,95,190,191,'RDAAAA','CGKAAA','OOOOxx'
+4827,6919,1,3,7,7,27,827,827,4827,4827,54,55,'RDAAAA','DGKAAA','VVVVxx'
+4307,6920,1,3,7,7,7,307,307,4307,4307,14,15,'RJAAAA','EGKAAA','AAAAxx'
+1505,6921,1,1,5,5,5,505,1505,1505,1505,10,11,'XFAAAA','FGKAAA','HHHHxx'
+8191,6922,1,3,1,11,91,191,191,3191,8191,182,183,'BDAAAA','GGKAAA','OOOOxx'
+5037,6923,1,1,7,17,37,37,1037,37,5037,74,75,'TLAAAA','HGKAAA','VVVVxx'
+7363,6924,1,3,3,3,63,363,1363,2363,7363,126,127,'FXAAAA','IGKAAA','AAAAxx'
+8427,6925,1,3,7,7,27,427,427,3427,8427,54,55,'DMAAAA','JGKAAA','HHHHxx'
+5231,6926,1,3,1,11,31,231,1231,231,5231,62,63,'FTAAAA','KGKAAA','OOOOxx'
+2943,6927,1,3,3,3,43,943,943,2943,2943,86,87,'FJAAAA','LGKAAA','VVVVxx'
+4624,6928,0,0,4,4,24,624,624,4624,4624,48,49,'WVAAAA','MGKAAA','AAAAxx'
+2020,6929,0,0,0,0,20,20,20,2020,2020,40,41,'SZAAAA','NGKAAA','HHHHxx'
+6155,6930,1,3,5,15,55,155,155,1155,6155,110,111,'TCAAAA','OGKAAA','OOOOxx'
+4381,6931,1,1,1,1,81,381,381,4381,4381,162,163,'NMAAAA','PGKAAA','VVVVxx'
+1057,6932,1,1,7,17,57,57,1057,1057,1057,114,115,'ROAAAA','QGKAAA','AAAAxx'
+9010,6933,0,2,0,10,10,10,1010,4010,9010,20,21,'OIAAAA','RGKAAA','HHHHxx'
+4947,6934,1,3,7,7,47,947,947,4947,4947,94,95,'HIAAAA','SGKAAA','OOOOxx'
+335,6935,1,3,5,15,35,335,335,335,335,70,71,'XMAAAA','TGKAAA','VVVVxx'
+6890,6936,0,2,0,10,90,890,890,1890,6890,180,181,'AFAAAA','UGKAAA','AAAAxx'
+5070,6937,0,2,0,10,70,70,1070,70,5070,140,141,'ANAAAA','VGKAAA','HHHHxx'
+5270,6938,0,2,0,10,70,270,1270,270,5270,140,141,'SUAAAA','WGKAAA','OOOOxx'
+8657,6939,1,1,7,17,57,657,657,3657,8657,114,115,'ZUAAAA','XGKAAA','VVVVxx'
+7625,6940,1,1,5,5,25,625,1625,2625,7625,50,51,'HHAAAA','YGKAAA','AAAAxx'
+5759,6941,1,3,9,19,59,759,1759,759,5759,118,119,'NNAAAA','ZGKAAA','HHHHxx'
+9483,6942,1,3,3,3,83,483,1483,4483,9483,166,167,'TAAAAA','AHKAAA','OOOOxx'
+8304,6943,0,0,4,4,4,304,304,3304,8304,8,9,'KHAAAA','BHKAAA','VVVVxx'
+296,6944,0,0,6,16,96,296,296,296,296,192,193,'KLAAAA','CHKAAA','AAAAxx'
+1176,6945,0,0,6,16,76,176,1176,1176,1176,152,153,'GTAAAA','DHKAAA','HHHHxx'
+2069,6946,1,1,9,9,69,69,69,2069,2069,138,139,'PBAAAA','EHKAAA','OOOOxx'
+1531,6947,1,3,1,11,31,531,1531,1531,1531,62,63,'XGAAAA','FHKAAA','VVVVxx'
+5329,6948,1,1,9,9,29,329,1329,329,5329,58,59,'ZWAAAA','GHKAAA','AAAAxx'
+3702,6949,0,2,2,2,2,702,1702,3702,3702,4,5,'KMAAAA','HHKAAA','HHHHxx'
+6520,6950,0,0,0,0,20,520,520,1520,6520,40,41,'UQAAAA','IHKAAA','OOOOxx'
+7310,6951,0,2,0,10,10,310,1310,2310,7310,20,21,'EVAAAA','JHKAAA','VVVVxx'
+1175,6952,1,3,5,15,75,175,1175,1175,1175,150,151,'FTAAAA','KHKAAA','AAAAxx'
+9107,6953,1,3,7,7,7,107,1107,4107,9107,14,15,'HMAAAA','LHKAAA','HHHHxx'
+2737,6954,1,1,7,17,37,737,737,2737,2737,74,75,'HBAAAA','MHKAAA','OOOOxx'
+3437,6955,1,1,7,17,37,437,1437,3437,3437,74,75,'FCAAAA','NHKAAA','VVVVxx'
+281,6956,1,1,1,1,81,281,281,281,281,162,163,'VKAAAA','OHKAAA','AAAAxx'
+6676,6957,0,0,6,16,76,676,676,1676,6676,152,153,'UWAAAA','PHKAAA','HHHHxx'
+145,6958,1,1,5,5,45,145,145,145,145,90,91,'PFAAAA','QHKAAA','OOOOxx'
+3172,6959,0,0,2,12,72,172,1172,3172,3172,144,145,'ASAAAA','RHKAAA','VVVVxx'
+4049,6960,1,1,9,9,49,49,49,4049,4049,98,99,'TZAAAA','SHKAAA','AAAAxx'
+6042,6961,0,2,2,2,42,42,42,1042,6042,84,85,'KYAAAA','THKAAA','HHHHxx'
+9122,6962,0,2,2,2,22,122,1122,4122,9122,44,45,'WMAAAA','UHKAAA','OOOOxx'
+7244,6963,0,0,4,4,44,244,1244,2244,7244,88,89,'QSAAAA','VHKAAA','VVVVxx'
+5361,6964,1,1,1,1,61,361,1361,361,5361,122,123,'FYAAAA','WHKAAA','AAAAxx'
+8647,6965,1,3,7,7,47,647,647,3647,8647,94,95,'PUAAAA','XHKAAA','HHHHxx'
+7956,6966,0,0,6,16,56,956,1956,2956,7956,112,113,'AUAAAA','YHKAAA','OOOOxx'
+7812,6967,0,0,2,12,12,812,1812,2812,7812,24,25,'MOAAAA','ZHKAAA','VVVVxx'
+570,6968,0,2,0,10,70,570,570,570,570,140,141,'YVAAAA','AIKAAA','AAAAxx'
+4115,6969,1,3,5,15,15,115,115,4115,4115,30,31,'HCAAAA','BIKAAA','HHHHxx'
+1856,6970,0,0,6,16,56,856,1856,1856,1856,112,113,'KTAAAA','CIKAAA','OOOOxx'
+9582,6971,0,2,2,2,82,582,1582,4582,9582,164,165,'OEAAAA','DIKAAA','VVVVxx'
+2025,6972,1,1,5,5,25,25,25,2025,2025,50,51,'XZAAAA','EIKAAA','AAAAxx'
+986,6973,0,2,6,6,86,986,986,986,986,172,173,'YLAAAA','FIKAAA','HHHHxx'
+8358,6974,0,2,8,18,58,358,358,3358,8358,116,117,'MJAAAA','GIKAAA','OOOOxx'
+510,6975,0,2,0,10,10,510,510,510,510,20,21,'QTAAAA','HIKAAA','VVVVxx'
+6101,6976,1,1,1,1,1,101,101,1101,6101,2,3,'RAAAAA','IIKAAA','AAAAxx'
+4167,6977,1,3,7,7,67,167,167,4167,4167,134,135,'HEAAAA','JIKAAA','HHHHxx'
+6139,6978,1,3,9,19,39,139,139,1139,6139,78,79,'DCAAAA','KIKAAA','OOOOxx'
+6912,6979,0,0,2,12,12,912,912,1912,6912,24,25,'WFAAAA','LIKAAA','VVVVxx'
+339,6980,1,3,9,19,39,339,339,339,339,78,79,'BNAAAA','MIKAAA','AAAAxx'
+8759,6981,1,3,9,19,59,759,759,3759,8759,118,119,'XYAAAA','NIKAAA','HHHHxx'
+246,6982,0,2,6,6,46,246,246,246,246,92,93,'MJAAAA','OIKAAA','OOOOxx'
+2831,6983,1,3,1,11,31,831,831,2831,2831,62,63,'XEAAAA','PIKAAA','VVVVxx'
+2327,6984,1,3,7,7,27,327,327,2327,2327,54,55,'NLAAAA','QIKAAA','AAAAxx'
+7001,6985,1,1,1,1,1,1,1001,2001,7001,2,3,'HJAAAA','RIKAAA','HHHHxx'
+4398,6986,0,2,8,18,98,398,398,4398,4398,196,197,'ENAAAA','SIKAAA','OOOOxx'
+1495,6987,1,3,5,15,95,495,1495,1495,1495,190,191,'NFAAAA','TIKAAA','VVVVxx'
+8522,6988,0,2,2,2,22,522,522,3522,8522,44,45,'UPAAAA','UIKAAA','AAAAxx'
+7090,6989,0,2,0,10,90,90,1090,2090,7090,180,181,'SMAAAA','VIKAAA','HHHHxx'
+8457,6990,1,1,7,17,57,457,457,3457,8457,114,115,'HNAAAA','WIKAAA','OOOOxx'
+4238,6991,0,2,8,18,38,238,238,4238,4238,76,77,'AHAAAA','XIKAAA','VVVVxx'
+6791,6992,1,3,1,11,91,791,791,1791,6791,182,183,'FBAAAA','YIKAAA','AAAAxx'
+1342,6993,0,2,2,2,42,342,1342,1342,1342,84,85,'QZAAAA','ZIKAAA','HHHHxx'
+4580,6994,0,0,0,0,80,580,580,4580,4580,160,161,'EUAAAA','AJKAAA','OOOOxx'
+1475,6995,1,3,5,15,75,475,1475,1475,1475,150,151,'TEAAAA','BJKAAA','VVVVxx'
+9184,6996,0,0,4,4,84,184,1184,4184,9184,168,169,'GPAAAA','CJKAAA','AAAAxx'
+1189,6997,1,1,9,9,89,189,1189,1189,1189,178,179,'TTAAAA','DJKAAA','HHHHxx'
+638,6998,0,2,8,18,38,638,638,638,638,76,77,'OYAAAA','EJKAAA','OOOOxx'
+5867,6999,1,3,7,7,67,867,1867,867,5867,134,135,'RRAAAA','FJKAAA','VVVVxx'
+9911,7000,1,3,1,11,11,911,1911,4911,9911,22,23,'FRAAAA','GJKAAA','AAAAxx'
+8147,7001,1,3,7,7,47,147,147,3147,8147,94,95,'JBAAAA','HJKAAA','HHHHxx'
+4492,7002,0,0,2,12,92,492,492,4492,4492,184,185,'UQAAAA','IJKAAA','OOOOxx'
+385,7003,1,1,5,5,85,385,385,385,385,170,171,'VOAAAA','JJKAAA','VVVVxx'
+5235,7004,1,3,5,15,35,235,1235,235,5235,70,71,'JTAAAA','KJKAAA','AAAAxx'
+4812,7005,0,0,2,12,12,812,812,4812,4812,24,25,'CDAAAA','LJKAAA','HHHHxx'
+9807,7006,1,3,7,7,7,807,1807,4807,9807,14,15,'FNAAAA','MJKAAA','OOOOxx'
+9588,7007,0,0,8,8,88,588,1588,4588,9588,176,177,'UEAAAA','NJKAAA','VVVVxx'
+9832,7008,0,0,2,12,32,832,1832,4832,9832,64,65,'EOAAAA','OJKAAA','AAAAxx'
+3757,7009,1,1,7,17,57,757,1757,3757,3757,114,115,'NOAAAA','PJKAAA','HHHHxx'
+9703,7010,1,3,3,3,3,703,1703,4703,9703,6,7,'FJAAAA','QJKAAA','OOOOxx'
+1022,7011,0,2,2,2,22,22,1022,1022,1022,44,45,'INAAAA','RJKAAA','VVVVxx'
+5165,7012,1,1,5,5,65,165,1165,165,5165,130,131,'RQAAAA','SJKAAA','AAAAxx'
+7129,7013,1,1,9,9,29,129,1129,2129,7129,58,59,'FOAAAA','TJKAAA','HHHHxx'
+4164,7014,0,0,4,4,64,164,164,4164,4164,128,129,'EEAAAA','UJKAAA','OOOOxx'
+7239,7015,1,3,9,19,39,239,1239,2239,7239,78,79,'LSAAAA','VJKAAA','VVVVxx'
+523,7016,1,3,3,3,23,523,523,523,523,46,47,'DUAAAA','WJKAAA','AAAAxx'
+4670,7017,0,2,0,10,70,670,670,4670,4670,140,141,'QXAAAA','XJKAAA','HHHHxx'
+8503,7018,1,3,3,3,3,503,503,3503,8503,6,7,'BPAAAA','YJKAAA','OOOOxx'
+714,7019,0,2,4,14,14,714,714,714,714,28,29,'MBAAAA','ZJKAAA','VVVVxx'
+1350,7020,0,2,0,10,50,350,1350,1350,1350,100,101,'YZAAAA','AKKAAA','AAAAxx'
+8318,7021,0,2,8,18,18,318,318,3318,8318,36,37,'YHAAAA','BKKAAA','HHHHxx'
+1834,7022,0,2,4,14,34,834,1834,1834,1834,68,69,'OSAAAA','CKKAAA','OOOOxx'
+4306,7023,0,2,6,6,6,306,306,4306,4306,12,13,'QJAAAA','DKKAAA','VVVVxx'
+8543,7024,1,3,3,3,43,543,543,3543,8543,86,87,'PQAAAA','EKKAAA','AAAAxx'
+9397,7025,1,1,7,17,97,397,1397,4397,9397,194,195,'LXAAAA','FKKAAA','HHHHxx'
+3145,7026,1,1,5,5,45,145,1145,3145,3145,90,91,'ZQAAAA','GKKAAA','OOOOxx'
+3942,7027,0,2,2,2,42,942,1942,3942,3942,84,85,'QVAAAA','HKKAAA','VVVVxx'
+8583,7028,1,3,3,3,83,583,583,3583,8583,166,167,'DSAAAA','IKKAAA','AAAAxx'
+8073,7029,1,1,3,13,73,73,73,3073,8073,146,147,'NYAAAA','JKKAAA','HHHHxx'
+4940,7030,0,0,0,0,40,940,940,4940,4940,80,81,'AIAAAA','KKKAAA','OOOOxx'
+9573,7031,1,1,3,13,73,573,1573,4573,9573,146,147,'FEAAAA','LKKAAA','VVVVxx'
+5325,7032,1,1,5,5,25,325,1325,325,5325,50,51,'VWAAAA','MKKAAA','AAAAxx'
+1833,7033,1,1,3,13,33,833,1833,1833,1833,66,67,'NSAAAA','NKKAAA','HHHHxx'
+1337,7034,1,1,7,17,37,337,1337,1337,1337,74,75,'LZAAAA','OKKAAA','OOOOxx'
+9749,7035,1,1,9,9,49,749,1749,4749,9749,98,99,'ZKAAAA','PKKAAA','VVVVxx'
+7505,7036,1,1,5,5,5,505,1505,2505,7505,10,11,'RCAAAA','QKKAAA','AAAAxx'
+9731,7037,1,3,1,11,31,731,1731,4731,9731,62,63,'HKAAAA','RKKAAA','HHHHxx'
+4098,7038,0,2,8,18,98,98,98,4098,4098,196,197,'QBAAAA','SKKAAA','OOOOxx'
+1418,7039,0,2,8,18,18,418,1418,1418,1418,36,37,'OCAAAA','TKKAAA','VVVVxx'
+63,7040,1,3,3,3,63,63,63,63,63,126,127,'LCAAAA','UKKAAA','AAAAxx'
+9889,7041,1,1,9,9,89,889,1889,4889,9889,178,179,'JQAAAA','VKKAAA','HHHHxx'
+2871,7042,1,3,1,11,71,871,871,2871,2871,142,143,'LGAAAA','WKKAAA','OOOOxx'
+1003,7043,1,3,3,3,3,3,1003,1003,1003,6,7,'PMAAAA','XKKAAA','VVVVxx'
+8796,7044,0,0,6,16,96,796,796,3796,8796,192,193,'IAAAAA','YKKAAA','AAAAxx'
+22,7045,0,2,2,2,22,22,22,22,22,44,45,'WAAAAA','ZKKAAA','HHHHxx'
+8244,7046,0,0,4,4,44,244,244,3244,8244,88,89,'CFAAAA','ALKAAA','OOOOxx'
+2282,7047,0,2,2,2,82,282,282,2282,2282,164,165,'UJAAAA','BLKAAA','VVVVxx'
+3487,7048,1,3,7,7,87,487,1487,3487,3487,174,175,'DEAAAA','CLKAAA','AAAAxx'
+8633,7049,1,1,3,13,33,633,633,3633,8633,66,67,'BUAAAA','DLKAAA','HHHHxx'
+6418,7050,0,2,8,18,18,418,418,1418,6418,36,37,'WMAAAA','ELKAAA','OOOOxx'
+4682,7051,0,2,2,2,82,682,682,4682,4682,164,165,'CYAAAA','FLKAAA','VVVVxx'
+4103,7052,1,3,3,3,3,103,103,4103,4103,6,7,'VBAAAA','GLKAAA','AAAAxx'
+6256,7053,0,0,6,16,56,256,256,1256,6256,112,113,'QGAAAA','HLKAAA','HHHHxx'
+4040,7054,0,0,0,0,40,40,40,4040,4040,80,81,'KZAAAA','ILKAAA','OOOOxx'
+9342,7055,0,2,2,2,42,342,1342,4342,9342,84,85,'IVAAAA','JLKAAA','VVVVxx'
+9969,7056,1,1,9,9,69,969,1969,4969,9969,138,139,'LTAAAA','KLKAAA','AAAAxx'
+223,7057,1,3,3,3,23,223,223,223,223,46,47,'PIAAAA','LLKAAA','HHHHxx'
+4593,7058,1,1,3,13,93,593,593,4593,4593,186,187,'RUAAAA','MLKAAA','OOOOxx'
+44,7059,0,0,4,4,44,44,44,44,44,88,89,'SBAAAA','NLKAAA','VVVVxx'
+3513,7060,1,1,3,13,13,513,1513,3513,3513,26,27,'DFAAAA','OLKAAA','AAAAxx'
+5771,7061,1,3,1,11,71,771,1771,771,5771,142,143,'ZNAAAA','PLKAAA','HHHHxx'
+5083,7062,1,3,3,3,83,83,1083,83,5083,166,167,'NNAAAA','QLKAAA','OOOOxx'
+3839,7063,1,3,9,19,39,839,1839,3839,3839,78,79,'RRAAAA','RLKAAA','VVVVxx'
+2986,7064,0,2,6,6,86,986,986,2986,2986,172,173,'WKAAAA','SLKAAA','AAAAxx'
+2200,7065,0,0,0,0,0,200,200,2200,2200,0,1,'QGAAAA','TLKAAA','HHHHxx'
+197,7066,1,1,7,17,97,197,197,197,197,194,195,'PHAAAA','ULKAAA','OOOOxx'
+7455,7067,1,3,5,15,55,455,1455,2455,7455,110,111,'TAAAAA','VLKAAA','VVVVxx'
+1379,7068,1,3,9,19,79,379,1379,1379,1379,158,159,'BBAAAA','WLKAAA','AAAAxx'
+4356,7069,0,0,6,16,56,356,356,4356,4356,112,113,'OLAAAA','XLKAAA','HHHHxx'
+6888,7070,0,0,8,8,88,888,888,1888,6888,176,177,'YEAAAA','YLKAAA','OOOOxx'
+9139,7071,1,3,9,19,39,139,1139,4139,9139,78,79,'NNAAAA','ZLKAAA','VVVVxx'
+7682,7072,0,2,2,2,82,682,1682,2682,7682,164,165,'MJAAAA','AMKAAA','AAAAxx'
+4873,7073,1,1,3,13,73,873,873,4873,4873,146,147,'LFAAAA','BMKAAA','HHHHxx'
+783,7074,1,3,3,3,83,783,783,783,783,166,167,'DEAAAA','CMKAAA','OOOOxx'
+6071,7075,1,3,1,11,71,71,71,1071,6071,142,143,'NZAAAA','DMKAAA','VVVVxx'
+5160,7076,0,0,0,0,60,160,1160,160,5160,120,121,'MQAAAA','EMKAAA','AAAAxx'
+2291,7077,1,3,1,11,91,291,291,2291,2291,182,183,'DKAAAA','FMKAAA','HHHHxx'
+187,7078,1,3,7,7,87,187,187,187,187,174,175,'FHAAAA','GMKAAA','OOOOxx'
+7786,7079,0,2,6,6,86,786,1786,2786,7786,172,173,'MNAAAA','HMKAAA','VVVVxx'
+3432,7080,0,0,2,12,32,432,1432,3432,3432,64,65,'ACAAAA','IMKAAA','AAAAxx'
+5450,7081,0,2,0,10,50,450,1450,450,5450,100,101,'QBAAAA','JMKAAA','HHHHxx'
+2699,7082,1,3,9,19,99,699,699,2699,2699,198,199,'VZAAAA','KMKAAA','OOOOxx'
+692,7083,0,0,2,12,92,692,692,692,692,184,185,'QAAAAA','LMKAAA','VVVVxx'
+6081,7084,1,1,1,1,81,81,81,1081,6081,162,163,'XZAAAA','MMKAAA','AAAAxx'
+4829,7085,1,1,9,9,29,829,829,4829,4829,58,59,'TDAAAA','NMKAAA','HHHHxx'
+238,7086,0,2,8,18,38,238,238,238,238,76,77,'EJAAAA','OMKAAA','OOOOxx'
+9100,7087,0,0,0,0,0,100,1100,4100,9100,0,1,'AMAAAA','PMKAAA','VVVVxx'
+1968,7088,0,0,8,8,68,968,1968,1968,1968,136,137,'SXAAAA','QMKAAA','AAAAxx'
+1872,7089,0,0,2,12,72,872,1872,1872,1872,144,145,'AUAAAA','RMKAAA','HHHHxx'
+7051,7090,1,3,1,11,51,51,1051,2051,7051,102,103,'FLAAAA','SMKAAA','OOOOxx'
+2743,7091,1,3,3,3,43,743,743,2743,2743,86,87,'NBAAAA','TMKAAA','VVVVxx'
+1237,7092,1,1,7,17,37,237,1237,1237,1237,74,75,'PVAAAA','UMKAAA','AAAAxx'
+3052,7093,0,0,2,12,52,52,1052,3052,3052,104,105,'KNAAAA','VMKAAA','HHHHxx'
+8021,7094,1,1,1,1,21,21,21,3021,8021,42,43,'NWAAAA','WMKAAA','OOOOxx'
+657,7095,1,1,7,17,57,657,657,657,657,114,115,'HZAAAA','XMKAAA','VVVVxx'
+2236,7096,0,0,6,16,36,236,236,2236,2236,72,73,'AIAAAA','YMKAAA','AAAAxx'
+7011,7097,1,3,1,11,11,11,1011,2011,7011,22,23,'RJAAAA','ZMKAAA','HHHHxx'
+4067,7098,1,3,7,7,67,67,67,4067,4067,134,135,'LAAAAA','ANKAAA','OOOOxx'
+9449,7099,1,1,9,9,49,449,1449,4449,9449,98,99,'LZAAAA','BNKAAA','VVVVxx'
+7428,7100,0,0,8,8,28,428,1428,2428,7428,56,57,'SZAAAA','CNKAAA','AAAAxx'
+1272,7101,0,0,2,12,72,272,1272,1272,1272,144,145,'YWAAAA','DNKAAA','HHHHxx'
+6897,7102,1,1,7,17,97,897,897,1897,6897,194,195,'HFAAAA','ENKAAA','OOOOxx'
+5839,7103,1,3,9,19,39,839,1839,839,5839,78,79,'PQAAAA','FNKAAA','VVVVxx'
+6835,7104,1,3,5,15,35,835,835,1835,6835,70,71,'XCAAAA','GNKAAA','AAAAxx'
+1887,7105,1,3,7,7,87,887,1887,1887,1887,174,175,'PUAAAA','HNKAAA','HHHHxx'
+1551,7106,1,3,1,11,51,551,1551,1551,1551,102,103,'RHAAAA','INKAAA','OOOOxx'
+4667,7107,1,3,7,7,67,667,667,4667,4667,134,135,'NXAAAA','JNKAAA','VVVVxx'
+9603,7108,1,3,3,3,3,603,1603,4603,9603,6,7,'JFAAAA','KNKAAA','AAAAxx'
+4332,7109,0,0,2,12,32,332,332,4332,4332,64,65,'QKAAAA','LNKAAA','HHHHxx'
+5681,7110,1,1,1,1,81,681,1681,681,5681,162,163,'NKAAAA','MNKAAA','OOOOxx'
+8062,7111,0,2,2,2,62,62,62,3062,8062,124,125,'CYAAAA','NNKAAA','VVVVxx'
+2302,7112,0,2,2,2,2,302,302,2302,2302,4,5,'OKAAAA','ONKAAA','AAAAxx'
+2825,7113,1,1,5,5,25,825,825,2825,2825,50,51,'REAAAA','PNKAAA','HHHHxx'
+4527,7114,1,3,7,7,27,527,527,4527,4527,54,55,'DSAAAA','QNKAAA','OOOOxx'
+4230,7115,0,2,0,10,30,230,230,4230,4230,60,61,'SGAAAA','RNKAAA','VVVVxx'
+3053,7116,1,1,3,13,53,53,1053,3053,3053,106,107,'LNAAAA','SNKAAA','AAAAxx'
+983,7117,1,3,3,3,83,983,983,983,983,166,167,'VLAAAA','TNKAAA','HHHHxx'
+9458,7118,0,2,8,18,58,458,1458,4458,9458,116,117,'UZAAAA','UNKAAA','OOOOxx'
+4128,7119,0,0,8,8,28,128,128,4128,4128,56,57,'UCAAAA','VNKAAA','VVVVxx'
+425,7120,1,1,5,5,25,425,425,425,425,50,51,'JQAAAA','WNKAAA','AAAAxx'
+3911,7121,1,3,1,11,11,911,1911,3911,3911,22,23,'LUAAAA','XNKAAA','HHHHxx'
+6607,7122,1,3,7,7,7,607,607,1607,6607,14,15,'DUAAAA','YNKAAA','OOOOxx'
+5431,7123,1,3,1,11,31,431,1431,431,5431,62,63,'XAAAAA','ZNKAAA','VVVVxx'
+6330,7124,0,2,0,10,30,330,330,1330,6330,60,61,'MJAAAA','AOKAAA','AAAAxx'
+3592,7125,0,0,2,12,92,592,1592,3592,3592,184,185,'EIAAAA','BOKAAA','HHHHxx'
+154,7126,0,2,4,14,54,154,154,154,154,108,109,'YFAAAA','COKAAA','OOOOxx'
+9879,7127,1,3,9,19,79,879,1879,4879,9879,158,159,'ZPAAAA','DOKAAA','VVVVxx'
+3202,7128,0,2,2,2,2,202,1202,3202,3202,4,5,'ETAAAA','EOKAAA','AAAAxx'
+3056,7129,0,0,6,16,56,56,1056,3056,3056,112,113,'ONAAAA','FOKAAA','HHHHxx'
+9890,7130,0,2,0,10,90,890,1890,4890,9890,180,181,'KQAAAA','GOKAAA','OOOOxx'
+5840,7131,0,0,0,0,40,840,1840,840,5840,80,81,'QQAAAA','HOKAAA','VVVVxx'
+9804,7132,0,0,4,4,4,804,1804,4804,9804,8,9,'CNAAAA','IOKAAA','AAAAxx'
+681,7133,1,1,1,1,81,681,681,681,681,162,163,'FAAAAA','JOKAAA','HHHHxx'
+3443,7134,1,3,3,3,43,443,1443,3443,3443,86,87,'LCAAAA','KOKAAA','OOOOxx'
+8088,7135,0,0,8,8,88,88,88,3088,8088,176,177,'CZAAAA','LOKAAA','VVVVxx'
+9447,7136,1,3,7,7,47,447,1447,4447,9447,94,95,'JZAAAA','MOKAAA','AAAAxx'
+1490,7137,0,2,0,10,90,490,1490,1490,1490,180,181,'IFAAAA','NOKAAA','HHHHxx'
+3684,7138,0,0,4,4,84,684,1684,3684,3684,168,169,'SLAAAA','OOKAAA','OOOOxx'
+3113,7139,1,1,3,13,13,113,1113,3113,3113,26,27,'TPAAAA','POKAAA','VVVVxx'
+9004,7140,0,0,4,4,4,4,1004,4004,9004,8,9,'IIAAAA','QOKAAA','AAAAxx'
+7147,7141,1,3,7,7,47,147,1147,2147,7147,94,95,'XOAAAA','ROKAAA','HHHHxx'
+7571,7142,1,3,1,11,71,571,1571,2571,7571,142,143,'FFAAAA','SOKAAA','OOOOxx'
+5545,7143,1,1,5,5,45,545,1545,545,5545,90,91,'HFAAAA','TOKAAA','VVVVxx'
+4558,7144,0,2,8,18,58,558,558,4558,4558,116,117,'ITAAAA','UOKAAA','AAAAxx'
+6206,7145,0,2,6,6,6,206,206,1206,6206,12,13,'SEAAAA','VOKAAA','HHHHxx'
+5695,7146,1,3,5,15,95,695,1695,695,5695,190,191,'BLAAAA','WOKAAA','OOOOxx'
+9600,7147,0,0,0,0,0,600,1600,4600,9600,0,1,'GFAAAA','XOKAAA','VVVVxx'
+5432,7148,0,0,2,12,32,432,1432,432,5432,64,65,'YAAAAA','YOKAAA','AAAAxx'
+9299,7149,1,3,9,19,99,299,1299,4299,9299,198,199,'RTAAAA','ZOKAAA','HHHHxx'
+2386,7150,0,2,6,6,86,386,386,2386,2386,172,173,'UNAAAA','APKAAA','OOOOxx'
+2046,7151,0,2,6,6,46,46,46,2046,2046,92,93,'SAAAAA','BPKAAA','VVVVxx'
+3293,7152,1,1,3,13,93,293,1293,3293,3293,186,187,'RWAAAA','CPKAAA','AAAAxx'
+3046,7153,0,2,6,6,46,46,1046,3046,3046,92,93,'ENAAAA','DPKAAA','HHHHxx'
+214,7154,0,2,4,14,14,214,214,214,214,28,29,'GIAAAA','EPKAAA','OOOOxx'
+7893,7155,1,1,3,13,93,893,1893,2893,7893,186,187,'PRAAAA','FPKAAA','VVVVxx'
+891,7156,1,3,1,11,91,891,891,891,891,182,183,'HIAAAA','GPKAAA','AAAAxx'
+6499,7157,1,3,9,19,99,499,499,1499,6499,198,199,'ZPAAAA','HPKAAA','HHHHxx'
+5003,7158,1,3,3,3,3,3,1003,3,5003,6,7,'LKAAAA','IPKAAA','OOOOxx'
+6487,7159,1,3,7,7,87,487,487,1487,6487,174,175,'NPAAAA','JPKAAA','VVVVxx'
+9403,7160,1,3,3,3,3,403,1403,4403,9403,6,7,'RXAAAA','KPKAAA','AAAAxx'
+945,7161,1,1,5,5,45,945,945,945,945,90,91,'JKAAAA','LPKAAA','HHHHxx'
+6713,7162,1,1,3,13,13,713,713,1713,6713,26,27,'FYAAAA','MPKAAA','OOOOxx'
+9928,7163,0,0,8,8,28,928,1928,4928,9928,56,57,'WRAAAA','NPKAAA','VVVVxx'
+8585,7164,1,1,5,5,85,585,585,3585,8585,170,171,'FSAAAA','OPKAAA','AAAAxx'
+4004,7165,0,0,4,4,4,4,4,4004,4004,8,9,'AYAAAA','PPKAAA','HHHHxx'
+2528,7166,0,0,8,8,28,528,528,2528,2528,56,57,'GTAAAA','QPKAAA','OOOOxx'
+3350,7167,0,2,0,10,50,350,1350,3350,3350,100,101,'WYAAAA','RPKAAA','VVVVxx'
+2160,7168,0,0,0,0,60,160,160,2160,2160,120,121,'CFAAAA','SPKAAA','AAAAxx'
+1521,7169,1,1,1,1,21,521,1521,1521,1521,42,43,'NGAAAA','TPKAAA','HHHHxx'
+5660,7170,0,0,0,0,60,660,1660,660,5660,120,121,'SJAAAA','UPKAAA','OOOOxx'
+5755,7171,1,3,5,15,55,755,1755,755,5755,110,111,'JNAAAA','VPKAAA','VVVVxx'
+7614,7172,0,2,4,14,14,614,1614,2614,7614,28,29,'WGAAAA','WPKAAA','AAAAxx'
+3121,7173,1,1,1,1,21,121,1121,3121,3121,42,43,'BQAAAA','XPKAAA','HHHHxx'
+2735,7174,1,3,5,15,35,735,735,2735,2735,70,71,'FBAAAA','YPKAAA','OOOOxx'
+7506,7175,0,2,6,6,6,506,1506,2506,7506,12,13,'SCAAAA','ZPKAAA','VVVVxx'
+2693,7176,1,1,3,13,93,693,693,2693,2693,186,187,'PZAAAA','AQKAAA','AAAAxx'
+2892,7177,0,0,2,12,92,892,892,2892,2892,184,185,'GHAAAA','BQKAAA','HHHHxx'
+3310,7178,0,2,0,10,10,310,1310,3310,3310,20,21,'IXAAAA','CQKAAA','OOOOxx'
+3484,7179,0,0,4,4,84,484,1484,3484,3484,168,169,'AEAAAA','DQKAAA','VVVVxx'
+9733,7180,1,1,3,13,33,733,1733,4733,9733,66,67,'JKAAAA','EQKAAA','AAAAxx'
+29,7181,1,1,9,9,29,29,29,29,29,58,59,'DBAAAA','FQKAAA','HHHHxx'
+9013,7182,1,1,3,13,13,13,1013,4013,9013,26,27,'RIAAAA','GQKAAA','OOOOxx'
+3847,7183,1,3,7,7,47,847,1847,3847,3847,94,95,'ZRAAAA','HQKAAA','VVVVxx'
+6724,7184,0,0,4,4,24,724,724,1724,6724,48,49,'QYAAAA','IQKAAA','AAAAxx'
+2559,7185,1,3,9,19,59,559,559,2559,2559,118,119,'LUAAAA','JQKAAA','HHHHxx'
+5326,7186,0,2,6,6,26,326,1326,326,5326,52,53,'WWAAAA','KQKAAA','OOOOxx'
+4802,7187,0,2,2,2,2,802,802,4802,4802,4,5,'SCAAAA','LQKAAA','VVVVxx'
+131,7188,1,3,1,11,31,131,131,131,131,62,63,'BFAAAA','MQKAAA','AAAAxx'
+1634,7189,0,2,4,14,34,634,1634,1634,1634,68,69,'WKAAAA','NQKAAA','HHHHxx'
+919,7190,1,3,9,19,19,919,919,919,919,38,39,'JJAAAA','OQKAAA','OOOOxx'
+9575,7191,1,3,5,15,75,575,1575,4575,9575,150,151,'HEAAAA','PQKAAA','VVVVxx'
+1256,7192,0,0,6,16,56,256,1256,1256,1256,112,113,'IWAAAA','QQKAAA','AAAAxx'
+9428,7193,0,0,8,8,28,428,1428,4428,9428,56,57,'QYAAAA','RQKAAA','HHHHxx'
+5121,7194,1,1,1,1,21,121,1121,121,5121,42,43,'ZOAAAA','SQKAAA','OOOOxx'
+6584,7195,0,0,4,4,84,584,584,1584,6584,168,169,'GTAAAA','TQKAAA','VVVVxx'
+7193,7196,1,1,3,13,93,193,1193,2193,7193,186,187,'RQAAAA','UQKAAA','AAAAxx'
+4047,7197,1,3,7,7,47,47,47,4047,4047,94,95,'RZAAAA','VQKAAA','HHHHxx'
+104,7198,0,0,4,4,4,104,104,104,104,8,9,'AEAAAA','WQKAAA','OOOOxx'
+1527,7199,1,3,7,7,27,527,1527,1527,1527,54,55,'TGAAAA','XQKAAA','VVVVxx'
+3460,7200,0,0,0,0,60,460,1460,3460,3460,120,121,'CDAAAA','YQKAAA','AAAAxx'
+8526,7201,0,2,6,6,26,526,526,3526,8526,52,53,'YPAAAA','ZQKAAA','HHHHxx'
+8959,7202,1,3,9,19,59,959,959,3959,8959,118,119,'PGAAAA','ARKAAA','OOOOxx'
+3633,7203,1,1,3,13,33,633,1633,3633,3633,66,67,'TJAAAA','BRKAAA','VVVVxx'
+1799,7204,1,3,9,19,99,799,1799,1799,1799,198,199,'FRAAAA','CRKAAA','AAAAxx'
+461,7205,1,1,1,1,61,461,461,461,461,122,123,'TRAAAA','DRKAAA','HHHHxx'
+718,7206,0,2,8,18,18,718,718,718,718,36,37,'QBAAAA','ERKAAA','OOOOxx'
+3219,7207,1,3,9,19,19,219,1219,3219,3219,38,39,'VTAAAA','FRKAAA','VVVVxx'
+3494,7208,0,2,4,14,94,494,1494,3494,3494,188,189,'KEAAAA','GRKAAA','AAAAxx'
+9402,7209,0,2,2,2,2,402,1402,4402,9402,4,5,'QXAAAA','HRKAAA','HHHHxx'
+7983,7210,1,3,3,3,83,983,1983,2983,7983,166,167,'BVAAAA','IRKAAA','OOOOxx'
+7919,7211,1,3,9,19,19,919,1919,2919,7919,38,39,'PSAAAA','JRKAAA','VVVVxx'
+8036,7212,0,0,6,16,36,36,36,3036,8036,72,73,'CXAAAA','KRKAAA','AAAAxx'
+5164,7213,0,0,4,4,64,164,1164,164,5164,128,129,'QQAAAA','LRKAAA','HHHHxx'
+4160,7214,0,0,0,0,60,160,160,4160,4160,120,121,'AEAAAA','MRKAAA','OOOOxx'
+5370,7215,0,2,0,10,70,370,1370,370,5370,140,141,'OYAAAA','NRKAAA','VVVVxx'
+5347,7216,1,3,7,7,47,347,1347,347,5347,94,95,'RXAAAA','ORKAAA','AAAAxx'
+7109,7217,1,1,9,9,9,109,1109,2109,7109,18,19,'LNAAAA','PRKAAA','HHHHxx'
+4826,7218,0,2,6,6,26,826,826,4826,4826,52,53,'QDAAAA','QRKAAA','OOOOxx'
+1338,7219,0,2,8,18,38,338,1338,1338,1338,76,77,'MZAAAA','RRKAAA','VVVVxx'
+2711,7220,1,3,1,11,11,711,711,2711,2711,22,23,'HAAAAA','SRKAAA','AAAAxx'
+6299,7221,1,3,9,19,99,299,299,1299,6299,198,199,'HIAAAA','TRKAAA','HHHHxx'
+1616,7222,0,0,6,16,16,616,1616,1616,1616,32,33,'EKAAAA','URKAAA','OOOOxx'
+7519,7223,1,3,9,19,19,519,1519,2519,7519,38,39,'FDAAAA','VRKAAA','VVVVxx'
+1262,7224,0,2,2,2,62,262,1262,1262,1262,124,125,'OWAAAA','WRKAAA','AAAAxx'
+7228,7225,0,0,8,8,28,228,1228,2228,7228,56,57,'ASAAAA','XRKAAA','HHHHxx'
+7892,7226,0,0,2,12,92,892,1892,2892,7892,184,185,'ORAAAA','YRKAAA','OOOOxx'
+7929,7227,1,1,9,9,29,929,1929,2929,7929,58,59,'ZSAAAA','ZRKAAA','VVVVxx'
+7705,7228,1,1,5,5,5,705,1705,2705,7705,10,11,'JKAAAA','ASKAAA','AAAAxx'
+3111,7229,1,3,1,11,11,111,1111,3111,3111,22,23,'RPAAAA','BSKAAA','HHHHxx'
+3066,7230,0,2,6,6,66,66,1066,3066,3066,132,133,'YNAAAA','CSKAAA','OOOOxx'
+9559,7231,1,3,9,19,59,559,1559,4559,9559,118,119,'RDAAAA','DSKAAA','VVVVxx'
+3787,7232,1,3,7,7,87,787,1787,3787,3787,174,175,'RPAAAA','ESKAAA','AAAAxx'
+8710,7233,0,2,0,10,10,710,710,3710,8710,20,21,'AXAAAA','FSKAAA','HHHHxx'
+4870,7234,0,2,0,10,70,870,870,4870,4870,140,141,'IFAAAA','GSKAAA','OOOOxx'
+1883,7235,1,3,3,3,83,883,1883,1883,1883,166,167,'LUAAAA','HSKAAA','VVVVxx'
+9689,7236,1,1,9,9,89,689,1689,4689,9689,178,179,'RIAAAA','ISKAAA','AAAAxx'
+9491,7237,1,3,1,11,91,491,1491,4491,9491,182,183,'BBAAAA','JSKAAA','HHHHxx'
+2035,7238,1,3,5,15,35,35,35,2035,2035,70,71,'HAAAAA','KSKAAA','OOOOxx'
+655,7239,1,3,5,15,55,655,655,655,655,110,111,'FZAAAA','LSKAAA','VVVVxx'
+6305,7240,1,1,5,5,5,305,305,1305,6305,10,11,'NIAAAA','MSKAAA','AAAAxx'
+9423,7241,1,3,3,3,23,423,1423,4423,9423,46,47,'LYAAAA','NSKAAA','HHHHxx'
+283,7242,1,3,3,3,83,283,283,283,283,166,167,'XKAAAA','OSKAAA','OOOOxx'
+2607,7243,1,3,7,7,7,607,607,2607,2607,14,15,'HWAAAA','PSKAAA','VVVVxx'
+7740,7244,0,0,0,0,40,740,1740,2740,7740,80,81,'SLAAAA','QSKAAA','AAAAxx'
+6956,7245,0,0,6,16,56,956,956,1956,6956,112,113,'OHAAAA','RSKAAA','HHHHxx'
+884,7246,0,0,4,4,84,884,884,884,884,168,169,'AIAAAA','SSKAAA','OOOOxx'
+5730,7247,0,2,0,10,30,730,1730,730,5730,60,61,'KMAAAA','TSKAAA','VVVVxx'
+3438,7248,0,2,8,18,38,438,1438,3438,3438,76,77,'GCAAAA','USKAAA','AAAAxx'
+3250,7249,0,2,0,10,50,250,1250,3250,3250,100,101,'AVAAAA','VSKAAA','HHHHxx'
+5470,7250,0,2,0,10,70,470,1470,470,5470,140,141,'KCAAAA','WSKAAA','OOOOxx'
+2037,7251,1,1,7,17,37,37,37,2037,2037,74,75,'JAAAAA','XSKAAA','VVVVxx'
+6593,7252,1,1,3,13,93,593,593,1593,6593,186,187,'PTAAAA','YSKAAA','AAAAxx'
+3893,7253,1,1,3,13,93,893,1893,3893,3893,186,187,'TTAAAA','ZSKAAA','HHHHxx'
+3200,7254,0,0,0,0,0,200,1200,3200,3200,0,1,'CTAAAA','ATKAAA','OOOOxx'
+7125,7255,1,1,5,5,25,125,1125,2125,7125,50,51,'BOAAAA','BTKAAA','VVVVxx'
+2295,7256,1,3,5,15,95,295,295,2295,2295,190,191,'HKAAAA','CTKAAA','AAAAxx'
+2056,7257,0,0,6,16,56,56,56,2056,2056,112,113,'CBAAAA','DTKAAA','HHHHxx'
+2962,7258,0,2,2,2,62,962,962,2962,2962,124,125,'YJAAAA','ETKAAA','OOOOxx'
+993,7259,1,1,3,13,93,993,993,993,993,186,187,'FMAAAA','FTKAAA','VVVVxx'
+9127,7260,1,3,7,7,27,127,1127,4127,9127,54,55,'BNAAAA','GTKAAA','AAAAxx'
+2075,7261,1,3,5,15,75,75,75,2075,2075,150,151,'VBAAAA','HTKAAA','HHHHxx'
+9338,7262,0,2,8,18,38,338,1338,4338,9338,76,77,'EVAAAA','ITKAAA','OOOOxx'
+8100,7263,0,0,0,0,0,100,100,3100,8100,0,1,'OZAAAA','JTKAAA','VVVVxx'
+5047,7264,1,3,7,7,47,47,1047,47,5047,94,95,'DMAAAA','KTKAAA','AAAAxx'
+7032,7265,0,0,2,12,32,32,1032,2032,7032,64,65,'MKAAAA','LTKAAA','HHHHxx'
+6374,7266,0,2,4,14,74,374,374,1374,6374,148,149,'ELAAAA','MTKAAA','OOOOxx'
+4137,7267,1,1,7,17,37,137,137,4137,4137,74,75,'DDAAAA','NTKAAA','VVVVxx'
+7132,7268,0,0,2,12,32,132,1132,2132,7132,64,65,'IOAAAA','OTKAAA','AAAAxx'
+3064,7269,0,0,4,4,64,64,1064,3064,3064,128,129,'WNAAAA','PTKAAA','HHHHxx'
+3621,7270,1,1,1,1,21,621,1621,3621,3621,42,43,'HJAAAA','QTKAAA','OOOOxx'
+6199,7271,1,3,9,19,99,199,199,1199,6199,198,199,'LEAAAA','RTKAAA','VVVVxx'
+4926,7272,0,2,6,6,26,926,926,4926,4926,52,53,'MHAAAA','STKAAA','AAAAxx'
+8035,7273,1,3,5,15,35,35,35,3035,8035,70,71,'BXAAAA','TTKAAA','HHHHxx'
+2195,7274,1,3,5,15,95,195,195,2195,2195,190,191,'LGAAAA','UTKAAA','OOOOxx'
+5366,7275,0,2,6,6,66,366,1366,366,5366,132,133,'KYAAAA','VTKAAA','VVVVxx'
+3478,7276,0,2,8,18,78,478,1478,3478,3478,156,157,'UDAAAA','WTKAAA','AAAAxx'
+1926,7277,0,2,6,6,26,926,1926,1926,1926,52,53,'CWAAAA','XTKAAA','HHHHxx'
+7265,7278,1,1,5,5,65,265,1265,2265,7265,130,131,'LTAAAA','YTKAAA','OOOOxx'
+7668,7279,0,0,8,8,68,668,1668,2668,7668,136,137,'YIAAAA','ZTKAAA','VVVVxx'
+3335,7280,1,3,5,15,35,335,1335,3335,3335,70,71,'HYAAAA','AUKAAA','AAAAxx'
+7660,7281,0,0,0,0,60,660,1660,2660,7660,120,121,'QIAAAA','BUKAAA','HHHHxx'
+9604,7282,0,0,4,4,4,604,1604,4604,9604,8,9,'KFAAAA','CUKAAA','OOOOxx'
+7301,7283,1,1,1,1,1,301,1301,2301,7301,2,3,'VUAAAA','DUKAAA','VVVVxx'
+4475,7284,1,3,5,15,75,475,475,4475,4475,150,151,'DQAAAA','EUKAAA','AAAAxx'
+9954,7285,0,2,4,14,54,954,1954,4954,9954,108,109,'WSAAAA','FUKAAA','HHHHxx'
+5723,7286,1,3,3,3,23,723,1723,723,5723,46,47,'DMAAAA','GUKAAA','OOOOxx'
+2669,7287,1,1,9,9,69,669,669,2669,2669,138,139,'RYAAAA','HUKAAA','VVVVxx'
+1685,7288,1,1,5,5,85,685,1685,1685,1685,170,171,'VMAAAA','IUKAAA','AAAAxx'
+2233,7289,1,1,3,13,33,233,233,2233,2233,66,67,'XHAAAA','JUKAAA','HHHHxx'
+8111,7290,1,3,1,11,11,111,111,3111,8111,22,23,'ZZAAAA','KUKAAA','OOOOxx'
+7685,7291,1,1,5,5,85,685,1685,2685,7685,170,171,'PJAAAA','LUKAAA','VVVVxx'
+3773,7292,1,1,3,13,73,773,1773,3773,3773,146,147,'DPAAAA','MUKAAA','AAAAxx'
+7172,7293,0,0,2,12,72,172,1172,2172,7172,144,145,'WPAAAA','NUKAAA','HHHHxx'
+1740,7294,0,0,0,0,40,740,1740,1740,1740,80,81,'YOAAAA','OUKAAA','OOOOxx'
+5416,7295,0,0,6,16,16,416,1416,416,5416,32,33,'IAAAAA','PUKAAA','VVVVxx'
+1823,7296,1,3,3,3,23,823,1823,1823,1823,46,47,'DSAAAA','QUKAAA','AAAAxx'
+1668,7297,0,0,8,8,68,668,1668,1668,1668,136,137,'EMAAAA','RUKAAA','HHHHxx'
+1795,7298,1,3,5,15,95,795,1795,1795,1795,190,191,'BRAAAA','SUKAAA','OOOOxx'
+8599,7299,1,3,9,19,99,599,599,3599,8599,198,199,'TSAAAA','TUKAAA','VVVVxx'
+5542,7300,0,2,2,2,42,542,1542,542,5542,84,85,'EFAAAA','UUKAAA','AAAAxx'
+5658,7301,0,2,8,18,58,658,1658,658,5658,116,117,'QJAAAA','VUKAAA','HHHHxx'
+9824,7302,0,0,4,4,24,824,1824,4824,9824,48,49,'WNAAAA','WUKAAA','OOOOxx'
+19,7303,1,3,9,19,19,19,19,19,19,38,39,'TAAAAA','XUKAAA','VVVVxx'
+9344,7304,0,0,4,4,44,344,1344,4344,9344,88,89,'KVAAAA','YUKAAA','AAAAxx'
+5900,7305,0,0,0,0,0,900,1900,900,5900,0,1,'YSAAAA','ZUKAAA','HHHHxx'
+7818,7306,0,2,8,18,18,818,1818,2818,7818,36,37,'SOAAAA','AVKAAA','OOOOxx'
+8377,7307,1,1,7,17,77,377,377,3377,8377,154,155,'FKAAAA','BVKAAA','VVVVxx'
+6886,7308,0,2,6,6,86,886,886,1886,6886,172,173,'WEAAAA','CVKAAA','AAAAxx'
+3201,7309,1,1,1,1,1,201,1201,3201,3201,2,3,'DTAAAA','DVKAAA','HHHHxx'
+87,7310,1,3,7,7,87,87,87,87,87,174,175,'JDAAAA','EVKAAA','OOOOxx'
+1089,7311,1,1,9,9,89,89,1089,1089,1089,178,179,'XPAAAA','FVKAAA','VVVVxx'
+3948,7312,0,0,8,8,48,948,1948,3948,3948,96,97,'WVAAAA','GVKAAA','AAAAxx'
+6383,7313,1,3,3,3,83,383,383,1383,6383,166,167,'NLAAAA','HVKAAA','HHHHxx'
+837,7314,1,1,7,17,37,837,837,837,837,74,75,'FGAAAA','IVKAAA','OOOOxx'
+6285,7315,1,1,5,5,85,285,285,1285,6285,170,171,'THAAAA','JVKAAA','VVVVxx'
+78,7316,0,2,8,18,78,78,78,78,78,156,157,'ADAAAA','KVKAAA','AAAAxx'
+4389,7317,1,1,9,9,89,389,389,4389,4389,178,179,'VMAAAA','LVKAAA','HHHHxx'
+4795,7318,1,3,5,15,95,795,795,4795,4795,190,191,'LCAAAA','MVKAAA','OOOOxx'
+9369,7319,1,1,9,9,69,369,1369,4369,9369,138,139,'JWAAAA','NVKAAA','VVVVxx'
+69,7320,1,1,9,9,69,69,69,69,69,138,139,'RCAAAA','OVKAAA','AAAAxx'
+7689,7321,1,1,9,9,89,689,1689,2689,7689,178,179,'TJAAAA','PVKAAA','HHHHxx'
+5642,7322,0,2,2,2,42,642,1642,642,5642,84,85,'AJAAAA','QVKAAA','OOOOxx'
+2348,7323,0,0,8,8,48,348,348,2348,2348,96,97,'IMAAAA','RVKAAA','VVVVxx'
+9308,7324,0,0,8,8,8,308,1308,4308,9308,16,17,'AUAAAA','SVKAAA','AAAAxx'
+9093,7325,1,1,3,13,93,93,1093,4093,9093,186,187,'TLAAAA','TVKAAA','HHHHxx'
+1199,7326,1,3,9,19,99,199,1199,1199,1199,198,199,'DUAAAA','UVKAAA','OOOOxx'
+307,7327,1,3,7,7,7,307,307,307,307,14,15,'VLAAAA','VVKAAA','VVVVxx'
+3814,7328,0,2,4,14,14,814,1814,3814,3814,28,29,'SQAAAA','WVKAAA','AAAAxx'
+8817,7329,1,1,7,17,17,817,817,3817,8817,34,35,'DBAAAA','XVKAAA','HHHHxx'
+2329,7330,1,1,9,9,29,329,329,2329,2329,58,59,'PLAAAA','YVKAAA','OOOOxx'
+2932,7331,0,0,2,12,32,932,932,2932,2932,64,65,'UIAAAA','ZVKAAA','VVVVxx'
+1986,7332,0,2,6,6,86,986,1986,1986,1986,172,173,'KYAAAA','AWKAAA','AAAAxx'
+5279,7333,1,3,9,19,79,279,1279,279,5279,158,159,'BVAAAA','BWKAAA','HHHHxx'
+5357,7334,1,1,7,17,57,357,1357,357,5357,114,115,'BYAAAA','CWKAAA','OOOOxx'
+6778,7335,0,2,8,18,78,778,778,1778,6778,156,157,'SAAAAA','DWKAAA','VVVVxx'
+2773,7336,1,1,3,13,73,773,773,2773,2773,146,147,'RCAAAA','EWKAAA','AAAAxx'
+244,7337,0,0,4,4,44,244,244,244,244,88,89,'KJAAAA','FWKAAA','HHHHxx'
+6900,7338,0,0,0,0,0,900,900,1900,6900,0,1,'KFAAAA','GWKAAA','OOOOxx'
+4739,7339,1,3,9,19,39,739,739,4739,4739,78,79,'HAAAAA','HWKAAA','VVVVxx'
+3217,7340,1,1,7,17,17,217,1217,3217,3217,34,35,'TTAAAA','IWKAAA','AAAAxx'
+7563,7341,1,3,3,3,63,563,1563,2563,7563,126,127,'XEAAAA','JWKAAA','HHHHxx'
+1807,7342,1,3,7,7,7,807,1807,1807,1807,14,15,'NRAAAA','KWKAAA','OOOOxx'
+4199,7343,1,3,9,19,99,199,199,4199,4199,198,199,'NFAAAA','LWKAAA','VVVVxx'
+1077,7344,1,1,7,17,77,77,1077,1077,1077,154,155,'LPAAAA','MWKAAA','AAAAxx'
+8348,7345,0,0,8,8,48,348,348,3348,8348,96,97,'CJAAAA','NWKAAA','HHHHxx'
+841,7346,1,1,1,1,41,841,841,841,841,82,83,'JGAAAA','OWKAAA','OOOOxx'
+8154,7347,0,2,4,14,54,154,154,3154,8154,108,109,'QBAAAA','PWKAAA','VVVVxx'
+5261,7348,1,1,1,1,61,261,1261,261,5261,122,123,'JUAAAA','QWKAAA','AAAAxx'
+1950,7349,0,2,0,10,50,950,1950,1950,1950,100,101,'AXAAAA','RWKAAA','HHHHxx'
+8472,7350,0,0,2,12,72,472,472,3472,8472,144,145,'WNAAAA','SWKAAA','OOOOxx'
+8745,7351,1,1,5,5,45,745,745,3745,8745,90,91,'JYAAAA','TWKAAA','VVVVxx'
+8715,7352,1,3,5,15,15,715,715,3715,8715,30,31,'FXAAAA','UWKAAA','AAAAxx'
+9708,7353,0,0,8,8,8,708,1708,4708,9708,16,17,'KJAAAA','VWKAAA','HHHHxx'
+5860,7354,0,0,0,0,60,860,1860,860,5860,120,121,'KRAAAA','WWKAAA','OOOOxx'
+9142,7355,0,2,2,2,42,142,1142,4142,9142,84,85,'QNAAAA','XWKAAA','VVVVxx'
+6582,7356,0,2,2,2,82,582,582,1582,6582,164,165,'ETAAAA','YWKAAA','AAAAxx'
+1255,7357,1,3,5,15,55,255,1255,1255,1255,110,111,'HWAAAA','ZWKAAA','HHHHxx'
+6459,7358,1,3,9,19,59,459,459,1459,6459,118,119,'LOAAAA','AXKAAA','OOOOxx'
+6327,7359,1,3,7,7,27,327,327,1327,6327,54,55,'JJAAAA','BXKAAA','VVVVxx'
+4692,7360,0,0,2,12,92,692,692,4692,4692,184,185,'MYAAAA','CXKAAA','AAAAxx'
+3772,7361,0,0,2,12,72,772,1772,3772,3772,144,145,'CPAAAA','DXKAAA','HHHHxx'
+4203,7362,1,3,3,3,3,203,203,4203,4203,6,7,'RFAAAA','EXKAAA','OOOOxx'
+2946,7363,0,2,6,6,46,946,946,2946,2946,92,93,'IJAAAA','FXKAAA','VVVVxx'
+3524,7364,0,0,4,4,24,524,1524,3524,3524,48,49,'OFAAAA','GXKAAA','AAAAxx'
+8409,7365,1,1,9,9,9,409,409,3409,8409,18,19,'LLAAAA','HXKAAA','HHHHxx'
+1824,7366,0,0,4,4,24,824,1824,1824,1824,48,49,'ESAAAA','IXKAAA','OOOOxx'
+4637,7367,1,1,7,17,37,637,637,4637,4637,74,75,'JWAAAA','JXKAAA','VVVVxx'
+589,7368,1,1,9,9,89,589,589,589,589,178,179,'RWAAAA','KXKAAA','AAAAxx'
+484,7369,0,0,4,4,84,484,484,484,484,168,169,'QSAAAA','LXKAAA','HHHHxx'
+8963,7370,1,3,3,3,63,963,963,3963,8963,126,127,'TGAAAA','MXKAAA','OOOOxx'
+5502,7371,0,2,2,2,2,502,1502,502,5502,4,5,'QDAAAA','NXKAAA','VVVVxx'
+6982,7372,0,2,2,2,82,982,982,1982,6982,164,165,'OIAAAA','OXKAAA','AAAAxx'
+8029,7373,1,1,9,9,29,29,29,3029,8029,58,59,'VWAAAA','PXKAAA','HHHHxx'
+4395,7374,1,3,5,15,95,395,395,4395,4395,190,191,'BNAAAA','QXKAAA','OOOOxx'
+2595,7375,1,3,5,15,95,595,595,2595,2595,190,191,'VVAAAA','RXKAAA','VVVVxx'
+2133,7376,1,1,3,13,33,133,133,2133,2133,66,67,'BEAAAA','SXKAAA','AAAAxx'
+1414,7377,0,2,4,14,14,414,1414,1414,1414,28,29,'KCAAAA','TXKAAA','HHHHxx'
+8201,7378,1,1,1,1,1,201,201,3201,8201,2,3,'LDAAAA','UXKAAA','OOOOxx'
+4706,7379,0,2,6,6,6,706,706,4706,4706,12,13,'AZAAAA','VXKAAA','VVVVxx'
+5310,7380,0,2,0,10,10,310,1310,310,5310,20,21,'GWAAAA','WXKAAA','AAAAxx'
+7333,7381,1,1,3,13,33,333,1333,2333,7333,66,67,'BWAAAA','XXKAAA','HHHHxx'
+9420,7382,0,0,0,0,20,420,1420,4420,9420,40,41,'IYAAAA','YXKAAA','OOOOxx'
+1383,7383,1,3,3,3,83,383,1383,1383,1383,166,167,'FBAAAA','ZXKAAA','VVVVxx'
+6225,7384,1,1,5,5,25,225,225,1225,6225,50,51,'LFAAAA','AYKAAA','AAAAxx'
+2064,7385,0,0,4,4,64,64,64,2064,2064,128,129,'KBAAAA','BYKAAA','HHHHxx'
+6700,7386,0,0,0,0,0,700,700,1700,6700,0,1,'SXAAAA','CYKAAA','OOOOxx'
+1352,7387,0,0,2,12,52,352,1352,1352,1352,104,105,'AAAAAA','DYKAAA','VVVVxx'
+4249,7388,1,1,9,9,49,249,249,4249,4249,98,99,'LHAAAA','EYKAAA','AAAAxx'
+9429,7389,1,1,9,9,29,429,1429,4429,9429,58,59,'RYAAAA','FYKAAA','HHHHxx'
+8090,7390,0,2,0,10,90,90,90,3090,8090,180,181,'EZAAAA','GYKAAA','OOOOxx'
+5378,7391,0,2,8,18,78,378,1378,378,5378,156,157,'WYAAAA','HYKAAA','VVVVxx'
+9085,7392,1,1,5,5,85,85,1085,4085,9085,170,171,'LLAAAA','IYKAAA','AAAAxx'
+7468,7393,0,0,8,8,68,468,1468,2468,7468,136,137,'GBAAAA','JYKAAA','HHHHxx'
+9955,7394,1,3,5,15,55,955,1955,4955,9955,110,111,'XSAAAA','KYKAAA','OOOOxx'
+8692,7395,0,0,2,12,92,692,692,3692,8692,184,185,'IWAAAA','LYKAAA','VVVVxx'
+1463,7396,1,3,3,3,63,463,1463,1463,1463,126,127,'HEAAAA','MYKAAA','AAAAxx'
+3577,7397,1,1,7,17,77,577,1577,3577,3577,154,155,'PHAAAA','NYKAAA','HHHHxx'
+5654,7398,0,2,4,14,54,654,1654,654,5654,108,109,'MJAAAA','OYKAAA','OOOOxx'
+7955,7399,1,3,5,15,55,955,1955,2955,7955,110,111,'ZTAAAA','PYKAAA','VVVVxx'
+4843,7400,1,3,3,3,43,843,843,4843,4843,86,87,'HEAAAA','QYKAAA','AAAAxx'
+1776,7401,0,0,6,16,76,776,1776,1776,1776,152,153,'IQAAAA','RYKAAA','HHHHxx'
+2223,7402,1,3,3,3,23,223,223,2223,2223,46,47,'NHAAAA','SYKAAA','OOOOxx'
+8442,7403,0,2,2,2,42,442,442,3442,8442,84,85,'SMAAAA','TYKAAA','VVVVxx'
+9738,7404,0,2,8,18,38,738,1738,4738,9738,76,77,'OKAAAA','UYKAAA','AAAAxx'
+4867,7405,1,3,7,7,67,867,867,4867,4867,134,135,'FFAAAA','VYKAAA','HHHHxx'
+2983,7406,1,3,3,3,83,983,983,2983,2983,166,167,'TKAAAA','WYKAAA','OOOOxx'
+3300,7407,0,0,0,0,0,300,1300,3300,3300,0,1,'YWAAAA','XYKAAA','VVVVxx'
+3815,7408,1,3,5,15,15,815,1815,3815,3815,30,31,'TQAAAA','YYKAAA','AAAAxx'
+1779,7409,1,3,9,19,79,779,1779,1779,1779,158,159,'LQAAAA','ZYKAAA','HHHHxx'
+1123,7410,1,3,3,3,23,123,1123,1123,1123,46,47,'FRAAAA','AZKAAA','OOOOxx'
+4824,7411,0,0,4,4,24,824,824,4824,4824,48,49,'ODAAAA','BZKAAA','VVVVxx'
+5407,7412,1,3,7,7,7,407,1407,407,5407,14,15,'ZZAAAA','CZKAAA','AAAAxx'
+5123,7413,1,3,3,3,23,123,1123,123,5123,46,47,'BPAAAA','DZKAAA','HHHHxx'
+2515,7414,1,3,5,15,15,515,515,2515,2515,30,31,'TSAAAA','EZKAAA','OOOOxx'
+4781,7415,1,1,1,1,81,781,781,4781,4781,162,163,'XBAAAA','FZKAAA','VVVVxx'
+7831,7416,1,3,1,11,31,831,1831,2831,7831,62,63,'FPAAAA','GZKAAA','AAAAxx'
+6946,7417,0,2,6,6,46,946,946,1946,6946,92,93,'EHAAAA','HZKAAA','HHHHxx'
+1215,7418,1,3,5,15,15,215,1215,1215,1215,30,31,'TUAAAA','IZKAAA','OOOOxx'
+7783,7419,1,3,3,3,83,783,1783,2783,7783,166,167,'JNAAAA','JZKAAA','VVVVxx'
+4532,7420,0,0,2,12,32,532,532,4532,4532,64,65,'ISAAAA','KZKAAA','AAAAxx'
+9068,7421,0,0,8,8,68,68,1068,4068,9068,136,137,'UKAAAA','LZKAAA','HHHHxx'
+7030,7422,0,2,0,10,30,30,1030,2030,7030,60,61,'KKAAAA','MZKAAA','OOOOxx'
+436,7423,0,0,6,16,36,436,436,436,436,72,73,'UQAAAA','NZKAAA','VVVVxx'
+6549,7424,1,1,9,9,49,549,549,1549,6549,98,99,'XRAAAA','OZKAAA','AAAAxx'
+3348,7425,0,0,8,8,48,348,1348,3348,3348,96,97,'UYAAAA','PZKAAA','HHHHxx'
+6229,7426,1,1,9,9,29,229,229,1229,6229,58,59,'PFAAAA','QZKAAA','OOOOxx'
+3933,7427,1,1,3,13,33,933,1933,3933,3933,66,67,'HVAAAA','RZKAAA','VVVVxx'
+1876,7428,0,0,6,16,76,876,1876,1876,1876,152,153,'EUAAAA','SZKAAA','AAAAxx'
+8920,7429,0,0,0,0,20,920,920,3920,8920,40,41,'CFAAAA','TZKAAA','HHHHxx'
+7926,7430,0,2,6,6,26,926,1926,2926,7926,52,53,'WSAAAA','UZKAAA','OOOOxx'
+8805,7431,1,1,5,5,5,805,805,3805,8805,10,11,'RAAAAA','VZKAAA','VVVVxx'
+6729,7432,1,1,9,9,29,729,729,1729,6729,58,59,'VYAAAA','WZKAAA','AAAAxx'
+7397,7433,1,1,7,17,97,397,1397,2397,7397,194,195,'NYAAAA','XZKAAA','HHHHxx'
+9303,7434,1,3,3,3,3,303,1303,4303,9303,6,7,'VTAAAA','YZKAAA','OOOOxx'
+4255,7435,1,3,5,15,55,255,255,4255,4255,110,111,'RHAAAA','ZZKAAA','VVVVxx'
+7229,7436,1,1,9,9,29,229,1229,2229,7229,58,59,'BSAAAA','AALAAA','AAAAxx'
+854,7437,0,2,4,14,54,854,854,854,854,108,109,'WGAAAA','BALAAA','HHHHxx'
+6723,7438,1,3,3,3,23,723,723,1723,6723,46,47,'PYAAAA','CALAAA','OOOOxx'
+9597,7439,1,1,7,17,97,597,1597,4597,9597,194,195,'DFAAAA','DALAAA','VVVVxx'
+6532,7440,0,0,2,12,32,532,532,1532,6532,64,65,'GRAAAA','EALAAA','AAAAxx'
+2910,7441,0,2,0,10,10,910,910,2910,2910,20,21,'YHAAAA','FALAAA','HHHHxx'
+6717,7442,1,1,7,17,17,717,717,1717,6717,34,35,'JYAAAA','GALAAA','OOOOxx'
+1790,7443,0,2,0,10,90,790,1790,1790,1790,180,181,'WQAAAA','HALAAA','VVVVxx'
+3761,7444,1,1,1,1,61,761,1761,3761,3761,122,123,'ROAAAA','IALAAA','AAAAxx'
+1565,7445,1,1,5,5,65,565,1565,1565,1565,130,131,'FIAAAA','JALAAA','HHHHxx'
+6205,7446,1,1,5,5,5,205,205,1205,6205,10,11,'REAAAA','KALAAA','OOOOxx'
+2726,7447,0,2,6,6,26,726,726,2726,2726,52,53,'WAAAAA','LALAAA','VVVVxx'
+799,7448,1,3,9,19,99,799,799,799,799,198,199,'TEAAAA','MALAAA','AAAAxx'
+3540,7449,0,0,0,0,40,540,1540,3540,3540,80,81,'EGAAAA','NALAAA','HHHHxx'
+5878,7450,0,2,8,18,78,878,1878,878,5878,156,157,'CSAAAA','OALAAA','OOOOxx'
+2542,7451,0,2,2,2,42,542,542,2542,2542,84,85,'UTAAAA','PALAAA','VVVVxx'
+4888,7452,0,0,8,8,88,888,888,4888,4888,176,177,'AGAAAA','QALAAA','AAAAxx'
+5290,7453,0,2,0,10,90,290,1290,290,5290,180,181,'MVAAAA','RALAAA','HHHHxx'
+7995,7454,1,3,5,15,95,995,1995,2995,7995,190,191,'NVAAAA','SALAAA','OOOOxx'
+3519,7455,1,3,9,19,19,519,1519,3519,3519,38,39,'JFAAAA','TALAAA','VVVVxx'
+3571,7456,1,3,1,11,71,571,1571,3571,3571,142,143,'JHAAAA','UALAAA','AAAAxx'
+7854,7457,0,2,4,14,54,854,1854,2854,7854,108,109,'CQAAAA','VALAAA','HHHHxx'
+5184,7458,0,0,4,4,84,184,1184,184,5184,168,169,'KRAAAA','WALAAA','OOOOxx'
+3498,7459,0,2,8,18,98,498,1498,3498,3498,196,197,'OEAAAA','XALAAA','VVVVxx'
+1264,7460,0,0,4,4,64,264,1264,1264,1264,128,129,'QWAAAA','YALAAA','AAAAxx'
+3159,7461,1,3,9,19,59,159,1159,3159,3159,118,119,'NRAAAA','ZALAAA','HHHHxx'
+5480,7462,0,0,0,0,80,480,1480,480,5480,160,161,'UCAAAA','ABLAAA','OOOOxx'
+1706,7463,0,2,6,6,6,706,1706,1706,1706,12,13,'QNAAAA','BBLAAA','VVVVxx'
+4540,7464,0,0,0,0,40,540,540,4540,4540,80,81,'QSAAAA','CBLAAA','AAAAxx'
+2799,7465,1,3,9,19,99,799,799,2799,2799,198,199,'RDAAAA','DBLAAA','HHHHxx'
+7389,7466,1,1,9,9,89,389,1389,2389,7389,178,179,'FYAAAA','EBLAAA','OOOOxx'
+5565,7467,1,1,5,5,65,565,1565,565,5565,130,131,'BGAAAA','FBLAAA','VVVVxx'
+3896,7468,0,0,6,16,96,896,1896,3896,3896,192,193,'WTAAAA','GBLAAA','AAAAxx'
+2100,7469,0,0,0,0,0,100,100,2100,2100,0,1,'UCAAAA','HBLAAA','HHHHxx'
+3507,7470,1,3,7,7,7,507,1507,3507,3507,14,15,'XEAAAA','IBLAAA','OOOOxx'
+7971,7471,1,3,1,11,71,971,1971,2971,7971,142,143,'PUAAAA','JBLAAA','VVVVxx'
+2312,7472,0,0,2,12,12,312,312,2312,2312,24,25,'YKAAAA','KBLAAA','AAAAxx'
+2494,7473,0,2,4,14,94,494,494,2494,2494,188,189,'YRAAAA','LBLAAA','HHHHxx'
+2474,7474,0,2,4,14,74,474,474,2474,2474,148,149,'ERAAAA','MBLAAA','OOOOxx'
+3136,7475,0,0,6,16,36,136,1136,3136,3136,72,73,'QQAAAA','NBLAAA','VVVVxx'
+7242,7476,0,2,2,2,42,242,1242,2242,7242,84,85,'OSAAAA','OBLAAA','AAAAxx'
+9430,7477,0,2,0,10,30,430,1430,4430,9430,60,61,'SYAAAA','PBLAAA','HHHHxx'
+1052,7478,0,0,2,12,52,52,1052,1052,1052,104,105,'MOAAAA','QBLAAA','OOOOxx'
+4172,7479,0,0,2,12,72,172,172,4172,4172,144,145,'MEAAAA','RBLAAA','VVVVxx'
+970,7480,0,2,0,10,70,970,970,970,970,140,141,'ILAAAA','SBLAAA','AAAAxx'
+882,7481,0,2,2,2,82,882,882,882,882,164,165,'YHAAAA','TBLAAA','HHHHxx'
+9799,7482,1,3,9,19,99,799,1799,4799,9799,198,199,'XMAAAA','UBLAAA','OOOOxx'
+5850,7483,0,2,0,10,50,850,1850,850,5850,100,101,'ARAAAA','VBLAAA','VVVVxx'
+9473,7484,1,1,3,13,73,473,1473,4473,9473,146,147,'JAAAAA','WBLAAA','AAAAxx'
+8635,7485,1,3,5,15,35,635,635,3635,8635,70,71,'DUAAAA','XBLAAA','HHHHxx'
+2349,7486,1,1,9,9,49,349,349,2349,2349,98,99,'JMAAAA','YBLAAA','OOOOxx'
+2270,7487,0,2,0,10,70,270,270,2270,2270,140,141,'IJAAAA','ZBLAAA','VVVVxx'
+7887,7488,1,3,7,7,87,887,1887,2887,7887,174,175,'JRAAAA','ACLAAA','AAAAxx'
+3091,7489,1,3,1,11,91,91,1091,3091,3091,182,183,'XOAAAA','BCLAAA','HHHHxx'
+3728,7490,0,0,8,8,28,728,1728,3728,3728,56,57,'KNAAAA','CCLAAA','OOOOxx'
+3658,7491,0,2,8,18,58,658,1658,3658,3658,116,117,'SKAAAA','DCLAAA','VVVVxx'
+5975,7492,1,3,5,15,75,975,1975,975,5975,150,151,'VVAAAA','ECLAAA','AAAAxx'
+332,7493,0,0,2,12,32,332,332,332,332,64,65,'UMAAAA','FCLAAA','HHHHxx'
+7990,7494,0,2,0,10,90,990,1990,2990,7990,180,181,'IVAAAA','GCLAAA','OOOOxx'
+8688,7495,0,0,8,8,88,688,688,3688,8688,176,177,'EWAAAA','HCLAAA','VVVVxx'
+9601,7496,1,1,1,1,1,601,1601,4601,9601,2,3,'HFAAAA','ICLAAA','AAAAxx'
+8401,7497,1,1,1,1,1,401,401,3401,8401,2,3,'DLAAAA','JCLAAA','HHHHxx'
+8093,7498,1,1,3,13,93,93,93,3093,8093,186,187,'HZAAAA','KCLAAA','OOOOxx'
+4278,7499,0,2,8,18,78,278,278,4278,4278,156,157,'OIAAAA','LCLAAA','VVVVxx'
+5467,7500,1,3,7,7,67,467,1467,467,5467,134,135,'HCAAAA','MCLAAA','AAAAxx'
+3137,7501,1,1,7,17,37,137,1137,3137,3137,74,75,'RQAAAA','NCLAAA','HHHHxx'
+204,7502,0,0,4,4,4,204,204,204,204,8,9,'WHAAAA','OCLAAA','OOOOxx'
+8224,7503,0,0,4,4,24,224,224,3224,8224,48,49,'IEAAAA','PCLAAA','VVVVxx'
+2944,7504,0,0,4,4,44,944,944,2944,2944,88,89,'GJAAAA','QCLAAA','AAAAxx'
+7593,7505,1,1,3,13,93,593,1593,2593,7593,186,187,'BGAAAA','RCLAAA','HHHHxx'
+814,7506,0,2,4,14,14,814,814,814,814,28,29,'IFAAAA','SCLAAA','OOOOxx'
+8047,7507,1,3,7,7,47,47,47,3047,8047,94,95,'NXAAAA','TCLAAA','VVVVxx'
+7802,7508,0,2,2,2,2,802,1802,2802,7802,4,5,'COAAAA','UCLAAA','AAAAxx'
+901,7509,1,1,1,1,1,901,901,901,901,2,3,'RIAAAA','VCLAAA','HHHHxx'
+6168,7510,0,0,8,8,68,168,168,1168,6168,136,137,'GDAAAA','WCLAAA','OOOOxx'
+2950,7511,0,2,0,10,50,950,950,2950,2950,100,101,'MJAAAA','XCLAAA','VVVVxx'
+5393,7512,1,1,3,13,93,393,1393,393,5393,186,187,'LZAAAA','YCLAAA','AAAAxx'
+3585,7513,1,1,5,5,85,585,1585,3585,3585,170,171,'XHAAAA','ZCLAAA','HHHHxx'
+9392,7514,0,0,2,12,92,392,1392,4392,9392,184,185,'GXAAAA','ADLAAA','OOOOxx'
+8314,7515,0,2,4,14,14,314,314,3314,8314,28,29,'UHAAAA','BDLAAA','VVVVxx'
+9972,7516,0,0,2,12,72,972,1972,4972,9972,144,145,'OTAAAA','CDLAAA','AAAAxx'
+9130,7517,0,2,0,10,30,130,1130,4130,9130,60,61,'ENAAAA','DDLAAA','HHHHxx'
+975,7518,1,3,5,15,75,975,975,975,975,150,151,'NLAAAA','EDLAAA','OOOOxx'
+5720,7519,0,0,0,0,20,720,1720,720,5720,40,41,'AMAAAA','FDLAAA','VVVVxx'
+3769,7520,1,1,9,9,69,769,1769,3769,3769,138,139,'ZOAAAA','GDLAAA','AAAAxx'
+5303,7521,1,3,3,3,3,303,1303,303,5303,6,7,'ZVAAAA','HDLAAA','HHHHxx'
+6564,7522,0,0,4,4,64,564,564,1564,6564,128,129,'MSAAAA','IDLAAA','OOOOxx'
+7855,7523,1,3,5,15,55,855,1855,2855,7855,110,111,'DQAAAA','JDLAAA','VVVVxx'
+8153,7524,1,1,3,13,53,153,153,3153,8153,106,107,'PBAAAA','KDLAAA','AAAAxx'
+2292,7525,0,0,2,12,92,292,292,2292,2292,184,185,'EKAAAA','LDLAAA','HHHHxx'
+3156,7526,0,0,6,16,56,156,1156,3156,3156,112,113,'KRAAAA','MDLAAA','OOOOxx'
+6580,7527,0,0,0,0,80,580,580,1580,6580,160,161,'CTAAAA','NDLAAA','VVVVxx'
+5324,7528,0,0,4,4,24,324,1324,324,5324,48,49,'UWAAAA','ODLAAA','AAAAxx'
+8871,7529,1,3,1,11,71,871,871,3871,8871,142,143,'FDAAAA','PDLAAA','HHHHxx'
+2543,7530,1,3,3,3,43,543,543,2543,2543,86,87,'VTAAAA','QDLAAA','OOOOxx'
+7857,7531,1,1,7,17,57,857,1857,2857,7857,114,115,'FQAAAA','RDLAAA','VVVVxx'
+4084,7532,0,0,4,4,84,84,84,4084,4084,168,169,'CBAAAA','SDLAAA','AAAAxx'
+9887,7533,1,3,7,7,87,887,1887,4887,9887,174,175,'HQAAAA','TDLAAA','HHHHxx'
+6940,7534,0,0,0,0,40,940,940,1940,6940,80,81,'YGAAAA','UDLAAA','OOOOxx'
+3415,7535,1,3,5,15,15,415,1415,3415,3415,30,31,'JBAAAA','VDLAAA','VVVVxx'
+5012,7536,0,0,2,12,12,12,1012,12,5012,24,25,'UKAAAA','WDLAAA','AAAAxx'
+3187,7537,1,3,7,7,87,187,1187,3187,3187,174,175,'PSAAAA','XDLAAA','HHHHxx'
+8556,7538,0,0,6,16,56,556,556,3556,8556,112,113,'CRAAAA','YDLAAA','OOOOxx'
+7966,7539,0,2,6,6,66,966,1966,2966,7966,132,133,'KUAAAA','ZDLAAA','VVVVxx'
+7481,7540,1,1,1,1,81,481,1481,2481,7481,162,163,'TBAAAA','AELAAA','AAAAxx'
+8524,7541,0,0,4,4,24,524,524,3524,8524,48,49,'WPAAAA','BELAAA','HHHHxx'
+3021,7542,1,1,1,1,21,21,1021,3021,3021,42,43,'FMAAAA','CELAAA','OOOOxx'
+6045,7543,1,1,5,5,45,45,45,1045,6045,90,91,'NYAAAA','DELAAA','VVVVxx'
+8022,7544,0,2,2,2,22,22,22,3022,8022,44,45,'OWAAAA','EELAAA','AAAAxx'
+3626,7545,0,2,6,6,26,626,1626,3626,3626,52,53,'MJAAAA','FELAAA','HHHHxx'
+1030,7546,0,2,0,10,30,30,1030,1030,1030,60,61,'QNAAAA','GELAAA','OOOOxx'
+8903,7547,1,3,3,3,3,903,903,3903,8903,6,7,'LEAAAA','HELAAA','VVVVxx'
+7488,7548,0,0,8,8,88,488,1488,2488,7488,176,177,'ACAAAA','IELAAA','AAAAxx'
+9293,7549,1,1,3,13,93,293,1293,4293,9293,186,187,'LTAAAA','JELAAA','HHHHxx'
+4586,7550,0,2,6,6,86,586,586,4586,4586,172,173,'KUAAAA','KELAAA','OOOOxx'
+9282,7551,0,2,2,2,82,282,1282,4282,9282,164,165,'ATAAAA','LELAAA','VVVVxx'
+1948,7552,0,0,8,8,48,948,1948,1948,1948,96,97,'YWAAAA','MELAAA','AAAAxx'
+2534,7553,0,2,4,14,34,534,534,2534,2534,68,69,'MTAAAA','NELAAA','HHHHxx'
+1150,7554,0,2,0,10,50,150,1150,1150,1150,100,101,'GSAAAA','OELAAA','OOOOxx'
+4931,7555,1,3,1,11,31,931,931,4931,4931,62,63,'RHAAAA','PELAAA','VVVVxx'
+2866,7556,0,2,6,6,66,866,866,2866,2866,132,133,'GGAAAA','QELAAA','AAAAxx'
+6172,7557,0,0,2,12,72,172,172,1172,6172,144,145,'KDAAAA','RELAAA','HHHHxx'
+4819,7558,1,3,9,19,19,819,819,4819,4819,38,39,'JDAAAA','SELAAA','OOOOxx'
+569,7559,1,1,9,9,69,569,569,569,569,138,139,'XVAAAA','TELAAA','VVVVxx'
+1146,7560,0,2,6,6,46,146,1146,1146,1146,92,93,'CSAAAA','UELAAA','AAAAxx'
+3062,7561,0,2,2,2,62,62,1062,3062,3062,124,125,'UNAAAA','VELAAA','HHHHxx'
+7690,7562,0,2,0,10,90,690,1690,2690,7690,180,181,'UJAAAA','WELAAA','OOOOxx'
+8611,7563,1,3,1,11,11,611,611,3611,8611,22,23,'FTAAAA','XELAAA','VVVVxx'
+1142,7564,0,2,2,2,42,142,1142,1142,1142,84,85,'YRAAAA','YELAAA','AAAAxx'
+1193,7565,1,1,3,13,93,193,1193,1193,1193,186,187,'XTAAAA','ZELAAA','HHHHxx'
+2507,7566,1,3,7,7,7,507,507,2507,2507,14,15,'LSAAAA','AFLAAA','OOOOxx'
+1043,7567,1,3,3,3,43,43,1043,1043,1043,86,87,'DOAAAA','BFLAAA','VVVVxx'
+7472,7568,0,0,2,12,72,472,1472,2472,7472,144,145,'KBAAAA','CFLAAA','AAAAxx'
+1817,7569,1,1,7,17,17,817,1817,1817,1817,34,35,'XRAAAA','DFLAAA','HHHHxx'
+3868,7570,0,0,8,8,68,868,1868,3868,3868,136,137,'USAAAA','EFLAAA','OOOOxx'
+9031,7571,1,3,1,11,31,31,1031,4031,9031,62,63,'JJAAAA','FFLAAA','VVVVxx'
+7254,7572,0,2,4,14,54,254,1254,2254,7254,108,109,'ATAAAA','GFLAAA','AAAAxx'
+5030,7573,0,2,0,10,30,30,1030,30,5030,60,61,'MLAAAA','HFLAAA','HHHHxx'
+6594,7574,0,2,4,14,94,594,594,1594,6594,188,189,'QTAAAA','IFLAAA','OOOOxx'
+6862,7575,0,2,2,2,62,862,862,1862,6862,124,125,'YDAAAA','JFLAAA','VVVVxx'
+1994,7576,0,2,4,14,94,994,1994,1994,1994,188,189,'SYAAAA','KFLAAA','AAAAxx'
+9017,7577,1,1,7,17,17,17,1017,4017,9017,34,35,'VIAAAA','LFLAAA','HHHHxx'
+5716,7578,0,0,6,16,16,716,1716,716,5716,32,33,'WLAAAA','MFLAAA','OOOOxx'
+1900,7579,0,0,0,0,0,900,1900,1900,1900,0,1,'CVAAAA','NFLAAA','VVVVxx'
+120,7580,0,0,0,0,20,120,120,120,120,40,41,'QEAAAA','OFLAAA','AAAAxx'
+9003,7581,1,3,3,3,3,3,1003,4003,9003,6,7,'HIAAAA','PFLAAA','HHHHxx'
+4178,7582,0,2,8,18,78,178,178,4178,4178,156,157,'SEAAAA','QFLAAA','OOOOxx'
+8777,7583,1,1,7,17,77,777,777,3777,8777,154,155,'PZAAAA','RFLAAA','VVVVxx'
+3653,7584,1,1,3,13,53,653,1653,3653,3653,106,107,'NKAAAA','SFLAAA','AAAAxx'
+1137,7585,1,1,7,17,37,137,1137,1137,1137,74,75,'TRAAAA','TFLAAA','HHHHxx'
+6362,7586,0,2,2,2,62,362,362,1362,6362,124,125,'SKAAAA','UFLAAA','OOOOxx'
+8537,7587,1,1,7,17,37,537,537,3537,8537,74,75,'JQAAAA','VFLAAA','VVVVxx'
+1590,7588,0,2,0,10,90,590,1590,1590,1590,180,181,'EJAAAA','WFLAAA','AAAAxx'
+374,7589,0,2,4,14,74,374,374,374,374,148,149,'KOAAAA','XFLAAA','HHHHxx'
+2597,7590,1,1,7,17,97,597,597,2597,2597,194,195,'XVAAAA','YFLAAA','OOOOxx'
+8071,7591,1,3,1,11,71,71,71,3071,8071,142,143,'LYAAAA','ZFLAAA','VVVVxx'
+9009,7592,1,1,9,9,9,9,1009,4009,9009,18,19,'NIAAAA','AGLAAA','AAAAxx'
+1978,7593,0,2,8,18,78,978,1978,1978,1978,156,157,'CYAAAA','BGLAAA','HHHHxx'
+1541,7594,1,1,1,1,41,541,1541,1541,1541,82,83,'HHAAAA','CGLAAA','OOOOxx'
+4998,7595,0,2,8,18,98,998,998,4998,4998,196,197,'GKAAAA','DGLAAA','VVVVxx'
+1649,7596,1,1,9,9,49,649,1649,1649,1649,98,99,'LLAAAA','EGLAAA','AAAAxx'
+5426,7597,0,2,6,6,26,426,1426,426,5426,52,53,'SAAAAA','FGLAAA','HHHHxx'
+1492,7598,0,0,2,12,92,492,1492,1492,1492,184,185,'KFAAAA','GGLAAA','OOOOxx'
+9622,7599,0,2,2,2,22,622,1622,4622,9622,44,45,'CGAAAA','HGLAAA','VVVVxx'
+701,7600,1,1,1,1,1,701,701,701,701,2,3,'ZAAAAA','IGLAAA','AAAAxx'
+2781,7601,1,1,1,1,81,781,781,2781,2781,162,163,'ZCAAAA','JGLAAA','HHHHxx'
+3982,7602,0,2,2,2,82,982,1982,3982,3982,164,165,'EXAAAA','KGLAAA','OOOOxx'
+7259,7603,1,3,9,19,59,259,1259,2259,7259,118,119,'FTAAAA','LGLAAA','VVVVxx'
+9868,7604,0,0,8,8,68,868,1868,4868,9868,136,137,'OPAAAA','MGLAAA','AAAAxx'
+564,7605,0,0,4,4,64,564,564,564,564,128,129,'SVAAAA','NGLAAA','HHHHxx'
+6315,7606,1,3,5,15,15,315,315,1315,6315,30,31,'XIAAAA','OGLAAA','OOOOxx'
+9092,7607,0,0,2,12,92,92,1092,4092,9092,184,185,'SLAAAA','PGLAAA','VVVVxx'
+8237,7608,1,1,7,17,37,237,237,3237,8237,74,75,'VEAAAA','QGLAAA','AAAAxx'
+1513,7609,1,1,3,13,13,513,1513,1513,1513,26,27,'FGAAAA','RGLAAA','HHHHxx'
+1922,7610,0,2,2,2,22,922,1922,1922,1922,44,45,'YVAAAA','SGLAAA','OOOOxx'
+5396,7611,0,0,6,16,96,396,1396,396,5396,192,193,'OZAAAA','TGLAAA','VVVVxx'
+2485,7612,1,1,5,5,85,485,485,2485,2485,170,171,'PRAAAA','UGLAAA','AAAAxx'
+5774,7613,0,2,4,14,74,774,1774,774,5774,148,149,'COAAAA','VGLAAA','HHHHxx'
+3983,7614,1,3,3,3,83,983,1983,3983,3983,166,167,'FXAAAA','WGLAAA','OOOOxx'
+221,7615,1,1,1,1,21,221,221,221,221,42,43,'NIAAAA','XGLAAA','VVVVxx'
+8662,7616,0,2,2,2,62,662,662,3662,8662,124,125,'EVAAAA','YGLAAA','AAAAxx'
+2456,7617,0,0,6,16,56,456,456,2456,2456,112,113,'MQAAAA','ZGLAAA','HHHHxx'
+9736,7618,0,0,6,16,36,736,1736,4736,9736,72,73,'MKAAAA','AHLAAA','OOOOxx'
+8936,7619,0,0,6,16,36,936,936,3936,8936,72,73,'SFAAAA','BHLAAA','VVVVxx'
+5395,7620,1,3,5,15,95,395,1395,395,5395,190,191,'NZAAAA','CHLAAA','AAAAxx'
+9523,7621,1,3,3,3,23,523,1523,4523,9523,46,47,'HCAAAA','DHLAAA','HHHHxx'
+6980,7622,0,0,0,0,80,980,980,1980,6980,160,161,'MIAAAA','EHLAAA','OOOOxx'
+2091,7623,1,3,1,11,91,91,91,2091,2091,182,183,'LCAAAA','FHLAAA','VVVVxx'
+6807,7624,1,3,7,7,7,807,807,1807,6807,14,15,'VBAAAA','GHLAAA','AAAAxx'
+8818,7625,0,2,8,18,18,818,818,3818,8818,36,37,'EBAAAA','HHLAAA','HHHHxx'
+5298,7626,0,2,8,18,98,298,1298,298,5298,196,197,'UVAAAA','IHLAAA','OOOOxx'
+1726,7627,0,2,6,6,26,726,1726,1726,1726,52,53,'KOAAAA','JHLAAA','VVVVxx'
+3878,7628,0,2,8,18,78,878,1878,3878,3878,156,157,'ETAAAA','KHLAAA','AAAAxx'
+8700,7629,0,0,0,0,0,700,700,3700,8700,0,1,'QWAAAA','LHLAAA','HHHHxx'
+5201,7630,1,1,1,1,1,201,1201,201,5201,2,3,'BSAAAA','MHLAAA','OOOOxx'
+3936,7631,0,0,6,16,36,936,1936,3936,3936,72,73,'KVAAAA','NHLAAA','VVVVxx'
+776,7632,0,0,6,16,76,776,776,776,776,152,153,'WDAAAA','OHLAAA','AAAAxx'
+5302,7633,0,2,2,2,2,302,1302,302,5302,4,5,'YVAAAA','PHLAAA','HHHHxx'
+3595,7634,1,3,5,15,95,595,1595,3595,3595,190,191,'HIAAAA','QHLAAA','OOOOxx'
+9061,7635,1,1,1,1,61,61,1061,4061,9061,122,123,'NKAAAA','RHLAAA','VVVVxx'
+6261,7636,1,1,1,1,61,261,261,1261,6261,122,123,'VGAAAA','SHLAAA','AAAAxx'
+8878,7637,0,2,8,18,78,878,878,3878,8878,156,157,'MDAAAA','THLAAA','HHHHxx'
+3312,7638,0,0,2,12,12,312,1312,3312,3312,24,25,'KXAAAA','UHLAAA','OOOOxx'
+9422,7639,0,2,2,2,22,422,1422,4422,9422,44,45,'KYAAAA','VHLAAA','VVVVxx'
+7321,7640,1,1,1,1,21,321,1321,2321,7321,42,43,'PVAAAA','WHLAAA','AAAAxx'
+3813,7641,1,1,3,13,13,813,1813,3813,3813,26,27,'RQAAAA','XHLAAA','HHHHxx'
+5848,7642,0,0,8,8,48,848,1848,848,5848,96,97,'YQAAAA','YHLAAA','OOOOxx'
+3535,7643,1,3,5,15,35,535,1535,3535,3535,70,71,'ZFAAAA','ZHLAAA','VVVVxx'
+1040,7644,0,0,0,0,40,40,1040,1040,1040,80,81,'AOAAAA','AILAAA','AAAAxx'
+8572,7645,0,0,2,12,72,572,572,3572,8572,144,145,'SRAAAA','BILAAA','HHHHxx'
+5435,7646,1,3,5,15,35,435,1435,435,5435,70,71,'BBAAAA','CILAAA','OOOOxx'
+8199,7647,1,3,9,19,99,199,199,3199,8199,198,199,'JDAAAA','DILAAA','VVVVxx'
+8775,7648,1,3,5,15,75,775,775,3775,8775,150,151,'NZAAAA','EILAAA','AAAAxx'
+7722,7649,0,2,2,2,22,722,1722,2722,7722,44,45,'ALAAAA','FILAAA','HHHHxx'
+3549,7650,1,1,9,9,49,549,1549,3549,3549,98,99,'NGAAAA','GILAAA','OOOOxx'
+2578,7651,0,2,8,18,78,578,578,2578,2578,156,157,'EVAAAA','HILAAA','VVVVxx'
+1695,7652,1,3,5,15,95,695,1695,1695,1695,190,191,'FNAAAA','IILAAA','AAAAxx'
+1902,7653,0,2,2,2,2,902,1902,1902,1902,4,5,'EVAAAA','JILAAA','HHHHxx'
+6058,7654,0,2,8,18,58,58,58,1058,6058,116,117,'AZAAAA','KILAAA','OOOOxx'
+6591,7655,1,3,1,11,91,591,591,1591,6591,182,183,'NTAAAA','LILAAA','VVVVxx'
+7962,7656,0,2,2,2,62,962,1962,2962,7962,124,125,'GUAAAA','MILAAA','AAAAxx'
+5612,7657,0,0,2,12,12,612,1612,612,5612,24,25,'WHAAAA','NILAAA','HHHHxx'
+3341,7658,1,1,1,1,41,341,1341,3341,3341,82,83,'NYAAAA','OILAAA','OOOOxx'
+5460,7659,0,0,0,0,60,460,1460,460,5460,120,121,'ACAAAA','PILAAA','VVVVxx'
+2368,7660,0,0,8,8,68,368,368,2368,2368,136,137,'CNAAAA','QILAAA','AAAAxx'
+8646,7661,0,2,6,6,46,646,646,3646,8646,92,93,'OUAAAA','RILAAA','HHHHxx'
+4987,7662,1,3,7,7,87,987,987,4987,4987,174,175,'VJAAAA','SILAAA','OOOOxx'
+9018,7663,0,2,8,18,18,18,1018,4018,9018,36,37,'WIAAAA','TILAAA','VVVVxx'
+8685,7664,1,1,5,5,85,685,685,3685,8685,170,171,'BWAAAA','UILAAA','AAAAxx'
+694,7665,0,2,4,14,94,694,694,694,694,188,189,'SAAAAA','VILAAA','HHHHxx'
+2012,7666,0,0,2,12,12,12,12,2012,2012,24,25,'KZAAAA','WILAAA','OOOOxx'
+2417,7667,1,1,7,17,17,417,417,2417,2417,34,35,'ZOAAAA','XILAAA','VVVVxx'
+4022,7668,0,2,2,2,22,22,22,4022,4022,44,45,'SYAAAA','YILAAA','AAAAxx'
+5935,7669,1,3,5,15,35,935,1935,935,5935,70,71,'HUAAAA','ZILAAA','HHHHxx'
+1656,7670,0,0,6,16,56,656,1656,1656,1656,112,113,'SLAAAA','AJLAAA','OOOOxx'
+6195,7671,1,3,5,15,95,195,195,1195,6195,190,191,'HEAAAA','BJLAAA','VVVVxx'
+3057,7672,1,1,7,17,57,57,1057,3057,3057,114,115,'PNAAAA','CJLAAA','AAAAxx'
+2852,7673,0,0,2,12,52,852,852,2852,2852,104,105,'SFAAAA','DJLAAA','HHHHxx'
+4634,7674,0,2,4,14,34,634,634,4634,4634,68,69,'GWAAAA','EJLAAA','OOOOxx'
+1689,7675,1,1,9,9,89,689,1689,1689,1689,178,179,'ZMAAAA','FJLAAA','VVVVxx'
+4102,7676,0,2,2,2,2,102,102,4102,4102,4,5,'UBAAAA','GJLAAA','AAAAxx'
+3287,7677,1,3,7,7,87,287,1287,3287,3287,174,175,'LWAAAA','HJLAAA','HHHHxx'
+5246,7678,0,2,6,6,46,246,1246,246,5246,92,93,'UTAAAA','IJLAAA','OOOOxx'
+7450,7679,0,2,0,10,50,450,1450,2450,7450,100,101,'OAAAAA','JJLAAA','VVVVxx'
+6548,7680,0,0,8,8,48,548,548,1548,6548,96,97,'WRAAAA','KJLAAA','AAAAxx'
+379,7681,1,3,9,19,79,379,379,379,379,158,159,'POAAAA','LJLAAA','HHHHxx'
+7435,7682,1,3,5,15,35,435,1435,2435,7435,70,71,'ZZAAAA','MJLAAA','OOOOxx'
+2041,7683,1,1,1,1,41,41,41,2041,2041,82,83,'NAAAAA','NJLAAA','VVVVxx'
+8462,7684,0,2,2,2,62,462,462,3462,8462,124,125,'MNAAAA','OJLAAA','AAAAxx'
+9076,7685,0,0,6,16,76,76,1076,4076,9076,152,153,'CLAAAA','PJLAAA','HHHHxx'
+761,7686,1,1,1,1,61,761,761,761,761,122,123,'HDAAAA','QJLAAA','OOOOxx'
+795,7687,1,3,5,15,95,795,795,795,795,190,191,'PEAAAA','RJLAAA','VVVVxx'
+1671,7688,1,3,1,11,71,671,1671,1671,1671,142,143,'HMAAAA','SJLAAA','AAAAxx'
+695,7689,1,3,5,15,95,695,695,695,695,190,191,'TAAAAA','TJLAAA','HHHHxx'
+4981,7690,1,1,1,1,81,981,981,4981,4981,162,163,'PJAAAA','UJLAAA','OOOOxx'
+1211,7691,1,3,1,11,11,211,1211,1211,1211,22,23,'PUAAAA','VJLAAA','VVVVxx'
+5914,7692,0,2,4,14,14,914,1914,914,5914,28,29,'MTAAAA','WJLAAA','AAAAxx'
+9356,7693,0,0,6,16,56,356,1356,4356,9356,112,113,'WVAAAA','XJLAAA','HHHHxx'
+1500,7694,0,0,0,0,0,500,1500,1500,1500,0,1,'SFAAAA','YJLAAA','OOOOxx'
+3353,7695,1,1,3,13,53,353,1353,3353,3353,106,107,'ZYAAAA','ZJLAAA','VVVVxx'
+1060,7696,0,0,0,0,60,60,1060,1060,1060,120,121,'UOAAAA','AKLAAA','AAAAxx'
+7910,7697,0,2,0,10,10,910,1910,2910,7910,20,21,'GSAAAA','BKLAAA','HHHHxx'
+1329,7698,1,1,9,9,29,329,1329,1329,1329,58,59,'DZAAAA','CKLAAA','OOOOxx'
+6011,7699,1,3,1,11,11,11,11,1011,6011,22,23,'FXAAAA','DKLAAA','VVVVxx'
+7146,7700,0,2,6,6,46,146,1146,2146,7146,92,93,'WOAAAA','EKLAAA','AAAAxx'
+4602,7701,0,2,2,2,2,602,602,4602,4602,4,5,'AVAAAA','FKLAAA','HHHHxx'
+6751,7702,1,3,1,11,51,751,751,1751,6751,102,103,'RZAAAA','GKLAAA','OOOOxx'
+2666,7703,0,2,6,6,66,666,666,2666,2666,132,133,'OYAAAA','HKLAAA','VVVVxx'
+2785,7704,1,1,5,5,85,785,785,2785,2785,170,171,'DDAAAA','IKLAAA','AAAAxx'
+5851,7705,1,3,1,11,51,851,1851,851,5851,102,103,'BRAAAA','JKLAAA','HHHHxx'
+2435,7706,1,3,5,15,35,435,435,2435,2435,70,71,'RPAAAA','KKLAAA','OOOOxx'
+7429,7707,1,1,9,9,29,429,1429,2429,7429,58,59,'TZAAAA','LKLAAA','VVVVxx'
+4241,7708,1,1,1,1,41,241,241,4241,4241,82,83,'DHAAAA','MKLAAA','AAAAxx'
+5691,7709,1,3,1,11,91,691,1691,691,5691,182,183,'XKAAAA','NKLAAA','HHHHxx'
+7731,7710,1,3,1,11,31,731,1731,2731,7731,62,63,'JLAAAA','OKLAAA','OOOOxx'
+249,7711,1,1,9,9,49,249,249,249,249,98,99,'PJAAAA','PKLAAA','VVVVxx'
+1731,7712,1,3,1,11,31,731,1731,1731,1731,62,63,'POAAAA','QKLAAA','AAAAxx'
+8716,7713,0,0,6,16,16,716,716,3716,8716,32,33,'GXAAAA','RKLAAA','HHHHxx'
+2670,7714,0,2,0,10,70,670,670,2670,2670,140,141,'SYAAAA','SKLAAA','OOOOxx'
+4654,7715,0,2,4,14,54,654,654,4654,4654,108,109,'AXAAAA','TKLAAA','VVVVxx'
+1027,7716,1,3,7,7,27,27,1027,1027,1027,54,55,'NNAAAA','UKLAAA','AAAAxx'
+1099,7717,1,3,9,19,99,99,1099,1099,1099,198,199,'HQAAAA','VKLAAA','HHHHxx'
+3617,7718,1,1,7,17,17,617,1617,3617,3617,34,35,'DJAAAA','WKLAAA','OOOOxx'
+4330,7719,0,2,0,10,30,330,330,4330,4330,60,61,'OKAAAA','XKLAAA','VVVVxx'
+9750,7720,0,2,0,10,50,750,1750,4750,9750,100,101,'ALAAAA','YKLAAA','AAAAxx'
+467,7721,1,3,7,7,67,467,467,467,467,134,135,'ZRAAAA','ZKLAAA','HHHHxx'
+8525,7722,1,1,5,5,25,525,525,3525,8525,50,51,'XPAAAA','ALLAAA','OOOOxx'
+5990,7723,0,2,0,10,90,990,1990,990,5990,180,181,'KWAAAA','BLLAAA','VVVVxx'
+4839,7724,1,3,9,19,39,839,839,4839,4839,78,79,'DEAAAA','CLLAAA','AAAAxx'
+9914,7725,0,2,4,14,14,914,1914,4914,9914,28,29,'IRAAAA','DLLAAA','HHHHxx'
+7047,7726,1,3,7,7,47,47,1047,2047,7047,94,95,'BLAAAA','ELLAAA','OOOOxx'
+874,7727,0,2,4,14,74,874,874,874,874,148,149,'QHAAAA','FLLAAA','VVVVxx'
+6061,7728,1,1,1,1,61,61,61,1061,6061,122,123,'DZAAAA','GLLAAA','AAAAxx'
+5491,7729,1,3,1,11,91,491,1491,491,5491,182,183,'FDAAAA','HLLAAA','HHHHxx'
+4344,7730,0,0,4,4,44,344,344,4344,4344,88,89,'CLAAAA','ILLAAA','OOOOxx'
+1281,7731,1,1,1,1,81,281,1281,1281,1281,162,163,'HXAAAA','JLLAAA','VVVVxx'
+3597,7732,1,1,7,17,97,597,1597,3597,3597,194,195,'JIAAAA','KLLAAA','AAAAxx'
+4992,7733,0,0,2,12,92,992,992,4992,4992,184,185,'AKAAAA','LLLAAA','HHHHxx'
+3849,7734,1,1,9,9,49,849,1849,3849,3849,98,99,'BSAAAA','MLLAAA','OOOOxx'
+2655,7735,1,3,5,15,55,655,655,2655,2655,110,111,'DYAAAA','NLLAAA','VVVVxx'
+147,7736,1,3,7,7,47,147,147,147,147,94,95,'RFAAAA','OLLAAA','AAAAxx'
+9110,7737,0,2,0,10,10,110,1110,4110,9110,20,21,'KMAAAA','PLLAAA','HHHHxx'
+1637,7738,1,1,7,17,37,637,1637,1637,1637,74,75,'ZKAAAA','QLLAAA','OOOOxx'
+9826,7739,0,2,6,6,26,826,1826,4826,9826,52,53,'YNAAAA','RLLAAA','VVVVxx'
+5957,7740,1,1,7,17,57,957,1957,957,5957,114,115,'DVAAAA','SLLAAA','AAAAxx'
+6932,7741,0,0,2,12,32,932,932,1932,6932,64,65,'QGAAAA','TLLAAA','HHHHxx'
+9684,7742,0,0,4,4,84,684,1684,4684,9684,168,169,'MIAAAA','ULLAAA','OOOOxx'
+4653,7743,1,1,3,13,53,653,653,4653,4653,106,107,'ZWAAAA','VLLAAA','VVVVxx'
+8065,7744,1,1,5,5,65,65,65,3065,8065,130,131,'FYAAAA','WLLAAA','AAAAxx'
+1202,7745,0,2,2,2,2,202,1202,1202,1202,4,5,'GUAAAA','XLLAAA','HHHHxx'
+9214,7746,0,2,4,14,14,214,1214,4214,9214,28,29,'KQAAAA','YLLAAA','OOOOxx'
+196,7747,0,0,6,16,96,196,196,196,196,192,193,'OHAAAA','ZLLAAA','VVVVxx'
+4486,7748,0,2,6,6,86,486,486,4486,4486,172,173,'OQAAAA','AMLAAA','AAAAxx'
+2585,7749,1,1,5,5,85,585,585,2585,2585,170,171,'LVAAAA','BMLAAA','HHHHxx'
+2464,7750,0,0,4,4,64,464,464,2464,2464,128,129,'UQAAAA','CMLAAA','OOOOxx'
+3467,7751,1,3,7,7,67,467,1467,3467,3467,134,135,'JDAAAA','DMLAAA','VVVVxx'
+9295,7752,1,3,5,15,95,295,1295,4295,9295,190,191,'NTAAAA','EMLAAA','AAAAxx'
+517,7753,1,1,7,17,17,517,517,517,517,34,35,'XTAAAA','FMLAAA','HHHHxx'
+6870,7754,0,2,0,10,70,870,870,1870,6870,140,141,'GEAAAA','GMLAAA','OOOOxx'
+5732,7755,0,0,2,12,32,732,1732,732,5732,64,65,'MMAAAA','HMLAAA','VVVVxx'
+9376,7756,0,0,6,16,76,376,1376,4376,9376,152,153,'QWAAAA','IMLAAA','AAAAxx'
+838,7757,0,2,8,18,38,838,838,838,838,76,77,'GGAAAA','JMLAAA','HHHHxx'
+9254,7758,0,2,4,14,54,254,1254,4254,9254,108,109,'YRAAAA','KMLAAA','OOOOxx'
+8879,7759,1,3,9,19,79,879,879,3879,8879,158,159,'NDAAAA','LMLAAA','VVVVxx'
+6281,7760,1,1,1,1,81,281,281,1281,6281,162,163,'PHAAAA','MMLAAA','AAAAxx'
+8216,7761,0,0,6,16,16,216,216,3216,8216,32,33,'AEAAAA','NMLAAA','HHHHxx'
+9213,7762,1,1,3,13,13,213,1213,4213,9213,26,27,'JQAAAA','OMLAAA','OOOOxx'
+7234,7763,0,2,4,14,34,234,1234,2234,7234,68,69,'GSAAAA','PMLAAA','VVVVxx'
+5692,7764,0,0,2,12,92,692,1692,692,5692,184,185,'YKAAAA','QMLAAA','AAAAxx'
+693,7765,1,1,3,13,93,693,693,693,693,186,187,'RAAAAA','RMLAAA','HHHHxx'
+9050,7766,0,2,0,10,50,50,1050,4050,9050,100,101,'CKAAAA','SMLAAA','OOOOxx'
+3623,7767,1,3,3,3,23,623,1623,3623,3623,46,47,'JJAAAA','TMLAAA','VVVVxx'
+2130,7768,0,2,0,10,30,130,130,2130,2130,60,61,'YDAAAA','UMLAAA','AAAAxx'
+2514,7769,0,2,4,14,14,514,514,2514,2514,28,29,'SSAAAA','VMLAAA','HHHHxx'
+1812,7770,0,0,2,12,12,812,1812,1812,1812,24,25,'SRAAAA','WMLAAA','OOOOxx'
+9037,7771,1,1,7,17,37,37,1037,4037,9037,74,75,'PJAAAA','XMLAAA','VVVVxx'
+5054,7772,0,2,4,14,54,54,1054,54,5054,108,109,'KMAAAA','YMLAAA','AAAAxx'
+7801,7773,1,1,1,1,1,801,1801,2801,7801,2,3,'BOAAAA','ZMLAAA','HHHHxx'
+7939,7774,1,3,9,19,39,939,1939,2939,7939,78,79,'JTAAAA','ANLAAA','OOOOxx'
+7374,7775,0,2,4,14,74,374,1374,2374,7374,148,149,'QXAAAA','BNLAAA','VVVVxx'
+1058,7776,0,2,8,18,58,58,1058,1058,1058,116,117,'SOAAAA','CNLAAA','AAAAxx'
+1972,7777,0,0,2,12,72,972,1972,1972,1972,144,145,'WXAAAA','DNLAAA','HHHHxx'
+3741,7778,1,1,1,1,41,741,1741,3741,3741,82,83,'XNAAAA','ENLAAA','OOOOxx'
+2227,7779,1,3,7,7,27,227,227,2227,2227,54,55,'RHAAAA','FNLAAA','VVVVxx'
+304,7780,0,0,4,4,4,304,304,304,304,8,9,'SLAAAA','GNLAAA','AAAAxx'
+4914,7781,0,2,4,14,14,914,914,4914,4914,28,29,'AHAAAA','HNLAAA','HHHHxx'
+2428,7782,0,0,8,8,28,428,428,2428,2428,56,57,'KPAAAA','INLAAA','OOOOxx'
+6660,7783,0,0,0,0,60,660,660,1660,6660,120,121,'EWAAAA','JNLAAA','VVVVxx'
+2676,7784,0,0,6,16,76,676,676,2676,2676,152,153,'YYAAAA','KNLAAA','AAAAxx'
+2454,7785,0,2,4,14,54,454,454,2454,2454,108,109,'KQAAAA','LNLAAA','HHHHxx'
+3798,7786,0,2,8,18,98,798,1798,3798,3798,196,197,'CQAAAA','MNLAAA','OOOOxx'
+1341,7787,1,1,1,1,41,341,1341,1341,1341,82,83,'PZAAAA','NNLAAA','VVVVxx'
+1611,7788,1,3,1,11,11,611,1611,1611,1611,22,23,'ZJAAAA','ONLAAA','AAAAxx'
+2681,7789,1,1,1,1,81,681,681,2681,2681,162,163,'DZAAAA','PNLAAA','HHHHxx'
+7292,7790,0,0,2,12,92,292,1292,2292,7292,184,185,'MUAAAA','QNLAAA','OOOOxx'
+7775,7791,1,3,5,15,75,775,1775,2775,7775,150,151,'BNAAAA','RNLAAA','VVVVxx'
+794,7792,0,2,4,14,94,794,794,794,794,188,189,'OEAAAA','SNLAAA','AAAAxx'
+8709,7793,1,1,9,9,9,709,709,3709,8709,18,19,'ZWAAAA','TNLAAA','HHHHxx'
+1901,7794,1,1,1,1,1,901,1901,1901,1901,2,3,'DVAAAA','UNLAAA','OOOOxx'
+3089,7795,1,1,9,9,89,89,1089,3089,3089,178,179,'VOAAAA','VNLAAA','VVVVxx'
+7797,7796,1,1,7,17,97,797,1797,2797,7797,194,195,'XNAAAA','WNLAAA','AAAAxx'
+6070,7797,0,2,0,10,70,70,70,1070,6070,140,141,'MZAAAA','XNLAAA','HHHHxx'
+2191,7798,1,3,1,11,91,191,191,2191,2191,182,183,'HGAAAA','YNLAAA','OOOOxx'
+3497,7799,1,1,7,17,97,497,1497,3497,3497,194,195,'NEAAAA','ZNLAAA','VVVVxx'
+8302,7800,0,2,2,2,2,302,302,3302,8302,4,5,'IHAAAA','AOLAAA','AAAAxx'
+4365,7801,1,1,5,5,65,365,365,4365,4365,130,131,'XLAAAA','BOLAAA','HHHHxx'
+3588,7802,0,0,8,8,88,588,1588,3588,3588,176,177,'AIAAAA','COLAAA','OOOOxx'
+8292,7803,0,0,2,12,92,292,292,3292,8292,184,185,'YGAAAA','DOLAAA','VVVVxx'
+4696,7804,0,0,6,16,96,696,696,4696,4696,192,193,'QYAAAA','EOLAAA','AAAAxx'
+5641,7805,1,1,1,1,41,641,1641,641,5641,82,83,'ZIAAAA','FOLAAA','HHHHxx'
+9386,7806,0,2,6,6,86,386,1386,4386,9386,172,173,'AXAAAA','GOLAAA','OOOOxx'
+507,7807,1,3,7,7,7,507,507,507,507,14,15,'NTAAAA','HOLAAA','VVVVxx'
+7201,7808,1,1,1,1,1,201,1201,2201,7201,2,3,'ZQAAAA','IOLAAA','AAAAxx'
+7785,7809,1,1,5,5,85,785,1785,2785,7785,170,171,'LNAAAA','JOLAAA','HHHHxx'
+463,7810,1,3,3,3,63,463,463,463,463,126,127,'VRAAAA','KOLAAA','OOOOxx'
+6656,7811,0,0,6,16,56,656,656,1656,6656,112,113,'AWAAAA','LOLAAA','VVVVxx'
+807,7812,1,3,7,7,7,807,807,807,807,14,15,'BFAAAA','MOLAAA','AAAAxx'
+7278,7813,0,2,8,18,78,278,1278,2278,7278,156,157,'YTAAAA','NOLAAA','HHHHxx'
+6237,7814,1,1,7,17,37,237,237,1237,6237,74,75,'XFAAAA','OOLAAA','OOOOxx'
+7671,7815,1,3,1,11,71,671,1671,2671,7671,142,143,'BJAAAA','POLAAA','VVVVxx'
+2235,7816,1,3,5,15,35,235,235,2235,2235,70,71,'ZHAAAA','QOLAAA','AAAAxx'
+4042,7817,0,2,2,2,42,42,42,4042,4042,84,85,'MZAAAA','ROLAAA','HHHHxx'
+5273,7818,1,1,3,13,73,273,1273,273,5273,146,147,'VUAAAA','SOLAAA','OOOOxx'
+7557,7819,1,1,7,17,57,557,1557,2557,7557,114,115,'REAAAA','TOLAAA','VVVVxx'
+4007,7820,1,3,7,7,7,7,7,4007,4007,14,15,'DYAAAA','UOLAAA','AAAAxx'
+1428,7821,0,0,8,8,28,428,1428,1428,1428,56,57,'YCAAAA','VOLAAA','HHHHxx'
+9739,7822,1,3,9,19,39,739,1739,4739,9739,78,79,'PKAAAA','WOLAAA','OOOOxx'
+7836,7823,0,0,6,16,36,836,1836,2836,7836,72,73,'KPAAAA','XOLAAA','VVVVxx'
+1777,7824,1,1,7,17,77,777,1777,1777,1777,154,155,'JQAAAA','YOLAAA','AAAAxx'
+5192,7825,0,0,2,12,92,192,1192,192,5192,184,185,'SRAAAA','ZOLAAA','HHHHxx'
+7236,7826,0,0,6,16,36,236,1236,2236,7236,72,73,'ISAAAA','APLAAA','OOOOxx'
+1623,7827,1,3,3,3,23,623,1623,1623,1623,46,47,'LKAAAA','BPLAAA','VVVVxx'
+8288,7828,0,0,8,8,88,288,288,3288,8288,176,177,'UGAAAA','CPLAAA','AAAAxx'
+2827,7829,1,3,7,7,27,827,827,2827,2827,54,55,'TEAAAA','DPLAAA','HHHHxx'
+458,7830,0,2,8,18,58,458,458,458,458,116,117,'QRAAAA','EPLAAA','OOOOxx'
+1818,7831,0,2,8,18,18,818,1818,1818,1818,36,37,'YRAAAA','FPLAAA','VVVVxx'
+6837,7832,1,1,7,17,37,837,837,1837,6837,74,75,'ZCAAAA','GPLAAA','AAAAxx'
+7825,7833,1,1,5,5,25,825,1825,2825,7825,50,51,'ZOAAAA','HPLAAA','HHHHxx'
+9146,7834,0,2,6,6,46,146,1146,4146,9146,92,93,'UNAAAA','IPLAAA','OOOOxx'
+8451,7835,1,3,1,11,51,451,451,3451,8451,102,103,'BNAAAA','JPLAAA','VVVVxx'
+6438,7836,0,2,8,18,38,438,438,1438,6438,76,77,'QNAAAA','KPLAAA','AAAAxx'
+4020,7837,0,0,0,0,20,20,20,4020,4020,40,41,'QYAAAA','LPLAAA','HHHHxx'
+4068,7838,0,0,8,8,68,68,68,4068,4068,136,137,'MAAAAA','MPLAAA','OOOOxx'
+2411,7839,1,3,1,11,11,411,411,2411,2411,22,23,'TOAAAA','NPLAAA','VVVVxx'
+6222,7840,0,2,2,2,22,222,222,1222,6222,44,45,'IFAAAA','OPLAAA','AAAAxx'
+3164,7841,0,0,4,4,64,164,1164,3164,3164,128,129,'SRAAAA','PPLAAA','HHHHxx'
+311,7842,1,3,1,11,11,311,311,311,311,22,23,'ZLAAAA','QPLAAA','OOOOxx'
+5683,7843,1,3,3,3,83,683,1683,683,5683,166,167,'PKAAAA','RPLAAA','VVVVxx'
+3993,7844,1,1,3,13,93,993,1993,3993,3993,186,187,'PXAAAA','SPLAAA','AAAAxx'
+9897,7845,1,1,7,17,97,897,1897,4897,9897,194,195,'RQAAAA','TPLAAA','HHHHxx'
+6609,7846,1,1,9,9,9,609,609,1609,6609,18,19,'FUAAAA','UPLAAA','OOOOxx'
+1362,7847,0,2,2,2,62,362,1362,1362,1362,124,125,'KAAAAA','VPLAAA','VVVVxx'
+3918,7848,0,2,8,18,18,918,1918,3918,3918,36,37,'SUAAAA','WPLAAA','AAAAxx'
+7376,7849,0,0,6,16,76,376,1376,2376,7376,152,153,'SXAAAA','XPLAAA','HHHHxx'
+6996,7850,0,0,6,16,96,996,996,1996,6996,192,193,'CJAAAA','YPLAAA','OOOOxx'
+9567,7851,1,3,7,7,67,567,1567,4567,9567,134,135,'ZDAAAA','ZPLAAA','VVVVxx'
+7525,7852,1,1,5,5,25,525,1525,2525,7525,50,51,'LDAAAA','AQLAAA','AAAAxx'
+9069,7853,1,1,9,9,69,69,1069,4069,9069,138,139,'VKAAAA','BQLAAA','HHHHxx'
+9999,7854,1,3,9,19,99,999,1999,4999,9999,198,199,'PUAAAA','CQLAAA','OOOOxx'
+9237,7855,1,1,7,17,37,237,1237,4237,9237,74,75,'HRAAAA','DQLAAA','VVVVxx'
+8441,7856,1,1,1,1,41,441,441,3441,8441,82,83,'RMAAAA','EQLAAA','AAAAxx'
+6769,7857,1,1,9,9,69,769,769,1769,6769,138,139,'JAAAAA','FQLAAA','HHHHxx'
+6073,7858,1,1,3,13,73,73,73,1073,6073,146,147,'PZAAAA','GQLAAA','OOOOxx'
+1091,7859,1,3,1,11,91,91,1091,1091,1091,182,183,'ZPAAAA','HQLAAA','VVVVxx'
+9886,7860,0,2,6,6,86,886,1886,4886,9886,172,173,'GQAAAA','IQLAAA','AAAAxx'
+3971,7861,1,3,1,11,71,971,1971,3971,3971,142,143,'TWAAAA','JQLAAA','HHHHxx'
+4621,7862,1,1,1,1,21,621,621,4621,4621,42,43,'TVAAAA','KQLAAA','OOOOxx'
+3120,7863,0,0,0,0,20,120,1120,3120,3120,40,41,'AQAAAA','LQLAAA','VVVVxx'
+9773,7864,1,1,3,13,73,773,1773,4773,9773,146,147,'XLAAAA','MQLAAA','AAAAxx'
+8712,7865,0,0,2,12,12,712,712,3712,8712,24,25,'CXAAAA','NQLAAA','HHHHxx'
+801,7866,1,1,1,1,1,801,801,801,801,2,3,'VEAAAA','OQLAAA','OOOOxx'
+9478,7867,0,2,8,18,78,478,1478,4478,9478,156,157,'OAAAAA','PQLAAA','VVVVxx'
+3466,7868,0,2,6,6,66,466,1466,3466,3466,132,133,'IDAAAA','QQLAAA','AAAAxx'
+6326,7869,0,2,6,6,26,326,326,1326,6326,52,53,'IJAAAA','RQLAAA','HHHHxx'
+1723,7870,1,3,3,3,23,723,1723,1723,1723,46,47,'HOAAAA','SQLAAA','OOOOxx'
+4978,7871,0,2,8,18,78,978,978,4978,4978,156,157,'MJAAAA','TQLAAA','VVVVxx'
+2311,7872,1,3,1,11,11,311,311,2311,2311,22,23,'XKAAAA','UQLAAA','AAAAxx'
+9532,7873,0,0,2,12,32,532,1532,4532,9532,64,65,'QCAAAA','VQLAAA','HHHHxx'
+3680,7874,0,0,0,0,80,680,1680,3680,3680,160,161,'OLAAAA','WQLAAA','OOOOxx'
+1244,7875,0,0,4,4,44,244,1244,1244,1244,88,89,'WVAAAA','XQLAAA','VVVVxx'
+3821,7876,1,1,1,1,21,821,1821,3821,3821,42,43,'ZQAAAA','YQLAAA','AAAAxx'
+9586,7877,0,2,6,6,86,586,1586,4586,9586,172,173,'SEAAAA','ZQLAAA','HHHHxx'
+3894,7878,0,2,4,14,94,894,1894,3894,3894,188,189,'UTAAAA','ARLAAA','OOOOxx'
+6169,7879,1,1,9,9,69,169,169,1169,6169,138,139,'HDAAAA','BRLAAA','VVVVxx'
+5919,7880,1,3,9,19,19,919,1919,919,5919,38,39,'RTAAAA','CRLAAA','AAAAxx'
+4187,7881,1,3,7,7,87,187,187,4187,4187,174,175,'BFAAAA','DRLAAA','HHHHxx'
+5477,7882,1,1,7,17,77,477,1477,477,5477,154,155,'RCAAAA','ERLAAA','OOOOxx'
+2806,7883,0,2,6,6,6,806,806,2806,2806,12,13,'YDAAAA','FRLAAA','VVVVxx'
+8158,7884,0,2,8,18,58,158,158,3158,8158,116,117,'UBAAAA','GRLAAA','AAAAxx'
+7130,7885,0,2,0,10,30,130,1130,2130,7130,60,61,'GOAAAA','HRLAAA','HHHHxx'
+7133,7886,1,1,3,13,33,133,1133,2133,7133,66,67,'JOAAAA','IRLAAA','OOOOxx'
+6033,7887,1,1,3,13,33,33,33,1033,6033,66,67,'BYAAAA','JRLAAA','VVVVxx'
+2415,7888,1,3,5,15,15,415,415,2415,2415,30,31,'XOAAAA','KRLAAA','AAAAxx'
+8091,7889,1,3,1,11,91,91,91,3091,8091,182,183,'FZAAAA','LRLAAA','HHHHxx'
+8347,7890,1,3,7,7,47,347,347,3347,8347,94,95,'BJAAAA','MRLAAA','OOOOxx'
+7879,7891,1,3,9,19,79,879,1879,2879,7879,158,159,'BRAAAA','NRLAAA','VVVVxx'
+9360,7892,0,0,0,0,60,360,1360,4360,9360,120,121,'AWAAAA','ORLAAA','AAAAxx'
+3369,7893,1,1,9,9,69,369,1369,3369,3369,138,139,'PZAAAA','PRLAAA','HHHHxx'
+8536,7894,0,0,6,16,36,536,536,3536,8536,72,73,'IQAAAA','QRLAAA','OOOOxx'
+8628,7895,0,0,8,8,28,628,628,3628,8628,56,57,'WTAAAA','RRLAAA','VVVVxx'
+1580,7896,0,0,0,0,80,580,1580,1580,1580,160,161,'UIAAAA','SRLAAA','AAAAxx'
+705,7897,1,1,5,5,5,705,705,705,705,10,11,'DBAAAA','TRLAAA','HHHHxx'
+4650,7898,0,2,0,10,50,650,650,4650,4650,100,101,'WWAAAA','URLAAA','OOOOxx'
+9165,7899,1,1,5,5,65,165,1165,4165,9165,130,131,'NOAAAA','VRLAAA','VVVVxx'
+4820,7900,0,0,0,0,20,820,820,4820,4820,40,41,'KDAAAA','WRLAAA','AAAAxx'
+3538,7901,0,2,8,18,38,538,1538,3538,3538,76,77,'CGAAAA','XRLAAA','HHHHxx'
+9947,7902,1,3,7,7,47,947,1947,4947,9947,94,95,'PSAAAA','YRLAAA','OOOOxx'
+4954,7903,0,2,4,14,54,954,954,4954,4954,108,109,'OIAAAA','ZRLAAA','VVVVxx'
+1104,7904,0,0,4,4,4,104,1104,1104,1104,8,9,'MQAAAA','ASLAAA','AAAAxx'
+8455,7905,1,3,5,15,55,455,455,3455,8455,110,111,'FNAAAA','BSLAAA','HHHHxx'
+8307,7906,1,3,7,7,7,307,307,3307,8307,14,15,'NHAAAA','CSLAAA','OOOOxx'
+9203,7907,1,3,3,3,3,203,1203,4203,9203,6,7,'ZPAAAA','DSLAAA','VVVVxx'
+7565,7908,1,1,5,5,65,565,1565,2565,7565,130,131,'ZEAAAA','ESLAAA','AAAAxx'
+7745,7909,1,1,5,5,45,745,1745,2745,7745,90,91,'XLAAAA','FSLAAA','HHHHxx'
+1787,7910,1,3,7,7,87,787,1787,1787,1787,174,175,'TQAAAA','GSLAAA','OOOOxx'
+4861,7911,1,1,1,1,61,861,861,4861,4861,122,123,'ZEAAAA','HSLAAA','VVVVxx'
+5183,7912,1,3,3,3,83,183,1183,183,5183,166,167,'JRAAAA','ISLAAA','AAAAxx'
+529,7913,1,1,9,9,29,529,529,529,529,58,59,'JUAAAA','JSLAAA','HHHHxx'
+2470,7914,0,2,0,10,70,470,470,2470,2470,140,141,'ARAAAA','KSLAAA','OOOOxx'
+1267,7915,1,3,7,7,67,267,1267,1267,1267,134,135,'TWAAAA','LSLAAA','VVVVxx'
+2059,7916,1,3,9,19,59,59,59,2059,2059,118,119,'FBAAAA','MSLAAA','AAAAxx'
+1862,7917,0,2,2,2,62,862,1862,1862,1862,124,125,'QTAAAA','NSLAAA','HHHHxx'
+7382,7918,0,2,2,2,82,382,1382,2382,7382,164,165,'YXAAAA','OSLAAA','OOOOxx'
+4796,7919,0,0,6,16,96,796,796,4796,4796,192,193,'MCAAAA','PSLAAA','VVVVxx'
+2331,7920,1,3,1,11,31,331,331,2331,2331,62,63,'RLAAAA','QSLAAA','AAAAxx'
+8870,7921,0,2,0,10,70,870,870,3870,8870,140,141,'EDAAAA','RSLAAA','HHHHxx'
+9581,7922,1,1,1,1,81,581,1581,4581,9581,162,163,'NEAAAA','SSLAAA','OOOOxx'
+9063,7923,1,3,3,3,63,63,1063,4063,9063,126,127,'PKAAAA','TSLAAA','VVVVxx'
+2192,7924,0,0,2,12,92,192,192,2192,2192,184,185,'IGAAAA','USLAAA','AAAAxx'
+6466,7925,0,2,6,6,66,466,466,1466,6466,132,133,'SOAAAA','VSLAAA','HHHHxx'
+7096,7926,0,0,6,16,96,96,1096,2096,7096,192,193,'YMAAAA','WSLAAA','OOOOxx'
+6257,7927,1,1,7,17,57,257,257,1257,6257,114,115,'RGAAAA','XSLAAA','VVVVxx'
+7009,7928,1,1,9,9,9,9,1009,2009,7009,18,19,'PJAAAA','YSLAAA','AAAAxx'
+8136,7929,0,0,6,16,36,136,136,3136,8136,72,73,'YAAAAA','ZSLAAA','HHHHxx'
+1854,7930,0,2,4,14,54,854,1854,1854,1854,108,109,'ITAAAA','ATLAAA','OOOOxx'
+3644,7931,0,0,4,4,44,644,1644,3644,3644,88,89,'EKAAAA','BTLAAA','VVVVxx'
+4437,7932,1,1,7,17,37,437,437,4437,4437,74,75,'ROAAAA','CTLAAA','AAAAxx'
+7209,7933,1,1,9,9,9,209,1209,2209,7209,18,19,'HRAAAA','DTLAAA','HHHHxx'
+1516,7934,0,0,6,16,16,516,1516,1516,1516,32,33,'IGAAAA','ETLAAA','OOOOxx'
+822,7935,0,2,2,2,22,822,822,822,822,44,45,'QFAAAA','FTLAAA','VVVVxx'
+1778,7936,0,2,8,18,78,778,1778,1778,1778,156,157,'KQAAAA','GTLAAA','AAAAxx'
+8161,7937,1,1,1,1,61,161,161,3161,8161,122,123,'XBAAAA','HTLAAA','HHHHxx'
+6030,7938,0,2,0,10,30,30,30,1030,6030,60,61,'YXAAAA','ITLAAA','OOOOxx'
+3515,7939,1,3,5,15,15,515,1515,3515,3515,30,31,'FFAAAA','JTLAAA','VVVVxx'
+1702,7940,0,2,2,2,2,702,1702,1702,1702,4,5,'MNAAAA','KTLAAA','AAAAxx'
+2671,7941,1,3,1,11,71,671,671,2671,2671,142,143,'TYAAAA','LTLAAA','HHHHxx'
+7623,7942,1,3,3,3,23,623,1623,2623,7623,46,47,'FHAAAA','MTLAAA','OOOOxx'
+9828,7943,0,0,8,8,28,828,1828,4828,9828,56,57,'AOAAAA','NTLAAA','VVVVxx'
+1888,7944,0,0,8,8,88,888,1888,1888,1888,176,177,'QUAAAA','OTLAAA','AAAAxx'
+4520,7945,0,0,0,0,20,520,520,4520,4520,40,41,'WRAAAA','PTLAAA','HHHHxx'
+3461,7946,1,1,1,1,61,461,1461,3461,3461,122,123,'DDAAAA','QTLAAA','OOOOxx'
+1488,7947,0,0,8,8,88,488,1488,1488,1488,176,177,'GFAAAA','RTLAAA','VVVVxx'
+7753,7948,1,1,3,13,53,753,1753,2753,7753,106,107,'FMAAAA','STLAAA','AAAAxx'
+5525,7949,1,1,5,5,25,525,1525,525,5525,50,51,'NEAAAA','TTLAAA','HHHHxx'
+5220,7950,0,0,0,0,20,220,1220,220,5220,40,41,'USAAAA','UTLAAA','OOOOxx'
+305,7951,1,1,5,5,5,305,305,305,305,10,11,'TLAAAA','VTLAAA','VVVVxx'
+7883,7952,1,3,3,3,83,883,1883,2883,7883,166,167,'FRAAAA','WTLAAA','AAAAxx'
+1222,7953,0,2,2,2,22,222,1222,1222,1222,44,45,'AVAAAA','XTLAAA','HHHHxx'
+8552,7954,0,0,2,12,52,552,552,3552,8552,104,105,'YQAAAA','YTLAAA','OOOOxx'
+6097,7955,1,1,7,17,97,97,97,1097,6097,194,195,'NAAAAA','ZTLAAA','VVVVxx'
+2298,7956,0,2,8,18,98,298,298,2298,2298,196,197,'KKAAAA','AULAAA','AAAAxx'
+956,7957,0,0,6,16,56,956,956,956,956,112,113,'UKAAAA','BULAAA','HHHHxx'
+9351,7958,1,3,1,11,51,351,1351,4351,9351,102,103,'RVAAAA','CULAAA','OOOOxx'
+6669,7959,1,1,9,9,69,669,669,1669,6669,138,139,'NWAAAA','DULAAA','VVVVxx'
+9383,7960,1,3,3,3,83,383,1383,4383,9383,166,167,'XWAAAA','EULAAA','AAAAxx'
+1607,7961,1,3,7,7,7,607,1607,1607,1607,14,15,'VJAAAA','FULAAA','HHHHxx'
+812,7962,0,0,2,12,12,812,812,812,812,24,25,'GFAAAA','GULAAA','OOOOxx'
+2109,7963,1,1,9,9,9,109,109,2109,2109,18,19,'DDAAAA','HULAAA','VVVVxx'
+207,7964,1,3,7,7,7,207,207,207,207,14,15,'ZHAAAA','IULAAA','AAAAxx'
+7124,7965,0,0,4,4,24,124,1124,2124,7124,48,49,'AOAAAA','JULAAA','HHHHxx'
+9333,7966,1,1,3,13,33,333,1333,4333,9333,66,67,'ZUAAAA','KULAAA','OOOOxx'
+3262,7967,0,2,2,2,62,262,1262,3262,3262,124,125,'MVAAAA','LULAAA','VVVVxx'
+1070,7968,0,2,0,10,70,70,1070,1070,1070,140,141,'EPAAAA','MULAAA','AAAAxx'
+7579,7969,1,3,9,19,79,579,1579,2579,7579,158,159,'NFAAAA','NULAAA','HHHHxx'
+9283,7970,1,3,3,3,83,283,1283,4283,9283,166,167,'BTAAAA','OULAAA','OOOOxx'
+4917,7971,1,1,7,17,17,917,917,4917,4917,34,35,'DHAAAA','PULAAA','VVVVxx'
+1328,7972,0,0,8,8,28,328,1328,1328,1328,56,57,'CZAAAA','QULAAA','AAAAxx'
+3042,7973,0,2,2,2,42,42,1042,3042,3042,84,85,'ANAAAA','RULAAA','HHHHxx'
+8352,7974,0,0,2,12,52,352,352,3352,8352,104,105,'GJAAAA','SULAAA','OOOOxx'
+2710,7975,0,2,0,10,10,710,710,2710,2710,20,21,'GAAAAA','TULAAA','VVVVxx'
+3330,7976,0,2,0,10,30,330,1330,3330,3330,60,61,'CYAAAA','UULAAA','AAAAxx'
+2822,7977,0,2,2,2,22,822,822,2822,2822,44,45,'OEAAAA','VULAAA','HHHHxx'
+5627,7978,1,3,7,7,27,627,1627,627,5627,54,55,'LIAAAA','WULAAA','OOOOxx'
+7848,7979,0,0,8,8,48,848,1848,2848,7848,96,97,'WPAAAA','XULAAA','VVVVxx'
+7384,7980,0,0,4,4,84,384,1384,2384,7384,168,169,'AYAAAA','YULAAA','AAAAxx'
+727,7981,1,3,7,7,27,727,727,727,727,54,55,'ZBAAAA','ZULAAA','HHHHxx'
+9926,7982,0,2,6,6,26,926,1926,4926,9926,52,53,'URAAAA','AVLAAA','OOOOxx'
+2647,7983,1,3,7,7,47,647,647,2647,2647,94,95,'VXAAAA','BVLAAA','VVVVxx'
+6416,7984,0,0,6,16,16,416,416,1416,6416,32,33,'UMAAAA','CVLAAA','AAAAxx'
+8751,7985,1,3,1,11,51,751,751,3751,8751,102,103,'PYAAAA','DVLAAA','HHHHxx'
+6515,7986,1,3,5,15,15,515,515,1515,6515,30,31,'PQAAAA','EVLAAA','OOOOxx'
+2472,7987,0,0,2,12,72,472,472,2472,2472,144,145,'CRAAAA','FVLAAA','VVVVxx'
+7205,7988,1,1,5,5,5,205,1205,2205,7205,10,11,'DRAAAA','GVLAAA','AAAAxx'
+9654,7989,0,2,4,14,54,654,1654,4654,9654,108,109,'IHAAAA','HVLAAA','HHHHxx'
+5646,7990,0,2,6,6,46,646,1646,646,5646,92,93,'EJAAAA','IVLAAA','OOOOxx'
+4217,7991,1,1,7,17,17,217,217,4217,4217,34,35,'FGAAAA','JVLAAA','VVVVxx'
+4484,7992,0,0,4,4,84,484,484,4484,4484,168,169,'MQAAAA','KVLAAA','AAAAxx'
+6654,7993,0,2,4,14,54,654,654,1654,6654,108,109,'YVAAAA','LVLAAA','HHHHxx'
+4876,7994,0,0,6,16,76,876,876,4876,4876,152,153,'OFAAAA','MVLAAA','OOOOxx'
+9690,7995,0,2,0,10,90,690,1690,4690,9690,180,181,'SIAAAA','NVLAAA','VVVVxx'
+2453,7996,1,1,3,13,53,453,453,2453,2453,106,107,'JQAAAA','OVLAAA','AAAAxx'
+829,7997,1,1,9,9,29,829,829,829,829,58,59,'XFAAAA','PVLAAA','HHHHxx'
+2547,7998,1,3,7,7,47,547,547,2547,2547,94,95,'ZTAAAA','QVLAAA','OOOOxx'
+9726,7999,0,2,6,6,26,726,1726,4726,9726,52,53,'CKAAAA','RVLAAA','VVVVxx'
+9267,8000,1,3,7,7,67,267,1267,4267,9267,134,135,'LSAAAA','SVLAAA','AAAAxx'
+7448,8001,0,0,8,8,48,448,1448,2448,7448,96,97,'MAAAAA','TVLAAA','HHHHxx'
+610,8002,0,2,0,10,10,610,610,610,610,20,21,'MXAAAA','UVLAAA','OOOOxx'
+2791,8003,1,3,1,11,91,791,791,2791,2791,182,183,'JDAAAA','VVLAAA','VVVVxx'
+3651,8004,1,3,1,11,51,651,1651,3651,3651,102,103,'LKAAAA','WVLAAA','AAAAxx'
+5206,8005,0,2,6,6,6,206,1206,206,5206,12,13,'GSAAAA','XVLAAA','HHHHxx'
+8774,8006,0,2,4,14,74,774,774,3774,8774,148,149,'MZAAAA','YVLAAA','OOOOxx'
+4753,8007,1,1,3,13,53,753,753,4753,4753,106,107,'VAAAAA','ZVLAAA','VVVVxx'
+4755,8008,1,3,5,15,55,755,755,4755,4755,110,111,'XAAAAA','AWLAAA','AAAAxx'
+686,8009,0,2,6,6,86,686,686,686,686,172,173,'KAAAAA','BWLAAA','HHHHxx'
+8281,8010,1,1,1,1,81,281,281,3281,8281,162,163,'NGAAAA','CWLAAA','OOOOxx'
+2058,8011,0,2,8,18,58,58,58,2058,2058,116,117,'EBAAAA','DWLAAA','VVVVxx'
+8900,8012,0,0,0,0,0,900,900,3900,8900,0,1,'IEAAAA','EWLAAA','AAAAxx'
+8588,8013,0,0,8,8,88,588,588,3588,8588,176,177,'ISAAAA','FWLAAA','HHHHxx'
+2904,8014,0,0,4,4,4,904,904,2904,2904,8,9,'SHAAAA','GWLAAA','OOOOxx'
+8917,8015,1,1,7,17,17,917,917,3917,8917,34,35,'ZEAAAA','HWLAAA','VVVVxx'
+9026,8016,0,2,6,6,26,26,1026,4026,9026,52,53,'EJAAAA','IWLAAA','AAAAxx'
+2416,8017,0,0,6,16,16,416,416,2416,2416,32,33,'YOAAAA','JWLAAA','HHHHxx'
+1053,8018,1,1,3,13,53,53,1053,1053,1053,106,107,'NOAAAA','KWLAAA','OOOOxx'
+7141,8019,1,1,1,1,41,141,1141,2141,7141,82,83,'ROAAAA','LWLAAA','VVVVxx'
+9771,8020,1,3,1,11,71,771,1771,4771,9771,142,143,'VLAAAA','MWLAAA','AAAAxx'
+2774,8021,0,2,4,14,74,774,774,2774,2774,148,149,'SCAAAA','NWLAAA','HHHHxx'
+3213,8022,1,1,3,13,13,213,1213,3213,3213,26,27,'PTAAAA','OWLAAA','OOOOxx'
+5694,8023,0,2,4,14,94,694,1694,694,5694,188,189,'ALAAAA','PWLAAA','VVVVxx'
+6631,8024,1,3,1,11,31,631,631,1631,6631,62,63,'BVAAAA','QWLAAA','AAAAxx'
+6638,8025,0,2,8,18,38,638,638,1638,6638,76,77,'IVAAAA','RWLAAA','HHHHxx'
+7407,8026,1,3,7,7,7,407,1407,2407,7407,14,15,'XYAAAA','SWLAAA','OOOOxx'
+8972,8027,0,0,2,12,72,972,972,3972,8972,144,145,'CHAAAA','TWLAAA','VVVVxx'
+2202,8028,0,2,2,2,2,202,202,2202,2202,4,5,'SGAAAA','UWLAAA','AAAAxx'
+6135,8029,1,3,5,15,35,135,135,1135,6135,70,71,'ZBAAAA','VWLAAA','HHHHxx'
+5043,8030,1,3,3,3,43,43,1043,43,5043,86,87,'ZLAAAA','WWLAAA','OOOOxx'
+5163,8031,1,3,3,3,63,163,1163,163,5163,126,127,'PQAAAA','XWLAAA','VVVVxx'
+1191,8032,1,3,1,11,91,191,1191,1191,1191,182,183,'VTAAAA','YWLAAA','AAAAxx'
+6576,8033,0,0,6,16,76,576,576,1576,6576,152,153,'YSAAAA','ZWLAAA','HHHHxx'
+3455,8034,1,3,5,15,55,455,1455,3455,3455,110,111,'XCAAAA','AXLAAA','OOOOxx'
+3688,8035,0,0,8,8,88,688,1688,3688,3688,176,177,'WLAAAA','BXLAAA','VVVVxx'
+4982,8036,0,2,2,2,82,982,982,4982,4982,164,165,'QJAAAA','CXLAAA','AAAAxx'
+4180,8037,0,0,0,0,80,180,180,4180,4180,160,161,'UEAAAA','DXLAAA','HHHHxx'
+4708,8038,0,0,8,8,8,708,708,4708,4708,16,17,'CZAAAA','EXLAAA','OOOOxx'
+1241,8039,1,1,1,1,41,241,1241,1241,1241,82,83,'TVAAAA','FXLAAA','VVVVxx'
+4921,8040,1,1,1,1,21,921,921,4921,4921,42,43,'HHAAAA','GXLAAA','AAAAxx'
+3197,8041,1,1,7,17,97,197,1197,3197,3197,194,195,'ZSAAAA','HXLAAA','HHHHxx'
+8225,8042,1,1,5,5,25,225,225,3225,8225,50,51,'JEAAAA','IXLAAA','OOOOxx'
+5913,8043,1,1,3,13,13,913,1913,913,5913,26,27,'LTAAAA','JXLAAA','VVVVxx'
+6387,8044,1,3,7,7,87,387,387,1387,6387,174,175,'RLAAAA','KXLAAA','AAAAxx'
+2706,8045,0,2,6,6,6,706,706,2706,2706,12,13,'CAAAAA','LXLAAA','HHHHxx'
+1461,8046,1,1,1,1,61,461,1461,1461,1461,122,123,'FEAAAA','MXLAAA','OOOOxx'
+7646,8047,0,2,6,6,46,646,1646,2646,7646,92,93,'CIAAAA','NXLAAA','VVVVxx'
+8066,8048,0,2,6,6,66,66,66,3066,8066,132,133,'GYAAAA','OXLAAA','AAAAxx'
+4171,8049,1,3,1,11,71,171,171,4171,4171,142,143,'LEAAAA','PXLAAA','HHHHxx'
+8008,8050,0,0,8,8,8,8,8,3008,8008,16,17,'AWAAAA','QXLAAA','OOOOxx'
+2088,8051,0,0,8,8,88,88,88,2088,2088,176,177,'ICAAAA','RXLAAA','VVVVxx'
+7907,8052,1,3,7,7,7,907,1907,2907,7907,14,15,'DSAAAA','SXLAAA','AAAAxx'
+2429,8053,1,1,9,9,29,429,429,2429,2429,58,59,'LPAAAA','TXLAAA','HHHHxx'
+9629,8054,1,1,9,9,29,629,1629,4629,9629,58,59,'JGAAAA','UXLAAA','OOOOxx'
+1470,8055,0,2,0,10,70,470,1470,1470,1470,140,141,'OEAAAA','VXLAAA','VVVVxx'
+4346,8056,0,2,6,6,46,346,346,4346,4346,92,93,'ELAAAA','WXLAAA','AAAAxx'
+7219,8057,1,3,9,19,19,219,1219,2219,7219,38,39,'RRAAAA','XXLAAA','HHHHxx'
+1185,8058,1,1,5,5,85,185,1185,1185,1185,170,171,'PTAAAA','YXLAAA','OOOOxx'
+8776,8059,0,0,6,16,76,776,776,3776,8776,152,153,'OZAAAA','ZXLAAA','VVVVxx'
+684,8060,0,0,4,4,84,684,684,684,684,168,169,'IAAAAA','AYLAAA','AAAAxx'
+2343,8061,1,3,3,3,43,343,343,2343,2343,86,87,'DMAAAA','BYLAAA','HHHHxx'
+4470,8062,0,2,0,10,70,470,470,4470,4470,140,141,'YPAAAA','CYLAAA','OOOOxx'
+5116,8063,0,0,6,16,16,116,1116,116,5116,32,33,'UOAAAA','DYLAAA','VVVVxx'
+1746,8064,0,2,6,6,46,746,1746,1746,1746,92,93,'EPAAAA','EYLAAA','AAAAxx'
+3216,8065,0,0,6,16,16,216,1216,3216,3216,32,33,'STAAAA','FYLAAA','HHHHxx'
+4594,8066,0,2,4,14,94,594,594,4594,4594,188,189,'SUAAAA','GYLAAA','OOOOxx'
+3013,8067,1,1,3,13,13,13,1013,3013,3013,26,27,'XLAAAA','HYLAAA','VVVVxx'
+2307,8068,1,3,7,7,7,307,307,2307,2307,14,15,'TKAAAA','IYLAAA','AAAAxx'
+7663,8069,1,3,3,3,63,663,1663,2663,7663,126,127,'TIAAAA','JYLAAA','HHHHxx'
+8504,8070,0,0,4,4,4,504,504,3504,8504,8,9,'CPAAAA','KYLAAA','OOOOxx'
+3683,8071,1,3,3,3,83,683,1683,3683,3683,166,167,'RLAAAA','LYLAAA','VVVVxx'
+144,8072,0,0,4,4,44,144,144,144,144,88,89,'OFAAAA','MYLAAA','AAAAxx'
+203,8073,1,3,3,3,3,203,203,203,203,6,7,'VHAAAA','NYLAAA','HHHHxx'
+5255,8074,1,3,5,15,55,255,1255,255,5255,110,111,'DUAAAA','OYLAAA','OOOOxx'
+4150,8075,0,2,0,10,50,150,150,4150,4150,100,101,'QDAAAA','PYLAAA','VVVVxx'
+5701,8076,1,1,1,1,1,701,1701,701,5701,2,3,'HLAAAA','QYLAAA','AAAAxx'
+7400,8077,0,0,0,0,0,400,1400,2400,7400,0,1,'QYAAAA','RYLAAA','HHHHxx'
+8203,8078,1,3,3,3,3,203,203,3203,8203,6,7,'NDAAAA','SYLAAA','OOOOxx'
+637,8079,1,1,7,17,37,637,637,637,637,74,75,'NYAAAA','TYLAAA','VVVVxx'
+2898,8080,0,2,8,18,98,898,898,2898,2898,196,197,'MHAAAA','UYLAAA','AAAAxx'
+1110,8081,0,2,0,10,10,110,1110,1110,1110,20,21,'SQAAAA','VYLAAA','HHHHxx'
+6255,8082,1,3,5,15,55,255,255,1255,6255,110,111,'PGAAAA','WYLAAA','OOOOxx'
+1071,8083,1,3,1,11,71,71,1071,1071,1071,142,143,'FPAAAA','XYLAAA','VVVVxx'
+541,8084,1,1,1,1,41,541,541,541,541,82,83,'VUAAAA','YYLAAA','AAAAxx'
+8077,8085,1,1,7,17,77,77,77,3077,8077,154,155,'RYAAAA','ZYLAAA','HHHHxx'
+6809,8086,1,1,9,9,9,809,809,1809,6809,18,19,'XBAAAA','AZLAAA','OOOOxx'
+4749,8087,1,1,9,9,49,749,749,4749,4749,98,99,'RAAAAA','BZLAAA','VVVVxx'
+2886,8088,0,2,6,6,86,886,886,2886,2886,172,173,'AHAAAA','CZLAAA','AAAAxx'
+5510,8089,0,2,0,10,10,510,1510,510,5510,20,21,'YDAAAA','DZLAAA','HHHHxx'
+713,8090,1,1,3,13,13,713,713,713,713,26,27,'LBAAAA','EZLAAA','OOOOxx'
+8388,8091,0,0,8,8,88,388,388,3388,8388,176,177,'QKAAAA','FZLAAA','VVVVxx'
+9524,8092,0,0,4,4,24,524,1524,4524,9524,48,49,'ICAAAA','GZLAAA','AAAAxx'
+9949,8093,1,1,9,9,49,949,1949,4949,9949,98,99,'RSAAAA','HZLAAA','HHHHxx'
+885,8094,1,1,5,5,85,885,885,885,885,170,171,'BIAAAA','IZLAAA','OOOOxx'
+8699,8095,1,3,9,19,99,699,699,3699,8699,198,199,'PWAAAA','JZLAAA','VVVVxx'
+2232,8096,0,0,2,12,32,232,232,2232,2232,64,65,'WHAAAA','KZLAAA','AAAAxx'
+5142,8097,0,2,2,2,42,142,1142,142,5142,84,85,'UPAAAA','LZLAAA','HHHHxx'
+8891,8098,1,3,1,11,91,891,891,3891,8891,182,183,'ZDAAAA','MZLAAA','OOOOxx'
+1881,8099,1,1,1,1,81,881,1881,1881,1881,162,163,'JUAAAA','NZLAAA','VVVVxx'
+3751,8100,1,3,1,11,51,751,1751,3751,3751,102,103,'HOAAAA','OZLAAA','AAAAxx'
+1896,8101,0,0,6,16,96,896,1896,1896,1896,192,193,'YUAAAA','PZLAAA','HHHHxx'
+8258,8102,0,2,8,18,58,258,258,3258,8258,116,117,'QFAAAA','QZLAAA','OOOOxx'
+3820,8103,0,0,0,0,20,820,1820,3820,3820,40,41,'YQAAAA','RZLAAA','VVVVxx'
+6617,8104,1,1,7,17,17,617,617,1617,6617,34,35,'NUAAAA','SZLAAA','AAAAxx'
+5100,8105,0,0,0,0,0,100,1100,100,5100,0,1,'EOAAAA','TZLAAA','HHHHxx'
+4277,8106,1,1,7,17,77,277,277,4277,4277,154,155,'NIAAAA','UZLAAA','OOOOxx'
+2498,8107,0,2,8,18,98,498,498,2498,2498,196,197,'CSAAAA','VZLAAA','VVVVxx'
+4343,8108,1,3,3,3,43,343,343,4343,4343,86,87,'BLAAAA','WZLAAA','AAAAxx'
+8319,8109,1,3,9,19,19,319,319,3319,8319,38,39,'ZHAAAA','XZLAAA','HHHHxx'
+4803,8110,1,3,3,3,3,803,803,4803,4803,6,7,'TCAAAA','YZLAAA','OOOOxx'
+3100,8111,0,0,0,0,0,100,1100,3100,3100,0,1,'GPAAAA','ZZLAAA','VVVVxx'
+428,8112,0,0,8,8,28,428,428,428,428,56,57,'MQAAAA','AAMAAA','AAAAxx'
+2811,8113,1,3,1,11,11,811,811,2811,2811,22,23,'DEAAAA','BAMAAA','HHHHxx'
+2989,8114,1,1,9,9,89,989,989,2989,2989,178,179,'ZKAAAA','CAMAAA','OOOOxx'
+1100,8115,0,0,0,0,0,100,1100,1100,1100,0,1,'IQAAAA','DAMAAA','VVVVxx'
+6586,8116,0,2,6,6,86,586,586,1586,6586,172,173,'ITAAAA','EAMAAA','AAAAxx'
+3124,8117,0,0,4,4,24,124,1124,3124,3124,48,49,'EQAAAA','FAMAAA','HHHHxx'
+1635,8118,1,3,5,15,35,635,1635,1635,1635,70,71,'XKAAAA','GAMAAA','OOOOxx'
+3888,8119,0,0,8,8,88,888,1888,3888,3888,176,177,'OTAAAA','HAMAAA','VVVVxx'
+8369,8120,1,1,9,9,69,369,369,3369,8369,138,139,'XJAAAA','IAMAAA','AAAAxx'
+3148,8121,0,0,8,8,48,148,1148,3148,3148,96,97,'CRAAAA','JAMAAA','HHHHxx'
+2842,8122,0,2,2,2,42,842,842,2842,2842,84,85,'IFAAAA','KAMAAA','OOOOxx'
+4965,8123,1,1,5,5,65,965,965,4965,4965,130,131,'ZIAAAA','LAMAAA','VVVVxx'
+3742,8124,0,2,2,2,42,742,1742,3742,3742,84,85,'YNAAAA','MAMAAA','AAAAxx'
+5196,8125,0,0,6,16,96,196,1196,196,5196,192,193,'WRAAAA','NAMAAA','HHHHxx'
+9105,8126,1,1,5,5,5,105,1105,4105,9105,10,11,'FMAAAA','OAMAAA','OOOOxx'
+6806,8127,0,2,6,6,6,806,806,1806,6806,12,13,'UBAAAA','PAMAAA','VVVVxx'
+5849,8128,1,1,9,9,49,849,1849,849,5849,98,99,'ZQAAAA','QAMAAA','AAAAxx'
+6504,8129,0,0,4,4,4,504,504,1504,6504,8,9,'EQAAAA','RAMAAA','HHHHxx'
+9841,8130,1,1,1,1,41,841,1841,4841,9841,82,83,'NOAAAA','SAMAAA','OOOOxx'
+457,8131,1,1,7,17,57,457,457,457,457,114,115,'PRAAAA','TAMAAA','VVVVxx'
+8856,8132,0,0,6,16,56,856,856,3856,8856,112,113,'QCAAAA','UAMAAA','AAAAxx'
+8043,8133,1,3,3,3,43,43,43,3043,8043,86,87,'JXAAAA','VAMAAA','HHHHxx'
+5933,8134,1,1,3,13,33,933,1933,933,5933,66,67,'FUAAAA','WAMAAA','OOOOxx'
+5725,8135,1,1,5,5,25,725,1725,725,5725,50,51,'FMAAAA','XAMAAA','VVVVxx'
+8607,8136,1,3,7,7,7,607,607,3607,8607,14,15,'BTAAAA','YAMAAA','AAAAxx'
+9280,8137,0,0,0,0,80,280,1280,4280,9280,160,161,'YSAAAA','ZAMAAA','HHHHxx'
+6017,8138,1,1,7,17,17,17,17,1017,6017,34,35,'LXAAAA','ABMAAA','OOOOxx'
+4946,8139,0,2,6,6,46,946,946,4946,4946,92,93,'GIAAAA','BBMAAA','VVVVxx'
+7373,8140,1,1,3,13,73,373,1373,2373,7373,146,147,'PXAAAA','CBMAAA','AAAAxx'
+8096,8141,0,0,6,16,96,96,96,3096,8096,192,193,'KZAAAA','DBMAAA','HHHHxx'
+3178,8142,0,2,8,18,78,178,1178,3178,3178,156,157,'GSAAAA','EBMAAA','OOOOxx'
+1849,8143,1,1,9,9,49,849,1849,1849,1849,98,99,'DTAAAA','FBMAAA','VVVVxx'
+8813,8144,1,1,3,13,13,813,813,3813,8813,26,27,'ZAAAAA','GBMAAA','AAAAxx'
+460,8145,0,0,0,0,60,460,460,460,460,120,121,'SRAAAA','HBMAAA','HHHHxx'
+7756,8146,0,0,6,16,56,756,1756,2756,7756,112,113,'IMAAAA','IBMAAA','OOOOxx'
+4425,8147,1,1,5,5,25,425,425,4425,4425,50,51,'FOAAAA','JBMAAA','VVVVxx'
+1602,8148,0,2,2,2,2,602,1602,1602,1602,4,5,'QJAAAA','KBMAAA','AAAAxx'
+5981,8149,1,1,1,1,81,981,1981,981,5981,162,163,'BWAAAA','LBMAAA','HHHHxx'
+8139,8150,1,3,9,19,39,139,139,3139,8139,78,79,'BBAAAA','MBMAAA','OOOOxx'
+754,8151,0,2,4,14,54,754,754,754,754,108,109,'ADAAAA','NBMAAA','VVVVxx'
+26,8152,0,2,6,6,26,26,26,26,26,52,53,'ABAAAA','OBMAAA','AAAAxx'
+106,8153,0,2,6,6,6,106,106,106,106,12,13,'CEAAAA','PBMAAA','HHHHxx'
+7465,8154,1,1,5,5,65,465,1465,2465,7465,130,131,'DBAAAA','QBMAAA','OOOOxx'
+1048,8155,0,0,8,8,48,48,1048,1048,1048,96,97,'IOAAAA','RBMAAA','VVVVxx'
+2303,8156,1,3,3,3,3,303,303,2303,2303,6,7,'PKAAAA','SBMAAA','AAAAxx'
+5794,8157,0,2,4,14,94,794,1794,794,5794,188,189,'WOAAAA','TBMAAA','HHHHxx'
+3321,8158,1,1,1,1,21,321,1321,3321,3321,42,43,'TXAAAA','UBMAAA','OOOOxx'
+6122,8159,0,2,2,2,22,122,122,1122,6122,44,45,'MBAAAA','VBMAAA','VVVVxx'
+6474,8160,0,2,4,14,74,474,474,1474,6474,148,149,'APAAAA','WBMAAA','AAAAxx'
+827,8161,1,3,7,7,27,827,827,827,827,54,55,'VFAAAA','XBMAAA','HHHHxx'
+6616,8162,0,0,6,16,16,616,616,1616,6616,32,33,'MUAAAA','YBMAAA','OOOOxx'
+2131,8163,1,3,1,11,31,131,131,2131,2131,62,63,'ZDAAAA','ZBMAAA','VVVVxx'
+5483,8164,1,3,3,3,83,483,1483,483,5483,166,167,'XCAAAA','ACMAAA','AAAAxx'
+606,8165,0,2,6,6,6,606,606,606,606,12,13,'IXAAAA','BCMAAA','HHHHxx'
+922,8166,0,2,2,2,22,922,922,922,922,44,45,'MJAAAA','CCMAAA','OOOOxx'
+8475,8167,1,3,5,15,75,475,475,3475,8475,150,151,'ZNAAAA','DCMAAA','VVVVxx'
+7645,8168,1,1,5,5,45,645,1645,2645,7645,90,91,'BIAAAA','ECMAAA','AAAAxx'
+5097,8169,1,1,7,17,97,97,1097,97,5097,194,195,'BOAAAA','FCMAAA','HHHHxx'
+5377,8170,1,1,7,17,77,377,1377,377,5377,154,155,'VYAAAA','GCMAAA','OOOOxx'
+6116,8171,0,0,6,16,16,116,116,1116,6116,32,33,'GBAAAA','HCMAAA','VVVVxx'
+8674,8172,0,2,4,14,74,674,674,3674,8674,148,149,'QVAAAA','ICMAAA','AAAAxx'
+8063,8173,1,3,3,3,63,63,63,3063,8063,126,127,'DYAAAA','JCMAAA','HHHHxx'
+5271,8174,1,3,1,11,71,271,1271,271,5271,142,143,'TUAAAA','KCMAAA','OOOOxx'
+1619,8175,1,3,9,19,19,619,1619,1619,1619,38,39,'HKAAAA','LCMAAA','VVVVxx'
+6419,8176,1,3,9,19,19,419,419,1419,6419,38,39,'XMAAAA','MCMAAA','AAAAxx'
+7651,8177,1,3,1,11,51,651,1651,2651,7651,102,103,'HIAAAA','NCMAAA','HHHHxx'
+2897,8178,1,1,7,17,97,897,897,2897,2897,194,195,'LHAAAA','OCMAAA','OOOOxx'
+8148,8179,0,0,8,8,48,148,148,3148,8148,96,97,'KBAAAA','PCMAAA','VVVVxx'
+7461,8180,1,1,1,1,61,461,1461,2461,7461,122,123,'ZAAAAA','QCMAAA','AAAAxx'
+9186,8181,0,2,6,6,86,186,1186,4186,9186,172,173,'IPAAAA','RCMAAA','HHHHxx'
+7127,8182,1,3,7,7,27,127,1127,2127,7127,54,55,'DOAAAA','SCMAAA','OOOOxx'
+8233,8183,1,1,3,13,33,233,233,3233,8233,66,67,'REAAAA','TCMAAA','VVVVxx'
+9651,8184,1,3,1,11,51,651,1651,4651,9651,102,103,'FHAAAA','UCMAAA','AAAAxx'
+6746,8185,0,2,6,6,46,746,746,1746,6746,92,93,'MZAAAA','VCMAAA','HHHHxx'
+7835,8186,1,3,5,15,35,835,1835,2835,7835,70,71,'JPAAAA','WCMAAA','OOOOxx'
+8815,8187,1,3,5,15,15,815,815,3815,8815,30,31,'BBAAAA','XCMAAA','VVVVxx'
+6398,8188,0,2,8,18,98,398,398,1398,6398,196,197,'CMAAAA','YCMAAA','AAAAxx'
+5344,8189,0,0,4,4,44,344,1344,344,5344,88,89,'OXAAAA','ZCMAAA','HHHHxx'
+8209,8190,1,1,9,9,9,209,209,3209,8209,18,19,'TDAAAA','ADMAAA','OOOOxx'
+8444,8191,0,0,4,4,44,444,444,3444,8444,88,89,'UMAAAA','BDMAAA','VVVVxx'
+5669,8192,1,1,9,9,69,669,1669,669,5669,138,139,'BKAAAA','CDMAAA','AAAAxx'
+2455,8193,1,3,5,15,55,455,455,2455,2455,110,111,'LQAAAA','DDMAAA','HHHHxx'
+6767,8194,1,3,7,7,67,767,767,1767,6767,134,135,'HAAAAA','EDMAAA','OOOOxx'
+135,8195,1,3,5,15,35,135,135,135,135,70,71,'FFAAAA','FDMAAA','VVVVxx'
+3503,8196,1,3,3,3,3,503,1503,3503,3503,6,7,'TEAAAA','GDMAAA','AAAAxx'
+6102,8197,0,2,2,2,2,102,102,1102,6102,4,5,'SAAAAA','HDMAAA','HHHHxx'
+7136,8198,0,0,6,16,36,136,1136,2136,7136,72,73,'MOAAAA','IDMAAA','OOOOxx'
+4933,8199,1,1,3,13,33,933,933,4933,4933,66,67,'THAAAA','JDMAAA','VVVVxx'
+8804,8200,0,0,4,4,4,804,804,3804,8804,8,9,'QAAAAA','KDMAAA','AAAAxx'
+3760,8201,0,0,0,0,60,760,1760,3760,3760,120,121,'QOAAAA','LDMAAA','HHHHxx'
+8603,8202,1,3,3,3,3,603,603,3603,8603,6,7,'XSAAAA','MDMAAA','OOOOxx'
+7411,8203,1,3,1,11,11,411,1411,2411,7411,22,23,'BZAAAA','NDMAAA','VVVVxx'
+834,8204,0,2,4,14,34,834,834,834,834,68,69,'CGAAAA','ODMAAA','AAAAxx'
+7385,8205,1,1,5,5,85,385,1385,2385,7385,170,171,'BYAAAA','PDMAAA','HHHHxx'
+3696,8206,0,0,6,16,96,696,1696,3696,3696,192,193,'EMAAAA','QDMAAA','OOOOxx'
+8720,8207,0,0,0,0,20,720,720,3720,8720,40,41,'KXAAAA','RDMAAA','VVVVxx'
+4539,8208,1,3,9,19,39,539,539,4539,4539,78,79,'PSAAAA','SDMAAA','AAAAxx'
+9837,8209,1,1,7,17,37,837,1837,4837,9837,74,75,'JOAAAA','TDMAAA','HHHHxx'
+8595,8210,1,3,5,15,95,595,595,3595,8595,190,191,'PSAAAA','UDMAAA','OOOOxx'
+3673,8211,1,1,3,13,73,673,1673,3673,3673,146,147,'HLAAAA','VDMAAA','VVVVxx'
+475,8212,1,3,5,15,75,475,475,475,475,150,151,'HSAAAA','WDMAAA','AAAAxx'
+2256,8213,0,0,6,16,56,256,256,2256,2256,112,113,'UIAAAA','XDMAAA','HHHHxx'
+6349,8214,1,1,9,9,49,349,349,1349,6349,98,99,'FKAAAA','YDMAAA','OOOOxx'
+9968,8215,0,0,8,8,68,968,1968,4968,9968,136,137,'KTAAAA','ZDMAAA','VVVVxx'
+7261,8216,1,1,1,1,61,261,1261,2261,7261,122,123,'HTAAAA','AEMAAA','AAAAxx'
+5799,8217,1,3,9,19,99,799,1799,799,5799,198,199,'BPAAAA','BEMAAA','HHHHxx'
+8159,8218,1,3,9,19,59,159,159,3159,8159,118,119,'VBAAAA','CEMAAA','OOOOxx'
+92,8219,0,0,2,12,92,92,92,92,92,184,185,'ODAAAA','DEMAAA','VVVVxx'
+5927,8220,1,3,7,7,27,927,1927,927,5927,54,55,'ZTAAAA','EEMAAA','AAAAxx'
+7925,8221,1,1,5,5,25,925,1925,2925,7925,50,51,'VSAAAA','FEMAAA','HHHHxx'
+5836,8222,0,0,6,16,36,836,1836,836,5836,72,73,'MQAAAA','GEMAAA','OOOOxx'
+7935,8223,1,3,5,15,35,935,1935,2935,7935,70,71,'FTAAAA','HEMAAA','VVVVxx'
+5505,8224,1,1,5,5,5,505,1505,505,5505,10,11,'TDAAAA','IEMAAA','AAAAxx'
+5882,8225,0,2,2,2,82,882,1882,882,5882,164,165,'GSAAAA','JEMAAA','HHHHxx'
+4411,8226,1,3,1,11,11,411,411,4411,4411,22,23,'RNAAAA','KEMAAA','OOOOxx'
+64,8227,0,0,4,4,64,64,64,64,64,128,129,'MCAAAA','LEMAAA','VVVVxx'
+2851,8228,1,3,1,11,51,851,851,2851,2851,102,103,'RFAAAA','MEMAAA','AAAAxx'
+1665,8229,1,1,5,5,65,665,1665,1665,1665,130,131,'BMAAAA','NEMAAA','HHHHxx'
+2895,8230,1,3,5,15,95,895,895,2895,2895,190,191,'JHAAAA','OEMAAA','OOOOxx'
+2210,8231,0,2,0,10,10,210,210,2210,2210,20,21,'AHAAAA','PEMAAA','VVVVxx'
+9873,8232,1,1,3,13,73,873,1873,4873,9873,146,147,'TPAAAA','QEMAAA','AAAAxx'
+5402,8233,0,2,2,2,2,402,1402,402,5402,4,5,'UZAAAA','REMAAA','HHHHxx'
+285,8234,1,1,5,5,85,285,285,285,285,170,171,'ZKAAAA','SEMAAA','OOOOxx'
+8545,8235,1,1,5,5,45,545,545,3545,8545,90,91,'RQAAAA','TEMAAA','VVVVxx'
+5328,8236,0,0,8,8,28,328,1328,328,5328,56,57,'YWAAAA','UEMAAA','AAAAxx'
+733,8237,1,1,3,13,33,733,733,733,733,66,67,'FCAAAA','VEMAAA','HHHHxx'
+7726,8238,0,2,6,6,26,726,1726,2726,7726,52,53,'ELAAAA','WEMAAA','OOOOxx'
+5418,8239,0,2,8,18,18,418,1418,418,5418,36,37,'KAAAAA','XEMAAA','VVVVxx'
+7761,8240,1,1,1,1,61,761,1761,2761,7761,122,123,'NMAAAA','YEMAAA','AAAAxx'
+9263,8241,1,3,3,3,63,263,1263,4263,9263,126,127,'HSAAAA','ZEMAAA','HHHHxx'
+5579,8242,1,3,9,19,79,579,1579,579,5579,158,159,'PGAAAA','AFMAAA','OOOOxx'
+5434,8243,0,2,4,14,34,434,1434,434,5434,68,69,'ABAAAA','BFMAAA','VVVVxx'
+5230,8244,0,2,0,10,30,230,1230,230,5230,60,61,'ETAAAA','CFMAAA','AAAAxx'
+9981,8245,1,1,1,1,81,981,1981,4981,9981,162,163,'XTAAAA','DFMAAA','HHHHxx'
+5830,8246,0,2,0,10,30,830,1830,830,5830,60,61,'GQAAAA','EFMAAA','OOOOxx'
+128,8247,0,0,8,8,28,128,128,128,128,56,57,'YEAAAA','FFMAAA','VVVVxx'
+2734,8248,0,2,4,14,34,734,734,2734,2734,68,69,'EBAAAA','GFMAAA','AAAAxx'
+4537,8249,1,1,7,17,37,537,537,4537,4537,74,75,'NSAAAA','HFMAAA','HHHHxx'
+3899,8250,1,3,9,19,99,899,1899,3899,3899,198,199,'ZTAAAA','IFMAAA','OOOOxx'
+1000,8251,0,0,0,0,0,0,1000,1000,1000,0,1,'MMAAAA','JFMAAA','VVVVxx'
+9896,8252,0,0,6,16,96,896,1896,4896,9896,192,193,'QQAAAA','KFMAAA','AAAAxx'
+3640,8253,0,0,0,0,40,640,1640,3640,3640,80,81,'AKAAAA','LFMAAA','HHHHxx'
+2568,8254,0,0,8,8,68,568,568,2568,2568,136,137,'UUAAAA','MFMAAA','OOOOxx'
+2026,8255,0,2,6,6,26,26,26,2026,2026,52,53,'YZAAAA','NFMAAA','VVVVxx'
+3955,8256,1,3,5,15,55,955,1955,3955,3955,110,111,'DWAAAA','OFMAAA','AAAAxx'
+7152,8257,0,0,2,12,52,152,1152,2152,7152,104,105,'CPAAAA','PFMAAA','HHHHxx'
+2402,8258,0,2,2,2,2,402,402,2402,2402,4,5,'KOAAAA','QFMAAA','OOOOxx'
+9522,8259,0,2,2,2,22,522,1522,4522,9522,44,45,'GCAAAA','RFMAAA','VVVVxx'
+4011,8260,1,3,1,11,11,11,11,4011,4011,22,23,'HYAAAA','SFMAAA','AAAAxx'
+3297,8261,1,1,7,17,97,297,1297,3297,3297,194,195,'VWAAAA','TFMAAA','HHHHxx'
+4915,8262,1,3,5,15,15,915,915,4915,4915,30,31,'BHAAAA','UFMAAA','OOOOxx'
+5397,8263,1,1,7,17,97,397,1397,397,5397,194,195,'PZAAAA','VFMAAA','VVVVxx'
+5454,8264,0,2,4,14,54,454,1454,454,5454,108,109,'UBAAAA','WFMAAA','AAAAxx'
+4568,8265,0,0,8,8,68,568,568,4568,4568,136,137,'STAAAA','XFMAAA','HHHHxx'
+5875,8266,1,3,5,15,75,875,1875,875,5875,150,151,'ZRAAAA','YFMAAA','OOOOxx'
+3642,8267,0,2,2,2,42,642,1642,3642,3642,84,85,'CKAAAA','ZFMAAA','VVVVxx'
+8506,8268,0,2,6,6,6,506,506,3506,8506,12,13,'EPAAAA','AGMAAA','AAAAxx'
+9621,8269,1,1,1,1,21,621,1621,4621,9621,42,43,'BGAAAA','BGMAAA','HHHHxx'
+7739,8270,1,3,9,19,39,739,1739,2739,7739,78,79,'RLAAAA','CGMAAA','OOOOxx'
+3987,8271,1,3,7,7,87,987,1987,3987,3987,174,175,'JXAAAA','DGMAAA','VVVVxx'
+2090,8272,0,2,0,10,90,90,90,2090,2090,180,181,'KCAAAA','EGMAAA','AAAAxx'
+3838,8273,0,2,8,18,38,838,1838,3838,3838,76,77,'QRAAAA','FGMAAA','HHHHxx'
+17,8274,1,1,7,17,17,17,17,17,17,34,35,'RAAAAA','GGMAAA','OOOOxx'
+3406,8275,0,2,6,6,6,406,1406,3406,3406,12,13,'ABAAAA','HGMAAA','VVVVxx'
+8312,8276,0,0,2,12,12,312,312,3312,8312,24,25,'SHAAAA','IGMAAA','AAAAxx'
+4034,8277,0,2,4,14,34,34,34,4034,4034,68,69,'EZAAAA','JGMAAA','HHHHxx'
+1535,8278,1,3,5,15,35,535,1535,1535,1535,70,71,'BHAAAA','KGMAAA','OOOOxx'
+7198,8279,0,2,8,18,98,198,1198,2198,7198,196,197,'WQAAAA','LGMAAA','VVVVxx'
+8885,8280,1,1,5,5,85,885,885,3885,8885,170,171,'TDAAAA','MGMAAA','AAAAxx'
+4081,8281,1,1,1,1,81,81,81,4081,4081,162,163,'ZAAAAA','NGMAAA','HHHHxx'
+980,8282,0,0,0,0,80,980,980,980,980,160,161,'SLAAAA','OGMAAA','OOOOxx'
+551,8283,1,3,1,11,51,551,551,551,551,102,103,'FVAAAA','PGMAAA','VVVVxx'
+7746,8284,0,2,6,6,46,746,1746,2746,7746,92,93,'YLAAAA','QGMAAA','AAAAxx'
+4756,8285,0,0,6,16,56,756,756,4756,4756,112,113,'YAAAAA','RGMAAA','HHHHxx'
+3655,8286,1,3,5,15,55,655,1655,3655,3655,110,111,'PKAAAA','SGMAAA','OOOOxx'
+7075,8287,1,3,5,15,75,75,1075,2075,7075,150,151,'DMAAAA','TGMAAA','VVVVxx'
+3950,8288,0,2,0,10,50,950,1950,3950,3950,100,101,'YVAAAA','UGMAAA','AAAAxx'
+2314,8289,0,2,4,14,14,314,314,2314,2314,28,29,'ALAAAA','VGMAAA','HHHHxx'
+8432,8290,0,0,2,12,32,432,432,3432,8432,64,65,'IMAAAA','WGMAAA','OOOOxx'
+62,8291,0,2,2,2,62,62,62,62,62,124,125,'KCAAAA','XGMAAA','VVVVxx'
+6920,8292,0,0,0,0,20,920,920,1920,6920,40,41,'EGAAAA','YGMAAA','AAAAxx'
+4077,8293,1,1,7,17,77,77,77,4077,4077,154,155,'VAAAAA','ZGMAAA','HHHHxx'
+9118,8294,0,2,8,18,18,118,1118,4118,9118,36,37,'SMAAAA','AHMAAA','OOOOxx'
+5375,8295,1,3,5,15,75,375,1375,375,5375,150,151,'TYAAAA','BHMAAA','VVVVxx'
+178,8296,0,2,8,18,78,178,178,178,178,156,157,'WGAAAA','CHMAAA','AAAAxx'
+1079,8297,1,3,9,19,79,79,1079,1079,1079,158,159,'NPAAAA','DHMAAA','HHHHxx'
+4279,8298,1,3,9,19,79,279,279,4279,4279,158,159,'PIAAAA','EHMAAA','OOOOxx'
+8436,8299,0,0,6,16,36,436,436,3436,8436,72,73,'MMAAAA','FHMAAA','VVVVxx'
+1931,8300,1,3,1,11,31,931,1931,1931,1931,62,63,'HWAAAA','GHMAAA','AAAAxx'
+2096,8301,0,0,6,16,96,96,96,2096,2096,192,193,'QCAAAA','HHMAAA','HHHHxx'
+1638,8302,0,2,8,18,38,638,1638,1638,1638,76,77,'ALAAAA','IHMAAA','OOOOxx'
+2788,8303,0,0,8,8,88,788,788,2788,2788,176,177,'GDAAAA','JHMAAA','VVVVxx'
+4751,8304,1,3,1,11,51,751,751,4751,4751,102,103,'TAAAAA','KHMAAA','AAAAxx'
+8824,8305,0,0,4,4,24,824,824,3824,8824,48,49,'KBAAAA','LHMAAA','HHHHxx'
+3098,8306,0,2,8,18,98,98,1098,3098,3098,196,197,'EPAAAA','MHMAAA','OOOOxx'
+4497,8307,1,1,7,17,97,497,497,4497,4497,194,195,'ZQAAAA','NHMAAA','VVVVxx'
+5223,8308,1,3,3,3,23,223,1223,223,5223,46,47,'XSAAAA','OHMAAA','AAAAxx'
+9212,8309,0,0,2,12,12,212,1212,4212,9212,24,25,'IQAAAA','PHMAAA','HHHHxx'
+4265,8310,1,1,5,5,65,265,265,4265,4265,130,131,'BIAAAA','QHMAAA','OOOOxx'
+6898,8311,0,2,8,18,98,898,898,1898,6898,196,197,'IFAAAA','RHMAAA','VVVVxx'
+8808,8312,0,0,8,8,8,808,808,3808,8808,16,17,'UAAAAA','SHMAAA','AAAAxx'
+5629,8313,1,1,9,9,29,629,1629,629,5629,58,59,'NIAAAA','THMAAA','HHHHxx'
+3779,8314,1,3,9,19,79,779,1779,3779,3779,158,159,'JPAAAA','UHMAAA','OOOOxx'
+4972,8315,0,0,2,12,72,972,972,4972,4972,144,145,'GJAAAA','VHMAAA','VVVVxx'
+4511,8316,1,3,1,11,11,511,511,4511,4511,22,23,'NRAAAA','WHMAAA','AAAAxx'
+6761,8317,1,1,1,1,61,761,761,1761,6761,122,123,'BAAAAA','XHMAAA','HHHHxx'
+2335,8318,1,3,5,15,35,335,335,2335,2335,70,71,'VLAAAA','YHMAAA','OOOOxx'
+732,8319,0,0,2,12,32,732,732,732,732,64,65,'ECAAAA','ZHMAAA','VVVVxx'
+4757,8320,1,1,7,17,57,757,757,4757,4757,114,115,'ZAAAAA','AIMAAA','AAAAxx'
+6624,8321,0,0,4,4,24,624,624,1624,6624,48,49,'UUAAAA','BIMAAA','HHHHxx'
+5869,8322,1,1,9,9,69,869,1869,869,5869,138,139,'TRAAAA','CIMAAA','OOOOxx'
+5842,8323,0,2,2,2,42,842,1842,842,5842,84,85,'SQAAAA','DIMAAA','VVVVxx'
+5735,8324,1,3,5,15,35,735,1735,735,5735,70,71,'PMAAAA','EIMAAA','AAAAxx'
+8276,8325,0,0,6,16,76,276,276,3276,8276,152,153,'IGAAAA','FIMAAA','HHHHxx'
+7227,8326,1,3,7,7,27,227,1227,2227,7227,54,55,'ZRAAAA','GIMAAA','OOOOxx'
+4923,8327,1,3,3,3,23,923,923,4923,4923,46,47,'JHAAAA','HIMAAA','VVVVxx'
+9135,8328,1,3,5,15,35,135,1135,4135,9135,70,71,'JNAAAA','IIMAAA','AAAAxx'
+5813,8329,1,1,3,13,13,813,1813,813,5813,26,27,'PPAAAA','JIMAAA','HHHHxx'
+9697,8330,1,1,7,17,97,697,1697,4697,9697,194,195,'ZIAAAA','KIMAAA','OOOOxx'
+3222,8331,0,2,2,2,22,222,1222,3222,3222,44,45,'YTAAAA','LIMAAA','VVVVxx'
+2394,8332,0,2,4,14,94,394,394,2394,2394,188,189,'COAAAA','MIMAAA','AAAAxx'
+5784,8333,0,0,4,4,84,784,1784,784,5784,168,169,'MOAAAA','NIMAAA','HHHHxx'
+3652,8334,0,0,2,12,52,652,1652,3652,3652,104,105,'MKAAAA','OIMAAA','OOOOxx'
+8175,8335,1,3,5,15,75,175,175,3175,8175,150,151,'LCAAAA','PIMAAA','VVVVxx'
+7568,8336,0,0,8,8,68,568,1568,2568,7568,136,137,'CFAAAA','QIMAAA','AAAAxx'
+6645,8337,1,1,5,5,45,645,645,1645,6645,90,91,'PVAAAA','RIMAAA','HHHHxx'
+8176,8338,0,0,6,16,76,176,176,3176,8176,152,153,'MCAAAA','SIMAAA','OOOOxx'
+530,8339,0,2,0,10,30,530,530,530,530,60,61,'KUAAAA','TIMAAA','VVVVxx'
+5439,8340,1,3,9,19,39,439,1439,439,5439,78,79,'FBAAAA','UIMAAA','AAAAxx'
+61,8341,1,1,1,1,61,61,61,61,61,122,123,'JCAAAA','VIMAAA','HHHHxx'
+3951,8342,1,3,1,11,51,951,1951,3951,3951,102,103,'ZVAAAA','WIMAAA','OOOOxx'
+5283,8343,1,3,3,3,83,283,1283,283,5283,166,167,'FVAAAA','XIMAAA','VVVVxx'
+7226,8344,0,2,6,6,26,226,1226,2226,7226,52,53,'YRAAAA','YIMAAA','AAAAxx'
+1954,8345,0,2,4,14,54,954,1954,1954,1954,108,109,'EXAAAA','ZIMAAA','HHHHxx'
+334,8346,0,2,4,14,34,334,334,334,334,68,69,'WMAAAA','AJMAAA','OOOOxx'
+3921,8347,1,1,1,1,21,921,1921,3921,3921,42,43,'VUAAAA','BJMAAA','VVVVxx'
+6276,8348,0,0,6,16,76,276,276,1276,6276,152,153,'KHAAAA','CJMAAA','AAAAxx'
+3378,8349,0,2,8,18,78,378,1378,3378,3378,156,157,'YZAAAA','DJMAAA','HHHHxx'
+5236,8350,0,0,6,16,36,236,1236,236,5236,72,73,'KTAAAA','EJMAAA','OOOOxx'
+7781,8351,1,1,1,1,81,781,1781,2781,7781,162,163,'HNAAAA','FJMAAA','VVVVxx'
+8601,8352,1,1,1,1,1,601,601,3601,8601,2,3,'VSAAAA','GJMAAA','AAAAxx'
+1473,8353,1,1,3,13,73,473,1473,1473,1473,146,147,'REAAAA','HJMAAA','HHHHxx'
+3246,8354,0,2,6,6,46,246,1246,3246,3246,92,93,'WUAAAA','IJMAAA','OOOOxx'
+3601,8355,1,1,1,1,1,601,1601,3601,3601,2,3,'NIAAAA','JJMAAA','VVVVxx'
+6861,8356,1,1,1,1,61,861,861,1861,6861,122,123,'XDAAAA','KJMAAA','AAAAxx'
+9032,8357,0,0,2,12,32,32,1032,4032,9032,64,65,'KJAAAA','LJMAAA','HHHHxx'
+216,8358,0,0,6,16,16,216,216,216,216,32,33,'IIAAAA','MJMAAA','OOOOxx'
+3824,8359,0,0,4,4,24,824,1824,3824,3824,48,49,'CRAAAA','NJMAAA','VVVVxx'
+8486,8360,0,2,6,6,86,486,486,3486,8486,172,173,'KOAAAA','OJMAAA','AAAAxx'
+276,8361,0,0,6,16,76,276,276,276,276,152,153,'QKAAAA','PJMAAA','HHHHxx'
+1838,8362,0,2,8,18,38,838,1838,1838,1838,76,77,'SSAAAA','QJMAAA','OOOOxx'
+6175,8363,1,3,5,15,75,175,175,1175,6175,150,151,'NDAAAA','RJMAAA','VVVVxx'
+3719,8364,1,3,9,19,19,719,1719,3719,3719,38,39,'BNAAAA','SJMAAA','AAAAxx'
+6958,8365,0,2,8,18,58,958,958,1958,6958,116,117,'QHAAAA','TJMAAA','HHHHxx'
+6822,8366,0,2,2,2,22,822,822,1822,6822,44,45,'KCAAAA','UJMAAA','OOOOxx'
+3318,8367,0,2,8,18,18,318,1318,3318,3318,36,37,'QXAAAA','VJMAAA','VVVVxx'
+7222,8368,0,2,2,2,22,222,1222,2222,7222,44,45,'URAAAA','WJMAAA','AAAAxx'
+85,8369,1,1,5,5,85,85,85,85,85,170,171,'HDAAAA','XJMAAA','HHHHxx'
+5158,8370,0,2,8,18,58,158,1158,158,5158,116,117,'KQAAAA','YJMAAA','OOOOxx'
+6360,8371,0,0,0,0,60,360,360,1360,6360,120,121,'QKAAAA','ZJMAAA','VVVVxx'
+2599,8372,1,3,9,19,99,599,599,2599,2599,198,199,'ZVAAAA','AKMAAA','AAAAxx'
+4002,8373,0,2,2,2,2,2,2,4002,4002,4,5,'YXAAAA','BKMAAA','HHHHxx'
+6597,8374,1,1,7,17,97,597,597,1597,6597,194,195,'TTAAAA','CKMAAA','OOOOxx'
+5762,8375,0,2,2,2,62,762,1762,762,5762,124,125,'QNAAAA','DKMAAA','VVVVxx'
+8383,8376,1,3,3,3,83,383,383,3383,8383,166,167,'LKAAAA','EKMAAA','AAAAxx'
+4686,8377,0,2,6,6,86,686,686,4686,4686,172,173,'GYAAAA','FKMAAA','HHHHxx'
+5972,8378,0,0,2,12,72,972,1972,972,5972,144,145,'SVAAAA','GKMAAA','OOOOxx'
+1432,8379,0,0,2,12,32,432,1432,1432,1432,64,65,'CDAAAA','HKMAAA','VVVVxx'
+1601,8380,1,1,1,1,1,601,1601,1601,1601,2,3,'PJAAAA','IKMAAA','AAAAxx'
+3012,8381,0,0,2,12,12,12,1012,3012,3012,24,25,'WLAAAA','JKMAAA','HHHHxx'
+9345,8382,1,1,5,5,45,345,1345,4345,9345,90,91,'LVAAAA','KKMAAA','OOOOxx'
+8869,8383,1,1,9,9,69,869,869,3869,8869,138,139,'DDAAAA','LKMAAA','VVVVxx'
+6612,8384,0,0,2,12,12,612,612,1612,6612,24,25,'IUAAAA','MKMAAA','AAAAxx'
+262,8385,0,2,2,2,62,262,262,262,262,124,125,'CKAAAA','NKMAAA','HHHHxx'
+300,8386,0,0,0,0,0,300,300,300,300,0,1,'OLAAAA','OKMAAA','OOOOxx'
+3045,8387,1,1,5,5,45,45,1045,3045,3045,90,91,'DNAAAA','PKMAAA','VVVVxx'
+7252,8388,0,0,2,12,52,252,1252,2252,7252,104,105,'YSAAAA','QKMAAA','AAAAxx'
+9099,8389,1,3,9,19,99,99,1099,4099,9099,198,199,'ZLAAAA','RKMAAA','HHHHxx'
+9006,8390,0,2,6,6,6,6,1006,4006,9006,12,13,'KIAAAA','SKMAAA','OOOOxx'
+3078,8391,0,2,8,18,78,78,1078,3078,3078,156,157,'KOAAAA','TKMAAA','VVVVxx'
+5159,8392,1,3,9,19,59,159,1159,159,5159,118,119,'LQAAAA','UKMAAA','AAAAxx'
+9329,8393,1,1,9,9,29,329,1329,4329,9329,58,59,'VUAAAA','VKMAAA','HHHHxx'
+1393,8394,1,1,3,13,93,393,1393,1393,1393,186,187,'PBAAAA','WKMAAA','OOOOxx'
+5894,8395,0,2,4,14,94,894,1894,894,5894,188,189,'SSAAAA','XKMAAA','VVVVxx'
+11,8396,1,3,1,11,11,11,11,11,11,22,23,'LAAAAA','YKMAAA','AAAAxx'
+5606,8397,0,2,6,6,6,606,1606,606,5606,12,13,'QHAAAA','ZKMAAA','HHHHxx'
+5541,8398,1,1,1,1,41,541,1541,541,5541,82,83,'DFAAAA','ALMAAA','OOOOxx'
+2689,8399,1,1,9,9,89,689,689,2689,2689,178,179,'LZAAAA','BLMAAA','VVVVxx'
+1023,8400,1,3,3,3,23,23,1023,1023,1023,46,47,'JNAAAA','CLMAAA','AAAAxx'
+8134,8401,0,2,4,14,34,134,134,3134,8134,68,69,'WAAAAA','DLMAAA','HHHHxx'
+5923,8402,1,3,3,3,23,923,1923,923,5923,46,47,'VTAAAA','ELMAAA','OOOOxx'
+6056,8403,0,0,6,16,56,56,56,1056,6056,112,113,'YYAAAA','FLMAAA','VVVVxx'
+653,8404,1,1,3,13,53,653,653,653,653,106,107,'DZAAAA','GLMAAA','AAAAxx'
+367,8405,1,3,7,7,67,367,367,367,367,134,135,'DOAAAA','HLMAAA','HHHHxx'
+1828,8406,0,0,8,8,28,828,1828,1828,1828,56,57,'ISAAAA','ILMAAA','OOOOxx'
+6506,8407,0,2,6,6,6,506,506,1506,6506,12,13,'GQAAAA','JLMAAA','VVVVxx'
+5772,8408,0,0,2,12,72,772,1772,772,5772,144,145,'AOAAAA','KLMAAA','AAAAxx'
+8052,8409,0,0,2,12,52,52,52,3052,8052,104,105,'SXAAAA','LLMAAA','HHHHxx'
+2633,8410,1,1,3,13,33,633,633,2633,2633,66,67,'HXAAAA','MLMAAA','OOOOxx'
+4878,8411,0,2,8,18,78,878,878,4878,4878,156,157,'QFAAAA','NLMAAA','VVVVxx'
+5621,8412,1,1,1,1,21,621,1621,621,5621,42,43,'FIAAAA','OLMAAA','AAAAxx'
+41,8413,1,1,1,1,41,41,41,41,41,82,83,'PBAAAA','PLMAAA','HHHHxx'
+4613,8414,1,1,3,13,13,613,613,4613,4613,26,27,'LVAAAA','QLMAAA','OOOOxx'
+9389,8415,1,1,9,9,89,389,1389,4389,9389,178,179,'DXAAAA','RLMAAA','VVVVxx'
+9414,8416,0,2,4,14,14,414,1414,4414,9414,28,29,'CYAAAA','SLMAAA','AAAAxx'
+3583,8417,1,3,3,3,83,583,1583,3583,3583,166,167,'VHAAAA','TLMAAA','HHHHxx'
+3454,8418,0,2,4,14,54,454,1454,3454,3454,108,109,'WCAAAA','ULMAAA','OOOOxx'
+719,8419,1,3,9,19,19,719,719,719,719,38,39,'RBAAAA','VLMAAA','VVVVxx'
+6188,8420,0,0,8,8,88,188,188,1188,6188,176,177,'AEAAAA','WLMAAA','AAAAxx'
+2288,8421,0,0,8,8,88,288,288,2288,2288,176,177,'AKAAAA','XLMAAA','HHHHxx'
+1287,8422,1,3,7,7,87,287,1287,1287,1287,174,175,'NXAAAA','YLMAAA','OOOOxx'
+1397,8423,1,1,7,17,97,397,1397,1397,1397,194,195,'TBAAAA','ZLMAAA','VVVVxx'
+7763,8424,1,3,3,3,63,763,1763,2763,7763,126,127,'PMAAAA','AMMAAA','AAAAxx'
+5194,8425,0,2,4,14,94,194,1194,194,5194,188,189,'URAAAA','BMMAAA','HHHHxx'
+3167,8426,1,3,7,7,67,167,1167,3167,3167,134,135,'VRAAAA','CMMAAA','OOOOxx'
+9218,8427,0,2,8,18,18,218,1218,4218,9218,36,37,'OQAAAA','DMMAAA','VVVVxx'
+2065,8428,1,1,5,5,65,65,65,2065,2065,130,131,'LBAAAA','EMMAAA','AAAAxx'
+9669,8429,1,1,9,9,69,669,1669,4669,9669,138,139,'XHAAAA','FMMAAA','HHHHxx'
+146,8430,0,2,6,6,46,146,146,146,146,92,93,'QFAAAA','GMMAAA','OOOOxx'
+6141,8431,1,1,1,1,41,141,141,1141,6141,82,83,'FCAAAA','HMMAAA','VVVVxx'
+2843,8432,1,3,3,3,43,843,843,2843,2843,86,87,'JFAAAA','IMMAAA','AAAAxx'
+7934,8433,0,2,4,14,34,934,1934,2934,7934,68,69,'ETAAAA','JMMAAA','HHHHxx'
+2536,8434,0,0,6,16,36,536,536,2536,2536,72,73,'OTAAAA','KMMAAA','OOOOxx'
+7088,8435,0,0,8,8,88,88,1088,2088,7088,176,177,'QMAAAA','LMMAAA','VVVVxx'
+2519,8436,1,3,9,19,19,519,519,2519,2519,38,39,'XSAAAA','MMMAAA','AAAAxx'
+6650,8437,0,2,0,10,50,650,650,1650,6650,100,101,'UVAAAA','NMMAAA','HHHHxx'
+3007,8438,1,3,7,7,7,7,1007,3007,3007,14,15,'RLAAAA','OMMAAA','OOOOxx'
+4507,8439,1,3,7,7,7,507,507,4507,4507,14,15,'JRAAAA','PMMAAA','VVVVxx'
+4892,8440,0,0,2,12,92,892,892,4892,4892,184,185,'EGAAAA','QMMAAA','AAAAxx'
+7159,8441,1,3,9,19,59,159,1159,2159,7159,118,119,'JPAAAA','RMMAAA','HHHHxx'
+3171,8442,1,3,1,11,71,171,1171,3171,3171,142,143,'ZRAAAA','SMMAAA','OOOOxx'
+1080,8443,0,0,0,0,80,80,1080,1080,1080,160,161,'OPAAAA','TMMAAA','VVVVxx'
+7248,8444,0,0,8,8,48,248,1248,2248,7248,96,97,'USAAAA','UMMAAA','AAAAxx'
+7230,8445,0,2,0,10,30,230,1230,2230,7230,60,61,'CSAAAA','VMMAAA','HHHHxx'
+3823,8446,1,3,3,3,23,823,1823,3823,3823,46,47,'BRAAAA','WMMAAA','OOOOxx'
+5517,8447,1,1,7,17,17,517,1517,517,5517,34,35,'FEAAAA','XMMAAA','VVVVxx'
+1482,8448,0,2,2,2,82,482,1482,1482,1482,164,165,'AFAAAA','YMMAAA','AAAAxx'
+9953,8449,1,1,3,13,53,953,1953,4953,9953,106,107,'VSAAAA','ZMMAAA','HHHHxx'
+2754,8450,0,2,4,14,54,754,754,2754,2754,108,109,'YBAAAA','ANMAAA','OOOOxx'
+3875,8451,1,3,5,15,75,875,1875,3875,3875,150,151,'BTAAAA','BNMAAA','VVVVxx'
+9800,8452,0,0,0,0,0,800,1800,4800,9800,0,1,'YMAAAA','CNMAAA','AAAAxx'
+8819,8453,1,3,9,19,19,819,819,3819,8819,38,39,'FBAAAA','DNMAAA','HHHHxx'
+8267,8454,1,3,7,7,67,267,267,3267,8267,134,135,'ZFAAAA','ENMAAA','OOOOxx'
+520,8455,0,0,0,0,20,520,520,520,520,40,41,'AUAAAA','FNMAAA','VVVVxx'
+5770,8456,0,2,0,10,70,770,1770,770,5770,140,141,'YNAAAA','GNMAAA','AAAAxx'
+2114,8457,0,2,4,14,14,114,114,2114,2114,28,29,'IDAAAA','HNMAAA','HHHHxx'
+5045,8458,1,1,5,5,45,45,1045,45,5045,90,91,'BMAAAA','INMAAA','OOOOxx'
+1094,8459,0,2,4,14,94,94,1094,1094,1094,188,189,'CQAAAA','JNMAAA','VVVVxx'
+8786,8460,0,2,6,6,86,786,786,3786,8786,172,173,'YZAAAA','KNMAAA','AAAAxx'
+353,8461,1,1,3,13,53,353,353,353,353,106,107,'PNAAAA','LNMAAA','HHHHxx'
+290,8462,0,2,0,10,90,290,290,290,290,180,181,'ELAAAA','MNMAAA','OOOOxx'
+3376,8463,0,0,6,16,76,376,1376,3376,3376,152,153,'WZAAAA','NNMAAA','VVVVxx'
+9305,8464,1,1,5,5,5,305,1305,4305,9305,10,11,'XTAAAA','ONMAAA','AAAAxx'
+186,8465,0,2,6,6,86,186,186,186,186,172,173,'EHAAAA','PNMAAA','HHHHxx'
+4817,8466,1,1,7,17,17,817,817,4817,4817,34,35,'HDAAAA','QNMAAA','OOOOxx'
+4638,8467,0,2,8,18,38,638,638,4638,4638,76,77,'KWAAAA','RNMAAA','VVVVxx'
+3558,8468,0,2,8,18,58,558,1558,3558,3558,116,117,'WGAAAA','SNMAAA','AAAAxx'
+9285,8469,1,1,5,5,85,285,1285,4285,9285,170,171,'DTAAAA','TNMAAA','HHHHxx'
+848,8470,0,0,8,8,48,848,848,848,848,96,97,'QGAAAA','UNMAAA','OOOOxx'
+8923,8471,1,3,3,3,23,923,923,3923,8923,46,47,'FFAAAA','VNMAAA','VVVVxx'
+6826,8472,0,2,6,6,26,826,826,1826,6826,52,53,'OCAAAA','WNMAAA','AAAAxx'
+5187,8473,1,3,7,7,87,187,1187,187,5187,174,175,'NRAAAA','XNMAAA','HHHHxx'
+2398,8474,0,2,8,18,98,398,398,2398,2398,196,197,'GOAAAA','YNMAAA','OOOOxx'
+7653,8475,1,1,3,13,53,653,1653,2653,7653,106,107,'JIAAAA','ZNMAAA','VVVVxx'
+8835,8476,1,3,5,15,35,835,835,3835,8835,70,71,'VBAAAA','AOMAAA','AAAAxx'
+5736,8477,0,0,6,16,36,736,1736,736,5736,72,73,'QMAAAA','BOMAAA','HHHHxx'
+1238,8478,0,2,8,18,38,238,1238,1238,1238,76,77,'QVAAAA','COMAAA','OOOOxx'
+6021,8479,1,1,1,1,21,21,21,1021,6021,42,43,'PXAAAA','DOMAAA','VVVVxx'
+6815,8480,1,3,5,15,15,815,815,1815,6815,30,31,'DCAAAA','EOMAAA','AAAAxx'
+2549,8481,1,1,9,9,49,549,549,2549,2549,98,99,'BUAAAA','FOMAAA','HHHHxx'
+5657,8482,1,1,7,17,57,657,1657,657,5657,114,115,'PJAAAA','GOMAAA','OOOOxx'
+6855,8483,1,3,5,15,55,855,855,1855,6855,110,111,'RDAAAA','HOMAAA','VVVVxx'
+1225,8484,1,1,5,5,25,225,1225,1225,1225,50,51,'DVAAAA','IOMAAA','AAAAxx'
+7452,8485,0,0,2,12,52,452,1452,2452,7452,104,105,'QAAAAA','JOMAAA','HHHHxx'
+2479,8486,1,3,9,19,79,479,479,2479,2479,158,159,'JRAAAA','KOMAAA','OOOOxx'
+7974,8487,0,2,4,14,74,974,1974,2974,7974,148,149,'SUAAAA','LOMAAA','VVVVxx'
+1212,8488,0,0,2,12,12,212,1212,1212,1212,24,25,'QUAAAA','MOMAAA','AAAAxx'
+8883,8489,1,3,3,3,83,883,883,3883,8883,166,167,'RDAAAA','NOMAAA','HHHHxx'
+8150,8490,0,2,0,10,50,150,150,3150,8150,100,101,'MBAAAA','OOMAAA','OOOOxx'
+3392,8491,0,0,2,12,92,392,1392,3392,3392,184,185,'MAAAAA','POMAAA','VVVVxx'
+6774,8492,0,2,4,14,74,774,774,1774,6774,148,149,'OAAAAA','QOMAAA','AAAAxx'
+904,8493,0,0,4,4,4,904,904,904,904,8,9,'UIAAAA','ROMAAA','HHHHxx'
+5068,8494,0,0,8,8,68,68,1068,68,5068,136,137,'YMAAAA','SOMAAA','OOOOxx'
+9339,8495,1,3,9,19,39,339,1339,4339,9339,78,79,'FVAAAA','TOMAAA','VVVVxx'
+1062,8496,0,2,2,2,62,62,1062,1062,1062,124,125,'WOAAAA','UOMAAA','AAAAxx'
+3841,8497,1,1,1,1,41,841,1841,3841,3841,82,83,'TRAAAA','VOMAAA','HHHHxx'
+8924,8498,0,0,4,4,24,924,924,3924,8924,48,49,'GFAAAA','WOMAAA','OOOOxx'
+9795,8499,1,3,5,15,95,795,1795,4795,9795,190,191,'TMAAAA','XOMAAA','VVVVxx'
+3981,8500,1,1,1,1,81,981,1981,3981,3981,162,163,'DXAAAA','YOMAAA','AAAAxx'
+4290,8501,0,2,0,10,90,290,290,4290,4290,180,181,'AJAAAA','ZOMAAA','HHHHxx'
+1067,8502,1,3,7,7,67,67,1067,1067,1067,134,135,'BPAAAA','APMAAA','OOOOxx'
+8679,8503,1,3,9,19,79,679,679,3679,8679,158,159,'VVAAAA','BPMAAA','VVVVxx'
+2894,8504,0,2,4,14,94,894,894,2894,2894,188,189,'IHAAAA','CPMAAA','AAAAxx'
+9248,8505,0,0,8,8,48,248,1248,4248,9248,96,97,'SRAAAA','DPMAAA','HHHHxx'
+1072,8506,0,0,2,12,72,72,1072,1072,1072,144,145,'GPAAAA','EPMAAA','OOOOxx'
+3510,8507,0,2,0,10,10,510,1510,3510,3510,20,21,'AFAAAA','FPMAAA','VVVVxx'
+6871,8508,1,3,1,11,71,871,871,1871,6871,142,143,'HEAAAA','GPMAAA','AAAAxx'
+8701,8509,1,1,1,1,1,701,701,3701,8701,2,3,'RWAAAA','HPMAAA','HHHHxx'
+8170,8510,0,2,0,10,70,170,170,3170,8170,140,141,'GCAAAA','IPMAAA','OOOOxx'
+2730,8511,0,2,0,10,30,730,730,2730,2730,60,61,'ABAAAA','JPMAAA','VVVVxx'
+2668,8512,0,0,8,8,68,668,668,2668,2668,136,137,'QYAAAA','KPMAAA','AAAAxx'
+8723,8513,1,3,3,3,23,723,723,3723,8723,46,47,'NXAAAA','LPMAAA','HHHHxx'
+3439,8514,1,3,9,19,39,439,1439,3439,3439,78,79,'HCAAAA','MPMAAA','OOOOxx'
+6219,8515,1,3,9,19,19,219,219,1219,6219,38,39,'FFAAAA','NPMAAA','VVVVxx'
+4264,8516,0,0,4,4,64,264,264,4264,4264,128,129,'AIAAAA','OPMAAA','AAAAxx'
+3929,8517,1,1,9,9,29,929,1929,3929,3929,58,59,'DVAAAA','PPMAAA','HHHHxx'
+7,8518,1,3,7,7,7,7,7,7,7,14,15,'HAAAAA','QPMAAA','OOOOxx'
+3737,8519,1,1,7,17,37,737,1737,3737,3737,74,75,'TNAAAA','RPMAAA','VVVVxx'
+358,8520,0,2,8,18,58,358,358,358,358,116,117,'UNAAAA','SPMAAA','AAAAxx'
+5128,8521,0,0,8,8,28,128,1128,128,5128,56,57,'GPAAAA','TPMAAA','HHHHxx'
+7353,8522,1,1,3,13,53,353,1353,2353,7353,106,107,'VWAAAA','UPMAAA','OOOOxx'
+8758,8523,0,2,8,18,58,758,758,3758,8758,116,117,'WYAAAA','VPMAAA','VVVVxx'
+7284,8524,0,0,4,4,84,284,1284,2284,7284,168,169,'EUAAAA','WPMAAA','AAAAxx'
+4037,8525,1,1,7,17,37,37,37,4037,4037,74,75,'HZAAAA','XPMAAA','HHHHxx'
+435,8526,1,3,5,15,35,435,435,435,435,70,71,'TQAAAA','YPMAAA','OOOOxx'
+3580,8527,0,0,0,0,80,580,1580,3580,3580,160,161,'SHAAAA','ZPMAAA','VVVVxx'
+4554,8528,0,2,4,14,54,554,554,4554,4554,108,109,'ETAAAA','AQMAAA','AAAAxx'
+4337,8529,1,1,7,17,37,337,337,4337,4337,74,75,'VKAAAA','BQMAAA','HHHHxx'
+512,8530,0,0,2,12,12,512,512,512,512,24,25,'STAAAA','CQMAAA','OOOOxx'
+2032,8531,0,0,2,12,32,32,32,2032,2032,64,65,'EAAAAA','DQMAAA','VVVVxx'
+1755,8532,1,3,5,15,55,755,1755,1755,1755,110,111,'NPAAAA','EQMAAA','AAAAxx'
+9923,8533,1,3,3,3,23,923,1923,4923,9923,46,47,'RRAAAA','FQMAAA','HHHHxx'
+3747,8534,1,3,7,7,47,747,1747,3747,3747,94,95,'DOAAAA','GQMAAA','OOOOxx'
+27,8535,1,3,7,7,27,27,27,27,27,54,55,'BBAAAA','HQMAAA','VVVVxx'
+3075,8536,1,3,5,15,75,75,1075,3075,3075,150,151,'HOAAAA','IQMAAA','AAAAxx'
+6259,8537,1,3,9,19,59,259,259,1259,6259,118,119,'TGAAAA','JQMAAA','HHHHxx'
+2940,8538,0,0,0,0,40,940,940,2940,2940,80,81,'CJAAAA','KQMAAA','OOOOxx'
+5724,8539,0,0,4,4,24,724,1724,724,5724,48,49,'EMAAAA','LQMAAA','VVVVxx'
+5638,8540,0,2,8,18,38,638,1638,638,5638,76,77,'WIAAAA','MQMAAA','AAAAxx'
+479,8541,1,3,9,19,79,479,479,479,479,158,159,'LSAAAA','NQMAAA','HHHHxx'
+4125,8542,1,1,5,5,25,125,125,4125,4125,50,51,'RCAAAA','OQMAAA','OOOOxx'
+1525,8543,1,1,5,5,25,525,1525,1525,1525,50,51,'RGAAAA','PQMAAA','VVVVxx'
+7529,8544,1,1,9,9,29,529,1529,2529,7529,58,59,'PDAAAA','QQMAAA','AAAAxx'
+931,8545,1,3,1,11,31,931,931,931,931,62,63,'VJAAAA','RQMAAA','HHHHxx'
+5175,8546,1,3,5,15,75,175,1175,175,5175,150,151,'BRAAAA','SQMAAA','OOOOxx'
+6798,8547,0,2,8,18,98,798,798,1798,6798,196,197,'MBAAAA','TQMAAA','VVVVxx'
+2111,8548,1,3,1,11,11,111,111,2111,2111,22,23,'FDAAAA','UQMAAA','AAAAxx'
+6145,8549,1,1,5,5,45,145,145,1145,6145,90,91,'JCAAAA','VQMAAA','HHHHxx'
+4712,8550,0,0,2,12,12,712,712,4712,4712,24,25,'GZAAAA','WQMAAA','OOOOxx'
+3110,8551,0,2,0,10,10,110,1110,3110,3110,20,21,'QPAAAA','XQMAAA','VVVVxx'
+97,8552,1,1,7,17,97,97,97,97,97,194,195,'TDAAAA','YQMAAA','AAAAxx'
+758,8553,0,2,8,18,58,758,758,758,758,116,117,'EDAAAA','ZQMAAA','HHHHxx'
+1895,8554,1,3,5,15,95,895,1895,1895,1895,190,191,'XUAAAA','ARMAAA','OOOOxx'
+5289,8555,1,1,9,9,89,289,1289,289,5289,178,179,'LVAAAA','BRMAAA','VVVVxx'
+5026,8556,0,2,6,6,26,26,1026,26,5026,52,53,'ILAAAA','CRMAAA','AAAAxx'
+4725,8557,1,1,5,5,25,725,725,4725,4725,50,51,'TZAAAA','DRMAAA','HHHHxx'
+1679,8558,1,3,9,19,79,679,1679,1679,1679,158,159,'PMAAAA','ERMAAA','OOOOxx'
+4433,8559,1,1,3,13,33,433,433,4433,4433,66,67,'NOAAAA','FRMAAA','VVVVxx'
+5340,8560,0,0,0,0,40,340,1340,340,5340,80,81,'KXAAAA','GRMAAA','AAAAxx'
+6340,8561,0,0,0,0,40,340,340,1340,6340,80,81,'WJAAAA','HRMAAA','HHHHxx'
+3261,8562,1,1,1,1,61,261,1261,3261,3261,122,123,'LVAAAA','IRMAAA','OOOOxx'
+8108,8563,0,0,8,8,8,108,108,3108,8108,16,17,'WZAAAA','JRMAAA','VVVVxx'
+8785,8564,1,1,5,5,85,785,785,3785,8785,170,171,'XZAAAA','KRMAAA','AAAAxx'
+7391,8565,1,3,1,11,91,391,1391,2391,7391,182,183,'HYAAAA','LRMAAA','HHHHxx'
+1496,8566,0,0,6,16,96,496,1496,1496,1496,192,193,'OFAAAA','MRMAAA','OOOOxx'
+1484,8567,0,0,4,4,84,484,1484,1484,1484,168,169,'CFAAAA','NRMAAA','VVVVxx'
+5884,8568,0,0,4,4,84,884,1884,884,5884,168,169,'ISAAAA','ORMAAA','AAAAxx'
+342,8569,0,2,2,2,42,342,342,342,342,84,85,'ENAAAA','PRMAAA','HHHHxx'
+7659,8570,1,3,9,19,59,659,1659,2659,7659,118,119,'PIAAAA','QRMAAA','OOOOxx'
+6635,8571,1,3,5,15,35,635,635,1635,6635,70,71,'FVAAAA','RRMAAA','VVVVxx'
+8507,8572,1,3,7,7,7,507,507,3507,8507,14,15,'FPAAAA','SRMAAA','AAAAxx'
+2583,8573,1,3,3,3,83,583,583,2583,2583,166,167,'JVAAAA','TRMAAA','HHHHxx'
+6533,8574,1,1,3,13,33,533,533,1533,6533,66,67,'HRAAAA','URMAAA','OOOOxx'
+5879,8575,1,3,9,19,79,879,1879,879,5879,158,159,'DSAAAA','VRMAAA','VVVVxx'
+5511,8576,1,3,1,11,11,511,1511,511,5511,22,23,'ZDAAAA','WRMAAA','AAAAxx'
+3682,8577,0,2,2,2,82,682,1682,3682,3682,164,165,'QLAAAA','XRMAAA','HHHHxx'
+7182,8578,0,2,2,2,82,182,1182,2182,7182,164,165,'GQAAAA','YRMAAA','OOOOxx'
+1409,8579,1,1,9,9,9,409,1409,1409,1409,18,19,'FCAAAA','ZRMAAA','VVVVxx'
+3363,8580,1,3,3,3,63,363,1363,3363,3363,126,127,'JZAAAA','ASMAAA','AAAAxx'
+729,8581,1,1,9,9,29,729,729,729,729,58,59,'BCAAAA','BSMAAA','HHHHxx'
+5857,8582,1,1,7,17,57,857,1857,857,5857,114,115,'HRAAAA','CSMAAA','OOOOxx'
+235,8583,1,3,5,15,35,235,235,235,235,70,71,'BJAAAA','DSMAAA','VVVVxx'
+193,8584,1,1,3,13,93,193,193,193,193,186,187,'LHAAAA','ESMAAA','AAAAxx'
+5586,8585,0,2,6,6,86,586,1586,586,5586,172,173,'WGAAAA','FSMAAA','HHHHxx'
+6203,8586,1,3,3,3,3,203,203,1203,6203,6,7,'PEAAAA','GSMAAA','OOOOxx'
+6795,8587,1,3,5,15,95,795,795,1795,6795,190,191,'JBAAAA','HSMAAA','VVVVxx'
+3211,8588,1,3,1,11,11,211,1211,3211,3211,22,23,'NTAAAA','ISMAAA','AAAAxx'
+9763,8589,1,3,3,3,63,763,1763,4763,9763,126,127,'NLAAAA','JSMAAA','HHHHxx'
+9043,8590,1,3,3,3,43,43,1043,4043,9043,86,87,'VJAAAA','KSMAAA','OOOOxx'
+2854,8591,0,2,4,14,54,854,854,2854,2854,108,109,'UFAAAA','LSMAAA','VVVVxx'
+565,8592,1,1,5,5,65,565,565,565,565,130,131,'TVAAAA','MSMAAA','AAAAxx'
+9284,8593,0,0,4,4,84,284,1284,4284,9284,168,169,'CTAAAA','NSMAAA','HHHHxx'
+7886,8594,0,2,6,6,86,886,1886,2886,7886,172,173,'IRAAAA','OSMAAA','OOOOxx'
+122,8595,0,2,2,2,22,122,122,122,122,44,45,'SEAAAA','PSMAAA','VVVVxx'
+4934,8596,0,2,4,14,34,934,934,4934,4934,68,69,'UHAAAA','QSMAAA','AAAAxx'
+1766,8597,0,2,6,6,66,766,1766,1766,1766,132,133,'YPAAAA','RSMAAA','HHHHxx'
+2554,8598,0,2,4,14,54,554,554,2554,2554,108,109,'GUAAAA','SSMAAA','OOOOxx'
+488,8599,0,0,8,8,88,488,488,488,488,176,177,'USAAAA','TSMAAA','VVVVxx'
+825,8600,1,1,5,5,25,825,825,825,825,50,51,'TFAAAA','USMAAA','AAAAxx'
+678,8601,0,2,8,18,78,678,678,678,678,156,157,'CAAAAA','VSMAAA','HHHHxx'
+4543,8602,1,3,3,3,43,543,543,4543,4543,86,87,'TSAAAA','WSMAAA','OOOOxx'
+1699,8603,1,3,9,19,99,699,1699,1699,1699,198,199,'JNAAAA','XSMAAA','VVVVxx'
+3771,8604,1,3,1,11,71,771,1771,3771,3771,142,143,'BPAAAA','YSMAAA','AAAAxx'
+1234,8605,0,2,4,14,34,234,1234,1234,1234,68,69,'MVAAAA','ZSMAAA','HHHHxx'
+4152,8606,0,0,2,12,52,152,152,4152,4152,104,105,'SDAAAA','ATMAAA','OOOOxx'
+1632,8607,0,0,2,12,32,632,1632,1632,1632,64,65,'UKAAAA','BTMAAA','VVVVxx'
+4988,8608,0,0,8,8,88,988,988,4988,4988,176,177,'WJAAAA','CTMAAA','AAAAxx'
+1980,8609,0,0,0,0,80,980,1980,1980,1980,160,161,'EYAAAA','DTMAAA','HHHHxx'
+7479,8610,1,3,9,19,79,479,1479,2479,7479,158,159,'RBAAAA','ETMAAA','OOOOxx'
+2586,8611,0,2,6,6,86,586,586,2586,2586,172,173,'MVAAAA','FTMAAA','VVVVxx'
+5433,8612,1,1,3,13,33,433,1433,433,5433,66,67,'ZAAAAA','GTMAAA','AAAAxx'
+2261,8613,1,1,1,1,61,261,261,2261,2261,122,123,'ZIAAAA','HTMAAA','HHHHxx'
+1180,8614,0,0,0,0,80,180,1180,1180,1180,160,161,'KTAAAA','ITMAAA','OOOOxx'
+3938,8615,0,2,8,18,38,938,1938,3938,3938,76,77,'MVAAAA','JTMAAA','VVVVxx'
+6714,8616,0,2,4,14,14,714,714,1714,6714,28,29,'GYAAAA','KTMAAA','AAAAxx'
+2890,8617,0,2,0,10,90,890,890,2890,2890,180,181,'EHAAAA','LTMAAA','HHHHxx'
+7379,8618,1,3,9,19,79,379,1379,2379,7379,158,159,'VXAAAA','MTMAAA','OOOOxx'
+5896,8619,0,0,6,16,96,896,1896,896,5896,192,193,'USAAAA','NTMAAA','VVVVxx'
+5949,8620,1,1,9,9,49,949,1949,949,5949,98,99,'VUAAAA','OTMAAA','AAAAxx'
+3194,8621,0,2,4,14,94,194,1194,3194,3194,188,189,'WSAAAA','PTMAAA','HHHHxx'
+9325,8622,1,1,5,5,25,325,1325,4325,9325,50,51,'RUAAAA','QTMAAA','OOOOxx'
+9531,8623,1,3,1,11,31,531,1531,4531,9531,62,63,'PCAAAA','RTMAAA','VVVVxx'
+711,8624,1,3,1,11,11,711,711,711,711,22,23,'JBAAAA','STMAAA','AAAAxx'
+2450,8625,0,2,0,10,50,450,450,2450,2450,100,101,'GQAAAA','TTMAAA','HHHHxx'
+1929,8626,1,1,9,9,29,929,1929,1929,1929,58,59,'FWAAAA','UTMAAA','OOOOxx'
+6165,8627,1,1,5,5,65,165,165,1165,6165,130,131,'DDAAAA','VTMAAA','VVVVxx'
+4050,8628,0,2,0,10,50,50,50,4050,4050,100,101,'UZAAAA','WTMAAA','AAAAxx'
+9011,8629,1,3,1,11,11,11,1011,4011,9011,22,23,'PIAAAA','XTMAAA','HHHHxx'
+7916,8630,0,0,6,16,16,916,1916,2916,7916,32,33,'MSAAAA','YTMAAA','OOOOxx'
+9136,8631,0,0,6,16,36,136,1136,4136,9136,72,73,'KNAAAA','ZTMAAA','VVVVxx'
+8782,8632,0,2,2,2,82,782,782,3782,8782,164,165,'UZAAAA','AUMAAA','AAAAxx'
+8491,8633,1,3,1,11,91,491,491,3491,8491,182,183,'POAAAA','BUMAAA','HHHHxx'
+5114,8634,0,2,4,14,14,114,1114,114,5114,28,29,'SOAAAA','CUMAAA','OOOOxx'
+5815,8635,1,3,5,15,15,815,1815,815,5815,30,31,'RPAAAA','DUMAAA','VVVVxx'
+5628,8636,0,0,8,8,28,628,1628,628,5628,56,57,'MIAAAA','EUMAAA','AAAAxx'
+810,8637,0,2,0,10,10,810,810,810,810,20,21,'EFAAAA','FUMAAA','HHHHxx'
+6178,8638,0,2,8,18,78,178,178,1178,6178,156,157,'QDAAAA','GUMAAA','OOOOxx'
+2619,8639,1,3,9,19,19,619,619,2619,2619,38,39,'TWAAAA','HUMAAA','VVVVxx'
+3340,8640,0,0,0,0,40,340,1340,3340,3340,80,81,'MYAAAA','IUMAAA','AAAAxx'
+2491,8641,1,3,1,11,91,491,491,2491,2491,182,183,'VRAAAA','JUMAAA','HHHHxx'
+3574,8642,0,2,4,14,74,574,1574,3574,3574,148,149,'MHAAAA','KUMAAA','OOOOxx'
+6754,8643,0,2,4,14,54,754,754,1754,6754,108,109,'UZAAAA','LUMAAA','VVVVxx'
+1566,8644,0,2,6,6,66,566,1566,1566,1566,132,133,'GIAAAA','MUMAAA','AAAAxx'
+9174,8645,0,2,4,14,74,174,1174,4174,9174,148,149,'WOAAAA','NUMAAA','HHHHxx'
+1520,8646,0,0,0,0,20,520,1520,1520,1520,40,41,'MGAAAA','OUMAAA','OOOOxx'
+2691,8647,1,3,1,11,91,691,691,2691,2691,182,183,'NZAAAA','PUMAAA','VVVVxx'
+6961,8648,1,1,1,1,61,961,961,1961,6961,122,123,'THAAAA','QUMAAA','AAAAxx'
+5722,8649,0,2,2,2,22,722,1722,722,5722,44,45,'CMAAAA','RUMAAA','HHHHxx'
+9707,8650,1,3,7,7,7,707,1707,4707,9707,14,15,'JJAAAA','SUMAAA','OOOOxx'
+2891,8651,1,3,1,11,91,891,891,2891,2891,182,183,'FHAAAA','TUMAAA','VVVVxx'
+341,8652,1,1,1,1,41,341,341,341,341,82,83,'DNAAAA','UUMAAA','AAAAxx'
+4690,8653,0,2,0,10,90,690,690,4690,4690,180,181,'KYAAAA','VUMAAA','HHHHxx'
+7841,8654,1,1,1,1,41,841,1841,2841,7841,82,83,'PPAAAA','WUMAAA','OOOOxx'
+6615,8655,1,3,5,15,15,615,615,1615,6615,30,31,'LUAAAA','XUMAAA','VVVVxx'
+9169,8656,1,1,9,9,69,169,1169,4169,9169,138,139,'ROAAAA','YUMAAA','AAAAxx'
+6689,8657,1,1,9,9,89,689,689,1689,6689,178,179,'HXAAAA','ZUMAAA','HHHHxx'
+8721,8658,1,1,1,1,21,721,721,3721,8721,42,43,'LXAAAA','AVMAAA','OOOOxx'
+7508,8659,0,0,8,8,8,508,1508,2508,7508,16,17,'UCAAAA','BVMAAA','VVVVxx'
+8631,8660,1,3,1,11,31,631,631,3631,8631,62,63,'ZTAAAA','CVMAAA','AAAAxx'
+480,8661,0,0,0,0,80,480,480,480,480,160,161,'MSAAAA','DVMAAA','HHHHxx'
+7094,8662,0,2,4,14,94,94,1094,2094,7094,188,189,'WMAAAA','EVMAAA','OOOOxx'
+319,8663,1,3,9,19,19,319,319,319,319,38,39,'HMAAAA','FVMAAA','VVVVxx'
+9421,8664,1,1,1,1,21,421,1421,4421,9421,42,43,'JYAAAA','GVMAAA','AAAAxx'
+4352,8665,0,0,2,12,52,352,352,4352,4352,104,105,'KLAAAA','HVMAAA','HHHHxx'
+5019,8666,1,3,9,19,19,19,1019,19,5019,38,39,'BLAAAA','IVMAAA','OOOOxx'
+3956,8667,0,0,6,16,56,956,1956,3956,3956,112,113,'EWAAAA','JVMAAA','VVVVxx'
+114,8668,0,2,4,14,14,114,114,114,114,28,29,'KEAAAA','KVMAAA','AAAAxx'
+1196,8669,0,0,6,16,96,196,1196,1196,1196,192,193,'AUAAAA','LVMAAA','HHHHxx'
+1407,8670,1,3,7,7,7,407,1407,1407,1407,14,15,'DCAAAA','MVMAAA','OOOOxx'
+7432,8671,0,0,2,12,32,432,1432,2432,7432,64,65,'WZAAAA','NVMAAA','VVVVxx'
+3141,8672,1,1,1,1,41,141,1141,3141,3141,82,83,'VQAAAA','OVMAAA','AAAAxx'
+2073,8673,1,1,3,13,73,73,73,2073,2073,146,147,'TBAAAA','PVMAAA','HHHHxx'
+3400,8674,0,0,0,0,0,400,1400,3400,3400,0,1,'UAAAAA','QVMAAA','OOOOxx'
+505,8675,1,1,5,5,5,505,505,505,505,10,11,'LTAAAA','RVMAAA','VVVVxx'
+1263,8676,1,3,3,3,63,263,1263,1263,1263,126,127,'PWAAAA','SVMAAA','AAAAxx'
+190,8677,0,2,0,10,90,190,190,190,190,180,181,'IHAAAA','TVMAAA','HHHHxx'
+6686,8678,0,2,6,6,86,686,686,1686,6686,172,173,'EXAAAA','UVMAAA','OOOOxx'
+9821,8679,1,1,1,1,21,821,1821,4821,9821,42,43,'TNAAAA','VVMAAA','VVVVxx'
+1119,8680,1,3,9,19,19,119,1119,1119,1119,38,39,'BRAAAA','WVMAAA','AAAAxx'
+2955,8681,1,3,5,15,55,955,955,2955,2955,110,111,'RJAAAA','XVMAAA','HHHHxx'
+224,8682,0,0,4,4,24,224,224,224,224,48,49,'QIAAAA','YVMAAA','OOOOxx'
+7562,8683,0,2,2,2,62,562,1562,2562,7562,124,125,'WEAAAA','ZVMAAA','VVVVxx'
+8845,8684,1,1,5,5,45,845,845,3845,8845,90,91,'FCAAAA','AWMAAA','AAAAxx'
+5405,8685,1,1,5,5,5,405,1405,405,5405,10,11,'XZAAAA','BWMAAA','HHHHxx'
+9192,8686,0,0,2,12,92,192,1192,4192,9192,184,185,'OPAAAA','CWMAAA','OOOOxx'
+4927,8687,1,3,7,7,27,927,927,4927,4927,54,55,'NHAAAA','DWMAAA','VVVVxx'
+997,8688,1,1,7,17,97,997,997,997,997,194,195,'JMAAAA','EWMAAA','AAAAxx'
+989,8689,1,1,9,9,89,989,989,989,989,178,179,'BMAAAA','FWMAAA','HHHHxx'
+7258,8690,0,2,8,18,58,258,1258,2258,7258,116,117,'ETAAAA','GWMAAA','OOOOxx'
+6899,8691,1,3,9,19,99,899,899,1899,6899,198,199,'JFAAAA','HWMAAA','VVVVxx'
+1770,8692,0,2,0,10,70,770,1770,1770,1770,140,141,'CQAAAA','IWMAAA','AAAAxx'
+4423,8693,1,3,3,3,23,423,423,4423,4423,46,47,'DOAAAA','JWMAAA','HHHHxx'
+5671,8694,1,3,1,11,71,671,1671,671,5671,142,143,'DKAAAA','KWMAAA','OOOOxx'
+8393,8695,1,1,3,13,93,393,393,3393,8393,186,187,'VKAAAA','LWMAAA','VVVVxx'
+4355,8696,1,3,5,15,55,355,355,4355,4355,110,111,'NLAAAA','MWMAAA','AAAAxx'
+3919,8697,1,3,9,19,19,919,1919,3919,3919,38,39,'TUAAAA','NWMAAA','HHHHxx'
+338,8698,0,2,8,18,38,338,338,338,338,76,77,'ANAAAA','OWMAAA','OOOOxx'
+5790,8699,0,2,0,10,90,790,1790,790,5790,180,181,'SOAAAA','PWMAAA','VVVVxx'
+1452,8700,0,0,2,12,52,452,1452,1452,1452,104,105,'WDAAAA','QWMAAA','AAAAxx'
+939,8701,1,3,9,19,39,939,939,939,939,78,79,'DKAAAA','RWMAAA','HHHHxx'
+8913,8702,1,1,3,13,13,913,913,3913,8913,26,27,'VEAAAA','SWMAAA','OOOOxx'
+7157,8703,1,1,7,17,57,157,1157,2157,7157,114,115,'HPAAAA','TWMAAA','VVVVxx'
+7240,8704,0,0,0,0,40,240,1240,2240,7240,80,81,'MSAAAA','UWMAAA','AAAAxx'
+3492,8705,0,0,2,12,92,492,1492,3492,3492,184,185,'IEAAAA','VWMAAA','HHHHxx'
+3464,8706,0,0,4,4,64,464,1464,3464,3464,128,129,'GDAAAA','WWMAAA','OOOOxx'
+388,8707,0,0,8,8,88,388,388,388,388,176,177,'YOAAAA','XWMAAA','VVVVxx'
+4135,8708,1,3,5,15,35,135,135,4135,4135,70,71,'BDAAAA','YWMAAA','AAAAxx'
+1194,8709,0,2,4,14,94,194,1194,1194,1194,188,189,'YTAAAA','ZWMAAA','HHHHxx'
+5476,8710,0,0,6,16,76,476,1476,476,5476,152,153,'QCAAAA','AXMAAA','OOOOxx'
+9844,8711,0,0,4,4,44,844,1844,4844,9844,88,89,'QOAAAA','BXMAAA','VVVVxx'
+9364,8712,0,0,4,4,64,364,1364,4364,9364,128,129,'EWAAAA','CXMAAA','AAAAxx'
+5238,8713,0,2,8,18,38,238,1238,238,5238,76,77,'MTAAAA','DXMAAA','HHHHxx'
+3712,8714,0,0,2,12,12,712,1712,3712,3712,24,25,'UMAAAA','EXMAAA','OOOOxx'
+6189,8715,1,1,9,9,89,189,189,1189,6189,178,179,'BEAAAA','FXMAAA','VVVVxx'
+5257,8716,1,1,7,17,57,257,1257,257,5257,114,115,'FUAAAA','GXMAAA','AAAAxx'
+81,8717,1,1,1,1,81,81,81,81,81,162,163,'DDAAAA','HXMAAA','HHHHxx'
+3289,8718,1,1,9,9,89,289,1289,3289,3289,178,179,'NWAAAA','IXMAAA','OOOOxx'
+1177,8719,1,1,7,17,77,177,1177,1177,1177,154,155,'HTAAAA','JXMAAA','VVVVxx'
+5038,8720,0,2,8,18,38,38,1038,38,5038,76,77,'ULAAAA','KXMAAA','AAAAxx'
+325,8721,1,1,5,5,25,325,325,325,325,50,51,'NMAAAA','LXMAAA','HHHHxx'
+7221,8722,1,1,1,1,21,221,1221,2221,7221,42,43,'TRAAAA','MXMAAA','OOOOxx'
+7123,8723,1,3,3,3,23,123,1123,2123,7123,46,47,'ZNAAAA','NXMAAA','VVVVxx'
+6364,8724,0,0,4,4,64,364,364,1364,6364,128,129,'UKAAAA','OXMAAA','AAAAxx'
+4468,8725,0,0,8,8,68,468,468,4468,4468,136,137,'WPAAAA','PXMAAA','HHHHxx'
+9185,8726,1,1,5,5,85,185,1185,4185,9185,170,171,'HPAAAA','QXMAAA','OOOOxx'
+4158,8727,0,2,8,18,58,158,158,4158,4158,116,117,'YDAAAA','RXMAAA','VVVVxx'
+9439,8728,1,3,9,19,39,439,1439,4439,9439,78,79,'BZAAAA','SXMAAA','AAAAxx'
+7759,8729,1,3,9,19,59,759,1759,2759,7759,118,119,'LMAAAA','TXMAAA','HHHHxx'
+3325,8730,1,1,5,5,25,325,1325,3325,3325,50,51,'XXAAAA','UXMAAA','OOOOxx'
+7991,8731,1,3,1,11,91,991,1991,2991,7991,182,183,'JVAAAA','VXMAAA','VVVVxx'
+1650,8732,0,2,0,10,50,650,1650,1650,1650,100,101,'MLAAAA','WXMAAA','AAAAxx'
+8395,8733,1,3,5,15,95,395,395,3395,8395,190,191,'XKAAAA','XXMAAA','HHHHxx'
+286,8734,0,2,6,6,86,286,286,286,286,172,173,'ALAAAA','YXMAAA','OOOOxx'
+1507,8735,1,3,7,7,7,507,1507,1507,1507,14,15,'ZFAAAA','ZXMAAA','VVVVxx'
+4122,8736,0,2,2,2,22,122,122,4122,4122,44,45,'OCAAAA','AYMAAA','AAAAxx'
+2625,8737,1,1,5,5,25,625,625,2625,2625,50,51,'ZWAAAA','BYMAAA','HHHHxx'
+1140,8738,0,0,0,0,40,140,1140,1140,1140,80,81,'WRAAAA','CYMAAA','OOOOxx'
+5262,8739,0,2,2,2,62,262,1262,262,5262,124,125,'KUAAAA','DYMAAA','VVVVxx'
+4919,8740,1,3,9,19,19,919,919,4919,4919,38,39,'FHAAAA','EYMAAA','AAAAxx'
+7266,8741,0,2,6,6,66,266,1266,2266,7266,132,133,'MTAAAA','FYMAAA','HHHHxx'
+630,8742,0,2,0,10,30,630,630,630,630,60,61,'GYAAAA','GYMAAA','OOOOxx'
+2129,8743,1,1,9,9,29,129,129,2129,2129,58,59,'XDAAAA','HYMAAA','VVVVxx'
+9552,8744,0,0,2,12,52,552,1552,4552,9552,104,105,'KDAAAA','IYMAAA','AAAAxx'
+3018,8745,0,2,8,18,18,18,1018,3018,3018,36,37,'CMAAAA','JYMAAA','HHHHxx'
+7145,8746,1,1,5,5,45,145,1145,2145,7145,90,91,'VOAAAA','KYMAAA','OOOOxx'
+1633,8747,1,1,3,13,33,633,1633,1633,1633,66,67,'VKAAAA','LYMAAA','VVVVxx'
+7957,8748,1,1,7,17,57,957,1957,2957,7957,114,115,'BUAAAA','MYMAAA','AAAAxx'
+774,8749,0,2,4,14,74,774,774,774,774,148,149,'UDAAAA','NYMAAA','HHHHxx'
+9371,8750,1,3,1,11,71,371,1371,4371,9371,142,143,'LWAAAA','OYMAAA','OOOOxx'
+6007,8751,1,3,7,7,7,7,7,1007,6007,14,15,'BXAAAA','PYMAAA','VVVVxx'
+5277,8752,1,1,7,17,77,277,1277,277,5277,154,155,'ZUAAAA','QYMAAA','AAAAxx'
+9426,8753,0,2,6,6,26,426,1426,4426,9426,52,53,'OYAAAA','RYMAAA','HHHHxx'
+9190,8754,0,2,0,10,90,190,1190,4190,9190,180,181,'MPAAAA','SYMAAA','OOOOxx'
+8996,8755,0,0,6,16,96,996,996,3996,8996,192,193,'AIAAAA','TYMAAA','VVVVxx'
+3409,8756,1,1,9,9,9,409,1409,3409,3409,18,19,'DBAAAA','UYMAAA','AAAAxx'
+7212,8757,0,0,2,12,12,212,1212,2212,7212,24,25,'KRAAAA','VYMAAA','HHHHxx'
+416,8758,0,0,6,16,16,416,416,416,416,32,33,'AQAAAA','WYMAAA','OOOOxx'
+7211,8759,1,3,1,11,11,211,1211,2211,7211,22,23,'JRAAAA','XYMAAA','VVVVxx'
+7454,8760,0,2,4,14,54,454,1454,2454,7454,108,109,'SAAAAA','YYMAAA','AAAAxx'
+8417,8761,1,1,7,17,17,417,417,3417,8417,34,35,'TLAAAA','ZYMAAA','HHHHxx'
+5562,8762,0,2,2,2,62,562,1562,562,5562,124,125,'YFAAAA','AZMAAA','OOOOxx'
+4996,8763,0,0,6,16,96,996,996,4996,4996,192,193,'EKAAAA','BZMAAA','VVVVxx'
+5718,8764,0,2,8,18,18,718,1718,718,5718,36,37,'YLAAAA','CZMAAA','AAAAxx'
+7838,8765,0,2,8,18,38,838,1838,2838,7838,76,77,'MPAAAA','DZMAAA','HHHHxx'
+7715,8766,1,3,5,15,15,715,1715,2715,7715,30,31,'TKAAAA','EZMAAA','OOOOxx'
+2780,8767,0,0,0,0,80,780,780,2780,2780,160,161,'YCAAAA','FZMAAA','VVVVxx'
+1013,8768,1,1,3,13,13,13,1013,1013,1013,26,27,'ZMAAAA','GZMAAA','AAAAxx'
+8465,8769,1,1,5,5,65,465,465,3465,8465,130,131,'PNAAAA','HZMAAA','HHHHxx'
+7976,8770,0,0,6,16,76,976,1976,2976,7976,152,153,'UUAAAA','IZMAAA','OOOOxx'
+7150,8771,0,2,0,10,50,150,1150,2150,7150,100,101,'APAAAA','JZMAAA','VVVVxx'
+6471,8772,1,3,1,11,71,471,471,1471,6471,142,143,'XOAAAA','KZMAAA','AAAAxx'
+1927,8773,1,3,7,7,27,927,1927,1927,1927,54,55,'DWAAAA','LZMAAA','HHHHxx'
+227,8774,1,3,7,7,27,227,227,227,227,54,55,'TIAAAA','MZMAAA','OOOOxx'
+6462,8775,0,2,2,2,62,462,462,1462,6462,124,125,'OOAAAA','NZMAAA','VVVVxx'
+5227,8776,1,3,7,7,27,227,1227,227,5227,54,55,'BTAAAA','OZMAAA','AAAAxx'
+1074,8777,0,2,4,14,74,74,1074,1074,1074,148,149,'IPAAAA','PZMAAA','HHHHxx'
+9448,8778,0,0,8,8,48,448,1448,4448,9448,96,97,'KZAAAA','QZMAAA','OOOOxx'
+4459,8779,1,3,9,19,59,459,459,4459,4459,118,119,'NPAAAA','RZMAAA','VVVVxx'
+2478,8780,0,2,8,18,78,478,478,2478,2478,156,157,'IRAAAA','SZMAAA','AAAAxx'
+5005,8781,1,1,5,5,5,5,1005,5,5005,10,11,'NKAAAA','TZMAAA','HHHHxx'
+2418,8782,0,2,8,18,18,418,418,2418,2418,36,37,'APAAAA','UZMAAA','OOOOxx'
+6991,8783,1,3,1,11,91,991,991,1991,6991,182,183,'XIAAAA','VZMAAA','VVVVxx'
+4729,8784,1,1,9,9,29,729,729,4729,4729,58,59,'XZAAAA','WZMAAA','AAAAxx'
+3548,8785,0,0,8,8,48,548,1548,3548,3548,96,97,'MGAAAA','XZMAAA','HHHHxx'
+9616,8786,0,0,6,16,16,616,1616,4616,9616,32,33,'WFAAAA','YZMAAA','OOOOxx'
+2901,8787,1,1,1,1,1,901,901,2901,2901,2,3,'PHAAAA','ZZMAAA','VVVVxx'
+10,8788,0,2,0,10,10,10,10,10,10,20,21,'KAAAAA','AANAAA','AAAAxx'
+2637,8789,1,1,7,17,37,637,637,2637,2637,74,75,'LXAAAA','BANAAA','HHHHxx'
+6747,8790,1,3,7,7,47,747,747,1747,6747,94,95,'NZAAAA','CANAAA','OOOOxx'
+797,8791,1,1,7,17,97,797,797,797,797,194,195,'REAAAA','DANAAA','VVVVxx'
+7609,8792,1,1,9,9,9,609,1609,2609,7609,18,19,'RGAAAA','EANAAA','AAAAxx'
+8290,8793,0,2,0,10,90,290,290,3290,8290,180,181,'WGAAAA','FANAAA','HHHHxx'
+8765,8794,1,1,5,5,65,765,765,3765,8765,130,131,'DZAAAA','GANAAA','OOOOxx'
+8053,8795,1,1,3,13,53,53,53,3053,8053,106,107,'TXAAAA','HANAAA','VVVVxx'
+5602,8796,0,2,2,2,2,602,1602,602,5602,4,5,'MHAAAA','IANAAA','AAAAxx'
+3672,8797,0,0,2,12,72,672,1672,3672,3672,144,145,'GLAAAA','JANAAA','HHHHxx'
+7513,8798,1,1,3,13,13,513,1513,2513,7513,26,27,'ZCAAAA','KANAAA','OOOOxx'
+3462,8799,0,2,2,2,62,462,1462,3462,3462,124,125,'EDAAAA','LANAAA','VVVVxx'
+4457,8800,1,1,7,17,57,457,457,4457,4457,114,115,'LPAAAA','MANAAA','AAAAxx'
+6547,8801,1,3,7,7,47,547,547,1547,6547,94,95,'VRAAAA','NANAAA','HHHHxx'
+7417,8802,1,1,7,17,17,417,1417,2417,7417,34,35,'HZAAAA','OANAAA','OOOOxx'
+8641,8803,1,1,1,1,41,641,641,3641,8641,82,83,'JUAAAA','PANAAA','VVVVxx'
+149,8804,1,1,9,9,49,149,149,149,149,98,99,'TFAAAA','QANAAA','AAAAxx'
+5041,8805,1,1,1,1,41,41,1041,41,5041,82,83,'XLAAAA','RANAAA','HHHHxx'
+9232,8806,0,0,2,12,32,232,1232,4232,9232,64,65,'CRAAAA','SANAAA','OOOOxx'
+3603,8807,1,3,3,3,3,603,1603,3603,3603,6,7,'PIAAAA','TANAAA','VVVVxx'
+2792,8808,0,0,2,12,92,792,792,2792,2792,184,185,'KDAAAA','UANAAA','AAAAxx'
+6620,8809,0,0,0,0,20,620,620,1620,6620,40,41,'QUAAAA','VANAAA','HHHHxx'
+4000,8810,0,0,0,0,0,0,0,4000,4000,0,1,'WXAAAA','WANAAA','OOOOxx'
+659,8811,1,3,9,19,59,659,659,659,659,118,119,'JZAAAA','XANAAA','VVVVxx'
+8174,8812,0,2,4,14,74,174,174,3174,8174,148,149,'KCAAAA','YANAAA','AAAAxx'
+4599,8813,1,3,9,19,99,599,599,4599,4599,198,199,'XUAAAA','ZANAAA','HHHHxx'
+7851,8814,1,3,1,11,51,851,1851,2851,7851,102,103,'ZPAAAA','ABNAAA','OOOOxx'
+6284,8815,0,0,4,4,84,284,284,1284,6284,168,169,'SHAAAA','BBNAAA','VVVVxx'
+7116,8816,0,0,6,16,16,116,1116,2116,7116,32,33,'SNAAAA','CBNAAA','AAAAxx'
+5595,8817,1,3,5,15,95,595,1595,595,5595,190,191,'FHAAAA','DBNAAA','HHHHxx'
+2903,8818,1,3,3,3,3,903,903,2903,2903,6,7,'RHAAAA','EBNAAA','OOOOxx'
+5948,8819,0,0,8,8,48,948,1948,948,5948,96,97,'UUAAAA','FBNAAA','VVVVxx'
+225,8820,1,1,5,5,25,225,225,225,225,50,51,'RIAAAA','GBNAAA','AAAAxx'
+524,8821,0,0,4,4,24,524,524,524,524,48,49,'EUAAAA','HBNAAA','HHHHxx'
+7639,8822,1,3,9,19,39,639,1639,2639,7639,78,79,'VHAAAA','IBNAAA','OOOOxx'
+7297,8823,1,1,7,17,97,297,1297,2297,7297,194,195,'RUAAAA','JBNAAA','VVVVxx'
+2606,8824,0,2,6,6,6,606,606,2606,2606,12,13,'GWAAAA','KBNAAA','AAAAxx'
+4771,8825,1,3,1,11,71,771,771,4771,4771,142,143,'NBAAAA','LBNAAA','HHHHxx'
+8162,8826,0,2,2,2,62,162,162,3162,8162,124,125,'YBAAAA','MBNAAA','OOOOxx'
+8999,8827,1,3,9,19,99,999,999,3999,8999,198,199,'DIAAAA','NBNAAA','VVVVxx'
+2309,8828,1,1,9,9,9,309,309,2309,2309,18,19,'VKAAAA','OBNAAA','AAAAxx'
+3594,8829,0,2,4,14,94,594,1594,3594,3594,188,189,'GIAAAA','PBNAAA','HHHHxx'
+6092,8830,0,0,2,12,92,92,92,1092,6092,184,185,'IAAAAA','QBNAAA','OOOOxx'
+7467,8831,1,3,7,7,67,467,1467,2467,7467,134,135,'FBAAAA','RBNAAA','VVVVxx'
+6986,8832,0,2,6,6,86,986,986,1986,6986,172,173,'SIAAAA','SBNAAA','AAAAxx'
+9898,8833,0,2,8,18,98,898,1898,4898,9898,196,197,'SQAAAA','TBNAAA','HHHHxx'
+9578,8834,0,2,8,18,78,578,1578,4578,9578,156,157,'KEAAAA','UBNAAA','OOOOxx'
+156,8835,0,0,6,16,56,156,156,156,156,112,113,'AGAAAA','VBNAAA','VVVVxx'
+5810,8836,0,2,0,10,10,810,1810,810,5810,20,21,'MPAAAA','WBNAAA','AAAAxx'
+790,8837,0,2,0,10,90,790,790,790,790,180,181,'KEAAAA','XBNAAA','HHHHxx'
+6840,8838,0,0,0,0,40,840,840,1840,6840,80,81,'CDAAAA','YBNAAA','OOOOxx'
+6725,8839,1,1,5,5,25,725,725,1725,6725,50,51,'RYAAAA','ZBNAAA','VVVVxx'
+5528,8840,0,0,8,8,28,528,1528,528,5528,56,57,'QEAAAA','ACNAAA','AAAAxx'
+4120,8841,0,0,0,0,20,120,120,4120,4120,40,41,'MCAAAA','BCNAAA','HHHHxx'
+6694,8842,0,2,4,14,94,694,694,1694,6694,188,189,'MXAAAA','CCNAAA','OOOOxx'
+3552,8843,0,0,2,12,52,552,1552,3552,3552,104,105,'QGAAAA','DCNAAA','VVVVxx'
+1478,8844,0,2,8,18,78,478,1478,1478,1478,156,157,'WEAAAA','ECNAAA','AAAAxx'
+8084,8845,0,0,4,4,84,84,84,3084,8084,168,169,'YYAAAA','FCNAAA','HHHHxx'
+7578,8846,0,2,8,18,78,578,1578,2578,7578,156,157,'MFAAAA','GCNAAA','OOOOxx'
+6314,8847,0,2,4,14,14,314,314,1314,6314,28,29,'WIAAAA','HCNAAA','VVVVxx'
+6123,8848,1,3,3,3,23,123,123,1123,6123,46,47,'NBAAAA','ICNAAA','AAAAxx'
+9443,8849,1,3,3,3,43,443,1443,4443,9443,86,87,'FZAAAA','JCNAAA','HHHHxx'
+9628,8850,0,0,8,8,28,628,1628,4628,9628,56,57,'IGAAAA','KCNAAA','OOOOxx'
+8508,8851,0,0,8,8,8,508,508,3508,8508,16,17,'GPAAAA','LCNAAA','VVVVxx'
+5552,8852,0,0,2,12,52,552,1552,552,5552,104,105,'OFAAAA','MCNAAA','AAAAxx'
+5327,8853,1,3,7,7,27,327,1327,327,5327,54,55,'XWAAAA','NCNAAA','HHHHxx'
+7771,8854,1,3,1,11,71,771,1771,2771,7771,142,143,'XMAAAA','OCNAAA','OOOOxx'
+8932,8855,0,0,2,12,32,932,932,3932,8932,64,65,'OFAAAA','PCNAAA','VVVVxx'
+3526,8856,0,2,6,6,26,526,1526,3526,3526,52,53,'QFAAAA','QCNAAA','AAAAxx'
+4340,8857,0,0,0,0,40,340,340,4340,4340,80,81,'YKAAAA','RCNAAA','HHHHxx'
+9419,8858,1,3,9,19,19,419,1419,4419,9419,38,39,'HYAAAA','SCNAAA','OOOOxx'
+8421,8859,1,1,1,1,21,421,421,3421,8421,42,43,'XLAAAA','TCNAAA','VVVVxx'
+7431,8860,1,3,1,11,31,431,1431,2431,7431,62,63,'VZAAAA','UCNAAA','AAAAxx'
+172,8861,0,0,2,12,72,172,172,172,172,144,145,'QGAAAA','VCNAAA','HHHHxx'
+3279,8862,1,3,9,19,79,279,1279,3279,3279,158,159,'DWAAAA','WCNAAA','OOOOxx'
+1508,8863,0,0,8,8,8,508,1508,1508,1508,16,17,'AGAAAA','XCNAAA','VVVVxx'
+7091,8864,1,3,1,11,91,91,1091,2091,7091,182,183,'TMAAAA','YCNAAA','AAAAxx'
+1419,8865,1,3,9,19,19,419,1419,1419,1419,38,39,'PCAAAA','ZCNAAA','HHHHxx'
+3032,8866,0,0,2,12,32,32,1032,3032,3032,64,65,'QMAAAA','ADNAAA','OOOOxx'
+8683,8867,1,3,3,3,83,683,683,3683,8683,166,167,'ZVAAAA','BDNAAA','VVVVxx'
+4763,8868,1,3,3,3,63,763,763,4763,4763,126,127,'FBAAAA','CDNAAA','AAAAxx'
+4424,8869,0,0,4,4,24,424,424,4424,4424,48,49,'EOAAAA','DDNAAA','HHHHxx'
+8640,8870,0,0,0,0,40,640,640,3640,8640,80,81,'IUAAAA','EDNAAA','OOOOxx'
+7187,8871,1,3,7,7,87,187,1187,2187,7187,174,175,'LQAAAA','FDNAAA','VVVVxx'
+6247,8872,1,3,7,7,47,247,247,1247,6247,94,95,'HGAAAA','GDNAAA','AAAAxx'
+7340,8873,0,0,0,0,40,340,1340,2340,7340,80,81,'IWAAAA','HDNAAA','HHHHxx'
+182,8874,0,2,2,2,82,182,182,182,182,164,165,'AHAAAA','IDNAAA','OOOOxx'
+2948,8875,0,0,8,8,48,948,948,2948,2948,96,97,'KJAAAA','JDNAAA','VVVVxx'
+9462,8876,0,2,2,2,62,462,1462,4462,9462,124,125,'YZAAAA','KDNAAA','AAAAxx'
+5997,8877,1,1,7,17,97,997,1997,997,5997,194,195,'RWAAAA','LDNAAA','HHHHxx'
+5608,8878,0,0,8,8,8,608,1608,608,5608,16,17,'SHAAAA','MDNAAA','OOOOxx'
+1472,8879,0,0,2,12,72,472,1472,1472,1472,144,145,'QEAAAA','NDNAAA','VVVVxx'
+277,8880,1,1,7,17,77,277,277,277,277,154,155,'RKAAAA','ODNAAA','AAAAxx'
+4807,8881,1,3,7,7,7,807,807,4807,4807,14,15,'XCAAAA','PDNAAA','HHHHxx'
+4969,8882,1,1,9,9,69,969,969,4969,4969,138,139,'DJAAAA','QDNAAA','OOOOxx'
+5611,8883,1,3,1,11,11,611,1611,611,5611,22,23,'VHAAAA','RDNAAA','VVVVxx'
+372,8884,0,0,2,12,72,372,372,372,372,144,145,'IOAAAA','SDNAAA','AAAAxx'
+6666,8885,0,2,6,6,66,666,666,1666,6666,132,133,'KWAAAA','TDNAAA','HHHHxx'
+476,8886,0,0,6,16,76,476,476,476,476,152,153,'ISAAAA','UDNAAA','OOOOxx'
+5225,8887,1,1,5,5,25,225,1225,225,5225,50,51,'ZSAAAA','VDNAAA','VVVVxx'
+5143,8888,1,3,3,3,43,143,1143,143,5143,86,87,'VPAAAA','WDNAAA','AAAAxx'
+1853,8889,1,1,3,13,53,853,1853,1853,1853,106,107,'HTAAAA','XDNAAA','HHHHxx'
+675,8890,1,3,5,15,75,675,675,675,675,150,151,'ZZAAAA','YDNAAA','OOOOxx'
+5643,8891,1,3,3,3,43,643,1643,643,5643,86,87,'BJAAAA','ZDNAAA','VVVVxx'
+5317,8892,1,1,7,17,17,317,1317,317,5317,34,35,'NWAAAA','AENAAA','AAAAxx'
+8102,8893,0,2,2,2,2,102,102,3102,8102,4,5,'QZAAAA','BENAAA','HHHHxx'
+978,8894,0,2,8,18,78,978,978,978,978,156,157,'QLAAAA','CENAAA','OOOOxx'
+4620,8895,0,0,0,0,20,620,620,4620,4620,40,41,'SVAAAA','DENAAA','VVVVxx'
+151,8896,1,3,1,11,51,151,151,151,151,102,103,'VFAAAA','EENAAA','AAAAxx'
+972,8897,0,0,2,12,72,972,972,972,972,144,145,'KLAAAA','FENAAA','HHHHxx'
+6820,8898,0,0,0,0,20,820,820,1820,6820,40,41,'ICAAAA','GENAAA','OOOOxx'
+7387,8899,1,3,7,7,87,387,1387,2387,7387,174,175,'DYAAAA','HENAAA','VVVVxx'
+9634,8900,0,2,4,14,34,634,1634,4634,9634,68,69,'OGAAAA','IENAAA','AAAAxx'
+6308,8901,0,0,8,8,8,308,308,1308,6308,16,17,'QIAAAA','JENAAA','HHHHxx'
+8323,8902,1,3,3,3,23,323,323,3323,8323,46,47,'DIAAAA','KENAAA','OOOOxx'
+6672,8903,0,0,2,12,72,672,672,1672,6672,144,145,'QWAAAA','LENAAA','VVVVxx'
+8283,8904,1,3,3,3,83,283,283,3283,8283,166,167,'PGAAAA','MENAAA','AAAAxx'
+7996,8905,0,0,6,16,96,996,1996,2996,7996,192,193,'OVAAAA','NENAAA','HHHHxx'
+6488,8906,0,0,8,8,88,488,488,1488,6488,176,177,'OPAAAA','OENAAA','OOOOxx'
+2365,8907,1,1,5,5,65,365,365,2365,2365,130,131,'ZMAAAA','PENAAA','VVVVxx'
+9746,8908,0,2,6,6,46,746,1746,4746,9746,92,93,'WKAAAA','QENAAA','AAAAxx'
+8605,8909,1,1,5,5,5,605,605,3605,8605,10,11,'ZSAAAA','RENAAA','HHHHxx'
+3342,8910,0,2,2,2,42,342,1342,3342,3342,84,85,'OYAAAA','SENAAA','OOOOxx'
+8429,8911,1,1,9,9,29,429,429,3429,8429,58,59,'FMAAAA','TENAAA','VVVVxx'
+1162,8912,0,2,2,2,62,162,1162,1162,1162,124,125,'SSAAAA','UENAAA','AAAAxx'
+531,8913,1,3,1,11,31,531,531,531,531,62,63,'LUAAAA','VENAAA','HHHHxx'
+8408,8914,0,0,8,8,8,408,408,3408,8408,16,17,'KLAAAA','WENAAA','OOOOxx'
+8862,8915,0,2,2,2,62,862,862,3862,8862,124,125,'WCAAAA','XENAAA','VVVVxx'
+5843,8916,1,3,3,3,43,843,1843,843,5843,86,87,'TQAAAA','YENAAA','AAAAxx'
+8704,8917,0,0,4,4,4,704,704,3704,8704,8,9,'UWAAAA','ZENAAA','HHHHxx'
+7070,8918,0,2,0,10,70,70,1070,2070,7070,140,141,'YLAAAA','AFNAAA','OOOOxx'
+9119,8919,1,3,9,19,19,119,1119,4119,9119,38,39,'TMAAAA','BFNAAA','VVVVxx'
+8344,8920,0,0,4,4,44,344,344,3344,8344,88,89,'YIAAAA','CFNAAA','AAAAxx'
+8979,8921,1,3,9,19,79,979,979,3979,8979,158,159,'JHAAAA','DFNAAA','HHHHxx'
+2971,8922,1,3,1,11,71,971,971,2971,2971,142,143,'HKAAAA','EFNAAA','OOOOxx'
+7700,8923,0,0,0,0,0,700,1700,2700,7700,0,1,'EKAAAA','FFNAAA','VVVVxx'
+8280,8924,0,0,0,0,80,280,280,3280,8280,160,161,'MGAAAA','GFNAAA','AAAAxx'
+9096,8925,0,0,6,16,96,96,1096,4096,9096,192,193,'WLAAAA','HFNAAA','HHHHxx'
+99,8926,1,3,9,19,99,99,99,99,99,198,199,'VDAAAA','IFNAAA','OOOOxx'
+6696,8927,0,0,6,16,96,696,696,1696,6696,192,193,'OXAAAA','JFNAAA','VVVVxx'
+9490,8928,0,2,0,10,90,490,1490,4490,9490,180,181,'ABAAAA','KFNAAA','AAAAxx'
+9073,8929,1,1,3,13,73,73,1073,4073,9073,146,147,'ZKAAAA','LFNAAA','HHHHxx'
+1861,8930,1,1,1,1,61,861,1861,1861,1861,122,123,'PTAAAA','MFNAAA','OOOOxx'
+4413,8931,1,1,3,13,13,413,413,4413,4413,26,27,'TNAAAA','NFNAAA','VVVVxx'
+6002,8932,0,2,2,2,2,2,2,1002,6002,4,5,'WWAAAA','OFNAAA','AAAAxx'
+439,8933,1,3,9,19,39,439,439,439,439,78,79,'XQAAAA','PFNAAA','HHHHxx'
+5449,8934,1,1,9,9,49,449,1449,449,5449,98,99,'PBAAAA','QFNAAA','OOOOxx'
+9737,8935,1,1,7,17,37,737,1737,4737,9737,74,75,'NKAAAA','RFNAAA','VVVVxx'
+1898,8936,0,2,8,18,98,898,1898,1898,1898,196,197,'AVAAAA','SFNAAA','AAAAxx'
+4189,8937,1,1,9,9,89,189,189,4189,4189,178,179,'DFAAAA','TFNAAA','HHHHxx'
+1408,8938,0,0,8,8,8,408,1408,1408,1408,16,17,'ECAAAA','UFNAAA','OOOOxx'
+394,8939,0,2,4,14,94,394,394,394,394,188,189,'EPAAAA','VFNAAA','VVVVxx'
+1935,8940,1,3,5,15,35,935,1935,1935,1935,70,71,'LWAAAA','WFNAAA','AAAAxx'
+3965,8941,1,1,5,5,65,965,1965,3965,3965,130,131,'NWAAAA','XFNAAA','HHHHxx'
+6821,8942,1,1,1,1,21,821,821,1821,6821,42,43,'JCAAAA','YFNAAA','OOOOxx'
+349,8943,1,1,9,9,49,349,349,349,349,98,99,'LNAAAA','ZFNAAA','VVVVxx'
+8428,8944,0,0,8,8,28,428,428,3428,8428,56,57,'EMAAAA','AGNAAA','AAAAxx'
+8200,8945,0,0,0,0,0,200,200,3200,8200,0,1,'KDAAAA','BGNAAA','HHHHxx'
+1737,8946,1,1,7,17,37,737,1737,1737,1737,74,75,'VOAAAA','CGNAAA','OOOOxx'
+6516,8947,0,0,6,16,16,516,516,1516,6516,32,33,'QQAAAA','DGNAAA','VVVVxx'
+5441,8948,1,1,1,1,41,441,1441,441,5441,82,83,'HBAAAA','EGNAAA','AAAAxx'
+5999,8949,1,3,9,19,99,999,1999,999,5999,198,199,'TWAAAA','FGNAAA','HHHHxx'
+1539,8950,1,3,9,19,39,539,1539,1539,1539,78,79,'FHAAAA','GGNAAA','OOOOxx'
+9067,8951,1,3,7,7,67,67,1067,4067,9067,134,135,'TKAAAA','HGNAAA','VVVVxx'
+4061,8952,1,1,1,1,61,61,61,4061,4061,122,123,'FAAAAA','IGNAAA','AAAAxx'
+1642,8953,0,2,2,2,42,642,1642,1642,1642,84,85,'ELAAAA','JGNAAA','HHHHxx'
+4657,8954,1,1,7,17,57,657,657,4657,4657,114,115,'DXAAAA','KGNAAA','OOOOxx'
+9934,8955,0,2,4,14,34,934,1934,4934,9934,68,69,'CSAAAA','LGNAAA','VVVVxx'
+6385,8956,1,1,5,5,85,385,385,1385,6385,170,171,'PLAAAA','MGNAAA','AAAAxx'
+6775,8957,1,3,5,15,75,775,775,1775,6775,150,151,'PAAAAA','NGNAAA','HHHHxx'
+3873,8958,1,1,3,13,73,873,1873,3873,3873,146,147,'ZSAAAA','OGNAAA','OOOOxx'
+3862,8959,0,2,2,2,62,862,1862,3862,3862,124,125,'OSAAAA','PGNAAA','VVVVxx'
+1224,8960,0,0,4,4,24,224,1224,1224,1224,48,49,'CVAAAA','QGNAAA','AAAAxx'
+4483,8961,1,3,3,3,83,483,483,4483,4483,166,167,'LQAAAA','RGNAAA','HHHHxx'
+3685,8962,1,1,5,5,85,685,1685,3685,3685,170,171,'TLAAAA','SGNAAA','OOOOxx'
+6082,8963,0,2,2,2,82,82,82,1082,6082,164,165,'YZAAAA','TGNAAA','VVVVxx'
+7798,8964,0,2,8,18,98,798,1798,2798,7798,196,197,'YNAAAA','UGNAAA','AAAAxx'
+9039,8965,1,3,9,19,39,39,1039,4039,9039,78,79,'RJAAAA','VGNAAA','HHHHxx'
+985,8966,1,1,5,5,85,985,985,985,985,170,171,'XLAAAA','WGNAAA','OOOOxx'
+5389,8967,1,1,9,9,89,389,1389,389,5389,178,179,'HZAAAA','XGNAAA','VVVVxx'
+1716,8968,0,0,6,16,16,716,1716,1716,1716,32,33,'AOAAAA','YGNAAA','AAAAxx'
+4209,8969,1,1,9,9,9,209,209,4209,4209,18,19,'XFAAAA','ZGNAAA','HHHHxx'
+746,8970,0,2,6,6,46,746,746,746,746,92,93,'SCAAAA','AHNAAA','OOOOxx'
+6295,8971,1,3,5,15,95,295,295,1295,6295,190,191,'DIAAAA','BHNAAA','VVVVxx'
+9754,8972,0,2,4,14,54,754,1754,4754,9754,108,109,'ELAAAA','CHNAAA','AAAAxx'
+2336,8973,0,0,6,16,36,336,336,2336,2336,72,73,'WLAAAA','DHNAAA','HHHHxx'
+3701,8974,1,1,1,1,1,701,1701,3701,3701,2,3,'JMAAAA','EHNAAA','OOOOxx'
+3551,8975,1,3,1,11,51,551,1551,3551,3551,102,103,'PGAAAA','FHNAAA','VVVVxx'
+8516,8976,0,0,6,16,16,516,516,3516,8516,32,33,'OPAAAA','GHNAAA','AAAAxx'
+9290,8977,0,2,0,10,90,290,1290,4290,9290,180,181,'ITAAAA','HHNAAA','HHHHxx'
+5686,8978,0,2,6,6,86,686,1686,686,5686,172,173,'SKAAAA','IHNAAA','OOOOxx'
+2893,8979,1,1,3,13,93,893,893,2893,2893,186,187,'HHAAAA','JHNAAA','VVVVxx'
+6279,8980,1,3,9,19,79,279,279,1279,6279,158,159,'NHAAAA','KHNAAA','AAAAxx'
+2278,8981,0,2,8,18,78,278,278,2278,2278,156,157,'QJAAAA','LHNAAA','HHHHxx'
+1618,8982,0,2,8,18,18,618,1618,1618,1618,36,37,'GKAAAA','MHNAAA','OOOOxx'
+3450,8983,0,2,0,10,50,450,1450,3450,3450,100,101,'SCAAAA','NHNAAA','VVVVxx'
+8857,8984,1,1,7,17,57,857,857,3857,8857,114,115,'RCAAAA','OHNAAA','AAAAxx'
+1005,8985,1,1,5,5,5,5,1005,1005,1005,10,11,'RMAAAA','PHNAAA','HHHHxx'
+4727,8986,1,3,7,7,27,727,727,4727,4727,54,55,'VZAAAA','QHNAAA','OOOOxx'
+7617,8987,1,1,7,17,17,617,1617,2617,7617,34,35,'ZGAAAA','RHNAAA','VVVVxx'
+2021,8988,1,1,1,1,21,21,21,2021,2021,42,43,'TZAAAA','SHNAAA','AAAAxx'
+9124,8989,0,0,4,4,24,124,1124,4124,9124,48,49,'YMAAAA','THNAAA','HHHHxx'
+3175,8990,1,3,5,15,75,175,1175,3175,3175,150,151,'DSAAAA','UHNAAA','OOOOxx'
+2949,8991,1,1,9,9,49,949,949,2949,2949,98,99,'LJAAAA','VHNAAA','VVVVxx'
+2424,8992,0,0,4,4,24,424,424,2424,2424,48,49,'GPAAAA','WHNAAA','AAAAxx'
+4791,8993,1,3,1,11,91,791,791,4791,4791,182,183,'HCAAAA','XHNAAA','HHHHxx'
+7500,8994,0,0,0,0,0,500,1500,2500,7500,0,1,'MCAAAA','YHNAAA','OOOOxx'
+4893,8995,1,1,3,13,93,893,893,4893,4893,186,187,'FGAAAA','ZHNAAA','VVVVxx'
+121,8996,1,1,1,1,21,121,121,121,121,42,43,'REAAAA','AINAAA','AAAAxx'
+1965,8997,1,1,5,5,65,965,1965,1965,1965,130,131,'PXAAAA','BINAAA','HHHHxx'
+2972,8998,0,0,2,12,72,972,972,2972,2972,144,145,'IKAAAA','CINAAA','OOOOxx'
+662,8999,0,2,2,2,62,662,662,662,662,124,125,'MZAAAA','DINAAA','VVVVxx'
+7074,9000,0,2,4,14,74,74,1074,2074,7074,148,149,'CMAAAA','EINAAA','AAAAxx'
+981,9001,1,1,1,1,81,981,981,981,981,162,163,'TLAAAA','FINAAA','HHHHxx'
+3520,9002,0,0,0,0,20,520,1520,3520,3520,40,41,'KFAAAA','GINAAA','OOOOxx'
+6540,9003,0,0,0,0,40,540,540,1540,6540,80,81,'ORAAAA','HINAAA','VVVVxx'
+6648,9004,0,0,8,8,48,648,648,1648,6648,96,97,'SVAAAA','IINAAA','AAAAxx'
+7076,9005,0,0,6,16,76,76,1076,2076,7076,152,153,'EMAAAA','JINAAA','HHHHxx'
+6919,9006,1,3,9,19,19,919,919,1919,6919,38,39,'DGAAAA','KINAAA','OOOOxx'
+1108,9007,0,0,8,8,8,108,1108,1108,1108,16,17,'QQAAAA','LINAAA','VVVVxx'
+317,9008,1,1,7,17,17,317,317,317,317,34,35,'FMAAAA','MINAAA','AAAAxx'
+3483,9009,1,3,3,3,83,483,1483,3483,3483,166,167,'ZDAAAA','NINAAA','HHHHxx'
+6764,9010,0,0,4,4,64,764,764,1764,6764,128,129,'EAAAAA','OINAAA','OOOOxx'
+1235,9011,1,3,5,15,35,235,1235,1235,1235,70,71,'NVAAAA','PINAAA','VVVVxx'
+7121,9012,1,1,1,1,21,121,1121,2121,7121,42,43,'XNAAAA','QINAAA','AAAAxx'
+426,9013,0,2,6,6,26,426,426,426,426,52,53,'KQAAAA','RINAAA','HHHHxx'
+6880,9014,0,0,0,0,80,880,880,1880,6880,160,161,'QEAAAA','SINAAA','OOOOxx'
+5401,9015,1,1,1,1,1,401,1401,401,5401,2,3,'TZAAAA','TINAAA','VVVVxx'
+7323,9016,1,3,3,3,23,323,1323,2323,7323,46,47,'RVAAAA','UINAAA','AAAAxx'
+9751,9017,1,3,1,11,51,751,1751,4751,9751,102,103,'BLAAAA','VINAAA','HHHHxx'
+3436,9018,0,0,6,16,36,436,1436,3436,3436,72,73,'ECAAAA','WINAAA','OOOOxx'
+7319,9019,1,3,9,19,19,319,1319,2319,7319,38,39,'NVAAAA','XINAAA','VVVVxx'
+7882,9020,0,2,2,2,82,882,1882,2882,7882,164,165,'ERAAAA','YINAAA','AAAAxx'
+8260,9021,0,0,0,0,60,260,260,3260,8260,120,121,'SFAAAA','ZINAAA','HHHHxx'
+9758,9022,0,2,8,18,58,758,1758,4758,9758,116,117,'ILAAAA','AJNAAA','OOOOxx'
+4205,9023,1,1,5,5,5,205,205,4205,4205,10,11,'TFAAAA','BJNAAA','VVVVxx'
+8884,9024,0,0,4,4,84,884,884,3884,8884,168,169,'SDAAAA','CJNAAA','AAAAxx'
+1112,9025,0,0,2,12,12,112,1112,1112,1112,24,25,'UQAAAA','DJNAAA','HHHHxx'
+2186,9026,0,2,6,6,86,186,186,2186,2186,172,173,'CGAAAA','EJNAAA','OOOOxx'
+8666,9027,0,2,6,6,66,666,666,3666,8666,132,133,'IVAAAA','FJNAAA','VVVVxx'
+4325,9028,1,1,5,5,25,325,325,4325,4325,50,51,'JKAAAA','GJNAAA','AAAAxx'
+4912,9029,0,0,2,12,12,912,912,4912,4912,24,25,'YGAAAA','HJNAAA','HHHHxx'
+6497,9030,1,1,7,17,97,497,497,1497,6497,194,195,'XPAAAA','IJNAAA','OOOOxx'
+9072,9031,0,0,2,12,72,72,1072,4072,9072,144,145,'YKAAAA','JJNAAA','VVVVxx'
+8899,9032,1,3,9,19,99,899,899,3899,8899,198,199,'HEAAAA','KJNAAA','AAAAxx'
+5619,9033,1,3,9,19,19,619,1619,619,5619,38,39,'DIAAAA','LJNAAA','HHHHxx'
+4110,9034,0,2,0,10,10,110,110,4110,4110,20,21,'CCAAAA','MJNAAA','OOOOxx'
+7025,9035,1,1,5,5,25,25,1025,2025,7025,50,51,'FKAAAA','NJNAAA','VVVVxx'
+5605,9036,1,1,5,5,5,605,1605,605,5605,10,11,'PHAAAA','OJNAAA','AAAAxx'
+2572,9037,0,0,2,12,72,572,572,2572,2572,144,145,'YUAAAA','PJNAAA','HHHHxx'
+3895,9038,1,3,5,15,95,895,1895,3895,3895,190,191,'VTAAAA','QJNAAA','OOOOxx'
+9138,9039,0,2,8,18,38,138,1138,4138,9138,76,77,'MNAAAA','RJNAAA','VVVVxx'
+4713,9040,1,1,3,13,13,713,713,4713,4713,26,27,'HZAAAA','SJNAAA','AAAAxx'
+6079,9041,1,3,9,19,79,79,79,1079,6079,158,159,'VZAAAA','TJNAAA','HHHHxx'
+8898,9042,0,2,8,18,98,898,898,3898,8898,196,197,'GEAAAA','UJNAAA','OOOOxx'
+2650,9043,0,2,0,10,50,650,650,2650,2650,100,101,'YXAAAA','VJNAAA','VVVVxx'
+5316,9044,0,0,6,16,16,316,1316,316,5316,32,33,'MWAAAA','WJNAAA','AAAAxx'
+5133,9045,1,1,3,13,33,133,1133,133,5133,66,67,'LPAAAA','XJNAAA','HHHHxx'
+2184,9046,0,0,4,4,84,184,184,2184,2184,168,169,'AGAAAA','YJNAAA','OOOOxx'
+2728,9047,0,0,8,8,28,728,728,2728,2728,56,57,'YAAAAA','ZJNAAA','VVVVxx'
+6737,9048,1,1,7,17,37,737,737,1737,6737,74,75,'DZAAAA','AKNAAA','AAAAxx'
+1128,9049,0,0,8,8,28,128,1128,1128,1128,56,57,'KRAAAA','BKNAAA','HHHHxx'
+9662,9050,0,2,2,2,62,662,1662,4662,9662,124,125,'QHAAAA','CKNAAA','OOOOxx'
+9384,9051,0,0,4,4,84,384,1384,4384,9384,168,169,'YWAAAA','DKNAAA','VVVVxx'
+4576,9052,0,0,6,16,76,576,576,4576,4576,152,153,'AUAAAA','EKNAAA','AAAAxx'
+9613,9053,1,1,3,13,13,613,1613,4613,9613,26,27,'TFAAAA','FKNAAA','HHHHxx'
+4001,9054,1,1,1,1,1,1,1,4001,4001,2,3,'XXAAAA','GKNAAA','OOOOxx'
+3628,9055,0,0,8,8,28,628,1628,3628,3628,56,57,'OJAAAA','HKNAAA','VVVVxx'
+6968,9056,0,0,8,8,68,968,968,1968,6968,136,137,'AIAAAA','IKNAAA','AAAAxx'
+6491,9057,1,3,1,11,91,491,491,1491,6491,182,183,'RPAAAA','JKNAAA','HHHHxx'
+1265,9058,1,1,5,5,65,265,1265,1265,1265,130,131,'RWAAAA','KKNAAA','OOOOxx'
+6128,9059,0,0,8,8,28,128,128,1128,6128,56,57,'SBAAAA','LKNAAA','VVVVxx'
+4274,9060,0,2,4,14,74,274,274,4274,4274,148,149,'KIAAAA','MKNAAA','AAAAxx'
+3598,9061,0,2,8,18,98,598,1598,3598,3598,196,197,'KIAAAA','NKNAAA','HHHHxx'
+7961,9062,1,1,1,1,61,961,1961,2961,7961,122,123,'FUAAAA','OKNAAA','OOOOxx'
+2643,9063,1,3,3,3,43,643,643,2643,2643,86,87,'RXAAAA','PKNAAA','VVVVxx'
+4547,9064,1,3,7,7,47,547,547,4547,4547,94,95,'XSAAAA','QKNAAA','AAAAxx'
+3568,9065,0,0,8,8,68,568,1568,3568,3568,136,137,'GHAAAA','RKNAAA','HHHHxx'
+8954,9066,0,2,4,14,54,954,954,3954,8954,108,109,'KGAAAA','SKNAAA','OOOOxx'
+8802,9067,0,2,2,2,2,802,802,3802,8802,4,5,'OAAAAA','TKNAAA','VVVVxx'
+7829,9068,1,1,9,9,29,829,1829,2829,7829,58,59,'DPAAAA','UKNAAA','AAAAxx'
+1008,9069,0,0,8,8,8,8,1008,1008,1008,16,17,'UMAAAA','VKNAAA','HHHHxx'
+3627,9070,1,3,7,7,27,627,1627,3627,3627,54,55,'NJAAAA','WKNAAA','OOOOxx'
+3999,9071,1,3,9,19,99,999,1999,3999,3999,198,199,'VXAAAA','XKNAAA','VVVVxx'
+7697,9072,1,1,7,17,97,697,1697,2697,7697,194,195,'BKAAAA','YKNAAA','AAAAxx'
+9380,9073,0,0,0,0,80,380,1380,4380,9380,160,161,'UWAAAA','ZKNAAA','HHHHxx'
+2707,9074,1,3,7,7,7,707,707,2707,2707,14,15,'DAAAAA','ALNAAA','OOOOxx'
+4430,9075,0,2,0,10,30,430,430,4430,4430,60,61,'KOAAAA','BLNAAA','VVVVxx'
+6440,9076,0,0,0,0,40,440,440,1440,6440,80,81,'SNAAAA','CLNAAA','AAAAxx'
+9958,9077,0,2,8,18,58,958,1958,4958,9958,116,117,'ATAAAA','DLNAAA','HHHHxx'
+7592,9078,0,0,2,12,92,592,1592,2592,7592,184,185,'AGAAAA','ELNAAA','OOOOxx'
+7852,9079,0,0,2,12,52,852,1852,2852,7852,104,105,'AQAAAA','FLNAAA','VVVVxx'
+9253,9080,1,1,3,13,53,253,1253,4253,9253,106,107,'XRAAAA','GLNAAA','AAAAxx'
+5910,9081,0,2,0,10,10,910,1910,910,5910,20,21,'ITAAAA','HLNAAA','HHHHxx'
+7487,9082,1,3,7,7,87,487,1487,2487,7487,174,175,'ZBAAAA','ILNAAA','OOOOxx'
+6324,9083,0,0,4,4,24,324,324,1324,6324,48,49,'GJAAAA','JLNAAA','VVVVxx'
+5792,9084,0,0,2,12,92,792,1792,792,5792,184,185,'UOAAAA','KLNAAA','AAAAxx'
+7390,9085,0,2,0,10,90,390,1390,2390,7390,180,181,'GYAAAA','LLNAAA','HHHHxx'
+8534,9086,0,2,4,14,34,534,534,3534,8534,68,69,'GQAAAA','MLNAAA','OOOOxx'
+2690,9087,0,2,0,10,90,690,690,2690,2690,180,181,'MZAAAA','NLNAAA','VVVVxx'
+3992,9088,0,0,2,12,92,992,1992,3992,3992,184,185,'OXAAAA','OLNAAA','AAAAxx'
+6928,9089,0,0,8,8,28,928,928,1928,6928,56,57,'MGAAAA','PLNAAA','HHHHxx'
+7815,9090,1,3,5,15,15,815,1815,2815,7815,30,31,'POAAAA','QLNAAA','OOOOxx'
+9477,9091,1,1,7,17,77,477,1477,4477,9477,154,155,'NAAAAA','RLNAAA','VVVVxx'
+497,9092,1,1,7,17,97,497,497,497,497,194,195,'DTAAAA','SLNAAA','AAAAxx'
+7532,9093,0,0,2,12,32,532,1532,2532,7532,64,65,'SDAAAA','TLNAAA','HHHHxx'
+9838,9094,0,2,8,18,38,838,1838,4838,9838,76,77,'KOAAAA','ULNAAA','OOOOxx'
+1557,9095,1,1,7,17,57,557,1557,1557,1557,114,115,'XHAAAA','VLNAAA','VVVVxx'
+2467,9096,1,3,7,7,67,467,467,2467,2467,134,135,'XQAAAA','WLNAAA','AAAAxx'
+2367,9097,1,3,7,7,67,367,367,2367,2367,134,135,'BNAAAA','XLNAAA','HHHHxx'
+5677,9098,1,1,7,17,77,677,1677,677,5677,154,155,'JKAAAA','YLNAAA','OOOOxx'
+6193,9099,1,1,3,13,93,193,193,1193,6193,186,187,'FEAAAA','ZLNAAA','VVVVxx'
+7126,9100,0,2,6,6,26,126,1126,2126,7126,52,53,'COAAAA','AMNAAA','AAAAxx'
+5264,9101,0,0,4,4,64,264,1264,264,5264,128,129,'MUAAAA','BMNAAA','HHHHxx'
+850,9102,0,2,0,10,50,850,850,850,850,100,101,'SGAAAA','CMNAAA','OOOOxx'
+4854,9103,0,2,4,14,54,854,854,4854,4854,108,109,'SEAAAA','DMNAAA','VVVVxx'
+4414,9104,0,2,4,14,14,414,414,4414,4414,28,29,'UNAAAA','EMNAAA','AAAAxx'
+8971,9105,1,3,1,11,71,971,971,3971,8971,142,143,'BHAAAA','FMNAAA','HHHHxx'
+9240,9106,0,0,0,0,40,240,1240,4240,9240,80,81,'KRAAAA','GMNAAA','OOOOxx'
+7341,9107,1,1,1,1,41,341,1341,2341,7341,82,83,'JWAAAA','HMNAAA','VVVVxx'
+3151,9108,1,3,1,11,51,151,1151,3151,3151,102,103,'FRAAAA','IMNAAA','AAAAxx'
+1742,9109,0,2,2,2,42,742,1742,1742,1742,84,85,'APAAAA','JMNAAA','HHHHxx'
+1347,9110,1,3,7,7,47,347,1347,1347,1347,94,95,'VZAAAA','KMNAAA','OOOOxx'
+9418,9111,0,2,8,18,18,418,1418,4418,9418,36,37,'GYAAAA','LMNAAA','VVVVxx'
+5452,9112,0,0,2,12,52,452,1452,452,5452,104,105,'SBAAAA','MMNAAA','AAAAxx'
+8637,9113,1,1,7,17,37,637,637,3637,8637,74,75,'FUAAAA','NMNAAA','HHHHxx'
+8287,9114,1,3,7,7,87,287,287,3287,8287,174,175,'TGAAAA','OMNAAA','OOOOxx'
+9865,9115,1,1,5,5,65,865,1865,4865,9865,130,131,'LPAAAA','PMNAAA','VVVVxx'
+1664,9116,0,0,4,4,64,664,1664,1664,1664,128,129,'AMAAAA','QMNAAA','AAAAxx'
+9933,9117,1,1,3,13,33,933,1933,4933,9933,66,67,'BSAAAA','RMNAAA','HHHHxx'
+3416,9118,0,0,6,16,16,416,1416,3416,3416,32,33,'KBAAAA','SMNAAA','OOOOxx'
+7981,9119,1,1,1,1,81,981,1981,2981,7981,162,163,'ZUAAAA','TMNAAA','VVVVxx'
+1981,9120,1,1,1,1,81,981,1981,1981,1981,162,163,'FYAAAA','UMNAAA','AAAAxx'
+441,9121,1,1,1,1,41,441,441,441,441,82,83,'ZQAAAA','VMNAAA','HHHHxx'
+1380,9122,0,0,0,0,80,380,1380,1380,1380,160,161,'CBAAAA','WMNAAA','OOOOxx'
+7325,9123,1,1,5,5,25,325,1325,2325,7325,50,51,'TVAAAA','XMNAAA','VVVVxx'
+5682,9124,0,2,2,2,82,682,1682,682,5682,164,165,'OKAAAA','YMNAAA','AAAAxx'
+1024,9125,0,0,4,4,24,24,1024,1024,1024,48,49,'KNAAAA','ZMNAAA','HHHHxx'
+1096,9126,0,0,6,16,96,96,1096,1096,1096,192,193,'EQAAAA','ANNAAA','OOOOxx'
+4717,9127,1,1,7,17,17,717,717,4717,4717,34,35,'LZAAAA','BNNAAA','VVVVxx'
+7948,9128,0,0,8,8,48,948,1948,2948,7948,96,97,'STAAAA','CNNAAA','AAAAxx'
+4074,9129,0,2,4,14,74,74,74,4074,4074,148,149,'SAAAAA','DNNAAA','HHHHxx'
+211,9130,1,3,1,11,11,211,211,211,211,22,23,'DIAAAA','ENNAAA','OOOOxx'
+8993,9131,1,1,3,13,93,993,993,3993,8993,186,187,'XHAAAA','FNNAAA','VVVVxx'
+4509,9132,1,1,9,9,9,509,509,4509,4509,18,19,'LRAAAA','GNNAAA','AAAAxx'
+823,9133,1,3,3,3,23,823,823,823,823,46,47,'RFAAAA','HNNAAA','HHHHxx'
+4747,9134,1,3,7,7,47,747,747,4747,4747,94,95,'PAAAAA','INNAAA','OOOOxx'
+6955,9135,1,3,5,15,55,955,955,1955,6955,110,111,'NHAAAA','JNNAAA','VVVVxx'
+7922,9136,0,2,2,2,22,922,1922,2922,7922,44,45,'SSAAAA','KNNAAA','AAAAxx'
+6936,9137,0,0,6,16,36,936,936,1936,6936,72,73,'UGAAAA','LNNAAA','HHHHxx'
+1546,9138,0,2,6,6,46,546,1546,1546,1546,92,93,'MHAAAA','MNNAAA','OOOOxx'
+9836,9139,0,0,6,16,36,836,1836,4836,9836,72,73,'IOAAAA','NNNAAA','VVVVxx'
+5626,9140,0,2,6,6,26,626,1626,626,5626,52,53,'KIAAAA','ONNAAA','AAAAxx'
+4879,9141,1,3,9,19,79,879,879,4879,4879,158,159,'RFAAAA','PNNAAA','HHHHxx'
+8590,9142,0,2,0,10,90,590,590,3590,8590,180,181,'KSAAAA','QNNAAA','OOOOxx'
+8842,9143,0,2,2,2,42,842,842,3842,8842,84,85,'CCAAAA','RNNAAA','VVVVxx'
+6505,9144,1,1,5,5,5,505,505,1505,6505,10,11,'FQAAAA','SNNAAA','AAAAxx'
+2803,9145,1,3,3,3,3,803,803,2803,2803,6,7,'VDAAAA','TNNAAA','HHHHxx'
+9258,9146,0,2,8,18,58,258,1258,4258,9258,116,117,'CSAAAA','UNNAAA','OOOOxx'
+741,9147,1,1,1,1,41,741,741,741,741,82,83,'NCAAAA','VNNAAA','VVVVxx'
+1457,9148,1,1,7,17,57,457,1457,1457,1457,114,115,'BEAAAA','WNNAAA','AAAAxx'
+5777,9149,1,1,7,17,77,777,1777,777,5777,154,155,'FOAAAA','XNNAAA','HHHHxx'
+2883,9150,1,3,3,3,83,883,883,2883,2883,166,167,'XGAAAA','YNNAAA','OOOOxx'
+6610,9151,0,2,0,10,10,610,610,1610,6610,20,21,'GUAAAA','ZNNAAA','VVVVxx'
+4331,9152,1,3,1,11,31,331,331,4331,4331,62,63,'PKAAAA','AONAAA','AAAAxx'
+2712,9153,0,0,2,12,12,712,712,2712,2712,24,25,'IAAAAA','BONAAA','HHHHxx'
+9268,9154,0,0,8,8,68,268,1268,4268,9268,136,137,'MSAAAA','CONAAA','OOOOxx'
+410,9155,0,2,0,10,10,410,410,410,410,20,21,'UPAAAA','DONAAA','VVVVxx'
+9411,9156,1,3,1,11,11,411,1411,4411,9411,22,23,'ZXAAAA','EONAAA','AAAAxx'
+4683,9157,1,3,3,3,83,683,683,4683,4683,166,167,'DYAAAA','FONAAA','HHHHxx'
+7072,9158,0,0,2,12,72,72,1072,2072,7072,144,145,'AMAAAA','GONAAA','OOOOxx'
+5050,9159,0,2,0,10,50,50,1050,50,5050,100,101,'GMAAAA','HONAAA','VVVVxx'
+5932,9160,0,0,2,12,32,932,1932,932,5932,64,65,'EUAAAA','IONAAA','AAAAxx'
+2756,9161,0,0,6,16,56,756,756,2756,2756,112,113,'ACAAAA','JONAAA','HHHHxx'
+9813,9162,1,1,3,13,13,813,1813,4813,9813,26,27,'LNAAAA','KONAAA','OOOOxx'
+7388,9163,0,0,8,8,88,388,1388,2388,7388,176,177,'EYAAAA','LONAAA','VVVVxx'
+2596,9164,0,0,6,16,96,596,596,2596,2596,192,193,'WVAAAA','MONAAA','AAAAxx'
+5102,9165,0,2,2,2,2,102,1102,102,5102,4,5,'GOAAAA','NONAAA','HHHHxx'
+208,9166,0,0,8,8,8,208,208,208,208,16,17,'AIAAAA','OONAAA','OOOOxx'
+86,9167,0,2,6,6,86,86,86,86,86,172,173,'IDAAAA','PONAAA','VVVVxx'
+8127,9168,1,3,7,7,27,127,127,3127,8127,54,55,'PAAAAA','QONAAA','AAAAxx'
+5154,9169,0,2,4,14,54,154,1154,154,5154,108,109,'GQAAAA','RONAAA','HHHHxx'
+4491,9170,1,3,1,11,91,491,491,4491,4491,182,183,'TQAAAA','SONAAA','OOOOxx'
+7423,9171,1,3,3,3,23,423,1423,2423,7423,46,47,'NZAAAA','TONAAA','VVVVxx'
+6441,9172,1,1,1,1,41,441,441,1441,6441,82,83,'TNAAAA','UONAAA','AAAAxx'
+2920,9173,0,0,0,0,20,920,920,2920,2920,40,41,'IIAAAA','VONAAA','HHHHxx'
+6386,9174,0,2,6,6,86,386,386,1386,6386,172,173,'QLAAAA','WONAAA','OOOOxx'
+9744,9175,0,0,4,4,44,744,1744,4744,9744,88,89,'UKAAAA','XONAAA','VVVVxx'
+2667,9176,1,3,7,7,67,667,667,2667,2667,134,135,'PYAAAA','YONAAA','AAAAxx'
+5754,9177,0,2,4,14,54,754,1754,754,5754,108,109,'INAAAA','ZONAAA','HHHHxx'
+4645,9178,1,1,5,5,45,645,645,4645,4645,90,91,'RWAAAA','APNAAA','OOOOxx'
+4327,9179,1,3,7,7,27,327,327,4327,4327,54,55,'LKAAAA','BPNAAA','VVVVxx'
+843,9180,1,3,3,3,43,843,843,843,843,86,87,'LGAAAA','CPNAAA','AAAAxx'
+4085,9181,1,1,5,5,85,85,85,4085,4085,170,171,'DBAAAA','DPNAAA','HHHHxx'
+2849,9182,1,1,9,9,49,849,849,2849,2849,98,99,'PFAAAA','EPNAAA','OOOOxx'
+5734,9183,0,2,4,14,34,734,1734,734,5734,68,69,'OMAAAA','FPNAAA','VVVVxx'
+5307,9184,1,3,7,7,7,307,1307,307,5307,14,15,'DWAAAA','GPNAAA','AAAAxx'
+8433,9185,1,1,3,13,33,433,433,3433,8433,66,67,'JMAAAA','HPNAAA','HHHHxx'
+3031,9186,1,3,1,11,31,31,1031,3031,3031,62,63,'PMAAAA','IPNAAA','OOOOxx'
+5714,9187,0,2,4,14,14,714,1714,714,5714,28,29,'ULAAAA','JPNAAA','VVVVxx'
+5969,9188,1,1,9,9,69,969,1969,969,5969,138,139,'PVAAAA','KPNAAA','AAAAxx'
+2532,9189,0,0,2,12,32,532,532,2532,2532,64,65,'KTAAAA','LPNAAA','HHHHxx'
+5219,9190,1,3,9,19,19,219,1219,219,5219,38,39,'TSAAAA','MPNAAA','OOOOxx'
+7343,9191,1,3,3,3,43,343,1343,2343,7343,86,87,'LWAAAA','NPNAAA','VVVVxx'
+9089,9192,1,1,9,9,89,89,1089,4089,9089,178,179,'PLAAAA','OPNAAA','AAAAxx'
+9337,9193,1,1,7,17,37,337,1337,4337,9337,74,75,'DVAAAA','PPNAAA','HHHHxx'
+5131,9194,1,3,1,11,31,131,1131,131,5131,62,63,'JPAAAA','QPNAAA','OOOOxx'
+6253,9195,1,1,3,13,53,253,253,1253,6253,106,107,'NGAAAA','RPNAAA','VVVVxx'
+5140,9196,0,0,0,0,40,140,1140,140,5140,80,81,'SPAAAA','SPNAAA','AAAAxx'
+2953,9197,1,1,3,13,53,953,953,2953,2953,106,107,'PJAAAA','TPNAAA','HHHHxx'
+4293,9198,1,1,3,13,93,293,293,4293,4293,186,187,'DJAAAA','UPNAAA','OOOOxx'
+9974,9199,0,2,4,14,74,974,1974,4974,9974,148,149,'QTAAAA','VPNAAA','VVVVxx'
+5061,9200,1,1,1,1,61,61,1061,61,5061,122,123,'RMAAAA','WPNAAA','AAAAxx'
+8570,9201,0,2,0,10,70,570,570,3570,8570,140,141,'QRAAAA','XPNAAA','HHHHxx'
+9504,9202,0,0,4,4,4,504,1504,4504,9504,8,9,'OBAAAA','YPNAAA','OOOOxx'
+604,9203,0,0,4,4,4,604,604,604,604,8,9,'GXAAAA','ZPNAAA','VVVVxx'
+4991,9204,1,3,1,11,91,991,991,4991,4991,182,183,'ZJAAAA','AQNAAA','AAAAxx'
+880,9205,0,0,0,0,80,880,880,880,880,160,161,'WHAAAA','BQNAAA','HHHHxx'
+3861,9206,1,1,1,1,61,861,1861,3861,3861,122,123,'NSAAAA','CQNAAA','OOOOxx'
+8262,9207,0,2,2,2,62,262,262,3262,8262,124,125,'UFAAAA','DQNAAA','VVVVxx'
+5689,9208,1,1,9,9,89,689,1689,689,5689,178,179,'VKAAAA','EQNAAA','AAAAxx'
+1793,9209,1,1,3,13,93,793,1793,1793,1793,186,187,'ZQAAAA','FQNAAA','HHHHxx'
+2661,9210,1,1,1,1,61,661,661,2661,2661,122,123,'JYAAAA','GQNAAA','OOOOxx'
+7954,9211,0,2,4,14,54,954,1954,2954,7954,108,109,'YTAAAA','HQNAAA','VVVVxx'
+1874,9212,0,2,4,14,74,874,1874,1874,1874,148,149,'CUAAAA','IQNAAA','AAAAxx'
+2982,9213,0,2,2,2,82,982,982,2982,2982,164,165,'SKAAAA','JQNAAA','HHHHxx'
+331,9214,1,3,1,11,31,331,331,331,331,62,63,'TMAAAA','KQNAAA','OOOOxx'
+5021,9215,1,1,1,1,21,21,1021,21,5021,42,43,'DLAAAA','LQNAAA','VVVVxx'
+9894,9216,0,2,4,14,94,894,1894,4894,9894,188,189,'OQAAAA','MQNAAA','AAAAxx'
+7709,9217,1,1,9,9,9,709,1709,2709,7709,18,19,'NKAAAA','NQNAAA','HHHHxx'
+4980,9218,0,0,0,0,80,980,980,4980,4980,160,161,'OJAAAA','OQNAAA','OOOOxx'
+8249,9219,1,1,9,9,49,249,249,3249,8249,98,99,'HFAAAA','PQNAAA','VVVVxx'
+7120,9220,0,0,0,0,20,120,1120,2120,7120,40,41,'WNAAAA','QQNAAA','AAAAxx'
+7464,9221,0,0,4,4,64,464,1464,2464,7464,128,129,'CBAAAA','RQNAAA','HHHHxx'
+8086,9222,0,2,6,6,86,86,86,3086,8086,172,173,'AZAAAA','SQNAAA','OOOOxx'
+3509,9223,1,1,9,9,9,509,1509,3509,3509,18,19,'ZEAAAA','TQNAAA','VVVVxx'
+3902,9224,0,2,2,2,2,902,1902,3902,3902,4,5,'CUAAAA','UQNAAA','AAAAxx'
+9907,9225,1,3,7,7,7,907,1907,4907,9907,14,15,'BRAAAA','VQNAAA','HHHHxx'
+6278,9226,0,2,8,18,78,278,278,1278,6278,156,157,'MHAAAA','WQNAAA','OOOOxx'
+9316,9227,0,0,6,16,16,316,1316,4316,9316,32,33,'IUAAAA','XQNAAA','VVVVxx'
+2824,9228,0,0,4,4,24,824,824,2824,2824,48,49,'QEAAAA','YQNAAA','AAAAxx'
+1558,9229,0,2,8,18,58,558,1558,1558,1558,116,117,'YHAAAA','ZQNAAA','HHHHxx'
+5436,9230,0,0,6,16,36,436,1436,436,5436,72,73,'CBAAAA','ARNAAA','OOOOxx'
+1161,9231,1,1,1,1,61,161,1161,1161,1161,122,123,'RSAAAA','BRNAAA','VVVVxx'
+7569,9232,1,1,9,9,69,569,1569,2569,7569,138,139,'DFAAAA','CRNAAA','AAAAxx'
+9614,9233,0,2,4,14,14,614,1614,4614,9614,28,29,'UFAAAA','DRNAAA','HHHHxx'
+6970,9234,0,2,0,10,70,970,970,1970,6970,140,141,'CIAAAA','ERNAAA','OOOOxx'
+2422,9235,0,2,2,2,22,422,422,2422,2422,44,45,'EPAAAA','FRNAAA','VVVVxx'
+8860,9236,0,0,0,0,60,860,860,3860,8860,120,121,'UCAAAA','GRNAAA','AAAAxx'
+9912,9237,0,0,2,12,12,912,1912,4912,9912,24,25,'GRAAAA','HRNAAA','HHHHxx'
+1109,9238,1,1,9,9,9,109,1109,1109,1109,18,19,'RQAAAA','IRNAAA','OOOOxx'
+3286,9239,0,2,6,6,86,286,1286,3286,3286,172,173,'KWAAAA','JRNAAA','VVVVxx'
+2277,9240,1,1,7,17,77,277,277,2277,2277,154,155,'PJAAAA','KRNAAA','AAAAxx'
+8656,9241,0,0,6,16,56,656,656,3656,8656,112,113,'YUAAAA','LRNAAA','HHHHxx'
+4656,9242,0,0,6,16,56,656,656,4656,4656,112,113,'CXAAAA','MRNAAA','OOOOxx'
+6965,9243,1,1,5,5,65,965,965,1965,6965,130,131,'XHAAAA','NRNAAA','VVVVxx'
+7591,9244,1,3,1,11,91,591,1591,2591,7591,182,183,'ZFAAAA','ORNAAA','AAAAxx'
+4883,9245,1,3,3,3,83,883,883,4883,4883,166,167,'VFAAAA','PRNAAA','HHHHxx'
+452,9246,0,0,2,12,52,452,452,452,452,104,105,'KRAAAA','QRNAAA','OOOOxx'
+4018,9247,0,2,8,18,18,18,18,4018,4018,36,37,'OYAAAA','RRNAAA','VVVVxx'
+4066,9248,0,2,6,6,66,66,66,4066,4066,132,133,'KAAAAA','SRNAAA','AAAAxx'
+6480,9249,0,0,0,0,80,480,480,1480,6480,160,161,'GPAAAA','TRNAAA','HHHHxx'
+8634,9250,0,2,4,14,34,634,634,3634,8634,68,69,'CUAAAA','URNAAA','OOOOxx'
+9387,9251,1,3,7,7,87,387,1387,4387,9387,174,175,'BXAAAA','VRNAAA','VVVVxx'
+3476,9252,0,0,6,16,76,476,1476,3476,3476,152,153,'SDAAAA','WRNAAA','AAAAxx'
+5995,9253,1,3,5,15,95,995,1995,995,5995,190,191,'PWAAAA','XRNAAA','HHHHxx'
+9677,9254,1,1,7,17,77,677,1677,4677,9677,154,155,'FIAAAA','YRNAAA','OOOOxx'
+3884,9255,0,0,4,4,84,884,1884,3884,3884,168,169,'KTAAAA','ZRNAAA','VVVVxx'
+6500,9256,0,0,0,0,0,500,500,1500,6500,0,1,'AQAAAA','ASNAAA','AAAAxx'
+7972,9257,0,0,2,12,72,972,1972,2972,7972,144,145,'QUAAAA','BSNAAA','HHHHxx'
+5281,9258,1,1,1,1,81,281,1281,281,5281,162,163,'DVAAAA','CSNAAA','OOOOxx'
+1288,9259,0,0,8,8,88,288,1288,1288,1288,176,177,'OXAAAA','DSNAAA','VVVVxx'
+4366,9260,0,2,6,6,66,366,366,4366,4366,132,133,'YLAAAA','ESNAAA','AAAAxx'
+6557,9261,1,1,7,17,57,557,557,1557,6557,114,115,'FSAAAA','FSNAAA','HHHHxx'
+7086,9262,0,2,6,6,86,86,1086,2086,7086,172,173,'OMAAAA','GSNAAA','OOOOxx'
+6588,9263,0,0,8,8,88,588,588,1588,6588,176,177,'KTAAAA','HSNAAA','VVVVxx'
+9062,9264,0,2,2,2,62,62,1062,4062,9062,124,125,'OKAAAA','ISNAAA','AAAAxx'
+9230,9265,0,2,0,10,30,230,1230,4230,9230,60,61,'ARAAAA','JSNAAA','HHHHxx'
+7672,9266,0,0,2,12,72,672,1672,2672,7672,144,145,'CJAAAA','KSNAAA','OOOOxx'
+5204,9267,0,0,4,4,4,204,1204,204,5204,8,9,'ESAAAA','LSNAAA','VVVVxx'
+2836,9268,0,0,6,16,36,836,836,2836,2836,72,73,'CFAAAA','MSNAAA','AAAAxx'
+7165,9269,1,1,5,5,65,165,1165,2165,7165,130,131,'PPAAAA','NSNAAA','HHHHxx'
+971,9270,1,3,1,11,71,971,971,971,971,142,143,'JLAAAA','OSNAAA','OOOOxx'
+3851,9271,1,3,1,11,51,851,1851,3851,3851,102,103,'DSAAAA','PSNAAA','VVVVxx'
+8593,9272,1,1,3,13,93,593,593,3593,8593,186,187,'NSAAAA','QSNAAA','AAAAxx'
+7742,9273,0,2,2,2,42,742,1742,2742,7742,84,85,'ULAAAA','RSNAAA','HHHHxx'
+2887,9274,1,3,7,7,87,887,887,2887,2887,174,175,'BHAAAA','SSNAAA','OOOOxx'
+8479,9275,1,3,9,19,79,479,479,3479,8479,158,159,'DOAAAA','TSNAAA','VVVVxx'
+9514,9276,0,2,4,14,14,514,1514,4514,9514,28,29,'YBAAAA','USNAAA','AAAAxx'
+273,9277,1,1,3,13,73,273,273,273,273,146,147,'NKAAAA','VSNAAA','HHHHxx'
+2938,9278,0,2,8,18,38,938,938,2938,2938,76,77,'AJAAAA','WSNAAA','OOOOxx'
+9793,9279,1,1,3,13,93,793,1793,4793,9793,186,187,'RMAAAA','XSNAAA','VVVVxx'
+8050,9280,0,2,0,10,50,50,50,3050,8050,100,101,'QXAAAA','YSNAAA','AAAAxx'
+6702,9281,0,2,2,2,2,702,702,1702,6702,4,5,'UXAAAA','ZSNAAA','HHHHxx'
+7290,9282,0,2,0,10,90,290,1290,2290,7290,180,181,'KUAAAA','ATNAAA','OOOOxx'
+1837,9283,1,1,7,17,37,837,1837,1837,1837,74,75,'RSAAAA','BTNAAA','VVVVxx'
+3206,9284,0,2,6,6,6,206,1206,3206,3206,12,13,'ITAAAA','CTNAAA','AAAAxx'
+4925,9285,1,1,5,5,25,925,925,4925,4925,50,51,'LHAAAA','DTNAAA','HHHHxx'
+5066,9286,0,2,6,6,66,66,1066,66,5066,132,133,'WMAAAA','ETNAAA','OOOOxx'
+3401,9287,1,1,1,1,1,401,1401,3401,3401,2,3,'VAAAAA','FTNAAA','VVVVxx'
+3474,9288,0,2,4,14,74,474,1474,3474,3474,148,149,'QDAAAA','GTNAAA','AAAAxx'
+57,9289,1,1,7,17,57,57,57,57,57,114,115,'FCAAAA','HTNAAA','HHHHxx'
+2082,9290,0,2,2,2,82,82,82,2082,2082,164,165,'CCAAAA','ITNAAA','OOOOxx'
+100,9291,0,0,0,0,0,100,100,100,100,0,1,'WDAAAA','JTNAAA','VVVVxx'
+9665,9292,1,1,5,5,65,665,1665,4665,9665,130,131,'THAAAA','KTNAAA','AAAAxx'
+8284,9293,0,0,4,4,84,284,284,3284,8284,168,169,'QGAAAA','LTNAAA','HHHHxx'
+958,9294,0,2,8,18,58,958,958,958,958,116,117,'WKAAAA','MTNAAA','OOOOxx'
+5282,9295,0,2,2,2,82,282,1282,282,5282,164,165,'EVAAAA','NTNAAA','VVVVxx'
+4257,9296,1,1,7,17,57,257,257,4257,4257,114,115,'THAAAA','OTNAAA','AAAAxx'
+3160,9297,0,0,0,0,60,160,1160,3160,3160,120,121,'ORAAAA','PTNAAA','HHHHxx'
+8449,9298,1,1,9,9,49,449,449,3449,8449,98,99,'ZMAAAA','QTNAAA','OOOOxx'
+500,9299,0,0,0,0,0,500,500,500,500,0,1,'GTAAAA','RTNAAA','VVVVxx'
+6432,9300,0,0,2,12,32,432,432,1432,6432,64,65,'KNAAAA','STNAAA','AAAAxx'
+6220,9301,0,0,0,0,20,220,220,1220,6220,40,41,'GFAAAA','TTNAAA','HHHHxx'
+7233,9302,1,1,3,13,33,233,1233,2233,7233,66,67,'FSAAAA','UTNAAA','OOOOxx'
+2723,9303,1,3,3,3,23,723,723,2723,2723,46,47,'TAAAAA','VTNAAA','VVVVxx'
+1899,9304,1,3,9,19,99,899,1899,1899,1899,198,199,'BVAAAA','WTNAAA','AAAAxx'
+7158,9305,0,2,8,18,58,158,1158,2158,7158,116,117,'IPAAAA','XTNAAA','HHHHxx'
+202,9306,0,2,2,2,2,202,202,202,202,4,5,'UHAAAA','YTNAAA','OOOOxx'
+2286,9307,0,2,6,6,86,286,286,2286,2286,172,173,'YJAAAA','ZTNAAA','VVVVxx'
+5356,9308,0,0,6,16,56,356,1356,356,5356,112,113,'AYAAAA','AUNAAA','AAAAxx'
+3809,9309,1,1,9,9,9,809,1809,3809,3809,18,19,'NQAAAA','BUNAAA','HHHHxx'
+3979,9310,1,3,9,19,79,979,1979,3979,3979,158,159,'BXAAAA','CUNAAA','OOOOxx'
+8359,9311,1,3,9,19,59,359,359,3359,8359,118,119,'NJAAAA','DUNAAA','VVVVxx'
+3479,9312,1,3,9,19,79,479,1479,3479,3479,158,159,'VDAAAA','EUNAAA','AAAAxx'
+4895,9313,1,3,5,15,95,895,895,4895,4895,190,191,'HGAAAA','FUNAAA','HHHHxx'
+6059,9314,1,3,9,19,59,59,59,1059,6059,118,119,'BZAAAA','GUNAAA','OOOOxx'
+9560,9315,0,0,0,0,60,560,1560,4560,9560,120,121,'SDAAAA','HUNAAA','VVVVxx'
+6756,9316,0,0,6,16,56,756,756,1756,6756,112,113,'WZAAAA','IUNAAA','AAAAxx'
+7504,9317,0,0,4,4,4,504,1504,2504,7504,8,9,'QCAAAA','JUNAAA','HHHHxx'
+6762,9318,0,2,2,2,62,762,762,1762,6762,124,125,'CAAAAA','KUNAAA','OOOOxx'
+5304,9319,0,0,4,4,4,304,1304,304,5304,8,9,'AWAAAA','LUNAAA','VVVVxx'
+9533,9320,1,1,3,13,33,533,1533,4533,9533,66,67,'RCAAAA','MUNAAA','AAAAxx'
+6649,9321,1,1,9,9,49,649,649,1649,6649,98,99,'TVAAAA','NUNAAA','HHHHxx'
+38,9322,0,2,8,18,38,38,38,38,38,76,77,'MBAAAA','OUNAAA','OOOOxx'
+5713,9323,1,1,3,13,13,713,1713,713,5713,26,27,'TLAAAA','PUNAAA','VVVVxx'
+3000,9324,0,0,0,0,0,0,1000,3000,3000,0,1,'KLAAAA','QUNAAA','AAAAxx'
+3738,9325,0,2,8,18,38,738,1738,3738,3738,76,77,'UNAAAA','RUNAAA','HHHHxx'
+3327,9326,1,3,7,7,27,327,1327,3327,3327,54,55,'ZXAAAA','SUNAAA','OOOOxx'
+3922,9327,0,2,2,2,22,922,1922,3922,3922,44,45,'WUAAAA','TUNAAA','VVVVxx'
+9245,9328,1,1,5,5,45,245,1245,4245,9245,90,91,'PRAAAA','UUNAAA','AAAAxx'
+2172,9329,0,0,2,12,72,172,172,2172,2172,144,145,'OFAAAA','VUNAAA','HHHHxx'
+7128,9330,0,0,8,8,28,128,1128,2128,7128,56,57,'EOAAAA','WUNAAA','OOOOxx'
+1195,9331,1,3,5,15,95,195,1195,1195,1195,190,191,'ZTAAAA','XUNAAA','VVVVxx'
+8445,9332,1,1,5,5,45,445,445,3445,8445,90,91,'VMAAAA','YUNAAA','AAAAxx'
+8638,9333,0,2,8,18,38,638,638,3638,8638,76,77,'GUAAAA','ZUNAAA','HHHHxx'
+1249,9334,1,1,9,9,49,249,1249,1249,1249,98,99,'BWAAAA','AVNAAA','OOOOxx'
+8659,9335,1,3,9,19,59,659,659,3659,8659,118,119,'BVAAAA','BVNAAA','VVVVxx'
+3556,9336,0,0,6,16,56,556,1556,3556,3556,112,113,'UGAAAA','CVNAAA','AAAAxx'
+3347,9337,1,3,7,7,47,347,1347,3347,3347,94,95,'TYAAAA','DVNAAA','HHHHxx'
+3260,9338,0,0,0,0,60,260,1260,3260,3260,120,121,'KVAAAA','EVNAAA','OOOOxx'
+5139,9339,1,3,9,19,39,139,1139,139,5139,78,79,'RPAAAA','FVNAAA','VVVVxx'
+9991,9340,1,3,1,11,91,991,1991,4991,9991,182,183,'HUAAAA','GVNAAA','AAAAxx'
+5499,9341,1,3,9,19,99,499,1499,499,5499,198,199,'NDAAAA','HVNAAA','HHHHxx'
+8082,9342,0,2,2,2,82,82,82,3082,8082,164,165,'WYAAAA','IVNAAA','OOOOxx'
+1640,9343,0,0,0,0,40,640,1640,1640,1640,80,81,'CLAAAA','JVNAAA','VVVVxx'
+8726,9344,0,2,6,6,26,726,726,3726,8726,52,53,'QXAAAA','KVNAAA','AAAAxx'
+2339,9345,1,3,9,19,39,339,339,2339,2339,78,79,'ZLAAAA','LVNAAA','HHHHxx'
+2601,9346,1,1,1,1,1,601,601,2601,2601,2,3,'BWAAAA','MVNAAA','OOOOxx'
+9940,9347,0,0,0,0,40,940,1940,4940,9940,80,81,'ISAAAA','NVNAAA','VVVVxx'
+4185,9348,1,1,5,5,85,185,185,4185,4185,170,171,'ZEAAAA','OVNAAA','AAAAxx'
+9546,9349,0,2,6,6,46,546,1546,4546,9546,92,93,'EDAAAA','PVNAAA','HHHHxx'
+5218,9350,0,2,8,18,18,218,1218,218,5218,36,37,'SSAAAA','QVNAAA','OOOOxx'
+4374,9351,0,2,4,14,74,374,374,4374,4374,148,149,'GMAAAA','RVNAAA','VVVVxx'
+288,9352,0,0,8,8,88,288,288,288,288,176,177,'CLAAAA','SVNAAA','AAAAxx'
+7445,9353,1,1,5,5,45,445,1445,2445,7445,90,91,'JAAAAA','TVNAAA','HHHHxx'
+1710,9354,0,2,0,10,10,710,1710,1710,1710,20,21,'UNAAAA','UVNAAA','OOOOxx'
+6409,9355,1,1,9,9,9,409,409,1409,6409,18,19,'NMAAAA','VVNAAA','VVVVxx'
+7982,9356,0,2,2,2,82,982,1982,2982,7982,164,165,'AVAAAA','WVNAAA','AAAAxx'
+4950,9357,0,2,0,10,50,950,950,4950,4950,100,101,'KIAAAA','XVNAAA','HHHHxx'
+9242,9358,0,2,2,2,42,242,1242,4242,9242,84,85,'MRAAAA','YVNAAA','OOOOxx'
+3272,9359,0,0,2,12,72,272,1272,3272,3272,144,145,'WVAAAA','ZVNAAA','VVVVxx'
+739,9360,1,3,9,19,39,739,739,739,739,78,79,'LCAAAA','AWNAAA','AAAAxx'
+5526,9361,0,2,6,6,26,526,1526,526,5526,52,53,'OEAAAA','BWNAAA','HHHHxx'
+8189,9362,1,1,9,9,89,189,189,3189,8189,178,179,'ZCAAAA','CWNAAA','OOOOxx'
+9106,9363,0,2,6,6,6,106,1106,4106,9106,12,13,'GMAAAA','DWNAAA','VVVVxx'
+9775,9364,1,3,5,15,75,775,1775,4775,9775,150,151,'ZLAAAA','EWNAAA','AAAAxx'
+4643,9365,1,3,3,3,43,643,643,4643,4643,86,87,'PWAAAA','FWNAAA','HHHHxx'
+8396,9366,0,0,6,16,96,396,396,3396,8396,192,193,'YKAAAA','GWNAAA','OOOOxx'
+3255,9367,1,3,5,15,55,255,1255,3255,3255,110,111,'FVAAAA','HWNAAA','VVVVxx'
+301,9368,1,1,1,1,1,301,301,301,301,2,3,'PLAAAA','IWNAAA','AAAAxx'
+6014,9369,0,2,4,14,14,14,14,1014,6014,28,29,'IXAAAA','JWNAAA','HHHHxx'
+6046,9370,0,2,6,6,46,46,46,1046,6046,92,93,'OYAAAA','KWNAAA','OOOOxx'
+984,9371,0,0,4,4,84,984,984,984,984,168,169,'WLAAAA','LWNAAA','VVVVxx'
+2420,9372,0,0,0,0,20,420,420,2420,2420,40,41,'CPAAAA','MWNAAA','AAAAxx'
+2922,9373,0,2,2,2,22,922,922,2922,2922,44,45,'KIAAAA','NWNAAA','HHHHxx'
+2317,9374,1,1,7,17,17,317,317,2317,2317,34,35,'DLAAAA','OWNAAA','OOOOxx'
+7332,9375,0,0,2,12,32,332,1332,2332,7332,64,65,'AWAAAA','PWNAAA','VVVVxx'
+6451,9376,1,3,1,11,51,451,451,1451,6451,102,103,'DOAAAA','QWNAAA','AAAAxx'
+2589,9377,1,1,9,9,89,589,589,2589,2589,178,179,'PVAAAA','RWNAAA','HHHHxx'
+4333,9378,1,1,3,13,33,333,333,4333,4333,66,67,'RKAAAA','SWNAAA','OOOOxx'
+8650,9379,0,2,0,10,50,650,650,3650,8650,100,101,'SUAAAA','TWNAAA','VVVVxx'
+6856,9380,0,0,6,16,56,856,856,1856,6856,112,113,'SDAAAA','UWNAAA','AAAAxx'
+4194,9381,0,2,4,14,94,194,194,4194,4194,188,189,'IFAAAA','VWNAAA','HHHHxx'
+6246,9382,0,2,6,6,46,246,246,1246,6246,92,93,'GGAAAA','WWNAAA','OOOOxx'
+4371,9383,1,3,1,11,71,371,371,4371,4371,142,143,'DMAAAA','XWNAAA','VVVVxx'
+1388,9384,0,0,8,8,88,388,1388,1388,1388,176,177,'KBAAAA','YWNAAA','AAAAxx'
+1056,9385,0,0,6,16,56,56,1056,1056,1056,112,113,'QOAAAA','ZWNAAA','HHHHxx'
+6041,9386,1,1,1,1,41,41,41,1041,6041,82,83,'JYAAAA','AXNAAA','OOOOxx'
+6153,9387,1,1,3,13,53,153,153,1153,6153,106,107,'RCAAAA','BXNAAA','VVVVxx'
+8450,9388,0,2,0,10,50,450,450,3450,8450,100,101,'ANAAAA','CXNAAA','AAAAxx'
+3469,9389,1,1,9,9,69,469,1469,3469,3469,138,139,'LDAAAA','DXNAAA','HHHHxx'
+5226,9390,0,2,6,6,26,226,1226,226,5226,52,53,'ATAAAA','EXNAAA','OOOOxx'
+8112,9391,0,0,2,12,12,112,112,3112,8112,24,25,'AAAAAA','FXNAAA','VVVVxx'
+647,9392,1,3,7,7,47,647,647,647,647,94,95,'XYAAAA','GXNAAA','AAAAxx'
+2567,9393,1,3,7,7,67,567,567,2567,2567,134,135,'TUAAAA','HXNAAA','HHHHxx'
+9064,9394,0,0,4,4,64,64,1064,4064,9064,128,129,'QKAAAA','IXNAAA','OOOOxx'
+5161,9395,1,1,1,1,61,161,1161,161,5161,122,123,'NQAAAA','JXNAAA','VVVVxx'
+5260,9396,0,0,0,0,60,260,1260,260,5260,120,121,'IUAAAA','KXNAAA','AAAAxx'
+8988,9397,0,0,8,8,88,988,988,3988,8988,176,177,'SHAAAA','LXNAAA','HHHHxx'
+9678,9398,0,2,8,18,78,678,1678,4678,9678,156,157,'GIAAAA','MXNAAA','OOOOxx'
+6853,9399,1,1,3,13,53,853,853,1853,6853,106,107,'PDAAAA','NXNAAA','VVVVxx'
+5294,9400,0,2,4,14,94,294,1294,294,5294,188,189,'QVAAAA','OXNAAA','AAAAxx'
+9864,9401,0,0,4,4,64,864,1864,4864,9864,128,129,'KPAAAA','PXNAAA','HHHHxx'
+8702,9402,0,2,2,2,2,702,702,3702,8702,4,5,'SWAAAA','QXNAAA','OOOOxx'
+1132,9403,0,0,2,12,32,132,1132,1132,1132,64,65,'ORAAAA','RXNAAA','VVVVxx'
+1524,9404,0,0,4,4,24,524,1524,1524,1524,48,49,'QGAAAA','SXNAAA','AAAAxx'
+4560,9405,0,0,0,0,60,560,560,4560,4560,120,121,'KTAAAA','TXNAAA','HHHHxx'
+2137,9406,1,1,7,17,37,137,137,2137,2137,74,75,'FEAAAA','UXNAAA','OOOOxx'
+3283,9407,1,3,3,3,83,283,1283,3283,3283,166,167,'HWAAAA','VXNAAA','VVVVxx'
+3377,9408,1,1,7,17,77,377,1377,3377,3377,154,155,'XZAAAA','WXNAAA','AAAAxx'
+2267,9409,1,3,7,7,67,267,267,2267,2267,134,135,'FJAAAA','XXNAAA','HHHHxx'
+8987,9410,1,3,7,7,87,987,987,3987,8987,174,175,'RHAAAA','YXNAAA','OOOOxx'
+6709,9411,1,1,9,9,9,709,709,1709,6709,18,19,'BYAAAA','ZXNAAA','VVVVxx'
+8059,9412,1,3,9,19,59,59,59,3059,8059,118,119,'ZXAAAA','AYNAAA','AAAAxx'
+3402,9413,0,2,2,2,2,402,1402,3402,3402,4,5,'WAAAAA','BYNAAA','HHHHxx'
+6443,9414,1,3,3,3,43,443,443,1443,6443,86,87,'VNAAAA','CYNAAA','OOOOxx'
+8858,9415,0,2,8,18,58,858,858,3858,8858,116,117,'SCAAAA','DYNAAA','VVVVxx'
+3974,9416,0,2,4,14,74,974,1974,3974,3974,148,149,'WWAAAA','EYNAAA','AAAAxx'
+3521,9417,1,1,1,1,21,521,1521,3521,3521,42,43,'LFAAAA','FYNAAA','HHHHxx'
+9509,9418,1,1,9,9,9,509,1509,4509,9509,18,19,'TBAAAA','GYNAAA','OOOOxx'
+5442,9419,0,2,2,2,42,442,1442,442,5442,84,85,'IBAAAA','HYNAAA','VVVVxx'
+8968,9420,0,0,8,8,68,968,968,3968,8968,136,137,'YGAAAA','IYNAAA','AAAAxx'
+333,9421,1,1,3,13,33,333,333,333,333,66,67,'VMAAAA','JYNAAA','HHHHxx'
+952,9422,0,0,2,12,52,952,952,952,952,104,105,'QKAAAA','KYNAAA','OOOOxx'
+7482,9423,0,2,2,2,82,482,1482,2482,7482,164,165,'UBAAAA','LYNAAA','VVVVxx'
+1486,9424,0,2,6,6,86,486,1486,1486,1486,172,173,'EFAAAA','MYNAAA','AAAAxx'
+1815,9425,1,3,5,15,15,815,1815,1815,1815,30,31,'VRAAAA','NYNAAA','HHHHxx'
+7937,9426,1,1,7,17,37,937,1937,2937,7937,74,75,'HTAAAA','OYNAAA','OOOOxx'
+1436,9427,0,0,6,16,36,436,1436,1436,1436,72,73,'GDAAAA','PYNAAA','VVVVxx'
+3470,9428,0,2,0,10,70,470,1470,3470,3470,140,141,'MDAAAA','QYNAAA','AAAAxx'
+8195,9429,1,3,5,15,95,195,195,3195,8195,190,191,'FDAAAA','RYNAAA','HHHHxx'
+6906,9430,0,2,6,6,6,906,906,1906,6906,12,13,'QFAAAA','SYNAAA','OOOOxx'
+2539,9431,1,3,9,19,39,539,539,2539,2539,78,79,'RTAAAA','TYNAAA','VVVVxx'
+5988,9432,0,0,8,8,88,988,1988,988,5988,176,177,'IWAAAA','UYNAAA','AAAAxx'
+8908,9433,0,0,8,8,8,908,908,3908,8908,16,17,'QEAAAA','VYNAAA','HHHHxx'
+2319,9434,1,3,9,19,19,319,319,2319,2319,38,39,'FLAAAA','WYNAAA','OOOOxx'
+3263,9435,1,3,3,3,63,263,1263,3263,3263,126,127,'NVAAAA','XYNAAA','VVVVxx'
+4039,9436,1,3,9,19,39,39,39,4039,4039,78,79,'JZAAAA','YYNAAA','AAAAxx'
+6373,9437,1,1,3,13,73,373,373,1373,6373,146,147,'DLAAAA','ZYNAAA','HHHHxx'
+1168,9438,0,0,8,8,68,168,1168,1168,1168,136,137,'YSAAAA','AZNAAA','OOOOxx'
+8338,9439,0,2,8,18,38,338,338,3338,8338,76,77,'SIAAAA','BZNAAA','VVVVxx'
+1172,9440,0,0,2,12,72,172,1172,1172,1172,144,145,'CTAAAA','CZNAAA','AAAAxx'
+200,9441,0,0,0,0,0,200,200,200,200,0,1,'SHAAAA','DZNAAA','HHHHxx'
+6355,9442,1,3,5,15,55,355,355,1355,6355,110,111,'LKAAAA','EZNAAA','OOOOxx'
+7768,9443,0,0,8,8,68,768,1768,2768,7768,136,137,'UMAAAA','FZNAAA','VVVVxx'
+25,9444,1,1,5,5,25,25,25,25,25,50,51,'ZAAAAA','GZNAAA','AAAAxx'
+7144,9445,0,0,4,4,44,144,1144,2144,7144,88,89,'UOAAAA','HZNAAA','HHHHxx'
+8671,9446,1,3,1,11,71,671,671,3671,8671,142,143,'NVAAAA','IZNAAA','OOOOxx'
+9163,9447,1,3,3,3,63,163,1163,4163,9163,126,127,'LOAAAA','JZNAAA','VVVVxx'
+8889,9448,1,1,9,9,89,889,889,3889,8889,178,179,'XDAAAA','KZNAAA','AAAAxx'
+5950,9449,0,2,0,10,50,950,1950,950,5950,100,101,'WUAAAA','LZNAAA','HHHHxx'
+6163,9450,1,3,3,3,63,163,163,1163,6163,126,127,'BDAAAA','MZNAAA','OOOOxx'
+8119,9451,1,3,9,19,19,119,119,3119,8119,38,39,'HAAAAA','NZNAAA','VVVVxx'
+1416,9452,0,0,6,16,16,416,1416,1416,1416,32,33,'MCAAAA','OZNAAA','AAAAxx'
+4132,9453,0,0,2,12,32,132,132,4132,4132,64,65,'YCAAAA','PZNAAA','HHHHxx'
+2294,9454,0,2,4,14,94,294,294,2294,2294,188,189,'GKAAAA','QZNAAA','OOOOxx'
+9094,9455,0,2,4,14,94,94,1094,4094,9094,188,189,'ULAAAA','RZNAAA','VVVVxx'
+4168,9456,0,0,8,8,68,168,168,4168,4168,136,137,'IEAAAA','SZNAAA','AAAAxx'
+9108,9457,0,0,8,8,8,108,1108,4108,9108,16,17,'IMAAAA','TZNAAA','HHHHxx'
+5706,9458,0,2,6,6,6,706,1706,706,5706,12,13,'MLAAAA','UZNAAA','OOOOxx'
+2231,9459,1,3,1,11,31,231,231,2231,2231,62,63,'VHAAAA','VZNAAA','VVVVxx'
+2173,9460,1,1,3,13,73,173,173,2173,2173,146,147,'PFAAAA','WZNAAA','AAAAxx'
+90,9461,0,2,0,10,90,90,90,90,90,180,181,'MDAAAA','XZNAAA','HHHHxx'
+9996,9462,0,0,6,16,96,996,1996,4996,9996,192,193,'MUAAAA','YZNAAA','OOOOxx'
+330,9463,0,2,0,10,30,330,330,330,330,60,61,'SMAAAA','ZZNAAA','VVVVxx'
+2052,9464,0,0,2,12,52,52,52,2052,2052,104,105,'YAAAAA','AAOAAA','AAAAxx'
+1093,9465,1,1,3,13,93,93,1093,1093,1093,186,187,'BQAAAA','BAOAAA','HHHHxx'
+5817,9466,1,1,7,17,17,817,1817,817,5817,34,35,'TPAAAA','CAOAAA','OOOOxx'
+1559,9467,1,3,9,19,59,559,1559,1559,1559,118,119,'ZHAAAA','DAOAAA','VVVVxx'
+8405,9468,1,1,5,5,5,405,405,3405,8405,10,11,'HLAAAA','EAOAAA','AAAAxx'
+9962,9469,0,2,2,2,62,962,1962,4962,9962,124,125,'ETAAAA','FAOAAA','HHHHxx'
+9461,9470,1,1,1,1,61,461,1461,4461,9461,122,123,'XZAAAA','GAOAAA','OOOOxx'
+3028,9471,0,0,8,8,28,28,1028,3028,3028,56,57,'MMAAAA','HAOAAA','VVVVxx'
+6814,9472,0,2,4,14,14,814,814,1814,6814,28,29,'CCAAAA','IAOAAA','AAAAxx'
+9587,9473,1,3,7,7,87,587,1587,4587,9587,174,175,'TEAAAA','JAOAAA','HHHHxx'
+6863,9474,1,3,3,3,63,863,863,1863,6863,126,127,'ZDAAAA','KAOAAA','OOOOxx'
+4963,9475,1,3,3,3,63,963,963,4963,4963,126,127,'XIAAAA','LAOAAA','VVVVxx'
+7811,9476,1,3,1,11,11,811,1811,2811,7811,22,23,'LOAAAA','MAOAAA','AAAAxx'
+7608,9477,0,0,8,8,8,608,1608,2608,7608,16,17,'QGAAAA','NAOAAA','HHHHxx'
+5321,9478,1,1,1,1,21,321,1321,321,5321,42,43,'RWAAAA','OAOAAA','OOOOxx'
+9971,9479,1,3,1,11,71,971,1971,4971,9971,142,143,'NTAAAA','PAOAAA','VVVVxx'
+6161,9480,1,1,1,1,61,161,161,1161,6161,122,123,'ZCAAAA','QAOAAA','AAAAxx'
+2181,9481,1,1,1,1,81,181,181,2181,2181,162,163,'XFAAAA','RAOAAA','HHHHxx'
+3828,9482,0,0,8,8,28,828,1828,3828,3828,56,57,'GRAAAA','SAOAAA','OOOOxx'
+348,9483,0,0,8,8,48,348,348,348,348,96,97,'KNAAAA','TAOAAA','VVVVxx'
+5459,9484,1,3,9,19,59,459,1459,459,5459,118,119,'ZBAAAA','UAOAAA','AAAAxx'
+9406,9485,0,2,6,6,6,406,1406,4406,9406,12,13,'UXAAAA','VAOAAA','HHHHxx'
+9852,9486,0,0,2,12,52,852,1852,4852,9852,104,105,'YOAAAA','WAOAAA','OOOOxx'
+3095,9487,1,3,5,15,95,95,1095,3095,3095,190,191,'BPAAAA','XAOAAA','VVVVxx'
+5597,9488,1,1,7,17,97,597,1597,597,5597,194,195,'HHAAAA','YAOAAA','AAAAxx'
+8841,9489,1,1,1,1,41,841,841,3841,8841,82,83,'BCAAAA','ZAOAAA','HHHHxx'
+3536,9490,0,0,6,16,36,536,1536,3536,3536,72,73,'AGAAAA','ABOAAA','OOOOxx'
+4009,9491,1,1,9,9,9,9,9,4009,4009,18,19,'FYAAAA','BBOAAA','VVVVxx'
+7366,9492,0,2,6,6,66,366,1366,2366,7366,132,133,'IXAAAA','CBOAAA','AAAAxx'
+7327,9493,1,3,7,7,27,327,1327,2327,7327,54,55,'VVAAAA','DBOAAA','HHHHxx'
+1613,9494,1,1,3,13,13,613,1613,1613,1613,26,27,'BKAAAA','EBOAAA','OOOOxx'
+8619,9495,1,3,9,19,19,619,619,3619,8619,38,39,'NTAAAA','FBOAAA','VVVVxx'
+4880,9496,0,0,0,0,80,880,880,4880,4880,160,161,'SFAAAA','GBOAAA','AAAAxx'
+1552,9497,0,0,2,12,52,552,1552,1552,1552,104,105,'SHAAAA','HBOAAA','HHHHxx'
+7636,9498,0,0,6,16,36,636,1636,2636,7636,72,73,'SHAAAA','IBOAAA','OOOOxx'
+8397,9499,1,1,7,17,97,397,397,3397,8397,194,195,'ZKAAAA','JBOAAA','VVVVxx'
+6224,9500,0,0,4,4,24,224,224,1224,6224,48,49,'KFAAAA','KBOAAA','AAAAxx'
+9102,9501,0,2,2,2,2,102,1102,4102,9102,4,5,'CMAAAA','LBOAAA','HHHHxx'
+7906,9502,0,2,6,6,6,906,1906,2906,7906,12,13,'CSAAAA','MBOAAA','OOOOxx'
+9467,9503,1,3,7,7,67,467,1467,4467,9467,134,135,'DAAAAA','NBOAAA','VVVVxx'
+828,9504,0,0,8,8,28,828,828,828,828,56,57,'WFAAAA','OBOAAA','AAAAxx'
+9585,9505,1,1,5,5,85,585,1585,4585,9585,170,171,'REAAAA','PBOAAA','HHHHxx'
+925,9506,1,1,5,5,25,925,925,925,925,50,51,'PJAAAA','QBOAAA','OOOOxx'
+7375,9507,1,3,5,15,75,375,1375,2375,7375,150,151,'RXAAAA','RBOAAA','VVVVxx'
+4027,9508,1,3,7,7,27,27,27,4027,4027,54,55,'XYAAAA','SBOAAA','AAAAxx'
+766,9509,0,2,6,6,66,766,766,766,766,132,133,'MDAAAA','TBOAAA','HHHHxx'
+5633,9510,1,1,3,13,33,633,1633,633,5633,66,67,'RIAAAA','UBOAAA','OOOOxx'
+5648,9511,0,0,8,8,48,648,1648,648,5648,96,97,'GJAAAA','VBOAAA','VVVVxx'
+148,9512,0,0,8,8,48,148,148,148,148,96,97,'SFAAAA','WBOAAA','AAAAxx'
+2072,9513,0,0,2,12,72,72,72,2072,2072,144,145,'SBAAAA','XBOAAA','HHHHxx'
+431,9514,1,3,1,11,31,431,431,431,431,62,63,'PQAAAA','YBOAAA','OOOOxx'
+1711,9515,1,3,1,11,11,711,1711,1711,1711,22,23,'VNAAAA','ZBOAAA','VVVVxx'
+9378,9516,0,2,8,18,78,378,1378,4378,9378,156,157,'SWAAAA','ACOAAA','AAAAxx'
+6776,9517,0,0,6,16,76,776,776,1776,6776,152,153,'QAAAAA','BCOAAA','HHHHxx'
+6842,9518,0,2,2,2,42,842,842,1842,6842,84,85,'EDAAAA','CCOAAA','OOOOxx'
+2656,9519,0,0,6,16,56,656,656,2656,2656,112,113,'EYAAAA','DCOAAA','VVVVxx'
+3116,9520,0,0,6,16,16,116,1116,3116,3116,32,33,'WPAAAA','ECOAAA','AAAAxx'
+7904,9521,0,0,4,4,4,904,1904,2904,7904,8,9,'ASAAAA','FCOAAA','HHHHxx'
+3529,9522,1,1,9,9,29,529,1529,3529,3529,58,59,'TFAAAA','GCOAAA','OOOOxx'
+3240,9523,0,0,0,0,40,240,1240,3240,3240,80,81,'QUAAAA','HCOAAA','VVVVxx'
+5801,9524,1,1,1,1,1,801,1801,801,5801,2,3,'DPAAAA','ICOAAA','AAAAxx'
+4090,9525,0,2,0,10,90,90,90,4090,4090,180,181,'IBAAAA','JCOAAA','HHHHxx'
+7687,9526,1,3,7,7,87,687,1687,2687,7687,174,175,'RJAAAA','KCOAAA','OOOOxx'
+9711,9527,1,3,1,11,11,711,1711,4711,9711,22,23,'NJAAAA','LCOAAA','VVVVxx'
+4760,9528,0,0,0,0,60,760,760,4760,4760,120,121,'CBAAAA','MCOAAA','AAAAxx'
+5524,9529,0,0,4,4,24,524,1524,524,5524,48,49,'MEAAAA','NCOAAA','HHHHxx'
+2251,9530,1,3,1,11,51,251,251,2251,2251,102,103,'PIAAAA','OCOAAA','OOOOxx'
+1511,9531,1,3,1,11,11,511,1511,1511,1511,22,23,'DGAAAA','PCOAAA','VVVVxx'
+5991,9532,1,3,1,11,91,991,1991,991,5991,182,183,'LWAAAA','QCOAAA','AAAAxx'
+7808,9533,0,0,8,8,8,808,1808,2808,7808,16,17,'IOAAAA','RCOAAA','HHHHxx'
+8708,9534,0,0,8,8,8,708,708,3708,8708,16,17,'YWAAAA','SCOAAA','OOOOxx'
+8939,9535,1,3,9,19,39,939,939,3939,8939,78,79,'VFAAAA','TCOAAA','VVVVxx'
+4295,9536,1,3,5,15,95,295,295,4295,4295,190,191,'FJAAAA','UCOAAA','AAAAxx'
+5905,9537,1,1,5,5,5,905,1905,905,5905,10,11,'DTAAAA','VCOAAA','HHHHxx'
+2649,9538,1,1,9,9,49,649,649,2649,2649,98,99,'XXAAAA','WCOAAA','OOOOxx'
+2347,9539,1,3,7,7,47,347,347,2347,2347,94,95,'HMAAAA','XCOAAA','VVVVxx'
+6339,9540,1,3,9,19,39,339,339,1339,6339,78,79,'VJAAAA','YCOAAA','AAAAxx'
+292,9541,0,0,2,12,92,292,292,292,292,184,185,'GLAAAA','ZCOAAA','HHHHxx'
+9314,9542,0,2,4,14,14,314,1314,4314,9314,28,29,'GUAAAA','ADOAAA','OOOOxx'
+6893,9543,1,1,3,13,93,893,893,1893,6893,186,187,'DFAAAA','BDOAAA','VVVVxx'
+3970,9544,0,2,0,10,70,970,1970,3970,3970,140,141,'SWAAAA','CDOAAA','AAAAxx'
+1652,9545,0,0,2,12,52,652,1652,1652,1652,104,105,'OLAAAA','DDOAAA','HHHHxx'
+4326,9546,0,2,6,6,26,326,326,4326,4326,52,53,'KKAAAA','EDOAAA','OOOOxx'
+7881,9547,1,1,1,1,81,881,1881,2881,7881,162,163,'DRAAAA','FDOAAA','VVVVxx'
+5291,9548,1,3,1,11,91,291,1291,291,5291,182,183,'NVAAAA','GDOAAA','AAAAxx'
+957,9549,1,1,7,17,57,957,957,957,957,114,115,'VKAAAA','HDOAAA','HHHHxx'
+2313,9550,1,1,3,13,13,313,313,2313,2313,26,27,'ZKAAAA','IDOAAA','OOOOxx'
+5463,9551,1,3,3,3,63,463,1463,463,5463,126,127,'DCAAAA','JDOAAA','VVVVxx'
+1268,9552,0,0,8,8,68,268,1268,1268,1268,136,137,'UWAAAA','KDOAAA','AAAAxx'
+5028,9553,0,0,8,8,28,28,1028,28,5028,56,57,'KLAAAA','LDOAAA','HHHHxx'
+656,9554,0,0,6,16,56,656,656,656,656,112,113,'GZAAAA','MDOAAA','OOOOxx'
+9274,9555,0,2,4,14,74,274,1274,4274,9274,148,149,'SSAAAA','NDOAAA','VVVVxx'
+8217,9556,1,1,7,17,17,217,217,3217,8217,34,35,'BEAAAA','ODOAAA','AAAAxx'
+2175,9557,1,3,5,15,75,175,175,2175,2175,150,151,'RFAAAA','PDOAAA','HHHHxx'
+6028,9558,0,0,8,8,28,28,28,1028,6028,56,57,'WXAAAA','QDOAAA','OOOOxx'
+7584,9559,0,0,4,4,84,584,1584,2584,7584,168,169,'SFAAAA','RDOAAA','VVVVxx'
+4114,9560,0,2,4,14,14,114,114,4114,4114,28,29,'GCAAAA','SDOAAA','AAAAxx'
+8894,9561,0,2,4,14,94,894,894,3894,8894,188,189,'CEAAAA','TDOAAA','HHHHxx'
+781,9562,1,1,1,1,81,781,781,781,781,162,163,'BEAAAA','UDOAAA','OOOOxx'
+133,9563,1,1,3,13,33,133,133,133,133,66,67,'DFAAAA','VDOAAA','VVVVxx'
+7572,9564,0,0,2,12,72,572,1572,2572,7572,144,145,'GFAAAA','WDOAAA','AAAAxx'
+8514,9565,0,2,4,14,14,514,514,3514,8514,28,29,'MPAAAA','XDOAAA','HHHHxx'
+3352,9566,0,0,2,12,52,352,1352,3352,3352,104,105,'YYAAAA','YDOAAA','OOOOxx'
+8098,9567,0,2,8,18,98,98,98,3098,8098,196,197,'MZAAAA','ZDOAAA','VVVVxx'
+9116,9568,0,0,6,16,16,116,1116,4116,9116,32,33,'QMAAAA','AEOAAA','AAAAxx'
+9444,9569,0,0,4,4,44,444,1444,4444,9444,88,89,'GZAAAA','BEOAAA','HHHHxx'
+2590,9570,0,2,0,10,90,590,590,2590,2590,180,181,'QVAAAA','CEOAAA','OOOOxx'
+7302,9571,0,2,2,2,2,302,1302,2302,7302,4,5,'WUAAAA','DEOAAA','VVVVxx'
+7444,9572,0,0,4,4,44,444,1444,2444,7444,88,89,'IAAAAA','EEOAAA','AAAAxx'
+8748,9573,0,0,8,8,48,748,748,3748,8748,96,97,'MYAAAA','FEOAAA','HHHHxx'
+7615,9574,1,3,5,15,15,615,1615,2615,7615,30,31,'XGAAAA','GEOAAA','OOOOxx'
+6090,9575,0,2,0,10,90,90,90,1090,6090,180,181,'GAAAAA','HEOAAA','VVVVxx'
+1529,9576,1,1,9,9,29,529,1529,1529,1529,58,59,'VGAAAA','IEOAAA','AAAAxx'
+9398,9577,0,2,8,18,98,398,1398,4398,9398,196,197,'MXAAAA','JEOAAA','HHHHxx'
+6114,9578,0,2,4,14,14,114,114,1114,6114,28,29,'EBAAAA','KEOAAA','OOOOxx'
+2736,9579,0,0,6,16,36,736,736,2736,2736,72,73,'GBAAAA','LEOAAA','VVVVxx'
+468,9580,0,0,8,8,68,468,468,468,468,136,137,'ASAAAA','MEOAAA','AAAAxx'
+1487,9581,1,3,7,7,87,487,1487,1487,1487,174,175,'FFAAAA','NEOAAA','HHHHxx'
+4784,9582,0,0,4,4,84,784,784,4784,4784,168,169,'ACAAAA','OEOAAA','OOOOxx'
+6731,9583,1,3,1,11,31,731,731,1731,6731,62,63,'XYAAAA','PEOAAA','VVVVxx'
+3328,9584,0,0,8,8,28,328,1328,3328,3328,56,57,'AYAAAA','QEOAAA','AAAAxx'
+6891,9585,1,3,1,11,91,891,891,1891,6891,182,183,'BFAAAA','REOAAA','HHHHxx'
+8039,9586,1,3,9,19,39,39,39,3039,8039,78,79,'FXAAAA','SEOAAA','OOOOxx'
+4064,9587,0,0,4,4,64,64,64,4064,4064,128,129,'IAAAAA','TEOAAA','VVVVxx'
+542,9588,0,2,2,2,42,542,542,542,542,84,85,'WUAAAA','UEOAAA','AAAAxx'
+1039,9589,1,3,9,19,39,39,1039,1039,1039,78,79,'ZNAAAA','VEOAAA','HHHHxx'
+5603,9590,1,3,3,3,3,603,1603,603,5603,6,7,'NHAAAA','WEOAAA','OOOOxx'
+6641,9591,1,1,1,1,41,641,641,1641,6641,82,83,'LVAAAA','XEOAAA','VVVVxx'
+6307,9592,1,3,7,7,7,307,307,1307,6307,14,15,'PIAAAA','YEOAAA','AAAAxx'
+5354,9593,0,2,4,14,54,354,1354,354,5354,108,109,'YXAAAA','ZEOAAA','HHHHxx'
+7878,9594,0,2,8,18,78,878,1878,2878,7878,156,157,'ARAAAA','AFOAAA','OOOOxx'
+6391,9595,1,3,1,11,91,391,391,1391,6391,182,183,'VLAAAA','BFOAAA','VVVVxx'
+4575,9596,1,3,5,15,75,575,575,4575,4575,150,151,'ZTAAAA','CFOAAA','AAAAxx'
+6644,9597,0,0,4,4,44,644,644,1644,6644,88,89,'OVAAAA','DFOAAA','HHHHxx'
+5207,9598,1,3,7,7,7,207,1207,207,5207,14,15,'HSAAAA','EFOAAA','OOOOxx'
+1736,9599,0,0,6,16,36,736,1736,1736,1736,72,73,'UOAAAA','FFOAAA','VVVVxx'
+3547,9600,1,3,7,7,47,547,1547,3547,3547,94,95,'LGAAAA','GFOAAA','AAAAxx'
+6647,9601,1,3,7,7,47,647,647,1647,6647,94,95,'RVAAAA','HFOAAA','HHHHxx'
+4107,9602,1,3,7,7,7,107,107,4107,4107,14,15,'ZBAAAA','IFOAAA','OOOOxx'
+8125,9603,1,1,5,5,25,125,125,3125,8125,50,51,'NAAAAA','JFOAAA','VVVVxx'
+9223,9604,1,3,3,3,23,223,1223,4223,9223,46,47,'TQAAAA','KFOAAA','AAAAxx'
+6903,9605,1,3,3,3,3,903,903,1903,6903,6,7,'NFAAAA','LFOAAA','HHHHxx'
+3639,9606,1,3,9,19,39,639,1639,3639,3639,78,79,'ZJAAAA','MFOAAA','OOOOxx'
+9606,9607,0,2,6,6,6,606,1606,4606,9606,12,13,'MFAAAA','NFOAAA','VVVVxx'
+3232,9608,0,0,2,12,32,232,1232,3232,3232,64,65,'IUAAAA','OFOAAA','AAAAxx'
+2063,9609,1,3,3,3,63,63,63,2063,2063,126,127,'JBAAAA','PFOAAA','HHHHxx'
+3731,9610,1,3,1,11,31,731,1731,3731,3731,62,63,'NNAAAA','QFOAAA','OOOOxx'
+2558,9611,0,2,8,18,58,558,558,2558,2558,116,117,'KUAAAA','RFOAAA','VVVVxx'
+2357,9612,1,1,7,17,57,357,357,2357,2357,114,115,'RMAAAA','SFOAAA','AAAAxx'
+6008,9613,0,0,8,8,8,8,8,1008,6008,16,17,'CXAAAA','TFOAAA','HHHHxx'
+8246,9614,0,2,6,6,46,246,246,3246,8246,92,93,'EFAAAA','UFOAAA','OOOOxx'
+8220,9615,0,0,0,0,20,220,220,3220,8220,40,41,'EEAAAA','VFOAAA','VVVVxx'
+1075,9616,1,3,5,15,75,75,1075,1075,1075,150,151,'JPAAAA','WFOAAA','AAAAxx'
+2410,9617,0,2,0,10,10,410,410,2410,2410,20,21,'SOAAAA','XFOAAA','HHHHxx'
+3253,9618,1,1,3,13,53,253,1253,3253,3253,106,107,'DVAAAA','YFOAAA','OOOOxx'
+4370,9619,0,2,0,10,70,370,370,4370,4370,140,141,'CMAAAA','ZFOAAA','VVVVxx'
+8426,9620,0,2,6,6,26,426,426,3426,8426,52,53,'CMAAAA','AGOAAA','AAAAxx'
+2262,9621,0,2,2,2,62,262,262,2262,2262,124,125,'AJAAAA','BGOAAA','HHHHxx'
+4149,9622,1,1,9,9,49,149,149,4149,4149,98,99,'PDAAAA','CGOAAA','OOOOxx'
+2732,9623,0,0,2,12,32,732,732,2732,2732,64,65,'CBAAAA','DGOAAA','VVVVxx'
+8606,9624,0,2,6,6,6,606,606,3606,8606,12,13,'ATAAAA','EGOAAA','AAAAxx'
+6311,9625,1,3,1,11,11,311,311,1311,6311,22,23,'TIAAAA','FGOAAA','HHHHxx'
+7223,9626,1,3,3,3,23,223,1223,2223,7223,46,47,'VRAAAA','GGOAAA','OOOOxx'
+3054,9627,0,2,4,14,54,54,1054,3054,3054,108,109,'MNAAAA','HGOAAA','VVVVxx'
+3952,9628,0,0,2,12,52,952,1952,3952,3952,104,105,'AWAAAA','IGOAAA','AAAAxx'
+8252,9629,0,0,2,12,52,252,252,3252,8252,104,105,'KFAAAA','JGOAAA','HHHHxx'
+6020,9630,0,0,0,0,20,20,20,1020,6020,40,41,'OXAAAA','KGOAAA','OOOOxx'
+3846,9631,0,2,6,6,46,846,1846,3846,3846,92,93,'YRAAAA','LGOAAA','VVVVxx'
+3755,9632,1,3,5,15,55,755,1755,3755,3755,110,111,'LOAAAA','MGOAAA','AAAAxx'
+3765,9633,1,1,5,5,65,765,1765,3765,3765,130,131,'VOAAAA','NGOAAA','HHHHxx'
+3434,9634,0,2,4,14,34,434,1434,3434,3434,68,69,'CCAAAA','OGOAAA','OOOOxx'
+1381,9635,1,1,1,1,81,381,1381,1381,1381,162,163,'DBAAAA','PGOAAA','VVVVxx'
+287,9636,1,3,7,7,87,287,287,287,287,174,175,'BLAAAA','QGOAAA','AAAAxx'
+4476,9637,0,0,6,16,76,476,476,4476,4476,152,153,'EQAAAA','RGOAAA','HHHHxx'
+2916,9638,0,0,6,16,16,916,916,2916,2916,32,33,'EIAAAA','SGOAAA','OOOOxx'
+4517,9639,1,1,7,17,17,517,517,4517,4517,34,35,'TRAAAA','TGOAAA','VVVVxx'
+4561,9640,1,1,1,1,61,561,561,4561,4561,122,123,'LTAAAA','UGOAAA','AAAAxx'
+5106,9641,0,2,6,6,6,106,1106,106,5106,12,13,'KOAAAA','VGOAAA','HHHHxx'
+2077,9642,1,1,7,17,77,77,77,2077,2077,154,155,'XBAAAA','WGOAAA','OOOOxx'
+5269,9643,1,1,9,9,69,269,1269,269,5269,138,139,'RUAAAA','XGOAAA','VVVVxx'
+5688,9644,0,0,8,8,88,688,1688,688,5688,176,177,'UKAAAA','YGOAAA','AAAAxx'
+8831,9645,1,3,1,11,31,831,831,3831,8831,62,63,'RBAAAA','ZGOAAA','HHHHxx'
+3867,9646,1,3,7,7,67,867,1867,3867,3867,134,135,'TSAAAA','AHOAAA','OOOOxx'
+6062,9647,0,2,2,2,62,62,62,1062,6062,124,125,'EZAAAA','BHOAAA','VVVVxx'
+8460,9648,0,0,0,0,60,460,460,3460,8460,120,121,'KNAAAA','CHOAAA','AAAAxx'
+3138,9649,0,2,8,18,38,138,1138,3138,3138,76,77,'SQAAAA','DHOAAA','HHHHxx'
+3173,9650,1,1,3,13,73,173,1173,3173,3173,146,147,'BSAAAA','EHOAAA','OOOOxx'
+7018,9651,0,2,8,18,18,18,1018,2018,7018,36,37,'YJAAAA','FHOAAA','VVVVxx'
+4836,9652,0,0,6,16,36,836,836,4836,4836,72,73,'AEAAAA','GHOAAA','AAAAxx'
+1007,9653,1,3,7,7,7,7,1007,1007,1007,14,15,'TMAAAA','HHOAAA','HHHHxx'
+658,9654,0,2,8,18,58,658,658,658,658,116,117,'IZAAAA','IHOAAA','OOOOxx'
+5205,9655,1,1,5,5,5,205,1205,205,5205,10,11,'FSAAAA','JHOAAA','VVVVxx'
+5805,9656,1,1,5,5,5,805,1805,805,5805,10,11,'HPAAAA','KHOAAA','AAAAxx'
+5959,9657,1,3,9,19,59,959,1959,959,5959,118,119,'FVAAAA','LHOAAA','HHHHxx'
+2863,9658,1,3,3,3,63,863,863,2863,2863,126,127,'DGAAAA','MHOAAA','OOOOxx'
+7272,9659,0,0,2,12,72,272,1272,2272,7272,144,145,'STAAAA','NHOAAA','VVVVxx'
+8437,9660,1,1,7,17,37,437,437,3437,8437,74,75,'NMAAAA','OHOAAA','AAAAxx'
+4900,9661,0,0,0,0,0,900,900,4900,4900,0,1,'MGAAAA','PHOAAA','HHHHxx'
+890,9662,0,2,0,10,90,890,890,890,890,180,181,'GIAAAA','QHOAAA','OOOOxx'
+3530,9663,0,2,0,10,30,530,1530,3530,3530,60,61,'UFAAAA','RHOAAA','VVVVxx'
+6209,9664,1,1,9,9,9,209,209,1209,6209,18,19,'VEAAAA','SHOAAA','AAAAxx'
+4595,9665,1,3,5,15,95,595,595,4595,4595,190,191,'TUAAAA','THOAAA','HHHHxx'
+5982,9666,0,2,2,2,82,982,1982,982,5982,164,165,'CWAAAA','UHOAAA','OOOOxx'
+1101,9667,1,1,1,1,1,101,1101,1101,1101,2,3,'JQAAAA','VHOAAA','VVVVxx'
+9555,9668,1,3,5,15,55,555,1555,4555,9555,110,111,'NDAAAA','WHOAAA','AAAAxx'
+1918,9669,0,2,8,18,18,918,1918,1918,1918,36,37,'UVAAAA','XHOAAA','HHHHxx'
+3527,9670,1,3,7,7,27,527,1527,3527,3527,54,55,'RFAAAA','YHOAAA','OOOOxx'
+7309,9671,1,1,9,9,9,309,1309,2309,7309,18,19,'DVAAAA','ZHOAAA','VVVVxx'
+8213,9672,1,1,3,13,13,213,213,3213,8213,26,27,'XDAAAA','AIOAAA','AAAAxx'
+306,9673,0,2,6,6,6,306,306,306,306,12,13,'ULAAAA','BIOAAA','HHHHxx'
+845,9674,1,1,5,5,45,845,845,845,845,90,91,'NGAAAA','CIOAAA','OOOOxx'
+16,9675,0,0,6,16,16,16,16,16,16,32,33,'QAAAAA','DIOAAA','VVVVxx'
+437,9676,1,1,7,17,37,437,437,437,437,74,75,'VQAAAA','EIOAAA','AAAAxx'
+9518,9677,0,2,8,18,18,518,1518,4518,9518,36,37,'CCAAAA','FIOAAA','HHHHxx'
+2142,9678,0,2,2,2,42,142,142,2142,2142,84,85,'KEAAAA','GIOAAA','OOOOxx'
+8121,9679,1,1,1,1,21,121,121,3121,8121,42,43,'JAAAAA','HIOAAA','VVVVxx'
+7354,9680,0,2,4,14,54,354,1354,2354,7354,108,109,'WWAAAA','IIOAAA','AAAAxx'
+1720,9681,0,0,0,0,20,720,1720,1720,1720,40,41,'EOAAAA','JIOAAA','HHHHxx'
+6078,9682,0,2,8,18,78,78,78,1078,6078,156,157,'UZAAAA','KIOAAA','OOOOxx'
+5929,9683,1,1,9,9,29,929,1929,929,5929,58,59,'BUAAAA','LIOAAA','VVVVxx'
+3856,9684,0,0,6,16,56,856,1856,3856,3856,112,113,'ISAAAA','MIOAAA','AAAAxx'
+3424,9685,0,0,4,4,24,424,1424,3424,3424,48,49,'SBAAAA','NIOAAA','HHHHxx'
+1712,9686,0,0,2,12,12,712,1712,1712,1712,24,25,'WNAAAA','OIOAAA','OOOOxx'
+2340,9687,0,0,0,0,40,340,340,2340,2340,80,81,'AMAAAA','PIOAAA','VVVVxx'
+5570,9688,0,2,0,10,70,570,1570,570,5570,140,141,'GGAAAA','QIOAAA','AAAAxx'
+8734,9689,0,2,4,14,34,734,734,3734,8734,68,69,'YXAAAA','RIOAAA','HHHHxx'
+6077,9690,1,1,7,17,77,77,77,1077,6077,154,155,'TZAAAA','SIOAAA','OOOOxx'
+2960,9691,0,0,0,0,60,960,960,2960,2960,120,121,'WJAAAA','TIOAAA','VVVVxx'
+5062,9692,0,2,2,2,62,62,1062,62,5062,124,125,'SMAAAA','UIOAAA','AAAAxx'
+1532,9693,0,0,2,12,32,532,1532,1532,1532,64,65,'YGAAAA','VIOAAA','HHHHxx'
+8298,9694,0,2,8,18,98,298,298,3298,8298,196,197,'EHAAAA','WIOAAA','OOOOxx'
+2496,9695,0,0,6,16,96,496,496,2496,2496,192,193,'ASAAAA','XIOAAA','VVVVxx'
+8412,9696,0,0,2,12,12,412,412,3412,8412,24,25,'OLAAAA','YIOAAA','AAAAxx'
+724,9697,0,0,4,4,24,724,724,724,724,48,49,'WBAAAA','ZIOAAA','HHHHxx'
+1019,9698,1,3,9,19,19,19,1019,1019,1019,38,39,'FNAAAA','AJOAAA','OOOOxx'
+6265,9699,1,1,5,5,65,265,265,1265,6265,130,131,'ZGAAAA','BJOAAA','VVVVxx'
+740,9700,0,0,0,0,40,740,740,740,740,80,81,'MCAAAA','CJOAAA','AAAAxx'
+8495,9701,1,3,5,15,95,495,495,3495,8495,190,191,'TOAAAA','DJOAAA','HHHHxx'
+6983,9702,1,3,3,3,83,983,983,1983,6983,166,167,'PIAAAA','EJOAAA','OOOOxx'
+991,9703,1,3,1,11,91,991,991,991,991,182,183,'DMAAAA','FJOAAA','VVVVxx'
+3189,9704,1,1,9,9,89,189,1189,3189,3189,178,179,'RSAAAA','GJOAAA','AAAAxx'
+4487,9705,1,3,7,7,87,487,487,4487,4487,174,175,'PQAAAA','HJOAAA','HHHHxx'
+5554,9706,0,2,4,14,54,554,1554,554,5554,108,109,'QFAAAA','IJOAAA','OOOOxx'
+1258,9707,0,2,8,18,58,258,1258,1258,1258,116,117,'KWAAAA','JJOAAA','VVVVxx'
+5359,9708,1,3,9,19,59,359,1359,359,5359,118,119,'DYAAAA','KJOAAA','AAAAxx'
+2709,9709,1,1,9,9,9,709,709,2709,2709,18,19,'FAAAAA','LJOAAA','HHHHxx'
+361,9710,1,1,1,1,61,361,361,361,361,122,123,'XNAAAA','MJOAAA','OOOOxx'
+4028,9711,0,0,8,8,28,28,28,4028,4028,56,57,'YYAAAA','NJOAAA','VVVVxx'
+3735,9712,1,3,5,15,35,735,1735,3735,3735,70,71,'RNAAAA','OJOAAA','AAAAxx'
+4427,9713,1,3,7,7,27,427,427,4427,4427,54,55,'HOAAAA','PJOAAA','HHHHxx'
+7540,9714,0,0,0,0,40,540,1540,2540,7540,80,81,'AEAAAA','QJOAAA','OOOOxx'
+3569,9715,1,1,9,9,69,569,1569,3569,3569,138,139,'HHAAAA','RJOAAA','VVVVxx'
+1916,9716,0,0,6,16,16,916,1916,1916,1916,32,33,'SVAAAA','SJOAAA','AAAAxx'
+7596,9717,0,0,6,16,96,596,1596,2596,7596,192,193,'EGAAAA','TJOAAA','HHHHxx'
+9721,9718,1,1,1,1,21,721,1721,4721,9721,42,43,'XJAAAA','UJOAAA','OOOOxx'
+4429,9719,1,1,9,9,29,429,429,4429,4429,58,59,'JOAAAA','VJOAAA','VVVVxx'
+3471,9720,1,3,1,11,71,471,1471,3471,3471,142,143,'NDAAAA','WJOAAA','AAAAxx'
+1157,9721,1,1,7,17,57,157,1157,1157,1157,114,115,'NSAAAA','XJOAAA','HHHHxx'
+5700,9722,0,0,0,0,0,700,1700,700,5700,0,1,'GLAAAA','YJOAAA','OOOOxx'
+4431,9723,1,3,1,11,31,431,431,4431,4431,62,63,'LOAAAA','ZJOAAA','VVVVxx'
+9409,9724,1,1,9,9,9,409,1409,4409,9409,18,19,'XXAAAA','AKOAAA','AAAAxx'
+8752,9725,0,0,2,12,52,752,752,3752,8752,104,105,'QYAAAA','BKOAAA','HHHHxx'
+9484,9726,0,0,4,4,84,484,1484,4484,9484,168,169,'UAAAAA','CKOAAA','OOOOxx'
+1266,9727,0,2,6,6,66,266,1266,1266,1266,132,133,'SWAAAA','DKOAAA','VVVVxx'
+9097,9728,1,1,7,17,97,97,1097,4097,9097,194,195,'XLAAAA','EKOAAA','AAAAxx'
+3068,9729,0,0,8,8,68,68,1068,3068,3068,136,137,'AOAAAA','FKOAAA','HHHHxx'
+5490,9730,0,2,0,10,90,490,1490,490,5490,180,181,'EDAAAA','GKOAAA','OOOOxx'
+1375,9731,1,3,5,15,75,375,1375,1375,1375,150,151,'XAAAAA','HKOAAA','VVVVxx'
+2487,9732,1,3,7,7,87,487,487,2487,2487,174,175,'RRAAAA','IKOAAA','AAAAxx'
+1705,9733,1,1,5,5,5,705,1705,1705,1705,10,11,'PNAAAA','JKOAAA','HHHHxx'
+1571,9734,1,3,1,11,71,571,1571,1571,1571,142,143,'LIAAAA','KKOAAA','OOOOxx'
+4005,9735,1,1,5,5,5,5,5,4005,4005,10,11,'BYAAAA','LKOAAA','VVVVxx'
+5497,9736,1,1,7,17,97,497,1497,497,5497,194,195,'LDAAAA','MKOAAA','AAAAxx'
+2144,9737,0,0,4,4,44,144,144,2144,2144,88,89,'MEAAAA','NKOAAA','HHHHxx'
+4052,9738,0,0,2,12,52,52,52,4052,4052,104,105,'WZAAAA','OKOAAA','OOOOxx'
+4942,9739,0,2,2,2,42,942,942,4942,4942,84,85,'CIAAAA','PKOAAA','VVVVxx'
+5504,9740,0,0,4,4,4,504,1504,504,5504,8,9,'SDAAAA','QKOAAA','AAAAxx'
+2913,9741,1,1,3,13,13,913,913,2913,2913,26,27,'BIAAAA','RKOAAA','HHHHxx'
+5617,9742,1,1,7,17,17,617,1617,617,5617,34,35,'BIAAAA','SKOAAA','OOOOxx'
+8179,9743,1,3,9,19,79,179,179,3179,8179,158,159,'PCAAAA','TKOAAA','VVVVxx'
+9437,9744,1,1,7,17,37,437,1437,4437,9437,74,75,'ZYAAAA','UKOAAA','AAAAxx'
+1821,9745,1,1,1,1,21,821,1821,1821,1821,42,43,'BSAAAA','VKOAAA','HHHHxx'
+5737,9746,1,1,7,17,37,737,1737,737,5737,74,75,'RMAAAA','WKOAAA','OOOOxx'
+4207,9747,1,3,7,7,7,207,207,4207,4207,14,15,'VFAAAA','XKOAAA','VVVVxx'
+4815,9748,1,3,5,15,15,815,815,4815,4815,30,31,'FDAAAA','YKOAAA','AAAAxx'
+8707,9749,1,3,7,7,7,707,707,3707,8707,14,15,'XWAAAA','ZKOAAA','HHHHxx'
+5970,9750,0,2,0,10,70,970,1970,970,5970,140,141,'QVAAAA','ALOAAA','OOOOxx'
+5501,9751,1,1,1,1,1,501,1501,501,5501,2,3,'PDAAAA','BLOAAA','VVVVxx'
+4013,9752,1,1,3,13,13,13,13,4013,4013,26,27,'JYAAAA','CLOAAA','AAAAxx'
+9235,9753,1,3,5,15,35,235,1235,4235,9235,70,71,'FRAAAA','DLOAAA','HHHHxx'
+2503,9754,1,3,3,3,3,503,503,2503,2503,6,7,'HSAAAA','ELOAAA','OOOOxx'
+9181,9755,1,1,1,1,81,181,1181,4181,9181,162,163,'DPAAAA','FLOAAA','VVVVxx'
+2289,9756,1,1,9,9,89,289,289,2289,2289,178,179,'BKAAAA','GLOAAA','AAAAxx'
+4256,9757,0,0,6,16,56,256,256,4256,4256,112,113,'SHAAAA','HLOAAA','HHHHxx'
+191,9758,1,3,1,11,91,191,191,191,191,182,183,'JHAAAA','ILOAAA','OOOOxx'
+9655,9759,1,3,5,15,55,655,1655,4655,9655,110,111,'JHAAAA','JLOAAA','VVVVxx'
+8615,9760,1,3,5,15,15,615,615,3615,8615,30,31,'JTAAAA','KLOAAA','AAAAxx'
+3011,9761,1,3,1,11,11,11,1011,3011,3011,22,23,'VLAAAA','LLOAAA','HHHHxx'
+6376,9762,0,0,6,16,76,376,376,1376,6376,152,153,'GLAAAA','MLOAAA','OOOOxx'
+68,9763,0,0,8,8,68,68,68,68,68,136,137,'QCAAAA','NLOAAA','VVVVxx'
+4720,9764,0,0,0,0,20,720,720,4720,4720,40,41,'OZAAAA','OLOAAA','AAAAxx'
+6848,9765,0,0,8,8,48,848,848,1848,6848,96,97,'KDAAAA','PLOAAA','HHHHxx'
+456,9766,0,0,6,16,56,456,456,456,456,112,113,'ORAAAA','QLOAAA','OOOOxx'
+5887,9767,1,3,7,7,87,887,1887,887,5887,174,175,'LSAAAA','RLOAAA','VVVVxx'
+9249,9768,1,1,9,9,49,249,1249,4249,9249,98,99,'TRAAAA','SLOAAA','AAAAxx'
+4041,9769,1,1,1,1,41,41,41,4041,4041,82,83,'LZAAAA','TLOAAA','HHHHxx'
+2304,9770,0,0,4,4,4,304,304,2304,2304,8,9,'QKAAAA','ULOAAA','OOOOxx'
+8763,9771,1,3,3,3,63,763,763,3763,8763,126,127,'BZAAAA','VLOAAA','VVVVxx'
+2115,9772,1,3,5,15,15,115,115,2115,2115,30,31,'JDAAAA','WLOAAA','AAAAxx'
+8014,9773,0,2,4,14,14,14,14,3014,8014,28,29,'GWAAAA','XLOAAA','HHHHxx'
+9895,9774,1,3,5,15,95,895,1895,4895,9895,190,191,'PQAAAA','YLOAAA','OOOOxx'
+671,9775,1,3,1,11,71,671,671,671,671,142,143,'VZAAAA','ZLOAAA','VVVVxx'
+3774,9776,0,2,4,14,74,774,1774,3774,3774,148,149,'EPAAAA','AMOAAA','AAAAxx'
+134,9777,0,2,4,14,34,134,134,134,134,68,69,'EFAAAA','BMOAAA','HHHHxx'
+534,9778,0,2,4,14,34,534,534,534,534,68,69,'OUAAAA','CMOAAA','OOOOxx'
+7308,9779,0,0,8,8,8,308,1308,2308,7308,16,17,'CVAAAA','DMOAAA','VVVVxx'
+5244,9780,0,0,4,4,44,244,1244,244,5244,88,89,'STAAAA','EMOAAA','AAAAxx'
+1512,9781,0,0,2,12,12,512,1512,1512,1512,24,25,'EGAAAA','FMOAAA','HHHHxx'
+8960,9782,0,0,0,0,60,960,960,3960,8960,120,121,'QGAAAA','GMOAAA','OOOOxx'
+6602,9783,0,2,2,2,2,602,602,1602,6602,4,5,'YTAAAA','HMOAAA','VVVVxx'
+593,9784,1,1,3,13,93,593,593,593,593,186,187,'VWAAAA','IMOAAA','AAAAxx'
+2353,9785,1,1,3,13,53,353,353,2353,2353,106,107,'NMAAAA','JMOAAA','HHHHxx'
+4139,9786,1,3,9,19,39,139,139,4139,4139,78,79,'FDAAAA','KMOAAA','OOOOxx'
+3063,9787,1,3,3,3,63,63,1063,3063,3063,126,127,'VNAAAA','LMOAAA','VVVVxx'
+652,9788,0,0,2,12,52,652,652,652,652,104,105,'CZAAAA','MMOAAA','AAAAxx'
+7405,9789,1,1,5,5,5,405,1405,2405,7405,10,11,'VYAAAA','NMOAAA','HHHHxx'
+3034,9790,0,2,4,14,34,34,1034,3034,3034,68,69,'SMAAAA','OMOAAA','OOOOxx'
+4614,9791,0,2,4,14,14,614,614,4614,4614,28,29,'MVAAAA','PMOAAA','VVVVxx'
+2351,9792,1,3,1,11,51,351,351,2351,2351,102,103,'LMAAAA','QMOAAA','AAAAxx'
+8208,9793,0,0,8,8,8,208,208,3208,8208,16,17,'SDAAAA','RMOAAA','HHHHxx'
+5475,9794,1,3,5,15,75,475,1475,475,5475,150,151,'PCAAAA','SMOAAA','OOOOxx'
+6875,9795,1,3,5,15,75,875,875,1875,6875,150,151,'LEAAAA','TMOAAA','VVVVxx'
+563,9796,1,3,3,3,63,563,563,563,563,126,127,'RVAAAA','UMOAAA','AAAAxx'
+3346,9797,0,2,6,6,46,346,1346,3346,3346,92,93,'SYAAAA','VMOAAA','HHHHxx'
+291,9798,1,3,1,11,91,291,291,291,291,182,183,'FLAAAA','WMOAAA','OOOOxx'
+6345,9799,1,1,5,5,45,345,345,1345,6345,90,91,'BKAAAA','XMOAAA','VVVVxx'
+8099,9800,1,3,9,19,99,99,99,3099,8099,198,199,'NZAAAA','YMOAAA','AAAAxx'
+2078,9801,0,2,8,18,78,78,78,2078,2078,156,157,'YBAAAA','ZMOAAA','HHHHxx'
+8238,9802,0,2,8,18,38,238,238,3238,8238,76,77,'WEAAAA','ANOAAA','OOOOxx'
+4482,9803,0,2,2,2,82,482,482,4482,4482,164,165,'KQAAAA','BNOAAA','VVVVxx'
+716,9804,0,0,6,16,16,716,716,716,716,32,33,'OBAAAA','CNOAAA','AAAAxx'
+7288,9805,0,0,8,8,88,288,1288,2288,7288,176,177,'IUAAAA','DNOAAA','HHHHxx'
+5906,9806,0,2,6,6,6,906,1906,906,5906,12,13,'ETAAAA','ENOAAA','OOOOxx'
+5618,9807,0,2,8,18,18,618,1618,618,5618,36,37,'CIAAAA','FNOAAA','VVVVxx'
+1141,9808,1,1,1,1,41,141,1141,1141,1141,82,83,'XRAAAA','GNOAAA','AAAAxx'
+8231,9809,1,3,1,11,31,231,231,3231,8231,62,63,'PEAAAA','HNOAAA','HHHHxx'
+3713,9810,1,1,3,13,13,713,1713,3713,3713,26,27,'VMAAAA','INOAAA','OOOOxx'
+9158,9811,0,2,8,18,58,158,1158,4158,9158,116,117,'GOAAAA','JNOAAA','VVVVxx'
+4051,9812,1,3,1,11,51,51,51,4051,4051,102,103,'VZAAAA','KNOAAA','AAAAxx'
+1973,9813,1,1,3,13,73,973,1973,1973,1973,146,147,'XXAAAA','LNOAAA','HHHHxx'
+6710,9814,0,2,0,10,10,710,710,1710,6710,20,21,'CYAAAA','MNOAAA','OOOOxx'
+1021,9815,1,1,1,1,21,21,1021,1021,1021,42,43,'HNAAAA','NNOAAA','VVVVxx'
+2196,9816,0,0,6,16,96,196,196,2196,2196,192,193,'MGAAAA','ONOAAA','AAAAxx'
+8335,9817,1,3,5,15,35,335,335,3335,8335,70,71,'PIAAAA','PNOAAA','HHHHxx'
+2272,9818,0,0,2,12,72,272,272,2272,2272,144,145,'KJAAAA','QNOAAA','OOOOxx'
+3818,9819,0,2,8,18,18,818,1818,3818,3818,36,37,'WQAAAA','RNOAAA','VVVVxx'
+679,9820,1,3,9,19,79,679,679,679,679,158,159,'DAAAAA','SNOAAA','AAAAxx'
+7512,9821,0,0,2,12,12,512,1512,2512,7512,24,25,'YCAAAA','TNOAAA','HHHHxx'
+493,9822,1,1,3,13,93,493,493,493,493,186,187,'ZSAAAA','UNOAAA','OOOOxx'
+5663,9823,1,3,3,3,63,663,1663,663,5663,126,127,'VJAAAA','VNOAAA','VVVVxx'
+4655,9824,1,3,5,15,55,655,655,4655,4655,110,111,'BXAAAA','WNOAAA','AAAAxx'
+3996,9825,0,0,6,16,96,996,1996,3996,3996,192,193,'SXAAAA','XNOAAA','HHHHxx'
+8797,9826,1,1,7,17,97,797,797,3797,8797,194,195,'JAAAAA','YNOAAA','OOOOxx'
+2991,9827,1,3,1,11,91,991,991,2991,2991,182,183,'BLAAAA','ZNOAAA','VVVVxx'
+7038,9828,0,2,8,18,38,38,1038,2038,7038,76,77,'SKAAAA','AOOAAA','AAAAxx'
+4174,9829,0,2,4,14,74,174,174,4174,4174,148,149,'OEAAAA','BOOAAA','HHHHxx'
+6908,9830,0,0,8,8,8,908,908,1908,6908,16,17,'SFAAAA','COOAAA','OOOOxx'
+8477,9831,1,1,7,17,77,477,477,3477,8477,154,155,'BOAAAA','DOOAAA','VVVVxx'
+3576,9832,0,0,6,16,76,576,1576,3576,3576,152,153,'OHAAAA','EOOAAA','AAAAxx'
+2685,9833,1,1,5,5,85,685,685,2685,2685,170,171,'HZAAAA','FOOAAA','HHHHxx'
+9161,9834,1,1,1,1,61,161,1161,4161,9161,122,123,'JOAAAA','GOOAAA','OOOOxx'
+2951,9835,1,3,1,11,51,951,951,2951,2951,102,103,'NJAAAA','HOOAAA','VVVVxx'
+8362,9836,0,2,2,2,62,362,362,3362,8362,124,125,'QJAAAA','IOOAAA','AAAAxx'
+2379,9837,1,3,9,19,79,379,379,2379,2379,158,159,'NNAAAA','JOOAAA','HHHHxx'
+1277,9838,1,1,7,17,77,277,1277,1277,1277,154,155,'DXAAAA','KOOAAA','OOOOxx'
+1728,9839,0,0,8,8,28,728,1728,1728,1728,56,57,'MOAAAA','LOOAAA','VVVVxx'
+9816,9840,0,0,6,16,16,816,1816,4816,9816,32,33,'ONAAAA','MOOAAA','AAAAxx'
+6288,9841,0,0,8,8,88,288,288,1288,6288,176,177,'WHAAAA','NOOAAA','HHHHxx'
+8985,9842,1,1,5,5,85,985,985,3985,8985,170,171,'PHAAAA','OOOAAA','OOOOxx'
+771,9843,1,3,1,11,71,771,771,771,771,142,143,'RDAAAA','POOAAA','VVVVxx'
+464,9844,0,0,4,4,64,464,464,464,464,128,129,'WRAAAA','QOOAAA','AAAAxx'
+9625,9845,1,1,5,5,25,625,1625,4625,9625,50,51,'FGAAAA','ROOAAA','HHHHxx'
+9608,9846,0,0,8,8,8,608,1608,4608,9608,16,17,'OFAAAA','SOOAAA','OOOOxx'
+9170,9847,0,2,0,10,70,170,1170,4170,9170,140,141,'SOAAAA','TOOAAA','VVVVxx'
+9658,9848,0,2,8,18,58,658,1658,4658,9658,116,117,'MHAAAA','UOOAAA','AAAAxx'
+7515,9849,1,3,5,15,15,515,1515,2515,7515,30,31,'BDAAAA','VOOAAA','HHHHxx'
+9400,9850,0,0,0,0,0,400,1400,4400,9400,0,1,'OXAAAA','WOOAAA','OOOOxx'
+2045,9851,1,1,5,5,45,45,45,2045,2045,90,91,'RAAAAA','XOOAAA','VVVVxx'
+324,9852,0,0,4,4,24,324,324,324,324,48,49,'MMAAAA','YOOAAA','AAAAxx'
+4252,9853,0,0,2,12,52,252,252,4252,4252,104,105,'OHAAAA','ZOOAAA','HHHHxx'
+8329,9854,1,1,9,9,29,329,329,3329,8329,58,59,'JIAAAA','APOAAA','OOOOxx'
+4472,9855,0,0,2,12,72,472,472,4472,4472,144,145,'AQAAAA','BPOAAA','VVVVxx'
+1047,9856,1,3,7,7,47,47,1047,1047,1047,94,95,'HOAAAA','CPOAAA','AAAAxx'
+9341,9857,1,1,1,1,41,341,1341,4341,9341,82,83,'HVAAAA','DPOAAA','HHHHxx'
+7000,9858,0,0,0,0,0,0,1000,2000,7000,0,1,'GJAAAA','EPOAAA','OOOOxx'
+1429,9859,1,1,9,9,29,429,1429,1429,1429,58,59,'ZCAAAA','FPOAAA','VVVVxx'
+2701,9860,1,1,1,1,1,701,701,2701,2701,2,3,'XZAAAA','GPOAAA','AAAAxx'
+6630,9861,0,2,0,10,30,630,630,1630,6630,60,61,'AVAAAA','HPOAAA','HHHHxx'
+3669,9862,1,1,9,9,69,669,1669,3669,3669,138,139,'DLAAAA','IPOAAA','OOOOxx'
+8613,9863,1,1,3,13,13,613,613,3613,8613,26,27,'HTAAAA','JPOAAA','VVVVxx'
+7080,9864,0,0,0,0,80,80,1080,2080,7080,160,161,'IMAAAA','KPOAAA','AAAAxx'
+8788,9865,0,0,8,8,88,788,788,3788,8788,176,177,'AAAAAA','LPOAAA','HHHHxx'
+6291,9866,1,3,1,11,91,291,291,1291,6291,182,183,'ZHAAAA','MPOAAA','OOOOxx'
+7885,9867,1,1,5,5,85,885,1885,2885,7885,170,171,'HRAAAA','NPOAAA','VVVVxx'
+7160,9868,0,0,0,0,60,160,1160,2160,7160,120,121,'KPAAAA','OPOAAA','AAAAxx'
+6140,9869,0,0,0,0,40,140,140,1140,6140,80,81,'ECAAAA','PPOAAA','HHHHxx'
+9881,9870,1,1,1,1,81,881,1881,4881,9881,162,163,'BQAAAA','QPOAAA','OOOOxx'
+9140,9871,0,0,0,0,40,140,1140,4140,9140,80,81,'ONAAAA','RPOAAA','VVVVxx'
+644,9872,0,0,4,4,44,644,644,644,644,88,89,'UYAAAA','SPOAAA','AAAAxx'
+3667,9873,1,3,7,7,67,667,1667,3667,3667,134,135,'BLAAAA','TPOAAA','HHHHxx'
+2675,9874,1,3,5,15,75,675,675,2675,2675,150,151,'XYAAAA','UPOAAA','OOOOxx'
+9492,9875,0,0,2,12,92,492,1492,4492,9492,184,185,'CBAAAA','VPOAAA','VVVVxx'
+5004,9876,0,0,4,4,4,4,1004,4,5004,8,9,'MKAAAA','WPOAAA','AAAAxx'
+9456,9877,0,0,6,16,56,456,1456,4456,9456,112,113,'SZAAAA','XPOAAA','HHHHxx'
+8197,9878,1,1,7,17,97,197,197,3197,8197,194,195,'HDAAAA','YPOAAA','OOOOxx'
+2837,9879,1,1,7,17,37,837,837,2837,2837,74,75,'DFAAAA','ZPOAAA','VVVVxx'
+127,9880,1,3,7,7,27,127,127,127,127,54,55,'XEAAAA','AQOAAA','AAAAxx'
+9772,9881,0,0,2,12,72,772,1772,4772,9772,144,145,'WLAAAA','BQOAAA','HHHHxx'
+5743,9882,1,3,3,3,43,743,1743,743,5743,86,87,'XMAAAA','CQOAAA','OOOOxx'
+2007,9883,1,3,7,7,7,7,7,2007,2007,14,15,'FZAAAA','DQOAAA','VVVVxx'
+7586,9884,0,2,6,6,86,586,1586,2586,7586,172,173,'UFAAAA','EQOAAA','AAAAxx'
+45,9885,1,1,5,5,45,45,45,45,45,90,91,'TBAAAA','FQOAAA','HHHHxx'
+6482,9886,0,2,2,2,82,482,482,1482,6482,164,165,'IPAAAA','GQOAAA','OOOOxx'
+4565,9887,1,1,5,5,65,565,565,4565,4565,130,131,'PTAAAA','HQOAAA','VVVVxx'
+6975,9888,1,3,5,15,75,975,975,1975,6975,150,151,'HIAAAA','IQOAAA','AAAAxx'
+7260,9889,0,0,0,0,60,260,1260,2260,7260,120,121,'GTAAAA','JQOAAA','HHHHxx'
+2830,9890,0,2,0,10,30,830,830,2830,2830,60,61,'WEAAAA','KQOAAA','OOOOxx'
+9365,9891,1,1,5,5,65,365,1365,4365,9365,130,131,'FWAAAA','LQOAAA','VVVVxx'
+8207,9892,1,3,7,7,7,207,207,3207,8207,14,15,'RDAAAA','MQOAAA','AAAAxx'
+2506,9893,0,2,6,6,6,506,506,2506,2506,12,13,'KSAAAA','NQOAAA','HHHHxx'
+8081,9894,1,1,1,1,81,81,81,3081,8081,162,163,'VYAAAA','OQOAAA','OOOOxx'
+8678,9895,0,2,8,18,78,678,678,3678,8678,156,157,'UVAAAA','PQOAAA','VVVVxx'
+9932,9896,0,0,2,12,32,932,1932,4932,9932,64,65,'ASAAAA','QQOAAA','AAAAxx'
+447,9897,1,3,7,7,47,447,447,447,447,94,95,'FRAAAA','RQOAAA','HHHHxx'
+9187,9898,1,3,7,7,87,187,1187,4187,9187,174,175,'JPAAAA','SQOAAA','OOOOxx'
+89,9899,1,1,9,9,89,89,89,89,89,178,179,'LDAAAA','TQOAAA','VVVVxx'
+7027,9900,1,3,7,7,27,27,1027,2027,7027,54,55,'HKAAAA','UQOAAA','AAAAxx'
+1536,9901,0,0,6,16,36,536,1536,1536,1536,72,73,'CHAAAA','VQOAAA','HHHHxx'
+160,9902,0,0,0,0,60,160,160,160,160,120,121,'EGAAAA','WQOAAA','OOOOxx'
+7679,9903,1,3,9,19,79,679,1679,2679,7679,158,159,'JJAAAA','XQOAAA','VVVVxx'
+5973,9904,1,1,3,13,73,973,1973,973,5973,146,147,'TVAAAA','YQOAAA','AAAAxx'
+4401,9905,1,1,1,1,1,401,401,4401,4401,2,3,'HNAAAA','ZQOAAA','HHHHxx'
+395,9906,1,3,5,15,95,395,395,395,395,190,191,'FPAAAA','AROAAA','OOOOxx'
+4904,9907,0,0,4,4,4,904,904,4904,4904,8,9,'QGAAAA','BROAAA','VVVVxx'
+2759,9908,1,3,9,19,59,759,759,2759,2759,118,119,'DCAAAA','CROAAA','AAAAxx'
+8713,9909,1,1,3,13,13,713,713,3713,8713,26,27,'DXAAAA','DROAAA','HHHHxx'
+3770,9910,0,2,0,10,70,770,1770,3770,3770,140,141,'APAAAA','EROAAA','OOOOxx'
+8272,9911,0,0,2,12,72,272,272,3272,8272,144,145,'EGAAAA','FROAAA','VVVVxx'
+5358,9912,0,2,8,18,58,358,1358,358,5358,116,117,'CYAAAA','GROAAA','AAAAxx'
+9747,9913,1,3,7,7,47,747,1747,4747,9747,94,95,'XKAAAA','HROAAA','HHHHxx'
+1567,9914,1,3,7,7,67,567,1567,1567,1567,134,135,'HIAAAA','IROAAA','OOOOxx'
+2136,9915,0,0,6,16,36,136,136,2136,2136,72,73,'EEAAAA','JROAAA','VVVVxx'
+314,9916,0,2,4,14,14,314,314,314,314,28,29,'CMAAAA','KROAAA','AAAAxx'
+4583,9917,1,3,3,3,83,583,583,4583,4583,166,167,'HUAAAA','LROAAA','HHHHxx'
+375,9918,1,3,5,15,75,375,375,375,375,150,151,'LOAAAA','MROAAA','OOOOxx'
+5566,9919,0,2,6,6,66,566,1566,566,5566,132,133,'CGAAAA','NROAAA','VVVVxx'
+6865,9920,1,1,5,5,65,865,865,1865,6865,130,131,'BEAAAA','OROAAA','AAAAxx'
+894,9921,0,2,4,14,94,894,894,894,894,188,189,'KIAAAA','PROAAA','HHHHxx'
+5399,9922,1,3,9,19,99,399,1399,399,5399,198,199,'RZAAAA','QROAAA','OOOOxx'
+1385,9923,1,1,5,5,85,385,1385,1385,1385,170,171,'HBAAAA','RROAAA','VVVVxx'
+2156,9924,0,0,6,16,56,156,156,2156,2156,112,113,'YEAAAA','SROAAA','AAAAxx'
+9659,9925,1,3,9,19,59,659,1659,4659,9659,118,119,'NHAAAA','TROAAA','HHHHxx'
+477,9926,1,1,7,17,77,477,477,477,477,154,155,'JSAAAA','UROAAA','OOOOxx'
+8194,9927,0,2,4,14,94,194,194,3194,8194,188,189,'EDAAAA','VROAAA','VVVVxx'
+3937,9928,1,1,7,17,37,937,1937,3937,3937,74,75,'LVAAAA','WROAAA','AAAAxx'
+3745,9929,1,1,5,5,45,745,1745,3745,3745,90,91,'BOAAAA','XROAAA','HHHHxx'
+4096,9930,0,0,6,16,96,96,96,4096,4096,192,193,'OBAAAA','YROAAA','OOOOxx'
+5487,9931,1,3,7,7,87,487,1487,487,5487,174,175,'BDAAAA','ZROAAA','VVVVxx'
+2475,9932,1,3,5,15,75,475,475,2475,2475,150,151,'FRAAAA','ASOAAA','AAAAxx'
+6105,9933,1,1,5,5,5,105,105,1105,6105,10,11,'VAAAAA','BSOAAA','HHHHxx'
+6036,9934,0,0,6,16,36,36,36,1036,6036,72,73,'EYAAAA','CSOAAA','OOOOxx'
+1315,9935,1,3,5,15,15,315,1315,1315,1315,30,31,'PYAAAA','DSOAAA','VVVVxx'
+4473,9936,1,1,3,13,73,473,473,4473,4473,146,147,'BQAAAA','ESOAAA','AAAAxx'
+4016,9937,0,0,6,16,16,16,16,4016,4016,32,33,'MYAAAA','FSOAAA','HHHHxx'
+8135,9938,1,3,5,15,35,135,135,3135,8135,70,71,'XAAAAA','GSOAAA','OOOOxx'
+8892,9939,0,0,2,12,92,892,892,3892,8892,184,185,'AEAAAA','HSOAAA','VVVVxx'
+4850,9940,0,2,0,10,50,850,850,4850,4850,100,101,'OEAAAA','ISOAAA','AAAAxx'
+2545,9941,1,1,5,5,45,545,545,2545,2545,90,91,'XTAAAA','JSOAAA','HHHHxx'
+3788,9942,0,0,8,8,88,788,1788,3788,3788,176,177,'SPAAAA','KSOAAA','OOOOxx'
+1672,9943,0,0,2,12,72,672,1672,1672,1672,144,145,'IMAAAA','LSOAAA','VVVVxx'
+3664,9944,0,0,4,4,64,664,1664,3664,3664,128,129,'YKAAAA','MSOAAA','AAAAxx'
+3775,9945,1,3,5,15,75,775,1775,3775,3775,150,151,'FPAAAA','NSOAAA','HHHHxx'
+3103,9946,1,3,3,3,3,103,1103,3103,3103,6,7,'JPAAAA','OSOAAA','OOOOxx'
+9335,9947,1,3,5,15,35,335,1335,4335,9335,70,71,'BVAAAA','PSOAAA','VVVVxx'
+9200,9948,0,0,0,0,0,200,1200,4200,9200,0,1,'WPAAAA','QSOAAA','AAAAxx'
+8665,9949,1,1,5,5,65,665,665,3665,8665,130,131,'HVAAAA','RSOAAA','HHHHxx'
+1356,9950,0,0,6,16,56,356,1356,1356,1356,112,113,'EAAAAA','SSOAAA','OOOOxx'
+6118,9951,0,2,8,18,18,118,118,1118,6118,36,37,'IBAAAA','TSOAAA','VVVVxx'
+4605,9952,1,1,5,5,5,605,605,4605,4605,10,11,'DVAAAA','USOAAA','AAAAxx'
+5651,9953,1,3,1,11,51,651,1651,651,5651,102,103,'JJAAAA','VSOAAA','HHHHxx'
+9055,9954,1,3,5,15,55,55,1055,4055,9055,110,111,'HKAAAA','WSOAAA','OOOOxx'
+8461,9955,1,1,1,1,61,461,461,3461,8461,122,123,'LNAAAA','XSOAAA','VVVVxx'
+6107,9956,1,3,7,7,7,107,107,1107,6107,14,15,'XAAAAA','YSOAAA','AAAAxx'
+1967,9957,1,3,7,7,67,967,1967,1967,1967,134,135,'RXAAAA','ZSOAAA','HHHHxx'
+8910,9958,0,2,0,10,10,910,910,3910,8910,20,21,'SEAAAA','ATOAAA','OOOOxx'
+8257,9959,1,1,7,17,57,257,257,3257,8257,114,115,'PFAAAA','BTOAAA','VVVVxx'
+851,9960,1,3,1,11,51,851,851,851,851,102,103,'TGAAAA','CTOAAA','AAAAxx'
+7823,9961,1,3,3,3,23,823,1823,2823,7823,46,47,'XOAAAA','DTOAAA','HHHHxx'
+3208,9962,0,0,8,8,8,208,1208,3208,3208,16,17,'KTAAAA','ETOAAA','OOOOxx'
+856,9963,0,0,6,16,56,856,856,856,856,112,113,'YGAAAA','FTOAAA','VVVVxx'
+2654,9964,0,2,4,14,54,654,654,2654,2654,108,109,'CYAAAA','GTOAAA','AAAAxx'
+7185,9965,1,1,5,5,85,185,1185,2185,7185,170,171,'JQAAAA','HTOAAA','HHHHxx'
+309,9966,1,1,9,9,9,309,309,309,309,18,19,'XLAAAA','ITOAAA','OOOOxx'
+9752,9967,0,0,2,12,52,752,1752,4752,9752,104,105,'CLAAAA','JTOAAA','VVVVxx'
+6405,9968,1,1,5,5,5,405,405,1405,6405,10,11,'JMAAAA','KTOAAA','AAAAxx'
+6113,9969,1,1,3,13,13,113,113,1113,6113,26,27,'DBAAAA','LTOAAA','HHHHxx'
+9774,9970,0,2,4,14,74,774,1774,4774,9774,148,149,'YLAAAA','MTOAAA','OOOOxx'
+1674,9971,0,2,4,14,74,674,1674,1674,1674,148,149,'KMAAAA','NTOAAA','VVVVxx'
+9602,9972,0,2,2,2,2,602,1602,4602,9602,4,5,'IFAAAA','OTOAAA','AAAAxx'
+1363,9973,1,3,3,3,63,363,1363,1363,1363,126,127,'LAAAAA','PTOAAA','HHHHxx'
+6887,9974,1,3,7,7,87,887,887,1887,6887,174,175,'XEAAAA','QTOAAA','OOOOxx'
+6170,9975,0,2,0,10,70,170,170,1170,6170,140,141,'IDAAAA','RTOAAA','VVVVxx'
+8888,9976,0,0,8,8,88,888,888,3888,8888,176,177,'WDAAAA','STOAAA','AAAAxx'
+2981,9977,1,1,1,1,81,981,981,2981,2981,162,163,'RKAAAA','TTOAAA','HHHHxx'
+7369,9978,1,1,9,9,69,369,1369,2369,7369,138,139,'LXAAAA','UTOAAA','OOOOxx'
+6227,9979,1,3,7,7,27,227,227,1227,6227,54,55,'NFAAAA','VTOAAA','VVVVxx'
+8002,9980,0,2,2,2,2,2,2,3002,8002,4,5,'UVAAAA','WTOAAA','AAAAxx'
+4288,9981,0,0,8,8,88,288,288,4288,4288,176,177,'YIAAAA','XTOAAA','HHHHxx'
+5136,9982,0,0,6,16,36,136,1136,136,5136,72,73,'OPAAAA','YTOAAA','OOOOxx'
+1084,9983,0,0,4,4,84,84,1084,1084,1084,168,169,'SPAAAA','ZTOAAA','VVVVxx'
+9117,9984,1,1,7,17,17,117,1117,4117,9117,34,35,'RMAAAA','AUOAAA','AAAAxx'
+2406,9985,0,2,6,6,6,406,406,2406,2406,12,13,'OOAAAA','BUOAAA','HHHHxx'
+1384,9986,0,0,4,4,84,384,1384,1384,1384,168,169,'GBAAAA','CUOAAA','OOOOxx'
+9194,9987,0,2,4,14,94,194,1194,4194,9194,188,189,'QPAAAA','DUOAAA','VVVVxx'
+858,9988,0,2,8,18,58,858,858,858,858,116,117,'AHAAAA','EUOAAA','AAAAxx'
+8592,9989,0,0,2,12,92,592,592,3592,8592,184,185,'MSAAAA','FUOAAA','HHHHxx'
+4773,9990,1,1,3,13,73,773,773,4773,4773,146,147,'PBAAAA','GUOAAA','OOOOxx'
+4093,9991,1,1,3,13,93,93,93,4093,4093,186,187,'LBAAAA','HUOAAA','VVVVxx'
+6587,9992,1,3,7,7,87,587,587,1587,6587,174,175,'JTAAAA','IUOAAA','AAAAxx'
+6093,9993,1,1,3,13,93,93,93,1093,6093,186,187,'JAAAAA','JUOAAA','HHHHxx'
+429,9994,1,1,9,9,29,429,429,429,429,58,59,'NQAAAA','KUOAAA','OOOOxx'
+5780,9995,0,0,0,0,80,780,1780,780,5780,160,161,'IOAAAA','LUOAAA','VVVVxx'
+1783,9996,1,3,3,3,83,783,1783,1783,1783,166,167,'PQAAAA','MUOAAA','AAAAxx'
+2992,9997,0,0,2,12,92,992,992,2992,2992,184,185,'CLAAAA','NUOAAA','HHHHxx'
+0,9998,0,0,0,0,0,0,0,0,0,0,1,'AAAAAA','OUOAAA','OOOOxx'
+2968,9999,0,0,8,8,68,968,968,2968,2968,136,137,'EKAAAA','PUOAAA','VVVVxx'
diff --git a/sql-bench/Makefile.am b/sql-bench/Makefile.am
new file mode 100644
index 00000000000..0f01de71074
--- /dev/null
+++ b/sql-bench/Makefile.am
@@ -0,0 +1,79 @@
+# 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
+
+benchdir = $(prefix)/sql-bench
+bench_SCRIPTS = test-ATIS test-connect test-create test-insert \
+ test-big-tables test-select test-wisconsin \
+ test-alter-table \
+ bench-init.pl compare-results run-all-tests \
+ server-cfg crash-me copy-db
+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 \
+ bench-init.pl.sh compare-results.sh server-cfg.sh \
+ run-all-tests.sh crash-me.sh copy-db.sh
+EXTRA_DIST = $(EXTRA_SCRIPTS)
+
+dist-hook:
+ mkdir -p $(distdir)/Data/ATIS $(distdir)/Data/Wisconsin \
+ $(distdir)/Results $(distdir)/Results-linux \
+ $(distdir)/Results-win32 \
+ $(distdir)/limits
+ cp -pr $(srcdir)/Data/ATIS $(distdir)/Data
+ cp -pr $(srcdir)/Data/Wisconsin $(distdir)/Data
+ cp -pr $(srcdir)/Results $(distdir)/
+ cp -pr $(srcdir)/Results-linux $(distdir)/
+ cp -pr $(srcdir)/Results-win32 $(distdir)/
+ cp -pr $(srcdir)/limits $(distdir)/
+
+install-data-local:
+ $(mkinstalldirs) \
+ $(DESTDIR)$(benchdir)/Data \
+ $(DESTDIR)$(benchdir)/Data/ATIS \
+ $(DESTDIR)$(benchdir)/Data/Wisconsin \
+ $(DESTDIR)$(benchdir)/Results \
+ $(DESTDIR)$(benchdir)/Results-linux \
+ $(DESTDIR)$(benchdir)/Results-win32 \
+ $(DESTDIR)$(benchdir)/limits
+ cp -p $(srcdir)/README $(DESTDIR)$(benchdir)
+ cp -pr $(srcdir)/Data/ATIS $(DESTDIR)$(benchdir)/Data
+ cp -pr $(srcdir)/Data/Wisconsin $(DESTDIR)$(benchdir)/Data
+ cp -pr $(srcdir)/Results $(DESTDIR)$(benchdir)
+ cp -pr $(srcdir)/Results-linux $(DESTDIR)$(benchdir)
+ cp -pr $(srcdir)/Results-win32 $(DESTDIR)$(benchdir)
+ cp -pr $(srcdir)/limits $(DESTDIR)$(benchdir)
+
+SUFFIXES = .sh
+
+.sh:
+ @RM@ -f $@ $@-t
+ @SED@ \
+ -e 's!@''benchdir''@!$(benchdir)!g' \
+ -e 's!@''bindir''@!$(bindir)!g' \
+ -e 's!@''scriptdir''@!$(bindir)!g' \
+ -e 's!@''prefix''@!$(prefix)!g' \
+ -e 's!@''datadir''@!$(datadir)!g' \
+ -e 's!@''localstatedir''@!$(localstatedir)!g' \
+ -e 's!@''libexecdir''@!$(libexecdir)!g' \
+ -e 's!@''PERL''@!@PERL@!' \
+ -e 's!@''VERSION''@!@VERSION@!' \
+ $< > $@-t
+ @CHMOD@ +x $@-t
+ @MV@ $@-t $@
diff --git a/sql-bench/README b/sql-bench/README
new file mode 100755
index 00000000000..6096c5cc1e8
--- /dev/null
+++ b/sql-bench/README
@@ -0,0 +1,97 @@
+The MySQL Benchmarks
+
+These tests needs a MySQL version of at least 3.20.28 or 3.21.10.
+NOTE: With MySQL 3.20.# you have to use '--skip-in', because MySQL 3.20
+doesn't support the IN operator.
+
+Currently the following servers are supported:
+MySQL 3.20 and 3.21, PostgreSQL 6.#, mSQL 2.# and Solid Server 2.2
+
+In this directory are the queries and raw data files used to populate
+the MySQL benchmarks. In order to run the benchmarks you should normally
+execute a command like the following:
+
+run-all-tests --server=msyql --cmp=mysql,pg,solid --user=test --password=test --log
+
+The above means that one wants to run the benchmark with MySQL. The limits
+should be taken from all of mysql,PostgreSQL and Solid. Login name and
+password is 'test'. The result should be saved as a RUN file in the output
+directory.
+
+When the above script has run you will have the individual results and the
+the total RUN- file in the output directory.
+
+If you want to look at some old results, try:
+
+compare-results --dir=Results --cmp=mysql,pg,solid
+compare-results --dir=Results --cmp=mysql,pg,solid --relative
+
+compare-results --dir=Results --cmp=msql,mysql,pg,solid
+compare-results --dir=Results --cmp=msql,mysql,pg,solid --relative
+
+compare-results --dir=results --server=mysql --same-server --cmp=mysql,pg,solid
+
+
+File Description
+
+Data/ATIS Contains data for 29 related tables used in the ATIS tests.
+Data/Wisconsin Contains data for the Wisconsin benchmark.
+Results Contains old benchmark results.
+Makefile.am Automake Makefile
+Overview-paper A paper nicked from the net about database bench-
+ marking.
+README This file.
+test-ATIS.sh Cretation of 29 tables and a lot of selects on them.
+test-connect.sh Test how fast a connection to the server is.
+test-create.sh Test how fast a table is created.
+test-insert.sh Test create and fill of a table.
+test-wisconsin.sh This is a port of the PostgreSQL version of this
+ benchmark.
+run-all-test Use this to run all tests. When all test are run,
+ use the --log --use-old option to get a RUN-file.
+compare-results Makes a compare table from different RUN files.
+server-cfg Contains the limit and functions for all supported
+ SQL servers. If you want to add a new server, this
+ should be the only file that neads to be changed.
+
+
+Most of the test should use portable SQL to make it possible to
+compare different databases. Sometimes SQL extensions can make things
+a lot faster. In this case the test may use the extensions if the --fast
+option is used.
+
+Useful options to all test-scripts (and run-all-tests):
+
+--host=# Hostname for MySQL server (default: localhost)
+--db=# Database to use (default: test)
+--fast Allow use of any non-standard SQL extension to
+ do the get things done faster.
+--skip-in Don't do test with the IN operation (if the SQL server
+ hasn't implemented this, for example mSQL and MySQL 3.20).
+--lock-tables Use table locking to get more speed.
+
+From a text at http://www.mgt.ncu.edu.tw/CSIM/Paper/sixth/11.html
+
+The Wisconsin Benchmark
+
+The Wisconsin Benchmark described in [Bitton, DeWitt, and Turbyfill
+1983] [Boral and DeWitt 1984] [Bitton and Turbyfill 1985] [Bitton and
+Turbyfill 1988], and [DeWitt 1993] is the first effort to
+systematically measure and compare the performance of relational
+database systems with database machines. The benchmark is a
+single-user and single-factor experiment using a synthetic database
+and a controlled workload. It measures the query optimization
+performance of database systems with 32 query types to exe cise the
+components of the proposed systems. The query suites include
+selection, join, projection, aggregate, and simple update queries.
+
+The test database consists of four generic relations. The tenk
+relation is the key table and most used. Two data types of small
+integer number and character string are utilized. Data values are
+uniformly distributed. The primary metric is the query elapsed
+time. The main criticisms of the benchmark include the nature of
+single-user workload, the simplistic database structure, and the
+unrealistic query tests. A number of efforts have been made to extend
+the benchmark to incorporate the multi-user test. However, they do
+not receive the same acceptance as the original Wisconsin benchmark
+except an extension work called the AS3AP benchmark.
diff --git a/sql-bench/Results-win32/ATIS-access_odbc-win98-cmp-access,mysql b/sql-bench/Results-win32/ATIS-access_odbc-win98-cmp-access,mysql
new file mode 100644
index 00000000000..2a20462392c
--- /dev/null
+++ b/sql-bench/Results-win32/ATIS-access_odbc-win98-cmp-access,mysql
@@ -0,0 +1,19 @@
+Testing server 'Access 2000' at 2000-01-03 3:59:36
+
+ATIS table test
+
+Creating tables
+Time for create_table (28): 1 wallclock secs ( 0.50 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Inserting data
+Time to insert (9768): 58 wallclock secs (58.44 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Retrieving data
+Time for select_simple_join (500): 12 wallclock secs (11.59 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_join (200): 82 wallclock secs (81.89 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_distinct (800): 46 wallclock secs (46.14 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_group (2400): 42 wallclock secs (42.24 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Removing tables
+Time to drop_table (28): 0 wallclock secs ( 0.16 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Total time: 241 wallclock secs (241.02 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results-win32/ATIS-db2_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase b/sql-bench/Results-win32/ATIS-db2_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
new file mode 100644
index 00000000000..854f3cb2fd1
--- /dev/null
+++ b/sql-bench/Results-win32/ATIS-db2_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
@@ -0,0 +1,19 @@
+Testing server 'IBM DB2 5' at 1998-11-21 23:09:24
+
+ATIS table test
+
+Creating tables
+Time for create_table (28): 47 secs (46.89 usr 0.00 sys = 46.89 cpu)
+
+Inserting data
+Time to insert (9768): 101 secs (101.33 usr 0.00 sys = 101.33 cpu)
+
+Retrieving data
+Time for select_simple_join (500): 26 secs (26.36 usr 0.00 sys = 26.36 cpu)
+Time for select_join (200): 225 secs (224.28 usr 0.00 sys = 224.28 cpu)
+Time for select_distinct (800): 82 secs (82.50 usr 0.00 sys = 82.50 cpu)
+Time for select_group (2100): 32 secs (31.38 usr 0.00 sys = 31.38 cpu)
+
+Removing tables
+Time to drop_table (28): 1 secs ( 1.23 usr 0.00 sys = 1.23 cpu)
+Total time: 515 secs (514.66 usr 0.00 sys = 514.66 cpu)
diff --git a/sql-bench/Results-win32/ATIS-informix_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase b/sql-bench/Results-win32/ATIS-informix_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
new file mode 100644
index 00000000000..d5fc3965902
--- /dev/null
+++ b/sql-bench/Results-win32/ATIS-informix_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
@@ -0,0 +1,19 @@
+Testing server 'Informix 7.30C1 ' at 1998-09-01 2:00:37
+
+ATIS table test
+
+Creating tables
+Time for create_table (28): 3 secs ( 2.81 usr 0.00 sys = 2.81 cpu)
+
+Inserting data
+Time to insert (9768): 53 secs (52.98 usr 0.00 sys = 52.98 cpu)
+
+Retrieving data
+Time for select_simple_join (500): 22 secs (21.83 usr 0.00 sys = 21.83 cpu)
+Time for select_join (200): 99 secs (98.99 usr 0.00 sys = 98.99 cpu)
+Time for select_distinct (800): 97 secs (97.37 usr 0.00 sys = 97.37 cpu)
+Time for select_group (2100): 59 secs (58.55 usr 0.00 sys = 58.55 cpu)
+
+Removing tables
+Time to drop_table (28): 0 secs ( 0.78 usr 0.00 sys = 0.78 cpu)
+Total time: 333 secs (333.33 usr 0.00 sys = 333.33 cpu)
diff --git a/sql-bench/Results-win32/ATIS-ms-sql_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase b/sql-bench/Results-win32/ATIS-ms-sql_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
new file mode 100644
index 00000000000..061447969d9
--- /dev/null
+++ b/sql-bench/Results-win32/ATIS-ms-sql_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
@@ -0,0 +1,19 @@
+Testing server 'Microsoft SQL Server 7.00 - 7.00.517 (Intel X86) ' at 1998-09-07 2:15:22
+
+ATIS table test
+
+Creating tables
+Time for create_table (28): 1 secs ( 1.21 usr 0.00 sys = 1.21 cpu)
+
+Inserting data
+Time to insert (9768): 65 secs (64.59 usr 0.00 sys = 64.59 cpu)
+
+Retrieving data
+Time for select_simple_join (500): 8 secs ( 8.30 usr 0.00 sys = 8.30 cpu)
+Time for select_join (200): 66 secs (65.25 usr 0.00 sys = 65.25 cpu)
+Time for select_distinct (800): 59 secs (59.65 usr 0.00 sys = 59.65 cpu)
+Time for select_group (2100): 31 secs (30.33 usr 0.00 sys = 30.33 cpu)
+
+Removing tables
+Time to drop_table (28): 1 secs ( 1.07 usr 0.00 sys = 1.07 cpu)
+Total time: 231 secs (230.45 usr 0.00 sys = 230.45 cpu)
diff --git a/sql-bench/Results-win32/ATIS-mysql-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase b/sql-bench/Results-win32/ATIS-mysql-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
new file mode 100644
index 00000000000..8b5cd5d24c9
--- /dev/null
+++ b/sql-bench/Results-win32/ATIS-mysql-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
@@ -0,0 +1,19 @@
+Testing server 'MySQL 3.22.16 gamma' at 1999-02-20 19:53:01
+
+ATIS table test
+
+Creating tables
+Time for create_table (28): 0 wallclock secs ( 0.00 usr + 0.01 sys = 0.01 CPU)
+
+Inserting data
+Time to insert (9768): 8 wallclock secs ( 1.66 usr + 1.41 sys = 3.07 CPU)
+
+Retrieving data
+Time for select_simple_join (500): 3 wallclock secs ( 1.23 usr + 0.50 sys = 1.73 CPU)
+Time for select_join (200): 31 wallclock secs ( 8.80 usr + 4.19 sys = 12.99 CPU)
+Time for select_distinct (800): 17 wallclock secs ( 3.22 usr + 1.51 sys = 4.74 CPU)
+Time for select_group (2100): 12 wallclock secs ( 1.95 usr + 0.58 sys = 2.53 CPU)
+
+Removing tables
+Time to drop_table (28): 0 wallclock secs ( 0.00 usr + 0.02 sys = 0.02 CPU)
+Total time: 71 wallclock secs (16.88 usr + 8.22 sys = 25.11 CPU)
diff --git a/sql-bench/Results-win32/ATIS-mysql-win98 b/sql-bench/Results-win32/ATIS-mysql-win98
new file mode 100644
index 00000000000..1febfa34bcb
--- /dev/null
+++ b/sql-bench/Results-win32/ATIS-mysql-win98
@@ -0,0 +1,19 @@
+Testing server 'MySQL 3.23.13a alpha' at 2000-03-15 2:22:09
+
+ATIS table test
+
+Creating tables
+Time for create_table (28): 7 wallclock secs ( 6.93 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Inserting data
+Time to insert (9768): 12 wallclock secs (11.97 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Retrieving data
+Time for select_simple_join (500): 7 wallclock secs ( 7.47 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_join (200): 51 wallclock secs (50.15 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_distinct (800): 33 wallclock secs (33.34 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_group (2800): 33 wallclock secs (33.61 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Removing tables
+Time to drop_table (28): 1 wallclock secs ( 0.06 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Total time: 144 wallclock secs (143.53 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results-win32/ATIS-mysql-win98-cmp-access,mysql b/sql-bench/Results-win32/ATIS-mysql-win98-cmp-access,mysql
new file mode 100644
index 00000000000..35e02bc97f0
--- /dev/null
+++ b/sql-bench/Results-win32/ATIS-mysql-win98-cmp-access,mysql
@@ -0,0 +1,19 @@
+Testing server 'MySQL 3.23.8 alpha' at 2000-01-04 12:17:54
+
+ATIS table test
+
+Creating tables
+Time for create_table (28): 0 wallclock secs ( 0.22 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Inserting data
+Time to insert (9768): 15 wallclock secs (15.48 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Retrieving data
+Time for select_simple_join (500): 9 wallclock secs ( 8.35 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_join (200): 51 wallclock secs (51.25 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_distinct (800): 36 wallclock secs (36.52 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_group (2100): 23 wallclock secs (22.96 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Removing tables
+Time to drop_table (28): 0 wallclock secs ( 0.06 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Total time: 134 wallclock secs (134.84 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results-win32/ATIS-mysql_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase b/sql-bench/Results-win32/ATIS-mysql_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
new file mode 100644
index 00000000000..d0ab9a21940
--- /dev/null
+++ b/sql-bench/Results-win32/ATIS-mysql_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
@@ -0,0 +1,19 @@
+Testing server 'MySQL 3.22.16 gamma' at 1999-02-07 11:41:12
+
+ATIS table test
+
+Creating tables
+Time for create_table (28): 1 secs ( 0.17 usr 0.00 sys = 0.17 cpu)
+
+Inserting data
+Time to insert (9768): 15 secs (15.52 usr 0.00 sys = 15.52 cpu)
+
+Retrieving data
+Time for select_simple_join (500): 10 secs ( 9.62 usr 0.00 sys = 9.62 cpu)
+Time for select_join (200): 91 secs (90.99 usr 0.00 sys = 90.99 cpu)
+Time for select_distinct (800): 35 secs (35.07 usr 0.00 sys = 35.07 cpu)
+Time for select_group (2100): 16 secs (15.83 usr 0.00 sys = 15.83 cpu)
+
+Removing tables
+Time to drop_table (28): 0 secs ( 0.07 usr 0.00 sys = 0.07 cpu)
+Total time: 168 secs (167.31 usr 0.00 sys = 167.31 cpu)
diff --git a/sql-bench/Results-win32/ATIS-oracle_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase b/sql-bench/Results-win32/ATIS-oracle_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
new file mode 100644
index 00000000000..c33c525126c
--- /dev/null
+++ b/sql-bench/Results-win32/ATIS-oracle_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
@@ -0,0 +1,19 @@
+Testing server 'Oracle 8.0.4.0.0' at 1999-04-03 22:29:55
+
+ATIS table test
+
+Creating tables
+Time for create_table (28): 3 wallclock secs ( 0.11 usr 0.03 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Inserting data
+Time to insert (9768): 87 wallclock secs (13.15 usr 1.56 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Retrieving data
+Time for select_simple_join (500): 28 wallclock secs (13.20 usr 2.31 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_join (200): 255 wallclock secs (112.16 usr 20.68 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_distinct (800): 79 wallclock secs (37.62 usr 6.46 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_group (2100): 30 wallclock secs ( 9.51 usr 2.02 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Removing tables
+Time to drop_table (28): 4 wallclock secs ( 0.03 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Total time: 486 wallclock secs (185.81 usr 33.07 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results-win32/ATIS-solid_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase b/sql-bench/Results-win32/ATIS-solid_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
new file mode 100644
index 00000000000..4935821fd48
--- /dev/null
+++ b/sql-bench/Results-win32/ATIS-solid_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
@@ -0,0 +1,22 @@
+Testing server 'Solid version ???' at 1998-10-06 17:43:41
+
+ATIS table test
+
+Creating tables
+Time for create_table (28): 2 secs ( 1.80 usr 0.00 sys = 1.80 cpu)
+
+Inserting data
+Time to insert (9768): 45 secs (45.27 usr 0.00 sys = 45.27 cpu)
+
+Retrieving data
+Time for select_simple_join (500): 69 secs (69.48 usr 0.00 sys = 69.48 cpu)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+172 queries in 86 loops of 100 loops took 601 seconds
+Estimated time for select_join (200): 698 secs (698.11 usr 0.00 sys = 698.11 cpu)
+Time for select_distinct (800): 327 secs (327.14 usr 0.00 sys = 327.14 cpu)
+Time for select_group (2100): 105 secs (105.28 usr 0.00 sys = 105.28 cpu)
+
+Removing tables
+Time to drop_table (28): 2 secs ( 1.68 usr 0.00 sys = 1.68 cpu)
+Estimated total time: 1248 secs (1248.81 usr 0.00 sys = 1248.81 cpu)
diff --git a/sql-bench/Results-win32/ATIS-sybase_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase b/sql-bench/Results-win32/ATIS-sybase_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
new file mode 100644
index 00000000000..40c0f169f40
--- /dev/null
+++ b/sql-bench/Results-win32/ATIS-sybase_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
@@ -0,0 +1,19 @@
+Testing server 'Sybase enterprise 11.5 NT' at 1998-08-27 2:08:30
+
+ATIS table test
+
+Creating tables
+Time for create_table (28): 2 secs ( 1.41 usr 0.00 sys = 1.41 cpu)
+
+Inserting data
+Time to insert (9768): 120 secs (120.34 usr 0.00 sys = 120.34 cpu)
+
+Retrieving data
+Time for select_simple_join (500): 17 secs (16.86 usr 0.00 sys = 16.86 cpu)
+Time for select_join (200): 114 secs (114.63 usr 0.00 sys = 114.63 cpu)
+Time for select_distinct (800): 64 secs (63.34 usr 0.00 sys = 63.34 cpu)
+Time for select_group (2100): 21 secs (21.00 usr 0.00 sys = 21.00 cpu)
+
+Removing tables
+Time to drop_table (28): 0 secs ( 0.31 usr 0.00 sys = 0.31 cpu)
+Total time: 338 secs (337.94 usr 0.00 sys = 337.94 cpu)
diff --git a/sql-bench/Results-win32/RUN-access_odbc-win98-cmp-access,mysql b/sql-bench/Results-win32/RUN-access_odbc-win98-cmp-access,mysql
new file mode 100644
index 00000000000..58dbaa500e3
--- /dev/null
+++ b/sql-bench/Results-win32/RUN-access_odbc-win98-cmp-access,mysql
@@ -0,0 +1,68 @@
+Benchmark DBD suite: 2.5
+Date of test: 2000-01-06 2:01:10
+Running tests on: Windows 98 [Version 4.10.1998]
+Arguments:
+Comments:
+Limits from: access,mysql
+Server version: Access 2000
+
+alter-table: Total time: 8 wallclock secs ( 8.02 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+ATIS: Total time: 241 wallclock secs (241.02 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+big-tables: Total time: 457 wallclock secs (457.69 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+connect: Total time: 5012 wallclock secs (5011.52 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+create: Total time: 699 wallclock secs (698.76 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+insert: Estimated total time: 39293 wallclock secs (39294.15 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+select: Estimated total time: 1710 wallclock secs (1710.98 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+wisconsin: Total time: 282 wallclock secs (281.60 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+All 8 test executed successfully
+Tests with estimated time have a + at end of line
+Tests with didn't return the correct result have a ? at end of line
+
+Totals per operation:
+Operation seconds usr sys cpu tests
+alter_table_add 1 1.15 0.00 0.00 247
+alter_table_drop 1 0.71 0.00 0.00 124
+connect 1267 1267.63 0.00 0.00 10000
+connect+select_1_row 1780 1779.92 0.00 0.00 10000 ?
+connect+select_simpl 1766 1765.08 0.00 0.00 10000
+count 328 327.46 0.00 0.00 100
+count_on_key 460 460.61 0.00 0.00 50100
+create+drop 187 186.36 0.00 0.00 7000
+create_index 0 0.11 0.00 0.00 8
+create_key+drop 207 207.73 0.00 0.00 7000
+create_many_tables 142 141.43 0.00 0.00 7000
+create_table 2 0.67 0.00 0.00 31
+delete_big 276 275.57 0.00 0.00 13
+delete_big_many_keys 12569 12568.66 0.00 0.00 2
+delete_key 79 79.31 0.00 0.00 500
+drop_index 0 0.06 0.00 0.00 8
+drop_table 109 109.79 0.00 0.00 7028
+insert 2347 2347.51 0.00 0.00 350768
+insert_duplicates 209 208.61 0.00 0.00 300000
+insert_key 10591 10591.45 0.00 0.00 100000
+insert_many_fields 124 124.51 0.00 0.00 2000
+min_max 186 186.25 0.00 0.00 60
+min_max_on_key 1148 1148.04 0.00 0.00 73000 +
+order_by 388 388.10 0.00 0.00 10
+order_by_key 396 395.80 0.00 0.00 10
+select_1_row 55 55.04 0.00 0.00 10000
+select_2_rows 56 55.81 0.00 0.00 10000
+select_big 365 364.81 0.00 0.00 10080
+select_diff_key 3 3.63 0.00 0.00 500
+select_distinct 46 46.14 0.00 0.00 800
+select_group 435 436.28 0.00 0.00 9491
+select_join 82 81.89 0.00 0.00 200
+select_key 2064 2064.23 0.00 0.00 200000 +
+select_key_prefix 1674 1673.75 0.00 0.00 200000 +
+select_many_fields 320 319.89 0.00 0.00 2000
+select_range 603 602.54 0.00 0.00 25420
+select_range_prefix 2091 2092.64 0.00 0.00 25010 +
+select_simple 38 38.12 0.00 0.00 10000
+select_simple_join 12 11.59 0.00 0.00 500
+update_big 1550 1550.11 0.00 0.00 500
+update_of_key 887 887.11 0.00 0.00 756
+update_of_key_big 548 548.43 0.00 0.00 501
+update_with_key 2081 2080.30 0.00 0.00 100000
+wisc_benchmark 33 33.17 0.00 0.00 114
+TOTALS 47506 47508.00 0.00 0.00 1540881 ?++++
diff --git a/sql-bench/Results-win32/RUN-db2_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase b/sql-bench/Results-win32/RUN-db2_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
new file mode 100644
index 00000000000..8d429da7866
--- /dev/null
+++ b/sql-bench/Results-win32/RUN-db2_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
@@ -0,0 +1,54 @@
+Benchmark DBD suit: 2.0
+Date of test: 1999-02-02 7:10:24
+Running tests on: Windows NT Version 4.0
+Arguments: --force
+Comments:
+Limits from: db2,informix,ms-sql,mysql,oracle,solid,sybase
+Server version: IBM DB2 5
+
+alter-table: Failed
+ATIS: Total time: 515 secs (514.66 usr 0.00 sys = 514.66 cpu)
+big-tables: Total time: 250 secs (249.43 usr 0.00 sys = 249.43 cpu)
+connect: Failed
+create: Total time: 1106 secs (1106.62 usr 0.00 sys = 1106.62 cpu)
+insert: Estimated total time: 17508 secs (17508.04 usr 0.00 sys = 17508.04 cpu)
+select: Estimated total time: 1934 secs (1934.67 usr 0.00 sys = 1934.67 cpu)
+wisconsin: Total time: 368 secs (367.48 usr 0.00 sys = 367.48 cpu)
+
+Of 8 tests, 2 tests didn't work
+Tests with estimated time have a + at end of line
+
+Totals per operation:
+Operation seconds usr sys cpu tests
+count 87 87.24 0.00 87.24 100
+count_key 753 753.46 0.00 753.46 50000 +
+count_on_key 58 57.98 0.00 57.98 100
+create+drop 408 408.21 0.00 408.21 1000
+create_key+drop 193 192.75 0.00 192.75 1000
+create_table 439 439.52 0.00 439.52 1031
+delete_big 451 450.96 0.00 450.96 15
+delete_key 16 15.97 0.00 15.97 500
+drop_table 107 107.42 0.00 107.42 1028
+insert 3460 3460.94 0.00 3460.94 350768
+insert_duplicates 353 353.39 0.00 353.39 300000
+insert_key 2484 2484.63 0.00 2484.63 100000
+insert_many_fields 135 135.62 0.00 135.62 20000
+min_max 56 55.56 0.00 55.56 60
+min_max_on_key 1631 1631.00 0.00 1631.00 73000 +
+order_by 361 361.08 0.00 361.08 10
+order_by_key 369 368.78 0.00 368.78 10
+select_big 383 382.60 0.00 382.60 80
+select_distinct 82 82.50 0.00 82.50 800
+select_group 184 183.57 0.00 183.57 3191
+select_join 225 224.28 0.00 224.28 200
+select_key 1206 1206.37 0.00 1206.37 200000 +
+select_key_prefix 1199 1199.40 0.00 1199.40 200000 +
+select_many_fields 113 112.90 0.00 112.90 20000
+select_range 2170 2168.69 0.00 2168.69 25400 ++
+select_range_prefix 2150 2151.84 0.00 2151.84 25000 ++
+select_simple_join 26 26.36 0.00 26.36 500
+update_key 5 5.24 0.00 5.24 500
+update_key_big 542 542.23 0.00 542.23 501
+update_of_key 175 174.76 0.00 174.76 256
+wisc_benchmark 32 32.10 0.00 32.10 114
+TOTALS 19853 19857.35 0.00 19857.35 1375164 ++++++++
diff --git a/sql-bench/Results-win32/RUN-informix_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase b/sql-bench/Results-win32/RUN-informix_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
new file mode 100644
index 00000000000..7e8f0efd6e1
--- /dev/null
+++ b/sql-bench/Results-win32/RUN-informix_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
@@ -0,0 +1,60 @@
+Benchmark DBD suit: 2.0
+Date of test: 1998-10-05 15:25:42
+Running tests on: Windows NT Version 4.0
+Arguments: --force
+Comments:
+Limits from: db2,informix,ms-sql,mysql,oracle,solid,sybase
+Server version: Informix 7.30C1
+
+alter-table: Total time: 7 secs ( 6.60 usr 0.00 sys = 6.60 cpu)
+ATIS: Total time: 333 secs (333.33 usr 0.00 sys = 333.33 cpu)
+big-tables: Total time: 285 secs (285.73 usr 0.00 sys = 285.73 cpu)
+connect: Total time: 4225 secs (4225.65 usr 0.00 sys = 4225.65 cpu)
+create: Total time: 222 secs (221.64 usr 0.00 sys = 221.64 cpu)
+insert: Estimated total time: 305853 secs (305711.97 usr 0.00 sys = 305711.97 cpu)
+select: Estimated total time: 8393 secs (8391.74 usr 0.00 sys = 8391.74 cpu)
+wisconsin: Total time: 219 secs (219.03 usr 0.00 sys = 219.03 cpu)
+
+All 8 test executed successfully
+Tests with estimated time have a + at end of line
+
+Totals per operation:
+Operation seconds usr sys cpu tests
+alter_table_add 0 0.39 0.00 0.39 8
+connect 1989 1989.51 0.00 1989.51 10000
+connect+select 2050 2049.47 0.00 2049.47 10000
+count 116 115.85 0.00 115.85 100
+count_key 7825 7824.40 0.00 7824.40 50000 +
+count_on_key 931 930.38 0.00 930.38 100
+create+drop 35 35.34 0.00 35.34 1000
+create_index 1 0.44 0.00 0.44 8
+create_key+drop 90 89.37 0.00 89.37 1000
+create_table 59 58.80 0.00 58.80 1031
+delete_big 11257 11256.92 0.00 11256.92 15
+delete_key 738 737.82 0.00 737.82 500
+drop_index 0 0.10 0.00 0.10 8
+drop_table 33 33.47 0.00 33.47 1028
+insert 2692 2693.19 0.00 2693.19 350768
+insert_duplicates 280 280.34 0.00 280.34 300000
+insert_key 8231 8231.23 0.00 8231.23 100000
+insert_many_fields 111 110.94 0.00 110.94 20000
+min_max 344 344.44 0.00 344.44 60
+min_max_on_key 1083 1083.57 0.00 1083.57 73000 +
+order_by 518 517.79 0.00 517.79 10
+order_by_key 485 485.49 0.00 485.49 10
+select 112 112.36 0.00 112.36 20000
+select_big 580 579.87 0.00 579.87 10080
+select_distinct 97 97.37 0.00 97.37 800
+select_group 963 962.51 0.00 962.51 3191
+select_join 99 98.99 0.00 98.99 200
+select_key 121126 120992.76 0.00 120992.76 200000 +
+select_key_prefix 119960 119942.91 0.00 119942.91 200000 +
+select_many_fields 174 174.64 0.00 174.64 20000
+select_range 7307 7309.74 0.00 7309.74 25400 ++
+select_range_prefix 7448 7449.00 0.00 7449.00 25000 ++
+select_simple_join 22 21.83 0.00 21.83 500
+update_key 771 771.67 0.00 771.67 500
+update_key_big 3000 2999.42 0.00 2999.42 501
+update_of_key 2190 2190.23 0.00 2190.23 256
+wisc_benchmark 45 44.91 0.00 44.91 114
+TOTALS 302762 302617.46 0.00 302617.46 1425188 ++++++++
diff --git a/sql-bench/Results-win32/RUN-ms-sql_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase b/sql-bench/Results-win32/RUN-ms-sql_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
new file mode 100644
index 00000000000..b08b487e1f4
--- /dev/null
+++ b/sql-bench/Results-win32/RUN-ms-sql_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
@@ -0,0 +1,60 @@
+Benchmark DBD suit: 2.0
+Date of test: 1998-09-27 10:54:51
+Running tests on: Windows NT Version 4.0
+Arguments: --force
+Comments:
+Limits from: db2,informix,ms-sql,mysql,oracle,solid,sybase
+Server version: Microsoft SQL Server 7.00 - 7.00.517 (Intel X86)
+
+alter-table: Total time: 7 secs ( 7.50 usr 0.00 sys = 7.50 cpu)
+ATIS: Total time: 231 secs (230.45 usr 0.00 sys = 230.45 cpu)
+big-tables: Total time: 155 secs (154.44 usr 0.00 sys = 154.44 cpu)
+connect: Total time: 535 secs (534.85 usr 0.00 sys = 534.85 cpu)
+create: Total time: 152 secs (151.76 usr 0.00 sys = 151.76 cpu)
+insert: Estimated total time: 15454 secs (15453.34 usr 0.00 sys = 15453.34 cpu)
+select: Estimated total time: 1186 secs (1185.72 usr 0.00 sys = 1185.72 cpu)
+wisconsin: Total time: 290 secs (290.80 usr 0.00 sys = 290.80 cpu)
+
+All 8 test executed successfully
+Tests with estimated time have a + at end of line
+
+Totals per operation:
+Operation seconds usr sys cpu tests
+alter_table_add 0 0.04 0.00 0.04 8
+connect 202 201.91 0.00 201.91 10000
+connect+select 234 234.54 0.00 234.54 10000
+count 49 49.15 0.00 49.15 100
+count_key 763 762.84 0.00 762.84 50000 +
+count_on_key 18 17.22 0.00 17.22 100
+create+drop 35 34.23 0.00 34.23 1000
+create_index 1 0.64 0.00 0.64 8
+create_key+drop 36 36.10 0.00 36.10 1000
+create_table 56 57.17 0.00 57.17 1031
+delete_big 877 877.05 0.00 877.05 15
+delete_key 21 21.33 0.00 21.33 500
+drop_index 0 0.07 0.00 0.07 8
+drop_table 7 6.87 0.00 6.87 1028
+insert 4012 4011.32 0.00 4011.32 350768
+insert_duplicates 286 285.70 0.00 285.70 300000
+insert_key 5181 5181.56 0.00 5181.56 100000
+insert_many_fields 76 75.76 0.00 75.76 20000
+min_max 115 115.58 0.00 115.58 60
+min_max_on_key 333 332.78 0.00 332.78 73000
+order_by 250 250.66 0.00 250.66 10
+order_by_key 201 200.90 0.00 200.90 10
+select 65 64.78 0.00 64.78 20000
+select_big 238 237.78 0.00 237.78 10080
+select_distinct 59 59.65 0.00 59.65 800
+select_group 126 126.06 0.00 126.06 3191
+select_join 66 65.25 0.00 65.25 200
+select_key 1634 1634.55 0.00 1634.55 200000 +
+select_key_prefix 1698 1696.55 0.00 1696.55 200000 +
+select_many_fields 78 78.61 0.00 78.61 20000
+select_range 87 86.24 0.00 86.24 25400
+select_range_prefix 68 69.08 0.00 69.08 25000
+select_simple_join 8 8.30 0.00 8.30 500
+update_key 8 8.00 0.00 8.00 500
+update_key_big 403 402.89 0.00 402.89 501
+update_of_key 674 674.29 0.00 674.29 256
+wisc_benchmark 24 23.97 0.00 23.97 114
+TOTALS 17989 17989.42 0.00 17989.42 1425188 +++
diff --git a/sql-bench/Results-win32/RUN-mysql-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase b/sql-bench/Results-win32/RUN-mysql-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
new file mode 100644
index 00000000000..91a519b208c
--- /dev/null
+++ b/sql-bench/Results-win32/RUN-mysql-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
@@ -0,0 +1,60 @@
+Benchmark DBD suit: 2.0
+Date of test: 1999-03-08 10:55:47
+Running tests on: Windows NT Version 4.0
+Arguments: --force
+Comments:
+Limits from: db2,informix,ms-sql,mysql,oracle,solid,sybase
+Server version: MySQL 3.22.16 gamma
+
+ATIS: Total time: 71 wallclock secs (16.88 usr + 8.22 sys = 25.11 CPU)
+alter-table: Total time: 5 wallclock secs ( 0.19 usr + 0.17 sys = 0.36 CPU)
+big-tables: Total time: 74 wallclock secs (23.40 usr + 8.04 sys = 31.45 CPU)
+connect: Total time: 155 wallclock secs (45.74 usr + 33.56 sys = 79.29 CPU)
+create: Total time: 72 wallclock secs ( 2.05 usr + 0.97 sys = 3.02 CPU)
+insert: Total time: 5368 wallclock secs (568.77 usr + 216.27 sys = 785.04 CPU)
+select: Estimated total time: 899 wallclock secs (90.43 usr + 24.97 sys = 115.41 CPU)
+wisconsin: Total time: 38 wallclock secs ( 7.83 usr + 5.25 sys = 13.08 CPU)
+
+All 8 test executed successfully
+Tests with estimated time have a + at end of line
+
+Totals per operation:
+Operation seconds usr sys cpu tests
+alter_table_add 1 0.01 0.00 0.01 8
+connect 56 16.91 13.01 29.92 10000
+connect+select 64 18.76 14.96 33.72 10000
+count 54 0.06 0.01 0.07 100
+count_key 665 36.67 9.66 46.33 50000 +
+count_on_key 31 0.08 0.04 0.12 100
+create+drop 14 0.40 0.19 0.59 1000
+create_index 2 0.00 0.00 0.00 8
+create_key+drop 18 0.85 0.33 1.18 1000
+create_table 23 0.47 0.19 0.66 1031
+delete_big 678 0.01 0.00 0.01 15
+delete_key 1 0.10 0.08 0.18 500
+drop_index 1 0.00 0.00 0.00 8
+drop_table 3 0.10 0.18 0.28 1028
+insert 381 67.34 48.27 115.61 350768
+insert_duplicates 68 16.34 13.36 29.70 300000
+insert_key 2906 27.77 14.64 42.41 100000
+insert_many_fields 30 7.32 2.84 10.16 20000
+min_max 26 0.06 0.01 0.07 60
+min_max_on_key 220 51.97 14.10 66.07 73000
+order_by 100 40.72 19.97 60.69 10
+order_by_key 73 40.79 20.33 61.12 10
+select 21 3.50 3.78 7.30 20000
+select_big 88 47.93 21.83 69.76 10080
+select_distinct 17 3.22 1.51 4.74 800
+select_group 53 2.23 0.70 2.93 3191
+select_join 31 8.80 4.19 12.99 200
+select_key 367 157.27 40.25 197.51 200000
+select_key_prefix 375 158.15 38.91 197.05 200000
+select_many_fields 44 16.07 5.19 21.28 20000
+select_range 40 13.94 3.73 17.68 25400
+select_range_prefix 34 12.64 3.04 15.68 25000
+select_simple_join 3 1.23 0.50 1.73 500
+update_key 0 0.09 0.05 0.14 500
+update_key_big 26 0.10 0.06 0.16 501
+update_of_key 157 0.04 0.04 0.08 256
+wisc_benchmark 8 3.07 1.29 4.37 114
+TOTALS 6679 755.01 297.24 1052.30 1425188 +
diff --git a/sql-bench/Results-win32/RUN-mysql-win98 b/sql-bench/Results-win32/RUN-mysql-win98
new file mode 100644
index 00000000000..18ff522a929
--- /dev/null
+++ b/sql-bench/Results-win32/RUN-mysql-win98
@@ -0,0 +1,74 @@
+Benchmark DBD suite: 2.7
+Date of test: 2000-03-15 1:51:13
+Running tests on: Windows 98 [Version 4.10.1998]
+Arguments:
+Comments: AMD K6, 400mz, 128M, 16M key_cache
+Limits from:
+Server version: MySQL 3.23.13a alpha
+
+alter-table: Total time: 1855 wallclock secs (1854.89 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+ATIS: Total time: 144 wallclock secs (143.53 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+big-tables: Total time: 151 wallclock secs (150.66 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+connect: Total time: 369 wallclock secs (368.94 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+create: Total time: 5141 wallclock secs (5140.97 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+insert: Estimated total time: 8358 wallclock secs (8356.07 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+select: Total time: 1294 wallclock secs (1293.83 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+wisconsin: Total time: 63 wallclock secs (62.40 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+All 8 test executed successfully
+Tests with estimated time have a + at end of line
+
+Totals per operation:
+Operation seconds usr sys cpu tests
+alter_table_add 1046 1046.38 0.00 0.00 992
+alter_table_drop 773 772.97 0.00 0.00 496
+connect 52 51.85 0.00 0.00 10000
+connect+select_1_row 72 71.95 0.00 0.00 10000
+connect+select_simple 67 66.90 0.00 0.00 10000
+count 55 54.87 0.00 0.00 100
+count_on_key 640 639.71 0.00 0.00 50100
+create+drop 1433 1433.28 0.00 0.00 10000
+create_MANY_tables 1510 1510.83 0.00 0.00 5000
+create_index 17 16.70 0.00 0.00 8
+create_key+drop 1457 1456.57 0.00 0.00 10000
+create_table 8 7.92 0.00 0.00 31
+delete_big 23 22.25 0.00 0.00 13
+delete_big_many_keys 112 112.11 0.00 0.00 2
+delete_key 0 0.82 0.00 0.00 500
+drop_index 17 16.64 0.00 0.00 8
+drop_table 1 0.06 0.00 0.00 28
+drop_table_when_MANY_tables 160 159.83 0.00 0.00 5000
+insert 510 508.11 0.00 0.00 350768
+insert_duplicates 91 91.06 0.00 0.00 300000
+insert_key 364 363.72 0.00 0.00 100000
+insert_many_fields 25 24.71 0.00 0.00 2000
+min_max 33 32.90 0.00 0.00 60
+min_max_on_key 339 339.56 0.00 0.00 73000
+multiple_value_insert 11 11.64 0.00 0.00 100000
+order_by 249 248.87 0.00 0.00 10
+order_by_key 175 174.66 0.00 0.00 10
+outer_join 146 145.66 0.00 0.00 10
+outer_join_found 144 144.40 0.00 0.00 10
+outer_join_not_found 606 605.55 0.00 0.00 500 +
+outer_join_on_key 63 63.33 0.00 0.00 10
+select_1_row 16 15.99 0.00 0.00 10000
+select_2_rows 19 18.89 0.00 0.00 10000
+select_big 304 306.16 0.00 0.00 10080
+select_diff_key 241 240.63 0.00 0.00 500
+select_distinct 33 33.34 0.00 0.00 800
+select_group 91 91.83 0.00 0.00 2911
+select_group_when_MANY_tables 581 580.46 0.00 0.00 5000
+select_join 51 50.15 0.00 0.00 200
+select_key 540 540.35 0.00 0.00 200000
+select_key_prefix 542 542.23 0.00 0.00 200000
+select_many_fields 124 124.24 0.00 0.00 2000
+select_range 423 423.21 0.00 0.00 25420
+select_range_prefix 66 66.62 0.00 0.00 25010
+select_simple 12 12.20 0.00 0.00 10000
+select_simple_join 7 7.47 0.00 0.00 500
+update_big 84 83.33 0.00 0.00 500
+update_of_key 59 59.21 0.00 0.00 756
+update_of_key_big 38 38.07 0.00 0.00 501
+update_with_key 432 432.20 0.00 0.00 100000
+wisc_benchmark 17 17.08 0.00 0.00 114
+TOTALS 13879 13879.47 0.00 0.00 1642948 +
diff --git a/sql-bench/Results-win32/RUN-mysql-win98-cmp-access,mysql b/sql-bench/Results-win32/RUN-mysql-win98-cmp-access,mysql
new file mode 100644
index 00000000000..a6858c2b2fa
--- /dev/null
+++ b/sql-bench/Results-win32/RUN-mysql-win98-cmp-access,mysql
@@ -0,0 +1,67 @@
+Benchmark DBD suite: 2.5
+Date of test: 2000-01-05 11:04:50
+Running tests on: Windows 98 [Version 4.10.1998]
+Arguments:
+Comments: key_buffer=16M
+Limits from: access,mysql
+Server version: MySQL 3.23.8 alpha
+
+alter-table: Total time: 57 wallclock secs (57.17 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+ATIS: Total time: 134 wallclock secs (134.84 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+big-tables: Total time: 51 wallclock secs (50.91 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+connect: Total time: 276 wallclock secs (275.78 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+create: Total time: 9601 wallclock secs (9600.98 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+insert: Estimated total time: 4315 wallclock secs (4316.21 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+select: Estimated total time: 1053 wallclock secs (1053.14 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+wisconsin: Total time: 68 wallclock secs (68.32 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+All 8 test executed successfully
+Tests with estimated time have a + at end of line
+
+Totals per operation:
+Operation seconds usr sys cpu tests
+alter_table_add 31 30.48 0.00 0.00 247
+alter_table_drop 21 21.25 0.00 0.00 124
+connect 55 54.76 0.00 0.00 10000
+connect+select_1_row 75 75.96 0.00 0.00 10000
+connect+select_simpl 71 70.80 0.00 0.00 10000
+count 58 57.94 0.00 0.00 100
+count_on_key 697 697.45 0.00 0.00 50100 +
+create+drop 1011 1011.13 0.00 0.00 7000
+create_index 2 2.09 0.00 0.00 8
+create_key+drop 1025 1025.23 0.00 0.00 7000
+create_many_tables 2530 2529.76 0.00 0.00 7000
+create_table 0 0.33 0.00 0.00 31
+delete_big 28 26.81 0.00 0.00 13
+delete_big_many_keys 102 102.60 0.00 0.00 2
+delete_key 1 0.93 0.00 0.00 500
+drop_index 2 1.98 0.00 0.00 8
+drop_table 316 315.72 0.00 0.00 7028
+insert 569 569.79 0.00 0.00 350768
+insert_duplicates 107 106.89 0.00 0.00 300000
+insert_key 367 367.34 0.00 0.00 100000
+insert_many_fields 8 7.91 0.00 0.00 2000
+min_max 34 33.78 0.00 0.00 60
+min_max_on_key 360 360.20 0.00 0.00 73000
+order_by 282 281.88 0.00 0.00 10
+order_by_key 192 192.79 0.00 0.00 10
+select_1_row 18 17.30 0.00 0.00 10000
+select_2_rows 20 20.65 0.00 0.00 10000
+select_big 216 216.01 0.00 0.00 10080
+select_diff_key 264 263.97 0.00 0.00 500
+select_distinct 36 36.52 0.00 0.00 800
+select_group 4781 4780.38 0.00 0.00 9191
+select_join 51 51.25 0.00 0.00 200
+select_key 635 635.54 0.00 0.00 200000 +
+select_key_prefix 639 638.34 0.00 0.00 200000 +
+select_many_fields 43 42.89 0.00 0.00 2000
+select_range 113 113.04 0.00 0.00 25420
+select_range_prefix 76 76.23 0.00 0.00 25010
+select_simple 13 13.45 0.00 0.00 10000
+select_simple_join 9 8.35 0.00 0.00 500
+update_big 96 96.78 0.00 0.00 500
+update_of_key 54 54.00 0.00 0.00 756
+update_of_key_big 40 39.93 0.00 0.00 501
+update_with_key 485 484.77 0.00 0.00 100000
+wisc_benchmark 18 18.67 0.00 0.00 114
+TOTALS 15551 15553.87 0.00 0.00 1540581 +++
diff --git a/sql-bench/Results-win32/RUN-mysql_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase b/sql-bench/Results-win32/RUN-mysql_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
new file mode 100644
index 00000000000..4eea1681670
--- /dev/null
+++ b/sql-bench/Results-win32/RUN-mysql_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
@@ -0,0 +1,60 @@
+Benchmark DBD suit: 2.0
+Date of test: 1999-02-07 11:41:07
+Running tests on: Windows NT Version 4.0
+Arguments: --force
+Comments:
+Limits from: db2,informix,ms-sql,mysql,oracle,solid,sybase
+Server version: MySQL 3.22.16 gamma
+
+alter-table: Total time: 4 secs ( 4.33 usr 0.00 sys = 4.33 cpu)
+ATIS: Total time: 168 secs (167.31 usr 0.00 sys = 167.31 cpu)
+big-tables: Total time: 100 secs (100.14 usr 0.00 sys = 100.14 cpu)
+connect: Total time: 459 secs (458.81 usr 0.00 sys = 458.81 cpu)
+create: Total time: 78 secs (78.59 usr 0.00 sys = 78.59 cpu)
+insert: Total time: 6744 secs (6743.40 usr 0.00 sys = 6743.40 cpu)
+select: Estimated total time: 1003 secs (1003.10 usr 0.00 sys = 1003.10 cpu)
+wisconsin: Total time: 74 secs (74.07 usr 0.00 sys = 74.07 cpu)
+
+All 8 test executed successfully
+Tests with estimated time have a + at end of line
+
+Totals per operation:
+Operation seconds usr sys cpu tests
+alter_table_add 1 0.61 0.00 0.61 8
+connect 189 188.69 0.00 188.69 10000
+connect+select 211 211.59 0.00 211.59 10000
+count 58 58.27 0.00 58.27 100
+count_key 709 709.52 0.00 709.52 50000 +
+count_on_key 34 33.86 0.00 33.86 100
+create+drop 15 15.21 0.00 15.21 1000
+create_index 1 0.91 0.00 0.91 8
+create_key+drop 20 20.05 0.00 20.05 1000
+create_table 23 22.06 0.00 22.06 1031
+delete_big 681 680.82 0.00 680.82 15
+delete_key 2 1.83 0.00 1.83 500
+drop_index 1 1.11 0.00 1.11 8
+drop_table 4 3.80 0.00 3.80 1028
+insert 619 619.49 0.00 619.49 350768
+insert_duplicates 144 143.90 0.00 143.90 300000
+insert_key 2908 2907.97 0.00 2907.97 100000
+insert_many_fields 40 40.29 0.00 40.29 20000
+min_max 28 28.04 0.00 28.04 60
+min_max_on_key 268 267.73 0.00 267.73 73000
+order_by 382 381.52 0.00 381.52 10
+order_by_key 355 355.39 0.00 355.39 10
+select 39 38.76 0.00 38.76 20000
+select_big 377 376.50 0.00 376.50 10080
+select_distinct 35 35.07 0.00 35.07 800
+select_group 61 61.91 0.00 61.91 3191
+select_join 91 90.99 0.00 90.99 200
+select_key 464 463.54 0.00 463.54 200000
+select_key_prefix 470 470.56 0.00 470.56 200000
+select_many_fields 60 59.85 0.00 59.85 20000
+select_range 62 61.89 0.00 61.89 25400
+select_range_prefix 51 50.65 0.00 50.65 25000
+select_simple_join 10 9.62 0.00 9.62 500
+update_key 1 0.95 0.00 0.95 500
+update_key_big 26 26.35 0.00 26.35 501
+update_of_key 164 163.52 0.00 163.52 256
+wisc_benchmark 23 23.44 0.00 23.44 114
+TOTALS 8627 8626.26 0.00 8626.26 1425188 +
diff --git a/sql-bench/Results-win32/RUN-oracle_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase b/sql-bench/Results-win32/RUN-oracle_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
new file mode 100644
index 00000000000..db88db47926
--- /dev/null
+++ b/sql-bench/Results-win32/RUN-oracle_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
@@ -0,0 +1,59 @@
+Benchmark DBD suite: 2.0b
+Date of test: 1999-04-03 22:29:52
+Running tests on: Windows NT Version 4.0
+Arguments: --force
+Comments:
+Limits from: db2,informix,ms-sql,mysql,oracle,solid,sybase
+Server version: Oracle 8.0.4.0.0
+
+ATIS: Total time: 486 wallclock secs (185.81 usr 33.07 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+alter-table: Total time: 8 wallclock secs ( 1.15 usr 0.10 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+big-tables: Total time: 246 wallclock secs (93.94 usr 13.29 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+connect: Total time: 17520 wallclock secs (504.84 usr 806.71 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+create: Total time: 947 wallclock secs (15.04 usr 1.62 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+insert: Estimated total time: 114468 wallclock secs (3850.94 usr 602.34 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+select: Estimated total time: 2147 wallclock secs (304.96 usr 63.03 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+wisconsin: Total time: 335 wallclock secs (86.43 usr 10.31 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+All 8 test executed successfully
+Tests with estimated time have a + at end of line
+
+Totals per operation:
+Operation seconds usr sys cpu tests
+alter_table_add 1 0.00 0.00 0.00 8
+connect 8713 195.47 436.40 0.00 10000
+connect+select 8722 257.48 362.71 0.00 10000
+count 51 0.30 0.04 0.00 100
+count_on_key 869 118.48 25.29 0.00 50100 +
+create+drop 288 4.23 0.58 0.00 1000
+create_index 0 0.00 0.00 0.00 8
+create_key+drop 411 4.65 0.38 0.00 1000
+create_table 135 3.45 0.41 0.00 1031
+delete_big 784 0.09 0.18 0.00 15
+delete_key 628 0.70 0.16 0.00 500
+drop_index 1 0.01 0.02 0.00 8
+drop_table 112 1.34 0.17 0.00 1028
+insert 2924 493.77 58.70 0.00 350768
+insert_duplicates 353 195.15 26.95 0.00 300000
+insert_key 1293 151.81 16.58 0.00 100000
+insert_many_fields 150 29.55 3.33 0.00 20000
+min_max 25 0.22 0.03 0.00 60
+min_max_on_key 1181 165.25 35.39 0.00 73000 +
+order_by 1098 570.85 95.67 0.00 10 +
+order_by_key 1125 580.64 95.55 0.00 10 +
+select 47 30.58 2.91 0.00 20000
+select_big 1174 599.95 105.18 0.00 10080
+select_distinct 79 37.62 6.46 0.00 800
+select_group 82 11.18 2.22 0.00 3191
+select_join 255 112.16 20.68 0.00 200
+select_key 86849 639.74 105.64 0.00 200000 +
+select_key_prefix 1037 576.33 93.13 0.00 200000 +
+select_many_fields 96 64.39 9.96 0.00 20000
+select_range 8072 36.50 5.27 0.00 25400 ++
+select_range_prefix 95 58.76 8.18 0.00 25000
+select_simple_join 28 13.20 2.31 0.00 500
+update_key 220 0.76 0.07 0.00 500
+update_key_big 429 0.83 0.20 0.00 501
+update_of_key 568 0.30 0.06 0.00 256
+wisc_benchmark 82 44.61 5.10 0.00 114
+TOTALS 127977 5000.35 1525.91 0.00 1425188 ++++++++
diff --git a/sql-bench/Results-win32/RUN-solid_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase b/sql-bench/Results-win32/RUN-solid_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
new file mode 100644
index 00000000000..766942e7db3
--- /dev/null
+++ b/sql-bench/Results-win32/RUN-solid_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
@@ -0,0 +1,60 @@
+Benchmark DBD suit: 2.0
+Date of test: 1998-10-23 9:11:16
+Running tests on: Windows NT Version 4.0
+Arguments: --force
+Comments:
+Limits from: db2,informix,ms-sql,mysql,oracle,solid,sybase
+Server version: Solid version ???
+
+alter-table: Total time: 7 secs ( 6.71 usr 0.00 sys = 6.71 cpu)
+ATIS: Estimated total time: 1248 secs (1248.81 usr 0.00 sys = 1248.81 cpu)
+big-tables: Total time: 107 secs (107.11 usr 0.00 sys = 107.11 cpu)
+connect: Total time: 871 secs (871.19 usr 0.00 sys = 871.19 cpu)
+create: Total time: 161 secs (160.95 usr 0.00 sys = 160.95 cpu)
+insert: Estimated total time: 192155 secs (192149.60 usr 0.00 sys = 192149.60 cpu)
+select: Estimated total time: 28523 secs (28507.76 usr 0.00 sys = 28507.76 cpu)
+wisconsin: Total time: 338 secs (338.33 usr 0.00 sys = 338.33 cpu)
+
+All 8 test executed successfully
+Tests with estimated time have a + at end of line
+
+Totals per operation:
+Operation seconds usr sys cpu tests
+alter_table_add 0 0.07 0.00 0.07 8
+connect 385 385.29 0.00 385.29 10000
+connect+select 414 413.81 0.00 413.81 10000
+count 2221 2220.87 0.00 2220.87 100
+count_key 16862 16847.20 0.00 16847.20 50000 +
+count_on_key 2139 2139.16 0.00 2139.16 100
+create+drop 41 41.20 0.00 41.20 1000
+create_index 1 1.06 0.00 1.06 8
+create_key+drop 72 72.18 0.00 72.18 1000
+create_table 24 23.35 0.00 23.35 1031
+delete_big 2236 2235.76 0.00 2235.76 15
+delete_key 65 65.34 0.00 65.34 500
+drop_index 1 0.97 0.00 0.97 8
+drop_table 20 19.66 0.00 19.66 1028
+insert 1801 1801.89 0.00 1801.89 350768
+insert_duplicates 172 172.25 0.00 172.25 300000
+insert_key 9758 9757.93 0.00 9757.93 100000
+insert_many_fields 49 48.44 0.00 48.44 20000
+min_max 36388 36350.61 0.00 36350.61 3000 +
+min_max_on_key 11504 11503.86 0.00 11503.86 73000 +
+order_by 648 647.94 0.00 647.94 10
+order_by_key 653 653.06 0.00 653.06 10
+select 47 47.32 0.00 47.32 20000
+select_big 619 618.61 0.00 618.61 10080
+select_distinct 327 327.14 0.00 327.14 800
+select_group 2608 2608.20 0.00 2608.20 3191
+select_join 698 698.11 0.00 698.11 200 +
+select_key 877 877.85 0.00 877.85 200000 +
+select_key_prefix 843 842.99 0.00 842.99 200000 +
+select_many_fields 56 56.39 0.00 56.39 20000
+select_range 22763 22774.06 0.00 22774.06 25400 ++
+select_range_prefix 22548 22532.98 0.00 22532.98 25000 ++
+select_simple_join 69 69.48 0.00 69.48 500
+update_key 2 2.71 0.00 2.71 500
+update_key_big 994 993.63 0.00 993.63 501
+update_of_key 16656 16655.63 0.00 16655.63 256
+wisc_benchmark 84 83.66 0.00 83.66 114
+TOTALS 154645 154590.66 0.00 154590.66 1428128 ++++++++++
diff --git a/sql-bench/Results-win32/RUN-sybase_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase b/sql-bench/Results-win32/RUN-sybase_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
new file mode 100644
index 00000000000..4cf61ed860d
--- /dev/null
+++ b/sql-bench/Results-win32/RUN-sybase_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
@@ -0,0 +1,58 @@
+Benchmark DBD suite: 2.0
+Date of test: 1998-10-02 8:13:24
+Running tests on: Windows NT Version 4.0
+Arguments: --force
+Comments:
+Limits from: db2,informix,ms-sql,mysql,oracle,solid,sybase
+Server version: Sybase enterprise 11.5 NT
+
+ATIS: Total time: 338 secs (337.94 usr 0.00 sys = 337.94 cpu)
+alter-table: Total time: 12 secs (12.39 usr 0.00 sys = 12.39 cpu)
+big-tables: Total time: 353 secs (352.68 usr 0.00 sys = 352.68 cpu)
+connect: Total time: 2725 secs (2724.61 usr 0.00 sys = 2724.61 cpu)
+create: Total time: 228 secs (228.22 usr 0.00 sys = 228.22 cpu)
+insert: Estimated total time: 69907 secs (69908.40 usr 0.00 sys = 69908.40 cpu)
+select: Failed (results-win32/select-sybase_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase)
+wisconsin: Failed (results-win32/wisconsin-sybase_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase)
+
+Of 8 tests, 2 tests didn't work
+Tests with estimated time have a + at end of line
+
+Totals per operation:
+Operation seconds usr sys cpu tests
+alter_table_add 1 0.14 0.00 0.14 8
+connect 1275 1274.97 0.00 1274.97 10000
+connect+select 1330 1329.69 0.00 1329.69 10000
+count 23 22.40 0.00 22.40 100
+count_on_key 14 14.21 0.00 14.21 100
+create+drop 63 63.53 0.00 63.53 1000
+create_index 0 0.41 0.00 0.41 8
+create_key+drop 52 51.41 0.00 51.41 1000
+create_table 82 81.78 0.00 81.78 1028
+delete_big 7917 7916.71 0.00 7916.71 14
+delete_key 43 42.44 0.00 42.44 500
+drop_index 0 0.07 0.00 0.07 8
+drop_table 19 18.94 0.00 18.94 1028
+insert 4802 4801.96 0.00 4801.96 309768
+insert_duplicates 331 331.28 0.00 331.28 300000
+insert_key 7053 7053.03 0.00 7053.03 100000
+insert_many_fields 231 230.56 0.00 230.56 20000
+min_max 17 16.74 0.00 16.74 60
+min_max_on_key 96 96.64 0.00 96.64 3000
+order_by 395 394.89 0.00 394.89 10
+order_by_key 273 272.97 0.00 272.97 10
+select 80 79.97 0.00 79.97 20000
+select_big 315 314.76 0.00 314.76 10010
+select_distinct 64 63.34 0.00 63.34 800
+select_group 91 91.13 0.00 91.13 3191
+select_join 114 114.63 0.00 114.63 200
+select_key 17614 17614.13 0.00 17614.13 200000 +
+select_key_prefix 17410 17410.02 0.00 17410.02 200000 +
+select_many_fields 122 122.05 0.00 122.05 20000
+select_range 2626 2624.11 0.00 2624.11 25000 ++
+select_range_prefix 2618 2620.08 0.00 2620.08 25000 ++
+select_simple_join 17 16.86 0.00 16.86 500
+update_key 40 39.90 0.00 39.90 500
+update_key_big 347 347.05 0.00 347.05 501
+update_of_key 1023 1022.68 0.00 1022.68 256
+TOTALS 66498 66495.48 0.00 66495.48 1263600 ++++++
diff --git a/sql-bench/Results-win32/alter-table-access_odbc-win98-cmp-access,mysql b/sql-bench/Results-win32/alter-table-access_odbc-win98-cmp-access,mysql
new file mode 100644
index 00000000000..e3aef89c461
--- /dev/null
+++ b/sql-bench/Results-win32/alter-table-access_odbc-win98-cmp-access,mysql
@@ -0,0 +1,16 @@
+Testing server 'Access 2000' at 2000-01-03 3:59:28
+
+Testing of ALTER TABLE
+Testing with 255 columns and 1000 rows in 20 steps
+Insert data into the table
+Time for insert (1000) 6 wallclock secs ( 5.93 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Time for alter_table_add (247): 1 wallclock secs ( 1.15 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Time for create_index (8): 0 wallclock secs ( 0.11 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Time for drop_index (8): 0 wallclock secs ( 0.06 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Time for alter_table_drop (124): 1 wallclock secs ( 0.71 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Total time: 8 wallclock secs ( 8.02 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results-win32/alter-table-db2_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase b/sql-bench/Results-win32/alter-table-db2_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
new file mode 100644
index 00000000000..8ed8d259e13
--- /dev/null
+++ b/sql-bench/Results-win32/alter-table-db2_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
@@ -0,0 +1,10 @@
+Testing server 'IBM DB2 5' at 1998-11-21 23:08:51
+
+Testing of ALTER TABLE
+Testing with 16 columns and 1000 rows in 20 steps
+Insert data into the table
+Time for insert (1000)10 secs (10.26 usr 0.00 sys = 10.26 cpu)
+
+Time for alter_table_add (8): 0 secs ( 0.20 usr 0.00 sys = 0.20 cpu)
+
+Time for create_index (8): 1 secs ( 0.91 usr 0.00 sys = 0.91 cpu)
diff --git a/sql-bench/Results-win32/alter-table-informix_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase b/sql-bench/Results-win32/alter-table-informix_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
new file mode 100644
index 00000000000..cad6c802af6
--- /dev/null
+++ b/sql-bench/Results-win32/alter-table-informix_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
@@ -0,0 +1,14 @@
+Testing server 'Informix 7.30C1 ' at 1998-09-01 2:00:29
+
+Testing of ALTER TABLE
+Testing with 16 columns and 1000 rows in 20 steps
+Insert data into the table
+Time for insert (1000) 6 secs ( 5.53 usr 0.00 sys = 5.53 cpu)
+
+Time for alter_table_add (8): 0 secs ( 0.39 usr 0.00 sys = 0.39 cpu)
+
+Time for create_index (8): 1 secs ( 0.44 usr 0.00 sys = 0.44 cpu)
+
+Time for drop_index (8): 0 secs ( 0.10 usr 0.00 sys = 0.10 cpu)
+
+Total time: 7 secs ( 6.60 usr 0.00 sys = 6.60 cpu)
diff --git a/sql-bench/Results-win32/alter-table-ms-sql_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase b/sql-bench/Results-win32/alter-table-ms-sql_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
new file mode 100644
index 00000000000..7c2495ffe54
--- /dev/null
+++ b/sql-bench/Results-win32/alter-table-ms-sql_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
@@ -0,0 +1,14 @@
+Testing server 'Microsoft SQL Server 7.00 - 7.00.517 (Intel X86) ' at 1998-09-07 2:15:14
+
+Testing of ALTER TABLE
+Testing with 16 columns and 1000 rows in 20 steps
+Insert data into the table
+Time for insert (1000) 6 secs ( 6.49 usr 0.00 sys = 6.49 cpu)
+
+Time for alter_table_add (8): 0 secs ( 0.04 usr 0.00 sys = 0.04 cpu)
+
+Time for create_index (8): 1 secs ( 0.64 usr 0.00 sys = 0.64 cpu)
+
+Time for drop_index (8): 0 secs ( 0.07 usr 0.00 sys = 0.07 cpu)
+
+Total time: 7 secs ( 7.50 usr 0.00 sys = 7.50 cpu)
diff --git a/sql-bench/Results-win32/alter-table-mysql-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase b/sql-bench/Results-win32/alter-table-mysql-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
new file mode 100644
index 00000000000..a3d6284dd67
--- /dev/null
+++ b/sql-bench/Results-win32/alter-table-mysql-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
@@ -0,0 +1,14 @@
+Testing server 'MySQL 3.22.16 gamma' at 1999-02-20 19:54:12
+
+Testing of ALTER TABLE
+Testing with 16 columns and 1000 rows in 20 steps
+Insert data into the table
+Time for insert (1000) 1 wallclock secs ( 0.18 usr + 0.17 sys = 0.35 CPU)
+
+Time for alter_table_add (8): 1 wallclock secs ( 0.01 usr + 0.00 sys = 0.01 CPU)
+
+Time for create_index (8): 2 wallclock secs ( 0.00 usr + 0.00 sys = 0.00 CPU)
+
+Time for drop_index (8): 1 wallclock secs ( 0.00 usr + 0.00 sys = 0.00 CPU)
+
+Total time: 5 wallclock secs ( 0.19 usr + 0.17 sys = 0.36 CPU)
diff --git a/sql-bench/Results-win32/alter-table-mysql-win98 b/sql-bench/Results-win32/alter-table-mysql-win98
new file mode 100644
index 00000000000..922aa8906a9
--- /dev/null
+++ b/sql-bench/Results-win32/alter-table-mysql-win98
@@ -0,0 +1,16 @@
+Testing server 'MySQL 3.23.13a alpha' at 2000-03-15 1:51:14
+
+Testing of ALTER TABLE
+Testing with 1000 columns and 1000 rows in 20 steps
+Insert data into the table
+Time for insert (1000) 1 wallclock secs ( 1.09 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Time for alter_table_add (992): 1046 wallclock secs (1046.38 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Time for create_index (8): 17 wallclock secs (16.70 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Time for drop_index (8): 17 wallclock secs (16.64 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Time for alter_table_drop (496): 773 wallclock secs (772.97 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Total time: 1855 wallclock secs (1854.89 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results-win32/alter-table-mysql-win98-cmp-access,mysql b/sql-bench/Results-win32/alter-table-mysql-win98-cmp-access,mysql
new file mode 100644
index 00000000000..fcb94e46b89
--- /dev/null
+++ b/sql-bench/Results-win32/alter-table-mysql-win98-cmp-access,mysql
@@ -0,0 +1,16 @@
+Testing server 'MySQL 3.23.8 alpha' at 2000-01-04 20:05:06
+
+Testing of ALTER TABLE
+Testing with 255 columns and 1000 rows in 20 steps
+Insert data into the table
+Time for insert (1000) 1 wallclock secs ( 1.21 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Time for alter_table_add (247): 31 wallclock secs (30.48 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Time for create_index (8): 2 wallclock secs ( 2.09 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Time for drop_index (8): 2 wallclock secs ( 1.98 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Time for alter_table_drop (124): 21 wallclock secs (21.25 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Total time: 57 wallclock secs (57.17 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results-win32/alter-table-mysql_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase b/sql-bench/Results-win32/alter-table-mysql_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
new file mode 100644
index 00000000000..f05586245dd
--- /dev/null
+++ b/sql-bench/Results-win32/alter-table-mysql_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
@@ -0,0 +1,14 @@
+Testing server 'MySQL 3.22.16 gamma' at 1999-02-07 11:41:08
+
+Testing of ALTER TABLE
+Testing with 16 columns and 1000 rows in 20 steps
+Insert data into the table
+Time for insert (1000) 1 secs ( 1.66 usr 0.00 sys = 1.66 cpu)
+
+Time for alter_table_add (8): 1 secs ( 0.61 usr 0.00 sys = 0.61 cpu)
+
+Time for create_index (8): 1 secs ( 0.91 usr 0.00 sys = 0.91 cpu)
+
+Time for drop_index (8): 1 secs ( 1.11 usr 0.00 sys = 1.11 cpu)
+
+Total time: 4 secs ( 4.33 usr 0.00 sys = 4.33 cpu)
diff --git a/sql-bench/Results-win32/alter-table-oracle_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase b/sql-bench/Results-win32/alter-table-oracle_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
new file mode 100644
index 00000000000..216c20f0245
--- /dev/null
+++ b/sql-bench/Results-win32/alter-table-oracle_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
@@ -0,0 +1,14 @@
+Testing server 'Oracle 8.0.4.0.0' at 1999-04-03 22:38:03
+
+Testing of ALTER TABLE
+Testing with 16 columns and 1000 rows in 20 steps
+Insert data into the table
+Time for insert (1000) 6 wallclock secs ( 1.14 usr 0.08 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Time for alter_table_add (8): 1 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Time for create_index (8): 0 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Time for drop_index (8): 1 wallclock secs ( 0.01 usr 0.02 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Total time: 8 wallclock secs ( 1.15 usr 0.10 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results-win32/alter-table-solid_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase b/sql-bench/Results-win32/alter-table-solid_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
new file mode 100644
index 00000000000..4058a2aa8cf
--- /dev/null
+++ b/sql-bench/Results-win32/alter-table-solid_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
@@ -0,0 +1,14 @@
+Testing server 'Solid version ???' at 1998-10-06 17:43:33
+
+Testing of ALTER TABLE
+Testing with 16 columns and 1000 rows in 20 steps
+Insert data into the table
+Time for insert (1000) 5 secs ( 4.42 usr 0.00 sys = 4.42 cpu)
+
+Time for alter_table_add (8): 0 secs ( 0.07 usr 0.00 sys = 0.07 cpu)
+
+Time for create_index (8): 1 secs ( 1.06 usr 0.00 sys = 1.06 cpu)
+
+Time for drop_index (8): 1 secs ( 0.97 usr 0.00 sys = 0.97 cpu)
+
+Total time: 7 secs ( 6.71 usr 0.00 sys = 6.71 cpu)
diff --git a/sql-bench/Results-win32/alter-table-sybase_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase b/sql-bench/Results-win32/alter-table-sybase_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
new file mode 100644
index 00000000000..98d44441908
--- /dev/null
+++ b/sql-bench/Results-win32/alter-table-sybase_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
@@ -0,0 +1,14 @@
+Testing server 'Sybase enterprise 11.5 NT' at 1998-08-27 2:08:17
+
+Testing of ALTER TABLE
+Testing with 16 columns and 1000 rows in 20 steps
+Insert data into the table
+Time for insert (1000)11 secs (11.30 usr 0.00 sys = 11.30 cpu)
+
+Time for alter_table_add (8): 1 secs ( 0.14 usr 0.00 sys = 0.14 cpu)
+
+Time for create_index (8): 0 secs ( 0.41 usr 0.00 sys = 0.41 cpu)
+
+Time for drop_index (8): 0 secs ( 0.07 usr 0.00 sys = 0.07 cpu)
+
+Total time: 12 secs (12.39 usr 0.00 sys = 12.39 cpu)
diff --git a/sql-bench/Results-win32/big-tables-access_odbc-win98-cmp-access,mysql b/sql-bench/Results-win32/big-tables-access_odbc-win98-cmp-access,mysql
new file mode 100644
index 00000000000..a37d1050f43
--- /dev/null
+++ b/sql-bench/Results-win32/big-tables-access_odbc-win98-cmp-access,mysql
@@ -0,0 +1,19 @@
+Testing server 'Access 2000' at 2000-01-03 4:03:38
+
+Testing of some unusual tables
+All tests are done 1000 times with 255 fields
+
+Testing table with 255 fields
+Testing select * from table with 1 record
+Time to select_many_fields(1000): 126 wallclock secs (125.72 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing select all_fields from table with 1 record
+Time to select_many_fields(1000): 194 wallclock secs (194.17 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing insert VALUES()
+Time to insert_many_fields(1000): 42 wallclock secs (42.34 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing insert (all_fields) VALUES()
+Time to insert_many_fields(1000): 82 wallclock secs (82.17 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Total time: 457 wallclock secs (457.69 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results-win32/big-tables-db2_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase b/sql-bench/Results-win32/big-tables-db2_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
new file mode 100644
index 00000000000..82183d9221d
--- /dev/null
+++ b/sql-bench/Results-win32/big-tables-db2_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
@@ -0,0 +1,19 @@
+Testing server 'IBM DB2 5' at 1998-11-21 23:18:02
+
+Testing of some unusual tables
+All tests are done 10000 times with 16 fields
+
+Testing table with 16 fields
+Testing select * from table with 1 record
+Time to select_many_fields(10000): 56 secs (56.08 usr 0.00 sys = 56.08 cpu)
+
+Testing select all_fields from table with 1 record
+Time to select_many_fields(10000): 57 secs (56.82 usr 0.00 sys = 56.82 cpu)
+
+Testing insert VALUES()
+Time to insert_many_fields(10000): 67 secs (67.80 usr 0.00 sys = 67.80 cpu)
+
+Testing insert (all_fields) VALUES()
+Time to insert_many_fields(10000): 68 secs (67.82 usr 0.00 sys = 67.82 cpu)
+
+Total time: 250 secs (249.43 usr 0.00 sys = 249.43 cpu)
diff --git a/sql-bench/Results-win32/big-tables-informix_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase b/sql-bench/Results-win32/big-tables-informix_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
new file mode 100644
index 00000000000..5bfdaf2ad6f
--- /dev/null
+++ b/sql-bench/Results-win32/big-tables-informix_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
@@ -0,0 +1,19 @@
+Testing server 'Informix 7.30C1 ' at 1998-09-01 2:06:11
+
+Testing of some unusual tables
+All tests are done 10000 times with 16 fields
+
+Testing table with 16 fields
+Testing select * from table with 1 record
+Time to select_many_fields(10000): 83 secs (83.28 usr 0.00 sys = 83.28 cpu)
+
+Testing select all_fields from table with 1 record
+Time to select_many_fields(10000): 91 secs (91.36 usr 0.00 sys = 91.36 cpu)
+
+Testing insert VALUES()
+Time to insert_many_fields(10000): 54 secs (53.26 usr 0.00 sys = 53.26 cpu)
+
+Testing insert (all_fields) VALUES()
+Time to insert_many_fields(10000): 57 secs (57.68 usr 0.00 sys = 57.68 cpu)
+
+Total time: 285 secs (285.73 usr 0.00 sys = 285.73 cpu)
diff --git a/sql-bench/Results-win32/big-tables-ms-sql_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase b/sql-bench/Results-win32/big-tables-ms-sql_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
new file mode 100644
index 00000000000..4089de66c75
--- /dev/null
+++ b/sql-bench/Results-win32/big-tables-ms-sql_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
@@ -0,0 +1,19 @@
+Testing server 'Microsoft SQL Server 7.00 - 7.00.517 (Intel X86) ' at 1998-09-07 2:19:13
+
+Testing of some unusual tables
+All tests are done 10000 times with 16 fields
+
+Testing table with 16 fields
+Testing select * from table with 1 record
+Time to select_many_fields(10000): 39 secs (39.20 usr 0.00 sys = 39.20 cpu)
+
+Testing select all_fields from table with 1 record
+Time to select_many_fields(10000): 39 secs (39.41 usr 0.00 sys = 39.41 cpu)
+
+Testing insert VALUES()
+Time to insert_many_fields(10000): 39 secs (38.70 usr 0.00 sys = 38.70 cpu)
+
+Testing insert (all_fields) VALUES()
+Time to insert_many_fields(10000): 37 secs (37.06 usr 0.00 sys = 37.06 cpu)
+
+Total time: 155 secs (154.44 usr 0.00 sys = 154.44 cpu)
diff --git a/sql-bench/Results-win32/big-tables-mysql-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase b/sql-bench/Results-win32/big-tables-mysql-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
new file mode 100644
index 00000000000..ee1bad8c086
--- /dev/null
+++ b/sql-bench/Results-win32/big-tables-mysql-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
@@ -0,0 +1,19 @@
+Testing server 'MySQL 3.22.16 gamma' at 1999-02-20 19:54:17
+
+Testing of some unusual tables
+All tests are done 10000 times with 16 fields
+
+Testing table with 16 fields
+Testing select * from table with 1 record
+Time to select_many_fields(10000): 17 wallclock secs ( 8.14 usr + 2.49 sys = 10.64 CPU)
+
+Testing select all_fields from table with 1 record
+Time to select_many_fields(10000): 27 wallclock secs ( 7.93 usr + 2.70 sys = 10.64 CPU)
+
+Testing insert VALUES()
+Time to insert_many_fields(10000): 13 wallclock secs ( 6.14 usr + 1.46 sys = 7.60 CPU)
+
+Testing insert (all_fields) VALUES()
+Time to insert_many_fields(10000): 17 wallclock secs ( 1.18 usr + 1.38 sys = 2.56 CPU)
+
+Total time: 74 wallclock secs (23.40 usr + 8.04 sys = 31.45 CPU)
diff --git a/sql-bench/Results-win32/big-tables-mysql-win98 b/sql-bench/Results-win32/big-tables-mysql-win98
new file mode 100644
index 00000000000..dc57828441f
--- /dev/null
+++ b/sql-bench/Results-win32/big-tables-mysql-win98
@@ -0,0 +1,19 @@
+Testing server 'MySQL 3.23.13a alpha' at 2000-03-15 2:24:33
+
+Testing of some unusual tables
+All tests are done 1000 times with 1000 fields
+
+Testing table with 1000 fields
+Testing select * from table with 1 record
+Time to select_many_fields(1000): 55 wallclock secs (55.36 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing select all_fields from table with 1 record
+Time to select_many_fields(1000): 69 wallclock secs (68.88 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing insert VALUES()
+Time to insert_many_fields(1000): 6 wallclock secs ( 6.20 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing insert (all_fields) VALUES()
+Time to insert_many_fields(1000): 19 wallclock secs (18.51 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Total time: 151 wallclock secs (150.66 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results-win32/big-tables-mysql-win98-cmp-access,mysql b/sql-bench/Results-win32/big-tables-mysql-win98-cmp-access,mysql
new file mode 100644
index 00000000000..0eac237d1bc
--- /dev/null
+++ b/sql-bench/Results-win32/big-tables-mysql-win98-cmp-access,mysql
@@ -0,0 +1,19 @@
+Testing server 'MySQL 3.23.8 alpha' at 2000-01-04 12:20:10
+
+Testing of some unusual tables
+All tests are done 1000 times with 255 fields
+
+Testing table with 255 fields
+Testing select * from table with 1 record
+Time to select_many_fields(1000): 20 wallclock secs (19.77 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing select all_fields from table with 1 record
+Time to select_many_fields(1000): 23 wallclock secs (23.12 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing insert VALUES()
+Time to insert_many_fields(1000): 3 wallclock secs ( 2.86 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing insert (all_fields) VALUES()
+Time to insert_many_fields(1000): 5 wallclock secs ( 5.05 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Total time: 51 wallclock secs (50.91 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results-win32/big-tables-mysql_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase b/sql-bench/Results-win32/big-tables-mysql_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
new file mode 100644
index 00000000000..140650bba24
--- /dev/null
+++ b/sql-bench/Results-win32/big-tables-mysql_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
@@ -0,0 +1,19 @@
+Testing server 'MySQL 3.22.16 gamma' at 1999-02-07 11:44:00
+
+Testing of some unusual tables
+All tests are done 10000 times with 16 fields
+
+Testing table with 16 fields
+Testing select * from table with 1 record
+Time to select_many_fields(10000): 25 secs (24.41 usr 0.00 sys = 24.41 cpu)
+
+Testing select all_fields from table with 1 record
+Time to select_many_fields(10000): 35 secs (35.44 usr 0.00 sys = 35.44 cpu)
+
+Testing insert VALUES()
+Time to insert_many_fields(10000): 15 secs (15.06 usr 0.00 sys = 15.06 cpu)
+
+Testing insert (all_fields) VALUES()
+Time to insert_many_fields(10000): 25 secs (25.23 usr 0.00 sys = 25.23 cpu)
+
+Total time: 100 secs (100.14 usr 0.00 sys = 100.14 cpu)
diff --git a/sql-bench/Results-win32/big-tables-oracle_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase b/sql-bench/Results-win32/big-tables-oracle_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
new file mode 100644
index 00000000000..d7c7f5f846f
--- /dev/null
+++ b/sql-bench/Results-win32/big-tables-oracle_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
@@ -0,0 +1,19 @@
+Testing server 'Oracle 8.0.4.0.0' at 1999-04-03 22:38:13
+
+Testing of some unusual tables
+All tests are done 10000 times with 16 fields
+
+Testing table with 16 fields
+Testing select * from table with 1 record
+Time to select_many_fields(10000): 48 wallclock secs (31.69 usr 4.93 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing select all_fields from table with 1 record
+Time to select_many_fields(10000): 48 wallclock secs (32.70 usr 5.03 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing insert VALUES()
+Time to insert_many_fields(10000): 69 wallclock secs (14.82 usr 1.82 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing insert (all_fields) VALUES()
+Time to insert_many_fields(10000): 81 wallclock secs (14.73 usr 1.51 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Total time: 246 wallclock secs (93.94 usr 13.29 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results-win32/big-tables-solid_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase b/sql-bench/Results-win32/big-tables-solid_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
new file mode 100644
index 00000000000..3ac6358776a
--- /dev/null
+++ b/sql-bench/Results-win32/big-tables-solid_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
@@ -0,0 +1,19 @@
+Testing server 'Solid version ???' at 1998-10-06 18:02:53
+
+Testing of some unusual tables
+All tests are done 10000 times with 16 fields
+
+Testing table with 16 fields
+Testing select * from table with 1 record
+Time to select_many_fields(10000): 30 secs (29.42 usr 0.00 sys = 29.42 cpu)
+
+Testing select all_fields from table with 1 record
+Time to select_many_fields(10000): 26 secs (26.97 usr 0.00 sys = 26.97 cpu)
+
+Testing insert VALUES()
+Time to insert_many_fields(10000): 25 secs (24.27 usr 0.00 sys = 24.27 cpu)
+
+Testing insert (all_fields) VALUES()
+Time to insert_many_fields(10000): 24 secs (24.17 usr 0.00 sys = 24.17 cpu)
+
+Total time: 107 secs (107.11 usr 0.00 sys = 107.11 cpu)
diff --git a/sql-bench/Results-win32/big-tables-sybase_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase b/sql-bench/Results-win32/big-tables-sybase_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
new file mode 100644
index 00000000000..b25986c12fb
--- /dev/null
+++ b/sql-bench/Results-win32/big-tables-sybase_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
@@ -0,0 +1,19 @@
+Testing server 'Sybase enterprise 11.5 NT' at 1998-08-27 2:14:09
+
+Testing of some unusual tables
+All tests are done 10000 times with 16 fields
+
+Testing table with 16 fields
+Testing select * from table with 1 record
+Time to select_many_fields(10000): 54 secs (54.47 usr 0.00 sys = 54.47 cpu)
+
+Testing select all_fields from table with 1 record
+Time to select_many_fields(10000): 68 secs (67.58 usr 0.00 sys = 67.58 cpu)
+
+Testing insert VALUES()
+Time to insert_many_fields(10000): 115 secs (115.28 usr 0.00 sys = 115.28 cpu)
+
+Testing insert (all_fields) VALUES()
+Time to insert_many_fields(10000): 116 secs (115.28 usr 0.00 sys = 115.28 cpu)
+
+Total time: 353 secs (352.68 usr 0.00 sys = 352.68 cpu)
diff --git a/sql-bench/Results-win32/connect-access_odbc-win98-cmp-access,mysql b/sql-bench/Results-win32/connect-access_odbc-win98-cmp-access,mysql
new file mode 100644
index 00000000000..f79ffcb44ee
--- /dev/null
+++ b/sql-bench/Results-win32/connect-access_odbc-win98-cmp-access,mysql
@@ -0,0 +1,33 @@
+Testing server 'Access 2000' at 2000-01-04 1:49:15
+
+Testing the speed of connecting to the server and sending of data
+All tests are done 10000 times
+
+Testing connection/disconnect
+Time to connect (10000): 1267 wallclock secs (1267.63 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Test connect/simple select/disconnect
+Time for connect+select_simple (10000): 1766 wallclock secs (1765.08 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Test simple select
+Time for select_simple (10000): 38 wallclock secs (38.12 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing connect/select 1 row from table/disconnect
+DBI->connect failed: [Microsoft][Drivrutin för ODBC Microsoft Access] Fel på disk eller nätverk. (SQL-S1000)(DBD: db_login/SQLConnect err=-1) at test-connect line 140
+Warning: 1 connections didn't work without a time delay
+Time to connect+select_1_row (10000): 1780 wallclock secs (1779.92 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing select 1 row from table
+Time to select_1_row (10000): 55 wallclock secs (55.04 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing select 2 rows from table
+Time to select_2_rows (10000): 56 wallclock secs (55.81 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing retrieval of big records (255 bytes)
+Time to select_big (10000): 50 wallclock secs (49.92 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+[Microsoft][Drivrutin för ODBC Microsoft Access] Databasmotorn kunde inte låsa tabellen 'bench1'. Den används redan av en annan användare eller process. (SQL-S1000)(DBD: st_execute/SQLExecute err=-1) at test-connect line 240.
+
+# The following row is calculated by hand from the above:
+
+Total time: 5012 wallclock secs (5011.52 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU) \ No newline at end of file
diff --git a/sql-bench/Results-win32/connect-db2_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase b/sql-bench/Results-win32/connect-db2_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
new file mode 100644
index 00000000000..a6fbfc1695e
--- /dev/null
+++ b/sql-bench/Results-win32/connect-db2_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
@@ -0,0 +1,6 @@
+Testing server 'IBM DB2 5' at 1999-02-02 7:07:03
+
+Testing the speed of connecting to the server and sending of data
+All tests are done 10000 times
+
+Testing connection/disconnect
diff --git a/sql-bench/Results-win32/connect-informix_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase b/sql-bench/Results-win32/connect-informix_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
new file mode 100644
index 00000000000..0619aa5eb7d
--- /dev/null
+++ b/sql-bench/Results-win32/connect-informix_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
@@ -0,0 +1,21 @@
+Testing server 'Informix 7.30C1 ' at 1998-09-01 2:10:58
+
+Testing the speed of connecting to the server and sending of data
+All tests are done 10000 times
+
+Testing connection/disconnect
+Time to connect (10000): 1989 secs (1989.51 usr 0.00 sys = 1989.51 cpu)
+
+Testing connect/select 1 row from table/disconnect
+Time to connect+select (10000): 2050 secs (2049.47 usr 0.00 sys = 2049.47 cpu)
+
+Testing select 1 row from table
+Time to select (10000): 56 secs (55.99 usr 0.00 sys = 55.99 cpu)
+
+Testing select 2 rows from table
+Time to select (10000): 56 secs (56.37 usr 0.00 sys = 56.37 cpu)
+
+Testing retrieval of big records (224 bytes)
+Time to select_big (10000): 73 secs (73.49 usr 0.00 sys = 73.49 cpu)
+
+Total time: 4225 secs (4225.65 usr 0.00 sys = 4225.65 cpu)
diff --git a/sql-bench/Results-win32/connect-ms-sql_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase b/sql-bench/Results-win32/connect-ms-sql_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
new file mode 100644
index 00000000000..fb72abf899c
--- /dev/null
+++ b/sql-bench/Results-win32/connect-ms-sql_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
@@ -0,0 +1,21 @@
+Testing server 'Microsoft SQL Server 7.00 - 7.00.517 (Intel X86) ' at 1998-09-07 2:21:49
+
+Testing the speed of connecting to the server and sending of data
+All tests are done 10000 times
+
+Testing connection/disconnect
+Time to connect (10000): 202 secs (201.91 usr 0.00 sys = 201.91 cpu)
+
+Testing connect/select 1 row from table/disconnect
+Time to connect+select (10000): 234 secs (234.54 usr 0.00 sys = 234.54 cpu)
+
+Testing select 1 row from table
+Time to select (10000): 33 secs (32.33 usr 0.00 sys = 32.33 cpu)
+
+Testing select 2 rows from table
+Time to select (10000): 32 secs (32.45 usr 0.00 sys = 32.45 cpu)
+
+Testing retrieval of big records (224 bytes)
+Time to select_big (10000): 34 secs (33.44 usr 0.00 sys = 33.44 cpu)
+
+Total time: 535 secs (534.85 usr 0.00 sys = 534.85 cpu)
diff --git a/sql-bench/Results-win32/connect-mysql-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase b/sql-bench/Results-win32/connect-mysql-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
new file mode 100644
index 00000000000..315b8c78a73
--- /dev/null
+++ b/sql-bench/Results-win32/connect-mysql-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
@@ -0,0 +1,21 @@
+Testing server 'MySQL 3.22.16 gamma' at 1999-02-20 19:55:31
+
+Testing the speed of connecting to the server and sending of data
+All tests are done 10000 times
+
+Testing connection/disconnect
+Time to connect (10000): 56 wallclock secs (16.91 usr + 13.01 sys = 29.92 CPU)
+
+Testing connect/select 1 row from table/disconnect
+Time to connect+select (10000): 64 wallclock secs (18.76 usr + 14.96 sys = 33.72 CPU)
+
+Testing select 1 row from table
+Time to select (10000): 9 wallclock secs ( 1.66 usr + 1.76 sys = 3.43 CPU)
+
+Testing select 2 rows from table
+Time to select (10000): 12 wallclock secs ( 1.84 usr + 2.02 sys = 3.87 CPU)
+
+Testing retrieval of big records (224 bytes)
+Time to select_big (10000): 14 wallclock secs ( 6.55 usr + 1.80 sys = 8.35 CPU)
+
+Total time: 155 wallclock secs (45.74 usr + 33.56 sys = 79.29 CPU)
diff --git a/sql-bench/Results-win32/connect-mysql-win98 b/sql-bench/Results-win32/connect-mysql-win98
new file mode 100644
index 00000000000..cf0c35ddc8e
--- /dev/null
+++ b/sql-bench/Results-win32/connect-mysql-win98
@@ -0,0 +1,27 @@
+Testing server 'MySQL 3.23.13a alpha' at 2000-03-15 2:27:04
+
+Testing the speed of connecting to the server and sending of data
+All tests are done 10000 times
+
+Testing connection/disconnect
+Time to connect (10000): 52 wallclock secs (51.85 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Test connect/simple select/disconnect
+Time for connect+select_simple (10000): 67 wallclock secs (66.90 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Test simple select
+Time for select_simple (10000): 12 wallclock secs (12.20 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing connect/select 1 row from table/disconnect
+Time to connect+select_1_row (10000): 72 wallclock secs (71.95 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing select 1 row from table
+Time to select_1_row (10000): 16 wallclock secs (15.99 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing select 2 rows from table
+Time to select_2_rows (10000): 19 wallclock secs (18.89 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing retrieval of big records (65000 bytes)
+Time to select_big (10000): 130 wallclock secs (130.56 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Total time: 369 wallclock secs (368.94 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results-win32/connect-mysql-win98-cmp-access,mysql b/sql-bench/Results-win32/connect-mysql-win98-cmp-access,mysql
new file mode 100644
index 00000000000..dd5a7eaac9d
--- /dev/null
+++ b/sql-bench/Results-win32/connect-mysql-win98-cmp-access,mysql
@@ -0,0 +1,27 @@
+Testing server 'MySQL 3.23.8 alpha' at 2000-01-04 21:06:49
+
+Testing the speed of connecting to the server and sending of data
+All tests are done 10000 times
+
+Testing connection/disconnect
+Time to connect (10000): 55 wallclock secs (54.76 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Test connect/simple select/disconnect
+Time for connect+select_simple (10000): 71 wallclock secs (70.80 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Test simple select
+Time for select_simple (10000): 13 wallclock secs (13.45 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing connect/select 1 row from table/disconnect
+Time to connect+select_1_row (10000): 75 wallclock secs (75.96 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing select 1 row from table
+Time to select_1_row (10000): 18 wallclock secs (17.30 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing select 2 rows from table
+Time to select_2_rows (10000): 20 wallclock secs (20.65 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing retrieval of big records (255 bytes)
+Time to select_big (10000): 22 wallclock secs (22.19 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Total time: 276 wallclock secs (275.78 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results-win32/connect-mysql_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase b/sql-bench/Results-win32/connect-mysql_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
new file mode 100644
index 00000000000..ff5511fa1a8
--- /dev/null
+++ b/sql-bench/Results-win32/connect-mysql_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
@@ -0,0 +1,21 @@
+Testing server 'MySQL 3.22.16 gamma' at 1999-02-07 11:45:41
+
+Testing the speed of connecting to the server and sending of data
+All tests are done 10000 times
+
+Testing connection/disconnect
+Time to connect (10000): 189 secs (188.69 usr 0.00 sys = 188.69 cpu)
+
+Testing connect/select 1 row from table/disconnect
+Time to connect+select (10000): 211 secs (211.59 usr 0.00 sys = 211.59 cpu)
+
+Testing select 1 row from table
+Time to select (10000): 19 secs (18.79 usr 0.00 sys = 18.79 cpu)
+
+Testing select 2 rows from table
+Time to select (10000): 20 secs (19.97 usr 0.00 sys = 19.97 cpu)
+
+Testing retrieval of big records (224 bytes)
+Time to select_big (10000): 20 secs (19.71 usr 0.00 sys = 19.71 cpu)
+
+Total time: 459 secs (458.81 usr 0.00 sys = 458.81 cpu)
diff --git a/sql-bench/Results-win32/connect-oracle_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase b/sql-bench/Results-win32/connect-oracle_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
new file mode 100644
index 00000000000..5420cdb3998
--- /dev/null
+++ b/sql-bench/Results-win32/connect-oracle_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
@@ -0,0 +1,21 @@
+Testing server 'Oracle 8.0.4.0.0' at 1999-04-03 22:42:21
+
+Testing the speed of connecting to the server and sending of data
+All tests are done 10000 times
+
+Testing connection/disconnect
+Time to connect (10000): 8713 wallclock secs (195.47 usr 436.40 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing connect/select 1 row from table/disconnect
+Time to connect+select (10000): 8722 wallclock secs (257.48 usr 362.71 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing select 1 row from table
+Time to select (10000): 24 wallclock secs (14.99 usr 1.74 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing select 2 rows from table
+Time to select (10000): 23 wallclock secs (15.59 usr 1.17 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing retrieval of big records (224 bytes)
+Time to select_big (10000): 35 wallclock secs (21.24 usr 4.63 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Total time: 17520 wallclock secs (504.84 usr 806.71 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results-win32/connect-solid_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase b/sql-bench/Results-win32/connect-solid_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
new file mode 100644
index 00000000000..d42946a3995
--- /dev/null
+++ b/sql-bench/Results-win32/connect-solid_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
@@ -0,0 +1,21 @@
+Testing server 'Solid version ???' at 1998-10-06 18:04:41
+
+Testing the speed of connecting to the server and sending of data
+All tests are done 10000 times
+
+Testing connection/disconnect
+Time to connect (10000): 385 secs (385.29 usr 0.00 sys = 385.29 cpu)
+
+Testing connect/select 1 row from table/disconnect
+Time to connect+select (10000): 414 secs (413.81 usr 0.00 sys = 413.81 cpu)
+
+Testing select 1 row from table
+Time to select (10000): 23 secs (23.32 usr 0.00 sys = 23.32 cpu)
+
+Testing select 2 rows from table
+Time to select (10000): 24 secs (24.00 usr 0.00 sys = 24.00 cpu)
+
+Testing retrieval of big records (224 bytes)
+Time to select_big (10000): 25 secs (24.64 usr 0.00 sys = 24.64 cpu)
+
+Total time: 871 secs (871.19 usr 0.00 sys = 871.19 cpu)
diff --git a/sql-bench/Results-win32/connect-sybase_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase b/sql-bench/Results-win32/connect-sybase_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
new file mode 100644
index 00000000000..b90e8036719
--- /dev/null
+++ b/sql-bench/Results-win32/connect-sybase_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
@@ -0,0 +1,21 @@
+Testing server 'Sybase enterprise 11.5 NT' at 1998-08-27 2:20:02
+
+Testing the speed of connecting to the server and sending of data
+All tests are done 10000 times
+
+Testing connection/disconnect
+Time to connect (10000): 1275 secs (1274.97 usr 0.00 sys = 1274.97 cpu)
+
+Testing connect/select 1 row from table/disconnect
+Time to connect+select (10000): 1330 secs (1329.69 usr 0.00 sys = 1329.69 cpu)
+
+Testing select 1 row from table
+Time to select (10000): 40 secs (39.77 usr 0.00 sys = 39.77 cpu)
+
+Testing select 2 rows from table
+Time to select (10000): 40 secs (40.20 usr 0.00 sys = 40.20 cpu)
+
+Testing retrieval of big records (224 bytes)
+Time to select_big (10000): 40 secs (39.56 usr 0.00 sys = 39.56 cpu)
+
+Total time: 2725 secs (2724.61 usr 0.00 sys = 2724.61 cpu)
diff --git a/sql-bench/Results-win32/create-access_odbc-win98-cmp-access,mysql b/sql-bench/Results-win32/create-access_odbc-win98-cmp-access,mysql
new file mode 100644
index 00000000000..2feabb9ddf3
--- /dev/null
+++ b/sql-bench/Results-win32/create-access_odbc-win98-cmp-access,mysql
@@ -0,0 +1,18 @@
+Testing server 'Access 2000' at 2000-01-06 1:49:25
+
+Testing the speed of creating and droping tables
+All tests are done 7000 times
+
+Testing create of tables
+Time for create_many_tables (7000): 142 wallclock secs (141.43 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Accessing tables
+Time to select_group (7000): 52 wallclock secs (52.84 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing drop
+Time for drop_table (7000): 109 wallclock secs (109.63 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing create+drop
+Time for create+drop (7000): 187 wallclock secs (186.36 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for create_key+drop (7000): 207 wallclock secs (207.73 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Total time: 699 wallclock secs (698.76 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results-win32/create-db2_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase b/sql-bench/Results-win32/create-db2_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
new file mode 100644
index 00000000000..1ae88e6607b
--- /dev/null
+++ b/sql-bench/Results-win32/create-db2_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
@@ -0,0 +1,20 @@
+Testing server 'IBM DB2 5' at 1999-02-02 7:10:24
+
+Testing the speed of creating and droping tables
+All tests are done 1000 times
+
+Okay..Let's make sure that our tables don't exist yet.
+
+Testing create of tables
+Time for create_table (1000): 389 secs (389.60 usr 0.00 sys = 389.60 cpu)
+
+Accessing tables
+Time to select_group (1000): 7 secs ( 7.37 usr 0.00 sys = 7.37 cpu)
+
+Testing drop
+Time for drop_table (1000): 106 secs (106.19 usr 0.00 sys = 106.19 cpu)
+
+Testing create+drop
+Time for create+drop (1000): 408 secs (408.21 usr 0.00 sys = 408.21 cpu)
+Time for create_key+drop (1000): 193 secs (192.75 usr 0.00 sys = 192.75 cpu)
+Total time: 1106 secs (1106.62 usr 0.00 sys = 1106.62 cpu)
diff --git a/sql-bench/Results-win32/create-informix_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase b/sql-bench/Results-win32/create-informix_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
new file mode 100644
index 00000000000..89ec2fcbfe4
--- /dev/null
+++ b/sql-bench/Results-win32/create-informix_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
@@ -0,0 +1,20 @@
+Testing server 'Informix 7.30C1 ' at 1998-09-01 3:21:25
+
+Testing the speed of creating and droping tables
+All tests are done 1000 times
+
+Okay..Let's make sure that our tables don't exist yet.
+
+Testing create of tables
+Time for create_table (1000): 56 secs (55.74 usr 0.00 sys = 55.74 cpu)
+
+Accessing tables
+Time to select_group (1000): 8 secs ( 8.49 usr 0.00 sys = 8.49 cpu)
+
+Testing drop
+Time for drop_table (1000): 33 secs (32.69 usr 0.00 sys = 32.69 cpu)
+
+Testing create+drop
+Time for create+drop (1000): 35 secs (35.34 usr 0.00 sys = 35.34 cpu)
+Time for create_key+drop (1000): 90 secs (89.37 usr 0.00 sys = 89.37 cpu)
+Total time: 222 secs (221.64 usr 0.00 sys = 221.64 cpu)
diff --git a/sql-bench/Results-win32/create-ms-sql_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase b/sql-bench/Results-win32/create-ms-sql_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
new file mode 100644
index 00000000000..e255cfc05a2
--- /dev/null
+++ b/sql-bench/Results-win32/create-ms-sql_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
@@ -0,0 +1,20 @@
+Testing server 'Microsoft SQL Server 7.00 - 7.00.517 (Intel X86) ' at 1998-09-07 10:22:16
+
+Testing the speed of creating and droping tables
+All tests are done 1000 times
+
+Okay..Let's make sure that our tables don't exist yet.
+
+Testing create of tables
+Time for create_table (1000): 55 secs (55.35 usr 0.00 sys = 55.35 cpu)
+
+Accessing tables
+Time to select_group (1000): 20 secs (20.25 usr 0.00 sys = 20.25 cpu)
+
+Testing drop
+Time for drop_table (1000): 6 secs ( 5.80 usr 0.00 sys = 5.80 cpu)
+
+Testing create+drop
+Time for create+drop (1000): 35 secs (34.23 usr 0.00 sys = 34.23 cpu)
+Time for create_key+drop (1000): 36 secs (36.10 usr 0.00 sys = 36.10 cpu)
+Total time: 152 secs (151.76 usr 0.00 sys = 151.76 cpu)
diff --git a/sql-bench/Results-win32/create-mysql-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase b/sql-bench/Results-win32/create-mysql-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
new file mode 100644
index 00000000000..822a7d6cda7
--- /dev/null
+++ b/sql-bench/Results-win32/create-mysql-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
@@ -0,0 +1,20 @@
+Testing server 'MySQL 3.22.16 gamma' at 1999-02-20 19:58:06
+
+Testing the speed of creating and droping tables
+All tests are done 1000 times
+
+Okay..Let's make sure that our tables don't exist yet.
+
+Testing create of tables
+Time for create_table (1000): 23 wallclock secs ( 0.47 usr + 0.18 sys = 0.65 CPU)
+
+Accessing tables
+Time to select_group (1000): 14 wallclock secs ( 0.22 usr + 0.11 sys = 0.33 CPU)
+
+Testing drop
+Time for drop_table (1000): 3 wallclock secs ( 0.10 usr + 0.16 sys = 0.26 CPU)
+
+Testing create+drop
+Time for create+drop (1000): 14 wallclock secs ( 0.40 usr + 0.19 sys = 0.59 CPU)
+Time for create_key+drop (1000): 18 wallclock secs ( 0.85 usr + 0.33 sys = 1.18 CPU)
+Total time: 72 wallclock secs ( 2.05 usr + 0.97 sys = 3.02 CPU)
diff --git a/sql-bench/Results-win32/create-mysql-win98 b/sql-bench/Results-win32/create-mysql-win98
new file mode 100644
index 00000000000..e0211664f23
--- /dev/null
+++ b/sql-bench/Results-win32/create-mysql-win98
@@ -0,0 +1,18 @@
+Testing server 'MySQL 3.23.13a alpha' at 2000-03-15 2:33:13
+
+Testing the speed of creating and droping tables
+Testing with 5000 tables and 10000 loop count
+
+Testing create of tables
+Time for create_MANY_tables (5000): 1510 wallclock secs (1510.83 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Accessing tables
+Time to select_group_when_MANY_tables (5000): 581 wallclock secs (580.46 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing drop
+Time for drop_table_when_MANY_tables (5000): 160 wallclock secs (159.83 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing create+drop
+Time for create+drop (10000): 1433 wallclock secs (1433.28 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for create_key+drop (10000): 1457 wallclock secs (1456.57 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Total time: 5141 wallclock secs (5140.97 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results-win32/create-mysql-win98-cmp-access,mysql b/sql-bench/Results-win32/create-mysql-win98-cmp-access,mysql
new file mode 100644
index 00000000000..15de75eb663
--- /dev/null
+++ b/sql-bench/Results-win32/create-mysql-win98-cmp-access,mysql
@@ -0,0 +1,18 @@
+Testing server 'MySQL 3.23.8 alpha' at 2000-01-05 4:37:04
+
+Testing the speed of creating and droping tables
+All tests are done 7000 times
+
+Testing create of tables
+Time for create_many_tables (7000): 2530 wallclock secs (2529.76 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Accessing tables
+Time to select_group (7000): 4718 wallclock secs (4718.04 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing drop
+Time for drop_table (7000): 316 wallclock secs (315.66 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing create+drop
+Time for create+drop (7000): 1011 wallclock secs (1011.13 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for create_key+drop (7000): 1025 wallclock secs (1025.23 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Total time: 9601 wallclock secs (9600.98 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results-win32/create-mysql_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase b/sql-bench/Results-win32/create-mysql_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
new file mode 100644
index 00000000000..726d05c2881
--- /dev/null
+++ b/sql-bench/Results-win32/create-mysql_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
@@ -0,0 +1,20 @@
+Testing server 'MySQL 3.22.16 gamma' at 1999-02-07 11:53:20
+
+Testing the speed of creating and droping tables
+All tests are done 1000 times
+
+Okay..Let's make sure that our tables don't exist yet.
+
+Testing create of tables
+Time for create_table (1000): 22 secs (21.84 usr 0.00 sys = 21.84 cpu)
+
+Accessing tables
+Time to select_group (1000): 17 secs (17.75 usr 0.00 sys = 17.75 cpu)
+
+Testing drop
+Time for drop_table (1000): 4 secs ( 3.73 usr 0.00 sys = 3.73 cpu)
+
+Testing create+drop
+Time for create+drop (1000): 15 secs (15.21 usr 0.00 sys = 15.21 cpu)
+Time for create_key+drop (1000): 20 secs (20.05 usr 0.00 sys = 20.05 cpu)
+Total time: 78 secs (78.59 usr 0.00 sys = 78.59 cpu)
diff --git a/sql-bench/Results-win32/create-oracle_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase b/sql-bench/Results-win32/create-oracle_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
new file mode 100644
index 00000000000..71177a8d45a
--- /dev/null
+++ b/sql-bench/Results-win32/create-oracle_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
@@ -0,0 +1,20 @@
+Testing server 'Oracle 8.0.4.0.0' at 1999-04-04 3:34:22
+
+Testing the speed of creating and droping tables
+All tests are done 1000 times
+
+Okay..Let's make sure that our tables don't exist yet.
+
+Testing create of tables
+Time for create_table (1000): 132 wallclock secs ( 3.33 usr 0.37 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Accessing tables
+Time to select_group (1000): 7 wallclock secs ( 1.52 usr 0.12 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing drop
+Time for drop_table (1000): 108 wallclock secs ( 1.31 usr 0.17 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing create+drop
+Time for create+drop (1000): 288 wallclock secs ( 4.23 usr 0.58 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for create_key+drop (1000): 411 wallclock secs ( 4.65 usr 0.38 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Total time: 947 wallclock secs (15.04 usr 1.62 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results-win32/create-solid_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase b/sql-bench/Results-win32/create-solid_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
new file mode 100644
index 00000000000..038dd13cf5f
--- /dev/null
+++ b/sql-bench/Results-win32/create-solid_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
@@ -0,0 +1,20 @@
+Testing server 'Solid version ???' at 1998-10-06 18:19:13
+
+Testing the speed of creating and droping tables
+All tests are done 1000 times
+
+Okay..Let's make sure that our tables don't exist yet.
+
+Testing create of tables
+Time for create_table (1000): 22 secs (21.35 usr 0.00 sys = 21.35 cpu)
+
+Accessing tables
+Time to select_group (1000): 8 secs ( 8.23 usr 0.00 sys = 8.23 cpu)
+
+Testing drop
+Time for drop_table (1000): 18 secs (17.98 usr 0.00 sys = 17.98 cpu)
+
+Testing create+drop
+Time for create+drop (1000): 41 secs (41.20 usr 0.00 sys = 41.20 cpu)
+Time for create_key+drop (1000): 72 secs (72.18 usr 0.00 sys = 72.18 cpu)
+Total time: 161 secs (160.95 usr 0.00 sys = 160.95 cpu)
diff --git a/sql-bench/Results-win32/create-sybase_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase b/sql-bench/Results-win32/create-sybase_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
new file mode 100644
index 00000000000..242fe125667
--- /dev/null
+++ b/sql-bench/Results-win32/create-sybase_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
@@ -0,0 +1,20 @@
+Testing server 'Sybase enterprise 11.5 NT' at 1998-08-27 3:05:28
+
+Testing the speed of creating and droping tables
+All tests are done 1000 times
+
+Okay..Let's make sure that our tables don't exist yet.
+
+Testing create of tables
+Time for create_table (1000): 80 secs (80.37 usr 0.00 sys = 80.37 cpu)
+
+Accessing tables
+Time to select_group (1000): 14 secs (14.25 usr 0.00 sys = 14.25 cpu)
+
+Testing drop
+Time for drop_table (1000): 19 secs (18.63 usr 0.00 sys = 18.63 cpu)
+
+Testing create+drop
+Time for create+drop (1000): 63 secs (63.53 usr 0.00 sys = 63.53 cpu)
+Time for create_key+drop (1000): 52 secs (51.41 usr 0.00 sys = 51.41 cpu)
+Total time: 228 secs (228.22 usr 0.00 sys = 228.22 cpu)
diff --git a/sql-bench/Results-win32/insert-access_odbc-win98-cmp-access,mysql b/sql-bench/Results-win32/insert-access_odbc-win98-cmp-access,mysql
new file mode 100644
index 00000000000..88b87322eaa
--- /dev/null
+++ b/sql-bench/Results-win32/insert-access_odbc-win98-cmp-access,mysql
@@ -0,0 +1,67 @@
+Testing server 'Access 2000' at 2000-01-03 15:01:30
+
+Testing the speed of inserting data into 1 table and do some selects on it.
+The tests are done with a table that has 100000 rows.
+
+Generating random keys
+Creating tables
+Inserting 100000 rows in order
+Inserting 100000 rows in reverse order
+Inserting 100000 rows in random order
+Time for insert (300000): 1974 wallclock secs (1973.91 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing insert of duplicates
+Time for insert_duplicates (300000): 209 wallclock secs (208.61 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Retrieving data from the table
+Time for select_big (10:3000000): 311 wallclock secs (310.93 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for order_by_key (10:3000000): 396 wallclock secs (395.80 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for order_by (10:3000000): 388 wallclock secs (388.10 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_diff_key (500:1000): 3 wallclock secs ( 3.63 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_range_prefix (5010:42084): 68 wallclock secs (67.77 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_range (5010:42084): 65 wallclock secs (64.65 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+71768 queries in 35884 loops of 100000 loops took 601 seconds
+Estimated time for select_key_prefix (200000): 1674 wallclock secs (1673.75 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+58230 queries in 29115 loops of 100000 loops took 601 seconds
+Estimated time for select_key (200000): 2064 wallclock secs (2064.23 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Test of compares with simple ranges
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+5960 queries in 149 loops of 500 loops took 603 seconds
+Estimated time for select_range_prefix (20000:12963): 2023 wallclock secs (2024.87 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_range (20000:43500): 475 wallclock secs (474.78 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_group (91): 341 wallclock secs (341.20 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for min_max_on_key (3000): 19 wallclock secs (18.56 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for min_max (60): 186 wallclock secs (186.25 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for count_on_key (100): 15 wallclock secs (15.44 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for count (100): 328 wallclock secs (327.46 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing update of keys with functions
+Time for update_of_key (500): 14 wallclock secs (14.12 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for update_of_key_big (501): 548 wallclock secs (548.43 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing update with key
+Time for update_with_key (100000): 2081 wallclock secs (2080.30 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing update of all rows
+Time for update_big (500): 1550 wallclock secs (1550.11 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing delete
+Time for delete_key (500): 79 wallclock secs (79.31 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for delete_big (12): 274 wallclock secs (274.25 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Insert into table with 16 keys and with a primary key with 10 parts
+Time for insert_key (100000): 10591 wallclock secs (10591.45 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing update of keys
+Time for update_of_key (256): 873 wallclock secs (872.99 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Deleting everything from table
+Time for delete_big_many_keys (2): 12569 wallclock secs (12568.66 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Estimated total time: 39293 wallclock secs (39294.15 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results-win32/insert-db2_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase b/sql-bench/Results-win32/insert-db2_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
new file mode 100644
index 00000000000..4537891dcbf
--- /dev/null
+++ b/sql-bench/Results-win32/insert-db2_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
@@ -0,0 +1,99 @@
+Testing server 'IBM DB2 5' at 1999-02-02 0:15:24
+
+Testing the speed of inserting data into 1 table and do some selects on it.
+The tests are done with a table that has 100000 rows.
+
+Generating random keys
+Creating tables
+Inserting 100000 rows in order
+0 : Tue Feb 2 00:15:41 1999
+10000 : Tue Feb 2 00:17:14 1999
+20000 : Tue Feb 2 00:18:48 1999
+30000 : Tue Feb 2 00:20:23 1999
+40000 : Tue Feb 2 00:22:02 1999
+50000 : Tue Feb 2 00:23:40 1999
+60000 : Tue Feb 2 00:25:16 1999
+70000 : Tue Feb 2 00:26:54 1999
+80000 : Tue Feb 2 00:28:31 1999
+90000 : Tue Feb 2 00:30:05 1999
+Inserting 100000 rows in reverse order
+0 : Tue Feb 2 00:31:40 1999
+10000 : Tue Feb 2 00:33:22 1999
+20000 : Tue Feb 2 00:34:59 1999
+30000 : Tue Feb 2 00:36:34 1999
+40000 : Tue Feb 2 00:38:18 1999
+50000 : Tue Feb 2 00:39:54 1999
+60000 : Tue Feb 2 00:41:29 1999
+70000 : Tue Feb 2 00:43:13 1999
+80000 : Tue Feb 2 00:44:49 1999
+90000 : Tue Feb 2 00:46:25 1999
+Inserting 100000 rows in random order
+0 : Tue Feb 2 00:48:02 1999
+10000 : Tue Feb 2 00:49:44 1999
+20000 : Tue Feb 2 00:51:21 1999
+30000 : Tue Feb 2 00:53:01 1999
+40000 : Tue Feb 2 00:54:42 1999
+50000 : Tue Feb 2 00:56:16 1999
+60000 : Tue Feb 2 00:57:52 1999
+70000 : Tue Feb 2 00:59:38 1999
+80000 : Tue Feb 2 01:01:12 1999
+90000 : Tue Feb 2 01:02:47 1999
+Time for insert (300000): 2932 secs (2932.59 usr 0.00 sys = 2932.59 cpu)
+
+Testing insert of duplicates
+Time for insert_duplicates (300000): 353 secs (353.39 usr 0.00 sys = 353.39 cpu)
+
+Retrieving data from the table
+Time for select_big (10:3000000): 379 secs (379.32 usr 0.00 sys = 379.32 cpu)
+Time for order_by_key (10:3000000): 369 secs (368.78 usr 0.00 sys = 368.78 cpu)
+Time for order_by (10:3000000): 361 secs (361.08 usr 0.00 sys = 361.08 cpu)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+1940 queries in 1940 loops of 5000 loops took 601 seconds
+Estimated time for select_range_prefix (5000:7760): 1548 secs (1548.93 usr 0.00 sys = 1548.93 cpu)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+1950 queries in 1950 loops of 5000 loops took 602 seconds
+Estimated time for select_range (5000:7800): 1543 secs (1542.09 usr 0.00 sys = 1542.09 cpu)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+100196 queries in 50098 loops of 100000 loops took 601 seconds
+Estimated time for select_key_prefix (200000): 1199 secs (1199.40 usr 0.00 sys = 1199.40 cpu)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+99640 queries in 49820 loops of 100000 loops took 601 seconds
+Estimated time for select_key (200000): 1206 secs (1206.37 usr 0.00 sys = 1206.37 cpu)
+
+Test of compares with simple ranges
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+8320 queries in 208 loops of 500 loops took 602 seconds
+Estimated time for select_range_prefix (20000:18096): 602 secs (602.91 usr 0.00 sys = 602.91 cpu)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+8280 queries in 207 loops of 500 loops took 603 seconds
+Estimated time for select_range (20000:18009): 603 secs (602.74 usr 0.00 sys = 602.74 cpu)
+Time for select_group (91): 145 secs (144.82 usr 0.00 sys = 144.82 cpu)
+Time for min_max_on_key (3000): 576 secs (575.99 usr 0.00 sys = 575.99 cpu)
+Time for min_max (60): 56 secs (55.56 usr 0.00 sys = 55.56 cpu)
+Time for count_on_key (100): 58 secs (57.98 usr 0.00 sys = 57.98 cpu)
+Time for count (100): 87 secs (87.24 usr 0.00 sys = 87.24 cpu)
+
+Testing update with functions
+Time for update_key (500): 5 secs ( 5.24 usr 0.00 sys = 5.24 cpu)
+Time for update_key_big (501): 542 secs (542.23 usr 0.00 sys = 542.23 cpu)
+
+Testing delete
+Time for delete_key (500): 16 secs (15.97 usr 0.00 sys = 15.97 cpu)
+Time for delete_big (12): 133 secs (133.19 usr 0.00 sys = 133.19 cpu)
+
+Insert into table with 16 keys and with a primary key with 15 parts
+Time for insert_key (100000): 2484 secs (2484.63 usr 0.00 sys = 2484.63 cpu)
+
+Testing update of keys
+Time for update_of_key (256): 175 secs (174.76 usr 0.00 sys = 174.76 cpu)
+
+Deleting everything from table
+Time for delete_big (2): 316 secs (315.91 usr 0.00 sys = 315.91 cpu)
+
+Estimated total time: 17508 secs (17508.04 usr 0.00 sys = 17508.04 cpu)
diff --git a/sql-bench/Results-win32/insert-informix_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase b/sql-bench/Results-win32/insert-informix_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
new file mode 100644
index 00000000000..9a8e755e9b8
--- /dev/null
+++ b/sql-bench/Results-win32/insert-informix_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
@@ -0,0 +1,102 @@
+Testing server 'Informix 7.30C1 ' at 1998-10-05 15:25:46
+
+Testing the speed of inserting data into 1 table and do some selects on it.
+The tests are done with a table that has 100000 rows.
+
+Generating random keys
+Creating tables
+Inserting 100000 rows in order
+0 : Mon Oct 5 15:25:50 1998
+10000 : Mon Oct 5 15:26:40 1998
+20000 : Mon Oct 5 15:27:31 1998
+30000 : Mon Oct 5 15:28:22 1998
+40000 : Mon Oct 5 15:29:14 1998
+50000 : Mon Oct 5 15:30:04 1998
+60000 : Mon Oct 5 15:30:55 1998
+70000 : Mon Oct 5 15:31:45 1998
+80000 : Mon Oct 5 15:32:36 1998
+90000 : Mon Oct 5 15:33:26 1998
+Inserting 100000 rows in reverse order
+0 : Mon Oct 5 15:34:17 1998
+10000 : Mon Oct 5 15:35:08 1998
+20000 : Mon Oct 5 15:36:00 1998
+30000 : Mon Oct 5 15:36:51 1998
+40000 : Mon Oct 5 15:37:43 1998
+50000 : Mon Oct 5 15:38:34 1998
+60000 : Mon Oct 5 15:39:26 1998
+70000 : Mon Oct 5 15:40:18 1998
+80000 : Mon Oct 5 15:41:10 1998
+90000 : Mon Oct 5 15:42:01 1998
+Inserting 100000 rows in random order
+0 : Mon Oct 5 15:42:53 1998
+10000 : Mon Oct 5 15:43:45 1998
+20000 : Mon Oct 5 15:44:36 1998
+30000 : Mon Oct 5 15:45:31 1998
+40000 : Mon Oct 5 15:47:13 1998
+50000 : Mon Oct 5 15:49:41 1998
+60000 : Mon Oct 5 15:52:40 1998
+70000 : Mon Oct 5 15:55:47 1998
+80000 : Mon Oct 5 15:59:09 1998
+90000 : Mon Oct 5 16:02:35 1998
+Time for insert (300000): 2417 secs (2417.46 usr 0.00 sys = 2417.46 cpu)
+
+Testing insert of duplicates
+Time for insert_duplicates (300000): 280 secs (280.34 usr 0.00 sys = 280.34 cpu)
+
+Retrieving data from the table
+Time for select_big (10:3000000): 495 secs (494.46 usr 0.00 sys = 494.46 cpu)
+Time for order_by_key (10:3000000): 485 secs (485.49 usr 0.00 sys = 485.49 cpu)
+Time for order_by (10:3000000): 518 secs (517.79 usr 0.00 sys = 517.79 cpu)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+440 queries in 440 loops of 5000 loops took 602 seconds
+Estimated time for select_range_prefix (5000:1760): 6840 secs (6840.98 usr 0.00 sys = 6840.98 cpu)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+460 queries in 460 loops of 5000 loops took 613 seconds
+Estimated time for select_range (5000:1840): 6663 secs (6665.89 usr 0.00 sys = 6665.89 cpu)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+1002 queries in 501 loops of 100000 loops took 601 seconds
+Estimated time for select_key_prefix (200000): 119960 secs (119942.91 usr 0.00 sys = 119942.91 cpu)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+994 queries in 497 loops of 100000 loops took 602 seconds
+Estimated time for select_key (200000): 121126 secs (120992.76 usr 0.00 sys = 120992.76 cpu)
+
+Test of compares with simple ranges
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+1360 queries in 34 loops of 500 loops took 608 seconds
+Estimated time for select_range_prefix (20000:2958): 608 secs (608.02 usr 0.00 sys = 608.02 cpu)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+1360 queries in 34 loops of 500 loops took 615 seconds
+Estimated time for select_range (20000:2958): 615 secs (615.40 usr 0.00 sys = 615.40 cpu)
+Time for select_group (91): 896 secs (895.47 usr 0.00 sys = 895.47 cpu)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+2964 queries in 494 loops of 500 loops took 601 seconds
+Estimated time for min_max_on_key (3000): 608 secs (608.68 usr 0.00 sys = 608.68 cpu)
+Time for min_max (60): 344 secs (344.44 usr 0.00 sys = 344.44 cpu)
+Time for count_on_key (100): 931 secs (930.38 usr 0.00 sys = 930.38 cpu)
+Time for count (100): 116 secs (115.85 usr 0.00 sys = 115.85 cpu)
+
+Testing update with functions
+Time for update_key (500): 771 secs (771.67 usr 0.00 sys = 771.67 cpu)
+Time for update_key_big (501): 3000 secs (2999.42 usr 0.00 sys = 2999.42 cpu)
+
+Testing delete
+Time for delete_key (500): 738 secs (737.82 usr 0.00 sys = 737.82 cpu)
+Time for delete_big (12): 929 secs (928.69 usr 0.00 sys = 928.69 cpu)
+
+Insert into table with 16 keys and with a primary key with 15 parts
+Time for insert_key (100000): 8231 secs (8231.23 usr 0.00 sys = 8231.23 cpu)
+
+Testing update of keys
+Time for update_of_key (256): 2190 secs (2190.23 usr 0.00 sys = 2190.23 cpu)
+
+Deleting everything from table
+Time for delete_big (2): 10326 secs (10325.87 usr 0.00 sys = 10325.87 cpu)
+
+Estimated total time: 305853 secs (305711.97 usr 0.00 sys = 305711.97 cpu)
diff --git a/sql-bench/Results-win32/insert-ms-sql_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase b/sql-bench/Results-win32/insert-ms-sql_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
new file mode 100644
index 00000000000..c32fb0d0b4c
--- /dev/null
+++ b/sql-bench/Results-win32/insert-ms-sql_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
@@ -0,0 +1,57 @@
+Testing server 'Microsoft SQL Server 7.00 - 7.00.517 (Intel X86) ' at 1998-09-27 10:54:53
+
+Testing the speed of inserting data into 1 table and do some selects on it.
+The tests are done with a table that has 100000 rows.
+
+Generating random keys
+Creating tables
+Inserting 100000 rows in order
+Inserting 100000 rows in reverse order
+Inserting 100000 rows in random order
+Time for insert (300000): 3592 secs (3591.82 usr 0.00 sys = 3591.82 cpu)
+
+Testing insert of duplicates
+Time for insert_duplicates (300000): 286 secs (285.70 usr 0.00 sys = 285.70 cpu)
+
+Retrieving data from the table
+Time for select_big (10:3000000): 202 secs (202.02 usr 0.00 sys = 202.02 cpu)
+Time for order_by_key (10:3000000): 201 secs (200.90 usr 0.00 sys = 200.90 cpu)
+Time for order_by (10:3000000): 250 secs (250.66 usr 0.00 sys = 250.66 cpu)
+Time for select_range_prefix (5000:20000): 25 secs (25.49 usr 0.00 sys = 25.49 cpu)
+Time for select_range (5000:20000): 24 secs (24.02 usr 0.00 sys = 24.02 cpu)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+70770 queries in 35385 loops of 100000 loops took 601 seconds
+Estimated time for select_key_prefix (200000): 1698 secs (1696.55 usr 0.00 sys = 1696.55 cpu)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+73534 queries in 36767 loops of 100000 loops took 601 seconds
+Estimated time for select_key (200000): 1634 secs (1634.55 usr 0.00 sys = 1634.55 cpu)
+
+Test of compares with simple ranges
+Time for select_range_prefix (20000:43500): 43 secs (43.59 usr 0.00 sys = 43.59 cpu)
+Time for select_range (20000:43500): 44 secs (43.58 usr 0.00 sys = 43.58 cpu)
+Time for select_group (91): 75 secs (75.48 usr 0.00 sys = 75.48 cpu)
+Time for min_max_on_key (3000): 25 secs (24.60 usr 0.00 sys = 24.60 cpu)
+Time for min_max (60): 115 secs (115.58 usr 0.00 sys = 115.58 cpu)
+Time for count_on_key (100): 18 secs (17.22 usr 0.00 sys = 17.22 cpu)
+Time for count (100): 49 secs (49.15 usr 0.00 sys = 49.15 cpu)
+
+Testing update with functions
+Time for update_key (500): 8 secs ( 8.00 usr 0.00 sys = 8.00 cpu)
+Time for update_key_big (501): 403 secs (402.89 usr 0.00 sys = 402.89 cpu)
+
+Testing delete
+Time for delete_key (500): 21 secs (21.33 usr 0.00 sys = 21.33 cpu)
+Time for delete_big (12): 186 secs (186.21 usr 0.00 sys = 186.21 cpu)
+
+Insert into table with 16 keys and with a primary key with 15 parts
+Time for insert_key (100000): 5181 secs (5181.56 usr 0.00 sys = 5181.56 cpu)
+
+Testing update of keys
+Time for update_of_key (256): 674 secs (674.29 usr 0.00 sys = 674.29 cpu)
+
+Deleting everything from table
+Time for delete_big (2): 687 secs (686.86 usr 0.00 sys = 686.86 cpu)
+
+Estimated total time: 15454 secs (15453.34 usr 0.00 sys = 15453.34 cpu)
diff --git a/sql-bench/Results-win32/insert-mysql-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase b/sql-bench/Results-win32/insert-mysql-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
new file mode 100644
index 00000000000..4782dc717df
--- /dev/null
+++ b/sql-bench/Results-win32/insert-mysql-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
@@ -0,0 +1,81 @@
+Testing server 'MySQL 3.22.16 gamma' at 1999-02-20 19:59:21
+
+Testing the speed of inserting data into 1 table and do some selects on it.
+The tests are done with a table that has 100000 rows.
+
+Generating random keys
+Creating tables
+Inserting 100000 rows in order
+0 : Sat Feb 20 19:59:22 1999
+10000 : Sat Feb 20 19:59:33 1999
+20000 : Sat Feb 20 19:59:43 1999
+30000 : Sat Feb 20 19:59:54 1999
+40000 : Sat Feb 20 20:00:05 1999
+50000 : Sat Feb 20 20:00:15 1999
+60000 : Sat Feb 20 20:00:26 1999
+70000 : Sat Feb 20 20:00:37 1999
+80000 : Sat Feb 20 20:00:48 1999
+90000 : Sat Feb 20 20:01:00 1999
+Inserting 100000 rows in reverse order
+0 : Sat Feb 20 20:01:11 1999
+10000 : Sat Feb 20 20:01:22 1999
+20000 : Sat Feb 20 20:01:33 1999
+30000 : Sat Feb 20 20:01:44 1999
+40000 : Sat Feb 20 20:01:55 1999
+50000 : Sat Feb 20 20:02:06 1999
+60000 : Sat Feb 20 20:02:18 1999
+70000 : Sat Feb 20 20:02:29 1999
+80000 : Sat Feb 20 20:02:40 1999
+90000 : Sat Feb 20 20:02:51 1999
+Inserting 100000 rows in random order
+0 : Sat Feb 20 20:03:02 1999
+10000 : Sat Feb 20 20:03:13 1999
+20000 : Sat Feb 20 20:03:24 1999
+30000 : Sat Feb 20 20:03:36 1999
+40000 : Sat Feb 20 20:03:47 1999
+50000 : Sat Feb 20 20:03:58 1999
+60000 : Sat Feb 20 20:04:09 1999
+70000 : Sat Feb 20 20:04:20 1999
+80000 : Sat Feb 20 20:04:31 1999
+90000 : Sat Feb 20 20:04:42 1999
+Time for insert (300000): 332 wallclock secs (58.41 usr + 41.64 sys = 100.05 CPU)
+
+Testing insert of duplicates
+Time for insert_duplicates (300000): 68 wallclock secs (16.34 usr + 13.36 sys = 29.70 CPU)
+
+Retrieving data from the table
+Time for select_big (10:3000000): 73 wallclock secs (41.15 usr + 19.92 sys = 61.07 CPU)
+Time for order_by_key (10:3000000): 73 wallclock secs (40.79 usr + 20.33 sys = 61.12 CPU)
+Time for order_by (10:3000000): 100 wallclock secs (40.72 usr + 19.97 sys = 60.69 CPU)
+Time for select_range_prefix (5000:20000): 12 wallclock secs ( 4.27 usr + 0.95 sys = 5.22 CPU)
+Time for select_range (5000:20000): 13 wallclock secs ( 4.34 usr + 1.00 sys = 5.34 CPU)
+Time for select_key_prefix (200000): 375 wallclock secs (158.15 usr + 38.91 sys = 197.05 CPU)
+Time for select_key (200000): 367 wallclock secs (157.27 usr + 40.25 sys = 197.51 CPU)
+
+Test of compares with simple ranges
+Time for select_range_prefix (20000:43500): 22 wallclock secs ( 8.37 usr + 2.09 sys = 10.46 CPU)
+Time for select_range (20000:43500): 22 wallclock secs ( 8.39 usr + 2.31 sys = 10.71 CPU)
+Time for select_group (91): 27 wallclock secs ( 0.06 usr + 0.01 sys = 0.07 CPU)
+Time for min_max_on_key (3000): 4 wallclock secs ( 2.17 usr + 0.59 sys = 2.76 CPU)
+Time for min_max (60): 26 wallclock secs ( 0.06 usr + 0.01 sys = 0.07 CPU)
+Time for count_on_key (100): 31 wallclock secs ( 0.08 usr + 0.04 sys = 0.12 CPU)
+Time for count (100): 54 wallclock secs ( 0.06 usr + 0.01 sys = 0.07 CPU)
+
+Testing update with functions
+Time for update_key (500): 0 wallclock secs ( 0.09 usr + 0.05 sys = 0.14 CPU)
+Time for update_key_big (501): 26 wallclock secs ( 0.10 usr + 0.06 sys = 0.16 CPU)
+
+Testing delete
+Time for delete_key (500): 1 wallclock secs ( 0.10 usr + 0.08 sys = 0.18 CPU)
+Time for delete_big (12): 14 wallclock secs ( 0.00 usr + 0.00 sys = 0.00 CPU)
+
+Insert into table with 16 keys and with a primary key with 15 parts
+Time for insert_key (100000): 2906 wallclock secs (27.77 usr + 14.64 sys = 42.41 CPU)
+
+Testing update of keys
+Time for update_of_key (256): 157 wallclock secs ( 0.04 usr + 0.04 sys = 0.08 CPU)
+
+Deleting everything from table
+Time for delete_big (2): 663 wallclock secs ( 0.01 usr + 0.00 sys = 0.01 CPU)
+
+Total time: 5368 wallclock secs (568.77 usr + 216.27 sys = 785.04 CPU)
diff --git a/sql-bench/Results-win32/insert-mysql-win98 b/sql-bench/Results-win32/insert-mysql-win98
new file mode 100644
index 00000000000..12c85e60dee
--- /dev/null
+++ b/sql-bench/Results-win32/insert-mysql-win98
@@ -0,0 +1,72 @@
+Testing server 'MySQL 3.23.13a alpha' at 2000-03-15 3:59:00
+
+Testing the speed of inserting data into 1 table and do some selects on it.
+The tests are done with a table that has 100000 rows.
+
+Generating random keys
+Creating tables
+Inserting 100000 rows in order
+Inserting 100000 rows in reverse order
+Inserting 100000 rows in random order
+Time for insert (300000): 438 wallclock secs (437.15 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing insert of duplicates
+Time for insert_duplicates (300000): 91 wallclock secs (91.06 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Retrieving data from the table
+Time for select_big (10:3000000): 173 wallclock secs (173.79 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for order_by_key (10:3000000): 175 wallclock secs (174.66 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for order_by (10:3000000): 249 wallclock secs (248.87 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_diff_key (500:1000): 241 wallclock secs (240.63 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_range_prefix (5010:42084): 33 wallclock secs (33.50 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_range (5010:42084): 34 wallclock secs (33.67 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_key_prefix (200000): 542 wallclock secs (542.23 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_key (200000): 540 wallclock secs (540.35 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Test of compares with simple ranges
+Time for select_range_prefix (20000:43500): 33 wallclock secs (33.12 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_range (20000:43500): 33 wallclock secs (33.45 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_group (111): 58 wallclock secs (58.22 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for min_max_on_key (3000): 7 wallclock secs ( 6.87 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for min_max (60): 33 wallclock secs (32.90 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for count_on_key (100): 52 wallclock secs (52.23 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for count (100): 55 wallclock secs (54.87 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing update of keys with functions
+Time for update_of_key (500): 1 wallclock secs ( 0.99 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for update_of_key_big (501): 38 wallclock secs (38.07 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing update with key
+Time for update_with_key (100000): 432 wallclock secs (432.20 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing update of all rows
+Time for update_big (500): 84 wallclock secs (83.33 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing left outer join
+Time for outer_join_on_key (10:10): 63 wallclock secs (63.33 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for outer_join (10:10): 146 wallclock secs (145.66 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for outer_join_found (10:10): 144 wallclock secs (144.40 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+75 queries in 74 loops of 500 loops took 606 seconds
+Estimated time for outer_join_not_found (500:506): 606 wallclock secs (605.55 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing delete
+Time for delete_key (500): 0 wallclock secs ( 0.82 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for delete_big (12): 22 wallclock secs (21.59 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Insert into table with 16 keys and with a primary key with 16 parts
+Time for insert_key (100000): 364 wallclock secs (363.72 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing update of keys
+Time for update_of_key (256): 58 wallclock secs (58.22 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Deleting everything from table
+Time for delete_big_many_keys (2): 112 wallclock secs (112.11 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Inserting 100000 rows with multiple values
+Time for multiple_value_insert (100000): 11 wallclock secs (11.64 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Time for drop table(1): 0 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Estimated total time: 8358 wallclock secs (8356.07 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results-win32/insert-mysql-win98-cmp-access,mysql b/sql-bench/Results-win32/insert-mysql-win98-cmp-access,mysql
new file mode 100644
index 00000000000..f45c0f45f36
--- /dev/null
+++ b/sql-bench/Results-win32/insert-mysql-win98-cmp-access,mysql
@@ -0,0 +1,64 @@
+Testing server 'MySQL 3.23.8 alpha' at 2000-01-04 12:26:26
+
+Testing the speed of inserting data into 1 table and do some selects on it.
+The tests are done with a table that has 100000 rows.
+
+Generating random keys
+Creating tables
+Inserting 100000 rows in order
+Inserting 100000 rows in reverse order
+Inserting 100000 rows in random order
+Time for insert (300000): 486 wallclock secs (486.04 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing insert of duplicates
+Time for insert_duplicates (300000): 107 wallclock secs (106.89 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Retrieving data from the table
+Time for select_big (10:3000000): 192 wallclock secs (191.85 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for order_by_key (10:3000000): 192 wallclock secs (192.79 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for order_by (10:3000000): 282 wallclock secs (281.88 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_diff_key (500:1000): 264 wallclock secs (263.97 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_range_prefix (5010:42084): 38 wallclock secs (37.95 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_range (5010:42084): 38 wallclock secs (38.06 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+188074 queries in 94037 loops of 100000 loops took 601 seconds
+Estimated time for select_key_prefix (200000): 639 wallclock secs (638.34 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+189130 queries in 94565 loops of 100000 loops took 601 seconds
+Estimated time for select_key (200000): 635 wallclock secs (635.54 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Test of compares with simple ranges
+Time for select_range_prefix (20000:43500): 38 wallclock secs (38.28 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_range (20000:43500): 38 wallclock secs (38.62 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_group (91): 40 wallclock secs (39.38 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for min_max_on_key (3000): 8 wallclock secs ( 7.96 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for min_max (60): 34 wallclock secs (33.78 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for count_on_key (100): 54 wallclock secs (54.27 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for count (100): 58 wallclock secs (57.94 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing update of keys with functions
+Time for update_of_key (500): 1 wallclock secs ( 1.16 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for update_of_key_big (501): 40 wallclock secs (39.93 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing update with key
+Time for update_with_key (100000): 485 wallclock secs (484.77 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing update of all rows
+Time for update_big (500): 96 wallclock secs (96.78 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing delete
+Time for delete_key (500): 1 wallclock secs ( 0.93 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for delete_big (12): 27 wallclock secs (26.15 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Insert into table with 16 keys and with a primary key with 10 parts
+Time for insert_key (100000): 367 wallclock secs (367.34 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing update of keys
+Time for update_of_key (256): 53 wallclock secs (52.84 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Deleting everything from table
+Time for delete_big_many_keys (2): 102 wallclock secs (102.60 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Estimated total time: 4315 wallclock secs (4316.21 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results-win32/insert-mysql_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase b/sql-bench/Results-win32/insert-mysql_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
new file mode 100644
index 00000000000..5149348b5d4
--- /dev/null
+++ b/sql-bench/Results-win32/insert-mysql_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
@@ -0,0 +1,81 @@
+Testing server 'MySQL 3.22.16 gamma' at 1999-02-07 11:54:41
+
+Testing the speed of inserting data into 1 table and do some selects on it.
+The tests are done with a table that has 100000 rows.
+
+Generating random keys
+Creating tables
+Inserting 100000 rows in order
+0 : Sun Feb 7 11:54:43 1999
+10000 : Sun Feb 7 11:55:01 1999
+20000 : Sun Feb 7 11:55:18 1999
+30000 : Sun Feb 7 11:55:36 1999
+40000 : Sun Feb 7 11:55:53 1999
+50000 : Sun Feb 7 11:56:11 1999
+60000 : Sun Feb 7 11:56:28 1999
+70000 : Sun Feb 7 11:56:46 1999
+80000 : Sun Feb 7 11:57:03 1999
+90000 : Sun Feb 7 11:57:21 1999
+Inserting 100000 rows in reverse order
+0 : Sun Feb 7 11:57:38 1999
+10000 : Sun Feb 7 11:57:56 1999
+20000 : Sun Feb 7 11:58:14 1999
+30000 : Sun Feb 7 11:58:32 1999
+40000 : Sun Feb 7 11:58:50 1999
+50000 : Sun Feb 7 11:59:08 1999
+60000 : Sun Feb 7 11:59:26 1999
+70000 : Sun Feb 7 11:59:44 1999
+80000 : Sun Feb 7 12:00:03 1999
+90000 : Sun Feb 7 12:00:21 1999
+Inserting 100000 rows in random order
+0 : Sun Feb 7 12:00:39 1999
+10000 : Sun Feb 7 12:00:57 1999
+20000 : Sun Feb 7 12:01:15 1999
+30000 : Sun Feb 7 12:01:33 1999
+40000 : Sun Feb 7 12:01:51 1999
+50000 : Sun Feb 7 12:02:09 1999
+60000 : Sun Feb 7 12:02:27 1999
+70000 : Sun Feb 7 12:02:45 1999
+80000 : Sun Feb 7 12:03:03 1999
+90000 : Sun Feb 7 12:03:21 1999
+Time for insert (300000): 536 secs (535.99 usr 0.00 sys = 535.99 cpu)
+
+Testing insert of duplicates
+Time for insert_duplicates (300000): 144 secs (143.90 usr 0.00 sys = 143.90 cpu)
+
+Retrieving data from the table
+Time for select_big (10:3000000): 354 secs (353.98 usr 0.00 sys = 353.98 cpu)
+Time for order_by_key (10:3000000): 355 secs (355.39 usr 0.00 sys = 355.39 cpu)
+Time for order_by (10:3000000): 382 secs (381.52 usr 0.00 sys = 381.52 cpu)
+Time for select_range_prefix (5000:20000): 18 secs (17.77 usr 0.00 sys = 17.77 cpu)
+Time for select_range (5000:20000): 18 secs (17.89 usr 0.00 sys = 17.89 cpu)
+Time for select_key_prefix (200000): 470 secs (470.56 usr 0.00 sys = 470.56 cpu)
+Time for select_key (200000): 464 secs (463.54 usr 0.00 sys = 463.54 cpu)
+
+Test of compares with simple ranges
+Time for select_range_prefix (20000:43500): 33 secs (32.88 usr 0.00 sys = 32.88 cpu)
+Time for select_range (20000:43500): 32 secs (32.18 usr 0.00 sys = 32.18 cpu)
+Time for select_group (91): 28 secs (28.33 usr 0.00 sys = 28.33 cpu)
+Time for min_max_on_key (3000): 7 secs ( 6.69 usr 0.00 sys = 6.69 cpu)
+Time for min_max (60): 28 secs (28.04 usr 0.00 sys = 28.04 cpu)
+Time for count_on_key (100): 34 secs (33.86 usr 0.00 sys = 33.86 cpu)
+Time for count (100): 58 secs (58.27 usr 0.00 sys = 58.27 cpu)
+
+Testing update with functions
+Time for update_key (500): 1 secs ( 0.95 usr 0.00 sys = 0.95 cpu)
+Time for update_key_big (501): 26 secs (26.35 usr 0.00 sys = 26.35 cpu)
+
+Testing delete
+Time for delete_key (500): 2 secs ( 1.83 usr 0.00 sys = 1.83 cpu)
+Time for delete_big (12): 15 secs (15.01 usr 0.00 sys = 15.01 cpu)
+
+Insert into table with 16 keys and with a primary key with 15 parts
+Time for insert_key (100000): 2908 secs (2907.97 usr 0.00 sys = 2907.97 cpu)
+
+Testing update of keys
+Time for update_of_key (256): 164 secs (163.52 usr 0.00 sys = 163.52 cpu)
+
+Deleting everything from table
+Time for delete_big (2): 665 secs (665.36 usr 0.00 sys = 665.36 cpu)
+
+Total time: 6744 secs (6743.40 usr 0.00 sys = 6743.40 cpu)
diff --git a/sql-bench/Results-win32/insert-oracle_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase b/sql-bench/Results-win32/insert-oracle_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
new file mode 100644
index 00000000000..03c00927dcc
--- /dev/null
+++ b/sql-bench/Results-win32/insert-oracle_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
@@ -0,0 +1,69 @@
+Testing server 'Oracle 8.0.4.0.0' at 1999-04-04 3:50:22
+
+Testing the speed of inserting data into 1 table and do some selects on it.
+The tests are done with a table that has 100000 rows.
+
+Generating random keys
+Creating tables
+Inserting 100000 rows in order
+Inserting 100000 rows in reverse order
+Inserting 100000 rows in random order
+Time for insert (300000): 2511 wallclock secs (425.27 usr 50.44 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing insert of duplicates
+Time for insert_duplicates (300000): 353 wallclock secs (195.15 usr 26.95 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Retrieving data from the table
+Time for select_big (10:3000000): 1130 wallclock secs (575.36 usr 100.01 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+6 queries in 6 loops of 10 loops took 675 seconds
+Estimated time for order_by_key (10:1800000): 1125 wallclock secs (580.64 usr 95.55 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+6 queries in 6 loops of 10 loops took 659 seconds
+Estimated time for order_by (10:1800000): 1098 wallclock secs (570.85 usr 95.67 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_range_prefix (5000:20000): 31 wallclock secs (18.04 usr 3.01 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+410 queries in 410 loops of 5000 loops took 608 seconds
+Estimated time for select_range (5000:1640): 7414 wallclock secs (19.17 usr 3.06 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+115830 queries in 57915 loops of 100000 loops took 601 seconds
+Estimated time for select_key_prefix (200000): 1037 wallclock secs (576.33 usr 93.13 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+1384 queries in 692 loops of 100000 loops took 601 seconds
+Estimated time for select_key (200000): 86849 wallclock secs (639.74 usr 105.64 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Test of compares with simple ranges
+Time for select_range_prefix (20000:43500): 64 wallclock secs (40.72 usr 5.17 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+1400 queries in 35 loops of 500 loops took 605 seconds
+Estimated time for select_range (20000:3045): 605 wallclock secs ( 3.09 usr 0.29 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_group (91): 45 wallclock secs ( 0.15 usr 0.08 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for min_max_on_key (3000): 15 wallclock secs ( 9.59 usr 1.60 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for min_max (60): 25 wallclock secs ( 0.22 usr 0.03 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for count_on_key (100): 37 wallclock secs ( 0.33 usr 0.04 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for count (100): 51 wallclock secs ( 0.30 usr 0.04 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing update with functions
+Time for update_key (500): 220 wallclock secs ( 0.76 usr 0.07 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for update_key_big (501): 429 wallclock secs ( 0.83 usr 0.20 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing delete
+Time for delete_key (500): 628 wallclock secs ( 0.70 usr 0.16 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for delete_big (12): 399 wallclock secs ( 0.09 usr 0.17 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Insert into table with 16 keys and with a primary key with 15 parts
+Time for insert_key (100000): 1293 wallclock secs (151.81 usr 16.58 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing update of keys
+Time for update_of_key (256): 568 wallclock secs ( 0.30 usr 0.06 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Deleting everything from table
+Time for delete_big (2): 378 wallclock secs ( 0.00 usr 0.01 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Estimated total time: 114468 wallclock secs (3850.94 usr 602.34 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results-win32/insert-solid_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase b/sql-bench/Results-win32/insert-solid_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
new file mode 100644
index 00000000000..191e9b11934
--- /dev/null
+++ b/sql-bench/Results-win32/insert-solid_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
@@ -0,0 +1,102 @@
+Testing server 'Solid version ???' at 1998-10-23 9:11:17
+
+Testing the speed of inserting data into 1 table and do some selects on it.
+The tests are done with a table that has 100000 rows.
+
+Generating random keys
+Creating tables
+Inserting 100000 rows in order
+0 : Fri Oct 23 09:11:20 1998
+10000 : Fri Oct 23 09:12:05 1998
+20000 : Fri Oct 23 09:12:51 1998
+30000 : Fri Oct 23 09:13:38 1998
+40000 : Fri Oct 23 09:14:25 1998
+50000 : Fri Oct 23 09:15:13 1998
+60000 : Fri Oct 23 09:16:01 1998
+70000 : Fri Oct 23 09:16:49 1998
+80000 : Fri Oct 23 09:17:37 1998
+90000 : Fri Oct 23 09:18:25 1998
+Inserting 100000 rows in reverse order
+0 : Fri Oct 23 09:19:14 1998
+10000 : Fri Oct 23 09:20:02 1998
+20000 : Fri Oct 23 09:20:49 1998
+30000 : Fri Oct 23 09:21:36 1998
+40000 : Fri Oct 23 09:22:23 1998
+50000 : Fri Oct 23 09:23:11 1998
+60000 : Fri Oct 23 09:24:00 1998
+70000 : Fri Oct 23 09:24:48 1998
+80000 : Fri Oct 23 09:25:37 1998
+90000 : Fri Oct 23 09:26:25 1998
+Inserting 100000 rows in random order
+0 : Fri Oct 23 09:27:13 1998
+10000 : Fri Oct 23 09:28:01 1998
+20000 : Fri Oct 23 09:28:50 1998
+30000 : Fri Oct 23 09:29:39 1998
+40000 : Fri Oct 23 09:30:30 1998
+50000 : Fri Oct 23 09:31:21 1998
+60000 : Fri Oct 23 09:32:13 1998
+70000 : Fri Oct 23 09:33:06 1998
+80000 : Fri Oct 23 09:34:00 1998
+90000 : Fri Oct 23 09:34:55 1998
+Time for insert (300000): 1468 secs (1468.33 usr 0.00 sys = 1468.33 cpu)
+
+Testing insert of duplicates
+Time for insert_duplicates (300000): 172 secs (172.25 usr 0.00 sys = 172.25 cpu)
+
+Retrieving data from the table
+Time for select_big (10:3000000): 589 secs (588.93 usr 0.00 sys = 588.93 cpu)
+Time for order_by_key (10:3000000): 653 secs (653.06 usr 0.00 sys = 653.06 cpu)
+Time for order_by (10:3000000): 648 secs (647.94 usr 0.00 sys = 647.94 cpu)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+140 queries in 140 loops of 5000 loops took 614 seconds
+Estimated time for select_range_prefix (5000:560): 21928 secs (21912.93 usr 0.00 sys = 21912.93 cpu)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+140 queries in 140 loops of 5000 loops took 617 seconds
+Estimated time for select_range (5000:560): 22035 secs (22045.64 usr 0.00 sys = 22045.64 cpu)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+142458 queries in 71229 loops of 100000 loops took 601 seconds
+Estimated time for select_key_prefix (200000): 843 secs (842.99 usr 0.00 sys = 842.99 cpu)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+136926 queries in 68463 loops of 100000 loops took 601 seconds
+Estimated time for select_key (200000): 877 secs (877.85 usr 0.00 sys = 877.85 cpu)
+
+Test of compares with simple ranges
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+360 queries in 9 loops of 500 loops took 620 seconds
+Estimated time for select_range_prefix (20000:783): 620 secs (620.05 usr 0.00 sys = 620.05 cpu)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+360 queries in 9 loops of 500 loops took 622 seconds
+Estimated time for select_range (20000:783): 622 secs (622.63 usr 0.00 sys = 622.63 cpu)
+Time for select_group (91): 2495 secs (2494.69 usr 0.00 sys = 2494.69 cpu)
+Time for min_max_on_key (3000): 13 secs (13.34 usr 0.00 sys = 13.34 cpu)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+54 queries in 9 loops of 500 loops took 655 seconds
+Estimated time for min_max (3000): 36388 secs (36350.61 usr 0.00 sys = 36350.61 cpu)
+Time for count_on_key (100): 2139 secs (2139.16 usr 0.00 sys = 2139.16 cpu)
+Time for count (100): 2221 secs (2220.87 usr 0.00 sys = 2220.87 cpu)
+
+Testing update with functions
+Time for update_key (500): 2 secs ( 2.71 usr 0.00 sys = 2.71 cpu)
+Time for update_key_big (501): 994 secs (993.63 usr 0.00 sys = 993.63 cpu)
+
+Testing delete
+Time for delete_key (500): 65 secs (65.34 usr 0.00 sys = 65.34 cpu)
+Time for delete_big (12): 492 secs (491.75 usr 0.00 sys = 491.75 cpu)
+
+Insert into table with 16 keys and with a primary key with 15 parts
+Time for insert_key (100000): 9758 secs (9757.93 usr 0.00 sys = 9757.93 cpu)
+
+Testing update of keys
+Time for update_of_key (256): 16656 secs (16655.63 usr 0.00 sys = 16655.63 cpu)
+
+Deleting everything from table
+Time for delete_big (2): 1736 secs (1735.77 usr 0.00 sys = 1735.77 cpu)
+
+Estimated total time: 192155 secs (192149.60 usr 0.00 sys = 192149.60 cpu)
diff --git a/sql-bench/Results-win32/insert-sybase_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase b/sql-bench/Results-win32/insert-sybase_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
new file mode 100644
index 00000000000..b5cd78f3c4a
--- /dev/null
+++ b/sql-bench/Results-win32/insert-sybase_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
@@ -0,0 +1,99 @@
+Testing server 'Sybase enterprise 11.5 NT' at 1998-10-02 8:13:25
+
+Testing the speed of inserting data into 1 table and do some selects on it.
+The tests are done with a table that has 100000 rows.
+
+Generating random keys
+Creating tables
+Inserting 100000 rows in order
+0 : Fri Oct 2 08:13:31 1998
+10000 : Fri Oct 2 08:15:49 1998
+20000 : Fri Oct 2 08:18:01 1998
+30000 : Fri Oct 2 08:20:14 1998
+40000 : Fri Oct 2 08:22:27 1998
+50000 : Fri Oct 2 08:24:48 1998
+60000 : Fri Oct 2 08:27:19 1998
+70000 : Fri Oct 2 08:30:03 1998
+80000 : Fri Oct 2 08:32:09 1998
+90000 : Fri Oct 2 08:34:12 1998
+Inserting 100000 rows in reverse order
+0 : Fri Oct 2 08:36:14 1998
+10000 : Fri Oct 2 08:38:17 1998
+20000 : Fri Oct 2 08:40:22 1998
+30000 : Fri Oct 2 08:42:31 1998
+40000 : Fri Oct 2 08:44:39 1998
+50000 : Fri Oct 2 08:46:43 1998
+60000 : Fri Oct 2 08:48:50 1998
+70000 : Fri Oct 2 08:51:04 1998
+80000 : Fri Oct 2 08:53:26 1998
+90000 : Fri Oct 2 08:56:23 1998
+Inserting 100000 rows in random order
+0 : Fri Oct 2 08:58:39 1998
+10000 : Fri Oct 2 09:01:03 1998
+20000 : Fri Oct 2 09:04:49 1998
+30000 : Fri Oct 2 09:08:33 1998
+40000 : Fri Oct 2 09:12:29 1998
+50000 : Fri Oct 2 09:15:12 1998
+60000 : Fri Oct 2 09:18:09 1998
+70000 : Fri Oct 2 09:21:29 1998
+80000 : Fri Oct 2 09:24:42 1998
+90000 : Fri Oct 2 09:28:39 1998
+Time for insert (300000): 4682 secs (4681.62 usr 0.00 sys = 4681.62 cpu)
+
+Testing insert of duplicates
+Time for insert_duplicates (300000): 331 secs (331.28 usr 0.00 sys = 331.28 cpu)
+
+Retrieving data from the table
+Time for select_big (10:3000000): 275 secs (275.20 usr 0.00 sys = 275.20 cpu)
+Time for order_by_key (10:3000000): 273 secs (272.97 usr 0.00 sys = 272.97 cpu)
+Time for order_by (10:3000000): 395 secs (394.89 usr 0.00 sys = 394.89 cpu)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+1490 queries in 1490 loops of 5000 loops took 601 seconds
+Estimated time for select_range_prefix (5000:5960): 2016 secs (2017.70 usr 0.00 sys = 2017.70 cpu)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+1490 queries in 1490 loops of 5000 loops took 603 seconds
+Estimated time for select_range (5000:5960): 2023 secs (2021.03 usr 0.00 sys = 2021.03 cpu)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+6904 queries in 3452 loops of 100000 loops took 601 seconds
+Estimated time for select_key_prefix (200000): 17410 secs (17410.02 usr 0.00 sys = 17410.02 cpu)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+6824 queries in 3412 loops of 100000 loops took 601 seconds
+Estimated time for select_key (200000): 17614 secs (17614.13 usr 0.00 sys = 17614.13 cpu)
+
+Test of compares with simple ranges
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+2920 queries in 73 loops of 500 loops took 602 seconds
+Estimated time for select_range_prefix (20000:6351): 602 secs (602.38 usr 0.00 sys = 602.38 cpu)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+2920 queries in 73 loops of 500 loops took 603 seconds
+Estimated time for select_range (20000:6351): 603 secs (603.08 usr 0.00 sys = 603.08 cpu)
+Time for select_group (91): 56 secs (55.88 usr 0.00 sys = 55.88 cpu)
+Time for min_max_on_key (3000): 96 secs (96.64 usr 0.00 sys = 96.64 cpu)
+Time for min_max (60): 17 secs (16.74 usr 0.00 sys = 16.74 cpu)
+Time for count_on_key (100): 14 secs (14.21 usr 0.00 sys = 14.21 cpu)
+Time for count (100): 23 secs (22.40 usr 0.00 sys = 22.40 cpu)
+
+Testing update with functions
+Time for update_key (500): 40 secs (39.90 usr 0.00 sys = 39.90 cpu)
+Time for update_key_big (501): 347 secs (347.05 usr 0.00 sys = 347.05 cpu)
+
+Testing delete
+Time for delete_key (500): 43 secs (42.44 usr 0.00 sys = 42.44 cpu)
+Time for delete_big (12): 181 secs (181.45 usr 0.00 sys = 181.45 cpu)
+
+Insert into table with 16 keys and with a primary key with 15 parts
+Time for insert_key (100000): 7053 secs (7053.03 usr 0.00 sys = 7053.03 cpu)
+
+Testing update of keys
+Time for update_of_key (256): 1023 secs (1022.68 usr 0.00 sys = 1022.68 cpu)
+
+Deleting everything from table
+Time for delete_big (2): 7736 secs (7735.26 usr 0.00 sys = 7735.26 cpu)
+
+Estimated total time: 69907 secs (69908.40 usr 0.00 sys = 69908.40 cpu)
diff --git a/sql-bench/Results-win32/select-access_odbc-win98-cmp-access,mysql b/sql-bench/Results-win32/select-access_odbc-win98-cmp-access,mysql
new file mode 100644
index 00000000000..b51c2999152
--- /dev/null
+++ b/sql-bench/Results-win32/select-access_odbc-win98-cmp-access,mysql
@@ -0,0 +1,19 @@
+Testing server 'Access 2000' at 2000-01-04 0:50:34
+
+Testing the speed of selecting on keys that consist of many parts
+The test-table has 10000 rows and the test is done with 45.5 ranges.
+
+Creating table
+Inserting 10000 rows
+Time to insert (10000): 69 wallclock secs (68.33 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing big selects on the table
+Time for select_big (70:17207): 4 wallclock secs ( 3.96 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_range (410:248587): 63 wallclock secs (63.11 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+37233 queries in 5319 loops of 10000 loops took 601 seconds
+Estimated time for min_max_on_key (70000): 1129 wallclock secs (1129.48 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for count_on_key (50000): 445 wallclock secs (445.17 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Estimated total time: 1710 wallclock secs (1710.98 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results-win32/select-db2_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase b/sql-bench/Results-win32/select-db2_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
new file mode 100644
index 00000000000..7408c75b6a6
--- /dev/null
+++ b/sql-bench/Results-win32/select-db2_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
@@ -0,0 +1,22 @@
+Testing server 'IBM DB2 5' at 1999-02-02 3:47:34
+
+Testing the speed of selecting on keys that consist of many parts
+The test-table has 10000 rows and the test is done with 8.5 ranges.
+
+Creating table
+Inserting 10000 rows
+Time to insert (10000): 97 secs (97.40 usr 0.00 sys = 97.40 cpu)
+
+Testing big selects on the table
+Time for select_big (70:17207): 4 secs ( 3.28 usr 0.00 sys = 3.28 cpu)
+Time for select_range (400:61130): 24 secs (23.86 usr 0.00 sys = 23.86 cpu)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+39872 queries in 5696 loops of 10000 loops took 601 seconds
+Estimated time for min_max_on_key (70000): 1055 secs (1055.01 usr 0.00 sys = 1055.01 cpu)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+39885 queries in 7977 loops of 10000 loops took 601 seconds
+Estimated time for count_key (50000): 753 secs (753.46 usr 0.00 sys = 753.46 cpu)
+
+Estimated total time: 1934 secs (1934.67 usr 0.00 sys = 1934.67 cpu)
diff --git a/sql-bench/Results-win32/select-informix_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase b/sql-bench/Results-win32/select-informix_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
new file mode 100644
index 00000000000..f3c45dd6258
--- /dev/null
+++ b/sql-bench/Results-win32/select-informix_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
@@ -0,0 +1,19 @@
+Testing server 'Informix 7.30C1 ' at 1998-10-06 1:41:01
+
+Testing the speed of selecting on keys that consist of many parts
+The test-table has 10000 rows and the test is done with 8.5 ranges.
+
+Creating table
+Inserting 10000 rows
+Time to insert (10000): 51 secs (51.92 usr 0.00 sys = 51.92 cpu)
+
+Testing big selects on the table
+Time for select_big (70:17207): 12 secs (11.92 usr 0.00 sys = 11.92 cpu)
+Time for select_range (400:61130): 29 secs (28.45 usr 0.00 sys = 28.45 cpu)
+Time for min_max_on_key (70000): 475 secs (474.89 usr 0.00 sys = 474.89 cpu)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+3840 queries in 768 loops of 10000 loops took 601 seconds
+Estimated time for count_key (50000): 7825 secs (7824.40 usr 0.00 sys = 7824.40 cpu)
+
+Estimated total time: 8393 secs (8391.74 usr 0.00 sys = 8391.74 cpu)
diff --git a/sql-bench/Results-win32/select-ms-sql_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase b/sql-bench/Results-win32/select-ms-sql_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
new file mode 100644
index 00000000000..4475ad4572c
--- /dev/null
+++ b/sql-bench/Results-win32/select-ms-sql_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
@@ -0,0 +1,19 @@
+Testing server 'Microsoft SQL Server 7.00 - 7.00.517 (Intel X86) ' at 1998-09-07 14:22:16
+
+Testing the speed of selecting on keys that consist of many parts
+The test-table has 10000 rows and the test is done with 8.5 ranges.
+
+Creating table
+Inserting 10000 rows
+Time to insert (10000): 93 secs (93.21 usr 0.00 sys = 93.21 cpu)
+
+Testing big selects on the table
+Time for select_big (70:17207): 2 secs ( 2.32 usr 0.00 sys = 2.32 cpu)
+Time for select_range (400:61130): 19 secs (18.64 usr 0.00 sys = 18.64 cpu)
+Time for min_max_on_key (70000): 308 secs (308.18 usr 0.00 sys = 308.18 cpu)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+39370 queries in 7874 loops of 10000 loops took 601 seconds
+Estimated time for count_key (50000): 763 secs (762.84 usr 0.00 sys = 762.84 cpu)
+
+Estimated total time: 1186 secs (1185.72 usr 0.00 sys = 1185.72 cpu)
diff --git a/sql-bench/Results-win32/select-mysql-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase b/sql-bench/Results-win32/select-mysql-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
new file mode 100644
index 00000000000..e41c1620a2c
--- /dev/null
+++ b/sql-bench/Results-win32/select-mysql-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
@@ -0,0 +1,19 @@
+Testing server 'MySQL 3.22.16 gamma' at 1999-02-20 21:28:50
+
+Testing the speed of selecting on keys that consist of many parts
+The test-table has 10000 rows and the test is done with 8.5 ranges.
+
+Creating table
+Inserting 10000 rows
+Time to insert (10000): 12 wallclock secs ( 2.52 usr + 1.26 sys = 3.79 CPU)
+
+Testing big selects on the table
+Time for select_big (70:17207): 1 wallclock secs ( 0.23 usr + 0.11 sys = 0.34 CPU)
+Time for select_range (400:61130): 5 wallclock secs ( 1.21 usr + 0.42 sys = 1.63 CPU)
+Time for min_max_on_key (70000): 216 wallclock secs (49.80 usr + 13.51 sys = 63.31 CPU)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+45135 queries in 9027 loops of 10000 loops took 601 seconds
+Estimated time for count_key (50000): 665 wallclock secs (36.67 usr + 9.66 sys = 46.33 CPU)
+
+Estimated total time: 899 wallclock secs (90.43 usr + 24.97 sys = 115.41 CPU)
diff --git a/sql-bench/Results-win32/select-mysql-win98 b/sql-bench/Results-win32/select-mysql-win98
new file mode 100644
index 00000000000..c028aaf9661
--- /dev/null
+++ b/sql-bench/Results-win32/select-mysql-win98
@@ -0,0 +1,16 @@
+Testing server 'MySQL 3.23.13a alpha' at 2000-03-15 5:20:12
+
+Testing the speed of selecting on keys that consist of many parts
+The test-table has 10000 rows and the test is done with 500 ranges.
+
+Creating table
+Inserting 10000 rows
+Time to insert (10000): 16 wallclock secs (15.32 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing big selects on the table
+Time for select_big (70:17207): 1 wallclock secs ( 1.81 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_range (410:1057904): 356 wallclock secs (356.09 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for min_max_on_key (70000): 332 wallclock secs (332.69 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for count_on_key (50000): 588 wallclock secs (587.48 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Total time: 1294 wallclock secs (1293.83 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results-win32/select-mysql-win98-cmp-access,mysql b/sql-bench/Results-win32/select-mysql-win98-cmp-access,mysql
new file mode 100644
index 00000000000..3607cb4d07e
--- /dev/null
+++ b/sql-bench/Results-win32/select-mysql-win98-cmp-access,mysql
@@ -0,0 +1,19 @@
+Testing server 'MySQL 3.23.8 alpha' at 2000-01-04 13:37:12
+
+Testing the speed of selecting on keys that consist of many parts
+The test-table has 10000 rows and the test is done with 40 ranges.
+
+Creating table
+Inserting 10000 rows
+Time to insert (10000): 19 wallclock secs (19.39 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing big selects on the table
+Time for select_big (70:17207): 2 wallclock secs ( 1.97 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_range (410:214316): 37 wallclock secs (36.36 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for min_max_on_key (70000): 352 wallclock secs (352.24 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+46695 queries in 9339 loops of 10000 loops took 601 seconds
+Estimated time for count_on_key (50000): 643 wallclock secs (643.18 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Estimated total time: 1053 wallclock secs (1053.14 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results-win32/select-mysql_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase b/sql-bench/Results-win32/select-mysql_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
new file mode 100644
index 00000000000..64e97b34913
--- /dev/null
+++ b/sql-bench/Results-win32/select-mysql_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
@@ -0,0 +1,19 @@
+Testing server 'MySQL 3.22.16 gamma' at 1999-02-07 13:47:07
+
+Testing the speed of selecting on keys that consist of many parts
+The test-table has 10000 rows and the test is done with 8.5 ranges.
+
+Creating table
+Inserting 10000 rows
+Time to insert (10000): 18 secs (17.89 usr 0.00 sys = 17.89 cpu)
+
+Testing big selects on the table
+Time for select_big (70:17207): 3 secs ( 2.81 usr 0.00 sys = 2.81 cpu)
+Time for select_range (400:61130): 12 secs (11.82 usr 0.00 sys = 11.82 cpu)
+Time for min_max_on_key (70000): 261 secs (261.04 usr 0.00 sys = 261.04 cpu)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+42345 queries in 8469 loops of 10000 loops took 601 seconds
+Estimated time for count_key (50000): 709 secs (709.52 usr 0.00 sys = 709.52 cpu)
+
+Estimated total time: 1003 secs (1003.10 usr 0.00 sys = 1003.10 cpu)
diff --git a/sql-bench/Results-win32/select-oracle_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase b/sql-bench/Results-win32/select-oracle_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
new file mode 100644
index 00000000000..fd7f03a54a6
--- /dev/null
+++ b/sql-bench/Results-win32/select-oracle_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
@@ -0,0 +1,22 @@
+Testing server 'Oracle 8.0.4.0.0' at 1999-04-04 7:11:38
+
+Testing the speed of selecting on keys that consist of many parts
+The test-table has 10000 rows and the test is done with 8.5 ranges.
+
+Creating table
+Inserting 10000 rows
+Time to insert (10000): 81 wallclock secs (13.55 usr 1.50 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing big selects on the table
+Time for select_big (70:17207): 9 wallclock secs ( 3.35 usr 0.54 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_range (400:61130): 53 wallclock secs (14.24 usr 1.92 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+36078 queries in 5154 loops of 10000 loops took 601 seconds
+Estimated time for min_max_on_key (70000): 1166 wallclock secs (155.66 usr 33.79 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+36075 queries in 7215 loops of 10000 loops took 601 seconds
+Estimated time for count_on_key (50000): 832 wallclock secs (118.15 usr 25.25 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Estimated total time: 2147 wallclock secs (304.96 usr 63.03 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results-win32/select-solid_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase b/sql-bench/Results-win32/select-solid_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
new file mode 100644
index 00000000000..2a83ce0e6ad
--- /dev/null
+++ b/sql-bench/Results-win32/select-solid_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
@@ -0,0 +1,22 @@
+Testing server 'Solid version ???' at 1998-10-08 16:21:29
+
+Testing the speed of selecting on keys that consist of many parts
+The test-table has 10000 rows and the test is done with 8.5 ranges.
+
+Creating table
+Inserting 10000 rows
+Time to insert (10000): 55 secs (55.66 usr 0.00 sys = 55.66 cpu)
+
+Testing big selects on the table
+Time for select_big (70:17207): 5 secs ( 5.04 usr 0.00 sys = 5.04 cpu)
+Time for select_range (400:61800): 106 secs (105.79 usr 0.00 sys = 105.79 cpu)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+3661 queries in 523 loops of 10000 loops took 601 seconds
+Estimated time for min_max_on_key (70000): 11491 secs (11490.52 usr 0.00 sys = 11490.52 cpu)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+1785 queries in 357 loops of 10000 loops took 602 seconds
+Estimated time for count_key (50000): 16862 secs (16847.20 usr 0.00 sys = 16847.20 cpu)
+
+Estimated total time: 28523 secs (28507.76 usr 0.00 sys = 28507.76 cpu)
diff --git a/sql-bench/Results-win32/wisconsin-access_odbc-win98-cmp-access,mysql b/sql-bench/Results-win32/wisconsin-access_odbc-win98-cmp-access,mysql
new file mode 100644
index 00000000000..bc3161800aa
--- /dev/null
+++ b/sql-bench/Results-win32/wisconsin-access_odbc-win98-cmp-access,mysql
@@ -0,0 +1,14 @@
+Testing server 'Access 2000' at 2000-01-04 1:10:19
+
+Wisconsin benchmark test
+
+Time for create_table (3): 1 wallclock secs ( 0.17 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Inserting data
+Time to insert (31000): 246 wallclock secs (246.83 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time to delete_big (1): 2 wallclock secs ( 1.32 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Running actual benchmark
+Time for wisc_benchmark (114): 33 wallclock secs (33.17 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Total time: 282 wallclock secs (281.60 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results-win32/wisconsin-db2_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase b/sql-bench/Results-win32/wisconsin-db2_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
new file mode 100644
index 00000000000..12e5cc45966
--- /dev/null
+++ b/sql-bench/Results-win32/wisconsin-db2_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
@@ -0,0 +1,14 @@
+Testing server 'IBM DB2 5' at 1999-02-02 4:09:47
+
+Wisconsin benchmark test
+
+Time for create_table (3): 3 secs ( 3.03 usr 0.00 sys = 3.03 cpu)
+
+Inserting data
+Time to insert (31000): 330 secs (329.62 usr 0.00 sys = 329.62 cpu)
+Time to delete_big (1): 2 secs ( 1.86 usr 0.00 sys = 1.86 cpu)
+
+Running actual benchmark
+Time for wisc_benchmark (114): 32 secs (32.10 usr 0.00 sys = 32.10 cpu)
+
+Total time: 368 secs (367.48 usr 0.00 sys = 367.48 cpu)
diff --git a/sql-bench/Results-win32/wisconsin-informix_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase b/sql-bench/Results-win32/wisconsin-informix_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
new file mode 100644
index 00000000000..b05d8a1472e
--- /dev/null
+++ b/sql-bench/Results-win32/wisconsin-informix_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
@@ -0,0 +1,14 @@
+Testing server 'Informix 7.30C1 ' at 1998-10-06 2:00:31
+
+Wisconsin benchmark test
+
+Time for create_table (3): 0 secs ( 0.25 usr 0.00 sys = 0.25 cpu)
+
+Inserting data
+Time to insert (31000): 171 secs (170.83 usr 0.00 sys = 170.83 cpu)
+Time to delete_big (1): 2 secs ( 2.36 usr 0.00 sys = 2.36 cpu)
+
+Running actual benchmark
+Time for wisc_benchmark (114): 45 secs (44.91 usr 0.00 sys = 44.91 cpu)
+
+Total time: 219 secs (219.03 usr 0.00 sys = 219.03 cpu)
diff --git a/sql-bench/Results-win32/wisconsin-ms-sql_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase b/sql-bench/Results-win32/wisconsin-ms-sql_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
new file mode 100644
index 00000000000..79a4c199124
--- /dev/null
+++ b/sql-bench/Results-win32/wisconsin-ms-sql_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
@@ -0,0 +1,14 @@
+Testing server 'Microsoft SQL Server 7.00 - 7.00.517 (Intel X86) ' at 1998-09-07 14:39:20
+
+Wisconsin benchmark test
+
+Time for create_table (3): 0 secs ( 0.61 usr 0.00 sys = 0.61 cpu)
+
+Inserting data
+Time to insert (31000): 262 secs (261.70 usr 0.00 sys = 261.70 cpu)
+Time to delete_big (1): 4 secs ( 3.98 usr 0.00 sys = 3.98 cpu)
+
+Running actual benchmark
+Time for wisc_benchmark (114): 24 secs (23.97 usr 0.00 sys = 23.97 cpu)
+
+Total time: 290 secs (290.80 usr 0.00 sys = 290.80 cpu)
diff --git a/sql-bench/Results-win32/wisconsin-mysql-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase b/sql-bench/Results-win32/wisconsin-mysql-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
new file mode 100644
index 00000000000..194401cb8f7
--- /dev/null
+++ b/sql-bench/Results-win32/wisconsin-mysql-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
@@ -0,0 +1,14 @@
+Testing server 'MySQL 3.22.16 gamma' at 1999-02-20 21:42:45
+
+Wisconsin benchmark test
+
+Time for create_table (3): 0 wallclock secs ( 0.00 usr + 0.00 sys = 0.00 CPU)
+
+Inserting data
+Time to insert (31000): 29 wallclock secs ( 4.75 usr + 3.96 sys = 8.70 CPU)
+Time to delete_big (1): 1 wallclock secs ( 0.00 usr + 0.00 sys = 0.00 CPU)
+
+Running actual benchmark
+Time for wisc_benchmark (114): 8 wallclock secs ( 3.07 usr + 1.29 sys = 4.37 CPU)
+
+Total time: 38 wallclock secs ( 7.83 usr + 5.25 sys = 13.08 CPU)
diff --git a/sql-bench/Results-win32/wisconsin-mysql-win98 b/sql-bench/Results-win32/wisconsin-mysql-win98
new file mode 100644
index 00000000000..71bb6b4f3de
--- /dev/null
+++ b/sql-bench/Results-win32/wisconsin-mysql-win98
@@ -0,0 +1,14 @@
+Testing server 'MySQL 3.23.13a alpha' at 2000-03-15 5:41:46
+
+Wisconsin benchmark test
+
+Time for create_table (3): 1 wallclock secs ( 0.99 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Inserting data
+Time to insert (31000): 44 wallclock secs (43.67 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time to delete_big (1): 1 wallclock secs ( 0.66 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Running actual benchmark
+Time for wisc_benchmark (114): 17 wallclock secs (17.08 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Total time: 63 wallclock secs (62.40 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results-win32/wisconsin-mysql-win98-cmp-access,mysql b/sql-bench/Results-win32/wisconsin-mysql-win98-cmp-access,mysql
new file mode 100644
index 00000000000..0acaf169c1a
--- /dev/null
+++ b/sql-bench/Results-win32/wisconsin-mysql-win98-cmp-access,mysql
@@ -0,0 +1,14 @@
+Testing server 'MySQL 3.23.8 alpha' at 2000-01-04 13:54:03
+
+Wisconsin benchmark test
+
+Time for create_table (3): 0 wallclock secs ( 0.11 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Inserting data
+Time to insert (31000): 49 wallclock secs (48.88 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time to delete_big (1): 1 wallclock secs ( 0.66 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Running actual benchmark
+Time for wisc_benchmark (114): 18 wallclock secs (18.67 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Total time: 68 wallclock secs (68.32 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results-win32/wisconsin-mysql_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase b/sql-bench/Results-win32/wisconsin-mysql_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
new file mode 100644
index 00000000000..b064bc0d04b
--- /dev/null
+++ b/sql-bench/Results-win32/wisconsin-mysql_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
@@ -0,0 +1,14 @@
+Testing server 'MySQL 3.22.16 gamma' at 1999-02-07 14:02:02
+
+Wisconsin benchmark test
+
+Time for create_table (3): 0 secs ( 0.05 usr 0.00 sys = 0.05 cpu)
+
+Inserting data
+Time to insert (31000): 50 secs (50.09 usr 0.00 sys = 50.09 cpu)
+Time to delete_big (1): 1 secs ( 0.45 usr 0.00 sys = 0.45 cpu)
+
+Running actual benchmark
+Time for wisc_benchmark (114): 23 secs (23.44 usr 0.00 sys = 23.44 cpu)
+
+Total time: 74 secs (74.07 usr 0.00 sys = 74.07 cpu)
diff --git a/sql-bench/Results-win32/wisconsin-oracle_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase b/sql-bench/Results-win32/wisconsin-oracle_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
new file mode 100644
index 00000000000..252c484443a
--- /dev/null
+++ b/sql-bench/Results-win32/wisconsin-oracle_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
@@ -0,0 +1,14 @@
+Testing server 'Oracle 8.0.4.0.0' at 1999-04-04 7:34:35
+
+Wisconsin benchmark test
+
+Time for create_table (3): 0 wallclock secs ( 0.01 usr 0.01 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Inserting data
+Time to insert (31000): 245 wallclock secs (41.80 usr 5.20 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time to delete_big (1): 7 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Running actual benchmark
+Time for wisc_benchmark (114): 82 wallclock secs (44.61 usr 5.10 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Total time: 335 wallclock secs (86.43 usr 10.31 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results-win32/wisconsin-solid_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase b/sql-bench/Results-win32/wisconsin-solid_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
new file mode 100644
index 00000000000..8b953a2933d
--- /dev/null
+++ b/sql-bench/Results-win32/wisconsin-solid_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase
@@ -0,0 +1,14 @@
+Testing server 'Solid version ???' at 1998-10-08 16:44:23
+
+Wisconsin benchmark test
+
+Time for create_table (3): 0 secs ( 0.20 usr 0.00 sys = 0.20 cpu)
+
+Inserting data
+Time to insert (31000): 233 secs (232.63 usr 0.00 sys = 232.63 cpu)
+Time to delete_big (1): 8 secs ( 8.24 usr 0.00 sys = 8.24 cpu)
+
+Running actual benchmark
+Time for wisc_benchmark (114): 84 secs (83.66 usr 0.00 sys = 83.66 cpu)
+
+Total time: 338 secs (338.33 usr 0.00 sys = 338.33 cpu)
diff --git a/sql-bench/Results/ATIS-Adabas-Linux_2.0.35_i686-cmp-adabas,mysql b/sql-bench/Results/ATIS-Adabas-Linux_2.0.35_i686-cmp-adabas,mysql
new file mode 100644
index 00000000000..a3c2bf9eb79
--- /dev/null
+++ b/sql-bench/Results/ATIS-Adabas-Linux_2.0.35_i686-cmp-adabas,mysql
@@ -0,0 +1,19 @@
+Testing server 'Adabas 10.01.00' at 1998-08-18 23:58:32
+
+ATIS table test
+
+Creating tables
+Time for create_table (28): 2 secs ( 0.05 usr 0.03 sys = 0.08 cpu)
+
+Inserting data
+Time to insert (9768): 172 secs ( 6.70 usr 3.12 sys = 9.82 cpu)
+
+Retrieving data
+Time for select_simple_join (500): 14 secs ( 2.35 usr 4.08 sys = 6.43 cpu)
+Time for select_join (200): 74 secs (22.10 usr 21.09 sys = 43.19 cpu)
+Time for select_distinct (800): 95 secs ( 6.59 usr 14.43 sys = 21.02 cpu)
+Time for select_group (2300): 86 secs ( 3.97 usr 7.49 sys = 11.46 cpu)
+
+Removing tables
+Time to drop_table (28): 2 secs ( 0.00 usr 0.01 sys = 0.01 cpu)
+Total time: 445 secs (41.77 usr 50.26 sys = 92.03 cpu)
diff --git a/sql-bench/Results/ATIS-AdabasD-Linux_2.0.35_i686-cmp-adabasd,mysql b/sql-bench/Results/ATIS-AdabasD-Linux_2.0.35_i686-cmp-adabasd,mysql
new file mode 100644
index 00000000000..4481b411247
--- /dev/null
+++ b/sql-bench/Results/ATIS-AdabasD-Linux_2.0.35_i686-cmp-adabasd,mysql
@@ -0,0 +1,19 @@
+Testing server 'Adabas 10.01.00' at 1998-08-20 19:07:58
+
+ATIS table test
+
+Creating tables
+Time for create_table (28): 3 secs ( 0.01 usr 0.01 sys = 0.02 cpu)
+
+Inserting data
+Time to insert (9768): 164 secs ( 1.53 usr 1.54 sys = 3.07 cpu)
+
+Retrieving data
+Time for select_simple_join (500): 31 secs ( 5.45 usr 9.53 sys = 14.98 cpu)
+Time for select_join (200): 254 secs (52.81 usr 82.97 sys = 135.78 cpu)
+Time for select_distinct (800): 146 secs (11.45 usr 37.01 sys = 48.46 cpu)
+Time for select_group (2300): 109 secs ( 7.42 usr 14.55 sys = 21.97 cpu)
+
+Removing tables
+Time to drop_table (28): 3 secs ( 0.02 usr 0.01 sys = 0.03 cpu)
+Total time: 710 secs (78.70 usr 145.64 sys = 224.34 cpu)
diff --git a/sql-bench/Results/ATIS-msql-Linux_2.2.10_i686-cmp-msql,mysql b/sql-bench/Results/ATIS-msql-Linux_2.2.10_i686-cmp-msql,mysql
new file mode 100644
index 00000000000..5090863cb93
--- /dev/null
+++ b/sql-bench/Results/ATIS-msql-Linux_2.2.10_i686-cmp-msql,mysql
@@ -0,0 +1,18 @@
+Testing server 'mSQL server version 2.0.10' at 1999-09-22 8:39:03
+
+ATIS table test
+
+Creating tables
+Time for create_table (28): 0 wallclock secs ( 0.02 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Inserting data
+Time to insert (9768): 4 wallclock secs ( 1.16 usr 0.10 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Retrieving data
+Time for select_simple_join (500): 5 wallclock secs ( 1.88 usr 0.33 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_join (200): 219 wallclock secs (14.80 usr 3.71 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_distinct (700): 22 wallclock secs ( 5.65 usr 1.10 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Removing tables
+Time to drop_table (28): 0 wallclock secs ( 0.01 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Total time: 250 wallclock secs (23.58 usr 5.24 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results/ATIS-mysql-3.21-Linux_2.2.1_i686 b/sql-bench/Results/ATIS-mysql-3.21-Linux_2.2.1_i686
new file mode 100644
index 00000000000..7e2b8a6a265
--- /dev/null
+++ b/sql-bench/Results/ATIS-mysql-3.21-Linux_2.2.1_i686
@@ -0,0 +1,19 @@
+Testing server 'MySQL 3.21.34' at 1999-02-28 15:42:21
+
+ATIS table test
+
+Creating tables
+Time for create_table (28): 0 wallclock secs ( 0.02 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Inserting data
+Time to insert (9768): 3 wallclock secs ( 0.90 usr 0.26 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Retrieving data
+Time for select_simple_join (500): 3 wallclock secs ( 0.95 usr 0.31 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for select_join (200): 26 wallclock secs ( 6.04 usr 3.37 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for select_distinct (800): 17 wallclock secs ( 2.46 usr 1.09 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for select_group (2700): 15 wallclock secs ( 2.27 usr 0.57 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Removing tables
+Time to drop_table (28): 0 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Total time: 64 wallclock secs (12.66 usr 5.60 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
diff --git a/sql-bench/Results/ATIS-mysql-HP_UX_B.10.20_9000_778 b/sql-bench/Results/ATIS-mysql-HP_UX_B.10.20_9000_778
new file mode 100644
index 00000000000..66b000d8a57
--- /dev/null
+++ b/sql-bench/Results/ATIS-mysql-HP_UX_B.10.20_9000_778
@@ -0,0 +1,19 @@
+Testing server 'MySQL 3.23.4 alpha' at 1999-09-27 15:10:30
+
+ATIS table test
+
+Creating tables
+Time for create_table (28): 0 wallclock secs ( 0.01 usr 0.01 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Inserting data
+Time to insert (9768): 9 wallclock secs ( 1.54 usr 0.65 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Retrieving data
+Time for select_simple_join (500): 8 wallclock secs ( 2.34 usr 1.03 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_join (200): 66 wallclock secs (17.47 usr 12.46 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_distinct (800): 52 wallclock secs ( 6.58 usr 3.30 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_group (2700): 55 wallclock secs ( 5.33 usr 1.59 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Removing tables
+Time to drop_table (28): 0 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Total time: 190 wallclock secs (33.29 usr 19.04 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results/ATIS-mysql-Linux_2.0.35_i686-cmp-adabas,mysql b/sql-bench/Results/ATIS-mysql-Linux_2.0.35_i686-cmp-adabas,mysql
new file mode 100644
index 00000000000..71b73b390bb
--- /dev/null
+++ b/sql-bench/Results/ATIS-mysql-Linux_2.0.35_i686-cmp-adabas,mysql
@@ -0,0 +1,19 @@
+Testing server 'MySQL 3.22.9 beta' at 1998-10-20 6:54:10
+
+ATIS table test
+
+Creating tables
+Time for create_table (28): 0 secs ( 0.00 usr 0.01 sys = 0.01 cpu)
+
+Inserting data
+Time to insert (9768): 5 secs ( 0.43 usr 1.05 sys = 1.48 cpu)
+
+Retrieving data
+Time for select_simple_join (500): 3 secs ( 0.50 usr 1.29 sys = 1.79 cpu)
+Time for select_join (200): 34 secs ( 3.85 usr 12.82 sys = 16.67 cpu)
+Time for select_distinct (800): 20 secs ( 0.92 usr 3.98 sys = 4.90 cpu)
+Time for select_group (2300): 13 secs ( 0.82 usr 2.54 sys = 3.36 cpu)
+
+Removing tables
+Time to drop_table (28): 0 secs ( 0.01 usr 0.00 sys = 0.01 cpu)
+Total time: 75 secs ( 6.54 usr 21.70 sys = 28.24 cpu)
diff --git a/sql-bench/Results/ATIS-mysql-Linux_2.0.36_i686-cmp-mysql,pg,solid b/sql-bench/Results/ATIS-mysql-Linux_2.0.36_i686-cmp-mysql,pg,solid
new file mode 100644
index 00000000000..555f277d503
--- /dev/null
+++ b/sql-bench/Results/ATIS-mysql-Linux_2.0.36_i686-cmp-mysql,pg,solid
@@ -0,0 +1,19 @@
+Testing server 'MySQL 3.22.18' at 1999-03-07 22:58:13
+
+ATIS table test
+
+Creating tables
+Time for create_table (28): 0 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Inserting data
+Time to insert (9768): 4 wallclock secs ( 0.94 usr 0.27 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Retrieving data
+Time for select_simple_join (500): 2 wallclock secs ( 0.91 usr 0.24 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for select_join (200): 22 wallclock secs ( 4.87 usr 2.75 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for select_distinct (800): 14 wallclock secs ( 2.23 usr 0.74 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for select_group (2000): 7 wallclock secs ( 1.43 usr 0.19 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Removing tables
+Time to drop_table (28): 0 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Total time: 49 wallclock secs (10.38 usr 4.19 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
diff --git a/sql-bench/Results/ATIS-mysql-Linux_2.2.10_i686 b/sql-bench/Results/ATIS-mysql-Linux_2.2.10_i686
new file mode 100644
index 00000000000..0f88b0dd39a
--- /dev/null
+++ b/sql-bench/Results/ATIS-mysql-Linux_2.2.10_i686
@@ -0,0 +1,19 @@
+Testing server 'MySQL 3.23.3 alpha' at 1999-09-17 8:33:50
+
+ATIS table test
+
+Creating tables
+Time for create_table (28): 0 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Inserting data
+Time to insert (9768): 4 wallclock secs ( 1.34 usr 0.15 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Retrieving data
+Time for select_simple_join (500): 3 wallclock secs ( 1.40 usr 0.18 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_join (200): 23 wallclock secs ( 9.91 usr 1.72 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_distinct (800): 19 wallclock secs ( 3.71 usr 0.50 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_group (2700): 16 wallclock secs ( 3.35 usr 0.37 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Removing tables
+Time to drop_table (28): 0 wallclock secs ( 0.00 usr 0.01 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Total time: 65 wallclock secs (19.72 usr 2.93 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results/ATIS-mysql-Linux_2.2.10_i686-cmp-msql,mysql b/sql-bench/Results/ATIS-mysql-Linux_2.2.10_i686-cmp-msql,mysql
new file mode 100644
index 00000000000..26cf40eddae
--- /dev/null
+++ b/sql-bench/Results/ATIS-mysql-Linux_2.2.10_i686-cmp-msql,mysql
@@ -0,0 +1,18 @@
+Testing server 'MySQL 3.23.3 alpha' at 1999-09-24 9:48:19
+
+ATIS table test
+
+Creating tables
+Time for create_table (28): 0 wallclock secs ( 0.01 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Inserting data
+Time to insert (9768): 4 wallclock secs ( 1.36 usr 0.28 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Retrieving data
+Time for select_simple_join (500): 3 wallclock secs ( 1.30 usr 0.25 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_join (200): 23 wallclock secs ( 9.83 usr 1.84 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_distinct (700): 15 wallclock secs ( 3.62 usr 0.44 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Removing tables
+Time to drop_table (28): 0 wallclock secs ( 0.01 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Total time: 45 wallclock secs (16.16 usr 2.81 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results/ATIS-mysql-Linux_2.2.14_i686_xeon b/sql-bench/Results/ATIS-mysql-Linux_2.2.14_i686_xeon
new file mode 100644
index 00000000000..d0b7b89c2ce
--- /dev/null
+++ b/sql-bench/Results/ATIS-mysql-Linux_2.2.14_i686_xeon
@@ -0,0 +1,19 @@
+Testing server 'MySQL 3.23.17 alpha' at 2000-06-01 3:11:25
+
+ATIS table test
+
+Creating tables
+Time for create_table (28): 0 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Inserting data
+Time to insert (9768): 2 wallclock secs ( 0.45 usr 0.27 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Retrieving data
+Time for select_simple_join (500): 2 wallclock secs ( 0.59 usr 0.26 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_join (200): 13 wallclock secs ( 4.26 usr 2.21 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_distinct (800): 11 wallclock secs ( 1.69 usr 0.81 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_group (2800): 12 wallclock secs ( 1.56 usr 0.37 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Removing tables
+Time to drop_table (28): 0 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Total time: 40 wallclock secs ( 8.55 usr 3.92 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results/ATIS-mysql-Linux_2.2.1_i686-cmp-adabas,mysql b/sql-bench/Results/ATIS-mysql-Linux_2.2.1_i686-cmp-adabas,mysql
new file mode 100644
index 00000000000..9766a825848
--- /dev/null
+++ b/sql-bench/Results/ATIS-mysql-Linux_2.2.1_i686-cmp-adabas,mysql
@@ -0,0 +1,19 @@
+Testing server 'MySQL 3.22.18' at 1999-02-27 21:10:25
+
+ATIS table test
+
+Creating tables
+Time for create_table (28): 0 wallclock secs ( 0.00 usr 0.01 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Inserting data
+Time to insert (9768): 4 wallclock secs ( 0.82 usr 0.31 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Retrieving data
+Time for select_simple_join (500): 2 wallclock secs ( 0.96 usr 0.24 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for select_join (200): 27 wallclock secs ( 5.95 usr 3.49 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for select_distinct (800): 17 wallclock secs ( 2.78 usr 0.90 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for select_group (2300): 10 wallclock secs ( 2.04 usr 0.48 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Removing tables
+Time to drop_table (28): 0 wallclock secs ( 0.00 usr 0.01 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Total time: 60 wallclock secs (12.57 usr 5.44 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
diff --git a/sql-bench/Results/ATIS-mysql-NT_4.0 b/sql-bench/Results/ATIS-mysql-NT_4.0
new file mode 100644
index 00000000000..e09863441a6
--- /dev/null
+++ b/sql-bench/Results/ATIS-mysql-NT_4.0
@@ -0,0 +1,19 @@
+Testing server 'MySQL 3.23.17a alpha' at 2000-06-02 17:36:42
+
+ATIS table test
+
+Creating tables
+Time for create_table (28): 1 wallclock secs ( 0.02 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Inserting data
+Time to insert (9768): 5 wallclock secs ( 0.88 usr 1.38 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Retrieving data
+Time for select_simple_join (500): 3 wallclock secs ( 1.58 usr 0.66 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_join (200): 22 wallclock secs (12.86 usr 5.22 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_distinct (800): 17 wallclock secs ( 4.78 usr 1.80 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_group (2800): 20 wallclock secs ( 3.55 usr 1.13 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Removing tables
+Time to drop_table (28): 0 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Total time: 68 wallclock secs (23.67 usr 10.17 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results/ATIS-mysql-SunOS_5.5.1_sun4u b/sql-bench/Results/ATIS-mysql-SunOS_5.5.1_sun4u
new file mode 100644
index 00000000000..cdb07a4af15
--- /dev/null
+++ b/sql-bench/Results/ATIS-mysql-SunOS_5.5.1_sun4u
@@ -0,0 +1,19 @@
+Testing server 'MySQL 3.22.19' at 1999-03-02 3:11:24
+
+ATIS table test
+
+Creating tables
+Time for create_table (28): 0 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Inserting data
+Time to insert (9768): 11 wallclock secs ( 1.51 usr 1.08 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Retrieving data
+Time for select_simple_join (500): 8 wallclock secs ( 2.20 usr 0.97 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_join (200): 90 wallclock secs (17.84 usr 8.44 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_distinct (800): 53 wallclock secs ( 6.14 usr 2.71 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_group (2700): 45 wallclock secs ( 4.87 usr 1.79 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Removing tables
+Time to drop_table (28): 0 wallclock secs ( 0.01 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Total time: 207 wallclock secs (32.58 usr 14.99 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results/ATIS-mysql-SunOS_5.7_sun4m b/sql-bench/Results/ATIS-mysql-SunOS_5.7_sun4m
new file mode 100644
index 00000000000..c2da532cc0e
--- /dev/null
+++ b/sql-bench/Results/ATIS-mysql-SunOS_5.7_sun4m
@@ -0,0 +1,19 @@
+Testing server 'MySQL 3.22.20' at 1999-03-19 12:57:30
+
+ATIS table test
+
+Creating tables
+Time for create_table (28): 2 secs ( 0.05 usr 0.05 sys + 0.00 cusr 0.00 csys = 0.10 cpu)
+
+Inserting data
+Time to insert (9768): 40 secs ( 7.14 usr 7.21 sys + 0.00 cusr 0.00 csys = 14.35 cpu)
+
+Retrieving data
+Time for select_simple_join (500): 37 secs ( 9.62 usr 7.92 sys + 0.00 cusr 0.00 csys = 17.54 cpu)
+Time for select_join (200): 572 secs (81.23 usr 73.44 sys + 0.00 cusr 0.00 csys = 154.67 cpu)
+Time for select_distinct (800): 292 secs (28.26 usr 22.92 sys + 0.00 cusr 0.00 csys = 51.18 cpu)
+Time for select_group (2700): 209 secs (20.70 usr 12.94 sys + 0.00 cusr 0.00 csys = 33.64 cpu)
+
+Removing tables
+Time to drop_table (28): 1 secs ( 0.02 usr 0.02 sys + 0.00 cusr 0.00 csys = 0.04 cpu)
+Total time: 1153 secs (147.11 usr 124.50 sys + 0.00 cusr 0.00 csys = 271.61 cpu)
diff --git a/sql-bench/Results/ATIS-mysql-SunOS_5.7_sun4u b/sql-bench/Results/ATIS-mysql-SunOS_5.7_sun4u
new file mode 100644
index 00000000000..c1aefa8eb83
--- /dev/null
+++ b/sql-bench/Results/ATIS-mysql-SunOS_5.7_sun4u
@@ -0,0 +1,19 @@
+Testing server 'MySQL 3.23.8 alpha' at 2000-01-17 20:51:25
+
+ATIS table test
+
+Creating tables
+Time for create_table (28): 1 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Inserting data
+Time to insert (9768): 5 wallclock secs ( 0.67 usr 0.88 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Retrieving data
+Time for select_simple_join (500): 4 wallclock secs ( 1.19 usr 0.90 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_join (200): 26 wallclock secs ( 9.53 usr 7.43 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_distinct (800): 27 wallclock secs ( 3.30 usr 2.56 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_group (2700): 24 wallclock secs ( 2.16 usr 1.58 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Removing tables
+Time to drop_table (28): 2 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Total time: 89 wallclock secs (16.85 usr 13.36 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results/ATIS-mysql-win98 b/sql-bench/Results/ATIS-mysql-win98
new file mode 100644
index 00000000000..1febfa34bcb
--- /dev/null
+++ b/sql-bench/Results/ATIS-mysql-win98
@@ -0,0 +1,19 @@
+Testing server 'MySQL 3.23.13a alpha' at 2000-03-15 2:22:09
+
+ATIS table test
+
+Creating tables
+Time for create_table (28): 7 wallclock secs ( 6.93 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Inserting data
+Time to insert (9768): 12 wallclock secs (11.97 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Retrieving data
+Time for select_simple_join (500): 7 wallclock secs ( 7.47 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_join (200): 51 wallclock secs (50.15 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_distinct (800): 33 wallclock secs (33.34 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_group (2800): 33 wallclock secs (33.61 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Removing tables
+Time to drop_table (28): 1 wallclock secs ( 0.06 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Total time: 144 wallclock secs (143.53 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results/ATIS-mysql_3.21-Linux_2.0.35_i686 b/sql-bench/Results/ATIS-mysql_3.21-Linux_2.0.35_i686
new file mode 100644
index 00000000000..e4c0c10eede
--- /dev/null
+++ b/sql-bench/Results/ATIS-mysql_3.21-Linux_2.0.35_i686
@@ -0,0 +1,19 @@
+Testing server 'MySQL 3.21.33' at 1998-08-21 11:28:22
+
+ATIS table test
+
+Creating tables
+Time for create_table (28): 0 secs ( 0.01 usr 0.01 sys = 0.02 cpu)
+
+Inserting data
+Time to insert (9768): 5 secs ( 0.48 usr 0.75 sys = 1.23 cpu)
+
+Retrieving data
+Time for select_simple_join (500): 2 secs ( 0.62 usr 1.00 sys = 1.62 cpu)
+Time for select_join (200): 31 secs ( 2.65 usr 11.18 sys = 13.83 cpu)
+Time for select_distinct (800): 20 secs ( 1.11 usr 2.93 sys = 4.04 cpu)
+Time for select_group (2700): 17 secs ( 0.65 usr 2.51 sys = 3.16 cpu)
+
+Removing tables
+Time to drop_table (28): 0 secs ( 0.00 usr 0.01 sys = 0.01 cpu)
+Total time: 75 secs ( 5.52 usr 18.40 sys = 23.92 cpu)
diff --git a/sql-bench/Results/ATIS-mysql_fast-Linux_2.2.10_i686-cmp-msql,mysql b/sql-bench/Results/ATIS-mysql_fast-Linux_2.2.10_i686-cmp-msql,mysql
new file mode 100644
index 00000000000..5c37e09f701
--- /dev/null
+++ b/sql-bench/Results/ATIS-mysql_fast-Linux_2.2.10_i686-cmp-msql,mysql
@@ -0,0 +1,18 @@
+Testing server 'MySQL 3.23.3 alpha' at 1999-09-24 9:07:48
+
+ATIS table test
+
+Creating tables
+Time for create_table (28): 0 wallclock secs ( 0.01 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Inserting data
+Time to insert (9768): 1 wallclock secs ( 0.01 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Retrieving data
+Time for select_simple_join (500): 3 wallclock secs ( 1.40 usr 0.15 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_join (200): 22 wallclock secs ( 9.94 usr 1.56 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_distinct (700): 15 wallclock secs ( 3.57 usr 0.55 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Removing tables
+Time to drop_table (28): 0 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Total time: 41 wallclock secs (14.97 usr 2.26 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results/ATIS-mysql_odbc-win98 b/sql-bench/Results/ATIS-mysql_odbc-win98
new file mode 100644
index 00000000000..c154befe7e3
--- /dev/null
+++ b/sql-bench/Results/ATIS-mysql_odbc-win98
@@ -0,0 +1,19 @@
+Testing server 'MySQL 3.22.19a' at 1999-03-02 16:23:37
+
+ATIS table test
+
+Creating tables
+Time for create_table (28): 1 wallclock secs ( 0.88 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Inserting data
+Time to insert (9768): 31 wallclock secs (30.87 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Retrieving data
+Time for select_simple_join (500): 13 wallclock secs (13.35 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_join (200): 142 wallclock secs (141.54 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_distinct (800): 58 wallclock secs (57.84 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_group (2700): 50 wallclock secs (50.26 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Removing tables
+Time to drop_table (28): 0 wallclock secs ( 0.11 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Total time: 295 wallclock secs (294.90 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results/ATIS-oracle-Linux_2.0.36_i686-cmp-mysql,oracle b/sql-bench/Results/ATIS-oracle-Linux_2.0.36_i686-cmp-mysql,oracle
new file mode 100644
index 00000000000..829dff6a0f4
--- /dev/null
+++ b/sql-bench/Results/ATIS-oracle-Linux_2.0.36_i686-cmp-mysql,oracle
@@ -0,0 +1,19 @@
+Testing server 'Oracle 8.0.5.0.0' at 1999-03-25 0:33:02
+
+ATIS table test
+
+Creating tables
+Time for create_table (28): 5 wallclock secs ( 0.06 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Inserting data
+Time to insert (9768): 33 wallclock secs ( 7.31 usr 0.97 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Retrieving data
+Time for select_simple_join (500): 23 wallclock secs ( 8.65 usr 2.06 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for select_join (200): 204 wallclock secs (71.18 usr 19.08 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for select_distinct (800): 63 wallclock secs (24.27 usr 6.17 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for select_group (2300): 42 wallclock secs (12.18 usr 2.49 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Removing tables
+Time to drop_table (28): 3 wallclock secs ( 0.03 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Total time: 373 wallclock secs (123.71 usr 30.77 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
diff --git a/sql-bench/Results/ATIS-oracle_fast-Linux_2.0.36_i686-cmp-mysql,oracle b/sql-bench/Results/ATIS-oracle_fast-Linux_2.0.36_i686-cmp-mysql,oracle
new file mode 100644
index 00000000000..7bf02092fec
--- /dev/null
+++ b/sql-bench/Results/ATIS-oracle_fast-Linux_2.0.36_i686-cmp-mysql,oracle
@@ -0,0 +1,25 @@
+Testing server 'Oracle 8.0.5.0.0' at 1999-03-23 8:05:46
+
+ATIS table test
+
+Creating tables
+Time for create_table (28): 4 wallclock secs ( 0.04 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Time for book-keeping (1): 22 wallclock secs ( 0.05 usr 0.01 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Inserting data
+Time to insert (9768): 46 wallclock secs ( 7.61 usr 0.91 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Time for book-keeping (1): 23 wallclock secs ( 0.07 usr 0.02 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Retrieving data
+Time for select_simple_join (500): 20 wallclock secs ( 8.26 usr 1.90 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for select_join (200): 188 wallclock secs (71.78 usr 18.08 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for select_distinct (800): 56 wallclock secs (24.55 usr 5.45 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for select_group (2300): 29 wallclock secs (12.06 usr 2.85 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Removing tables
+Time to drop_table (28): 3 wallclock secs ( 0.01 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for book-keeping (1): 3 wallclock secs ( 0.01 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Total time: 396 wallclock secs (124.50 usr 29.24 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
diff --git a/sql-bench/Results/ATIS-pg-Linux_2.0.36_i686-cmp-mysql,pg,solid b/sql-bench/Results/ATIS-pg-Linux_2.0.36_i686-cmp-mysql,pg,solid
new file mode 100644
index 00000000000..67d12518f57
--- /dev/null
+++ b/sql-bench/Results/ATIS-pg-Linux_2.0.36_i686-cmp-mysql,pg,solid
@@ -0,0 +1,22 @@
+Testing server 'PostgreSQL 6.4' at 1999-03-09 18:59:52
+
+ATIS table test
+
+Creating tables
+Time for create_table (28): 1 wallclock secs ( 0.03 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Inserting data
+Time to insert (9768): 23 wallclock secs ( 5.25 usr 0.67 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Retrieving data
+Time for select_simple_join (500): 6 wallclock secs ( 1.02 usr 0.10 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+96 queries in 48 loops of 100 loops took 606 seconds
+Estimated time for select_join (200): 1262 wallclock secs ( 5.94 usr 0.52 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for select_distinct (800): 139 wallclock secs ( 2.82 usr 0.22 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for select_group (2000): 89 wallclock secs ( 1.53 usr 0.15 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Removing tables
+Time to drop_table (28): 0 wallclock secs ( 0.03 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Estimated total time: 1520 wallclock secs (16.64 usr 1.66 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
diff --git a/sql-bench/Results/ATIS-pg_fast-Linux_2.0.36_i686-cmp-mysql,pg,solid b/sql-bench/Results/ATIS-pg_fast-Linux_2.0.36_i686-cmp-mysql,pg,solid
new file mode 100644
index 00000000000..6e7d5530da4
--- /dev/null
+++ b/sql-bench/Results/ATIS-pg_fast-Linux_2.0.36_i686-cmp-mysql,pg,solid
@@ -0,0 +1,23 @@
+Testing server 'PostgreSQL 6.4' at 1999-03-11 7:20:16
+
+ATIS table test
+
+Creating tables
+Time for create_table (28): 1 wallclock secs ( 0.03 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Inserting data
+Time to insert (9768): 29 wallclock secs ( 5.56 usr 0.60 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Time for book-keeping (1): 1 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Retrieving data
+Time for select_simple_join (500): 44 wallclock secs ( 1.11 usr 0.12 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for select_join (200): 60 wallclock secs ( 6.07 usr 0.42 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for select_distinct (800): 70 wallclock secs ( 3.23 usr 0.22 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for select_group (2000): 95 wallclock secs ( 1.88 usr 0.18 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Removing tables
+Time to drop_table (28): 0 wallclock secs ( 0.01 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for book-keeping (1): 0 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Total time: 300 wallclock secs (17.90 usr 1.54 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
diff --git a/sql-bench/Results/ATIS-solid-Linux_2.0.36_i686-cmp-mysql,pg,solid b/sql-bench/Results/ATIS-solid-Linux_2.0.36_i686-cmp-mysql,pg,solid
new file mode 100644
index 00000000000..8ba087218d1
--- /dev/null
+++ b/sql-bench/Results/ATIS-solid-Linux_2.0.36_i686-cmp-mysql,pg,solid
@@ -0,0 +1,19 @@
+Testing server 'SOLID Server - v.02.30.0026 (Linux ix86)' at 1999-03-06 12:47:44
+
+ATIS table test
+
+Creating tables
+Time for create_table (28): 0 wallclock secs ( 0.04 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Inserting data
+Time to insert (9768): 27 wallclock secs ( 8.34 usr 0.73 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Retrieving data
+Time for select_simple_join (500): 37 wallclock secs ( 3.65 usr 0.22 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for select_join (200): 408 wallclock secs (28.07 usr 1.80 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for select_distinct (800): 169 wallclock secs (11.26 usr 0.54 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for select_group (2000): 59 wallclock secs ( 3.54 usr 0.18 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Removing tables
+Time to drop_table (28): 1 wallclock secs ( 0.02 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Total time: 701 wallclock secs (54.93 usr 3.47 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
diff --git a/sql-bench/Results/RUN-Adabas-Linux_2.0.35_i686-cmp-adabas,mysql b/sql-bench/Results/RUN-Adabas-Linux_2.0.35_i686-cmp-adabas,mysql
new file mode 100644
index 00000000000..4dc95282073
--- /dev/null
+++ b/sql-bench/Results/RUN-Adabas-Linux_2.0.35_i686-cmp-adabas,mysql
@@ -0,0 +1,60 @@
+Benchmark DBD suit: 2.0
+Date of test: 1998-09-24 15:16:40
+Running tests on: Linux 2.0.35 i686
+Arguments: --small-tables
+Comments:
+Limits from: adabas,mysql
+Server version: Adabas 10.01.00
+
+ATIS: Total time: 445 secs (41.77 usr 50.26 sys = 92.03 cpu)
+alter-table: Total time: 40 secs ( 0.76 usr 0.47 sys = 1.23 cpu)
+big-tables: Total time: 89 secs ( 8.81 usr 10.98 sys = 19.79 cpu)
+connect: Total time: 570 secs (65.81 usr 250.86 sys = 316.67 cpu)
+create: Total time: 348 secs ( 2.35 usr 7.46 sys = 9.81 cpu)
+insert: Estimated total time: 11695 secs ( 249.00 463.00 713.00)
+select: Estimated total time: 3338 secs (87.31 usr 141.31 sys = 228.62 cpu)
+wisconsin: Total time: 654 secs (34.14 usr 21.26 sys = 55.40 cpu)
+
+All 8 test executed successfully
+Tests with estimated time have a + at end of line
+
+Totals per operation:
+Operation seconds usr sys cpu tests
+alter_table_add 11 0.07 0.10 0.17 246
+alter_table_drop 8 0.01 0.08 0.09 123
+connect 164 29.40 100.88 130.28 10000
+connect+select 295 22.17 121.92 144.09 10000
+count 107 0.11 0.12 0.23 100
+count_on_key 760 28.47 56.52 84.99 50100 +
+create+drop 126 0.25 2.57 2.82 1000
+create_index 1 0.00 0.00 0.00 8
+create_key+drop 97 0.27 2.86 3.13 1000
+create_table 48 1.48 0.63 2.11 1031
+delete_big 17 0.02 0.01 0.03 15
+delete_key 48 0.39 0.35 0.74 500
+drop_index 1 0.00 0.00 0.00 8
+drop_table 78 0.12 0.64 0.76 1028
+insert 1669 55.14 18.59 73.73 80768
+insert_duplicates 9 3.57 3.81 7.38 30000
+insert_key 241 8.58 2.07 10.65 10000
+insert_many_fields 54 0.73 1.52 2.25 2000
+min_max 40 0.09 0.09 0.18 60
+min_max_on_key 2421 46.26 76.81 123.06 73000 +
+order_by 54 12.73 11.78 24.51 10
+order_by_key 48 13.45 11.16 24.61 10
+select 63 7.83 16.02 23.85 20000
+select_big 89 21.11 23.12 44.23 10080
+select_distinct 95 6.59 14.43 21.02 800
+select_group 180 4.37 8.47 12.84 3401
+select_join 74 22.10 21.09 43.19 200
+select_key 1646 16.74 27.42 44.15 20000 +
+select_key_prefix 79 11.74 21.54 33.28 20000
+select_many_fields 35 8.08 9.45 17.53 2000
+select_range 5123 16.41 26.30 42.71 25410 ++
+select_range_prefix 1782 14.73 26.43 41.15 25000 +
+select_simple_join 14 2.35 4.08 6.43 500
+update_key 51 0.32 0.40 0.72 500
+update_key_big 77 0.29 0.33 0.62 480
+update_of_key 17 0.10 0.16 0.26 256
+wisc_benchmark 64 15.03 14.19 29.22 114
+TOTALS 15686 371.10 625.94 997.01 399748 ++++++
diff --git a/sql-bench/Results/RUN-msql-Linux_2.2.10_i686-cmp-msql,mysql b/sql-bench/Results/RUN-msql-Linux_2.2.10_i686-cmp-msql,mysql
new file mode 100644
index 00000000000..b561d1295da
--- /dev/null
+++ b/sql-bench/Results/RUN-msql-Linux_2.2.10_i686-cmp-msql,mysql
@@ -0,0 +1,55 @@
+Benchmark DBD suite: 2.4
+Date of test: 1999-09-23 8:59:17
+Running tests on: Linux 2.2.10 i686
+Arguments: --force
+Comments:
+Limits from: msql,mysql
+Server version: mSQL server version 2.0.10
+
+ATIS: Total time: 250 wallclock secs (23.58 usr 5.24 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+alter-table: Total time: 0 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+big-tables: Total time: 145 wallclock secs (62.58 usr 8.07 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+connect: Total time: 85 wallclock secs (47.36 usr 7.46 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+create: Total time: 14 wallclock secs ( 2.44 usr 0.28 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+insert: Estimated total time: 131515 wallclock secs (800.98 usr 112.30 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+select: Total time: 76 wallclock secs ( 5.15 usr 0.88 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+wisconsin: Total time: 23 wallclock secs ( 8.84 usr 1.42 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+All 8 test executed successfully
+Tests with estimated time have a + at end of line
+
+Totals per operation:
+Operation seconds usr sys cpu tests
+connect 19 14.02 1.84 0.00 10000
+connect+select_1_row 24 15.66 2.66 0.00 10000
+create+drop 2 0.78 0.05 0.00 1000
+create_key+drop 2 0.72 0.05 0.00 1000
+create_table 9 0.63 0.10 0.00 1031
+delete_big 11 0.01 0.00 0.00 13
+delete_big_many_keys 676 0.00 0.00 0.00 2
+delete_key 1 0.05 0.00 0.00 500
+drop_table 1 0.11 0.02 0.00 1028
+insert 126 44.02 6.90 0.00 350768
+insert_duplicates 20 7.44 1.70 0.00 300000
+insert_key 40 12.67 2.51 0.00 100000
+insert_many_fields 37 7.94 0.38 0.00 20000
+order_by 137 62.94 14.03 0.00 10
+order_by_key 138 62.91 14.50 0.00 10
+select 0 0.23 0.06 0.00 1000
+select_1_row 4 1.60 0.51 0.00 10000
+select_2_rows 4 1.72 0.47 0.00 10000
+select_big 142 77.86 16.66 0.00 10080
+select_diff_key 143 0.52 0.04 0.00 500
+select_distinct 22 5.65 1.10 0.00 700
+select_join 219 14.80 3.71 0.00 200
+select_key 244 177.74 12.56 0.00 200000
+select_key_prefix 39617 190.51 18.46 0.00 200000 +
+select_many_fields 108 54.63 7.69 0.00 20000
+select_range 15708 21.13 1.86 0.00 25400 ++
+select_range_prefix 15762 16.87 2.30 0.00 25000 ++
+select_simple_join 5 1.88 0.33 0.00 500
+update_big 73 0.00 0.00 0.00 500
+update_of_key 854 104.25 15.53 0.00 600255
+update_with_key 57942 46.67 8.71 0.00 100000
+wisc_benchmark 9 4.81 0.92 0.00 74
+TOTALS 132099 950.77 135.65 0.00 1999571 +++++
diff --git a/sql-bench/Results/RUN-mysql-3.21-Linux_2.2.1_i686 b/sql-bench/Results/RUN-mysql-3.21-Linux_2.2.1_i686
new file mode 100644
index 00000000000..97d9d3c8684
--- /dev/null
+++ b/sql-bench/Results/RUN-mysql-3.21-Linux_2.2.1_i686
@@ -0,0 +1,61 @@
+Benchmark DBD suite: 2.0b
+Date of test: 1999-02-28 15:42:20
+Running tests on: Linux 2.2.1 i686
+Arguments:
+Comments: pentiumpro 400mz x2, 256M, SCSI, gcc 2.9 compiled, key_buffer=1M
+Limits from:
+Server version: MySQL 3.21.34
+
+ATIS: Total time: 64 wallclock secs (12.66 usr 5.60 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+alter-table: Total time: 815 wallclock secs ( 0.61 usr 0.14 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+big-tables: Total time: 188 wallclock secs (10.99 usr 10.75 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+connect: Total time: 148 wallclock secs (66.47 usr 42.30 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+create: Total time: 11 wallclock secs ( 1.68 usr 0.32 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+insert: Total time: 1971 wallclock secs (362.50 usr 103.19 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+select: Estimated total time: 1794 wallclock secs (79.34 usr 14.54 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+wisconsin: Total time: 20 wallclock secs ( 4.70 usr 2.13 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+All 8 test executed successfully
+Tests with estimated time have a + at end of line
+
+Totals per operation:
+Operation seconds usr sys cpu tests
+alter_table_add 476 0.35 0.09 0.00 992
+alter_table_drop 338 0.17 0.03 0.00 496
+connect 30 14.51 10.85 0.00 10000
+connect+select 34 18.27 7.11 0.00 10000
+count 61 0.09 0.03 0.00 100
+count_on_key 640 27.18 3.47 0.00 50100 +
+create+drop 1 0.37 0.06 0.00 1000
+create_index 0 0.00 0.00 0.00 8
+create_key+drop 3 0.77 0.07 0.00 1000
+create_table 5 0.29 0.06 0.00 1031
+delete_big 206 0.00 0.00 0.00 15
+delete_key 12 0.02 0.02 0.00 500
+drop_index 0 0.00 0.00 0.00 8
+drop_table 1 0.08 0.02 0.00 1028
+insert 149 34.57 12.16 0.00 350768
+insert_duplicates 26 6.84 3.72 0.00 300000
+insert_key 157 14.40 3.85 0.00 100000
+insert_many_fields 82 0.57 0.12 0.00 2000
+min_max 23 0.04 0.00 0.00 60
+min_max_on_key 1260 40.08 4.69 0.00 73000 +
+order_by 71 28.62 19.26 0.00 10
+order_by_key 71 28.30 20.45 0.00 10
+select 7 1.71 1.41 0.00 20000
+select_big 97 44.76 25.37 0.00 10080
+select_distinct 17 2.46 1.09 0.00 800
+select_group 96 2.58 0.70 0.00 3811
+select_join 26 6.04 3.37 0.00 200
+select_key 213 109.13 13.71 0.00 200000
+select_key_prefix 247 94.75 12.42 0.00 200000
+select_many_fields 106 10.40 10.63 0.00 2000
+select_range 349 21.73 7.72 0.00 25420
+select_range_prefix 38 10.18 1.70 0.00 25010
+select_simple 34 15.95 13.30 0.00 20000
+select_simple_join 3 0.95 0.31 0.00 500
+update_key 0 0.05 0.03 0.00 500
+update_key_big 52 0.04 0.01 0.00 501
+update_of_key 72 0.03 0.03 0.00 256
+wisc_benchmark 6 2.48 1.08 0.00 114
+TOTALS 5009 538.76 178.94 0.00 1411318 ++
diff --git a/sql-bench/Results/RUN-mysql-HP_UX_B.10.20_9000_778 b/sql-bench/Results/RUN-mysql-HP_UX_B.10.20_9000_778
new file mode 100644
index 00000000000..ddbe2c4313b
--- /dev/null
+++ b/sql-bench/Results/RUN-mysql-HP_UX_B.10.20_9000_778
@@ -0,0 +1,71 @@
+Benchmark DBD suite: 2.4
+Date of test: 1999-09-27 15:10:29
+Running tests on: HP-UX B.10.20 9000/778
+Arguments: --die-on-errors
+Comments:
+Limits from:
+Server version: MySQL 3.23.4 alpha
+
+ATIS: Total time: 190 wallclock secs (33.29 usr 19.04 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+alter-table: Total time: 1664 wallclock secs ( 0.84 usr 0.22 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+big-tables: Total time: 200 wallclock secs (30.97 usr 48.92 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+connect: Total time: 238 wallclock secs (94.79 usr 32.25 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+create: Total time: 29 wallclock secs ( 2.79 usr 0.56 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+insert: Estimated total time: 16527 wallclock secs (874.45 usr 374.80 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+select: Estimated total time: 3166 wallclock secs (151.82 usr 39.40 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+wisconsin: Total time: 62 wallclock secs (10.85 usr 5.05 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+All 8 test executed successfully
+Tests with estimated time have a + at end of line
+
+Totals per operation:
+Operation seconds usr sys cpu tests
+alter_table_add 925 0.47 0.10 0.00 992
+alter_table_drop 708 0.21 0.05 0.00 496
+connect 35 18.98 4.56 0.00 10000
+connect+select_1_row 49 21.11 6.36 0.00 10000
+connect+select_simpl 44 20.27 5.93 0.00 10000
+count 321 0.11 0.01 0.00 100
+count_on_key 1745 50.62 8.11 0.00 50100 +
+create+drop 7 0.63 0.14 0.00 1000
+create_index 15 0.00 0.00 0.00 8
+create_key+drop 9 1.34 0.15 0.00 1000
+create_table 10 0.54 0.09 0.00 1031
+delete_big 47 0.00 0.00 0.00 13
+delete_big_many_keys 302 0.00 0.00 0.00 2
+delete_key 1 0.10 0.04 0.00 500
+drop_index 15 0.01 0.00 0.00 8
+drop_table 1 0.11 0.06 0.00 1028
+insert 385 51.74 23.59 0.00 350768
+insert_duplicates 50 10.92 5.91 0.00 300000
+insert_key 419 35.34 7.55 0.00 100000
+insert_many_fields 46 1.25 0.28 0.00 2000
+min_max 111 0.07 0.01 0.00 60
+min_max_on_key 644 67.10 11.51 0.00 73000 +
+multiple_value_inser 22 3.75 0.02 0.00 100000
+order_by 359 81.85 62.84 0.00 10
+order_by_key 265 81.83 80.00 0.00 10
+outer_join 414 0.01 0.00 0.00 10
+outer_join_found 396 0.01 0.01 0.00 10
+outer_join_not_found 605 0.04 0.00 0.00 500 +
+outer_join_on_key 165 0.02 0.00 0.00 10
+select_1_row 9 1.48 1.45 0.00 10000
+select_2_rows 10 1.61 1.63 0.00 10000
+select_big 357 112.70 94.48 0.00 10080
+select_diff_key 20 0.01 0.00 0.00 10 +
+select_distinct 52 6.58 3.30 0.00 800
+select_group 251 5.65 1.75 0.00 3811
+select_join 66 17.47 12.46 0.00 200
+select_key 668 218.05 41.63 0.00 200000 +
+select_key_prefix 669 217.48 41.21 0.00 200000 +
+select_many_fields 153 29.70 48.64 0.00 2000
+select_range 1011 55.72 23.90 0.00 25420 +
+select_range_prefix 91 21.34 4.68 0.00 25010
+select_simple 6 1.14 1.14 0.00 10000
+select_simple_join 8 2.34 1.03 0.00 500
+update_big 148 0.00 0.00 0.00 500
+update_of_key 170 0.15 0.06 0.00 756
+update_of_key_big 85 0.09 0.04 0.00 501
+update_with_key 681 52.02 22.51 0.00 100000
+wisc_benchmark 24 6.96 2.92 0.00 114
+TOTALS 12594 1198.92 520.15 0.00 1612358 +++++++
diff --git a/sql-bench/Results/RUN-mysql-Linux_2.0.35_i686-cmp-adabas,mysql b/sql-bench/Results/RUN-mysql-Linux_2.0.35_i686-cmp-adabas,mysql
new file mode 100644
index 00000000000..c2c9b9ba5ee
--- /dev/null
+++ b/sql-bench/Results/RUN-mysql-Linux_2.0.35_i686-cmp-adabas,mysql
@@ -0,0 +1,60 @@
+Benchmark DBD suit: 2.0
+Date of test: 1998-10-20 6:54:10
+Running tests on: Linux 2.0.35 i686
+Arguments: --small-tables
+Comments: pentiumpro 400mz x2, 256M, SCSI, pgcc compiled, key_cache=1M
+Limits from: adabas,mysql
+Server version: MySQL 3.22.9 beta
+
+ATIS: Total time: 75 secs ( 6.54 usr 21.70 sys = 28.24 cpu)
+alter-table: Total time: 39 secs ( 0.08 usr 0.33 sys = 0.41 cpu)
+big-tables: Total time: 17 secs ( 3.29 usr 6.92 sys = 10.21 cpu)
+connect: Total time: 134 secs (17.63 usr 95.64 sys = 113.27 cpu)
+create: Total time: 19 secs ( 0.75 usr 1.48 sys = 2.23 cpu)
+insert: Total time: 229 secs (30.40 usr 67.93 sys = 98.33 cpu)
+select: Estimated total time: 1075 secs (23.53 usr 69.27 sys = 92.80 cpu)
+wisconsin: Total time: 30 secs ( 3.27 usr 5.49 sys = 8.76 cpu)
+
+All 8 test executed successfully
+Tests with estimated time have a + at end of line
+
+Totals per operation:
+Operation seconds usr sys cpu tests
+alter_table_add 21 0.03 0.08 0.11 246
+alter_table_drop 15 0.02 0.11 0.13 123
+connect 53 6.27 42.43 48.70 10000
+connect+select 59 8.21 42.61 50.82 10000
+count 7 0.01 0.06 0.07 100
+count_on_key 816 10.62 28.10 38.72 50100 +
+create+drop 3 0.24 0.33 0.57 1000
+create_index 2 0.00 0.00 0.00 8
+create_key+drop 3 0.11 0.69 0.80 1000
+create_table 7 0.32 0.13 0.45 1031
+delete_big 11 0.02 0.01 0.03 15
+delete_key 0 0.00 0.04 0.04 500
+drop_index 1 0.00 0.00 0.00 8
+drop_table 0 0.07 0.12 0.19 1028
+insert 46 4.94 7.46 12.40 80768
+insert_duplicates 4 0.00 1.39 1.39 30000
+insert_key 15 0.72 1.30 2.02 10000
+insert_many_fields 4 0.43 0.25 0.68 2000
+min_max 4 0.00 0.08 0.08 60
+min_max_on_key 233 11.76 38.73 50.49 73000
+order_by 10 2.24 6.64 8.88 10
+order_by_key 6 1.44 4.75 6.19 10
+select 12 0.79 5.75 6.54 20000
+select_big 18 4.43 9.37 13.80 10080
+select_distinct 20 0.92 3.98 4.90 800
+select_group 24 0.85 2.84 3.69 3401
+select_join 34 3.85 12.82 16.67 200
+select_key 25 5.64 11.36 17.00 20000
+select_key_prefix 27 6.22 11.03 17.25 20000
+select_many_fields 13 2.84 6.67 9.51 2000
+select_range 60 5.59 13.95 19.54 25420
+select_range_prefix 40 4.40 11.13 15.53 25010
+select_simple_join 3 0.50 1.29 1.79 500
+update_key 1 0.05 0.07 0.12 500
+update_key_big 4 0.03 0.04 0.07 480
+update_of_key 7 0.02 0.04 0.06 256
+wisc_benchmark 9 1.84 2.92 4.76 114
+TOTALS 1617 85.42 268.57 353.99 399768 +
diff --git a/sql-bench/Results/RUN-mysql-Linux_2.0.36_i686-cmp-mysql,pg,solid b/sql-bench/Results/RUN-mysql-Linux_2.0.36_i686-cmp-mysql,pg,solid
new file mode 100644
index 00000000000..fed62d5cefb
--- /dev/null
+++ b/sql-bench/Results/RUN-mysql-Linux_2.0.36_i686-cmp-mysql,pg,solid
@@ -0,0 +1,58 @@
+Benchmark DBD suite: 2.0b
+Date of test: 1999-03-07 22:58:12
+Running tests on: Linux 2.0.36 i686
+Arguments: --force
+Comments:
+Limits from: mysql,pg,solid
+Server version: MySQL 3.22.18
+
+ATIS: Total time: 49 wallclock secs (10.38 usr 4.19 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+alter-table: Total time: 23 wallclock secs ( 0.14 usr 0.03 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+big-tables: Total time: 15 wallclock secs ( 4.57 usr 2.58 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+connect: Total time: 53 wallclock secs (25.85 usr 5.76 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+create: Total time: 15 wallclock secs ( 1.48 usr 0.25 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+insert: Total time: 1389 wallclock secs (376.47 usr 81.30 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+select: Total time: 630 wallclock secs (42.58 usr 5.63 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+wisconsin: Total time: 20 wallclock secs ( 4.61 usr 1.48 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+All 8 test executed successfully
+
+Totals per operation:
+Operation seconds usr sys cpu tests
+alter_table_add 21 0.08 0.01 0.00 293
+connect 15 8.66 1.63 0.00 10000
+connect+select 19 9.61 2.34 0.00 10000
+count 59 0.08 0.01 0.00 100
+count_on_key 640 25.56 3.32 0.00 50100
+create+drop 3 0.39 0.08 0.00 1000
+create_index 1 0.00 0.00 0.00 7
+create_key+drop 2 0.55 0.02 0.00 1000
+create_table 6 0.31 0.05 0.00 1031
+delete_big 67 0.01 0.00 0.00 15
+delete_key 10 0.11 0.02 0.00 500
+drop_index 1 0.00 0.00 0.00 7
+drop_table 0 0.12 0.05 0.00 1028
+insert 162 41.63 9.65 0.00 350768
+insert_duplicates 18 5.06 2.17 0.00 300000
+insert_key 165 12.53 3.21 0.00 100000
+insert_many_fields 4 0.55 0.10 0.00 2000
+min_max 27 0.02 0.00 0.00 60
+min_max_on_key 32 15.90 1.97 0.00 73000
+order_by 73 23.18 12.42 0.00 10
+order_by_key 50 23.37 12.37 0.00 10
+select 8 1.75 0.95 0.00 20000
+select_big 61 29.19 12.82 0.00 10080
+select_distinct 14 2.23 0.74 0.00 800
+select_group 41 1.57 0.25 0.00 3101
+select_join 22 4.87 2.75 0.00 200
+select_key 230 115.25 13.94 0.00 200000
+select_key_prefix 242 115.60 13.94 0.00 200000
+select_many_fields 11 4.02 2.48 0.00 2000
+select_range 29 10.70 1.56 0.00 25420
+select_range_prefix 35 10.03 1.41 0.00 25010
+select_simple_join 2 0.91 0.24 0.00 500
+update_key 4 0.07 0.02 0.00 500
+update_key_big 27 0.06 0.01 0.00 501
+update_of_key 83 0.02 0.00 0.00 256
+wisc_benchmark 6 1.99 0.67 0.00 114
+TOTALS 2190 465.98 101.20 0.00 1389411
diff --git a/sql-bench/Results/RUN-mysql-Linux_2.2.10_i686 b/sql-bench/Results/RUN-mysql-Linux_2.2.10_i686
new file mode 100644
index 00000000000..680c9ab70cb
--- /dev/null
+++ b/sql-bench/Results/RUN-mysql-Linux_2.2.10_i686
@@ -0,0 +1,71 @@
+Benchmark DBD suite: 2.4
+Date of test: 1999-09-17 8:33:49
+Running tests on: Linux 2.2.10 i686
+Arguments: --force
+Comments:
+Limits from:
+Server version: MySQL 3.23.3 alpha
+
+ATIS: Total time: 65 wallclock secs (19.72 usr 2.93 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+alter-table: Total time: 514 wallclock secs ( 0.65 usr 0.06 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+big-tables: Total time: 50 wallclock secs (18.30 usr 6.26 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+connect: Total time: 120 wallclock secs (66.02 usr 10.12 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+create: Total time: 9 wallclock secs ( 2.21 usr 0.26 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+insert: Estimated total time: 6039 wallclock secs (648.24 usr 76.17 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+select: Total time: 1209 wallclock secs (110.89 usr 8.88 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+wisconsin: Total time: 23 wallclock secs ( 7.83 usr 1.45 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+All 8 test executed successfully
+Tests with estimated time have a + at end of line
+
+Totals per operation:
+Operation seconds usr sys cpu tests
+alter_table_add 280 0.37 0.03 0.00 992
+alter_table_drop 222 0.16 0.01 0.00 496
+connect 18 13.36 1.13 0.00 10000
+connect+select_1_row 23 14.47 1.60 0.00 10000
+connect+select_simpl 21 14.34 1.42 0.00 10000
+count 73 0.08 0.02 0.00 100
+count_on_key 648 38.95 2.36 0.00 50100
+create+drop 1 0.63 0.01 0.00 1000
+create_index 5 0.00 0.00 0.00 8
+create_key+drop 2 0.78 0.07 0.00 1000
+create_table 4 0.46 0.07 0.00 1031
+delete_big 21 0.00 0.00 0.00 13
+delete_big_many_keys 257 0.00 0.00 0.00 2
+delete_key 1 0.12 0.00 0.00 500
+drop_index 6 0.00 0.00 0.00 8
+drop_table 1 0.15 0.05 0.00 1028
+insert 173 53.61 9.85 0.00 350768
+insert_duplicates 16 5.74 1.67 0.00 300000
+insert_key 209 21.42 3.48 0.00 100000
+insert_many_fields 13 0.88 0.09 0.00 2000
+min_max 37 0.04 0.01 0.00 60
+min_max_on_key 265 53.70 3.63 0.00 73000
+multiple_value_inser 9 2.46 0.02 0.00 100000
+order_by 90 46.67 8.04 0.00 10
+order_by_key 69 46.84 7.93 0.00 10
+outer_join 84 0.00 0.00 0.00 10
+outer_join_found 82 0.01 0.00 0.00 10
+outer_join_not_found 605 0.13 0.00 0.00 500 +
+outer_join_on_key 65 0.02 0.00 0.00 10
+select_1_row 3 1.05 0.33 0.00 10000
+select_2_rows 4 1.26 0.35 0.00 10000
+select_big 118 67.93 13.05 0.00 10080
+select_diff_key 305 0.55 0.02 0.00 500
+select_distinct 19 3.71 0.50 0.00 800
+select_group 75 3.65 0.46 0.00 3811
+select_join 23 9.91 1.72 0.00 200
+select_key 401 164.79 11.47 0.00 200000
+select_key_prefix 406 175.76 12.40 0.00 200000
+select_many_fields 37 17.41 6.17 0.00 2000
+select_range 387 33.53 3.87 0.00 25420
+select_range_prefix 42 15.23 1.30 0.00 25010
+select_simple 2 0.74 0.31 0.00 10000
+select_simple_join 3 1.40 0.18 0.00 500
+update_big 34 0.00 0.00 0.00 500
+update_of_key 61 0.11 0.06 0.00 756
+update_of_key_big 29 0.08 0.00 0.00 501
+update_with_key 381 57.20 11.84 0.00 100000
+wisc_benchmark 7 3.42 0.58 0.00 114
+TOTALS 5637 873.12 106.10 0.00 1612848 +
diff --git a/sql-bench/Results/RUN-mysql-Linux_2.2.10_i686-cmp-msql,mysql b/sql-bench/Results/RUN-mysql-Linux_2.2.10_i686-cmp-msql,mysql
new file mode 100644
index 00000000000..eb86300dcbe
--- /dev/null
+++ b/sql-bench/Results/RUN-mysql-Linux_2.2.10_i686-cmp-msql,mysql
@@ -0,0 +1,55 @@
+Benchmark DBD suite: 2.4
+Date of test: 1999-09-24 9:48:18
+Running tests on: Linux 2.2.10 i686
+Arguments: --force
+Comments:
+Limits from: msql,mysql
+Server version: MySQL 3.23.3 alpha
+
+ATIS: Total time: 45 wallclock secs (16.16 usr 2.81 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+alter-table: Total time: 0 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+big-tables: Total time: 63 wallclock secs (32.36 usr 5.77 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+connect: Total time: 83 wallclock secs (43.74 usr 9.45 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+create: Total time: 14 wallclock secs ( 1.89 usr 0.16 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+insert: Estimated total time: 3485 wallclock secs (788.07 usr 99.92 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+select: Total time: 18 wallclock secs ( 5.78 usr 0.91 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+wisconsin: Total time: 20 wallclock secs ( 6.95 usr 1.15 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+All 8 test executed successfully
+Tests with estimated time have a + at end of line
+
+Totals per operation:
+Operation seconds usr sys cpu tests
+connect 23 13.79 3.43 0.00 10000
+connect+select_1_row 27 14.93 4.05 0.00 10000
+create+drop 3 0.46 0.03 0.00 1000
+create_key+drop 3 0.54 0.02 0.00 1000
+create_table 4 0.47 0.05 0.00 1031
+delete_big 20 0.00 0.00 0.00 13
+delete_big_many_keys 35 0.00 0.00 0.00 2
+delete_key 1 0.16 0.01 0.00 500
+drop_table 2 0.16 0.03 0.00 1028
+insert 171 53.22 8.79 0.00 350768
+insert_duplicates 18 6.67 2.24 0.00 300000
+insert_key 80 15.22 2.82 0.00 100000
+insert_many_fields 19 7.17 0.61 0.00 20000
+order_by 90 46.72 8.08 0.00 10
+order_by_key 69 47.13 7.95 0.00 10
+select 2 0.27 0.03 0.00 1000
+select_1_row 3 1.07 0.37 0.00 10000
+select_2_rows 4 1.16 0.50 0.00 10000
+select_big 95 59.90 9.19 0.00 10080
+select_diff_key 305 0.59 0.01 0.00 500
+select_distinct 15 3.62 0.44 0.00 700
+select_join 23 9.83 1.84 0.00 200
+select_key 402 154.50 10.45 0.00 200000
+select_key_prefix 404 172.53 12.29 0.00 200000
+select_many_fields 44 25.18 5.15 0.00 20000
+select_range 50 18.23 1.91 0.00 25400
+select_range_prefix 41 14.77 1.16 0.00 25000
+select_simple_join 3 1.30 0.25 0.00 500
+update_big 50 0.00 0.01 0.00 500
+update_of_key 1336 160.83 25.83 0.00 600256 +
+update_with_key 381 62.03 12.20 0.00 100000
+wisc_benchmark 4 2.40 0.42 0.00 74
+TOTALS 3727 894.85 120.16 0.00 1999572 +
diff --git a/sql-bench/Results/RUN-mysql-Linux_2.2.14_i686_xeon b/sql-bench/Results/RUN-mysql-Linux_2.2.14_i686_xeon
new file mode 100644
index 00000000000..3a6307a943d
--- /dev/null
+++ b/sql-bench/Results/RUN-mysql-Linux_2.2.14_i686_xeon
@@ -0,0 +1,79 @@
+Benchmark DBD suite: 2.8
+Date of test: 2000-06-01 11:07:08
+Running tests on: Linux 2.2.14 i686
+Arguments:
+Comments: Pentium 2x550 MZ Xeon, 512M, IDE, 16M key_buffer
+Limits from:
+Server version: MySQL 3.23.17 alpha
+
+alter-table: Total time: 359 wallclock secs ( 0.47 usr 0.14 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+ATIS: Total time: 40 wallclock secs ( 8.55 usr 3.92 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+big-tables: Total time: 33 wallclock secs ( 8.89 usr 7.76 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+connect: Total time: 74 wallclock secs (30.09 usr 16.72 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+create: Total time: 419 wallclock secs (10.58 usr 3.09 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+insert: Total time: 1552 wallclock secs (263.84 usr 86.41 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+select: Total time: 1797 wallclock secs (126.08 usr 67.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+wisconsin: Total time: 15 wallclock secs ( 3.20 usr 1.66 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+All 8 test executed successfully
+
+Totals per operation:
+Operation seconds usr sys cpu tests
+alter_table_add 198.00 0.29 0.06 0.00 992
+alter_table_drop 154.00 0.14 0.04 0.00 496
+connect 12.00 6.38 2.82 0.00 10000
+connect+select_1_row 15.00 6.57 3.78 0.00 10000
+connect+select_simple 13.00 6.71 3.26 0.00 10000
+count 42.00 0.10 0.00 0.00 100
+count_distinct 110.00 0.78 0.10 0.00 1000
+count_distinct_big 632.00 73.98 55.47 0.00 1020
+count_distinct_group 75.00 1.20 0.44 0.00 1000
+count_distinct_group_on_key 58.00 0.41 0.03 0.00 1000
+count_distinct_group_on_key_parts 74.00 1.18 0.60 0.00 1000
+count_group_on_key_parts 0.00 0.00 0.00 0.00 0
+count_on_key 557.00 17.72 2.69 0.00 50100
+create+drop 19.00 2.43 0.72 0.00 10000
+create_MANY_tables 263.00 2.58 0.48 0.00 10000
+create_index 4.00 0.00 0.00 0.00 8
+create_key+drop 18.00 3.88 0.95 0.00 10000
+create_table 0.00 0.00 0.00 0.00 31
+delete_big 15.00 0.01 0.00 0.00 13
+delete_big_many_keys 59.00 0.00 0.00 0.00 2
+delete_key 3.00 0.73 0.34 0.00 10000
+drop_index 3.00 0.01 0.00 0.00 8
+drop_table 0.00 0.00 0.00 0.00 28
+drop_table_when_MANY_tables 22.00 0.59 0.42 0.00 10000
+insert 109.00 20.53 9.93 0.00 350768
+insert_duplicates 14.00 3.03 3.14 0.00 300000
+insert_key 111.00 10.00 3.74 0.00 100000
+insert_many_fields 10.00 0.45 0.11 0.00 2000
+min_max 29.00 0.00 0.00 0.00 60
+min_max_on_key 219.00 26.38 4.12 0.00 85000
+multiple_value_insert 7.00 1.92 0.05 0.00 100000
+order_by 47.00 20.41 15.62 0.00 10
+order_by_key 30.00 20.22 10.11 0.00 10
+outer_join 63.00 0.01 0.00 0.00 10
+outer_join_found 60.00 0.00 0.00 0.00 10
+outer_join_not_found 46.00 0.00 0.00 0.00 500
+outer_join_on_key 51.00 0.00 0.00 0.00 10
+select_1_row 2.00 0.54 0.38 0.00 10000
+select_2_rows 3.00 0.57 0.44 0.00 10000
+select_big 59.00 29.63 15.74 0.00 10080
+select_diff_key 174.00 0.28 0.03 0.00 500
+select_distinct 11.00 1.69 0.81 0.00 800
+select_group 64.00 1.61 0.41 0.00 2911
+select_group_when_MANY_tables 97.00 1.09 0.52 0.00 10000
+select_join 13.00 4.26 2.21 0.00 200
+select_key 128.00 66.75 11.61 0.00 200000
+select_key_prefix 130.00 66.91 10.48 0.00 200000
+select_many_fields 23.00 8.43 7.65 0.00 2000
+select_range 208.00 14.67 5.30 0.00 25420
+select_range_prefix 18.00 5.83 1.38 0.00 25010
+select_simple 2.00 0.34 0.39 0.00 10000
+select_simple_join 2.00 0.59 0.26 0.00 500
+update_big 28.00 0.00 0.00 0.00 500
+update_of_key 59.00 2.65 1.37 0.00 756
+update_of_key_big 25.00 0.02 0.01 0.00 501
+update_with_key 97.00 15.38 7.87 0.00 100000
+wisc_benchmark 4.00 1.72 0.77 0.00 114
+TOTALS 4289.00 451.60 186.65 0.00 1684468
diff --git a/sql-bench/Results/RUN-mysql-Linux_2.2.1_i686-cmp-adabas,mysql b/sql-bench/Results/RUN-mysql-Linux_2.2.1_i686-cmp-adabas,mysql
new file mode 100644
index 00000000000..0a6bb635a0e
--- /dev/null
+++ b/sql-bench/Results/RUN-mysql-Linux_2.2.1_i686-cmp-adabas,mysql
@@ -0,0 +1,60 @@
+Benchmark DBD suite: 2.0b
+Date of test: 1999-02-27 21:10:25
+Running tests on: Linux 2.2.1 i686
+Arguments: --small-tables
+Comments: pentiumpro 400mz x2, 256M, SCSI, gcc 2.9 compiled, key_buffer=16M
+Limits from: adabas,mysql
+Server version: MySQL 3.22.18
+
+ATIS: Total time: 60 wallclock secs (12.57 usr 5.44 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+alter-table: Total time: 52 wallclock secs ( 0.24 usr 0.05 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+big-tables: Total time: 14 wallclock secs ( 4.45 usr 2.53 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+connect: Total time: 82 wallclock secs (37.13 usr 26.79 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+create: Total time: 8 wallclock secs ( 1.54 usr 0.17 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+insert: Total time: 190 wallclock secs (58.47 usr 13.42 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+select: Estimated total time: 870 wallclock secs (63.67 usr 9.06 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+wisconsin: Total time: 20 wallclock secs ( 4.66 usr 1.94 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+All 8 test executed successfully
+Tests with estimated time have a + at end of line
+
+Totals per operation:
+Operation seconds usr sys cpu tests
+alter_table_add 28 0.08 0.01 0.00 246
+alter_table_drop 20 0.06 0.00 0.00 123
+connect 31 15.46 11.47 0.00 10000
+connect+select 35 15.54 13.17 0.00 10000
+count 6 0.07 0.00 0.00 100
+count_on_key 666 26.25 3.49 0.00 50100 +
+create+drop 1 0.34 0.08 0.00 1000
+create_index 1 0.00 0.00 0.00 8
+create_key+drop 2 0.66 0.04 0.00 1000
+create_table 3 0.27 0.04 0.00 1031
+delete_big 9 0.00 0.01 0.00 15
+delete_key 0 0.05 0.01 0.00 500
+drop_index 3 0.00 0.00 0.00 8
+drop_table 1 0.11 0.01 0.00 1028
+insert 34 7.31 2.56 0.00 80768
+insert_duplicates 2 0.66 0.33 0.00 30000
+insert_key 12 1.48 0.37 0.00 10000
+insert_many_fields 4 0.48 0.08 0.00 2000
+min_max 3 0.03 0.00 0.00 60
+min_max_on_key 198 35.49 4.72 0.00 73000
+order_by 6 2.90 2.06 0.00 10
+order_by_key 5 2.85 1.53 0.00 10
+select 7 1.75 1.39 0.00 20000
+select_big 16 7.44 2.22 0.00 10080
+select_distinct 17 2.78 0.90 0.00 800
+select_group 15 2.30 0.51 0.00 3401
+select_join 27 5.95 3.49 0.00 200
+select_key 21 10.95 1.39 0.00 20000
+select_key_prefix 23 11.28 1.58 0.00 20000
+select_many_fields 10 3.96 2.45 0.00 2000
+select_range 36 12.14 2.53 0.00 25420
+select_range_prefix 35 10.36 1.69 0.00 25010
+select_simple_join 2 0.96 0.24 0.00 500
+update_key 1 0.04 0.02 0.00 500
+update_key_big 3 0.08 0.00 0.00 480
+update_of_key 6 0.03 0.01 0.00 256
+wisc_benchmark 7 2.45 0.96 0.00 114
+TOTALS 1296 182.56 59.36 0.00 399768 +
diff --git a/sql-bench/Results/RUN-mysql-NT_4.0 b/sql-bench/Results/RUN-mysql-NT_4.0
new file mode 100644
index 00000000000..10b09bab41a
--- /dev/null
+++ b/sql-bench/Results/RUN-mysql-NT_4.0
@@ -0,0 +1,78 @@
+Benchmark DBD suite: 2.8
+Date of test: 2000-06-02 23:00:05
+Running tests on: Windows NT Version 4.0
+Arguments:
+Comments: Pentium 2x550 xeon, 550 Mhz, IDE
+Limits from:
+Server version: MySQL 3.23.17a alpha
+
+alter-table: Total time: 2260 wallclock secs ( 0.89 usr 0.42 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+ATIS: Total time: 68 wallclock secs (23.67 usr 10.17 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+big-tables: Total time: 80 wallclock secs (17.91 usr 18.64 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+connect: Total time: 186 wallclock secs (56.84 usr 51.02 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+create: Total time: 1040 wallclock secs (13.34 usr 9.47 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+insert: Total time: 4284 wallclock secs (485.59 usr 280.22 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+select: Total time: 2255 wallclock secs (315.95 usr 115.52 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+wisconsin: Total time: 29 wallclock secs ( 8.19 usr 5.44 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Totals per operation:
+Operation seconds usr sys cpu tests
+alter_table_add 1201.00 0.53 0.19 0.00 992
+alter_table_drop 1009.00 0.23 0.09 0.00 496
+connect 34.00 11.53 10.31 0.00 10000
+connect+select_1_row 39.00 12.75 13.53 0.00 10000
+connect+select_simple 37.00 12.56 11.92 0.00 10000
+count 40.00 0.11 0.05 0.00 100
+count_distinct 69.00 1.17 0.41 0.00 1000
+count_distinct_big 1229.00 224.25 81.19 0.00 1020
+count_distinct_group 152.00 2.81 0.92 0.00 1000
+count_distinct_group_on_key 38.00 0.70 0.17 0.00 1000
+count_distinct_group_on_key_parts 153.00 2.61 1.03 0.00 1000
+count_group_on_key_parts 34.00 2.64 1.00 0.00 1000
+count_on_key 347.00 21.47 8.38 0.00 50100
+create+drop 123.00 3.36 2.61 0.00 10000
+create_MANY_tables 232.00 2.97 1.23 0.00 10000
+create_index 25.00 0.00 0.00 0.00 8
+create_key+drop 156.00 5.13 2.78 0.00 10000
+create_table 1.00 0.02 0.00 0.00 31
+delete_big 21.00 0.00 0.00 0.00 13
+delete_big_many_keys 438.00 0.00 0.00 0.00 2
+delete_key 6.00 0.84 1.30 0.00 10000
+drop_index 25.00 0.00 0.00 0.00 8
+drop_table 0.00 0.00 0.00 0.00 28
+drop_table_when_MANY_tables 223.00 0.80 1.34 0.00 10000
+insert 235.00 34.08 47.74 0.00 350768
+insert_duplicates 38.00 8.48 12.98 0.00 300000
+insert_key 1418.00 13.78 12.97 0.00 100000
+insert_many_fields 22.00 0.58 0.49 0.00 2000
+min_max 18.00 0.05 0.00 0.00 60
+min_max_on_key 175.00 37.82 14.90 0.00 85000
+multiple_value_insert 10.00 2.59 0.14 0.00 100000
+order_by 98.00 62.59 25.67 0.00 10
+order_by_key 88.00 62.23 25.44 0.00 10
+outer_join 115.00 0.00 0.00 0.00 10
+outer_join_found 102.00 0.01 0.00 0.00 10
+outer_join_not_found 54.00 0.02 0.00 0.00 500
+outer_join_on_key 37.00 0.05 0.00 0.00 10
+select_1_row 5.00 1.11 1.91 0.00 10000
+select_2_rows 7.00 1.23 1.58 0.00 10000
+select_big 142.00 78.10 33.81 0.00 10080
+select_column+column 6.00 1.05 1.86 0.00 10000
+select_diff_key 138.00 0.52 0.16 0.00 500
+select_distinct 17.00 4.78 1.80 0.00 800
+select_group 51.00 3.64 1.15 0.00 2911
+select_group_when_MANY_tables 306.00 1.09 1.50 0.00 10000
+select_join 22.00 12.86 5.22 0.00 200
+select_key 201.00 92.41 38.77 0.00 200000
+select_key_prefix 198.00 93.94 37.94 0.00 200000
+select_many_fields 55.00 17.33 18.16 0.00 2000
+select_range 213.00 37.28 12.82 0.00 25420
+select_range_prefix 28.00 9.94 4.00 0.00 25010
+select_simple 4.00 0.94 1.67 0.00 10000
+select_simple_join 3.00 1.58 0.66 0.00 500
+update_big 64.00 0.00 0.01 0.00 500
+update_of_key 468.00 4.61 6.75 0.00 756
+update_of_key_big 33.00 0.05 0.05 0.00 501
+update_with_key 185.00 25.34 40.66 0.00 100000
+wisc_benchmark 9.00 5.66 1.53 0.00 114
+TOTALS 10191.00 921.17 488.93 0.00 1685468
diff --git a/sql-bench/Results/RUN-mysql-SunOS_5.5.1_sun4u b/sql-bench/Results/RUN-mysql-SunOS_5.5.1_sun4u
new file mode 100644
index 00000000000..03154c0bc1d
--- /dev/null
+++ b/sql-bench/Results/RUN-mysql-SunOS_5.5.1_sun4u
@@ -0,0 +1,62 @@
+Benchmark DBD suite: 2.0b
+Date of test: 1999-03-02 8:21:57
+Running tests on: SunOS 5.5.1 sun4u
+Arguments:
+Comments: UltraSPARC, 2 CPU 200 MHz, 1G mem, key_buffer=8M
+Limits from:
+Server version: MySQL 3.22.19
+
+ATIS: Total time: 207 wallclock secs (32.58 usr 14.99 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+alter-table: Total time: 1333 wallclock secs ( 0.81 usr 0.36 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+big-tables: Total time: 130 wallclock secs (29.10 usr 30.32 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+connect: Total time: 322 wallclock secs (94.60 usr 95.02 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+create: Total time: 75 wallclock secs ( 2.76 usr 1.05 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+insert: Total time: 3635 wallclock secs (781.69 usr 305.43 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+select: Estimated total time: 3136 wallclock secs (134.58 usr 42.60 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+wisconsin: Total time: 59 wallclock secs (10.08 usr 6.48 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+All 8 test executed successfully
+Tests with estimated time have a + at end of line
+
+Totals per operation:
+Operation seconds usr sys cpu tests
+alter_table_add 775 0.47 0.12 0.00 992
+alter_table_drop 534 0.22 0.13 0.00 496
+connect 79 23.14 25.86 0.00 10000
+connect+select 87 25.51 28.78 0.00 10000
+count 131 0.14 0.01 0.00 100
+count_on_key 2201 43.27 11.20 0.00 50100 +
+create+drop 22 0.78 0.32 0.00 1000
+create_index 11 0.00 0.00 0.00 8
+create_key+drop 20 1.12 0.26 0.00 1000
+create_table 22 0.56 0.17 0.00 1031
+delete_big 328 0.00 0.00 0.00 15
+delete_key 1 0.09 0.05 0.00 500
+drop_index 12 0.01 0.00 0.00 8
+drop_table 10 0.12 0.12 0.00 1028
+insert 435 56.40 42.52 0.00 350768
+insert_duplicates 59 14.62 11.60 0.00 300000
+insert_key 432 32.22 14.09 0.00 100000
+insert_many_fields 40 1.01 0.29 0.00 2000
+min_max 86 0.12 0.00 0.00 60
+min_max_on_key 411 58.42 16.34 0.00 73000
+multiple_value_inser 24 3.72 0.06 0.00 100000
+order_by 215 84.17 40.10 0.00 10
+order_by_key 137 83.69 41.88 0.00 10
+select 18 3.55 3.71 0.00 20000
+select_big 178 101.72 48.96 0.00 10080
+select_distinct 53 6.14 2.71 0.00 800
+select_group 303 5.27 2.02 0.00 3811
+select_join 90 17.84 8.44 0.00 200
+select_key 468 197.61 52.82 0.00 200000
+select_key_prefix 468 190.39 54.04 0.00 200000
+select_many_fields 89 28.07 30.03 0.00 2000
+select_range 719 52.11 20.66 0.00 25420
+select_range_prefix 87 19.41 5.90 0.00 25010
+select_simple 93 25.87 29.33 0.00 20000
+select_simple_join 8 2.20 0.97 0.00 500
+update_key 1 0.07 0.04 0.00 500
+update_key_big 82 0.12 0.05 0.00 501
+update_of_key 149 0.09 0.03 0.00 256
+wisc_benchmark 16 5.71 2.51 0.00 114
+TOTALS 8894 1085.97 496.12 0.00 1511318 +
diff --git a/sql-bench/Results/RUN-mysql-SunOS_5.7_sun4m b/sql-bench/Results/RUN-mysql-SunOS_5.7_sun4m
new file mode 100644
index 00000000000..2543a44ebc5
--- /dev/null
+++ b/sql-bench/Results/RUN-mysql-SunOS_5.7_sun4m
@@ -0,0 +1,62 @@
+Benchmark DBD suite: 2.0b
+Date of test: 1999-03-19 11:16:57
+Running tests on: SunOS 5.7 sun4m
+Arguments:
+Comments: Sparc sun4m, 40MHz, 196M RAM
+Limits from:
+Server version: MySQL 3.22.20
+
+alter-table: Total time: 6026 secs ( 3.39 usr 2.11 sys + 0.00 cusr 0.00 csys = 5.50 cpu)
+ATIS: Total time: 1153 secs (147.11 usr 124.50 sys + 0.00 cusr 0.00 csys = 271.61 cpu)
+big-tables: Total time: 674 secs (112.16 usr 179.21 sys + 0.00 cusr 0.00 csys = 291.37 cpu)
+connect: Total time: 1514 secs (426.83 usr 331.83 sys + 0.00 cusr 0.00 csys = 758.66 cpu)
+create: Total time: 377 secs (11.94 usr 6.22 sys + 0.00 cusr 0.00 csys = 18.16 cpu)
+insert: Estimated total time: 20234 secs (3468.07 usr 1826.12 sys + 0.00 cusr 0.00 csys = 5294.18 cpu)
+select: Estimated total time: 17283 secs (681.00 usr 335.49 sys + 0.00 cusr 0.00 csys = 1016.50 cpu)
+wisconsin: Total time: 291 secs (47.32 usr 34.98 sys + 0.00 cusr 0.00 csys = 82.30 cpu)
+
+All 8 test executed successfully
+Tests with estimated time have a + at end of line
+
+Totals per operation:
+Operation seconds usr sys cpu tests
+alter_table_add 3419 1.97 0.98 2.95 992
+alter_table_drop 2509 0.68 0.48 1.16 496
+connect 292 88.91 68.44 157.35 10000
+connect+select 363 104.08 83.81 187.89 10000
+count 539 0.53 0.14 0.67 100
+count_on_key 12306 215.39 80.44 295.84 50100 +
+create+drop 110 2.56 2.18 4.74 1000
+create_index 47 0.02 0.01 0.03 8
+create_key+drop 116 5.71 1.29 7.00 1000
+create_table 98 2.20 1.07 3.27 1031
+delete_big 2534 0.02 0.02 0.04 15
+delete_key 4 0.43 0.34 0.77 500
+drop_index 47 0.01 0.00 0.01 8
+drop_table 48 0.61 0.77 1.38 1028
+insert 1898 251.51 256.93 508.44 350768
+insert_duplicates 330 64.66 64.80 129.46 300000
+insert_key 2879 151.51 77.43 228.94 100000
+insert_many_fields 203 6.43 2.61 9.04 2000
+min_max 437 0.34 0.09 0.43 60
+min_max_on_key 2306 286.71 107.71 394.42 73000 +
+multiple_value_inser 128 16.22 0.49 16.71 100000
+order_by 1373 367.25 247.43 614.68 10 +
+order_by_key 932 400.17 269.81 669.99 10 +
+select 111 15.93 28.54 44.47 20000
+select_big 1298 507.77 332.35 840.12 10080
+select_distinct 292 28.26 22.92 51.18 800
+select_group 1508 22.22 14.17 36.39 3811
+select_join 572 81.23 73.44 154.67 200
+select_key 2290 906.93 309.98 1216.91 200000 +
+select_key_prefix 2353 783.46 293.15 1076.61 200000 +
+select_many_fields 469 105.58 176.57 282.15 2000
+select_range 3599 259.81 172.56 432.37 25420 +
+select_range_prefix 401 81.95 32.65 114.60 25010
+select_simple 362 95.62 92.74 188.36 20000
+select_simple_join 37 9.62 7.92 17.54 500
+update_key 2 0.34 0.33 0.67 500
+update_key_big 380 0.33 0.25 0.58 501
+update_of_key 835 0.30 0.30 0.60 256
+wisc_benchmark 110 29.24 14.59 43.83 114
+TOTALS 47537 4896.51 2839.73 7736.26 1511318 +++++++
diff --git a/sql-bench/Results/RUN-mysql-SunOS_5.7_sun4u b/sql-bench/Results/RUN-mysql-SunOS_5.7_sun4u
new file mode 100644
index 00000000000..e39e16a8c00
--- /dev/null
+++ b/sql-bench/Results/RUN-mysql-SunOS_5.7_sun4u
@@ -0,0 +1,72 @@
+Benchmark DBD suite: 2.5
+Date of test: 2000-01-18 9:22:49
+Running tests on: SunOS 5.7 sun4u
+Arguments:
+Comments: UltraSPARC-II 2/CPU 400 MHz, 2G mem, key_buffer=16M
+Limits from:
+Server version: MySQL 3.23.8 alpha
+
+ATIS: Total time: 89 wallclock secs (16.85 usr 13.36 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+alter-table: Total time: 1397 wallclock secs ( 0.41 usr 0.23 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+big-tables: Total time: 73 wallclock secs (15.87 usr 24.95 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+connect: Total time: 141 wallclock secs (46.24 usr 45.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+create: Total time: 3631 wallclock secs (10.19 usr 5.95 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+insert: Estimated total time: 8580 wallclock secs (396.21 usr 267.41 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+select: Total time: 1094 wallclock secs (67.65 usr 35.57 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+wisconsin: Total time: 30 wallclock secs ( 4.87 usr 5.02 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+All 8 test executed successfully
+Tests with estimated time have a + at end of line
+
+Totals per operation:
+Operation seconds usr sys cpu tests
+alter_table_add 821 0.23 0.09 0.00 992
+alter_table_drop 555 0.10 0.04 0.00 496
+connect 30 10.70 10.77 0.00 10000
+connect+select_1_row 35 11.86 11.88 0.00 10000
+connect+select_simpl 33 11.76 11.97 0.00 10000
+count 53 0.05 0.01 0.00 100
+count_on_key 585 20.36 8.74 0.00 50100
+create+drop 934 2.88 1.85 0.00 10000
+create_index 11 0.00 0.00 0.00 8
+create_key+drop 1008 3.17 1.20 0.00 10000
+create_many_tables 1130 2.65 0.89 0.00 10000
+create_table 1 0.00 0.00 0.00 31
+delete_big 25 0.00 0.00 0.00 13
+delete_big_many_keys 251 0.00 0.00 0.00 2
+delete_key 1 0.04 0.00 0.00 500
+drop_index 10 0.00 0.00 0.00 8
+drop_table 520 0.60 0.72 0.00 10028
+insert 261 24.45 30.83 0.00 350768
+insert_duplicates 33 6.55 8.84 0.00 300000
+insert_key 1333 14.75 8.04 0.00 100000
+insert_many_fields 18 0.62 0.18 0.00 2000
+min_max 36 0.06 0.01 0.00 60
+min_max_on_key 228 30.61 12.97 0.00 73000
+multiple_value_inser 13 1.72 0.03 0.00 100000
+order_by 111 45.15 37.26 0.00 10
+order_by_key 84 45.63 36.98 0.00 10
+outer_join 132 0.00 0.00 0.00 10
+outer_join_found 132 0.01 0.00 0.00 10
+outer_join_not_found 603 0.07 0.00 0.00 500 +
+outer_join_on_key 86 0.00 0.00 0.00 10
+select_1_row 5 0.94 1.70 0.00 10000
+select_2_rows 6 0.96 1.77 0.00 10000
+select_big 114 55.66 42.41 0.00 10080
+select_diff_key 311 0.28 0.11 0.00 500
+select_distinct 27 3.30 2.56 0.00 800
+select_group 132 3.14 2.90 0.00 12811
+select_join 26 9.53 7.43 0.00 200
+select_key 210 84.78 37.42 0.00 200000
+select_key_prefix 213 92.33 41.44 0.00 200000
+select_many_fields 55 15.24 24.77 0.00 2000
+select_range 366 25.66 17.72 0.00 25420
+select_range_prefix 36 9.23 4.79 0.00 25010
+select_simple 4 0.82 1.35 0.00 10000
+select_simple_join 4 1.19 0.90 0.00 500
+update_big 69 0.01 0.00 0.00 500
+update_of_key 165 0.09 0.05 0.00 756
+update_of_key_big 44 0.03 0.05 0.00 501
+update_with_key 200 17.53 24.56 0.00 100000
+wisc_benchmark 9 2.97 2.12 0.00 114
+TOTALS 11069 557.71 397.35 0.00 1657848 +
diff --git a/sql-bench/Results/RUN-mysql-win98 b/sql-bench/Results/RUN-mysql-win98
new file mode 100644
index 00000000000..18ff522a929
--- /dev/null
+++ b/sql-bench/Results/RUN-mysql-win98
@@ -0,0 +1,74 @@
+Benchmark DBD suite: 2.7
+Date of test: 2000-03-15 1:51:13
+Running tests on: Windows 98 [Version 4.10.1998]
+Arguments:
+Comments: AMD K6, 400mz, 128M, 16M key_cache
+Limits from:
+Server version: MySQL 3.23.13a alpha
+
+alter-table: Total time: 1855 wallclock secs (1854.89 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+ATIS: Total time: 144 wallclock secs (143.53 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+big-tables: Total time: 151 wallclock secs (150.66 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+connect: Total time: 369 wallclock secs (368.94 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+create: Total time: 5141 wallclock secs (5140.97 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+insert: Estimated total time: 8358 wallclock secs (8356.07 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+select: Total time: 1294 wallclock secs (1293.83 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+wisconsin: Total time: 63 wallclock secs (62.40 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+All 8 test executed successfully
+Tests with estimated time have a + at end of line
+
+Totals per operation:
+Operation seconds usr sys cpu tests
+alter_table_add 1046 1046.38 0.00 0.00 992
+alter_table_drop 773 772.97 0.00 0.00 496
+connect 52 51.85 0.00 0.00 10000
+connect+select_1_row 72 71.95 0.00 0.00 10000
+connect+select_simple 67 66.90 0.00 0.00 10000
+count 55 54.87 0.00 0.00 100
+count_on_key 640 639.71 0.00 0.00 50100
+create+drop 1433 1433.28 0.00 0.00 10000
+create_MANY_tables 1510 1510.83 0.00 0.00 5000
+create_index 17 16.70 0.00 0.00 8
+create_key+drop 1457 1456.57 0.00 0.00 10000
+create_table 8 7.92 0.00 0.00 31
+delete_big 23 22.25 0.00 0.00 13
+delete_big_many_keys 112 112.11 0.00 0.00 2
+delete_key 0 0.82 0.00 0.00 500
+drop_index 17 16.64 0.00 0.00 8
+drop_table 1 0.06 0.00 0.00 28
+drop_table_when_MANY_tables 160 159.83 0.00 0.00 5000
+insert 510 508.11 0.00 0.00 350768
+insert_duplicates 91 91.06 0.00 0.00 300000
+insert_key 364 363.72 0.00 0.00 100000
+insert_many_fields 25 24.71 0.00 0.00 2000
+min_max 33 32.90 0.00 0.00 60
+min_max_on_key 339 339.56 0.00 0.00 73000
+multiple_value_insert 11 11.64 0.00 0.00 100000
+order_by 249 248.87 0.00 0.00 10
+order_by_key 175 174.66 0.00 0.00 10
+outer_join 146 145.66 0.00 0.00 10
+outer_join_found 144 144.40 0.00 0.00 10
+outer_join_not_found 606 605.55 0.00 0.00 500 +
+outer_join_on_key 63 63.33 0.00 0.00 10
+select_1_row 16 15.99 0.00 0.00 10000
+select_2_rows 19 18.89 0.00 0.00 10000
+select_big 304 306.16 0.00 0.00 10080
+select_diff_key 241 240.63 0.00 0.00 500
+select_distinct 33 33.34 0.00 0.00 800
+select_group 91 91.83 0.00 0.00 2911
+select_group_when_MANY_tables 581 580.46 0.00 0.00 5000
+select_join 51 50.15 0.00 0.00 200
+select_key 540 540.35 0.00 0.00 200000
+select_key_prefix 542 542.23 0.00 0.00 200000
+select_many_fields 124 124.24 0.00 0.00 2000
+select_range 423 423.21 0.00 0.00 25420
+select_range_prefix 66 66.62 0.00 0.00 25010
+select_simple 12 12.20 0.00 0.00 10000
+select_simple_join 7 7.47 0.00 0.00 500
+update_big 84 83.33 0.00 0.00 500
+update_of_key 59 59.21 0.00 0.00 756
+update_of_key_big 38 38.07 0.00 0.00 501
+update_with_key 432 432.20 0.00 0.00 100000
+wisc_benchmark 17 17.08 0.00 0.00 114
+TOTALS 13879 13879.47 0.00 0.00 1642948 +
diff --git a/sql-bench/Results/RUN-mysql_3.21-Linux_2.0.35_i686 b/sql-bench/Results/RUN-mysql_3.21-Linux_2.0.35_i686
new file mode 100644
index 00000000000..78b18540dd7
--- /dev/null
+++ b/sql-bench/Results/RUN-mysql_3.21-Linux_2.0.35_i686
@@ -0,0 +1,59 @@
+Benchmark DBD suit: 2.0
+Date of test: 1998-08-21 13:27:33
+Running tests on: Linux 2.0.35 i686
+Arguments:
+Comments: pentiumpro 400mz x2, 256M, SCSI, pgcc compiled, key_buffer=16M
+Limits from:
+Server version: MySQL 3.21.33
+
+ATIS: Total time: 75 secs ( 5.52 usr 18.40 sys = 23.92 cpu)
+alter-table: Total time: 1949 secs ( 0.26 usr 0.93 sys = 1.19 cpu)
+big-tables: Total time: 281 secs ( 5.73 usr 22.43 sys = 28.16 cpu)
+connect: Total time: 230 secs (31.85 usr 149.46 sys = 181.31 cpu)
+create: Total time: 20 secs ( 0.81 usr 1.22 sys = 2.03 cpu)
+insert: Total time: 2988 secs (172.92 usr 472.21 sys = 645.13 cpu)
+select: Estimated total time: 2117 secs (34.14 usr 74.63 sys = 108.77 cpu)
+wisconsin: Total time: 27 secs ( 2.40 usr 5.39 sys = 7.79 cpu)
+
+All 8 test executed successfully
+Tests with estimated time have a + at end of line
+
+Totals per operation:
+Operation seconds usr sys cpu tests
+alter_table_add 1949 0.25 0.80 1.05 1992
+connect 54 6.43 42.04 48.47 10000
+connect+select 58 8.15 42.24 50.39 10000
+count 58 0.00 0.09 0.09 100
+count_on_key 780 13.21 22.42 35.63 50100 +
+create+drop 3 0.20 0.31 0.51 1000
+create_index 0 0.00 0.00 0.00 8
+create_key+drop 3 0.21 0.45 0.66 1000
+create_table 8 0.31 0.23 0.54 1031
+delete_big 148 0.00 0.01 0.01 15
+delete_key 0 0.05 0.06 0.11 500
+drop_index 0 0.00 0.00 0.00 8
+drop_table 1 0.02 0.07 0.09 1028
+insert 206 15.52 39.66 55.18 350768
+insert_duplicates 34 4.70 8.53 13.23 300000
+insert_key 698 8.57 12.08 20.65 100000
+insert_many_fields 129 0.22 0.65 0.87 2000
+min_max 25 0.00 0.07 0.07 60
+min_max_on_key 1474 14.64 38.47 53.11 73000 +
+order_by 91 1.63 63.23 64.86 5
+order_by_key 92 1.88 62.99 64.87 5
+select 11 0.76 4.55 5.31 20000
+select_big 103 12.16 68.00 80.16 10080
+select_distinct 20 1.11 2.93 4.04 800
+select_group 114 0.74 2.79 3.53 3811
+select_join 31 2.65 11.18 13.83 200
+select_key 247 65.75 99.71 165.46 200000
+select_key_prefix 270 60.23 105.01 165.24 200000
+select_many_fields 151 5.51 21.76 27.27 2000
+select_range 357 9.98 24.74 34.72 25420
+select_range_prefix 42 4.12 10.63 14.75 25010
+select_simple 60 7.72 44.33 52.05 20000
+select_simple_join 2 0.62 1.00 1.62 500
+update_key 356 4.81 10.29 15.10 100256
+update_key_big 85 0.41 0.31 0.72 105003
+wisc_benchmark 7 1.04 2.86 3.90 114
+TOTALS 7667 253.60 744.49 998.09 1615814 ++
diff --git a/sql-bench/Results/RUN-mysql_fast-Linux_2.2.10_i686-cmp-msql,mysql b/sql-bench/Results/RUN-mysql_fast-Linux_2.2.10_i686-cmp-msql,mysql
new file mode 100644
index 00000000000..7df4c17f69d
--- /dev/null
+++ b/sql-bench/Results/RUN-mysql_fast-Linux_2.2.10_i686-cmp-msql,mysql
@@ -0,0 +1,55 @@
+Benchmark DBD suite: 2.4
+Date of test: 1999-09-24 9:07:48
+Running tests on: Linux 2.2.10 i686
+Arguments: --force --fast
+Comments:
+Limits from: msql,mysql
+Server version: MySQL 3.23.3 alpha
+
+ATIS: Total time: 41 wallclock secs (14.97 usr 2.26 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+alter-table: Total time: 0 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+big-tables: Total time: 63 wallclock secs (32.15 usr 5.59 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+connect: Total time: 77 wallclock secs (42.05 usr 9.01 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+create: Total time: 9 wallclock secs ( 1.85 usr 0.18 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+insert: Estimated total time: 2211 wallclock secs (751.12 usr 86.95 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+select: Total time: 17 wallclock secs ( 5.57 usr 0.80 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+wisconsin: Total time: 7 wallclock secs ( 2.43 usr 0.29 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+All 8 test executed successfully
+Tests with estimated time have a + at end of line
+
+Totals per operation:
+Operation seconds usr sys cpu tests
+connect 20 14.35 1.53 0.00 10000
+connect+select_1_row 24 15.08 2.21 0.00 10000
+create+drop 2 0.55 0.04 0.00 1000
+create_key+drop 2 0.62 0.06 0.00 1000
+create_table 4 0.40 0.03 0.00 1031
+delete_big 19 0.00 0.00 0.00 13
+delete_big_many_keys 8 0.00 0.00 0.00 2
+delete_key 0 0.06 0.01 0.00 500
+drop_table 0 0.02 0.00 0.00 1028
+insert 119 43.27 6.98 0.00 350768
+insert_duplicates 15 5.68 1.77 0.00 300000
+insert_key 68 13.88 2.39 0.00 100000
+insert_many_fields 19 7.12 0.65 0.00 20000
+order_by 86 47.40 7.63 0.00 10
+order_by_key 69 47.67 7.32 0.00 10
+select 1 0.26 0.05 0.00 1000
+select_1_row 4 1.14 0.33 0.00 10000
+select_2_rows 4 1.24 0.37 0.00 10000
+select_big 95 58.19 12.13 0.00 10080
+select_diff_key 305 0.62 0.03 0.00 500
+select_distinct 15 3.57 0.55 0.00 700
+select_join 22 9.94 1.56 0.00 200
+select_key 262 162.27 10.69 0.00 200000
+select_key_prefix 265 165.34 9.78 0.00 200000
+select_many_fields 44 25.02 4.94 0.00 20000
+select_range 41 17.25 1.56 0.00 25400
+select_range_prefix 30 14.63 1.11 0.00 25000
+select_simple_join 3 1.40 0.15 0.00 500
+update_big 34 0.00 0.00 0.00 500
+update_of_key 694 152.73 23.25 0.00 600256 +
+update_with_key 147 37.92 7.66 0.00 100000
+wisc_benchmark 4 2.43 0.29 0.00 74
+TOTALS 2425 850.05 105.07 0.00 1999572 +
diff --git a/sql-bench/Results/RUN-mysql_odbc-win98 b/sql-bench/Results/RUN-mysql_odbc-win98
new file mode 100644
index 00000000000..9c714aaa57c
--- /dev/null
+++ b/sql-bench/Results/RUN-mysql_odbc-win98
@@ -0,0 +1,62 @@
+Benchmark DBD suite: 2.0b
+Date of test: 1999-03-02 15:47:10
+Running tests on: Windows 98 [Version 4.10.1998]
+Arguments: --odbc
+Comments:
+Limits from:
+Server version: MySQL 3.22.19a
+
+alter-table: Total time: 2185 wallclock secs (2185.65 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+ATIS: Total time: 295 wallclock secs (294.90 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+big-tables: Total time: 249 wallclock secs (248.70 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+connect: Total time: 1628 wallclock secs (1627.82 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+create: Total time: 146 wallclock secs (145.72 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+insert: Estimated total time: 6093 wallclock secs (6093.46 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+select: Estimated total time: 3235 wallclock secs (3234.82 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+wisconsin: Total time: 135 wallclock secs (134.46 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+All 8 test executed successfully
+Tests with estimated time have a + at end of line
+
+Totals per operation:
+Operation seconds usr sys cpu tests
+alter_table_add 1174 1174.09 0.00 0.00 992
+alter_table_drop 964 964.00 0.00 0.00 496
+connect 337 336.42 0.00 0.00 10000
+connect+select 511 511.30 0.00 0.00 10000
+count 93 92.82 0.00 0.00 100
+count_on_key 2175 2174.21 0.00 0.00 50100 +
+create+drop 27 26.86 0.00 0.00 1000
+create_index 22 22.19 0.00 0.00 8
+create_key+drop 30 30.16 0.00 0.00 1000
+create_table 52 50.48 0.00 0.00 1031
+delete_big 212 211.34 0.00 0.00 15
+delete_key 2 1.82 0.00 0.00 500
+drop_index 22 22.08 0.00 0.00 8
+drop_table 9 9.11 0.00 0.00 1028
+insert 1199 1198.90 0.00 0.00 350768
+insert_duplicates 280 280.34 0.00 0.00 300000
+insert_key 648 648.40 0.00 0.00 100000
+insert_many_fields 37 36.25 0.00 0.00 2000
+min_max 51 51.52 0.00 0.00 60
+min_max_on_key 508 507.63 0.00 0.00 73000
+multiple_value_inser 40 40.32 0.00 0.00 100000
+order_by 491 490.87 0.00 0.00 10
+order_by_key 370 369.81 0.00 0.00 10
+select 82 82.23 0.00 0.00 20000
+select_big 595 594.45 0.00 0.00 10080
+select_distinct 58 57.84 0.00 0.00 800
+select_group 270 270.62 0.00 0.00 3811
+select_join 142 141.54 0.00 0.00 200
+select_key 914 914.74 0.00 0.00 200000 +
+select_key_prefix 929 928.96 0.00 0.00 200000 +
+select_many_fields 210 210.14 0.00 0.00 2000
+select_range 702 703.22 0.00 0.00 25420
+select_range_prefix 115 115.23 0.00 0.00 25010
+select_simple 476 475.82 0.00 0.00 20000
+select_simple_join 13 13.35 0.00 0.00 500
+update_key 2 1.81 0.00 0.00 500
+update_key_big 59 59.81 0.00 0.00 501
+update_of_key 110 109.57 0.00 0.00 256
+wisc_benchmark 29 28.83 0.00 0.00 114
+TOTALS 13960 13959.08 0.00 0.00 1511318 +++
diff --git a/sql-bench/Results/RUN-oracle-Linux_2.0.36_i686-cmp-mysql,oracle b/sql-bench/Results/RUN-oracle-Linux_2.0.36_i686-cmp-mysql,oracle
new file mode 100644
index 00000000000..f01d1675f53
--- /dev/null
+++ b/sql-bench/Results/RUN-oracle-Linux_2.0.36_i686-cmp-mysql,oracle
@@ -0,0 +1,56 @@
+Benchmark DBD suite: 2.0b
+Date of test: 1999-03-25 0:33:00
+Running tests on: Linux 2.0.36 i686
+Arguments: --force
+Comments:
+Limits from: mysql,oracle
+Server version: Oracle 8.0.5.0.0
+
+ATIS: Total time: 373 wallclock secs (123.71 usr 30.77 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+alter-table: Total time: 12 wallclock secs ( 0.87 usr 0.13 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+big-tables: Total time: 47 wallclock secs (13.47 usr 8.76 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+connect: Failed (output/connect-oracle-Linux_2.0.36_i686-cmp-mysql,oracle)
+create: Total time: 548 wallclock secs ( 9.48 usr 0.90 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+insert: Estimated total time: 123077 wallclock secs (1962.20 usr 413.70 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+select: Estimated total time: 2769 wallclock secs (257.98 usr 54.82 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+wisconsin: Total time: 179 wallclock secs (52.39 usr 7.30 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Of 8 tests, 1 tests didn't work
+Tests with estimated time have a + at end of line
+
+Totals per operation:
+Operation seconds usr sys cpu tests
+alter_table_add 8 0.20 0.03 0.00 246
+count 50 0.08 0.03 0.00 100
+count_on_key 831 53.95 11.21 0.00 50100 +
+create+drop 202 2.66 0.31 0.00 1000
+create_index 0 0.02 0.00 0.00 8
+create_key+drop 175 3.33 0.25 0.00 1000
+create_table 91 2.05 0.18 0.00 1031
+delete_big 1040 0.04 0.05 0.00 15
+delete_key 265 0.34 0.04 0.00 500
+drop_index 1 0.01 0.00 0.00 8
+drop_table 80 0.66 0.08 0.00 1028
+insert 1193 265.59 32.51 0.00 350768
+insert_duplicates 2000 0.00 0.00 0.00 300000
+insert_key 647 78.18 9.80 0.00 100000
+insert_many_fields 6 2.06 0.16 0.00 2000
+min_max 25 0.04 0.01 0.00 60
+min_max_on_key 1216 81.52 17.31 0.00 73000 +
+order_by 813 362.89 88.91 0.00 10 +
+order_by_key 846 362.64 93.30 0.00 10 +
+select_big 851 368.42 91.53 0.00 80
+select_distinct 63 24.27 6.17 0.00 800
+select_group 100 13.12 2.59 0.00 3391
+select_join 204 71.18 19.08 0.00 200
+select_key 91337 252.28 48.63 0.00 200000 +
+select_key_prefix 641 235.18 40.05 0.00 200000 +
+select_many_fields 40 11.38 8.59 0.00 2000
+select_range 15505 134.75 29.30 0.00 25410 +++
+select_range_prefix 83 36.62 6.48 0.00 25010
+select_simple_join 23 8.65 2.06 0.00 500
+update_key 221 0.26 0.08 0.00 500
+update_key_big 299 0.40 0.07 0.00 501
+update_of_key 445 0.19 0.00 0.00 256
+wisc_benchmark 70 30.55 4.78 0.00 114
+TOTALS 119371 2403.51 513.59 0.00 1339646 +++++++++
diff --git a/sql-bench/Results/RUN-oracle_fast-Linux_2.0.36_i686-cmp-mysql,oracle b/sql-bench/Results/RUN-oracle_fast-Linux_2.0.36_i686-cmp-mysql,oracle
new file mode 100644
index 00000000000..572ddd0e3b0
--- /dev/null
+++ b/sql-bench/Results/RUN-oracle_fast-Linux_2.0.36_i686-cmp-mysql,oracle
@@ -0,0 +1,57 @@
+Benchmark DBD suite: 2.0b
+Date of test: 1999-03-23 8:05:45
+Running tests on: Linux 2.0.36 i686
+Arguments: --force --fast
+Comments:
+Limits from: mysql,oracle
+Server version: Oracle 8.0.5.0.0
+
+ATIS: Total time: 396 wallclock secs (124.50 usr 29.24 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+alter-table: Total time: 13 wallclock secs ( 1.14 usr 0.11 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+big-tables: Total time: 49 wallclock secs (12.68 usr 0.78 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+connect: Total time: 49 wallclock secs (12.68 usr 0.78 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+create: Total time: 611 wallclock secs (11.43 usr 1.28 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+insert: Estimated total time: 124637 wallclock secs (1926.54 usr 389.27 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+select: Estimated total time: 2285 wallclock secs (259.15 usr 54.33 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+wisconsin: Total time: 190 wallclock secs (53.06 usr 7.56 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+All 8 test executed successfully
+Tests with estimated time have a + at end of line
+
+Totals per operation:
+Operation seconds usr sys cpu tests
+alter_table_add 8 0.31 0.02 0.00 246
+book-keeping 362 1.79 0.26 0.00 34
+count 50 0.10 0.04 0.00 100
+count_on_key 813 56.44 12.01 0.00 50100 +
+create+drop 198 2.72 0.37 0.00 1000
+create_index 0 0.01 0.00 0.00 8
+create_key+drop 174 3.64 0.28 0.00 1000
+create_table 108 1.93 0.18 0.00 1031
+delete_big 1475 0.06 0.06 0.00 15
+delete_key 262 0.31 0.03 0.00 500
+drop_index 1 0.00 0.00 0.00 8
+drop_table 88 0.71 0.04 0.00 1028
+insert 1357 259.88 32.29 0.00 350768
+insert_duplicates 2001 0.00 0.00 0.00 300000
+insert_key 677 78.14 9.36 0.00 100000
+insert_many_fields 7 2.04 0.14 0.00 2000
+min_max 25 0.09 0.02 0.00 60
+min_max_on_key 890 78.61 16.96 0.00 73000 +
+order_by 807 349.92 85.42 0.00 10 +
+order_by_key 856 370.12 85.01 0.00 10 +
+select_big 861 368.26 96.12 0.00 80
+select_distinct 56 24.55 5.45 0.00 800
+select_group 94 13.03 2.94 0.00 3391
+select_join 188 71.78 18.08 0.00 200
+select_key 91615 228.66 33.54 0.00 200000 +
+select_key_prefix 753 235.02 39.45 0.00 200000 +
+select_many_fields 40 10.55 0.64 0.00 2000
+select_range 15390 137.88 27.54 0.00 25410 ++
+select_range_prefix 84 35.44 6.75 0.00 25010
+select_simple_join 20 8.26 1.90 0.00 500
+update_key 223 0.31 0.02 0.00 500
+update_key_big 302 0.45 0.10 0.00 501
+update_of_key 601 0.18 0.00 0.00 256
+wisc_benchmark 63 30.34 4.90 0.00 114
+TOTALS 120449 2371.53 479.92 0.00 1339680 ++++++++
diff --git a/sql-bench/Results/RUN-pg-Linux_2.0.36_i686-cmp-mysql,pg,solid b/sql-bench/Results/RUN-pg-Linux_2.0.36_i686-cmp-mysql,pg,solid
new file mode 100644
index 00000000000..9b9404b981c
--- /dev/null
+++ b/sql-bench/Results/RUN-pg-Linux_2.0.36_i686-cmp-mysql,pg,solid
@@ -0,0 +1,59 @@
+Benchmark DBD suite: 2.0b
+Date of test: 1999-03-09 18:59:51
+Running tests on: Linux 2.0.36 i686
+Arguments: --force
+Comments:
+Limits from: mysql,pg,solid
+Server version: PostgreSQL 6.4
+
+ATIS: Estimated total time: 1520 wallclock secs (16.64 usr 1.66 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+alter-table: Total time: 4 wallclock secs ( 0.80 usr 0.07 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+big-tables: Total time: 470 wallclock secs ( 7.63 usr 0.60 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+connect: Total time: 349 wallclock secs (42.65 usr 10.17 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+create: Total time: 168 wallclock secs ( 6.14 usr 0.53 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+insert: Estimated total time: 133319 wallclock secs (625.54 usr 64.54 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+select: Estimated total time: 2069 wallclock secs (51.44 usr 5.76 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+wisconsin: Total time: 452 wallclock secs (22.00 usr 2.22 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+All 8 test executed successfully
+Tests with estimated time have a + at end of line
+
+Totals per operation:
+Operation seconds usr sys cpu tests
+alter_table_add 1 0.15 0.00 0.00 293
+connect 84 9.71 2.81 0.00 10000
+connect+select 210 17.17 5.07 0.00 10000
+count 156 0.04 0.01 0.00 100
+count_on_key 1685 27.36 3.43 0.00 50100 +
+create+drop 46 1.86 0.23 0.00 1000
+create_index 1 0.00 0.00 0.00 7
+create_key+drop 33 1.56 0.14 0.00 1000
+create_table 68 1.54 0.11 0.00 1031
+delete_big 76 0.01 0.00 0.00 15
+delete_key 634 0.32 0.09 0.00 500
+drop_index 0 0.00 0.00 0.00 7
+drop_table 17 0.62 0.03 0.00 1028
+insert 1213 198.22 22.62 0.00 350768
+insert_duplicates 164 46.42 5.41 0.00 300000
+insert_key 944 57.30 6.79 0.00 100000
+insert_many_fields 123 1.37 0.14 0.00 2000
+min_max 49 0.04 0.00 0.00 60
+min_max_on_key 2153 18.34 1.75 0.00 73000 +
+order_by 269 26.89 1.27 0.00 10
+order_by_key 265 26.66 1.20 0.00 10
+select 35 10.00 1.13 0.00 20000
+select_big 136 32.59 2.75 0.00 10080
+select_distinct 139 2.82 0.22 0.00 800
+select_group 5688 2.22 0.22 0.00 3101
+select_join 1262 5.94 0.52 0.00 200 +
+select_key 634 122.95 13.45 0.00 200000 +
+select_key_prefix 639 123.46 13.29 0.00 200000 +
+select_many_fields 347 6.25 0.46 0.00 2000
+select_range 34472 3.80 0.07 0.00 25410 ++
+select_range_prefix 34462 6.24 0.56 0.00 25000 ++
+select_simple_join 6 1.02 0.10 0.00 500
+update_key 443 0.23 0.03 0.00 500
+update_key_big 978 0.34 0.06 0.00 501
+update_of_key 3569 0.14 0.03 0.00 256
+wisc_benchmark 310 5.05 0.37 0.00 114
+TOTALS 91311 758.63 84.36 0.00 1389391 +++++++++
diff --git a/sql-bench/Results/RUN-pg_fast-Linux_2.0.36_i686-cmp-mysql,pg,solid b/sql-bench/Results/RUN-pg_fast-Linux_2.0.36_i686-cmp-mysql,pg,solid
new file mode 100644
index 00000000000..0fea94d6674
--- /dev/null
+++ b/sql-bench/Results/RUN-pg_fast-Linux_2.0.36_i686-cmp-mysql,pg,solid
@@ -0,0 +1,60 @@
+Benchmark DBD suite: 2.0b
+Date of test: 1999-03-11 7:20:15
+Running tests on: Linux 2.0.36 i686
+Arguments: --force --fast
+Comments:
+Limits from: mysql,pg,solid
+Server version: PostgreSQL 6.4
+
+ATIS: Total time: 300 wallclock secs (17.90 usr 1.54 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+alter-table: Total time: 4 wallclock secs ( 0.79 usr 0.07 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+big-tables: Total time: 430 wallclock secs ( 7.48 usr 0.64 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+connect: Total time: 379 wallclock secs (43.62 usr 7.61 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+create: Total time: 388 wallclock secs ( 5.92 usr 0.76 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+insert: Estimated total time: 62302 wallclock secs (630.39 usr 65.36 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+select: Estimated total time: 2120 wallclock secs (52.41 usr 5.73 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+wisconsin: Total time: 166 wallclock secs (22.23 usr 2.21 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+All 8 test executed successfully
+Tests with estimated time have a + at end of line
+
+Totals per operation:
+Operation seconds usr sys cpu tests
+alter_table_add 1 0.19 0.03 0.00 293
+book-keeping 4184 0.03 0.00 0.00 37
+connect 90 9.98 1.52 0.00 10000
+connect+select 218 15.97 3.53 0.00 10000
+count 153 0.10 0.03 0.00 100
+count_on_key 1773 28.66 3.21 0.00 50100 +
+create+drop 36 2.08 0.26 0.00 1000
+create_index 0 0.00 0.00 0.00 7
+create_key+drop 16 1.32 0.09 0.00 1000
+create_table 68 1.44 0.14 0.00 1031
+delete_big 59 0.01 0.00 0.00 15
+delete_key 11 0.20 0.15 0.00 500
+drop_index 1 0.00 0.01 0.00 7
+drop_table 16 0.58 0.12 0.00 1028
+insert 1093 198.15 21.77 0.00 350768
+insert_duplicates 169 48.44 5.24 0.00 300000
+insert_key 956 57.05 7.08 0.00 100000
+insert_many_fields 120 1.46 0.12 0.00 2000
+min_max 48 0.03 0.00 0.00 60
+min_max_on_key 2085 18.44 2.02 0.00 73000 +
+order_by 209 26.70 1.83 0.00 10
+order_by_key 208 26.76 1.38 0.00 10
+select 44 10.36 1.24 0.00 20000
+select_big 108 33.96 2.77 0.00 10080
+select_distinct 70 3.23 0.22 0.00 800
+select_group 7804 2.48 0.36 0.00 3101
+select_join 60 6.07 0.42 0.00 200
+select_key 547 123.81 13.35 0.00 200000
+select_key_prefix 550 123.88 13.39 0.00 200000
+select_many_fields 308 6.02 0.52 0.00 2000
+select_range 733 5.47 0.69 0.00 25420 +
+select_range_prefix 720 4.95 0.56 0.00 25010 +
+select_simple_join 44 1.11 0.12 0.00 500
+update_key 11 0.33 0.03 0.00 500
+update_key_big 343 0.34 0.05 0.00 501
+update_of_key 2292 0.21 0.03 0.00 256
+wisc_benchmark 29 5.00 0.27 0.00 114
+TOTALS 25177 764.81 82.55 0.00 1389448 ++++
diff --git a/sql-bench/Results/RUN-solid-Linux_2.0.36_i686-cmp-mysql,pg,solid b/sql-bench/Results/RUN-solid-Linux_2.0.36_i686-cmp-mysql,pg,solid
new file mode 100644
index 00000000000..335c1c9276e
--- /dev/null
+++ b/sql-bench/Results/RUN-solid-Linux_2.0.36_i686-cmp-mysql,pg,solid
@@ -0,0 +1,59 @@
+Benchmark DBD suite: 2.0b
+Date of test: 1999-03-06 12:47:43
+Running tests on: Linux 2.0.36 i686
+Arguments: --force
+Comments:
+Limits from: mysql,pg,solid
+Server version: SOLID Server - v.02.30.0026 (Linux ix86)
+
+ATIS: Total time: 701 wallclock secs (54.93 usr 3.47 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+alter-table: Total time: 8 wallclock secs ( 1.04 usr 0.08 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+big-tables: Total time: 20 wallclock secs ( 8.71 usr 0.28 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+connect: Total time: 236 wallclock secs (149.92 usr 23.13 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+create: Total time: 59 wallclock secs ( 7.00 usr 0.60 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+insert: Estimated total time: 457496 wallclock secs (1277.60 usr 88.42 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+select: Estimated total time: 9245 wallclock secs (91.67 usr 7.28 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+wisconsin: Total time: 226 wallclock secs (37.18 usr 2.77 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+All 8 test executed successfully
+Tests with estimated time have a + at end of line
+
+Totals per operation:
+Operation seconds usr sys cpu tests
+alter_table_add 3 0.19 0.02 0.00 293
+connect 84 58.46 10.25 0.00 10000
+connect+select 105 66.76 11.09 0.00 10000
+count 1213 0.10 0.00 0.00 100
+count_on_key 10121 48.79 4.19 0.00 50100 +
+create+drop 18 2.08 0.19 0.00 1000
+create_index 0 0.01 0.00 0.00 7
+create_key+drop 20 2.03 0.15 0.00 1000
+create_table 9 1.36 0.06 0.00 1031
+delete_big 417 0.00 0.00 0.00 15
+delete_key 29 0.43 0.06 0.00 500
+drop_index 1 0.00 0.00 0.00 7
+drop_table 9 0.70 0.09 0.00 1028
+insert 1267 303.56 25.66 0.00 350768
+insert_duplicates 91 59.65 3.36 0.00 300000
+insert_key 1153 85.87 7.46 0.00 100000
+insert_many_fields 9 1.63 0.12 0.00 2000
+min_max 406 0.03 0.00 0.00 60
+min_max_on_key 114 33.07 2.41 0.00 73000
+order_by 367 116.72 6.11 0.00 10
+order_by_key 375 120.22 7.12 0.00 10
+select 27 14.11 0.75 0.00 20000
+select_big 335 131.33 7.72 0.00 10080
+select_distinct 169 11.26 0.54 0.00 800
+select_group 1269 4.50 0.30 0.00 3101
+select_join 408 28.07 1.80 0.00 200
+select_key 573 251.14 17.44 0.00 200000
+select_key_prefix 545 216.93 15.32 0.00 200000
+select_many_fields 10 7.06 0.16 0.00 2000
+select_range 200311 10.49 1.78 0.00 25410 ++
+select_range_prefix 201289 10.39 0.03 0.00 25000 ++
+select_simple_join 37 3.65 0.22 0.00 500
+update_key 2 0.42 0.05 0.00 500
+update_key_big 818 0.30 0.02 0.00 501
+update_of_key 3015 0.28 0.02 0.00 256
+wisc_benchmark 55 10.89 0.42 0.00 114
+TOTALS 424674 1602.48 124.91 0.00 1389391 +++++
diff --git a/sql-bench/Results/alter-table-Adabas-Linux_2.0.35_i686-cmp-adabas,mysql b/sql-bench/Results/alter-table-Adabas-Linux_2.0.35_i686-cmp-adabas,mysql
new file mode 100644
index 00000000000..96fa7b183dc
--- /dev/null
+++ b/sql-bench/Results/alter-table-Adabas-Linux_2.0.35_i686-cmp-adabas,mysql
@@ -0,0 +1,16 @@
+Testing server 'Adabas 10.01.00' at 1998-08-18 21:09:05
+
+Testing of ALTER TABLE
+Testing with 254 columns and 1000 rows in 20 steps
+Insert data into the table
+Time for insert (1000)19 secs ( 0.68 usr 0.28 sys = 0.96 cpu)
+
+Time for alter_table_add (246): 11 secs ( 0.07 usr 0.10 sys = 0.17 cpu)
+
+Time for create_index (8): 1 secs ( 0.00 usr 0.00 sys = 0.00 cpu)
+
+Time for drop_index (8): 1 secs ( 0.00 usr 0.00 sys = 0.00 cpu)
+
+Time for alter_table_drop (123): 8 secs ( 0.01 usr 0.08 sys = 0.09 cpu)
+
+Total time: 40 secs ( 0.76 usr 0.47 sys = 1.23 cpu)
diff --git a/sql-bench/Results/alter-table-AdabasD-Linux_2.0.35_i686-cmp-adabasd,mysql b/sql-bench/Results/alter-table-AdabasD-Linux_2.0.35_i686-cmp-adabasd,mysql
new file mode 100644
index 00000000000..727bcb6c148
--- /dev/null
+++ b/sql-bench/Results/alter-table-AdabasD-Linux_2.0.35_i686-cmp-adabasd,mysql
@@ -0,0 +1,16 @@
+Testing server 'Adabas 10.01.00' at 1998-08-20 19:19:50
+
+Testing of ALTER TABLE
+Testing with 254 columns and 1000 rows in 20 steps
+Insert data into the table
+Time for insert (1000)18 secs ( 0.26 usr 0.08 sys = 0.34 cpu)
+
+Time for alter_table_add (246): 10 secs ( 0.02 usr 0.02 sys = 0.04 cpu)
+
+Time for create_index (8): 1 secs ( 0.00 usr 0.00 sys = 0.00 cpu)
+
+Time for drop_index (8): 1 secs ( 0.00 usr 0.01 sys = 0.01 cpu)
+
+Time for alter_table_drop (123): 10 secs ( 0.00 usr 0.07 sys = 0.07 cpu)
+
+Total time: 40 secs ( 0.29 usr 0.18 sys = 0.47 cpu)
diff --git a/sql-bench/Results/alter-table-msql-Linux_2.2.10_i686-cmp-msql,mysql b/sql-bench/Results/alter-table-msql-Linux_2.2.10_i686-cmp-msql,mysql
new file mode 100644
index 00000000000..47ae8e2c56e
--- /dev/null
+++ b/sql-bench/Results/alter-table-msql-Linux_2.2.10_i686-cmp-msql,mysql
@@ -0,0 +1,6 @@
+Testing server 'mSQL server version 2.0.10' at 1999-09-22 8:43:14
+
+Some of the servers given with --cmp or --server doesn't support ALTER TABLE
+Test aborted
+
+Total time: 0 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results/alter-table-mysql-3.21-Linux_2.2.1_i686 b/sql-bench/Results/alter-table-mysql-3.21-Linux_2.2.1_i686
new file mode 100644
index 00000000000..ff14dd9bf99
--- /dev/null
+++ b/sql-bench/Results/alter-table-mysql-3.21-Linux_2.2.1_i686
@@ -0,0 +1,16 @@
+Testing server 'MySQL 3.21.34' at 1999-02-28 15:43:25
+
+Testing of ALTER TABLE
+Testing with 1000 columns and 1000 rows in 20 steps
+Insert data into the table
+Time for insert (1000) 1 wallclock secs ( 0.08 usr 0.02 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Time for alter_table_add (992): 476 wallclock secs ( 0.35 usr 0.09 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Time for create_index (8): 0 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Time for drop_index (8): 0 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Time for alter_table_drop (496): 338 wallclock secs ( 0.17 usr 0.03 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Total time: 815 wallclock secs ( 0.61 usr 0.14 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
diff --git a/sql-bench/Results/alter-table-mysql-HP_UX_B.10.20_9000_778 b/sql-bench/Results/alter-table-mysql-HP_UX_B.10.20_9000_778
new file mode 100644
index 00000000000..eed78d5d472
--- /dev/null
+++ b/sql-bench/Results/alter-table-mysql-HP_UX_B.10.20_9000_778
@@ -0,0 +1,16 @@
+Testing server 'MySQL 3.23.4 alpha' at 1999-09-27 15:13:41
+
+Testing of ALTER TABLE
+Testing with 1000 columns and 1000 rows in 20 steps
+Insert data into the table
+Time for insert (1000) 1 wallclock secs ( 0.15 usr 0.07 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Time for alter_table_add (992): 925 wallclock secs ( 0.47 usr 0.10 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Time for create_index (8): 15 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Time for drop_index (8): 15 wallclock secs ( 0.01 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Time for alter_table_drop (496): 708 wallclock secs ( 0.21 usr 0.05 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Total time: 1664 wallclock secs ( 0.84 usr 0.22 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results/alter-table-mysql-Linux_2.0.35_i686-cmp-adabas,mysql b/sql-bench/Results/alter-table-mysql-Linux_2.0.35_i686-cmp-adabas,mysql
new file mode 100644
index 00000000000..6a428bcb20b
--- /dev/null
+++ b/sql-bench/Results/alter-table-mysql-Linux_2.0.35_i686-cmp-adabas,mysql
@@ -0,0 +1,16 @@
+Testing server 'MySQL 3.22.9 beta' at 1998-10-20 6:55:25
+
+Testing of ALTER TABLE
+Testing with 254 columns and 1000 rows in 20 steps
+Insert data into the table
+Time for insert (1000) 0 secs ( 0.03 usr 0.14 sys = 0.17 cpu)
+
+Time for alter_table_add (246): 21 secs ( 0.03 usr 0.08 sys = 0.11 cpu)
+
+Time for create_index (8): 2 secs ( 0.00 usr 0.00 sys = 0.00 cpu)
+
+Time for drop_index (8): 1 secs ( 0.00 usr 0.00 sys = 0.00 cpu)
+
+Time for alter_table_drop (123): 15 secs ( 0.02 usr 0.11 sys = 0.13 cpu)
+
+Total time: 39 secs ( 0.08 usr 0.33 sys = 0.41 cpu)
diff --git a/sql-bench/Results/alter-table-mysql-Linux_2.0.36_i686-cmp-mysql,pg,solid b/sql-bench/Results/alter-table-mysql-Linux_2.0.36_i686-cmp-mysql,pg,solid
new file mode 100644
index 00000000000..e226cbd41c5
--- /dev/null
+++ b/sql-bench/Results/alter-table-mysql-Linux_2.0.36_i686-cmp-mysql,pg,solid
@@ -0,0 +1,14 @@
+Testing server 'MySQL 3.22.18' at 1999-03-07 22:59:02
+
+Testing of ALTER TABLE
+Testing with 300 columns and 1000 rows in 20 steps
+Insert data into the table
+Time for insert (1000) 0 wallclock secs ( 0.06 usr 0.02 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Time for alter_table_add (293): 21 wallclock secs ( 0.08 usr 0.01 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Time for create_index (7): 1 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Time for drop_index (7): 1 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Total time: 23 wallclock secs ( 0.14 usr 0.03 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
diff --git a/sql-bench/Results/alter-table-mysql-Linux_2.2.10_i686 b/sql-bench/Results/alter-table-mysql-Linux_2.2.10_i686
new file mode 100644
index 00000000000..8e0f58a0df7
--- /dev/null
+++ b/sql-bench/Results/alter-table-mysql-Linux_2.2.10_i686
@@ -0,0 +1,16 @@
+Testing server 'MySQL 3.23.3 alpha' at 1999-09-17 8:34:56
+
+Testing of ALTER TABLE
+Testing with 1000 columns and 1000 rows in 20 steps
+Insert data into the table
+Time for insert (1000) 0 wallclock secs ( 0.12 usr 0.02 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Time for alter_table_add (992): 280 wallclock secs ( 0.37 usr 0.03 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Time for create_index (8): 5 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Time for drop_index (8): 6 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Time for alter_table_drop (496): 222 wallclock secs ( 0.16 usr 0.01 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Total time: 514 wallclock secs ( 0.65 usr 0.06 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results/alter-table-mysql-Linux_2.2.10_i686-cmp-msql,mysql b/sql-bench/Results/alter-table-mysql-Linux_2.2.10_i686-cmp-msql,mysql
new file mode 100644
index 00000000000..62dabc44bbf
--- /dev/null
+++ b/sql-bench/Results/alter-table-mysql-Linux_2.2.10_i686-cmp-msql,mysql
@@ -0,0 +1,6 @@
+Testing server 'MySQL 3.23.3 alpha' at 1999-09-24 9:49:04
+
+Some of the servers given with --cmp or --server doesn't support ALTER TABLE
+Test aborted
+
+Total time: 0 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results/alter-table-mysql-Linux_2.2.14_i686_xeon b/sql-bench/Results/alter-table-mysql-Linux_2.2.14_i686_xeon
new file mode 100644
index 00000000000..fee67f1a7e0
--- /dev/null
+++ b/sql-bench/Results/alter-table-mysql-Linux_2.2.14_i686_xeon
@@ -0,0 +1,16 @@
+Testing server 'MySQL 3.23.17 alpha' at 2000-06-01 3:05:26
+
+Testing of ALTER TABLE
+Testing with 1000 columns and 1000 rows in 20 steps
+Insert data into the table
+Time for insert (1000) 0 wallclock secs ( 0.03 usr 0.04 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Time for alter_table_add (992): 198 wallclock secs ( 0.29 usr 0.06 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Time for create_index (8): 4 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Time for drop_index (8): 3 wallclock secs ( 0.01 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Time for alter_table_drop (496): 154 wallclock secs ( 0.14 usr 0.04 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Total time: 359 wallclock secs ( 0.47 usr 0.14 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results/alter-table-mysql-Linux_2.2.1_i686-cmp-adabas,mysql b/sql-bench/Results/alter-table-mysql-Linux_2.2.1_i686-cmp-adabas,mysql
new file mode 100644
index 00000000000..1be3d062236
--- /dev/null
+++ b/sql-bench/Results/alter-table-mysql-Linux_2.2.1_i686-cmp-adabas,mysql
@@ -0,0 +1,16 @@
+Testing server 'MySQL 3.22.18' at 1999-02-27 21:11:26
+
+Testing of ALTER TABLE
+Testing with 254 columns and 1000 rows in 20 steps
+Insert data into the table
+Time for insert (1000) 0 wallclock secs ( 0.09 usr 0.04 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Time for alter_table_add (246): 28 wallclock secs ( 0.08 usr 0.01 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Time for create_index (8): 1 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Time for drop_index (8): 3 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Time for alter_table_drop (123): 20 wallclock secs ( 0.06 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Total time: 52 wallclock secs ( 0.24 usr 0.05 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
diff --git a/sql-bench/Results/alter-table-mysql-NT_4.0 b/sql-bench/Results/alter-table-mysql-NT_4.0
new file mode 100644
index 00000000000..ef53199b9c8
--- /dev/null
+++ b/sql-bench/Results/alter-table-mysql-NT_4.0
@@ -0,0 +1,16 @@
+Testing server 'MySQL 3.23.17a alpha' at 2000-06-02 16:59:02
+
+Testing of ALTER TABLE
+Testing with 1000 columns and 1000 rows in 20 steps
+Insert data into the table
+Time for insert (1000) 0 wallclock secs ( 0.13 usr 0.13 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Time for alter_table_add (992): 1201 wallclock secs ( 0.53 usr 0.19 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Time for create_index (8): 25 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Time for drop_index (8): 25 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Time for alter_table_drop (496): 1009 wallclock secs ( 0.23 usr 0.09 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Total time: 2260 wallclock secs ( 0.89 usr 0.42 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results/alter-table-mysql-SunOS_5.5.1_sun4u b/sql-bench/Results/alter-table-mysql-SunOS_5.5.1_sun4u
new file mode 100644
index 00000000000..7a0e0948186
--- /dev/null
+++ b/sql-bench/Results/alter-table-mysql-SunOS_5.5.1_sun4u
@@ -0,0 +1,16 @@
+Testing server 'MySQL 3.22.19' at 1999-03-02 3:14:52
+
+Testing of ALTER TABLE
+Testing with 1000 columns and 1000 rows in 20 steps
+Insert data into the table
+Time for insert (1000) 1 wallclock secs ( 0.09 usr 0.11 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Time for alter_table_add (992): 775 wallclock secs ( 0.47 usr 0.12 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Time for create_index (8): 11 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Time for drop_index (8): 12 wallclock secs ( 0.01 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Time for alter_table_drop (496): 534 wallclock secs ( 0.22 usr 0.13 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Total time: 1333 wallclock secs ( 0.81 usr 0.36 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results/alter-table-mysql-SunOS_5.7_sun4m b/sql-bench/Results/alter-table-mysql-SunOS_5.7_sun4m
new file mode 100644
index 00000000000..502dbd24f9b
--- /dev/null
+++ b/sql-bench/Results/alter-table-mysql-SunOS_5.7_sun4m
@@ -0,0 +1,16 @@
+Testing server 'MySQL 3.22.20' at 1999-03-19 11:17:01
+
+Testing of ALTER TABLE
+Testing with 1000 columns and 1000 rows in 20 steps
+Insert data into the table
+Time for insert (1000) 4 secs ( 0.69 usr 0.64 sys + 0.00 cusr 0.00 csys = 1.33 cpu)
+
+Time for alter_table_add (992): 3419 secs ( 1.97 usr 0.98 sys + 0.00 cusr 0.00 csys = 2.95 cpu)
+
+Time for create_index (8): 47 secs ( 0.02 usr 0.01 sys + 0.00 cusr 0.00 csys = 0.03 cpu)
+
+Time for drop_index (8): 47 secs ( 0.01 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.01 cpu)
+
+Time for alter_table_drop (496): 2509 secs ( 0.68 usr 0.48 sys + 0.00 cusr 0.00 csys = 1.16 cpu)
+
+Total time: 6026 secs ( 3.39 usr 2.11 sys + 0.00 cusr 0.00 csys = 5.50 cpu)
diff --git a/sql-bench/Results/alter-table-mysql-SunOS_5.7_sun4u b/sql-bench/Results/alter-table-mysql-SunOS_5.7_sun4u
new file mode 100644
index 00000000000..f43ab028645
--- /dev/null
+++ b/sql-bench/Results/alter-table-mysql-SunOS_5.7_sun4u
@@ -0,0 +1,16 @@
+Testing server 'MySQL 3.23.8 alpha' at 2000-01-17 20:52:54
+
+Testing of ALTER TABLE
+Testing with 1000 columns and 1000 rows in 20 steps
+Insert data into the table
+Time for insert (1000) 0 wallclock secs ( 0.08 usr 0.10 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Time for alter_table_add (992): 821 wallclock secs ( 0.23 usr 0.09 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Time for create_index (8): 11 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Time for drop_index (8): 10 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Time for alter_table_drop (496): 555 wallclock secs ( 0.10 usr 0.04 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Total time: 1397 wallclock secs ( 0.41 usr 0.23 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results/alter-table-mysql-win98 b/sql-bench/Results/alter-table-mysql-win98
new file mode 100644
index 00000000000..922aa8906a9
--- /dev/null
+++ b/sql-bench/Results/alter-table-mysql-win98
@@ -0,0 +1,16 @@
+Testing server 'MySQL 3.23.13a alpha' at 2000-03-15 1:51:14
+
+Testing of ALTER TABLE
+Testing with 1000 columns and 1000 rows in 20 steps
+Insert data into the table
+Time for insert (1000) 1 wallclock secs ( 1.09 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Time for alter_table_add (992): 1046 wallclock secs (1046.38 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Time for create_index (8): 17 wallclock secs (16.70 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Time for drop_index (8): 17 wallclock secs (16.64 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Time for alter_table_drop (496): 773 wallclock secs (772.97 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Total time: 1855 wallclock secs (1854.89 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results/alter-table-mysql_3.21-Linux_2.0.35_i686 b/sql-bench/Results/alter-table-mysql_3.21-Linux_2.0.35_i686
new file mode 100644
index 00000000000..ccf053ec2d1
--- /dev/null
+++ b/sql-bench/Results/alter-table-mysql_3.21-Linux_2.0.35_i686
@@ -0,0 +1,14 @@
+Testing server 'MySQL 3.21.33' at 1998-08-21 11:29:38
+
+Testing of ALTER TABLE
+Testing with 2000 columns and 1000 rows in 20 steps
+Insert data into the table
+Time for insert (1000) 0 secs ( 0.01 usr 0.13 sys = 0.14 cpu)
+
+Time for alter_table_add (1992): 1949 secs ( 0.25 usr 0.80 sys = 1.05 cpu)
+
+Time for create_index (8): 0 secs ( 0.00 usr 0.00 sys = 0.00 cpu)
+
+Time for drop_index (8): 0 secs ( 0.00 usr 0.00 sys = 0.00 cpu)
+
+Total time: 1949 secs ( 0.26 usr 0.93 sys = 1.19 cpu)
diff --git a/sql-bench/Results/alter-table-mysql_fast-Linux_2.2.10_i686-cmp-msql,mysql b/sql-bench/Results/alter-table-mysql_fast-Linux_2.2.10_i686-cmp-msql,mysql
new file mode 100644
index 00000000000..ee1506b7cc1
--- /dev/null
+++ b/sql-bench/Results/alter-table-mysql_fast-Linux_2.2.10_i686-cmp-msql,mysql
@@ -0,0 +1,6 @@
+Testing server 'MySQL 3.23.3 alpha' at 1999-09-24 9:08:30
+
+Some of the servers given with --cmp or --server doesn't support ALTER TABLE
+Test aborted
+
+Total time: 0 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results/alter-table-mysql_odbc-win98 b/sql-bench/Results/alter-table-mysql_odbc-win98
new file mode 100644
index 00000000000..9da9bcfc060
--- /dev/null
+++ b/sql-bench/Results/alter-table-mysql_odbc-win98
@@ -0,0 +1,16 @@
+Testing server 'MySQL 3.22.19a' at 1999-03-02 15:47:11
+
+Testing of ALTER TABLE
+Testing with 1000 columns and 1000 rows in 20 steps
+Insert data into the table
+Time for insert (1000) 3 wallclock secs ( 3.18 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Time for alter_table_add (992): 1174 wallclock secs (1174.09 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Time for create_index (8): 22 wallclock secs (22.19 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Time for drop_index (8): 22 wallclock secs (22.08 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Time for alter_table_drop (496): 964 wallclock secs (964.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Total time: 2185 wallclock secs (2185.65 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results/alter-table-oracle-Linux_2.0.36_i686-cmp-mysql,oracle b/sql-bench/Results/alter-table-oracle-Linux_2.0.36_i686-cmp-mysql,oracle
new file mode 100644
index 00000000000..39ecbd97005
--- /dev/null
+++ b/sql-bench/Results/alter-table-oracle-Linux_2.0.36_i686-cmp-mysql,oracle
@@ -0,0 +1,14 @@
+Testing server 'Oracle 8.0.5.0.0' at 1999-03-25 0:39:16
+
+Testing of ALTER TABLE
+Testing with 254 columns and 1000 rows in 20 steps
+Insert data into the table
+Time for insert (1000) 3 wallclock secs ( 0.64 usr 0.10 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Time for alter_table_add (246): 8 wallclock secs ( 0.20 usr 0.03 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Time for create_index (8): 0 wallclock secs ( 0.02 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Time for drop_index (8): 1 wallclock secs ( 0.01 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Total time: 12 wallclock secs ( 0.87 usr 0.13 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
diff --git a/sql-bench/Results/alter-table-oracle_fast-Linux_2.0.36_i686-cmp-mysql,oracle b/sql-bench/Results/alter-table-oracle_fast-Linux_2.0.36_i686-cmp-mysql,oracle
new file mode 100644
index 00000000000..1ba6134b44f
--- /dev/null
+++ b/sql-bench/Results/alter-table-oracle_fast-Linux_2.0.36_i686-cmp-mysql,oracle
@@ -0,0 +1,14 @@
+Testing server 'Oracle 8.0.5.0.0' at 1999-03-23 8:12:23
+
+Testing of ALTER TABLE
+Testing with 254 columns and 1000 rows in 20 steps
+Insert data into the table
+Time for insert (1000) 4 wallclock secs ( 0.81 usr 0.09 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Time for alter_table_add (246): 8 wallclock secs ( 0.31 usr 0.02 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Time for create_index (8): 0 wallclock secs ( 0.01 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Time for drop_index (8): 1 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Total time: 13 wallclock secs ( 1.14 usr 0.11 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
diff --git a/sql-bench/Results/alter-table-pg-Linux_2.0.36_i686-cmp-mysql,pg,solid b/sql-bench/Results/alter-table-pg-Linux_2.0.36_i686-cmp-mysql,pg,solid
new file mode 100644
index 00000000000..5d8a624b7a6
--- /dev/null
+++ b/sql-bench/Results/alter-table-pg-Linux_2.0.36_i686-cmp-mysql,pg,solid
@@ -0,0 +1,14 @@
+Testing server 'PostgreSQL 6.4' at 1999-03-09 19:14:16
+
+Testing of ALTER TABLE
+Testing with 300 columns and 1000 rows in 20 steps
+Insert data into the table
+Time for insert (1000) 2 wallclock secs ( 0.65 usr 0.07 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Time for alter_table_add (293): 1 wallclock secs ( 0.15 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Time for create_index (7): 1 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Time for drop_index (7): 0 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Total time: 4 wallclock secs ( 0.80 usr 0.07 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
diff --git a/sql-bench/Results/alter-table-pg_fast-Linux_2.0.36_i686-cmp-mysql,pg,solid b/sql-bench/Results/alter-table-pg_fast-Linux_2.0.36_i686-cmp-mysql,pg,solid
new file mode 100644
index 00000000000..baa92dc4532
--- /dev/null
+++ b/sql-bench/Results/alter-table-pg_fast-Linux_2.0.36_i686-cmp-mysql,pg,solid
@@ -0,0 +1,14 @@
+Testing server 'PostgreSQL 6.4' at 1999-03-11 7:25:18
+
+Testing of ALTER TABLE
+Testing with 300 columns and 1000 rows in 20 steps
+Insert data into the table
+Time for insert (1000) 2 wallclock secs ( 0.60 usr 0.03 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Time for alter_table_add (293): 1 wallclock secs ( 0.19 usr 0.03 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Time for create_index (7): 0 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Time for drop_index (7): 1 wallclock secs ( 0.00 usr 0.01 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Total time: 4 wallclock secs ( 0.79 usr 0.07 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
diff --git a/sql-bench/Results/alter-table-solid-Linux_2.0.36_i686-cmp-mysql,pg,solid b/sql-bench/Results/alter-table-solid-Linux_2.0.36_i686-cmp-mysql,pg,solid
new file mode 100644
index 00000000000..c23922e273c
--- /dev/null
+++ b/sql-bench/Results/alter-table-solid-Linux_2.0.36_i686-cmp-mysql,pg,solid
@@ -0,0 +1,14 @@
+Testing server 'SOLID Server - v.02.30.0026 (Linux ix86)' at 1999-03-06 12:59:26
+
+Testing of ALTER TABLE
+Testing with 300 columns and 1000 rows in 20 steps
+Insert data into the table
+Time for insert (1000) 4 wallclock secs ( 0.83 usr 0.06 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Time for alter_table_add (293): 3 wallclock secs ( 0.19 usr 0.02 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Time for create_index (7): 0 wallclock secs ( 0.01 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Time for drop_index (7): 1 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Total time: 8 wallclock secs ( 1.04 usr 0.08 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
diff --git a/sql-bench/Results/big-tables-Adabas-Linux_2.0.35_i686-cmp-adabas,mysql b/sql-bench/Results/big-tables-Adabas-Linux_2.0.35_i686-cmp-adabas,mysql
new file mode 100644
index 00000000000..5f92b17ef31
--- /dev/null
+++ b/sql-bench/Results/big-tables-Adabas-Linux_2.0.35_i686-cmp-adabas,mysql
@@ -0,0 +1,19 @@
+Testing server 'Adabas 10.01.00' at 1998-08-18 21:09:46
+
+Testing of some unusual tables
+All tests are done 1000 times with 254 fields
+
+Testing table with 254 fields
+Testing select * from table with 1 record
+Time to select_many_fields(1000): 15 secs ( 4.52 usr 4.36 sys = 8.88 cpu)
+
+Testing select all_fields from table with 1 record
+Time to select_many_fields(1000): 20 secs ( 3.56 usr 5.09 sys = 8.65 cpu)
+
+Testing insert VALUES()
+Time to insert_many_fields(1000): 26 secs ( 0.43 usr 0.65 sys = 1.08 cpu)
+
+Testing insert (all_fields) VALUES()
+Time to insert_many_fields(1000): 28 secs ( 0.30 usr 0.87 sys = 1.17 cpu)
+
+Total time: 89 secs ( 8.81 usr 10.98 sys = 19.79 cpu)
diff --git a/sql-bench/Results/big-tables-msql-Linux_2.2.10_i686-cmp-msql,mysql b/sql-bench/Results/big-tables-msql-Linux_2.2.10_i686-cmp-msql,mysql
new file mode 100644
index 00000000000..8201e856d39
--- /dev/null
+++ b/sql-bench/Results/big-tables-msql-Linux_2.2.10_i686-cmp-msql,mysql
@@ -0,0 +1,19 @@
+Testing server 'mSQL server version 2.0.10' at 1999-09-22 8:43:14
+
+Testing of some unusual tables
+All tests are done 10000 times with 75 fields
+
+Testing table with 75 fields
+Testing select * from table with 1 record
+Time to select_many_fields(10000): 52 wallclock secs (26.83 usr 3.83 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing select all_fields from table with 1 record
+Time to select_many_fields(10000): 56 wallclock secs (27.80 usr 3.86 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing insert VALUES()
+Time to insert_many_fields(10000): 20 wallclock secs ( 7.24 usr 0.21 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing insert (all_fields) VALUES()
+Time to insert_many_fields(10000): 17 wallclock secs ( 0.70 usr 0.17 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Total time: 145 wallclock secs (62.58 usr 8.07 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results/big-tables-mysql-3.21-Linux_2.2.1_i686 b/sql-bench/Results/big-tables-mysql-3.21-Linux_2.2.1_i686
new file mode 100644
index 00000000000..fe4890c9c31
--- /dev/null
+++ b/sql-bench/Results/big-tables-mysql-3.21-Linux_2.2.1_i686
@@ -0,0 +1,19 @@
+Testing server 'MySQL 3.21.34' at 1999-02-28 15:57:02
+
+Testing of some unusual tables
+All tests are done 1000 times with 1000 fields
+
+Testing table with 1000 fields
+Testing select * from table with 1 record
+Time to select_many_fields(1000): 16 wallclock secs ( 6.68 usr 4.57 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing select all_fields from table with 1 record
+Time to select_many_fields(1000): 90 wallclock secs ( 3.72 usr 6.06 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing insert VALUES()
+Time to insert_many_fields(1000): 4 wallclock secs ( 0.47 usr 0.04 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing insert (all_fields) VALUES()
+Time to insert_many_fields(1000): 78 wallclock secs ( 0.10 usr 0.08 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Total time: 188 wallclock secs (10.99 usr 10.75 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
diff --git a/sql-bench/Results/big-tables-mysql-HP_UX_B.10.20_9000_778 b/sql-bench/Results/big-tables-mysql-HP_UX_B.10.20_9000_778
new file mode 100644
index 00000000000..6dd80f33e7e
--- /dev/null
+++ b/sql-bench/Results/big-tables-mysql-HP_UX_B.10.20_9000_778
@@ -0,0 +1,19 @@
+Testing server 'MySQL 3.23.4 alpha' at 1999-09-27 15:41:25
+
+Testing of some unusual tables
+All tests are done 1000 times with 1000 fields
+
+Testing table with 1000 fields
+Testing select * from table with 1 record
+Time to select_many_fields(1000): 69 wallclock secs (14.62 usr 24.79 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing select all_fields from table with 1 record
+Time to select_many_fields(1000): 84 wallclock secs (15.08 usr 23.85 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing insert VALUES()
+Time to insert_many_fields(1000): 14 wallclock secs ( 1.04 usr 0.13 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing insert (all_fields) VALUES()
+Time to insert_many_fields(1000): 32 wallclock secs ( 0.21 usr 0.15 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Total time: 200 wallclock secs (30.97 usr 48.92 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results/big-tables-mysql-Linux_2.0.35_i686-cmp-adabas,mysql b/sql-bench/Results/big-tables-mysql-Linux_2.0.35_i686-cmp-adabas,mysql
new file mode 100644
index 00000000000..fbb59a077cf
--- /dev/null
+++ b/sql-bench/Results/big-tables-mysql-Linux_2.0.35_i686-cmp-adabas,mysql
@@ -0,0 +1,19 @@
+Testing server 'MySQL 3.22.9 beta' at 1998-10-20 6:56:05
+
+Testing of some unusual tables
+All tests are done 1000 times with 254 fields
+
+Testing table with 254 fields
+Testing select * from table with 1 record
+Time to select_many_fields(1000): 6 secs ( 1.21 usr 3.68 sys = 4.89 cpu)
+
+Testing select all_fields from table with 1 record
+Time to select_many_fields(1000): 7 secs ( 1.63 usr 2.99 sys = 4.62 cpu)
+
+Testing insert VALUES()
+Time to insert_many_fields(1000): 2 secs ( 0.37 usr 0.17 sys = 0.54 cpu)
+
+Testing insert (all_fields) VALUES()
+Time to insert_many_fields(1000): 2 secs ( 0.06 usr 0.08 sys = 0.14 cpu)
+
+Total time: 17 secs ( 3.29 usr 6.92 sys = 10.21 cpu)
diff --git a/sql-bench/Results/big-tables-mysql-Linux_2.0.36_i686-cmp-mysql,pg,solid b/sql-bench/Results/big-tables-mysql-Linux_2.0.36_i686-cmp-mysql,pg,solid
new file mode 100644
index 00000000000..f8ec1afe3e9
--- /dev/null
+++ b/sql-bench/Results/big-tables-mysql-Linux_2.0.36_i686-cmp-mysql,pg,solid
@@ -0,0 +1,19 @@
+Testing server 'MySQL 3.22.18' at 1999-03-07 22:59:26
+
+Testing of some unusual tables
+All tests are done 1000 times with 300 fields
+
+Testing table with 300 fields
+Testing select * from table with 1 record
+Time to select_many_fields(1000): 4 wallclock secs ( 2.10 usr 1.17 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing select all_fields from table with 1 record
+Time to select_many_fields(1000): 7 wallclock secs ( 1.92 usr 1.31 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing insert VALUES()
+Time to insert_many_fields(1000): 1 wallclock secs ( 0.47 usr 0.03 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing insert (all_fields) VALUES()
+Time to insert_many_fields(1000): 3 wallclock secs ( 0.08 usr 0.07 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Total time: 15 wallclock secs ( 4.57 usr 2.58 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
diff --git a/sql-bench/Results/big-tables-mysql-Linux_2.2.10_i686 b/sql-bench/Results/big-tables-mysql-Linux_2.2.10_i686
new file mode 100644
index 00000000000..06f5a38b022
--- /dev/null
+++ b/sql-bench/Results/big-tables-mysql-Linux_2.2.10_i686
@@ -0,0 +1,19 @@
+Testing server 'MySQL 3.23.3 alpha' at 1999-09-17 8:43:30
+
+Testing of some unusual tables
+All tests are done 1000 times with 1000 fields
+
+Testing table with 1000 fields
+Testing select * from table with 1 record
+Time to select_many_fields(1000): 16 wallclock secs ( 8.58 usr 2.89 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing select all_fields from table with 1 record
+Time to select_many_fields(1000): 21 wallclock secs ( 8.83 usr 3.28 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing insert VALUES()
+Time to insert_many_fields(1000): 4 wallclock secs ( 0.77 usr 0.06 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing insert (all_fields) VALUES()
+Time to insert_many_fields(1000): 9 wallclock secs ( 0.11 usr 0.03 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Total time: 50 wallclock secs (18.30 usr 6.26 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results/big-tables-mysql-Linux_2.2.10_i686-cmp-msql,mysql b/sql-bench/Results/big-tables-mysql-Linux_2.2.10_i686-cmp-msql,mysql
new file mode 100644
index 00000000000..89647023274
--- /dev/null
+++ b/sql-bench/Results/big-tables-mysql-Linux_2.2.10_i686-cmp-msql,mysql
@@ -0,0 +1,19 @@
+Testing server 'MySQL 3.23.3 alpha' at 1999-09-24 9:49:05
+
+Testing of some unusual tables
+All tests are done 10000 times with 75 fields
+
+Testing table with 75 fields
+Testing select * from table with 1 record
+Time to select_many_fields(10000): 20 wallclock secs (11.98 usr 2.79 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing select all_fields from table with 1 record
+Time to select_many_fields(10000): 24 wallclock secs (13.20 usr 2.36 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing insert VALUES()
+Time to insert_many_fields(10000): 11 wallclock secs ( 6.53 usr 0.33 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing insert (all_fields) VALUES()
+Time to insert_many_fields(10000): 8 wallclock secs ( 0.64 usr 0.28 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Total time: 63 wallclock secs (32.36 usr 5.77 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results/big-tables-mysql-Linux_2.2.14_i686_xeon b/sql-bench/Results/big-tables-mysql-Linux_2.2.14_i686_xeon
new file mode 100644
index 00000000000..63198f66a06
--- /dev/null
+++ b/sql-bench/Results/big-tables-mysql-Linux_2.2.14_i686_xeon
@@ -0,0 +1,19 @@
+Testing server 'MySQL 3.23.17 alpha' at 2000-06-01 3:12:05
+
+Testing of some unusual tables
+All tests are done 1000 times with 1000 fields
+
+Testing table with 1000 fields
+Testing select * from table with 1 record
+Time to select_many_fields(1000): 10 wallclock secs ( 4.33 usr 3.89 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing select all_fields from table with 1 record
+Time to select_many_fields(1000): 13 wallclock secs ( 4.10 usr 3.76 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing insert VALUES()
+Time to insert_many_fields(1000): 3 wallclock secs ( 0.40 usr 0.04 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing insert (all_fields) VALUES()
+Time to insert_many_fields(1000): 7 wallclock secs ( 0.05 usr 0.07 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Total time: 33 wallclock secs ( 8.89 usr 7.76 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results/big-tables-mysql-Linux_2.2.1_i686-cmp-adabas,mysql b/sql-bench/Results/big-tables-mysql-Linux_2.2.1_i686-cmp-adabas,mysql
new file mode 100644
index 00000000000..d5e04b416e2
--- /dev/null
+++ b/sql-bench/Results/big-tables-mysql-Linux_2.2.1_i686-cmp-adabas,mysql
@@ -0,0 +1,19 @@
+Testing server 'MySQL 3.22.18' at 1999-02-27 21:12:19
+
+Testing of some unusual tables
+All tests are done 1000 times with 254 fields
+
+Testing table with 254 fields
+Testing select * from table with 1 record
+Time to select_many_fields(1000): 5 wallclock secs ( 1.97 usr 1.21 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing select all_fields from table with 1 record
+Time to select_many_fields(1000): 5 wallclock secs ( 1.99 usr 1.24 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing insert VALUES()
+Time to insert_many_fields(1000): 2 wallclock secs ( 0.39 usr 0.04 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing insert (all_fields) VALUES()
+Time to insert_many_fields(1000): 2 wallclock secs ( 0.09 usr 0.04 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Total time: 14 wallclock secs ( 4.45 usr 2.53 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
diff --git a/sql-bench/Results/big-tables-mysql-NT_4.0 b/sql-bench/Results/big-tables-mysql-NT_4.0
new file mode 100644
index 00000000000..7fd214d8138
--- /dev/null
+++ b/sql-bench/Results/big-tables-mysql-NT_4.0
@@ -0,0 +1,19 @@
+Testing server 'MySQL 3.23.17a alpha' at 2000-06-02 17:37:50
+
+Testing of some unusual tables
+All tests are done 1000 times with 1000 fields
+
+Testing table with 1000 fields
+Testing select * from table with 1 record
+Time to select_many_fields(1000): 20 wallclock secs ( 8.56 usr 9.05 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing select all_fields from table with 1 record
+Time to select_many_fields(1000): 35 wallclock secs ( 8.77 usr 9.11 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing insert VALUES()
+Time to insert_many_fields(1000): 3 wallclock secs ( 0.39 usr 0.30 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing insert (all_fields) VALUES()
+Time to insert_many_fields(1000): 19 wallclock secs ( 0.19 usr 0.19 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Total time: 80 wallclock secs (17.91 usr 18.64 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results/big-tables-mysql-SunOS_5.5.1_sun4u b/sql-bench/Results/big-tables-mysql-SunOS_5.5.1_sun4u
new file mode 100644
index 00000000000..ee26135c77e
--- /dev/null
+++ b/sql-bench/Results/big-tables-mysql-SunOS_5.5.1_sun4u
@@ -0,0 +1,19 @@
+Testing server 'MySQL 3.22.19' at 1999-03-02 3:37:07
+
+Testing of some unusual tables
+All tests are done 1000 times with 1000 fields
+
+Testing table with 1000 fields
+Testing select * from table with 1 record
+Time to select_many_fields(1000): 37 wallclock secs (13.80 usr 14.92 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing select all_fields from table with 1 record
+Time to select_many_fields(1000): 52 wallclock secs (14.27 usr 15.11 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing insert VALUES()
+Time to insert_many_fields(1000): 13 wallclock secs ( 0.90 usr 0.15 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing insert (all_fields) VALUES()
+Time to insert_many_fields(1000): 27 wallclock secs ( 0.11 usr 0.14 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Total time: 130 wallclock secs (29.10 usr 30.32 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results/big-tables-mysql-SunOS_5.7_sun4m b/sql-bench/Results/big-tables-mysql-SunOS_5.7_sun4m
new file mode 100644
index 00000000000..5b82ad4d720
--- /dev/null
+++ b/sql-bench/Results/big-tables-mysql-SunOS_5.7_sun4m
@@ -0,0 +1,19 @@
+Testing server 'MySQL 3.22.20' at 1999-03-19 13:16:46
+
+Testing of some unusual tables
+All tests are done 1000 times with 1000 fields
+
+Testing table with 1000 fields
+Testing select * from table with 1 record
+Time to select_many_fields(1000): 181 secs (49.75 usr 84.73 sys + 0.00 cusr 0.00 csys = 134.48 cpu)
+
+Testing select all_fields from table with 1 record
+Time to select_many_fields(1000): 288 secs (55.83 usr 91.84 sys + 0.00 cusr 0.00 csys = 147.67 cpu)
+
+Testing insert VALUES()
+Time to insert_many_fields(1000): 59 secs ( 5.28 usr 1.31 sys + 0.00 cusr 0.00 csys = 6.59 cpu)
+
+Testing insert (all_fields) VALUES()
+Time to insert_many_fields(1000): 144 secs ( 1.15 usr 1.30 sys + 0.00 cusr 0.00 csys = 2.45 cpu)
+
+Total time: 674 secs (112.16 usr 179.21 sys + 0.00 cusr 0.00 csys = 291.37 cpu)
diff --git a/sql-bench/Results/big-tables-mysql-SunOS_5.7_sun4u b/sql-bench/Results/big-tables-mysql-SunOS_5.7_sun4u
new file mode 100644
index 00000000000..7a53b2f8eab
--- /dev/null
+++ b/sql-bench/Results/big-tables-mysql-SunOS_5.7_sun4u
@@ -0,0 +1,19 @@
+Testing server 'MySQL 3.23.8 alpha' at 2000-01-17 21:16:12
+
+Testing of some unusual tables
+All tests are done 1000 times with 1000 fields
+
+Testing table with 1000 fields
+Testing select * from table with 1 record
+Time to select_many_fields(1000): 24 wallclock secs ( 7.27 usr 12.69 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing select all_fields from table with 1 record
+Time to select_many_fields(1000): 31 wallclock secs ( 7.97 usr 12.08 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing insert VALUES()
+Time to insert_many_fields(1000): 6 wallclock secs ( 0.47 usr 0.14 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing insert (all_fields) VALUES()
+Time to insert_many_fields(1000): 12 wallclock secs ( 0.15 usr 0.04 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Total time: 73 wallclock secs (15.87 usr 24.95 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results/big-tables-mysql-win98 b/sql-bench/Results/big-tables-mysql-win98
new file mode 100644
index 00000000000..dc57828441f
--- /dev/null
+++ b/sql-bench/Results/big-tables-mysql-win98
@@ -0,0 +1,19 @@
+Testing server 'MySQL 3.23.13a alpha' at 2000-03-15 2:24:33
+
+Testing of some unusual tables
+All tests are done 1000 times with 1000 fields
+
+Testing table with 1000 fields
+Testing select * from table with 1 record
+Time to select_many_fields(1000): 55 wallclock secs (55.36 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing select all_fields from table with 1 record
+Time to select_many_fields(1000): 69 wallclock secs (68.88 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing insert VALUES()
+Time to insert_many_fields(1000): 6 wallclock secs ( 6.20 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing insert (all_fields) VALUES()
+Time to insert_many_fields(1000): 19 wallclock secs (18.51 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Total time: 151 wallclock secs (150.66 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results/big-tables-mysql_3.21-Linux_2.0.35_i686 b/sql-bench/Results/big-tables-mysql_3.21-Linux_2.0.35_i686
new file mode 100644
index 00000000000..de22198ab8f
--- /dev/null
+++ b/sql-bench/Results/big-tables-mysql_3.21-Linux_2.0.35_i686
@@ -0,0 +1,19 @@
+Testing server 'MySQL 3.21.33' at 1998-08-21 12:02:09
+
+Testing of some unusual tables
+All tests are done 1000 times with 1000 fields
+
+Testing table with 1000 fields
+Testing select * from table with 1 record
+Time to select_many_fields(1000): 16 secs ( 3.22 usr 10.31 sys = 13.53 cpu)
+
+Testing select all_fields from table with 1 record
+Time to select_many_fields(1000): 135 secs ( 2.29 usr 11.45 sys = 13.74 cpu)
+
+Testing insert VALUES()
+Time to insert_many_fields(1000): 4 secs ( 0.13 usr 0.51 sys = 0.64 cpu)
+
+Testing insert (all_fields) VALUES()
+Time to insert_many_fields(1000): 125 secs ( 0.09 usr 0.14 sys = 0.23 cpu)
+
+Total time: 281 secs ( 5.73 usr 22.43 sys = 28.16 cpu)
diff --git a/sql-bench/Results/big-tables-mysql_fast-Linux_2.2.10_i686-cmp-msql,mysql b/sql-bench/Results/big-tables-mysql_fast-Linux_2.2.10_i686-cmp-msql,mysql
new file mode 100644
index 00000000000..46aae6ac429
--- /dev/null
+++ b/sql-bench/Results/big-tables-mysql_fast-Linux_2.2.10_i686-cmp-msql,mysql
@@ -0,0 +1,19 @@
+Testing server 'MySQL 3.23.3 alpha' at 1999-09-24 9:08:30
+
+Testing of some unusual tables
+All tests are done 10000 times with 75 fields
+
+Testing table with 75 fields
+Testing select * from table with 1 record
+Time to select_many_fields(10000): 21 wallclock secs (11.87 usr 2.62 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing select all_fields from table with 1 record
+Time to select_many_fields(10000): 23 wallclock secs (13.15 usr 2.32 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing insert VALUES()
+Time to insert_many_fields(10000): 11 wallclock secs ( 6.45 usr 0.41 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing insert (all_fields) VALUES()
+Time to insert_many_fields(10000): 8 wallclock secs ( 0.67 usr 0.24 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Total time: 63 wallclock secs (32.15 usr 5.59 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results/big-tables-mysql_odbc-win98 b/sql-bench/Results/big-tables-mysql_odbc-win98
new file mode 100644
index 00000000000..87ac9b1c570
--- /dev/null
+++ b/sql-bench/Results/big-tables-mysql_odbc-win98
@@ -0,0 +1,19 @@
+Testing server 'MySQL 3.22.19a' at 1999-03-02 16:28:33
+
+Testing of some unusual tables
+All tests are done 1000 times with 1000 fields
+
+Testing table with 1000 fields
+Testing select * from table with 1 record
+Time to select_many_fields(1000): 99 wallclock secs (98.59 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing select all_fields from table with 1 record
+Time to select_many_fields(1000): 111 wallclock secs (111.55 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing insert VALUES()
+Time to insert_many_fields(1000): 9 wallclock secs ( 8.85 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing insert (all_fields) VALUES()
+Time to insert_many_fields(1000): 28 wallclock secs (27.40 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Total time: 249 wallclock secs (248.70 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results/big-tables-oracle-Linux_2.0.36_i686-cmp-mysql,oracle b/sql-bench/Results/big-tables-oracle-Linux_2.0.36_i686-cmp-mysql,oracle
new file mode 100644
index 00000000000..c92c28fdeff
--- /dev/null
+++ b/sql-bench/Results/big-tables-oracle-Linux_2.0.36_i686-cmp-mysql,oracle
@@ -0,0 +1,19 @@
+Testing server 'Oracle 8.0.5.0.0' at 1999-03-25 0:39:28
+
+Testing of some unusual tables
+All tests are done 1000 times with 254 fields
+
+Testing table with 254 fields
+Testing select * from table with 1 record
+Time to select_many_fields(1000): 20 wallclock secs ( 1.39 usr 8.59 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing select all_fields from table with 1 record
+Time to select_many_fields(1000): 20 wallclock secs ( 9.99 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing insert VALUES()
+Time to insert_many_fields(1000): 3 wallclock secs ( 0.91 usr 0.05 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing insert (all_fields) VALUES()
+Time to insert_many_fields(1000): 3 wallclock secs ( 1.15 usr 0.11 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Total time: 47 wallclock secs (13.47 usr 8.76 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
diff --git a/sql-bench/Results/big-tables-oracle_fast-Linux_2.0.36_i686-cmp-mysql,oracle b/sql-bench/Results/big-tables-oracle_fast-Linux_2.0.36_i686-cmp-mysql,oracle
new file mode 100644
index 00000000000..ecd01e24826
--- /dev/null
+++ b/sql-bench/Results/big-tables-oracle_fast-Linux_2.0.36_i686-cmp-mysql,oracle
@@ -0,0 +1,25 @@
+Testing server 'Oracle 8.0.5.0.0' at 1999-03-23 8:12:38
+
+Testing of some unusual tables
+All tests are done 1000 times with 254 fields
+
+Testing table with 254 fields
+Time for book-keeping (1): 0 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing select * from table with 1 record
+Time to select_many_fields(1000): 20 wallclock secs ( 0.57 usr 0.63 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing select all_fields from table with 1 record
+Time to select_many_fields(1000): 20 wallclock secs ( 9.98 usr 0.01 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing insert VALUES()
+Time to insert_many_fields(1000): 3 wallclock secs ( 0.85 usr 0.09 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Time for book-keeping (1): 1 wallclock secs ( 0.01 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing insert (all_fields) VALUES()
+Time to insert_many_fields(1000): 4 wallclock secs ( 1.19 usr 0.05 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Time for book-keeping (1): 0 wallclock secs ( 0.01 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Total time: 49 wallclock secs (12.68 usr 0.78 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
diff --git a/sql-bench/Results/big-tables-pg-Linux_2.0.36_i686-cmp-mysql,pg,solid b/sql-bench/Results/big-tables-pg-Linux_2.0.36_i686-cmp-mysql,pg,solid
new file mode 100644
index 00000000000..4f83b61778c
--- /dev/null
+++ b/sql-bench/Results/big-tables-pg-Linux_2.0.36_i686-cmp-mysql,pg,solid
@@ -0,0 +1,19 @@
+Testing server 'PostgreSQL 6.4' at 1999-03-09 19:14:20
+
+Testing of some unusual tables
+All tests are done 1000 times with 300 fields
+
+Testing table with 300 fields
+Testing select * from table with 1 record
+Time to select_many_fields(1000): 170 wallclock secs ( 3.13 usr 0.25 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing select all_fields from table with 1 record
+Time to select_many_fields(1000): 177 wallclock secs ( 3.12 usr 0.21 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing insert VALUES()
+Time to insert_many_fields(1000): 53 wallclock secs ( 0.61 usr 0.07 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing insert (all_fields) VALUES()
+Time to insert_many_fields(1000): 70 wallclock secs ( 0.76 usr 0.07 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Total time: 470 wallclock secs ( 7.63 usr 0.60 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
diff --git a/sql-bench/Results/big-tables-pg_fast-Linux_2.0.36_i686-cmp-mysql,pg,solid b/sql-bench/Results/big-tables-pg_fast-Linux_2.0.36_i686-cmp-mysql,pg,solid
new file mode 100644
index 00000000000..70038af27f1
--- /dev/null
+++ b/sql-bench/Results/big-tables-pg_fast-Linux_2.0.36_i686-cmp-mysql,pg,solid
@@ -0,0 +1,25 @@
+Testing server 'PostgreSQL 6.4' at 1999-03-11 7:25:22
+
+Testing of some unusual tables
+All tests are done 1000 times with 300 fields
+
+Testing table with 300 fields
+Time for book-keeping (1): 1 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing select * from table with 1 record
+Time to select_many_fields(1000): 150 wallclock secs ( 2.78 usr 0.29 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing select all_fields from table with 1 record
+Time to select_many_fields(1000): 158 wallclock secs ( 3.24 usr 0.23 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing insert VALUES()
+Time to insert_many_fields(1000): 51 wallclock secs ( 0.60 usr 0.07 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Time for book-keeping (1): 1 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing insert (all_fields) VALUES()
+Time to insert_many_fields(1000): 69 wallclock secs ( 0.86 usr 0.05 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Time for book-keeping (1): 0 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Total time: 430 wallclock secs ( 7.48 usr 0.64 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
diff --git a/sql-bench/Results/big-tables-solid-Linux_2.0.36_i686-cmp-mysql,pg,solid b/sql-bench/Results/big-tables-solid-Linux_2.0.36_i686-cmp-mysql,pg,solid
new file mode 100644
index 00000000000..22fe0b710c4
--- /dev/null
+++ b/sql-bench/Results/big-tables-solid-Linux_2.0.36_i686-cmp-mysql,pg,solid
@@ -0,0 +1,19 @@
+Testing server 'SOLID Server - v.02.30.0026 (Linux ix86)' at 1999-03-06 12:59:34
+
+Testing of some unusual tables
+All tests are done 1000 times with 300 fields
+
+Testing table with 300 fields
+Testing select * from table with 1 record
+Time to select_many_fields(1000): 5 wallclock secs ( 3.41 usr 0.09 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing select all_fields from table with 1 record
+Time to select_many_fields(1000): 5 wallclock secs ( 3.65 usr 0.07 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing insert VALUES()
+Time to insert_many_fields(1000): 4 wallclock secs ( 0.72 usr 0.07 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing insert (all_fields) VALUES()
+Time to insert_many_fields(1000): 5 wallclock secs ( 0.91 usr 0.05 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Total time: 20 wallclock secs ( 8.71 usr 0.28 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
diff --git a/sql-bench/Results/connect-Adabas-Linux_2.0.35_i686-cmp-adabas,mysql b/sql-bench/Results/connect-Adabas-Linux_2.0.35_i686-cmp-adabas,mysql
new file mode 100644
index 00000000000..a4558059cb6
--- /dev/null
+++ b/sql-bench/Results/connect-Adabas-Linux_2.0.35_i686-cmp-adabas,mysql
@@ -0,0 +1,21 @@
+Testing server 'Adabas 10.01.00' at 1998-08-18 21:11:15
+
+Testing the speed of connecting to the server and sending of data
+All tests are done 10000 times
+
+Testing connection/disconnect
+Time to connect (10000): 164 secs (29.40 usr 100.88 sys = 130.28 cpu)
+
+Testing connect/select 1 row from table/disconnect
+Time to connect+select (10000): 295 secs (22.17 usr 121.92 sys = 144.09 cpu)
+
+Testing select 1 row from table
+Time to select (10000): 32 secs ( 3.68 usr 7.99 sys = 11.67 cpu)
+
+Testing select 2 rows from table
+Time to select (10000): 31 secs ( 4.15 usr 8.03 sys = 12.18 cpu)
+
+Testing retrieval of big records (2000 bytes)
+Time to select_big (10000): 44 secs ( 6.41 usr 11.98 sys = 18.39 cpu)
+
+Total time: 570 secs (65.81 usr 250.86 sys = 316.67 cpu)
diff --git a/sql-bench/Results/connect-msql-Linux_2.2.10_i686-cmp-msql,mysql b/sql-bench/Results/connect-msql-Linux_2.2.10_i686-cmp-msql,mysql
new file mode 100644
index 00000000000..ecd8af20ab1
--- /dev/null
+++ b/sql-bench/Results/connect-msql-Linux_2.2.10_i686-cmp-msql,mysql
@@ -0,0 +1,21 @@
+Testing server 'mSQL server version 2.0.10' at 1999-09-22 8:45:40
+
+Testing the speed of connecting to the server and sending of data
+All tests are done 10000 times
+
+Testing connection/disconnect
+Time to connect (10000): 19 wallclock secs (14.02 usr 1.84 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing connect/select 1 row from table/disconnect
+Time to connect+select_1_row (10000): 24 wallclock secs (15.66 usr 2.66 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing select 1 row from table
+Time to select_1_row (10000): 4 wallclock secs ( 1.60 usr 0.51 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing select 2 rows from table
+Time to select_2_rows (10000): 4 wallclock secs ( 1.72 usr 0.47 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing retrieval of big records (32000 bytes)
+Time to select_big (10000): 34 wallclock secs (14.34 usr 1.98 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Total time: 85 wallclock secs (47.36 usr 7.46 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results/connect-mysql-3.21-Linux_2.2.1_i686 b/sql-bench/Results/connect-mysql-3.21-Linux_2.2.1_i686
new file mode 100644
index 00000000000..3a9b06afb68
--- /dev/null
+++ b/sql-bench/Results/connect-mysql-3.21-Linux_2.2.1_i686
@@ -0,0 +1,27 @@
+Testing server 'MySQL 3.21.34' at 1999-02-28 16:00:11
+
+Testing the speed of connecting to the server and sending of data
+All tests are done 10000 times
+
+Testing connection/disconnect
+Time to connect (10000): 30 wallclock secs (14.51 usr 10.85 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Test connect/simple select/disconnect
+Time for select_simple (10000): 32 wallclock secs (15.36 usr 12.85 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Test simple select
+Time for select_simple (10000): 2 wallclock secs ( 0.59 usr 0.45 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing connect/select 1 row from table/disconnect
+Time to connect+select (10000): 34 wallclock secs (18.27 usr 7.11 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing select 1 row from table
+Time to select (10000): 3 wallclock secs ( 0.91 usr 0.77 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing select 2 rows from table
+Time to select (10000): 4 wallclock secs ( 0.80 usr 0.64 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing retrieval of big records (65000 bytes)
+Time to select_big (10000): 43 wallclock secs (16.00 usr 9.63 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Total time: 148 wallclock secs (66.47 usr 42.30 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
diff --git a/sql-bench/Results/connect-mysql-HP_UX_B.10.20_9000_778 b/sql-bench/Results/connect-mysql-HP_UX_B.10.20_9000_778
new file mode 100644
index 00000000000..0071b0e12cc
--- /dev/null
+++ b/sql-bench/Results/connect-mysql-HP_UX_B.10.20_9000_778
@@ -0,0 +1,27 @@
+Testing server 'MySQL 3.23.4 alpha' at 1999-09-27 15:44:45
+
+Testing the speed of connecting to the server and sending of data
+All tests are done 10000 times
+
+Testing connection/disconnect
+Time to connect (10000): 35 wallclock secs (18.98 usr 4.56 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Test connect/simple select/disconnect
+Time for connect+select_simple (10000): 44 wallclock secs (20.27 usr 5.93 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Test simple select
+Time for select_simple (10000): 6 wallclock secs ( 1.14 usr 1.14 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing connect/select 1 row from table/disconnect
+Time to connect+select_1_row (10000): 49 wallclock secs (21.11 usr 6.36 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing select 1 row from table
+Time to select_1_row (10000): 9 wallclock secs ( 1.48 usr 1.45 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing select 2 rows from table
+Time to select_2_rows (10000): 10 wallclock secs ( 1.61 usr 1.63 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing retrieval of big records (65000 bytes)
+Time to select_big (10000): 85 wallclock secs (30.19 usr 11.18 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Total time: 238 wallclock secs (94.79 usr 32.25 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results/connect-mysql-Linux_2.0.35_i686-cmp-adabas,mysql b/sql-bench/Results/connect-mysql-Linux_2.0.35_i686-cmp-adabas,mysql
new file mode 100644
index 00000000000..adc60870908
--- /dev/null
+++ b/sql-bench/Results/connect-mysql-Linux_2.0.35_i686-cmp-adabas,mysql
@@ -0,0 +1,21 @@
+Testing server 'MySQL 3.22.9 beta' at 1998-10-20 6:56:24
+
+Testing the speed of connecting to the server and sending of data
+All tests are done 10000 times
+
+Testing connection/disconnect
+Time to connect (10000): 53 secs ( 6.27 usr 42.43 sys = 48.70 cpu)
+
+Testing connect/select 1 row from table/disconnect
+Time to connect+select (10000): 59 secs ( 8.21 usr 42.61 sys = 50.82 cpu)
+
+Testing select 1 row from table
+Time to select (10000): 5 secs ( 0.44 usr 2.67 sys = 3.11 cpu)
+
+Testing select 2 rows from table
+Time to select (10000): 7 secs ( 0.35 usr 3.08 sys = 3.43 cpu)
+
+Testing retrieval of big records (2000 bytes)
+Time to select_big (10000): 10 secs ( 2.35 usr 4.83 sys = 7.18 cpu)
+
+Total time: 134 secs (17.63 usr 95.64 sys = 113.27 cpu)
diff --git a/sql-bench/Results/connect-mysql-Linux_2.0.36_i686-cmp-mysql,pg,solid b/sql-bench/Results/connect-mysql-Linux_2.0.36_i686-cmp-mysql,pg,solid
new file mode 100644
index 00000000000..545df086c0c
--- /dev/null
+++ b/sql-bench/Results/connect-mysql-Linux_2.0.36_i686-cmp-mysql,pg,solid
@@ -0,0 +1,21 @@
+Testing server 'MySQL 3.22.18' at 1999-03-07 22:59:43
+
+Testing the speed of connecting to the server and sending of data
+All tests are done 10000 times
+
+Testing connection/disconnect
+Time to connect (10000): 15 wallclock secs ( 8.66 usr 1.63 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing connect/select 1 row from table/disconnect
+Time to connect+select (10000): 19 wallclock secs ( 9.61 usr 2.34 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing select 1 row from table
+Time to select (10000): 3 wallclock secs ( 0.74 usr 0.46 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing select 2 rows from table
+Time to select (10000): 5 wallclock secs ( 1.01 usr 0.49 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing retrieval of big records (7000 bytes)
+Time to select_big (10000): 11 wallclock secs ( 5.81 usr 0.84 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Total time: 53 wallclock secs (25.85 usr 5.76 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
diff --git a/sql-bench/Results/connect-mysql-Linux_2.2.10_i686 b/sql-bench/Results/connect-mysql-Linux_2.2.10_i686
new file mode 100644
index 00000000000..bb2bb14559d
--- /dev/null
+++ b/sql-bench/Results/connect-mysql-Linux_2.2.10_i686
@@ -0,0 +1,27 @@
+Testing server 'MySQL 3.23.3 alpha' at 1999-09-17 8:44:21
+
+Testing the speed of connecting to the server and sending of data
+All tests are done 10000 times
+
+Testing connection/disconnect
+Time to connect (10000): 18 wallclock secs (13.36 usr 1.13 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Test connect/simple select/disconnect
+Time for connect+select_simple (10000): 21 wallclock secs (14.34 usr 1.42 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Test simple select
+Time for select_simple (10000): 2 wallclock secs ( 0.74 usr 0.31 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing connect/select 1 row from table/disconnect
+Time to connect+select_1_row (10000): 23 wallclock secs (14.47 usr 1.60 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing select 1 row from table
+Time to select_1_row (10000): 3 wallclock secs ( 1.05 usr 0.33 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing select 2 rows from table
+Time to select_2_rows (10000): 4 wallclock secs ( 1.26 usr 0.35 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing retrieval of big records (65000 bytes)
+Time to select_big (10000): 49 wallclock secs (20.80 usr 4.97 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Total time: 120 wallclock secs (66.02 usr 10.12 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results/connect-mysql-Linux_2.2.10_i686-cmp-msql,mysql b/sql-bench/Results/connect-mysql-Linux_2.2.10_i686-cmp-msql,mysql
new file mode 100644
index 00000000000..82f6128e7d7
--- /dev/null
+++ b/sql-bench/Results/connect-mysql-Linux_2.2.10_i686-cmp-msql,mysql
@@ -0,0 +1,21 @@
+Testing server 'MySQL 3.23.3 alpha' at 1999-09-24 9:50:08
+
+Testing the speed of connecting to the server and sending of data
+All tests are done 10000 times
+
+Testing connection/disconnect
+Time to connect (10000): 23 wallclock secs (13.79 usr 3.43 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing connect/select 1 row from table/disconnect
+Time to connect+select_1_row (10000): 27 wallclock secs (14.93 usr 4.05 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing select 1 row from table
+Time to select_1_row (10000): 3 wallclock secs ( 1.07 usr 0.37 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing select 2 rows from table
+Time to select_2_rows (10000): 4 wallclock secs ( 1.16 usr 0.50 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing retrieval of big records (32000 bytes)
+Time to select_big (10000): 26 wallclock secs (12.76 usr 1.10 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Total time: 83 wallclock secs (43.74 usr 9.45 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results/connect-mysql-Linux_2.2.14_i686_xeon b/sql-bench/Results/connect-mysql-Linux_2.2.14_i686_xeon
new file mode 100644
index 00000000000..cf28bdb2eab
--- /dev/null
+++ b/sql-bench/Results/connect-mysql-Linux_2.2.14_i686_xeon
@@ -0,0 +1,27 @@
+Testing server 'MySQL 3.23.17 alpha' at 2000-06-01 3:12:38
+
+Testing the speed of connecting to the server and sending of data
+All tests are done 10000 times
+
+Testing connection/disconnect
+Time to connect (10000): 12 wallclock secs ( 6.38 usr 2.82 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Test connect/simple select/disconnect
+Time for connect+select_simple (10000): 13 wallclock secs ( 6.71 usr 3.26 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Test simple select
+Time for select_simple (10000): 2 wallclock secs ( 0.34 usr 0.39 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing connect/select 1 row from table/disconnect
+Time to connect+select_1_row (10000): 15 wallclock secs ( 6.57 usr 3.78 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing select 1 row from table
+Time to select_1_row (10000): 2 wallclock secs ( 0.54 usr 0.38 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing select 2 rows from table
+Time to select_2_rows (10000): 3 wallclock secs ( 0.57 usr 0.44 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing retrieval of big records (65000 bytes)
+Time to select_big (10000): 27 wallclock secs ( 8.98 usr 5.65 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Total time: 74 wallclock secs (30.09 usr 16.72 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results/connect-mysql-Linux_2.2.1_i686-cmp-adabas,mysql b/sql-bench/Results/connect-mysql-Linux_2.2.1_i686-cmp-adabas,mysql
new file mode 100644
index 00000000000..24ab14ca097
--- /dev/null
+++ b/sql-bench/Results/connect-mysql-Linux_2.2.1_i686-cmp-adabas,mysql
@@ -0,0 +1,21 @@
+Testing server 'MySQL 3.22.18' at 1999-02-27 21:12:34
+
+Testing the speed of connecting to the server and sending of data
+All tests are done 10000 times
+
+Testing connection/disconnect
+Time to connect (10000): 31 wallclock secs (15.46 usr 11.47 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing connect/select 1 row from table/disconnect
+Time to connect+select (10000): 35 wallclock secs (15.54 usr 13.17 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing select 1 row from table
+Time to select (10000): 3 wallclock secs ( 0.83 usr 0.67 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing select 2 rows from table
+Time to select (10000): 4 wallclock secs ( 0.92 usr 0.72 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing retrieval of big records (2000 bytes)
+Time to select_big (10000): 9 wallclock secs ( 4.37 usr 0.76 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Total time: 82 wallclock secs (37.13 usr 26.79 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
diff --git a/sql-bench/Results/connect-mysql-NT_4.0 b/sql-bench/Results/connect-mysql-NT_4.0
new file mode 100644
index 00000000000..937b4704b5b
--- /dev/null
+++ b/sql-bench/Results/connect-mysql-NT_4.0
@@ -0,0 +1,30 @@
+Testing server 'MySQL 3.23.17a alpha' at 2000-06-02 22:55:01
+
+Testing the speed of connecting to the server and sending of data
+All tests are done 10000 times
+
+Testing connection/disconnect
+Time to connect (10000): 34 wallclock secs (11.53 usr 10.31 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Test connect/simple select/disconnect
+Time for connect+select_simple (10000): 37 wallclock secs (12.56 usr 11.92 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Test simple select
+Time for select_simple (10000): 4 wallclock secs ( 0.94 usr 1.67 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing connect/select 1 row from table/disconnect
+Time to connect+select_1_row (10000): 39 wallclock secs (12.75 usr 13.53 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing select 1 row from table
+Time to select_1_row (10000): 5 wallclock secs ( 1.11 usr 1.91 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing select 2 rows from table
+Time to select_2_rows (10000): 7 wallclock secs ( 1.23 usr 1.58 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Test select with aritmetic (+)
+Time for select_column+column (10000): 6 wallclock secs ( 1.05 usr 1.86 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing retrieval of big records (65000 bytes)
+Time to select_big (10000): 54 wallclock secs (15.66 usr 8.23 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Total time: 186 wallclock secs (56.84 usr 51.02 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results/connect-mysql-SunOS_5.5.1_sun4u b/sql-bench/Results/connect-mysql-SunOS_5.5.1_sun4u
new file mode 100644
index 00000000000..d8696b7c5db
--- /dev/null
+++ b/sql-bench/Results/connect-mysql-SunOS_5.5.1_sun4u
@@ -0,0 +1,27 @@
+Testing server 'MySQL 3.22.19' at 1999-03-02 3:39:17
+
+Testing the speed of connecting to the server and sending of data
+All tests are done 10000 times
+
+Testing connection/disconnect
+Time to connect (10000): 79 wallclock secs (23.14 usr 25.86 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Test connect/simple select/disconnect
+Time for select_simple (10000): 87 wallclock secs (24.54 usr 27.59 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Test simple select
+Time for select_simple (10000): 6 wallclock secs ( 1.33 usr 1.74 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing connect/select 1 row from table/disconnect
+Time to connect+select (10000): 87 wallclock secs (25.51 usr 28.78 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing select 1 row from table
+Time to select (10000): 9 wallclock secs ( 1.92 usr 1.93 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing select 2 rows from table
+Time to select (10000): 9 wallclock secs ( 1.63 usr 1.78 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing retrieval of big records (65000 bytes)
+Time to select_big (10000): 45 wallclock secs (16.52 usr 7.33 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Total time: 322 wallclock secs (94.60 usr 95.02 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results/connect-mysql-SunOS_5.7_sun4m b/sql-bench/Results/connect-mysql-SunOS_5.7_sun4m
new file mode 100644
index 00000000000..4b2154a9d52
--- /dev/null
+++ b/sql-bench/Results/connect-mysql-SunOS_5.7_sun4m
@@ -0,0 +1,27 @@
+Testing server 'MySQL 3.22.20' at 1999-03-19 13:28:05
+
+Testing the speed of connecting to the server and sending of data
+All tests are done 10000 times
+
+Testing connection/disconnect
+Time to connect (10000): 292 secs (88.91 usr 68.44 sys + 0.00 cusr 0.00 csys = 157.35 cpu)
+
+Test connect/simple select/disconnect
+Time for select_simple (10000): 314 secs (88.59 usr 81.30 sys + 0.00 cusr 0.00 csys = 169.89 cpu)
+
+Test simple select
+Time for select_simple (10000): 48 secs ( 7.03 usr 11.44 sys + 0.00 cusr 0.00 csys = 18.47 cpu)
+
+Testing connect/select 1 row from table/disconnect
+Time to connect+select (10000): 363 secs (104.08 usr 83.81 sys + 0.00 cusr 0.00 csys = 187.89 cpu)
+
+Testing select 1 row from table
+Time to select (10000): 57 secs ( 8.47 usr 14.74 sys + 0.00 cusr 0.00 csys = 23.21 cpu)
+
+Testing select 2 rows from table
+Time to select (10000): 54 secs ( 7.46 usr 13.80 sys + 0.00 cusr 0.00 csys = 21.26 cpu)
+
+Testing retrieval of big records (65000 bytes)
+Time to select_big (10000): 385 secs (122.16 usr 58.29 sys + 0.00 cusr 0.00 csys = 180.45 cpu)
+
+Total time: 1514 secs (426.83 usr 331.83 sys + 0.00 cusr 0.00 csys = 758.66 cpu)
diff --git a/sql-bench/Results/connect-mysql-SunOS_5.7_sun4u b/sql-bench/Results/connect-mysql-SunOS_5.7_sun4u
new file mode 100644
index 00000000000..fd415d9fa8c
--- /dev/null
+++ b/sql-bench/Results/connect-mysql-SunOS_5.7_sun4u
@@ -0,0 +1,27 @@
+Testing server 'MySQL 3.23.8 alpha' at 2000-01-17 21:17:26
+
+Testing the speed of connecting to the server and sending of data
+All tests are done 10000 times
+
+Testing connection/disconnect
+Time to connect (10000): 30 wallclock secs (10.70 usr 10.77 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Test connect/simple select/disconnect
+Time for connect+select_simple (10000): 33 wallclock secs (11.76 usr 11.97 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Test simple select
+Time for select_simple (10000): 4 wallclock secs ( 0.82 usr 1.35 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing connect/select 1 row from table/disconnect
+Time to connect+select_1_row (10000): 35 wallclock secs (11.86 usr 11.88 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing select 1 row from table
+Time to select_1_row (10000): 5 wallclock secs ( 0.94 usr 1.70 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing select 2 rows from table
+Time to select_2_rows (10000): 6 wallclock secs ( 0.96 usr 1.77 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing retrieval of big records (65000 bytes)
+Time to select_big (10000): 28 wallclock secs ( 9.19 usr 5.55 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Total time: 141 wallclock secs (46.24 usr 45.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results/connect-mysql-win98 b/sql-bench/Results/connect-mysql-win98
new file mode 100644
index 00000000000..cf0c35ddc8e
--- /dev/null
+++ b/sql-bench/Results/connect-mysql-win98
@@ -0,0 +1,27 @@
+Testing server 'MySQL 3.23.13a alpha' at 2000-03-15 2:27:04
+
+Testing the speed of connecting to the server and sending of data
+All tests are done 10000 times
+
+Testing connection/disconnect
+Time to connect (10000): 52 wallclock secs (51.85 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Test connect/simple select/disconnect
+Time for connect+select_simple (10000): 67 wallclock secs (66.90 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Test simple select
+Time for select_simple (10000): 12 wallclock secs (12.20 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing connect/select 1 row from table/disconnect
+Time to connect+select_1_row (10000): 72 wallclock secs (71.95 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing select 1 row from table
+Time to select_1_row (10000): 16 wallclock secs (15.99 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing select 2 rows from table
+Time to select_2_rows (10000): 19 wallclock secs (18.89 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing retrieval of big records (65000 bytes)
+Time to select_big (10000): 130 wallclock secs (130.56 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Total time: 369 wallclock secs (368.94 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results/connect-mysql_3.21-Linux_2.0.35_i686 b/sql-bench/Results/connect-mysql_3.21-Linux_2.0.35_i686
new file mode 100644
index 00000000000..9ce05b3dd93
--- /dev/null
+++ b/sql-bench/Results/connect-mysql_3.21-Linux_2.0.35_i686
@@ -0,0 +1,27 @@
+Testing server 'MySQL 3.21.33' at 1998-08-21 12:06:50
+
+Testing the speed of connecting to the server and sending of data
+All tests are done 10000 times
+
+Testing connection/disconnect
+Time to connect (10000): 54 secs ( 6.43 usr 42.04 sys = 48.47 cpu)
+
+Test connect/simple select/disconnect
+Time for select_simple (10000): 56 secs ( 7.46 usr 42.52 sys = 49.98 cpu)
+
+Test simple select
+Time for select_simple (10000): 4 secs ( 0.26 usr 1.81 sys = 2.07 cpu)
+
+Testing connect/select 1 row from table/disconnect
+Time to connect+select (10000): 58 secs ( 8.15 usr 42.24 sys = 50.39 cpu)
+
+Testing select 1 row from table
+Time to select (10000): 5 secs ( 0.42 usr 1.87 sys = 2.29 cpu)
+
+Testing select 2 rows from table
+Time to select (10000): 6 secs ( 0.34 usr 2.68 sys = 3.02 cpu)
+
+Testing retrieval of big records (65000 bytes)
+Time to select_big (10000): 47 secs ( 8.79 usr 16.29 sys = 25.08 cpu)
+
+Total time: 230 secs (31.85 usr 149.46 sys = 181.31 cpu)
diff --git a/sql-bench/Results/connect-mysql_fast-Linux_2.2.10_i686-cmp-msql,mysql b/sql-bench/Results/connect-mysql_fast-Linux_2.2.10_i686-cmp-msql,mysql
new file mode 100644
index 00000000000..3bd592e5855
--- /dev/null
+++ b/sql-bench/Results/connect-mysql_fast-Linux_2.2.10_i686-cmp-msql,mysql
@@ -0,0 +1,21 @@
+Testing server 'MySQL 3.23.3 alpha' at 1999-09-24 9:09:34
+
+Testing the speed of connecting to the server and sending of data
+All tests are done 10000 times
+
+Testing connection/disconnect
+Time to connect (10000): 20 wallclock secs (14.35 usr 1.53 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing connect/select 1 row from table/disconnect
+Time to connect+select_1_row (10000): 24 wallclock secs (15.08 usr 2.21 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing select 1 row from table
+Time to select_1_row (10000): 4 wallclock secs ( 1.14 usr 0.33 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing select 2 rows from table
+Time to select_2_rows (10000): 4 wallclock secs ( 1.24 usr 0.37 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing retrieval of big records (32000 bytes)
+Time to select_big (10000): 25 wallclock secs (10.23 usr 4.56 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Total time: 77 wallclock secs (42.05 usr 9.01 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results/connect-mysql_odbc-win98 b/sql-bench/Results/connect-mysql_odbc-win98
new file mode 100644
index 00000000000..9ec5a2e9f76
--- /dev/null
+++ b/sql-bench/Results/connect-mysql_odbc-win98
@@ -0,0 +1,27 @@
+Testing server 'MySQL 3.22.19a' at 1999-03-02 16:32:42
+
+Testing the speed of connecting to the server and sending of data
+All tests are done 10000 times
+
+Testing connection/disconnect
+Time to connect (10000): 337 wallclock secs (336.42 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Test connect/simple select/disconnect
+Time for select_simple (10000): 442 wallclock secs (442.59 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Test simple select
+Time for select_simple (10000): 34 wallclock secs (33.23 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing connect/select 1 row from table/disconnect
+Time to connect+select (10000): 511 wallclock secs (511.30 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing select 1 row from table
+Time to select (10000): 39 wallclock secs (38.67 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing select 2 rows from table
+Time to select (10000): 43 wallclock secs (43.56 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing retrieval of big records (65000 bytes)
+Time to select_big (10000): 222 wallclock secs (221.78 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Total time: 1628 wallclock secs (1627.82 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results/connect-oracle-Linux_2.0.36_i686-cmp-mysql,oracle b/sql-bench/Results/connect-oracle-Linux_2.0.36_i686-cmp-mysql,oracle
new file mode 100644
index 00000000000..5da8ad03c13
--- /dev/null
+++ b/sql-bench/Results/connect-oracle-Linux_2.0.36_i686-cmp-mysql,oracle
@@ -0,0 +1,9 @@
+Testing server 'Oracle 8.0.5.0.0' at 1999-03-15 7:47:56
+
+Testing the speed of connecting to the server and sending of data
+All tests are done 10000 times
+
+Testing connection/disconnect
+Time to connect (10000): 597 wallclock secs (123.36 usr 77.92 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing connect/select 1 row from table/disconnect
diff --git a/sql-bench/Results/connect-pg-Linux_2.0.36_i686-cmp-mysql,pg,solid b/sql-bench/Results/connect-pg-Linux_2.0.36_i686-cmp-mysql,pg,solid
new file mode 100644
index 00000000000..add26af2080
--- /dev/null
+++ b/sql-bench/Results/connect-pg-Linux_2.0.36_i686-cmp-mysql,pg,solid
@@ -0,0 +1,21 @@
+Testing server 'PostgreSQL 6.4' at 1999-03-09 19:22:10
+
+Testing the speed of connecting to the server and sending of data
+All tests are done 10000 times
+
+Testing connection/disconnect
+Time to connect (10000): 84 wallclock secs ( 9.71 usr 2.81 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing connect/select 1 row from table/disconnect
+Time to connect+select (10000): 210 wallclock secs (17.17 usr 5.07 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing select 1 row from table
+Time to select (10000): 17 wallclock secs ( 4.91 usr 0.60 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing select 2 rows from table
+Time to select (10000): 18 wallclock secs ( 5.09 usr 0.53 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing retrieval of big records (7000 bytes)
+Time to select_big (10000): 20 wallclock secs ( 5.76 usr 1.16 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Total time: 349 wallclock secs (42.65 usr 10.17 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
diff --git a/sql-bench/Results/connect-pg_fast-Linux_2.0.36_i686-cmp-mysql,pg,solid b/sql-bench/Results/connect-pg_fast-Linux_2.0.36_i686-cmp-mysql,pg,solid
new file mode 100644
index 00000000000..add64ed612f
--- /dev/null
+++ b/sql-bench/Results/connect-pg_fast-Linux_2.0.36_i686-cmp-mysql,pg,solid
@@ -0,0 +1,29 @@
+Testing server 'PostgreSQL 6.4' at 1999-03-11 7:32:32
+
+Testing the speed of connecting to the server and sending of data
+All tests are done 10000 times
+
+Testing connection/disconnect
+Time to connect (10000): 90 wallclock secs ( 9.98 usr 1.52 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Time for book-keeping (1): 0 wallclock secs ( 0.01 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing connect/select 1 row from table/disconnect
+Time to connect+select (10000): 218 wallclock secs (15.97 usr 3.53 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing select 1 row from table
+Time to select (10000): 22 wallclock secs ( 5.14 usr 0.68 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing select 2 rows from table
+Time to select (10000): 22 wallclock secs ( 5.22 usr 0.56 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Time for book-keeping (1): 1 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing retrieval of big records (7000 bytes)
+Time for book-keeping (1): 0 wallclock secs ( 0.01 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Time to select_big (10000): 25 wallclock secs ( 7.28 usr 1.31 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Time for book-keeping (1): 1 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Total time: 379 wallclock secs (43.62 usr 7.61 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
diff --git a/sql-bench/Results/connect-solid-Linux_2.0.36_i686-cmp-mysql,pg,solid b/sql-bench/Results/connect-solid-Linux_2.0.36_i686-cmp-mysql,pg,solid
new file mode 100644
index 00000000000..69e74431c09
--- /dev/null
+++ b/sql-bench/Results/connect-solid-Linux_2.0.36_i686-cmp-mysql,pg,solid
@@ -0,0 +1,21 @@
+Testing server 'SOLID Server - v.02.30.0026 (Linux ix86)' at 1999-03-06 12:59:54
+
+Testing the speed of connecting to the server and sending of data
+All tests are done 10000 times
+
+Testing connection/disconnect
+Time to connect (10000): 84 wallclock secs (58.46 usr 10.25 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing connect/select 1 row from table/disconnect
+Time to connect+select (10000): 105 wallclock secs (66.76 usr 11.09 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing select 1 row from table
+Time to select (10000): 13 wallclock secs ( 7.03 usr 0.35 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing select 2 rows from table
+Time to select (10000): 14 wallclock secs ( 7.08 usr 0.40 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing retrieval of big records (7000 bytes)
+Time to select_big (10000): 20 wallclock secs (10.57 usr 1.03 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Total time: 236 wallclock secs (149.92 usr 23.13 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
diff --git a/sql-bench/Results/create-Adabas-Linux_2.0.35_i686-cmp-adabas,mysql b/sql-bench/Results/create-Adabas-Linux_2.0.35_i686-cmp-adabas,mysql
new file mode 100644
index 00000000000..71908966bd0
--- /dev/null
+++ b/sql-bench/Results/create-Adabas-Linux_2.0.35_i686-cmp-adabas,mysql
@@ -0,0 +1,18 @@
+Testing server 'Adabas 10.01.00' at 1998-08-18 21:20:47
+
+Testing the speed of creating and droping tables
+All tests are done 1000 times
+
+Testing create of tables
+Time for create_table (1000): 46 secs ( 1.43 usr 0.59 sys = 2.02 cpu)
+
+Accessing tables
+Time to select_group (1000): 3 secs ( 0.28 usr 0.81 sys = 1.09 cpu)
+
+Testing drop
+Time for drop_table (1000): 76 secs ( 0.12 usr 0.63 sys = 0.75 cpu)
+
+Testing create+drop
+Time for create+drop (1000): 126 secs ( 0.25 usr 2.57 sys = 2.82 cpu)
+Time for create_key+drop (1000): 97 secs ( 0.27 usr 2.86 sys = 3.13 cpu)
+Total time: 348 secs ( 2.35 usr 7.46 sys = 9.81 cpu)
diff --git a/sql-bench/Results/create-msql-Linux_2.2.10_i686-cmp-msql,mysql b/sql-bench/Results/create-msql-Linux_2.2.10_i686-cmp-msql,mysql
new file mode 100644
index 00000000000..72be2853563
--- /dev/null
+++ b/sql-bench/Results/create-msql-Linux_2.2.10_i686-cmp-msql,mysql
@@ -0,0 +1,20 @@
+Testing server 'mSQL server version 2.0.10' at 1999-09-22 8:47:06
+
+Testing the speed of creating and droping tables
+All tests are done 1000 times
+
+Okay..Let's make sure that our tables don't exist yet.
+
+Testing create of tables
+Time for create_table (1000): 9 wallclock secs ( 0.61 usr 0.10 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Accessing tables
+Time to select (1000): 0 wallclock secs ( 0.23 usr 0.06 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing drop
+Time for drop_table (1000): 1 wallclock secs ( 0.10 usr 0.02 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing create+drop
+Time for create+drop (1000): 2 wallclock secs ( 0.78 usr 0.05 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for create_key+drop (1000): 2 wallclock secs ( 0.72 usr 0.05 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Total time: 14 wallclock secs ( 2.44 usr 0.28 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results/create-mysql-3.21-Linux_2.2.1_i686 b/sql-bench/Results/create-mysql-3.21-Linux_2.2.1_i686
new file mode 100644
index 00000000000..b45664e653d
--- /dev/null
+++ b/sql-bench/Results/create-mysql-3.21-Linux_2.2.1_i686
@@ -0,0 +1,18 @@
+Testing server 'MySQL 3.21.34' at 1999-02-28 16:02:40
+
+Testing the speed of creating and droping tables
+All tests are done 1000 times
+
+Testing create of tables
+Time for create_table (1000): 5 wallclock secs ( 0.27 usr 0.06 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Accessing tables
+Time to select_group (1000): 1 wallclock secs ( 0.19 usr 0.11 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing drop
+Time for drop_table (1000): 1 wallclock secs ( 0.08 usr 0.02 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing create+drop
+Time for create+drop (1000): 1 wallclock secs ( 0.37 usr 0.06 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for create_key+drop (1000): 3 wallclock secs ( 0.77 usr 0.07 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Total time: 11 wallclock secs ( 1.68 usr 0.32 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
diff --git a/sql-bench/Results/create-mysql-HP_UX_B.10.20_9000_778 b/sql-bench/Results/create-mysql-HP_UX_B.10.20_9000_778
new file mode 100644
index 00000000000..1347014c3d4
--- /dev/null
+++ b/sql-bench/Results/create-mysql-HP_UX_B.10.20_9000_778
@@ -0,0 +1,18 @@
+Testing server 'MySQL 3.23.4 alpha' at 1999-09-27 15:48:44
+
+Testing the speed of creating and droping tables
+All tests are done 1000 times
+
+Testing create of tables
+Time for create_table (1000): 10 wallclock secs ( 0.53 usr 0.08 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Accessing tables
+Time to select_group (1000): 2 wallclock secs ( 0.18 usr 0.13 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing drop
+Time for drop_table (1000): 1 wallclock secs ( 0.11 usr 0.06 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing create+drop
+Time for create+drop (1000): 7 wallclock secs ( 0.63 usr 0.14 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for create_key+drop (1000): 9 wallclock secs ( 1.34 usr 0.15 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Total time: 29 wallclock secs ( 2.79 usr 0.56 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results/create-mysql-Linux_2.0.35_i686-cmp-adabas,mysql b/sql-bench/Results/create-mysql-Linux_2.0.35_i686-cmp-adabas,mysql
new file mode 100644
index 00000000000..7887f908f8d
--- /dev/null
+++ b/sql-bench/Results/create-mysql-Linux_2.0.35_i686-cmp-adabas,mysql
@@ -0,0 +1,18 @@
+Testing server 'MySQL 3.22.9 beta' at 1998-10-20 6:58:38
+
+Testing the speed of creating and droping tables
+All tests are done 1000 times
+
+Testing create of tables
+Time for create_table (1000): 7 secs ( 0.32 usr 0.12 sys = 0.44 cpu)
+
+Accessing tables
+Time to select_group (1000): 6 secs ( 0.02 usr 0.22 sys = 0.24 cpu)
+
+Testing drop
+Time for drop_table (1000): 0 secs ( 0.06 usr 0.12 sys = 0.18 cpu)
+
+Testing create+drop
+Time for create+drop (1000): 3 secs ( 0.24 usr 0.33 sys = 0.57 cpu)
+Time for create_key+drop (1000): 3 secs ( 0.11 usr 0.69 sys = 0.80 cpu)
+Total time: 19 secs ( 0.75 usr 1.48 sys = 2.23 cpu)
diff --git a/sql-bench/Results/create-mysql-Linux_2.0.36_i686-cmp-mysql,pg,solid b/sql-bench/Results/create-mysql-Linux_2.0.36_i686-cmp-mysql,pg,solid
new file mode 100644
index 00000000000..2a129309e9e
--- /dev/null
+++ b/sql-bench/Results/create-mysql-Linux_2.0.36_i686-cmp-mysql,pg,solid
@@ -0,0 +1,20 @@
+Testing server 'MySQL 3.22.18' at 1999-03-07 23:00:37
+
+Testing the speed of creating and droping tables
+All tests are done 1000 times
+
+Okay..Let's make sure that our tables don't exist yet.
+
+Testing create of tables
+Time for create_table (1000): 6 wallclock secs ( 0.31 usr 0.05 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Accessing tables
+Time to select_group (1000): 4 wallclock secs ( 0.11 usr 0.05 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing drop
+Time for drop_table (1000): 0 wallclock secs ( 0.12 usr 0.05 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing create+drop
+Time for create+drop (1000): 3 wallclock secs ( 0.39 usr 0.08 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for create_key+drop (1000): 2 wallclock secs ( 0.55 usr 0.02 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Total time: 15 wallclock secs ( 1.48 usr 0.25 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
diff --git a/sql-bench/Results/create-mysql-Linux_2.2.10_i686 b/sql-bench/Results/create-mysql-Linux_2.2.10_i686
new file mode 100644
index 00000000000..59af359d8dc
--- /dev/null
+++ b/sql-bench/Results/create-mysql-Linux_2.2.10_i686
@@ -0,0 +1,20 @@
+Testing server 'MySQL 3.23.3 alpha' at 1999-09-17 8:46:21
+
+Testing the speed of creating and droping tables
+All tests are done 1000 times
+
+Okay..Let's make sure that our tables don't exist yet.
+
+Testing create of tables
+Time for create_table (1000): 4 wallclock secs ( 0.46 usr 0.07 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Accessing tables
+Time to select_group (1000): 1 wallclock secs ( 0.19 usr 0.07 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing drop
+Time for drop_table (1000): 1 wallclock secs ( 0.15 usr 0.04 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing create+drop
+Time for create+drop (1000): 1 wallclock secs ( 0.63 usr 0.01 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for create_key+drop (1000): 2 wallclock secs ( 0.78 usr 0.07 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Total time: 9 wallclock secs ( 2.21 usr 0.26 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results/create-mysql-Linux_2.2.10_i686-cmp-msql,mysql b/sql-bench/Results/create-mysql-Linux_2.2.10_i686-cmp-msql,mysql
new file mode 100644
index 00000000000..72c2850ca99
--- /dev/null
+++ b/sql-bench/Results/create-mysql-Linux_2.2.10_i686-cmp-msql,mysql
@@ -0,0 +1,20 @@
+Testing server 'MySQL 3.23.3 alpha' at 1999-09-24 9:51:31
+
+Testing the speed of creating and droping tables
+All tests are done 1000 times
+
+Okay..Let's make sure that our tables don't exist yet.
+
+Testing create of tables
+Time for create_table (1000): 4 wallclock secs ( 0.46 usr 0.05 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Accessing tables
+Time to select (1000): 2 wallclock secs ( 0.27 usr 0.03 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing drop
+Time for drop_table (1000): 2 wallclock secs ( 0.15 usr 0.03 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing create+drop
+Time for create+drop (1000): 3 wallclock secs ( 0.46 usr 0.03 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for create_key+drop (1000): 3 wallclock secs ( 0.54 usr 0.02 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Total time: 14 wallclock secs ( 1.89 usr 0.16 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results/create-mysql-Linux_2.2.14_i686_xeon b/sql-bench/Results/create-mysql-Linux_2.2.14_i686_xeon
new file mode 100644
index 00000000000..18cc2be47ca
--- /dev/null
+++ b/sql-bench/Results/create-mysql-Linux_2.2.14_i686_xeon
@@ -0,0 +1,18 @@
+Testing server 'MySQL 3.23.17 alpha' at 2000-06-01 3:13:52
+
+Testing the speed of creating and droping tables
+Testing with 10000 tables and 10000 loop count
+
+Testing create of tables
+Time for create_MANY_tables (10000): 263 wallclock secs ( 2.58 usr 0.48 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Accessing tables
+Time to select_group_when_MANY_tables (10000): 97 wallclock secs ( 1.09 usr 0.52 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing drop
+Time for drop_table_when_MANY_tables (10000): 22 wallclock secs ( 0.59 usr 0.42 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing create+drop
+Time for create+drop (10000): 19 wallclock secs ( 2.43 usr 0.72 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for create_key+drop (10000): 18 wallclock secs ( 3.88 usr 0.95 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Total time: 419 wallclock secs (10.58 usr 3.09 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results/create-mysql-Linux_2.2.1_i686-cmp-adabas,mysql b/sql-bench/Results/create-mysql-Linux_2.2.1_i686-cmp-adabas,mysql
new file mode 100644
index 00000000000..d422cb3078f
--- /dev/null
+++ b/sql-bench/Results/create-mysql-Linux_2.2.1_i686-cmp-adabas,mysql
@@ -0,0 +1,18 @@
+Testing server 'MySQL 3.22.18' at 1999-02-27 21:13:56
+
+Testing the speed of creating and droping tables
+All tests are done 1000 times
+
+Testing create of tables
+Time for create_table (1000): 3 wallclock secs ( 0.26 usr 0.03 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Accessing tables
+Time to select_group (1000): 1 wallclock secs ( 0.17 usr 0.02 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing drop
+Time for drop_table (1000): 1 wallclock secs ( 0.11 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing create+drop
+Time for create+drop (1000): 1 wallclock secs ( 0.34 usr 0.08 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for create_key+drop (1000): 2 wallclock secs ( 0.66 usr 0.04 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Total time: 8 wallclock secs ( 1.54 usr 0.17 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
diff --git a/sql-bench/Results/create-mysql-NT_4.0 b/sql-bench/Results/create-mysql-NT_4.0
new file mode 100644
index 00000000000..687a10e3664
--- /dev/null
+++ b/sql-bench/Results/create-mysql-NT_4.0
@@ -0,0 +1,18 @@
+Testing server 'MySQL 3.23.17a alpha' at 2000-06-02 17:41:14
+
+Testing the speed of creating and droping tables
+Testing with 10000 tables and 10000 loop count
+
+Testing create of tables
+Time for create_MANY_tables (10000): 232 wallclock secs ( 2.97 usr 1.23 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Accessing tables
+Time to select_group_when_MANY_tables (10000): 306 wallclock secs ( 1.09 usr 1.50 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing drop
+Time for drop_table_when_MANY_tables (10000): 223 wallclock secs ( 0.80 usr 1.34 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing create+drop
+Time for create+drop (10000): 123 wallclock secs ( 3.36 usr 2.61 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for create_key+drop (10000): 156 wallclock secs ( 5.13 usr 2.78 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Total time: 1040 wallclock secs (13.34 usr 9.47 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results/create-mysql-SunOS_5.5.1_sun4u b/sql-bench/Results/create-mysql-SunOS_5.5.1_sun4u
new file mode 100644
index 00000000000..b4f5bad6afa
--- /dev/null
+++ b/sql-bench/Results/create-mysql-SunOS_5.5.1_sun4u
@@ -0,0 +1,18 @@
+Testing server 'MySQL 3.22.19' at 1999-03-02 3:44:40
+
+Testing the speed of creating and droping tables
+All tests are done 1000 times
+
+Testing create of tables
+Time for create_table (1000): 22 wallclock secs ( 0.56 usr 0.17 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Accessing tables
+Time to select_group (1000): 1 wallclock secs ( 0.18 usr 0.18 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing drop
+Time for drop_table (1000): 10 wallclock secs ( 0.11 usr 0.12 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing create+drop
+Time for create+drop (1000): 22 wallclock secs ( 0.78 usr 0.32 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for create_key+drop (1000): 20 wallclock secs ( 1.12 usr 0.26 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Total time: 75 wallclock secs ( 2.76 usr 1.05 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results/create-mysql-SunOS_5.7_sun4m b/sql-bench/Results/create-mysql-SunOS_5.7_sun4m
new file mode 100644
index 00000000000..c1c58255862
--- /dev/null
+++ b/sql-bench/Results/create-mysql-SunOS_5.7_sun4m
@@ -0,0 +1,18 @@
+Testing server 'MySQL 3.22.20' at 1999-03-19 13:53:23
+
+Testing the speed of creating and droping tables
+All tests are done 1000 times
+
+Testing create of tables
+Time for create_table (1000): 95 secs ( 2.15 usr 1.01 sys + 0.00 cusr 0.00 csys = 3.16 cpu)
+
+Accessing tables
+Time to select_group (1000): 9 secs ( 0.92 usr 0.99 sys + 0.00 cusr 0.00 csys = 1.91 cpu)
+
+Testing drop
+Time for drop_table (1000): 47 secs ( 0.59 usr 0.75 sys + 0.00 cusr 0.00 csys = 1.34 cpu)
+
+Testing create+drop
+Time for create+drop (1000): 110 secs ( 2.56 usr 2.18 sys + 0.00 cusr 0.00 csys = 4.74 cpu)
+Time for create_key+drop (1000): 116 secs ( 5.71 usr 1.29 sys + 0.00 cusr 0.00 csys = 7.00 cpu)
+Total time: 377 secs (11.94 usr 6.22 sys + 0.00 cusr 0.00 csys = 18.16 cpu)
diff --git a/sql-bench/Results/create-mysql-SunOS_5.7_sun4u b/sql-bench/Results/create-mysql-SunOS_5.7_sun4u
new file mode 100644
index 00000000000..6f7eaa07f47
--- /dev/null
+++ b/sql-bench/Results/create-mysql-SunOS_5.7_sun4u
@@ -0,0 +1,18 @@
+Testing server 'MySQL 3.23.8 alpha' at 2000-01-17 21:19:48
+
+Testing the speed of creating and droping tables
+All tests are done 10000 times
+
+Testing create of tables
+Time for create_many_tables (10000): 1130 wallclock secs ( 2.65 usr 0.89 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Accessing tables
+Time to select_group (10000): 41 wallclock secs ( 0.88 usr 1.29 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing drop
+Time for drop_table (10000): 518 wallclock secs ( 0.60 usr 0.72 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing create+drop
+Time for create+drop (10000): 934 wallclock secs ( 2.88 usr 1.85 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for create_key+drop (10000): 1008 wallclock secs ( 3.17 usr 1.20 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Total time: 3631 wallclock secs (10.19 usr 5.95 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results/create-mysql-win98 b/sql-bench/Results/create-mysql-win98
new file mode 100644
index 00000000000..e0211664f23
--- /dev/null
+++ b/sql-bench/Results/create-mysql-win98
@@ -0,0 +1,18 @@
+Testing server 'MySQL 3.23.13a alpha' at 2000-03-15 2:33:13
+
+Testing the speed of creating and droping tables
+Testing with 5000 tables and 10000 loop count
+
+Testing create of tables
+Time for create_MANY_tables (5000): 1510 wallclock secs (1510.83 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Accessing tables
+Time to select_group_when_MANY_tables (5000): 581 wallclock secs (580.46 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing drop
+Time for drop_table_when_MANY_tables (5000): 160 wallclock secs (159.83 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing create+drop
+Time for create+drop (10000): 1433 wallclock secs (1433.28 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for create_key+drop (10000): 1457 wallclock secs (1456.57 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Total time: 5141 wallclock secs (5140.97 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results/create-mysql_3.21-Linux_2.0.35_i686 b/sql-bench/Results/create-mysql_3.21-Linux_2.0.35_i686
new file mode 100644
index 00000000000..3d16d0561af
--- /dev/null
+++ b/sql-bench/Results/create-mysql_3.21-Linux_2.0.35_i686
@@ -0,0 +1,18 @@
+Testing server 'MySQL 3.21.33' at 1998-08-21 12:10:41
+
+Testing the speed of creating and droping tables
+All tests are done 1000 times
+
+Testing create of tables
+Time for create_table (1000): 8 secs ( 0.30 usr 0.22 sys = 0.52 cpu)
+
+Accessing tables
+Time to select_group (1000): 5 secs ( 0.08 usr 0.18 sys = 0.26 cpu)
+
+Testing drop
+Time for drop_table (1000): 1 secs ( 0.02 usr 0.06 sys = 0.08 cpu)
+
+Testing create+drop
+Time for create+drop (1000): 3 secs ( 0.20 usr 0.31 sys = 0.51 cpu)
+Time for create_key+drop (1000): 3 secs ( 0.21 usr 0.45 sys = 0.66 cpu)
+Total time: 20 secs ( 0.81 usr 1.22 sys = 2.03 cpu)
diff --git a/sql-bench/Results/create-mysql_fast-Linux_2.2.10_i686-cmp-msql,mysql b/sql-bench/Results/create-mysql_fast-Linux_2.2.10_i686-cmp-msql,mysql
new file mode 100644
index 00000000000..925b9604b41
--- /dev/null
+++ b/sql-bench/Results/create-mysql_fast-Linux_2.2.10_i686-cmp-msql,mysql
@@ -0,0 +1,20 @@
+Testing server 'MySQL 3.23.3 alpha' at 1999-09-24 9:10:51
+
+Testing the speed of creating and droping tables
+All tests are done 1000 times
+
+Okay..Let's make sure that our tables don't exist yet.
+
+Testing create of tables
+Time for create_table (1000): 4 wallclock secs ( 0.39 usr 0.03 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Accessing tables
+Time to select (1000): 1 wallclock secs ( 0.26 usr 0.05 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing drop
+Time for drop_table (1000): 0 wallclock secs ( 0.02 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing create+drop
+Time for create+drop (1000): 2 wallclock secs ( 0.55 usr 0.04 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for create_key+drop (1000): 2 wallclock secs ( 0.62 usr 0.06 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Total time: 9 wallclock secs ( 1.85 usr 0.18 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results/create-mysql_odbc-win98 b/sql-bench/Results/create-mysql_odbc-win98
new file mode 100644
index 00000000000..c8e5ca1991a
--- /dev/null
+++ b/sql-bench/Results/create-mysql_odbc-win98
@@ -0,0 +1,18 @@
+Testing server 'MySQL 3.22.19a' at 1999-03-02 16:59:53
+
+Testing the speed of creating and droping tables
+All tests are done 1000 times
+
+Testing create of tables
+Time for create_table (1000): 50 wallclock secs (49.43 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Accessing tables
+Time to select_group (1000): 30 wallclock secs (30.27 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing drop
+Time for drop_table (1000): 9 wallclock secs ( 9.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing create+drop
+Time for create+drop (1000): 27 wallclock secs (26.86 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for create_key+drop (1000): 30 wallclock secs (30.16 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Total time: 146 wallclock secs (145.72 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results/create-oracle-Linux_2.0.36_i686-cmp-mysql,oracle b/sql-bench/Results/create-oracle-Linux_2.0.36_i686-cmp-mysql,oracle
new file mode 100644
index 00000000000..5457b19b297
--- /dev/null
+++ b/sql-bench/Results/create-oracle-Linux_2.0.36_i686-cmp-mysql,oracle
@@ -0,0 +1,20 @@
+Testing server 'Oracle 8.0.5.0.0' at 1999-03-25 0:40:16
+
+Testing the speed of creating and droping tables
+All tests are done 1000 times
+
+Okay..Let's make sure that our tables don't exist yet.
+
+Testing create of tables
+Time for create_table (1000): 86 wallclock secs ( 1.99 usr 0.18 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Accessing tables
+Time to select_group (1000): 8 wallclock secs ( 0.86 usr 0.08 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing drop
+Time for drop_table (1000): 77 wallclock secs ( 0.63 usr 0.08 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing create+drop
+Time for create+drop (1000): 202 wallclock secs ( 2.66 usr 0.31 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for create_key+drop (1000): 175 wallclock secs ( 3.33 usr 0.25 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Total time: 548 wallclock secs ( 9.48 usr 0.90 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
diff --git a/sql-bench/Results/create-oracle_fast-Linux_2.0.36_i686-cmp-mysql,oracle b/sql-bench/Results/create-oracle_fast-Linux_2.0.36_i686-cmp-mysql,oracle
new file mode 100644
index 00000000000..ee840d8f51a
--- /dev/null
+++ b/sql-bench/Results/create-oracle_fast-Linux_2.0.36_i686-cmp-mysql,oracle
@@ -0,0 +1,30 @@
+Testing server 'Oracle 8.0.5.0.0' at 1999-03-23 8:13:28
+
+Testing the speed of creating and droping tables
+All tests are done 1000 times
+
+Okay..Let's make sure that our tables don't exist yet.
+
+Time for book-keeping (1): 0 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing create of tables
+Time for create_table (1000): 103 wallclock secs ( 1.89 usr 0.18 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Time for book-keeping (1): 37 wallclock secs ( 1.55 usr 0.23 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Accessing tables
+Time to select_group (1000): 12 wallclock secs ( 0.89 usr 0.09 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing drop
+Time for drop_table (1000): 85 wallclock secs ( 0.70 usr 0.04 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Time for book-keeping (1): 0 wallclock secs ( 0.01 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing create+drop
+Time for create+drop (1000): 198 wallclock secs ( 2.72 usr 0.37 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for book-keeping (1): 0 wallclock secs ( 0.01 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Time for create_key+drop (1000): 174 wallclock secs ( 3.64 usr 0.28 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for book-keeping (1): 0 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Total time: 611 wallclock secs (11.43 usr 1.28 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
diff --git a/sql-bench/Results/create-pg-Linux_2.0.36_i686-cmp-mysql,pg,solid b/sql-bench/Results/create-pg-Linux_2.0.36_i686-cmp-mysql,pg,solid
new file mode 100644
index 00000000000..6c8a3e9b39e
--- /dev/null
+++ b/sql-bench/Results/create-pg-Linux_2.0.36_i686-cmp-mysql,pg,solid
@@ -0,0 +1,56 @@
+Testing server 'PostgreSQL 6.4' at 1999-03-09 19:27:59
+
+Testing the speed of creating and droping tables
+All tests are done 1000 times
+
+Okay..Let's make sure that our tables don't exist yet.
+
+Testing create of tables
+Time for create_table (1000): 67 wallclock secs ( 1.51 usr 0.10 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Accessing tables
+Time to select_group (1000): 5 wallclock secs ( 0.62 usr 0.03 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing drop
+NOTICE: trying to delete a reldesc that does not exist.
+NOTICE: trying to delete a reldesc that does not exist.
+NOTICE: trying to delete a reldesc that does not exist.
+NOTICE: trying to delete a reldesc that does not exist.
+NOTICE: trying to delete a reldesc that does not exist.
+NOTICE: trying to delete a reldesc that does not exist.
+NOTICE: trying to delete a reldesc that does not exist.
+NOTICE: trying to delete a reldesc that does not exist.
+NOTICE: trying to delete a reldesc that does not exist.
+NOTICE: trying to delete a reldesc that does not exist.
+NOTICE: trying to delete a reldesc that does not exist.
+NOTICE: trying to delete a reldesc that does not exist.
+NOTICE: trying to delete a reldesc that does not exist.
+NOTICE: trying to delete a reldesc that does not exist.
+NOTICE: trying to delete a reldesc that does not exist.
+NOTICE: trying to delete a reldesc that does not exist.
+NOTICE: trying to delete a reldesc that does not exist.
+NOTICE: trying to delete a reldesc that does not exist.
+NOTICE: trying to delete a reldesc that does not exist.
+NOTICE: trying to delete a reldesc that does not exist.
+NOTICE: trying to delete a reldesc that does not exist.
+NOTICE: trying to delete a reldesc that does not exist.
+NOTICE: trying to delete a reldesc that does not exist.
+NOTICE: trying to delete a reldesc that does not exist.
+NOTICE: trying to delete a reldesc that does not exist.
+NOTICE: trying to delete a reldesc that does not exist.
+NOTICE: trying to delete a reldesc that does not exist.
+NOTICE: trying to delete a reldesc that does not exist.
+NOTICE: trying to delete a reldesc that does not exist.
+NOTICE: trying to delete a reldesc that does not exist.
+NOTICE: trying to delete a reldesc that does not exist.
+NOTICE: trying to delete a reldesc that does not exist.
+NOTICE: trying to delete a reldesc that does not exist.
+NOTICE: trying to delete a reldesc that does not exist.
+NOTICE: trying to delete a reldesc that does not exist.
+NOTICE: trying to delete a reldesc that does not exist.
+Time for drop_table (1000): 17 wallclock secs ( 0.59 usr 0.03 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing create+drop
+Time for create+drop (1000): 46 wallclock secs ( 1.86 usr 0.23 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for create_key+drop (1000): 33 wallclock secs ( 1.56 usr 0.14 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Total time: 168 wallclock secs ( 6.14 usr 0.53 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
diff --git a/sql-bench/Results/create-pg_fast-Linux_2.0.36_i686-cmp-mysql,pg,solid b/sql-bench/Results/create-pg_fast-Linux_2.0.36_i686-cmp-mysql,pg,solid
new file mode 100644
index 00000000000..481c68fa0ec
--- /dev/null
+++ b/sql-bench/Results/create-pg_fast-Linux_2.0.36_i686-cmp-mysql,pg,solid
@@ -0,0 +1,60 @@
+Testing server 'PostgreSQL 6.4' at 1999-03-11 7:38:51
+
+Testing the speed of creating and droping tables
+All tests are done 1000 times
+
+Okay..Let's make sure that our tables don't exist yet.
+
+Time for book-keeping (1): 0 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing create of tables
+Time for create_table (1000): 67 wallclock secs ( 1.40 usr 0.14 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Time for book-keeping (1): 14 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Accessing tables
+Time to select_group (1000): 5 wallclock secs ( 0.53 usr 0.14 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing drop
+NOTICE: trying to delete a reldesc that does not exist.
+NOTICE: trying to delete a reldesc that does not exist.
+NOTICE: trying to delete a reldesc that does not exist.
+NOTICE: trying to delete a reldesc that does not exist.
+NOTICE: trying to delete a reldesc that does not exist.
+NOTICE: trying to delete a reldesc that does not exist.
+NOTICE: trying to delete a reldesc that does not exist.
+NOTICE: trying to delete a reldesc that does not exist.
+NOTICE: trying to delete a reldesc that does not exist.
+NOTICE: trying to delete a reldesc that does not exist.
+NOTICE: trying to delete a reldesc that does not exist.
+NOTICE: trying to delete a reldesc that does not exist.
+NOTICE: trying to delete a reldesc that does not exist.
+NOTICE: trying to delete a reldesc that does not exist.
+NOTICE: trying to delete a reldesc that does not exist.
+NOTICE: trying to delete a reldesc that does not exist.
+NOTICE: trying to delete a reldesc that does not exist.
+NOTICE: trying to delete a reldesc that does not exist.
+NOTICE: trying to delete a reldesc that does not exist.
+NOTICE: trying to delete a reldesc that does not exist.
+NOTICE: trying to delete a reldesc that does not exist.
+NOTICE: trying to delete a reldesc that does not exist.
+NOTICE: trying to delete a reldesc that does not exist.
+NOTICE: trying to delete a reldesc that does not exist.
+NOTICE: trying to delete a reldesc that does not exist.
+NOTICE: trying to delete a reldesc that does not exist.
+NOTICE: trying to delete a reldesc that does not exist.
+NOTICE: trying to delete a reldesc that does not exist.
+NOTICE: trying to delete a reldesc that does not exist.
+NOTICE: trying to delete a reldesc that does not exist.
+Time for drop_table (1000): 16 wallclock secs ( 0.57 usr 0.12 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Time for book-keeping (1): 28 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing create+drop
+Time for create+drop (1000): 36 wallclock secs ( 2.08 usr 0.26 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for book-keeping (1): 75 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Time for create_key+drop (1000): 16 wallclock secs ( 1.32 usr 0.09 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for book-keeping (1): 131 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Total time: 388 wallclock secs ( 5.92 usr 0.76 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
diff --git a/sql-bench/Results/create-solid-Linux_2.0.36_i686-cmp-mysql,pg,solid b/sql-bench/Results/create-solid-Linux_2.0.36_i686-cmp-mysql,pg,solid
new file mode 100644
index 00000000000..f93324a1baf
--- /dev/null
+++ b/sql-bench/Results/create-solid-Linux_2.0.36_i686-cmp-mysql,pg,solid
@@ -0,0 +1,20 @@
+Testing server 'SOLID Server - v.02.30.0026 (Linux ix86)' at 1999-03-06 13:03:51
+
+Testing the speed of creating and droping tables
+All tests are done 1000 times
+
+Okay..Let's make sure that our tables don't exist yet.
+
+Testing create of tables
+Time for create_table (1000): 9 wallclock secs ( 1.30 usr 0.05 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Accessing tables
+Time to select_group (1000): 4 wallclock secs ( 0.90 usr 0.12 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing drop
+Time for drop_table (1000): 8 wallclock secs ( 0.68 usr 0.09 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing create+drop
+Time for create+drop (1000): 18 wallclock secs ( 2.08 usr 0.19 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for create_key+drop (1000): 20 wallclock secs ( 2.03 usr 0.15 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Total time: 59 wallclock secs ( 7.00 usr 0.60 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
diff --git a/sql-bench/Results/insert-Adabas-Linux_2.0.35_i686-cmp-adabas,mysql b/sql-bench/Results/insert-Adabas-Linux_2.0.35_i686-cmp-adabas,mysql
new file mode 100644
index 00000000000..c190337a8dd
--- /dev/null
+++ b/sql-bench/Results/insert-Adabas-Linux_2.0.35_i686-cmp-adabas,mysql
@@ -0,0 +1,63 @@
+Testing server 'Adabas 10.01.00' at 1998-09-24 12:13:15
+
+Testing the speed of inserting data into 1 table and do some selects on it.
+The tests are done with a table that has 10000 rows.
+
+Generating random keys
+Creating tables
+Inserting 10000 rows in order
+Inserting 10000 rows in reverse order
+Inserting 10000 rows in random order
+Time for insert (30000): 733 secs (22.19 usr 6.46 sys = 28.65 cpu)
+
+Testing insert of duplicates
+Time for insert_duplicates (30000): 9 secs ( 3.57 usr 3.81 sys = 7.38 cpu)
+
+Retrieving data from the table
+Time for select_big (10:300000): 41 secs (14.31 usr 10.02 sys = 24.33 cpu)
+Time for order_by_key (10:300000): 48 secs (13.45 usr 11.16 sys = 24.61 cpu)
+Time for order_by (10:300000): 54 secs (12.73 usr 11.78 sys = 24.51 cpu)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+1740 queries in 1740 loops of 5000 loops took 602 seconds
+Estimated time for select_range_prefix (5000:14616): 1729 secs ( 7.39 usr 12.30 sys = 19.68 cpu)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+690 queries in 690 loops of 5000 loops took 612 seconds
+Estimated time for select_range (5000:5796): 4434 secs ( 7.54 usr 13.55 sys = 21.09 cpu)
+Time for select_key_prefix (20000): 79 secs (11.74 usr 21.54 sys = 33.28 cpu)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+7302 queries in 3651 loops of 10000 loops took 601 seconds
+Estimated time for select_key (20000): 1646 secs (16.74 usr 27.42 sys = 44.15 cpu)
+
+Test of compares with simple ranges
+Time for select_range_prefix (20000:43500): 53 secs ( 7.34 usr 14.13 sys = 21.47 cpu)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+5280 queries in 132 loops of 500 loops took 603 seconds
+Estimated time for select_range (20000:11484): 603 secs ( 2.41 usr 4.34 sys = 6.75 cpu)
+Time for select_group (101): 91 secs ( 0.12 usr 0.17 sys = 0.29 cpu)
+Time for min_max_on_key (3000): 12 secs ( 1.31 usr 3.39 sys = 4.70 cpu)
+Time for min_max (60): 40 secs ( 0.09 usr 0.09 sys = 0.18 cpu)
+Time for count_on_key (100): 102 secs ( 0.10 usr 0.12 sys = 0.22 cpu)
+Time for count (100): 107 secs ( 0.11 usr 0.12 sys = 0.23 cpu)
+
+Testing update with functions
+Time for update_key (500): 51 secs ( 0.32 usr 0.40 sys = 0.72 cpu)
+Time for update_key_big (480): 77 secs ( 0.29 usr 0.33 sys = 0.62 cpu)
+
+Testing delete
+Time for delete_key (500): 48 secs ( 0.39 usr 0.35 sys = 0.74 cpu)
+Time for delete_big (12): 8 secs ( 0.02 usr 0.01 sys = 0.03 cpu)
+
+Insert into table with 16 keys and with a primary key with 16 parts
+Time for insert_key (10000): 241 secs ( 8.58 usr 2.07 sys = 10.65 cpu)
+
+Testing update of keys
+Time for update_of_key (256): 17 secs ( 0.10 usr 0.16 sys = 0.26 cpu)
+
+Deleting everything from table
+Time for delete_big (2): 4 secs ( 0.00 usr 0.00 sys = 0.00 cpu)
+
+Estimated total time: 11695 secs ( 249.00 463.00 713.00)
diff --git a/sql-bench/Results/insert-msql-Linux_2.2.10_i686-cmp-msql,mysql b/sql-bench/Results/insert-msql-Linux_2.2.10_i686-cmp-msql,mysql
new file mode 100644
index 00000000000..48b3ece2180
--- /dev/null
+++ b/sql-bench/Results/insert-msql-Linux_2.2.10_i686-cmp-msql,mysql
@@ -0,0 +1,67 @@
+Testing server 'mSQL server version 2.0.10' at 1999-09-23 8:59:18
+
+Testing the speed of inserting data into 1 table and do some selects on it.
+The tests are done with a table that has 100000 rows.
+
+Generating random keys
+Creating tables
+Inserting 100000 rows in order
+Inserting 100000 rows in reverse order
+Inserting 100000 rows in random order
+Time for insert (300000): 105 wallclock secs (37.17 usr 6.05 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing insert of duplicates
+Time for insert_duplicates (300000): 20 wallclock secs ( 7.44 usr 1.70 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Retrieving data from the table
+Time for select_big (10:3000000): 106 wallclock secs (63.07 usr 14.60 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for order_by_key (10:3000000): 138 wallclock secs (62.91 usr 14.50 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for order_by (10:3000000): 137 wallclock secs (62.94 usr 14.03 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_diff_key (500:1000): 143 wallclock secs ( 0.52 usr 0.04 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+290 queries in 290 loops of 5000 loops took 602 seconds
+Estimated time for select_range_prefix (5000:3654): 10379 wallclock secs ( 7.41 usr 0.69 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+300 queries in 300 loops of 5000 loops took 610 seconds
+Estimated time for select_range (5000:3780): 10166 wallclock secs ( 7.83 usr 0.67 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+3034 queries in 1517 loops of 100000 loops took 601 seconds
+Estimated time for select_key_prefix (200000): 39617 wallclock secs (190.51 usr 18.46 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_key (200000): 244 wallclock secs (177.74 usr 12.56 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Test of compares with simple ranges
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+2240 queries in 56 loops of 500 loops took 603 seconds
+Estimated time for select_range_prefix (20000:4872): 5383 wallclock secs ( 9.46 usr 1.61 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+2200 queries in 55 loops of 500 loops took 602 seconds
+Estimated time for select_range (20000:4785): 5472 wallclock secs (10.27 usr 0.64 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing update of keys in loops
+Time for update_of_key (599999): 220 wallclock secs (104.21 usr 15.51 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing update with key
+Time for update_with_key (100000): 57942 wallclock secs (46.67 usr 8.71 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing update of all rows
+Time for update_big (500): 73 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing delete
+Time for delete_key (500): 1 wallclock secs ( 0.05 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for delete_big (12): 10 wallclock secs ( 0.01 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Insert into table with 5 keys and with a primary key with 5 parts
+Time for insert_key (100000): 40 wallclock secs (12.67 usr 2.51 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing update of keys
+Time for update_of_key (256): 634 wallclock secs ( 0.04 usr 0.02 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Deleting everything from table
+Time for delete_big_many_keys (2): 676 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Estimated total time: 131515 wallclock secs (800.98 usr 112.30 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results/insert-mysql-3.21-Linux_2.2.1_i686 b/sql-bench/Results/insert-mysql-3.21-Linux_2.2.1_i686
new file mode 100644
index 00000000000..7285139393a
--- /dev/null
+++ b/sql-bench/Results/insert-mysql-3.21-Linux_2.2.1_i686
@@ -0,0 +1,51 @@
+Testing server 'MySQL 3.21.34' at 1999-02-28 16:02:51
+
+Testing the speed of inserting data into 1 table and do some selects on it.
+The tests are done with a table that has 100000 rows.
+
+Generating random keys
+Creating tables
+Inserting 100000 rows in order
+Inserting 100000 rows in reverse order
+Inserting 100000 rows in random order
+Time for insert (300000): 128 wallclock secs (30.13 usr 10.46 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing insert of duplicates
+Time for insert_duplicates (300000): 26 wallclock secs ( 6.84 usr 3.72 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Retrieving data from the table
+Time for select_big (10:3000000): 53 wallclock secs (28.53 usr 15.67 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for order_by_key (10:3000000): 71 wallclock secs (28.30 usr 20.45 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for order_by (10:3000000): 71 wallclock secs (28.62 usr 19.26 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for select_range_prefix (5010:42084): 24 wallclock secs ( 3.65 usr 0.79 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for select_range (5010:42084): 15 wallclock secs ( 3.70 usr 0.90 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for select_key_prefix (200000): 247 wallclock secs (94.75 usr 12.42 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for select_key (200000): 213 wallclock secs (109.13 usr 13.71 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Test of compares with simple ranges
+Time for select_range_prefix (20000:43500): 14 wallclock secs ( 6.53 usr 0.91 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for select_range (20000:43500): 14 wallclock secs ( 5.80 usr 0.72 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for select_group (111): 80 wallclock secs ( 0.12 usr 0.02 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for min_max_on_key (3000): 395 wallclock secs ( 1.64 usr 0.18 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for min_max (60): 23 wallclock secs ( 0.04 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for count_on_key (100): 37 wallclock secs ( 0.06 usr 0.01 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for count (100): 61 wallclock secs ( 0.09 usr 0.03 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing update with functions
+Time for update_key (500): 0 wallclock secs ( 0.05 usr 0.03 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for update_key_big (501): 52 wallclock secs ( 0.04 usr 0.01 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing delete
+Time for delete_key (500): 12 wallclock secs ( 0.02 usr 0.02 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for delete_big (12): 72 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Insert into table with 16 keys and with a primary key with 16 parts
+Time for insert_key (100000): 157 wallclock secs (14.40 usr 3.85 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing update of keys
+Time for update_of_key (256): 72 wallclock secs ( 0.03 usr 0.03 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Deleting everything from table
+Time for delete_big (2): 133 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Total time: 1971 wallclock secs (362.50 usr 103.19 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
diff --git a/sql-bench/Results/insert-mysql-HP_UX_B.10.20_9000_778 b/sql-bench/Results/insert-mysql-HP_UX_B.10.20_9000_778
new file mode 100644
index 00000000000..03e2ea3f5f2
--- /dev/null
+++ b/sql-bench/Results/insert-mysql-HP_UX_B.10.20_9000_778
@@ -0,0 +1,81 @@
+Testing server 'MySQL 3.23.4 alpha' at 1999-09-27 15:49:14
+
+Testing the speed of inserting data into 1 table and do some selects on it.
+The tests are done with a table that has 100000 rows.
+
+Generating random keys
+Creating tables
+Inserting 100000 rows in order
+Inserting 100000 rows in reverse order
+Inserting 100000 rows in random order
+Time for insert (300000): 327 wallclock secs (44.25 usr 20.12 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing insert of duplicates
+Time for insert_duplicates (300000): 50 wallclock secs (10.92 usr 5.91 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Retrieving data from the table
+Time for select_big (10:3000000): 268 wallclock secs (81.97 usr 82.93 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for order_by_key (10:3000000): 265 wallclock secs (81.83 usr 80.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for order_by (10:3000000): 359 wallclock secs (81.85 usr 62.84 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+291 queries in 291 loops of 10 loops took 602 seconds
+Estimated time for select_diff_key (10:582): 20 wallclock secs ( 0.01 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_range_prefix (5010:42084): 50 wallclock secs ( 9.27 usr 2.15 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_range (5010:42084): 49 wallclock secs ( 9.30 usr 2.16 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+179500 queries in 89750 loops of 100000 loops took 601 seconds
+Estimated time for select_key_prefix (200000): 669 wallclock secs (217.48 usr 41.21 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+179928 queries in 89964 loops of 100000 loops took 601 seconds
+Estimated time for select_key (200000): 668 wallclock secs (218.05 usr 41.63 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Test of compares with simple ranges
+Time for select_range_prefix (20000:43500): 41 wallclock secs (12.07 usr 2.53 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_range (20000:43500): 40 wallclock secs (12.06 usr 2.53 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_group (111): 194 wallclock secs ( 0.14 usr 0.03 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for min_max_on_key (3000): 6 wallclock secs ( 2.75 usr 0.47 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for min_max (60): 111 wallclock secs ( 0.07 usr 0.01 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for count_on_key (100): 156 wallclock secs ( 0.12 usr 0.02 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for count (100): 321 wallclock secs ( 0.11 usr 0.01 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing update of keys with functions
+Time for update_of_key (500): 1 wallclock secs ( 0.10 usr 0.03 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for update_of_key_big (501): 85 wallclock secs ( 0.09 usr 0.04 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing update with key
+Time for update_with_key (100000): 681 wallclock secs (52.02 usr 22.51 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing update of all rows
+Time for update_big (500): 148 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing left outer join
+Time for outer_join_on_key (10:10): 165 wallclock secs ( 0.02 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for outer_join (10:10): 414 wallclock secs ( 0.01 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for outer_join_found (10:10): 396 wallclock secs ( 0.01 usr 0.01 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+31 queries in 30 loops of 500 loops took 605 seconds
+Estimated time for outer_join_not_found (500:516): 605 wallclock secs ( 0.04 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing delete
+Time for delete_key (500): 1 wallclock secs ( 0.10 usr 0.04 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for delete_big (12): 46 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Insert into table with 16 keys and with a primary key with 16 parts
+Time for insert_key (100000): 419 wallclock secs (35.34 usr 7.55 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing update of keys
+Time for update_of_key (256): 169 wallclock secs ( 0.05 usr 0.03 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Deleting everything from table
+Time for delete_big_many_keys (2): 302 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Inserting 100000 rows with multiple values
+Time for multiple_value_insert (100000): 22 wallclock secs ( 3.75 usr 0.02 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Time for drop table(1): 0 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Estimated total time: 16527 wallclock secs (874.45 usr 374.80 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results/insert-mysql-Linux_2.0.35_i686-cmp-adabas,mysql b/sql-bench/Results/insert-mysql-Linux_2.0.35_i686-cmp-adabas,mysql
new file mode 100644
index 00000000000..878c0d16a7c
--- /dev/null
+++ b/sql-bench/Results/insert-mysql-Linux_2.0.35_i686-cmp-adabas,mysql
@@ -0,0 +1,51 @@
+Testing server 'MySQL 3.22.9 beta' at 1998-10-20 6:58:58
+
+Testing the speed of inserting data into 1 table and do some selects on it.
+The tests are done with a table that has 10000 rows.
+
+Generating random keys
+Creating tables
+Inserting 10000 rows in order
+Inserting 10000 rows in reverse order
+Inserting 10000 rows in random order
+Time for insert (30000): 17 secs ( 2.03 usr 2.84 sys = 4.87 cpu)
+
+Testing insert of duplicates
+Time for insert_duplicates (30000): 4 secs ( 0.00 usr 1.39 sys = 1.39 cpu)
+
+Retrieving data from the table
+Time for select_big (10:300000): 6 secs ( 2.08 usr 4.11 sys = 6.19 cpu)
+Time for order_by_key (10:300000): 6 secs ( 1.44 usr 4.75 sys = 6.19 cpu)
+Time for order_by (10:300000): 10 secs ( 2.24 usr 6.64 sys = 8.88 cpu)
+Time for select_range_prefix (5010:42084): 24 secs ( 1.10 usr 5.05 sys = 6.15 cpu)
+Time for select_range (5010:42084): 17 secs ( 1.39 usr 4.77 sys = 6.16 cpu)
+Time for select_key_prefix (20000): 27 secs ( 6.22 usr 11.03 sys = 17.25 cpu)
+Time for select_key (20000): 25 secs ( 5.64 usr 11.36 sys = 17.00 cpu)
+
+Test of compares with simple ranges
+Time for select_range_prefix (20000:43500): 16 secs ( 3.30 usr 6.08 sys = 9.38 cpu)
+Time for select_range (20000:43500): 15 secs ( 3.32 usr 6.80 sys = 10.12 cpu)
+Time for select_group (101): 5 secs ( 0.01 usr 0.08 sys = 0.09 cpu)
+Time for min_max_on_key (3000): 3 secs ( 0.79 usr 1.31 sys = 2.10 cpu)
+Time for min_max (60): 4 secs ( 0.00 usr 0.08 sys = 0.08 cpu)
+Time for count_on_key (100): 6 secs ( 0.00 usr 0.06 sys = 0.06 cpu)
+Time for count (100): 7 secs ( 0.01 usr 0.06 sys = 0.07 cpu)
+
+Testing update with functions
+Time for update_key (500): 1 secs ( 0.05 usr 0.07 sys = 0.12 cpu)
+Time for update_key_big (480): 4 secs ( 0.03 usr 0.04 sys = 0.07 cpu)
+
+Testing delete
+Time for delete_key (500): 0 secs ( 0.00 usr 0.04 sys = 0.04 cpu)
+Time for delete_big (12): 2 secs ( 0.01 usr 0.01 sys = 0.02 cpu)
+
+Insert into table with 16 keys and with a primary key with 16 parts
+Time for insert_key (10000): 15 secs ( 0.72 usr 1.30 sys = 2.02 cpu)
+
+Testing update of keys
+Time for update_of_key (256): 7 secs ( 0.02 usr 0.04 sys = 0.06 cpu)
+
+Deleting everything from table
+Time for delete_big (2): 8 secs ( 0.00 usr 0.00 sys = 0.00 cpu)
+
+Total time: 229 secs (30.40 usr 67.93 sys = 98.33 cpu)
diff --git a/sql-bench/Results/insert-mysql-Linux_2.0.36_i686-cmp-mysql,pg,solid b/sql-bench/Results/insert-mysql-Linux_2.0.36_i686-cmp-mysql,pg,solid
new file mode 100644
index 00000000000..0543275819c
--- /dev/null
+++ b/sql-bench/Results/insert-mysql-Linux_2.0.36_i686-cmp-mysql,pg,solid
@@ -0,0 +1,51 @@
+Testing server 'MySQL 3.22.18' at 1999-03-07 23:00:52
+
+Testing the speed of inserting data into 1 table and do some selects on it.
+The tests are done with a table that has 100000 rows.
+
+Generating random keys
+Creating tables
+Inserting 100000 rows in order
+Inserting 100000 rows in reverse order
+Inserting 100000 rows in random order
+Time for insert (300000): 140 wallclock secs (36.53 usr 8.29 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing insert of duplicates
+Time for insert_duplicates (300000): 18 wallclock secs ( 5.06 usr 2.17 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Retrieving data from the table
+Time for select_big (10:3000000): 49 wallclock secs (23.21 usr 11.90 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for order_by_key (10:3000000): 50 wallclock secs (23.37 usr 12.37 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for order_by (10:3000000): 73 wallclock secs (23.18 usr 12.42 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for select_range_prefix (5010:42084): 22 wallclock secs ( 4.13 usr 0.60 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for select_range (5010:42084): 14 wallclock secs ( 4.31 usr 0.65 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for select_key_prefix (200000): 242 wallclock secs (115.60 usr 13.94 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for select_key (200000): 230 wallclock secs (115.25 usr 13.94 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Test of compares with simple ranges
+Time for select_range_prefix (20000:43500): 13 wallclock secs ( 5.90 usr 0.81 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for select_range (20000:43500): 13 wallclock secs ( 5.96 usr 0.80 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for select_group (101): 30 wallclock secs ( 0.03 usr 0.01 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for min_max_on_key (3000): 2 wallclock secs ( 0.99 usr 0.13 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for min_max (60): 27 wallclock secs ( 0.02 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for count_on_key (100): 48 wallclock secs ( 0.04 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for count (100): 59 wallclock secs ( 0.08 usr 0.01 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing update with functions
+Time for update_key (500): 4 wallclock secs ( 0.07 usr 0.02 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for update_key_big (501): 27 wallclock secs ( 0.06 usr 0.01 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing delete
+Time for delete_key (500): 10 wallclock secs ( 0.11 usr 0.02 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for delete_big (12): 25 wallclock secs ( 0.01 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Insert into table with 7 keys and with a primary key with 7 parts
+Time for insert_key (100000): 165 wallclock secs (12.53 usr 3.21 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing update of keys
+Time for update_of_key (256): 83 wallclock secs ( 0.02 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Deleting everything from table
+Time for delete_big (2): 41 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Total time: 1389 wallclock secs (376.47 usr 81.30 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
diff --git a/sql-bench/Results/insert-mysql-Linux_2.2.10_i686 b/sql-bench/Results/insert-mysql-Linux_2.2.10_i686
new file mode 100644
index 00000000000..4d48a8fcf83
--- /dev/null
+++ b/sql-bench/Results/insert-mysql-Linux_2.2.10_i686
@@ -0,0 +1,72 @@
+Testing server 'MySQL 3.23.3 alpha' at 1999-09-17 8:46:31
+
+Testing the speed of inserting data into 1 table and do some selects on it.
+The tests are done with a table that has 100000 rows.
+
+Generating random keys
+Creating tables
+Inserting 100000 rows in order
+Inserting 100000 rows in reverse order
+Inserting 100000 rows in random order
+Time for insert (300000): 148 wallclock secs (45.77 usr 8.55 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing insert of duplicates
+Time for insert_duplicates (300000): 16 wallclock secs ( 5.74 usr 1.67 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Retrieving data from the table
+Time for select_big (10:3000000): 68 wallclock secs (46.81 usr 8.02 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for order_by_key (10:3000000): 69 wallclock secs (46.84 usr 7.93 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for order_by (10:3000000): 90 wallclock secs (46.67 usr 8.04 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_diff_key (500:1000): 305 wallclock secs ( 0.55 usr 0.02 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_range_prefix (5010:42084): 20 wallclock secs ( 5.91 usr 0.57 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_range (5010:42084): 20 wallclock secs ( 6.05 usr 0.51 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_key_prefix (200000): 406 wallclock secs (175.76 usr 12.40 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_key (200000): 401 wallclock secs (164.79 usr 11.47 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Test of compares with simple ranges
+Time for select_range_prefix (20000:43500): 22 wallclock secs ( 9.32 usr 0.73 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_range (20000:43500): 22 wallclock secs ( 9.27 usr 0.61 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_group (111): 58 wallclock secs ( 0.11 usr 0.02 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for min_max_on_key (3000): 4 wallclock secs ( 2.23 usr 0.20 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for min_max (60): 37 wallclock secs ( 0.04 usr 0.01 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for count_on_key (100): 52 wallclock secs ( 0.16 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for count (100): 73 wallclock secs ( 0.08 usr 0.02 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing update of keys with functions
+Time for update_of_key (500): 1 wallclock secs ( 0.08 usr 0.03 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for update_of_key_big (501): 29 wallclock secs ( 0.08 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing update with key
+Time for update_with_key (100000): 381 wallclock secs (57.20 usr 11.84 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing update of all rows
+Time for update_big (500): 34 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing left outer join
+Time for outer_join_on_key (10:10): 65 wallclock secs ( 0.02 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for outer_join (10:10): 84 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for outer_join_found (10:10): 82 wallclock secs ( 0.01 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+102 queries in 101 loops of 500 loops took 605 seconds
+Estimated time for outer_join_not_found (500:504): 605 wallclock secs ( 0.13 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing delete
+Time for delete_key (500): 1 wallclock secs ( 0.12 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for delete_big (12): 20 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Insert into table with 16 keys and with a primary key with 16 parts
+Time for insert_key (100000): 209 wallclock secs (21.42 usr 3.48 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing update of keys
+Time for update_of_key (256): 60 wallclock secs ( 0.03 usr 0.03 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Deleting everything from table
+Time for delete_big_many_keys (2): 257 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Inserting 100000 rows with multiple values
+Time for multiple_value_insert (100000): 9 wallclock secs ( 2.46 usr 0.02 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Time for drop table(1): 0 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Estimated total time: 6039 wallclock secs (648.24 usr 76.17 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results/insert-mysql-Linux_2.2.10_i686-cmp-msql,mysql b/sql-bench/Results/insert-mysql-Linux_2.2.10_i686-cmp-msql,mysql
new file mode 100644
index 00000000000..49f5ecdf760
--- /dev/null
+++ b/sql-bench/Results/insert-mysql-Linux_2.2.10_i686-cmp-msql,mysql
@@ -0,0 +1,56 @@
+Testing server 'MySQL 3.23.3 alpha' at 1999-09-24 9:51:46
+
+Testing the speed of inserting data into 1 table and do some selects on it.
+The tests are done with a table that has 100000 rows.
+
+Generating random keys
+Creating tables
+Inserting 100000 rows in order
+Inserting 100000 rows in reverse order
+Inserting 100000 rows in random order
+Time for insert (300000): 145 wallclock secs (45.22 usr 7.48 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing insert of duplicates
+Time for insert_duplicates (300000): 18 wallclock secs ( 6.67 usr 2.24 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Retrieving data from the table
+Time for select_big (10:3000000): 68 wallclock secs (46.86 usr 8.02 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for order_by_key (10:3000000): 69 wallclock secs (47.13 usr 7.95 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for order_by (10:3000000): 90 wallclock secs (46.72 usr 8.08 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_diff_key (500:1000): 305 wallclock secs ( 0.59 usr 0.01 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_range_prefix (5000:63000): 19 wallclock secs ( 5.62 usr 0.47 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_range (5000:63000): 18 wallclock secs ( 5.57 usr 0.57 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_key_prefix (200000): 404 wallclock secs (172.53 usr 12.29 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_key (200000): 402 wallclock secs (154.50 usr 10.45 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Test of compares with simple ranges
+Time for select_range_prefix (20000:43500): 22 wallclock secs ( 9.15 usr 0.69 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_range (20000:43500): 21 wallclock secs ( 9.26 usr 0.80 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing update of keys in loops
+note: Aborting update loop because of timeout
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+548951 queries in 548951 loops of 600000 loops took 1194 seconds
+Estimated time for update_of_key (600000): 1305 wallclock secs (160.80 usr 25.83 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing update with key
+Time for update_with_key (100000): 381 wallclock secs (62.03 usr 12.20 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing update of all rows
+Time for update_big (500): 50 wallclock secs ( 0.00 usr 0.01 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing delete
+Time for delete_key (500): 1 wallclock secs ( 0.16 usr 0.01 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for delete_big (12): 20 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Insert into table with 5 keys and with a primary key with 5 parts
+Time for insert_key (100000): 80 wallclock secs (15.22 usr 2.82 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing update of keys
+Time for update_of_key (256): 31 wallclock secs ( 0.03 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Deleting everything from table
+Time for delete_big_many_keys (2): 35 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Estimated total time: 3485 wallclock secs (788.07 usr 99.92 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results/insert-mysql-Linux_2.2.14_i686_xeon b/sql-bench/Results/insert-mysql-Linux_2.2.14_i686_xeon
new file mode 100644
index 00000000000..fc370ae0e21
--- /dev/null
+++ b/sql-bench/Results/insert-mysql-Linux_2.2.14_i686_xeon
@@ -0,0 +1,70 @@
+Testing server 'MySQL 3.23.17 alpha' at 2000-06-01 3:20:52
+
+Testing the speed of inserting data into 1 table and do some selects on it.
+The tests are done with a table that has 100000 rows.
+
+Generating random keys
+Creating tables
+Inserting 100000 rows in order
+Inserting 100000 rows in reverse order
+Inserting 100000 rows in random order
+Time for insert (300000): 93 wallclock secs (17.97 usr 8.51 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing insert of duplicates
+Time for insert_duplicates (300000): 14 wallclock secs ( 3.03 usr 3.14 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Retrieving data from the table
+Time for select_big (10:3000000): 31 wallclock secs (20.53 usr 10.03 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for order_by_key (10:3000000): 30 wallclock secs (20.22 usr 10.11 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for order_by (10:3000000): 47 wallclock secs (20.41 usr 15.62 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_diff_key (500:1000): 174 wallclock secs ( 0.28 usr 0.03 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_range_prefix (5010:42084): 10 wallclock secs ( 2.73 usr 0.64 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_range (5010:42084): 10 wallclock secs ( 2.73 usr 0.58 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_key_prefix (200000): 130 wallclock secs (66.91 usr 10.48 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_key (200000): 128 wallclock secs (66.75 usr 11.61 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Test of compares with simple ranges
+Time for select_range_prefix (20000:43500): 8 wallclock secs ( 3.10 usr 0.74 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_range (20000:43500): 8 wallclock secs ( 3.45 usr 0.82 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_group (111): 52 wallclock secs ( 0.05 usr 0.04 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for min_max_on_key (15000): 9 wallclock secs ( 4.75 usr 0.64 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for min_max (60): 29 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for count_on_key (100): 51 wallclock secs ( 0.06 usr 0.02 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for count (100): 42 wallclock secs ( 0.10 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for count_distinct_big (20): 62 wallclock secs ( 0.03 usr 0.02 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing update of keys with functions
+Time for update_of_key (500): 22 wallclock secs ( 2.61 usr 1.35 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for update_of_key_big (501): 25 wallclock secs ( 0.02 usr 0.01 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing update with key
+Time for update_with_key (100000): 97 wallclock secs (15.38 usr 7.87 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing update of all rows
+Time for update_big (500): 28 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing left outer join
+Time for outer_join_on_key (10:10): 51 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for outer_join (10:10): 63 wallclock secs ( 0.01 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for outer_join_found (10:10): 60 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for outer_join_not_found (500:10): 46 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing delete
+Time for delete_key (10000): 3 wallclock secs ( 0.73 usr 0.34 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for delete_big (12): 15 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Insert into table with 16 keys and with a primary key with 16 parts
+Time for insert_key (100000): 111 wallclock secs (10.00 usr 3.74 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing update of keys
+Time for update_of_key (256): 37 wallclock secs ( 0.04 usr 0.02 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Deleting everything from table
+Time for delete_big_many_keys (2): 59 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Inserting 100000 rows with multiple values
+Time for multiple_value_insert (100000): 7 wallclock secs ( 1.92 usr 0.05 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Time for drop table(1): 0 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Total time: 1552 wallclock secs (263.84 usr 86.41 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results/insert-mysql-Linux_2.2.1_i686-cmp-adabas,mysql b/sql-bench/Results/insert-mysql-Linux_2.2.1_i686-cmp-adabas,mysql
new file mode 100644
index 00000000000..efcd2895f38
--- /dev/null
+++ b/sql-bench/Results/insert-mysql-Linux_2.2.1_i686-cmp-adabas,mysql
@@ -0,0 +1,51 @@
+Testing server 'MySQL 3.22.18' at 1999-02-27 21:14:05
+
+Testing the speed of inserting data into 1 table and do some selects on it.
+The tests are done with a table that has 10000 rows.
+
+Generating random keys
+Creating tables
+Inserting 10000 rows in order
+Inserting 10000 rows in reverse order
+Inserting 10000 rows in random order
+Time for insert (30000): 12 wallclock secs ( 2.84 usr 0.94 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing insert of duplicates
+Time for insert_duplicates (30000): 2 wallclock secs ( 0.66 usr 0.33 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Retrieving data from the table
+Time for select_big (10:300000): 6 wallclock secs ( 2.83 usr 1.37 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for order_by_key (10:300000): 5 wallclock secs ( 2.85 usr 1.53 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for order_by (10:300000): 6 wallclock secs ( 2.90 usr 2.06 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for select_range_prefix (5010:42084): 21 wallclock secs ( 4.63 usr 0.72 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for select_range (5010:42084): 14 wallclock secs ( 3.89 usr 0.93 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for select_key_prefix (20000): 23 wallclock secs (11.28 usr 1.58 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for select_key (20000): 21 wallclock secs (10.95 usr 1.39 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Test of compares with simple ranges
+Time for select_range_prefix (20000:43500): 14 wallclock secs ( 5.73 usr 0.97 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for select_range (20000:43500): 13 wallclock secs ( 6.41 usr 0.99 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for select_group (101): 4 wallclock secs ( 0.09 usr 0.01 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for min_max_on_key (3000): 3 wallclock secs ( 1.51 usr 0.17 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for min_max (60): 3 wallclock secs ( 0.03 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for count_on_key (100): 6 wallclock secs ( 0.10 usr 0.01 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for count (100): 6 wallclock secs ( 0.07 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing update with functions
+Time for update_key (500): 1 wallclock secs ( 0.04 usr 0.02 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for update_key_big (480): 3 wallclock secs ( 0.08 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing delete
+Time for delete_key (500): 0 wallclock secs ( 0.05 usr 0.01 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for delete_big (12): 2 wallclock secs ( 0.00 usr 0.01 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Insert into table with 16 keys and with a primary key with 16 parts
+Time for insert_key (10000): 12 wallclock secs ( 1.48 usr 0.37 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing update of keys
+Time for update_of_key (256): 6 wallclock secs ( 0.03 usr 0.01 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Deleting everything from table
+Time for delete_big (2): 7 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Total time: 190 wallclock secs (58.47 usr 13.42 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
diff --git a/sql-bench/Results/insert-mysql-NT_4.0 b/sql-bench/Results/insert-mysql-NT_4.0
new file mode 100644
index 00000000000..24b49d6502e
--- /dev/null
+++ b/sql-bench/Results/insert-mysql-NT_4.0
@@ -0,0 +1,70 @@
+Testing server 'MySQL 3.23.17a alpha' at 2000-06-02 17:58:36
+
+Testing the speed of inserting data into 1 table and do some selects on it.
+The tests are done with a table that has 100000 rows.
+
+Generating random keys
+Creating tables
+Inserting 100000 rows in order
+Inserting 100000 rows in reverse order
+Inserting 100000 rows in random order
+Time for insert (300000): 204 wallclock secs (29.41 usr 41.03 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing insert of duplicates
+Time for insert_duplicates (300000): 38 wallclock secs ( 8.48 usr 12.98 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Retrieving data from the table
+Time for select_big (10:3000000): 87 wallclock secs (62.05 usr 25.47 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for order_by_key (10:3000000): 88 wallclock secs (62.23 usr 25.44 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for order_by (10:3000000): 98 wallclock secs (62.59 usr 25.67 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_diff_key (500:1000): 138 wallclock secs ( 0.52 usr 0.16 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_range_prefix (5010:42084): 15 wallclock secs ( 4.33 usr 1.58 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_range (5010:42084): 15 wallclock secs ( 4.53 usr 1.78 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_key_prefix (200000): 198 wallclock secs (93.94 usr 37.94 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_key (200000): 201 wallclock secs (92.41 usr 38.77 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Test of compares with simple ranges
+Time for select_range_prefix (20000:43500): 13 wallclock secs ( 5.61 usr 2.42 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_range (20000:43500): 13 wallclock secs ( 5.55 usr 2.27 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_group (111): 31 wallclock secs ( 0.09 usr 0.02 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for min_max_on_key (15000): 14 wallclock secs ( 6.27 usr 2.73 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for min_max (60): 18 wallclock secs ( 0.05 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for count_on_key (100): 26 wallclock secs ( 0.06 usr 0.05 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for count (100): 40 wallclock secs ( 0.11 usr 0.05 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for count_distinct_big (20): 95 wallclock secs ( 0.05 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing update of keys with functions
+Time for update_of_key (500): 62 wallclock secs ( 4.58 usr 6.73 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for update_of_key_big (501): 33 wallclock secs ( 0.05 usr 0.05 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing update with key
+Time for update_with_key (100000): 185 wallclock secs (25.34 usr 40.66 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing update of all rows
+Time for update_big (500): 64 wallclock secs ( 0.00 usr 0.01 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing left outer join
+Time for outer_join_on_key (10:10): 37 wallclock secs ( 0.05 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for outer_join (10:10): 115 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for outer_join_found (10:10): 102 wallclock secs ( 0.01 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for outer_join_not_found (500:10): 54 wallclock secs ( 0.02 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing delete
+Time for delete_key (10000): 6 wallclock secs ( 0.84 usr 1.30 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for delete_big (12): 21 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Insert into table with 16 keys and with a primary key with 16 parts
+Time for insert_key (100000): 1418 wallclock secs (13.78 usr 12.97 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing update of keys
+Time for update_of_key (256): 406 wallclock secs ( 0.03 usr 0.02 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Deleting everything from table
+Time for delete_big_many_keys (2): 438 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Inserting 100000 rows with multiple values
+Time for multiple_value_insert (100000): 10 wallclock secs ( 2.59 usr 0.14 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Time for drop table(1): 0 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Total time: 4284 wallclock secs (485.59 usr 280.22 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results/insert-mysql-SunOS_5.5.1_sun4u b/sql-bench/Results/insert-mysql-SunOS_5.5.1_sun4u
new file mode 100644
index 00000000000..b1a11de8ff8
--- /dev/null
+++ b/sql-bench/Results/insert-mysql-SunOS_5.5.1_sun4u
@@ -0,0 +1,56 @@
+Testing server 'MySQL 3.22.19' at 1999-03-02 3:45:56
+
+Testing the speed of inserting data into 1 table and do some selects on it.
+The tests are done with a table that has 100000 rows.
+
+Generating random keys
+Creating tables
+Inserting 100000 rows in order
+Inserting 100000 rows in reverse order
+Inserting 100000 rows in random order
+Time for insert (300000): 371 wallclock secs (48.34 usr 36.37 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing insert of duplicates
+Time for insert_duplicates (300000): 59 wallclock secs (14.62 usr 11.60 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Retrieving data from the table
+Time for select_big (10:3000000): 129 wallclock secs (84.68 usr 41.39 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for order_by_key (10:3000000): 137 wallclock secs (83.69 usr 41.88 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for order_by (10:3000000): 215 wallclock secs (84.17 usr 40.10 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_range_prefix (5010:42084): 54 wallclock secs ( 8.51 usr 2.66 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_range (5010:42084): 39 wallclock secs ( 8.39 usr 2.44 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_key_prefix (200000): 468 wallclock secs (190.39 usr 54.04 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_key (200000): 468 wallclock secs (197.61 usr 52.82 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Test of compares with simple ranges
+Time for select_range_prefix (20000:43500): 33 wallclock secs (10.90 usr 3.24 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_range (20000:43500): 30 wallclock secs (10.83 usr 3.79 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_group (111): 257 wallclock secs ( 0.22 usr 0.05 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for min_max_on_key (3000): 6 wallclock secs ( 2.61 usr 0.68 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for min_max (60): 86 wallclock secs ( 0.12 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for count_on_key (100): 136 wallclock secs ( 0.11 usr 0.03 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for count (100): 131 wallclock secs ( 0.14 usr 0.01 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing update with functions
+Time for update_key (500): 1 wallclock secs ( 0.07 usr 0.04 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for update_key_big (501): 82 wallclock secs ( 0.12 usr 0.05 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing delete
+Time for delete_key (500): 1 wallclock secs ( 0.09 usr 0.05 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for delete_big (12): 58 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Insert into table with 16 keys and with a primary key with 16 parts
+Time for insert_key (100000): 432 wallclock secs (32.22 usr 14.09 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing update of keys
+Time for update_of_key (256): 149 wallclock secs ( 0.09 usr 0.03 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Deleting everything from table
+Time for delete_big (2): 268 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Inserting 100000 rows with multiple values
+Time for multiple_value_insert (100000): 24 wallclock secs ( 3.72 usr 0.06 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Time for drop table(1): 0 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Total time: 3635 wallclock secs (781.69 usr 305.43 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results/insert-mysql-SunOS_5.7_sun4m b/sql-bench/Results/insert-mysql-SunOS_5.7_sun4m
new file mode 100644
index 00000000000..515e9a8a1c1
--- /dev/null
+++ b/sql-bench/Results/insert-mysql-SunOS_5.7_sun4m
@@ -0,0 +1,68 @@
+Testing server 'MySQL 3.22.20' at 1999-03-19 13:59:43
+
+Testing the speed of inserting data into 1 table and do some selects on it.
+The tests are done with a table that has 100000 rows.
+
+Generating random keys
+Creating tables
+Inserting 100000 rows in order
+Inserting 100000 rows in reverse order
+Inserting 100000 rows in random order
+Time for insert (300000): 1615 secs (216.50 usr 221.44 sys + 0.00 cusr 0.00 csys = 437.94 cpu)
+
+Testing insert of duplicates
+Time for insert_duplicates (300000): 330 secs (64.66 usr 64.80 sys + 0.00 cusr 0.00 csys = 129.46 cpu)
+
+Retrieving data from the table
+Time for select_big (10:3000000): 896 secs (383.17 usr 271.88 sys + 0.00 cusr 0.00 csys = 655.05 cpu)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+8 queries in 8 loops of 10 loops took 746 seconds
+Estimated time for order_by_key (10:2400000): 932 secs (400.17 usr 269.81 sys + 0.00 cusr 0.00 csys = 669.99 cpu)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+6 queries in 6 loops of 10 loops took 824 seconds
+Estimated time for order_by (10:1800000): 1373 secs (367.25 usr 247.43 sys + 0.00 cusr 0.00 csys = 614.68 cpu)
+Time for select_range_prefix (5010:42084): 262 secs (37.71 usr 15.74 sys + 0.00 cusr 0.00 csys = 53.45 cpu)
+Time for select_range (5010:42084): 181 secs (35.49 usr 14.52 sys + 0.00 cusr 0.00 csys = 50.01 cpu)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+51066 queries in 25533 loops of 100000 loops took 601 seconds
+Estimated time for select_key_prefix (200000): 2353 secs (783.46 usr 293.15 sys + 0.00 cusr 0.00 csys = 1076.61 cpu)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+52474 queries in 26237 loops of 100000 loops took 601 seconds
+Estimated time for select_key (200000): 2290 secs (906.93 usr 309.98 sys + 0.00 cusr 0.00 csys = 1216.91 cpu)
+
+Test of compares with simple ranges
+Time for select_range_prefix (20000:43500): 139 secs (44.24 usr 16.91 sys + 0.00 cusr 0.00 csys = 61.15 cpu)
+Time for select_range (20000:43500): 148 secs (44.42 usr 16.74 sys + 0.00 cusr 0.00 csys = 61.16 cpu)
+Time for select_group (111): 1290 secs ( 0.60 usr 0.24 sys + 0.00 cusr 0.00 csys = 0.84 cpu)
+Time for min_max_on_key (3000): 31 secs (12.80 usr 3.85 sys + 0.00 cusr 0.00 csys = 16.65 cpu)
+Time for min_max (60): 437 secs ( 0.34 usr 0.09 sys + 0.00 cusr 0.00 csys = 0.43 cpu)
+Time for count_on_key (100): 659 secs ( 0.47 usr 0.21 sys + 0.00 cusr 0.00 csys = 0.68 cpu)
+Time for count (100): 539 secs ( 0.53 usr 0.14 sys + 0.00 cusr 0.00 csys = 0.67 cpu)
+
+Testing update with functions
+Time for update_key (500): 2 secs ( 0.34 usr 0.33 sys + 0.00 cusr 0.00 csys = 0.67 cpu)
+Time for update_key_big (501): 380 secs ( 0.33 usr 0.25 sys + 0.00 cusr 0.00 csys = 0.58 cpu)
+
+Testing delete
+Time for delete_key (500): 4 secs ( 0.43 usr 0.34 sys + 0.00 cusr 0.00 csys = 0.77 cpu)
+Time for delete_big (12): 283 secs ( 0.02 usr 0.01 sys + 0.00 cusr 0.00 csys = 0.03 cpu)
+
+Insert into table with 16 keys and with a primary key with 16 parts
+Time for insert_key (100000): 2879 secs (151.51 usr 77.43 sys + 0.00 cusr 0.00 csys = 228.94 cpu)
+
+Testing update of keys
+Time for update_of_key (256): 835 secs ( 0.30 usr 0.30 sys + 0.00 cusr 0.00 csys = 0.60 cpu)
+
+Deleting everything from table
+Time for delete_big (2): 2240 secs ( 0.00 usr 0.01 sys + 0.00 cusr 0.00 csys = 0.01 cpu)
+
+Inserting 100000 rows with multiple values
+Time for multiple_value_insert (100000): 128 secs (16.22 usr 0.49 sys + 0.00 cusr 0.00 csys = 16.71 cpu)
+
+Time for drop table(1): 1 secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 cpu)
+
+Estimated total time: 20234 secs (3468.07 usr 1826.12 sys + 0.00 cusr 0.00 csys = 5294.18 cpu)
diff --git a/sql-bench/Results/insert-mysql-SunOS_5.7_sun4u b/sql-bench/Results/insert-mysql-SunOS_5.7_sun4u
new file mode 100644
index 00000000000..8bec0426b04
--- /dev/null
+++ b/sql-bench/Results/insert-mysql-SunOS_5.7_sun4u
@@ -0,0 +1,72 @@
+Testing server 'MySQL 3.23.8 alpha' at 2000-01-17 22:20:19
+
+Testing the speed of inserting data into 1 table and do some selects on it.
+The tests are done with a table that has 100000 rows.
+
+Generating random keys
+Creating tables
+Inserting 100000 rows in order
+Inserting 100000 rows in reverse order
+Inserting 100000 rows in random order
+Time for insert (300000): 229 wallclock secs (20.94 usr 26.27 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing insert of duplicates
+Time for insert_duplicates (300000): 33 wallclock secs ( 6.55 usr 8.84 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Retrieving data from the table
+Time for select_big (10:3000000): 84 wallclock secs (46.20 usr 36.63 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for order_by_key (10:3000000): 84 wallclock secs (45.63 usr 36.98 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for order_by (10:3000000): 111 wallclock secs (45.15 usr 37.26 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_diff_key (500:1000): 311 wallclock secs ( 0.28 usr 0.11 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_range_prefix (5010:42084): 22 wallclock secs ( 3.89 usr 2.04 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_range (5010:42084): 21 wallclock secs ( 3.91 usr 1.73 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_key_prefix (200000): 213 wallclock secs (92.33 usr 41.44 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_key (200000): 210 wallclock secs (84.78 usr 37.42 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Test of compares with simple ranges
+Time for select_range_prefix (20000:43500): 14 wallclock secs ( 5.34 usr 2.75 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_range (20000:43500): 15 wallclock secs ( 5.01 usr 2.61 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_group (111): 67 wallclock secs ( 0.10 usr 0.03 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for min_max_on_key (3000): 3 wallclock secs ( 1.22 usr 0.53 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for min_max (60): 36 wallclock secs ( 0.06 usr 0.01 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for count_on_key (100): 54 wallclock secs ( 0.05 usr 0.01 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for count (100): 53 wallclock secs ( 0.05 usr 0.01 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing update of keys with functions
+Time for update_of_key (500): 2 wallclock secs ( 0.07 usr 0.03 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for update_of_key_big (501): 44 wallclock secs ( 0.03 usr 0.05 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing update with key
+Time for update_with_key (100000): 200 wallclock secs (17.53 usr 24.56 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing update of all rows
+Time for update_big (500): 69 wallclock secs ( 0.01 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing left outer join
+Time for outer_join_on_key (10:10): 86 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for outer_join (10:10): 132 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for outer_join_found (10:10): 132 wallclock secs ( 0.01 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+67 queries in 66 loops of 500 loops took 603 seconds
+Estimated time for outer_join_not_found (500:507): 603 wallclock secs ( 0.07 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing delete
+Time for delete_key (500): 1 wallclock secs ( 0.04 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for delete_big (12): 25 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Insert into table with 16 keys and with a primary key with 16 parts
+Time for insert_key (100000): 1333 wallclock secs (14.75 usr 8.04 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing update of keys
+Time for update_of_key (256): 163 wallclock secs ( 0.02 usr 0.02 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Deleting everything from table
+Time for delete_big_many_keys (2): 251 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Inserting 100000 rows with multiple values
+Time for multiple_value_insert (100000): 13 wallclock secs ( 1.72 usr 0.03 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Time for drop table(1): 0 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Estimated total time: 8580 wallclock secs (396.21 usr 267.41 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results/insert-mysql-win98 b/sql-bench/Results/insert-mysql-win98
new file mode 100644
index 00000000000..12c85e60dee
--- /dev/null
+++ b/sql-bench/Results/insert-mysql-win98
@@ -0,0 +1,72 @@
+Testing server 'MySQL 3.23.13a alpha' at 2000-03-15 3:59:00
+
+Testing the speed of inserting data into 1 table and do some selects on it.
+The tests are done with a table that has 100000 rows.
+
+Generating random keys
+Creating tables
+Inserting 100000 rows in order
+Inserting 100000 rows in reverse order
+Inserting 100000 rows in random order
+Time for insert (300000): 438 wallclock secs (437.15 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing insert of duplicates
+Time for insert_duplicates (300000): 91 wallclock secs (91.06 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Retrieving data from the table
+Time for select_big (10:3000000): 173 wallclock secs (173.79 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for order_by_key (10:3000000): 175 wallclock secs (174.66 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for order_by (10:3000000): 249 wallclock secs (248.87 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_diff_key (500:1000): 241 wallclock secs (240.63 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_range_prefix (5010:42084): 33 wallclock secs (33.50 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_range (5010:42084): 34 wallclock secs (33.67 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_key_prefix (200000): 542 wallclock secs (542.23 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_key (200000): 540 wallclock secs (540.35 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Test of compares with simple ranges
+Time for select_range_prefix (20000:43500): 33 wallclock secs (33.12 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_range (20000:43500): 33 wallclock secs (33.45 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_group (111): 58 wallclock secs (58.22 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for min_max_on_key (3000): 7 wallclock secs ( 6.87 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for min_max (60): 33 wallclock secs (32.90 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for count_on_key (100): 52 wallclock secs (52.23 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for count (100): 55 wallclock secs (54.87 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing update of keys with functions
+Time for update_of_key (500): 1 wallclock secs ( 0.99 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for update_of_key_big (501): 38 wallclock secs (38.07 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing update with key
+Time for update_with_key (100000): 432 wallclock secs (432.20 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing update of all rows
+Time for update_big (500): 84 wallclock secs (83.33 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing left outer join
+Time for outer_join_on_key (10:10): 63 wallclock secs (63.33 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for outer_join (10:10): 146 wallclock secs (145.66 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for outer_join_found (10:10): 144 wallclock secs (144.40 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+75 queries in 74 loops of 500 loops took 606 seconds
+Estimated time for outer_join_not_found (500:506): 606 wallclock secs (605.55 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing delete
+Time for delete_key (500): 0 wallclock secs ( 0.82 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for delete_big (12): 22 wallclock secs (21.59 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Insert into table with 16 keys and with a primary key with 16 parts
+Time for insert_key (100000): 364 wallclock secs (363.72 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing update of keys
+Time for update_of_key (256): 58 wallclock secs (58.22 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Deleting everything from table
+Time for delete_big_many_keys (2): 112 wallclock secs (112.11 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Inserting 100000 rows with multiple values
+Time for multiple_value_insert (100000): 11 wallclock secs (11.64 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Time for drop table(1): 0 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Estimated total time: 8358 wallclock secs (8356.07 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results/insert-mysql_3.21-Linux_2.0.35_i686 b/sql-bench/Results/insert-mysql_3.21-Linux_2.0.35_i686
new file mode 100644
index 00000000000..36f845dd0df
--- /dev/null
+++ b/sql-bench/Results/insert-mysql_3.21-Linux_2.0.35_i686
@@ -0,0 +1,51 @@
+Testing server 'MySQL 3.21.33' at 1998-08-21 13:27:34
+
+Testing the speed of inserting data into 1 table and do some selects on it.
+The tests are done with a table that has 100000 rows.
+
+Generating random keys
+Creating tables
+Inserting 100000 rows in order
+Inserting 100000 rows in reverse order
+Inserting 100000 rows in random order
+Time for insert (300000): 176 secs (13.67 usr 34.60 sys = 48.27 cpu)
+
+Testing insert of duplicates
+Time for insert_duplicates (300000): 34 secs ( 4.70 usr 8.53 sys = 13.23 cpu)
+
+Retrieving data from the table
+Time for select_big (10:3000000): 55 secs ( 3.26 usr 51.46 sys = 54.72 cpu)
+Time for order_by_key (5:3000000): 92 secs ( 1.88 usr 62.99 sys = 64.87 cpu)
+Time for order_by (5:3000000): 91 secs ( 1.63 usr 63.23 sys = 64.86 cpu)
+Time for select_range_prefix (5010:42084): 26 secs ( 1.15 usr 4.63 sys = 5.78 cpu)
+Time for select_range (5010:42084): 18 secs ( 0.73 usr 5.18 sys = 5.91 cpu)
+Time for select_key_prefix (200000): 270 secs (60.23 usr 105.01 sys = 165.24 cpu)
+Time for select_key (200000): 247 secs (65.75 usr 99.71 sys = 165.46 cpu)
+
+Test of compares with simple ranges
+Time for select_range_prefix (20000:43500): 16 secs ( 2.97 usr 6.00 sys = 8.97 cpu)
+Time for select_range (20000:43500): 15 secs ( 3.01 usr 5.54 sys = 8.55 cpu)
+Time for select_group (111): 92 secs ( 0.01 usr 0.10 sys = 0.11 cpu)
+Time for min_max_on_key (3000): 427 secs ( 0.07 usr 2.19 sys = 2.26 cpu)
+Time for min_max (60): 25 secs ( 0.00 usr 0.07 sys = 0.07 cpu)
+Time for count_on_key (100): 41 secs ( 0.01 usr 0.11 sys = 0.12 cpu)
+Time for count (100): 58 secs ( 0.00 usr 0.09 sys = 0.09 cpu)
+
+Testing update with functions
+Time for update_key (500): 259 secs ( 4.80 usr 10.25 sys = 15.05 cpu)
+Time for update_key_big (105003): 85 secs ( 0.41 usr 0.31 sys = 0.72 cpu)
+
+Testing delete
+Time for delete_key (500): 0 secs ( 0.05 usr 0.06 sys = 0.11 cpu)
+Time for delete_big (12): 27 secs ( 0.00 usr 0.01 sys = 0.01 cpu)
+
+Insert into table with 16 keys and with a primary key with 16 parts
+Time for insert_key (100000): 698 secs ( 8.57 usr 12.08 sys = 20.65 cpu)
+
+Testing update of keys
+Time for update_key (256): 97 secs ( 0.01 usr 0.04 sys = 0.05 cpu)
+
+Deleting everything from table
+Time for delete_big (2): 120 secs ( 0.00 usr 0.00 sys = 0.00 cpu)
+
+Total time: 2988 secs (172.92 usr 472.21 sys = 645.13 cpu)
diff --git a/sql-bench/Results/insert-mysql_fast-Linux_2.2.10_i686-cmp-msql,mysql b/sql-bench/Results/insert-mysql_fast-Linux_2.2.10_i686-cmp-msql,mysql
new file mode 100644
index 00000000000..41f9cabadd5
--- /dev/null
+++ b/sql-bench/Results/insert-mysql_fast-Linux_2.2.10_i686-cmp-msql,mysql
@@ -0,0 +1,55 @@
+Testing server 'MySQL 3.23.3 alpha' at 1999-09-24 9:11:01
+
+Testing the speed of inserting data into 1 table and do some selects on it.
+The tests are done with a table that has 100000 rows.
+
+Generating random keys
+Creating tables
+Inserting 100000 rows in order
+Inserting 100000 rows in reverse order
+Inserting 100000 rows in random order
+Time for insert (300000): 111 wallclock secs (41.50 usr 6.72 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing insert of duplicates
+Time for insert_duplicates (300000): 15 wallclock secs ( 5.68 usr 1.77 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Retrieving data from the table
+Time for select_big (10:3000000): 69 wallclock secs (47.62 usr 7.54 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for order_by_key (10:3000000): 69 wallclock secs (47.67 usr 7.32 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for order_by (10:3000000): 86 wallclock secs (47.40 usr 7.63 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_diff_key (500:1000): 305 wallclock secs ( 0.62 usr 0.03 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_range_prefix (5000:63000): 15 wallclock secs ( 5.62 usr 0.48 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_range (5000:63000): 15 wallclock secs ( 5.43 usr 0.41 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_key_prefix (200000): 265 wallclock secs (165.34 usr 9.78 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_key (200000): 262 wallclock secs (162.27 usr 10.69 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Test of compares with simple ranges
+Time for select_range_prefix (20000:43500): 15 wallclock secs ( 9.01 usr 0.63 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_range (20000:43500): 15 wallclock secs ( 8.36 usr 0.64 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing update of keys in loops
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+599999 queries in 599999 loops of 600000 loops took 665 seconds
+Estimated time for update_of_key (600000): 665 wallclock secs (152.71 usr 23.25 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing update with key
+Time for update_with_key (100000): 147 wallclock secs (37.92 usr 7.66 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing update of all rows
+Time for update_big (500): 34 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing delete
+Time for delete_key (500): 0 wallclock secs ( 0.06 usr 0.01 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for delete_big (12): 18 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Insert into table with 5 keys and with a primary key with 5 parts
+Time for insert_key (100000): 68 wallclock secs (13.88 usr 2.39 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing update of keys
+Time for update_of_key (256): 29 wallclock secs ( 0.02 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Deleting everything from table
+Time for delete_big_many_keys (2): 8 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Estimated total time: 2211 wallclock secs (751.12 usr 86.95 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results/insert-mysql_odbc-win98 b/sql-bench/Results/insert-mysql_odbc-win98
new file mode 100644
index 00000000000..d8e61806266
--- /dev/null
+++ b/sql-bench/Results/insert-mysql_odbc-win98
@@ -0,0 +1,62 @@
+Testing server 'MySQL 3.22.19a' at 1999-03-02 17:02:20
+
+Testing the speed of inserting data into 1 table and do some selects on it.
+The tests are done with a table that has 100000 rows.
+
+Generating random keys
+Creating tables
+Inserting 100000 rows in order
+Inserting 100000 rows in reverse order
+Inserting 100000 rows in random order
+Time for insert (300000): 1029 wallclock secs (1028.97 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing insert of duplicates
+Time for insert_duplicates (300000): 280 wallclock secs (280.34 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Retrieving data from the table
+Time for select_big (10:3000000): 369 wallclock secs (368.66 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for order_by_key (10:3000000): 370 wallclock secs (369.81 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for order_by (10:3000000): 491 wallclock secs (490.87 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_range_prefix (5010:42084): 59 wallclock secs (59.10 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_range (5010:42084): 54 wallclock secs (54.49 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+129260 queries in 64630 loops of 100000 loops took 601 seconds
+Estimated time for select_key_prefix (200000): 929 wallclock secs (928.96 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+131414 queries in 65707 loops of 100000 loops took 601 seconds
+Estimated time for select_key (200000): 914 wallclock secs (914.74 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Test of compares with simple ranges
+Time for select_range_prefix (20000:43500): 56 wallclock secs (56.13 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_range (20000:43500): 56 wallclock secs (56.03 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_group (111): 190 wallclock secs (190.09 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for min_max_on_key (3000): 12 wallclock secs (12.03 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for min_max (60): 51 wallclock secs (51.52 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for count_on_key (100): 67 wallclock secs (66.63 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for count (100): 93 wallclock secs (92.82 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing update with functions
+Time for update_key (500): 2 wallclock secs ( 1.81 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for update_key_big (501): 59 wallclock secs (59.81 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing delete
+Time for delete_key (500): 2 wallclock secs ( 1.82 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for delete_big (12): 42 wallclock secs (41.46 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Insert into table with 16 keys and with a primary key with 16 parts
+Time for insert_key (100000): 648 wallclock secs (648.40 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing update of keys
+Time for update_of_key (256): 110 wallclock secs (109.57 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Deleting everything from table
+Time for delete_big (2): 169 wallclock secs (168.73 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Inserting 100000 rows with multiple values
+Time for multiple_value_insert (100000): 40 wallclock secs (40.32 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Time for drop table(1): 0 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Estimated total time: 6093 wallclock secs (6093.46 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results/insert-oracle-Linux_2.0.36_i686-cmp-mysql,oracle b/sql-bench/Results/insert-oracle-Linux_2.0.36_i686-cmp-mysql,oracle
new file mode 100644
index 00000000000..43d8400226e
--- /dev/null
+++ b/sql-bench/Results/insert-oracle-Linux_2.0.36_i686-cmp-mysql,oracle
@@ -0,0 +1,69 @@
+Testing server 'Oracle 8.0.5.0.0' at 1999-03-25 0:49:44
+
+Testing the speed of inserting data into 1 table and do some selects on it.
+The tests are done with a table that has 100000 rows.
+
+Generating random keys
+Creating tables
+Inserting 100000 rows in order
+Inserting 100000 rows in reverse order
+Inserting 100000 rows in random order
+Time for insert (300000): 1017 wallclock secs (228.54 usr 28.12 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing insert of duplicates
+Time for insert_duplicates (300000): 2000 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Retrieving data from the table
+Time for select_big (10:3000000): 844 wallclock secs (366.38 usr 91.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+8 queries in 8 loops of 10 loops took 677 seconds
+Estimated time for order_by_key (10:2400000): 846 wallclock secs (362.64 usr 93.30 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+8 queries in 8 loops of 10 loops took 651 seconds
+Estimated time for order_by (10:2400000): 813 wallclock secs (362.89 usr 88.91 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for select_range_prefix (5010:42084): 46 wallclock secs (18.80 usr 3.50 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+225 queries in 225 loops of 5000 loops took 638 seconds
+Estimated time for select_range (5000:1890): 14177 wallclock secs (17.56 usr 3.56 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+187460 queries in 93730 loops of 100000 loops took 601 seconds
+Estimated time for select_key_prefix (200000): 641 wallclock secs (235.18 usr 40.05 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+1316 queries in 658 loops of 100000 loops took 601 seconds
+Estimated time for select_key (200000): 91337 wallclock secs (252.28 usr 48.63 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Test of compares with simple ranges
+Time for select_range_prefix (20000:43500): 37 wallclock secs (17.82 usr 2.98 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+1480 queries in 37 loops of 500 loops took 608 seconds
+Estimated time for select_range (20000:3219): 608 wallclock secs ( 1.26 usr 0.21 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for select_group (91): 50 wallclock secs ( 0.08 usr 0.02 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for min_max_on_key (3000): 9 wallclock secs ( 3.29 usr 0.62 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for min_max (60): 25 wallclock secs ( 0.04 usr 0.01 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for count_on_key (100): 31 wallclock secs ( 0.08 usr 0.04 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for count (100): 50 wallclock secs ( 0.08 usr 0.03 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing update with functions
+Time for update_key (500): 221 wallclock secs ( 0.26 usr 0.08 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for update_key_big (501): 299 wallclock secs ( 0.40 usr 0.07 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing delete
+Time for delete_key (500): 265 wallclock secs ( 0.34 usr 0.04 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for delete_big (12): 495 wallclock secs ( 0.04 usr 0.04 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Insert into table with 16 keys and with a primary key with 16 parts
+Time for insert_key (100000): 647 wallclock secs (78.18 usr 9.80 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing update of keys
+Time for update_of_key (256): 445 wallclock secs ( 0.19 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Deleting everything from table
+Time for delete_big (2): 544 wallclock secs ( 0.00 usr 0.01 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Estimated total time: 123077 wallclock secs (1962.20 usr 413.70 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
diff --git a/sql-bench/Results/insert-oracle_fast-Linux_2.0.36_i686-cmp-mysql,oracle b/sql-bench/Results/insert-oracle_fast-Linux_2.0.36_i686-cmp-mysql,oracle
new file mode 100644
index 00000000000..8e691054811
--- /dev/null
+++ b/sql-bench/Results/insert-oracle_fast-Linux_2.0.36_i686-cmp-mysql,oracle
@@ -0,0 +1,101 @@
+Testing server 'Oracle 8.0.5.0.0' at 1999-03-23 8:24:00
+
+Testing the speed of inserting data into 1 table and do some selects on it.
+The tests are done with a table that has 100000 rows.
+
+Generating random keys
+Creating tables
+Time for book-keeping (1): 0 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Inserting 100000 rows in order
+Inserting 100000 rows in reverse order
+Inserting 100000 rows in random order
+Time for insert (300000): 1154 wallclock secs (221.85 usr 27.98 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Time for book-keeping (1): 14 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing insert of duplicates
+Time for insert_duplicates (300000): 2001 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Time for book-keeping (1): 11 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Retrieving data from the table
+Time for select_big (10:3000000): 855 wallclock secs (366.27 usr 95.53 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+8 queries in 8 loops of 10 loops took 685 seconds
+Estimated time for order_by_key (10:2400000): 856 wallclock secs (370.12 usr 85.01 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for book-keeping (1): 12 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+8 queries in 8 loops of 10 loops took 646 seconds
+Estimated time for order_by (10:2400000): 807 wallclock secs (349.92 usr 85.42 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for book-keeping (1): 11 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Time for select_range_prefix (5010:42084): 47 wallclock secs (18.29 usr 3.52 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+225 queries in 225 loops of 5000 loops took 639 seconds
+Estimated time for select_range (5000:1890): 14200 wallclock secs (18.89 usr 2.67 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+159614 queries in 79807 loops of 100000 loops took 601 seconds
+Estimated time for select_key_prefix (200000): 753 wallclock secs (235.02 usr 39.45 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+1312 queries in 656 loops of 100000 loops took 601 seconds
+Estimated time for select_key (200000): 91615 wallclock secs (228.66 usr 33.54 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for book-keeping (1): 12 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+
+Test of compares with simple ranges
+Time for select_range_prefix (20000:43500): 37 wallclock secs (17.15 usr 3.23 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for book-keeping (1): 11 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+1480 queries in 37 loops of 500 loops took 615 seconds
+Estimated time for select_range (20000:3219): 615 wallclock secs ( 1.24 usr 0.17 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for book-keeping (1): 11 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Time for select_group (91): 53 wallclock secs ( 0.08 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for min_max_on_key (3000): 9 wallclock secs ( 3.39 usr 0.70 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for min_max (60): 25 wallclock secs ( 0.09 usr 0.02 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for count_on_key (100): 35 wallclock secs ( 0.11 usr 0.01 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for count (100): 50 wallclock secs ( 0.10 usr 0.04 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing update with functions
+Time for update_key (500): 223 wallclock secs ( 0.31 usr 0.02 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for book-keeping (1): 11 wallclock secs ( 0.01 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Time for update_key_big (501): 302 wallclock secs ( 0.45 usr 0.10 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Time for book-keeping (1): 29 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing delete
+Time for delete_key (500): 262 wallclock secs ( 0.31 usr 0.03 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for book-keeping (1): 11 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Time for delete_big (12): 500 wallclock secs ( 0.03 usr 0.05 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Time for book-keeping (1): 0 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Insert into table with 16 keys and with a primary key with 16 parts
+Time for book-keeping (1): 0 wallclock secs ( 0.01 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Time for insert_key (100000): 677 wallclock secs (78.14 usr 9.36 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Time for book-keeping (1): 24 wallclock secs ( 0.01 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing update of keys
+Time for update_of_key (256): 601 wallclock secs ( 0.18 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Time for book-keeping (1): 111 wallclock secs ( 0.01 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Deleting everything from table
+Time for delete_big (2): 969 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Time for book-keeping (1): 0 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Estimated total time: 124637 wallclock secs (1926.54 usr 389.27 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
diff --git a/sql-bench/Results/insert-pg-Linux_2.0.36_i686-cmp-mysql,pg,solid b/sql-bench/Results/insert-pg-Linux_2.0.36_i686-cmp-mysql,pg,solid
new file mode 100644
index 00000000000..3c697d918d1
--- /dev/null
+++ b/sql-bench/Results/insert-pg-Linux_2.0.36_i686-cmp-mysql,pg,solid
@@ -0,0 +1,72 @@
+Testing server 'PostgreSQL 6.4' at 1999-03-09 19:30:50
+
+Testing the speed of inserting data into 1 table and do some selects on it.
+The tests are done with a table that has 100000 rows.
+
+Generating random keys
+Creating tables
+Inserting 100000 rows in order
+Inserting 100000 rows in reverse order
+Inserting 100000 rows in random order
+Time for insert (300000): 1011 wallclock secs (169.92 usr 19.49 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing insert of duplicates
+Time for insert_duplicates (300000): 164 wallclock secs (46.42 usr 5.41 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Retrieving data from the table
+Time for select_big (10:3000000): 113 wallclock secs (26.65 usr 1.59 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for order_by_key (10:3000000): 265 wallclock secs (26.66 usr 1.20 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for order_by (10:3000000): 269 wallclock secs (26.89 usr 1.27 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+90 queries in 90 loops of 5000 loops took 609 seconds
+Estimated time for select_range_prefix (5000:756): 33833 wallclock secs ( 6.11 usr 0.56 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+90 queries in 90 loops of 5000 loops took 609 seconds
+Estimated time for select_range (5000:756): 33833 wallclock secs ( 2.78 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+187952 queries in 93976 loops of 100000 loops took 601 seconds
+Estimated time for select_key_prefix (200000): 639 wallclock secs (123.46 usr 13.29 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+189328 queries in 94664 loops of 100000 loops took 601 seconds
+Estimated time for select_key (200000): 634 wallclock secs (122.95 usr 13.45 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Test of compares with simple ranges
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+520 queries in 13 loops of 500 loops took 629 seconds
+Estimated time for select_range_prefix (20000:1131): 629 wallclock secs ( 0.13 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+520 queries in 13 loops of 500 loops took 626 seconds
+Estimated time for select_range (20000:1131): 626 wallclock secs ( 0.23 usr 0.03 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for select_group (101): 5594 wallclock secs ( 0.07 usr 0.04 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+1080 queries in 180 loops of 500 loops took 603 seconds
+Estimated time for min_max_on_key (3000): 1675 wallclock secs ( 1.28 usr 0.08 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for min_max (60): 49 wallclock secs ( 0.04 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for count_on_key (100): 148 wallclock secs ( 0.06 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for count (100): 156 wallclock secs ( 0.04 usr 0.01 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing update with functions
+Time for update_key (500): 443 wallclock secs ( 0.23 usr 0.03 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for update_key_big (501): 978 wallclock secs ( 0.34 usr 0.06 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing delete
+Time for delete_key (500): 634 wallclock secs ( 0.32 usr 0.09 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for delete_big (12): 43 wallclock secs ( 0.01 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Insert into table with 7 keys and with a primary key with 7 parts
+Time for insert_key (100000): 944 wallclock secs (57.30 usr 6.79 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing update of keys
+Time for update_of_key (256): 3569 wallclock secs ( 0.14 usr 0.03 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Deleting everything from table
+Time for delete_big (2): 33 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Estimated total time: 133319 wallclock secs (625.54 usr 64.54 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
diff --git a/sql-bench/Results/insert-pg_fast-Linux_2.0.36_i686-cmp-mysql,pg,solid b/sql-bench/Results/insert-pg_fast-Linux_2.0.36_i686-cmp-mysql,pg,solid
new file mode 100644
index 00000000000..406c3bb5708
--- /dev/null
+++ b/sql-bench/Results/insert-pg_fast-Linux_2.0.36_i686-cmp-mysql,pg,solid
@@ -0,0 +1,92 @@
+Testing server 'PostgreSQL 6.4' at 1999-03-11 7:45:22
+
+Testing the speed of inserting data into 1 table and do some selects on it.
+The tests are done with a table that has 100000 rows.
+
+Generating random keys
+Creating tables
+Time for book-keeping (1): 1 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Inserting 100000 rows in order
+Inserting 100000 rows in reverse order
+Inserting 100000 rows in random order
+Time for insert (300000): 901 wallclock secs (169.33 usr 18.66 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Time for book-keeping (1): 47 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing insert of duplicates
+Time for insert_duplicates (300000): 169 wallclock secs (48.44 usr 5.24 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Time for book-keeping (1): 15 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Retrieving data from the table
+Time for select_big (10:3000000): 82 wallclock secs (26.48 usr 1.45 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for order_by_key (10:3000000): 208 wallclock secs (26.76 usr 1.38 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for book-keeping (1): 33 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Time for order_by (10:3000000): 209 wallclock secs (26.70 usr 1.83 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for book-keeping (1): 32 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Time for select_range_prefix (5010:42084): 88 wallclock secs ( 4.67 usr 0.54 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for select_range (5010:42084): 89 wallclock secs ( 4.78 usr 0.65 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for select_key_prefix (200000): 550 wallclock secs (123.88 usr 13.39 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for select_key (200000): 547 wallclock secs (123.81 usr 13.35 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for book-keeping (1): 2 wallclock secs ( 0.01 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+
+Test of compares with simple ranges
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+600 queries in 15 loops of 500 loops took 632 seconds
+Estimated time for select_range_prefix (20000:1305): 632 wallclock secs ( 0.28 usr 0.02 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for book-keeping (1): 2 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+600 queries in 15 loops of 500 loops took 633 seconds
+Estimated time for select_range (20000:1305): 633 wallclock secs ( 0.19 usr 0.02 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for book-keeping (1): 2 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Time for select_group (101): 7704 wallclock secs ( 0.07 usr 0.04 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+1110 queries in 185 loops of 500 loops took 601 seconds
+Estimated time for min_max_on_key (3000): 1624 wallclock secs ( 1.35 usr 0.08 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for min_max (60): 48 wallclock secs ( 0.03 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for count_on_key (100): 161 wallclock secs ( 0.10 usr 0.02 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for count (100): 153 wallclock secs ( 0.10 usr 0.03 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing update with functions
+Time for update_key (500): 11 wallclock secs ( 0.33 usr 0.03 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for book-keeping (1): 28 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Time for update_key_big (501): 343 wallclock secs ( 0.34 usr 0.05 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Time for book-keeping (1): 1818 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing delete
+Time for delete_key (500): 11 wallclock secs ( 0.20 usr 0.15 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for book-keeping (1): 89 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Time for delete_big (12): 39 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Time for book-keeping (1): 2 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Insert into table with 7 keys and with a primary key with 7 parts
+Time for book-keeping (1): 1 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Time for insert_key (100000): 956 wallclock secs (57.05 usr 7.08 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Time for book-keeping (1): 17 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing update of keys
+Time for update_of_key (256): 2292 wallclock secs ( 0.21 usr 0.03 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Time for book-keeping (1): 1829 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Deleting everything from table
+Time for delete_big (2): 19 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Time for book-keeping (1): 5 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Estimated total time: 62302 wallclock secs (630.39 usr 65.36 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
diff --git a/sql-bench/Results/insert-solid-Linux_2.0.36_i686-cmp-mysql,pg,solid b/sql-bench/Results/insert-solid-Linux_2.0.36_i686-cmp-mysql,pg,solid
new file mode 100644
index 00000000000..fcc6c53ad20
--- /dev/null
+++ b/sql-bench/Results/insert-solid-Linux_2.0.36_i686-cmp-mysql,pg,solid
@@ -0,0 +1,63 @@
+Testing server 'SOLID Server - v.02.30.0026 (Linux ix86)' at 1999-03-06 13:04:51
+
+Testing the speed of inserting data into 1 table and do some selects on it.
+The tests are done with a table that has 100000 rows.
+
+Generating random keys
+Creating tables
+Inserting 100000 rows in order
+Inserting 100000 rows in reverse order
+Inserting 100000 rows in random order
+Time for insert (300000): 947 wallclock secs (259.72 usr 21.92 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing insert of duplicates
+Time for insert_duplicates (300000): 91 wallclock secs (59.65 usr 3.36 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Retrieving data from the table
+Time for select_big (10:3000000): 312 wallclock secs (119.98 usr 6.62 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for order_by_key (10:3000000): 375 wallclock secs (120.22 usr 7.12 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for order_by (10:3000000): 367 wallclock secs (116.72 usr 6.11 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+15 queries in 15 loops of 5000 loops took 602 seconds
+Estimated time for select_range_prefix (5000:126): 200666 wallclock secs (10.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+30 queries in 30 loops of 5000 loops took 1198 seconds
+Estimated time for select_range (5000:252): 199666 wallclock secs ( 8.33 usr 1.67 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for select_key_prefix (200000): 545 wallclock secs (216.93 usr 15.32 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for select_key (200000): 573 wallclock secs (251.14 usr 17.44 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Test of compares with simple ranges
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+560 queries in 14 loops of 500 loops took 623 seconds
+Estimated time for select_range_prefix (20000:1218): 623 wallclock secs ( 0.39 usr 0.03 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+560 queries in 14 loops of 500 loops took 622 seconds
+Estimated time for select_range (20000:1218): 622 wallclock secs ( 0.32 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for select_group (101): 1206 wallclock secs ( 0.06 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for min_max_on_key (3000): 6 wallclock secs ( 1.91 usr 0.16 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for min_max (60): 406 wallclock secs ( 0.03 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for count_on_key (100): 1151 wallclock secs ( 0.13 usr 0.01 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for count (100): 1213 wallclock secs ( 0.10 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing update with functions
+Time for update_key (500): 2 wallclock secs ( 0.42 usr 0.05 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for update_key_big (501): 818 wallclock secs ( 0.30 usr 0.02 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing delete
+Time for delete_key (500): 29 wallclock secs ( 0.43 usr 0.06 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for delete_big (12): 250 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Insert into table with 7 keys and with a primary key with 7 parts
+Time for insert_key (100000): 1153 wallclock secs (85.87 usr 7.46 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing update of keys
+Time for update_of_key (256): 3015 wallclock secs ( 0.28 usr 0.02 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Deleting everything from table
+Time for delete_big (2): 163 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Estimated total time: 457496 wallclock secs (1277.60 usr 88.42 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
diff --git a/sql-bench/Results/select-Adabas-Linux_2.0.35_i686-cmp-adabas,mysql b/sql-bench/Results/select-Adabas-Linux_2.0.35_i686-cmp-adabas,mysql
new file mode 100644
index 00000000000..caded6105d7
--- /dev/null
+++ b/sql-bench/Results/select-Adabas-Linux_2.0.35_i686-cmp-adabas,mysql
@@ -0,0 +1,22 @@
+Testing server 'Adabas 10.01.00' at 1998-08-19 5:18:19
+
+Testing the speed of selecting on keys that consist of many parts
+The test-table has 10000 rows and the test is done with 22 ranges.
+
+Creating table
+Inserting 10000 rows
+Time to insert (10000): 179 secs ( 7.14 usr 1.96 sys = 9.10 cpu)
+
+Testing big selects on the table
+Time for select_big (70:17207): 4 secs ( 0.39 usr 1.12 sys = 1.51 cpu)
+Time for select_range (410:127625): 86 secs ( 6.46 usr 8.41 sys = 14.87 cpu)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+17458 queries in 2494 loops of 10000 loops took 601 seconds
+Estimated time for min_max_on_key (70000): 2409 secs (44.95 usr 73.42 sys = 118.36 cpu)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+45645 queries in 9129 loops of 10000 loops took 601 seconds
+Estimated time for count_on_key (50000): 658 secs (28.37 usr 56.40 sys = 84.77 cpu)
+
+Estimated total time: 3338 secs (87.31 usr 141.31 sys = 228.62 cpu)
diff --git a/sql-bench/Results/select-msql-Linux_2.2.10_i686-cmp-msql,mysql b/sql-bench/Results/select-msql-Linux_2.2.10_i686-cmp-msql,mysql
new file mode 100644
index 00000000000..856ad7dce50
--- /dev/null
+++ b/sql-bench/Results/select-msql-Linux_2.2.10_i686-cmp-msql,mysql
@@ -0,0 +1,13 @@
+Testing server 'mSQL server version 2.0.10' at 1999-09-24 2:37:52
+
+Testing the speed of selecting on keys that consist of many parts
+The test-table has 10000 rows and the test is done with 34 ranges.
+
+Creating table
+Inserting 10000 rows
+Time to insert (10000): 4 wallclock secs ( 1.66 usr 0.25 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing big selects on the table
+Time for select_big (70:17207): 2 wallclock secs ( 0.45 usr 0.08 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_range (400:81810): 70 wallclock secs ( 3.03 usr 0.55 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Total time: 76 wallclock secs ( 5.15 usr 0.88 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results/select-mysql-3.21-Linux_2.2.1_i686 b/sql-bench/Results/select-mysql-3.21-Linux_2.2.1_i686
new file mode 100644
index 00000000000..e5a56215acb
--- /dev/null
+++ b/sql-bench/Results/select-mysql-3.21-Linux_2.2.1_i686
@@ -0,0 +1,22 @@
+Testing server 'MySQL 3.21.34' at 1999-02-28 16:35:44
+
+Testing the speed of selecting on keys that consist of many parts
+The test-table has 10000 rows and the test is done with 500 ranges.
+
+Creating table
+Inserting 10000 rows
+Time to insert (10000): 5 wallclock secs ( 1.32 usr 0.39 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing big selects on the table
+Time for select_big (70:17207): 1 wallclock secs ( 0.23 usr 0.07 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for select_range (410:1057904): 320 wallclock secs (12.23 usr 6.10 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+48622 queries in 6946 loops of 10000 loops took 601 seconds
+Estimated time for min_max_on_key (70000): 865 wallclock secs (38.44 usr 4.51 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+49800 queries in 9960 loops of 10000 loops took 601 seconds
+Estimated time for count_on_key (50000): 603 wallclock secs (27.12 usr 3.46 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Estimated total time: 1794 wallclock secs (79.34 usr 14.54 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
diff --git a/sql-bench/Results/select-mysql-HP_UX_B.10.20_9000_778 b/sql-bench/Results/select-mysql-HP_UX_B.10.20_9000_778
new file mode 100644
index 00000000000..a93cce3a548
--- /dev/null
+++ b/sql-bench/Results/select-mysql-HP_UX_B.10.20_9000_778
@@ -0,0 +1,25 @@
+Testing server 'MySQL 3.23.4 alpha' at 1999-09-27 17:54:14
+
+Testing the speed of selecting on keys that consist of many parts
+The test-table has 10000 rows and the test is done with 500 ranges.
+
+Creating table
+Inserting 10000 rows
+Time to insert (10000): 12 wallclock secs ( 2.07 usr 0.69 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing big selects on the table
+Time for select_big (70:17207): 4 wallclock secs ( 0.54 usr 0.37 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+287 queries in 7 loops of 10 loops took 646 seconds
+Estimated time for select_range (410:721903): 922 wallclock secs (34.36 usr 19.21 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+65898 queries in 9414 loops of 10000 loops took 601 seconds
+Estimated time for min_max_on_key (70000): 638 wallclock secs (64.35 usr 11.04 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+18910 queries in 3782 loops of 10000 loops took 601 seconds
+Estimated time for count_on_key (50000): 1589 wallclock secs (50.50 usr 8.09 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Estimated total time: 3166 wallclock secs (151.82 usr 39.40 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results/select-mysql-Linux_2.0.35_i686-cmp-adabas,mysql b/sql-bench/Results/select-mysql-Linux_2.0.35_i686-cmp-adabas,mysql
new file mode 100644
index 00000000000..f9792f8a316
--- /dev/null
+++ b/sql-bench/Results/select-mysql-Linux_2.0.35_i686-cmp-adabas,mysql
@@ -0,0 +1,19 @@
+Testing server 'MySQL 3.22.9 beta' at 1998-10-20 7:02:48
+
+Testing the speed of selecting on keys that consist of many parts
+The test-table has 10000 rows and the test is done with 22 ranges.
+
+Creating table
+Inserting 10000 rows
+Time to insert (10000): 5 secs ( 1.06 usr 1.00 sys = 2.06 cpu)
+
+Testing big selects on the table
+Time for select_big (70:17207): 2 secs ( 0.00 usr 0.43 sys = 0.43 cpu)
+Time for select_range (410:127625): 28 secs ( 0.88 usr 2.38 sys = 3.26 cpu)
+Time for min_max_on_key (70000): 230 secs (10.97 usr 37.42 sys = 48.39 cpu)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+37070 queries in 7414 loops of 10000 loops took 601 seconds
+Estimated time for count_on_key (50000): 810 secs (10.62 usr 28.04 sys = 38.66 cpu)
+
+Estimated total time: 1075 secs (23.53 usr 69.27 sys = 92.80 cpu)
diff --git a/sql-bench/Results/select-mysql-Linux_2.0.36_i686-cmp-mysql,pg,solid b/sql-bench/Results/select-mysql-Linux_2.0.36_i686-cmp-mysql,pg,solid
new file mode 100644
index 00000000000..b74c0af713e
--- /dev/null
+++ b/sql-bench/Results/select-mysql-Linux_2.0.36_i686-cmp-mysql,pg,solid
@@ -0,0 +1,16 @@
+Testing server 'MySQL 3.22.18' at 1999-03-07 23:24:05
+
+Testing the speed of selecting on keys that consist of many parts
+The test-table has 10000 rows and the test is done with 1.5 ranges.
+
+Creating table
+Inserting 10000 rows
+Time to insert (10000): 5 wallclock secs ( 1.55 usr 0.28 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing big selects on the table
+Time for select_big (70:17207): 1 wallclock secs ( 0.17 usr 0.08 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for select_range (410:24731): 2 wallclock secs ( 0.43 usr 0.11 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for min_max_on_key (70000): 30 wallclock secs (14.91 usr 1.84 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for count_on_key (50000): 592 wallclock secs (25.52 usr 3.32 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Total time: 630 wallclock secs (42.58 usr 5.63 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
diff --git a/sql-bench/Results/select-mysql-Linux_2.2.10_i686 b/sql-bench/Results/select-mysql-Linux_2.2.10_i686
new file mode 100644
index 00000000000..e4f98335289
--- /dev/null
+++ b/sql-bench/Results/select-mysql-Linux_2.2.10_i686
@@ -0,0 +1,16 @@
+Testing server 'MySQL 3.23.3 alpha' at 1999-09-17 9:47:21
+
+Testing the speed of selecting on keys that consist of many parts
+The test-table has 10000 rows and the test is done with 500 ranges.
+
+Creating table
+Inserting 10000 rows
+Time to insert (10000): 6 wallclock secs ( 2.10 usr 0.28 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing big selects on the table
+Time for select_big (70:17207): 1 wallclock secs ( 0.32 usr 0.06 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_range (410:1057904): 345 wallclock secs (18.21 usr 2.75 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for min_max_on_key (70000): 261 wallclock secs (51.47 usr 3.43 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for count_on_key (50000): 596 wallclock secs (38.79 usr 2.36 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Total time: 1209 wallclock secs (110.89 usr 8.88 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results/select-mysql-Linux_2.2.10_i686-cmp-msql,mysql b/sql-bench/Results/select-mysql-Linux_2.2.10_i686-cmp-msql,mysql
new file mode 100644
index 00000000000..ab21b9bb609
--- /dev/null
+++ b/sql-bench/Results/select-mysql-Linux_2.2.10_i686-cmp-msql,mysql
@@ -0,0 +1,13 @@
+Testing server 'MySQL 3.23.3 alpha' at 1999-09-24 10:48:02
+
+Testing the speed of selecting on keys that consist of many parts
+The test-table has 10000 rows and the test is done with 34 ranges.
+
+Creating table
+Inserting 10000 rows
+Time to insert (10000): 6 wallclock secs ( 2.10 usr 0.30 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing big selects on the table
+Time for select_big (70:17207): 1 wallclock secs ( 0.28 usr 0.07 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_range (400:182200): 11 wallclock secs ( 3.40 usr 0.54 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Total time: 18 wallclock secs ( 5.78 usr 0.91 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results/select-mysql-Linux_2.2.14_i686_xeon b/sql-bench/Results/select-mysql-Linux_2.2.14_i686_xeon
new file mode 100644
index 00000000000..6c952473000
--- /dev/null
+++ b/sql-bench/Results/select-mysql-Linux_2.2.14_i686_xeon
@@ -0,0 +1,23 @@
+Testing server 'MySQL 3.23.17 alpha' at 2000-06-01 3:46:46
+
+Testing the speed of selecting on keys that consist of many parts
+The test-table has 10000 rows and the test is done with 500 ranges.
+
+Creating table
+Inserting 10000 rows
+Time to insert (10000): 3 wallclock secs ( 0.64 usr 0.26 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing big selects on the table
+Time for select_big (70:17207): 1 wallclock secs ( 0.12 usr 0.06 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_range (410:1057904): 190 wallclock secs ( 8.49 usr 3.90 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for min_max_on_key (70000): 210 wallclock secs (21.63 usr 3.48 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for count_on_key (50000): 506 wallclock secs (17.66 usr 2.67 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Time for count_group_on_key_parts (0:0): 0 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Testing count(distinct) on the table
+Time for count_distinct (1000:2000): 110 wallclock secs ( 0.78 usr 0.10 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for count_distinct_group_on_key (1000:6000): 58 wallclock secs ( 0.41 usr 0.03 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for count_distinct_group_on_key_parts (1000:100000): 74 wallclock secs ( 1.18 usr 0.60 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for count_distinct_group (1000:100000): 75 wallclock secs ( 1.20 usr 0.44 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for count_distinct_big (1000:10000000): 570 wallclock secs (73.95 usr 55.45 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Total time: 1797 wallclock secs (126.08 usr 67.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results/select-mysql-Linux_2.2.1_i686-cmp-adabas,mysql b/sql-bench/Results/select-mysql-Linux_2.2.1_i686-cmp-adabas,mysql
new file mode 100644
index 00000000000..90aba31a72b
--- /dev/null
+++ b/sql-bench/Results/select-mysql-Linux_2.2.1_i686-cmp-adabas,mysql
@@ -0,0 +1,19 @@
+Testing server 'MySQL 3.22.18' at 1999-02-27 21:17:16
+
+Testing the speed of selecting on keys that consist of many parts
+The test-table has 10000 rows and the test is done with 22 ranges.
+
+Creating table
+Inserting 10000 rows
+Time to insert (10000): 5 wallclock secs ( 1.45 usr 0.33 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing big selects on the table
+Time for select_big (70:17207): 1 wallclock secs ( 0.24 usr 0.09 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for select_range (410:127625): 9 wallclock secs ( 1.84 usr 0.61 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for min_max_on_key (70000): 195 wallclock secs (33.98 usr 4.55 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+45510 queries in 9102 loops of 10000 loops took 601 seconds
+Estimated time for count_on_key (50000): 660 wallclock secs (26.15 usr 3.48 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Estimated total time: 870 wallclock secs (63.67 usr 9.06 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
diff --git a/sql-bench/Results/select-mysql-NT_4.0 b/sql-bench/Results/select-mysql-NT_4.0
new file mode 100644
index 00000000000..d6cb0942867
--- /dev/null
+++ b/sql-bench/Results/select-mysql-NT_4.0
@@ -0,0 +1,23 @@
+Testing server 'MySQL 3.23.17a alpha' at 2000-06-02 19:10:01
+
+Testing the speed of selecting on keys that consist of many parts
+The test-table has 10000 rows and the test is done with 500 ranges.
+
+Creating table
+Inserting 10000 rows
+Time to insert (10000): 7 wallclock secs ( 1.27 usr 1.42 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing big selects on the table
+Time for select_big (70:17207): 1 wallclock secs ( 0.39 usr 0.11 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_range (410:1057904): 185 wallclock secs (27.20 usr 8.77 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for min_max_on_key (70000): 161 wallclock secs (31.55 usr 12.17 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for count_on_key (50000): 321 wallclock secs (21.41 usr 8.33 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Time for count_group_on_key_parts (1000:0): 34 wallclock secs ( 2.64 usr 1.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Testing count(distinct) on the table
+Time for count_distinct (1000:2000): 69 wallclock secs ( 1.17 usr 0.41 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for count_distinct_group_on_key (1000:6000): 38 wallclock secs ( 0.70 usr 0.17 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for count_distinct_group_on_key_parts (1000:100000): 153 wallclock secs ( 2.61 usr 1.03 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for count_distinct_group (1000:100000): 152 wallclock secs ( 2.81 usr 0.92 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for count_distinct_big (1000:10000000): 1134 wallclock secs (224.20 usr 81.19 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Total time: 2255 wallclock secs (315.95 usr 115.52 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results/select-mysql-SunOS_5.5.1_sun4u b/sql-bench/Results/select-mysql-SunOS_5.5.1_sun4u
new file mode 100644
index 00000000000..fcda0257f5f
--- /dev/null
+++ b/sql-bench/Results/select-mysql-SunOS_5.5.1_sun4u
@@ -0,0 +1,19 @@
+Testing server 'MySQL 3.22.19' at 1999-03-02 4:46:36
+
+Testing the speed of selecting on keys that consist of many parts
+The test-table has 10000 rows and the test is done with 500 ranges.
+
+Creating table
+Inserting 10000 rows
+Time to insert (10000): 12 wallclock secs ( 2.19 usr 1.10 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing big selects on the table
+Time for select_big (70:17207): 4 wallclock secs ( 0.52 usr 0.24 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_range (410:1057904): 650 wallclock secs (32.89 usr 14.43 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for min_max_on_key (70000): 405 wallclock secs (55.81 usr 15.66 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+14550 queries in 2910 loops of 10000 loops took 601 seconds
+Estimated time for count_on_key (50000): 2065 wallclock secs (43.16 usr 11.17 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Estimated total time: 3136 wallclock secs (134.58 usr 42.60 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results/select-mysql-SunOS_5.7_sun4m b/sql-bench/Results/select-mysql-SunOS_5.7_sun4m
new file mode 100644
index 00000000000..665311b095e
--- /dev/null
+++ b/sql-bench/Results/select-mysql-SunOS_5.7_sun4m
@@ -0,0 +1,25 @@
+Testing server 'MySQL 3.22.20' at 1999-03-19 18:27:41
+
+Testing the speed of selecting on keys that consist of many parts
+The test-table has 10000 rows and the test is done with 500 ranges.
+
+Creating table
+Inserting 10000 rows
+Time to insert (10000): 74 secs ( 9.81 usr 7.90 sys + 0.00 cusr 0.00 csys = 17.71 cpu)
+
+Testing big selects on the table
+Time for select_big (70:17207): 17 secs ( 2.44 usr 2.18 sys + 0.00 cusr 0.00 csys = 4.62 cpu)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+82 queries in 2 loops of 10 loops took 654 seconds
+Estimated time for select_range (410:233157): 3270 secs (179.90 usr 141.30 sys + 0.00 cusr 0.00 csys = 321.20 cpu)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+18487 queries in 2641 loops of 10000 loops took 601 seconds
+Estimated time for min_max_on_key (70000): 2275 secs (273.91 usr 103.86 sys + 0.00 cusr 0.00 csys = 377.77 cpu)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+2580 queries in 516 loops of 10000 loops took 601 seconds
+Estimated time for count_on_key (50000): 11647 secs (214.92 usr 80.23 sys + 0.00 cusr 0.00 csys = 295.16 cpu)
+
+Estimated total time: 17283 secs (681.00 usr 335.49 sys + 0.00 cusr 0.00 csys = 1016.50 cpu)
diff --git a/sql-bench/Results/select-mysql-SunOS_5.7_sun4u b/sql-bench/Results/select-mysql-SunOS_5.7_sun4u
new file mode 100644
index 00000000000..6b69a9c531a
--- /dev/null
+++ b/sql-bench/Results/select-mysql-SunOS_5.7_sun4u
@@ -0,0 +1,16 @@
+Testing server 'MySQL 3.23.8 alpha' at 2000-01-17 23:37:17
+
+Testing the speed of selecting on keys that consist of many parts
+The test-table has 10000 rows and the test is done with 500 ranges.
+
+Creating table
+Inserting 10000 rows
+Time to insert (10000): 6 wallclock secs ( 0.94 usr 0.79 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing big selects on the table
+Time for select_big (70:17207): 2 wallclock secs ( 0.27 usr 0.23 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_range (410:1057904): 330 wallclock secs (16.74 usr 13.38 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for min_max_on_key (70000): 225 wallclock secs (29.39 usr 12.44 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for count_on_key (50000): 531 wallclock secs (20.31 usr 8.73 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Total time: 1094 wallclock secs (67.65 usr 35.57 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results/select-mysql-win98 b/sql-bench/Results/select-mysql-win98
new file mode 100644
index 00000000000..c028aaf9661
--- /dev/null
+++ b/sql-bench/Results/select-mysql-win98
@@ -0,0 +1,16 @@
+Testing server 'MySQL 3.23.13a alpha' at 2000-03-15 5:20:12
+
+Testing the speed of selecting on keys that consist of many parts
+The test-table has 10000 rows and the test is done with 500 ranges.
+
+Creating table
+Inserting 10000 rows
+Time to insert (10000): 16 wallclock secs (15.32 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing big selects on the table
+Time for select_big (70:17207): 1 wallclock secs ( 1.81 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_range (410:1057904): 356 wallclock secs (356.09 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for min_max_on_key (70000): 332 wallclock secs (332.69 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for count_on_key (50000): 588 wallclock secs (587.48 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Total time: 1294 wallclock secs (1293.83 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results/select-mysql_3.21-Linux_2.0.35_i686 b/sql-bench/Results/select-mysql_3.21-Linux_2.0.35_i686
new file mode 100644
index 00000000000..f3a66d6ee90
--- /dev/null
+++ b/sql-bench/Results/select-mysql_3.21-Linux_2.0.35_i686
@@ -0,0 +1,22 @@
+Testing server 'MySQL 3.21.33' at 1998-08-21 14:17:23
+
+Testing the speed of selecting on keys that consist of many parts
+The test-table has 10000 rows and the test is done with 500 ranges.
+
+Creating table
+Inserting 10000 rows
+Time to insert (10000): 6 secs ( 0.01 usr 1.78 sys = 1.79 cpu)
+
+Testing big selects on the table
+Time for select_big (70:17207): 1 secs ( 0.11 usr 0.25 sys = 0.36 cpu)
+Time for select_range (410:1057904): 324 secs ( 6.24 usr 14.02 sys = 20.26 cpu)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+40173 queries in 5739 loops of 10000 loops took 601 seconds
+Estimated time for min_max_on_key (70000): 1047 secs (14.57 usr 36.28 sys = 50.85 cpu)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+40640 queries in 8128 loops of 10000 loops took 601 seconds
+Estimated time for count_on_key (50000): 739 secs (13.20 usr 22.31 sys = 35.51 cpu)
+
+Estimated total time: 2117 secs (34.14 usr 74.63 sys = 108.77 cpu)
diff --git a/sql-bench/Results/select-mysql_fast-Linux_2.2.10_i686-cmp-msql,mysql b/sql-bench/Results/select-mysql_fast-Linux_2.2.10_i686-cmp-msql,mysql
new file mode 100644
index 00000000000..324e1003d74
--- /dev/null
+++ b/sql-bench/Results/select-mysql_fast-Linux_2.2.10_i686-cmp-msql,mysql
@@ -0,0 +1,13 @@
+Testing server 'MySQL 3.23.3 alpha' at 1999-09-24 9:47:54
+
+Testing the speed of selecting on keys that consist of many parts
+The test-table has 10000 rows and the test is done with 34 ranges.
+
+Creating table
+Inserting 10000 rows
+Time to insert (10000): 5 wallclock secs ( 1.76 usr 0.26 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing big selects on the table
+Time for select_big (70:17207): 1 wallclock secs ( 0.34 usr 0.03 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_range (400:182200): 11 wallclock secs ( 3.46 usr 0.51 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Total time: 17 wallclock secs ( 5.57 usr 0.80 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results/select-mysql_odbc-win98 b/sql-bench/Results/select-mysql_odbc-win98
new file mode 100644
index 00000000000..bee30632f5b
--- /dev/null
+++ b/sql-bench/Results/select-mysql_odbc-win98
@@ -0,0 +1,19 @@
+Testing server 'MySQL 3.22.19a' at 1999-03-02 18:33:15
+
+Testing the speed of selecting on keys that consist of many parts
+The test-table has 10000 rows and the test is done with 500 ranges.
+
+Creating table
+Inserting 10000 rows
+Time to insert (10000): 35 wallclock secs (34.87 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Testing big selects on the table
+Time for select_big (70:17207): 4 wallclock secs ( 4.01 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for select_range (410:1057904): 592 wallclock secs (592.70 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time for min_max_on_key (70000): 496 wallclock secs (495.60 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+14250 queries in 2850 loops of 10000 loops took 601 seconds
+Estimated time for count_on_key (50000): 2108 wallclock secs (2107.58 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Estimated total time: 3235 wallclock secs (3234.82 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results/select-oracle-Linux_2.0.36_i686-cmp-mysql,oracle b/sql-bench/Results/select-oracle-Linux_2.0.36_i686-cmp-mysql,oracle
new file mode 100644
index 00000000000..2f558da5b5a
--- /dev/null
+++ b/sql-bench/Results/select-oracle-Linux_2.0.36_i686-cmp-mysql,oracle
@@ -0,0 +1,25 @@
+Testing server 'Oracle 8.0.5.0.0' at 1999-03-25 3:50:08
+
+Testing the speed of selecting on keys that consist of many parts
+The test-table has 10000 rows and the test is done with 254 ranges.
+
+Creating table
+Inserting 10000 rows
+Time to insert (10000): 35 wallclock secs ( 7.91 usr 0.90 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing big selects on the table
+Time for select_big (70:17207): 7 wallclock secs ( 2.04 usr 0.53 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+369 queries in 9 loops of 10 loops took 648 seconds
+Estimated time for select_range (410:714201): 720 wallclock secs (115.93 usr 25.53 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+34853 queries in 4979 loops of 10000 loops took 601 seconds
+Estimated time for min_max_on_key (70000): 1207 wallclock secs (78.23 usr 16.69 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+37555 queries in 7511 loops of 10000 loops took 601 seconds
+Estimated time for count_on_key (50000): 800 wallclock secs (53.87 usr 11.17 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Estimated total time: 2769 wallclock secs (257.98 usr 54.82 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
diff --git a/sql-bench/Results/select-oracle_fast-Linux_2.0.36_i686-cmp-mysql,oracle b/sql-bench/Results/select-oracle_fast-Linux_2.0.36_i686-cmp-mysql,oracle
new file mode 100644
index 00000000000..8a99ed02d26
--- /dev/null
+++ b/sql-bench/Results/select-oracle_fast-Linux_2.0.36_i686-cmp-mysql,oracle
@@ -0,0 +1,28 @@
+Testing server 'Oracle 8.0.5.0.0' at 1999-03-23 11:42:05
+
+Testing the speed of selecting on keys that consist of many parts
+The test-table has 10000 rows and the test is done with 254 ranges.
+
+Creating table
+Time for book-keeping (1): 0 wallclock secs ( 0.01 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Inserting 10000 rows
+Time to insert (10000): 41 wallclock secs ( 7.78 usr 0.78 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Time for book-keeping (1): 1 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing big selects on the table
+Time for select_big (70:17207): 6 wallclock secs ( 1.99 usr 0.59 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for select_range (410:785994): 575 wallclock secs (117.75 usr 24.70 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+47740 queries in 6820 loops of 10000 loops took 601 seconds
+Estimated time for min_max_on_key (70000): 881 wallclock secs (75.22 usr 16.26 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+38585 queries in 7717 loops of 10000 loops took 601 seconds
+Estimated time for count_on_key (50000): 778 wallclock secs (56.33 usr 12.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Time for book-keeping (1): 0 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Estimated total time: 2285 wallclock secs (259.15 usr 54.33 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
diff --git a/sql-bench/Results/select-pg-Linux_2.0.36_i686-cmp-mysql,pg,solid b/sql-bench/Results/select-pg-Linux_2.0.36_i686-cmp-mysql,pg,solid
new file mode 100644
index 00000000000..fc36c849b92
--- /dev/null
+++ b/sql-bench/Results/select-pg-Linux_2.0.36_i686-cmp-mysql,pg,solid
@@ -0,0 +1,19 @@
+Testing server 'PostgreSQL 6.4' at 1999-03-10 0:42:54
+
+Testing the speed of selecting on keys that consist of many parts
+The test-table has 10000 rows and the test is done with 1.5 ranges.
+
+Creating table
+Inserting 10000 rows
+Time to insert (10000): 37 wallclock secs ( 6.11 usr 0.62 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing big selects on the table
+Time for select_big (70:17207): 3 wallclock secs ( 0.18 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for select_range (410:24731): 13 wallclock secs ( 0.79 usr 0.04 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for min_max_on_key (70000): 478 wallclock secs (17.06 usr 1.67 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+19545 queries in 3909 loops of 10000 loops took 601 seconds
+Estimated time for count_on_key (50000): 1537 wallclock secs (27.30 usr 3.43 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Estimated total time: 2069 wallclock secs (51.44 usr 5.76 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
diff --git a/sql-bench/Results/select-pg_fast-Linux_2.0.36_i686-cmp-mysql,pg,solid b/sql-bench/Results/select-pg_fast-Linux_2.0.36_i686-cmp-mysql,pg,solid
new file mode 100644
index 00000000000..6d8f5384c77
--- /dev/null
+++ b/sql-bench/Results/select-pg_fast-Linux_2.0.36_i686-cmp-mysql,pg,solid
@@ -0,0 +1,25 @@
+Testing server 'PostgreSQL 6.4' at 1999-03-11 13:25:07
+
+Testing the speed of selecting on keys that consist of many parts
+The test-table has 10000 rows and the test is done with 1.5 ranges.
+
+Creating table
+Time for book-keeping (1): 0 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Inserting 10000 rows
+Time to insert (10000): 33 wallclock secs ( 6.05 usr 0.57 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Time for book-keeping (1): 1 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing big selects on the table
+Time for select_big (70:17207): 1 wallclock secs ( 0.20 usr 0.01 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for select_range (410:24731): 11 wallclock secs ( 0.50 usr 0.02 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for min_max_on_key (70000): 461 wallclock secs (17.09 usr 1.94 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+18630 queries in 3726 loops of 10000 loops took 601 seconds
+Estimated time for count_on_key (50000): 1612 wallclock secs (28.56 usr 3.19 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Time for book-keeping (1): 0 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Estimated total time: 2120 wallclock secs (52.41 usr 5.73 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
diff --git a/sql-bench/Results/select-solid-Linux_2.0.36_i686-cmp-mysql,pg,solid b/sql-bench/Results/select-solid-Linux_2.0.36_i686-cmp-mysql,pg,solid
new file mode 100644
index 00000000000..386216650e8
--- /dev/null
+++ b/sql-bench/Results/select-solid-Linux_2.0.36_i686-cmp-mysql,pg,solid
@@ -0,0 +1,19 @@
+Testing server 'SOLID Server - v.02.30.0026 (Linux ix86)' at 1999-03-06 17:27:17
+
+Testing the speed of selecting on keys that consist of many parts
+The test-table has 10000 rows and the test is done with 1.5 ranges.
+
+Creating table
+Inserting 10000 rows
+Time to insert (10000): 139 wallclock secs ( 9.23 usr 0.67 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Testing big selects on the table
+Time for select_big (70:17207): 3 wallclock secs ( 0.78 usr 0.07 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for select_range (410:24731): 23 wallclock secs ( 1.84 usr 0.11 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for min_max_on_key (70000): 108 wallclock secs (31.16 usr 2.25 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Note: Query took longer then time-limit: 600
+Estimating end time based on:
+3350 queries in 670 loops of 10000 loops took 601 seconds
+Estimated time for count_on_key (50000): 8970 wallclock secs (48.66 usr 4.18 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Estimated total time: 9245 wallclock secs (91.67 usr 7.28 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
diff --git a/sql-bench/Results/wisconsin-Adabas-Linux_2.0.35_i686-cmp-adabas,mysql b/sql-bench/Results/wisconsin-Adabas-Linux_2.0.35_i686-cmp-adabas,mysql
new file mode 100644
index 00000000000..1d391c9143d
--- /dev/null
+++ b/sql-bench/Results/wisconsin-Adabas-Linux_2.0.35_i686-cmp-adabas,mysql
@@ -0,0 +1,14 @@
+Testing server 'Adabas 10.01.00' at 1998-08-19 5:42:51
+
+Wisconsin benchmark test
+
+Time for create_table (3): 0 secs ( 0.00 usr 0.01 sys = 0.01 cpu)
+
+Inserting data
+Time to insert (31000): 585 secs (19.11 usr 7.05 sys = 26.16 cpu)
+Time to delete_big (1): 5 secs ( 0.00 usr 0.00 sys = 0.00 cpu)
+
+Running actual benchmark
+Time for wisc_benchmark (114): 64 secs (15.03 usr 14.19 sys = 29.22 cpu)
+
+Total time: 654 secs (34.14 usr 21.26 sys = 55.40 cpu)
diff --git a/sql-bench/Results/wisconsin-msql-Linux_2.2.10_i686-cmp-msql,mysql b/sql-bench/Results/wisconsin-msql-Linux_2.2.10_i686-cmp-msql,mysql
new file mode 100644
index 00000000000..8ec3e482f15
--- /dev/null
+++ b/sql-bench/Results/wisconsin-msql-Linux_2.2.10_i686-cmp-msql,mysql
@@ -0,0 +1,14 @@
+Testing server 'mSQL server version 2.0.10' at 1999-09-24 2:39:09
+
+Wisconsin benchmark test
+
+Time for create_table (3): 0 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Inserting data
+Time to insert (31000): 13 wallclock secs ( 4.03 usr 0.50 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time to delete_big (1): 1 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Running actual benchmark
+Time for wisc_benchmark (74): 9 wallclock secs ( 4.81 usr 0.92 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Total time: 23 wallclock secs ( 8.84 usr 1.42 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results/wisconsin-mysql-3.21-Linux_2.2.1_i686 b/sql-bench/Results/wisconsin-mysql-3.21-Linux_2.2.1_i686
new file mode 100644
index 00000000000..f502c4e40c8
--- /dev/null
+++ b/sql-bench/Results/wisconsin-mysql-3.21-Linux_2.2.1_i686
@@ -0,0 +1,14 @@
+Testing server 'MySQL 3.21.34' at 1999-02-28 17:01:12
+
+Wisconsin benchmark test
+
+Time for create_table (3): 0 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Inserting data
+Time to insert (31000): 13 wallclock secs ( 2.22 usr 1.05 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time to delete_big (1): 1 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Running actual benchmark
+Time for wisc_benchmark (114): 6 wallclock secs ( 2.48 usr 1.08 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Total time: 20 wallclock secs ( 4.70 usr 2.13 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
diff --git a/sql-bench/Results/wisconsin-mysql-HP_UX_B.10.20_9000_778 b/sql-bench/Results/wisconsin-mysql-HP_UX_B.10.20_9000_778
new file mode 100644
index 00000000000..0f7507959ed
--- /dev/null
+++ b/sql-bench/Results/wisconsin-mysql-HP_UX_B.10.20_9000_778
@@ -0,0 +1,14 @@
+Testing server 'MySQL 3.23.4 alpha' at 1999-09-27 18:25:18
+
+Wisconsin benchmark test
+
+Time for create_table (3): 0 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Inserting data
+Time to insert (31000): 37 wallclock secs ( 3.88 usr 2.13 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time to delete_big (1): 1 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Running actual benchmark
+Time for wisc_benchmark (114): 24 wallclock secs ( 6.96 usr 2.92 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Total time: 62 wallclock secs (10.85 usr 5.05 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results/wisconsin-mysql-Linux_2.0.35_i686-cmp-adabas,mysql b/sql-bench/Results/wisconsin-mysql-Linux_2.0.35_i686-cmp-adabas,mysql
new file mode 100644
index 00000000000..d6ea3b9b7e6
--- /dev/null
+++ b/sql-bench/Results/wisconsin-mysql-Linux_2.0.35_i686-cmp-adabas,mysql
@@ -0,0 +1,14 @@
+Testing server 'MySQL 3.22.9 beta' at 1998-10-20 7:17:14
+
+Wisconsin benchmark test
+
+Time for create_table (3): 0 secs ( 0.00 usr 0.00 sys = 0.00 cpu)
+
+Inserting data
+Time to insert (31000): 19 secs ( 1.42 usr 2.57 sys = 3.99 cpu)
+Time to delete_big (1): 1 secs ( 0.01 usr 0.00 sys = 0.01 cpu)
+
+Running actual benchmark
+Time for wisc_benchmark (114): 9 secs ( 1.84 usr 2.92 sys = 4.76 cpu)
+
+Total time: 30 secs ( 3.27 usr 5.49 sys = 8.76 cpu)
diff --git a/sql-bench/Results/wisconsin-mysql-Linux_2.0.36_i686-cmp-mysql,pg,solid b/sql-bench/Results/wisconsin-mysql-Linux_2.0.36_i686-cmp-mysql,pg,solid
new file mode 100644
index 00000000000..77b0d64569b
--- /dev/null
+++ b/sql-bench/Results/wisconsin-mysql-Linux_2.0.36_i686-cmp-mysql,pg,solid
@@ -0,0 +1,14 @@
+Testing server 'MySQL 3.22.18' at 1999-03-07 23:34:36
+
+Wisconsin benchmark test
+
+Time for create_table (3): 0 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Inserting data
+Time to insert (31000): 13 wallclock secs ( 2.61 usr 0.81 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time to delete_big (1): 1 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Running actual benchmark
+Time for wisc_benchmark (114): 6 wallclock secs ( 1.99 usr 0.67 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Total time: 20 wallclock secs ( 4.61 usr 1.48 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
diff --git a/sql-bench/Results/wisconsin-mysql-Linux_2.2.10_i686 b/sql-bench/Results/wisconsin-mysql-Linux_2.2.10_i686
new file mode 100644
index 00000000000..bd2ba43a8be
--- /dev/null
+++ b/sql-bench/Results/wisconsin-mysql-Linux_2.2.10_i686
@@ -0,0 +1,14 @@
+Testing server 'MySQL 3.23.3 alpha' at 1999-09-17 10:07:31
+
+Wisconsin benchmark test
+
+Time for create_table (3): 0 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Inserting data
+Time to insert (31000): 15 wallclock secs ( 4.40 usr 0.87 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time to delete_big (1): 1 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Running actual benchmark
+Time for wisc_benchmark (114): 7 wallclock secs ( 3.42 usr 0.58 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Total time: 23 wallclock secs ( 7.83 usr 1.45 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results/wisconsin-mysql-Linux_2.2.10_i686-cmp-msql,mysql b/sql-bench/Results/wisconsin-mysql-Linux_2.2.10_i686-cmp-msql,mysql
new file mode 100644
index 00000000000..67537400723
--- /dev/null
+++ b/sql-bench/Results/wisconsin-mysql-Linux_2.2.10_i686-cmp-msql,mysql
@@ -0,0 +1,14 @@
+Testing server 'MySQL 3.23.3 alpha' at 1999-09-24 10:48:20
+
+Wisconsin benchmark test
+
+Time for create_table (3): 0 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Inserting data
+Time to insert (31000): 16 wallclock secs ( 4.54 usr 0.73 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time to delete_big (1): 0 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Running actual benchmark
+Time for wisc_benchmark (74): 4 wallclock secs ( 2.40 usr 0.42 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Total time: 20 wallclock secs ( 6.95 usr 1.15 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results/wisconsin-mysql-Linux_2.2.14_i686_xeon b/sql-bench/Results/wisconsin-mysql-Linux_2.2.14_i686_xeon
new file mode 100644
index 00000000000..276d22f2e7b
--- /dev/null
+++ b/sql-bench/Results/wisconsin-mysql-Linux_2.2.14_i686_xeon
@@ -0,0 +1,14 @@
+Testing server 'MySQL 3.23.17 alpha' at 2000-06-01 4:16:45
+
+Wisconsin benchmark test
+
+Time for create_table (3): 0 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Inserting data
+Time to insert (31000): 11 wallclock secs ( 1.47 usr 0.89 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time to delete_big (1): 0 wallclock secs ( 0.01 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Running actual benchmark
+Time for wisc_benchmark (114): 4 wallclock secs ( 1.72 usr 0.77 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Total time: 15 wallclock secs ( 3.20 usr 1.66 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results/wisconsin-mysql-Linux_2.2.1_i686-cmp-adabas,mysql b/sql-bench/Results/wisconsin-mysql-Linux_2.2.1_i686-cmp-adabas,mysql
new file mode 100644
index 00000000000..0bbf83b94f3
--- /dev/null
+++ b/sql-bench/Results/wisconsin-mysql-Linux_2.2.1_i686-cmp-adabas,mysql
@@ -0,0 +1,14 @@
+Testing server 'MySQL 3.22.18' at 1999-02-27 21:30:47
+
+Wisconsin benchmark test
+
+Time for create_table (3): 0 wallclock secs ( 0.01 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Inserting data
+Time to insert (31000): 13 wallclock secs ( 2.20 usr 0.98 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time to delete_big (1): 0 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Running actual benchmark
+Time for wisc_benchmark (114): 7 wallclock secs ( 2.45 usr 0.96 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Total time: 20 wallclock secs ( 4.66 usr 1.94 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
diff --git a/sql-bench/Results/wisconsin-mysql-NT_4.0 b/sql-bench/Results/wisconsin-mysql-NT_4.0
new file mode 100644
index 00000000000..20d34da7f90
--- /dev/null
+++ b/sql-bench/Results/wisconsin-mysql-NT_4.0
@@ -0,0 +1,14 @@
+Testing server 'MySQL 3.23.17a alpha' at 2000-06-02 19:47:36
+
+Wisconsin benchmark test
+
+Time for create_table (3): 0 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Inserting data
+Time to insert (31000): 19 wallclock secs ( 2.52 usr 3.91 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time to delete_big (1): 0 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Running actual benchmark
+Time for wisc_benchmark (114): 9 wallclock secs ( 5.66 usr 1.53 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Total time: 29 wallclock secs ( 8.19 usr 5.44 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results/wisconsin-mysql-SunOS_5.5.1_sun4u b/sql-bench/Results/wisconsin-mysql-SunOS_5.5.1_sun4u
new file mode 100644
index 00000000000..2dc3ffa7ceb
--- /dev/null
+++ b/sql-bench/Results/wisconsin-mysql-SunOS_5.5.1_sun4u
@@ -0,0 +1,14 @@
+Testing server 'MySQL 3.22.19' at 1999-03-02 5:14:28
+
+Wisconsin benchmark test
+
+Time for create_table (3): 0 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Inserting data
+Time to insert (31000): 41 wallclock secs ( 4.36 usr 3.97 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time to delete_big (1): 2 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Running actual benchmark
+Time for wisc_benchmark (114): 16 wallclock secs ( 5.71 usr 2.51 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Total time: 59 wallclock secs (10.08 usr 6.48 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results/wisconsin-mysql-SunOS_5.7_sun4m b/sql-bench/Results/wisconsin-mysql-SunOS_5.7_sun4m
new file mode 100644
index 00000000000..607c908e9e9
--- /dev/null
+++ b/sql-bench/Results/wisconsin-mysql-SunOS_5.7_sun4m
@@ -0,0 +1,14 @@
+Testing server 'MySQL 3.22.20' at 1999-03-19 19:00:11
+
+Wisconsin benchmark test
+
+Time for create_table (3): 1 secs ( 0.00 usr 0.01 sys + 0.00 cusr 0.00 csys = 0.01 cpu)
+
+Inserting data
+Time to insert (31000): 169 secs (18.06 usr 20.38 sys + 0.00 cusr 0.00 csys = 38.44 cpu)
+Time to delete_big (1): 11 secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 cpu)
+
+Running actual benchmark
+Time for wisc_benchmark (114): 110 secs (29.24 usr 14.59 sys + 0.00 cusr 0.00 csys = 43.83 cpu)
+
+Total time: 291 secs (47.32 usr 34.98 sys + 0.00 cusr 0.00 csys = 82.30 cpu)
diff --git a/sql-bench/Results/wisconsin-mysql-SunOS_5.7_sun4u b/sql-bench/Results/wisconsin-mysql-SunOS_5.7_sun4u
new file mode 100644
index 00000000000..3dedbb0f4ce
--- /dev/null
+++ b/sql-bench/Results/wisconsin-mysql-SunOS_5.7_sun4u
@@ -0,0 +1,14 @@
+Testing server 'MySQL 3.23.8 alpha' at 2000-01-17 23:55:32
+
+Wisconsin benchmark test
+
+Time for create_table (3): 0 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Inserting data
+Time to insert (31000): 21 wallclock secs ( 1.90 usr 2.89 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time to delete_big (1): 0 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Running actual benchmark
+Time for wisc_benchmark (114): 9 wallclock secs ( 2.97 usr 2.12 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Total time: 30 wallclock secs ( 4.87 usr 5.02 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results/wisconsin-mysql-win98 b/sql-bench/Results/wisconsin-mysql-win98
new file mode 100644
index 00000000000..71bb6b4f3de
--- /dev/null
+++ b/sql-bench/Results/wisconsin-mysql-win98
@@ -0,0 +1,14 @@
+Testing server 'MySQL 3.23.13a alpha' at 2000-03-15 5:41:46
+
+Wisconsin benchmark test
+
+Time for create_table (3): 1 wallclock secs ( 0.99 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Inserting data
+Time to insert (31000): 44 wallclock secs (43.67 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time to delete_big (1): 1 wallclock secs ( 0.66 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Running actual benchmark
+Time for wisc_benchmark (114): 17 wallclock secs (17.08 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Total time: 63 wallclock secs (62.40 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results/wisconsin-mysql_3.21-Linux_2.0.35_i686 b/sql-bench/Results/wisconsin-mysql_3.21-Linux_2.0.35_i686
new file mode 100644
index 00000000000..d9046277c6f
--- /dev/null
+++ b/sql-bench/Results/wisconsin-mysql_3.21-Linux_2.0.35_i686
@@ -0,0 +1,14 @@
+Testing server 'MySQL 3.21.33' at 1998-08-21 14:42:57
+
+Wisconsin benchmark test
+
+Time for create_table (3): 0 secs ( 0.00 usr 0.00 sys = 0.00 cpu)
+
+Inserting data
+Time to insert (31000): 19 secs ( 1.36 usr 2.53 sys = 3.89 cpu)
+Time to delete_big (1): 1 secs ( 0.00 usr 0.00 sys = 0.00 cpu)
+
+Running actual benchmark
+Time for wisc_benchmark (114): 7 secs ( 1.04 usr 2.86 sys = 3.90 cpu)
+
+Total time: 27 secs ( 2.40 usr 5.39 sys = 7.79 cpu)
diff --git a/sql-bench/Results/wisconsin-mysql_fast-Linux_2.2.10_i686-cmp-msql,mysql b/sql-bench/Results/wisconsin-mysql_fast-Linux_2.2.10_i686-cmp-msql,mysql
new file mode 100644
index 00000000000..d9f356f165b
--- /dev/null
+++ b/sql-bench/Results/wisconsin-mysql_fast-Linux_2.2.10_i686-cmp-msql,mysql
@@ -0,0 +1,14 @@
+Testing server 'MySQL 3.23.3 alpha' at 1999-09-24 9:48:11
+
+Wisconsin benchmark test
+
+Time for create_table (3): 0 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Inserting data
+Time to insert (31000): 2 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time to delete_big (1): 1 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Running actual benchmark
+Time for wisc_benchmark (74): 4 wallclock secs ( 2.43 usr 0.29 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Total time: 7 wallclock secs ( 2.43 usr 0.29 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results/wisconsin-mysql_odbc-win98 b/sql-bench/Results/wisconsin-mysql_odbc-win98
new file mode 100644
index 00000000000..4da9b366a06
--- /dev/null
+++ b/sql-bench/Results/wisconsin-mysql_odbc-win98
@@ -0,0 +1,14 @@
+Testing server 'MySQL 3.22.19a' at 1999-03-02 19:02:03
+
+Wisconsin benchmark test
+
+Time for create_table (3): 1 wallclock secs ( 0.17 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Inserting data
+Time to insert (31000): 104 wallclock secs (104.19 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+Time to delete_big (1): 1 wallclock secs ( 1.15 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Running actual benchmark
+Time for wisc_benchmark (114): 29 wallclock secs (28.83 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
+
+Total time: 135 wallclock secs (134.46 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU)
diff --git a/sql-bench/Results/wisconsin-oracle-Linux_2.0.36_i686-cmp-mysql,oracle b/sql-bench/Results/wisconsin-oracle-Linux_2.0.36_i686-cmp-mysql,oracle
new file mode 100644
index 00000000000..8fb12cfaa67
--- /dev/null
+++ b/sql-bench/Results/wisconsin-oracle-Linux_2.0.36_i686-cmp-mysql,oracle
@@ -0,0 +1,14 @@
+Testing server 'Oracle 8.0.5.0.0' at 1999-03-25 4:21:44
+
+Wisconsin benchmark test
+
+Time for create_table (3): 0 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Inserting data
+Time to insert (31000): 108 wallclock secs (21.83 usr 2.52 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time to delete_big (1): 1 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Running actual benchmark
+Time for wisc_benchmark (114): 70 wallclock secs (30.55 usr 4.78 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Total time: 179 wallclock secs (52.39 usr 7.30 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
diff --git a/sql-bench/Results/wisconsin-oracle_fast-Linux_2.0.36_i686-cmp-mysql,oracle b/sql-bench/Results/wisconsin-oracle_fast-Linux_2.0.36_i686-cmp-mysql,oracle
new file mode 100644
index 00000000000..ea85252c6bc
--- /dev/null
+++ b/sql-bench/Results/wisconsin-oracle_fast-Linux_2.0.36_i686-cmp-mysql,oracle
@@ -0,0 +1,22 @@
+Testing server 'Oracle 8.0.5.0.0' at 1999-03-23 12:12:34
+
+Wisconsin benchmark test
+
+Time for create_table (3): 1 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Time for book-keeping (1): 0 wallclock secs ( 0.01 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Inserting data
+Time to insert (31000): 116 wallclock secs (22.64 usr 2.62 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for book-keeping (1): 4 wallclock secs ( 0.01 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Time to delete_big (1): 6 wallclock secs ( 0.03 usr 0.01 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Time for book-keeping (1): 3 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Running actual benchmark
+Time for wisc_benchmark (114): 63 wallclock secs (30.34 usr 4.90 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Time for book-keeping (1): 0 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Total time: 190 wallclock secs (53.06 usr 7.56 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
diff --git a/sql-bench/Results/wisconsin-pg-Linux_2.0.36_i686-cmp-mysql,pg,solid b/sql-bench/Results/wisconsin-pg-Linux_2.0.36_i686-cmp-mysql,pg,solid
new file mode 100644
index 00000000000..aabea5b54e1
--- /dev/null
+++ b/sql-bench/Results/wisconsin-pg-Linux_2.0.36_i686-cmp-mysql,pg,solid
@@ -0,0 +1,14 @@
+Testing server 'PostgreSQL 6.4' at 1999-03-10 1:01:47
+
+Wisconsin benchmark test
+
+Time for create_table (3): 0 wallclock secs ( 0.00 usr 0.01 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Inserting data
+Time to insert (31000): 142 wallclock secs (16.94 usr 1.84 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time to delete_big (1): 0 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Running actual benchmark
+Time for wisc_benchmark (114): 310 wallclock secs ( 5.05 usr 0.37 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Total time: 452 wallclock secs (22.00 usr 2.22 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
diff --git a/sql-bench/Results/wisconsin-pg_fast-Linux_2.0.36_i686-cmp-mysql,pg,solid b/sql-bench/Results/wisconsin-pg_fast-Linux_2.0.36_i686-cmp-mysql,pg,solid
new file mode 100644
index 00000000000..76ec51fb2e7
--- /dev/null
+++ b/sql-bench/Results/wisconsin-pg_fast-Linux_2.0.36_i686-cmp-mysql,pg,solid
@@ -0,0 +1,22 @@
+Testing server 'PostgreSQL 6.4' at 1999-03-11 13:43:36
+
+Wisconsin benchmark test
+
+Time for create_table (3): 0 wallclock secs ( 0.01 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Time for book-keeping (1): 0 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Inserting data
+Time to insert (31000): 130 wallclock secs (17.21 usr 1.94 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time for book-keeping (1): 1 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Time to delete_big (1): 1 wallclock secs ( 0.01 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Time for book-keeping (1): 4 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Running actual benchmark
+Time for wisc_benchmark (114): 29 wallclock secs ( 5.00 usr 0.27 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Time for book-keeping (1): 2 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Total time: 166 wallclock secs (22.23 usr 2.21 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
diff --git a/sql-bench/Results/wisconsin-solid-Linux_2.0.36_i686-cmp-mysql,pg,solid b/sql-bench/Results/wisconsin-solid-Linux_2.0.36_i686-cmp-mysql,pg,solid
new file mode 100644
index 00000000000..06d4cdc9d36
--- /dev/null
+++ b/sql-bench/Results/wisconsin-solid-Linux_2.0.36_i686-cmp-mysql,pg,solid
@@ -0,0 +1,14 @@
+Testing server 'SOLID Server - v.02.30.0026 (Linux ix86)' at 1999-03-06 17:41:55
+
+Wisconsin benchmark test
+
+Time for create_table (3): 0 wallclock secs ( 0.02 usr 0.01 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Inserting data
+Time to insert (31000): 154 wallclock secs (26.27 usr 2.34 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+Time to delete_big (1): 4 wallclock secs ( 0.00 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Running actual benchmark
+Time for wisc_benchmark (114): 55 wallclock secs (10.89 usr 0.42 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
+
+Total time: 226 wallclock secs (37.18 usr 2.77 sys + 0.00 cusr 0.00 csys = 0.00 CPU secs)
diff --git a/sql-bench/bench-init.pl.sh b/sql-bench/bench-init.pl.sh
new file mode 100755
index 00000000000..aca915f2914
--- /dev/null
+++ b/sql-bench/bench-init.pl.sh
@@ -0,0 +1,514 @@
+#@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
+#
+##########################################################
+# this is the base file every test is using ....
+# this is made for not changing every file if we want to
+# add an option or just want to change something in
+# code what is the same in every file ...
+##########################################################
+
+#
+# The exported values are:
+
+# $opt_... Various options
+# $date Current date in ISO format
+# $server Object for current server
+# $limits Hash reference to limits for benchmark
+
+$benchmark_version="2.8";
+use Getopt::Long;
+
+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=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_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",
+ "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","hires") || usage();
+
+usage() if ($opt_help);
+$server=get_server($opt_server,$opt_host,$opt_database,$opt_odbc,
+ machine_part());
+$limits=merge_limits($server,$opt_cmp);
+$date=date();
+@estimated=(0.0,0.0,0.0); # For estimated time support
+
+if ($opt_hires)
+{
+ eval "use Time::HiRes;";
+}
+
+{
+ my $tmp= $opt_server;
+ $tmp =~ s/_odbc$//;
+ if (length($opt_cmp) && index($opt_cmp,$tmp) < 0)
+ {
+ $opt_cmp.=",$tmp";
+ }
+}
+$opt_cmp=lc(join(",",sort(split(',',$opt_cmp))));
+
+#
+# set opt_lock_tables if one uses --fast and drivers supports it
+#
+
+if (($opt_lock_tables || $opt_fast) && $server->{'limits'}->{'lock_tables'})
+{
+ $opt_lock_tables=1;
+}
+else
+{
+ $opt_lock_tables=0;
+}
+if ($opt_fast)
+{
+ $opt_fast_insert=1;
+ $opt_suffix="_fast" if (!length($opt_suffix));
+}
+
+if ($opt_odbc)
+{
+ $opt_suffix="_odbc" if (!length($opt_suffix));
+}
+
+if (!$opt_silent)
+{
+ print "Testing server '" . $server->version() . "' at $date\n\n";
+}
+
+if ($opt_debug)
+{
+ print "\nCurrent limits: \n";
+ foreach $key (sort keys %$limits)
+ {
+ print $key . " " x (30-length($key)) . $limits->{$key} . "\n";
+ }
+ print "\n";
+}
+
+#
+# Some help functions
+#
+
+sub skip_arguments
+{
+ my($argv,@skip_args)=@_;
+ my($skip,$arg,$name,@res);
+
+ foreach $arg (@$argv)
+ {
+ if ($arg =~ /^\-+([^=]*)/)
+ {
+ $name=$1;
+ foreach $skip (@skip_args)
+ {
+ if (index($skip,$name) == 0)
+ {
+ $name=""; # Don't use this parameters
+ last;
+ }
+ }
+ push (@res,$arg) if (length($name));
+ }
+ }
+ return @res;
+}
+
+
+sub merge_limits
+{
+ my ($server,$cmp)= @_;
+ my ($name,$tmp_server,$limits,$res_limits,$limit,$tmp_limits);
+
+ $res_limits=$server->{'limits'};
+ if ($cmp)
+ {
+ foreach $name (split(",",$cmp))
+ {
+ $tmp_server= get_server($name,$opt_host, $opt_database,
+ $opt_odbc) || die "Unknown SQL server: $name\n";
+ $limits=$tmp_server->{'limits'};
+ %new_limits=();
+ foreach $limit (keys(%$limits))
+ {
+ if (defined($res_limits->{$limit}) && defined($limits->{$limit}))
+ {
+ $new_limits{$limit}=min($res_limits->{$limit},$limits->{$limit});
+ }
+ }
+ %tmp_limits=%new_limits;
+ $res_limits=\%tmp_limits;
+ }
+ }
+ return $res_limits;
+}
+
+sub date
+{
+ my ($sec, $min, $hour, $mday, $mon, $year) = localtime(time());
+ sprintf("%04d-%02d-%02d %2d:%02d:%02d",
+ 1900+$year,$mon+1,$mday,$hour,$min,$sec);
+}
+
+sub min
+{
+ my($min)=$_[0];
+ my($i);
+ for ($i=1 ; $i <= $#_; $i++)
+ {
+ $min=$_[$i] if ($min > $_[$i]);
+ }
+ return $min;
+}
+
+sub max
+{
+ my($max)=$_[0];
+ my($i);
+ for ($i=1 ; $i <= $#_; $i++)
+ {
+ $max=$_[$i] if ($max < $_[$i]);
+ }
+ return $max;
+}
+
+
+#
+# Execute many statements in a row
+#
+
+sub do_many
+{
+ my ($dbh,@statements)=@_;
+ my ($statement,$sth);
+
+ foreach $statement (@statements)
+ {
+ if (!($sth=$dbh->do($statement)))
+ {
+ die "Can't execute command '$statement'\nError: $DBI::errstr\n";
+ }
+ }
+}
+
+sub safe_do_many
+{
+ my ($dbh,@statements)=@_;
+ my ($statement,$sth);
+
+ foreach $statement (@statements)
+ {
+ if (!($sth=$dbh->do($statement)))
+ {
+ print STDERR "Can't execute command '$statement'\nError: $DBI::errstr\n";
+ return 1;
+ }
+ }
+ return 0;
+}
+
+
+
+#
+# Do a query and fetch all rows from a statement and return the number of rows
+#
+
+sub fetch_all_rows
+{
+ my ($dbh,$query,$must_get_result)=@_;
+ my ($count,$sth);
+ $count=0;
+
+ print "$query: " if ($opt_debug);
+ if (!($sth= $dbh->prepare($query)))
+ {
+ print "\n" if ($opt_debug);
+ die "Error occured with prepare($query)\n -> $DBI::errstr\n";
+ return undef;
+ }
+ if (!$sth->execute)
+ {
+ print "\n" if ($opt_debug);
+ die "Error occured with execute($query)\n -> $DBI::errstr\n";
+ $sth->finish;
+ return undef;
+ }
+ while ($sth->fetchrow_arrayref)
+ {
+ $count++;
+ }
+ print "$count\n" if ($opt_debug);
+ if (defined($must_get_result) && $must_get_result && !$count)
+ {
+ die "Error: Query $query didn't return any rows\n";
+ }
+ $sth->finish;
+ undef($sth);
+ return $count;
+}
+
+sub do_query
+{
+ my($dbh,$query)=@_;
+ print "$query\n" if ($opt_debug);
+ $dbh->do($query) or
+ die "\nError executing '$query':\n$DBI::errstr\n";
+}
+
+
+#
+# Handle estimated time of the server is too slow
+# Returns 0 if one should continue as normal
+#
+
+sub predict_query_time
+{
+ my ($loop_time,$end_time,$count_ref,$loop,$loop_count)= @_;
+ my ($k,$tmp);
+
+ if (($end_time->[0] - $loop_time->[0]) > $opt_time_limit)
+ {
+ # We can't wait until the SUN dies. Try to predict the end time
+ if ($loop != $loop_count)
+ {
+ $tmp=($end_time->[0] - $loop_time->[0]);
+ print "Note: Query took longer then time-limit: $opt_time_limit\nEstimating end time based on:\n";
+ print "$$count_ref queries in $loop loops of $loop_count loops took $tmp seconds\n";
+ for ($k=0; $k < 3; $k++)
+ {
+ $tmp=$loop_time->[$k]+($end_time->[$k]-$loop_time->[$k])/$loop*
+ $loop_count;
+ $estimated[$k]+=($tmp-$end_time->[$k]);
+ $end_time->[$k]=$tmp;
+ }
+ $$count_ref= int($$count_ref/$loop*$loop_count);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+#
+# standard end of benchmark
+#
+
+sub end_benchmark
+{
+ my ($start_time)=@_;
+
+ $end_time=new Benchmark;
+ if ($estimated[0])
+ {
+ print "Estimated total time: ";
+ $end_time->[0]+=$estimated[0];
+ $end_time->[1]+=$estimated[1];
+ $end_time->[2]+=$estimated[2];
+ }
+ else
+ {
+ print "Total time: "
+ }
+ print timestr(timediff($end_time, $start_time),"all") . "\n";
+ exit 0;
+}
+
+#
+# Create a filename part for the machine that can be used for log file.
+#
+
+sub machine_part
+{
+ my ($name);
+ return $opt_machine if (length($opt_machine)); # Specified by user
+ $name=machine();
+ $name="win9$1" if ($name =~ /win.*9(\d)/i);
+ $name="NT_$1" if ($name =~ /Windows NT.*(\d+\.\d+)/i);
+ $name =~ s/\s+/_/g; # Make the filenames easier to parse
+ $name =~ s/-/_/g;
+ $name =~ s/\//_/g;
+ return $name;
+}
+
+sub machine
+{
+ $name= `uname -s -r -m`;
+ if ($?)
+ {
+ $name= `uname -s -m`;
+ }
+ if ($?)
+ {
+ $name= `uname -s`;
+ }
+ if ($?)
+ {
+ $name= `uname`;
+ }
+ if ($?)
+ {
+ $name="unknown";
+ }
+ chomp($name); $name =~ s/[\n\r]//g;
+ return $name;
+}
+
+#
+# Usage
+#
+
+sub usage
+{
+ print <<EOF;
+The MySQL benchmarks Ver $benchmark_version
+
+All benchmarks takes the following options:
+
+--comments
+ Add a comment to the benchmark output. Comments should contain
+ extra information that 'uname -a' doesn\'t give and if the database was
+ stared with some specific, non default, options.
+
+--database (Default $opt_database)
+ In which database the test tables are created.
+
+--debug
+ This is a test specific option that is only used when debugging a test.
+ Print out debugging information.
+
+--dir (Default $opt_dir)
+ Option to 'run-all-tests' to where the test results should be stored.
+
+--fast
+ Allow the database to use non standard ANSI SQL commands to make the
+ test go faster.
+
+--fast-insert
+ Use "insert into table_name values(...)" instead of
+ "insert into table_name (....) values(...)"
+ If the database supports it, some tests uses multiple value lists.
+
+--field-count
+ This is a test specific option that is only used when debugging a test.
+ This usually means how many fields there should be in the test table.
+
+--force
+ This is a test specific option that is only used when debugging a test.
+ Continue the test even if there is some error.
+ Delete tables before creating new ones.
+
+--groups (Default $opt_groups)
+ This is a test specific option that is only used when debugging a test.
+ This usually means how many different groups there should be in the test.
+
+--lock-tables
+ Allow the database to use table locking to get more speed.
+
+--log
+ Option to 'run-all-tests' to save the result to the '--dir' directory.
+
+--loop-count (Default $opt_loop_count)
+ This is a test specific option that is only used when debugging a test.
+ This usually means how many times times each test loop is executed.
+
+--help
+ Shows this help
+
+--host='host name' (Default $opt_host)
+ Host name where the database server is located.
+
+--machine="machine or os_name"
+ The machine/os name that is added to the benchmark output filename.
+ The default is the OS name + version.
+
+--odbc
+ Use the ODBC DBI driver to connect to the database.
+
+--password='password'
+ Password for the current user.
+
+--regions
+ This is a test specific option that is only used when debugging a test.
+ This usually means how AND levels should be tested.
+
+--old-headers
+ Get the old benchmark headers from the old RUN- file.
+
+--server='server name' (Default $opt_server)
+ Run the test on the given SQL server.
+ Known servers names are: Access, Adabas, AdabasD, Empress, Oracle,
+ Informix, DB2, mSQL, MS-SQL, MySQL, Pg, Solid and Sybase
+
+--skip-delete
+ This is a test specific option that is only used when debugging a test.
+ This will keep the test tables after the test is run.
+
+--skip-test=test1[,test2,...]
+ For run-all-programs; Don\'t execute the named tests
+
+--small-test
+ This runs some tests with smaller limits to get a faster test.
+ Can be used if you just want to verify that the database works, but
+ don't have time to run a full test.
+
+--small-tables
+ This runs some tests that generate big tables with fewer rows.
+ This can be used with databases that can\'t handle that many rows
+ because of pre-sized partitions.
+
+--suffix (Default $opt_suffix)
+ The suffix that is added to the database name in the benchmark output
+ filename. This can be used to run the benchmark multiple times with
+ different server options without overwritten old files.
+ When using --fast the suffix is automaticly set to '_fast'.
+
+--time-limit (Default $opt_time_limit)
+ How long a test loop is allowed to take, in seconds, before the end result
+ is 'estimated'.
+
+--use-old-results
+ Option to 'run-all-tests' to use the old results from the '--dir' directory
+ instead of running the tests.
+
+--user='user_name'
+ User name to log into the SQL server.
+
+--verbose
+ This is a test specific option that is only used when debugging a test.
+ Print more information about what is going on.
+EOF
+ exit(0);
+}
+
+
+
+####
+#### The end of the base file ...
+####
+1;
diff --git a/sql-bench/compare-results.sh b/sql-bench/compare-results.sh
new file mode 100755
index 00000000000..7b2ba95da5c
--- /dev/null
+++ b/sql-bench/compare-results.sh
@@ -0,0 +1,630 @@
+#!@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
+#
+# a little program to generate a table of results
+# just read all the RUN-*.log files and format them nicely
+# Made by Luuk de Boer
+# Patched by Monty
+
+use Getopt::Long;
+
+$opt_server="mysql";
+$opt_dir="output";
+$opt_machine="";
+$opt_relative=$opt_same_server=$opt_help=$opt_Information=$opt_skip_count=$opt_no_bars=$opt_verbose=0;
+
+GetOptions("Information","help","server=s","cmp=s","machine=s","relative","same-server","dir=s","skip-count","no-bars","html","verbose") || usage();
+
+usage() if ($opt_help || $opt_Information);
+
+$opt_cmp=lc(join(",",sort(split(',',$opt_cmp))));
+
+if ($opt_same_server)
+{
+ $files="$opt_dir/RUN-$opt_server*$opt_machine";
+}
+else
+{
+ $files="$opt_dir/RUN-*$opt_machine";
+}
+$files.= "-cmp-$opt_cmp" if (length($opt_cmp));
+
+#
+# Go trough all RUN files and gather statistics.
+#
+
+if ($#ARGV == -1)
+{
+ @ARGV=glob($files);
+ $automatic_files=1;
+}
+else
+{
+ $opt_cmp="";
+}
+
+foreach (@ARGV)
+{
+ next if (!$opt_cmp && /-cmp-/ && $automatic_files || defined($found{$_}));
+ $prog=$filename = $_;
+ $found{$_}=1; # Remove dupplicates
+ /RUN-(.*)$/;
+ $tot{$prog}{'version'}=$1;
+ push(@key_order,$prog);
+ $next = 0;
+ open(TMP, "<$filename") || die "Can't open $filename: $!\n";
+ while (<TMP>)
+ {
+ chomp;
+ if ($next == 0) {
+ if (/Server version:\s+(\S+.*)/i)
+ {
+ $tot{$prog}{'server'} = $1;
+ }
+ elsif (/Arguments:\s+(.+)/i)
+ {
+ $arguments= $1;
+ # Remove some standard, not informative arguments
+ $arguments =~ s/--force|--log|--use-old\S*|--server=\S+|--cmp=\S+|--user=\S+|--pass=\S+|--machine=\S+|--dir=\S+//g;
+ if (($tmp=index($arguments,"--comment")) >= 0)
+ {
+ if (($end=index($arguments,$tmp+2,"--")) >= 0)
+ {
+ substr($arguments,$tmp,($end-$tmp))="";
+ }
+ else
+ {
+ $arguments=substr($arguments,0,$tmp);
+ }
+ }
+ $arguments =~ s/\s+/ /g;
+ $tot{$prog}{'arguments'}=$arguments;
+ }
+ elsif (/Comments:\s+(.+)/i) {
+ $tot{$prog}{'comments'} = $1;
+ } elsif (/^(\S+):\s*(estimated\s|)total\stime:\s+([\d.]+)\s+(wallclock\s|)secs/i)
+ {
+ $tmp = $1; $tmp =~ s/://;
+ $tot{$prog}{$tmp} = [ $3, (length($2) ? "+" : "")];
+ $op1{$tmp} = $tmp;
+ } elsif (/Totals per operation:/i) {
+ $next = 1;
+ next;
+ }
+ }
+ elsif ($next == 1)
+ {
+ if (/^(\S+)\s+([\d.]+)\s+([\d.]+)\s+([\d.]+)\s+([\d.]+)\s+([\d.]+)\s*([+|?])*/)
+ {
+ $tot1{$prog}{$1} = [$2,$6,$7];
+ $op{$1} = $1;
+ }
+ }
+ }
+}
+
+if (!%op)
+{
+ print "Didn't find any files matching: '$files'\n";
+ print "Use the --cmp=server,server option to compare benchmarks\n";
+ exit 1;
+}
+
+
+# everything is loaded ...
+# now we have to create a fancy output :-)
+
+# I prefer to redirect scripts instead to force it to file ; Monty
+#
+# open(RES, ">$resultfile") || die "Can't write to $resultfile: $!\n";
+# select(RES)
+#
+
+if ($opt_html) {
+ html_output();
+} else {
+ ascii_output();
+}
+exit 0;
+
+#
+# some output + format functions;
+#
+
+sub ascii_output {
+ print <<EOF;
+This is the result file of the different benchmark tests.
+
+The number in () after each tests shows how many SQL commands the particular
+test did. As one test may have many different parameters this gives only
+a rough picture of what was done. Check the source for more information :)
+
+Keep in mind that one can\'t compare benchmarks run with different --cmp
+options. The --cmp options sets the all limits according to the worst
+limit for all server in the benchmark.
+
+Numbers marked with '+' are estimated according to previous runs because
+the query took longer than a given time-limit to finish. The estimation
+shouldn\'t be far from the real result thought.
+
+Numbers marked with '?' contains results that gave wrong result. This can only
+be used as an indication of how long it took for the server to produce a wrong
+result :)
+
+Numbers marked with '*' are tests that was run a different number times
+than the test in the first column. The reason for this is normally that the
+marked test was run with different options that affects the number of tests
+or that the test was from another version of the MySQL benchmarks.
+
+Hope this will give you some idea how each db is performing at what thing ....
+Hope you like it .... Luuk & Monty (1997)
+
+EOF
+
+ if ($opt_relative)
+ {
+ print "Column 1 is in seconds. All other columns are presented relative\n";
+ print "to this. 1.00 is the same, bigger numbers indicates slower\n\n";
+ }
+
+ if ($opt_verbose)
+ {
+ print "The test values is printed in the format 'time:number of tests'\n";
+ }
+
+ if (length($opt_cmp))
+ {
+ print "The test was run with limits from: $opt_cmp\n\n";
+ }
+ print "The result logs which where found and the options:\n";
+ $bar= $opt_no_bars ? " " : "|";
+
+ # Move $opt_server first in array if not filename on command line
+ if ($automatic_files)
+ {
+ @key_order=sort {$a cmp $b} keys %tot;
+ for ($i=0; $i <= $#key_order; $i++)
+ {
+ if ($tot{$key_order[$i]}{'version'} =~ /^$opt_server-/)
+ {
+ unshift(@key_order,$key_order[$i]);
+ splice(@key_order,$i+1,1);
+ last;
+ }
+ }
+ }
+ # Print header
+
+ $column_count=0;
+ foreach $key (@key_order)
+ {
+ $tmp=$tmp=$tot{$key}{'version'};
+ $tmp =~ s/-cmp-$opt_cmp// if (length($opt_cmp));
+ $column_count++;
+ printf "%2d %-40.40s: %s %s\n", $column_count, $tmp,
+ $tot{$key}{'server'}, $tot{$key}{'arguments'};
+ print " $tot{$key}{'comments'}\n"
+ if ($tot{$key}{'comments'} =~ /\w+/);
+ }
+
+ print "\n";
+
+ $namewidth=($opt_skip_count && !$opt_verbose) ? 29 : 36;
+ $colwidth= $opt_relative ? 10 : 7;
+ $count_width=7;
+ $colwidth+=$count_width if ($opt_verbose);
+
+ print_sep("=");
+ printf "%-$namewidth.${namewidth}s${bar}", "Operation";
+ $count = 1;
+ foreach $key (@key_order)
+ {
+ printf "%${colwidth}d${bar}", $count;
+ $count++;
+ }
+ printf "\n%-$namewidth.${namewidth}s${bar}", "";
+ foreach $key (@key_order)
+ {
+ $ver=$tot{$key}{'version'};
+ $ver =~ s/-[a-zA-Z0-9_\.]+-cmp-$opt-cmp$//;
+ printf "%${colwidth}.${colwidth}s${bar}", $ver;
+ }
+ print "\n";
+ print_sep("-");
+ print_string($opt_relative ? "Relative results per test (First column is in seconds):" : "Results per test in seconds:");
+ print_sep("-");
+
+ foreach $key (sort {$a cmp $b} keys %op1)
+ {
+ printf "%-$namewidth.${namewidth}s${bar}", $key;
+ $first=undef();
+ foreach $server (@key_order)
+ {
+ print_value($first,$tot{$server}{$key}->[0],undef(),$tot{$server}{$key}->[1]);
+ $first=$tot{$server}{$key}->[0] if (!defined($first));
+ }
+ print "\n";
+ }
+
+ print_sep("-");
+ print_string("The results per operation:");
+ print_sep("-");
+
+ foreach $key (sort {$a cmp $b} keys %op)
+ {
+ next if ($key =~ /TOTALS/i);
+ $tmp=$key;
+ $count=$tot1{$key_order[0]}{$key}->[1];
+ $tmp.= " (" . $count . ")" if (!$skip_count);
+ printf "%-$namewidth.${namewidth}s${bar}", $tmp;
+ $first=undef();
+ foreach $server (@key_order)
+ {
+ $tmp= $count != $tot1{$server}{$key}->[1] ? "*" : "";
+ print_value($first,$tot1{$server}{$key}->[0],$tot1{$server}{$key}->[1],
+ $tot1{$server}{$key}->[2] . $tmp);
+ $first=$tot1{$server}{$key}->[0] if (!defined($first));
+ }
+ print "\n";
+ }
+
+ print_sep("-");
+ $key="TOTALS";
+ printf "%-$namewidth.${namewidth}s${bar}", $key;
+ $first=undef();
+ foreach $server (@key_order)
+ {
+ print_value($first,$tot1{$server}{$key}->[0],undef(),
+ $tot1{$server}{$key}->[2]);
+ $first=$tot1{$server}{$key}->[0] if (!defined($first));
+ }
+ print "\n";
+ print_sep("=");
+}
+
+
+sub html_output
+{
+ my $template="template.html";
+ my $title="MySQL Benchmark Results - Compare with $opt_cmp";
+ my $image="info.gif";
+ $bar="";
+
+ open(TEMPLATE, $template) || die;
+ while (<TEMPLATE>)
+ {
+ if (/<center>/)
+ {
+ print $_;
+ print "<!---- This is AUTOMATICALLY Generated. Do not edit here! ---->\n";
+ }
+ elsif (/TITLE:SUBTITLE/)
+ {
+ s|TITLE:SUBTITLE|$title|;
+ print $_;
+ }
+ elsif (m|/images/.gif|)
+ {
+ s|/images/.gif|/images/$image|;
+ s|alt=""|alt="$title"|;
+ print $_;
+ }
+ # Find line to inactivate
+ elsif (m|<img src="/images/${text}1.gif" border="0" width="66" height="20" alt="$text">|)
+ {
+ # Print inactive thing
+ print '<td align="center" bgcolor="#310063"><img src="/images/zero.gif" border="0" width="66" height="20" alt=""></td>';
+ }
+ elsif (/ subchapter name /)
+ {
+ # Nothing here for now
+ print $_;
+ }
+ elsif (/ text of chapter /)
+ {
+ print $_;
+ print_html_body();
+ }
+ else
+ {
+ print $_;
+ }
+ }
+ close(TEMPLATE);
+}
+
+
+sub print_html_body
+{
+ my ($title,$count,$key);
+ print <<EOF;
+<center>
+<font size=+4><b>MySQL Benchmark Results</b></font><br>
+<font size=+1><b>Compare with $opt_cmp</b></font><p><p>
+</center>
+This is the result file of the different benchmark tests.
+<p>
+
+The number in () after each tests shows how many SQL commands the particular
+test did. As one test may have many different parameters this gives only
+a rough picture of what was done. Check the source for more information.
+<p>
+Keep in mind that one can\'t compare benchmarks run with different --cmp
+options. The --cmp options sets the all limits according to the worst
+limit for all server in the benchmark.
+<p>
+Numbers marked with '+' are estimated according to previous runs because
+the query took longer than a given time-limit to finish. The estimation
+shouldn\'t be far from the real result thought.
+<p>
+Numbers marked with '?' contains results that gave wrong result. This can only
+be used as an indication of how long it took for the server to produce a wrong
+result :)
+<p>
+Hope this will give you some idea how each db is performing at what thing ....
+<br>
+Hope you like it .... Luuk & Monty (1997)
+<p><p>
+EOF
+
+ if ($opt_relative)
+ {
+ print "Column 1 is in seconds. All other columns are presented relative<br>\n";
+ print "to this. 1.00 is the same, bigger numbers indicates slower<p>\n\n";
+ }
+
+ if (length($opt_cmp))
+ {
+ print "The test was run with limits from: $opt_cmp\n\n";
+ }
+ print "The result logs which where found and the options:<br>\n";
+
+ # Move $opt_server first in array
+ if ($automatic_files)
+ {
+ @key_order=sort {$a cmp $b} keys %tot;
+ for ($i=0; $i <= $#key_order; $i++)
+ {
+ if ($tot{$key_order[$i]}{'version'} =~ /^$opt_server-/)
+ {
+ unshift(@key_order,$key_order[$i]);
+ splice(@key_order,$i+1,1);
+ last;
+ }
+ }
+ }
+ # Print header
+ print "<p><center><table border=1 width=100%>\n";
+ $column_count=0;
+ foreach $key (@key_order)
+ {
+ $tmp=$tot{$key}{'version'};
+ $tmp =~ s/-cmp-$opt_cmp// if (length($opt_cmp));
+ $column_count++;
+# printf "<tr><td>%2d<td>%-36.36s<td>%s %s</tr>\n", $column_count, $tmp,
+ printf "<tr><td>%2d</td><td>%s</td><td>%s %s</td></tr>\n",
+ $column_count, $tmp, $tot{$key}{'server'}, $tot{$key}{'arguments'};
+ print "<tr><td colspan=3>$tot{$key}{'comments'}</td></tr>\n"
+ if ($tot{$key}{'comments'} =~ /\w+/);
+ }
+
+ print "</table></center><p><center><table border=1 width=100%>\n";
+
+ $namewidth=$opt_skip_count ? 22 :29;
+ $colwidth= $opt_relative ? 10 : 7;
+ $count_width=7;
+
+ printf "<tr><td><b>%s</b></td>\n", "Operation";
+ $count = 1;
+ foreach $key (@key_order)
+ {
+ $ver=$tot{$key}{'version'};
+ printf "<td align=center><b>%d", $count;
+ printf "<br>%${colwidth}.${colwidth}s</b></td>\n", substr($ver,0,index($ver,"-"));
+ $count++;
+ }
+ print "</tr>\n";
+ $title = $opt_relative ? "Relative results per test (First column is in seconds):" : "Results per test in seconds:";
+ printf "<tr><td colspan=%d><b>%s</b></td></tr>\n", $count, $title;
+
+ foreach $key (sort {$a cmp $b} keys %op1)
+ {
+ if (!$opt_html)
+ {
+ printf "<tr><td>%-$namewidth.${namewidth}s</td>", $key;
+ }
+ else
+ {
+ print "<tr><td>$key</td>";
+ }
+ $first=undef();
+ foreach $server (@key_order)
+ {
+ print_value($first,$tot{$server}{$key}->[0],undef(),
+ $tot{$server}{$key}->[1]);
+ $first=$tot{$server}{$key}->[0] if (!defined($first));
+ }
+ print "</tr>\n";
+ }
+
+ $title = "The results per operation:";
+ printf "<tr><td colspan=%d><b>%s</b></td></tr>\n", $count, $title;
+
+ foreach $key (sort {$a cmp $b} keys %op)
+ {
+ next if ($key =~ /TOTALS/i);
+ $tmp=$key;
+ $tmp.= " (" . $tot1{$key_order[0]}{$key}->[1] . ")" if (!$skip_count);
+ if (!$opt_html)
+ {
+ printf "<tr><td>%-$namewidth.${namewidth}s</td>", $tmp;
+ }
+ else
+ {
+ print "<tr><td>$tmp</td>";
+ }
+ $first=undef();
+ foreach $server (@key_order)
+ {
+ print_value($first,$tot1{$server}{$key}->[0],
+ $tot1{$server}{$key}->[1],
+ $tot1{$server}{$key}->[2]);
+ $first=$tot1{$server}{$key}->[0] if (!defined($first));
+ }
+ print "</tr>\n";
+ }
+
+ $key="TOTALS";
+ printf "<tr><td><b>%-$namewidth.${namewidth}s</b></td>", $key;
+ $first=undef();
+ foreach $server (@key_order)
+ {
+ print_value($first,$tot1{$server}{$key}->[0],undef(),
+ $tot1{$server}{$key}->[2]);
+ $first=$tot1{$server}{$key}->[0] if (!defined($first));
+ }
+ print "</tr>\n</table>\n";
+}
+
+
+sub print_sep
+{
+ my ($sep)=@_;
+ print $sep x ($namewidth + (($colwidth+1) * $column_count)+1),"\n";
+}
+
+
+sub print_value
+{
+ my ($first,$value,$count,$flags)=@_;
+ my ($tmp,$width);
+
+ if (defined($value))
+ {
+ if (!defined($first) || !$opt_relative)
+ {
+ $tmp=sprintf("%.2f",$value);
+ }
+ else
+ {
+ $first=1 if (!$first == 0);# Assume that it took one second instead of 0
+ $tmp= sprintf("%.2f",$value/$first);
+ }
+ if (defined($flags))
+ {
+ $tmp="+".$tmp if ($flags =~ /\+/);
+ $tmp="?".$tmp if ($flags =~ /\?/);
+ $tmp="*".$tmp if ($flags =~ /\*/);
+ }
+ }
+ else
+ {
+ $tmp="";
+ }
+ $width= ($opt_verbose ? $colwidth - $count_width : $colwidth);
+ if (!$opt_html)
+ {
+ $tmp= " " x ($width-length($tmp)) . $tmp if (length($tmp) < $width);
+ }
+ if ($opt_verbose)
+ {
+ if ($count)
+ {
+ $tmp.= ":" . " " x ($count_width-1-length($count)) . $count;
+ }
+ else
+ {
+ $tmp.= " " x ($count_width);
+ }
+ }
+
+ if (!$opt_html) {
+ print $tmp . "${bar}";
+ } else {
+ print "<td align=right>$tmp</td>";
+ }
+}
+
+
+sub print_string
+{
+ my ($str)=@_;
+ if (!$opt_html)
+ {
+ my ($width);
+ $width=$namewidth + ($colwidth+1)*$column_count;
+ $str=substr($str,1,$width) if (length($str) > $width);
+ print($str," " x ($width - length($str)),"${bar}\n");
+ }
+ else
+ {
+ print $str,"\n";
+ }
+}
+
+
+sub usage
+{
+ print <<EOF;
+$0 Ver 1.2
+
+This program parses all RUN files from old 'run-all-tests --log' scripts
+and makes a nice comparable table.
+
+$0 takes currently the following options:
+
+--help or --Information
+ Shows this help
+
+--cmp=server,server,server (Default $opt_cmp)
+Compares all runs that are done with the same --cmp options to run-all-tests.
+The most normal options are '--cmp=mysql,pg,solid' and '--cmp ""'
+
+--dir=... (Default $opt_dir)
+From which directory one should get the runs. All runs made by
+run-all-tests --log is saved in the 'output' directory.
+In the 'results' directory you may have some example runs from different
+databases.
+
+--html
+ Print the table in html format.
+
+--machine='full-machine-name' (Default $opt_machine)
+Use only runs that match this machine.
+
+--relative
+Show all numbers in times of the first server where the time for the
+first server is 1.0
+
+--same-server
+Compare all runs for --server=.... The --machine is not used in this case
+This is nice to compare how the same server runs on different machines.
+
+--server='server name' (Default $opt_server)
+Put this server in the first result column.
+
+--skip-count
+Do not write the number of tests after the test-name.
+
+--verbose
+Write the number of tests in each column. This is useful when some column
+is marked with '*'.
+EOF
+
+ exit(0);
+}
diff --git a/sql-bench/copy-db.sh b/sql-bench/copy-db.sh
new file mode 100755
index 00000000000..245aa4e79b6
--- /dev/null
+++ b/sql-bench/copy-db.sh
@@ -0,0 +1,371 @@
+#!@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
+#
+# start initialition
+#
+
+$VER = "1.0";
+
+use Getopt::Long;
+use DBI;
+
+$max_row_length=500000; # Don't create bigger SQL rows that this
+$opt_lock=1; # lock tables
+
+chomp($pwd = `pwd`); $pwd = "." if ($pwd eq '');
+
+require "$pwd/server-cfg" || die "Can't read Configuration file: $!\n";
+
+$|=1;
+
+$opt_from_server= $opt_to_server= "mysql";
+$opt_from_host= $opt_to_host= "localhost";
+$opt_from_db= $opt_to_db= "test";
+$opt_from_user=$opt_from_password=$opt_to_user=$opt_to_password="";
+$opt_help=$opt_verbose=$opt_debug=0;
+
+
+GetOptions("from-server=s","to-server=s","from-host=s","to-host=s","from-db=s",
+ "to-db=s", "help", "verbose","debug") || usage();
+
+usage() if ($opt_help ||
+ ($opt_from_server eq $opt_to_server &&
+ $opt_from_db eq $opt_to_db &&
+ $opt_from_host eq $opt_to_host));
+
+####
+#### Usage
+####
+
+
+sub usage
+{
+ print <<EOF;
+
+$0 version $VER by Monty
+
+ Copies tables between two database servers. If the destination table doesn\'t
+ exist it\'s autoamticly created. If the destination table exists, it
+ should be compatible with the source table.
+
+ Because DBI doesn\'t provide full information about the columns in a table,
+ some columns may not have optimal types in a create tables. Any created
+ tables will also not have any keys!
+
+ Usage: $0 [options] tables...
+
+ Options:
+ --help Show this help and exit
+ --from-server Source server (Default: $opt_from_server)
+ --from-host Source hostname (Default: $opt_from_host)
+ --from-db Source database name (Default: $opt_from_db)
+ --from-user Source user (Default: $opt_from_password)
+ --from-password Source password (Default: $opt_from_password)
+ --to-server Destination server (Default: $opt_to_server)
+ --to-host Destination hostname (Default: $opt_to_host)
+ --to-db Destination database name (Default: $opt_to_db)
+ --to-user Destination user (Default: $opt_to_user)
+ --to-password Destination password (Default: $opt_to_password)
+ --verbose Be more verbose
+
+ If you the server names ends with _ODBC, then this program will connect
+ through ODBC instead of using a native driver.
+EOF
+ exit(0);
+}
+
+####
+#### Connect
+####
+
+$from_server=get_server($opt_from_server,$opt_from_host,$opt_from_db);
+$to_server=get_server($opt_to_server,$opt_to_host,$opt_to_db);
+
+$opt_user=$opt_from_user; $opt_password=$opt_from_password;
+print "- connecting to SQL servers\n" if ($opt_verbose);
+$from_dbh=$from_server->connect() || die "Can't connect to source server $opt_from_server on host $opt_from_host using db $opt_from_db";
+$opt_user=$opt_to_user; $opt_password=$opt_to_password;
+$to_dbh=$to_server->connect() || die "Can't connect to source server $opt_to_server on host $opt_to_host using db $opt_to_db";
+
+####
+#### Copy data
+####
+
+foreach $table (@ARGV)
+{
+
+ print "- querying $table\n" if ($opt_verbose);
+ $sth=$from_dbh->prepare("select * from $table") || die "Can't prepare query to get $table; $DBI::errstr";
+ $sth->execute || die "Can't execute query to get data from $table; $DBI::errstr";
+
+ if (!table_exists($to_server,$to_dbh,$table))
+ {
+ print "- creating $table\n" if ($opt_verbose);
+ $table_def=get_table_definition($from_server,$from_dbh,$sth);
+ do_many($to_dbh,$to_server->create($table,$table_def,[]));
+ }
+ if ($opt_lock && $to_server->{'lock_tables'})
+ {
+ print "- locking $table\n" if ($opt_verbose);
+ $to_dbh->do("lock tables $table WRITE");
+ }
+
+ $columns=$sth->{NUM_OF_FIELDS};
+ $columns_to_quote=get_columns_to_quote($sth);
+ $multi_value_insert=$sth->{'multi_value_insert'};
+ $query="insert into $table values"; $result="";
+
+ print "- copying $table\n" if ($opt_verbose);
+ while (($row = $sth->fetchrow_arrayref))
+ {
+ $tmp="(";
+ for ($i=0 ; $i < $columns ; $i++)
+ {
+ if ($columns_to_quote->[$i])
+ {
+ $tmp.= $to_dbh->quote($row->[$i]) . ",";
+ }
+ else
+ {
+ $tmp.= $row->[$i] . ",";
+ }
+ }
+ substr($tmp,-1)=")"; # Remove last ','
+ if ($multi_value_insert)
+ {
+ $to_dbh->do($query . $tmp) || die "Can't insert row: $DBI::errstr";
+ }
+ elsif (length($result)+length($tmp) >= $max_row_length && $result)
+ {
+ $to_dbh->do($query . $result) || die "Can't insert row: $DBI::errstr";
+ $result="";
+ }
+ elsif (length($result))
+ {
+ $result.= ",$tmp";
+ }
+ else
+ {
+ $result=$tmp;
+ }
+ }
+ if (length($result))
+ {
+ $to_dbh->do($query . $result) || die "Can't insert row: $DBI::errstr";
+ }
+ if ($opt_lock && $to_server->{'lock_tables'})
+ {
+ $to_dbh->do("unlock tables");
+ }
+}
+
+
+sub get_table_definition
+{
+ my ($server,$dbh,$sth)=@_;
+ my ($i,$names,$types,$scale,$precision,$nullable,@res);
+
+ $names=$sth->{NAME};
+ $types=$sth->{TYPE};
+ $nullable=$sth->{NULLABLE};
+ if (0)
+ {
+ # The following doesn't yet work
+ $scale=$sth->{SCALE};
+ $precision=$sth->{PRECISION};
+ }
+ else
+ {
+ my (@tmp);
+ @tmp= (undef()) x $sth->{NUM_OF_FIELDS};
+ $precision= $scale= \@tmp;
+ }
+ for ($i = 0; $i < $sth->{NUM_OF_FIELDS} ; $i++)
+ {
+ push(@res,$names->[$i] . " " .
+ odbc_to_sql($server,$types->[$i],$precision->[$i],$scale->[$i]) .
+ ($nullable->[$i] ? "" : " NOT NULL"));
+ }
+ return \@res;
+}
+
+
+sub odbc_to_sql
+{
+ my ($server,$type,$precision,$scale)=@_;
+
+ if ($type == DBI::SQL_CHAR())
+ {
+ return defined($precision) ? "char($precision)" : "varchar(255)";
+ }
+
+ if ($type == DBI::SQL_NUMERIC())
+ {
+ $precision=15 if (!defined($precision));
+ $scale=6 if (!defined($scale));
+ return "numeric($precision,$scale)";
+ }
+ if ($type == DBI::SQL_DECIMAL())
+ {
+ $precision=15 if (!defined($precision));
+ $scale=6 if (!defined($scale));
+ return "decimal($precision,$scale)";
+ }
+ if ($type == DBI::SQL_INTEGER())
+ {
+ return "integer" if (!defined($precision));
+ return "integer($precision)";
+ }
+ if ($type == DBI::SQL_SMALLINT())
+ {
+ return "smallint" if (!defined($precision));
+ return "smallint($precision)";
+ }
+ if ($type == DBI::SQL_FLOAT())
+ {
+ $precision=12 if (!defined($precision));
+ $scale=2 if (!defined($scale));
+ return "float($precision,$scale)";
+ }
+ if ($type == DBI::SQL_REAL())
+ {
+ $precision=12 if (!defined($precision));
+ $scale=2 if (!defined($scale));
+ return "float($precision,$scale)";
+ }
+ if ($type == DBI::SQL_DOUBLE())
+ {
+ $precision=22 if (!defined($precision));
+ $scale=2 if (!defined($scale));
+ return "double($precision,$scale)";
+ }
+ if ($type == DBI::SQL_VARCHAR())
+ {
+ $precision=255 if (!defined($precision));
+ return "varchar($precision)";
+ }
+ return "date" if ($type == DBI::SQL_DATE());
+ return "time" if ($type == DBI::SQL_TIME());
+ return "timestamp" if ($type == DBI::SQL_TIMESTAMP());
+ return $server->{'text'} if ($type == DBI::SQL_LONGVARCHAR());
+ return $server->{'blob'} if ($type == DBI::SQL_LONGVARBINARY());
+ if ($type == DBI::SQL_BIGINT())
+ {
+ return "bigint" if (!defined($precision));
+ return "bigint($precision)";
+ }
+ if ($type == DBI::SQL_TINYINT())
+ {
+ return "tinyint" if (!defined($precision));
+ return "tinyint($precision)";
+ }
+ die "Can't covert type '$type' to a ODBC type\n";
+}
+
+#
+# return an array with 1 for all coumns that we have to quote
+#
+
+sub get_columns_to_quote($sth)
+{
+ my ($sth)=@_;
+ my ($i,@res,$type,$tmp);
+
+ @res=();
+ for ($i = 0; $i < $sth->{NUM_OF_FIELDS} ; $i++)
+ {
+ $type=$sth->{TYPE}->[$i];
+ $tmp=1; # String by default
+ if ($type == DBI::SQL_NUMERIC() || $type == DBI::SQL_DECIMAL() ||
+ $type == DBI::SQL_INTEGER() || $type == DBI::SQL_SMALLINT() ||
+ $type == DBI::SQL_SMALLINT() || $type == DBI::SQL_FLOAT() ||
+ $type == DBI::SQL_REAL() || $type == DBI::SQL_DOUBLE() ||
+ $type == DBI::SQL_BIGINT() || $type == DBI::SQL_TINYINT())
+ {
+ $tmp=0;
+ }
+ push (@res,$tmp);
+ }
+ return \@res;
+}
+
+#
+# Check if table exists; Return 1 if table exists
+#
+
+sub table_exists
+{
+ my ($server,$dbh,$table)=@_;
+ if ($server->{'limits'}->{'group_functions'})
+ {
+ return !safe_query($dbh,"select count(*) from $table");
+ }
+ if ($server->{'limits'}->{'limit'})
+ {
+ return !safe_query($dbh,"select * from $table limit 1");
+ }
+ die "Don't know how to check if table '$table' exists in destination server\n";
+}
+
+
+#
+# execute query; return 0 if query is ok
+#
+
+sub safe_query
+{
+ my ($dbh,$query)=@_;
+ my ($sth);
+
+ print "query: $query\n" if ($opt_debug);
+ if (!($sth= $dbh->prepare($query)))
+ {
+ print "error: $DBI::errstr\n" if ($opt_debug);
+ return 1;
+ }
+ if (!$sth->execute)
+ {
+ print "error: $DBI::errstr\n" if ($opt_debug);
+ return 1
+ }
+ while ($sth->fetchrow_arrayref)
+ {
+ }
+ $sth->finish;
+ undef($sth);
+ return 0;
+}
+
+#
+# execute an array of queries
+#
+
+sub do_many
+{
+ my ($dbh,@statements)=@_;
+ my ($statement,$sth);
+
+ foreach $statement (@statements)
+ {
+ print "query: $statement\n" if ($opt_debug);
+ if (!($sth=$dbh->do($statement)))
+ {
+ die "Can't execute command '$statement'\nError: $DBI::errstr\n";
+ }
+ }
+}
diff --git a/sql-bench/crash-me.sh b/sql-bench/crash-me.sh
new file mode 100755
index 00000000000..19d358c6613
--- /dev/null
+++ b/sql-bench/crash-me.sh
@@ -0,0 +1,3442 @@
+#!@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
+
+# Written by Monty for the TCX/Monty Program/Detron benchmark suite.
+# Empress and PostgreSQL patches by Luuk de Boer
+# Extensions for ANSI SQL and Mimer by Bengt Gunne
+# Some additions and corrections by Matthias Urlich
+#
+# This programs tries to find all limits for a sql server
+# It gets the name from what it does to most servers :)
+#
+# Be sure to use --help before running this!
+#
+# If you want to add support for another server, add a new package for the
+# server in server-cfg. You only have to support the 'new' and 'version'
+# functions. new doesn't need to have any limits if one doesn't want to
+# use the benchmarks.
+#
+
+# TODO:
+# CMT includes types and functions which are synonyms for other types
+# and functions, including those in SQL9x. It should label those synonyms
+# as such, and clarify ones such as "mediumint" with comments such as
+# "3-byte int" or "same as xxx".
+
+
+$version="1.47";
+
+use DBI;
+use Getopt::Long;
+chomp($pwd = `pwd`); $pwd = "." if ($pwd eq '');
+require "$pwd/server-cfg" || die "Can't read Configuration file: $!\n";
+
+$opt_server="mysql"; $opt_host="localhost"; $opt_database="test";
+$opt_dir="limits";
+$opt_debug=$opt_help=$opt_Information=$opt_restart=$opt_force=$opt_quick=0;
+$opt_log_all_queries=$opt_fix_limit_file=$opt_batch_mode=0;
+$opt_db_start_cmd=""; # the db server start command
+$opt_sleep=10; # time to sleep while starting the db server
+$limit_changed=0; # For configure file
+$reconnect_count=0;
+$opt_comment=$opt_config_file=$opt_log_queries_to_file="";
+$limits{'crash_me_safe'}='yes';
+$prompts{'crash_me_safe'}='crash me safe';
+$limits{'operating_system'}= machine();
+$prompts{'operating_system'}='crash-me tested on';
+$retry_limit=3;
+
+GetOptions("Information","help","server=s","debug","user=s","password=s","database=s","restart","force","quick","log-all-queries","comment=s","host=s","fix-limit-file","dir=s","db-start-cmd=s","sleep=s","batch-mode","config-file=s","log-queries-to-file=s") || usage();
+usage() if ($opt_help || $opt_Information);
+
+$opt_config_file="$pwd/$opt_dir/$opt_server.cfg" if (length($opt_config_file) == 0);
+
+if ($opt_fix_limit_file)
+{
+ print "Fixing limit file for $opt_server\n";
+ read_config_data();
+ $limit_changed=1;
+ save_all_config_data();
+ exit 0;
+}
+
+$server=get_server($opt_server,$opt_host,$opt_database);
+$opt_server=$server->{'cmp_name'};
+
+$|=1; # For debugging
+
+print "Running $0 $version on '",($server_version=$server->version()),"'\n\n";
+print "I hope you didn't have anything important running on this server....\n";
+read_config_data();
+if ($limit_changed) # Must have been restarted
+{
+ save_config_data('crash_me_safe','no',"crash me safe");
+}
+
+if (!$opt_force && !$opt_batch_mode)
+{
+ server_info();
+}
+else
+{
+ print "Using --force. I assume you know what you are doing...\n";
+}
+print "\n";
+
+save_config_data('crash_me_version',$version,"crash me version");
+if ($server_version)
+{
+ save_config_data('server_version',$server_version,"server version");
+}
+if (length($opt_comment))
+{
+ save_config_data('user_comment',$opt_comment,"comment");
+}
+
+$opt_log=0;
+if (length($opt_log_queries_to_file))
+{
+ open(LOG,">$opt_log_queries_to_file") || die "Can't open file $opt_log_queries_to_file\n";
+ $opt_log=1;
+}
+
+#
+# Set up some limits that's regared as unlimited
+# We don't want to take up all resources from the server...
+#
+
+$max_connections="+1000"; # Number of simultaneous connections
+$max_buffer_size="+16000000"; # size of communication buffer.
+$max_string_size="+8000000"; # Enough for this test
+$max_name_length="+512"; # Actually 256, but ...
+$max_keys="+64"; # Probably too big.
+$max_join_tables="+64"; # Probably too big.
+$max_columns="+8192"; # Probably too big.
+$max_row_length=$max_string_size;
+$max_key_length="+8192"; # Big enough
+$max_order_by="+64"; # Big enough
+$max_expressions="+10000";
+$max_big_expressions="+100";
+$max_stacked_expressions="+2000";
+$query_size=$max_buffer_size;
+$longreadlen=16000000; # For retrieval buffer
+
+#
+# First do some checks that needed for the rest of the benchmark
+#
+use sigtrap; # Must be removed with perl5.005_2 on Win98
+$SIG{PIPE} = 'IGNORE';
+$SIG{SEGV} = sub {warn('SEGFAULT')};
+$dbh=safe_connect();
+$dbh->do("drop table crash_me"); # Remove old run
+$dbh->do("drop table crash_me2"); # Remove old run
+$dbh->do("drop table crash_me3"); # Remove old run
+$dbh->do("drop table crash_q"); # Remove old run
+$dbh->do("drop table crash_q1"); # Remove old run
+
+$prompt="Tables without primary key";
+if (!safe_query(["create table crash_me (a integer not null,b char(10) not null)",
+ "insert into crash_me (a,b) values (1,'a')"]))
+{
+ if (!safe_query(["create table crash_me (a integer not null,b char(10) not null, primary key (a))",
+ "insert into crash_me (a,b) values (1,'a')"]))
+ {
+ die "Can't create table 'crash_me' with one record: $DBI::errstr\n";
+ }
+ save_config_data('no_primary_key',"no",$prompt);
+}
+else
+{
+ save_config_data('no_primary_key',"yes",$prompt);
+}
+#
+# Define strings for character NULL and numeric NULL used in expressions
+#
+$char_null=$server->{'char_null'};
+$numeric_null=$server->{'numeric_null'};
+if ($char_null eq '')
+{
+ $char_null="NULL";
+}
+if ($numeric_null eq '')
+{
+ $numeric_null="NULL";
+}
+
+print "$prompt: $limits{'no_primary_key'}\n";
+
+report("SELECT without FROM",'select_without_from',"select 1");
+if ($limits{'select_without_from'} ne "yes")
+{
+ $end_query=" from crash_me";
+ $check_connect="select a from crash_me";
+}
+else
+{
+ $end_query="";
+ $check_connect="select 1";
+}
+
+assert($check_connect);
+assert("select a from crash_me where b<'b'");
+
+report("Select constants",'select_constants',"select 1 $end_query");
+report("Select table_name.*",'table_wildcard',
+ "select crash_me.* from crash_me");
+report("Allows \' and \" as string markers",'quote_with_"',
+ 'select a from crash_me where b<"c"');
+check_and_report("Double '' as ' in strings",'double_quotes',[],
+ "select 'Walker''s' $end_query",[],"Walker's",1);
+check_and_report("Multiple line strings","multi_strings",[],
+ "select a from crash_me where b < 'a'\n'b'",[],"1",0);
+check_and_report("\" as identifier quote (ANSI SQL)",'quote_ident_with_"',[],
+ 'select "A" from crash_me',[],"1",0);
+check_and_report("\` as identifier quote",'quote_ident_with_`',[],
+ 'select `A` from crash_me',[],"1",0);
+check_and_report("[] as identifier quote",'quote_ident_with_[',[],
+ 'select [A] from crash_me',[],"1",0);
+
+report("Column alias","column_alias","select a as ab from crash_me");
+report("Table alias","table_alias","select b.a from crash_me as b");
+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 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");
+report("Group by alias",'group_by_alias',
+ "select a as ab from crash_me group by ab");
+report("Order by",'order_by',"select a from crash_me order by a");
+report("Order by position",'order_by_position',
+ "select a from crash_me order by 1");
+report("Order by function","order_by_function",
+ "select a from crash_me order by a+1");
+check_and_report("Order by DESC is remembered",'order_by_remember_desc',
+ ["create table crash_q (s int,s1 int)",
+ "insert into crash_q values(1,1)",
+ "insert into crash_q values(3,1)",
+ "insert into crash_q values(2,1)"],
+ "select s,s1 from crash_q order by s1 DESC,s",
+ ["drop table crash_q"],[3,2,1],7,undef(),3);
+report("Compute",'compute',
+ "select a from crash_me order by a compute sum(a) by a");
+report("Value lists in INSERT",'multi_value_insert',
+ "create table crash_q (s char(10))",
+ "insert into crash_q values ('a'),('b')",
+ "drop table crash_q");
+report("INSERT with set syntax",'insert_with_set',
+ "create table crash_q (a integer)",
+ "insert into crash_q SET a=1",
+ "drop table crash_q");
+report("allows end ';'","end_colon", "select * from crash_me;");
+try_and_report("LIMIT number of rows","select_limit",
+ ["with LIMIT",
+ "select * from crash_me limit 1"],
+ ["with TOP",
+ "select TOP 1 * from crash_me"]);
+report("SELECT with LIMIT #,#","select_limit2", "select * from crash_me limit 1,1");
+
+# The following alter table commands MUST be kept together!
+if ($dbh->do("create table crash_q (a integer, b integer,c CHAR(10))"))
+{
+ report("Alter table add column",'alter_add_col',
+ "alter table crash_q add d integer");
+ report_one("Alter table add many columns",'alter_add_multi_col',
+ [["alter table crash_q add (f integer,g integer)","yes"],
+ ["alter table crash_q add f integer, add g integer","with add"],
+ ["alter table crash_q add f integer,g integer","without add"]] );
+ report("Alter table change column",'alter_change_col',
+ "alter table crash_q change a e char(50)");
+
+ # informix can only change data type with modify
+ report_one("Alter table modify column",'alter_modify_col',
+ [["alter table crash_q modify c CHAR(20)","yes"],
+ ["alter table crash_q alter c CHAR(20)","with alter"]]);
+ report("Alter table alter column default",'alter_alter_col',
+ "alter table crash_q alter b set default 10",
+ "alter table crash_q alter b set default NULL");
+ report("Alter table drop column",'alter_drop_col',
+ "alter table crash_q drop column b");
+ report("Alter table rename table",'alter_rename_table',
+ "alter table crash_q rename to crash_q1");
+}
+# Make sure both tables will be dropped, even if rename fails.
+$dbh->do("drop table crash_q1");
+$dbh->do("drop table crash_q");
+
+if ($dbh->do("create table crash_q (a integer, b integer,c CHAR(10))") &&
+ $dbh->do("create table crash_q1 (a integer, b integer,c CHAR(10) not null)"))
+{
+ report("Alter table add constraint",'alter_add_constraint',
+ "alter table crash_q add constraint c1 check(a > b)");
+ report("Alter table drop constraint",'alter_drop_constraint',
+ "alter table crash_q drop constraint c1");
+ report("Alter table add unique",'alter_add_unique',
+ "alter table crash_q add constraint u1 unique(c)");
+ try_and_report("Alter table drop unique",'alter_drop_unique',
+ ["with constraint",
+ "alter table crash_q drop constraint u1"],
+ ["with drop key",
+ "alter table crash_q drop key c"]);
+ try_and_report("Alter table add primary key",'alter_add_primary_key',
+ ["with constraint",
+ "alter table crash_q1 add constraint p1 primary key(c)"],
+ ["with add primary key",
+ "alter table crash_q1 add primary key(c)"]);
+ report("Alter table add foreign key",'alter_add_foreign_key',
+ "alter table crash_q add constraint f1 foreign key(c) references crash_q1(c)");
+ try_and_report("Alter table drop foreign key",'alter_drop_foreign_key',
+ ["with drop constraint",
+ "alter table crash_q drop constraint f1"],
+ ["with drop foreign key",
+ "alter table crash_q drop foreign key f1"]);
+ try_and_report("Alter table drop primary key",'alter_drop_primary_key',
+ ["drop constraint",
+ "alter table crash_q1 drop constraint p1 restrict"],
+ ["drop primary key",
+ "alter table crash_q1 drop primary key"]);
+}
+$dbh->do("drop table crash_q");
+$dbh->do("drop table crash_q1");
+
+check_and_report("case insensitive compare","case_insensitive_strings",
+ [],"select b from crash_me where b = 'A'",[],'a',1);
+check_and_report("ignore end space in compare","ignore_end_space",
+ [],"select b from crash_me where b = 'a '",[],'a',1);
+check_and_report("group on column with null values",'group_by_null',
+ ["create table crash_q (s char(10))",
+ "insert into crash_q values(null)",
+ "insert into crash_q values(null)"],
+ "select count(*) from crash_q group by s",
+ ["drop table crash_q"],2,0);
+
+$prompt="Having";
+if (!defined($limits{'having'}))
+{ # Complicated because of postgreSQL
+ if (!safe_query_result("select a from crash_me group by a having a > 0",1,0))
+ {
+ if (!safe_query_result("select a from crash_me group by a having a < 0",
+ 1,0))
+ { save_config_data("having","error",$prompt); }
+ else
+ { save_config_data("having","yes",$prompt); }
+ }
+ else
+ { save_config_data("having","no",$prompt); }
+}
+print "$prompt: $limits{'having'}\n";
+
+if ($limits{'having'} eq 'yes')
+{
+ report("Having with group function","having_with_group",
+ "select a from crash_me group by a having count(*) = 1");
+}
+
+if ($limits{'column_alias'} eq 'yes')
+{
+ report("Order by alias",'order_by_alias',
+ "select a as ab from crash_me order by ab");
+ if ($limits{'having'} eq 'yes')
+ {
+ report("Having on alias","having_with_alias",
+ "select a as ab from crash_me group by a having ab > 0");
+ }
+}
+report("binary numbers (0b1001)","binary_numbers","select 0b1001 $end_query");
+report("hex numbers (0x41)","hex_numbers","select 0x41 $end_query");
+report("binary strings (b'0110')","binary_strings","select b'0110' $end_query");
+report("hex strings (x'1ace')","hex_strings","select x'1ace' $end_query");
+
+report_result("Value of logical operation (1=1)","logical_value",
+ "select (1=1) $end_query");
+
+$logical_value= $limits{'logical_value'};
+
+$false=0;
+$result="no";
+if ($res=safe_query("select (1=1)=true $end_query")) {
+ $false="false";
+ $result="yes";
+}
+save_config_data('has_true_false',$result,"TRUE and FALSE");
+
+#
+# Check how many connections the server can handle:
+# We can't test unlimited connections, because this may take down the
+# server...
+#
+
+$prompt="Simultaneous connections (installation default)";
+print "$prompt: ";
+if (defined($limits{'connections'}))
+{
+ print "$limits{'connections'}\n";
+}
+else
+{
+ @connect=($dbh);
+
+ for ($i=1; $i < $max_connections ; $i++)
+ {
+ if (!($dbh=DBI->connect($server->{'data_source'},$opt_user,$opt_password,
+ { PrintError => 0})))
+ {
+ print "Last connect error: $DBI::errstr\n" if ($opt_debug);
+ last;
+ }
+ $dbh->{LongReadLen}= $longreadlen; # Set retrieval buffer
+ print "." if ($opt_debug);
+ push(@connect,$dbh);
+ }
+ print "$i\n";
+ save_config_data('connections',$i,$prompt);
+ foreach $dbh (@connect)
+ {
+ print "#" if ($opt_debug);
+ $dbh->disconnect || warn $dbh->errstr; # close connection
+ }
+
+ $#connect=-1; # Free connections
+
+ if ($i == 0)
+ {
+ print "Can't connect to server: $DBI::errstr. Please start it and try again\n";
+ exit 1;
+ }
+ $dbh=safe_connect();
+}
+
+
+#
+# Check size of communication buffer, strings...
+#
+
+$prompt="query size";
+print "$prompt: ";
+if (!defined($limits{'query_size'}))
+{
+ $query="select ";
+ $first=64;
+ $end=$max_buffer_size;
+ $select= $limits{'select_without_from'} eq 'yes' ? 1 : 'a';
+
+ assert($query . "$select$end_query");
+
+ $first=$limits{'restart'}{'low'} if ($limits{'restart'}{'low'});
+
+ if ($limits{'restart'}{'tohigh'})
+ {
+ $end = $limits{'restart'}{'tohigh'} - 1;
+ print "\nRestarting this with low limit: $first and high limit: $end\n";
+ delete $limits{'restart'};
+ $first=$first+int(($end-$first+4)/5); # Prefere lower on errors
+ }
+ for ($i=$first ; $i < $end ; $i*=2)
+ {
+ last if (!safe_query($query . (" " x ($i - length($query)-length($end_query) -1)) . "$select$end_query"));
+ $first=$i;
+ save_config_data("restart",$i,"") if ($opt_restart);
+ }
+ $end=$i;
+
+ if ($i < $max_buffer_size)
+ {
+ while ($first != $end)
+ {
+ $i=int(($first+$end+1)/2);
+ if (safe_query($query .
+ (" " x ($i - length($query)-length($end_query) -1)) .
+ "$select$end_query"))
+ {
+ $first=$i;
+ }
+ else
+ {
+ $end=$i-1;
+ }
+ }
+ }
+ save_config_data('query_size',$end,$prompt);
+}
+$query_size=$limits{'query_size'};
+
+print "$limits{'query_size'}\n";
+#
+# Test database types
+#
+
+@sql_types=("character(1)","char(1)","char varying(1)", "character varying(1)",
+ "boolean",
+ "varchar(1)",
+ "integer","int","smallint",
+ "numeric(9,2)","decimal(6,2)","dec(6,2)",
+ "bit", "bit(2)","bit varying(2)","float","float(8)","real",
+ "double precision", "date","time","timestamp",
+ "interval year", "interval year to month",
+ "interval month",
+ "interval day", "interval day to hour", "interval day to minute",
+ "interval day to second",
+ "interval hour", "interval hour to minute", "interval hour to second",
+ "interval minute", "interval minute to second",
+ "interval second",
+ "national character varying(20)",
+ "national character(20)","nchar(1)",
+ "national char varying(20)","nchar varying(20)",
+ "national character varying(20)",
+ "timestamp with time zone");
+@odbc_types=("binary(1)","varbinary(1)","tinyint","bigint",
+ "datetime");
+@extra_types=("blob","byte","long varbinary","image","text","text(10)",
+ "mediumtext",
+ "long varchar(1)", "varchar2(257)",
+ "mediumint","middleint","int unsigned",
+ "int1","int2","int3","int4","int8","uint",
+ "money","smallmoney","float4","float8","smallfloat",
+ "float(6,2)","double",
+ "enum('red')","set('red')", "int(5) zerofill", "serial",
+ "char(10) binary","int not null auto_increment,unique(q)",
+ "abstime","year","datetime","smalldatetime","timespan","reltime",
+ # Sybase types
+ "int not null identity,unique(q)",
+ # postgres types
+ "box","bool","circle","polygon","point","line","lseg","path",
+ "interval", "serial", "inet", "cidr", "macaddr",
+
+ # oracle types
+ "varchar2(16)","nvarchar2(16)","number(9,2)","number(9)",
+ "number", "long","raw(16)","long raw","rowid","mlslabel","clob",
+ "nclob","bfile"
+ );
+
+@types=(["sql",\@sql_types],
+ ["odbc",\@odbc_types],
+ ["extra",\@extra_types]);
+
+foreach $types (@types)
+{
+ print "\nSupported $types->[0] types\n";
+ $tmp=@$types->[1];
+ foreach $use_type (@$tmp)
+ {
+ $type=$use_type;
+ $type =~ s/\(.*\)/(1 arg)/;
+ if (index($use_type,",")>= 0)
+ {
+ $type =~ s/\(1 arg\)/(2 arg)/;
+ }
+ if (($tmp2=index($type,",unique")) >= 0)
+ {
+ $type=substr($type,0,$tmp2);
+ }
+ $tmp2=$type;
+ $tmp2 =~ s/ /_/g;
+ $tmp2 =~ s/_not_null//g;
+ report("Type $type","type_$types->[0]_$tmp2",
+ "create table crash_q (q $use_type)",
+ "drop table crash_q");
+ }
+}
+
+#
+# Test some type limits
+#
+
+check_and_report("Remembers end space in char()","remember_end_space",
+ ["create table crash_q (a char(10))",
+ "insert into crash_q values('hello ')"],
+ "select a from crash_q where a = 'hello '",
+ ["drop table crash_q"],
+ 'hello ',6);
+
+check_and_report("Remembers end space in varchar()",
+ "remember_end_space_varchar",
+ ["create table crash_q (a varchar(10))",
+ "insert into crash_q values('hello ')"],
+ "select a from crash_q where a = 'hello '",
+ ["drop table crash_q"],
+ 'hello ',6);
+
+check_and_report("Supports 0000-00-00 dates","date_zero",
+ ["create table crash_me2 (a date not null)",
+ "insert into crash_me2 values ('0000-00-00')"],
+ "select a from crash_me2",
+ ["drop table crash_me2"],
+ "0000-00-00",1);
+
+check_and_report("Supports 0001-01-01 dates","date_one",
+ ["create table crash_me2 (a date not null)",
+ "insert into crash_me2 values (DATE '0001-01-01')"],
+ "select a from crash_me2",
+ ["drop table crash_me2"],
+ "0001-01-01",1);
+
+check_and_report("Supports 9999-12-31 dates","date_last",
+ ["create table crash_me2 (a date not null)",
+ "insert into crash_me2 values (DATE '9999-12-31')"],
+ "select a from crash_me2",
+ ["drop table crash_me2"],
+ "9999-12-31",1);
+
+check_and_report("Supports 'infinity dates","date_infinity",
+ ["create table crash_me2 (a date not null)",
+ "insert into crash_me2 values ('infinity')"],
+ "select a from crash_me2",
+ ["drop table crash_me2"],
+ "infinity",1);
+
+if (!defined($limits{'date_with_YY'}))
+{
+ check_and_report("Supports YY-MM-DD dates","date_with_YY",
+ ["create table crash_me2 (a date not null)",
+ "insert into crash_me2 values ('98-03-03')"],
+ "select a from crash_me2",
+ ["drop table crash_me2"],
+ "1998-03-03",5);
+ if ($limits{'date_with_YY'} eq "yes")
+ {
+ undef($limits{'date_with_YY'});
+ check_and_report("Supports YY-MM-DD 2000 compilant dates",
+ "date_with_YY",
+ ["create table crash_me2 (a date not null)",
+ "insert into crash_me2 values ('10-03-03')"],
+ "select a from crash_me2",
+ ["drop table crash_me2"],
+ "2010-03-03",5);
+ }
+}
+
+if (($limits{'type_extra_float(2_arg)'} eq "yes" ||
+ $limits{'type_sql_decimal(2_arg)'} eq "yes") &&
+ (!defined($limits{'storage_of_float'})))
+{
+ my $type=$limits{'type_extra_float(2_arg)'} eq "yes" ? "float(4,1)" :
+ "decimal(4,1)";
+ my $result="undefined";
+ if (execute_and_check(["create table crash_q (q1 $type)",
+ "insert into crash_q values(1.14)"],
+ "select q1 from crash_q",
+ ["drop table crash_q"],1.1,0) &&
+ execute_and_check(["create table crash_q (q1 $type)",
+ "insert into crash_q values(1.16)"],
+ "select q1 from crash_q",
+ ["drop table crash_q"],1.1,0))
+ {
+ $result="truncate";
+ }
+ elsif (execute_and_check(["create table crash_q (q1 $type)",
+ "insert into crash_q values(1.14)"],
+ "select q1 from crash_q",
+ ["drop table crash_q"],1.1,0) &&
+ execute_and_check(["create table crash_q (q1 $type)",
+ "insert into crash_q values(1.16)"],
+ "select q1 from crash_q",
+ ["drop table crash_q"],1.2,0))
+ {
+ $result="round";
+ }
+ elsif (execute_and_check(["create table crash_q (q1 $type)",
+ "insert into crash_q values(1.14)"],
+ "select q1 from crash_q",
+ ["drop table crash_q"],1.14,0) &&
+ execute_and_check(["create table crash_q (q1 $type)",
+ "insert into crash_q values(1.16)"],
+ "select q1 from crash_q",
+ ["drop table crash_q"],1.16,0))
+ {
+ $result="exact";
+ }
+ $prompt="Storage of float values";
+ print "$prompt: $result\n";
+ save_config_data("storage_of_float", $result, $prompt);
+}
+
+try_and_report("Type for row id", "rowid",
+ ["rowid",
+ "create table crash_q (a rowid)","drop table crash_q"],
+ ["auto_increment",
+ "create table crash_q (a int not null auto_increment, primary key(a))","drop table crash_q"],
+ ["oid",
+ "create table crash_q (a oid, primary key(a))","drop table crash_q"],
+ ["serial",
+ "create table crash_q (a serial, primary key(a))","drop table crash_q"]);
+
+try_and_report("Automatic rowid", "automatic_rowid",
+ ["_rowid",
+ "create table crash_q (a int not null, primary key(a))",
+ "insert into crash_q values (1)",
+ "select _rowid from crash_q",
+ "drop table crash_q"]);
+
+#
+# Test functions
+#
+
+@sql_functions=
+ (["+, -, * and /","+","5*3-4/2+1",14,0],
+ ["ANSI SQL SUBSTRING","substring","substring('abcd' from 2 for 2)","bc",1],
+ ["BIT_LENGTH","bit_length","bit_length('abc')",24,0],
+ ["searched CASE","searched_case","case when 1 > 2 then 'false' when 2 > 1 then 'true' end", "true",1],
+ ["simple CASE","simple_case","case 2 when 1 then 'false' when 2 then 'true' end", "true",1],
+ ["CAST","cast","CAST(1 as CHAR)","1",1],
+ ["CHARACTER_LENGTH","character_length","character_length('abcd')","4",0],
+ ["CHAR_LENGTH","char_length","char_length(b)","10",0],
+ ["CHAR_LENGTH(constant)","char_length(constant)","char_length('abcd')","4",0],
+ ["COALESCE","coalesce","coalesce($char_null,'bcd','qwe')","bcd",1],
+ ["CURRENT_DATE","current_date","current_date",0,2],
+ ["CURRENT_TIME","current_time","current_time",0,2],
+ ["CURRENT_TIMESTAMP","current_timestamp","current_timestamp",0,2],
+ ["CURRENT_USER","current_user","current_user",0,2],
+ ["EXTRACT","extract_sql","extract(minute from timestamp '2000-02-23 18:43:12.987')",43,0],
+ ["LOCALTIME","localtime","localtime",0,2],
+ ["LOCALTIMESTAMP","localtimestamp","localtimestamp",0,2],
+ ["LOWER","lower","LOWER('ABC')","abc",1],
+ ["NULLIF with strings","nullif_string","NULLIF(NULLIF('first','second'),'first')",undef(),4],
+ ["NULLIF with numbers","nullif_num","NULLIF(NULLIF(1,2),1)",undef(),4],
+ ["OCTET_LENGTH","octet_length","octet_length('abc')",3,0],
+ ["POSITION","position","position('ll' in 'hello')",3,0],
+ ["SESSION_USER","session_user","session_user",0,2],
+ ["SYSTEM_USER","system_user","system_user",0,2],
+ ["TRIM","trim","trim(trailing from trim(LEADING FROM ' abc '))","abc",3],
+ ["UPPER","upper","UPPER('abc')","ABC",1],
+ ["USER","user","user"],
+ ["concatenation with ||","concat_as_||","'abc' || 'def'","abcdef",1],
+ );
+
+@odbc_functions=
+ (["ASCII", "ascii", "ASCII('A')","65",0],
+ ["CHAR", "char", "CHAR(65)" ,"A",1],
+ ["CONCAT(2 arg)","concat", "concat('a','b')","ab",1],
+ ["DIFFERENCE()","difference","difference('abc','abe')",0,2],
+ ["INSERT","insert","insert('abcd',2,2,'ef')","aefd",1],
+ ["LEFT","left","left('abcd',2)","ab",1],
+ ["LTRIM","ltrim","ltrim(' abcd')","abcd",1],
+ ["REAL LENGTH","length","length('abcd ')","5",0],
+ ["ODBC LENGTH","length_without_space","length('abcd ')","4",0],
+ ["LOCATE(2 arg)","locate_2","locate('bcd','abcd')","2",0],
+ ["LOCATE(3 arg)","locate_3","locate('bcd','abcd',3)","0",0],
+ ["LCASE","lcase","lcase('ABC')","abc",1],
+ ["REPEAT","repeat","repeat('ab',3)","ababab",1],
+ ["REPLACE","replace","replace('abbaab','ab','ba')","bababa",1],
+ ["RIGHT","right","right('abcd',2)","cd",1],
+ ["RTRIM","rtrim","rtrim(' abcd ')"," abcd",1],
+ ["SPACE","space","space(5)"," ",3],
+ ["SOUNDEX","soundex","soundex('hello')",0,2],
+ ["ODBC SUBSTRING","substring","substring('abcd',3,2)","cd",1],
+ ["UCASE","ucase","ucase('abc')","ABC",1],
+
+ ["ABS","abs","abs(-5)",5,0],
+ ["ACOS","acos","acos(0)","1.570796",0],
+ ["ASIN","asin","asin(1)","1.570796",0],
+ ["ATAN","atan","atan(1)","0.785398",0],
+ ["ATAN2","atan2","atan2(1,0)","1.570796",0],
+ ["CEILING","ceiling","ceiling(-4.5)",-4,0],
+ ["COS","cos","cos(0)","1.00000",0],
+ ["COT","cot","cot(1)","0.64209262",0],
+ ["DEGREES","degrees","degrees(6.283185)","360",0],
+ ["EXP","exp","exp(1)","2.718282",0],
+ ["FLOOR","floor","floor(2.5)","2",0],
+ ["LOG","log","log(2)","0.693147",0],
+ ["LOG10","log10","log10(10)","1",0],
+ ["MOD","mod","mod(11,7)","4",0],
+ ["PI","pi","pi()","3.141593",0],
+ ["POWER","power","power(2,4)","16",0],
+ ["RAND","rand","rand(1)",0,2], # Any value is acceptable
+ ["RADIANS","radians","radians(360)","6.283185",0],
+ ["ROUND(2 arg)","round","round(5.63,2)","5.6",0],
+ ["SIGN","sign","sign(-5)",-1,0],
+ ["SIN","sin","sin(1)","0.841471",0],
+ ["SQRT","sqrt","sqrt(4)",2,0],
+ ["TAN","tan","tan(1)","1.557408",0],
+ ["TRUNCATE","truncate","truncate(18.18,-1)",10,0],
+ ["NOW","now","now()",0,2], # Any value is acceptable
+ ["CURDATE","curdate","curdate()",0,2],
+ ["DAYNAME","dayname","dayname(DATE '1997-02-01')","",2],
+ ["MONTH","month","month(DATE '1997-02-01')","",2],
+ ["MONTHNAME","monthname","monthname(DATE '1997-02-01')","",2],
+ ["DAYOFMONTH","dayofmonth","dayofmonth(DATE '1997-02-01')",1,0],
+ ["DAYOFWEEK","dayofweek","dayofweek(DATE '1997-02-01')",7,0],
+ ["DAYOFYEAR","dayofyear","dayofyear(DATE '1997-02-01')",32,0],
+ ["QUARTER","quarter","quarter(DATE '1997-02-01')",1,0],
+ ["WEEK","week","week(DATE '1997-02-01')",5,0],
+ ["YEAR","year","year(DATE '1997-02-01')",1997,0],
+ ["CURTIME","curtime","curtime()",0,2],
+ ["HOUR","hour","hour('12:13:14')",12,0],
+ ["ANSI HOUR","hour_time","hour(TIME '12:13:14')",12,0],
+ ["MINUTE","minute","minute('12:13:14')",13,0],
+ ["SECOND","second","second('12:13:14')",14,0],
+ ["TIMESTAMPADD","timestampadd",
+ "timestampadd(SQL_TSI_SECOND,1,'1997-01-01 00:00:00')",
+ "1997-01-01 00:00:01",1],
+ ["TIMESTAMPDIFF","timestampdiff",
+ "timestampdiff(SQL_TSI_SECOND,'1997-01-01 00:00:02', '1997-01-01 00:00:01')","1",0],
+ ["USER()","user()","user()",0,2],
+ ["DATABASE","database","database()",0,2],
+ ["IFNULL","ifnull","ifnull(2,3)",2,0],
+ ["ODBC syntax LEFT & RIGHT", "fn_left",
+ "{ fn LEFT( { fn RIGHT('abcd',2) },1) }","c",1],
+ );
+
+@extra_functions=
+ (
+ ["& (bitwise and)",'&',"5 & 3",1,0],
+ ["| (bitwise or)",'|',"1 | 2",3,0],
+ ["<< and >> (bitwise shifts)",'binary_shifts',"(1 << 4) >> 2",4,0],
+ ["<> in SELECT","<>","1<>1","0",0],
+ ["=","=","(1=1)",1,$logical_value],
+ ["~* (case insensitive compare)","~*","'hi' ~* 'HI'",1,$logical_value],
+ ["ADD_MONTHS","add_months","add_months('1997-01-01',1)","1997-02-01",0], # oracle the date plus n months
+ ["AND and OR in SELECT","and_or","1=1 AND 2=2",$logical_value,0],
+ ["AND as '&&'",'&&',"1=1 && 2=2",$logical_value,0],
+ ["ASCII_CHAR", "ascii_char", "ASCII_CHAR(65)","A",1],
+ ["ASCII_CODE", "ascii_code", "ASCII_CODE('A')","65",0],
+ ["ATN2","atn2","atn2(1,0)","1.570796",0],
+ ["BETWEEN in SELECT","between","5 between 4 and 6",$logical_value,0],
+ ["BIT_COUNT","bit_count","bit_count(5)",2,0],
+ ["CEIL","ceil","ceil(-4.5)",-4,0], # oracle
+ ["CHARINDEX","charindex","charindex('a','crash')",3,0],
+ ["CHR", "chr", "CHR(65)" ,"A",1], # oracle
+ ["CONCAT(list)","concat_list", "concat('a','b','c','d')","abcd",1],
+ ["CONVERT","convert","convert(CHAR,5)","5",1],
+ ["COSH","cosh","cosh(0)","1",0], # oracle hyperbolic cosine of n.
+ ["DATEADD","dateadd","dateadd(day,3,'Nov 30 1997')",0,2],
+ ["DATEDIFF","datediff","datediff(month,'Oct 21 1997','Nov 30 1997')",0,2],
+ ["DATENAME","datename","datename(month,'Nov 30 1997')",0,2],
+ ["DATEPART","datepart","datepart(month,'July 20 1997')",0,2],
+ ["DATE_FORMAT","date_format", "date_format('1997-01-02 03:04:05','M W D Y y m d h i s w')", 0,2],
+ ["ELT","elt","elt(2,'ONE','TWO','THREE')","TWO",1],
+ ["ENCRYPT","encrypt","encrypt('hello')",0,2],
+ ["FIELD","field","field('IBM','NCA','ICL','SUN','IBM','DIGITAL')",4,0],
+ ["FORMAT","format","format(1234.5555,2)","1,234.56",1],
+ ["FROM_DAYS","from_days","from_days(729024)","1996-01-01",1],
+ ["FROM_UNIXTIME","from_unixtime","from_unixtime(0)",0,2],
+ ["GETDATE","getdate","getdate()",0,2],
+ ["GREATEST","greatest","greatest('HARRY','HARRIOT','HAROLD')","HARRY",1], # oracle
+ ["IF","if", "if(5,6,7)",6,0],
+ ["IN on numbers in SELECT","in_num","2 in (3,2,5,9,5,1)",$logical_value,0],
+ ["IN on strings in SELECT","in_str","'monty' in ('david','monty','allan')", $logical_value,0],
+ ["INITCAP","initcap","initcap('the soap')","The Soap",1], # oracle Returns char, with the first letter of each word in uppercase
+ ["INSTR (Oracle syntax)", "instr_oracle", "INSTR('CORPORATE FLOOR','OR',3,2)" ,"14",0], # oracle instring
+ ["INSTRB", "instrb", "INSTRB('CORPORATE FLOOR','OR',5,2)" ,"27",0], # oracle instring in bytes
+ ["INTERVAL","interval","interval(55,10,20,30,40,50,60,70,80,90,100)",5,0],
+ ["LAST_DAY","last_day","last_day('1997-04-01')","1997-04-30",0], # oracle last day of month of date
+ ["LAST_INSERT_ID","last_insert_id","last_insert_id()",0,2],
+ ["LEAST","least","least('HARRY','HARRIOT','HAROLD')","HAROLD",1], # oracle
+ ["LENGTHB","lengthb","lengthb('CANDIDE')","14",0], # oracle length in bytes
+ ["LIKE ESCAPE in SELECT","like_escape","'%' like 'a%' escape 'a'",$logical_value,0],
+ ["LIKE in SELECT","like","'a' like 'a%'",$logical_value,0],
+ ["LN","ln","ln(95)","4.55387689",0], # oracle natural logarithm of n
+ ["LOCATE as INSTR","instr","instr('hello','ll')",3,0],
+ ["LOG(m,n)","log(m_n)","log(10,100)","2",0], # oracle logarithm, base m, of n
+ ["LOGN","logn","logn(2)","0.693147",0], # informix
+ ["LPAD","lpad","lpad('hi',4,'??')",'??hi',3],
+ ["MDY","mdy","mdy(7,1,1998)","1998-07-01",0], # informix
+ ["MOD as %","%","10%7","3",0],
+ ["MONTHS_BETWEEN","months_between","months_between('1997-02-02','1997-01-01')","1.03225806",0], # oracle number of months between 2 dates
+ ["NOT BETWEEN in SELECT","not_between","5 not between 4 and 6",0,0],
+ ["NOT LIKE in SELECT","not_like","'a' not like 'a%'",0,0],
+ ["NOT as '!' in SELECT","!","! 1",0,0],
+ ["NOT in SELECT","not","not $false",$logical_value,0],
+ ["ODBC CONVERT","odbc_convert","convert(5,SQL_CHAR)","5",1],
+ ["OR as '||'",'||',"1=0 || 1=1",$logical_value,0],
+ ["PASSWORD","password","password('hello')",0,2],
+ ["PASTE", "paste", "paste('ABCDEFG',3,2,'1234')","AB1234EFG",1],
+ ["PATINDEX","patindex","patindex('%a%','crash')",3,0],
+ ["PERIOD_ADD","period_add","period_add(9602,-12)",199502,0],
+ ["PERIOD_DIFF","period_diff","period_diff(199505,199404)",13,0],
+ ["POW","pow","pow(3,2)",9,0],
+ ["RANGE","range","range(a)","0.0",0], # informix range(a) = max(a) - min(a)
+ ["REGEXP in SELECT","regexp","'a' regexp '^(a|b)*\$'",$logical_value,0],
+ ["REPLICATE","replicate","replicate('a',5)","aaaaa",1],
+ ["REVERSE","reverse","reverse('abcd')","dcba",1],
+ ["ROOT","root","root(4)",2,0], # informix
+ ["ROUND(1 arg)","round1","round(5.63)","6",0],
+ ["RPAD","rpad","rpad('hi',4,'??')",'hi??',3],
+ ["SEC_TO_TIME","sec_to_time","sec_to_time(5001)","01:23:21",1],
+ ["SINH","sinh","sinh(1)","1.17520119",0], # oracle hyperbolic sine of n
+ ["STR","str","str(123.45,5,1)",123.5,3],
+ ["STRCMP","strcmp","strcmp('abc','adc')",-1,0],
+ ["STUFF","stuff","stuff('abc',2,3,'xyz')",'axyz',3],
+ ["SUBSTRB", "substrb", "SUBSTRB('ABCDEFG',5,4.2)" ,"CD",1], # oracle substring with bytes
+ ["SUBSTRING as MID","mid","mid('hello',3,2)","ll",1],
+ ["SUBSTRING_INDEX","substring_index","substring_index('www.tcx.se','.',-2)", "tcx.se",1],
+ ["SYSDATE","sysdate","sysdate()",0,2],
+ ["TAIL","tail","tail('ABCDEFG',3)","EFG",0],
+ ["TANH","tanh","tanh(1)","0.462117157",0], # oracle hyperbolic tangent of n
+ ["TIME_TO_SEC","time_to_sec","time_to_sec('01:23:21')","5001",0],
+ ["TO_DAYS","to_days","to_days(DATE '1996-01-01')",729024,0],
+ ["TRANSLATE","translate","translate('abc','bc','de')",'ade',3],
+ ["TRIM; Many char extension","trim_many_char","trim(':!' FROM ':abc!')","abc",3],
+ ["TRIM; Substring extension","trim_substring","trim('cb' FROM 'abccb')","abc",3],
+ ["TRUNC","trunc","trunc(18.18,-1)",10,0], # oracle
+ ["UID","uid","uid",0,2], # oracle uid from user
+ ["UNIX_TIMESTAMP","unix_timestamp","unix_timestamp()",0,2],
+ ["USERENV","userenv","userenv",0,2], # oracle user enviroment
+ ["VERSION","version","version()",0,2],
+ ["WEEKDAY","weekday","weekday(DATE '1997-11-29')",5,0],
+ ["automatic num->string convert","auto_num2string","concat('a',2)","a2",1],
+ ["automatic string->num convert","auto_string2num","'1'+2",3,0],
+ ["concatenation with +","concat_as_+","'abc' + 'def'","abcdef",1],
+ );
+
+@sql_group_functions=
+ (
+ ["AVG","avg","avg(a)",1,0],
+ ["COUNT (*)","count_*","count(*)",1,0],
+ ["COUNT column name","count_column","count(a)",1,0],
+ ["COUNT(DISTINCT expr)","count_distinct","count(distinct a)",1,0],
+ ["MAX on numbers","max","max(a)",1,0],
+ ["MAX on strings","max_str","max(b)","a",1],
+ ["MIN on numbers","min","min(a)",1,0],
+ ["MIN on strings","min_str","min(b)","a",1],
+ ["SUM","sum","sum(a)",1,0],
+ );
+
+@extra_group_functions=
+ (
+ ["BIT_AND",'bit_and',"bit_and(a)",1,0],
+ ["BIT_OR", 'bit_or', "bit_or(a)",1,0],
+ ["COUNT(DISTINCT expr,expr,...)","count_distinct_list","count(distinct a,b)",1,0],
+ ["STD","std","std(a)",0,0],
+ ["STDDEV","stddev","stddev(a)",0,0],
+ ["VARIANCE","variance","variance(a)",0,0],
+ );
+
+@where_functions=
+(
+ ["= ALL","eq_all","b =all (select b from crash_me)",1,0],
+ ["= ANY","eq_any","b =any (select b from crash_me)",1,0],
+ ["= SOME","eq_some","b =some (select b from crash_me)",1,0],
+ ["BETWEEN","between","5 between 4 and 6",1,0],
+ ["EXISTS","exists","exists (select * from crash_me)",1,0],
+ ["IN on numbers","in_num","2 in (3,2,5,9,5,1)",1,0],
+ ["LIKE ESCAPE","like_escape","b like '%' escape 'a'",1,0],
+ ["LIKE","like","b like 'a%'",1,0],
+ ["MATCH UNIQUE","match_unique","1 match unique (select a from crash_me)",1,0],
+ ["MATCH","match","1 match (select a from crash_me)",1,0],
+ ["MATCHES","matches","b matcjhes 'a*'",1,0],
+ ["NOT BETWEEN","not_between","7 not between 4 and 6",1,0],
+ ["NOT EXISTS","not_exists","not exists (select * from crash_me where a = 2)",1,0],
+ ["NOT LIKE","not_like","b not like 'b%'",1,0],
+ ["NOT UNIQUE","not_unique","not unique (select * from crash_me where a = 2)",1,0],
+ ["UNIQUE","unique","unique (select * from crash_me)",1,0],
+ );
+
+@types=(["sql",\@sql_functions,0],
+ ["odbc",\@odbc_functions,0],
+ ["extra",\@extra_functions,0],
+ ["where",\@where_functions,0]);
+
+@group_types=(["sql",\@sql_group_functions,0],
+ ["extra",\@extra_group_functions,0]);
+
+
+foreach $types (@types)
+{
+ print "\nSupported $types->[0] functions\n";
+ $tmp=@$types->[1];
+ foreach $type (@$tmp)
+ {
+ if (defined($limits{"func_$types->[0]_$type->[1]"}))
+ {
+ next;
+ }
+ if ($types->[0] eq "where")
+ {
+ check_and_report("Function $type->[0]","func_$types->[0]_$type->[1]",
+ [],"select a from crash_me where $type->[2]",[],
+ $type->[3],$type->[4]);
+ }
+ elsif ($limits{'functions'} eq 'yes')
+ {
+ if (($type->[2] =~ /char_length\(b\)/) && (!$end_query))
+ {
+ my $tmp= $type->[2];
+ $tmp .= " from crash_me ";
+ undef($limits{"func_$types->[0]_$type->[1]"});
+ check_and_report("Function $type->[0]",
+ "func_$types->[0]_$type->[1]",
+ [],"select $tmp ",[],
+ $type->[3],$type->[4]);
+ }
+ else
+ {
+ undef($limits{"func_$types->[0]_$type->[1]"});
+ $result = check_and_report("Function $type->[0]",
+ "func_$types->[0]_$type->[1]",
+ [],"select $type->[2] $end_query",[],
+ $type->[3],$type->[4]);
+ if (!$result)
+ {
+ # check without type specifyer
+ if ($type->[2] =~ /DATE /)
+ {
+ my $tmp= $type->[2];
+ $tmp =~ s/DATE //;
+ undef($limits{"func_$types->[0]_$type->[1]"});
+ $result = check_and_report("Function $type->[0]",
+ "func_$types->[0]_$type->[1]",
+ [],"select $tmp $end_query",[],
+ $type->[3],$type->[4]);
+ }
+ if (!$result)
+ {
+ if ($types->[0] eq "odbc" && ! ($type->[2] =~ /\{fn/))
+ {
+ my $tmp= $type->[2];
+ # Check by converting to ODBC format
+ undef($limits{"func_$types->[0]_$type->[1]"});
+ $tmp= "{fn $tmp }";
+ $tmp =~ s/('1997-\d\d-\d\d \d\d:\d\d:\d\d')/{ts $1}/g;
+ $tmp =~ s/(DATE '1997-\d\d-\d\d')/{d $1}/g;
+ $tmp =~ s/(TIME '12:13:14')/{t $1}/g;
+ $tmp =~ s/DATE //;
+ $tmp =~ s/TIME //;
+ check_and_report("Function $type->[0]",
+ "func_$types->[0]_$type->[1]",
+ [],"select $tmp $end_query",[],
+ $type->[3],$type->[4]);
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+if ($limits{'functions'} eq 'yes')
+{
+ foreach $types (@group_types)
+ {
+ print "\nSupported $types->[0] group functions\n";
+ $tmp=@$types->[1];
+ foreach $type (@$tmp)
+ {
+ check_and_report("Group function $type->[0]",
+ "group_func_$types->[0]_$type->[1]",
+ [],"select $type->[2],a from crash_me group by a",[],
+ $type->[3],$type->[4]);
+ }
+ }
+ print "\n";
+ report("mixing of integer and float in expression","float_int_expr",
+ "select 1+1.0 $end_query");
+
+ check_and_report("Is 1+NULL = NULL","null_num_expr",
+ [],"select 1+$numeric_null $end_query",[],undef(),4);
+ $tmp=sql_concat("'a'",$char_null);
+ if (defined($tmp))
+ {
+ check_and_report("Is $tmp = NULL", "null_concat_expr", [],
+ "select $tmp $end_query",[], undef(),4);
+ }
+ $prompt="Need to cast NULL for arithmetic";
+ save_config_data("Need_cast_for_null",
+ ($numeric_null eq "NULL") ? "no" : "yes",
+ $prompt);
+}
+else
+{
+ print "\n";
+}
+
+
+report("LIKE on numbers","like_with_number",
+ "create table crash_q (a int,b int)",
+ "insert into crash_q values(10,10)",
+ "select * from crash_q where a like '10'",
+ "drop table crash_q");
+
+report("column LIKE column","like_with_column",
+ "create table crash_q (a char(10),b char(10))",
+ "insert into crash_q values('abc','abc')",
+ "select * from crash_q where a like b",
+ "drop table crash_q");
+
+report("update of column= -column","NEG",
+ "create table crash_q (a integer)",
+ "insert into crash_q values(10)",
+ "update crash_q set a=-a",
+ "drop table crash_q");
+
+if ($limits{'func_odbc_left'} eq 'yes' ||
+ $limits{'func_odbc_substring'} eq 'yes')
+{
+ my $type= ($limits{'func_odbc_left'} eq 'yes' ?
+ "left(a,4)" : "substring(a for 4)");
+
+ check_and_report("String functions on date columns","date_as_string",
+ ["create table crash_me2 (a date not null)",
+ "insert into crash_me2 values ('1998-03-03')"],
+ "select $type from crash_me2",
+ ["drop table crash_me2"],
+ "1998",1);
+}
+
+
+$tmp=sql_concat("b","b");
+if (defined($tmp))
+{
+ check_and_report("char are space filled","char_is_space_filled",
+ [],"select $tmp from crash_me where b = 'a '",[],
+ 'a a ',6);
+}
+
+if (!defined($limits{'multi_table_update'}))
+{
+ if (check_and_report("Update with many tables","multi_table_update",
+ ["create table crash_q (a integer,b char(10))",
+ "insert into crash_q values(1,'c')",
+ "update crash_q left join crash_me on crash_q.a=crash_me.a set crash_q.b=crash_me.b"],
+ "select b from crash_q",
+ ["drop table crash_q"],
+ "a",1,undef(),2))
+ {
+ check_and_report("Update with many tables","multi_table_update",
+ ["create table crash_q (a integer,b char(10))",
+ "insert into crash_q values(1,'c')",
+ "update crash_q,crash_me set crash_q.b=crash_me.b where crash_q.a=crash_me.a"],
+ "select b from crash_q",
+ ["drop table crash_q"],
+ "a",1,
+ 1);
+ }
+}
+
+report("DELETE FROM table1,table2...","multi_table_delete",
+ "create table crash_q (a integer,b char(10))",
+ "insert into crash_q values(1,'c')",
+ "delete crash_q.* from crash_q,crash_me where crash_q.a=crash_me.a",
+ "drop table crash_q");
+
+check_and_report("Update with sub select","select_table_update",
+ ["create table crash_q (a integer,b char(10))",
+ "insert into crash_q values(1,'c')",
+ "update crash_q set b= (select b from crash_me where crash_q.a = crash_me.a)"],
+ "select b from crash_q",
+ ["drop table crash_q"],
+ "a",1);
+
+check_and_report("Calculate 1--1","minus_neg",[],
+ "select a--1 from crash_me",[],0,2);
+
+report("ANSI SQL simple joins","simple_joins",
+ "select crash_me.a from crash_me, crash_me t0");
+
+#
+# Check max string size, and expression limits
+#
+$found=undef;
+foreach $type (('mediumtext','text','text()','blob','long'))
+{
+ if ($limits{"type_extra_$type"} eq 'yes')
+ {
+ $found=$type;
+ last;
+ }
+}
+if (defined($found))
+{
+ $found =~ s/\(\)/\(%d\)/;
+ find_limit("max text or blob size","max_text_size",
+ new query_many(["create table crash_q (q $found)",
+ "insert into crash_q values ('%s')"],
+ "select * from crash_q","%s",
+ ["drop table crash_q"],
+ min($max_string_size,$limits{'query_size'}-30)));
+
+}
+
+# It doesn't make lots of sense to check for string lengths much bigger than
+# what can be stored...
+
+find_limit(($prompt="constant string size in where"),"where_string_size",
+ new query_repeat([],"select a from crash_me where b <'",
+ "","","a","","'"));
+if ($limits{'where_string_size'} == 10)
+{
+ save_config_data('where_string_size','nonstandard',$prompt);
+}
+
+if ($limits{'select_constants'} eq 'yes')
+{
+ find_limit("constant string size in SELECT","select_string_size",
+ new query_repeat([],"select '","","","a","","'$end_query"));
+}
+
+goto no_functions if ($limits{'functions'} ne "yes");
+
+if ($limits{'func_odbc_repeat'} eq 'yes')
+{
+ find_limit("return string size from function","repeat_string_size",
+ new query_many([],
+ "select repeat('a',%d) $end_query","%s",
+ [],
+ $max_string_size,0));
+}
+
+$tmp=find_limit("simple expressions","max_expressions",
+ new query_repeat([],"select 1","","","+1","",$end_query,
+ undef(),$max_expressions));
+
+if ($tmp > 10)
+{
+ $tmp= "(1" . ( '+1' x ($tmp-10) ) . ")";
+ find_limit("big expressions", "max_big_expressions",
+ new query_repeat([],"select 0","","","+$tmp","",$end_query,
+ undef(),$max_big_expressions));
+}
+
+find_limit("stacked expressions", "max_stack_expression",
+ new query_repeat([],"select 1","","","+(1",")",$end_query,
+ undef(),$max_stacked_expressions));
+
+no_functions:
+
+if (!defined($limits{'max_conditions'}))
+{
+ find_limit("OR and AND in WHERE","max_conditions",
+ new query_repeat([],
+ "select a from crash_me where a=1 and b='a'","",
+ "", " or a=%d and b='%d'","","","",
+ [],($query_size-42)/29,undef,2));
+ $limits{'max_conditions'}*=2;
+}
+# The 42 is the length of the constant part.
+# The 29 is the length of the variable part, plus two seven-digit numbers.
+
+find_limit("tables in join", "join_tables",
+ new query_repeat([],
+ "select crash_me.a",",t%d.a","from crash_me",
+ ",crash_me t%d","","",[],$max_join_tables,undef,
+ 1));
+
+# Different CREATE TABLE options
+
+report("primary key in create table",'primary_key_in_create',
+ "create table crash_q (q integer not null,primary key (q))",
+ "drop table crash_q");
+
+report("unique in create table",'unique_in_create',
+ "create table crash_q (q integer not null,unique (q))",
+ "drop table crash_q");
+
+if ($limits{'unique_in_create'} eq 'yes')
+{
+ report("unique null in create",'unique_null_in_create',
+ "create table crash_q (q integer,unique (q))",
+ "insert into crash_q (q) values (NULL)",
+ "insert into crash_q (q) values (NULL)",
+ "insert into crash_q (q) values (1)",
+ "drop table crash_q");
+}
+
+report("default value for column",'create_default',
+ "create table crash_q (q integer default 10 not null)",
+ "drop table crash_q");
+
+report("default value function for column",'create_default_func',
+ "create table crash_q (q integer not null,q1 integer default (1+1)",
+ "drop table crash_q");
+
+report("temporary tables",'tempoary_table',
+ "create temporary table crash_q (q integer not null)",
+ "drop table crash_q");
+
+report("create table from select",'create_table_select',
+ "create table crash_q SELECT * from crash_me",
+ "drop table crash_q");
+
+report("index in create table",'index_in_create',
+ "create table crash_q (q integer not null,index (q))",
+ "drop table crash_q");
+
+# The following must be executed as we need the value of end_drop_keyword
+# later
+if (! defined($limits{'create_index'}) &&
+ ! defined($limits{'drop_index'}) )
+{
+ if ($res=safe_query("create index crash_q on crash_me (a)"))
+ {
+ $res="yes";
+ $drop_res="yes";
+ $end_drop_keyword="";
+ if (!safe_query("drop index crash_q"))
+ {
+ # Can't drop the standard way; Check if mSQL
+ if (safe_query("drop index crash_q from crash_me"))
+ {
+ $drop_res="with 'FROM'"; # Drop is not ANSI SQL
+ $end_drop_keyword="drop index %i from %t";
+ }
+ # else check if Access or MySQL
+ elsif (safe_query("drop index crash_q on crash_me"))
+ {
+ $drop_res="with 'ON'"; # Drop is not ANSI SQL
+ $end_drop_keyword="drop index %i on %t";
+ }
+ # else check if MS-SQL
+ elsif (safe_query("drop index crash_me.crash_q"))
+ {
+ $drop_res="with 'table.index'"; # Drop is not ANSI SQL
+ $end_drop_keyword="drop index %t.%i";
+ }
+ }
+ else
+ {
+ # Old MySQL 3.21 supports only the create index syntax
+ # This means that the second create doesn't give an error.
+ $res=safe_query(["create index crash_q on crash_me (a)",
+ "create index crash_q on crash_me (a)",
+ "drop index crash_q"]);
+ $res= $res ? 'ignored' : 'yes';
+ }
+ }
+ else
+ {
+ $drop_res=$res='no';
+ }
+ save_config_data('create_index',$res,"create index");
+ save_config_data('drop_index',$drop_res,"drop index");
+
+ print "create index: $limits{'create_index'}\n";
+ print "drop index: $limits{'drop_index'}\n";
+}
+
+# check if we can have 'NULL' as a key
+check_and_report("null in index","null_in_index",
+ [create_table("crash_q",["a char(10)"],["(a)"]),
+ "insert into crash_q values (NULL)"],
+ "select * from crash_q",
+ ["drop table crash_q"],
+ undef(),4);
+
+if ($limits{'unique_in_create'} eq 'yes')
+{
+ report("null in unique index",'null_in_unique',
+ create_table("crash_q",["q integer"],["unique(q)"]),
+ "insert into crash_q (q) values(NULL)",
+ "insert into crash_q (q) values(NULL)",
+ "drop table crash_q");
+}
+
+if ($limits{'null_in_unique'} eq 'yes')
+{
+ report("null in unique index",'multi_null_in_unique',
+ create_table("crash_q",["q integer, x integer"],["unique(q)"]),
+ "insert into crash_q(x) values(1)",
+ "insert into crash_q(x) values(2)",
+ "drop table crash_q");
+}
+
+if ($limits{'create_index'} ne 'no')
+{
+ $end_drop=$end_drop_keyword;
+ $end_drop =~ s/%i/crash_q/;
+ $end_drop =~ s/%t/crash_me/;
+ report("index on column part (extension)","index_parts",,
+ "create index crash_q on crash_me (b(5))",
+ $end_drop);
+ $end_drop=$end_drop_keyword;
+ $end_drop =~ s/%i/crash_me/;
+ $end_drop =~ s/%t/crash_me/;
+ report("different namespace for index",
+ "index_namespace",
+ "create index crash_me on crash_me (b)",
+ $end_drop);
+}
+
+if (!report("case independent table names","table_name_case",
+ "create table crash_q (q integer)",
+ "drop table CRASH_Q"))
+{
+ safe_query("drop table crash_q");
+}
+
+if (!report("drop table if exists","drop_if_exists",
+ "create table crash_q (q integer)",
+ "drop table if exists crash_q"))
+{
+ safe_query("drop table crash_q");
+}
+
+report("create table if not exists","create_if_not_exists",
+ "create table crash_q (q integer)",
+ "create table if not exists crash_q (q integer)");
+safe_query("drop table crash_q");
+
+#
+# test of different join types
+#
+
+assert("create table crash_me2 (a integer not null,b char(10) not null, c integer)");
+assert("insert into crash_me2 (a,b,c) values (1,'b',1)");
+assert("create table crash_me3 (a integer not null,b char(10) not null)");
+assert("insert into crash_me3 (a,b) values (1,'b')");
+
+report("inner join","inner_join",
+ "select crash_me.a from crash_me inner join crash_me2 ON crash_me.a=crash_me2.a");
+report("left outer join","left_outer_join",
+ "select crash_me.a from crash_me left join crash_me2 ON crash_me.a=crash_me2.a");
+report("natural left outer join","natural_left_outer_join",
+ "select c from crash_me natural left join crash_me2");
+report("left outer join using","left_outer_join_using",
+ "select c from crash_me left join crash_me2 using (a)");
+report("left outer join odbc style","odbc_left_outer_join",
+ "select crash_me.a from { oj crash_me left outer join crash_me2 ON crash_me.a=crash_me2.a }");
+report("right outer join","right_outer_join",
+ "select crash_me.a from crash_me right join crash_me2 ON crash_me.a=crash_me2.a");
+report("full outer join","full_outer_join",
+ "select crash_me.a from crash_me full join crash_me2 ON crash_me.a=crash_me2.a");
+report("cross join (same as from a,b)","cross_join",
+ "select crash_me.a from crash_me cross join crash_me3");
+report("natural join","natural_join",
+ "select * from crash_me natural join crash_me3");
+report("union","union",
+ "select * from crash_me union select a,b from crash_me3");
+report("union all","union_all",
+ "select * from crash_me union all select a,b from crash_me3");
+report("intersect","intersect",
+ "select * from crash_me intersect select * from crash_me3");
+report("intersect all","intersect_all",
+ "select * from crash_me intersect all select * from crash_me3");
+report("except","except",
+ "select * from crash_me except select * from crash_me3");
+report("except all","except_all",
+ "select * from crash_me except all select * from crash_me3");
+report("except","except",
+ "select * from crash_me except select * from crash_me3");
+report("except all","except_all",
+ "select * from crash_me except all select * from crash_me3");
+report("minus","minus",
+ "select * from crash_me minus select * from crash_me3"); # oracle ...
+
+report("natural join (incompatible lists)","natural_join_incompat",
+ "select c from crash_me natural join crash_me2");
+report("union (incompatible lists)","union_incompat",
+ "select * from crash_me union select a,b from crash_me2");
+report("union all (incompatible lists)","union_all_incompat",
+ "select * from crash_me union all select a,b from crash_me2");
+report("intersect (incompatible lists)","intersect_incompat",
+ "select * from crash_me intersect select * from crash_me2");
+report("intersect all (incompatible lists)","intersect_all_incompat",
+ "select * from crash_me intersect all select * from crash_me2");
+report("except (incompatible lists)","except_incompat",
+ "select * from crash_me except select * from crash_me2");
+report("except all (incompatible lists)","except_all_incompat",
+ "select * from crash_me except all select * from crash_me2");
+report("except (incompatible lists)","except_incompat",
+ "select * from crash_me except select * from crash_me2");
+report("except all (incompatible lists)","except_all_incompat",
+ "select * from crash_me except all select * from crash_me2");
+report("minus (incompatible lists)","minus_incompat",
+ "select * from crash_me minus select * from crash_me2"); # oracle ...
+
+assert("drop table crash_me2");
+assert("drop table crash_me3");
+
+# somethings to be added here ....
+# FOR UNION - INTERSECT - EXCEPT -> CORRESPONDING [ BY ]
+# after subqueries:
+# >ALL | ANY | SOME - EXISTS - UNIQUE
+
+if (report("subqueries","subqueries",
+ "select a from crash_me where crash_me.a in (select max(a) from crash_me)"))
+{
+ $tmp=new query_repeat([],"select a from crash_me","","",
+ " where a in (select a from crash_me",")",
+ "",[],$max_join_tables);
+ find_limit("recursive subqueries", "recursive_subqueries",$tmp);
+}
+
+report("insert INTO ... SELECT ...","insert_select",
+ "create table crash_q (a int)",
+ "insert into crash_q (a) SELECT crash_me.a from crash_me",
+ "drop table crash_q");
+
+report_trans("transactions","transactions",
+ [create_table("crash_q",["a integer not null"],[]),
+ "insert into crash_q values (1)"],
+ "select * from crash_q",
+ "drop table crash_q"
+ );
+
+report("atomic updates","atomic_updates",
+ create_table("crash_q",["a integer not null"],["primary key (a)"]),
+ "insert into crash_q values (2)",
+ "insert into crash_q values (3)",
+ "insert into crash_q values (1)",
+ "update crash_q set a=a+1",
+ "drop table crash_q");
+
+if ($limits{'atomic_updates'} eq 'yes')
+{
+ report_fail("atomic_updates_with_rollback","atomic_updates_with_rollback",
+ create_table("crash_q",["a integer not null"],
+ ["primary key (a)"]),
+ "insert into crash_q values (2)",
+ "insert into crash_q values (3)",
+ "insert into crash_q values (1)",
+ "update crash_q set a=a+1 where a < 3",
+ "drop table crash_q");
+}
+
+# To add with the views:
+# DROP VIEW - CREAT VIEW *** [ WITH [ CASCADE | LOCAL ] CHECK OPTION ]
+report("views","views",
+ "create view crash_q as select a from crash_me",
+ "drop view crash_q");
+
+report("foreign key syntax","foreign_key_syntax",
+ create_table("crash_q",["a integer not null"],["primary key (a)"]),
+ create_table("crash_q2",["a integer not null",
+ "foreign key (a) references crash_q (a)"],
+ []),
+ "insert into crash_q values (1)",
+ "insert into crash_q2 values (1)",
+ "drop table crash_q2",
+ "drop table crash_q");
+
+if ($limits{'foreign_key_syntax'} eq 'yes')
+{
+ report_fail("foreign keys","foreign_key",
+ create_table("crash_q",["a integer not null"],
+ ["primary key (a)"]),
+ create_table("crash_q2",["a integer not null",
+ "foreign key (a) references crash_q (a)"],
+ []),
+ "insert into crash_q values (1)",
+ "insert into crash_q2 values (2)",
+ "drop table crash_q2",
+ "drop table crash_q");
+}
+
+report("Create SCHEMA","create_schema",
+ "create schema crash_schema create table crash_q (a int) create table crash_q2(b int)",
+ "drop schema crash_schema cascade");
+
+if ($limits{'foreign_key'} eq 'yes')
+{
+ if ($limits{'create_schema'} eq 'yes')
+ {
+ report("Circular foreign keys","foreign_key_circular",
+ "create schema crash_schema create table crash_q (a int primary key, b int, foreign key (b) references crash_q2(a)) create table crash_q2(a int, b int, primary key(a), foreign key (b) references crash_q(a))",
+ "drop schema crash_schema cascade");
+ }
+}
+
+report("Column constraints","constraint_check",
+ "create table crash_q (a int check (a>0))",
+ "drop table crash_q");
+
+report("Table constraints","constraint_check_table",
+ "create table crash_q (a int ,b int, check (a>b))",
+ "drop table crash_q");
+
+report("Named constraints","constraint_check",
+ "create table crash_q (a int ,b int, constraint abc check (a>b))",
+ "drop table crash_q");
+
+report("NULL constraint (SyBase style)","constraint_null",
+ "create table crash_q (a int null)",
+ "drop table crash_q");
+
+report("Triggers (ANSI SQL)","psm_trigger",
+ "create table crash_q (a int ,b int)",
+ "create trigger crash_trigger after insert on crash_q referencing new table as new_a when (localtime > time '18:00:00') begin atomic end",
+ "insert into crash_q values(1,2)",
+ "drop trigger crash_trigger",
+ "drop table crash_q");
+
+report("PSM procedures (ANSI SQL)","psm_procedures",
+ "create table crash_q (a int,b int)",
+ "create procedure crash_proc(in a1 int, in b1 int) language sql modifies sql data begin declare c1 int; set c1 = a1 + b1; insert into crash_q(a,b) values (a1,c1); end",
+ "call crash_proc(1,10)",
+ "drop procedure crash_proc",
+ "drop table crash_q");
+
+report("PSM modules (ANSI SQL)","psm_modules",
+ "create table crash_q (a int,b int)",
+ "create module crash_m declare procedure crash_proc(in a1 int, in b1 int) language sql modifies sql data begin declare c1 int; set c1 = a1 + b1; insert into crash_q(a,b) values (a1,c1); end; declare procedure crash_proc2(INOUT a int, in b int) contains sql set a = b + 10; end module",
+ "call crash_proc(1,10)",
+ "drop module crash_m cascade",
+ "drop table crash_q cascade");
+
+report("PSM functions (ANSI SQL)","psm_functions",
+ "create table crash_q (a int)",
+ "create function crash_func(in a1 int, in b1 int) returns int language sql deterministic contains sql begin return a1 * b1; end",
+ "insert into crash_q values(crash_func(2,4))",
+ "select a,crash_func(a,2) from crash_q",
+ "drop function crash_func cascade",
+ "drop table crash_q");
+
+report("Domains (ANSI SQL)","domains",
+ "create domain crash_d as varchar(10) default 'Empty' check (value <> 'abcd')",
+ "create table crash_q(a crash_d, b int)",
+ "insert into crash_q(a,b) values('xyz',10)",
+ "insert into crash_q(b) values(10)",
+ "drop table crash_q",
+ "drop domain crash_d");
+
+
+if (!defined($limits{'lock_tables'}))
+{
+ report("lock table","lock_tables",
+ "lock table crash_me READ",
+ "unlock tables");
+ if ($limits{'lock_tables'} eq 'no')
+ {
+ delete $limits{'lock_tables'};
+ report("lock table","lock_tables",
+ "lock table crash_me IN SHARE MODE");
+ }
+}
+
+if (!report("many tables to drop table","multi_drop",
+ "create table crash_q (a int)",
+ "create table crash_q2 (a int)",
+ "drop table crash_q,crash_q2"))
+{
+ $dbh->do("drop table crash_q");
+ $dbh->do("drop table crash_q2");
+}
+
+
+report("-- as comment","comment_--",
+ "select * from crash_me -- Testing of comments");
+report("// as comment","comment_//",
+ "select * from crash_me // Testing of comments");
+report("# as comment","comment_#",
+ "select * from crash_me # Testing of comments");
+report("/* */ as comment","comment_/**/",
+ "select * from crash_me /* Testing of comments */");
+
+#
+# Check things that fails one some servers
+#
+
+# Empress can't insert empty strings in a char() field
+report("insert empty string","insert_empty_string",
+ create_table("crash_q",["a char(10) not null,b char(10)"],[]),
+ "insert into crash_q values ('','')",
+ "drop table crash_q");
+
+report("Having with alias","having_with_alias",
+ create_table("crash_q",["a integer"],[]),
+ "insert into crash_q values (10)",
+ "select sum(a) as b from crash_q group by a having b > 0",
+ "drop table crash_q");
+
+#
+# test name limits
+#
+
+find_limit("table name length","max_table_name",
+ new query_many(["create table crash_q%s (q integer)",
+ "insert into crash_q%s values(1)"],
+ "select * from crash_q%s",1,
+ ["drop table crash_q%s"],
+ $max_name_length,7,1));
+
+find_limit("column name length","max_column_name",
+ new query_many(["create table crash_q (q%s integer)",
+ "insert into crash_q (q%s) values(1)"],
+ "select q%s from crash_q",1,
+ ["drop table crash_q"],
+ $max_name_length,1));
+
+if ($limits{'column_alias'} eq 'yes')
+{
+ find_limit("select alias name length","max_select_alias_name",
+ new query_many(undef,
+ "select b as %s from crash_me",undef,
+ undef, $max_name_length));
+}
+
+find_limit("table alias name length","max_table_alias_name",
+ new query_many(undef,
+ "select %s.b from crash_me %s",
+ undef,
+ undef, $max_name_length));
+
+$end_drop_keyword = "drop index %i" if (!$end_drop_keyword);
+$end_drop=$end_drop_keyword;
+$end_drop =~ s/%i/crash_q%s/;
+$end_drop =~ s/%t/crash_me/;
+
+if ($limits{'create_index'} ne 'no')
+{
+ find_limit("index name length","max_index_name",
+ new query_many(["create index crash_q%s on crash_me (a)"],
+ undef,undef,
+ [$end_drop],
+ $max_name_length,7));
+}
+
+find_limit("max char() size","max_char_size",
+ new query_many(["create table crash_q (q char(%d))",
+ "insert into crash_q values ('%s')"],
+ "select * from crash_q","%s",
+ ["drop table crash_q"],
+ min($max_string_size,$limits{'query_size'})));
+
+if ($limits{'type_sql_varchar(1_arg)'} eq 'yes')
+{
+ find_limit("max varchar() size","max_varchar_size",
+ new query_many(["create table crash_q (q varchar(%d))",
+ "insert into crash_q values ('%s')"],
+ "select * from crash_q","%s",
+ ["drop table crash_q"],
+ min($max_string_size,$limits{'query_size'})));
+}
+
+$found=undef;
+foreach $type (('mediumtext','text','text()','blob','long'))
+{
+ if ($limits{"type_extra_$type"} eq 'yes')
+ {
+ $found=$type;
+ last;
+ }
+}
+if (defined($found))
+{
+ $found =~ s/\(\)/\(%d\)/;
+ find_limit("max text or blob size","max_text_size",
+ new query_many(["create table crash_q (q $found)",
+ "insert into crash_q values ('%s')"],
+ "select * from crash_q","%s",
+ ["drop table crash_q"],
+ min($max_string_size,$limits{'query_size'}-30)));
+
+}
+
+$tmp=new query_repeat([],"create table crash_q (a integer","","",
+ ",a%d integer","",")",["drop table crash_q"],
+ $max_columns);
+$tmp->{'offset'}=1;
+find_limit("Columns in table","max_columns",$tmp);
+
+# Make a field definition to be used when testing keys
+
+$key_definitions="q0 integer not null";
+$key_fields="q0";
+for ($i=1; $i < min($limits{'max_columns'},$max_keys) ; $i++)
+{
+ $key_definitions.=",q$i integer not null";
+ $key_fields.=",q$i";
+}
+$key_values="1," x $i;
+chop($key_values);
+
+if ($limits{'unique_in_create'} eq 'yes')
+{
+ find_limit("unique indexes","max_unique_index",
+ new query_table("create table crash_q (q integer",
+ ",q%d integer not null,unique (q%d)",")",
+ ["insert into crash_q (q,%f) values (1,%v)"],
+ "select q from crash_q",1,
+ "drop table crash_q",
+ $max_keys,0));
+
+ find_limit("index parts","max_index_parts",
+ new query_table("create table crash_q ($key_definitions,unique (q0",
+ ",q%d","))",
+ ["insert into crash_q ($key_fields) values ($key_values)"],
+ "select q0 from crash_q",1,
+ "drop table crash_q",
+ $max_keys,1));
+
+ find_limit("max index part length","max_index_part_length",
+ new query_many(["create table crash_q (q char(%d) not null,unique(q))",
+ "insert into crash_q (q) values ('%s')"],
+ "select q from crash_q","%s",
+ ["drop table crash_q"],
+ $limits{'max_char_size'},0));
+
+ if ($limits{'type_sql_varchar(1_arg)'} eq 'yes')
+ {
+ find_limit("index varchar part length","max_index_varchar_part_length",
+ new query_many(["create table crash_q (q varchar(%d) not null,unique(q))",
+ "insert into crash_q (q) values ('%s')"],
+ "select q from crash_q","%s",
+ ["drop table crash_q"],
+ $limits{'max_varchar_size'},0));
+ }
+}
+
+
+if ($limits{'create_index'} ne 'no')
+{
+ if ($limits{'create_index'} eq 'ignored' ||
+ $limits{'unique_in_create'} eq 'yes')
+ { # This should be true
+ save_config_data('max_index',$limits{'max_unique_index'},"max index");
+ print "indexes: $limits{'max_index'}\n";
+ }
+ else
+ {
+ if (!defined($limits{'max_index'}))
+ {
+ assert("create table crash_q ($key_definitions)");
+ for ($i=1; $i <= min($limits{'max_columns'},$max_keys) ; $i++)
+ {
+ last if (!safe_query("create index crash_q$i on crash_q (q$i)"));
+ }
+ save_config_data('max_index',$i == $max_keys ? $max_keys : $i,
+ "max index");
+ while ( --$i > 0)
+ {
+ $end_drop=$end_drop_keyword;
+ $end_drop =~ s/%i/crash_q$i/;
+ $end_drop =~ s/%t/crash_q/;
+ assert($end_drop);
+ }
+ assert("drop table crash_q");
+ }
+ print "indexs: $limits{'max_index'}\n";
+ if (!defined($limits{'max_unique_index'}))
+ {
+ assert("create table crash_q ($key_definitions)");
+ for ($i=0; $i < min($limits{'max_columns'},$max_keys) ; $i++)
+ {
+ last if (!safe_query("create unique index crash_q$i on crash_q (q$i)"));
+ }
+ save_config_data('max_unique_index',$i == $max_keys ? $max_keys : $i,
+ "max unique index");
+ while ( --$i >= 0)
+ {
+ $end_drop=$end_drop_keyword;
+ $end_drop =~ s/%i/crash_q$i/;
+ $end_drop =~ s/%t/crash_q/;
+ assert($end_drop);
+ }
+ assert("drop table crash_q");
+ }
+ print "unique indexes: $limits{'max_unique_index'}\n";
+ if (!defined($limits{'max_index_parts'}))
+ {
+ assert("create table crash_q ($key_definitions)");
+ $end_drop=$end_drop_keyword;
+ $end_drop =~ s/%i/crash_q1%d/;
+ $end_drop =~ s/%t/crash_q/;
+ find_limit("index parts","max_index_parts",
+ new query_table("create index crash_q1%d on crash_q (q0",
+ ",q%d",")",
+ [],
+ undef,undef,
+ $end_drop,
+ $max_keys,1));
+ assert("drop table crash_q");
+ }
+ else
+ {
+ print "index parts: $limits{'max_index_parts'}\n";
+ }
+ $end_drop=$end_drop_keyword;
+ $end_drop =~ s/%i/crash_q2%d/;
+ $end_drop =~ s/%t/crash_me/;
+
+ find_limit("index part length","max_index_part_length",
+ new query_many(["create table crash_q (q char(%d))",
+ "create index crash_q2%d on crash_q (q)",
+ "insert into crash_q values('%s')"],
+ "select q from crash_q",
+ "%s",
+ [ $end_drop,
+ "drop table crash_q"],
+ min($limits{'max_char_size'},"+8192")));
+ }
+}
+
+find_limit("index length","max_index_length",
+ new query_index_length("create table crash_q ",
+ "drop table crash_q",
+ $max_key_length));
+
+find_limit("max table row length (without blobs)","max_row_length",
+ new query_row_length("crash_q ",
+ "not null",
+ "drop table crash_q",
+ min($max_row_length,
+ $limits{'max_columns'}*
+ min($limits{'max_char_size'},255))));
+
+find_limit("table row length with nulls (without blobs)",
+ "max_row_length_with_null",
+ new query_row_length("crash_q ",
+ "",
+ "drop table crash_q",
+ $limits{'max_row_length'}*2));
+
+find_limit("number of columns in order by","columns_in_order_by",
+ new query_many(["create table crash_q (%F)",
+ "insert into crash_q values(%v)",
+ "insert into crash_q values(%v)"],
+ "select * from crash_q order by %f",
+ undef(),
+ ["drop table crash_q"],
+ $max_order_by));
+
+find_limit("number of columns in group by","columns_in_group_by",
+ new query_many(["create table crash_q (%F)",
+ "insert into crash_q values(%v)",
+ "insert into crash_q values(%v)"],
+ "select %f from crash_q group by %f",
+ undef(),
+ ["drop table crash_q"],
+ $max_order_by));
+
+#
+# End of test
+#
+
+$dbh->do("drop table crash_me"); # Remove temporary table
+
+print "crash-me safe: $limits{'crash_me_safe'}\n";
+print "reconnected $reconnect_count times\n";
+
+$dbh->disconnect || warn $dbh->errstr;
+save_all_config_data();
+exit 0;
+
+sub usage
+{
+ print <<EOF;
+$0 Ver $version
+
+This program tries to find all limits and capabilities for a SQL
+server. As it will use the server in some 'unexpected' ways, one
+shouldn\'t have anything important running on it at the same time this
+program runs! There is a slight chance that something unexpected may
+happen....
+
+As all used queries are legal according to some SQL standard. any
+reasonable SQL server should be able to run this test without any
+problems.
+
+All questions is cached in $opt_dir/'server_name'.cfg that future runs will use
+limits found in previous runs. Remove this file if you want to find the
+current limits for your version of the database server.
+
+This program uses some table names while testing things. If you have any
+tables with the name of 'crash_me' or 'crash_qxxxx' where 'x' is a number,
+they will be deleted by this test!
+
+$0 takes the following options:
+
+--help or --Information
+ Shows this help
+
+--batch-mode
+ Don\'t ask any questions, quit on errors.
+
+--comment='some comment'
+ Add this comment to the crash-me limit file
+
+--database='database' (Default $opt_database)
+ Create test tables in this database.
+
+--dir='limits'
+ Save crash-me output in this directory
+
+--debug
+ Lots of printing to help debugging if something goes wrong.
+
+--fix-limit-file
+ Reformat the crash-me limit file. crash-me is not run!
+
+--force
+ Start test at once, without a warning screen and without questions.
+ This is a option for the very brave.
+ Use this in your cron scripts to test your database every night.
+
+--log-all-queries
+ Prints all queries that are executed. Mostly used for debugging crash-me.
+
+--log-queries-to-file='filename'
+ Log full queries to file.
+
+--host='hostname' (Default $opt_host)
+ Run tests on this host.
+
+--password='password'
+ Password for the current user.
+
+--restart
+ Save states during each limit tests. This will make it possible to continue
+ by restarting with the same options if there is some bug in the DBI or
+ DBD driver that caused $0 to die!
+
+--server='server name' (Default $opt_server)
+ Run the test on the given server.
+ Known servers names are: Access, Adabas, AdabasD, Empress, Oracle, Informix, DB2, Mimer, mSQL, MS-SQL, MySQL, Pg, Solid or Sybase.
+ For others $0 can\'t report the server version.
+
+--user='user_name'
+ User name to log into the SQL server.
+
+--start-cmd='command to restart server'
+ Automaticly restarts server with this command if the server dies.
+
+--sleep='time in seconds' (Default $opt_sleep)
+ Wait this long before restarting server.
+
+EOF
+ exit(0);
+}
+
+
+sub server_info
+{
+ my ($ok,$tmp);
+ $ok=0;
+ print "\nNOTE: You should be familiar with '$0 --help' before continuing!\n\n";
+ if (lc($opt_server) eq "mysql")
+ {
+ $ok=1;
+ print <<EOF;
+This test should not crash MySQL if it was distributed together with the
+running MySQL version.
+If this is the case you can probably continue without having to worry about
+destroying something.
+EOF
+ }
+ elsif (lc($opt_server) eq "msql")
+ {
+ print <<EOF;
+This test will take down mSQL repeatedly while finding limits.
+To make this test easier, start mSQL in another terminal with something like:
+
+while (true); do /usr/local/mSQL/bin/msql2d ; done
+
+You should be sure that no one is doing anything important with mSQL and that
+you have privileges to restart it!
+It may take awhile to determinate the number of joinable tables, so prepare to
+wait!
+EOF
+ }
+ elsif (lc($opt_server) eq "solid")
+ {
+ print <<EOF;
+This test will take down Solid server repeatedly while finding limits.
+You should be sure that no one is doing anything important with Solid
+and that you have privileges to restart it!
+
+If you are running Solid without logging and/or backup YOU WILL LOSE!
+Solid does not write data from the cache often enough. So if you continue
+you may lose tables and data that you entered hours ago!
+
+Solid will also take a lot of memory running this test. You will nead
+at least 234M free!
+
+When doing the connect test Solid server or the perl api will hang when
+freeing connections. Kill this program and restart it to continue with the
+test. You don\'t have to use --restart for this case.
+EOF
+ if (!$opt_restart)
+ {
+ print "\nWhen DBI/Solid dies you should run this program repeatedly\n";
+ print "with --restart until all tests have completed\n";
+ }
+ }
+ elsif (lc($opt_server) eq "pg")
+ {
+ print <<EOF;
+This test will crash postgreSQL when calculating the number of joinable tables!
+You should be sure that no one is doing anything important with postgreSQL
+and that you have privileges to restart it!
+EOF
+ }
+ else
+ {
+ print <<EOF;
+This test may crash $opt_server repeatedly while finding limits!
+You should be sure that no one is doing anything important with $opt_server
+and that you have privileges to restart it!
+EOF
+ }
+ print <<EOF;
+
+Some of the tests you are about to execute may require a lot of
+memory. Your tests WILL adversely affect system performance. It's
+not uncommon that either this crash-me test program, or the actual
+database back-end, will DIE with an out-of-memory error. So might
+any other program on your system if it requests more memory at the
+wrong time.
+
+Note also that while crash-me tries to find limits for the database server
+it will make a lot of queries that can't be categorized as 'normal'. It's
+not unlikely that crash-me finds some limit bug in your server so if you
+run this test you have to be prepared that your server may die during it!
+
+We, the creators of this utility, are not responsible in any way if your
+database server unexpectedly crashes while this program tries to find the
+limitations of your server. By accepting the following question with 'yes',
+you agree to the above!
+
+You have been warned!
+
+EOF
+
+ #
+ # No default reply here so no one can blame us for starting the test
+ # automaticly.
+ #
+ for (;;)
+ {
+ print "Start test (yes/no) ? ";
+ $tmp=<STDIN>; chomp($tmp); $tmp=lc($tmp);
+ last if ($tmp =~ /^yes$/i);
+ exit 1 if ($tmp =~ /^n/i);
+ print "\n";
+ }
+}
+
+sub machine
+{
+ $name= `uname -s -r -m`;
+ if ($?)
+ {
+ $name= `uname -s -m`;
+ }
+ if ($?)
+ {
+ $name= `uname -s`;
+ }
+ if ($?)
+ {
+ $name= `uname`;
+ }
+ if ($?)
+ {
+ $name="unknown";
+ }
+ chomp($name); $name =~ s/[\n\r]//g;
+ return $name;
+}
+
+
+#
+# Help functions that we need
+#
+
+sub safe_connect
+{
+ my ($object)=@_;
+ my ($dbh,$tmp);
+
+ for (;;)
+ {
+ if (($dbh=DBI->connect($server->{'data_source'},$opt_user,$opt_password,
+ { PrintError => 0, AutoCommit => 1})))
+ {
+ $dbh->{LongReadLen}= 16000000; # Set max retrieval buffer
+ return $dbh;
+ }
+ print "Error: $DBI::errstr; $server->{'data_source'} - '$opt_user' - '$opt_password'\n";
+ print "I got the above error when connecting to $opt_server\n";
+ if (defined($object) && defined($object->{'limit'}))
+ {
+ print "This check was done with limit: $object->{'limit'}.\nNext check will be done with a smaller limit!\n";
+ $object=undef();
+ }
+ save_config_data('crash_me_safe','no',"crash me safe");
+ if ($opt_db_start_cmd)
+ {
+ print "Restarting the db server with:\n'$opt_db_start_cmd'\n";
+ system("$opt_db_start_cmd");
+ print "Waiting $opt_sleep seconds so the server can initialize\n";
+ sleep $opt_sleep;
+ }
+ else
+ {
+ exit(1) if ($opt_batch_mode);
+ print "Can you check/restart it so I can continue testing?\n";
+ for (;;)
+ {
+ print "Continue test (yes/no) ? [yes] ";
+ $tmp=<STDIN>; chomp($tmp); $tmp=lc($tmp);
+ $tmp = "yes" if ($tmp eq "");
+ last if (index("yes",$tmp) >= 0);
+ exit 1 if (index("no",$tmp) >= 0);
+ print "\n";
+ }
+ }
+ }
+}
+
+#
+# Check if the server is upp and running. If not, ask the user to restart it
+#
+
+sub check_connect
+{
+ my ($object)=@_;
+ my ($sth);
+ print "Checking connection\n" if ($opt_log_all_queries);
+ # The following line will not work properly with interbase
+ return if (defined($check_connect) && defined($dbh->do($check_connect)));
+ $dbh->disconnect || warn $dbh->errstr;
+ print "\nreconnecting\n" if ($opt_debug);
+ $reconnect_count++;
+ undef($dbh);
+ $dbh=safe_connect($object);
+}
+
+#
+# print query if debugging
+#
+sub print_query
+{
+ my ($query)=@_;
+ $last_error=$DBI::errstr;
+ if ($opt_debug)
+ {
+ if (length($query) > 130)
+ {
+ $query=substr($query,0,120) . "...(" . (length($query)-120) . ")";
+ }
+ printf "\nGot error from query: '%s'\n%s\n",$query,$DBI::errstr;
+ }
+}
+
+#
+# Do one or many queries. Return 1 if all was ok
+# Note that all rows are executed (to ensure that we execute drop table commands)
+#
+
+sub safe_query
+{
+ my($queries)=@_;
+ my($query,$ok,$retry_ok,$retry,@tmp,$sth);
+ $ok=1;
+ if (ref($queries) ne "ARRAY")
+ {
+ push(@tmp,$queries);
+ $queries= \@tmp;
+ }
+ foreach $query (@$queries)
+ {
+ printf "query1: %-80.80s ...(%d - %d)\n",$query,length($query),$retry_limit if ($opt_log_all_queries);
+ print LOG "$query;\n" if ($opt_log);
+ if (length($query) > $query_size)
+ {
+ $ok=0;
+ next;
+ }
+
+ $retry_ok=0;
+ for ($retry=0; $retry < $retry_limit ; $retry++)
+ {
+ if (! ($sth=$dbh->prepare($query)))
+ {
+ print_query($query);
+ $retry=100 if (!$server->abort_if_fatal_error());
+ # Force a reconnect because of Access drop table bug!
+ if ($retry == $retry_limit-2)
+ {
+ print "Forcing disconnect to retry query\n" if ($opt_debug);
+ $dbh->disconnect || warn $dbh->errstr;
+ }
+ check_connect(); # Check that server is still up
+ }
+ else
+ {
+ if (!$sth->execute())
+ {
+ print_query($query);
+ $retry=100 if (!$server->abort_if_fatal_error());
+ # Force a reconnect because of Access drop table bug!
+ if ($retry == $retry_limit-2)
+ {
+ print "Forcing disconnect to retry query\n" if ($opt_debug);
+ $dbh->disconnect || warn $dbh->errstr;
+ }
+ check_connect(); # Check that server is still up
+ }
+ else
+ {
+ $retry = $retry_limit;
+ $retry_ok = 1;
+ }
+ $sth->finish;
+ }
+ }
+ $ok=0 if (!$retry_ok);
+ if ($query =~ /create/i && $server->reconnect_on_errors())
+ {
+ print "Forcing disconnect to retry query\n" if ($opt_debug);
+ $dbh->disconnect || warn $dbh->errstr;
+ $dbh=safe_connect();
+ }
+ }
+ return $ok;
+}
+
+
+#
+# Do a query on a query package object.
+#
+
+sub limit_query
+{
+ my($object,$limit)=@_;
+ my ($query,$result,$retry,$sth);
+
+ $query=$object->query($limit);
+ $result=safe_query($query);
+ if (!$result)
+ {
+ $object->cleanup();
+ return 0;
+ }
+ if (defined($query=$object->check_query()))
+ {
+ for ($retry=0 ; $retry < $retry_limit ; $retry++)
+ {
+ printf "query2: %-80.80s\n",$query if ($opt_log_all_queries);
+ print LOG "$query;\n" if ($opt_log);
+ if (($sth= $dbh->prepare($query)))
+ {
+ if ($sth->execute)
+ {
+ $result= $object->check($sth);
+ $sth->finish;
+ $object->cleanup();
+ return $result;
+ }
+ print_query($query);
+ $sth->finish;
+ }
+ else
+ {
+ print_query($query);
+ }
+ $retry=100 if (!$server->abort_if_fatal_error()); # No need to continue
+ if ($retry == $retry_limit-2)
+ {
+ print "Forcing discoennect to retry query\n" if ($opt_debug);
+ $dbh->disconnect || warn $dbh->errstr;
+ }
+ check_connect($object); # Check that server is still up
+ }
+ $result=0; # Query failed
+ }
+ $object->cleanup();
+ return $result; # Server couldn't handle the query
+}
+
+
+sub report
+{
+ my ($prompt,$limit,@queries)=@_;
+ print "$prompt: ";
+ if (!defined($limits{$limit}))
+ {
+ save_config_data($limit,safe_query(\@queries) ? "yes" : "no",$prompt);
+ }
+ print "$limits{$limit}\n";
+ return $limits{$limit} ne "no";
+}
+
+sub report_fail
+{
+ my ($prompt,$limit,@queries)=@_;
+ print "$prompt: ";
+ if (!defined($limits{$limit}))
+ {
+ save_config_data($limit,safe_query(\@queries) ? "no" : "yes",$prompt);
+ }
+ print "$limits{$limit}\n";
+ return $limits{$limit} ne "no";
+}
+
+
+# Return true if one of the queries is ok
+
+sub report_one
+{
+ my ($prompt,$limit,$queries)=@_;
+ my ($query,$res,$result);
+ print "$prompt: ";
+ if (!defined($limits{$limit}))
+ {
+ $result="no";
+ foreach $query (@$queries)
+ {
+ if (safe_query($query->[0]))
+ {
+ $result= $query->[1];
+ last;
+ }
+ }
+ save_config_data($limit,$result,$prompt);
+ }
+ print "$limits{$limit}\n";
+ return $limits{$limit} ne "no";
+}
+
+
+# Execute query and save result as limit value.
+
+sub report_result
+{
+ my ($prompt,$limit,$query)=@_;
+ my($error);
+ print "$prompt: ";
+ if (!defined($limits{$limit}))
+ {
+ $error=safe_query_result($query,"1",2);
+ save_config_data($limit,$error ? "not supported" : $last_result,$prompt);
+ }
+ print "$limits{$limit}\n";
+ return $limits{$limit} ne "no";
+}
+
+sub report_trans
+{
+ my ($prompt,$limit,$queries,$check,$clear)=@_;
+ print "$prompt: ";
+ if (!defined($limits{$limit}))
+ {
+ eval {undef($dbh->{AutoCommit})};
+ if (!$@)
+ {
+ if (safe_query(\@$queries))
+ {
+ $rc = $dbh->rollback;
+ if ($rc) {
+ $dbh->{AutoCommit} = 1;
+ if (safe_query_result($check,"","")) {
+ save_config_data($limit,"yes",$prompt);
+ }
+ safe_query($clear);
+ } else {
+ $dbh->{AutoCommit} = 1;
+ safe_query($clear);
+ save_config_data($limit,"error",$prompt);
+ }
+ } else {
+ save_config_data($limit,"error",$prompt);
+ }
+ $dbh->{AutoCommit} = 1;
+ }
+ else
+ {
+ save_config_data($limit,"no",$prompt);
+ }
+ safe_query($clear);
+ }
+ print "$limits{$limit}\n";
+ return $limits{$limit} ne "no";
+}
+
+
+sub check_and_report
+{
+ my ($prompt,$limit,$pre,$query,$post,$answer,$string_type,$skip_prompt,
+ $function)=@_;
+ my ($tmp);
+ $function=0 if (!defined($function));
+
+ print "$prompt: " if (!defined($skip_prompt));
+ if (!defined($limits{$limit}))
+ {
+ $tmp=1-safe_query(\@$pre);
+ $tmp=safe_query_result($query,$answer,$string_type) if (!$tmp);
+ safe_query(\@$post);
+ if ($function == 3) # Report error as 'no'.
+ {
+ $function=0;
+ $tmp= -$tmp;
+ }
+ if ($function == 0 ||
+ $tmp != 0 && $function == 1 ||
+ $tmp == 0 && $function== 2)
+ {
+ save_config_data($limit, $tmp == 0 ? "yes" : $tmp == 1 ? "no" : "error",
+ $prompt);
+ print "$limits{$limit}\n";
+ return $function == 0 ? $limits{$limit} eq "yes" : 0;
+ }
+ return 1; # more things to check
+ }
+ print "$limits{$limit}\n";
+ return 0 if ($function);
+ return $limits{$limit} eq "yes";
+}
+
+
+sub try_and_report
+{
+ my ($prompt,$limit,@tests)=@_;
+ my ($tmp,$test,$type);
+
+ print "$prompt: ";
+ if (!defined($limits{$limit}))
+ {
+ $type="no"; # Not supported
+ foreach $test (@tests)
+ {
+ my $tmp_type= shift(@$test);
+ if (safe_query(\@$test))
+ {
+ $type=$tmp_type;
+ goto outer;
+ }
+ }
+ outer:
+ save_config_data($limit, $type, $prompt);
+ }
+ print "$limits{$limit}\n";
+ return $limits{$limit} ne "no";
+}
+
+#
+# Just execute the query and check values; Returns 1 if ok
+#
+
+sub execute_and_check
+{
+ my ($pre,$query,$post,$answer,$string_type)=@_;
+ my ($tmp);
+
+ $tmp=safe_query(\@$pre);
+ $tmp=safe_query_result($query,$answer,$string_type) == 0 if ($tmp);
+ safe_query(\@$post);
+ return $tmp;
+}
+
+
+# returns 0 if ok, 1 if error, -1 if wrong answer
+# Sets $last_result to value of query
+
+sub safe_query_result
+{
+ my ($query,$answer,$result_type)=@_;
+ my ($sth,$row,$result,$retry);
+ undef($last_result);
+
+ printf "\nquery3: %-80.80s\n",$query if ($opt_log_all_queries);
+ print LOG "$query;\n" if ($opt_log);
+ for ($retry=0; $retry < $retry_limit ; $retry++)
+ {
+ if (!($sth=$dbh->prepare($query)))
+ {
+ print_query($query);
+ if ($server->abort_if_fatal_error())
+ {
+ check_connect(); # Check that server is still up
+ next; # Retry again
+ }
+ check_connect(); # Check that server is still up
+ return 1;
+ }
+ if (!$sth->execute)
+ {
+ print_query($query);
+ if ($server->abort_if_fatal_error())
+ {
+ check_connect(); # Check that server is still up
+ next; # Retry again
+ }
+ check_connect(); # Check that server is still up
+ return 1;
+ }
+ else
+ {
+ last;
+ }
+ }
+ if (!($row=$sth->fetchrow_arrayref))
+ {
+ print "\nquery: $query didn't return any result\n" if ($opt_debug);
+ $sth->finish;
+ return ($result_type == 8) ? 0 : 1;
+ }
+ if(result_type == 8) {
+ $sth->finish;
+ return 1;
+ }
+ $result=0; # Ok
+ $last_result= $row->[0]; # Save for report_result;
+ if ($result_type == 0) # Compare numbers
+ {
+ $row->[0] =~ s/,/,/; # Fix if ',' is used instead of '.'
+ if ($row->[0] != $answer && (abs($row->[0]- $answer)/
+ (abs($row->[0]) + abs($answer))) > 0.01)
+ {
+ $result=-1;
+ }
+ }
+ elsif ($result_type == 1) # Compare where end space may differ
+ {
+ $row->[0] =~ s/\s+$//;
+ $result=-1 if ($row->[0] ne $answer);
+ }
+ elsif ($result_type == 3) # This should be a exact match
+ {
+ $result= -1 if ($row->[0] ne $answer);
+ }
+ elsif ($result_type == 4) # If results should be NULL
+ {
+ $result= -1 if (defined($row->[0]));
+ }
+ 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);
+ }
+ elsif ($result_type == 6) # Exact match but ignore errors
+ {
+ $result= 1 if ($row->[0] ne $answer);
+ }
+ elsif ($result_type == 7) # Compare against array of numbers
+ {
+ if ($row->[0] != $answer->[0])
+ {
+ $result= -1;
+ }
+ else
+ {
+ my ($value);
+ shift @$answer;
+ while (($row=$sth->fetchrow_arrayref))
+ {
+ $value=shift(@$answer);
+ if (!defined($value))
+ {
+ print "\nquery: $query returned to many results\n"
+ if ($opt_debug);
+ $result= 1;
+ last;
+ }
+ if ($row->[0] != $value)
+ {
+ $result= -1;
+ last;
+ }
+ }
+ if ($#$answer != -1)
+ {
+ print "\nquery: $query returned too few results\n"
+ if ($opt_debug);
+ $result= 1;
+ }
+ }
+ }
+ $sth->finish;
+ print "\nquery: '$query' returned '$row->[0]' instead of '$answer'\n"
+ if ($opt_debug && $result && $result_type != 7);
+ return $result;
+}
+
+#
+# Find limit using binary search. This is a weighed binary search that
+# will prefere lower limits to get the server to crash as few times as possible
+#
+
+sub find_limit()
+{
+ my ($prompt,$limit,$query)=@_;
+ my ($first,$end,$i,$tmp);
+ print "$prompt: ";
+ if (defined($end=$limits{$limit}))
+ {
+ print "$end (cache)\n";
+ return $end;
+ }
+ if (defined($query->{'init'}) && !defined($end=$limits{'restart'}{'tohigh'}))
+ {
+ if (!safe_query($query->{'init'}))
+ {
+ $query->cleanup();
+ return "error";
+ }
+ }
+
+ if (!limit_query($query,1)) # This must work
+ {
+ print "\nMaybe fatal error: Can't check '$prompt' for limit=1\nerror: $last_error\n";
+ return "error";
+ }
+
+ $first=0;
+ $first=$limits{'restart'}{'low'} if ($limits{'restart'}{'low'});
+
+ if (defined($end=$limits{'restart'}{'tohigh'}))
+ {
+ $end--;
+ print "\nRestarting this with low limit: $first and high limit: $end\n";
+ delete $limits{'restart'};
+ $i=$first+int(($end-$first+4)/5); # Prefere lower on errors
+ }
+ else
+ {
+ $end= $query->max_limit();
+ $i=int(($end+$first)/2);
+ }
+
+ unless(limit_query($query,0+$end)) {
+ while ($first < $end)
+ {
+ print "." if ($opt_debug);
+ save_config_data("restart",$i,"") if ($opt_restart);
+ if (limit_query($query,$i))
+ {
+ $first=$i;
+ $i=$first+int(($end-$first+1)/2); # to be a bit faster to go up
+ }
+ else
+ {
+ $end=$i-1;
+ $i=$first+int(($end-$first+4)/5); # Prefere lower on errors
+ }
+ }
+ }
+ $end+=$query->{'offset'} if ($end && defined($query->{'offset'}));
+ if ($end >= $query->{'max_limit'} &&
+ substr($query->{'max_limit'},0,1) eq '+')
+ {
+ $end= $query->{'max_limit'};
+ }
+ print "$end\n";
+ save_config_data($limit,$end,$prompt);
+ delete $limits{'restart'};
+ return $end;
+}
+
+#
+# Check that the query works!
+#
+
+sub assert
+{
+ my($query)=@_;
+
+ if (!safe_query($query))
+ {
+ $query=join("; ",@$query) if (ref($query) eq "ARRAY");
+ print "\nFatal error:\nquery: '$query'\nerror: $DBI::errstr\n";
+ exit 1;
+ }
+}
+
+
+sub read_config_data
+{
+ my ($key,$limit,$prompt);
+ if (-e $opt_config_file)
+ {
+ open(CONFIG_FILE,"+<$opt_config_file") ||
+ die "Can't open configure file $opt_config_file\n";
+ print "Reading old values from cache: $opt_config_file\n";
+ }
+ else
+ {
+ open(CONFIG_FILE,"+>>$opt_config_file") ||
+ die "Can't create configure file $opt_config_file: $!\n";
+ }
+ select CONFIG_FILE;
+ $|=1;
+ select STDOUT;
+ while (<CONFIG_FILE>)
+ {
+ chomp;
+ if (/^(\S+)=([^\#]*[^\#\s])\s*(\# .*)*$/)
+ {
+ $key=$1; $limit=$2 ; $prompt=$3;
+ if (!$opt_quick || $limit =~ /\d/ || $key =~ /crash_me/)
+ {
+ if ($key !~ /restart/i)
+ {
+ $limits{$key}=$limit;
+ $prompts{$key}=length($prompt) ? substr($prompt,2) : "";
+ delete $limits{'restart'};
+ }
+ else
+ {
+ $limit_changed=1;
+ if ($limit > $limits{'restart'}{'tohigh'})
+ {
+ $limits{'restart'}{'low'} = $limits{'restart'}{'tohigh'};
+ }
+ $limits{'restart'}{'tohigh'} = $limit;
+ }
+ }
+ }
+ elsif (!/^\s*$/ && !/^\#/)
+ {
+ die "Wrong config row: $_\n";
+ }
+ }
+}
+
+
+sub save_config_data
+{
+ my ($key,$limit,$prompt)=@_;
+ $prompts{$key}=$prompt;
+ return if (defined($limits{$key}) && $limits{$key} eq $limit);
+ if (!defined($limit) || $limit eq "")
+ {
+ die "Undefined limit for $key\n";
+ }
+ print CONFIG_FILE "$key=$limit\t# $prompt\n";
+ $limits{$key}=$limit;
+ $limit_changed=1;
+ if (($opt_restart && $limits{'operating_system'} =~ /windows/i) ||
+ ($limits{'operating_system'} =~ /NT/))
+ {
+ # If perl crashes in windows, everything is lost (Wonder why? :)
+ close CONFIG_FILE;
+ open(CONFIG_FILE,"+>>$opt_config_file") ||
+ die "Can't reopen configure file $opt_config_file: $!\n";
+ }
+}
+
+
+sub save_all_config_data
+{
+ my ($key,$tmp);
+ close CONFIG_FILE;
+ return if (!$limit_changed);
+ open(CONFIG_FILE,">$opt_config_file") ||
+ die "Can't create configure file $opt_config_file: $!\n";
+ select CONFIG_FILE;
+ $|=1;
+ select STDOUT;
+ delete $limits{'restart'};
+
+ print CONFIG_FILE "#This file is automaticly generated by crash-me $version\n\n";
+ foreach $key (sort keys %limits)
+ {
+ $tmp="$key=$limits{$key}";
+ print CONFIG_FILE $tmp . ("\t" x (int((32-min(length($tmp),32)+7)/8)+1)) .
+ "# $prompts{$key}\n";
+ }
+ close CONFIG_FILE;
+}
+
+
+sub check_repeat
+{
+ my ($sth,$limit)=@_;
+ my ($row);
+
+ return 0 if (!($row=$sth->fetchrow_arrayref));
+ return (defined($row->[0]) && ('a' x $limit) eq $row->[0]) ? 1 : 0;
+}
+
+
+sub min
+{
+ my($min)=$_[0];
+ my($i);
+ for ($i=1 ; $i <= $#_; $i++)
+ {
+ $min=$_[$i] if ($min > $_[$i]);
+ }
+ return $min;
+}
+
+sub sql_concat
+{
+ my ($a,$b)= @_;
+ return "$a || $b" if ($limits{'func_sql_concat_as_||'} eq 'yes');
+ return "concat($a,$b)" if ($limits{'func_odbc_concat'} eq 'yes');
+ return "$a + $b" if ($limits{'func_extra_concat_as_+'} eq 'yes');
+ return undef;
+}
+
+#
+# Returns a list of statements to create a table in a portable manner
+# but still utilizing features in the databases.
+#
+
+sub create_table
+{
+ my($table_name,$fields,$index) = @_;
+ my($query,$nr,$parts,@queries,@index);
+
+ $query="create table $table_name (";
+ $nr=0;
+ foreach $field (@$fields)
+ {
+ $query.= $field . ',';
+ }
+ foreach $index (@$index)
+ {
+ $index =~ /\(([^\(]*)\)$/i;
+ $parts=$1;
+ if ($index =~ /^primary key/)
+ {
+ if ($limits{'primary_key_in_create'} eq 'yes')
+ {
+ $query.= $index . ',';
+ }
+ else
+ {
+ push(@queries,
+ "create unique index ${table_name}_prim on $table_name ($parts)");
+ }
+ }
+ elsif ($index =~ /^unique/)
+ {
+ if ($limits{'unique_in_create'} eq 'yes')
+ {
+ $query.= "unique ($parts),";
+ }
+ else
+ {
+ $nr++;
+ push(@queries,
+ "create unique index ${table_name}_$nr on $table_name ($parts)");
+
+ }
+ }
+ else
+ {
+ if ($limits{'index_in_create'} eq 'yes')
+ {
+ $query.= "index ($parts),";
+ }
+ else
+ {
+ $nr++;
+ push(@queries,
+ "create index ${table_name}_$nr on $table_name ($1)");
+ }
+ }
+ }
+ chop($query);
+ $query.= ')';
+ unshift(@queries,$query);
+ return @queries;
+}
+
+
+#
+# This is used by some query packages to change:
+# %d -> limit
+# %s -> 'a' x limit
+# %v -> "1,1,1,1,1" where there are 'limit' number of ones
+# %f -> q1,q2,q3....
+# %F -> q1 integer,q2 integer,q3 integer....
+
+sub fix_query
+{
+ my ($query,$limit)=@_;
+ my ($repeat,$i);
+
+ return $query if !(defined($query));
+ $query =~ s/%d/$limit/g;
+ if ($query =~ /%s/)
+ {
+ $repeat= 'a' x $limit;
+ $query =~ s/%s/$repeat/g;
+ }
+ if ($query =~ /%v/)
+ {
+ $repeat= '1,' x $limit;
+ chop($repeat);
+ $query =~ s/%v/$repeat/g;
+ }
+ if ($query =~ /%f/)
+ {
+ $repeat="";
+ for ($i=1 ; $i <= $limit ; $i++)
+ {
+ $repeat.="q$i,";
+ }
+ chop($repeat);
+ $query =~ s/%f/$repeat/g;
+ }
+ if ($query =~ /%F/)
+ {
+ $repeat="";
+ for ($i=1 ; $i <= $limit ; $i++)
+ {
+ $repeat.="q$i integer,";
+ }
+ chop($repeat);
+ $query =~ s/%F/$repeat/g;
+ }
+ return $query;
+}
+
+
+#
+# Different query packages
+#
+
+package query_repeat;
+
+sub new
+{
+ my ($type,$init,$query,$add1,$add_mid,$add,$add_end,$end_query,$cleanup,
+ $max_limit, $check, $offset)=@_;
+ my $self={};
+ if (defined($init) && $#$init != -1)
+ {
+ $self->{'init'}=$init;
+ }
+ $self->{'query'}=$query;
+ $self->{'add1'}=$add1;
+ $self->{'add_mid'}=$add_mid;
+ $self->{'add'}=$add;
+ $self->{'add_end'}=$add_end;
+ $self->{'end_query'}=$end_query;
+ $self->{'cleanup'}=$cleanup;
+ $self->{'max_limit'}=(defined($max_limit) ? $max_limit : $main::query_size);
+ $self->{'check'}=$check;
+ $self->{'offset'}=$offset;
+ $self->{'printf'}= ($add =~ /%d/);
+ bless $self;
+}
+
+sub query
+{
+ my ($self,$limit)=@_;
+ if (!$self->{'printf'})
+ {
+ return $self->{'query'} . ($self->{'add'} x $limit) .
+ ($self->{'add_end'} x $limit) . $self->{'end_query'};
+ }
+ my ($tmp,$tmp2,$tmp3,$i);
+ $tmp=$self->{'query'};
+ if ($self->{'add1'})
+ {
+ for ($i=0; $i < $limit ; $i++)
+ {
+ $tmp3 = $self->{'add1'};
+ $tmp3 =~ s/%d/$i/g;
+ $tmp .= $tmp3;
+ }
+ }
+ $tmp .= " ".$self->{'add_mid'};
+ if ($self->{'add'})
+ {
+ for ($i=0; $i < $limit ; $i++)
+ {
+ $tmp2 = $self->{'add'};
+ $tmp2 =~ s/%d/$i/g;
+ $tmp .= $tmp2;
+ }
+ }
+ return ($tmp .
+ ($self->{'add_end'} x $limit) . $self->{'end_query'});
+}
+
+sub max_limit
+{
+ my ($self)=@_;
+ my $tmp;
+ $tmp=int(($main::limits{"query_size"}-length($self->{'query'})
+ -length($self->{'add_mid'})-length($self->{'end_query'}))/
+ (length($self->{'add1'})+
+ length($self->{'add'})+length($self->{'add_end'})));
+ return main::min($self->{'max_limit'},$tmp);
+}
+
+
+sub cleanup
+{
+ my ($self)=@_;
+ my($tmp,$statement);
+ $tmp=$self->{'cleanup'};
+ foreach $statement (@$tmp)
+ {
+ main::safe_query($statement) if (defined($statement) && length($statement));
+ }
+}
+
+sub check
+{
+ my ($self,$sth)=@_;
+ my $check=$self->{'check'};
+ return &$check($sth,$self->{'limit'}) if (defined($check));
+ return 1;
+}
+
+sub check_query
+{
+ return undef;
+}
+
+
+package query_num;
+
+sub new
+{
+ my ($type,$query,$end_query,$cleanup,$max_limit,$check)=@_;
+ my $self={};
+ $self->{'query'}=$query;
+ $self->{'end_query'}=$end_query;
+ $self->{'cleanup'}=$cleanup;
+ $self->{'max_limit'}=$max_limit;
+ $self->{'check'}=$check;
+ bless $self;
+}
+
+
+sub query
+{
+ my ($self,$i)=@_;
+ $self->{'limit'}=$i;
+ return "$self->{'query'}$i$self->{'end_query'}";
+}
+
+sub max_limit
+{
+ my ($self)=@_;
+ return $self->{'max_limit'};
+}
+
+sub cleanup
+{
+ my ($self)=@_;
+ my($statement);
+ foreach $statement ($self->{'$cleanup'})
+ {
+ main::safe_query($statement) if (defined($statement) && length($statement));
+ }
+}
+
+
+sub check
+{
+ my ($self,$sth)=@_;
+ my $check=$self->{'check'};
+ return &$check($sth,$self->{'limit'}) if (defined($check));
+ return 1;
+}
+
+sub check_query
+{
+ return undef;
+}
+
+#
+# This package is used when testing CREATE TABLE!
+#
+
+package query_table;
+
+sub new
+{
+ my ($type,$query, $add, $end_query, $extra_init, $safe_query, $check,
+ $cleanup, $max_limit, $offset)=@_;
+ my $self={};
+ $self->{'query'}=$query;
+ $self->{'add'}=$add;
+ $self->{'end_query'}=$end_query;
+ $self->{'extra_init'}=$extra_init;
+ $self->{'safe_query'}=$safe_query;
+ $self->{'check'}=$check;
+ $self->{'cleanup'}=$cleanup;
+ $self->{'max_limit'}=$max_limit;
+ $self->{'offset'}=$offset;
+ bless $self;
+}
+
+
+sub query
+{
+ my ($self,$limit)=@_;
+ $self->{'limit'}=$limit;
+ $self->cleanup(); # Drop table before create
+
+ my ($tmp,$tmp2,$i,$query,@res);
+ $tmp =$self->{'query'};
+ $tmp =~ s/%d/$limit/g;
+ for ($i=1; $i <= $limit ; $i++)
+ {
+ $tmp2 = $self->{'add'};
+ $tmp2 =~ s/%d/$i/g;
+ $tmp .= $tmp2;
+ }
+ push(@res,$tmp . $self->{'end_query'});
+ $tmp=$self->{'extra_init'};
+ foreach $query (@$tmp)
+ {
+ push(@res,main::fix_query($query,$limit));
+ }
+ return \@res;
+}
+
+
+sub max_limit
+{
+ my ($self)=@_;
+ return $self->{'max_limit'};
+}
+
+
+sub check_query
+{
+ my ($self)=@_;
+ return main::fix_query($self->{'safe_query'},$self->{'limit'});
+}
+
+sub check
+{
+ my ($self,$sth)=@_;
+ my $check=$self->{'check'};
+ return 0 if (!($row=$sth->fetchrow_arrayref));
+ if (defined($check))
+ {
+ return (defined($row->[0]) &&
+ $row->[0] eq main::fix_query($check,$self->{'limit'})) ? 1 : 0;
+ }
+ return 1;
+}
+
+
+# Remove table before and after create table query
+
+sub cleanup()
+{
+ my ($self)=@_;
+ main::safe_query(main::fix_query($self->{'cleanup'},$self->{'limit'}));
+}
+
+#
+# Package to do many queries with %d, and %s substitution
+#
+
+package query_many;
+
+sub new
+{
+ my ($type,$query,$safe_query,$check_result,$cleanup,$max_limit,$offset,
+ $safe_cleanup)=@_;
+ my $self={};
+ $self->{'query'}=$query;
+ $self->{'safe_query'}=$safe_query;
+ $self->{'check'}=$check_result;
+ $self->{'cleanup'}=$cleanup;
+ $self->{'max_limit'}=$max_limit;
+ $self->{'offset'}=$offset;
+ $self->{'safe_cleanup'}=$safe_cleanup;
+ bless $self;
+}
+
+
+sub query
+{
+ my ($self,$limit)=@_;
+ my ($queries,$query,@res);
+ $self->{'limit'}=$limit;
+ $self->cleanup() if (defined($self->{'safe_cleanup'}));
+ $queries=$self->{'query'};
+ foreach $query (@$queries)
+ {
+ push(@res,main::fix_query($query,$limit));
+ }
+ return \@res;
+}
+
+sub check_query
+{
+ my ($self)=@_;
+ return main::fix_query($self->{'safe_query'},$self->{'limit'});
+}
+
+sub cleanup
+{
+ my ($self)=@_;
+ my($tmp,$statement);
+ return if (!defined($self->{'cleanup'}));
+ $tmp=$self->{'cleanup'};
+ foreach $statement (@$tmp)
+ {
+ if (defined($statement) && length($statement))
+ {
+ main::safe_query(main::fix_query($statement,$self->{'limit'}));
+ }
+ }
+}
+
+
+sub check
+{
+ my ($self,$sth)=@_;
+ my ($check,$row);
+ return 0 if (!($row=$sth->fetchrow_arrayref));
+ $check=$self->{'check'};
+ if (defined($check))
+ {
+ return (defined($row->[0]) &&
+ $row->[0] eq main::fix_query($check,$self->{'limit'})) ? 1 : 0;
+ }
+ return 1;
+}
+
+sub max_limit
+{
+ my ($self)=@_;
+ return $self->{'max_limit'};
+}
+
+#
+# Used to find max supported row length
+#
+
+package query_row_length;
+
+sub new
+{
+ my ($type,$create,$null,$drop,$max_limit)=@_;
+ my $self={};
+ $self->{'table_name'}=$create;
+ $self->{'null'}=$null;
+ $self->{'cleanup'}=$drop;
+ $self->{'max_limit'}=$max_limit;
+ bless $self;
+}
+
+
+sub query
+{
+ my ($self,$limit)=@_;
+ my ($res,$values,$size,$length,$i);
+ $self->{'limit'}=$limit;
+
+ $res="";
+ $size=main::min($main::limits{'max_char_size'},255);
+ $size = 255 if (!$size); # Safety
+ for ($length=$i=0; $length + $size <= $limit ; $length+=$size, $i++)
+ {
+ $res.= "q$i char($size) $self->{'null'},";
+ $values.="'" . ('a' x $size) . "',";
+ }
+ if ($length < $limit)
+ {
+ $size=$limit-$length;
+ $res.= "q$i char($size) $self->{'null'},";
+ $values.="'" . ('a' x $size) . "',";
+ }
+ chop($res);
+ chop($values);
+ return ["create table " . $self->{'table_name'} . " ($res)",
+ "insert into " . $self->{'table_name'} . " values ($values)"];
+}
+
+sub max_limit
+{
+ my ($self)=@_;
+ return $self->{'max_limit'};
+}
+
+sub cleanup
+{
+ my ($self)=@_;
+ main::safe_query($self->{'cleanup'});
+}
+
+
+sub check
+{
+ return 1;
+}
+
+sub check_query
+{
+ return undef;
+}
+
+#
+# Used to find max supported index length
+#
+
+package query_index_length;
+
+sub new
+{
+ my ($type,$create,$drop,$max_limit)=@_;
+ my $self={};
+ $self->{'create'}=$create;
+ $self->{'cleanup'}=$drop;
+ $self->{'max_limit'}=$max_limit;
+ bless $self;
+}
+
+
+sub query
+{
+ my ($self,$limit)=@_;
+ my ($res,$size,$length,$i,$parts,$values);
+ $self->{'limit'}=$limit;
+
+ $res=$parts=$values="";
+ $size=main::min($main::limits{'max_index_part_length'},$main::limits{'max_char_size'});
+ $size=1 if ($size == 0); # Avoid infinite loop errors
+ for ($length=$i=0; $length + $size <= $limit ; $length+=$size, $i++)
+ {
+ $res.= "q$i char($size) not null,";
+ $parts.= "q$i,";
+ $values.= "'" . ('a' x $size) . "',";
+ }
+ if ($length < $limit)
+ {
+ $size=$limit-$length;
+ $res.= "q$i char($size) not null,";
+ $parts.="q$i,";
+ $values.= "'" . ('a' x $size) . "',";
+ }
+ chop($parts);
+ chop($res);
+ chop($values);
+ if ($main::limits{'unique_in_create'} eq 'yes')
+ {
+ return [$self->{'create'} . "($res,unique ($parts))",
+ "insert into crash_q values($values)"];
+ }
+ return [$self->{'create'} . "($res)",
+ "create index crash_q_index on crash_q ($parts)",
+ "insert into crash_q values($values)"];
+}
+
+sub max_limit
+{
+ my ($self)=@_;
+ return $self->{'max_limit'};
+}
+
+sub cleanup
+{
+ my ($self)=@_;
+ main::safe_query($self->{'cleanup'});
+}
+
+
+sub check
+{
+ return 1;
+}
+
+sub check_query
+{
+ return undef;
+}
+
+
+### TODO:
+# OID test instead of / in addition to _rowid
diff --git a/sql-bench/example.bat b/sql-bench/example.bat
new file mode 100644
index 00000000000..5bc1b458008
--- /dev/null
+++ b/sql-bench/example.bat
@@ -0,0 +1,7 @@
+REM
+REM Example use to run test on PC
+REM One need only to run 'comapre-results' to view results from old runs
+
+perl run-all-tests --server mysql --cmp "access,mysql"
+perl run-all-tests --server mysql --cmp "access,mysql" --log --use-old-results
+perl compare-results --cmp "access,mysql" -rel
diff --git a/sql-bench/limits/Adabas.cfg b/sql-bench/limits/Adabas.cfg
new file mode 100644
index 00000000000..939d1731006
--- /dev/null
+++ b/sql-bench/limits/Adabas.cfg
@@ -0,0 +1,429 @@
+#This file is automaticly generated by crash-me 1.20b
+
+NEG=yes # update of column= -column
+alter_add_col=yes # Alter table add column
+alter_add_multi_col=without add # Alter table add many columns
+alter_alter_col=no # Alter table alter column
+alter_change_col=no # Alter table change column
+alter_drop_col=yes # Alter table drop column
+alter_modify_col=yes # Alter table modify column
+alter_rename_table=no # Alter table rename table
+atomic_updates=no # atomic updates
+binary_items=yes # binary items (0x41)
+case_insensitive_strings=no # case insensitive compare
+char_is_space_filled=no # char are space filled
+column_alias=yes # Column alias
+columns_in_group_by=16 # number of columns in group by
+columns_in_order_by=16 # number of columns in order by
+comment_#=no # # as comment
+comment_--=no # -- as comment
+comment_/**/=no # /* */ as comment
+compute=no # Compute
+connections=1 # Simultaneous connections
+crash_me_safe=no # crash me safe
+crash_me_version=1.20b # crash me version
+create_default=yes # default value for column
+create_index=yes # create index
+cross_join=no # cross join (same as from a,b)
+date_as_string=yes # String functions on date columns
+date_with_YY=no # Supports YY-MM-DD dates
+date_zero=no # Supports 0000-00-00 dates
+double_quotes=yes # Double '' as ' in strings
+drop_index=yes # drop index
+end_colon=no # allows end ';'
+except=yes # except
+except_all=yes # except all
+float_int_expr=yes # mixing of integer and float in expression
+foreign_key=yes # foreign keys
+foreign_key_syntax=yes # foreign key syntax
+full_outer_join=no # 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_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=yes # Function CEIL
+func_extra_charindex=no # Function CHARINDEX
+func_extra_chr=error # 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=yes # 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=yes # 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=yes # Function INITCAP
+func_extra_instr=no # Function LOCATE as INSTR
+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=yes # 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=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_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=yes # Function ROUND(1 arg)
+func_extra_rpad=no # Function RPAD
+func_extra_sec_to_time=no # Function SEC_TO_TIME
+func_extra_sinh=yes # 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_tanh=error # Function TANH
+func_extra_time_to_sec=no # Function TIME_TO_SEC
+func_extra_to_days=no # Function TO_DAYS
+func_extra_translate=yes # 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=yes # 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_odbc_abs=yes # Function ABS
+func_odbc_acos=yes # Function ACOS
+func_odbc_ascii=error # Function ASCII
+func_odbc_asin=yes # Function ASIN
+func_odbc_atan=yes # Function ATAN
+func_odbc_atan2=yes # Function ATAN2
+func_odbc_ceiling=yes # Function CEILING
+func_odbc_char=no # Function CHAR
+func_odbc_concat=no # Function CONCAT(2 arg)
+func_odbc_cos=yes # Function COS
+func_odbc_cot=yes # Function COT
+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=error # Function DAYOFWEEK
+func_odbc_dayofyear=yes # Function DAYOFYEAR
+func_odbc_degrees=yes # Function DEGREES
+func_odbc_difference=no # Function DIFFERENCE()
+func_odbc_exp=yes # Function EXP
+func_odbc_extract=no # Function EXTRACT
+func_odbc_floor=yes # Function FLOOR
+func_odbc_fn_left=no # Function ODBC syntax LEFT & RIGHT
+func_odbc_hour=yes # Function HOUR
+func_odbc_hour_time=no # Function ANSI HOUR
+func_odbc_ifnull=yes # Function IFNULL
+func_odbc_insert=no # Function INSERT
+func_odbc_lcase=yes # Function LCASE
+func_odbc_left=yes # Function LEFT
+func_odbc_length=error # Function REAL LENGTH
+func_odbc_length_without_space=yes # Function ODBC LENGTH
+func_odbc_locate_2=no # Function LOCATE(2 arg)
+func_odbc_locate_3=no # Function LOCATE(3 arg)
+func_odbc_log=yes # Function LOG
+func_odbc_log10=yes # Function LOG10
+func_odbc_ltrim=yes # Function LTRIM
+func_odbc_minute=yes # Function MINUTE
+func_odbc_mod=no # Function MOD
+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_radians=yes # Function RADIANS
+func_odbc_rand=no # Function RAND
+func_odbc_repeat=no # Function REPEAT
+func_odbc_replace=yes # Function REPLACE
+func_odbc_right=yes # Function RIGHT
+func_odbc_round=yes # Function ROUND(2 arg)
+func_odbc_rtrim=yes # Function RTRIM
+func_odbc_second=yes # Function SECOND
+func_odbc_sign=yes # Function SIGN
+func_odbc_sin=yes # Function SIN
+func_odbc_soundex=yes # Function SOUNDEX
+func_odbc_space=no # Function SPACE
+func_odbc_sqrt=yes # Function SQRT
+func_odbc_substring=no # 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=yes # Function UCASE
+func_odbc_user=yes # Function USER
+func_odbc_user()=yes # Function USER()
+func_odbc_week=no # Function WEEK
+func_odbc_year=yes # Function YEAR
+func_sql_+=yes # Function +, -, * and /
+func_sql_bit_length=no # Function BIT_LENGTH
+func_sql_case=no # Function CASE
+func_sql_cast=no # Function CAST
+func_sql_char_length=no # Function CHAR_LENGTH
+func_sql_character_length=no # Function CHARACTER_LENGTH
+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=yes # Function LOWER
+func_sql_octet_length=no # Function OCTET_LENGTH
+func_sql_position=no # Function POSITION
+func_sql_session_user=no # Function SESSION_USER
+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=yes # Function UPPER
+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 # null values in group by
+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_std=no # Group function STD
+group_func_extra_stddev=yes # Group function STDDEV
+group_func_extra_variance=yes # Group function VARIANCE
+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_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_sum=yes # Group function SUM
+group_functions=yes # Group functions
+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
+index_in_create=no # index in create table
+index_namespace=no # different namespace for index
+index_parts=no # index on column part (extension)
+insert_empty_string=yes # insert empty string
+insert_select=yes # insert INTO ... SELECT ...
+insert_with_set=yes # INSERT with set syntax
+intersect=yes # intersect
+intersect_all=yes # intersect all
+join_tables=16 # tables in join
+left_outer_join=no # left outer join
+left_outer_join_using=no # left outer join using
+like_with_column=yes # column LIKE column
+like_with_number=no # LIKE on numbers
+lock_tables=yes # lock table
+logical_value=not supported # Value of logical operation (1=1)
+max_big_expressions=1 # big expressions
+max_char_size=4000 # max char() size
+max_column_name=+512 # column name length
+max_columns=254 # Columns in table
+max_conditions=252 # OR and AND in WHERE
+max_expressions=1723 # simple expressions
+max_index=+64 # max index
+max_index_length=254 # index length
+max_index_name=+512 # index name length
+max_index_part_length=254 # max index part length
+max_index_parts=15 # index parts
+max_index_varchar_part_length=254 # index varchar part length
+max_row_length=3991 # max table row length (without blobs)
+max_row_length_with_null=3991 # table row length with nulls (without blobs)
+max_select_alias_name=+512 # select alias name length
+max_stack_expression=1022 # stacked expressions
+max_table_alias_name=+512 # table alias name length
+max_table_name=+512 # table name length
+max_unique_index=+64 # unique indexes
+max_varchar_size=4000 # max varchar() size
+minus=no # minus
+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
+multi_value_insert=no # Value lists in INSERT
+natural_join=no # natural join
+natural_left_outer_join=no # natural left outer join
+no_primary_key=yes # Tables without primary key
+null_concat_expr=yes # Is 'a' || NULL = NULL
+null_in_index=yes # null in index
+null_in_unique=yes # null in unique
+null_num_expr=yes # Is 1+NULL = NULL
+odbc_left_outer_join=yes # left outer join odbc style
+operating_system=Linux 2.0.35 i686 # crash-me tested on
+order_by=yes # Order by
+order_by_alias=yes # Order by alias
+order_by_position=yes # Order by position
+primary_key_in_create=yes # primary key in create table
+query_size=8202 # query size
+quote_with_"=no # Allows ' and " as string markers
+recursive_subqueries=223 # recursive subqueries
+remember_end_space=no # Remembers end space in char()
+remember_end_space_varchar=no # Remembers end space in varchar()
+right_outer_join=no # right outer join
+round_on_store=yes # Correct rounding when storing float values
+select_constants=yes # Select constants
+select_string_size=4023 # constant string size in SELECT
+select_table_update=no # Update with sub select
+select_without_from=no # SELECT without FROM
+server_version=Adabas 10.01.00 # server version
+simple_joins=yes # ANSI SQL simple joins
+subqueries=yes # subqueries
+table_alias=no # Table alias
+table_name_case=no # case independent table names
+table_wildcard=yes # Select table_name.*
+transactions=yes # transactions
+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_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_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_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_line=no # Type line
+type_extra_long=yes # 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_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_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_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)=yes # 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)=no # Type char varying(1 arg)
+type_sql_character(1_arg)=yes # Type character(1 arg)
+type_sql_character_varying(1_arg)=no # 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=no # Type double
+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_int=yes # Type int
+type_sql_integer=yes # Type integer
+type_sql_interval_year=no # Type interval year
+type_sql_numeric(2_arg)=no # Type numeric(2 arg)
+type_sql_real=yes # Type real
+type_sql_time=yes # Type time
+type_sql_timestamp=yes # Type timestamp
+type_sql_varchar(1_arg)=yes # Type varchar(1 arg)
+union=yes # union
+union_all=yes # union all
+unique_in_create=yes # unique in create table
+unique_null_in_create=yes # unique null in create
+views=yes # views
+where_string_size=4023 # constant string size in where
diff --git a/sql-bench/limits/Adabas.comment b/sql-bench/limits/Adabas.comment
new file mode 100644
index 00000000000..d36d05047cc
--- /dev/null
+++ b/sql-bench/limits/Adabas.comment
@@ -0,0 +1,36 @@
+
+I did not spend much time for tuning crash-me or the limits file. In short,
+here's what I did:
+
+ - Put engine into ANSI SQL mode by using the following odbc.ini:
+
+ [ODBC Data Sources]
+ test
+
+ [test]
+ ServerDB=test
+ ServerNode=
+ SQLMode=3
+
+ - Grabbed the db_Oracle package and copied it to db_Adabas
+ - Implemented a 'version' method.
+ - Ran crash-me with the --restart option; it failed when guessing the
+ query_size.
+ - Reran crash-me 3 or 4 times until it succeeded. At some point it
+ justified its name; I had to restart the Adabas server in the
+ table name length test ...
+ - Finally crash-me succeeded.
+
+That's it, folks. The benchmarks have been running on my P90 machine,
+32 MB RAM, with Red Hat Linux 5.0 (Kernel 2.0.33, glibc-2.0.7-6).
+Mysql was version 3.21.30, Adabas was version 6.1.15.42 (the one from
+the promotion CD of 1997). I was using X11 and Emacs while benchmarking.
+
+An interesting note: The mysql server had 4 processes, the three usual
+ones and a process for serving me, each about 2 MB RAM, including a
+shared memory segment of about 900K. Adabas had 10 processes running from
+the start, each about 16-20 MB, including a shared segment of 1-5 MB. You
+guess which one I prefer ... :-)
+
+
+Jochen Wiedmann, joe@ispsoft.de
diff --git a/sql-bench/limits/Informix.cfg b/sql-bench/limits/Informix.cfg
new file mode 100644
index 00000000000..85e79b53f21
--- /dev/null
+++ b/sql-bench/limits/Informix.cfg
@@ -0,0 +1,420 @@
+#This file is automaticly generated by crash-me 1.19a
+
+NEG=yes # update of column= -column
+alter_add_col=yes # Alter table add column
+alter_change_col=no # Alter table change column
+alter_drop_col=yes # Alter table drop column
+alter_modify_col=yes # Alter table modify column
+alter_rename_table=no # Alter table rename table
+atomic_updates=no # atomic updates
+binary_items=yes # binary items (0x41)
+case_insensitive_strings=no # case insensitive compare
+char_is_space_filled=no # char are space filled
+column_alias=yes # Column alias
+comment_#=no # # as comment
+comment_--=yes # -- as comment
+comment_/**/=yes # /* */ as comment
+compute=no # Compute
+connections=269 # Simultaneous connections
+crash_me_safe=no # crash me safe
+crash_me_version=1.19a # crash me version
+create_default=no # default value for column
+create_index=yes # create index
+cross_join=no # cross join (same as from a,b)
+date_as_string=no # String functions on date columns
+date_with_YY=no # Supports YY-MM-DD dates
+date_zero=no # Supports 0000-00-00 dates
+double_quotes=no # Double '' as ' in strings
+drop_index=yes # drop index
+except=no # except
+except_all=no # except all
+float_int_expr=yes # mixing of integer and float in expression
+foreign_key=yes # foreign keys
+foreign_key_syntax=yes # foreign key syntax
+full_outer_join=no # 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_atn2=no # Function ATN2
+func_extra_auto_num2string=no # Function automatic num->string convert
+func_extra_auto_string2num=yes # 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=yes # Function INITCAP
+func_extra_instr=no # Function LOCATE as INSTR
+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=yes # Function LOGN
+func_extra_lpad=yes # Function LPAD
+func_extra_max_num=no # Function MAX on numbers
+func_extra_mdy=yes # 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_patindex=no # Function PATINDEX
+func_extra_period_add=no # Function PERIOD_ADD
+func_extra_period_diff=no # Function PERIOD_DIFF
+func_extra_pow=yes # Function POW
+func_extra_range=yes # 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=yes # Function ROOT
+func_extra_round1=yes # Function ROUND(1 arg)
+func_extra_rpad=yes # 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_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=yes # 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_odbc_abs=yes # Function ABS
+func_odbc_acos=yes # Function ACOS
+func_odbc_ascii=no # Function ASCII
+func_odbc_asin=yes # Function ASIN
+func_odbc_atan=yes # Function ATAN
+func_odbc_atan2=yes # 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=yes # 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=yes # Function EXP
+func_odbc_extract=no # Function EXTRACT
+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=error # Function REAL LENGTH
+func_odbc_length_without_space=yes # 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=yes # Function LOG10
+func_odbc_ltrim=no # Function LTRIM
+func_odbc_minute=no # 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_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=yes # Function REPLACE
+func_odbc_right=no # Function RIGHT
+func_odbc_round=yes # 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=yes # Function SIN
+func_odbc_soundex=no # Function SOUNDEX
+func_odbc_space=no # Function SPACE
+func_odbc_sqrt=yes # Function SQRT
+func_odbc_substring=no # Function ODBC SUBSTRING
+func_odbc_tan=yes # 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=yes # Function USER
+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_case=yes # Function CASE
+func_sql_cast=no # Function CAST
+func_sql_char_length=yes # Function CHAR_LENGTH
+func_sql_character_length=yes # Function CHARACTER_LENGTH
+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=yes # Function LOWER
+func_sql_octet_length=yes # Function OCTET_LENGTH
+func_sql_position=no # Function POSITION
+func_sql_session_user=no # Function SESSION_USER
+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=yes # Function UPPER
+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 # Test nulls in group by
+group_by_position=yes # 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_std=no # Group function STD
+group_func_extra_stddev=no # Group function STDDEV
+group_func_extra_variance=no # Group function VARIANCE
+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_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_sum=yes # Group function SUM
+group_functions=yes # Group functions
+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
+index_in_create=no # index in create table
+index_namespace=no # different namespace for index
+index_parts=no # index on column part (extension)
+insert_empty_string=yes # insert empty string
+insert_select=yes # insert INTO ... SELECT ...
+intersect=no # intersect
+intersect_all=no # intersect all
+join_tables=+64 # tables in join
+left_outer_join=no # left outer join
+left_outer_join_using=no # left outer join using
+like_with_column=yes # column LIKE column
+like_with_number=no # LIKE on numbers
+lock_tables=yes # lock table
+logical_value=not supported # Value of logical operation (1=1)
+max_big_expressions=1 # big expressions
+max_char_size=256 # max char() size
+max_column_name=18 # column name length
+max_columns=994 # Columns in table
+max_conditions=1204 # OR and AND in WHERE
+max_expressions=16372 # simple expressions
+max_index=+64 # max index
+max_index_length=255 # index length
+max_index_name=18 # index name length
+max_index_part_length=255 # max index part length
+max_index_parts=15 # index parts
+max_index_varchar_part_length=254 # index varchar part length
+max_row_length=32356 # max table row length (without blobs)
+max_row_length_with_null=32356 # table row length with nulls (without blobs)
+max_select_alias_name=18 # select alias name length
+max_stack_expression=47 # stacked expressions
+max_table_alias_name=18 # table alias name length
+max_table_name=18 # table name length
+max_unique_index=+64 # unique indexes
+max_varchar_size=255 # max varchar() size
+minus=no # minus
+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_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=yes # null in unique
+null_num_expr=no # Is 1+NULL = NULL
+odbc_left_outer_join=yes # left outer join odbc style
+operating_system=Windows NT Version 4.0 # crash-me tested on
+order_by=yes # Order by
+order_by_alias=yes # Order by alias
+order_by_position=yes # Order by position
+primary_key_in_create=yes # primary key in create table
+query_size=32766 # query size
+quote_with_"=yes # Allows ' and " as string markers
+recursive_subqueries=10 # recursive subqueries
+remember_end_space=no # Remembers end space in char()
+remember_end_space_varchar=no # Remembers end space in varchar()
+right_outer_join=no # right outer join
+select_constants=yes # Select constants
+select_string_size=256 # constant string size in SELECT
+select_table_update=yes # Update with sub select
+select_without_from=no # SELECT without FROM
+server_version=Informix 7.30C1 # server version
+simple_joins=yes # ANSI SQL simple joins
+subqueries=yes # subqueries
+table_alias=yes # Table alias
+table_wildcard=yes # Select table_name.*
+transactions=error # transactions
+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=yes # 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_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_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_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_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_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=yes # Type money
+type_sql_nchar(1_arg)=yes # 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)=yes # Type nvarchar(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=yes # Type serial
+type_extra_set(1_arg)=no # Type set(1 arg)
+type_extra_smalldatetime=no # Type smalldatetime
+type_extra_smallfloat=yes # Type smallfloat
+type_extra_smallmoney=no # Type smallmoney
+type_extra_text=yes # Type text
+type_extra_text(1_arg)=no # Type text(1 arg)
+type_extra_timespan=no # Type timespan
+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_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_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=no # Type double
+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_int=yes # Type int
+type_sql_integer=yes # Type integer
+type_sql_interval_year=no # Type interval year
+type_sql_numeric(2_arg)=yes # Type numeric(2 arg)
+type_sql_real=yes # Type real
+type_sql_time=no # Type time
+type_sql_timestamp=no # Type timestamp
+type_sql_varchar(1_arg)=yes # Type varchar(1 arg)
+union=yes # union
+union_all=yes # union all
+unique_in_create=yes # unique in create table
+unique_null_in_create=no # unique null in create
+views=yes # views
+where_string_size=32452 # constant string size in where
diff --git a/sql-bench/limits/Informix.comment b/sql-bench/limits/Informix.comment
new file mode 100644
index 00000000000..557db012dd8
--- /dev/null
+++ b/sql-bench/limits/Informix.comment
@@ -0,0 +1,26 @@
+*****************************************************************
+NOTE:
+I, Monty, pulled this comment out from the public mail I got from
+Honza when he published the first crash-me run on Informix
+*****************************************************************
+
+Also attached are diffs from server-cfg and crash-me -- some of
+them are actual bugs in the code, some add extensions for Informix,
+some of the comment-outs were necessary to finish the test. Some of
+the problematic pieces that are commented out sent Informix to
+veeeery long load 1 on the machine (max_conditions for example), so
+could be considered crashes, but I'd prefer that someone checks the
+code before giving out such a conclusion.
+
+Some of the code that is commented out failed with some other SQL
+error message which might mean a problem with the sequence of commands
+in crash-me. Interesting thing, some of the tests failed for the
+first time but in the next or third run went OK, so the results are
+results of more iterations (like column doesn't exist in the first
+try but the second pass goes OK).
+
+I'd like to hear your comments on the bug fixes and Informix specific
+code before we go into debugging the problems.
+
+Yours,
+ Honza Pazdziora
diff --git a/sql-bench/limits/access.cfg b/sql-bench/limits/access.cfg
new file mode 100644
index 00000000000..19e59e98168
--- /dev/null
+++ b/sql-bench/limits/access.cfg
@@ -0,0 +1,501 @@
+#This file is automaticly generated by crash-me 1.45
+
+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=no # Alter table add constraint
+alter_add_foreign_key=yes # Alter table add foreign key
+alter_add_multi_col=without add # Alter table add many columns
+alter_add_primary_key=with constraint # Alter table add primary key
+alter_add_unique=yes # Alter table add unique
+alter_alter_col=no # Alter table alter column default
+alter_change_col=no # Alter table change column
+alter_drop_col=yes # Alter table drop column
+alter_drop_constraint=no # Alter table drop constraint
+alter_drop_foreign_key=with drop constraint # Alter table drop foreign key
+alter_drop_primary_key=drop constraint # Alter table drop primary key
+alter_drop_unique=with constraint # Alter table drop unique
+alter_modify_col=with alter # Alter table modify column
+alter_rename_table=no # Alter table rename table
+atomic_updates=no # atomic updates
+automatic_rowid=no # Automatic rowid
+binary_numbers=no # binary numbers (0b1001)
+binary_strings=no # binary strings (b'0110')
+case_insensitive_strings=yes # case insensitive compare
+char_is_space_filled=no # char are space filled
+column_alias=yes # Column alias
+columns_in_group_by=37 # number of columns in group by
+columns_in_order_by=37 # number of columns in order by
+comment_#=no # # as comment
+comment_--=no # -- as comment
+comment_/**/=no # /* */ as comment
+comment_//=no # // as comment
+compute=no # Compute
+connections=64 # 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.45 # crash me version
+create_default=no # 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=error # String functions on date columns
+date_last=no # Supports 9999-12-31 dates
+date_one=no # Supports 0001-01-01 dates
+date_with_YY=yes # Supports YY-MM-DD 2000 compilant 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=with 'ON' # drop index
+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=no # full outer join
+func_extra_!=no # Function NOT as '!' in SELECT
+func_extra_%=no # Function MOD as %
+func_extra_&=error # Function & (bitwise and)
+func_extra_&&=no # Function AND as '&&'
+func_extra_<>=yes # Function <> in SELECT
+func_extra_==yes # Function =
+func_extra_add_months=no # Function ADD_MONTHS
+func_extra_and_or=yes # 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=yes # Function automatic string->num convert
+func_extra_between=yes # 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=yes # Function CHR
+func_extra_concat_as_+=yes # 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=error # 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=yes # Function IN on numbers in SELECT
+func_extra_in_str=yes # Function IN on strings in SELECT
+func_extra_initcap=no # Function INITCAP
+func_extra_instr=yes # 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=yes # 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=yes # Function SUBSTRING as MID
+func_extra_months_between=no # Function MONTHS_BETWEEN
+func_extra_not=yes # Function NOT in SELECT
+func_extra_not_between=yes # Function NOT BETWEEN in SELECT
+func_extra_not_like=yes # 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=yes # 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=error # Function WEEKDAY
+func_extra_|=no # Function | (bitwise or)
+func_extra_||=no # Function OR as '||'
+func_odbc_abs=yes # Function ABS
+func_odbc_acos=no # Function ACOS
+func_odbc_ascii=yes # Function ASCII
+func_odbc_asin=no # Function ASIN
+func_odbc_atan=yes # Function ATAN
+func_odbc_atan2=no # Function ATAN2
+func_odbc_ceiling=yes # Function CEILING
+func_odbc_char=yes # Function CHAR
+func_odbc_concat=yes # Function CONCAT(2 arg)
+func_odbc_cos=yes # Function COS
+func_odbc_cot=no # Function COT
+func_odbc_curdate=yes # Function CURDATE
+func_odbc_curtime=yes # Function CURTIME
+func_odbc_database=no # 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=no # Function DEGREES
+func_odbc_difference=no # Function DIFFERENCE()
+func_odbc_exp=yes # Function EXP
+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=yes # Function ANSI HOUR
+func_odbc_ifnull=no # Function IFNULL
+func_odbc_insert=no # Function INSERT
+func_odbc_lcase=yes # Function LCASE
+func_odbc_left=yes # Function LEFT
+func_odbc_length=error # Function REAL 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
+func_odbc_log10=no # Function LOG10
+func_odbc_ltrim=yes # Function LTRIM
+func_odbc_minute=yes # Function MINUTE
+func_odbc_mod=yes # Function MOD
+func_odbc_month=yes # Function MONTH
+func_odbc_monthname=yes # Function MONTHNAME
+func_odbc_now=yes # Function NOW
+func_odbc_pi=no # Function PI
+func_odbc_power=yes # Function POWER
+func_odbc_quarter=yes # Function QUARTER
+func_odbc_radians=no # Function RADIANS
+func_odbc_rand=yes # Function RAND
+func_odbc_repeat=no # Function REPEAT
+func_odbc_replace=no # Function REPLACE
+func_odbc_right=yes # Function RIGHT
+func_odbc_round=yes # Function ROUND(2 arg)
+func_odbc_rtrim=yes # Function RTRIM
+func_odbc_second=yes # Function SECOND
+func_odbc_sign=yes # Function SIGN
+func_odbc_sin=yes # Function SIN
+func_odbc_soundex=no # Function SOUNDEX
+func_odbc_space=yes # Function SPACE
+func_odbc_sqrt=yes # Function SQRT
+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=no # Function TRUNCATE
+func_odbc_ucase=yes # Function UCASE
+func_odbc_user()=no # 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_cast=no # 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_||=no # Function concatenation with ||
+func_sql_current_date=no # Function CURRENT_DATE
+func_sql_current_time=no # Function CURRENT_TIME
+func_sql_current_timestamp=no # Function CURRENT_TIMESTAMP
+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=no # Function LOWER
+func_sql_nullif=no # Function NULLIF
+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=no # Function UPPER
+func_sql_user=no # 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=no # 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=no # 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_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=no # Group function COUNT(DISTINCT expr)
+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_sum=yes # Group function SUM
+group_functions=yes # Group functions
+has_true_false=yes # 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=yes # 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_select=yes # 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=32 # 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=-1 # Value of logical operation (1=1)
+max_big_expressions=1 # big expressions
+max_char_size=85 # max char() size
+max_column_name=59 # column name length
+max_columns=255 # Columns in table
+max_conditions=97 # OR and AND in WHERE
+max_expressions=+10000 # simple expressions
+max_index=32 # max index
+max_index_length=10 # index length
+max_index_name=64 # index name length
+max_index_part_length=50 # max index part length
+max_index_parts=10 # index parts
+max_index_varchar_part_length=50 # index varchar part length
+max_row_length=2025 # max table row length (without blobs)
+max_row_length_with_null=2025 # table row length with nulls (without blobs)
+max_select_alias_name=64 # select alias name length
+max_stack_expression=14 # stacked expressions
+max_table_alias_name=253 # table alias name length
+max_table_name=64 # table name length
+max_text_size=17 # max text or blob size
+max_unique_index=32 # unique indexes
+max_varchar_size=85 # 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_null_in_unique=yes # null in unique index
+multi_strings=no # Multiple line strings
+multi_table_delete=yes # DELETE FROM table1,table2...
+multi_table_update=yes # Update with many tables
+multi_value_insert=no # Value lists in INSERT
+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 concat('a',NULL) = NULL
+null_in_index=yes # null in index
+null_in_unique=yes # null in unique index
+odbc_left_outer_join=yes # left outer join odbc style
+operating_system=Microsoft Windows 2000 [Version 5.00.2195] # crash-me tested on
+order_by=yes # Order by
+order_by_alias=no # 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
+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_[=yes # [] as identifier quote
+quote_ident_with_`=yes # ` as identifier quote
+quote_with_"=no # Allows ' and " as string markers
+recursive_subqueries=49 # recursive subqueries
+remember_end_space=no # Remembers end space in char()
+remember_end_space_varchar=yes # Remembers end space in varchar()
+right_outer_join=yes # right outer join
+rowid=no # Type for row id
+select_constants=yes # Select constants
+select_limit=with TOP # LIMIT number of rows
+select_limit2=no # SELECT with LIMIT #,#
+select_string_size=516076 # constant string size in SELECT
+select_table_update=no # Update with sub select
+select_without_from=yes # SELECT without FROM
+server_version=Access 2000 # server version
+simple_joins=yes # ANSI SQL simple joins
+subqueries=yes # subqueries
+table_alias=yes # Table alias
+table_name_case=yes # case independent table names
+table_wildcard=yes # Select table_name.*
+tempoary_table=no # temporary tables
+transactions=error # transactions
+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=yes # Type byte
+type_extra_char(1_arg)_binary=no # Type char(1 arg) binary
+type_extra_circle=no # Type circle
+type_extra_clob=no # Type clob
+type_extra_datetime=yes # Type datetime
+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=yes # Type float4
+type_extra_float8=yes # Type float8
+type_extra_image=yes # Type image
+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=yes # 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_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=yes # Type money
+type_extra_nclob=no # Type nclob
+type_extra_number=yes # 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=yes # Type text
+type_extra_text(1_arg)=yes # 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)=yes # Type binary(1 arg)
+type_odbc_datetime=yes # Type datetime
+type_odbc_tinyint=no # Type tinyint
+type_odbc_varbinary(1_arg)=yes # Type varbinary(1 arg)
+type_sql_bit=yes # 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)=no # Type char varying(1 arg)
+type_sql_character(1_arg)=no # Type character(1 arg)
+type_sql_character_varying(1_arg)=no # Type character varying(1 arg)
+type_sql_date=yes # Type date
+type_sql_dec(2_arg)=no # Type dec(2 arg)
+type_sql_decimal(2_arg)=no # Type decimal(2 arg)
+type_sql_double_precision=no # Type double precision
+type_sql_float=yes # Type float
+type_sql_float(1_arg)=no # 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)=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)=no # 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=yes # unique null in create
+views=no # views
+where_string_size=258035 # constant string size in where
diff --git a/sql-bench/limits/access.comment b/sql-bench/limits/access.comment
new file mode 100644
index 00000000000..f4a419aa159
--- /dev/null
+++ b/sql-bench/limits/access.comment
@@ -0,0 +1,40 @@
+Access 97 tested through ODBC 1998.04.19, by monty@mysql.com
+
+Access 97 has a bug when on executes a SELECT follwed very fast with a
+DROP TABLE or a DROP INDEX command:
+
+[Microsoft][ODBC Microsoft Access 97 Driver] The database engine couldn't lock table 'crash_q' because it's already in use by another person or process. (SQL-S1
+000)(DBD: st_execute/SQLExecute err=-1)
+
+Debugging SQL queries in Access 97 is terrible because most error messages
+are of type:
+
+Error: [Microsoft][ODBC Microsoft Access 97 Driver] Syntax error in CREATE TABLE statement. (SQL-37000)(DBD: st_prepare/SQLPrepare err=-1)
+
+Which doesn't tell a thing!
+
+--------------
+
+Access 2000 tested through ODBC 2000.01.02, by monty@mysql.com
+
+crash-me takes a LONG time to run under Access 2000.
+
+The '1+NULL' and the 'OR and AND in WHERE' tests kills
+Activestate Perl, build 521, DBI-DBC with an OUT OF MEMORY error.
+The later test also kills perl/access with some internal errors.
+To go around this one must run crash-me repeatedly with the --restart option.
+
+Testing of the 'constant string size' (< 500K) takes a LOT of memory
+in Access (at least 250M on My computer).
+
+Testing of number of 'simple expressions' takes REALLY a lot of time
+and memory; At some point I was up to 350M of used memory!
+
+To fix the above, I modified crash-me to have lower max limits in the
+above tests.
+
+Benchmarks (under Win98):
+
+Running the connect-test will take up all available memory and this
+will not be freed even after quitting perl! There is probably some
+bug in the Access connect code that eats memory!
diff --git a/sql-bench/limits/access_odbc.cfg b/sql-bench/limits/access_odbc.cfg
new file mode 100644
index 00000000000..fc06ce97fac
--- /dev/null
+++ b/sql-bench/limits/access_odbc.cfg
@@ -0,0 +1,448 @@
+#This file is automaticly generated by crash-me 1.37
+
+NEG=yes # update of column= -column
+alter_add_col=yes # Alter table add column
+alter_add_multi_col=without add # Alter table add many columns
+alter_alter_col=no # Alter table alter column
+alter_change_col=no # Alter table change column
+alter_drop_col=yes # Alter table drop column
+alter_modify_col=no # Alter table modify column
+alter_rename_table=no # Alter table rename table
+atomic_updates=no # atomic updates
+binary_items=yes # binary items (0x41)
+case_insensitive_strings=yes # case insensitive compare
+char_is_space_filled=no # char are space filled
+column_alias=yes # Column alias
+columns_in_group_by=11 # number of columns in group by
+columns_in_order_by=11 # number of columns in order by
+comment_#=no # # as comment
+comment_--=no # -- as comment
+comment_/**/=no # /* */ as comment
+comment_//=no # // as comment
+compute=no # Compute
+connections=64 # Simultaneous connections
+constraint_check=no # CHECK constraint
+constraint_null=yes # NULL constraint (SyBase style)
+crash_me_safe=no # crash me safe
+crash_me_version=1.37 # crash me version
+create_default=no # 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_table_select=no # create table from select
+cross_join=no # cross join (same as from a,b)
+date_as_string=error # String functions on date columns
+date_with_YY=yes # Supports YY-MM-DD 2000 compilant dates
+date_zero=no # Supports 0000-00-00 dates
+double_quotes=yes # Double '' as ' in strings
+drop_if_exists=no # drop table if exists
+drop_index=with 'ON' # drop index
+end_colon=yes # allows end ';'
+except=no # except
+except_all=no # except all
+float_int_expr=yes # mixing of integer and float in expression
+foreign_key_syntax=no # foreign key syntax
+full_outer_join=no # full outer join
+func_extra_!=no # Function NOT as '!' in SELECT
+func_extra_%=no # Function MOD as %
+func_extra_&=error # Function & (bitwise and)
+func_extra_&&=no # Function AND as '&&'
+func_extra_<>=yes # Function <> in SELECT
+func_extra_==yes # Function =
+func_extra_add_months=no # Function ADD_MONTHS
+func_extra_and_or=yes # Function AND and OR in SELECT
+func_extra_atn2=no # Function ATN2
+func_extra_auto_num2string=no # Function automatic num->string convert
+func_extra_auto_string2num=yes # Function automatic string->num convert
+func_extra_between=yes # 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=yes # Function CHR
+func_extra_coalesce=no # Function COALESCE
+func_extra_concat_as_+=yes # 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=error # 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=yes # Function IN on numbers in SELECT
+func_extra_in_str=yes # Function IN on strings in SELECT
+func_extra_initcap=no # Function INITCAP
+func_extra_instr=yes # 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=yes # 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=yes # Function SUBSTRING as MID
+func_extra_months_between=no # Function MONTHS_BETWEEN
+func_extra_not=yes # Function NOT in SELECT
+func_extra_not_between=yes # Function NOT BETWEEN in SELECT
+func_extra_not_like=yes # Function NOT LIKE in SELECT
+func_extra_odbc_convert=no # Function ODBC CONVERT
+func_extra_password=no # Function PASSWORD
+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=yes # 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_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=error # Function WEEKDAY
+func_extra_|=no # Function | (bitwise or)
+func_extra_||=no # Function OR as '||'
+func_odbc_abs=yes # 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=yes # 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=yes # Function EXP
+func_odbc_extract=no # Function EXTRACT
+func_odbc_floor=no # 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_insert=no # Function INSERT
+func_odbc_lcase=yes # Function LCASE
+func_odbc_left=yes # 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=yes # Function LOG
+func_odbc_log10=no # Function LOG10
+func_odbc_ltrim=yes # Function LTRIM
+func_odbc_minute=yes # Function MINUTE
+func_odbc_mod=no # Function MOD
+func_odbc_month=yes # Function MONTH
+func_odbc_monthname=no # Function MONTHNAME
+func_odbc_now=yes # 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=yes # Function RIGHT
+func_odbc_round=yes # Function ROUND(2 arg)
+func_odbc_rtrim=yes # Function RTRIM
+func_odbc_second=yes # Function SECOND
+func_odbc_sign=no # Function SIGN
+func_odbc_sin=yes # Function SIN
+func_odbc_soundex=no # Function SOUNDEX
+func_odbc_space=yes # Function SPACE
+func_odbc_sqrt=no # Function SQRT
+func_odbc_substring=no # Function ODBC SUBSTRING
+func_odbc_tan=yes # Function TAN
+func_odbc_timestampadd=no # Function TIMESTAMPADD
+func_odbc_timestampdiff=no # Function TIMESTAMPDIFF
+func_odbc_truncate=no # Function TRUNCATE
+func_odbc_ucase=yes # Function UCASE
+func_odbc_user()=no # Function USER()
+func_odbc_week=no # Function WEEK
+func_odbc_year=yes # Function YEAR
+func_sql_+=yes # Function +, -, * and /
+func_sql_bit_length=no # Function BIT_LENGTH
+func_sql_case=no # Function CASE
+func_sql_cast=no # 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_concat_as_||=no # Function concatenation with ||
+func_sql_current_date=no # Function CURRENT_DATE
+func_sql_current_time=no # Function CURRENT_TIME
+func_sql_current_timestamp=no # Function CURRENT_TIMESTAMP
+func_sql_current_user=no # Function CURRENT_USER
+func_sql_lower=no # Function LOWER
+func_sql_octet_length=no # Function OCTET_LENGTH
+func_sql_position=no # Function POSITION
+func_sql_session_user=no # Function SESSION_USER
+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=no # Function UPPER
+func_sql_user=no # 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=no # 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=no # 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_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=no # Group function COUNT(DISTINCT expr)
+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_sum=yes # Group function SUM
+group_functions=yes # Group functions
+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
+index_in_create=no # index in create table
+index_namespace=yes # different namespace for index
+index_parts=no # index on column part (extension)
+insert_empty_string=yes # insert empty string
+insert_select=no # insert INTO ... SELECT ...
+insert_with_set=no # INSERT with set syntax
+intersect=no # intersect
+intersect_all=no # intersect all
+join_tables=32 # tables in join
+left_outer_join=yes # left outer join
+left_outer_join_using=no # left outer join using
+like_with_column=yes # column LIKE column
+like_with_number=yes # LIKE on numbers
+lock_tables=no # lock table
+logical_value=-1 # Value of logical operation (1=1)
+max_big_expressions=1 # big expressions
+max_char_size=255 # max char() size
+max_column_name=59 # column name length
+max_columns=255 # Columns in table
+max_conditions=97 # OR and AND in WHERE
+max_expressions=+10000 # simple expressions
+max_index=32 # max index
+max_index_length=2026 # index length
+max_index_name=64 # index name length
+max_index_part_length=255 # max index part length
+max_index_parts=10 # index parts
+max_index_varchar_part_length=85 # index varchar part length
+max_row_length=2025 # max table row length (without blobs)
+max_row_length_with_null=2025 # table row length with nulls (without blobs)
+max_select_alias_name=64 # select alias name length
+max_stack_expression=14 # stacked expressions
+max_table_alias_name=253 # table alias name length
+max_table_name=64 # table name length
+max_text_size=17 # max text or blob size
+max_unique_index=32 # unique indexes
+max_varchar_size=85 # max varchar() size
+minus=no # minus
+minus_neg=yes # Calculate 1--1
+multi_drop=yes # many tables to drop table
+multi_strings=no # Multiple line strings
+multi_table_delete=yes # DELETE FROM table1,table2...
+multi_table_update=yes # Update with many tables
+multi_value_insert=no # Value lists in INSERT
+natural_join=no # natural join
+natural_left_outer_join=no # natural left outer join
+no_primary_key=yes # Tables without primary key
+null_in_index=yes # null in index
+null_in_unique=yes # null in unique
+odbc_left_outer_join=yes # left outer join odbc style
+operating_system=Windows 98 [Version 4.10.1998] # crash-me tested on
+order_by=yes # Order by
+order_by_alias=no # 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
+primary_key_in_create=yes # primary key in create table
+query_size=16777216 # query size
+quote_ident_with_"=yes # " as identifier quote (ANSI SQL)
+quote_ident_with_[=yes # [] as identifier quote
+quote_ident_with_`=yes # ` as identifier quote
+quote_with_"=no # Allows ' and " as string markers
+recursive_subqueries=49 # recursive subqueries
+remember_end_space=no # Remembers end space in char()
+remember_end_space_varchar=yes # Remembers end space in varchar()
+right_outer_join=yes # right outer join
+rowid=no # Type for row id
+select_constants=yes # Select constants
+select_limit=no # SELECT with LIMIT
+select_limit2=no # SELECT with LIMIT #,#
+select_string_size=516076 # constant string size in SELECT
+select_table_update=no # Update with sub select
+select_without_from=yes # SELECT without FROM
+server_version=Access 2000 # server version
+simple_joins=yes # ANSI SQL simple joins
+subqueries=yes # subqueries
+table_alias=yes # Table alias
+table_name_case=yes # case independent table names
+table_wildcard=yes # Select table_name.*
+tempoary_table=no # temporary tables
+transactions=yes # transactions
+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=yes # Type byte
+type_extra_char(1_arg)_binary=no # Type char(1 arg) binary
+type_extra_circle=no # Type circle
+type_extra_clob=no # Type clob
+type_extra_datetime=yes # Type datetime
+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=yes # Type float4
+type_extra_float8=yes # Type float8
+type_extra_image=yes # Type image
+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_unsigned=no # Type int unsigned
+type_extra_interval=no # Type interval
+type_extra_line=no # Type line
+type_extra_long=yes # 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_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=yes # Type money
+type_extra_nclob=no # Type nclob
+type_extra_number=yes # 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=yes # Type text
+type_extra_text(1_arg)=yes # 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)=yes # Type binary(1 arg)
+type_odbc_datetime=yes # Type datetime
+type_odbc_tinyint=no # Type tinyint
+type_odbc_varbinary(1_arg)=yes # Type varbinary(1 arg)
+type_sql_bit=yes # 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)=no # Type char varying(1 arg)
+type_sql_character(1_arg)=no # Type character(1 arg)
+type_sql_character_varying(1_arg)=no # Type character varying(1 arg)
+type_sql_date=yes # Type date
+type_sql_dec(2_arg)=no # Type dec(2 arg)
+type_sql_decimal(2_arg)=no # Type decimal(2 arg)
+type_sql_double_precision=no # Type double precision
+type_sql_float=yes # Type float
+type_sql_float(1_arg)=no # Type float(1 arg)
+type_sql_int=yes # Type int
+type_sql_integer=yes # Type integer
+type_sql_interval_day_to_second=no # Type interval day to 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)=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)=no # 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
+unique_in_create=yes # unique in create table
+unique_null_in_create=yes # unique null in create
+views=no # views
+where_string_size=258035 # constant string size in where
diff --git a/sql-bench/limits/db2.cfg b/sql-bench/limits/db2.cfg
new file mode 100644
index 00000000000..31280fbe643
--- /dev/null
+++ b/sql-bench/limits/db2.cfg
@@ -0,0 +1,422 @@
+#This file is automaticly generated by crash-me 1.19a
+
+NEG=yes # update of column= -column
+alter_add_col=yes # Alter table add column
+alter_change_col=no # Alter table change column
+alter_drop_col=no # Alter table drop column
+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
+column_alias=yes # Column alias
+comment_#=no # # as comment
+comment_--=yes # -- as comment
+comment_/**/=no # /* */ as comment
+compute=no # Compute
+connections=125 # Simultaneous connections
+crash_me_safe=no # crash me safe
+crash_me_version=1.19a # crash me version
+create_default=yes # default value for column
+create_index=yes # create index
+cross_join=no # cross join (same as from a,b)
+date_as_string=no # String functions on date columns
+date_with_YY=no # Supports YY-MM-DD dates
+date_zero=no # Supports 0000-00-00 dates
+double_quotes=yes # Double '' as ' in strings
+drop_index=yes # drop index
+except=yes # except
+except_all=yes # except all
+float_int_expr=yes # mixing of integer and float in expression
+foreign_key=yes # foreign keys
+foreign_key_syntax=yes # 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_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=yes # Function CEIL
+func_extra_charindex=no # Function CHARINDEX
+func_extra_chr=yes # 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_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=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_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_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=error # 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=yes # 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_odbc_abs=yes # Function ABS
+func_odbc_acos=yes # Function ACOS
+func_odbc_ascii=yes # Function ASCII
+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_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_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_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_locate_2=yes # Function LOCATE(2 arg)
+func_odbc_locate_3=yes # Function LOCATE(3 arg)
+func_odbc_log=yes # Function LOG
+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_power=yes # Function POWER
+func_odbc_quarter=no # Function QUARTER
+func_odbc_radians=yes # Function RADIANS
+func_odbc_rand=yes # Function RAND
+func_odbc_repeat=yes # Function REPEAT
+func_odbc_replace=yes # Function REPLACE
+func_odbc_right=yes # Function RIGHT
+func_odbc_round=yes # Function ROUND(2 arg)
+func_odbc_rtrim=yes # Function RTRIM
+func_odbc_second=yes # Function SECOND
+func_odbc_sign=yes # Function SIGN
+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_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_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_character_length=no # Function CHARACTER_LENGTH
+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_octet_length=no # Function OCTET_LENGTH
+func_sql_position=no # Function POSITION
+func_sql_session_user=no # Function SESSION_USER
+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_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 # Test nulls in group by
+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_std=no # Group function STD
+group_func_extra_stddev=yes # Group function STDDEV
+group_func_extra_variance=yes # Group function VARIANCE
+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_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_sum=yes # Group function SUM
+group_functions=yes # Group functions
+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
+index_in_create=no # index in create table
+index_namespace=no # different namespace for index
+index_parts=no # index on column part (extension)
+insert_empty_string=yes # insert empty string
+insert_select=yes # insert INTO ... SELECT ...
+intersect=yes # intersect
+intersect_all=yes # intersect all
+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=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_columns=500 # Columns in table
+max_conditions=418 # OR and AND in WHERE
+max_expressions=9820 # simple expressions
+max_index=+64 # max index
+max_index_length=255 # 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_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_stack_expression=1363 # stacked expressions
+max_table_alias_name=18 # table alias name length
+max_table_name=18 # table name length
+max_unique_index=+64 # unique indexes
+max_varchar_size=4000 # max varchar() size
+minus=no # minus
+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_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_num_expr=no # Is 1+NULL = NULL
+odbc_left_outer_join=yes # left outer join odbc style
+operating_system=Windows NT Version 4.0 # crash-me tested on
+order_by=yes # Order by
+order_by_alias=yes # Order by alias
+order_by_position=yes # Order by position
+primary_key_in_create=yes # primary key in create table
+query_size=19662 # query size
+quote_with_"=no # Allows ' and " as string markers
+recursive_subqueries=22 # recursive subqueries
+remember_end_space=no # Remembers end space in char()
+remember_end_space_varchar=yes # Remembers end space in varchar()
+repeat_string_size=4000 # return string size from function
+right_outer_join=yes # right outer join
+select_constants=yes # Select constants
+select_string_size=4000 # 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
+simple_joins=yes # ANSI SQL simple joins
+subqueries=yes # subqueries
+table_alias=yes # Table alias
+table_wildcard=yes # Select table_name.*
+transactions=yes # transactions
+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_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_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_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_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_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_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_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_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_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_double_precision=yes # Type double precision
+type_sql_float=yes # Type float
+type_extra_float(2_arg)=no # Type float(1 arg)
+type_sql_int=yes # Type int
+type_sql_integer=yes # Type integer
+type_sql_interval_year=no # Type interval year
+type_sql_numeric(2_arg)=yes # Type numeric(2 arg)
+type_sql_real=yes # Type real
+type_sql_time=yes # Type time
+type_sql_timestamp=yes # Type timestamp
+type_sql_varchar(1_arg)=yes # Type varchar(1 arg)
+union=yes # union
+union_all=yes # union all
+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
diff --git a/sql-bench/limits/empress.cfg b/sql-bench/limits/empress.cfg
new file mode 100644
index 00000000000..67256adb3bf
--- /dev/null
+++ b/sql-bench/limits/empress.cfg
@@ -0,0 +1,364 @@
+#This file is automaticly generated by crash-me 1.18a
+
+NEG=yes # update of column= -column
+atomic_updates=no # atomic updates
+binary_items=no # binary items (0x41)
+case_insensitive_strings=no # case insensitive compare
+column_alias=no # Column alias
+comment_#=no # # as comment
+comment_--=yes # -- as comment
+comment_/**/=yes # /* */ as comment
+compute=no # Compute
+connections=10 # Simultaneous connections
+crash_me_safe=no # crash me safe
+crash_me_version=1.18a # crash me version
+create_default=no # default value for column
+create_index=yes # create index
+cross_join=no # cross join (same as from a,b)
+date_as_string=no # String functions on date columns
+date_with_YY=no # Supports YY-MM-DD dates
+date_zero=no # Supports 0000-00-00 dates
+double_quotes=yes # Double '' as ' in strings
+drop_index=yes # drop index
+except=no # except
+except_all=no # except all
+float_int_expr=yes # mixing of integer and float in expression
+foreign_key_syntax=no # foreign key syntax
+full_outer_join=no # full outer join
+func_extra_!=no # Function NOT as '!' in SELECT
+func_extra_%=yes # 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_and_or=no # Function AND and OR in SELECT
+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_bit_count=no # Function BIT_COUNT
+func_extra_charindex=no # Function CHARINDEX
+func_extra_concat_as_+=no # Function concatenation with +
+func_extra_concat_list=no # Function CONCAT(list)
+func_extra_convert=no # Function CONVERT
+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_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_instr=no # Function LOCATE as INSTR
+func_extra_interval=no # Function INTERVAL
+func_extra_last_insert_id=no # Function LAST_INSERT_ID
+func_extra_like=no # Function LIKE in SELECT
+func_extra_like_escape=no # Function LIKE ESCAPE in SELECT
+func_extra_lpad=no # Function LPAD
+func_extra_max_num=no # Function MAX on numbers
+func_extra_mid=no # Function SUBSTRING as MID
+func_extra_min_num=no # Function MIN on numbers
+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_patindex=no # Function PATINDEX
+func_extra_period_add=no # Function PERIOD_ADD
+func_extra_period_diff=no # Function PERIOD_DIFF
+func_extra_pow=yes # Function POW
+func_extra_regexp=no # Function REGEXP in SELECT
+func_extra_replicate=no # Function REPLICATE
+func_extra_reverse=no # Function REVERSE
+func_extra_round1=yes # Function ROUND(1 arg)
+func_extra_rpad=no # Function RPAD
+func_extra_sec_to_time=no # Function SEC_TO_TIME
+func_extra_str=no # Function STR
+func_extra_strcmp=no # Function STRCMP
+func_extra_stuff=no # Function STUFF
+func_extra_substring_index=no # Function SUBSTRING_INDEX
+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_unix_timestamp=no # Function UNIX_TIMESTAMP
+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_odbc_abs=yes # Function ABS
+func_odbc_acos=yes # Function ACOS
+func_odbc_ascii=no # Function ASCII
+func_odbc_asin=yes # Function ASIN
+func_odbc_atan=yes # Function ATAN
+func_odbc_atan2=yes # Function ATAN2
+func_odbc_ceiling=yes # Function CEILING
+func_odbc_char=no # Function CHAR
+func_odbc_concat=no # Function CONCAT(2 arg)
+func_odbc_cos=yes # 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=yes # Function EXP
+func_odbc_extract=no # Function EXTRACT
+func_odbc_floor=yes # 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=yes # Function REAL LENGTH
+func_odbc_length_without_space=error # Function ODBC LENGTH
+func_odbc_locate_2=no # Function LOCATE(2 arg)
+func_odbc_locate_3=no # Function LOCATE(3 arg)
+func_odbc_log=yes # Function LOG
+func_odbc_log10=yes # Function LOG10
+func_odbc_ltrim=yes # 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=yes # Function ROUND(2 arg)
+func_odbc_rtrim=yes # Function RTRIM
+func_odbc_second=no # Function SECOND
+func_odbc_sign=yes # Function SIGN
+func_odbc_sin=yes # Function SIN
+func_odbc_soundex=no # Function SOUNDEX
+func_odbc_space=no # Function SPACE
+func_odbc_sqrt=yes # Function SQRT
+func_odbc_substring=no # Function ODBC SUBSTRING
+func_odbc_tan=yes # 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_case=no # Function CASE
+func_sql_cast=no # Function CAST
+func_sql_char_length=no # Function CHAR_LENGTH
+func_sql_character_length=no # Function CHARACTER_LENGTH
+func_sql_concat_as_||=no # 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_octet_length=no # Function OCTET_LENGTH
+func_sql_position=no # Function POSITION
+func_sql_session_user=no # Function SESSION_USER
+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_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=yes # Function MATCH
+func_where_match_unique=no # Function MATCH UNIQUE
+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_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_std=no # Group function STD
+group_func_extra_stddev=no # Group function STDDEV
+group_func_extra_variance=no # Group function VARIANCE
+group_func_sql_avg=yes # Group function AVG
+group_func_sql_count_*=yes # Group function COUNT (*)
+group_func_sql_count_column=no # Group function COUNT column name
+group_func_sql_count_distinct=yes # Group function COUNT DISTINCT column name
+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_sum=yes # Group function SUM
+group_functions=yes # Group functions
+having=yes # Having
+having_with_alias=no # Having with alias
+having_with_group=yes # Having with group function
+index_in_create=no # index in create table
+index_namespace=yes # different namespace for index
+index_parts=no # index on column part (extension)
+insert_empty_string=no # insert empty string
+insert_select=yes # insert INTO ... SELECT ...
+intersect=no # intersect
+intersect_all=no # intersect all
+join_tables=63 # tables in join
+left_outer_join=no # left outer join
+left_outer_join_using=no # left outer join using
+like_with_column=yes # column LIKE column
+like_with_number=yes # LIKE on numbers
+lock_tables=yes # lock table
+logical_value=not supported # Value of logical operation (1=1)
+max_big_expressions=1 # big expressions
+max_char_size=7930634 # max char() size
+max_column_name=31 # column name length
+max_columns=2419 # Columns in table
+max_conditions=628 # OR and AND in WHERE
+max_expressions=4092 # simple expressions
+max_index=+64 # max index
+max_index_length=2710 # index length
+max_index_name=32 # index name length
+max_index_part_length=2710 # index part length
+max_index_parts=+64 # index parts
+max_row_length=62696 # max table row length (without blobs)
+max_row_length_with_null=62702 # table row length with nulls (without blobs)
+max_stack_expression=131 # stacked expressions
+max_table_alias_name=+512 # table alias name length
+max_table_name=32 # table name length
+max_text_size=4095 # max text or blob size
+max_unique_index=+64 # max unique index
+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_left_outer_join=no # natural left outer join
+no_primary_key=yes # Tables without primary key
+null_concat_expr=no # Is concat('a',NULL) = NULL
+null_in_index=no # null in index
+null_num_expr=no # Is 1+NULL = NULL
+odbc_left_outer_join=no # left outer join odbc style
+operating_system=Linux 2.0.33 i586 # crash-me tested on
+order_by=yes # Order by
+order_by_position=yes # Order by position
+primary_key_in_create=no # primary key in create table
+query_size=16777216 # query size
+quote_with_"=yes # Allows ' and " as string markers
+recursive_subqueries=49 # recursive subqueries
+remember_end_space=error # Remembers end space in char()
+right_outer_join=no # right outer join
+select_constants=yes # Select constants
+select_string_size=32753 # constant string string size in SELECT
+select_table_update=no # Update with sub select
+select_without_from=no # SELECT without FROM
+server_version=EMPRESS Version 6.10 # server version
+simple_joins=yes # ANSI SQL simple joins
+subqueries=yes # subqueries
+table_alias=no # Table alias
+table_wildcard=no # Select table_name.*
+transactions=yes # transactions
+type_extra_abstime=no # Type abstime
+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_circle=no # Type circle
+type_extra_datetime=no # Type datetime
+type_extra_enum(1_arg)=no # Type enum(1 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_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_line=no # Type line
+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_mediumint=no # Type mediumint
+type_extra_mediumtext=no # Type mediumtext
+type_extra_middleint=no # Type middleint
+type_extra_money=no # Type money
+type_sql_nchar(1_arg)=no # Type nchar(1 arg)
+type_extra_nvarchar(2_arg)=no # Type nvarchar(2 arg)
+type_extra_path=no # Type path
+type_extra_point=no # Type point
+type_extra_polygon=no # Type polygon
+type_extra_reltime=no # Type reltime
+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=yes # Type text
+type_extra_text(1_arg)=yes # Type text(1 arg)
+type_extra_timespan=no # Type timespan
+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_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)=no # Type char varying(1 arg)
+type_sql_character(1_arg)=yes # Type character(1 arg)
+type_sql_character_varying(1_arg)=no # 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=no # Type double
+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_int=yes # Type int
+type_sql_integer=yes # Type integer
+type_sql_interval_year=no # Type interval year
+type_sql_numeric(2_arg)=no # Type numeric(2 arg)
+type_sql_real=yes # Type real
+type_sql_time=yes # Type time
+type_sql_timestamp=no # Type timestamp
+type_sql_varchar(1_arg)=no # Type varchar(1 arg)
+union=no # union
+union_all=no # union all
+unique_in_create=no # unique in create table
+views=yes # views
+where_string_size=nonstandard # constant string size in where
diff --git a/sql-bench/limits/empress.comment b/sql-bench/limits/empress.comment
new file mode 100644
index 00000000000..b60bf4f19a9
--- /dev/null
+++ b/sql-bench/limits/empress.comment
@@ -0,0 +1,102 @@
+*****************************************************************
+NOTE:
+This is an old comment about how it was to run crash-me on empress
+the first time. I think it was on Empress 6.0
+*****************************************************************
+
+start testing empress ...
+added a nice line for the max join ....
+strip the as out of the from field ...
+that's working on empress ....
+
+at this moment with ....
+max constant string size in where .... taking a lot of memory ...
+at this moment (it's still growing just waiting till it stops ..) 99mb ..
+sorry it started growing again ...
+max 170 mb ... then it gives an error ...
+Yes it crashed .....
+at max constant string size in where ... with IOT trap/Abort(core dumped) :-)
+nice isn't it ... hope it saved the things ....
+I outcommented the sig story because I could see how the script is running
+and I wasn't sure if SIG{PIPE} ='DEFAULT' ... is working ...
+restarting with limit 8333xxx ... couldn't see it any more ...
+query is printed ...(200000 lines ..). mmm Nice IOT trap/Abort ...
+and again ..and again ...
+aha ... and now it's going further ...
+max constant string string size in select: ...
+taking 100 mb
+crashing over and over again ....
+max simple expressions ...
+is taking ... 82 mb ...
+mmmm this is taking very very very long .... after 10 minutes I will kill it and run it again ... I think he can't proces this query that fast ... and will crash any way ...
+still growing very slow to the 90 mb ...
+killed it ... strange is ... it don't react on ctrl-c ... but kill 15 does work
+mmm still bussy with killing his self ... memory is growing to 128 mb ...
+sorry .. 150 mb .. and then the output ..
+maybe something for the extra things for crash-me ...
+if debug ....
+if length $query > 300 ... just print $errstr .. else print $query + $errstr ..
+at this moment he is still bussy printing ....
+first clear all locks ... with empadm test lockclear ... else it will give me
+the error with a lock ...
+restarting at 4194297 .... mmm a bit high I think ...
+after 5 minutes I will kill it ...
+mmm have to kill it again ... took 30 mb ..now growing to 42 mb ..
+restarting at 838859 ... hope this will crash normaly ... :-)
+I will give it again 5 minutes to complete ...
+taking 12 mb .... will kill it ... after 4 minutes ....
+restarting at 167771 ... taking 6 mb ... give it again 5 minutes ....
+ will kill it again ... else it becomes to late tonight ...
+mmm started with 33xxxx and it crashes ...:-) yes ...
+can't we build in a function which will restart his self again ...
+mmmm this is really boring .. start it over and over again ...
+WHO .... NICE >>>>
+Restarting this with high limit: 4097
+.................
+*** Program Bug *** setexpr: unknown EXPR = 1254 (4e6)
+isn't it ... starting it again ...
+finally finished with 4092 ....
+now max big expression .....
+directly taking .. 85 mb ... give it again 5 minutes ...
+mmm I am going to kill it again ... mmm it grows to 146 mb ...
+restarting with 1026 ... taking 25 mb ..
+won't give him that long ... because it will crash any way (just a ques) ..
+killed it ...
+restarting at 205 ... hope this will work ....
+won't think so ... give it 2 minutes ... taking 12 mb ...
+killed it ...restarting at ... 40 ... yes it crashes ...
+ 7 is crashing ... 1 ....is good .. finaly ... a long way ...
+now max stacked expressions ....
+taking 80 mb ... mmmm what sort of test is this ...it looks more like a harddisk test .. but it crashes .. nice ...
+mmm a YACC overflow ... that's a nice error ...
+but it goes on ... yep it didn't crashed just an error ...
+ mmm
+my patch for the join didn't work ... let's take a look what goes wrong ...
+saw it ... forgot some little thing .. mm not .. them ... another little typo
+mmm again a really nice bug ...
+Restarting this with high limit: 131
+...
+*** Program Bug *** xflkadd: too many read locks
+them the lock forgotten ....
+mmmm bigger problem ...
+with empadm test lockinfo ... gives ...
+*** System Problem *** no more clients can be registered in coordinator
+
+*** User Error *** '/usr/local/empress/rdbms/bin/test' is not a valid database
+that's really really nice ....
+hmmm after coordclear ... it's fine again ...
+strange ...
+ after restarting it again the script ... it is going further ....
+the overflow trick is nice and working good ...
+now I have table 'crash_q' does not exist for every thing ...
+normal ...???? mmm went after all good .. so I think it's normal ...
+mmmm a lot of table 'crash_q' does not exist ... again ...
+sometimes when the overflow is there ... I restart it and it is saying ...
+restarting at xxxx that's not good ... but hey ... what the hack ...
+maybe that's good because if one test run's more then 200 times ....
+it won't exceeds that test ...
+....
+yes finally the end of crash-me ...
+at last ... crash-me safe: yes ...
+yep don't think so he ....
+
diff --git a/sql-bench/limits/interbase.cfg b/sql-bench/limits/interbase.cfg
new file mode 100644
index 00000000000..7427208df5d
--- /dev/null
+++ b/sql-bench/limits/interbase.cfg
@@ -0,0 +1,472 @@
+#This file is automaticly generated by crash-me 1.40
+
+NEG=no # update of column= -column
+alter_add_col=yes # Alter table add column
+alter_add_constraint=yes # Alter table add constraint
+alter_add_foreign_key=no # 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=yes # Alter table drop column
+alter_drop_constraint=yes # Alter table drop constraint
+alter_drop_foreign_key=no # 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 rowid
+binary_items=yes # binary items (0x41)
+case_insensitive_strings=no # case insensitive compare
+char_is_space_filled=no # char are space filled
+column_alias=yes # Column alias
+comment_#=no # # as comment
+comment_--=no # -- as comment
+comment_/**/=yes # /* */ as comment
+comment_//=no # // as comment
+compute=no # Compute
+connections=10 # Simultaneous connections
+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.40 # 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=ignored # 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_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
+end_colon=yes # allows end ';'
+except=no # except
+except_all=no # except all
+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=yes # 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_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_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=no # Function NULLIF
+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_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_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_sum=yes # Group function SUM
+group_functions=yes # Group functions
+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
+index_in_create=no # index in create table
+index_namespace=no # different namespace for index
+index_parts=no # index on column part (extension)
+insert_empty_string=yes # insert empty string
+insert_select=yes # insert INTO ... SELECT ...
+insert_with_set=no # INSERT with set syntax
+intersect=no # intersect
+intersect_all=no # intersect all
+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=+100 # big expressions
+max_columns=4743 # Columns in table
+max_conditions=441504 # OR and AND in WHERE
+max_expressions=+100 # simple expressions
+max_index_name=31 # index name length
+max_select_alias_name=255 # select alias name length
+max_stack_expression=100 # stacked expressions
+max_table_alias_name=255 # table alias name length
+max_table_name=32 # table name length
+minus=no # minus
+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
+multi_value_insert=no # Value lists in INSERT
+natural_join=no # natural join
+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=no # null in index
+null_in_unique=no # null in unique
+null_num_expr=no # Is 1+NULL = NULL
+odbc_left_outer_join=no # left outer join odbc style
+operating_system=Linux 2.2.14-5.0 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
+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_"=error # " as identifier quote (ANSI SQL)
+quote_ident_with_[=no # [] as identifier quote
+quote_ident_with_`=no # ` as identifier quote
+quote_with_"=yes # Allows ' and " as string markers
+recursive_subqueries=+64 # recursive subqueries
+remember_end_space=no # Remembers end space in char()
+remember_end_space_varchar=yes # Remembers end space in varchar()
+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=no # Update with sub select
+select_without_from=no # SELECT without FROM
+server_version=6.0Beta # server version
+simple_joins=yes # ANSI SQL simple joins
+storage_of_float=truncate # 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.*
+tempoary_table=no # temporary tables
+transactions=error # transactions
+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_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_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_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_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
+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/mimer.cfg b/sql-bench/limits/mimer.cfg
new file mode 100644
index 00000000000..d18e43aa892
--- /dev/null
+++ b/sql-bench/limits/mimer.cfg
@@ -0,0 +1,491 @@
+#This file is automaticly generated by crash-me 1.38
+
+NEG=yes # update of column= -column
+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=yes # Alter table add many columns
+alter_add_primary_key=yes # Alter table add primary key
+alter_add_unique=yes # Alter table add unique
+alter_alter_col=yes # Alter table alter column default
+alter_change_col=no # Alter table change column
+alter_drop_col=yes # Alter table drop column
+alter_drop_constraint=yes # Alter table drop constraint
+alter_drop_foreign_key=yes # Alter table drop foreign key
+alter_drop_primary_key=yes # Alter table drop primary key
+alter_drop_unique=yes # 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
+automatic_rowid=no # Automatic rowid
+binary_items=yes # binary items (0x41)
+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_/**/=no # /* */ as comment
+comment_//=no # // as comment
+compute=no # Compute
+connections=50 # Simultaneous connections
+constraint_check=yes # Column constraints
+constraint_check_table=yes # Table constraints
+constraint_null=no # NULL constraint (SyBase style)
+crash_me_safe=yes # crash me safe
+crash_me_version=1.38 # 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=yes # 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_last=yes # Supports 9999-12-31 dates
+date_one=yes # Supports 0001-01-01 dates
+date_with_YY=no # Supports YY-MM-DD dates
+date_zero=no # Supports 0000-00-00 dates
+domains=yes # Domains (ANSI SQL)
+double_quotes=yes # Double '' as ' in strings
+drop_if_exists=no # drop table if exists
+drop_index=yes # drop index
+end_colon=yes # allows end ';'
+except=no # except
+except_all=no # except all
+float_int_expr=yes # mixing of integer and float in expression
+foreign_key=yes # foreign keys
+foreign_key_circular=yes # Circular foreign keys
+foreign_key_syntax=yes # foreign key syntax
+full_outer_join=no # 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=yes # Function ASCII_CHAR
+func_extra_ascii_code=yes # 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=yes # 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=yes # 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_odbc_abs=yes # Function ABS
+func_odbc_acos=yes # Function ACOS
+func_odbc_ascii=yes # Function ASCII
+func_odbc_asin=yes # Function ASIN
+func_odbc_atan=yes # Function ATAN
+func_odbc_atan2=yes # Function ATAN2
+func_odbc_ceiling=yes # Function CEILING
+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=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=yes # 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=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=error # Function REAL 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
+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=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=yes # Function QUARTER
+func_odbc_radians=yes # Function RADIANS
+func_odbc_rand=yes # Function RAND
+func_odbc_repeat=yes # Function REPEAT
+func_odbc_replace=yes # Function REPLACE
+func_odbc_right=yes # Function RIGHT
+func_odbc_round=yes # Function ROUND(2 arg)
+func_odbc_rtrim=yes # Function RTRIM
+func_odbc_second=yes # Function SECOND
+func_odbc_sign=yes # Function SIGN
+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=yes # Function ODBC SUBSTRING
+func_odbc_tan=yes # Function TAN
+func_odbc_timestampadd=yes # Function TIMESTAMPADD
+func_odbc_timestampdiff=yes # Function TIMESTAMPDIFF
+func_odbc_truncate=yes # Function TRUNCATE
+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=yes # Function BIT_LENGTH
+func_sql_cast=yes # Function CAST
+func_sql_char_length=yes # Function CHAR_LENGTH
+func_sql_char_length(constant)=yes # Function CHAR_LENGTH(constant)
+func_sql_character_length=yes # Function CHARACTER_LENGTH
+func_sql_coalesce=yes # 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=yes # Function CURRENT_USER
+func_sql_extract_sql=yes # Function EXTRACT
+func_sql_localtime=yes # Function LOCALTIME
+func_sql_localtimestamp=yes # Function LOCALTIMESTAMP
+func_sql_lower=yes # Function LOWER
+func_sql_nullif=yes # Function NULLIF
+func_sql_octet_length=yes # Function OCTET_LENGTH
+func_sql_position=yes # Function POSITION
+func_sql_searched_case=yes # Function searched CASE
+func_sql_session_user=yes # Function SESSION_USER
+func_sql_simple_case=yes # Function simple CASE
+func_sql_substring=yes # Function ANSI SQL SUBSTRING
+func_sql_system_user=yes # Function SYSTEM_USER
+func_sql_trim=yes # 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_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_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_sum=yes # Group function SUM
+group_functions=yes # Group functions
+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
+index_in_create=no # index in create table
+index_namespace=no # different namespace for index
+index_parts=no # index on column part (extension)
+insert_empty_string=yes # insert empty string
+insert_select=yes # insert INTO ... SELECT ...
+insert_with_set=no # INSERT with set syntax
+intersect=no # intersect
+intersect_all=no # intersect all
+join_tables=+64 # tables in join
+left_outer_join=yes # left outer join
+left_outer_join_using=yes # left outer join using
+like_with_column=yes # 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=10 # big expressions
+max_char_size=15000 # max char() size
+max_column_name=128 # column name length
+max_columns=252 # Columns in table
+max_conditions=1020 # OR and AND in WHERE
+max_expressions=1019 # simple expressions
+max_index=+64 # max index
+max_index_length=+8192 # index length
+max_index_name=128 # index name length
+max_index_part_length=15000 # max index part length
+max_index_parts=32 # index parts
+max_index_varchar_part_length=15000 # index varchar part length
+max_row_length=15925 # max table row length (without blobs)
+max_row_length_with_null=15925 # table row length with nulls (without blobs)
+max_select_alias_name=128 # select alias name length
+max_stack_expression=62 # stacked expressions
+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=15000 # max varchar() size
+minus=no # minus
+minus_neg=no # Calculate 1--1
+multi_drop=no # many tables to drop table
+multi_strings=yes # Multiple line strings
+multi_table_delete=no # DELETE FROM table1,table2...
+multi_table_update=no # Update with many tables
+multi_value_insert=no # Value lists in INSERT
+natural_join=yes # natural join
+natural_left_outer_join=yes # natural left outer join
+no_primary_key=yes # Tables without primary key
+null_concat_expr=yes # Is 'a' || cast(NULL as char(1)) = NULL
+null_in_index=yes # null in index
+null_in_unique=yes # null in unique
+null_num_expr=yes # Is 1+NULL = NULL
+odbc_left_outer_join=yes # left outer join odbc style
+operating_system=Windows NT 4.0 # crash-me tested on
+order_by=yes # Order by
+order_by_alias=yes # 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
+primary_key_in_create=yes # primary key in create table
+psm_functions=yes # PSM functions (ANSI SQL)
+psm_modules=yes # PSM modules (ANSI SQL)
+psm_procedures=yes # PSM procedures (ANSI SQL)
+psm_trigger=yes # 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=15 # recursive subqueries
+remember_end_space=no # Remembers end space in char()
+remember_end_space_varchar=yes # Remembers end space in varchar()
+repeat_string_size=15000 # return string size from function
+right_outer_join=yes # right outer join
+round_on_store=error # Correct rounding when storing float values
+rowid=no # Type for row id
+select_constants=yes # Select constants
+select_limit=no # SELECT with LIMIT
+select_limit2=no # SELECT with LIMIT #,#
+select_string_size=15000 # constant string size in SELECT
+select_table_update=no # Update with sub select
+select_without_from=no # SELECT without FROM
+server_version=MIMER 8.2.0C # server version
+simple_joins=yes # ANSI SQL simple joins
+subqueries=yes # subqueries
+table_alias=yes # Table alias
+table_name_case=yes # case independent table names
+table_wildcard=yes # Select table_name.*
+tempoary_table=no # temporary tables
+transactions=yes # transactions
+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_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_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_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_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=yes # Type bigint
+type_odbc_binary(1_arg)=yes # Type binary(1 arg)
+type_odbc_datetime=no # Type datetime
+type_odbc_tinyint=no # Type tinyint
+type_odbc_varbinary(1_arg)=yes # 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_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=yes # Type interval day
+type_sql_interval_day_to_hour=yes # Type interval day to hour
+type_sql_interval_day_to_minute=yes # Type interval day to minute
+type_sql_interval_day_to_second=yes # Type interval day to second
+type_sql_interval_hour=yes # Type interval hour
+type_sql_interval_hour_to_minute=yes # Type interval hour to minute
+type_sql_interval_hour_to_second=yes # Type interval hour to second
+type_sql_interval_minute=yes # Type interval minute
+type_sql_interval_minute_to_second=yes # Type interval minute to second
+type_sql_interval_month=yes # Type interval month
+type_sql_interval_second=yes # Type interval second
+type_sql_interval_year=yes # Type interval year
+type_sql_interval_year_to_month=yes # 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_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
+unique_in_create=yes # unique in create table
+unique_null_in_create=yes # unique null in create
+views=yes # views
+where_string_size=15000 # constant string size in where
diff --git a/sql-bench/limits/ms-sql.cfg b/sql-bench/limits/ms-sql.cfg
new file mode 100644
index 00000000000..b9cad41c1a1
--- /dev/null
+++ b/sql-bench/limits/ms-sql.cfg
@@ -0,0 +1,506 @@
+#This file is automaticly generated by crash-me 1.45
+
+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=without add # Alter table add many columns
+alter_add_primary_key=with constraint # Alter table add primary key
+alter_add_unique=yes # Alter table add unique
+alter_alter_col=no # Alter table alter column default
+alter_change_col=no # Alter table change column
+alter_drop_col=yes # 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=with constraint # 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
+automatic_rowid=no # Automatic rowid
+binary_numbers=yes # binary numbers (0b1001)
+binary_strings=no # binary strings (b'0110')
+case_insensitive_strings=yes # case insensitive compare
+char_is_space_filled=no # 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
+comment_//=no # // as comment
+compute=yes # Compute
+connections=1000 # Simultaneous connections (installation default)
+constraint_check=no # Column constraints
+constraint_check_table=yes # Table constraints
+constraint_null=yes # NULL constraint (SyBase style)
+crash_me_safe=no # crash me safe
+crash_me_version=1.45 # 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=yes # Create SCHEMA
+create_table_select=no # create table from select
+cross_join=yes # cross join (same as from a,b)
+date_as_string=no # String functions on date columns
+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=with 'table.index' # drop index
+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=yes # foreign keys
+foreign_key_circular=no # Circular foreign keys
+foreign_key_syntax=yes # foreign key syntax
+full_outer_join=yes # full outer join
+func_extra_!=no # Function NOT as '!' in SELECT
+func_extra_%=yes # Function MOD as %
+func_extra_&=yes # 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=yes # Function ATN2
+func_extra_auto_num2string=no # Function automatic num->string convert
+func_extra_auto_string2num=yes # 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=yes # Function CHARINDEX
+func_extra_chr=no # Function CHR
+func_extra_concat_as_+=yes # Function concatenation with +
+func_extra_concat_list=no # Function CONCAT(list)
+func_extra_convert=yes # Function CONVERT
+func_extra_cosh=no # Function COSH
+func_extra_date_format=no # Function DATE_FORMAT
+func_extra_dateadd=yes # Function DATEADD
+func_extra_datediff=yes # Function DATEDIFF
+func_extra_datename=yes # Function DATENAME
+func_extra_datepart=yes # Function DATEPART
+func_extra_elt=no # Function ELT
+func_extra_encrypt=yes # 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=yes # 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=yes # 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=yes # Function REPLICATE
+func_extra_reverse=yes # 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=yes # Function STR
+func_extra_strcmp=no # Function STRCMP
+func_extra_stuff=yes # 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_|=yes # Function | (bitwise or)
+func_extra_||=no # Function OR as '||'
+func_odbc_abs=yes # Function ABS
+func_odbc_acos=yes # Function ACOS
+func_odbc_ascii=yes # Function ASCII
+func_odbc_asin=yes # Function ASIN
+func_odbc_atan=yes # Function ATAN
+func_odbc_atan2=yes # Function ATAN2
+func_odbc_ceiling=yes # Function CEILING
+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=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_floor=yes # Function FLOOR
+func_odbc_fn_left=yes # Function ODBC syntax LEFT & RIGHT
+func_odbc_hour=yes # Function HOUR
+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=error # Function REAL 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
+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=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=yes # Function QUARTER
+func_odbc_radians=error # Function RADIANS
+func_odbc_rand=yes # Function RAND
+func_odbc_repeat=yes # Function REPEAT
+func_odbc_replace=yes # Function REPLACE
+func_odbc_right=yes # Function RIGHT
+func_odbc_round=yes # Function ROUND(2 arg)
+func_odbc_rtrim=yes # Function RTRIM
+func_odbc_second=yes # Function SECOND
+func_odbc_sign=yes # Function SIGN
+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=yes # Function ODBC SUBSTRING
+func_odbc_tan=yes # Function TAN
+func_odbc_timestampadd=error # Function TIMESTAMPADD
+func_odbc_timestampdiff=error # Function TIMESTAMPDIFF
+func_odbc_truncate=yes # Function TRUNCATE
+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_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=yes # Function COALESCE
+func_sql_concat_as_||=no # 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=yes # 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=yes # Function NULLIF
+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=yes # Function SESSION_USER
+func_sql_simple_case=yes # Function simple CASE
+func_sql_substring=no # Function ANSI SQL SUBSTRING
+func_sql_system_user=yes # 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_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_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_sum=yes # Group function SUM
+group_functions=yes # Group functions
+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=yes # 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_select=yes # 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=yes # column LIKE column
+like_with_number=yes # LIKE on numbers
+lock_tables=no # lock table
+logical_value=not supported # Value of logical operation (1=1)
+max_big_expressions=7 # big expressions
+max_char_size=8000 # max char() size
+max_column_name=128 # column name length
+max_columns=1024 # Columns in table
+max_conditions=10922 # OR and AND in WHERE
+max_expressions=2783 # simple expressions
+max_index=+64 # max index
+max_index_length=900 # index length
+max_index_name=128 # index name length
+max_index_part_length=900 # max index part length
+max_index_parts=16 # index parts
+max_index_varchar_part_length=900 # index varchar part length
+max_row_length=8036 # max table row length (without blobs)
+max_row_length_with_null=8036 # table row length with nulls (without blobs)
+max_select_alias_name=128 # select alias name length
+max_stack_expression=164 # stacked expressions
+max_table_alias_name=128 # table alias name length
+max_table_name=128 # table name length
+max_text_size=+8000000 # max text or blob size
+max_unique_index=+64 # unique indexes
+max_varchar_size=8000 # max varchar() size
+minus=yes # minus
+minus_incompat=yes # 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
+multi_value_insert=no # Value lists in INSERT
+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 concat('a',NULL) = NULL
+null_in_index=yes # null in index
+null_in_unique=no # null in unique index
+null_num_expr=yes # Is 1+NULL = NULL
+odbc_left_outer_join=yes # left outer join odbc style
+operating_system=Microsoft Windows 2000 [Version 5.00.2195] # 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
+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_[=yes # [] as identifier quote
+quote_ident_with_`=no # ` as identifier quote
+quote_with_"=no # Allows ' and " as string markers
+recursive_subqueries=40 # recursive subqueries
+remember_end_space=no # Remembers end space in char()
+remember_end_space_varchar=yes # Remembers end space in varchar()
+repeat_string_size=8000 # return string size from function
+right_outer_join=yes # right outer join
+rowid=no # Type for row id
+select_constants=yes # Select constants
+select_limit=with TOP # LIMIT number of rows
+select_limit2=no # SELECT with LIMIT #,#
+select_string_size=16777207 # constant string size in SELECT
+select_table_update=yes # Update with sub select
+select_without_from=yes # SELECT without FROM
+server_version=Microsoft SQL Server 7.00 - 7.00.842 (Intel X86) # server version
+simple_joins=yes # ANSI SQL simple joins
+storage_of_float=round # 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.*
+tempoary_table=no # temporary tables
+transactions=yes # transactions
+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_circle=no # Type circle
+type_extra_clob=no # Type clob
+type_extra_datetime=yes # 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=yes # Type image
+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=yes # 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_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=yes # 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=yes # Type smalldatetime
+type_extra_smallfloat=no # Type smallfloat
+type_extra_smallmoney=yes # Type smallmoney
+type_extra_text=yes # 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)=yes # Type binary(1 arg)
+type_odbc_datetime=yes # Type datetime
+type_odbc_tinyint=yes # Type tinyint
+type_odbc_varbinary(1_arg)=yes # Type varbinary(1 arg)
+type_sql_bit=yes # 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_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=yes # views
+where_string_size=8000 # constant string size in where
diff --git a/sql-bench/limits/ms-sql65.cfg b/sql-bench/limits/ms-sql65.cfg
new file mode 100644
index 00000000000..488ce14d992
--- /dev/null
+++ b/sql-bench/limits/ms-sql65.cfg
@@ -0,0 +1,418 @@
+#This file is automaticly generated by crash-me 1.19a
+
+NEG=yes # update of column= -column
+alter_add_col=yes # Alter table add column
+alter_change_col=no # Alter table change column
+alter_drop_col=no # Alter table drop column
+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=yes # binary items (0x41)
+case_insensitive_strings=yes # case insensitive compare
+char_is_space_filled=no # char are space filled
+column_alias=yes # Column alias
+comment_#=no # # as comment
+comment_--=yes # -- as comment
+comment_/**/=yes # /* */ as comment
+compute=yes # Compute
+connections=14 # Simultaneous connections
+crash_me_safe=no # crash me safe
+crash_me_version=1.19a # crash me version
+create_default=yes # default value for column
+create_index=no # create index
+cross_join=yes # cross join (same as from a,b)
+date_as_string=no # String functions on date columns
+date_with_YY=no # Supports YY-MM-DD dates
+date_zero=no # Supports 0000-00-00 dates
+double_quotes=yes # Double '' as ' in strings
+drop_index=no # drop index
+except=no # except
+except_all=no # except all
+float_int_expr=yes # mixing of integer and float in expression
+foreign_key=yes # foreign keys
+foreign_key_syntax=yes # foreign key syntax
+full_outer_join=yes # full outer join
+func_extra_!=no # Function NOT as '!' in SELECT
+func_extra_%=yes # Function MOD as %
+func_extra_&=yes # 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_atn2=yes # 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=yes # Function CHARINDEX
+func_extra_chr=no # Function CHR
+func_extra_concat_as_+=yes # Function concatenation with +
+func_extra_concat_list=no # Function CONCAT(list)
+func_extra_convert=yes # Function CONVERT
+func_extra_cosh=no # Function COSH
+func_extra_date_format=no # Function DATE_FORMAT
+func_extra_dateadd=yes # Function DATEADD
+func_extra_datediff=yes # Function DATEDIFF
+func_extra_datename=yes # Function DATENAME
+func_extra_datepart=yes # Function DATEPART
+func_extra_elt=no # Function ELT
+func_extra_encrypt=yes # 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=yes # 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_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_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_patindex=yes # 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=yes # Function REPLICATE
+func_extra_reverse=yes # 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=yes # Function STR
+func_extra_strcmp=no # Function STRCMP
+func_extra_stuff=yes # Function STUFF
+func_extra_substrb=no # Function SUBSTRB
+func_extra_substring_index=no # Function SUBSTRING_INDEX
+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_|=yes # Function | (bitwise or)
+func_extra_||=no # Function OR as '||'
+func_odbc_abs=yes # Function ABS
+func_odbc_acos=yes # Function ACOS
+func_odbc_ascii=yes # Function ASCII
+func_odbc_asin=yes # Function ASIN
+func_odbc_atan=yes # Function ATAN
+func_odbc_atan2=no # Function ATAN2
+func_odbc_ceiling=yes # Function CEILING
+func_odbc_char=yes # Function CHAR
+func_odbc_concat=no # 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_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=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=yes # Function LOG
+func_odbc_log10=yes # Function LOG10
+func_odbc_ltrim=yes # 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=yes # Function PI
+func_odbc_power=yes # Function POWER
+func_odbc_quarter=no # Function QUARTER
+func_odbc_radians=error # Function RADIANS
+func_odbc_rand=yes # Function RAND
+func_odbc_repeat=no # Function REPEAT
+func_odbc_replace=no # Function REPLACE
+func_odbc_right=yes # Function RIGHT
+func_odbc_round=yes # Function ROUND(2 arg)
+func_odbc_rtrim=yes # Function RTRIM
+func_odbc_second=no # Function SECOND
+func_odbc_sign=yes # Function SIGN
+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=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=no # 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_sql_+=yes # Function +, -, * and /
+func_sql_bit_length=no # Function BIT_LENGTH
+func_sql_case=yes # Function CASE
+func_sql_cast=no # Function CAST
+func_sql_char_length=no # Function CHAR_LENGTH
+func_sql_character_length=no # Function CHARACTER_LENGTH
+func_sql_concat_as_||=no # 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=yes # Function CURRENT_TIMESTAMP
+func_sql_current_timestamp()=no # Function CURRENT_TIMESTAMP()
+func_sql_lower=yes # Function LOWER
+func_sql_octet_length=no # Function OCTET_LENGTH
+func_sql_position=no # Function POSITION
+func_sql_session_user=no # Function SESSION_USER
+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=yes # Function UPPER
+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 # Test nulls in group by
+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_std=no # Group function STD
+group_func_extra_stddev=no # Group function STDDEV
+group_func_extra_variance=no # Group function VARIANCE
+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_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_sum=yes # Group function SUM
+group_functions=yes # Group functions
+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
+index_in_create=no # index in create table
+insert_empty_string=yes # insert empty string
+insert_select=yes # insert INTO ... SELECT ...
+intersect=no # intersect
+intersect_all=no # intersect all
+join_tables=16 # tables in join
+left_outer_join=yes # left outer join
+left_outer_join_using=no # left outer join using
+like_with_column=yes # 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=4 # big expressions
+max_char_size=255 # max char() size
+max_column_name=30 # column name length
+max_columns=250 # Columns in table
+max_conditions=3144 # OR and AND in WHERE
+max_expressions=6972 # simple expressions
+max_index_length=900 # index length
+max_index_part_length=255 # max index part length
+max_index_parts=15 # index parts
+max_index_varchar_part_length=255 # index varchar part length
+max_row_length=1960 # max table row length (without blobs)
+max_row_length_with_null=1942 # table row length with nulls (without blobs)
+max_select_alias_name=30 # select alias name length
+max_stack_expression=97 # stacked expressions
+max_table_alias_name=30 # table alias name length
+max_table_name=30 # table name length
+max_text_size=65505 # max text or blob size
+max_unique_index=+64 # unique indexes
+max_varchar_size=255 # max varchar() size
+minus=yes # minus
+minus_neg=no # Calculate 1--1
+multi_drop=yes # 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_left_outer_join=no # natural left outer join
+no_primary_key=yes # Tables without primary key
+null_concat_expr=error # Is 'a' + NULL = NULL
+null_in_index=yes # null in index
+null_in_unique=yes # null in unique
+null_num_expr=yes # Is 1+NULL = NULL
+odbc_left_outer_join=yes # left outer join odbc style
+operating_system=Windows NT Version 4.0 # crash-me tested on
+order_by=yes # Order by
+order_by_alias=yes # Order by alias
+order_by_position=yes # Order by position
+primary_key_in_create=yes # primary key in create table
+query_size=16777216 # query size
+quote_with_"=no # Allows ' and " as string markers
+recursive_subqueries=15 # recursive subqueries
+remember_end_space=no # Remembers end space in char()
+remember_end_space_varchar=no # Remembers end space in varchar()
+right_outer_join=yes # right outer join
+select_constants=yes # Select constants
+select_string_size=65527 # constant string size in SELECT
+select_table_update=yes # Update with sub select
+select_without_from=yes # SELECT without FROM
+server_version=Microsoft SQL server 6.5 # server version
+simple_joins=yes # ANSI SQL simple joins
+subqueries=yes # subqueries
+table_alias=yes # Table alias
+table_wildcard=yes # Select table_name.*
+transactions=yes # transactions
+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_circle=no # Type circle
+type_extra_clob=no # Type clob
+type_extra_datetime=yes # Type datetime
+type_extra_enum(1_arg)=no # Type enum(1 arg)
+type_sql_float(1_arg)=yes # Type float(1 arg)
+type_extra_float4=no # Type float4
+type_extra_float8=no # Type float8
+type_extra_image=yes # Type image
+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_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_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=yes # 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_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=yes # Type smalldatetime
+type_extra_smallfloat=no # Type smallfloat
+type_extra_smallmoney=yes # Type smallmoney
+type_extra_text=yes # Type text
+type_extra_text(1_arg)=no # Type text(1 arg)
+type_extra_timespan=no # Type timespan
+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)=yes # Type binary(1 arg)
+type_odbc_datetime=yes # Type datetime
+type_sql_smallint=yes # Type smallint
+type_odbc_tinyint=yes # Type tinyint
+type_odbc_varbinary(1_arg)=yes # Type varbinary(1 arg)
+type_sql_bit=yes # 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_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_extra_double=no # Type double
+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_int=yes # Type int
+type_sql_integer=yes # Type integer
+type_sql_interval_year=no # Type interval year
+type_sql_numeric(2_arg)=yes # Type numeric(2 arg)
+type_sql_real=yes # Type real
+type_sql_time=no # Type time
+type_sql_timestamp=yes # Type timestamp
+type_sql_varchar(1_arg)=yes # Type varchar(1 arg)
+union=yes # union
+union_all=yes # union all
+unique_in_create=yes # unique in create table
+unique_null_in_create=no # unique null in create
+views=yes # views
+where_string_size=255 # constant string size in where
diff --git a/sql-bench/limits/msql.cfg b/sql-bench/limits/msql.cfg
new file mode 100644
index 00000000000..028eb4cd399
--- /dev/null
+++ b/sql-bench/limits/msql.cfg
@@ -0,0 +1,227 @@
+#This file is automaticly generated by crash-me 1.32
+
+NEG=no # update of column= -column
+alter_add_col=no # Alter table add column
+alter_add_multi_col=no # Alter table add many columns
+alter_alter_col=no # Alter table alter column
+alter_change_col=no # Alter table change column
+alter_drop_col=no # Alter table drop column
+alter_modify_col=no # Alter table modify column
+alter_rename_table=no # Alter table rename table
+atomic_updates=no # atomic updates
+binary_items=no # binary items (0x41)
+case_insensitive_strings=no # case insensitive compare
+column_alias=no # Column alias
+columns_in_order_by=+64 # number of columns in order by
+comment_#=yes # # as comment
+comment_--=no # -- as comment
+comment_/**/=no # /* */ as comment
+compute=no # Compute
+connections=200 # Simultaneous connections
+crash_me_safe=yes # crash me safe
+crash_me_version=1.32 # crash me version
+create_default=no # 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_table_select=no # create table from select
+cross_join=no # cross join (same as from a,b)
+date_with_YY=no # Supports YY-MM-DD dates
+date_zero=no # Supports 0000-00-00 dates
+double_quotes=no # Double '' as ' in strings
+drop_if_exists=no # drop table if exists
+drop_index=with 'FROM' # drop index
+end_colon=no # allows end ';'
+except=no # except
+except_all=no # except all
+foreign_key_syntax=no # foreign key syntax
+full_outer_join=no # full outer join
+func_where_between=no # Function BETWEEN
+func_where_eq_all=no # Function = ALL
+func_where_eq_any=no # Function = ANY
+func_where_eq_some=no # Function = SOME
+func_where_exists=no # Function EXISTS
+func_where_in_num=no # Function IN on numbers
+func_where_like=yes # Function LIKE
+func_where_like_escape=no # 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=no # Function NOT BETWEEN
+func_where_not_exists=no # 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=no # Functions
+group_by=no # Group by
+group_by_alias=no # Group by alias
+group_by_null=no # group on column with null values
+group_by_position=no # Group by position
+group_distinct_functions=no # Group functions with distinct
+group_functions=no # Group functions
+having=no # Having
+having_with_alias=no # Having with alias
+having_with_group=no # Having with group function
+ignore_end_space=no # ignore end space in compare
+index_in_create=no # index in create table
+index_namespace=yes # different namespace for index
+index_parts=no # index on column part (extension)
+insert_empty_string=yes # insert empty string
+insert_select=no # insert INTO ... SELECT ...
+insert_with_set=no # INSERT with set syntax
+intersect=no # intersect
+intersect_all=no # intersect all
+join_tables=+64 # tables in join
+left_outer_join=no # left outer join
+left_outer_join_using=no # left outer join using
+like_with_column=yes # 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_char_size=131038 # max char() size
+max_columns=75 # Columns in table
+max_conditions=72 # OR and AND in WHERE
+max_index=+64 # max index
+max_index_length=+8192 # index length
+max_index_name=35 # index name length
+max_index_part_length=+8192 # index part length
+max_index_parts=9 # index parts
+max_row_length=19125 # max table row length (without blobs)
+max_row_length_with_null=19125 # table row length with nulls (without blobs)
+max_table_alias_name=34 # table alias name length
+max_table_name=35 # table name length
+max_unique_index=+64 # max unique index
+minus=no # minus
+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
+multi_value_insert=no # Value lists in INSERT
+natural_join=no # natural join
+natural_left_outer_join=no # natural left outer join
+no_primary_key=yes # Tables without primary key
+null_in_index=no # null in index
+odbc_left_outer_join=no # left outer join odbc style
+operating_system=Linux 2.2.10 i686 # crash-me tested on
+order_by=yes # Order by
+order_by_function=no # Order by function
+order_by_position=no # Order by position
+order_by_remember_desc=no # Order by DESC is remembered
+primary_key_in_create=no # primary key in create table
+query_size=131069 # query size
+quote_with_"=no # Allows ' and " as string markers
+remember_end_space=yes # Remembers end space in char()
+remember_end_space_varchar=no # Remembers end space in varchar()
+right_outer_join=no # right outer join
+rowid=no # Type for row id
+select_constants=no # Select constants
+select_limit=yes # SELECT with LIMIT
+select_limit2=no # SELECT with LIMIT #,#
+select_table_update=no # Update with sub select
+select_without_from=no # SELECT without FROM
+server_version=mSQL server version 2.0.11 # server version
+simple_joins=yes # ANSI SQL simple joins
+subqueries=no # subqueries
+table_alias=yes # Table alias
+table_name_case=no # case independent table names
+table_wildcard=no # Select table_name.*
+tempoary_table=no # temporary tables
+transactions=no # transactions
+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_circle=no # Type circle
+type_extra_clob=no # Type clob
+type_extra_datetime=no # Type datetime
+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_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_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_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=yes # 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)=yes # Type text(1 arg)
+type_extra_timespan=no # Type timespan
+type_extra_uint=yes # Type uint
+type_extra_varchar2(1_arg)=no # Type varchar2(1 arg)
+type_extra_year=no # Type year
+type_odbc_bigint=yes # Type bigint
+type_odbc_binary(1_arg)=no # Type binary(1 arg)
+type_odbc_datetime=no # Type datetime
+type_odbc_tinyint=yes # 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)=no # Type char varying(1 arg)
+type_sql_character(1_arg)=yes # Type character(1 arg)
+type_sql_character_varying(1_arg)=no # Type character varying(1 arg)
+type_sql_date=yes # Type date
+type_sql_dec(2_arg)=no # Type dec(2 arg)
+type_sql_decimal(2_arg)=no # Type decimal(2 arg)
+type_sql_double_precision=no # Type double precision
+type_sql_float=yes # Type float
+type_sql_float(1_arg)=no # Type float(1 arg)
+type_sql_int=yes # Type int
+type_sql_integer=yes # Type integer
+type_sql_interval_day_to_second=no # Type interval day to 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)=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_numeric(2_arg)=no # 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=no # Type timestamp
+type_sql_timestamp_with_time_zone=no # Type timestamp with time zone
+type_sql_varchar(1_arg)=no # Type varchar(1 arg)
+union=no # union
+union_all=no # union all
+unique_in_create=no # unique in create table
+views=no # views
+where_string_size=131035 # constant string size in where
diff --git a/sql-bench/limits/mysql-3.22.cfg b/sql-bench/limits/mysql-3.22.cfg
new file mode 100644
index 00000000000..6f0ee740c5a
--- /dev/null
+++ b/sql-bench/limits/mysql-3.22.cfg
@@ -0,0 +1,452 @@
+#This file is automaticly generated by crash-me 1.36
+
+NEG=yes # update of column= -column
+alter_add_col=yes # Alter table add column
+alter_add_multi_col=yes # Alter table add many columns
+alter_alter_col=yes # Alter table alter column
+alter_change_col=yes # Alter table change column
+alter_drop_col=yes # Alter table drop column
+alter_modify_col=yes # Alter table modify column
+alter_rename_table=yes # Alter table rename table
+atomic_updates=no # atomic updates
+binary_items=yes # binary items (0x41)
+case_insensitive_strings=yes # case insensitive compare
+char_is_space_filled=no # 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_#=yes # # as comment
+comment_--=no # -- as comment
+comment_/**/=yes # /* */ as comment
+comment_//=no # // as comment
+compute=no # Compute
+connections=101 # Simultaneous connections
+constraint_check=no # CHECK constraint
+constraint_null=yes # NULL constraint (SyBase style)
+crash_me_safe=yes # crash me safe
+crash_me_version=1.36 # 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_table_select=no # create table from select
+cross_join=yes # cross join (same as from a,b)
+date_as_string=yes # String functions on date columns
+date_with_YY=yes # Supports YY-MM-DD 2000 compilant dates
+date_zero=yes # Supports 0000-00-00 dates
+double_quotes=yes # Double '' as ' in strings
+drop_if_exists=yes # drop table if exists
+drop_index=with 'ON' # drop index
+end_colon=yes # allows end ';'
+except=no # except
+except_all=no # except all
+float_int_expr=yes # mixing of integer and float in expression
+foreign_key=no # foreign keys
+foreign_key_syntax=yes # foreign key syntax
+full_outer_join=no # full outer join
+func_extra_!=yes # Function NOT as '!' in SELECT
+func_extra_%=yes # Function MOD as %
+func_extra_&=yes # Function & (bitwise and)
+func_extra_&&=yes # Function AND as '&&'
+func_extra_<>=yes # Function <> in SELECT
+func_extra_==yes # Function =
+func_extra_add_months=no # Function ADD_MONTHS
+func_extra_and_or=yes # Function AND and OR in SELECT
+func_extra_atn2=no # Function ATN2
+func_extra_auto_num2string=yes # Function automatic num->string convert
+func_extra_auto_string2num=yes # Function automatic string->num convert
+func_extra_between=yes # Function BETWEEN in SELECT
+func_extra_binary_shifts=yes # Function << and >> (bitwise shifts)
+func_extra_bit_count=yes # Function BIT_COUNT
+func_extra_ceil=no # Function CEIL
+func_extra_charindex=no # Function CHARINDEX
+func_extra_chr=no # Function CHR
+func_extra_coalesce=no # Function COALESCE
+func_extra_concat_as_+=error # Function concatenation with +
+func_extra_concat_list=yes # Function CONCAT(list)
+func_extra_convert=no # Function CONVERT
+func_extra_cosh=no # Function COSH
+func_extra_date_format=yes # 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=yes # Function ELT
+func_extra_encrypt=yes # Function ENCRYPT
+func_extra_field=yes # Function FIELD
+func_extra_format=yes # Function FORMAT
+func_extra_from_days=yes # Function FROM_DAYS
+func_extra_from_unixtime=yes # Function FROM_UNIXTIME
+func_extra_getdate=no # Function GETDATE
+func_extra_greatest=yes # Function GREATEST
+func_extra_if=yes # Function IF
+func_extra_in_num=yes # Function IN on numbers in SELECT
+func_extra_in_str=yes # Function IN on strings in SELECT
+func_extra_initcap=no # Function INITCAP
+func_extra_instr=yes # Function LOCATE as INSTR
+func_extra_instr_oracle=no # Function INSTR (Oracle syntax)
+func_extra_instrb=no # Function INSTRB
+func_extra_interval=yes # Function INTERVAL
+func_extra_last_day=no # Function LAST_DAY
+func_extra_last_insert_id=yes # Function LAST_INSERT_ID
+func_extra_least=yes # Function LEAST
+func_extra_lengthb=no # Function LENGTHB
+func_extra_like=yes # Function LIKE in SELECT
+func_extra_like_escape=yes # 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=yes # Function LPAD
+func_extra_mdy=no # Function MDY
+func_extra_mid=yes # Function SUBSTRING as MID
+func_extra_months_between=no # Function MONTHS_BETWEEN
+func_extra_not=yes # Function NOT in SELECT
+func_extra_not_between=yes # Function NOT BETWEEN in SELECT
+func_extra_not_like=yes # Function NOT LIKE in SELECT
+func_extra_odbc_convert=no # Function ODBC CONVERT
+func_extra_password=yes # Function PASSWORD
+func_extra_patindex=no # Function PATINDEX
+func_extra_period_add=yes # Function PERIOD_ADD
+func_extra_period_diff=yes # Function PERIOD_DIFF
+func_extra_pow=yes # Function POW
+func_extra_range=no # Function RANGE
+func_extra_regexp=yes # Function REGEXP in SELECT
+func_extra_replicate=no # Function REPLICATE
+func_extra_reverse=yes # Function REVERSE
+func_extra_root=no # Function ROOT
+func_extra_round1=yes # Function ROUND(1 arg)
+func_extra_rpad=yes # Function RPAD
+func_extra_sec_to_time=yes # Function SEC_TO_TIME
+func_extra_sinh=no # Function SINH
+func_extra_str=no # Function STR
+func_extra_strcmp=yes # Function STRCMP
+func_extra_stuff=no # Function STUFF
+func_extra_substrb=no # Function SUBSTRB
+func_extra_substring_index=yes # Function SUBSTRING_INDEX
+func_extra_sysdate=yes # Function SYSDATE
+func_extra_tanh=no # Function TANH
+func_extra_time_to_sec=yes # Function TIME_TO_SEC
+func_extra_to_days=yes # Function TO_DAYS
+func_extra_translate=no # Function TRANSLATE
+func_extra_trim_many_char=error # Function TRIM; Many char extension
+func_extra_trim_substring=yes # Function TRIM; Substring extension
+func_extra_trunc=no # Function TRUNC
+func_extra_uid=no # Function UID
+func_extra_unix_timestamp=yes # Function UNIX_TIMESTAMP
+func_extra_userenv=no # Function USERENV
+func_extra_version=yes # Function VERSION
+func_extra_weekday=yes # Function WEEKDAY
+func_extra_|=yes # Function | (bitwise or)
+func_extra_||=yes # Function OR as '||'
+func_odbc_abs=yes # Function ABS
+func_odbc_acos=yes # Function ACOS
+func_odbc_ascii=yes # Function ASCII
+func_odbc_asin=yes # Function ASIN
+func_odbc_atan=yes # Function ATAN
+func_odbc_atan2=yes # Function ATAN2
+func_odbc_ceiling=yes # Function CEILING
+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=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=no # 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=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_locate_2=yes # Function LOCATE(2 arg)
+func_odbc_locate_3=yes # Function LOCATE(3 arg)
+func_odbc_log=yes # Function LOG
+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=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=yes # Function QUARTER
+func_odbc_radians=yes # Function RADIANS
+func_odbc_rand=yes # Function RAND
+func_odbc_repeat=yes # Function REPEAT
+func_odbc_replace=yes # Function REPLACE
+func_odbc_right=yes # Function RIGHT
+func_odbc_round=yes # Function ROUND(2 arg)
+func_odbc_rtrim=yes # Function RTRIM
+func_odbc_second=yes # Function SECOND
+func_odbc_sign=yes # Function SIGN
+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=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=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=no # Function CASE
+func_sql_cast=no # Function CAST
+func_sql_char_length=yes # Function CHAR_LENGTH
+func_sql_char_length(constant)=yes # Function CHAR_LENGTH(constant)
+func_sql_character_length=yes # Function CHARACTER_LENGTH
+func_sql_concat_as_||=error # 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_lower=yes # Function LOWER
+func_sql_octet_length=yes # Function OCTET_LENGTH
+func_sql_position=yes # Function POSITION
+func_sql_session_user=no # Function SESSION_USER
+func_sql_substring=yes # Function ANSI SQL SUBSTRING
+func_sql_system_user=no # Function SYSTEM_USER
+func_sql_trim=yes # Function TRIM
+func_sql_upper=yes # Function UPPER
+func_sql_user=no # Function USER
+func_where_between=yes # Function BETWEEN
+func_where_eq_all=no # Function = ALL
+func_where_eq_any=no # Function = ANY
+func_where_eq_some=no # Function = SOME
+func_where_exists=no # 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=no # 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=yes # Group by alias
+group_by_null=yes # group on column with null values
+group_by_position=yes # Group by position
+group_distinct_functions=no # Group functions with distinct
+group_func_extra_bit_and=yes # Group function BIT_AND
+group_func_extra_bit_or=yes # Group function BIT_OR
+group_func_extra_count_distinct_list=no # Group function COUNT(DISTINCT expr,expr,...)
+group_func_extra_std=yes # Group function STD
+group_func_extra_stddev=yes # Group function STDDEV
+group_func_extra_variance=no # Group function VARIANCE
+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=no # Group function COUNT(DISTINCT expr)
+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_sum=yes # Group function SUM
+group_functions=yes # Group functions
+having=yes # Having
+having_with_alias=yes # Having on alias
+having_with_group=yes # Having with group function
+ignore_end_space=yes # ignore end space in compare
+index_in_create=yes # index in create table
+index_namespace=yes # different namespace for index
+index_parts=yes # index on column part (extension)
+insert_empty_string=yes # insert empty string
+insert_select=yes # insert INTO ... SELECT ...
+insert_with_set=yes # INSERT with set syntax
+intersect=no # intersect
+intersect_all=no # intersect all
+join_tables=32 # tables in join
+left_outer_join=yes # left outer join
+left_outer_join_using=yes # left outer join using
+like_with_column=yes # column LIKE column
+like_with_number=yes # LIKE on numbers
+lock_tables=yes # lock table
+logical_value=1 # Value of logical operation (1=1)
+max_big_expressions=10 # big expressions
+max_char_size=255 # max char() size
+max_column_name=64 # column name length
+max_columns=2364 # Columns in table
+max_conditions=85660 # OR and AND in WHERE
+max_expressions=1392 # simple expressions
+max_index=16 # max index
+max_index_length=256 # index length
+max_index_name=64 # index name length
+max_index_part_length=255 # max index part length
+max_index_parts=16 # index parts
+max_index_varchar_part_length=255 # index varchar part length
+max_row_length=65534 # max table row length (without blobs)
+max_row_length_with_null=65501 # table row length with nulls (without blobs)
+max_select_alias_name=+512 # select alias name length
+max_stack_expression=1392 # stacked expressions
+max_table_alias_name=+512 # table alias name length
+max_table_name=64 # table name length
+max_text_size=1048543 # max text or blob size
+max_unique_index=16 # unique indexes
+max_varchar_size=255 # max varchar() size
+minus=no # minus
+minus_neg=yes # Calculate 1--1
+multi_drop=yes # many tables to drop table
+multi_strings=yes # Multiple line strings
+multi_table_delete=no # DELETE FROM table1,table2...
+multi_table_update=no # Update with many tables
+multi_value_insert=yes # Value lists in INSERT
+natural_join=no # natural join
+natural_left_outer_join=yes # natural left outer join
+no_primary_key=yes # Tables without primary key
+null_concat_expr=yes # Is concat('a',NULL) = NULL
+null_in_index=no # null in index
+null_in_unique=no # null in unique
+null_num_expr=yes # Is 1+NULL = NULL
+odbc_left_outer_join=yes # left outer join odbc style
+operating_system=Linux 2.2.13-my-SMP i686 # crash-me tested on
+order_by=yes # Order by
+order_by_alias=yes # 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
+primary_key_in_create=yes # primary key in create table
+query_size=1048574 # query size
+quote_ident_with_"=error # " as identifier quote (ANSI SQL)
+quote_ident_with_[=no # [] as identifier quote
+quote_ident_with_`=no # ` as identifier quote
+quote_with_"=yes # Allows ' and " as string markers
+remember_end_space=no # Remembers end space in char()
+remember_end_space_varchar=no # Remembers end space in varchar()
+repeat_string_size=1048576 # return string size from function
+right_outer_join=no # right outer join
+round_on_store=yes # Correct rounding when storing float values
+rowid=auto_increment # Type for row id
+select_constants=yes # Select constants
+select_limit=yes # SELECT with LIMIT
+select_limit2=yes # SELECT with LIMIT #,#
+select_string_size=1048565 # constant string size in SELECT
+select_table_update=no # Update with sub select
+select_without_from=yes # SELECT without FROM
+server_version=MySQL 3.22.29 debug # server version
+simple_joins=yes # ANSI SQL simple joins
+subqueries=no # subqueries
+table_alias=yes # Table alias
+table_name_case=no # case independent table names
+table_wildcard=yes # Select table_name.*
+tempoary_table=no # temporary tables
+transactions=no # transactions
+type_extra_abstime=no # Type abstime
+type_extra_bfile=no # Type bfile
+type_extra_blob=yes # Type blob
+type_extra_bool=yes # Type bool
+type_extra_box=no # Type box
+type_extra_byte=no # Type byte
+type_extra_char(1_arg)_binary=yes # Type char(1 arg) binary
+type_extra_circle=no # Type circle
+type_extra_clob=no # Type clob
+type_extra_datetime=yes # Type datetime
+type_extra_double=yes # Type double
+type_extra_enum(1_arg)=yes # Type enum(1 arg)
+type_extra_float(2_arg)=yes # Type float(2 arg)
+type_extra_float4=yes # Type float4
+type_extra_float8=yes # Type float8
+type_extra_image=no # Type image
+type_extra_int(1_arg)_zerofill=yes # Type int(1 arg) zerofill
+type_extra_int1=yes # Type int1
+type_extra_int2=yes # Type int2
+type_extra_int3=yes # Type int3
+type_extra_int4=yes # Type int4
+type_extra_int8=yes # Type int8
+type_extra_int_auto_increment=yes # Type int not null auto_increment
+type_extra_int_unsigned=yes # 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=yes # Type long varbinary
+type_extra_long_varchar(1_arg)=no # Type long varchar(1 arg)
+type_extra_lseg=no # Type lseg
+type_extra_mediumint=yes # Type mediumint
+type_extra_mediumtext=yes # Type mediumtext
+type_extra_middleint=yes # 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)=yes # 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=yes # 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=yes # Type year
+type_odbc_bigint=yes # Type bigint
+type_odbc_binary(1_arg)=yes # Type binary(1 arg)
+type_odbc_datetime=yes # Type datetime
+type_odbc_tinyint=yes # Type tinyint
+type_odbc_varbinary(1_arg)=yes # Type varbinary(1 arg)
+type_sql_bit=yes # 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_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_to_second=no # Type interval day to 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)=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_timestamp_with_time_zone=no # Type timestamp with time zone
+type_sql_varchar(1_arg)=yes # Type varchar(1 arg)
+union=no # union
+union_all=no # union all
+unique_in_create=yes # unique in create table
+unique_null_in_create=no # unique null in create
+views=no # views
+where_string_size=1048540 # constant string size in where
diff --git a/sql-bench/limits/mysql-3.23.cfg b/sql-bench/limits/mysql-3.23.cfg
new file mode 100644
index 00000000000..aebb879a574
--- /dev/null
+++ b/sql-bench/limits/mysql-3.23.cfg
@@ -0,0 +1,511 @@
+#This file is automaticly generated by crash-me 1.47
+
+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=yes # Alter table add many columns
+alter_add_primary_key=with constraint # Alter table add primary key
+alter_add_unique=yes # Alter table add unique
+alter_alter_col=yes # Alter table alter column default
+alter_change_col=yes # Alter table change column
+alter_drop_col=yes # Alter table drop column
+alter_drop_constraint=no # Alter table drop constraint
+alter_drop_foreign_key=with drop foreign key # Alter table drop foreign key
+alter_drop_primary_key=drop primary key # Alter table drop primary key
+alter_drop_unique=with drop key # Alter table drop unique
+alter_modify_col=yes # Alter table modify column
+alter_rename_table=yes # Alter table rename table
+atomic_updates=no # atomic updates
+automatic_rowid=_rowid # Automatic rowid
+binary_numbers=no # binary numbers (0b1001)
+binary_strings=no # binary strings (b'0110')
+case_insensitive_strings=yes # case insensitive compare
+char_is_space_filled=no # 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_#=yes # # as comment
+comment_--=yes # -- as comment
+comment_/**/=yes # /* */ as comment
+comment_//=no # // as comment
+compute=no # Compute
+connections=30 # Simultaneous connections (installation default)
+constraint_check=no # Column constraints
+constraint_check_table=no # Table constraints
+constraint_null=yes # NULL constraint (SyBase style)
+crash_me_safe=no # crash me safe
+crash_me_version=1.47 # crash me version
+create_default=yes # default value for column
+create_default_func=no # default value function for column
+create_if_not_exists=yes # create table if not exists
+create_index=yes # create index
+create_schema=no # Create SCHEMA
+create_table_select=yes # create table from select
+cross_join=yes # cross join (same as from a,b)
+date_as_string=yes # String functions on date columns
+date_infinity=error # Supports 'infinity dates
+date_last=yes # Supports 9999-12-31 dates
+date_one=yes # Supports 0001-01-01 dates
+date_with_YY=yes # Supports YY-MM-DD 2000 compilant dates
+date_zero=yes # Supports 0000-00-00 dates
+domains=no # Domains (ANSI SQL)
+double_quotes=yes # Double '' as ' in strings
+drop_if_exists=yes # drop table if exists
+drop_index=with 'ON' # drop index
+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=no # foreign keys
+foreign_key_syntax=yes # foreign key syntax
+full_outer_join=no # full outer join
+func_extra_!=yes # Function NOT as '!' in SELECT
+func_extra_%=yes # Function MOD as %
+func_extra_&=yes # Function & (bitwise and)
+func_extra_&&=yes # Function AND as '&&'
+func_extra_<>=yes # Function <> in SELECT
+func_extra_==yes # Function =
+func_extra_add_months=no # Function ADD_MONTHS
+func_extra_and_or=yes # 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=yes # Function automatic num->string convert
+func_extra_auto_string2num=yes # Function automatic string->num convert
+func_extra_between=yes # Function BETWEEN in SELECT
+func_extra_binary_shifts=yes # Function << and >> (bitwise shifts)
+func_extra_bit_count=yes # 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_+=error # Function concatenation with +
+func_extra_concat_list=yes # Function CONCAT(list)
+func_extra_convert=no # Function CONVERT
+func_extra_cosh=no # Function COSH
+func_extra_date_format=yes # 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=yes # Function ELT
+func_extra_encrypt=yes # Function ENCRYPT
+func_extra_field=yes # Function FIELD
+func_extra_format=yes # Function FORMAT
+func_extra_from_days=yes # Function FROM_DAYS
+func_extra_from_unixtime=yes # Function FROM_UNIXTIME
+func_extra_getdate=no # Function GETDATE
+func_extra_greatest=yes # Function GREATEST
+func_extra_if=yes # Function IF
+func_extra_in_num=yes # Function IN on numbers in SELECT
+func_extra_in_str=yes # Function IN on strings in SELECT
+func_extra_initcap=no # Function INITCAP
+func_extra_instr=yes # Function LOCATE as INSTR
+func_extra_instr_oracle=no # Function INSTR (Oracle syntax)
+func_extra_instrb=no # Function INSTRB
+func_extra_interval=yes # Function INTERVAL
+func_extra_last_day=no # Function LAST_DAY
+func_extra_last_insert_id=yes # Function LAST_INSERT_ID
+func_extra_least=yes # Function LEAST
+func_extra_lengthb=no # Function LENGTHB
+func_extra_like=yes # Function LIKE in SELECT
+func_extra_like_escape=yes # 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=yes # Function LPAD
+func_extra_mdy=no # Function MDY
+func_extra_mid=yes # Function SUBSTRING as MID
+func_extra_months_between=no # Function MONTHS_BETWEEN
+func_extra_not=yes # Function NOT in SELECT
+func_extra_not_between=yes # Function NOT BETWEEN in SELECT
+func_extra_not_like=yes # Function NOT LIKE in SELECT
+func_extra_odbc_convert=no # Function ODBC CONVERT
+func_extra_password=yes # Function PASSWORD
+func_extra_paste=no # Function PASTE
+func_extra_patindex=no # Function PATINDEX
+func_extra_period_add=yes # Function PERIOD_ADD
+func_extra_period_diff=yes # Function PERIOD_DIFF
+func_extra_pow=yes # Function POW
+func_extra_range=no # Function RANGE
+func_extra_regexp=yes # Function REGEXP in SELECT
+func_extra_replicate=no # Function REPLICATE
+func_extra_reverse=yes # Function REVERSE
+func_extra_root=no # Function ROOT
+func_extra_round1=yes # Function ROUND(1 arg)
+func_extra_rpad=yes # Function RPAD
+func_extra_sec_to_time=yes # Function SEC_TO_TIME
+func_extra_sinh=no # Function SINH
+func_extra_str=no # Function STR
+func_extra_strcmp=yes # Function STRCMP
+func_extra_stuff=no # Function STUFF
+func_extra_substrb=no # Function SUBSTRB
+func_extra_substring_index=yes # Function SUBSTRING_INDEX
+func_extra_sysdate=yes # Function SYSDATE
+func_extra_tail=no # Function TAIL
+func_extra_tanh=no # Function TANH
+func_extra_time_to_sec=yes # Function TIME_TO_SEC
+func_extra_to_days=yes # Function TO_DAYS
+func_extra_translate=no # Function TRANSLATE
+func_extra_trim_many_char=error # Function TRIM; Many char extension
+func_extra_trim_substring=yes # Function TRIM; Substring extension
+func_extra_trunc=no # Function TRUNC
+func_extra_uid=no # Function UID
+func_extra_unix_timestamp=yes # Function UNIX_TIMESTAMP
+func_extra_userenv=no # Function USERENV
+func_extra_version=yes # Function VERSION
+func_extra_weekday=yes # Function WEEKDAY
+func_extra_|=yes # Function | (bitwise or)
+func_extra_||=yes # 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
+func_odbc_asin=yes # Function ASIN
+func_odbc_atan=yes # Function ATAN
+func_odbc_atan2=yes # Function ATAN2
+func_odbc_ceiling=yes # Function CEILING
+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=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=no # Function DIFFERENCE()
+func_odbc_exp=yes # Function EXP
+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=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_locate_2=yes # Function LOCATE(2 arg)
+func_odbc_locate_3=yes # Function LOCATE(3 arg)
+func_odbc_log=yes # Function LOG
+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=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=yes # Function QUARTER
+func_odbc_radians=yes # Function RADIANS
+func_odbc_rand=yes # Function RAND
+func_odbc_repeat=yes # Function REPEAT
+func_odbc_replace=yes # Function REPLACE
+func_odbc_right=yes # Function RIGHT
+func_odbc_round=yes # Function ROUND(2 arg)
+func_odbc_rtrim=yes # Function RTRIM
+func_odbc_second=yes # Function SECOND
+func_odbc_sign=yes # Function SIGN
+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=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=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_cast=no # Function CAST
+func_sql_char_length=error # Function CHAR_LENGTH
+func_sql_char_length(constant)=yes # Function CHAR_LENGTH(constant)
+func_sql_character_length=yes # Function CHARACTER_LENGTH
+func_sql_coalesce=yes # Function COALESCE
+func_sql_concat_as_||=error # 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=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=yes # Function OCTET_LENGTH
+func_sql_position=yes # 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=yes # Function ANSI SQL SUBSTRING
+func_sql_system_user=no # Function SYSTEM_USER
+func_sql_trim=yes # Function TRIM
+func_sql_upper=yes # Function UPPER
+func_sql_user=no # Function USER
+func_where_between=yes # Function BETWEEN
+func_where_eq_all=no # Function = ALL
+func_where_eq_any=no # Function = ANY
+func_where_eq_some=no # Function = SOME
+func_where_exists=no # 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=no # 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=yes # Group by alias
+group_by_null=yes # group on column with null values
+group_by_position=yes # Group by position
+group_distinct_functions=yes # Group functions with distinct
+group_func_extra_bit_and=yes # Group function BIT_AND
+group_func_extra_bit_or=yes # Group function BIT_OR
+group_func_extra_count_distinct_list=yes # Group function COUNT(DISTINCT expr,expr,...)
+group_func_extra_std=yes # Group function STD
+group_func_extra_stddev=yes # Group function STDDEV
+group_func_extra_variance=no # Group function VARIANCE
+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_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_sum=yes # Group function SUM
+group_functions=yes # Group functions
+has_true_false=no # TRUE and FALSE
+having=yes # Having
+having_with_alias=yes # 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=yes # index in create table
+index_namespace=yes # different namespace for index
+index_parts=yes # index on column part (extension)
+inner_join=yes # inner join
+insert_empty_string=yes # insert empty string
+insert_select=yes # insert INTO ... SELECT ...
+insert_with_set=yes # 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=31 # tables in join
+left_outer_join=yes # left outer join
+left_outer_join_using=yes # left outer join using
+like_with_column=yes # column LIKE column
+like_with_number=yes # LIKE on numbers
+lock_tables=yes # lock table
+logical_value=1 # Value of logical operation (1=1)
+max_big_expressions=10 # big expressions
+max_char_size=255 # max char() size
+max_column_name=64 # column name length
+max_columns=3398 # Columns in table
+max_conditions=85660 # OR and AND in WHERE
+max_expressions=859 # simple expressions
+max_index=32 # max index
+max_index_length=500 # index length
+max_index_name=64 # index name length
+max_index_part_length=255 # max index part length
+max_index_parts=16 # index parts
+max_index_varchar_part_length=255 # index varchar part length
+max_row_length=65534 # max table row length (without blobs)
+max_row_length_with_null=65502 # table row length with nulls (without blobs)
+max_select_alias_name=+512 # select alias name length
+max_stack_expression=859 # stacked expressions
+max_table_alias_name=+512 # table alias name length
+max_table_name=64 # table name length
+max_text_size=1048543 # max text or blob size
+max_unique_index=32 # unique indexes
+max_varchar_size=255 # max varchar() size
+minus=no # minus
+minus_incompat=no # minus (incompatible lists)
+minus_neg=yes # Calculate 1--1
+multi_drop=yes # many tables to drop table
+multi_null_in_unique=yes # null in unique index
+multi_strings=yes # Multiple line strings
+multi_table_delete=no # DELETE FROM table1,table2...
+multi_table_update=no # Update with many tables
+multi_value_insert=yes # Value lists in INSERT
+natural_join=yes # natural join
+natural_join_incompat=yes # natural join (incompatible lists)
+natural_left_outer_join=yes # natural left outer join
+no_primary_key=yes # Tables without primary key
+null_concat_expr=yes # Is concat('a',NULL) = NULL
+null_in_index=yes # null in index
+null_in_unique=yes # null in unique index
+null_num_expr=yes # Is 1+NULL = NULL
+odbc_left_outer_join=yes # left outer join odbc style
+operating_system=Linux 2.2.14-my-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
+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=1048574 # query size
+quote_ident_with_"=error # " as identifier quote (ANSI SQL)
+quote_ident_with_[=no # [] as identifier quote
+quote_ident_with_`=yes # ` as identifier quote
+quote_with_"=yes # Allows ' and " as string markers
+remember_end_space=no # Remembers end space in char()
+remember_end_space_varchar=no # Remembers end space in varchar()
+repeat_string_size=1048576 # return string size from function
+right_outer_join=no # right outer join
+rowid=auto_increment # Type for row id
+select_constants=yes # Select constants
+select_limit=with LIMIT # LIMIT number of rows
+select_limit2=yes # SELECT with LIMIT #,#
+select_string_size=1048565 # constant string size in SELECT
+select_table_update=no # Update with sub select
+select_without_from=yes # SELECT without FROM
+server_version=MySQL 3.23.19 beta debug # server version
+simple_joins=yes # ANSI SQL simple joins
+storage_of_float=round # Storage of float values
+subqueries=no # subqueries
+table_alias=yes # Table alias
+table_name_case=no # case independent table names
+table_wildcard=yes # Select table_name.*
+tempoary_table=yes # temporary tables
+transactions=no # transactions
+type_extra_abstime=no # Type abstime
+type_extra_bfile=no # Type bfile
+type_extra_blob=yes # Type blob
+type_extra_bool=yes # Type bool
+type_extra_box=no # Type box
+type_extra_byte=no # Type byte
+type_extra_char(1_arg)_binary=yes # 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=yes # Type datetime
+type_extra_double=yes # Type double
+type_extra_enum(1_arg)=yes # Type enum(1 arg)
+type_extra_float(2_arg)=yes # Type float(2 arg)
+type_extra_float4=yes # Type float4
+type_extra_float8=yes # Type float8
+type_extra_image=no # Type image
+type_extra_inet=no # Type inet
+type_extra_int(1_arg)_zerofill=yes # Type int(1 arg) zerofill
+type_extra_int1=yes # Type int1
+type_extra_int2=yes # Type int2
+type_extra_int3=yes # Type int3
+type_extra_int4=yes # Type int4
+type_extra_int8=yes # Type int8
+type_extra_int_auto_increment=yes # Type int not null auto_increment
+type_extra_int_identity=no # Type int not null identity
+type_extra_int_unsigned=yes # 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=yes # 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=yes # Type mediumint
+type_extra_mediumtext=yes # Type mediumtext
+type_extra_middleint=yes # 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)=yes # 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=yes # 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=yes # Type year
+type_odbc_bigint=yes # Type bigint
+type_odbc_binary(1_arg)=yes # Type binary(1 arg)
+type_odbc_datetime=yes # Type datetime
+type_odbc_tinyint=yes # Type tinyint
+type_odbc_varbinary(1_arg)=yes # Type varbinary(1 arg)
+type_sql_bit=yes # Type bit
+type_sql_bit(1_arg)=yes # 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=no # union
+union_all=no # union all
+union_all_incompat=no # union all (incompatible lists)
+union_incompat=no # union (incompatible lists)
+unique_in_create=yes # unique in create table
+unique_null_in_create=yes # unique null in create
+views=no # views
+where_string_size=1048540 # constant string size in where
diff --git a/sql-bench/limits/mysql.cfg b/sql-bench/limits/mysql.cfg
new file mode 100644
index 00000000000..aebb879a574
--- /dev/null
+++ b/sql-bench/limits/mysql.cfg
@@ -0,0 +1,511 @@
+#This file is automaticly generated by crash-me 1.47
+
+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=yes # Alter table add many columns
+alter_add_primary_key=with constraint # Alter table add primary key
+alter_add_unique=yes # Alter table add unique
+alter_alter_col=yes # Alter table alter column default
+alter_change_col=yes # Alter table change column
+alter_drop_col=yes # Alter table drop column
+alter_drop_constraint=no # Alter table drop constraint
+alter_drop_foreign_key=with drop foreign key # Alter table drop foreign key
+alter_drop_primary_key=drop primary key # Alter table drop primary key
+alter_drop_unique=with drop key # Alter table drop unique
+alter_modify_col=yes # Alter table modify column
+alter_rename_table=yes # Alter table rename table
+atomic_updates=no # atomic updates
+automatic_rowid=_rowid # Automatic rowid
+binary_numbers=no # binary numbers (0b1001)
+binary_strings=no # binary strings (b'0110')
+case_insensitive_strings=yes # case insensitive compare
+char_is_space_filled=no # 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_#=yes # # as comment
+comment_--=yes # -- as comment
+comment_/**/=yes # /* */ as comment
+comment_//=no # // as comment
+compute=no # Compute
+connections=30 # Simultaneous connections (installation default)
+constraint_check=no # Column constraints
+constraint_check_table=no # Table constraints
+constraint_null=yes # NULL constraint (SyBase style)
+crash_me_safe=no # crash me safe
+crash_me_version=1.47 # crash me version
+create_default=yes # default value for column
+create_default_func=no # default value function for column
+create_if_not_exists=yes # create table if not exists
+create_index=yes # create index
+create_schema=no # Create SCHEMA
+create_table_select=yes # create table from select
+cross_join=yes # cross join (same as from a,b)
+date_as_string=yes # String functions on date columns
+date_infinity=error # Supports 'infinity dates
+date_last=yes # Supports 9999-12-31 dates
+date_one=yes # Supports 0001-01-01 dates
+date_with_YY=yes # Supports YY-MM-DD 2000 compilant dates
+date_zero=yes # Supports 0000-00-00 dates
+domains=no # Domains (ANSI SQL)
+double_quotes=yes # Double '' as ' in strings
+drop_if_exists=yes # drop table if exists
+drop_index=with 'ON' # drop index
+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=no # foreign keys
+foreign_key_syntax=yes # foreign key syntax
+full_outer_join=no # full outer join
+func_extra_!=yes # Function NOT as '!' in SELECT
+func_extra_%=yes # Function MOD as %
+func_extra_&=yes # Function & (bitwise and)
+func_extra_&&=yes # Function AND as '&&'
+func_extra_<>=yes # Function <> in SELECT
+func_extra_==yes # Function =
+func_extra_add_months=no # Function ADD_MONTHS
+func_extra_and_or=yes # 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=yes # Function automatic num->string convert
+func_extra_auto_string2num=yes # Function automatic string->num convert
+func_extra_between=yes # Function BETWEEN in SELECT
+func_extra_binary_shifts=yes # Function << and >> (bitwise shifts)
+func_extra_bit_count=yes # 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_+=error # Function concatenation with +
+func_extra_concat_list=yes # Function CONCAT(list)
+func_extra_convert=no # Function CONVERT
+func_extra_cosh=no # Function COSH
+func_extra_date_format=yes # 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=yes # Function ELT
+func_extra_encrypt=yes # Function ENCRYPT
+func_extra_field=yes # Function FIELD
+func_extra_format=yes # Function FORMAT
+func_extra_from_days=yes # Function FROM_DAYS
+func_extra_from_unixtime=yes # Function FROM_UNIXTIME
+func_extra_getdate=no # Function GETDATE
+func_extra_greatest=yes # Function GREATEST
+func_extra_if=yes # Function IF
+func_extra_in_num=yes # Function IN on numbers in SELECT
+func_extra_in_str=yes # Function IN on strings in SELECT
+func_extra_initcap=no # Function INITCAP
+func_extra_instr=yes # Function LOCATE as INSTR
+func_extra_instr_oracle=no # Function INSTR (Oracle syntax)
+func_extra_instrb=no # Function INSTRB
+func_extra_interval=yes # Function INTERVAL
+func_extra_last_day=no # Function LAST_DAY
+func_extra_last_insert_id=yes # Function LAST_INSERT_ID
+func_extra_least=yes # Function LEAST
+func_extra_lengthb=no # Function LENGTHB
+func_extra_like=yes # Function LIKE in SELECT
+func_extra_like_escape=yes # 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=yes # Function LPAD
+func_extra_mdy=no # Function MDY
+func_extra_mid=yes # Function SUBSTRING as MID
+func_extra_months_between=no # Function MONTHS_BETWEEN
+func_extra_not=yes # Function NOT in SELECT
+func_extra_not_between=yes # Function NOT BETWEEN in SELECT
+func_extra_not_like=yes # Function NOT LIKE in SELECT
+func_extra_odbc_convert=no # Function ODBC CONVERT
+func_extra_password=yes # Function PASSWORD
+func_extra_paste=no # Function PASTE
+func_extra_patindex=no # Function PATINDEX
+func_extra_period_add=yes # Function PERIOD_ADD
+func_extra_period_diff=yes # Function PERIOD_DIFF
+func_extra_pow=yes # Function POW
+func_extra_range=no # Function RANGE
+func_extra_regexp=yes # Function REGEXP in SELECT
+func_extra_replicate=no # Function REPLICATE
+func_extra_reverse=yes # Function REVERSE
+func_extra_root=no # Function ROOT
+func_extra_round1=yes # Function ROUND(1 arg)
+func_extra_rpad=yes # Function RPAD
+func_extra_sec_to_time=yes # Function SEC_TO_TIME
+func_extra_sinh=no # Function SINH
+func_extra_str=no # Function STR
+func_extra_strcmp=yes # Function STRCMP
+func_extra_stuff=no # Function STUFF
+func_extra_substrb=no # Function SUBSTRB
+func_extra_substring_index=yes # Function SUBSTRING_INDEX
+func_extra_sysdate=yes # Function SYSDATE
+func_extra_tail=no # Function TAIL
+func_extra_tanh=no # Function TANH
+func_extra_time_to_sec=yes # Function TIME_TO_SEC
+func_extra_to_days=yes # Function TO_DAYS
+func_extra_translate=no # Function TRANSLATE
+func_extra_trim_many_char=error # Function TRIM; Many char extension
+func_extra_trim_substring=yes # Function TRIM; Substring extension
+func_extra_trunc=no # Function TRUNC
+func_extra_uid=no # Function UID
+func_extra_unix_timestamp=yes # Function UNIX_TIMESTAMP
+func_extra_userenv=no # Function USERENV
+func_extra_version=yes # Function VERSION
+func_extra_weekday=yes # Function WEEKDAY
+func_extra_|=yes # Function | (bitwise or)
+func_extra_||=yes # 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
+func_odbc_asin=yes # Function ASIN
+func_odbc_atan=yes # Function ATAN
+func_odbc_atan2=yes # Function ATAN2
+func_odbc_ceiling=yes # Function CEILING
+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=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=no # Function DIFFERENCE()
+func_odbc_exp=yes # Function EXP
+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=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_locate_2=yes # Function LOCATE(2 arg)
+func_odbc_locate_3=yes # Function LOCATE(3 arg)
+func_odbc_log=yes # Function LOG
+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=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=yes # Function QUARTER
+func_odbc_radians=yes # Function RADIANS
+func_odbc_rand=yes # Function RAND
+func_odbc_repeat=yes # Function REPEAT
+func_odbc_replace=yes # Function REPLACE
+func_odbc_right=yes # Function RIGHT
+func_odbc_round=yes # Function ROUND(2 arg)
+func_odbc_rtrim=yes # Function RTRIM
+func_odbc_second=yes # Function SECOND
+func_odbc_sign=yes # Function SIGN
+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=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=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_cast=no # Function CAST
+func_sql_char_length=error # Function CHAR_LENGTH
+func_sql_char_length(constant)=yes # Function CHAR_LENGTH(constant)
+func_sql_character_length=yes # Function CHARACTER_LENGTH
+func_sql_coalesce=yes # Function COALESCE
+func_sql_concat_as_||=error # 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=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=yes # Function OCTET_LENGTH
+func_sql_position=yes # 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=yes # Function ANSI SQL SUBSTRING
+func_sql_system_user=no # Function SYSTEM_USER
+func_sql_trim=yes # Function TRIM
+func_sql_upper=yes # Function UPPER
+func_sql_user=no # Function USER
+func_where_between=yes # Function BETWEEN
+func_where_eq_all=no # Function = ALL
+func_where_eq_any=no # Function = ANY
+func_where_eq_some=no # Function = SOME
+func_where_exists=no # 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=no # 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=yes # Group by alias
+group_by_null=yes # group on column with null values
+group_by_position=yes # Group by position
+group_distinct_functions=yes # Group functions with distinct
+group_func_extra_bit_and=yes # Group function BIT_AND
+group_func_extra_bit_or=yes # Group function BIT_OR
+group_func_extra_count_distinct_list=yes # Group function COUNT(DISTINCT expr,expr,...)
+group_func_extra_std=yes # Group function STD
+group_func_extra_stddev=yes # Group function STDDEV
+group_func_extra_variance=no # Group function VARIANCE
+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_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_sum=yes # Group function SUM
+group_functions=yes # Group functions
+has_true_false=no # TRUE and FALSE
+having=yes # Having
+having_with_alias=yes # 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=yes # index in create table
+index_namespace=yes # different namespace for index
+index_parts=yes # index on column part (extension)
+inner_join=yes # inner join
+insert_empty_string=yes # insert empty string
+insert_select=yes # insert INTO ... SELECT ...
+insert_with_set=yes # 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=31 # tables in join
+left_outer_join=yes # left outer join
+left_outer_join_using=yes # left outer join using
+like_with_column=yes # column LIKE column
+like_with_number=yes # LIKE on numbers
+lock_tables=yes # lock table
+logical_value=1 # Value of logical operation (1=1)
+max_big_expressions=10 # big expressions
+max_char_size=255 # max char() size
+max_column_name=64 # column name length
+max_columns=3398 # Columns in table
+max_conditions=85660 # OR and AND in WHERE
+max_expressions=859 # simple expressions
+max_index=32 # max index
+max_index_length=500 # index length
+max_index_name=64 # index name length
+max_index_part_length=255 # max index part length
+max_index_parts=16 # index parts
+max_index_varchar_part_length=255 # index varchar part length
+max_row_length=65534 # max table row length (without blobs)
+max_row_length_with_null=65502 # table row length with nulls (without blobs)
+max_select_alias_name=+512 # select alias name length
+max_stack_expression=859 # stacked expressions
+max_table_alias_name=+512 # table alias name length
+max_table_name=64 # table name length
+max_text_size=1048543 # max text or blob size
+max_unique_index=32 # unique indexes
+max_varchar_size=255 # max varchar() size
+minus=no # minus
+minus_incompat=no # minus (incompatible lists)
+minus_neg=yes # Calculate 1--1
+multi_drop=yes # many tables to drop table
+multi_null_in_unique=yes # null in unique index
+multi_strings=yes # Multiple line strings
+multi_table_delete=no # DELETE FROM table1,table2...
+multi_table_update=no # Update with many tables
+multi_value_insert=yes # Value lists in INSERT
+natural_join=yes # natural join
+natural_join_incompat=yes # natural join (incompatible lists)
+natural_left_outer_join=yes # natural left outer join
+no_primary_key=yes # Tables without primary key
+null_concat_expr=yes # Is concat('a',NULL) = NULL
+null_in_index=yes # null in index
+null_in_unique=yes # null in unique index
+null_num_expr=yes # Is 1+NULL = NULL
+odbc_left_outer_join=yes # left outer join odbc style
+operating_system=Linux 2.2.14-my-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
+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=1048574 # query size
+quote_ident_with_"=error # " as identifier quote (ANSI SQL)
+quote_ident_with_[=no # [] as identifier quote
+quote_ident_with_`=yes # ` as identifier quote
+quote_with_"=yes # Allows ' and " as string markers
+remember_end_space=no # Remembers end space in char()
+remember_end_space_varchar=no # Remembers end space in varchar()
+repeat_string_size=1048576 # return string size from function
+right_outer_join=no # right outer join
+rowid=auto_increment # Type for row id
+select_constants=yes # Select constants
+select_limit=with LIMIT # LIMIT number of rows
+select_limit2=yes # SELECT with LIMIT #,#
+select_string_size=1048565 # constant string size in SELECT
+select_table_update=no # Update with sub select
+select_without_from=yes # SELECT without FROM
+server_version=MySQL 3.23.19 beta debug # server version
+simple_joins=yes # ANSI SQL simple joins
+storage_of_float=round # Storage of float values
+subqueries=no # subqueries
+table_alias=yes # Table alias
+table_name_case=no # case independent table names
+table_wildcard=yes # Select table_name.*
+tempoary_table=yes # temporary tables
+transactions=no # transactions
+type_extra_abstime=no # Type abstime
+type_extra_bfile=no # Type bfile
+type_extra_blob=yes # Type blob
+type_extra_bool=yes # Type bool
+type_extra_box=no # Type box
+type_extra_byte=no # Type byte
+type_extra_char(1_arg)_binary=yes # 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=yes # Type datetime
+type_extra_double=yes # Type double
+type_extra_enum(1_arg)=yes # Type enum(1 arg)
+type_extra_float(2_arg)=yes # Type float(2 arg)
+type_extra_float4=yes # Type float4
+type_extra_float8=yes # Type float8
+type_extra_image=no # Type image
+type_extra_inet=no # Type inet
+type_extra_int(1_arg)_zerofill=yes # Type int(1 arg) zerofill
+type_extra_int1=yes # Type int1
+type_extra_int2=yes # Type int2
+type_extra_int3=yes # Type int3
+type_extra_int4=yes # Type int4
+type_extra_int8=yes # Type int8
+type_extra_int_auto_increment=yes # Type int not null auto_increment
+type_extra_int_identity=no # Type int not null identity
+type_extra_int_unsigned=yes # 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=yes # 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=yes # Type mediumint
+type_extra_mediumtext=yes # Type mediumtext
+type_extra_middleint=yes # 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)=yes # 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=yes # 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=yes # Type year
+type_odbc_bigint=yes # Type bigint
+type_odbc_binary(1_arg)=yes # Type binary(1 arg)
+type_odbc_datetime=yes # Type datetime
+type_odbc_tinyint=yes # Type tinyint
+type_odbc_varbinary(1_arg)=yes # Type varbinary(1 arg)
+type_sql_bit=yes # Type bit
+type_sql_bit(1_arg)=yes # 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=no # union
+union_all=no # union all
+union_all_incompat=no # union all (incompatible lists)
+union_incompat=no # union (incompatible lists)
+unique_in_create=yes # unique in create table
+unique_null_in_create=yes # unique null in create
+views=no # views
+where_string_size=1048540 # constant string size in where
diff --git a/sql-bench/limits/oracle.cfg b/sql-bench/limits/oracle.cfg
new file mode 100644
index 00000000000..b910f91fb05
--- /dev/null
+++ b/sql-bench/limits/oracle.cfg
@@ -0,0 +1,505 @@
+#This file is automaticly generated by crash-me 1.44a
+
+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=yes # Alter table add many columns
+alter_add_primary_key=with constraint # Alter table add primary key
+alter_add_unique=yes # Alter table add unique
+alter_alter_col=no # Alter table alter column default
+alter_change_col=no # Alter table change column
+alter_drop_col=yes # 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=with constraint # Alter table drop unique
+alter_modify_col=yes # Alter table modify column
+alter_rename_table=yes # Alter table rename table
+atomic_updates=yes # atomic updates
+atomic_updates_with_rollback=yes # atomic_updates_with_rollback
+automatic_rowid=no # Automatic rowid
+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
+comment_//=no # // as comment
+compute=no # Compute
+connections=41 # Simultaneous connections (installation default)
+constraint_check=yes # Column constraints
+constraint_check_table=yes # Table constraints
+constraint_null=yes # NULL constraint (SyBase style)
+crash_me_safe=yes # crash me safe
+crash_me_version=1.45 # 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_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
+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=yes # foreign keys
+foreign_key_syntax=yes # foreign key syntax
+full_outer_join=no # 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=yes # Function automatic num->string convert
+func_extra_auto_string2num=yes # 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=yes # Function CEIL
+func_extra_charindex=no # Function CHARINDEX
+func_extra_chr=yes # 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=yes # 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=yes # 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=yes # Function INITCAP
+func_extra_instr=yes # Function LOCATE as INSTR
+func_extra_instr_oracle=yes # Function INSTR (Oracle syntax)
+func_extra_instrb=error # 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=yes # Function LEAST
+func_extra_lengthb=error # Function LENGTHB
+func_extra_like=no # Function LIKE in SELECT
+func_extra_like_escape=no # Function LIKE ESCAPE in SELECT
+func_extra_ln=yes # Function LN
+func_extra_log(m_n)=yes # Function LOG(m,n)
+func_extra_logn=no # Function LOGN
+func_extra_lpad=yes # 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=yes # Function REVERSE
+func_extra_root=no # Function ROOT
+func_extra_round1=yes # Function ROUND(1 arg)
+func_extra_rpad=yes # Function RPAD
+func_extra_sec_to_time=no # Function SEC_TO_TIME
+func_extra_sinh=yes # Function SINH
+func_extra_str=no # Function STR
+func_extra_strcmp=no # Function STRCMP
+func_extra_stuff=no # Function STUFF
+func_extra_substrb=error # 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=error # Function TANH
+func_extra_time_to_sec=no # Function TIME_TO_SEC
+func_extra_to_days=no # Function TO_DAYS
+func_extra_translate=yes # 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=yes # Function TRUNC
+func_extra_uid=yes # 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_odbc_abs=yes # Function ABS
+func_odbc_acos=yes # Function ACOS
+func_odbc_ascii=yes # Function ASCII
+func_odbc_asin=yes # Function ASIN
+func_odbc_atan=yes # Function ATAN
+func_odbc_atan2=yes # Function ATAN2
+func_odbc_ceiling=no # Function CEILING
+func_odbc_char=no # Function CHAR
+func_odbc_concat=yes # Function CONCAT(2 arg)
+func_odbc_cos=yes # Function COS
+func_odbc_cot=no # Function COT
+func_odbc_curdate=yes # Function CURDATE
+func_odbc_curtime=yes # Function CURTIME
+func_odbc_database=yes # Function DATABASE
+func_odbc_dayname=no # Function DAYNAME
+func_odbc_dayofmonth=yes # Function DAYOFMONTH
+func_odbc_dayofweek=error # Function DAYOFWEEK
+func_odbc_dayofyear=yes # Function DAYOFYEAR
+func_odbc_degrees=no # Function DEGREES
+func_odbc_difference=no # 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=no # Function HOUR
+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_locate_2=yes # Function LOCATE(2 arg)
+func_odbc_locate_3=yes # Function LOCATE(3 arg)
+func_odbc_log=yes # Function LOG
+func_odbc_log10=yes # Function LOG10
+func_odbc_ltrim=yes # Function LTRIM
+func_odbc_minute=no # Function MINUTE
+func_odbc_mod=yes # Function MOD
+func_odbc_month=yes # Function MONTH
+func_odbc_monthname=no # Function MONTHNAME
+func_odbc_now=yes # Function NOW
+func_odbc_pi=yes # Function PI
+func_odbc_power=yes # Function POWER
+func_odbc_quarter=yes # Function QUARTER
+func_odbc_radians=no # Function RADIANS
+func_odbc_rand=no # Function RAND
+func_odbc_repeat=yes # Function REPEAT
+func_odbc_replace=yes # Function REPLACE
+func_odbc_right=yes # Function RIGHT
+func_odbc_round=no # Function ROUND(2 arg)
+func_odbc_rtrim=yes # Function RTRIM
+func_odbc_second=no # Function SECOND
+func_odbc_sign=yes # Function SIGN
+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=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=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_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=no # 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=yes # Function LOWER
+func_sql_nullif=no # Function NULLIF
+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=no # Function simple CASE
+func_sql_substring=no # Function ANSI SQL SUBSTRING
+func_sql_system_user=no # Function SYSTEM_USER
+func_sql_trim=yes # 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=yes # Group function STDDEV
+group_func_extra_variance=yes # Group function VARIANCE
+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_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_sum=yes # Group function SUM
+group_functions=yes # Group functions
+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=no # 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=no # inner join
+insert_empty_string=no # insert empty string
+insert_select=yes # insert INTO ... SELECT ...
+insert_with_set=no # INSERT with set syntax
+intersect=yes # 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=no # left outer join
+left_outer_join_using=no # left outer join using
+like_with_column=yes # column LIKE column
+like_with_number=yes # LIKE on numbers
+lock_tables=yes # lock table
+logical_value=not supported # Value of logical operation (1=1)
+max_big_expressions=8 # big expressions
+max_char_size=2000 # max char() size
+max_column_name=30 # column name length
+max_columns=1000 # Columns in table
+max_conditions=36392 # OR and AND in WHERE
+max_expressions=+10000 # simple expressions
+max_index=+64 # max index
+max_index_length=749 # index length
+max_index_name=30 # index name length
+max_index_part_length=2000 # max index part length
+max_index_parts=33 # index parts
+max_index_varchar_part_length=3209 # index varchar part length
+max_row_length=255000 # max table row length (without blobs)
+max_row_length_with_null=255000 # table row length with nulls (without blobs)
+max_select_alias_name=30 # select alias name length
+max_stack_expression=+2000 # stacked expressions
+max_table_alias_name=30 # table alias name length
+max_table_name=30 # table name length
+max_unique_index=+64 # unique indexes
+max_varchar_size=4000 # max varchar() size
+minus=yes # minus
+minus_incompat=no # minus (incompatible lists)
+minus_neg=no # Calculate 1--1
+multi_drop=no # many tables to drop table
+multi_null_in_unique=yes # null in unique index
+multi_strings=no # Multiple line strings
+multi_table_delete=no # DELETE FROM table1,table2...
+multi_table_update=no # Update with many tables
+multi_value_insert=no # Value lists in INSERT
+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=error # Is 'a' || NULL = NULL
+null_in_index=yes # null in index
+null_in_unique=yes # null in unique index
+null_num_expr=yes # Is 1+NULL = NULL
+odbc_left_outer_join=yes # left outer join odbc style
+operating_system=Microsoft Windows 2000 [Version 5.00.2195] # 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
+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=+64 # recursive subqueries
+remember_end_space=no # Remembers end space in char()
+remember_end_space_varchar=yes # Remembers end space in varchar()
+right_outer_join=no # right outer join
+rowid=rowid # 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=4000 # constant string size in SELECT
+select_table_update=yes # Update with sub select
+select_without_from=no # SELECT without FROM
+server_version=Oracle 8.1.6.0.0 # server version
+simple_joins=yes # ANSI SQL simple joins
+storage_of_float=undefined # 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.*
+tempoary_table=no # temporary tables
+transactions=yes # transactions
+type_extra_abstime=no # Type abstime
+type_extra_bfile=yes # 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_circle=no # Type circle
+type_extra_clob=yes # 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_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=yes # Type long
+type_extra_long_raw=yes # 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_mediumint=no # Type mediumint
+type_extra_mediumtext=no # Type mediumtext
+type_extra_middleint=no # Type middleint
+type_extra_mlslabel=yes # Type mlslabel
+type_extra_money=no # Type money
+type_extra_nclob=yes # Type nclob
+type_extra_number=yes # Type number
+type_extra_number(1_arg)=yes # Type number(1 arg)
+type_extra_number(2_arg)=yes # Type number(2 arg)
+type_extra_nvarchar2(1_arg)=yes # 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)=yes # Type raw(1 arg)
+type_extra_reltime=no # Type reltime
+type_extra_rowid=yes # 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)=yes # 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_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=no # Type time
+type_sql_timestamp=no # 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=yes # unique null in create
+views=yes # views
+where_string_size=4000 # constant string size in where
diff --git a/sql-bench/limits/pg.cfg b/sql-bench/limits/pg.cfg
new file mode 100644
index 00000000000..493d5f68150
--- /dev/null
+++ b/sql-bench/limits/pg.cfg
@@ -0,0 +1,504 @@
+#This file is automaticly generated by crash-me 1.45
+
+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=no # 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=no # Alter table add primary key
+alter_add_unique=no # Alter table add unique
+alter_alter_col=yes # Alter table alter column default
+alter_change_col=no # Alter table change column
+alter_drop_col=no # Alter table drop column
+alter_drop_constraint=no # Alter table drop constraint
+alter_drop_foreign_key=no # 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=yes # Alter table rename table
+atomic_updates=no # atomic updates
+automatic_rowid=no # Automatic rowid
+binary_numbers=no # binary numbers (0b1001)
+binary_strings=yes # 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
+comment_//=no # // as comment
+compute=no # Compute
+connections=32 # Simultaneous connections (installation default)
+constraint_check=yes # Column constraints
+constraint_check_table=yes # Table constraints
+constraint_null=yes # NULL constraint (SyBase style)
+crash_me_safe=yes # crash me safe
+crash_me_version=1.45 # 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=yes # cross join (same as from a,b)
+date_last=yes # Supports 9999-12-31 dates
+date_one=yes # Supports 0001-01-01 dates
+date_with_YY=yes # Supports YY-MM-DD 2000 compilant 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
+end_colon=yes # allows end ';'
+except=yes # 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=yes # foreign keys
+foreign_key_syntax=yes # foreign key syntax
+full_outer_join=no # full outer join
+func_extra_!=no # Function NOT as '!' in SELECT
+func_extra_%=yes # Function MOD as %
+func_extra_&=no # Function & (bitwise and)
+func_extra_&&=no # Function AND as '&&'
+func_extra_<>=yes # Function <> in SELECT
+func_extra_==yes # Function =
+func_extra_add_months=no # Function ADD_MONTHS
+func_extra_and_or=yes # 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=yes # Function automatic string->num convert
+func_extra_between=yes # Function BETWEEN in SELECT
+func_extra_binary_shifts=no # Function << and >> (bitwise shifts)
+func_extra_bit_count=no # Function BIT_COUNT
+func_extra_ceil=yes # 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=yes # Function IN on numbers in SELECT
+func_extra_in_str=no # Function IN on strings in SELECT
+func_extra_initcap=yes # 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=yes # 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)=yes # Function LOG(m,n)
+func_extra_logn=no # Function LOGN
+func_extra_lpad=yes # 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=yes # Function NOT in SELECT
+func_extra_not_between=yes # Function NOT BETWEEN in SELECT
+func_extra_not_like=yes # 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=yes # Function ROUND(1 arg)
+func_extra_rpad=yes # 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=yes # Function TRANSLATE
+func_extra_trim_many_char=yes # Function TRIM; Many char extension
+func_extra_trim_substring=error # Function TRIM; Substring extension
+func_extra_trunc=yes # 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=yes # Function VERSION
+func_extra_weekday=no # Function WEEKDAY
+func_extra_|=no # Function | (bitwise or)
+func_extra_||=no # Function OR as '||'
+func_odbc_abs=yes # Function ABS
+func_odbc_acos=yes # Function ACOS
+func_odbc_ascii=yes # Function ASCII
+func_odbc_asin=yes # Function ASIN
+func_odbc_atan=yes # Function ATAN
+func_odbc_atan2=yes # 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=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_degrees=yes # Function DEGREES
+func_odbc_difference=no # Function DIFFERENCE()
+func_odbc_exp=no # Function EXP
+func_odbc_floor=yes # 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=yes # Function LTRIM
+func_odbc_minute=no # Function MINUTE
+func_odbc_mod=yes # Function MOD
+func_odbc_month=no # Function MONTH
+func_odbc_monthname=no # Function MONTHNAME
+func_odbc_now=yes # Function NOW
+func_odbc_pi=yes # Function PI
+func_odbc_power=no # Function POWER
+func_odbc_quarter=no # Function QUARTER
+func_odbc_radians=yes # Function RADIANS
+func_odbc_rand=no # Function RAND
+func_odbc_repeat=yes # Function REPEAT
+func_odbc_replace=no # Function REPLACE
+func_odbc_right=no # Function RIGHT
+func_odbc_round=yes # Function ROUND(2 arg)
+func_odbc_rtrim=yes # Function RTRIM
+func_odbc_second=no # Function SECOND
+func_odbc_sign=yes # Function SIGN
+func_odbc_sin=yes # 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=yes # 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=yes # Function CHAR_LENGTH
+func_sql_char_length(constant)=yes # Function CHAR_LENGTH(constant)
+func_sql_character_length=yes # Function CHARACTER_LENGTH
+func_sql_coalesce=yes # 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=yes # 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=yes # Function LOWER
+func_sql_nullif=no # Function NULLIF
+func_sql_octet_length=no # Function OCTET_LENGTH
+func_sql_position=yes # Function POSITION
+func_sql_searched_case=yes # Function searched CASE
+func_sql_session_user=yes # Function SESSION_USER
+func_sql_simple_case=yes # Function simple CASE
+func_sql_substring=yes # Function ANSI SQL SUBSTRING
+func_sql_system_user=no # Function SYSTEM_USER
+func_sql_trim=yes # 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=no # 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=yes # Group by alias
+group_by_null=yes # group on column with null values
+group_by_position=yes # 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_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_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_sum=yes # Group function SUM
+group_functions=yes # Group functions
+has_true_false=yes # TRUE and FALSE
+having=yes # Having
+having_with_alias=no # Having on alias
+having_with_group=yes # Having with group function
+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=no # inner join
+insert_empty_string=yes # insert empty string
+insert_select=yes # insert INTO ... SELECT ...
+insert_with_set=no # INSERT with set syntax
+intersect=yes # 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=no # left outer join
+left_outer_join_using=no # left outer join using
+like_with_column=yes # column LIKE column
+like_with_number=yes # LIKE on numbers
+lock_tables=yes # lock table
+logical_value=1 # Value of logical operation (1=1)
+max_big_expressions=10 # big expressions
+max_char_size=8104 # max char() size
+max_column_name=+512 # column name length
+max_columns=1600 # Columns in table
+max_conditions=19994 # OR and AND in WHERE
+max_expressions=9999 # simple expressions
+max_index=+64 # max index
+max_index_length=2704 # index length
+max_index_name=+512 # index name length
+max_index_part_length=2704 # max index part length
+max_index_parts=16 # index parts
+max_index_varchar_part_length=2704 # index varchar part length
+max_row_length=7949 # max table row length (without blobs)
+max_row_length_with_null=7949 # table row length with nulls (without blobs)
+max_select_alias_name=+512 # select alias name length
+max_stack_expression=+2000 # stacked expressions
+max_table_alias_name=+512 # table alias name length
+max_table_name=+512 # table name length
+max_text_size=8104 # max text or blob size
+max_unique_index=+64 # unique indexes
+max_varchar_size=8104 # max varchar() size
+minus=no # minus
+minus_incompat=no # minus (incompatible lists)
+minus_neg=no # Calculate 1--1
+multi_drop=yes # many tables to drop table
+multi_null_in_unique=yes # null in unique index
+multi_strings=yes # Multiple line strings
+multi_table_delete=no # DELETE FROM table1,table2...
+multi_table_update=no # Update with many tables
+multi_value_insert=no # Value lists in INSERT
+natural_join=yes # natural join
+natural_join_incompat=yes # natural join (incompatible lists)
+natural_left_outer_join=no # natural left outer join
+no_primary_key=yes # Tables without primary key
+null_concat_expr=yes # Is 'a' || NULL = NULL
+null_in_index=yes # null in index
+null_in_unique=yes # null in unique index
+null_num_expr=yes # Is 1+NULL = NULL
+odbc_left_outer_join=no # left outer join odbc style
+operating_system=Linux 2.2.14-5.0 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
+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_"=no # " 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=+64 # recursive subqueries
+remember_end_space=no # Remembers end space in char()
+remember_end_space_varchar=yes # Remembers end space in varchar()
+repeat_string_size=+8000000 # return string size from function
+right_outer_join=no # right outer join
+rowid=oid # Type for row id
+select_constants=yes # Select constants
+select_limit=with LIMIT # LIMIT number of rows
+select_limit2=yes # SELECT with LIMIT #,#
+select_string_size=16777207 # constant string size in SELECT
+select_table_update=yes # Update with sub select
+select_without_from=yes # SELECT without FROM
+server_version=PostgreSQL 7.0 # server version
+simple_joins=yes # ANSI SQL simple joins
+storage_of_float=round # 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.*
+tempoary_table=yes # temporary tables
+transactions=yes # transactions
+type_extra_abstime=yes # Type abstime
+type_extra_bfile=no # Type bfile
+type_extra_blob=no # Type blob
+type_extra_bool=yes # Type bool
+type_extra_box=yes # Type box
+type_extra_byte=no # Type byte
+type_extra_char(1_arg)_binary=no # Type char(1 arg) binary
+type_extra_circle=yes # Type circle
+type_extra_clob=no # Type clob
+type_extra_datetime=yes # 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=yes # Type float4
+type_extra_float8=yes # Type float8
+type_extra_image=no # Type image
+type_extra_int(1_arg)_zerofill=no # Type int(1 arg) zerofill
+type_extra_int1=no # Type int1
+type_extra_int2=yes # Type int2
+type_extra_int3=no # Type int3
+type_extra_int4=yes # Type int4
+type_extra_int8=yes # 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=yes # Type interval
+type_extra_line=yes # 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=yes # Type lseg
+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=yes # 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=yes # Type path
+type_extra_point=yes # Type point
+type_extra_polygon=yes # Type polygon
+type_extra_raw(1_arg)=no # Type raw(1 arg)
+type_extra_reltime=yes # Type reltime
+type_extra_rowid=no # Type rowid
+type_extra_serial=yes # 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=yes # Type text
+type_extra_text(1_arg)=no # Type text(1 arg)
+type_extra_timespan=yes # 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=yes # Type datetime
+type_odbc_tinyint=no # Type tinyint
+type_odbc_varbinary(1_arg)=no # Type varbinary(1 arg)
+type_sql_bit=yes # Type bit
+type_sql_bit(1_arg)=yes # Type bit(1 arg)
+type_sql_bit_varying(1_arg)=yes # 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_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=yes # Type interval day
+type_sql_interval_day_to_hour=yes # Type interval day to hour
+type_sql_interval_day_to_minute=yes # Type interval day to minute
+type_sql_interval_day_to_second=yes # Type interval day to second
+type_sql_interval_hour=yes # Type interval hour
+type_sql_interval_hour_to_minute=yes # Type interval hour to minute
+type_sql_interval_hour_to_second=yes # Type interval hour to second
+type_sql_interval_minute=yes # Type interval minute
+type_sql_interval_minute_to_second=yes # Type interval minute to second
+type_sql_interval_month=yes # Type interval month
+type_sql_interval_second=yes # Type interval second
+type_sql_interval_year=yes # Type interval year
+type_sql_interval_year_to_month=yes # 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=yes # 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=yes # unique null in create
+views=yes # views
+where_string_size=16777182 # constant string size in where
diff --git a/sql-bench/limits/pg.comment b/sql-bench/limits/pg.comment
new file mode 100644
index 00000000000..c693817cc91
--- /dev/null
+++ b/sql-bench/limits/pg.comment
@@ -0,0 +1,30 @@
+*****************************************************************
+NOTE:
+This is an old comment about how it was to run crash-me on postgreSQL
+the first time. I think it was on pg 6.2
+*****************************************************************
+
+mmm memory use of postgres is very very much ...
+at this moment I am testing it ...
+and the tables in join: is taking 200MB memory ...
+I am happy to have 400mb swap ... so he can do have it ...
+but other programs will give some errors ...
+just a second ago ... vim core dumped .. XFree crashed full ... to the prompt
+the menu bar of redhat disappeared ....
+at this momemt the max is 215 mb memore postgres is taking ...
+
+the problem with postgres is the following error:
+PQexec() -- Request was sent to backend, but backend closed the channel before r
+esponding. This probably means the backend terminated abnormally before or whil
+e processing the request
+
+I think we can solve this with a goto command ... to go back again ... after
+the connect again ...
+postgres is taking 377 mb .... mmm allmost out of memory ... 53mb left ..
+mmm it's growing ... 389 mb ..393 mb ... 397 mb .. better can wait for the out of memory ... i think 409 412 max ...
+
+ps added some nice code for the channel closing ...
+it must now do again the query when the error is the above error ...
+hopes this helps ...
+after crashing my X again ...
+I stopped testing postgres
diff --git a/sql-bench/limits/solid-nt4.cfg b/sql-bench/limits/solid-nt4.cfg
new file mode 100644
index 00000000000..3a5c387c7d2
--- /dev/null
+++ b/sql-bench/limits/solid-nt4.cfg
@@ -0,0 +1,422 @@
+#This file is automaticly generated by crash-me 1.19a
+
+NEG=yes # update of column= -column
+alter_add_col=yes # Alter table add column
+alter_change_col=no # Alter table change column
+alter_drop_col=yes # Alter table drop column
+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=yes # binary items (0x41)
+case_insensitive_strings=no # case insensitive compare
+char_is_space_filled=no # char are space filled
+column_alias=yes # Column alias
+comment_#=no # # as comment
+comment_--=yes # -- as comment
+comment_/**/=no # /* */ as comment
+compute=no # Compute
+connections=1000 # Simultaneous connections
+crash_me_safe=no # crash me safe
+crash_me_version=1.19a # crash me version
+create_default=no # default value for column
+create_index=yes # create index
+cross_join=yes # cross join (same as from a,b)
+date_as_string=no # String functions on date columns
+date_with_YY=yes # Supports YY-MM-DD 2000 compilant dates
+date_zero=yes # Supports 0000-00-00 dates
+double_quotes=yes # Double '' as ' in strings
+drop_index=yes # drop index
+except=yes # except
+except_all=yes # except all
+float_int_expr=yes # mixing of integer and float in expression
+foreign_key=yes # foreign keys
+foreign_key_syntax=yes # 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_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_+=yes # 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_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_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_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_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_odbc_abs=yes # Function ABS
+func_odbc_acos=yes # Function ACOS
+func_odbc_ascii=yes # Function ASCII
+func_odbc_asin=yes # Function ASIN
+func_odbc_atan=yes # Function ATAN
+func_odbc_atan2=yes # Function ATAN2
+func_odbc_ceiling=yes # Function CEILING
+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=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=no # Function DIFFERENCE()
+func_odbc_exp=yes # Function EXP
+func_odbc_extract=yes # 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=yes # Function ANSI HOUR
+func_odbc_ifnull=yes # Function IFNULL
+func_odbc_insert=no # Function INSERT
+func_odbc_lcase=yes # Function LCASE
+func_odbc_left=no # Function LEFT
+func_odbc_length=yes # Function REAL LENGTH
+func_odbc_length_without_space=error # 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
+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=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=yes # Function QUARTER
+func_odbc_radians=yes # Function RADIANS
+func_odbc_rand=no # Function RAND
+func_odbc_repeat=yes # Function REPEAT
+func_odbc_replace=yes # Function REPLACE
+func_odbc_right=no # Function RIGHT
+func_odbc_round=yes # Function ROUND(2 arg)
+func_odbc_rtrim=yes # Function RTRIM
+func_odbc_second=yes # Function SECOND
+func_odbc_sign=yes # Function SIGN
+func_odbc_sin=yes # Function SIN
+func_odbc_soundex=no # Function SOUNDEX
+func_odbc_space=yes # Function SPACE
+func_odbc_sqrt=yes # Function SQRT
+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=yes # Function UCASE
+func_odbc_user=yes # Function USER
+func_odbc_user()=no # Function USER()
+func_odbc_week=yes # Function WEEK
+func_odbc_year=yes # Function YEAR
+func_sql_+=yes # Function +, -, * and /
+func_sql_bit_length=yes # Function BIT_LENGTH
+func_sql_case=yes # Function CASE
+func_sql_cast=yes # Function CAST
+func_sql_char_length=yes # Function CHAR_LENGTH
+func_sql_character_length=yes # Function CHARACTER_LENGTH
+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=yes # Function LOWER
+func_sql_octet_length=yes # Function OCTET_LENGTH
+func_sql_position=yes # Function POSITION
+func_sql_session_user=no # Function SESSION_USER
+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=yes # Function UPPER
+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=yes # Group by alias
+group_by_null=yes # Test nulls in group by
+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_std=no # Group function STD
+group_func_extra_stddev=no # Group function STDDEV
+group_func_extra_variance=no # Group function VARIANCE
+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_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_sum=yes # Group function SUM
+group_functions=yes # Group functions
+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
+index_in_create=no # index in create table
+index_namespace=no # different namespace for index
+index_parts=no # index on column part (extension)
+insert_empty_string=yes # insert empty string
+insert_select=yes # insert INTO ... SELECT ...
+intersect=yes # intersect
+intersect_all=yes # intersect all
+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=yes # 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=65489 # max char() size
+max_column_name=254 # column name length
+max_columns=1000 # Columns in table
+max_conditions=1518 # OR and AND in WHERE
+max_expressions=3093 # simple expressions
+max_index=+64 # max index
+max_index_length=+8192 # index length
+max_index_name=254 # index name length
+max_index_part_length=65485 # max index part length
+max_index_parts=63 # index parts
+max_index_varchar_part_length=65485 # index varchar part length
+max_row_length=2634 # max table row length (without blobs)
+max_row_length_with_null=2634 # table row length with nulls (without blobs)
+max_select_alias_name=+512 # select alias name length
+max_stack_expression=48 # stacked expressions
+max_table_alias_name=+512 # table alias name length
+max_table_name=254 # table name length
+max_unique_index=+64 # unique indexes
+max_varchar_size=65489 # max varchar() size
+minus=no # minus
+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_left_outer_join=no # natural left outer join
+no_primary_key=yes # Tables without primary key
+null_concat_expr=yes # Is 'a' || NULL = NULL
+null_in_index=yes # null in index
+null_in_unique=no # null in unique
+null_num_expr=yes # Is 1+NULL = NULL
+odbc_left_outer_join=yes # left outer join odbc style
+operating_system=Windows NT Version 4.0 # crash-me tested on
+order_by=yes # Order by
+order_by_alias=yes # Order by alias
+order_by_position=yes # Order by position
+primary_key_in_create=yes # primary key in create table
+query_size=65520 # query size
+quote_with_"=no # Allows ' and " as string markers
+recursive_subqueries=14 # recursive subqueries
+remember_end_space=no # Remembers end space in char()
+remember_end_space_varchar=yes # Remembers end space in varchar()
+repeat_string_size=254 # return string size from function
+right_outer_join=yes # right outer join
+select_constants=yes # Select constants
+select_string_size=6185 # constant string size in SELECT
+select_table_update=yes # Update with sub select
+select_without_from=yes # SELECT without FROM
+server_version=Solid version ??? # server version
+simple_joins=yes # ANSI SQL simple joins
+subqueries=yes # subqueries
+table_alias=yes # Table alias
+table_wildcard=yes # Select table_name.*
+transactions=yes # transactions
+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_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_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_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_line=no # Type line
+type_extra_long=no # Type long
+type_extra_long_raw=no # Type long raw
+type_extra_long_varbinary=yes # Type long varbinary
+type_extra_long_varchar(1_arg)=yes # Type long varchar(1 arg)
+type_extra_lseg=no # Type lseg
+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_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_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)=yes # Type binary(1 arg)
+type_odbc_datetime=no # Type datetime
+type_sql_smallint=yes # Type smallint
+type_odbc_tinyint=yes # Type tinyint
+type_odbc_varbinary(1_arg)=yes # 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)=no # 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=no # Type double
+type_sql_double_precision=yes # Type double precision
+type_sql_float=yes # Type float
+type_extra_float(2_arg)=yes # Type float(1 arg)
+type_sql_int=yes # Type int
+type_sql_integer=yes # Type integer
+type_sql_interval_year=no # Type interval year
+type_sql_numeric(2_arg)=yes # Type numeric(2 arg)
+type_sql_real=yes # Type real
+type_sql_time=yes # Type time
+type_sql_timestamp=yes # Type timestamp
+type_sql_varchar(1_arg)=yes # Type varchar(1 arg)
+union=yes # union
+union_all=yes # union all
+unique_in_create=yes # unique in create table
+unique_null_in_create=no # unique null in create
+views=yes # views
+where_string_size=254 # constant string size in where
diff --git a/sql-bench/limits/solid.cfg b/sql-bench/limits/solid.cfg
new file mode 100644
index 00000000000..88638a1a876
--- /dev/null
+++ b/sql-bench/limits/solid.cfg
@@ -0,0 +1,422 @@
+#This file is automaticly generated by crash-me 1.19a
+
+NEG=yes # update of column= -column
+alter_add_col=yes # Alter table add column
+alter_change_col=no # Alter table change column
+alter_drop_col=yes # Alter table drop column
+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=yes # binary items (0x41)
+case_insensitive_strings=no # case insensitive compare
+char_is_space_filled=no # char are space filled
+column_alias=yes # Column alias
+comment_#=no # # as comment
+comment_--=yes # -- as comment
+comment_/**/=no # /* */ as comment
+compute=no # Compute
+connections=248 # Simultaneous connections
+crash_me_safe=yes # crash me safe
+crash_me_version=1.19a # crash me version
+create_default=no # default value for column
+create_index=yes # create index
+cross_join=yes # cross join (same as from a,b)
+date_as_string=no # String functions on date columns
+date_with_YY=yes # Supports YY-MM-DD 2000 compilant dates
+date_zero=yes # Supports 0000-00-00 dates
+double_quotes=yes # Double '' as ' in strings
+drop_index=yes # drop index
+except=yes # except
+except_all=yes # except all
+float_int_expr=yes # mixing of integer and float in expression
+foreign_key=yes # foreign keys
+foreign_key_syntax=yes # 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_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_+=yes # 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_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_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_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_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_odbc_abs=yes # Function ABS
+func_odbc_acos=yes # Function ACOS
+func_odbc_ascii=yes # Function ASCII
+func_odbc_asin=yes # Function ASIN
+func_odbc_atan=yes # Function ATAN
+func_odbc_atan2=yes # Function ATAN2
+func_odbc_ceiling=yes # Function CEILING
+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=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=no # Function DIFFERENCE()
+func_odbc_exp=yes # Function EXP
+func_odbc_extract=yes # 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=yes # Function ANSI HOUR
+func_odbc_ifnull=yes # Function IFNULL
+func_odbc_insert=no # Function INSERT
+func_odbc_lcase=yes # Function LCASE
+func_odbc_left=no # Function LEFT
+func_odbc_length=yes # Function REAL LENGTH
+func_odbc_length_without_space=error # 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
+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=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=yes # Function QUARTER
+func_odbc_radians=yes # Function RADIANS
+func_odbc_rand=no # Function RAND
+func_odbc_repeat=yes # Function REPEAT
+func_odbc_replace=yes # Function REPLACE
+func_odbc_right=no # Function RIGHT
+func_odbc_round=yes # Function ROUND(2 arg)
+func_odbc_rtrim=yes # Function RTRIM
+func_odbc_second=yes # Function SECOND
+func_odbc_sign=yes # Function SIGN
+func_odbc_sin=yes # Function SIN
+func_odbc_soundex=no # Function SOUNDEX
+func_odbc_space=yes # Function SPACE
+func_odbc_sqrt=yes # Function SQRT
+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=yes # Function UCASE
+func_odbc_user=yes # Function USER
+func_odbc_user()=no # Function USER()
+func_odbc_week=yes # Function WEEK
+func_odbc_year=yes # Function YEAR
+func_sql_+=yes # Function +, -, * and /
+func_sql_bit_length=yes # Function BIT_LENGTH
+func_sql_case=yes # Function CASE
+func_sql_cast=yes # Function CAST
+func_sql_char_length=yes # Function CHAR_LENGTH
+func_sql_character_length=yes # Function CHARACTER_LENGTH
+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=yes # Function LOWER
+func_sql_octet_length=yes # Function OCTET_LENGTH
+func_sql_position=yes # Function POSITION
+func_sql_session_user=no # Function SESSION_USER
+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=yes # Function UPPER
+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=yes # Group by alias
+group_by_null=yes # Test nulls in group by
+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_std=no # Group function STD
+group_func_extra_stddev=no # Group function STDDEV
+group_func_extra_variance=no # Group function VARIANCE
+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_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_sum=yes # Group function SUM
+group_functions=yes # Group functions
+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
+index_in_create=no # index in create table
+index_namespace=no # different namespace for index
+index_parts=no # index on column part (extension)
+insert_empty_string=yes # insert empty string
+insert_select=yes # insert INTO ... SELECT ...
+intersect=yes # intersect
+intersect_all=yes # intersect all
+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=yes # 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=65489 # max char() size
+max_column_name=254 # column name length
+max_columns=1000 # Columns in table
+max_conditions=5886 # OR and AND in WHERE
+max_expressions=126 # simple expressions
+max_index=+64 # max index
+max_index_length=+8192 # index length
+max_index_name=254 # index name length
+max_index_part_length=65485 # max index part length
+max_index_parts=63 # index parts
+max_index_varchar_part_length=65485 # index varchar part length
+max_row_length=2634 # max table row length (without blobs)
+max_row_length_with_null=2634 # table row length with nulls (without blobs)
+max_select_alias_name=254 # select alias name length
+max_stack_expression=48 # stacked expressions
+max_table_alias_name=+512 # table alias name length
+max_table_name=254 # table name length
+max_unique_index=+64 # unique indexes
+max_varchar_size=65489 # max varchar() size
+minus=no # minus
+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_left_outer_join=no # natural left outer join
+no_primary_key=yes # Tables without primary key
+null_concat_expr=yes # Is 'a' || NULL = NULL
+null_in_index=yes # null in index
+null_in_unique=no # null in unique
+null_num_expr=yes # Is 1+NULL = NULL
+odbc_left_outer_join=yes # left outer join odbc style
+operating_system=Linux 2.0.34 i586 # crash-me tested on
+order_by=yes # Order by
+order_by_alias=yes # Order by alias
+order_by_position=yes # Order by position
+primary_key_in_create=yes # primary key in create table
+query_size=65520 # query size
+quote_with_"=no # Allows ' and " as string markers
+recursive_subqueries=14 # recursive subqueries
+remember_end_space=no # Remembers end space in char()
+remember_end_space_varchar=yes # Remembers end space in varchar()
+repeat_string_size=254 # return string size from function
+right_outer_join=yes # right outer join
+select_constants=yes # Select constants
+select_string_size=252 # constant string size in SELECT
+select_table_update=yes # Update with sub select
+select_without_from=yes # SELECT without FROM
+server_version=SOLID Server - v.02.30.0026 (Linux ix86) # server version
+simple_joins=yes # ANSI SQL simple joins
+subqueries=yes # subqueries
+table_alias=yes # Table alias
+table_wildcard=yes # Select table_name.*
+transactions=yes # transactions
+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_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_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_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_line=no # Type line
+type_extra_long=no # Type long
+type_extra_long_raw=no # Type long raw
+type_extra_long_varbinary=yes # Type long varbinary
+type_extra_long_varchar(1_arg)=yes # Type long varchar(1 arg)
+type_extra_lseg=no # Type lseg
+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_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_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)=yes # Type binary(1 arg)
+type_odbc_datetime=no # Type datetime
+type_sql_smallint=yes # Type smallint
+type_odbc_tinyint=yes # Type tinyint
+type_odbc_varbinary(1_arg)=yes # 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)=no # 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=no # Type double
+type_sql_double_precision=yes # Type double precision
+type_sql_float=yes # Type float
+type_extra_float(2_arg)=yes # Type float(1 arg)
+type_sql_int=yes # Type int
+type_sql_integer=yes # Type integer
+type_sql_interval_year=no # Type interval year
+type_sql_numeric(2_arg)=yes # Type numeric(2 arg)
+type_sql_real=yes # Type real
+type_sql_time=yes # Type time
+type_sql_timestamp=yes # Type timestamp
+type_sql_varchar(1_arg)=yes # Type varchar(1 arg)
+union=yes # union
+union_all=yes # union all
+unique_in_create=yes # unique in create table
+unique_null_in_create=no # unique null in create
+views=yes # views
+where_string_size=254 # constant string size in where
diff --git a/sql-bench/limits/sybase.cfg b/sql-bench/limits/sybase.cfg
new file mode 100644
index 00000000000..910c8e9f3b1
--- /dev/null
+++ b/sql-bench/limits/sybase.cfg
@@ -0,0 +1,422 @@
+#This file is automaticly generated by crash-me 1.19a
+
+NEG=yes # update of column= -column
+alter_add_col=yes # Alter table add column
+alter_change_col=no # Alter table change column
+alter_drop_col=yes # Alter table drop column
+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=yes # binary items (0x41)
+case_insensitive_strings=no # case insensitive compare
+char_is_space_filled=no # char are space filled
+column_alias=yes # Column alias
+comment_#=no # # as comment
+comment_--=yes # -- as comment
+comment_/**/=yes # /* */ as comment
+compute=yes # Compute
+connections=25 # Simultaneous connections
+crash_me_safe=yes # crash me safe
+crash_me_version=1.19a # crash me version
+create_default=no # default value for column
+create_index=yes # create index
+cross_join=no # cross join (same as from a,b)
+date_as_string=no # String functions on date columns
+date_with_YY=no # Supports YY-MM-DD dates
+date_zero=no # Supports 0000-00-00 dates
+double_quotes=yes # Double '' as ' in strings
+drop_index=with 'table.index' # drop index
+except=no # except
+except_all=no # except all
+float_int_expr=yes # mixing of integer and float in expression
+foreign_key=yes # foreign keys
+foreign_key_syntax=yes # foreign key syntax
+full_outer_join=no # full outer join
+func_extra_!=no # Function NOT as '!' in SELECT
+func_extra_%=yes # Function MOD as %
+func_extra_&=yes # 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_atn2=yes # 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=yes # Function CHARINDEX
+func_extra_chr=no # Function CHR
+func_extra_concat_as_+=yes # Function concatenation with +
+func_extra_concat_list=no # Function CONCAT(list)
+func_extra_convert=yes # Function CONVERT
+func_extra_cosh=no # Function COSH
+func_extra_date_format=no # Function DATE_FORMAT
+func_extra_dateadd=yes # Function DATEADD
+func_extra_datediff=yes # Function DATEDIFF
+func_extra_datename=yes # Function DATENAME
+func_extra_datepart=yes # 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=yes # 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_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_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_patindex=yes # 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=yes # Function REPLICATE
+func_extra_reverse=yes # 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=yes # Function STR
+func_extra_strcmp=no # Function STRCMP
+func_extra_stuff=yes # Function STUFF
+func_extra_substrb=no # Function SUBSTRB
+func_extra_substring_index=no # Function SUBSTRING_INDEX
+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_|=yes # Function | (bitwise or)
+func_extra_||=no # Function OR as '||'
+func_odbc_abs=yes # Function ABS
+func_odbc_acos=yes # Function ACOS
+func_odbc_ascii=yes # Function ASCII
+func_odbc_asin=yes # Function ASIN
+func_odbc_atan=yes # Function ATAN
+func_odbc_atan2=no # Function ATAN2
+func_odbc_ceiling=yes # Function CEILING
+func_odbc_char=yes # Function CHAR
+func_odbc_concat=no # 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_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=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=yes # Function LOG
+func_odbc_log10=yes # Function LOG10
+func_odbc_ltrim=yes # 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=yes # Function PI
+func_odbc_power=yes # Function POWER
+func_odbc_quarter=no # Function QUARTER
+func_odbc_radians=error # Function RADIANS
+func_odbc_rand=yes # Function RAND
+func_odbc_repeat=no # Function REPEAT
+func_odbc_replace=no # Function REPLACE
+func_odbc_right=yes # Function RIGHT
+func_odbc_round=yes # Function ROUND(2 arg)
+func_odbc_rtrim=yes # Function RTRIM
+func_odbc_second=no # Function SECOND
+func_odbc_sign=yes # Function SIGN
+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=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=no # 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_sql_+=yes # Function +, -, * and /
+func_sql_bit_length=no # Function BIT_LENGTH
+func_sql_case=yes # Function CASE
+func_sql_cast=no # Function CAST
+func_sql_char_length=yes # Function CHAR_LENGTH
+func_sql_character_length=yes # Function CHARACTER_LENGTH
+func_sql_concat_as_||=no # 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=yes # Function LOWER
+func_sql_octet_length=yes # Function OCTET_LENGTH
+func_sql_position=no # Function POSITION
+func_sql_session_user=no # Function SESSION_USER
+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=yes # Function UPPER
+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 # Test nulls in group by
+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_std=no # Group function STD
+group_func_extra_stddev=no # Group function STDDEV
+group_func_extra_variance=no # Group function VARIANCE
+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_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_sum=yes # Group function SUM
+group_functions=yes # Group functions
+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
+index_in_create=no # index in create table
+index_namespace=yes # different namespace for index
+index_parts=no # index on column part (extension)
+insert_empty_string=yes # insert empty string
+insert_select=yes # insert INTO ... SELECT ...
+intersect=no # intersect
+intersect_all=no # intersect all
+join_tables=16 # tables in join
+left_outer_join=no # left outer join
+left_outer_join_using=no # left outer join using
+like_with_column=yes # 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=10 # big expressions
+max_char_size=255 # max char() size
+max_column_name=30 # column name length
+max_columns=250 # Columns in table
+max_conditions=250 # OR and AND in WHERE
+max_expressions=1051 # simple expressions
+max_index=+64 # max index
+max_index_length=600 # index length
+max_index_name=30 # index name length
+max_index_part_length=255 # max index part length
+max_index_parts=15 # index parts
+max_index_varchar_part_length=255 # index varchar part length
+max_row_length=1960 # max table row length (without blobs)
+max_row_length_with_null=1941 # table row length with nulls (without blobs)
+max_select_alias_name=30 # select alias name length
+max_stack_expression=97 # stacked expressions
+max_table_alias_name=30 # table alias name length
+max_table_name=30 # table name length
+max_text_size=65504 # max text or blob size
+max_unique_index=+64 # unique indexes
+max_varchar_size=255 # max varchar() size
+minus=yes # minus
+minus_neg=no # Calculate 1--1
+multi_drop=yes # 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_left_outer_join=no # natural left outer join
+no_primary_key=yes # Tables without primary key
+null_concat_expr=error # Is 'a' + NULL = NULL
+null_in_index=yes # null in index
+null_in_unique=yes # null in unique
+null_num_expr=yes # Is 1+NULL = NULL
+odbc_left_outer_join=yes # left outer join odbc style
+operating_system=Windows NT Version 4.0 # crash-me tested on
+order_by=yes # Order by
+order_by_alias=yes # Order by alias
+order_by_position=yes # Order by position
+primary_key_in_create=yes # primary key in create table
+query_size=65535 # query size
+quote_with_"=yes # Allows ' and " as string markers
+recursive_subqueries=15 # recursive subqueries
+remember_end_space=no # Remembers end space in char()
+remember_end_space_varchar=no # Remembers end space in varchar()
+right_outer_join=no # right outer join
+select_constants=yes # Select constants
+select_string_size=65526 # constant string size in SELECT
+select_table_update=yes # Update with sub select
+select_without_from=yes # SELECT without FROM
+server_version=Sybase enterprise 11.5 NT # server version
+simple_joins=yes # ANSI SQL simple joins
+subqueries=yes # subqueries
+table_alias=no # Table alias
+table_wildcard=yes # Select table_name.*
+transactions=error # transactions
+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_circle=no # Type circle
+type_extra_clob=no # Type clob
+type_extra_datetime=yes # Type datetime
+type_extra_enum(1_arg)=no # Type enum(1 arg)
+type_sql_float(1_arg)=yes # Type float(1 arg)
+type_extra_float4=no # Type float4
+type_extra_float8=no # Type float8
+type_extra_image=yes # Type image
+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_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_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=yes # Type money
+type_sql_nchar(1_arg)=yes # 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_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=yes # Type smalldatetime
+type_extra_smallfloat=no # Type smallfloat
+type_extra_smallmoney=yes # Type smallmoney
+type_extra_text=yes # Type text
+type_extra_text(1_arg)=no # Type text(1 arg)
+type_extra_timespan=no # Type timespan
+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)=yes # Type binary(1 arg)
+type_odbc_datetime=yes # Type datetime
+type_sql_smallint=yes # Type smallint
+type_odbc_tinyint=yes # Type tinyint
+type_odbc_varbinary(1_arg)=yes # Type varbinary(1 arg)
+type_sql_bit=yes # 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_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_extra_double=no # Type double
+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_int=yes # Type int
+type_sql_integer=yes # Type integer
+type_sql_interval_year=no # Type interval year
+type_sql_numeric(2_arg)=yes # Type numeric(2 arg)
+type_sql_real=yes # Type real
+type_sql_time=no # Type time
+type_sql_timestamp=yes # Type timestamp
+type_sql_varchar(1_arg)=yes # Type varchar(1 arg)
+union=yes # union
+union_all=yes # union all
+unique_in_create=yes # unique in create table
+unique_null_in_create=no # unique null in create
+views=yes # views
+where_string_size=255 # constant string size in where
diff --git a/sql-bench/print-limit-table b/sql-bench/print-limit-table
new file mode 100755
index 00000000000..787eb88ae07
--- /dev/null
+++ b/sql-bench/print-limit-table
@@ -0,0 +1,360 @@
+#!/usr/bin/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
+#
+# Output a html table with a compare of all servers
+#
+$cmp_server="mysql"; # Get limit names from here
+$full_html=1;
+$opt_txt=0;
+
+if ($#ARGV < 0)
+{
+ @ARGV=glob("limits/*.cfg");
+ $skip_header=0;
+}
+else
+{
+ $skip_header=1;
+}
+
+foreach (@ARGV)
+{
+ /([^\/\.]*)\.cfg$/;
+ $server=$1;
+ if ($server eq $cmp_server)
+ {
+ unshift(@limits,read_config_data($server,$_));
+ }
+ else
+ {
+ push(@limits,read_config_data($server,$_));
+ }
+}
+
+@global_limits= sort keys(%all_limits);
+find_match('group_functions|functions'); # Don't report these
+
+if ($full_html)
+{
+ if (!$skip_header)
+ {
+ print "<!doctype HTML public \"-//W3O//DTD W3 HTML3.0//EN\"><HTML>";
+ }
+ print <<EOF;
+<!doctype HTML public \"-//W3O//DTD W3 HTML3.0//EN\"><HTML>
+<HEAD><TITLE>Database comparison table</TITLE></HEAD>
+<BODY>
+<center><h3>Database comparison table generated with <B>crash-me</B></h3></center>
+<table><tr><td><IMG SRC="icons/mysql-03.gif" ALT=logo></td>
+<td>You can get a copy of <B>crash-me</B> from the MySQL 3.23 distribution at
+<A HREF="http://www.mysql.com">http://www.mysql.com</A>.
+</td></tr></table>
+<br>
+<strong>crash-me</strong> is a program that automatically detects
+limits and capabilities in a SQL server. We at TCX have worked very
+hard to make crash-me as fair and accurate as possible, but there is
+always a small possibility that some particular tests fails for some
+database, even if the database has the capability. We are always
+willing to correct this as soon as this comes to our attention. Some
+tests may fail because the database in questions does not follow
+<B>ANSI SQL 99</B> or <B>ODBC 3.0</B> but in this case we regard this
+as a failure in the database.
+<br><br>
+Note that crash-me test the <B>ODBC</B> functionality by executing
+SQL commands through the perl DBD driver. As some SQL servers implements
+the <B>ODBC</B> functionality in the <B>ODBC</B> driver, crash-me may
+tell you that the SQL server doesn\'t support some functionality, even
+if this is supported when you are using the SQL server through <B>ODBC</B>.
+<br><br>
+Note that even if crash-me reports that some feature is missing, not
+supported, or doesn\'t work it doesn\'t mean that the SQL server
+doesn\'t follow the SQL standard or that you can\'t do the operation
+in some other way. crash-me just tells you how the SQL server works
+if you send it some specific query. The result is however often useful
+for applications writers that tries to write portable code and needs to be
+aware of the differences between different SQL servers.
+<br><br>
+TCX is trying to add as much tests to the crash-me program as they can
+but it\'s always possible that some database vendor specific functions
+/ queries aren\'t tested. If you find some entries not tested on a
+database please let us know and try to patch the crash-me program your
+self or give us some example queries so we can add those entries. We
+are always open for suggestions for adding things to the crash-me
+program. The crash-me program is also our input reference for the
+MySQL benchmark program.<br>
+
+<B>Note:</B>
+The crash-me table is generated from databases started with default
+parameters. If this is not the case, this is noted in the comment row.
+Some detected limits may also be configurable, OS dependent, depend of the
+Perl DBI driver or depending on the license of the used database version.
+<BR><BR>
+The following markers are used in the comparison table
+<table border=1>
+<tr><th>Marker</th><th>Description</th></tr>
+<tr><td><IMG SRC=\"images/ok.gif\" WIDTH=20 HEIGHT=16 ALT=\"yes\"></td>
+<td>Function is supported</td></tr>
+<tr><td><IMG SRC=\"images/no.gif\" WIDTH=14 HEIGHT=14 ALT=\"no\"></td>
+<td>Function is not supported</td></tr>
+<tr><td><IMG SRC=\"images/error.gif\" WIDTH=20 HEIGHT=16 ALT=\"error\"></td>
+<td>Function exists but didn\'t return expected result. This usually means that
+the database is using some non standard extension for the option in question</td></tr>
+<tr><td>ignored</td><td>Function doesn\'t give an error from the server but it
+doesn\'t do anything. One can probably do the same action with some other
+command</td></tr>
+<tr><td>nonstandard</td><td>Function exists but doesn\'t work according to
+<B>ANSI SQL 92</B> or <B>ODBC 3.0</B></td></tr>
+<tr><td>&nbsp;</td><td>Not relevant or not tested with the database</td></tr>
+<tr><td>+number</td><td>At least <b>number</b> operations is supported</td></tr>
+<tr><td><IMG SRC=\"images/warning.gif\" WIDTH=28 HEIGHT=28 ALT=\"warning\"></td>
+<td><B>Anyone with normal access to the database server can take it down, possible
+forever!</B></td> </table>
+
+<center><h3>The <B>crash-me</B> comparisons</h3></center>
+EOF
+}
+
+print "<TABLE BORDER=2><TR ALIGN=left>\n";
+#
+# printer server names
+#
+
+$columns=$#limits+2;
+print "<th>Function</th>\n";
+foreach $server (@limits)
+{
+ print "<td>$server->[1]->{'server_version'}</td>";
+ $server->[1]->{'server_version'} =~ /^(\S*)/;
+ push(@server_names,$1);
+}
+find_match("server_version"); # Mark used
+print "</tr>\n";
+
+print_match("Crash-me information",'crash_me|operating_system|user_comment',undef(),1);
+print_match("ANSI SQL 92 types","type_sql");
+print_match("ODBC 3.0 types","type_odbc");
+print_match("Other types","type_extra");
+print_match("Constraints and type modifiers","constraint|foreign|primary|unique|default","alter|max_unique");
+print_match("ANSI SQL 92 functions","func_sql","group");
+print_match("ODBC 3.0 functions","func_odbc","group");
+print_match("Other functions","func_extra","group");
+print_match("Functions in WHERE","func_where","group");
+print_match("ANSI SQL 92 group functions","group_func_sql");
+print_match("Other group functions","group_func");
+print_match("Function use","NEG|minus_neg|like|null.*expr");
+print_match("Order by and group by","order|having|group");
+print_match("Join methods",'join|subqueries|multi_table|select_table_update');
+print_match("String handling","string|select_constant|quote_with|double_quotes|end_space");
+print_match("Quoting","quote");
+print_match("Name limits","name");
+print_match("Index limits",'index|primary|unique');
+print_match("Type limits",'char|float|binary|text_size|date|end_space');
+print_match("Expression limits",'expression|conditions|select_limit');
+print_match("Comments",'comment');
+print_match("ALTER TABLE",'alter');
+print_options("Other features");
+print_match("Other limits",'\S');
+
+print "</table>\n";
+
+if ($full_html)
+{
+ print <<EOF;
+<BR>
+This information is provided by TCX so one can get the real limitations from
+the database server (not the information from sales managers!). Hopefully the
+above information will make it easier for you to find a database server that
+has the functionality you need and that you can rely on!
+<BR><BR>
+TCX will continue to extend <b>crash-me</b> and add more database servers
+to the above chart. We are also very interested in new tests so if you have
+any suggestions, please mail us (or even better, send us code).
+<BR>
+We are also working on the <B>MySQL</B> <A HREF ="/benchmark.html">benchmark</A>
+to help users see how fast a database is when doing different typical things.
+<br>
+<IMG SRC="images/eyesleft.gif" HEIGHT=9 WIDTH=582 ALT="==============================================">
+<ADDRESS> You can direct questions about crash-me and the benchmark to the
+<A HREF=\"http://www.tcx.se/mail.html\">MySQL mailing list</A>.
+</ADDRESS>
+</BODY></HTML>
+EOF
+} exit 0;
+
+
+sub read_config_data
+{
+ my ($server,$file)=@_;
+ my (%limits,%prompts);
+ open(CONFIG_FILE,"<$file") ||
+ die "Can't open configure file $file\n";
+ while (<CONFIG_FILE>)
+ {
+ chomp;
+ if (/^(\S+)=([^\#]*[^\#\s])\s*(\# .*)*$/)
+ {
+ $all_limits{$1}=1;
+ $limits{$1}=$2;
+ $prompts{$1}=length($3) ? substr($3,2) : "";
+ }
+ elsif (!/^\s*$/ && !/^\#/)
+ {
+ die "Wrong config row: $_\n";
+ }
+ }
+ close CONFIG_FILE;
+ return ([$server,\%limits,\%prompts]);
+}
+
+
+sub find_match
+{
+ my ($find,$find_not)=@_;
+ my ($key,@res);
+
+ foreach $key (@global_limits)
+ {
+ if ($key =~ /$find/ && (!defined($find_not) || !($key =~ /$find_not/)))
+ {
+ push(@res,$key);
+ $key="";
+ }
+ }
+ return @res;
+}
+
+
+sub print_match
+{
+ my ($header,$match,$not_match,$no_server_names)=@_;
+ my ($key);
+ if ($opt_txt)
+ {
+ print "\n$header\n";
+ }
+ else
+ {
+ print "<tr><th colspan=$columns ALIGN=center>$header</th></tr>\n";
+ }
+ print_server_names() if (!$no_server_names);
+ foreach $key (find_match($match,$not_match))
+ {
+ print_key($key,$key eq "crash_me_safe" ? 1: 0);
+ }
+}
+
+
+sub print_options
+{
+ my ($header)=@_;
+ if ($opt_txt)
+ {
+ print "\n$header\n";
+ }
+ else
+ {
+ print "<tr><th colspan=$columns ALIGN=center>$header</th></tr>\n";
+ }
+ print_server_names();
+ foreach $key (@global_limits)
+ {
+ if ($key && !($limits[0]->[1]{$key} =~ /^\d+$/))
+ {
+ print_key($key,0);
+ $key="";
+ }
+ }
+}
+
+
+sub print_key
+{
+ my ($key,$fatal)=@_;
+ my ($i,$server,$option,$tmp);
+ $option=$key;
+ for ($i=0 ; $i < $columns ; $i++)
+ {
+ if ($limits[$i]->[2]{$key})
+ {
+ $option=$limits[$i]->[2]{$key};
+ last;
+ }
+ }
+ $option =~ s/>/&gt\;/g;
+ $option =~ s/</&lt\;/g;
+
+ if ($opt_txt)
+ {
+ print "\n$option\t";
+ foreach $server (@limits)
+ {
+ $tmp=$server->[1]->{$key};
+ $tmp="yes" if ($tmp eq "yes");
+ $tmp="no" if ($tmp eq "no" && !$fatal);
+ $tmp="warning" if ($tmp eq "no" && $fatal);
+ $tmp="error" if ($tmp eq "error");
+ $tmp="" if (!defined($tmp) || $tmp eq "");
+ print "\t$tmp";
+ }
+ }
+ else
+ {
+ $option =~ s/ /&nbsp;/g;
+ print "<tr><td>$option</td>";
+ foreach $server (@limits)
+ {
+ $tmp=$server->[1]->{$key};
+ $tmp="<IMG SRC=\"images/ok.gif\" WIDTH=20 HEIGHT=16 ALT=\"yes\">" if ($tmp eq "yes" && !$fatal);
+ $tmp="<IMG SRC=\"images/thumbs_up.gif\" ALT=\"yes\">" if ($tmp eq "yes" && $fatal);
+ $tmp="<IMG SRC=\"images/no.gif\" WIDTH=14 HEIGHT=14 ALT=\"no\">" if ($tmp eq "no" && !$fatal);
+ $tmp="<IMG SRC=\"images/warning.gif\" WIDTH=28 HEIGHT=28 ALT=\"warning\">" if ($tmp eq "no" && $fatal);
+ $tmp="<IMG SRC=\"images/error.gif\" WIDTH=20 HEIGHT=16 ALT=\"error\">" if ($tmp eq "error");
+ $tmp="&nbsp;" if (!defined($tmp) || $tmp eq "");
+ print "<td>$tmp</td>";
+ }
+ print"</tr>\n";
+ }
+}
+
+
+sub print_server_names
+{
+ my ($server);
+
+ if ($opt_txt)
+ {
+ my $tab;
+ $tab="";
+ foreach $server (@server_names)
+ {
+ print "$tab$server";
+ $tab="\t";
+ }
+ print "\n";
+ }
+ else
+ {
+ print "<tr><th></th>";
+ foreach $server (@server_names)
+ {
+ print "<th>$server</th>";
+ }
+ print "</tr>\n";
+ }
+}
+
diff --git a/sql-bench/pwd.bat b/sql-bench/pwd.bat
new file mode 100644
index 00000000000..104fd349d4e
--- /dev/null
+++ b/sql-bench/pwd.bat
@@ -0,0 +1,2 @@
+@echo off
+@cd
diff --git a/sql-bench/run-all-tests.sh b/sql-bench/run-all-tests.sh
new file mode 100755
index 00000000000..cbcafce3117
--- /dev/null
+++ b/sql-bench/run-all-tests.sh
@@ -0,0 +1,288 @@
+#!@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
+#
+# This program runs all test that starts with 'test-' and sums
+# the results that the program prints.
+# Each time result should be of the form:
+# Time for|to KEYWORD (number_of_runs) 'other info': timestr()
+#
+# All options to this script is passed to all test program.
+# useful options:
+# --fast --force --lock-tables
+# --server ==> mysql (default) / mSQL / Pg (postgres) / Solid
+# --user ==> the user with permission to create / drop / select
+# --pass ==> password for the user
+# --cmp ==> Compare --server with one of the others (mysql/mSQL/Pg/Solid)
+# --comments ==> everything you want to say such as the extra options you
+# gave to the db server. (use --comments="xxx xxx xxx"
+# --machine ==> Give a OS/machine id for your logfiles.
+# --log ==> puts output in output/RUN-server-machine-cmp-$opt_cmp
+
+use DBI;
+
+$opt_silent=1; # Don't write header
+$prog_args="";
+foreach $arg (@ARGV)
+{
+ $prog_args.="'" . $arg . "' ";
+}
+
+chomp($pwd = `pwd`); $pwd = "." if ($pwd eq '');
+require "$pwd/bench-init.pl" || die "Can't read Configuration file: $!\n";
+$opt_silent=0;
+$perl=$^X;
+$machine=machine();
+$redirect= !($machine =~ /windows/i || $machine =~ "^NT\s") ? "2>&1" : "";
+$dir= ($pwd =~ /\\/) ? '\\' : '/'; # directory symbol for shell
+
+$prog_count=$errors=0;
+
+if ($opt_cmp) {
+ $filename = "$opt_server$opt_suffix-" . machine_part() . "-cmp-$opt_cmp";
+} else {
+ $filename = "$opt_server$opt_suffix-" . machine_part();
+}
+
+if (! -d $opt_dir)
+{
+ if (-e $opt_dir)
+ {
+ die "$opt_dir isn't a directory\n";
+ }
+ mkdir $opt_dir,0777 || die "Can't create directory: $opt_dir\n";
+}
+
+if ($opt_skip_test) {
+ (@skip_tests) = split(/,\s*/, $opt_skip_test);
+}
+
+if ($opt_old_headers)
+{
+ read_headers("$opt_dir/RUN-$filename");
+}
+else
+{
+ $server_version=$server->version();
+}
+
+if (!$opt_log)
+{
+ open(LOG,">&STDOUT");
+}
+else
+{
+ open(LOG, "> $opt_dir/RUN-$filename") ||
+ die "Can't write to $opt_dir/RUN-$filename: $!\n";
+}
+
+select(LOG);
+$|=1;
+
+print "Benchmark DBD suite: $benchmark_version\n";
+print "Date of test: $date\n";
+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";
+
+
+$estimated=$warning=$got_warning=0;
+while (<test-*>)
+{
+ next if (/\.sh$/); # configure script
+ next if (/\-fork$/); # test script
+ $prog_count++;
+ /test-(.*)$/; # Remove test from name
+ $prog=$1;
+ $skip_prog = 0;
+ foreach $skip_this (@skip_tests) {
+ if ($prog =~ /$skip_this/i) {
+ $skip_prog = 1;
+ last;
+ }
+ }
+ print "$prog: ";
+ if ((!$opt_use_old_results) && (!$skip_prog))
+ {
+ if (system("$perl ./test-$prog $prog_args > \"$opt_dir$dir$prog-$filename\" $redirect"))
+ {
+ printf STDERR "Warning: Can't execute $prog. Check the file '$opt_dir$dir$prog-$filename'\n";
+ die "aborted" if ($opt_die_on_errors);
+ }
+ }
+ open(TEST,"$opt_dir/$prog-$filename");
+ $last_line="";
+ while(<TEST>)
+ {
+ chomp;
+ $last_line=$_ if (!(/^\s*$/)); # Search after last line
+ }
+ if ($last_line =~ /Total time:/i)
+ {
+ print $last_line . "\n";
+ open(TEST,"$opt_dir/$prog-$filename");
+ while (<TEST>)
+ {
+ if (/^(estimated |)time (to|for) ([^\s:]*)\s*\((\d*)(:\d*)*\)[^:]*:\s*([\d.]+) .*secs \(\s*([^\s]*) usr\s*\+*\s*([^\s]*) sys.*=\s+([\d.]*)\s+cpu/i)
+ {
+ $arg=$summa{$3};
+ if (!defined($arg))
+ {
+ $summa{$3}= [ $4,$6,$7,$8,$9,""];
+ }
+ else
+ {
+ $arg->[0]+=$4;
+ $arg->[1]+=$6;
+ $arg->[2]+=$7;
+ $arg->[3]+=$8;
+ $arg->[4]+=$9;
+ }
+ $prog_sum[0]+=$4;
+ $prog_sum[1]+=$6;
+ $prog_sum[2]+=$7;
+ $prog_sum[3]+=$8;
+ $prog_sum[4]+=$9;
+ if (length($1))
+ {
+ $summa{$3}->[5].="+";
+ $estimated=1;
+ }
+ if ($got_warning)
+ {
+ $summa{$3}->[5].="?";
+ $warning=1;
+ $got_warning=0;
+ }
+ }
+ elsif (/^warning/i)
+ {
+ $got_warning=1;
+ }
+ else
+ {
+ $got_warning=0;
+ }
+ }
+ if ($opt_debug)
+ {
+ print "Summary for $prog: ", join(" ",@prog_sum), "\n";
+ }
+ }
+ else
+ {
+ $errors++;
+ print "Failed ($opt_dir/$prog-$filename)\n";
+ }
+}
+
+print "\n";
+if (!$errors)
+{
+ print "All $prog_count test executed successfully\n";
+}
+else
+{
+ print "Of $prog_count tests, $errors tests didn't work\n";
+}
+if ($estimated)
+{
+ print "Tests with estimated time have a + at end of line\n"
+}
+if ($warning)
+{
+ print "Tests with didn't return the correct result have a ? at end of line\n";
+}
+
+if (%summa)
+{
+ @total=(0,0,0,0,0,"");
+ print "\nTotals per operation:\n";
+ print "Operation seconds usr sys cpu tests\n";
+ foreach $key (sort(keys %summa))
+ {
+ $arg=$summa{$key};
+ printf("%-35.35s %7.2f %7.2f %7.2f %7.2f %7d %s\n",
+ $key,$arg->[1],$arg->[2],$arg->[3],$arg->[4],$arg->[0],
+ $arg->[5]);
+
+ for ($i=0 ; $i < 5 ; $i++)
+ {
+ $total[$i]+=$arg->[$i];
+ }
+ $total[5].=$arg->[$i];
+ }
+ printf("%-35.35s %7.2f %7.2f %7.2f %7.2f %7d %s\n",
+ "TOTALS",$total[1],$total[2],$total[3],$total[4],$total[0],
+ $total[5]);
+}
+
+select(STDOUT);
+if ($opt_log)
+{
+ print "Test finished. You can find the result in:\n$opt_dir/RUN-$filename\n";
+}
+
+
+#
+# Read headers from an old benchmark run
+#
+
+sub read_headers
+{
+ my ($filename)=@_;
+
+ # Clear current values
+ $benchmark_version=$date=$machine=$server_version="";
+
+ open(TMP, "<$filename") || die "Can't open $filename\n";
+ while (<TMP>)
+ {
+ chop;
+ if (/^Benchmark DBD.*:\s+(.*)$/)
+ {
+ $benchmark_version=$1;
+ }
+ elsif (/^Date of.*:\s+(.*)/)
+ {
+ $date=$1;
+ }
+ elsif (/^Running.*:\s+(.*)$/)
+ {
+ $machine=$1;
+ }
+ elsif (/^Arguments.*:\s+(.*)$/)
+ {
+ $log_prog_args=$1;
+ }
+ elsif (/^Comments.*:\s+(.*)$/)
+ {
+ $opt_comments=$1;
+ }
+ elsif (/^Limits.*:\s+(.*)$/)
+ {
+ $opt_cmp=$1;
+ }
+ elsif (/^Server ver.*:\s+(.*)$/)
+ {
+ $server_version=$1;
+ }
+ }
+ close(TMP);
+}
diff --git a/sql-bench/server-cfg.sh b/sql-bench/server-cfg.sh
new file mode 100755
index 00000000000..f4d16b908b7
--- /dev/null
+++ b/sql-bench/server-cfg.sh
@@ -0,0 +1,3030 @@
+#@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
+#
+# The configuration file for the DBI/DBD tests on different databases ....
+# You will need the DBD module for the database you are running.
+# Monty made this bench script and I (Luuk de Boer) rewrote it to DBI/DBD.
+# Monty rewrote this again to use packages.
+#
+# Each database has a different package that has 3 functions:
+# new Creates a object with some standard slot
+# version Version number of the server
+# create Generates commands to create a table
+#
+
+#
+# First some global functions that help use the packages:
+#
+
+sub get_server
+{
+ my ($name,$host,$database,$odbc,$machine)=@_;
+ my ($server);
+ if ($name =~ /mysql/i)
+ { $server=new db_MySQL($host, $database, $machine); }
+ elsif ($name =~ /pg/i)
+ { $server= new db_Pg($host,$database); }
+ elsif ($name =~ /msql/i)
+ { $server= new db_mSQL($host,$database); }
+ elsif ($name =~ /solid/i)
+ { $server= new db_Solid($host,$database); }
+ elsif ($name =~ /Empress/i)
+ { $server= new db_Empress($host,$database); }
+ elsif ($name =~ /Oracle/i)
+ { $server= new db_Oracle($host,$database); }
+ elsif ($name =~ /Access/i)
+ { $server= new db_access($host,$database); }
+ elsif ($name =~ /Informix/i)
+ { $server= new db_Informix($host,$database); }
+ elsif ($name =~ /ms-sql/i)
+ { $server= new db_ms_sql($host,$database); }
+ elsif ($name =~ /sybase/i)
+ { $server= new db_sybase($host,$database); }
+ elsif ($name =~ /Adabas/i) # Adabas has two drivers
+ {
+ $server= new db_Adabas($host,$database);
+ if ($name =~ /AdabasD/i)
+ {
+ $server->{'data_source'} =~ s/:Adabas:/:AdabasD:/;
+ }
+ }
+ elsif ($name =~ /DB2/i)
+ { $server= new db_db2($host,$database); }
+ elsif ($name =~ /Mimer/i)
+ { $server= new db_Mimer($host,$database); }
+ elsif ($name =~ /interBase/i)
+ { $server= new db_interbase($host,$database); }
+ else
+ {
+ die "Unknown sql server name used: $name\nUse one of: Access, Adabas, AdabasD, Empress, 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";
+ }
+ if ($name =~ /_ODBC$/i || defined($odbc) && $odbc)
+ {
+ if (! ($server->{'data_source'} =~ /^([^:]*):([^:]+):([^:]*)/ ))
+ {
+ die "Can't find databasename in data_source: '" .
+ $server->{'data_source'}. "'\n";
+ }
+ if ($3) {
+ $server->{'data_source'} = "$1:ODBC:$3";
+ } else {
+ $server->{'data_source'} = "$1:ODBC:$database";
+ }
+ }
+ return $server;
+}
+
+sub all_servers
+{
+ return ["Access", "Adabas", "DB2", "Empress", "Oracle", "Informix",
+ "InterBase", "Mimer", "mSQL", "MS-SQL", "MySQL", "Pg", "Solid",
+ "Sybase"];
+}
+
+#############################################################################
+# First the configuration for MySQL off course :-)
+#############################################################################
+
+package db_MySQL;
+
+sub new
+{
+ my ($type,$host,$database,$machine)= @_;
+ my $self= {};
+ my %limits;
+ bless $self;
+
+ $self->{'cmp_name'} = "mysql";
+ $self->{'data_source'} = "DBI:mysql:$database:$host";
+ $self->{'limits'} = \%limits;
+ $self->{'smds'} = \%smds;
+ $self->{'blob'} = "blob";
+ $self->{'text'} = "text";
+ $self->{'double_quotes'} = 1; # Can handle: 'Walker''s'
+
+ $limits{'max_conditions'} = 9999; # (Actually not a limit)
+ $limits{'max_columns'} = 2000; # Max number of columns in table
+ # Windows can't handle that many files in one directory
+ $limits{'max_tables'} = ($machine =~ "^win") ? 5000 : 65000;
+ $limits{'max_text_size'} = 65000; # Max size with default buffers.
+ $limits{'query_size'} = 1000000; # Max size with default buffers.
+ $limits{'max_index'} = 16; # Max number of keys
+ $limits{'max_index_parts'} = 16; # Max segments/key
+ $limits{'max_column_name'} = 64; # max table and column name
+
+ $limits{'join_optimizer'} = 1; # Can optimize FROM tables
+ $limits{'load_data_infile'} = 1; # Has load data infile
+ $limits{'lock_tables'} = 1; # Has lock tables
+ $limits{'functions'} = 1; # Has simple functions (+/-)
+ $limits{'group_functions'} = 1; # Have group functions
+ $limits{'group_func_sql_min_str'} = 1; # Can execute MIN() and MAX() on strings
+ $limits{'group_distinct_functions'}= 1; # Have count(distinct)
+ $limits{'select_without_from'}= 1; # Can do 'select 1';
+ $limits{'multi_drop'} = 1; # Drop table can take many tables
+ $limits{'subqueries'} = 0; # Doesn't support sub-queries.
+ $limits{'left_outer_join'} = 1; # Supports left outer joins
+ $limits{'table_wildcard'} = 1; # Has SELECT table_name.*
+ $limits{'having_with_alias'} = 1; # Can use aliases in HAVING
+ $limits{'having_with_group'} = 1; # Can use group functions in HAVING
+ $limits{'like_with_column'} = 1; # Can use column1 LIKE column2
+ $limits{'order_by_position'} = 1; # Can use 'ORDER BY 1'
+ $limits{'group_by_position'} = 1; # Can use 'GROUP BY 1'
+ $limits{'alter_table'} = 1; # Have ALTER TABLE
+ $limits{'alter_add_multi_col'}= 1; #Have ALTER TABLE t add a int,add b int;
+ $limits{'alter_table_dropcol'}= 1; # Have ALTER TABLE DROP column
+ $limits{'multi_value_insert'} = 1; # Have INSERT ... values (1,2),(3,4)
+
+ $limits{'group_func_extra_std'} = 1; # Have group function std().
+
+ $limits{'func_odbc_mod'} = 1; # Have function mod.
+ $limits{'func_extra_%'} = 1; # Has % as alias for mod()
+ $limits{'func_odbc_floor'} = 1; # Has func_odbc_floor function
+ $limits{'func_extra_if'} = 1; # Have function if.
+ $limits{'column_alias'} = 1; # Alias for fields in select statement.
+ $limits{'NEG'} = 1; # Supports -id
+ $limits{'func_extra_in_num'} = 1; # Has function in
+ $limits{'limit'} = 1; # supports the limit attribute
+
+ $smds{'time'} = 1;
+ $smds{'q1'} = 'b'; # with time not supp by mysql ('')
+ $smds{'q2'} = 'b';
+ $smds{'q3'} = 'b'; # with time ('')
+ $smds{'q4'} = 'c'; # with time not supp by mysql (d)
+ $smds{'q5'} = 'b'; # with time not supp by mysql ('')
+ $smds{'q6'} = 'c'; # with time not supp by mysql ('')
+ $smds{'q7'} = 'c';
+ $smds{'q8'} = 'f';
+ $smds{'q9'} = 'c';
+ $smds{'q10'} = 'b';
+ $smds{'q11'} = 'b';
+ $smds{'q12'} = 'd';
+ $smds{'q13'} = 'c';
+ $smds{'q14'} = 'd';
+ $smds{'q15'} = 'd';
+ $smds{'q16'} = 'a';
+ $smds{'q17'} = 'c';
+
+ return $self;
+}
+
+#
+# Get the version number of the database
+#
+
+sub version
+{
+ my ($self)=@_;
+ my ($dbh,$sth,$version,@row);
+
+ $dbh=$self->connect();
+ $sth = $dbh->prepare("select VERSION()") or die $DBI::errstr;
+ $version="MySQL 3.20.?";
+ if ($sth->execute && (@row = $sth->fetchrow_array))
+ {
+ $row[0] =~ s/-/ /g; # To get better tables with long names
+ $version="MySQL $row[0]";
+ }
+ $sth->finish;
+ $dbh->disconnect;
+ return $version;
+}
+
+#
+# Connection with optional disabling of logging
+#
+
+sub connect
+{
+ my ($self)=@_;
+ my ($dbh);
+ $dbh=DBI->connect($self->{'data_source'}, $main::opt_user,
+ $main::opt_password,{ PrintError => 0}) ||
+ die "Got error: '$DBI::errstr' when connecting to " . $self->{'data_source'} ." with user: '$main::opt_user' password: '$main::opt_password'\n";
+
+ $dbh->do("SET OPTION LOG_OFF=1,UPDATE_LOG=0");
+ return $dbh;
+}
+
+#
+# Returns a list of statements to create a table
+# The field types are in ANSI SQL format.
+#
+# If one uses $main::opt_fast then one is allowed to use
+# non standard types to get better speed.
+#
+
+sub create
+{
+ my($self,$table_name,$fields,$index,$options) = @_;
+ my($query,@queries);
+
+ $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 ?
+ $query.= $field . ',';
+ }
+ foreach $index (@$index)
+ {
+ $query.= $index . ',';
+ }
+ substr($query,-1)=")"; # Remove last ',';
+ $query.=" $options" if (defined($options));
+ $query.=" $main::opt_create_options" if (defined($main::opt_create_options));
+ push(@queries,$query);
+ return @queries;
+}
+
+sub insert_file {
+ my ($self,$dbname, $file, $dbh) = @_;
+ my ($command, $sth);
+
+ $file =~ s|\\|/|g; # Change Win32 names to Unix syntax
+ $command = "load data infile '$file' into table $dbname columns optionally enclosed by '\\'' terminated by ','";
+# print "$command\n";
+ $sth = $dbh->do($command) or die $DBI::errstr;
+ return $sth; # Contains number of rows
+}
+
+#
+# Do any conversions to the ANSI SQL query so that the database can handle it
+#
+
+sub query {
+ my($self,$sql) = @_;
+ return $sql;
+}
+
+sub drop_index {
+ my ($self,$table,$index) = @_;
+ return "DROP INDEX $index ON $table";
+}
+
+#
+# Abort if the server has crashed
+# return: 0 if ok
+# 1 question should be retried
+#
+
+sub abort_if_fatal_error
+{
+ return 0;
+}
+
+#
+# This should return 1 if we to do disconnect / connect when doing
+# big batches
+#
+
+sub small_rollback_segment
+{
+ return 0;
+}
+
+#
+# reconnect on errors (needed mainly be crash-me)
+#
+
+sub reconnect_on_errors
+{
+ return 0;
+}
+
+#############################################################################
+# Definitions for mSQL
+#############################################################################
+
+package db_mSQL;
+
+sub new
+{
+ my ($type,$host,$database)= @_;
+ my $self= {};
+ my %limits;
+ bless $self;
+
+ $self->{'cmp_name'} = "msql";
+ $self->{'data_source'} = "DBI:mSQL:$database:$main::$opt_host";
+ $self->{'limits'} = \%limits;
+ $self->{'double_quotes'} = 0;
+
+ $limits{'max_conditions'} = 74;
+ $limits{'max_columns'} = 75;
+ $limits{'max_tables'} = 65000; # Should be big enough
+ $limits{'max_text_size'} = 32000;
+ $limits{'query_size'} = 65535;
+ $limits{'max_index'} = 5;
+ $limits{'max_index_parts'} = 10;
+ $limits{'max_column_name'} = 35;
+
+ $limits{'join_optimizer'} = 0; # Can't optimize FROM tables
+ $limits{'load_data_infile'} = 0;
+ $limits{'lock_tables'} = 0;
+ $limits{'functions'} = 0;
+ $limits{'group_functions'} = 0;
+ $limits{'group_distinct_functions'}= 0; # Have count(distinct)
+ $limits{'multi_drop'} = 0;
+ $limits{'select_without_from'}= 0;
+ $limits{'subqueries'} = 0;
+ $limits{'left_outer_join'} = 0;
+ $limits{'table_wildcard'} = 0;
+ $limits{'having_with_alias'} = 0;
+ $limits{'having_with_group'} = 0;
+ $limits{'like_with_column'} = 1;
+ $limits{'order_by_position'} = 1;
+ $limits{'group_by_position'} = 1;
+ $limits{'alter_table'} = 0;
+ $limits{'alter_add_multi_col'}= 0;
+ $limits{'alter_table_dropcol'}= 0;
+ $limits{'group_func_extra_std'} = 0;
+ $limits{'limit'} = 1; # supports the limit attribute
+
+ $limits{'func_odbc_mod'} = 0;
+ $limits{'func_extra_%'} = 0;
+ $limits{'func_odbc_floor'} = 0;
+ $limits{'func_extra_if'} = 0;
+ $limits{'column_alias'} = 0;
+ $limits{'NEG'} = 0;
+ $limits{'func_extra_in_num'} = 0;
+
+ $self->{'blob'} = "text(" . $limits{'max_text_size'} .")";
+ $self->{'text'} = "text(" . $limits{'max_text_size'} .")";
+ return $self;
+}
+
+#
+# Get the version number of the database
+#
+
+sub version
+{
+ my ($tmp,$dir);
+ foreach $dir ("/usr/local/Hughes", "/usr/local/mSQL","/my/local/mSQL",
+ "/usr/local")
+ {
+ if (-x "$dir/bin/msqladmin")
+ {
+ $tmp=`$dir/bin/msqladmin version | grep server`;
+ if ($tmp =~ /^\s*(.*\w)\s*$/)
+ { # Strip pre- and endspace
+ $tmp=$1;
+ $tmp =~ s/\s+/ /g; # Remove unnecessary spaces
+ return $tmp;
+ }
+ }
+ }
+ return "mSQL version ???";
+}
+
+
+sub connect
+{
+ my ($self)=@_;
+ my ($dbh);
+ $dbh=DBI->connect($self->{'data_source'}, $main::opt_user,
+ $main::opt_password,{ PrintError => 0}) ||
+ die "Got error: '$DBI::errstr' when connecting to " . $self->{'data_source'} ." with user: '$main::opt_user' password: '$main::opt_password'\n";
+ return $dbh;
+}
+
+#
+# Can't handle many field types, so we map everything to int and real.
+#
+
+sub create
+{
+ my($self,$table_name,$fields,$index) = @_;
+ my($query,@queries,$name,$nr);
+
+ $query="create table $table_name (";
+ foreach $field (@$fields)
+ {
+ $field =~ s/varchar/char/i; # mSQL doesn't have VARCHAR()
+ # mSQL can't handle more than the real basic int types
+ $field =~ s/tinyint|smallint|mediumint|integer/int/i;
+ # mSQL can't handle different visual lengths
+ $field =~ s/int\(\d*\)/int/i;
+ # mSQL dosen't have float, change it to real
+ $field =~ s/float(\(\d*,\d*\)){0,1}/real/i;
+ $field =~ s/double(\(\d*,\d*\)){0,1}/real/i;
+ # mSQL doesn't have blob, it has text instead
+ if ($field =~ / blob/i)
+ {
+ $name=$self->{'blob'};
+ $field =~ s/ blob/ $name/;
+ }
+ $query.= $field . ',';
+ }
+ substr($query,-1)=")"; # Remove last ',';
+ push(@queries,$query);
+ $nr=0;
+
+ # Prepend table_name to index name because the the name may clash with
+ # a field name. (Should be diffent name space, but this is mSQL...)
+
+ foreach $index (@$index)
+ {
+ # Primary key is unique index in mSQL
+ $index =~ s/primary key/unique index primary/i;
+ if ($index =~ /^unique\s*\(([^\(]*)\)$/i)
+ {
+ $nr++;
+ push(@queries,"create unique index ${table_name}_$nr on $table_name ($1)");
+ }
+ else
+ {
+ if (!($index =~ /^(.*index)\s+(\w*)\s+(\(.*\))$/i))
+ {
+ die "Can't parse index information in '$index'\n";
+ }
+ push(@queries,"create $1 ${table_name}_$2 on $table_name $3");
+ }
+ }
+ return @queries;
+}
+
+
+sub insert_file {
+ my($self,$dbname, $file) = @_;
+ print "insert an ascii file isn't supported by mSQL\n";
+ return 0;
+}
+
+
+sub query {
+ my($self,$sql) = @_;
+ return $sql;
+}
+
+sub drop_index
+{
+ my ($self,$table,$index) = @_;
+ return "DROP INDEX $index FROM $table";
+}
+
+sub abort_if_fatal_error
+{
+ return 0;
+}
+
+sub small_rollback_segment
+{
+ return 0;
+}
+
+sub reconnect_on_errors
+{
+ return 0;
+}
+
+#############################################################################
+# Definitions for PostgreSQL #
+#############################################################################
+
+package db_Pg;
+
+sub new
+{
+ my ($type,$host,$database)= @_;
+ my $self= {};
+ my %limits;
+ bless $self;
+
+ $self->{'cmp_name'} = "pg";
+ $self->{'data_source'} = "DBI:Pg:dbname=$database";
+ $self->{'limits'} = \%limits;
+ $self->{'smds'} = \%smds;
+ $self->{'blob'} = "text";
+ $self->{'text'} = "text";
+ $self->{'double_quotes'} = 1;
+ $self->{"vacuum"} = 1;
+ $limits{'join_optimizer'} = 1; # Can optimize FROM tables
+ $limits{'load_data_infile'} = 0; # Is this true ?
+
+ $limits{'NEG'} = 1; # Can't handle -id
+ $limits{'alter_table'} = 1; # alter ??
+ $limits{'alter_add_multi_col'}= 0; # alter_add_multi_col ?
+ $limits{'alter_table_dropcol'}= 0; # alter_drop_col ?
+ $limits{'column_alias'} = 1;
+ $limits{'func_extra_%'} = 1;
+ $limits{'func_extra_if'} = 0;
+ $limits{'func_extra_in_num'} = 1;
+ $limits{'func_odbc_floor'} = 1;
+ $limits{'func_odbc_mod'} = 1; # Has %
+ $limits{'functions'} = 1;
+ $limits{'group_by_position'} = 1;
+ $limits{'group_func_extra_std'} = 0;
+ $limits{'group_func_sql_min_str'}= 1; # Can execute MIN() and MAX() on strings
+ $limits{'group_functions'} = 1;
+ $limits{'group_distinct_functions'}= 1; # Have count(distinct)
+ $limits{'having_with_alias'} = 0;
+ $limits{'having_with_group'} = 0;
+ $limits{'left_outer_join'} = 0;
+ $limits{'like_with_column'} = 1;
+ $limits{'lock_tables'} = 0; # in ATIS gives this a problem
+ $limits{'max_column_name'} = 32; # Is this true
+ $limits{'max_columns'} = 300; # 500 crashes pg 6.3
+ $limits{'max_tables'} = 65000; # Should be big enough
+ $limits{'max_conditions'} = 9; # This makes Pg real slow
+ $limits{'max_index'} = 7; # Is this true ?
+ $limits{'max_index_parts'} = 16; # Is this true ?
+ $limits{'max_text_size'} = 7000; # 8000 crashes pg 6.3
+ $limits{'multi_drop'} = 1;
+ $limits{'order_by_position'} = 1;
+ $limits{'query_size'} = 8191;
+ $limits{'select_without_from'}= 1;
+ $limits{'subqueries'} = 1;
+ $limits{'table_wildcard'} = 1;
+
+ # the different cases per query ...
+ $smds{'q1'} = 'b'; # with time
+ $smds{'q2'} = 'b';
+ $smds{'q3'} = 'b'; # with time
+ $smds{'q4'} = 'c'; # with time
+ $smds{'q5'} = 'b'; # with time
+ $smds{'q6'} = 'c'; # strange error ....
+ $smds{'q7'} = 'c';
+ $smds{'q8'} = 'f'; # needs 128M to execute - can't do insert ...group by
+ $smds{'q9'} = 'c';
+ $smds{'q10'} = 'b';
+ $smds{'q11'} = 'b'; # can't do float8 * int4 - create operator
+ $smds{'q12'} = 'd'; # strange error???
+ $smds{'q13'} = 'c';
+ $smds{'q14'} = 'd'; # strange error???
+ $smds{'q15'} = 'd'; # strange error???
+ $smds{'q16'} = 'a';
+ $smds{'q17'} = 'c';
+ $smds{'time'} = 1; # the use of the time table -> 1 is on.
+ # when 0 then the date field must be a
+ # date field not a int field!!!
+ return $self;
+}
+
+# couldn't find the option to get the version number
+
+sub version
+{
+ my ($version,$dir);
+ foreach $dir ($ENV{'PGDATA'},"/usr/local/pgsql/data", "/my/local/pgsql/")
+ {
+ if ($dir && -e "$dir/PG_VERSION")
+ {
+ $version= `cat $dir/PG_VERSION`;
+ if ($? == 0)
+ {
+ chomp($version);
+ return "PostgreSQL $version";
+ }
+ }
+ }
+ return "PostgreSQL version ???";
+}
+
+
+sub connect
+{
+ my ($self)=@_;
+ my ($dbh);
+ $dbh=DBI->connect($self->{'data_source'}, $main::opt_user,
+ $main::opt_password,{ PrintError => 0}) ||
+ die "Got error: '$DBI::errstr' when connecting to " . $self->{'data_source'} ." with user: '$main::opt_user' password: '$main::opt_password'\n";
+ return $dbh;
+}
+
+
+sub create
+{
+ my($self,$table_name,$fields,$index) = @_;
+ my($query,@queries,$name,$in,$indfield,$table,$nr);
+
+ $query="create table $table_name (";
+ foreach $field (@$fields)
+ {
+ if ($main::opt_fast)
+ {
+ # Allow use of char2, char4, char8 or char16
+ $field =~ s/char(2|4|8|16)/char$1/;
+ }
+ # Pg can't handle more than the real basic int types
+ $field =~ s/tinyint|smallint|mediumint|integer/int/;
+ # Pg can't handle different visual lengths
+ $field =~ s/int\(\d*\)/int/;
+ $field =~ s/float\(\d*,\d*\)/float/;
+ $field =~ s/ double/ float/;
+ $field =~ s/ decimal/ float/i;
+ $field =~ s/ big_decimal/ float/i;
+ $field =~ s/ date/ int/i;
+ # Pg doesn't have blob, it has text instead
+ $field =~ s/ blob/ text/;
+ $query.= $field . ',';
+ }
+ substr($query,-1)=")"; # Remove last ',';
+ push(@queries,$query);
+ foreach $index (@$index)
+ {
+ $index =~ s/primary key/unique index primary_key/i;
+ if ($index =~ /^unique.*\(([^\(]*)\)$/i)
+ {
+ $indfield="using btree (" .$1.")";
+ $in="unique index";
+ $table="index_$nr"; $nr++;
+ }
+ elsif ($index =~ /^(.*index)\s+(\w*)\s+(\(.*\))$/i)
+ {
+ $indfield="using btree " .$3;
+ $in="index";
+ $table="index_$nr"; $nr++;
+ }
+ else
+ {
+ die "Can't parse index information in '$index'\n";
+ }
+ push(@queries,"create $in ${table_name}_$table on $table_name $indfield");
+ }
+ $queries[0]=$query;
+ return @queries;
+}
+
+sub insert_file {
+ my ($self,$dbname, $file, $dbh) = @_;
+ my ($command, $sth);
+
+# Syntax:
+# copy [binary] <class_name> [with oids]
+# {to|from} {<filename>|stdin|stdout} [using delimiters <delim>]
+ print "The ascii files aren't correct for postgres ....!!!\n";
+ $command = "copy $dbname from '$file' using delimiters ','";
+ print "$command\n";
+ $sth = $dbh->do($command) or die $DBI::errstr;
+ return $sth;
+}
+
+#
+# As postgreSQL wants A % B instead of standard mod(A,B) we have to map
+# This will not handle all cases, but as the benchmarks doesn't use functions
+# inside MOD() the following should work
+#
+# PostgreSQL cant handle count(*) or even count(1), but it can handle
+# count(1+1) sometimes. ==> this is solved in PostgreSQL 6.3
+#
+# PostgreSQL 6.5 is supporting MOD.
+
+sub query {
+ my($self,$sql) = @_;
+ my(@select,$change);
+# if you use PostgreSQL 6.x and x is lower as 5 then uncomment the line below.
+# $sql =~ s/mod\(([^,]*),([^\)]*)\)/\($1 % $2\)/gi;
+#
+# if you use PostgreSQL 6.1.x uncomment the lines below
+# if ($sql =~ /select\s+count\(\*\)\s+from/i) {
+# }
+# elsif ($sql =~ /count\(\*\)/i)
+# {
+# if ($sql =~ /select\s+(.*)\s+from/i)
+# {
+# @select = split(/,/,$1);
+# if ($select[0] =~ /(.*)\s+as\s+\w+$/i)
+# {
+# $change = $1;
+# }
+# else
+# {
+# $change = $select[0];
+# }
+# }
+# if (($change =~ /count/i) || ($change eq "")) {
+# $change = "1+1";
+# }
+# $sql =~ s/count\(\*\)/count($change)/gi;
+# }
+# till here.
+ return $sql;
+}
+
+sub drop_index
+{
+ my ($self,$table,$index) = @_;
+ return "DROP INDEX $index";
+}
+
+sub abort_if_fatal_error
+{
+ return 1 if ($DBI::errstr =~ /sent to backend, but backend closed/i);
+ return 0;
+}
+
+sub small_rollback_segment
+{
+ return 0;
+}
+
+sub reconnect_on_errors
+{
+ return 0;
+}
+
+sub vacuum
+{
+ my ($self,$full_vacuum,$dbh_ref)=@_;
+ my ($loop_time,$end_time,$dbh);
+ if (defined($full_vacuum))
+ {
+ $$dbh_ref->disconnect; $$dbh_ref= $self->connect();
+ }
+ $dbh=$$dbh_ref;
+ $loop_time=new Benchmark;
+ $dbh->do("vacuum") || die "Got error: $DBI::errstr when executing 'vacuum'\n";
+ $dbh->do("vacuum pg_attributes") || die "Got error: $DBI::errstr when executing 'vacuum'\n";
+ $dbh->do("vacuum pg_index") || die "Got error: $DBI::errstr when executing 'vacuum'\n";
+ $dbh->do("vacuum analyze") || 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";
+ $dbh->disconnect; $$dbh_ref= $self->connect();
+}
+
+
+#############################################################################
+# Definitions for Solid
+#############################################################################
+
+package db_Solid;
+
+sub new
+{
+ my ($type,$host,$database)= @_;
+ my $self= {};
+ my %limits;
+ bless $self;
+
+ $self->{'cmp_name'} = "solid";
+ $self->{'data_source'} = "DBI:Solid:";
+ $self->{'limits'} = \%limits;
+ $self->{'smds'} = \%smds;
+ $self->{'blob'} = "long varchar";
+ $self->{'text'} = "long varchar";
+ $self->{'double_quotes'} = 1;
+
+ $limits{'max_conditions'} = 9999; # Probably big enough
+ $limits{'max_columns'} = 2000; # From crash-me
+ $limits{'max_tables'} = 65000; # Should be big enough
+ $limits{'max_text_size'} = 65492; # According to tests
+ $limits{'query_size'} = 65535; # Probably a limit
+ $limits{'max_index'} = 64; # Probably big enough
+ $limits{'max_index_parts'} = 64;
+ $limits{'max_column_name'} = 80;
+
+ $limits{'join_optimizer'} = 1;
+ $limits{'load_data_infile'} = 0;
+ $limits{'lock_tables'} = 0;
+ $limits{'functions'} = 1;
+ $limits{'group_functions'} = 1;
+ $limits{'group_func_sql_min_str'} = 1; # Can execute MIN() and MAX() on strings
+ $limits{'group_distinct_functions'}= 1; # Have count(distinct)
+ $limits{'select_without_from'}= 0; # Can do 'select 1' ?;
+ $limits{'multi_drop'} = 0;
+ $limits{'subqueries'} = 1;
+ $limits{'left_outer_join'} = 1;
+ $limits{'table_wildcard'} = 1;
+ $limits{'having_with_alias'} = 0;
+ $limits{'having_with_group'} = 1;
+ $limits{'like_with_column'} = 1;
+ $limits{'order_by_position'} = 0; # 2.30.0018 can this
+ $limits{'group_by_position'} = 0;
+ $limits{'alter_table'} = 1;
+ $limits{'alter_add_multi_col'}= 0;
+ $limits{'alter_table_dropcol'}= 0;
+
+ $limits{'group_func_extra_std'} = 0; # Have group function std().
+
+ $limits{'func_odbc_mod'} = 1;
+ $limits{'func_extra_%'} = 0;
+ $limits{'func_odbc_floor'} = 1;
+ $limits{'column_alias'} = 1;
+ $limits{'NEG'} = 1;
+ $limits{'func_extra_in_num'} = 1;
+
+ # for the smds small benchmark test ....
+ # the different cases per query ...
+ $smds{'q1'} = 'a';
+ $smds{'q2'} = '';
+ $smds{'q3'} = 'b'; #doesn't work -> strange error about column -fixed
+ $smds{'q4'} = 'a';
+ $smds{'q5'} = 'b';
+ $smds{'q6'} = 'c';
+ $smds{'q7'} = 'b';
+ $smds{'q8'} = 'f';
+ $smds{'q9'} = 'b';
+ $smds{'q10'} = 'b';
+ $smds{'q11'} = '';
+ $smds{'q12'} = 'd';
+ $smds{'q13'} = 'b';
+ $smds{'q14'} = 'd';
+ $smds{'q15'} = 'd';
+ $smds{'q16'} = '';
+ $smds{'q17'} = '';
+ $smds{'time'} = 1; # the use of the time table -> 1 is on.
+ # when 0 then the date field must be a
+ # date field not a int field!!!
+ return $self;
+}
+
+#
+# Get the version number of the database
+#
+
+sub version
+{
+ my ($version,$dir);
+ foreach $dir ($ENV{'SOLIDDIR'},"/usr/local/solid", "/my/local/solid")
+ {
+ if ($dir && -e "$dir/bin/solcon")
+ {
+ $version=`$dir/bin/solcon -e"ver" $main::opt_user $main::opt_password | grep Server | head -1`;
+ if ($? == 0)
+ {
+ chomp($version);
+ return $version;
+ }
+ }
+ }
+ return "Solid version ???";
+}
+
+sub connect
+{
+ my ($self)=@_;
+ my ($dbh);
+ $dbh=DBI->connect($self->{'data_source'}, $main::opt_user,
+ $main::opt_password,{ PrintError => 0}) ||
+ die "Got error: '$DBI::errstr' when connecting to " . $self->{'data_source'} ." with user: '$main::opt_user' password: '$main::opt_password'\n";
+ return $dbh;
+}
+
+#
+# Returns a list of statements to create a table
+# The field types are in ANSI SQL format.
+#
+
+sub create
+{
+ my($self,$table_name,$fields,$index) = @_;
+ my($query,@queries,$nr);
+
+ $query="create table $table_name (";
+ foreach $field (@$fields)
+ {
+ $field =~ s/mediumint/integer/i;
+ $field =~ s/ double/ float/i;
+ # Solid doesn't have blob, it has long varchar
+ $field =~ s/ blob/ long varchar/;
+ $field =~ s/ decimal/ float/i;
+ $field =~ s/ big_decimal/ float/i;
+ $field =~ s/ date/ int/i;
+ $query.= $field . ',';
+ }
+ substr($query,-1)=")"; # Remove last ',';
+ push(@queries,$query);
+ $nr=0;
+ foreach $index (@$index)
+ {
+ if ($index =~ /^primary key/i || $index =~ /^unique/i)
+ { # Add to create statement
+ substr($queries[0],-1,0)="," . $index;
+ }
+ else
+ {
+ $index =~ /^(.*)\s+(\(.*\))$/;
+ push(@queries,"create ${1}$nr on $table_name $2");
+ $nr++;
+ }
+ }
+ return @queries;
+}
+
+# there is no sql statement in solid which can do the load from
+# an ascii file in the db ... but there is the speedloader program
+# an external program which can load the ascii file in the db ...
+# the server must be down before using speedloader !!!!
+# (in the standalone version)
+# it works also with a control file ... that one must be made ....
+sub insert_file {
+ my ($self, $dbname, $file) = @_;
+ my ($speedcmd);
+ $speedcmd = '/usr/local/solid/bin/solload';
+ print "At this moment not supported - solid server must go down \n";
+ return 0;
+}
+
+# solid can't handle an alias in a having statement so
+# select test as foo from tmp group by foo having foor > 2
+# becomes
+# select test as foo from tmp group by foo having test > 2
+#
+sub query {
+ my($self,$sql) = @_;
+ my(@select,$tmp,$newhaving,$key,%change);
+
+ if ($sql =~ /having\s+/i)
+ {
+ if ($sql =~ /select (.*) from/i)
+ {
+ (@select) = split(/,\s*/, $1);
+ foreach $tmp (@select)
+ {
+ if ($tmp =~ /(.*)\s+as\s+(\w+)/)
+ {
+ $change{$2} = $1;
+ }
+ }
+ }
+ if ($sql =~ /having\s+(\w+)/i)
+ {
+ $newhaving = $1;
+ foreach $key (sort {$a cmp $b} keys %change)
+ {
+ if ($newhaving eq $key)
+ {
+ $newhaving =~ s/$key/$change{$key}/g;
+ }
+ }
+ }
+ $sql =~ s/(having)\s+(\w+)/$1 $newhaving/i;
+ }
+ return $sql;
+}
+
+
+sub drop_index
+{
+ my ($self,$table,$index) = @_;
+ return "DROP INDEX $index";
+}
+
+sub abort_if_fatal_error
+{
+ return 0;
+}
+
+sub small_rollback_segment
+{
+ return 0;
+}
+
+sub reconnect_on_errors
+{
+ return 0;
+}
+
+#############################################################################
+# Definitions for Empress
+#
+# at this moment DBI:Empress can only handle 200 prepare statements ...
+# so Empress can't be tested with the benchmark test :(
+#############################################################################
+
+package db_Empress;
+
+sub new
+{
+ my ($type,$host,$database)= @_;
+ my $self= {};
+ my %limits;
+ bless $self;
+
+ $self->{'cmp_name'} = "empress";
+ $self->{'data_source'} = "DBI:EmpressNet:SERVER=$main::$opt_host;Database=/usr/local/empress/rdbms/bin/$database";
+ $self->{'limits'} = \%limits;
+ $self->{'smds'} = \%smds;
+ $self->{'blob'} = "text";
+ $self->{'text'} = "text";
+ $self->{'double_quotes'} = 1; # Can handle: 'Walker''s'
+
+ $limits{'max_conditions'} = 1258;
+ $limits{'max_columns'} = 226; # server is disconnecting????
+ # above this value .... but can handle 2419 columns
+ # maybe something for crash-me ... but how to check ???
+ $limits{'max_tables'} = 65000; # Should be big enough
+ $limits{'max_text_size'} = 4095; # max returned ....
+ $limits{'query_size'} = 65535; # Not a limit, big enough
+ $limits{'max_index'} = 64; # Big enough
+ $limits{'max_index_parts'} = 64; # Big enough
+ $limits{'max_column_name'} = 31;
+
+ $limits{'join_optimizer'} = 1;
+ $limits{'load_data_infile'} = 0;
+ $limits{'lock_tables'} = 1;
+ $limits{'functions'} = 1;
+ $limits{'group_functions'} = 1;
+ $limits{'group_func_sql_min_str'} = 1; # Can execute MIN() and MAX() on strings
+ $limits{'group_distinct_functions'}= 1; # Have count(distinct)
+ $limits{'select_without_from'}= 0;
+ $limits{'multi_drop'} = 0;
+ $limits{'subqueries'} = 1;
+ $limits{'table_wildcard'} = 0;
+ $limits{'having_with_alias'} = 0; # AS isn't supported in a select
+ $limits{'having_with_group'} = 1;
+ $limits{'like_with_column'} = 1;
+ $limits{'order_by_position'} = 1;
+ $limits{'group_by_position'} = 0;
+ $limits{'alter_table'} = 1;
+ $limits{'alter_add_multi_col'}= 0;
+ $limits{'alter_table_dropcol'}= 0;
+
+ $limits{'group_func_extra_std'}= 0; # Have group function std().
+
+ $limits{'func_odbc_mod'} = 0;
+ $limits{'func_extra_%'} = 1;
+ $limits{'func_odbc_floor'} = 1;
+ $limits{'func_extra_if'} = 0;
+ $limits{'column_alias'} = 0;
+ $limits{'NEG'} = 1;
+ $limits{'func_extra_in_num'} = 0;
+
+ # for the smds small benchmark test ....
+ # the different cases per query ... EMPRESS
+ $smds{'q1'} = 'a';
+ $smds{'q2'} = '';
+ $smds{'q3'} = 'a';
+ $smds{'q4'} = 'a';
+ $smds{'q5'} = 'a';
+ $smds{'q6'} = 'a';
+ $smds{'q7'} = 'b';
+ $smds{'q8'} = 'd';
+ $smds{'q9'} = 'b';
+ $smds{'q10'} = 'a';
+ $smds{'q11'} = '';
+ $smds{'q12'} = 'd';
+ $smds{'q13'} = 'b';
+ $smds{'q14'} = 'b';
+ $smds{'q15'} = 'a';
+ $smds{'q16'} = '';
+ $smds{'q17'} = '';
+ $smds{'time'} = 1; # the use of the time table -> 1 is on.
+ # when 0 then the date field must be a
+ # date field not a int field!!!
+ return $self;
+}
+
+#
+# Get the version number of the database
+#
+
+sub version
+{
+ my ($self,$dbh)=@_;
+ my ($version);
+ $version="";
+ if (-x "/usr/local/empress/rdbms/bin/empvers")
+ {
+ $version=`/usr/local/empress/rdbms/bin/empvers | grep Version`;
+ }
+ if ($version)
+ {
+ chomp($version);
+ }
+ else
+ {
+ $version="Empress version ???";
+ }
+ return $version;
+}
+
+sub connect
+{
+ my ($self)=@_;
+ my ($dbh);
+ $dbh=DBI->connect($self->{'data_source'}, $main::opt_user,
+ $main::opt_password,{ PrintError => 0}) ||
+ die "Got error: '$DBI::errstr' when connecting to " . $self->{'data_source'} ." with user: '$main::opt_user' password: '$main::opt_password'\n";
+ return $dbh;
+}
+
+sub insert_file {
+ my($self,$dbname, $file) = @_;
+ my($command,$sth);
+ $command = "insert into $dbname from '$file'";
+ print "$command\n" if ($opt_debug);
+ $sth = $dbh->do($command) or die $DBI::errstr;
+
+ return $sth;
+}
+
+#
+# Returns a list of statements to create a table
+# The field types are in ANSI SQL format.
+#
+
+sub create
+{
+ my($self,$table_name,$fields,$index) = @_;
+ my($query,@queries,$nr);
+
+ $query="create table $table_name (";
+ foreach $field (@$fields)
+ {
+ $field =~ s/mediumint/int/i;
+ $field =~ s/tinyint/int/i;
+ $field =~ s/smallint/int/i;
+ $field =~ s/longint/int/i;
+ $field =~ s/integer/int/i;
+ $field =~ s/ double/ longfloat/i;
+ # Solid doesn't have blob, it has long varchar
+# $field =~ s/ blob/ text(65535,65535,65535,65535)/;
+ $field =~ s/ blob/ text/;
+ $field =~ s/ varchar\((\d+)\)/ char($1,3)/;
+ $field =~ s/ char\((\d+)\)/ char($1,3)/;
+ $field =~ s/ decimal/ float/i;
+ $field =~ s/ big_decimal/ longfloat/i;
+ $field =~ s/ date/ int/i;
+ $field =~ s/ float(.*)/ float/i;
+ if ($field =~ / int\((\d+)\)/) {
+ if ($1 > 4) {
+ $field =~ s/ int\(\d+\)/ longinteger/i;
+ } else {
+ $field =~ s/ int\(\d+\)/ longinteger/i;
+ }
+ } else {
+ $field =~ s/ int/ longinteger/i;
+ }
+ $query.= $field . ',';
+ }
+ substr($query,-1)=")"; # Remove last ',';
+ push(@queries,$query);
+ $nr=1;
+ foreach $index (@$index)
+ {
+ # Primary key is unique index in Empress
+ $index =~ s/primary key/unique index/i;
+ if ($index =~ /^unique.*\(([^\(]*)\)$/i)
+ {
+ $nr++;
+ push(@queries,"create unique index ${table_name}_$nr on $table_name ($1)");
+ }
+ else
+ {
+ if (!($index =~ /^(.*index)\s+(\w*)\s+(\(.*\))$/i))
+ {
+ die "Can't parse index information in '$index'\n";
+ }
+ push(@queries,"create $1 ${table_name}_$2 on $table_name $3");
+ }
+ }
+ return @queries;
+}
+
+# empress can't handle an alias and but can handle the number of the
+# columname - so
+# select test as foo from tmp order by foo
+# becomes
+# select test from tmp order by 1
+#
+sub query {
+ my($self,$sql) = @_;
+ my(@select,$i,$tmp,$newselect,$neworder,@order,$key,%change);
+ my($tmp1,$otmp,$tmp2);
+
+ if ($sql =~ /\s+as\s+/i)
+ {
+ if ($sql =~ /select\s+(.*)\s+from/i) {
+ $newselect = $1;
+ (@select) = split(/,\s*/, $1);
+ $i = 1;
+ foreach $tmp (@select) {
+ if ($tmp =~ /\s+as\s+(\w+)/) {
+ $change{$1} = $i;
+ }
+ $i++;
+ }
+ }
+ $newselect =~ s/\s+as\s+(\w+)//gi;
+ $tmp2 = 0;
+ if ($sql =~ /order\s+by\s+(.*)$/i) {
+ (@order) = split(/,\s*/, $1);
+ foreach $otmp (@order) {
+ foreach $key (sort {$a cmp $b} keys %change) {
+ if ($otmp eq $key) {
+ $neworder .= "$tmp1"."$change{$key}";
+ $tmp1 = ", ";
+ $tmp2 = 1;
+ } elsif ($otmp =~ /(\w+)\s+(.+)$/) {
+ if ($key eq $1) {
+ $neworder .= "$tmp1"."$change{$key} $2";
+ $tmp2 = 1;
+ }
+ }
+ }
+ if ($tmp2 == 0) {
+ $neworder .= "$tmp1"."$otmp";
+ }
+ $tmp2 = 0;
+ $tmp1 = ", ";
+ }
+ }
+ $sql =~ s/(select)\s+(.*)\s+(from)/$1 $newselect $3/i;
+ $sql =~ s/(order\s+by)\s+(.*)$/$1 $neworder/i;
+ }
+ return $sql;
+}
+
+sub drop_index
+{
+ my ($self,$table,$index) = @_;
+ return "DROP INDEX $index";
+}
+
+# This is a because of the 200 statement problem with DBI-Empress
+
+sub abort_if_fatal_error
+{
+ if ($DBI::errstr =~ /Overflow of table of prepared statements/i)
+ {
+ print "Overflow of prepared statements ... killing the process\n";
+ exit 1;
+ }
+ return 0;
+}
+
+sub small_rollback_segment
+{
+ return 0;
+}
+
+sub reconnect_on_errors
+{
+ return 0;
+}
+
+#############################################################################
+# Definitions for Oracle
+#############################################################################
+
+package db_Oracle;
+
+sub new
+{
+ my ($type,$host,$database)= @_;
+ my $self= {};
+ my %limits;
+ bless $self;
+
+ $self->{'cmp_name'} = "Oracle";
+ $self->{'data_source'} = "DBI:Oracle:$database";
+ $self->{'limits'} = \%limits;
+ $self->{'smds'} = \%smds;
+ $self->{'blob'} = "long";
+ $self->{'text'} = "long";
+ $self->{'double_quotes'} = 1; # Can handle: 'Walker''s'
+ $self->{"vacuum"} = 1;
+
+ $limits{'max_conditions'} = 9999; # (Actually not a limit)
+ $limits{'max_columns'} = 254; # Max number of columns in table
+ $limits{'max_tables'} = 65000; # Should be big enough
+ $limits{'max_text_size'} = 2000; # Limit for blob test-connect
+ $limits{'query_size'} = 65525; # Max size with default buffers.
+ $limits{'max_index'} = 16; # Max number of keys
+ $limits{'max_index_parts'} = 16; # Max segments/key
+ $limits{'max_column_name'} = 32; # max table and column name
+
+ $limits{'join_optimizer'} = 1; # Can optimize FROM tables
+ $limits{'load_data_infile'} = 0; # Has load data infile
+ $limits{'lock_tables'} = 0; # Has lock tables
+ $limits{'functions'} = 1; # Has simple functions (+/-)
+ $limits{'group_functions'} = 1; # Have group functions
+ $limits{'group_func_sql_min_str'} = 1; # Can execute MIN() and MAX() on strings
+ $limits{'group_distinct_functions'}= 1; # Have count(distinct)
+ $limits{'select_without_from'}= 0;
+ $limits{'multi_drop'} = 0;
+ $limits{'subqueries'} = 1;
+ $limits{'left_outer_join'} = 0; # This may be fixed in the query module
+ $limits{'table_wildcard'} = 1; # Has SELECT table_name.*
+ $limits{'having_with_alias'} = 0; # Can use aliases in HAVING
+ $limits{'having_with_group'} = 1; # Can't use group functions in HAVING
+ $limits{'like_with_column'} = 1; # Can use column1 LIKE column2
+ $limits{'order_by_position'} = 1; # Can use 'ORDER BY 1'
+ $limits{'group_by_position'} = 0;
+ $limits{'alter_table'} = 1;
+ $limits{'alter_add_multi_col'}= 0;
+ $limits{'alter_table_dropcol'}= 0;
+
+ $limits{'group_func_extra_std'} = 0; # Have group function std().
+
+ $limits{'func_odbc_mod'} = 0; # Oracle has problem with mod()
+ $limits{'func_extra_%'} = 0; # Has % as alias for mod()
+ $limits{'func_odbc_floor'} = 1; # Has func_odbc_floor function
+ $limits{'func_extra_if'} = 0; # Have function if.
+ $limits{'column_alias'} = 1; # Alias for fields in select statement.
+ $limits{'NEG'} = 1; # Supports -id
+ $limits{'func_extra_in_num'} = 1; # Has function in
+
+ $smds{'time'} = 1;
+ $smds{'q1'} = 'b'; # with time not supp by mysql ('')
+ $smds{'q2'} = 'b';
+ $smds{'q3'} = 'b'; # with time ('')
+ $smds{'q4'} = 'c'; # with time not supp by mysql (d)
+ $smds{'q5'} = 'b'; # with time not supp by mysql ('')
+ $smds{'q6'} = 'c'; # with time not supp by mysql ('')
+ $smds{'q7'} = 'c';
+ $smds{'q8'} = 'f';
+ $smds{'q9'} = 'c';
+ $smds{'q10'} = 'b';
+ $smds{'q11'} = 'b';
+ $smds{'q12'} = 'd';
+ $smds{'q13'} = 'c';
+ $smds{'q14'} = 'd';
+ $smds{'q15'} = 'd';
+ $smds{'q16'} = 'a';
+ $smds{'q17'} = 'c';
+
+ return $self;
+}
+
+#
+# Get the version number of the database
+#
+
+sub version
+{
+ my ($self)=@_;
+ my ($dbh,$sth,$version,@row);
+
+ $dbh=$self->connect();
+ $sth = $dbh->prepare("select VERSION from product_component_version WHERE PRODUCT like 'Oracle%'") or die $DBI::errstr;
+ $version="Oracle 7.x";
+ if ($sth->execute && (@row = $sth->fetchrow_array))
+ {
+ $version="Oracle $row[0]";
+ }
+ $sth->finish;
+ $dbh->disconnect;
+ return $version;
+}
+
+sub connect
+{
+ my ($self)=@_;
+ my ($dbh);
+ $dbh=DBI->connect($self->{'data_source'}, $main::opt_user,
+ $main::opt_password,{ PrintError => 0}) ||
+ die "Got error: '$DBI::errstr' when connecting to " . $self->{'data_source'} ." with user: '$main::opt_user' password: '$main::opt_password'\n";
+ return $dbh;
+}
+
+#
+# Returns a list of statements to create a table
+# The field types are in ANSI SQL format.
+#
+# If one uses $main::opt_fast then one is allowed to use
+# non standard types to get better speed.
+#
+
+sub create
+{
+ my($self,$table_name,$fields,$index) = @_;
+ my($query,@queries,$ind,@keys);
+
+ $query="create table $table_name (";
+ foreach $field (@$fields)
+ {
+ $field =~ s/ character\((\d+)\)/ char\($1\)/i;
+ $field =~ s/ character varying\((\d+)\)/ varchar\($1\)/i;
+ $field =~ s/ char varying\((\d+)\)/ varchar\($1\)/i;
+ $field =~ s/ integer/ number\(38\)/i;
+ $field =~ s/ int/ number\(38\)/i;
+ $field =~ s/ tinyint/ number\(38\)/i;
+ $field =~ s/ smallint/ number\(38\)/i;
+ $field =~ s/ mediumint/ number\(38\)/i;
+ $field =~ s/ tinynumber\((\d+)\)\((\d+)\)/ number\($1,$2\)/i;
+ $field =~ s/ smallnumber\((\d+)\)\((\d+)\)/ number\($1,$2\)/i;
+ $field =~ s/ mediumnumber\((\d+)\)\((\d+)\)/ number\($1,$2\)/i;
+ $field =~ s/ number\((\d+)\)\((\d+)\)/ number\($1,$2\)/i;
+ $field =~ s/ numeric\((\d+)\)\((\d+)\)/ number\($1,$2\)/i;
+ $field =~ s/ decimal\((\d+)\)\((\d+)\)/ number\($1,$2\)/i;
+ $field =~ s/ dec\((\d+)\)\((\d+)\)/ number\($1,$2\)/i;
+ $field =~ s/ float/ number/;
+ $field =~ s/ real/ number/;
+ $field =~ s/ double precision/ number/;
+ $field =~ s/ double/ number/;
+ $field =~ s/ blob/ long/;
+ $query.= $field . ',';
+ }
+
+ foreach $ind (@$index)
+ {
+ my @index;
+ if ( $ind =~ /\bKEY\b/i ){
+ push(@keys,"ALTER TABLE $table_name ADD $ind");
+ }else{
+ my @fields = split(' ',$index);
+ my $query="CREATE INDEX $fields[1] ON $table_name $fields[2]";
+ push(@index,$query);
+ }
+ }
+ substr($query,-1)=")"; # Remove last ',';
+ push(@queries,$query,@keys,@index);
+#print "query:$query\n";
+
+ return @queries;
+}
+
+sub insert_file {
+ my($self,$dbname, $file) = @_;
+ print "insert an ascii file isn't supported by Oracle (?)\n";
+ return 0;
+}
+
+#
+# Do any conversions to the ANSI SQL query so that the database can handle it
+#
+
+sub query {
+ my($self,$sql) = @_;
+ return $sql;
+}
+
+sub drop_index
+{
+ my ($self,$table,$index) = @_;
+ return "DROP INDEX $index";
+}
+
+#
+# Abort if the server has crashed
+# return: 0 if ok
+# 1 question should be retried
+#
+
+sub abort_if_fatal_error
+{
+ return 0;
+}
+
+sub small_rollback_segment
+{
+ return 1;
+}
+
+sub reconnect_on_errors
+{
+ return 0;
+}
+
+#
+# optimize the tables ....
+#
+sub vacuum
+{
+ my ($self,$full_vacuum,$dbh_ref)=@_;
+ my ($loop_time,$end_time,$sth,$dbh);
+
+ if (defined($full_vacuum))
+ {
+ $$dbh_ref->disconnect; $$dbh_ref= $self->connect();
+ }
+ $dbh=$$dbh_ref;
+ $loop_time=new Benchmark;
+ # first analyze all tables
+ $sth = $dbh->prepare("select table_name from user_tables") || die "Got error: $DBI::errstr";
+ $sth->execute || die "Got error: $DBI::errstr when select user_tables";
+ while (my @r = $sth->fetchrow_array)
+ {
+ $dbh->do("analyze table $r[0] compute statistics") || die "Got error: $DBI::errstr when executing 'analyze table'\n";
+ }
+ # now analyze all indexes ...
+ $sth = $dbh->prepare("select index_name from user_indexes") || die "Got error: $DBI::errstr";
+ $sth->execute || die "Got error: $DBI::errstr when select user_indexes";
+ while (my @r1 = $sth->fetchrow_array)
+ {
+ $dbh->do("analyze index $r1[0] compute statistics") || die "Got error: $DBI::errstr when executing 'analyze index $r1[0]'\n";
+ }
+ $end_time=new Benchmark;
+ print "Time for book-keeping (1): " .
+ Benchmark::timestr(Benchmark::timediff($end_time, $loop_time),"all") . "\n\n";
+ $dbh->disconnect; $$dbh_ref= $self->connect();
+}
+
+
+#############################################################################
+# Definitions for Informix
+#############################################################################
+
+package db_Informix;
+
+sub new
+{
+ my ($type,$host,$database)= @_;
+ my $self= {};
+ my %limits;
+ bless $self;
+
+ $self->{'cmp_name'} = "Informix";
+ $self->{'data_source'} = "DBI:Informix:$database";
+ $self->{'limits'} = \%limits;
+ $self->{'smds'} = \%smds;
+ $self->{'blob'} = "byte in table";
+ $self->{'text'} = "byte in table";
+ $self->{'double_quotes'} = 0; # Can handle: 'Walker''s'
+ $self->{'host'} = $main::opt_host;
+
+ $limits{'NEG'} = 1; # Supports -id
+ $limits{'alter_table'} = 1;
+ $limits{'alter_add_multi_col'}= 0;
+ $limits{'alter_table_dropcol'}= 1;
+ $limits{'column_alias'} = 1; # Alias for fields in select statement.
+ $limits{'func_extra_%'} = 0; # Has % as alias for mod()
+ $limits{'func_extra_if'} = 0; # Have function if.
+ $limits{'func_extra_in_num'}= 0; # Has function in
+ $limits{'func_odbc_floor'} = 0; # Has func_odbc_floor function
+ $limits{'func_odbc_mod'} = 1; # Have function mod.
+ $limits{'functions'} = 1; # Has simple functions (+/-)
+ $limits{'group_by_position'} = 1; # Can use 'GROUP BY 1'
+ $limits{'group_by_alias'} = 0; # Can use 'select a as ab from x GROUP BY ab'
+ $limits{'group_func_extra_std'} = 0; # Have group function std().
+ $limits{'group_functions'} = 1; # Have group functions
+ $limits{'group_func_sql_min_str'} = 1; # Can execute MIN() and MAX() on strings
+ $limits{'group_distinct_functions'}= 1; # Have count(distinct)
+ $limits{'having_with_alias'} = 0; # Can use aliases in HAVING
+ $limits{'having_with_group'}= 1; # Can't use group functions in HAVING
+ $limits{'join_optimizer'} = 1; # Can optimize FROM tables (always 1 only for msql)
+ $limits{'left_outer_join'} = 0; # Supports left outer joins (ANSI)
+ $limits{'like_with_column'} = 1; # Can use column1 LIKE column2
+ $limits{'load_data_infile'} = 0; # Has load data infile
+ $limits{'lock_tables'} = 1; # Has lock tables
+ $limits{'max_conditions'} = 1214; # (Actually not a limit)
+ $limits{'max_column_name'} = 18; # max table and column name
+ $limits{'max_columns'} = 994; # Max number of columns in table
+ $limits{'max_tables'} = 65000; # Should be big enough
+ $limits{'max_index'} = 64; # Max number of keys
+ $limits{'max_index_parts'} = 15; # Max segments/key
+ $limits{'max_text_size'} = 65535; # Max size with default buffers. ??
+ $limits{'multi_drop'} = 0; # Drop table can take many tables
+ $limits{'order_by_position'} = 1; # Can use 'ORDER BY 1'
+ $limits{'query_size'} = 32766; # Max size with default buffers.
+ $limits{'select_without_from'}= 0; # Can do 'select 1';
+ $limits{'subqueries'} = 1; # Doesn't support sub-queries.
+ $limits{'table_wildcard'} = 1; # Has SELECT table_name.*
+
+
+ return $self;
+}
+
+#
+# Get the version number of the database
+#
+
+sub version
+{
+ my ($self)=@_;
+ my ($dbh,$sth,$version,@row);
+
+ $ENV{'INFORMIXSERVER'} = $self->{'host'};
+ $dbh=$self->connect();
+ $sth = $dbh->prepare("SELECT owner FROM systables WHERE tabname = ' VERSION'")
+ or die $DBI::errstr;
+ $version='Informix unknown';
+ if ($sth->execute && (@row = $sth->fetchrow_array))
+ {
+ $version="Informix $row[0]";
+ }
+ $sth->finish;
+ $dbh->disconnect;
+ return $version;
+}
+
+sub connect
+{
+ my ($self)=@_;
+ my ($dbh);
+ $dbh=DBI->connect($self->{'data_source'}, $main::opt_user,
+ $main::opt_password,{ PrintError => 0}) ||
+ die "Got error: '$DBI::errstr' when connecting to " . $self->{'data_source'} ." with user: '$main::opt_user' password: '$main::opt_password'\n";
+ return $dbh;
+}
+
+
+#
+# Create table
+#
+
+sub create
+{
+ my($self,$table_name,$fields,$index) = @_;
+ my($query,@queries,$name,$nr);
+
+ $query="create table $table_name (";
+ foreach $field (@$fields)
+ {
+# $field =~ s/\btransport_description\b/transport_desc/;
+ # to overcome limit 18 chars
+ $field =~ s/tinyint/smallint/i;
+ $field =~ s/tinyint\(\d+\)/smallint/i;
+ $field =~ s/mediumint/integer/i;
+ $field =~ s/mediumint\(\d+\)/integer/i;
+ $field =~ s/smallint\(\d+\)/smallint/i;
+ $field =~ s/integer\(\d+\)/integer/i;
+ $field =~ s/int\(\d+\)/integer/i;
+# $field =~ s/\b(?:small)?int(?:eger)?\((\d+)\)/decimal($1)/i;
+# $field =~ s/float(\(\d*,\d*\)){0,1}/real/i;
+ $field =~ s/(float|double)(\(.*?\))?/float/i;
+
+ if ($field =~ / blob/i)
+ {
+ $name=$self->{'blob'};
+ $field =~ s/ blob/ $name/;
+ }
+ $query.= $field . ',';
+ }
+ substr($query,-1)=")"; # Remove last ',';
+ push(@queries,$query);
+ $nr=0;
+
+ foreach $index (@$index)
+ {
+ # Primary key is unique index in Informix
+ $index =~ s/primary key/unique index primary/i;
+ if ($index =~ /^unique\s*\(([^\(]*)\)$/i)
+ {
+ $nr++;
+ push(@queries,"create unique index ${table_name}_$nr on $table_name ($1)");
+ }
+ else
+ {
+ if (!($index =~ /^(.*index)\s+(\w*)\s+(\(.*\))$/i))
+ {
+ die "Can't parse index information in '$index'\n";
+ }
+ ### push(@queries,"create $1 ${table_name}_$2 on $table_name $3");
+ $nr++;
+ push(@queries,"create $1 ${table_name}_$nr on $table_name $3");
+ }
+ }
+ return @queries;
+}
+#
+# Some test needed this
+#
+
+sub query {
+ my($self,$sql) = @_;
+ return $sql;
+}
+
+sub drop_index
+{
+ my ($self,$table,$index) = @_;
+ return "DROP INDEX $index";
+}
+
+#
+# Abort if the server has crashed
+# return: 0 if ok
+# 1 question should be retried
+#
+
+sub abort_if_fatal_error
+{
+ return 0;
+}
+
+sub small_rollback_segment
+{
+ return 0;
+}
+
+sub reconnect_on_errors
+{
+ return 0;
+}
+
+#############################################################################
+# Configuration for Access
+#############################################################################
+
+package db_access;
+
+sub new
+{
+ my ($type,$host,$database)= @_;
+ my $self= {};
+ my %limits;
+ bless $self;
+
+ $self->{'cmp_name'} = "access";
+ $self->{'data_source'} = "DBI:ODBC:$database";
+ if (defined($opt_host) && $opt_host ne "")
+ {
+ $self->{'data_source'} .= ":$host";
+ }
+ $self->{'limits'} = \%limits;
+ $self->{'smds'} = \%smds;
+ $self->{'blob'} = "blob";
+ $self->{'text'} = "blob"; # text ?
+ $self->{'double_quotes'} = 1; # Can handle: 'Walker''s'
+
+ $limits{'max_conditions'} = 97; # We get 'Query is too complex'
+ $limits{'max_columns'} = 255; # Max number of columns in table
+ $limits{'max_tables'} = 65000; # Should be big enough
+ $limits{'max_text_size'} = 255; # Max size with default buffers.
+ $limits{'query_size'} = 65535; # Not a limit, big enough
+ $limits{'max_index'} = 32; # Max number of keys
+ $limits{'max_index_parts'} = 10; # Max segments/key
+ $limits{'max_column_name'} = 64; # max table and column name
+
+ $limits{'join_optimizer'} = 1; # Can optimize FROM tables
+ $limits{'load_data_infile'} = 0; # Has load data infile
+ $limits{'lock_tables'} = 0; # Has lock tables
+ $limits{'functions'} = 1; # Has simple functions (+/-)
+ $limits{'group_functions'} = 1; # Have group functions
+ $limits{'group_func_sql_min_str'} = 1; # Can execute MIN() and MAX() on strings
+ $limits{'group_distinct_functions'}= 0; # Have count(distinct)
+ $limits{'select_without_from'}= 1; # Can do 'select 1';
+ $limits{'multi_drop'} = 0; # Drop table can take many tables
+ $limits{'subqueries'} = 1; # Supports sub-queries.
+ $limits{'left_outer_join'} = 1; # Supports left outer joins
+ $limits{'table_wildcard'} = 1; # Has SELECT table_name.*
+ $limits{'having_with_alias'} = 0; # Can use aliases in HAVING
+ $limits{'having_with_group'} = 1; # Can use group functions in HAVING
+ $limits{'like_with_column'} = 1; # Can use column1 LIKE column2
+ $limits{'order_by_position'} = 1; # Can use 'ORDER BY 1'
+ $limits{'group_by_position'} = 0; # Can use 'GROUP BY 1'
+ $limits{'alter_table'} = 1;
+ $limits{'alter_add_multi_col'}= 2; #Have ALTER TABLE t add a int, b int;
+ $limits{'alter_table_dropcol'}= 1;
+
+ $limits{'group_func_extra_std'} = 0; # Have group function std().
+
+ $limits{'func_odbc_mod'} = 0; # Have function mod.
+ $limits{'func_extra_%'} = 0; # Has % as alias for mod()
+ $limits{'func_odbc_floor'} = 0; # Has func_odbc_floor function
+ $limits{'func_extra_if'} = 0; # Have function if.
+ $limits{'column_alias'} = 1; # Alias for fields in select statement.
+ $limits{'NEG'} = 1; # Supports -id
+ $limits{'func_extra_in_num'} = 1; # Has function in
+ return $self;
+}
+
+#
+# Get the version number of the database
+#
+
+sub version
+{
+ my ($self)=@_;
+ return "Access 2000"; #DBI/ODBC can't return the server version
+}
+
+sub connect
+{
+ my ($self)=@_;
+ my ($dbh);
+ $dbh=DBI->connect($self->{'data_source'}, $main::opt_user,
+ $main::opt_password,{ PrintError => 0}) ||
+ die "Got error: '$DBI::errstr' when connecting to " . $self->{'data_source'} ." with user: '$main::opt_user' password: '$main::opt_password'\n";
+ return $dbh;
+}
+
+#
+# Returns a list of statements to create a table
+# The field types are in ANSI SQL format.
+#
+
+sub create
+{
+ my($self,$table_name,$fields,$index) = @_;
+ my($query,@queries,$nr);
+
+ $query="create table $table_name (";
+ foreach $field (@$fields)
+ {
+ $field =~ s/mediumint/integer/i;
+ $field =~ s/tinyint/smallint/i;
+ $field =~ s/float\(\d+,\d+\)/float/i;
+ $field =~ s/integer\(\d+\)/integer/i;
+ $field =~ s/smallint\(\d+\)/smallint/i;
+ $field =~ s/int\(\d+\)/integer/i;
+ $field =~ s/blob/text/i;
+ $query.= $field . ',';
+ }
+ substr($query,-1)=")"; # Remove last ',';
+ push(@queries,$query);
+ $nr=0;
+ foreach $index (@$index)
+ {
+ $ext="WITH DISALLOW NULL";
+ if (($index =~ s/primary key/unique index primary_key/i))
+ {
+ $ext="WITH PRIMARY;"
+ }
+ if ($index =~ /^unique.*\(([^\(]*)\)$/i)
+ {
+ $nr++;
+ $index="unique index ${table_name}_$nr ($1)";
+ }
+ $index =~ /^(.*)\s+(\(.*\))$/;
+ push(@queries,"create ${1} on $table_name $2");
+ }
+ return @queries;
+}
+
+#
+# Do any conversions to the ANSI SQL query so that the database can handle it
+#
+
+sub query {
+ my($self,$sql) = @_;
+ return $sql;
+}
+
+sub drop_index
+{
+ my ($self,$table,$index) = @_;
+ return "DROP INDEX $index ON $table";
+}
+
+#
+# Abort if the server has crashed
+# return: 0 if ok
+# 1 question should be retried
+#
+
+sub abort_if_fatal_error
+{
+ return 1 if (($DBI::errstr =~ /The database engine couldn\'t lock table/i) ||
+ ($DBI::errstr =~ /niet vergrendelen. De tabel is momenteel in gebruik /i) ||
+ ($DBI::errstr =~ /Den anv.* redan av en annan/i) ||
+ ($DBI::errstr =~ /non-exclusive access/));
+ return 0;
+}
+
+sub small_rollback_segment
+{
+ return 0;
+}
+
+sub reconnect_on_errors
+{
+ return 1;
+}
+
+#############################################################################
+# Configuration for Microsoft SQL server
+#############################################################################
+
+package db_ms_sql;
+
+sub new
+{
+ my ($type,$host,$database)= @_;
+ my $self= {};
+ my %limits;
+ bless $self;
+
+ $self->{'cmp_name'} = "ms-sql";
+ $self->{'data_source'} = "DBI:ODBC:$database";
+ if (defined($opt_host) && $opt_host ne "")
+ {
+ $self->{'data_source'} .= ":$host";
+ }
+ $self->{'limits'} = \%limits;
+ $self->{'smds'} = \%smds;
+ $self->{'blob'} = "text";
+ $self->{'text'} = "text";
+ $self->{'double_quotes'} = 1; # Can handle: 'Walker''s'
+
+ $limits{'max_conditions'} = 1030; # We get 'Query is too complex'
+ $limits{'max_columns'} = 250; # Max number of columns in table
+ $limits{'max_tables'} = 65000; # Should be big enough
+ $limits{'max_text_size'} = 9830; # Max size with default buffers.
+ $limits{'query_size'} = 9830; # Max size with default buffers.
+ $limits{'max_index'} = 64; # Max number of keys
+ $limits{'max_index_parts'} = 15; # Max segments/key
+ $limits{'max_column_name'} = 30; # max table and column name
+
+ $limits{'join_optimizer'} = 1; # Can optimize FROM tables
+ $limits{'load_data_infile'} = 0; # Has load data infile
+ $limits{'lock_tables'} = 0; # Has lock tables
+ $limits{'functions'} = 1; # Has simple functions (+/-)
+ $limits{'group_functions'} = 1; # Have group functions
+ $limits{'group_func_sql_min_str'} = 1; # Can execute MIN() and MAX() on strings
+ $limits{'group_distinct_functions'}= 1; # Have count(distinct)
+ $limits{'select_without_from'}= 1; # Can do 'select 1';
+ $limits{'multi_drop'} = 1; # Drop table can take many tables
+ $limits{'subqueries'} = 1; # Supports sub-queries.
+ $limits{'left_outer_join'} = 1; # Supports left outer joins
+ $limits{'table_wildcard'} = 1; # Has SELECT table_name.*
+ $limits{'having_with_alias'} = 0; # Can use aliases in HAVING
+ $limits{'having_with_group'} = 1; # Can't use group functions in HAVING
+ $limits{'like_with_column'} = 1; # Can use column1 LIKE column2
+ $limits{'order_by_position'} = 1; # Can use 'ORDER BY 1'
+ $limits{'group_by_position'} = 0; # Can use 'GROUP BY 1'
+ $limits{'alter_table'} = 1;
+ $limits{'alter_add_multi_col'}= 0;
+ $limits{'alter_table_dropcol'}= 0;
+
+ $limits{'group_func_extra_std'} = 0; # Have group function std().
+
+ $limits{'func_odbc_mod'} = 0; # Have function mod.
+ $limits{'func_extra_%'} = 1; # Has % as alias for mod()
+ $limits{'func_odbc_floor'} = 1; # Has func_odbc_floor function
+ $limits{'func_extra_if'} = 0; # Have function if.
+ $limits{'column_alias'} = 1; # Alias for fields in select statement.
+ $limits{'NEG'} = 1; # Supports -id
+ $limits{'func_extra_in_num'} = 0; # Has function in
+ return $self;
+}
+
+#
+# Get the version number of the database
+#
+
+sub version
+{
+ my ($self)=@_;
+ my($sth,@row);
+ $dbh=$self->connect();
+ $sth = $dbh->prepare("SELECT \@\@VERSION") or die $DBI::errstr;
+ $sth->execute or die $DBI::errstr;
+ @row = $sth->fetchrow_array;
+ if ($row[0]) {
+ @server = split(/\n/,$row[0]);
+ chomp(@server);
+ return "$server[0]";
+ } else {
+ return "Microsoft SQL server ?";
+ }
+}
+
+sub connect
+{
+ my ($self)=@_;
+ my ($dbh);
+ $dbh=DBI->connect($self->{'data_source'}, $main::opt_user,
+ $main::opt_password,{ PrintError => 0}) ||
+ die "Got error: '$DBI::errstr' when connecting to " . $self->{'data_source'} ." with user: '$main::opt_user' password: '$main::opt_password'\n";
+ return $dbh;
+}
+
+#
+# Returns a list of statements to create a table
+# The field types are in ANSI SQL format.
+#
+
+sub create
+{
+ my($self,$table_name,$fields,$index) = @_;
+ my($query,@queries,$nr);
+
+ $query="create table $table_name (";
+ foreach $field (@$fields)
+ {
+ $field =~ s/mediumint/integer/i;
+ $field =~ s/float\(\d+,\d+\)/float/i;
+ $field =~ s/double\(\d+,\d+\)/float/i;
+ $field =~ s/double/float/i;
+ $field =~ s/integer\(\d+\)/integer/i;
+ $field =~ s/int\(\d+\)/integer/i;
+ $field =~ s/smallint\(\d+\)/smallint/i;
+ $field =~ s/smallinteger/smallint/i;
+ $field =~ s/tinyint\(\d+\)/tinyint/i;
+ $field =~ s/tinyinteger/tinyint/i;
+ $field =~ s/blob/text/i;
+ $query.= $field . ',';
+ }
+ substr($query,-1)=")"; # Remove last ',';
+ push(@queries,$query);
+ $nr=0;
+ foreach $index (@$index)
+ {
+ $ext="WITH DISALLOW NULL";
+ if (($index =~ s/primary key/unique index primary_key/i))
+ {
+ $ext="WITH PRIMARY;"
+ }
+ if ($index =~ /^unique.*\(([^\(]*)\)$/i)
+ {
+ $nr++;
+ $index="unique index ${table_name}_$nr ($1)";
+ }
+ $index =~ /^(.*)\s+(\(.*\))$/;
+ push(@queries,"create ${1} on $table_name $2");
+ }
+ return @queries;
+}
+
+#
+# Do any conversions to the ANSI SQL query so that the database can handle it
+#
+
+sub query {
+ my($self,$sql) = @_;
+ return $sql;
+}
+
+sub drop_index
+{
+ my ($self,$table,$index) = @_;
+ return "DROP INDEX $table.$index";
+}
+
+#
+# Abort if the server has crashed
+# return: 0 if ok
+# 1 question should be retried
+#
+
+sub abort_if_fatal_error
+{
+ return 0;
+}
+
+sub small_rollback_segment
+{
+ return 0;
+}
+
+sub reconnect_on_errors
+{
+ return 0;
+}
+
+#############################################################################
+# Configuration for Sybase
+#############################################################################
+
+package db_sybase;
+
+sub new
+{
+ my ($type,$host,$database)= @_;
+ my $self= {};
+ my %limits;
+ bless $self;
+
+ $self->{'cmp_name'} = "sybase";
+ $self->{'data_source'} = "DBI:ODBC:$database";
+ if (defined($opt_host) && $opt_host ne "")
+ {
+ $self->{'data_source'} .= ":$host";
+ }
+ $self->{'limits'} = \%limits;
+ $self->{'smds'} = \%smds;
+ $self->{'blob'} = "text";
+ $self->{'text'} = "text";
+ $self->{'double_quotes'} = 1; # Can handle: 'Walker''s'
+ $self->{"vacuum"} = 1;
+
+ $limits{'max_conditions'} = 1030; # We get 'Query is too complex'
+ $limits{'max_columns'} = 250; # Max number of columns in table
+ $limits{'max_tables'} = 65000; # Should be big enough
+ $limits{'max_text_size'} = 9830; # Max size with default buffers.
+ $limits{'query_size'} = 9830; # Max size with default buffers.
+ $limits{'max_index'} = 64; # Max number of keys
+ $limits{'max_index_parts'} = 15; # Max segments/key
+ $limits{'max_column_name'} = 30; # max table and column name
+
+ $limits{'join_optimizer'} = 1; # Can optimize FROM tables
+ $limits{'load_data_infile'} = 0; # Has load data infile
+ $limits{'lock_tables'} = 0; # Has lock tables
+ $limits{'functions'} = 1; # Has simple functions (+/-)
+ $limits{'group_functions'} = 1; # Have group functions
+ $limits{'group_func_sql_min_str'} = 1; # Can execute MIN() and MAX() on strings
+ $limits{'group_distinct_functions'}= 1; # Have count(distinct)
+ $limits{'select_without_from'}= 1; # Can do 'select 1';
+ $limits{'multi_drop'} = 1; # Drop table can take many tables
+ $limits{'subqueries'} = 1; # Supports sub-queries.
+ $limits{'left_outer_join'} = 1; # Supports left outer joins
+ $limits{'table_wildcard'} = 1; # Has SELECT table_name.*
+ $limits{'having_with_alias'} = 0; # Can use aliases in HAVING
+ $limits{'having_with_group'} = 1; # Can't use group functions in HAVING
+ $limits{'like_with_column'} = 1; # Can use column1 LIKE column2
+ $limits{'order_by_position'} = 1; # Can use 'ORDER BY 1'
+ $limits{'group_by_position'} = 0; # Can use 'GROUP BY 1'
+ $limits{'alter_table'} = 1;
+ $limits{'alter_add_multi_col'}= 0;
+ $limits{'alter_table_dropcol'}= 0;
+
+ $limits{'group_func_extra_std'} = 0; # Have group function std().
+
+ $limits{'func_odbc_mod'} = 0; # Have function mod.
+ $limits{'func_extra_%'} = 1; # Has % as alias for mod()
+ $limits{'func_odbc_floor'} = 1; # Has func_odbc_floor function
+ $limits{'func_extra_if'} = 0; # Have function if.
+ $limits{'column_alias'} = 1; # Alias for fields in select statement.
+ $limits{'NEG'} = 1; # Supports -id
+ $limits{'func_extra_in_num'} = 0; # Has function in
+ return $self;
+}
+
+#
+# Get the version number of the database
+#
+
+sub version
+{
+ my ($self)=@_;
+ return "Sybase enterprise 11.5 NT"; #DBI/ODBC can't return the server version
+}
+
+sub connect
+{
+ my ($self)=@_;
+ my ($dbh);
+ $dbh=DBI->connect($self->{'data_source'}, $main::opt_user,
+ $main::opt_password,{ PrintError => 0}) ||
+ die "Got error: '$DBI::errstr' when connecting to " . $self->{'data_source'} ." with user: '$main::opt_user' password: '$main::opt_password'\n";
+ return $dbh;
+}
+
+#
+# Returns a list of statements to create a table
+# The field types are in ANSI SQL format.
+#
+
+sub create
+{
+ my($self,$table_name,$fields,$index) = @_;
+ my($query,@queries,$nr);
+
+ $query="create table $table_name (";
+ foreach $field (@$fields)
+ {
+ $field =~ s/mediumint/integer/i;
+ $field =~ s/float\(\d+,\d+\)/float/i;
+ $field =~ s/int\(\d+\)/int/i;
+ $field =~ s/double/float/i;
+ $field =~ s/integer\(\d+\)/integer/i;
+ $field =~ s/smallint\(\d+\)/smallint/i;
+ $field =~ s/tinyint\(\d+\)/tinyint/i;
+ $field =~ s/blob/text/i;
+ $query.= $field . ',';
+ }
+ substr($query,-1)=")"; # Remove last ',';
+ push(@queries,$query);
+ $nr=0;
+ foreach $index (@$index)
+ {
+# $ext="WITH DISALLOW NULL";
+ if (($index =~ s/primary key/unique index primary_key/i))
+ {
+# $ext="WITH PRIMARY;"
+ }
+ if ($index =~ /^unique.*\(([^\(]*)\)$/i)
+ {
+ $nr++;
+ $index="unique index ${table_name}_$nr ($1)";
+ }
+ $index =~ /^(.*)\s+(\(.*\))$/;
+ push(@queries,"create ${1} on $table_name $2");
+ }
+ return @queries;
+}
+
+#
+# Do any conversions to the ANSI SQL query so that the database can handle it
+#
+
+sub query {
+ my($self,$sql) = @_;
+ return $sql;
+}
+
+sub drop_index
+{
+ my ($self,$table,$index) = @_;
+ return "DROP INDEX $table.$index";
+}
+
+#
+# Abort if the server has crashed
+# return: 0 if ok
+# 1 question should be retried
+#
+
+sub abort_if_fatal_error
+{
+ return 0;
+}
+
+sub small_rollback_segment
+{
+ return 0;
+}
+
+sub reconnect_on_errors
+{
+ return 0;
+}
+
+#
+# optimize the tables ....
+#
+sub vacuum
+{
+ my ($self,$full_vacuum,$dbh_ref)=@_;
+ my ($loop_time,$end_time,$dbh);
+
+ if (defined($full_vacuum))
+ {
+ $$dbh_ref->disconnect; $$dbh_ref= $self->connect();
+ }
+ $dbh=$$dbh_ref;
+ $loop_time=new Benchmark;
+ $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";
+ $dbh->disconnect; $$dbh_ref= $self->connect();
+}
+
+
+#############################################################################
+# Definitions for Adabas
+#############################################################################
+
+package db_Adabas;
+
+sub new
+{
+ my ($type,$host,$database)= @_;
+ my $self= {};
+ my %limits;
+ bless $self;
+
+ $self->{'cmp_name'} = "Adabas";
+ $self->{'data_source'} = "DBI:Adabas:$database";
+ $self->{'limits'} = \%limits;
+ $self->{'smds'} = \%smds;
+ $self->{'blob'} = "long";
+ $self->{'text'} = "long";
+ $self->{'double_quotes'} = 1; # Can handle: 'Walker''s'
+
+ $limits{'max_conditions'} = 50; # (Actually not a limit)
+ $limits{'max_columns'} = 254; # Max number of columns in table
+ $limits{'max_tables'} = 65000; # Should be big enough
+ $limits{'max_text_size'} = 2000; # Limit for blob test-connect
+ $limits{'query_size'} = 65525; # Max size with default buffers.
+ $limits{'max_index'} = 16; # Max number of keys
+ $limits{'max_index_parts'} = 16; # Max segments/key
+ $limits{'max_column_name'} = 32; # max table and column name
+
+ $limits{'join_optimizer'} = 1; # Can optimize FROM tables
+ $limits{'load_data_infile'} = 0; # Has load data infile
+ $limits{'lock_tables'} = 0; # Has lock tables
+ $limits{'functions'} = 1; # Has simple functions (+/-)
+ $limits{'group_functions'} = 1; # Have group functions
+ $limits{'group_func_sql_min_str'} = 1; # Can execute MIN() and MAX() on strings
+ $limits{'group_distinct_functions'}= 1; # Have count(distinct)
+ $limits{'select_without_from'}= 0;
+ $limits{'multi_drop'} = 0;
+ $limits{'subqueries'} = 1;
+ $limits{'left_outer_join'} = 0; # This may be fixed in the query module
+ $limits{'table_wildcard'} = 1; # Has SELECT table_name.*
+ $limits{'having_with_alias'} = 0; # Can use aliases in HAVING
+ $limits{'having_with_group'} = 1; # Can't use group functions in HAVING
+ $limits{'like_with_column'} = 1; # Can use column1 LIKE column2
+ $limits{'order_by_position'} = 1; # Can use 'ORDER BY 1'
+ $limits{'group_by_position'} = 1;
+ $limits{'alter_table'} = 1;
+ $limits{'alter_add_multi_col'}= 2; #Have ALTER TABLE t add a int, b int;
+ $limits{'alter_table_dropcol'}= 1;
+
+ $limits{'group_func_extra_std'} = 0; # Have group function std().
+
+ $limits{'func_odbc_mod'} = 0; # Oracle has problem with mod()
+ $limits{'func_extra_%'} = 0; # Has % as alias for mod()
+ $limits{'func_odbc_floor'} = 1; # Has func_odbc_floor function
+ $limits{'func_extra_if'} = 0; # Have function if.
+ $limits{'column_alias'} = 1; # Alias for fields in select statement.
+ $limits{'NEG'} = 1; # Supports -id
+ $limits{'func_extra_in_num'} = 1; # Has function in
+
+ $smds{'time'} = 1;
+ $smds{'q1'} = 'b'; # with time not supp by mysql ('')
+ $smds{'q2'} = 'b';
+ $smds{'q3'} = 'b'; # with time ('')
+ $smds{'q4'} = 'c'; # with time not supp by mysql (d)
+ $smds{'q5'} = 'b'; # with time not supp by mysql ('')
+ $smds{'q6'} = 'c'; # with time not supp by mysql ('')
+ $smds{'q7'} = 'c';
+ $smds{'q8'} = 'f';
+ $smds{'q9'} = 'c';
+ $smds{'q10'} = 'b';
+ $smds{'q11'} = 'b';
+ $smds{'q12'} = 'd';
+ $smds{'q13'} = 'c';
+ $smds{'q14'} = 'd';
+ $smds{'q15'} = 'd';
+ $smds{'q16'} = 'a';
+ $smds{'q17'} = 'c';
+
+ return $self;
+}
+
+#
+# Get the version number of the database
+#
+
+sub version
+{
+ my ($self)=@_;
+ my ($dbh,$sth,$version,@row);
+
+ $dbh=$self->connect();
+ $sth = $dbh->prepare("SELECT KERNEL FROM VERSIONS") or die $DBI::errstr;
+ $version="Adabas (unknown)";
+ if ($sth->execute && (@row = $sth->fetchrow_array)
+ && $row[0] =~ /([\d\.]+)/)
+ {
+ $version="Adabas $1";
+ }
+ $sth->finish;
+ $dbh->disconnect;
+ return $version;
+}
+
+sub connect
+{
+ my ($self)=@_;
+ my ($dbh);
+ $dbh=DBI->connect($self->{'data_source'}, $main::opt_user,
+ $main::opt_password,{ PrintError => 0}) ||
+ die "Got error: '$DBI::errstr' when connecting to " . $self->{'data_source'} ." with user: '$main::opt_user' password: '$main::opt_password'\n";
+ return $dbh;
+}
+
+#
+# Returns a list of statements to create a table
+# The field types are in ANSI SQL format.
+#
+# If one uses $main::opt_fast then one is allowed to use
+# non standard types to get better speed.
+#
+
+sub create
+{
+ my($self,$table_name,$fields,$index) = @_;
+ my($query,@queries,$ind,@keys);
+
+ $query="create table $table_name (";
+ foreach $field (@$fields)
+ {
+ $field =~ s/CHARACTER\s+VARYING/VARCHAR/i;
+ $field =~ s/TINYINT/SMALLINT/i;
+ $field =~ s/MEDIUMINT/INT/i;
+ $field =~ s/SMALLINT\s*\(\d+\)/SMALLINT/i;
+ $field =~ s/INT\s*\(\d+\)/INT/i;
+ $field =~ s/BLOB/LONG/i;
+ $field =~ s/INTEGER\s*\(\d+\)/INTEGER/i;
+ $field =~ s/FLOAT\s*\((\d+),\d+\)/FLOAT\($1\)/i;
+ $field =~ s/DOUBLE/FLOAT\(38\)/i;
+ $field =~ s/DOUBLE\s+PRECISION/FLOAT\(38\)/i;
+ $query.= $field . ',';
+ }
+
+ foreach $ind (@$index)
+ {
+ my @index;
+ if ( $ind =~ /\bKEY\b/i ){
+ push(@keys,"ALTER TABLE $table_name ADD $ind");
+ }else{
+ my @fields = split(' ',$index);
+ my $query="CREATE INDEX $fields[1] ON $table_name $fields[2]";
+ push(@index,$query);
+ }
+ }
+ substr($query,-1)=")"; # Remove last ',';
+ push(@queries,$query,@keys,@index);
+#print "query:$query\n";
+
+ return @queries;
+}
+
+sub insert_file {
+ my($self,$dbname, $file) = @_;
+ print "insert an ascii file isn't supported by Oracle (?)\n";
+ return 0;
+}
+
+#
+# Do any conversions to the ANSI SQL query so that the database can handle it
+#
+
+sub query {
+ my($self,$sql) = @_;
+ return $sql;
+}
+
+sub drop_index
+{
+ my ($self,$table,$index) = @_;
+ return "DROP INDEX $index";
+}
+
+#
+# Abort if the server has crashed
+# return: 0 if ok
+# 1 question should be retried
+#
+
+sub abort_if_fatal_error
+{
+ return 0;
+}
+
+sub small_rollback_segment
+{
+ return 0;
+}
+
+sub reconnect_on_errors
+{
+ return 0;
+}
+
+#############################################################################
+# Configuration for IBM DB2
+#############################################################################
+
+package db_db2;
+
+sub new
+{
+ my ($type,$host,$database)= @_;
+ my $self= {};
+ my %limits;
+ bless $self;
+
+ $self->{'cmp_name'} = "DB2";
+ $self->{'data_source'} = "DBI:ODBC:$database";
+ if (defined($opt_host) && $opt_host ne "")
+ {
+ $self->{'data_source'} .= ":$host";
+ }
+ $self->{'limits'} = \%limits;
+ $self->{'smds'} = \%smds;
+ $self->{'blob'} = "varchar(255)";
+ $self->{'text'} = "varchar(255)";
+ $self->{'double_quotes'} = 1; # Can handle: 'Walker''s'
+
+ $limits{'max_conditions'} = 418; # We get 'Query is too complex'
+ $limits{'max_columns'} = 500; # Max number of columns in table
+ $limits{'max_tables'} = 65000; # Should be big enough
+ $limits{'max_text_size'} = 254; # Max size with default buffers.
+ $limits{'query_size'} = 254; # Max size with default buffers.
+ $limits{'max_index'} = 48; # Max number of keys
+ $limits{'max_index_parts'} = 15; # Max segments/key
+ $limits{'max_column_name'} = 18; # max table and column name
+
+ $limits{'join_optimizer'} = 1; # Can optimize FROM tables
+ $limits{'load_data_infile'} = 0; # Has load data infile
+ $limits{'lock_tables'} = 0; # Has lock tables
+ $limits{'functions'} = 1; # Has simple functions (+/-)
+ $limits{'group_functions'} = 1; # Have group functions
+ $limits{'group_func_sql_min_str'}= 1;
+ $limits{'group_distinct_functions'}= 1; # Have count(distinct)
+ $limits{'select_without_from'}= 0; # Can do 'select 1';
+ $limits{'multi_drop'} = 0; # Drop table can take many tables
+ $limits{'subqueries'} = 1; # Supports sub-queries.
+ $limits{'left_outer_join'} = 1; # Supports left outer joins
+ $limits{'table_wildcard'} = 1; # Has SELECT table_name.*
+ $limits{'having_with_alias'} = 0; # Can use aliases in HAVING
+ $limits{'having_with_group'} = 1; # Can't use group functions in HAVING
+ $limits{'like_with_column'} = 0; # Can use column1 LIKE column2
+ $limits{'order_by_position'} = 1; # Can use 'ORDER BY 1'
+ $limits{'group_by_position'} = 0; # Can use 'GROUP BY 1'
+ $limits{'alter_table'} = 1;
+ $limits{'alter_add_multi_col'}= 0;
+ $limits{'alter_table_dropcol'}= 0;
+
+ $limits{'group_func_extra_std'} = 0; # Have group function std().
+
+ $limits{'func_odbc_mod'} = 1; # Have function mod.
+ $limits{'func_extra_%'} = 0; # Has % as alias for mod()
+ $limits{'func_odbc_floor'} = 1; # Has func_odbc_floor function
+ $limits{'func_extra_if'} = 0; # Have function if.
+ $limits{'column_alias'} = 1; # Alias for fields in select statement.
+ $limits{'NEG'} = 1; # Supports -id
+ $limits{'func_extra_in_num'} = 0; # Has function in
+ return $self;
+}
+
+#
+# Get the version number of the database
+#
+
+sub version
+{
+ my ($self)=@_;
+ return "IBM DB2 5"; #DBI/ODBC can't return the server version
+}
+
+sub connect
+{
+ my ($self)=@_;
+ my ($dbh);
+ $dbh=DBI->connect($self->{'data_source'}, $main::opt_user, $main::opt_password) ||
+ die "Got error: '$DBI::errstr' when connecting to " . $self->{'data_source'} ." with user: '$main::opt_user' password: '$main::opt_password'\n";
+ return $dbh;
+}
+
+#
+# Returns a list of statements to create a table
+# The field types are in ANSI SQL format.
+#
+
+sub create
+{
+ my($self,$table_name,$fields,$index) = @_;
+ my($query,@queries,$nr);
+
+ $query="create table $table_name (";
+ foreach $field (@$fields)
+ {
+ $field =~ s/mediumint/integer/i;
+ $field =~ s/float\(\d+,\d+\)/float/i;
+ $field =~ s/integer\(\d+\)/integer/i;
+ $field =~ s/int\(\d+\)/integer/i;
+ $field =~ s/tinyint\(\d+\)/smallint/i;
+ $field =~ s/tinyint/smallint/i;
+ $field =~ s/smallint\(\d+\)/smallint/i;
+ $field =~ s/smallinteger/smallint/i;
+ $field =~ s/blob/varchar(256)/i;
+ $query.= $field . ',';
+ }
+ substr($query,-1)=")"; # Remove last ',';
+ push(@queries,$query);
+ $nr=0;
+ foreach $index (@$index)
+ {
+ $ext="WITH DISALLOW NULL";
+ if (($index =~ s/primary key/unique index primary_key/i))
+ {
+ $ext="WITH PRIMARY;"
+ }
+ if ($index =~ /^unique.*\(([^\(]*)\)$/i)
+ {
+ $nr++;
+ $index="unique index ${table_name}_$nr ($1)";
+ }
+ $index =~ /^(.*)\s+(\(.*\))$/;
+ push(@queries,"create ${1} on $table_name $2");
+ }
+ return @queries;
+}
+
+#
+# Do any conversions to the ANSI SQL query so that the database can handle it
+#
+
+sub query {
+ my($self,$sql) = @_;
+ return $sql;
+}
+
+sub drop_index
+{
+ my ($self,$table,$index) = @_;
+ return "DROP INDEX $table.$index";
+}
+
+#
+# Abort if the server has crashed
+# return: 0 if ok
+# 1 question should be retried
+#
+
+sub abort_if_fatal_error
+{
+ return 0;
+}
+
+sub small_rollback_segment
+{
+ return 1;
+}
+
+sub reconnect_on_errors
+{
+ return 0;
+}
+
+#############################################################################
+# Configuration for MIMER
+#############################################################################
+
+package db_Mimer;
+
+sub new
+{
+ my ($type,$host,$database)= @_;
+ my $self= {};
+ my %limits;
+ bless $self;
+
+ $self->{'cmp_name'} = "mimer";
+ $self->{'data_source'} = "DBI:mimer:$database:$host";
+ $self->{'limits'} = \%limits;
+ $self->{'smds'} = \%smds;
+ $self->{'blob'} = "binary varying(15000)";
+ $self->{'text'} = "character varying(15000)";
+ $self->{'double_quotes'} = 1; # Can handle: 'Walker''s'
+ $self->{'char_null'} = "cast(NULL as char(1))";
+ $self->{'numeric_null'} = "cast(NULL as int)";
+
+ $limits{'max_conditions'} = 9999; # (Actually not a limit)
+ $limits{'max_columns'} = 252; # Max number of columns in table
+ $limits{'max_tables'} = 65000; # Should be big enough
+ $limits{'max_text_size'} = 15000; # Max size with default buffers.
+ $limits{'query_size'} = 1000000; # Max size with default buffers.
+ $limits{'max_index'} = 32; # Max number of keys
+ $limits{'max_index_parts'} = 16; # Max segments/key
+ $limits{'max_column_name'} = 128; # max table and column name
+
+ $limits{'join_optimizer'} = 1; # Can optimize FROM tables
+ $limits{'load_data_infile'} = 1; # Has load data infile
+ $limits{'lock_tables'} = 0; # Has lock tables
+ $limits{'functions'} = 1; # Has simple functions (+/-)
+ $limits{'group_functions'} = 1; # Have group functions
+ $limits{'group_func_sql_min_str'} = 1; # Can execute MIN() and MAX() on strings
+ $limits{'group_distinct_functions'}= 1; # Have count(distinct)
+ $limits{'select_without_from'}= 0; # Cannot do 'select 1';
+ $limits{'multi_drop'} = 0; # Drop table cannot take many tables
+ $limits{'subqueries'} = 1; # Supports sub-queries.
+ $limits{'left_outer_join'} = 1; # Supports left outer joins
+ $limits{'table_wildcard'} = 1; # Has SELECT table_name.*
+ $limits{'having_with_alias'} = 1; # Can use aliases in HAVING
+ $limits{'having_with_group'} = 1; # Can use group functions in HAVING
+ $limits{'like_with_column'} = 1; # Can use column1 LIKE column2
+ $limits{'order_by_position'} = 1; # Can use 'ORDER BY 1'
+ $limits{'group_by_position'} = 0; # Cannot use 'GROUP BY 1'
+ $limits{'alter_table'} = 1; # Have ALTER TABLE
+ $limits{'alter_add_multi_col'}= 0; # Have ALTER TABLE t add a int,add b int;
+ $limits{'alter_table_dropcol'}= 1; # Have ALTER TABLE DROP column
+ $limits{'multi_value_insert'} = 0; # Does not have INSERT ... values (1,2),(3,4)
+
+ $limits{'group_func_extra_std'} = 0; # Does not have group function std().
+
+ $limits{'func_odbc_mod'} = 1; # Have function mod.
+ $limits{'func_extra_%'} = 0; # Does not have % as alias for mod()
+ $limits{'func_odbc_floor'} = 1; # Has func_odbc_floor function
+ $limits{'func_extra_if'} = 0; # Does not have function if.
+ $limits{'column_alias'} = 1; # Alias for fields in select statement.
+ $limits{'NEG'} = 1; # Supports -id
+ $limits{'func_extra_in_num'} = 1; # Has function in
+ $limits{'limit'} = 0; # Does not support the limit attribute
+
+ $smds{'time'} = 1;
+ $smds{'q1'} = 'b'; # with time not supp by mysql ('')
+ $smds{'q2'} = 'b';
+ $smds{'q3'} = 'b'; # with time ('')
+ $smds{'q4'} = 'c'; # with time not supp by mysql (d)
+ $smds{'q5'} = 'b'; # with time not supp by mysql ('')
+ $smds{'q6'} = 'c'; # with time not supp by mysql ('')
+ $smds{'q7'} = 'c';
+ $smds{'q8'} = 'f';
+ $smds{'q9'} = 'c';
+ $smds{'q10'} = 'b';
+ $smds{'q11'} = 'b';
+ $smds{'q12'} = 'd';
+ $smds{'q13'} = 'c';
+ $smds{'q14'} = 'd';
+ $smds{'q15'} = 'd';
+ $smds{'q16'} = 'a';
+ $smds{'q17'} = 'c';
+
+ return $self;
+}
+
+#
+# Get the version number of the database
+#
+
+sub version
+{
+ my ($self)=@_;
+ my ($dbh,$sth,$version,@row);
+
+ $dbh=$self->connect();
+#
+# Pick up SQLGetInfo option SQL_DBMS_VER (18)
+#
+ $version = $dbh->func(18, GetInfo);
+ $dbh->disconnect;
+ return $version;
+}
+
+#
+# Connection with optional disabling of logging
+#
+
+sub connect
+{
+ my ($self)=@_;
+ my ($dbh);
+ $dbh=DBI->connect($self->{'data_source'}, $main::opt_user,
+ $main::opt_password,{ PrintError => 0}) ||
+ die "Got error: '$DBI::errstr' when connecting to " . $self->{'data_source'} ." with user: '$main::opt_user' password: '$main::opt_password'\n";
+
+ $dbh->do("SET OPTION LOG_OFF=1,UPDATE_LOG=0");
+ return $dbh;
+}
+
+#
+# Returns a list of statements to create a table
+# The field types are in ANSI SQL format.
+#
+# If one uses $main::opt_fast then one is allowed to use
+# non standard types to get better speed.
+#
+
+sub create
+{
+ my($self,$table_name,$fields,$index,$options) = @_;
+ my($query,@queries);
+
+ $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 ?
+ $query.= $field . ',';
+ }
+ foreach $index (@$index)
+ {
+ $query.= $index . ',';
+ }
+ substr($query,-1)=")"; # Remove last ',';
+ $query.=" $options" if (defined($options));
+ push(@queries,$query);
+ return @queries;
+}
+
+sub insert_file {
+ my($self,$dbname, $file) = @_;
+ print "insert of an ascii file isn't supported by Mimer\n";
+ return 0;
+}
+
+#
+# Do any conversions to the ANSI SQL query so that the database can handle it
+#
+
+sub query {
+ my($self,$sql) = @_;
+ return $sql;
+}
+
+sub drop_index {
+ my ($self,$table,$index) = @_;
+ return "DROP INDEX $index";
+}
+
+#
+# Abort if the server has crashed
+# return: 0 if ok
+# 1 question should be retried
+#
+
+sub abort_if_fatal_error
+{
+ return 1 if ($DBI::errstr =~ /Table locked by another cursor/);
+ return 0;
+}
+
+sub small_rollback_segment
+{
+ return 0;
+}
+
+sub reconnect_on_errors
+{
+ return 0;
+}
+
+#############################################################################
+# Configuration for InterBase
+#############################################################################
+
+package db_interbase;
+
+sub new
+{
+ my ($type,$host,$database)= @_;
+ my $self= {};
+ my %limits;
+ bless $self;
+
+ $self->{'cmp_name'} = "interbase";
+ $self->{'data_source'} = "DBI:InterBase:database=$database";
+ $self->{'limits'} = \%limits;
+ $self->{'smds'} = \%smds;
+ $self->{'blob'} = "blob";
+ $self->{'text'} = "";
+ $self->{'double_quotes'} = 1; # Can handle: 'Walker''s'
+ $self->{'char_null'} = "";
+ $self->{'numeric_null'} = "";
+
+ $limits{'max_conditions'} = 9999; # (Actually not a limit)
+ $limits{'max_columns'} = 252; # Max number of columns in table
+ $limits{'max_tables'} = 65000; # Should be big enough
+ $limits{'max_text_size'} = 15000; # Max size with default buffers.
+ $limits{'query_size'} = 1000000; # Max size with default buffers.
+ $limits{'max_index'} = 31; # Max number of keys
+ $limits{'max_index_parts'} = 8; # Max segments/key
+ $limits{'max_column_name'} = 128; # max table and column name
+
+ $limits{'join_optimizer'} = 1; # Can optimize FROM tables
+ $limits{'load_data_infile'} = 0; # Has load data infile
+ $limits{'lock_tables'} = 0; # Has lock tables
+ $limits{'functions'} = 1; # Has simple functions (+/-)
+ $limits{'group_functions'} = 1; # Have group functions
+ $limits{'group_func_sql_min_str'} = 1; # Can execute MIN() and MAX() on strings
+ $limits{'group_distinct_functions'}= 1; # Have count(distinct)
+ $limits{'select_without_from'}= 0; # Cannot do 'select 1';
+ $limits{'multi_drop'} = 0; # Drop table cannot take many tables
+ $limits{'subqueries'} = 1; # Supports sub-queries.
+ $limits{'left_outer_join'} = 1; # Supports left outer joins
+ $limits{'table_wildcard'} = 1; # Has SELECT table_name.*
+ $limits{'having_with_alias'} = 0; # Can use aliases in HAVING
+ $limits{'having_with_group'} = 1; # Can use group functions in HAVING
+ $limits{'like_with_column'} = 0; # Can use column1 LIKE column2
+ $limits{'order_by_position'} = 1; # Can use 'ORDER BY 1'
+ $limits{'group_by_position'} = 0; # Cannot use 'GROUP BY 1'
+ $limits{'alter_table'} = 1; # Have ALTER TABLE
+ $limits{'alter_add_multi_col'}= 1; # Have ALTER TABLE t add a int,add b int;
+ $limits{'alter_table_dropcol'}= 1; # Have ALTER TABLE DROP column
+ $limits{'multi_value_insert'} = 0; # Does not have INSERT ... values (1,2),(3,4)
+
+ $limits{'group_func_extra_std'} = 0; # Does not have group function std().
+
+ $limits{'func_odbc_mod'} = 0; # Have function mod.
+ $limits{'func_extra_%'} = 0; # Does not have % as alias for mod()
+ $limits{'func_odbc_floor'} = 0; # Has func_odbc_floor function
+ $limits{'func_extra_if'} = 0; # Does not have function if.
+ $limits{'column_alias'} = 1; # Alias for fields in select statement.
+ $limits{'NEG'} = 0; # Supports -id
+ $limits{'func_extra_in_num'} = 0; # Has function in
+ $limits{'limit'} = 0; # Does not support the limit attribute
+
+ $smds{'time'} = 1;
+ $smds{'q1'} = 'b'; # with time not supp by mysql ('')
+ $smds{'q2'} = 'b';
+ $smds{'q3'} = 'b'; # with time ('')
+ $smds{'q4'} = 'c'; # with time not supp by mysql (d)
+ $smds{'q5'} = 'b'; # with time not supp by mysql ('')
+ $smds{'q6'} = 'c'; # with time not supp by mysql ('')
+ $smds{'q7'} = 'c';
+ $smds{'q8'} = 'f';
+ $smds{'q9'} = 'c';
+ $smds{'q10'} = 'b';
+ $smds{'q11'} = 'b';
+ $smds{'q12'} = 'd';
+ $smds{'q13'} = 'c';
+ $smds{'q14'} = 'd';
+ $smds{'q15'} = 'd';
+ $smds{'q16'} = 'a';
+ $smds{'q17'} = 'c';
+
+ return $self;
+}
+
+#
+# Get the version number of the database
+#
+
+sub version
+{
+ my ($self)=@_;
+ my ($dbh,$sth,$version,@row);
+
+ $dbh=$self->connect();
+# $sth = $dbh->prepare("show version");
+# $sth->execute;
+# @row = $sth->fetchrow_array;
+# $version = $row[0];
+# $version =~ s/.*version \"(.*)\"$/$1/;
+ $dbh->disconnect;
+ $version = "6.0Beta";
+ return $version;
+}
+
+#
+# Connection with optional disabling of logging
+#
+
+sub connect
+{
+ my ($self)=@_;
+ my ($dbh);
+ $dbh=DBI->connect($self->{'data_source'}, $main::opt_user,
+ $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;
+}
+
+#
+# Returns a list of statements to create a table
+# The field types are in ANSI SQL format.
+#
+# If one uses $main::opt_fast then one is allowed to use
+# non standard types to get better speed.
+#
+
+sub create
+{
+ my($self,$table_name,$fields,$index,$options) = @_;
+ my($query,@queries);
+
+ $query="create table $table_name (";
+ foreach $field (@$fields)
+ {
+ $field =~ s/ big_decimal/ float/i;
+ $field =~ s/ double/ float/i;
+ $field =~ s/ tinyint/ smallint/i;
+ $field =~ s/ mediumint/ int/i;
+ $field =~ s/ integer/ int/i;
+ $field =~ s/ float\(\d,\d\)/ float/i;
+ $field =~ s/ date/ int/i; # Because of tcp ?
+ $field =~ s/ smallint\(\d\)/ smallint/i;
+ $field =~ s/ int\(\d\)/ int/i;
+ $query.= $field . ',';
+ }
+ foreach $ind (@$index)
+ {
+ my @index;
+ if ( $ind =~ /\bKEY\b/i ){
+ push(@keys,"ALTER TABLE $table_name ADD $ind");
+ }else{
+ my @fields = split(' ',$index);
+ my $query="CREATE INDEX $fields[1] ON $table_name $fields[2]";
+ push(@index,$query);
+ }
+ }
+ substr($query,-1)=")"; # Remove last ',';
+ $query.=" $options" if (defined($options));
+ push(@queries,$query);
+ return @queries;
+}
+
+sub insert_file {
+ my($self,$dbname, $file) = @_;
+ print "insert of an ascii file isn't supported by InterBase\n";
+ return 0;
+}
+
+#
+# Do any conversions to the ANSI SQL query so that the database can handle it
+#
+
+sub query {
+ my($self,$sql) = @_;
+ return $sql;
+}
+
+sub drop_index {
+ my ($self,$table,$index) = @_;
+ return "DROP INDEX $index";
+}
+
+#
+# Abort if the server has crashed
+# return: 0 if ok
+# 1 question should be retried
+#
+
+sub abort_if_fatal_error
+{
+ return 1 if ($DBI::errstr =~ /Table locked by another cursor/);
+ return 0;
+}
+
+sub small_rollback_segment
+{
+ return 1;
+}
+
+sub reconnect_on_errors
+{
+ return 1;
+}
+
+1;
diff --git a/sql-bench/test-ATIS.sh b/sql-bench/test-ATIS.sh
new file mode 100755
index 00000000000..35ec616d8f5
--- /dev/null
+++ b/sql-bench/test-ATIS.sh
@@ -0,0 +1,548 @@
+#!@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 creating the ATIS database and doing many different selects on it
+#
+# changes made for Oracle compatibility
+# - added Oracle to the '' to ' ' translation
+# - skip blank lines from the datafiles
+# - skip a couple of the tests in Q4 that Oracle doesn't understand
+################### Standard benchmark inits ##############################
+
+use DBI;
+use Benchmark;
+
+$opt_loop_count=100; # Run selects this many times
+
+chomp($pwd = `pwd`); $pwd = "." if ($pwd eq '');
+require "$pwd/bench-init.pl" || die "Can't read Configuration file: $!\n";
+
+if ($opt_small_test)
+{
+ $opt_loop_count/=10;
+}
+
+print "ATIS table test\n\n";
+
+####
+#### Connect and start timeing
+####
+
+$dbh = $server->connect();
+$start_time=new Benchmark;
+
+####
+#### Create needed tables
+####
+
+init_data(); # Get table definitions
+
+if (!$opt_skip_create)
+{
+ print "Creating tables\n";
+ $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");
+
+ print "Creating table $table_name\n" if ($opt_verbose);
+ do_many($dbh,@$array_ref);
+ }
+ $end_time=new Benchmark;
+ print "Time for create_table (" . ($#tables+1) ."): " .
+ timestr(timediff($end_time, $loop_time),"all") . "\n\n";
+
+if ($opt_fast && defined($server->{vacuum}))
+{
+ $server->vacuum(0,\$dbh);
+}
+
+####
+#### Insert data
+####
+
+ print "Inserting data\n";
+
+ $loop_time= new Benchmark;
+ $row_count=0;
+ $double_quotes=$server->{'double_quotes'};
+
+ if ($opt_lock_tables)
+ {
+ @tmp=@table_names; push(@tmp,@extra_names);
+ print "LOCK TABLES @tmp\n" if ($opt_debug);
+ $sth = $dbh->do("LOCK TABLES " . join(" WRITE,", @tmp) . " WRITE") ||
+ die $DBI::errstr;
+ }
+
+ 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/ATIS/${table_name}.txt";
+ 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];
+ my $array_ref = $tables[$ti];
+ my @table = @$array_ref;
+ my $insert_start = "insert into $table_name values (";
+
+ open(DATA, "$pwd/Data/ATIS/${table_name}.txt") || die "Can't open text file: $pwd/Data/ATIS/${table_name}.txt\n";
+ while(<DATA>)
+ {
+ 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);
+ print "$command\n" if ($opt_debug);
+ $command =~ s/\\'/\'\'/g if ($double_quotes);
+
+ $sth = $dbh->do($command) or die "Got error: $DBI::errstr when executing '$command'\n";
+ $row_count++;
+ }
+ }
+ close(DATA);
+ }
+ $end_time=new Benchmark;
+ print "Time to insert ($row_count): " .
+ 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(" READ,", @tmp) . " READ") ||
+ die $DBI::errstr;
+}
+
+if ($opt_fast && defined($server->{vacuum}))
+{
+ $server->vacuum(0,\$dbh);
+}
+
+#
+# Now the fun begins. Let's do some simple queries on the result
+#
+# The query array is defined as:
+# query, number of rows in result, 0|1 where 1 means that the query is possible
+#
+
+print "Retrieving data\n";
+@Q1=("select_simple_join",
+ "select city.city_name,state.state_name,city.city_code from city,state where city.city_code='MATL' and city.state_code=state.state_code",1,1,
+ "select city.city_name,state.state_name,city.city_code from state,city where city.state_code=state.state_code",11,1,
+ "select month_name.month_name,day_name.day_name from month_name,day_name where month_name.month_number=day_name.day_code",7,1,
+ "select month_name.month_name,day_name.day_name from month_name,day_name where month_name.month_number=day_name.day_code and day_name.day_code >= 4",4,1,
+ "select flight.flight_code,aircraft.aircraft_type from flight,aircraft where flight.aircraft_code=aircraft.aircraft_code",579,1,
+ );
+
+@Q2=("select_join",
+ "select airline.airline_name,aircraft.aircraft_type from aircraft,airline,flight where flight.aircraft_code=aircraft.aircraft_code and flight.airline_code=airline.airline_code",579,1,
+ "select fare.fare_code from restrict_carrier,airline,fare where restrict_carrier.airline_code=airline.airline_code and fare.restrict_code=restrict_carrier.restrict_code",5692,1,
+ );
+
+@Q3=("select_distinct",
+ "select distinct category from aircraft",6,1,
+ "select distinct from_airport from flight",9,1,
+ "select distinct aircraft_code from flight",22,1,
+ "select distinct * from fare",534,1,
+ "select distinct flight_code from flight_fare",579,1,
+ "select distinct flight.flight_code,aircraft.aircraft_type from flight,aircraft where flight.aircraft_code=aircraft.aircraft_code",579,1,
+ "select distinct airline.airline_name,aircraft.aircraft_type from aircraft,airline,flight where flight.aircraft_code=aircraft.aircraft_code and flight.airline_code=airline.airline_code",44,$limits->{'join_optimizer'},
+ "select distinct airline.airline_name,aircraft.aircraft_type from flight,aircraft,airline where flight.aircraft_code=aircraft.aircraft_code and flight.airline_code=airline.airline_code",44,1,
+ );
+
+@Q4=("select_group",
+ "select day_name.day_name,day_name.day_code,count(*) from flight_day,day_name where day_name.day_code=flight_day.day_code group by day_name.day_name,day_name.day_code order by day_name.day_code",7,$limits->{'group_functions'},
+ "select day_name.day_name,count(*) from flight_day,day_name where day_name.day_code=flight_day.day_code group by day_name.day_name",7,$limits->{'group_functions'},
+ "select month_name,day_name from month_name,day_name where month_number=day_code and day_code>3 group by month_name,day_name",4,$limits->{'group_functions'},
+ "select day_name.day_name,flight_day.day_code,count(*) from flight_day,day_name where day_name.day_code=flight_day.day_code group by flight_day.day_code,day_name.day_name order by flight_day.day_code",7,$limits->{'group_functions'},
+ "select sum(engines) from aircraft",1,$limits->{'group_functions'},
+ "select avg(engines) from aircraft",1,$limits->{'group_functions'},
+ "select avg(engines) from aircraft where engines>0",1,$limits->{'group_functions'},
+ "select count(*),min(pay_load),max(pay_load) from aircraft where pay_load>0",1,$limits->{'group_functions'},
+ "select min(flight_code),min(flight_code) from flight",1,$limits->{'group_functions'},
+ "select min(from_airport),min(to_airport) from flight",1,$limits->{'group_functions'} && $limits->{'group_func_sql_min_str'},
+ "select count(*) from aircraft where pay_load>10000",1,$limits->{'group_functions'},
+ "select count(*) from aircraft where pay_load<>0",1,$limits->{'group_functions'},
+ "select count(*) from flight where flight_code >= 112793",1,$limits->{'group_functions'},
+ "select count(if(pay_load,1,NULL)) from aircraft",1,$limits->{'if'} && $limits->{'group_functions'},
+ "select std(engines) from aircraft",1,$limits->{'group_func_extra_std'},
+ "SELECT from_airport,to_airport,avg(time_elapsed) FROM flight WHERE from_airport='ATL' AND to_airport='BOS' group by from_airport,to_airport",1,$limits->{'group_functions'},
+ "select city_code, avg(ground_fare) from ground_service where ground_fare<>0 group by city_code",11,$limits->{'group_functions'},
+ "select count(*), ground_service.city_code from ground_service group by ground_service.city_code",12,$limits->{'group_functions'},
+ "select category,count(*) as totalnr from aircraft where engines=2 group by category having totalnr>4",3,$limits->{'group_functions'} && $limits->{'having_with_alias'},
+ "select category,count(*) from aircraft where engines=2 group by category having count(*)>4",3,$limits->{'group_functions'} && $limits->{'having_with_group'},
+ "select flight_number,range_miles,fare_class FROM aircraft,flight,flight_class WHERE flight.flight_code=flight_class.flight_code AND flight.aircraft_code=aircraft.aircraft_code AND range_miles<>0 AND (stops=1 OR stops=2) GROUP BY flight_number,range_miles,fare_class",150,$limits->{'group_functions'},
+ "select distinct from_airport.time_zone_code,to_airport.time_zone_code,(FLOOR(arrival_time/100)*60+MOD(arrival_time,100)-FLOOR(departure_time/100)*60-MOD(departure_time,100)-time_elapsed)/60 AS time_zone_diff FROM flight,airport AS from_airport,airport AS to_airport WHERE flight.from_airport=from_airport.airport_code AND flight.to_airport=to_airport.airport_code GROUP BY from_airport.time_zone_code,to_airport.time_zone_code,arrival_time,departure_time,time_elapsed",21,$limits->{'func_odbc_mod'} && $limits->{'func_odbc_floor'} && $limits->{'group_functions'},
+ "select DISTINCT from_airport.time_zone_code,to_airport.time_zone_code,MOD((FLOOR(arrival_time/100)*60+MOD(arrival_time,100)-FLOOR(departure_time/100)*60-MOD(departure_time,100)-time_elapsed)/60+36,24)-12 AS time_zone_diff FROM flight,airport AS from_airport,airport AS to_airport WHERE flight.from_airport=from_airport.airport_code AND flight.to_airport=to_airport.airport_code and MOD((FLOOR(arrival_time/100)*60+MOD(arrival_time,100)-FLOOR(departure_time/100)*60-MOD(departure_time,100)-time_elapsed)/60+36,24)-12 < 10",14,$limits->{'func_odbc_mod'} && $limits->{'func_odbc_floor'} && $limits->{'group_functions'},
+ "select from_airport,to_airport,range_miles,time_elapsed FROM aircraft,flight WHERE aircraft.aircraft_code=flight.aircraft_code AND to_airport NOT LIKE from_airport AND range_miles<>0 AND time_elapsed<>0 GROUP BY from_airport,to_airport,range_miles,time_elapsed",409,$limits->{'group_functions'} && $limits->{'like_with_column'},
+ "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 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'},
+ );
+
+@Q=(\@Q1,\@Q2,\@Q3,\@Q4);
+
+
+foreach $Q (@Q)
+{
+ $count=$estimated=0;
+ $loop_time= new Benchmark;
+ for ($i=1 ; $i <= $opt_loop_count; $i++)
+ {
+ for ($j=1 ; $j < $#$Q ; $j+=3)
+ {
+ if ($Q->[$j+2])
+ { # We can do it with current limits
+ $count++;
+ if ($i == 100) # Do something different
+ {
+ if (($row_count=fetch_all_rows($dbh,$server->query($Q->[$j]))) !=
+ $Q->[$j+1])
+ {
+ if ($row_count == undef())
+ {
+ die "Got error: $DBI::errstr when executing " . $Q->[$j] ."\n"."got $row_count instead of $Q->[$j+1] *** \n";
+ }
+ print "Warning: Query '" . $Q->[$j] . "' returned $row_count rows when it should have returned " . $Q->[$j+1] . " rows\n";
+ }
+ }
+ else
+ {
+ defined(fetch_all_rows($dbh,$server->query($Q->[$j])))
+ or die "ERROR: $DBI::errstr executing '$Q->[$j]'\n";
+ }
+ }
+ }
+ $end_time=new Benchmark;
+ last if ($estimated=predict_query_time($loop_time,$end_time,\$count,$i,
+ $opt_loop_count));
+ print "Loop $i\n" if ($opt_verbose);
+ }
+ if ($count)
+ {
+ if ($estimated)
+ { print "Estimated time"; }
+ else
+ { print "Time"; }
+ print " for " . $Q->[0] . " ($count): " .
+ timestr(timediff($end_time, $loop_time),"all") . "\n";
+ }
+}
+
+print "\n";
+
+####
+#### Delete the tables
+####
+
+if (!$opt_skip_delete) # Only used when testing
+{
+ print "Removing tables\n";
+ $loop_time= new Benchmark;
+ if ($opt_lock_tables)
+ {
+ $sth = $dbh->do("UNLOCK TABLES") || die $DBI::errstr;
+ }
+ for ($ti = 0; $ti <= $#table_names; $ti++)
+ {
+ my $table_name = $table_names[$ti];
+ $sth = $dbh->do("drop table $table_name");
+ }
+
+ $end_time=new Benchmark;
+ print "Time to drop_table (" .($#table_names+1) . "): " .
+ timestr(timediff($end_time, $loop_time),"all") . "\n";
+}
+
+if ($opt_fast && defined($server->{vacuum}))
+{
+ $server->vacuum(0,\$dbh);
+}
+
+####
+#### End of benchmark
+####
+
+$dbh->disconnect; # close connection
+
+end_benchmark($start_time);
+
+
+sub init_data
+{
+ @aircraft=
+ $server->create("aircraft",
+ ["aircraft_code char(3) NOT NULL",
+ "aircraft_type char(64) NOT NULL",
+ "engines tinyint(1) NOT NULL",
+ "category char(10) NOT NULL",
+ "wide_body char(3) NOT NULL",
+ "wing_span float(6,2) NOT NULL",
+ "length1 float(6,2) NOT NULL",
+ "weight integer(7) NOT NULL",
+ "capacity smallint(3) NOT NULL",
+ "pay_load integer(7) NOT NULL",
+ "cruising_speed mediumint(5) NOT NULL",
+ "range_miles mediumint(5) NOT NULL",
+ "pressurized char(3) NOT NULL"],
+ ["PRIMARY KEY (aircraft_code)"]);
+ @airline=
+ $server->create("airline",
+ ["airline_code char(2) NOT NULL",
+ "airline_name char(64) NOT NULL",
+ "notes char(38) NOT NULL"],
+ ["PRIMARY KEY (airline_code)"]);
+ @airport=
+ $server->create("airport",
+ ["airport_code char(3) NOT NULL",
+ "airport_name char(40) NOT NULL",
+ "location char(36) NOT NULL",
+ "state_code char(2) NOT NULL",
+ "country_name char(25) NOT NULL",
+ "time_zone_code char(3) NOT NULL"],
+ ["PRIMARY KEY (airport_code)"]);
+ @airport_service=
+ $server->create("airport_service",
+ ["city_code char(4) NOT NULL",
+ "airport_code char(3) NOT NULL",
+ "miles_distant float(4,1) NOT NULL",
+ "direction char(3) NOT NULL",
+ "minutes_distant smallint(3) NOT NULL"],
+ ["PRIMARY KEY (city_code, airport_code)"]);
+ @city=
+ $server->create("city",
+ ["city_code char(4) NOT NULL",
+ "city_name char(25) NOT NULL",
+ "state_code char(2) NOT NULL",
+ "country_name char(25) NOT NULL",
+ "time_zone_code char(3) NOT NULL"],
+ ["PRIMARY KEY (city_code)"]);
+ @class_of_service=
+ $server->create("class_of_service",
+ ["class_code char(2) NOT NULL",
+ "rank tinyint(2) NOT NULL",
+ "class_description char(80) NOT NULL"],
+ ["PRIMARY KEY (class_code)"]);
+ @code_description=
+ $server->create("code_description",
+ ["code char(5) NOT NULL",
+ "description char(110) NOT NULL"],
+ ["PRIMARY KEY (code)"]);
+ @compound_class=
+ $server->create("compound_class",
+ ["fare_class char(3) NOT NULL",
+ "base_class char(2) NOT NULL",
+ "class_type char(10) NOT NULL",
+ "premium char(3) NOT NULL",
+ "economy char(3) NOT NULL",
+ "discounted char(3) NOT NULL",
+ "night char(3) NOT NULL",
+ "season_fare char(4) NOT NULL",
+ "class_days char(7) NOT NULL"],
+ ["PRIMARY KEY (fare_class)"]);
+ @connect_leg=
+ $server->create("connect_leg",
+ ["connect_code integer(8) NOT NULL",
+ "leg_number tinyint(1) NOT NULL",
+ "flight_code integer(8) NOT NULL"],
+ ["PRIMARY KEY (connect_code, leg_number, flight_code)"]);
+ @connection=
+ $server->create("connection",
+ ["connect_code integer(8) NOT NULL",
+ "from_airport char(3) NOT NULL",
+ "to_airport char(3) NOT NULL",
+ "departure_time smallint(4) NOT NULL",
+ "arrival_time smallint(4) NOT NULL",
+ "flight_days char(7) NOT NULL",
+ "stops tinyint(1) NOT NULL",
+ "connections tinyint(1) NOT NULL",
+ "time_elapsed smallint(4) NOT NULL"],
+ ["PRIMARY KEY (connect_code)",
+ "INDEX from_airport1 (from_airport)",
+ "INDEX to_airport1 (to_airport)"]);
+ @day_name=
+ $server->create("day_name",
+ ["day_code tinyint(1) NOT NULL",
+ "day_name char(9) NOT NULL"],
+ ["PRIMARY KEY (day_code)"]);
+ @dual_carrier=
+ $server->create("dual_carrier",
+ ["main_airline char(2) NOT NULL",
+ "dual_airline char(2) NOT NULL",
+ "low_flight smallint(4) NOT NULL",
+ "high_flight smallint(4) NOT NULL",
+ "connection_name char(64) NOT NULL"],
+ ["PRIMARY KEY (main_airline, dual_airline, low_flight)",
+ "INDEX main_airline1 (main_airline)"]);
+
+ @fare=
+ $server->create("fare",
+ ["fare_code char(8) NOT NULL",
+ "from_airport char(3) NOT NULL",
+ "to_airport char(3) NOT NULL",
+ "fare_class char(3) NOT NULL",
+ "fare_airline char(2) NOT NULL",
+ "restrict_code char(5) NOT NULL",
+ "one_way_cost float(7,2) NOT NULL",
+ "rnd_trip_cost float(8,2) NOT NULL"],
+ ["PRIMARY KEY (fare_code)",
+ "INDEX from_airport2 (from_airport)",
+ "INDEX to_airport2 (to_airport)"]);
+ @flight=
+ $server->create("flight",
+ ["flight_code integer(8) NOT NULL",
+ "flight_days char(7) NOT NULL",
+ "from_airport char(3) NOT NULL",
+ "to_airport char(3) NOT NULL",
+ "departure_time smallint(4) NOT NULL",
+ "arrival_time smallint(4) NOT NULL",
+ "airline_code char(2) NOT NULL",
+ "flight_number smallint(4) NOT NULL",
+ "class_string char(8) NOT NULL",
+ "aircraft_code char(3) NOT NULL",
+ "meal_code char(7) NOT NULL",
+ "stops tinyint(1) NOT NULL",
+ "dual_carrier char(1) NOT NULL",
+ "time_elapsed smallint(4) NOT NULL"],
+ ["PRIMARY KEY (flight_code)",
+ "INDEX from_airport3 (from_airport)",
+ "INDEX to_airport3 (to_airport)"]);
+ @flight_class=
+ $server->create("flight_class",
+ ["flight_code integer(8) NOT NULL",
+ "fare_class char(3) NOT NULL"],
+ ["PRIMARY KEY (flight_code, fare_class)"]);
+ @flight_day=
+ $server->create("flight_day",
+ ["day_mask char(7) NOT NULL",
+ "day_code tinyint(1) NOT NULL",
+ "day_name char(9) NOT NULL"],
+ ["PRIMARY KEY (day_mask, day_code)"]);
+ @flight_fare=
+ $server->create("flight_fare",
+ ["flight_code integer(8) NOT NULL",
+ "fare_code char(8) NOT NULL"],
+ ["PRIMARY KEY (flight_code, fare_code)"]);
+ @food_service=
+ $server->create("food_service",
+ ["meal_code char(4) NOT NULL",
+ "meal_number tinyint(1) NOT NULL",
+ "meal_class char(10) NOT NULL",
+ "meal_description char(10) NOT NULL"],
+ ["PRIMARY KEY (meal_code, meal_number, meal_class)"]);
+ @ground_service=
+ $server->create("ground_service",
+ ["city_code char(4) NOT NULL",
+ "airport_code char(3) NOT NULL",
+ "transport_code char(1) NOT NULL",
+ "ground_fare float(6,2) NOT NULL"],
+ ["PRIMARY KEY (city_code, airport_code, transport_code)"]);
+ @time_interval=
+ $server->create("time_interval",
+ ["period char(20) NOT NULL",
+ "begin_time smallint(4) NOT NULL",
+ "end_time smallint(4) NOT NULL"],
+ ["PRIMARY KEY (period, begin_time)"]);
+ @month_name=
+ $server->create("month_name",
+ ["month_number tinyint(2) NOT NULL",
+ "month_name char(9) NOT NULL"],
+ ["PRIMARY KEY (month_number)"]);
+ @restrict_carrier=
+ $server->create("restrict_carrier",
+ ["restrict_code char(5) NOT NULL",
+ "airline_code char(2) NOT NULL"],
+ ["PRIMARY KEY (restrict_code, airline_code)"]);
+ @restrict_class=
+ $server->create("restrict_class",
+ ["restrict_code char(5) NOT NULL",
+ "ex_fare_class char(12) NOT NULL"],
+ ["PRIMARY KEY (restrict_code, ex_fare_class)"]);
+ @restriction=
+ $server->create("restriction",
+ ["restrict_code char(5) NOT NULL",
+ "application char(80) NOT NULL",
+ "no_discounts char(80) NOT NULL",
+ "reserve_ticket smallint(3) NOT NULL",
+ "stopovers char(1) NOT NULL",
+ "return_min smallint(3) NOT NULL",
+ "return_max smallint(3) NOT NULL"],
+ ["PRIMARY KEY (restrict_code)"]);
+ @state=
+ $server->create("state",
+ ["state_code char(2) NOT NULL",
+ "state_name char(25) NOT NULL",
+ "country_name char(25) NOT NULL"],
+ ["PRIMARY KEY (state_code)"]);
+ @stop=
+ $server->create("stop1",
+ ["flight_code integer(8) NOT NULL",
+ "stop_number tinyint(1) NOT NULL",
+ "stop_flight integer(8) NOT NULL"],
+ ["PRIMARY KEY (flight_code, stop_number)"]);
+ @time_zone=
+ $server->create("time_zone",
+ ["time_zone_code char(3) NOT NULL",
+ "time_zone_name char(32) NOT NULL"],
+ ["PRIMARY KEY (time_zone_code, time_zone_name)"]);
+ @transport=
+ $server->create("transport",
+ ["transport_code char(1) NOT NULL",
+ "transport_desc char(32) NOT NULL"],
+ ["PRIMARY KEY (transport_code)"]);
+
+# Avoid not used warnings
+
+ @tables =
+ (\@aircraft, \@airline, \@airport, \@airport_service,
+ \@city, \@class_of_service, \@code_description,
+ \@compound_class, \@connect_leg, \@connection, \@day_name,
+ \@dual_carrier, \@fare, \@flight, \@flight_class, \@flight_day,
+ \@flight_fare, \@food_service, \@ground_service, \@time_interval,
+ \@month_name,
+ \@restrict_carrier, \@restrict_class, \@restriction, \@state, \@stop,
+ \@time_zone, \@transport);
+
+ @table_names =
+ ("aircraft", "airline", "airport", "airport_service",
+ "city", "class_of_service", "code_description",
+ "compound_class", "connect_leg", "connection", "day_name",
+ "dual_carrier", "fare", "flight", "flight_class", "flight_day",
+ "flight_fare", "food_service", "ground_service", "time_interval",
+ "month_name",
+ "restrict_carrier", "restrict_class", "restriction", "state", "stop1",
+ "time_zone", "transport");
+
+# Alias used in joins
+ @extra_names=("airport as from_airport","airport as to_airport");
+}
diff --git a/sql-bench/test-alter-table.sh b/sql-bench/test-alter-table.sh
new file mode 100755
index 00000000000..295325ec0dc
--- /dev/null
+++ b/sql-bench/test-alter-table.sh
@@ -0,0 +1,180 @@
+#!@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 alter table
+#
+##################### Standard benchmark inits ##############################
+
+use DBI;
+use Benchmark;
+
+$opt_start_field_count=8; # start with this many fields
+$opt_loop_count=20; # How many tests to do
+$opt_row_count=1000; # Rows in the table
+$opt_field_count=1000; # Add until this many fields.
+
+chomp($pwd = `pwd`); $pwd = "." if ($pwd eq '');
+require "$pwd/bench-init.pl" || die "Can't read Configuration file: $!\n";
+
+$opt_field_count=min($opt_field_count,$limits->{'max_columns'},
+ ($limits->{'query_size'}-30)/14);
+$opt_start_field_count=min($opt_start_field_count,$limits->{'max_index'});
+
+if ($opt_small_test)
+{
+ $opt_row_count/=10;
+ $opt_field_count/=10;
+}
+
+if (!$limits->{'alter_table'})
+{
+ print("Some of the servers given with --cmp or --server doesn't support ALTER TABLE\nTest aborted\n\n");
+ $start_time=new Benchmark;
+ end_benchmark($start_time);
+ exit 0;
+}
+
+print "Testing of ALTER TABLE\n";
+print "Testing with $opt_field_count columns and $opt_row_count rows in $opt_loop_count steps\n";
+
+####
+#### Create a table and fill it with data
+####
+
+$dbh = $server->connect();
+@fields=();
+@index=();
+push(@fields,"i1 int not null");
+for ($i=2 ; $i <= $opt_start_field_count ; $i++)
+{
+ push(@fields,"i${i} int not null");
+}
+$field_count= $opt_start_field_count;
+
+$start_time=new Benchmark;
+
+$dbh->do("drop table bench");
+do_many($dbh,$server->create("bench",\@fields,\@index));
+
+print "Insert data into the table\n";
+
+$loop_time=new Benchmark;
+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;
+}
+$end_time=new Benchmark;
+
+print "Time for insert ($opt_row_count)",
+ timestr(timediff($end_time, $loop_time),"all") . "\n\n";
+
+
+####
+#### Add fields to the table.
+####
+
+$loop_time=new Benchmark;
+$add= int(($opt_field_count-$opt_start_field_count)/$opt_loop_count)+1;
+
+
+$add=1 if (!$limits{'alter_add_multi_col'});
+$multi_add=$server->{'limits'}->{'alter_add_multi_col'} == 1;
+
+$count=0;
+while ($field_count < $opt_field_count)
+{
+ $count++;
+ $end=min($field_count+$add,$opt_field_count);
+ $fields="";
+ $tmp="ADD ";
+ while ($field_count < $end)
+ {
+ $field_count++;
+ $fields.=",$tmp i${field_count} integer";
+ $tmp="" if (!$multi_add); # Adabas
+ }
+ do_query($dbh,"ALTER TABLE bench " . substr($fields,1));
+}
+
+$end_time=new Benchmark;
+print "Time for alter_table_add ($count): " .
+ timestr(timediff($end_time, $loop_time),"all") . "\n\n";
+
+####
+#### Test adding and deleting index on the first $opt_start_fields
+####
+
+$loop_time=new Benchmark;
+
+for ($i=1; $i < $opt_start_field_count ; $i++)
+{
+ $dbh->do("CREATE INDEX bench_ind$i ON bench (i${i})") || die $DBI::errstr;
+}
+
+$end_time=new Benchmark;
+print "Time for create_index ($opt_start_field_count): " .
+ timestr(timediff($end_time, $loop_time),"all") . "\n\n";
+
+$loop_time=new Benchmark;
+for ($i=1; $i < $opt_start_field_count ; $i++)
+{
+ $dbh->do($server->drop_index("bench","bench_ind$i")) || die $DBI::errstr;
+}
+
+$end_time=new Benchmark;
+print "Time for drop_index ($opt_start_field_count): " .
+ timestr(timediff($end_time, $loop_time),"all") . "\n\n";
+
+####
+#### Delete fields from the table
+####
+
+goto skip_dropcol if (!$limits->{'alter_table_dropcol'});
+
+$loop_time=new Benchmark;
+
+$count=0;
+while ($field_count > $opt_start_field_count)
+{
+ $count++;
+ $end=max($field_count-$add,$opt_start_field_count);
+ $fields="";
+ while(--$field_count >= $end)
+ {
+ $fields.=",DROP i${field_count}";
+ }
+ $dbh->do("ALTER TABLE bench " . substr($fields,1)) || die $DBI::errstr;
+}
+
+$end_time=new Benchmark;
+print "Time for alter_table_drop ($count): " .
+ timestr(timediff($end_time, $loop_time),"all") . "\n\n";
+
+skip_dropcol:
+
+################################ END ###################################
+####
+#### End of the test...Finally print time used to execute the
+#### whole test.
+
+$dbh->do("drop table bench");
+
+$dbh->disconnect;
+
+end_benchmark($start_time);
diff --git a/sql-bench/test-big-tables.sh b/sql-bench/test-big-tables.sh
new file mode 100755
index 00000000000..037a45b01bd
--- /dev/null
+++ b/sql-bench/test-big-tables.sh
@@ -0,0 +1,154 @@
+#!@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 extreme tables.
+#
+
+##################### Standard benchmark inits ##############################
+
+use DBI;
+use Benchmark;
+
+$opt_loop_count=1000; # Change this to make test harder/easier
+$opt_field_count=1000;
+
+chomp($pwd = `pwd`); $pwd = "." if ($pwd eq '');
+require "$pwd/bench-init.pl" || die "Can't read Configuration file: $!\n";
+
+$opt_field_count=min($opt_field_count,$limits->{'max_columns'},
+ ($limits->{'query_size'}-30)/14);
+
+$opt_loop_count*=10 if ($opt_field_count<100); # mSQL has so few fields...
+
+if ($opt_small_test)
+{
+ $opt_loop_count/=10;
+ $opt_field_count/=10;
+}
+
+
+print "Testing of some unusual tables\n";
+print "All tests are done $opt_loop_count times with $opt_field_count fields\n\n";
+
+
+####
+#### Testing many fields
+####
+
+$dbh = $server->connect();
+print "Testing table with $opt_field_count fields\n";
+
+$sth = $dbh->do("drop table bench1");
+
+my @fields=();
+my @index=();
+my $fields="i1";
+push(@fields,"$fields int");
+$values= "1," x ($opt_field_count-1) . "1";
+for ($i=2 ; $i <= $opt_field_count ; $i++)
+{
+ push(@fields,"i${i} int");
+ $fields.=",i${i}";
+}
+
+$start_time=new Benchmark;
+
+do_many($dbh,$server->create("bench1",\@fields,\@index));
+$sth = $dbh->do("insert into bench1 values ($values)") or die $DBI::errstr;
+
+if ($opt_fast && defined($server->{vacuum}))
+{
+ $server->vacuum(0,\$dbh);
+}
+
+test_query("Testing select * from table with 1 record",
+ "Time to select_many_fields",
+ "select * from bench1",
+ $dbh,$opt_loop_count);
+
+test_query("Testing select all_fields from table with 1 record",
+ "Time to select_many_fields",
+ "select $fields from bench1",
+ $dbh,$opt_loop_count);
+
+test_query("Testing insert VALUES()",
+ "Time to insert_many_fields",
+ "insert into bench1 values($values)",
+ $dbh,$opt_loop_count);
+
+if ($opt_fast && defined($server->{vacuum}))
+{
+ $server->vacuum(0,\$dbh);
+}
+
+test_command("Testing insert (all_fields) VALUES()",
+ "Time to insert_many_fields",
+ "insert into bench1 ($fields) values($values)",
+ $dbh,$opt_loop_count);
+
+$sth = $dbh->do("drop table bench1") or die $DBI::errstr;
+
+if ($opt_fast && defined($server->{vacuum}))
+{
+ $server->vacuum(0,\$dbh);
+}
+
+################################ 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 die $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";
+}
diff --git a/sql-bench/test-connect.sh b/sql-bench/test-connect.sh
new file mode 100755
index 00000000000..087cce4fe1d
--- /dev/null
+++ b/sql-bench/test-connect.sh
@@ -0,0 +1,287 @@
+#!@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
+#
+# This test is for testing the speed of connections and sending
+# data to the client.
+#
+# By changing the variable '$opt_loop_count' value you can make this test
+# easier/harderto your computer to execute. You can also change this value
+# by using option --loop_value='what_ever_you_like'.
+##################### Standard benchmark inits ##############################
+
+use DBI;
+use Benchmark;
+
+$opt_loop_count=10000; # 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
+
+chomp($pwd = `pwd`); $pwd = "." if ($pwd eq '');
+require "$pwd/bench-init.pl" || die "Can't read Configuration file: $!\n";
+
+# This is the length of blob strings in PART:5
+$str_length=min($limits->{'max_text_size'},$limits->{'query_size'}-30,$str_length);
+
+if ($opt_small_test)
+{
+ $opt_loop_count/=100;
+}
+
+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";
+
+################################# PART:1 ###################################
+####
+#### Start timeing and start connect test..
+####
+
+$start_time=new Benchmark;
+
+print "Testing connection/disconnect\n";
+
+$loop_time=new Benchmark;
+$errors=0;
+
+for ($i=0 ; $i < $opt_loop_count ; $i++)
+{
+ print "$i " if (($opt_debug));
+ for ($j=0; $j < $max_test ; $j++)
+ {
+ if ($dbh = DBI->connect($server->{'data_source'}, $opt_user,
+ $opt_password))
+ {
+ $dbh->disconnect;
+ last;
+ }
+ select(undef, undef, undef, 0.001);
+ print "$errors " if (($opt_debug));
+ $errors++;
+ }
+ die $DBI::errstr if ($j == $max_test);
+ $dbh->disconnect;
+ undef($dbh);
+}
+$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): " .
+ 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.
+
+if ($limits->{'select_without_from'})
+{
+ print "Test connect/simple select/disconnect\n";
+ $loop_time=new Benchmark;
+
+ for ($i=0; $i<$opt_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;
+ $dbh->disconnect;
+ }
+ $end_time=new Benchmark;
+ print "Time for connect+select_simple ($opt_loop_count): " .
+ timestr(timediff($end_time, $loop_time),"all") . "\n\n";
+}
+
+################################# PART:3 ###################################
+####
+#### Okay..Next thing we'll do is a simple select $opt_loop_count times.
+####
+
+$dbh = DBI->connect($server->{'data_source'}, $opt_user, $opt_password,
+ { PrintError => 0}) || die $DBI::errstr;
+
+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 1") 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 ###################################
+#### 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.
+
+$sth = $dbh->do("drop table bench1");
+do_many($dbh,$server->create("bench1",
+ ["a int NOT NULL",
+ "i int",
+ "s char(10)"],
+ ["primary key (a)"]));
+$sth = $dbh->do("insert into bench1 values(1,100,'AAA')") or die $DBI::errstr;
+
+if ($opt_fast && defined($server->{vacuum}))
+{
+ $server->vacuum(0,\$dbh);
+}
+$dbh->disconnect;
+
+#
+# First test connect/select/disconnect
+#
+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 ($j=0; $j < $max_test ; $j++)
+ {
+ last if ($dbh = DBI->connect($server->{'data_source'}, $opt_user, $opt_password));
+ $errors++;
+ }
+ die $DBI::errstr if ($j == $max_test);
+
+ $sth = $dbh->do("select * 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): " .
+ timestr(timediff($end_time, $loop_time),"all") . "\n\n";
+
+#
+# The same test, but without connect/disconnect
+#
+print "Testing select 1 row from table\n";
+
+$dbh = $server->connect();
+$loop_time=new Benchmark;
+
+for ($i=0 ; $i<$opt_loop_count ; $i++)
+{
+ $sth = $dbh->do("select * from bench1") # Select * from table with 1 record
+ or die $DBI::errstr;
+}
+
+$end_time=new Benchmark;
+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.
+#
+print "Testing select 2 rows from table\n";
+
+$sth = $dbh->do("insert into bench1 values(2,200,'BBB')")
+ or die $DBI::errstr;
+
+$loop_time=new Benchmark;
+
+for ($i=0 ; $i<$opt_loop_count ; $i++)
+{
+ $sth = $dbh->do("select * from bench1") # Select * from table with 2 record
+ or die $DBI::errstr;
+}
+
+$end_time=new Benchmark;
+print "Time to select_2_rows ($opt_loop_count): " .
+ timestr(timediff($end_time, $loop_time),"all") . "\n\n";
+
+if ($limits->{'functions'})
+{
+ print "Test select with aritmetic (+)\n";
+ $loop_time=new Benchmark;
+
+ 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;
+ }
+ $end_time=new Benchmark;
+ print "Time for select_column+column ($opt_loop_count): " .
+ timestr(timediff($end_time, $loop_time),"all") . "\n\n";
+}
+
+$sth = $dbh->do("drop table bench1")
+ or die $DBI::errstr;
+
+if ($opt_fast && defined($server->{vacuum}))
+{
+ $server->vacuum(0,\$dbh);
+}
+
+################################# PART:5 ###################################
+#### We'll create one table with a single blob field,but with a
+#### huge record in it and then we'll do $opt_loop_count selects
+#### from it.
+
+print "Testing retrieval of big records ($str_length bytes)\n";
+
+do_many($dbh,$server->create("bench1", ["b blob"], []));
+$dbh->{LongReadLen}= $str_length; # Set retrieval buffer
+
+my $string=(A) x ($str_length); # This will make a string $str_length long.
+$sth = $dbh->prepare("insert into bench1 values(?)") or die $dbh->errstr;
+$sth->execute($string) or die $sth->errstr;
+undef($string);
+if ($opt_fast && defined($server->{vacuum}))
+{
+ $server->vacuum(0,\$dbh);
+}
+
+$loop_time=new Benchmark;
+
+for ($i=0 ; $i < $opt_loop_count ; $i++)
+{
+ $sth = $dbh->prepare("select * from bench1");
+ if (!$sth->execute || !(@row = $sth->fetchrow_array) ||
+ length($row[0]) != $str_length)
+ {
+ warn "$DBI::errstr - ".length($row[0])." - $str_length **\n";
+ }
+ $sth->finish;
+}
+
+$end_time=new Benchmark;
+print "Time to select_big ($opt_loop_count): " .
+ timestr(timediff($end_time, $loop_time),"all") . "\n\n";
+
+$sth = $dbh->do("drop table bench1")
+ or do
+{
+ # Fix for Access 2000
+ die $dbh->errstr if (!$dbh->abort_if_fatal_error());
+};
+
+if ($opt_fast && defined($server->{vacuum}))
+{
+ $server->vacuum(0,\$dbh);
+}
+
+
+################################ END ###################################
+####
+#### End of the test...Finally print time used to execute the
+#### whole test.
+
+$dbh->disconnect;
+end_benchmark($start_time);
diff --git a/sql-bench/test-create.sh b/sql-bench/test-create.sh
new file mode 100755
index 00000000000..f72461a6c48
--- /dev/null
+++ b/sql-bench/test-create.sh
@@ -0,0 +1,259 @@
+#!@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
+#
+# This test is for testing how long it takes to create tables,
+# make a count(*) from them and finally drop the tables. These
+# commands will be done in different ways in this test.
+# Using option --fast will drop all the tables in the end
+# of this test with one command instead of making own
+# 'drop' command for each and every table.
+# By changing the variable '$table_amount' value you can make
+# this test a lot harder/easier for your computer to drive.
+# Note that when using value bigger than 64 for this variable
+# will do 'drop table'-command in totally different way because of that
+# how MySQL handles these commands.
+
+##################### Standard benchmark inits ##############################
+
+use DBI;
+use Benchmark;
+
+$opt_loop_count=10000; # Change this to make test harder/easier
+# This is the default value for the amount of tables used in this test.
+
+chomp($pwd = `pwd`); $pwd = "." if ($pwd eq '');
+require "$pwd/bench-init.pl" || die "Can't read Configuration file: $!\n";
+
+if ($opt_small_test)
+{
+ $opt_loop_count/=100;
+}
+
+$max_tables=min($limits->{'max_tables'},$opt_loop_count);
+
+print "Testing the speed of creating and droping tables\n";
+print "Testing with $max_tables tables and $opt_loop_count loop count\n\n";
+
+####
+#### Connect and start timeing
+####
+
+$dbh = $server->connect();
+
+### Test how the database can handle many tables
+### Create $max_tables ; Access all off them with a simple query
+### and then drop the tables
+
+if ($opt_force) # If tables used in this test exist, drop 'em
+{
+ print "Okay..Let's make sure that our tables don't exist yet.\n\n";
+ for ($i=1 ; $i <= $max_tables ; $i++)
+ {
+ $dbh->do("drop table bench_$i");
+ }
+}
+
+if ($opt_fast && defined($server->{vacuum}))
+{
+ $server->vacuum(1,\$dbh);
+}
+
+print "Testing create of tables\n";
+
+$loop_time=$start_time=new Benchmark;
+
+for ($i=1 ; $i <= $max_tables ; $i++)
+{
+ if (do_many($dbh,$server->create("bench_$i",
+ ["i int NOT NULL",
+ "d double",
+ "f float",
+ "s char(10)",
+ "v varchar(100)"],
+ ["primary key (i)"])))
+ {
+ # Got an error; Do cleanup
+ for ($i=1 ; $i <= $max_tables ; $i++)
+ {
+ $dbh->do("drop table bench_$i");
+ }
+ die "Test aborted";
+ }
+}
+
+$end_time=new Benchmark;
+print "Time for create_MANY_tables ($max_tables): " .
+ timestr(timediff($end_time, $loop_time),"all") . "\n\n";
+
+if ($opt_fast && defined($server->{vacuum}))
+{
+ $server->vacuum(1,\$dbh);
+}
+
+#### Here comes $max_tables couples of cont(*) to the tables.
+#### We'll check how long it will take...
+####
+
+print "Accessing tables\n";
+
+if ($limits->{'group_functions'})
+{
+ $query="select count(*) from ";
+ $type="select_group_when_MANY_tables";
+}
+else
+{
+ $query="select * from ";
+ $type="select_when_MANY_tables";
+}
+
+$loop_time=new Benchmark;
+for ($i=1 ; $i <= $max_tables ; $i++)
+{
+ $sth = $dbh->do("$query bench_$i") or die $DBI::errstr;
+}
+
+$end_time=new Benchmark;
+print "Time to $type ($max_tables): " .
+ timestr(timediff($end_time, $loop_time),"all") . "\n\n";
+
+####
+#### Now we are going to drop $max_tables tables;
+####
+
+print "Testing drop\n";
+
+$loop_time=new Benchmark;
+
+if ($opt_fast && $server->{'limits'}->{'multi_drop'} &&
+ $server->{'limits'}->{'query_size'} > 11+$max_tables*10)
+{
+ my $query="drop table bench_1";
+ for ($i=2 ; $i <= $max_tables ; $i++)
+ {
+ $query.=",bench_$i";
+ }
+ $sth = $dbh->do($query) or die $DBI::errstr;
+}
+else
+{
+ for ($i=1 ; $i <= $max_tables ; $i++)
+ {
+ $sth = $dbh->do("drop table bench_$i")
+ or die $DBI::errstr;
+ }
+}
+
+
+$end_time=new Benchmark;
+print "Time for drop_table_when_MANY_tables ($max_tables): " .
+ timestr(timediff($end_time, $loop_time),"all") . "\n\n";
+
+if ($opt_fast && defined($server->{vacuum}))
+{
+ $server->vacuum(1,\$dbh);
+}
+
+#### We'll do first one 'create table' and then we'll drop it
+#### away immediately. This loop shall be executed $opt_loop_count
+#### times.
+
+print "Testing create+drop\n";
+
+$loop_time=new Benchmark;
+
+for ($i=1 ; $i <= $opt_loop_count ; $i++)
+{
+ do_many($dbh,$server->create("bench_$i",
+ ["i int NOT NULL",
+ "d double",
+ "f float",
+ "s char(10)",
+ "v varchar(100)"],
+ ["primary key (i)"]));
+ $sth = $dbh->do("drop table bench_$i") or die $DBI::errstr;
+}
+
+$end_time=new Benchmark;
+print "Time for create+drop ($opt_loop_count): " .
+ timestr(timediff($end_time, $loop_time),"all") . "\n";
+
+if ($opt_fast && defined($server->{vacuum}))
+{
+ $server->vacuum(1,\$dbh);
+}
+
+#
+# Same test, but with a table with many keys
+#
+
+my @fields=(); my @keys=();
+$keys=min($limits->{'max_index'},16); # 16 is more than enough
+$seg= min($limits->{'max_index_parts'},$keys,16); # 16 is more than enough
+
+# 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,"field2 mediumint not null");
+push(@fields,"field3 smallint not null");
+push(@fields,"field4 char(16) not null");
+push(@fields,"field5 integer not null");
+push(@fields,"field6 float not null");
+push(@fields,"field7 double not null");
+for ($i=8 ; $i <= $keys ; $i++)
+{
+ push(@fields,"field$i char(5) not null"); # Should be relatively fair
+}
+
+# Let first key contain many segments
+my $query="primary key (";
+for ($i= 1 ; $i <= $seg ; $i++)
+{
+ $query.= "field$i,";
+}
+substr($query,-1)=")";
+push (@keys,$query);
+
+#Create other keys
+for ($i=2 ; $i <= $keys ; $i++)
+{
+ push(@keys,"index index$i (field$i)");
+}
+
+$loop_time=new Benchmark;
+for ($i=1 ; $i <= $opt_loop_count ; $i++)
+{
+ do_many($dbh,$server->create("bench_$i", \@fields, \@index));
+ $dbh->do("drop table bench_$i") or die $DBI::errstr;
+}
+
+$end_time=new Benchmark;
+print "Time for create_key+drop ($opt_loop_count): " .
+ timestr(timediff($end_time, $loop_time),"all") . "\n";
+
+if ($opt_fast && defined($server->{vacuum}))
+{
+ $server->vacuum(1,\$dbh);
+}
+
+####
+#### End of benchmark
+####
+
+$dbh->disconnect; # close connection
+end_benchmark($start_time);
diff --git a/sql-bench/test-insert.sh b/sql-bench/test-insert.sh
new file mode 100755
index 00000000000..5cde7c25405
--- /dev/null
+++ b/sql-bench/test-insert.sh
@@ -0,0 +1,1312 @@
+#@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 creating a simple table and inserting $record_count records in it,
+# $opt_loop_count rows in order, $opt_loop_count rows in reverse order and
+# $opt_loop_count rows in random order
+#
+# changes made for Oracle compatibility
+# - $limits{'func_odbc_mod'} is OK from crash-me, but it fails here so set we
+# set it to 0 in server-cfg
+# - the default server config runs out of rollback segments, so I added a couple
+# of disconnect/connects to reset
+##################### Standard benchmark inits ##############################
+
+use DBI;
+use Benchmark;
+
+$opt_loop_count=100000; # number of rows/3
+$small_loop_count=10; # Loop for full table retrieval
+$range_loop_count=$small_loop_count*50;
+$many_keys_loop_count=$opt_loop_count;
+
+chomp($pwd = `pwd`); $pwd = "." if ($pwd eq '');
+require "$pwd/bench-init.pl" || die "Can't read Configuration file: $!\n";
+
+if ($opt_loop_count < 256)
+{
+ $opt_loop_count=256; # Some tests must have some data to work!
+}
+
+if ($opt_small_test)
+{
+ $opt_loop_count/=100;
+ $range_loop_count/=10;
+ $many_keys_loop_count=$opt_loop_count/10;
+}
+elsif ($opt_small_tables)
+{
+ $opt_loop_count=10000; # number of rows/3
+ $many_keys_loop_count=$opt_loop_count;
+}
+elsif ($opt_small_key_tables)
+{
+ $many_keys_loop_count/=10;
+}
+
+print "Testing the speed of inserting data into 1 table and do some selects on it.\n";
+print "The tests are done with a table that has $opt_loop_count rows.\n\n";
+
+####
+#### Generating random keys
+####
+
+print "Generating random keys\n";
+$random[$opt_loop_count]=0;
+for ($i=0 ; $i < $opt_loop_count ; $i++)
+{
+ $random[$i]=$i+$opt_loop_count;
+}
+
+my $tmpvar=1;
+for ($i=0 ; $i < $opt_loop_count ; $i++)
+{
+ $tmpvar^= ((($tmpvar + 63) + $i)*3 % $opt_loop_count);
+ $swap=$tmpvar % $opt_loop_count;
+ $tmp=$random[$i]; $random[$i]=$random[$swap]; $random[$swap]=$tmp;
+}
+
+$total_rows=$opt_loop_count*3;
+
+####
+#### Connect and start timeing
+####
+$start_time=new Benchmark;
+$dbh = $server->connect();
+####
+#### Create needed tables
+####
+
+goto keys_test if ($opt_stage == 2);
+goto select_test if ($opt_skip_create);
+
+print "Creating tables\n";
+$dbh->do("drop table bench1");
+do_many($dbh,$server->create("bench1",
+ ["id int NOT NULL",
+ "id2 int NOT NULL",
+ "id3 int NOT NULL",
+ "dummy1 char(30)"],
+ ["primary key (id,id2)",
+ "index index_id3 (id3)"]));
+
+if ($opt_lock_tables)
+{
+ $sth = $dbh->do("LOCK TABLES bench1 WRITE") || die $DBI::errstr;
+}
+
+####
+#### Insert $total_rows records in order, in reverse order and random.
+####
+
+$loop_time=new Benchmark;
+
+if ($opt_fast_insert)
+{
+ $query="insert into bench1 values ";
+}
+else
+{
+ $query="insert into bench1 (id,id2,id3,dummy1) values ";
+}
+
+if (($opt_fast || $opt_fast_insert) && $limits->{'multi_value_insert'})
+{
+ $query_size=$server->{'limits'}->{'query_size'};
+
+ print "Inserting $opt_loop_count multiple-value rows in order\n";
+ $res=$query;
+ for ($i=0 ; $i < $opt_loop_count ; $i++)
+ {
+ $tmp= "($i,$i,$i,'ABCDEFGHIJ'),";
+ if (length($tmp)+length($res) < $query_size)
+ {
+ $res.= $tmp;
+ }
+ else
+ {
+ $sth = $dbh->do(substr($res,0,length($res)-1)) or die $DBI::errstr;
+ $res=$query . $tmp;
+ }
+ }
+ print "Inserting $opt_loop_count multiple-value rows in reverse order\n";
+ for ($i=0 ; $i < $opt_loop_count ; $i++)
+ {
+ $tmp= "(" . ($total_rows-1-$i) . "," .($total_rows-1-$i) .
+ "," .($total_rows-1-$i) . ",'BCDEFGHIJK'),";
+ if (length($tmp)+length($res) < $query_size)
+ {
+ $res.= $tmp;
+ }
+ else
+ {
+ $sth = $dbh->do(substr($res,0,length($res)-1)) or die $DBI::errstr;
+ $res=$query . $tmp;
+ }
+ }
+ print "Inserting $opt_loop_count multiple-value rows in random order\n";
+ for ($i=0 ; $i < $opt_loop_count ; $i++)
+ {
+ $tmp= "(" . $random[$i] . "," . $random[$i] . "," . $random[$i] .
+ ",'CDEFGHIJKL')," or die $DBI::errstr;
+ if (length($tmp)+length($res) < $query_size)
+ {
+ $res.= $tmp;
+ }
+ else
+ {
+ $sth = $dbh->do(substr($res,0,length($res)-1)) or die $DBI::errstr;
+ $res=$query . $tmp;
+ }
+ }
+ $sth = $dbh->do(substr($res,0,length($res)-1)) or die $DBI::errstr;
+}
+else
+{
+ print "Inserting $opt_loop_count rows in order\n";
+ for ($i=0 ; $i < $opt_loop_count ; $i++)
+ {
+ $sth = $dbh->do($query . "($i,$i,$i,'ABCDEFGHIJ')") or die $DBI::errstr;
+ }
+
+ print "Inserting $opt_loop_count rows in reverse order\n";
+ for ($i=0 ; $i < $opt_loop_count ; $i++)
+ {
+ $sth = $dbh->do($query . "(" . ($total_rows-1-$i) . "," .
+ ($total_rows-1-$i) . "," .
+ ($total_rows-1-$i) . ",'BCDEFGHIJK')")
+ or die $DBI::errstr;
+ }
+
+ print "Inserting $opt_loop_count rows in random order\n";
+
+ for ($i=0 ; $i < $opt_loop_count ; $i++)
+ {
+ $sth = $dbh->do($query . "(". $random[$i] . "," . $random[$i] .
+ "," . $random[$i] . ",'CDEFGHIJKL')") or die $DBI::errstr;
+ }
+}
+
+$end_time=new Benchmark;
+print "Time for insert (" . ($total_rows) . "): " .
+ timestr(timediff($end_time, $loop_time),"all") . "\n\n";
+
+if ($opt_fast && defined($server->{vacuum}))
+{
+ $server->vacuum(1,\$dbh);
+}
+
+####
+#### insert $opt_loop_count records with duplicate id
+####
+
+print "Testing insert of duplicates\n";
+$loop_time=new Benchmark;
+for ($i=0 ; $i < $opt_loop_count ; $i++)
+{
+ $tmpvar^= ((($tmpvar + 63) + $i)*3 % $opt_loop_count);
+ $tmp=$tmpvar % ($total_rows);
+ $tmpquery = "$query" . "$tmp" . ",1,2,'D')";
+ if ($dbh->do($tmpquery))
+ {
+ die "Didn't get an error when inserting duplicate record $tmp\n";
+ }
+}
+
+$end_time=new Benchmark;
+print "Time for insert_duplicates (" . ($total_rows) . "): " .
+ timestr(timediff($end_time, $loop_time),"all") . "\n\n";
+
+if ($opt_fast && defined($server->{vacuum}))
+{
+ $server->vacuum(1,\$dbh);
+}
+
+####
+#### Do some selects on the table
+####
+
+select_test:
+
+print "Retrieving data from the table\n";
+$loop_time=new Benchmark;
+$error=0;
+
+# It's really a small table, so we can try a select on everything
+
+$count=0;
+for ($i=1 ; $i <= $small_loop_count ; $i++)
+{
+ if (($found_rows=fetch_all_rows($dbh,"select id from bench1")) !=
+ $total_rows)
+ {
+ if (!$error++)
+ {
+ print "Warning: Got $found_rows rows when selecting a hole table of " . ($total_rows) . " rows\nContact the database or DBD author!\n";
+ }
+ }
+ $count+=$found_rows;
+}
+
+$end_time=new Benchmark;
+print "Time for select_big ($small_loop_count:$count): " .
+ timestr(timediff($end_time, $loop_time),"all") . "\n";
+
+$loop_time=new Benchmark;
+$estimated=0;
+$rows=0;
+$count=0;
+for ($i=1 ; $i <= $small_loop_count/2 ; $i++)
+{
+ $rows+=fetch_all_rows($dbh,"select id from bench1 order by id",1);
+ $rows+=fetch_all_rows($dbh,"select id from bench1 order by id desc",1);
+ $count+=2;
+ $end_time=new Benchmark;
+ last if ($estimated=predict_query_time($loop_time,$end_time,\$count,$count,
+ $small_loop_count));
+}
+if ($estimated)
+{ print "Estimated time"; }
+else
+{ print "Time"; }
+print " for order_by_key ($count:$rows): " .
+ timestr(timediff($end_time, $loop_time),"all") . "\n";
+
+$loop_time=new Benchmark;
+$estimated=0;
+$rows=0;
+$count=0;
+for ($i=1 ; $i <= $small_loop_count/2 ; $i++)
+{
+ $rows+=fetch_all_rows($dbh,"select id2 from bench1 order by id2",1);
+ $rows+=fetch_all_rows($dbh,"select id2 from bench1 order by id2 desc",1);
+ $count+=2;
+ $end_time=new Benchmark;
+ last if ($estimated=predict_query_time($loop_time,$end_time,\$count,$count,
+ $small_loop_count));
+}
+if ($estimated)
+{ print "Estimated time"; }
+else
+{ print "Time"; }
+print " for order_by ($count:$rows): " .
+ timestr(timediff($end_time, $loop_time),"all") . "\n";
+
+#
+# Test of select on 2 different keys with or
+# (In this case database can only use keys if they do an automatic union).
+#
+
+$loop_time=new Benchmark;
+$estimated=0;
+$rows=0;
+$count=0;
+for ($i=1 ; $i <= $range_loop_count ; $i++)
+{
+ my $rnd=$i;
+ my $rnd2=$random[$i];
+ $rows+=fetch_all_rows($dbh,"select id2 from bench1 where id=$rnd or id3=$rnd2",1);
+ $count++;
+ $end_time=new Benchmark;
+ last if ($estimated=predict_query_time($loop_time,$end_time,\$count,$count,
+ $range_loop_count));
+}
+if ($estimated)
+{ print "Estimated time"; }
+else
+{ print "Time"; }
+print " for select_diff_key ($count:$rows): " .
+ timestr(timediff($end_time, $loop_time),"all") . "\n";
+
+
+# Test select that is very popular when using ODBC
+
+check_or_range("id","select_range_prefix");
+check_or_range("id3","select_range");
+
+# Check reading on direct key on id and id3
+
+check_select_key("id","select_key_prefix");
+check_select_key("id3","select_key");
+
+####
+#### A lot of simple selects on ranges
+####
+
+@Q=("select * from bench1 where !id!=3 or !id!=2 or !id!=1 or !id!=4 or !id!=16 or !id!=10",
+ 6,
+ "select * from bench1 where !id!>=" . ($total_rows-1) ." or !id!<1",
+ 2,
+ "select * from bench1 where !id!>=1 and !id!<=2",
+ 2,
+ "select * from bench1 where (!id!>=1 and !id!<=2) or (!id!>=1 and !id!<=2)",
+ 2,
+ "select * from bench1 where !id!>=1 and !id!<=10 and !id!<=5",
+ 5,
+ "select * from bench1 where (!id!>0 and !id!<2) or !id!>=" . ($total_rows-1),
+ 2,
+ "select * from bench1 where (!id!>0 and !id!<2) or (!id!>= " . ($opt_loop_count/2) . " and !id! <= " . ($opt_loop_count/2+2) . ") or !id! = " . ($opt_loop_count/2-1),
+ 5,
+ "select * from bench1 where (!id!>=5 and !id!<=10) or (!id!>=1 and !id!<=4)",
+ 10,
+ "select * from bench1 where (!id!=1 or !id!=2) and (!id!=3 or !id!=4)",
+ 0,
+ "select * from bench1 where (!id!=1 or !id!=2) and (!id!=2 or !id!=3)",
+ 1,
+ "select * from bench1 where (!id!=1 or !id!=5 or !id!=20 or !id!=40) and (!id!=1 or !id!>=20 or !id!=4)",
+ 3,
+ "select * from bench1 where ((!id!=1 or !id!=3) or (!id!>1 and !id!<3)) and !id!<=2",
+ 2,
+ "select * from bench1 where (!id! >= 0 and !id! < 4) or (!id! >=4 and !id! < 6)",
+ 6,
+ "select * from bench1 where !id! <= -1 or (!id! >= 0 and !id! <= 5) or (!id! >=4 and !id! < 6) or (!id! >=6 and !id! <=7) or (!id!>7 and !id! <= 8)",
+ 9,
+ "select * from bench1 where (!id!>=1 and !id!<=2 or !id!>=4 and !id!<=5) or (!id!>=0 and !id! <=10)",
+ 11,
+ "select * from bench1 where (!id!>=1 and !id!<=2 or !id!>=4 and !id!<=5) or (!id!>2 and !id! <=10)",
+ 10,
+ "select * from bench1 where (!id!>1 or !id! <1) and !id!<=2",
+ 2,
+ "select * from bench1 where !id! <= 2 and (!id!>1 or !id! <=1)",
+ 3,
+ "select * from bench1 where (!id!>=1 or !id! <1) and !id!<=2",
+ 3,
+ "select * from bench1 where (!id!>=1 or !id! <=2) and !id!<=2",
+ 3
+ );
+
+print "\nTest of compares with simple ranges\n";
+check_select_range("id","select_range_prefix");
+check_select_range("id3","select_range");
+
+####
+#### Some group queries
+####
+
+if ($limits->{'group_functions'})
+{
+ $loop_time=new Benchmark;
+ $count=1;
+
+ for ($tests=0 ; $tests < $small_loop_count ; $tests++)
+ {
+ $sth=$dbh->prepare($query="select count(*) from bench1") or die $DBI::errstr;
+ $sth->execute or die $sth->errstr;
+ if (($sth->fetchrow_array)[0] != $total_rows)
+ {
+ print "Warning: '$query' returned wrong result\n";
+ }
+ $sth->finish;
+
+ # min, max in keys are very normal
+ $count+=7;
+ fetch_all_rows($dbh,"select min(id) from bench1");
+ fetch_all_rows($dbh,"select max(id) from bench1");
+ fetch_all_rows($dbh,"select sum(id+0.0) from bench1");
+ fetch_all_rows($dbh,"select min(id3),max(id3),sum(id3 +0.0) from bench1");
+ if ($limits->{'group_func_sql_min_str'})
+ {
+ fetch_all_rows($dbh,"select min(dummy1),max(dummy1) from bench1");
+ }
+ $count++;
+ $sth=$dbh->prepare($query="select count(*) from bench1 where id >= " .
+ ($opt_loop_count*2)) or die $DBI::errstr;
+ $sth->execute or die $DBI::errstr;
+ if (($sth->fetchrow_array)[0] != $opt_loop_count)
+ {
+ print "Warning: '$query' returned wrong result\n";
+ }
+ $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;
+ @row=$sth->fetchrow_array;
+ if ($row[0] != $total_rows ||
+ int($row[1]+0.5) != int((($total_rows-1)/2*$total_rows)+0.5) ||
+ $row[2] != 0 ||
+ $row[3] != $total_rows-1 ||
+ 1-$row[4]/(($total_rows-1)/2) > 0.001)
+ {
+ # PostgreSQL 6.3 fails here
+ print "Warning: '$query' returned wrong result: @row\n";
+ }
+ $sth->finish;
+
+ if ($limits->{'func_odbc_mod'})
+ {
+ $tmp="mod(id,10)";
+ if ($limits->{'func_extra_%'})
+ {
+ $tmp="id % 10"; # For postgreSQL
+ }
+ $count++;
+ if ($limits->{'group_by_alias'}) {
+ if (fetch_all_rows($dbh,$query=$server->query("select $tmp as last_digit,count(*) from bench1 group by last_digit")) != 10)
+ {
+ print "Warning: '$query' returned wrong number of rows\n";
+ }
+ } elsif ($limits->{'group_by_position'}) {
+ if (fetch_all_rows($dbh,$query=$server->query("select $tmp,count(*) from bench1 group by 1")) != 10)
+ {
+ print "Warning: '$query' returned wrong number of rows\n";
+ }
+ }
+ }
+
+ if ($limits->{'order_by_position'} && $limits->{'group_by_position'})
+ {
+ $count++;
+ if (fetch_all_rows($dbh, $query="select id,id3,dummy1 from bench1 where id < 100+$count-$count group by id,id3,dummy1 order by id desc,id3,dummy1") != 100)
+ {
+ print "Warning: '$query' returned wrong number of rows\n";
+ }
+ }
+ }
+ $end_time=new Benchmark;
+ print "Time for select_group ($count): " .
+ timestr(timediff($end_time, $loop_time),"all") . "\n";
+
+ $loop_time=new Benchmark;
+ $count=$estimated=0;
+ for ($tests=1 ; $tests <= $range_loop_count*5 ; $tests++)
+ {
+ $count+=6;
+ fetch_all_rows($dbh,"select min(id) from bench1");
+ fetch_all_rows($dbh,"select max(id) from bench1");
+ fetch_all_rows($dbh,"select min(id2) from bench1 where id=$tests");
+ fetch_all_rows($dbh,"select max(id2) from bench1 where id=$tests");
+ if ($limits->{'group_func_sql_min_str'})
+ {
+ fetch_all_rows($dbh,"select min(dummy1) from bench1 where id=$tests");
+ fetch_all_rows($dbh,"select max(dummy1) from bench1 where id=$tests");
+ }
+ $end_time=new Benchmark;
+ last if ($estimated=predict_query_time($loop_time,$end_time,\$count,$tests,
+ $range_loop_count*5));
+ }
+ if ($estimated)
+ { print "Estimated time"; }
+ else
+ { print "Time"; }
+ print " for min_max_on_key ($count): " .
+ timestr(timediff($end_time, $loop_time),"all") . "\n";
+
+ $loop_time=new Benchmark;
+ $count=$estimated=0;
+ for ($tests=1 ; $tests <= $small_loop_count ; $tests++)
+ {
+ $count+=6;
+ fetch_all_rows($dbh,"select min(id2) from bench1");
+ fetch_all_rows($dbh,"select max(id2) from bench1");
+ fetch_all_rows($dbh,"select min(id3) from bench1 where id2=$tests");
+ fetch_all_rows($dbh,"select max(id3) from bench1 where id2=$tests");
+ if ($limits->{'group_func_sql_min_str'})
+ {
+ fetch_all_rows($dbh,"select min(dummy1) from bench1 where id2=$tests");
+ fetch_all_rows($dbh,"select max(dummy1) from bench1 where id2=$tests");
+ }
+ $end_time=new Benchmark;
+ last if ($estimated=predict_query_time($loop_time,$end_time,\$count,$tests,
+ $range_loop_count));
+ }
+ if ($estimated)
+ { print "Estimated time"; }
+ else
+ { print "Time"; }
+ print " for min_max ($count): " .
+ timestr(timediff($end_time, $loop_time),"all") . "\n";
+
+ $loop_time=new Benchmark;
+ $count=0;
+ $total=$opt_loop_count*3;
+ for ($tests=0 ; $tests < $total ; $tests+=$total/100)
+ {
+ $count+=1;
+ fetch_all_rows($dbh,"select count(id) from bench1 where id < $tests");
+ }
+ $end_time=new Benchmark;
+ print "Time for count_on_key ($count): " .
+ timestr(timediff($end_time, $loop_time),"all") . "\n";
+
+ $loop_time=new Benchmark;
+ $count=0;
+ for ($tests=0 ; $tests < $total ; $tests+=$total/100)
+ {
+ $count+=1;
+ fetch_all_rows($dbh,"select count(dummy1) from bench1 where id2 < $tests");
+ }
+ $end_time=new Benchmark;
+ print "Time for count ($count): " .
+ timestr(timediff($end_time, $loop_time),"all") . "\n";
+
+ $loop_time=new Benchmark;
+ $count=$estimated=0;
+ for ($tests=0 ; $tests < $small_loop_count ; $tests++)
+ {
+ $count+=2;
+ fetch_all_rows($dbh,"select count(distinct dummy1) from bench1");
+ fetch_all_rows($dbh,"select dummy1,count(distinct id) from bench1 group by dummy1");
+ $end_time=new Benchmark;
+ last if ($estimated=predict_query_time($loop_time,$end_time,\$count,$tests,
+ $small_loop_count));
+ }
+ if ($estimated)
+ { print "Estimated time"; }
+ else
+ { print "Time"; }
+ print " for count_distinct_big ($count): " .
+ timestr(timediff($end_time, $loop_time),"all") . "\n";
+}
+
+
+if ($server->small_rollback_segment())
+{
+ $dbh->disconnect; # close connection
+ $dbh = $server->connect();
+}
+
+####
+#### Some updates on the table
+####
+
+$loop_time=new Benchmark;
+
+if ($limits->{'functions'})
+{
+ print "\nTesting update of keys with functions\n";
+ my $update_loop_count=$opt_loop_count/2;
+ for ($i=0 ; $i < $update_loop_count ; $i++)
+ {
+ my $tmp=$opt_loop_count+$random[$i]; # $opt_loop_count*2 <= $tmp < $total_rows
+ $sth = $dbh->do("update bench1 set id3=-$tmp where id3=$tmp") or die $DBI::errstr;
+ }
+
+ $end_time=new Benchmark;
+ print "Time for update_of_key ($range_loop_count): " .
+ timestr(timediff($end_time, $loop_time),"all") . "\n";
+
+ if ($opt_fast && defined($server->{vacuum}))
+ {
+ $server->vacuum(1,\$dbh);
+ }
+
+ if ($server->small_rollback_segment())
+ {
+ $dbh->disconnect; # close connection
+ $dbh = $server->connect();
+ }
+
+ $loop_time=new Benchmark;
+ $count=0;
+ $step=int($opt_loop_count/$range_loop_count+1);
+ for ($i= 0 ; $i < $opt_loop_count ; $i+= $step)
+ {
+ $count++;
+ $sth=$dbh->do("update bench1 set id3= 0-id3 where id3 >= 0 and id3 <= $i") or die $DBI::errstr;
+ }
+
+ if ($server->small_rollback_segment())
+ {
+ $dbh->disconnect; # close connection
+ $dbh = $server->connect();
+ }
+ $count++;
+ $sth=$dbh->do("update bench1 set id3= 0-id3 where id3 >= 0 and id3 < $opt_loop_count") or die $DBI::errstr;
+
+ if ($server->small_rollback_segment())
+ {
+ $dbh->disconnect; # close connection
+ $dbh = $server->connect();
+ }
+ $count++;
+ $sth=$dbh->do("update bench1 set id3= 0-id3 where id3 >= $opt_loop_count and id3 < ". ($opt_loop_count*2)) or die $DBI::errstr;
+
+ #
+ # Check that everything was updated
+ # In principle we shouldn't time this in the update loop..
+ #
+
+ if ($server->small_rollback_segment())
+ {
+ $dbh->disconnect; # close connection
+ $dbh = $server->connect();
+ }
+ $row_count=0;
+ if (($sth=$dbh->prepare("select count(*) from bench1 where id3>=0"))
+ && $sth->execute)
+ {
+ ($row_count)=$sth->fetchrow;
+ }
+ $result=1 + $opt_loop_count-$update_loop_count;
+ if ($row_count != $result)
+ {
+ print "Warning: Update check returned $row_count instead of $result\n";
+ }
+
+ $sth->finish;
+ if ($server->small_rollback_segment())
+ {
+ $dbh->disconnect; # close connection
+ $dbh = $server->connect();
+ }
+ #restore id3 to 0 <= id3 < $total_rows/10 or 0<= id3 < $total_rows
+
+ my $func=($limits->{'func_odbc_floor'}) ? "floor((0-id3)/20)" : "0-id3";
+ $count++;
+ $sth=$dbh->do($query="update bench1 set id3=$func where id3<0") or die $DBI::errstr;
+
+ $end_time=new Benchmark;
+ print "Time for update_of_key_big ($count): " .
+ timestr(timediff($end_time, $loop_time),"all") . "\n\n";
+}
+else
+{
+ print "\nTesting update of keys in loops\n";
+ #
+ # This is for mSQL that doesn't have functions. Do we really need this ????
+ #
+
+ $sth=$dbh->prepare("select id3 from bench1 where id3 >= 0") or die $DBI::errstr;
+ $sth->execute or die $DBI::errstr;
+ $count=0;
+ while (@tmp = $sth->fetchrow_array)
+ {
+ my $tmp1 = "-$tmp[0]";
+ my $sth1 = $dbh->do("update bench1 set id3 = $tmp1 where id3 = $tmp[0]");
+ $count++;
+ $end_time=new Benchmark;
+ if (($end_time->[0] - $loop_time->[0]) > $opt_time_limit)
+ {
+ print "note: Aborting update loop because of timeout\n";
+ last;
+ }
+ }
+ $sth->finish;
+ # Check that everything except id3=0 was updated
+ # In principle we shouldn't time this in the update loop..
+ #
+ if (fetch_all_rows($dbh,$query="select * from bench1 where id3>=0") != 1)
+ {
+ if ($count == $total_rows)
+ {
+ print "Warning: Wrong information after update: Found '$row_count' rows, but should have been: 1\n";
+ }
+ }
+ #restore id3 to 0 <= id3 < $total_rows
+ $sth=$dbh->prepare("select id3 from bench1 where id3 < 0") or die $DBI::errstr;
+ $sth->execute or die $DBI::errstr;
+ while (@tmp = $sth->fetchrow_array)
+ {
+ $count++;
+ my $tmp1 = floor((0-$tmp[0])/10);
+ my $sth1 = $dbh->do("update bench1 set id3 = $tmp1 where id3 = $tmp[0]");
+ }
+ $sth->finish;
+ $end_time=new Benchmark;
+ $estimated=predict_query_time($loop_time,$end_time,\$count,$count,
+ $opt_loop_count*6);
+ if ($estimated)
+ { print "Estimated time"; }
+ else
+ { print "Time"; }
+ print " for update_of_key ($count): " .
+ timestr(timediff($end_time, $loop_time),"all") . "\n\n";
+}
+
+if ($opt_fast && defined($server->{vacuum}))
+{
+ $server->vacuum(1,\$dbh);
+}
+
+#
+# Testing some simple updates
+#
+
+print "Testing update with key\n";
+$loop_time=new Benchmark;
+for ($i=0 ; $i < $opt_loop_count*3 ; $i++)
+{
+ $sth = $dbh->do("update bench1 set dummy1='updated' where id=$i") or die $DBI::errstr;
+}
+
+$end_time=new Benchmark;
+print "Time for update_with_key ($opt_loop_count): " .
+ timestr(timediff($end_time, $loop_time),"all") . "\n";
+
+print "\nTesting update of all rows\n";
+$loop_time=new Benchmark;
+for ($i=0 ; $i < $small_loop_count ; $i++)
+{
+ $sth = $dbh->do("update bench1 set dummy1='updated $i'") or die $DBI::errstr;
+}
+$end_time=new Benchmark;
+print "Time for update_big ($range_loop_count): " .
+ timestr(timediff($end_time, $loop_time),"all") . "\n";
+
+
+#
+# Testing left outer join
+#
+
+if ($limits->{'func_odbc_floor'} && $limits->{'left_outer_join'})
+{
+ if ($opt_lock_tables)
+ {
+ $sth = $dbh->do("LOCK TABLES bench1 a READ, bench1 b READ") || die $DBI::errstr;
+ }
+ print "\nTesting left outer join\n";
+ $loop_time=new Benchmark;
+ $count=0;
+ for ($i=0 ; $i < $small_loop_count ; $i++)
+ {
+ $count+=fetch_all_rows($dbh,"select count(*) from bench1 as a left outer join bench1 as b on (a.id2=b.id3)");
+ }
+ $end_time=new Benchmark;
+ print "Time for outer_join_on_key ($small_loop_count:$count): " .
+ timestr(timediff($end_time, $loop_time),"all") . "\n";
+
+ $loop_time=new Benchmark;
+ $count=0;
+ for ($i=0 ; $i < $small_loop_count ; $i++)
+ {
+ $count+=fetch_all_rows($dbh,"select count(a.dummy1),count(b.dummy1) from bench1 as a left outer join bench1 as b on (a.id2=b.id3)");
+ }
+ $end_time=new Benchmark;
+ print "Time for outer_join ($small_loop_count:$count): " .
+ timestr(timediff($end_time, $loop_time),"all") . "\n";
+
+ $count=0;
+ $loop_time=new Benchmark;
+ for ($i=0 ; $i < $small_loop_count ; $i++)
+ {
+ $count+=fetch_all_rows($dbh,"select count(a.dummy1),count(b.dummy1) from bench1 as a left outer join bench1 as b on (a.id2=b.id3) where b.id3 is not null");
+ }
+ $end_time=new Benchmark;
+ print "Time for outer_join_found ($small_loop_count:$count): " .
+ timestr(timediff($end_time, $loop_time),"all") . "\n";
+
+ $count=$estimated=0;
+ $loop_time=new Benchmark;
+ for ($i=0 ; $i < $small_loop_count ; $i++)
+ {
+ $count+=fetch_all_rows($dbh,"select count(a.dummy1),count(b.dummy1) from bench1 as a left outer join bench1 as b on (a.id2=b.id3) where b.id3 is null");
+ $end_time=new Benchmark;
+ last if ($estimated=predict_query_time($loop_time,$end_time,
+ \$count,$i,
+ $range_loop_count));
+ }
+ if ($estimated)
+ { print "Estimated time"; }
+ else
+ { print "Time"; }
+ print " for outer_join_not_found ($range_loop_count:$count): " .
+ timestr(timediff($end_time, $loop_time),"all") . "\n";
+
+ if ($opt_lock_tables)
+ {
+ $sth = $dbh->do("LOCK TABLES bench1 WRITE") || die $DBI::errstr;
+ }
+}
+
+if ($server->small_rollback_segment())
+{
+ $dbh->disconnect; # close connection
+ $dbh = $server->connect();
+}
+
+####
+#### Do some deletes on the table
+####
+
+if (!$opt_skip_delete)
+{
+ print "\nTesting delete\n";
+ $loop_time=new Benchmark;
+ $count=0;
+ for ($i=0 ; $i < $opt_loop_count ; $i+=10)
+ {
+ $count++;
+ $tmp=$opt_loop_count+$random[$i]; # $opt_loop_count*2 <= $tmp < $total_rows
+ $dbh->do("delete from bench1 where id3=$tmp") or die $DBI::errstr;
+ }
+
+ $end_time=new Benchmark;
+ print "Time for delete_key ($count): " .
+ timestr(timediff($end_time, $loop_time),"all") . "\n";
+
+ if ($server->small_rollback_segment())
+ {
+ $dbh->disconnect; # close connection
+ $dbh = $server->connect();
+ }
+
+ $count=0;
+ $loop_time=new Benchmark;
+ for ($i= 0 ; $i < $opt_loop_count ; $i+=$opt_loop_count/10)
+ {
+ $sth=$dbh->do("delete from bench1 where id3 >= 0 and id3 <= $i") or die $DBI::errstr;
+ $count++;
+ }
+ $count+=2;
+ if ($server->small_rollback_segment())
+ {
+ $dbh->disconnect; # close connection
+ $dbh = $server->connect();
+ }
+ $sth=$dbh->do("delete from bench1 where id3 >= 0 and id3 <= $opt_loop_count") or die $DBI::errstr;
+ if ($server->small_rollback_segment())
+ {
+ $dbh->disconnect; # close connection
+ $dbh = $server->connect();
+ }
+
+ $sth=$dbh->do("delete from bench1 where id >= $opt_loop_count and id <= " . ($opt_loop_count*2) ) or die $DBI::errstr;
+
+ if ($server->small_rollback_segment())
+ {
+ $dbh->disconnect; # close connection
+ $dbh = $server->connect();
+ }
+ if ($opt_fast)
+ {
+ $sth=$dbh->do("delete from bench1") or die $DBI::errstr;
+ }
+ else
+ {
+ $sth = $dbh->do("delete from bench1 where id3 < " . ($total_rows)) or die $DBI::errstr;
+ }
+
+ $end_time=new Benchmark;
+ print "Time for delete_big ($count): " .
+ timestr(timediff($end_time, $loop_time),"all") . "\n\n";
+
+ if ($opt_lock_tables)
+ {
+ $sth = $dbh->do("UNLOCK TABLES ") || die $DBI::errstr;
+ }
+ $sth = $dbh->do("drop table bench1") or die $DBI::errstr;
+}
+
+if ($server->small_rollback_segment())
+{
+ $dbh->disconnect; # close connection
+ $dbh = $server->connect();
+}
+if ($opt_fast && defined($server->{vacuum}))
+{
+ $server->vacuum(1,\$dbh);
+}
+
+
+keys_test:
+#
+# Test of insert in table with many keys
+# This test assumes that the server really create the keys!
+#
+
+my @fields=(); my @keys=();
+$keys=min($limits->{'max_index'},16); # 16 is more than enough
+$seg= min($limits->{'max_index_parts'},$keys,16); # 16 is more than enough
+
+print "Insert into table with $keys keys and with a primary key with $seg parts\n";
+
+# 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,"field2 mediumint not null");
+push(@fields,"field3 smallint not null");
+push(@fields,"field4 char(16) not null");
+push(@fields,"field5 integer not null");
+push(@fields,"field6 float not null");
+push(@fields,"field7 double not null");
+for ($i=8 ; $i <= $keys ; $i++)
+{
+ push(@fields,"field$i char(6) not null"); # Should be relatively fair
+}
+
+# First key contains many segments
+$query="primary key (";
+for ($i= 1 ; $i <= $seg ; $i++)
+{
+ $query.= "field$i,";
+}
+substr($query,-1)=")";
+push (@keys,$query);
+
+#Create other keys
+for ($i=2 ; $i <= $keys ; $i++)
+{
+ push(@keys,"index index$i (field$i)");
+}
+
+do_many($dbh,$server->create("bench1",\@fields,\@keys));
+if ($opt_lock_tables)
+{
+ $dbh->do("LOCK TABLES bench1 WRITE") || die $DBI::errstr;
+}
+
+if ($server->small_rollback_segment())
+{
+ $dbh->disconnect; # close connection
+ $dbh = $server->connect();
+}
+
+$loop_time=new Benchmark;
+$fields=$#fields;
+if (($opt_fast || $opt_fast_insert) && $limits->{'multi_value_insert'})
+{
+ $query_size=$server->{'limits'}->{'query_size'};
+ $query="insert into bench1 values ";
+ $res=$query;
+ for ($i=0; $i < $many_keys_loop_count; $i++)
+ {
+ $rand=$random[$i];
+ $tmp="(" . ($i & 127) . ",$rand," . ($i & 32766) .
+ ",'ABCDEF$rand',0,";
+
+ for ($j=5; $j <= $fields ; $j++)
+ {
+ $tmp.= ($types[$j] == 0) ? "$rand," : "'$rand',";
+ }
+ substr($tmp,-1)=")";
+ if (length($tmp)+length($res) < $query_size)
+ {
+ $res.= $tmp . ",";
+ }
+ else
+ {
+ $sth = $dbh->do(substr($res,0,length($res)-1)) or die $DBI::errstr;
+ $res=$query . $tmp . ",";
+ }
+ }
+ $sth = $dbh->do(substr($res,0,length($res)-1)) or die $DBI::errstr;
+}
+else
+{
+ for ($i=0; $i < $many_keys_loop_count; $i++)
+ {
+ $rand=$random[$i];
+ $query="insert into bench1 values (" . ($i & 127) . ",$rand," . ($i & 32767) .
+ ",'ABCDEF$rand',0,";
+
+ for ($j=5; $j <= $fields ; $j++)
+ {
+ $query.= ($types[$j] == 0) ? "$rand," : "'$rand',";
+ }
+ substr($query,-1)=")";
+ print "query1: $query\n" if ($opt_debug);
+ $dbh->do($query) or die "Got error $DBI::errstr with query: $query\n";
+ }
+}
+$end_time=new Benchmark;
+print "Time for insert_key ($many_keys_loop_count): " .
+ timestr(timediff($end_time, $loop_time),"all") . "\n\n";
+
+if ($server->small_rollback_segment())
+{
+ $dbh->disconnect; # close connection
+ $dbh = $server->connect();
+}
+if ($opt_fast && defined($server->{vacuum}))
+{
+ $server->vacuum(1,\$dbh);
+}
+
+#
+# update one key of the above
+#
+
+print "Testing update of keys\n";
+$loop_time=new Benchmark;
+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";
+}
+$end_time=new Benchmark;
+print "Time for update_of_key (256): " .
+ timestr(timediff($end_time, $loop_time),"all") . "\n\n";
+
+if ($server->small_rollback_segment())
+{
+ $dbh->disconnect; # close connection
+ $dbh = $server->connect();
+}
+if ($opt_fast && defined($server->{vacuum}))
+{
+ $server->vacuum(1,\$dbh);
+}
+
+if ($server->small_rollback_segment())
+{
+ $dbh->disconnect; # close connection
+ $dbh = $server->connect();
+}
+
+#
+# Delete everything from table
+#
+
+print "Deleting everything from table\n";
+$loop_time=new Benchmark;
+$count=0;
+if ($opt_fast)
+{
+ $dbh->do("delete from bench1 where field1 = 0") or die $DBI::errstr;
+ $dbh->do("delete from bench1") or die $DBI::errstr;
+ $count+=2;
+}
+else
+{
+ $dbh->do("delete from bench1 where field1 = 0") or die $DBI::errstr;
+ $dbh->do("delete from bench1 where field1 > 0") or die $DBI::errstr;
+ $count+=2;
+}
+
+if ($opt_lock_tables)
+{
+ $sth = $dbh->do("UNLOCK TABLES") || die $DBI::errstr;
+}
+
+$end_time=new Benchmark;
+print "Time for delete_big_many_keys ($count): " .
+ timestr(timediff($end_time, $loop_time),"all") . "\n\n";
+
+$sth = $dbh->do("drop table bench1") or die $DBI::errstr;
+if ($opt_fast && defined($server->{vacuum}))
+{
+ $server->vacuum(1,\$dbh);
+}
+
+#
+# Test multi value inserts if the server supports it
+#
+
+if ($limits->{'multi_value_insert'})
+{
+ $query_size=$limits->{'query_size'}; # Same limit for all databases
+
+ $sth = $dbh->do("drop table bench1");
+ do_many($dbh,$server->create("bench1",
+ ["id int NOT NULL",
+ "id2 int NOT NULL",
+ "id3 int NOT NULL",
+ "dummy1 char(30)"],
+ ["primary key (id,id2)",
+ "index index_id3 (id3)"]));
+ if ($opt_lock_tables)
+ {
+ $sth = $dbh->do("LOCK TABLES bench1 write") || die $DBI::errstr;
+ }
+
+ $loop_time=new Benchmark;
+ print "Inserting $opt_loop_count rows with multiple values\n";
+ $query="insert into bench1 values ";
+ $res=$query;
+ for ($i=0 ; $i < $opt_loop_count ; $i++)
+ {
+ my $tmp= "($i,$i,$i,'EFGHIJKLM'),";
+ if (length($i)+length($res) < $query_size)
+ {
+ $res.= $tmp;
+ }
+ else
+ {
+ do_query($dbh,substr($res,0,length($res)-1));
+ $res=$query .$tmp;
+ }
+ }
+ do_query($dbh,substr($res,0,length($res)-1));
+
+ if ($opt_lock_tables)
+ {
+ $sth = $dbh->do("UNLOCK TABLES ") || die $DBI::errstr;
+ }
+
+ $end_time=new Benchmark;
+ print "Time for multiple_value_insert (" . ($opt_loop_count) . "): " .
+ timestr(timediff($end_time, $loop_time),"all") . "\n\n";
+
+ if ($opt_fast && defined($server->{vacuum}))
+ {
+ $server->vacuum(1,\$dbh);
+ }
+ if ($opt_lock_tables)
+ {
+ $sth = $dbh->do("UNLOCK TABLES ") || die $DBI::errstr;
+ }
+
+ # A big table may take a while to drop
+ $loop_time=new Benchmark;
+ $sth = $dbh->do("drop table bench1") or die $DBI::errstr;
+ $end_time=new Benchmark;
+ print "Time for drop table(1): " .
+ timestr(timediff($end_time, $loop_time),"all") . "\n\n";
+}
+
+####
+#### End of benchmark
+####
+
+$dbh->disconnect; # close connection
+
+end_benchmark($start_time);
+
+###
+### Some help functions
+###
+
+
+# Do some sample selects on direct key
+# First select finds a row, the second one doesn't find.
+
+sub check_select_key
+{
+ my ($column,$check)= @_;
+ my ($loop_time,$end_time,$i,$tmp_var,$tmp,$count,$row_count,$estimated);
+
+ $estimated=0;
+ $loop_time=new Benchmark;
+ $count=0;
+ for ($i=1 ; $i <= $opt_loop_count; $i++)
+ {
+ $count+=2;
+ $tmpvar^= ((($tmpvar + 63) + $i)*3 % $opt_loop_count);
+ $tmp=$tmpvar % ($total_rows);
+ fetch_all_rows($dbh,"select * from bench1 where $column=$tmp")
+ or die $DBI::errstr;
+ $tmp+=$total_rows;
+ defined($row_count=fetch_all_rows($dbh,"select * from bench1 where $column=$tmp")) or die $DBI::errstr;
+ die "Found $row_count rows on impossible id: $tmp\n" if ($row_count);
+ $end_time=new Benchmark;
+ last if ($estimated=predict_query_time($loop_time,$end_time,\$count,$i,
+ $opt_loop_count));
+ }
+ if ($estimated)
+ { print "Estimated time"; }
+ else
+ { print "Time"; }
+ print " for $check ($count): " .
+ timestr(timediff($end_time, $loop_time),"all") . "\n";
+}
+
+#
+# Search using some very simple queries
+#
+
+sub check_select_range
+{
+ my ($column,$check)= @_;
+ my ($loop_time,$end_time,$i,$tmp_var,$tmp,$query,$rows,$estimated);
+
+ $estimated=0;
+ $loop_time=new Benchmark;
+ $found=$count=0;
+ for ($test=1 ; $test <= $range_loop_count; $test++)
+ {
+ $count+=$#Q+1;
+ for ($i=0 ; $i < $#Q ; $i+=2)
+ {
+ $query=$Q[$i];
+ $rows=$Q[$i+1];
+ $query =~ s/!id!/$column/g;
+ if (($row_count=fetch_all_rows($dbh,$query)) != $rows)
+ {
+ if ($row_count == undef())
+ {
+ die "Got error: $DBI::errstr when executing $query\n";
+ }
+ die "'$query' returned wrong number of rows: $row_count instead of $rows\n";
+ }
+ $found+=$row_count;
+ }
+ $end_time=new Benchmark;
+ last if ($estimated=predict_query_time($loop_time,$end_time,\$count,$test,
+ $range_loop_count));
+ }
+ if ($estimated)
+ { print "Estimated time"; }
+ else
+ { print "Time"; }
+ print " for $check ($count:$found): " .
+ timestr(timediff($end_time, $loop_time),"all") . "\n";
+}
+
+
+#
+# SELECT * from bench where col=x or col=x or col=x ...
+
+
+sub check_or_range
+{
+ my ($column,$check)= @_;
+ my ($loop_time,$end_time,$i,$tmp_var,$tmp,$columns,$estimated,$found,
+ $or_part,$count,$loop_count);
+
+ $columns=min($limits->{'max_columns'},50,($limits->{'query_size'}-50)/13);
+ $columns=$columns- ($columns % 4); # Make Divisible by 4
+
+ $estimated=0;
+ $loop_time=new Benchmark;
+ $found=0;
+ $loop_count=$range_loop_count*10;
+ for ($count=0 ; $count < $loop_count ; )
+ {
+ for ($rowcnt=0; $rowcnt <= $columns; $rowcnt+= $columns/4)
+ {
+ my $query="select * from bench1 where ";
+ my $or_part= "$column = 1";
+ $count+=2;
+
+ for ($i=1 ; $i < $rowcnt ; $i++)
+ {
+ $tmpvar^= ((($tmpvar + 63) + $i)*3 % $opt_loop_count);
+ $tmp=$tmpvar % ($opt_loop_count*4);
+ $or_part.=" or $column=$tmp";
+ }
+ print $query . $or_part . "\n" if ($opt_debug);
+ ($rows=fetch_all_rows($dbh,$query . $or_part)) or die $DBI::errstr;
+ $found+=$rows;
+
+ if ($limits->{'func_extra_in_num'})
+ {
+ my $in_part=$or_part; # Same query, but use 'func_extra_in_num' instead.
+ $in_part=~ s/ = / IN \(/;
+ $in_part=~ s/ or $column=/,/g;
+ $in_part.= ")";
+ fetch_all_rows($dbh,$query . $in_part) or die $DBI::errstr;
+ $count++;
+ }
+ # Do it a little harder by setting a extra range
+ defined(($rows=fetch_all_rows($dbh,"$query($or_part) and $column < 10"))) or die $DBI::errstr;
+ $found+=$rows;
+ }
+ $end_time=new Benchmark;
+ last if ($estimated=predict_query_time($loop_time,$end_time,\$count,$count,
+ $loop_count));
+ }
+
+ if ($estimated)
+ { print "Estimated time"; }
+ else
+ { print "Time"; }
+ print " for $check ($count:$found): " .
+ timestr(timediff($end_time, $loop_time),"all") . "\n";
+}
diff --git a/sql-bench/test-select.sh b/sql-bench/test-select.sh
new file mode 100755
index 00000000000..7ed8a4cac9f
--- /dev/null
+++ b/sql-bench/test-select.sh
@@ -0,0 +1,353 @@
+#@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=1000;
+$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");
+
+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_fast && defined($server->{vacuum}))
+{
+ $server->vacuum(0,\$dbh);
+}
+
+####
+#### Do some selects on the table
+####
+
+select_test:
+
+print "Testing big selects on the table\n";
+$loop_time=new Benchmark;
+$rows=0;
+for ($i=0 ; $i < $opt_small_loop_count ; $i++)
+{
+ $grp=$i*11 % $opt_groups;
+ $region=chr(65+$i%($opt_regions+1)); # One larger to test misses
+ $rows+=fetch_all_rows($dbh,"select idn from bench1 where region='$region'");
+ $rows+=fetch_all_rows($dbh,"select idn from bench1 where region='$region' and idn=$i");
+ $rows+=fetch_all_rows($dbh,"select idn from bench1 where region='$region' and rev_idn=$i");
+ $rows+=fetch_all_rows($dbh,"select idn from bench1 where region='$region' and grp=$grp");
+ $rows+=fetch_all_rows($dbh,"select idn from bench1 where region>='B' and region<='C' and grp=$grp");
+ $rows+=fetch_all_rows($dbh,"select idn from bench1 where region>='B' and region<='E' and grp=$grp");
+ $rows+=fetch_all_rows($dbh,"select idn from bench1 where grp=$grp"); # This is hard
+}
+$count=$opt_small_loop_count*7;
+
+$end_time=new Benchmark;
+print "Time for select_big ($count:$rows): " .
+ timestr(timediff($end_time, $loop_time),"all") . "\n";
+
+# Test select with many OR's
+
+$loop_time=new Benchmark;
+$tmpvar=0;
+$count=0;
+$estimated=0;
+$max_and_conditions=$limits->{'max_conditions'}/2;
+$rows=0;
+
+for ($i=0 ; $i < $opt_small_loop_count ; $i++)
+{
+ $region=chr(65+$i%($opt_regions+1)); # One larger to test out-of-regions
+ $query="select * from bench1 where ";
+ $or_part="grp = 1";
+ $or_part2="region='A' and grp=1";
+
+ for ($j=1 ; $j < $columns; $j++)
+ {
+ $tmpvar^= ((($tmpvar + 63) + $j)*3 % 100000);
+ $tmp=$tmpvar % $opt_groups;
+ $tmp_region=chr(65+$tmpvar%$opt_regions);
+ $or_part.=" or grp=$tmp";
+ if ($j < $max_and_conditions)
+ {
+ $or_part2.=" or region='$tmp_region' and grp=$tmp";
+ }
+ }
+ $or_part="region='$region' and ($or_part)";
+
+# Same query, but use 'func_extra_in_num' instead.
+ if ($limits->{'func_extra_in_num'})
+ {
+ $in_part=$or_part;
+ $in_part=~ s/ = / IN \(/;
+ $in_part=~ s/ or grp=/,/g;
+ $in_part.= ")";
+ defined($found=fetch_all_rows($dbh,$query . $in_part)) || die $DBI::errstr;
+ $rows+=$found;
+ $count++;
+ }
+ for ($j=0; $j < 10 ; $j++)
+ {
+ $rows+=fetch_all_rows($dbh,$query . $or_part);
+ $rows+=fetch_all_rows($dbh,$query . $or_part2);
+# Do it a little harder by setting a extra range
+ $rows+=fetch_all_rows($dbh,"$query ($or_part) and idn < 50");
+ $rows+=fetch_all_rows($dbh,"$query (($or_part) or (region='A' and grp < 10)) and region <='B'")
+ }
+ $count+=$j*4;
+ $end_time=new Benchmark;
+ last if ($estimated=predict_query_time($loop_time,$end_time,\$count,$i+1,
+ $opt_small_loop_count));
+}
+
+if ($estimated)
+{ print "Estimated time"; }
+else
+{ print "Time"; }
+print " for select_range ($count:$rows): " .
+ timestr(timediff($end_time, $loop_time),"all") . "\n";
+
+#
+# Testing MIN() and MAX() on keys
+#
+
+if ($limits->{'group_functions'})
+{
+ $loop_time=new Benchmark;
+ $count=0;
+ $estimated=0;
+ for ($tests=0 ; $tests < $opt_loop_count ; $tests++)
+ {
+ $count+=7;
+ $grp=$tests*3 % $opt_groups;
+ $region=chr(65+$tests % $opt_regions);
+ if ($limits->{'group_func_sql_min_str'})
+ {
+ fetch_all_rows($dbh,"select min(region) from bench1");
+ fetch_all_rows($dbh,"select max(region) from bench1");
+ fetch_all_rows($dbh,"select min(region),max(region) from bench1");
+ }
+ fetch_all_rows($dbh,"select min(rev_idn) from bench1 where region='$region'");
+ fetch_all_rows($dbh,"select max(grp) from bench1 where region='$region'");
+ fetch_all_rows($dbh,"select max(idn) from bench1 where region='$region' and grp=$grp");
+ if ($limits->{'group_func_sql_min_str'})
+ {
+ fetch_all_rows($dbh,"select max(region) from bench1 where region<'$region'");
+ }
+ $end_time=new Benchmark;
+ last if ($estimated=predict_query_time($loop_time,$end_time,\$count,
+ $tests+1, $opt_loop_count));
+ }
+ if ($estimated)
+ { print "Estimated time"; }
+ else
+ { print "Time"; }
+ print " for min_max_on_key ($count): " .
+ timestr(timediff($end_time, $loop_time),"all") . "\n";
+
+ $loop_time=new Benchmark;
+ $count=0;
+ $estimated=0;
+ for ($tests=0 ; $tests < $opt_loop_count ; $tests++)
+ {
+ $count+=5;
+ $grp=$tests*3 % $opt_groups;
+ $region=chr(65+$tests % $opt_regions);
+ fetch_all_rows($dbh,"select count(*) from bench1 where region='$region'");
+ fetch_all_rows($dbh,"select count(*) from bench1 where region='$region' and grp=$grp");
+ fetch_all_rows($dbh,"select count(*) from bench1 where region>'$region'");
+ fetch_all_rows($dbh,"select count(*) from bench1 where region<='$region'");
+ fetch_all_rows($dbh,"select count(*) from bench1 where region='$region' and grp>$grp");
+ $end_time=new Benchmark;
+ last if ($estimated=predict_query_time($loop_time,$end_time,\$count,
+ $tests+1, $opt_loop_count));
+ }
+ if ($estimated)
+ { print "Estimated time"; }
+ else
+ { print "Time"; }
+ print " for count_on_key ($count): " .
+ timestr(timediff($end_time, $loop_time),"all") . "\n\n";
+
+ $loop_time=new Benchmark;
+ $rows=0;
+ for ($i=0 ; $i < $opt_medium_loop_count ; $i++)
+ {
+ fetch_all_rows($dbh,"select grp,count(*) from bench1 group by grp");
+ }
+ $end_time=new Benchmark;
+ print "Time for count_group_on_key_parts ($i:$rows): " .
+ timestr(timediff($end_time, $loop_time),"all") . "\n";
+}
+
+if ($limits->{'group_functions'})
+{
+ print "Testing count(distinct) on the table\n";
+ $loop_time=new Benchmark;
+ $rows=0;
+ for ($i=0 ; $i < $opt_medium_loop_count ; $i++)
+ {
+ $rows+=fetch_all_rows($dbh,"select count(distinct region) from bench1");
+ $rows+=fetch_all_rows($dbh,"select count(distinct grp) from bench1");
+ }
+ $end_time=new Benchmark;
+ print "Time for count_distinct ($i:$rows): " .
+ timestr(timediff($end_time, $loop_time),"all") . "\n";
+
+ $loop_time=new Benchmark;
+ $rows=0;
+ for ($i=0 ; $i < $opt_medium_loop_count ; $i++)
+ {
+ $rows+=fetch_all_rows($dbh,"select region,count(distinct idn) from bench1 group by region");
+ }
+ $end_time=new Benchmark;
+ print "Time for count_distinct_group_on_key ($i:$rows): " .
+ timestr(timediff($end_time, $loop_time),"all") . "\n";
+
+ $loop_time=new Benchmark;
+ $rows=0;
+ for ($i=0 ; $i < $opt_medium_loop_count ; $i++)
+ {
+ $rows+=fetch_all_rows($dbh,"select grp,count(distinct idn) from bench1 group by grp");
+ }
+ $end_time=new Benchmark;
+ print "Time for count_distinct_group_on_key_parts ($i:$rows): " .
+ timestr(timediff($end_time, $loop_time),"all") . "\n";
+
+ $loop_time=new Benchmark;
+ $rows=0;
+ for ($i=0 ; $i < $opt_medium_loop_count ; $i++)
+ {
+ $rows+=fetch_all_rows($dbh,"select grp,count(distinct rev_idn) from bench1 group by grp");
+ }
+ $end_time=new Benchmark;
+ print "Time for count_distinct_group ($i:$rows): " .
+ timestr(timediff($end_time, $loop_time),"all") . "\n";
+
+ $loop_time=new Benchmark;
+ $rows=0;
+ for ($i=0 ; $i < $opt_medium_loop_count ; $i++)
+ {
+ $rows+=fetch_all_rows($dbh,"select idn,count(distinct region) from bench1 group by idn");
+ }
+ $end_time=new Benchmark;
+ print "Time for count_distinct_big ($i:$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");
+}
+
+if ($opt_fast && defined($server->{vacuum}))
+{
+ $server->vacuum(0,\$dbh);
+}
+
+$dbh->disconnect; # close connection
+
+end_benchmark($start_time);
diff --git a/sql-bench/test-wisconsin.sh b/sql-bench/test-wisconsin.sh
new file mode 100755
index 00000000000..00b0e933c4d
--- /dev/null
+++ b/sql-bench/test-wisconsin.sh
@@ -0,0 +1,344 @@
+#!@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
+#
+
+use DBI;
+use Benchmark;
+
+$opt_loop_count=10;
+
+chomp($pwd = `pwd`); $pwd = "." if ($pwd eq '');
+require "$pwd/bench-init.pl" || die "Can't read Configuration file: $!\n";
+
+$into_table = "";
+
+if ($opt_small_test)
+{
+ $opt_loop_count/=5;
+}
+
+####
+#### Connect and start timeing
+####
+
+$dbh = $server->connect();
+$start_time=new Benchmark;
+
+####
+#### Create needed tables
+####
+
+init_data();
+init_query();
+
+print "Wisconsin benchmark test\n\n";
+
+if (!$opt_skip_create)
+{
+ $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");
+ 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);
+}
+
+
+####
+#### Insert data
+####
+
+print "Inserting data\n";
+$loop_time= new Benchmark;
+$row_count=0;
+if ($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 && $server->{'limits'}->{'load_data_infile'})
+{
+ for ($ti = 0; $ti <= $#table_names; $ti++)
+ {
+ my $table_name = $table_names[$ti];
+ if ($table_name =~ /tenk|Bprime/i) {
+ $filename = "$pwd/Data/Wisconsin/tenk.data";
+ } else {
+ $filename = "$pwd/Data/Wisconsin/$table_name.data";
+ }
+ $row_count+=$server->insert_file($table_name,$filename,$dbh);
+ }
+}
+else
+{
+ for ($ti = 0; $ti <= $#table_names; $ti++)
+ {
+ my $table_name = $table_names[$ti];
+ my $array_ref = $tables[$ti];
+ my @table = @$array_ref;
+ my $insert_start = "insert into $table_name values (";
+
+ if ($table_name =~ /tenk|Bprime/i) {
+ $filename = "$pwd/Data/Wisconsin/tenk.data";
+ } else {
+ $filename = "$pwd/Data/Wisconsin/$table_name.data";
+ }
+ open(DATA, "$filename") || die "Can't open text file: $filename\n";
+ while(<DATA>)
+ {
+ chomp;
+ $command = $insert_start . $_ . ")";
+ print "$command\n" if ($opt_debug);
+ $sth = $dbh->do($command) or die $DBI::errstr;
+ $row_count++;
+ }
+ }
+ close(DATA);
+}
+$end_time=new Benchmark;
+print "Time to insert ($row_count): " .
+ timestr(timediff($end_time, $loop_time),"all") . "\n";
+
+## Oracle runs out of rollback segments here if using the default "small"
+## configuration so disconnect and reconnect to use a new segment
+if ($server->small_rollback_segment())
+{
+ $dbh->disconnect; # close connection
+ $dbh=$server->connect();
+}
+
+if ($opt_fast && defined($server->{vacuum}))
+{
+ $server->vacuum(0,\$dbh);
+}
+
+$loop_time= $end_time;
+print "Delete from Bprime where unique2 >= 1000\n" if ($opt_debug);
+$sth = $dbh->do("delete from Bprime where Bprime.unique2 >= 1000") or
+ die $DBI::errstr;
+$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}))
+{
+ $server->vacuum(0,\$dbh);
+}
+
+####
+#### Running the benchmark
+####
+
+print "Running actual benchmark\n";
+
+$loop_time= new Benchmark;
+$count=0;
+for ($i = 0; $i <= $#query; $i+=2)
+{
+ if ($query[$i+1]) # If the server can handle it
+ {
+ $loop_count = 1;
+ $loop_count = $opt_loop_count if ($query[$i] =~ /^select/i);
+ $query[$i] =~ s/\sAS\s+[^\s,]+//ig if (!$limits->{'column_alias'});
+ timeit($loop_count, "fetch_all_rows(\$dbh,\"$query[$i]\")");
+ $count+=$loop_count;
+ }
+}
+
+$end_time=new Benchmark;
+print "Time for wisc_benchmark ($count): " .
+ timestr(timediff($end_time, $loop_time),"all") . "\n\n";
+
+if (!$opt_skip_delete)
+{
+ for ($ti = 0; $ti <= $#table_names; $ti++)
+ {
+ my $table_name = $table_names[$ti];
+ $sth = $dbh->do("drop table $table_name");
+ }
+}
+
+if ($opt_fast && defined($server->{vacuum}))
+{
+ $server->vacuum(0,\$dbh);
+}
+
+####
+#### The END
+####
+
+$dbh->disconnect; # close connection
+end_benchmark($start_time);
+
+
+################################
+###### subroutine for database structure
+################################
+
+sub init_data
+{
+ @onek=
+ $server->create("onek",
+ ["unique1 int(4) NOT NULL",
+ "unique2 int(4) NOT NULL",
+ "two int(4)",
+ "four int(4)",
+ "ten int(4)",
+ "twenty int(4)",
+ "hundred int(4) NOT NULL",
+ "thousand int(4)",
+ "twothousand int(4)",
+ "fivethous int(4)",
+ "tenthous int(4)",
+ "odd int(4)",
+ "even int(4)",
+ "stringu1 char(16)",
+ "stringu2 char(16)",
+ "string4 char(16)"],
+ ["UNIQUE (unique1)",
+ "UNIQUE (unique2)",
+ "INDEX hundred1 (hundred)"]);
+
+ @tenk1=
+ $server->create("tenk1",
+ ["unique1 int(4) NOT NULL",
+ "unique2 int(4) NOT NULL",
+ "two int(4)",
+ "four int(4)",
+ "ten int(4)",
+ "twenty int(4)",
+ "hundred int(4) NOT NULL",
+ "thousand int(4)",
+ "twothousand int(4)",
+ "fivethous int(4)",
+ "tenthous int(4)",
+ "odd int(4)",
+ "even int(4)",
+ "stringu1 char(16)",
+ "stringu2 char(16)",
+ "string4 char(16)"],
+ ["UNIQUE (unique1)",
+ "UNIQUE (unique2)",
+ "INDEX hundred2 (hundred)"]);
+
+ @tenk2=
+ $server->create("tenk2",
+ ["unique1 int(4) NOT NULL",
+ "unique2 int(4) NOT NULL",
+ "two int(4)",
+ "four int(4)",
+ "ten int(4)",
+ "twenty int(4)",
+ "hundred int(4) NOT NULL",
+ "thousand int(4)",
+ "twothousand int(4)",
+ "fivethous int(4)",
+ "tenthous int(4)",
+ "odd int(4)",
+ "even int(4)",
+ "stringu1 char(16)",
+ "stringu2 char(16)",
+ "string4 char(16)"],
+ ["UNIQUE (unique1)",
+ "UNIQUE (unique2)",
+ "INDEX hundred3 (hundred)"]);
+
+ @Bprime=
+ $server->create("Bprime",
+ ["unique1 int(4) NOT NULL",
+ "unique2 int(4) NOT NULL",
+ "two int(4)",
+ "four int(4)",
+ "ten int(4)",
+ "twenty int(4)",
+ "hundred int(4) NOT NULL",
+ "thousand int(4)",
+ "twothousand int(4)",
+ "fivethous int(4)",
+ "tenthous int(4)",
+ "odd int(4)",
+ "even int(4)",
+ "stringu1 char(16)",
+ "stringu2 char(16)",
+ "string4 char(16)"],
+ ["UNIQUE (unique1)",
+ "UNIQUE (unique2)",
+ "INDEX hundred4 (hundred)"]);
+
+ @tables =
+ (\@onek, \@tenk1, \@tenk2, \@Bprime);
+
+ @table_names =
+ ("onek", "tenk1", "tenk2", "Bprime");
+
+# Alias used in joins
+ @extra_names=
+ ("tenk1 as t", "tenk1 as t1","tenk1 as t2", "Bprime as B","onek as o");
+}
+
+
+sub init_query
+{
+ @query=
+ ("select * $into_table from tenk1 where (unique2 > 301) and (unique2 < 402)",1,
+ "select * $into_table from tenk1 where (unique1 > 647) and (unique1 < 1648)",1,
+ "select * from tenk1 where unique2 = 2001",1,
+ "select * from tenk1 where (unique2 > 301) and (unique2 < 402)",1,
+ "select t1.*, t2.unique1 AS t2unique1, t2.unique2 AS t2unique2, t2.two AS t2two, t2.four AS t2four, t2.ten AS t2ten, t2.twenty AS t2twenty, t2.hundred AS t2hundred, t2.thousand AS t2thousand, t2.twothousand AS t2twothousand, t2.fivethous AS t2fivethous, t2.tenthous AS t2tenthous, t2.odd AS t2odd, t2.even AS t2even, t2.stringu1 AS t2stringu1, t2.stringu2 AS t2stringu2, t2.string4 AS t2string4 $into_table from tenk1 t1, tenk1 t2 where (t1.unique2 = t2.unique2) and (t2.unique2 < 1000)",$limits->{'table_wildcard'},
+ "select t.*,B.unique1 AS Bunique1,B.unique2 AS Bunique2,B.two AS Btwo,B.four AS Bfour,B.ten AS Bten,B.twenty AS Btwenty,B.hundred AS Bhundred,B.thousand AS Bthousand,B.twothousand AS Btwothousand,B.fivethous AS Bfivethous,B.tenthous AS Btenthous,B.odd AS Bodd,B.even AS Beven,B.stringu1 AS Bstringu1,B.stringu2 AS Bstringu2,B.string4 AS Bstring4 $into_table from tenk1 t, Bprime B where t.unique2 = B.unique2",$limits->{'table_wildcard'},
+ "select t1.*,o.unique1 AS ounique1,o.unique2 AS ounique2,o.two AS otwo,o.four AS ofour,o.ten AS oten,o.twenty AS otwenty,o.hundred AS ohundred,o.thousand AS othousand,o.twothousand AS otwothousand,o.fivethous AS ofivethous,o.tenthous AS otenthous,o.odd AS oodd, o.even AS oeven,o.stringu1 AS ostringu1,o.stringu2 AS ostringu2,o.string4 AS ostring4 $into_table from onek o, tenk1 t1, tenk1 t2 where (o.unique2 = t1.unique2) and (t1.unique2 = t2.unique2) and (t1.unique2 < 1000) and (t2.unique2 < 1000)",$limits->{'table_wildcard'},
+ "select two, four, ten, twenty, hundred, string4 $into_table from tenk1",1,
+ "select * $into_table from onek",1,
+ "select MIN(unique2) as x $into_table from tenk1",$limits->{'group_functions'},
+ "insert into tenk1 (unique1, unique2, two, four, ten, twenty, hundred, thousand, twothousand, fivethous, tenthous, odd, even,stringu1,stringu2, string4) values (10001, 74001, 0, 2, 0, 10, 50, 688, 1950, 4950, 9950, 1, 100, 'ron may choi','jae kwang choi', 'u. c. berkeley')",1,
+ "insert into tenk1 (unique1, unique2, two, four, ten, twenty, hundred, thousand, twothousand, fivethous, tenthous, odd, even,stringu1,stringu2, string4) values (19991, 60001, 0, 2, 0, 10, 50, 688, 1950, 4950, 9950, 1, 100, 'ron may choi','jae kwang choi', 'u. c. berkeley')",1,
+ "delete from tenk1 where tenk1.unique2 = 877",1,
+ "delete from tenk1 where tenk1.unique2 = 876",1,
+ "update tenk1 set unique2 = 10001 where tenk1.unique2 =1491",1,
+ "update tenk1 set unique2 = 10023 where tenk1.unique2 =1480",1,
+ "insert into tenk1 (unique1, unique2, two, four, ten, twenty, hundred, thousand, twothousand, fivethous, tenthous, odd, even, stringu1, stringu2, string4) values (20002, 70002, 0, 2, 0, 10, 50, 688, 1950, 4950, 9950, 1, 100, 'ron may choi', 'jae kwang choi', 'u. c. berkeley')",1,
+ "insert into tenk1 (unique1, unique2, two, four, ten, twenty, hundred, thousand, twothousand, fivethous, tenthous, odd, even, stringu1, stringu2, string4) values (50002, 40002, 0, 2, 0, 10, 50, 688, 1950, 4950, 9950, 1, 100, 'ron may choi', 'jae kwang choi', 'u. c. berkeley')",1,
+ "delete from tenk1 where tenk1.unique2 = 10001",1,
+ "delete from tenk1 where tenk1.unique2 = 900",1,
+ "update tenk1 set unique2 = 10088 where tenk1.unique2 =187",1,
+ "update tenk1 set unique2 = 10003 where tenk1.unique2 =2000",1,
+ "update tenk1 set unique2 = 10020 where tenk1.unique2 =1974",1,
+ "update tenk1 set unique2 = 16001 where tenk1.unique2 =1140",1,
+ );
+}
diff --git a/sql-bench/uname.bat b/sql-bench/uname.bat
new file mode 100644
index 00000000000..dd9fe012a3d
--- /dev/null
+++ b/sql-bench/uname.bat
@@ -0,0 +1,2 @@
+@echo off
+@ver
diff --git a/sql/.cvsignore b/sql/.cvsignore
new file mode 100644
index 00000000000..3e2f44f5a10
--- /dev/null
+++ b/sql/.cvsignore
@@ -0,0 +1,12 @@
+.deps
+.libs
+Makefile
+Makefile.in
+deadlock_test.c
+gen_lex_hash
+lex_hash.h
+mysqlbinlog
+mysqlbinlog
+mysqld
+sql_yacc.cc
+sql_yacc.h
diff --git a/sql/Attic/lex_hash.h b/sql/Attic/lex_hash.h
new file mode 100644
index 00000000000..6e89119a3dc
--- /dev/null
+++ b/sql/Attic/lex_hash.h
@@ -0,0 +1,416 @@
+/* This code is generated by program for seeking hash algorithms, copyright TcX Datakonsult AB */
+
+#include "lex.h"
+
+static uint16 char_table[] = {
+258,39835,4883,21845,23130,46003,12850,35980,514,65278,61937,7196,40863,26728,26985,9766,
+5654,23644,21331,17733,3341,25186,30069,1542,31354,39321,4626,52171,46260,57568,21588,14906,
+60652,20560,6939,39578,52428,10794,46517,40606,58596,17990,58339,24672,42148,60138,3598,5911,
+43947,37522,36494,1799,36751,30840,57311,34952,56540,27499,45232,41891,61423,38550,29812,24158,
+771,37779,57054,257,8224,64250,51657,16962,13878,20303,42662,6168,19275,20817,34438,44461,
+12336,48059,49087,28013,3855,16191,32896,26214,57825,38807,29298,35723,51400,12079,6682,25957,
+8738,37779,57054,257,8224,64250,51657,16962,13878,20303,42662,6168,19275,20817,34438,44461,
+12336,48059,49087,28013,3855,16191,32896,26214,57825,38807,29298,32639,11051,43690,2313,33924,
+16705,53970,4112,24415,30583,17476,45746,7967,34695,35466,25700,6425,29555,59881,10537,37008,
+7710,2827,62965,11565,26471,43433,34181,30326,13364,29041,54998,47802,52685,63993,2056,51914,
+31097,44718,48830,50372,23387,62194,19789,19532,53456,62451,16448,54741,63736,18761,10023,3084,
+20046,31868,50629,15420,54484,42405,47288,31611,28270,47031,61680,65535,49344,23901,42919,48316,
+10280,55512,60395,51143,9252,53199,40349,56797,13621,11308,49601,36237,18247,15934,18504,46774,
+43176,11822,56283,28784,59624,39064,63479,19018,58853,65021,9509,8995,58082,5140,5397,15163,
+27242,22102,28527,22873,59367,47545,13107,60909,41120,24929,22616,49858,38036,17219,4369,64507,
+50115,62708,7453,41377,53713,33153,32382,59110,64764,50886,33410,8481,63222,41634,12593,56026
+};
+
+
+static uchar unique_length[] = {
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,3,1,2,0,
+0,5,5,13,9,7,6,6,6,7,1,4,5,7,5,7,
+8,3,12,10,6,7,4,5,0,5,1,0,0,0,0,0,
+0,5,5,13,9,7,6,6,6,7,1,4,5,7,5,7,
+8,3,12,10,6,7,4,5,0,5,1,0,1,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
+};
+
+
+static uint16 my_function_table[] = {
+32767,32767,32767,32767,32767,32767,32767,32767,102,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,282,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,297,32767,32767,202,382,126,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,169,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,306,152,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,354,32767,32767,32767,32767,32767,370,256,32767,
+32767,32767,32767,32767,32767,32767,355,32767,32767,32767,32767,361,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,313,32767,32767,32767,32767,32767,32767,
+14,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,315,
+32767,32767,32767,32767,32767,32767,32767,32767,42,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,189,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,27,32767,32767,32767,32767,32767,32767,32767,374,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,166,32767,32767,32767,32767,32767,32767,349,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+46,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,353,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,223,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+216,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,143,32767,32767,32767,32767,32767,32767,32767,
+32767,20,32767,32767,32767,140,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,125,32767,32767,32767,
+32767,224,32767,32767,32767,32767,267,32767,175,32767,32767,32767,
+246,32767,32767,32767,32767,32767,32767,109,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,324,32767,
+32767,32767,32767,32767,161,32767,21,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,11,32767,32767,32767,32767,32767,32767,32767,
+194,32767,32767,32767,32767,32767,32767,32767,32767,332,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,364,342,32767,
+32767,32767,32767,32767,32767,193,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,373,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,212,32767,32767,32767,32,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,54,
+67,32767,32767,32767,32767,32767,32767,32767,32767,287,32767,32767,
+32767,32767,32767,51,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,273,219,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,261,32767,32767,32767,32767,
+32767,123,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,198,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,233,32767,32767,32767,32767,32767,32767,32767,338,32767,32767,
+32767,32767,32767,32767,32767,236,32767,32767,32767,310,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,232,32767,32767,32767,32767,135,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,65,32767,32767,150,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,2,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,378,32767,32767,32767,32767,32767,107,32767,32767,32767,32767,
+32767,32767,32767,335,32767,358,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,188,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+254,32767,32767,146,32767,32767,32767,32767,32767,153,33,32767,
+32767,32767,32767,32767,32767,32767,242,32767,32767,32767,32767,32767,
+32767,32767,32767,226,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,167,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,104,32767,32767,
+32767,32767,32767,32767,32767,195,37,32767,32767,253,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,88,32767,32767,32767,32767,154,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,300,32767,32767,32767,330,314,326,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,259,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,134,32767,32767,32767,32767,341,
+32767,32767,32767,32767,32767,32767,281,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,316,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,22,32767,32767,32767,32767,32767,
+32767,32767,268,32767,32767,144,32767,32767,32767,32767,32767,32767,
+32767,239,165,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,200,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,351,87,32767,32767,255,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,180,32767,32767,32767,32767,32767,10,24,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,376,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,230,32767,32767,32767,32767,32767,303,44,217,
+32767,32767,32767,32767,32767,32767,32767,32767,317,32767,32767,32767,
+266,32767,58,32767,84,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,181,32767,381,32767,296,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,40,32767,32767,32767,32767,32767,133,196,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,263,32767,
+32767,32767,32767,32767,32767,182,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,28,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,307,32767,32767,
+32767,32767,3,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+174,298,32767,32767,32767,32767,362,32767,32767,32767,151,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,99,32767,112,
+32767,32767,15,32767,32767,32767,32767,32767,32767,32767,32767,129,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,76,32767,32767,32767,32767,93,32767,337,32767,32767,
+356,32767,32767,32767,328,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,91,32767,250,32767,32767,32767,32767,
+32767,32767,32767,32767,205,32767,32767,32767,32767,32767,32767,32767,
+32767,368,32767,1,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,38,32767,203,32767,176,32767,32767,32767,32767,
+32767,32767,208,32767,32767,32767,32767,32767,32767,32767,320,32767,
+156,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,277,32767,32767,32767,32767,32767,32767,
+32767,30,32767,32767,344,32767,32767,32767,32767,383,32767,32767,
+155,32767,32767,119,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,211,43,32767,32767,32767,32767,32767,141,32767,158,32767,
+32767,32767,32767,32767,283,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,280,32767,120,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,35,32767,32767,32767,32767,32767,347,32767,32767,
+32767,32767,318,32767,32767,32767,235,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,262,32767,32767,32767,32767,45,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,305,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,278,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,238,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,7,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,122,32767,19,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,288,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,206,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,139,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,56,32767,32767,32767,32767,106,32767,77,32767,32767,32767,
+32767,101,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,379,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,4,32767,32767,62,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,201,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,163,32767,32767,
+98,32767,32767,32767,32767,32767,32767,162,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,192,82,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,340,32767,32767,32767,145,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,184,32767,32767,32767,32767,32767,32767,173,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,301,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,149,32767,32767,32767,32767,32767,32767,32767,32767,279,32767,
+142,32767,32767,294,32767,32767,32767,32767,32767,32767,32767,333,
+32767,32767,32767,32767,32767,117,32767,32767,69,32767,32767,96,
+32767,32767,32767,286,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,73,32767,32767,32767,32767,
+32767,103,32767,164,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+92,32767,32767,32767,32767,32767,221,272,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,25,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,311,
+225,32767,207,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,295,32767,108,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,290,384,32767,32767,32767,32767,
+32767,32767,32767,32767,80,32767,346,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,366,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,128,32767,32767,
+32767,32767,32767,83,243,32767,32767,32767,270,32767,32767,118,
+32767,32767,249,32767,32767,241,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,229,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,86,32767,32767,260,50,32767,32767,227,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,23,32767,32767,32767,32767,32767,32767,309,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+371,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,114,32767,32767,32767,32767,32767,32767,
+365,13,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,352,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,178,289,32767,32767,32767,32767,32767,32767,
+32767,32767,81,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,60,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,105,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+168,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,350,32767,32767,32767,32767,
+276,32767,32767,32767,32767,32767,32767,32767,199,59,32767,32767,
+32767,32767,32767,32767,32767,322,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,339,32767,32767,32767,32767,
+32767,32767,32767,94,32767,32767,228,32767,32767,32767,32767,293,
+32767,32767,32767,55,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,244,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,66,32767,32767,32767,32767,258,357,32767,32767,32767,
+32767,8,32767,32767,32767,12,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,124,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+111,32767,32767,32767,32767,32767,63,32767,32767,32767,95,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,329,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,159,32767,32767,32767,32767,
+215,32767,32767,274,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,85,32767,6,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,312,113,32767,32767,32767,78,
+32767,323,18,32767,32767,32767,32767,32767,32767,369,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,90,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+325,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+210,32767,32767,32767,32767,32767,9,32767,32767,121,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,319,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,220,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,39,32767,32767,
+271,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,234,
+32767,32767,32767,367,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,363,0,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+204,177,32767,32767,32767,32767,32767,32767,32767,32767,148,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,284,252,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,222,32767,75,32767,32767,32767,32767,292,
+32767,32767,32767,32767,32767,32767,172,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,360,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,138,32767,32767,380,32767,359,32767,
+32767,32767,32767,32767,32767,79,32767,32767,32767,32767,248,32767,
+32767,32767,32767,32767,32767,32767,147,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,327,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,299,32767,32767,32767,32767,72,32767,32767,32767,
+32767,240,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+343,32767,32767,32767,32767,32767,137,32767,32767,32767,32767,32767,
+32767,32767,32767,130,32767,32767,32767,32767,32767,32767,32767,131,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,57,32767,5,32767,32767,32767,
+32767,32767,32767,291,32767,32767,32767,32767,32767,213,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,375,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,68,
+32767,32767,32767,32767,64,32767,32767,32767,32767,32767,32767,171,
+32767,32767,32767,49,32767,32767,32767,32767,32767,48,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,275,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,345,331,32767,32767,32767,32767,32767,157,32767,32767,32767,
+32767,32767,32767,32767,32767,190,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,74,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+334,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,179,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,264,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,53,32767,32767,
+32767,32767,32767,32767,209,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,245,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,61,32767,
+52,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,186,32767,41,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+70,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,247,32767,32767,32767,32767,136,36,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,31,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,336,32767,32767,32767,265,191,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,127,32767,32767,32767,32767,32767,32767,
+321,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,116,32767,32767,32767,32767,32767,32767,26,32767,32767,
+32767,32767,32767,32767,32767,32767,269,32767,32767,32767,32767,32767,
+100,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,183,34,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,372,32767,32767,32767,32767,32767,
+308,32767,32767,285,32767,32767,32767,32767,377,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,257,32767,32767,32767,32767,32767,97,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,89,32767,32767,302,160,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,170,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,110,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,16,32767,214,71,32767,32767,32767,
+32767,32767,32767,197,32767,32767,32767,32767,32767,32767,32767,17,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+237,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,187,32767,218,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,304,32767,32767,32767,32767,32767,32767,32767,32767,185,32767,
+348,32767,32767,32767,231,32767,32767,32767,32767,32767,251,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+32767,132,32767,32767,32767,32767,32767,32767,32767,115,32767,32767,
+32767,29,32767,32767,32767,32767,32767,32767,32767,32767,32767,47,
+32767,32767,32767,32767,32767
+};
+
+
+/* t1= 45205 t2=3702303 type= 0 */
+
+inline SYMBOL *get_hash_symbol(const char *s,unsigned int length,bool function)
+{
+ ulong idx = 2003+char_table[(uchar) *s];
+ SYMBOL *sim;
+ const char *start=s;
+ int i=unique_length[(uchar) *s++];
+ if (i > (int) length) i=(int) length;
+ while (--i > 0)
+ idx= (idx ^ (char_table[(uchar) *s++] + (idx << 7)));
+ idx=my_function_table[(idx & 8388607) % 4133];
+ if (idx >= 262)
+ {
+ if (!function || idx >= 32767) return (SYMBOL*) 0;
+ sim=sql_functions + (idx - 262);
+ }
+ else
+ sim=symbols + idx;
+ if ((length != sim->length) || lex_casecmp(start,sim->name,length))
+ return (SYMBOL *)0;
+ return sim;
+}
diff --git a/sql/Attic/mini_client.c b/sql/Attic/mini_client.c
new file mode 100644
index 00000000000..56a6de14742
--- /dev/null
+++ b/sql/Attic/mini_client.c
@@ -0,0 +1,783 @@
+/* Copyright Abandoned 1996 TCX DataKonsult AB & Monty Program KB & Detron HB
+ This file is public domain and comes with NO WARRANTY of any kind */
+
+/*
+ mini MySQL client to be included into the server to do server to server
+ commincation by Sasha Pachev
+
+ Note: all file-global symbols must begin with mc_ , even the static ones, just
+ in case we decide to make them external at some point
+ */
+
+#define DONT_USE_RAID
+#if defined(__WIN32__) || defined(WIN32)
+#include <winsock.h>
+#include <odbcinst.h>
+#endif
+#include <global.h>
+#include <my_sys.h>
+#include <mysys_err.h>
+#include <m_string.h>
+#include <m_ctype.h>
+#include "mysql.h"
+#include "mini_client.h"
+#include "mysql_version.h"
+#include "mysqld_error.h"
+#include "errmsg.h"
+#include <violite.h>
+#include <sys/stat.h>
+#include <signal.h>
+#ifdef HAVE_PWD_H
+#include <pwd.h>
+#endif
+#if !defined(MSDOS) && !defined(__WIN32__)
+#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
+#if defined(THREAD) && !defined(__WIN32__)
+#include <my_pthread.h> /* because of signal() */
+#endif
+#ifndef INADDR_NONE
+#define INADDR_NONE -1
+#endif
+
+
+static 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);
+
+
+#define CLIENT_CAPABILITIES (CLIENT_LONG_PASSWORD | CLIENT_LONG_FLAG | CLIENT_LOCAL_FILES)
+
+#if defined(MSDOS) || defined(__WIN32__)
+#define ERRNO WSAGetLastError()
+#define perror(A)
+#else
+#include <sys/errno.h>
+#define ERRNO errno
+#define SOCKET_ERROR -1
+#define closesocket(A) close(A)
+#endif
+
+#ifdef __WIN32__
+static my_bool is_NT(void)
+{
+ char *os=getenv("OS");
+ return (os && !strcmp(os, "Windows_NT")) ? 1 : 0;
+}
+#endif
+
+/*
+** Create a named pipe connection
+*/
+
+#ifdef __WIN32__
+
+HANDLE create_named_pipe(NET *net, uint connect_timeout, char **arg_host,
+ char **arg_unix_socket)
+{
+ HANDLE hPipe=INVALID_HANDLE_VALUE;
+ char szPipeName [ 257 ];
+ DWORD dwMode;
+ int i;
+ my_bool testing_named_pipes=0;
+ char *host= *arg_host, *unix_socket= *arg_unix_socket;
+
+ if (!host || !strcmp(host,LOCAL_HOST))
+ host=LOCAL_HOST_NAMEDPIPE;
+
+ sprintf( szPipeName, "\\\\%s\\pipe\\%s", host, unix_socket);
+ DBUG_PRINT("info",("Server name: '%s'. Named Pipe: %s",
+ host, unix_socket));
+
+ for (i=0 ; i < 100 ; i++) /* Don't retry forever */
+ {
+ if ((hPipe = CreateFile(szPipeName,
+ GENERIC_READ | GENERIC_WRITE,
+ 0,
+ NULL,
+ OPEN_EXISTING,
+ 0,
+ NULL )) != INVALID_HANDLE_VALUE)
+ break;
+ if (GetLastError() != ERROR_PIPE_BUSY)
+ {
+ net->last_errno=CR_NAMEDPIPEOPEN_ERROR;
+ sprintf(net->last_error,ER(net->last_errno),host, unix_socket,
+ (ulong) GetLastError());
+ return INVALID_HANDLE_VALUE;
+ }
+ /* wait for for an other instance */
+ if (! WaitNamedPipe(szPipeName, connect_timeout*1000) )
+ {
+ net->last_errno=CR_NAMEDPIPEWAIT_ERROR;
+ sprintf(net->last_error,ER(net->last_errno),host, unix_socket,
+ (ulong) GetLastError());
+ return INVALID_HANDLE_VALUE;
+ }
+ }
+ if (hPipe == INVALID_HANDLE_VALUE)
+ {
+ net->last_errno=CR_NAMEDPIPEOPEN_ERROR;
+ sprintf(net->last_error,ER(net->last_errno),host, unix_socket,
+ (ulong) GetLastError());
+ return INVALID_HANDLE_VALUE;
+ }
+ dwMode = PIPE_READMODE_BYTE | PIPE_WAIT;
+ if ( !SetNamedPipeHandleState(hPipe, &dwMode, NULL, NULL) )
+ {
+ CloseHandle( hPipe );
+ net->last_errno=CR_NAMEDPIPESETSTATE_ERROR;
+ sprintf(net->last_error,ER(net->last_errno),host, unix_socket,
+ (ulong) GetLastError());
+ return INVALID_HANDLE_VALUE;
+ }
+ *arg_host=host ; *arg_unix_socket=unix_socket; /* connect arg */
+ return (hPipe);
+}
+#endif
+
+
+/****************************************************************************
+** Init MySQL structure or allocate one
+****************************************************************************/
+
+MYSQL * STDCALL
+mc_mysql_init(MYSQL *mysql)
+{
+ 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)));
+#ifdef __WIN32__
+ mysql->options.connect_timeout=20;
+#endif
+ return mysql;
+}
+
+/**************************************************************************
+** Shut down connection
+**************************************************************************/
+
+static void
+mc_end_server(MYSQL *mysql)
+{
+ DBUG_ENTER("mc_end_server");
+ if (mysql->net.vio != 0)
+ {
+ DBUG_PRINT("info",("Net: %s", vio_description(mysql->net.vio)));
+ vio_delete(mysql->net.vio);
+ mysql->net.vio= 0; /* Marker */
+ }
+ net_end(&mysql->net);
+ mc_free_old_query(mysql);
+ DBUG_VOID_RETURN;
+}
+
+static void mc_free_old_query(MYSQL *mysql)
+{
+ DBUG_ENTER("mc_free_old_query");
+ if (mysql->fields)
+ free_root(&mysql->field_alloc);
+ init_alloc_root(&mysql->field_alloc,8192); /* Assume rowlength < 8192 */
+ mysql->fields=0;
+ mysql->field_count=0; /* For API */
+ DBUG_VOID_RETURN;
+}
+
+
+/****************************************************************************
+* A modified version of connect(). mc_sock_connect() 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,
+* mc_sock_connect() will behave exactly like connect().
+*
+* Base version coded by Steve Bernacki, Jr. <steve@navinet.net>
+*****************************************************************************/
+
+static int mc_sock_connect(File s, const struct sockaddr *name, uint namelen, uint to)
+{
+#if defined(__WIN32__)
+ return connect(s, (struct sockaddr*) name, namelen);
+#else
+ int flags, res, s_err;
+ size_socket s_err_size = sizeof(uint);
+ fd_set sfds;
+ struct timeval tv;
+
+ /* If they passed us a timeout of zero, we should behave
+ * exactly like the normal connect() call does.
+ */
+
+ if (to == 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);
+ tv.tv_sec = (long) to;
+ tv.tv_usec = 0;
+ res = select(s+1, NULL, &sfds, NULL, &tv);
+ if (res <= 0) /* Never became writable */
+ 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 suceed */
+ errno = s_err;
+ return(-1); /* but return an error... */
+ }
+ return(0); /* It's all good! */
+#endif
+}
+
+/*****************************************************************************
+** read a packet from server. Give error message if socket was down
+** or packet is an error message
+*****************************************************************************/
+
+uint STDCALL
+mc_net_safe_read(MYSQL *mysql)
+{
+ NET *net= &mysql->net;
+ uint len=0;
+
+ if (net->vio != 0)
+ len=my_net_read(net);
+
+ if (len == packet_error || len == 0)
+ {
+ DBUG_PRINT("error",("Wrong connection or packet. fd: %s len: %d",
+ vio_description(net->vio),len));
+ if(errno != EINTR)
+ {
+ mc_end_server(mysql);
+ net->last_errno=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;
+ if(!net->last_errno)
+ net->last_errno = CR_UNKNOWN_ERROR;
+ }
+ 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;
+}
+
+
+char * STDCALL mc_mysql_error(MYSQL *mysql)
+{
+ return (mysql)->net.last_error;
+}
+
+my_bool STDCALL mc_mysql_reconnect(MYSQL *mysql)
+{
+ MYSQL tmp_mysql;
+ DBUG_ENTER("mc_mysql_reconnect");
+
+ mc_mysql_init(&tmp_mysql);
+ tmp_mysql.options=mysql->options;
+ if (!mc_mysql_connect(&tmp_mysql,mysql->host,mysql->user,mysql->passwd,
+ mysql->db, mysql->port, mysql->unix_socket,
+ mysql->client_flag))
+ DBUG_RETURN(1);
+ tmp_mysql.free_me=mysql->free_me;
+ mysql->free_me=0;
+ bzero((char*) &mysql->options,sizeof(&mysql->options));
+ mc_mysql_close(mysql);
+ *mysql=tmp_mysql;
+ net_clear(&mysql->net);
+ mysql->affected_rows= ~(my_ulonglong) 0;
+ DBUG_RETURN(0);
+}
+
+
+
+int STDCALL
+mc_simple_command(MYSQL *mysql,enum enum_server_command command, const char *arg,
+ uint length, my_bool skipp_check)
+{
+ NET *net= &mysql->net;
+ int result= -1;
+
+ if (mysql->net.vio == 0)
+ { /* Do reconnect if possible */
+ if (mc_mysql_reconnect(mysql))
+ {
+ net->last_errno=CR_SERVER_GONE_ERROR;
+ strmov(net->last_error,ER(net->last_errno));
+ goto end;
+ }
+ }
+ if (mysql->status != MYSQL_STATUS_READY)
+ {
+ strmov(net->last_error,ER(mysql->net.last_errno=CR_COMMANDS_OUT_OF_SYNC));
+ goto end;
+ }
+
+ mysql->net.last_error[0]=0;
+ mysql->net.last_errno=0;
+ mysql->info=0;
+ mysql->affected_rows= ~(my_ulonglong) 0;
+ net_clear(net); /* Clear receive buffer */
+ if (!arg)
+ arg="";
+
+ if (net_write_command(net,(uchar) command,arg,
+ length ? length :strlen(arg)))
+ {
+ DBUG_PRINT("error",("Can't send command to server. Error: %d",errno));
+ mc_end_server(mysql);
+ if (mc_mysql_reconnect(mysql) ||
+ net_write_command(net,(uchar) command,arg,
+ length ? length :strlen(arg)))
+ {
+ net->last_errno=CR_SERVER_GONE_ERROR;
+ strmov(net->last_error,ER(net->last_errno));
+ goto end;
+ }
+ }
+ result=0;
+ if (!skipp_check)
+ result= ((mysql->packet_length=mc_net_safe_read(mysql)) == packet_error ?
+ -1 : 0);
+ end:
+ return result;
+}
+
+
+MYSQL * STDCALL
+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)
+{
+ char buff[100],*end,*host_info;
+ int sock;
+ ulong ip_addr;
+ struct sockaddr_in sock_addr;
+ uint pkt_length;
+ NET *net= &mysql->net;
+#ifdef __WIN32__
+ HANDLE hPipe=INVALID_HANDLE_VALUE;
+#endif
+#ifdef HAVE_SYS_UN_H
+ struct sockaddr_un UNIXaddr;
+#endif
+ DBUG_ENTER("mysql_real_connect");
+
+ DBUG_PRINT("enter",("host: %s db: %s user: %s",
+ host ? host : "(Null)",
+ db ? db : "(Null)",
+ user ? user : "(Null)"));
+
+ bzero((char*) &mysql->options,sizeof(mysql->options));
+ net->vio = 0; /* If something goes wrong */
+ mysql->charset=default_charset_info; /* Set character set */
+ if (!port)
+ port = MYSQL_PORT; /* Should always be set by mysqld */
+ if (!unix_socket)
+ unix_socket=MYSQL_UNIX_ADDR;
+
+ mysql->reconnect=1; /* Reconnect as default */
+
+ /*
+ ** Grab a socket and connect it to the server
+ */
+
+#if defined(HAVE_SYS_UN_H)
+ if (!host || !strcmp(host,LOCAL_HOST))
+ {
+ host=LOCAL_HOST;
+ host_info=(char*) ER(CR_LOCALHOST_CONNECTION);
+ DBUG_PRINT("info",("Using UNIX sock '%s'",unix_socket));
+ if ((sock = socket(AF_UNIX,SOCK_STREAM,0)) == SOCKET_ERROR)
+ {
+ net->last_errno=CR_SOCKET_CREATE_ERROR;
+ sprintf(net->last_error,ER(net->last_errno),ERRNO);
+ goto error;
+ }
+ net->vio = vio_new(sock, VIO_TYPE_SOCKET, TRUE);
+ bzero((char*) &UNIXaddr,sizeof(UNIXaddr));
+ UNIXaddr.sun_family = AF_UNIX;
+ strmov(UNIXaddr.sun_path, unix_socket);
+ if (mc_sock_connect(sock,(struct sockaddr *) &UNIXaddr, sizeof(UNIXaddr),
+ mysql->options.connect_timeout) <0)
+ {
+ DBUG_PRINT("error",("Got error %d on connect to local server",ERRNO));
+ net->last_errno=CR_CONNECTION_ERROR;
+ sprintf(net->last_error,ER(net->last_errno),unix_socket,ERRNO);
+ goto error;
+ }
+ }
+ else
+#elif defined(__WIN32__)
+ {
+ if ((unix_socket ||
+ !host && is_NT() ||
+ host && !strcmp(host,LOCAL_HOST_NAMEDPIPE) ||
+ mysql->options.named_pipe || !have_tcpip))
+ {
+ sock=0;
+ if ((hPipe=create_named_pipe(net, mysql->options.connect_timeout,
+ (char**) &host, (char**) &unix_socket)) ==
+ INVALID_HANDLE_VALUE)
+ {
+ DBUG_PRINT("error",
+ ("host: '%s' socket: '%s' named_pipe: %d have_tcpip: %d",
+ host ? host : "<null>",
+ unix_socket ? unix_socket : "<null>",
+ (int) mysql->options.named_pipe,
+ (int) have_tcpip));
+ if (mysql->options.named_pipe ||
+ (host && !strcmp(host,LOCAL_HOST_NAMEDPIPE)) ||
+ (unix_socket && !strcmp(unix_socket,MYSQL_NAMEDPIPE)))
+ goto error; /* User only requested named pipes */
+ /* Try also with TCP/IP */
+ }
+ else
+ {
+ net->vio=vio_new_win32pipe(hPipe);
+ sprintf(host_info=buff, ER(CR_NAMEDPIPE_CONNECTION), host,
+ unix_socket);
+ }
+ }
+ }
+ if (hPipe == INVALID_HANDLE_VALUE)
+#endif
+ {
+ unix_socket=0; /* This is not used */
+ if (!host)
+ host=LOCAL_HOST;
+ sprintf(host_info=buff,ER(CR_TCP_CONNECTION),host);
+ DBUG_PRINT("info",("Server name: '%s'. TCP sock: %d", host,port));
+ if ((sock = socket(AF_INET,SOCK_STREAM,0)) == SOCKET_ERROR)
+ {
+ net->last_errno=CR_IPSOCK_ERROR;
+ sprintf(net->last_error,ER(net->last_errno),ERRNO);
+ goto error;
+ }
+ net->vio = vio_new(sock,VIO_TYPE_TCPIP,FALSE);
+ bzero((char*) &sock_addr,sizeof(sock_addr));
+ sock_addr.sin_family = AF_INET;
+
+ /*
+ ** The server name may be a host name or IP address
+ */
+
+ 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)
+ {
+ net->last_errno=CR_UNKNOWN_HOST;
+ sprintf(net->last_error, ER(CR_UNKNOWN_HOST), host, tmp_errno);
+ goto error;
+ }
+ memcpy(&sock_addr.sin_addr,hp->h_addr, (size_t) hp->h_length);
+ }
+#else
+ {
+ struct hostent *hp;
+ if (!(hp=gethostbyname(host)))
+ {
+ net->last_errno=CR_UNKNOWN_HOST;
+ sprintf(net->last_error, ER(CR_UNKNOWN_HOST), host, errno);
+ goto error;
+ }
+ memcpy(&sock_addr.sin_addr,hp->h_addr, (size_t) hp->h_length);
+ }
+#endif
+ sock_addr.sin_port = (ushort) htons((ushort) port);
+ if (mc_sock_connect(sock,(struct sockaddr *) &sock_addr, sizeof(sock_addr),
+ mysql->options.connect_timeout) <0)
+ {
+ DBUG_PRINT("error",("Got error %d on connect to '%s'",ERRNO,host));
+ net->last_errno= CR_CONN_HOST_ERROR;
+ sprintf(net->last_error ,ER(CR_CONN_HOST_ERROR), host, ERRNO);
+ goto error;
+ }
+ }
+
+ if (!net->vio || 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;
+ }
+ vio_keepalive(net->vio,TRUE);
+
+ /* Get version info */
+ mysql->protocol_version= PROTOCOL_VERSION; /* Assume this */
+ if ((pkt_length=mc_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);
+ if (pkt_length > (uint) (end+9 - (char*) net->read_pos))
+ mysql->server_capabilities=uint2korr(end+9);
+
+ /* Save connection information */
+ if (!user) user="";
+ if (!passwd) passwd="";
+ if (!my_multi_malloc(MYF(0),
+ &mysql->host_info,strlen(host_info)+1,
+ &mysql->host,strlen(host)+1,
+ &mysql->unix_socket,unix_socket ? strlen(unix_socket)+1
+ :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",
+ mysql->server_version,mysql->server_capabilities));
+
+ /* Send client information for access check */
+ client_flag|=CLIENT_CAPABILITIES;
+
+#ifdef HAVE_OPENSSL
+ if (mysql->options.use_ssl)
+ client_flag|=CLIENT_SSL;
+#endif /* HAVE_OPENSSL */
+
+ if (db)
+ client_flag|=CLIENT_CONNECT_WITH_DB;
+#ifdef HAVE_COMPRESS
+ if (mysql->server_capabilities & CLIENT_COMPRESS &&
+ (mysql->options.compress || client_flag & CLIENT_COMPRESS))
+ client_flag|=CLIENT_COMPRESS; /* We will use compression */
+ else
+#endif
+ client_flag&= ~CLIENT_COMPRESS;
+
+#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;
+ }
+#endif /* HAVE_OPENSSL */
+
+ int2store(buff,client_flag);
+ mysql->client_flag=client_flag;
+
+#ifdef HAVE_OPENSSL
+ /* Oops.. are we careful enough to not send ANY information */
+ /* without encryption? */
+ if (client_flag & CLIENT_SSL)
+ {
+ if (my_net_write(net,buff,(uint) (2)) || net_flush(net))
+ 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);
+ }
+#endif /* HAVE_OPENSSL */
+
+ int3store(buff+2,max_allowed_packet);
+ if (user && user[0])
+ strmake(buff+5,user,32);
+ else
+ {
+ user = getenv("USER");
+ if(!user) user = "mysql";
+ strmov((char*) buff+5, user );
+ }
+
+ 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));
+ }
+ if (my_net_write(net,buff,(uint) (end-buff)) || net_flush(net) ||
+ mc_net_safe_read(mysql) == packet_error)
+ goto error;
+ if (client_flag & CLIENT_COMPRESS) /* We will use compression */
+ net->compress=1;
+ DBUG_PRINT("exit",("Mysql handler: %lx",mysql));
+ DBUG_RETURN(mysql);
+
+error:
+ DBUG_PRINT("error",("message: %u (%s)",net->last_errno,net->last_error));
+ {
+ /* Free alloced memory */
+ my_bool free_me=mysql->free_me;
+ mc_end_server(mysql);
+ mysql->free_me=0;
+ mc_mysql_close(mysql);
+ mysql->free_me=free_me;
+ }
+ DBUG_RETURN(0);
+}
+
+/*************************************************************************
+** Send a QUIT to the server and close the connection
+** If handle is alloced by mysql connect free it.
+*************************************************************************/
+
+void STDCALL
+mc_mysql_close(MYSQL *mysql)
+{
+ DBUG_ENTER("mysql_close");
+ if (mysql) /* Some simple safety */
+ {
+ if (mysql->net.vio != 0)
+ {
+ mc_free_old_query(mysql);
+ mysql->status=MYSQL_STATUS_READY; /* Force command */
+ mc_simple_command(mysql,COM_QUIT,NullS,0,1);
+ mc_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));
+ /* 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;
+}
diff --git a/sql/Attic/mini_client_errors.c b/sql/Attic/mini_client_errors.c
new file mode 100644
index 00000000000..96f1f415544
--- /dev/null
+++ b/sql/Attic/mini_client_errors.c
@@ -0,0 +1,64 @@
+/* Copyright Abandoned 1997 TCX DataKonsult AB & Monty Program KB & Detron HB
+ This file is public domain and comes with NO WARRANTY of any kind */
+
+/* Error messages for MySQL clients */
+/* error messages for the demon is in share/language/errmsg.sys */
+
+#include <global.h>
+#include <my_sys.h>
+#include "errmsg.h"
+
+#ifdef GERMAN
+const char *client_errors[]=
+{
+ "Unbekannter MySQL Fehler",
+ "Kann UNIX-Socket nicht anlegen (%d)",
+ "Keine Verbindung zu lokalem MySQL Server, socket: '%-.64s' (%d)",
+ "Keine Verbindung zu MySQL Server auf %-.64s (%d)",
+ "Kann TCP/IP-Socket nicht anlegen (%d)",
+ "Unbekannter MySQL Server Host (%-.64s) (%d)",
+ "MySQL Server nicht vorhanden",
+ "Protokolle ungleich. Server Version = % d Client Version = %d",
+ "MySQL client got out of memory",
+ "Wrong host info",
+ "Localhost via UNIX socket",
+ "%s via TCP/IP",
+ "Error in server handshake",
+ "Lost connection to MySQL server during query",
+ "Commands out of sync; You can't run this command now",
+ "Verbindung ueber Named Pipe; Host: %-.64s",
+ "Kann nicht auf Named Pipe warten. Host: %-.64s pipe: %-.32s (%lu)",
+ "Kann Named Pipe nicht oeffnen. Host: %-.64s pipe: %-.32s (%lu)",
+ "Kann den Status der Named Pipe nicht setzen. Host: %-.64s pipe: %-.32s (%lu)"
+};
+
+#else /* ENGLISH */
+const char *client_errors[]=
+{
+ "Unknown MySQL error",
+ "Can't create UNIX socket (%d)",
+ "Can't connect to local MySQL server through socket '%-.64s' (%d)",
+ "Can't connect to MySQL server on '%-.64s' (%d)",
+ "Can't create TCP/IP socket (%d)",
+ "Unknown MySQL Server Host '%-.64s' (%d)",
+ "MySQL server has gone away",
+ "Protocol mismatch. Server Version = %d Client Version = %d",
+ "MySQL client run out of memory",
+ "Wrong host info",
+ "Localhost via UNIX socket",
+ "%s via TCP/IP",
+ "Error in server handshake",
+ "Lost connection to MySQL server during query",
+ "Commands out of sync; You can't run this command now",
+ "%s via named pipe",
+ "Can't wait for named pipe to host: %-.64s pipe: %-.32s (%lu)",
+ "Can't open named pipe to host: %-.64s pipe: %-.32s (%lu)",
+ "Can't set state of named pipe to host: %-.64s pipe: %-.32s (%lu)",
+};
+#endif
+
+
+void init_client_errs(void)
+{
+ errmsg[CLIENT_ERRMAP] = &client_errors[0];
+}
diff --git a/sql/Attic/mybinlogdump.cc b/sql/Attic/mybinlogdump.cc
new file mode 100644
index 00000000000..b94943c9847
--- /dev/null
+++ b/sql/Attic/mybinlogdump.cc
@@ -0,0 +1,138 @@
+
+#undef MYSQL_SERVER
+#include "log_event.h"
+#include <getopt.h>
+#include <config.h>
+
+static const char* default_dbug_option = "d:t:o,/tmp/mybinlogdump.trace";
+
+static struct option long_options[] =
+{
+ {"short-form", no_argument, 0, 's'},
+ {"offset", required_argument,0, 'o'},
+ {"help", no_argument, 0, 'h'},
+#ifndef DBUG_OFF
+ {"debug", required_argument, 0, '#'}
+#endif
+};
+
+static bool short_form = 0;
+static int offset = 0;
+
+static int parse_args(int argc, char** argv);
+static void dump_log_entries();
+static void die(char* fmt, ...);
+
+static void die(char* fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ fprintf(stderr, "ERROR: ");
+ vfprintf(stderr, fmt, args);
+ fprintf(stderr, "\n");
+ va_end(args);
+ exit(1);
+}
+
+static void usage()
+{
+ fprintf(stderr, "Usage: mybinlogdump [options] log-files\n");
+ fprintf(stderr, "Options:\n\
+ -s,--short-form - just show the queries, no extra info\n\
+ -o,--offset=N - skip the first N entries\n\
+ -h,--help - this message\n");
+}
+
+static int parse_args(int *argc, char*** argv)
+{
+ int c, opt_index = 0;
+
+ while((c = getopt_long(*argc, *argv, "so:#:h", long_options,
+ &opt_index)) != EOF)
+ {
+ switch(c)
+ {
+#ifndef DBUG_OFF
+ case '#':
+ DBUG_PUSH(optarg ? optarg : default_dbug_option);
+ break;
+#endif
+ case 's':
+ short_form = 1;
+ break;
+
+ case 'o':
+ offset = atoi(optarg);
+ break;
+
+ case 'h':
+ default:
+ usage();
+ exit(0);
+
+ }
+ }
+
+ (*argc)-=optind;
+ (*argv)+=optind;
+
+
+ return 0;
+}
+
+
+static void dump_log_entries(const char* logname)
+{
+ FILE* file;
+ int rec_count = 0;
+
+ if(logname && logname[0] != '-')
+ file = my_fopen(logname, O_RDONLY, MYF(MY_WME));
+ else
+ file = stdin;
+
+ if(!file)
+ die("Could not open log file %s", logname);
+ while(1)
+ {
+ Log_event* ev = Log_event::read_log_event(file);
+ if(!ev)
+ if(!feof(file))
+ die("Could not read entry at offset %ld : Error in log format or \
+read error",
+ my_ftell(file, MYF(MY_WME)));
+ else
+ break;
+
+ if(rec_count >= offset)
+ ev->print(stdout, short_form);
+ rec_count++;
+ delete ev;
+ }
+
+ my_fclose(file, MYF(MY_WME));
+}
+
+int main(int argc, char** argv)
+{
+ MY_INIT(argv[0]);
+ parse_args(&argc, (char***)&argv);
+
+ if(!argc)
+ {
+ usage();
+ return -1;
+ }
+
+ while(--argc >= 0)
+ {
+ dump_log_entries(*(argv++));
+ }
+
+ return 0;
+}
+
+
+
+
+
diff --git a/sql/Attic/net_serv.c b/sql/Attic/net_serv.c
new file mode 100644
index 00000000000..8f5ba20664a
--- /dev/null
+++ b/sql/Attic/net_serv.c
@@ -0,0 +1,616 @@
+/* Copyright Abandoned 1996 TCX DataKonsult AB & Monty Program KB & Detron HB
+ This file is public domain and comes with NO WARRANTY of any kind */
+
+/* Write and read of logical packets to/from socket
+** Writes are cached into net_buffer_length big packets.
+** Read packets are reallocated dynamicly when reading big packets.
+** Each logical packet has the following pre-info:
+** 3 byte length & 1 byte package-number.
+*/
+
+#ifdef _WIN32
+#include <winsock.h>
+#endif
+#include <global.h>
+#include <violite.h>
+#include <my_sys.h>
+#include <m_string.h>
+#include "mysql.h"
+#include <signal.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <violite.h>
+
+#if !defined(__WIN32__) && !defined(MSDOS)
+#include <sys/socket.h>
+#endif
+#if !defined(MSDOS) && !defined(__WIN32__) && !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
+#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
+typedef my_bool thr_alarm_t;
+#define thr_alarm_init(A) (*A)=0
+#define thr_alarm_in_use(A) (A)
+#define thr_end_alarm(A)
+#define thr_alarm(A,B) local_thr_alarm((A),(B))
+static inline int local_thr_alarm(my_bool *A,int B __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 pthread_mutex_t LOCK_bytes_sent , LOCK_bytes_received;
+#else
+#undef thread_safe_add
+#define thread_safe_add(A,B,C)
+#endif
+
+/*
+** 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.
+*/
+
+#ifdef MYSQL_SERVER
+ulong max_allowed_packet=65536;
+extern uint test_flags;
+#else
+ulong max_allowed_packet=16*1024*1024L;
+#endif
+ulong net_buffer_length=8192; /* Default length. Enlarged if necessary */
+
+#define TEST_BLOCKING 8
+static int net_write_buff(NET *net,const char *packet,uint 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))))
+ return 1;
+ if (net_buffer_length > max_allowed_packet)
+ max_allowed_packet=net_buffer_length;
+ net->buff_end=net->buff+(net->max_packet=net_buffer_length);
+ net->vio = vio;
+ net->error=net->return_errno=0;
+ net->timeout=NET_READ_TIMEOUT; /* Timeout for read */
+ net->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;
+
+ if (vio != 0) /* If real connection */
+ {
+ net->fd = vio_fd(vio); /* For perl DBI/DBD */
+#if defined(MYSQL_SERVER) && !defined(___WIN32__) && !defined(__EMX__)
+ if (!(test_flags & TEST_BLOCKING))
+ vio_blocking(vio, FALSE);
+#endif
+ vio_fastsend(vio,TRUE);
+ }
+ return 0;
+}
+
+void net_end(NET *net)
+{
+ my_free((gptr) net->buff,MYF(MY_ALLOW_ZERO_PTR));
+ net->buff=0;
+}
+
+/* Realloc the packet buffer */
+
+static my_bool net_realloc(NET *net, ulong length)
+{
+ uchar *buff;
+ ulong pkt_length;
+ if (length >= max_allowed_packet)
+ {
+ DBUG_PRINT("error",("Packet too large (%ld)", length));
+#ifdef MYSQL_SERVER
+ sql_print_error("Packet too large (%ld)\n", length);
+#else
+ fprintf(stderr,"Packet too large (%ld)\n", length);
+#endif
+ net->error=1;
+#ifdef MYSQL_SERVER
+ net->last_errno=ER_NET_PACKET_TOO_LARGE;
+#endif
+ return 1;
+ }
+ pkt_length = (length+IO_SIZE-1) & ~(IO_SIZE-1);
+ if (!(buff=(uchar*) my_realloc((char*) net->buff, pkt_length, MYF(MY_WME))))
+ {
+ net->error=1;
+#ifdef MYSQL_SERVER
+ net->last_errno=ER_OUT_OF_RESOURCES;
+#endif
+ return 1;
+ }
+ net->buff=net->write_pos=buff;
+ net->buff_end=buff+(net->max_packet=pkt_length);
+ return 0;
+}
+
+ /* Remove unwanted characters from connection */
+
+void net_clear(NET *net)
+{
+#ifndef EXTRA_DEBUG
+ int count;
+ 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)
+ 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->write_pos=net->buff;
+}
+
+ /* Flush write_buffer if not empty. */
+
+int net_flush(NET *net)
+{
+ int error=0;
+ DBUG_ENTER("net_flush");
+ if (net->buff != net->write_pos)
+ {
+ error=net_real_write(net,(char*) net->buff,
+ (uint) (net->write_pos - net->buff));
+ net->write_pos=net->buff;
+ }
+ DBUG_RETURN(error);
+}
+
+
+/*****************************************************************************
+** 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!
+*/
+
+int
+my_net_write(NET *net,const char *packet,ulong len)
+{
+ uchar buff[NET_HEADER_SIZE];
+ int3store(buff,len);
+ buff[3]= (net->compress) ? 0 : (uchar) (net->pkt_nr++);
+ if (net_write_buff(net,(char*) buff,NET_HEADER_SIZE))
+ return 1;
+ return net_write_buff(net,packet,len);
+}
+
+int
+net_write_command(NET *net,uchar command,const char *packet,ulong len)
+{
+ uchar buff[NET_HEADER_SIZE+1];
+ uint length=len+1; /* 1 extra byte for command */
+
+ 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));
+}
+
+
+static int
+net_write_buff(NET *net,const char *packet,uint len)
+{
+ uint left_length=(uint) (net->buff_end - net->write_pos);
+
+ while (len > left_length)
+ {
+ memcpy((char*) net->write_pos,packet,left_length);
+ if (net_real_write(net,(char*) net->buff,net->max_packet))
+ return 1;
+ net->write_pos=net->buff;
+ packet+=left_length;
+ len-=left_length;
+ left_length=net->max_packet;
+ }
+ memcpy((char*) net->write_pos,packet,len);
+ net->write_pos+=len;
+ return 0;
+}
+
+/* Read and write using timeouts */
+
+int
+net_real_write(NET *net,const char *packet,ulong len)
+{
+ int length;
+ char *pos,*end;
+ thr_alarm_t alarmed;
+ uint retry_count=0;
+ my_bool net_blocking = vio_is_blocking(net->vio);
+ DBUG_ENTER("net_real_write");
+
+ net->reading_or_writing=2;
+#ifdef HAVE_COMPRESS
+ if (net->compress)
+ {
+ 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))))
+ {
+#ifdef MYSQL_SERVER
+ net->last_errno=ER_OUT_OF_RESOURCES;
+ net->error=1;
+#endif
+ net->reading_or_writing=0;
+ DBUG_RETURN(1);
+ }
+ memcpy(b+header_length,packet,len);
+
+ if (my_compress((byte*) b+header_length,&len,&complen))
+ {
+ DBUG_PRINT("warning",
+ ("Compression error; Continuing without compression"));
+ complen=0;
+ }
+ int3store(&b[NET_HEADER_SIZE],complen);
+ int3store(b,len);
+ b[3]=(uchar) (net->pkt_nr++);
+ len+= header_length;
+ packet= (char*) b;
+ }
+#endif /* HAVE_COMPRESS */
+
+ /* DBUG_DUMP("net",packet,len); */
+#ifdef MYSQL_SERVER
+ thr_alarm_init(&alarmed);
+ if (net_blocking)
+ thr_alarm(&alarmed,NET_WRITE_TIMEOUT);
+#else
+ alarmed=0;
+#endif /* MYSQL_SERVER */
+
+ pos=(char*) packet; end=pos+len;
+ while (pos != end)
+ {
+ if ((int) (length=vio_write(net->vio,pos,(size_t) (end-pos))) <= 0)
+ {
+ my_bool interrupted = vio_should_retry(net->vio);
+#if (!defined(__WIN32__) && !defined(__EMX__))
+ if ((interrupted || length==0) && !thr_alarm_in_use(alarmed))
+ {
+ if (!thr_alarm(&alarmed,NET_WRITE_TIMEOUT))
+ { /* Always true for client */
+ if (!vio_is_blocking(net->vio))
+ {
+ while (vio_blocking(net->vio, TRUE) < 0)
+ {
+ if (vio_should_retry(net->vio) && retry_count++ < RETRY_COUNT)
+ continue;
+#ifdef EXTRA_DEBUG
+ fprintf(stderr,
+ "%s: my_net_write: fcntl returned error %d, aborting thread\n",
+ my_progname,vio_errno(net->vio));
+#endif /* EXTRA_DEBUG */
+ net->error=1; /* Close socket */
+ goto end;
+ }
+ }
+ retry_count=0;
+ continue;
+ }
+ }
+ else
+#endif /* (!defined(__WIN32__) && !defined(__EMX__)) */
+ if (thr_alarm_in_use(alarmed) && !thr_got_alarm(alarmed) &&
+ interrupted)
+ {
+ if (retry_count++ < RETRY_COUNT)
+ continue;
+#ifdef EXTRA_DEBUG
+ fprintf(stderr, "%s: write looped, aborting thread\n",
+ my_progname);
+#endif /* EXTRA_DEBUG */
+ }
+#if defined(THREAD_SAFE_CLIENT) && !defined(MYSQL_SERVER)
+ if (vio_errno(net->vio) == EINTR)
+ {
+ DBUG_PRINT("warning",("Interrupted write. Retrying..."));
+ continue;
+ }
+#endif /* defined(THREAD_SAFE_CLIENT) && !defined(MYSQL_SERVER) */
+ net->error=1; /* Close socket */
+#ifdef MYSQL_SERVER
+ net->last_errno= (interrupted ? ER_NET_WRITE_INTERRUPTED :
+ ER_NET_ERROR_ON_WRITE);
+#endif /* MYSQL_SERVER */
+ break;
+ }
+ pos+=length;
+ thread_safe_add(bytes_sent,length,&LOCK_bytes_sent);
+ }
+#ifndef __WIN32__
+ end:
+#endif
+#ifdef HAVE_COMPRESS
+ if (net->compress)
+ my_free((char*) packet,MYF(0));
+#endif
+ if (thr_alarm_in_use(alarmed))
+ {
+ thr_end_alarm(&alarmed);
+ vio_blocking(net->vio, net_blocking);
+ }
+ net->reading_or_writing=0;
+ DBUG_RETURN(((int) (pos != end)));
+}
+
+
+/*****************************************************************************
+** Read something from server/clinet
+*****************************************************************************/
+
+
+static uint
+my_real_read(NET *net, ulong *complen)
+{
+ uchar *pos;
+ long length;
+ uint i,retry_count=0;
+ ulong len=packet_error;
+ thr_alarm_t alarmed;
+ my_bool net_blocking=vio_is_blocking(net->vio);
+ ulong 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
+ if (net_blocking)
+ thr_alarm(&alarmed,net->timeout);
+#endif /* MYSQL_SERVER */
+
+ pos = net->buff + net->where_b; /* net->packet -4 */
+ for (i=0 ; i < 2 ; i++)
+ {
+ while (remain > 0)
+ {
+ /* First read is done with non blocking mode */
+ if ((int) (length=vio_read(net->vio,(char*) pos,remain)) <= 0L)
+ {
+ my_bool interrupted = vio_should_retry(net->vio);
+
+ DBUG_PRINT("info",("vio_read returned %d, errno: %d",
+ length, vio_errno(net->vio)));
+#if (!defined(__WIN32__) && !defined(__EMX__)) || !defined(MYSQL_SERVER)
+ /*
+ We got an error that there was no data on the socket. We now set up
+ an alarm to not 'read forever', change the socket to non blocking
+ mode and try again
+ */
+ if ((interrupted || length == 0) && !thr_alarm_in_use(alarmed))
+ {
+ if (!thr_alarm(&alarmed,net->timeout)) /* Don't wait too long */
+ {
+ if (!vio_is_blocking(net->vio))
+ {
+ while (vio_blocking(net->vio,TRUE) < 0)
+ {
+ if (vio_should_retry(net->vio) &&
+ retry_count++ < RETRY_COUNT)
+ continue;
+ DBUG_PRINT("error",
+ ("fcntl returned error %d, aborting thread",
+ vio_errno(net->vio)));
+#ifdef EXTRA_DEBUG
+ fprintf(stderr,
+ "%s: read: fcntl returned error %d, aborting thread\n",
+ my_progname,vio_errno(net->vio));
+#endif /* EXTRA_DEBUG */
+ len= packet_error;
+ net->error=1; /* Close socket */
+#ifdef MYSQL_SERVER
+ net->last_errno=ER_NET_FCNTL_ERROR;
+#endif
+ goto end;
+ }
+ }
+ retry_count=0;
+ continue;
+ }
+ }
+#endif /* (!defined(__WIN32__) && !defined(__EMX__)) || !defined(MYSQL_SERVER) */
+ if (thr_alarm_in_use(alarmed) && !thr_got_alarm(alarmed) &&
+ interrupted)
+ { /* Probably in MIT threads */
+ if (retry_count++ < RETRY_COUNT)
+ continue;
+#ifdef EXTRA_DEBUG
+ fprintf(stderr, "%s: read looped with error %d, aborting thread\n",
+ my_progname,vio_errno(net->vio));
+#endif /* EXTRA_DEBUG */
+ }
+#if defined(THREAD_SAFE_CLIENT) && !defined(MYSQL_SERVER)
+ if (vio_should_retry(net->vio))
+ {
+ DBUG_PRINT("warning",("Interrupted read. Retrying..."));
+ continue;
+ }
+#endif
+ DBUG_PRINT("error",("Couldn't read packet: remain: %d errno: %d length: %d alarmed: %d", remain,vio_errno(net->vio),length,alarmed));
+ len= packet_error;
+ net->error=1; /* Close socket */
+#ifdef MYSQL_SERVER
+ net->last_errno= (interrupted ? ER_NET_READ_INTERRUPTED :
+ ER_NET_READ_ERROR);
+#endif
+ goto end;
+ }
+ remain -= (ulong) length;
+ pos+= (ulong) length;
+ thread_safe_add(bytes_received,(ulong) length,&LOCK_bytes_received);
+ }
+ if (i == 0)
+ { /* First parts is packet length */
+ ulong helping;
+ if (net->buff[net->where_b + 3] != (uchar) net->pkt_nr)
+ {
+ if (net->buff[net->where_b] != (uchar) 255)
+ {
+ DBUG_PRINT("error",
+ ("Packets out of order (Found: %d, expected %d)",
+ (int) net->buff[net->where_b + 3],
+ (uint) (uchar) net->pkt_nr));
+#ifdef EXTRA_DEBUG
+ fprintf(stderr,"Packets out of order (Found: %d, expected %d)\n",
+ (int) net->buff[net->where_b + 3],
+ (uint) (uchar) net->pkt_nr);
+#endif
+ }
+ len= packet_error;
+#ifdef MYSQL_SERVER
+ net->last_errno=ER_NET_PACKETS_OUT_OF_ORDER;
+#endif
+ goto end;
+ }
+ net->pkt_nr++;
+#ifdef HAVE_COMPRESS
+ if (net->compress)
+ {
+ /* complen is > 0 if package is really compressed */
+ *complen=uint3korr(&(net->buff[net->where_b + NET_HEADER_SIZE]));
+ }
+#endif
+
+ len=uint3korr(net->buff+net->where_b);
+ 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))
+ {
+ len= packet_error; /* Return error */
+ goto end;
+ }
+ }
+ pos=net->buff + net->where_b;
+ remain = len;
+ }
+ }
+
+end:
+ if (thr_alarm_in_use(alarmed))
+ {
+ thr_end_alarm(&alarmed);
+ vio_blocking(net->vio, net_blocking);
+ }
+ net->reading_or_writing=0;
+ return(len);
+}
+
+
+uint
+my_net_read(NET *net)
+{
+ ulong len,complen;
+
+#ifdef HAVE_COMPRESS
+ if (!net->compress)
+ {
+#endif
+ len = my_real_read (net,&complen);
+ 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 (;;)
+ {
+ if (net->remain_in_buf)
+ {
+ uchar *pos = net->buff + net->buf_length - net->remain_in_buf;
+ if (net->remain_in_buf >= 4)
+ {
+ net->length = uint3korr(pos);
+ if (net->length <= net->remain_in_buf - 4)
+ {
+ /* 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 */
+ }
+ }
+ /* Move data down to read next data packet after current one */
+ if (net->buf_length != net->remain_in_buf)
+ {
+ memmove(net->buff,pos,net->remain_in_buf);
+ net->buf_length=net->remain_in_buf;
+ }
+ 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=1; /* caller will close socket */
+#ifdef MYSQL_SERVER
+ net->last_errno=ER_NET_UNCOMPRESS_ERROR;
+#endif
+ break;
+ }
+ net->buf_length+=len;
+ net->remain_in_buf+=len;
+ }
+ if (len != packet_error)
+ {
+ net->save_char= net->read_pos[len]; /* Must be saved */
+ net->read_pos[len]=0; /* Safeguard for mysql_use_result */
+ }
+ return len;
+#endif
+}
diff --git a/sql/ChangeLog b/sql/ChangeLog
new file mode 100644
index 00000000000..81ce83aa243
--- /dev/null
+++ b/sql/ChangeLog
@@ -0,0 +1,3268 @@
+2000-07-11 Michael Widenius <monty@mysql.com>
+
+* Extended safe_mysqld; Patch by Christian Hammers
+
+2000-07-04 Michael Widenius <monty@mysql.com>
+
+* Changed the update log to take the query length argument; This
+ should make the update log \0 safe.
+
+2000-06-21 Michael Widenius <monty@mysql.com>
+
+* Added net_read_timeout and net_write_timeout as startup parameters to mysqld
+
+2000-06-19 Michael Widenius <monty@mysql.com>
+
+* Changed the copyright of MySQL to GPL and LGPL.
+* Added myisampack and pack_isam to the MySQL distribution.
+
+2000-06-01 Michael Widenius <monty@mysql.com>
+
+* Added "FLUSH TABLES WITH READ LOCK" command
+
+2000-05-31 Michael Widenius <monty@mysql.com>
+
+* Added table locks to Berkeley DB.
+
+2000-05-28 Michael Widenius <monty@mysql.com>
+
+* Allow ON and USING with INNER JOIN.
+
+2000-05-23 Sasha
+
+* Fix that USE INDEX with 'PRIMARY' keys works.
+
+2000-05-20 Michael Widenius <monty@tik.pp.sci.fi>
+
+* Added symbolic links support for Win32.
+
+2000-05-19 Michael Widenius <monty@tik.pp.sci.fi>
+
+* Changed protocol to let client know if the server is in AUTOCOMMIT mode
+ and if there is a pending transaction. If there is a pending transaction
+ the client library will give an error before reconnecting to the server to
+ let the client know that the server did a rollback.
+ The protocol is still backward compatible with old clients
+* 'kill' now works on a thread that is locked on a 'write' to a dead client.
+
+2000-05-18 Michael Widenius <monty@tik.pp.sci.fi>
+
+* unlock tables before sending last packet of SELECT ... result to client.
+
+2000-05-16 Michael Widenius <monty@mysql.com>
+
+* split Item_bool_func2::compare function into individual functions to get more
+ speed.
+* Small optimizations of do_select() to get more speed.
+
+2000-05-15 Michael Widenius <monty@mysql.com>
+
+* CHECK will update the statistics for the keys.
+* Fixed bug in REPAIR TABLE when the table was used by other threads.
+
+2000-05-11 Michael Widenius <monty@mysql.com>
+
+* put CREATE TEMPORARY TABLE commands in the update log.
+* UPDATE IGNORE will not abort if an update gives a DUPLICATE_KEY error.
+* Ensure that all fn_format() or unpack_filename() is called for all
+ generated filenames.
+
+2000-05-05 Michael Widenius <monty@mysql.com>
+
+* Added timzone variable to SHOW VARIABLES.
+
+2000-05-04 Michael Widenius <monty@mysql.com>
+
+* Don't write INSERT DELAYED to update log if SQL_LOG_UPDATE=0
+
+2000-05-03 Michael Widenius <monty@mysql.com>
+
+* Fixed problem with REPLACE on HEAP tables.
+
+2000-04-26 Michael Widenius <monty@mysql.com>
+
+* Added 'Writing to net' and 'Reading from net' as 'status' to
+ mysqladmin processlist.
+
+2000-04-23 Michael Widenius <monty@mysql.com>
+
+* Added CREATE DATABASE and DROP DATABASE to the update log
+* Fixed problem when doing a GROUP BY on an enum column with MANY
+ value combinations.
+* Avoid sorting for some simple GROUP BY queries.
+
+2000-04-22 Michael Widenius <monty@mysql.com>
+
+* Fixed problems in update log when using LAST_INSERT_ID() to update
+ an table with an auto_increment key.
+* New function: 'NULLIF(expr1,expr2)'
+
+2000-04-14 Michael Widenius <monty@tik.pp.sci.fi>
+
+* UPDATE and DELETE on UNIQUE keys, where the whole key is used in the WHERE
+ part, are now faster than before.
+
+* Added optimisation to skip ORDER BY parts where the order by column
+ is a constant expression in the WHERE part. ORDER BY will also
+ be skipped if ORDER BY matches a key where the key parts that are
+ missing in the ORDER BY is constants:
+
+ In the following case the ORDER BY will be removed:
+ SELECT * FROM foo WHERE column=constant ORDER BY column;
+
+ In the following case the first key will be used to solve the ORDER BY:
+ SELECT * FROM foo WHERE key_part1=const ORDER BY key_part2;
+
+2000-04-10 Michael Widenius <monty@mysql.com>
+
+* Changed mysql.server to wait until the pid file is deleted on stop
+* Clients will automaticly be set to the same character set as the
+ server if one hasn't specified a character set with mysql_option()
+ or in the my.cnf files.
+
+2000-04-09 Michael Widenius <monty@mysql.com>
+
+* Release of 3.23.14
+* Fixed bug where complex CONCAT() use returned the wrong result.
+
+2000-04-07 Michael Widenius <monty@mysql.com>
+
+* Added some optimization to LIMIT when the used KEY matches almost all
+ rows in the table. (SELECT * from table where key_column > "a" LIMIT 1).
+* REPLACE now honors the LOW_PRIORITY_UPDATES flag.
+
+2000-04-05 Michael Widenius <monty@mysql.com>
+
+* Fixed that DROP TABLE is logged in the update log.
+* Fixed problem when searching on DECIMAL() key field
+ where the column data contained pre-zeros.
+
+2000-04-02 Michael Widenius <monty@mysql.com>
+
+* Fix bug in myisamchk when the auto_increment isn't the first key.
+
+2000-03-30 "Thimble Smith" <tim@mysql.com>
+
+* Allow DATETIME in ISO8601 format: 2000-03-12T12:00:00
+
+2000-03-30 Michael Widenius <monty@mysql.com>
+
+* Added UMASK_DIR environment variable.
+* Fixed problem with seek and RAID tables.
+
+2000-03-29 Michael Widenius <monty@mysql.com>
+
+* slow_queries log wasn't flushed on FLUSH LOGS.
+
+2000-03-28 Michael Widenius <monty@mysql.com>
+
+* Fix that DELETE FROM table_name; works on RAID tables.
+* Fix that DROP DATABASE works correctly with RAID tables.
+
+2000-03-27 Michael Widenius <monty@mysql.com>
+
+* Added function CONNECTION_ID()
+
+2000-03-26 Michael Widenius <monty@mysql.com>
+
+* When using = on BLOB or VARCHAR BINARY keys where only a part of the column
+ was indexed, the whole column of the result row wasn't compared.
+
+2000-03-24 takeshi@SoftAgency.co.jp
+
+* Fix for sjis & order by
+
+2000-03-23 Michael Widenius <monty@mysql.com>
+
+* Added patches to allow client library to compile on BEOS.
+
+2000-03-16 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Added STDCALL to some functions in libmysql that missed this.
+* When running in ANSI mode, don't allow one to use columns that isn't in
+ the GROUP BY part.
+
+2000-03-14 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Release of 3.23.13
+* Removed end space from double/float numbers in results from temporary
+ tables.
+
+2000-03-13 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Fixed automatic removal of table locks if doing a DROP TABLE on the last
+ locked table.
+
+2000-03-13 Sasha
+
+* Added CHECK TABLE command.
+
+2000-03-12 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Changed int2str and longlong2str to use the optimized
+ int10_to_str / longlong10_to_str functions.
+
+2000-03-09 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Fixed bug so that mysqladmin shutdown will wait for the local server to close
+ down.
+* Fixed a possible endless loop when calculating timestamp.
+
+2000-02-27 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Release of 3.23.12
+* Changed that mysql_ping() doesn't increment the 'questions' status variable.
+* Fixed that mysql -D database doesn't kill 'mysql'.
+
+2000-02-24 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Only allow SHOW GRANTS if you have a privilege on the mysql
+ tables
+* Fixed bug when storing 0 into a timestamp.
+
+2000-02-23 Michael Widenius <monty@monty.pp.sci.fi>
+
+* When doing mysqladmin shutdown on a local connection, mysqladmin now
+ waits until the pidfile is gone before doing an shutdown.
+* Changed that the pid file is not removed until all threads have died.
+
+2000-02-23 Matt Wagner
+
+* When doing mysqladmin shutdown on a local connection, mysqladmin now
+ waits until the pidfile is gone before doing an shutdown.
+
+2000-02-23 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Fixed problem with LEFT JOIN and key_field IS NULL.
+
+2000-02-23 Sasha
+
+* Fixed core dump with some COUNT(DISTINCT ...) queries.
+
+2000-02-21 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Added options USE KEYS (key_list) and IGNORE KEYS (key_list) as
+ join parameters in SELECT.
+* DROP of table is now done through the handler.
+
+2000-02-17 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Added ANSI SQL syntax ALTER TABLE ADD (column_def1, column_def2 ...)
+
+2000-02-16 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Fixed problem with optimizer that could sometimes use wrong keys
+
+2000-02-15 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Fixed that GRANT/REVOKE ALL PRIVILEGES doesn't affect GRANT OPTION
+* Removed extra ) from the output of SHOW GRANTS
+
+2000-02-13 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Fixed problem when storing numbers in timestamps.
+* Fix problem with timezones that has half hour offsets.
+* Storage of numbers in timestamp columns are now faster.
+
+2000-02-11 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Allow the syntax UNIQUE INDEX in CREATE statements.
+
+2000-02-10 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Added options --i-am-a-dummy and --safe-updates to mysql.cc
+* Added variables select_limit and max_join_size to mysql.cc
+* Added sql variables: SQL_MAX_JOIN_SIZE and SQL_SAFE_UPDATES
+* Added READ_LOCAL lock that doesn't lock the table for concurrent inserts
+* Changed that LOCK TABLES .. READ doesn't anymore allow concurrent inserts
+* Added option --skip-delay-key-write to mysqld.
+
+2000-02-09 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Fixed security problem in the protocol regarding password checking.
+
+2000-02-03 Michael Widenius <monty@tik.pp.sci.fi>
+
+* Allow 'end' as a field name.
+* Added _rowid as an alias for an auto_increment column.
+
+2000-01-28 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Ignore empty queries in mysql when running in batch mode
+ (To be able to handle rows with double ';' chars).
+
+2000-01-27 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Fixed problem with timestamps and INSERT DELAYED
+
+2000-01-26 Michael Widenius <monty@tik.pp.sci.fi>
+
+* Fixed problem that affected queries that did arithmetic on GROUP functions.
+
+2000-01-24 Michael Widenius <monty@tik.pp.sci.fi>
+
+* Don't give a unnecessary GRANT error when using tables from many
+ databases in the same query.
+
+2000-01-20 Michael Widenius <monty@tik.pp.sci.fi>
+
+* Fixed that 'date_column BETWEEN const_date AND const_date' works.
+
+2000-01-19 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Fixed problem when only changing a 0 to NULL in a table with BLOB/TEXT
+ columns.
+* Fixed bug in range optimizer when using many key parts and or on the middle
+ key parts: WHERE K1=1 and K3=2 and (K2=2 and K4=4 or K2=3 and K4=5)
+* Added the virtual VIO interface to the mysql connection streams.
+ (This will make it possible to use SSL through the VIO classe interface)
+
+2000-01-14 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Added command 'source' to mysql to allow reading of batch files inside
+ mysql. Original patch by Matthew Vanecek.
+
+2000-01-12 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Fixed bug that a change of all VARCHAR columns to CHAR columns didn't change
+ row type from dynamic to fixed.
+
+2000-01-11 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Added print of default arguments options to all clients.
+* Added --log-slow-queries to mysqld to log all queries that takes a
+ long time to a separate log file with a time of how long the query took.
+* Fixed critical problem with the WITH GRANT OPTION option.
+* Added read-next-on-key to HEAP tables. This should fix all
+ problems with HEAP tables when using not UNIQUE keys.
+* Disabled floating point exceptions for FreeBSD to fix core dump when
+ doing SELECT floor(pow(2,63));
+
+2000-01-07 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Fixed core dump when doing WHERE key_column=RAND(...)
+ (Note that this query can never use keys as the RAND() function must be
+ re-evaluated for each row)
+2000-01-04 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Fixed optimization bug in SELECT .. LEFT JOIN ... key_column IS NULL, when
+ key_column could contain NULL values.
+* Fixed problem with 8 bit characters as separators in LOAD DATA INFILE.
+
+2000-01-02 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Release of 3.23.8
+
+1999-12-31 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Fixed GRANT problem when doing 'CREATE TABLE ... SELECT'
+
+1999-12-30 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Fixed problem with timezones that are < GMT -11
+* Fixed problem with ISAM when doing some ORDER BY .. DESC queries.
+
+1999-12-28 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Fixed bug when doing a join on a text key which didn't covert the whole key.
+* Option --delay-key-write didn't enable delayed key writing
+* Fixed update of TEXT column which only involved case changes.
+
+1999-12-27 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Fixed that INSERT DELAYED doesn't update timestamps that are given.
+
+1999-12-25 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Added function yearweek() and options 'x', 'X', 'v' and 'V' to date_format()
+
+1999-12-22 Michael Widenius <monty@tik.pp.sci.fi>
+
+* Fixed problem with MAX(indexed_column) and HEAP tables.
+* Fixed problem with BLOB NULL keys and LIKE "prefix%".
+
+1999-12-20 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Fixed problem with MyISAM and fixed length rows < 5 bytes.
+
+1999-12-10 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Added RAID support (patch from Tõnu Samuel)
+
+1999-12-02 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Added -O interactive_timeout to mysqld.
+* Changed the argument of mysql_data_seek to ulonglong from ulong.
+
+1999-11-30 Michael Widenius <monty@monty.pp.sci.fi>
+
+Fixed bug in replace() on Alpha. Patch by 'Tom Holroyd'
+Fixed bug in LOAD DATA LOCAL INFILE on Alpha. Patch by 'Tom Holroyd'
+
+1999-11-29 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Added detection of pthread_attr_stacksize() in configure.
+* Added variable net_retry_count (needed for FreeBSD).
+
+Sun Nov 28 20:55:45 1999 Michael Widenius <monty@bitch.pp.sci.fi>
+
+* Added option '--verbose' to mysqladmin
+
+1999-11-28 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Fixed problem when converting heap to myisam.
+* Fixed bug in HEAP tables when doing insert + delete + insert + scan the
+ table.
+
+1999-11-23 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Fix core dump when releasing a lock from a non existing table
+* Remove locks on tables before starting to remove duplicates.
+* Added patch to make most string functions multi-byte safe (by Wei He)
+* Added Bytes_recieived/Bytes_sent statistics (by Sasha Pachev)
+* Added optimization of read_next() with MyISAM
+* Changed MyISAM to use concurrent inserts.
+
+1999-11-21 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Inverted flag 'delayed_key_write' on 'show variables'
+
+1999-11-20 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Added variable max_write_lock_count
+
+1999-11-13 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Release of 3.23.6
+* Made floor() overflow safe on FREEBSD.
+* Allow quoting of identifers with `
+* Temporary tables now start with #sql
+* Added option --quote-names to mysqldump.
+* Added option --ansi to change " to a identifier delimiter and || to
+ string concatenation.
+* Fixed INTO DUMPFILE to give better error messages. NULL is now written
+ as an empty string.
+* Changed Field_double and double->string to use snprintf() to avoid overflows.
+* Fixed bug that one could make a part of a PRIMARY KEY not null.
+* Fixed encrypt() to be thread safe and not reuse buffer.
+
+1999-11-11 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Changed that FLOAT(X) where X <= 24 -> FLOAT and X <= 53 -> DOUBLE.
+* Changed DECIMAL(X) to be DECIMAL(X,0) and DECIMAL to be DECIMAL(10,0)
+
+1999-11-09 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Added mysqld option -O lower_case_table_names=[0|1] to force table
+ names to lower case.
+* Added mysql_odbc_escape_string() function to support big5 characters in
+ MyOBC.
+
+1999-11-08 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Added patch by Sasha for user defined variables.
+* Changed that FLOAT and DOUBLE (without any length modifiers) are
+ not anymore fixed decimal point numbers.
+
+1999-10-22 Michael Widenius <monty@tik.pp.sci.fi>
+
+* Added option ROW_FORMAT=[default, dynamic, static, compressed] to
+ CREATE_TABLE
+
+1999-10-20 Michael Widenius <monty@monty.pp.sci.fi>
+
+* 'DELETE FROM table_name' didn't work on temporary tables
+
+1999-10-18 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Release of MySQL 3.23.5
+* Fixed problem with LIKE "%const"
+
+1999-10-17 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Added bit function ~ (neg)
+
+1999-10-14 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Added support for the GBK Chinese character set (by Wei He)
+
+1999-10-13 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Storage of date results is now much faster to date and datetime columns.
+
+1999-10-12 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Fixed bug when using DISTINCT + ORDER BY RAND()
+* new option --relative to mysqladmin.
+
+1999-10-11 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Added some error messages in mysqld.cc
+* Allow use of NATIONAL and NCHAR when defining character columns.
+ (They don't do anything)
+* Don't allow NULL columns in PRIMARY KEY:s (only in UNIQUE keys)
+
+1999-10-10 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Clear LAST_INSERT_ID if in uses this in ODBC context:
+ WHERE auto_increment_column IS NULL;
+* 'SET SQL_AUTO_IS_NULL=0|1' now turns off/on the above handling of
+ auto_increment columns
+
+1999-10-09 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Added parameter 'concurrency' for Solaris.
+
+1999-10-07 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Fixed problem when using an auto_increment column in two keys
+
+1999-10-06 Michael Widenius <monty@monty.pp.sci.fi>
+
+* AS on fieldname with CREATE TABLE table_name SELECT ... didn't work.
+
+1999-10-01 Michael Widenius <monty@tik.pp.sci.fi>
+
+* LIKE with many % ("%xxx%yy%zz%") are now much faster.
+
+1999-09-24 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Fix privilege check for LOAD DATA REPLACE .
+
+1999-09-22 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Added SHOW GRANT FOR user (by Sinisa)
+* Added date + INTERVALL # date_interval_type
+
+1999-09-19 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Fixed problem with index optimzation with 'WHERE index is not null'
+
+* Allow creation of temporary tables with same name as original table.
+* When granting user a grant option for a database, he couldn't grant
+ privileges to other users.
+
+1999-09-17 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Inserting a DATETIME into a TIME column will not anymore try to store 'days'
+ in it.
+* Fixed problem with storage of float/double on low endian machines.
+
+1999-09-08 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Release of 3.23.3
+* Added limit to UPDATE
+* Added client library function: mysql_change_user()
+
+1999-09-07 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Added character set to 'show variables'
+* Added support of '--[white-space]' as comment
+* Allow 'INSERT into table_name VALUES ();'
+
+1999-09-03 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Add mysqld option --delay-key-write to mysqld.cc
+
+1999-08-30 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Fixed problem with COUNT(DISTINCT) and GROUP BY
+
+1999-08-29 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Added /*!version */
+* Fixed core dump with empty blob to reverse()
+* Fixed problem with year(now()) and year(curdate()).
+
+1999-08-28 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Added construct:
+
+ CASE value WHEN [compare-value] THEN result
+ [WHEN [compare-value] THEN result ...]
+ [ELSE result]
+ END
+
+ CASE WHEN [condition] THEN result
+ [WHEN [condition] THEN result ...]
+ [ELSE result]
+ END
+1999-08-19 Michael Widenius <monty@tik.pp.sci.fi>
+
+* Added check of arguments to acos() and asin().
+* unique_column IS NULL only returned the first row with NULL.
+
+1999-08-12 Michael Widenius <monty@tik.pp.sci.fi>
+
+* REGEXP(...,NULL) will not return an error anymore.
+
+* Removed ifdef mSQL_COMPLIANT when comparing NULL to NULL
+
+1999-08-05 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Fix problem with LOCK TABLES and DELETE FROM table.
+
+1999-08-04 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Don't pack all keys even if one key is packed when not using PACK_KEYS=1.
+
+1999-08-03 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Fixed core-dump bug when inserting table or column grant on user name ""
+
+1999-08-02 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Fix problem with LOCK TABLES when no database is selected.
+* New functions: MD5(), (by Tõnu Samuel) and EXPORT_SET (by Sasha Pachev)
+* Changed Socket to my_socket (to avoid conflicts)
+
+1999-07-29 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Fixed problem with DISTINCT on BLOB column
+* new keywords: CASE, THEN, WHEN, ELSE, END
+* The CASE operator (by Tõnu Samuel) (not yet working)
+* set SQL_LOW_PRIORITY_UPDATES=# didn't work
+* Fixed range optimizer bug in
+ SELECT * FROM table_name WHERE key_part1 >= const AND (key_part2 = const OR key_part2 = const)
+
+1999-07-26 Michael Widenius <monty@tik.pp.sci.fi>
+
+* One can now update indexes columns that are used in the WHERE clause.
+ UPDATE tbl_name SET KEY=KEY+1 WHERE KEY > 100;
+
+1999-07-25 Michael Widenius <monty@tik.pp.sci.fi>
+
+* Added get_date() function to all item and fields. This makes date handling
+ a lot faster!
+* Added handling of fuzzy dates (dates where day or month is 0)
+
+1999-07-21 Michael Widenius <monty@tik.pp.sci.fi>
+
+* Fixed optimization of SELECT ... WHERE key_part1=const1 and key_part_2=const2 and key_part1=const4 and key_part2=const4
+ (indextype should be range instead of ref)
+
+1999-07-20 Michael Widenius <monty@tik.pp.sci.fi>
+
+* Changed handling of 'const_item' to allow handling of
+ ORDER BY RAND().
+* MyISAM tables now allows keys on NULL and BLOB columns.
+* Optimize the following LEFT JOIN:
+ SELECT ... FROM t1 LEFT JOIN t2 ON ... WHERE t2.not_null_column IS NULL
+
+1999-07-19 Michael Widenius <monty@tik.pp.sci.fi>
+
+* Added ORDER BY and GROUP BY with functions
+* Changed all handling of tables in sql_select.cc to use table_map instead
+ of table_nr.
+* Added use of column_name = formula to use keys
+* column_name = column_name2 don't anymore have to have identical packing
+* field IS NULL can now use keys
+
+1999-07-16 Michael Widenius <monty@tik.pp.sci.fi>
+
+* Changed heap tables to be stored in low_byte_first order (to make it easy
+ to convert to MyISAM tables)
+* Automatic change of HEAP temporary tables to MYISAM tables in case of
+ 'table is full' errors.
+* Added option --init-file=file_name to mysqld
+
+1999-07-15 Michael Widenius <monty@tik.pp.sci.fi>
+
+* Added COUNT(DISTINCT value,[value,...])
+
+1999-07-14 Michael Widenius <monty@tik.pp.sci.fi>
+
+* changed name of temporary table to include getpid().
+* Added full support for CREATE TEMPORARY
+
+1999-07-04 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Added CREATE TABLE options 'CHECKSUM' and 'PACK_KEYS'
+* Added mysqld option --default-table-type
+* Added column 'packed' to 'show index'
+* Added pack_keys and checksum to show table status
+
+1999-07-01 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Release of 3.23.0
+* Show NULL as the default value for AUTO_INCREMENT columns.
+* Fixed optimizer bug with tables with only one row.
+* Fixed bug when using LOCK TABLES table_name READ; FLUSH TABLES;
+
+1999-06-30 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Added use of LIBWRAP (by "Henning P . Schmiedehausen" <hps@tanstaafl.de>)
+
+1999-06-28 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Don't allow AUTO_INCREMENT for other than numerical columns
+* Using AUTO_INCREMENT will now automaticly make the column NOT NULL.
+
+1999-06-22 Michael Widenius <monty@tik.pp.sci.fi>
+
+* Added privilege column to 'show columns'
+
+1999-07-13 Michael Widenius <monty@tik.pp.sci.fi>
+
+* Added SQL_BIG_RESULT (SQL_SMALL_RESULT is now default)
+* Use the MYISAM UNIQUE constraint to solve SELECT DISTINCT faster.
+
+1999-06-06 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Changed most macros in the libmysql library to functions to avoid many
+ versions of shared libraries.
+
+1999-05-16 Michael Widenius <monty@tik.pp.sci.fi>
+
+* Added "Row_type" to SHOW TABLE STATUS.
+
+1999-05-15 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Added option IF NOT EXISTS to CREATE TABLE
+* Allow creation of CHAR(0) columns.
+
+1999-05-14 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Added more error checking of errors from the table handler.
+
+1999-05-13 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Added the '<=>' operator which will act as '=' but will return TRUE if both
+ arguments are NULL.
+
+1999-05-12 Michael Widenius <monty@monty.pp.sci.fi>
+
+* The default base for the log, update-log and pid-file name is now
+ 'hostname' with everything after the first '.' removed.
+
+1999-05-11 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Require '%' before format characters in DATE_FORMAT().
+* Add logging of GRANT and SET PASSWORD in the update log.
+
+1999-05-10 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Changed LIKE compare to behave as =; This means that 'e' LIKE 'é' is now
+ true.
+
+1999-05-10 Michael Widenius <monty@tik.pp.sci.fi>
+
+* REPLACE now used direct read to find dupplicate row instead of key read;
+ This makes REPLACE a lot faster.
+
+1999-05-05 Michael Widenius <monty@tik.pp.sci.fi>
+
+* New option: CREATE TABLE SELECT ....
+* Added syntax for CREATE TEMPORARY TABLE (not yet implemented)
+
+1999-05-03 Michael Widenius <monty@tik.pp.sci.fi>
+
+@code{DESCRIBE TABLE} returns a lot of information about the tables
+
+1999-05-02 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Added comments to tables
+* Added UNIQUE, in CREATE TABLE table_name (col int not null UNIQUE);
+
+1999-04-29 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Use auto_increment value provided by MYISAM
+* Use key_part statistics if available
+
+1999-04-28 Michael Widenius <monty@monty.pp.sci.fi>
+
+* null bits are now stored at start of row instead at the end.
+ (Now we only need one bit to mark a row deleted)
+
+* DELAYED is now a reserved words. (because of conflicts from yacc)
+
+1999-04-20 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Added patches for DEC_3_2 by "Andrea Suatoni" <and@itaca.it>
+
+1999-04-19 Jani Tolonen <jani@monty.pp.sci.fi>
+
+* Added load_file() function
+
+1999-04-15 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Added option --skip-show-databases to mysqld.
+
+1999-04-10 Michael Widenius <monty@monty.pp.sci.fi>
+
+* set start time when connection.
+
+1999-04-03 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Fixed problem with 'DELETE FROM TABLE' when table was locked by another
+ thread.
+
+1999-04-03 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Check if rows has changed now also works with BLOB/TEXT.
+* Added the INNER JOIN syntax; This made 'INNER' a reserved word.
+
+1999-04-02 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Fixed problem with 'Host '..' is not allowed to connect to this MySQL
+ server' after one had inserted a new MySQL user with a GRANT command.
+
+1999-04-01 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Added support for netmasks to the hostname in the MySQL tables.
+
+1999-03-31 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Changed net.cc to use TCP_NODELAY also on Linux.
+* If one compares a NOT NULL DATE/DATETIME column with IS NULL, this
+ is changed to a compare against 0 to satisfy some ODBC applications.
+ (By shreeve@uci.edu)
+
+1999-03-30 Michael Widenius <monty@monty.pp.sci.fi>
+
+* NULL IN (...) now returns NULL instead of 0.
+ This will ensure that 'null_column NOT IN (...)' doesn't match NULL values.
+* Changed the mysql.db entry to char(60).
+
+1999-03-16 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Fix storage of floating point values in TIME columns
+* Changed parsing of TIME strings to be more strict. Now the fractional
+ second part is detected (and currently skipped)
+ The following formats are supported
+ [[[DAYS] [H]H:]MM:]SS[.fraction] and [[[[H]H]H]H]MM]SS[.fraction]
+* Detect (and ignore) second fraction part from DATETIME
+
+1999-03-10 Michael Widenius <monty@monty.pp.sci.fi>
+
+* On Win32 detect --basedir automaticly from path to mysqld.
+* Added option --skip-column-names to mysql.
+* Added some memory checks in sql_string.cc
+
+1999-03-08 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Added the ODBC 3.0 EXTRACT(interval FROM datetime) function
+* Added lots of 'out of memory' checks for SELECT statements.
+
+1999-03-05 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Fixed std() for big tables when result should be 0.
+
+1999-03-04 Michael Widenius <monty@monty.pp.sci.fi>
+
+* INSERT DELAYED had some garbage at end in the update log.
+
+1999-03-03 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Added a lot of casts in filesort.cc to make it more portable.
+
+1999-02-28 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Changed default size of key_buffer to 4M
+* Fixed problem with queries that needed temporary tables with blobs.
+
+1999-02-26 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Added LOAD DATA [LOW_PRIORITY] INFILE.
+* Added option 'flush-time' to force MySQL-Win32 version to flush
+ the tables once in a while.
+* On Linux all process didn't die on shutdown.
+
+1999-02-18 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Fixed a core dump problem when using --log-update and connecting
+ without a default database.
+* Added more error check if one get an error writing to the log files.
+
+1999-02-16 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Fixed some configure errors
+* If one used @code{LEFT JOIN} on tables that had circular dependencies this
+ caused mysqld to hang forever.
+
+1999-02-05 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Release of 3.22.16
+* mysqladmin processlist could core dump mysqld if a new user logged in.
+* DELETE FROM table_name WHERE key_column=column_name didn't find any matching
+ rows.
+* The default index name is now using the same case as the used column name.
+
+1999-02-03 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Added the MODIFY attribute to ALTER TABLE (to be compatible with some other
+ SQL databases)
+* Added LIKE to 'show status'
+
+1999-01-31 Michael Widenius <monty@monty.pp.sci.fi>
+
+* DATE_ADD(column,...) didn't work.
+* INSERT DELAYED could deadlock with status 'upgrading lock'
+
+1999-01-30 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Extended item_encrypt() to take longer salt strings than 2 characters.
+ (for FreeBSD)
+
+1999-01-26 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Release of 3.22.15
+* LIKE on binary strings didn't work if one used a multi-byte character set.
+* mysqladmin -w will now wait for the server to come up if it's killed.
+
+Tue Jan 26 00:06:10 1999 Michael Widenius <monty@bitch.pp.sci.fi>
+
+* Fixed problem with ORDER BY whith 'only index' optimzation when there
+ where multiple key definitions for an used column.
+* GRANT with password didn't update in memory GRANT table before
+ 'mysqladmin flush'
+
+1999-01-20 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Updating BLOB/TEXT through formulas didn't work for short (< 256 char)
+ strings.
+* Changed option --extended_insert-insert to --extended-insert in mysqldump
+
+1999-01-19 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Lots of changes to support INSERT DELAYED.
+
+1999-01-17 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Changed unpacking of DATE and DATETIME; These are now about 5 times faster.
+
+1999-01-16 Michael Widenius <monty@monty.pp.sci.fi>
+
+* DATE_ADD with now() or curdate() reused the same string.
+* Added BENCHMARK(loop-count,expression) function to time expressions.
+
+1999-01-14 Michael Widenius <monty@monty.pp.sci.fi>
+
+* LEFT JOIN USING (col1,col2) gave an error if one used it with tables
+ from 2 different databases.
+* LOAD DATA LOCAL INFILE didn't work in the unix version because of a missing
+ file in the sql directory
+* Fixed problems with VARCHAR/BLOB on very short rows (< 4 bytes); One
+ could get error 127 when deleting rows.
+
+1999-01-13 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Nicer error messages for table types.
+* Changed default number of connections to 100
+
+1999-01-11 Michael Widenius <monty@monty.pp.sci.fi>
+
+* When one did a GRANT on a new host mysqld could die on the first connect
+ from this host.
+* Use as default bigger buffers when using 'load data infile'.
+
+1999-01-06 Michael Widenius <monty@monty.pp.sci.fi>
+
+* All blob pointers have now reserved 8 bytes in the .frm files; This makes
+ the .frm files portable to 64 bit architectures.
+
+* DECIMAL(x,y) now works according to ANSI SQL.
+
+1998-12-30 Michael Widenius <monty@monty.pp.sci.fi>
+
+* If one used ORDER BY on column name that was the same name as an alias,
+ the ORDER BY was done on the alias.
+
+1998-12-29 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Added aggregate UDF functions. Thanks to
+ Andreas F. Bobak <bobak@relog.ch> for this !
+
+1998-12-28 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Changed sql_crypt() a bit to make it a bit more secure; This will make old
+ string stored with the old decrypt() function unreadable!
+
+1998-12-27 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Allow empty arguments to mysqld to make it easier to start it
+ from shell scripts!
+
+1998-12-23 Michael Widenius <monty@monty.pp.sci.fi>
+
+* last_insert_id() is now updated for INSERT INTO ... SELECT
+* Setting a TIMESTAMP column to NULL didn't record the timestamp
+ value in the update log.
+
+1998-12-21 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Fixed lock handler bug when one did:
+ INSERT INTO TABLE ... SELECT ... GROUP BY.
+* Added a patch for localtime_r() on Win32 that it will not crash anymore
+ if your date is > 2039, but instead it will return a time of all zero.
+* UDF function names are not longer case sensitive.
+* Added escape of '^Z' to \Z as ^Z doesn't work with pipes on Win32
+* Changed optimizer to not use 'range search' in some cases.
+* Changed optimizer to use result form 'check_range' in optimization of
+ searching of part keys.
+
+1998-12-16 Michael Widenius <monty@monty.pp.sci.fi>
+
+* SELECT COUNT(*) didn't work on LEFT JOIN queries with only had expressions
+ in the ON part and there where no WHERE clause.
+* Added optional support for crypted frm files.
+
+1998-12-13 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Saving NOW(), CURDATE() or CURTIME() directly in a column didn't work.
+* SELECT COUNT(*) didn't work on LEFT JOIN queries with only had expressions
+ in the ON part and no WHERE clause.
+
+1998-12-09 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Fixed a bug in sql_list.h that made ALTER TABLE dump a core in some context.
+
+1998-12-08 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Allow use of negative real numbers without a decimal point.
+* day number is now adjusted to max days in month if the resulting month
+ after DATE_ADD/DATE_SUB() doesn't have enough days.
+
+1998-12-07 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Fix that GRANT compares columns case insensitive.
+* Add / to TMPDIR if needed.
+
+1998-12-06 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Allow GLOBAL as a table or database name.
+
+Thu Dec 3 10:29:11 1998 Michael Widenius <monty@tik>
+
+* Added option SQL_SMALL_RESULT to SELECT to force use of fast temporary
+ tables when one knows that the result set will be small!
+
+1998-11-27 Michael Widenius <monty@monty.pp.sci.fi>
+
+* The hostname in user@hostname can now include '.' and '-' without quotes.
+
+1998-11-26 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Fixed problem when using DATE_ADD()/DATE_SUB() in a WHERE clause.
+* One can now set the password for a user with the
+ GRANT ... user IDENTIFIED BY 'password' syntax.
+* Fixed bug in GRANT checking with SELECT on many tables.
+* Removed some 'no Database selected' errors.
+* Release of 3.22.11
+
+1998-11-21 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Changed USER() to return user@host
+* New command: FLUSH STATUS ; to reset most status variables.
+* New status variables: aborted_threads and aborted_connects.
+
+1998-11-20 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Fixed bug in ORDER BY on FIELD()
+* New function make_set() (70% by Jani Tolonen)
+
+1998-11-18 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Added functions encrypt() and decrypt(). Because of endspace stripping of
+ CHAR() and VARCHAR() these should only be used with fixed size strings or
+ with BLOB/TEXT columns.
+
+1998-11-17 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Silently remove DEFAULT values from AUTO_INCREMENT columns.
+* Added new variable to mysqld: connection_timeout
+
+1998-11-13 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Better error message when table doesn't exists.
+
+1998-11-12 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Added option SET SQL_WARNINGS=1 to get a warning count also for simple
+ inserts.
+* IS NULL on a AUTO_INCREMENT column in a LEFT JOIN didn't work.
+* MySQL now uses SIGTERM instead of SIGQUIT with shutdown to work better
+ on FreeBSD.
+* Added option \G (print vertically) to mysql
+* SELECT HIGH_PRIORITY ... killed mysqld.
+
+1998-11-11 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Added grant checking to 'show tables'
+* Large changes to get grants integrated with the current privilege system.
+
+1998-11-10 Michael Widenius <monty@monty.pp.sci.fi>
+
+* SELECT .. WHERE t1.id1=t2.id2 could fail if t1.id1 and t1.id2 was keys
+ and of radically differently types.
+* Changed get_password to use getpass function. (Patch by Jaromir
+ Dolecek <dolecek@ics.muni.cz>)
+
+1998-11-04 Michael Widenius <monty@analytik>
+
+* Release of 3.22.10
+* Changed +, - (sign and minus), *, /, % and ABS() to be BIGINT aware.
+* ALTER TABLE and UPDATE now writes out the values of any duplicated keys.
+
+1998-11-03 Michael Widenius <monty@monty.pp.sci.fi>
+
+* ADABASD like INSERT statement:
+ INSERT INTO table_name SET column=value,column=value...
+* The client flag option 'CLIENT_IGNORE_SPACE' didn't work properly.
+* Fixed bug in ALTER TABLE that caused a core dump.
+* Added optimization of SELECT ... FROM table ORDER BY key_part1 LIMIT ...
+ This query will now use indexes instead of sorting the table.
+
+Mon Nov 2 20:52:15 1998 Jani Tolonen <jani@bitch.pp.sci.fi>
+
+* Added more variables to SHOW STATUS and changed format of output
+* Added command extended-status to mysqladmin which will show the
+ new status
+
+1998-10-30 Michael Widenius <monty@monty.pp.sci.fi>
+
+* columns of type date, date_time and 'set' are now stored a little
+ more efficient if they are 0, NULL or ''.
+
+1998-10-26 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Most errors are now printed through sql_write_error() which will add
+ date, time and thread id to the .err log.
+
+1998-10-25 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Added option MYSQL_INIT_COMMAND to mysql_options() to make a query
+ on connect or reconnect.
+* Added option MYSQL_READ_DEFAULT_FILE and MYSQL_READ_DEFAULT_GROUP to
+ mysql_option() to read the following parameters from the my.cnf file:
+ "port", "socket", "compress", "password", "pipe", "timeout", "user",
+ "init-command", "host" and "database"
+
+* Added maybe_null to the UDF structure
+
+1998-10-22 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Added IGNORE to INSERT with many rows.
+* Added SQL GRANT commands
+* Release of 3.22.9
+
+1998-10-18 Michael Widenius <monty@monty.pp.sci.fi>
+
+* One can new set the last_insert_id() value in an update with
+ LAST_INSERT_ID(expr). This makes it possible to return a value for things
+ like:
+ UPDATE table SET COUNT=LAST_INSERT_ID(COUNT+1) WHERE primary_key_col=#
+* display key name used by 'range' in the 'key' column in 'show processlist'
+* new SQL command: FLUSH [ TABLES | HOSTS | LOGS | PRIVILEGES ] [, ...]
+* new SQL command: KILL thread_id
+
+Thu Oct 15 18:57:15 1998 Michael Widenius <monty@tik>
+
+* Reuse memory for identical set and enum fields.
+
+1998-10-14 Michael Widenius <monty@analytik>
+
+* Added open file information to mysqladmin debug
+* Fixed conversion problem when using ALTER TABLE from a INT to a short CHAR()
+ column.
+* Added 'SELECT HIGH_PRIORITY'; This will get a lock for the SELECT even if
+ there is a thread waiting another SELECT to get a WRITE LOCK.
+ NOTE: This makes HIGH_PRIORITY a reserved word
+
+1998-10-12 Michael Widenius <monty@analytik>
+
+* Moved wild_compare to string class to be able to use LIKE on BLOB/TEXT columns with \0
+* Added ESCAPE option to LIKE
+
+1998-10-08 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Update for AIX: Added a cast to all bzero() calls and changed to use
+ my_gethostbyname_r instead of gethostbyname_r.
+
+1998-10-03 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Release of 3.22.8
+* Added an extra thread signal loop on shutdown to avoid some error messages
+ from the client.
+* MySQL now uses the next available number as extension for the update
+ log file.
+
+1998-09-25 Michael Widenius <monty@monty.pp.sci.fi>
+
+* MySQL clients on NT will now by default first try to connect with named pipes
+ and after this with TCP/IP.
+
+1998-09-24 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Fixed problems with TIME columns and negative strings.
+* Added a new column 'state' to 'mysqladmin proc' that gives some
+ information what the thread is doing.
+
+* DATE_ADD() and DATE_SUB() didn't work with group functions.
+
+1998-09-23 Michael Widenius <monty@monty.pp.sci.fi>
+
+* 'mysql' will now also try to reconnect on 'use database' commands.
+
+* Fix problem with ORDER BY and LEFT JOIN and const tables.
+
+1998-09-22 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Fixed problem with ORDER BY if the first ORDER BY column was a key and
+ the rest wasn't.
+
+1998-09-17 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Release of 3.22.7
+* OPTIMIZE TABLE table_name can now be used to reclaim disk space
+ after many deletes. This uses currently ALTER TABLE to re-generate
+ the table, but in the future it will use an integrated isamchk
+ for more speed.
+
+1998-09-16 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Added functions for perfect hashing of symbols. Moved some other things
+ to the LEX structure for faster setup.
+* Changed libmysql.dll on Win32 to use TLS to get better multi-threading
+
+1998-09-15 Michael Widenius <monty@monty.pp.sci.fi>
+* Added --where to mysqldump (patch by Jim Faucette).
+* Fixed slow UPDATE/DELETE when using DATETIME or DATE keys.
+
+1998-09-14 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Changed some optimizations parameters to make better joins.
+* Anyone can now use 'mysqladmin proc' to check ones own
+ threads. Only users with the 'Process_priv' privilege can get
+ information about all threads.
+* Fixed very unlikely optimizer bug in the range optimizer
+ (bug introduced in 3.22.6)
+* Added handling of formats YYMMDD, YYYYMMDD, YYMMDDHHMMSS to
+ DATETIME/TIMESTAMP when using numbers. (Before these formats only worked
+ with strings).
+
+1998-09-06 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Added connect option CLIENT_IGNORE_SPACE to allow one to use
+ space after the function name and before '(' (Powerbuilder requires this).
+ This will make all function names reserved words.
+* comments that start with /*! are now interpreted as commands. This feature
+ allows one to use MySQL extensions like:
+ 'SELECT /*! STRAIGHT_JOIN */ * from table1,table1'
+ in a portable manor.
+
+1998-09-04 Michael Widenius <monty@analytik>
+
+* Added SET OPTION INSERT_ID=# to force use of specific INSERT_ID. This is
+ usable with new --log-long-format option.
+
+1998-08-31 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Fixed problem when INSERTING into TIME fields.
+
+1998-08-29 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Added key cache and handler statistic to 'mysqladmin debug'.
+* changed UPDATE and DELETE to not use 'index only' range detection.
+ (Fixed slow update_key in the benchmarks)
+* Changed the insert benchmark because it was impossible to use it with
+ postgreSQL (to slow).
+
+Thu Aug 27 15:38:23 1998 Michael Widenius <monty@bitch.pp.sci.fi>
+
+* mysqldump will automaticly use LOAD DATA LOCAL INFILE if one uses
+ an TCP/IP connection.
+
+1998-08-27 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Added support of local files with LOAD DATA LOCAL INFILE ..
+* Save history if one kills mysql with ^C. Save history in MYSQL_HISTFILE.
+ Modfied patch by Tommy Larsen <tommy@mix.hive.no>
+
+1998-08-26 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Fixed a possible problem with mysql_refresh().
+
+Tue Aug 18 14:07:53 1998 Michael Widenius <monty@bitch.pp.sci.fi>
+
+* Give an error for queries that mix GROUP columns and fields when there
+ is no GROUP BY specification.
+
+1998-08-17 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Changed sql_yacc.yy to allow field attributes in any order.
+
+1998-08-15 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Increased max_allowed_packed to 1M as default.
+* LOAD DATA INFILE didn't copy single field separators in some case:
+ "Hello"Atif"!"
+
+1998-08-13 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Fixed fatal bug in lpad().
+
+Thu Aug 13 01:00:44 1998 Michael Widenius <monty@bitch.pp.sci.fi>
+
+* REGEXP can now take a expression as the second argument.
+
+1998-08-12 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Changed LIKE to be faster in some cases with many '%': LIKE '%c%ompiler%'
+
+1998-08-11 Michael Widenius <monty@monty.pp.sci.fi>
+
+* All table lock handing is changed to avoid some very subtitle
+ deadlocks when using DROP TABLE, ALTER TABLE, DELETE FROM TABLE and
+ mysqladmin flush-tables under heavy usage.
+
+1998-08-10 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Allow one to use the syntax 'CONSTRAINT symbol' before FOREIGN KEY.
+* new mysqld option '--low-priority-insert' to give inserts lower priority
+ than selects.
+* One can now use {INSERT | REPLACE} LOW_PRIORITY INTO ...
+ One side effect is that LOW_PRIORITY is now a reserved word :(
+* Changed locking code to get better handling of locks of different types.
+
+1998-08-09 Michael Widenius <monty@monty.pp.sci.fi>
+
+* mysqld will now ignore trailing ';' characters in queries. This is to
+ make it easier to emigrate from some other SQL servers that require the
+ end ';'
+* One can now use a LIMIT value with DELETE to make it return after deleting
+ a given number of rows.
+* Fix for corrupted output of fixed format and SELECT INTO OUTFILE:
+ select * from test into outfile "/tmp/test.txt" fields terminated by '' enclosed by ''
+
+1998-08-04 Michael Widenius <monty@monty.pp.sci.fi>
+
+* new mysqld option: '-O max_connect_errors=#'.
+ Connect errors are now reset for each correct connection.
+* Add support for INSERT INTO table ... VALUES(...),(...),(...)
+
+1998-08-03 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Added Oracle GREATEST() and LEAST() functions. One must now use
+ these instead if the MAX() and MIN() functions to get the biggest/smallest
+ value from a list of values. These can now handle real, bigint and
+ string values.
+* The following query now uses indexing instead of sorting the table:
+ SELECT ... FROM table ORDER BY key_part1 desc,key_part2 desc,...
+* Added check that the error message file has enough error messages.
+* DAYOFWEEK() had offset 0 for Sunday. Changed the offset to 1.
+
+1998-08-02 Michael Widenius <monty@monty.pp.sci.fi>
+
+* new option to mysql: '--vertical' to print results in vertical mode.
+* All count structures in the client (affected_rows, insert_id...) are now of
+ type BIGINT to allow one to use 64 bit values.
+ This required a minor change in the MySQL protocol which may affect
+ old clients when using tables with auto_increment values > 24M.
+* The return type of mysql_fetch_lengths() has changed from uint *
+ to ulong *. This may give a warning for old clients but should work
+ on most machines.
+
+Thu Jul 30 15:29:05 1998 Michael Widenius <monty@tik>
+
+* COUNT(), STD() and AVG() are extended to handle more than 4G rows.
+
+Wed Jul 29 10:36:05 1998 Michael Widenius <monty@tik>
+
+* Added new option:
+ SET OPTION SQL_LOG_UPDATE=[0,1] to allow users with process_priv
+ privilege to bypass the update log.
+ (Modified patch from Sergey A Mukhin <violet@rosnet.net>)
+
+Thu Jul 23 15:58:13 1998 Michael Widenius <monty@tik>
+
+* Initialize line buffer in mysql.cc to make blob readings from pipes safer.
+
+Tue Jul 21 22:04:43 1998 Michael Widenius <monty@tik>
+
+* One can now store -838:59:59 <= x <= 838:59:59 in a TIME column.
+* TIME_TO_SEC() and SEC_TO_TIME() can now handle negative times and hours
+ up to 32767.
+
+Mon Jul 20 20:34:33 1998 Michael Widenius <monty@tik>
+
+* Change mysys/dbug to allocate all thread varibles in one struct.
+ This makes it easier to make a threaded libmysql.dll
+
+Sun Jul 19 12:54:45 1998 Michael Widenius <monty@tik>
+
+* Changed ALTER TABLE to make it more multi-thread safe.
+* normal INSERT INTO TABLE are now also cached when used with
+ LOCK TABLES. (previously only INSERT ... SELECT and LOAD DATA INFILE
+ was cached)
+
+Fri Jul 17 20:53:23 1998 Michael Widenius <monty@tik>
+
+* Allow group functions with HAVING:
+ SELECT col FROM table GROUP BY col HAVING COUNT(*)>0;
+
+Tue Jul 14 15:11:52 1998 Michael Widenius <monty@tik>
+
+* Use the result from 'gethostname' as the name for pid files
+ (instead of uname()).
+
+Sun Jul 12 12:38:45 1998 Michael Widenius <monty@tik>
+
+* Index only optimization; Some queries are now resolved using
+ only indexes. Until MySQL 4.0 this works only for number columns.
+
+ SELECT key_part1,key_part2 FROM table WHERE key_part1=#
+ SELECT COUNT(*) FROM table WHERE key_part1=# and key_part2=#
+ SELECT key_part2 FROM table GROUP BY key_part1;
+ SELECT * FROM table ORDER BY key_part2;
+
+1998-07-07 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Added function DATE_ADD() and DATE_SUB()
+
+1998-07-06 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Added function SUBSTRING() with 2 arguments.
+
+1998-07-05 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Added optimization to remove const reference tables from ORDER BY and
+ GROUP BY.
+* Allow '$' in table and column names.
+
+1998-07-04 Michael Widenius <monty@monty.pp.sci.fi>
+
+* new option --tmpdir for mysqld.
+
+1998-07-03 Michael Widenius <monty@monty.pp.sci.fi>
+
+* MySQL now automaticly changes a query from an ODBC client:
+ SELECT ... from table WHERE auto_increment_column IS NULL
+ to
+ SELECT ... from table WHERE auto_increment_column == LAST_INSERT_ID().
+ This allows some ODBC programs (Delphi, Access) to retrieve the newly
+ inserted row to fetch the auto_increment id.
+* Drop table now waits for all users to free a table before deleting it
+
+1998-07-02 Michael Widenius <monty@monty.pp.sci.fi>
+
+* New functions: BIN(), HEX() and CONV() for converting between different
+ number bases.
+
+1998-07-01 Michael Widenius <monty@monty.pp.sci.fi>
+
+* If one created a table with smaller record length than 5, one couldn't
+ delete rows from this table
+* mysqld now automaticly disables system locking on Linux, Win32 and if
+ one uses MIT-threads. One can force the use of locking by doing:
+ --enable-locking.
+* Added new mysqld option --console, to force a console window (for error
+ messages) when using Win32.
+* Removed a useless check in the ISAM delete code; Delete should now be
+ a bit faster.
+
+1998-06-28 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Release of MySQL 3.22.3
+* New flag to mysqld: --one-thread for debugging with linuxthreads (or glibc)
+
+1998-06-27 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Added the LEX structure to THD to get a bit more speed.
+* Added DROP TABLE IF EXISTS to not get an error if the table doesn't exists.
+* IF and EXISTS are now reserved words (they would have to be sooner or later)
+
+1998-06-26 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Added lots of new options to mysqldump.
+
+Wed Jun 24 23:33:35 1998 Michael Widenius <monty@tik>
+
+* Server error messages are now in mysqld_errror.h
+* Added compression server/client protocol. (By Sinisa).
+
+1998-06-22 Michael Widenius <monty@monty.pp.sci.fi>
+
+* New functions: <<, >>, rpad() and lpad().
+* Fixed a core-dump bug in the range optimizer.
+
+Fri Jun 19 01:51:09 1998 Michael Widenius <monty@tik>
+
+* One can now save default options (like passwords) in a config file (my.cnf).
+
+1998-06-17 Michael Widenius <monty@monty.pp.sci.fi>
+
+* searching on multiple constant keys that matched > 30 % of the rows didn't
+ always use the best possible key.
+
+1998-06-16 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Lot's of small changes to get ORDER BY to work when no records are found
+ when using fields that are not in GROUP BY (MySQL extension)
+* Added new option --chroot to mysqld to start mysqld in a chroot environment
+ (by Nikki Chumakov <nikkic@cityline.ru>)
+
+1998-06-15 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Add option --one-database to mysql to only update one database
+ from a update log.
+
+1998-06-13 Michael Widenius <monty@monty.pp.sci.fi>
+
+* end space is now ignored when comparing case sensitive strings;
+ This should fix some problems with ODBC!
+* mysql_free_result() now automaticly handles a mysql_use_result() set that
+ is not completely read.
+
+1998-06-10 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Release of MySQL 3.22.1
+* Fixed problems with date_format() and wrong dates.
+* enum() and set() columns was compared binary; Changed to be case insensitive.
+
+1998-06-08 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Added new API functions: mysql_init() and mysql_options().
+ One MUST now call mysql_init() before one calls mysql_real_connect().
+ One doesn't have to call mysql_init if one only calls mysql_connect().
+* LEFT JOIN core dumped if the second table is used with a constant
+ WHERE/ON expression with uniquely identifies one record.
+
+1998-06-07 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Range optimizer is not used anymore when comparing a string column
+ to a number. This will make such compares slower but safer.
+
+Sun Jun 7 04:47:14 1998 Michael Widenius <monty@tik>
+
+* UPDATE now returns a update information about how many rows was
+ matched, updated and if one got any 'warnings' when doing the update.
+
+Sat Jun 6 22:58:02 1998 Michael Widenius <monty@tik>
+
+* Fixed wrong result from 'format(-100,2)'.
+
+1998-06-06 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Added new C-API function: mysql_ping().
+* Added options AFTER column and FIRST to ALTER TABLE ... ADD columns.
+ This makes is possible to add a new column at some specific location
+ in an old table.
+* Fixed problem with find_in_set().
+
+1998-05-18 Michael Widenius <monty@analytik>
+
+* Added new API function: mysql_ping().
+
+1998-05-15 Michael Widenius <monty@monty.pp.sci.fi>
+
+* WEEK() now takes an optional argument to allow handling of weeks when the
+ first day of the week = Sunday (default or 0) or Monday ( extra argument is
+ 1). WEEK() now returns the week number in the range 0-53 for the used
+ year.
+
+1998-05-13 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Added flag -T32 to mysqld for running all queries under the main thread.
+ This makes it possible to debug mysqld under Linux with gdb!
+ (This is now called --one-thread)
+
+1998-05-12 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Added optimization of 'not_null_column IS NULL' (needed for some Access
+ queries)
+* Made all time functions 'more streamlined'.
+
+1998-05-09 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Allow one to use STRAIGHT_JOIN between two tables to force the optimizer
+ to join them in a specific order.
+
+Fri May 8 02:35:00 1998 Michael Widenius <monty@bitch.pp.sci.fi>
+
+* Added SET OPTION PASSWORD='new_crypted_password' and
+ SET OPTION PASSWORD= 'host' : 'user' : 'new_password'. The last version
+ only works for users with write access to the mysql database.
+ One can also use: SET OPTION PASSWORD=PASSWORD("new_password");
+
+Tue May 5 14:41:47 1998 Michael Widenius <monty@bitch.pp.sci.fi>
+
+* String functions now return VARCHAR() instead of CHAR() and
+ the column type is now VARCHAR() for fields saved as VARCHAR().
+ This should make the MyODBC driver better, but may break some old
+ MySQL clients that doesn't handle FIELD_TYPE_VARCHAR identical as
+ FIELD_TYPE_CHAR.
+
+Mon May 4 00:33:27 1998 Michael Widenius <monty@bitch.pp.sci.fi>
+
+* Added BOOL as a synonym for BIT and DISTINCTROW as a synonym for DISTINCT.
+* CREATE INDEX and DROP INDEX are now implemented trough ALTER TABLE.
+ CREATE TABLE is still the recommended (fast) way to create indexes.
+* Added option SET OPTION PASSWORD='new_password'.
+ mysqladmin can now be used by not anonymous users to change their
+ password.
+
+Sun May 3 18:47:24 1998 Michael Widenius <monty@bitch.pp.sci.fi>
+
+* Added option wait_timeout to mysqld.
+
+Sat Apr 18 14:14:23 1998 Michael Widenius <monty@bitch.pp.sci.fi>
+
+* Added hashing of fieldnames for tables with many fields.
+* The most frequently used string functions are now in assembler (Linux-intel).
+
+Thu Apr 16 16:14:14 1998 Michael Widenius <monty@bitch.pp.sci.fi>
+
+* Added quick checking if ok host.
+* Changed the interface for field->val_str() to better use stack buffers.
+
+Thu Apr 9 20:02:26 1998 Michael Widenius <monty@bitch.pp.sci.fi>
+
+* One can now reference to tables in different databases with:
+ table@database or database.table
+* Added cacheing of users & access rights (for faster access rights checking)
+
+1998-04-08 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Save of command line history to file in mysql client.
+ by Tommy Larsen <tommy@mix.hive.no>
+
+1998-04-07 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Added time column to 'mysqladmin processes' to show how long a query
+ has taken or how long a thread has sleeped.
+
+1998-04-06 Michael Widenius <monty@monty.pp.sci.fi>
+
+* 'show variables' now gives the correct path for 'datadir'.
+* Added logging and update_log to "show variables"
+
+1998-03-29 Michael Widenius <monty@analytik>
+
+* Added new type: YEAR. YEAR is stored on 1 byte with range 0, 1901-2155.
+* Added new DATE type that is stored on 3 bytes instead of 4. All new
+ tables will created with the new date type if one doesn't use
+ --old-protocol.
+* Fixed bug in record caches; One could get 'Error from table handler: #'
+ on some OS from some queries.
+
+1998-03-27 Michael Widenius <monty@monty.pp.sci.fi>
+
+* mysql (the command line tool) striped start space from new rows.
+
+1998-03-25 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Added user level locks: GET_LOCK(string,timeout), RELEASE_LOCK(string)
+* Fixed bug in range optimizer when using:
+ WHERE key_part_1 >= something and key_part_2 <= something_else
+* Changed connect timeout to 3 seconds to make it somewhat harder
+ for crackers to kill mysqld trough telnet + TCP/IP.
+
+1998-03-24 Michael Widenius <monty@monty.pp.sci.fi>
+
+* new mysqld option --big-selects:
+ Allow big result sets by saving all temporary sets on file.
+ (Solves most 'table full' errors)
+
+1998-03-21 Michael Widenius <monty@monty.pp.sci.fi>
+
+* WHERE with string-column-key = constant-string didn't always find all rows
+ if the column had many values differing only with characters of the same sort
+ value (like e and é).
+* Added opened_tables to 'show status'.
+* Strings keys looked up with 'ref' was not compared case sensitively.
+* Added flag '--big-selects' to avoid 'Table is full' errors.
+ Using this will slow down some queries thought.
+* Added umask() to make log_files non-readable for normal users.
+* Fixed some odd cases with queries that uses group functions where
+ the WHERE or HAVING didn't match anything.
+* Ignore users with old password (8 byte) on startup if not using
+ --old-protocol.
+* Changed name of the sql_memory allocation system and moved this to
+ the mysys library.
+
+1998-03-17 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Added use of current_date, current_time and current_timestamp functions
+ without (). This automaticly made these reservered words :(
+
+Tue Mar 10 12:34:50 1998 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Changed mysql_real_connect() to include possible db for faster connection
+ to a new db.
+* select which matched all key fields returned the values in the same
+ case as the matched values instead of the found values.
+* Release of 3.21.26
+* In DATE_FORMAT() PM and AM was swapped for hours 00 and 12.
+
+Mon Mar 9 14:15:00 1998 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Added some tests to the table order optimizer to get some cases with
+ 'SELECT ... FROM many_tables' much faster.
+* Added a retry loop around accept() to possible fix some problems on some
+ Linux machines.
+
+Fri Mar 6 01:18:47 1998 Michael Widenius <monty@monty.pp.sci.fi>
+
+* from_days(0) now returns "0000-00-00"
+* Enchanted mysql_connect protocol to allow one to specify database
+ on connection. This will make MySQL twice as fast to connect to a database
+ for new clients.
+
+Thu Mar 5 18:09:45 1998 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Updated record_cache code to be aligned for more speed.
+* New tests to crash-me
+* Extended the default max key size to 256.
+
+Wed Mar 4 00:02:16 1998 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Fixed bug when using BLOB/TEXT in GROUP BY with many tables.
+
+Mon Mar 2 18:58:10 1998 Michael Widenius <monty@monty.pp.sci.fi>
+
+* A enum field that is not declared NOT NULL has NULL as default value.
+ (Before the default value was the first enum option)
+
+Tue Feb 24 20:11:30 1998 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Fixed bug in the join optimizer code when using many part keys
+ on the same key: INDEX (Organisation,Surname(35),Initials(35)).
+
+Mon Feb 23 16:15:39 1998 Michael Widenius <monty@monty.pp.sci.fi>
+
+* One can now kill threads that are waiting for 'disk full'.
+* Fixed some problems with UDF functions.
+* ALTER TABLE + IGNORE now returns right number of affected rows.
+* Fixed a bug when using 8 bytes long (alpha); filesort() didn't work.
+ Affects DISTINCT, ORDER BY and GROUP BY on 64 bit processors.
+
+Sat Feb 21 15:36:48 1998 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Changed typedef string to my_string because of C++ new string class.
+* now one can kill threads that's are waiting on 'disk full'.
+
+Fri Feb 13 23:19:23 1998 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Release of MySQL 3.21.24
+* Fixed problem with LEFT JOIN and constant expressions in the ON part.
+
+Thu Feb 12 02:54:57 1998 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Added much more descriptive error messages to mysqladmin if connect failed.
+* Dynamic loadable functions. Based on source from:
+ Alexis Mikhailov <root@medinf.chuvashia.su>
+
+Thu Feb 5 15:19:14 1998 <monty@monty.pp.sci.fi>
+
+* One couldn't delete from a table if no one had done a select on the table.
+* Fixed problem with range optimizer which many OR's on key parts inside
+ each other.
+
+Tue Feb 3 14:34:32 1998 <monty@monty.pp.sci.fi>
+
+* Changed default umask for new files from 0664 to 0660.
+
+Fri Jan 30 23:58:19 1998 <monty@monty.pp.sci.fi>
+
+* Release of MySQL 3.21.23
+* Changed ALTER TABLE to work with WIN32 (Win32 can't rename open files)
+
+Thu Jan 29 20:37:50 1998 <monty@monty.pp.sci.fi>
+
+* Fixed that the following symbols are not reserved words:
+ TIME DATE TIMESTAMP TEXT BIT ENUM NO ACTION CHECK YEAR MONTH DAY HOUR
+ MINUTE SECOND STATUS VARIABLES.
+* Changed string handling in sql_yacc.yy and sql_lex.cc to be faster.
+* Setting a TIMSTAMP to NULL in LOAD DATA INFILE... didn't set the current
+ time for the TIMESTAMP.
+* Fixed that key conversions are tested in the WHERE clause
+* LOAD DATA INFILE .... REPLACE INTO ... had wrong 'skipped' count
+
+Tue Jan 27 15:24:50 1998 <monty@monty.pp.sci.fi>
+
+* Added switch --skip-thread-prior for systems where mysqld's thread
+ scheduling doesn't work properly. At least BSDI 3.1 works better with
+ this!
+* Added ODBC functions DAYNAME() and MONTHNAME().
+* Fixed unlikely(?) key optimizer bug when using ORs inside ANDs.
+
+Sat Jan 24 03:35:46 1998 <monty@monty.pp.sci.fi>
+
+* Release of 3.21.22
+* Added support of 'long constant strings' from ANSI SQL:
+ select 'first ' 'second'; -> 'first second';
+
+Mon Jan 19 17:59:49 1998 <monty@monty.pp.sci.fi>
+
+* Fixed problem with Russian character set and LIKE.
+* Fixed bug in ORDER BY on string formula with possible NULL values.
+* Added functions DAYOFYEAR(), DAYOFMONTH(), MONTH(), YEAR(), WEEK(),
+ QUARTER(), HOUR(), MINUTE(), SECOND() and FIND_IN_SET().
+* Changed weighting, when using many key parts, in join optimizer to avoid
+ full joins for a couple of cases.
+
+Sun Jan 18 21:16:06 1998 <monty@monty.pp.sci.fi>
+
+* Removed that NULL = NULL is true. Now one must use IS NULL or IS NOT NULL
+ to test if a value is NULL. (This is according to ANSI SQL but may break
+ old applications that are ported from mSQL)
+ One can get the old behaviour by compiling with -DmSQL_COMPLIANT
+* Fix of count(*) problems when the WHERE clause didn't match any records.
+* Added function DAYOFMONTH()
+
+1998-01-14 Michael Widenius <monty@analytik>
+
+* Fixed mysqladmin.c to display only the used socket or TCP/IP port.
+
+Mon Jan 12 19:32:31 1998 <monty@monty.pp.sci.fi>
+
+* Changed SHOW FIELDS to return NULL as default value for TIMESTAMP
+ (This removes the DEFAULT "" entry for timestamps in mysqldump)
+* Release of MySQL 3.21.21
+* Added commands SHOW STATUS and SHOW VARIABLES.
+* Fixed optimizer bug when using
+ 'WHERE data_field=date_field2 and date_field2=constant'
+
+Sun Jan 11 05:07:59 1998 <monty@monty.pp.sci.fi>
+
+* Release of MySQL 3.21.20
+* Added long comments to MySQL /* */
+* Changed lex parsing to be a bit faster in some cases.
+
+Sat Jan 10 15:17:44 1998 <monty@monty.pp.sci.fi>
+
+* Fixed bug when using SELECT DISTINCT + NULL values.
+
+Fri Jan 9 16:45:26 1998 <monty@monty.pp.sci.fi>
+
+* Changed maximum table name and column name lengths from 32 to 64.
+* Aliases can now be of 'any' length.
+
+Thu Jan 8 02:28:11 1998 <monty@monty.pp.sci.fi>
+
+* Now one gets an error if one tries to create an INDEX or UNIQUE
+ on a column that allows NULL values. (Before the column was silently
+ made NOT NULL).
+
+Wed Jan 7 23:19:11 1998 <monty@monty.pp.sci.fi>
+
+* Changed protocol (downward compatible) to mark if a column
+ is auto_increment or a timestamp. This is needed for the
+ new java driver.
+* One can now in the clients check if a column is a automatic
+ TIMESTAMP or a AUTO_INCREMENT field.
+
+Sun Jan 4 20:10:21 1998 <monty@monty.pp.sci.fi>
+
+* Added update of big5 by jou@pdlc.ieo.nctu.edu.tw
+* Added hebrew sorting order by Zeev Suraski.
+
+Thu Jan 1 12:57:04 1998 <monty@monty.pp.sci.fi>
+
+* Release of 3.21.19
+* unique key fields was not marked as unique keys in mysqlshow.
+* Added function REVERSE() (by Zeev Suraski)
+* Changed ni_range() to fixed a case of slow range searching.
+
+Wed Dec 31 15:46:25 1997 <monty@monty.pp.sci.fi>
+
+* Release of 3.21.18a
+* Fixed problem with new filesort code from 3.21.18 on Linux
+
+Mon Dec 29 10:02:24 1997 <monty@monty.pp.sci.fi>
+
+* Added CROSS JOIN syntax. CROSS is now a reserved word
+* USE database was not always written to output log.
+* mysqladmin command 'status' doesn't increment 'Questions' anymore.
+
+Sun Dec 28 13:20:20 1997 <monty@monty.pp.sci.fi>
+
+* Recoded yacc/bison stack allocation to be even safer and allow MysQL
+ to handle even bigger expressions.
+
+Sat Dec 27 15:28:39 1997 <monty@monty.pp.sci.fi>
+
+* last_insert_id and used timestamp is now written to update log file.
+ timestamps, calculations with time and LAST_INSERT_ID() will now work
+ correctly when updating from the update log.
+
+Fri Dec 26 17:03:14 1997 <monty@monty.pp.sci.fi>
+
+* Give error message if client C functions are called in wrong order.
+* Added automatic reconnect of clients for some cases.
+
+Mon Dec 22 00:25:34 1997 <monty@monty.pp.sci.fi>
+
+* Range optimizer didn't solve ranges of type:
+ key_part1= x AND key_part2 > y. This forced some ORDER BY queries to
+ do a full table scan when used with where like above.
+* Small sort sets doesn't use temporary files anymore.
+
+Fri Dec 19 16:30:24 1997 <monty@monty.pp.sci.fi>
+
+* Release of MySQL 3.21.17a
+* Fixed problem with compare of binary strings and blobs with ASCII
+ characters over 127.
+
+Thu Dec 18 00:33:25 1997 <monty@monty.pp.sci.fi>
+
+* Fixed core dump in first() when chaning some very specific AND and OR
+ key columns.
+* Fixed lock problem: When freeing a read lock on a table with multiple
+ read locks, a thread waiting for write lock would have given the lock.
+ This shouldn't affect data integrity, but could possible make mysqld
+ to restart if one thread was reading data that another thread modified.
+* LIMIT offset,count didn't work in INSERT ... SELECT.
+
+Wed Dec 17 12:35:11 1997 <monty@monty.pp.sci.fi>
+
+* optimized key block caching. This will be quicker than the old one when
+ using bigger key caches.
+
+Tue Dec 16 23:33:24 1997 <monty@monty.pp.sci.fi>
+
+* Changed bool to my_bool in some item structures to use less memory.
+* Changed optimizer to use array references. This made the code 'nicer'
+
+Mon Dec 15 17:03:43 1997 <monty@monty.pp.sci.fi>
+
+* Release of Mysql 3.21.17
+* mysql: Added ouput of line number on errors when running batch.
+* SELECT column,SUM(expr) now returns NULL for column when there is no
+ matching rows.
+
+Sun Dec 14 14:59:46 1997 <monty@monty.pp.sci.fi>
+
+* Fixed create problem with fixed length records of exactly 256 bytes.
+ (One couldn't insert more than 1 record in such a table).
+
+Fri Dec 12 18:31:32 1997 <monty@monty.pp.sci.fi>
+
+* Added ODBC and ANSI SQL style LEFT OUTER JOIN.
+ The following are new reserved words: LEFT, NATURAL, USING
+* Changed use of table bits and key bits to use typedefs to make it easy
+ to extend join tables and keys to 64.
+* The client library is now using the environment variable MYSQL_HOST as
+ the default host if it's defined.
+
+Wed Dec 10 01:29:11 1997 <monty@monty.pp.sci.fi>
+
+* Release of 3.21.16a
+* Field type SET with 33-55 elements didn't work.
+* Release of 3.21.16
+* Fixed bug in ALTER TABLE when copying from DATETIME to TIMESTAMP.
+ (All TIMESTAMP where set to current time).
+
+Tue Dec 9 14:53:15 1997 <monty@monty.pp.sci.fi>
+
+* Added function TIME_TO_SEC()
+
+Mon Dec 8 09:56:44 1997 <monty@monty.pp.sci.fi>
+
+* Allow empty strings as default values for BLOB and TEXT to be compatible with
+ mysqldump.
+* Added ODBC 2.0 & 3.0 functions: POWER(), SPACE(), COT(), DEGREES(), RADIANS(),
+ ROUND(2 arg) and TRUNCATE().
+* Added optional (ignored) argument to CURRENT_TIME() and CURRENT_TIMESTAMP().
+* LOCATE() parameters where swapped according to ODBC standard. Fixed.
+* Added detection of all ODBC 3.0 functions to crash-me
+* In some cases default values was not used for NOT NULL fields.
+* Timestamp wasn't updated in UPDATE SET... if the timestamp was used as
+ a value or in the WHERE clause.
+
+Sun Nov 30 04:06:31 1997 <monty@monty.pp.sci.fi>
+
+* Renamed version.h to mysql_version.h
+
+Sat Nov 29 10:50:28 1997 <monty@monty.pp.sci.fi>
+
+* Added dayofweek() for ODBC.
+* Allow DATE '1997-01-01', TIME '12:10:10' and TIMESTAMP '1997-01-01 12:10:10'
+ formats required by ANSI SQL.
+ This has the unfortunate side-effect that one can't have columns named
+ DATE, TIME or TIMESTAMP anymore :(
+* Changed net_write() to my_net_write() because of name conflict with sybase.
+* Added --no-auto-rehash option to mysql.
+* Added VARBINARY as synonym for VARCHAR BINARY
+
+Wed Nov 26 12:53:41 1997 <monty@monty.pp.sci.fi>
+
+* Added framework for multiple character sorting
+
+Tue Nov 25 04:03:29 1997 <monty@monty.pp.sci.fi>
+
+* Added extra client flag to mysql_real_connect to be compatible with
+ MyODBC.
+* Zeev fixed bug in DATE_FORMAT: It forgot to reset the null marker.
+
+Mon Nov 24 20:19:18 1997 <monty@monty.pp.sci.fi>
+
+* Fixed problem with wrong result order when using all of
+ DISTINCT + JOIN + ORDER BY + LIMIT.
+
+Sun Nov 23 14:29:54 1997 <monty@monty.pp.sci.fi>
+
+* mysql: edit command now allows one to edit last query in a editor;
+ (patch by Zeev Suraski)
+* Recoded all delete item to avoid use of stack space for deletes.
+ (For crash-me)
+* Added command: SET SQL_LOG_OFF=1 to not log commands to standard log.
+ This will only affect users with process list privileges.
+
+Sat Nov 22 13:08:55 1997 <monty@monty.pp.sci.fi>
+
+* Added stack checking for crash-me :)
+ The following failed before: select 1+1+1+1+1+.... (687 times)
+
+Fri Nov 21 01:50:34 1997 <monty@monty.pp.sci.fi>
+
+* Added new patch for Chinese Big5 code.
+* Change that blobs returns the max length for a blob instead of 8192
+ to the client as field_length.
+
+Thu Nov 20 15:37:05 1997 <monty@monty.pp.sci.fi>
+
+* fixed bug in range-optimizer that crashed mysql on some queries.
+* table and column name completion for mysql by
+ Zeev Suraski and Andi Gutmans
+* Fixed problem with queries that didn't find any records: This happens only
+ when using multiple part keys where the first part is a number and some
+ other part is a char or varchar.
+* Removed some wrong warning messages from range optimizer
+
+Wed Nov 19 16:41:14 1997 <monty@monty.pp.sci.fi>
+
+* Added new command REPLACE, which works like INSERT but replaces conflicting
+ records with the new record. REPLACE INTO TABLE ... SELECT ... works also.
+* Added new commands: CREATE DATABASE db_name and DROP DATABASE db_name
+* Added RENAME option to ALTER TABLE: ALTER TABLE name RENAME AS new_name
+
+Sun Nov 16 21:41:32 1997 <monty@monty.pp.sci.fi>
+
+* The thread stack was overwritten if one tried to create a table with too many
+ fields (more than 1000).
+- Table scanning was a bit slower when using LOCK TABLE xxx WRITE. Fixed.
+
+Thu Nov 13 03:12:54 1997 <monty@monty.pp.sci.fi>
+
+* ALTER TABLE forgot BINARY attribute for strings and BLOBS
+* Change comparision of strings to integer to compare as floats instead
+ of as integers.
+* Added printing of Access denied errors to log.
+* Fixed some not 100% portable typedefs in mysql_com.h
+* Added Luuk de Boers defines for interval handling.
+ This isn't compleat yet.
+
+Wed Nov 12 00:28:58 1997 <monty@monty.pp.sci.fi>
+
+* Added automatic removal of 'ODBC function conversions': {fn now() }
+* Added new function DATE_FORMAT(date_expr,format). The format string is the
+ same one that was previously integrated with from_unix_timestamp().
+* Changed from_unix_timestamp() to call function DATE_FORMAT() with format
+ element.
+
+Mon Nov 10 18:17:39 1997 <monty@monty.pp.sci.fi>
+
+* Added flag for stupid ODBC applications (like access) that wants found_rows
+ instead of affected_rows.
+* Added basic functions for handling av ANSI INTERVAL.
+
+Sat Nov 8 01:20:03 1997 <monty@monty.pp.sci.fi>
+
+* compare with DATE and TIME with NULL didn't work. (IS NULL worked)
+* Added many changes from the Win32 port.
+* new function: DATE_ADD_MM().
+
+Wed Nov 5 13:10:10 1997 Michael Widenius <monty@analytik>
+
+* SORTING on calculated DOUBLE values sorted on integer results instead.
+* SELECT ... WHERE KEY=constant ORDER BY ... didn't use key to retrieve
+ records. This was slow because everything was sorted..
+* CHECK isn't a reserved word anymore.
+
+Mon Nov 3 07:55:47 1997 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Allow start of mysqld.cc without a current database.
+* Changed server version to include -debug and -log if compiled with debugging
+ and to show that one has a logging enabled.
+
+Sat Nov 1 13:08:00 1997 <monty@monty.pp.sci.fi>
+
+* Added missing expression 'NOT IN'
+* Changed the place where HAVING should be. According to ANSI it should be
+ after GROUP BY but before ORDER BY. MySQL 3.20 had it wrongly last.
+* Added Sybase command: USE DATABASE to start using another database.
+* Fixed core dump when one had a wrong password in the password column.
+* Added automatic adjusting of number of connections and table cache size
+ if the maximum number of files that can be opened are less than needed.
+ This should fix that mysqld doesn't crash even if one hasn't done a
+ ulimit -n 256 before starting mysqld.
+* Added limit checks for create table.
+* Added more checks of different errors from net_read for SCO port.
+
+Tue Oct 28 14:30:31 1997 <monty@monty.pp.sci.fi>
+
+* Fixed problem when using big table_caches; MySQL could previously only
+ open 256 files.
+
+Mon Oct 27 10:02:19 1997 <monty@monty.pp.sci.fi>
+
+* Added options LINE STARTING WITH to LOAD DATA INFILE and
+ SELECT ... into outfile. Now one can do:
+
+ LOAD DATA INFILE '/tmp/syslog.sql' INTO TABLE uptime
+ FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED by "'"
+ LINES STARTING WITH 'VALUES (' LINES TERMINATED by ');\n' ignore 100 lines
+
+and
+ SELECT * from uptime into outfile '/tmp/syslog2.sql'
+ FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED by "'"
+ LINES STARTING WITH 'INSERT INTO uptime VALUES (' LINES TERMINATED by ');\n'
+
+* Added IGNORE # LINES to LOAD DATA INFILE.
+
+* Allow \N as a shorthand of NULL in SQL statements.
+
+Sun Oct 26 11:34:38 1997 <monty@monty.pp.sci.fi>
+
+* More memory checking.
+* Fixed grouping of functions with many from tables.
+
+Sat Oct 25 01:46:27 1997 <monty@monty.pp.sci.fi>
+
+* New error message so one can check if the connection was lost while
+ the command was running or if the connection was down from the start.
+* The mysql command tool now does a automatic reconnect if the connection
+ was lost when it does a query.
+* new command: 'mysqladmin debug'. This forces the server to dump out some
+ useful information to stdout. Currently it prints all lock information.
+* Rewrite lexer to be faster and more easy to extend.
+
+Fri Oct 24 13:57:06 1997 <monty@monty.pp.sci.fi>
+
+* Fixed bug when like on number key.
+* Added --table option to mysql to print in table format.
+ Moved time and row information after query result.
+* Added != as an alias for <>.
+
+Thu Oct 23 16:00:22 1997 <monty@monty.pp.sci.fi>
+
+* Added function VERSION() to make easier logs.
+
+Tue Oct 21 00:09:13 1997 <monty@monty.pp.sci.fi>
+
+* Relase of 3.21.12
+* Added memory checks to all string functions to return NULL if some
+ string gets bigger than max_allowed_packet. This is to make MySQL more
+ secure.
+* Fixed core dump bug on range optimizer.
+* In some cases doing a join + group + INTO OUTFILE, the result wasn't
+ grouped.
+* Now SQL_BIG_TABLES + DISTINCT is also optimized.
+* Changed the syntax of ALTER TABLE ... ALTER COLUMN ident SET DEFAULT ...
+ (The DEFAULT keyword wasn't allowed or required before).
+* Added russian error messages.
+
+Mon Oct 20 04:10:53 1997 <monty@monty.pp.sci.fi>
+
+* LIKE with '_' as last character didn't work. Fixed
+* Added many error checks for 'end of memory'
+* Added ENCRYPT() function by Zeev Suraski.
+* Fixed better FOREIGN KEY syntax skipping.
+ New reserved words: MATCH, FULL, PARTIAL
+
+Sun Oct 19 23:13:50 1997 <monty@monty.pp.sci.fi>
+
+* Force .log to logfile-name if one uses hostname as logfile.
+* mysqld now allows ip and hostname to the --bind-address option.
+
+Sat Oct 18 22:02:36 1997 <monty@monty.pp.sci.fi>
+
+* Added "SET OPTION CHARACTER SET cp1251_koi8" to enable conversions off
+ data to/from different character sets. Currently cp1251_koi8 is the only
+ one, but it's now trivial to add others.
+ Conversions: strings in the query -> intern set
+ fields and items in result -> terminal set
+ One can get back to the old one with:
+ SET OPTION CHARACTER SET DEFAULT
+* Lots of changes for Win95 port
+
+Fri Oct 17 15:29:44 1997 <monty@monty.pp.sci.fi>
+
+* Changed the create column syntax off NOT NULL to be after the DEFAULT value
+ as specified in the ANSI SQL standard. This will make mysqldump with
+ NOT NULL and default values incompatible with MySQL 3.20.
+* New reserved words are: BOTH, FOR, LEADING and TRAILING
+* Added a lot of function name alias so one can use the functions with
+ ODBC or ANSI SQL92 syntax.
+* Fixed ALTER TABLE person ALTER COLUMN phone SET DEFAULT NULL syntax.
+* Added CHAR and BIT as a synonyms for CHAR(1)
+* Changed the name if the INTERVAL type to ENUM, because INTERVAL is used in
+ ANSI SQL.
+* Added extended ANSI SQL TRIM() function.
+* Added CURTIME().
+
+Thu Oct 16 17:26:48 1997 <monty@monty.pp.sci.fi>
+
+* Fixed core dump when updating as user with only select privilige.
+
+Wed Oct 15 04:25:47 1997 <monty@monty.pp.sci.fi>
+
+* INSERT ... SELECT ... GROUP BY didn't work in some cases. On got
+ 'Invalid use of group function'
+* When using LIMIT, SELECT now always uses keys instead of record scan.
+ This will give better performance on SELECT and a WHERE that matches many
+ rows.
+* Added function last_insert_id() to retreive last auto_increment value.
+ This is for clients to ODBC that can't use the mysql_insert_id API function.
+* Added option '--flush-logs' to mysqladmin.
+* Added command 'status' to mysql.
+* Moved some messages from libmysql.c to errmsg.c
+
+Mon Oct 13 18:38:01 1997 <monty@monty.pp.sci.fi>
+
+* Tested on BSDI 3.0 with the newest pthread library.
+* Added new group functions: BIT_OR() and BIT_AND().
+* Added compatibility functions: CHECK, REFERENCES.
+* Added BIT as a synonym for CHAR(1) to get better compatibility.
+* Added option ALL to GRANT for better compatibility. (GRANT is still
+ a dummy fuction.
+* CHECK is now a reserved word.
+
+Fri Oct 10 17:01:25 1997 <monty@monty.pp.sci.fi>
+
+* Added partly translated dutch messages.
+* Fixed bug in ORDER BY and GROUP BY with NULL columns
+
+Thu Oct 9 10:26:47 1997 <monty@monty.pp.sci.fi>
+
+* Added test of create of table without columns.
+* Release of 3.21.10
+* Fixed a couple of bugs in the range optimizer. Now test-select works.
+
+Tue Sep 30 02:40:42 1997 <monty@monty.pp.sci.fi>
+
+* Added new function: REPEAT(string,count).
+* Added patch of support of Chinese(BIG5).
+* Fixed awful slowdown of libmysql.c when configuring using '--with-debug=yes'
+ This affected all clients that got large results from the server.
+ (This didn't affect using --quick or mysql_use_result).
+
+Sun Sep 28 20:59:41 1997 <monty@monty.pp.sci.fi>
+
+* Made a new function: mysql_real_connect, that takes two extra arguments:
+ port and socket to use on connection.
+* Added text types: TINYTEXT, TEXT, MIDDLETEXT and LONGTEXT.
+ These are actually blobs, but all searching is done text independent.
+ All old BLOB fields are now TEXT fields.
+* LONG VARCHAR is a synonym for TEXT. LONG BINARY is a synonym for BLOB.
+* 'LONG' is now a reserved word.
+
+Fri Sep 26 16:11:34 1997 <monty@monty.pp.sci.fi>
+
+* Release of 3.21.9
+* Fixed a couple of portable problems with include files.
+* Fixed bug in range calculation that could return empty
+ set when searching on multiple key with only one entry (very rare).
+
+Wed Sep 24 15:51:37 1997 <monty@monty.pp.sci.fi>
+
+* Changed thread scope from PROCESS to SYSTEM. This should give better
+ scheduling (performance) on Solaris.
+* Fixed duplicated free bug in sql_base with io_cache.
+
+Tue Sep 23 13:05:23 1997 <monty@monty.pp.sci.fi>
+
+* Allow also the old SELECT ... INTO OUTFILE syntax.
+* Fixed bug with group by and select on key with many values.
+
+Mon Sep 22 14:54:00 1997 <monty@monty.pp.sci.fi>
+
+* mysql_fetch_lengths() returned sometimes wrong lengths when one used
+ mysql_use_result(). This affected at least some cases of mysqldump --quick.
+
+Sun Sep 21 20:50:07 1997 <monty@monty.pp.sci.fi>
+
+* Fixed memory leak bug in range optimizer.
+
+Sat Sep 20 00:03:51 1997 <monty@monty.pp.sci.fi>
+
+* Allow TIME, DATE and TIMESTAMP as column names.
+* Fixed bug in optimization of WHERE const op field.
+
+Fri Sep 19 12:06:37 1997 <monty@monty.pp.sci.fi>
+
+* Fixed problem when sorting on NULL fields.
+* Added handling of calculation of sum() functions.
+* Added handling of trigometric functions: PI(), ACOS(), ASIN(), ATAN(),
+ COS(), SIN() and TAN().
+* Fixed sorting of big tables for 64 bit integers (Alpha).
+
+Fri Aug 29 13:06:32 1997 Michael Widenius <monty@analytik>
+
+* Added option --pid-file=# to mysqld
+* Added date formating to from_unixtime(), originally by Zeev Suraski.
+
+Wed Aug 27 01:35:18 1997 <monty@monty.pp.sci.fi>
+
+* Fixed bug when using 'unsigned long' on Alpa.
+
+Tue Aug 26 03:23:28 1997 <monty@monty.pp.sci.fi>
+
+* Added option --bind-address to mysqld.
+* Changed 'Access denied' to return username and password usage.
+* Changed 'Access to database denied' to return username and database.
+
+Sun Aug 24 22:55:24 1997 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Changed password crypt from 31 bits to 62 bits to make passwords more
+ secure.
+* Changed protocol to allow for passing of mysql_errno to client.
+
+Fri Aug 22 18:14:00 1997 <monty@monty.pp.sci.fi>
+
+* Fixed bug in BETWEEN in range optimizer (Did only test = of the first
+ argument).
+
+Thu Aug 21 16:40:21 1997 <monty@monty.pp.sci.fi>
+
+* Version 3.21.6
+* Enabled range optimizer for update and delete. Now update and delete can
+ use keys again.
+* Fixed bug when using unknown field in group clause.
+
+Tue Aug 19 00:49:13 1997 <monty@monty.pp.sci.fi>
+
+* The range optimizer is now enabled as default. Use msyqld --skip-new
+ to disable it.
+* numerous small fixes to the range optimzer and a couple if fixes to
+ group and where handling.
+* Added patch from JOERG_HENNE@Non-HP-Germany-om88.om.hp.com to allow
+ mit-threads to work on HPUX10. (This patch is regarded alpha)
+
+Fri Aug 15 02:29:21 1997 <monty@monty.pp.sci.fi>
+
+* Remove reverse lookup of hostnames because this takes 2 seconds
+ one some machines for every connection!
+ This can be enabled with the --secure option to mysqld.
+
+Thu Aug 14 22:40:15 1997 <monty@monty.pp.sci.fi>
+
+* remove HAVING -> WHERE optimization. To fix this one has to change
+ all Item_ref fields to Item_fields.
+* Added patch for fast TCP/IP on FreeBSD.
+
+Wed Aug 13 17:14:50 1997 <monty@monty.pp.sci.fi>
+
+* Add optimizing of SELECT DISTINCT .... LIMIT # when there is no
+ GROUP or ORDER BY.
+* Changed mysql to only print time information if not silent or if -vvv.
+* Added polish error messages
+
+Sun Aug 10 11:31:10 1997 <monty@monty.pp.sci.fi>
+
+* new function: substring_index(), originally by Zeev Suraski.
+* Added new option to mysqld: -O tmp_table_size=#
+* Removed all use of PTHREAD_MUTEX_INIT and PTHREAD_COND_INIT for
+ porting to FreeBSD 3.0 and HPUX.
+
+Thu Aug 7 01:24:50 1997 <monty@monty.pp.sci.fi>
+
+* New function from_unixtime(timestamp) which returns a date string in
+ YYYY-MM-DD HH:MM:DD format.
+* New function sec_to_time(seconds) which returns a string in H:MM:SS format.
+
+Sat Aug 2 17:18:22 1997 <monty@monty.pp.sci.fi>
+
+* Fixed some porting issues for OSF1 and for Alpha.
+ Now MySQL is know to configure on OSF1 with the Dec compiler,
+ after changeing one line in config.h:
+ #define SOCKET_SIZE_TYPE int
+
+Wed Jul 30 11:05:39 1997 <monty@monty.pp.sci.fi>
+
+* Added reverse check lookup of hostnames to get better security.
+* Fixed some possible buffer overflows if one uses too long filenames.
+* mysqld doesn't accept hostnames that starts with digits followed by a '.'
+ because the hostname may look like a IP.
+* Added option --skip-networking to only allow socket connections.
+ (This will not work with MIT threads!)
+
+Tue Jul 29 10:38:55 1997 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Removed wrong free() that killed the server on 'create/drop database'.
+* Changed the name of some mysqld -O options to better names.
+* Added option '-O join_cache_size=#'.
+* Added option '-O max_join_size=#' to be able to set a limit how big queries
+ (in this case big = slow) one should be able to handle without specifying
+ 'SQL_OPTION OPTION_BIG_SELECTS=1'.
+ A # = is about 10 examined records. The default is 'unlimited'.
+* When comparing a TIME, DATE, DATETIME or TIMESTAMP column to a
+ constant the constant is converted to a time value before comparing.
+ This will make it easier to get ODBC and particularly Access97 to work with
+ the above types. It should also make dates easier to use and the compares
+ should be quicker than before.
+* added check of too long table names for alias.
+
+Mon Jul 21 16:09:47 1997 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Applied patch from Jochen Wiedmann that fixes that query() in mysqlperl now
+ can take queries with \0 in it.
+
+Sat Jul 19 01:11:38 1997 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Store of timestamp with 2 digit year YYMMDD didn't work.
+* Fix that timestamp isn't automaticly updated if set in a update clause.
+* Now the automatic timestamp field is the FIRST timestamp field.
+
+Thu Jul 3 13:34:26 1997 <monty@monty.pp.sci.fi>
+
+* Added check if database name is okey.
+* Addded check if too long table names.
+* SELECT * INTO OUTFILE, which didn't correctly if the outfile already existed.
+* 'mysql' now shows thread id when starting or doing a reconnect.
+* Changed the default sort buffer size from 2M to 1M.
+
+Mon Jun 30 10:18:39 1997 <monty@monty.pp.sci.fi>
+
+* mysqladmin: One can now do 'mysqladmin kill 5,6,7,8'
+* Fixed 'Packets out of order' message. This error come sometimes when the
+ server was out of threads/memory. Now the correct message is retrieved by
+ the client.
+* Added more checks with thread create for 'out of memory' errors.
+* Added more checks if threads is killed to get faster kill.
+* Changed the default record cache from 512K to 128K to get less problem on
+ systems with little memory.
+
+Sat Jun 28 00:18:02 1997 <monty@monty.pp.sci.fi>
+
+* When the max connection limit is reached, one extra connection by a user with
+ the PROCESS_ACL privilege is granted.
+
+Fri Jun 27 22:03:24 1997 <monty@monty.pp.sci.fi>
+
+* Added new mysqld option: -O backlog=#
+
+Tue Jun 24 22:08:58 1997 <monty@monty.pp.sci.fi>
+
+* Fixed SELECT DISTINCT when using 'hidden group'. For example:
+ SELECT DISTINCT MOD(some_field,10) FROM test GROUP BY some_field;
+* Increased max packet size from 512K to 1024K for client.
+* Removed a lot of unused functions
+
+Mon Jun 23 22:58:07 1997 <monty@monty.pp.sci.fi>
+
+* Changed key_parts to have own field for shortened keys. This gives much
+ nicer code in select.
+
+Thu Jun 19 13:09:14 1997 <monty@monty.pp.sci.fi>
+
+* ALTER TABLE now returns warnings from field conversions.
+ Changed all numerical fields to check for correct number and
+ increment warning counts if the value is wrong.
+
+Wed Jun 18 22:14:36 1997 <monty@monty.pp.sci.fi>
+
+* Fixed buffer overflow when retrieving big packets.
+
+Tue Jun 17 03:26:27 1997 <monty@monty.pp.sci.fi>
+
+* Port changed to 3306 (got it reserved from ISI).
+
+Mon Jun 16 15:46:42 1997 <monty@monty.pp.sci.fi>
+
+* All double are now rounded before storad as integer values.
+* Fixed bug when using: SELECT WHERE A=const1 OR A=const2 OR A=const3,
+ and const1 = const3. In this case a key over A=const1 was wrongly used and
+ A=const2 wasn't used.
+* Added a fix for Visual Fox Base so that any schema name from a table
+ specification is automaticly removed.
+
+Sun Jun 15 12:47:23 1997 <monty@monty.pp.sci.fi>
+
+* The thr_alarm array is now initialized based on number of connections
+* Changed some memcpy() to bmove() to get rid of some warnings from purify.
+* Changed the sql_yacc.c to drop schema name from table name. This is a crude
+ patch to get VFP
+
+Sat Jun 14 12:04:59 1997 <monty@monty.pp.sci.fi>
+
+* fixed missed ptr variable in filesort.
+* Fixed wrong tablename and record count EXPLAIN.
+* Changed the 'key use' test to prefere keys even more over full join.
+* Fixed LIKE to work for binary strings.
+
+Fri Jun 13 13:38:14 1997 <monty@monty.pp.sci.fi>
+
+* New function char(num,....).
+
+Wed Jun 11 14:53:17 1997 <monty@monty.pp.sci.fi>
+
+* All field types tested with extrema values. date_time and timestamp
+ now require at least year, month and day on insert.
+
+Mon Jun 9 01:23:36 1997 <monty@monty.pp.sci.fi>
+
+* Added French error messages (by Therrien, Gilbert). English is still default.
+* Added option '--skip-name-resolve' to get mysqld to use only IP's to
+ autenticate a host. 'localhost' will still be used for local UNIX sockets.
+* Removed the between() function. On should use the 'col BETWEEN a AND b'
+ syntax instead.
+
+Sun Jun 8 11:05:46 1997 <monty@monty.pp.sci.fi>
+
+* New function ASCII.
+
+Sat May 31 01:00:18 1997 <monty@monty.pp.sci.fi>
+
+* host names are now compared case insensitive.
+
+Wed May 28 13:04:00 1997 <monty@monty.pp.sci.fi>
+
+* HAVING is added to WHERE if there is no grouping.
+* MySQL now doesn't anymore have to use a extra temporary table when sorting
+ on functions or SUM functions.
+
+Tue May 27 00:54:51 1997 <monty@monty.pp.sci.fi>
+
+* Added function to print a item for debugging purposes.
+* Fixed bug that one couldn't use 'table_name.field_name' in UPDATE.
+* Removed init code with reset some of the mysqld -O variables to default after
+ they where set by start options.
+
+Thu May 22 14:52:26 1997 <monty@monty.pp.sci.fi>
+
+* Added varbinary syntax: 0x###### which can be used as a string (default) or a
+ number.
+
+Sun May 18 22:00:58 1997 <monty@bitch.sci.fi>
+
+* mysqldump: added options to lock tables and specify many tables to dump
+* Add support of NULL fields in filesort
+* SELECT with COUNT(),MIN() .... with no matching rows now returns 1 row.
+
+Sat May 17 22:06:29 1997 <monty@bitch.sci.fi>
+
+* New operator IN. This uses a binary search to find a match.
+* Added 'SET OPTION SQL_BIG_TABLES= (0 | 1). Setting this to 1 will force
+ all temporary tables to disk. This will allow one to do big selects that
+ ordinary would give a 'table full' error.
+
+Fri May 16 18:53:21 1997 <monty@bitch.sci.fi>
+
+* New command LOCK TABLES table_name [alias] (READ | WRITE), ....
+
+Wed May 14 14:33:07 1997 <monty@bitch.sci.fi>
+
+* Renamed FIELD_TYPE_CHAR to FIELD_TYPE_TINY
+
+Mon May 12 09:54:24 1997 <monty@bitch.sci.fi>
+
+* Added command --log-update to get a update log for incremental backups.
+* log file rotation for mysqld.
+* log file for incremental backups
+* new command: DESCRIBE SELECT ....
+* Removed mysql_reload() and added mysql_refresh() instead.
+ Left a define to get old source to compile.
+
+Fri May 9 10:41:36 1997 <monty@bitch.sci.fi>
+
+* All functions now regards a binary type as 'sticky'.
+* The time is now only requested once at start of each query.
+* Splitted item_func.cc in two tables to get around that gcc uses too
+ much memory compiling it.
+* Changed MIN() and MAX() to return the original type.
+* Fixed bug in acl with anonymous user: Now if one gets accepted by the user
+ table as a empty user name, the user name is set to '' when checking against
+ the 'db' and 'host' tables.
+* calculate all const expressions in the first optimizer pass.
+
+Tue May 6 19:16:56 1997 <monty@bitch.sci.fi>
+
+* Fixed ORDER BY bug when selecting on very small tables that made the
+ optimizer use a full join.
+
+Mon May 5 00:15:52 1997 <monty@bitch.sci.fi>
+
+* Added use of table alias in insert, delete and update.
+* Removed FIELD_TYPE_TINY_BLOB, FIELD_TYPE_MEDIUM_BLOB, FIELD_TYPE_LONG_BLOB,
+ FIELD_TYPE_VAR_STRING from client code.
+* Change syntax of SELECT .. WHERE ... INTO OUTFILE .. to the more standard
+ SELECT .. INTO OUTFILE 'name' WHERE ...
+
+Thu May 1 23:16:14 1997 <monty@bitch.sci.fi>
+
+* Added new API functions:
+ mysql_row_seek(),mysql_row_tell() and mysql_field_tell().
+ mysql_field_seek() now returns old offset.
+* Added expr BETWEEN expr2 AND expr3.
+
+Sun Apr 27 16:16:17 1997 <monty@bitch.sci.fi>
+
+* Changed range() detection to get queries on prefix to works faster.
+ Now SELECT name FROM table WHERE name="prefix" is quick even if there
+ are lots of rows where name starts with prefix.
+* Fixed crash with shutdown and --log-isam
+* Added group function STD() (standard derivation).
+* mysql.cc: Fixed that NULL columns are always at least 4 wide for nicer output
+ of NULL values.
+* Fixed that calculations that are not in GROUP BY works as expected.
+ (ANSI SQL extension)
+ Example: SELECT id,id+1 FROM table GROUP BY id
+
+Thu Apr 24 13:41:01 1997 Michael Widenius TcX DataKonsulter AB <monty@analytik>
+
+* Fixed convert bug which got mysqld to core dump with Aritmetic error on
+ Sparc-386
+
+Wed Apr 23 12:11:05 1997 Michael Widenius TcX DataKonsulter AB <monty@analytik>
+
+* Added tty password to mysqlshow.c
+
+Tue Apr 22 15:44:11 1997 Michael Widenius TcX DataKonsulter AB <monty@analytik>
+
+* The test of using MYSQL_PWD was reversed. Now MYSQL_PWD is enabled as default
+ in the default release
+
+Sun Apr 20 14:36:39 1997 <monty@bitch.sci.fi>
+
+* Now one usually only have to give --basedir to mysqld. All other paths
+ are relative in a normal installation.
+* BLOBs contained sometimes garbage when used with a SELECT on more than
+ one table and ORDER BY.
+* Added option --unbuffered to mysql. (For new mysqlaccess)
+* 'select *' without tables crashed server.
+* When using overlapping (unnecessary keys) and join over many tables
+ the optimizer could get confused and return 0 records.
+* Changed safe_mysqld to allow one to move installed releases.
+
+Sun Apr 13 10:40:50 1997 <monty@bitch.sci.fi>
+
+* Release 3.20.17
+* Added new function unix_timestamp([timestamp_column])
+
+Sat Apr 12 11:27:57 1997 <monty@bitch.sci.fi>
+
+* Fixed memory over run bug when using selects with many brace levels.
+* Change from_days() and weekday() to also take a full timestamp or
+ a datetime as argument. Before they only took a number of type YYYYMMDD or
+ YYMMDD.
+
+Wed Apr 9 13:22:24 1997 Michael Widenius <monty@bitch.sci.fi>
+
+* Changed stack usage to use less memory.
+* All communication packages and row buffers are now alloced on demand.
+ The default communication buffers are now smaller than before.
+* count(field) where field could have a NULL value didn't work.
+* IS NULL and IS NOT NULL now work in the WHERE.
+* BLOBs now work in the WHERE.
+* Remove pre-space from numbers when writing decimal() coulmns to file.
+* INSERT INTO ... SELECT .. WHERE could give the error 'Dupplicated field'
+
+Tue Apr 8 16:14:54 1997 Michael Widenius <monty@bitch.sci.fi>
+
+* Added commands SET OPTION SQL_SELECT_LIMIT=# to provide framework
+ for options and to get some ODBC things to work.
+* Fixed bug in SELECT ... two tables ... GROUP BY
+* Fixed bug in INSERT ... SELECT ... GROUP BY
+* Fixed bug in acl: To use FILE_PRIV one also had to have SELECT PRIV
+ in the user grant table.
+* Fixed fatal bug in ranged querie with OR when one part of the query didn't
+ have any matching records.
+
+Mon Apr 7 16:03:00 1997 Michael Widenius <monty@bitch.sci.fi>
+
+* Now connections are allowed even if hostname isn't found.
+ In this case all hostname checks are done on IP.
+* When doing insert on timestamps, the timestamp was set to the
+ current time even if updated by a value.
+* Fixed LOAD DATA.. that if one has COLUMN TERMINATED BY to be same as
+ LINE TERMINATED BY, then LINE TERMINATED BY is set to a empty string.
+ This wasn't a bug, but a common mistake when reading columns separated
+ with newlines.
+
+Sun Apr 6 22:37:53 1997 Michael Widenius <monty@bitch.sci.fi>
+
+* Changed definition of function ELT as it should have been:
+ ELT(index,element,element,element....) now returns the index:s
+ element in the list. The first element has index 1.
+ FIELD(find,string,string,string) searches after the 'find' string
+ in the string list and returns a index to the found string.
+ The strings are compared case insensitive.
+* Added some tests to safe_mysqld to make it 'safer'
+
+Fri Apr 4 02:17:40 1997 Michael Widenius <monty@bitch.sci.fi>
+
+* When sorting the db grant table, host wasn't sorted.
+
+Wed Apr 2 03:00:14 1997 Michael Widenius <monty@bitch.sci.fi>
+
+* Fixed case 'WHERE key_num_column = "string"'
+* LIKE was case sensitive in some places and case insensitive in other.
+ Now LIKE is always case insensitive.
+* Fixed bug in select optimizer when using many tables with the same
+ column used as key to different tables.
+
+Sun Mar 30 21:22:39 1997 Michael Widenius <monty@bitch.sci.fi>
+
+* mysql.cc; Allow '#' anywhere on the line.
+
+Thu Mar 27 02:42:12 1997 Michael Widenius <monty@bitch.sci.fi>
+
+* Added new latin2 and Russian KOI8 character tables.
+* Added support for a dummy GRANT command satisfy Powerbuilder.
+
+Wed Mar 26 03:03:07 1997 Michael Widenius <monty@bitch.sci.fi>
+
+* Release of 3.20.15
+* Removed possible loop when thread waits for command from client
+ and fcntl() fails. Thanks to Mike Bretz for finding this bug
+
+Tue Mar 25 18:03:15 1997 Michael Widenius <monty@bitch.sci.fi>
+
+* Changed alarm loop in mysqld.cc because shutdown didn't always
+ succeed in Linux.
+* Removed use of termbits from mysql.cc This conflicted with glibc 2.0
+* Fixed syntax error in get_password.c (for BSD). Added flush of line.
+* Added test if 'linux' style gethostbyaddr_r in mysqld.cc
+* Fixed bug when doing a select as superuser without a database.
+* Fixed bug when doing SELECT with group calculation to outfile.
+
+Mon Mar 24 16:03:01 1997 Michael Widenius <monty@bitch.sci.fi>
+
+* Release of 3.20.14
+* Added new function SOUNDEX()
+* If one gives '-p' or -password to mysql or mysqladmin without an argument,
+ the password will be asked from the tty.
+
+Sun Mar 23 00:19:42 1997 Michael Widenius <monty@bitch.sci.fi>
+
+* Sometimes when doing a reconnect on a down connection this succeded
+ first on second try. Fixed by removing handling of SIGPIPE in client.
+* When adding a auto_increment key with ALTER_TABLE on got the error:
+ 'Can't write, duplicate key'.
+
+Sat Mar 22 22:55:12 1997 Michael Widenius <monty@bitch.sci.fi>
+
+* AVG() gave too small value on some selects with GROUP BY and ORDER BY.
+
+Fri Mar 21 12:27:32 1997 Michael Widenius <monty@bitch.sci.fi>
+
+* Added new DATETIME type (by Giovanni Maruzzelli <maruzz@matrice.it>)
+* Fixed that define 'DONT_USE_DEFAULT_FIELDS' works
+* Added default password from MYSQL_PWD. (by Elmar Haneke)
+* Changed C++ code to be compatible with Sun Workshop
+
+Thu Mar 20 12:28:06 1997 Michael Widenius TcX DataKonsulter AB <monty@analytik>
+
+* Changed to use a thread to handle alarms instead of signals on Solaris to
+ avoid race conditions.
+* Fixed default length of signed numbers. (George Harvey <georgeh@pinacl.co.uk>)
+* Added commando 'kill' to mysqladmin to kill a specific mysql thread.
+
+Wed Mar 19 12:21:33 1997 Michael Widenius TcX DataKonsulter AB <monty@analytik>
+
+* sql_base.cc: Allow anything for CREATE INDEX.
+
+Mon Mar 17 19:54:11 1997 Michael Widenius TcX DataKonsulter AB <monty@analytik>
+
+* Add prezeros when packing numbers to DATE, TIME and TIMESTAMP.
+* Fixed the OR bug for good.
+
+Fri Mar 14 11:46:54 1997 Michael Widenius <monty@bitch.sci.fi>
+
+* Release 3.20.13
+* Added changes by bonis@kiss.de to allow WHERE const op field
+* Fixed bug in mysql.c when reading long commands from batch.
+* mysqldump.c
+ Changed newlines, return and ASCII 0 to "\n", "\r" and "\0",
+ to allow restoring of columns with these.
+
+Thu Mar 13 20:02:53 1997 Michael Widenius <monty@bitch.sci.fi>
+
+* Fixed bug in select with and-or levels.
+
+Mon Mar 10 04:04:03 1997 Michael Widenius <monty@bitch.sci.fi>
+
+* Added support for Slovenian characters.
+* Fixed bug with limit and order by.
+* Allow order and group on items that isn't in the select list.
+
+Sun Mar 9 00:21:36 1997 Michael Widenius <monty@bitch.sci.fi>
+
+* Added ANSISQL94 DATE and TIME types. Changed TIMESTAMP fields to work better
+ when updateing it with a number.
+
+Sat Mar 8 20:19:21 1997 Michael Widenius <monty@bitch.sci.fi>
+
+* Allow setting of timestamp values in INSERT.
+* Fixed bug with SELECT ... WHERE ... = NULL.
+* Added changes for glibc 2.0
+
+Fri Mar 7 07:53:01 1997 Michael Widenius <monty@bitch.sci.fi>
+
+* Fixed bug in alter table when changeing a not null field to allow NULLs.
+* Added HAVE_READDIR_R as a define which can be removed if one has
+ a broken readdir_r implementation (Sparc/Linux).
+
+Thu Mar 6 21:06:02 1997 Michael Widenius <monty@bitch.sci.fi>
+
+* Added some ANS92 synonyms as field types to CREATE TABLE.
+ CREATE TABLE now allows FLOAT(4) and FLOAT(8) to mean FLOAT and DOUBLE.
+
+Wed Mar 5 00:41:29 1997 Michael Widenius <monty@bitch.sci.fi>
+
+* Release 3.20.11
+* Added sync of records count in sql_update. This fixed slow updates on first
+ connection. (Thanks to Vaclav Bittner for the test)
+* Changed temporary file prefix from UN to MY.
+* When using SELECT .... INTO OUTFILE all temporary tables are ISAM instead of
+ HEAP to allow big dumps.
+* Changed date functions to be 'string functions'. This fixed some 'funny'
+ side effects when sorting on dates.
+
+Tue Mar 4 23:07:03 1997 Michael Widenius <monty@bitch.sci.fi>
+
+* Changed FOREIGN KEY to not create a key. Now it's only for compability.
+* Extended ALTER TABLE according to SQL92.
+* Some minor compability changes.
+* Added --port and --socket to all utility programs and mysqld.
+
+Sat Feb 15 01:27:51 1997 Michael Widenius <monty@bitch.sci.fi>
+
+* Added Oracle command DESCRIBE (DESC) as a synomym for some SHOW commands:
+ DESC table_name <==> SHOW FIELDS FROM table_name
+ DESC table_name column <==> SHOW FIELDS FROM table_name LIKE 'column'
+ DESC table_name 'column' <==> SHOW FIELDS FROM table_name LIKE 'column'
+ mysql.cc thought that tinyblob, mediumblob and longblob was numerical.
+ (Was right adjusted)
+
+Thu Feb 13 00:49:29 1997 Michael Widenius <monty@bitch.sci.fi>
+
+* mediumblob didn't work.
+* Fixed safe_mysqld and make_binary_distribution to work better.
+* ALTER TABLE and changeing a BLOB to a CHAR() added some garabage at
+ string end.
+
+Wed Feb 12 16:10:49 1997 Michael Widenius <monty@bitch.sci.fi>
+
+* new insert type: INSERT INTO ... SELECT ....;
+
+Tue Feb 11 12:58:36 1997 Michael Widenius <monty@bitch.sci.fi>
+
+* Fixed some defines to get mysql to compile on freebsd 2.0 (intel)
+* Removed all _A() from prototype declaration.
+* Removed use of ulong in mysql.h and mysql_com.h
+* Changed mysqldump to dump keynames.
+* SELECT ... INTO OUTFILE 'test' create the file in the base directory
+ instead in database directory (if one didn't give a full path)
+* A primary key is now defined as a key with name PRIMARY or the first
+ unique key if there doesn't exist a key with name PRIMARY.
+
+Mon Feb 10 00:40:48 1997 Michael Widenius <monty@bitch.sci.fi>
+
+* Fixed leak bug when using LOAD DATA into a blob with is sometimes NULL.
+* DROP TABLE can now take a list of tables.
+* If a databas was crashed, in some cases a read of the wrong record
+ was used as a 'end of file', instead of returning an error.
+
+Sat Feb 8 00:16:07 1997 Michael Widenius <monty@bitch.sci.fi>
+
+* merged structs field_t and FIELD to FIELD.
+
+Fri Feb 7 12:49:01 1997 Michael Widenius <monty@bitch.sci.fi>
+
+* version 3.20.9
+* Alter table didn't copy null bit. This resulted that NULL fields where
+ always NULL.
+* CREATE didn't take numbers as DEFAULT.
+
+Wed Feb 5 13:28:19 1997 Michael Widenius <monty@bitch.sci.fi>
+
+* New scripts 'add_file_priv' which add the new field 'file_priv'
+ to the user table. This scripts must be executed if one wants to
+ use the new SELECT ... INTO and LOAD DATA INFILE... commands
+ with a version of mysql less than 3.20.7.
+* Found bug in locking code when another thread got a table opened
+ by another thread. This could make a thread block forever wating
+ for a write lock.
+
+Tue Feb 4 00:57:24 1997 Michael Widenius <monty@bitch.sci.fi>
+
+* Changed select_test.c and insert_test.c to include config.h
+
+Mon Feb 3 00:42:08 1997 Michael Widenius <monty@bitch.sci.fi>
+
+* Add an optional keyname for all key declarators.
+
+Sat Feb 1 19:02:43 1997 Michael Widenius <monty@bitch.sci.fi>
+
+* Added command 'status' to mysqladmin for short logging.
+* Increased max keys to 16 and max key parts to 15.
+
+Fri Jan 31 00:05:23 1997 Michael Widenius <monty@bitch.sci.fi>
+
+* Added ANSI92 extended ALTER TABLE statement.
+* Changed all locking code to detect ALTER table after one got a lock.
+ Tables are automaticly reopened if ALTERed.
+* Changed some structs to classes to get better code when using CREATE TABLE.
+
+Thu Jan 30 01:12:13 1997 Michael Widenius <monty@bitch.sci.fi>
+
+* Added new privilege to the user grant table: file_priv
+* Added some compitibility changes to mysql.cc
+* Added new syntax for creating keys with is a sub part of some field.
+* Did a lot of changes to get around bug when comparing fields of
+ different lengths. Hope I didn't break something else :)
+* Added long options to mysqldump.
+* Added new function NOW().
+
+Wed Jan 29 15:51:22 1997 Michael Widenius <monty@bitch.sci.fi>
+
+* Added option -k for mysqlshow to get key info for table.
+* Changed some definitions from int to uint in mysql.h to get fewer warning
+ with prolint.
+
+Mon Jan 27 02:01:29 1997 Michael Widenius <monty@bitch.sci.fi>
+
+* Added sql command 'load data infile...' for export from textfiles.
+* Added new API function mysql->info to pass info to client.
+* Added INTO OUTFILE as option to select to get result to file.
+
+Fri Jan 24 14:56:19 1997 Michael Widenius <monty@bitch.sci.fi>
+
+* Relase 3.20.5-beta
+* Got first version to work which MIT-threads.
+* Added long options to mysqld
+* mysqld now starts without system locking if compiled with MIT threads.
+* Added new sql function RAND([init])
+* Changed sql_lex to handle \0 unquoted, but the client can't send
+ the query through the C api, because it takes a str pointer.
+ one have to use mysql_real_query() to send the query.
+
+Thu Jan 23 00:33:26 1997 Michael Widenius <monty@bitch.sci.fi>
+
+* Added API function: mysql_get_client_info
+* mysqld now uses the N_MAX_KEY_LENGTH from nisam.h as the max allowed key
+ length.
+* The following now works: "select filter_nr,filter_nr from filter order by
+ filter_nr"
+ Before you got the error: "Column: 'filter_nr' in order clause is ambiguous"
+
+Wed Jan 22 14:48:58 1997 Michael Widenius <monty@bitch.sci.fi>
+
+* Changed fctnl flag O_NDELAY to O_NONBLOCK (Posix, and to get MIT threads
+ to work)
+
+Tue Jan 21 12:31:17 1997 Michael Widenius <monty@bitch.sci.fi>
+
+* mysql now outputs \0 \t \n and \\ when writing tab separated output.
+ when encountering ascii 0, tab, newline or \. This is to allow printing of
+ binary data in a portable format.
+ To get old behavior use -r (or --raw).
+* Added long options to mysqladmin, mysql and mysqlshow.
+* Added german error messages (60 of 80 error messages translated)
+* Added new api function: mysql_fetch_lengths(MYSQL_RES *) which
+ returns a array of of column lengths (of type uint).
+
+Sat Jan 18 23:59:53 1997 Michael Widenius <monty@bitch.sci.fi>
+
+* Fixed bug with IS NULL in where clause.
+
+Fri Jan 17 12:14:38 1997 Michael Widenius <monty@bitch.sci.fi>
+
+* Changed the optimizer a little to get better results when searching on a key
+ part.
+* Added select option STRAIGHT_JOIN to tell the optimizer that it should join
+ tables in the given order.
+
+Thu Jan 16 00:55:41 1997 Michael Widenius <monty@bitch.sci.fi>
+
+* Added support of comment starting with '--' in mysql.cc (Postgres syntax)
+* You can now have select_expressions and table columns in a select which
+ are not used in the group part. This makes it efficient to implement lookups.
+ If the not used column is not a constant for the group the column value
+ is unspecified.
+ Example: SELECT id,lookup.text,sum(*) FROM test,lookup
+ WHERE test.id=lookup.id group by id;
+
+* Fixed bug in sum(function) (Could make core dump)
+* Changed auto_increment according to SQL_SYNTAX:
+ INSERT into table (auto_field) values (0) inserted 0, but the SQL_SYNTAX
+ statied it should insert a auto_incremnt value.
+
+Wed Jan 15 10:42:09 1997 Michael Widenius <monty@bitch.sci.fi>
+
+* mysqlshow.c: Added number of records in table. Had to change the client code a
+ little to fix this.
+* mysql now allows double '' or "" in strings for embedded ' or ".
+* Changed copyright text in mysqlshow and mysqladmin.
+
+Mon Jan 13 02:33:09 1997 Michael Widenius <monty@bitch.sci.fi>
+
+* Relase 3.20.3
+* Using the new readline library from bash.
+* Updated a lot of text files.
+* safe_mysqld and mysql.server changed to be more compatible between the
+ source and the binary releases.
+
+Sun Jan 12 18:23:30 1997 Michael Widenius <monty@bitch.sci.fi>
+
+* LIMIT takes now one or two numerical arguments.
+ If one argument the argument indicates the maximum number of rows in a result.
+ If two arguments the first arguments says the offset to the first row to return,
+ the second is the maximum number of rows.
+ With this it's easy to do a poor mans next page/previous page www application.
+* Changed name of SQL function FIELDS to ELT.
+* Made SHOW COLUMNS a synonym for SHOW FIELDS.
+ Added compatibility syntax FRIEND KEY to create table. This creates in mysql
+ a non unique key on the given columns.
+* Added CREATE INDEX and DROP INDEX as compatibility functions. In mysql
+ CREATE INDEX only checks if the index exists and gives an error if it doesn't
+ exists. DROP INDEX always succeeds.
+
+Sat Jan 11 00:44:29 1997 Michael Widenius <monty@bitch.sci.fi>
+
+* mysqladmin.c: Added client version to version info.
+
+Fri Jan 10 20:30:04 1997 Michael Widenius <monty@bitch.sci.fi>
+
+* Fixed core dump bug in sql_acl (core on new connection).
+* Removed host,user and db tables from database test in the distribution.
+* FIELD_TYPE_CHAR can now be signed (-128 - 127) or unsigned (0 - 255)
+ Before it was always unsigned.
+
+Thu Jan 9 00:02:03 1997 Michael Widenius <monty@bitch.sci.fi>
+
+* Changed name from mysqllib to mysqlclient for mysql client lib.
+* The following failed: concat(1,concat(2),2).
+ Could not call a variable argument function in a variable argument count
+ function. Fixed.
+
+Wed Jan 8 15:58:49 1997 Michael Widenius <monty@bitch.sci.fi>
+
+* weekday() returned wrong day 6 of 7 times.
+
+Mon Jan 6 23:49:31 1997 Michael Widenius <monty@bitch.sci.fi>
+
+* changed a lot of source to get mysqld to be compiled with SUNPRO compiler.
+* sql functions must now have a '(' directly after the function name.
+ user '(' is now regarders as an identifier and a '('
+
+Fri Jan 3 12:18:14 1997 Michael Widenius <monty@bitch.sci.fi>
+
+* Fixed possible bug when sorting with float and double.
+ Changed static sort_length to thread variable. This may have caused some
+ big sorts to fail when running two simultaneous sorts.
+* Changed sql function INTERVALL() to INTERVAL().
+
+Wed Jan 1 16:18:30 1997 Michael Widenius <monty@bitch.sci.fi>
+
+* Added some portability files for testing with RTS threads.
+* Lot of changes for configure.
+
+Sun Dec 29 13:26:52 1996 Michael Widenius <monty@bitch.sci.fi>
+
+* Remove Makefile-linux-pl and Makefile-solaris-pl from the binary distribution.
+ Now only Makefile.PL is needed.
+
+Sat Dec 28 22:41:09 1996 Michael Widenius <monty@bitch.sci.fi>
+
+* Fixed that insert with a timestamp set to NULL works. (This is for a cleaner
+ syntax)
+
+Fri Dec 27 01:28:02 1996 Michael Widenius <monty@bitch.sci.fi>
+
+* mysqld now has english & swedish error messages.
+* unireg files moved to sql directory changed to c++.
+
+Thu Dec 26 11:57:57 1996 Michael Widenius <monty@bitch.sci.fi>
+
+* mysqld: Added option 'b' for mysql basedir. All given directories is
+ prefixed with this if not given with hard path.
+ added option '-L' (language). Default is 'english/'
+ Moved all unireg files to sql directory.
+
+Fri Dec 20 11:05:37 1996 Michael Widenius TcX DataKonsulter AB <monty@ozelot>
+
+* Changed lex to allow a database name, table name and field name to start with
+ number or '_'.
+
+* mysqldump should now be able to dump all field types.
+ Changed 'show fields from table' to be fully compatible with create.
+* Some bugs when parsing 'create table' fixed. (Blobs and timestamps was effected)
+* Fixed one possible dead lock bug when using many tables.
+* Changed a lot for configure
+
+Sun Dec 15 02:29:53 1996 Michael Widenius <monty@bitch.sci.fi>
+
+* Added new functions: INSERT(),RTRIM(),LTRIM(),FORMAT().
+
+* New relase 3.19.5
+* Added functions DATABASE(),USER(),POW(),LOG10() (needed for ODBC).
+
+Sat Dec 14 10:10:42 1996 Michael Widenius <monty@bitch.sci.fi>
+
+* In a WHERE with a ORDER BY on fields from only one table the table is
+ now preferred as first table in a multi-join.
+* HAVING and IS NULL or IS NOT NULL now works.
+* a group on one column and a sort on a group function (SUM,AVG...) didn't
+ work together. Fixed.
+
+Fri Dec 13 07:20:47 1996 Michael Widenius <monty@bitch.sci.fi>
+
+* mysqldump: Didn't send password to server.
+
+* New relase 3.19.4
+* Fixed horrible locking bug when inserting in one thread and reading
+ on another thread.
+* Fixed one-off decimal bug. 1.00 was outputed as 1.0
+* Added attribute 'Locked' to process list as info if a query is
+ locked by another query.
+* Fixed full magic timestamp. Timestamp length may now be 14,12,10,8,6,4 or 2.
+
+Thu Dec 12 18:14:57 1996 Michael Widenius <monty@bitch.sci.fi>
+
+* sort on some number functions could be sorted wrong on last number.
+* if(arg,syntax_error,syntax_error) crashed.
+* added functions ceiling() and round(), exp(), log() and sqrt()
+* enchanted BETWEEN to handle strings.
+
+Wed Dec 11 09:09:02 1996 Michael Widenius <monty@bitch.sci.fi>
+
+* MYODBC: Sometimes password test failed because of faulty charactermap in
+ windows.
+
+Mon Dec 9 12:50:56 1996 Michael Widenius <monty@bitch.sci.fi>
+
+* new relase 3.19.3
+* Fixed that select with grouping on blob's doesn't return wrong blob info.
+ grouping, sorting and distinct on blobs will not yet work as expected
+ (Probably it will group/sort by the first 7 characters in the blob)
+ Groping on formulas with a fixed string size (use mid on blob) should work.
+* When doing a full join (no direct keys) on multiple tables with blob fields,
+ the blob was garbage on output.
+* Fixed distinct with calculated columns.
+
+Sun Dec 8 19:53:24 1996 Michael Widenius <monty@bitch.sci.fi>
+
+* Fixed bug when allocation string for group
+* new release 3.19.2
+* mysqldump.c: Didn't output ' around blobs.
+
+Sat Dec 7 13:00:43 1996 Michael Widenius <monty@bitch.sci.fi>
+
+* Added user flag to mysqldump & mysqlshow.
+* ODBC: Added full support of SQLGetInfo(). Fixed limit bug (from 1.0.3).
+ myodbc-1.0.4 released
+
+Fri Dec 6 01:35:22 1996 Michael Widenius <monty@bitch.sci.fi>
+
+* ODBC: Added more support SetStmtOptions(). Added more debugging code
+ myodbc-1.0.3 released
+
+Tue Dec 3 22:12:30 1996 Michael Widenius <monty@bitch.sci.fi>
+
+* Added 'max_connections' and 'table_cache' as start variables to mysqld.
+* Changed weights in join optimizer: Now prefers to use keys even more:
+ Before the optimizer would prefer to do a full join on small tables
+ (< 300 records), even if there was a usable key.
+
+Mon Dec 2 00:17:42 1996 Michael Widenius <monty@bitch.sci.fi>
+
+* new release 3.19.1
+* Fixed bug when joining tables without keys and null fields and varchars.
+ (mysqld hang)
+* Fixed output of 'mysql show'. All fields was 'unsigned zerofill'.
+
+* new release 3.19.0
+* Added new column specifier AUTO_INCREMENT.
+* Changed format of sql command 'show fields'.
+* Changed mysqlshow to use sql command 'show fields' to get more info.
+* Added synonym RLIKE for REGEXP to be compatible with mSQL
+
+Sun Dec 1 12:53:05 1996 Michael Widenius <monty@bitch.sci.fi>
+
+* item_func.cc (fix_fields): Fixed new bug when calculation and levels.
+ Crashed stack when optimizing where! (fatal bug in 3.18.1)
+
+Fri Nov 29 00:32:09 1996 Michael Widenius <monty@bitch.sci.fi>
+
+* Distribution 3.18.1
+* Fixed optimizeing bug.
+* New ODBC version with traceing in all functions with isn't supported yet
+ for easier debugging. Added NO WARRANTY info.
+ Released as 1.0.2
+
+Wed Nov 27 17:18:51 1996 Michael Widenius TcX DataKonsulter AB <monty@ozelot>
+
+* Added Henry Spencer's regexp in 'field REGEXP string'. Can only be used
+ in select_expression or HAVING until I fix the where clause.
+
+Mon Nov 25 20:01:05 1996 Michael Widenius TcX DataKonsulter AB <monty@ozelot>
+
+* Created files: CREDITS, PUBLIC. Updated FAQ, README, TODO, SQL_SYNTAX...
+* Done a lot of testing on HAVING.
+
+Sun Nov 24 00:45:07 1996 Michael Widenius <monty@bitch.sci.fi>
+
+* mysql didn't stop on error in batch mode even if -f wasn't used.
+* Fixed DBD Makefile.PL for linux
+* Added a function.tst & function.res (test and result file of mysql functions)
+* libmysql.c: Added some checking for calls after connection has gone done.
+* Implemented HAVING with full expr syntax
+* Changed operators '=,
+
+Sat Nov 23 20:52:42 1996 Michael Widenius <monty@bitch.sci.fi>
+
+* SQL_SYNTAX added 'like' as a boolean expression in select.
+* mysqladmin.c: 'mysqladmin garbage' didn't give an error.
+* sql_insert.cc: If one read a deleted record and did a insert with all fields
+ then the new record was marked deleted.
+* perl DBI interface ported.
+
+Thu Nov 21 00:58:44 1996 Michael Widenius <monty@bitch.sci.fi>
+
+* mysql only used the TCP connection, no socket was ever created
+* There was a bug in when reading from getenv(MYSQL_TCP_PORT)
+* Added some more start-logging to check for port & socket.
+* If something got wrong at startup some threads was kept alive in Linux
+* If argument -h to mysqld is a relative path, change it to './'
+* Search after the 'unireg' directory from: current dir,
+ mysqld program dir/.. and in env(MY_BASEDIR_VERSION)
+* Added longlong support to Linux
+* Added copyright notices to all files. Everything should be ready for
+ distribution.
+
+Wed Nov 20 19:03:02 1996 Michael Widenius <monty@bitch.sci.fi>
+
+* Added function IF.
+* Added select without FROM clause (for easy test of functions)
+
+Tue Nov 19 11:48:55 1996 Michael Widenius <monty@bitch.sci.fi>
+
+* mysql.c: Sometimes 'in-string' was not initialized.
+* linux distribution
+
+Mon Nov 18 13:47:09 1996 Michael Widenius <monty@bitch.sci.fi>
+
+* Fixed blob:s to work (as varchar) in ODBC (myodbc-1.0.1.zip)
+* Added option -O to set buffer sizes to mysqld
+
+Wed Nov 13 15:21:14 1996 Michael Widenius <monty@monty.pp.sci.fi>
+
+* New sql functions: REPLACE, LCASE and UCASE
+* hacked search on '%xxx' to work.
+
+Tue Nov 12 00:52:35 1996 Michael Widenius <monty@monty.pp.sci.fi>
+
+* mysql.cc: Fixed problems with strings containing not backslashed ' or ".
+
+Mon Nov 11 14:52:30 1996 Michael Widenius <monty@monty.pp.sci.fi>
+
+* added braces to where clause. Change where to use items.
+
+Wed Nov 6 00:17:37 1996 Michael Widenius <monty@analytikerna.se>
+
+* added PRIMARY KEY, KEY and UNIQUE to sql create.
diff --git a/sql/Makefile.am b/sql/Makefile.am
new file mode 100644
index 00000000000..a4aee97d0bb
--- /dev/null
+++ b/sql/Makefile.am
@@ -0,0 +1,126 @@
+# Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public 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
+
+
+MYSQLDATAdir = $(localstatedir)
+MYSQLSHAREdir = $(pkgdatadir)
+MYSQLBASEdir= $(prefix)
+INCLUDES = @MT_INCLUDES@ @bdb_includes@ -I$(srcdir)/../include \
+ -I$(srcdir)/../regex \
+ -I$(srcdir) -I../include -I.. -I.
+WRAPLIBS= @WRAPLIBS@
+SUBDIRS = share
+bin_PROGRAMS = mysqlbinlog
+libexec_PROGRAMS = mysqld
+noinst_PROGRAMS = gen_lex_hash
+LDADD = ../isam/libnisam.a \
+ ../merge/libmerge.a \
+ ../myisam/libmyisam.a \
+ ../myisammrg/libmyisammrg.a \
+ ../heap/libheap.a \
+ ../mysys/libmysys.a \
+ ../dbug/libdbug.a \
+ ../regex/libregex.a \
+ ../strings/libmystrings.a
+mysqld_LDADD = @MYSQLD_EXTRA_LDFLAGS@ @bdb_libs@ $(LDADD) $(CXXLDFLAGS) $(WRAPLIBS)
+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 \
+ procedure.h sql_class.h sql_lex.h sql_list.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\
+ opt_range.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 \
+ log_event.h mini_client.h
+mysqld_SOURCES = sql_lex.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 \
+ sql_string.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 \
+ procedure.cc item_uniq.cc sql_test.cc \
+ log.cc init.cc derror.cc sql_acl.cc unireg.cc \
+ time.cc opt_range.cc opt_sum.cc \
+ records.cc filesort.cc handler.cc \
+ ha_isam.cc ha_isammrg.cc ha_heap.cc \
+ ha_myisam.cc ha_myisammrg.cc ha_berkeley.cc \
+ sql_db.cc sql_table.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 \
+ md5.c log_event.cc mini_client.cc mini_client_errors.c
+gen_lex_hash_SOURCES = gen_lex_hash.cc
+gen_lex_hash_LDADD = $(LDADD) $(CXXLDFLAGS)
+mysqlbinlog_SOURCES = mysqlbinlog.cc mini_client.cc net_serv.cc \
+ mini_client_errors.c violite.c password.c
+mysqlbinlog_LDADD = $(LDADD) $(CXXLDFLAGS)
+
+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 = sql_yacc.cc sql_yacc.h
+EXTRA_DIST = udf_example.cc $(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
+
+gen_lex_hash.o: gen_lex_hash.cc lex.h
+ $(CXXCOMPILE) -c $(INCLUDES) $<
+
+# Try to get better dependencies for the grammar. Othervise really bad
+# things like different grammars for different pars of MySQL can
+# happen if you are unlucky.
+sql_yacc.cc: sql_yacc.yy
+sql_yacc.h: sql_yacc.yy
+
+sql_yacc.o: sql_yacc.cc sql_yacc.h
+ @echo "Note: The folloing compile may take a long time."
+ @echo "If it fails, re-run configure with --with-low-memory"
+ $(CXXCOMPILE) $(LM_CFLAGS) -c $<
+
+lex_hash.h: lex.h gen_lex_hash.cc sql_yacc.h
+ $(MAKE) gen_lex_hash
+ ./gen_lex_hash > $@
+
+# Hack to ensure that lex_hash.h is built early
+sql_lex.o: lex_hash.h
+
+#distclean:
+# rm -f lex_hash.h
diff --git a/sql/add_errmsg b/sql/add_errmsg
new file mode 100755
index 00000000000..cf54ede5dce
--- /dev/null
+++ b/sql/add_errmsg
@@ -0,0 +1,17 @@
+#!/bin/sh
+
+if test $# -ne 1
+then
+ echo "Copies # error messages from share/english/errmsg.txt to other message files"
+ echo "Usage: $0 number_of_messages_to_copy"
+ exit 1;
+fi
+
+FILE=/tmp/add.$$
+tail -$1 share/english/errmsg.txt > $FILE
+for i in `ls share/*/errmsg.txt | grep -v english`
+do
+ cat $FILE >> $i
+done
+rm $FILE
+
diff --git a/sql/cache_manager.cc b/sql/cache_manager.cc
new file mode 100644
index 00000000000..9ea25315f8c
--- /dev/null
+++ b/sql/cache_manager.cc
@@ -0,0 +1,150 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#ifdef __GNUC__
+#pragma implementation /* gcc: Class implementation */
+#endif
+
+#include <global.h>
+#include <my_sys.h>
+#include "cache_manager.h"
+
+/*
+ cache_manager.cc
+ -----------------------------------------------------------------------
+ The cache_manager class manages a number of blocks (which are allocatable
+ units of memory).
+ -----------------------------------------------------------------------
+*/
+
+#define HEADER_LENGTH ALIGN_SIZE(8)
+#define SUFFIX_LENGTH 4
+
+#define ALLOC_MASK 0x3FFFFFFFL
+#define FREE_BIT (1L << 31)
+#define LOCK_BIT (1L << 30)
+#define SMALLEST_BLOCK 32
+
+
+
+/*
+** Internal Methods
+** --------------------
+*/
+
+
+/* list manipulation methods */
+void *cache_manager::init_list(void)
+{
+
+return;
+}
+
+
+void *cache_manager::link_into_abs(void *ptr)
+{
+ for (int i(0); (*abs_list)[i] != NULL; i++);
+
+ (*abs_list)[i] = ptr;
+
+ return (abs_list)[i]; // ???
+}
+
+
+
+bool *cache_manager::unlink_from_abs(void *ptr)
+{
+ (*ptr) = NULL;
+
+return;
+}
+
+
+
+/* memory allocation methods */
+void *cache_manager::find_in_llist(uint)
+{
+
+return;
+}
+
+
+void cache_manager::defrag(void)
+{
+ printf("Defragging: ..........");
+
+ return;
+}
+
+
+
+/*
+** Public Methods
+** ------------------
+*/
+
+cache_manager::cache_manager(uint size)
+{
+ base_ptr = my_malloc(size, MY_WME); /* MY_WME = write mesg on err */
+
+ return;
+}
+
+
+cache_manager::~cache_manager(void)
+{
+ free(base_ptr);
+ delete base_ptr;
+
+ return;
+}
+
+
+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)))
+ {
+ //defrag();
+ if (!(llist = find_in_llist(size)))
+ return 0; /* return null pointer, buffer exhausted! */
+ }
+ 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;
+}
+
+
+void cache_manager::dealloc(void)
+{
+ printf("Deallocating: ..........\n");
+
+ return;
+}
+
+
+
+void cache_manager::clear(void)
+{
+ // reset the internal linked list, forgetting all pointers to mem blks
+
+ return;
+}
diff --git a/sql/cache_manager.h b/sql/cache_manager.h
new file mode 100644
index 00000000000..fc3b8f7016a
--- /dev/null
+++ b/sql/cache_manager.h
@@ -0,0 +1,65 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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
+
+#ifndef _CACHE_MANAGER_H_
+#define _CACHE_MANAGER_H_
+#endif
+
+/*
+ cache_manager.h
+ -----------------------------------------------------------------------
+ The cache_manager class manages a number of blocks (which are allocatable
+ units of memory).
+ -----------------------------------------------------------------------
+*/
+
+
+
+class cache_manager {
+ void **abs_list; /* List holding block abstraction ptrs */
+
+ typedef struct free_blks {
+ struct free_blks *next, **prev;
+ uint Size;
+ } FREE_BLKS;
+ FREE_BLKS *base_ptr; /* Pointer to newly allocated sys mem */
+
+
+ /* list manipulation methods */
+ void *link_into_abs(void *); /* Return an abstract pointer to blk */
+ bool *unlink_from_abs(void *); /* Used to dealloc a blk */
+ void *find_in_fblist(uint); /* */
+
+ /* memory allocation methods */
+ void defrag(void); /* Defragment the cache */
+ bool *init_blk(void *); /* Return a pointer to new list */
+
+ public:
+ cache_manager(uint); /* Get allocation of size from system */
+ ~cache_manager(void); /* Destructor; return the cache */
+
+ void *alloc(uint); /* Alloc size bytes from the cache */
+ bool *dealloc(void *); /* Deallocate blocks (with *ptr_arg) */
+ void clear(void); /* Clear the cache */
+};
+
+
+
+
diff --git a/sql/convert.cc b/sql/convert.cc
new file mode 100644
index 00000000000..3e0fbf18ace
--- /dev/null
+++ b/sql/convert.cc
@@ -0,0 +1,465 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+
+/*
+** Convert tables between different character sets
+** Some of the tables are hidden behind IFDEF to reduce some space.
+** One can enable them by removing the // characters from the next comment
+** One must also give a name to each mapping that one wants to use...
+*/
+
+/* #define DEFINE_ALL_CHARACTER_SETS */
+
+#include "mysql_priv.h"
+
+/****************************************************************************
+** Convert tables
+****************************************************************************/
+
+/* Windows cp1251->koi8 and reverse conversion by Timur I. Bakeyev <translate@bat.ru> */
+/* based on Russian-Apache Team tables by Dmitry M. Klimoff <dmk@kosnet.ru> */
+
+static unsigned char cp1251_koi8[256] = {
+ 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, 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,189,166,167,179,169,180,171,172,173,174,183,
+176,177,182,166,173,181,182,183,163,185,164,187,188,189,190,167,
+225,226,247,231,228,229,246,250,233,234,235,236,237,238,239,240,
+242,243,244,245,230,232,227,254,251,253,255,249,248,252,224,241,
+193,194,215,199,196,197,214,218,201,202,203,204,205,206,207,208,
+210,211,212,213,198,200,195,222,219,221,223,217,216,220,192,209
+};
+
+static unsigned char koi8_cp1251[256] = {
+ 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, 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,184,186,165,179,191,168,169,170,171,172,180,174,175,
+176,177,178,168,170,181,178,175,184,185,186,187,188,165,190,191,
+254,224,225,246,228,229,244,227,245,232,233,234,235,236,237,238,
+239,255,240,241,242,243,230,226,252,251,231,248,253,249,247,250,
+222,192,193,214,196,197,212,195,213,200,201,202,203,204,205,206,
+207,223,208,209,210,211,198,194,220,219,199,216,221,217,215,218
+};
+
+
+#ifdef DEFINE_ALL_CHARACTER_SETS
+
+/* These tables was generated from package 'cstools' (author Jan "Yenya" Kasprzak <kas@muni.cz>) */
+
+/* Windows pc1250 to iso 8859-2 */
+
+static unsigned char t1250_til2[256] = {
+ 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, 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, 0,131, 0, 0, 0, 0,136, 0,169, 0,166,171,174,172,
+144, 0, 0, 0, 0, 0, 0, 0,152, 0,185, 0,182,187,190,188,
+160,183,162,163,164,161, 0,167,168, 0,170, 0, 0,173, 0,175,
+176, 0,178,179,180, 0, 0, 0,184,177,186, 0,165,189,181,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,
+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
+};
+
+static unsigned char til2_t1250[256] = {
+ 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, 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, 0,131, 0, 0, 0, 0,136, 0, 0, 0, 0, 0, 0, 0,
+144, 0, 0, 0, 0, 0, 0, 0,152, 0, 0, 0, 0, 0, 0, 0,
+160,165,162,163,164,188,140,167,168,138,170,141,143,173,142,175,
+176,185,178,179,180,190,156,161,184,154,186,157,159,189,158,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,
+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
+};
+
+/* Windows pc1252 to iso 8859-2 */
+
+static unsigned char t1252_til2[256] = {
+ 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, 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, 0, 0, 0, 0, 0, 0,136, 0,169, 0, 0,141,142,143,
+144, 0, 0, 0, 0, 0, 0, 0,189, 0,185, 0, 0,157,158, 0,
+160, 0, 0, 0,164, 0, 0,167,168, 0, 0, 0, 0,173, 0, 0,
+176, 0, 0, 0,180, 0, 0, 0,184, 0, 0, 0, 0, 0, 0, 0,
+ 0,193,194, 0,196, 0, 0,199, 0,201, 0,203, 0,205,206, 0,
+208, 0, 0,211,212, 0,214,215, 0, 0,218, 0,220,221, 0,223,
+ 0,225,226, 0,228, 0, 0,231, 0,233, 0,235, 0,237,238, 0,
+240, 0, 0,243,244, 0,246,247, 0, 0,250, 0,252,253, 0, 0
+};
+static unsigned char til2_t1252[256] = {
+ 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, 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, 0, 0, 0, 0, 0, 0,136, 0, 0, 0, 0,141,142,143,
+144, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,157,158, 0,
+160, 0, 0, 0,164, 0, 0,167,168,138, 0, 0, 0,173, 0, 0,
+176, 0, 0, 0,180, 0, 0, 0,184,154, 0, 0, 0,152, 0, 0,
+ 0,193,194, 0,196, 0, 0,199, 0,201, 0,203, 0,205,206, 0,
+208, 0, 0,211,212, 0,214,215, 0, 0,218, 0,220,221, 0,223,
+ 0,225,226, 0,228, 0, 0,231, 0,233, 0,235, 0,237,238, 0,
+240, 0, 0,243,244, 0,246,247, 0, 0,250, 0,252,253, 0, 0
+};
+
+/* MSDOS Kamenicky encoding (for Czech/Slovak) to iso 8859-2 */
+
+static unsigned char tkam_til2[256] = {
+ 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, 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,
+200,252,233,239,228,207,171,232,236,204,197,205,181,229,196,193,
+201,190,174,244,246,211,249,218,253,214,220,169,165,221,216,187,
+225,237,243,250,242,210,217,212,185,248,224,192, 0,167, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,247, 0,176, 0, 0, 0, 0, 0, 0, 0
+};
+static unsigned char til2_tkam[256] = {
+ 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, 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,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,156, 0,173, 0,155, 0,134, 0, 0,146, 0,
+248, 0, 0, 0, 0,140, 0, 0, 0,168, 0,159, 0, 0,145, 0,
+171,143, 0, 0,142,138, 0, 0,128,144, 0, 0,137,139, 0,133,
+ 0, 0,165,149,167, 0,153, 0,158,166,151, 0,154,157, 0, 0,
+170,160, 0, 0,132,141, 0, 0,135,130, 0, 0,136,161, 0,131,
+ 0, 0,164,162,147, 0,148,246,169,150,163, 0,129,152, 0, 0
+};
+
+/* Macintosh Roman encoding to iso 8859-2 */
+
+static unsigned char tmac_til2[256] = {
+ 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, 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,
+196, 0,199,201, 0,214,220,225, 0,226,228, 0, 0,231,233, 0,
+ 0,235,237, 0,238, 0, 0,243, 0,244,246, 0,250, 0, 0,252,
+ 0,176, 0, 0,167, 0, 0,223, 0, 0, 0,180,168, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,160, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,247, 0, 0, 0, 0,164, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,194, 0,193,203, 0,205,206, 0, 0,211,212,
+ 0, 0,218, 0, 0, 0, 0, 0, 0,162,255, 0,184,189,178,183
+};
+static unsigned char til2_tmac[256] = {
+ 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, 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,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+202, 0,249, 0,219, 0, 0,164,172, 0, 0, 0, 0, 0, 0, 0,
+161, 0,254, 0,171, 0, 0,255,252, 0, 0, 0, 0,253, 0, 0,
+ 0,231,229, 0,128, 0, 0,130, 0,131, 0,232, 0,234,235, 0,
+ 0, 0, 0,238,239, 0,133, 0, 0, 0,242, 0,134, 0, 0,167,
+ 0,135,137, 0,138, 0, 0,141, 0,142, 0,145, 0,146,148, 0,
+ 0, 0, 0,151,153, 0,154,214, 0, 0,156, 0,159, 0, 0,250
+};
+
+/* Macintosh Central European encodingto iso 8859-2 */
+
+static unsigned char tmacce_til2[256] = {
+ 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, 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,
+196, 0, 0,201,161,214,220,225,177,200,228,232,198,230,233,172,
+188,207,237,239, 0, 0, 0,243, 0,244,246, 0,250,204,236,252,
+ 0,176,202, 0,167, 0, 0,223, 0, 0, 0,234,168, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,179, 0, 0,165,181,197,229, 0,
+ 0,209, 0, 0,241,210, 0, 0, 0, 0,160,242,213, 0,245, 0,
+ 0, 0, 0, 0, 0, 0,247, 0, 0,192,224,216, 0, 0,248, 0,
+ 0,169, 0, 0,185,166,182,193,171,187,205,174,190, 0,211,212,
+ 0,217,218,249,219,251, 0, 0,221,253, 0,175,163,191, 0,183
+};
+static unsigned char til2_tmacce[256] = {
+ 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, 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,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+202,132, 0,252, 0,187,229,164,172,225, 0,232,143, 0,235,251,
+161,136, 0,184, 0,188,230,255, 0,228, 0,233,144, 0,236,253,
+217,231, 0, 0,128,189,140, 0,137,131,162, 0,157,234, 0,145,
+ 0,193,197,238,239,204,133, 0,219,241,242,244,134,248, 0,167,
+218,135, 0, 0,138,190,141, 0,139,142,171, 0,158,146, 0,147,
+ 0,196,203,151,153,206,154,214,222,243,156,245,159,249, 0, 0
+};
+
+/* PC-Latin2 encoding, supported by M$-DOS to iso 8859-2 */
+
+static unsigned char tpc2_til2[256] = {
+ 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, 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,
+199,252,233,226,228,249,230,231,179,235,213,245,238,172,196,198,
+201,197,229,244,246,165,181,166,182,214,220,171,187,163,215,232,
+225,237,243,250,161,177,174,190,202,234, 0,188,200,186, 0, 0,
+ 0, 0, 0, 0, 0,193,194,204,170, 0, 0, 0, 0,175,191, 0,
+ 0, 0, 0, 0, 0, 0,195,227, 0, 0, 0, 0, 0, 0, 0,164,
+240,208,207,203,239,210,205,206,236, 0, 0, 0, 0,222,217, 0,
+211,223,212,209,241,242,169,185,192,218,224,219,253,221,254,180,
+ 0,189,178,183,162,167,247,184, 0,168,255,251,216,248, 0, 0
+};
+static unsigned char til2_tpc2[256] = {
+ 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, 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,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,164,244,157,207,149,151,245,249,230,184,155,141, 0,166,189,
+ 0,165,242,136,239,150,152,243,247,231,173,156,171,241,167,190,
+232,181,182,198,142,145,143,128,172,144,168,211,183,214,215,210,
+209,227,213,224,226,138,153,158,252,222,233,235,154,237,221,225,
+234,160,131,199,132,146,134,135,159,130,169,137,216,161,140,212,
+208,228,229,162,147,139,148,246,253,133,163,251,129,236,238,250
+};
+
+/* Encoding used by standard IBM PC vga cards to iso8859-2 */
+static unsigned char tvga_til2[256] = {
+ 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, 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,
+199,252,233,226,228, 0, 0,231, 0,235, 0, 0,238, 0,196, 0,
+201, 0, 0,244,246, 0, 0, 0, 0,214,220, 0, 0, 0, 0, 0,
+225,237,243,250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,247, 0,176, 0, 0, 0, 0, 0, 0, 0
+};
+static unsigned char til2_tvga[256] = {
+ 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, 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,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,142, 0, 0,128, 0,144, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,153, 0, 0, 0, 0, 0,154, 0, 0, 0,
+ 0,160,131, 0,132, 0, 0,135, 0,130, 0,137, 0,161,140, 0,
+ 0, 0, 0,162,147, 0,148,246, 0, 0,163, 0,129, 0, 0, 0
+};
+
+//Ukrainian koi8 and win1251 converting tables by Max Veremayenko
+//(verem@tg.kiev.ua
+
+static unsigned char koi8_ukr_win1251ukr[256] = {
+ 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, 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,184,186,165,179,191,168,169,170,171,172,180,174,175,
+176,177,178,168,170,181,178,175,184,185,186,187,188,165,190,191,
+254,224,225,246,228,229,244,227,245,232,233,234,235,236,237,238,
+239,255,240,241,242,243,230,226,252,251,231,248,253,249,247,250,
+222,192,193,214,196,197,212,195,213,200,201,202,203,204,205,206,
+207,223,208,209,210,211,198,194,220,219,199,216,221,217,215,218
+};
+
+static unsigned char win1251ukr_koi8_ukr[256] = {
+ 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, 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,189,166,167,179,169,180,171,172,173,174,183,
+176,177,182,166,173,181,182,183,163,185,164,187,188,189,190,167,
+225,226,247,231,228,229,246,250,233,234,235,236,237,238,239,240,
+242,243,244,245,230,232,227,254,251,253,255,249,248,252,224,241,
+193,194,215,199,196,197,214,218,201,202,203,204,205,206,207,208,
+210,211,212,213,198,200,195,222,219,221,223,217,216,220,192,209
+};
+
+#endif /* DEFINE_ALL_CHARACTER_SETS */
+
+/****************************************************************************
+** Declare mapping variables
+****************************************************************************/
+
+
+CONVERT conv_cp1251_koi8("cp1251_koi8", cp1251_koi8, koi8_cp1251);
+#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_win1251ukr_koi8_ukr("win1251ukr_koi8_ukr", win1251ukr_koi8_ukr,
+ koi8_ukr_win1251ukr);
+CONVERT conv_koi8_ukr_win1251ukr("koi8_ukr_win1251ukr", koi8_ukr_win1251ukr,
+ win1251ukr_koi8_ukr);
+#endif /* DEFINE_ALL_CHARACTER_SETS */
+
+CONVERT *convert_tables[]= {
+ &conv_cp1251_koi8,
+#ifdef DEFINE_ALL_CHARACTER_SETS
+ &conv_cp1250_latin2,
+ &conv_kam_latin2,
+ &conv_mac_latin2,
+ &conv_macce_latin2,
+ &conv_pc2_latin2,
+ &conv_vga_latin2,
+ &conv_koi8_cp1251,
+ &conv_win1251ukr_koi8_ukr,
+ &conv_koi8_ukr_win1251ukr,
+#endif /* DEFINE_ALL_CHARACTER_SETS */
+ NULL
+};
+
+
+CONVERT *get_convert_set(const char *name)
+{
+ for (CONVERT **ptr=convert_tables ; *ptr ; ptr++)
+ {
+ if (!my_strcasecmp((*ptr)->name,name))
+ return (*ptr);
+ }
+ return 0;
+}
+
+
+void CONVERT::convert_array(const uchar *map, uchar * buf, uint len)
+{
+ for (uchar *end=buf+len ; buf != end ; buf++)
+ *buf= map[*buf];
+}
+
+
+/* This is identical as net_store_data, but with a conversion */
+
+bool CONVERT::store(String *packet,const char *from,uint length)
+{
+ uint packet_length=packet->length();
+ if (packet_length+5+length > packet->alloced_length() &&
+ packet->realloc(packet_length+5+length))
+ return 1;
+ char *to=(char*) net_store_length((char*) packet->ptr()+packet_length,
+ length);
+
+ for (const char *end=from+length ; from != end ; from++)
+ *to++= to_map[(uchar) *from];
+ packet->length((uint) (to-packet->ptr()));
+ return 0;
+}
diff --git a/sql/custom_conf.h b/sql/custom_conf.h
new file mode 100644
index 00000000000..af6012e28ec
--- /dev/null
+++ b/sql/custom_conf.h
@@ -0,0 +1,28 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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_CUSTOM_BUILD_CONFIG__
+#define __MYSQL_CUSTOM_BUILD_CONFIG__
+
+#define MYSQL_PORT 5002
+#ifdef __WIN__
+#define MYSQL_NAMEDPIPE "SwSqlServer"
+#define MYSQL_SERVICENAME "SwSqlServer"
+#define KEY_SERVICE_PARAMETERS
+"SYSTEM\\CurrentControlSet\\Services\\SwSqlServer\\Parameters"
+#endif
+
+#endif /* __MYSQL_CUSTOM_BUILD_CONFIG__ */
diff --git a/sql/derror.cc b/sql/derror.cc
new file mode 100644
index 00000000000..3b29d2c511b
--- /dev/null
+++ b/sql/derror.cc
@@ -0,0 +1,146 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 language depeneded messagefile */
+
+#include "mysql_priv.h"
+#include "mysys_err.h"
+
+static void read_texts(const char *file_name,const char ***point,
+ uint error_messages);
+static void init_myfunc_errs(void);
+
+ /* Read messages from errorfile */
+
+void init_errmessage(void)
+{
+ DBUG_ENTER("init_errmessage");
+
+ read_texts(ERRMSG_FILE,&errmsg[ERRMAPP],ER_ERROR_MESSAGES);
+ errmesg=errmsg[ERRMAPP]; /* Init global variabel */
+ init_myfunc_errs(); /* Init myfunc messages */
+ DBUG_VOID_RETURN;
+}
+
+
+ /* Read text from packed textfile in language-directory */
+ /* If we can't read messagefile then it's panic- we can't continue */
+
+static void read_texts(const char *file_name,const char ***point,
+ uint error_messages)
+{
+ register uint i;
+ uint ant,funktpos,length,textant;
+ File file;
+ char name[FN_REFLEN];
+ const char *buff;
+ uchar head[32],*pos;
+ DBUG_ENTER("read_texts");
+
+ LINT_INIT(buff);
+ funktpos=0;
+ if ((file=my_open(fn_format(name,file_name,language,"",4),
+ O_RDONLY | O_SHARE | O_BINARY,
+ MYF(0))) < 0)
+ goto err; /* purecov: inspected */
+
+ funktpos=1;
+ if (my_read(file,(byte*) head,32,MYF(MY_NABP))) goto err;
+ 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);
+
+ if (ant < 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);
+ VOID(my_close(file,MYF(MY_WME)));
+ clean_up(); /* Clean_up frees everything */
+ exit(1); /* We can't continue */
+ }
+
+ x_free((gptr) *point); /* Free old language */
+ if (!(*point= (const char**)
+ my_malloc((uint) (length+ant*sizeof(char*)),MYF(0))))
+ {
+ funktpos=2; /* purecov: inspected */
+ goto err; /* purecov: inspected */
+ }
+ buff= (char*) (*point + ant);
+
+ if (my_read(file,(byte*) buff,(uint) ant*2,MYF(MY_NABP))) goto err;
+ for (i=0, pos= (uchar*) buff ; i< ant ; 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++)
+ {
+ point[i]= *point +uint2korr(head+10+i+i);
+ }
+ VOID(my_close(file,MYF(0)));
+ DBUG_VOID_RETURN;
+
+err:
+ switch (funktpos) {
+ case 2:
+ buff="\n%s: Fatal error: Not enough memory for messagefile '%s'\n\n";
+ break;
+ case 1:
+ buff="\n%s: Fatal error: Can't read from messagefile '%s'\n\n";
+ break;
+ default:
+ buff="\n%s: Fatal error: Can't find messagefile '%s'\n\n";
+ break;
+ }
+ if (file != FERR)
+ VOID(my_close(file,MYF(MY_WME)));
+ fprintf(stderr,buff,my_progname,name);
+ clean_up(); /* Clean_up frees everything */
+ exit(1); /* We can't continue */
+} /* read_texts */
+
+
+ /* Initiates error-messages used by my_func-library */
+
+static void init_myfunc_errs()
+{
+ init_glob_errs(); /* Initiate english errors */
+ if (!(specialflag & SPECIAL_ENGLISH))
+ {
+ globerrs[EE_FILENOTFOUND % ERRMOD] = ER(ER_FILE_NOT_FOUND);
+ globerrs[EE_CANTCREATEFILE % ERRMOD]= ER(ER_CANT_CREATE_FILE);
+ globerrs[EE_READ % ERRMOD] = ER(ER_ERROR_ON_READ);
+ globerrs[EE_WRITE % ERRMOD] = ER(ER_ERROR_ON_WRITE);
+ globerrs[EE_BADCLOSE % ERRMOD] = ER(ER_ERROR_ON_CLOSE);
+ globerrs[EE_OUTOFMEMORY % ERRMOD] = ER(ER_OUTOFMEMORY);
+ globerrs[EE_DELETE % ERRMOD] = ER(ER_CANT_DELETE_FILE);
+ globerrs[EE_LINK % ERRMOD] = ER(ER_ERROR_ON_RENAME);
+ globerrs[EE_EOFERR % ERRMOD] = ER(ER_UNEXPECTED_EOF);
+ globerrs[EE_CANTLOCK % ERRMOD] = ER(ER_CANT_LOCK);
+ globerrs[EE_DIR % ERRMOD] = ER(ER_CANT_READ_DIR);
+ globerrs[EE_STAT % ERRMOD] = ER(ER_CANT_GET_STAT);
+ globerrs[EE_GETWD % ERRMOD] = ER(ER_CANT_GET_WD);
+ globerrs[EE_SETWD % ERRMOD] = ER(ER_CANT_SET_WD);
+ globerrs[EE_DISK_FULL % ERRMOD] = ER(ER_DISK_FULL);
+ }
+}
diff --git a/sql/field.cc b/sql/field.cc
new file mode 100644
index 00000000000..c903ea456a5
--- /dev/null
+++ b/sql/field.cc
@@ -0,0 +1,4576 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+
+/*
+ NOTES:
+ Some of the number class uses the system functions strtol(), strtoll()...
+ To avoid patching the end \0 or copying the buffer unnecessary, all calls
+ to system functions are wrapped to a String object that adds the end null
+ if it only if it isn't there.
+ This adds some overhead when assigning numbers from strings but makes
+ everything simpler.
+ */
+
+/*****************************************************************************
+** This file implements classes defined in field.h
+*****************************************************************************/
+
+#ifdef __GNUC__
+#pragma implementation // gcc: Class implementation
+#endif
+
+#include "mysql_priv.h"
+#include "sql_select.h"
+#include <m_ctype.h>
+#include <errno.h>
+#ifdef HAVE_FCONVERT
+#include <floatingpoint.h>
+#endif
+
+/*****************************************************************************
+** Instansiate templates and static variables
+*****************************************************************************/
+
+#ifdef __GNUC__
+template class List<create_field>;
+template class List_iterator<create_field>;
+#endif
+
+struct st_decstr {
+ uint nr_length,nr_dec,sign,extra;
+ char sign_char;
+};
+
+uchar Field_null::null[1]={1};
+const char field_separator=',';
+
+/*****************************************************************************
+** Static help functions
+*****************************************************************************/
+
+ /*
+ ** Calculate length of number and it's parts
+ ** Increment cuted_fields if wrong number
+ */
+
+static bool
+number_dec(struct st_decstr *sdec, const char *str, const char *end)
+{
+ sdec->sign=sdec->extra=0;
+ if (str == end)
+ {
+ current_thd->cuted_fields++;
+ sdec->nr_length=sdec->nr_dec=sdec->sign=0;
+ sdec->extra=1; // We must put one 0 before .
+ return 1;
+ }
+
+ if (*str == '-' || *str == '+') /* sign */
+ {
+ sdec->sign_char= *str;
+ sdec->sign=1;
+ str++;
+ }
+ const char *start=str;
+ while (str != end && isdigit(*str))
+ str++;
+ if (!(sdec->nr_length=(uint) (str-start)))
+ sdec->extra=1; // We must put one 0 before .
+ start=str;
+ if (str != end && *str == '.')
+ {
+ str++;
+ start=str;
+ while (str != end && isdigit(*str))
+ str++;
+ }
+ sdec->nr_dec=(uint) (str-start);
+ if (current_thd->count_cuted_fields)
+ {
+ while (str != end && isspace(*str))
+ str++; /* purecov: inspected */
+ if (str != end)
+ {
+ current_thd->cuted_fields++;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+
+void Field_num::prepend_zeros(String *value)
+{
+ int diff;
+ if ((diff= (int) (field_length - value->length())) > 0)
+ {
+ bmove_upp((char*) value->ptr()+field_length,value->ptr()+value->length(),
+ value->length());
+ bfill((char*) value->ptr(),diff,'0');
+ value->length(field_length);
+ (void) value->c_ptr_quick(); // Avoid warnings in purify
+ }
+}
+
+/*
+** Test if given number is a int (or a fixed format float with .000)
+** This is only used to give warnings in ALTER TABLE or LOAD DATA...
+*/
+
+bool test_if_int(const char *str,int length)
+{
+ const char *end=str+length;
+
+ while (str != end && isspace(*str)) // Allow start space
+ str++; /* purecov: inspected */
+ if (str != end && (*str == '-' || *str == '+'))
+ str++;
+ if (str == end)
+ return 0; // Error: Empty string
+ for ( ; str != end ; str++)
+ {
+ if (!isdigit(*str))
+ {
+ if (*str == '.')
+ { // Allow '.0000'
+ for (str++ ; str != end && *str == '0'; str++) ;
+ if (str == end)
+ return 1;
+ }
+ if (!isspace(*str))
+ return 0;
+ for (str++ ; str != end ; str++)
+ if (!isspace(*str))
+ return 0;
+ return 1;
+ }
+ }
+ return 1;
+}
+
+
+static bool test_if_real(const char *str,int length)
+{
+ while (length && isspace(*str))
+ { // Allow start space
+ length--; str++;
+ }
+ if (!length)
+ return 0;
+ if (*str == '+' || *str == '-')
+ {
+ length--; str++;
+ if (!length || !(isdigit(*str) || *str == '.'))
+ return 0;
+ }
+ while (length && isdigit(*str))
+ {
+ length--; str++;
+ }
+ if (!length)
+ return 1;
+ if (*str == '.')
+ {
+ length--; str++;
+ while (length && isdigit(*str))
+ {
+ length--; str++;
+ }
+ }
+ if (!length)
+ return 1;
+ if (*str == 'E' || *str == 'e')
+ {
+ if (length < 3 || (str[1] != '+' && str[1] != '-') || !isdigit(str[2]))
+ return 0;
+ length-=3;
+ str+=3;
+ while (length && isdigit(*str))
+ {
+ length--; str++;
+ }
+ }
+ for ( ; length ; length--, str++)
+ { // Allow end space
+ if (!isspace(*str))
+ return 0;
+ }
+ return 1;
+}
+
+
+/****************************************************************************
+** Functions for the base classes
+** This is a unpacked number.
+****************************************************************************/
+
+Field::Field(char *ptr_arg,uint32 length_arg,uchar *null_ptr_arg,
+ uint 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),
+ table_name(table_arg ? table_arg->table_name : 0),
+ field_name(field_name_arg), unireg_check(unireg_check_arg),
+ field_length(length_arg)
+{
+ flags=null_ptr ? 0: NOT_NULL_FLAG;
+}
+
+uint Field::offset()
+{
+ return (uint) (ptr - (char*) table->record[0]);
+}
+
+
+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);
+ }
+}
+
+
+bool Field::send(String *packet)
+{
+ if (is_null())
+ return net_store_null(packet);
+ char buff[MAX_FIELD_WIDTH];
+ String tmp(buff,sizeof(buff));
+ val_str(&tmp,&tmp);
+ CONVERT *convert;
+ if ((convert=current_thd->convert_set))
+ return convert->store(packet,tmp.ptr(),tmp.length());
+ return net_store_data(packet,tmp.ptr(),tmp.length());
+}
+
+
+void Field_num::add_zerofill_and_unsigned(String &res) const
+{
+ res.length(strlen(res.ptr())); // Fix length
+ if (unsigned_flag)
+ res.append(" unsigned");
+ if (zerofill)
+ res.append(" zerofill");
+}
+
+void Field_num::make_field(Send_field *field)
+{
+ field->table_name=table_name;
+ field->col_name=field_name;
+ field->length=field_length;
+ field->type=type();
+ field->flags=table->maybe_null ? (flags & ~NOT_NULL_FLAG) : flags;
+ field->decimals=dec;
+}
+
+
+void Field_str::make_field(Send_field *field)
+{
+ field->table_name=table_name;
+ field->col_name=field_name;
+ field->length=field_length;
+ field->type=type();
+ field->flags=table->maybe_null ? (flags & ~NOT_NULL_FLAG) : flags;
+ field->decimals=0;
+}
+
+
+uint Field::fill_cache_field(CACHE_FIELD *copy)
+{
+ copy->str=ptr;
+ copy->length=pack_length();
+ copy->blob_field=0;
+ if (flags & BLOB_FLAG)
+ {
+ copy->blob_field=(Field_blob*) this;
+ copy->strip=0;
+ copy->length-=table->blob_ptr_size;
+ return copy->length;
+ }
+ else if (!zero_pack() && (type() == FIELD_TYPE_STRING && copy->length > 4 ||
+ type() == FIELD_TYPE_VAR_STRING))
+ copy->strip=1; /* Remove end space */
+ else
+ copy->strip=0;
+ return copy->length+(int) copy->strip;
+}
+
+bool Field::get_date(TIME *ltime,bool fuzzydate)
+{
+ char buff[40];
+ String tmp(buff,sizeof(buff)),tmp2,*res;
+ if (!(res=val_str(&tmp,&tmp2)) ||
+ str_to_TIME(res->ptr(),res->length(),ltime,fuzzydate) == TIMESTAMP_NONE)
+ return 1;
+ return 0;
+}
+
+bool Field::get_time(TIME *ltime)
+{
+ char buff[40];
+ String tmp(buff,sizeof(buff)),tmp2,*res;
+ if (!(res=val_str(&tmp,&tmp2)) ||
+ str_to_time(res->ptr(),res->length(),ltime) == TIMESTAMP_NONE)
+ return 1;
+ return 0;
+}
+
+
+/* This is called when storing a date in a string */
+void Field::store_time(TIME *ltime,timestamp_type type)
+{
+ char buff[25];
+ switch (type) {
+ case TIMESTAMP_NONE:
+ store("",0); // Probably an error
+ break;
+ case TIMESTAMP_DATE:
+ sprintf(buff,"%04d-%02d-%02d", ltime->year,ltime->month,ltime->day);
+ store(buff,10);
+ break;
+ case TIMESTAMP_FULL:
+ sprintf(buff,"%04d-%02d-%02d %02d:%02d:%02d",
+ ltime->year,ltime->month,ltime->day,
+ ltime->hour,ltime->minute,ltime->second);
+ store(buff,19);
+ break;
+ case TIMESTAMP_TIME:
+ sprintf(buff, "%02d:%02d:%02d",
+ ltime->hour,ltime->minute,ltime->second);
+ store(buff,strlen(buff));
+ break;
+ }
+}
+
+
+bool Field::optimize_range()
+{
+ return test(table->file->option_flag() & HA_READ_NEXT);
+}
+
+/****************************************************************************
+** Functions for the Field_decimal class
+** This is a unpacked number.
+****************************************************************************/
+
+void
+Field_decimal::reset(void)
+{
+ Field_decimal::store("0",1);
+}
+
+void Field_decimal::overflow(bool negative)
+{
+ uint len=field_length;
+ char *to=ptr;
+ if (negative && !unsigned_flag)
+ {
+ *to++ = '-';
+ len--;
+ }
+ bfill(to,len,negative && unsigned_flag ? '0' : '9');
+ if (dec)
+ ptr[field_length-dec-1]='.';
+ return;
+}
+
+
+void Field_decimal::store(const char *from,uint len)
+{
+ reg3 int i;
+ uint tmp_dec;
+ char fyllchar;
+ const char *end=from+len;
+ struct st_decstr decstr;
+ bool error;
+
+ if ((tmp_dec= dec))
+ tmp_dec++; // Calculate pos of '.'
+ while (from != end && isspace(*from))
+ from++;
+ if (zerofill)
+ {
+ fyllchar = '0';
+ if (from != end)
+ while (*from == '0' && from != end-1) // Skipp prezero
+ from++;
+ }
+ else
+ fyllchar=' ';
+ error=number_dec(&decstr,from,end);
+ if (decstr.sign)
+ {
+ from++;
+ if (unsigned_flag) // No sign with zerofill
+ {
+ if (!error)
+ current_thd->cuted_fields++;
+ Field_decimal::overflow(1);
+ return;
+ }
+ }
+ /*
+ ** Remove pre-zeros if too big number
+ */
+ for (i= (int) (decstr.nr_length+decstr.extra -(field_length-tmp_dec)+
+ decstr.sign) ;
+ i > 0 ;
+ i--)
+ {
+ if (*from == '0')
+ {
+ from++;
+ decstr.nr_length--;
+ continue;
+ }
+ if (decstr.sign && decstr.sign_char == '+' && i == 1)
+ { // Remove pre '+'
+ decstr.sign=0;
+ break;
+ }
+ current_thd->cuted_fields++;
+ // too big number, change to max or min number
+ Field_decimal::overflow(decstr.sign && decstr.sign_char == '-');
+ return;
+ }
+ char *to=ptr;
+ for (i=(int) (field_length-tmp_dec-decstr.nr_length-decstr.extra - decstr.sign) ;
+ i-- > 0 ;)
+ *to++ = fyllchar;
+ if (decstr.sign)
+ *to++= decstr.sign_char;
+ if (decstr.extra)
+ *to++ = '0';
+ for (i=(int) decstr.nr_length ; i-- > 0 ; )
+ *to++ = *from++;
+ if (tmp_dec--)
+ {
+ *to++ ='.';
+ if (decstr.nr_dec) from++; // Skipp '.'
+ 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';
+ }
+
+ /*
+ ** Check for incorrect string if in batch mode (ALTER TABLE/LOAD DATA...)
+ */
+ if (!error && current_thd->count_cuted_fields && from != end)
+ { // Check if number was cuted
+ for (; from != end ; from++)
+ {
+ if (*from != '0')
+ {
+ if (!isspace(*from)) // Space is ok
+ current_thd->cuted_fields++;
+ break;
+ }
+ }
+ }
+}
+
+
+void Field_decimal::store(double nr)
+{
+ if (unsigned_flag && nr < 0)
+ {
+ overflow(1);
+ current_thd->cuted_fields++;
+ return;
+ }
+ reg4 uint i,length;
+ char fyllchar,*to;
+ char buff[320];
+
+ fyllchar = zerofill ? (char) '0' : (char) ' ';
+ sprintf(buff,"%.*f",dec,nr);
+ length=strlen(buff);
+
+ if (length > field_length)
+ {
+ overflow(nr < 0.0);
+ current_thd->cuted_fields++;
+ }
+ else
+ {
+ to=ptr;
+ for (i=field_length-length ; i-- > 0 ;)
+ *to++ = fyllchar;
+ memcpy(to,buff,length);
+ }
+}
+
+
+void Field_decimal::store(longlong nr)
+{
+ if (unsigned_flag && nr < 0)
+ {
+ overflow(1);
+ current_thd->cuted_fields++;
+ return;
+ }
+ char buff[22];
+ uint length=(uint) (longlong10_to_str(nr,buff,-10)-buff);
+ uint int_part=field_length- (dec ? dec+1 : 0);
+
+ if (length > int_part)
+ {
+ overflow(test(nr < 0L)); /* purecov: inspected */
+ current_thd->cuted_fields++; /* purecov: inspected */
+ }
+ else
+ {
+ char fyllchar = zerofill ? (char) '0' : (char) ' ';
+ char *to=ptr;
+ for (uint i=int_part-length ; i-- > 0 ;)
+ *to++ = fyllchar;
+ memcpy(to,buff,length);
+ if (dec)
+ {
+ to[length]='.';
+ bfill(to+length+1,dec,'0');
+ }
+ }
+}
+
+
+double Field_decimal::val_real(void)
+{
+ char temp= *(ptr+field_length); *(ptr+field_length) = '\0';
+ double nr=atod(ptr);
+ *(ptr+field_length)=temp;
+ return(nr);
+}
+
+longlong Field_decimal::val_int(void)
+{
+ char temp= *(ptr+field_length); *(ptr+field_length) = '\0';
+ longlong nr;
+ if (unsigned_flag)
+ nr=(longlong) strtoull(ptr,NULL,10);
+ else
+ nr=strtoll(ptr,NULL,10);
+ *(ptr+field_length)=temp;
+ return(nr);
+}
+
+String *Field_decimal::val_str(String *val_buffer __attribute__((unused)),
+ String *val_ptr)
+{
+ char *str;
+ for (str=ptr ; *str == ' ' ; str++) ;
+ uint tmp_length=(uint) (str-ptr);
+ if (field_length < tmp_length) // Error in data
+ val_ptr->length(0);
+ else
+ val_ptr->set((const char*) str,field_length-tmp_length);
+ return val_ptr;
+}
+
+/*
+** Should be able to handle at least the following fixed decimal formats:
+** 5.00 , -1.0, 05, -05, +5 with optional pre/end space
+*/
+
+int Field_decimal::cmp(const char *a_ptr,const char *b_ptr)
+{
+ const char *end;
+ /* First remove prefixes '0', ' ', and '-' */
+ for (end=a_ptr+field_length;
+ a_ptr != end &&
+ (*a_ptr == *b_ptr ||
+ ((isspace(*a_ptr) || *a_ptr == '+' || *a_ptr == '0') &&
+ (isspace(*b_ptr) || *b_ptr == '+' || *b_ptr == '0')));
+ a_ptr++,b_ptr++) ;
+
+ if (a_ptr == end)
+ return 0;
+ int swap=0;
+ if (*a_ptr == '-')
+ {
+ if (*b_ptr != '-')
+ return -1;
+ swap= -1 ^ 1; // Swap result
+ a_ptr++, b_ptr++;
+ } else if (*b_ptr == '-')
+ return 1;
+
+ while (a_ptr != end)
+ {
+ if (*a_ptr++ != *b_ptr++)
+ return swap ^ (a_ptr[-1] < b_ptr[-1] ? -1 : 1); // compare digits
+ }
+ return 0;
+}
+
+
+void Field_decimal::sort_string(char *to,uint length)
+{
+ char *str,*end;
+ for (str=ptr,end=ptr+length;
+ str != end &&
+ ((isspace(*str) || *str == '+' || *str == '0')) ;
+
+ str++)
+ *to++=' ';
+ if (str == end)
+ return; /* purecov: inspected */
+
+ if (*str == '-')
+ {
+ *to++=1; // Smaller than any number
+ str++;
+ while (str != end)
+ if (isdigit(*str))
+ *to++= (char) ('9' - *str++);
+ else
+ *to++= *str++;
+ }
+ else memcpy(to,str,(uint) (end-str));
+}
+
+void Field_decimal::sql_type(String &res) const
+{
+ uint tmp=field_length;
+ if (!unsigned_flag)
+ tmp--;
+ if (dec)
+ tmp--;
+ sprintf((char*) res.ptr(),"decimal(%d,%d)",tmp,dec);
+ add_zerofill_and_unsigned(res);
+}
+
+
+/****************************************************************************
+** tiny int
+****************************************************************************/
+
+void Field_tiny::store(const char *from,uint len)
+{
+ String tmp_str(from,len);
+ long tmp= strtol(tmp_str.c_ptr(),NULL,10);
+
+ if (unsigned_flag)
+ {
+ if (tmp < 0)
+ {
+ tmp=0; /* purecov: inspected */
+ current_thd->cuted_fields++; /* purecov: inspected */
+ }
+ else if (tmp > 255)
+ {
+ tmp= 255;
+ current_thd->cuted_fields++;
+ }
+ else if (current_thd->count_cuted_fields && !test_if_int(from,len))
+ current_thd->cuted_fields++;
+ }
+ else
+ {
+ if (tmp < -128)
+ {
+ tmp= -128;
+ current_thd->cuted_fields++;
+ }
+ else if (tmp >= 128)
+ {
+ tmp= 127;
+ current_thd->cuted_fields++;
+ }
+ else if (current_thd->count_cuted_fields && !test_if_int(from,len))
+ current_thd->cuted_fields++;
+ }
+ ptr[0]= (char) tmp;
+}
+
+
+void Field_tiny::store(double nr)
+{
+ nr=rint(nr);
+ if (unsigned_flag)
+ {
+ if (nr < 0.0)
+ {
+ *ptr=0;
+ current_thd->cuted_fields++;
+ }
+ else if (nr > 255.0)
+ {
+ *ptr=(char) 255;
+ current_thd->cuted_fields++;
+ }
+ else
+ *ptr=(char) nr;
+ }
+ else
+ {
+ if (nr < -128.0)
+ {
+ *ptr= (char) -128;
+ current_thd->cuted_fields++;
+ }
+ else if (nr > 127.0)
+ {
+ *ptr=127;
+ current_thd->cuted_fields++;
+ }
+ else
+ *ptr=(char) nr;
+ }
+}
+
+void Field_tiny::store(longlong nr)
+{
+ if (unsigned_flag)
+ {
+ if (nr < 0L)
+ {
+ *ptr=0;
+ current_thd->cuted_fields++;
+ }
+ else if (nr > 255L)
+ {
+ *ptr= (char) 255;
+ current_thd->cuted_fields++;
+ }
+ else
+ *ptr=(char) nr;
+ }
+ else
+ {
+ if (nr < -128L)
+ {
+ *ptr= (char) -128;
+ current_thd->cuted_fields++;
+ }
+ else if (nr > 127L)
+ {
+ *ptr=127;
+ current_thd->cuted_fields++;
+ }
+ else
+ *ptr=(char) nr;
+ }
+}
+
+
+double Field_tiny::val_real(void)
+{
+ int tmp= unsigned_flag ? (int) ((uchar*) ptr)[0] :
+ (int) ((signed char*) ptr)[0];
+ return (double) tmp;
+}
+
+longlong Field_tiny::val_int(void)
+{
+ int tmp= unsigned_flag ? (int) ((uchar*) ptr)[0] :
+ (int) ((signed char*) ptr)[0];
+ return (longlong) tmp;
+}
+
+String *Field_tiny::val_str(String *val_buffer,
+ String *val_ptr __attribute__((unused)))
+{
+ uint length;
+ val_buffer->alloc(max(field_length+1,5));
+ char *to=(char*) val_buffer->ptr();
+ if (unsigned_flag)
+ length= (uint) (int10_to_str((long) *((uchar*) ptr),to,10)-to);
+ else
+ length=(int10_to_str((long) *((signed char*) ptr),to,-10)-to);
+ val_buffer->length(length);
+ if (zerofill)
+ prepend_zeros(val_buffer);
+ return val_buffer;
+}
+
+
+int Field_tiny::cmp(const char *a_ptr, const char *b_ptr)
+{
+ signed char a,b;
+ a=(signed char) a_ptr[0]; b= (signed char) b_ptr[0];
+ if (unsigned_flag)
+ return ((uchar) a < (uchar) b) ? -1 : ((uchar) a > (uchar) b) ? 1 : 0;
+ return (a < b) ? -1 : (a > b) ? 1 : 0;
+}
+
+void Field_tiny::sort_string(char *to,uint length __attribute__((unused)))
+{
+ if (unsigned_flag)
+ *to= *ptr;
+ else
+ to[0] = (char) ((uchar) ptr[0] ^ (uchar) 128); /* Revers signbit */
+}
+
+void Field_tiny::sql_type(String &res) const
+{
+ sprintf((char*) res.ptr(),"tinyint(%d)",(int) field_length);
+ add_zerofill_and_unsigned(res);
+}
+
+/****************************************************************************
+** short int
+****************************************************************************/
+
+
+// Note: Sometimes this should be fixed to use one strtol() to use
+// len and check for garbage after number.
+
+void Field_short::store(const char *from,uint len)
+{
+ String tmp_str(from,len);
+ long tmp= strtol(tmp_str.c_ptr(),NULL,10);
+ if (unsigned_flag)
+ {
+ if (tmp < 0)
+ {
+ tmp=0;
+ current_thd->cuted_fields++;
+ }
+ else if (tmp > (uint16) ~0)
+ {
+ tmp=(uint16) ~0;
+ current_thd->cuted_fields++;
+ }
+ else if (current_thd->count_cuted_fields && !test_if_int(from,len))
+ current_thd->cuted_fields++;
+ }
+ else
+ {
+ if (tmp < INT_MIN16)
+ {
+ tmp= INT_MIN16;
+ current_thd->cuted_fields++;
+ }
+ else if (tmp > INT_MAX16)
+ {
+ tmp=INT_MAX16;
+ current_thd->cuted_fields++;
+ }
+ else if (current_thd->count_cuted_fields && !test_if_int(from,len))
+ current_thd->cuted_fields++;
+ }
+#ifdef WORDS_BIGENDIAN
+ if (table->db_low_byte_first)
+ {
+ int2store(ptr,tmp);
+ }
+ else
+#endif
+ shortstore(ptr,(short) tmp);
+}
+
+
+void Field_short::store(double nr)
+{
+ int16 res;
+ nr=rint(nr);
+ if (unsigned_flag)
+ {
+ if (nr < 0)
+ {
+ res=0;
+ current_thd->cuted_fields++;
+ }
+ else if (nr > (double) (uint16) ~0)
+ {
+ res=(int16) (uint16) ~0;
+ current_thd->cuted_fields++;
+ }
+ else
+ res=(int16) (uint16) nr;
+ }
+ else
+ {
+ if (nr < (double) INT_MIN16)
+ {
+ res=INT_MIN16;
+ current_thd->cuted_fields++;
+ }
+ else if (nr > (double) INT_MAX16)
+ {
+ res=INT_MAX16;
+ current_thd->cuted_fields++;
+ }
+ else
+ res=(int16) nr;
+ }
+#ifdef WORDS_BIGENDIAN
+ if (table->db_low_byte_first)
+ {
+ int2store(ptr,res);
+ }
+ else
+#endif
+ shortstore(ptr,res);
+}
+
+void Field_short::store(longlong nr)
+{
+ int16 res;
+ if (unsigned_flag)
+ {
+ if (nr < 0L)
+ {
+ res=0;
+ current_thd->cuted_fields++;
+ }
+ else if (nr > (longlong) (uint16) ~0)
+ {
+ res=(int16) (uint16) ~0;
+ current_thd->cuted_fields++;
+ }
+ else
+ res=(int16) (uint16) nr;
+ }
+ else
+ {
+ if (nr < INT_MIN16)
+ {
+ res=INT_MIN16;
+ current_thd->cuted_fields++;
+ }
+ else if (nr > INT_MAX16)
+ {
+ res=INT_MAX16;
+ current_thd->cuted_fields++;
+ }
+ else
+ res=(int16) nr;
+ }
+#ifdef WORDS_BIGENDIAN
+ if (table->db_low_byte_first)
+ {
+ int2store(ptr,res);
+ }
+ else
+#endif
+ shortstore(ptr,res);
+}
+
+
+double Field_short::val_real(void)
+{
+ short j;
+#ifdef WORDS_BIGENDIAN
+ if (table->db_low_byte_first)
+ j=sint2korr(ptr);
+ else
+#endif
+ shortget(j,ptr);
+ return unsigned_flag ? (double) (unsigned short) j : (double) j;
+}
+
+longlong Field_short::val_int(void)
+{
+ short j;
+#ifdef WORDS_BIGENDIAN
+ if (table->db_low_byte_first)
+ j=sint2korr(ptr);
+ else
+#endif
+ shortget(j,ptr);
+ return unsigned_flag ? (longlong) (unsigned short) j : (longlong) j;
+}
+
+String *Field_short::val_str(String *val_buffer,
+ String *val_ptr __attribute__((unused)))
+{
+ uint length;
+ val_buffer->alloc(max(field_length+1,7));
+ char *to=(char*) val_buffer->ptr();
+ short j;
+#ifdef WORDS_BIGENDIAN
+ if (table->db_low_byte_first)
+ j=sint2korr(ptr);
+ else
+#endif
+ shortget(j,ptr);
+
+ if (unsigned_flag)
+ length=(uint) (int10_to_str((long) (uint16) j,to,10)-to);
+ else
+ length=(uint) (int10_to_str((long) j,to,-10)-to);
+ val_buffer->length(length);
+ if (zerofill)
+ prepend_zeros(val_buffer);
+ return val_buffer;
+}
+
+
+int Field_short::cmp(const char *a_ptr, const char *b_ptr)
+{
+ short a,b;
+#ifdef WORDS_BIGENDIAN
+ if (table->db_low_byte_first)
+ {
+ a=sint2korr(a_ptr);
+ b=sint2korr(b_ptr);
+ }
+ else
+#endif
+ {
+ shortget(a,a_ptr);
+ shortget(b,b_ptr);
+ }
+
+ if (unsigned_flag)
+ return ((unsigned short) a < (unsigned short) b) ? -1 :
+ ((unsigned short) a > (unsigned short) b) ? 1 : 0;
+ return (a < b) ? -1 : (a > b) ? 1 : 0;
+}
+
+void Field_short::sort_string(char *to,uint length __attribute__((unused)))
+{
+#ifdef WORDS_BIGENDIAN
+ if (!table->db_low_byte_first)
+ {
+ if (unsigned_flag)
+ to[0] = ptr[0];
+ else
+ to[0] = ptr[0] ^ 128; /* Revers signbit */
+ to[1] = ptr[1];
+ }
+ else
+#endif
+ {
+ if (unsigned_flag)
+ to[0] = ptr[1];
+ else
+ to[0] = ptr[1] ^ 128; /* Revers signbit */
+ to[1] = ptr[0];
+ }
+}
+
+void Field_short::sql_type(String &res) const
+{
+ sprintf((char*) res.ptr(),"smallint(%d)",(int) field_length);
+ add_zerofill_and_unsigned(res);
+}
+
+
+/****************************************************************************
+** medium int
+****************************************************************************/
+
+// Note: Sometimes this should be fixed to use one strtol() to use
+// len and check for garbage after number.
+
+void Field_medium::store(const char *from,uint len)
+{
+ String tmp_str(from,len);
+ long tmp= strtol(tmp_str.c_ptr(),NULL,10);
+
+ if (unsigned_flag)
+ {
+ if (tmp < 0)
+ {
+ tmp=0;
+ current_thd->cuted_fields++;
+ }
+ else if (tmp >= (long) (1L << 24))
+ {
+ tmp=(long) (1L << 24)-1L;
+ current_thd->cuted_fields++;
+ }
+ else if (current_thd->count_cuted_fields && !test_if_int(from,len))
+ current_thd->cuted_fields++;
+ }
+ else
+ {
+ if (tmp < INT_MIN24)
+ {
+ tmp= INT_MIN24;
+ current_thd->cuted_fields++;
+ }
+ else if (tmp > INT_MAX24)
+ {
+ tmp=INT_MAX24;
+ current_thd->cuted_fields++;
+ }
+ else if (current_thd->count_cuted_fields && !test_if_int(from,len))
+ current_thd->cuted_fields++;
+ }
+
+ int3store(ptr,tmp);
+}
+
+
+void Field_medium::store(double nr)
+{
+ nr=rint(nr);
+ if (unsigned_flag)
+ {
+ if (nr < 0)
+ {
+ int3store(ptr,0);
+ current_thd->cuted_fields++;
+ }
+ else if (nr >= (double) (long) (1L << 24))
+ {
+ ulong tmp=(ulong) (1L << 24)-1L;
+ int3store(ptr,tmp);
+ current_thd->cuted_fields++;
+ }
+ else
+ int3store(ptr,(ulong) nr);
+ }
+ else
+ {
+ if (nr < (double) INT_MIN24)
+ {
+ long tmp=(long) INT_MIN24;
+ int3store(ptr,tmp);
+ current_thd->cuted_fields++;
+ }
+ else if (nr > (double) INT_MAX24)
+ {
+ long tmp=(long) INT_MAX24;
+ int3store(ptr,tmp);
+ current_thd->cuted_fields++;
+ }
+ else
+ int3store(ptr,(long) nr);
+ }
+}
+
+void Field_medium::store(longlong nr)
+{
+ if (unsigned_flag)
+ {
+ if (nr < 0L)
+ {
+ int3store(ptr,0);
+ current_thd->cuted_fields++;
+ }
+ else if (nr >= (longlong) (long) (1L << 24))
+ {
+ long tmp=(long) (1L << 24)-1L;;
+ int3store(ptr,tmp);
+ current_thd->cuted_fields++;
+ }
+ else
+ int3store(ptr,(ulong) nr);
+ }
+ else
+ {
+ if (nr < (longlong) INT_MIN24)
+ {
+ long tmp=(long) INT_MIN24;
+ int3store(ptr,tmp);
+ current_thd->cuted_fields++;
+ }
+ else if (nr > (longlong) INT_MAX24)
+ {
+ long tmp=(long) INT_MAX24;
+ int3store(ptr,tmp);
+ current_thd->cuted_fields++;
+ }
+ else
+ int3store(ptr,(long) nr);
+ }
+}
+
+
+double Field_medium::val_real(void)
+{
+ long j= unsigned_flag ? (long) uint3korr(ptr) : sint3korr(ptr);
+ return (double) j;
+}
+
+longlong Field_medium::val_int(void)
+{
+ long j= unsigned_flag ? (long) uint3korr(ptr) : sint3korr(ptr);
+ return (longlong) j;
+}
+
+String *Field_medium::val_str(String *val_buffer,
+ String *val_ptr __attribute__((unused)))
+{
+ uint length;
+ val_buffer->alloc(max(field_length+1,10));
+ char *to=(char*) val_buffer->ptr();
+ long j= unsigned_flag ? (long) uint3korr(ptr) : sint3korr(ptr);
+
+ length=(uint) (int10_to_str(j,to,-10)-to);
+ val_buffer->length(length);
+ if (zerofill)
+ prepend_zeros(val_buffer); /* purecov: inspected */
+ return val_buffer;
+}
+
+
+int Field_medium::cmp(const char *a_ptr, const char *b_ptr)
+{
+ long a,b;
+ if (unsigned_flag)
+ {
+ a=uint3korr(a_ptr);
+ b=uint3korr(b_ptr);
+ }
+ else
+ {
+ a=sint3korr(a_ptr);
+ b=sint3korr(b_ptr);
+ }
+ return (a < b) ? -1 : (a > b) ? 1 : 0;
+}
+
+void Field_medium::sort_string(char *to,uint length __attribute__((unused)))
+{
+ if (unsigned_flag)
+ to[0] = ptr[2];
+ else
+ to[0] = (uchar) (ptr[2] ^ 128); /* Revers signbit */
+ to[1] = ptr[1];
+ to[2] = ptr[0];
+}
+
+
+void Field_medium::sql_type(String &res) const
+{
+ sprintf((char*) res.ptr(),"mediumint(%d)",(int) field_length);
+ add_zerofill_and_unsigned(res);
+}
+
+/****************************************************************************
+** long int
+****************************************************************************/
+
+
+// Note: Sometimes this should be fixed to use one strtol() to use
+// len and check for garbage after number.
+
+void Field_long::store(const char *from,uint len)
+{
+ while (len && isspace(*from))
+ {
+ len--; from++;
+ }
+ long tmp;
+ String tmp_str(from,len);
+ errno=0;
+ if (unsigned_flag)
+ {
+ if (!len || *from == '-')
+ {
+ tmp=0; // Set negative to 0
+ errno=ERANGE;
+ }
+ else
+ tmp=(long) strtoul(tmp_str.c_ptr(),NULL,10);
+ }
+ else
+ tmp=strtol(tmp_str.c_ptr(),NULL,10);
+ if (errno || current_thd->count_cuted_fields && !test_if_int(from,len))
+ current_thd->cuted_fields++;
+#ifdef WORDS_BIGENDIAN
+ if (table->db_low_byte_first)
+ {
+ int4store(ptr,tmp);
+ }
+ else
+#endif
+ longstore(ptr,tmp);
+}
+
+
+void Field_long::store(double nr)
+{
+ int32 res;
+ nr=rint(nr);
+ if (unsigned_flag)
+ {
+ if (nr < 0)
+ {
+ res=0;
+ current_thd->cuted_fields++;
+ }
+ else if (nr > (double) (ulong) ~0L)
+ {
+ res=(int32) (uint32) ~0L;
+ current_thd->cuted_fields++;
+ }
+ else
+ res=(int32) (ulong) nr;
+ }
+ else
+ {
+ if (nr < (double) INT_MIN32)
+ {
+ res=(int32) INT_MIN32;
+ current_thd->cuted_fields++;
+ }
+ else if (nr > (double) INT_MAX32)
+ {
+ res=(int32) INT_MAX32;
+ current_thd->cuted_fields++;
+ }
+ else
+ res=(int32) nr;
+ }
+#ifdef WORDS_BIGENDIAN
+ if (table->db_low_byte_first)
+ {
+ int4store(ptr,res);
+ }
+ else
+#endif
+ longstore(ptr,res);
+}
+
+
+void Field_long::store(longlong nr)
+{
+ int32 res;
+ if (unsigned_flag)
+ {
+ if (nr < 0)
+ {
+ res=0;
+ current_thd->cuted_fields++;
+ }
+ else if (nr >= (LL(1) << 32))
+ {
+ res=(int32) (uint32) ~0L;
+ current_thd->cuted_fields++;
+ }
+ else
+ res=(int32) (uint32) nr;
+ }
+ else
+ {
+ if (nr < (longlong) INT_MIN32)
+ {
+ res=(int32) INT_MIN32;
+ current_thd->cuted_fields++;
+ }
+ else if (nr > (longlong) INT_MAX32)
+ {
+ res=(int32) INT_MAX32;
+ current_thd->cuted_fields++;
+ }
+ else
+ res=(int32) nr;
+ }
+#ifdef WORDS_BIGENDIAN
+ if (table->db_low_byte_first)
+ {
+ int4store(ptr,res);
+ }
+ else
+#endif
+ longstore(ptr,res);
+}
+
+
+double Field_long::val_real(void)
+{
+ int32 j;
+#ifdef WORDS_BIGENDIAN
+ if (table->db_low_byte_first)
+ j=sint4korr(ptr);
+ else
+#endif
+ longget(j,ptr);
+ return unsigned_flag ? (double) (uint32) j : (double) j;
+}
+
+longlong Field_long::val_int(void)
+{
+ int32 j;
+#ifdef WORDS_BIGENDIAN
+ if (table->db_low_byte_first)
+ j=sint4korr(ptr);
+ else
+#endif
+ longget(j,ptr);
+ return unsigned_flag ? (longlong) (uint32) j : (longlong) j;
+}
+
+String *Field_long::val_str(String *val_buffer,
+ String *val_ptr __attribute__((unused)))
+{
+ uint length;
+ val_buffer->alloc(max(field_length+1,12));
+ char *to=(char*) val_buffer->ptr();
+ int32 j;
+#ifdef WORDS_BIGENDIAN
+ if (table->db_low_byte_first)
+ j=sint4korr(ptr);
+ else
+#endif
+ longget(j,ptr);
+
+ length=(uint) (int10_to_str((unsigned_flag ? (long) (uint32) j : (long) j),
+ to,
+ unsigned_flag ? 10 : -10)-to);
+ val_buffer->length(length);
+ if (zerofill)
+ prepend_zeros(val_buffer);
+ return val_buffer;
+}
+
+
+int Field_long::cmp(const char *a_ptr, const char *b_ptr)
+{
+ int32 a,b;
+#ifdef WORDS_BIGENDIAN
+ if (table->db_low_byte_first)
+ {
+ a=sint4korr(a_ptr);
+ b=sint4korr(b_ptr);
+ }
+ else
+#endif
+ {
+ longget(a,a_ptr);
+ longget(b,b_ptr);
+ }
+ if (unsigned_flag)
+ return ((ulong) a < (ulong) b) ? -1 : ((ulong) a > (ulong) b) ? 1 : 0;
+ return (a < b) ? -1 : (a > b) ? 1 : 0;
+}
+
+void Field_long::sort_string(char *to,uint length __attribute__((unused)))
+{
+#ifdef WORDS_BIGENDIAN
+ if (!table->db_low_byte_first)
+ {
+ if (unsigned_flag)
+ to[0] = ptr[0];
+ else
+ to[0] = ptr[0] ^ 128; /* Revers signbit */
+ to[1] = ptr[1];
+ to[2] = ptr[2];
+ to[3] = ptr[3];
+ }
+ else
+#endif
+ {
+ if (unsigned_flag)
+ to[0] = ptr[3];
+ else
+ to[0] = ptr[3] ^ 128; /* Revers signbit */
+ to[1] = ptr[2];
+ to[2] = ptr[1];
+ to[3] = ptr[0];
+ }
+}
+
+
+void Field_long::sql_type(String &res) const
+{
+ sprintf((char*) res.ptr(),"int(%d)",(int) field_length);
+ add_zerofill_and_unsigned(res);
+}
+
+/****************************************************************************
+** longlong int
+****************************************************************************/
+
+void Field_longlong::store(const char *from,uint len)
+{
+ while (len && isspace(*from))
+ { // For easy error check
+ len--; from++;
+ }
+ longlong tmp;
+ String tmp_str(from,len);
+ errno=0;
+ if (unsigned_flag)
+ {
+ if (!len || *from == '-')
+ {
+ tmp=0; // Set negative to 0
+ errno=ERANGE;
+ }
+ else
+ tmp=(longlong) strtoull(tmp_str.c_ptr(),NULL,10);
+ }
+ else
+ tmp=strtoll(tmp_str.c_ptr(),NULL,10);
+ if (errno || current_thd->count_cuted_fields && !test_if_int(from,len))
+ current_thd->cuted_fields++;
+#ifdef WORDS_BIGENDIAN
+ if (table->db_low_byte_first)
+ {
+ int8store(ptr,tmp);
+ }
+ else
+#endif
+ longlongstore(ptr,tmp);
+}
+
+
+void Field_longlong::store(double nr)
+{
+ longlong res;
+ nr=rint(nr);
+ if (unsigned_flag)
+ {
+ if (nr < 0)
+ {
+ res=0;
+ current_thd->cuted_fields++;
+ }
+ else if (nr >= (double) ~ (ulonglong) 0)
+ {
+ res= ~(longlong) 0;
+ current_thd->cuted_fields++;
+ }
+ else
+ res=(longlong) (ulonglong) nr;
+ }
+ else
+ {
+ if (nr <= (double) LONGLONG_MIN)
+ {
+ res=(longlong) LONGLONG_MIN;
+ current_thd->cuted_fields++;
+ }
+ else if (nr >= (double) LONGLONG_MAX)
+ {
+ res=(longlong) LONGLONG_MAX;
+ current_thd->cuted_fields++;
+ }
+ else
+ res=(longlong) nr;
+ }
+#ifdef WORDS_BIGENDIAN
+ if (table->db_low_byte_first)
+ {
+ int8store(ptr,res);
+ }
+ else
+#endif
+ longlongstore(ptr,res);
+}
+
+
+void Field_longlong::store(longlong nr)
+{
+#ifdef WORDS_BIGENDIAN
+ if (table->db_low_byte_first)
+ {
+ int8store(ptr,nr);
+ }
+ else
+#endif
+ longlongstore(ptr,nr);
+}
+
+
+double Field_longlong::val_real(void)
+{
+ longlong j;
+#ifdef WORDS_BIGENDIAN
+ if (table->db_low_byte_first)
+ {
+ j=sint8korr(ptr);
+ }
+ else
+#endif
+ longlongget(j,ptr);
+ return unsigned_flag ? ulonglong2double(j) : (double) j;
+}
+
+longlong Field_longlong::val_int(void)
+{
+ longlong j;
+#ifdef WORDS_BIGENDIAN
+ if (table->db_low_byte_first)
+ j=sint8korr(ptr);
+ else
+#endif
+ longlongget(j,ptr);
+ return j;
+}
+
+
+String *Field_longlong::val_str(String *val_buffer,
+ String *val_ptr __attribute__((unused)))
+{
+ uint length;
+ val_buffer->alloc(max(field_length+1,22));
+ char *to=(char*) val_buffer->ptr();
+ longlong j;
+#ifdef WORDS_BIGENDIAN
+ if (table->db_low_byte_first)
+ j=sint8korr(ptr);
+ else
+#endif
+ longlongget(j,ptr);
+
+ length=(uint) (longlong10_to_str(j,to,unsigned_flag ? 10 : -10)-to);
+ val_buffer->length(length);
+ if (zerofill)
+ prepend_zeros(val_buffer);
+ return val_buffer;
+}
+
+
+int Field_longlong::cmp(const char *a_ptr, const char *b_ptr)
+{
+ longlong a,b;
+#ifdef WORDS_BIGENDIAN
+ if (table->db_low_byte_first)
+ {
+ a=sint8korr(a_ptr);
+ b=sint8korr(b_ptr);
+ }
+ else
+#endif
+ {
+ longlongget(a,a_ptr);
+ longlongget(b,b_ptr);
+ }
+ if (unsigned_flag)
+ return ((ulonglong) a < (ulonglong) b) ? -1 :
+ ((ulonglong) a > (ulonglong) b) ? 1 : 0;
+ return (a < b) ? -1 : (a > b) ? 1 : 0;
+}
+
+void Field_longlong::sort_string(char *to,uint length __attribute__((unused)))
+{
+#ifdef WORDS_BIGENDIAN
+ if (!table->db_low_byte_first)
+ {
+ if (unsigned_flag)
+ to[0] = ptr[0];
+ else
+ to[0] = ptr[0] ^ 128; /* Revers signbit */
+ to[1] = ptr[1];
+ to[2] = ptr[2];
+ to[3] = ptr[3];
+ to[4] = ptr[4];
+ to[5] = ptr[5];
+ to[6] = ptr[6];
+ to[7] = ptr[7];
+ }
+ else
+#endif
+ {
+ if (unsigned_flag)
+ to[0] = ptr[7];
+ else
+ to[0] = ptr[7] ^ 128; /* Revers signbit */
+ to[1] = ptr[6];
+ to[2] = ptr[5];
+ to[3] = ptr[4];
+ to[4] = ptr[3];
+ to[5] = ptr[2];
+ to[6] = ptr[1];
+ to[7] = ptr[0];
+ }
+}
+
+
+void Field_longlong::sql_type(String &res) const
+{
+ sprintf((char*) res.ptr(),"bigint(%d)",(int) field_length);
+ add_zerofill_and_unsigned(res);
+}
+
+/****************************************************************************
+** single precision float
+****************************************************************************/
+
+void Field_float::store(const char *from,uint len)
+{
+ String tmp_str(from,len);
+ errno=0;
+ Field_float::store(atof(tmp_str.c_ptr()));
+ if (errno || current_thd->count_cuted_fields && !test_if_real(from,len))
+ current_thd->cuted_fields++;
+}
+
+
+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 (nr < -FLT_MAX)
+ {
+ j= -FLT_MAX;
+ current_thd->cuted_fields++;
+ }
+ else if (nr > FLT_MAX)
+ {
+ j=FLT_MAX;
+ current_thd->cuted_fields++;
+ }
+ else
+ j= (float) nr;
+#ifdef WORDS_BIGENDIAN
+ if (table->db_low_byte_first)
+ {
+ float4store(ptr,j);
+ }
+ else
+#endif
+ memcpy_fixed(ptr,(byte*) &j,sizeof(j));
+}
+
+
+void Field_float::store(longlong nr)
+{
+ float j= (float) nr;
+#ifdef WORDS_BIGENDIAN
+ if (table->db_low_byte_first)
+ {
+ float4store(ptr,j);
+ }
+ else
+#endif
+ memcpy_fixed(ptr,(byte*) &j,sizeof(j));
+}
+
+
+double Field_float::val_real(void)
+{
+ float j;
+#ifdef WORDS_BIGENDIAN
+ if (table->db_low_byte_first)
+ {
+ float4get(j,ptr);
+ }
+ else
+#endif
+ memcpy_fixed((byte*) &j,ptr,sizeof(j));
+ return ((double) j);
+}
+
+longlong Field_float::val_int(void)
+{
+ float j;
+#ifdef WORDS_BIGENDIAN
+ if (table->db_low_byte_first)
+ {
+ float4get(j,ptr);
+ }
+ else
+#endif
+ memcpy_fixed((byte*) &j,ptr,sizeof(j));
+ return ((longlong) j);
+}
+
+
+String *Field_float::val_str(String *val_buffer,
+ String *val_ptr __attribute__((unused)))
+{
+ float nr;
+#ifdef WORDS_BIGENDIAN
+ if (table->db_low_byte_first)
+ {
+ float4get(nr,ptr);
+ }
+ else
+#endif
+ memcpy_fixed((byte*) &nr,ptr,sizeof(nr));
+
+ val_buffer->alloc(max(field_length,70));
+ char *to=(char*) val_buffer->ptr();
+
+ if (dec >= NOT_FIXED_DEC)
+ {
+ sprintf(to,"%-*.*g",(int) field_length,FLT_DIG,nr);
+ to=strcend(to,' ');
+ *to=0;
+ }
+ else
+ {
+#ifdef HAVE_FCONVERT
+ char buff[70],*pos=buff;
+ int decpt,sign,tmp_dec=dec;
+
+ VOID(sfconvert(&nr,tmp_dec,&decpt,&sign,buff));
+ if (sign)
+ {
+ *to++='-';
+ }
+ if (decpt < 0)
+ { /* val_buffer is < 0 */
+ *to++='0';
+ if (!tmp_dec)
+ goto end;
+ *to++='.';
+ if (-decpt > tmp_dec)
+ decpt= - (int) tmp_dec;
+ tmp_dec=(uint) ((int) tmp_dec+decpt);
+ while (decpt++ < 0)
+ *to++='0';
+ }
+ else if (decpt == 0)
+ {
+ *to++= '0';
+ if (!tmp_dec)
+ goto end;
+ *to++='.';
+ }
+ else
+ {
+ while (decpt-- > 0)
+ *to++= *pos++;
+ if (!tmp_dec)
+ goto end;
+ *to++='.';
+ }
+ while (tmp_dec--)
+ *to++= *pos++;
+#else
+ sprintf(to,"%.*f",dec,nr);
+ to=strend(to);
+#endif
+ }
+#ifdef HAVE_FCONVERT
+ end:
+#endif
+ val_buffer->length((uint) (to-val_buffer->ptr()));
+ if (zerofill)
+ prepend_zeros(val_buffer);
+ return val_buffer;
+}
+
+
+int Field_float::cmp(const char *a_ptr, const char *b_ptr)
+{
+ float a,b;
+#ifdef WORDS_BIGENDIAN
+ if (table->db_low_byte_first)
+ {
+ float4get(a,a_ptr);
+ float4get(b,b_ptr);
+ }
+ else
+#endif
+ {
+ memcpy_fixed(&a,a_ptr,sizeof(float));
+ memcpy_fixed(&b,b_ptr,sizeof(float));
+ }
+ return (a < b) ? -1 : (a > b) ? 1 : 0;
+}
+
+#define FLT_EXP_DIG (sizeof(float)*8-FLT_MANT_DIG)
+
+void Field_float::sort_string(char *to,uint length __attribute__((unused)))
+{
+ float nr;
+#ifdef WORDS_BIGENDIAN
+ if (table->db_low_byte_first)
+ {
+ float4get(nr,ptr);
+ }
+ else
+#endif
+ memcpy_fixed(&nr,ptr,sizeof(float));
+
+ uchar *tmp= (uchar*) to;
+ if (nr == (float) 0.0)
+ { /* Change to zero string */
+ tmp[0]=(uchar) 128;
+ bzero((char*) tmp+1,sizeof(nr)-1);
+ }
+ else
+ {
+#ifdef WORDS_BIGENDIAN
+ memcpy_fixed(tmp,&nr,sizeof(nr));
+#else
+ tmp[0]= ptr[3]; tmp[1]=ptr[2]; tmp[2]= ptr[1]; tmp[3]=ptr[0];
+#endif
+ if (tmp[0] & 128) /* Negative */
+ { /* make complement */
+ uint i;
+ for (i=0 ; i < sizeof(nr); i++)
+ tmp[i]=tmp[i] ^ (uchar) 255;
+ }
+ else
+ {
+ ushort exp_part=(((ushort) tmp[0] << 8) | (ushort) tmp[1] |
+ (ushort) 32768);
+ exp_part+= (ushort) 1 << (16-1-FLT_EXP_DIG);
+ tmp[0]= (uchar) (exp_part >> 8);
+ tmp[1]= (uchar) exp_part;
+ }
+ }
+}
+
+
+void Field_float::sql_type(String &res) const
+{
+ if (dec == NOT_FIXED_DEC)
+ strmov((char*) res.ptr(),"float");
+ else
+ sprintf((char*) res.ptr(),"float(%d,%d)",(int) field_length,dec);
+ add_zerofill_and_unsigned(res);
+}
+
+/****************************************************************************
+** double precision floating point numbers
+****************************************************************************/
+
+void Field_double::store(const char *from,uint len)
+{
+ String tmp_str(from,len);
+ errno=0;
+ double j= atof(tmp_str.c_ptr());
+ if (errno || current_thd->count_cuted_fields && !test_if_real(from,len))
+ current_thd->cuted_fields++;
+#ifdef WORDS_BIGENDIAN
+ if (table->db_low_byte_first)
+ {
+ float8store(ptr,j);
+ }
+ else
+#endif
+ doublestore(ptr,j);
+}
+
+
+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
+#ifdef WORDS_BIGENDIAN
+ if (table->db_low_byte_first)
+ {
+ float8store(ptr,nr);
+ }
+ else
+#endif
+ doublestore(ptr,nr);
+}
+
+
+void Field_double::store(longlong nr)
+{
+ double j= (double) nr;
+#ifdef WORDS_BIGENDIAN
+ if (table->db_low_byte_first)
+ {
+ float8store(ptr,j);
+ }
+ else
+#endif
+ doublestore(ptr,j);
+}
+
+
+double Field_double::val_real(void)
+{
+ double j;
+#ifdef WORDS_BIGENDIAN
+ if (table->db_low_byte_first)
+ {
+ float8get(j,ptr);
+ }
+ else
+#endif
+ doubleget(j,ptr);
+ return j;
+}
+
+longlong Field_double::val_int(void)
+{
+ double j;
+#ifdef WORDS_BIGENDIAN
+ if (table->db_low_byte_first)
+ {
+ float8get(j,ptr);
+ }
+ else
+#endif
+ doubleget(j,ptr);
+ return ((longlong) j);
+}
+
+
+String *Field_double::val_str(String *val_buffer,
+ String *val_ptr __attribute__((unused)))
+{
+ double nr;
+#ifdef WORDS_BIGENDIAN
+ if (table->db_low_byte_first)
+ {
+ float8get(nr,ptr);
+ }
+ else
+#endif
+ doubleget(nr,ptr);
+
+ uint to_length=max(field_length,320);
+ val_buffer->alloc(to_length);
+ char *to=(char*) val_buffer->ptr();
+
+ if (dec >= NOT_FIXED_DEC)
+ {
+ sprintf(to,"%-*.*g",(int) field_length,DBL_DIG,nr);
+ to=strcend(to,' ');
+ }
+ else
+ {
+#ifdef HAVE_FCONVERT
+ char buff[320],*pos=buff;
+ int decpt,sign,tmp_dec=dec;
+
+ VOID(fconvert(nr,tmp_dec,&decpt,&sign,buff));
+ if (sign)
+ {
+ *to++='-';
+ }
+ if (decpt < 0)
+ { /* val_buffer is < 0 */
+ *to++='0';
+ if (!tmp_dec)
+ goto end;
+ *to++='.';
+ if (-decpt > tmp_dec)
+ decpt= - (int) tmp_dec;
+ tmp_dec=(uint) ((int) tmp_dec+decpt);
+ while (decpt++ < 0)
+ *to++='0';
+ }
+ else if (decpt == 0)
+ {
+ *to++= '0';
+ if (!tmp_dec)
+ goto end;
+ *to++='.';
+ }
+ else
+ {
+ while (decpt-- > 0)
+ *to++= *pos++;
+ if (!tmp_dec)
+ goto end;
+ *to++='.';
+ }
+ while (tmp_dec--)
+ *to++= *pos++;
+#else
+#ifdef HAVE_SNPRINTF
+ snprintf(to,to_length,"%.*f",dec,nr);
+#else
+ sprintf(to,"%.*f",dec,nr);
+#endif
+ to=strend(to);
+#endif
+ }
+#ifdef HAVE_FCONVERT
+ end:
+#endif
+
+ val_buffer->length((uint) (to-val_buffer->ptr()));
+ if (zerofill)
+ prepend_zeros(val_buffer);
+ return val_buffer;
+}
+
+
+int Field_double::cmp(const char *a_ptr, const char *b_ptr)
+{
+ double a,b;
+#ifdef WORDS_BIGENDIAN
+ if (table->db_low_byte_first)
+ {
+ float8get(a,a_ptr);
+ float8get(b,b_ptr);
+ }
+ else
+#endif
+ {
+ memcpy_fixed(&a,a_ptr,sizeof(double));
+ memcpy_fixed(&b,b_ptr,sizeof(double));
+ }
+ return (a < b) ? -1 : (a > b) ? 1 : 0;
+}
+
+
+#define DBL_EXP_DIG (sizeof(double)*8-DBL_MANT_DIG)
+
+/* The following should work for IEEE */
+
+void Field_double::sort_string(char *to,uint length __attribute__((unused)))
+{
+ double nr;
+#ifdef WORDS_BIGENDIAN
+ if (table->db_low_byte_first)
+ {
+ float8get(nr,ptr);
+ }
+ else
+#endif
+ memcpy_fixed(&nr,ptr,sizeof(nr));
+ change_double_for_sort(nr, (byte*) to);
+}
+
+
+void Field_double::sql_type(String &res) const
+{
+ if (dec == NOT_FIXED_DEC)
+ strmov((char*) res.ptr(),"double");
+ else
+ sprintf((char*) res.ptr(),"double(%d,%d)",(int) field_length,dec);
+ add_zerofill_and_unsigned(res);
+}
+
+
+/****************************************************************************
+** timestamp
+** The first timestamp in the table is automaticly updated
+** by handler.cc. The form->timestamp points at the automatic timestamp.
+****************************************************************************/
+
+Field_timestamp::Field_timestamp(char *ptr_arg, uint32 len_arg,
+ enum utype unireg_check_arg,
+ const char *field_name_arg,
+ struct st_table *table_arg)
+ :Field_num(ptr_arg, len_arg, (uchar*) 0,0,
+ unireg_check_arg, field_name_arg, table_arg,
+ 0, 1, 1)
+{
+ if (table && !table->timestamp_field)
+ {
+ table->timestamp_field= this; // Automatic timestamp
+ table->time_stamp=(ulong) (ptr_arg - (char*) table->record[0])+1;
+ flags|=TIMESTAMP_FLAG;
+ }
+}
+
+
+void Field_timestamp::store(const char *from,uint len)
+{
+ long tmp=(long) str_to_timestamp(from,len);
+#ifdef WORDS_BIGENDIAN
+ if (table->db_low_byte_first)
+ {
+ int4store(ptr,tmp);
+ }
+ else
+#endif
+ longstore(ptr,tmp);
+}
+
+void Field_timestamp::fill_and_store(char *from,uint len)
+{
+ uint res_length;
+ if (len <= field_length)
+ res_length=field_length;
+ else if (len <= 12)
+ res_length=12; /* purecov: inspected */
+ else if (len <= 14)
+ res_length=14; /* purecov: inspected */
+ else
+ res_length=(len+1)/2*2; // must be even
+ if (res_length != len)
+ {
+ bmove_upp(from+res_length,from+len,len);
+ bfill(from,res_length-len,'0');
+ len=res_length;
+ }
+ long tmp=(long) str_to_timestamp(from,len);
+#ifdef WORDS_BIGENDIAN
+ if (table->db_low_byte_first)
+ {
+ int4store(ptr,tmp);
+ }
+ else
+#endif
+ longstore(ptr,tmp);
+}
+
+
+void Field_timestamp::store(double nr)
+{
+ if (nr < 0 || nr > 99991231235959.0)
+ {
+ nr=0; // Avoid overflow on buff
+ current_thd->cuted_fields++;
+ }
+ Field_timestamp::store((longlong) rint(nr));
+}
+
+
+/*
+** Convert a datetime of formats YYMMDD, YYYYMMDD or YYMMDDHHMSS to
+** YYYYMMDDHHMMSS. The high date '99991231235959' is checked before this
+** function.
+*/
+
+static longlong fix_datetime(longlong nr)
+{
+ if (nr == LL(0) || nr >= LL(10000101000000))
+ return nr; // Normal datetime >= Year 1000
+ if (nr < 101)
+ goto err;
+ if (nr <= (YY_PART_YEAR-1)*10000L+1231L)
+ return (nr+20000000L)*1000000L; // YYMMDD, year: 2000-2069
+ if (nr < (YY_PART_YEAR)*10000L+101L)
+ goto err;
+ if (nr <= 991231L)
+ return (nr+19000000L)*1000000L; // YYMMDD, year: 1970-1999
+ if (nr < 10000101L)
+ goto err;
+ if (nr <= 99991231L)
+ return nr*1000000L;
+ if (nr < 101000000L)
+ goto err;
+ if (nr <= (YY_PART_YEAR-1)*LL(10000000000)+LL(1231235959))
+ return nr+LL(20000000000000); // YYMMDDHHMMSS, 2000-2069
+ if (nr < YY_PART_YEAR*LL(10000000000)+ LL(101000000))
+ goto err;
+ if (nr <= LL(991231235959))
+ return nr+LL(19000000000000); // YYMMDDHHMMSS, 1970-1999
+
+ err:
+ current_thd->cuted_fields++;
+ return LL(0);
+}
+
+
+void Field_timestamp::store(longlong nr)
+{
+ TIME l_time;
+ time_t timestamp;
+ long part1,part2;
+
+ if ((nr=fix_datetime(nr)))
+ {
+ part1=(long) (nr/LL(1000000));
+ part2=(long) (nr - (longlong) part1*LL(1000000));
+ l_time.year= 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.minute=(int) part2 / 100;
+ l_time.second=(int) part2 % 100;
+ timestamp=my_gmt_sec(&l_time);
+ }
+ else
+ timestamp=0;
+#ifdef WORDS_BIGENDIAN
+ if (table->db_low_byte_first)
+ {
+ int4store(ptr,timestamp);
+ }
+ else
+#endif
+ longstore(ptr,timestamp);
+}
+
+
+double Field_timestamp::val_real(void)
+{
+ return (double) Field_timestamp::val_int();
+}
+
+longlong Field_timestamp::val_int(void)
+{
+ uint len,pos;
+ int part_time;
+ uint32 temp;
+ time_t time_arg;
+ struct tm *l_time;
+ longlong res;
+ struct tm tm_tmp;
+
+#ifdef WORDS_BIGENDIAN
+ if (table->db_low_byte_first)
+ temp=uint4korr(ptr);
+ else
+#endif
+ longget(temp,ptr);
+
+ if (temp == 0L) // No time
+ return(0); /* purecov: inspected */
+ time_arg=(time_t) temp;
+ localtime_r(&time_arg,&tm_tmp);
+ l_time=&tm_tmp;
+ res=(longlong) 0;
+ for (pos=len=0; len+1 < (uint) field_length ; len+=2,pos++)
+ {
+ bool year_flag=0;
+ switch (dayord.pos[pos]) {
+ case 0: part_time=l_time->tm_year % 100; year_flag=1 ; break;
+ case 1: part_time=l_time->tm_mon+1; break;
+ case 2: part_time=l_time->tm_mday; break;
+ case 3: part_time=l_time->tm_hour; break;
+ case 4: part_time=l_time->tm_min; break;
+ case 5: part_time=l_time->tm_sec; break;
+ default: part_time=0; break; /* purecov: deadcode */
+ }
+ if (year_flag && (field_length == 8 || field_length == 14))
+ {
+ res=res*(longlong) 10000+(part_time+
+ ((part_time < YY_PART_YEAR) ? 2000 : 1900));
+ len+=2;
+ }
+ else
+ res=res*(longlong) 100+part_time;
+ }
+ return (longlong) res;
+}
+
+
+String *Field_timestamp::val_str(String *val_buffer,
+ String *val_ptr __attribute__((unused)))
+{
+ uint pos;
+ int part_time;
+ uint32 temp;
+ time_t time_arg;
+ struct tm *l_time;
+ struct tm tm_tmp;
+
+ val_buffer->alloc(field_length+1);
+ char *to=(char*) val_buffer->ptr(),*end=to+field_length;
+
+#ifdef WORDS_BIGENDIAN
+ if (table->db_low_byte_first)
+ temp=uint4korr(ptr);
+ else
+#endif
+ longget(temp,ptr);
+
+ if (temp == 0L)
+ { /* Zero time is "000000" */
+ VOID(strfill(to,field_length,'0'));
+ val_buffer->length(field_length);
+ return val_buffer;
+ }
+ time_arg=(time_t) temp;
+ localtime_r(&time_arg,&tm_tmp);
+ l_time=&tm_tmp;
+ for (pos=0; to < end ; pos++)
+ {
+ bool year_flag=0;
+ switch (dayord.pos[pos]) {
+ case 0: part_time=l_time->tm_year % 100; year_flag=1; break;
+ case 1: part_time=l_time->tm_mon+1; break;
+ case 2: part_time=l_time->tm_mday; break;
+ case 3: part_time=l_time->tm_hour; break;
+ case 4: part_time=l_time->tm_min; break;
+ case 5: part_time=l_time->tm_sec; break;
+ default: part_time=0; break; /* purecov: deadcode */
+ }
+ if (year_flag && (field_length == 8 || field_length == 14))
+ {
+ if (part_time < YY_PART_YEAR)
+ {
+ *to++='2'; *to++='0'; /* purecov: inspected */
+ }
+ else
+ {
+ *to++='1'; *to++='9';
+ }
+ }
+ *to++=(char) ('0'+((uint) part_time/10));
+ *to++=(char) ('0'+((uint) part_time % 10));
+ }
+ *to=0; // Safeguard
+ val_buffer->length((uint) (to-val_buffer->ptr()));
+ return val_buffer;
+}
+
+bool Field_timestamp::get_date(TIME *ltime,
+ bool fuzzydate __attribute__((unused)))
+{
+ long temp;
+#ifdef WORDS_BIGENDIAN
+ if (table->db_low_byte_first)
+ temp=uint4korr(ptr);
+ else
+#endif
+ longget(temp,ptr);
+ if (temp == 0L)
+ { /* Zero time is "000000" */
+ bzero((char*) ltime,sizeof(*ltime));
+ }
+ else
+ {
+ struct tm tm_tmp;
+ time_t time_arg= (time_t) temp;
+ localtime_r(&time_arg,&tm_tmp);
+ struct tm *start= &tm_tmp;
+ ltime->year= start->tm_year+1900;
+ ltime->month= start->tm_mon+1;
+ ltime->day= start->tm_mday;
+ ltime->hour= start->tm_hour;
+ ltime->minute= start->tm_min;
+ ltime->second= start->tm_sec;
+ ltime->second_part= 0;
+ ltime->neg= 0;
+ }
+ return 0;
+}
+
+bool Field_timestamp::get_time(TIME *ltime)
+{
+ Field_timestamp::get_date(ltime,0);
+ return 0;
+}
+
+int Field_timestamp::cmp(const char *a_ptr, const char *b_ptr)
+{
+ int32 a,b;
+#ifdef WORDS_BIGENDIAN
+ if (table->db_low_byte_first)
+ {
+ a=sint4korr(a_ptr);
+ b=sint4korr(b_ptr);
+ }
+ else
+#endif
+ {
+ longget(a,a_ptr);
+ longget(b,b_ptr);
+ }
+ return ((uint32) a < (uint32) b) ? -1 : ((uint32) a > (uint32) b) ? 1 : 0;
+}
+
+void Field_timestamp::sort_string(char *to,uint length __attribute__((unused)))
+{
+#ifdef WORDS_BIGENDIAN
+ if (!table->db_low_byte_first)
+ {
+ to[0] = ptr[0];
+ to[1] = ptr[1];
+ to[2] = ptr[2];
+ to[3] = ptr[3];
+ }
+ else
+#endif
+ {
+ to[0] = ptr[3];
+ to[1] = ptr[2];
+ to[2] = ptr[1];
+ to[3] = ptr[0];
+ }
+}
+
+
+void Field_timestamp::sql_type(String &res) const
+{
+ sprintf((char*) res.ptr(),"timestamp(%d)",(int) field_length);
+ res.length(strlen(res.ptr()));
+}
+
+
+void Field_timestamp::set_time()
+{
+ long tmp= (long) current_thd->query_start();
+#ifdef WORDS_BIGENDIAN
+ if (table->db_low_byte_first)
+ {
+ int4store(ptr,tmp);
+ }
+ else
+#endif
+ longstore(ptr,tmp);
+}
+
+/****************************************************************************
+** time type
+** In string context: HH:MM:SS
+** In number context: HHMMSS
+** Stored as a 3 byte unsigned int
+****************************************************************************/
+
+void Field_time::store(const char *from,uint len)
+{
+ TIME ltime;
+ long tmp;
+ if (str_to_time(from,len,&ltime))
+ tmp=0L;
+ else
+ {
+ if (ltime.month)
+ ltime.day=0;
+ tmp=(ltime.day*24L+ltime.hour)*10000L+(ltime.minute*100+ltime.second);
+ if (tmp > 8385959)
+ {
+ tmp=8385959;
+ current_thd->cuted_fields++;
+ }
+ }
+ if (ltime.neg)
+ tmp= -tmp;
+ Field_time::store((longlong) tmp);
+}
+
+
+void Field_time::store(double nr)
+{
+ long tmp;
+ if (nr > 8385959.0)
+ {
+ tmp=8385959L;
+ current_thd->cuted_fields++;
+ }
+ else if (nr < -8385959.0)
+ {
+ tmp= -8385959L;
+ current_thd->cuted_fields++;
+ }
+ else
+ {
+ tmp=(long) floor(fabs(nr)); // Remove fractions
+ if (nr < 0)
+ tmp= -tmp;
+ if (tmp % 100 > 59 || tmp/100 % 100 > 59)
+ {
+ tmp=0;
+ current_thd->cuted_fields++;
+ }
+ }
+ int3store(ptr,tmp);
+}
+
+
+void Field_time::store(longlong nr)
+{
+ long tmp;
+ if (nr > (longlong) 8385959L)
+ {
+ tmp=8385959L;
+ current_thd->cuted_fields++;
+ }
+ else if (nr < (longlong) -8385959L)
+ {
+ tmp= -8385959L;
+ current_thd->cuted_fields++;
+ }
+ else
+ {
+ tmp=(long) nr;
+ if (tmp % 100 > 59 || tmp/100 % 100 > 59)
+ {
+ tmp=0;
+ current_thd->cuted_fields++;
+ }
+ }
+ int3store(ptr,tmp);
+}
+
+
+double Field_time::val_real(void)
+{
+ ulong j= (ulong) uint3korr(ptr);
+ return (double) j;
+}
+
+longlong Field_time::val_int(void)
+{
+ return (longlong) sint3korr(ptr);
+}
+
+String *Field_time::val_str(String *val_buffer,
+ String *val_ptr __attribute__((unused)))
+{
+ val_buffer->alloc(16);
+ long tmp=(long) sint3korr(ptr);
+ const char *sign="";
+ if (tmp < 0)
+ {
+ tmp= -tmp;
+ sign= "-";
+ }
+ sprintf((char*) val_buffer->ptr(),"%s%02d:%02d:%02d",
+ sign,(int) (tmp/10000), (int) (tmp/100 % 100),
+ (int) (tmp % 100));
+ val_buffer->length(strlen(val_buffer->ptr()));
+ return val_buffer;
+}
+
+bool Field_time::get_time(TIME *ltime)
+{
+ long tmp=(long) sint3korr(ptr);
+ ltime->neg=0;
+ if (tmp < 0)
+ {
+ ltime->neg= 1;
+ tmp=-tmp;
+ }
+ ltime->day=tmp/10000;
+ tmp-=ltime->day*10000;
+ ltime->hour= tmp/100;
+ ltime->second= 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);
+ return (a < b) ? -1 : (a > b) ? 1 : 0;
+}
+
+void Field_time::sort_string(char *to,uint length __attribute__((unused)))
+{
+ to[0] = (uchar) (ptr[2] ^ 128);
+ to[1] = ptr[1];
+ to[2] = ptr[0];
+}
+
+void Field_time::sql_type(String &res) const
+{
+ res.set("time",4);
+}
+
+/****************************************************************************
+** year type
+** Save in a byte the year 0, 1901->2155
+** Can handle 2 byte or 4 byte years!
+****************************************************************************/
+
+void Field_year::store(const char *from, uint len)
+{
+ String tmp_str(from,len);
+ long nr= strtol(tmp_str.c_ptr(),NULL,10);
+
+ if (nr < 0 || nr >= 100 && nr <= 1900 || nr > 2155)
+ {
+ *ptr=0;
+ current_thd->cuted_fields++;
+ return;
+ }
+ else if (current_thd->count_cuted_fields && !test_if_int(from,len))
+ current_thd->cuted_fields++;
+ if (nr != 0 || len != 4)
+ {
+ if (nr < YY_PART_YEAR)
+ nr+=100; // 2000 - 2069
+ else if (nr > 1900)
+ nr-= 1900;
+ }
+ *ptr= (char) (unsigned char) nr;
+}
+
+void Field_year::store(double nr)
+{
+ if (nr < 0.0 || nr >= 2155.0)
+ Field_year::store((longlong) -1);
+ else
+ Field_year::store((longlong) nr);
+}
+
+void Field_year::store(longlong nr)
+{
+ if (nr < 0 || nr >= 100 && nr <= 1900 || nr > 2155)
+ {
+ *ptr=0;
+ current_thd->cuted_fields++;
+ return;
+ }
+ if (nr != 0 || field_length != 4) // 0000 -> 0; 00 -> 2000
+ {
+ if (nr < YY_PART_YEAR)
+ nr+=100; // 2000 - 2069
+ else if (nr > 1900)
+ nr-= 1900;
+ }
+ *ptr= (char) (unsigned char) nr;
+}
+
+
+double Field_year::val_real(void)
+{
+ return (double) Field_year::val_int();
+}
+
+longlong Field_year::val_int(void)
+{
+ int tmp= (int) ((uchar*) ptr)[0];
+ if (field_length != 4)
+ tmp%=100; // Return last 2 char
+ else if (tmp)
+ tmp+=1900;
+ return (longlong) tmp;
+}
+
+String *Field_year::val_str(String *val_buffer,
+ String *val_ptr __attribute__((unused)))
+{
+ val_buffer->alloc(5);
+ val_buffer->length(field_length);
+ char *to=(char*) val_buffer->ptr();
+ sprintf(to,field_length == 2 ? "%02d" : "%04d",(int) Field_year::val_int());
+ return val_buffer;
+}
+
+void Field_year::sql_type(String &res) const
+{
+ sprintf((char*) res.ptr(),"year(%d)",(int) field_length);
+ res.length(strlen(res.ptr()));
+}
+
+
+/****************************************************************************
+** date type
+** In string context: YYYY-MM-DD
+** In number context: YYYYMMDD
+** Stored as a 4 byte unsigned int
+****************************************************************************/
+
+void Field_date::store(const char *from,uint len)
+{
+ TIME l_time;
+ ulong 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);
+#ifdef WORDS_BIGENDIAN
+ if (table->db_low_byte_first)
+ {
+ int4store(ptr,tmp);
+ }
+ else
+#endif
+ longstore(ptr,tmp);
+}
+
+
+void Field_date::store(double nr)
+{
+ long tmp;
+ if (nr >= 19000000000000.0 && nr <= 99991231235959.0)
+ nr=floor(nr/1000000.0); // Timestamp to date
+ if (nr < 0.0 || nr > 99991231.0)
+ {
+ tmp=0L;
+ current_thd->cuted_fields++;
+ }
+ else
+ tmp=(long) rint(nr);
+#ifdef WORDS_BIGENDIAN
+ if (table->db_low_byte_first)
+ {
+ int4store(ptr,tmp);
+ }
+ else
+#endif
+ longstore(ptr,tmp);
+}
+
+
+void Field_date::store(longlong nr)
+{
+ long tmp;
+ if (nr >= LL(19000000000000) && nr < LL(99991231235959))
+ nr=nr/LL(1000000); // Timestamp to date
+ if (nr < 0 || nr > LL(99991231))
+ {
+ tmp=0L;
+ current_thd->cuted_fields++;
+ }
+ else
+ tmp=(long) nr;
+#ifdef WORDS_BIGENDIAN
+ if (table->db_low_byte_first)
+ {
+ int4store(ptr,tmp);
+ }
+ else
+#endif
+ longstore(ptr,tmp);
+}
+
+
+double Field_date::val_real(void)
+{
+ int32 j;
+#ifdef WORDS_BIGENDIAN
+ if (table->db_low_byte_first)
+ j=sint4korr(ptr);
+ else
+#endif
+ longget(j,ptr);
+ return (double) (uint32) j;
+}
+
+longlong Field_date::val_int(void)
+{
+ int32 j;
+#ifdef WORDS_BIGENDIAN
+ if (table->db_low_byte_first)
+ j=sint4korr(ptr);
+ else
+#endif
+ longget(j,ptr);
+ return (longlong) (uint32) j;
+}
+
+String *Field_date::val_str(String *val_buffer,
+ String *val_ptr __attribute__((unused)))
+{
+ val_buffer->alloc(field_length);
+ val_buffer->length(field_length);
+ int32 tmp;
+#ifdef WORDS_BIGENDIAN
+ if (table->db_low_byte_first)
+ tmp=sint4korr(ptr);
+ else
+#endif
+ longget(tmp,ptr);
+ sprintf((char*) val_buffer->ptr(),"%04d-%02d-%02d",
+ (int) ((uint32) tmp/10000L % 10000), (int) ((uint32) tmp/100 % 100),
+ (int) ((uint32) tmp % 100));
+ return val_buffer;
+}
+
+int Field_date::cmp(const char *a_ptr, const char *b_ptr)
+{
+ int32 a,b;
+#ifdef WORDS_BIGENDIAN
+ if (table->db_low_byte_first)
+ {
+ a=sint4korr(a_ptr);
+ b=sint4korr(b_ptr);
+ }
+ else
+#endif
+ {
+ longget(a,a_ptr);
+ longget(b,b_ptr);
+ }
+ return ((uint32) a < (uint32) b) ? -1 : ((uint32) a > (uint32) b) ? 1 : 0;
+}
+
+
+void Field_date::sort_string(char *to,uint length __attribute__((unused)))
+{
+#ifdef WORDS_BIGENDIAN
+ if (!table->db_low_byte_first)
+ {
+ to[0] = ptr[0];
+ to[1] = ptr[1];
+ to[2] = ptr[2];
+ to[3] = ptr[3];
+ }
+ else
+#endif
+ {
+ to[0] = ptr[3];
+ to[1] = ptr[2];
+ to[2] = ptr[1];
+ to[3] = ptr[0];
+ }
+}
+
+void Field_date::sql_type(String &res) const
+{
+ res.set("date",4);
+}
+
+/****************************************************************************
+** The new date type
+** This is identical to the old date type, but stored on 3 bytes instead of 4
+** In number context: YYYYMMDD
+****************************************************************************/
+
+void Field_newdate::store(const char *from,uint len)
+{
+ TIME l_time;
+ long tmp;
+ if (str_to_TIME(from,len,&l_time,1) == TIMESTAMP_NONE)
+ tmp=0L;
+ else
+ tmp= l_time.day + l_time.month*32 + l_time.year*16*32;
+ int3store(ptr,tmp);
+}
+
+void Field_newdate::store(double nr)
+{
+ if (nr < 0.0 || nr > 99991231235959.0)
+ Field_newdate::store((longlong) -1);
+ else
+ Field_newdate::store((longlong) rint(nr));
+}
+
+
+void Field_newdate::store(longlong nr)
+{
+ long tmp;
+ if (nr >= LL(100000000) && nr <= LL(99991231235959))
+ nr=nr/LL(1000000); // Timestamp to date
+ if (nr < 0L || nr > 99991231L)
+ {
+ tmp=0;
+ current_thd->cuted_fields++;
+ }
+ else
+ {
+ tmp=(long) nr;
+ if (tmp)
+ {
+ if (tmp < YY_PART_YEAR*10000L) // Fix short dates
+ tmp+=20000000L;
+ else if (tmp < 999999L)
+ tmp+=19000000L;
+ }
+ uint month=((tmp/100) % 100);
+ uint day= tmp%100;
+ if (month > 12 || day > 31)
+ {
+ tmp=0L; // Don't allow date to change
+ current_thd->cuted_fields++;
+ }
+ else
+ tmp= day + month*32 + (tmp/10000)*16*32;
+ }
+ int3store(ptr,tmp);
+}
+
+void Field_newdate::store_time(TIME *ltime,timestamp_type type)
+{
+ long tmp;
+ if (type == TIMESTAMP_DATE || type == TIMESTAMP_FULL)
+ tmp=ltime->year*16*32+ltime->month*32+ltime->day;
+ else
+ {
+ tmp=0;
+ current_thd->cuted_fields++;
+ }
+ int3store(ptr,tmp);
+}
+
+
+
+double Field_newdate::val_real(void)
+{
+ return (double) Field_newdate::val_int();
+}
+
+longlong Field_newdate::val_int(void)
+{
+ ulong j=uint3korr(ptr);
+ j= (j % 32L)+(j / 32L % 16L)*100L + (j/(16L*32L))*10000L;
+ return (longlong) j;
+}
+
+String *Field_newdate::val_str(String *val_buffer,
+ String *val_ptr __attribute__((unused)))
+{
+ val_buffer->alloc(field_length);
+ val_buffer->length(field_length);
+ ulong tmp=(ulong) uint3korr(ptr);
+ int part;
+ char *pos=(char*) val_buffer->ptr()+10;
+
+ /* Open coded to get more speed */
+ *pos--=0;
+ part=(int) (tmp & 31);
+ *pos--='0'+part%10;
+ *pos--='0'+part/10;
+ *pos--='-';
+ part=(int) (tmp >> 5 & 15);
+ *pos--='0'+part%10;
+ *pos--='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;
+ return val_buffer;
+}
+
+bool Field_newdate::get_date(TIME *ltime,bool fuzzydate)
+{
+ if (is_null())
+ return 1;
+ ulong tmp=(ulong) uint3korr(ptr);
+ bzero((char*) ltime,sizeof(*ltime));
+ ltime->day= tmp & 31;
+ ltime->month= (tmp >> 5) & 15;
+ ltime->year= (tmp >> 9);
+ return (!fuzzydate && (!ltime->month || !ltime->day) && ltime->year) ? 1 : 0;
+}
+
+bool Field_newdate::get_time(TIME *ltime)
+{
+ Field_newdate::get_date(ltime,0);
+ return 0;
+}
+
+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);
+ return (a < b) ? -1 : (a > b) ? 1 : 0;
+}
+
+void Field_newdate::sort_string(char *to,uint length __attribute__((unused)))
+{
+ to[0] = ptr[2];
+ to[1] = ptr[1];
+ to[2] = ptr[0];
+}
+
+void Field_newdate::sql_type(String &res) const
+{
+ res.set("date",4);
+}
+
+
+/****************************************************************************
+** datetime type
+** In string context: YYYY-MM-DD HH:MM:DD
+** In number context: YYYYMMDDHHMMDD
+** Stored as a 8 byte unsigned int. Should sometimes be change to a 6 byte int.
+****************************************************************************/
+
+void Field_datetime::store(const char *from,uint len)
+{
+ longlong tmp=str_to_datetime(from,len,1);
+#ifdef WORDS_BIGENDIAN
+ if (table->db_low_byte_first)
+ {
+ int8store(ptr,tmp);
+ }
+ else
+#endif
+ longlongstore(ptr,tmp);
+}
+
+
+void Field_datetime::store(double nr)
+{
+ if (nr < 0.0 || nr > 99991231235959.0)
+ {
+ nr=0.0;
+ current_thd->cuted_fields++;
+ }
+ Field_datetime::store((longlong) rint(nr));
+}
+
+
+void Field_datetime::store(longlong nr)
+{
+ if (nr < 0 || nr > LL(99991231235959))
+ {
+ nr=0;
+ current_thd->cuted_fields++;
+ }
+ else
+ nr=fix_datetime(nr);
+#ifdef WORDS_BIGENDIAN
+ if (table->db_low_byte_first)
+ {
+ int8store(ptr,nr);
+ }
+ else
+#endif
+ longlongstore(ptr,nr);
+}
+
+void Field_datetime::store_time(TIME *ltime,timestamp_type type)
+{
+ longlong tmp;
+ if (type == TIMESTAMP_DATE || type == TIMESTAMP_FULL)
+ tmp=((ltime->year*10000L+ltime->month*100+ltime->day)*LL(1000000)+
+ (ltime->hour*10000L+ltime->minute*100+ltime->second));
+ else
+ {
+ tmp=0;
+ current_thd->cuted_fields++;
+ }
+#ifdef WORDS_BIGENDIAN
+ if (table->db_low_byte_first)
+ {
+ int8store(ptr,tmp);
+ }
+ else
+#endif
+ longlongstore(ptr,tmp);
+}
+
+
+double Field_datetime::val_real(void)
+{
+ return (double) Field_datetime::val_int();
+}
+
+longlong Field_datetime::val_int(void)
+{
+ longlong j;
+#ifdef WORDS_BIGENDIAN
+ if (table->db_low_byte_first)
+ j=sint8korr(ptr);
+ else
+#endif
+ longlongget(j,ptr);
+ return j;
+}
+
+
+String *Field_datetime::val_str(String *val_buffer,
+ String *val_ptr __attribute__((unused)))
+{
+ val_buffer->alloc(field_length);
+ val_buffer->length(field_length);
+ ulonglong tmp;
+ long part1,part2;
+ char *pos;
+ int part3;
+
+#ifdef WORDS_BIGENDIAN
+ if (table->db_low_byte_first)
+ tmp=sint8korr(ptr);
+ else
+#endif
+ longlongget(tmp,ptr);
+
+ /*
+ Avoid problem with slow longlong aritmetic and sprintf
+ */
+
+ part1=(long) (tmp/LL(1000000));
+ part2=(long) (tmp - (ulonglong) part1*LL(1000000));
+
+ 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;
+ 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));
+
+ 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;
+ return (!fuzzydate && (!ltime->month || !ltime->day) && ltime->year) ? 1 : 0;
+}
+
+bool Field_datetime::get_time(TIME *ltime)
+{
+ Field_datetime::get_date(ltime,0);
+ return 0;
+}
+
+int Field_datetime::cmp(const char *a_ptr, const char *b_ptr)
+{
+ longlong a,b;
+#ifdef WORDS_BIGENDIAN
+ if (table->db_low_byte_first)
+ {
+ a=sint8korr(a_ptr);
+ b=sint8korr(b_ptr);
+ }
+ else
+#endif
+ {
+ longlongget(a,a_ptr);
+ longlongget(b,b_ptr);
+ }
+ return ((ulonglong) a < (ulonglong) b) ? -1 :
+ ((ulonglong) a > (ulonglong) b) ? 1 : 0;
+}
+
+void Field_datetime::sort_string(char *to,uint length __attribute__((unused)))
+{
+#ifdef WORDS_BIGENDIAN
+ if (!table->db_low_byte_first)
+ {
+ to[0] = ptr[0];
+ to[1] = ptr[1];
+ to[2] = ptr[2];
+ to[3] = ptr[3];
+ to[4] = ptr[4];
+ to[5] = ptr[5];
+ to[6] = ptr[6];
+ to[7] = ptr[7];
+ }
+ else
+#endif
+ {
+ to[0] = ptr[7];
+ to[1] = ptr[6];
+ to[2] = ptr[5];
+ to[3] = ptr[4];
+ to[4] = ptr[3];
+ to[5] = ptr[2];
+ to[6] = ptr[1];
+ to[7] = ptr[0];
+ }
+}
+
+
+void Field_datetime::sql_type(String &res) const
+{
+ res.set("datetime",8);
+}
+
+/****************************************************************************
+** string type
+** A string may be varchar or binary
+****************************************************************************/
+
+ /* Copy a string and fill with space */
+
+void Field_string::store(const char *from,uint length)
+{
+#ifdef USE_TIS620
+ if(!binary_flag) {
+ ThNormalize((uchar *)ptr, field_length, (uchar *)from, length);
+ if(length < field_length) {
+ bfill(ptr + length, field_length - length, ' ');
+ }
+ }
+#else
+ if (length <= field_length)
+ {
+ memcpy(ptr,from,length);
+ if (length < field_length)
+ bfill(ptr+length,field_length-length,' ');
+ }
+ else
+ {
+ memcpy(ptr,from,field_length);
+ if (current_thd->count_cuted_fields)
+ { // Check if we loosed some info
+ const char *end=from+length;
+ for (from+=field_length ; from != end ; from++)
+ {
+ if (!isspace(*from))
+ {
+ current_thd->cuted_fields++;
+ break;
+ }
+ }
+ }
+ }
+#endif /* USE_TIS620 */
+}
+
+
+void Field_string::store(double nr)
+{
+ char buff[MAX_FIELD_WIDTH],*end;
+ int width=min(field_length,DBL_DIG+5);
+ sprintf(buff,"%-*.*g",width,max(width-5,0),nr);
+ end=strcend(buff,' ');
+ Field_string::store(buff,(uint) (end - buff));
+}
+
+
+void Field_string::store(longlong nr)
+{
+ char buff[22];
+ char *end=longlong10_to_str(nr,buff,-10);
+ Field_string::store(buff,end-buff);
+}
+
+
+double Field_string::val_real(void)
+{
+ double value;
+ char save=ptr[field_length]; // Ok to patch record
+ ptr[field_length]=0;
+ value=atof(ptr);
+ ptr[field_length]=save;
+ return value;
+}
+
+
+longlong Field_string::val_int(void)
+{
+ longlong value;
+ char save=ptr[field_length]; // Ok to patch record
+ ptr[field_length]=0;
+ value=strtoll(ptr,NULL,10);
+ ptr[field_length]=save;
+ return value;
+}
+
+
+String *Field_string::val_str(String *val_buffer __attribute__((unused)),
+ String *val_ptr)
+{
+ char *end=ptr+field_length;
+#ifdef WANT_TRUE_BINARY_STRINGS
+ if (!binary)
+#endif
+ while (end > ptr && end[-1] == ' ')
+ end--;
+ val_ptr->set((const char*) ptr,(uint) (end - ptr));
+ return val_ptr;
+}
+
+
+int Field_string::cmp(const char *a_ptr, const char *b_ptr)
+{
+ if (binary_flag)
+ return memcmp(a_ptr,b_ptr,field_length);
+ else
+ return my_sortcmp(a_ptr,b_ptr,field_length);
+}
+
+void Field_string::sort_string(char *to,uint length)
+{
+ if (binary_flag)
+ memcpy((byte*) to,(byte*) ptr,(size_t) length);
+ else
+ {
+#ifdef USE_STRCOLL
+ if (use_strcoll(default_charset_info)) {
+ uint tmp=my_strnxfrm(default_charset_info,
+ (unsigned char *)to, (unsigned char *) ptr,
+ length, field_length);
+ if (tmp < length)
+ bzero(to + tmp, length - tmp);
+ }
+ else
+#endif
+ for (char *from=ptr,*end=ptr+length ; from != end ;)
+ *to++=(char) my_sort_order[(uint) (uchar) *from++];
+ }
+}
+
+
+void Field_string::sql_type(String &res) const
+{
+ sprintf((char*) res.ptr(),"%s(%d)",
+ field_length > 3 &&
+ (table->db_options_in_use & HA_OPTION_PACK_RECORD) ?
+ "varchar" : "char",
+ (int) field_length);
+ res.length(strlen(res.ptr()));
+ if (binary_flag)
+ res.append(" binary");
+}
+
+
+char *Field_string::pack(char *to, const char *from, uint max_length)
+{
+ const char *end=from+min(field_length,max_length);
+ uchar length;
+ while (end > from && end[-1] == ' ')
+ end--;
+ *to= length=(uchar) (end-from);
+ memcpy(to+1, from, (int) length);
+ return to+1+length;
+}
+
+
+const char *Field_string::unpack(char *to, const char *from)
+{
+ uint length= (uint) (uchar) *from++;
+ memcpy(to, from, (int) length);
+ bfill(to+length, field_length - length, ' ');
+ return from+length;
+}
+
+
+int Field_string::pack_cmp(const char *a, const char *b, uint length)
+{
+ uint a_length= (uint) (uchar) *a++;
+ uint b_length= (uint) (uchar) *b++;
+
+ if (binary_flag)
+ {
+ int cmp= memcmp(a,b,min(a_length,b_length));
+ return cmp ? cmp : (int) (a_length - b_length);
+ }
+ return my_sortncmp(a,a_length, b,b_length);
+}
+
+
+uint Field_string::packed_col_length(const char *ptr)
+{
+ if (field_length > 255)
+ return uint2korr(ptr)+2;
+ else
+ return (uint) ((uchar) *ptr)+1;
+}
+
+uint Field_string::max_packed_col_length(uint max_length)
+{
+ return (field_length > 255 ? 2 : 1)+max_length;
+}
+
+
+/****************************************************************************
+** VARCHAR type (Not available for the end user yet)
+****************************************************************************/
+
+
+void Field_varstring::store(const char *from,uint length)
+{
+#ifdef USE_TIS620
+ if(!binary_flag)
+ {
+ ThNormalize((uchar *) ptr+2, field_length, (uchar *) from, length);
+ }
+#else
+ if (length <= field_length)
+ {
+ memcpy(ptr+2,from,length);
+ }
+ else
+ {
+ length=field_length;
+ memcpy(ptr+2,from,field_length);
+ current_thd->cuted_fields++;
+ }
+#endif /* USE_TIS620 */
+ int2store(ptr,length);
+}
+
+
+void Field_varstring::store(double nr)
+{
+ char buff[MAX_FIELD_WIDTH],*end;
+ int width=min(field_length,DBL_DIG+5);
+ sprintf(buff,"%-*.*g",width,max(width-5,0),nr);
+ end=strcend(buff,' ');
+ Field_varstring::store(buff,(uint) (end - buff));
+}
+
+
+void Field_varstring::store(longlong nr)
+{
+ char buff[22];
+ char *end=longlong10_to_str(nr,buff,-10);
+ Field_varstring::store(buff,end-buff);
+}
+
+
+double Field_varstring::val_real(void)
+{
+ double value;
+ uint length=uint2korr(ptr)+2;
+ char save=ptr[length]; // Ok to patch record
+ ptr[length]=0;
+ value=atof(ptr+2);
+ ptr[length]=save;
+ return value;
+}
+
+
+longlong Field_varstring::val_int(void)
+{
+ longlong value;
+ uint length=uint2korr(ptr)+2;
+ char save=ptr[length]; // Ok to patch record
+ ptr[length]=0;
+ value=strtoll(ptr+2,NULL,10);
+ ptr[length]=save;
+ return value;
+}
+
+
+String *Field_varstring::val_str(String *val_buffer __attribute__((unused)),
+ String *val_ptr)
+{
+ uint length=uint2korr(ptr);
+ val_ptr->set((const char*) ptr+2,length);
+ return val_ptr;
+}
+
+
+int Field_varstring::cmp(const char *a_ptr, const char *b_ptr)
+{
+ uint a_length=uint2korr(a_ptr);
+ uint b_length=uint2korr(b_ptr);
+ int diff;
+ if (binary_flag)
+ diff=memcmp(a_ptr+2,b_ptr+2,min(a_length,b_length));
+ else
+ diff=my_sortcmp(a_ptr+2,b_ptr+2,min(a_length,b_length));
+ return diff ? diff : (int) (a_length - b_length);
+}
+
+void Field_varstring::sort_string(char *to,uint length)
+{
+ uint tot_length=uint2korr(ptr);
+ if (binary_flag)
+ memcpy((byte*) to,(byte*) ptr+2,(size_t) tot_length);
+ else
+ {
+#ifdef USE_STRCOLL
+ if (use_strcoll(default_charset_info))
+ tot_length=my_strnxfrm(default_charset_info,
+ (unsigned char *) to, (unsigned char *)ptr+2,
+ length, tot_length);
+ else
+ {
+#endif
+ char *tmp=to;
+ if (tot_length > length)
+ tot_length=length;
+ for (char *from=ptr+2,*end=from+tot_length ; from != end ;)
+ *tmp++=(char) my_sort_order[(uint) (uchar) *from++];
+#ifdef USE_STRCOLL
+ }
+#endif
+ }
+ if (tot_length < length)
+ bzero(to+tot_length,length-tot_length);
+}
+
+
+void Field_varstring::sql_type(String &res) const
+{
+ sprintf((char*) res.ptr(),"varchar(%d)",(int) field_length);
+ res.length(strlen(res.ptr()));
+ if (binary_flag)
+ res.append(" binary");
+}
+
+char *Field_varstring::pack(char *to, const char *from, uint max_length)
+{
+ uint length=uint2korr(to);
+ if (length > max_length)
+ length=max_length;
+ *to++= (length & 255);
+ if (max_length > 255)
+ *to++= (uchar) (length >> 8);
+ if (length)
+ memcpy(to, from+2, length);
+ return to+length;
+}
+
+
+const char *Field_varstring::unpack(char *to, const char *from)
+{
+ uint length;
+ if (field_length > 255)
+ {
+ length= (uint) (uchar) (*to= *from++);
+ to[1]=0;
+ }
+ else
+ {
+ length=uint2korr(from);
+ to[0] = *from++;
+ to[1] = *from++;
+ }
+ if (length)
+ memcpy(to+2, from, length);
+ return from+length;
+}
+
+
+int Field_varstring::pack_cmp(const char *a, const char *b, uint key_length)
+{
+ uint a_length;
+ uint b_length;
+ if (key_length > 255)
+ {
+ a_length=uint2korr(a); a+=2;
+ b_length=uint2korr(b); b+=2;
+ }
+ else
+ {
+ a_length= (uint) (uchar) *a++;
+ b_length= (uint) (uchar) *b++;
+ }
+ if (binary_flag)
+ {
+ int cmp= memcmp(a,b,min(a_length,b_length));
+ return cmp ? cmp : (int) (a_length - b_length);
+ }
+ return my_sortncmp(a,a_length, b,b_length);
+}
+
+uint Field_varstring::packed_col_length(const char *ptr)
+{
+ if (field_length > 255)
+ return uint2korr(ptr)+2;
+ else
+ return (uint) ((uchar) *ptr)+1;
+}
+
+uint Field_varstring::max_packed_col_length(uint max_length)
+{
+ return (field_length > 255 ? 2 : 1)+max_length;
+}
+
+/****************************************************************************
+** blob type
+** A blob is saved as a length and a pointer. The length is stored in the
+** packlength slot and may be from 1-4.
+****************************************************************************/
+
+Field_blob::Field_blob(char *ptr_arg, uchar *null_ptr_arg, uint 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)
+ :Field_str(ptr_arg, (1L << min(blob_pack_length,3)*8)-1L,
+ null_ptr_arg, null_bit_arg, unireg_check_arg, field_name_arg,
+ table_arg),
+ packlength(blob_pack_length),binary_flag(binary_arg)
+{
+ flags|= BLOB_FLAG;
+ if (binary_arg)
+ flags|=BINARY_FLAG;
+ if (table)
+ table->blob_fields++;
+}
+
+
+void Field_blob::store_length(ulong number)
+{
+ switch (packlength) {
+ case 1:
+ if (number > 255)
+ {
+ number=255;
+ current_thd->cuted_fields++;
+ }
+ ptr[0]= (uchar) number;
+ break;
+ case 2:
+ if (number > (uint16) ~0)
+ {
+ number= (uint16) ~0;
+ current_thd->cuted_fields++;
+ }
+#ifdef WORDS_BIGENDIAN
+ if (table->db_low_byte_first)
+ {
+ int2store(ptr,(unsigned short) number);
+ }
+ else
+#endif
+ shortstore(ptr,(unsigned short) number);
+ break;
+ case 3:
+ if (number > (ulong) (1L << 24))
+ {
+ number= (ulong) (1L << 24)-1L;
+ current_thd->cuted_fields++;
+ }
+ int3store(ptr,number);
+ break;
+ case 4:
+#ifdef WORDS_BIGENDIAN
+ if (table->db_low_byte_first)
+ {
+ int4store(ptr,number);
+ }
+ else
+#endif
+ longstore(ptr,number);
+ }
+}
+
+
+ulong Field_blob::get_length(const char *pos)
+{
+ switch (packlength) {
+ case 1:
+ return (ulong) (uchar) pos[0];
+ case 2:
+ {
+ uint16 tmp;
+#ifdef WORDS_BIGENDIAN
+ if (table->db_low_byte_first)
+ tmp=sint2korr(pos);
+ else
+#endif
+ shortget(tmp,pos);
+ return (ulong) tmp;
+ }
+ case 3:
+ return (ulong) uint3korr(pos);
+ case 4:
+ {
+ uint32 tmp;
+#ifdef WORDS_BIGENDIAN
+ if (table->db_low_byte_first)
+ tmp=uint4korr(pos);
+ else
+#endif
+ longget(tmp,pos);
+ return (ulong) tmp;
+ }
+ }
+ return 0; // Impossible
+}
+
+
+void Field_blob::store(const char *from,uint len)
+{
+ if (!len)
+ {
+ bzero(ptr,Field_blob::pack_length());
+ }
+ else
+ {
+#ifdef USE_TIS620
+ char *th_ptr=0;
+#endif
+ Field_blob::store_length(len);
+ if (table->copy_blobs || len <= MAX_FIELD_WIDTH)
+ { // Must make a copy
+#ifdef USE_TIS620
+ if(!binary_flag)
+ {
+ /* If there isn't enough memory, use original string */
+ if ((th_ptr=(char * ) my_malloc(sizeof(char) * len,MYF(0))))
+ {
+ ThNormalize((uchar *) th_ptr, len, (uchar *) from, len);
+ from= (const char*) th_ptr;
+ }
+ }
+#endif /* USE_TIS620 */
+ value.copy(from,len);
+ from=value.ptr();
+#ifdef USE_TIS620
+ my_free(th_ptr,MYF(MY_ALLOW_ZERO_PTR));
+#endif
+ }
+ bmove(ptr+packlength,(char*) &from,sizeof(char*));
+ }
+}
+
+
+void Field_blob::store(double nr)
+{
+ value.set(nr);
+ Field_blob::store(value.ptr(),value.length());
+}
+
+
+void Field_blob::store(longlong nr)
+{
+ value.set(nr);
+ Field_blob::store(value.ptr(),value.length());
+}
+
+
+double Field_blob::val_real(void)
+{
+ char *blob;
+
+ memcpy_fixed(&blob,ptr+packlength,sizeof(char*));
+ if (!blob)
+ return 0.0;
+ ulong length=get_length(ptr);
+
+ char save=blob[length]; // Ok to patch blob in NISAM
+ blob[length]=0;
+ double nr=atof(blob);
+ blob[length]=save;
+ return nr;
+}
+
+
+longlong Field_blob::val_int(void)
+{
+ char *blob;
+ memcpy_fixed(&blob,ptr+packlength,sizeof(char*));
+ if (!blob)
+ return 0;
+ ulong length=get_length(ptr);
+
+ char save=blob[length]; // Ok to patch blob in NISAM
+ blob[length]=0;
+ longlong nr=strtoll(blob,NULL,10);
+ blob[length]=save;
+ return nr;
+}
+
+
+String *Field_blob::val_str(String *val_buffer __attribute__((unused)),
+ String *val_ptr)
+{
+ char *blob;
+ memcpy_fixed(&blob,ptr+packlength,sizeof(char*));
+ if (!blob)
+ val_ptr->length(0);
+ else
+ val_ptr->set((const char*) blob,get_length(ptr));
+ return val_ptr;
+}
+
+
+int Field_blob::cmp(const char *a,ulong a_length, const char *b,
+ ulong b_length)
+{
+ int diff;
+ if (binary_flag)
+ diff=memcmp(a,b,min(a_length,b_length));
+ else
+ diff=my_sortcmp(a,b,min(a_length,b_length));
+ return diff ? diff : (int) (a_length - b_length);
+}
+
+
+int Field_blob::cmp(const char *a_ptr, const char *b_ptr)
+{
+ char *blob1,*blob2;
+ memcpy_fixed(&blob1,a_ptr+packlength,sizeof(char*));
+ memcpy_fixed(&blob2,b_ptr+packlength,sizeof(char*));
+ return Field_blob::cmp(blob1,get_length(a_ptr),
+ blob2,get_length(b_ptr));
+}
+
+
+int Field_blob::cmp_offset(uint row_offset)
+{
+ return Field_blob::cmp(ptr,ptr+row_offset);
+}
+
+
+int Field_blob::cmp_binary_offset(uint row_offset)
+{
+ return cmp_binary(ptr, ptr+row_offset);
+}
+
+
+int Field_blob::cmp_binary(const char *a_ptr, const char *b_ptr,
+ ulong max_length)
+{
+ char *a,*b;
+ uint diff;
+ ulong 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);
+ if (a_length > max_length)
+ a_length=max_length;
+ b_length=get_length(b_ptr);
+ if (b_length > max_length)
+ b_length=max_length;
+ diff=memcmp(a,b,min(a_length,b_length));
+ return diff ? diff : (int) (a_length - b_length);
+}
+
+
+/* The following is used only when comparing a key */
+
+void Field_blob::get_key_image(char *buff,uint length)
+{
+ length-=HA_KEY_BLOB_LENGTH;
+ ulong blob_length=get_length(ptr);
+ char *blob;
+ if ((ulong) length > blob_length)
+ length=(uint) blob_length;
+ int2store(buff,length);
+ get_ptr(&blob);
+ memcpy(buff+2,blob,length);
+}
+
+void Field_blob::set_key_image(char *buff,uint length)
+{
+ length=uint2korr(buff);
+ Field_blob::store(buff+2,length);
+}
+
+int Field_blob::key_cmp(const byte *key_ptr, uint max_key_length)
+{
+ char *blob1;
+ uint blob_length=get_length(ptr);
+ max_key_length-=2;
+ memcpy_fixed(&blob1,ptr+packlength,sizeof(char*));
+ return Field_blob::cmp(blob1,min(blob_length, max_key_length),
+ (char*) key_ptr+2,uint2korr(key_ptr));
+}
+
+int Field_blob::key_cmp(const byte *a,const byte *b)
+{
+ return Field_blob::cmp((char*) a+2,uint2korr(a),
+ (char*) b+2,uint2korr(b));
+}
+
+
+void Field_blob::sort_string(char *to,uint length)
+{
+ char *blob;
+ uint blob_length=get_length();
+#ifdef USE_STRCOLL
+ uint blob_org_length=blob_length;
+#endif
+ if (!blob_length)
+ bzero(to,length);
+ else
+ {
+ if (blob_length > length)
+ blob_length=length;
+ memcpy_fixed(&blob,ptr+packlength,sizeof(char*));
+ if (binary_flag)
+ {
+ memcpy(to,blob,blob_length);
+ to+=blob_length;
+ }
+ else
+ {
+#ifdef USE_STRCOLL
+ if (use_strcoll(default_charset_info))
+ {
+ blob_length=my_strnxfrm(default_charset_info,
+ (unsigned char *)to,(unsigned char *)blob,
+ length,blob_org_length);
+ if (blob_length >= length)
+ return;
+ to+=blob_length;
+ }
+ else
+#endif
+ for (char *end=blob+blob_length ; blob != end ;)
+ *to++=(char) my_sort_order[(uint) (uchar) *blob++];
+ }
+ bzero(to,length-blob_length);
+ }
+}
+
+
+void Field_blob::sql_type(String &res) const
+{
+ const char *str;
+ switch (packlength) {
+ default: str="tiny"; break;
+ case 2: str=""; break;
+ case 3: str="medium"; break;
+ case 4: str="long"; break;
+ }
+ res.set(str,strlen(str));
+ res.append(binary_flag ? "blob" : "text");
+}
+
+
+/* Keys for blobs are like keys on varchars */
+
+int Field_blob::pack_cmp(const char *a, const char *b, uint key_length)
+{
+ uint a_length;
+ uint b_length;
+ if (key_length > 255)
+ {
+ a_length=uint2korr(a); a+=2;
+ b_length=uint2korr(b); b+=2;
+ }
+ else
+ {
+ a_length= (uint) (uchar) *a++;
+ b_length= (uint) (uchar) *b++;
+ }
+ if (binary_flag)
+ {
+ int cmp= memcmp(a,b,min(a_length,b_length));
+ return cmp ? cmp : (int) (a_length - b_length);
+ }
+ return my_sortncmp(a,a_length, b,b_length);
+}
+
+char *Field_blob::pack_key(char *to, const char *from, uint max_length)
+{
+ uint length=uint2korr(to);
+ if (length > max_length)
+ length=max_length;
+ *to++= (length & 255);
+ if (max_length > 255)
+ *to++= (uchar) (length >> 8);
+ if (length)
+ memcpy(to, from+2, length);
+ return to+length;
+}
+
+/****************************************************************************
+** enum type.
+** This is a string which only can have a selection of different values.
+** If one uses this string in a number context one gets the type number.
+****************************************************************************/
+
+enum ha_base_keytype Field_enum::key_type() const
+{
+ switch (packlength) {
+ default: return HA_KEYTYPE_BINARY;
+ case 2: return HA_KEYTYPE_USHORT_INT;
+ case 3: return HA_KEYTYPE_UINT24;
+ case 4: return HA_KEYTYPE_ULONG_INT;
+ case 8: return HA_KEYTYPE_ULONGLONG;
+ }
+}
+
+void Field_enum::store_type(ulonglong value)
+{
+ switch (packlength) {
+ case 1: ptr[0]= (uchar) value; break;
+ case 2:
+#ifdef WORDS_BIGENDIAN
+ if (table->db_low_byte_first)
+ {
+ int2store(ptr,(unsigned short) value);
+ }
+ else
+#endif
+ shortstore(ptr,(unsigned short) value);
+ break;
+ case 3: int3store(ptr,(long) value); break;
+ case 4:
+#ifdef WORDS_BIGENDIAN
+ if (table->db_low_byte_first)
+ {
+ int4store(ptr,value);
+ }
+ else
+#endif
+ longstore(ptr,(long) value);
+ break;
+ case 8:
+#ifdef WORDS_BIGENDIAN
+ if (table->db_low_byte_first)
+ {
+ int8store(ptr,value);
+ }
+ else
+#endif
+ longlongstore(ptr,value); break;
+ }
+}
+
+
+uint find_enum(TYPELIB *lib,const char *x, uint length)
+{
+ const char *end=x+length;
+ while (end > x && isspace(end[-1]))
+ end--;
+
+ const char *i;
+ const char *j;
+ for (uint pos=0 ; (j=lib->type_names[pos]) ; pos++)
+ {
+ for (i=x ; i != end && toupper(*i) == toupper(*j) ; i++, j++) ;
+ if (i == end && ! *j)
+ return(pos+1);
+ }
+ return(0);
+}
+
+
+/*
+** Note. Storing a empty string in a enum field gives a warning
+** (if there isn't a empty value in the enum)
+*/
+
+void Field_enum::store(const char *from,uint length)
+{
+ uint tmp=find_enum(typelib,from,length);
+ {
+ if (!tmp)
+ {
+ current_thd->cuted_fields++;
+ Field_enum::store_type((longlong) 0);
+ }
+ else
+ store_type((ulonglong) tmp);
+ }
+}
+
+
+void Field_enum::store(double nr)
+{
+ Field_enum::store((longlong) nr);
+}
+
+
+void Field_enum::store(longlong nr)
+{
+ if ((uint) nr > typelib->count || nr == 0)
+ {
+ current_thd->cuted_fields++;
+ nr=0;
+ }
+ store_type((ulonglong) (uint) nr);
+}
+
+
+double Field_enum::val_real(void)
+{
+ return (double) Field_enum::val_int();
+}
+
+
+longlong Field_enum::val_int(void)
+{
+ switch (packlength) {
+ case 1:
+ return (longlong) (uchar) ptr[0];
+ case 2:
+ {
+ uint16 tmp;
+#ifdef WORDS_BIGENDIAN
+ if (table->db_low_byte_first)
+ tmp=sint2korr(ptr);
+ else
+#endif
+ shortget(tmp,ptr);
+ return (longlong) tmp;
+ }
+ case 3:
+ return (longlong) uint3korr(ptr);
+ case 4:
+ {
+ uint32 tmp;
+#ifdef WORDS_BIGENDIAN
+ if (table->db_low_byte_first)
+ tmp=uint4korr(ptr);
+ else
+#endif
+ longget(tmp,ptr);
+ return (longlong) tmp;
+ }
+ case 8:
+ {
+ longlong tmp;
+#ifdef WORDS_BIGENDIAN
+ if (table->db_low_byte_first)
+ tmp=sint8korr(ptr);
+ else
+#endif
+ longlongget(tmp,ptr);
+ return tmp;
+ }
+ }
+ return 0; // impossible
+}
+
+
+String *Field_enum::val_str(String *val_buffer __attribute__((unused)),
+ String *val_ptr)
+{
+ uint tmp=(uint) Field_enum::val_int();
+ if (!tmp || tmp > typelib->count)
+ val_ptr->length(0);
+ else
+ val_ptr->set((const char*) typelib->type_names[tmp-1],
+ strlen(typelib->type_names[tmp-1]));
+ return val_ptr;
+}
+
+int Field_enum::cmp(const char *a_ptr, const char *b_ptr)
+{
+ char *old=ptr;
+ ptr=(char*) a_ptr;
+ ulonglong a=Field_enum::val_int();
+ ptr=(char*) b_ptr;
+ ulonglong b=Field_enum::val_int();
+ ptr=old;
+ return (a < b) ? -1 : (a > b) ? 1 : 0;
+}
+
+void Field_enum::sort_string(char *to,uint length __attribute__((unused)))
+{
+ ulonglong value=Field_enum::val_int();
+ to+=packlength-1;
+ for (uint i=0 ; i < packlength ; i++)
+ {
+ *to-- = (uchar) (value & 255);
+ value>>=8;
+ }
+}
+
+
+void Field_enum::sql_type(String &res) const
+{
+ res.length(0);
+ res.append("enum(");
+
+ bool flag=0;
+ for (const char **pos=typelib->type_names; *pos ; pos++)
+ {
+ if (flag)
+ res.append(',');
+ res.append('\'');
+ append_unescaped(&res,*pos);
+ res.append('\'');
+ flag=1;
+ }
+ res.append(')');
+}
+
+
+/****************************************************************************
+** set type.
+** This is a string which can have a collection of different values.
+** Each string value is separated with a ','.
+** For example "One,two,five"
+** If one uses this string in a number context one gets the bits as a longlong
+** number.
+****************************************************************************/
+
+ulonglong find_set(TYPELIB *lib,const char *x,uint length)
+{
+ const char *end=x+length;
+ while (end > x && isspace(end[-1]))
+ end--;
+
+ ulonglong found=0;
+ if (x != end)
+ {
+ const char *start=x;
+ bool error=0;
+ for (;;)
+ {
+ const char *pos=start;
+ for ( ; pos != end && *pos != field_separator ; pos++) ;
+ uint find=find_enum(lib,start,(uint) (pos-start));
+ if (!find)
+ error=1;
+ else
+ found|= ((longlong) 1 << (find-1));
+ if (pos == end)
+ break;
+ start=pos+1;
+ }
+ if (error)
+ current_thd->cuted_fields++;
+ }
+ return found;
+}
+
+
+void Field_set::store(const char *from,uint length)
+{
+ store_type(find_set(typelib,from,length));
+}
+
+
+void Field_set::store(longlong nr)
+{
+ if ((ulonglong) nr > (ulonglong) (((longlong) 1 << typelib->count) -
+ (longlong) 1))
+ {
+ nr&= (longlong) (((longlong) 1 << typelib->count) - (longlong) 1);
+ current_thd->cuted_fields++;
+ }
+ store_type((ulonglong) nr);
+}
+
+
+String *Field_set::val_str(String *val_buffer,
+ String *val_ptr __attribute__((unused)))
+{
+ ulonglong tmp=(ulonglong) Field_enum::val_int();
+ uint bitnr=0;
+
+ val_buffer->length(0);
+ while (tmp && bitnr < (uint) typelib->count)
+ {
+ if (tmp & 1)
+ {
+ if (val_buffer->length())
+ val_buffer->append(field_separator);
+ String str(typelib->type_names[bitnr],
+ strlen(typelib->type_names[bitnr]));
+ val_buffer->append(str);
+ }
+ tmp>>=1;
+ bitnr++;
+ }
+ return val_buffer;
+}
+
+
+void Field_set::sql_type(String &res) const
+{
+ res.length(0);
+ res.append("set(");
+
+ bool flag=0;
+ for (const char **pos=typelib->type_names; *pos ; pos++)
+ {
+ if (flag)
+ res.append(',');
+ res.append('\'');
+ append_unescaped(&res,*pos);
+ res.append('\'');
+ flag=1;
+ }
+ res.append(')');
+}
+
+/* returns 1 if the fields are equally defined */
+
+bool Field::eq_def(Field *field)
+{
+ if (real_type() != field->real_type() || binary() != field->binary() ||
+ pack_length() != field->pack_length())
+ return 0;
+ return 1;
+}
+
+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++)
+ if (my_strcasecmp(typelib->type_names[i],from_lib->type_names[i]))
+ return 0;
+ return 1;
+}
+
+bool Field_num::eq_def(Field *field)
+{
+ if (!Field::eq_def(field))
+ return 0;
+ Field_num *from_num= (Field_num*) field;
+
+ if (unsigned_flag != from_num->unsigned_flag ||
+ zerofill && !from_num->zerofill && !zero_pack() ||
+ dec != from_num->dec)
+ return 0;
+ return 1;
+}
+
+
+/*****************************************************************************
+** Handling of field and create_field
+*****************************************************************************/
+
+/*
+** Make a field from the .frm file info
+*/
+
+uint32 calc_pack_length(enum_field_types type,uint32 length)
+{
+ switch (type) {
+ case FIELD_TYPE_STRING:
+ case FIELD_TYPE_DECIMAL: return (length);
+ case FIELD_TYPE_VAR_STRING: return (length+2);
+ case FIELD_TYPE_YEAR:
+ case FIELD_TYPE_TINY : return 1;
+ case FIELD_TYPE_SHORT : return 2;
+ case FIELD_TYPE_INT24:
+ case FIELD_TYPE_NEWDATE:
+ case FIELD_TYPE_TIME: return 3;
+ case FIELD_TYPE_TIMESTAMP:
+ case FIELD_TYPE_DATE:
+ case FIELD_TYPE_LONG : return 4;
+ case FIELD_TYPE_FLOAT : return sizeof(float);
+ case FIELD_TYPE_DOUBLE: return sizeof(double);
+ case FIELD_TYPE_DATETIME:
+ case FIELD_TYPE_LONGLONG: return 8; /* Don't crash if no longlong */
+ case FIELD_TYPE_NULL : return 0;
+ case FIELD_TYPE_TINY_BLOB: return 1+portable_sizeof_char_ptr;
+ case FIELD_TYPE_BLOB: return 2+portable_sizeof_char_ptr;
+ case FIELD_TYPE_MEDIUM_BLOB: return 3+portable_sizeof_char_ptr;
+ case FIELD_TYPE_LONG_BLOB: return 4+portable_sizeof_char_ptr;
+ case FIELD_TYPE_SET:
+ case FIELD_TYPE_ENUM: abort(); return 0; // This shouldn't happen
+ }
+ return 0; // This shouldn't happen
+}
+
+
+uint pack_length_to_packflag(uint type)
+{
+ switch (type) {
+ case 1: return f_settype((uint) FIELD_TYPE_TINY);
+ case 2: return f_settype((uint) FIELD_TYPE_SHORT);
+ case 3: return f_settype((uint) FIELD_TYPE_INT24);
+ case 4: return f_settype((uint) FIELD_TYPE_LONG);
+ case 8: return f_settype((uint) FIELD_TYPE_LONGLONG);
+ }
+ return 0; // This shouldn't happen
+}
+
+
+Field *make_field(char *ptr, uint32 field_length,
+ uchar *null_pos, uint null_bit,
+ uint pack_flag,
+ Field::utype unireg_check,
+ TYPELIB *interval,
+ const char *field_name,
+ struct st_table *table)
+{
+ if (!f_maybe_null(pack_flag))
+ {
+ null_pos=0;
+ null_bit=0;
+ }
+ if (f_is_alpha(pack_flag))
+ {
+ if (!f_is_packed(pack_flag))
+ return new Field_string(ptr,field_length,null_pos,null_bit,
+ unireg_check, field_name, table,
+ f_is_binary(pack_flag) != 0);
+
+ uint pack_length=calc_pack_length((enum_field_types)
+ f_packtype(pack_flag),
+ field_length);
+
+ if (f_is_blob(pack_flag))
+ return new Field_blob(ptr,null_pos,null_bit,
+ unireg_check, field_name, table,
+ pack_length,f_is_binary(pack_flag) != 0);
+ if (interval)
+ {
+ if (f_is_enum(pack_flag))
+ return new Field_enum(ptr,field_length,null_pos,null_bit,
+ unireg_check, field_name, table,
+ pack_length, interval);
+ else
+ return new Field_set(ptr,field_length,null_pos,null_bit,
+ unireg_check, field_name, table,
+ pack_length, interval);
+ }
+ }
+
+ switch ((enum enum_field_types) f_packtype(pack_flag)) {
+ case FIELD_TYPE_DECIMAL:
+ return new Field_decimal(ptr,field_length,null_pos,null_bit,
+ unireg_check, field_name, table,
+ f_decimals(pack_flag),
+ f_is_zerofill(pack_flag) != 0,
+ f_is_dec(pack_flag) == 0);
+ case FIELD_TYPE_FLOAT:
+ return new Field_float(ptr,field_length,null_pos,null_bit,
+ unireg_check, field_name, table,
+ f_decimals(pack_flag),
+ f_is_zerofill(pack_flag) != 0,
+ f_is_dec(pack_flag)== 0);
+ case FIELD_TYPE_DOUBLE:
+ return new Field_double(ptr,field_length,null_pos,null_bit,
+ unireg_check, field_name, table,
+ f_decimals(pack_flag),
+ f_is_zerofill(pack_flag) != 0,
+ f_is_dec(pack_flag)== 0);
+ case FIELD_TYPE_TINY:
+ return new Field_tiny(ptr,field_length,null_pos,null_bit,
+ unireg_check, field_name, table,
+ f_is_zerofill(pack_flag) != 0,
+ f_is_dec(pack_flag) == 0);
+ case FIELD_TYPE_SHORT:
+ return new Field_short(ptr,field_length,null_pos,null_bit,
+ unireg_check, field_name, table,
+ f_is_zerofill(pack_flag) != 0,
+ f_is_dec(pack_flag) == 0);
+ case FIELD_TYPE_INT24:
+ return new Field_medium(ptr,field_length,null_pos,null_bit,
+ unireg_check, field_name, table,
+ f_is_zerofill(pack_flag) != 0,
+ f_is_dec(pack_flag) == 0);
+ case FIELD_TYPE_LONG:
+ return new Field_long(ptr,field_length,null_pos,null_bit,
+ unireg_check, field_name, table,
+ f_is_zerofill(pack_flag) != 0,
+ f_is_dec(pack_flag) == 0);
+ case FIELD_TYPE_LONGLONG:
+ return new Field_longlong(ptr,field_length,null_pos,null_bit,
+ unireg_check, field_name, table,
+ f_is_zerofill(pack_flag) != 0,
+ f_is_dec(pack_flag) == 0);
+ case FIELD_TYPE_TIMESTAMP:
+ return new Field_timestamp(ptr,field_length,
+ unireg_check, field_name, table);
+ case FIELD_TYPE_YEAR:
+ return new Field_year(ptr,field_length,null_pos,null_bit,
+ unireg_check, field_name, table);
+ case FIELD_TYPE_DATE:
+ return new Field_date(ptr,null_pos,null_bit,
+ unireg_check, field_name, table);
+ case FIELD_TYPE_NEWDATE:
+ return new Field_newdate(ptr,null_pos,null_bit,
+ unireg_check, field_name, table);
+ case FIELD_TYPE_TIME:
+ return new Field_time(ptr,null_pos,null_bit,
+ unireg_check, field_name, table);
+ case FIELD_TYPE_DATETIME:
+ return new Field_datetime(ptr,null_pos,null_bit,
+ unireg_check, field_name, table);
+ case FIELD_TYPE_NULL:
+ default: // Impossible (Wrong version)
+ return new Field_null(ptr,field_length,unireg_check,field_name,table);
+ }
+ return 0; // Impossible (Wrong version)
+}
+
+
+/* Create a field suitable for create of table */
+
+create_field::create_field(Field *old_field,bool ignore_default)
+{
+ field= old_field;
+ field_name=change=old_field->field_name;
+ length= old_field->field_length;
+ flags= old_field->flags;
+ unireg_check=old_field->unireg_check;
+ pack_length=old_field->pack_length();
+ sql_type= old_field->real_type();
+
+ /* Fix if the original table had 4 byte pointer blobs */
+ if (flags & BLOB_FLAG)
+ pack_length= (pack_length- old_field->table->blob_ptr_size +
+ portable_sizeof_char_ptr);
+ decimals= old_field->decimals();
+ if (sql_type == FIELD_TYPE_STRING)
+ {
+ sql_type=old_field->type();
+ decimals=0;
+ }
+ if (flags & (ENUM_FLAG | SET_FLAG))
+ interval= ((Field_enum*) old_field)->typelib;
+ else
+ interval=0;
+ if (!ignore_default && !old_field->is_real_null() && ! (flags & BLOB_FLAG) &&
+ old_field->type() != FIELD_TYPE_TIMESTAMP && old_field->ptr)
+ {
+ char buff[MAX_FIELD_WIDTH],*pos;
+ String tmp(buff,sizeof(buff));
+ field->val_str(&tmp,&tmp);
+ pos= (char*) sql_memdup(tmp.ptr(),tmp.length()+1);
+ pos[tmp.length()]=0;
+ def=new Item_string(pos,tmp.length());
+ }
+ else
+ def=0;
+}
diff --git a/sql/field.h b/sql/field.h
new file mode 100644
index 00000000000..1d819231bd2
--- /dev/null
+++ b/sql/field.h
@@ -0,0 +1,1082 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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.
+*/
+
+#ifdef __GNUC__
+#pragma interface /* gcc class implementation */
+#endif
+
+#define NOT_FIXED_DEC 31
+
+class Send_field;
+struct st_cache_field;
+
+class Field {
+ Field(const Item &); /* Prevent use of theese */
+ void operator=(Field &);
+public:
+ static void *operator new(size_t size) {return (void*) sql_alloc(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,CASEDN,NEXT_NUMBER,INTERVAL_FIELD,BIT_FIELD,
+ TIMESTAMP_FIELD,CAPITALIZE,BLOB_FIELD};
+ 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; // Which keys a field is in
+ 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,
+ utype unireg_check_arg, const char *field_name_arg,
+ struct st_table *table_arg);
+ virtual ~Field() {}
+ virtual void store(const char *to,uint length)=0;
+ virtual void store(double nr)=0;
+ virtual void store(longlong nr)=0;
+ virtual void store_time(TIME *ltime,timestamp_type t_type);
+ virtual double val_real(void)=0;
+ virtual longlong val_int(void)=0;
+ virtual String *val_str(String*,String *)=0;
+ virtual Item_result result_type () const=0;
+ virtual Item_result cmp_type () const { return result_type(); }
+ bool eq(Field *field) { return ptr == field->ptr; }
+ virtual bool eq_def(Field *field);
+ virtual uint32 pack_length() const { return (uint32) field_length; }
+ virtual void reset(void) { bzero(ptr,pack_length()); }
+ virtual void reset_fields() {}
+ virtual bool binary() const { return 1; }
+ virtual bool zero_pack() const { return 1; }
+ virtual enum ha_base_keytype key_type() const { return HA_KEYTYPE_BINARY; }
+ virtual uint32 key_length() const { return pack_length(); }
+ virtual enum_field_types type() const =0;
+ 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)
+ { return memcmp(a,b,pack_length()); }
+ virtual int cmp_offset(uint row_offset)
+ { return memcmp(ptr,ptr+row_offset,pack_length()); }
+ virtual int cmp_binary_offset(uint row_offset)
+ { return memcmp(ptr,ptr+row_offset,pack_length()); }
+ virtual int key_cmp(const byte *a,const byte *b)
+ { return cmp((char*) a,(char*) b); }
+ virtual int key_cmp(const byte *str, uint length)
+ { return cmp(ptr,(char*) str); }
+ virtual uint decimals() const { return 0; }
+ virtual void sql_type(String &str) const =0;
+ // 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; }
+ inline bool is_real_null(uint row_offset=0)
+ { return null_ptr ? (null_ptr[row_offset] & null_bit ? 1 : 0) : 0; }
+ 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; }
+ 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=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)
+ {
+ 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)
+ {
+ ptr=ADD_TO_PTR(ptr,ptr_diff,char*);
+ if (null_ptr)
+ null_ptr=ADD_TO_PTR(null_ptr,ptr_diff,uchar*);
+ }
+ inline void get_image(char *buff,uint length)
+ { memcpy(buff,ptr,length); }
+ inline void set_image(char *buff,uint length)
+ { memcpy(ptr,buff,length); }
+ virtual void get_key_image(char *buff,uint length)
+ { get_image(buff,length); }
+ virtual void set_key_image(char *buff,uint length)
+ { set_image(buff,length); }
+ inline int cmp_image(char *buff,uint length)
+ {
+ if (binary())
+ return memcmp(ptr,buff,length);
+ else
+ return my_casecmp(ptr,buff,length);
+ }
+ inline longlong val_int_offset(uint row_offset)
+ {
+ ptr+=row_offset;
+ longlong tmp=val_int();
+ ptr-=row_offset;
+ return tmp;
+ }
+ bool send(String *packet);
+ virtual char *pack(char* to, const char *from, uint max_length=~(uint) 0)
+ {
+ uint length=pack_length();
+ memcpy(to,from,length);
+ return to+length;
+ }
+ virtual const char *unpack(char* to, const char *from)
+ {
+ uint length=pack_length();
+ memcpy(to,from,length);
+ return from+length;
+ }
+ virtual char *keypack(char* to, const char *from, uint max_length=~(uint) 0)
+ {
+ return pack(to,from,max_length);
+ }
+ virtual uint packed_col_length(const char *to)
+ { return pack_length();}
+ virtual uint max_packed_col_length(uint max_length)
+ { return pack_length();}
+
+ virtual int pack_cmp(const char *a,const char *b, uint key_length_arg)
+ { return cmp(a,b); }
+ uint offset(); // Should be inline ...
+ void copy_from_tmp(int offset);
+ uint fill_cache_field(struct st_cache_field *copy);
+ virtual bool get_date(TIME *ltime,bool fuzzydate);
+ virtual bool get_time(TIME *ltime);
+ friend bool reopen_table(THD *,struct st_table *,bool);
+ friend int cre_myisam(my_string name, register TABLE *form, uint options,
+ ulonglong auto_increment_value);
+ friend class Copy_field;
+ friend class Item_avg_field;
+ friend class Item_std_field;
+ friend class Item_sum_num;
+ friend class Item_sum_sum;
+ friend class Item_sum_str;
+ friend class Item_sum_count;
+ friend class Item_sum_avg;
+ friend class Item_sum_std;
+ friend class Item_sum_min;
+ friend class Item_sum_max;
+};
+
+
+class Field_num :public Field {
+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,
+ const char *field_name_arg,
+ struct st_table *table_arg,
+ uint dec_arg,bool zero_arg,bool unsigned_arg)
+ :Field(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
+ unireg_check_arg, field_name_arg, table_arg),
+ dec(dec_arg),zerofill(zero_arg),unsigned_flag(unsigned_arg)
+ {
+ if (zerofill)
+ flags|=ZEROFILL_FLAG;
+ if (unsigned_flag)
+ flags|=UNSIGNED_FLAG;
+ }
+ Item_result result_type () const { return REAL_RESULT; }
+ void prepend_zeros(String *value);
+ void add_zerofill_and_unsigned(String &res) const;
+ friend class create_field;
+ void make_field(Send_field *);
+ uint decimals() const { return dec; }
+ uint size_of() const { return sizeof(*this); }
+ bool eq_def(Field *field);
+};
+
+
+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,
+ const char *field_name_arg,
+ struct st_table *table_arg)
+ :Field(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
+ unireg_check_arg, field_name_arg, table_arg)
+ {}
+ Item_result result_type () const { return STRING_RESULT; }
+ uint decimals() const { return NOT_FIXED_DEC; }
+ friend class create_field;
+ void make_field(Send_field *);
+ uint size_of() const { return sizeof(*this); }
+};
+
+
+class Field_decimal :public Field_num {
+public:
+ Field_decimal(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
+ uint 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)
+ :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)
+ {}
+ enum_field_types type() const { return FIELD_TYPE_DECIMAL;}
+ enum ha_base_keytype key_type() const
+ { return zerofill ? HA_KEYTYPE_BINARY : HA_KEYTYPE_NUM; }
+ void reset(void);
+ void store(const char *to,uint length);
+ void store(double nr);
+ void store(longlong nr);
+ double val_real(void);
+ longlong val_int(void);
+ String *val_str(String*,String *);
+ int cmp(const char *,const char*);
+ void sort_string(char *buff,uint length);
+ void overflow(bool negative);
+ bool zero_pack() const { return 0; }
+ void sql_type(String &str) const;
+};
+
+
+class Field_tiny :public Field_num {
+public:
+ Field_tiny(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
+ uint null_bit_arg,
+ enum utype unireg_check_arg, const char *field_name_arg,
+ struct st_table *table_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,
+ 0, zero_arg,unsigned_arg)
+ {}
+ enum Item_result result_type () const { return INT_RESULT; }
+ enum_field_types type() const { return FIELD_TYPE_TINY;}
+ enum ha_base_keytype key_type() const
+ { return unsigned_flag ? HA_KEYTYPE_BINARY : HA_KEYTYPE_INT8; }
+ void store(const char *to,uint length);
+ void store(double nr);
+ void store(longlong nr);
+ double val_real(void);
+ longlong val_int(void);
+ String *val_str(String*,String *);
+ int cmp(const char *,const char*);
+ void sort_string(char *buff,uint length);
+ uint32 pack_length() const { return 1; }
+ void sql_type(String &str) const;
+};
+
+
+class Field_short :public Field_num {
+public:
+ Field_short(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
+ uint null_bit_arg,
+ enum utype unireg_check_arg, const char *field_name_arg,
+ struct st_table *table_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,
+ 0, zero_arg,unsigned_arg)
+ {}
+ enum Item_result result_type () const { return INT_RESULT; }
+ enum_field_types type() const { return FIELD_TYPE_SHORT;}
+ enum ha_base_keytype key_type() const
+ { return unsigned_flag ? HA_KEYTYPE_USHORT_INT : HA_KEYTYPE_SHORT_INT;}
+ void store(const char *to,uint length);
+ void store(double nr);
+ void store(longlong nr);
+ double val_real(void);
+ longlong val_int(void);
+ String *val_str(String*,String *);
+ int cmp(const char *,const char*);
+ void sort_string(char *buff,uint length);
+ uint32 pack_length() const { return 2; }
+ void sql_type(String &str) const;
+};
+
+
+class Field_medium :public Field_num {
+public:
+ Field_medium(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
+ uint null_bit_arg,
+ enum utype unireg_check_arg, const char *field_name_arg,
+ struct st_table *table_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,
+ 0, zero_arg,unsigned_arg)
+ {}
+ enum Item_result result_type () const { return INT_RESULT; }
+ enum_field_types type() const { return FIELD_TYPE_INT24;}
+ enum ha_base_keytype key_type() const
+ { return unsigned_flag ? HA_KEYTYPE_UINT24 : HA_KEYTYPE_INT24; }
+ void store(const char *to,uint length);
+ void store(double nr);
+ void store(longlong nr);
+ double val_real(void);
+ longlong val_int(void);
+ String *val_str(String*,String *);
+ int cmp(const char *,const char*);
+ void sort_string(char *buff,uint length);
+ uint32 pack_length() const { return 3; }
+ void sql_type(String &str) const;
+};
+
+
+class Field_long :public Field_num {
+public:
+ Field_long(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
+ uint null_bit_arg,
+ enum utype unireg_check_arg, const char *field_name_arg,
+ struct st_table *table_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,
+ 0, zero_arg,unsigned_arg)
+ {}
+ Field_long(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,unsigned_arg)
+ {}
+ enum Item_result result_type () const { return INT_RESULT; }
+ enum_field_types type() const { return FIELD_TYPE_LONG;}
+ enum ha_base_keytype key_type() const
+ { return unsigned_flag ? HA_KEYTYPE_ULONG_INT : HA_KEYTYPE_LONG_INT; }
+ void store(const char *to,uint length);
+ void store(double nr);
+ void store(longlong nr);
+ double val_real(void);
+ longlong val_int(void);
+ String *val_str(String*,String *);
+ int cmp(const char *,const char*);
+ void sort_string(char *buff,uint length);
+ uint32 pack_length() const { return 4; }
+ void sql_type(String &str) const;
+};
+
+
+#ifdef HAVE_LONG_LONG
+class Field_longlong :public Field_num {
+public:
+ Field_longlong(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
+ uint null_bit_arg,
+ enum utype unireg_check_arg, const char *field_name_arg,
+ struct st_table *table_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,
+ 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_num((char*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0,0,
+ NONE, field_name_arg, table_arg,0,0,0)
+ {}
+ enum Item_result result_type () const { return INT_RESULT; }
+ enum_field_types type() const { return FIELD_TYPE_LONGLONG;}
+ enum ha_base_keytype key_type() const
+ { return unsigned_flag ? HA_KEYTYPE_ULONGLONG : HA_KEYTYPE_LONGLONG; }
+ void store(const char *to,uint length);
+ void store(double nr);
+ void store(longlong nr);
+ double val_real(void);
+ longlong val_int(void);
+ String *val_str(String*,String *);
+ int cmp(const char *,const char*);
+ void sort_string(char *buff,uint length);
+ uint32 pack_length() const { return 8; }
+ void sql_type(String &str) const;
+};
+#endif
+
+class Field_float :public Field_num {
+public:
+ Field_float(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
+ uint 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)
+ :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)
+ {}
+ enum_field_types type() const { return FIELD_TYPE_FLOAT;}
+ enum ha_base_keytype key_type() const { return HA_KEYTYPE_FLOAT; }
+ void store(const char *to,uint length);
+ void store(double nr);
+ void store(longlong nr);
+ double val_real(void);
+ longlong val_int(void);
+ String *val_str(String*,String *);
+ int cmp(const char *,const char*);
+ void sort_string(char *buff,uint length);
+ uint32 pack_length() const { return sizeof(float); }
+ void sql_type(String &str) const;
+};
+
+
+class Field_double :public Field_num {
+public:
+ Field_double(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
+ uint 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)
+ :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)
+ :Field_num((char*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0, (uint) 0,
+ NONE, field_name_arg, table_arg,dec_arg,0,0)
+ {}
+ enum_field_types type() const { return FIELD_TYPE_DOUBLE;}
+ enum ha_base_keytype key_type() const { return HA_KEYTYPE_DOUBLE; }
+ void store(const char *to,uint length);
+ void store(double nr);
+ void store(longlong nr);
+ double val_real(void);
+ longlong val_int(void);
+ String *val_str(String*,String *);
+ int cmp(const char *,const char*);
+ void sort_string(char *buff,uint length);
+ uint32 pack_length() const { return sizeof(double); }
+ void sql_type(String &str) const;
+};
+
+
+/* Everything saved in this will disapper. It will always return NULL */
+
+class Field_null :public Field_str {
+ static uchar null[1];
+public:
+ Field_null(char *ptr_arg, uint32 len_arg,
+ enum utype unireg_check_arg, const char *field_name_arg,
+ struct st_table *table_arg)
+ :Field_str(ptr_arg, len_arg, null, 1,
+ unireg_check_arg, field_name_arg, table_arg)
+ {}
+ enum_field_types type() const { return FIELD_TYPE_NULL;}
+ void store(const char *to, uint length) { null[0]=1; }
+ void store(double nr) { null[0]=1; }
+ void store(longlong nr) { null[0]=1; }
+ double val_real(void) { return 0.0;}
+ longlong val_int(void) { return 0;}
+ String *val_str(String *value,String *value2)
+ { value2->length(0); return value2;}
+ int cmp(const char *a, const char *b) { return 0;}
+ void sort_string(char *buff, uint length) {}
+ uint32 pack_length() const { return 0; }
+ void sql_type(String &str) const { str.set("null",4); }
+ uint size_of() const { return sizeof(*this); }
+};
+
+
+class Field_timestamp :public Field_num {
+public:
+ Field_timestamp(char *ptr_arg, uint32 len_arg,
+ enum utype unireg_check_arg, const char *field_name_arg,
+ struct st_table *table_arg);
+ enum Item_result result_type () const { return INT_RESULT; }
+ enum_field_types type() const { return FIELD_TYPE_TIMESTAMP;}
+ enum ha_base_keytype key_type() const { return HA_KEYTYPE_ULONG_INT; }
+ void store(const char *to,uint length);
+ void store(double nr);
+ void store(longlong nr);
+ double val_real(void);
+ longlong val_int(void);
+ String *val_str(String*,String *);
+ int cmp(const char *,const char*);
+ void sort_string(char *buff,uint length);
+ uint32 pack_length() const { return 4; }
+ void sql_type(String &str) const;
+ bool store_for_compare() { return 1; }
+ bool zero_pack() const { return 0; }
+ void set_time();
+ inline long get_timestamp()
+ {
+#ifdef WORDS_BIGENDIAN
+ if (table->db_low_byte_first)
+ return sint4korr(ptr);
+#endif
+ long tmp;
+ longget(tmp,ptr);
+ return tmp;
+ }
+ void fill_and_store(char *from,uint len);
+ bool get_date(TIME *ltime,bool fuzzydate);
+ bool get_time(TIME *ltime);
+};
+
+
+class Field_year :public Field_tiny {
+public:
+ Field_year(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
+ uint 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,
+ unireg_check_arg, field_name_arg, table_arg, 1, 1)
+ {}
+ enum_field_types type() const { return FIELD_TYPE_YEAR;}
+ void store(const char *to,uint length);
+ void store(double nr);
+ void store(longlong nr);
+ double val_real(void);
+ longlong val_int(void);
+ String *val_str(String*,String *);
+ void sql_type(String &str) const;
+};
+
+
+class Field_date :public Field_str {
+public:
+ Field_date(char *ptr_arg, uchar *null_ptr_arg, uint 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)
+ {}
+ 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; }
+ void store(const char *to,uint length);
+ void store(double nr);
+ void store(longlong nr);
+ double val_real(void);
+ longlong val_int(void);
+ String *val_str(String*,String *);
+ int cmp(const char *,const char*);
+ void sort_string(char *buff,uint length);
+ uint32 pack_length() const { return 4; }
+ void sql_type(String &str) const;
+ bool store_for_compare() { return 1; }
+ bool zero_pack() const { return 1; }
+};
+
+class Field_newdate :public Field_str {
+public:
+ Field_newdate(char *ptr_arg, uchar *null_ptr_arg, uint 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)
+ {}
+ enum_field_types type() const { return FIELD_TYPE_DATE;}
+ enum_field_types real_type() const { return FIELD_TYPE_NEWDATE; }
+ enum ha_base_keytype key_type() const { return HA_KEYTYPE_UINT24; }
+ enum Item_result cmp_type () const { return INT_RESULT; }
+ void store(const char *to,uint length);
+ void store(double nr);
+ void store(longlong nr);
+ void store_time(TIME *ltime,timestamp_type type);
+ double val_real(void);
+ longlong val_int(void);
+ String *val_str(String*,String *);
+ int cmp(const char *,const char*);
+ void sort_string(char *buff,uint length);
+ uint32 pack_length() const { return 3; }
+ void sql_type(String &str) const;
+ bool store_for_compare() { return 1; }
+ bool zero_pack() const { return 1; }
+ bool get_date(TIME *ltime,bool fuzzydate);
+ bool get_time(TIME *ltime);
+};
+
+
+class Field_time :public Field_str {
+public:
+ Field_time(char *ptr_arg, uchar *null_ptr_arg, uint 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)
+ {}
+ 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; }
+ void store(const char *to,uint length);
+ void store(double nr);
+ void store(longlong nr);
+ double val_real(void);
+ longlong val_int(void);
+ String *val_str(String*,String *);
+ bool get_time(TIME *ltime);
+ int cmp(const char *,const char*);
+ void sort_string(char *buff,uint length);
+ uint32 pack_length() const { return 3; }
+ void sql_type(String &str) const;
+ bool store_for_compare() { return 1; }
+ bool zero_pack() const { return 1; }
+};
+
+
+class Field_datetime :public Field_str {
+public:
+ Field_datetime(char *ptr_arg, uchar *null_ptr_arg, uint 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)
+ {}
+ enum_field_types type() const { return FIELD_TYPE_DATETIME;}
+#ifdef HAVE_LONG_LONG
+ enum ha_base_keytype key_type() const { return HA_KEYTYPE_ULONGLONG; }
+#endif
+ enum Item_result cmp_type () const { return INT_RESULT; }
+ void store(const char *to,uint length);
+ void store(double nr);
+ void store(longlong nr);
+ void store_time(TIME *ltime,timestamp_type type);
+ double val_real(void);
+ longlong val_int(void);
+ String *val_str(String*,String *);
+ int cmp(const char *,const char*);
+ void sort_string(char *buff,uint length);
+ uint32 pack_length() const { return 8; }
+ void sql_type(String &str) const;
+ bool store_for_compare() { return 1; }
+ bool zero_pack() const { return 1; }
+ bool get_date(TIME *ltime,bool fuzzydate);
+ bool get_time(TIME *ltime);
+};
+
+
+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,
+ 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,
+ unireg_check_arg, field_name_arg, table_arg),
+ binary_flag(binary_arg)
+ {
+ if (binary_arg)
+ flags|=BINARY_FLAG;
+ }
+ Field_string(uint32 len_arg,bool maybe_null_arg, const char *field_name_arg,
+ struct st_table *table_arg, bool binary_arg)
+ :Field_str((char*) 0,len_arg, maybe_null_arg ? (uchar*) "": 0,0,
+ NONE, field_name_arg, table_arg),
+ binary_flag(binary_arg)
+ {
+ if (binary_arg)
+ flags|=BINARY_FLAG;
+ }
+
+ enum_field_types type() const
+ {
+ return ((table && table->db_create_options & HA_OPTION_PACK_RECORD &&
+ field_length >= 4) ?
+ FIELD_TYPE_VAR_STRING : FIELD_TYPE_STRING);
+ }
+ enum ha_base_keytype key_type() const
+ { return binary_flag ? HA_KEYTYPE_BINARY : HA_KEYTYPE_TEXT; }
+ bool zero_pack() const { return 0; }
+ bool binary() const { return binary_flag; }
+ void reset(void) { bfill(ptr,field_length,' '); }
+ void store(const char *to,uint length);
+ void store(double nr);
+ void store(longlong nr);
+ double val_real(void);
+ longlong val_int(void);
+ String *val_str(String*,String *);
+ int cmp(const char *,const char*);
+ void sort_string(char *buff,uint length);
+ void sql_type(String &str) const;
+ char *pack(char *to, const char *from, uint max_length=~(uint) 0);
+ const char *unpack(char* to, const char *from);
+ int pack_cmp(const char *a,const char *b,uint key_length);
+ uint packed_col_length(const char *to);
+ uint max_packed_col_length(uint max_length);
+ uint size_of() const { return sizeof(*this); }
+ enum_field_types real_type() const { return FIELD_TYPE_STRING; }
+};
+
+
+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,
+ 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,
+ unireg_check_arg, field_name_arg, table_arg),
+ binary_flag(binary_arg)
+ {
+ if (binary_arg)
+ flags|=BINARY_FLAG;
+ }
+ Field_varstring(uint32 len_arg,bool maybe_null_arg, const char *field_name_arg,
+ struct st_table *table_arg, bool binary_arg)
+ :Field_str((char*) 0,len_arg, maybe_null_arg ? (uchar*) "": 0,0,
+ NONE, field_name_arg, table_arg),
+ binary_flag(binary_arg)
+ {
+ if (binary_arg)
+ flags|=BINARY_FLAG;
+ }
+
+ enum_field_types type() const { return FIELD_TYPE_VAR_STRING; }
+ enum ha_base_keytype key_type() const
+ { return binary_flag ? HA_KEYTYPE_VARBINARY : HA_KEYTYPE_VARTEXT; }
+ bool zero_pack() const { return 0; }
+ bool binary() const { return binary_flag; }
+ void reset(void) { bzero(ptr,field_length+2); }
+ uint32 pack_length() const { return (uint32) field_length+2; }
+ uint32 key_length() const { return (uint32) field_length; }
+ void store(const char *to,uint length);
+ void store(double nr);
+ void store(longlong nr);
+ double val_real(void);
+ longlong val_int(void);
+ String *val_str(String*,String *);
+ int cmp(const char *,const char*);
+ void sort_string(char *buff,uint length);
+ void sql_type(String &str) const;
+ char *pack(char *to, const char *from, uint max_length=~(uint) 0);
+ const char *unpack(char* to, const char *from);
+ int pack_cmp(const char *a, const char *b, uint key_length);
+ uint packed_col_length(const char *to);
+ uint max_packed_col_length(uint max_length);
+ uint size_of() const { return sizeof(*this); }
+ enum_field_types real_type() const { return FIELD_TYPE_VAR_STRING; }
+};
+
+
+class Field_blob :public Field_str {
+ uint packlength;
+ String value; // For temporaries
+ bool binary_flag;
+public:
+ Field_blob(char *ptr_arg, uchar *null_ptr_arg, uint 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);
+ Field_blob(uint32 len_arg,bool maybe_null_arg, const char *field_name_arg,
+ struct st_table *table_arg, bool binary_arg)
+ :Field_str((char*) 0,len_arg, maybe_null_arg ? (uchar*) "": 0,0,
+ NONE, field_name_arg, table_arg),
+ packlength(3),binary_flag(binary_arg)
+ {
+ flags|= BLOB_FLAG;
+ if (binary_arg)
+ flags|=BINARY_FLAG;
+ }
+ enum_field_types type() const { return FIELD_TYPE_BLOB;}
+ enum ha_base_keytype key_type() const
+ { return binary_flag ? HA_KEYTYPE_VARBINARY : HA_KEYTYPE_VARTEXT; }
+ void store(const char *to,uint length);
+ void store(double nr);
+ void store(longlong nr);
+ double val_real(void);
+ 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_offset(uint offset);
+ int cmp_binary(const char *a,const char *b, ulong 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*)); }
+ void reset_fields() { bzero((char*) &value,sizeof(value)); }
+ void store_length(ulong number);
+ inline ulong get_length(uint row_offset=0)
+ { return get_length(ptr+row_offset); }
+ ulong get_length(const char *ptr);
+ bool binary() const { return binary_flag; }
+ inline void get_ptr(char **str)
+ {
+ memcpy_fixed(str,ptr+packlength,sizeof(char*));
+ }
+ inline void set_ptr(char *length,char *data)
+ {
+ memcpy(ptr,length,packlength);
+ memcpy_fixed(ptr+packlength,&data,sizeof(char*));
+ }
+ inline void set_ptr(ulong length,char *data)
+ {
+ store_length(length);
+ memcpy_fixed(ptr+packlength,&data,sizeof(char*));
+ }
+ void get_key_image(char *buff,uint length);
+ void set_key_image(char *buff,uint length);
+ void sql_type(String &str) const;
+ inline bool copy()
+ { char *tmp;
+ get_ptr(&tmp);
+ if (value.copy(tmp,get_length()))
+ {
+ Field_blob::reset();
+ return 1;
+ }
+ tmp=(char*) value.ptr(); memcpy_fixed(ptr+packlength,&tmp,sizeof(char*));
+ return 0;
+ }
+ char *pack(char *to, const char *from, uint max_length= ~(uint) 0)
+ {
+ ulong length=get_length();
+ if (length > max_length)
+ {
+ length=max_length;
+ char *save=ptr;
+ ptr=to;
+ store_length(length);
+ ptr=save;
+ }
+ else
+ memcpy(to,from,packlength);
+ if (length)
+ {
+ get_ptr((char**) &from);
+ memcpy(to+packlength, from,length);
+ return to+packlength+length;
+ }
+ return to+packlength;
+ }
+ const char *unpack(char *to, const char *from)
+ {
+ memcpy(to,from,packlength);
+ from+=packlength;
+ ulong length=get_length();
+ if (length)
+ memcpy_fixed(to+packlength, &from, sizeof(from));
+ else
+ bzero(to+packlength,sizeof(from));
+ return from+length;
+ }
+ char *pack_key(char *to, const char *from, uint max_length=~(uint) 0);
+ int pack_cmp(const char *a, const char *b, uint key_length);
+ uint packed_col_length(const char *col_ptr)
+ { return get_length(col_ptr)+packlength;}
+ virtual uint max_packed_col_length(uint max_length)
+ { return packlength+max_length; }
+
+ inline void free() { value.free(); }
+ inline void clear_temporary() { bzero((char*) &value,sizeof(value)); }
+ friend void field_conv(Field *to,Field *from);
+ uint size_of() const { return sizeof(*this); }
+};
+
+
+class Field_enum :public Field_str {
+protected:
+ uint packlength;
+public:
+ TYPELIB *typelib;
+ Field_enum(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
+ uint null_bit_arg,
+ enum utype unireg_check_arg, const char *field_name_arg,
+ struct st_table *table_arg,uint packlength_arg,
+ TYPELIB *typelib_arg)
+ :Field_str(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
+ unireg_check_arg, field_name_arg, table_arg),
+ packlength(packlength_arg),typelib(typelib_arg)
+ {
+ flags|=ENUM_FLAG;
+ }
+ enum_field_types type() const { return FIELD_TYPE_STRING; }
+ enum Item_result cmp_type () const { return INT_RESULT; }
+ enum ha_base_keytype key_type() const;
+ void store(const char *to,uint length);
+ void store(double nr);
+ void store(longlong nr);
+ double val_real(void);
+ longlong val_int(void);
+ String *val_str(String*,String *);
+ int cmp(const char *,const char*);
+ void sort_string(char *buff,uint length);
+ uint32 pack_length() const { return (uint32) packlength; }
+ void store_type(ulonglong value);
+ void sql_type(String &str) const;
+ uint size_of() const { return sizeof(*this); }
+ enum_field_types real_type() const { return FIELD_TYPE_ENUM; }
+ virtual bool zero_pack() const { return 0; }
+ bool optimize_range() { return 0; }
+ bool binary() const { return 0; }
+ bool eq_def(Field *field);
+};
+
+
+class Field_set :public Field_enum {
+public:
+ Field_set(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
+ uint null_bit_arg,
+ enum utype unireg_check_arg, const char *field_name_arg,
+ struct st_table *table_arg,uint32 packlength_arg,
+ TYPELIB *typelib_arg)
+ :Field_enum(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
+ unireg_check_arg, field_name_arg,
+ table_arg, packlength_arg,
+ typelib_arg)
+ {
+ flags=(flags & ~ENUM_FLAG) | SET_FLAG;
+ }
+ void store(const char *to,uint length);
+ void store(double nr) { Field_set::store((longlong) nr); }
+ void store(longlong nr);
+ virtual bool zero_pack() const { return 1; }
+ String *val_str(String*,String *);
+ void sql_type(String &str) const;
+ enum_field_types real_type() const { return FIELD_TYPE_SET; }
+};
+
+
+/*
+** Create field class for CREATE TABLE
+*/
+
+class create_field :public Sql_alloc {
+public:
+ const char *field_name;
+ const char *change; // If done with alter table
+ const char *after; // Put column after this one
+ Item *def; // Default value
+ enum enum_field_types sql_type;
+ uint32 length;
+ uint decimals,flags,pack_length;
+ Field::utype unireg_check;
+ TYPELIB *interval; // Which interval to use
+ Field *field; // For alter table
+
+ uint8 row,col,sc_length,interval_id; // For rea_create_table
+ uint offset,pack_flag;
+ create_field() :after(0) {}
+ create_field(Field *field,bool ignore_default=0);
+};
+
+
+/*
+** A class for sending info to the client
+*/
+
+class Send_field {
+ public:
+ const char *table_name,*col_name;
+ uint length,flags,decimals;
+ enum_field_types type;
+ Send_field() {}
+};
+
+
+/*
+** A class for quick copying data to fields
+*/
+
+class Copy_field :public Sql_alloc {
+ void (*get_copy_func(Field *to,Field *from))(Copy_field *);
+public:
+ char *from_ptr,*to_ptr;
+ uchar *from_null_ptr,*to_null_ptr;
+ my_bool *null_row;
+ uint from_bit,to_bit;
+ uint from_length,to_length;
+ Field *from_field,*to_field;
+ String tmp; // For items
+
+ Copy_field() {}
+ ~Copy_field() {}
+ void set(Field *to,Field *from,bool save); // Field to field
+ void set(char *to,Field *from); // Field to string
+ void (*do_copy)(Copy_field *);
+ void (*do_copy2)(Copy_field *); // Used to handle null values
+};
+
+
+Field *make_field(char *ptr, uint32 field_length,
+ uchar *null_pos, uint null_bit,
+ uint pack_flag, Field::utype unireg_check,
+ TYPELIB *interval, const char *field_name,
+ struct st_table *table);
+uint pack_length_to_packflag(uint type);
+uint32 calc_pack_length(enum_field_types type,uint32 length);
+bool set_field_to_null(Field *field);
+uint find_enum(TYPELIB *typelib,const char *x, uint length);
+ulonglong find_set(TYPELIB *typelib,const char *x, uint length);
+bool test_if_int(const char *str,int length);
+
+/*
+** The following are for the interface with the .frm file
+*/
+
+#define FIELDFLAG_DECIMAL 1
+#define FIELDFLAG_BINARY 1 // Shares same flag
+#define FIELDFLAG_NUMBER 2
+#define FIELDFLAG_ZEROFILL 4
+#define FIELDFLAG_PACK 120 // Bits used for packing
+#define FIELDFLAG_INTERVAL 256
+#define FIELDFLAG_BITFIELD 512 // mangled with dec!
+#define FIELDFLAG_BLOB 1024 // mangled with dec!
+#define FIELDFLAG_LEFT_FULLSCREEN 8192
+#define FIELDFLAG_RIGHT_FULLSCREEN 16384
+#define FIELDFLAG_FORMAT_NUMBER 16384 // predit: ###,,## in output
+#define FIELDFLAG_SUM ((uint) 32768)// predit: +#fieldflag
+#define FIELDFLAG_MAYBE_NULL ((uint) 32768)// sql
+#define FIELDFLAG_PACK_SHIFT 3
+#define FIELDFLAG_DEC_SHIFT 8
+#define FIELDFLAG_MAX_DEC 31
+#define FIELDFLAG_NUM_SCREEN_TYPE 0x7F01
+#define FIELDFLAG_ALFA_SCREEN_TYPE 0x7800
+
+#define FIELD_SORT_REVERSE 16384
+
+#define MTYP_TYPENR(type) (type & 127) /* Remove bits from type */
+
+#define f_is_dec(x) ((x) & FIELDFLAG_DECIMAL)
+#define f_is_num(x) ((x) & FIELDFLAG_NUMBER)
+#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_is_alpha(x) (!f_is_num(x))
+#define f_is_binary(x) ((x) & FIELDFLAG_BINARY)
+#define f_is_enum(x) ((x) & FIELDFLAG_INTERVAL)
+#define f_is_bitfield(x) ((x) & FIELDFLAG_BITFIELD)
+#define f_is_blob(x) (((x) & (FIELDFLAG_BLOB | FIELDFLAG_NUMBER)) == FIELDFLAG_BLOB)
+#define f_is_equ(x) ((x) & (1+2+FIELDFLAG_PACK+31*256))
+#define f_settype(x) (((int) x) << FIELDFLAG_PACK_SHIFT)
+#define f_maybe_null(x) (x & FIELDFLAG_MAYBE_NULL)
diff --git a/sql/field_conv.cc b/sql/field_conv.cc
new file mode 100644
index 00000000000..aae9f18e6a0
--- /dev/null
+++ b/sql/field_conv.cc
@@ -0,0 +1,528 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 copy data to or from fields
+ This could be done with a single short function but opencooding this
+ gives much more speed.
+ */
+
+#include "mysql_priv.h"
+#include <m_ctype.h>
+
+static void do_field_eq(Copy_field *copy)
+{
+ memcpy(copy->to_ptr,copy->from_ptr,copy->from_length);
+}
+
+static void do_field_1(Copy_field *copy)
+{
+ copy->to_ptr[0]=copy->from_ptr[0];
+}
+
+static void do_field_2(Copy_field *copy)
+{
+ copy->to_ptr[0]=copy->from_ptr[0];
+ copy->to_ptr[1]=copy->from_ptr[1];
+}
+
+static void do_field_3(Copy_field *copy)
+{
+ copy->to_ptr[0]=copy->from_ptr[0];
+ copy->to_ptr[1]=copy->from_ptr[1];
+ copy->to_ptr[2]=copy->from_ptr[2];
+}
+
+static void do_field_4(Copy_field *copy)
+{
+ copy->to_ptr[0]=copy->from_ptr[0];
+ copy->to_ptr[1]=copy->from_ptr[1];
+ copy->to_ptr[2]=copy->from_ptr[2];
+ copy->to_ptr[3]=copy->from_ptr[3];
+}
+
+static void do_field_6(Copy_field *copy)
+{ // For blob field
+ copy->to_ptr[0]=copy->from_ptr[0];
+ copy->to_ptr[1]=copy->from_ptr[1];
+ copy->to_ptr[2]=copy->from_ptr[2];
+ copy->to_ptr[3]=copy->from_ptr[3];
+ copy->to_ptr[4]=copy->from_ptr[4];
+ copy->to_ptr[5]=copy->from_ptr[5];
+}
+
+static void do_field_8(Copy_field *copy)
+{
+ copy->to_ptr[0]=copy->from_ptr[0];
+ copy->to_ptr[1]=copy->from_ptr[1];
+ copy->to_ptr[2]=copy->from_ptr[2];
+ copy->to_ptr[3]=copy->from_ptr[3];
+ copy->to_ptr[4]=copy->from_ptr[4];
+ copy->to_ptr[5]=copy->from_ptr[5];
+ copy->to_ptr[6]=copy->from_ptr[6];
+ copy->to_ptr[7]=copy->from_ptr[7];
+}
+
+
+static void do_field_to_null_str(Copy_field *copy)
+{
+ if (*copy->from_null_ptr & copy->from_bit)
+ {
+ bzero(copy->to_ptr,copy->from_length);
+ copy->to_null_ptr[0]=1; // Always bit 1
+ }
+ else
+ {
+ copy->to_null_ptr[0]=0;
+ memcpy(copy->to_ptr,copy->from_ptr,copy->from_length);
+ }
+}
+
+
+static void do_outer_field_to_null_str(Copy_field *copy)
+{
+ if (*copy->null_row ||
+ copy->from_null_ptr && (*copy->from_null_ptr & copy->from_bit))
+ {
+ bzero(copy->to_ptr,copy->from_length);
+ copy->to_null_ptr[0]=1; // Always bit 1
+ }
+ else
+ {
+ copy->to_null_ptr[0]=0;
+ memcpy(copy->to_ptr,copy->from_ptr,copy->from_length);
+ }
+}
+
+
+bool
+set_field_to_null(Field *field)
+{
+ if (field->maybe_null())
+ {
+ field->set_null();
+ field->reset();
+ }
+ else
+ {
+ if (field->type() == FIELD_TYPE_TIMESTAMP)
+ {
+ ((Field_timestamp*) field)->set_time();
+ return 0; // Ok to set time to NULL
+ }
+ field->reset();
+ if (field == field->table->next_number_field)
+ return 0; // field is set in handler.cc
+ if (current_thd->count_cuted_fields)
+ {
+ current_thd->cuted_fields++; // Increment error counter
+ return 0;
+ }
+ if (!current_thd->no_errors)
+ my_printf_error(ER_BAD_NULL_ERROR,ER(ER_BAD_NULL_ERROR),MYF(0),field->field_name);
+ return 1;
+ }
+ return 0;
+}
+
+
+static void do_skip(Copy_field *copy __attribute__((unused)))
+{
+}
+
+
+static void do_copy_null(Copy_field *copy)
+{
+ if (*copy->from_null_ptr & copy->from_bit)
+ {
+ *copy->to_null_ptr|=copy->to_bit;
+ copy->to_field->reset();
+ }
+ else
+ {
+ *copy->to_null_ptr&= ~copy->to_bit;
+ (copy->do_copy2)(copy);
+ }
+}
+
+
+static void do_outer_field_null(Copy_field *copy)
+{
+ if (*copy->null_row ||
+ copy->from_null_ptr && (*copy->from_null_ptr & copy->from_bit))
+ {
+ *copy->to_null_ptr|=copy->to_bit;
+ copy->to_field->reset();
+ }
+ else
+ {
+ *copy->to_null_ptr&= ~copy->to_bit;
+ (copy->do_copy2)(copy);
+ }
+}
+
+
+static void do_copy_not_null(Copy_field *copy)
+{
+ if (*copy->from_null_ptr & copy->from_bit)
+ {
+ current_thd->cuted_fields++;
+ copy->to_field->reset();
+ }
+ else
+ (copy->do_copy2)(copy);
+}
+
+
+static void do_copy_maybe_null(Copy_field *copy)
+{
+ *copy->to_null_ptr&= ~copy->to_bit;
+ (copy->do_copy2)(copy);
+}
+
+/* timestamp and next_number has special handling in case of NULL values */
+
+static void do_copy_timestamp(Copy_field *copy)
+{
+ if (*copy->from_null_ptr & copy->from_bit)
+ {
+ ((Field_timestamp*) copy->to_field)->set_time();// Same as set_field_to_null
+ }
+ else
+ (copy->do_copy2)(copy);
+}
+
+
+static void do_copy_next_number(Copy_field *copy)
+{
+ if (*copy->from_null_ptr & copy->from_bit)
+ copy->to_field->reset(); // Same as set_field_to_null
+ else
+ (copy->do_copy2)(copy);
+}
+
+
+static void do_copy_blob(Copy_field *copy)
+{
+ ulong length=((Field_blob*) copy->from_field)->get_length();
+ ((Field_blob*) copy->to_field)->store_length(length);
+ memcpy_fixed(copy->to_ptr,copy->from_ptr,sizeof(char*));
+}
+
+static void do_conv_blob(Copy_field *copy)
+{
+ copy->from_field->val_str(&copy->tmp,&copy->tmp);
+ ((Field_blob *) copy->to_field)->store(copy->tmp.ptr(),
+ copy->tmp.length());
+}
+
+/* Save blob in copy->tmp for GROUP BY */
+
+static void do_save_blob(Copy_field *copy)
+{
+ char buff[MAX_FIELD_WIDTH];
+ String res(buff,sizeof(buff));
+ copy->from_field->val_str(&res,&res);
+ copy->tmp.copy(res);
+ ((Field_blob *) copy->to_field)->store(copy->tmp.ptr(),
+ copy->tmp.length());
+}
+
+
+static void do_field_string(Copy_field *copy)
+{
+ char buff[MAX_FIELD_WIDTH];
+ copy->tmp.set_quick(buff,sizeof(buff));
+ copy->from_field->val_str(&copy->tmp,&copy->tmp);
+ copy->to_field->store(copy->tmp.c_ptr_quick(),copy->tmp.length());
+}
+
+
+static void do_field_int(Copy_field *copy)
+{
+ longlong value=copy->from_field->val_int();
+ copy->to_field->store(value);
+}
+
+static void do_field_real(Copy_field *copy)
+{
+ double value=copy->from_field->val_real();
+ copy->to_field->store(value);
+}
+
+
+static void do_cut_string(Copy_field *copy)
+{ // Shorter string field
+ memcpy(copy->to_ptr,copy->from_ptr,copy->to_length);
+
+ /* Check if we loosed any important characters */
+ char *ptr,*end;
+ for (ptr=copy->from_ptr+copy->to_length,end=copy->from_ptr+copy->from_length ;
+ ptr != end ;
+ ptr++)
+ {
+ if (!isspace(*ptr))
+ {
+ current_thd->cuted_fields++; // Give a warning
+ break;
+ }
+ }
+}
+
+
+static void do_expand_string(Copy_field *copy)
+{
+ memcpy(copy->to_ptr,copy->from_ptr,copy->from_length);
+ bfill(copy->to_ptr+copy->from_length,copy->to_length-copy->from_length,' ');
+}
+
+static void do_varstring(Copy_field *copy)
+{
+ uint length=uint2korr(copy->from_ptr);
+ if (length > copy->to_length-2)
+ {
+ length=copy->to_length-2;
+ if (current_thd->count_cuted_fields)
+ current_thd->cuted_fields++; // Increment error counter
+ }
+ int2store(copy->to_ptr,length);
+ memcpy(copy->to_ptr+2, copy->from_ptr,length);
+}
+
+/***************************************************************************
+** The different functions that fills in a Copy_field class
+***************************************************************************/
+
+/*
+ copy of field to maybe null string.
+ If field is null then the all bytes are set to 0.
+ if field is not null then the first byte is set to 1 and the rest of the
+ string is the field value.
+ The 'to' buffer should have a size of field->pack_length()+1
+*/
+
+void Copy_field::set(char *to,Field *from)
+{
+ from_ptr=from->ptr;
+ to_ptr=to;
+ from_length=from->pack_length();
+ if (from->maybe_null())
+ {
+ from_null_ptr=from->null_ptr;
+ from_bit= from->null_bit;
+ to_ptr[0]= 1; // Null as default value
+ to_null_ptr= (uchar*) to_ptr++;
+ to_bit= 1;
+ if (from->table->maybe_null)
+ {
+ null_row= &from->table->null_row;
+ do_copy= do_outer_field_to_null_str;
+ }
+ else
+ do_copy= do_field_to_null_str;
+ }
+ else
+ {
+ to_null_ptr= 0; // For easy debugging
+ do_copy= do_field_eq;
+ }
+}
+
+
+
+void Copy_field::set(Field *to,Field *from,bool save)
+{
+ if (to->type() == FIELD_TYPE_NULL)
+ {
+ to_null_ptr=0; // For easy debugging
+ to_ptr=0;
+ do_copy=do_skip;
+ return;
+ }
+ from_field=from;
+ to_field=to;
+ from_ptr=from->ptr;
+ from_length=from->pack_length();
+ to_ptr= to->ptr;
+ to_length=to_field->pack_length();
+
+ // set up null handling
+ from_null_ptr=to_null_ptr=0;
+ if (from->maybe_null())
+ {
+ from_null_ptr= from->null_ptr;
+ from_bit= from->null_bit;
+ if (to_field->real_maybe_null())
+ {
+ to_null_ptr= to->null_ptr;
+ to_bit= to->null_bit;
+ if (from_null_ptr)
+ do_copy= do_copy_null;
+ else
+ {
+ null_row= &from->table->null_row;
+ do_copy= do_outer_field_null;
+ }
+ }
+ else
+ do_copy=do_copy_not_null;
+ }
+ else if (to_field->real_maybe_null())
+ {
+ to_null_ptr= to->null_ptr;
+ to_bit= to->null_bit;
+ if (to_field->type() == FIELD_TYPE_TIMESTAMP)
+ do_copy=do_copy_timestamp; // Automatic timestamp
+ else if (to_field == to_field->table->next_number_field)
+ do_copy=do_copy_next_number;
+ else
+ do_copy=do_copy_maybe_null;
+ }
+ else
+ do_copy=0;
+
+ if ((to->flags & BLOB_FLAG) && save)
+ do_copy2= do_save_blob;
+ else
+ do_copy2= get_copy_func(to,from);
+ if (!do_copy) // Not null
+ do_copy=do_copy2;
+}
+
+
+void (*Copy_field::get_copy_func(Field *to,Field *from))(Copy_field*)
+{
+ if (to->flags & BLOB_FLAG)
+ {
+ if (!(from->flags & BLOB_FLAG))
+ return do_conv_blob;
+ if (from_length != to_length ||
+ to->table->db_low_byte_first != from->table->db_low_byte_first)
+ {
+ // Correct pointer to point at char pointer
+ to_ptr+=to_length - to->table->blob_ptr_size;
+ from_ptr+=from_length- from->table->blob_ptr_size;
+ return do_copy_blob;
+ }
+ }
+ else
+ {
+ // Check if identical fields
+ if (from->result_type() == STRING_RESULT)
+ {
+ if (to->real_type() != from->real_type() ||
+ to->table->db_low_byte_first != from->table->db_low_byte_first)
+ {
+ if (from->real_type() == FIELD_TYPE_ENUM ||
+ from->real_type() == FIELD_TYPE_SET)
+ if (to->result_type() != STRING_RESULT)
+ return do_field_int; // Convert SET to number
+ return do_field_string;
+ }
+ if (to->real_type() == FIELD_TYPE_ENUM ||
+ to->real_type() == FIELD_TYPE_SET)
+ {
+ if (!to->eq_def(from))
+ return do_field_string;
+ }
+ else if (to->real_type() == FIELD_TYPE_VAR_STRING && to_length !=
+ from_length)
+ return do_varstring;
+ else if (to_length < from_length)
+ return do_cut_string;
+ else if (to_length > from_length)
+ return do_expand_string;
+ }
+ else if (to->real_type() != from->real_type() ||
+ to_length != from_length ||
+ to->table->db_low_byte_first != from->table->db_low_byte_first)
+ {
+ if (to->real_type() == FIELD_TYPE_DECIMAL ||
+ to->result_type() == STRING_RESULT)
+ return do_field_string;
+ if (to->result_type() == INT_RESULT)
+ return do_field_int;
+ return do_field_real;
+ }
+ else
+ {
+ if (!to->eq_def(from) ||
+ to->table->db_low_byte_first != from->table->db_low_byte_first)
+ {
+ if (to->real_type() == FIELD_TYPE_DECIMAL)
+ return do_field_string;
+ if (to->result_type() == INT_RESULT)
+ return do_field_int;
+ else
+ return do_field_real;
+ }
+ }
+ }
+ /* Eq fields */
+ switch (to_length) {
+ case 1: return do_field_1;
+ case 2: return do_field_2;
+ case 3: return do_field_3;
+ case 4: return do_field_4;
+ case 6: return do_field_6;
+ case 8: return do_field_8;
+ }
+ return do_field_eq;
+}
+
+
+/* Simple quick field convert that is called on insert */
+
+void field_conv(Field *to,Field *from)
+{
+ if (to->real_type() == from->real_type())
+ {
+ if (to->pack_length() == from->pack_length() &&
+ to->real_type() != FIELD_TYPE_ENUM &&
+ to->real_type() != FIELD_TYPE_SET &&
+ to->table->db_low_byte_first == from->table->db_low_byte_first)
+ { // Identical fields
+ memcpy(to->ptr,from->ptr,to->pack_length());
+ return;
+ }
+ }
+ if (to->type() == FIELD_TYPE_BLOB)
+ { // Be sure the value is stored
+ Field_blob *blob=(Field_blob*) to;
+ from->val_str(&blob->value,&blob->value);
+ if (!blob->value.is_alloced() &&
+ from->real_type() != FIELD_TYPE_STRING)
+ blob->value.copy();
+ blob->store(blob->value.ptr(),blob->value.length());
+ return;
+ }
+ if ((from->result_type() == STRING_RESULT &&
+ (to->result_type() == STRING_RESULT ||
+ (from->real_type() != FIELD_TYPE_ENUM &&
+ from->real_type() != FIELD_TYPE_SET))) ||
+ to->type() == FIELD_TYPE_DECIMAL)
+ {
+ char buff[MAX_FIELD_WIDTH];
+ String result(buff,sizeof(buff));
+ from->val_str(&result,&result);
+ to->store(result.c_ptr_quick(),result.length());
+ }
+ else if (from->result_type() == REAL_RESULT)
+ to->store(from->val_real());
+ else
+ to->store(from->val_int());
+}
diff --git a/sql/filesort.cc b/sql/filesort.cc
new file mode 100644
index 00000000000..44b7a7ab42e
--- /dev/null
+++ b/sql/filesort.cc
@@ -0,0 +1,957 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+
+/* Sorts a database */
+
+#include "mysql_priv.h"
+#ifdef HAVE_STDDEF_H
+#include <stddef.h> /* for macro offsetof */
+#endif
+#include <m_ctype.h>
+#ifndef THREAD
+#define SKIPP_DBUG_IN_FILESORT
+#endif
+ /* static variabels */
+
+#define MERGEBUFF 7
+#define MERGEBUFF2 15
+
+ /* How to write record_ref. */
+
+#define WRITE_REF(file,from) \
+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 */
+ ha_rows count; /* Number of rows in table */
+ uchar *base,*key; /* key pointers */
+ 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;
+ 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 ha_rows find_all_keys(SORTPARAM *param,SQL_SELECT *select,
+ uchar * *sort_keys,
+ BUFFPEK *buffpek,uint *maxbuffer,
+ 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,
+ BUFFPEK *buffpek,
+ uint maxbuffer,IO_CACHE *tempfile,
+ IO_CACHE *outfile);
+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 */
+
+ha_rows filesort(TABLE **table, SORT_FIELD *sortorder, uint s_length,
+ SQL_SELECT *select, ha_rows special, ha_rows max_rows)
+{
+ int error;
+ uint memavl,old_memavl,maxbuffer,skr;
+ BUFFPEK *buffpek;
+ ha_rows records;
+ uchar **sort_keys;
+ gptr save_1,save_2;
+ IO_CACHE tempfile,*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_PUSH(""); /* No DBUG here */
+#endif
+
+ outfile= table[0]->io_cache;
+ my_b_clear(&tempfile);
+ save_1=save_2=0;
+ buffpek= (BUFFPEK *) NULL; sort_keys= (uchar **) NULL; error= 1;
+ maxbuffer=1;
+ param.ref_length= table[0]->file->ref_length;
+ param.sort_length=sortlength(sortorder,s_length)+ param.ref_length;
+ param.max_rows= max_rows;
+
+ if (select && my_b_inited(&select->file))
+ {
+ records=special=select->records; /* purecov: deadcode */
+ selected_records_file= &select->file; /* purecov: deadcode */
+ reinit_io_cache(selected_records_file,READ_CACHE,0L,0,0); /* purecov: deadcode */
+ }
+ else if (special)
+ {
+ records=special; /* purecov: deadcode */
+ selected_records_file= outfile; /* purecov: deadcode */
+ reinit_io_cache(selected_records_file,READ_CACHE,0L,0,0); /* purecov: deadcode */
+ }
+#ifdef CAN_TRUST_RANGE
+ else if (select && select->quick && select->quick->records > 0L)
+ {
+ VOID(ha_info(&table[0]->form,0)); /* Get record-count */
+ records=min((ha_rows) (select->quick->records*2+EXTRA_RECORDS*2),
+ table[0]->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->records+EXTRA_RECORDS;
+ selected_records_file= 0;
+ }
+ if (param.sort_length == param.ref_length && records > param.max_rows)
+ records=param.max_rows; /* purecov: inspected */
+
+#ifdef USE_STRCOLL
+ if (use_strcoll(default_charset_info) &&
+ !(param.tmp_buffer=my_malloc(param.sort_length,MYF(MY_WME))))
+ goto err;
+#endif
+
+ /* Reserve memory for IO_CACHE files */
+ if (! (save_1=my_malloc(DISK_BUFFER_SIZE,MYF(MY_WME))) ||
+ ! (save_2=my_malloc(DISK_BUFFER_SIZE,MYF(MY_WME))))
+ goto err;
+
+ memavl=sortbuff_size;
+ while (memavl >= MIN_SORT_MEMORY)
+ {
+ if ((records+1)*(param.sort_length+sizeof(char*))+sizeof(BUFFPEK)*10 <
+ (ulong) 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,
+ MYF(0))))
+ if ((buffpek = (BUFFPEK*) my_malloc((uint) sizeof(BUFFPEK)*
+ (maxbuffer+10),
+ MYF(0))))
+ break;
+ else
+ my_free((gptr) sort_keys,MYF(0));
+ 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;
+ }
+ my_free(save_1,MYF(0)); /* Free for later use */
+ my_free(save_2,MYF(0));
+ save_1=save_2=0;
+
+ param.sort_form= table[0];
+ param.end=(param.local_sortorder=sortorder)+s_length;
+ if ((records=find_all_keys(&param,select,sort_keys,buffpek,&maxbuffer,
+ &tempfile, selected_records_file)) ==
+ HA_POS_ERROR)
+ goto err;
+ if (maxbuffer == 0)
+ {
+ if (save_index(&param,sort_keys,(uint) records))
+ goto err;
+ }
+ else
+ {
+ /* Open cached file if it isn't open */
+ if (! my_b_inited(outfile) &&
+ open_cached_file(outfile,mysql_tmpdir,TEMP_PREFIX,READ_RECORD_BUFFER,
+ MYF(MY_WME)))
+ goto err;
+ reinit_io_cache(outfile,WRITE_CACHE,0L,0,0);
+
+ param.keys=((param.keys*(param.sort_length+sizeof(char*))) /
+ param.sort_length-1);
+ if (merge_many_buff(&param,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))
+ goto err;
+ }
+ if (records > param.max_rows)
+ records=param.max_rows;
+ error =0;
+
+ err:
+#ifdef USE_STRCOLL
+ if (use_strcoll(default_charset_info))
+ x_free(param.tmp_buffer);
+#endif
+ x_free((gptr) sort_keys);
+ x_free((gptr) buffpek);
+ x_free(save_1);
+ x_free(save_2);
+ close_cached_file(&tempfile);
+ if (my_b_inited(outfile))
+ {
+ if (flush_io_cache(outfile))
+ error=1;
+ {
+ my_off_t save_pos=outfile->pos_in_file;
+ /* For following reads */
+ if (reinit_io_cache(outfile,READ_CACHE,0L,0,0))
+ error=1;
+ outfile->end_of_file=save_pos;
+ }
+ }
+ if (error)
+ my_error(ER_FILSORT_ABORT,MYF(ME_ERROR+ME_WAITTANG));
+
+#ifdef SKIPP_DBUG_IN_FILESORT
+ DBUG_POP(); /* Ok to DBUG */
+#endif
+ DBUG_PRINT("exit",("records: %ld",records));
+ DBUG_RETURN(error ? HA_POS_ERROR : records);
+} /* filesort */
+
+
+ /* Make a array of string pointers */
+
+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((uint) 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 */
+
+
+ /* 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 *tempfile, IO_CACHE *indexfile)
+{
+ int error,flag,quick_select;
+ uint idx,indexpos,ref_length;
+ byte *ref_pos,*next_pos,ref_buff[MAX_REFLENGTH];
+ my_off_t record;
+ TABLE *sort_form;
+ volatile bool *killed= &current_thd->killed;
+ handler *file;
+ DBUG_ENTER("find_all_keys");
+
+ idx=indexpos=0;
+ error=quick_select=0;
+ sort_form=param->sort_form;
+ file=sort_form->file;
+ ref_length=param->ref_length;
+ ref_pos= ref_buff;
+ quick_select=select && select->quick;
+ record=0;
+ flag= ((!indexfile && file->option_flag() & HA_REC_NOT_IN_SEQ)
+ || quick_select);
+ if (indexfile || flag)
+ ref_pos= &file->ref[0];
+ next_pos=ref_pos;
+ if (! indexfile && ! quick_select)
+ {
+ file->reset();
+ next_pos=(byte*) 0; /* Find records in sequence */
+ file->rnd_init();
+ file->extra(HA_EXTRA_CACHE); /* Quicker reads */
+ }
+
+ for (;;)
+ {
+ if (quick_select)
+ {
+ if ((error=select->quick->get_next()))
+ break;
+ file->position(sort_form->record[0]);
+ }
+ else /* Not quick-select */
+ {
+ if (indexfile)
+ {
+ if (my_b_read(indexfile,(byte*) ref_pos,ref_length)) /* purecov: deadcode */
+ {
+ error= my_errno ? my_errno : -1; /* Abort */
+ break;
+ }
+ if (TEST_IF_LASTREF(ref_pos,ref_length))
+ {
+ error=HA_ERR_END_OF_FILE;
+ break;
+ }
+ error=file->rnd_pos(sort_form->record[0],next_pos);
+ }
+ else
+ {
+ error=file->rnd_next(sort_form->record[0]);
+ if (!flag)
+ {
+ ha_store_ptr(ref_pos,ref_length,record); // Position to row
+ record+=sort_form->db_record_offset;
+ }
+ else
+ file->position(sort_form->record[0]);
+ }
+ if (error && error != HA_ERR_RECORD_DELETED)
+ break;
+ }
+ if (*killed)
+ {
+ (void) file->extra(HA_EXTRA_NO_CACHE);
+ file->rnd_end();
+ DBUG_RETURN(HA_POS_ERROR); /* purecov: inspected */
+ }
+ if (error == 0 && (!select || select->skipp_record() == 0))
+ {
+ if (idx == param->keys)
+ {
+ if (indexpos >= *maxbuffer ||
+ write_keys(param,sort_keys,idx,buffpek+indexpos,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)
+ {
+ error=HA_ERR_END_OF_FILE;
+ break; /* Found enough records */
+ }
+ }
+ make_sortkey(param,sort_keys[idx++],ref_pos);
+ }
+ }
+ (void) file->extra(HA_EXTRA_NO_CACHE); /* End cacheing of records */
+ file->rnd_end();
+ DBUG_PRINT("test",("error: %d indexpos: %d",error,indexpos));
+ if (error != HA_ERR_END_OF_FILE)
+ {
+ 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;
+ DBUG_RETURN(my_b_inited(tempfile) ?
+ (ha_rows) (my_b_tell(tempfile)/param->sort_length) :
+ idx);
+} /* find_all_keys */
+
+
+ /* Skriver en buffert med nycklar till filen */
+
+static int write_keys(SORTPARAM *param, register uchar **sort_keys, uint count,
+ BUFFPEK *buffpek, IO_CACHE *tempfile)
+{
+ uint sort_length;
+ DBUG_ENTER("write_keys");
+
+ sort_length=param->sort_length;
+#ifdef MC68000
+ quicksort(sort_keys,count,sort_length);
+#else
+ my_string_ptr_sort((gptr) sort_keys,(uint) count,sort_length);
+#endif
+ 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);
+ 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++)
+ if (my_b_write(tempfile,(byte*) *sort_keys,(uint) sort_length))
+ DBUG_RETURN(1);
+ DBUG_RETURN(0);
+} /* write_keys */
+
+
+ /* makes a sort-key from record */
+
+static void make_sortkey(register SORTPARAM *param,
+ register uchar *to, byte *ref_pos)
+{
+ reg3 Field *field;
+ reg1 SORT_FIELD *sort_field;
+ reg5 uint length;
+
+ for (sort_field=param->local_sortorder ;
+ sort_field != param->end ;
+ sort_field++)
+ {
+ if ((field=sort_field->field))
+ { // Field
+ if (field->maybe_null())
+ {
+ if (field->is_null())
+ {
+ if (sort_field->reverse)
+ bfill(to,sort_field->length+1,(char) 255);
+ else
+ bzero((char*) to,sort_field->length+1);
+ to+= sort_field->length+1;
+ continue;
+ }
+ else
+ *to++=1;
+ }
+ field->sort_string((char*) to,sort_field->length);
+ }
+ else
+ { // Item
+ Item *item=sort_field->item;
+ switch (sort_field->result_type) {
+ case STRING_RESULT:
+ {
+ if (item->maybe_null)
+ *to++=1;
+ /* All item->str() to use some extra byte for end null.. */
+ String tmp((char*) to,sort_field->length+4);
+ String *res=item->val_str(&tmp);
+ if (!res)
+ {
+ if (item->maybe_null)
+ bzero((char*) to-1,sort_field->length+1);
+ else
+ {
+ DBUG_PRINT("warning",
+ ("Got null on something that shouldn't be null"));
+ bzero((char*) to,sort_field->length); // Avoid crash
+ }
+ break;
+ }
+ length=res->length();
+ int diff=(int) (sort_field->length-length);
+ if (diff < 0)
+ {
+ diff=0; /* purecov: inspected */
+ length=sort_field->length;
+ }
+#ifdef USE_STRCOLL
+ if (use_strcoll(default_charset_info))
+ {
+ if (item->binary)
+ {
+ if (res->ptr() != (char*) to)
+ memcpy(to,res->ptr(),length);
+ bzero((char*) to+length,diff);
+ }
+ else
+ {
+ char *from=(char*) res->ptr();
+ if ((unsigned char *)from == to)
+ {
+ set_if_smaller(length,sort_field->length);
+ memcpy(param->tmp_buffer,from,length);
+ from=param->tmp_buffer;
+ }
+ uint tmp_length=my_strnxfrm(default_charset_info,
+ to,(unsigned char *) from,
+ sort_field->length,
+ length);
+ if (tmp_length < sort_field->length)
+ bzero((char*) to+tmp_length,sort_field->length-tmp_length);
+ }
+ }
+ else
+ {
+#endif
+ if (res->ptr() != (char*) to)
+ memcpy(to,res->ptr(),length);
+ bzero((char *)to+length,diff);
+ if (!item->binary)
+ case_sort((char*) to,length);
+#ifdef USE_STRCOLL
+ }
+#endif
+ break;
+ }
+ case INT_RESULT:
+ {
+ longlong value=item->val_int();
+ if (item->maybe_null)
+ *to++=1; /* purecov: inspected */
+ if (item->null_value)
+ {
+ if (item->maybe_null)
+ bzero((char*) to-1,sort_field->length+1);
+ else
+ {
+ DBUG_PRINT("warning",
+ ("Got null on something that shouldn't be null"));
+ bzero((char*) to,sort_field->length);
+ }
+ break;
+ }
+#if SIZEOF_LONG_LONG > 4
+ to[7]= (uchar) value;
+ to[6]= (uchar) (value >> 8);
+ to[5]= (uchar) (value >> 16);
+ to[4]= (uchar) (value >> 24);
+ to[3]= (uchar) (value >> 32);
+ to[2]= (uchar) (value >> 40);
+ to[1]= (uchar) (value >> 48);
+ to[0]= (uchar) (value >> 56) ^ 128; // Fix sign
+#else
+ to[3]= (uchar) value;
+ to[2]= (uchar) (value >> 8);
+ to[1]= (uchar) (value >> 16);
+ to[0]= (uchar) (value >> 24) ^ 128; // Fix sign
+#endif
+ break;
+ }
+ case REAL_RESULT:
+ {
+ double value=item->val();
+ if (item->null_value)
+ {
+ bzero((char*) to,sort_field->length+1);
+ to++;
+ break;
+ }
+ if (item->maybe_null)
+ *to++=1;
+ change_double_for_sort(value,(byte*) to);
+ break;
+ }
+ }
+ }
+ if (sort_field->reverse)
+ { /* Revers key */
+ length=sort_field->length;
+ while (length--)
+ {
+ *to = (uchar) (~ *to);
+ to++;
+ }
+ }
+ else
+ to+= sort_field->length;
+ }
+ memcpy((byte*) to,ref_pos,(size_s) param->ref_length);/* Save filepos last */
+ return;
+}
+
+
+static bool save_index(SORTPARAM *param, uchar **sort_keys, uint count)
+{
+ uint offset,ref_length;
+ byte *to;
+ DBUG_ENTER("save_index");
+
+ my_string_ptr_sort((gptr) sort_keys,(uint) count,param->sort_length);
+ ref_length=param->ref_length;
+ offset=param->sort_length-ref_length;
+ if ((ha_rows) count > param->max_rows)
+ count=(uint) param->max_rows;
+ if (!(to=param->sort_form->record_pointers=
+ (byte*) my_malloc(ref_length*count,MYF(MY_WME))))
+ DBUG_RETURN(1); /* purecov: inspected */
+ for (uchar **end=sort_keys+count ; sort_keys != end ; sort_keys++)
+ {
+ memcpy(to,*sort_keys+offset,ref_length);
+ to+=ref_length;
+ }
+ DBUG_RETURN(0);
+}
+
+
+ /* Merge buffers to make < MERGEBUFF2 buffers */
+
+static int merge_many_buff(SORTPARAM *param, uchar **sort_keys,
+ BUFFPEK *buffpek, uint *maxbuffer, IO_CACHE *t_file)
+{
+ register int i;
+ IO_CACHE t_file2,*from_file,*to_file,*temp;
+ BUFFPEK *lastbuff;
+ DBUG_ENTER("merge_many_buff");
+
+ if (*maxbuffer < MERGEBUFF2)
+ DBUG_RETURN(0); /* purecov: inspected */
+ if (flush_io_cache(t_file) ||
+ open_cached_file(&t_file2,mysql_tmpdir,TEMP_PREFIX,DISK_BUFFER_SIZE,
+ MYF(MY_WME)))
+ DBUG_RETURN(1); /* purecov: inspected */
+
+ from_file= t_file ; to_file= &t_file2;
+ while (*maxbuffer >= MERGEBUFF2)
+ {
+ reinit_io_cache(from_file,READ_CACHE,0L,0,0);
+ reinit_io_cache(to_file,WRITE_CACHE,0L,0,0);
+ lastbuff=buffpek;
+ for (i=0 ; i <= (int) *maxbuffer-MERGEBUFF*3/2 ; i+=MERGEBUFF)
+ {
+ if (merge_buffers(param,from_file,to_file,sort_keys,lastbuff++,
+ buffpek+i,buffpek+i+MERGEBUFF-1,0))
+ break; /* purecov: inspected */
+ }
+ if (merge_buffers(param,from_file,to_file,sort_keys,lastbuff++,
+ buffpek+i,buffpek+ *maxbuffer,0))
+ break; /* purecov: inspected */
+ if (flush_io_cache(to_file))
+ break; /* purecov: inspected */
+ temp=from_file; from_file=to_file; to_file=temp;
+ *maxbuffer= (uint) (lastbuff-buffpek)-1;
+ }
+ close_cached_file(to_file); // This holds old result
+ if (to_file == t_file)
+ *t_file=t_file2; // Copy result file
+
+ DBUG_RETURN(*maxbuffer >= MERGEBUFF2); /* Return 1 if interrupted */
+} /* merge_many_buff */
+
+
+ /* Read data to buffer */
+ /* This returns (uint) -1 if something goes wrong */
+
+static uint read_to_buffer(IO_CACHE *fromfile, BUFFPEK *buffpek,
+ uint sort_length)
+{
+ register uint count;
+ uint length;
+
+ if ((count=(uint) min((ha_rows) buffpek->max_keys,buffpek->count)))
+ {
+ if (my_pread(fromfile->file,(byte*) buffpek->base,
+ (length= sort_length*count),buffpek->file_pos,MYF_RW))
+ return((uint) -1); /* purecov: inspected */
+ buffpek->key=buffpek->base;
+ buffpek->file_pos+= length; /* New filepos */
+ buffpek->count-= count;
+ buffpek->mem_count= count;
+ }
+ return (count*sort_length);
+} /* read_to_buffer */
+
+
+ /* Merge buffers to one buffer */
+
+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 error;
+ uint sort_length,offset;
+ ulong maxcount;
+ ha_rows count,max_rows;
+ my_off_t to_start_filepos;
+ uchar *strpos;
+ BUFFPEK *buffpek,**refpek;
+ QUEUE queue;
+ volatile bool *killed= &current_thd->killed;
+ DBUG_ENTER("merge_buffers");
+
+ count=error=0;
+ offset=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;
+
+ if (init_queue(&queue,(uint) (Tb-Fb)+1,offsetof(BUFFPEK,key),0,
+ (int (*) (void *, byte *,byte*))
+ 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,
+ sort_length));
+ if (error == -1)
+ goto err; /* purecov: inspected */
+ queue_insert(&queue,(byte*) buffpek);
+ }
+
+ while (queue.elements > 1)
+ {
+ if (*killed)
+ {
+ error=1; goto err; /* purecov: inspected */
+ }
+ for (;;)
+ {
+ buffpek=(BUFFPEK*) queue_top(&queue);
+ if (flag == 0)
+ {
+ if (my_b_write(to_file,(byte*) buffpek->key, sort_length))
+ {
+ error=1; goto err; /* purecov: inspected */
+ }
+ }
+ else
+ {
+ WRITE_REF(to_file,(byte*) buffpek->key+offset);
+ }
+ if (!--max_rows)
+ {
+ error=0; /* purecov: inspected */
+ goto end; /* purecov: inspected */
+ }
+ buffpek->key+=sort_length;
+ if (! --buffpek->mem_count)
+ {
+ if (!(error=(int) read_to_buffer(from_file,buffpek,
+ sort_length)))
+ {
+ uchar *base=buffpek->base;
+ ulong max_keys=buffpek->max_keys;
+
+ VOID(queue_remove(&queue,0));
+
+ /* Put room used by buffer to use in other buffer */
+ for (refpek= (BUFFPEK**) &queue_top(&queue);
+ refpek <= (BUFFPEK**) &queue_end(&queue);
+ refpek++)
+ {
+ buffpek= *refpek;
+ if (buffpek->base+buffpek->max_keys*sort_length == base)
+ {
+ buffpek->max_keys+=max_keys;
+ break;
+ }
+ else if (base+max_keys*sort_length == buffpek->base)
+ {
+ buffpek->base=base;
+ buffpek->max_keys+=max_keys;
+ break;
+ }
+ }
+ break; /* One buffer have been removed */
+ }
+ else if (error == -1)
+ goto err; /* purecov: inspected */
+ }
+ queue_replaced(&queue); /* Top element has been replaced */
+ }
+ }
+ buffpek=(BUFFPEK*) queue_top(&queue);
+ buffpek->base=(uchar *) sort_keys;
+ buffpek->max_keys=param->keys;
+ do
+ {
+ if ((ha_rows) buffpek->mem_count > max_rows)
+ { /* Don't write too many records */
+ buffpek->mem_count=(uint) max_rows;
+ buffpek->count=0; /* Don't read more */
+ }
+ if (flag == 0)
+ {
+ if (my_b_write(to_file,(byte*) buffpek->key,
+ (sort_length*buffpek->mem_count)))
+ {
+ error=1; goto err; /* purecov: inspected */
+ }
+ }
+ else
+ {
+ register uchar *end;
+ strpos= buffpek->key+offset;
+ for (end=strpos+buffpek->mem_count*sort_length;
+ strpos != end ;
+ strpos+=sort_length)
+ {
+ WRITE_REF(to_file,strpos);
+ }
+ }
+ }
+ while ((error=(int) read_to_buffer(from_file,buffpek,sort_length))
+ != -1 && error != 0);
+
+end:
+ lastbuff->count=min(count,param->max_rows);
+ lastbuff->file_pos=to_start_filepos;
+err:
+ delete_queue(&queue);
+ DBUG_RETURN(error);
+} /* merge_buffers */
+
+
+ /* Do a merge to output-file (save only positions) */
+
+static int merge_index(SORTPARAM *param, uchar **sort_keys,
+ BUFFPEK *buffpek, uint maxbuffer,
+ IO_CACHE *tempfile, IO_CACHE *outfile)
+{
+ DBUG_ENTER("merge_index");
+ if (merge_buffers(param,tempfile,outfile,sort_keys,buffpek,buffpek,
+ buffpek+maxbuffer,1))
+ DBUG_RETURN(1); /* purecov: inspected */
+ DBUG_RETURN(0);
+ /* Was: DBUG_RETURN(my_b_write(outfile,last_ref,param->ref_length)); */
+} /* merge_index */
+
+
+ /* Calculate length of sort key */
+
+static uint
+sortlength(SORT_FIELD *sortorder, uint s_length)
+{
+ reg2 uint length;
+
+ length=0;
+ for (; s_length-- ; sortorder++)
+ {
+ if (sortorder->field)
+ {
+ if (sortorder->field->type() == FIELD_TYPE_BLOB)
+ sortorder->length=max_item_sort_length;
+ else
+ {
+ sortorder->length=sortorder->field->pack_length();
+#ifdef USE_STRCOLL
+ if (use_strcoll(default_charset_info) && !sortorder->field->binary())
+ sortorder->length= sortorder->length*MY_STRXFRM_MULTIPLY;
+#endif
+ }
+ if (sortorder->field->maybe_null())
+ length++; // Place for NULL marker
+ }
+ else
+ {
+ switch ((sortorder->result_type=sortorder->item->result_type())) {
+ case STRING_RESULT:
+ sortorder->length=sortorder->item->max_length;
+#ifdef USE_STRCOLL
+ if (use_strcoll(default_charset_info) && !sortorder->item->binary)
+ sortorder->length= sortorder->length*MY_STRXFRM_MULTIPLY;
+#endif
+ break;
+ case INT_RESULT:
+#if SIZEOF_LONG_LONG > 4
+ sortorder->length=8; // Size of intern longlong
+#else
+ sortorder->length=4;
+#endif
+ break;
+ case REAL_RESULT:
+ sortorder->length=sizeof(double);
+ break;
+ }
+ if (sortorder->item->maybe_null)
+ length++; // Place for NULL marker
+ }
+ set_if_smaller(sortorder->length,max_item_sort_length);
+ length+=sortorder->length;
+ }
+ sortorder->field= (Field*) 0; // end marker
+ DBUG_PRINT("info",("sort_length: %d",length));
+ return length;
+}
+
+
+/*
+** functions to change a double or float to a sortable string
+** The following should work for IEEE
+*/
+
+#define DBL_EXP_DIG (sizeof(double)*8-DBL_MANT_DIG)
+
+void change_double_for_sort(double nr,byte *to)
+{
+ uchar *tmp=(uchar*) to;
+ if (nr == 0.0)
+ { /* Change to zero string */
+ tmp[0]=(uchar) 128;
+ bzero((char*) tmp+1,sizeof(nr)-1);
+ }
+ else
+ {
+#ifdef WORDS_BIGENDIAN
+ memcpy_fixed(tmp,&nr,sizeof(nr));
+#else
+ {
+ uchar *ptr= (uchar*) &nr;
+ tmp[0]= ptr[7]; tmp[1]=ptr[6]; tmp[2]= ptr[5]; tmp[3]=ptr[4];
+ tmp[4]= ptr[3]; tmp[5]=ptr[2]; tmp[6]= ptr[1]; tmp[7]=ptr[0];
+ }
+#endif
+ if (tmp[0] & 128) /* Negative */
+ { /* make complement */
+ uint i;
+ for (i=0 ; i < sizeof(nr); i++)
+ tmp[i]=tmp[i] ^ (uchar) 255;
+ }
+ else
+ { /* Set high and move exponent one up */
+ ushort exp_part=(((ushort) tmp[0] << 8) | (ushort) tmp[1] |
+ (ushort) 32768);
+ exp_part+= (ushort) 1 << (16-1-DBL_EXP_DIG);
+ tmp[0]= (uchar) (exp_part >> 8);
+ tmp[1]= (uchar) exp_part;
+ }
+ }
+}
diff --git a/sql/frm_crypt.cc b/sql/frm_crypt.cc
new file mode 100644
index 00000000000..629e4ffab95
--- /dev/null
+++ b/sql/frm_crypt.cc
@@ -0,0 +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 */
+
+
+/*
+** change the following to the output of password('our password')
+** split into 2 parts of 8 characters each.
+** This is done to make it impossible to search after a text string in the
+** mysql binary.
+*/
+
+#include "mysql_priv.h"
+
+#ifdef HAVE_CRYPTED_FRM
+
+/* password('test') */
+ulong password_seed[2]={0x378b243e, 0x220ca493};
+
+SQL_CRYPT *get_crypt_for_frm(void)
+{
+ return new SQL_CRYPT(password_seed);
+}
+
+#endif
diff --git a/sql/gen_lex_hash.cc b/sql/gen_lex_hash.cc
new file mode 100644
index 00000000000..3e1f6f15a6b
--- /dev/null
+++ b/sql/gen_lex_hash.cc
@@ -0,0 +1,560 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 NO_YACC_SYMBOLS
+#include <global.h>
+#include <my_sys.h>
+#include <m_string.h>
+#ifndef __GNU_LIBRARY__
+#define __GNU_LIBRARY__ // Skipp warnings in getopt.h
+#endif
+#include <getopt.h>
+#include "mysql_version.h"
+#include "lex.h"
+
+bool opt_search=0,opt_verbose=0;
+
+#define max_allowed_array 8000 // Don't generate bigger arrays than this
+#define max_symbol 32767 // Use this for 'not found'
+#define how_much_for_plus 8 // 2-8
+#define type_count 1 // 1-5
+#define char_table_count 5
+#define total_symbols (sizeof(symbols)/sizeof(SYMBOL) +\
+ sizeof(sql_functions)/sizeof(SYMBOL))
+
+#define how_much_and INT_MAX24
+
+/*
+ The following only have to work with characters in the set
+ used by SQL commands
+*/
+
+#undef tolower
+#define tolower(a) ((a) >= 'A' && (a) <= 'Z') ? ((a)- 'A' + 'a') : (a)
+
+static uint how_long_symbols,function_plus,function_mod,function_type;
+static uint char_table[256];
+static uchar unique_length[256];
+static uchar bits[how_much_and/8+1];
+static uint primes[max_allowed_array+1];
+static ulong hash_results[type_count][how_much_for_plus+1][total_symbols];
+static ulong start_value=0;
+
+struct rand_struct {
+ unsigned long seed1,seed2,max_value;
+ double max_value_dbl;
+};
+
+void randominit(struct rand_struct *rand_st,ulong seed1, ulong seed2)
+{ /* For mysql 3.21.# */
+ rand_st->max_value= 0x3FFFFFFFL;
+ rand_st->max_value_dbl=(double) rand_st->max_value;
+ rand_st->seed1=seed1%rand_st->max_value ;
+ rand_st->seed2=seed2%rand_st->max_value;
+}
+
+double rnd(struct rand_struct *rand_st)
+{
+ rand_st->seed1=(rand_st->seed1*3+rand_st->seed2) % rand_st->max_value;
+ rand_st->seed2=(rand_st->seed1+rand_st->seed2+33) % rand_st->max_value;
+ return (((double) rand_st->seed1)/rand_st->max_value_dbl);
+}
+
+
+static void make_char_table(ulong t1,ulong t2,int type)
+{
+ uint i;
+ struct rand_struct rand_st;
+ randominit(&rand_st,t1,t2);
+
+ for (i=0 ; i < 256 ; i++)
+ {
+ switch (type) {
+ case 0: char_table[i]= i + (i << 8); break;
+ case 1: char_table[i]= i + ((i ^255 ) << 8); break;
+ case 2: char_table[i]= i; break;
+ case 3: char_table[i]= i + ((uint) (rnd(&rand_st)*255) << 8); break;
+ case 4: char_table[i]= (uint) (rnd(&rand_st)*255) + (i << 8); break;
+ }
+ }
+ char_table[0]|=1+257; // Avoid problems with 0
+ for (i=0 ; i < 256 ; i++)
+ {
+ uint tmp=(uint) (rnd(&rand_st)*255);
+ swap(uint,char_table[i],char_table[tmp]);
+ }
+ /* lower characters should be mapped to upper */
+ for (i= 'a' ; i <= 'z' ; i++)
+ {
+ /* This loop is coded with extra variables to avoid a bug in gcc 2.96 */
+ uchar tmp= (uchar) (i - 'a'); // Assume ascii
+ tmp+='A';
+ char_table[i]=char_table[tmp];
+ }
+}
+
+/* Fill array primes with primes between start and 'max_allowed_array' */
+
+static void make_prime_array(uint start)
+{
+ uint i,j,*to;
+ uint max_index=(uint) sqrt((double) max_allowed_array);
+
+ bzero((char*) primes,sizeof(primes[0])*max_allowed_array);
+
+ i=2;
+ while (i < max_index)
+ {
+ for (j=i+i ; j <= max_allowed_array ; j+=i)
+ primes[j]=1;
+ while (primes[++i]) ;
+ }
+
+ to=primes;
+ for (i=start ; i <= max_allowed_array ; i++)
+ if (!primes[i])
+ *to++=i;
+ *to=0; // end marker
+}
+
+#define USE_char_table
+
+static ulong tab_index_function(const char *s,uint add, uint type)
+{
+ register ulong nr=start_value+char_table[(uchar) *s]; // Nice value
+ ulong pos=3;
+ uint tmp_length=unique_length[(uchar) *s]-1;
+ while (*++s && tmp_length-- > 0)
+ {
+ switch (type) {
+ case 0:
+ nr= (nr ^ (char_table[(uchar) *s] + (nr << add)));
+ break;
+ case 1:
+ nr= (nr + (char_table[(uchar) *s] + (nr << add)));
+ break;
+ case 2:
+ nr= (nr ^ (char_table[(uchar) *s] ^ (nr << add)));
+ break;
+ case 3:
+ nr= (char_table[(uchar) *s] ^ (nr << add));
+ break;
+ case 4:
+ nr+= nr+nr+((nr & 63)+pos)*((ulong) char_table[(uchar) *s]);
+ pos+=add;
+ break;
+ }
+ }
+ return nr & INT_MAX24;
+}
+
+static int search(bool write_warning)
+{
+ uint size_symbols = sizeof(symbols)/sizeof(SYMBOL);
+ uint size_functions = sizeof(sql_functions)/sizeof(SYMBOL);
+ uint size=size_symbols + size_functions;
+ uint i=0,found,*prime,type;
+ int igra[max_allowed_array],test_count=INT_MAX;
+ uint possible_plus[how_much_for_plus*type_count+type_count];
+
+ how_long_symbols = sizeof(symbols)/sizeof(SYMBOL);
+
+ bzero((char*) possible_plus,sizeof(possible_plus));
+ found=0;
+
+ /* Check first which function_plus are possible */
+ for (type=0 ; type < type_count ; type ++)
+ {
+ for (function_plus = 1;
+ function_plus <= how_much_for_plus;
+ function_plus++)
+ {
+ bzero((char*) bits,sizeof(bits));
+ for (i=0; i < size; i++)
+ {
+ ulong order= tab_index_function ((i < how_long_symbols) ?
+ symbols[i].name :
+ sql_functions[i-how_long_symbols].name,
+ function_plus, type);
+ hash_results[type][function_plus][i]=order;
+ uint pos=order/8;
+ uint bit=order & 7;
+ if (bits[pos] & (1 << bit))
+ break;
+ bits[pos]|=1 << bit;
+ }
+ if (i == size)
+ {
+ possible_plus[found++]=function_plus;
+ }
+ }
+ possible_plus[found++]=0; // End marker
+ }
+ if (found == type_count)
+ {
+ if (write_warning)
+ fprintf(stderr,"\
+The hash function didn't return a unique value for any parameter\n\
+You have to change gen_lex_code.cc, function 'tab_index_function' to\n\
+generate unique values for some parameter. When you have succeeded in this,\n\
+you have to change 'main' to print out the new function\n");
+ return(1);
+ }
+
+ if (opt_verbose)
+ fprintf (stderr,"Info: Possible add values: %d\n",found-type_count);
+
+ for (prime=primes; (function_mod=*prime) ; prime++)
+ {
+ uint *plus_ptr=possible_plus;
+ for (type=0 ; type < type_count ; type++ )
+ {
+ while ((function_plus= *plus_ptr++))
+ {
+ ulong *order_pos= &hash_results[type][function_plus][0];
+ if (test_count++ == INT_MAX)
+ {
+ test_count=1;
+ bzero((char*) igra,sizeof(igra));
+ }
+ for (i=0; i<size ;i++)
+ {
+ ulong order;
+ order = *order_pos++ % function_mod;
+ if (igra[order] == test_count)
+ break;
+ igra[order] = test_count;
+ }
+ if (i == size)
+ {
+ *prime=0; // Mark this used
+ function_type=type;
+ return 0; // Found ok value
+ }
+ }
+ }
+ }
+
+ function_mod=max_allowed_array;
+ if (write_warning)
+ fprintf (stderr,"Fatal error when generating hash for symbols\n\
+Didn't find suitable values for perfect hashing:\n\
+You have to edit gen_lex_hase.cc to generate a new hashing function.\n\
+You can try running gen_lex_hash with --search to find a suitable value\n\
+Symbol array size = %d\n",function_mod);
+ return -1;
+}
+
+
+void print_arrays()
+{
+ uint size_symbols = sizeof(symbols)/sizeof(SYMBOL);
+ uint size_functions = sizeof(sql_functions)/sizeof(SYMBOL);
+ uint size=size_symbols + size_functions;
+ uint i;
+
+ fprintf(stderr,"Symbols: %d Functions: %d; Total: %d\nShifts per char: %d, Array size: %d\n",
+ size_symbols,size_functions,size_symbols+size_functions,
+ function_plus,function_mod);
+
+ int *prva= (int*) my_alloca(sizeof(int)*function_mod);
+ for (i=0 ; i <= function_mod; i++)
+ prva[i]= max_symbol;
+
+ for (i=0;i<size;i++)
+ {
+ ulong order = tab_index_function ((i < how_long_symbols) ? symbols[i].name : sql_functions[i - how_long_symbols].name,function_plus,function_type);
+ order %= function_mod;
+ prva [order] = i;
+ }
+
+#ifdef USE_char_table
+ printf("static uint16 char_table[] = {\n");
+ for (i=0; i < 255 ;i++) // < 255 is correct
+ {
+ printf("%u,",char_table[i]);
+ if (((i+1) & 15) == 0)
+ puts("");
+ }
+ printf("%d\n};\n\n\n",char_table[i]);
+#endif
+
+ printf("static uchar unique_length[] = {\n");
+ for (i=0; i < 255 ;i++) // < 255 is correct
+ {
+ printf("%u,",unique_length[i]);
+ if (((i+1) & 15) == 0)
+ puts("");
+ }
+ printf("%d\n};\n\n\n",unique_length[i]);
+
+ printf("static uint16 my_function_table[] = {\n");
+ for (i=0; i < function_mod-1 ;i++)
+ {
+ printf("%d,",prva[i]);
+ if (((i+1) % 12) == 0)
+ puts("");
+ }
+ printf("%d\n};\n\n\n",prva[i]);
+ my_afree((gptr) prva);
+}
+
+
+static struct option long_options[] =
+{
+ {"search", no_argument, 0, 'S'},
+ {"verbose", no_argument, 0, 'v'},
+ {"version", no_argument, 0, 'V'},
+ {"rnd1", required_argument, 0, 'r'},
+ {"rnd2", required_argument, 0, 'R'},
+ {"type", required_argument, 0, 't'},
+ {0, 0, 0, 0}
+};
+
+
+static void usage(int version)
+{
+ printf("%s Ver 3.0 Distrib %s, for %s (%s)\n",
+ my_progname, MYSQL_SERVER_VERSION, SYSTEM_TYPE, MACHINE_TYPE);
+ if (version)
+ return;
+ puts("Copyright (C) 2000 MySQL AB & MySQL Finland AB, by Sinisa and Monty");
+ 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("This program generates a perfect hashing function for the sql_lex.cc");
+ printf("Usage: %s [OPTIONS]\n", my_progname);
+ printf("\n\
+-r, --rnd1=# Set 1 part of rnd value for hash generator\n\
+-R, --rnd2=# Set 2 part of rnd value for hash generator\n\
+-t, --type=# Set type of char table to generate\n\
+-S, --search Search after good rnd1 and rnd2 values\n\
+-v, --verbose Write some information while the program executes\n\
+-V, --version Output version information and exit\n");
+
+}
+
+static uint best_type;
+static ulong best_t1,best_t2;
+
+static int get_options(int argc, char **argv)
+{
+ int c,option_index=0;
+
+ while ((c=getopt_long(argc,argv,"?SvVr:R:t:",
+ long_options, &option_index)) != EOF)
+ {
+ switch(c) {
+ case 'r':
+ best_t1=atol(optarg);
+ break;
+ case 'R':
+ best_t2=atol(optarg);
+ break;
+ case 't':
+ best_type=atoi(optarg);
+ break;
+ case 'S':
+ opt_search=1;
+ break;
+ case 'v':
+ opt_verbose=1;
+ break;
+ case 'V': usage(1); exit(0);
+ case 'I':
+ case '?':
+ usage(0);
+ exit(0);
+ default:
+ fprintf(stderr,"illegal option: -%c\n",opterr);
+ usage(0);
+ exit(1);
+ }
+ }
+ argc-=optind;
+ argv+=optind;
+ if (argc >= 1)
+ {
+ usage(0);
+ exit(1);
+ }
+ return(0);
+}
+
+static uint max_prefix(const char *name)
+{
+ uint i;
+ uint max_length=1;
+ for (i=0 ; i < sizeof(symbols)/sizeof(SYMBOL) ; i++)
+ {
+ const char *str=symbols[i].name;
+ if (str != name)
+ {
+ const char *str2=name;
+ uint length;
+ while (*str && *str == *str2)
+ {
+ str++;
+ str2++;
+ }
+ length=(uint) (str2 - name)+1;
+ if (length > max_length)
+ max_length=length;
+ }
+ }
+ for (i=0 ; i < sizeof(sql_functions)/sizeof(SYMBOL) ; i++)
+ {
+ const char *str=sql_functions[i].name;
+ if (str != name)
+ {
+ const char *str2=name;
+ uint length;
+ while (*str && *str == *str2)
+ {
+ str++;
+ str2++;
+ }
+ length=(uint) (str2 - name)+1;
+ if (length > max_length)
+ max_length=length;
+ }
+ }
+ return max_length;
+}
+
+
+static void make_max_length_table(void)
+{
+ uint i;
+ for (i=0 ; i < sizeof(symbols)/sizeof(SYMBOL) ; i++)
+ {
+ uint length=max_prefix(symbols[i].name);
+ if (length > unique_length[(uchar) symbols[i].name[0]])
+ {
+ unique_length[(uchar) symbols[i].name[0]]=length;
+ unique_length[(uchar) tolower(symbols[i].name[0])]=length;
+ }
+ }
+ for (i=0 ; i < sizeof(sql_functions)/sizeof(SYMBOL) ; i++)
+ {
+ uint length=max_prefix(sql_functions[i].name);
+ if (length > unique_length[(uchar) sql_functions[i].name[0]])
+ {
+ unique_length[(uchar) sql_functions[i].name[0]]=length;
+ unique_length[(uchar) tolower(sql_functions[i].name[0])]=length;
+ }
+ }
+}
+
+
+int main(int argc,char **argv)
+{
+ struct rand_struct rand_st;
+ static uint best_mod,best_add,best_functype;
+ int error;
+
+ MY_INIT(argv[0]);
+ start_value=1277803L; best_t1=331678L; best_t2=4097229L; best_type=1;
+ /* mode=5791 add=6 func_type: 0 */
+ if (get_options(argc,(char **) argv))
+ exit(1);
+
+ make_max_length_table();
+ make_char_table(best_t1,best_t2,best_type);
+ make_prime_array(sizeof(symbols)/sizeof(SYMBOL) +
+ sizeof(sql_functions)/sizeof(SYMBOL));
+
+ if ((error=search(1)) > 0 || error && !opt_search)
+ exit(1); // This should work
+ best_mod=function_mod; best_add=function_plus; best_functype=function_type;
+
+ if (opt_search)
+ {
+ time_t start_time=time((time_t*) 0);
+ randominit(&rand_st,start_time,start_time/2); // Some random values
+ 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);
+
+ for (uint i=1 ; i <= 100000 ; i++)
+ {
+ if (i % 10 == 0)
+ {
+ putchar('.');
+ fflush(stdout);
+ }
+ ulong t1=(ulong) (rnd(&rand_st)*INT_MAX24);
+ ulong t2=(ulong) (rnd(&rand_st)*INT_MAX24);
+ uint type=(int) (rnd(&rand_st)*char_table_count);
+ start_value=(ulong) (rnd(&rand_st)*INT_MAX24);
+ make_char_table(t1,t2,type);
+ if (!search(0))
+ {
+ best_mod=function_mod; best_add=function_plus;
+ best_functype=function_type;
+ best_t1=t1; best_t2=t2; best_type=type;
+ printf("\nstart_value=%ldL; best_t1=%ldL; best_t2=%ldL; best_type=%d; /* mode=%d add=%d func_type: %d */\n",
+ start_value,best_t1,best_t2,best_type,best_mod,best_add,best_functype);
+ }
+ }
+ }
+
+ function_mod=best_mod; function_plus=best_add;
+ make_char_table(best_t1,best_t2,best_type);
+
+ printf("/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB\n\
+ This program is free software; you can redistribute it and/or modify\n\
+ it under the terms of the GNU General Public License as published by\n\
+ the Free Software Foundation; either version 2 of the License, or\n\
+ (at your option) any later version.\n\n\
+ This program is distributed in the hope that it will be useful,\n\
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\n\
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n\
+ GNU General Public License for more details.\n\n\
+ You should have received a copy of the GNU General Public License\n\
+ along with this program; if not, write to the Free Software\n\
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */\n\n");
+
+printf("/* This code is generated by gen_lex_hash.cc that seeks for a perfect\nhash function */\n\n");
+ printf("#include \"lex.h\"\n\n");
+
+ print_arrays();
+
+ printf("/* t1= %lu t2=%lu type= %d */\n\n",best_t1,best_t2,best_type);
+
+ printf("inline SYMBOL *get_hash_symbol(const char *s,unsigned int length,bool function)\n\
+{\n\
+ ulong idx = %lu+char_table[(uchar) *s];\n\
+ SYMBOL *sim;\n\
+ const char *start=s;\n\
+ int i=unique_length[(uchar) *s++];\n\
+ if (i > (int) length) i=(int) length;\n\
+ while (--i > 0)\n\
+ idx= (idx ^ (char_table[(uchar) *s++] + (idx << %d)));\n\
+ idx=my_function_table[(idx & %d) %% %d];\n\
+ if (idx >= %d)\n\
+ {\n\
+ if (!function || idx >= %d) return (SYMBOL*) 0;\n\
+ sim=sql_functions + (idx - %d);\n\
+ }\n\
+ else\n\
+ sim=symbols + idx;\n\
+ if ((length != sim->length) || lex_casecmp(start,sim->name,length))\n\
+ return (SYMBOL *)0;\n\
+ return sim;\n\
+}\n",(ulong) start_value,(int) function_plus,(int) how_much_and,function_mod,how_long_symbols,max_symbol,how_long_symbols);
+ exit(0);
+ return 0;
+}
diff --git a/sql/ha_berkeley.cc b/sql/ha_berkeley.cc
new file mode 100644
index 00000000000..f9cafd44839
--- /dev/null
+++ b/sql/ha_berkeley.cc
@@ -0,0 +1,1398 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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:
+ - Not compressed keys should use cmp_fix_length_key
+ - Don't automaticly pack all string keys (To do this we need to modify
+ CREATE TABLE so that one can use the pack_keys argument per key).
+ - An argument to pack_key that we don't want compression.
+ - Interaction with LOCK TABLES (Monty will fix this)
+ - DB_DBT_USERMEN should be used for fixed length tables
+ We will need an updated Berkeley DB version for this.
+ - Killing threads that has got a 'deadlock'
+ - SHOW TABLE STATUS should give more information about the table.
+ - Get a more accurate count of the number of rows.
+ - Introduce hidden primary keys for tables without a primary key
+ - We will need a manager thread that calls flush_logs, removes old
+ logs and makes checkpoints at given intervals.
+ - When not using UPDATE IGNORE, don't make a sub transaction but abort
+ the main transaction on errors.
+ - Handling of drop table during autocommit=0 ?
+ (Should we just give an error in this case if there is a pending
+ transaction ?)
+ - When using ALTER TABLE IGNORE, we should not start an transaction, but do
+ everything wthout transactions.
+
+ Testing of:
+ - ALTER TABLE
+ - LOCK TABLES
+ - CHAR keys
+ - BLOBS
+ - delete from t1;
+*/
+
+
+#ifdef __GNUC__
+#pragma implementation // gcc: Class implementation
+#endif
+
+#include "mysql_priv.h"
+#ifdef HAVE_BERKELEY_DB
+#include <m_ctype.h>
+#include <myisampack.h>
+#include <assert.h>
+#include <hash.h>
+#include "ha_berkeley.h"
+
+#define HA_BERKELEY_ROWS_IN_TABLE 10000 /* to get optimization right */
+#define HA_BERKELEY_RANGE_COUNT 100
+
+const char *ha_berkeley_ext=".db";
+bool berkeley_skip=0;
+u_int32_t berkeley_init_flags=0,berkeley_lock_type=DB_LOCK_DEFAULT;
+ulong berkeley_cache_size;
+char *berkeley_home, *berkeley_tmpdir, *berkeley_logdir;
+long berkeley_lock_scan_time=0;
+ulong berkeley_trans_retry=5;
+pthread_mutex_t bdb_mutex;
+
+static DB_ENV *db_env;
+static HASH bdb_open_tables;
+
+const char *berkeley_lock_names[] =
+{ "DEFAULT", "OLDEST","RANDOM","YOUNGEST" };
+u_int32_t berkeley_lock_types[]=
+{ DB_LOCK_DEFAULT, DB_LOCK_OLDEST, DB_LOCK_RANDOM };
+TYPELIB berkeley_lock_typelib= {array_elements(berkeley_lock_names),"",
+ berkeley_lock_names};
+
+static void berkeley_print_error(const char *db_errpfx, char *buffer);
+static byte* bdb_get_key(BDB_SHARE *share,uint *length,
+ my_bool not_used __attribute__((unused)));
+static BDB_SHARE *get_share(const char *table_name);
+static void free_share(BDB_SHARE *share);
+
+
+/* General functions */
+
+bool berkeley_init(void)
+{
+ char buff[1024],*config[10], **conf_pos, *str_pos;
+ conf_pos=config; str_pos=buff;
+ DBUG_ENTER("berkeley_init");
+
+ if (!berkeley_tmpdir)
+ berkeley_tmpdir=mysql_tmpdir;
+ if (!berkeley_home)
+ berkeley_home=mysql_real_data_home;
+
+ if (db_env_create(&db_env,0))
+ DBUG_RETURN(1);
+ db_env->set_errcall(db_env,berkeley_print_error);
+ db_env->set_errpfx(db_env,"bdb");
+ db_env->set_tmp_dir(db_env, berkeley_tmpdir);
+ db_env->set_data_dir(db_env, mysql_data_home);
+ if (berkeley_logdir)
+ db_env->set_lg_dir(db_env, berkeley_logdir);
+
+ if (opt_endinfo)
+ db_env->set_verbose(db_env,
+ DB_VERB_CHKPOINT | DB_VERB_DEADLOCK | DB_VERB_RECOVERY,
+ 1);
+
+ db_env->set_cachesize(db_env, 0, berkeley_cache_size, 0);
+ db_env->set_lk_detect(db_env, berkeley_lock_type);
+ if (db_env->open(db_env,
+ berkeley_home,
+ berkeley_init_flags | DB_INIT_LOCK |
+ DB_INIT_LOG | DB_INIT_MPOOL | DB_INIT_TXN |
+ DB_CREATE | DB_THREAD | DB_PRIVATE, 0666))
+ {
+ db_env->close(db_env,0);
+ db_env=0;
+ }
+ (void) hash_init(&bdb_open_tables,32,0,0,
+ (hash_get_key) bdb_get_key,0,0);
+ pthread_mutex_init(&bdb_mutex,NULL);
+ DBUG_RETURN(db_env == 0);
+}
+
+
+bool berkeley_end(void)
+{
+ int error;
+ DBUG_ENTER("berkeley_end");
+ if (!db_env)
+ return 1;
+ error=db_env->close(db_env,0); // Error is logged
+ db_env=0;
+ hash_free(&bdb_open_tables);
+ pthread_mutex_destroy(&bdb_mutex);
+ DBUG_RETURN(error != 0);
+}
+
+bool berkeley_flush_logs()
+{
+ int error;
+ bool result=0;
+ DBUG_ENTER("berkeley_flush_logs");
+ if ((error=log_flush(db_env,0)))
+ {
+ my_error(ER_ERROR_DURING_FLUSH_LOGS,MYF(0),error);
+ result=1;
+ }
+ if ((error=txn_checkpoint(db_env,0,0,0)))
+ {
+ my_error(ER_ERROR_DURING_CHECKPOINT,MYF(0),error);
+ result=1;
+ }
+ DBUG_RETURN(result);
+}
+
+
+int berkeley_commit(THD *thd)
+{
+ DBUG_ENTER("berkeley_commit");
+ DBUG_PRINT("trans",("ending transaction"));
+ int error=txn_commit((DB_TXN*) thd->transaction.bdb_tid,0);
+#ifndef DBUG_OFF
+ if (error)
+ DBUG_PRINT("error",("error: %d",error));
+#endif
+ thd->transaction.bdb_tid=0;
+ DBUG_RETURN(error);
+}
+
+int berkeley_rollback(THD *thd)
+{
+ DBUG_ENTER("berkeley_rollback");
+ DBUG_PRINT("trans",("aborting transaction"));
+ int error=txn_abort((DB_TXN*) thd->transaction.bdb_tid);
+ thd->transaction.bdb_tid=0;
+ DBUG_RETURN(error);
+}
+
+
+static void berkeley_print_error(const char *db_errpfx, char *buffer)
+{
+ sql_print_error("%s: %s",db_errpfx,buffer);
+}
+
+
+
+/*****************************************************************************
+** Berkeley DB tables
+*****************************************************************************/
+
+const char **ha_berkeley::bas_ext() const
+{ static const char *ext[]= { ha_berkeley_ext, NullS }; return ext; }
+
+
+static int
+berkeley_cmp_packed_key(const DBT *new_key, const DBT *saved_key)
+{
+ KEY *key= (KEY*) new_key->app_private;
+ char *new_key_ptr= (char*) new_key->data;
+ char *saved_key_ptr=(char*) saved_key->data;
+ KEY_PART_INFO *key_part= key->key_part, *end=key_part+key->key_parts;
+ uint key_length=new_key->size;
+
+ for ( ; key_part != end && (int) key_length > 0; key_part++)
+ {
+ int cmp;
+ if (key_part->null_bit)
+ {
+ if (*new_key_ptr++ != *saved_key_ptr++)
+ return ((int) new_key_ptr[-1] - (int) saved_key_ptr[-1]);
+ }
+ if ((cmp=key_part->field->pack_cmp(new_key_ptr,saved_key_ptr,
+ key_part->length)))
+ return cmp;
+ uint length=key_part->field->packed_col_length(new_key_ptr);
+ new_key_ptr+=length;
+ key_length-=length;
+ saved_key_ptr+=key_part->field->packed_col_length(saved_key_ptr);
+ }
+ return 0;
+}
+
+
+static int
+berkeley_cmp_fix_length_key(const DBT *new_key, const DBT *saved_key)
+{
+ KEY *key=(KEY*) (new_key->app_private);
+ char *new_key_ptr= (char*) new_key->data;
+ char *saved_key_ptr=(char*) saved_key->data;
+ KEY_PART_INFO *key_part= key->key_part, *end=key_part+key->key_parts;
+ uint key_length=new_key->size;
+
+ for ( ; key_part != end && (int) key_length > 0 ; key_part++)
+ {
+ int cmp;
+ if ((cmp=key_part->field->pack_cmp(new_key_ptr,saved_key_ptr,0)))
+ return cmp;
+ new_key_ptr+=key_part->length;
+ key_length-= key_part->length;
+ saved_key_ptr+=key_part->length;
+ }
+ return 0;
+}
+
+
+int ha_berkeley::open(const char *name, int mode, int test_if_locked)
+{
+ char name_buff[FN_REFLEN];
+ uint open_mode=(mode == O_RDONLY ? DB_RDONLY : 0) | DB_THREAD;
+ int error;
+ DBUG_ENTER("ha_berkeley::open");
+
+ /* Need some extra memory in case of packed keys */
+ uint max_key_length= table->max_key_length + MAX_REF_PARTS*2;
+ if (!(alloc_ptr=
+ my_multi_malloc(MYF(MY_WME),
+ &key_file, table->keys*sizeof(*key_file),
+ &key_type, table->keys*sizeof(u_int32_t),
+ &key_buff, max_key_length,
+ &key_buff2, max_key_length,
+ &primary_key_buff,
+ table->key_info[table->primary_key].key_length,
+ NullS)))
+ DBUG_RETURN(1);
+ if (!(rec_buff=my_malloc((alloced_rec_buff_length=table->reclength),
+ MYF(MY_WME))))
+ {
+ my_free(alloc_ptr,MYF(0));
+ DBUG_RETURN(1);
+ }
+
+ /* Init table lock structure */
+ if (!(share=get_share(name)))
+ {
+ my_free(rec_buff,MYF(0));
+ my_free(alloc_ptr,MYF(0));
+ DBUG_RETURN(1);
+ }
+ thr_lock_data_init(&share->lock,&lock,(void*) 0);
+
+ if ((error=db_create(&file, db_env, 0)))
+ {
+ free_share(share);
+ my_free(rec_buff,MYF(0));
+ my_free(alloc_ptr,MYF(0));
+ my_errno=error;
+ DBUG_RETURN(1);
+ }
+
+ /* Open primary key */
+ file->set_bt_compare(file, berkeley_cmp_packed_key);
+ if ((error=(file->open(file, fn_format(name_buff,name,"", ha_berkeley_ext,
+ 2 | 4),
+ "main", DB_BTREE, open_mode,0))))
+ {
+ free_share(share);
+ my_free(rec_buff,MYF(0));
+ my_free(alloc_ptr,MYF(0));
+ my_errno=error;
+ DBUG_RETURN(1);
+ }
+
+ info(HA_STATUS_NO_LOCK | HA_STATUS_VARIABLE | HA_STATUS_CONST);
+ transaction=0;
+ cursor=0;
+
+ fixed_length_row=!(table->db_create_options & HA_OPTION_PACK_RECORD);
+
+ /* Open other keys */
+ bzero((char*) key_file,sizeof(*key_file)*table->keys);
+ key_used_on_scan=primary_key=table->primary_key;
+ key_file[primary_key]=file;
+ bzero((char*) &current_row,sizeof(current_row));
+
+ DB **ptr=key_file;
+ for (uint i=0, used_keys=0; i < table->keys ; i++, ptr++)
+ {
+ char part[7];
+ key_type[i]=table->key_info[i].flags & HA_NOSAME ? DB_NOOVERWRITE : 0;
+ if (i != primary_key)
+ {
+ if ((error=db_create(ptr, db_env, 0)))
+ {
+ close();
+ my_errno=error;
+ DBUG_RETURN(1);
+ }
+ sprintf(part,"key%02d",++used_keys);
+ (*ptr)->set_bt_compare(*ptr, berkeley_cmp_packed_key);
+ if (!(table->key_info[i].flags & HA_NOSAME))
+ (*ptr)->set_flags(*ptr, DB_DUP);
+ if ((error=((*ptr)->open(*ptr, name_buff, part, DB_BTREE,
+ open_mode, 0))))
+ {
+ close();
+ my_errno=error;
+ DBUG_RETURN(1);
+ }
+ }
+ }
+ DBUG_RETURN(0);
+}
+
+
+void ha_berkeley::initialize(void)
+{
+ /* Calculate pack_length of primary key */
+ ref_length=0;
+ KEY_PART_INFO *key_part= table->key_info[primary_key].key_part;
+ KEY_PART_INFO *end=key_part+table->key_info[primary_key].key_parts;
+ for ( ; key_part != end ; key_part++)
+ ref_length+= key_part->field->max_packed_col_length(key_part->length);
+ fixed_length_primary_key=
+ (ref_length == table->key_info[primary_key].key_length);
+}
+
+int ha_berkeley::close(void)
+{
+ int error,result=0;
+ DBUG_ENTER("ha_berkeley::close");
+
+ for (uint i=0; i < table->keys; i++)
+ {
+ if (key_file[i] && (error=key_file[i]->close(key_file[i],0)))
+ result=error;
+ }
+ free_share(share);
+ my_free(rec_buff,MYF(MY_ALLOW_ZERO_PTR));
+ my_free(alloc_ptr,MYF(MY_ALLOW_ZERO_PTR));
+ if (result)
+ my_errno=result;
+ DBUG_RETURN(result);
+}
+
+
+/* Reallocate buffer if needed */
+
+bool ha_berkeley::fix_rec_buff_for_blob(ulong length)
+{
+ uint extra;
+ if (! rec_buff || length > alloced_rec_buff_length)
+ {
+ byte *newptr;
+ if (!(newptr=(byte*) my_realloc((gptr) rec_buff, length,
+ MYF(MY_ALLOW_ZERO_PTR))))
+ return 1;
+ rec_buff=newptr;
+ alloced_rec_buff_length=length;
+ }
+ return 0;
+}
+
+
+/* Calculate max length needed for row */
+
+ulong ha_berkeley::max_row_length(const byte *buf)
+{
+ ulong length=table->reclength + table->fields*2;
+ for (Field_blob **ptr=table->blob_field ; *ptr ; ptr++)
+ length+= (*ptr)->get_length(buf+(*ptr)->offset())+2;
+ return length;
+}
+
+
+/*
+ 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_berkeley::pack_row(DBT *row, const byte *record)
+{
+ bzero((char*) row,sizeof(*row));
+ if (fixed_length_row)
+ {
+ row->data=(void*) record;
+ row->size=table->reclength;
+ return 0;
+ }
+ if (table->blob_fields)
+ {
+ if (fix_rec_buff_for_blob(max_row_length(record)))
+ return HA_ERR_OUT_OF_MEM;
+ }
+
+ /* Copy null bits */
+ memcpy(rec_buff, record, table->null_bytes);
+ byte *ptr=rec_buff + table->null_bytes;
+
+ for (Field **field=table->field ; *field ; field++)
+ ptr=(byte*) (*field)->pack((char*) ptr,record + (*field)->offset());
+ row->data=rec_buff;
+ row->size= (size_t) (ptr - rec_buff);
+ return 0;
+}
+
+
+void ha_berkeley::unpack_row(char *record, DBT *row)
+{
+ if (fixed_length_row)
+ memcpy(record,row->data,table->reclength);
+ else
+ {
+ /* Copy null bits */
+ const char *ptr= (const char*) row->data;
+ memcpy(record, ptr, table->null_bytes);
+ ptr+=table->null_bytes;
+ for (Field **field=table->field ; *field ; field++)
+ ptr= (*field)->unpack(record + (*field)->offset(), ptr);
+ }
+}
+
+
+/*
+ Create a packed key from from a row
+ This will never fail as the key buffer is pre allocated.
+*/
+
+DBT *ha_berkeley::pack_key(DBT *key, uint keynr, char *buff,
+ const byte *record)
+{
+ 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;
+ DBUG_ENTER("pack_key");
+
+ bzero((char*) key,sizeof(*key));
+ key->data=buff;
+ key->app_private= key_info;
+
+ for ( ; key_part != end ; key_part++)
+ {
+ if (key_part->null_bit)
+ {
+ /* Store 0 if the key part is a NULL part */
+ if (record[key_part->null_offset] & key_part->null_bit)
+ {
+ *buff++ =0;
+ key->flags|=DB_DBT_DUPOK;
+ continue;
+ }
+ *buff++ = 1; // Store NOT NULL marker
+ }
+ buff=key_part->field->pack(buff,record + key_part->offset,
+ key_part->length);
+ }
+ key->size= (buff - (char*) key->data);
+ DBUG_DUMP("key",(char*) key->data, key->size);
+ DBUG_RETURN(key);
+}
+
+
+/*
+ Create a packed key from from a MySQL unpacked key
+*/
+
+DBT *ha_berkeley::pack_key(DBT *key, uint keynr, char *buff,
+ 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;
+ DBUG_ENTER("pack_key2");
+
+ bzero((char*) key,sizeof(*key));
+ key->data=buff;
+ key->app_private= key_info;
+
+ for (; key_part != end && (int) key_length > 0 ; key_part++)
+ {
+ uint offset=0;
+ if (key_part->null_bit)
+ {
+ offset=1;
+ if (!(*buff++ = (*key_ptr == 0))) // Store 0 if NULL
+ {
+ key_length-= key_part->store_length;
+ key_ptr+= key_part->store_length;
+ key->flags|=DB_DBT_DUPOK;
+ continue;
+ }
+ key_ptr++;
+ }
+ buff=key_part->field->keypack(buff,key_ptr+offset,key_part->length);
+ key_ptr+=key_part->store_length;
+ key_length-=key_part->store_length;
+ }
+ key->size= (buff - (char*) key->data);
+ DBUG_DUMP("key",(char*) key->data, key->size);
+ DBUG_RETURN(key);
+}
+
+
+int ha_berkeley::write_row(byte * record)
+{
+ DBT row,prim_key,key;
+ int error;
+ DBUG_ENTER("write_row");
+
+ statistic_increment(ha_write_count,&LOCK_status);
+ if (table->time_stamp)
+ update_timestamp(record+table->time_stamp-1);
+ if (table->next_number_field && record == table->record[0])
+ update_auto_increment();
+ if ((error=pack_row(&row, record)))
+ DBUG_RETURN(error);
+
+ if (table->keys == 1)
+ {
+ error=file->put(file, transaction, pack_key(&prim_key, primary_key,
+ key_buff, record),
+ &row, key_type[primary_key]);
+ }
+ else
+ {
+ for (uint retry=0 ; retry < berkeley_trans_retry ; retry++)
+ {
+ uint keynr;
+ DB_TXN *sub_trans;
+ if ((error=txn_begin(db_env, transaction, &sub_trans, 0)))
+ break;
+ DBUG_PRINT("trans",("starting subtransaction"));
+ if (!(error=file->put(file, sub_trans, pack_key(&prim_key, primary_key,
+ key_buff, record),
+ &row, key_type[primary_key])))
+ {
+ for (keynr=0 ; keynr < table->keys ; keynr++)
+ {
+ if (keynr == primary_key)
+ continue;
+ if ((error=key_file[keynr]->put(key_file[keynr], sub_trans,
+ pack_key(&key, keynr, key_buff2,
+ record),
+ &prim_key, key_type[keynr])))
+ {
+ last_dup_key=keynr;
+ break;
+ }
+ }
+ }
+ if (!error)
+ {
+ DBUG_PRINT("trans",("committing subtransaction"));
+ error=txn_commit(sub_trans, 0);
+ }
+ else
+ {
+ /* Remove inserted row */
+ int new_error;
+ DBUG_PRINT("error",("Got error %d",error));
+ DBUG_PRINT("trans",("aborting subtransaction"));
+ if ((new_error=txn_abort(sub_trans)))
+ {
+ error=new_error; // This shouldn't happen
+ break;
+ }
+ }
+ if (error != DB_LOCK_DEADLOCK)
+ break;
+ }
+ }
+ if (error == DB_KEYEXIST)
+ error=HA_ERR_FOUND_DUPP_KEY;
+ DBUG_RETURN(error);
+}
+
+
+/* Compare if a key in a row has changed */
+
+int ha_berkeley::key_cmp(uint keynr, const byte * old_row,
+ const byte * new_row)
+{
+ KEY_PART_INFO *key_part=table->key_info[keynr].key_part;
+ KEY_PART_INFO *end=key_part+table->key_info[keynr].key_parts;
+
+ for ( ; key_part != end ; key_part++)
+ {
+ if (key_part->null_bit)
+ {
+ if ((old_row[key_part->null_offset] & key_part->null_bit) !=
+ (new_row[key_part->null_offset] & key_part->null_bit))
+ return 1;
+ }
+ if (key_part->key_part_flag & (HA_BLOB_PART | HA_VAR_LENGTH))
+ {
+
+ if (key_part->field->cmp_binary(old_row + key_part->offset,
+ new_row + key_part->offset,
+ (ulong) key_part->length))
+ return 1;
+ }
+ else
+ {
+ if (memcmp(old_row+key_part->offset, new_row+key_part->offset,
+ key_part->length))
+ return 1;
+ }
+ }
+ return 0;
+}
+
+
+/*
+ Update a row from one value to another.
+*/
+
+int ha_berkeley::update_primary_key(DB_TXN *trans, bool primary_key_changed,
+ const byte * old_row,
+ const byte * new_row, DBT *prim_key)
+{
+ DBT row, old_key;
+ int error,new_error;
+ DBUG_ENTER("update_primary_key");
+
+ if (primary_key_changed)
+ {
+ // Primary key changed or we are updating a key that can have duplicates.
+ // Delete the old row and add a new one
+ pack_key(&old_key, primary_key, key_buff2, old_row);
+ if ((error=remove_key(trans, primary_key, old_row, (DBT *) 0, &old_key)))
+ DBUG_RETURN(error); // This should always succeed
+ if ((error=pack_row(&row, new_row)))
+ {
+ // Out of memory (this shouldn't happen!)
+ (void) file->put(file, trans, &old_key, &row,
+ key_type[primary_key]);
+ DBUG_RETURN(error);
+ }
+ // Write new key
+ if ((error=file->put(file, trans, prim_key, &row, key_type[primary_key])))
+ {
+ // Probably a duplicated key; Return the error and let the caller
+ // abort.
+ last_dup_key=primary_key;
+ DBUG_RETURN(error);
+ }
+ }
+ else
+ {
+ // Primary key didn't change; just update the row data
+ if ((error=pack_row(&row, new_row)))
+ DBUG_RETURN(error);
+ error=file->put(file, trans, prim_key, &row, 0);
+ if (error)
+ DBUG_RETURN(error); // Fatal error
+ }
+ DBUG_RETURN(0);
+}
+
+
+
+int ha_berkeley::update_row(const byte * old_row, byte * new_row)
+{
+ DBT row, prim_key, key, old_prim_key;
+ int error;
+ uint keynr;
+ DB_TXN *sub_trans;
+ bool primary_key_changed;
+ DBUG_ENTER("update_row");
+
+ statistic_increment(ha_update_count,&LOCK_status);
+ if (table->time_stamp)
+ update_timestamp(new_row+table->time_stamp-1);
+ pack_key(&prim_key, primary_key, key_buff, new_row);
+
+ if ((primary_key_changed=key_cmp(primary_key, old_row, new_row)))
+ pack_key(&old_prim_key, primary_key, primary_key_buff, old_row);
+ else
+ old_prim_key=prim_key;
+
+ LINT_INIT(error);
+ for (uint retry=0 ; retry < berkeley_trans_retry ; retry++)
+ {
+ if ((error=txn_begin(db_env, transaction, &sub_trans, 0)))
+ break;
+ DBUG_PRINT("trans",("starting subtransaction"));
+ /* Start by updating the primary key */
+ if (!(error=update_primary_key(sub_trans, primary_key_changed,
+ old_row, new_row, &prim_key)))
+ {
+ // Update all other keys
+ for (uint keynr=0 ; keynr < table->keys ; keynr++)
+ {
+ if (keynr == primary_key)
+ continue;
+ if (key_cmp(keynr, old_row, new_row) || primary_key_changed)
+ {
+ if ((error=remove_key(sub_trans, keynr, old_row, (DBT*) 0,
+ &old_prim_key)) ||
+ (error=key_file[keynr]->put(key_file[keynr], sub_trans,
+ pack_key(&key, keynr, key_buff2,
+ new_row),
+ &prim_key, key_type[keynr])))
+ {
+ last_dup_key=keynr;
+ break;
+ }
+ }
+ }
+ }
+ if (!error)
+ {
+ DBUG_PRINT("trans",("committing subtransaction"));
+ error=txn_commit(sub_trans, 0);
+ }
+ else
+ {
+ /* Remove inserted row */
+ int new_error;
+ DBUG_PRINT("error",("Got error %d",error));
+ DBUG_PRINT("trans",("aborting subtransaction"));
+ if ((new_error=txn_abort(sub_trans)))
+ {
+ error=new_error; // This shouldn't happen
+ break;
+ }
+ }
+ if (error != DB_LOCK_DEADLOCK)
+ break;
+ }
+ if (error == DB_KEYEXIST)
+ error=HA_ERR_FOUND_DUPP_KEY;
+ DBUG_RETURN(error);
+}
+
+
+/*
+ Delete one key
+ This uses key_buff2, when keynr != primary key, so it's important that
+ a function that calls this doesn't use this buffer for anything else.
+ packed_record may be NULL if the key is unique
+*/
+
+int ha_berkeley::remove_key(DB_TXN *sub_trans, uint keynr, const byte *record,
+ DBT *packed_record,
+ DBT *prim_key)
+{
+ int error;
+ DBT key;
+ DBUG_ENTER("remove_key");
+ DBUG_PRINT("enter",("index: %d",keynr));
+
+ if ((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);
+ error=key_file[keynr]->del(key_file[keynr], sub_trans,
+ keynr == primary_key ?
+ prim_key :
+ pack_key(&key, keynr, key_buff2, record),
+ 0);
+ }
+ else
+ {
+ /*
+ To delete the not duplicated key, we need to open an cursor on the
+ 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);
+ DBC *cursor;
+ if (!(error=file->cursor(key_file[keynr], sub_trans, &cursor, 0)))
+ {
+ if (!(error=cursor->c_get(cursor,
+ (keynr == primary_key ?
+ prim_key :
+ pack_key(&key, keynr, key_buff2, record)),
+ (keynr == primary_key ?
+ packed_record : prim_key),
+ DB_GET_BOTH)))
+ { // This shouldn't happen
+ error=cursor->c_del(cursor,0);
+ }
+ int result=cursor->c_close(cursor);
+ if (!error)
+ error=result;
+ }
+ }
+ DBUG_RETURN(error);
+}
+
+
+/* Delete all keys for new_record */
+
+int ha_berkeley::remove_keys(DB_TXN *trans, const byte *record,
+ DBT *new_record, DBT *prim_key, key_map keys,
+ int result)
+{
+ for (uint keynr=0 ; keys ;keynr++, keys>>=1)
+ {
+ if (keys & 1)
+ {
+ int new_error=remove_key(trans, keynr, record, new_record, prim_key);
+ if (new_error)
+ {
+ result=new_error; // Return last error
+ if (trans)
+ break; // Let rollback correct things
+ }
+ }
+ }
+ return result;
+}
+
+
+int ha_berkeley::delete_row(const byte * record)
+{
+ int error;
+ DBT row, prim_key;
+ key_map keys=table->keys_in_use;
+ DBUG_ENTER("delete_row");
+ statistic_increment(ha_delete_count,&LOCK_status);
+
+ if ((error=pack_row(&row, record)))
+ DBUG_RETURN((error));
+ pack_key(&prim_key, primary_key, key_buff, record);
+ for (uint retry=0 ; retry < berkeley_trans_retry ; retry++)
+ {
+ DB_TXN *sub_trans;
+ if ((error=txn_begin(db_env, transaction, &sub_trans, 0)))
+ break;
+ DBUG_PRINT("trans",("starting sub transaction"));
+ if (!error)
+ error=remove_keys(sub_trans, record, &row, &prim_key, keys,0);
+ if (!error)
+ {
+ DBUG_PRINT("trans",("ending sub transaction"));
+ error=txn_commit(sub_trans, 0);
+ }
+ if (error)
+ {
+ /* retry */
+ int new_error;
+ DBUG_PRINT("error",("Got error %d",error));
+ DBUG_PRINT("trans",("aborting subtransaction"));
+ if ((new_error=txn_abort(sub_trans)))
+ {
+ error=new_error; // This shouldn't happen
+ break;
+ }
+ }
+ if (error != DB_LOCK_DEADLOCK)
+ break;
+ }
+ DBUG_RETURN(0);
+}
+
+
+int ha_berkeley::index_init(uint keynr)
+{
+ int error;
+ DBUG_ENTER("index_init");
+ active_index=keynr;
+ dbug_assert(cursor == 0);
+ if ((error=file->cursor(key_file[keynr], transaction, &cursor,
+ table->reginfo.lock_type > TL_WRITE_ALLOW_READ ?
+ 0 : 0)))
+ cursor=0; // Safety
+ bzero((char*) &last_key,sizeof(last_key));
+ DBUG_RETURN(error);
+}
+
+int ha_berkeley::index_end()
+{
+ int error=0;
+ DBUG_ENTER("index_end");
+ if (cursor)
+ {
+ error=cursor->c_close(cursor);
+ cursor=0;
+ }
+ DBUG_RETURN(error);
+}
+
+
+/* What to do after we have read a row based on an index */
+
+int ha_berkeley::read_row(int error, char *buf, uint keynr, DBT *row,
+ bool read_next)
+{
+ DBUG_ENTER("read_row");
+ if (error)
+ {
+ if (error == DB_NOTFOUND || error == DB_KEYEMPTY)
+ error=read_next ? HA_ERR_END_OF_FILE : HA_ERR_KEY_NOT_FOUND;
+ table->status=STATUS_NOT_FOUND;
+ DBUG_RETURN(error);
+ }
+
+ if (keynr != primary_key)
+ {
+ DBT key;
+ bzero((char*) &key,sizeof(key));
+ key.data=key_buff2;
+ key.size=row->size;
+ key.app_private=table->key_info+primary_key;
+ memcpy(key_buff2,row->data,row->size);
+ /* Read the data into current_row */
+ current_row.flags=DB_DBT_REALLOC;
+ if ((error=file->get(file, transaction, &key, &current_row, 0)))
+ {
+ table->status=STATUS_NOT_FOUND;
+ DBUG_RETURN(error == DB_NOTFOUND ? HA_ERR_CRASHED : error);
+ }
+ row= &current_row;
+ }
+ unpack_row(buf,row);
+ table->status=0;
+ DBUG_RETURN(0);
+}
+
+
+int ha_berkeley::index_read_idx(byte * buf, uint keynr, const byte * key,
+ uint key_len, enum ha_rkey_function find_flag)
+{
+ statistic_increment(ha_read_key_count,&LOCK_status);
+ DBUG_ENTER("index_read_idx");
+ current_row.flags=DB_DBT_REALLOC;
+ DBUG_RETURN(read_row(file->get(file, transaction,
+ pack_key(&last_key, keynr, key_buff, key,
+ key_len),
+ &current_row,0),
+ buf, keynr, &current_row, 0));
+}
+
+
+int ha_berkeley::index_read(byte * buf, const byte * key,
+ uint key_len, enum ha_rkey_function find_flag)
+{
+ DBT row;
+ DBUG_ENTER("index_read");
+ statistic_increment(ha_read_key_count,&LOCK_status);
+ bzero((char*) &row,sizeof(row));
+ DBUG_RETURN(read_row(cursor->c_get(cursor,
+ pack_key(&last_key, active_index,
+ key_buff, key, key_len),
+ &row, DB_SET),
+ buf, active_index, &row, 0));
+}
+
+
+int ha_berkeley::index_next(byte * buf)
+{
+ DBT row;
+ DBUG_ENTER("index_next");
+ statistic_increment(ha_read_next_count,&LOCK_status);
+ bzero((char*) &row,sizeof(row));
+ DBUG_RETURN(read_row(cursor->c_get(cursor, &last_key, &row, DB_NEXT),
+ buf, active_index, &row ,1));
+}
+
+int ha_berkeley::index_next_same(byte * buf, const byte *key, uint keylen)
+{
+ DBT row;
+ int error;
+ DBUG_ENTER("index_next_same");
+ statistic_increment(ha_read_next_count,&LOCK_status);
+ bzero((char*) &row,sizeof(row));
+ if (keylen == table->key_info[active_index].key_length)
+ error=read_row(cursor->c_get(cursor, &last_key, &row, DB_NEXT_DUP),
+ buf, active_index, &row,1);
+ else
+ {
+ error=read_row(cursor->c_get(cursor, &last_key, &row, DB_NEXT),
+ buf, active_index, &row,1);
+ if (!error && ::key_cmp(table, key, active_index, keylen))
+ error=HA_ERR_END_OF_FILE;
+ }
+ DBUG_RETURN(error);
+}
+
+
+int ha_berkeley::index_prev(byte * buf)
+{
+ DBT row;
+ DBUG_ENTER("index_prev");
+ statistic_increment(ha_read_prev_count,&LOCK_status);
+ bzero((char*) &row,sizeof(row));
+ DBUG_RETURN(read_row(cursor->c_get(cursor, &last_key, &row, DB_PREV),
+ buf, active_index, &row,1));
+}
+
+
+int ha_berkeley::index_first(byte * buf)
+{
+ DBT row;
+ DBUG_ENTER("index_first");
+ statistic_increment(ha_read_first_count,&LOCK_status);
+ bzero((char*) &row,sizeof(row));
+ DBUG_RETURN(read_row(cursor->c_get(cursor, &last_key, &row, DB_FIRST),
+ buf, active_index, &row,0));
+}
+
+int ha_berkeley::index_last(byte * buf)
+{
+ DBT row;
+ DBUG_ENTER("index_last");
+ statistic_increment(ha_read_last_count,&LOCK_status);
+ bzero((char*) &row,sizeof(row));
+ DBUG_RETURN(read_row(cursor->c_get(cursor, &last_key, &row, DB_LAST),
+ buf, active_index, &row,0));
+}
+
+int ha_berkeley::rnd_init(bool scan)
+{
+ current_row.flags=DB_DBT_REALLOC;
+ return index_init(primary_key);
+}
+
+int ha_berkeley::rnd_end()
+{
+ return index_end();
+}
+
+int ha_berkeley::rnd_next(byte *buf)
+{
+ DBT row;
+ DBUG_ENTER("rnd_next");
+ statistic_increment(ha_read_rnd_next_count,&LOCK_status);
+ bzero((char*) &row,sizeof(row));
+ DBUG_RETURN(read_row(cursor->c_get(cursor, &last_key, &row, DB_NEXT),
+ buf, active_index, &row, 1));
+}
+
+
+DBT *ha_berkeley::get_pos(DBT *to, byte *pos)
+{
+ bzero((char*) to,sizeof(*to));
+
+ to->data=pos;
+ to->app_private=table->key_info+primary_key;
+ if (fixed_length_primary_key)
+ to->size=ref_length;
+ else
+ {
+ KEY_PART_INFO *key_part=table->key_info[primary_key].key_part;
+ KEY_PART_INFO *end=key_part+table->key_info[primary_key].key_parts;
+
+ for ( ; key_part != end ; key_part++)
+ pos+=key_part->field->packed_col_length(pos);
+ to->size= (uint) (pos- (byte*) to->data);
+ }
+ return to;
+}
+
+
+int ha_berkeley::rnd_pos(byte * buf, byte *pos)
+{
+ DBT db_pos;
+ statistic_increment(ha_read_rnd_count,&LOCK_status);
+
+ return read_row(file->get(file, transaction,
+ get_pos(&db_pos, pos),
+ &current_row, 0),
+ buf, active_index, &current_row,0);
+}
+
+void ha_berkeley::position(const byte *record)
+{
+ DBT key;
+ pack_key(&key, primary_key, ref, record);
+}
+
+
+void ha_berkeley::info(uint flag)
+{
+ DBUG_ENTER("info");
+ if (flag & HA_STATUS_VARIABLE)
+ {
+ records = HA_BERKELEY_ROWS_IN_TABLE; // Just to get optimisations right
+ deleted = 0;
+ }
+ else if (flag & HA_STATUS_ERRKEY)
+ errkey=last_dup_key;
+ DBUG_VOID_RETURN;
+}
+
+
+int ha_berkeley::extra(enum ha_extra_function operation)
+{
+ return 0;
+}
+
+int ha_berkeley::reset(void)
+{
+ 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_berkeley::external_lock(THD *thd, int lock_type)
+{
+ int error=0;
+ DBUG_ENTER("ha_berkeley::external_lock");
+ if (lock_type != F_UNLCK)
+ {
+ if (!thd->transaction.bdb_lock_count++ && !thd->transaction.bdb_tid)
+ {
+ /* Found first lock, start transaction */
+ DBUG_PRINT("trans",("starting transaction"));
+ if ((error=txn_begin(db_env, 0,
+ (DB_TXN**) &thd->transaction.bdb_tid,
+ 0)))
+ thd->transaction.bdb_lock_count--;
+ }
+ transaction= (DB_TXN*) thd->transaction.bdb_tid;
+ }
+ else
+ {
+ lock.type=TL_UNLOCK; // Unlocked
+ if (current_row.flags & (DB_DBT_MALLOC | DB_DBT_REALLOC))
+ {
+ current_row.flags=0;
+ if (current_row.data)
+ {
+ free(current_row.data);
+ current_row.data=0;
+ }
+ }
+ current_row.data=0;
+ if (!--thd->transaction.bdb_lock_count)
+ {
+ if (thd->transaction.bdb_tid && (thd->options &
+ (OPTION_AUTO_COMMIT | OPTION_BEGIN)))
+ {
+ /*
+ F_UNLOCK is done without a transaction commit / rollback. This
+ means that something went wrong.
+ We can in this case silenty abort the transaction.
+ */
+ DBUG_PRINT("trans",("aborting transaction"));
+ error=txn_abort((DB_TXN*) thd->transaction.bdb_tid);
+ thd->transaction.bdb_tid=0;
+ }
+ }
+ }
+ DBUG_RETURN(error);
+}
+
+
+THR_LOCK_DATA **ha_berkeley::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;
+ }
+ *to++= &lock;
+ return to;
+}
+
+
+static int create_sub_table(const char *table_name, const char *sub_name,
+ DBTYPE type, int flags)
+{
+ int error,error2;
+ DB *file;
+ DBUG_ENTER("create_sub_table");
+ DBUG_PRINT("enter",("sub_name: %s",sub_name));
+
+ if (!(error=db_create(&file, db_env, 0)))
+ {
+ file->set_flags(file, flags);
+ error=(file->open(file, table_name, sub_name, type,
+ DB_THREAD | DB_CREATE, my_umask));
+ if (error)
+ {
+ DBUG_PRINT("error",("Got error: %d when opening table '%s'",error,
+ table_name));
+ (void) file->remove(file,table_name,NULL,0);
+ }
+ else
+ (void) file->close(file,0);
+ }
+ else
+ {
+ DBUG_PRINT("error",("Got error: %d when creting table",error));
+ }
+ if (error)
+ my_errno=error;
+ DBUG_RETURN(error);
+}
+
+
+int ha_berkeley::create(const char *name, register TABLE *form,
+ HA_CREATE_INFO *create_info)
+{
+ char name_buff[FN_REFLEN];
+ char part[7];
+ DBUG_ENTER("ha_berkeley::create");
+
+ fn_format(name_buff,name,"", ha_berkeley_ext,2 | 4);
+
+ /* Create the main table that will hold the real rows */
+ if (create_sub_table(name_buff,"main",DB_BTREE,0))
+ DBUG_RETURN(1);
+
+ /* Create the keys */
+ for (uint i=1; i < form->keys; i++)
+ {
+ sprintf(part,"key%02d",i);
+ if (create_sub_table(name_buff, part, DB_BTREE,
+ (table->key_info[i].flags & HA_NOSAME) ? 0 :
+ DB_DUP))
+ DBUG_RETURN(1);
+ }
+
+ /* Create the status block to save information from last status command */
+ /* Is DB_BTREE the best option here ? (QUEUE can't be used in sub tables) */
+ if (create_sub_table(name_buff,"status",DB_BTREE,0))
+ DBUG_RETURN(1);
+ DBUG_RETURN(0);
+}
+
+
+int ha_berkeley::delete_table(const char *name)
+{
+ int error;
+ char name_buff[FN_REFLEN];
+ if ((error=db_create(&file, db_env, 0)))
+ {
+ my_errno=error;
+ file=0;
+ return 1;
+ }
+ error=file->remove(file,fn_format(name_buff,name,"",ha_berkeley_ext,2 | 4),
+ NULL,0);
+ file=0; // Safety
+ return error;
+}
+
+/*
+ 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_berkeley::scan_time()
+{
+ return records/3;
+ }
+
+ha_rows ha_berkeley::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)
+{
+ DBT key;
+ DB_KEY_RANGE start_range, end_range;
+ double start_pos,end_pos,rows;
+ DBUG_ENTER("records_in_range");
+ if ((start_key && file->key_range(file,transaction,
+ pack_key(&key, keynr, key_buff, start_key,
+ start_key_len),
+ &start_range,0)) ||
+ (end_key && file->key_range(file,transaction,
+ pack_key(&key, keynr, key_buff, end_key,
+ end_key_len),
+ &end_range,0)))
+ DBUG_RETURN(HA_BERKELEY_RANGE_COUNT); // Better than returning an error
+
+ if (!start_key)
+ start_pos=0.0;
+ else if (start_search_flag == HA_READ_KEY_EXACT)
+ start_pos=start_range.less;
+ else
+ start_pos=start_range.less+start_range.equal;
+
+ if (!end_key)
+ end_pos=1.0;
+ else if (end_search_flag == HA_READ_BEFORE_KEY)
+ end_pos=end_range.less;
+ else
+ end_pos=end_range.less+end_range.equal;
+ rows=(end_pos-start_pos)*records;
+ DBUG_PRINT("exit",("rows: %g",rows));
+ DBUG_RETURN(rows <= 1.0 ? (ha_rows) 1 : (ha_rows) rows);
+}
+
+/****************************************************************************
+ Handling the shared BDB_SHARE structure that is needed to provide table
+ locking.
+****************************************************************************/
+
+static byte* bdb_get_key(BDB_SHARE *share,uint *length,
+ my_bool not_used __attribute__((unused)))
+{
+ *length=share->table_name_length;
+ return (byte*) share->table_name;
+}
+
+static BDB_SHARE *get_share(const char *table_name)
+{
+ BDB_SHARE *share;
+ pthread_mutex_lock(&bdb_mutex);
+ uint length=strlen(table_name);
+ if (!(share=(BDB_SHARE*) hash_search(&bdb_open_tables, table_name, length)))
+ {
+ if ((share=(BDB_SHARE *) my_malloc(sizeof(*share)+length+1,
+ MYF(MY_WME | MY_ZEROFILL))))
+ {
+ // pthread_mutex_init(&share->mutex);
+ // pthread_cond_init(&share->cond);
+ share->table_name_length=length;
+ share->table_name=(char*) (share+1);
+ strmov(share->table_name,table_name);
+ if (hash_insert(&bdb_open_tables, (char*) share))
+ {
+ pthread_mutex_unlock(&bdb_mutex);
+ my_free((gptr) share,0);
+ return 0;
+ }
+ thr_lock_init(&share->lock);
+ }
+ }
+ share->use_count++;
+ pthread_mutex_unlock(&bdb_mutex);
+ return share;
+}
+
+static void free_share(BDB_SHARE *share)
+{
+ pthread_mutex_lock(&bdb_mutex);
+ if (!--share->use_count)
+ {
+ hash_delete(&bdb_open_tables, (gptr) share);
+ thr_lock_delete(&share->lock);
+ // pthread_mutex_destroy(&share->mutex);
+ my_free((gptr) share, MYF(0));
+ }
+ pthread_mutex_unlock(&bdb_mutex);
+}
+
+#endif /* HAVE_BERKELEY_DB */
diff --git a/sql/ha_berkeley.h b/sql/ha_berkeley.h
new file mode 100644
index 00000000000..d8e55995635
--- /dev/null
+++ b/sql/ha_berkeley.h
@@ -0,0 +1,141 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+
+#ifdef __GNUC__
+#pragma interface /* gcc class implementation */
+#endif
+
+/* class for the the myisam handler */
+
+#include <db.h>
+
+typedef struct st_berkeley_share {
+ THR_LOCK lock;
+ char *table_name;
+ uint table_name_length,use_count;
+} BDB_SHARE;
+
+class ha_berkeley: public handler
+{
+ THR_LOCK_DATA lock;
+ DBT last_key,current_row;
+ gptr alloc_ptr;
+ byte *rec_buff;
+ char *key_buff, *key_buff2, *primary_key_buff;
+ DB *file, **key_file;
+ DB_TXN *transaction;
+ u_int32_t *key_type;
+ DBC *cursor;
+ BDB_SHARE *share;
+ ulong int_option_flag;
+ ulong alloced_rec_buff_length;
+ uint primary_key,last_dup_key;
+ bool fixed_length_row, fixed_length_primary_key;
+
+ bool fix_rec_buff_for_blob(ulong length);
+ ulong max_row_length(const byte *buf);
+ int pack_row(DBT *row,const byte *record);
+ void unpack_row(char *record, DBT *row);
+ DBT *pack_key(DBT *key, uint keynr, char *buff, const byte *record);
+ DBT *pack_key(DBT *key, uint keynr, char *buff, const byte *key,
+ uint key_length);
+ int remove_key(DB_TXN *trans, uint keynr, const byte *record,
+ DBT *packed_record, DBT *prim_key);
+ int remove_keys(DB_TXN *trans,const byte *record, DBT *new_record,
+ DBT *prim_key, key_map keys, int result);
+ int key_cmp(uint keynr, const byte * old_row, const byte * new_row);
+ int update_primary_key(DB_TXN *trans, bool primary_key_changed,
+ const byte * old_row, const byte * new_row,
+ DBT *prim_key);
+ int read_row(int error, char *buf, uint keynr, DBT *row, bool);
+ DBT *get_pos(DBT *to, byte *pos);
+
+ public:
+ ha_berkeley(TABLE *table): handler(table), alloc_ptr(0),rec_buff(0), file(0),
+ int_option_flag(HA_READ_NEXT+HA_READ_PREV+
+ HA_KEYPOS_TO_RNDPOS+ HA_READ_ORDER+ HA_LASTKEY_ORDER+
+ HA_LONGLONG_KEYS+ HA_NULL_KEY +
+ HA_BLOB_KEY +
+ HA_REQUIRE_PRIMARY_KEY + HA_NOT_EXACT_COUNT +
+ HA_PRIMARY_KEY_IN_READ_INDEX + HA_DROP_BEFORE_CREATE),
+ last_dup_key((uint) -1)
+ {
+ }
+ ~ha_berkeley() {}
+ const char *table_type() const { return "BerkeleyDB"; }
+ 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 MAX_KEY; }
+ uint max_key_parts() const { return MAX_REF_PARTS; }
+ uint max_key_length() const { return MAX_KEY_LENGTH; }
+ bool fast_key_read() { return 1;}
+ bool has_transactions() { return 1;}
+
+ int open(const char *name, int mode, int test_if_locked);
+ void initialize(void);
+ 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 external_lock(THD *thd, int lock_type);
+ void ha_berkeley::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);
+
+ int ha_berkeley::create(const char *name, register TABLE *form,
+ HA_CREATE_INFO *create_info);
+ int ha_berkeley::delete_table(const char *name);
+ THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to,
+ enum thr_lock_type lock_type);
+};
+
+extern bool berkeley_skip;
+extern u_int32_t berkeley_init_flags,berkeley_lock_type,berkeley_lock_types[];
+extern ulong berkeley_cache_size;
+extern char *berkeley_home, *berkeley_tmpdir, *berkeley_logdir;
+extern long berkeley_lock_scan_time;
+extern TYPELIB berkeley_lock_typelib;
+
+bool berkeley_init(void);
+bool berkeley_end(void);
+bool berkeley_flush_logs(void);
+int berkeley_commit(THD *thd);
+int berkeley_rollback(THD *thd);
diff --git a/sql/ha_hash.h b/sql/ha_hash.h
new file mode 100644
index 00000000000..80416611406
--- /dev/null
+++ b/sql/ha_hash.h
@@ -0,0 +1,31 @@
+
+int ha_hash::create(my_string name, register TABLE *form,
+ ulonglong auto_increment_value)
+{
+ register uint i,j;
+ char buff[FN_REFLEN];
+ KEY *pos;
+ H_KEYDEF keydef[MAX_KEY];
+ DBUG_ENTER("cre_hash");
+
+ pos=form->key_info;
+ for (i=0; i < form->keys ; i++, pos++)
+ {
+ keydef[i].hk_flag= pos->flags & HA_NOSAME;
+ for (j=0 ; (int7) j < pos->key_parts ; j++)
+ {
+ uint flag=pos->key_part[j].key_type;
+ if (!f_is_packed(flag) && f_packtype(flag) == (int) FIELD_TYPE_DECIMAL &&
+ !(flag & FIELDFLAG_BINARY))
+ keydef[i].hk_keyseg[j].key_type= (int) HA_KEYTYPE_TEXT;
+ else
+ keydef[i].hk_keyseg[j].key_type= (int) HA_KEYTYPE_BINARY;
+ keydef[i].hk_keyseg[j].start= pos->key_part[j].offset;
+ keydef[i].hk_keyseg[j].length= pos->key_part[j].length;
+ }
+ keydef[i].hk_keyseg[j].key_type= 0;
+ }
+ DBUG_RETURN(h_create(fn_format(buff,name,"","",2+4+16),i,
+ keydef,form->reclength,form->max_rows,form->min_rows,
+ 0));
+} /* cre_hash */
diff --git a/sql/ha_heap.cc b/sql/ha_heap.cc
new file mode 100644
index 00000000000..989497cee6e
--- /dev/null
+++ b/sql/ha_heap.cc
@@ -0,0 +1,261 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+
+#ifdef __GNUC__
+#pragma implementation // gcc: Class implementation
+#endif
+
+#include "mysql_priv.h"
+#include <myisampack.h>
+#include "ha_heap.h"
+
+/*****************************************************************************
+** HEAP tables
+*****************************************************************************/
+
+const char **ha_heap::bas_ext() const
+{ static const char *ext[1]= { NullS }; return ext; }
+
+
+int ha_heap::open(const char *name, int mode, int test_if_locked)
+{
+ uint key,part,parts;
+ HP_KEYDEF *keydef;
+ HP_KEYSEG *seg;
+
+ for (key=parts=0 ; key < table->keys ; key++)
+ parts+=table->key_info[key].key_parts;
+
+ if (!(keydef=(HP_KEYDEF*) my_malloc(table->keys*sizeof(HP_KEYDEF)+
+ parts*sizeof(HP_KEYSEG),MYF(MY_WME))))
+ return my_errno;
+ seg=my_reinterpret_cast(HP_KEYSEG*) (keydef+table->keys);
+ for (key=0 ; key < table->keys ; key++)
+ {
+ KEY *pos=table->key_info+key;
+
+ keydef[key].keysegs=(uint) pos->key_parts;
+ keydef[key].flag = (pos->flags & HA_NOSAME);
+ keydef[key].seg=seg;
+
+ for (part=0 ; part < pos->key_parts ; part++)
+ {
+ uint flag=pos->key_part[part].key_type;
+ 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++;
+ }
+ }
+ file=heap_open(table->path,mode,
+ table->keys,keydef,
+ table->reclength,table->max_rows,
+ table->min_rows);
+ my_free((gptr) keydef,MYF(0));
+ info(HA_STATUS_NO_LOCK | HA_STATUS_CONST | HA_STATUS_VARIABLE);
+ ref_length=sizeof(HEAP_PTR);
+ return (!file ? errno : 0);
+}
+
+int ha_heap::close(void)
+{
+ return heap_close(file);
+}
+
+int ha_heap::write_row(byte * buf)
+{
+ statistic_increment(ha_write_count,&LOCK_status);
+ if (table->time_stamp)
+ update_timestamp(buf+table->time_stamp-1);
+ return heap_write(file,buf);
+}
+
+int ha_heap::update_row(const byte * old_data, byte * new_data)
+{
+ statistic_increment(ha_update_count,&LOCK_status);
+ if (table->time_stamp)
+ update_timestamp(new_data+table->time_stamp-1);
+ return heap_update(file,old_data,new_data);
+}
+
+int ha_heap::delete_row(const byte * buf)
+{
+ statistic_increment(ha_delete_count,&LOCK_status);
+ return heap_delete(file,buf);
+}
+
+int ha_heap::index_read(byte * buf, const byte * key,
+ uint key_len __attribute__((unused)),
+ enum ha_rkey_function find_flag
+ __attribute__((unused)))
+{
+ statistic_increment(ha_read_key_count,&LOCK_status);
+ int error=heap_rkey(file,buf,active_index, key);
+ table->status=error ? STATUS_NOT_FOUND: 0;
+ return error;
+}
+
+int ha_heap::index_read_idx(byte * buf, uint index, const byte * key,
+ uint key_len __attribute__((unused)),
+ enum ha_rkey_function find_flag
+ __attribute__((unused)))
+{
+ statistic_increment(ha_read_key_count,&LOCK_status);
+ int error=heap_rkey(file, buf, index, key);
+ table->status=error ? STATUS_NOT_FOUND: 0;
+ return error;
+}
+
+
+int ha_heap::index_next(byte * buf)
+{
+ statistic_increment(ha_read_next_count,&LOCK_status);
+ int error=heap_rnext(file,buf);
+ table->status=error ? STATUS_NOT_FOUND: 0;
+ return error;
+}
+
+int ha_heap::index_prev(byte * buf)
+{
+ statistic_increment(ha_read_prev_count,&LOCK_status);
+ int error=heap_rprev(file,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);
+ int error=heap_rfirst(file, buf);
+ table->status=error ? STATUS_NOT_FOUND: 0;
+ return error;
+}
+
+int ha_heap::index_last(byte * buf)
+{
+ statistic_increment(ha_read_last_count,&LOCK_status);
+ int error=heap_rlast(file, buf);
+ table->status=error ? STATUS_NOT_FOUND: 0;
+ return error;
+}
+
+int ha_heap::rnd_init(bool scan)
+{
+ return scan ? heap_scan_init(file) : 0;
+}
+
+int ha_heap::rnd_next(byte *buf)
+{
+ statistic_increment(ha_read_rnd_next_count,&LOCK_status);
+ int error=heap_scan(file, buf);
+ table->status=error ? STATUS_NOT_FOUND: 0;
+ return error;
+}
+
+int ha_heap::rnd_pos(byte * buf, byte *pos)
+{
+ int error;
+ HEAP_PTR position;
+ statistic_increment(ha_read_rnd_count,&LOCK_status);
+ memcpy_fixed((char*) &position,pos,sizeof(HEAP_PTR));
+ error=heap_rrnd(file, buf, position);
+ table->status=error ? STATUS_NOT_FOUND: 0;
+ return error;
+}
+
+void ha_heap::position(const byte *record)
+{
+ *(HEAP_PTR*) ref= heap_position(file); // Ref is aligned
+}
+
+void ha_heap::info(uint flag)
+{
+ HEAPINFO info;
+ (void) heap_info(file,&info,flag);
+
+ records = info.records;
+ deleted = info.deleted;
+ errkey = info.errkey;
+ mean_rec_length=info.reclength;
+ data_file_length=info.data_length;
+ index_file_length=info.index_length;
+ max_data_file_length= info.max_records* info.reclength;
+ delete_length= info.deleted * info.reclength;
+}
+
+int ha_heap::extra(enum ha_extra_function operation)
+{
+ return heap_extra(file,operation);
+}
+
+int ha_heap::reset(void)
+{
+ return heap_extra(file,HA_EXTRA_RESET);
+}
+
+int ha_heap::delete_all_rows()
+{
+ heap_clear(file);
+ return 0;
+}
+
+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,
+ enum thr_lock_type lock_type)
+{
+ if (lock_type != TL_IGNORE && file->lock.type == TL_UNLOCK)
+ file->lock.type=lock_type;
+ *to++= &file->lock;
+ return to;
+}
+
+
+/*
+ We have to ignore ENOENT entries as the HEAP table is created on open and
+ not when doing a CREATE on the table.
+*/
+
+int ha_heap::delete_table(const char *name)
+{
+ int error=heap_delete_all(name);
+ return error == ENOENT ? 0 : error;
+}
+
+int ha_heap::rename_table(const char * from, const char * to)
+{
+ return heap_rename(from,to);
+}
+
+
+/* We can just delete the heap on creation */
+
+int ha_heap::create(const char *name, TABLE *form, HA_CREATE_INFO *create_info)
+
+{
+ char buff[FN_REFLEN];
+ return heap_create(fn_format(buff,name,"","",2));
+}
diff --git a/sql/ha_heap.h b/sql/ha_heap.h
new file mode 100644
index 00000000000..acbc0975f1e
--- /dev/null
+++ b/sql/ha_heap.h
@@ -0,0 +1,83 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+
+#ifdef __GNUC__
+#pragma interface /* gcc class implementation */
+#endif
+
+/* class for the the heap handler */
+
+#include <heap.h>
+
+class ha_heap: public handler
+{
+ HP_INFO *file;
+
+ public:
+ ha_heap(TABLE *table): handler(table), file(0) {}
+ ~ha_heap() {}
+ const char *table_type() const { return "HEAP"; }
+ const char **bas_ext() const;
+ ulong option_flag() const
+ { return (HA_READ_RND_SAME+HA_NO_INDEX+HA_BINARY_KEYS+HA_WRONG_ASCII_ORDER+
+ HA_KEYPOS_TO_RNDPOS+HA_NO_BLOBS+HA_REC_NOT_IN_SEQ); }
+ 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; }
+ uint max_key_length() const { return HA_MAX_REC_LENGTH; }
+ virtual double scan_time() { return (double) (records+deleted) / 100.0; }
+ virtual double read_time(ha_rows rows) { return (double) rows / 100.0; }
+ virtual bool fast_key_read() { return 1;}
+
+ int open(const char *name, int mode, int test_if_locked);
+ int close(void);
+ int write_row(byte * buf);
+ int update_row(const byte * old_data, byte * new_data);
+ int delete_row(const byte * buf);
+ int index_read(byte * buf, const byte * key,
+ uint key_len, enum ha_rkey_function find_flag);
+ int index_read_idx(byte * buf, uint idx, const byte * key,
+ uint key_len, enum ha_rkey_function find_flag);
+ int index_next(byte * buf);
+ int index_prev(byte * buf);
+ int index_first(byte * buf);
+ int index_last(byte * buf);
+ int rnd_init(bool scan=1);
+ int rnd_next(byte *buf);
+ int rnd_pos(byte * buf, byte *pos);
+ void position(const byte *record);
+ void info(uint);
+ int extra(enum ha_extra_function operation);
+ int reset(void);
+ int external_lock(THD *thd, int lock_type);
+ int delete_all_rows(void);
+
+ int delete_table(const char *from);
+ int rename_table(const char * from, const char * to);
+ int create(const char *name, TABLE *form, HA_CREATE_INFO *create_info);
+
+ THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to,
+ enum thr_lock_type lock_type);
+
+};
+
+
+
+
+
+
+
diff --git a/sql/ha_isam.cc b/sql/ha_isam.cc
new file mode 100644
index 00000000000..fc836977f23
--- /dev/null
+++ b/sql/ha_isam.cc
@@ -0,0 +1,390 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+
+#ifdef __GNUC__
+#pragma implementation // gcc: Class implementation
+#endif
+
+#include "mysql_priv.h"
+#include <m_ctype.h>
+#include <myisampack.h>
+#include "ha_isam.h"
+#ifndef MASTER
+#include "../srclib/isam/isamdef.h"
+#else
+#include "../isam/isamdef.h"
+#endif
+
+/*****************************************************************************
+** isam tables
+*****************************************************************************/
+
+const char **ha_isam::bas_ext() const
+{ static const char *ext[]= { ".ISD",".ISM", NullS }; return ext; }
+
+
+int ha_isam::open(const char *name, int mode, int test_if_locked)
+{
+ char name_buff[FN_REFLEN];
+ if (!(file=nisam_open(fn_format(name_buff,name,"","",2 | 4), mode,
+ test_if_locked)))
+ return (my_errno ? my_errno : -1);
+
+ if (!(test_if_locked == HA_OPEN_WAIT_IF_LOCKED ||
+ test_if_locked == HA_OPEN_ABORT_IF_LOCKED))
+ (void) nisam_extra(file,HA_EXTRA_NO_WAIT_LOCK);
+ info(HA_STATUS_NO_LOCK | HA_STATUS_VARIABLE | HA_STATUS_CONST);
+ if (!(test_if_locked & HA_OPEN_WAIT_IF_LOCKED))
+ (void) nisam_extra(file,HA_EXTRA_WAIT_LOCK);
+ if (!table->db_record_offset)
+ int_option_flag|=HA_REC_NOT_IN_SEQ;
+ return (0);
+}
+
+int ha_isam::close(void)
+{
+ return !nisam_close(file) ? 0 : my_errno ? my_errno : -1;
+}
+
+uint ha_isam::min_record_length(uint options) const
+{
+ return (options & HA_OPTION_PACK_RECORD) ? 1 : 5;
+}
+
+
+int ha_isam::write_row(byte * buf)
+{
+ statistic_increment(ha_write_count,&LOCK_status);
+ if (table->time_stamp)
+ update_timestamp(buf+table->time_stamp-1);
+ if (table->next_number_field && buf == table->record[0])
+ update_auto_increment();
+ return !nisam_write(file,buf) ? 0 : my_errno ? my_errno : -1;
+}
+
+int ha_isam::update_row(const byte * old_data, byte * new_data)
+{
+ statistic_increment(ha_update_count,&LOCK_status);
+ if (table->time_stamp)
+ update_timestamp(new_data+table->time_stamp-1);
+ return !nisam_update(file,old_data,new_data) ? 0 : my_errno ? my_errno : -1;
+}
+
+int ha_isam::delete_row(const byte * buf)
+{
+ statistic_increment(ha_delete_count,&LOCK_status);
+ return !nisam_delete(file,buf) ? 0 : my_errno ? my_errno : -1;
+}
+
+int ha_isam::index_read(byte * buf, const byte * key,
+ uint key_len, enum ha_rkey_function find_flag)
+{
+ statistic_increment(ha_read_key_count,&LOCK_status);
+ int error=nisam_rkey(file, buf, active_index, key, key_len, find_flag);
+ table->status=error ? STATUS_NOT_FOUND: 0;
+ return !error ? 0 : my_errno ? my_errno : -1;
+}
+
+int ha_isam::index_read_idx(byte * buf, uint index, const byte * key,
+ uint key_len, enum ha_rkey_function find_flag)
+{
+ statistic_increment(ha_read_key_count,&LOCK_status);
+ int error=nisam_rkey(file, buf, index, key, key_len, find_flag);
+ table->status=error ? STATUS_NOT_FOUND: 0;
+ return !error ? 0 : my_errno ? my_errno : -1;
+}
+
+int ha_isam::index_next(byte * buf)
+{
+ statistic_increment(ha_read_next_count,&LOCK_status);
+ int error=nisam_rnext(file,buf,active_index);
+ table->status=error ? STATUS_NOT_FOUND: 0;
+ return !error ? 0 : my_errno ? my_errno : HA_ERR_END_OF_FILE;
+}
+
+int ha_isam::index_prev(byte * buf)
+{
+ statistic_increment(ha_read_prev_count,&LOCK_status);
+ int error=nisam_rprev(file,buf, active_index);
+ table->status=error ? STATUS_NOT_FOUND: 0;
+ return !error ? 0 : my_errno ? my_errno : HA_ERR_END_OF_FILE;
+}
+
+int ha_isam::index_first(byte * buf)
+{
+ statistic_increment(ha_read_first_count,&LOCK_status);
+ int error=nisam_rfirst(file, buf, active_index);
+ table->status=error ? STATUS_NOT_FOUND: 0;
+ return !error ? 0 : my_errno ? my_errno : HA_ERR_END_OF_FILE;
+}
+
+int ha_isam::index_last(byte * buf)
+{
+ statistic_increment(ha_read_last_count,&LOCK_status);
+ int error=nisam_rlast(file, buf, active_index);
+ table->status=error ? STATUS_NOT_FOUND: 0;
+ return !error ? 0 : my_errno ? my_errno : HA_ERR_END_OF_FILE;
+}
+
+int ha_isam::rnd_init(bool scan)
+{
+ return nisam_extra(file,HA_EXTRA_RESET) ? 0 : my_errno ? my_errno : -1;;
+}
+
+int ha_isam::rnd_next(byte *buf)
+{
+ statistic_increment(ha_read_rnd_next_count,&LOCK_status);
+ int error=nisam_rrnd(file, buf, NI_POS_ERROR);
+ table->status=error ? STATUS_NOT_FOUND: 0;
+ return !error ? 0 : my_errno ? my_errno : -1;
+}
+
+int ha_isam::rnd_pos(byte * buf, byte *pos)
+{
+ statistic_increment(ha_read_rnd_count,&LOCK_status);
+ int error=nisam_rrnd(file, buf, (ulong) ha_get_ptr(pos,ref_length));
+ table->status=error ? STATUS_NOT_FOUND: 0;
+ return !error ? 0 : my_errno ? my_errno : -1;
+}
+
+void ha_isam::position(const byte *record)
+{
+ my_off_t position=nisam_position(file);
+ if (position == (my_off_t) ~ (ulong) 0)
+ position=HA_OFFSET_ERROR;
+ ha_store_ptr(ref, ref_length, position);
+}
+
+void ha_isam::info(uint flag)
+{
+ N_ISAMINFO info;
+ (void) nisam_info(file,&info,flag);
+ if (flag & HA_STATUS_VARIABLE)
+ {
+ records = info.records;
+ deleted = info.deleted;
+ data_file_length=info.data_file_length;
+ index_file_length=info.index_file_length;
+ delete_length = info.delete_length;
+ check_time = info.isamchk_time;
+ mean_rec_length=info.mean_reclength;
+ }
+ if (flag & HA_STATUS_CONST)
+ {
+ max_data_file_length=info.max_data_file_length;
+ max_index_file_length=info.max_index_file_length;
+ create_time = info.create_time;
+ sortkey = info.sortkey;
+ block_size=nisam_block_size;
+ table->keys = min(table->keys,info.keys);
+ table->keys_in_use= (((key_map) 1) << table->keys)- (key_map) 1;
+ table->db_options_in_use= info.options;
+ table->db_record_offset=
+ (table->db_options_in_use &
+ (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)) ? 0 :
+ table->reclength;
+ if (!table->tmp_table)
+ {
+ ulong *rec_per_key=info.rec_per_key;
+ for (uint i=0 ; i < table->keys ; i++)
+ {
+ table->key_info[i].rec_per_key[table->key_info[i].key_parts-1]=
+ *(rec_per_key++);
+ }
+ }
+ ref_length=4;
+ }
+ if (flag & HA_STATUS_ERRKEY)
+ {
+ errkey = info.errkey;
+ ha_store_ptr(dupp_ref, ref_length, info.dupp_key_pos);
+ }
+ if (flag & HA_STATUS_TIME)
+ update_time = info.update_time;
+}
+
+
+int ha_isam::extra(enum ha_extra_function operation)
+{
+ if ((specialflag & SPECIAL_SAFE_MODE || test_flags & TEST_NO_EXTRA) &&
+ (operation == HA_EXTRA_WRITE_CACHE ||
+ operation == HA_EXTRA_KEYREAD))
+ return 0;
+ return nisam_extra(file,operation);
+}
+
+int ha_isam::reset(void)
+{
+ return nisam_extra(file,HA_EXTRA_RESET);
+}
+
+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,
+ THR_LOCK_DATA **to,
+ enum thr_lock_type lock_type)
+{
+ if (lock_type != TL_IGNORE && file->lock.type == TL_UNLOCK)
+ file->lock.type=lock_type;
+ *to++= &file->lock;
+ return to;
+}
+
+
+int ha_isam::create(const char *name, register TABLE *form,
+ HA_CREATE_INFO *create_info)
+
+{
+ uint options=form->db_options_in_use;
+ int error;
+ uint i,j,recpos,minpos,fieldpos,temp_length,length;
+ enum ha_base_keytype type;
+ char buff[FN_REFLEN];
+ KEY *pos;
+ N_KEYDEF keydef[MAX_KEY];
+ N_RECINFO *recinfo,*recinfo_pos;
+ DBUG_ENTER("ha_isam::create");
+
+ type=HA_KEYTYPE_BINARY; // Keep compiler happy
+ if (!(recinfo= (N_RECINFO*) my_malloc((form->fields*2+2)*sizeof(N_RECINFO),
+ MYF(MY_WME))))
+ DBUG_RETURN(1);
+
+ pos=form->key_info;
+ for (i=0; i < form->keys ; i++, pos++)
+ {
+ keydef[i].base.flag= (pos->flags & HA_NOSAME);
+ for (j=0 ; (int7) j < pos->key_parts ; j++)
+ {
+ keydef[i].seg[j].base.flag=pos->key_part[j].key_part_flag;
+ Field *field=pos->key_part[j].field;
+ type=field->key_type();
+
+ if ((options & HA_OPTION_PACK_KEYS ||
+ (pos->flags & (HA_PACK_KEY | HA_BINARY_PACK_KEY |
+ HA_SPACE_PACK_USED))) &&
+ pos->key_part[j].length > 8 &&
+ (type == HA_KEYTYPE_TEXT ||
+ type == HA_KEYTYPE_NUM ||
+ (type == HA_KEYTYPE_BINARY && !field->zero_pack())))
+ {
+ if (j == 0)
+ keydef[i].base.flag|=HA_PACK_KEY;
+ if (!(field->flags & ZEROFILL_FLAG) &&
+ (field->type() == FIELD_TYPE_STRING ||
+ field->type() == FIELD_TYPE_VAR_STRING ||
+ ((int) (pos->key_part[j].length - field->decimals()))
+ >= 4))
+ keydef[i].seg[j].base.flag|=HA_SPACE_PACK;
+ }
+ keydef[i].seg[j].base.type=(int) type;
+ keydef[i].seg[j].base.start= pos->key_part[j].offset;
+ keydef[i].seg[j].base.length= pos->key_part[j].length;
+ }
+ keydef[i].seg[j].base.type=(int) HA_KEYTYPE_END; /* End of key-parts */
+ }
+
+ recpos=0; recinfo_pos=recinfo;
+ while (recpos < (uint) form->reclength)
+ {
+ Field **field,*found=0;
+ minpos=form->reclength; length=0;
+
+ for (field=form->field ; *field ; field++)
+ {
+ if ((fieldpos=(*field)->offset()) >= recpos &&
+ fieldpos <= minpos)
+ {
+ /* skip null fields */
+ if (!(temp_length= (*field)->pack_length()))
+ continue; /* Skipp null-fields */
+ if (! found || fieldpos < minpos ||
+ (fieldpos == minpos && temp_length < length))
+ {
+ minpos=fieldpos; found= *field; length=temp_length;
+ }
+ }
+ }
+ DBUG_PRINT("loop",("found: %lx recpos: %d minpos: %d length: %d",
+ found,recpos,minpos,length));
+ if (recpos != minpos)
+ { // Reserved space (Null bits?)
+ recinfo_pos->base.type=(int) FIELD_NORMAL;
+ recinfo_pos++->base.length= (uint16) (minpos-recpos);
+ }
+ if (! found)
+ break;
+
+ if (found->flags & BLOB_FLAG)
+ {
+ /* ISAM can only handle blob pointers of sizeof(char(*)) */
+ recinfo_pos->base.type= (int) FIELD_BLOB;
+ if (options & HA_OPTION_LONG_BLOB_PTR)
+ length= length-portable_sizeof_char_ptr+sizeof(char*);
+ }
+ else if (!(options & HA_OPTION_PACK_RECORD))
+ recinfo_pos->base.type= (int) FIELD_NORMAL;
+ else if (found->zero_pack())
+ recinfo_pos->base.type= (int) FIELD_SKIPP_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);
+ recinfo_pos++ ->base.length=(uint16) length;
+ recpos=minpos+length;
+ DBUG_PRINT("loop",("length: %d type: %d",
+ recinfo_pos[-1].base.length,recinfo_pos[-1].base.type));
+
+ if ((found->flags & BLOB_FLAG) && (options & HA_OPTION_LONG_BLOB_PTR) &&
+ sizeof(char*) != portable_sizeof_char_ptr)
+ { // Not used space
+ recinfo_pos->base.type=(int) FIELD_ZERO;
+ recinfo_pos++->base.length=
+ (uint16) (portable_sizeof_char_ptr-sizeof(char*));
+ recpos+= (portable_sizeof_char_ptr-sizeof(char*));
+ }
+ }
+ recinfo_pos->base.type= (int) FIELD_LAST; /* End of fieldinfo */
+ error=nisam_create(fn_format(buff,name,"","",2+4+16),form->keys,keydef,
+ recinfo,form->max_rows,form->min_rows,0,0,0L);
+ my_free((gptr) recinfo,MYF(0));
+ DBUG_RETURN(error);
+
+}
+
+
+ha_rows ha_isam::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)
+{
+ return (ha_rows) nisam_records_in_range(file,
+ inx,
+ start_key,start_key_len,
+ start_search_flag,
+ end_key,end_key_len,
+ end_search_flag);
+}
diff --git a/sql/ha_isam.h b/sql/ha_isam.h
new file mode 100644
index 00000000000..440f029451f
--- /dev/null
+++ b/sql/ha_isam.h
@@ -0,0 +1,87 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+
+#ifdef __GNUC__
+#pragma interface /* gcc class implementation */
+#endif
+
+/* class for the the myisam handler */
+
+#include <nisam.h>
+
+class ha_isam: public handler
+{
+ N_INFO *file;
+ uint int_option_flag;
+
+ public:
+ ha_isam(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_HAVE_KEY_READ_ONLY+HA_READ_NOT_EXACT_KEY+
+ HA_LONGLONG_KEYS+HA_KEY_READ_WRONG_STR + HA_DUPP_POS)
+ {}
+ ~ha_isam() {}
+ const char *table_type() const { return "ISAM"; }
+ 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 N_MAXKEY; }
+ uint max_key_parts() const { return N_MAXKEY_SEG; }
+ uint max_key_length() const { return N_MAX_KEY_LENGTH; }
+ uint min_record_length(uint options) const;
+ bool low_byte_first() const { return 0; }
+
+ int open(const char *name, int mode, int test_if_locked);
+ int close(void);
+ int write_row(byte * buf);
+ int update_row(const byte * old_data, byte * new_data);
+ int delete_row(const byte * buf);
+ int index_read(byte * buf, const byte * key,
+ uint key_len, enum ha_rkey_function find_flag);
+ int index_read_idx(byte * buf, uint idx, const byte * key,
+ uint key_len, enum ha_rkey_function find_flag);
+ int index_next(byte * buf);
+ int index_prev(byte * buf);
+ int index_first(byte * buf);
+ int index_last(byte * buf);
+ int rnd_init(bool scan=1);
+ int rnd_next(byte *buf);
+ int rnd_pos(byte * buf, byte *pos);
+ void position(const byte *record);
+ my_off_t row_position() { return nisam_position(file); }
+ void info(uint);
+ int extra(enum ha_extra_function operation);
+ int reset(void);
+ int external_lock(THD *thd, int lock_type);
+ ha_rows records_in_range(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);
+
+ int create(const char *name, TABLE *form, HA_CREATE_INFO *create_info);
+ THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to,
+ enum thr_lock_type lock_type);
+
+};
+
+
+
+
+
+
diff --git a/sql/ha_isammrg.cc b/sql/ha_isammrg.cc
new file mode 100644
index 00000000000..66e310b5256
--- /dev/null
+++ b/sql/ha_isammrg.cc
@@ -0,0 +1,210 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+
+#ifdef __GNUC__
+#pragma implementation // gcc: Class implementation
+#endif
+
+#include "mysql_priv.h"
+#include <m_ctype.h>
+#ifndef MASTER
+#include "../srclib/merge/mrgdef.h"
+#else
+#include "../merge/mrgdef.h"
+#endif
+#include "ha_isammrg.h"
+
+/*****************************************************************************
+** ISAM MERGE tables
+*****************************************************************************/
+
+const char **ha_isammrg::bas_ext() const
+{ static const char *ext[]= { ".MRG", NullS }; return ext; }
+
+int ha_isammrg::open(const char *name, int mode, int test_if_locked)
+{
+ char name_buff[FN_REFLEN];
+ if (!(file=mrg_open(fn_format(name_buff,name,"","",2 | 4), mode,
+ test_if_locked)))
+ return (my_errno ? my_errno : -1);
+
+ if (!(test_if_locked == HA_OPEN_WAIT_IF_LOCKED ||
+ test_if_locked == HA_OPEN_ABORT_IF_LOCKED))
+ mrg_extra(file,HA_EXTRA_NO_WAIT_LOCK);
+ info(HA_STATUS_NO_LOCK | HA_STATUS_VARIABLE | HA_STATUS_CONST);
+ if (!(test_if_locked & HA_OPEN_WAIT_IF_LOCKED))
+ mrg_extra(file,HA_EXTRA_WAIT_LOCK);
+ if (table->reclength != mean_rec_length)
+ {
+ DBUG_PRINT("error",("reclength: %d mean_rec_length: %d",
+ table->reclength, mean_rec_length));
+ mrg_close(file);
+ file=0;
+ return ER_WRONG_MRG_TABLE;
+ }
+ return (0);
+}
+
+int ha_isammrg::close(void)
+{
+ return !mrg_close(file) ? 0 : my_errno ? my_errno : -1;
+}
+
+uint ha_isammrg::min_record_length(uint options) const
+{
+ return (options & HA_OPTION_PACK_RECORD) ? 1 : 5;
+}
+
+int ha_isammrg::write_row(byte * buf)
+{
+ return (my_errno=HA_ERR_WRONG_COMMAND);
+}
+
+int ha_isammrg::update_row(const byte * old_data, byte * new_data)
+{
+ statistic_increment(ha_update_count,&LOCK_status);
+ if (table->time_stamp)
+ update_timestamp(new_data+table->time_stamp-1);
+ return !mrg_update(file,old_data,new_data) ? 0 : my_errno ? my_errno : -1;
+}
+
+int ha_isammrg::delete_row(const byte * buf)
+{
+ statistic_increment(ha_delete_count,&LOCK_status);
+ return !mrg_delete(file,buf) ? 0 : my_errno ? my_errno : -1;
+}
+
+int ha_isammrg::index_read(byte * buf, const byte * key,
+ uint key_len, enum ha_rkey_function find_flag)
+{
+ return (my_errno=HA_ERR_WRONG_COMMAND);
+}
+
+int ha_isammrg::index_read_idx(byte * buf, uint index, const byte * key,
+ uint key_len, enum ha_rkey_function find_flag)
+{
+ return (my_errno=HA_ERR_WRONG_COMMAND);
+}
+
+int ha_isammrg::index_next(byte * buf)
+{
+ return (my_errno=HA_ERR_WRONG_COMMAND);
+}
+
+int ha_isammrg::index_prev(byte * buf)
+{
+ return (my_errno=HA_ERR_WRONG_COMMAND);
+}
+
+int ha_isammrg::index_first(byte * buf)
+{
+ return (my_errno=HA_ERR_WRONG_COMMAND);
+}
+
+int ha_isammrg::index_last(byte * buf)
+{
+ return (my_errno=HA_ERR_WRONG_COMMAND);
+}
+
+int ha_isammrg::rnd_init(bool scan)
+{
+ return !mrg_extra(file,HA_EXTRA_RESET) ? 0 : my_errno ? my_errno : -1;
+}
+
+int ha_isammrg::rnd_next(byte *buf)
+{
+ statistic_increment(ha_read_rnd_next_count,&LOCK_status);
+ int error=mrg_rrnd(file, buf, ~(mrg_off_t) 0);
+ table->status=error ? STATUS_NOT_FOUND: 0;
+ return !error ? 0 : my_errno ? my_errno : -1;
+}
+
+int ha_isammrg::rnd_pos(byte * buf, byte *pos)
+{
+ statistic_increment(ha_read_rnd_count,&LOCK_status);
+ int error=mrg_rrnd(file, buf, (ulong) ha_get_ptr(pos,ref_length));
+ table->status=error ? STATUS_NOT_FOUND: 0;
+ return !error ? 0 : my_errno ? my_errno : -1;
+}
+
+void ha_isammrg::position(const byte *record)
+{
+ ulong position= mrg_position(file);
+ ha_store_ptr(ref, ref_length, (my_off_t) position);
+}
+
+
+void ha_isammrg::info(uint flag)
+{
+ MERGE_INFO info;
+ (void) mrg_info(file,&info,flag);
+ records = (ha_rows) info.records;
+ deleted = (ha_rows) info.deleted;
+ data_file_length=info.data_file_length;
+ errkey = info.errkey;
+ table->keys_in_use=0; // No keys yet
+ table->db_options_in_use = info.options;
+ mean_rec_length=info.reclength;
+ block_size=0;
+ update_time=0;
+ ref_length=4; // Should be big enough
+}
+
+
+int ha_isammrg::extra(enum ha_extra_function operation)
+{
+ return !mrg_extra(file,operation) ? 0 : my_errno ? my_errno : -1;
+}
+
+int ha_isammrg::reset(void)
+{
+ return !mrg_extra(file,HA_EXTRA_RESET) ? 0 : my_errno ? my_errno : -1;
+}
+
+int ha_isammrg::external_lock(THD *thd, int lock_type)
+{
+ return !mrg_lock_database(file,lock_type) ? 0 : my_errno ? my_errno : -1;
+}
+
+uint ha_isammrg::lock_count(void) const
+{
+ return file->tables;
+}
+
+THR_LOCK_DATA **ha_isammrg::store_lock(THD *thd,
+ THR_LOCK_DATA **to,
+ enum thr_lock_type lock_type)
+{
+ MRG_TABLE *table;
+
+ for (table=file->open_tables ; table != file->end_table ; table++)
+ {
+ *(to++)= &table->table->lock;
+ if (lock_type != TL_IGNORE && table->table->lock.type == TL_UNLOCK)
+ table->table->lock.type=lock_type;
+ }
+ return to;
+}
+
+
+int ha_isammrg::create(const char *name, register TABLE *form,
+ HA_CREATE_INFO *create_info)
+
+{
+ char buff[FN_REFLEN];
+ return mrg_create(fn_format(buff,name,"","",2+4+16),0);
+}
diff --git a/sql/ha_isammrg.h b/sql/ha_isammrg.h
new file mode 100644
index 00000000000..9fe1984d76f
--- /dev/null
+++ b/sql/ha_isammrg.h
@@ -0,0 +1,69 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+
+#ifdef __GNUC__
+#pragma interface /* gcc class implementation */
+#endif
+
+/* class for the the myisam merge handler */
+
+#include <merge.h>
+
+class ha_isammrg: public handler
+{
+ MRG_INFO *file;
+
+ public:
+ ha_isammrg(TABLE *table): handler(table), file(0) {}
+ ~ha_isammrg() {}
+ const char *table_type() const { return "MRG_ISAM"; }
+ const char **bas_ext() const;
+ ulong option_flag() const { return HA_READ_RND_SAME+HA_KEYPOS_TO_RNDPOS+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; }
+ uint max_key_length() const { return 0; }
+ bool low_byte_first() const { return 0; }
+ uint min_record_length(uint options) const;
+
+ int open(const char *name, int mode, int test_if_locked);
+ int close(void);
+ int write_row(byte * buf);
+ int update_row(const byte * old_data, byte * new_data);
+ int delete_row(const byte * buf);
+ int index_read(byte * buf, const byte * key,
+ uint key_len, enum ha_rkey_function find_flag);
+ int index_read_idx(byte * buf, uint indx, const byte * key,
+ uint key_len, enum ha_rkey_function find_flag);
+ int index_next(byte * buf);
+ int index_prev(byte * buf);
+ int index_first(byte * buf);
+ int index_last(byte * buf);
+ int rnd_init(bool scan=1);
+ int rnd_next(byte *buf);
+ int rnd_pos(byte * buf, byte *pos);
+ void position(const byte *record);
+ my_off_t row_position() { return mrg_position(file); }
+ void info(uint);
+ int extra(enum ha_extra_function operation);
+ int reset(void);
+ int external_lock(THD *thd, int lock_type);
+ uint lock_count(void) const;
+ int create(const char *name, TABLE *form, HA_CREATE_INFO *create_info);
+ THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to,
+ enum thr_lock_type lock_type);
+};
diff --git a/sql/ha_myisam.cc b/sql/ha_myisam.cc
new file mode 100644
index 00000000000..513a5affcb2
--- /dev/null
+++ b/sql/ha_myisam.cc
@@ -0,0 +1,873 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+
+#ifdef __GNUC__
+#pragma implementation // gcc: Class implementation
+#endif
+
+#include "mysql_priv.h"
+#include <m_ctype.h>
+#include <myisampack.h>
+#include "ha_myisam.h"
+#include <stdarg.h>
+#ifndef MASTER
+#include "../srclib/myisam/myisamdef.h"
+#else
+#include "../myisam/myisamdef.h"
+#endif
+
+ulong myisam_sort_buffer_size;
+#if !defined(HAVE_PREAD)
+pthread_mutex_t THR_LOCK_keycache;
+#endif
+
+/*****************************************************************************
+** MyISAM tables
+*****************************************************************************/
+
+// collect errors printed by mi_check routines
+static void mi_check_print_msg(MI_CHECK *param, const char* msg_type,
+ const char *fmt, va_list args)
+{
+ THD* thd = (THD*)param->thd;
+ String* packet = &thd->packet;
+ packet->length(0);
+ char msgbuf[MI_MAX_MSG_BUF];
+ msgbuf[0] = 0;
+
+ my_vsnprintf(msgbuf, sizeof(msgbuf), fmt, args);
+ msgbuf[sizeof(msgbuf) - 1] = 0; // healthy paranoia
+
+ if (thd->net.vio == 0)
+ {
+ sql_print_error(msgbuf);
+ return;
+ }
+
+ net_store_data(packet, param->table_name);
+ net_store_data(packet, param->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()))
+ fprintf(stderr,
+ "Failed on my_net_write, writing to stderr instead: %s\n",
+ msgbuf);
+ return;
+}
+
+extern "C" {
+
+void mi_check_print_error(MI_CHECK *param, const char *fmt,...)
+{
+ param->error_printed|=1;
+ va_list args;
+ va_start(args, fmt);
+ mi_check_print_msg(param, "error", fmt, args);
+ va_end(args);
+}
+
+void mi_check_print_info(MI_CHECK *param, const char *fmt,...)
+{
+ va_list args;
+ va_start(args, fmt);
+ mi_check_print_msg(param, "info", fmt, args);
+ va_end(args);
+}
+
+void mi_check_print_warning(MI_CHECK *param, const char *fmt,...)
+{
+ param->warning_printed=1;
+ va_list args;
+ va_start(args, fmt);
+ mi_check_print_msg(param, "warning", fmt, args);
+ va_end(args);
+}
+
+}
+
+const char **ha_myisam::bas_ext() const
+{ static const char *ext[]= { ".MYD",".MYI", NullS }; return ext; }
+
+
+int ha_myisam::net_read_dump(NET* net)
+{
+ MYISAM_SHARE* share = file->s;
+ int data_fd = file->dfile;
+ int error = 0;
+
+ my_seek(data_fd, 0L, MY_SEEK_SET, MYF(MY_WME));
+ for(;;)
+ {
+ uint packet_len = my_net_read(net);
+ if (!packet_len)
+ break ; // end of file
+ if (packet_len == packet_error)
+ {
+ sql_print_error("ha_myisam::net_read_dump - read error ");
+ error= -1;
+ goto err;
+ }
+ if (my_write(data_fd, (byte*)net->read_pos, packet_len,
+ MYF(MY_WME|MY_FNABP)))
+ {
+ error = errno;
+ goto err;
+ }
+ }
+
+err:
+ return error;
+}
+
+
+int ha_myisam::dump(THD* thd, int fd)
+{
+ MYISAM_SHARE* share = file->s;
+ NET* net = &thd->net;
+ uint blocksize = share->blocksize;
+ my_off_t bytes_to_read = share->state.state.data_file_length;
+ int data_fd = file->dfile;
+ byte * buf = (byte*) my_malloc(blocksize, MYF(MY_WME));
+ if(!buf)
+ return ENOMEM;
+
+ int error = 0;
+ my_seek(data_fd, 0L, MY_SEEK_SET, MYF(MY_WME));
+ for(; bytes_to_read > 0;)
+ {
+ uint bytes = my_read(data_fd, buf, blocksize, MYF(MY_WME));
+ if (bytes == MY_FILE_ERROR)
+ {
+ error = errno;
+ goto err;
+ }
+
+ if (fd >= 0)
+ {
+ if (my_write(fd, buf, bytes, MYF(MY_WME | MY_FNABP)))
+ {
+ error = errno ? errno : EPIPE;
+ goto err;
+ }
+ }
+ else
+ {
+ if (my_net_write(net, (char*) buf, bytes))
+ {
+ error = errno ? errno : EPIPE;
+ goto err;
+ }
+ }
+ bytes_to_read -= bytes;
+ }
+
+ if (fd < 0)
+ {
+ my_net_write(net, "", 0);
+ net_flush(net);
+ }
+
+err:
+ my_free((gptr) buf, MYF(0));
+ return error;
+}
+
+int ha_myisam::open(const char *name, int mode, int test_if_locked)
+{
+ char name_buff[FN_REFLEN];
+ if (!(file=mi_open(fn_format(name_buff,name,"","",2 | 4), mode,
+ test_if_locked)))
+ return (my_errno ? my_errno : -1);
+
+ if (!(test_if_locked == HA_OPEN_WAIT_IF_LOCKED ||
+ test_if_locked == HA_OPEN_ABORT_IF_LOCKED))
+ VOID(mi_extra(file,HA_EXTRA_NO_WAIT_LOCK));
+ info(HA_STATUS_NO_LOCK | HA_STATUS_VARIABLE | HA_STATUS_CONST);
+ if (!(test_if_locked & HA_OPEN_WAIT_IF_LOCKED))
+ VOID(mi_extra(file,HA_EXTRA_WAIT_LOCK));
+ if (!table->db_record_offset)
+ int_option_flag|=HA_REC_NOT_IN_SEQ;
+ return (0);
+}
+
+int ha_myisam::close(void)
+{
+ MI_INFO *tmp=file;
+ file=0;
+ return mi_close(tmp);
+}
+
+int ha_myisam::write_row(byte * buf)
+{
+ 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])
+ update_auto_increment();
+ return mi_write(file,buf);
+}
+
+int ha_myisam::check(THD* thd, HA_CHECK_OPT* check_opt)
+{
+ if (!file) return HA_CHECK_INTERNAL_ERROR;
+ int error ;
+ MI_CHECK param;
+ MYISAM_SHARE* share = file->s;
+
+ myisamchk_init(&param);
+ param.thd = thd;
+ param.op_name = (char*)"check";
+ param.table_name = table->table_name;
+ param.testflag = check_opt->flags | T_CHECK | T_SILENT;
+ if (check_opt->quick)
+ param.testflag |= T_FAST;
+
+ if (!(table->db_stat & HA_READ_ONLY))
+ param.testflag|= T_STATISTICS;
+ param.using_global_keycache = 1;
+
+ error = chk_size(&param, file);
+ if (!((param.testflag & T_FAST) && share->state.open_count == 1 &&
+ !share->state.changed))
+ {
+ if (!error)
+ error |= chk_del(&param, file, param.testflag);
+ if (!error)
+ error = chk_key(&param, file);
+ if (!error)
+ {
+ if (!(param.testflag & T_FAST) ||
+ (share->options & (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)))
+ {
+ init_io_cache(&param.read_cache, file->dfile,
+ my_default_record_cache_size, READ_CACHE,
+ share->pack.header_length, 1, MYF(MY_WME));
+ error |= chk_data_link(&param, file, param.testflag & T_EXTEND);
+ end_io_cache(&(param.read_cache));
+ }
+ }
+ }
+ if (!error)
+ {
+ if (share->state.changed)
+ {
+ file->update|=HA_STATE_CHANGED | HA_STATE_ROW_CHANGED;
+ pthread_mutex_lock(&share->intern_lock);
+#ifndef HAVE_PREAD
+ pthread_mutex_lock(&THR_LOCK_keycache); // QQ; Has to be removed!
+#endif
+ share->state.changed=0;
+ if (!(table->db_stat & HA_READ_ONLY))
+ error=update_state_info(&param,file,UPDATE_TIME | UPDATE_OPEN_COUNT);
+#ifndef HAVE_PREAD
+ pthread_mutex_unlock(&THR_LOCK_keycache);// QQ; Has to be removed!
+#endif
+ pthread_mutex_unlock(&share->intern_lock);
+ }
+ }
+ else if (!mi_is_crashed(file))
+ {
+ mi_mark_crashed(file);
+ file->update |= HA_STATE_CHANGED | HA_STATE_ROW_CHANGED;
+ }
+
+ return error ? HA_CHECK_CORRUPT : HA_CHECK_OK;
+}
+
+
+/*
+ analyze the key distribution in the table
+ As the table may be only locked for read, we have to take into account that
+ two threads may do an analyze at the same time!
+*/
+
+int ha_myisam::analyze(THD *thd)
+{
+ int error;
+ MI_CHECK param;
+ MYISAM_SHARE* share = file->s;
+
+ myisamchk_init(&param);
+ param.thd = thd;
+ param.op_name = (char*)" analyze";
+ param.table_name = table->table_name;
+ param.testflag=(T_FAST | T_CHECK | T_SILENT | T_STATISTICS |
+ T_DONT_CHECK_CHECKSUM);
+ param.using_global_keycache = 1;
+
+ error = chk_key(&param, file);
+ if (!error)
+ {
+ pthread_mutex_lock(&share->intern_lock);
+#ifndef HAVE_PREAD
+ pthread_mutex_lock(&THR_LOCK_keycache); // QQ; Has to be removed!
+#endif
+ error=update_state_info(&param,file,UPDATE_STAT);
+#ifndef HAVE_PREAD
+ pthread_mutex_unlock(&THR_LOCK_keycache);// QQ; Has to be removed!
+#endif
+ pthread_mutex_unlock(&share->intern_lock);
+ }
+ else if (!mi_is_crashed(file))
+ mi_mark_crashed(file);
+ return error ? HA_CHECK_CORRUPT : HA_CHECK_OK;
+}
+
+
+int ha_myisam::repair(THD* thd, HA_CHECK_OPT* check_opt)
+{
+ if (!file) return HA_CHECK_INTERNAL_ERROR;
+ int error ;
+ MI_CHECK param;
+ MYISAM_SHARE* share = file->s;
+ char fixed_name[FN_REFLEN];
+
+ myisamchk_init(&param);
+ param.thd = thd;
+ param.op_name = (char*) "repair";
+ param.table_name = table->table_name;
+ param.testflag = check_opt->flags | T_SILENT|T_FORCE_CREATE|T_REP_BY_SORT;
+ param.sort_buffer_length= check_opt->sort_buffer_size;
+ if (check_opt->quick)
+ param.opt_rep_quick++;
+ param.tmpfile_createflag = O_RDWR | O_TRUNC;
+ param.using_global_keycache = 1;
+
+ VOID(fn_format(fixed_name,file->filename,"",MI_NAME_IEXT,
+ 4+ (param.opt_follow_links ? 16 : 0)));
+
+ if (share->state.key_map)
+ error = mi_repair_by_sort(&param, file, fixed_name, param.opt_rep_quick);
+ else
+ error= mi_repair(&param, file, fixed_name, param.opt_rep_quick);
+ if (!error)
+ {
+ if (share->state.changed)
+ {
+ share->state.changed = 0;
+ file->update|=HA_STATE_CHANGED | HA_STATE_ROW_CHANGED;
+ }
+ file->save_state=file->s->state.state;
+ if (file->s->base.auto_key)
+ update_auto_increment_key(&param, file, 1);
+ error = update_state_info(&param, file, UPDATE_TIME|UPDATE_STAT);
+ }
+ else if (!mi_is_crashed(file))
+ {
+ mi_mark_crashed(file);
+ file->update |= HA_STATE_CHANGED | HA_STATE_ROW_CHANGED;
+ }
+ if (!error)
+ {
+ if (param.out_flag & (O_NEW_DATA | O_NEW_INDEX))
+ {
+ /*
+ We have to close all instances of this file to ensure that we can
+ do the rename safely and that all threads are using the new version.
+ */
+ VOID(pthread_mutex_lock(&LOCK_open));
+ if (close_cached_table(thd,table))
+ error=1;
+
+ if (param.out_flag & O_NEW_DATA)
+ error|=change_to_newfile(fixed_name,MI_NAME_DEXT,
+ DATA_TMP_EXT, 0);
+
+ if (param.out_flag & O_NEW_INDEX)
+ error|=change_to_newfile(fixed_name,MI_NAME_IEXT,
+ INDEX_TMP_EXT,0);
+ VOID(pthread_mutex_unlock(&LOCK_open));
+ }
+ }
+ return error ? HA_REPAIR_FAILED : HA_REPAIR_OK;
+}
+
+
+
+int ha_myisam::update_row(const byte * old_data, byte * new_data)
+{
+ statistic_increment(ha_update_count,&LOCK_status);
+ if (table->time_stamp)
+ update_timestamp(new_data+table->time_stamp-1);
+ return mi_update(file,old_data,new_data);
+}
+
+int ha_myisam::delete_row(const byte * buf)
+{
+ statistic_increment(ha_delete_count,&LOCK_status);
+ return mi_delete(file,buf);
+}
+
+int ha_myisam::index_read(byte * buf, const byte * key,
+ uint key_len, enum ha_rkey_function find_flag)
+{
+ statistic_increment(ha_read_key_count,&LOCK_status);
+ int error=mi_rkey(file,buf,active_index, key, key_len, find_flag);
+ table->status=error ? STATUS_NOT_FOUND: 0;
+ return error;
+}
+
+int ha_myisam::index_read_idx(byte * buf, uint index, const byte * key,
+ uint key_len, enum ha_rkey_function find_flag)
+{
+ statistic_increment(ha_read_key_count,&LOCK_status);
+ int error=mi_rkey(file,buf,index, key, key_len, find_flag);
+ table->status=error ? STATUS_NOT_FOUND: 0;
+ return error;
+}
+
+int ha_myisam::index_next(byte * buf)
+{
+ statistic_increment(ha_read_next_count,&LOCK_status);
+ int error=mi_rnext(file,buf,active_index);
+ table->status=error ? STATUS_NOT_FOUND: 0;
+ return error;
+}
+
+int ha_myisam::index_prev(byte * buf)
+{
+ statistic_increment(ha_read_prev_count,&LOCK_status);
+ int error=mi_rprev(file,buf, active_index);
+ table->status=error ? STATUS_NOT_FOUND: 0;
+ return error;
+}
+
+int ha_myisam::index_first(byte * buf)
+{
+ statistic_increment(ha_read_first_count,&LOCK_status);
+ int error=mi_rfirst(file, buf, active_index);
+ table->status=error ? STATUS_NOT_FOUND: 0;
+ return error;
+}
+
+int ha_myisam::index_last(byte * buf)
+{
+ statistic_increment(ha_read_last_count,&LOCK_status);
+ int error=mi_rlast(file, buf, active_index);
+ table->status=error ? STATUS_NOT_FOUND: 0;
+ return error;
+}
+
+int ha_myisam::index_next_same(byte * buf,
+ const byte *key __attribute__((unused)),
+ uint length __attribute__((unused)))
+{
+ statistic_increment(ha_read_next_count,&LOCK_status);
+ int error=mi_rnext_same(file,buf);
+ table->status=error ? STATUS_NOT_FOUND: 0;
+ return error;
+}
+
+
+int ha_myisam::rnd_init(bool scan)
+{
+ if (scan)
+ return mi_scan_init(file);
+ else
+ return mi_extra(file,HA_EXTRA_RESET);
+}
+
+int ha_myisam::rnd_next(byte *buf)
+{
+ statistic_increment(ha_read_rnd_next_count,&LOCK_status);
+ int error=mi_scan(file, buf);
+ table->status=error ? STATUS_NOT_FOUND: 0;
+ return error;
+}
+
+int ha_myisam::restart_rnd_next(byte *buf, byte *pos)
+{
+ return rnd_pos(buf,pos);
+}
+
+int ha_myisam::rnd_pos(byte * buf, byte *pos)
+{
+ statistic_increment(ha_read_rnd_count,&LOCK_status);
+ int error=mi_rrnd(file, buf, ha_get_ptr(pos,ref_length));
+ table->status=error ? STATUS_NOT_FOUND: 0;
+ return error;
+}
+
+void ha_myisam::position(const byte* record)
+{
+ my_off_t position=mi_position(file);
+ ha_store_ptr(ref, ref_length, position);
+}
+
+void ha_myisam::info(uint flag)
+{
+ MI_ISAMINFO info;
+ (void) mi_status(file,&info,flag);
+ if (flag & HA_STATUS_VARIABLE)
+ {
+ records = info.records;
+ deleted = info.deleted;
+ data_file_length=info.data_file_length;
+ index_file_length=info.index_file_length;
+ delete_length = info.delete_length;
+ check_time = info.check_time;
+ mean_rec_length=info.mean_reclength;
+ }
+ if (flag & HA_STATUS_CONST)
+ {
+ max_data_file_length=info.max_data_file_length;
+ max_index_file_length=info.max_index_file_length;
+ create_time = info.create_time;
+ sortkey = info.sortkey;
+ ref_length=info.reflength;
+ table->db_options_in_use = info.options;
+ block_size=myisam_block_size;
+ table->keys_in_use &= info.key_map;
+ table->db_record_offset=info.record_offset;
+ if (table->key_parts)
+ memcpy((char*) table->key_info[0].rec_per_key,
+ (char*) info.rec_per_key,
+ sizeof(ulong)*table->key_parts);
+ raid_type=info.raid_type;
+ raid_chunks=info.raid_chunks;
+ raid_chunksize=info.raid_chunksize;
+ }
+ if (flag & HA_STATUS_ERRKEY)
+ {
+ errkey = info.errkey;
+ ha_store_ptr(dupp_ref, ref_length, info.dupp_key_pos);
+ }
+ if (flag & HA_STATUS_TIME)
+ update_time = info.update_time;
+ if (flag & HA_STATUS_AUTO)
+ auto_increment_value= info.auto_increment;
+}
+
+
+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))
+ return 0;
+ return mi_extra(file,operation);
+}
+
+int ha_myisam::reset(void)
+{
+ return mi_extra(file,HA_EXTRA_RESET);
+}
+
+int ha_myisam::delete_all_rows()
+{
+ return mi_delete_all_rows(file);
+}
+
+int ha_myisam::delete_table(const char *name)
+{
+ return mi_delete_table(name);
+}
+
+int ha_myisam::external_lock(THD *thd, int lock_type)
+{
+ return mi_lock_database(file,lock_type);
+}
+
+
+THR_LOCK_DATA **ha_myisam::store_lock(THD *thd,
+ THR_LOCK_DATA **to,
+ enum thr_lock_type lock_type)
+{
+ if (lock_type != TL_IGNORE && file->lock.type == TL_UNLOCK)
+ file->lock.type=lock_type;
+ *to++= &file->lock;
+ return to;
+}
+
+void ha_myisam::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;
+ }
+ if (!(create_info->used_fields & HA_CREATE_USED_RAID))
+ {
+ create_info->raid_type= raid_type;
+ create_info->raid_chunks= raid_chunks;
+ create_info->raid_chunksize= raid_chunksize;
+ }
+}
+
+
+int ha_myisam::create(const char *name, register TABLE *form,
+ HA_CREATE_INFO *info)
+{
+ int error;
+ uint i,j,recpos,minpos,fieldpos,temp_length,length;
+ bool found_auto_increment=0;
+ enum ha_base_keytype type;
+ char buff[FN_REFLEN];
+ KEY *pos;
+ MI_KEYDEF *keydef;
+ MI_COLUMNDEF *recinfo,*recinfo_pos;
+ MI_KEYSEG *keyseg;
+ uint options=form->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),
+ &keyseg,
+ ((form->key_parts + form->keys) * sizeof(MI_KEYSEG)),
+ 0)))
+ DBUG_RETURN(1);
+
+ pos=form->key_info;
+ for (i=0; i < form->keys ; i++, pos++)
+ {
+ keydef[i].flag= (pos->flags & (HA_NOSAME | HA_FULLTEXT));
+ keydef[i].seg=keyseg;
+ keydef[i].keysegs=pos->key_parts;
+ for (j=0 ; j < pos->key_parts ; j++)
+ {
+ keydef[i].seg[j].flag=pos->key_part[j].key_part_flag;
+ Field *field=pos->key_part[j].field;
+ type=field->key_type();
+
+ if (options & HA_OPTION_PACK_KEYS ||
+ (pos->flags & (HA_PACK_KEY | HA_BINARY_PACK_KEY |
+ HA_SPACE_PACK_USED)))
+ {
+ if (pos->key_part[j].length > 8 &&
+ (type == HA_KEYTYPE_TEXT ||
+ type == HA_KEYTYPE_NUM ||
+ (type == HA_KEYTYPE_BINARY && !field->zero_pack())))
+ {
+ /* No blobs here */
+ if (j == 0)
+ keydef[i].flag|=HA_PACK_KEY;
+ if (!(field->flags & ZEROFILL_FLAG) &&
+ (field->type() == FIELD_TYPE_STRING ||
+ field->type() == FIELD_TYPE_VAR_STRING ||
+ ((int) (pos->key_part[j].length - field->decimals()))
+ >= 4))
+ keydef[i].seg[j].flag|=HA_SPACE_PACK;
+ }
+ else if (j == 0 && (!(pos->flags & HA_NOSAME) || pos->key_length > 16))
+ keydef[i].flag|= HA_BINARY_PACK_KEY;
+ }
+ keydef[i].seg[j].type= (int) type;
+ keydef[i].seg[j].start= pos->key_part[j].offset;
+ keydef[i].seg[j].length= pos->key_part[j].length;
+ keydef[i].seg[j].bit_start=keydef[i].seg[j].bit_end=0;
+ keydef[i].seg[j].language=MY_CHARSET_CURRENT;
+
+ if (field->null_ptr)
+ {
+ keydef[i].seg[j].null_bit=field->null_bit;
+ keydef[i].seg[j].null_pos= (uint) (field->null_ptr-
+ (uchar*) form->record[0]);
+ }
+ else
+ {
+ keydef[i].seg[j].null_bit=0;
+ keydef[i].seg[j].null_pos=0;
+ }
+ if (j == 0 && field->flags & AUTO_INCREMENT_FLAG &&
+ !found_auto_increment)
+ {
+ keydef[i].flag|=HA_AUTO_KEY;
+ found_auto_increment=1;
+ }
+ if (field->type() == FIELD_TYPE_BLOB)
+ {
+ 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);
+ }
+ }
+ keyseg+=pos->key_parts;
+ }
+
+ recpos=0; recinfo_pos=recinfo;
+ while (recpos < (uint) form->reclength)
+ {
+ Field **field,*found=0;
+ minpos=form->reclength; length=0;
+
+ for (field=form->field ; *field ; field++)
+ {
+ if ((fieldpos=(*field)->offset()) >= recpos &&
+ fieldpos <= minpos)
+ {
+ /* skip null fields */
+ if (!(temp_length= (*field)->pack_length()))
+ continue; /* Skipp null-fields */
+ if (! found || fieldpos < minpos ||
+ (fieldpos == minpos && temp_length < length))
+ {
+ minpos=fieldpos; found= *field; length=temp_length;
+ }
+ }
+ }
+ DBUG_PRINT("loop",("found: %lx recpos: %d minpos: %d length: %d",
+ found,recpos,minpos,length));
+ if (recpos != minpos)
+ { // Reserved space (Null bits?)
+ bzero((char*) recinfo_pos,sizeof(*recinfo_pos));
+ recinfo_pos->type=(int) FIELD_NORMAL;
+ recinfo_pos++->length= (uint16) (minpos-recpos);
+ }
+ if (! found)
+ break;
+
+ if (found->flags & BLOB_FLAG)
+ {
+ recinfo_pos->type= (int) FIELD_BLOB;
+ }
+ 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;
+ 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);
+ if (found->null_ptr)
+ {
+ recinfo_pos->null_bit=found->null_bit;
+ recinfo_pos->null_pos= (uint) (found->null_ptr-
+ (uchar*) form->record[0]);
+ }
+ else
+ {
+ recinfo_pos->null_bit=0;
+ recinfo_pos->null_pos=0;
+ }
+ (recinfo_pos++) ->length=(uint16) length;
+ recpos=minpos+length;
+ DBUG_PRINT("loop",("length: %d type: %d",
+ recinfo_pos[-1].length,recinfo_pos[-1].type));
+
+ }
+ 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.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.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,
+ (uint) (recinfo_pos-recinfo), recinfo,
+ 0, (MI_UNIQUEDEF*) 0,
+ &create_info,
+ (((options & HA_OPTION_PACK_RECORD) ? HA_PACK_RECORD : 0) |
+ ((options & HA_OPTION_CHECKSUM) ? HA_CREATE_CHECKSUM : 0) |
+ ((options & HA_OPTION_DELAY_KEY_WRITE) ?
+ HA_CREATE_DELAY_KEY_WRITE : 0)));
+
+
+ my_free((gptr) recinfo,MYF(0));
+ DBUG_RETURN(error);
+}
+
+
+int ha_myisam::rename_table(const char * from, const char * to)
+{
+ return mi_rename(from,to);
+}
+
+
+longlong ha_myisam::get_auto_increment()
+{
+ if (!table->next_number_key_offset)
+ { // Autoincrement at key-start
+ ha_myisam::info(HA_STATUS_AUTO);
+ return auto_increment_value;
+ }
+
+ longlong nr;
+ int error;
+ byte key[MAX_KEY_LENGTH];
+ (void) extra(HA_EXTRA_KEYREAD);
+ key_copy(key,table,table->next_number_index,
+ table->next_number_key_offset);
+ error=mi_rkey(file,table->record[1],(int) table->next_number_index,
+ key,table->next_number_key_offset,HA_READ_PREFIX_LAST);
+ if (error)
+ nr=1;
+ else
+ nr=(longlong)
+ table->next_number_field->val_int_offset(table->rec_buff_length)+1;
+ extra(HA_EXTRA_NO_KEYREAD);
+ return nr;
+}
+
+
+ha_rows ha_myisam::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)
+{
+ return (ha_rows) mi_records_in_range(file,
+ inx,
+ start_key,start_key_len,
+ start_search_flag,
+ end_key,end_key_len,
+ end_search_flag);
+}
+
+int ha_myisam::ft_init(uint inx, const byte *key, uint keylen, bool presort)
+{
+ if (ft_handler)
+ return -1;
+
+ // Do the search!
+ ft_handler=ft_init_search(file,inx,(byte*) key,keylen,presort);
+
+ if (!ft_handler)
+ return (my_errno ? my_errno : -1);
+
+ return 0;
+}
+
+int ha_myisam::ft_read(byte * buf)
+{
+ int error;
+
+ thread_safe_increment(ha_read_next_count,&LOCK_status); // why ?
+ if (ft_handler)
+ ft_relevance=ft_read_next((FT_DOCLIST *) ft_handler,(char*) buf);
+ else
+ ft_relevance=0;
+
+ error=((ft_relevance == 0) ? HA_ERR_END_OF_FILE :
+ (ft_relevance > 0) ? 0 :
+ (int) -ft_relevance);
+ table->status=error ? STATUS_NOT_FOUND: 0;
+ return error;
+}
+
diff --git a/sql/ha_myisam.h b/sql/ha_myisam.h
new file mode 100644
index 00000000000..a25711d720b
--- /dev/null
+++ b/sql/ha_myisam.h
@@ -0,0 +1,96 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+
+#ifdef __GNUC__
+#pragma interface /* gcc class implementation */
+#endif
+
+/* class for the the myisam handler */
+
+#include <myisam.h>
+#include <ft_global.h>
+
+extern ulong myisam_sort_buffer_size;
+
+class ha_myisam: public handler
+{
+ MI_INFO *file;
+ uint int_option_flag;
+
+ 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_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_myisam() { ft_close(); }
+ const char *table_type() const { return "MyISAM"; }
+ 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 1; }
+ uint max_key_parts() const { return MAX_REF_PARTS; }
+ uint max_key_length() const { return MAX_KEY_LENGTH; }
+
+ int open(const char *name, int mode, int test_if_locked);
+ int close(void);
+ int write_row(byte * buf);
+ int update_row(const byte * old_data, byte * new_data);
+ int delete_row(const byte * buf);
+ int index_read(byte * buf, const byte * key,
+ uint key_len, enum ha_rkey_function find_flag);
+ int index_read_idx(byte * buf, uint idx, const byte * key,
+ uint key_len, enum ha_rkey_function find_flag);
+ int index_next(byte * buf);
+ int index_prev(byte * buf);
+ int index_first(byte * buf);
+ int index_last(byte * buf);
+ int index_next_same(byte *buf, const byte *key, uint keylen);
+ int ft_init(uint inx,const byte *key, uint keylen, bool presort);
+ int ft_read(byte *buf);
+ int ft_close() { if(ft_handler) ft_close_search(ft_handler); ft_handler=0; return 0;}
+ int rnd_init(bool scan=1);
+ int rnd_next(byte *buf);
+ int rnd_pos(byte * buf, byte *pos);
+ int restart_rnd_next(byte *buf, byte *pos);
+ void position(const byte *record);
+ my_off_t row_position() { return mi_position(file); }
+ void info(uint);
+ int extra(enum ha_extra_function operation);
+ int reset(void);
+ int external_lock(THD *thd, int lock_type);
+ int delete_all_rows(void);
+ 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, TABLE *form, HA_CREATE_INFO *create_info);
+ THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to,
+ enum thr_lock_type lock_type);
+ longlong get_auto_increment();
+ int rename_table(const char * from, const char * to);
+ int delete_table(const char *name);
+ int check(THD* thd, HA_CHECK_OPT* check_opt);
+ int analyze(THD* thd);
+ int repair(THD* thd, HA_CHECK_OPT* check_opt);
+ int dump(THD* thd, int fd);
+ int net_read_dump(NET* net);
+};
diff --git a/sql/ha_myisammrg.cc b/sql/ha_myisammrg.cc
new file mode 100644
index 00000000000..f43dd901e1f
--- /dev/null
+++ b/sql/ha_myisammrg.cc
@@ -0,0 +1,209 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+
+#ifdef __GNUC__
+#pragma implementation // gcc: Class implementation
+#endif
+
+#include "mysql_priv.h"
+#include <m_ctype.h>
+#include "ha_myisammrg.h"
+#ifndef MASTER
+#include "../srclib/myisammrg/mymrgdef.h"
+#else
+#include "../myisammrg/mymrgdef.h"
+#endif
+
+/*****************************************************************************
+** MyISAM MERGE tables
+*****************************************************************************/
+
+const char **ha_myisammrg::bas_ext() const
+{ static const char *ext[]= { ".MRG", NullS }; return ext; }
+
+int ha_myisammrg::open(const char *name, int mode, int test_if_locked)
+{
+ char name_buff[FN_REFLEN];
+ if (!(file=myrg_open(fn_format(name_buff,name,"","",2 | 4), mode,
+ test_if_locked)))
+ return (my_errno ? my_errno : -1);
+
+ if (!(test_if_locked == HA_OPEN_WAIT_IF_LOCKED ||
+ test_if_locked == HA_OPEN_ABORT_IF_LOCKED))
+ myrg_extra(file,HA_EXTRA_NO_WAIT_LOCK);
+ info(HA_STATUS_NO_LOCK | HA_STATUS_VARIABLE | HA_STATUS_CONST);
+ if (!(test_if_locked & HA_OPEN_WAIT_IF_LOCKED))
+ myrg_extra(file,HA_EXTRA_WAIT_LOCK);
+ if (table->reclength != mean_rec_length)
+ {
+ DBUG_PRINT("error",("reclength: %d mean_rec_length: %d",
+ table->reclength, mean_rec_length));
+ myrg_close(file);
+ file=0;
+ return my_errno=HA_ERR_WRONG_TABLE_DEF;
+ }
+ return (0);
+}
+
+int ha_myisammrg::close(void)
+{
+ return myrg_close(file);
+}
+
+int ha_myisammrg::write_row(byte * buf)
+{
+ return (my_errno=HA_ERR_WRONG_COMMAND);
+}
+
+int ha_myisammrg::update_row(const byte * old_data, byte * new_data)
+{
+ statistic_increment(ha_update_count,&LOCK_status);
+ if (table->time_stamp)
+ update_timestamp(new_data+table->time_stamp-1);
+ return myrg_update(file,old_data,new_data);
+}
+
+int ha_myisammrg::delete_row(const byte * buf)
+{
+ statistic_increment(ha_delete_count,&LOCK_status);
+ return myrg_delete(file,buf);
+}
+
+int ha_myisammrg::index_read(byte * buf, const byte * key,
+ uint key_len, enum ha_rkey_function find_flag)
+{
+ return (my_errno=HA_ERR_WRONG_COMMAND);
+}
+
+int ha_myisammrg::index_read_idx(byte * buf, uint index, const byte * key,
+ uint key_len, enum ha_rkey_function find_flag)
+{
+ return (my_errno=HA_ERR_WRONG_COMMAND);
+}
+
+int ha_myisammrg::index_next(byte * buf)
+{
+ return (my_errno=HA_ERR_WRONG_COMMAND);
+}
+
+int ha_myisammrg::index_prev(byte * buf)
+{
+ return (my_errno=HA_ERR_WRONG_COMMAND);
+}
+
+int ha_myisammrg::index_first(byte * buf)
+{
+ return (my_errno=HA_ERR_WRONG_COMMAND);
+}
+
+int ha_myisammrg::index_last(byte * buf)
+{
+ return (my_errno=HA_ERR_WRONG_COMMAND);
+}
+
+int ha_myisammrg::rnd_init(bool scan)
+{
+ return myrg_extra(file,HA_EXTRA_RESET);
+}
+
+int ha_myisammrg::rnd_next(byte *buf)
+{
+ statistic_increment(ha_read_rnd_next_count,&LOCK_status);
+ int error=myrg_rrnd(file, buf, HA_OFFSET_ERROR);
+ table->status=error ? STATUS_NOT_FOUND: 0;
+ return error;
+}
+
+int ha_myisammrg::rnd_pos(byte * buf, byte *pos)
+{
+ statistic_increment(ha_read_rnd_count,&LOCK_status);
+ int error=myrg_rrnd(file, buf, ha_get_ptr(pos,ref_length));
+ table->status=error ? STATUS_NOT_FOUND: 0;
+ return error;
+}
+
+void ha_myisammrg::position(const byte *record)
+{
+ ulonglong position= myrg_position(file);
+ ha_store_ptr(ref, ref_length, (my_off_t) position);
+}
+
+
+void ha_myisammrg::info(uint flag)
+{
+ MYMERGE_INFO info;
+ (void) myrg_status(file,&info,flag);
+ records = (ha_rows) info.records;
+ deleted = (ha_rows) info.deleted;
+ data_file_length=info.data_file_length;
+ errkey = info.errkey;
+ table->keys_in_use=0; // No keys yet
+ table->db_options_in_use = info.options;
+ mean_rec_length=info.reclength;
+ block_size=0;
+ update_time=0;
+#if SIZEOF_OFF_T > 4
+ ref_length=6; // Should be big enough
+#else
+ ref_length=4;
+#endif
+}
+
+
+int ha_myisammrg::extra(enum ha_extra_function operation)
+{
+ return myrg_extra(file,operation);
+}
+
+int ha_myisammrg::reset(void)
+{
+ return myrg_extra(file,HA_EXTRA_RESET);
+}
+
+int ha_myisammrg::external_lock(THD *thd, int lock_type)
+{
+ return myrg_lock_database(file,lock_type);
+}
+
+uint ha_myisammrg::lock_count(void) const
+{
+ return file->tables;
+}
+
+
+THR_LOCK_DATA **ha_myisammrg::store_lock(THD *thd,
+ THR_LOCK_DATA **to,
+ enum thr_lock_type lock_type)
+{
+ MYRG_TABLE *table;
+
+ for (table=file->open_tables ; table != file->end_table ; table++)
+ {
+ *(to++)= &table->table->lock;
+ if (lock_type != TL_IGNORE && table->table->lock.type == TL_UNLOCK)
+ table->table->lock.type=lock_type;
+ }
+ return to;
+}
+
+
+int ha_myisammrg::create(const char *name, register TABLE *form,
+ HA_CREATE_INFO *create_info)
+{
+ char buff[FN_REFLEN];
+ return myrg_create(fn_format(buff,name,"","",2+4+16),0);
+}
diff --git a/sql/ha_myisammrg.h b/sql/ha_myisammrg.h
new file mode 100644
index 00000000000..cb1feb52989
--- /dev/null
+++ b/sql/ha_myisammrg.h
@@ -0,0 +1,67 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+
+#ifdef __GNUC__
+#pragma interface /* gcc class implementation */
+#endif
+
+/* class for the the myisam merge handler */
+
+#include <myisammrg.h>
+
+class ha_myisammrg: public handler
+{
+ MYRG_INFO *file;
+
+ public:
+ ha_myisammrg(TABLE *table): handler(table), file(0) {}
+ ~ha_myisammrg() {}
+ const char *table_type() const { return "MRG_MyISAM"; }
+ const char **bas_ext() const;
+ ulong option_flag() const { return HA_READ_RND_SAME+HA_KEYPOS_TO_RNDPOS+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; }
+ uint max_key_length() const { return 0; }
+
+ int open(const char *name, int mode, int test_if_locked);
+ int close(void);
+ int write_row(byte * buf);
+ int update_row(const byte * old_data, byte * new_data);
+ int delete_row(const byte * buf);
+ int index_read(byte * buf, const byte * key,
+ uint key_len, enum ha_rkey_function find_flag);
+ int index_read_idx(byte * buf, uint idx, const byte * key,
+ uint key_len, enum ha_rkey_function find_flag);
+ int index_next(byte * buf);
+ int index_prev(byte * buf);
+ int index_first(byte * buf);
+ int index_last(byte * buf);
+ int rnd_init(bool scan=1);
+ int rnd_next(byte *buf);
+ int rnd_pos(byte * buf, byte *pos);
+ void position(const byte *record);
+ my_off_t row_position() { return myrg_position(file); }
+ void info(uint);
+ int extra(enum ha_extra_function operation);
+ int reset(void);
+ int external_lock(THD *thd, int lock_type);
+ uint lock_count(void) const;
+ int create(const char *name, TABLE *form, HA_CREATE_INFO *create_info);
+ THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to,
+ enum thr_lock_type lock_type);
+};
diff --git a/sql/handler.cc b/sql/handler.cc
new file mode 100644
index 00000000000..817e3fa79dc
--- /dev/null
+++ b/sql/handler.cc
@@ -0,0 +1,614 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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-calling-functions */
+
+#ifdef __GNUC__
+#pragma implementation // gcc: Class implementation
+#endif
+
+#include "mysql_priv.h"
+#include "ha_heap.h"
+#include "ha_myisam.h"
+#include "ha_myisammrg.h"
+#ifndef NO_ISAM
+#include "ha_isam.h"
+#include "ha_isammrg.h"
+#endif
+#ifdef HAVE_BERKELEY_DB
+#include "ha_berkeley.h"
+#endif
+#include <myisampack.h>
+#include <errno.h>
+
+ /* static functions defined in this file */
+
+static void NEAR_F set_form_timestamp(TABLE *table, byte *record);
+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_read_rnd_count, ha_read_rnd_next_count;
+
+const char *ha_table_type[] = {
+ "", "DIAB_ISAM","HASH","MISAM","PISAM","RMS_ISAM","HEAP", "ISAM",
+ "MRG_ISAM","MYISAM", "MRG_MYISAM", "BERKELEY_DB?", "?", "?",NullS
+};
+
+const char *ha_row_type[] = {
+ "", "FIXED", "DYNAMIC", "COMPRESSED","?","?","?"
+};
+
+TYPELIB ha_table_typelib= {array_elements(ha_table_type)-4,"",
+ ha_table_type+1};
+
+
+ /* Use other database handler if databasehandler is not incompiled */
+
+enum db_type ha_checktype(enum db_type database_type)
+{
+ switch (database_type) {
+#ifdef HAVE_BERKELEY_DB
+ case DB_TYPE_BERKELEY_DB:
+ return(berkeley_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
+ case DB_TYPE_ISAM:
+#endif
+ case DB_TYPE_HEAP:
+ case DB_TYPE_MYISAM:
+ case DB_TYPE_MRG_MYISAM:
+ return (database_type); /* Database exists on system */
+ default:
+ break;
+ }
+ return(DB_TYPE_MYISAM); /* Use this as default */
+} /* ha_checktype */
+
+
+handler *get_new_handler(TABLE *table, enum db_type db_type)
+{
+ switch (db_type) {
+#ifndef NO_HASH
+ return new ha_hash(table);
+#endif
+#ifndef NO_MERGE
+ case DB_TYPE_MRG_ISAM:
+ return new ha_isammrg(table);
+#endif
+#ifndef NO_ISAM
+ case DB_TYPE_ISAM:
+ return new ha_isam(table);
+#endif
+#ifdef HAVE_BERKELEY_DB
+ case DB_TYPE_BERKELEY_DB:
+ return new ha_berkeley(table);
+#endif
+ case DB_TYPE_HEAP:
+ return new ha_heap(table);
+ case DB_TYPE_MYISAM:
+ default: // should never happen
+ return new ha_myisam(table);
+ case DB_TYPE_MRG_MYISAM:
+ return new ha_myisammrg(table);
+ }
+}
+
+int ha_init()
+{
+#ifdef HAVE_BERKELEY_DB
+ if (!berkeley_skip)
+ {
+ int error;
+ if ((error=berkeley_init()))
+ return error;
+ }
+#endif
+ return 0;
+}
+
+ /* close, flush or restart databases */
+ /* Ignore this for other databases than ours */
+
+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);
+ error|=nisam_panic(flag);
+ error|=mi_panic(flag);
+ error|=myrg_panic(flag);
+#ifdef HAVE_BERKELEY_DB
+ if (!berkeley_skip)
+ error|=berkeley_end();
+#endif
+ return error;
+} /* ha_panic */
+
+
+int ha_autocommit_or_rollback(THD *thd, int error)
+{
+ DBUG_ENTER("ha_autocommit_or_rollback");
+#ifdef HAVE_BERKELEY_DB
+ if ((thd->options & OPTION_AUTO_COMMIT) && !thd->locked_tables)
+ {
+ if (!error)
+ {
+ if (ha_commit(thd))
+ error=1;
+ }
+ else
+ (void) ha_rollback(thd);
+ }
+#endif
+ DBUG_RETURN(error);
+}
+
+int ha_commit(THD *thd)
+{
+ int error=0;
+ DBUG_ENTER("commit");
+#ifdef HAVE_BERKELEY_DB
+ if (thd->transaction.bdb_tid)
+ {
+ int error=berkeley_commit(thd);
+ if (error)
+ {
+ my_error(ER_ERROR_DURING_COMMIT, MYF(0), error);
+ error=1;
+ }
+ }
+#endif
+ DBUG_RETURN(error);
+}
+
+int ha_rollback(THD *thd)
+{
+ int error=0;
+ DBUG_ENTER("commit");
+#ifdef HAVE_BERKELEY_DB
+ if (thd->transaction.bdb_tid)
+ {
+ int error=berkeley_rollback(thd);
+ if (error)
+ {
+ my_error(ER_ERROR_DURING_ROLLBACK, MYF(0), error);
+ error=1;
+ }
+ }
+#endif
+ DBUG_RETURN(error);
+}
+
+
+bool ha_flush_logs()
+{
+ bool result=0;
+#ifdef HAVE_BERKELEY_DB
+ if (!berkeley_skip && berkeley_flush_logs())
+ result=1;
+#endif
+ return result;
+}
+
+
+int ha_delete_table(enum db_type table_type, const char *path)
+{
+ handler *file=get_new_handler((TABLE*) 0, table_type);
+ if (!file)
+ return -1;
+ int error=file->delete_table(path);
+ delete file;
+ return error;
+}
+
+void ha_store_ptr(byte *buff, uint pack_length, my_off_t pos)
+{
+ switch (pack_length) {
+#if SIZEOF_OFF_T > 4
+ case 8: mi_int8store(buff,pos); break;
+ case 7: mi_int7store(buff,pos); break;
+ case 6: mi_int6store(buff,pos); break;
+ case 5: mi_int5store(buff,pos); break;
+#endif
+ case 4: mi_int4store(buff,pos); break;
+ case 3: mi_int3store(buff,pos); break;
+ case 2: mi_int2store(buff,(uint) pos); break;
+ case 1: buff[0]= (uchar) pos; break;
+ }
+ return;
+}
+
+my_off_t ha_get_ptr(byte *ptr, uint pack_length)
+{
+ my_off_t pos;
+ switch (pack_length) {
+#if SIZEOF_OFF_T > 4
+ case 8:
+ pos= (my_off_t) mi_uint8korr(ptr);
+ break;
+ case 7:
+ pos= (my_off_t) mi_uint7korr(ptr);
+ break;
+ case 6:
+ pos= (my_off_t) mi_uint6korr(ptr);
+ break;
+ case 5:
+ pos= (my_off_t) mi_uint5korr(ptr);
+ break;
+#endif
+ case 4:
+ pos= (my_off_t) mi_uint4korr(ptr);
+ break;
+ case 3:
+ pos= (my_off_t) mi_uint3korr(ptr);
+ break;
+ case 2:
+ pos= (my_off_t) mi_uint2korr(ptr);
+ break;
+ case 1:
+ pos= (my_off_t) mi_uint2korr(ptr);
+ break;
+ default:
+ pos=0; // Impossible
+ break;
+ }
+ return pos;
+}
+
+/****************************************************************************
+** General handler functions
+****************************************************************************/
+
+ /* Open database-handler. Try O_RDONLY if can't open as O_RDWR */
+ /* Don't wait for locks if not HA_OPEN_WAIT_IF_LOCKED is set */
+
+int handler::ha_open(const char *name, int mode, int test_if_locked)
+{
+ int error;
+ DBUG_ENTER("handler::open");
+ DBUG_PRINT("enter",("db_type: %d db_stat: %d mode: %d lock_test: %d",
+ table->db_type, table->db_stat, mode, test_if_locked));
+
+ if ((error=open(name,mode,test_if_locked)))
+ {
+ if ((error == EACCES || error == EROFS) && mode == O_RDWR &&
+ (table->db_stat & HA_TRY_READ_ONLY))
+ {
+ table->db_stat|=HA_READ_ONLY;
+ error=open(name,O_RDONLY,test_if_locked);
+ }
+ }
+ if (error)
+ {
+ my_errno=error; /* Safeguard */
+ DBUG_PRINT("error",("error: %d errno: %d",error,errno));
+ }
+ else
+ {
+ if (table->db_options_in_use & HA_OPTION_READ_ONLY_DATA)
+ table->db_stat|=HA_READ_ONLY;
+ }
+ if (!error)
+ {
+
+ if (!(ref=(byte*) my_malloc(ALIGN_SIZE(ref_length)*2,MYF(0))))
+ {
+ close();
+ error=HA_ERR_OUT_OF_MEM;
+ }
+ else
+ dupp_ref=ref+ALIGN_SIZE(ref_length);
+ }
+ DBUG_RETURN(error);
+}
+
+int handler::check(THD* thd, HA_CHECK_OPT* check_opt)
+{
+ return HA_CHECK_NOT_IMPLEMENTED;
+}
+
+int handler::repair(THD* thd, HA_CHECK_OPT* check_opt)
+{
+ return HA_REPAIR_NOT_IMPLEMENTED;
+}
+
+int handler::optimize(THD* thd)
+{
+ return HA_OPTIMIZE_NOT_IMPLEMENTED;
+}
+
+int handler::analyze(THD* thd)
+{
+ return HA_ANALYZE_NOT_IMPLEMENTED;
+}
+
+ /* Read first row from a table */
+
+int handler::rnd_first(byte * buf)
+{
+ register int error;
+ DBUG_ENTER("handler::rnd_first");
+
+ statistic_increment(ha_read_first_count,&LOCK_status);
+ (void) rnd_init();
+ while ((error= rnd_next(buf)) == HA_ERR_RECORD_DELETED) ;
+ (void) rnd_end();
+ DBUG_RETURN(error);
+}
+
+
+/*
+ The following function is only needed for tables that may be temporary tables
+ during joins
+*/
+
+int handler::restart_rnd_next(byte *buf, byte *pos)
+{
+ return HA_ERR_WRONG_COMMAND;
+}
+
+
+ /* Set a timestamp in record */
+
+void handler::update_timestamp(byte *record)
+{
+ long skr= (long) current_thd->query_start();
+#ifdef WORDS_BIGENDIAN
+ if (table->db_low_byte_first)
+ {
+ int4store(record,skr);
+ }
+ else
+#endif
+ longstore(record,skr);
+ return;
+}
+
+ /* 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()
+{
+ longlong nr;
+ THD *thd;
+ DBUG_ENTER("update_auto_increment");
+ if (table->next_number_field->val_int() != 0)
+ DBUG_VOID_RETURN;
+ thd=current_thd;
+ if ((nr=thd->next_insert_id))
+ thd->next_insert_id=0; // Clear after use
+ else
+ nr=get_auto_increment();
+ thd->insert_id((ulonglong) nr);
+ table->next_number_field->store(nr);
+ DBUG_VOID_RETURN;
+}
+
+
+longlong handler::get_auto_increment()
+{
+ longlong nr;
+ int error;
+ (void) extra(HA_EXTRA_KEYREAD);
+ index_init(table->next_number_index);
+ error=index_last(table->record[1]);
+ if (error)
+ nr=1;
+ else
+ nr=(longlong) table->next_number_field->
+ val_int_offset(table->rec_buff_length)+1;
+ (void) extra(HA_EXTRA_NO_KEYREAD);
+ index_end();
+ return nr;
+}
+
+ /* Print error that we got from handler function */
+
+void handler::print_error(int error, myf errflag)
+{
+ DBUG_ENTER("print_error");
+ DBUG_PRINT("enter",("error: %d",error));
+
+ int textno=ER_GET_ERRNO;
+ switch (error) {
+ case EAGAIN:
+ textno=ER_FILE_USED;
+ break;
+ case ENOENT:
+ textno=ER_FILE_NOT_FOUND;
+ break;
+ case HA_ERR_KEY_NOT_FOUND:
+ case HA_ERR_NO_ACTIVE_RECORD:
+ case HA_ERR_END_OF_FILE:
+ textno=ER_KEY_NOT_FOUND;
+ break;
+ case HA_ERR_WRONG_TABLE_DEF:
+ textno=ER_WRONG_MRG_TABLE;
+ break;
+ case HA_ERR_FOUND_DUPP_KEY:
+ {
+ uint key_nr=get_dup_key(error);
+ if ((int) key_nr >= 0)
+ {
+ /* Write the dupplicated key in the error message */
+ char key[MAX_KEY_LENGTH];
+ String str(key,sizeof(key));
+ key_unpack(&str,table,(uint) key_nr);
+ uint max_length=MYSQL_ERRMSG_SIZE-strlen(ER(ER_DUP_ENTRY));
+ if (str.length() >= max_length)
+ {
+ str.length(max_length-4);
+ str.append("...");
+ }
+ my_error(ER_DUP_ENTRY,MYF(0),str.c_ptr(),key_nr+1);
+ DBUG_VOID_RETURN;
+ }
+ textno=ER_DUP_KEY;
+ break;
+ }
+ case HA_ERR_FOUND_DUPP_UNIQUE:
+ textno=ER_DUP_UNIQUE;
+ break;
+ case HA_ERR_RECORD_CHANGED:
+ textno=ER_CHECKREAD;
+ break;
+ case HA_ERR_CRASHED:
+ textno=ER_NOT_KEYFILE;
+ break;
+ case HA_ERR_OUT_OF_MEM:
+ my_error(ER_OUT_OF_RESOURCES,errflag);
+ DBUG_VOID_RETURN;
+ case HA_ERR_WRONG_COMMAND:
+ textno=ER_ILLEGAL_HA;
+ break;
+ case HA_ERR_OLD_FILE:
+ textno=ER_OLD_KEYFILE;
+ break;
+ case HA_ERR_UNSUPPORTED:
+ textno=ER_UNSUPPORTED_EXTENSION;
+ break;
+ case HA_ERR_RECORD_FILE_FULL:
+ textno=ER_RECORD_FILE_FULL;
+ break;
+ default:
+ {
+ my_error(ER_GET_ERRNO,errflag,error);
+ DBUG_VOID_RETURN;
+ }
+ }
+ my_error(textno,errflag,table->table_name,error);
+ DBUG_VOID_RETURN;
+}
+
+ /* Return key if error because of duplicated keys */
+
+uint handler::get_dup_key(int error)
+{
+ DBUG_ENTER("key_error");
+ table->file->errkey = (uint) -1;
+ if (error == HA_ERR_FOUND_DUPP_KEY || error == HA_ERR_FOUND_DUPP_UNIQUE)
+ info(HA_STATUS_ERRKEY | HA_STATUS_NO_LOCK);
+ DBUG_RETURN(table->file->errkey);
+}
+
+int handler::delete_table(const char *name)
+{
+ for (const char **ext=bas_ext(); *ext ; ext++)
+ {
+ if (delete_file(name,*ext,2))
+ return my_errno;
+ }
+ return 0;
+}
+
+
+int handler::rename_table(const char * from, const char * to)
+{
+ DBUG_ENTER("handler::rename_table");
+ for (const char **ext=bas_ext(); *ext ; ext++)
+ {
+ if (rename_file_ext(from,to,*ext))
+ DBUG_RETURN(my_errno);
+ }
+ DBUG_RETURN(0);
+}
+
+
+int handler::index_next_same(byte *buf, const byte *key, uint keylen)
+{
+ int error;
+ if (!(error=index_next(buf)))
+ {
+ if (key_cmp(table, key, active_index, keylen))
+ {
+ table->status=STATUS_NOT_FOUND;
+ error=HA_ERR_END_OF_FILE;
+ }
+ }
+ return error;
+}
+
+
+/*
+ The following is only needed if we would like to use the database
+ for internal temporary tables
+*/
+
+int handler::delete_all_rows()
+{
+ return (my_errno=HA_ERR_WRONG_COMMAND);
+}
+
+/****************************************************************************
+** Some general functions that isn't in the handler class
+****************************************************************************/
+
+ /* Initiates table-file and calls apropriate database-creator */
+ /* Returns 1 if something got wrong */
+
+int ha_create_table(const char *name, HA_CREATE_INFO *create_info,
+ bool update_create_info)
+
+{
+ int error;
+ TABLE table;
+ DBUG_ENTER("ha_create_table");
+
+ if (openfrm(name,"",0,(uint) READ_ALL,&table))
+ DBUG_RETURN(1);
+ if (update_create_info)
+ {
+ update_create_info_from_table(create_info, &table);
+ if (table.file->option_flag() & HA_DROP_BEFORE_CREATE)
+ table.file->delete_table(name); // Needed for BDB tables
+ }
+ error=table.file->create(name,&table,create_info);
+ VOID(closefrm(&table));
+ if (error)
+ my_error(ER_CANT_CREATE_TABLE,MYF(ME_BELL+ME_WAITTANG),name,my_errno);
+ DBUG_RETURN(error != 0);
+}
+
+ /* Use key cacheing on all databases */
+
+void ha_key_cache(void)
+{
+ if (keybuff_size)
+ (void) init_key_cache(keybuff_size,0);
+} /* ha_key_cache */
+
+
+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)));
+}
diff --git a/sql/handler.h b/sql/handler.h
new file mode 100644
index 00000000000..a86b390e78b
--- /dev/null
+++ b/sql/handler.h
@@ -0,0 +1,307 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+
+/* Definitions for parameters to do with handler-routines */
+
+#ifdef __GNUC__
+#pragma interface /* gcc class implementation */
+#endif
+
+#ifndef NO_HASH
+#define NO_HASH /* Not yet implemented */
+#endif
+
+// the following is for checking tables
+
+#define HA_CHECK_OK 0
+#define HA_CHECK_NOT_IMPLEMENTED -1
+#define HA_CHECK_CORRUPT -2
+#define HA_CHECK_INTERNAL_ERROR -3
+
+#define HA_REPAIR_OK 0
+#define HA_REPAIR_NOT_IMPLEMENTED -1
+#define HA_REPAIR_FAILED -2
+#define HA_REPAIR_INTERNAL_ERROR -3
+
+#define HA_OPTIMIZE_OK 0
+#define HA_OPTIMIZE_NOT_IMPLEMENTED -1
+#define HA_OPTIMIZE_FAILED -2
+#define HA_OPTIMIZE_INTERNAL_ERROR -3
+
+#define HA_ANALYZE_OK 0
+#define HA_ANALYZE_NOT_IMPLEMENTED -1
+#define HA_ANALYZE_FAILED -2
+#define HA_ANALYZE_INTERNAL_ERROR -3
+
+/* 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_REC_NOT_IN_SEQ 64 /* ha_info don't return recnumber;
+ It returns a position to ha_r_rnd */
+#define HA_BINARY_KEYS 128 /* Keys must be exact */
+#define HA_RSAME_NO_INDEX 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 */
+#define HA_NO_BLOBS 131072 /* Doesn't support blobs */
+#define HA_BLOB_KEY (HA_NO_BLOBS*2) /* key on blob */
+#define HA_AUTO_PART_KEY (HA_BLOB_KEY*2)
+#define HA_REQUIRE_PRIMARY_KEY (HA_AUTO_PART_KEY*2)
+#define HA_NOT_EXACT_COUNT (HA_REQUIRE_PRIMARY_KEY*2)
+#define HA_NO_WRITE_DELAYED (HA_NOT_EXACT_COUNT*2)
+#define HA_PRIMARY_KEY_IN_READ_INDEX (HA_NO_WRITE_DELAYED*2)
+#define HA_DROP_BEFORE_CREATE (HA_PRIMARY_KEY_IN_READ_INDEX*2)
+
+ /* Parameters for open() (in register form->filestat) */
+ /* HA_GET_INFO does a implicit HA_ABORT_IF_LOCKED */
+
+#define HA_OPEN_KEYFILE 1
+#define HA_OPEN_RNDFILE 2
+#define HA_GET_INDEX 4
+#define HA_GET_INFO 8 /* do a ha_info() after open */
+#define HA_READ_ONLY 16 /* File opened as readonly */
+#define HA_TRY_READ_ONLY 32 /* Try readonly if can't */
+ /* open with read and write */
+#define HA_WAIT_IF_LOCKED 64 /* Wait if locked on open */
+#define HA_ABORT_IF_LOCKED 128 /* skip if locked on open.*/
+#define HA_BLOCK_LOCK 256 /* unlock when reading some records */
+#define HA_OPEN_TEMPORARY 512
+
+ /* Error on write which is recoverable (Key exist) */
+
+#define HA_WRITE_SKIPP 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 */
+
+ /* Some key definitions */
+#define HA_KEY_NULL_LENGTH 1
+#define HA_KEY_BLOB_LENGTH 2
+
+#define HA_LEX_CREATE_TMP_TABLE 1
+#define HA_LEX_CREATE_IF_NOT_EXISTS 2
+#define HA_OPTION_NO_CHECKSUM (1L << 17)
+#define HA_OPTION_NO_DELAY_KEY_WRITE (1L << 18)
+#define HA_MAX_REC_LENGTH 65535
+
+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_DEFAULT };
+
+enum row_type { 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
+
+typedef struct st_ha_create_information
+{
+ ulong table_options;
+ enum db_type db_type;
+ enum row_type row_type;
+ ulong avg_row_length;
+ ulonglong max_rows,min_rows;
+ ulonglong auto_increment_value;
+ char *comment,*password;
+ uint options; /* OR of HA_CREATE_ options */
+ uint raid_type,raid_chunks;
+ ulong raid_chunksize;
+ bool if_not_exists;
+ ulong used_fields;
+} HA_CREATE_INFO;
+
+
+/* The handler for a table type. Will be included in the TABLE structure */
+
+struct st_table;
+typedef struct st_table TABLE;
+extern ulong myisam_sort_buffer_size;
+
+typedef struct st_ha_check_opt
+{
+ ulong sort_buffer_size;
+ uint flags;
+ bool quick;
+ bool changed_files;
+ inline void init()
+ {
+ flags= 0; quick= 0;
+ sort_buffer_size = myisam_sort_buffer_size;
+ }
+} HA_CHECK_OPT;
+
+class handler :public Sql_alloc
+{
+ protected:
+ struct st_table *table; /* The table definition */
+ uint active_index;
+
+public:
+ byte *ref; /* Pointer to current row */
+ byte *dupp_ref; /* Pointer to dupp row */
+ uint ref_length; /* Length of ref (1-8) */
+ uint block_size; /* index block size */
+ ha_rows records; /* Records i datafilen */
+ ha_rows deleted; /* Deleted records */
+ ulonglong data_file_length; /* Length off data file */
+ ulonglong max_data_file_length; /* Length off data file */
+ ulonglong index_file_length;
+ ulonglong max_index_file_length;
+ ulonglong delete_length; /* Free bytes */
+ ulonglong auto_increment_value;
+ uint raid_type,raid_chunks;
+ ulong raid_chunksize;
+ uint errkey; /* Last dup key */
+ uint sortkey, key_used_on_scan;
+ time_t create_time; /* When table was created */
+ time_t check_time;
+ time_t update_time;
+ ulong mean_rec_length; /* physical reclength */
+ double ft_relevance;
+ void *ft_handler;
+
+ handler(TABLE *table_arg) : table(table_arg),active_index(MAX_REF_PARTS),
+ ref(0),ref_length(sizeof(my_off_t)), block_size(0),records(0),deleted(0),
+ data_file_length(0), max_data_file_length(0), index_file_length(0),
+ delete_length(0), auto_increment_value(0), raid_type(0),
+ key_used_on_scan(MAX_KEY),
+ create_time(0), check_time(0), update_time(0), mean_rec_length(0),
+ ft_relevance(0.0), ft_handler(0)
+ {}
+ virtual ~handler(void) { my_free((char*) ref,MYF(MY_ALLOW_ZERO_PTR)); }
+ int ha_open(const char *name, int mode, int test_if_locked);
+ void update_timestamp(byte *record);
+ void update_auto_increment();
+ void print_error(int error, myf errflag);
+ uint get_dup_key(int error);
+ void change_table_ptr(TABLE *table_arg) { table=table_arg; }
+ virtual double scan_time()
+ { return ulonglong2double(data_file_length) / IO_SIZE + 1; }
+ virtual double read_time(ha_rows rows) { return rows; }
+ virtual bool fast_key_read() { return 0;}
+ virtual bool has_transactions(){ return 0;}
+
+ virtual int index_init(uint idx) { active_index=idx; return 0;}
+ virtual int index_end() {return 0; }
+ uint get_index(void) const { return active_index; }
+ virtual int open(const char *name, int mode, int test_if_locked)=0;
+ virtual void initialize(void) {}
+ virtual int close(void)=0;
+ virtual int write_row(byte * buf)=0;
+ 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;
+ 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;
+ virtual int index_prev(byte * buf)=0;
+ 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 ft_init(uint inx,const byte *key, uint keylen, bool presort)
+ { return -1; }
+ virtual int ft_read(byte *buf) { return -1; }
+ virtual int ft_close() { 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 restart_rnd_next(byte *buf, byte *pos);
+ virtual 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)
+ { return (ha_rows) 10; }
+ virtual void position(const byte *record)=0;
+ virtual my_off_t row_position() { return HA_OFFSET_ERROR; }
+ virtual void info(uint)=0;
+ virtual int extra(enum ha_extra_function operation)=0;
+ virtual int reset()=0;
+ virtual int external_lock(THD *thd, int lock_type)=0;
+ virtual int delete_all_rows();
+ virtual longlong get_auto_increment();
+ virtual void update_create_info(HA_CREATE_INFO *create_info) {}
+ virtual int check(THD* thd, HA_CHECK_OPT* check_opt );
+ virtual int repair(THD* thd, HA_CHECK_OPT* check_opt);
+ virtual int optimize(THD* thd);
+ virtual int analyze(THD* thd);
+ virtual int dump(THD* thd, int fd = -1) { return ER_DUMP_NOT_IMPLEMENTED; }
+ // not implemented by default
+ virtual int net_read_dump(NET* net)
+ { return ER_DUMP_NOT_IMPLEMENTED; }
+
+ /* The following can be called without an open handler */
+ virtual const char *table_type() const =0;
+ virtual const char **bas_ext() const =0;
+ virtual ulong option_flag() const =0;
+ virtual uint max_record_length() const =0;
+ virtual uint max_keys() const =0;
+ virtual uint max_key_parts() const =0;
+ virtual uint max_key_length()const =0;
+ virtual uint min_record_length(uint options) const { return 1; }
+ virtual bool low_byte_first() const { return 1; }
+
+ virtual int rename_table(const char *from, const char *to);
+ virtual int delete_table(const char *name);
+ virtual int create(const char *name, TABLE *form, HA_CREATE_INFO *info)=0;
+ virtual uint lock_count(void) const { return 1; }
+ virtual THR_LOCK_DATA **store_lock(THD *thd,
+ THR_LOCK_DATA **to,
+ enum thr_lock_type lock_type)=0;
+};
+
+ /* Some extern variables used with handlers */
+
+extern const char *ha_row_type[];
+extern TYPELIB ha_table_typelib;
+
+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);
+int ha_init(void);
+int ha_panic(enum ha_panic_function flag);
+enum db_type ha_checktype(enum db_type database_type);
+int ha_create_table(const char *name, HA_CREATE_INFO *create_info,
+ bool update_create_info);
+int ha_delete_table(enum db_type db_type, const char *path);
+void ha_key_cache(void);
+int ha_commit(THD *thd);
+int ha_rollback(THD *thd);
+int ha_autocommit_or_rollback(THD *thd, int error);
+bool ha_flush_logs(void);
+
diff --git a/sql/hash_filo.cc b/sql/hash_filo.cc
new file mode 100644
index 00000000000..990d2d662d6
--- /dev/null
+++ b/sql/hash_filo.cc
@@ -0,0 +1,28 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 class for static sized hash tables where old entries are deleted according
+** to usage.
+*/
+
+#ifdef __GNUC__
+#pragma implementation // gcc: Class implementation
+#endif
+
+#include "mysql_priv.h"
+#include "hash_filo.h"
diff --git a/sql/hash_filo.h b/sql/hash_filo.h
new file mode 100644
index 00000000000..7d659f706a3
--- /dev/null
+++ b/sql/hash_filo.h
@@ -0,0 +1,131 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 class for static sized hash tables where old entries are deleted in
+** first-in-last-out to usage.
+*/
+
+#ifndef HASH_FILO_H
+#define HASH_FILO_H
+
+#ifdef __GNUC__
+#pragma interface /* gcc class implementation */
+#endif
+
+class hash_filo_element
+{
+ hash_filo_element *next_used,*prev_used;
+ public:
+ hash_filo_element() {}
+ friend class hash_filo;
+};
+
+
+class hash_filo
+{
+ const uint size, key_offset, key_length;
+ const hash_get_key get_key;
+ void (*free_element)(void*);
+ bool init;
+
+ hash_filo_element *first_link,*last_link;
+public:
+ pthread_mutex_t lock;
+ HASH cache;
+
+ hash_filo(uint size_arg, uint key_offset_arg , uint key_length_arg,
+ hash_get_key get_key_arg,void (*free_element_arg)(void*))
+ :size(size_arg), key_offset(key_offset_arg), key_length(key_length_arg),
+ get_key(get_key_arg), free_element(free_element_arg),init(0)
+ {
+ bzero((char*) &cache,sizeof(cache));
+ }
+
+ ~hash_filo()
+ {
+ if (init)
+ {
+ if (cache.array.buffer) /* Avoid problems with thread library */
+ (void) hash_free(&cache);
+ pthread_mutex_destroy(&lock);
+ }
+ }
+ void clear(bool locked=0)
+ {
+ if (!init)
+ {
+ init=1;
+ (void) pthread_mutex_init(&lock,NULL);
+ }
+ if (!locked)
+ (void) pthread_mutex_lock(&lock);
+ (void) hash_free(&cache);
+ (void) hash_init(&cache,size,key_offset, key_length, get_key, free_element,
+ 0);
+ if (!locked)
+ (void) pthread_mutex_unlock(&lock);
+ first_link=last_link=0;
+ }
+
+ hash_filo_element *search(gptr key,uint length)
+ {
+ hash_filo_element *entry=(hash_filo_element*)
+ hash_search(&cache,(byte*) key,length);
+ if (entry)
+ { // Found; link it first
+ if (entry != first_link)
+ { // Relink used-chain
+ if (entry == last_link)
+ last_link=entry->prev_used;
+ else
+ {
+ entry->next_used->prev_used = entry->prev_used;
+ entry->prev_used->next_used = entry->next_used;
+ }
+ if ((entry->next_used= first_link))
+ first_link->prev_used=entry;
+ first_link=entry;
+ }
+ }
+ return entry;
+ }
+
+ my_bool add(hash_filo_element *entry)
+ {
+ if (cache.records == size)
+ {
+ hash_filo_element *tmp=last_link;
+ last_link=last_link->prev_used;
+ hash_delete(&cache,(byte*) tmp);
+ }
+ if (hash_insert(&cache,(byte*) entry))
+ {
+ if (free_element)
+ (*free_element)(entry); // This should never happen
+ return 1;
+ }
+ if ((entry->next_used=first_link))
+ first_link->prev_used=entry;
+ else
+ last_link=entry;
+ first_link=entry;
+ return 0;
+ }
+};
+
+#endif
diff --git a/sql/hostname.cc b/sql/hostname.cc
new file mode 100644
index 00000000000..0e8d6e36f0f
--- /dev/null
+++ b/sql/hostname.cc
@@ -0,0 +1,235 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 hostname for an IP. Hostnames are checked with reverse name lookup and
+ checked that they doesn't resemble an ip.
+*/
+
+#include "mysql_priv.h"
+#include "hash_filo.h"
+#include <m_ctype.h>
+#ifdef __cplusplus
+extern "C" { // Because of SCO 3.2V4.2
+#endif
+#ifndef __WIN__
+#include <sys/resource.h>
+#ifdef HAVE_SYS_UN_H
+#include <sys/un.h>
+#endif
+#include <netdb.h>
+#include <sys/utsname.h>
+#endif // __WIN__
+#ifdef __cplusplus
+}
+#endif
+
+
+class host_entry :public hash_filo_element
+{
+public:
+ char ip[sizeof(((struct in_addr *) 0)->s_addr)];
+ uint errors;
+ char *hostname;
+};
+
+static hash_filo *hostname_cache;
+
+void hostname_cache_refresh()
+{
+ hostname_cache->clear();
+}
+
+bool hostname_cache_init()
+{
+ if (!(hostname_cache=new hash_filo(HOST_CACHE_SIZE,offsetof(host_entry,ip),
+ sizeof(struct in_addr),NULL,
+ (void (*)(void*)) free)))
+ return 1;
+ hostname_cache->clear();
+ return 0;
+}
+
+void hostname_cache_free()
+{
+ delete hostname_cache;
+}
+
+static void add_hostname(struct in_addr *in,const char *name)
+{
+ if (!(specialflag & SPECIAL_NO_HOST_CACHE))
+ {
+ VOID(pthread_mutex_lock(&hostname_cache->lock));
+ host_entry *entry;
+ if (!(entry=(host_entry*) hostname_cache->search((gptr) &in->s_addr,0)))
+ {
+ uint length=name ? strlen(name) : 0;
+
+ if ((entry=(host_entry*) malloc(sizeof(host_entry)+length+1)))
+ {
+ char *new_name= (char *) (entry+1);
+ memcpy_fixed(&entry->ip, &in->s_addr, sizeof(in->s_addr));
+ memcpy(new_name, name, length); // Should work even if name == NULL
+ new_name[length]=0; // End of string
+ entry->hostname=new_name;
+ entry->errors=0;
+ (void) hostname_cache->add(entry);
+ }
+ }
+ VOID(pthread_mutex_unlock(&hostname_cache->lock));
+ }
+}
+
+
+static inline void add_wrong_ip(struct in_addr *in)
+{
+ add_hostname(in,NullS);
+}
+
+void inc_host_errors(struct in_addr *in)
+{
+ VOID(pthread_mutex_lock(&hostname_cache->lock));
+ host_entry *entry;
+ if ((entry=(host_entry*) hostname_cache->search((gptr) &in->s_addr,0)))
+ entry->errors++;
+ VOID(pthread_mutex_unlock(&hostname_cache->lock));
+}
+
+void reset_host_errors(struct in_addr *in)
+{
+ VOID(pthread_mutex_lock(&hostname_cache->lock));
+ host_entry *entry;
+ if ((entry=(host_entry*) hostname_cache->search((gptr) &in->s_addr,0)))
+ entry->errors=0;
+ VOID(pthread_mutex_unlock(&hostname_cache->lock));
+}
+
+
+my_string ip_to_hostname(struct in_addr *in, uint *errors)
+{
+ host_entry *entry;
+ DBUG_ENTER("ip_to_hostname");
+
+ /* Check first if we have name in cache */
+ *errors=0;
+ if (!(specialflag & SPECIAL_NO_HOST_CACHE))
+ {
+ VOID(pthread_mutex_lock(&hostname_cache->lock));
+ if ((entry=(host_entry*) hostname_cache->search((gptr) &in->s_addr,0)))
+ {
+ char *name;
+ if (!entry->hostname)
+ name=0; // Don't allow connection
+ else
+ name=my_strdup(entry->hostname,MYF(0));
+ *errors= entry->errors;
+ VOID(pthread_mutex_unlock(&hostname_cache->lock));
+ DBUG_RETURN(name);
+ }
+ VOID(pthread_mutex_unlock(&hostname_cache->lock));
+ }
+
+ struct hostent *hp, *check;
+ char *name;
+ LINT_INIT(check);
+#if defined(HAVE_GETHOSTBYADDR_R) && defined(HAVE_SOLARIS_STYLE_GETHOST)
+ char buff[GETHOSTBYADDR_BUFF_SIZE],buff2[GETHOSTBYNAME_BUFF_SIZE];
+ int tmp_errno;
+ struct hostent tmp_hostent, tmp_hostent2;
+#ifdef HAVE_purify
+ bzero(buff,sizeof(buff)); // Bug in purify
+#endif
+ if (!(hp=gethostbyaddr_r((char*) in,sizeof(*in),
+ AF_INET,
+ &tmp_hostent,buff,sizeof(buff),&tmp_errno)))
+ {
+ DBUG_PRINT("error",("gethostbyaddr_r returned %d",tmp_errno));
+ return 0;
+ }
+ if (!(check=my_gethostbyname_r(hp->h_name,&tmp_hostent2,buff2,sizeof(buff2),
+ &tmp_errno)))
+ {
+ DBUG_PRINT("error",("gethostbyname_r returned %d",tmp_errno));
+ add_wrong_ip(in);
+ DBUG_RETURN(0);
+ }
+ if (!hp->h_name[0])
+ {
+ DBUG_PRINT("error",("Got an empty hostname"));
+ add_wrong_ip(in);
+ DBUG_RETURN(0); // Don't allow empty hostnames
+ }
+ if (!(name=my_strdup(hp->h_name,MYF(0))))
+ DBUG_RETURN(0); // out of memory
+
+#else
+ VOID(pthread_mutex_lock(&hostname_cache->lock));
+ if (!(hp=gethostbyaddr((char*) in,sizeof(*in), AF_INET)))
+ {
+ DBUG_PRINT("error",("gethostbyaddr returned %d",errno));
+ VOID(pthread_mutex_unlock(&hostname_cache->lock));
+ add_wrong_ip(in);
+ DBUG_RETURN(0);
+ }
+ if (!hp->h_name[0])
+ {
+ VOID(pthread_mutex_unlock(&hostname_cache->lock));
+ DBUG_PRINT("error",("Got an empty hostname"));
+ add_wrong_ip(in);
+ DBUG_RETURN(0); // Don't allow empty hostnames
+ }
+ if (!(name=my_strdup(hp->h_name,MYF(0))))
+ DBUG_RETURN(0); // out of memory
+ check=gethostbyname(name);
+ VOID(pthread_mutex_unlock(&hostname_cache->lock));
+ if (!check)
+ {
+ DBUG_PRINT("error",("gethostbyname returned %d",errno));
+ my_free(name,MYF(0));
+ DBUG_RETURN(0);
+ }
+#endif
+
+ /* Don't accept hostnames that starts with digits because they may be
+ false ip:s */
+ if (isdigit(name[0]))
+ {
+ char *pos;
+ for (pos= name+1 ; isdigit(*pos); pos++) ;
+ if (*pos == '.')
+ {
+ DBUG_PRINT("error",("mysqld doesn't accept hostnames that starts with a number followed by a '.'"));
+ my_free(name,MYF(0));
+ add_wrong_ip(in);
+ DBUG_RETURN(0);
+ }
+ }
+
+ /* Check that 'gethostbyname' returned the used ip */
+ for (uint i=0; check->h_addr_list[i]; i++)
+ {
+ if (*(uint32*)(check->h_addr_list)[i] == in->s_addr)
+ {
+ add_hostname(in,name);
+ DBUG_RETURN(name);
+ }
+ }
+ DBUG_PRINT("error",("Couldn't verify hostname with gethostbyname"));
+ my_free(name,MYF(0));
+ add_wrong_ip(in);
+ DBUG_RETURN(0);
+}
diff --git a/sql/init.cc b/sql/init.cc
new file mode 100644
index 00000000000..0103cd5038a
--- /dev/null
+++ b/sql/init.cc
@@ -0,0 +1,69 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+
+/* Init and dummy functions for interface with unireg */
+
+#include "mysql_priv.h"
+#include <m_ctype.h>
+
+void unireg_init(ulong options)
+{
+ uint i;
+ double nr;
+ DBUG_ENTER("unireg_init");
+
+ MYSYS_PROGRAM_DONT_USE_CURSES();
+ abort_loop=0;
+
+ my_disable_async_io=1; /* aioread is only in shared library */
+ wild_many='%'; wild_one='_'; wild_prefix='\\'; /* Change to sql syntax */
+
+ current_pid=(ulong) getpid(); /* Save for later ref */
+ init_time(); /* Init time-functions (read zone) */
+#ifdef USE_MY_ATOF
+ init_my_atof(); /* use our atof */
+#endif
+ my_abort_hook=unireg_abort; /* Abort with close of databases */
+ f_fyllchar=' '; /* Input fill char */
+ bfill(last_ref,MAX_REFLENGTH,(uchar) 255); /* This is indexfile-last-ref */
+
+ VOID(strmov(reg_ext,".frm"));
+ for (i=0 ; i < 6 ; i++) // YYMMDDHHMMSS
+ dayord.pos[i]=i;
+ specialflag=SPECIAL_SAME_DB_NAME;
+ blob_newline='^'; /* Convert newline in blobs to this */
+ /* Make a tab of powers of 10 */
+ for (i=0,nr=1.0; i < array_elements(log_10) ; i++)
+ { /* It's used by filesort... */
+ log_10[i]= nr ; nr*= 10.0;
+ }
+ specialflag|=options; /* Set options from argv */
+
+ // The following is needed because of like optimization in select.cc
+
+ uchar max_char=my_sort_order[(uchar) max_sort_char];
+ for (i = 0; i < 256; i++)
+ {
+ if ((uchar) my_sort_order[i] > max_char)
+ {
+ max_char=(uchar) my_sort_order[i];
+ max_sort_char= (char) i;
+ }
+ }
+ thread_stack_min=thread_stack - STACK_MIN_SIZE;
+ DBUG_VOID_RETURN;
+}
diff --git a/sql/item.cc b/sql/item.cc
new file mode 100644
index 00000000000..cc3f8101601
--- /dev/null
+++ b/sql/item.cc
@@ -0,0 +1,680 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+
+#ifdef __GNUC__
+#pragma implementation // gcc: Class implementation
+#endif
+
+#include "mysql_priv.h"
+#include <m_ctype.h>
+#include "my_dir.h"
+
+/*****************************************************************************
+** Item functions
+*****************************************************************************/
+
+/* Init all special items */
+
+void item_init(void)
+{
+ item_user_lock_init();
+}
+
+Item::Item()
+{
+ marker=0;
+ binary=maybe_null=null_value=with_sum_func=0;
+ name=0;
+ decimals=0; max_length=0;
+ next=current_thd->free_list; // Put in free list
+ current_thd->free_list=this;
+}
+
+void Item::set_name(char *str,uint length)
+{
+ if (!length)
+ name=str; // Used by AS
+ else
+ {
+ while (length && !isgraph(*str))
+ { // Fix problem with yacc
+ length--;
+ str++;
+ }
+ name=sql_strmake(str,min(length,MAX_FIELD_WIDTH));
+ }
+}
+
+bool Item::eq(const Item *item) const // Only doing this on conds
+{
+ return type() == item->type() && name && item->name &&
+ !my_strcasecmp(name,item->name);
+}
+
+/*
+ Get the value of the function as a TIME structure.
+ As a extra convenience the time structure is reset on error!
+ */
+
+bool Item::get_date(TIME *ltime,bool fuzzydate)
+{
+ char buff[40];
+ String tmp(buff,sizeof(buff)),*res;
+ if (!(res=val_str(&tmp)) ||
+ str_to_TIME(res->ptr(),res->length(),ltime,0) == TIMESTAMP_NONE)
+ {
+ bzero((char*) ltime,sizeof(*ltime));
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ Get time of first argument.
+ As a extra convenience the time structure is reset on error!
+ */
+
+bool Item::get_time(TIME *ltime)
+{
+ char buff[40];
+ String tmp(buff,sizeof(buff)),*res;
+ if (!(res=val_str(&tmp)) ||
+ str_to_time(res->ptr(),res->length(),ltime))
+ {
+ bzero((char*) ltime,sizeof(*ltime));
+ return 1;
+ }
+ return 0;
+}
+
+Item_field::Item_field(Field *f) :Item_ident(NullS,f->table_name,f->field_name)
+{
+ set_field(f);
+}
+
+
+void Item_field::set_field(Field *field_par)
+{
+ field=result_field=field_par; // for easy coding with fields
+ maybe_null=field->maybe_null();
+ max_length=field_par->field_length;
+ decimals= field->decimals();
+ table_name=field_par->table_name;
+ field_name=field_par->field_name;
+ binary=field_par->binary();
+}
+
+const char *Item_ident::full_name() const
+{
+ char *tmp;
+ if (!table_name)
+ return field_name ? field_name : name ? name : "tmp_field";
+ if (db_name)
+ {
+ tmp=(char*) sql_alloc(strlen(db_name)+strlen(table_name)+
+ strlen(field_name)+3);
+ strxmov(tmp,db_name,".",table_name,".",field_name,NullS);
+ }
+ else
+ {
+ tmp=(char*) sql_alloc(strlen(table_name)+strlen(field_name)+2);
+ strxmov(tmp,table_name,".",field_name,NullS);
+ }
+ return tmp;
+}
+
+/* ARGSUSED */
+String *Item_field::val_str(String *str)
+{
+ if ((null_value=field->is_null()))
+ return 0;
+ return field->val_str(str,&str_value);
+}
+
+double Item_field::val()
+{
+ if ((null_value=field->is_null()))
+ return 0.0;
+ return field->val_real();
+}
+
+longlong Item_field::val_int()
+{
+ if ((null_value=field->is_null()))
+ return 0;
+ return field->val_int();
+}
+
+
+String *Item_field::str_result(String *str)
+{
+ if ((null_value=result_field->is_null()))
+ return 0;
+ return result_field->val_str(str,&str_value);
+}
+
+bool Item_field::get_date(TIME *ltime,bool fuzzydate)
+{
+ if ((null_value=field->is_null()) || field->get_date(ltime,fuzzydate))
+ {
+ bzero((char*) ltime,sizeof(*ltime));
+ return 1;
+ }
+ return 0;
+}
+
+bool Item_field::get_time(TIME *ltime)
+{
+ if ((null_value=field->is_null()) || field->get_time(ltime))
+ {
+ bzero((char*) ltime,sizeof(*ltime));
+ return 1;
+ }
+ return 0;
+}
+
+double Item_field::val_result()
+{
+ if ((null_value=result_field->is_null()))
+ return 0.0;
+ return result_field->val_real();
+}
+
+longlong Item_field::val_int_result()
+{
+ if ((null_value=result_field->is_null()))
+ return 0;
+ return result_field->val_int();
+}
+
+bool Item_field::eq(const Item *item) const
+{
+ return item->type() == FIELD_ITEM && ((Item_field*) item)->field == field;
+}
+
+table_map Item_field::used_tables() const
+{
+ if (field->table->const_table)
+ return 0; // const item
+ return field->table->map;
+}
+
+
+String *Item_int::val_str(String *str)
+{
+ str->set(value);
+ return str;
+}
+
+void Item_int::print(String *str)
+{
+ if (!name)
+ {
+ str_value.set(value);
+ name=str_value.c_ptr();
+ }
+ str->append(name);
+}
+
+
+String *Item_real::val_str(String *str)
+{
+ str->set(value,decimals);
+ return str;
+}
+
+void Item_string::print(String *str)
+{
+ str->append('\'');
+ str->append(full_name());
+ str->append('\'');
+}
+
+bool Item_null::eq(const Item *item) const { return item->type() == type(); }
+double Item_null::val() { null_value=1; return 0.0; }
+longlong Item_null::val_int() { null_value=1; return 0; }
+/* ARGSUSED */
+String *Item_null::val_str(String *str)
+{ null_value=1; return 0;}
+
+
+void Item_copy_string::copy()
+{
+ String *res=item->val_str(&str_value);
+ if (res && res != &str_value)
+ str_value.copy(*res);
+ null_value=item->null_value;
+}
+
+/* ARGSUSED */
+String *Item_copy_string::val_str(String *str)
+{
+ if (null_value)
+ return (String*) 0;
+ return &str_value;
+}
+
+/*
+** Functions to convert item to field (for send_fields)
+*/
+
+/* ARGSUSED */
+bool Item::fix_fields(THD *thd,
+ struct st_table_list *list)
+{
+ return 0;
+}
+
+bool Item_field::fix_fields(THD *thd,TABLE_LIST *tables)
+{
+ if (!field)
+ {
+ Field *tmp;
+ if (!(tmp=find_field_in_tables(thd,this,tables)))
+ return 1;
+ set_field(tmp);
+ }
+ return 0;
+}
+
+
+void Item::init_make_field(Send_field *tmp_field,
+ enum enum_field_types field_type)
+{
+ tmp_field->table_name=(char*) "";
+ tmp_field->col_name=name;
+ tmp_field->flags=maybe_null ? 0 : NOT_NULL_FLAG;
+ tmp_field->type=field_type;
+ tmp_field->length=max_length;
+ tmp_field->decimals=decimals;
+}
+
+/* ARGSUSED */
+void Item_field::make_field(Send_field *tmp_field)
+{
+ field->make_field(tmp_field);
+ if (name)
+ tmp_field->col_name=name; // Use user supplied name
+}
+
+void Item_int::make_field(Send_field *tmp_field)
+{
+ init_make_field(tmp_field,FIELD_TYPE_LONGLONG);
+}
+
+void Item_real::make_field(Send_field *tmp_field)
+{
+ init_make_field(tmp_field,FIELD_TYPE_DOUBLE);
+}
+
+void Item_string::make_field(Send_field *tmp_field)
+{
+ init_make_field(tmp_field,FIELD_TYPE_STRING);
+}
+
+void Item_datetime::make_field(Send_field *tmp_field)
+{
+ init_make_field(tmp_field,FIELD_TYPE_DATETIME);
+}
+
+void Item_null::make_field(Send_field *tmp_field)
+{
+ init_make_field(tmp_field,FIELD_TYPE_NULL);
+ tmp_field->length=4;
+}
+
+void Item_func::make_field(Send_field *tmp_field)
+{
+ init_make_field(tmp_field, ((result_type() == STRING_RESULT) ?
+ FIELD_TYPE_VAR_STRING :
+ (result_type() == INT_RESULT) ?
+ FIELD_TYPE_LONGLONG : FIELD_TYPE_DOUBLE));
+}
+
+void Item_avg_field::make_field(Send_field *tmp_field)
+{
+ init_make_field(tmp_field,FIELD_TYPE_DOUBLE);
+}
+
+void Item_std_field::make_field(Send_field *tmp_field)
+{
+ init_make_field(tmp_field,FIELD_TYPE_DOUBLE);
+}
+
+/*
+** Set a field:s value from a item
+*/
+
+
+void Item_field::save_org_in_field(Field *to)
+{
+ if (field->is_null())
+ {
+ null_value=1;
+ set_field_to_null(to);
+ }
+ else
+ {
+ to->set_notnull();
+ field_conv(to,field);
+ null_value=0;
+ }
+}
+
+bool Item_field::save_in_field(Field *to)
+{
+ if (result_field->is_null())
+ {
+ null_value=1;
+ return set_field_to_null(to);
+ }
+ else
+ {
+ to->set_notnull();
+ field_conv(to,result_field);
+ null_value=0;
+ }
+ return 0;
+}
+
+
+bool Item_null::save_in_field(Field *field)
+{
+ return set_field_to_null(field);
+}
+
+
+bool Item::save_in_field(Field *field)
+{
+ if (result_type() == STRING_RESULT ||
+ result_type() == REAL_RESULT &&
+ field->result_type() == STRING_RESULT)
+ {
+ String *result;
+ char buff[MAX_FIELD_WIDTH]; // Alloc buffer for small columns
+ str_value.set_quick(buff,sizeof(buff));
+ result=val_str(&str_value);
+ if (null_value)
+ return set_field_to_null(field);
+ field->set_notnull();
+ field->store(result->ptr(),result->length());
+ str_value.set_quick(0, 0);
+ }
+ else if (result_type() == REAL_RESULT)
+ {
+ double nr=val();
+ if (null_value)
+ return set_field_to_null(field);
+ field->set_notnull();
+ field->store(nr);
+ }
+ else
+ {
+ longlong nr=val_int();
+ if (null_value)
+ return set_field_to_null(field);
+ field->set_notnull();
+ field->store(nr);
+ }
+ return 0;
+}
+
+bool Item_string::save_in_field(Field *field)
+{
+ String *result;
+ result=val_str(&str_value);
+ if (null_value)
+ return set_field_to_null(field);
+ field->set_notnull();
+ field->store(result->ptr(),result->length());
+ return 0;
+}
+
+bool Item_int::save_in_field(Field *field)
+{
+ longlong nr=val_int();
+ if (null_value)
+ return set_field_to_null(field);
+ field->set_notnull();
+ field->store(nr);
+ return 0;
+}
+
+bool Item_real::save_in_field(Field *field)
+{
+ double nr=val();
+ if (null_value)
+ return set_field_to_null(field);
+ field->set_notnull();
+ field->store(nr);
+ return 0;
+}
+
+/****************************************************************************
+** varbinary item
+** In string context this is a binary string
+** In number context this is a longlong value.
+****************************************************************************/
+
+static inline uint char_val(char X)
+{
+ return (uint) (X >= '0' && X <= '9' ? X-'0' :
+ X >= 'A' && X <= 'Z' ? X-'A'+10 :
+ X-'a'+10);
+}
+
+Item_varbinary::Item_varbinary(const char *str, uint str_length)
+{
+ name=(char*) str-2; // Lex makes this start with 0x
+ max_length=(str_length+1)/2;
+ char *ptr=(char*) sql_alloc(max_length+1);
+ if (!ptr)
+ return;
+ str_value.set(ptr,max_length);
+ char *end=ptr+max_length;
+ if (max_length*2 != str_length)
+ *ptr++=char_val(*str++); // Not even, assume 0 prefix
+ while (ptr != end)
+ {
+ *ptr++= (char) (char_val(str[0])*16+char_val(str[1]));
+ str+=2;
+ }
+ *ptr=0; // Keep purify happy
+ binary=1; // Binary is default
+}
+
+longlong Item_varbinary::val_int()
+{
+ char *end=(char*) str_value.ptr()+str_value.length(),
+ *ptr=end-min(str_value.length(),sizeof(longlong));
+
+ ulonglong value=0;
+ for (; ptr != end ; ptr++)
+ value=(value << 8)+ (ulonglong) (uchar) *ptr;
+ return (longlong) value;
+}
+
+
+bool Item_varbinary::save_in_field(Field *field)
+{
+ field->set_notnull();
+ if (field->result_type() == STRING_RESULT)
+ {
+ field->store(str_value.ptr(),str_value.length());
+ }
+ else
+ {
+ longlong nr=val_int();
+ field->store(nr);
+ }
+ return 0;
+}
+
+
+void Item_varbinary::make_field(Send_field *tmp_field)
+{
+ init_make_field(tmp_field,FIELD_TYPE_STRING);
+}
+
+/*
+** pack data in buffer for sending
+*/
+
+bool Item::send(String *packet)
+{
+ char buff[MAX_FIELD_WIDTH];
+ String s(buff,sizeof(buff)),*res;
+ if (!(res=val_str(&s)))
+ return net_store_null(packet);
+ CONVERT *convert;
+ if ((convert=current_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)
+{
+ return net_store_null(packet);
+}
+
+/*
+ This is used for HAVING clause
+ Find field in select list having the same name
+ */
+
+bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables)
+{
+ if (!ref)
+ {
+ if (!(ref=find_item_in_list(this,thd->lex.item_list)))
+ return 1;
+ max_length= (*ref)->max_length;
+ maybe_null= (*ref)->maybe_null;
+ decimals= (*ref)->decimals;
+ binary= (*ref)->binary;
+ }
+ return 0;
+}
+
+/*
+** If item is a const function, calculate it and return a const item
+** The original item is freed if not returned
+*/
+
+Item_result item_cmp_type(Item_result a,Item_result b)
+{
+ if (a == STRING_RESULT && b == STRING_RESULT)
+ return STRING_RESULT;
+ else if (a == INT_RESULT && b == INT_RESULT)
+ return INT_RESULT;
+ else
+ return REAL_RESULT;
+}
+
+
+Item *resolve_const_item(Item *item,Item *comp_item)
+{
+ if (item->basic_const_item())
+ return item; // Can't be better
+ Item_result res_type=item_cmp_type(comp_item->result_type(),
+ item->result_type());
+ char *name=item->name; // Alloced by sql_alloc
+
+ if (res_type == STRING_RESULT)
+ {
+ char buff[MAX_FIELD_WIDTH];
+ String tmp(buff,sizeof(buff)),*result;
+ result=item->val_str(&tmp);
+ if (item->null_value)
+ {
+#ifdef DELETE_ITEMS
+ delete item;
+#endif
+ return new Item_null(name);
+ }
+ uint length=result->length();
+ char *tmp_str=sql_strmake(result->ptr(),length);
+#ifdef DELETE_ITEMS
+ delete item;
+#endif
+ return new Item_string(name,tmp_str,length);
+ }
+ if (res_type == INT_RESULT)
+ {
+ longlong result=item->val_int();
+ uint length=item->max_length;
+ bool null_value=item->null_value;
+#ifdef DELETE_ITEMS
+ delete item;
+#endif
+ return (null_value ? (Item*) new Item_null(name) :
+ (Item*) new Item_int(name,result,length));
+ }
+ else
+ { // It must REAL_RESULT
+ double result=item->val();
+ uint length=item->max_length,decimals=item->decimals;
+ bool null_value=item->null_value;
+#ifdef DELETE_ITEMS
+ delete item;
+#endif
+ return (null_value ? (Item*) new Item_null(name) :
+ (Item*) new Item_real(name,result,decimals,length));
+ }
+}
+
+/*
+ Return true if the value stored in the field is equal to the const item
+ We need to use this on the range optimizer because in some cases
+ we can't store the value in the field without some precision/character loss.
+*/
+
+bool field_is_equal_to_item(Field *field,Item *item)
+{
+
+ Item_result res_type=item_cmp_type(field->result_type(),
+ item->result_type());
+ if (res_type == STRING_RESULT)
+ {
+ char item_buff[MAX_FIELD_WIDTH];
+ char field_buff[MAX_FIELD_WIDTH];
+ String item_tmp(item_buff,sizeof(item_buff)),*item_result;
+ String field_tmp(field_buff,sizeof(field_buff));
+ item_result=item->val_str(&item_tmp);
+ if (item->null_value)
+ return 1; // This must be true
+ field->val_str(&field_tmp,&field_tmp);
+ return !stringcmp(&field_tmp,item_result);
+ }
+ if (res_type == INT_RESULT)
+ return 1; // Both where of type int
+ double result=item->val();
+ if (item->null_value)
+ return 1;
+ return result == field->val_real();
+}
+
+
+/*****************************************************************************
+** Instantiate templates
+*****************************************************************************/
+
+#ifdef __GNUC__
+template class List<Item>;
+template class List_iterator<Item>;
+template class List<List_item>;
+#endif
diff --git a/sql/item.h b/sql/item.h
new file mode 100644
index 00000000000..bce9c6600ef
--- /dev/null
+++ b/sql/item.h
@@ -0,0 +1,432 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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
+
+struct st_table_list;
+void item_init(void); /* Init item functions */
+
+class Item {
+ Item(const Item &); /* Prevent use of theese */
+ void operator=(Item &);
+public:
+ static void *operator new(size_t size) {return (void*) sql_alloc(size); }
+ static void operator delete(void *ptr,size_t size) {} /*lint -e715 */
+
+ enum Type {FIELD_ITEM,FUNC_ITEM,SUM_FUNC_ITEM,STRING_ITEM,
+ INT_ITEM,REAL_ITEM,NULL_ITEM,VARBIN_ITEM,
+ COPY_STR_ITEM,FIELD_AVG_ITEM,
+ PROC_ITEM,COND_ITEM,REF_ITEM,FIELD_STD_ITEM, CONST_ITEM};
+ enum cond_result { COND_UNDEF,COND_OK,COND_TRUE,COND_FALSE };
+
+ String str_value; /* used to store value */
+ my_string name; /* Name from select */
+ Item *next;
+ uint32 max_length;
+ uint8 marker,decimals;
+ my_bool maybe_null; /* If item may be null */
+ my_bool null_value; /* if item is null */
+ my_bool binary;
+ my_bool with_sum_func;
+
+
+ // alloc & destruct is done as start of select using sql_alloc
+ Item();
+ virtual ~Item() { name=0; } /*lint -e1509 */
+ void set_name(char* str,uint length=0);
+ void init_make_field(Send_field *tmp_field,enum enum_field_types type);
+ virtual bool fix_fields(THD *,struct st_table_list *);
+ 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 eq(const Item *) const;
+ virtual Item_result result_type () const { return REAL_RESULT; }
+ virtual enum Type type() const =0;
+ virtual double val()=0;
+ 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 const char *full_name() const { return name ? name : "???"; }
+ virtual double val_result() { return val(); }
+ virtual longlong val_int_result() { return val_int(); }
+ virtual String *str_result(String* tmp) { return val_str(tmp); }
+ virtual table_map used_tables() const { return (table_map) 0L; }
+ virtual bool basic_const_item() const { return 0; }
+ virtual Item *new_item() { return 0; } /* Only for const items */
+ virtual cond_result eq_cmp_result() const { return COND_OK; }
+ inline uint float_length(uint decimals_par) const
+ { return decimals != NOT_FIXED_DEC ? (DBL_DIG+2+decimals_par) : DBL_DIG+8;}
+ virtual bool const_item() const { return used_tables() == 0; }
+ virtual void print(String *str_arg) { str_arg->append(full_name()); }
+ virtual void update_used_tables() {}
+ virtual void split_sum_func(List<Item> &fields) {}
+ virtual bool get_date(TIME *ltime,bool fuzzydate);
+ virtual bool get_time(TIME *ltime);
+};
+
+
+class Item_ident :public Item
+{
+public:
+ const char *db_name;
+ const char *table_name;
+ const char *field_name;
+ Item_ident(const char *db_name_par,const char *table_name_par,
+ const char *field_name_par)
+ :db_name(db_name_par),table_name(table_name_par),field_name(field_name_par)
+ { name = (char*) field_name_par; }
+ const char *full_name() const;
+};
+
+class Item_field :public Item_ident
+{
+ void set_field(Field *field);
+public:
+ Field *field,*result_field;
+ // Item_field() {}
+
+ Item_field(const char *db_par,const char *table_name_par,
+ const char *field_name_par)
+ :Item_ident(db_par,table_name_par,field_name_par),field(0),result_field(0)
+ {}
+ Item_field(Field *field);
+ enum Type type() const { return FIELD_ITEM; }
+ bool eq(const Item *item) const;
+ double val();
+ longlong val_int();
+ String *val_str(String*);
+ double val_result();
+ longlong val_int_result();
+ String *str_result(String* tmp);
+ bool send(String *str_arg) { return result_field->send(str_arg); }
+ void make_field(Send_field *field);
+ bool fix_fields(THD *,struct st_table_list *);
+ bool save_in_field(Field *field);
+ void save_org_in_field(Field *field);
+ table_map used_tables() const;
+ enum Item_result result_type () const
+ {
+ return field->result_type();
+ }
+ Field *tmp_table_field() { return result_field; }
+ bool get_date(TIME *ltime,bool fuzzydate);
+ bool get_time(TIME *ltime);
+};
+
+
+class Item_null :public Item
+{
+public:
+ Item_null(char *name_par=0)
+ { maybe_null=null_value=TRUE; name= name_par ? name_par : (char*) "NULL";}
+ enum Type type() const { return NULL_ITEM; }
+ bool eq(const Item *item) const;
+ double val();
+ longlong val_int();
+ String *val_str(String *str);
+ void make_field(Send_field *field);
+ bool save_in_field(Field *field);
+ enum Item_result result_type () const
+ { return STRING_RESULT; }
+ bool send(String *str);
+ bool basic_const_item() const { return 1; }
+ Item *new_item() { return new Item_null(name); }
+};
+
+
+class Item_int :public Item
+{
+public:
+ const longlong value;
+ Item_int(int32 i,uint length=11) :value((longlong) i)
+ { max_length=length;}
+#ifdef HAVE_LONG_LONG
+ Item_int(longlong i,uint length=21) :value(i)
+ { max_length=length;}
+#endif
+ Item_int(const char *str_arg,longlong i,uint length) :value(i)
+ { max_length=length; name=(char*) str_arg;}
+ Item_int(const char *str_arg) :
+ value(str_arg[0] == '-' ? strtoll(str_arg,(char**) 0,10) :
+ (longlong) strtoull(str_arg,(char**) 0,10))
+ { max_length=strlen(str_arg); name=(char*) str_arg;}
+ enum Type type() const { return INT_ITEM; }
+ virtual enum Item_result result_type () const { return INT_RESULT; }
+ longlong val_int() { return value; }
+ double val() { return (double) value; }
+ String *val_str(String*);
+ void make_field(Send_field *field);
+ bool save_in_field(Field *field);
+ bool basic_const_item() const { return 1; }
+ Item *new_item() { return new Item_int(name,value,max_length); }
+ void print(String *str);
+};
+
+
+class Item_real :public Item
+{
+public:
+ const double value;
+ // Item_real() :value(0) {}
+ Item_real(const char *str_arg,uint length) :value(atof(str_arg))
+ {
+ name=(char*) str_arg;
+ decimals=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;
+ max_length=length;
+ }
+ Item_real(double value_par) :value(value_par) {}
+ bool save_in_field(Field *field);
+ enum Type type() const { return REAL_ITEM; }
+ double val() { return value; }
+ longlong val_int() { return (longlong) (value+(value > 0 ? 0.5 : -0.5));}
+ String *val_str(String*);
+ void make_field(Send_field *field);
+ bool basic_const_item() const { return 1; }
+ Item *new_item() { return new Item_real(name,value,decimals,max_length); }
+};
+
+
+class Item_float :public Item_real
+{
+public:
+ Item_float(const char *str,uint length) :Item_real(str,length)
+ {
+ decimals=NOT_FIXED_DEC;
+ max_length=DBL_DIG+8;
+ }
+};
+
+class Item_string :public Item
+{
+public:
+ Item_string(const char *str,uint length)
+ {
+ str_value.set(str,length);
+ max_length=length;
+ name=(char*) str_value.ptr();
+ decimals=NOT_FIXED_DEC;
+ }
+ Item_string(const char *name_par,const char *str,uint length)
+ {
+ str_value.set(str,length);
+ max_length=length;
+ name=(char*) name_par;
+ decimals=NOT_FIXED_DEC;
+ }
+ ~Item_string() {}
+ enum Type type() const { return STRING_ITEM; }
+ double val() { return atof(str_value.ptr()); }
+ longlong val_int() { return strtoll(str_value.ptr(),(char**) 0,10); }
+ String *val_str(String*) { return (String*) &str_value; }
+ bool save_in_field(Field *field);
+ void make_field(Send_field *field);
+ enum Item_result result_type () const { return STRING_RESULT; }
+ bool basic_const_item() const { return 1; }
+ Item *new_item() { return new Item_string(name,str_value.ptr(),max_length); }
+ String *const_string() { return &str_value; }
+ inline void append(char *str,uint length) { str_value.append(str,length); }
+ void print(String *str);
+};
+
+/* for show tables */
+
+class Item_datetime :public Item_string
+{
+public:
+ Item_datetime(const char *item_name): Item_string(item_name,"",0)
+ { max_length=19;}
+ void make_field(Send_field *field);
+};
+
+class Item_empty_string :public Item_string
+{
+public:
+ Item_empty_string(const char *header,uint length) :Item_string("",0)
+ { name=(char*) header; max_length=length;}
+};
+
+class Item_varbinary :public Item
+{
+public:
+ Item_varbinary(const char *str,uint str_length);
+ ~Item_varbinary() {}
+ enum Type type() const { return VARBIN_ITEM; }
+ double val() { return (double) Item_varbinary::val_int(); }
+ longlong val_int();
+ String *val_str(String*) { return &str_value; }
+ bool save_in_field(Field *field);
+ void make_field(Send_field *field);
+ enum Item_result result_type () const { return INT_RESULT; }
+};
+
+
+class Item_result_field :public Item /* Item with result field */
+{
+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; }
+ virtual void fix_length_and_dec()=0;
+};
+
+
+class Item_ref :public Item_ident
+{
+ Item **ref;
+public:
+ Item_ref(char *db_par,char *table_name_par,char *field_name_par)
+ :Item_ident(db_par,table_name_par,field_name_par),ref(0) {}
+ Item_ref(Item **item, char *table_name_par,char *field_name_par)
+ :Item_ident(NullS,table_name_par,field_name_par),ref(item) {}
+ enum Type type() const { return REF_ITEM; }
+ bool eq(const Item *item) const { return (*ref)->eq(item); }
+ ~Item_ref() { if (ref) delete *ref; }
+ double val()
+ {
+ double tmp=(*ref)->val_result();
+ null_value=(*ref)->null_value;
+ return tmp;
+ }
+ longlong val_int()
+ {
+ longlong tmp=(*ref)->val_int_result();
+ null_value=(*ref)->null_value;
+ return tmp;
+ }
+ String *val_str(String* tmp)
+ {
+ tmp=(*ref)->str_result(tmp);
+ null_value=(*ref)->null_value;
+ return tmp;
+ }
+ bool get_date(TIME *ltime,bool fuzzydate)
+ {
+ return (null_value=(*ref)->get_date(ltime,fuzzydate));
+ }
+ bool send(String *tmp) { return (*ref)->send(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); }
+ void save_org_in_field(Field *field) { (*ref)->save_org_in_field(field); }
+ enum Item_result result_type () const { return (*ref)->result_type(); }
+ table_map used_tables() const { return (*ref)->used_tables(); }
+};
+
+
+#include "item_sum.h"
+#include "item_func.h"
+#include "item_cmpfunc.h"
+#include "item_strfunc.h"
+#include "item_timefunc.h"
+#include "item_uniq.h"
+
+class Item_copy_string :public Item
+{
+public:
+ Item *item;
+ Item_copy_string(Item *i) :item(i)
+ {
+ null_value=maybe_null=item->maybe_null;
+ decimals=item->decimals;
+ max_length=item->max_length;
+ name=item->name;
+ }
+ ~Item_copy_string() { delete item; }
+ enum Type type() const { return COPY_STR_ITEM; }
+ enum Item_result result_type () const { return STRING_RESULT; }
+ double val()
+ { return null_value ? 0.0 : atof(str_value.c_ptr()); }
+ longlong val_int()
+ { return null_value ? LL(0) : strtoll(str_value.c_ptr(),(char**) 0,10); }
+ String *val_str(String*);
+ void make_field(Send_field *field) { item->make_field(field); }
+ void copy();
+ table_map used_tables() const { return (table_map) 1L; }
+ bool const_item() const { return 0; }
+};
+
+
+class Item_buff :public Sql_alloc
+{
+public:
+ my_bool null_value;
+ Item_buff() :null_value(0) {}
+ virtual bool cmp(void)=0;
+ virtual ~Item_buff(); /*line -e1509 */
+};
+
+class Item_str_buff :public Item_buff
+{
+ Item *item;
+ String value,tmp_value;
+public:
+ Item_str_buff(Item *arg) :item(arg),value(arg->max_length) {}
+ bool cmp(void);
+ ~Item_str_buff(); // Deallocate String:s
+};
+
+
+class Item_real_buff :public Item_buff
+{
+ Item *item;
+ double value;
+public:
+ Item_real_buff(Item *item_par) :item(item_par),value(0.0) {}
+ bool cmp(void);
+};
+
+class Item_int_buff :public Item_buff
+{
+ Item *item;
+ longlong value;
+public:
+ Item_int_buff(Item *item_par) :item(item_par),value(0) {}
+ bool cmp(void);
+};
+
+
+class Item_field_buff :public Item_buff
+{
+ char *buff;
+ Field *field;
+ uint length;
+
+public:
+ Item_field_buff(Item_field *item)
+ {
+ field=item->field;
+ buff= (char*) sql_calloc(length=field->pack_length());
+ }
+ bool cmp(void);
+};
+
+extern Item_buff *new_Item_buff(Item *item);
+extern Item_result item_cmp_type(Item_result a,Item_result b);
+extern Item *resolve_const_item(Item *item,Item *cmp_item);
+extern bool field_is_equal_to_item(Field *field,Item *item);
diff --git a/sql/item_buff.cc b/sql/item_buff.cc
new file mode 100644
index 00000000000..61e1f5498a9
--- /dev/null
+++ b/sql/item_buff.cc
@@ -0,0 +1,119 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+
+/* Buffers to save and compare item values */
+
+#include "mysql_priv.h"
+
+/*
+** Create right type of item_buffer for an item
+*/
+
+Item_buff *new_Item_buff(Item *item)
+{
+ if (item->type() == Item::FIELD_ITEM &&
+ !(((Item_field *) item)->field->flags & BLOB_FLAG))
+ return new Item_field_buff((Item_field *) item);
+ if (item->result_type() == STRING_RESULT)
+ return new Item_str_buff((Item_field *) item);
+ if (item->result_type() == INT_RESULT)
+ return new Item_int_buff((Item_field *) item);
+ return new Item_real_buff(item);
+}
+
+Item_buff::~Item_buff() {}
+
+/*
+** Compare with old value and replace value with new value
+** Return true if values have changed
+*/
+
+bool Item_str_buff::cmp(void)
+{
+ String *res;
+ bool tmp;
+
+ res=item->val_str(&tmp_value);
+ if (null_value != item->null_value)
+ {
+ if ((null_value= item->null_value))
+ return TRUE; // New value was null
+ tmp=TRUE;
+ }
+ else if (null_value)
+ return 0; // new and old value was null
+ else if (!item->binary)
+ tmp= sortcmp(&value,res) != 0;
+ else
+ tmp= stringcmp(&value,res) != 0;
+ if (tmp)
+ value.copy(*res); // Remember for next cmp
+ return tmp;
+}
+
+Item_str_buff::~Item_str_buff()
+{
+ item=0; // Safety
+}
+
+bool Item_real_buff::cmp(void)
+{
+ double nr=item->val();
+ if (null_value != item->null_value || nr != value)
+ {
+ null_value= item->null_value;
+ value=nr;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+bool Item_int_buff::cmp(void)
+{
+ longlong nr=item->val_int();
+ if (null_value != item->null_value || nr != value)
+ {
+ null_value= item->null_value;
+ value=nr;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+bool Item_field_buff::cmp(void)
+{
+ bool tmp= field->cmp(buff) != 0; // This is not a blob!
+ if (tmp)
+ field->get_image(buff,length);
+ if (null_value != field->is_null())
+ {
+ null_value= !null_value;
+ tmp=TRUE;
+ }
+ return tmp;
+}
+
+
+/*****************************************************************************
+** Instansiate templates
+*****************************************************************************/
+
+#ifdef __GNUC__
+template class List<Item_buff>;
+template class List_iterator<Item_buff>;
+#endif
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
new file mode 100644
index 00000000000..0a75998ffe1
--- /dev/null
+++ b/sql/item_cmpfunc.cc
@@ -0,0 +1,1298 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 defines all compare functions */
+
+#ifdef __GNUC__
+#pragma implementation // gcc: Class implementation
+#endif
+
+#include "mysql_priv.h"
+#include <m_ctype.h>
+
+/*
+** Test functions
+** These returns 0LL if false and 1LL if true and null if some arg is null
+** 'AND' and 'OR' never return null
+*/
+
+longlong Item_func_not::val_int()
+{
+ double value=args[0]->val();
+ null_value=args[0]->null_value;
+ return !null_value && value == 0 ? 1 : 0;
+}
+
+
+static bool convert_constant_item(Field *field, Item **item)
+{
+ if ((*item)->const_item())
+ {
+ (*item)->save_in_field(field);
+ if (!((*item)->null_value))
+ {
+ Item *tmp=new Item_int(field->val_int());
+ if ((tmp))
+ *item=tmp;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+
+void Item_bool_func2::fix_length_and_dec()
+{
+ max_length=1;
+
+ /* As some compare functions are generated after sql_yacc,
+ we have to check for out of memory conditons here */
+ if (!args[0] || !args[1])
+ return;
+ // Make a special case of compare with fields to get nicer DATE comparisons
+ if (args[0]->type() == FIELD_ITEM)
+ {
+ Field *field=((Item_field*) args[0])->field;
+ if (field->store_for_compare())
+ {
+ if (convert_constant_item(field,&args[1]))
+ {
+ cmp_func= &Item_bool_func2::compare_int; // Works for all types.
+ return;
+ }
+ }
+ }
+ if (args[1]->type() == FIELD_ITEM)
+ {
+ Field *field=((Item_field*) args[1])->field;
+ if (field->store_for_compare())
+ {
+ if (convert_constant_item(field,&args[0]))
+ {
+ cmp_func= &Item_bool_func2::compare_int; // Works for all types.
+ return;
+ }
+ }
+ }
+ set_cmp_func(item_cmp_type(args[0]->result_type(),args[1]->result_type()));
+}
+
+
+void Item_bool_func2::set_cmp_func(Item_result type)
+{
+ switch (type) {
+ case STRING_RESULT:
+ cmp_func=&Item_bool_func2::compare_string;
+ break;
+ case REAL_RESULT:
+ cmp_func=&Item_bool_func2::compare_real;
+ break;
+ case INT_RESULT:
+ cmp_func=&Item_bool_func2::compare_int;
+ break;
+ }
+}
+
+
+int Item_bool_func2::compare_string()
+{
+ String *res1,*res2;
+ if ((res1=args[0]->val_str(&tmp_value1)))
+ {
+ if ((res2=args[1]->val_str(&tmp_value2)))
+ {
+ null_value=0;
+ return binary ? stringcmp(res1,res2) : sortcmp(res1,res2);
+ }
+ }
+ null_value=1;
+ return -1;
+}
+
+int Item_bool_func2::compare_real()
+{
+ double val1=args[0]->val();
+ if (!args[0]->null_value)
+ {
+ double val2=args[1]->val();
+ if (!args[1]->null_value)
+ {
+ null_value=0;
+ if (val1 < val2) return -1;
+ if (val1 == val2) return 0;
+ return 1;
+ }
+ }
+ null_value=1;
+ return -1;
+}
+
+
+int Item_bool_func2::compare_int()
+{
+ longlong val1=args[0]->val_int();
+ if (!args[0]->null_value)
+ {
+ longlong val2=args[1]->val_int();
+ if (!args[1]->null_value)
+ {
+ null_value=0;
+ if (val1 < val2) return -1;
+ if (val1 == val2) return 0;
+ return 1;
+ }
+ }
+ null_value=1;
+ return -1;
+}
+
+
+
+longlong Item_func_eq::val_int()
+{
+ int value=(this->*cmp_func)();
+ return value == 0 ? 1 : 0;
+}
+
+/* Same as Item_func_eq, but NULL = NULL */
+
+longlong Item_func_equal::val_int()
+{
+ int value=(this->*cmp_func)();
+ if (null_value)
+ {
+ null_value=0;
+ return (args[0]->null_value && args[1]->null_value) ? 1 : 0;
+ }
+ return value == 0;
+}
+
+
+longlong Item_func_ne::val_int()
+{
+ int value=(this->*cmp_func)();
+ return value != 0 ? 1 : 0;
+}
+
+
+longlong Item_func_ge::val_int()
+{
+ int value=(this->*cmp_func)();
+ return value >= 0 ? 1 : 0;
+}
+
+
+longlong Item_func_gt::val_int()
+{
+ int value=(this->*cmp_func)();
+ return value > 0 ? 1 : 0;
+}
+
+longlong Item_func_le::val_int()
+{
+ int value=(this->*cmp_func)();
+ return value <= 0 && !null_value ? 1 : 0;
+}
+
+
+longlong Item_func_lt::val_int()
+{
+ int value=(this->*cmp_func)();
+ return value < 0 && !null_value ? 1 : 0;
+}
+
+
+longlong Item_func_strcmp::val_int()
+{
+ String *a=args[0]->val_str(&tmp_value1);
+ String *b=args[1]->val_str(&tmp_value2);
+ if (!a || !b)
+ {
+ null_value=1;
+ return 0;
+ }
+ int value=stringcmp(a,b);
+ null_value=0;
+ return !value ? 0 : (value < 0 ? (longlong) -1 : (longlong) 1);
+}
+
+
+void Item_func_interval::fix_length_and_dec()
+{
+ bool nums=1;
+ uint i;
+ for (i=0 ; i < arg_count ; i++)
+ {
+ if (!args[i])
+ return; // End of memory
+ if (args[i]->type() != Item::INT_ITEM &&
+ args[i]->type() != Item::REAL_ITEM)
+ {
+ nums=0;
+ break;
+ }
+ }
+ if (nums && arg_count >= 8)
+ {
+ if ((intervals=(double*) sql_alloc(sizeof(double)*arg_count)))
+ {
+ for (i=0 ; i < arg_count ; i++)
+ intervals[i]=args[i]->val();
+ }
+ }
+ maybe_null=0; max_length=2;
+ used_tables_cache|=item->used_tables();
+}
+
+/*
+ return -1 if null value,
+ 0 if lower than lowest
+ 1 - arg_count if between args[n] and args[n+1]
+ arg_count+1 if higher than biggest argument
+*/
+
+longlong Item_func_interval::val_int()
+{
+ double value=item->val();
+ if (item->null_value)
+ return -1; // -1 if null /* purecov: inspected */
+ if (intervals)
+ { // Use binary search to find interval
+ uint start,end;
+ start=0; end=arg_count-1;
+ while (start != end)
+ {
+ uint mid=(start+end+1)/2;
+ if (intervals[mid] <= value)
+ start=mid;
+ else
+ end=mid-1;
+ }
+ return (value < intervals[start]) ? 0 : start+1;
+ }
+ if (args[0]->val() > value)
+ return 0;
+ for (uint i=1 ; i < arg_count ; i++)
+ {
+ if (args[i]->val() > value)
+ return i;
+ }
+ return (longlong) arg_count;
+}
+
+
+void Item_func_interval::update_used_tables()
+{
+ Item_func::update_used_tables();
+ item->update_used_tables();
+ used_tables_cache|=item->used_tables();
+ const_item_cache&=item->const_item();
+}
+
+void Item_func_between::fix_length_and_dec()
+{
+ max_length=1;
+
+ /* As some compare functions are generated after sql_yacc,
+ we have to check for out of memory conditons here */
+ if (!args[0] || !args[1] || !args[2])
+ return;
+ cmp_type=args[0]->result_type();
+ if (args[0]->binary)
+ string_compare=stringcmp;
+ else
+ string_compare=sortcmp;
+
+ // Make a special case of compare with fields to get nicer DATE comparisons
+ if (args[0]->type() == FIELD_ITEM)
+ {
+ Field *field=((Item_field*) args[0])->field;
+ if (field->store_for_compare())
+ {
+ if (convert_constant_item(field,&args[1]))
+ cmp_type=INT_RESULT; // Works for all types.
+ if (convert_constant_item(field,&args[2]))
+ cmp_type=INT_RESULT; // Works for all types.
+ }
+ }
+}
+
+
+longlong Item_func_between::val_int()
+{ // ANSI BETWEEN
+ if (cmp_type == STRING_RESULT)
+ {
+ String *value,*a,*b;
+ value=args[0]->val_str(&value0);
+ if ((null_value=args[0]->null_value))
+ return 0;
+ a=args[1]->val_str(&value1);
+ b=args[2]->val_str(&value2);
+ if (!args[1]->null_value && !args[2]->null_value)
+ return (string_compare(value,a) >= 0 && string_compare(value,b) <= 0) ?
+ 1 : 0;
+ if (args[1]->null_value && args[2]->null_value)
+ null_value=1;
+ else if (args[1]->null_value)
+ {
+ null_value= string_compare(value,b) <= 0; // not null if false range.
+ }
+ else
+ {
+ null_value= string_compare(value,a) >= 0; // not null if false range.
+ }
+ }
+ else if (cmp_type == INT_RESULT)
+ {
+ longlong value=args[0]->val_int(),a,b;
+ if ((null_value=args[0]->null_value))
+ return 0; /* purecov: inspected */
+ a=args[1]->val_int();
+ b=args[2]->val_int();
+ if (!args[1]->null_value && !args[2]->null_value)
+ return (value >= a && value <= b) ? 1 : 0;
+ if (args[1]->null_value && args[2]->null_value)
+ null_value=1;
+ else if (args[1]->null_value)
+ {
+ null_value= value <= b; // not null if false range.
+ }
+ else
+ {
+ null_value= value >= a;
+ }
+ }
+ else
+ {
+ double value=args[0]->val(),a,b;
+ if ((null_value=args[0]->null_value))
+ return 0; /* purecov: inspected */
+ a=args[1]->val();
+ b=args[2]->val();
+ if (!args[1]->null_value && !args[2]->null_value)
+ return (value >= a && value <= b) ? 1 : 0;
+ if (args[1]->null_value && args[2]->null_value)
+ null_value=1;
+ else if (args[1]->null_value)
+ {
+ null_value= value <= b; // not null if false range.
+ }
+ else
+ {
+ null_value= value >= a;
+ }
+ }
+ return 0;
+}
+
+void
+Item_func_ifnull::fix_length_and_dec()
+{
+ maybe_null=args[1]->maybe_null;
+ max_length=max(args[0]->max_length,args[1]->max_length);
+ decimals=max(args[0]->decimals,args[1]->decimals);
+ cached_result_type=args[0]->result_type();
+}
+
+double
+Item_func_ifnull::val()
+{
+ double value=args[0]->val();
+ if (!args[0]->null_value)
+ {
+ null_value=0;
+ return value;
+ }
+ value=args[1]->val();
+ if ((null_value=args[1]->null_value))
+ return 0.0;
+ return value;
+}
+
+longlong
+Item_func_ifnull::val_int()
+{
+ longlong value=args[0]->val_int();
+ if (!args[0]->null_value)
+ {
+ null_value=0;
+ return value;
+ }
+ value=args[1]->val_int();
+ if ((null_value=args[1]->null_value))
+ return 0;
+ return value;
+}
+
+String *
+Item_func_ifnull::val_str(String *str)
+{
+ String *res =args[0]->val_str(str);
+ if (!args[0]->null_value)
+ {
+ null_value=0;
+ return res;
+ }
+ res=args[1]->val_str(str);
+ if ((null_value=args[1]->null_value))
+ return 0;
+ return res;
+}
+
+void
+Item_func_if::fix_length_and_dec()
+{
+ maybe_null=args[1]->maybe_null || args[2]->maybe_null;
+ max_length=max(args[1]->max_length,args[2]->max_length);
+ decimals=max(args[0]->decimals,args[1]->decimals);
+ enum Item_result arg1_type=args[1]->result_type();
+ enum Item_result arg2_type=args[2]->result_type();
+ if (arg1_type == STRING_RESULT || arg2_type == STRING_RESULT)
+ cached_result_type = STRING_RESULT;
+ else if (arg1_type == REAL_RESULT || arg2_type == REAL_RESULT)
+ cached_result_type = REAL_RESULT;
+ else
+ cached_result_type=arg1_type; // Should be INT_RESULT
+}
+
+
+double
+Item_func_if::val()
+{
+ Item *arg= args[0]->val_int() ? args[1] : args[2];
+ double value=arg->val();
+ null_value=arg->null_value;
+ return value;
+}
+
+longlong
+Item_func_if::val_int()
+{
+ Item *arg= args[0]->val_int() ? args[1] : args[2];
+ longlong value=arg->val_int();
+ null_value=arg->null_value;
+ return value;
+}
+
+String *
+Item_func_if::val_str(String *str)
+{
+ Item *arg= args[0]->val_int() ? args[1] : args[2];
+ String *res=arg->val_str(str);
+ null_value=arg->null_value;
+ return res;
+}
+
+
+void
+Item_func_nullif::fix_length_and_dec()
+{
+ Item_bool_func2::fix_length_and_dec();
+ maybe_null=1;
+ if (args[0]) // Only false if EOM
+ {
+ max_length=args[0]->max_length;
+ decimals=args[0]->decimals;
+ cached_result_type=args[0]->result_type();
+ }
+}
+
+/*
+ nullif() returns NULL if arguments are different, else it returns the
+ first argument.
+ Note that we have to evaluate the first argument twice as the compare
+ may have been done with a different type than return value
+*/
+
+double
+Item_func_nullif::val()
+{
+ double value;
+ if (!(this->*cmp_func)() || null_value)
+ {
+ null_value=1;
+ return 0.0;
+ }
+ value=args[0]->val();
+ null_value=args[0]->null_value;
+ return value;
+}
+
+longlong
+Item_func_nullif::val_int()
+{
+ longlong value;
+ if (!(this->*cmp_func)() || null_value)
+ {
+ null_value=1;
+ return 0;
+ }
+ value=args[0]->val_int();
+ null_value=args[0]->null_value;
+ return value;
+}
+
+String *
+Item_func_nullif::val_str(String *str)
+{
+ String *res;
+ if (!(this->*cmp_func)() || null_value)
+ {
+ null_value=1;
+ return 0;
+ }
+ res=args[0]->val_str(str);
+ null_value=args[0]->null_value;
+ return res;
+}
+
+/*
+** CASE expression
+*/
+
+/* Return the matching ITEM or NULL if all compares (including else) failed */
+
+Item *Item_func_case::find_item(String *str)
+{
+ String *first_expr_str,*tmp;
+ longlong first_expr_int;
+ double first_expr_real;
+ bool int_used, real_used,str_used;
+ int_used=real_used=str_used=0;
+
+ /* These will be initialized later */
+ LINT_INIT(first_expr_str);
+ LINT_INIT(first_expr_int);
+ LINT_INIT(first_expr_real);
+
+ // Compare every WHEN argument with it and return the first match
+ for (uint i=0 ; i < arg_count ; i+=2)
+ {
+ if (!first_expr)
+ {
+ // No expression between CASE and first WHEN
+ if (args[i]->val_int())
+ return args[i+1];
+ continue;
+ }
+ switch (args[i]->result_type()) {
+ case STRING_RESULT:
+ if (!str_used)
+ {
+ str_used=1;
+ // We can't use 'str' here as this may be overwritten
+ if (!(first_expr_str= first_expr->val_str(&str_value)))
+ return else_expr; // Impossible
+ }
+ if ((tmp=args[i]->val_str(str))) // If not null
+ {
+ if (first_expr->binary || args[i]->binary)
+ {
+ if (stringcmp(tmp,first_expr_str)==0)
+ return args[i+1];
+ }
+ else if (sortcmp(tmp,first_expr_str)==0)
+ return args[i+1];
+ }
+ break;
+ case INT_RESULT:
+ if (!int_used)
+ {
+ int_used=1;
+ first_expr_int= first_expr->val_int();
+ if (first_expr->null_value)
+ return else_expr;
+ }
+ if (args[i]->val_int()==first_expr_int && !args[i]->null_value)
+ return args[i+1];
+ break;
+ case REAL_RESULT:
+ if (!real_used)
+ {
+ real_used=1;
+ first_expr_real= first_expr->val();
+ if (first_expr->null_value)
+ return else_expr;
+ }
+ if (args[i]->val()==first_expr_real && !args[i]->null_value)
+ return args[i+1];
+ }
+ }
+ // No, WHEN clauses all missed, return ELSE expression
+ return else_expr;
+}
+
+
+
+String *Item_func_case::val_str(String *str)
+{
+ String *res;
+ Item *item=find_item(str);
+
+ if (!item)
+ {
+ null_value=1;
+ return 0;
+ }
+ if (!(res=item->val_str(str)))
+ null_value=1;
+ return res;
+}
+
+
+longlong Item_func_case::val_int()
+{
+ char buff[MAX_FIELD_WIDTH];
+ String dummy_str(buff,sizeof(buff));
+ Item *item=find_item(&dummy_str);
+ longlong res;
+
+ if (!item)
+ {
+ null_value=1;
+ return 0;
+ }
+ res=item->val_int();
+ null_value=item->null_value;
+ return res;
+}
+
+double Item_func_case::val()
+{
+ char buff[MAX_FIELD_WIDTH];
+ String dummy_str(buff,sizeof(buff));
+ Item *item=find_item(&dummy_str);
+ double res;
+
+ if (!item)
+ {
+ null_value=1;
+ return 0;
+ }
+ res=item->val();
+ null_value=item->null_value;
+ return res;
+}
+
+
+bool
+Item_func_case::fix_fields(THD *thd,TABLE_LIST *tables)
+{
+
+ if (first_expr && first_expr->fix_fields(thd,tables) ||
+ else_expr && else_expr->fix_fields(thd,tables))
+ return 1;
+ if (Item_func::fix_fields(thd,tables))
+ return 1;
+ if (!else_expr || else_expr->maybe_null)
+ maybe_null=1; // The result may be NULL
+ return 0;
+}
+
+
+void Item_func_case::fix_length_and_dec()
+{
+ max_length=0;
+ decimals=0;
+ cached_result_type = args[1]->result_type();
+ for (uint i=0 ; i < arg_count ; i+=2)
+ {
+ set_if_bigger(max_length,args[i+1]->max_length);
+ set_if_bigger(decimals,args[i+1]->decimals);
+ }
+ if (else_expr != NULL)
+ {
+ set_if_bigger(max_length,else_expr->max_length);
+ set_if_bigger(decimals,else_expr->decimals);
+ }
+}
+
+
+void Item_func_case::print(String *str)
+{
+ str->append("case "); // Not yet complete
+}
+
+/*
+** Coalesce - return first not NULL argument.
+*/
+
+String *Item_func_coalesce::val_str(String *str)
+{
+ null_value=0;
+ for (uint i=0 ; i < arg_count ; i++)
+ {
+ if (args[i]->val_str(str) != NULL)
+ return args[i]->val_str(str);
+ }
+ null_value=1;
+ return 0;
+}
+
+longlong Item_func_coalesce::val_int()
+{
+ null_value=0;
+ for (uint i=0 ; i < arg_count ; i++)
+ {
+ longlong res=args[i]->val_int();
+ if (!args[i]->null_value)
+ return res;
+ }
+ null_value=1;
+ return 0;
+}
+
+double Item_func_coalesce::val()
+{
+ null_value=0;
+ for (uint i=0 ; i < arg_count ; i++)
+ {
+ double res=args[i]->val();
+ if (!args[i]->null_value)
+ return res;
+ }
+ null_value=1;
+ return 0;
+}
+
+
+void Item_func_coalesce::fix_length_and_dec()
+{
+ max_length=0;
+ decimals=0;
+ cached_result_type = args[0]->result_type();
+ for (uint i=0 ; i < arg_count ; i++)
+ {
+ set_if_bigger(max_length,args[i]->max_length);
+ set_if_bigger(decimals,args[i]->decimals);
+ }
+}
+
+/****************************************************************************
+** classes and function for the IN operator
+****************************************************************************/
+
+static int cmp_longlong(longlong *a,longlong *b)
+{
+ return *a < *b ? -1 : *a == *b ? 0 : 1;
+}
+
+static int cmp_double(double *a,double *b)
+{
+ return *a < *b ? -1 : *a == *b ? 0 : 1;
+}
+
+int in_vector::find(Item *item)
+{
+ byte *result=get_value(item);
+ if (!result || !used_count)
+ return 0; // Null value
+
+ uint start,end;
+ start=0; end=used_count-1;
+ while (start != end)
+ {
+ uint mid=(start+end+1)/2;
+ int res;
+ if ((res=(*compare)(base+mid*size,result)) == 0)
+ return 1;
+ if (res < 0)
+ start=mid;
+ else
+ end=mid-1;
+ }
+ return (int) ((*compare)(base+start*size,result) == 0);
+}
+
+
+in_string::in_string(uint elements,qsort_cmp cmp_func)
+ :in_vector(elements,sizeof(String),cmp_func),tmp(buff,sizeof(buff))
+{}
+
+in_string::~in_string()
+{
+ for (uint i=0 ; i < count ; i++)
+ ((String*) base)[i].free();
+}
+
+void in_string::set(uint pos,Item *item)
+{
+ String *str=((String*) base)+pos;
+ String *res=item->val_str(str);
+ if (res && res != str)
+ *str= *res;
+}
+
+byte *in_string::get_value(Item *item)
+{
+ return (byte*) item->val_str(&tmp);
+}
+
+
+in_longlong::in_longlong(uint elements)
+ :in_vector(elements,sizeof(longlong),(qsort_cmp) cmp_longlong)
+{}
+
+void in_longlong::set(uint pos,Item *item)
+{
+ ((longlong*) base)[pos]=item->val_int();
+}
+
+byte *in_longlong::get_value(Item *item)
+{
+ tmp=item->val_int();
+ if (item->null_value)
+ return 0; /* purecov: inspected */
+ return (byte*) &tmp;
+}
+
+
+in_double::in_double(uint elements)
+ :in_vector(elements,sizeof(double),(qsort_cmp) cmp_double)
+{}
+
+void in_double::set(uint pos,Item *item)
+{
+ ((double*) base)[pos]=item->val();
+}
+
+byte *in_double::get_value(Item *item)
+{
+ tmp=item->val();
+ if (item->null_value)
+ return 0; /* purecov: inspected */
+ return (byte*) &tmp;
+}
+
+
+void Item_func_in::fix_length_and_dec()
+{
+ if (const_item())
+ {
+ switch (item->result_type()) {
+ case STRING_RESULT:
+ if (item->binary)
+ array=new in_string(arg_count,(qsort_cmp) stringcmp); /* purecov: inspected */
+ else
+ array=new in_string(arg_count,(qsort_cmp) sortcmp);
+ break;
+ case INT_RESULT:
+ array= new in_longlong(arg_count);
+ break;
+ case REAL_RESULT:
+ array= new in_double(arg_count);
+ break;
+ }
+ uint j=0;
+ for (uint i=0 ; i < arg_count ; i++)
+ {
+ array->set(j,args[i]);
+ if (!args[i]->null_value) // Skipp NULL values
+ j++;
+ }
+ if ((array->used_count=j))
+ array->sort();
+ }
+ else
+ {
+ switch (item->result_type()) {
+ case STRING_RESULT:
+ if (item->binary)
+ in_item= new cmp_item_binary_string;
+ else
+ in_item= new cmp_item_sort_string;
+ break;
+ case INT_RESULT:
+ in_item= new cmp_item_int;
+ break;
+ case REAL_RESULT:
+ in_item= new cmp_item_real;
+ break;
+ }
+ }
+ maybe_null= item->maybe_null;
+ max_length=2;
+ used_tables_cache|=item->used_tables();
+ const_item_cache&=item->const_item();
+}
+
+
+void Item_func_in::print(String *str)
+{
+ str->append('(');
+ item->print(str);
+ Item_func::print(str);
+ str->append(')');
+}
+
+
+longlong Item_func_in::val_int()
+{
+ if (array)
+ {
+ int tmp=array->find(item);
+ null_value=item->null_value;
+ return tmp;
+ }
+ in_item->store_value(item);
+ if ((null_value=item->null_value))
+ return 0;
+ for (uint i=0 ; i < arg_count ; i++)
+ {
+ if (!in_item->cmp(args[i]) && !args[i]->null_value)
+ return 1; // Would maybe be nice with i ?
+ }
+ return 0;
+}
+
+
+void Item_func_in::update_used_tables()
+{
+ Item_func::update_used_tables();
+ item->update_used_tables();
+ used_tables_cache|=item->used_tables();
+ const_item_cache&=item->const_item();
+}
+
+
+longlong Item_func_bit_or::val_int()
+{
+ ulonglong arg1= (ulonglong) args[0]->val_int();
+ if (args[0]->null_value)
+ {
+ null_value=1; /* purecov: inspected */
+ return 0; /* purecov: inspected */
+ }
+ ulonglong arg2= (ulonglong) args[1]->val_int();
+ if (args[1]->null_value)
+ {
+ null_value=1;
+ return 0;
+ }
+ null_value=0;
+ return (longlong) (arg1 | arg2);
+}
+
+
+longlong Item_func_bit_and::val_int()
+{
+ ulonglong arg1= (ulonglong) args[0]->val_int();
+ if (args[0]->null_value)
+ {
+ null_value=1; /* purecov: inspected */
+ return 0; /* purecov: inspected */
+ }
+ ulonglong arg2= (ulonglong) args[1]->val_int();
+ if (args[1]->null_value)
+ {
+ null_value=1; /* purecov: inspected */
+ return 0; /* purecov: inspected */
+ }
+ null_value=0;
+ return (longlong) (arg1 & arg2);
+}
+
+
+bool
+Item_cond::fix_fields(THD *thd,TABLE_LIST *tables)
+{
+ List_iterator<Item> li(list);
+ Item *item;
+ char buff[sizeof(char*)]; // Max local vars in function
+ used_tables_cache=0;
+ const_item_cache=0;
+
+ if (thd && check_stack_overrun(thd,buff))
+ return 0; // Fatal error flag is set!
+ while ((item=li++))
+ {
+ while (item->type() == Item::COND_ITEM &&
+ ((Item_cond*) item)->functype() == functype())
+ { // Identical function
+ li.replace(((Item_cond*) item)->list);
+ ((Item_cond*) item)->list.empty();
+#ifdef DELETE_ITEMS
+ delete (Item_cond*) item;
+#endif
+ item= *li.ref(); // new current item
+ }
+ if (item->fix_fields(thd,tables))
+ return 1; /* purecov: inspected */
+ used_tables_cache|=item->used_tables();
+ with_sum_func= with_sum_func || item->with_sum_func;
+ const_item_cache&=item->const_item();
+ }
+ if (thd)
+ thd->cond_count+=list.elements;
+ fix_length_and_dec();
+ return 0;
+}
+
+
+void Item_cond::split_sum_func(List<Item> &fields)
+{
+ List_iterator<Item> li(list);
+ Item *item;
+ used_tables_cache=0;
+ const_item_cache=0;
+ while ((item=li++))
+ {
+ if (item->with_sum_func && item->type() != SUM_FUNC_ITEM)
+ item->split_sum_func(fields);
+ else if (item->used_tables() || item->type() == SUM_FUNC_ITEM)
+ {
+ fields.push_front(item);
+ li.replace(new Item_ref((Item**) fields.head_ref(),0,item->name));
+ }
+ item->update_used_tables();
+ used_tables_cache|=item->used_tables();
+ const_item_cache&=item->const_item();
+ }
+}
+
+
+table_map
+Item_cond::used_tables() const
+{ // This caches used_tables
+ return used_tables_cache;
+}
+
+void Item_cond::update_used_tables()
+{
+ used_tables_cache=0;
+ const_item_cache=1;
+ List_iterator<Item> li(list);
+ Item *item;
+ while ((item=li++))
+ {
+ item->update_used_tables();
+ used_tables_cache|=item->used_tables();
+ const_item_cache&= item->const_item();
+ }
+}
+
+
+void Item_cond::print(String *str)
+{
+ str->append('(');
+ List_iterator<Item> li(list);
+ Item *item;
+ if ((item=li++))
+ item->print(str);
+ while ((item=li++))
+ {
+ str->append(' ');
+ str->append(func_name());
+ str->append(' ');
+ item->print(str);
+ }
+ str->append(')');
+}
+
+
+longlong Item_cond_and::val_int()
+{
+ List_iterator<Item> li(list);
+ Item *item;
+ while ((item=li++))
+ {
+ if (item->val_int() == 0)
+ {
+ /* TODO: In case of NULL, ANSI would require us to continue evaluation
+ until we get a FALSE value or run out of values; This would
+ require a lot of unnecessary evaluation, which we skip for now */
+ null_value=item->null_value;
+ return 0;
+ }
+ }
+ null_value=0;
+ return 1;
+}
+
+longlong Item_cond_or::val_int()
+{
+ List_iterator<Item> li(list);
+ Item *item;
+ null_value=0;
+ while ((item=li++))
+ {
+ if (item->val_int() != 0)
+ {
+ null_value=0;
+ return 1;
+ }
+ if (item->null_value)
+ null_value=1;
+ }
+ return 0;
+}
+
+longlong Item_func_isnull::val_int()
+{
+ (void) args[0]->val();
+ return (args[0]->null_value) ? 1 : 0;
+}
+
+longlong Item_func_isnotnull::val_int()
+{
+ (void) args[0]->val();
+ return !(args[0]->null_value) ? 1 : 0;
+}
+
+
+void Item_func_like::fix_length_and_dec()
+{
+ decimals=0; max_length=1;
+ // cmp_type=STRING_RESULT; // For quick select
+}
+
+
+longlong Item_func_like::val_int()
+{
+ String *res,*res2;
+ res=args[0]->val_str(&tmp_value1);
+ if (args[0]->null_value)
+ {
+ null_value=1;
+ return 0;
+ }
+ res2=args[1]->val_str(&tmp_value2);
+ if (args[1]->null_value)
+ {
+ null_value=1;
+ return 0;
+ }
+ null_value=0;
+ if (binary)
+ return wild_compare(*res,*res2,escape) ? 0 : 1;
+ else
+ return wild_case_compare(*res,*res2,escape) ? 0 : 1;
+}
+
+
+/* We can optimize a where if first character isn't a wildcard */
+
+Item_func::optimize_type Item_func_like::select_optimize() const
+{
+ if (args[1]->type() == STRING_ITEM)
+ {
+ if (((Item_string *) args[1])->str_value[0] != wild_many)
+ {
+ if ((args[0]->result_type() != STRING_RESULT) ||
+ ((Item_string *) args[1])->str_value[0] != wild_one)
+ return OPTIMIZE_OP;
+ }
+ }
+ return OPTIMIZE_NONE;
+}
+
+#ifdef USE_REGEX
+
+bool
+Item_func_regex::fix_fields(THD *thd,TABLE_LIST *tables)
+{
+ if (args[0]->fix_fields(thd,tables) || args[1]->fix_fields(thd,tables))
+ return 1; /* purecov: inspected */
+ with_sum_func=args[0]->with_sum_func || args[1]->with_sum_func;
+ max_length=1; decimals=0;
+ binary=args[0]->binary || args[1]->binary;
+ used_tables_cache=args[0]->used_tables() | args[1]->used_tables();
+ const_item_cache=args[0]->const_item() && args[1]->const_item();
+ if (!regex_compiled && args[1]->const_item())
+ {
+ char buff[MAX_FIELD_WIDTH];
+ String tmp(buff,sizeof(buff));
+ String *res=args[1]->val_str(&tmp);
+ if (args[1]->null_value)
+ { // Will always return NULL
+ maybe_null=1;
+ return 0;
+ }
+ int error;
+ if ((error=regcomp(&preg,res->c_ptr(),
+ binary ? REG_EXTENDED | REG_NOSUB :
+ REG_EXTENDED | REG_NOSUB | REG_ICASE)))
+ {
+ (void) regerror(error,&preg,buff,sizeof(buff));
+ my_printf_error(ER_REGEXP_ERROR,ER(ER_REGEXP_ERROR),MYF(0),buff);
+ return 1;
+ }
+ regex_compiled=regex_is_const=1;
+ maybe_null=args[0]->maybe_null;
+ }
+ else
+ maybe_null=1;
+ return 0;
+}
+
+
+longlong Item_func_regex::val_int()
+{
+ char buff[MAX_FIELD_WIDTH];
+ String *res, tmp(buff,sizeof(buff));
+
+ res=args[0]->val_str(&tmp);
+ if (args[0]->null_value)
+ {
+ null_value=1;
+ return 0;
+ }
+ if (!regex_is_const)
+ {
+ char buff2[MAX_FIELD_WIDTH];
+ String *res2, tmp2(buff2,sizeof(buff2));
+
+ res2= args[1]->val_str(&tmp2);
+ if (args[1]->null_value)
+ {
+ null_value=1;
+ return 0;
+ }
+ if (!regex_compiled || stringcmp(res2,&prev_regexp))
+ {
+ prev_regexp.copy(*res2);
+ if (regex_compiled)
+ {
+ regfree(&preg);
+ regex_compiled=0;
+ }
+ if (regcomp(&preg,res2->c_ptr(),
+ binary ? REG_EXTENDED | REG_NOSUB :
+ REG_EXTENDED | REG_NOSUB | REG_ICASE))
+
+ {
+ null_value=1;
+ return 0;
+ }
+ regex_compiled=1;
+ }
+ }
+ null_value=0;
+ return regexec(&preg,res->c_ptr(),0,(regmatch_t*) 0,0) ? 0 : 1;
+}
+
+
+Item_func_regex::~Item_func_regex()
+{
+ if (regex_compiled)
+ {
+ regfree(&preg);
+ regex_compiled=0;
+ }
+}
+
+#endif /* USE_REGEX */
diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h
new file mode 100644
index 00000000000..591d0f6a2f7
--- /dev/null
+++ b/sql/item_cmpfunc.h
@@ -0,0 +1,567 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+
+/* compare and test functions */
+
+#ifdef __GNUC__
+#pragma interface /* gcc class implementation */
+#endif
+
+class Item_bool_func :public Item_int_func
+{
+public:
+ Item_bool_func() :Item_int_func() {}
+ Item_bool_func(Item *a) :Item_int_func(a) {}
+ Item_bool_func(Item *a,Item *b) :Item_int_func(a,b) {}
+ void fix_length_and_dec() { decimals=0; max_length=1; }
+};
+
+class Item_bool_func2 :public Item_int_func
+{ /* Bool with 2 string args */
+protected:
+ String tmp_value1,tmp_value2;
+public:
+ Item_bool_func2(Item *a,Item *b) :Item_int_func(a,b) {}
+ void fix_length_and_dec();
+ void set_cmp_func(Item_result type);
+ int (Item_bool_func2::*cmp_func)();
+ int compare_string(); /* compare arg[0] & arg[1] */
+ int compare_real(); /* compare arg[0] & arg[1] */
+ int compare_int(); /* compare arg[0] & arg[1] */
+ optimize_type select_optimize() const { return OPTIMIZE_OP; }
+ 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); }
+};
+
+
+class Item_func_not :public Item_bool_func
+{
+public:
+ Item_func_not(Item *a) :Item_bool_func(a) {}
+ longlong val_int();
+ const char *func_name() const { return "not"; }
+};
+
+class Item_func_eq :public Item_bool_func2
+{
+public:
+ Item_func_eq(Item *a,Item *b) :Item_bool_func2(a,b) { };
+ longlong val_int();
+ enum Functype functype() const { return EQ_FUNC; }
+ enum Functype rev_functype() const { return EQ_FUNC; }
+ cond_result eq_cmp_result() const { return COND_TRUE; }
+ const char *func_name() const { return "="; }
+};
+
+class Item_func_equal :public Item_bool_func2
+{
+public:
+ Item_func_equal(Item *a,Item *b) :Item_bool_func2(a,b) { };
+ longlong val_int();
+ void fix_length_and_dec()
+ { Item_bool_func2::fix_length_and_dec() ; maybe_null=0; }
+ enum Functype functype() const { return EQUAL_FUNC; }
+ enum Functype rev_functype() const { return EQUAL_FUNC; }
+ cond_result eq_cmp_result() const { return COND_TRUE; }
+ const char *func_name() const { return "<=>"; }
+};
+
+
+class Item_func_ge :public Item_bool_func2
+{
+public:
+ Item_func_ge(Item *a,Item *b) :Item_bool_func2(a,b) { };
+ longlong val_int();
+ enum Functype functype() const { return GE_FUNC; }
+ enum Functype rev_functype() const { return LE_FUNC; }
+ cond_result eq_cmp_result() const { return COND_TRUE; }
+ const char *func_name() const { return ">="; }
+};
+
+
+class Item_func_gt :public Item_bool_func2
+{
+public:
+ Item_func_gt(Item *a,Item *b) :Item_bool_func2(a,b) { };
+ longlong val_int();
+ enum Functype functype() const { return GT_FUNC; }
+ enum Functype rev_functype() const { return LT_FUNC; }
+ cond_result eq_cmp_result() const { return COND_FALSE; }
+ const char *func_name() const { return ">"; }
+};
+
+
+class Item_func_le :public Item_bool_func2
+{
+public:
+ Item_func_le(Item *a,Item *b) :Item_bool_func2(a,b) { };
+ longlong val_int();
+ enum Functype functype() const { return LE_FUNC; }
+ enum Functype rev_functype() const { return GE_FUNC; }
+ cond_result eq_cmp_result() const { return COND_TRUE; }
+ const char *func_name() const { return "<="; }
+};
+
+
+class Item_func_lt :public Item_bool_func2
+{
+public:
+ Item_func_lt(Item *a,Item *b) :Item_bool_func2(a,b) { }
+ longlong val_int();
+ enum Functype functype() const { return LT_FUNC; }
+ enum Functype rev_functype() const { return GT_FUNC; }
+ cond_result eq_cmp_result() const { return COND_FALSE; }
+ const char *func_name() const { return "<"; }
+};
+
+
+class Item_func_ne :public Item_bool_func2
+{
+public:
+ Item_func_ne(Item *a,Item *b) :Item_bool_func2(a,b) { }
+ longlong val_int();
+ enum Functype functype() const { return NE_FUNC; }
+ cond_result eq_cmp_result() const { return COND_FALSE; }
+ optimize_type select_optimize() const { return OPTIMIZE_NONE; }
+ const char *func_name() const { return "<>"; }
+};
+
+
+class Item_func_between :public Item_int_func
+{
+ int (*string_compare)(const String *x,const String *y);
+public:
+ Item_result cmp_type;
+ String value0,value1,value2;
+ Item_func_between(Item *a,Item *b,Item *c) :Item_int_func(a,b,c) {}
+ longlong val_int();
+ optimize_type select_optimize() const { return OPTIMIZE_KEY; }
+ enum Functype functype() const { return BETWEEN; }
+ const char *func_name() const { return "between"; }
+ void fix_length_and_dec();
+};
+
+
+class Item_func_strcmp :public Item_bool_func2
+{
+public:
+ Item_func_strcmp(Item *a,Item *b) :Item_bool_func2(a,b) {}
+ longlong val_int();
+ void fix_length_and_dec() { max_length=2; }
+ optimize_type select_optimize() const { return OPTIMIZE_NONE; }
+ const char *func_name() const { return "strcmp"; }
+};
+
+
+class Item_func_interval :public Item_int_func
+{
+ Item *item;
+ double *intervals;
+public:
+ Item_func_interval(Item *a,List<Item> &list)
+ :Item_int_func(list),item(a),intervals(0) {}
+ longlong val_int();
+ bool fix_fields(THD *thd,struct st_table_list *tlist)
+ {
+ return (item->fix_fields(thd,tlist) || Item_func::fix_fields(thd,tlist));
+ }
+ void fix_length_and_dec();
+ ~Item_func_interval() { delete item; }
+ const char *func_name() const { return "interval"; }
+ void update_used_tables();
+};
+
+
+class Item_func_ifnull :public Item_func
+{
+ enum Item_result cached_result_type;
+public:
+ Item_func_ifnull(Item *a,Item *b) :Item_func(a,b) { }
+ double val();
+ longlong val_int();
+ String *val_str(String *str);
+ enum Item_result result_type () const { return cached_result_type; }
+ void fix_length_and_dec();
+ const char *func_name() const { return "ifnull"; }
+};
+
+
+class Item_func_if :public Item_func
+{
+ enum Item_result cached_result_type;
+public:
+ Item_func_if(Item *a,Item *b,Item *c) :Item_func(a,b,c) { }
+ double val();
+ longlong val_int();
+ String *val_str(String *str);
+ enum Item_result result_type () const { return cached_result_type; }
+ void fix_length_and_dec();
+ const char *func_name() const { return "if"; }
+};
+
+
+class Item_func_nullif :public Item_bool_func2
+{
+ enum Item_result cached_result_type;
+public:
+ Item_func_nullif(Item *a,Item *b) :Item_bool_func2(a,b) { }
+ double val();
+ longlong val_int();
+ String *val_str(String *str);
+ enum Item_result result_type () const { return cached_result_type; }
+ void fix_length_and_dec();
+ const char *func_name() const { return "nullif"; }
+};
+
+
+class Item_func_coalesce :public Item_func
+{
+ enum Item_result cached_result_type;
+public:
+ Item_func_coalesce(List<Item> &list) :Item_func(list) {}
+ double val();
+ longlong val_int();
+ String *val_str(String *);
+ void fix_length_and_dec();
+ enum Item_result result_type () const { return cached_result_type; }
+ const char *func_name() const { return "coalesce"; }
+};
+
+class Item_func_case :public Item_func
+{
+ Item * first_expr, *else_expr;
+ enum Item_result cached_result_type;
+ String tmp_value;
+public:
+ Item_func_case(List<Item> &list, Item *first_expr_, Item *else_expr_)
+ :Item_func(list), first_expr(first_expr_), else_expr(else_expr_) {}
+ double val();
+ longlong val_int();
+ String *val_str(String *);
+ void fix_length_and_dec();
+ enum Item_result result_type () const { return cached_result_type; }
+ const char *func_name() const { return "case"; }
+ void print(String *str);
+ bool fix_fields(THD *thd,struct st_table_list *tlist);
+ Item *find_item(String *str);
+};
+
+
+/* Functions to handle the optimized IN */
+
+class in_vector :public Sql_alloc
+{
+ protected:
+ char *base;
+ uint size;
+ qsort_cmp compare;
+ uint count;
+public:
+ uint used_count;
+ in_vector(uint elements,uint element_length,qsort_cmp cmp_func)
+ :base((char*) sql_calloc(elements*element_length)),
+ size(element_length), compare(cmp_func), count(elements),
+ used_count(elements) {}
+ virtual ~in_vector() {}
+ virtual void set(uint pos,Item *item)=0;
+ virtual byte *get_value(Item *item)=0;
+ void sort()
+ {
+ qsort(base,used_count,size,compare);
+ }
+ int find(Item *item);
+};
+
+
+class in_string :public in_vector
+{
+ char buff[80];
+ String tmp;
+public:
+ in_string(uint elements,qsort_cmp cmp_func);
+ ~in_string();
+ void set(uint pos,Item *item);
+ byte *get_value(Item *item);
+};
+
+
+class in_longlong :public in_vector
+{
+ longlong tmp;
+public:
+ in_longlong(uint elements);
+ void set(uint pos,Item *item);
+ byte *get_value(Item *item);
+};
+
+
+class in_double :public in_vector
+{
+ double tmp;
+public:
+ in_double(uint elements);
+ void set(uint pos,Item *item);
+ byte *get_value(Item *item);
+};
+
+
+/*
+** Classes for easy comparing of non const items
+*/
+
+class cmp_item :public Sql_alloc
+{
+public:
+ cmp_item() {}
+ virtual ~cmp_item() {}
+ virtual void store_value(Item *item)=0;
+ virtual int cmp(Item *item)=0;
+};
+
+
+class cmp_item_sort_string :public cmp_item {
+ protected:
+ char value_buff[80];
+ String value,*value_res;
+public:
+ cmp_item_sort_string() :value(value_buff,sizeof(value_buff)) {}
+ void store_value(Item *item)
+ {
+ value_res=item->val_str(&value);
+ }
+ int cmp(Item *arg)
+ {
+ char buff[80];
+ String tmp(buff,sizeof(buff)),*res;
+ if (!(res=arg->val_str(&tmp)))
+ return 1; /* Can't be right */
+ return sortcmp(value_res,res);
+ }
+};
+
+class cmp_item_binary_string :public cmp_item_sort_string {
+public:
+ cmp_item_binary_string() {}
+ int cmp(Item *arg)
+ {
+ char buff[80];
+ String tmp(buff,sizeof(buff)),*res;
+ if (!(res=arg->val_str(&tmp)))
+ return 1; /* Can't be right */
+ return stringcmp(value_res,res);
+ }
+};
+
+
+class cmp_item_int :public cmp_item
+{
+ longlong value;
+public:
+ void store_value(Item *item)
+ {
+ value=item->val_int();
+ }
+ int cmp(Item *arg)
+ {
+ return value != arg->val_int();
+ }
+};
+
+
+class cmp_item_real :public cmp_item
+{
+ double value;
+public:
+ void store_value(Item *item)
+ {
+ value= item->val();
+ }
+ int cmp(Item *arg)
+ {
+ return value != arg->val();
+ }
+};
+
+
+class Item_func_in :public Item_int_func
+{
+ Item *item;
+ in_vector *array;
+ cmp_item *in_item;
+ public:
+ Item_func_in(Item *a,List<Item> &list)
+ :Item_int_func(list),item(a),array(0),in_item(0) {}
+ longlong val_int();
+ bool fix_fields(THD *thd,struct st_table_list *tlist)
+ {
+ return (item->fix_fields(thd,tlist) || Item_func::fix_fields(thd,tlist));
+ }
+ void fix_length_and_dec();
+ ~Item_func_in() { delete item; delete array; delete in_item; }
+ optimize_type select_optimize() const
+ { return array ? OPTIMIZE_KEY : OPTIMIZE_NONE; }
+ Item *key_item() const { return item; }
+ void print(String *str);
+ enum Functype functype() const { return IN_FUNC; }
+ const char *func_name() const { return " IN "; }
+ void update_used_tables();
+};
+
+
+
+/* Functions used by where clause */
+
+class Item_func_isnull :public Item_bool_func
+{
+public:
+ Item_func_isnull(Item *a) :Item_bool_func(a) {}
+ longlong val_int();
+ enum Functype functype() const { return ISNULL_FUNC; }
+ void fix_length_and_dec()
+ {
+ decimals=0; max_length=1; maybe_null=0;
+ Item_func_isnull::update_used_tables();
+ }
+ const char *func_name() const { return "isnull"; }
+ /* Optimize case of not_null_column IS NULL */
+ void update_used_tables()
+ {
+ if (!args[0]->maybe_null)
+ used_tables_cache=0; /* is always false */
+ else
+ {
+ args[0]->update_used_tables();
+ used_tables_cache=args[0]->used_tables();
+ }
+ }
+ optimize_type select_optimize() const { return OPTIMIZE_NULL; }
+};
+
+class Item_func_isnotnull :public Item_bool_func
+{
+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; }
+ const char *func_name() const { return "isnotnull"; }
+ optimize_type select_optimize() const { return OPTIMIZE_NULL; }
+};
+
+class Item_func_like :public Item_bool_func2
+{
+ char escape;
+public:
+ Item_func_like(Item *a,Item *b, char* escape_arg) :Item_bool_func2(a,b),escape(*escape_arg)
+ {}
+ longlong val_int();
+ enum Functype functype() const { return LIKE_FUNC; }
+ optimize_type select_optimize() const;
+ cond_result eq_cmp_result() const { return COND_TRUE; }
+ const char *func_name() const { return "like"; }
+ void fix_length_and_dec();
+};
+
+#ifdef USE_REGEX
+
+#include <regex.h>
+
+class Item_func_regex :public Item_bool_func
+{
+ regex_t preg;
+ bool regex_compiled;
+ bool regex_is_const;
+ String prev_regexp;
+public:
+ Item_func_regex(Item *a,Item *b) :Item_bool_func(a,b),
+ regex_compiled(0),regex_is_const(0) {}
+ ~Item_func_regex();
+ longlong val_int();
+ bool fix_fields(THD *thd,struct st_table_list *tlist);
+ const char *func_name() const { return "regex"; }
+};
+
+#else
+
+class Item_func_regex :public Item_bool_func
+{
+public:
+ Item_func_regex(Item *a,Item *b) :Item_bool_func(a,b) {}
+ longlong val_int() { return 0;}
+ const char *func_name() const { return "regex"; }
+};
+
+#endif /* USE_REGEX */
+
+
+typedef class Item COND;
+
+class Item_cond :public Item_bool_func
+{
+protected:
+ List<Item> list;
+public:
+ Item_cond() : Item_bool_func() { const_item_cache=0; }
+ Item_cond(Item *i1,Item *i2) :Item_bool_func()
+ { list.push_back(i1); list.push_back(i2); }
+ ~Item_cond() { list.delete_elements(); }
+ bool add(Item *item) { return list.push_back(item); }
+ bool fix_fields(THD *,struct st_table_list *);
+
+ enum Type type() const { return COND_ITEM; }
+ List<Item>* argument_list() { return &list; }
+ table_map used_tables() const;
+ void update_used_tables();
+ void print(String *str);
+ void split_sum_func(List<Item> &fields);
+ friend int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds);
+};
+
+
+class Item_cond_and :public Item_cond
+{
+public:
+ Item_cond_and() :Item_cond() {}
+ Item_cond_and(Item *i1,Item *i2) :Item_cond(i1,i2) {}
+ enum Functype functype() const { return COND_AND_FUNC; }
+ longlong val_int();
+ const char *func_name() const { return "and"; }
+};
+
+class Item_cond_or :public Item_cond
+{
+public:
+ Item_cond_or() :Item_cond() {}
+ Item_cond_or(Item *i1,Item *i2) :Item_cond(i1,i2) {}
+ enum Functype functype() const { return COND_OR_FUNC; }
+ longlong val_int();
+ const char *func_name() const { return "or"; }
+};
+
+
+/* Some usefull inline functions */
+
+inline Item *and_conds(Item *a,Item *b)
+{
+ if (!b) return a;
+ if (!a) return b;
+ Item *cond=new Item_cond_and(a,b);
+ if (cond)
+ cond->update_used_tables();
+ return cond;
+}
diff --git a/sql/item_create.cc b/sql/item_create.cc
new file mode 100644
index 00000000000..a8f41c14aad
--- /dev/null
+++ b/sql/item_create.cc
@@ -0,0 +1,383 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 create an item. Used by lex.h */
+
+#include "mysql_priv.h"
+
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+
+Item *create_func_abs(Item* a)
+{
+ return new Item_func_abs(a);
+}
+
+Item *create_func_acos(Item* a)
+{
+ return new Item_func_acos(a);
+}
+
+Item *create_func_ascii(Item* a)
+{
+ return new Item_func_ascii(a);
+}
+
+Item *create_func_ord(Item* a)
+{
+ return new Item_func_ord(a);
+}
+
+Item *create_func_asin(Item* a)
+{
+ return new Item_func_asin(a);
+}
+
+Item *create_func_bin(Item* a)
+{
+ return new Item_func_conv(a,new Item_int((int32) 10,2),
+ new Item_int((int32) 2,1));
+}
+
+Item *create_func_bit_count(Item* a)
+{
+ return new Item_func_bit_count(a);
+}
+
+Item *create_func_ceiling(Item* a)
+{
+ return new Item_func_ceiling(a);
+}
+
+Item *create_func_connection_id(void)
+{
+ return new Item_int("CONNECTION_ID()",(longlong) current_thd->thread_id,10);
+}
+
+Item *create_func_conv(Item* a, Item *b, Item *c)
+{
+ return new Item_func_conv(a,b,c);
+}
+
+Item *create_func_cos(Item* a)
+{
+ return new Item_func_cos(a);
+}
+
+Item *create_func_cot(Item* a)
+{
+ return new Item_func_div(new Item_int((char*) "1",1,1),
+ new Item_func_tan(a));
+}
+
+Item *create_func_date_format(Item* a,Item *b)
+{
+ return new Item_func_date_format(a,b,0);
+}
+
+Item *create_func_dayofmonth(Item* a)
+{
+ return new Item_func_dayofmonth(a);
+}
+
+Item *create_func_dayofweek(Item* a)
+{
+ return new Item_func_weekday(new Item_func_to_days(a),1);
+}
+
+Item *create_func_dayofyear(Item* a)
+{
+ return new Item_func_dayofyear(a);
+}
+
+Item *create_func_dayname(Item* a)
+{
+ return new Item_func_dayname(new Item_func_to_days(a));
+}
+
+Item *create_func_degrees(Item *a)
+{
+ return new Item_func_units((char*) "degrees",a,180/M_PI,0.0);
+}
+
+Item *create_func_exp(Item* a)
+{
+ return new Item_func_exp(a);
+}
+
+Item *create_func_find_in_set(Item* a, Item *b)
+{
+ return new Item_func_find_in_set(a, b);
+}
+
+Item *create_func_floor(Item* a)
+{
+ return new Item_func_floor(a);
+}
+
+Item *create_func_from_days(Item* a)
+{
+ return new Item_func_from_days(a);
+}
+
+Item *create_func_get_lock(Item* a, Item *b)
+{
+ 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));
+}
+
+Item *create_func_inet_ntoa(Item* a)
+{
+ return new Item_func_inet_ntoa(a);
+}
+
+Item *create_func_inet_aton(Item* a)
+{
+ return new Item_func_inet_aton(a);
+}
+
+
+Item *create_func_ifnull(Item* a, Item *b)
+{
+ return new Item_func_ifnull(a,b);
+}
+
+Item *create_func_nullif(Item* a, Item *b)
+{
+ return new Item_func_nullif(a,b);
+}
+
+Item *create_func_locate(Item* a, Item *b)
+{
+ return new Item_func_locate(b,a);
+}
+
+Item *create_func_instr(Item* a, Item *b)
+{
+ return new Item_func_locate(a,b);
+}
+
+Item *create_func_isnull(Item* a)
+{
+ return new Item_func_isnull(a);
+}
+
+Item *create_func_lcase(Item* a)
+{
+ return new Item_func_lcase(a);
+}
+
+Item *create_func_length(Item* a)
+{
+ return new Item_func_length(a);
+}
+
+Item *create_func_char_length(Item* a)
+{
+ return new Item_func_char_length(a);
+}
+
+Item *create_func_log(Item* a)
+{
+ return new Item_func_log(a);
+}
+
+Item *create_func_log10(Item* a)
+{
+ return new Item_func_log10(a);
+}
+
+Item *create_func_lpad(Item* a, Item *b, Item *c)
+{
+ return new Item_func_lpad(a,b,c);
+}
+
+Item *create_func_ltrim(Item* a)
+{
+ return new Item_func_ltrim(a,new Item_string(" ",1));
+}
+
+Item *create_func_md5(Item* a)
+{
+ return new Item_func_md5(a);
+}
+
+Item *create_func_mod(Item* a, Item *b)
+{
+ return new Item_func_mod(a,b);
+}
+
+Item *create_func_monthname(Item* a)
+{
+ return new Item_func_monthname(a);
+}
+
+Item *create_func_month(Item* a)
+{
+ return new Item_func_month(a);
+}
+
+Item *create_func_oct(Item *a)
+{
+ return new Item_func_conv(a,new Item_int((int32) 10,2),
+ new Item_int((int32) 8,1));
+}
+
+Item *create_func_period_add(Item* a, Item *b)
+{
+ return new Item_func_period_add(a,b);
+}
+
+Item *create_func_period_diff(Item* a, Item *b)
+{
+ return new Item_func_period_diff(a,b);
+}
+
+Item *create_func_pi(void)
+{
+ return new Item_real("PI()",M_PI,6,8);
+}
+
+Item *create_func_pow(Item* a, Item *b)
+{
+ return new Item_func_pow(a,b);
+}
+
+Item *create_func_quarter(Item* a)
+{
+ return new Item_func_quarter(a);
+}
+
+Item *create_func_radians(Item *a)
+{
+ return new Item_func_units((char*) "radians",a,M_PI/180,0.0);
+}
+
+Item *create_func_release_lock(Item* a)
+{
+ return new Item_func_release_lock(a);
+}
+
+Item *create_func_repeat(Item* a, Item *b)
+{
+ return new Item_func_repeat(a,b);
+}
+
+Item *create_func_reverse(Item* a)
+{
+ return new Item_func_reverse(a);
+}
+
+Item *create_func_rpad(Item* a, Item *b, Item *c)
+{
+ return new Item_func_rpad(a,b,c);
+}
+
+Item *create_func_rtrim(Item* a)
+{
+ return new Item_func_rtrim(a,new Item_string(" ",1));
+}
+
+Item *create_func_sec_to_time(Item* a)
+{
+ return new Item_func_sec_to_time(a);
+}
+
+Item *create_func_sign(Item* a)
+{
+ return new Item_func_sign(a);
+}
+
+Item *create_func_sin(Item* a)
+{
+ return new Item_func_sin(a);
+}
+
+Item *create_func_space(Item *a)
+{
+ return new Item_func_repeat(new Item_string(" ",1),a);
+}
+
+Item *create_func_soundex(Item* a)
+{
+ return new Item_func_soundex(a);
+}
+
+Item *create_func_sqrt(Item* a)
+{
+ return new Item_func_sqrt(a);
+}
+
+Item *create_func_strcmp(Item* a, Item *b)
+{
+ return new Item_func_strcmp(a,b);
+}
+
+Item *create_func_tan(Item* a)
+{
+ return new Item_func_tan(a);
+}
+
+Item *create_func_time_format(Item *a, Item *b)
+{
+ return new Item_func_date_format(a,b,1);
+}
+
+Item *create_func_time_to_sec(Item* a)
+{
+ return new Item_func_time_to_sec(a);
+}
+
+Item *create_func_to_days(Item* a)
+{
+ return new Item_func_to_days(a);
+}
+
+Item *create_func_truncate (Item *a, Item *b)
+{
+ return new Item_func_round(a,b,1);
+}
+
+Item *create_func_ucase(Item* a)
+{
+ return new Item_func_ucase(a);
+}
+
+Item *create_func_version(void)
+{
+ return new Item_string(NullS,server_version, strlen(server_version));
+}
+
+Item *create_func_weekday(Item* a)
+{
+ return new Item_func_weekday(new Item_func_to_days(a),0);
+}
+
+Item *create_func_year(Item* a)
+{
+ return new Item_func_year(a);
+}
+
+Item *create_load_file(Item* a)
+{
+ return new Item_load_file(a);
+}
diff --git a/sql/item_create.h b/sql/item_create.h
new file mode 100644
index 00000000000..aa617946d98
--- /dev/null
+++ b/sql/item_create.h
@@ -0,0 +1,88 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 create an item. Used by lex.h */
+
+Item *create_func_abs(Item* a);
+Item *create_func_acos(Item* a);
+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_ceiling(Item* a);
+Item *create_func_char_length(Item* a);
+Item *create_func_connection_id(void);
+Item *create_func_conv(Item* a, Item *b, Item *c);
+Item *create_func_cos(Item* a);
+Item *create_func_cot(Item* a);
+Item *create_func_date_format(Item* a,Item *b);
+Item *create_func_dayname(Item* a);
+Item *create_func_dayofmonth(Item* a);
+Item *create_func_dayofweek(Item* a);
+Item *create_func_dayofyear(Item* a);
+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_from_days(Item* a);
+Item *create_func_get_lock(Item* a, Item *b);
+Item *create_func_hex(Item *a);
+Item *create_func_inet_aton(Item* a);
+Item *create_func_inet_ntoa(Item* a);
+
+Item *create_func_ifnull(Item* a, Item *b);
+Item *create_func_instr(Item* a, Item *b);
+Item *create_func_isnull(Item* a);
+Item *create_func_lcase(Item* a);
+Item *create_func_length(Item* a);
+Item *create_func_locate(Item* a, Item *b);
+Item *create_func_log(Item* a);
+Item *create_func_log10(Item* a);
+Item *create_func_lpad(Item* a, Item *b, Item *c);
+Item *create_func_ltrim(Item* a);
+Item *create_func_md5(Item* a);
+Item *create_func_mod(Item* a, Item *b);
+Item *create_func_monthname(Item* a);
+Item *create_func_nullif(Item* a, Item *b);
+Item *create_func_oct(Item *);
+Item *create_func_ord(Item* a);
+Item *create_func_period_add(Item* a, Item *b);
+Item *create_func_period_diff(Item* a, Item *b);
+Item *create_func_pi(void);
+Item *create_func_pow(Item* a, Item *b);
+Item *create_func_quarter(Item* a);
+Item *create_func_radians(Item *a);
+Item *create_func_release_lock(Item* a);
+Item *create_func_repeat(Item* a, Item *b);
+Item *create_func_reverse(Item* a);
+Item *create_func_rpad(Item* a, Item *b, Item *c);
+Item *create_func_rtrim(Item* a);
+Item *create_func_sec_to_time(Item* a);
+Item *create_func_sign(Item* a);
+Item *create_func_sin(Item* a);
+Item *create_func_soundex(Item* a);
+Item *create_func_space(Item *);
+Item *create_func_sqrt(Item* a);
+Item *create_func_strcmp(Item* a, Item *b);
+Item *create_func_tan(Item* a);;
+Item *create_func_time_format(Item *a, Item *b);
+Item *create_func_time_to_sec(Item* a);
+Item *create_func_to_days(Item* a);
+Item *create_func_truncate (Item *a, Item *b);
+Item *create_func_ucase(Item* a);
+Item *create_func_version(void);
+Item *create_func_weekday(Item* a);
+Item *create_load_file(Item* a);
diff --git a/sql/item_func.cc b/sql/item_func.cc
new file mode 100644
index 00000000000..b5e9a0c4035
--- /dev/null
+++ b/sql/item_func.cc
@@ -0,0 +1,1981 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 defines all numerical functions */
+
+#ifdef __GNUC__
+#pragma implementation // gcc: Class implementation
+#endif
+
+#include "mysql_priv.h"
+#include <m_ctype.h>
+#include <hash.h>
+#include <time.h>
+#include <ft_global.h>
+
+/* return TRUE if item is a constant */
+
+bool
+eval_const_cond(COND *cond)
+{
+ return ((Item_func*) cond)->val_int() ? TRUE : FALSE;
+}
+
+
+Item_func::Item_func(List<Item> &list)
+{
+ arg_count=list.elements;
+ if ((args=(Item**) sql_alloc(sizeof(Item*)*arg_count)))
+ {
+ uint i=0;
+ List_iterator<Item> li(list);
+ Item *item;
+
+ while ((item=li++))
+ {
+ args[i++]= item;
+ with_sum_func|=item->with_sum_func;
+ }
+ }
+ list.empty(); // Fields are used
+}
+
+bool
+Item_func::fix_fields(THD *thd,TABLE_LIST *tables)
+{
+ Item **arg,**arg_end;
+ char buff[sizeof(double)]; // Max argument in function
+ binary=0;
+ used_tables_cache=0;
+ const_item_cache=1;
+
+ if (thd && check_stack_overrun(thd,buff))
+ return 0; // Fatal error if flag is set!
+ if (arg_count)
+ { // Print purify happy
+ for (arg=args, arg_end=args+arg_count; arg != arg_end ; arg++)
+ {
+ if ((*arg)->fix_fields(thd,tables))
+ return 1; /* purecov: inspected */
+ if ((*arg)->maybe_null)
+ maybe_null=1;
+ if ((*arg)->binary)
+ binary=1;
+ with_sum_func= with_sum_func || (*arg)->with_sum_func;
+ used_tables_cache|=(*arg)->used_tables();
+ const_item_cache&= (*arg)->const_item();
+ }
+ }
+ fix_length_and_dec();
+ return 0;
+}
+
+
+void Item_func::split_sum_func(List<Item> &fields)
+{
+ Item **arg,**arg_end;
+ for (arg=args, arg_end=args+arg_count; arg != arg_end ; arg++)
+ {
+ if ((*arg)->with_sum_func && (*arg)->type() != SUM_FUNC_ITEM)
+ (*arg)->split_sum_func(fields);
+ else if ((*arg)->used_tables() || (*arg)->type() == SUM_FUNC_ITEM)
+ {
+ fields.push_front(*arg);
+ *arg=new Item_ref((Item**) fields.head_ref(),0,(*arg)->name);
+ }
+ }
+}
+
+
+void Item_func::update_used_tables()
+{
+ used_tables_cache=0;
+ const_item_cache=1;
+ for (uint i=0 ; i < arg_count ; i++)
+ {
+ args[i]->update_used_tables();
+ used_tables_cache|=args[i]->used_tables();
+ const_item_cache&=args[i]->const_item();
+ }
+}
+
+
+table_map Item_func::used_tables() const
+{
+ return used_tables_cache;
+}
+
+void Item_func::print(String *str)
+{
+ str->append(func_name());
+ str->append('(');
+ for (uint i=0 ; i < arg_count ; i++)
+ {
+ if (i)
+ str->append(',');
+ args[i]->print(str);
+ }
+ str->append(')');
+}
+
+
+void Item_func::print_op(String *str)
+{
+ str->append('(');
+ for (uint i=0 ; i < arg_count-1 ; i++)
+ {
+ args[i]->print(str);
+ str->append(' ');
+ str->append(func_name());
+ str->append(' ');
+ }
+ args[arg_count-1]->print(str);
+ str->append(')');
+}
+
+bool Item_func::eq(const Item *item) const
+{
+ /* Assume we don't have rtti */
+ if (this == item)
+ return 1;
+ if (item->type() != FUNC_ITEM)
+ return 0;
+ Item_func *item_func=(Item_func*) item;
+ if (arg_count != item_func->arg_count ||
+ func_name() != item_func->func_name())
+ return 0;
+ for (uint i=0; i < arg_count ; i++)
+ if (!args[i]->eq(item_func->args[i]))
+ return 0;
+ return 1;
+}
+
+
+String *Item_real_func::val_str(String *str)
+{
+ double nr=val();
+ if (null_value)
+ return 0; /* purecov: inspected */
+ else
+ str->set(nr,decimals);
+ return str;
+}
+
+
+String *Item_num_func::val_str(String *str)
+{
+ if (hybrid_type == INT_RESULT)
+ {
+ longlong nr=val_int();
+ if (null_value)
+ return 0; /* purecov: inspected */
+ else
+ str->set(nr);
+ }
+ else
+ {
+ double nr=val();
+ if (null_value)
+ return 0; /* purecov: inspected */
+ else
+ str->set(nr,decimals);
+ }
+ return str;
+}
+
+
+void Item_func::fix_num_length_and_dec()
+{
+ decimals=0;
+ for (uint i=0 ; i < arg_count ; i++)
+ set_if_bigger(decimals,args[i]->decimals);
+ max_length=float_length(decimals);
+}
+
+
+String *Item_int_func::val_str(String *str)
+{
+ longlong nr=val_int();
+ if (null_value)
+ return 0;
+ else
+ str->set(nr);
+ return str;
+}
+
+/* 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;
+}
+
+String *Item_num_op::val_str(String *str)
+{
+ if (hybrid_type == INT_RESULT)
+ {
+ longlong nr=val_int();
+ if (null_value)
+ return 0; /* purecov: inspected */
+ else
+ str->set(nr);
+ }
+ else
+ {
+ double nr=val();
+ if (null_value)
+ return 0; /* purecov: inspected */
+ else
+ str->set(nr,decimals);
+ }
+ return str;
+}
+
+
+double Item_func_plus::val()
+{
+ double value=args[0]->val()+args[1]->val();
+ if ((null_value=args[0]->null_value || args[1]->null_value))
+ return 0.0;
+ return value;
+}
+
+longlong Item_func_plus::val_int()
+{
+ longlong value=args[0]->val_int()+args[1]->val_int();
+ if ((null_value=args[0]->null_value || args[1]->null_value))
+ return 0;
+ return value;
+}
+
+double Item_func_minus::val()
+{
+ double value=args[0]->val() - args[1]->val();
+ if ((null_value=args[0]->null_value || args[1]->null_value))
+ return 0.0;
+ return value;
+}
+
+longlong Item_func_minus::val_int()
+{
+ longlong value=args[0]->val_int() - args[1]->val_int();
+ if ((null_value=args[0]->null_value || args[1]->null_value))
+ return 0;
+ return value;
+}
+
+double Item_func_mul::val()
+{
+ double value=args[0]->val()*args[1]->val();
+ if ((null_value=args[0]->null_value || args[1]->null_value))
+ return 0.0; /* purecov: inspected */
+ return value;
+}
+
+longlong Item_func_mul::val_int()
+{
+ longlong value=args[0]->val_int()*args[1]->val_int();
+ if ((null_value=args[0]->null_value || args[1]->null_value))
+ return 0; /* purecov: inspected */
+ return value;
+}
+
+
+double Item_func_div::val()
+{
+ double value=args[0]->val();
+ double val2=args[1]->val();
+ if ((null_value= val2 == 0.0 || args[0]->null_value || args[1]->null_value))
+ return 0.0;
+ return value/val2;
+}
+
+longlong Item_func_div::val_int()
+{
+ longlong value=args[0]->val_int();
+ longlong val2=args[1]->val_int();
+ if ((null_value= val2 == 0 || args[0]->null_value || args[1]->null_value))
+ return 0;
+ return value/val2;
+}
+
+void Item_func_div::fix_length_and_dec()
+{
+ decimals=max(args[0]->decimals,args[1]->decimals)+2;
+ max_length=args[0]->max_length - args[0]->decimals + decimals;
+ uint tmp=float_length(decimals);
+ set_if_smaller(max_length,tmp);
+ maybe_null=1;
+}
+
+double Item_func_mod::val()
+{
+ double value= floor(args[0]->val()+0.5);
+ double val2=floor(args[1]->val()+0.5);
+ if ((null_value=val2 == 0.0 || args[0]->null_value || args[1]->null_value))
+ return 0.0; /* purecov: inspected */
+ return fmod(value,val2);
+}
+
+longlong Item_func_mod::val_int()
+{
+ longlong value= args[0]->val_int();
+ longlong val2= args[1]->val_int();
+ if ((null_value=val2 == 0 || args[0]->null_value || args[1]->null_value))
+ return 0; /* purecov: inspected */
+ return value % val2;
+}
+
+void Item_func_mod::fix_length_and_dec()
+{
+ max_length=args[1]->max_length;
+ decimals=0;
+ maybe_null=1;
+ find_num_type();
+}
+
+
+double Item_func_neg::val()
+{
+ double value=args[0]->val();
+ null_value=args[0]->null_value;
+ return -value;
+}
+
+longlong Item_func_neg::val_int()
+{
+ longlong value=args[0]->val_int();
+ null_value=args[0]->null_value;
+ return -value;
+}
+
+void Item_func_neg::fix_length_and_dec()
+{
+ decimals=args[0]->decimals;
+ max_length=args[0]->max_length;
+ hybrid_type= args[0]->result_type() == INT_RESULT ? INT_RESULT : REAL_RESULT;
+}
+
+double Item_func_abs::val()
+{
+ double value=args[0]->val();
+ null_value=args[0]->null_value;
+ return fabs(value);
+}
+
+longlong Item_func_abs::val_int()
+{
+ longlong value=args[0]->val_int();
+ null_value=args[0]->null_value;
+ return value >= 0 ? value : -value;
+}
+
+void Item_func_abs::fix_length_and_dec()
+{
+ decimals=args[0]->decimals;
+ max_length=args[0]->max_length;
+ hybrid_type= args[0]->result_type() == INT_RESULT ? INT_RESULT : REAL_RESULT;
+}
+
+double Item_func_log::val()
+{
+ double value=args[0]->val();
+ if ((null_value=(args[0]->null_value || value <= 0.0)))
+ return 0.0; /* purecov: inspected */
+ return log(value);
+}
+
+double Item_func_log10::val()
+{
+ double value=args[0]->val();
+ if ((null_value=(args[0]->null_value || value <= 0.0)))
+ return 0.0; /* purecov: inspected */
+ return log10(value);
+}
+
+double Item_func_exp::val()
+{
+ double value=args[0]->val();
+ if ((null_value=args[0]->null_value))
+ return 0.0; /* purecov: inspected */
+ return exp(value);
+}
+
+double Item_func_sqrt::val()
+{
+ double value=args[0]->val();
+ if ((null_value=(args[0]->null_value || value < 0)))
+ return 0.0; /* purecov: inspected */
+ return sqrt(value);
+}
+
+double Item_func_pow::val()
+{
+ double value=args[0]->val();
+ double val2=args[1]->val();
+ if ((null_value=(args[0]->null_value || args[1]->null_value)))
+ return 0.0; /* purecov: inspected */
+ return pow(value,val2);
+}
+
+// Trigonometric functions
+
+double Item_func_acos::val()
+{
+ double value=args[0]->val();
+ if ((null_value=(args[0]->null_value || (value < -1.0 || value > 1.0))))
+ return 0.0;
+ return fix_result(acos(value));
+}
+
+double Item_func_asin::val()
+{
+ double value=args[0]->val();
+ if ((null_value=(args[0]->null_value || (value < -1.0 || value > 1.0))))
+ return 0.0;
+ return fix_result(asin(value));
+}
+
+double Item_func_atan::val()
+{
+ double value=args[0]->val();
+ if ((null_value=args[0]->null_value))
+ return 0.0;
+ if (arg_count == 2)
+ {
+ double val2= args[1]->val();
+ if ((null_value=args[1]->null_value))
+ return 0.0;
+ return fix_result(atan2(value,val2));
+ }
+ return fix_result(atan(value));
+}
+
+double Item_func_cos::val()
+{
+ double value=args[0]->val();
+ if ((null_value=args[0]->null_value))
+ return 0.0;
+ return fix_result(cos(value));
+}
+
+double Item_func_sin::val()
+{
+ double value=args[0]->val();
+ if ((null_value=args[0]->null_value))
+ return 0.0;
+ return fix_result(sin(value));
+}
+
+double Item_func_tan::val()
+{
+ double value=args[0]->val();
+ if ((null_value=args[0]->null_value))
+ return 0.0;
+ return fix_result(tan(value));
+}
+
+
+// Shift-functions, same as << and >> in C/C++
+
+
+longlong Item_func_shift_left::val_int()
+{
+ uint shift;
+ ulonglong res= ((ulonglong) args[0]->val_int() <<
+ (shift=(uint) args[1]->val_int()));
+ if (args[0]->null_value || args[1]->null_value)
+ {
+ null_value=1;
+ return 0;
+ }
+ null_value=0;
+ return (shift < sizeof(longlong)*8 ? (longlong) res : LL(0));
+}
+
+longlong Item_func_shift_right::val_int()
+{
+ uint shift;
+ ulonglong res= (ulonglong) args[0]->val_int() >>
+ (shift=(uint) args[1]->val_int());
+ if (args[0]->null_value || args[1]->null_value)
+ {
+ null_value=1;
+ return 0;
+ }
+ null_value=0;
+ return (shift < sizeof(longlong)*8 ? (longlong) res : LL(0));
+}
+
+
+longlong Item_func_bit_neg::val_int()
+{
+ ulonglong res= (ulonglong) args[0]->val_int();
+ if ((null_value=args[0]->null_value))
+ return 0;
+ return ~res;
+}
+
+
+// Conversion functions
+
+void Item_func_integer::fix_length_and_dec()
+{
+ max_length=args[0]->max_length - args[0]->decimals+1;
+ uint tmp=float_length(decimals);
+ set_if_smaller(max_length,tmp);
+ decimals=0;
+}
+
+longlong Item_func_ceiling::val_int()
+{
+ double value=args[0]->val();
+ null_value=args[0]->null_value;
+ return (longlong) ceil(value);
+}
+
+longlong Item_func_floor::val_int()
+{
+ double value=args[0]->val();
+ null_value=args[0]->null_value;
+ return (longlong) floor(value);
+}
+
+void Item_func_round::fix_length_and_dec()
+{
+ max_length=args[0]->max_length;
+ decimals=args[0]->decimals;
+ if (args[1]->const_item())
+ {
+ int tmp=(int) args[1]->val_int();
+ if (tmp < 0)
+ decimals=0;
+ else
+ decimals=tmp;
+ }
+}
+
+double Item_func_round::val()
+{
+ double value=args[0]->val();
+ int dec=(int) args[1]->val_int();
+ uint abs_dec=abs(dec);
+
+ if ((null_value=args[0]->null_value || args[1]->null_value))
+ return 0.0;
+ double tmp=(abs_dec < array_elements(log_10) ?
+ log_10[abs_dec] : pow(10.0,(double) abs_dec));
+
+ if (truncate)
+ return dec < 0 ? floor(value/tmp)*tmp : floor(value*tmp)/tmp;
+ return dec < 0 ? rint(value/tmp)*tmp : rint(value*tmp)/tmp;
+}
+
+
+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);
+#ifdef DELETE_ITEMS
+ delete args[0];
+#endif
+ arg_count=0;
+ }
+ return rnd(&current_thd->rand);
+}
+
+longlong Item_func_sign::val_int()
+{
+ double value=args[0]->val();
+ null_value=args[0]->null_value;
+ return value < 0.0 ? -1 : (value > 0 ? 1 : 0);
+}
+
+
+double Item_func_units::val()
+{
+ double value=args[0]->val();
+ if ((null_value=args[0]->null_value))
+ return 0;
+ return value*mul+add;
+}
+
+
+void Item_func_min_max::fix_length_and_dec()
+{
+ decimals=0;
+ max_length=0;
+ maybe_null=1;
+ binary=0;
+ cmp_type=args[0]->result_type();
+ for (uint i=0 ; i < arg_count ; i++)
+ {
+ if (max_length < args[i]->max_length)
+ max_length=args[i]->max_length;
+ if (decimals < args[i]->decimals)
+ decimals=args[i]->decimals;
+ if (!args[i]->maybe_null)
+ maybe_null=0;
+ cmp_type=item_cmp_type(cmp_type,args[i]->result_type());
+ if (args[i]->binary)
+ binary=1;
+ }
+}
+
+
+String *Item_func_min_max::val_str(String *str)
+{
+ switch (cmp_type) {
+ case INT_RESULT:
+ {
+ longlong nr=val_int();
+ if (null_value)
+ return 0;
+ else
+ str->set(nr);
+ return str;
+ }
+ case REAL_RESULT:
+ {
+ double nr=val();
+ if (null_value)
+ return 0; /* purecov: inspected */
+ else
+ str->set(nr,decimals);
+ return str;
+ }
+ case STRING_RESULT:
+ {
+ String *res;
+ LINT_INIT(res);
+ null_value=1;
+ for (uint i=0; i < arg_count ; i++)
+ {
+ if (null_value)
+ {
+ res=args[i]->val_str(str);
+ null_value=args[i]->null_value;
+ }
+ else
+ {
+ String *res2;
+ res2= args[i]->val_str(res == str ? &tmp_value : str);
+ if (res2)
+ {
+ int cmp=binary ? stringcmp(res,res2) : sortcmp(res,res2);
+ if ((cmp_sign < 0 ? cmp : -cmp) < 0)
+ res=res2;
+ }
+ }
+ }
+ return res;
+ }
+ }
+ return 0; // Keep compiler happy
+}
+
+
+double Item_func_min_max::val()
+{
+ double value=0.0;
+ null_value=1;
+ for (uint i=0; i < arg_count ; i++)
+ {
+ if (null_value)
+ {
+ value=args[i]->val();
+ null_value=args[i]->null_value;
+ }
+ else
+ {
+ double tmp=args[i]->val();
+ if (!args[i]->null_value && (tmp < value ? cmp_sign : -cmp_sign) > 0)
+ value=tmp;
+ }
+ }
+ return value;
+}
+
+
+longlong Item_func_min_max::val_int()
+{
+ longlong value=0;
+ null_value=1;
+ for (uint i=0; i < arg_count ; i++)
+ {
+ if (null_value)
+ {
+ value=args[i]->val_int();
+ null_value=args[i]->null_value;
+ }
+ else
+ {
+ longlong tmp=args[i]->val_int();
+ if (!args[i]->null_value && (tmp < value ? cmp_sign : -cmp_sign) > 0)
+ value=tmp;
+ }
+ }
+ return value;
+}
+
+
+longlong Item_func_length::val_int()
+{
+ String *res=args[0]->val_str(&value);
+ if (!res)
+ {
+ null_value=1;
+ return 0; /* purecov: inspected */
+ }
+ null_value=0;
+ return (longlong) res->length();
+}
+
+longlong Item_func_char_length::val_int()
+{
+ String *res=args[0]->val_str(&value);
+ if (!res)
+ {
+ null_value=1;
+ return 0; /* purecov: inspected */
+ }
+ null_value=0;
+ return (longlong) (!args[0]->binary) ? res->numchars() : res->length();
+}
+
+
+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;
+ return 0; /* purecov: inspected */
+ }
+ null_value=0;
+ uint start=0,start0=0;
+ if (arg_count == 3)
+ {
+ start=(uint) args[2]->val_int()-1;
+#ifdef USE_MB
+ if (use_mb(default_charset_info))
+ {
+ start0=start;
+ if (!binary_str)
+ start=a->charpos(start);
+ }
+#endif
+ if (start > a->length() || start+b->length() > a->length())
+ return 0;
+ }
+ if (!b->length()) // Found empty string at start
+ return (longlong) (start+1);
+#ifdef USE_MB
+ if (use_mb(default_charset_info) && !binary_str)
+ {
+ const char *ptr=a->ptr()+start;
+ const char *search=b->ptr();
+ const char *strend = ptr+a->length();
+ const char *end=strend-b->length()+1;
+ const char *search_end=search+b->length();
+ register uint32 l;
+ while (ptr < end)
+ {
+ if (*ptr == *search)
+ {
+ register char *i,*j;
+ i=(char*) ptr+1; j=(char*) search+1;
+ while (j != search_end)
+ if (*i++ != *j++) goto skipp;
+ return (longlong) start0+1;
+ }
+ skipp:
+ if ((l=my_ismbchar(default_charset_info,ptr,strend))) ptr+=l;
+ else ++ptr;
+ ++start0;
+ }
+ return 0;
+ }
+#endif /* USE_MB */
+ return (longlong) (a->strstr(*b,start)+1) ;
+}
+
+
+longlong Item_func_field::val_int()
+{
+ String *field;
+ if (!(field=item->val_str(&value)))
+ return 0; // -1 if null ?
+ for (uint i=0 ; i < arg_count ; i++)
+ {
+ String *tmp_value=args[i]->val_str(&tmp);
+ if (tmp_value && field->length() == tmp_value->length() &&
+ !memcmp(field->ptr(),tmp_value->ptr(),tmp_value->length()))
+ return (longlong) (i+1);
+ }
+ return 0;
+}
+
+
+longlong Item_func_ascii::val_int()
+{
+ String *res=args[0]->val_str(&value);
+ if (!res)
+ {
+ null_value=1;
+ return 0;
+ }
+ null_value=0;
+ return (longlong) (res->length() ? (uchar) (*res)[0] : (uchar) 0);
+}
+
+longlong Item_func_ord::val_int()
+{
+ String *res=args[0]->val_str(&value);
+ if (!res)
+ {
+ null_value=1;
+ return 0;
+ }
+ null_value=0;
+ if (!res->length()) return 0;
+#ifdef USE_MB
+ if (use_mb(default_charset_info) && !args[0]->binary)
+ {
+ register const char *str=res->ptr();
+ register uint32 n=0, l=my_ismbchar(default_charset_info,
+ str,str+res->length());
+ if (!l) return (longlong)((uchar) *str);
+ while (l--)
+ n=(n<<8)|(uint32)((uchar) *str++);
+ return (longlong) n;
+ }
+#endif
+ return (longlong) ((uchar) (*res)[0]);
+}
+
+ /* Search after a string in a string of strings separated by ',' */
+ /* Returns number of found type >= 1 or 0 if not found */
+ /* This optimizes searching in enums to bit testing! */
+
+void Item_func_find_in_set::fix_length_and_dec()
+{
+ decimals=0;
+ max_length=3; // 1-999
+ if (args[0]->const_item() && args[1]->type() == FIELD_ITEM)
+ {
+ Field *field= ((Item_field*) args[1])->field;
+ if (field->real_type() == FIELD_TYPE_SET)
+ {
+ String *find=args[0]->val_str(&value);
+ if (find)
+ {
+ enum_value=find_enum(((Field_enum*) field)->typelib,find->ptr(),
+ find->length());
+ enum_bit=0;
+ if (enum_value)
+ enum_bit=LL(1) << (enum_value-1);
+ }
+ }
+ }
+}
+
+static const char separator=',';
+
+longlong Item_func_find_in_set::val_int()
+{
+ if (enum_value)
+ {
+ ulonglong tmp=(ulonglong) args[1]->val_int();
+ if (!(null_value=args[1]->null_value || args[0]->null_value))
+ {
+ if (tmp & enum_bit)
+ return enum_value;
+ }
+ return 0L;
+ }
+
+ String *find=args[0]->val_str(&value);
+ String *buffer=args[1]->val_str(&value2);
+ if (!find || !buffer)
+ {
+ null_value=1;
+ return 0; /* purecov: inspected */
+ }
+ null_value=0;
+
+ int diff;
+ if ((diff=buffer->length() - find->length()) >= 0)
+ {
+ const char *f_pos=find->ptr();
+ const char *f_end=f_pos+find->length();
+ const char *str=buffer->ptr();
+ const char *end=str+diff+1;
+ const char *real_end=str+buffer->length();
+ uint position=1;
+ do
+ {
+ const char *pos= f_pos;
+ while (pos != f_end)
+ {
+ if (toupper(*str) != toupper(*pos))
+ goto not_found;
+ str++;
+ pos++;
+ }
+ if (str == real_end || str[0] == separator)
+ return (longlong) position;
+ not_found:
+ while (str < end && str[0] != separator)
+ str++;
+ position++;
+ } while (++str <= end);
+ }
+ return 0;
+}
+
+static char nbits[256] = {
+ 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
+ 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+ 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+ 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+ 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+ 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+ 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+ 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+ 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+ 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8,
+};
+
+uint count_bits(ulonglong v)
+{
+#if SIZEOF_LONG_LONG > 4
+ /* The following code is a bit faster on 16 bit machines than if we would
+ only shift v */
+ ulong v2=(ulong) (v >> 32);
+ return (uint) (uchar) (nbits[(uchar) v] +
+ nbits[(uchar) (v >> 8)] +
+ nbits[(uchar) (v >> 16)] +
+ nbits[(uchar) (v >> 24)] +
+ nbits[(uchar) (v2)] +
+ nbits[(uchar) (v2 >> 8)] +
+ nbits[(uchar) (v2 >> 16)] +
+ nbits[(uchar) (v2 >> 24)]);
+#else
+ return (uint) (uchar) (nbits[(uchar) v] +
+ nbits[(uchar) (v >> 8)] +
+ nbits[(uchar) (v >> 16)] +
+ nbits[(uchar) (v >> 24)]);
+#endif
+}
+
+longlong Item_func_bit_count::val_int()
+{
+ ulonglong value= (ulonglong) args[0]->val_int();
+ if (args[0]->null_value)
+ {
+ null_value=1; /* purecov: inspected */
+ return 0; /* purecov: inspected */
+ }
+ return (longlong) count_bits(value);
+}
+
+
+/****************************************************************************
+** Functions to handle dynamic loadable functions
+** Original source by: Alexis Mikhailov <root@medinf.chuvashia.su>
+** Rewritten by: Monty.
+****************************************************************************/
+
+#ifdef HAVE_DLOPEN
+
+udf_handler::~udf_handler()
+{
+ if (initialized)
+ {
+ if (u_d->func_deinit != NULL)
+ {
+ void (*deinit)(UDF_INIT *) = (void (*)(UDF_INIT*))
+ u_d->func_deinit;
+ (*deinit)(&initid);
+ }
+ free_udf(u_d);
+ }
+ delete [] buffers;
+}
+
+
+bool
+udf_handler::fix_fields(THD *thd,TABLE_LIST *tables,Item_result_field *func,
+ uint arg_count, Item **arguments)
+{
+ char buff[sizeof(double)]; // Max argument in function
+ DBUG_ENTER("Item_udf_func::fix_fields");
+
+ if (thd && check_stack_overrun(thd,buff))
+ return 0; // Fatal error flag is set!
+
+ udf_func *tmp_udf=find_udf(u_d->name,strlen(u_d->name),1);
+
+ if (!tmp_udf)
+ {
+ my_printf_error(ER_CANT_FIND_UDF,ER(ER_CANT_FIND_UDF),MYF(0),u_d->name,
+ errno);
+ DBUG_RETURN(1);
+ }
+ u_d=tmp_udf;
+ args=arguments;
+
+ /* Fix all arguments */
+ func->binary=func->maybe_null=0;
+ used_tables_cache=0;
+ const_item_cache=1;
+
+ if ((f_args.arg_count=arg_count))
+ {
+ if (!(f_args.arg_type= (Item_result*)
+ sql_alloc(f_args.arg_count*sizeof(Item_result))))
+
+ {
+ free_udf(u_d);
+ DBUG_RETURN(1);
+ }
+ uint i;
+ Item **arg,**arg_end;
+ for (i=0, arg=arguments, arg_end=arguments+arg_count;
+ arg != arg_end ;
+ arg++,i++)
+ {
+ if ((*arg)->fix_fields(thd,tables))
+ return 1;
+ if ((*arg)->binary)
+ func->binary=1;
+ if ((*arg)->maybe_null)
+ func->maybe_null=1;
+ func->with_sum_func= func->with_sum_func || (*arg)->with_sum_func;
+ used_tables_cache|=(*arg)->used_tables();
+ const_item_cache&=(*arg)->const_item();
+ f_args.arg_type[i]=(*arg)->result_type();
+ }
+ if (!(buffers=new String[arg_count]) ||
+ !(f_args.args= (char**) sql_alloc(arg_count * sizeof(char *))) ||
+ !(f_args.lengths=(ulong*) sql_alloc(arg_count * sizeof(long))) ||
+ !(f_args.maybe_null=(char*) sql_alloc(arg_count * sizeof(char))) ||
+ !(num_buffer= (char*) sql_alloc(ALIGN_SIZE(sizeof(double))*arg_count)))
+ {
+ free_udf(u_d);
+ DBUG_RETURN(1);
+ }
+ }
+ func->fix_length_and_dec();
+ initid.max_length=func->max_length;
+ initid.maybe_null=func->maybe_null;
+ initid.const_item=const_item_cache;
+ initid.decimals=func->decimals;
+ initid.ptr=0;
+
+ if (u_d->func_init)
+ {
+ char *to=num_buffer;
+ for (uint i=0; i < arg_count; i++)
+ {
+ f_args.args[i]=0;
+ f_args.lengths[i]=arguments[i]->max_length;
+ f_args.maybe_null[i]=(char) arguments[i]->maybe_null;
+
+ switch(arguments[i]->type()) {
+ case Item::STRING_ITEM: // Constant string !
+ {
+ String *res=arguments[i]->val_str((String *) 0);
+ if (arguments[i]->null_value)
+ continue;
+ f_args.args[i]= (char*) res->ptr();
+ break;
+ }
+ case Item::INT_ITEM:
+ *((longlong*) to) = arguments[i]->val_int();
+ if (!arguments[i]->null_value)
+ {
+ f_args.args[i]=to;
+ to+= ALIGN_SIZE(sizeof(longlong));
+ }
+ break;
+ case Item::REAL_ITEM:
+ *((double*) to) = arguments[i]->val();
+ if (!arguments[i]->null_value)
+ {
+ f_args.args[i]=to;
+ to+= ALIGN_SIZE(sizeof(double));
+ }
+ break;
+ default: // Skip these
+ break;
+ }
+ }
+ thd->net.last_error[0]=0;
+ my_bool (*init)(UDF_INIT *, UDF_ARGS *, char *)=
+ (my_bool (*)(UDF_INIT *, UDF_ARGS *, char *))
+ u_d->func_init;
+ if ((error=(uchar) init(&initid, &f_args, thd->net.last_error)))
+ {
+ my_printf_error(ER_CANT_INITIALIZE_UDF,ER(ER_CANT_INITIALIZE_UDF),MYF(0),
+ u_d->name,thd->net.last_error);
+ free_udf(u_d);
+ DBUG_RETURN(1);
+ }
+ func->max_length=min(initid.max_length,MAX_BLOB_WIDTH);
+ func->maybe_null=initid.maybe_null;
+ const_item_cache=initid.const_item;
+ func->decimals=min(initid.decimals,31);
+ }
+ initialized=1;
+ if (error)
+ {
+ my_printf_error(ER_CANT_INITIALIZE_UDF,ER(ER_CANT_INITIALIZE_UDF),MYF(0),
+ u_d->name, ER(ER_UNKNOWN_ERROR));
+ DBUG_RETURN(1);
+ }
+ DBUG_RETURN(0);
+}
+
+
+bool udf_handler::get_arguments()
+{
+ if (error)
+ return 1; // Got an error earlier
+ char *to= num_buffer;
+ uint str_count=0;
+ for (uint i=0; i < f_args.arg_count; i++)
+ {
+ f_args.args[i]=0;
+ switch (f_args.arg_type[i]) {
+ case STRING_RESULT:
+ {
+ String *res=args[i]->val_str(&buffers[str_count++]);
+ if (!(args[i]->null_value))
+ {
+ f_args.args[i]= (char*) res->ptr();
+ f_args.lengths[i]= res->length();
+ break;
+ }
+ }
+ case INT_RESULT:
+ *((longlong*) to) = args[i]->val_int();
+ if (!args[i]->null_value)
+ {
+ f_args.args[i]=to;
+ to+= ALIGN_SIZE(sizeof(longlong));
+ }
+ break;
+ case REAL_RESULT:
+ *((double*) to) = args[i]->val();
+ if (!args[i]->null_value)
+ {
+ f_args.args[i]=to;
+ to+= ALIGN_SIZE(sizeof(double));
+ }
+ break;
+ }
+ }
+ return 0;
+}
+
+/* This returns (String*) 0 in case of NULL values */
+
+String *udf_handler::val_str(String *str,String *save_str)
+{
+ uchar is_null=0;
+ ulong res_length;
+
+ if (get_arguments())
+ return 0;
+ char * (*func)(UDF_INIT *, UDF_ARGS *, char *, ulong *, uchar *, uchar *)=
+ (char* (*)(UDF_INIT *, UDF_ARGS *, char *, ulong *, uchar *, uchar *))
+ u_d->func;
+
+ if ((res_length=str->alloced_length()) < MAX_FIELD_WIDTH)
+ { // This happens VERY seldom
+ if (str->alloc(MAX_FIELD_WIDTH))
+ {
+ error=1;
+ return 0;
+ }
+ }
+ char *res=func(&initid, &f_args, (char*) str->ptr(), &res_length, &is_null,
+ &error);
+ if (is_null || !res || error) // The !res is for safety
+ {
+ return 0;
+ }
+ if (res == str->ptr())
+ {
+ str->length(res_length);
+ return str;
+ }
+ save_str->set(res, res_length);
+ return save_str;
+}
+
+
+
+double Item_func_udf_float::val()
+{
+ DBUG_ENTER("Item_func_udf_float::val");
+ DBUG_PRINT("info",("result_type: %d arg_count: %d",
+ args[0]->result_type(), arg_count));
+ DBUG_RETURN(udf.val(&null_value));
+}
+
+
+String *Item_func_udf_float::val_str(String *str)
+{
+ double nr=val();
+ if (null_value)
+ return 0; /* purecov: inspected */
+ else
+ str->set(nr,decimals);
+ return str;
+}
+
+
+longlong Item_func_udf_int::val_int()
+{
+ DBUG_ENTER("Item_func_udf_int::val_int");
+ DBUG_PRINT("info",("result_type: %d arg_count: %d",
+ args[0]->result_type(), arg_count));
+
+ DBUG_RETURN(udf.val_int(&null_value));
+}
+
+
+String *Item_func_udf_int::val_str(String *str)
+{
+ longlong nr=val_int();
+ if (null_value)
+ return 0;
+ else
+ str->set(nr);
+ return str;
+}
+
+/* Default max_length is max argument length */
+
+void Item_func_udf_str::fix_length_and_dec()
+{
+ DBUG_ENTER("Item_func_udf_str::fix_length_and_dec");
+ max_length=0;
+ for (uint i = 0; i < arg_count; i++)
+ set_if_bigger(max_length,args[i]->max_length);
+ DBUG_VOID_RETURN;
+}
+
+String *Item_func_udf_str::val_str(String *str)
+{
+ String *res=udf.val_str(str,&str_value);
+ null_value = !res;
+ return res;
+}
+
+#else
+bool udf_handler::get_arguments() { return 0; }
+#endif /* HAVE_DLOPEN */
+
+/*
+** User level locks
+*/
+
+pthread_mutex_t LOCK_user_locks;
+static HASH hash_user_locks;
+
+class ULL
+{
+ char *key;
+ uint key_length;
+
+public:
+ int count;
+ bool locked;
+ pthread_cond_t cond;
+ pthread_t thread;
+
+ ULL(const char *key_arg,uint length) :key_length(length),count(1),locked(1)
+ {
+ key=(char*) my_memdup((byte*) key_arg,length,MYF(0));
+ pthread_cond_init(&cond,NULL);
+ if (key)
+ {
+ if (hash_insert(&hash_user_locks,(byte*) this))
+ {
+ my_free((gptr) key,MYF(0));
+ key=0;
+ }
+ }
+ }
+ ~ULL()
+ {
+ if (key)
+ {
+ hash_delete(&hash_user_locks,(byte*) this);
+ my_free((gptr) key,MYF(0));
+ }
+ pthread_cond_destroy(&cond);
+ }
+ inline bool initialized() { return key != 0; }
+ friend void item_user_lock_release(ULL *ull);
+ friend char *ull_get_key(const ULL *ull,uint *length,my_bool not_used);
+};
+
+char *ull_get_key(const ULL *ull,uint *length,
+ my_bool not_used __attribute__((unused)))
+{
+ *length=(uint) ull->key_length;
+ return (char*) ull->key;
+}
+
+void item_user_lock_init(void)
+{
+ pthread_mutex_init(&LOCK_user_locks,NULL);
+ hash_init(&hash_user_locks,16,0,0,(hash_get_key) ull_get_key,NULL,0);
+}
+
+void item_user_lock_free(void)
+{
+ hash_free(&hash_user_locks);
+}
+
+void item_user_lock_release(ULL *ull)
+{
+ ull->locked=0;
+ if (--ull->count)
+ pthread_cond_signal(&ull->cond);
+ else
+ delete ull;
+}
+
+/*
+ Get a user level lock. If the thread has an old lock this is first released.
+ Returns 1: Got lock
+ Returns 0: Timeout
+ Returns NULL: Error
+*/
+
+longlong Item_func_get_lock::val_int()
+{
+ String *res=args[0]->val_str(&value);
+ longlong timeout=args[1]->val_int();
+ struct timespec abstime;
+ THD *thd=current_thd;
+ ULL *ull;
+ int error;
+
+ pthread_mutex_lock(&LOCK_user_locks);
+
+ if (!res || !res->length())
+ {
+ pthread_mutex_unlock(&LOCK_user_locks);
+ null_value=1;
+ return 0;
+ }
+ null_value=0;
+
+ if (thd->ull)
+ {
+ item_user_lock_release(thd->ull);
+ thd->ull=0;
+ }
+
+ if (!(ull= ((ULL*) hash_search(&hash_user_locks,(byte*) res->ptr(),
+ res->length()))))
+ {
+ ull=new ULL(res->ptr(),res->length());
+ if (!ull || !ull->initialized())
+ {
+ delete ull;
+ pthread_mutex_unlock(&LOCK_user_locks);
+ null_value=1; // Probably out of memory
+ return 0;
+ }
+ ull->thread=thd->real_id;
+ thd->ull=ull;
+ pthread_mutex_unlock(&LOCK_user_locks);
+ return 1; // Got new lock
+ }
+ ull->count++;
+
+ /* structure is now initialized. Try to get the lock */
+ /* Set up control struct to allow others to abort locks */
+ pthread_mutex_lock(&thd->mysys_var->mutex);
+ thd->proc_info="User lock";
+ thd->mysys_var->current_mutex= &LOCK_user_locks;
+ thd->mysys_var->current_cond= &ull->cond;
+ pthread_mutex_unlock(&thd->mysys_var->mutex);
+
+ abstime.tv_sec=time((time_t*) 0)+(time_t) timeout;
+ abstime.tv_nsec=0;
+ while ((error=pthread_cond_timedwait(&ull->cond,&LOCK_user_locks,&abstime))
+ != ETIME && error != ETIMEDOUT && ull->locked)
+ {
+ if (thd->killed || abort_loop)
+ {
+ error=EINTR; // Return NULL
+ break;
+ }
+ }
+ if (ull->locked)
+ {
+ if (!--ull->count)
+ delete ull; // Should never happen
+ if (error != ETIME && error != ETIMEDOUT)
+ {
+ error=1;
+ null_value=1; // Return NULL
+ }
+ }
+ else
+ {
+ ull->locked=1;
+ ull->thread=thd->real_id;
+ thd->ull=ull;
+ error=0;
+ }
+ 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);
+
+ return !error ? 1 : 0;
+}
+
+
+/*
+** Release a user level lock.
+** Returns 1 if lock released
+** 0 if lock wasn't held
+** NULL if no such lock
+*/
+
+longlong Item_func_release_lock::val_int()
+{
+ String *res=args[0]->val_str(&value);
+ ULL *ull;
+ longlong result;
+ if (!res || !res->length())
+ {
+ null_value=1;
+ return 0;
+ }
+ null_value=0;
+
+ result=0;
+ pthread_mutex_lock(&LOCK_user_locks);
+ if (!(ull= ((ULL*) hash_search(&hash_user_locks,(const byte*) res->ptr(),
+ res->length()))))
+ {
+ null_value=1;
+ }
+ else
+ {
+ if (ull->locked && pthread_equal(pthread_self(),ull->thread))
+ {
+ result=1; // Release is ok
+ item_user_lock_release(ull);
+ current_thd->ull=0;
+ }
+ }
+ pthread_mutex_unlock(&LOCK_user_locks);
+ return result;
+}
+
+
+longlong Item_func_set_last_insert_id::val_int()
+{
+ longlong value=args[0]->val_int();
+ current_thd->insert_id(value);
+ null_value=args[0]->null_value;
+ return value;
+}
+
+/* This function is just used to test speed of different functions */
+
+longlong Item_func_benchmark::val_int()
+{
+ char buff[MAX_FIELD_WIDTH];
+ String tmp(buff,sizeof(buff));
+ THD *thd=current_thd;
+
+ for (ulong loop=0 ; loop < loop_count && !thd->killed; loop++)
+ {
+ switch (args[0]->result_type()) {
+ case REAL_RESULT:
+ (void) args[0]->val();
+ break;
+ case INT_RESULT:
+ (void) args[0]->val_int();
+ break;
+ case STRING_RESULT:
+ (void) args[0]->val_str(&tmp);
+ break;
+ }
+ }
+ return 0;
+}
+
+#define extra_size sizeof(double)
+
+static user_var_entry *get_variable(HASH *hash, LEX_STRING &name,
+ bool create_if_not_exists)
+{
+ user_var_entry *entry;
+
+ if (!(entry = (user_var_entry*) hash_search(hash, (byte*) name.str,
+ name.length)) &&
+ create_if_not_exists)
+ {
+ uint size=ALIGN_SIZE(sizeof(user_var_entry))+name.length+1+extra_size;
+ if (!hash_inited(hash))
+ return 0;
+ if (!(entry = (user_var_entry*) my_malloc(size,MYF(MY_WME))))
+ return 0;
+ entry->name.str=(char*) entry+ ALIGN_SIZE(sizeof(user_var_entry))+
+ extra_size;
+ entry->name.length=name.length;
+ entry->value=0;
+ entry->length=0;
+ entry->type=STRING_RESULT;
+ memcpy(entry->name.str, name.str, name.length+1);
+ if (hash_insert(hash,(byte*) entry))
+ {
+ my_free((char*) entry,MYF(0));
+ return 0;
+ }
+ }
+ return entry;
+}
+
+
+bool Item_func_set_user_var::fix_fields(THD *thd,TABLE_LIST *tables)
+{
+ if (Item_func::fix_fields(thd,tables) ||
+ !(entry= get_variable(&thd->user_vars, name, 1)))
+ return 1;
+ return 0;
+}
+
+
+void
+Item_func_set_user_var::fix_length_and_dec()
+{
+ maybe_null=args[0]->maybe_null;
+ max_length=args[0]->max_length;
+ decimals=args[0]->decimals;
+ cached_result_type=args[0]->result_type();
+}
+
+void Item_func_set_user_var::update_hash(void *ptr, uint length,
+ Item_result type)
+{
+ if ((null_value=args[0]->null_value))
+ {
+ char *pos= (char*) entry+ ALIGN_SIZE(sizeof(user_var_entry));
+ if (entry->value && entry->value != pos)
+ my_free(entry->value,MYF(0));
+ entry->value=0;
+ entry->length=0;
+ }
+ else
+ {
+ if (length <= extra_size)
+ {
+ /* Save value in value struct */
+ char *pos= (char*) entry+ ALIGN_SIZE(sizeof(user_var_entry));
+ if (entry->value != pos)
+ {
+ if (entry->value)
+ my_free(entry->value,MYF(0));
+ entry->value=pos;
+ }
+ }
+ else
+ {
+ /* Allocate variable */
+ if (entry->length != length)
+ {
+ char *pos= (char*) entry+ ALIGN_SIZE(sizeof(user_var_entry));
+ if (entry->value == pos)
+ entry->value=0;
+ if (!(entry->value=(char*) my_realloc(entry->value, length,
+ MYF(MY_ALLOW_ZERO_PTR))))
+ goto err;
+ }
+ }
+ memcpy(entry->value,ptr,length);
+ entry->length= length;
+ entry->type=type;
+ }
+ return;
+
+ err:
+ current_thd->fatal_error=1; // Probably end of memory
+ null_value=1;
+ return;
+}
+
+
+bool
+Item_func_set_user_var::update()
+{
+ switch (cached_result_type) {
+ case REAL_RESULT:
+ (void) val();
+ break;
+ case INT_RESULT:
+ (void) val_int();
+ break;
+ case STRING_RESULT:
+ char buffer[MAX_FIELD_WIDTH];
+ String tmp(buffer,sizeof(buffer));
+ (void) val_str(&tmp);
+ break;
+ }
+ return current_thd->fatal_error;
+}
+
+
+double
+Item_func_set_user_var::val()
+{
+ double value=args[0]->val();
+ update_hash((void*) &value,sizeof(value), REAL_RESULT);
+ return value;
+}
+
+longlong
+Item_func_set_user_var::val_int()
+{
+ longlong value=args[0]->val_int();
+ update_hash((void*) &value,sizeof(longlong),INT_RESULT);
+ return value;
+}
+
+String *
+Item_func_set_user_var::val_str(String *str)
+{
+ String *res=args[0]->val_str(str);
+ if (!res) // Null value
+ update_hash((void*) 0,0,STRING_RESULT);
+ else
+ update_hash(res->c_ptr(),res->length()+1,STRING_RESULT);
+ return res;
+}
+
+
+user_var_entry *Item_func_get_user_var::get_entry()
+{
+ if (!entry || ! entry->value)
+ {
+ null_value=1;
+ return 0;
+ }
+ null_value=0;
+ return entry;
+}
+
+
+String *
+Item_func_get_user_var::val_str(String *str)
+{
+ user_var_entry *entry=get_entry();
+ if (!entry)
+ return NULL;
+ switch (entry->type) {
+ case REAL_RESULT:
+ str->set(*(double*) entry->value);
+ break;
+ case INT_RESULT:
+ str->set(*(longlong*) entry->value);
+ break;
+ case STRING_RESULT:
+ if (str->copy(entry->value, entry->length-1))
+ {
+ null_value=1;
+ return NULL;
+ }
+ break;
+ }
+ return str;
+}
+
+
+double Item_func_get_user_var::val()
+{
+ user_var_entry *entry=get_entry();
+ if (!entry)
+ return 0.0;
+ switch (entry->type) {
+ case REAL_RESULT:
+ return *(double*) entry->value;
+ case INT_RESULT:
+ return (double) *(longlong*) entry->value;
+ case STRING_RESULT:
+ return atof(entry->value); // This is null terminated
+ }
+ return 0.0; // Impossible
+}
+
+
+longlong Item_func_get_user_var::val_int()
+{
+ user_var_entry *entry=get_entry();
+ if (!entry)
+ return LL(0);
+ switch (entry->type) {
+ case REAL_RESULT:
+ return (longlong) *(double*) entry->value;
+ case INT_RESULT:
+ return *(longlong*) entry->value;
+ case STRING_RESULT:
+ return strtoull(entry->value,NULL,10); // String is null terminated
+ }
+ return LL(0); // Impossible
+}
+
+
+void Item_func_get_user_var::fix_length_and_dec()
+{
+ maybe_null=1;
+ decimals=NOT_FIXED_DEC;
+ max_length=MAX_BLOB_WIDTH;
+ entry= get_variable(&current_thd->user_vars, name, 0);
+}
+
+
+enum Item_result Item_func_get_user_var::result_type() const
+{
+ user_var_entry *entry;
+ if (!(entry = (user_var_entry*) hash_search(&current_thd->user_vars,
+ (byte*) name.str,
+ name.length)))
+ return STRING_RESULT;
+ return entry->type;
+}
+
+longlong Item_func_inet_aton::val_int()
+{
+ uint byte_result = 0;
+ ulonglong result = 0; // We are ready for 64 bit addresses
+ const char *p,* end;
+ char c = '.'; // we mark c to indicate invalid IP in case length is 0
+ char buff[36];
+
+ String *s,tmp(buff,sizeof(buff));
+ if (!(s = args[0]->val_str(&tmp))) // If null value
+ goto err;
+ null_value=0;
+
+ end= (p = s->ptr()) + s->length();
+ while (p < end)
+ {
+ c = *p++;
+ int digit = (int) (c - '0'); // Assume ascii
+ if (digit >= 0 && digit <= 9)
+ {
+ if ((byte_result = byte_result * 10 + digit) > 255)
+ goto err; // Wrong address
+ }
+ else if (c == '.')
+ {
+ result= (result << 8) + (ulonglong) byte_result;
+ byte_result = 0;
+ }
+ else
+ goto err; // Invalid character
+ }
+ if (c != '.') // IP number can't end on '.'
+ return (result << 8) + (ulonglong) byte_result;
+
+err:
+ null_value=1;
+ return 0;
+}
+
+double Item_func_match::val()
+{
+ int a,b,c;
+ FT_DOC *docs;
+ my_off_t docid;
+
+ docid = table->file->row_position(); // HAVE to do it here...
+
+ if (table->file->ft_handler==NULL && !auto_init_was_done)
+ {
+ /* join won't use this ft-key, but we must to init it anyway */
+ String *ft_tmp=0;
+ char tmp1[FT_QUERY_MAXLEN];
+ String tmp2(tmp1,sizeof(tmp1));
+
+ ft_tmp=key_item()->val_str(&tmp2);
+ table->file->ft_init(key, (byte*) ft_tmp->ptr(), ft_tmp->length(), FALSE);
+ auto_init_was_done=1;
+ }
+
+ // Don't know how to return an error from val(), so NULL will be returned
+ if ((null_value=(table->file->ft_handler==NULL)))
+ return 0.0;
+
+ if (auto_init_was_done)
+ {
+ /* implicit initialization was done, so nobody will set proper
+ ft_relevance for us. We'll look for it in ft_handler array */
+
+ docs = ((FT_DOCLIST *)table->file->ft_handler)->doc;
+// docid = table->file->row_position();
+
+ if ((null_value=(docid==HA_OFFSET_ERROR)))
+ return 0.0;
+
+ // Assuming docs[] is sorted by dpos...
+
+ a=0, b=((FT_DOCLIST *)table->file->ft_handler)->ndocs;
+ for (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)
+ table->file->ft_relevance=docs[a].weight;
+ else
+ table->file->ft_relevance=0;
+ }
+
+ return table->file->ft_relevance;
+}
+
+bool Item_func_match::fix_fields(THD *thd,struct st_table_list *tlist)
+{
+ List_iterator<Item> li(fields);
+ Item *item;
+
+ /* Why testing for const_item ? Monty */
+ /* I'll remove it later, but this should include modifications to
+ find_best and auto_close as complement to auto_init code above. SerG */
+ if (Item_func::fix_fields(thd,tlist) || !const_item())
+ return 1;
+
+ while ((item=li++))
+ {
+ if (item->type() != Item::FIELD_ITEM || item->fix_fields(thd,tlist) ||
+ !item->used_tables())
+ return 1;
+ used_tables_cache|=item->used_tables();
+ }
+ /* check that all columns comes from the same table */
+ if (count_bits(used_tables_cache) != 1)
+ return 1;
+ const_item_cache=0;
+ table=((Item_field *)fields.head())->field->table;
+ auto_init_was_done=0;
+ table->file->ft_close(); // It's a bad solution to do it here, I know :-(
+ return 0;
+}
+
+
+bool Item_func_match::fix_index()
+{
+ List_iterator<Item> li(fields);
+ Item_field *item;
+ uint ft_to_key[MAX_KEY], ft_cnt[MAX_KEY], fts=0, key;
+
+ for (key=0 ; key<table->keys ; key++)
+ {
+ if ((table->key_info[key].flags & HA_FULLTEXT) &&
+ (table->keys_in_use_for_query & (((key_map)1) << key)))
+ {
+ ft_to_key[fts]=key;
+ ft_cnt[fts]=0;
+ fts++;
+ }
+ }
+
+ if (!fts)
+ {
+ my_printf_error(ER_FT_MATCHING_KEY_NOT_FOUND,
+ ER(ER_FT_MATCHING_KEY_NOT_FOUND),MYF(0));
+ return 1;
+ }
+
+ while ((item=(Item_field*)(li++)))
+ {
+ for (key=0 ; key<fts ; key++)
+ {
+ KEY *ft_key=&table->key_info[ft_to_key[key]];
+ uint key_parts=ft_key->key_parts;
+
+ for (uint part=0 ; part < key_parts ; part++)
+ {
+ if (item->field->eq(ft_key->key_part[part].field))
+ ft_cnt[key]++;
+ }
+ }
+ }
+
+ uint max_cnt=0, max_key=0;
+ for (key=0 ; key<fts ; key++)
+ {
+ if (ft_cnt[key] > max_cnt)
+ {
+ max_cnt=ft_cnt[key];
+ max_key=ft_to_key[key];
+ }
+ }
+
+ // for now, partial keys won't work. SerG
+
+ if (max_cnt < fields.elements ||
+ max_cnt < table->key_info[max_key].key_parts)
+ {
+ my_printf_error(ER_FT_MATCHING_KEY_NOT_FOUND,
+ ER(ER_FT_MATCHING_KEY_NOT_FOUND),MYF(0));
+ return 1;
+ }
+
+ this->key=max_key;
+
+ maybe_null=1;
+
+ return 0;
+}
+
+
diff --git a/sql/item_func.h b/sql/item_func.h
new file mode 100644
index 00000000000..bd66ebde3c2
--- /dev/null
+++ b/sql/item_func.h
@@ -0,0 +1,857 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 items used by mysql */
+
+#ifdef __GNUC__
+#pragma interface /* gcc class implementation */
+#endif
+
+#ifdef HAVE_IEEEFP_H
+extern "C" /* Bug in BSDI include file */
+{
+#include <ieeefp.h>
+}
+#endif
+
+class Item_func :public Item_result_field
+{
+protected:
+ Item **args,*tmp_arg[2];
+public:
+ uint arg_count;
+ table_map used_tables_cache;
+ bool const_item_cache;
+ enum Functype { UNKNOWN_FUNC,EQ_FUNC,EQUAL_FUNC,NE_FUNC,LT_FUNC,LE_FUNC,
+ GE_FUNC,GT_FUNC,FT_FUNC,
+ LIKE_FUNC,NOTLIKE_FUNC,ISNULL_FUNC,ISNOTNULL_FUNC,
+ COND_AND_FUNC,COND_OR_FUNC,BETWEEN,IN_FUNC,INTERVAL_FUNC};
+ enum optimize_type { OPTIMIZE_NONE,OPTIMIZE_KEY,OPTIMIZE_OP, OPTIMIZE_NULL };
+ enum Type type() const { return FUNC_ITEM; }
+ virtual enum Functype functype() const { return UNKNOWN_FUNC; }
+ Item_func(void)
+ {
+ arg_count=0; with_sum_func=0;
+ }
+ Item_func(Item *a)
+ {
+ arg_count=1;
+ args=tmp_arg;
+ args[0]=a;
+ with_sum_func=a->with_sum_func;
+ }
+ Item_func(Item *a,Item *b)
+ {
+ arg_count=2;
+ args=tmp_arg;
+ args[0]=a; args[1]=b;
+ with_sum_func=a->with_sum_func || b->with_sum_func;
+ }
+ Item_func(Item *a,Item *b,Item *c)
+ {
+ arg_count=0;
+ if ((args=(Item**) sql_alloc(sizeof(Item*)*3)))
+ {
+ arg_count=3;
+ args[0]=a; args[1]=b; args[2]=c;
+ with_sum_func=a->with_sum_func || b->with_sum_func || c->with_sum_func;
+ }
+ }
+ Item_func(Item *a,Item *b,Item *c,Item *d)
+ {
+ arg_count=0;
+ if ((args=(Item**) sql_alloc(sizeof(Item*)*4)))
+ {
+ arg_count=4;
+ args[0]=a; args[1]=b; args[2]=c; args[3]=d;
+ with_sum_func=a->with_sum_func || b->with_sum_func || c->with_sum_func ||
+ d->with_sum_func;
+ }
+ }
+ Item_func(Item *a,Item *b,Item *c,Item *d,Item* e)
+ {
+ arg_count=5;
+ if ((args=(Item**) sql_alloc(sizeof(Item*)*5)))
+ {
+ args[0]=a; args[1]=b; args[2]=c; args[3]=d; args[4]=e;
+ with_sum_func=a->with_sum_func || b->with_sum_func || c->with_sum_func ||
+ d->with_sum_func || e->with_sum_func ;
+ }
+ }
+ Item_func(List<Item> &list);
+ ~Item_func() {} /* Nothing to do; Items are freed automaticly */
+ bool fix_fields(THD *,struct st_table_list *);
+ void make_field(Send_field *field);
+ table_map used_tables() const;
+ void update_used_tables();
+ bool eq(const Item *item) const;
+ virtual optimize_type select_optimize() const { return OPTIMIZE_NONE; }
+ virtual bool have_rev_func() const { return 0; }
+ virtual Item *key_item() const { return args[0]; }
+ virtual const char *func_name() const { return "?"; }
+ virtual bool const_item() const { return const_item_cache; }
+ inline Item **arguments() const { return args; }
+ inline uint argument_count() const { return arg_count; }
+ inline void remove_arguments() { arg_count=0; }
+ virtual void split_sum_func(List<Item> &fields);
+ void print(String *str);
+ void print_op(String *str);
+ void fix_num_length_and_dec();
+ inline bool get_arg0_date(TIME *ltime,bool fuzzy_date)
+ {
+ return (null_value=args[0]->get_date(ltime,fuzzy_date));
+ }
+ inline bool get_arg0_time(TIME *ltime)
+ {
+ return (null_value=args[0]->get_time(ltime));
+ }
+ friend class udf_handler;
+};
+
+
+class Item_real_func :public Item_func
+{
+public:
+ Item_real_func() :Item_func() {}
+ Item_real_func(Item *a) :Item_func(a) {}
+ Item_real_func(Item *a,Item *b) :Item_func(a,b) {}
+ Item_real_func(List<Item> &list) :Item_func(list) {}
+ String *val_str(String*str);
+ longlong val_int() { 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); }
+};
+
+class Item_num_func :public Item_func
+{
+ protected:
+ Item_result hybrid_type;
+public:
+ Item_num_func(Item *a) :Item_func(a),hybrid_type(REAL_RESULT) {}
+ Item_num_func(Item *a,Item *b) :Item_func(a,b),hybrid_type(REAL_RESULT) {}
+ String *val_str(String*str);
+ longlong val_int() { return (longlong) val(); }
+ enum Item_result result_type () const { return hybrid_type; }
+ void fix_length_and_dec() { fix_num_length_and_dec(); }
+};
+
+
+class Item_num_op :public Item_func
+{
+ protected:
+ Item_result hybrid_type;
+ public:
+ Item_num_op(Item *a,Item *b) :Item_func(a,b),hybrid_type(REAL_RESULT) {}
+ String *val_str(String*str);
+ void print(String *str) { print_op(str); }
+ enum Item_result result_type () const { return hybrid_type; }
+ void fix_length_and_dec() { fix_num_length_and_dec(); find_num_type(); }
+ void find_num_type(void);
+};
+
+
+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) {}
+ 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; }
+};
+
+class Item_func_plus :public Item_num_op
+{
+public:
+ Item_func_plus(Item *a,Item *b) :Item_num_op(a,b) {}
+ const char *func_name() const { return "+"; }
+ double val();
+ longlong val_int();
+};
+
+class Item_func_minus :public Item_num_op
+{
+public:
+ Item_func_minus(Item *a,Item *b) :Item_num_op(a,b) {}
+ const char *func_name() const { return "-"; }
+ double val();
+ longlong val_int();
+};
+
+class Item_func_mul :public Item_num_op
+{
+public:
+ Item_func_mul(Item *a,Item *b) :Item_num_op(a,b) {}
+ const char *func_name() const { return "*"; }
+ double val();
+ longlong val_int();
+};
+
+
+class Item_func_div :public Item_num_op
+{
+public:
+ Item_func_div(Item *a,Item *b) :Item_num_op(a,b) {}
+ double val();
+ longlong val_int();
+ const char *func_name() const { return "/"; }
+ void fix_length_and_dec();
+};
+
+
+class Item_func_mod :public Item_num_op
+{
+public:
+ Item_func_mod(Item *a,Item *b) :Item_num_op(a,b) {}
+ double val();
+ longlong val_int();
+ const char *func_name() const { return "%"; }
+ void fix_length_and_dec();
+};
+
+
+class Item_func_neg :public Item_num_func
+{
+public:
+ Item_func_neg(Item *a) :Item_num_func(a) {}
+ double val();
+ longlong val_int();
+ const char *func_name() const { return "-"; }
+ void fix_length_and_dec();
+};
+
+
+class Item_func_abs :public Item_num_func
+{
+public:
+ Item_func_abs(Item *a) :Item_num_func(a) {}
+ const char *func_name() const { return "abs"; }
+ double val();
+ longlong val_int();
+ enum Item_result result_type () const
+ { return args[0]->result_type() == INT_RESULT ? INT_RESULT : REAL_RESULT; }
+ void fix_length_and_dec();
+};
+
+// A class to handle logaritmic and trigometric functions
+
+class Item_dec_func :public Item_real_func
+{
+ public:
+ Item_dec_func(Item *a) :Item_real_func(a) {}
+ Item_dec_func(Item *a,Item *b) :Item_real_func(a,b) {}
+ void fix_length_and_dec()
+ {
+ decimals=6; max_length=float_length(decimals);
+ maybe_null=1;
+ }
+ inline double fix_result(double value)
+ {
+#ifndef HAVE_FINITE
+ return value;
+#else
+ if (finite(value) && value != POSTFIX_ERROR)
+ return value;
+ null_value=1;
+ return 0.0;
+#endif
+ }
+};
+
+class Item_func_exp :public Item_dec_func
+{
+public:
+ Item_func_exp(Item *a) :Item_dec_func(a) {}
+ double val();
+ const char *func_name() const { return "exp"; }
+};
+
+class Item_func_log :public Item_dec_func
+{
+public:
+ Item_func_log(Item *a) :Item_dec_func(a) {}
+ double val();
+ const char *func_name() const { return "log"; }
+};
+
+
+class Item_func_log10 :public Item_dec_func
+{
+public:
+ Item_func_log10(Item *a) :Item_dec_func(a) {}
+ double val();
+ const char *func_name() const { return "log10"; }
+};
+
+
+class Item_func_sqrt :public Item_dec_func
+{
+public:
+ Item_func_sqrt(Item *a) :Item_dec_func(a) {}
+ double val();
+ const char *func_name() const { return "sqrt"; }
+};
+
+
+class Item_func_pow :public Item_dec_func
+{
+public:
+ Item_func_pow(Item *a,Item *b) :Item_dec_func(a,b) {}
+ double val();
+ const char *func_name() const { return "pow"; }
+};
+
+
+class Item_func_acos :public Item_dec_func
+{
+ public:
+ Item_func_acos(Item *a) :Item_dec_func(a) {}
+ double val();
+ const char *func_name() const { return "acos"; }
+};
+
+class Item_func_asin :public Item_dec_func
+{
+ public:
+ Item_func_asin(Item *a) :Item_dec_func(a) {}
+ double val();
+ const char *func_name() const { return "asin"; }
+};
+
+class Item_func_atan :public Item_dec_func
+{
+ public:
+ Item_func_atan(Item *a) :Item_dec_func(a) {}
+ Item_func_atan(Item *a,Item *b) :Item_dec_func(a,b) {}
+ double val();
+ const char *func_name() const { return "atan"; }
+};
+
+class Item_func_cos :public Item_dec_func
+{
+ public:
+ Item_func_cos(Item *a) :Item_dec_func(a) {}
+ double val();
+ const char *func_name() const { return "cos"; }
+};
+
+class Item_func_sin :public Item_dec_func
+{
+ public:
+ Item_func_sin(Item *a) :Item_dec_func(a) {}
+ double val();
+ const char *func_name() const { return "sin"; }
+};
+
+class Item_func_tan :public Item_dec_func
+{
+ public:
+ Item_func_tan(Item *a) :Item_dec_func(a) {}
+ double val();
+ const char *func_name() const { return "tan"; }
+};
+
+class Item_func_integer :public Item_int_func
+{
+public:
+ inline Item_func_integer(Item *a) :Item_int_func(a) {}
+ void fix_length_and_dec();
+};
+
+
+class Item_func_ceiling :public Item_func_integer
+{
+ Item_func_ceiling(); /* Never called */
+public:
+ Item_func_ceiling(Item *a) :Item_func_integer(a) {}
+ const char *func_name() const { return "ceiling"; }
+ longlong val_int();
+};
+
+class Item_func_floor :public Item_func_integer
+{
+public:
+ Item_func_floor(Item *a) :Item_func_integer(a) {}
+ const char *func_name() const { return "floor"; }
+ longlong val_int();
+};
+
+/* This handles round and truncate */
+
+class Item_func_round :public Item_real_func
+{
+ bool truncate;
+public:
+ Item_func_round(Item *a,Item *b,bool trunc_arg)
+ :Item_real_func(a,b),truncate(trunc_arg) {}
+ const char *func_name() const { return truncate ? "truncate" : "round"; }
+ double val();
+ void fix_length_and_dec();
+};
+
+
+class Item_func_rand :public Item_real_func
+{
+public:
+ Item_func_rand(Item *a) :Item_real_func(a) {}
+ Item_func_rand() :Item_real_func() {}
+ double val();
+ const char *func_name() const { return "rand"; }
+ void fix_length_and_dec() { decimals=NOT_FIXED_DEC; max_length=float_length(decimals); }
+ bool const_item() const { return 0; }
+ table_map used_tables() const { return RAND_TABLE_BIT; }
+};
+
+
+class Item_func_sign :public Item_int_func
+{
+public:
+ Item_func_sign(Item *a) :Item_int_func(a) {}
+ const char *func_name() const { return "sign"; }
+ longlong val_int();
+};
+
+
+class Item_func_units :public Item_real_func
+{
+ char *name;
+ double mul,add;
+ public:
+ Item_func_units(char *name_arg,Item *a,double mul_arg,double add_arg)
+ :Item_real_func(a),name(name_arg),mul(mul_arg),add(add_arg) {}
+ double val();
+ const char *func_name() const { return name; }
+ void fix_length_and_dec() { decimals=NOT_FIXED_DEC; max_length=float_length(decimals); }
+};
+
+
+class Item_func_min_max :public Item_func
+{
+ Item_result cmp_type;
+ String tmp_value;
+ int cmp_sign;
+public:
+ Item_func_min_max(List<Item> &list,int cmp_sign_arg) :Item_func(list),
+ cmp_sign(cmp_sign_arg) {}
+ double val();
+ longlong val_int();
+ String *val_str(String *);
+ void fix_length_and_dec();
+ enum Item_result result_type () const { return cmp_type; }
+};
+
+class Item_func_min :public Item_func_min_max
+{
+public:
+ Item_func_min(List<Item> &list) :Item_func_min_max(list,1) {}
+ const char *func_name() const { return "least"; }
+};
+
+class Item_func_max :public Item_func_min_max
+{
+public:
+ Item_func_max(List<Item> &list) :Item_func_min_max(list,-1) {}
+ const char *func_name() const { return "greatest"; }
+};
+
+
+class Item_func_length :public Item_int_func
+{
+ String value;
+public:
+ Item_func_length(Item *a) :Item_int_func(a) {}
+ longlong val_int();
+ const char *func_name() const { return "length"; }
+ void fix_length_and_dec() { max_length=10; }
+};
+
+class Item_func_char_length :public Item_int_func
+{
+ String value;
+public:
+ Item_func_char_length(Item *a) :Item_int_func(a) {}
+ longlong val_int();
+ const char *func_name() const { return "char_length"; }
+ void fix_length_and_dec() { max_length=10; }
+};
+
+class Item_func_locate :public Item_int_func
+{
+ String value1,value2;
+public:
+ Item_func_locate(Item *a,Item *b) :Item_int_func(a,b) {}
+ Item_func_locate(Item *a,Item *b,Item *c) :Item_int_func(a,b,c) {}
+ const char *func_name() const { return "locate"; }
+ longlong val_int();
+ void fix_length_and_dec() { maybe_null=0; max_length=11; }
+};
+
+
+class Item_func_field :public Item_int_func
+{
+ Item *item;
+ String value,tmp;
+public:
+ Item_func_field(Item *a,List<Item> &list) :Item_int_func(list),item(a) {}
+ ~Item_func_field() { delete item; }
+ longlong val_int();
+ bool fix_fields(THD *thd,struct st_table_list *tlist)
+ {
+ return (item->fix_fields(thd,tlist) || Item_func::fix_fields(thd,tlist));
+ }
+ void update_used_tables()
+ {
+ item->update_used_tables() ; Item_func::update_used_tables();
+ used_tables_cache|=item->used_tables();
+ }
+ const char *func_name() const { return "field"; }
+ void fix_length_and_dec()
+ { maybe_null=0; max_length=2; used_tables_cache|=item->used_tables();}
+};
+
+
+class Item_func_ascii :public Item_int_func
+{
+ String value;
+public:
+ Item_func_ascii(Item *a) :Item_int_func(a) {}
+ longlong val_int();
+ const char *func_name() const { return "ascii"; }
+ void fix_length_and_dec() { max_length=3; }
+};
+
+class Item_func_ord :public Item_int_func
+{
+ String value;
+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
+{
+ String value,value2;
+ uint enum_value;
+ ulonglong enum_bit;
+public:
+ Item_func_find_in_set(Item *a,Item *b) :Item_int_func(a,b),enum_value(0) {}
+ longlong val_int();
+ const char *func_name() const { return "find_in_set"; }
+ void fix_length_and_dec();
+};
+
+
+class Item_func_bit_or :public Item_int_func
+{
+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; }
+};
+
+class Item_func_bit_and :public Item_int_func
+{
+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; }
+};
+
+class Item_func_bit_count :public Item_int_func
+{
+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; }
+};
+
+class Item_func_shift_left :public Item_int_func
+{
+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; }
+};
+
+class Item_func_shift_right :public Item_int_func
+{
+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
+{
+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; }
+};
+
+class Item_func_set_last_insert_id :public Item_int_func
+{
+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; }
+};
+
+class Item_func_benchmark :public Item_int_func
+{
+ ulong loop_count;
+ public:
+ Item_func_benchmark(ulong loop_count_arg,Item *expr)
+ :Item_int_func(expr), loop_count(loop_count_arg)
+ {}
+ longlong val_int();
+ const char *func_name() const { return "benchmark"; }
+ void fix_length_and_dec() { decimals=0; max_length=1; maybe_null=0; }
+};
+
+
+#ifdef HAVE_DLOPEN
+
+class Item_udf_func :public Item_func
+{
+ protected:
+ udf_handler udf;
+
+public:
+ Item_udf_func(udf_func *udf_arg) :Item_func(), udf(udf_arg) {}
+ Item_udf_func(udf_func *udf_arg, List<Item> &list)
+ :Item_func(list), udf(udf_arg) {}
+ ~Item_udf_func() {}
+ const char *func_name() const { return udf.name(); }
+ bool fix_fields(THD *thd,struct st_table_list *tables)
+ {
+ bool res=udf.fix_fields(thd,tables,this,arg_count,args);
+ used_tables_cache=udf.used_tables_cache;
+ const_item_cache=udf.const_item_cache;
+ return res;
+ }
+ Item_result result_type () const { return udf.result_type(); }
+};
+
+
+class Item_func_udf_float :public Item_udf_func
+{
+ public:
+ Item_func_udf_float(udf_func *udf_arg) :Item_udf_func(udf_arg) {}
+ Item_func_udf_float(udf_func *udf_arg, List<Item> &list)
+ :Item_udf_func(udf_arg,list) {}
+ ~Item_func_udf_float() {}
+ longlong val_int() { return (longlong) Item_func_udf_float::val(); }
+ double val();
+ String *val_str(String *str);
+ void fix_length_and_dec() { fix_num_length_and_dec(); }
+};
+
+
+class Item_func_udf_int :public Item_udf_func
+{
+public:
+ Item_func_udf_int(udf_func *udf_arg) :Item_udf_func(udf_arg) {}
+ Item_func_udf_int(udf_func *udf_arg, List<Item> &list)
+ :Item_udf_func(udf_arg,list) {}
+ ~Item_func_udf_int() {}
+ longlong val_int();
+ double val() { return (double) Item_func_udf_int::val_int(); }
+ String *val_str(String *str);
+ enum Item_result result_type () const { return INT_RESULT; }
+ void fix_length_and_dec() { decimals=0; max_length=21; }
+};
+
+
+class Item_func_udf_str :public Item_udf_func
+{
+public:
+ Item_func_udf_str(udf_func *udf_arg) :Item_udf_func(udf_arg) {}
+ Item_func_udf_str(udf_func *udf_arg, List<Item> &list)
+ :Item_udf_func(udf_arg,list) {}
+ ~Item_func_udf_str() {}
+ String *val_str(String *);
+ double val()
+ {
+ String *res; res=val_str(&str_value);
+ return res ? atof(res->c_ptr()) : 0.0;
+ }
+ longlong val_int()
+ {
+ String *res; res=val_str(&str_value);
+ return res ? strtoll(res->c_ptr(),(char**) 0,10) : (longlong) 0;
+ }
+ enum Item_result result_type () const { return STRING_RESULT; }
+ void fix_length_and_dec();
+};
+
+#else /* Dummy functions to get sql_yacc.cc compiled */
+
+class Item_func_udf_float :public Item_real_func
+{
+ public:
+ Item_func_udf_float(udf_func *udf_arg) :Item_real_func() {}
+ Item_func_udf_float(udf_func *udf_arg, List<Item> &list) :Item_real_func(list) {}
+ ~Item_func_udf_float() {}
+ double val() { return 0.0; }
+};
+
+
+class Item_func_udf_int :public Item_int_func
+{
+public:
+ Item_func_udf_int(udf_func *udf_arg) :Item_int_func() {}
+ Item_func_udf_int(udf_func *udf_arg, List<Item> &list) :Item_int_func(list) {}
+ ~Item_func_udf_int() {}
+ longlong val_int() { return 0; }
+};
+
+
+class Item_func_udf_str :public Item_func
+{
+public:
+ Item_func_udf_str(udf_func *udf_arg) :Item_func() {}
+ Item_func_udf_str(udf_func *udf_arg, List<Item> &list) :Item_func(list) {}
+ ~Item_func_udf_str() {}
+ String *val_str(String *) { null_value=1; return 0; }
+ double val() { null_value=1; return 0.0; }
+ longlong val_int() { null_value=1; return 0; }
+ enum Item_result result_type () const { return STRING_RESULT; }
+ void fix_length_and_dec() { maybe_null=1; max_length=0; }
+};
+
+#endif /* HAVE_DLOPEN */
+
+/*
+** User level locks
+*/
+
+class ULL;
+void item_user_lock_init(void);
+void item_user_lock_release(ULL *ull);
+void item_user_lock_free(void);
+
+class Item_func_get_lock :public Item_int_func
+{
+ String value;
+ public:
+ 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;}
+};
+
+class Item_func_release_lock :public Item_int_func
+{
+ String value;
+ public:
+ 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;}
+};
+
+
+/* Handling of user definiable variables */
+
+class user_var_entry;
+
+class Item_func_set_user_var :public Item_func
+{
+ enum Item_result cached_result_type;
+ LEX_STRING name;
+ user_var_entry *entry;
+
+public:
+ Item_func_set_user_var(LEX_STRING a,Item *b): Item_func(b), name(a) {}
+ double val();
+ longlong val_int();
+ String *val_str(String *str);
+ void update_hash(void *ptr, uint length, enum Item_result type);
+ bool update();
+ enum Item_result result_type () const { return cached_result_type; }
+ bool fix_fields(THD *thd,struct st_table_list *tables);
+ void fix_length_and_dec();
+ const char *func_name() const { return "set_user_var"; }
+};
+
+
+class Item_func_get_user_var :public Item_func
+{
+ LEX_STRING name;
+ user_var_entry *entry;
+
+public:
+ Item_func_get_user_var(LEX_STRING a): Item_func(), name(a) {}
+ user_var_entry *get_entry();
+ double val();
+ longlong val_int();
+ String *val_str(String* str);
+ void fix_length_and_dec();
+ enum Item_result result_type() const;
+ const char *func_name() const { return "get_user_var"; }
+};
+
+class Item_func_inet_aton : public Item_int_func
+{
+public:
+ Item_func_inet_aton(Item *a) :Item_int_func(a) {}
+ longlong val_int();
+ const char *func_name() const { return "inet_aton"; }
+ void fix_length_and_dec() { decimals = 0; max_length = 21; maybe_null=1;}
+};
+
+
+/* SerG: for fulltext search */
+
+class Item_func_match :public Item_real_func
+{
+public:
+ // handler *File;
+ List<Item> fields;
+ TABLE *table;
+ uint key;
+ bool auto_init_was_done;
+
+ Item_func_match(List<Item> &a, Item *b): Item_real_func(b),
+ fields(a), table(0)
+ {}
+ ~Item_func_match() {}
+ const char *func_name() const { return "match"; }
+ //optimize_type select_optimize() const { return OPTIMIZE_FT; }
+ enum Functype functype() const { return FT_FUNC; }
+ void update_used_tables() {}
+ bool fix_fields(THD *thd,struct st_table_list *tlist);
+ bool fix_index();
+
+ double val();
+ longlong val_int() { return val()!=0.0; }
+};
+
diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc
new file mode 100644
index 00000000000..3050125f410
--- /dev/null
+++ b/sql/item_strfunc.cc
@@ -0,0 +1,1719 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 defines all string functions
+** Warning: Some string functions doesn't always put and end-null on a String
+** (This shouldn't be neaded)
+*/
+
+#ifdef __GNUC__
+#pragma implementation // gcc: Class implementation
+#endif
+
+#include "mysql_priv.h"
+#include "sql_acl.h"
+#include <m_ctype.h>
+#ifdef HAVE_CRYPT_H
+#include <crypt.h>
+#endif
+
+#include "md5.h"
+
+String empty_string("");
+
+uint nr_of_decimals(const char *str)
+{
+ if ((str=strchr(str,'.')))
+ {
+ const char *start= ++str;
+ for ( ; isdigit(*str) ; str++) ;
+ return (uint) (str-start);
+ }
+ return 0;
+}
+
+double Item_str_func::val()
+{
+ String *res;
+ res=val_str(&str_value);
+ return res ? atof(res->c_ptr()) : 0.0;
+}
+
+longlong Item_str_func::val_int()
+{
+ String *res;
+ res=val_str(&str_value);
+ return res ? strtoll(res->c_ptr(),NULL,10) : (longlong) 0;
+}
+
+
+String *Item_func_md5::val_str(String *str)
+{
+ String * sptr= args[0]->val_str(str);
+ if (sptr)
+ {
+ 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
+ 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],
+ digest[4], digest[5], digest[6], digest[7],
+ digest[8], digest[9], digest[10], digest[11],
+ digest[12], digest[13], digest[14], digest[15]);
+ str->length((uint) 32);
+ return str;
+ }
+ null_value=1;
+ return 0;
+}
+
+
+void Item_func_md5::fix_length_and_dec()
+{
+ max_length=32;
+}
+
+/*
+** Concatinate args with the following premissess
+** If only one arg which is ok, return value of arg
+** Don't reallocate val_str() if not absolute necessary.
+*/
+
+String *Item_func_concat::val_str(String *str)
+{
+ String *res,*res2,*use_as_buff;
+ uint i;
+
+ null_value=0;
+ if (!(res=args[0]->val_str(str)))
+ goto null;
+ use_as_buff= &tmp_value;
+ for (i=1 ; i < arg_count ; i++)
+ {
+ if (res->length() == 0)
+ {
+ if (!(res=args[i]->val_str(str)))
+ goto null;
+ }
+ else
+ {
+ if (!(res2=args[i]->val_str(use_as_buff)))
+ goto null;
+ if (res2->length() == 0)
+ continue;
+ if (res->length()+res2->length() > max_allowed_packet)
+ goto null; // Error check
+ if (res->alloced_length() >= res->length()+res2->length())
+ { // Use old buffer
+ res->append(*res2);
+ }
+ else if (str->alloced_length() >= res->length()+res2->length())
+ {
+ if (str == res2)
+ str->replace(0,0,*res);
+ else
+ {
+ str->copy(*res);
+ str->append(*res2);
+ }
+ res=str;
+ }
+ else if (res == &tmp_value)
+ {
+ if (res->append(*res2)) // Must be a blob
+ goto null;
+ }
+ else if (res2 == &tmp_value)
+ { // This can happend only 1 time
+ if (tmp_value.replace(0,0,*res))
+ goto null;
+ res= &tmp_value;
+ use_as_buff=str; // Put next arg here
+ }
+ else if (tmp_value.is_alloced() && res2->ptr() >= tmp_value.ptr() &&
+ res2->ptr() <= tmp_value.ptr() + tmp_value.alloced_length())
+ {
+ /*
+ This happens really seldom:
+ In this case res2 is sub string of tmp_value. We will
+ now work in place in tmp_value to set it to res | res2
+ */
+ /* Chop the last characters in tmp_value that isn't in res2 */
+ tmp_value.length((uint32) (res2->ptr() - tmp_value.ptr()) +
+ res2->length());
+ /* Place res2 at start of tmp_value, remove chars before res2 */
+ if (tmp_value.replace(0,(uint32) (res2->ptr() - tmp_value.ptr()),
+ *res))
+ goto null;
+ res= &tmp_value;
+ use_as_buff=str; // Put next arg here
+ }
+ else
+ { // Two big const strings
+ if (tmp_value.alloc(max_length) ||
+ tmp_value.copy(*res) ||
+ tmp_value.append(*res2))
+ goto null;
+ res= &tmp_value;
+ use_as_buff=str;
+ }
+ }
+ }
+ return res;
+
+null:
+ null_value=1;
+ return 0;
+}
+
+
+void Item_func_concat::fix_length_and_dec()
+{
+ max_length=0;
+ for (uint i=0 ; i < arg_count ; i++)
+ max_length+=args[i]->max_length;
+ if (max_length > MAX_BLOB_WIDTH)
+ {
+ max_length=MAX_BLOB_WIDTH;
+ maybe_null=1;
+ }
+}
+
+
+
+/*
+** concat with separator. First arg is the separator
+** concat_ws takes at least two arguments.
+*/
+
+String *Item_func_concat_ws::val_str(String *str)
+{
+ char tmp_str_buff[10];
+ String tmp_sep_str(tmp_str_buff, sizeof(tmp_str_buff)),
+ *sep_str, *res, *res2,*use_as_buff;
+ uint i;
+
+ null_value=0;
+ if (!(sep_str= separator->val_str(&tmp_sep_str)))
+ goto null;
+
+ use_as_buff= &tmp_value;
+ str->length(0);
+ res=str;
+
+ // Skip until non-null and non-empty argument is found.
+ // If not, return the empty string
+ for (i=0; !(res= args[i]->val_str(str)) || !res->length(); i++)
+ {
+ if ((i + 1) == arg_count)
+ return &empty_string;
+ }
+
+ for (i++; i < arg_count ; i++)
+ {
+ if (!(res2= args[i]->val_str(use_as_buff)) || !res2->length())
+ continue;
+ else
+ {
+ if (res->length() + sep_str->length() + res2->length() >
+ max_allowed_packet)
+ goto null; // Error check
+ if (res->alloced_length() >=
+ res->length() + sep_str->length() + res2->length())
+ { // Use old buffer
+ res->append(*sep_str); // res->length() > 0 always
+ res->append(*res2);
+ use_as_buff= &tmp_value;
+ }
+ else if (str->alloced_length() >=
+ res->length() + sep_str->length() + res2->length())
+ {
+ str->copy(*res);
+ str->append(*sep_str);
+ str->append(*res2);
+ res=str;
+ use_as_buff= &tmp_value;
+ }
+ else if (res == &tmp_value)
+ {
+ if ((res->length() && res->append(*sep_str)) || res->append(*res2))
+ goto null; // Must be a blob
+ }
+ else if (tmp_value.is_alloced() && res2->ptr() >= tmp_value.ptr() &&
+ res2->ptr() <= tmp_value.ptr() + tmp_value.alloced_length())
+ {
+ /*
+ This happens really seldom:
+ In this case res2 is sub string of tmp_value. We will
+ now work in place in tmp_value to set it to res | res2
+ */
+ /* Chop the last characters in tmp_value that isn't in res2 */
+ tmp_value.length((uint32) (res2->ptr() - tmp_value.ptr()) +
+ res2->length());
+ /* Place res2 at start of tmp_value, remove chars before res2 */
+ if (res->append(*sep_str))
+ goto null;
+ if (tmp_value.replace(0,(uint32) (res2->ptr() - tmp_value.ptr()),
+ *res))
+ goto null;
+ res= &tmp_value;
+ use_as_buff=str; // Put next arg here
+ }
+ else
+ { // Two big const strings
+ if (tmp_value.alloc(max_length) ||
+ tmp_value.copy(*res) ||
+ tmp_value.append(*sep_str) ||
+ tmp_value.append(*res2))
+ goto null;
+ res= &tmp_value;
+ use_as_buff=str;
+ }
+ }
+ }
+ return res;
+
+null:
+ null_value=1;
+ return 0;
+}
+
+
+void Item_func_concat_ws::fix_length_and_dec()
+{
+ max_length=0;
+ for (uint i=0 ; i < arg_count ; i++)
+ max_length+=args[i]->max_length;
+ if (max_length > MAX_BLOB_WIDTH)
+ {
+ max_length=MAX_BLOB_WIDTH;
+ maybe_null=1;
+ }
+}
+
+
+String *Item_func_reverse::val_str(String *str)
+{
+ String *res = args[0]->val_str(str);
+ char *ptr,*end;
+
+ if ((null_value=args[0]->null_value))
+ return 0;
+ /* An empty string is a special case as the string pointer may be null */
+ if (!res->length())
+ return &empty_string;
+ res=copy_if_not_alloced(str,res,res->length());
+ ptr = (char *) res->ptr();
+ end=ptr+res->length();
+#ifdef USE_MB
+ if (use_mb(default_charset_info) && !binary)
+ {
+ String tmpstr;
+ tmpstr.copy(*res);
+ char *tmp = (char *) tmpstr.ptr() + tmpstr.length();
+ register uint32 l;
+ while (ptr < end)
+ {
+ if ((l=my_ismbchar(default_charset_info, ptr,end)))
+ tmp-=l, memcpy(tmp,ptr,l), ptr+=l;
+ else
+ *--tmp=*ptr++;
+ }
+ memcpy((char *) res->ptr(),(char *) tmpstr.ptr(), res->length());
+ }
+ else
+#endif /* USE_MB */
+ {
+ char tmp;
+ while (ptr < end)
+ {
+ tmp=*ptr;
+ *ptr++=*--end;
+ *end=tmp;
+ }
+ }
+ return res;
+}
+
+
+void Item_func_reverse::fix_length_and_dec()
+{
+ max_length = args[0]->max_length;
+}
+
+/*
+** Replace all occurences of string2 in string1 with string3.
+** Don't reallocate val_str() if not neaded
+*/
+
+/* TODO: Fix that this works with binary strings when using USE_MB */
+
+String *Item_func_replace::val_str(String *str)
+{
+ String *res,*res2,*res3;
+ int offset=0;
+ uint from_length,to_length;
+ bool alloced=0;
+#ifdef USE_MB
+ const char *ptr,*end,*strend,*search,*search_end;
+ register uint32 l;
+#endif
+
+ null_value=0;
+ res=args[0]->val_str(str);
+ if (args[0]->null_value)
+ goto null;
+ res2=args[1]->val_str(&tmp_value);
+ if (args[1]->null_value)
+ goto null;
+
+ if (res2->length() == 0)
+ return res;
+#ifndef USE_MB
+ if ((offset=res->strstr(*res2)) < 0)
+ return res;
+#else
+ if (!use_mb(default_charset_info) && (offset=res->strstr(*res2)) < 0)
+ return res;
+#endif
+ if (!(res3=args[2]->val_str(&tmp_value2)))
+ goto null;
+ from_length= res2->length();
+ to_length= res3->length();
+
+#ifdef USE_MB
+ if (use_mb(default_charset_info))
+ {
+ search=res2->ptr();
+ search_end=search+from_length;
+redo:
+ ptr=res->ptr()+offset;
+ strend=res->ptr()+res->length();
+ end=strend-from_length+1;
+ while (ptr < end)
+ {
+ if (*ptr == *search)
+ {
+ register char *i,*j;
+ i=(char*) ptr+1; j=(char*) search+1;
+ while (j != search_end)
+ if (*i++ != *j++) goto skipp;
+ offset=ptr-res->ptr();
+ if (res->length()-from_length + to_length > max_allowed_packet)
+ goto null;
+ if (!alloced)
+ {
+ alloced=1;
+ res=copy_if_not_alloced(str,res,res->length()+to_length);
+ }
+ res->replace((uint) offset,from_length,*res3);
+ goto redo;
+ }
+skipp:
+ if ((l=my_ismbchar(default_charset_info, ptr,strend))) ptr+=l;
+ else ++ptr;
+ }
+ }
+ else
+#endif /* USE_MB */
+ do
+ {
+ if (res->length()-from_length + to_length > max_allowed_packet)
+ goto null;
+ if (!alloced)
+ {
+ alloced=1;
+ res=copy_if_not_alloced(str,res,res->length()+to_length);
+ }
+ res->replace((uint) offset,from_length,*res3);
+ offset+=(int) to_length;
+ }
+ while ((offset=res->strstr(*res2,(uint) offset)) >0);
+ return res;
+
+null:
+ null_value=1;
+ return 0;
+}
+
+
+void Item_func_replace::fix_length_and_dec()
+{
+ max_length=args[0]->max_length;
+ int diff=(int) (args[2]->max_length - args[1]->max_length);
+ if (diff > 0 && args[1]->max_length)
+ { // Calculate of maxreplaces
+ max_length= max_length/args[1]->max_length;
+ max_length= (max_length+1)*(uint) diff;
+ }
+ if (max_length > MAX_BLOB_WIDTH)
+ {
+ max_length=MAX_BLOB_WIDTH;
+ maybe_null=1;
+ }
+}
+
+
+String *Item_func_insert::val_str(String *str)
+{
+ String *res,*res2;
+ uint start,length;
+
+ null_value=0;
+ res=args[0]->val_str(str);
+ res2=args[3]->val_str(&tmp_value);
+ start=(uint) args[1]->val_int()-1;
+ length=(uint) args[2]->val_int();
+ if (args[0]->null_value || args[1]->null_value || args[2]->null_value ||
+ args[3]->null_value)
+ goto null; /* purecov: inspected */
+#ifdef USE_MB
+ if (use_mb(default_charset_info) && !args[0]->binary)
+ {
+ start=res->charpos(start);
+ length=res->charpos(length,start);
+ }
+#endif
+ if (start > res->length()+1)
+ return res; // Wrong param; skipp insert
+ if (length > res->length()-start)
+ length=res->length()-start;
+ if (res->length() - length + res2->length() > max_allowed_packet)
+ goto null; // OOM check
+ res=copy_if_not_alloced(str,res,res->length());
+ res->replace(start,length,*res2);
+ return res;
+null:
+ null_value=1;
+ return 0;
+}
+
+
+void Item_func_insert::fix_length_and_dec()
+{
+ max_length=args[0]->max_length+args[3]->max_length;
+ if (max_length > MAX_BLOB_WIDTH)
+ {
+ max_length=MAX_BLOB_WIDTH;
+ maybe_null=1;
+ }
+}
+
+
+String *Item_func_lcase::val_str(String *str)
+{
+ String *res;
+ if (!(res=args[0]->val_str(str)))
+ {
+ null_value=1; /* purecov: inspected */
+ return 0; /* purecov: inspected */
+ }
+ null_value=0;
+ res=copy_if_not_alloced(str,res,res->length());
+ res->casedn();
+ return res;
+}
+
+
+String *Item_func_ucase::val_str(String *str)
+{
+ String *res;
+ if (!(res=args[0]->val_str(str)))
+ {
+ null_value=1; /* purecov: inspected */
+ return 0; /* purecov: inspected */
+ }
+ null_value=0;
+ res=copy_if_not_alloced(str,res,res->length());
+ res->caseup();
+ return res;
+}
+
+
+String *Item_func_left::val_str(String *str)
+{
+ String *res =args[0]->val_str(str);
+ long length =(long) args[1]->val_int();
+
+ if ((null_value=args[0]->null_value))
+ return 0;
+ if (length <= 0)
+ return &empty_string;
+#ifdef USE_MB
+ if (use_mb(default_charset_info) && !binary)
+ length = res->charpos(length);
+#endif
+ if (res->length() > (ulong) length)
+ { // Safe even if const arg
+ if (!res->alloced_length())
+ { // Don't change const str
+ str_value= *res; // Not malloced string
+ res= &str_value;
+ }
+ res->length((uint) length);
+ }
+ return res;
+}
+
+
+void Item_str_func::left_right_max_length()
+{
+ max_length=args[0]->max_length;
+ if (args[1]->const_item())
+ {
+ int length=(int) args[1]->val_int();
+ if (length <= 0)
+ max_length=0;
+ else
+ set_if_smaller(max_length,(uint) length);
+ }
+}
+
+
+void Item_func_left::fix_length_and_dec()
+{
+ left_right_max_length();
+}
+
+
+String *Item_func_right::val_str(String *str)
+{
+ String *res =args[0]->val_str(str);
+ long length =(long) args[1]->val_int();
+
+ if ((null_value=args[0]->null_value))
+ return 0; /* purecov: inspected */
+ if (length <= 0)
+ return &empty_string; /* purecov: inspected */
+ if (res->length() <= (uint) length)
+ return res; /* purecov: inspected */
+#ifdef USE_MB
+ if (use_mb(default_charset_info) && !binary)
+ {
+ uint start=res->numchars()-(uint) length;
+ if (start<=0) return res;
+ start=res->charpos(start);
+ tmp_value.set(*res,start,res->length()-start);
+ }
+ else
+#endif
+ {
+ tmp_value.set(*res,(res->length()- (uint) length),(uint) length);
+ }
+ return &tmp_value;
+}
+
+
+void Item_func_right::fix_length_and_dec()
+{
+ left_right_max_length();
+}
+
+
+String *Item_func_substr::val_str(String *str)
+{
+ String *res = args[0]->val_str(str);
+ int32 start = (int32) args[1]->val_int()-1;
+ int32 length = arg_count == 3 ? (int32) args[2]->val_int() : INT_MAX32;
+ int32 tmp_length;
+
+ if ((null_value=(args[0]->null_value || args[1]->null_value ||
+ (arg_count == 3 && args[2]->null_value))))
+ return 0; /* purecov: inspected */
+#ifdef USE_MB
+ if (use_mb(default_charset_info) && !binary)
+ {
+ start=res->charpos(start);
+ length=res->charpos(length,start);
+ }
+#endif
+ if (start < 0 || (uint) start+1 > res->length() || length <= 0)
+ return &empty_string;
+
+ tmp_length=(int32) res->length()-start;
+ length=min(length,tmp_length);
+
+ if (!start && res->length() == (uint) length)
+ return res;
+ tmp_value.set(*res,(uint) start,(uint) length);
+ return &tmp_value;
+}
+
+
+void Item_func_substr::fix_length_and_dec()
+{
+ max_length=args[0]->max_length;
+
+ if (args[1]->const_item())
+ {
+ int32 start=(int32) args[1]->val_int()-1;
+ if (start < 0 || start >= (int32) max_length)
+ max_length=0; /* purecov: inspected */
+ else
+ max_length-= (uint) start;
+ }
+ if (arg_count == 3 && args[2]->const_item())
+ {
+ int32 length= (int32) args[2]->val_int();
+ if (length <= 0)
+ max_length=0; /* purecov: inspected */
+ else
+ set_if_smaller(max_length,(uint) length);
+ }
+}
+
+
+String *Item_func_substr_index::val_str(String *str)
+{
+ String *res =args[0]->val_str(str);
+ String *delimeter =args[1]->val_str(&tmp_value);
+ int32 count = (int32) args[2]->val_int();
+ uint offset;
+
+ if (args[0]->null_value || args[1]->null_value || args[2]->null_value)
+ { // string and/or delim are null
+ null_value=1;
+ return 0;
+ }
+ null_value=0;
+ uint delimeter_length=delimeter->length();
+ if (!res->length() || !delimeter_length || !count)
+ return &empty_string; // Wrong parameters
+
+#ifdef USE_MB
+ if (use_mb(default_charset_info) && !binary)
+ {
+ const char *ptr=res->ptr();
+ const char *strend = ptr+res->length();
+ const char *end=strend-delimeter_length+1;
+ const char *search=delimeter->ptr();
+ const char *search_end=search+delimeter_length;
+ int32 n=0,c=count,pass;
+ register uint32 l;
+ for (pass=(count>0);pass<2;++pass)
+ {
+ while (ptr < end)
+ {
+ if (*ptr == *search)
+ {
+ register char *i,*j;
+ i=(char*) ptr+1; j=(char*) search+1;
+ while (j != search_end)
+ if (*i++ != *j++) goto skipp;
+ if (pass==0) ++n;
+ else if (!--c) break;
+ ptr+=delimeter_length;
+ continue;
+ }
+ skipp:
+ if ((l=my_ismbchar(default_charset_info, ptr,strend))) ptr+=l;
+ else ++ptr;
+ } /* either not found or got total number when count<0 */
+ if (pass == 0) /* count<0 */
+ {
+ c+=n+1;
+ if (c<=0) return res; /* not found, return original string */
+ ptr=res->ptr();
+ }
+ else
+ {
+ if (c) return res; /* Not found, return original string */
+ if (count>0) /* return left part */
+ {
+ tmp_value.set(*res,0,ptr-res->ptr());
+ }
+ else /* return right part */
+ {
+ ptr+=delimeter_length;
+ tmp_value.set(*res,ptr-res->ptr(),strend-ptr);
+ }
+ }
+ }
+ }
+ else
+#endif /* USE_MB */
+ {
+ if (count > 0)
+ { // start counting from the beginning
+ for (offset=0 ;; offset+=delimeter_length)
+ {
+ if ((int) (offset=res->strstr(*delimeter,offset)) < 0)
+ return res; // Didn't find, return org string
+ if (!--count)
+ {
+ tmp_value.set(*res,0,offset);
+ break;
+ }
+ }
+ }
+ else
+ { // Start counting at end
+ for (offset=res->length() ; ; offset-=delimeter_length)
+ {
+ if ((int) (offset=res->strrstr(*delimeter,offset)) < 0)
+ return res; // Didn't find, return org string
+ if (!++count)
+ {
+ offset+=delimeter_length;
+ tmp_value.set(*res,offset,res->length()- offset);
+ break;
+ }
+ }
+ }
+ }
+ return (&tmp_value);
+}
+
+/*
+** The trim functions are extension to ANSI SQL because they trim substrings
+** They ltrim() and rtrim() functions are optimized for 1 byte strings
+** They also return the original string if possible, else they return
+** a substring that points at the original string.
+*/
+
+
+String *Item_func_ltrim::val_str(String *str)
+{
+ String *res =args[0]->val_str(str);
+ if ((null_value=args[0]->null_value))
+ return 0; /* purecov: inspected */
+ char buff[MAX_FIELD_WIDTH];
+ String tmp(buff,sizeof(buff));
+ String *remove_str=args[1]->val_str(&tmp);
+ uint remove_length;
+ LINT_INIT(remove_length);
+
+ if (!remove_str || (remove_length=remove_str->length()) == 0 ||
+ remove_length > res->length())
+ return res;
+
+ char *ptr=(char*) res->ptr();
+ char *end=ptr+res->length();
+ if (remove_length == 1)
+ {
+ char chr=(*remove_str)[0];
+ while (ptr != end && *ptr == chr)
+ ptr++;
+ }
+ else
+ {
+ const char *r_ptr=remove_str->ptr();
+ end-=remove_length;
+ while (ptr < end && !memcmp(ptr,r_ptr,remove_length))
+ ptr+=remove_length;
+ end+=remove_length;
+ }
+ if (ptr == res->ptr())
+ return res;
+ tmp_value.set(*res,(uint) (ptr - res->ptr()),(uint) (end-ptr));
+ return &tmp_value;
+}
+
+
+String *Item_func_rtrim::val_str(String *str)
+{
+ String *res =args[0]->val_str(str);
+ if ((null_value=args[0]->null_value))
+ return 0; /* purecov: inspected */
+ char buff[MAX_FIELD_WIDTH];
+ String tmp(buff,sizeof(buff));
+ String *remove_str=args[1]->val_str(&tmp);
+ uint remove_length;
+ LINT_INIT(remove_length);
+
+ if (!remove_str || (remove_length=remove_str->length()) == 0 ||
+ remove_length > res->length())
+ return res;
+
+ char *ptr=(char*) res->ptr();
+ char *end=ptr+res->length();
+#ifdef USE_MB
+ char *p=ptr;
+ register uint32 l;
+#endif
+ if (remove_length == 1)
+ {
+ char chr=(*remove_str)[0];
+#ifdef USE_MB
+ if (use_mb(default_charset_info) && !binary)
+ {
+ while (ptr < end)
+ {
+ if ((l=my_ismbchar(default_charset_info, ptr,end))) ptr+=l,p=ptr;
+ else ++ptr;
+ }
+ ptr=p;
+ }
+#endif
+ while (ptr != end && end[-1] == chr)
+ end--;
+ }
+ else
+ {
+ const char *r_ptr=remove_str->ptr();
+#ifdef USE_MB
+ if (use_mb(default_charset_info) && !binary)
+ {
+ loop:
+ while (ptr + remove_length < end)
+ {
+ if ((l=my_ismbchar(default_charset_info, ptr,end))) ptr+=l;
+ else ++ptr;
+ }
+ if (ptr + remove_length == end && !memcmp(ptr,r_ptr,remove_length))
+ {
+ end-=remove_length;
+ ptr=p;
+ goto loop;
+ }
+ }
+ else
+#endif /* USE_MB */
+ {
+ while (ptr + remove_length < end &&
+ !memcmp(end-remove_length,r_ptr,remove_length))
+ end-=remove_length;
+ }
+ }
+ if (end == res->ptr()+res->length())
+ return res;
+ tmp_value.set(*res,0,(uint) (end-res->ptr()));
+ return &tmp_value;
+}
+
+
+String *Item_func_trim::val_str(String *str)
+{
+ String *res =args[0]->val_str(str);
+ if ((null_value=args[0]->null_value))
+ return 0; /* purecov: inspected */
+ char buff[MAX_FIELD_WIDTH];
+ String tmp(buff,sizeof(buff));
+ String *remove_str=args[1]->val_str(&tmp);
+ uint remove_length;
+ LINT_INIT(remove_length);
+
+ if (!remove_str || (remove_length=remove_str->length()) == 0 ||
+ remove_length > res->length())
+ return res;
+
+ char *ptr=(char*) res->ptr();
+ char *end=ptr+res->length();
+ const char *r_ptr=remove_str->ptr();
+ while (ptr+remove_length < end && !memcmp(ptr,r_ptr,remove_length))
+ ptr+=remove_length;
+#ifdef USE_MB
+ if (use_mb(default_charset_info) && !binary)
+ {
+ char *p=ptr;
+ register uint32 l;
+ loop:
+ while (ptr + remove_length < end)
+ {
+ if ((l=my_ismbchar(default_charset_info, ptr,end))) ptr+=l;
+ else ++ptr;
+ }
+ if (ptr + remove_length == end && !memcmp(ptr,r_ptr,remove_length))
+ {
+ end-=remove_length;
+ ptr=p;
+ goto loop;
+ }
+ ptr=p;
+ }
+ else
+#endif /* USE_MB */
+ {
+ while (ptr + remove_length < end &&
+ !memcmp(end-remove_length,r_ptr,remove_length))
+ end-=remove_length;
+ }
+ if (ptr == res->ptr() && end == ptr+res->length())
+ return res;
+ tmp_value.set(*res,(uint) (ptr - res->ptr()),(uint) (end-ptr));
+ return &tmp_value;
+}
+
+
+String *Item_func_password::val_str(String *str)
+{
+ String *res =args[0]->val_str(str);
+ if ((null_value=args[0]->null_value))
+ return 0;
+ if (res->length() == 0)
+ return &empty_string;
+ make_scrambled_password(tmp_value,res->c_ptr());
+ str->set(tmp_value,16);
+ return str;
+}
+
+#define bin_to_ascii(c) ((c)>=38?((c)-38+'a'):(c)>=12?((c)-12+'A'):(c)+'.')
+
+String *Item_func_encrypt::val_str(String *str)
+{
+ String *res =args[0]->val_str(str);
+
+#ifdef HAVE_CRYPT
+ char salt[3],*salt_ptr;
+ if ((null_value=args[0]->null_value))
+ return 0;
+ if (res->length() == 0)
+ return &empty_string;
+
+ if (arg_count == 1)
+ { // generate random salt
+ time_t timestamp=current_thd->query_start();
+ salt[0] = bin_to_ascii(timestamp & 0x3f);
+ salt[1] = bin_to_ascii((timestamp >> 5) & 0x3f);
+ salt[2] = 0;
+ salt_ptr=salt;
+ }
+ else
+ { // obtain salt from the first two bytes
+ String *salt_str=args[1]->val_str(&tmp_value);
+ if ((null_value= (args[1]->null_value || salt_str->length() < 2)))
+ return 0;
+ salt_ptr= salt_str->c_ptr();
+ }
+ pthread_mutex_lock(&LOCK_crypt);
+ char *tmp=crypt(res->c_ptr(),salt_ptr);
+ str->set(tmp,strlen(tmp));
+ str->copy();
+ pthread_mutex_unlock(&LOCK_crypt);
+ return str;
+#else
+ null_value=1;
+ return 0;
+#endif /* HAVE_CRYPT */
+}
+
+void Item_func_encode::fix_length_and_dec()
+{
+ max_length=args[0]->max_length;
+ maybe_null=args[0]->maybe_null;
+}
+
+String *Item_func_encode::val_str(String *str)
+{
+ String *res;
+ if (!(res=args[0]->val_str(str)))
+ {
+ null_value=1; /* purecov: inspected */
+ return 0; /* purecov: inspected */
+ }
+ null_value=0;
+ res=copy_if_not_alloced(str,res,res->length());
+ sql_crypt.init();
+ sql_crypt.encode((char*) res->ptr(),res->length());
+ return res;
+}
+
+String *Item_func_decode::val_str(String *str)
+{
+ String *res;
+ if (!(res=args[0]->val_str(str)))
+ {
+ null_value=1; /* purecov: inspected */
+ return 0; /* purecov: inspected */
+ }
+ null_value=0;
+ res=copy_if_not_alloced(str,res,res->length());
+ sql_crypt.init();
+ sql_crypt.decode((char*) res->ptr(),res->length());
+ return res;
+}
+
+
+String *Item_func_database::val_str(String *str)
+{
+ if (!current_thd->db)
+ str->length(0);
+ else
+ str->set((const char*) current_thd->db,strlen(current_thd->db));
+ return str;
+}
+
+String *Item_func_user::val_str(String *str)
+{
+ THD *thd=current_thd;
+ if (str->copy((const char*) thd->user,strlen(thd->user)) ||
+ str->append('@') ||
+ str->append(thd->host ? thd->host : thd->ip ? thd->ip : ""))
+ return &empty_string;
+ return str;
+}
+
+void Item_func_soundex::fix_length_and_dec()
+{
+ max_length=args[0]->max_length;
+ set_if_bigger(max_length,4);
+}
+
+
+ /*
+ If alpha, map input letter to soundex code.
+ If not alpha and remove_garbage is set then skipp to next char
+ else return 0
+ */
+
+extern "C" {
+extern char *soundex_map; // In mysys/static.c
+}
+
+static char get_scode(char *ptr)
+{
+ uchar ch=toupper(*ptr);
+ if (ch < 'A' || ch > 'Z')
+ {
+ // Thread extended alfa (country spec)
+ return '0'; // as vokal
+ }
+ return(soundex_map[ch-'A']);
+}
+
+
+String *Item_func_soundex::val_str(String *str)
+{
+ String *res =args[0]->val_str(str);
+ char last_ch,ch;
+ if ((null_value=args[0]->null_value))
+ return 0; /* purecov: inspected */
+
+ if (str_value.alloc(max(res->length(),4)))
+ return str; /* purecov: inspected */
+ char *to= (char *) str_value.ptr();
+ char *from= (char *) res->ptr(), *end=from+res->length();
+
+ while (from != end && isspace(*from)) // Skipp pre-space
+ from++; /* purecov: inspected */
+ if (from == end)
+ return &empty_string; // No alpha characters.
+ *to++ = toupper(*from); // Copy first letter
+ last_ch = get_scode(from); // code of the first letter
+ // for the first 'double-letter check.
+ // Loop on input letters until
+ // end of input (null) or output
+ // letter code count = 3
+ for (from++ ; from < end ; from++)
+ {
+ if (!isalpha(*from))
+ continue;
+ ch=get_scode(from);
+ if ((ch != '0') && (ch != last_ch)) // if not skipped or double
+ {
+ *to++ = ch; // letter, copy to output
+ last_ch = ch; // save code of last input letter
+ } // for next double-letter check
+ }
+ for (end=(char*) str_value.ptr()+4 ; to < end ; to++)
+ *to = '0';
+ *to=0; // end string
+ str_value.length((uint) (to-str_value.ptr()));
+ return &str_value;
+}
+
+
+/*
+** Change a number to format '3,333,333,333.000'
+** This should be 'internationalized' sometimes.
+*/
+
+Item_func_format::Item_func_format(Item *org,int dec) :Item_str_func(org)
+{
+ decimals=(uint) set_zone(dec,0,30);
+}
+
+
+String *Item_func_format::val_str(String *str)
+{
+ double nr =args[0]->val();
+ uint32 diff,length,str_length;
+ uint dec;
+ if ((null_value=args[0]->null_value))
+ return 0; /* purecov: inspected */
+ dec= decimals ? decimals+1 : 0;
+ str->set(nr,decimals);
+ str_length=str->length();
+ if (nr < 0)
+ str_length--; // Don't count sign
+ length=str->length()+(diff=(str_length- dec-1)/3);
+ if (diff)
+ {
+ char *tmp,*pos;
+ str=copy_if_not_alloced(&tmp_str,str,length);
+ str->length(length);
+ tmp=(char*) str->ptr()+length - dec-1;
+ for (pos=(char*) str->ptr()+length ; pos != tmp; pos--)
+ pos[0]=pos[- (int) diff];
+ while (diff)
+ {
+ pos[0]=pos[-(int) diff]; pos--;
+ pos[0]=pos[-(int) diff]; pos--;
+ pos[0]=pos[-(int) diff]; pos--;
+ pos[0]=',';
+ pos--;
+ diff--;
+ }
+ }
+ return str;
+}
+
+
+void Item_func_elt::fix_length_and_dec()
+{
+ max_length=0;
+ decimals=0;
+ for (uint i=1 ; i < arg_count ; i++)
+ {
+ set_if_bigger(max_length,args[i]->max_length);
+ set_if_bigger(decimals,args[i]->decimals);
+ }
+ maybe_null=1; // NULL if wrong first arg
+ used_tables_cache|=item->used_tables();
+}
+
+
+void Item_func_elt::update_used_tables()
+{
+ Item_func::update_used_tables();
+ item->update_used_tables();
+ used_tables_cache|=item->used_tables();
+ const_item_cache&=item->const_item();
+}
+
+
+double Item_func_elt::val()
+{
+ uint tmp;
+ if ((tmp=(uint) item->val_int()) == 0 || tmp > arg_count)
+ {
+ null_value=1;
+ return 0.0;
+ }
+ null_value=0;
+ return args[tmp-1]->val();
+}
+
+longlong Item_func_elt::val_int()
+{
+ uint tmp;
+ if ((tmp=(uint) item->val_int()) == 0 || tmp > arg_count)
+ {
+ null_value=1;
+ return 0;
+ }
+ null_value=0;
+ return args[tmp-1]->val_int();
+}
+
+String *Item_func_elt::val_str(String *str)
+{
+ uint tmp;
+ if ((tmp=(uint) item->val_int()) == 0 || tmp > arg_count)
+ {
+ null_value=1;
+ return NULL;
+ }
+ null_value=0;
+ return args[tmp-1]->val_str(str);
+}
+
+
+void Item_func_make_set::fix_length_and_dec()
+{
+ max_length=arg_count-1;
+ for (uint i=1 ; i < arg_count ; i++)
+ max_length+=args[i]->max_length;
+ used_tables_cache|=item->used_tables();
+}
+
+
+void Item_func_make_set::update_used_tables()
+{
+ Item_func::update_used_tables();
+ item->update_used_tables();
+ used_tables_cache|=item->used_tables();
+ const_item_cache&=item->const_item();
+}
+
+
+String *Item_func_make_set::val_str(String *str)
+{
+ ulonglong bits;
+ bool first_found=0;
+ Item **ptr=args;
+ String *result=&empty_string;
+
+ bits=item->val_int();
+ if ((null_value=item->null_value))
+ return NULL;
+
+ if (arg_count < 64)
+ bits &= ((ulonglong) 1 << arg_count)-1;
+
+ for (; bits; bits >>= 1, ptr++)
+ {
+ if (bits & 1)
+ {
+ String *res= (*ptr)->val_str(str);
+ if (res) // Skipp nulls
+ {
+ if (!first_found)
+ { // First argument
+ first_found=1;
+ if (res != str)
+ result=res; // Use original string
+ else
+ {
+ if (tmp_str.copy(*res)) // Don't use 'str'
+ return &empty_string;
+ result= &tmp_str;
+ }
+ }
+ else
+ {
+ if (result != &tmp_str)
+ { // Copy data to tmp_str
+ if (tmp_str.alloc(result->length()+res->length()+1) ||
+ tmp_str.copy(*result))
+ return &empty_string;
+ result= &tmp_str;
+ }
+ if (tmp_str.append(',') || tmp_str.append(*res))
+ return &empty_string;
+ }
+ }
+ }
+ }
+ return result;
+}
+
+
+String *Item_func_char::val_str(String *str)
+{
+ str->length(0);
+ for (uint i=0 ; i < arg_count ; i++)
+ {
+ int32 num=(int32) args[i]->val_int();
+ if (!args[i]->null_value)
+#ifdef USE_MB
+ if (use_mb(default_charset_info))
+ {
+ if (num&0xFF000000L) {
+ str->append((char)(num>>24));
+ goto b2;
+ } else if (num&0xFF0000L) {
+b2: str->append((char)(num>>16));
+ goto b1;
+ } else if (num&0xFF00L) {
+b1: str->append((char)(num>>8));
+ }
+ }
+#endif
+ str->append((char)num);
+ }
+ str->realloc(str->length()); // Add end 0 (for Purify)
+ return str;
+}
+
+
+inline String* alloc_buffer(String *res,String *str,String *tmp_value,
+ ulong length)
+{
+ if (res->alloced_length() < length)
+ {
+ if (str->alloced_length() >= length)
+ {
+ (void) str->copy(*res);
+ str->length(length);
+ return str;
+ }
+ else
+ {
+ if (tmp_value->alloc(length))
+ return 0;
+ (void) tmp_value->copy(*res);
+ tmp_value->length(length);
+ return tmp_value;
+ }
+ }
+ res->length(length);
+ return res;
+}
+
+
+void Item_func_repeat::fix_length_and_dec()
+{
+ if (args[1]->const_item())
+ {
+ max_length=(long) (args[0]->max_length * args[1]->val_int());
+ if (max_length >= MAX_BLOB_WIDTH)
+ {
+ max_length=MAX_BLOB_WIDTH;
+ maybe_null=1;
+ }
+ }
+ else
+ {
+ max_length=MAX_BLOB_WIDTH;
+ maybe_null=1;
+ }
+}
+
+/*
+** Item_func_repeat::str is carefully written to avoid reallocs
+** as much as possible at the cost of a local buffer
+*/
+
+String *Item_func_repeat::val_str(String *str)
+{
+ uint length,tot_length;
+ char *to;
+ long count= (long) args[1]->val_int();
+ String *res =args[0]->val_str(str);
+
+ if (args[0]->null_value || args[1]->null_value)
+ goto err; // string and/or delim are null
+ null_value=0;
+ if (count <= 0) // For nicer SQL code
+ return &empty_string;
+ if (count == 1) // To avoid reallocs
+ return res;
+ length=res->length();
+ if (length > max_allowed_packet/count)// Safe length check
+ goto err; // Probably an error
+ tot_length= length*(uint) count;
+ if (!(res= alloc_buffer(res,str,&tmp_value,tot_length)))
+ goto err;
+
+ to=(char*) res->ptr()+length;
+ while (--count)
+ {
+ memcpy(to,res->ptr(),length);
+ to+=length;
+ }
+ return (res);
+
+err:
+ null_value=1;
+ return 0;
+}
+
+
+void Item_func_rpad::fix_length_and_dec()
+{
+ if (args[1]->const_item())
+ {
+ uint32 length= (uint32) args[1]->val_int();
+ max_length=max(args[0]->max_length,length);
+ if (max_length >= MAX_BLOB_WIDTH)
+ {
+ max_length=MAX_BLOB_WIDTH;
+ maybe_null=1;
+ }
+ }
+ else
+ {
+ max_length=MAX_BLOB_WIDTH;
+ maybe_null=1;
+ }
+}
+
+
+String *Item_func_rpad::val_str(String *str)
+{
+ uint32 res_length,length_pad;
+ char *to;
+ const char *ptr_pad;
+ int32 count= (int32) args[1]->val_int();
+ String *res =args[0]->val_str(str);
+ String *rpad = args[2]->val_str(str);
+
+ if (!res || args[1]->null_value || !rpad)
+ goto err;
+ null_value=0;
+ if (count <= (int32) (res_length=res->length()))
+ return (res); // String to pad is big enough
+ length_pad= rpad->length();
+ if ((ulong) count > max_allowed_packet || args[2]->null_value || !length_pad)
+ goto err;
+ if (!(res= alloc_buffer(res,str,&tmp_value,count)))
+ goto err;
+
+ to= (char*) res->ptr()+res_length;
+ ptr_pad=rpad->ptr();
+ for (count-= res_length; (uint32) count > length_pad; count-= length_pad)
+ {
+ memcpy(to,ptr_pad,length_pad);
+ to+= length_pad;
+ }
+ memcpy(to,ptr_pad,(size_t) count);
+ return (res);
+
+ err:
+ null_value=1;
+ return 0;
+}
+
+
+void Item_func_lpad::fix_length_and_dec()
+{
+ if (args[1]->const_item())
+ {
+ uint32 length= (uint32) args[1]->val_int();
+ max_length=max(args[0]->max_length,length);
+ if (max_length >= MAX_BLOB_WIDTH)
+ {
+ max_length=MAX_BLOB_WIDTH;
+ maybe_null=1;
+ }
+ }
+ else
+ {
+ max_length=MAX_BLOB_WIDTH;
+ maybe_null=1;
+ }
+}
+
+
+String *Item_func_lpad::val_str(String *str)
+{
+ uint32 res_length,length_pad;
+ char *to;
+ const char *ptr_pad;
+ ulong count= (long) args[1]->val_int();
+ String *res= args[0]->val_str(str);
+ String *lpad= args[2]->val_str(str);
+
+ if (!res || args[1]->null_value || !lpad)
+ goto err;
+ null_value=0;
+ if (count <= (res_length=res->length()))
+ return (res); // String to pad is big enough
+ length_pad= lpad->length();
+ if (count > max_allowed_packet || args[2]->null_value || !length_pad)
+ goto err;
+
+ if (res->alloced_length() < count)
+ {
+ if (str->alloced_length() >= count)
+ {
+ memcpy((char*) str->ptr()+(count-res_length),res->ptr(),res_length);
+ res=str;
+ }
+ else
+ {
+ if (tmp_value.alloc(count))
+ goto err;
+ memcpy((char*) tmp_value.ptr()+(count-res_length),res->ptr(),res_length);
+ res=&tmp_value;
+ }
+ }
+ else
+ bmove_upp((char*) res->ptr()+count,res->ptr()+res_length,res_length);
+ res->length(count);
+
+ to= (char*) res->ptr();
+ ptr_pad= lpad->ptr();
+ for (count-= res_length; count > length_pad; count-= length_pad)
+ {
+ memcpy(to,ptr_pad,length_pad);
+ to+= length_pad;
+ }
+ memcpy(to,ptr_pad,(size_t) count);
+ return (res);
+
+ err:
+ null_value=1;
+ return 0;
+}
+
+
+String *Item_func_conv::val_str(String *str)
+{
+ String *res= args[0]->val_str(str);
+ char *endptr,ans[65],*ptr;
+ longlong dec;
+ int from_base= (int) args[1]->val_int();
+ int to_base= (int) args[2]->val_int();
+
+ if (args[0]->null_value || args[1]->null_value || args[2]->null_value ||
+ abs(to_base) > 36 || abs(to_base) < 2 ||
+ abs(from_base) > 36 || abs(from_base) < 2 || !(res->length()))
+ {
+ null_value=1;
+ return 0;
+ }
+ null_value=0;
+ if (from_base < 0)
+ dec= strtoll(res->c_ptr(),&endptr,-from_base);
+ else
+ dec= (longlong) strtoull(res->c_ptr(),&endptr,from_base);
+ ptr= longlong2str(dec,ans,to_base);
+ if (str->copy(ans,(uint32) (ptr-ans)))
+ return &empty_string;
+ return str;
+}
+
+#include <my_dir.h> // For my_stat
+
+String *Item_load_file::val_str(String *str)
+{
+ String *file_name;
+ File file;
+ MY_STAT stat_info;
+ DBUG_ENTER("load_file");
+
+ if (!(file_name= args[0]->val_str(str)) ||
+ !(current_thd->master_access & FILE_ACL) ||
+ !my_stat(file_name->c_ptr(), &stat_info, MYF(MY_FAE)))
+ goto err;
+ if (!(stat_info.st_mode & S_IROTH))
+ {
+ /* my_error(ER_TEXTFILE_NOT_READABLE, MYF(0), file_name->c_ptr()); */
+ goto err;
+ }
+ if (stat_info.st_size > (long) max_allowed_packet)
+ {
+ /* my_error(ER_TOO_LONG_STRING, MYF(0), file_name->c_ptr()); */
+ goto err;
+ }
+ if (tmp_value.alloc(stat_info.st_size))
+ goto err;
+ if ((file = my_open(file_name->c_ptr(), O_RDONLY, MYF(0))) < 0)
+ goto err;
+ if (my_read(file, (byte*) tmp_value.ptr(), stat_info.st_size, MYF(MY_NABP)))
+ {
+ my_close(file, MYF(0));
+ goto err;
+ }
+ tmp_value.length(stat_info.st_size);
+ my_close(file, MYF(0));
+ null_value = 0;
+ return &tmp_value;
+
+err:
+ null_value = 1;
+ DBUG_RETURN(0);
+}
+
+
+String* Item_func_export_set::val_str(String* str)
+{
+ ulonglong the_set = (ulonglong) args[0]->val_int();
+ String yes_buf, *yes;
+ yes = args[1]->val_str(&yes_buf);
+ String no_buf, *no;
+ no = args[2]->val_str(&no_buf);
+ String *sep = NULL, sep_buf ;
+
+ uint num_set_values = 64;
+ ulonglong mask = 0x1;
+ str->length(0);
+
+ /* Check if some argument is a NULL value */
+ if (args[0]->null_value || args[1]->null_value || args[2]->null_value)
+ {
+ null_value=1;
+ return 0;
+ }
+ switch(arg_count) {
+ case 5:
+ num_set_values = (uint) args[4]->val_int();
+ if (num_set_values > 64)
+ num_set_values=64;
+ if (args[4]->null_value)
+ {
+ null_value=1;
+ return 0;
+ }
+ /* Fall through */
+ case 4:
+ if (!(sep = args[3]->val_str(&sep_buf))) // Only true if NULL
+ {
+ null_value=1;
+ return 0;
+ }
+ break;
+ case 3:
+ sep_buf.set(",", 1);
+ sep = &sep_buf;
+ }
+ null_value=0;
+
+ for (uint i = 0; i < num_set_values; i++, mask = (mask << 1))
+ {
+ if (the_set & mask)
+ str->append(*yes);
+ else
+ str->append(*no);
+ if(i != num_set_values - 1)
+ str->append(*sep);
+ }
+ return str;
+}
+
+void Item_func_export_set::fix_length_and_dec()
+{
+ uint length=max(args[1]->max_length,args[2]->max_length);
+ uint sep_length=(arg_count > 3 ? args[3]->max_length : 1);
+ max_length=length*64+sep_length*63;
+}
+
+String* Item_func_inet_ntoa::val_str(String* str)
+{
+ uchar buf[8], *p;
+ ulonglong n = (ulonglong) args[0]->val_int();
+ char num[4];
+ // we do not know if args[0] is NULL until we have called
+ // some val function on it if args[0] is not a constant!
+ if ((null_value=args[0]->null_value))
+ return 0; // Null value
+ str->length(0);
+ int8store(buf,n);
+
+ // now we can assume little endian
+ // 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)
+ {
+ uint c = *p;
+ uint n1,n2; // Try to avoid divisions
+ n1= c / 100; // 100 digits
+ c-= n1*100;
+ n2= c / 10; // 10 digits
+ c-=n2*10; // last digit
+ num[0]=(char) n1+'0';
+ num[1]=(char) n2+'0';
+ num[2]=(char) c+'0';
+ uint length=(n1 ? 4 : n2 ? 3 : 2); // Remove pre-zero
+
+ (void) str->append(num+4-length,length);
+ }
+ str->length(str->length()-1); // Remove last '.';
+ return str;
+}
diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h
new file mode 100644
index 00000000000..97bc1063db3
--- /dev/null
+++ b/sql/item_strfunc.h
@@ -0,0 +1,429 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 defines all string functions */
+
+#ifdef __GNUC__
+#pragma interface /* gcc class implementation */
+#endif
+
+class Item_str_func :public Item_func
+{
+public:
+ Item_str_func() :Item_func() { decimals=NOT_FIXED_DEC; }
+ Item_str_func(Item *a) :Item_func(a) {decimals=NOT_FIXED_DEC; }
+ Item_str_func(Item *a,Item *b) :Item_func(a,b) { decimals=NOT_FIXED_DEC; }
+ Item_str_func(Item *a,Item *b,Item *c) :Item_func(a,b,c) { decimals=NOT_FIXED_DEC; }
+ Item_str_func(Item *a,Item *b,Item *c,Item *d) :Item_func(a,b,c,d) {decimals=NOT_FIXED_DEC; }
+ Item_str_func(Item *a,Item *b,Item *c,Item *d, Item* e) :Item_func(a,b,c,d,e) {decimals=NOT_FIXED_DEC; }
+ Item_str_func(List<Item> &list) :Item_func(list) {decimals=NOT_FIXED_DEC; }
+ longlong val_int();
+ double val();
+ enum Item_result result_type () const { return STRING_RESULT; }
+ void left_right_max_length();
+};
+
+class Item_func_md5 :public Item_str_func
+{
+ String tmp_value;
+public:
+ Item_func_md5(Item *a) :Item_str_func(a) {}
+ String *val_str(String *);
+ void fix_length_and_dec();
+ const char *func_name() const { return "md5"; }
+};
+
+class Item_func_concat :public Item_str_func
+{
+ String tmp_value;
+public:
+ Item_func_concat(List<Item> &list) :Item_str_func(list) {}
+ Item_func_concat(Item *a,Item *b) :Item_str_func(a,b) {}
+ String *val_str(String *);
+ void fix_length_and_dec();
+ const char *func_name() const { return "concat"; }
+};
+
+class Item_func_concat_ws :public Item_str_func
+{
+ Item *separator;
+ String tmp_value;
+
+public:
+ Item_func_concat_ws(Item *a,List<Item> &list)
+ :Item_str_func(list),separator(a) {}
+ ~Item_func_concat_ws() { delete separator; }
+ String *val_str(String *);
+ void fix_length_and_dec();
+ const char *func_name() const { return "concat_ws"; }
+};
+
+class Item_func_reverse :public Item_str_func
+{
+public:
+ Item_func_reverse(Item *a) :Item_str_func(a) {}
+ String *val_str(String *);
+ void fix_length_and_dec();
+};
+
+
+class Item_func_replace :public Item_str_func
+{
+ String tmp_value,tmp_value2;
+public:
+ Item_func_replace(Item *org,Item *find,Item *replace)
+ :Item_str_func(org,find,replace) {}
+ String *val_str(String *);
+ void fix_length_and_dec();
+ const char *func_name() const { return "replace"; }
+};
+
+
+class Item_func_insert :public Item_str_func
+{
+ String tmp_value;
+public:
+ Item_func_insert(Item *org,Item *start,Item *length,Item *new_str)
+ :Item_str_func(org,start,length,new_str) {}
+ String *val_str(String *);
+ void fix_length_and_dec();
+ const char *func_name() const { return "insert"; }
+};
+
+
+class Item_str_conv :public Item_str_func
+{
+public:
+ Item_str_conv(Item *item) :Item_str_func(item) {}
+ void fix_length_and_dec() { max_length = args[0]->max_length; }
+};
+
+
+class Item_func_lcase :public Item_str_conv
+{
+public:
+ Item_func_lcase(Item *item) :Item_str_conv(item) {}
+ String *val_str(String *);
+ const char *func_name() const { return "lcase"; }
+};
+
+class Item_func_ucase :public Item_str_conv
+{
+public:
+ Item_func_ucase(Item *item) :Item_str_conv(item) {}
+ String *val_str(String *);
+ const char *func_name() const { return "ucase"; }
+};
+
+
+class Item_func_left :public Item_str_func
+{
+public:
+ Item_func_left(Item *a,Item *b) :Item_str_func(a,b) {}
+ String *val_str(String *);
+ void fix_length_and_dec();
+ const char *func_name() const { return "left"; }
+};
+
+
+class Item_func_right :public Item_str_func
+{
+ String tmp_value;
+public:
+ Item_func_right(Item *a,Item *b) :Item_str_func(a,b) {}
+ String *val_str(String *);
+ void fix_length_and_dec();
+ const char *func_name() const { return "right"; }
+};
+
+
+class Item_func_substr :public Item_str_func
+{
+ String tmp_value;
+public:
+ Item_func_substr(Item *a,Item *b) :Item_str_func(a,b) {}
+ Item_func_substr(Item *a,Item *b,Item *c) :Item_str_func(a,b,c) {}
+ String *val_str(String *);
+ void fix_length_and_dec();
+ const char *func_name() const { return "substr"; }
+};
+
+
+class Item_func_substr_index :public Item_str_func
+{
+ String tmp_value;
+public:
+ Item_func_substr_index(Item *a,Item *b,Item *c) :Item_str_func(a,b,c) {}
+ String *val_str(String *);
+ void fix_length_and_dec() { max_length= args[0]->max_length; }
+ const char *func_name() const { return "substr_index"; }
+};
+
+
+class Item_func_ltrim :public Item_str_func
+{
+ String tmp_value;
+public:
+ Item_func_ltrim(Item *a,Item *b) :Item_str_func(a,b) {}
+ String *val_str(String *);
+ void fix_length_and_dec() { max_length= args[0]->max_length; }
+ const char *func_name() const { return "ltrim"; }
+};
+
+
+class Item_func_rtrim :public Item_str_func
+{
+ String tmp_value;
+public:
+ Item_func_rtrim(Item *a,Item *b) :Item_str_func(a,b) {}
+ String *val_str(String *);
+ void fix_length_and_dec() { max_length= args[0]->max_length; }
+ const char *func_name() const { return "rtrim"; }
+};
+
+class Item_func_trim :public Item_str_func
+{
+ String tmp_value;
+public:
+ Item_func_trim(Item *a,Item *b) :Item_str_func(a,b) {}
+ String *val_str(String *);
+ void fix_length_and_dec() { max_length= args[0]->max_length; }
+ const char *func_name() const { return "trim"; }
+};
+
+
+class Item_func_password :public Item_str_func
+{
+ char tmp_value[17];
+public:
+ Item_func_password(Item *a) :Item_str_func(a) {}
+ String *val_str(String *);
+ void fix_length_and_dec() { max_length = 16; }
+ const char *func_name() const { return "password"; }
+};
+
+class Item_func_encrypt :public Item_str_func
+{
+ String tmp_value;
+public:
+ Item_func_encrypt(Item *a) :Item_str_func(a) {}
+ Item_func_encrypt(Item *a, Item *b): Item_str_func(a,b) {}
+ String *val_str(String *);
+ void fix_length_and_dec() { maybe_null=1; max_length = 13; }
+};
+
+#include "sql_crypt.h"
+
+class Item_func_encode :public Item_str_func
+{
+ protected:
+ SQL_CRYPT sql_crypt;
+public:
+ Item_func_encode(Item *a, char *seed):
+ Item_str_func(a),sql_crypt(seed) {}
+ String *val_str(String *);
+ void fix_length_and_dec();
+};
+
+class Item_func_decode :public Item_func_encode
+{
+public:
+ Item_func_decode(Item *a, char *seed): Item_func_encode(a,seed) {}
+ String *val_str(String *);
+};
+
+
+class Item_func_database :public Item_str_func
+{
+public:
+ Item_func_database() {}
+ String *val_str(String *);
+ void fix_length_and_dec() { max_length= MAX_FIELD_NAME; }
+ const char *func_name() const { return "database"; }
+};
+
+class Item_func_user :public Item_str_func
+{
+public:
+ Item_func_user() {}
+ String *val_str(String *);
+ void fix_length_and_dec() { max_length= USERNAME_LENGTH+HOSTNAME_LENGTH+1; }
+ const char *func_name() const { return "user"; }
+};
+
+
+class Item_func_soundex :public Item_str_func
+{
+public:
+ Item_func_soundex(Item *a) :Item_str_func(a) {}
+ String *val_str(String *);
+ void fix_length_and_dec();
+ const char *func_name() const { return "soundex"; }
+};
+
+
+class Item_func_elt :public Item_str_func
+{
+ Item *item;
+
+public:
+ Item_func_elt(Item *a,List<Item> &list) :Item_str_func(list),item(a) {}
+ ~Item_func_elt() { delete item; }
+ double val();
+ longlong val_int();
+ String *val_str(String *str);
+ bool fix_fields(THD *thd,struct st_table_list *tlist)
+ {
+ return (item->fix_fields(thd,tlist) || Item_func::fix_fields(thd,tlist));
+ }
+ void fix_length_and_dec();
+ void update_used_tables();
+ const char *func_name() const { return "elt"; }
+};
+
+
+class Item_func_make_set :public Item_str_func
+{
+ Item *item;
+ String tmp_str;
+
+public:
+ Item_func_make_set(Item *a,List<Item> &list) :Item_str_func(list),item(a) {}
+ ~Item_func_make_set() { delete item; }
+ String *val_str(String *str);
+ bool fix_fields(THD *thd,struct st_table_list *tlist)
+ {
+ return (item->fix_fields(thd,tlist) || Item_func::fix_fields(thd,tlist));
+ }
+ void fix_length_and_dec();
+ void update_used_tables();
+ const char *func_name() const { return "make_set"; }
+};
+
+
+class Item_func_format :public Item_str_func
+{
+ String tmp_str;
+public:
+ Item_func_format(Item *org,int dec);
+ String *val_str(String *);
+ void fix_length_and_dec()
+ {
+ max_length=args[0]->max_length+(args[0]->max_length-args[0]->decimals)/3;
+ }
+ const char *func_name() const { return "format"; }
+};
+
+
+class Item_func_char :public Item_str_func
+{
+public:
+ Item_func_char(List<Item> &list) :Item_str_func(list) {}
+ String *val_str(String *);
+ void fix_length_and_dec() { maybe_null=0; max_length=arg_count; binary=0;}
+ const char *func_name() const { return "char"; }
+};
+
+
+class Item_func_repeat :public Item_str_func
+{
+ String tmp_value;
+public:
+ Item_func_repeat(Item *arg1,Item *arg2) :Item_str_func(arg1,arg2) {}
+ String *val_str(String *);
+ void fix_length_and_dec();
+ const char *func_name() const { return "repeat"; }
+};
+
+
+class Item_func_rpad :public Item_str_func
+{
+ String tmp_value;
+public:
+ Item_func_rpad(Item *arg1,Item *arg2,Item *arg3)
+ :Item_str_func(arg1,arg2,arg3) {}
+ String *val_str(String *);
+ void fix_length_and_dec();
+ const char *func_name() const { return "rpad"; }
+};
+
+
+class Item_func_lpad :public Item_str_func
+{
+ String tmp_value;
+public:
+ Item_func_lpad(Item *arg1,Item *arg2,Item *arg3)
+ :Item_str_func(arg1,arg2,arg3) {}
+ String *val_str(String *);
+ void fix_length_and_dec();
+ const char *func_name() const { return "lpad"; }
+};
+
+
+class Item_func_conv :public Item_str_func
+{
+public:
+ Item_func_conv(Item *a,Item *b,Item *c) :Item_str_func(a,b,c) {}
+ const char *func_name() const { return "conv"; }
+ String *val_str(String *);
+ void fix_length_and_dec() { decimals=0; max_length=64; }
+};
+
+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)); }
+ void fix_length_and_dec() { binary=1; max_length=args[0]->max_length; }
+ void print(String *str) { print_op(str); }
+};
+
+
+class Item_load_file :public Item_str_func
+{
+ String tmp_value;
+public:
+ Item_load_file(Item *a) :Item_str_func(a) {}
+ String *val_str(String *);
+ const char *func_name() const { return "load_file"; }
+ void fix_length_and_dec()
+ { binary=1; maybe_null=1; max_length=MAX_BLOB_WIDTH;}
+};
+
+
+class Item_func_export_set: public Item_str_func
+{
+ public:
+ Item_func_export_set(Item *a,Item *b,Item* c) :Item_str_func(a,b,c) {}
+ Item_func_export_set(Item *a,Item *b,Item* c,Item* d) :Item_str_func(a,b,c,d) {}
+ Item_func_export_set(Item *a,Item *b,Item* c,Item* d,Item* e) :Item_str_func(a,b,c,d,e) {}
+ String *val_str(String *str);
+ void fix_length_and_dec();
+ const char *func_name() const { return "export_set"; }
+};
+
+ class Item_func_inet_ntoa : public Item_str_func
+{
+public:
+ Item_func_inet_ntoa(Item *a) :Item_str_func(a)
+ {
+ }
+ String* val_str(String* str);
+ const char *func_name() const { return "inet_ntoa"; }
+ void fix_length_and_dec() { decimals = 0; max_length=3*8+7; }
+};
diff --git a/sql/item_sum.cc b/sql/item_sum.cc
new file mode 100644
index 00000000000..408e5d941ae
--- /dev/null
+++ b/sql/item_sum.cc
@@ -0,0 +1,941 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+
+/* Sum functions (COUNT, MIN...) */
+
+#ifdef __GNUC__
+#pragma implementation // gcc: Class implementation
+#endif
+
+#include "mysql_priv.h"
+
+
+Item_sum::Item_sum(List<Item> &list)
+{
+ arg_count=list.elements;
+ if ((args=(Item**) sql_alloc(sizeof(Item*)*arg_count)))
+ {
+ uint i=0;
+ List_iterator<Item> li(list);
+ Item *item;
+
+ while ((item=li++))
+ {
+ args[i++]= item;
+ }
+ }
+ with_sum_func=1;
+ list.empty(); // Fields are used
+}
+
+
+void Item_sum::make_field(Send_field *tmp_field)
+{
+ if (args[0]->type() == Item::FIELD_ITEM && keep_field_type())
+ ((Item_field*) args[0])->field->make_field(tmp_field);
+ else
+ {
+ tmp_field->flags=0;
+ if (!maybe_null)
+ tmp_field->flags|= NOT_NULL_FLAG;
+ tmp_field->length=max_length;
+ tmp_field->decimals=decimals;
+ tmp_field->type=(result_type() == INT_RESULT ? FIELD_TYPE_LONG :
+ result_type() == REAL_RESULT ? FIELD_TYPE_DOUBLE :
+ FIELD_TYPE_VAR_STRING);
+ }
+ tmp_field->table_name=(char*)"";
+ tmp_field->col_name=name;
+}
+
+void Item_sum::print(String *str)
+{
+ str->append(func_name());
+ str->append('(');
+ for (uint i=0 ; i < arg_count ; i++)
+ {
+ if (i)
+ str->append(',');
+ args[i]->print(str);
+ }
+ str->append(')');
+}
+
+void Item_sum::fix_num_length_and_dec()
+{
+ decimals=0;
+ for (uint i=0 ; i < arg_count ; i++)
+ set_if_bigger(decimals,args[i]->decimals);
+ max_length=float_length(decimals);
+}
+
+
+String *
+Item_sum_num::val_str(String *str)
+{
+ double nr=val();
+ if (null_value)
+ return 0;
+ str->set(nr,decimals);
+ return str;
+}
+
+
+String *
+Item_sum_int::val_str(String *str)
+{
+ longlong nr=val_int();
+ if (null_value)
+ return 0;
+ char buff[21];
+ uint length= (uint) (longlong10_to_str(nr,buff,-10)-buff);
+ str->copy(buff,length);
+ return str;
+}
+
+
+bool
+Item_sum_num::fix_fields(THD *thd,TABLE_LIST *tables)
+{
+ if (!thd->allow_sum_func)
+ {
+ my_error(ER_INVALID_GROUP_FUNC_USE,MYF(0));
+ return 1;
+ }
+ thd->allow_sum_func=0; // No included group funcs
+ decimals=0;
+ maybe_null=0;
+ for (uint i=0 ; i < arg_count ; i++)
+ {
+ if (args[i]->fix_fields(thd,tables))
+ return 1;
+ if (decimals < args[i]->decimals)
+ decimals=args[i]->decimals;
+ maybe_null |= args[i]->maybe_null;
+ }
+ result_field=0;
+ max_length=float_length(decimals);
+ null_value=1;
+ fix_length_and_dec();
+ thd->allow_sum_func=1; // Allow group functions
+ return 0;
+}
+
+
+bool
+Item_sum_hybrid::fix_fields(THD *thd,TABLE_LIST *tables)
+{
+ Item *item=args[0];
+ if (!thd->allow_sum_func)
+ {
+ my_error(ER_INVALID_GROUP_FUNC_USE,MYF(0));
+ return 1;
+ }
+ thd->allow_sum_func=0; // No included group funcs
+ if (item->fix_fields(thd,tables))
+ return 1;
+ hybrid_type=item->result_type();
+ if (hybrid_type == INT_RESULT)
+ max_length=21;
+ else if (hybrid_type == REAL_RESULT)
+ max_length=float_length(decimals);
+ else
+ max_length=item->max_length;
+ decimals=item->decimals;
+ maybe_null=item->maybe_null;
+ binary=item->binary;
+ result_field=0;
+ null_value=1;
+ fix_length_and_dec();
+ thd->allow_sum_func=1; // Allow group functions
+ return 0;
+}
+
+
+/***********************************************************************
+** reset and add of sum_func
+***********************************************************************/
+
+void Item_sum_sum::reset()
+{
+ null_value=0; sum=0.0; Item_sum_sum::add();
+}
+
+bool Item_sum_sum::add()
+{
+ sum+=args[0]->val();
+ return 0;
+}
+
+double Item_sum_sum::val()
+{
+ return sum;
+}
+
+
+void Item_sum_count::reset()
+{
+ count=0; add();
+}
+
+bool Item_sum_count::add()
+{
+ if (!args[0]->maybe_null)
+ count++;
+ else
+ {
+ (void) args[0]->val_int();
+ if (!args[0]->null_value)
+ count++;
+ }
+ return 0;
+}
+
+longlong Item_sum_count::val_int()
+{
+ return (longlong) count;
+}
+
+/*
+** Avgerage
+*/
+
+void Item_sum_avg::reset()
+{
+ sum=0.0; count=0; Item_sum_avg::add();
+}
+
+bool Item_sum_avg::add()
+{
+ double nr=args[0]->val();
+ if (!args[0]->null_value)
+ {
+ sum+=nr;
+ count++;
+ }
+ return 0;
+}
+
+double Item_sum_avg::val()
+{
+ if (!count)
+ {
+ null_value=1;
+ return 0.0;
+ }
+ null_value=0;
+ return sum/ulonglong2double(count);
+}
+
+
+/*
+** Standard deviation
+*/
+
+void Item_sum_std::reset()
+{
+ sum=sum_sqr=0.0; count=0; (void) Item_sum_std::add();
+}
+
+bool Item_sum_std::add()
+{
+ double nr=args[0]->val();
+ if (!args[0]->null_value)
+ {
+ sum+=nr;
+ sum_sqr+=nr*nr;
+ count++;
+ }
+ return 0;
+}
+
+double Item_sum_std::val()
+{
+ if (!count)
+ {
+ null_value=1;
+ return 0.0;
+ }
+ null_value=0;
+ /* Avoid problems when the precision isn't good enough */
+ double tmp=ulonglong2double(count);
+ double tmp2=(sum_sqr - sum*sum/tmp)/tmp;
+ return tmp2 <= 0.0 ? 0.0 : sqrt(tmp2);
+}
+
+
+void Item_sum_std::reset_field()
+{
+ double nr=args[0]->val();
+ char *res=result_field->ptr;
+
+ if (args[0]->null_value)
+ bzero(res,sizeof(double)*2+sizeof(longlong));
+ else
+ {
+ float8store(res,nr);
+ nr*=nr;
+ float8store(res+sizeof(double),nr);
+ longlong tmp=1;
+ int8store(res+sizeof(double)*2,tmp);
+ }
+}
+
+void Item_sum_std::update_field(int offset)
+{
+ double nr,old_nr,old_sqr;
+ longlong field_count;
+ char *res=result_field->ptr;
+
+ float8get(old_nr,res+offset);
+ float8get(old_sqr,res+offset+sizeof(double));
+ field_count=sint8korr(res+offset+sizeof(double)*2);
+
+ nr=args[0]->val();
+ if (!args[0]->null_value)
+ {
+ old_nr+=nr;
+ old_sqr+=nr*nr;
+ field_count++;
+ }
+ float8store(res,old_nr);
+ float8store(res+sizeof(double),old_sqr);
+ int8store(res+sizeof(double)*2,field_count);
+}
+
+/* min & max */
+
+double Item_sum_hybrid::val()
+{
+ if (null_value)
+ return 0.0;
+ if (hybrid_type == STRING_RESULT)
+ {
+ String *res; res=val_str(&str_value);
+ return res ? atof(res->c_ptr()) : 0.0;
+ }
+ return sum;
+}
+
+
+String *
+Item_sum_hybrid::val_str(String *str)
+{
+ if (null_value)
+ return 0;
+ if (hybrid_type == STRING_RESULT)
+ return &value;
+ str->set(sum,decimals);
+ return str;
+}
+
+
+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
+ {
+ String *result=args[0]->val_str(&tmp_value);
+ if (!args[0]->null_value &&
+ (null_value ||
+ (binary ? stringcmp(&value,result) : sortcmp(&value,result)) > 0))
+ {
+ value.copy(*result);
+ null_value=0;
+ }
+ }
+ return 0;
+}
+
+
+bool Item_sum_max::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
+ {
+ String *result=args[0]->val_str(&tmp_value);
+ if (!args[0]->null_value &&
+ (null_value ||
+ (binary ? stringcmp(&value,result) : sortcmp(&value,result)) < 0))
+ {
+ value.copy(*result);
+ null_value=0;
+ }
+ }
+ return 0;
+}
+
+
+/* bit_or and bit_and */
+
+longlong Item_sum_bit::val_int()
+{
+ return (longlong) bits;
+}
+
+void Item_sum_bit::reset()
+{
+ bits=reset_bits; add();
+}
+
+bool Item_sum_or::add()
+{
+ ulonglong value= (ulonglong) args[0]->val_int();
+ if (!args[0]->null_value)
+ bits|=value;
+ return 0;
+}
+
+bool Item_sum_and::add()
+{
+ ulonglong value= (ulonglong) args[0]->val_int();
+ if (!args[0]->null_value)
+ bits&=value;
+ return 0;
+}
+
+/************************************************************************
+** reset result of a Item_sum with is saved in a tmp_table
+*************************************************************************/
+
+void Item_sum_num::reset_field()
+{
+ double nr=args[0]->val();
+ char *res=result_field->ptr;
+
+ if (maybe_null)
+ {
+ if (args[0]->null_value)
+ {
+ nr=0.0;
+ result_field->set_null();
+ }
+ else
+ result_field->set_notnull();
+ }
+ float8store(res,nr);
+}
+
+
+void Item_sum_hybrid::reset_field()
+{
+ if (hybrid_type == STRING_RESULT)
+ {
+ char buff[MAX_FIELD_WIDTH];
+ String tmp(buff,sizeof(buff)),*res;
+
+ res=args[0]->val_str(&tmp);
+ if (args[0]->null_value)
+ {
+ result_field->set_null();
+ result_field->reset();
+ }
+ else
+ {
+ result_field->set_notnull();
+ result_field->store(res->ptr(),res->length());
+ }
+ }
+ else if (hybrid_type == INT_RESULT)
+ {
+ longlong nr=args[0]->val_int();
+
+ if (maybe_null)
+ {
+ if (args[0]->null_value)
+ {
+ nr=0;
+ result_field->set_null();
+ }
+ else
+ result_field->set_notnull();
+ }
+ result_field->store(nr);
+ }
+ else // REAL_RESULT
+ {
+ double nr=args[0]->val();
+
+ if (maybe_null)
+ {
+ if (args[0]->null_value)
+ {
+ nr=0.0;
+ result_field->set_null();
+ }
+ else
+ result_field->set_notnull();
+ }
+ result_field->store(nr);
+ }
+}
+
+
+void Item_sum_sum::reset_field()
+{
+ double nr=args[0]->val(); // Nulls also return 0
+ float8store(result_field->ptr,nr);
+ null_value=0;
+ result_field->set_notnull();
+}
+
+
+void Item_sum_count::reset_field()
+{
+ char *res=result_field->ptr;
+ longlong nr=0;
+
+ if (!args[0]->maybe_null)
+ nr=1;
+ else
+ {
+ (void) args[0]->val_int();
+ if (!args[0]->null_value)
+ nr=1;
+ }
+ int8store(res,nr);
+}
+
+
+void Item_sum_avg::reset_field()
+{
+ double nr=args[0]->val();
+ char *res=result_field->ptr;
+
+ if (args[0]->null_value)
+ bzero(res,sizeof(double)+sizeof(longlong));
+ else
+ {
+ float8store(res,nr);
+ res+=sizeof(double);
+ longlong tmp=1;
+ int8store(res,tmp);
+ }
+}
+
+void Item_sum_bit::reset_field()
+{
+ char *res=result_field->ptr;
+ ulonglong nr=(ulonglong) args[0]->val_int();
+ int8store(res,nr);
+}
+
+/*
+** calc next value and merge it with field_value
+*/
+
+void Item_sum_sum::update_field(int offset)
+{
+ double old_nr,nr;
+ char *res=result_field->ptr;
+
+ float8get(old_nr,res+offset);
+ nr=args[0]->val();
+ if (!args[0]->null_value)
+ old_nr+=nr;
+ float8store(res,old_nr);
+}
+
+
+void Item_sum_count::update_field(int offset)
+{
+ longlong nr;
+ char *res=result_field->ptr;
+
+ nr=sint8korr(res+offset);
+ if (!args[0]->maybe_null)
+ nr++;
+ else
+ {
+ (void) args[0]->val_int();
+ if (!args[0]->null_value)
+ nr++;
+ }
+ int8store(res,nr);
+}
+
+
+void Item_sum_avg::update_field(int offset)
+{
+ double nr,old_nr;
+ longlong field_count;
+ char *res=result_field->ptr;
+
+ float8get(old_nr,res+offset);
+ field_count=sint8korr(res+offset+sizeof(double));
+
+ nr=args[0]->val();
+ if (!args[0]->null_value)
+ {
+ old_nr+=nr;
+ field_count++;
+ }
+ float8store(res,old_nr);
+ res+=sizeof(double);
+ int8store(res,field_count);
+}
+
+void Item_sum_hybrid::update_field(int offset)
+{
+ if (hybrid_type == STRING_RESULT)
+ min_max_update_str_field(offset);
+ else if (hybrid_type == INT_RESULT)
+ min_max_update_int_field(offset);
+ else
+ min_max_update_real_field(offset);
+}
+
+
+void
+Item_sum_hybrid::min_max_update_str_field(int offset)
+{
+ String *res_str=args[0]->val_str(&value);
+
+ if (args[0]->null_value)
+ result_field->copy_from_tmp(offset); // Use old value
+ else
+ {
+ res_str->strip_sp();
+ result_field->ptr+=offset; // Get old max/min
+ result_field->val_str(&tmp_value,&tmp_value);
+ result_field->ptr-=offset;
+
+ if (result_field->is_null() ||
+ (cmp_sign * (binary ? stringcmp(res_str,&tmp_value) :
+ sortcmp(res_str,&tmp_value)) < 0))
+ result_field->store(res_str->ptr(),res_str->length());
+ else
+ { // Use old value
+ char *res=result_field->ptr;
+ memcpy(res,res+offset,result_field->pack_length());
+ }
+ result_field->set_notnull();
+ }
+}
+
+
+void
+Item_sum_hybrid::min_max_update_real_field(int offset)
+{
+ double nr,old_nr;
+
+ result_field->ptr+=offset;
+ old_nr=result_field->val_real();
+ nr=args[0]->val();
+ if (!args[0]->null_value)
+ {
+ if (result_field->is_null(offset) ||
+ (cmp_sign > 0 ? old_nr > nr : old_nr < nr))
+ old_nr=nr;
+ result_field->set_notnull();
+ }
+ else if (result_field->is_null(offset))
+ result_field->set_null();
+ result_field->ptr-=offset;
+ result_field->store(old_nr);
+}
+
+
+void
+Item_sum_hybrid::min_max_update_int_field(int offset)
+{
+ longlong nr,old_nr;
+
+ result_field->ptr+=offset;
+ old_nr=result_field->val_int();
+ 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))
+ old_nr=nr;
+ result_field->set_notnull();
+ }
+ else if (result_field->is_null(offset))
+ result_field->set_null();
+ result_field->ptr-=offset;
+ result_field->store(old_nr);
+}
+
+
+void Item_sum_or::update_field(int offset)
+{
+ ulonglong nr;
+ char *res=result_field->ptr;
+
+ nr=uint8korr(res+offset);
+ nr|= (ulonglong) args[0]->val_int();
+ int8store(res,nr);
+}
+
+
+void Item_sum_and::update_field(int offset)
+{
+ ulonglong nr;
+ char *res=result_field->ptr;
+
+ nr=uint8korr(res+offset);
+ nr&= (ulonglong) args[0]->val_int();
+ int8store(res,nr);
+}
+
+
+Item_avg_field::Item_avg_field(Item_sum_avg *item)
+{
+ name=item->name;
+ decimals=item->decimals;
+ max_length=item->max_length;
+ field=item->result_field;
+ maybe_null=1;
+}
+
+double Item_avg_field::val()
+{
+ double nr;
+ longlong count;
+ float8get(nr,field->ptr);
+ char *res=(field->ptr+sizeof(double));
+ count=sint8korr(res);
+
+ if (!count)
+ {
+ null_value=1;
+ return 0.0;
+ }
+ null_value=0;
+ return nr/(double) count;
+}
+
+String *Item_avg_field::val_str(String *str)
+{
+ double nr=Item_avg_field::val();
+ if (null_value)
+ return 0;
+ str->set(nr,decimals);
+ return str;
+}
+
+Item_std_field::Item_std_field(Item_sum_std *item)
+{
+ name=item->name;
+ decimals=item->decimals;
+ max_length=item->max_length;
+ field=item->result_field;
+ maybe_null=1;
+}
+
+double Item_std_field::val()
+{
+ double sum,sum_sqr;
+ longlong count;
+ float8get(sum,field->ptr);
+ float8get(sum_sqr,(field->ptr+sizeof(double)));
+ count=sint8korr(field->ptr+sizeof(double)*2);
+
+ if (!count)
+ {
+ null_value=1;
+ return 0.0;
+ }
+ null_value=0;
+ double tmp= (double) count;
+ double tmp2=(sum_sqr - sum*sum/tmp)/tmp;
+ return tmp2 <= 0.0 ? 0.0 : sqrt(tmp2);
+}
+
+String *Item_std_field::val_str(String *str)
+{
+ double nr=val();
+ if (null_value)
+ return 0;
+ str->set(nr,decimals);
+ return str;
+}
+
+/****************************************************************************
+** COUNT(DISTINCT ...)
+****************************************************************************/
+
+#include "sql_select.h"
+
+Item_sum_count_distinct::~Item_sum_count_distinct()
+{
+ if (table)
+ free_tmp_table(current_thd, table);
+ delete tmp_table_param;
+}
+
+
+bool Item_sum_count_distinct::fix_fields(THD *thd,TABLE_LIST *tables)
+{
+ if (Item_sum_num::fix_fields(thd,tables) ||
+ !(tmp_table_param= new TMP_TABLE_PARAM))
+ return 1;
+ return 0;
+}
+
+bool Item_sum_count_distinct::setup(THD *thd)
+{
+ List<Item> list;
+ /* Create a table with an unique key over all parameters */
+ for (uint i=0; i < arg_count ; i++)
+ if (list.push_back(args[i]))
+ return 1;
+ count_field_types(tmp_table_param,list);
+ if (table)
+ {
+ free_tmp_table(thd, table);
+ tmp_table_param->cleanup();
+ }
+ if (!(table=create_tmp_table(thd, tmp_table_param, list, (ORDER*) 0, 1,
+ 0, 0, current_lex->options | thd->options)))
+ return 1;
+ table->file->extra(HA_EXTRA_NO_ROWS); // Don't update rows
+ return 0;
+}
+
+
+void Item_sum_count_distinct::reset()
+{
+ table->file->extra(HA_EXTRA_NO_CACHE);
+ table->file->delete_all_rows();
+ table->file->extra(HA_EXTRA_WRITE_CACHE);
+ (void) add();
+}
+
+bool Item_sum_count_distinct::add()
+{
+ int error;
+ copy_fields(tmp_table_param);
+ copy_funcs(tmp_table_param->funcs);
+
+ if ((error=table->file->write_row(table->record[0])))
+ {
+ if (error != HA_ERR_FOUND_DUPP_KEY &&
+ error != HA_ERR_FOUND_DUPP_UNIQUE)
+ {
+ if (create_myisam_from_heap(table, tmp_table_param, error,1))
+ return 1; // Not a table_is_full error
+ }
+ }
+ return 0;
+}
+
+longlong Item_sum_count_distinct::val_int()
+{
+ if (!table) // Empty query
+ return LL(0);
+ table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
+ return table->file->records;
+}
+
+/****************************************************************************
+** Functions to handle dynamic loadable aggregates
+** Original source by: Alexis Mikhailov <root@medinf.chuvashia.su>
+** Adapted for UDAs by: Andreas F. Bobak <bobak@relog.ch>.
+** Rewritten by: Monty.
+****************************************************************************/
+
+#ifdef HAVE_DLOPEN
+
+void Item_udf_sum::reset()
+{
+ DBUG_ENTER("Item_udf_sum::reset");
+ udf.reset(&null_value);
+ DBUG_VOID_RETURN;
+}
+
+bool Item_udf_sum::add()
+{
+ DBUG_ENTER("Item_udf_sum::reset");
+ udf.add(&null_value);
+ DBUG_RETURN(0);
+}
+
+double Item_sum_udf_float::val()
+{
+ DBUG_ENTER("Item_sum_udf_float::val");
+ DBUG_PRINT("info",("result_type: %d arg_count: %d",
+ args[0]->result_type(), arg_count));
+ DBUG_RETURN(udf.val(&null_value));
+}
+
+String *Item_sum_udf_float::val_str(String *str)
+{
+ double nr=val();
+ if (null_value)
+ return 0; /* purecov: inspected */
+ else
+ str->set(nr,decimals);
+ return str;
+}
+
+
+longlong Item_sum_udf_int::val_int()
+{
+ DBUG_ENTER("Item_sum_udf_int::val_int");
+ DBUG_PRINT("info",("result_type: %d arg_count: %d",
+ args[0]->result_type(), arg_count));
+ DBUG_RETURN(udf.val_int(&null_value));
+}
+
+String *Item_sum_udf_int::val_str(String *str)
+{
+ longlong nr=val_int();
+ if (null_value)
+ return 0;
+ else
+ str->set(nr);
+ return str;
+}
+
+/* Default max_length is max argument length */
+
+void Item_sum_udf_str::fix_length_and_dec()
+{
+ DBUG_ENTER("Item_sum_udf_str::fix_length_and_dec");
+ max_length=0;
+ for (uint i = 0; i < arg_count; i++)
+ set_if_bigger(max_length,args[i]->max_length);
+ DBUG_VOID_RETURN;
+}
+
+String *Item_sum_udf_str::val_str(String *str)
+{
+ DBUG_ENTER("Item_sum_udf_str::str");
+ String *res=udf.val_str(str,&str_value);
+ null_value = !res;
+ DBUG_RETURN(res);
+}
+
+#endif /* HAVE_DLOPEN */
diff --git a/sql/item_sum.h b/sql/item_sum.h
new file mode 100644
index 00000000000..66231040747
--- /dev/null
+++ b/sql/item_sum.h
@@ -0,0 +1,464 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+
+/* classes for sum functions */
+
+#ifdef __GNUC__
+#pragma interface /* gcc class implementation */
+#endif
+
+class Item_sum :public Item_result_field
+{
+public:
+ enum Sumfunctype {COUNT_FUNC,COUNT_DISTINCT_FUNC,SUM_FUNC,AVG_FUNC,MIN_FUNC,
+ MAX_FUNC, UNIQUE_USERS_FUNC,STD_FUNC,SUM_BIT_FUNC,
+ UDF_SUM_FUNC };
+
+ Item **args,*tmp_args[2];
+ uint arg_count;
+ bool quick_group; /* If incremental update of fields */
+
+ Item_sum() : arg_count(0),quick_group(1) { with_sum_func=1; }
+ Item_sum(Item *a) :quick_group(1)
+ {
+ arg_count=1;
+ args=tmp_args;
+ args[0]=a;
+ with_sum_func = 1;
+ }
+ Item_sum( Item *a, Item *b ) :quick_group(1)
+ {
+ arg_count=2;
+ args=tmp_args;
+ args[0]=a; args[1]=b;
+ with_sum_func=1;
+ }
+ Item_sum(List<Item> &list);
+ ~Item_sum() { result_field=0; }
+ enum Type type() const { return SUM_FUNC_ITEM; }
+ virtual enum Sumfunctype sum_func () const=0;
+ virtual void reset()=0;
+ virtual bool add()=0;
+ virtual void reset_field()=0;
+ virtual void update_field(int offset)=0;
+ virtual bool keep_field_type(void) const { return 0; }
+ virtual void fix_length_and_dec() { maybe_null=1; null_value=1; }
+ virtual const char *func_name() const { return "?"; }
+ virtual Item *result_item(Field *field)
+ { return new Item_field(field);}
+ table_map used_tables() const { return ~(table_map) 0; } /* Not used */
+ bool const_item() const { return 0; }
+ void update_used_tables() { }
+ void make_field(Send_field *field);
+ void print(String *str);
+ void fix_num_length_and_dec();
+ virtual bool setup(THD *thd) {return 0;}
+};
+
+
+class Item_sum_num :public Item_sum
+{
+public:
+ Item_sum_num() :Item_sum() {}
+ Item_sum_num(Item *item_par) :Item_sum(item_par) {}
+ Item_sum_num(Item *a, Item* b) :Item_sum(a,b) {}
+ Item_sum_num(List<Item> &list) :Item_sum(list) {}
+ bool fix_fields(THD *,struct st_table_list *);
+ longlong val_int() { return (longlong) val(); } /* Real as default */
+ String *val_str(String*str);
+ void reset_field();
+};
+
+
+class Item_sum_int :public Item_sum_num
+{
+ void fix_length_and_dec()
+ { decimals=0; max_length=21; maybe_null=null_value=0; }
+
+public:
+ Item_sum_int(Item *item_par) :Item_sum_num(item_par) {}
+ Item_sum_int(List<Item> &list) :Item_sum_num(list) {}
+ double val() { return (double) val_int(); }
+ String *val_str(String*str);
+ enum Item_result result_type () const { return INT_RESULT; }
+};
+
+
+class Item_sum_sum :public Item_sum_num
+{
+ double sum;
+ void fix_length_and_dec() { maybe_null=null_value=1; }
+
+ public:
+ Item_sum_sum(Item *item_par) :Item_sum_num(item_par),sum(0.0) {}
+ enum Sumfunctype sum_func () const {return SUM_FUNC;}
+ void reset();
+ bool add();
+ double val();
+ void reset_field();
+ void update_field(int offset);
+ const char *func_name() const { return "sum"; }
+};
+
+
+class Item_sum_count :public Item_sum_int
+{
+ longlong count;
+ table_map used_table_cache;
+
+ public:
+ Item_sum_count(Item *item_par)
+ :Item_sum_int(item_par),count(0),used_table_cache(~(table_map) 0)
+ {}
+ table_map used_tables() const { return used_table_cache; }
+ bool const_item() const { return !used_table_cache; }
+ enum Sumfunctype sum_func () const { return COUNT_FUNC; }
+ void reset();
+ bool add();
+ void make_const(longlong count_arg) { count=count_arg; used_table_cache=0; }
+ longlong val_int();
+ void reset_field();
+ void update_field(int offset);
+ const char *func_name() const { return "count"; }
+};
+
+
+class TMP_TABLE_PARAM;
+
+class Item_sum_count_distinct :public Item_sum_int
+{
+ TABLE *table;
+ table_map used_table_cache;
+ bool fix_fields(THD *thd,TABLE_LIST *tables);
+ TMP_TABLE_PARAM *tmp_table_param;
+
+ public:
+ Item_sum_count_distinct(List<Item> &list)
+ :Item_sum_int(list),table(0),used_table_cache(~(table_map) 0),
+ tmp_table_param(0)
+ { quick_group=0; }
+ ~Item_sum_count_distinct();
+ table_map used_tables() const { return used_table_cache; }
+ enum Sumfunctype sum_func () const { return COUNT_DISTINCT_FUNC; }
+ void reset();
+ bool add();
+ longlong val_int();
+ void reset_field() { return ;} // Never called
+ void update_field(int offset) { return ; } // Never called
+ const char *func_name() const { return "count_distinct"; }
+ bool setup(THD *thd);
+};
+
+
+/* Item to get the value of a stored sum function */
+
+class Item_avg_field :public Item_result_field
+{
+public:
+ Field *field;
+ Item_avg_field(Item_sum_avg *item);
+ enum Type type() const { return FIELD_AVG_ITEM; }
+ double val();
+ longlong val_int() { return (longlong) val(); }
+ String *val_str(String*);
+ void make_field(Send_field *field);
+ void fix_length_and_dec() {}
+};
+
+
+class Item_sum_avg :public Item_sum_num
+{
+ void fix_length_and_dec() { decimals+=4; maybe_null=1; }
+
+ double sum;
+ ulonglong count;
+
+ public:
+ Item_sum_avg(Item *item_par) :Item_sum_num(item_par),count(0) {}
+ enum Sumfunctype sum_func () const {return AVG_FUNC;}
+ void reset();
+ bool add();
+ double val();
+ void reset_field();
+ void update_field(int offset);
+ Item *result_item(Field *field)
+ { return new Item_avg_field(this); }
+ const char *func_name() const { return "avg"; }
+};
+
+
+class Item_std_field :public Item_result_field
+{
+public:
+ Field *field;
+ Item_std_field(Item_sum_std *item);
+ enum Type type() const { return FIELD_STD_ITEM; }
+ double val();
+ longlong val_int() { return (longlong) val(); }
+ String *val_str(String*);
+ void make_field(Send_field *field);
+ void fix_length_and_dec() {}
+};
+
+class Item_sum_std :public Item_sum_num
+{
+ double sum;
+ double sum_sqr;
+ ulonglong count;
+ void fix_length_and_dec() { decimals+=4; maybe_null=1; }
+
+ public:
+ Item_sum_std(Item *item_par) :Item_sum_num(item_par),count(0) {}
+ enum Sumfunctype sum_func () const { return STD_FUNC; }
+ void reset();
+ bool add();
+ double val();
+ void reset_field();
+ void update_field(int offset);
+ Item *result_item(Field *field)
+ { return new Item_std_field(this); }
+ const char *func_name() const { return "std"; }
+};
+
+
+// This class is a string or number function depending on num_func
+
+class Item_sum_hybrid :public Item_sum
+{
+ protected:
+ String value,tmp_value;
+ double sum;
+ Item_result hybrid_type;
+ int cmp_sign;
+ table_map used_table_cache;
+
+ public:
+ Item_sum_hybrid(Item *item_par,int sign) :Item_sum(item_par),cmp_sign(sign),
+ used_table_cache(~(table_map) 0)
+ {}
+ bool fix_fields(THD *,struct st_table_list *);
+ table_map used_tables() const { return used_table_cache; }
+ bool const_item() const { return !used_table_cache; }
+
+ void reset()
+ {
+ sum=0.0;
+ value.length(0);
+ null_value=1;
+ add();
+ }
+ double val();
+ longlong val_int() { return (longlong) val(); } /* Real as default */
+ void reset_field();
+ String *val_str(String *);
+ void make_const() { used_table_cache=0; }
+ bool keep_field_type(void) const { return 1; }
+ enum Item_result result_type () const { return hybrid_type; }
+ void update_field(int offset);
+ void min_max_update_str_field(int offset);
+ void min_max_update_real_field(int offset);
+ void min_max_update_int_field(int offset);
+};
+
+
+class Item_sum_min :public Item_sum_hybrid
+{
+public:
+ Item_sum_min(Item *item_par) :Item_sum_hybrid(item_par,1) {}
+ enum Sumfunctype sum_func () const {return MIN_FUNC;}
+
+ bool add();
+ const char *func_name() const { return "min"; }
+};
+
+
+class Item_sum_max :public Item_sum_hybrid
+{
+public:
+ Item_sum_max(Item *item_par) :Item_sum_hybrid(item_par,-1) {}
+ enum Sumfunctype sum_func () const {return MAX_FUNC;}
+
+ bool add();
+ const char *func_name() const { return "max"; }
+};
+
+
+class Item_sum_bit :public Item_sum_int
+{
+ protected:
+ ulonglong reset_bits,bits;
+
+ public:
+ Item_sum_bit(Item *item_par,ulonglong reset_arg)
+ :Item_sum_int(item_par),reset_bits(reset_arg),bits(reset_arg) {}
+ enum Sumfunctype sum_func () const {return SUM_BIT_FUNC;}
+ void reset();
+ longlong val_int();
+ void reset_field();
+};
+
+
+class Item_sum_or :public Item_sum_bit
+{
+ public:
+ Item_sum_or(Item *item_par) :Item_sum_bit(item_par,LL(0)) {}
+ bool add();
+ void update_field(int offset);
+ const char *func_name() const { return "bit_or"; }
+};
+
+
+class Item_sum_and :public Item_sum_bit
+{
+ public:
+ Item_sum_and(Item *item_par) :Item_sum_bit(item_par, ~(ulonglong) LL(0)) {}
+ bool add();
+ void update_field(int offset);
+ const char *func_name() const { return "bit_and"; }
+};
+
+/*
+** user defined aggregates
+*/
+#ifdef HAVE_DLOPEN
+
+class Item_udf_sum : public Item_sum
+{
+protected:
+ udf_handler udf;
+
+public:
+ Item_udf_sum(udf_func *udf_arg) :Item_sum(), udf(udf_arg) { quick_group=0;}
+ Item_udf_sum( udf_func *udf_arg, List<Item> &list )
+ :Item_sum( list ), udf(udf_arg)
+ { quick_group=0;}
+ ~Item_udf_sum() {}
+ const char *func_name() const { return udf.name(); }
+ bool fix_fields(THD *thd,struct st_table_list *tables)
+ {
+ return udf.fix_fields(thd,tables,this,this->arg_count,this->args);
+ }
+ enum Sumfunctype sum_func () const { return UDF_SUM_FUNC; }
+ virtual bool have_field_update(void) const { return 0; }
+
+ void reset();
+ bool add();
+ void reset_field() {};
+ void update_field(int offset_arg) {};
+};
+
+
+class Item_sum_udf_float :public Item_udf_sum
+{
+ public:
+ Item_sum_udf_float(udf_func *udf_arg) :Item_udf_sum(udf_arg) {}
+ Item_sum_udf_float(udf_func *udf_arg, List<Item> &list)
+ :Item_udf_sum(udf_arg,list) {}
+ ~Item_sum_udf_float() {}
+ longlong val_int() { return (longlong) Item_sum_udf_float::val(); }
+ double val();
+ String *val_str(String*str);
+ void fix_length_and_dec() { fix_num_length_and_dec(); }
+};
+
+
+class Item_sum_udf_int :public Item_udf_sum
+{
+public:
+ Item_sum_udf_int(udf_func *udf_arg) :Item_udf_sum(udf_arg) {}
+ Item_sum_udf_int(udf_func *udf_arg, List<Item> &list)
+ :Item_udf_sum(udf_arg,list) {}
+ ~Item_sum_udf_int() {}
+ longlong val_int();
+ double val() { return (double) Item_sum_udf_int::val_int(); }
+ String *val_str(String*str);
+ enum Item_result result_type () const { return INT_RESULT; }
+ void fix_length_and_dec() { decimals=0; max_length=21; }
+};
+
+
+class Item_sum_udf_str :public Item_udf_sum
+{
+public:
+ Item_sum_udf_str(udf_func *udf_arg) :Item_udf_sum(udf_arg) {}
+ Item_sum_udf_str(udf_func *udf_arg, List<Item> &list)
+ :Item_udf_sum(udf_arg,list) {}
+ ~Item_sum_udf_str() {}
+ String *val_str(String *);
+ double val()
+ {
+ String *res; res=val_str(&str_value);
+ return res ? atof(res->c_ptr()) : 0.0;
+ }
+ longlong val_int()
+ {
+ String *res; res=val_str(&str_value);
+ return res ? strtoll(res->c_ptr(),(char**) 0,10) : (longlong) 0;
+ }
+ enum Item_result result_type () const { return STRING_RESULT; }
+ void fix_length_and_dec();
+};
+
+#else /* Dummy functions to get sql_yacc.cc compiled */
+
+class Item_sum_udf_float :public Item_sum_num
+{
+ public:
+ Item_sum_udf_float(udf_func *udf_arg) :Item_sum_num() {}
+ Item_sum_udf_float(udf_func *udf_arg, List<Item> &list) :Item_sum_num() {}
+ ~Item_sum_udf_float() {}
+ enum Sumfunctype sum_func () const { return UDF_SUM_FUNC; }
+ double val() { return 0.0; }
+ void reset() {}
+ bool add() { return 0; }
+ void update_field(int offset) {}
+};
+
+
+class Item_sum_udf_int :public Item_sum_num
+{
+public:
+ Item_sum_udf_int(udf_func *udf_arg) :Item_sum_num() {}
+ Item_sum_udf_int(udf_func *udf_arg, List<Item> &list) :Item_sum_num() {}
+ ~Item_sum_udf_int() {}
+ enum Sumfunctype sum_func () const { return UDF_SUM_FUNC; }
+ longlong val_int() { return 0; }
+ double val() { return 0; }
+ void reset() {}
+ bool add() { return 0; }
+ void update_field(int offset) {}
+};
+
+
+class Item_sum_udf_str :public Item_sum_num
+{
+public:
+ Item_sum_udf_str(udf_func *udf_arg) :Item_sum_num() {}
+ Item_sum_udf_str(udf_func *udf_arg, List<Item> &list) :Item_sum_num() {}
+ ~Item_sum_udf_str() {}
+ String *val_str(String *) { null_value=1; return 0; }
+ double val() { null_value=1; return 0.0; }
+ longlong val_int() { null_value=1; return 0; }
+ enum Item_result result_type () const { return STRING_RESULT; }
+ void fix_length_and_dec() { maybe_null=1; max_length=0; }
+ enum Sumfunctype sum_func () const { return UDF_SUM_FUNC; }
+ void reset() {}
+ bool add() { return 0; }
+ void update_field(int offset) {}
+};
+
+#endif /* HAVE_DLOPEN */
diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc
new file mode 100644
index 00000000000..90a6cc2910c
--- /dev/null
+++ b/sql/item_timefunc.cc
@@ -0,0 +1,1117 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 defines all time functions */
+
+#ifdef __GNUC__
+#pragma implementation // gcc: Class implementation
+#endif
+
+#include "mysql_priv.h"
+#include <m_ctype.h>
+#include <time.h>
+
+/*
+** Todo: Move month and days to language files
+*/
+
+static String month_names[] = { "January", "February", "March", "April",
+ "May", "June", "July", "August",
+ "September", "October", "November", "December" };
+static String day_names[] = { "Monday", "Tuesday", "Wednesday",
+ "Thursday", "Friday", "Saturday" ,"Sunday" };
+
+/*
+** Get a array of positive numbers from a string object.
+** Each number is separated by 1 non digit character
+** Return error if there is too many numbers.
+** If there is too few numbers, assume that the numbers are left out
+** from the high end. This allows one to give:
+** DAY_TO_SECOND as "D MM:HH:SS", "MM:HH:SS" "HH:SS" or as seconds.
+*/
+
+bool get_interval_info(const char *str,uint length,uint count,
+ long *values)
+{
+ const char *end=str+length;
+ uint i;
+ while (str != end && !isdigit(*str))
+ str++;
+
+ for (i=0 ; i < count ; i++)
+ {
+ long value;
+ for (value=0; str != end && isdigit(*str) ; str++)
+ value=value*10L + (long) (*str - '0');
+ values[i]= value;
+ while (str != end && !isdigit(*str))
+ str++;
+ if (str == end && i != count-1)
+ {
+ i++;
+ /* Change values[0...i-1] -> values[0...count-1] */
+ bmove_upp((char*) (values+count), (char*) (values+i),
+ sizeof(long)*i);
+ bzero((char*) values, sizeof(long)*(count-i));
+ break;
+ }
+ }
+ return (str != end);
+}
+
+longlong Item_func_period_add::val_int()
+{
+ ulong period=(ulong) args[0]->val_int();
+ int months=(int) args[1]->val_int();
+
+ if ((null_value=args[0]->null_value || args[1]->null_value) ||
+ period == 0L)
+ return 0; /* purecov: inspected */
+ return (longlong)
+ convert_month_to_period((uint) ((int) convert_period_to_month(period)+
+ months));
+}
+
+
+longlong Item_func_period_diff::val_int()
+{
+ ulong period1=(ulong) args[0]->val_int();
+ ulong period2=(ulong) args[1]->val_int();
+
+ if ((null_value=args[0]->null_value || args[1]->null_value))
+ return 0; /* purecov: inspected */
+ return (longlong) ((long) convert_period_to_month(period1)-
+ (long) convert_period_to_month(period2));
+}
+
+
+
+longlong Item_func_to_days::val_int()
+{
+ TIME ltime;
+ if (get_arg0_date(&ltime,0))
+ return 0;
+ return (longlong) calc_daynr(ltime.year,ltime.month,ltime.day);
+}
+
+longlong Item_func_dayofyear::val_int()
+{
+ TIME ltime;
+ if (get_arg0_date(&ltime,0))
+ return 0;
+ return (longlong) calc_daynr(ltime.year,ltime.month,ltime.day) -
+ calc_daynr(ltime.year,1,1) + 1;
+}
+
+longlong Item_func_dayofmonth::val_int()
+{
+ TIME ltime;
+ (void) get_arg0_date(&ltime,1);
+ return (longlong) ltime.day;
+}
+
+longlong Item_func_month::val_int()
+{
+ TIME ltime;
+ (void) get_arg0_date(&ltime,1);
+ return (longlong) ltime.month;
+}
+
+String* Item_func_monthname::val_str(String* str)
+{
+ uint month=(uint) Item_func_month::val_int();
+ if (null_value)
+ return (String*) 0;
+ return &month_names[month-1];
+}
+
+// Returns the quarter of the year
+
+longlong Item_func_quarter::val_int()
+{
+ TIME ltime;
+ (void) get_arg0_date(&ltime,1);
+ return (longlong) ((ltime.month+2)/3);
+}
+
+longlong Item_func_hour::val_int()
+{
+ TIME ltime;
+ (void) get_arg0_time(&ltime);
+ return ltime.hour;
+}
+
+longlong Item_func_minute::val_int()
+{
+ TIME ltime;
+ (void) get_arg0_time(&ltime);
+ return ltime.minute;
+}
+// Returns the second in time_exp in the range of 0 - 59
+
+longlong Item_func_second::val_int()
+{
+ TIME ltime;
+ (void) get_arg0_time(&ltime);
+ return ltime.second;
+}
+
+
+// Returns the week of year in the range of 0 - 53
+
+longlong Item_func_week::val_int()
+{
+ uint year;
+ TIME ltime;
+ if (get_arg0_date(&ltime,0))
+ return 0;
+ return (longlong) calc_week(&ltime, 0, args[1]->val_int() == 0, &year);
+}
+
+
+longlong Item_func_yearweek::val_int()
+{
+ uint year,week;
+ TIME ltime;
+ if (get_arg0_date(&ltime,0))
+ return 0;
+ week=calc_week(&ltime, 1, args[1]->val_int() == 0, &year);
+ return week+year*100;
+}
+
+
+/* weekday() has a automatic to_days() on item */
+
+longlong Item_func_weekday::val_int()
+{
+ ulong tmp_value=(ulong) args[0]->val_int();
+ if ((null_value=(args[0]->null_value || !tmp_value)))
+ return 0; /* purecov: inspected */
+
+ return (longlong) calc_weekday(tmp_value,odbc_type)+test(odbc_type);
+}
+
+String* Item_func_dayname::val_str(String* str)
+{
+ uint weekday=(uint) val_int(); // Always Item_func_daynr()
+ if (null_value)
+ return (String*) 0;
+ return &day_names[weekday];
+}
+
+
+longlong Item_func_year::val_int()
+{
+ TIME ltime;
+ (void) get_arg0_date(&ltime,1);
+ return (longlong) ltime.year;
+}
+
+
+longlong Item_func_unix_timestamp::val_int()
+{
+ if (arg_count == 0)
+ return (longlong) current_thd->query_start();
+ if (args[0]->type() == FIELD_ITEM)
+ { // Optimize timestamp field
+ Field *field=((Item_field*) args[0])->field;
+ if (field->type() == FIELD_TYPE_TIMESTAMP)
+ return ((Field_timestamp*) field)->get_timestamp();
+ }
+ String *str=args[0]->val_str(&value);
+ if ((null_value=args[0]->null_value))
+ {
+ return 0; /* purecov: inspected */
+ }
+ return (longlong) str_to_timestamp(str->ptr(),str->length());
+}
+
+
+longlong Item_func_time_to_sec::val_int()
+{
+ TIME ltime;
+ (void) get_arg0_time(&ltime);
+ return ltime.hour*3600L+ltime.minute*60+ltime.second;
+}
+
+
+/*
+** Convert a string to a interval value
+** To make code easy, allow interval objects without separators.
+*/
+
+static bool get_interval_value(Item *args,interval_type int_type,
+ String *str_value, INTERVAL *t)
+{
+ long array[4],value;
+ const char *str;
+ uint32 length;
+ LINT_INIT(value); LINT_INIT(str); LINT_INIT(length);
+
+ bzero((char*) t,sizeof(*t));
+ if ((int) int_type <= INTERVAL_SECOND)
+ {
+ value=(long) args->val_int();
+ if (args->null_value)
+ return 1;
+ if (value < 0)
+ {
+ t->neg=1;
+ value= -value;
+ }
+ }
+ else
+ {
+ String *res;
+ if (!(res=args->val_str(str_value)))
+ return (1);
+
+ /* record negative intervalls in t->neg */
+ str=res->ptr();
+ const char *end=str+res->length();
+ while (str != end && isspace(*str))
+ str++;
+ if (str != end && *str == '-')
+ {
+ t->neg=1;
+ str++;
+ }
+ length=(uint32) (end-str); // Set up pointers to new str
+ }
+
+ switch (int_type) {
+ case INTERVAL_YEAR:
+ t->year=value;
+ break;
+ case INTERVAL_MONTH:
+ t->month=value;
+ break;
+ case INTERVAL_DAY:
+ t->day=value;
+ break;
+ case INTERVAL_HOUR:
+ t->hour=value;
+ break;
+ case INTERVAL_MINUTE:
+ t->minute=value;
+ break;
+ case INTERVAL_SECOND:
+ t->second=value;
+ break;
+ case INTERVAL_YEAR_MONTH: // Allow YEAR-MONTH YYYYYMM
+ if (get_interval_info(str,length,2,array))
+ return (1);
+ t->year=array[0];
+ t->month=array[1];
+ break;
+ case INTERVAL_DAY_HOUR:
+ if (get_interval_info(str,length,2,array))
+ return (1);
+ t->day=array[0];
+ t->hour=array[1];
+ break;
+ case INTERVAL_DAY_MINUTE:
+ if (get_interval_info(str,length,3,array))
+ return (1);
+ t->day=array[0];
+ t->hour=array[1];
+ t->minute=array[2];
+ break;
+ case INTERVAL_DAY_SECOND:
+ if (get_interval_info(str,length,4,array))
+ return (1);
+ t->day=array[0];
+ t->hour=array[1];
+ t->minute=array[2];
+ t->second=array[3];
+ break;
+ case INTERVAL_HOUR_MINUTE:
+ if (get_interval_info(str,length,2,array))
+ return (1);
+ t->hour=array[0];
+ t->minute=array[1];
+ break;
+ case INTERVAL_HOUR_SECOND:
+ if (get_interval_info(str,length,3,array))
+ return (1);
+ t->hour=array[0];
+ t->minute=array[1];
+ t->second=array[2];
+ break;
+ case INTERVAL_MINUTE_SECOND:
+ if (get_interval_info(str,length,2,array))
+ return (1);
+ t->minute=array[0];
+ t->second=array[1];
+ break;
+ }
+ return 0;
+}
+
+
+String *Item_date::val_str(String *str)
+{
+ ulong value=(ulong) val_int();
+ if (null_value)
+ return (String*) 0;
+ if (!value) // zero daynr
+ {
+ str->copy("0000-00-00");
+ return str;
+ }
+ if (str->alloc(11))
+ return &empty_string; /* purecov: inspected */
+ sprintf((char*) str->ptr(),"%04d-%02d-%02d",
+ (int) (value/10000L) % 10000,
+ (int) (value/100)%100,
+ (int) (value%100));
+ str->length(10);
+ return str;
+}
+
+
+bool Item_date::save_in_field(Field *field)
+{
+ TIME ltime;
+ timestamp_type t_type=TIMESTAMP_FULL;
+ if (get_date(&ltime,1))
+ {
+ if (null_value)
+ return set_field_to_null(field);
+ t_type=TIMESTAMP_NONE; // Error
+ }
+ field->set_notnull();
+ field->store_time(&ltime,t_type);
+ return 0;
+}
+
+
+longlong Item_func_from_days::val_int()
+{
+ longlong value=args[0]->val_int();
+ if ((null_value=args[0]->null_value))
+ return 0; /* purecov: inspected */
+
+ uint year,month,day;
+ get_date_from_daynr((long) value,&year,&month,&day);
+ return (longlong) (year*10000L+month*100+day);
+}
+
+
+void Item_func_curdate::fix_length_and_dec()
+{
+ struct tm tm_tmp,*start;
+ time_t query_start=current_thd->query_start();
+ decimals=0; max_length=10;
+ localtime_r(&query_start,&tm_tmp);
+ start=&tm_tmp;
+ value=(longlong) ((ulong) ((uint) start->tm_year+1900)*10000L+
+ ((uint) start->tm_mon+1)*100+
+ (uint) start->tm_mday);
+ /* For getdate */
+ ltime.year= start->tm_year+1900;
+ ltime.month= start->tm_mon+1;
+ ltime.day= start->tm_mday;
+ ltime.hour= 0;
+ ltime.minute= 0;
+ ltime.second= 0;
+ ltime.second_part=0;
+ ltime.neg=0;
+}
+
+bool Item_func_curdate::get_date(TIME *res,
+ bool fuzzy_date __attribute__((unused)))
+{
+ *res=ltime;
+ return 0;
+}
+
+void Item_func_curtime::fix_length_and_dec()
+{
+ struct tm tm_tmp,*start;
+ time_t query_start=current_thd->query_start();
+ decimals=0; max_length=8;
+ localtime_r(&query_start,&tm_tmp);
+ start=&tm_tmp;
+ value=(longlong) ((ulong) ((uint) start->tm_hour)*10000L+
+ (ulong) (((uint) start->tm_min)*100L+
+ (uint) start->tm_sec));
+ sprintf(buff,"%02d:%02d:%02d",
+ (int) start->tm_hour,
+ (int) start->tm_min,
+ (int) start->tm_sec);
+ buff_length=strlen(buff);
+}
+
+void Item_func_now::fix_length_and_dec()
+{
+ struct tm tm_tmp,*start;
+ time_t query_start=current_thd->query_start();
+ decimals=0; max_length=19;
+ localtime_r(&query_start,&tm_tmp);
+ start=&tm_tmp;
+ value=((longlong) ((ulong) ((uint) start->tm_year+1900)*10000L+
+ (((uint) start->tm_mon+1)*100+
+ (uint) start->tm_mday))*(longlong) 1000000L+
+ (longlong) ((ulong) ((uint) start->tm_hour)*10000L+
+ (ulong) (((uint) start->tm_min)*100L+
+ (uint) start->tm_sec)));
+ sprintf(buff,"%04d-%02d-%02d %02d:%02d:%02d",
+ ((int) (start->tm_year+1900)) % 10000,
+ (int) start->tm_mon+1,
+ (int) start->tm_mday,
+ (int) start->tm_hour,
+ (int) start->tm_min,
+ (int) start->tm_sec);
+ buff_length=strlen(buff);
+ /* For getdate */
+ ltime.year= start->tm_year+1900;
+ ltime.month= start->tm_mon+1;
+ ltime.day= start->tm_mday;
+ ltime.hour= start->tm_hour;
+ ltime.minute= start->tm_min;
+ ltime.second= start->tm_sec;
+ ltime.second_part=0;
+ ltime.neg=0;
+}
+
+bool Item_func_now::get_date(TIME *res,
+ bool fuzzy_date __attribute__((unused)))
+{
+ *res=ltime;
+ return 0;
+}
+
+
+bool Item_func_now::save_in_field(Field *to)
+{
+ to->set_notnull();
+ to->store_time(&ltime,TIMESTAMP_FULL);
+ return 0;
+}
+
+
+String *Item_func_sec_to_time::val_str(String *str)
+{
+ char buff[23];
+ const char *sign="";
+ longlong seconds=(longlong) args[0]->val_int();
+ if ((null_value=args[0]->null_value))
+ return (String*) 0;
+ if (seconds < 0)
+ {
+ seconds= -seconds;
+ sign= "-";
+ }
+ uint sec= (uint) (seconds % 3600);
+ sprintf(buff,"%s%02lu:%02u:%02u",sign,(long) (seconds/3600),
+ sec/60, sec % 60);
+ str->copy(buff,strlen(buff));
+ return str;
+}
+
+
+longlong Item_func_sec_to_time::val_int()
+{
+ longlong seconds=args[0]->val_int();
+ longlong sign=1;
+ if ((null_value=args[0]->null_value))
+ return 0;
+ if (seconds < 0)
+ {
+ seconds= -seconds;
+ sign= -1;
+ }
+ return sign*((seconds / 3600)*10000+((seconds/60) % 60)*100+ (seconds % 60));
+}
+
+
+void Item_func_date_format::fix_length_and_dec()
+{
+ decimals=0;
+ if (args[1]->type() == STRING_ITEM)
+ { // Optimize the normal case
+ fixed_length=1;
+ max_length=format_length(((Item_string*) args[1])->const_string());
+ }
+ else
+ {
+ fixed_length=0;
+ max_length=args[1]->max_length*10;
+ set_if_smaller(max_length,MAX_BLOB_WIDTH);
+ }
+ maybe_null=1; // If wrong date
+}
+
+
+uint Item_func_date_format::format_length(const String *format)
+{
+ uint size=0;
+ const char *ptr=format->ptr();
+ const char *end=ptr+format->length();
+
+ for (; ptr != end ; ptr++)
+ {
+ if (*ptr != '%' || ptr == end-1)
+ size++;
+ else
+ {
+ switch(*++ptr) {
+ case 'M': /* month, textual */
+ case 'W': /* day (of the week), textual */
+ size += 9;
+ break;
+ case 'D': /* day (of the month), numeric plus english suffix */
+ case 'Y': /* year, numeric, 4 digits */
+ case 'x': /* Year, used with 'v' */
+ case 'X': /* Year, used with 'v, where week starts with Monday' */
+ size += 4;
+ break;
+ case 'a': /* locale's abbreviated weekday name (Sun..Sat) */
+ case 'b': /* locale's abbreviated month name (Jan.Dec) */
+ case 'j': /* day of year (001..366) */
+ size += 3;
+ break;
+ case 'U': /* week (00..52) */
+ case 'u': /* week (00..52), where week starts with Monday */
+ case 'V': /* week 1..53 used with 'x' */
+ case 'v': /* week 1..53 used with 'x', where week starts with Monday */
+ case 'H': /* hour (00..23) */
+ case 'y': /* year, numeric, 2 digits */
+ case 'm': /* month, numeric */
+ case 'd': /* day (of the month), numeric */
+ case 'h': /* hour (01..12) */
+ case 'I': /* --||-- */
+ case 'i': /* minutes, numeric */
+ case 'k': /* hour ( 0..23) */
+ case 'l': /* hour ( 1..12) */
+ case 'p': /* locale's AM or PM */
+ case 'S': /* second (00..61) */
+ case 's': /* seconds, numeric */
+ case 'c': /* month (0..12) */
+ case 'e': /* day (0..31) */
+ size += 2;
+ break;
+ case 'r': /* time, 12-hour (hh:mm:ss [AP]M) */
+ size += 11;
+ break;
+ case 'T': /* time, 24-hour (hh:mm:ss) */
+ size += 8;
+ break;
+ case 'w': /* day (of the week), numeric */
+ case '%':
+ default:
+ size++;
+ break;
+ }
+ }
+ }
+ return size;
+}
+
+
+String *Item_func_date_format::val_str(String *str)
+{
+ String *format;
+ TIME l_time;
+ char intbuff[15];
+ uint size,weekday;
+
+ if (!date_or_time)
+ {
+ if (get_arg0_date(&l_time,1))
+ return 0;
+ }
+ else
+ {
+ String *res;
+ if (!(res=args[0]->val_str(str)))
+ {
+ null_value=1;
+ return 0;
+ }
+ if (str_to_time(res->ptr(),res->length(),&l_time))
+ {
+ null_value=1;
+ return 0;
+ }
+ l_time.year=l_time.month=l_time.day=0;
+ null_value=0;
+ }
+
+ if (!(format = args[1]->val_str(str)) || !format->length())
+ {
+ null_value=1;
+ return 0;
+ }
+
+ if (fixed_length)
+ size=max_length;
+ else
+ size=format_length(format);
+ if (format == str)
+ str=&str_value; // Save result here
+ if (str->alloc(size))
+ {
+ null_value=1;
+ return 0;
+ }
+ str->length(0);
+
+ /* Create the result string */
+ const char *ptr=format->ptr();
+ const char *end=ptr+format->length();
+ for ( ; ptr != end ; ptr++)
+ {
+ if (*ptr != '%' || ptr+1 == end)
+ str->append(*ptr);
+ else
+ {
+ switch (*++ptr) {
+ case 'M':
+ if(!l_time.month)
+ {
+ null_value=1;
+ return 0;
+ }
+ str->append(month_names[l_time.month-1]);
+ break;
+ case 'b':
+ if(!l_time.month)
+ {
+ null_value=1;
+ return 0;
+ }
+ str->append(month_names[l_time.month-1].ptr(),3);
+ break;
+ case 'W':
+ if(date_or_time)
+ {
+ null_value=1;
+ return 0;
+ }
+ weekday=calc_weekday(calc_daynr(l_time.year,l_time.month,l_time.day),0);
+ str->append(day_names[weekday]);
+ break;
+ case 'a':
+ if(date_or_time)
+ {
+ null_value=1;
+ return 0;
+ }
+ weekday=calc_weekday(calc_daynr(l_time.year,l_time.month,l_time.day),0);
+ str->append(day_names[weekday].ptr(),3);
+ break;
+ case 'D':
+ if(date_or_time)
+ {
+ null_value=1;
+ return 0;
+ }
+ sprintf(intbuff,"%d",l_time.day);
+ str->append(intbuff);
+ if (l_time.day >= 10 && l_time.day <= 19)
+ str->append("th");
+ else
+ {
+ switch (l_time.day %10)
+ {
+ case 1:
+ str->append("st");
+ break;
+ case 2:
+ str->append("nd");
+ break;
+ case 3:
+ str->append("rd");
+ break;
+ default:
+ str->append("th");
+ break;
+ }
+ }
+ break;
+ case 'Y':
+ sprintf(intbuff,"%04d",l_time.year);
+ str->append(intbuff);
+ break;
+ case 'y':
+ sprintf(intbuff,"%02d",l_time.year%100);
+ str->append(intbuff);
+ break;
+ case 'm':
+ sprintf(intbuff,"%02d",l_time.month);
+ str->append(intbuff);
+ break;
+ case 'c':
+ sprintf(intbuff,"%d",l_time.month);
+ str->append(intbuff);
+ break;
+ case 'd':
+ sprintf(intbuff,"%02d",l_time.day);
+ str->append(intbuff);
+ break;
+ case 'e':
+ sprintf(intbuff,"%d",l_time.day);
+ str->append(intbuff);
+ break;
+ case 'H':
+ sprintf(intbuff,"%02d",l_time.hour);
+ str->append(intbuff);
+ break;
+ case 'h':
+ case 'I':
+ sprintf(intbuff,"%02d", (l_time.hour+11)%12+1);
+ str->append(intbuff);
+ break;
+ case 'i': /* minutes */
+ sprintf(intbuff,"%02d",l_time.minute);
+ str->append(intbuff);
+ break;
+ case 'j':
+ if(date_or_time)
+ {
+ null_value=1;
+ return 0;
+ }
+ sprintf(intbuff,"%03d",
+ (int) (calc_daynr(l_time.year,l_time.month,l_time.day) -
+ calc_daynr(l_time.year,1,1)) + 1);
+ str->append(intbuff);
+ break;
+ case 'k':
+ sprintf(intbuff,"%d",l_time.hour);
+ str->append(intbuff);
+ break;
+ case 'l':
+ sprintf(intbuff,"%d", (l_time.hour+11)%12+1);
+ str->append(intbuff);
+ break;
+ case 'p':
+ str->append(l_time.hour < 12 ? "AM" : "PM");
+ break;
+ case 'r':
+ sprintf(intbuff,(l_time.hour < 12) ? "%02d:%02d:%02d AM" :
+ "%02d:%02d:%02d PM",(l_time.hour+11)%12+1,l_time.minute,
+ l_time.second);
+ str->append(intbuff);
+ break;
+ case 'S':
+ case 's':
+ sprintf(intbuff,"%02d",l_time.second);
+ str->append(intbuff);
+ break;
+ case 'T':
+ sprintf(intbuff,"%02d:%02d:%02d",l_time.hour,l_time.minute,l_time.second);
+ str->append(intbuff);
+ break;
+ case 'U':
+ case 'u':
+ {
+ uint year;
+ sprintf(intbuff,"%02d",calc_week(&l_time, 0, (*ptr) == 'U', &year));
+ str->append(intbuff);
+ }
+ break;
+ case 'v':
+ case 'V':
+ {
+ uint year;
+ sprintf(intbuff,"%02d",calc_week(&l_time, 1, (*ptr) == 'V', &year));
+ str->append(intbuff);
+ }
+ break;
+ case 'x':
+ case 'X':
+ {
+ uint year;
+ (void) calc_week(&l_time, 1, (*ptr) == 'X', &year);
+ sprintf(intbuff,"%04d",year);
+ str->append(intbuff);
+ }
+ break;
+ case 'w':
+ weekday=calc_weekday(calc_daynr(l_time.year,l_time.month,l_time.day),1);
+ sprintf(intbuff,"%01d",weekday);
+ str->append(intbuff);
+ break;
+ default:
+ str->append(*ptr);
+ break;
+ }
+ }
+ }
+ return str;
+}
+
+
+String *Item_func_from_unixtime::val_str(String *str)
+{
+ struct tm tm_tmp,*start;
+ time_t tmp=(time_t) args[0]->val_int();
+ if ((null_value=args[0]->null_value))
+ return 0;
+ localtime_r(&tmp,&tm_tmp);
+ start=&tm_tmp;
+ if (str->alloc(20))
+ return str; /* purecov: inspected */
+ sprintf((char*) str->ptr(),"%04d-%02d-%02d %02d:%02d:%02d",
+ (int) start->tm_year+1900,
+ (int) start->tm_mon+1,
+ (int) start->tm_mday,
+ (int) start->tm_hour,
+ (int) start->tm_min,
+ (int) start->tm_sec);
+ str->length(19);
+ return str;
+}
+
+
+longlong Item_func_from_unixtime::val_int()
+{
+ time_t tmp=(time_t) (ulong) args[0]->val_int();
+ if ((null_value=args[0]->null_value))
+ return 0;
+ struct tm tm_tmp,*start;
+ localtime_r(&tmp,&tm_tmp);
+ start= &tm_tmp;
+ return ((longlong) ((ulong) ((uint) start->tm_year+1900)*10000L+
+ (((uint) start->tm_mon+1)*100+
+ (uint) start->tm_mday))*LL(1000000)+
+ (longlong) ((ulong) ((uint) start->tm_hour)*10000L+
+ (ulong) (((uint) start->tm_min)*100L+
+ (uint) start->tm_sec)));
+}
+
+bool Item_func_from_unixtime::get_date(TIME *ltime,
+ bool fuzzy_date __attribute__((unused)))
+{
+ time_t tmp=(time_t) (ulong) args[0]->val_int();
+ if ((null_value=args[0]->null_value))
+ return 1;
+ struct tm tm_tmp,*start;
+ localtime_r(&tmp,&tm_tmp);
+ start= &tm_tmp;
+ ltime->year= start->tm_year+1900;
+ ltime->month= start->tm_mon+1;
+ ltime->day= start->tm_mday;
+ ltime->hour= start->tm_hour;
+ ltime->minute=start->tm_min;
+ ltime->second=start->tm_sec;
+ ltime->second_part=0;
+ ltime->neg=0;
+ return 0;
+}
+
+ /* Here arg[1] is a Item_interval object */
+
+bool Item_date_add_interval::get_date(TIME *ltime, bool fuzzy_date)
+{
+ long period,sign;
+ INTERVAL interval;
+
+ if (args[0]->get_date(ltime,0) ||
+ get_interval_value(args[1],int_type,&value,&interval))
+ goto null_date;
+ sign= (interval.neg ? -1 : 1);
+ if (date_sub_interval)
+ sign = -sign;
+
+ null_value=0;
+ switch (int_type) {
+ case INTERVAL_SECOND:
+ case INTERVAL_MINUTE:
+ case INTERVAL_HOUR:
+ case INTERVAL_MINUTE_SECOND:
+ case INTERVAL_HOUR_SECOND:
+ case INTERVAL_HOUR_MINUTE:
+ case INTERVAL_DAY_SECOND:
+ case INTERVAL_DAY_MINUTE:
+ case INTERVAL_DAY_HOUR:
+ long sec,days,daynr;
+ ltime->time_type=TIMESTAMP_FULL; // Return full date
+
+ sec=((ltime->day-1)*3600*24L+ltime->hour*3600+ltime->minute*60+
+ ltime->second +
+ sign*(interval.day*3600*24L +
+ interval.hour*3600+interval.minute*60+interval.second));
+ days=sec/(3600*24L); sec=sec-days*3600*24L;
+ if (sec < 0)
+ {
+ days--;
+ sec+=3600*24L;
+ }
+ ltime->second=sec % 60;
+ ltime->minute=sec/60 % 60;
+ ltime->hour=sec/3600;
+ daynr= calc_daynr(ltime->year,ltime->month,1) + days;
+ get_date_from_daynr(daynr,&ltime->year,&ltime->month,&ltime->day);
+ if (daynr < 0 || daynr >= 3652424) // Day number from year 0 to 9999-12-31
+ goto null_date;
+ break;
+ case INTERVAL_DAY:
+ period= calc_daynr(ltime->year,ltime->month,ltime->day) +
+ sign*interval.day;
+ if (period < 0 || period >= 3652424) // Daynumber from year 0 to 9999-12-31
+ goto null_date;
+ get_date_from_daynr((long) period,&ltime->year,&ltime->month,&ltime->day);
+ break;
+ case INTERVAL_YEAR:
+ ltime->year += sign*interval.year;
+ if ((int) ltime->year < 0 || ltime->year >= 10000L)
+ goto null_date;
+ if (ltime->month == 2 && ltime->day == 29 &&
+ calc_days_in_year(ltime->year) != 366)
+ ltime->day=28; // Was leap-year
+ break;
+ case INTERVAL_YEAR_MONTH:
+ case INTERVAL_MONTH:
+ period= (ltime->year*12 + sign*interval.year*12 +
+ ltime->month-1 + sign*interval.month);
+ if (period < 0 || period >= 120000L)
+ goto null_date;
+ ltime->year= (uint) (period / 12);
+ ltime->month= (uint) (period % 12L)+1;
+ /* Adjust day if the new month doesn't have enough days */
+ if (ltime->day > days_in_month[ltime->month-1])
+ {
+ ltime->day = days_in_month[ltime->month-1];
+ if (ltime->month == 2 && calc_days_in_year(ltime->year) == 366)
+ ltime->day++; // Leap-year
+ }
+ break;
+ default:
+ goto null_date;
+ }
+ return 0; // Ok
+
+ null_date:
+ return (null_value=1);
+}
+
+
+String *Item_date_add_interval::val_str(String *str)
+{
+ TIME ltime;
+
+ if (Item_date_add_interval::get_date(&ltime,0))
+ return 0;
+ if (ltime.time_type == TIMESTAMP_DATE)
+ {
+ if (str->alloc(11))
+ goto null_date;
+ sprintf((char*) str->ptr(),"%04d-%02d-%02d",
+ ltime.year,ltime.month,ltime.day);
+ str->length(10);
+ }
+ else
+ {
+ if (str->alloc(20))
+ goto null_date;
+ sprintf((char*) str->ptr(),"%04d-%02d-%02d %02d:%02d:%02d",
+ ltime.year,ltime.month,ltime.day,
+ ltime.hour,ltime.minute,ltime.second);
+ str->length(19);
+ }
+ return str;
+
+ null_date:
+ null_value=1;
+ return 0;
+}
+
+longlong Item_date_add_interval::val_int()
+{
+ TIME ltime;
+ if (Item_date_add_interval::get_date(&ltime,0))
+ return (longlong) 0;
+ return ((longlong) (((ulong) ltime.year)*10000L+
+ (((uint) ltime.month)*100+
+ (uint) ltime.day))*(longlong) 1000000L+
+ (longlong) ((ulong) ((uint) ltime.hour)*10000L+
+ (ulong) (((uint)ltime.minute)*100L+
+ (uint) ltime.second)));
+}
+
+void Item_extract::fix_length_and_dec()
+{
+ value.alloc(32); // alloc buffer
+
+ maybe_null=1; // If wrong date
+ switch (int_type) {
+ case INTERVAL_YEAR: max_length=4; date_value=1; break;
+ case INTERVAL_YEAR_MONTH: max_length=6; date_value=1; break;
+ case INTERVAL_MONTH: max_length=2; date_value=1; break;
+ case INTERVAL_DAY: max_length=2; date_value=1; break;
+ case INTERVAL_DAY_HOUR: max_length=9; date_value=0; break;
+ case INTERVAL_DAY_MINUTE: max_length=11; date_value=0; break;
+ case INTERVAL_DAY_SECOND: max_length=13; date_value=0; break;
+ case INTERVAL_HOUR: max_length=2; date_value=0; break;
+ case INTERVAL_HOUR_MINUTE: max_length=4; date_value=0; break;
+ case INTERVAL_HOUR_SECOND: max_length=6; date_value=0; break;
+ case INTERVAL_MINUTE: max_length=2; date_value=0; break;
+ case INTERVAL_MINUTE_SECOND: max_length=4; date_value=0; break;
+ case INTERVAL_SECOND: max_length=2; date_value=0; break;
+ }
+}
+
+
+longlong Item_extract::val_int()
+{
+ TIME ltime;
+ long neg;
+ if (date_value)
+ {
+ if (get_arg0_date(&ltime,1))
+ return 0;
+ neg=1;
+ }
+ else
+ {
+ String *res= args[0]->val_str(&value);
+ if (!res || str_to_time(res->ptr(),res->length(),&ltime))
+ {
+ null_value=1;
+ return 0;
+ }
+ neg= ltime.neg ? -1 : 1;
+ null_value=0;
+ }
+
+ switch (int_type) {
+ case INTERVAL_YEAR: return ltime.year;
+ case INTERVAL_YEAR_MONTH: return ltime.year*100L+ltime.month;
+ case INTERVAL_MONTH: return ltime.month;
+ case INTERVAL_DAY: return ltime.day;
+ case INTERVAL_DAY_HOUR: return (long) (ltime.day*100L+ltime.hour)*neg;
+ case INTERVAL_DAY_MINUTE: return (long) (ltime.day*10000L+
+ ltime.hour*100L+
+ ltime.minute)*neg;
+ case INTERVAL_DAY_SECOND: return ((longlong) ltime.day*1000000L+
+ (longlong) (ltime.hour*10000L+
+ ltime.minute*100+
+ ltime.second))*neg;
+ case INTERVAL_HOUR: return (long) ltime.hour*neg;
+ case INTERVAL_HOUR_MINUTE: return (long) (ltime.hour*100+ltime.minute)*neg;
+ case INTERVAL_HOUR_SECOND: return (long) (ltime.hour*10000+ltime.minute*100+
+ ltime.second)*neg;
+ case INTERVAL_MINUTE: return (long) ltime.minute*neg;
+ case INTERVAL_MINUTE_SECOND: return (long) (ltime.minute*100+ltime.second)*neg;
+ case INTERVAL_SECOND: return (long) ltime.second*neg;
+ }
+ return 0; // Impossible
+}
diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h
new file mode 100644
index 00000000000..1343cdad390
--- /dev/null
+++ b/sql/item_timefunc.h
@@ -0,0 +1,370 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 items used by mysql */
+
+#ifdef __GNUC__
+#pragma interface /* gcc class implementation */
+#endif
+
+class Item_func_period_add :public Item_int_func
+{
+public:
+ Item_func_period_add(Item *a,Item *b) :Item_int_func(a,b) {}
+ longlong val_int();
+ const char *func_name() const { return "period_add"; }
+ void fix_length_and_dec() { max_length=6; }
+};
+
+
+class Item_func_period_diff :public Item_int_func
+{
+public:
+ Item_func_period_diff(Item *a,Item *b) :Item_int_func(a,b) {}
+ longlong val_int();
+ const char *func_name() const { return "period_diff"; }
+ void fix_length_and_dec() { decimals=0; max_length=6; }
+};
+
+
+class Item_func_to_days :public Item_int_func
+{
+public:
+ Item_func_to_days(Item *a) :Item_int_func(a) {}
+ longlong val_int();
+ const char *func_name() const { return "to_days"; }
+ void fix_length_and_dec() { decimals=0; max_length=6; }
+};
+
+
+class Item_func_dayofmonth :public Item_int_func
+{
+public:
+ Item_func_dayofmonth(Item *a) :Item_int_func(a) {}
+ longlong val_int();
+ const char *func_name() const { return "dayofmonth"; }
+ void fix_length_and_dec() { decimals=0; max_length=2; maybe_null=1; }
+};
+
+
+class Item_func_month :public Item_func
+{
+public:
+ Item_func_month(Item *a) :Item_func(a) {}
+ longlong val_int();
+ double val() { return (double) Item_func_month::val_int(); }
+ String *val_str(String *str) { str->set(val_int()); return null_value ? 0 : str;}
+ const char *func_name() const { return "month"; }
+ enum Item_result result_type () const { return INT_RESULT; }
+ void fix_length_and_dec() { decimals=0; max_length=2; maybe_null=1; }
+};
+
+class Item_func_monthname :public Item_func_month
+{
+public:
+ Item_func_monthname(Item *a) :Item_func_month(a) {}
+ const char *func_name() const { return "monthname"; }
+ String *val_str(String *str);
+ enum Item_result result_type () const { return STRING_RESULT; }
+ void fix_length_and_dec() { decimals=0; max_length=10; maybe_null=1; }
+};
+
+
+class Item_func_dayofyear :public Item_int_func
+{
+public:
+ Item_func_dayofyear(Item *a) :Item_int_func(a) {}
+ longlong val_int();
+ const char *func_name() const { return "dayofyear"; }
+ void fix_length_and_dec() { decimals=0; max_length=3; maybe_null=1; }
+};
+
+
+class Item_func_hour :public Item_int_func
+{
+public:
+ Item_func_hour(Item *a) :Item_int_func(a) {}
+ longlong val_int();
+ const char *func_name() const { return "hour"; }
+ void fix_length_and_dec() { decimals=0; max_length=2; maybe_null=1; }
+};
+
+
+class Item_func_minute :public Item_int_func
+{
+public:
+ Item_func_minute(Item *a) :Item_int_func(a) {}
+ longlong val_int();
+ const char *func_name() const { return "minute"; }
+ void fix_length_and_dec() { decimals=0; max_length=2; maybe_null=1; }
+};
+
+
+class Item_func_quarter :public Item_int_func
+{
+public:
+ Item_func_quarter(Item *a) :Item_int_func(a) {}
+ longlong val_int();
+ const char *func_name() const { return "quarter"; }
+ void fix_length_and_dec() { decimals=0; max_length=1; maybe_null=1; }
+};
+
+
+class Item_func_second :public Item_int_func
+{
+public:
+ Item_func_second(Item *a) :Item_int_func(a) {}
+ longlong val_int();
+ const char *func_name() const { return "second"; }
+ void fix_length_and_dec() { decimals=0; max_length=2; maybe_null=1; }
+};
+
+
+class Item_func_week :public Item_int_func
+{
+public:
+ Item_func_week(Item *a,Item *b) :Item_int_func(a,b) {}
+ longlong val_int();
+ const char *func_name() const { return "week"; }
+ void fix_length_and_dec() { decimals=0; max_length=2; maybe_null=1; }
+};
+
+class Item_func_yearweek :public Item_int_func
+{
+public:
+ Item_func_yearweek(Item *a,Item *b) :Item_int_func(a,b) {}
+ longlong val_int();
+ const char *func_name() const { return "yearweek"; }
+ void fix_length_and_dec() { decimals=0; max_length=6; maybe_null=1; }
+};
+
+
+class Item_func_year :public Item_int_func
+{
+public:
+ Item_func_year(Item *a) :Item_int_func(a) {}
+ longlong val_int();
+ const char *func_name() const { return "year"; }
+ void fix_length_and_dec() { decimals=0; max_length=4; maybe_null=1; }
+};
+
+
+class Item_func_weekday :public Item_func
+{
+ bool odbc_type;
+public:
+ Item_func_weekday(Item *a,bool type_arg)
+ :Item_func(a), odbc_type(type_arg) {}
+ longlong val_int();
+ double val() { return (double) val_int(); }
+ String *val_str(String *str) { str->set(val_int()); return null_value ? 0 : str;}
+ const char *func_name() const { return "weekday"; }
+ enum Item_result result_type () const { return INT_RESULT; }
+ void fix_length_and_dec() { decimals=0; max_length=1; maybe_null=1; }
+};
+
+class Item_func_dayname :public Item_func_weekday
+{
+ public:
+ Item_func_dayname(Item *a) :Item_func_weekday(a,0) {}
+ const char *func_name() const { return "dayname"; }
+ String *val_str(String *str);
+ enum Item_result result_type () const { return STRING_RESULT; }
+ void fix_length_and_dec() { decimals=0; max_length=9; maybe_null=1; }
+};
+
+
+class Item_func_unix_timestamp :public Item_int_func
+{
+ String value;
+public:
+ Item_func_unix_timestamp() :Item_int_func() {}
+ Item_func_unix_timestamp(Item *a) :Item_int_func(a) {}
+ longlong val_int();
+ const char *func_name() const { return "timestamp"; }
+ void fix_length_and_dec()
+ {
+ decimals=0; max_length=10;
+ }
+};
+
+
+class Item_func_time_to_sec :public Item_int_func
+{
+public:
+ Item_func_time_to_sec(Item *item) :Item_int_func(item) {}
+ longlong val_int();
+ const char *func_name() const { return "time_to_sec"; }
+ void fix_length_and_dec()
+ {
+ decimals=0; max_length=10;
+ }
+};
+
+
+/* This can't be a Item_str_func, because the val() functions are special */
+
+class Item_date :public Item_func
+{
+public:
+ Item_date() :Item_func() {}
+ Item_date(Item *a) :Item_func(a) {}
+ enum Item_result result_type () const { return STRING_RESULT; }
+ String *val_str(String *str);
+ double val() { return (double) val_int(); }
+ const char *func_name() const { return "date"; }
+ void fix_length_and_dec() { decimals=0; max_length=10; }
+ bool save_in_field(Field *to);
+};
+
+
+class Item_func_curtime :public Item_func
+{
+ longlong value;
+ char buff[9];
+ uint buff_length;
+public:
+ Item_func_curtime() :Item_func() {}
+ Item_func_curtime(Item *a) :Item_func(a) {}
+ enum Item_result result_type () const { return STRING_RESULT; }
+ double val() { return (double) value; }
+ longlong val_int() { return value; }
+ String *val_str(String *str)
+ { str_value.set(buff,buff_length); return &str_value; }
+ const char *func_name() const { return "curtime"; }
+ void fix_length_and_dec();
+};
+
+
+class Item_func_curdate :public Item_date
+{
+ longlong value;
+ TIME ltime;
+public:
+ Item_func_curdate() :Item_date() {}
+ longlong val_int() { return (value) ; }
+ const char *func_name() const { return "curdate"; }
+ void fix_length_and_dec(); /* Retrieves curtime */
+ bool get_date(TIME *res,bool fuzzy_date);
+};
+
+
+class Item_func_now :public Item_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) {}
+ enum Item_result result_type () const { return STRING_RESULT; }
+ double val() { return (double) value; }
+ longlong val_int() { return value; }
+ bool save_in_field(Field *to);
+ String *val_str(String *str)
+ { str_value.set(buff,buff_length); return &str_value; }
+ const char *func_name() const { return "now"; }
+ void fix_length_and_dec();
+ bool get_date(TIME *res,bool fuzzy_date);
+};
+
+
+class Item_func_from_days :public Item_date
+{
+public:
+ Item_func_from_days(Item *a) :Item_date(a) {}
+ longlong val_int();
+ const char *func_name() const { return "from_days"; }
+};
+
+
+class Item_func_date_format :public Item_str_func
+{
+ int fixed_length;
+ const bool date_or_time;
+public:
+ Item_func_date_format(Item *a,Item *b,bool date_or_time_arg)
+ :Item_str_func(a,b),date_or_time(date_or_time_arg) {}
+ String *val_str(String *str);
+ const char *func_name() const { return "date_format"; }
+ void fix_length_and_dec();
+ uint format_length(const String *format);
+};
+
+
+class Item_func_from_unixtime :public Item_func
+{
+ public:
+ Item_func_from_unixtime(Item *a) :Item_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; }
+ bool get_date(TIME *res,bool fuzzy_date);
+};
+
+
+class Item_func_sec_to_time :public Item_str_func
+{
+public:
+ Item_func_sec_to_time(Item *item) :Item_str_func(item) {}
+ double val() { return (double) Item_func_sec_to_time::val_int(); }
+ longlong val_int();
+ String *val_str(String *);
+ void fix_length_and_dec() { maybe_null=1; max_length=13; }
+ const char *func_name() const { return "sec_to_time"; }
+};
+
+enum interval_type { INTERVAL_YEAR, INTERVAL_MONTH, INTERVAL_DAY,
+ INTERVAL_HOUR, INTERVAL_MINUTE, INTERVAL_SECOND,
+ INTERVAL_YEAR_MONTH, INTERVAL_DAY_HOUR,
+ INTERVAL_DAY_MINUTE, INTERVAL_DAY_SECOND,
+ INTERVAL_HOUR_MINUTE, INTERVAL_HOUR_SECOND,
+ INTERVAL_MINUTE_SECOND};
+
+class Item_date_add_interval :public Item_str_func
+{
+ const interval_type int_type;
+ String value;
+ const bool date_sub_interval;
+
+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) {}
+ 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);}
+ double val() { return (double) val_int(); }
+ longlong val_int();
+ bool get_date(TIME *res,bool fuzzy_date);
+};
+
+class Item_extract :public Item_int_func
+{
+ const interval_type int_type;
+ String value;
+ bool date_value;
+ public:
+ Item_extract(interval_type type_arg, Item *a)
+ :Item_int_func(a), int_type(type_arg) {}
+ longlong val_int();
+ const char *func_name() const { return "extract"; }
+ void fix_length_and_dec();
+};
diff --git a/sql/item_uniq.cc b/sql/item_uniq.cc
new file mode 100755
index 00000000000..80ed6433fd8
--- /dev/null
+++ b/sql/item_uniq.cc
@@ -0,0 +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 */
+
+/* Compability file */
+#ifdef __GNUC__
+#pragma implementation
+#endif
+
+#include "mysql_priv.h"
diff --git a/sql/item_uniq.h b/sql/item_uniq.h
new file mode 100755
index 00000000000..ff11222e2ee
--- /dev/null
+++ b/sql/item_uniq.h
@@ -0,0 +1,46 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* Compability file ; This file only contains dummy functions */
+
+#ifdef __GNUC__
+#pragma interface
+#endif
+
+#include <queues.h>
+
+class Item_func_unique_users :public Item_real_func
+{
+public:
+ Item_func_unique_users(Item *name_arg,int start,int end,List<Item> &list)
+ :Item_real_func(list) {}
+ double val() { return 0.0; }
+ void fix_length_and_dec() { decimals=0; max_length=6; }
+};
+
+class Item_sum_unique_users :public Item_sum_num
+{
+public:
+ Item_sum_unique_users(Item *name_arg,int start,int end,Item *item_arg)
+ :Item_sum_num(item_arg) {}
+ double val() { return 0.0; }
+ enum Sumfunctype sum_func () const {return UNIQUE_USERS_FUNC;}
+ void reset() {}
+ bool add() { return 0; }
+ void reset_field() {}
+ void update_field(int offset) {}
+ bool fix_fields(THD *thd,struct st_table_list *tlist) { return 0;}
+};
diff --git a/sql/key.cc b/sql/key.cc
new file mode 100644
index 00000000000..df3f0fe25d5
--- /dev/null
+++ b/sql/key.cc
@@ -0,0 +1,266 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+
+/* Functions to handle keys and fields in forms */
+
+#include "mysql_priv.h"
+
+ /*
+ ** Search after with key field is. If no key starts with field test
+ ** if field is part of some key.
+ **
+ ** returns number of key. keylength is set to length of key before
+ ** (not including) field
+ ** Used when calculating key for NEXT_NUMBER
+ */
+
+int find_ref_key(TABLE *table,Field *field, uint *key_length)
+{
+ reg2 int i;
+ reg3 KEY *key_info;
+ uint fieldpos;
+
+ fieldpos= field->offset();
+
+ /* Test if some key starts as fieldpos */
+
+ for (i=0, key_info=table->key_info ; i < (int) table->keys ; i++, key_info++)
+ {
+ if (key_info->key_part[0].offset == fieldpos)
+ { /* Found key. Calc keylength */
+ *key_length=0;
+ return(i); /* Use this key */
+ }
+ }
+ /* Test if some key contains fieldpos */
+
+ for (i=0, key_info=table->key_info ; i < (int) table->keys ; i++, key_info++)
+ {
+ uint j;
+ KEY_PART_INFO *key_part;
+ *key_length=0;
+ for (j=0, key_part=key_info->key_part ;
+ j < key_info->key_parts ;
+ j++, key_part++)
+ {
+ if (key_part->offset == fieldpos)
+ return(i); /* Use this key */
+ *key_length+=key_part->length;
+ }
+ }
+ return(-1); /* No key is ok */
+}
+
+
+ /* Copy a key from record to some buffer */
+ /* if length == 0 then copy hole key */
+
+void key_copy(byte *key,TABLE *table,uint idx,uint key_length)
+{
+ uint length;
+ KEY *key_info=table->key_info+idx;
+ KEY_PART_INFO *key_part;
+
+ if (key_length == 0)
+ key_length=key_info->key_length+key_info->extra_length;
+ for (key_part=key_info->key_part;
+ (int) key_length > 0 ;
+ key_part++)
+ {
+ if (key_part->null_bit)
+ {
+ *key++= test(table->record[0][key_part->null_offset] &
+ key_part->null_bit);
+ key_length--;
+ }
+ if (key_part->key_part_flag & HA_BLOB_PART)
+ {
+ char *pos;
+ ulong blob_length=((Field_blob*) key_part->field)->get_length();
+ key_length-=2;
+ ((Field_blob*) key_part->field)->get_ptr(&pos);
+ length=min(key_length,key_part->length);
+ set_if_smaller(blob_length,length);
+ int2store(key,(uint) blob_length);
+ key+=2; // Skipp length info
+ memcpy(key,pos,blob_length);
+ }
+ else
+ {
+ length=min(key_length,key_part->length);
+ memcpy(key,table->record[0]+key_part->offset,(size_t) length);
+ }
+ key+=length;
+ key_length-=length;
+ }
+} /* key_copy */
+
+
+ /* restore a key from some buffer to record */
+
+void key_restore(TABLE *table,byte *key,uint idx,uint key_length)
+{
+ uint length;
+ KEY *key_info=table->key_info+idx;
+ KEY_PART_INFO *key_part;
+
+ if (key_length == 0)
+ {
+ if (idx == (uint) -1)
+ return;
+ key_length=key_info->key_length+key_info->extra_length;
+ }
+ for (key_part=key_info->key_part;
+ (int) key_length > 0 ;
+ key_part++)
+ {
+ if (key_part->null_bit)
+ {
+ if (*key++)
+ table->record[0][key_part->null_offset]|= key_part->null_bit;
+ else
+ table->record[0][key_part->null_offset]&= ~key_part->null_bit;
+ key_length--;
+ }
+ if (key_part->key_part_flag & HA_BLOB_PART)
+ {
+ uint blob_length=uint2korr(key);
+ key+=2;
+ key_length-=2;
+ ((Field_blob*) key_part->field)->set_ptr((ulong) blob_length,
+ (char*) key);
+ length=key_part->length;
+ }
+ else
+ {
+ length=min(key_length,key_part->length);
+ memcpy(table->record[0]+key_part->offset,key,(size_t) length);
+ }
+ key+=length;
+ key_length-=length;
+ }
+} /* key_restore */
+
+
+ /* Compare if a key has changed */
+
+int key_cmp(TABLE *table,const byte *key,uint idx,uint key_length)
+{
+ uint length;
+ KEY_PART_INFO *key_part;
+
+ for (key_part=table->key_info[idx].key_part;
+ (int) key_length > 0;
+ key_part++, key+=length, key_length-=length)
+ {
+ if (key_part->null_bit)
+ {
+ key_length--;
+ if (*key != test(table->record[0][key_part->null_offset] &
+ key_part->null_bit))
+ return 1;
+ if (*key)
+ {
+ length=key_part->store_length;
+ continue;
+ }
+ key++;
+ }
+ if (key_part->key_part_flag & (HA_BLOB_PART | HA_VAR_LENGTH))
+ {
+ if (key_part->field->key_cmp(key, key_part->length+2))
+ return 1;
+ length=key_part->length+2;
+ }
+ else
+ {
+ length=min(key_length,key_part->length);
+ if (!(key_part->key_type & (FIELDFLAG_NUMBER+FIELDFLAG_BINARY+
+ FIELDFLAG_PACK)))
+ {
+ if (my_sortcmp((char*) key,(char*) table->record[0]+key_part->offset,
+ length))
+ return 1;
+ }
+ else if (memcmp(key,table->record[0]+key_part->offset,length))
+ return 1;
+ }
+ }
+ return 0;
+}
+
+ /* unpack key-fields from record to some buffer */
+ /* This is used to get a good error message */
+
+void key_unpack(String *to,TABLE *table,uint idx)
+{
+ KEY_PART_INFO *key_part,*key_part_end;
+ Field *field;
+ String tmp;
+ DBUG_ENTER("key_unpack");
+
+ to->length(0);
+ for (key_part=table->key_info[idx].key_part,key_part_end=key_part+
+ table->key_info[idx].key_parts ;
+ key_part < key_part_end;
+ key_part++)
+ {
+ if (to->length())
+ to->append('-');
+ if (key_part->null_bit)
+ {
+ if (table->record[0][key_part->null_offset] & key_part->null_bit)
+ {
+ to->append("NULL");
+ continue;
+ }
+ }
+ if ((field=key_part->field))
+ {
+ field->val_str(&tmp,&tmp);
+ if (key_part->length < field->pack_length())
+ tmp.length(min(tmp.length(),key_part->length));
+ to->append(tmp);
+ }
+ else
+ to->append("???");
+ }
+ DBUG_VOID_RETURN;
+}
+
+
+/* Return 1 if any field in a list is part of key */
+
+bool check_if_key_used(TABLE *table, uint idx, List<Item> &fields)
+{
+ List_iterator<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 ;
+ key_part < key_part_end;
+ key_part++)
+ {
+ Item_field *field;
+ f.rewind();
+ while ((field=(Item_field*) f++))
+ {
+ if (key_part->field == field->field)
+ return 1;
+ }
+ }
+ return 0;
+}
diff --git a/sql/lex.h b/sql/lex.h
new file mode 100644
index 00000000000..75c11a52273
--- /dev/null
+++ b/sql/lex.h
@@ -0,0 +1,446 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 all reserved words and functions */
+
+#include "lex_symbol.h"
+
+/* We don't want to include sql_yacc.h into gen_lex_hash */
+
+#ifdef NO_YACC_SYMBOLS
+#define SYM(A) 0
+#define CREATE_FUNC(A) 0
+#else
+#define SYM(A) A
+#define CREATE_FUNC(A) (void*) (A)
+#endif
+
+/*
+** Symbols are breaked in to separated arrays to allow fieldnames with
+** same name as functions
+** Theese are kept sorted for human lookup (the symbols are hashed)
+*/
+
+static SYMBOL symbols[] = {
+ { "&&", SYM(AND),0,0},
+ { "<", SYM(LT),0,0},
+ { "<=", SYM(LE),0,0},
+ { "<>", SYM(NE),0,0},
+ { "!=", SYM(NE),0,0},
+ { "=", SYM(EQ),0,0},
+ { ">", SYM(GT_SYM),0,0},
+ { ">=", SYM(GE),0,0},
+ { "<<", SYM(SHIFT_LEFT),0,0},
+ { ">>", SYM(SHIFT_RIGHT),0,0},
+ { "<=>", SYM(EQUAL_SYM),0,0},
+ { "ACTION", SYM(ACTION),0,0},
+ { "ADD", SYM(ADD),0,0},
+ { "AGGREGATE", SYM(AGGREGATE_SYM),0,0},
+ { "ALL", SYM(ALL),0,0},
+ { "ALTER", SYM(ALTER),0,0},
+ { "AFTER", SYM(AFTER_SYM),0,0},
+ { "AGAINST", SYM(AGAINST),0,0},
+ { "ANALYZE", SYM(ANALYZE_SYM),0,0},
+ { "AND", SYM(AND),0,0},
+ { "AS", SYM(AS),0,0},
+ { "ASC", SYM(ASC),0,0},
+ { "AVG", SYM(AVG_SYM),0,0},
+ { "AVG_ROW_LENGTH", SYM(AVG_ROW_LENGTH),0,0},
+ { "AUTO_INCREMENT", SYM(AUTO_INC),0,0},
+ { "AUTOCOMMIT", SYM(AUTOCOMMIT),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},
+ { "BLOB", SYM(BLOB_SYM),0,0},
+ { "BOOL", SYM(BOOL_SYM),0,0},
+ { "BOTH", SYM(BOTH),0,0},
+ { "BY", SYM(BY),0,0},
+ { "CASCADE", SYM(CASCADE),0,0},
+ { "CASE", SYM(CASE_SYM),0,0},
+ { "CHAR", SYM(CHAR_SYM),0,0},
+ { "CHARACTER", SYM(CHAR_SYM),0,0},
+ { "CHANGE", SYM(CHANGE),0,0},
+ { "CHECK", SYM(CHECK_SYM),0,0},
+ { "CHECKSUM", SYM(CHECKSUM_SYM),0,0},
+ { "COLLECTION", SYM(COLLECTION),0,0},
+ { "COLUMN", SYM(COLUMN_SYM),0,0},
+ { "COLUMNS", SYM(COLUMNS),0,0},
+ { "COMMENT", SYM(COMMENT_SYM),0,0},
+ { "COMMIT", SYM(COMMIT_SYM),0,0},
+ { "COMPRESSED", SYM(COMPRESSED_SYM),0,0},
+ { "CONSTRAINT", SYM(CONSTRAINT),0,0},
+ { "CREATE", SYM(CREATE),0,0},
+ { "CROSS", SYM(CROSS),0,0},
+ { "CURRENT_DATE", SYM(CURDATE),0,0},
+ { "CURRENT_TIME", SYM(CURTIME),0,0},
+ { "CURRENT_TIMESTAMP", SYM(NOW_SYM),0,0},
+ { "DATA", SYM(DATA_SYM),0,0},
+ { "DATABASE", SYM(DATABASE),0,0},
+ { "DATABASES", SYM(DATABASES),0,0},
+ { "DATE", SYM(DATE_SYM),0,0},
+ { "DATETIME", SYM(DATETIME),0,0},
+ { "DAY", SYM(DAY_SYM),0,0},
+ { "DAY_HOUR", SYM(DAY_HOUR_SYM),0,0},
+ { "DAY_MINUTE", SYM(DAY_MINUTE_SYM),0,0},
+ { "DAY_SECOND", SYM(DAY_SECOND_SYM),0,0},
+ { "DEC", SYM(DECIMAL_SYM),0,0},
+ { "DECIMAL", SYM(DECIMAL_SYM),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},
+ { "DESC", SYM(DESC),0,0},
+ { "DESCRIBE", SYM(DESCRIBE),0,0},
+ { "DISTINCT", SYM(DISTINCT),0,0},
+ { "DISTINCTROW", SYM(DISTINCT),0,0}, /* Access likes this */
+ { "DOUBLE", SYM(DOUBLE_SYM),0,0},
+ { "DROP", SYM(DROP),0,0},
+ { "DUMPFILE", SYM(DUMPFILE),0,0},
+ { "DYNAMIC", SYM(DYNAMIC_SYM),0,0},
+ { "END", SYM(END),0,0},
+ { "ELSE", SYM(ELSE),0,0},
+ { "ESCAPE", SYM(ESCAPE_SYM),0,0},
+ { "ESCAPED", SYM(ESCAPED),0,0},
+ { "ENCLOSED", SYM(ENCLOSED),0,0},
+ { "ENUM", SYM(ENUM),0,0},
+ { "EXPLAIN", SYM(DESCRIBE),0,0},
+ { "EXISTS", SYM(EXISTS),0,0},
+ { "EXTENDED", SYM(EXTENDED_SYM),0,0},
+ { "FIELDS", SYM(COLUMNS),0,0},
+ { "FILE", SYM(FILE_SYM),0,0},
+ { "FIRST", SYM(FIRST_SYM),0,0},
+ { "FIXED", SYM(FIXED_SYM),0,0},
+ { "FLOAT", SYM(FLOAT_SYM),0,0},
+ { "FLOAT4", SYM(FLOAT_SYM),0,0},
+ { "FLOAT8", SYM(DOUBLE_SYM),0,0},
+ { "FLUSH", SYM(FLUSH_SYM),0,0},
+ { "FOREIGN", SYM(FOREIGN),0,0},
+ { "RAID_TYPE", SYM(RAID_TYPE),0,0},
+ { "RAID_CHUNKS", SYM(RAID_CHUNKS),0,0},
+ { "RAID_CHUNKSIZE", SYM(RAID_CHUNKSIZE),0,0},
+ { "ROW_FORMAT", SYM(ROW_FORMAT_SYM),0,0},
+ { "FROM", SYM(FROM),0,0},
+ { "FOR", SYM(FOR_SYM),0,0},
+ { "FULL", SYM(FULL),0,0},
+ { "FUNCTION", SYM(UDF_SYM),0,0},
+ { "GRANT", SYM(GRANT),0,0},
+ { "GRANTS", SYM(GRANTS),0,0},
+ { "GROUP", SYM(GROUP),0,0},
+ { "HAVING", SYM(HAVING),0,0},
+ { "HEAP", SYM(HEAP_SYM),0,0},
+ { "HIGH_PRIORITY", SYM(HIGH_PRIORITY),0,0},
+ { "HOUR", SYM(HOUR_SYM),0,0},
+ { "HOUR_MINUTE", SYM(HOUR_MINUTE_SYM),0,0},
+ { "HOUR_SECOND", SYM(HOUR_SECOND_SYM),0,0},
+ { "HOSTS", SYM(HOSTS_SYM),0,0},
+ { "IDENTIFIED", SYM(IDENTIFIED_SYM),0,0},
+ { "IGNORE", SYM(IGNORE_SYM),0,0},
+ { "IN", SYM(IN_SYM),0,0},
+ { "INDEX", SYM(INDEX),0,0},
+ { "INFILE", SYM(INFILE),0,0},
+ { "INNER", SYM(INNER_SYM),0,0},
+ { "INSERT", SYM(INSERT),0,0},
+ { "INSERT_ID", SYM(INSERT_ID),0,0},
+ { "INT", SYM(INT_SYM),0,0},
+ { "INTEGER", SYM(INT_SYM),0,0},
+ { "INTERVAL", SYM(INTERVAL_SYM),0,0},
+ { "INT1", SYM(TINYINT),0,0},
+ { "INT2", SYM(SMALLINT),0,0},
+ { "INT3", SYM(MEDIUMINT),0,0},
+ { "INT4", SYM(INT_SYM),0,0},
+ { "INT8", SYM(BIGINT),0,0},
+ { "INTO", SYM(INTO),0,0},
+ { "IF", SYM(IF),0,0},
+ { "IS", SYM(IS),0,0},
+ { "ISAM", SYM(ISAM_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_INSERT_ID", SYM(LAST_INSERT_ID),0,0},
+ { "LEADING", SYM(LEADING),0,0},
+ { "LEFT", SYM(LEFT),0,0},
+ { "LIKE", SYM(LIKE),0,0},
+ { "LINES", SYM(LINES),0,0},
+ { "LIMIT", SYM(LIMIT),0,0},
+ { "LOAD", SYM(LOAD),0,0},
+ { "LOCAL", SYM(LOCAL_SYM),0,0},
+ { "LOCK", SYM(LOCK_SYM),0,0},
+ { "LOGS", SYM(LOGS_SYM),0,0},
+ { "LONG", SYM(LONG_SYM),0,0},
+ { "LONGBLOB", SYM(LONGBLOB),0,0},
+ { "LONGTEXT", SYM(LONGTEXT),0,0},
+ { "LOW_PRIORITY", SYM(LOW_PRIORITY),0,0},
+ { "MAX", SYM(MAX_SYM),0,0},
+ { "MASTER", SYM(MASTER_SYM),0,0},
+ { "MASTER_CONNECT_RETRY", SYM(MASTER_CONNECT_RETRY_SYM),0,0},
+ { "MASTER_HOST", SYM(MASTER_HOST_SYM),0,0},
+ { "MASTER_LOG_FILE", SYM(MASTER_LOG_FILE_SYM),0,0},
+ { "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_USER", SYM(MASTER_USER_SYM),0,0},
+ { "MAX_ROWS", SYM(MAX_ROWS),0,0},
+ { "MATCH", SYM(MATCH),0,0},
+ { "MEDIUMBLOB", SYM(MEDIUMBLOB),0,0},
+ { "MEDIUMTEXT", SYM(MEDIUMTEXT),0,0},
+ { "MEDIUMINT", SYM(MEDIUMINT),0,0},
+ { "MERGE", SYM(MERGE_SYM),0,0},
+ { "MIDDLEINT", SYM(MEDIUMINT),0,0}, /* For powerbuilder */
+ { "MIN_ROWS", SYM(MIN_ROWS),0,0},
+ { "MINUTE", SYM(MINUTE_SYM),0,0},
+ { "MINUTE_SECOND", SYM(MINUTE_SECOND_SYM),0,0},
+ { "MODIFY", SYM(MODIFY_SYM),0,0},
+ { "MONTH", SYM(MONTH_SYM),0,0},
+ { "MYISAM", SYM(MYISAM_SYM),0,0},
+ { "NATURAL", SYM(NATURAL),0,0},
+ { "NATIONAL", SYM(NATIONAL_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},
+ { "ON", SYM(ON),0,0},
+ { "OPTIMIZE", SYM(OPTIMIZE),0,0},
+ { "OPTION", SYM(OPTION),0,0},
+ { "OPTIONALLY", SYM(OPTIONALLY),0,0},
+ { "OR", SYM(OR),0,0},
+ { "ORDER", SYM(ORDER_SYM),0,0},
+ { "OUTER", SYM(OUTER),0,0},
+ { "OUTFILE", SYM(OUTFILE),0,0},
+ { "PACK_KEYS", SYM(PACK_KEYS_SYM),0,0},
+ { "PARTIAL", SYM(PARTIAL),0,0},
+ { "PASSWORD", SYM(PASSWORD),0,0},
+ { "PRECISION", SYM(PRECISION),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},
+ { "QUICK", SYM(QUICK),0,0},
+ { "RAID0", SYM(RAID_0_SYM),0,0},
+ { "READ", SYM(READ_SYM),0,0},
+ { "REAL", SYM(REAL),0,0},
+ { "REFERENCES", SYM(REFERENCES),0,0},
+ { "RELOAD", SYM(RELOAD),0,0},
+ { "REGEXP", SYM(REGEXP),0,0},
+ { "RENAME", SYM(RENAME),0,0},
+ { "REPAIR", SYM(REPAIR),0,0},
+ { "REPLACE", SYM(REPLACE),0,0},
+ { "RESTRICT", SYM(RESTRICT),0,0},
+ { "RETURNS", SYM(UDF_RETURNS_SYM),0,0},
+ { "REVOKE", SYM(REVOKE),0,0},
+ { "RLIKE", SYM(REGEXP),0,0}, /* Like in mSQL2 */
+ { "ROLLBACK", SYM(ROLLBACK_SYM),0,0},
+ { "ROW", SYM(ROW_SYM),0,0},
+ { "ROWS", SYM(ROWS_SYM),0,0},
+ { "SECOND", SYM(SECOND_SYM),0,0},
+ { "SELECT", SYM(SELECT_SYM),0,0},
+ { "SET", SYM(SET),0,0},
+ { "SHOW", SYM(SHOW),0,0},
+ { "SHUTDOWN", SYM(SHUTDOWN),0,0},
+ { "SLAVE", SYM(SLAVE),0,0},
+ { "SMALLINT", SYM(SMALLINT),0,0},
+ { "SONAME", SYM(UDF_SONAME_SYM),0,0},
+ { "SQL_AUTO_IS_NULL", SYM(SQL_AUTO_IS_NULL),0,0},
+ { "SQL_BIG_RESULT", SYM(SQL_BIG_RESULT),0,0},
+ { "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_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_SAFE_UPDATES", SYM(SQL_SAFE_UPDATES),0,0},
+ { "SQL_SELECT_LIMIT", SYM(SQL_SELECT_LIMIT),0,0},
+ { "SQL_SMALL_RESULT", SYM(SQL_SMALL_RESULT),0,0},
+ { "SQL_WARNINGS", SYM(SQL_WARNINGS),0,0},
+ { "STRAIGHT_JOIN", SYM(STRAIGHT_JOIN),0,0},
+ { "START", SYM(START_SYM),0,0},
+ { "STARTING", SYM(STARTING),0,0},
+ { "STATUS", SYM(STATUS_SYM),0,0},
+ { "STRING", SYM(STRING_SYM),0,0},
+ { "STOP", SYM(STOP_SYM),0,0},
+ { "STRIPED", SYM(RAID_STRIPED_SYM),0,0},
+ { "TABLE", SYM(TABLE_SYM),0,0},
+ { "TABLES", SYM(TABLES),0,0},
+ { "TEMPORARY", SYM(TEMPORARY),0,0},
+ { "TERMINATED", SYM(TERMINATED),0,0},
+ { "TEXT", SYM(TEXT_SYM),0,0},
+ { "THEN", SYM(THEN_SYM),0,0},
+ { "TIME", SYM(TIME_SYM),0,0},
+ { "TIMESTAMP", SYM(TIMESTAMP),0,0},
+ { "TINYBLOB", SYM(TINYBLOB),0,0},
+ { "TINYTEXT", SYM(TINYTEXT),0,0},
+ { "TINYINT", SYM(TINYINT),0,0},
+ { "TRAILING", SYM(TRAILING),0,0},
+ { "TO", SYM(TO_SYM),0,0},
+ { "TYPE", SYM(TYPE_SYM),0,0},
+ { "USE", SYM(USE_SYM),0,0},
+ { "USING", SYM(USING),0,0},
+ { "UNIQUE", SYM(UNIQUE_SYM),0,0},
+ { "UNLOCK", SYM(UNLOCK_SYM),0,0},
+ { "UNSIGNED", SYM(UNSIGNED),0,0},
+ { "UPDATE", SYM(UPDATE_SYM),0,0},
+ { "USAGE", SYM(USAGE),0,0},
+ { "VALUES", SYM(VALUES),0,0},
+ { "VARCHAR", SYM(VARCHAR),0,0},
+ { "VARIABLES", SYM(VARIABLES),0,0},
+ { "VARYING", SYM(VARYING),0,0},
+ { "VARBINARY", SYM(VARBINARY),0,0},
+ { "WITH", SYM(WITH),0,0},
+ { "WORK", SYM(WORK_SYM),0,0},
+ { "WRITE", SYM(WRITE_SYM),0,0},
+ { "WHEN", SYM(WHEN_SYM),0,0},
+ { "WHERE", SYM(WHERE),0,0},
+ { "YEAR", SYM(YEAR_SYM),0,0},
+ { "YEAR_MONTH", SYM(YEAR_MONTH_SYM),0,0},
+ { "ZEROFILL", SYM(ZEROFILL),0,0},
+ { "||", SYM(OR_OR_CONCAT),0,0}
+};
+
+
+static SYMBOL sql_functions[] = {
+ { "ABS", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_abs)},
+ { "ACOS", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_acos)},
+ { "ADDDATE", SYM(DATE_ADD_INTERVAL),0,0},
+ { "ASCII", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_ascii)},
+ { "ASIN", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_asin)},
+ { "ATAN", SYM(ATAN),0,0},
+ { "ATAN2", SYM(ATAN),0,0},
+ { "BENCHMARK", SYM(BENCHMARK_SYM),0,0},
+ { "BIN", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_bin)},
+ { "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},
+ { "CEILING", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_ceiling)},
+ { "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},
+ { "CONCAT", SYM(CONCAT),0,0},
+ { "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)},
+ { "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)},
+ { "CURDATE", SYM(CURDATE),0,0},
+ { "CURTIME", SYM(CURTIME),0,0},
+ { "DATE_ADD", SYM(DATE_ADD_INTERVAL),0,0},
+ { "DATE_FORMAT", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_date_format)},
+ { "DATE_SUB", SYM(DATE_SUB_INTERVAL),0,0},
+ { "DAYNAME", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_dayname)},
+ { "DAYOFMONTH", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_dayofmonth)},
+ { "DAYOFWEEK", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_dayofweek)},
+ { "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)},
+ { "ELT", SYM(ELT_FUNC),0,0},
+ { "ENCODE", SYM(ENCODE_SYM),0,0},
+ { "ENCRYPT", SYM(ENCRYPT),0,0},
+ { "EXTRACT", SYM(EXTRACT_SYM),0,0},
+ { "EXP", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_exp)},
+ { "EXPORT_SET", SYM(EXPORT_SET),0,0},
+ { "FIELD", SYM(FIELD_FUNC),0,0}, /* For compability */
+ { "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},
+ { "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)},
+ { "GREATEST", SYM(GREATEST_SYM),0,0},
+ { "GROUP_UNIQUE_USERS", SYM(GROUP_UNIQUE_USERS),0,0},
+ { "HEX", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_hex)},
+ { "IFNULL", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_ifnull)},
+ { "INET_ATON", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_inet_aton)},
+ { "INET_NTOA", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_inet_ntoa)},
+ { "INSTR", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_instr)},
+ { "ISNULL", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_isnull)},
+ { "LCASE", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_lcase)},
+ { "LEAST", SYM(LEAST_SYM),0,0},
+ { "LENGTH", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_length)},
+ { "LOAD_FILE", SYM(FUNC_ARG1),0,CREATE_FUNC(create_load_file)},
+ { "LOCATE", SYM(LOCATE),0,0},
+ { "LOG", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_log)},
+ { "LOG10", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_log10)},
+ { "LOWER", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_lcase)},
+ { "LPAD", SYM(FUNC_ARG3),0,CREATE_FUNC(create_func_lpad)},
+ { "LTRIM", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_ltrim)},
+ { "MAKE_SET", SYM(MAKE_SET_SYM),0,0},
+ { "MD5", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_md5)},
+ { "MID", SYM(SUBSTRING),0,0}, /* unireg function */
+ { "MIN", SYM(MIN_SYM),0,0},
+ { "MOD", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_mod)},
+ { "MONTHNAME", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_monthname)},
+ { "NOW", SYM(NOW_SYM),0,0},
+ { "NULLIF", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_nullif)},
+ { "OCTET_LENGTH", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_length)},
+ { "OCT", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_oct)},
+ { "ORD", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_ord)},
+ { "PERIOD_ADD", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_period_add)},
+ { "PERIOD_DIFF", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_period_diff)},
+ { "PI", SYM(FUNC_ARG0),0,CREATE_FUNC(create_func_pi)},
+ { "POSITION", SYM(POSITION_SYM),0,0},
+ { "POW", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_pow)},
+ { "POWER", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_pow)},
+ { "QUARTER", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_quarter)},
+ { "RADIANS", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_radians)},
+ { "RAND", SYM(RAND),0,0},
+ { "RELEASE_LOCK", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_release_lock)},
+ { "REPEAT", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_repeat)},
+ { "REVERSE", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_reverse)},
+ { "RIGHT", SYM(RIGHT),0,0},
+ { "ROUND", SYM(ROUND),0,0},
+ { "RPAD", SYM(FUNC_ARG3),0,CREATE_FUNC(create_func_rpad)},
+ { "RTRIM", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_rtrim)},
+ { "SEC_TO_TIME", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_sec_to_time)},
+ { "SESSION_USER", SYM(USER),0,0},
+ { "SUBDATE", SYM(DATE_SUB_INTERVAL),0,0},
+ { "SIGN", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_sign)},
+ { "SIN", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_sin)},
+ { "SOUNDEX", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_soundex)},
+ { "SPACE", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_space)},
+ { "SQRT", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_sqrt)},
+ { "STD", SYM(STD_SYM),0,0},
+ { "STDDEV", SYM(STD_SYM),0,0},
+ { "STRCMP", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_strcmp)},
+ { "SUBSTRING", SYM(SUBSTRING),0,0},
+ { "SUBSTRING_INDEX", SYM(SUBSTRING_INDEX),0,0},
+ { "SUM", SYM(SUM_SYM),0,0},
+ { "SYSDATE", SYM(NOW_SYM),0,0},
+ { "SYSTEM_USER", SYM(USER),0,0},
+ { "TAN", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_tan)},
+ { "TIME_FORMAT", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_time_format)},
+ { "TIME_TO_SEC", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_time_to_sec)},
+ { "TO_DAYS", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_to_days)},
+ { "TRIM", SYM(TRIM),0,0},
+ { "TRUNCATE", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_truncate )},
+ { "UCASE", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_ucase)},
+ { "UPPER", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_ucase)},
+ { "UNIQUE_USERS", SYM(UNIQUE_USERS),0,0},
+ { "UNIX_TIMESTAMP", SYM(UNIX_TIMESTAMP),0,0},
+ { "USER", SYM(USER),0,0},
+ { "VERSION", SYM(FUNC_ARG0),0,CREATE_FUNC(create_func_version)},
+ { "WEEK", SYM(WEEK_SYM),0,0},
+ { "WEEKDAY", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_weekday)},
+ { "YEARWEEK", SYM(YEARWEEK),0,0}
+};
diff --git a/sql/lex_symbol.h b/sql/lex_symbol.h
new file mode 100644
index 00000000000..a011e27b59e
--- /dev/null
+++ b/sql/lex_symbol.h
@@ -0,0 +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 */
+
+
+/* This struct includes all reserved words and functions */
+
+#ifndef _lex_symbol_h
+#define _lex_symbol_h
+
+typedef struct st_symbol {
+ const char *name;
+ uint tok;
+ uint length;
+ void *create_func;
+} SYMBOL;
+
+typedef struct st_lex_symbol
+{
+ SYMBOL *symbol;
+ char *str;
+ uint length;
+} LEX_SYMBOL;
+
+#endif /* _lex_symbol_h */
diff --git a/sql/lock.cc b/sql/lock.cc
new file mode 100644
index 00000000000..b65ae5ddc3e
--- /dev/null
+++ b/sql/lock.cc
@@ -0,0 +1,386 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+
+/* locking functions for mysql */
+/*
+ Because of the new concurrent inserts, we must first get external locks
+ before getting internal locks. If we do it in the other order, the status
+ information is not up to date when called from the lock handler.
+
+TODO:
+ Change to use my_malloc() ONLY when using LOCK TABLES command or when
+ we are forced to use mysql_lock_merge.
+*/
+
+#include "mysql_priv.h"
+#include <hash.h>
+
+extern HASH open_cache;
+
+static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table,uint count,
+ bool unlock, TABLE **write_locked);
+static int lock_external(TABLE **table,uint count);
+static int unlock_external(THD *thd, TABLE **table,uint count);
+
+
+MYSQL_LOCK *mysql_lock_tables(THD *thd,TABLE **tables,uint count)
+{
+ MYSQL_LOCK *sql_lock;
+ TABLE *write_lock_used;
+ DBUG_ENTER("mysql_lock_tables");
+
+ for (;;)
+ {
+ if (!(sql_lock = get_lock_data(thd,tables,count, 0,&write_lock_used)))
+ break;
+
+ if (global_read_lock && write_lock_used)
+ {
+ /*
+ 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
+ {
+ 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);
+ pthread_mutex_lock(&thd->mysys_var->mutex);
+ thd->mysys_var->current_mutex= &LOCK_open;
+ thd->mysys_var->current_cond= &COND_refresh;
+ thd->proc_info="Waiting for table";
+ pthread_mutex_unlock(&thd->mysys_var->mutex);
+
+ 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)
+ {
+ my_free((gptr) sql_lock,MYF(0));
+ goto retry;
+ }
+ }
+
+ thd->proc_info="System lock";
+ if (lock_external(tables,count))
+ {
+ my_free((gptr) sql_lock,MYF(0));
+ sql_lock=0;
+ thd->proc_info=0;
+ break;
+ }
+ thd->proc_info=0;
+ thd->locked=1;
+ if (thr_multi_lock(sql_lock->locks,sql_lock->lock_count))
+ {
+ thd->some_tables_deleted=1; // Try again
+ sql_lock->lock_count=0; // Locks are alread freed
+ }
+ else if (!thd->some_tables_deleted)
+ {
+ thd->locked=0;
+ break;
+ }
+
+ /* some table was altered or deleted. reopen tables marked deleted */
+ mysql_unlock_tables(thd,sql_lock);
+ thd->locked=0;
+retry:
+ sql_lock=0;
+ if (wait_for_tables(thd))
+ break; // Couldn't open tables
+ }
+ if (thd->killed)
+ {
+ my_error(ER_SERVER_SHUTDOWN,MYF(0));
+ if (sql_lock)
+ {
+ mysql_unlock_tables(thd,sql_lock);
+ sql_lock=0;
+ }
+ }
+ DBUG_RETURN (sql_lock);
+}
+
+
+static int lock_external(TABLE **tables,uint count)
+{
+ reg1 uint i;
+ int lock_type,error;
+ THD *thd=current_thd;
+ DBUG_ENTER("lock_external");
+
+ for (i=1 ; i <= count ; i++, tables++)
+ {
+ lock_type=F_WRLCK; /* Lock exclusive */
+ if ((*tables)->db_stat & HA_READ_ONLY ||
+ ((*tables)->reginfo.lock_type >= TL_READ &&
+ (*tables)->reginfo.lock_type <= TL_READ_NO_INSERT))
+ lock_type=F_RDLCK;
+
+ if ((error=(*tables)->file->external_lock(thd,lock_type)))
+ {
+ for ( ; i-- ; tables--)
+ {
+ (*tables)->file->external_lock(thd, F_UNLCK);
+ (*tables)->current_lock=F_UNLCK;
+ }
+ my_error(ER_CANT_LOCK,MYF(ME_BELL+ME_OLDWIN+ME_WAITTANG),error);
+ DBUG_RETURN(error);
+ }
+ else
+ {
+ (*tables)->db_stat &= ~ HA_BLOCK_LOCK;
+ (*tables)->current_lock= lock_type;
+ }
+ }
+ DBUG_RETURN(0);
+}
+
+
+void mysql_unlock_tables(THD *thd, MYSQL_LOCK *sql_lock)
+{
+ DBUG_ENTER("mysql_unlock_tables");
+ thr_multi_unlock(sql_lock->locks,sql_lock->lock_count);
+ VOID(unlock_external(thd,sql_lock->table,sql_lock->table_count));
+ my_free((gptr) sql_lock,MYF(0));
+ DBUG_VOID_RETURN;
+}
+
+/*
+ Unlock some of the tables locked by mysql_lock_tables
+ This will work even if get_lock_data fails (next unlock will free all)
+ */
+
+void mysql_unlock_some_tables(THD *thd, TABLE **table,uint count)
+{
+ MYSQL_LOCK *sql_lock;
+ TABLE *write_lock_used;
+ if ((sql_lock = get_lock_data(thd, table, count, 1, &write_lock_used)))
+ mysql_unlock_tables(thd, sql_lock);
+}
+
+
+/*
+** unlock all tables locked for read.
+*/
+
+void mysql_unlock_read_tables(THD *thd, MYSQL_LOCK *sql_lock)
+{
+ uint i,found;
+ DBUG_ENTER("mysql_unlock_read_tables");
+
+ /* Move all write locks first */
+ THR_LOCK_DATA **lock=sql_lock->locks;
+ for (i=found=0 ; i < sql_lock->lock_count ; i++)
+ {
+ if (sql_lock->locks[i]->type >= TL_WRITE_ALLOW_READ)
+ {
+ swap(THR_LOCK_DATA *,*lock,sql_lock->locks[i]);
+ lock++;
+ found++;
+ }
+ }
+ /* unlock the read locked tables */
+ if (i != found)
+ {
+ thr_multi_unlock(lock,i-found);
+ sql_lock->lock_count-=found;
+ }
+
+ /* Then to the same for the external locks */
+ /* Move all write locked tables first */
+ TABLE **table=sql_lock->table;
+ for (i=found=0 ; i < sql_lock->table_count ; i++)
+ {
+ if ((uint) sql_lock->table[i]->reginfo.lock_type >= TL_WRITE_ALLOW_READ)
+ {
+ swap(TABLE *,*table,sql_lock->table[i]);
+ table++;
+ found++;
+ }
+ }
+ /* Unlock all read locked tables */
+ if (i != found)
+ {
+ VOID(unlock_external(thd,table,i-found));
+ sql_lock->table_count-=found;
+ }
+ DBUG_VOID_RETURN;
+}
+
+
+
+void mysql_lock_remove(THD *thd, MYSQL_LOCK *locked,TABLE *table)
+{
+ mysql_unlock_some_tables(thd, &table,1);
+ if (locked)
+ {
+ reg1 uint i;
+ for (i=0; i < locked->table_count; i++)
+ {
+ if (locked->table[i] == table)
+ {
+ locked->table_count--;
+ bmove((char*) (locked->table+i),
+ (char*) (locked->table+i+1),
+ (locked->table_count-i)* sizeof(TABLE*));
+ break;
+ }
+ }
+ THR_LOCK_DATA **prev=locked->locks;
+ for (i=0 ; i < locked->lock_count ; i++)
+ {
+ if (locked->locks[i]->type != TL_UNLOCK)
+ *prev++ = locked->locks[i];
+ }
+ locked->lock_count=(prev - locked->locks);
+ }
+}
+
+/* abort all other threads waiting to get lock in table */
+
+void mysql_lock_abort(THD *thd, TABLE *table)
+{
+ MYSQL_LOCK *locked;
+ TABLE *write_lock_used;
+ if ((locked = get_lock_data(thd,&table,1,1,&write_lock_used)))
+ {
+ for (uint i=0; i < locked->lock_count; i++)
+ thr_abort_locks(locked->locks[i]->lock);
+ my_free((gptr) locked,MYF(0));
+ }
+}
+
+
+MYSQL_LOCK *mysql_lock_merge(MYSQL_LOCK *a,MYSQL_LOCK *b)
+{
+ MYSQL_LOCK *sql_lock;
+ DBUG_ENTER("mysql_lock_merge");
+ if (!(sql_lock= (MYSQL_LOCK*)
+ my_malloc(sizeof(*sql_lock)+
+ sizeof(THR_LOCK_DATA*)*(a->lock_count+b->lock_count)+
+ sizeof(TABLE*)*(a->table_count+b->table_count),MYF(MY_WME))))
+ DBUG_RETURN(0); // Fatal error
+ sql_lock->lock_count=a->lock_count+b->lock_count;
+ sql_lock->table_count=a->table_count+b->table_count;
+ sql_lock->locks=(THR_LOCK_DATA**) (sql_lock+1);
+ sql_lock->table=(TABLE**) (sql_lock->locks+sql_lock->lock_count);
+ memcpy(sql_lock->locks,a->locks,a->lock_count*sizeof(*a->locks));
+ memcpy(sql_lock->locks+a->lock_count,b->locks,
+ b->lock_count*sizeof(*b->locks));
+ memcpy(sql_lock->table,a->table,a->table_count*sizeof(*a->table));
+ memcpy(sql_lock->table+a->table_count,b->table,
+ b->table_count*sizeof(*b->table));
+ my_free((gptr) a,MYF(0));
+ my_free((gptr) b,MYF(0));
+ DBUG_RETURN(sql_lock);
+}
+
+
+ /* unlock a set of external */
+
+static int unlock_external(THD *thd, TABLE **table,uint count)
+{
+ int error,error_code;
+ DBUG_ENTER("unlock_external");
+
+ error_code=0;
+ for (; count-- ; table++)
+ {
+ if ((*table)->current_lock != F_UNLCK)
+ {
+ (*table)->current_lock = F_UNLCK;
+ if ((error=(*table)->file->external_lock(thd, F_UNLCK)))
+ error_code=error;
+ }
+ }
+ if (error_code)
+ my_error(ER_CANT_LOCK,MYF(ME_BELL+ME_OLDWIN+ME_WAITTANG),error_code);
+ DBUG_RETURN(error_code);
+}
+
+
+/*
+** Get lock structures from table structs and initialize locks
+*/
+
+
+static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count,
+ bool get_old_locks, TABLE **write_lock_used)
+{
+ uint i,tables,lock_count;
+ MYSQL_LOCK *sql_lock;
+ THR_LOCK_DATA **locks;
+ TABLE **to;
+
+ *write_lock_used=0;
+ for (i=tables=lock_count=0 ; i < count ; i++)
+ {
+ if (!table_ptr[i]->tmp_table)
+ {
+ tables+=table_ptr[i]->file->lock_count();
+ lock_count++;
+ }
+ }
+
+ if (!(sql_lock= (MYSQL_LOCK*)
+ my_malloc(sizeof(*sql_lock)+
+ sizeof(THR_LOCK_DATA*)*tables+sizeof(table_ptr)*lock_count,
+ MYF(0))))
+ return 0;
+ locks=sql_lock->locks=(THR_LOCK_DATA**) (sql_lock+1);
+ to=sql_lock->table=(TABLE**) (locks+tables);
+ sql_lock->table_count=lock_count;
+ sql_lock->lock_count=tables;
+
+ for (i=0 ; i < count ; i++)
+ {
+ TABLE *table;
+ if ((table=table_ptr[i])->tmp_table)
+ continue;
+ *to++=table;
+ enum thr_lock_type lock_type= table->reginfo.lock_type;
+ if (lock_type >= TL_WRITE_ALLOW_WRITE)
+ {
+ *write_lock_used=table;
+ if (table->db_stat & HA_READ_ONLY)
+ {
+ my_error(ER_OPEN_AS_READONLY,MYF(0),table->table_name);
+ my_free((gptr) sql_lock,MYF(0));
+ return 0;
+ }
+ }
+ locks=table->file->store_lock(thd, locks, get_old_locks ? TL_IGNORE :
+ lock_type);
+ }
+ return sql_lock;
+}
diff --git a/sql/log.cc b/sql/log.cc
new file mode 100644
index 00000000000..3c21a1a9422
--- /dev/null
+++ b/sql/log.cc
@@ -0,0 +1,733 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+
+/* logging of commands */
+
+#include "mysql_priv.h"
+#include "sql_acl.h"
+
+#include <my_dir.h>
+#include <stdarg.h>
+#include <m_ctype.h> // For test_if_number
+
+
+
+MYSQL_LOG mysql_log,mysql_update_log,mysql_slow_log,mysql_bin_log;
+extern I_List<i_string> binlog_do_db, binlog_ignore_db;
+
+static bool test_if_number(const char *str,
+ long *res, bool allow_wildcards);
+
+/****************************************************************************
+** Find a uniq filename for 'filename.#'.
+** Set # to a number as low as possible
+** returns != 0 if not possible to get uniq filename
+****************************************************************************/
+
+static int find_uniq_filename(char *name)
+{
+ long number;
+ uint i,length;
+ char buff[FN_REFLEN];
+ struct st_my_dir *dir_info;
+ reg1 struct fileinfo *file_info;
+ ulong max_found=0;
+ DBUG_ENTER("find_uniq_filename");
+
+ length=dirname_part(buff,name);
+ char *start=name+length,*end=strend(start);
+ *end='.';
+ length=end-start+1;
+
+ if (!(dir_info = my_dir(buff,MYF(MY_DONT_SORT))))
+ { // This shouldn't happen
+ strmov(end,".1"); // use name+1
+ DBUG_RETURN(0);
+ }
+ file_info= dir_info->dir_entry;
+ for (i=dir_info->number_off_files ; i-- ; file_info++)
+ {
+ if (bcmp(file_info->name,start,length) == 0 &&
+ test_if_number(file_info->name+length, &number,0))
+ {
+ set_if_bigger(max_found,(ulong) number);
+ }
+ }
+ my_dirend(dir_info);
+
+ *end++='.';
+ sprintf(end,"%03ld",max_found+1);
+ DBUG_RETURN(0);
+}
+
+
+
+MYSQL_LOG::MYSQL_LOG(): file(0),index_file(0),last_time(0),query_start(0),
+ name(0), log_type(LOG_CLOSED),write_error(0),inited(0)
+{
+ /*
+ We don't want to intialize LOCK_Log here as the thread system may
+ not have been initailized yet. We do it instead at 'open'.
+ */
+ index_file_name[0] = 0;
+}
+
+MYSQL_LOG::~MYSQL_LOG()
+{
+ if (inited)
+ {
+ (void) pthread_mutex_destroy(&LOCK_log);
+ (void) pthread_mutex_destroy(&LOCK_index);
+ }
+}
+
+void MYSQL_LOG::set_index_file_name(const char* index_file_name)
+{
+ if (index_file_name)
+ fn_format(this->index_file_name,index_file_name,mysql_data_home,"-index",
+ 4);
+ else
+ this->index_file_name[0] = 0;
+}
+
+int MYSQL_LOG::generate_new_name(char *new_name, const char *log_name)
+{
+ if (log_type == LOG_NORMAL)
+ fn_format(new_name,log_name,mysql_data_home,"",4);
+ else
+ {
+ fn_format(new_name,log_name,mysql_data_home,"",4);
+ if (!fn_ext(log_name)[0])
+ {
+ if (find_uniq_filename(new_name))
+ {
+ sql_print_error(ER(ER_NO_UNIQUE_LOGFILE), log_name);
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+
+void MYSQL_LOG::open(const char *log_name, enum_log_type log_type_arg,
+ const char *new_name)
+{
+
+ if (!inited)
+ {
+ inited=1;
+ (void) pthread_mutex_init(&LOCK_log,NULL);
+ (void) pthread_mutex_init(&LOCK_index, NULL);
+ }
+
+ log_type=log_type_arg;
+ name=my_strdup(log_name,MYF(0));
+ if (new_name)
+ strmov(log_file_name,new_name);
+ else if (generate_new_name(log_file_name, name))
+ return;
+
+ if (log_type == LOG_BIN && !index_file_name[0])
+ fn_format(index_file_name, name, mysql_data_home, ".index", 6);
+
+ db[0]=0;
+ file=my_fopen(log_file_name,O_APPEND | O_WRONLY,MYF(MY_WME | ME_WAITTANG));
+ if (!file)
+ {
+ my_free(name,MYF(0));
+ name=0;
+ log_type=LOG_CLOSED;
+ return;
+ }
+
+ if (log_type == LOG_NORMAL)
+ {
+#ifdef __NT__
+ fprintf( file, "%s, Version: %s, started with:\nTCP Port: %d, Named Pipe: %s\n", my_progname, server_version, mysql_port, mysql_unix_port);
+#else
+ fprintf(file,"%s, Version: %s, started with:\nTcp port: %d Unix socket: %s\n", my_progname,server_version,mysql_port,mysql_unix_port);
+#endif
+ fprintf(file,"Time Id Command Argument\n");
+ (void) fflush(file);
+ }
+ else if (log_type == LOG_NEW)
+ {
+ time_t skr=time(NULL);
+ struct tm tm_tmp;
+ localtime_r(&skr,&tm_tmp);
+
+ fprintf(file,"# %s, Version: %s at %02d%02d%02d %2d:%02d:%02d\n",
+ my_progname,server_version,
+ tm_tmp.tm_year % 100,
+ tm_tmp.tm_mon+1,
+ tm_tmp.tm_mday,
+ tm_tmp.tm_hour,
+ tm_tmp.tm_min,
+ tm_tmp.tm_sec);
+ (void) fflush(file);
+ }
+ else if (log_type == LOG_BIN)
+ {
+ Start_log_event s;
+ if(!index_file &&
+ !(index_file = my_fopen(index_file_name,O_APPEND | O_RDWR,
+ MYF(MY_WME))))
+ {
+ my_fclose(file,MYF(MY_WME));
+ my_free(name,MYF(0));
+ name=0;
+ file=0;
+ log_type=LOG_CLOSED;
+ return;
+ }
+ s.write(file);
+ pthread_mutex_lock(&LOCK_index);
+ my_fseek(index_file, 0L, MY_SEEK_END, MYF(MY_WME));
+ fprintf(index_file, "%s\n", log_file_name);
+ fflush(index_file);
+ pthread_mutex_unlock(&LOCK_index);
+ }
+}
+
+int MYSQL_LOG::get_current_log(LOG_INFO* linfo)
+{
+ pthread_mutex_lock(&LOCK_log);
+ strmake(linfo->log_file_name, log_file_name, sizeof(linfo->log_file_name));
+ linfo->pos = my_ftell(file, MYF(MY_WME));
+ pthread_mutex_unlock(&LOCK_log);
+ return 0;
+}
+
+// if log_name is "" we stop at the first entry
+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
+ if(!index_file) return LOG_INFO_INVALID;
+ int error = 0;
+ char* fname = linfo->log_file_name;
+ int log_name_len = strlen(log_name);
+
+ pthread_mutex_lock(&LOCK_index);
+ if(my_fseek(index_file, 0L, MY_SEEK_SET, MYF(MY_WME) ) == MY_FILEPOS_ERROR)
+ {
+ error = LOG_INFO_SEEK;
+ goto err;
+ }
+
+ for(;;)
+ {
+ if(!fgets(fname, FN_REFLEN, index_file))
+ {
+ error = feof(index_file) ? LOG_INFO_EOF : LOG_INFO_IO;
+ goto err;
+ }
+
+ // if the log entry matches, empty string matching anything
+ if(!log_name_len || (fname[log_name_len] == '\n' && !memcmp(fname, log_name, log_name_len)))
+ {
+ if(log_name_len)
+ fname[log_name_len] = 0; // to kill \n
+ else
+ {
+ *(strend(fname) - 1) = 0;
+ }
+ linfo->index_file_offset = my_ftell(index_file, MYF(MY_WME));
+ break;
+ }
+ }
+
+ error = 0;
+err:
+ pthread_mutex_unlock(&LOCK_index);
+ return error;
+
+}
+int MYSQL_LOG::find_next_log(LOG_INFO* linfo)
+{
+ // mutex needed because we need to make sure the file pointer does not move
+ // from under our feet
+ if(!index_file) return LOG_INFO_INVALID;
+ int error = 0;
+ char* fname = linfo->log_file_name;
+ char* end ;
+
+ pthread_mutex_lock(&LOCK_index);
+ if(my_fseek(index_file, linfo->index_file_offset, MY_SEEK_SET, MYF(MY_WME) ) == MY_FILEPOS_ERROR)
+ {
+ error = LOG_INFO_SEEK;
+ goto err;
+ }
+
+ if(!fgets(fname, FN_REFLEN, index_file))
+ {
+ error = feof(index_file) ? LOG_INFO_EOF : LOG_INFO_IO;
+ goto err;
+ }
+
+ end = strend(fname) - 1;
+ *end = 0; // kill /n
+ linfo->index_file_offset = ftell(index_file);
+ error = 0;
+err:
+ pthread_mutex_unlock(&LOCK_index);
+ 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)
+{
+ if(inited)
+ {
+ int dir_len = dirname_length(log_file_name);
+ int ident_len = strlen(log_ident);
+ if(dir_len + ident_len + 1 > FN_REFLEN)
+ {
+ buf[0] = 0;
+ return; // protection agains malicious buffer overflow
+ }
+
+ memcpy(buf, log_file_name, dir_len);
+ memcpy(buf + dir_len, log_ident, ident_len + 1); // this takes care of \0
+ // at the end
+ }
+ else
+ buf[0] = 0;
+}
+
+bool MYSQL_LOG::is_active(const char* log_file_name)
+{
+ return inited && !strcmp(log_file_name, this->log_file_name);
+}
+
+void MYSQL_LOG::new_file()
+{
+ if (file)
+ {
+ char new_name[FN_REFLEN], *old_name=name;
+ VOID(pthread_mutex_lock(&LOCK_log));
+ if (generate_new_name(new_name, name))
+ return; // Something went wrong
+ 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(file);
+ VOID(pthread_cond_broadcast(&COND_binlog_update));
+ }
+ name=0;
+ close();
+ open(old_name, log_type, new_name);
+ my_free(old_name,MYF(0));
+ if (!file) // Something got wrong
+ log_type=LOG_CLOSED;
+ last_time=query_start=0;
+ write_error=0;
+ VOID(pthread_mutex_unlock(&LOCK_log));
+ }
+}
+
+
+void MYSQL_LOG::write(enum enum_server_command command,
+ const char *format,...)
+{
+ if (name && (what_to_log & (1L << (uint) command)))
+ {
+ va_list args;
+ va_start(args,format);
+ VOID(pthread_mutex_lock(&LOCK_log));
+ if (log_type != LOG_CLOSED)
+ {
+ time_t skr;
+ ulong id;
+ THD *thd=current_thd;
+ int error=0;
+ if (thd)
+ { // Normal thread
+ if ((thd->options & OPTION_LOG_OFF) &&
+ (thd->master_access & PROCESS_ACL))
+ {
+ VOID(pthread_mutex_unlock(&LOCK_log));
+ return; // No logging
+ }
+ id=thd->thread_id;
+ if (thd->user_time || !(skr=thd->query_start()))
+ skr=time(NULL); // Connected
+ }
+ else
+ { // Log from connect handler
+ skr=time(NULL);
+ id=0;
+ }
+ if (skr != last_time)
+ {
+ last_time=skr;
+ struct tm tm_tmp;
+ struct tm *start;
+ localtime_r(&skr,&tm_tmp);
+ start=&tm_tmp;
+ if (fprintf(file,"%02d%02d%02d %2d:%02d:%02d\t",
+ start->tm_year % 100,
+ start->tm_mon+1,
+ start->tm_mday,
+ start->tm_hour,
+ start->tm_min,
+ start->tm_sec) < 0)
+ error=errno;
+ }
+ else if (fputs("\t\t",file) < 0)
+ error=errno;
+ if (fprintf(file,"%7ld %-10.10s",
+ id,command_name[(uint) command]) < 0)
+ error=errno;
+ if (format)
+ {
+ if (fputc(' ',file) < 0 || vfprintf(file,format,args) < 0)
+ error=errno;
+ }
+ if (fputc('\n',file) < 0)
+ error=errno;
+ if (fflush(file) < 0)
+ error=errno;
+ if (error && ! write_error)
+ {
+ write_error=1;
+ sql_print_error(ER(ER_ERROR_ON_WRITE),name,error);
+ }
+ }
+ va_end(args);
+ VOID(pthread_mutex_unlock(&LOCK_log));
+ }
+}
+
+/* Write to binary log in a format to be used for replication */
+
+void MYSQL_LOG::write(Query_log_event* event_info)
+{
+ if (name)
+ {
+ VOID(pthread_mutex_lock(&LOCK_log));
+ if(file)
+ {
+ THD *thd=event_info->thd;
+ if ((!(thd->options & OPTION_BIN_LOG) &&
+ thd->master_access & PROCESS_ACL) ||
+ !db_ok(event_info->db, binlog_do_db, binlog_ignore_db))
+ {
+ VOID(pthread_mutex_unlock(&LOCK_log));
+ return;
+ }
+
+ if (thd->last_insert_id_used)
+ {
+ Intvar_log_event e((uchar)LAST_INSERT_ID_EVENT, thd->last_insert_id);
+ if (e.write(file))
+ {
+ sql_print_error(ER(ER_ERROR_ON_WRITE), name, errno);
+ goto err;
+ }
+ }
+
+ if (thd->insert_id_used)
+ {
+ Intvar_log_event e((uchar)INSERT_ID_EVENT, thd->last_insert_id);
+ if(e.write(file))
+ {
+ sql_print_error(ER(ER_ERROR_ON_WRITE), name, errno);
+ goto err;
+ }
+ }
+
+ if(event_info->write(file))
+ {
+ sql_print_error(ER(ER_ERROR_ON_WRITE), name, errno);
+ }
+ err:
+ VOID(pthread_cond_broadcast(&COND_binlog_update));
+
+ VOID(pthread_mutex_unlock(&LOCK_log));
+ }
+ }
+
+}
+
+void MYSQL_LOG::write(Load_log_event* event_info)
+{
+ if(name)
+ {
+ VOID(pthread_mutex_lock(&LOCK_log));
+ if(file)
+ {
+ THD *thd=event_info->thd;
+ if (!(thd->options & OPTION_BIN_LOG) &&
+ (thd->master_access & PROCESS_ACL))
+ {
+ VOID(pthread_mutex_unlock(&LOCK_log));
+ return;
+ }
+
+
+ if (event_info->write(file))
+ sql_print_error(ER(ER_ERROR_ON_WRITE), name, errno);
+ VOID(pthread_cond_broadcast(&COND_binlog_update));
+
+ VOID(pthread_mutex_unlock(&LOCK_log));
+ }
+ }
+}
+
+
+/* Write update log in a format suitable for incremental backup */
+
+void MYSQL_LOG::write(const char *query, uint query_length,
+ ulong time_for_query)
+{
+ if (name)
+ {
+ VOID(pthread_mutex_lock(&LOCK_log));
+ if (file)
+ { // Safety agains reopen
+ int error=0;
+ THD *thd=current_thd;
+ char buff[80],*end;
+ end=buff;
+ if (!(thd->options & OPTION_UPDATE_LOG) &&
+ (thd->master_access & PROCESS_ACL))
+ {
+ VOID(pthread_mutex_unlock(&LOCK_log));
+ return;
+ }
+ if (specialflag & SPECIAL_LONG_LOG_FORMAT)
+ {
+ time_t skr=time(NULL);
+ if (skr != last_time)
+ {
+ last_time=skr;
+ struct tm tm_tmp;
+ struct tm *start;
+ localtime_r(&skr,&tm_tmp);
+ start=&tm_tmp;
+ if (fprintf(file,"# Time: %02d%02d%02d %2d:%02d:%02d\n",
+ start->tm_year % 100,
+ start->tm_mon+1,
+ start->tm_mday,
+ start->tm_hour,
+ start->tm_min,
+ start->tm_sec) < 0)
+ error=errno;
+ }
+ if (fprintf(file, "# User@Host: %s [%s] @ %s [%s]\n",
+ thd->priv_user,
+ thd->user,
+ thd->host ? thd->host : "",
+ thd->ip ? thd->ip : "") < 0)
+ error=errno;;
+ }
+ if (time_for_query)
+ fprintf(file,"# Time: %lu\n",time_for_query);
+ if (thd->db && strcmp(thd->db,db))
+ { // Database changed
+ if (fprintf(file,"use %s;\n",thd->db) < 0)
+ error=errno;
+ strmov(db,thd->db);
+ }
+ if (thd->last_insert_id_used)
+ {
+ end=strmov(end,",last_insert_id=");
+ end=longlong10_to_str((longlong) thd->current_insert_id,end,-10);
+ }
+ // Save value if we do an insert.
+ if (thd->insert_id_used)
+ {
+ if (specialflag & SPECIAL_LONG_LOG_FORMAT)
+ {
+ end=strmov(end,",insert_id=");
+ end=longlong10_to_str((longlong) thd->last_insert_id,end,-10);
+ }
+ }
+ if (thd->query_start_used)
+ {
+ if (query_start != thd->query_start())
+ {
+ query_start=thd->query_start();
+ end=strmov(end,",timestamp=");
+ end=int10_to_str((long) query_start,end,10);
+ }
+ }
+ if (end != buff)
+ {
+ *end++=';';
+ *end++='\n';
+ *end=0;
+ if (fputs("SET ",file) < 0 || fputs(buff+1,file) < 0)
+ error=errno;
+ }
+ if (!query)
+ {
+ query="#adminstrator command";
+ query_length=21;
+ }
+ if (my_fwrite(file,(byte*) query,query_length,MYF(MY_NABP)) ||
+ fputc(';',file) < 0 || fputc('\n',file) < 0)
+ error=errno;
+ if (fflush(file) < 0)
+ error=errno;
+ if (error && ! write_error)
+ {
+ write_error=1;
+ sql_print_error(ER(ER_ERROR_ON_WRITE),name,error);
+ }
+ }
+ VOID(pthread_mutex_unlock(&LOCK_log));
+ }
+}
+
+
+
+void MYSQL_LOG::flush()
+{
+ if (file)
+ if (fflush(file) < 0 && ! write_error)
+ {
+ write_error=1;
+ sql_print_error(ER(ER_ERROR_ON_WRITE),name,errno);
+ }
+}
+
+
+void MYSQL_LOG::close(bool exiting)
+{ // One can't set log_type here!
+ if (file)
+ {
+ if (log_type == LOG_BIN)
+ {
+ Stop_log_event s;
+ s.write(file);
+ VOID(pthread_cond_broadcast(&COND_binlog_update));
+ }
+ if (my_fclose(file,MYF(0)) < 0 && ! write_error)
+ {
+ write_error=1;
+ sql_print_error(ER(ER_ERROR_ON_WRITE),name,errno);
+ }
+ file=0;
+ }
+ if (name)
+ {
+ my_free(name,MYF(0));
+ name=0;
+ }
+
+ if(exiting && index_file)
+ {
+ if (my_fclose(index_file,MYF(0)) < 0 && ! write_error)
+ {
+ write_error=1;
+ sql_print_error(ER(ER_ERROR_ON_WRITE),name,errno);
+ }
+ index_file=0;
+
+ }
+}
+
+
+ /* Check if a string is a valid number */
+ /* Output: TRUE -> number */
+
+static bool test_if_number(register const char *str,
+ long *res, bool allow_wildcards)
+{
+ reg2 int flag;
+ const char *start;
+ DBUG_ENTER("test_if_number");
+
+ flag=0; start=str;
+ while (*str++ == ' ') ;
+ if (*--str == '-' || *str == '+')
+ str++;
+ while (isdigit(*str) || (allow_wildcards &&
+ (*str == wild_many || *str == wild_one)))
+ {
+ flag=1;
+ str++;
+ }
+ if (*str == '.')
+ {
+ for (str++ ;
+ isdigit(*str) ||
+ (allow_wildcards && (*str == wild_many || *str == wild_one)) ;
+ str++, flag=1) ;
+ }
+ if (*str != 0 || flag == 0)
+ DBUG_RETURN(0);
+ if (res)
+ *res=atol(start);
+ DBUG_RETURN(1); /* Number ok */
+} /* test_if_number */
+
+
+void sql_print_error(const char *format,...)
+{
+ va_list args;
+ time_t skr;
+ struct tm tm_tmp;
+ struct tm *start;
+ va_start(args,format);
+ DBUG_ENTER("sql_print_error");
+
+ VOID(pthread_mutex_lock(&LOCK_error_log));
+#ifndef DBUG_OFF
+ {
+ char buff[1024];
+ vsprintf(buff,format,args);
+ DBUG_PRINT("error",("%s",buff));
+ }
+#endif
+ skr=time(NULL);
+ localtime_r(&skr,&tm_tmp);
+ start=&tm_tmp;
+ fprintf(stderr,"%02d%02d%02d %2d:%02d:%02d ",
+ start->tm_year % 100,
+ start->tm_mon+1,
+ start->tm_mday,
+ start->tm_hour,
+ start->tm_min,
+ start->tm_sec);
+ (void) vfprintf(stderr,format,args);
+ (void) fputc('\n',stderr);
+ fflush(stderr);
+ va_end(args);
+
+ VOID(pthread_mutex_unlock(&LOCK_error_log));
+ DBUG_VOID_RETURN;
+}
+
+
+
+void sql_perror(const char *message)
+{
+#ifdef HAVE_STRERROR
+ sql_print_error("%s: %s",message, strerror(errno));
+#else
+ perror(message);
+#endif
+}
diff --git a/sql/log_event.cc b/sql/log_event.cc
new file mode 100644
index 00000000000..eae8d7c1e88
--- /dev/null
+++ b/sql/log_event.cc
@@ -0,0 +1,685 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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_CLIENT
+#ifdef __GNUC__
+#pragma implementation // gcc: Class implementation
+#endif
+#include "mysql_priv.h"
+#endif /* MYSQL_CLIENT */
+
+#define LOG_EVENT_HEADER_LEN 9
+#define QUERY_HEADER_LEN (sizeof(uint) + sizeof(uint) + sizeof(uchar))
+#define LOAD_HEADER_LEN (sizeof(uint) + sizeof(uint) + \
+ + sizeof(uint) + 2 + sizeof(uint))
+#define EVENT_LEN_OFFSET 5
+#define EVENT_TYPE_OFFSET 4
+#define MAX_EVENT_LEN 4*1024*1024
+#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))
+
+static void pretty_print_char(FILE* file, int c)
+{
+ 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;
+ }
+ fputc( '\'', file);
+}
+
+int Query_log_event::write(FILE* file)
+{
+ return query ? Log_event::write(file) : -1;
+}
+
+int Log_event::write(FILE* file)
+{
+ if (write_header(file)
+ || write_data(file) || fflush(file)) return -1;
+ return 0;
+}
+
+int Log_event::write_header(FILE* file)
+{
+ char buf[LOG_EVENT_HEADER_LEN];
+ // make sure to change this when the header gets bigger
+ char* pos = buf;
+ int4store(pos, when); // timestamp
+ pos += 4;
+ *pos++ = get_type_code(); // event type code
+ int4store(pos, get_data_size() +
+ sizeof(time_t) // timestamp
+ + sizeof(char) // event code
+ + sizeof(uint) // event entry size
+ );
+ pos += 4;
+ return (my_fwrite(file, (byte*) buf, (uint) (pos - buf),
+ MYF(MY_NABP | MY_WME)));
+}
+
+#ifndef MYSQL_CLIENT
+
+int Log_event::read_log_event(FILE* file, String* packet)
+{
+ ulong data_len;
+ char buf[LOG_EVENT_HEADER_LEN];
+ if (my_fread(file, (byte*)buf, sizeof(buf), MYF(MY_NABP)))
+ return feof(file) ? LOG_READ_EOF: LOG_READ_IO;
+
+ data_len = uint4korr(buf + EVENT_LEN_OFFSET);
+ if (data_len < LOG_EVENT_HEADER_LEN || data_len > MAX_EVENT_LEN)
+ return LOG_READ_BOGUS;
+
+ packet->append(buf, sizeof(buf));
+ data_len -= LOG_EVENT_HEADER_LEN;
+ if (!data_len)
+ return 0; // the event does not have a data section
+ if (packet->append(file, data_len, MYF(MY_WME|MY_NABP)))
+ return feof(file) ? LOG_READ_BOGUS: LOG_READ_IO;
+ return 0;
+}
+
+#endif // MYSQL_CLIENT
+
+// allocates memory - the caller is responsible for clean-up
+
+Log_event* Log_event::read_log_event(FILE* file)
+{
+ time_t timestamp;
+ char buf[5];
+ if (my_fread(file, (byte *) buf, sizeof(buf), MY_NABP))
+ return NULL;
+ timestamp = uint4korr(buf);
+
+ switch(buf[EVENT_TYPE_OFFSET])
+ {
+ case QUERY_EVENT:
+ {
+ Query_log_event* q = new Query_log_event(file, timestamp);
+ if (!q->query)
+ {
+ delete q;
+ return NULL;
+ }
+
+ return q;
+ }
+
+ case LOAD_EVENT:
+ {
+ Load_log_event* l = new Load_log_event(file, timestamp);
+ if (!l->table_name)
+ {
+ delete l;
+ return NULL;
+ }
+
+ return l;
+ }
+
+
+ case ROTATE_EVENT:
+ {
+ Rotate_log_event* r = new Rotate_log_event(file, timestamp);
+ if (!r->new_log_ident)
+ {
+ delete r;
+ return NULL;
+ }
+
+ return r;
+ }
+
+ case INTVAR_EVENT:
+ {
+ Intvar_log_event* e = new Intvar_log_event(file, timestamp);
+ if (e->type == INVALID_INT_EVENT)
+ {
+ delete e;
+ return NULL;
+ }
+
+ return e;
+ }
+
+ case START_EVENT: return new Start_log_event(file, timestamp);
+ case STOP_EVENT: return new Stop_log_event(file, timestamp);
+ default: return NULL;
+ }
+
+ //impossible
+ return NULL;
+}
+
+Log_event* Log_event::read_log_event(const char* buf, int max_buf)
+{
+
+ switch(buf[EVENT_TYPE_OFFSET])
+ {
+ case QUERY_EVENT:
+ {
+ Query_log_event* q = new Query_log_event(buf, max_buf);
+ if (!q->query)
+ {
+ delete q;
+ return NULL;
+ }
+
+ return q;
+ }
+
+ case LOAD_EVENT:
+ {
+ Load_log_event* l = new Load_log_event(buf, max_buf);
+ if (!l->table_name)
+ {
+ delete l;
+ return NULL;
+ }
+
+ return l;
+ }
+
+ case ROTATE_EVENT:
+ {
+ Rotate_log_event* r = new Rotate_log_event(buf, max_buf);
+ 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);
+ default: return NULL;
+ }
+
+ //impossible
+ return NULL;
+}
+
+void Log_event::print_timestamp(FILE* file)
+{
+ struct tm tm_tmp;
+ localtime_r(&when,&tm_tmp);
+
+ fprintf(file,"#%02d%02d%02d %2d:%02d:%02d",
+ tm_tmp.tm_year % 100,
+ tm_tmp.tm_mon+1,
+ tm_tmp.tm_mday,
+ tm_tmp.tm_hour,
+ tm_tmp.tm_min,
+ tm_tmp.tm_sec);
+}
+
+
+void Start_log_event::print(FILE* file, bool short_form)
+{
+ if (short_form)
+ return;
+
+ print_timestamp(file);
+ fprintf(file, "\tStart\n");
+ fflush(file);
+}
+
+void Stop_log_event::print(FILE* file, bool short_form)
+{
+ if (short_form)
+ return;
+
+ print_timestamp(file);
+ fprintf(file, "\tStop\n");
+ fflush(file);
+}
+
+void Rotate_log_event::print(FILE* file, bool short_form)
+{
+ if (short_form)
+ return;
+
+ print_timestamp(file);
+ fprintf(file, "\tRotate to ");
+ if (new_log_ident)
+ my_fwrite(file, (byte*) new_log_ident, (uint)ident_len,
+ MYF(MY_NABP | MY_WME));
+ fprintf(file, "\n");
+ fflush(file);
+}
+
+Rotate_log_event::Rotate_log_event(FILE* file, time_t when_arg):
+ Log_event(when_arg),new_log_ident(NULL),alloced(0)
+{
+ char *tmp_ident;
+ char buf[4];
+
+ if (my_fread(file, (byte*) buf, sizeof(buf), MYF(MY_NABP | MY_WME)))
+ 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_fread( file, (byte*) tmp_ident, (uint)ident_len, MYF(MY_NABP | MY_WME)))
+ {
+ my_free((gptr) tmp_ident, MYF(0));
+ return;
+ }
+
+ new_log_ident = tmp_ident;
+ alloced = 1;
+}
+
+Rotate_log_event::Rotate_log_event(const char* buf, int max_buf):
+ Log_event(buf),new_log_ident(NULL),alloced(0)
+{
+ ulong event_len;
+ event_len = uint4korr(buf + EVENT_LEN_OFFSET);
+ if(event_len < ROTATE_EVENT_OVERHEAD || event_len > (ulong) max_buf)
+ return;
+
+ ident_len = (uchar)(event_len - ROTATE_EVENT_OVERHEAD);
+ if (!(new_log_ident = (char*) my_memdup((byte*) buf + LOG_EVENT_HEADER_LEN,
+ (uint) ident_len, MYF(MY_WME))))
+ return;
+
+ alloced = 1;
+}
+
+int Rotate_log_event::write_data(FILE* file)
+{
+ if (my_fwrite(file, (byte*) new_log_ident, (uint) ident_len,
+ MYF(MY_NABP | MY_WME)))
+ return -1;
+ return 0;
+}
+
+Query_log_event::Query_log_event(FILE* file, time_t when_arg):
+ Log_event(when_arg),data_buf(0),query(NULL),db(NULL)
+{
+ char buf[QUERY_HEADER_LEN + 4];
+ ulong data_len;
+ if (my_fread(file, (byte*) buf, sizeof(buf), MYF(MY_NABP | MY_WME)))
+ 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];
+
+ if (!(data_buf = (char*) my_malloc(data_len+1, MYF(MY_WME))))
+ return;
+ if (my_fread( file, (byte*) data_buf, data_len, MYF(MY_NABP | MY_WME)))
+ {
+ my_free((gptr) data_buf, MYF(0));
+ data_buf = 0;
+ return;
+ }
+
+ 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;
+}
+
+Query_log_event::Query_log_event(const char* buf, int max_buf):
+ Log_event(buf),data_buf(0), query(NULL), db(NULL)
+{
+ ulong data_len;
+ buf += EVENT_LEN_OFFSET;
+ data_len = uint4korr(buf);
+ if (data_len < QUERY_EVENT_OVERHEAD || data_len > (ulong) max_buf)
+ return; // tear-drop attack protection :)
+
+ data_len -= QUERY_EVENT_OVERHEAD;
+ exec_time = uint4korr(buf + 8);
+
+ if (!(data_buf = (char*) my_malloc( data_len + 1, MYF(MY_WME))))
+ return;
+
+ memcpy(data_buf, buf + 13, data_len);
+ thread_id = uint4korr(buf + 4);
+ db = data_buf;
+ db_len = (uint)buf[12];
+ query=data_buf + db_len + 1;
+ q_len = data_len - 1 - db_len;
+ *((char*)query+q_len) = 0;
+}
+
+void Query_log_event::print(FILE* file, bool short_form)
+{
+ if (!short_form)
+ {
+ print_timestamp(file);
+ fprintf(file, "\tQuery\tthread_id=%lu\texec_time=%lu\n",
+ (ulong) thread_id, (ulong) exec_time);
+ }
+
+ if(db && db[0])
+ fprintf(file, "use %s;\n", db);
+ my_fwrite(file, (byte*) query, q_len, MYF(MY_NABP | MY_WME));
+ fprintf(file, ";\n");
+}
+
+int Query_log_event::write_data(FILE* 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;
+
+
+ if (my_fwrite(file, (byte*) buf, (uint)(pos - buf), MYF(MY_NABP | MY_WME)) ||
+ my_fwrite(file, (db) ? (byte*) db : (byte*)"",
+ db_len + 1, MYF(MY_NABP | MY_WME)) ||
+ my_fwrite(file, (byte*) query, q_len, MYF(MY_NABP | MY_WME)))
+ return -1;
+ return 0;
+}
+
+Intvar_log_event:: Intvar_log_event(FILE* file, time_t when_arg)
+ :Log_event(when_arg), type(INVALID_INT_EVENT)
+{
+ my_fseek(file, 4L, MY_SEEK_CUR, MYF(MY_WME)); // skip the event length
+ char buf[9];
+ if(my_fread(file, (byte*)buf, sizeof(buf), MYF(MY_NABP|MY_WME))) return;
+ type = buf[0];
+ val = uint8korr(buf+1);
+}
+
+Intvar_log_event::Intvar_log_event(const char* buf):Log_event(buf)
+{
+ buf += LOG_EVENT_HEADER_LEN;
+ type = buf[0];
+ val = uint8korr(buf+1);
+}
+
+int Intvar_log_event::write_data(FILE* file)
+{
+ char buf[9];
+ buf[0] = type;
+ int8store(buf + 1, val);
+ return my_fwrite(file, (byte*) buf, sizeof(buf), MYF(MY_NABP|MY_WME));
+}
+
+void Intvar_log_event::print(FILE* file, bool short_form)
+{
+ char llbuff[22];
+ if(!short_form)
+ {
+ print_timestamp(file);
+ fprintf(file, "\tIntvar\n");
+ }
+
+ fprintf(file, "SET ");
+ switch(type)
+ {
+ case LAST_INSERT_ID_EVENT:
+ fprintf(file, "LAST_INSERT_ID = ");
+ break;
+ case INSERT_ID_EVENT:
+ fprintf(file, "INSERT_ID = ");
+ break;
+ }
+ fprintf(file, "%s;\n", llstr(val,llbuff));
+ fflush(file);
+
+}
+
+int Load_log_event::write_data(FILE* file __attribute__((unused)))
+{
+ 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_fwrite(file, (byte*)buf, sizeof(buf), MYF(MY_NABP|MY_WME)) ||
+ my_fwrite(file, (byte*)&sql_ex, sizeof(sql_ex), MYF(MY_NABP|MY_WME)))
+ return 1;
+
+ if(num_fields && fields && field_lens)
+ {
+ if(my_fwrite(file, (byte*)field_lens, num_fields, MYF(MY_NABP|MY_WME)) ||
+ my_fwrite(file, (byte*)fields, field_block_len, MYF(MY_NABP|MY_WME)))
+ return 1;
+ }
+
+ if(my_fwrite(file, (byte*)table_name, table_name_len + 1, MYF(MY_NABP|MY_WME)) ||
+ my_fwrite(file, (byte*)db, db_len + 1, MYF(MY_NABP|MY_WME)) ||
+ my_fwrite(file, (byte*)fname, fname_len, MYF(MY_NABP|MY_WME)) )
+ return 1;
+
+
+ return 0;
+}
+
+Load_log_event::Load_log_event(FILE* file, time_t when):
+ Log_event(when),data_buf(0),num_fields(0),fields(0),field_lens(0),field_block_len(0),
+ table_name(0),db(0),fname(0)
+
+{
+ char buf[LOAD_HEADER_LEN + 4];
+ ulong data_len;
+ if(my_fread(file, (byte*)buf, sizeof(buf), MYF(MY_NABP|MY_WME)) ||
+ my_fread(file, (byte*)&sql_ex, sizeof(sql_ex), MYF(MY_NABP|MY_WME)))
+ return;
+
+ data_len = uint4korr(buf);
+ 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);
+
+ data_len -= LOAD_EVENT_OVERHEAD;
+ if(!(data_buf = (char*)my_malloc(data_len + 1, MYF(MY_WME))))
+ return;
+
+ if(my_fread(file, (byte*)data_buf, data_len, MYF(MY_NABP|MY_WME)))
+ return;
+
+ if(num_fields > data_len) // simple sanity check against corruption
+ return;
+
+ field_lens = (uchar*)data_buf;
+
+ 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;
+}
+
+Load_log_event::Load_log_event(const char* buf, int max_buf):
+ Log_event(when),data_buf(0),num_fields(0),fields(0),field_lens(0),field_block_len(0),
+ table_name(0),db(0),fname(0)
+
+{
+ ulong data_len;
+
+ if((uint)max_buf < (LOAD_EVENT_OVERHEAD + LOG_EVENT_HEADER_LEN))
+ return;
+
+ buf += EVENT_LEN_OFFSET;
+
+ data_len = uint4korr(buf);
+ if((uint)data_len > (uint)max_buf)
+ return;
+
+ 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);
+
+ data_len -= LOAD_EVENT_OVERHEAD;
+ memcpy(&sql_ex, buf + 22, sizeof(sql_ex));
+
+ if(!(data_buf = (char*)my_malloc(data_len + 1, MYF(MY_WME))))
+ return;
+
+ memcpy(data_buf, buf + 22 + sizeof(sql_ex), data_len);
+
+ if(num_fields > data_len) // simple sanity check against corruption
+ return;
+
+ field_lens = (uchar*)data_buf;
+
+ 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;
+
+}
+
+
+void Load_log_event::print(FILE* file, bool short_form)
+{
+ if (!short_form)
+ {
+ print_timestamp(file);
+ fprintf(file, "\tQuery\tthread_id=%d\texec_time=%ld\n",
+ thread_id, exec_time);
+ }
+
+ if(db && db[0])
+ fprintf(file, "use %s;\n", db);
+
+ fprintf(file, "LOAD DATA INFILE '%s' ", fname);
+
+ if(sql_ex.opt_flags && REPLACE_FLAG )
+ fprintf(file," REPLACE ");
+ else if(sql_ex.opt_flags && IGNORE_FLAG )
+ fprintf(file," IGNORE ");
+
+ fprintf(file, "INTO TABLE %s ", table_name);
+ if(!(sql_ex.empty_flags & FIELD_TERM_EMPTY))
+ {
+ fprintf(file, " FIELDS TERMINATED BY ");
+ pretty_print_char(file, sql_ex.field_term);
+ }
+
+ if(!(sql_ex.empty_flags & ENCLOSED_EMPTY))
+ {
+ if(sql_ex.opt_flags && OPT_ENCLOSED_FLAG )
+ fprintf(file," OPTIONALLY ");
+ fprintf(file, " ENCLOSED BY ");
+ pretty_print_char(file, sql_ex.enclosed);
+ }
+
+ if(!(sql_ex.empty_flags & ESCAPED_EMPTY))
+ {
+ fprintf(file, " ESCAPED BY ");
+ pretty_print_char(file, sql_ex.escaped);
+ }
+
+ if(!(sql_ex.empty_flags & LINE_TERM_EMPTY))
+ {
+ fprintf(file," LINES TERMINATED BY ");
+ pretty_print_char(file, sql_ex.line_term);
+ }
+
+ if(!(sql_ex.empty_flags & LINE_START_EMPTY))
+ {
+ fprintf(file," LINES STARTING BY ");
+ pretty_print_char(file, sql_ex.line_start);
+ }
+
+ if((int)skip_lines > 0)
+ fprintf(file, " IGNORE %d LINES ", skip_lines);
+
+ if(num_fields)
+ {
+ uint i;
+ const char* field = fields;
+ fprintf( file, " (");
+ for(i = 0; i < num_fields; i++)
+ {
+ if(i)
+ fputc(',', file);
+ fprintf(file, field);
+
+ field += field_lens[i] + 1;
+ }
+ fputc(')', file);
+ }
+
+ fprintf(file, ";\n");
+}
+
+#ifndef MYSQL_CLIENT
+
+void Load_log_event::set_fields(List<Item> &fields)
+{
+ uint i;
+ const char* field = this->fields;
+ for(i = 0; i < num_fields; i++)
+ {
+ fields.push_back(new Item_field(db, table_name, field));
+ field += field_lens[i] + 1;
+ }
+
+}
+
+#endif
diff --git a/sql/log_event.h b/sql/log_event.h
new file mode 100644
index 00000000000..fb585f01dea
--- /dev/null
+++ b/sql/log_event.h
@@ -0,0 +1,354 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 _LOG_EVENT_H
+#define _LOG_EVENT_H
+
+#if defined(__GNUC__) && !defined(MYSQL_CLIENT)
+#pragma interface /* gcc class implementation */
+#endif
+
+#define LOG_READ_EOF -1
+#define LOG_READ_BOGUS -2
+#define LOG_READ_IO -3
+#define LOG_READ_MEM -5
+
+#define LOG_EVENT_OFFSET 4
+
+
+enum Log_event_type { START_EVENT = 1, QUERY_EVENT =2,
+ STOP_EVENT=3, ROTATE_EVENT = 4, INTVAR_EVENT=5,
+ LOAD_EVENT=6};
+enum Int_event_type { INVALID_INT_EVENT = 0, LAST_INSERT_ID_EVENT = 1, INSERT_ID_EVENT = 2
+ };
+
+#ifndef MYSQL_CLIENT
+class String;
+#endif
+
+class Log_event
+{
+public:
+ time_t when;
+ ulong exec_time;
+ int valid_exec_time; // if false, the exec time setting is bogus and needs
+
+ int write(FILE* file);
+ int write_header(FILE* file);
+ virtual int write_data(FILE* 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): when(when_arg),
+ exec_time(exec_time_arg), valid_exec_time(valid_exec_time_arg) {}
+
+ Log_event(const char* buf): valid_exec_time(1)
+ {
+ when = uint4korr(buf);
+ exec_time = uint4korr(buf + 5);
+ }
+
+ virtual ~Log_event() {}
+
+ virtual int get_data_size() { return 0;}
+ virtual void print(FILE* file, bool short_form = 0) = 0;
+
+ void print_timestamp(FILE* file);
+
+ static Log_event* read_log_event(FILE* file);
+ static Log_event* read_log_event(const char* buf, int max_buf);
+
+#ifndef MYSQL_CLIENT
+ static int read_log_event(FILE* file, String* packet);
+#endif
+
+};
+
+
+class Query_log_event: public Log_event
+{
+protected:
+ char* data_buf;
+public:
+ const char* query;
+ const char* db;
+ uint q_len; // if we already know the length of the query string
+ // we pass it here, so we would not have to call strlen()
+ // otherwise, set it to 0, in which case, we compute it with strlen()
+ uint db_len;
+ int thread_id;
+#if !defined(MYSQL_CLIENT)
+ THD* thd;
+ Query_log_event(THD* thd_arg, const char* query_arg):
+ Log_event(thd_arg->start_time), data_buf(0),
+ query(query_arg), db(thd_arg->db), q_len(thd_arg->query_length),
+ thread_id(thd_arg->thread_id), thd(thd_arg)
+ {
+ time_t end_time;
+ time(&end_time);
+ exec_time = end_time - thd->start_time;
+ valid_exec_time = 1;
+ db_len = (db) ? strlen(db) : 0;
+ }
+#endif
+
+ Query_log_event(FILE* file, time_t when);
+ Query_log_event(const char* buf, int max_buf);
+ ~Query_log_event()
+ {
+ if (data_buf)
+ {
+ my_free((gptr)data_buf, MYF(0));
+ }
+ }
+ Log_event_type get_type_code() { return QUERY_EVENT; }
+ int write(FILE* file);
+ int write_data(FILE* file); // returns 0 on success, -1 on error
+ int get_data_size()
+ {
+ return q_len + db_len + 2 +
+ sizeof(uint) // thread_id
+ + sizeof(uint) // exec_time
+ ;
+ }
+
+ void print(FILE* file, bool short_form = 0);
+};
+
+#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 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;
+public:
+ int thread_id;
+ uint table_name_len;
+ uint db_len;
+ uint fname_len;
+ uint num_fields;
+ const char* fields;
+ const uchar* field_lens;
+ uint field_block_len;
+
+
+ const char* table_name;
+ const char* db;
+ const char* fname;
+ uint skip_lines;
+ 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* table_name,
+ List<Item>& fields, 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),
+ db(thd->db),
+ fname(ex->file_name),
+ thd(thd)
+ {
+ time_t end_time;
+ time(&end_time);
+ exec_time = end_time - thd->start_time;
+ valid_exec_time = 1;
+ db_len = (db) ? strlen(db) : 0;
+ table_name_len = (table_name) ? strlen(table_name) : 0;
+ fname_len = (fname) ? 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);
+ 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();
+ this->fields = fields_buf.ptr();
+ }
+ void set_fields(List<Item> &fields);
+#endif
+
+ Load_log_event(FILE* file, time_t when);
+ Load_log_event(const char* buf, int max_buf);
+ ~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(FILE* file); // returns 0 on success, -1 on error
+ int get_data_size()
+ {
+ return table_name_len + 2 + db_len + 2 + fname_len
+ + sizeof(thread_id) // thread_id
+ + sizeof(exec_time) // exec_time
+ + sizeof(skip_lines)
+ + sizeof(field_block_len)
+ + sizeof(sql_ex) + field_block_len + num_fields*sizeof(uchar) ;
+ ;
+ }
+
+ void print(FILE* file, bool short_form = 0);
+};
+
+
+class Start_log_event: public Log_event
+{
+public:
+ Start_log_event() :Log_event(time(NULL))
+ {}
+ Start_log_event(FILE* file, time_t when_arg) :Log_event(when_arg)
+ {
+ my_fseek(file, 4L, MY_SEEK_CUR, MYF(MY_WME)); // skip the event length
+ }
+ Start_log_event(const char* buf) :Log_event(buf)
+ {
+ }
+ ~Start_log_event() {}
+ Log_event_type get_type_code() { return START_EVENT;}
+ void print(FILE* file, bool short_form = 0);
+};
+
+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)
+ {}
+ Intvar_log_event(FILE* file, time_t when);
+ Intvar_log_event(const char* buf);
+ ~Intvar_log_event() {}
+ Log_event_type get_type_code() { return INTVAR_EVENT;}
+ int get_data_size() { return sizeof(type) + sizeof(val);}
+ int write_data(FILE* file);
+
+
+ void print(FILE* file, bool short_form = 0);
+};
+
+class Stop_log_event: public Log_event
+{
+public:
+ Stop_log_event() :Log_event(time(NULL))
+ {}
+ Stop_log_event(FILE* file, time_t when_arg): Log_event(when_arg)
+ {
+ my_fseek(file, 4L, MY_SEEK_CUR, MYF(MY_WME)); // skip the event length
+ }
+ Stop_log_event(const char* buf):Log_event(buf)
+ {
+ }
+ ~Stop_log_event() {}
+ Log_event_type get_type_code() { return STOP_EVENT;}
+ void print(FILE* file, bool short_form = 0);
+};
+
+class Rotate_log_event: public Log_event
+{
+public:
+ const char* new_log_ident;
+ uchar ident_len;
+ bool alloced;
+
+ Rotate_log_event(const char* new_log_ident_arg, uint ident_len_arg = 0) :
+ Log_event(time(NULL)),
+ new_log_ident(new_log_ident_arg),
+ ident_len(ident_len_arg ? ident_len_arg : strlen(new_log_ident_arg)),
+ alloced(0)
+ {}
+
+ Rotate_log_event(FILE* file, time_t when) ;
+ Rotate_log_event(const char* buf, int max_buf);
+ ~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 write_data(FILE* file);
+
+ void print(FILE* file, bool short_form = 0);
+};
+
+#endif
diff --git a/sql/matherr.c b/sql/matherr.c
new file mode 100644
index 00000000000..8523a78ce94
--- /dev/null
+++ b/sql/matherr.c
@@ -0,0 +1,43 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 <errno.h>
+
+ /* Fix that we gets POSTFIX_ERROR when error in math */
+
+#if defined(HAVE_MATHERR)
+int matherr(struct exception *x)
+{
+ if (x->type != PLOSS)
+ x->retval=POSTFIX_ERROR;
+ switch (x->type) {
+ case DOMAIN:
+ case SING:
+ my_errno=EDOM;
+ break;
+ case OVERFLOW:
+ case UNDERFLOW:
+ my_errno=ERANGE;
+ break;
+ default:
+ break;
+ }
+ return(1); /* Take no other action */
+}
+#endif
diff --git a/sql/md5.c b/sql/md5.c
new file mode 100644
index 00000000000..0775ba3bd1a
--- /dev/null
+++ b/sql/md5.c
@@ -0,0 +1,351 @@
+/* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm
+ */
+
+/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+rights reserved.
+
+License to copy and use this software is granted provided that it
+is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+Algorithm" in all material mentioning or referencing this software
+or this function.
+
+License is also granted to make and use derivative works provided
+that such works are identified as "derived from the RSA Data
+Security, Inc. MD5 Message-Digest Algorithm" in all material
+mentioning or referencing the derived work.
+
+RSA Data Security, Inc. makes no representations concerning either
+the merchantability of this software or the suitability of this
+software for any particular purpose. It is provided "as is"
+without express or implied warranty of any kind.
+
+These notices must be retained in any copies of any part of this
+documentation and/or software.
+*/
+
+/*
+ Changes by Monty:
+ Replace of MD5_memset and MD5_memcpy with memset & memcpy
+*/
+
+#include <global.h>
+#include <m_string.h>
+#include "md5.h"
+
+/* Constants for MD5Transform routine. */
+
+#define S11 7
+#define S12 12
+#define S13 17
+#define S14 22
+#define S21 5
+#define S22 9
+#define S23 14
+#define S24 20
+#define S31 4
+#define S32 11
+#define S33 16
+#define S34 23
+#define S41 6
+#define S42 10
+#define S43 15
+#define S44 21
+
+
+static void MD5Transform PROTO_LIST ((UINT4 [4], unsigned char [64]));
+static void Encode PROTO_LIST
+ ((unsigned char *, UINT4 *, unsigned int));
+static void Decode PROTO_LIST
+ ((UINT4 *, unsigned char *, unsigned int));
+#ifdef OLD_CODE
+static void MD5_memcpy PROTO_LIST ((POINTER, POINTER, unsigned int));
+static void MD5_memset PROTO_LIST ((POINTER, int, unsigned int));
+#else
+#define MD5_memcpy(A,B,C) memcpy((char*) (A),(char*) (B), (C))
+#define MD5_memset(A,B,C) memset((char*) (A),(B), (C))
+#endif
+
+static unsigned char PADDING[64] = {
+ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/* F, G, H and I are basic MD5 functions.
+ */
+#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
+#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define I(x, y, z) ((y) ^ ((x) | (~z)))
+
+/* ROTATE_LEFT rotates x left n bits.
+ */
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
+
+/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
+Rotation is separate from addition to prevent recomputation.
+ */
+#define FF(a, b, c, d, x, s, ac) { \
+ (a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define GG(a, b, c, d, x, s, ac) { \
+ (a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define HH(a, b, c, d, x, s, ac) { \
+ (a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define II(a, b, c, d, x, s, ac) { \
+ (a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+
+/* MD5 initialization. Begins an MD5 operation, writing a new context.
+ */
+void MD5Init (MD5_CTX *context) /* context */
+{
+ context->count[0] = context->count[1] = 0;
+ /* Load magic initialization constants.
+*/
+ context->state[0] = 0x67452301;
+ context->state[1] = 0xefcdab89;
+ context->state[2] = 0x98badcfe;
+ context->state[3] = 0x10325476;
+}
+
+/* MD5 block update operation. Continues an MD5 message-digest
+ operation, processing another message block, and updating the
+ context.
+ */
+void MD5Update (context, input, inputLen)
+MD5_CTX *context; /* context */
+unsigned char *input; /* input block */
+unsigned int inputLen; /* length of input block */
+{
+ unsigned int i, idx, partLen;
+
+ /* Compute number of bytes mod 64 */
+ idx = (unsigned int)((context->count[0] >> 3) & 0x3F);
+
+
+ /* Update number of bits */
+ if ((context->count[0] += ((UINT4)inputLen << 3))
+ < ((UINT4)inputLen << 3))
+ context->count[1]++;
+ context->count[1] += ((UINT4)inputLen >> 29);
+
+ partLen = 64 - idx;
+
+ /* Transform as many times as possible.
+*/
+ if (inputLen >= partLen) {
+ MD5_memcpy((POINTER)&context->buffer[idx], (POINTER)input, partLen);
+ MD5Transform(context->state, context->buffer);
+
+ for (i = partLen; i + 63 < inputLen; i += 64)
+ MD5Transform (context->state, &input[i]);
+
+ idx = 0;
+ }
+ else
+ i = 0;
+
+ /* Buffer remaining input */
+ MD5_memcpy((POINTER)&context->buffer[idx], (POINTER)&input[i],
+ inputLen-i);
+}
+
+/* MD5 finalization. Ends an MD5 message-digest operation, writing the
+ the message digest and zeroizing the context.
+ */
+void MD5Final (digest, context)
+unsigned char digest[16]; /* message digest */
+MD5_CTX *context; /* context */
+{
+ unsigned char bits[8];
+ unsigned int idx, padLen;
+
+ /* Save number of bits */
+ Encode (bits, context->count, 8);
+
+ /* Pad out to 56 mod 64.
+*/
+ idx = (unsigned int)((context->count[0] >> 3) & 0x3f);
+ padLen = (idx < 56) ? (56 - idx) : (120 - idx);
+ MD5Update (context, PADDING, padLen);
+
+ /* Append length (before padding) */
+ MD5Update (context, bits, 8);
+
+ /* Store state in digest */
+ Encode (digest, context->state, 16);
+
+ /* Zeroize sensitive information.
+*/
+ MD5_memset ((POINTER)context, 0, sizeof (*context));
+}
+
+/* MD5 basic transformation. Transforms state based on block.
+ */
+static void MD5Transform (state, block)
+UINT4 state[4];
+unsigned char block[64];
+{
+ UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
+
+ Decode (x, block, 64);
+
+ /* Round 1 */
+ FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
+ FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
+ FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
+ FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
+ FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
+ FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
+ FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
+ FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
+ FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
+ FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
+ FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
+ FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
+ FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
+ FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
+ FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
+ FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
+
+ /* Round 2 */
+ GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
+ GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
+ GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
+ GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
+ GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
+ GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */
+ GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
+ GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
+ GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
+ GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
+ GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
+ GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
+ GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
+ GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
+ GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
+ GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
+
+ /* Round 3 */
+ HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
+ HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
+ HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
+ HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
+ HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
+ HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
+ HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
+ HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
+ HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
+ HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
+ HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
+ HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */
+ HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
+ HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
+ HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
+ HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
+
+ /* Round 4 */
+ II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
+ II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
+ II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
+ II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
+ II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
+ II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
+ II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
+ II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
+ II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
+ II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
+ II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
+ II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
+ II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
+ II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
+ II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
+ II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
+
+
+ state[0] += a;
+ state[1] += b;
+ state[2] += c;
+ state[3] += d;
+
+ /* Zeroize sensitive information.
+*/
+ MD5_memset ((POINTER)x, 0, sizeof (x));
+}
+
+/* Encodes input (UINT4) into output (unsigned char). Assumes len is
+ a multiple of 4.
+ */
+static void Encode (output, input, len)
+unsigned char *output;
+UINT4 *input;
+unsigned int len;
+{
+ unsigned int i, j;
+
+ for (i = 0, j = 0; j < len; i++, j += 4) {
+ output[j] = (unsigned char)(input[i] & 0xff);
+ output[j+1] = (unsigned char)((input[i] >> 8) & 0xff);
+ output[j+2] = (unsigned char)((input[i] >> 16) & 0xff);
+ output[j+3] = (unsigned char)((input[i] >> 24) & 0xff);
+ }
+}
+
+
+/* Decodes input (unsigned char) into output (UINT4). Assumes len is
+ a multiple of 4.
+ */
+static void Decode (output, input, len)
+UINT4 *output;
+unsigned char *input;
+unsigned int len;
+{
+ unsigned int i, j;
+
+ for (i = 0, j = 0; j < len; i++, j += 4)
+ output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) |
+ (((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24);
+}
+
+/* Note: Replace "for loop" with standard memcpy if possible.
+ */
+
+#ifndef MD5_memcpy
+static void MD5_memcpy (output, input, len)
+POINTER output;
+POINTER input;
+unsigned int len;
+{
+ unsigned int i;
+
+ for (i = 0; i < len; i++)
+ output[i] = input[i];
+}
+#endif
+
+/* Note: Replace "for loop" with standard memset if possible.
+ */
+
+#ifndef MD5_memset
+static void MD5_memset (output, value, len)
+POINTER output;
+int value;
+unsigned int len;
+{
+ unsigned int i;
+
+ for (i = 0; i < len; i++)
+ ((char *)output)[i] = (char)value;
+}
+#endif
diff --git a/sql/md5.h b/sql/md5.h
new file mode 100644
index 00000000000..862129391f1
--- /dev/null
+++ b/sql/md5.h
@@ -0,0 +1,80 @@
+
+/* MD5.H - header file for MD5C.C
+ */
+
+/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+rights reserved.
+
+License to copy and use this software is granted provided that it
+is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+Algorithm" in all material mentioning or referencing this software
+or this function.
+
+License is also granted to make and use derivative works provided
+that such works are identified as "derived from the RSA Data
+Security, Inc. MD5 Message-Digest Algorithm" in all material
+mentioning or referencing the derived work.
+
+RSA Data Security, Inc. makes no representations concerning either
+the merchantability of this software or the suitability of this
+software for any particular purpose. It is provided "as is"
+without express or implied warranty of any kind.
+
+These notices must be retained in any copies of any part of this
+documentation and/or software.
+ */
+
+/* GLOBAL.H - RSAREF types and constants
+ */
+
+/* PROTOTYPES should be set to one if and only if the compiler supports
+ function argument prototyping.
+The following makes PROTOTYPES default to 0 if it has not already
+ been defined with C compiler flags.
+ */
+
+/* egcs 1.1.2 under linux didn't defined it.... :( */
+
+#ifndef PROTOTYPES
+#define PROTOTYPES 1 /* Assume prototypes */
+#endif
+
+/* POINTER defines a generic pointer type */
+typedef unsigned char *POINTER;
+
+/* UINT2 defines a two byte word */
+typedef uint16 UINT2; /* Fix for MySQL / Alpha */
+
+/* UINT4 defines a four byte word */
+typedef uint32 UINT4; /* Fix for MySQL / Alpha */
+
+/* PROTO_LIST is defined depending on how PROTOTYPES is defined above.
+If using PROTOTYPES, then PROTO_LIST returns the list, otherwise it
+ returns an empty list.
+ */
+#if PROTOTYPES
+#define PROTO_LIST(list) list
+#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;
+
+#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 *));
+
+#ifdef __cplusplus
+}
+#endif
+
diff --git a/sql/mf_iocache.cc b/sql/mf_iocache.cc
new file mode 100644
index 00000000000..e5ecc4bb428
--- /dev/null
+++ b/sql/mf_iocache.cc
@@ -0,0 +1,641 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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-
+ length records. A read isn't allowed to go over file-length. A read is ok
+ if it ends at file-length and next read can try to read after file-length
+ (and get a EOF-error).
+ 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.
+ 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.
+ 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().
+*/
+
+#define MAP_TO_USE_RAID
+#include "mysql_priv.h"
+#include <mysys_err.h>
+#ifdef HAVE_AIOWAIT
+#include <errno.h>
+static void my_aiowait(my_aio_result *result);
+#endif
+
+ /* if cachesize == 0 then use default cachesize (from s-file) */
+ /* returns 0 if we have enough memory */
+
+extern "C" {
+
+
+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 */
+ 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;
+ info->pos_in_file= seek_offset;
+ 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 || type == READ_NET) /* the same logic */
+ {
+ 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));
+ }
+ info->end_of_file=(type == READ_NET) ? 0 : MY_FILEPOS_ERROR; /* May be changed by user */
+ 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 (!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 (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);
+#ifdef HAVE_AIOWAIT
+ my_aiowait(&info->aio_result); /* Wait for outstanding req */
+#endif
+ }
+ else
+ {
+ if (info->type == WRITE_CACHE && type == READ_CACHE)
+ info->end_of_file=my_b_tell(info);
+ if (flush_io_cache(info))
+ DBUG_RETURN(1);
+ info->pos_in_file=seek_offset;
+ info->rc_request_pos=info->rc_pos=info->buffer;
+ if (type == READ_CACHE || type == READ_NET)
+ {
+ 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) ? 0 : MY_FILEPOS_ERROR;
+ }
+ }
+ 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 */
+ /* Returns 0 if record read */
+
+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;
+ 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 (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->end_of_file - pos_in_file;
+ if (max_length > info->read_length-diff_length)
+ max_length=info->read_length-diff_length;
+ 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
+ */
+
+int _my_b_net_read(register IO_CACHE *info, byte *Buffer,
+ uint Count __attribute__((unused)))
+{
+ int read_length;
+ NET *net= &(current_thd)->net;
+
+ if (info->end_of_file)
+ 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)
+ {
+ info->error=(uint) -1;
+ return 1;
+ }
+ if (read_length == 0)
+ {
+ /* End of file from client */
+ info->end_of_file = 1; 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 (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 */
+ VOID(my_seek(info->file,info->pos_in_file,MY_SEEK_SET,MYF(0)));
+ 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
+ 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 */
+
+}
diff --git a/sql/mini_client.cc b/sql/mini_client.cc
new file mode 100644
index 00000000000..49433bdf96a
--- /dev/null
+++ b/sql/mini_client.cc
@@ -0,0 +1,801 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/*
+ mini MySQL client to be included into the server to do server to server
+ commincation by Sasha Pachev
+
+ Note: all file-global symbols must begin with mc_ , even the static ones, just
+ in case we decide to make them external at some point
+ */
+
+#define DONT_USE_RAID
+#if defined(__WIN__) || defined(WIN32)
+#include <winsock.h>
+#include <odbcinst.h>
+#endif
+#include <global.h>
+#include <my_sys.h>
+#include <mysys_err.h>
+#include <m_string.h>
+#include <m_ctype.h>
+#include "mysql.h"
+#include "mini_client.h"
+#include "mysql_version.h"
+#include "mysqld_error.h"
+#include "errmsg.h"
+#include <violite.h>
+#include <sys/stat.h>
+#include <signal.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
+#if defined(THREAD) && !defined(__WIN__)
+#include <my_pthread.h> /* because of signal() */
+#endif
+#ifndef INADDR_NONE
+#define INADDR_NONE -1
+#endif
+
+
+static 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);
+
+
+#define CLIENT_CAPABILITIES (CLIENT_LONG_PASSWORD | CLIENT_LONG_FLAG | CLIENT_LOCAL_FILES)
+
+#if defined(MSDOS) || defined(__WIN__)
+#define ERRNO WSAGetLastError()
+#define perror(A)
+#else
+#include <sys/errno.h>
+#define ERRNO errno
+#define SOCKET_ERROR -1
+#define closesocket(A) close(A)
+#endif
+
+#ifdef __WIN__
+static my_bool is_NT(void)
+{
+ char *os=getenv("OS");
+ return (os && !strcmp(os, "Windows_NT")) ? 1 : 0;
+}
+#endif
+
+/*
+** Create a named pipe connection
+*/
+
+#ifdef __WIN__
+
+HANDLE create_named_pipe(NET *net, uint connect_timeout, char **arg_host,
+ char **arg_unix_socket)
+{
+ HANDLE hPipe=INVALID_HANDLE_VALUE;
+ char szPipeName [ 257 ];
+ DWORD dwMode;
+ int i;
+ my_bool testing_named_pipes=0;
+ char *host= *arg_host, *unix_socket= *arg_unix_socket;
+
+ if (!host || !strcmp(host,LOCAL_HOST))
+ host=LOCAL_HOST_NAMEDPIPE;
+
+ sprintf( szPipeName, "\\\\%s\\pipe\\%s", host, unix_socket);
+ DBUG_PRINT("info",("Server name: '%s'. Named Pipe: %s",
+ host, unix_socket));
+
+ for (i=0 ; i < 100 ; i++) /* Don't retry forever */
+ {
+ if ((hPipe = CreateFile(szPipeName,
+ GENERIC_READ | GENERIC_WRITE,
+ 0,
+ NULL,
+ OPEN_EXISTING,
+ 0,
+ NULL )) != INVALID_HANDLE_VALUE)
+ break;
+ if (GetLastError() != ERROR_PIPE_BUSY)
+ {
+ net->last_errno=CR_NAMEDPIPEOPEN_ERROR;
+ sprintf(net->last_error,ER(net->last_errno),host, unix_socket,
+ (ulong) GetLastError());
+ return INVALID_HANDLE_VALUE;
+ }
+ /* wait for for an other instance */
+ if (! WaitNamedPipe(szPipeName, connect_timeout*1000) )
+ {
+ net->last_errno=CR_NAMEDPIPEWAIT_ERROR;
+ sprintf(net->last_error,ER(net->last_errno),host, unix_socket,
+ (ulong) GetLastError());
+ return INVALID_HANDLE_VALUE;
+ }
+ }
+ if (hPipe == INVALID_HANDLE_VALUE)
+ {
+ net->last_errno=CR_NAMEDPIPEOPEN_ERROR;
+ sprintf(net->last_error,ER(net->last_errno),host, unix_socket,
+ (ulong) GetLastError());
+ return INVALID_HANDLE_VALUE;
+ }
+ dwMode = PIPE_READMODE_BYTE | PIPE_WAIT;
+ if ( !SetNamedPipeHandleState(hPipe, &dwMode, NULL, NULL) )
+ {
+ CloseHandle( hPipe );
+ net->last_errno=CR_NAMEDPIPESETSTATE_ERROR;
+ sprintf(net->last_error,ER(net->last_errno),host, unix_socket,
+ (ulong) GetLastError());
+ return INVALID_HANDLE_VALUE;
+ }
+ *arg_host=host ; *arg_unix_socket=unix_socket; /* connect arg */
+ return (hPipe);
+}
+#endif
+
+
+/****************************************************************************
+** Init MySQL structure or allocate one
+****************************************************************************/
+
+MYSQL * STDCALL
+mc_mysql_init(MYSQL *mysql)
+{
+ init_client_errs();
+ 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)));
+#ifdef __WIN__
+ mysql->options.connect_timeout=20;
+#endif
+ return mysql;
+}
+
+/**************************************************************************
+** Shut down connection
+**************************************************************************/
+
+static void
+mc_end_server(MYSQL *mysql)
+{
+ DBUG_ENTER("mc_end_server");
+ if (mysql->net.vio != 0)
+ {
+ DBUG_PRINT("info",("Net: %s", vio_description(mysql->net.vio)));
+ vio_delete(mysql->net.vio);
+ mysql->net.vio= 0; /* Marker */
+ }
+ net_end(&mysql->net);
+ mc_free_old_query(mysql);
+ DBUG_VOID_RETURN;
+}
+
+static void mc_free_old_query(MYSQL *mysql)
+{
+ DBUG_ENTER("mc_free_old_query");
+ if (mysql->fields)
+ free_root(&mysql->field_alloc);
+ init_alloc_root(&mysql->field_alloc,8192); /* Assume rowlength < 8192 */
+ mysql->fields=0;
+ mysql->field_count=0; /* For API */
+ DBUG_VOID_RETURN;
+}
+
+
+/****************************************************************************
+* A modified version of connect(). mc_sock_connect() 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,
+* mc_sock_connect() will behave exactly like connect().
+*
+* Base version coded by Steve Bernacki, Jr. <steve@navinet.net>
+*****************************************************************************/
+
+static int mc_sock_connect(File s, const struct sockaddr *name, uint namelen, uint to)
+{
+#if defined(__WIN__)
+ return connect(s, (struct sockaddr*) name, namelen);
+#else
+ int flags, res, s_err;
+ size_socket s_err_size = sizeof(uint);
+ fd_set sfds;
+ struct timeval tv;
+
+ /* If they passed us a timeout of zero, we should behave
+ * exactly like the normal connect() call does.
+ */
+
+ if (to == 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);
+ tv.tv_sec = (long) to;
+ tv.tv_usec = 0;
+#ifdef HPUX
+ res = select(s+1, NULL, (int*) &sfds, NULL, &tv);
+#else
+ res = select(s+1, NULL, &sfds, NULL, &tv);
+#endif
+ if (res <= 0) /* Never became writable */
+ 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 suceed */
+ errno = s_err;
+ return(-1); /* but return an error... */
+ }
+ return(0); /* It's all good! */
+#endif
+}
+
+/*****************************************************************************
+** read a packet from server. Give error message if socket was down
+** or packet is an error message
+*****************************************************************************/
+
+uint STDCALL
+mc_net_safe_read(MYSQL *mysql)
+{
+ NET *net= &mysql->net;
+ uint len=0;
+
+ if (net->vio != 0)
+ len=my_net_read(net);
+
+ if (len == packet_error || len == 0)
+ {
+ DBUG_PRINT("error",("Wrong connection or packet. fd: %s len: %d",
+ vio_description(net->vio),len));
+ if(errno != EINTR)
+ {
+ mc_end_server(mysql);
+ net->last_errno=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;
+ if(!net->last_errno)
+ net->last_errno = CR_UNKNOWN_ERROR;
+ }
+ 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;
+}
+
+
+char * STDCALL mc_mysql_error(MYSQL *mysql)
+{
+ return (mysql)->net.last_error;
+}
+
+my_bool STDCALL mc_mysql_reconnect(MYSQL *mysql)
+{
+ MYSQL tmp_mysql;
+ DBUG_ENTER("mc_mysql_reconnect");
+
+ mc_mysql_init(&tmp_mysql);
+ tmp_mysql.options=mysql->options;
+ if (!mc_mysql_connect(&tmp_mysql,mysql->host,mysql->user,mysql->passwd,
+ mysql->db, mysql->port, mysql->unix_socket,
+ mysql->client_flag))
+ DBUG_RETURN(1);
+ tmp_mysql.free_me=mysql->free_me;
+ mysql->free_me=0;
+ bzero((char*) &mysql->options,sizeof(&mysql->options));
+ mc_mysql_close(mysql);
+ *mysql=tmp_mysql;
+ net_clear(&mysql->net);
+ mysql->affected_rows= ~(my_ulonglong) 0;
+ DBUG_RETURN(0);
+}
+
+
+
+int STDCALL
+mc_simple_command(MYSQL *mysql,enum enum_server_command command, const char *arg,
+ uint length, my_bool skipp_check)
+{
+ NET *net= &mysql->net;
+ int result= -1;
+
+ if (mysql->net.vio == 0)
+ { /* Do reconnect if possible */
+ if (mc_mysql_reconnect(mysql))
+ {
+ net->last_errno=CR_SERVER_GONE_ERROR;
+ strmov(net->last_error,ER(net->last_errno));
+ goto end;
+ }
+ }
+ if (mysql->status != MYSQL_STATUS_READY)
+ {
+ strmov(net->last_error,ER(mysql->net.last_errno=CR_COMMANDS_OUT_OF_SYNC));
+ goto end;
+ }
+
+ mysql->net.last_error[0]=0;
+ mysql->net.last_errno=0;
+ mysql->info=0;
+ mysql->affected_rows= ~(my_ulonglong) 0;
+ net_clear(net); /* Clear receive buffer */
+ if (!arg)
+ arg="";
+
+ if (net_write_command(net,(uchar) command,arg,
+ length ? length :strlen(arg)))
+ {
+ DBUG_PRINT("error",("Can't send command to server. Error: %d",errno));
+ mc_end_server(mysql);
+ if (mc_mysql_reconnect(mysql) ||
+ net_write_command(net,(uchar) command,arg,
+ length ? length :strlen(arg)))
+ {
+ net->last_errno=CR_SERVER_GONE_ERROR;
+ strmov(net->last_error,ER(net->last_errno));
+ goto end;
+ }
+ }
+ result=0;
+ if (!skipp_check)
+ result= ((mysql->packet_length=mc_net_safe_read(mysql)) == packet_error ?
+ -1 : 0);
+ end:
+ return result;
+}
+
+
+MYSQL * STDCALL
+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)
+{
+ char buff[100],*end,*host_info;
+ int sock;
+ ulong ip_addr;
+ struct sockaddr_in sock_addr;
+ uint pkt_length;
+ NET *net= &mysql->net;
+#ifdef __WIN__
+ HANDLE hPipe=INVALID_HANDLE_VALUE;
+#endif
+#ifdef HAVE_SYS_UN_H
+ struct sockaddr_un UNIXaddr;
+#endif
+ DBUG_ENTER("mysql_real_connect");
+
+ DBUG_PRINT("enter",("host: %s db: %s user: %s",
+ host ? host : "(Null)",
+ db ? db : "(Null)",
+ user ? user : "(Null)"));
+
+ bzero((char*) &mysql->options,sizeof(mysql->options));
+ net->vio = 0; /* If something goes wrong */
+ mysql->charset=default_charset_info; /* Set character set */
+ if (!port)
+ port = MYSQL_PORT; /* Should always be set by mysqld */
+ if (!unix_socket)
+ unix_socket=MYSQL_UNIX_ADDR;
+
+ mysql->reconnect=1; /* Reconnect as default */
+
+ /*
+ ** Grab a socket and connect it to the server
+ */
+
+#if defined(HAVE_SYS_UN_H)
+ if (!host || !strcmp(host,LOCAL_HOST))
+ {
+ host=LOCAL_HOST;
+ host_info=(char*) ER(CR_LOCALHOST_CONNECTION);
+ DBUG_PRINT("info",("Using UNIX sock '%s'",unix_socket));
+ if ((sock = socket(AF_UNIX,SOCK_STREAM,0)) == SOCKET_ERROR)
+ {
+ net->last_errno=CR_SOCKET_CREATE_ERROR;
+ sprintf(net->last_error,ER(net->last_errno),ERRNO);
+ goto error;
+ }
+ net->vio = vio_new(sock, VIO_TYPE_SOCKET, TRUE);
+ bzero((char*) &UNIXaddr,sizeof(UNIXaddr));
+ UNIXaddr.sun_family = AF_UNIX;
+ strmov(UNIXaddr.sun_path, unix_socket);
+ if (mc_sock_connect(sock,(struct sockaddr *) &UNIXaddr, sizeof(UNIXaddr),
+ mysql->options.connect_timeout) <0)
+ {
+ DBUG_PRINT("error",("Got error %d on connect to local server",ERRNO));
+ net->last_errno=CR_CONNECTION_ERROR;
+ sprintf(net->last_error,ER(net->last_errno),unix_socket,ERRNO);
+ goto error;
+ }
+ }
+ else
+#elif defined(__WIN__)
+ {
+ if ((unix_socket ||
+ !host && is_NT() ||
+ host && !strcmp(host,LOCAL_HOST_NAMEDPIPE) ||
+ mysql->options.named_pipe || !have_tcpip))
+ {
+ sock=0;
+ if ((hPipe=create_named_pipe(net, mysql->options.connect_timeout,
+ (char**) &host, (char**) &unix_socket)) ==
+ INVALID_HANDLE_VALUE)
+ {
+ DBUG_PRINT("error",
+ ("host: '%s' socket: '%s' named_pipe: %d have_tcpip: %d",
+ host ? host : "<null>",
+ unix_socket ? unix_socket : "<null>",
+ (int) mysql->options.named_pipe,
+ (int) have_tcpip));
+ if (mysql->options.named_pipe ||
+ (host && !strcmp(host,LOCAL_HOST_NAMEDPIPE)) ||
+ (unix_socket && !strcmp(unix_socket,MYSQL_NAMEDPIPE)))
+ goto error; /* User only requested named pipes */
+ /* Try also with TCP/IP */
+ }
+ else
+ {
+ net->vio=vio_new_win32pipe(hPipe);
+ sprintf(host_info=buff, ER(CR_NAMEDPIPE_CONNECTION), host,
+ unix_socket);
+ }
+ }
+ }
+ if (hPipe == INVALID_HANDLE_VALUE)
+#endif
+ {
+ unix_socket=0; /* This is not used */
+ if (!host)
+ host=LOCAL_HOST;
+ sprintf(host_info=buff,ER(CR_TCP_CONNECTION),host);
+ DBUG_PRINT("info",("Server name: '%s'. TCP sock: %d", host,port));
+ if ((sock = socket(AF_INET,SOCK_STREAM,0)) == SOCKET_ERROR)
+ {
+ net->last_errno=CR_IPSOCK_ERROR;
+ sprintf(net->last_error,ER(net->last_errno),ERRNO);
+ goto error;
+ }
+ net->vio = vio_new(sock,VIO_TYPE_TCPIP,FALSE);
+ bzero((char*) &sock_addr,sizeof(sock_addr));
+ sock_addr.sin_family = AF_INET;
+
+ /*
+ ** The server name may be a host name or IP address
+ */
+
+ 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)
+ {
+ net->last_errno=CR_UNKNOWN_HOST;
+ sprintf(net->last_error, ER(CR_UNKNOWN_HOST), host, tmp_errno);
+ goto error;
+ }
+ memcpy(&sock_addr.sin_addr,hp->h_addr, (size_t) hp->h_length);
+ }
+#else
+ {
+ struct hostent *hp;
+ if (!(hp=gethostbyname(host)))
+ {
+ net->last_errno=CR_UNKNOWN_HOST;
+ sprintf(net->last_error, ER(CR_UNKNOWN_HOST), host, errno);
+ goto error;
+ }
+ memcpy(&sock_addr.sin_addr,hp->h_addr, (size_t) hp->h_length);
+ }
+#endif
+ sock_addr.sin_port = (ushort) htons((ushort) port);
+ if (mc_sock_connect(sock,(struct sockaddr *) &sock_addr, sizeof(sock_addr),
+ mysql->options.connect_timeout) <0)
+ {
+ DBUG_PRINT("error",("Got error %d on connect to '%s'",ERRNO,host));
+ net->last_errno= CR_CONN_HOST_ERROR;
+ sprintf(net->last_error ,ER(CR_CONN_HOST_ERROR), host, ERRNO);
+ goto error;
+ }
+ }
+
+ if (!net->vio || 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;
+ }
+ vio_keepalive(net->vio,TRUE);
+
+ /* Get version info */
+ mysql->protocol_version= PROTOCOL_VERSION; /* Assume this */
+ if ((pkt_length=mc_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);
+ if (pkt_length > (uint) (end+9 - (char*) net->read_pos))
+ mysql->server_capabilities=uint2korr(end+9);
+
+ /* Save connection information */
+ if (!user) user="";
+ if (!passwd) passwd="";
+ 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",
+ mysql->server_version,mysql->server_capabilities));
+
+ /* Send client information for access check */
+ client_flag|=CLIENT_CAPABILITIES;
+
+#ifdef HAVE_OPENSSL
+ if (mysql->options.use_ssl)
+ client_flag|=CLIENT_SSL;
+#endif /* HAVE_OPENSSL */
+
+ if (db)
+ client_flag|=CLIENT_CONNECT_WITH_DB;
+#ifdef HAVE_COMPRESS
+ if (mysql->server_capabilities & CLIENT_COMPRESS &&
+ (mysql->options.compress || client_flag & CLIENT_COMPRESS))
+ client_flag|=CLIENT_COMPRESS; /* We will use compression */
+ else
+#endif
+ client_flag&= ~CLIENT_COMPRESS;
+
+#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;
+ }
+#endif /* HAVE_OPENSSL */
+
+ int2store(buff,client_flag);
+ mysql->client_flag=client_flag;
+
+#ifdef HAVE_OPENSSL
+ /* Oops.. are we careful enough to not send ANY information */
+ /* without encryption? */
+ if (client_flag & CLIENT_SSL)
+ {
+ if (my_net_write(net,buff,(uint) (2)) || net_flush(net))
+ 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);
+ }
+#endif /* HAVE_OPENSSL */
+
+ int3store(buff+2,max_allowed_packet);
+ if (user && user[0])
+ strmake(buff+5,user,32);
+ else
+ {
+ user = getenv("USER");
+ if(!user) user = "mysql";
+ strmov((char*) buff+5, user );
+ }
+
+ 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));
+ }
+ if (my_net_write(net,buff,(uint) (end-buff)) || net_flush(net) ||
+ mc_net_safe_read(mysql) == packet_error)
+ goto error;
+ if (client_flag & CLIENT_COMPRESS) /* We will use compression */
+ net->compress=1;
+ DBUG_PRINT("exit",("Mysql handler: %lx",mysql));
+ DBUG_RETURN(mysql);
+
+error:
+ DBUG_PRINT("error",("message: %u (%s)",net->last_errno,net->last_error));
+ {
+ /* Free alloced memory */
+ my_bool free_me=mysql->free_me;
+ mc_end_server(mysql);
+ mysql->free_me=0;
+ mc_mysql_close(mysql);
+ mysql->free_me=free_me;
+ }
+ DBUG_RETURN(0);
+}
+
+/*************************************************************************
+** Send a QUIT to the server and close the connection
+** If handle is alloced by mysql connect free it.
+*************************************************************************/
+
+void STDCALL
+mc_mysql_close(MYSQL *mysql)
+{
+ DBUG_ENTER("mysql_close");
+ if (mysql) /* Some simple safety */
+ {
+ if (mysql->net.vio != 0)
+ {
+ mc_free_old_query(mysql);
+ mysql->status=MYSQL_STATUS_READY; /* Force command */
+ mc_simple_command(mysql,COM_QUIT,NullS,0,1);
+ mc_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));
+ /* 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;
+}
diff --git a/sql/mini_client.h b/sql/mini_client.h
new file mode 100644
index 00000000000..1103bd379fe
--- /dev/null
+++ b/sql/mini_client.h
@@ -0,0 +1,45 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 _MINI_CLIENT_H
+#define _MINI_CLIENT_H
+
+
+MYSQL* STDCALL
+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,
+ uint length, my_bool skipp_check);
+void STDCALL
+mc_mysql_close(MYSQL *mysql);
+
+MYSQL * STDCALL
+mc_mysql_init(MYSQL *mysql);
+
+void STDCALL
+mc_mysql_debug(const char *debug);
+
+uint STDCALL
+mc_net_safe_read(MYSQL *mysql);
+
+char * STDCALL mc_mysql_error(MYSQL *mysql);
+my_bool STDCALL mc_mysql_reconnect(MYSQL* mysql);
+
+
+#endif
diff --git a/sql/my_lock.c b/sql/my_lock.c
new file mode 100644
index 00000000000..6c35634203f
--- /dev/null
+++ b/sql/my_lock.c
@@ -0,0 +1,82 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 __EMX__
+#include "../mysys/my_lock.c"
+#else
+
+#undef MAP_TO_USE_RAID /* Avoid RAID mappings */
+#include <global.h>
+#include <my_sys.h>
+#include <mysys_err.h>
+#include <my_pthread.h>
+#include <thr_alarm.h>
+#include <errno.h>
+
+#ifdef HAVE_FCNTL
+static struct flock lock; /* Must be static for sun-sparc */
+#endif
+
+ /* Lock a part of a file */
+
+int my_lock(File fd,int locktype,my_off_t start,my_off_t length,myf MyFlags)
+{
+ thr_alarm_t alarmed;
+ ALARM alarm_buff;
+ uint wait_for_alarm;
+ DBUG_ENTER("my_lock");
+ DBUG_PRINT("my",("Fd: %d Op: %d start: %ld Length: %ld MyFlags: %d",
+ fd,locktype,(ulong) start,(ulong) length,MyFlags));
+ if (my_disable_locking)
+ DBUG_RETURN(0); /* purecov: inspected */
+ lock.l_type=(short) locktype;
+ lock.l_whence=0L;
+ lock.l_start=(long) start;
+ lock.l_len=(long) length;
+ wait_for_alarm=(MyFlags & MY_DONT_WAIT ? MY_HOW_OFTEN_TO_ALARM :
+ (uint) 12*60*60);
+ if (fcntl(fd,F_SETLK,&lock) != -1) /* Check if we can lock */
+ DBUG_RETURN(0); /* Ok, file locked */
+ DBUG_PRINT("info",("Was locked, trying with alarm"));
+ if (!thr_alarm(&alarmed,wait_for_alarm,&alarm_buff))
+ {
+ int value;
+ while ((value=fcntl(fd,F_SETLKW,&lock)) && !thr_got_alarm(alarmed) &&
+ errno == EINTR) ;
+ thr_end_alarm(&alarmed);
+ if (value != -1)
+ DBUG_RETURN(0);
+ }
+ else
+ {
+ errno=EINTR;
+ }
+ if (errno == EINTR || errno == EACCES)
+ my_errno=EAGAIN; /* Easier to check for this */
+ else
+ my_errno=errno;
+
+ if (MyFlags & MY_WME)
+ {
+ if (locktype == F_UNLCK)
+ my_error(EE_CANTUNLOCK,MYF(ME_BELL+ME_WAITTANG),errno);
+ else
+ my_error(EE_CANTLOCK,MYF(ME_BELL+ME_WAITTANG),errno);
+ }
+ DBUG_PRINT("error",("errno: %d",errno));
+ DBUG_RETURN(-1);
+}
+#endif
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
new file mode 100644
index 00000000000..0963b4dd03a
--- /dev/null
+++ b/sql/mysql_priv.h
@@ -0,0 +1,594 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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_PRIV_H
+#define _MYSQL_PRIV_H
+
+#include <global.h>
+#include <my_sys.h>
+#include <m_string.h>
+#include "mysql_version.h"
+#include <hash.h>
+#include <signal.h>
+#include <thr_lock.h>
+#include <my_base.h> /* Needed by field.h */
+#include <violite.h>
+
+typedef ulong table_map; /* Used for table bits in join */
+typedef ulong key_map; /* Used for finding keys */
+typedef ulong key_part_map; /* Used for finding key parts */
+
+#include "mysql_com.h"
+#include "unireg.h"
+
+void init_sql_alloc(MEM_ROOT *root,uint block_size);
+gptr sql_alloc(unsigned size);
+gptr sql_calloc(unsigned size);
+char *sql_strdup(const char *str);
+char *sql_strmake(const char *str,uint len);
+gptr sql_memdup(const void * ptr,unsigned size);
+void sql_element_free(void *ptr);
+
+#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; } }
+#define PREV_BITS(type,A) ((type) (((type) 1 << (A)) -1))
+#define all_bits_set(A,B) ((A) & (B) != (B))
+
+#ifndef LL
+#ifdef HAVE_LONG_LONG
+#define LL(A) A ## LL
+#else
+#define LL(A) A ## L
+#endif
+#endif
+
+/***************************************************************************
+ Configuration parameters
+****************************************************************************/
+
+#define ACL_CACHE_SIZE 256
+#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.
+#ifndef MYSQLD_NET_RETRY_COUNT
+#define MYSQLD_NET_RETRY_COUNT 10 // Abort read after this many int.
+#endif
+/* The following parameters is to decide when to use an extra cache to
+ optimise seeks when reading a big table in sorted order */
+#define MIN_FILE_LENGTH_TO_USE_ROW_CACHE (16L*1024*1024)
+#define MIN_ROWS_TO_USE_TABLE_CACHE 100
+
+// The following is used to decide if MySQL should use table scanning
+// instead of reading with keys. The number says how many evaluation of the
+// WHERE clause is comparable to reading one extra row from a table.
+#define TIME_FOR_COMPARE 5 // 5 compares == one read
+
+/* Don't pack string keys shorter than this (if PACK_KEYS=1 isn't used) */
+#define KEY_DEFAULT_PACK_LENGTH 8
+
+/* Characters shown for the command in 'show processlist' */
+#define PROCESS_LIST_WIDTH 100
+
+/* Time handling defaults */
+#define TIMESTAMP_MAX_YEAR 2038
+#define YY_PART_YEAR 70
+#define PRECISION_FOR_DOUBLE 53
+#define PRECISION_FOR_FLOAT 24
+
+/* The following can also be changed from the command line */
+#define CONNECT_TIMEOUT 5 // Do not wait long for connect
+#define DEFAULT_CONCURRENCY 10
+#define DELAYED_LIMIT 100 /* pause after xxx inserts */
+#define DELAYED_QUEUE_SIZE 1000
+#define DELAYED_WAIT_TIMEOUT 5*60 /* Wait for delayed insert */
+#define FLUSH_TIME 0 /* Don't flush tables */
+#define MAX_CONNECT_ERRORS 10 // errors before disabling host
+
+#ifdef __WIN__
+#define IF_WIN(A,B) (A)
+#undef FLUSH_TIME
+#define FLUSH_TIME 1800 /* Flush every half hour */
+
+#define INTERRUPT_PRIOR -2
+#define CONNECT_PRIOR -1
+#define WAIT_PRIOR 0
+#define QUERY_PRIOR 2
+#else
+#define IF_WIN(A,B) (B)
+#define INTERRUPT_PRIOR 10
+#define CONNECT_PRIOR 9
+#define WAIT_PRIOR 8
+#define QUERY_PRIOR 6
+#endif /* __WIN92__ */
+
+ /* Bits fro testflag */
+#define TEST_PRINT_CACHED_TABLES 1
+#define TEST_NO_KEY_GROUP 2
+#define TEST_MIT_THREAD 4
+#define TEST_BLOCKING 8
+#define TEST_KEEP_TMP_TABLES 16
+#define TEST_NO_THREADS 32 /* For debugging under Linux */
+#define TEST_READCHECK 64 /* Force use of readcheck */
+#define TEST_NO_EXTRA 128
+#define TEST_KILL_ON_DEBUG 256 /* Kill server */
+
+/* options for select set by the yacc parser */
+#define SELECT_DISTINCT 1
+#define SELECT_STRAIGHT_JOIN 2
+#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_BIG_TABLES 512 /* for SQL OPTION */
+#define OPTION_BIG_SELECTS 1024 /* for SQL OPTION */
+#define OPTION_LOG_OFF 2048
+#define OPTION_UPDATE_LOG 4096 /* update log flag */
+#define OPTION_LOW_PRIORITY_UPDATES 8192
+#define OPTION_WARNINGS 16384
+#define OPTION_AUTO_IS_NULL 32768
+#define OPTION_ANSI_MODE 65536L
+#define OPTION_SAFE_UPDATES OPTION_ANSI_MODE*2
+#define OPTION_BUFFER_RESULT OPTION_SAFE_UPDATES*2
+#define OPTION_BIN_LOG OPTION_BUFFER_RESULT*2
+#define OPTION_AUTO_COMMIT OPTION_BIN_LOG*2
+#define OPTION_BEGIN OPTION_AUTO_COMMIT*2
+
+#define RAID_BLOCK_SIZE 1024
+
+/* BINLOG_DUMP options */
+
+#define BINLOG_DUMP_NON_BLOCK 1
+
+/* Some portable defines */
+
+#define portable_sizeof_char_ptr 8
+
+#define tmp_file_prefix "#sql" /* Prefix for tmp tables */
+#define tmp_file_prefix_length 4
+
+struct st_table;
+class THD;
+
+/* Struct to handle simple linked lists */
+
+typedef struct st_sql_list {
+ uint elements;
+ byte *first;
+ byte **next;
+} SQL_LIST;
+
+
+uint nr_of_decimals(const char *str); /* Neaded by sql_string.h */
+
+extern pthread_key(THD*, THR_THD);
+inline THD *_current_thd(void)
+{
+ return my_pthread_getspecific_ptr(THD*,THR_THD);
+}
+#define current_thd _current_thd()
+
+#include "sql_string.h"
+#include "sql_list.h"
+#include "sql_map.h"
+#include "handler.h"
+#include "table.h"
+#include "field.h" /* Field definitions */
+#include "sql_udf.h"
+#include "item.h"
+#include "sql_class.h"
+#include "opt_range.h"
+
+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 show_binlog_info(THD* thd);
+
+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
+
+
+void mysql_create_db(THD *thd, char *db, uint create_info);
+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 quick_rm_table(enum db_type base,const char *db,
+ const char *table_name);
+bool mysql_change_db(THD *thd,const char *name);
+void mysql_parse(THD *thd,char *inBuf,uint length);
+pthread_handler_decl(handle_one_connection,arg);
+int handle_bootstrap(THD *thd,FILE *file);
+sig_handler end_thread_signal(int sig);
+void end_thread(THD *thd,bool put_in_cache);
+void flush_thread_cache();
+void mysql_execute_command(void);
+bool do_command(THD *thd);
+bool check_stack_overrun(THD *thd,char *dummy);
+bool reload_acl_and_cache(uint options);
+void mysql_rm_db(THD *thd,char *db,bool if_exists);
+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);
+
+int mysql_check_table(THD* thd, TABLE_LIST* table_list,
+ HA_CHECK_OPT* check_opt);
+int mysql_repair_table(THD* thd, TABLE_LIST* table_list,
+ HA_CHECK_OPT* check_opt);
+int mysql_analyze_table(THD* thd, TABLE_LIST* table_list);
+int mysql_optimize_table(THD* thd, TABLE_LIST* table_list);
+
+
+/* net_pkg.c */
+void send_error(NET *net,uint sql_errno=0, 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,
+ const char *info=0);
+void send_eof(NET *net,bool no_flush=0);
+char *net_store_length(char *packet,ulonglong length);
+char *net_store_length(char *packet,uint length);
+char *net_store_data(char *to,const char *from);
+char *net_store_data(char *to,int32 from);
+char *net_store_data(char *to,longlong from);
+bool net_store_null(String *packet);
+bool net_store_data(String *packet,uint32 from);
+bool net_store_data(String *packet,longlong from);
+bool net_store_data(String *packet,const char *from);
+bool net_store_data(String *packet,const char *from,uint length);
+bool net_store_data(String *packet,struct tm *tmp);
+bool net_store_data(String* packet, I_List<i_string>* str_list);
+
+int mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &list,COND *conds,
+ List<Item_func_match> &ftfuncs,
+ 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,
+ 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,
+ HA_CREATE_INFO *create_info,
+ List<create_field> &fields, List<Key> &keys,
+ bool tmp_table, bool no_log);
+// no_log is needed for the case of CREATE TABLE ... SELECT , as the logging
+// will be done later in sql_insert.cc
+
+TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info,
+ const char *db, const char *name,
+ List<create_field> *extra_fields,
+ List<Key> *keys,
+ List<Item> *items,
+ MYSQL_LOCK **lock);
+int mysql_alter_table(THD *thd, char *new_db, char *new_name,
+ HA_CREATE_INFO *create_info,
+ TABLE_LIST *table_list,
+ List<create_field> &fields,
+ List<Key> &keys,List<Alter_drop> &drop_list,
+ List<Alter_column> &alter_list,
+ bool drop_primary,
+ enum enum_duplicates handle_duplicates);
+bool close_cached_table(THD *thd,TABLE *table);
+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,
+ 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);
+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);
+TABLE *find_locked_table(THD *thd, const char *db,const char *table_name);
+bool reopen_table(TABLE *table,bool locked=0);
+bool reopen_tables(THD *thd,bool get_locks,bool in_refresh);
+void close_old_data_files(THD *thd, TABLE *table, bool abort_locks);
+bool close_data_tables(THD *thd,const char *db, const char *table_name);
+bool wait_for_tables(THD *thd);
+bool drop_locked_tables(THD *thd,const char *db, const char *table_name);
+void abort_locked_tables(THD *thd,const char *db, const char *table_name);
+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);
+
+/* sql_list.c */
+int mysqld_show_dbs(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);
+int mysqld_show_keys(THD *thd, TABLE_LIST *table);
+void mysqld_list_fields(THD *thd,TABLE_LIST *table, const char *wild);
+int mysqld_dump_create_info(THD *thd, TABLE *table, int fd = -1);
+int mysqld_show_create(THD *thd, TABLE_LIST *table_list);
+
+void mysqld_list_processes(THD *thd,const char *user,bool verbose);
+int mysqld_show_status(THD *thd);
+int mysqld_show_variables(THD *thd,const char *wild);
+int mysqld_show(THD *thd, const char *wild, show_var_st *variables);
+
+/* 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,
+ char *length, char *decimal,
+ uint type_modifier, Item *default_value,char *change,
+ TYPELIB *interval);
+void store_position_for_column(const char *name);
+bool add_to_list(SQL_LIST &list,Item *group,bool asc=0);
+TABLE_LIST *add_table_to_list(Table_ident *table,LEX_STRING *alias,
+ thr_lock_type flags=TL_UNLOCK,
+ List<String> *use_index=0,
+ List<String> *ignore_index=0);
+void add_join_on(TABLE_LIST *b,Item *expr);
+void add_join_natural(TABLE_LIST *a,TABLE_LIST *b);
+bool add_proc_to_list(Item *item);
+TABLE *unlink_open_table(THD *thd,TABLE *list,TABLE *find);
+
+SQL_SELECT *make_select(TABLE *head, table_map const_tables,
+ table_map read_tables, COND *conds, int *error);
+Item ** find_item_in_list(Item *item,List<Item> &items);
+int setup_fields(THD *thd,TABLE_LIST *tables,List<Item> &item,
+ bool set_query_id,List<Item> *sum_func_list);
+int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds);
+int setup_ftfuncs(THD *thd,TABLE_LIST *tables, List<Item_func_match> &ftfuncs);
+void wait_for_refresh(THD *thd);
+int open_tables(THD *thd,TABLE_LIST *tables);
+int open_and_lock_tables(THD *thd,TABLE_LIST *tables);
+int lock_tables(THD *thd,TABLE_LIST *tables);
+TABLE *open_temporary_table(THD *thd, const char *path, const char *db,
+ const char *table_name, bool link_in_list);
+bool rm_temporary_table(enum db_type base, char *path);
+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);
+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);
+void close_temporary(TABLE *table, bool delete_table=1);
+bool rename_temporary_table(TABLE *table, const char *new_db,
+ const char *table_name);
+void remove_db_from_cache(const my_string db);
+void flush_tables();
+bool remove_table_from_cache(THD *thd, const char *db, const char *table);
+bool close_cached_tables(bool wait_for_refresh);
+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);
+
+/* sql_calc.cc */
+bool eval_const_cond(COND *cond);
+
+/* sql_load.cc */
+int mysql_load(THD *thd,sql_exchange *ex, TABLE_LIST *table_list,
+ List<Item> &fields, enum enum_duplicates handle_duplicates,
+ bool local_file,thr_lock_type lock_type);
+int write_record(TABLE *table,COPY_INFO *info);
+/* sql_test.cc */
+#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);
+#endif
+void mysql_print_status(THD *thd);
+/* key.cc */
+int find_ref_key(TABLE *form,Field *field, uint *offset);
+void key_copy(byte *key,TABLE *form,uint index,uint key_length);
+void key_restore(TABLE *form,byte *key,uint index,uint key_length);
+int key_cmp(TABLE *form,const byte *key,uint index,uint key_length);
+void key_unpack(String *to,TABLE *form,uint index);
+bool check_if_key_used(TABLE *table, uint idx, List<Item> &fields);
+void init_errmessage(void);
+
+void sql_perror(const char *message);
+void sql_print_error(const char *format,...)
+ __attribute__ ((format (printf, 1, 2)));
+
+extern char mysql_data_home[2],server_version[50],max_sort_char,
+ mysql_real_data_home[];
+extern my_string mysql_unix_port,mysql_tmpdir;
+extern const char *first_keyword;
+extern ulong refresh_version,flush_version, thread_id,query_id,opened_tables,
+ created_tmp_tables, aborted_threads,aborted_connects,
+ delayed_insert_timeout,
+ delayed_insert_limit, delayed_queue_size,
+ delayed_insert_threads, delayed_insert_writes,
+ delayed_rows_in_use,delayed_insert_errors;
+extern uint test_flags,select_errors,mysql_port,ha_open_options;
+extern ulong thd_startup_options, slow_launch_threads, slow_launch_time;
+extern time_t start_time;
+extern const char *command_name[];
+extern I_List<THD> threads;
+extern MYSQL_LOG mysql_log,mysql_update_log,mysql_slow_log,mysql_bin_log;
+extern pthread_key(MEM_ROOT*,THR_MALLOC);
+extern pthread_key(NET*, THR_NET);
+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;
+extern pthread_cond_t COND_refresh,COND_thread_count, COND_binlog_update,
+ COND_slave_stopped;
+extern pthread_attr_t connection_attrib;
+extern bool opt_endinfo,using_udf_functions;
+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;
+
+extern char f_fyllchar;
+extern uchar *days_in_month;
+extern DATE_FORMAT dayord;
+extern double log_10[32];
+extern uint protocol_version,dropping_tables;
+extern ulong keybuff_size,sortbuff_size,max_item_sort_length,table_cache_size,
+ max_join_size,join_buff_size,tmp_table_size,
+ max_connections,max_connect_errors,long_query_time,
+ max_insert_delayed_threads,
+ long_query_count,net_wait_timeout,net_interactive_timeout,
+ net_read_timeout,net_write_timeout,
+ what_to_log,flush_time,
+ max_tmp_tables,max_heap_table_size,query_buff_size,
+ lower_case_table_names,thread_stack,thread_stack_min;
+extern ulong specialflag;
+extern ulong current_pid;
+extern bool low_priority_updates;
+extern bool opt_sql_bin_update;
+extern char language[LIBLEN],reg_ext[FN_EXTLEN],blob_newline;
+extern const char **errmesg; /* Error messages */
+extern byte last_ref[MAX_REFLENGTH]; /* Index ref of keys */
+extern String empty_string;
+extern struct show_var_st init_vars[];
+extern struct show_var_st status_vars[];
+extern enum db_type default_table_type;
+
+#ifndef __WIN__
+extern pthread_t signal_thread;
+#endif
+
+extern bool volatile abort_loop, shutdown_in_progress, grant_option;
+extern uint volatile thread_count, thread_running, global_read_lock;
+
+MYSQL_LOCK *mysql_lock_tables(THD *thd,TABLE **table,uint count);
+void mysql_unlock_tables(THD *thd, MYSQL_LOCK *sql_lock);
+void mysql_unlock_read_tables(THD *thd, MYSQL_LOCK *sql_lock);
+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);
+
+extern int flush_master_info(MASTER_INFO* mi);
+
+/* old unireg functions */
+
+void unireg_init(ulong options);
+void unireg_end(int signal);
+int rea_create_table(my_string file_name,HA_CREATE_INFO *create_info,
+ List<create_field> &create_field,
+ uint key_count,KEY *key_info);
+int format_number(uint inputflag,uint max_length,my_string pos,uint length,
+ my_string *errpos);
+int openfrm(const char *name,const char *alias,uint filestat,uint prgflag,
+ TABLE *outparam);
+int closefrm(TABLE *table);
+db_type get_table_type(const char *name);
+int read_string(File file, gptr *to, uint length);
+void free_blobs(TABLE *table);
+int set_zone(int nr,int min_zone,int max_zone);
+ulong convert_period_to_month(ulong period);
+ulong convert_month_to_period(ulong month);
+long calc_daynr(uint year,uint month,uint day);
+uint calc_days_in_year(uint year);
+void get_date_from_daynr(long daynr,uint *year, uint *month,
+ uint *day);
+void init_time(void);
+long my_gmt_sec(TIME *);
+time_t str_to_timestamp(const char *str,uint length);
+bool str_to_time(const char *str,uint length,TIME *l_time);
+longlong str_to_datetime(const char *str,uint length,bool fuzzy_date);
+timestamp_type str_to_TIME(const char *str, uint length, TIME *l_time,
+ bool fuzzy_date);
+
+int test_if_number(char *str,int *res,bool allow_wildcards);
+void change_byte(byte *,uint,char,char);
+void unireg_abort(int exit_code);
+void init_read_record(READ_RECORD *info, THD *thd, TABLE *reg_form,
+ SQL_SELECT *select,
+ bool 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,
+ SQL_SELECT *select, ha_rows special,ha_rows max_rows);
+void change_double_for_sort(double nr,byte *to);
+int get_quick_record(SQL_SELECT *select);
+int calc_weekday(long daynr,bool sunday_first_day_of_week);
+uint calc_week(TIME *ltime, bool with_year, bool sunday_first_day_of_week,
+ uint *year);
+void find_date(char *pos,uint *vek,uint flag);
+TYPELIB *convert_strings_to_array_type(my_string *typelibs, my_string *end);
+TYPELIB *typelib(List<String> &strings);
+void clean_up(void);
+ulong get_form_pos(File file, uchar *head, TYPELIB *save_names);
+ulong make_new_entry(File file,uchar *fileinfo,TYPELIB *formnames,
+ const char *newname);
+ulong next_io_size(ulong pos);
+void append_unescaped(String *res,const char *pos);
+int create_frm(char *name,uint reclength,uchar *fileinfo,
+ HA_CREATE_INFO *create_info, uint keys);
+void update_create_info_from_table(HA_CREATE_INFO *info, TABLE *form);
+int rename_file_ext(const char * from,const char * to,const char * ext);
+bool check_db_name(const char *db);
+bool check_column_name(const char *name);
+bool check_table_name(const char *name, uint length);
+char *get_field(MEM_ROOT *mem,TABLE *table,uint fieldnr);
+int wild_case_compare(const char *str,const char *wildstr);
+/* from hostname.cc */
+struct in_addr;
+my_string ip_to_hostname(struct in_addr *in,uint *errors);
+void inc_host_errors(struct in_addr *in);
+void reset_host_errors(struct in_addr *in);
+bool hostname_cache_init();
+void hostname_cache_free();
+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);
+
+/* Some inline functions for more speed */
+
+inline bool add_item_to_list(Item *item)
+{
+ return current_lex->item_list.push_back(item);
+}
+inline bool add_value_to_list(Item *value)
+{
+ return current_lex->value_list.push_back(value);
+}
+inline bool add_order_to_list(Item *item,bool asc)
+{
+ return add_to_list(current_lex->order_list,item,asc);
+}
+inline bool add_group_to_list(Item *item,bool asc)
+{
+ return add_to_list(current_lex->group_list,item,asc);
+}
+inline void mark_as_null_row(TABLE *table)
+{
+ table->null_row=1;
+ bfill(table->null_flags,table->null_bytes,255);
+}
+
+#endif
diff --git a/sql/mysqlbinlog.cc b/sql/mysqlbinlog.cc
new file mode 100644
index 00000000000..c088dc13fd3
--- /dev/null
+++ b/sql/mysqlbinlog.cc
@@ -0,0 +1,378 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 <global.h>
+#include <m_string.h>
+#include <my_sys.h>
+#include <getopt.h>
+#include <thr_alarm.h>
+#include "log_event.h"
+#define MYSQL_SERVER // We want the C++ version of net
+#include <mysql.h>
+#include "mini_client.h"
+
+#define CLIENT_CAPABILITIES (CLIENT_LONG_PASSWORD | CLIENT_LONG_FLAG | CLIENT_LOCAL_FILES)
+
+
+// needed by net_serv.c
+ulong bytes_sent = 0L, bytes_received = 0L;
+ulong mysqld_net_retry_count = 10L;
+ulong net_read_timeout= NET_READ_TIMEOUT;
+ulong net_write_timeout= NET_WRITE_TIMEOUT;
+uint test_flags = 0;
+
+#ifndef DBUG_OFF
+static const char* default_dbug_option = "d:t:o,/tmp/mysqlbinlog.trace";
+#endif
+
+static struct option long_options[] =
+{
+ {"short-form", no_argument, 0, 's'},
+ {"table", required_argument, 0, 't'},
+ {"offset", required_argument,0, 'o'},
+ {"help", no_argument, 0, '?'},
+ {"host", required_argument,0, 'h'},
+ {"port", required_argument,0, 'P'},
+ {"user", required_argument,0, 'u'},
+ {"password", required_argument,0, 'p'},
+ {"position", required_argument,0, 'j'},
+#ifndef DBUG_OFF
+ {"debug", required_argument, 0, '#'}
+#endif
+};
+
+void sql_print_error(const char *format,...);
+
+static bool short_form = 0;
+static int offset = 0;
+static const char* host = "localhost";
+static int port = MYSQL_PORT;
+static const char* user = "test";
+static const char* pass = "";
+static long position = 0;
+static bool use_remote = 0;
+static short binlog_flags = 0;
+static MYSQL* mysql = NULL;
+static const char* table = 0;
+
+static void dump_local_log_entries(const char* logname);
+static void dump_remote_log_entries(const char* logname);
+static void dump_log_entries(const char* logname);
+static void dump_remote_file(NET* net, const char* fname);
+static void dump_remote_table(NET* net, const char* db, const char* table);
+static void die(const char* fmt, ...);
+static MYSQL* safe_connect();
+
+ void sql_print_error(const char *format,...)
+ {
+ va_list args;
+ va_start(args, format);
+ fprintf(stderr, "ERROR: ");
+ vfprintf(stderr, format, args);
+ fprintf(stderr, "\n");
+ va_end(args);
+ }
+
+static void die(const char* fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ fprintf(stderr, "ERROR: ");
+ vfprintf(stderr, fmt, args);
+ fprintf(stderr, "\n");
+ va_end(args);
+ exit(1);
+}
+
+static void usage()
+{
+ printf("Usage: %s [options] log-files\n",my_progname);
+ printf("Options:\n\
+-s,--short-form just show the queries, no extra info\n\
+-o,--offset=N skip the first N entries\n\
+-h,--host=server get the binlog from server\n\
+-P,--port=port use port to connect to the remove server\n\
+-u,--user=username connect to the remove server as username\n\
+-p,--password=password use this password to connect to remote server\n\
+-j,--position=N start reading the binlog at postion N\n\
+-t,--table=name get raw table dump using COM_TABLE_DUMB \n\
+-?,--help this message\n");
+}
+
+static void dump_remote_file(NET* net, const char* fname)
+{
+ char buf[FN_REFLEN+1];
+ uint len = strlen(fname);
+ buf[0] = 0;
+ memcpy(buf + 1, fname, len + 1);
+ if(my_net_write(net, buf, len +2) || net_flush(net))
+ die("Failed requesting the remote dump of %s", fname);
+ for(;;)
+ {
+ uint packet_len = my_net_read(net);
+ if(packet_len == 0)
+ {
+ if(my_net_write(net, "", 0) || net_flush(net))
+ die("Failed sending the ack packet");
+
+ // we just need to send something, as the server will read but
+ // not examine the packet - this is because mysql_load() sends an OK when it is done
+ break;
+ }
+ else if(packet_len == packet_error)
+ die("Failed reading a packet during the dump of %s ", fname);
+
+ if(!short_form)
+ (void)my_fwrite(stdout, (byte*) net->read_pos, packet_len, MYF(0));
+ }
+
+ fflush(stdout);
+}
+
+static int parse_args(int *argc, char*** argv)
+{
+ int c, opt_index = 0;
+
+ while((c = getopt_long(*argc, *argv, "so:#:h:j:u:p:P:t:?", long_options,
+ &opt_index)) != EOF)
+ {
+ switch(c)
+ {
+#ifndef DBUG_OFF
+ case '#':
+ DBUG_PUSH(optarg ? optarg : default_dbug_option);
+ break;
+#endif
+ case 's':
+ short_form = 1;
+ break;
+
+ case 'o':
+ offset = atoi(optarg);
+ break;
+
+ case 'j':
+ position = atoi(optarg);
+ break;
+
+ case 'h':
+ 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));
+ break;
+
+ case 'u':
+ use_remote = 1;
+ user = my_strdup(optarg, MYF(0));
+ break;
+
+ case 't':
+ table = my_strdup(optarg, MYF(0));
+ break;
+
+ case '?':
+ default:
+ usage();
+ exit(0);
+
+ }
+ }
+
+ (*argc)-=optind;
+ (*argv)+=optind;
+
+
+ return 0;
+}
+
+static MYSQL* safe_connect()
+{
+ MYSQL *local_mysql = mc_mysql_init(NULL);
+ if(!local_mysql)
+ die("Failed on mc_mysql_init");
+
+ if(!mc_mysql_connect(local_mysql, host, user, pass, 0, port, 0, 0))
+ die("failed on connect: %s", mc_mysql_error(local_mysql));
+
+ return local_mysql;
+}
+
+static void dump_log_entries(const char* logname)
+{
+ if(use_remote)
+ dump_remote_log_entries(logname);
+ else
+ dump_local_log_entries(logname);
+}
+
+static void dump_remote_table(NET* net, const char* db, const char* table)
+{
+ char buf[1024];
+ char * p = buf;
+ uint table_len = strlen(table);
+ uint db_len = 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(mc_simple_command(mysql, COM_TABLE_DUMP, buf, p - buf + table_len, 1))
+ die("Error sending the table dump command");
+
+ for(;;)
+ {
+ uint packet_len = my_net_read(net);
+ if(packet_len == 0) break; // end of file
+ if(packet_len == packet_error)
+ die("Error reading packet in table dump");
+ my_fwrite(stdout, (byte*)net->read_pos, packet_len, MYF(MY_WME));
+ fflush(stdout);
+ }
+}
+
+
+static void dump_remote_log_entries(const char* logname)
+{
+ char buf[128];
+ uint len;
+ NET* net = &mysql->net;
+ int4store(buf, position);
+ int2store(buf + 4, binlog_flags);
+ len = strlen(logname);
+ memcpy(buf + 6, logname,len);
+ if(mc_simple_command(mysql, COM_BINLOG_DUMP, buf, len + 6, 1))
+ die("Error sending the log dump command");
+
+ for(;;)
+ {
+ len = mc_net_safe_read(mysql);
+ if (len == packet_error)
+ die("Error reading packet from server: %s", mc_mysql_error(mysql));
+ if(len == 1 && net->read_pos[0] == 254)
+ break; // end of data
+ DBUG_PRINT("info",( "len= %u, net->read_pos[5] = %d\n",
+ len, net->read_pos[5]));
+ Log_event * ev = Log_event::read_log_event((const char*) net->read_pos + 1 , len);
+ if(ev)
+ {
+ ev->print(stdout, short_form);
+ if(ev->get_type_code() == LOAD_EVENT)
+ dump_remote_file(net, ((Load_log_event*)ev)->fname);
+ delete ev;
+ }
+ else
+ die("Could not construct log event object");
+ }
+}
+
+static void dump_local_log_entries(const char* logname)
+{
+ FILE* file;
+ int rec_count = 0;
+
+ if(logname && logname[0] != '-')
+ file = my_fopen(logname, O_RDONLY, MYF(MY_WME));
+ else
+ file = stdin;
+
+ if(!file)
+ die("Could not open log file %s", logname);
+
+ if(my_fseek(file, position, MY_SEEK_SET, MYF(MY_WME)))
+ die("failed on my_fseek()");
+
+ while(1)
+ {
+ Log_event* ev = Log_event::read_log_event(file);
+ if(!ev)
+ if(!feof(file))
+ die("Could not read entry at offset %ld : Error in log format or \
+read error",
+ my_ftell(file, MYF(MY_WME)));
+ else
+ break;
+
+ if(rec_count >= offset)
+ ev->print(stdout, short_form);
+ rec_count++;
+ delete ev;
+ }
+
+ my_fclose(file, MYF(MY_WME));
+}
+
+int main(int argc, char** argv)
+{
+ MY_INIT(argv[0]);
+ parse_args(&argc, (char***)&argv);
+
+ if(!argc && !table)
+ {
+ usage();
+ return -1;
+ }
+
+ if(use_remote)
+ {
+ init_thr_alarm(10); // need to do this manually
+ mysql = safe_connect();
+ }
+
+ if(table)
+ {
+ if(!use_remote)
+ die("You must specify connection parameter to get table dump");
+ char* db = (char*)table;
+ char* tbl = (char*) strchr(table, '.');
+ if(!tbl)
+ die("You must use database.table syntax to specify the table");
+ *tbl++ = 0;
+ dump_remote_table(&mysql->net, db, tbl);
+ }
+ else
+ while(--argc >= 0)
+ {
+ dump_log_entries(*(argv++));
+ }
+
+ if(use_remote)
+ mc_mysql_close(mysql);
+
+ return 0;
+}
+
+/*
+ We must include this here as it's compiled with different options for
+ the server
+*/
+
+#include "log_event.cc"
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
new file mode 100644
index 00000000000..179c7ecd9dc
--- /dev/null
+++ b/sql/mysqld.cc
@@ -0,0 +1,3433 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 <mysql.h>
+#include <m_ctype.h>
+#include "sql_acl.h"
+#ifdef HAVE_BERKELEY_DB
+#include "ha_berkeley.h"
+#endif
+#include "ha_myisam.h"
+#include <nisam.h>
+#include <thr_alarm.h>
+#include <ft_global.h>
+
+#ifdef __cplusplus
+extern "C" { // Because of SCO 3.2V4.2
+#endif
+#include <errno.h>
+#include <sys/stat.h>
+#ifndef __GNU_LIBRARY__
+#define __GNU_LIBRARY__ // Skipp warnings in getopt.h
+#endif
+#include <getopt.h>
+#ifdef HAVE_SYSENT_H
+#include <sysent.h>
+#endif
+#ifdef HAVE_PWD_H
+#include <pwd.h> // For getpwent
+#endif
+#ifdef HAVE_GRP_H
+#include <grp.h>
+#endif
+
+#ifndef __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>
+#else
+#include <windows.h>
+#endif // __WIN__
+
+#ifdef HAVE_LIBWRAP
+#include <tcpd.h>
+#include <syslog.h>
+#ifdef NEED_SYS_SYSLOG_H
+#include <sys/syslog.h>
+#endif /* NEED_SYS_SYSLOG_H */
+int allow_severity = LOG_INFO;
+int deny_severity = LOG_WARNING;
+#endif /* HAVE_LIBWRAP */
+
+#if defined(__FreeBSD__) && defined(HAVE_IEEEFP_H)
+#include <ieeefp.h>
+#ifdef HAVE_FP_EXCEPT // Fix type conflict
+typedef fp_except fp_except_t;
+#endif
+
+ /* We can't handle floating point expections with threads, so disable
+ this on freebsd
+ */
+
+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));
+}
+#else
+#define reset_floating_point_exceptions()
+#endif /* __FreeBSD__ && HAVE_IEEEFP_H */
+
+#ifdef __cplusplus
+}
+#endif
+
+#if defined(HAVE_LINUXTHREADS)
+#define THR_KILL_SIGNAL SIGINT
+#else
+#define THR_KILL_SIGNAL SIGUSR2 // Can't use this with LinuxThreads
+#endif
+
+#ifdef HAVE_GLIBC2_STYLE_GETHOSTBYNAME_R
+#include <sys/types.h>
+#else
+#include <my_pthread.h> // For thr_setconcurency()
+#endif
+#if defined(HAVE_GETRLIMIT) && defined(RLIMIT_NOFILE) && !defined(__linux__) && !defined(HAVE_mit_thread)
+#define SET_RLIMIT_NOFILE
+#endif
+
+#ifdef SOLARIS
+extern "C" int gethostname(char *name, int namelen);
+#endif
+
+#define MYSQL_KILL_SIGNAL SIGTERM
+
+#ifndef DBUG_OFF
+static const char* default_dbug_option=IF_WIN("d:t:i:O,\\mysqld.trace",
+ "d:t:i:o,/tmp/mysqld.trace");
+#endif
+
+#ifdef __NT__
+static char szPipeName [ 257 ];
+static SECURITY_ATTRIBUTES saPipeSecurity;
+static SECURITY_DESCRIPTOR sdPipeDescriptor;
+static HANDLE hPipe = INVALID_HANDLE_VALUE;
+static pthread_cond_t COND_handler_count;
+static uint handler_count;
+#endif
+#ifdef __WIN__
+static bool opt_console=0;
+#endif
+
+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 my_string opt_logname=0,opt_update_logname=0,
+ opt_binlog_index_name = 0,opt_slow_logname=0;
+my_string opt_bin_logname = 0; // this one needs to be seen in sql_parse.cc
+static char mysql_home[FN_REFLEN],pidfile_name[FN_REFLEN];
+static pthread_t select_thread;
+static pthread_t flush_thread; // Used when debugging
+static bool opt_log,opt_update_log,opt_bin_log,opt_slow_log,opt_noacl,
+ opt_disable_networking=0, opt_bootstrap=0,opt_skip_show_db=0,
+ opt_ansi_mode;
+bool opt_sql_bin_update = 0, opt_log_slave_updates = 0;
+
+// 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;
+
+#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;
+#endif /* HAVE_OPENSSL */
+
+extern bool slave_running;
+
+I_List<i_string> replicate_do_db, replicate_ignore_db;
+// allow the user to tell us which db to replicate and which to ignore
+I_List<i_string> binlog_do_db, binlog_ignore_db;
+
+uint mysql_port;
+uint test_flags, 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;
+ulong thd_startup_options=(OPTION_UPDATE_LOG | OPTION_AUTO_IS_NULL |
+ OPTION_BIN_LOG | OPTION_AUTO_COMMIT);
+uint protocol_version=PROTOCOL_VERSION;
+ulong keybuff_size,sortbuff_size,max_item_sort_length,table_cache_size,
+ max_join_size,join_buff_size,tmp_table_size,thread_stack,
+ thread_stack_min,net_wait_timeout,what_to_log= ~ (1L << (uint) COM_TIME),
+ query_buff_size, lower_case_table_names, mysqld_net_retry_count,
+ net_interactive_timeout, slow_launch_time = 2L,
+ net_read_timeout,net_write_timeout;
+ulong thread_cache_size=0;
+volatile ulong cached_thread_count=0;
+
+// replication parameters, if master_host is not NULL, we are slaving off the master
+my_string master_user = (char*) "test", master_password = 0, master_host=0,
+ master_info_file = (char*) "master.info";
+uint master_port = MYSQL_PORT, master_connect_retry = 60;
+
+ulong max_tmp_tables,max_heap_table_size;
+ulong bytes_sent = 0L, bytes_received = 0L;
+
+bool opt_endinfo,using_udf_functions,low_priority_updates;
+bool volatile abort_loop,select_thread_in_use,flush_thread_in_use,grant_option;
+bool volatile ready_to_exit,shutdown_in_progress;
+ulong refresh_version=1L,flush_version=1L; /* Increments on each reload */
+ulong query_id=1L,long_query_count,long_query_time,aborted_threads,
+ aborted_connects,delayed_insert_timeout,delayed_insert_limit,
+ delayed_queue_size,delayed_insert_threads,delayed_insert_writes,
+ delayed_rows_in_use,delayed_insert_errors,flush_time;
+ulong specialflag=0,opened_tables=0,created_tmp_tables=0;
+ulong max_connections,max_insert_delayed_threads,max_used_connections,
+ max_connect_errors;
+ulong thread_id=1L,current_pid;
+ulong slow_launch_threads = 0;
+char mysql_real_data_home[FN_REFLEN],
+ mysql_data_home[2],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;
+char server_version[50]=MYSQL_SERVER_VERSION;
+const char *first_keyword="first";
+const char **errmesg; /* Error messages */
+byte last_ref[MAX_REFLENGTH]; /* Index ref of keys */
+my_string mysql_unix_port=NULL,mysql_tmpdir=NULL;
+ulong my_bind_addr; /* the address we bind to */
+DATE_FORMAT dayord;
+double log_10[32]; /* 10 potences */
+I_List<THD> threads,thread_cache;
+time_t start_time;
+
+pthread_key(MEM_ROOT*,THR_MALLOC);
+pthread_key(THD*, THR_THD);
+pthread_key(NET*, THR_NET);
+pthread_mutex_t LOCK_mysql_create_db, LOCK_Acl, LOCK_open, LOCK_thread_count,
+ LOCK_mapped_file, LOCK_status, LOCK_grant,
+ LOCK_error_log,
+ LOCK_delayed_insert, LOCK_delayed_status, LOCK_delayed_create,
+ LOCK_flush, LOCK_crypt, LOCK_bytes_sent, LOCK_bytes_received,
+ LOCK_binlog_update, LOCK_slave;
+
+pthread_cond_t COND_refresh,COND_thread_count,COND_flush, COND_binlog_update,
+ COND_slave_stopped;
+pthread_cond_t COND_thread_cache,COND_flush_thread_cache;
+pthread_t signal_thread;
+pthread_attr_t connection_attrib;
+enum db_type default_table_type=DB_TYPE_MYISAM;
+
+#ifdef __WIN__
+#undef getpid
+#include <process.h>
+HANDLE hEventShutdown;
+#include "nt_servc.h"
+static NTService Service; // Service object for WinNT
+#endif
+
+static void *signal_hand(void *arg);
+static void set_options(void);
+static void get_options(int argc,char **argv);
+static char *get_relative_path(const char *path);
+static void fix_paths(void);
+static pthread_handler_decl(handle_connections_sockets,arg);
+static int bootstrap(FILE *file);
+static bool read_init_file(char *file_name);
+#ifdef __NT__
+static pthread_handler_decl(handle_connections_namedpipes,arg);
+#endif
+#ifdef __WIN__
+static int get_service_parameters();
+#endif
+static pthread_handler_decl(handle_flush,arg);
+extern pthread_handler_decl(handle_slave,arg);
+#ifdef SET_RLIMIT_NOFILE
+static uint set_maximum_open_files(uint max_file_limit);
+#endif
+
+
+/****************************************************************************
+** Code to end mysqld
+****************************************************************************/
+
+static void close_connections(void)
+{
+#ifdef EXTRA_DEBUG
+ int count=0;
+#endif
+ NET net;
+ DBUG_ENTER("close_connections");
+
+ /* Clear thread cache */
+ kill_cached_threads++;
+ flush_thread_cache();
+
+ /* kill flush thread */
+ (void) pthread_mutex_lock(&LOCK_flush);
+ if (flush_thread_in_use)
+ {
+ DBUG_PRINT("quit",("killing flush thread: %lx",flush_thread));
+ (void) pthread_cond_signal(&COND_flush);
+ }
+ (void) pthread_mutex_unlock(&LOCK_flush);
+
+ /* kill connection thread */
+#if !defined(__WIN__) && !defined(__EMX__)
+ DBUG_PRINT("quit",("waiting for select thread: %lx",select_thread));
+ (void) pthread_mutex_lock(&LOCK_thread_count);
+
+ while (select_thread_in_use)
+ {
+ struct timespec abstime;
+ int error;
+ LINT_INIT(error);
+#ifndef DONT_USE_THR_ALARM
+ 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
+ for (uint tmp=0 ; tmp < 10 ; tmp++)
+ {
+ error=pthread_cond_timedwait(&COND_thread_count,&LOCK_thread_count,
+ &abstime);
+ if (error != EINTR)
+ break;
+ }
+#ifdef EXTRA_DEBUG
+ if (error != 0 && !count++)
+ sql_print_error("Got error %d from pthread_cond_timedwait",error);
+#endif
+#if defined(AIX_3_2) || defined(HAVE_DEC_3_2_THREADS)
+ if (ip_sock != INVALID_SOCKET)
+ {
+ VOID(shutdown(ip_sock,2));
+ VOID(closesocket(ip_sock));
+ VOID(shutdown(unix_sock,2));
+ VOID(closesocket(unix_sock));
+ VOID(unlink(mysql_unix_port));
+ ip_sock=unix_sock= INVALID_SOCKET;
+ }
+#endif
+ }
+ (void) pthread_mutex_unlock(&LOCK_thread_count);
+#endif /* __WIN__ */
+
+
+ /* Abort listening to new connections */
+ DBUG_PRINT("quit",("Closing sockets"));
+ if ( !opt_disable_networking )
+ {
+ if (ip_sock != INVALID_SOCKET)
+ {
+ (void) shutdown(ip_sock,2);
+ (void) closesocket(ip_sock);
+ ip_sock= INVALID_SOCKET;
+ }
+ }
+#ifdef __NT__
+ if ( hPipe != INVALID_HANDLE_VALUE )
+ {
+ HANDLE hTempPipe = hPipe;
+ DBUG_PRINT( "quit", ("Closing named pipes") );
+ hPipe = INVALID_HANDLE_VALUE;
+ CancelIo( hTempPipe );
+ DisconnectNamedPipe( hTempPipe );
+ CloseHandle( hTempPipe );
+ }
+#endif
+#ifdef HAVE_SYS_UN_H
+ if (unix_sock != INVALID_SOCKET)
+ {
+ (void) shutdown(unix_sock,2);
+ (void) closesocket(unix_sock);
+ (void) unlink(mysql_unix_port);
+ unix_sock= INVALID_SOCKET;
+ }
+#endif
+ end_thr_alarm(); // Don't allow alarms
+
+ /* First signal all threads that it's time to die */
+
+ THD *tmp;
+ (void) pthread_mutex_lock(&LOCK_thread_count); // For unlink from list
+
+ I_List_iterator<THD> it(threads);
+ while ((tmp=it++))
+ {
+ DBUG_PRINT("quit",("Informing thread %ld that it's time to die",
+ tmp->thread_id));
+ tmp->killed=1;
+ if (tmp->mysys_var)
+ {
+ tmp->mysys_var->abort=1;
+ if (tmp->mysys_var->current_mutex)
+ {
+ pthread_mutex_lock(tmp->mysys_var->current_mutex);
+ pthread_cond_broadcast(tmp->mysys_var->current_cond);
+ pthread_mutex_unlock(tmp->mysys_var->current_mutex);
+ }
+ }
+ }
+ (void) pthread_mutex_unlock(&LOCK_thread_count); // For unlink from list
+
+ if (thread_count)
+ {
+ sleep(1); // Give threads time to die
+ }
+
+ /* Force remaining threads to die by closing the connection to the client */
+
+ (void) my_net_init(&net, (Vio*) 0);
+ for (;;)
+ {
+ DBUG_PRINT("quit",("Locking LOCK_thread_count"));
+ (void) pthread_mutex_lock(&LOCK_thread_count); // For unlink from list
+ if (!(tmp=threads.get()))
+ {
+ DBUG_PRINT("quit",("Unlocking LOCK_thread_count"));
+ (void) pthread_mutex_unlock(&LOCK_thread_count);
+ break;
+ }
+#ifndef __bsdi__ // Bug in BSDI kernel
+ if ((net.vio=tmp->net.vio) != 0)
+ {
+ sql_print_error(ER(ER_FORCING_CLOSE),my_progname,
+ tmp->thread_id,tmp->user ? tmp->user : "");
+ close_connection(&net,0,0);
+ }
+#endif
+ DBUG_PRINT("quit",("Unlocking LOCK_thread_count"));
+ (void) pthread_mutex_unlock(&LOCK_thread_count);
+ }
+ net_end(&net);
+ /* All threads has now been aborted */
+ DBUG_PRINT("quit",("Waiting for threads to die (count=%u)",thread_count));
+ (void) pthread_mutex_lock(&LOCK_thread_count);
+ while (thread_count)
+ {
+ (void) pthread_cond_wait(&COND_thread_count,&LOCK_thread_count);
+ DBUG_PRINT("quit",("One thread died (count=%u)",thread_count));
+ }
+ (void) pthread_mutex_unlock(&LOCK_thread_count);
+
+ mysql_log.close();
+ mysql_update_log.close();
+ mysql_bin_log.close();
+ my_free(charsets_list, MYF(0));
+ DBUG_PRINT("quit",("close_connections thread"));
+ DBUG_VOID_RETURN;
+}
+
+void kill_mysql(void)
+{
+ DBUG_ENTER("kill_mysql");
+
+#if defined(__WIN__)
+ {
+ if (!SetEvent(hEventShutdown))
+ {
+ DBUG_PRINT("error",("Got error: %ld from SetEvent",GetLastError()));
+ }
+ // or:
+ // HANDLE hEvent=OpenEvent(0, FALSE, "MySqlShutdown");
+ // SetEvent(hEventShutdown);
+ // CloseHandle(hEvent);
+ }
+#elif defined(HAVE_PTHREAD_KILL)
+ if (pthread_kill(signal_thread,SIGTERM)) /* End everything nicely */
+ {
+ DBUG_PRINT("error",("Got error %d from pthread_kill",errno)); /* purecov: inspected */
+ }
+#else
+ kill(current_pid,SIGTERM);
+#endif
+ DBUG_PRINT("quit",("After pthread_kill"));
+ shutdown_in_progress=1; // Safety if kill didn't work
+ DBUG_VOID_RETURN;
+}
+
+
+ /* Force server down. kill all connections and threads and exit */
+
+#ifndef __WIN__
+static void *kill_server(void *sig_ptr)
+#define RETURN_FROM_KILL_SERVER return 0
+#else
+static void __cdecl kill_server(int sig_ptr)
+#define RETURN_FROM_KILL_SERVER return
+#endif
+{
+ 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 (kill_in_progress) // Safety
+ RETURN_FROM_KILL_SERVER;
+ kill_in_progress=TRUE;
+ abort_loop=1; // This should be set
+ signal(sig,SIG_IGN);
+ if (sig == MYSQL_KILL_SIGNAL || sig == 0)
+ sql_print_error(ER(ER_NORMAL_SHUTDOWN),my_progname);
+ else
+ sql_print_error(ER(ER_GOT_SIGNAL),my_progname,sig); /* purecov: inspected */
+
+#if defined(USE_ONE_SIGNAL_HAND) && !defined(__WIN__)
+ my_thread_init(); // If this is a new thread
+#endif
+ close_connections();
+ sql_print_error(ER(ER_SHUTDOWN_COMPLETE),my_progname);
+ if (sig != MYSQL_KILL_SIGNAL && sig != 0)
+ unireg_abort(1); /* purecov: inspected */
+ else
+ unireg_end(0);
+ pthread_exit(0); /* purecov: deadcode */
+ RETURN_FROM_KILL_SERVER;
+}
+
+
+#ifdef USE_ONE_SIGNAL_HAND
+pthread_handler_decl(kill_server_thread,arg __attribute__((unused)))
+{
+ my_thread_init(); // Initialize new thread
+ kill_server(0);
+ my_thread_end(); // Normally never reached
+ return 0;
+}
+#endif
+
+static sig_handler print_signal_warning(int sig)
+{
+ sql_print_error("Warning: Got signal %d from thread %d",
+ sig,my_thread_id());
+#ifdef DONT_REMEMBER_SIGNAL
+ sigset(sig,print_signal_warning); /* int. thread system calls */
+#endif
+#ifndef __WIN__
+ if (sig == SIGALRM)
+ alarm(2); /* reschedule alarm */
+#endif
+}
+
+
+void unireg_end(int signal_number __attribute__((unused)))
+{
+ clean_up();
+ pthread_exit(0); // Exit is in main thread
+}
+
+
+void unireg_abort(int exit_code)
+{
+ if (exit_code)
+ sql_print_error("Aborting\n");
+ (void) my_delete(pidfile_name,MYF(0)); // This may not always exist
+ clean_up(); /* purecov: inspected */
+ exit(exit_code); /* purecov: inspected */
+}
+
+
+void clean_up(void)
+{
+ DBUG_PRINT("exit",("clean_up"));
+ if (cleanup_done++)
+ return; /* purecov: inspected */
+ acl_free(1);
+ grant_free();
+ sql_cache_free();
+ table_cache_free();
+ hostname_cache_free();
+ item_user_lock_free();
+ lex_free(); /* Free some memory */
+#ifdef HAVE_DLOPEN
+ if (!opt_noacl)
+ udf_free();
+#endif
+ end_key_cache(); /* This is usually freed automaticly */
+ (void) ha_panic(HA_PANIC_CLOSE); /* close all tables */
+#ifdef USE_RAID
+ end_raid();
+#endif
+ x_free((gptr) errmsg[ERRMAPP]); /* Free messages */
+ free_defaults(defaults_argv);
+ my_free(mysql_tmpdir,MYF(0));
+ my_end(opt_endinfo ? MY_CHECK_ERROR | MY_GIVE_INFO : 0);
+
+ /* Tell main we are ready */
+ (void) pthread_mutex_lock(&LOCK_thread_count);
+ ready_to_exit=1;
+ (void) pthread_cond_broadcast(&COND_thread_count);
+ (void) pthread_mutex_unlock(&LOCK_thread_count);
+} /* clean_up */
+
+
+
+/****************************************************************************
+** Init IP and UNIX socket
+****************************************************************************/
+
+static void set_ports()
+{
+ char *env;
+ if (!mysql_port)
+ { // Get port if not from commandline
+ struct servent *serv_ptr;
+ mysql_port = MYSQL_PORT;
+ if ((serv_ptr = getservbyname("mysql", "tcp")))
+ mysql_port = ntohs((u_short) serv_ptr->s_port); /* purecov: inspected */
+ if ((env = getenv("MYSQL_TCP_PORT")))
+ mysql_port = (uint) atoi(env); /* purecov: inspected */
+ }
+ if (!mysql_unix_port)
+ {
+#ifdef __WIN__
+ mysql_unix_port = (char*) MYSQL_NAMEDPIPE;
+#else
+ mysql_unix_port = (char*) MYSQL_UNIX_ADDR;
+#endif
+ if ((env = getenv("MYSQL_UNIX_PORT")))
+ mysql_unix_port = env; /* purecov: inspected */
+ }
+}
+
+/* Change to run as another user if started with --user */
+
+static void set_user(const char *user)
+{
+#ifndef __WIN__
+ struct passwd *ent;
+
+ // don't bother if we aren't superuser
+ if (geteuid())
+ {
+ if (user)
+ fprintf(stderr,
+ "Warning: One can only use the --user switch if running as root\n");
+ return;
+ }
+ else if (!user)
+ {
+ if (!opt_bootstrap)
+ {
+ fprintf(stderr,"Fatal error: Please read \"Security\" section of the manual to find out how to run mysqld as root!\n");
+ unireg_abort(1);
+ }
+ return;
+ }
+ if (!strcmp(user,"root"))
+ return; // Avoid problem with dynamic libraries
+
+ 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);
+ }
+#ifdef HAVE_INITGROUPS
+ initgroups(user,ent->pw_gid);
+#endif
+ if (setgid(ent->pw_gid) == -1)
+ {
+ sql_perror("setgid");
+ unireg_abort(1);
+ }
+ if (setuid(ent->pw_uid) == -1)
+ {
+ sql_perror("setuid");
+ unireg_abort(1);
+ }
+#endif
+}
+
+/* Change root user if started with --chroot */
+
+static void set_root(const char *path)
+{
+#if !defined(__WIN__) && !defined(__EMX__)
+ if (chroot(path) == -1)
+ {
+ sql_perror("chroot");
+ unireg_abort(1);
+ }
+#endif
+}
+
+static void server_init(void)
+{
+ struct sockaddr_in IPaddr;
+#ifdef HAVE_SYS_UN_H
+ struct sockaddr_un UNIXaddr;
+#endif
+ int arg=1;
+ DBUG_ENTER("server_init");
+
+#ifdef __WIN__
+ if ( !opt_disable_networking )
+ {
+ WSADATA WsaData;
+ if (SOCKET_ERROR == WSAStartup (0x0101, &WsaData))
+ {
+ my_message(0,"WSAStartup Failed\n",MYF(0));
+ unireg_abort(1);
+ }
+ }
+#endif /* __WIN__ */
+
+ set_ports();
+
+ if (mysql_port != 0 && !opt_disable_networking && !opt_bootstrap)
+ {
+ DBUG_PRINT("general",("IP Socket is %d",mysql_port));
+ ip_sock = socket(AF_INET, SOCK_STREAM, 0);
+ if (ip_sock == INVALID_SOCKET)
+ {
+ DBUG_PRINT("error",("Got error: %d from socket()",socket_errno));
+ sql_perror(ER(ER_IPSOCK_ERROR)); /* purecov: tested */
+ unireg_abort(1); /* purecov: tested */
+ }
+ bzero((char*) &IPaddr, sizeof(IPaddr));
+ IPaddr.sin_family = AF_INET;
+ IPaddr.sin_addr.s_addr = my_bind_addr;
+ IPaddr.sin_port = (unsigned short) htons((unsigned short) mysql_port);
+ (void) setsockopt(ip_sock,SOL_SOCKET,SO_REUSEADDR,(char*)&arg,sizeof(arg));
+ for(;;)
+ {
+ if (bind(ip_sock, my_reinterpret_cast(struct sockaddr *) (&IPaddr),
+ sizeof(IPaddr)) >= 0)
+ break;
+ DBUG_PRINT("error",("Got error: %d from bind",socket_errno));
+ sql_perror("Can't start server: Bind on TCP/IP port");/* Had a loop here */
+ sql_print_error("Do you already have another mysqld server running on port: %d ?",mysql_port);
+ unireg_abort(1);
+ }
+ (void) listen(ip_sock,(int) back_log);
+ }
+
+ if (mysqld_chroot)
+ set_root(mysqld_chroot);
+
+ set_user(mysqld_user); // set_user now takes care of mysqld_user==NULL
+
+#ifdef __NT__
+ /* create named pipe */
+ if (Service.IsNT() && mysql_unix_port[0] && !opt_bootstrap)
+ {
+ sprintf( szPipeName, "\\\\.\\pipe\\%s", mysql_unix_port );
+ ZeroMemory( &saPipeSecurity, sizeof(saPipeSecurity) );
+ ZeroMemory( &sdPipeDescriptor, sizeof(sdPipeDescriptor) );
+ if ( !InitializeSecurityDescriptor(&sdPipeDescriptor,
+ SECURITY_DESCRIPTOR_REVISION) )
+ {
+ sql_perror("Can't start server : Initialize security descriptor");
+ unireg_abort(1);
+ }
+ if (!SetSecurityDescriptorDacl(&sdPipeDescriptor, TRUE, NULL, FALSE))
+ {
+ sql_perror("Can't start server : Set security descriptor");
+ unireg_abort(1);
+ }
+ saPipeSecurity.nLength = sizeof( SECURITY_ATTRIBUTES );
+ saPipeSecurity.lpSecurityDescriptor = &sdPipeDescriptor;
+ saPipeSecurity.bInheritHandle = FALSE;
+ if ((hPipe = CreateNamedPipe(szPipeName,
+ PIPE_ACCESS_DUPLEX,
+ PIPE_TYPE_BYTE |
+ PIPE_READMODE_BYTE |
+ PIPE_WAIT,
+ PIPE_UNLIMITED_INSTANCES,
+ (int) net_buffer_length,
+ (int) net_buffer_length,
+ NMPWAIT_USE_DEFAULT_WAIT,
+ &saPipeSecurity )) == INVALID_HANDLE_VALUE)
+ {
+ LPVOID lpMsgBuf;
+ int error=GetLastError();
+ FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ (LPTSTR) &lpMsgBuf, 0, NULL );
+ MessageBox( NULL, (LPTSTR) lpMsgBuf, "Error from CreateNamedPipe",
+ MB_OK|MB_ICONINFORMATION );
+ LocalFree( lpMsgBuf );
+ unireg_abort(1);
+ }
+ }
+#endif
+
+#if defined(HAVE_SYS_UN_H) && !defined(HAVE_mit_thread)
+ /*
+ ** Create the UNIX socket
+ */
+ if (mysql_unix_port[0] && !opt_bootstrap)
+ {
+ DBUG_PRINT("general",("UNIX Socket is %s",mysql_unix_port));
+
+ if ((unix_sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
+ {
+ sql_perror("Can't start server : UNIX Socket "); /* purecov: inspected */
+ unireg_abort(1); /* purecov: inspected */
+ }
+ bzero((char*) &UNIXaddr, sizeof(UNIXaddr));
+ UNIXaddr.sun_family = AF_UNIX;
+ strmov(UNIXaddr.sun_path, mysql_unix_port);
+ (void) unlink(mysql_unix_port);
+ (void) setsockopt(unix_sock,SOL_SOCKET,SO_REUSEADDR,(char*)&arg,
+ sizeof(arg));
+ umask(0);
+ if (bind(unix_sock, my_reinterpret_cast(struct sockaddr *) (&UNIXaddr),
+ sizeof(UNIXaddr)) < 0)
+ {
+ sql_perror("Can't start server : Bind on unix socket"); /* purecov: tested */
+ sql_print_error("Do you already have another mysqld server running on socket: %s ?",mysql_unix_port);
+ unireg_abort(1); /* purecov: tested */
+ }
+ umask(((~my_umask) & 0666));
+#if defined(S_IFSOCK) && defined(SECURE_SOCKETS)
+ (void) chmod(mysql_unix_port,S_IFSOCK); /* Fix solaris 2.6 bug */
+#endif
+ (void) listen(unix_sock,(int) back_log);
+ }
+#endif
+ DBUG_PRINT("info",("server started"));
+ DBUG_VOID_RETURN;
+}
+
+
+void yyerror(const char *s)
+{
+ NET *net=my_pthread_getspecific_ptr(NET*,THR_NET);
+ char *yytext=(char*) current_lex->tok_start;
+ if (!strcmp(s,"parse error"))
+ s=ER(ER_SYNTAX_ERROR);
+ net_printf(net,ER_PARSE_ERROR, s, yytext ? (char*) yytext : "",
+ current_lex->yylineno);
+}
+
+
+void close_connection(NET *net,uint errcode,bool lock)
+{
+ Vio* vio;
+ DBUG_ENTER("close_connection");
+ DBUG_PRINT("enter",("fd: %s error: '%s'",
+ net->vio? vio_description(net->vio):"(not connected)",
+ errcode ? ER(errcode) : ""));
+ if (lock)
+ (void) pthread_mutex_lock(&LOCK_thread_count);
+ if ((vio=net->vio) != 0)
+ {
+ if (errcode)
+ send_error(net,errcode,ER(errcode)); /* purecov: inspected */
+ vio_close(vio); /* vio is freed in delete thd */
+ }
+ if (lock)
+ (void) pthread_mutex_unlock(&LOCK_thread_count);
+ DBUG_VOID_RETURN;
+}
+
+ /* Called when a thread is aborted */
+ /* ARGSUSED */
+
+sig_handler end_thread_signal(int sig __attribute__((unused)))
+{
+ THD *thd=current_thd;
+ DBUG_ENTER("end_thread_signal");
+ if (thd)
+ end_thread(thd,0);
+ DBUG_VOID_RETURN; /* purecov: deadcode */
+}
+
+
+void end_thread(THD *thd, bool put_in_cache)
+{
+ DBUG_ENTER("end_thread");
+ (void) pthread_mutex_lock(&LOCK_thread_count);
+ thread_count--;
+ delete thd;
+
+ if (cached_thread_count < thread_cache_size && ! abort_loop &&
+ !kill_cached_threads)
+ {
+ /* Don't kill the thread, just put it in cache for reuse */
+ DBUG_PRINT("info", ("Adding thread to cache"))
+ cached_thread_count++;
+ while (!abort_loop && ! wake_thread && ! kill_cached_threads)
+ (void) pthread_cond_wait(&COND_thread_cache, &LOCK_thread_count);
+ cached_thread_count--;
+ if (kill_cached_threads)
+ pthread_cond_signal(&COND_flush_thread_cache);
+ if (wake_thread)
+ {
+ wake_thread--;
+ thd=thread_cache.get();
+ threads.append(thd);
+ (void) thd->store_globals();
+ pthread_mutex_unlock(&LOCK_thread_count);
+ DBUG_VOID_RETURN;
+ }
+ }
+
+ DBUG_PRINT("info", ("sending a broadcast"))
+
+ /* Tell main we are ready */
+ (void) pthread_cond_broadcast(&COND_thread_count);
+ (void) pthread_mutex_unlock(&LOCK_thread_count);
+ DBUG_PRINT("info", ("unlocked thread_count mutex"))
+#ifndef DBUG_OFF
+ if (!(test_flags & TEST_NO_THREADS)) // For debugging under Linux
+#endif
+ {
+ my_thread_end();
+ pthread_exit(0);
+ }
+ DBUG_VOID_RETURN;
+}
+
+
+/* Start a cached thread. LOCK_thread_count is locked on entry */
+
+static void start_cached_thread(THD *thd)
+{
+ thread_cache.append(thd);
+ wake_thread++;
+ thread_count++;
+ pthread_cond_signal(&COND_thread_cache);
+}
+
+
+void flush_thread_cache()
+{
+ (void) pthread_mutex_lock(&LOCK_thread_count);
+ kill_cached_threads++;
+ while (cached_thread_count)
+ {
+ pthread_cond_broadcast(&COND_thread_cache);
+ pthread_cond_wait(&COND_flush_thread_cache,&LOCK_thread_count);
+ }
+ kill_cached_threads--;
+ (void) pthread_mutex_unlock(&LOCK_thread_count);
+}
+
+
+ /*
+ ** Aborts a thread nicely. Commes here on SIGPIPE
+ ** TODO: One should have to fix that thr_alarm know about this
+ ** thread too
+ */
+
+#ifdef THREAD_SPECIFIC_SIGPIPE
+static sig_handler abort_thread(int sig __attribute__((unused)))
+{
+ THD *thd=current_thd;
+ DBUG_ENTER("abort_thread");
+ if (thd)
+ thd->killed=1;
+ DBUG_VOID_RETURN;
+}
+#endif
+
+/******************************************************************************
+** Setup a signal thread with handles all signals
+** Because linux doesn't support scemas use a mutex to check that
+** the signal thread is ready before continuing
+******************************************************************************/
+
+#ifdef __WIN__
+static void init_signals(void)
+{
+ int signals[] = {SIGINT,SIGILL,SIGFPE,SIGSEGV,SIGTERM,SIGABRT } ;
+ for (uint i=0 ; i < sizeof(signals)/sizeof(int) ; i++)
+ signal( signals[i], kill_server) ;
+ signal(SIGBREAK,SIG_IGN); //ignore SIGBREAK for NT
+}
+
+#elif defined(__EMX__)
+static void sig_reload(int signo)
+{
+ reload_acl_and_cache(~0); // Flush everything
+ signal(signo, SIG_ACK);
+}
+
+static void sig_kill(int signo)
+{
+ if (!abort_loop)
+ {
+ abort_loop=1; // mark abort for threads
+ kill_server((void*) 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();
+}
+#else
+
+static void init_signals(void)
+{
+ sigset_t set;
+ pthread_attr_t thr_attr;
+ int error;
+ DBUG_ENTER("init_signals");
+
+ sigset(THR_KILL_SIGNAL,end_thread_signal);
+ sigset(THR_SERVER_ALARM,print_signal_warning); // Should never be called!
+ (void) sigemptyset(&set);
+#ifdef THREAD_SPECIFIC_SIGPIPE
+ sigset(SIGPIPE,abort_thread);
+ sigaddset(&set,SIGPIPE);
+#else
+ (void) signal(SIGPIPE,SIG_IGN); // Can't know which thread
+ sigaddset(&set,SIGPIPE);
+#endif
+ sigaddset(&set,SIGINT);
+ sigaddset(&set,SIGQUIT);
+ sigaddset(&set,SIGTERM);
+ sigaddset(&set,SIGHUP);
+ signal(SIGTERM,SIG_DFL); // If it's blocked by parent
+#ifdef SIGTSTP
+ sigaddset(&set,SIGTSTP);
+#endif
+ sigaddset(&set,THR_SERVER_ALARM);
+ sigdelset(&set,THR_KILL_SIGNAL); // May be SIGINT
+ sigdelset(&set,THR_CLIENT_ALARM); // For alarms
+ (void) pthread_sigmask(SIG_SETMASK,&set,NULL);
+
+ (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);
+ if (!(opt_specialflag & SPECIAL_NO_PRIOR))
+ my_pthread_attr_setprio(&thr_attr,INTERRUPT_PRIOR);
+ pthread_attr_setstacksize(&thr_attr,32768);
+#endif
+
+ (void) pthread_mutex_lock(&LOCK_thread_count);
+ if ((error=pthread_create(&signal_thread,&thr_attr,signal_hand,0)))
+ {
+ sql_print_error("Can't create interrupt-thread (error %d, errno: %d)",
+ error,errno);
+ exit(1);
+ }
+ (void) pthread_cond_wait(&COND_thread_count,&LOCK_thread_count);
+ pthread_mutex_unlock(&LOCK_thread_count);
+
+ (void) pthread_attr_destroy(&thr_attr);
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+** This threads handles all signals and alarms
+*/
+
+/* ARGSUSED */
+static void *signal_hand(void *arg __attribute__((unused)))
+{
+ sigset_t set;
+ int sig;
+ my_thread_init(); // Init new thread
+ DBUG_ENTER("signal_hand");
+
+ /* Setup alarm handler */
+ init_thr_alarm(max_connections+max_insert_delayed_threads);
+#if SIGINT != THR_KILL_SIGNAL
+ (void) sigemptyset(&set); // Setup up SIGINT for debug
+ (void) sigaddset(&set,SIGINT); // For debugging
+ (void) pthread_sigmask(SIG_UNBLOCK,&set,NULL);
+#endif
+ (void) sigemptyset(&set); // Setup up SIGINT for debug
+#ifdef USE_ONE_SIGNAL_HAND
+ (void) sigaddset(&set,THR_SERVER_ALARM); // For alarms
+#endif
+ (void) sigaddset(&set,SIGQUIT);
+ (void) sigaddset(&set,SIGTERM);
+#if THR_CLIENT_ALARM != SIGHUP
+ (void) sigaddset(&set,SIGHUP);
+#endif
+ (void) sigaddset(&set,SIGTSTP);
+
+ /* Save pid to this process (or thread on Linux) */
+ {
+ FILE *pidFile;
+ if ((pidFile = my_fopen(pidfile_name,O_WRONLY,MYF(MY_WME))))
+ {
+ fprintf(pidFile,"%lu",(ulong) getpid());
+ (void) my_fclose(pidFile,MYF(0));
+ (void) chmod(pidfile_name,0644);
+ }
+ }
+
+ (void) pthread_mutex_lock(&LOCK_thread_count);
+ (void) pthread_cond_signal(&COND_thread_count); /* continue init_signals */
+ (void) pthread_mutex_unlock(&LOCK_thread_count);
+
+ for (;;)
+ {
+ int error; // Used when debugging
+ if (shutdown_in_progress && !abort_loop)
+ {
+ sig=SIGTERM;
+ error=0;
+ }
+ else
+ while ((error=my_sigwait(&set,&sig)) == EINTR) ;
+ if (cleanup_done)
+ pthread_exit(0); // Safety
+ switch (sig) {
+ case SIGTERM:
+ case SIGQUIT:
+ case SIGKILL:
+#ifdef EXTRA_DEBUG
+ sql_print_error("Got signal %d to shutdown mysqld",sig);
+#endif
+ DBUG_PRINT("info",("Got signal: %d abort_loop: %d",sig,abort_loop));
+ if (!abort_loop)
+ {
+ abort_loop=1; // mark abort for threads
+#ifdef USE_ONE_SIGNAL_HAND
+ pthread_t tmp;
+ if (!(opt_specialflag & SPECIAL_NO_PRIOR))
+ my_pthread_attr_setprio(&connection_attrib,INTERRUPT_PRIOR);
+ if (pthread_create(&tmp,&connection_attrib, kill_server_thread,
+ (void*) sig))
+ sql_print_error("Error: Can't create thread to kill server");
+#else
+ kill_server((void*) sig); // MIT THREAD has a alarm thread
+#endif
+ }
+ break;
+ case SIGHUP:
+ reload_acl_and_cache(~0); // Flush everything
+ mysql_print_status((THD*) 0); // Send debug some info
+ break;
+#ifdef USE_ONE_SIGNAL_HAND
+ case THR_SERVER_ALARM:
+ process_alarm(sig); // Trigger alarms.
+ break;
+#endif
+ default:
+#ifdef EXTRA_DEBUG
+ sql_print_error("Warning: Got signal: %d, error: %d",sig,error); /* purecov: tested */
+#endif
+ break; /* purecov: tested */
+ }
+ }
+ return(0); /* purecov: deadcode */
+}
+
+#endif /* __WIN__*/
+
+
+/*
+** All global error messages are sent here where the first one is stored for
+** the client
+*/
+
+
+/* ARGSUSED */
+static int my_message_sql(uint error, const char *str,
+ myf MyFlags __attribute__((unused)))
+{
+ NET *net;
+ DBUG_ENTER("my_message_sql");
+ DBUG_PRINT("error",("Message: '%s'",str));
+ if ((net=my_pthread_getspecific_ptr(NET*,THR_NET)))
+ {
+ if (!net->last_error[0]) // Return only first message
+ {
+ strmake(net->last_error,str,sizeof(net->last_error)-1);
+ net->last_errno=error ? error : ER_UNKNOWN_ERROR;
+ }
+ }
+ else
+ sql_print_error("%s: %s",my_progname,str); /* purecov: inspected */
+ DBUG_RETURN(0);
+}
+
+#ifdef __WIN__
+#undef errno
+#undef EINTR
+#define errno WSAGetLastError()
+#define EINTR WSAEINTR
+
+struct utsname
+{
+ char nodename[FN_REFLEN];
+};
+
+int uname(struct utsname *a)
+{
+ return -1;
+}
+#endif
+
+
+#ifdef __WIN__
+pthread_handler_decl(handle_shutdown,arg)
+{
+ MSG msg;
+ my_thread_init();
+
+ /* this call should create the message queue for this thread */
+ PeekMessage(&msg, NULL, 1, 65534,PM_NOREMOVE);
+
+ if (WaitForSingleObject(hEventShutdown,INFINITE)==WAIT_OBJECT_0)
+ kill_server(MYSQL_KILL_SIGNAL);
+ return 0;
+}
+
+int __stdcall handle_kill(ulong ctrl_type)
+{
+ if (ctrl_type == CTRL_CLOSE_EVENT ||
+ ctrl_type == CTRL_SHUTDOWN_EVENT)
+ {
+ kill_server(MYSQL_KILL_SIGNAL);
+ return TRUE;
+ }
+ return FALSE;
+}
+#endif
+
+const char *load_default_groups[]= { "mysqld","server",0 };
+
+#ifdef HAVE_LIBWRAP
+char *libwrapName=NULL;
+#endif
+
+static void open_log(MYSQL_LOG *log, const char *hostname,
+ const char *opt_name, const char *extension,
+ enum_log_type type)
+{
+ char tmp[FN_REFLEN];
+ if (!opt_name || !opt_name[0])
+ {
+ strnmov(tmp,hostname,FN_REFLEN-5);
+ strmov(strcend(tmp,'.'),extension);
+ opt_name=tmp;
+ }
+ log->open(opt_name,type);
+}
+
+
+
+#ifdef __WIN__
+int win_main(int argc, char **argv)
+#else
+int main(int argc, char **argv)
+#endif
+{
+ DEBUGGER_OFF;
+ char hostname[FN_REFLEN];
+
+ my_umask=0660; // Default umask for new files
+ my_umask_dir=0700; // Default umask for new directories
+ MY_INIT(argv[0]); // 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 == 1 ? 1 : 0]);
+ }
+#else
+ {
+ struct tm *start_tm;
+ start_tm=localtime(&start_time);
+ strmov(time_zone=tzname[start_tm->tm_isdst == 1 ? 1 : 0]);
+ }
+#endif
+#endif
+
+ if (gethostname(hostname,sizeof(hostname)-4) < 0)
+ strmov(hostname,"mysql");
+ strmov(pidfile_name,hostname);
+ strmov(strcend(pidfile_name,'.'),".pid"); // Add extension
+#ifdef DEMO_VERSION
+ strcat(server_version,"-demo");
+#endif
+#ifdef SHAREWARE_VERSION
+ strcat(server_version,"-shareware");
+#endif
+#ifndef DBUG_OFF
+ strcat(server_version,"-debug");
+#endif
+#ifdef _CUSTOMSTARTUPCONFIG_
+ if (_cust_check_startup())
+ {
+ /* _cust_check_startup will report startup failure error */
+ exit( 1 );
+ }
+#endif
+ load_defaults("my",load_default_groups,&argc,&argv);
+ defaults_argv=argv;
+ mysql_tmpdir=getenv("TMPDIR"); /* Use this if possible */
+#ifdef __WIN__
+ 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();
+#ifdef __WIN__
+ /* service parameters can be overwritten by options */
+ if (get_service_parameters())
+ {
+ my_message( 0, "Can't read MySQL service parameters", MYF(0) );
+ exit( 1 );
+ }
+#endif
+ get_options(argc,argv);
+ 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_cond_init(&COND_thread_count,NULL);
+ (void) pthread_mutex_init(&LOCK_mysql_create_db,NULL);
+ (void) pthread_mutex_init(&LOCK_Acl,NULL);
+ (void) pthread_mutex_init(&LOCK_grant,NULL);
+ (void) pthread_mutex_init(&LOCK_open,NULL);
+ (void) pthread_mutex_init(&LOCK_thread_count,NULL);
+ (void) pthread_mutex_init(&LOCK_mapped_file,NULL);
+ (void) pthread_mutex_init(&LOCK_status,NULL);
+ (void) pthread_mutex_init(&LOCK_error_log,NULL);
+ (void) pthread_mutex_init(&LOCK_delayed_insert,NULL);
+ (void) pthread_mutex_init(&LOCK_delayed_status,NULL);
+ (void) pthread_mutex_init(&LOCK_delayed_create,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_flush,NULL);
+ (void) pthread_mutex_init(&LOCK_flush,NULL);
+ (void) pthread_mutex_init(&LOCK_crypt,NULL);
+ (void) pthread_mutex_init(&LOCK_bytes_sent,NULL);
+ (void) pthread_mutex_init(&LOCK_bytes_received,NULL);
+ (void) pthread_mutex_init(&LOCK_timezone,NULL);
+ (void) pthread_mutex_init(&LOCK_binlog_update, NULL);
+ (void) pthread_mutex_init(&LOCK_slave, NULL);
+ (void) pthread_cond_init(&COND_binlog_update, NULL);
+ (void) pthread_cond_init(&COND_slave_stopped, NULL);
+
+ if (set_default_charset_by_name(default_charset, MYF(MY_WME)))
+ unireg_abort(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);
+ if (!ssl_acceptor_fd)
+ opt_use_ssl=0;
+ /* having ssl_acceptor_fd!=0 signals the use of SSL */
+ }
+#endif /* HAVE_OPENSSL */
+
+#ifdef HAVE_LIBWRAP
+ libwrapName= my_progname+dirname_length(my_progname);
+ openlog(libwrapName, LOG_PID, LOG_AUTH);
+#endif
+
+ if (!(opt_specialflag & SPECIAL_NO_PRIOR))
+ my_pthread_setprio(pthread_self(),CONNECT_PRIOR);
+ /* 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);
+
+ if (!(opt_specialflag & SPECIAL_NO_PRIOR))
+ my_pthread_attr_setprio(&connection_attrib,WAIT_PRIOR);
+ pthread_attr_setscope(&connection_attrib, PTHREAD_SCOPE_SYSTEM);
+
+#ifdef SET_RLIMIT_NOFILE
+ /* 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) (files-10)/5;
+ table_cache_size= (ulong) (files-10-max_connections)/2;
+ 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
+ select_thread=pthread_self();
+ select_thread_in_use=1;
+
+ /*
+ ** We have enough space for fiddling with the argv, continue
+ */
+ umask(((~my_umask) & 0666));
+ if (my_setwd(mysql_real_data_home,MYF(MY_WME)))
+ {
+ unireg_abort(1); /* purecov: inspected */
+ }
+ mysql_data_home[0]=FN_CURLIB; // all paths are relative from here
+ mysql_data_home[1]=0;
+ server_init();
+ 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();
+
+ /* Setup log files */
+ if (opt_log)
+ open_log(&mysql_log, hostname, opt_logname, ".log", LOG_NORMAL);
+ if (opt_update_log)
+ open_log(&mysql_update_log, hostname, opt_update_logname, "",
+ LOG_NEW);
+ if (opt_bin_log)
+ {
+ mysql_bin_log.set_index_file_name(opt_binlog_index_name);
+ open_log(&mysql_bin_log, hostname, opt_bin_logname, "-bin",
+ LOG_BIN);
+ }
+ if (opt_slow_log)
+ open_log(&mysql_slow_log, hostname, opt_slow_logname, "-slow.log",
+ LOG_NORMAL);
+ if (ha_init())
+ {
+ sql_print_error("Can't init databases");
+ exit(1);
+ }
+ ft_init_stopwords(NULL); /* SerG */
+
+#ifdef __WIN__
+#define MYSQL_ERR_FILE "mysql.err"
+ if (!opt_console)
+ {
+ freopen(MYSQL_ERR_FILE,"a+",stdout);
+ freopen(MYSQL_ERR_FILE,"a+",stderr);
+ FreeConsole(); // Remove window
+ }
+#endif
+
+ /*
+ 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);
+ }
+ init_signals(); // Creates pidfile
+ if (acl_init(opt_noacl))
+ {
+ select_thread_in_use=0;
+ (void) pthread_kill(signal_thread,MYSQL_KILL_SIGNAL);
+ (void) my_delete(pidfile_name,MYF(MY_WME)); // Not neaded anymore
+ exit(1);
+ }
+ if (!opt_noacl)
+ (void) grant_init();
+
+#ifdef HAVE_DLOPEN
+ if (!opt_noacl)
+ udf_init();
+#endif
+
+ if (opt_bootstrap)
+ {
+ int error=bootstrap(stdin);
+ end_thr_alarm(); // Don't allow alarms
+ unireg_abort(error ? 1 : 0);
+ }
+ if (opt_init_file)
+ {
+ if (read_init_file(opt_init_file))
+ {
+ end_thr_alarm(); // Don't allow alarms
+ unireg_abort(1);
+ }
+ }
+ (void) thr_setconcurrency(concurrency); // 10 by default
+#ifdef __WIN__ //IRENA
+ {
+ hEventShutdown=CreateEvent(0, FALSE, FALSE, "MySqlShutdown");
+ pthread_t hThread;
+ if (pthread_create(&hThread,&connection_attrib,handle_shutdown,0))
+ sql_print_error("Warning: Can't create thread to handle shutdown requests");
+
+ // On "Stop Service" we have to do regular shutdown
+ Service.SetShutdownEvent(hEventShutdown);
+ }
+#endif
+
+ if (flush_time && flush_time != ~(ulong) 0L)
+ {
+ pthread_t hThread;
+ if (pthread_create(&hThread,&connection_attrib,handle_flush,0))
+ sql_print_error("Warning: Can't create thread to handle flush");
+ }
+
+ // slave thread
+ if(master_host)
+ {
+ pthread_t hThread;
+ if(pthread_create(&hThread, &connection_attrib, handle_slave, 0))
+ sql_print_error("Warning: Can't create thread to handle slave");
+
+ }
+
+ printf(ER(ER_READY),my_progname,server_version,"");
+ fflush(stdout);
+
+#ifdef __NT__
+ if (hPipe == INVALID_HANDLE_VALUE && !have_tcpip)
+ {
+ sql_print_error("TCP/IP must be installed on Win98 platforms");
+ }
+ else
+ {
+ pthread_mutex_lock(&LOCK_thread_count);
+ (void) pthread_cond_init(&COND_handler_count,NULL);
+ {
+ pthread_t hThread;
+ handler_count=0;
+ if ( hPipe != INVALID_HANDLE_VALUE )
+ {
+ handler_count++;
+ if (pthread_create(&hThread,&connection_attrib,
+ handle_connections_namedpipes, 0))
+ {
+ sql_print_error("Warning: Can't create thread to handle named pipes");
+ handler_count--;
+ }
+ }
+ if (have_tcpip)
+ {
+ handler_count++;
+ if (pthread_create(&hThread,&connection_attrib,
+ handle_connections_sockets, 0))
+ {
+ sql_print_error("Warning: Can't create thread to handle named pipes");
+ handler_count--;
+ }
+ }
+ while (handler_count > 0)
+ {
+ pthread_cond_wait(&COND_handler_count,&LOCK_thread_count);
+ }
+ }
+ pthread_mutex_unlock(&LOCK_thread_count);
+ }
+#else
+ handle_connections_sockets(0);
+#ifdef EXTRA_DEBUG
+ sql_print_error("Exiting main thread");
+#endif
+#endif /* __NT__ */
+
+ /* (void) pthread_attr_destroy(&connection_attrib); */
+
+ DBUG_PRINT("quit",("Exiting main thread"));
+
+#ifndef __WIN__
+#ifdef EXTRA_DEBUG
+ sql_print_error("Before Lock_thread_count");
+#endif
+ (void) pthread_mutex_lock(&LOCK_thread_count);
+ 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
+ sql_print_error("After lock_thread_count");
+#endif
+#else
+ // remove the event, because it will not be valid anymore
+ Service.SetShutdownEvent(0);
+ if(hEventShutdown) CloseHandle(hEventShutdown);
+ // if it was started as service on NT try to stop the service
+ if(Service.IsNT())
+ Service.Stop();
+#endif
+
+ /* Wait until cleanup is done */
+ (void) pthread_mutex_lock(&LOCK_thread_count);
+ while (!ready_to_exit)
+ {
+ pthread_cond_wait(&COND_thread_count,&LOCK_thread_count);
+ }
+ (void) pthread_mutex_unlock(&LOCK_thread_count);
+ (void) my_delete(pidfile_name,MYF(MY_WME)); // Not neaded anymore
+ my_thread_end();
+ exit(0);
+ return(0); /* purecov: deadcode */
+}
+
+
+#ifdef __WIN__
+/* ------------------------------------------------------------------------
+ main and thread entry function for Win32
+ (all this is needed only to run mysqld as a service on WinNT)
+ -------------------------------------------------------------------------- */
+int mysql_service(void *p)
+{
+ win_main(Service.my_argc, Service.my_argv);
+ return 0;
+}
+
+int main(int argc, char **argv)
+{
+ // check environment variable OS
+ if (Service.GetOS()) // "OS" defined; Should be NT
+ {
+ if (argc == 2)
+ {
+ if (!strcmp(argv[1],"-install") || !strcmp(argv[1],"--install"))
+ {
+ char path[FN_REFLEN];
+ my_path(path, argv[0], ""); // Find name in path
+ fn_format(path,argv[0],path,"",1+4+16); // Force use of full path
+ if (!Service.Install(MYSQL_SERVICENAME,MYSQL_SERVICENAME,path))
+ MessageBox(NULL,"Failed to install Service",MYSQL_SERVICENAME,
+ MB_OK|MB_ICONSTOP);
+ return 0;
+ }
+ else if (!strcmp(argv[1],"-remove") || !strcmp(argv[1],"--remove"))
+ {
+ Service.Remove(MYSQL_SERVICENAME);
+ return 0;
+ }
+ }
+ else if (argc == 1) // No arguments; start as a service
+ {
+ // init service
+ long tmp=Service.Init(MYSQL_SERVICENAME,mysql_service);
+ return 0;
+ }
+ }
+
+ // 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;
+ mysql_service(NULL);
+ return 0;
+}
+/* ------------------------------------------------------------------------ */
+#endif
+
+
+static int bootstrap(FILE *file)
+{
+ THD *thd= new THD;
+ int error;
+ thd->bootstrap=1;
+ thd->client_capabilities=0;
+ my_net_init(&thd->net,(Vio*) 0);
+ thd->max_packet_length=thd->net.max_packet;
+ thd->master_access= ~0;
+ thread_count++;
+ thd->real_id=pthread_self();
+ error=handle_bootstrap(thd,file);
+ net_end(&thd->net);
+ delete thd;
+ return error;
+}
+
+static bool read_init_file(char *file_name)
+{
+ FILE *file;
+ DBUG_ENTER("read_init_file");
+ DBUG_PRINT("enter",("name: %s",file_name));
+ if (!(file=my_fopen(file_name,O_RDONLY,MYF(MY_WME))))
+ return(1);
+ bootstrap(file); /* Ignore errors from this */
+ (void) my_fclose(file,MYF(MY_WME));
+ return 0;
+}
+
+
+static void create_new_thread(THD *thd)
+{
+ DBUG_ENTER("create_new_thread");
+
+ NET *net=&thd->net; // For easy ref
+ net->timeout = (uint) connect_timeout; // Timeout for read
+ if (protocol_version > 9)
+ net->return_errno=1;
+
+ /* don't allow too many connections */
+ if (thread_count - delayed_insert_threads >= max_connections+1 || abort_loop)
+ {
+ DBUG_PRINT("error",("too many connections"));
+ close_connection(net,ER_CON_COUNT_ERROR);
+ delete thd;
+ DBUG_VOID_RETURN;
+ }
+ if (pthread_mutex_lock(&LOCK_thread_count))
+ {
+ DBUG_PRINT("error",("Can't lock LOCK_thread_count"));
+ close_connection(net,ER_OUT_OF_RESOURCES);
+ delete thd;
+ DBUG_VOID_RETURN;
+ }
+ if (thread_count-delayed_insert_threads > max_used_connections)
+ max_used_connections=thread_count-delayed_insert_threads;
+ thd->thread_id=thread_id++;
+ for (uint i=0; i < 8 ; i++) // Generate password teststring
+ thd->scramble[i]= (char) (rnd(&sql_rand)*94+33);
+ thd->scramble[8]=0;
+ thd->rand=sql_rand;
+ thd->real_id=pthread_self(); // Keep purify happy
+
+ /* Start a new thread to handle connection */
+#ifndef DBUG_OFF
+ if (test_flags & TEST_NO_THREADS) // For debugging under Linux
+ {
+ thread_cache_size=0; // Safety
+ thread_count++;
+ threads.append(thd);
+ thd->real_id=pthread_self();
+ (void) pthread_mutex_unlock(&LOCK_thread_count);
+ handle_one_connection((void*) thd);
+ }
+ else
+#endif
+ {
+ if (cached_thread_count > wake_thread)
+ {
+ start_cached_thread(thd);
+ (void) pthread_mutex_unlock(&LOCK_thread_count);
+ }
+ else
+ {
+ int error;
+ thread_count++;
+ threads.append(thd);
+ DBUG_PRINT("info",(("creating thread %d"), thd->thread_id));
+ thd->connect_time = time(NULL);
+ (void) pthread_mutex_unlock(&LOCK_thread_count);
+ if ((error=pthread_create(&thd->real_id,&connection_attrib,
+ handle_one_connection,
+ (void*) thd)))
+ {
+ DBUG_PRINT("error",
+ ("Can't create thread to handle request (error %d)",
+ error));
+ (void) pthread_mutex_lock(&LOCK_thread_count);
+ thread_count--;
+ thd->killed=1; // Safety
+ (void) pthread_mutex_unlock(&LOCK_thread_count);
+ net_printf(net,ER_CANT_CREATE_THREAD,error);
+ (void) pthread_mutex_lock(&LOCK_thread_count);
+ close_connection(net,0,0);
+ delete thd;
+ (void) pthread_mutex_unlock(&LOCK_thread_count);
+ DBUG_VOID_RETURN;
+ }
+ }
+ }
+ DBUG_PRINT("info",(("Thread %d created"), thd->thread_id));
+ DBUG_VOID_RETURN;
+}
+
+
+ /* Handle new connections and spawn new process to handle them */
+
+pthread_handler_decl(handle_connections_sockets,arg __attribute__((unused)))
+{
+ my_socket sock,new_sock;
+ uint error_count=0;
+ uint max_used_connection= (uint) (max(ip_sock,unix_sock)+1);
+ fd_set readFDs,clientFDs;
+ THD *thd;
+ struct sockaddr_in cAddr;
+ int ip_flags=0,socket_flags=0,flags;
+ Vio *vio_tmp;
+#ifdef __WIN__
+ my_thread_init();
+#endif
+ DBUG_ENTER("handle_connections_sockets");
+
+ LINT_INIT(new_sock);
+
+ (void) my_pthread_getprio(pthread_self()); // For debugging
+
+ FD_ZERO(&clientFDs);
+ if (ip_sock != INVALID_SOCKET)
+ {
+ FD_SET(ip_sock,&clientFDs);
+#ifdef HAVE_FCNTL
+ ip_flags = fcntl(ip_sock, F_GETFL, 0);
+#endif
+ }
+#ifdef HAVE_SYS_UN_H
+ FD_SET(unix_sock,&clientFDs);
+ socket_flags=fcntl(unix_sock, F_GETFL, 0);
+#endif
+
+ DBUG_PRINT("general",("Waiting for connections."));
+ while (!abort_loop)
+ {
+ readFDs=clientFDs;
+#ifdef HPUX
+ if (select(max_used_connection,(int*) &readFDs,0,0,0) < 0)
+ continue;
+#else
+ if (select((int) max_used_connection,&readFDs,0,0,0) < 0)
+ {
+ if (errno != EINTR)
+ {
+ if (!select_errors++ && !abort_loop) /* purecov: inspected */
+ sql_print_error("mysqld: Got error %d from select",errno); /* purecov: inspected */
+ }
+ continue;
+ }
+#endif /* HPUX */
+ if (abort_loop)
+ break;
+
+ /*
+ ** Is this a new connection request
+ */
+
+#ifdef HAVE_SYS_UN_H
+ if (FD_ISSET(unix_sock,&readFDs))
+ {
+ sock = unix_sock;
+ flags= socket_flags;
+ }
+ else
+#endif
+ {
+ sock = ip_sock;
+ flags= ip_flags;
+ }
+
+#if !defined(NO_FCNTL_NONBLOCK)
+ if (!(test_flags & TEST_BLOCKING))
+ {
+#if defined(O_NONBLOCK)
+ fcntl(sock, F_SETFL, flags | O_NONBLOCK);
+#elif defined(O_NDELAY)
+ fcntl(sock, F_SETFL, flags | O_NDELAY);
+#endif
+ }
+#endif /* NO_FCNTL_NONBLOCK */
+ for (uint retry=0; retry < MAX_ACCEPT_RETRY; retry++)
+ {
+ size_socket length=sizeof(struct sockaddr_in);
+ new_sock = accept(sock, my_reinterpret_cast(struct sockaddr *) (&cAddr),
+ &length);
+ if (new_sock != INVALID_SOCKET || (errno != EINTR && errno != EAGAIN))
+ break;
+#if !defined(NO_FCNTL_NONBLOCK)
+ if (!(test_flags & TEST_BLOCKING))
+ {
+ if (retry == MAX_ACCEPT_RETRY - 1)
+ fcntl(sock, F_SETFL, flags); // Try without O_NONBLOCK
+ }
+#endif
+ }
+#if !defined(NO_FCNTL_NONBLOCK)
+ if (!(test_flags & TEST_BLOCKING))
+ fcntl(sock, F_SETFL, flags);
+#endif
+ if (new_sock < 0)
+ {
+ if ((error_count++ & 255) == 0) // This can happen often
+ sql_perror("Error in accept");
+ if (errno == ENFILE || errno == EMFILE)
+ sleep(1); // Give other threads some time
+ continue;
+ }
+
+#ifdef HAVE_LIBWRAP
+ {
+ if (sock == ip_sock)
+ {
+ struct request_info req;
+ signal(SIGCHLD, SIG_DFL);
+ request_init(&req, RQ_DAEMON, libwrapName, RQ_FILE, new_sock, NULL);
+ 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 ...
+ syslog(deny_severity, "refused connect from %s", eval_client(&req));
+ 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...
+
+ (void) shutdown(new_sock,2); // This looks fine to me...
+ (void) closesocket(new_sock);
+ continue;
+ }
+ }
+ }
+#endif /* HAVE_LIBWRAP */
+
+ {
+ size_socket dummyLen;
+ struct sockaddr dummy;
+ dummyLen = sizeof(struct sockaddr);
+ if (getsockname(new_sock,&dummy, &dummyLen) < 0)
+ {
+ sql_perror("Error on new connection socket");
+ (void) shutdown(new_sock,2);
+ (void) closesocket(new_sock);
+ continue;
+ }
+ }
+
+ /*
+ ** Don't allow too many connections
+ */
+
+ if (!(thd= new THD))
+ {
+ (void) shutdown(new_sock,2); VOID(closesocket(new_sock));
+ continue;
+ }
+ if (!(vio_tmp=vio_new(new_sock,
+ new_sock == unix_sock ? VIO_TYPE_SOCKET :
+ VIO_TYPE_TCPIP,
+ new_sock == unix_sock)) ||
+ my_net_init(&thd->net,vio_tmp))
+ {
+ if (vio_tmp)
+ vio_delete(vio_tmp);
+ else
+ {
+ (void) shutdown(new_sock,2);
+ (void) closesocket(new_sock);
+ }
+ delete thd;
+ continue;
+ }
+ if (sock == unix_sock)
+ {
+ if (!(thd->host=my_strdup(LOCAL_HOST,MYF(0))))
+ {
+ close_connection(&thd->net,ER_OUT_OF_RESOURCES);
+ delete thd;
+ continue;
+ }
+ }
+ create_new_thread(thd);
+ }
+
+#ifdef __NT__
+ pthread_mutex_lock(&LOCK_thread_count);
+ handler_count--;
+ pthread_cond_signal(&COND_handler_count);
+ pthread_mutex_unlock(&LOCK_thread_count);
+#endif
+ DBUG_RETURN(0);
+}
+
+
+#ifdef __NT__
+pthread_handler_decl(handle_connections_namedpipes,arg)
+{
+ HANDLE hConnectedPipe;
+ BOOL fConnected;
+ THD *thd;
+ my_thread_init();
+ DBUG_ENTER("handle_connections_namedpipes");
+ (void) my_pthread_getprio(pthread_self()); // For debugging
+
+ DBUG_PRINT("general",("Waiting for named pipe connections."));
+ while (!abort_loop)
+ {
+ /* wait for named pipe connection */
+ fConnected = ConnectNamedPipe( hPipe, NULL );
+ if (abort_loop)
+ break;
+ if ( !fConnected )
+ fConnected = GetLastError() == ERROR_PIPE_CONNECTED;
+ if ( !fConnected )
+ {
+ CloseHandle( hPipe );
+ if ((hPipe = CreateNamedPipe(szPipeName,
+ PIPE_ACCESS_DUPLEX,
+ PIPE_TYPE_BYTE |
+ PIPE_READMODE_BYTE |
+ PIPE_WAIT,
+ PIPE_UNLIMITED_INSTANCES,
+ (int) net_buffer_length,
+ (int) net_buffer_length,
+ NMPWAIT_USE_DEFAULT_WAIT,
+ &saPipeSecurity )) ==
+ INVALID_HANDLE_VALUE )
+ {
+ sql_perror("Can't create new named pipe!");
+ break; // Abort
+ }
+ }
+ hConnectedPipe = hPipe;
+ /* create new pipe for new connection */
+ if ((hPipe = CreateNamedPipe(szPipeName,
+ PIPE_ACCESS_DUPLEX,
+ PIPE_TYPE_BYTE |
+ PIPE_READMODE_BYTE |
+ PIPE_WAIT,
+ PIPE_UNLIMITED_INSTANCES,
+ (int) net_buffer_length,
+ (int) net_buffer_length,
+ NMPWAIT_USE_DEFAULT_WAIT,
+ &saPipeSecurity)) ==
+ INVALID_HANDLE_VALUE)
+ {
+ sql_perror("Can't create new named pipe!");
+ hPipe=hConnectedPipe;
+ continue; // We have to try again
+ }
+
+ if ( !(thd = new THD))
+ {
+ DisconnectNamedPipe( hConnectedPipe );
+ CloseHandle( hConnectedPipe );
+ continue;
+ }
+ if (!(thd->net.vio = vio_new_win32pipe(hConnectedPipe)) ||
+ my_net_init(&thd->net, thd->net.vio))
+ {
+ close_connection(&thd->net,ER_OUT_OF_RESOURCES);
+ delete thd;
+ continue;
+ }
+ /* host name is unknown */
+ thd->host = my_strdup("localhost",MYF(0)); /* Host is unknown */
+ create_new_thread(thd);
+ }
+
+ pthread_mutex_lock(&LOCK_thread_count);
+ handler_count--;
+ pthread_cond_signal(&COND_handler_count);
+ pthread_mutex_unlock(&LOCK_thread_count);
+ DBUG_RETURN(0);
+}
+#endif /* __NT__ */
+
+/****************************************************************************
+** Create thread that automaticly flush all tables after a given time
+****************************************************************************/
+
+pthread_handler_decl(handle_flush,arg __attribute__((unused)))
+{
+ my_thread_init();
+ DBUG_ENTER("handle_flush");
+
+ pthread_detach_this_thread();
+ flush_thread=pthread_self();
+ flush_thread_in_use=1;
+
+ pthread_mutex_lock(&LOCK_flush);
+ for (;;)
+ {
+ struct timespec abstime;
+#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
+ (void) pthread_cond_timedwait(&COND_flush,&LOCK_flush, &abstime);
+ if (abort_loop)
+ break;
+ flush_tables();
+ }
+ flush_thread_in_use=0;
+ pthread_mutex_unlock(&LOCK_flush);
+ my_thread_end();
+ DBUG_RETURN(0);
+}
+
+
+/******************************************************************************
+** handle start options
+******************************************************************************/
+
+enum options {OPT_ISAM_LOG=256,OPT_SKIP_NEW,OPT_SKIP_GRANT,
+ OPT_SKIP_LOCK,OPT_ENABLE_LOCK,
+ OPT_USE_LOCKING,OPT_SOCKET,OPT_UPDATE_LOG, OPT_BIN_LOG,
+ OPT_SKIP_RESOLVE,OPT_SKIP_NETWORKING, OPT_BIN_LOG_INDEX,
+ OPT_BIND_ADDRESS,OPT_PID_FILE,OPT_SKIP_PRIOR,OPT_BIG_TABLES,
+ OPT_STANDALONE,OPT_ONE_THREAD,OPT_CONSOLE,
+ OPT_LOW_PRIORITY_UPDATES,OPT_SKIP_HOST_CACHE,OPT_LONG_FORMAT,
+ OPT_FLUSH, OPT_SAFE, OPT_BOOTSTRAP, OPT_SKIP_SHOW_DB,
+ OPT_TABLE_TYPE, OPT_INIT_FILE, OPT_DELAY_KEY_WRITE,
+ OPT_SLOW_QUERY_LOG, OPT_SKIP_DELAY_KEY_WRITE,
+ OPT_CHARSETS_DIR,
+ OPT_BDB_HOME, OPT_BDB_LOG, OPT_BDB_TMP, OPT_BDB_NOSYNC,
+ OPT_BDB_LOCK, OPT_BDB_SKIP, OPT_BDB_RECOVER,
+ OPT_MASTER_HOST, OPT_MASTER_USER, OPT_MASTER_PASSWORD,
+ OPT_MASTER_PORT, OPT_MASTER_INFO_FILE, OPT_MASTER_CONNECT_RETRY,
+ 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};
+
+static struct option long_options[] =
+{
+ {"ansi", no_argument,0, 'a'},
+ {"basedir", required_argument, 0, 'b'},
+#ifdef HAVE_BERKELEY_DB
+ {"bdb-home", required_argument, 0, OPT_BDB_HOME},
+ {"bdb-lock-detect", required_argument, 0, OPT_BDB_LOCK},
+ {"bdb-logdir", required_argument, 0, OPT_BDB_LOG},
+ {"bdb-recover", no_argument, 0, OPT_BDB_RECOVER},
+ {"bdb-no-sync", no_argument, 0, OPT_BDB_NOSYNC},
+ {"bdb-tmpdir", required_argument, 0, OPT_BDB_TMP},
+#endif
+ {"big-tables", no_argument,0,(int) OPT_BIG_TABLES},
+ {"binlog-do-db", required_argument, 0, OPT_BINLOG_DO_DB},
+ {"binlog-ignore-db", required_argument, 0, OPT_BINLOG_IGNORE_DB},
+ {"bind-address", required_argument, 0, OPT_BIND_ADDRESS},
+ {"bootstrap", no_argument,0,(int) OPT_BOOTSTRAP},
+#ifdef __WIN__
+ {"console", no_argument, 0, OPT_CONSOLE},
+#endif
+ {"chroot", required_argument,0, 'r'},
+ {"character-sets-dir",required_argument,0, OPT_CHARSETS_DIR},
+ {"datadir", required_argument, 0, 'h'},
+#ifndef DBUG_OFF
+ {"debug", optional_argument, 0, '#'},
+#endif
+ {"default-character-set",required_argument,0,'C'},
+ {"default-table-type",required_argument,0,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},
+ {"exit-info", optional_argument, 0, 'T'},
+ {"flush", no_argument, 0, OPT_FLUSH},
+ {"help", no_argument, 0, '?'},
+ {"init-file", required_argument, 0, (int) OPT_INIT_FILE},
+ {"log", optional_argument, 0, 'l'},
+ {"language", required_argument, 0, 'L'},
+ {"log-bin", optional_argument, 0, (int) OPT_BIN_LOG},
+ {"log-bin-index", optional_argument, 0, (int) OPT_BIN_LOG_INDEX},
+ {"log-isam", optional_argument, 0, (int) OPT_ISAM_LOG},
+ {"log-update", optional_argument, 0, (int) OPT_UPDATE_LOG},
+ {"log-slow-queries", optional_argument, 0, (int) OPT_SLOW_QUERY_LOG},
+ {"log-long-format", no_argument, 0, (int) OPT_LONG_FORMAT},
+ {"log-slave-updates", no_argument,0, (int) OPT_LOG_SLAVE_UPDATES},
+ {"low-priority-updates", no_argument, 0, (int) OPT_LOW_PRIORITY_UPDATES},
+ {"master-host", required_argument, 0, (int) OPT_MASTER_HOST},
+ {"master-user", required_argument, 0, (int) OPT_MASTER_USER},
+ {"master-password", required_argument, 0, (int) OPT_MASTER_PASSWORD},
+ {"master-port", required_argument, 0, (int) OPT_MASTER_PORT},
+ {"master-connect-retry", required_argument, 0, (int) OPT_MASTER_CONNECT_RETRY},
+ {"master-info-file", required_argument, 0, (int) OPT_MASTER_INFO_FILE},
+ {"new", no_argument, 0, 'n'},
+ {"old-protocol", no_argument, 0, 'o'},
+ {"one-thread", no_argument, 0, OPT_ONE_THREAD},
+ {"pid-file", required_argument, 0, (int) OPT_PID_FILE},
+ {"port", required_argument, 0, 'P'},
+ {"replicate-do-db", required_argument, 0, OPT_REPLICATE_DO_DB},
+ {"replicate-ignore-db", required_argument, 0, OPT_REPLICATE_IGNORE_DB},
+ {"safe-mode", no_argument, 0, (int) OPT_SAFE},
+ {"socket", required_argument, 0, (int) OPT_SOCKET},
+ {"set-variable", required_argument, 0, 'O'},
+#ifdef HAVE_BERKELEY_DB
+ {"skip-bdb", no_argument, 0, OPT_BDB_SKIP},
+#endif
+ {"skip-delay-key-write", no_argument, 0, (int) OPT_SKIP_DELAY_KEY_WRITE},
+ {"skip-grant-tables", no_argument,0, (int) OPT_SKIP_GRANT},
+ {"skip-locking", no_argument,0, (int) OPT_SKIP_LOCK},
+ {"skip-host-cache", no_argument,0, (int) OPT_SKIP_HOST_CACHE},
+ {"skip-name-resolve", no_argument,0, (int) OPT_SKIP_RESOLVE},
+ {"skip-new", no_argument,0, (int) OPT_SKIP_NEW},
+ {"skip-show-database",no_argument,0, (int) OPT_SKIP_SHOW_DB},
+ {"skip-networking", no_argument,0, (int) OPT_SKIP_NETWORKING},
+ {"skip-thread-priority", no_argument,0,(int) OPT_SKIP_PRIOR},
+ {"sql-bin-update-same", no_argument, 0, (int)OPT_SQL_BIN_UPDATE_SAME},
+#include "sslopt-longopts.h"
+#ifdef __WIN__
+ {"standalone", no_argument,0, (int) OPT_STANDALONE},
+#endif
+ {"tmpdir", required_argument, 0, 't'},
+ {"use-locking", no_argument, 0,(int) OPT_USE_LOCKING},
+#ifdef USE_SYMDIR
+ {"use-symbolic-links",no_argument, 0, 's'},
+#endif
+ {"user", required_argument, 0, 'u'},
+ {"version", no_argument, 0, 'V'},
+ {0, 0, 0, 0}
+};
+
+CHANGEABLE_VAR changeable_vars[] = {
+ { "back_log", (long*) &back_log,50,1,65535,0,1},
+#ifdef HAVE_BERKELEY_DB
+ { "bdb_cache_size", (long*) &berkeley_cache_size, KEY_CACHE_SIZE,
+ 20*1024, (long) ~0, 0, IO_SIZE},
+#endif
+ { "connect_timeout", (long*) &connect_timeout,CONNECT_TIMEOUT,1,65535,0,1},
+ { "delayed_insert_timeout",(long*) &delayed_insert_timeout,
+ DELAYED_WAIT_TIMEOUT,1,~0L,0,1},
+ { "delayed_insert_limit",(long*) &delayed_insert_limit,
+ DELAYED_LIMIT,1,~0L,0,1},
+ { "delayed_queue_size", (long*) &delayed_queue_size,DELAYED_QUEUE_SIZE,1,
+ ~0L,0,1},
+ { "flush_time", (long*) &flush_time,FLUSH_TIME,0,~0L,0,1},
+ { "interactive_timeout", (long*) &net_interactive_timeout,
+ NET_WAIT_TIMEOUT,1,31*24*60*60,0,1},
+ { "join_buffer_size", (long*) &join_buff_size,128*1024L,
+ IO_SIZE*2+MALLOC_OVERHEAD,~0L,MALLOC_OVERHEAD,IO_SIZE },
+ { "key_buffer_size", (long*) &keybuff_size,KEY_CACHE_SIZE,MALLOC_OVERHEAD,
+ (long) ~0, MALLOC_OVERHEAD, IO_SIZE },
+ { "long_query_time", (long*) &long_query_time,10,1,~0L,0,1},
+ { "lower_case_table_names", (long*) &lower_case_table_names,IF_WIN(1,0),
+ 0,1,0,1},
+ { "max_allowed_packet",(long*) &max_allowed_packet,1024*1024L,80,
+ 17*1024*1024L, MALLOC_OVERHEAD,1024},
+ { "max_connections", (long*) &max_connections,100,1,16384,0,1},
+ { "max_connect_errors", (long*) &max_connect_errors,MAX_CONNECT_ERRORS,1,
+ ~0L,0,1},
+ { "max_delayed_threads", (long*) &max_insert_delayed_threads,20,1,
+ 16384,0,1},
+ { "max_heap_table_size",(long*) &max_heap_table_size,16*1024*1024L,16384,~0L,
+ MALLOC_OVERHEAD,1024},
+ { "max_join_size",(long*) &max_join_size,~0L,1,~0L,0,1},
+ { "max_sort_length",(long*) &max_item_sort_length,1024,4,8192*1024L,0,1},
+ { "max_tmp_tables",(long*) &max_tmp_tables,32,1,~0L,0,1},
+ { "max_write_lock_count",(long*) &max_write_lock_count,~0L,1,~0L,0,1},
+ { "myisam_sort_buffer_size", (long*) &myisam_sort_buffer_size,8192*1024,4,
+ ~0L,0,1},
+ { "net_buffer_length",(long*) &net_buffer_length,16384,1024,1024*1024L,
+ MALLOC_OVERHEAD,1024},
+ { "net_retry_count",(long*) &mysqld_net_retry_count,MYSQLD_NET_RETRY_COUNT,
+ 1,~0L, 0,1},
+ { "net_read_timeout", (long*) &net_read_timeout, NET_READ_TIMEOUT,1,65535,0,1},
+ { "net_write_timeout", (long*) &net_write_timeout,NET_WRITE_TIMEOUT,1,65535,0,1},
+ { "query_buffer_size", (long*) &query_buff_size,0,MALLOC_OVERHEAD,
+ (long) ~0, MALLOC_OVERHEAD, IO_SIZE },
+ { "record_buffer", (long*) &my_default_record_cache_size,128*1024L,
+ IO_SIZE*2+MALLOC_OVERHEAD,~0L,MALLOC_OVERHEAD,IO_SIZE },
+ { "slow_launch_time", (long*) &slow_launch_time, 2L,
+ 0L,~0L,0,1 },
+ { "sort_buffer", (long*) &sortbuff_size,MAX_SORT_MEMORY,
+ MIN_SORT_MEMORY+MALLOC_OVERHEAD*2,~0L,MALLOC_OVERHEAD,1 },
+ { "table_cache", (long*) &table_cache_size,64,1,16384,0,1},
+ { "thread_concurrency", (long*) &concurrency,DEFAULT_CONCURRENCY,1,512,0,1},
+ { "thread_cache_size", (long*) &thread_cache_size, 0,1,16384,0,1},
+ { "tmp_table_size", (long*) &tmp_table_size,1024*1024L,1024,~0L,
+ MALLOC_OVERHEAD,1},
+ { "thread_stack", (long*) &thread_stack,1024*64,1024*32,~0L,0,1024},
+ { "wait_timeout", (long*) &net_wait_timeout,NET_WAIT_TIMEOUT,1,~0L,0,1},
+ { NullS,(long*) 0,0,0,0,0,0,} };
+
+
+struct show_var_st init_vars[]= {
+ {"ansi_mode",(char*) &opt_ansi_mode ,SHOW_BOOL},
+ {"back_log", (char*) &back_log, SHOW_LONG},
+ {"basedir", mysql_home,SHOW_CHAR},
+#ifdef HAVE_BERKELEY_DB
+ {"bdb_cache_size", (char*) &berkeley_cache_size, SHOW_LONG},
+ {"bdb_home", (char*) &berkeley_home, SHOW_CHAR_PTR},
+ {"bdb_logdir", (char*) &berkeley_logdir, SHOW_CHAR_PTR},
+ {"bdb_tmpdir", (char*) &berkeley_tmpdir, SHOW_CHAR_PTR},
+#endif
+ {"character_set", default_charset, SHOW_CHAR},
+ {"character_sets", (char*) &charsets_list, SHOW_CHAR_PTR},
+ {"connect_timeout", (char*) &connect_timeout, SHOW_LONG},
+ {"concurrent_insert",(char*) &myisam_concurrent_insert, SHOW_MY_BOOL},
+ {"datadir", mysql_real_data_home,SHOW_CHAR},
+ {"delay_key_write",(char*) &myisam_delay_key_write, SHOW_MY_BOOL},
+ {"delayed_insert_limit",(char*) &delayed_insert_limit,SHOW_LONG},
+ {"delayed_insert_timeout",(char*) &delayed_insert_timeout,SHOW_LONG},
+ {"delayed_queue_size", (char*) &delayed_queue_size,SHOW_LONG},
+ {"join_buffer_size", (char*) &join_buff_size, SHOW_LONG},
+ {"flush", (char*) &myisam_flush, SHOW_MY_BOOL},
+ {"flush_time",(char*) &flush_time, SHOW_LONG},
+ {"init_file", (char*) &opt_init_file, SHOW_CHAR_PTR},
+ {"interactive_timeout", (char*) &net_interactive_timeout, SHOW_LONG},
+ {"key_buffer_size", (char*) &keybuff_size, SHOW_LONG},
+ {"language", language, SHOW_CHAR},
+ {"log", (char*) &opt_log, SHOW_BOOL},
+ {"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},
+ {"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},
+ {"max_allowed_packet", (char*) &max_allowed_packet, SHOW_LONG},
+ {"max_connections", (char*) &max_connections, SHOW_LONG},
+ {"max_connect_errors", (char*) &max_connect_errors, SHOW_LONG},
+ {"max_delayed_threads", (char*) &max_insert_delayed_threads, SHOW_LONG},
+ {"max_heap_table_size", (char*) &max_heap_table_size,SHOW_LONG},
+ {"max_join_size", (char*) &max_join_size, SHOW_LONG},
+ {"max_sort_length", (char*) &max_item_sort_length,SHOW_LONG},
+ {"max_tmp_tables", (char*) &max_tmp_tables,SHOW_LONG},
+ {"max_write_lock_count",(char*) &max_write_lock_count,SHOW_LONG},
+ {"myisam_sort_buffer_size", (char*) &myisam_sort_buffer_size,SHOW_LONG},
+ {"net_buffer_length", (char*) &net_buffer_length, SHOW_LONG},
+ {"net_retry_count", (char*) &mysqld_net_retry_count, SHOW_LONG},
+ {"pid_file", (char*) pidfile_name, SHOW_CHAR},
+ {"port", (char*) &mysql_port, SHOW_INT},
+ {"protocol_version", (char*) &protocol_version, SHOW_INT},
+ {"record_buffer", (char*) &my_default_record_cache_size,SHOW_LONG},
+ {"skip_locking", (char*) &my_disable_locking, SHOW_MY_BOOL},
+ {"skip_networking", (char*) &opt_disable_networking, SHOW_BOOL},
+ {"skip_show_database", (char*) &opt_skip_show_db, SHOW_BOOL},
+ {"slow_launch_time", (char*) &slow_launch_time, SHOW_LONG},
+ {"socket", (char*) &mysql_unix_port, SHOW_CHAR_PTR},
+ {"sort_buffer", (char*) &sortbuff_size,SHOW_LONG},
+ {"table_cache", (char*) &table_cache_size,SHOW_LONG},
+ {"table_type", (char*) (&default_table_type_name), SHOW_CHAR_PTR},
+#ifdef HAVE_THR_SETCONCURRENCY
+ {"thread_concurrency", (char*) &concurrency, SHOW_LONG},
+#endif
+ {"thread_stack", (char*) &thread_stack,SHOW_LONG},
+ {"thread_cache_size", (char*) &thread_cache_size,SHOW_LONG},
+#ifdef HAVE_TZNAME
+ {"timezone", time_zone, SHOW_CHAR},
+#endif
+ {"tmp_table_size", (char*) &tmp_table_size,SHOW_LONG},
+ {"tmpdir", (char*) &mysql_tmpdir,SHOW_CHAR_PTR},
+ {"version", server_version, SHOW_CHAR},
+ {"wait_timeout",(char*) &net_wait_timeout,SHOW_LONG},
+ {NullS,NullS,SHOW_LONG}
+};
+
+struct show_var_st status_vars[]= {
+ {"Aborted_clients", (char*) &aborted_threads, SHOW_LONG},
+ {"Aborted_connects", (char*) &aborted_connects, SHOW_LONG},
+ {"Bytes_received", (char*) &bytes_received, SHOW_LONG},
+ {"Bytes_sent", (char*) &bytes_sent, SHOW_LONG},
+ {"Connections", (char*) &thread_id, SHOW_LONG_CONST},
+ {"Created_tmp_tables",(char*) &created_tmp_tables, SHOW_LONG},
+ {"Delayed_insert_threads", (char*) &delayed_insert_threads, SHOW_LONG},
+ {"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_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},
+ {"Handler_read_next", (char*) &ha_read_next_count, SHOW_LONG},
+ {"Handler_read_prev", (char*) &ha_read_prev_count, SHOW_LONG},
+ {"Handler_read_rnd", (char*) &ha_read_rnd_count, SHOW_LONG},
+ {"Handler_read_rnd_next", (char*) &ha_read_rnd_next_count, SHOW_LONG},
+ {"Handler_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},
+ {"Key_read_requests", (char*) &_my_cache_r_requests, SHOW_LONG},
+ {"Key_reads", (char*) &_my_cache_read, SHOW_LONG},
+ {"Key_write_requests",(char*) &_my_cache_w_requests, SHOW_LONG},
+ {"Key_writes", (char*) &_my_cache_write, SHOW_LONG},
+ {"Max_used_connections", (char*) &max_used_connections, SHOW_LONG},
+ {"Not_flushed_key_blocks", (char*) &_my_blocks_changed, SHOW_LONG_CONST},
+ {"Not_flushed_delayed_rows", (char*) &delayed_rows_in_use, SHOW_LONG_CONST},
+ {"Open_tables", (char*) 0, SHOW_OPENTABLES},
+ {"Open_files", (char*) &my_file_opened, SHOW_INT_CONST},
+ {"Open_streams", (char*) &my_stream_opened, SHOW_INT_CONST},
+ {"Opened_tables", (char*) &opened_tables, SHOW_LONG},
+ {"Questions", (char*) 0, SHOW_QUESTION},
+ {"Slow_launch_threads", (char*) &slow_launch_threads, SHOW_LONG},
+ {"Slow_queries", (char*) &long_query_count, SHOW_LONG},
+ {"Slave_running", (char*) &slave_running, SHOW_BOOL},
+ {"Threads_cached", (char*) &cached_thread_count, SHOW_LONG_CONST},
+ {"Threads_connected", (char*) &thread_count, SHOW_INT_CONST},
+ {"Threads_running", (char*) &thread_running, SHOW_INT_CONST},
+ {"Uptime", (char*) 0, SHOW_STARTTIME},
+ {NullS,NullS,SHOW_LONG}
+};
+
+static void print_version(void)
+{
+ printf("%s Ver %s for %s on %s\n",my_progname,
+ server_version,SYSTEM_TYPE,MACHINE_TYPE);
+}
+
+static void usage(void)
+{
+ print_version();
+ puts("Copyright (C) 2000 MySQL AB & MySQL Finland AB, by Monty and others");
+ 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("Starts the MySQL server\n");
+
+ printf("Usage: %s [OPTIONS]\n", my_progname);
+ puts("\n\
+ --ansi Use ANSI SQL syntax instead of MySQL syntax\n\
+ -b, --basedir=path Path to installation directory. All paths are\n\
+ usually resolved relative to this\n\
+ --big-tables Allow big result sets by saving all temporary sets\n\
+ on file (Solves most 'table full' errors)\n\
+ --bind-address=IP Ip address to bind to\n\
+ --bootstrap Used by mysql installation scripts\n\
+ --character-sets-dir=...\n\
+ Directory where character sets are\n\
+ --chroot=path Chroot mysqld daemon during startup\n\
+ -h, --datadir=path Path to the database root");
+#ifndef DBUG_OFF
+ printf("\
+ -#, --debug[=...] Debug log. Default is '%s'\n",default_dbug_option);
+#endif
+ puts("\
+ --default-character-set=charset\n\
+ Set the default character set\n\
+ --default-table-type=type\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\
+ --enable-locking Enable system locking\n\
+ -T, --exit-info Print some debug info at exit\n\
+ --flush Flush tables to disk between SQL commands\n\
+ -?, --help Display this help and exit\n\
+ --init-file=file Read SQL commands from this file at startup\n\
+ -L, --language=... Client error messages in given language. May be\n\
+ given as a full path\n\
+ -l, --log[=file] Log connections and queries to file\n\
+ --log-bin[=file] Log queries in new binary format (for replication)\n\
+ --log-bin-index=file File that holds the names for last binary log files\n\
+ --log-update[=file] Log updates to file.# where # is a unique number\n\
+ if not given.\n\
+ --log-isam[=file] Log all isam changes to file\n\
+ --log-long-format Log some extra information to update log\n\
+ --low-priority-updates INSERT/DELETE/UPDATE has lower priority than selects\n\
+ --pid-file=path Pid file used by safe_mysqld\n\
+ -P, --port=... Port number to use for connection\n\
+ -n, --new Use very new possible 'unsafe' functions\n\
+ -o, --old-protocol Use the old (3.20) protocol\n\
+ --one-thread Only use one thread (for debugging under Linux)\n\
+ -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\
+ --skip-delay-key-write\n\
+ Ignore the delay_key_write option for all tables\n\
+ --skip-locking Don't use system locking. To use isamchk one has\n\
+ to shut down the server.\n\
+ --skip-name-resolve Don't resolve hostnames.\n\
+ All hostnames are IP's or 'localhost'\n\
+ --skip-networking Don't allow connection with TCP/IP.\n\
+ --skip-new Don't use new, possible wrong routines.\n\
+ --skip-host-cache Don't cache host names\n");
+ /* We have to break the string here because of VC++ limits */
+ puts("\
+ --skip-show-database Don't allow 'SHOW DATABASE' commands\n\
+ --skip-thread-priority\n\
+ Don't give threads different priorities.\n\
+ --socket=... Socket file to use for connection\n\
+ -t, --tmpdir=path Path for temporary files\n\
+ -u, --user=user_name Run mysqld daemon as user\n\
+ -V, --version output version information and exit");
+#ifdef __WIN__
+ puts("NT and Win32 specific options:\n\
+ --console Don't remove the console window\n\
+ --install Install mysqld as a service (NT)\n\
+ --remove Remove mysqld from the service list (NT)\n\
+ --standalone Dummy option to start as a standalone program (NT)\n\
+");
+#endif
+#ifdef HAVE_BERKELEY_DB
+ puts("\
+ --bdb-home= directory Berkeley home direcory\n\
+ --bdb-lock-detect=# Berkeley lock detect\n\
+ (DEFAULT, OLDEST, RANDOM or YOUNGEST, # sec)\n\
+ --bdb-logdir=directory Berkeley DB log file directory\n\
+ --bdb-nosync Don't synchronously flush logs\n\
+ --bdb-recover Start Berkeley DB in recover mode\n\
+ --bdb-tmpdir=directory Berkeley DB tempfile name\n\
+ --skip-bdb Don't use berkeley db (will save memory)\n\
+");
+#endif
+ print_defaults("my",load_default_groups);
+ puts("");
+
+#include "sslopt-usage.h"
+
+ fix_paths();
+ set_ports();
+ printf("\
+To see what values a running MySQL server is using, type\n\
+'mysqladmin variables' instead of 'mysqld --help'.\n\
+The default values (after parsing the command line arguments) are:\n\n");
+
+ printf("basedir: %s\n",mysql_home);
+ printf("datadir: %s\n",mysql_real_data_home);
+ printf("tmpdir: %s\n",mysql_tmpdir);
+ printf("language: %s\n",language);
+ printf("pid file: %s\n",pidfile_name);
+ if (opt_logname)
+ printf("logfile: %s\n",opt_logname);
+ if (opt_update_logname)
+ printf("update log: %s\n",opt_update_logname);
+ if (opt_bin_logname)
+ {
+ printf("binary log: %s\n",opt_bin_logname);
+ printf("binary log index: %s\n",opt_binlog_index_name);
+ }
+ if (opt_slow_logname)
+ printf("update log: %s\n",opt_slow_logname);
+ printf("TCP port: %d\n",mysql_port);
+#if defined(HAVE_SYS_UN_H) && !defined(HAVE_mit_thread)
+ printf("Unix socket: %s\n",mysql_unix_port);
+#endif
+ if (my_disable_locking)
+ puts("\nsystem locking is not in use");
+ if (opt_noacl)
+ puts("\nGrant tables are not used. All users have full access rights");
+ printf("\nPossible variables for option --set-variable (-O) are:\n");
+ for (uint i=0 ; changeable_vars[i].name ; i++)
+ printf("%-20s current value: %lu\n",
+ changeable_vars[i].name,
+ (ulong) *changeable_vars[i].varptr);
+}
+
+
+static void set_options(void)
+{
+ set_all_changeable_vars( changeable_vars );
+#if !defined( my_pthread_setprio ) && !defined( HAVE_PTHREAD_SETSCHEDPARAM )
+ opt_specialflag |= SPECIAL_NO_PRIOR;
+#endif
+
+ (void) strmov( default_charset, MYSQL_CHARSET);
+ (void) strmov( language, LANGUAGE);
+ (void) strmov( mysql_real_data_home, get_relative_path(DATADIR));
+#ifdef __WIN__
+ /* Allow Win32 users to move MySQL anywhere */
+ {
+ char prg_dev[LIBLEN];
+ my_path(prg_dev,my_progname,"mysql/bin");
+ strcat(prg_dev,"/../"); // Remove 'bin' to get base dir
+ cleanup_dirname(mysql_home,prg_dev);
+ }
+#else
+ const char *tmpenv;
+ if ( !(tmpenv = getenv("MY_BASEDIR_VERSION")))
+ tmpenv = DEFAULT_MYSQL_HOME;
+ (void) strmov( mysql_home, tmpenv );
+#endif
+
+#if defined( HAVE_mit_thread ) || defined( __WIN__ ) || defined( HAVE_LINUXTHREADS )
+ my_disable_locking = 1;
+#endif
+ my_bind_addr = htonl( INADDR_ANY );
+}
+
+ /* Initiates DEBUG - but no debugging here ! */
+
+static void get_options(int argc,char **argv)
+{
+ int c,option_index=0;
+
+ myisam_delay_key_write=1; // Allow use of this
+ while ((c=getopt_long(argc,argv,"ab:C:h:#::T::?l::L:O:P:sS::t:u:noVvI?",
+ long_options, &option_index)) != EOF)
+ {
+ switch(c) {
+#ifndef DBUG_OFF
+ case '#':
+ DBUG_PUSH(optarg ? optarg : default_dbug_option);
+ opt_endinfo=1; /* unireg: memory allocation */
+ break;
+#endif
+ case 'a':
+ opt_ansi_mode=1;
+ thd_startup_options|=OPTION_ANSI_MODE;
+ break;
+ case 'b':
+ strmov(mysql_home,optarg);
+ break;
+ case 'l':
+ opt_log=1;
+ opt_logname=optarg; // Use hostname.log if null
+ break;
+ case 'h':
+ strmov(mysql_real_data_home,optarg);
+ break;
+ case 'L':
+ strmov(language,optarg);
+ break;
+ case 'n':
+ opt_specialflag|= SPECIAL_NEW_FUNC;
+ break;
+ case 'o':
+ protocol_version=PROTOCOL_VERSION-1;
+ break;
+ case 'O':
+ if (set_changeable_var(optarg, changeable_vars))
+ {
+ usage();
+ exit(1);
+ }
+ break;
+ case 'P':
+ mysql_port= (unsigned int) atoi(optarg);
+ break;
+ case OPT_SOCKET:
+ mysql_unix_port= optarg;
+ break;
+ case 'r':
+ mysqld_chroot=optarg;
+ break;
+#ifdef USE_SYMDIR
+ case 's':
+ my_use_symdir=1; /* Use internal symbolic links */
+ break;
+#endif
+ case 't':
+ mysql_tmpdir=optarg;
+ break;
+ case 'u':
+ mysqld_user=optarg;
+ break;
+ case 'v':
+ case 'V':
+ print_version();
+ exit(0);
+ case 'I':
+ case '?':
+ usage();
+ exit(0);
+ case 'T':
+ test_flags= optarg ? (uint) atoi(optarg) : (uint) ~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
+ {
+ usage();
+ exit(1);
+ }
+ break;
+ case (int) OPT_BIG_TABLES:
+ thd_startup_options|=OPTION_BIG_TABLES;
+ break;
+ case (int) OPT_ISAM_LOG:
+ if (optarg)
+ nisam_log_filename=optarg;
+ (void) nisam_log(1);
+ break;
+ case (int) OPT_UPDATE_LOG:
+ opt_update_log=1;
+ opt_update_logname=optarg; // Use hostname.# if null
+ break;
+ case (int) OPT_BIN_LOG_INDEX:
+ opt_binlog_index_name = optarg;
+ break;
+ case (int) OPT_BIN_LOG:
+ opt_bin_log=1;
+ opt_bin_logname=optarg;
+ break;
+ case (int) OPT_LOG_SLAVE_UPDATES:
+ opt_log_slave_updates = 1;
+ break;
+
+ case (int)OPT_REPLICATE_IGNORE_DB:
+ {
+ i_string *db = new i_string(optarg);
+ replicate_ignore_db.push_back(db);
+ break;
+ }
+ case (int)OPT_REPLICATE_DO_DB:
+ {
+ i_string *db = new i_string(optarg);
+ replicate_do_db.push_back(db);
+ break;
+ }
+
+ case (int)OPT_BINLOG_IGNORE_DB:
+ {
+ i_string *db = new i_string(optarg);
+ binlog_ignore_db.push_back(db);
+ break;
+ }
+ case (int)OPT_BINLOG_DO_DB:
+ {
+ i_string *db = new i_string(optarg);
+ binlog_do_db.push_back(db);
+ break;
+ }
+
+
+ case (int) OPT_SQL_BIN_UPDATE_SAME:
+ opt_sql_bin_update = 1;
+ break;
+ case (int) OPT_SLOW_QUERY_LOG:
+ opt_slow_log=1;
+ opt_slow_logname=optarg;
+ 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;
+ break;
+ case (int) OPT_SAFE:
+ opt_specialflag|= SPECIAL_SAFE_MODE;
+ myisam_delay_key_write=0;
+ myisam_concurrent_insert=0;
+ break;
+ case (int) OPT_SKIP_PRIOR:
+ opt_specialflag|= SPECIAL_NO_PRIOR;
+ break;
+ case (int) OPT_SKIP_GRANT:
+ opt_noacl=1;
+ break;
+ case (int) OPT_SKIP_LOCK:
+ my_disable_locking=1;
+ break;
+ case (int) OPT_SKIP_HOST_CACHE:
+ opt_specialflag|= SPECIAL_NO_HOST_CACHE;
+ break;
+ case (int) OPT_ENABLE_LOCK:
+ my_disable_locking=0;
+ break;
+ case (int) OPT_USE_LOCKING:
+ my_disable_locking=0;
+ break;
+ case (int) OPT_SKIP_RESOLVE:
+ opt_specialflag|=SPECIAL_NO_RESOLVE;
+ break;
+ case (int) OPT_LONG_FORMAT:
+ opt_specialflag|=SPECIAL_LONG_LOG_FORMAT;
+ break;
+ case (int) OPT_SKIP_NETWORKING:
+ opt_disable_networking=1;
+ mysql_port=0;
+ break;
+ case (int) OPT_SKIP_SHOW_DB:
+ opt_skip_show_db=1;
+ opt_specialflag|=SPECIAL_SKIP_SHOW_DB;
+ mysql_port=0;
+ break;
+ case (int) OPT_ONE_THREAD:
+ test_flags |= TEST_NO_THREADS;
+ break;
+ case (int) OPT_BIND_ADDRESS:
+ if (optarg && isdigit(optarg[0]))
+ {
+ my_bind_addr = (ulong) inet_addr(optarg);
+ }
+ else
+ {
+ struct hostent *ent;
+ if (!optarg || !optarg[0])
+ ent=gethostbyname(optarg);
+ else
+ {
+ char myhostname[255];
+ if (gethostname(myhostname,sizeof(myhostname)) < 0)
+ {
+ sql_perror("Can't start server: cannot get my own hostname!");
+ exit(1);
+ }
+ ent=gethostbyname(myhostname);
+ }
+ if (!ent)
+ {
+ sql_perror("Can't start server: cannot resolve hostname!");
+ exit(1);
+ }
+ my_bind_addr = (ulong) ((in_addr*)ent->h_addr_list[0])->s_addr;
+ }
+ break;
+ case (int) OPT_PID_FILE:
+ strmov(pidfile_name,optarg);
+ break;
+ case (int) OPT_INIT_FILE:
+ opt_init_file=optarg;
+ break;
+#ifdef __WIN__
+ case (int) OPT_STANDALONE: /* Dummy option for NT */
+ break;
+ case (int) OPT_CONSOLE:
+ opt_console=1;
+ break;
+#endif
+ case (int) OPT_FLUSH:
+ nisam_flush=myisam_flush=1;
+ flush_time=0; // No auto flush
+ break;
+ case OPT_LOW_PRIORITY_UPDATES:
+ thd_startup_options|=OPTION_LOW_PRIORITY_UPDATES;
+ low_priority_updates=1;
+ break;
+ case OPT_BOOTSTRAP:
+ opt_noacl=opt_bootstrap=1;
+ break;
+ case OPT_TABLE_TYPE:
+ {
+ int type;
+ if ((type=find_type(optarg, &ha_table_typelib, 2)) <= 0)
+ {
+ fprintf(stderr,"Unknown table type: %s\n",optarg);
+ exit(1);
+ }
+ default_table_type= (enum db_type) type;
+ break;
+ }
+ case OPT_DELAY_KEY_WRITE:
+ ha_open_options|=HA_OPEN_DELAY_KEY_WRITE;
+ myisam_delay_key_write=1;
+ break;
+ case OPT_SKIP_DELAY_KEY_WRITE:
+ myisam_delay_key_write=0;
+ break;
+ case 'C':
+ strmov(default_charset,optarg);
+ break;
+ case OPT_CHARSETS_DIR:
+ strmov(mysql_charsets_dir, optarg);
+ charsets_dir = mysql_charsets_dir;
+ break;
+#include "sslopt-case.h"
+#ifdef HAVE_BERKELEY_DB
+ case OPT_BDB_LOG:
+ berkeley_logdir=optarg;
+ break;
+ case OPT_BDB_HOME:
+ berkeley_home=optarg;
+ break;
+ case OPT_BDB_NOSYNC:
+ berkeley_init_flags|=DB_TXN_NOSYNC;
+ break;
+ case OPT_BDB_RECOVER:
+ berkeley_init_flags|=DB_RECOVER;
+ break;
+ case OPT_BDB_TMP:
+ berkeley_tmpdir=optarg;
+ break;
+ case OPT_BDB_LOCK:
+ {
+ int type;
+ if ((type=find_type(optarg, &berkeley_lock_typelib, 2)) > 0)
+ berkeley_lock_type=berkeley_lock_types[type-1];
+ else
+ {
+ if (test_if_int(optarg,strlen(optarg)))
+ berkeley_lock_scan_time=atoi(optarg);
+ else
+ {
+ fprintf(stderr,"Unknown lock type: %s\n",optarg);
+ exit(1);
+ }
+ }
+ break;
+ }
+ case OPT_BDB_SKIP:
+ berkeley_skip=1;
+ break;
+#endif
+ case OPT_MASTER_HOST:
+ master_host=optarg;
+ break;
+ case OPT_MASTER_USER:
+ master_user=optarg;
+ break;
+ case OPT_MASTER_PASSWORD:
+ master_password=optarg;
+ break;
+ case OPT_MASTER_INFO_FILE:
+ master_info_file=optarg;
+ break;
+ case OPT_MASTER_PORT:
+ master_port= atoi(optarg);
+ break;
+ case OPT_MASTER_CONNECT_RETRY:
+ master_connect_retry= atoi(optarg);
+ break;
+
+ default:
+ fprintf(stderr,"%s: Unrecognized option: %c\n",my_progname,c);
+ usage();
+ exit(1);
+ }
+ }
+ // Skipp empty arguments (from shell)
+ while (argc != optind && !argv[optind][0])
+ optind++;
+ if (argc != optind)
+ {
+ fprintf(stderr,"%s: Too many parameters\n",my_progname);
+ usage();
+ exit(1);
+ }
+ fix_paths();
+ default_table_type_name=ha_table_typelib.type_names[default_table_type-1];
+}
+
+
+#ifdef __WIN__
+
+#ifndef KEY_SERVICE_PARAMETERS
+#define KEY_SERVICE_PARAMETERS "SYSTEM\\CurrentControlSet\\Services\\MySql\\Parameters"
+#endif
+
+#define COPY_KEY_VALUE(value) if (copy_key_value(hParametersKey,&(value),lpszValue)) return 1
+#define CHECK_KEY_TYPE(type,name) if ( type != dwKeyValueType ) { key_type_error(hParametersKey,name); return 1; }
+#define SET_CHANGEABLE_VARVAL(varname) if (set_varval(hParametersKey,varname,szKeyValueName,dwKeyValueType,lpdwValue)) return 1;
+
+static void key_type_error(HKEY hParametersKey,const char *szKeyValueName)
+{
+ TCHAR szErrorMsg[512];
+ RegCloseKey( hParametersKey );
+ strxmov(szErrorMsg,TEXT("Value \""),
+ szKeyValueName,
+ TEXT("\" of registry key \"" KEY_SERVICE_PARAMETERS "\" has wrong type\n"),NullS);
+ fprintf(stderr, szErrorMsg); /* not unicode compatible */
+}
+
+static bool copy_key_value(HKEY hParametersKey, char **var, const char *value)
+{
+ if (!(*var=my_strdup(value,MYF(MY_WME))))
+ {
+ RegCloseKey(hParametersKey);
+ fprintf(stderr, "Couldn't allocate memory for registry key value\n");
+ return 1;
+ }
+ return 0;
+}
+
+static bool set_varval(HKEY hParametersKey,const char *var,
+ const char *szKeyValueName, DWORD dwKeyValueType,
+ LPDWORD lpdwValue)
+{
+ CHECK_KEY_TYPE(dwKeyValueType, szKeyValueName );
+ if (set_changeable_varval(var, *lpdwValue, changeable_vars))
+ {
+ TCHAR szErrorMsg [ 512 ];
+ RegCloseKey( hParametersKey );
+ strxmov(szErrorMsg,
+ TEXT("Value \""),
+ szKeyValueName,
+ TEXT("\" of registry key \"" KEY_SERVICE_PARAMETERS "\" is invalid\n"),NullS);
+ fprintf( stderr, szErrorMsg ); /* not unicode compatible */
+ return 1;
+ }
+ return 0;
+}
+
+
+static int get_service_parameters()
+{
+ DWORD dwLastError;
+ HKEY hParametersKey;
+ DWORD dwIndex;
+ TCHAR szKeyValueName [ 256 ];
+ DWORD dwKeyValueName;
+ DWORD dwKeyValueType;
+ BYTE bKeyValueBuffer [ 512 ];
+ DWORD dwKeyValueBuffer;
+ LPDWORD lpdwValue = (LPDWORD) &bKeyValueBuffer[0];
+ LPCTSTR lpszValue = (LPCTSTR) &bKeyValueBuffer[0];
+
+ /* open parameters of service */
+ dwLastError = (DWORD) RegOpenKeyEx( HKEY_LOCAL_MACHINE,
+ TEXT(KEY_SERVICE_PARAMETERS), 0,
+ KEY_READ, &hParametersKey );
+ if ( dwLastError == ERROR_FILE_NOT_FOUND ) /* no parameters available */
+ return 0;
+ if ( dwLastError != ERROR_SUCCESS )
+ {
+ fprintf(stderr,"Can't open registry key \"" KEY_SERVICE_PARAMETERS "\" for reading\n" );
+ return 1;
+ }
+
+ /* enumerate all values of key */
+ dwIndex = 0;
+ dwKeyValueName = sizeof( szKeyValueName ) / sizeof( TCHAR );
+ dwKeyValueBuffer = sizeof( bKeyValueBuffer );
+ while ( (dwLastError = (DWORD) RegEnumValue(hParametersKey, dwIndex,
+ szKeyValueName, &dwKeyValueName,
+ NULL, &dwKeyValueType,
+ &bKeyValueBuffer[0],
+ &dwKeyValueBuffer))
+ != ERROR_NO_MORE_ITEMS )
+ {
+ /* check if error occured */
+ if ( dwLastError != ERROR_SUCCESS )
+ {
+ RegCloseKey( hParametersKey );
+ fprintf( stderr, "Can't enumerate values of registry key \"" KEY_SERVICE_PARAMETERS "\"\n" );
+ return 1;
+ }
+ if ( lstrcmp(szKeyValueName, TEXT("BaseDir")) == 0 )
+ {
+ CHECK_KEY_TYPE( REG_SZ, szKeyValueName);
+ strmov( mysql_home, lpszValue ); /* not unicode compatible */
+ }
+ else if ( lstrcmp(szKeyValueName, TEXT("BindAddress")) == 0 )
+ {
+ CHECK_KEY_TYPE( REG_SZ, szKeyValueName);
+
+ my_bind_addr = (ulong) inet_addr( lpszValue );
+ if ( my_bind_addr == (ulong) INADDR_NONE )
+ {
+ struct hostent* ent;
+
+ if ( !(*lpszValue) )
+ {
+ char szHostName [ 256 ];
+ if ( gethostname(szHostName, sizeof(szHostName)) == SOCKET_ERROR )
+ {
+ RegCloseKey( hParametersKey );
+ fprintf( stderr, "Can't get my own hostname\n" );
+ return 1;
+ }
+ ent = gethostbyname( szHostName );
+ }
+ else ent = gethostbyname( lpszValue );
+ if ( !ent )
+ {
+ RegCloseKey( hParametersKey );
+ fprintf( stderr, "Can't resolve hostname!\n" );
+ return 1;
+ }
+ my_bind_addr = (ulong) ((in_addr*)ent->h_addr_list[0])->s_addr;
+ }
+ }
+ else if ( lstrcmp(szKeyValueName, TEXT("BigTables")) == 0 )
+ {
+ CHECK_KEY_TYPE( REG_DWORD, szKeyValueName);
+ if ( *lpdwValue )
+ thd_startup_options |= OPTION_BIG_TABLES;
+ else
+ thd_startup_options &= ~((ulong)OPTION_BIG_TABLES);
+ }
+ else if ( lstrcmp(szKeyValueName, TEXT("DataDir")) == 0 )
+ {
+ CHECK_KEY_TYPE( REG_SZ, szKeyValueName );
+ strmov( mysql_real_data_home, lpszValue ); /* not unicode compatible */
+ }
+ else if ( lstrcmp(szKeyValueName, TEXT("Locking")) == 0 )
+ {
+ CHECK_KEY_TYPE( REG_DWORD, szKeyValueName );
+ my_disable_locking = !(*lpdwValue);
+ }
+ else if ( lstrcmp(szKeyValueName, TEXT("LogFile")) == 0 )
+ {
+ CHECK_KEY_TYPE( REG_SZ, szKeyValueName );
+ opt_log = 1;
+ COPY_KEY_VALUE( opt_logname );
+ }
+ else if ( lstrcmp(szKeyValueName, TEXT("UpdateLogFile")) == 0 )
+ {
+ CHECK_KEY_TYPE( REG_SZ, szKeyValueName );
+ opt_update_log = 1;
+ COPY_KEY_VALUE( opt_update_logname );
+ }
+ else if ( lstrcmp(szKeyValueName, TEXT("BinaryLogFile")) == 0 )
+ {
+ CHECK_KEY_TYPE( REG_SZ, szKeyValueName );
+ opt_bin_log = 1;
+ COPY_KEY_VALUE( opt_bin_logname );
+ }
+ else if ( lstrcmp(szKeyValueName, TEXT("BinaryLogIndexFile")) == 0 )
+ {
+ CHECK_KEY_TYPE( REG_SZ, szKeyValueName );
+ opt_bin_log = 1;
+ COPY_KEY_VALUE( opt_binlog_index_name );
+ }
+ else if ( lstrcmp(szKeyValueName, TEXT("ISAMLogFile")) == 0 )
+ {
+ CHECK_KEY_TYPE( REG_SZ, szKeyValueName );
+ COPY_KEY_VALUE( nisam_log_filename );
+ (void) nisam_log( 1 );
+ }
+ else if ( lstrcmp(szKeyValueName, TEXT("LongLogFormat")) == 0 )
+ {
+ CHECK_KEY_TYPE( REG_DWORD, szKeyValueName );
+ if ( *lpdwValue )
+ opt_specialflag |= SPECIAL_LONG_LOG_FORMAT;
+ else
+ opt_specialflag &= ~((ulong)SPECIAL_LONG_LOG_FORMAT);
+ }
+ else if ( lstrcmp(szKeyValueName, TEXT("LowPriorityUpdates")) == 0 )
+ {
+ CHECK_KEY_TYPE( REG_DWORD, szKeyValueName );
+ if ( *lpdwValue )
+ {
+ thd_startup_options |= OPTION_LOW_PRIORITY_UPDATES;
+ low_priority_updates = 1;
+ }
+ else
+ {
+ thd_startup_options &= ~((ulong)OPTION_LOW_PRIORITY_UPDATES);
+ low_priority_updates = 0;
+ }
+ }
+ else if ( lstrcmp(szKeyValueName, TEXT("Port")) == 0 )
+ {
+ CHECK_KEY_TYPE( REG_DWORD, szKeyValueName );
+ mysql_port = (unsigned int) *lpdwValue;
+ }
+ else if ( lstrcmp(szKeyValueName, TEXT("OldProtocol")) == 0 )
+ {
+ CHECK_KEY_TYPE( REG_DWORD, szKeyValueName );
+ protocol_version = *lpdwValue ? PROTOCOL_VERSION - 1 : PROTOCOL_VERSION;
+ }
+ else if ( lstrcmp(szKeyValueName, TEXT("HostnameResolving")) == 0 )
+ {
+ CHECK_KEY_TYPE( REG_DWORD, szKeyValueName );
+ if ( !*lpdwValue )
+ opt_specialflag |= SPECIAL_NO_RESOLVE;
+ else
+ opt_specialflag &= ~((ulong)SPECIAL_NO_RESOLVE);
+ }
+ else if ( lstrcmp(szKeyValueName, TEXT("Networking")) == 0 )
+ {
+ CHECK_KEY_TYPE( REG_DWORD, szKeyValueName );
+ opt_disable_networking = !(*lpdwValue);
+ }
+ else if ( lstrcmp(szKeyValueName, TEXT("ShowDatabase")) == 0 )
+ {
+ CHECK_KEY_TYPE( REG_DWORD, szKeyValueName );
+ opt_disable_networking = !(*lpdwValue);
+ }
+ else if ( lstrcmp(szKeyValueName, TEXT("HostnameCaching")) == 0 )
+ {
+ CHECK_KEY_TYPE( REG_DWORD, szKeyValueName );
+ if ( !*lpdwValue )
+ opt_specialflag |= SPECIAL_NO_HOST_CACHE;
+ else
+ opt_specialflag &= ~((ulong)SPECIAL_NO_HOST_CACHE);
+ }
+ else if ( lstrcmp(szKeyValueName, TEXT("ThreadPriority")) == 0 )
+ {
+ CHECK_KEY_TYPE( REG_DWORD, szKeyValueName );
+ if ( !(*lpdwValue) )
+ opt_specialflag |= SPECIAL_NO_PRIOR;
+ else
+ opt_specialflag &= ~((ulong)SPECIAL_NO_PRIOR);
+ }
+ else if ( lstrcmp(szKeyValueName, TEXT("NamedPipe")) == 0 )
+ {
+ CHECK_KEY_TYPE( REG_SZ, szKeyValueName );
+ COPY_KEY_VALUE( mysql_unix_port );
+ }
+ else if ( lstrcmp(szKeyValueName, TEXT("TempDir")) == 0 )
+ {
+ CHECK_KEY_TYPE( REG_SZ, szKeyValueName );
+ COPY_KEY_VALUE( mysql_tmpdir );
+ }
+ else if ( lstrcmp(szKeyValueName, TEXT("FlushTables")) == 0 )
+ {
+ CHECK_KEY_TYPE( REG_DWORD, szKeyValueName );
+ nisam_flush = myisam_flush= *lpdwValue ? 1 : 0;
+ }
+ else if ( lstrcmp(szKeyValueName, TEXT("BackLog")) == 0 )
+ {
+ SET_CHANGEABLE_VARVAL( "back_log" );
+ }
+ else if ( lstrcmp(szKeyValueName, TEXT("ConnectTimeout")) == 0 )
+ {
+ SET_CHANGEABLE_VARVAL( "connect_timeout" );
+ }
+ else if ( lstrcmp(szKeyValueName, TEXT("JoinBufferSize")) == 0 )
+ {
+ SET_CHANGEABLE_VARVAL( "join_buffer" );
+ }
+ else if ( lstrcmp(szKeyValueName, TEXT("KeyBufferSize")) == 0 )
+ {
+ SET_CHANGEABLE_VARVAL( "key_buffer" );
+ }
+ else if ( lstrcmp(szKeyValueName, TEXT("LongQueryTime")) == 0 )
+ {
+ SET_CHANGEABLE_VARVAL( "long_query_time" );
+ }
+ else if ( lstrcmp(szKeyValueName, TEXT("MaxAllowedPacket")) == 0 )
+ {
+ SET_CHANGEABLE_VARVAL( "max_allowed_packet" );
+ }
+ else if ( lstrcmp(szKeyValueName, TEXT("MaxConnections")) == 0 )
+ {
+ SET_CHANGEABLE_VARVAL( "max_connections" );
+ }
+ else if ( lstrcmp(szKeyValueName, TEXT("MaxConnectErrors")) == 0 )
+ {
+ SET_CHANGEABLE_VARVAL( "max_connect_errors" );
+ }
+ else if ( lstrcmp(szKeyValueName, TEXT("MaxInsertDelayedThreads")) == 0 )
+ {
+ SET_CHANGEABLE_VARVAL( "max_delayed_threads" );
+ }
+ else if ( lstrcmp(szKeyValueName, TEXT("MaxJoinSize")) == 0 )
+ {
+ SET_CHANGEABLE_VARVAL( "max_join_size" );
+ }
+ else if ( lstrcmp(szKeyValueName, TEXT("MaxSortLength")) == 0 )
+ {
+ SET_CHANGEABLE_VARVAL( "max_sort_length" );
+ }
+ else if ( lstrcmp(szKeyValueName, TEXT("NetBufferLength")) == 0 )
+ {
+ SET_CHANGEABLE_VARVAL( "net_buffer_length" );
+ }
+ else if ( lstrcmp(szKeyValueName, TEXT("RecordBufferSize")) == 0 )
+ {
+ SET_CHANGEABLE_VARVAL( "record_buffer" );
+ }
+ else if ( lstrcmp(szKeyValueName, TEXT("SortBufferSize")) == 0 )
+ {
+ SET_CHANGEABLE_VARVAL( "sort_buffer" );
+ }
+ else if ( lstrcmp(szKeyValueName, TEXT("TableCacheSize")) == 0 )
+ {
+ SET_CHANGEABLE_VARVAL( "table_cache" );
+ }
+ else if ( lstrcmp(szKeyValueName, TEXT("TmpTableSize")) == 0 )
+ {
+ SET_CHANGEABLE_VARVAL( "tmp_table_size" );
+ }
+ else if ( lstrcmp(szKeyValueName, TEXT("ThreadStackSize")) == 0 )
+ {
+ SET_CHANGEABLE_VARVAL( "thread_stack" );
+ }
+ else if ( lstrcmp(szKeyValueName, TEXT("WaitTimeout")) == 0 )
+ {
+ SET_CHANGEABLE_VARVAL( "wait_timeout" );
+ }
+ else if ( lstrcmp(szKeyValueName, TEXT("DelayedInsertTimeout"))
+ == 0 )
+ {
+ SET_CHANGEABLE_VARVAL( "delayed_insert_timeout" );
+ }
+ else if ( lstrcmp(szKeyValueName, TEXT("DelayedInsertLimit")) ==
+ 0 )
+ {
+ SET_CHANGEABLE_VARVAL( "delayed_insert_limit" );
+ }
+ else if ( lstrcmp(szKeyValueName, TEXT("DelayedQueueSize")) == 0
+ )
+ {
+ SET_CHANGEABLE_VARVAL( "delayed_queue_size" );
+ }
+ else if ( lstrcmp(szKeyValueName, TEXT("FlushTime")) == 0 )
+ {
+ SET_CHANGEABLE_VARVAL( "flush_time" );
+ }
+ else if ( lstrcmp(szKeyValueName, TEXT("InteractiveTimeout")) ==
+ 0 )
+ {
+ SET_CHANGEABLE_VARVAL( "interactive_timeout" );
+ }
+ else if ( lstrcmp(szKeyValueName, TEXT("LowerCaseTableNames"))
+ == 0 )
+ {
+ SET_CHANGEABLE_VARVAL( "lower_case_table_names" );
+ }
+ else if ( lstrcmp(szKeyValueName, TEXT("MaxHeapTableSize")) == 0
+ )
+ {
+ SET_CHANGEABLE_VARVAL( "max_heap_table_size" );
+ }
+ else if ( lstrcmp(szKeyValueName, TEXT("MaxTmpTables")) == 0 )
+ {
+ SET_CHANGEABLE_VARVAL( "max_tmp_tables" );
+ }
+ else if ( lstrcmp(szKeyValueName, TEXT("MaxWriteLockCount")) ==
+ 0 )
+ {
+ SET_CHANGEABLE_VARVAL( "max_write_lock_count" );
+ }
+ else if ( lstrcmp(szKeyValueName, TEXT("NetRetryCount")) == 0 )
+ {
+ SET_CHANGEABLE_VARVAL( "net_retry_count" );
+ }
+ else if ( lstrcmp(szKeyValueName, TEXT("QueryBufferSize")) == 0
+ )
+ {
+ SET_CHANGEABLE_VARVAL( "query_buffer_size" );
+ }
+ else if ( lstrcmp(szKeyValueName, TEXT("ThreadConcurrency")) ==
+ 0 )
+ {
+ SET_CHANGEABLE_VARVAL( "thread_concurrency" );
+ }
+ else
+ {
+ TCHAR szErrorMsg [ 512 ];
+ RegCloseKey( hParametersKey );
+ lstrcpy( szErrorMsg, TEXT("Value \"") );
+ lstrcat( szErrorMsg, szKeyValueName );
+ lstrcat( szErrorMsg, TEXT("\" of registry key \"" KEY_SERVICE_PARAMETERS "\" is not defined by MySQL\n") );
+ fprintf( stderr, szErrorMsg ); /* not unicode compatible */
+ return 1;
+ }
+
+ dwIndex++;
+ dwKeyValueName = sizeof( szKeyValueName ) / sizeof( TCHAR );
+ dwKeyValueBuffer = sizeof( bKeyValueBuffer );
+ }
+ RegCloseKey( hParametersKey );
+
+ /* paths are fixed by method get_options() */
+ return 0;
+}
+#endif
+
+
+static char *get_relative_path(const char *path)
+{
+ if (test_if_hard_path(path) &&
+ is_prefix(path,DEFAULT_MYSQL_HOME) &&
+ strcmp(DEFAULT_MYSQL_HOME,FN_ROOTDIR))
+ {
+ path+=strlen(DEFAULT_MYSQL_HOME);
+ while (*path == FN_LIBCHAR)
+ path++;
+ }
+ return (char*) 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);
+ (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);
+
+ char buff[FN_REFLEN],*sharedir=get_relative_path(SHAREDIR);
+ if (test_if_hard_path(sharedir))
+ strmov(buff,sharedir); /* purecov: tested */
+ else
+ strxmov(buff,mysql_home,sharedir,NullS);
+ convert_dirname(buff);
+ (void) my_load_path(language,language,buff);
+
+ /* If --character-sets-dir isn't given, use shared library dir */
+ if (charsets_dir != mysql_charsets_dir)
+ {
+ strmov(strmov(mysql_charsets_dir,buff),CHARSET_DIR);
+ charsets_dir=mysql_charsets_dir;
+ }
+
+ /* Add '/' to TMPDIR if needed */
+ char *tmp= (char*) my_malloc(FN_REFLEN,MYF(MY_FAE));
+ if (tmp)
+ {
+ strmov(tmp,mysql_tmpdir);
+ mysql_tmpdir=tmp;
+ convert_dirname(mysql_tmpdir);
+ mysql_tmpdir=(char*) my_realloc(mysql_tmpdir,strlen(mysql_tmpdir)+1,
+ MYF(MY_HOLD_ON_ERROR));
+ }
+}
+
+
+#ifdef SET_RLIMIT_NOFILE
+static uint set_maximum_open_files(uint max_file_limit)
+{
+ struct rlimit rlimit;
+ ulong old_cur;
+
+ if (!getrlimit(RLIMIT_NOFILE,&rlimit))
+ {
+ old_cur=rlimit.rlim_cur;
+ if (rlimit.rlim_cur >= max_file_limit) // Nothing to do
+ return rlimit.rlim_cur; /* purecov: inspected */
+ 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 */
+ 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 */
+ max_file_limit=rlimit.rlim_cur;
+ }
+ }
+ return max_file_limit;
+}
+#endif
+
+
+/*****************************************************************************
+** Instantiate templates
+*****************************************************************************/
+
+#ifdef __GNUC__
+/* Used templates */
+template class I_List<THD>;
+template class I_List_iterator<THD>;
+template class I_List<i_string>;
+#endif
diff --git a/sql/net_pkg.cc b/sql/net_pkg.cc
new file mode 100644
index 00000000000..27065ee776e
--- /dev/null
+++ b/sql/net_pkg.cc
@@ -0,0 +1,329 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 <stdarg.h>
+
+ /* Send a error string to client */
+
+void send_error(NET *net, uint sql_errno, const char *err)
+{
+ uint length;
+ char buff[MYSQL_ERRMSG_SIZE+2];
+ THD *thd=current_thd;
+ DBUG_ENTER("send_error");
+ DBUG_PRINT("enter",("sql_errno: %d err: %s", sql_errno,
+ err ? err : net->last_error[0] ?
+ net->last_error : "NULL"));
+
+ if (thd)
+ thd->query_error = 1; // needed to catch query errors during replication
+ if (!err)
+ {
+ if (sql_errno)
+ err=ER(sql_errno);
+ else if (!err)
+ {
+ if ((err=net->last_error)[0])
+ sql_errno=net->last_errno;
+ else
+ {
+ sql_errno=ER_UNKNOWN_ERROR;
+ err=ER(sql_errno); /* purecov: inspected */
+ }
+ }
+ }
+ if (net->vio == 0)
+ {
+ if (thd && thd->bootstrap)
+ {
+ fprintf(stderr,"ERROR: %d %s\n",sql_errno,err);
+ }
+ DBUG_VOID_RETURN;
+ }
+
+ if (net->return_errno)
+ { // new client code; Add errno before message
+ int2store(buff,sql_errno);
+ length= (uint) (strmake(buff+2,err,MYSQL_ERRMSG_SIZE-1) - buff);
+ err=buff;
+ }
+ else
+ {
+ length=strlen(err);
+ set_if_smaller(length,MYSQL_ERRMSG_SIZE);
+ }
+ VOID(net_write_command(net,(uchar) 255,(char*) err,length));
+ if (thd)
+ thd->fatal_error=0; // Error message is given
+ DBUG_VOID_RETURN;
+}
+
+/**
+** write error package and flush to client
+** It's a little too low level, but I don't want to allow another buffer
+*/
+/* VARARGS3 */
+
+void
+net_printf(NET *net, uint errcode, ...)
+{
+ va_list args;
+ uint length,offset;
+ const char *format,*text_pos;
+ int head_length= NET_HEADER_SIZE;
+ THD *thd=current_thd;
+ DBUG_ENTER("net_printf");
+ DBUG_PRINT("enter",("message: %u",errcode));
+
+ if(thd) thd->query_error = 1;
+ // if we are here, something is wrong :-)
+
+ va_start(args,errcode);
+ format=ER(errcode);
+ offset= net->return_errno ? 2 : 0;
+ text_pos=(char*) net->buff+head_length+offset+1;
+ (void) vsprintf(my_const_cast(char*) (text_pos),format,args);
+ length=strlen((char*) text_pos);
+ if (length >= sizeof(net->last_error))
+ length=sizeof(net->last_error)-1; /* purecov: inspected */
+ va_end(args);
+
+ if (net->vio == 0)
+ {
+ if (thd && thd->bootstrap)
+ {
+ fprintf(stderr,"ERROR: %d %s\n",errcode,text_pos);
+ thd->fatal_error=1;
+ }
+ DBUG_VOID_RETURN;
+ }
+
+ int3store(net->buff,length+1+offset);
+ net->buff[3]= (net->compress) ? 0 : (uchar) (net->pkt_nr++);
+ net->buff[head_length]=(uchar) 255; // Error package
+ if (offset)
+ int2store(text_pos-2, errcode);
+ VOID(net_real_write(net,(char*) net->buff,length+head_length+1+offset));
+ if (thd)
+ thd->fatal_error=0; // Error message is given
+ DBUG_VOID_RETURN;
+}
+
+
+void
+send_ok(NET *net,ha_rows affected_rows,ulonglong id,const char *message)
+{
+ if(net->no_send_ok)
+ return;
+
+ char buff[MYSQL_ERRMSG_SIZE+10],*pos;
+ DBUG_ENTER("send_ok");
+ buff[0]=0; // No fields
+ pos=net_store_length(buff+1,(ulonglong) affected_rows);
+ pos=net_store_length(pos, (ulonglong) id);
+ if (net->return_status)
+ {
+ int2store(pos,*net->return_status);
+ pos+=2;
+ }
+ if (message)
+ pos=net_store_data((char*) pos,message);
+ if (net->vio != 0)
+ {
+ VOID(my_net_write(net,buff,(uint) (pos-buff)));
+ VOID(net_flush(net));
+ }
+ DBUG_VOID_RETURN;
+}
+
+void
+send_eof(NET *net,bool no_flush)
+{
+ static char eof_buff[1]= { (char) 254 }; /* Marker for end of fields */
+ DBUG_ENTER("send_eof");
+ if (net->vio != 0)
+ {
+ VOID(my_net_write(net,eof_buff,1));
+ if (!no_flush)
+ VOID(net_flush(net));
+ }
+ DBUG_VOID_RETURN;
+}
+
+
+/****************************************************************************
+** Store a field length in logical packet
+****************************************************************************/
+
+char *
+net_store_length(char *pkg, ulonglong length)
+{
+ uchar *packet=(uchar*) pkg;
+ if (length < LL(251))
+ {
+ *packet=(uchar) length;
+ return (char*) packet+1;
+ }
+ /* 251 is reserved for NULL */
+ if (length < LL(65536))
+ {
+ *packet++=252;
+ int2store(packet,(uint) length);
+ return (char*) packet+2;
+ }
+ if (length < LL(16777216))
+ {
+ *packet++=253;
+ int3store(packet,(ulong) length);
+ return (char*) packet+3;
+ }
+ *packet++=254;
+ int8store(packet,length);
+ return (char*) packet+9;
+}
+
+char *
+net_store_length(char *pkg, uint length)
+{
+ uchar *packet=(uchar*) pkg;
+ if (length < 251)
+ {
+ *packet=(uchar) length;
+ return (char*) packet+1;
+ }
+ *packet++=252;
+ int2store(packet,(uint) length);
+ return (char*) packet+2;
+}
+
+/* The following will only be used for short strings < 65K */
+char *
+net_store_data(char *to,const char *from)
+{
+ uint length=strlen(from);
+ to=net_store_length(to,length);
+ memcpy(to,from,length);
+ return to+length;
+}
+
+
+char *
+net_store_data(char *to,int32 from)
+{
+ char buff[20];
+ uint length=(uint) (int10_to_str(from,buff,10)-buff);
+ to=net_store_length(to,length);
+ memcpy(to,buff,length);
+ return to+length;
+}
+
+char *
+net_store_data(char *to,longlong from)
+{
+ char buff[22];
+ uint length=(uint) (longlong10_to_str(from,buff,10)-buff);
+ to=net_store_length(to,length);
+ memcpy(to,buff,length);
+ return to+length;
+}
+
+
+bool net_store_null(String *packet)
+{
+ return packet->append((char) 251);
+}
+
+bool
+net_store_data(String *packet,const char *from,uint length)
+{
+ ulong packet_length=packet->length();
+ if (packet_length+5+length > packet->alloced_length() &&
+ packet->realloc(packet_length+5+length))
+ return 1;
+ char *to=(char*) net_store_length((char*) packet->ptr()+packet_length,
+ (ulonglong) length);
+ memcpy(to,from,length);
+ packet->length((uint) (to+length-packet->ptr()));
+ return 0;
+}
+
+/* The following is only used at short, null terminated data */
+
+bool
+net_store_data(String *packet,const char *from)
+{
+ uint length=strlen(from);
+ uint packet_length=packet->length();
+ if (packet_length+5+length > packet->alloced_length() &&
+ packet->realloc(packet_length+5+length))
+ return 1;
+ char *to=(char*) net_store_length((char*) packet->ptr()+packet_length,
+ length);
+ memcpy(to,from,length);
+ packet->length((uint) (to+length-packet->ptr()));
+ return 0;
+}
+
+
+bool
+net_store_data(String *packet,uint32 from)
+{
+ char buff[20];
+ return net_store_data(packet,(char*) buff,
+ (uint) (int10_to_str(from,buff,10)-buff));
+}
+
+bool
+net_store_data(String *packet, longlong from)
+{
+ char buff[22];
+ return net_store_data(packet,(char*) buff,
+ (uint) (longlong10_to_str(from,buff,10)-buff));
+}
+
+bool
+net_store_data(String *packet,struct tm *tmp)
+{
+ char buff[20];
+ sprintf(buff,"%04d-%02d-%02d %02d:%02d:%02d",
+ ((int) (tmp->tm_year+1900)) % 10000,
+ (int) tmp->tm_mon+1,
+ (int) tmp->tm_mday,
+ (int) tmp->tm_hour,
+ (int) tmp->tm_min,
+ (int) tmp->tm_sec);
+ return net_store_data(packet,(char*) buff,19);
+}
+
+bool net_store_data(String* packet, I_List<i_string>* str_list)
+{
+ char buf[256];
+ String tmp(buf, sizeof(buf));
+ tmp.length(0);
+ I_List_iterator<i_string> it(*str_list);
+ i_string* s;
+
+ while((s=it++))
+ {
+ if(tmp.length())
+ tmp.append(',');
+ tmp.append(s->ptr);
+ }
+
+ return net_store_data(packet, (char*)tmp.ptr(), tmp.length());
+}
diff --git a/sql/net_serv.cc b/sql/net_serv.cc
new file mode 100644
index 00000000000..643b5e031cf
--- /dev/null
+++ b/sql/net_serv.cc
@@ -0,0 +1,680 @@
+/* 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 */
+
+/* Write and read of logical packets to/from socket
+** Writes are cached into net_buffer_length big packets.
+** Read packets are reallocated dynamicly when reading big packets.
+** Each logical packet has the following pre-info:
+** 3 byte length & 1 byte package-number.
+*/
+
+#ifdef __WIN__
+#include <winsock.h>
+#endif
+#include <global.h>
+#include <violite.h>
+#include <my_sys.h>
+#include <m_string.h>
+#include "mysql.h"
+#include "mysqld_error.h"
+#include <signal.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <violite.h>
+
+#ifdef MYSQL_SERVER
+ulong max_allowed_packet=65536;
+extern ulong net_read_timeout,net_write_timeout;
+extern uint test_flags;
+#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>
+#endif
+#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
+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))
+static 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 pthread_mutex_t LOCK_bytes_sent , LOCK_bytes_received;
+#else
+#undef statistic_add
+#define statistic_add(A,B,C)
+#endif
+
+/*
+** 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.
+*/
+
+#define TEST_BLOCKING 8
+static int net_write_buff(NET *net,const char *packet,uint 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))))
+ return 1;
+ if (net_buffer_length > max_allowed_packet)
+ max_allowed_packet=net_buffer_length;
+ net->buff_end=net->buff+(net->max_packet=net_buffer_length);
+ 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->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;
+
+ if (vio != 0) /* If real connection */
+ {
+ net->fd = vio_fd(vio); /* For perl DBI/DBD */
+#if defined(MYSQL_SERVER) && !defined(___WIN__) && !defined(__EMX__)
+ if (!(test_flags & TEST_BLOCKING))
+ vio_blocking(vio, FALSE);
+#endif
+ vio_fastsend(vio,TRUE);
+ }
+ return 0;
+}
+
+void net_end(NET *net)
+{
+ my_free((gptr) net->buff,MYF(MY_ALLOW_ZERO_PTR));
+ net->buff=0;
+}
+
+/* Realloc the packet buffer */
+
+static my_bool net_realloc(NET *net, ulong length)
+{
+ uchar *buff;
+ ulong pkt_length;
+ if (length >= max_allowed_packet)
+ {
+ DBUG_PRINT("error",("Packet too large (%lu)", length));
+ net->error=1;
+ 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))))
+ {
+ net->error=1;
+#ifdef MYSQL_SERVER
+ net->last_errno=ER_OUT_OF_RESOURCES;
+#endif
+ return 1;
+ }
+ net->buff=net->write_pos=buff;
+ net->buff_end=buff+(net->max_packet=pkt_length);
+ return 0;
+}
+
+ /* Remove unwanted characters from connection */
+
+void net_clear(NET *net)
+{
+#ifndef EXTRA_DEBUG
+ int count;
+ 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)
+ 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->write_pos=net->buff;
+}
+
+ /* Flush write_buffer if not empty. */
+
+int net_flush(NET *net)
+{
+ int error=0;
+ DBUG_ENTER("net_flush");
+ if (net->buff != net->write_pos)
+ {
+ error=net_real_write(net,(char*) net->buff,
+ (uint) (net->write_pos - net->buff));
+ net->write_pos=net->buff;
+ }
+ DBUG_RETURN(error);
+}
+
+
+/*****************************************************************************
+** 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!
+*/
+
+int
+my_net_write(NET *net,const char *packet,ulong len)
+{
+ uchar buff[NET_HEADER_SIZE];
+ int3store(buff,len);
+ buff[3]= (net->compress) ? 0 : (uchar) (net->pkt_nr++);
+ if (net_write_buff(net,(char*) buff,NET_HEADER_SIZE))
+ return 1;
+ return net_write_buff(net,packet,len);
+}
+
+int
+net_write_command(NET *net,uchar command,const char *packet,ulong len)
+{
+ uchar buff[NET_HEADER_SIZE+1];
+ uint length=len+1; /* 1 extra byte for command */
+
+ 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));
+}
+
+
+static int
+net_write_buff(NET *net,const char *packet,uint len)
+{
+ uint left_length=(uint) (net->buff_end - net->write_pos);
+
+ while (len > left_length)
+ {
+ memcpy((char*) net->write_pos,packet,left_length);
+ if (net_real_write(net,(char*) net->buff,net->max_packet))
+ return 1;
+ net->write_pos=net->buff;
+ packet+=left_length;
+ len-=left_length;
+ left_length=net->max_packet;
+ }
+ memcpy((char*) net->write_pos,packet,len);
+ net->write_pos+=len;
+ return 0;
+}
+
+/* Read and write using timeouts */
+
+int
+net_real_write(NET *net,const char *packet,ulong len)
+{
+ int length;
+ char *pos,*end;
+ thr_alarm_t alarmed;
+#if (!defined(__WIN__) && !defined(__EMX__))
+ ALARM alarm_buff;
+#endif
+ uint retry_count=0;
+ my_bool net_blocking = vio_is_blocking(net->vio);
+ DBUG_ENTER("net_real_write");
+
+ if (net->error == 2)
+ DBUG_RETURN(-1); /* socket can't be used */
+
+ net->reading_or_writing=2;
+#ifdef HAVE_COMPRESS
+ if (net->compress)
+ {
+ 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))))
+ {
+#ifdef MYSQL_SERVER
+ net->last_errno=ER_OUT_OF_RESOURCES;
+ net->error=2;
+#endif
+ net->reading_or_writing=0;
+ DBUG_RETURN(1);
+ }
+ memcpy(b+header_length,packet,len);
+
+ if (my_compress((byte*) b+header_length,&len,&complen))
+ {
+ DBUG_PRINT("warning",
+ ("Compression error; Continuing without compression"));
+ complen=0;
+ }
+ int3store(&b[NET_HEADER_SIZE],complen);
+ int3store(b,len);
+ b[3]=(uchar) (net->pkt_nr++);
+ len+= header_length;
+ packet= (char*) b;
+ }
+#endif /* HAVE_COMPRESS */
+
+ /* DBUG_DUMP("net",packet,len); */
+#ifdef MYSQL_SERVER
+ thr_alarm_init(&alarmed);
+ if (net_blocking)
+ thr_alarm(&alarmed,(uint) net_write_timeout,&alarm_buff);
+#else
+ alarmed=0;
+#endif /* MYSQL_SERVER */
+
+ pos=(char*) packet; end=pos+len;
+ while (pos != end)
+ {
+ if ((int) (length=vio_write(net->vio,pos,(size_t) (end-pos))) <= 0)
+ {
+ my_bool interrupted = vio_should_retry(net->vio);
+#if (!defined(__WIN__) && !defined(__EMX__))
+ if ((interrupted || length==0) && !thr_alarm_in_use(alarmed))
+ {
+ if (!thr_alarm(&alarmed,(uint) net_write_timeout,&alarm_buff))
+ { /* Always true for client */
+ if (!vio_is_blocking(net->vio))
+ {
+ while (vio_blocking(net->vio, TRUE) < 0)
+ {
+ if (vio_should_retry(net->vio) && retry_count++ < RETRY_COUNT)
+ continue;
+#ifdef EXTRA_DEBUG
+ fprintf(stderr,
+ "%s: my_net_write: fcntl returned error %d, aborting thread\n",
+ my_progname,vio_errno(net->vio));
+#endif /* EXTRA_DEBUG */
+ net->error=2; /* Close socket */
+ goto end;
+ }
+ }
+ retry_count=0;
+ continue;
+ }
+ }
+ else
+#endif /* (!defined(__WIN__) && !defined(__EMX__)) */
+ if (thr_alarm_in_use(alarmed) && !thr_got_alarm(alarmed) &&
+ interrupted)
+ {
+ if (retry_count++ < RETRY_COUNT)
+ continue;
+#ifdef EXTRA_DEBUG
+ fprintf(stderr, "%s: write looped, aborting thread\n",
+ my_progname);
+#endif /* EXTRA_DEBUG */
+ }
+#if defined(THREAD_SAFE_CLIENT) && !defined(MYSQL_SERVER)
+ if (vio_errno(net->vio) == EINTR)
+ {
+ DBUG_PRINT("warning",("Interrupted write. Retrying..."));
+ continue;
+ }
+#endif /* defined(THREAD_SAFE_CLIENT) && !defined(MYSQL_SERVER) */
+ net->error=2; /* Close socket */
+#ifdef MYSQL_SERVER
+ net->last_errno= (interrupted ? ER_NET_WRITE_INTERRUPTED :
+ ER_NET_ERROR_ON_WRITE);
+#endif /* MYSQL_SERVER */
+ break;
+ }
+ pos+=length;
+ statistic_add(bytes_sent,length,&LOCK_bytes_sent);
+ }
+#ifndef __WIN__
+ end:
+#endif
+#ifdef HAVE_COMPRESS
+ if (net->compress)
+ my_free((char*) packet,MYF(0));
+#endif
+ if (thr_alarm_in_use(alarmed))
+ {
+ thr_end_alarm(&alarmed);
+ vio_blocking(net->vio, net_blocking);
+ }
+ net->reading_or_writing=0;
+ DBUG_RETURN(((int) (pos != end)));
+}
+
+
+/*****************************************************************************
+** Read something from server/clinet
+*****************************************************************************/
+
+#ifdef MYSQL_SERVER
+
+/*
+ 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)
+{
+ char buff[1024];
+ ALARM alarm_buff;
+ uint retry_count=0;
+ if (!thr_alarm_in_use(alarmed))
+ {
+ if (!thr_alarm(alarmed,net->timeout,&alarm_buff) ||
+ (!vio_is_blocking(net->vio) && vio_blocking(net->vio,TRUE) < 0))
+ return; // Can't setup, abort
+ }
+ while (remain > 0)
+ {
+ ulong length;
+ 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)
+ { /* Probably in MIT threads */
+ if (retry_count++ < RETRY_COUNT)
+ continue;
+ }
+ return;
+ }
+ remain -=(ulong) length;
+ statistic_add(bytes_received,(ulong) length,&LOCK_bytes_received);
+ }
+}
+#endif /* MYSQL_SERVER */
+
+
+static uint
+my_real_read(NET *net, ulong *complen)
+{
+ uchar *pos;
+ long length;
+ uint i,retry_count=0;
+ ulong len=packet_error;
+ thr_alarm_t alarmed;
+#if (!defined(__WIN__) && !defined(__EMX__)) || 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);
+ *complen = 0;
+
+ net->reading_or_writing=1;
+ thr_alarm_init(&alarmed);
+#ifdef MYSQL_SERVER
+ if (net_blocking)
+ thr_alarm(&alarmed,net->timeout,&alarm_buff);
+#endif /* MYSQL_SERVER */
+
+ pos = net->buff + net->where_b; /* net->packet -4 */
+ for (i=0 ; i < 2 ; i++)
+ {
+ while (remain > 0)
+ {
+ /* First read is done with non blocking mode */
+ if ((int) (length=vio_read(net->vio,(char*) pos,remain)) <= 0L)
+ {
+ my_bool interrupted = vio_should_retry(net->vio);
+
+ DBUG_PRINT("info",("vio_read returned %d, errno: %d",
+ length, vio_errno(net->vio)));
+#if (!defined(__WIN__) && !defined(__EMX__)) || defined(MYSQL_SERVER)
+ /*
+ We got an error that there was no data on the socket. We now set up
+ an alarm to not 'read forever', change the socket to non blocking
+ mode and try again
+ */
+ if ((interrupted || length == 0) && !thr_alarm_in_use(alarmed))
+ {
+ if (!thr_alarm(&alarmed,net->timeout,&alarm_buff)) /* Don't wait too long */
+ {
+ if (!vio_is_blocking(net->vio))
+ {
+ while (vio_blocking(net->vio,TRUE) < 0)
+ {
+ if (vio_should_retry(net->vio) &&
+ retry_count++ < RETRY_COUNT)
+ continue;
+ DBUG_PRINT("error",
+ ("fcntl returned error %d, aborting thread",
+ vio_errno(net->vio)));
+#ifdef EXTRA_DEBUG
+ fprintf(stderr,
+ "%s: read: fcntl returned error %d, aborting thread\n",
+ my_progname,vio_errno(net->vio));
+#endif /* EXTRA_DEBUG */
+ len= packet_error;
+ net->error=2; /* Close socket */
+#ifdef MYSQL_SERVER
+ net->last_errno=ER_NET_FCNTL_ERROR;
+#endif
+ goto end;
+ }
+ }
+ retry_count=0;
+ continue;
+ }
+ }
+#endif /* (!defined(__WIN__) && !defined(__EMX__)) || defined(MYSQL_SERVER) */
+ if (thr_alarm_in_use(alarmed) && !thr_got_alarm(alarmed) &&
+ interrupted)
+ { /* Probably in MIT threads */
+ if (retry_count++ < RETRY_COUNT)
+ continue;
+#ifdef EXTRA_DEBUG
+ fprintf(stderr, "%s: read looped with error %d, aborting thread\n",
+ my_progname,vio_errno(net->vio));
+#endif /* EXTRA_DEBUG */
+ }
+#if defined(THREAD_SAFE_CLIENT) && !defined(MYSQL_SERVER)
+ if (vio_should_retry(net->vio))
+ {
+ DBUG_PRINT("warning",("Interrupted read. Retrying..."));
+ continue;
+ }
+#endif
+ DBUG_PRINT("error",("Couldn't read packet: remain: %d errno: %d length: %d alarmed: %d", remain,vio_errno(net->vio),length,alarmed));
+ len= packet_error;
+ net->error=2; /* Close socket */
+#ifdef MYSQL_SERVER
+ net->last_errno= (interrupted ? ER_NET_READ_INTERRUPTED :
+ ER_NET_READ_ERROR);
+#endif
+ goto end;
+ }
+ remain -= (ulong) length;
+ pos+= (ulong) length;
+ statistic_add(bytes_received,(ulong) length,&LOCK_bytes_received);
+ }
+ if (i == 0)
+ { /* First parts is packet length */
+ ulong helping;
+ if (net->buff[net->where_b + 3] != (uchar) net->pkt_nr)
+ {
+ if (net->buff[net->where_b] != (uchar) 255)
+ {
+ DBUG_PRINT("error",
+ ("Packets out of order (Found: %d, expected %d)",
+ (int) net->buff[net->where_b + 3],
+ (uint) (uchar) net->pkt_nr));
+#ifdef EXTRA_DEBUG
+ fprintf(stderr,"Packets out of order (Found: %d, expected %d)\n",
+ (int) net->buff[net->where_b + 3],
+ (uint) (uchar) net->pkt_nr);
+#endif
+ }
+ len= packet_error;
+#ifdef MYSQL_SERVER
+ net->last_errno=ER_NET_PACKETS_OUT_OF_ORDER;
+#endif
+ goto end;
+ }
+ net->pkt_nr++;
+#ifdef HAVE_COMPRESS
+ if (net->compress)
+ {
+ /* complen is > 0 if package is really compressed */
+ *complen=uint3korr(&(net->buff[net->where_b + NET_HEADER_SIZE]));
+ }
+#endif
+
+ len=uint3korr(net->buff+net->where_b);
+ 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))
+ {
+#ifdef MYSQL_SERVER
+ if (i == 1)
+ my_net_skip_rest(net, len, &alarmed);
+#endif
+ len= packet_error; /* Return error */
+ goto end;
+ }
+ }
+ pos=net->buff + net->where_b;
+ remain = len;
+ }
+ }
+
+end:
+ if (thr_alarm_in_use(alarmed))
+ {
+ thr_end_alarm(&alarmed);
+ vio_blocking(net->vio, net_blocking);
+ }
+ net->reading_or_writing=0;
+ return(len);
+}
+
+uint
+my_net_read(NET *net)
+{
+ ulong len,complen;
+
+#ifdef HAVE_COMPRESS
+ if (!net->compress)
+ {
+#endif
+ len = my_real_read (net,&complen);
+ 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 (;;)
+ {
+ if (net->remain_in_buf)
+ {
+ uchar *pos = net->buff + net->buf_length - net->remain_in_buf;
+ if (net->remain_in_buf >= 4)
+ {
+ net->length = uint3korr(pos);
+ if (net->length <= net->remain_in_buf - 4)
+ {
+ /* 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 */
+ }
+ }
+ /* Move data down to read next data packet after current one */
+ if (net->buf_length != net->remain_in_buf)
+ {
+ memmove(net->buff,pos,net->remain_in_buf);
+ net->buf_length=net->remain_in_buf;
+ }
+ 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 */
+#ifdef MYSQL_SERVER
+ net->last_errno=ER_NET_UNCOMPRESS_ERROR;
+#endif
+ break;
+ }
+ net->buf_length+=len;
+ net->remain_in_buf+=len;
+ }
+ if (len != packet_error)
+ {
+ net->save_char= net->read_pos[len]; /* Must be saved */
+ net->read_pos[len]=0; /* Safeguard for mysql_use_result */
+ }
+ return len;
+#endif
+}
diff --git a/sql/nt_servc.cc b/sql/nt_servc.cc
new file mode 100644
index 00000000000..5884300fe95
--- /dev/null
+++ b/sql/nt_servc.cc
@@ -0,0 +1,400 @@
+/* ------------------------------------------------------------------------
+ Windows NT Service class library
+ Copyright Abandoned 1998 Irena Pancirov - Irnet Snc
+ This file is public domain and comes with NO WARRANTY of any kind
+ -------------------------------------------------------------------------- */
+#include <windows.h>
+#include <process.h>
+#include "nt_servc.h"
+
+
+static NTService *pService;
+
+/* ------------------------------------------------------------------------
+
+ -------------------------------------------------------------------------- */
+NTService::NTService()
+{
+
+ bOsNT = FALSE;
+ //service variables
+ ServiceName = NULL;
+ hExitEvent = 0;
+ bPause = FALSE;
+ bRunning = FALSE;
+ hThreadHandle = 0;
+ fpServiceThread = NULL;
+
+ //time-out variables
+ nStartTimeOut = 15000;
+ nStopTimeOut = 15000;
+ nPauseTimeOut = 5000;
+ nResumeTimeOut = 5000;
+
+ //install variables
+ dwDesiredAccess = SERVICE_ALL_ACCESS;
+ dwServiceType = SERVICE_WIN32_OWN_PROCESS;
+ dwStartType = SERVICE_AUTO_START;
+ dwErrorControl = SERVICE_ERROR_NORMAL;
+ szLoadOrderGroup = NULL;
+ lpdwTagID = NULL;
+ szDependencies = NULL;
+
+ my_argc = 0;
+ my_argv = NULL;
+ hShutdownEvent = 0;
+ nError = 0;
+ dwState = 0;
+}
+
+/* ------------------------------------------------------------------------
+
+ -------------------------------------------------------------------------- */
+NTService::~NTService()
+{
+ if(ServiceName != NULL) delete[] ServiceName;
+}
+/* ------------------------------------------------------------------------
+
+ -------------------------------------------------------------------------- */
+BOOL NTService::GetOS()
+{
+ bOsNT = FALSE;
+ memset(&osVer, 0, sizeof(OSVERSIONINFO));
+ osVer.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+ if (GetVersionEx(&osVer))
+ {
+ if (osVer.dwPlatformId == VER_PLATFORM_WIN32_NT)
+ bOsNT = TRUE;
+ }
+ return bOsNT;
+}
+
+/* ------------------------------------------------------------------------
+ Init() Registers the main service thread with the service manager
+
+ ServiceThread - pointer to the main programs entry function
+ when the service is started
+ -------------------------------------------------------------------------- */
+long NTService::Init(LPCSTR szInternName,void *ServiceThread)
+{
+
+ pService = this;
+
+ fpServiceThread = (THREAD_FC)ServiceThread;
+ ServiceName = new char[lstrlen(szInternName)+1];
+ lstrcpy(ServiceName,szInternName);
+
+ SERVICE_TABLE_ENTRY stb[] =
+ {
+ { (char *)szInternName,(LPSERVICE_MAIN_FUNCTION) ServiceMain} ,
+ { NULL, NULL }
+ };
+
+ return StartServiceCtrlDispatcher(stb); //register with the Service Manager
+}
+/* ------------------------------------------------------------------------
+ Install() - Installs the service with Service manager
+ nError values:
+ 0 success
+ 1 Can't open the Service manager
+ 2 Failed to create service
+ -------------------------------------------------------------------------- */
+BOOL NTService::Install(LPCSTR szInternName,LPCSTR szDisplayName,
+ LPCSTR szFullPath, LPCSTR szAccountName,LPCSTR szPassword)
+{
+ SC_HANDLE newService, scm;
+
+ nError=0;
+
+ // open a connection to the SCM
+ scm = OpenSCManager(0, 0,SC_MANAGER_CREATE_SERVICE);
+ if(scm) // Install the new service
+ { newService = CreateService(
+ scm,
+ szInternName,
+ szDisplayName,
+ dwDesiredAccess, //default: SERVICE_ALL_ACCESS
+ dwServiceType, //default: SERVICE_WIN32_OWN_PROCESS
+ dwStartType, //default: SERVICE_AUTOSTART
+ dwErrorControl, //default: SERVICE_ERROR_NORMAL
+ szFullPath, //exec full path
+ szLoadOrderGroup, //default: NULL
+ lpdwTagID, //default: NULL
+ szDependencies, //default: NULL
+ szAccountName, //default: NULL
+ szPassword); //default: NULL
+
+ if (newService) CloseServiceHandle(newService); // clean up
+ else nError=2;
+
+ // clean up
+ CloseServiceHandle(scm);
+ }
+ else nError=1;
+
+ return (!nError);
+}
+/* ------------------------------------------------------------------------
+ Remove() - Removes the service
+ nError values:
+ 0 success
+ 1 Can't open the Service manager
+ 2 Failed to locate service
+ 3 Failed to delete service
+ -------------------------------------------------------------------------- */
+BOOL NTService::Remove(LPCSTR szInternName)
+{
+
+ SC_HANDLE service, scm;
+
+ nError=0;
+
+ // open a connection to the SCM
+ scm = OpenSCManager(0, 0,SC_MANAGER_CREATE_SERVICE);
+
+ if (scm)
+ {
+ //open the service
+ service = OpenService(scm,szInternName, DELETE );
+ if(service)
+ {
+ if(!DeleteService(service)) nError=3;
+ CloseServiceHandle(service);
+ }
+ else
+ {
+ //MessageBox(NULL,"Can't find the service","Remove Error",MB_OK|MB_ICONHAND);
+ nError=2;
+ }
+ CloseServiceHandle(scm);
+ }
+ else nError=1;
+
+ return (!nError);
+}
+
+/* ------------------------------------------------------------------------
+ Stop() - this function should be called before the app. exits to stop
+ the service
+ -------------------------------------------------------------------------- */
+void NTService::Stop(void)
+{
+ SetStatus(SERVICE_STOP_PENDING,NO_ERROR, 0, 1, 60000);
+ StopService();
+ SetStatus(SERVICE_STOPPED, NO_ERROR, 0, 1, 1000);
+}
+
+/* ------------------------------------------------------------------------
+ ServiceMain() - This is the function that is called from the
+ service manager to start the service
+ -------------------------------------------------------------------------- */
+void NTService::ServiceMain(DWORD argc, LPTSTR *argv)
+{
+
+ // registration function
+ pService->hServiceStatusHandle =
+ RegisterServiceCtrlHandler(pService->ServiceName,
+ (LPHANDLER_FUNCTION )NTService::ServiceCtrlHandler);
+
+ if(!pService->hServiceStatusHandle)
+ {
+ pService->Exit(GetLastError());
+ return;
+ }
+
+ // notify SCM of progress
+ if(!pService->SetStatus(SERVICE_START_PENDING,NO_ERROR, 0, 1, 8000))
+ {
+ pService->Exit(GetLastError());
+ return;
+ }
+
+ // create the exit event
+ pService->hExitEvent = CreateEvent (0, TRUE, FALSE,0);
+ if(!pService->hExitEvent)
+ {
+ pService->Exit(GetLastError());
+ return;
+ }
+
+ if(!pService->SetStatus(SERVICE_START_PENDING,NO_ERROR, 0, 3, pService->nStartTimeOut))
+ {
+ pService->Exit(GetLastError());
+ return;
+ }
+
+ // save start arguments
+ pService->my_argc=argc;
+ pService->my_argv=argv;
+
+ // start the service
+ if(!pService->StartService())
+ {
+ pService->Exit(GetLastError());
+ return;
+ }
+
+ // the service is now running.
+ if(!pService->SetStatus(SERVICE_RUNNING,NO_ERROR, 0, 0, 0))
+ {
+ pService->Exit(GetLastError());
+ return;
+ }
+
+ // wait for exit event
+ WaitForSingleObject (pService->hExitEvent, INFINITE);
+
+ // wait for thread to exit
+ WaitForSingleObject (pService->hThreadHandle, 30000);
+
+ pService->Exit(0);
+}
+
+/* ------------------------------------------------------------------------
+ StartService() - starts the appliaction thread
+ -------------------------------------------------------------------------- */
+BOOL NTService::StartService()
+{
+
+ // Start the real service's thread (application)
+ hThreadHandle = (HANDLE) _beginthread((THREAD_FC)fpServiceThread,0,(void *)this);
+
+ if (hThreadHandle==0) return FALSE;
+
+ bRunning = TRUE;
+ return TRUE;
+}
+/* ------------------------------------------------------------------------
+
+ -------------------------------------------------------------------------- */
+void NTService::StopService()
+{
+ bRunning=FALSE;
+
+ // Set the event for application
+ if(hShutdownEvent)
+ SetEvent(hShutdownEvent);
+
+ // Set the event for ServiceMain
+ SetEvent(hExitEvent);
+}
+/* ------------------------------------------------------------------------
+
+ -------------------------------------------------------------------------- */
+void NTService::PauseService()
+{
+ bPause = TRUE;
+ SuspendThread(hThreadHandle);
+}
+/* ------------------------------------------------------------------------
+
+ -------------------------------------------------------------------------- */
+void NTService::ResumeService()
+{
+ bPause=FALSE;
+ ResumeThread(hThreadHandle);
+}
+/* ------------------------------------------------------------------------
+
+ -------------------------------------------------------------------------- */
+BOOL NTService::SetStatus (DWORD dwCurrentState,DWORD dwWin32ExitCode,
+ DWORD dwServiceSpecificExitCode,DWORD dwCheckPoint,DWORD dwWaitHint)
+{
+ BOOL bRet;
+ SERVICE_STATUS serviceStatus;
+
+ dwState=dwCurrentState;
+
+ serviceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
+ serviceStatus.dwCurrentState = dwCurrentState;
+
+ if (dwCurrentState == SERVICE_START_PENDING)
+ serviceStatus.dwControlsAccepted = 0; //don't accept conrol events
+ else
+ serviceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP |
+ SERVICE_ACCEPT_PAUSE_CONTINUE | SERVICE_ACCEPT_SHUTDOWN;
+
+ // if a specific exit code is defined,set up the win32 exit code properly
+ if (dwServiceSpecificExitCode == 0)
+ serviceStatus.dwWin32ExitCode = dwWin32ExitCode;
+ else
+ serviceStatus.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR;
+
+ serviceStatus.dwServiceSpecificExitCode = dwServiceSpecificExitCode;
+
+ serviceStatus.dwCheckPoint = dwCheckPoint;
+ serviceStatus.dwWaitHint = dwWaitHint;
+
+ // Pass the status to the Service Manager
+ bRet=SetServiceStatus (hServiceStatusHandle, &serviceStatus);
+
+ if(!bRet) StopService();
+
+ return bRet;
+}
+/* ------------------------------------------------------------------------
+
+ -------------------------------------------------------------------------- */
+void NTService::ServiceCtrlHandler(DWORD ctrlCode)
+{
+
+ DWORD dwState = 0;
+
+ if(!pService) return;
+
+ dwState=pService->dwState; // get current state
+
+ switch(ctrlCode)
+ {
+
+ /*********** do we need this ? *******************************
+ case SERVICE_CONTROL_PAUSE:
+ if (pService->bRunning && ! pService->bPause)
+ {
+ dwState = SERVICE_PAUSED;
+ pService->SetStatus(SERVICE_PAUSE_PENDING,NO_ERROR, 0, 1, pService->nPauseTimeOut);
+ pService->PauseService();
+ }
+ break;
+
+ case SERVICE_CONTROL_CONTINUE:
+ if (pService->bRunning && pService->bPause)
+ {
+ dwState = SERVICE_RUNNING;
+ pService->SetStatus(SERVICE_CONTINUE_PENDING,NO_ERROR, 0, 1, pService->nResumeTimeOut);
+ pService->ResumeService();
+ }
+ break;
+ ****************************************************************/
+
+ case SERVICE_CONTROL_SHUTDOWN:
+ case SERVICE_CONTROL_STOP:
+ dwState = SERVICE_STOP_PENDING;
+ pService->SetStatus(SERVICE_STOP_PENDING,NO_ERROR, 0, 1, pService->nStopTimeOut);
+ pService->StopService();
+ break;
+
+ default:
+ pService->SetStatus(dwState, NO_ERROR,0, 0, 0);
+ break;
+ }
+ //pService->SetStatus(dwState, NO_ERROR,0, 0, 0);
+}
+/* ------------------------------------------------------------------------
+
+ -------------------------------------------------------------------------- */
+void NTService::Exit(DWORD error)
+{
+ if (hExitEvent) CloseHandle(hExitEvent);
+
+ // Send a message to the scm to tell that we stop
+ if (hServiceStatusHandle)
+ SetStatus(SERVICE_STOPPED, error,0, 0, 0);
+
+ // If the thread has started kill it ???
+ // if (hThreadHandle) CloseHandle(hThreadHandle);
+
+}
+
+/* ------------------------- the end -------------------------------------- */
diff --git a/sql/nt_servc.h b/sql/nt_servc.h
new file mode 100644
index 00000000000..5fda96dc4d8
--- /dev/null
+++ b/sql/nt_servc.h
@@ -0,0 +1,80 @@
+/* ------------------------------------------------------------------------
+ Windows NT Service class library
+ Copyright Abandoned 1998 Irena Pancirov - Irnet Snc
+ This file is public domain and comes with NO WARRANTY of any kind
+ -------------------------------------------------------------------------- */
+
+// main application thread
+typedef void (*THREAD_FC)(void *);
+
+class NTService
+{
+ public:
+ NTService();
+ ~NTService();
+
+ BOOL bOsNT; // true if OS is NT, false for Win95
+ //install optinos
+ DWORD dwDesiredAccess;
+ DWORD dwServiceType;
+ DWORD dwStartType;
+ DWORD dwErrorControl;
+
+ LPSTR szLoadOrderGroup;
+ LPDWORD lpdwTagID;
+ LPSTR szDependencies;
+ OSVERSIONINFO osVer;
+
+ // time-out (in milisec)
+ int nStartTimeOut;
+ int nStopTimeOut;
+ int nPauseTimeOut;
+ int nResumeTimeOut;
+
+ //
+ DWORD my_argc;
+ LPTSTR *my_argv;
+ HANDLE hShutdownEvent;
+ int nError;
+ DWORD dwState;
+
+ BOOL GetOS(); // returns TRUE if WinNT
+ BOOL IsNT() { return bOsNT;}
+ //init service entry point
+ long Init(LPCSTR szInternName,void *ServiceThread);
+
+ //application shutdown event
+ void SetShutdownEvent(HANDLE hEvent){ hShutdownEvent=hEvent; }
+
+
+ //service install / un-install
+ BOOL Install(LPCSTR szInternName,LPCSTR szDisplayName,LPCSTR szFullPath,
+ LPCSTR szAccountName=NULL,LPCSTR szPassword=NULL);
+ BOOL Remove(LPCSTR szInternName);
+
+ void Stop(void); //to be called from app. to stop service
+
+ protected:
+ LPSTR ServiceName;
+ HANDLE hExitEvent;
+ SERVICE_STATUS_HANDLE hServiceStatusHandle;
+ BOOL bPause;
+ BOOL bRunning;
+ HANDLE hThreadHandle;
+ THREAD_FC fpServiceThread;
+
+ void PauseService();
+ void ResumeService();
+ void StopService();
+ BOOL StartService();
+
+ static void ServiceMain(DWORD argc, LPTSTR *argv);
+ static void ServiceCtrlHandler (DWORD ctrlCode);
+
+ void Exit(DWORD error);
+ BOOL SetStatus (DWORD dwCurrentState,DWORD dwWin32ExitCode,
+ DWORD dwServiceSpecificExitCode,
+ DWORD dwCheckPoint,DWORD dwWaitHint);
+
+};
+/* ------------------------- the end -------------------------------------- */
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
new file mode 100644
index 00000000000..4f1abf9b685
--- /dev/null
+++ b/sql/opt_range.cc
@@ -0,0 +1,2543 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+
+#ifdef __GNUC__
+#pragma implementation // gcc: Class implementation
+#endif
+
+#include "mysql_priv.h"
+#include <m_ctype.h>
+#include <nisam.h>
+#include "sql_select.h"
+
+
+#ifndef EXTRA_DEBUG
+#define test_rb_tree(A,B) {}
+#define test_use_count(A) {}
+#endif
+
+
+static int sel_cmp(Field *f,char *a,char *b,uint8 a_flag,uint8 b_flag);
+
+static char is_null_string[2]= {1,0};
+
+class SEL_ARG :public Sql_alloc
+{
+public:
+ uint8 min_flag,max_flag,maybe_flag;
+ uint8 part; // Which key part
+ uint8 maybe_null;
+ uint16 elements; // Elements in tree
+ ulong use_count; // use of this sub_tree
+ Field *field;
+ char *min_value,*max_value; // Pointer to range
+
+ SEL_ARG *left,*right,*next,*prev,*parent,*next_key_part;
+ enum leaf_color { BLACK,RED } color;
+ enum Type { IMPOSSIBLE, MAYBE, MAYBE_KEY, KEY_RANGE } type;
+
+ SEL_ARG() {}
+ SEL_ARG(SEL_ARG &);
+ SEL_ARG(Field *,const char *,const char *);
+ SEL_ARG(Field *field, uint8 part, char *min_value, char *max_value,
+ uint8 min_flag, uint8 max_flag, uint8 maybe_flag);
+ SEL_ARG(enum Type type_arg)
+ :elements(1),use_count(1),left(0),next_key_part(0),type(type_arg) {}
+ inline bool is_same(SEL_ARG *arg)
+ {
+ if (type != arg->type)
+ return 0;
+ if (type != KEY_RANGE)
+ return 1;
+ return cmp_min_to_min(arg) == 0 && cmp_max_to_max(arg) == 0;
+ }
+ inline void merge_flags(SEL_ARG *arg) { maybe_flag|=arg->maybe_flag; }
+ inline void maybe_smaller() { maybe_flag=1; }
+ inline int cmp_min_to_min(SEL_ARG* arg)
+ {
+ return sel_cmp(field,min_value, arg->min_value, min_flag, arg->min_flag);
+ }
+ inline int cmp_min_to_max(SEL_ARG* arg)
+ {
+ return sel_cmp(field,min_value, arg->max_value, min_flag, arg->max_flag);
+ }
+ inline int cmp_max_to_max(SEL_ARG* arg)
+ {
+ return sel_cmp(field,max_value, arg->max_value, max_flag, arg->max_flag);
+ }
+ inline int cmp_max_to_min(SEL_ARG* arg)
+ {
+ return sel_cmp(field,max_value, arg->min_value, max_flag, arg->min_flag);
+ }
+ SEL_ARG *clone_and(SEL_ARG* arg)
+ { // Get overlapping range
+ char *new_min,*new_max;
+ uint8 flag_min,flag_max;
+ if (cmp_min_to_min(arg) >= 0)
+ {
+ new_min=min_value; flag_min=min_flag;
+ }
+ else
+ {
+ new_min=arg->min_value; flag_min=arg->min_flag; /* purecov: deadcode */
+ }
+ if (cmp_max_to_max(arg) <= 0)
+ {
+ new_max=max_value; flag_max=max_flag;
+ }
+ else
+ {
+ new_max=arg->max_value; flag_max=arg->max_flag;
+ }
+ return new SEL_ARG(field, part, new_min, new_max, flag_min, flag_max,
+ test(maybe_flag && arg->maybe_flag));
+ }
+ SEL_ARG *clone_first(SEL_ARG *arg)
+ { // min <= X < arg->min
+ return new SEL_ARG(field,part, min_value, arg->min_value,
+ min_flag, arg->min_flag & NEAR_MIN ? 0 : NEAR_MAX,
+ maybe_flag | arg->maybe_flag);
+ }
+ SEL_ARG *clone_last(SEL_ARG *arg)
+ { // min <= X <= key_max
+ return new SEL_ARG(field, part, min_value, arg->max_value,
+ min_flag, arg->max_flag, maybe_flag | arg->maybe_flag);
+ }
+ SEL_ARG *clone(SEL_ARG *new_parent,SEL_ARG **next);
+
+ bool copy_min(SEL_ARG* arg)
+ { // Get overlapping range
+ if (cmp_min_to_min(arg) > 0)
+ {
+ min_value=arg->min_value; min_flag=arg->min_flag;
+ if ((max_flag & (NO_MAX_RANGE | NO_MIN_RANGE)) ==
+ (NO_MAX_RANGE | NO_MIN_RANGE))
+ return 1; // Full range
+ }
+ maybe_flag|=arg->maybe_flag;
+ return 0;
+ }
+ bool copy_max(SEL_ARG* arg)
+ { // Get overlapping range
+ if (cmp_max_to_max(arg) <= 0)
+ {
+ max_value=arg->max_value; max_flag=arg->max_flag;
+ if ((max_flag & (NO_MAX_RANGE | NO_MIN_RANGE)) ==
+ (NO_MAX_RANGE | NO_MIN_RANGE))
+ return 1; // Full range
+ }
+ maybe_flag|=arg->maybe_flag;
+ return 0;
+ }
+
+ void copy_min_to_min(SEL_ARG *arg)
+ {
+ min_value=arg->min_value; min_flag=arg->min_flag;
+ }
+ void copy_min_to_max(SEL_ARG *arg)
+ {
+ max_value=arg->min_value;
+ max_flag=arg->min_flag & NEAR_MIN ? 0 : NEAR_MAX;
+ }
+ void copy_max_to_min(SEL_ARG *arg)
+ {
+ min_value=arg->max_value;
+ min_flag=arg->max_flag & NEAR_MAX ? 0 : NEAR_MIN;
+ }
+ void store(uint length,char **min_key,uint min_key_flag,
+ char **max_key, uint max_key_flag)
+ {
+ if (!(min_flag & NO_MIN_RANGE) &&
+ !(min_key_flag & (NO_MIN_RANGE | NEAR_MIN)))
+ {
+ if (maybe_null && *min_value)
+ {
+ **min_key=1;
+ bzero(*min_key+1,length);
+ }
+ else
+ memcpy(*min_key,min_value,length+(int) maybe_null);
+ (*min_key)+= length+(int) maybe_null;
+ }
+ if (!(max_flag & NO_MAX_RANGE) &&
+ !(max_key_flag & (NO_MAX_RANGE | NEAR_MAX)))
+ {
+ if (maybe_null && *max_value)
+ {
+ **max_key=1;
+ bzero(*max_key+1,length);
+ }
+ else
+ memcpy(*max_key,max_value,length+(int) maybe_null);
+ (*max_key)+= length+(int) maybe_null;
+ }
+ }
+
+ void store_min_key(KEY_PART *key,char **range_key, uint *range_key_flag)
+ {
+ SEL_ARG *key_tree= first();
+ key_tree->store(key[key_tree->part].part_length,
+ range_key,*range_key_flag,range_key,NO_MAX_RANGE);
+ *range_key_flag|= key_tree->min_flag;
+ if (key_tree->next_key_part &&
+ key_tree->next_key_part->part == key_tree->part+1 &&
+ !(*range_key_flag & (NO_MIN_RANGE | NEAR_MIN)) &&
+ key_tree->next_key_part->type == SEL_ARG::KEY_RANGE)
+ key_tree->next_key_part->store_min_key(key,range_key, range_key_flag);
+ }
+
+ void store_max_key(KEY_PART *key,char **range_key, uint *range_key_flag)
+ {
+ SEL_ARG *key_tree= last();
+ key_tree->store(key[key_tree->part].part_length,
+ range_key, NO_MIN_RANGE, range_key,*range_key_flag);
+ (*range_key_flag)|= key_tree->max_flag;
+ if (key_tree->next_key_part &&
+ key_tree->next_key_part->part == key_tree->part+1 &&
+ !(*range_key_flag & (NO_MAX_RANGE | NEAR_MAX)) &&
+ key_tree->next_key_part->type == SEL_ARG::KEY_RANGE)
+ key_tree->next_key_part->store_max_key(key,range_key, range_key_flag);
+ }
+
+ SEL_ARG *insert(SEL_ARG *key);
+ SEL_ARG *tree_delete(SEL_ARG *key);
+ SEL_ARG *find_range(SEL_ARG *key);
+ SEL_ARG *rb_insert(SEL_ARG *leaf);
+ friend SEL_ARG *rb_delete_fixup(SEL_ARG *root,SEL_ARG *key, SEL_ARG *par);
+#ifdef EXTRA_DEBUG
+ friend int test_rb_tree(SEL_ARG *element,SEL_ARG *parent);
+ void test_use_count(SEL_ARG *root);
+#endif
+ SEL_ARG *first();
+ SEL_ARG *last();
+ void make_root();
+ inline bool simple_key()
+ {
+ return !next_key_part && elements == 1;
+ }
+ void increment_use_count(long count)
+ {
+ if (next_key_part)
+ {
+ next_key_part->use_count+=count;
+ count*= (next_key_part->use_count-count);
+ for (SEL_ARG *pos=next_key_part->first(); pos ; pos=pos->next)
+ if (pos->next_key_part)
+ pos->increment_use_count(count);
+ }
+ }
+ void free_tree()
+ {
+ for (SEL_ARG *pos=first(); pos ; pos=pos->next)
+ if (pos->next_key_part)
+ {
+ pos->next_key_part->use_count--;
+ pos->next_key_part->free_tree();
+ }
+ }
+
+ inline SEL_ARG **parent_ptr()
+ {
+ return parent->left == this ? &parent->left : &parent->right;
+ }
+ SEL_ARG *clone_tree();
+};
+
+
+class SEL_TREE :public Sql_alloc
+{
+public:
+ enum Type { IMPOSSIBLE, ALWAYS, MAYBE, KEY, KEY_SMALLER } type;
+ SEL_TREE(enum Type type_arg) :type(type_arg) {}
+ SEL_TREE() :type(KEY) { bzero((char*) keys,sizeof(keys));}
+ SEL_ARG *keys[MAX_KEY];
+};
+
+
+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];
+ uint real_keynr[MAX_KEY];
+ char min_key[MAX_KEY_LENGTH+MAX_FIELD_WIDTH],
+ max_key[MAX_KEY_LENGTH+MAX_FIELD_WIDTH];
+} 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,
+ 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,
+ char max_sort_char,uint *min_length,uint *max_length);
+static SEL_TREE *get_mm_tree(PARAM *param,COND *cond);
+static ha_rows check_quick_select(PARAM *param,uint index,SEL_ARG *key_tree);
+static ha_rows check_quick_keys(PARAM *param,uint index,SEL_ARG *key_tree,
+ char *min_key,uint min_key_flag,
+ char *max_key, uint max_key_flag);
+
+static QUICK_SELECT *get_quick_select(PARAM *param,uint index,
+ SEL_ARG *key_tree);
+#ifndef DBUG_OFF
+static void print_quick(QUICK_SELECT *quick,key_map needed_reg);
+#endif
+static SEL_TREE *tree_and(PARAM *param,SEL_TREE *tree1,SEL_TREE *tree2);
+static SEL_TREE *tree_or(PARAM *param,SEL_TREE *tree1,SEL_TREE *tree2);
+static SEL_ARG *sel_add(SEL_ARG *key1,SEL_ARG *key2);
+static SEL_ARG *key_or(SEL_ARG *key1,SEL_ARG *key2);
+static SEL_ARG *key_and(SEL_ARG *key1,SEL_ARG *key2,uint clone_flag);
+static bool get_range(SEL_ARG **e1,SEL_ARG **e2,SEL_ARG *root1);
+static bool get_quick_keys(PARAM *param,QUICK_SELECT *quick,KEY_PART *key,
+ SEL_ARG *key_tree,char *min_key,uint min_key_flag,
+ char *max_key,uint max_key_flag);
+static bool eq_tree(SEL_ARG* a,SEL_ARG *b);
+
+static SEL_ARG null_element(SEL_ARG::IMPOSSIBLE);
+
+
+/***************************************************************************
+** Basic functions for SQL_SELECT and QUICK_SELECT
+***************************************************************************/
+
+ /* make a select from mysql info
+ Error is set as following:
+ 0 = ok
+ 1 = Got some error (out of memory?)
+ */
+
+SQL_SELECT *make_select(TABLE *head, table_map const_tables,
+ table_map read_tables, COND *conds, int *error)
+{
+ SQL_SELECT *select;
+ DBUG_ENTER("make_select");
+
+ *error=0;
+ if (!conds)
+ DBUG_RETURN(0);
+ if (!(select= new SQL_SELECT))
+ {
+ *error= 1;
+ DBUG_RETURN(0); /* purecov: inspected */
+ }
+ select->read_tables=read_tables;
+ select->const_tables=const_tables;
+ select->head=head;
+ select->cond=conds;
+
+ if (head->io_cache)
+ {
+ select->file= *head->io_cache;
+ select->records=(ha_rows) (select->file.end_of_file/
+ head->file->ref_length);
+ my_free((gptr) (head->io_cache),MYF(0));
+ head->io_cache=0;
+ }
+ DBUG_RETURN(select);
+}
+
+
+SQL_SELECT::SQL_SELECT() :quick(0),cond(0),free_cond(0)
+{
+ quick_keys=0; needed_reg=0;
+ my_b_clear(&file);
+}
+
+
+SQL_SELECT::~SQL_SELECT()
+{
+ delete quick;
+ if (free_cond)
+ delete cond;
+ close_cached_file(&file);
+}
+
+#undef index // Fix or 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),
+ it(ranges),range(0)
+{
+ if (!no_alloc)
+ {
+ init_sql_alloc(&alloc,1024); // Allocates everything here
+ my_pthread_setspecific_ptr(THR_MALLOC,&alloc);
+ }
+ else
+ bzero((char*) &alloc,sizeof(alloc));
+ file=head->file;
+ error=file->index_init(index);
+ record=head->record[0];
+}
+
+QUICK_SELECT::~QUICK_SELECT()
+{
+ file->index_end();
+ free_root(&alloc);
+}
+
+
+QUICK_RANGE::QUICK_RANGE()
+ :min_key(0),max_key(0),min_length(0),max_length(0),
+ flag(NO_MIN_RANGE | NO_MAX_RANGE)
+{}
+
+
+SEL_ARG::SEL_ARG(SEL_ARG &arg) :Sql_alloc()
+{
+ type=arg.type;
+ min_flag=arg.min_flag;
+ max_flag=arg.max_flag;
+ maybe_flag=arg.maybe_flag;
+ maybe_null=arg.maybe_null;
+ part=arg.part;
+ field=arg.field;
+ min_value=arg.min_value;
+ max_value=arg.max_value;
+ next_key_part=arg.next_key_part;
+ use_count=1; elements=1;
+}
+
+
+inline void SEL_ARG::make_root()
+{
+ left=right= &null_element;
+ color=BLACK;
+ next=prev=0;
+ use_count=0; elements=1;
+}
+
+SEL_ARG::SEL_ARG(Field *f,const char *min_value_arg,const char *max_value_arg)
+ :min_flag(0), max_flag(0), maybe_flag(0), maybe_null(f->real_maybe_null()),
+ elements(1), use_count(1), field(f), min_value((char*) min_value_arg),
+ max_value((char*) max_value_arg), next(0),prev(0),
+ next_key_part(0),color(BLACK),type(KEY_RANGE)
+{
+ left=right= &null_element;
+}
+
+SEL_ARG::SEL_ARG(Field *field_,uint8 part_,char *min_value_,char *max_value_,
+ uint8 min_flag_,uint8 max_flag_,uint8 maybe_flag_)
+ :min_flag(min_flag_),max_flag(max_flag_),maybe_flag(maybe_flag_),
+ part(part_),maybe_null(field_->real_maybe_null()), elements(1),use_count(1),
+ field(field_), min_value(min_value_), max_value(max_value_),
+ next(0),prev(0),next_key_part(0),color(BLACK),type(KEY_RANGE)
+{
+ left=right= &null_element;
+}
+
+SEL_ARG *SEL_ARG::clone(SEL_ARG *new_parent,SEL_ARG **next_arg)
+{
+ SEL_ARG *tmp;
+ if (type != KEY_RANGE)
+ {
+ tmp=new SEL_ARG(type);
+ tmp->prev= *next_arg; // Link into next/prev chain
+ (*next_arg)->next=tmp;
+ (*next_arg)= tmp;
+ }
+ else
+ {
+ tmp=new SEL_ARG(field,part, min_value,max_value,
+ min_flag, max_flag, maybe_flag);
+ tmp->parent=new_parent;
+ tmp->next_key_part=next_key_part;
+ if (left != &null_element)
+ tmp->left=left->clone(tmp,next_arg);
+
+ tmp->prev= *next_arg; // Link into next/prev chain
+ (*next_arg)->next=tmp;
+ (*next_arg)= tmp;
+
+ if (right != &null_element)
+ tmp->right=right->clone(tmp,next_arg);
+ }
+ increment_use_count(1);
+ return tmp;
+}
+
+SEL_ARG *SEL_ARG::first()
+{
+ SEL_ARG *next_arg=this;
+ if (!next_arg->left)
+ return 0; // MAYBE_KEY
+ while (next_arg->left != &null_element)
+ next_arg=next_arg->left;
+ return next_arg;
+}
+
+SEL_ARG *SEL_ARG::last()
+{
+ SEL_ARG *next_arg=this;
+ if (!next_arg->right)
+ return 0; // MAYBE_KEY
+ while (next_arg->right != &null_element)
+ next_arg=next_arg->right;
+ return next_arg;
+}
+
+/*
+ Check if a compare is ok, when one takes ranges in account
+ Returns -2 or 2 if the ranges where 'joined' like < 2 and >= 2
+ */
+
+static int sel_cmp(Field *field, char *a,char *b,uint8 a_flag,uint8 b_flag)
+{
+ int cmp;
+ /* First check if there was a compare to a min or max element */
+ if (a_flag & (NO_MIN_RANGE | NO_MAX_RANGE))
+ {
+ if ((a_flag & (NO_MIN_RANGE | NO_MAX_RANGE)) ==
+ (b_flag & (NO_MIN_RANGE | NO_MAX_RANGE)))
+ return 0;
+ return (a_flag & NO_MIN_RANGE) ? -1 : 1;
+ }
+ if (b_flag & (NO_MIN_RANGE | NO_MAX_RANGE))
+ return (b_flag & NO_MIN_RANGE) ? 1 : -1;
+
+ if (field->real_maybe_null()) // If null is part of key
+ {
+ if (*a != *b)
+ {
+ return *a ? -1 : 1;
+ }
+ if (*a)
+ goto end; // NULL where equal
+ a++; b++; // Skipp NULL marker
+ }
+ cmp=field->key_cmp((byte*) a,(byte*) b);
+ if (cmp) return cmp < 0 ? -1 : 1; // The values differed
+
+ // Check if the compared equal arguments was defined with open/closed range
+ end:
+ if (a_flag & (NEAR_MIN | NEAR_MAX))
+ {
+ if ((a_flag & (NEAR_MIN | NEAR_MAX)) == (b_flag & (NEAR_MIN | NEAR_MAX)))
+ return 0;
+ if (!(b_flag & (NEAR_MIN | NEAR_MAX)))
+ return (a_flag & NEAR_MIN) ? 2 : -2;
+ return (a_flag & NEAR_MIN) ? 1 : -1;
+ }
+ if (b_flag & (NEAR_MIN | NEAR_MAX))
+ return (b_flag & NEAR_MIN) ? -2 : 2;
+ return 0; // The elements where equal
+}
+
+
+SEL_ARG *SEL_ARG::clone_tree()
+{
+ SEL_ARG tmp_link,*next_arg,*root;
+ next_arg= &tmp_link;
+ root=clone((SEL_ARG *) 0, &next_arg);
+ next_arg->next=0; // Fix last link
+ tmp_link.next->prev=0; // Fix first link
+ root->use_count=0;
+ return root;
+}
+
+/*****************************************************************************
+** Test if a key can be used in different ranges
+** Returns:
+** -1 if impossible select
+** 0 if can't use quick_select
+** 1 if found usably range
+** Updates the following in the select parameter:
+** needed_reg ; Bits for keys with may be used if all prev regs are read
+** quick ; Parameter to use when reading records.
+** In the table struct the following information is updated:
+** quick_keys ; Which keys can be used
+** quick_rows ; How many rows the key matches
+*****************************************************************************/
+
+int SQL_SELECT::test_quick_select(key_map keys_to_use, table_map prev_tables,
+ ha_rows limit, bool force_quick_range)
+{
+ uint basflag;
+ uint idx;
+ double scan_time;
+ DBUG_ENTER("test_quick_select");
+
+ delete quick;
+ quick=0;
+ needed_reg=0; quick_keys=0;
+ if (!cond || (specialflag & SPECIAL_SAFE_MODE) && ! force_quick_range ||
+ !limit)
+ DBUG_RETURN(0); /* purecov: inspected */
+ if (!((basflag= head->file->option_flag()) & HA_KEYPOS_TO_RNDPOS) &&
+ keys_to_use == (uint) ~0 || !keys_to_use)
+ DBUG_RETURN(0); /* Not smart database */
+ records=head->file->records;
+ if (!records)
+ records++; /* purecov: inspected */
+ scan_time=(double) records / TIME_FOR_COMPARE+1;
+ read_time=(double) head->file->scan_time()+ scan_time + 1.0;
+ 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_PRINT("info",("Time to scan table: %ld",(long) read_time));
+
+ keys_to_use&=head->keys_in_use_for_query;
+ if (keys_to_use)
+ {
+ MEM_ROOT *old_root,alloc;
+ SEL_TREE *tree;
+ KEY_PART *key_parts;
+ PARAM param;
+
+ /* set up parameter that is passed to all functions */
+ param.baseflag=basflag;
+ param.prev_tables=prev_tables | const_tables;
+ param.read_tables=read_tables;
+ param.current_table= head->map;
+ param.table=head;
+ param.keys=0;
+
+ current_thd->no_errors=1; // Don't warn about NULL
+ init_sql_alloc(&alloc,2048);
+ if (!(param.key_parts = (KEY_PART*) alloc_root(&alloc,
+ sizeof(KEY_PART)*
+ head->key_parts)))
+ {
+ current_thd->no_errors=0;
+ free_root(&alloc); // Return memory & allocator
+ DBUG_RETURN(0); // Can't use range
+ }
+ key_parts= param.key_parts;
+ old_root=my_pthread_getspecific_ptr(MEM_ROOT*,THR_MALLOC);
+ my_pthread_setspecific_ptr(THR_MALLOC,&alloc);
+
+ for (idx=0 ; idx < head->keys ; idx++)
+ {
+ if (!(keys_to_use & ((key_map) 1L << idx)))
+ continue;
+ KEY *key_info= &head->key_info[idx];
+ if (key_info->flags & HA_FULLTEXT)
+ continue; // ToDo: ft-keys in non-ft ranges, if possible SerG
+
+ param.key[param.keys]=key_parts;
+ for (uint part=0 ; part < key_info->key_parts ; part++,key_parts++)
+ {
+ key_parts->key=param.keys;
+ key_parts->part=part;
+ key_parts->part_length= key_info->key_part[part].length;
+ key_parts->field= key_info->key_part[part].field;
+ key_parts->null_bit= key_info->key_part[part].null_bit;
+ if (key_parts->field->type() == FIELD_TYPE_BLOB)
+ key_parts->part_length+=HA_KEY_BLOB_LENGTH;
+ }
+ param.real_keynr[param.keys++]=idx;
+ }
+ param.key_parts_end=key_parts;
+
+ if ((tree=get_mm_tree(&param,cond)))
+ {
+ if (tree->type == SEL_TREE::IMPOSSIBLE)
+ {
+ records=0L; // Return -1 from this function
+ read_time= (double) HA_POS_ERROR;
+ }
+ else if (tree->type == SEL_TREE::KEY ||
+ tree->type == SEL_TREE::KEY_SMALLER)
+ {
+ SEL_ARG **key,**end,**best_key=0;
+
+ for (idx=0,key=tree->keys, end=key+param.keys ;
+ key != end ;
+ key++,idx++)
+ {
+ ha_rows found_records;
+ double found_read_time;
+
+ if (*key)
+ {
+ if ((*key)->type == SEL_ARG::MAYBE_KEY ||
+ (*key)->maybe_flag)
+ needed_reg|= (key_map) 1 << param.real_keynr[idx];
+
+ found_records=check_quick_select(&param,idx, *key);
+ if (found_records != HA_POS_ERROR && found_records > 2 &&
+ head->used_keys & ((table_map) 1 << param.real_keynr[idx]) &&
+ (head->file->option_flag() & HA_HAVE_KEY_READ_ONLY))
+ {
+ /*
+ ** We can resolve this by only reading through this key
+ ** Assume that we will read trough the whole key range
+ ** and that all key blocks are half full (normally things are
+ ** much better)
+ */
+ uint keys_per_block= head->file->block_size/2/head->key_info[param.real_keynr[idx]].key_length+1;
+ found_read_time=((double) (found_records+keys_per_block-1)/
+ (double) keys_per_block);
+ }
+ else
+ found_read_time= head->file->read_time(found_records)+
+ (double) found_records / TIME_FOR_COMPARE;
+ if (read_time > found_read_time)
+ {
+ read_time=found_read_time;
+ records=found_records;
+ best_key=key;
+ }
+ }
+ }
+ if (best_key && records)
+ {
+ if ((quick=get_quick_select(&param,(uint) (best_key-tree->keys),
+ *best_key)))
+ {
+ quick->records=records;
+ quick->read_time=read_time;
+ }
+ }
+ }
+ }
+ free_root(&alloc); // Return memory & allocator
+ my_pthread_setspecific_ptr(THR_MALLOC,old_root);
+ current_thd->no_errors=0;
+ }
+ DBUG_EXECUTE("info",print_quick(quick,needed_reg););
+ /*
+ Assume that if the user is using 'limit' we will only need to scan
+ limit rows if we are using a key
+ */
+ DBUG_RETURN(records ? test(quick) : -1);
+}
+
+ /* make a select tree of all keys in condition */
+
+static SEL_TREE *get_mm_tree(PARAM *param,COND *cond)
+{
+ SEL_TREE *tree=0;
+ DBUG_ENTER("get_mm_tree");
+
+ if (cond->type() == Item::COND_ITEM)
+ {
+ List_iterator<Item> li(*((Item_cond*) cond)->argument_list());
+
+ if (((Item_cond*) cond)->functype() == Item_func::COND_AND_FUNC)
+ {
+ tree=0;
+ Item *item;
+ while ((item=li++))
+ {
+ SEL_TREE *new_tree=get_mm_tree(param,item);
+ tree=tree_and(param,tree,new_tree);
+ if (tree && tree->type == SEL_TREE::IMPOSSIBLE)
+ break;
+ }
+ }
+ else
+ { // COND OR
+ tree=get_mm_tree(param,li++);
+ if (tree)
+ {
+ Item *item;
+ while ((item=li++))
+ {
+ SEL_TREE *new_tree=get_mm_tree(param,item);
+ if (!new_tree)
+ DBUG_RETURN(0);
+ tree=tree_or(param,tree,new_tree);
+ if (!tree || tree->type == SEL_TREE::ALWAYS)
+ break;
+ }
+ }
+ }
+ DBUG_RETURN(tree);
+ }
+ /* Here when simple cond */
+ if (cond->const_item())
+ {
+ if (cond->val_int())
+ DBUG_RETURN(new SEL_TREE(SEL_TREE::ALWAYS));
+ DBUG_RETURN(new SEL_TREE(SEL_TREE::IMPOSSIBLE));
+ }
+ table_map ref_tables=cond->used_tables();
+ if (ref_tables & ~(param->prev_tables | param->read_tables |
+ param->current_table))
+ DBUG_RETURN(0); // Can't be calculated yet
+ if (cond->type() != Item::FUNC_ITEM)
+ { // Should be a field
+ if (ref_tables & param->current_table)
+ DBUG_RETURN(0);
+ DBUG_RETURN(new SEL_TREE(SEL_TREE::MAYBE));
+ }
+ if (!(ref_tables & param->current_table))
+ DBUG_RETURN(new SEL_TREE(SEL_TREE::MAYBE)); // This may be false or true
+ Item_func *cond_func= (Item_func*) cond;
+ if (cond_func->select_optimize() == Item_func::OPTIMIZE_NONE)
+ DBUG_RETURN(0); // Can't be calculated
+
+ if (cond_func->functype() == Item_func::BETWEEN)
+ {
+ if (cond_func->arguments()[0]->type() == Item::FIELD_ITEM)
+ {
+ Field *field=((Item_field*) (cond_func->arguments()[0]))->field;
+ Item_result cmp_type=field->cmp_type();
+ tree= get_mm_parts(param,field,Item_func::GE_FUNC,
+ cond_func->arguments()[1],cmp_type);
+ DBUG_RETURN(tree_and(param,tree,
+ get_mm_parts(param, field,
+ Item_func::LE_FUNC,
+ cond_func->arguments()[2],cmp_type)));
+ }
+ DBUG_RETURN(0);
+ }
+ if (cond_func->functype() == Item_func::IN_FUNC)
+ { // COND OR
+ Item_func_in *func=(Item_func_in*) cond_func;
+ if (func->key_item()->type() == Item::FIELD_ITEM)
+ {
+ Field *field=((Item_field*) (func->key_item()))->field;
+ Item_result cmp_type=field->cmp_type();
+ tree= get_mm_parts(param,field,Item_func::EQ_FUNC,
+ func->arguments()[0],cmp_type);
+ if (!tree)
+ DBUG_RETURN(tree); // Not key field
+ for (uint i=1 ; i < func->argument_count(); i++)
+ {
+ SEL_TREE *new_tree=get_mm_parts(param,field,Item_func::EQ_FUNC,
+ func->arguments()[i],cmp_type);
+ tree=tree_or(param,tree,new_tree);
+ }
+ DBUG_RETURN(tree);
+ }
+ DBUG_RETURN(0); // Can't optimize this IN
+ }
+
+ /* check field op const */
+ /* btw, ft_func's arguments()[0] isn't FIELD_ITEM. SerG*/
+ if (cond_func->arguments()[0]->type() == Item::FIELD_ITEM)
+ {
+ tree= get_mm_parts(param,
+ ((Item_field*) (cond_func->arguments()[0]))->field,
+ cond_func->functype(),
+ cond_func->arg_count > 1 ? cond_func->arguments()[1] :
+ 0,
+ ((Item_field*) (cond_func->arguments()[0]))->field->
+ cmp_type());
+ }
+ /* check const op field */
+ if (!tree &&
+ cond_func->have_rev_func() &&
+ cond_func->arguments()[1]->type() == Item::FIELD_ITEM)
+ {
+ DBUG_RETURN(get_mm_parts(param,
+ ((Item_field*)
+ (cond_func->arguments()[1]))->field,
+ ((Item_bool_func2*) cond_func)->rev_functype(),
+ cond_func->arguments()[0],
+ ((Item_field*)
+ (cond_func->arguments()[1]))->field->cmp_type()
+ ));
+ }
+ DBUG_RETURN(tree);
+}
+
+
+static SEL_TREE *
+get_mm_parts(PARAM *param,Field *field, Item_func::Functype type,Item *value,
+ Item_result cmp_type)
+{
+ DBUG_ENTER("get_mm_parts");
+ if (field->table != param->table)
+ DBUG_RETURN(0);
+
+ KEY_PART *key_part = param->key_parts,*end=param->key_parts_end;
+ SEL_TREE *tree=0;
+ if (value &&
+ value->used_tables() & ~(param->prev_tables | param->read_tables))
+ DBUG_RETURN(0);
+ for ( ; key_part != end ; key_part++)
+ {
+ if (field->eq(key_part->field))
+ {
+ SEL_ARG *sel_arg=0;
+ if (!tree)
+ tree=new SEL_TREE();
+ if (!value || !(value->used_tables() & ~param->read_tables))
+ {
+ sel_arg=get_mm_leaf(key_part->field,key_part,type,value);
+ if (!sel_arg)
+ continue;
+ if (sel_arg->type == SEL_ARG::IMPOSSIBLE)
+ {
+ tree->type=SEL_TREE::IMPOSSIBLE;
+ DBUG_RETURN(tree);
+ }
+ }
+ else
+ sel_arg=new SEL_ARG(SEL_ARG::MAYBE_KEY);// This key may be used later
+ sel_arg->part=(uchar) key_part->part;
+ tree->keys[key_part->key]=sel_add(tree->keys[key_part->key],sel_arg);
+ }
+ }
+ DBUG_RETURN(tree);
+}
+
+
+static SEL_ARG *
+get_mm_leaf(Field *field,KEY_PART *key_part,
+ Item_func::Functype type,Item *value)
+{
+ uint maybe_null=(uint) field->real_maybe_null();
+ uint field_length=field->pack_length()+maybe_null;
+ SEL_ARG *tree;
+ DBUG_ENTER("get_mm_leaf");
+
+ if (type == Item_func::LIKE_FUNC)
+ {
+ bool like_error;
+ char buff1[MAX_FIELD_WIDTH],*min_str,*max_str;
+ String tmp(buff1,sizeof(buff1)),*res;
+ uint length,offset,min_length,max_length;
+
+ if (!(res= value->val_str(&tmp)))
+ DBUG_RETURN(&null_element);
+
+ // Check if this was a function. This should have be optimized away
+ // in the sql_select.cc
+ if (res != &tmp)
+ {
+ tmp.copy(*res); // Get own copy
+ res= &tmp;
+ }
+ if (field->cmp_type() != STRING_RESULT)
+ DBUG_RETURN(0); // Can only optimize strings
+
+ offset=maybe_null;
+ length=key_part->part_length;
+ if (field->type() == FIELD_TYPE_BLOB)
+ {
+ offset+=HA_KEY_BLOB_LENGTH;
+ field_length=key_part->part_length-HA_KEY_BLOB_LENGTH;
+ }
+ else
+ {
+ if (length < field_length)
+ length=field_length; // Only if overlapping key
+ else
+ field_length=length;
+ }
+ length+=offset;
+ if (!(min_str= (char*) sql_alloc(length*2)))
+ DBUG_RETURN(0);
+ max_str=min_str+length;
+ if (maybe_null)
+ max_str[0]= min_str[0]=0;
+ if (field->binary())
+ like_error=like_range(res->ptr(),res->length(),wild_prefix,field_length,
+ min_str+offset,max_str+offset,(char) 255,
+ &min_length,&max_length);
+ else
+ {
+#ifdef USE_STRCOLL
+ if (use_strcoll(default_charset_info))
+ like_error= my_like_range(default_charset_info,
+ res->ptr(),res->length(),wild_prefix,
+ field_length, min_str+maybe_null,
+ max_str+maybe_null,&min_length,&max_length);
+ else
+#endif
+ like_error=like_range(res->ptr(),res->length(),wild_prefix,field_length,
+ min_str+offset,max_str+offset,
+ max_sort_char,&min_length,&max_length);
+ }
+ if (like_error) // Can't optimize with LIKE
+ DBUG_RETURN(0);
+ if (offset != maybe_null) // Blob
+ {
+ int2store(min_str+maybe_null,min_length);
+ int2store(max_str+maybe_null,max_length);
+ }
+ DBUG_RETURN(new SEL_ARG(field,min_str,max_str));
+ }
+
+ if (!value) // IS NULL or IS NOT NULL
+ {
+ if (field->table->outer_join) // Can't use a key on this
+ DBUG_RETURN(0);
+ if (!maybe_null) // Not null field
+ DBUG_RETURN(type == Item_func::ISNULL_FUNC ? &null_element : 0);
+ tree=new SEL_ARG(field,is_null_string,is_null_string);
+ if (!tree)
+ DBUG_RETURN(0);
+ if (type == Item_func::ISNOTNULL_FUNC)
+ {
+ tree->min_flag=NEAR_MIN; /* IS NOT NULL -> X > NULL */
+ tree->max_flag=NO_MAX_RANGE;
+ }
+ DBUG_RETURN(tree);
+ }
+
+ if (!field->optimize_range() && type != Item_func::EQ_FUNC &&
+ type != Item_func::EQUAL_FUNC)
+ DBUG_RETURN(0); // Can't optimize this
+
+ /* 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 */
+ if (field->result_type() == STRING_RESULT &&
+ value->result_type() != STRING_RESULT &&
+ field->cmp_type() != value->result_type())
+ DBUG_RETURN(0);
+
+ if (value->save_in_field(field))
+ {
+ 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
+ if (!*str)
+ DBUG_RETURN(0);
+ *str = 1;
+ DBUG_RETURN(new SEL_ARG(field,str,str));
+ }
+ DBUG_RETURN(&null_element); // NULL is never true
+ }
+ // Get local copy of key
+ char *str= (char*) sql_alloc(key_part->part_length+maybe_null);
+ if (!str)
+ DBUG_RETURN(0);
+ if (maybe_null)
+ *str=0; // Not NULL
+ field->get_key_image(str+maybe_null,key_part->part_length);
+ if (!(tree=new SEL_ARG(field,str,str)))
+ DBUG_RETURN(0);
+
+ switch (type) {
+ case Item_func::LT_FUNC:
+ if (field_is_equal_to_item(field,value))
+ tree->max_flag=NEAR_MAX;
+ /* fall through */
+ case Item_func::LE_FUNC:
+ if (!maybe_null)
+ tree->min_flag=NO_MIN_RANGE; /* From start */
+ else
+ { // > NULL
+ tree->min_value=is_null_string;
+ tree->min_flag=NEAR_MIN;
+ }
+ break;
+ case Item_func::GT_FUNC:
+ if (field_is_equal_to_item(field,value))
+ tree->min_flag=NEAR_MIN;
+ /* fall through */
+ case Item_func::GE_FUNC:
+ tree->max_flag=NO_MAX_RANGE;
+ break;
+ default:
+ break;
+ }
+ DBUG_RETURN(tree);
+}
+
+
+/*
+** Calculate min_str and max_str that ranges a LIKE string.
+** Arguments:
+** ptr Pointer to LIKE string.
+** ptr_length Length of LIKE string.
+** escape Escape character in LIKE. (Normally '\').
+** All escape characters should be removed from min_str and max_str
+** res_length Length of min_str and max_str.
+** min_str Smallest case sensitive string that ranges LIKE.
+** Should be space padded to res_length.
+** max_str Largest case sensitive string that ranges LIKE.
+** Normally padded with the biggest character sort value.
+**
+** The function should return 0 if ok and 1 if the LIKE string can't be
+** optimized !
+*/
+
+static bool like_range(const char *ptr,uint ptr_length,char escape,
+ uint res_length, char *min_str,char *max_str,
+ char max_sort_chr, 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++; // Skipp escape
+ *min_str++= *max_str++ = *ptr;
+ continue;
+ }
+ if (*ptr == wild_one) // '_' in SQL
+ {
+ *min_str++='\0'; // This should be min char
+ *max_str++=max_sort_chr;
+ 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_chr;
+ } while (min_str != min_end);
+ return 0;
+ }
+ *min_str++= *max_str++ = *ptr;
+ }
+ *min_length= *max_length = (uint) (min_str - min_org);
+ while (min_str != min_end)
+ *min_str++ = *max_str++ = ' '; // Because if key compression
+ return 0;
+}
+
+
+/******************************************************************************
+** Tree manipulation functions
+** If tree is 0 it means that the condition can't be tested. It refers
+** to a non existent table or to a field in current table with isn't a key.
+** The different tree flags:
+** IMPOSSIBLE: Condition is never true
+** ALWAYS: Condition is always true
+** MAYBE: Condition may exists when tables are read
+** MAYBE_KEY: Condition refers to a key that may be used in join loop
+** KEY_RANGE: Condition uses a key
+******************************************************************************/
+
+/*
+** Add a new key test to a key when scanning through all keys
+** This will never be called for same key parts.
+*/
+
+static SEL_ARG *
+sel_add(SEL_ARG *key1,SEL_ARG *key2)
+{
+ SEL_ARG *root,**key_link;
+
+ if (!key1)
+ return key2;
+ if (!key2)
+ return key1;
+
+ key_link= &root;
+ while (key1 && key2)
+ {
+ if (key1->part < key2->part)
+ {
+ *key_link= key1;
+ key_link= &key1->next_key_part;
+ key1=key1->next_key_part;
+ }
+ else
+ {
+ *key_link= key2;
+ key_link= &key2->next_key_part;
+ key2=key2->next_key_part;
+ }
+ }
+ *key_link=key1 ? key1 : key2;
+ return root;
+}
+
+#define CLONE_KEY1_MAYBE 1
+#define CLONE_KEY2_MAYBE 2
+#define swap_clone_flag(A) ((A & 1) << 1) | ((A & 2) >> 1)
+
+
+static SEL_TREE *
+tree_and(PARAM *param,SEL_TREE *tree1,SEL_TREE *tree2)
+{
+ DBUG_ENTER("tree_and");
+ if (!tree1)
+ DBUG_RETURN(tree2);
+ if (!tree2)
+ DBUG_RETURN(tree1);
+ if (tree1->type == SEL_TREE::IMPOSSIBLE || tree2->type == SEL_TREE::ALWAYS)
+ DBUG_RETURN(tree1);
+ if (tree2->type == SEL_TREE::IMPOSSIBLE || tree1->type == SEL_TREE::ALWAYS)
+ DBUG_RETURN(tree2);
+ if (tree1->type == SEL_TREE::MAYBE)
+ {
+ if (tree2->type == SEL_TREE::KEY)
+ tree2->type=SEL_TREE::KEY_SMALLER;
+ DBUG_RETURN(tree2);
+ }
+ if (tree2->type == SEL_TREE::MAYBE)
+ {
+ tree1->type=SEL_TREE::KEY_SMALLER;
+ DBUG_RETURN(tree1);
+ }
+
+ /* Join the trees key per key */
+ SEL_ARG **key1,**key2,**end;
+ for (key1= tree1->keys,key2= tree2->keys,end=key1+param->keys ;
+ key1 != end ; key1++,key2++)
+ {
+ uint flag=0;
+ if (*key1 || *key2)
+ {
+ if (*key1 && !(*key1)->simple_key())
+ flag|=CLONE_KEY1_MAYBE;
+ if (*key2 && !(*key2)->simple_key())
+ flag|=CLONE_KEY2_MAYBE;
+ *key1=key_and(*key1,*key2,flag);
+ if ((*key1)->type == SEL_ARG::IMPOSSIBLE)
+ {
+ tree1->type= SEL_TREE::IMPOSSIBLE;
+ break;
+ }
+#ifdef EXTRA_DEBUG
+ (*key1)->test_use_count(*key1);
+#endif
+ }
+ }
+ DBUG_RETURN(tree1);
+}
+
+
+
+static SEL_TREE *
+tree_or(PARAM *param,SEL_TREE *tree1,SEL_TREE *tree2)
+{
+ DBUG_ENTER("tree_or");
+ if (!tree1 || !tree2)
+ DBUG_RETURN(0);
+ if (tree1->type == SEL_TREE::IMPOSSIBLE || tree2->type == SEL_TREE::ALWAYS)
+ DBUG_RETURN(tree2);
+ if (tree2->type == SEL_TREE::IMPOSSIBLE || tree1->type == SEL_TREE::ALWAYS)
+ DBUG_RETURN(tree1);
+ if (tree1->type == SEL_TREE::MAYBE)
+ DBUG_RETURN(tree1); // Can't use this
+ if (tree2->type == SEL_TREE::MAYBE)
+ DBUG_RETURN(tree2);
+
+ /* Join the trees key per key */
+ SEL_ARG **key1,**key2,**end;
+ SEL_TREE *result=0;
+ for (key1= tree1->keys,key2= tree2->keys,end=key1+param->keys ;
+ key1 != end ; key1++,key2++)
+ {
+ *key1=key_or(*key1,*key2);
+ if (*key1)
+ {
+ result=tree1; // Added to tree1
+#ifdef EXTRA_DEBUG
+ (*key1)->test_use_count(*key1);
+#endif
+ }
+ }
+ DBUG_RETURN(result);
+}
+
+
+/* And key trees where key1->part < key2 -> part */
+
+static SEL_ARG *
+and_all_keys(SEL_ARG *key1,SEL_ARG *key2,uint clone_flag)
+{
+ SEL_ARG *next;
+ ulong use_count=key1->use_count;
+
+ if (key1->elements != 1)
+ {
+ key2->use_count+=key1->elements-1;
+ key2->increment_use_count((int) key1->elements-1);
+ }
+ if (key1->type == SEL_ARG::MAYBE_KEY)
+ {
+ key1->left= &null_element; key1->next=0;
+ }
+ for (next=key1->first(); next ; next=next->next)
+ {
+ if (next->next_key_part)
+ {
+ SEL_ARG *tmp=key_and(next->next_key_part,key2,clone_flag);
+ if (tmp && tmp->type == SEL_ARG::IMPOSSIBLE)
+ {
+ key1=key1->tree_delete(next);
+ continue;
+ }
+ next->next_key_part=tmp;
+ if (use_count)
+ next->increment_use_count(use_count);
+ }
+ else
+ next->next_key_part=key2;
+ }
+ if (!key1)
+ return &null_element; // Impossible ranges
+ key1->use_count++;
+ return key1;
+}
+
+
+
+static SEL_ARG *
+key_and(SEL_ARG *key1,SEL_ARG *key2,uint clone_flag)
+{
+ if (!key1)
+ return key2;
+ if (!key2)
+ return key1;
+ if (key1->part != key2->part)
+ {
+ if (key1->part > key2->part)
+ {
+ swap(SEL_ARG *,key1,key2);
+ clone_flag=swap_clone_flag(clone_flag);
+ }
+ // key1->part < key2->part
+ key1->use_count--;
+ if (key1->use_count > 0)
+ key1=key1->clone_tree();
+ return and_all_keys(key1,key2,clone_flag);
+ }
+
+ if (((clone_flag & CLONE_KEY2_MAYBE) &&
+ !(clone_flag & CLONE_KEY1_MAYBE)) ||
+ key1->type == SEL_ARG::MAYBE_KEY)
+ { // Put simple key in key2
+ swap(SEL_ARG *,key1,key2);
+ clone_flag=swap_clone_flag(clone_flag);
+ }
+
+ // If one of the key is MAYBE_KEY then the found region may be smaller
+ if (key2->type == SEL_ARG::MAYBE_KEY)
+ {
+ if (key1->use_count > 1)
+ {
+ key1->use_count--;
+ key1=key1->clone_tree();
+ key1->use_count++;
+ }
+ if (key1->type == SEL_ARG::MAYBE_KEY)
+ { // Both are maybe key
+ key1->next_key_part=key_and(key1->next_key_part,key2->next_key_part,
+ clone_flag);
+ if (key1->next_key_part &&
+ key1->next_key_part->type == SEL_ARG::IMPOSSIBLE)
+ return key1;
+ }
+ else
+ {
+ key1->maybe_smaller();
+ if (key2->next_key_part)
+ return and_all_keys(key1,key2,clone_flag);
+ key2->use_count--; // Key2 doesn't have a tree
+ }
+ return key1;
+ }
+
+ key1->use_count--;
+ key2->use_count--;
+ SEL_ARG *e1=key1->first(), *e2=key2->first(), *new_tree=0;
+
+ while (e1 && e2)
+ {
+ int cmp=e1->cmp_min_to_min(e2);
+ if (cmp < 0)
+ {
+ if (get_range(&e1,&e2,key1))
+ continue;
+ }
+ else if (get_range(&e2,&e1,key2))
+ continue;
+ SEL_ARG *next=key_and(e1->next_key_part,e2->next_key_part,clone_flag);
+ e1->increment_use_count(1);
+ e2->increment_use_count(1);
+ if (!next || next->type != SEL_ARG::IMPOSSIBLE)
+ {
+ SEL_ARG *new_arg= e1->clone_and(e2);
+ new_arg->next_key_part=next;
+ if (!new_tree)
+ {
+ new_tree=new_arg;
+ }
+ else
+ new_tree=new_tree->insert(new_arg);
+ }
+ if (e1->cmp_max_to_max(e2) < 0)
+ e1=e1->next; // e1 can't overlapp next e2
+ else
+ e2=e2->next;
+ }
+ key1->free_tree();
+ key2->free_tree();
+ if (!new_tree)
+ return &null_element; // Impossible range
+ return new_tree;
+}
+
+
+static bool
+get_range(SEL_ARG **e1,SEL_ARG **e2,SEL_ARG *root1)
+{
+ (*e1)=root1->find_range(*e2); // first e1->min < e2->min
+ if ((*e1)->cmp_max_to_min(*e2) < 0)
+ {
+ if (!((*e1)=(*e1)->next))
+ return 1;
+ if ((*e1)->cmp_min_to_max(*e2) > 0)
+ {
+ (*e2)=(*e2)->next;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+
+static SEL_ARG *
+key_or(SEL_ARG *key1,SEL_ARG *key2)
+{
+ if (!key1)
+ {
+ if (key2)
+ {
+ key2->use_count--;
+ key2->free_tree();
+ }
+ return 0;
+ }
+ else if (!key2)
+ {
+ key1->use_count--;
+ key1->free_tree();
+ return 0;
+ }
+ key1->use_count--;
+ key2->use_count--;
+
+ if (key1->part != key2->part)
+ {
+ key1->free_tree();
+ key2->free_tree();
+ return 0; // Can't optimize this
+ }
+
+ // If one of the key is MAYBE_KEY then the found region may be bigger
+ if (key1->type == SEL_ARG::MAYBE_KEY)
+ {
+ key2->free_tree();
+ key1->use_count++;
+ return key1;
+ }
+ if (key2->type == SEL_ARG::MAYBE_KEY)
+ {
+ key1->free_tree();
+ key2->use_count++;
+ return key2;
+ }
+
+ if (key1->use_count > 0)
+ {
+ if (key2->use_count == 0 || key1->elements > key2->elements)
+ {
+ swap(SEL_ARG *,key1,key2);
+ }
+ else
+ key1=key1->clone_tree();
+ }
+
+ // Add tree at key2 to tree at key1
+ bool key2_shared=key2->use_count != 0;
+ key1->maybe_flag|=key2->maybe_flag;
+
+ for (key2=key2->first(); key2; )
+ {
+ SEL_ARG *tmp=key1->find_range(key2); // Find key1.min <= key2.min
+ int cmp;
+
+ if (!tmp)
+ {
+ tmp=key1->first(); // tmp.min > key2.min
+ cmp= -1;
+ }
+ else if ((cmp=tmp->cmp_max_to_min(key2)) < 0)
+ { // Found tmp.max < key2.min
+ SEL_ARG *next=tmp->next;
+ if (cmp == -2 && eq_tree(tmp->next_key_part,key2->next_key_part))
+ {
+ // Join near ranges like tmp.max < 0 and key2.min >= 0
+ SEL_ARG *key2_next=key2->next;
+ if (key2_shared)
+ {
+ key2=new SEL_ARG(*key2);
+ key2->increment_use_count(key1->use_count+1);
+ key2->next=key2_next; // New copy of key2
+ }
+ key2->copy_min(tmp);
+ if (!(key1=key1->tree_delete(tmp)))
+ { // Only one key in tree
+ key1=key2;
+ key1->make_root();
+ key2=key2_next;
+ break;
+ }
+ }
+ if (!(tmp=next)) // tmp.min > key2.min
+ break; // Copy rest of key2
+ }
+ if (cmp < 0)
+ { // tmp.min > key2.min
+ int tmp_cmp;
+ if ((tmp_cmp=tmp->cmp_min_to_max(key2)) > 0) // if tmp.min > key2.max
+ {
+ if (tmp_cmp == 2 && eq_tree(tmp->next_key_part,key2->next_key_part))
+ { // ranges are connected
+ tmp->copy_min_to_min(key2);
+ key1->merge_flags(key2);
+ if (tmp->min_flag & NO_MIN_RANGE &&
+ tmp->max_flag & NO_MAX_RANGE)
+ {
+ if (key1->maybe_flag)
+ return new SEL_ARG(SEL_ARG::MAYBE_KEY);
+ return 0;
+ }
+ key2->increment_use_count(-1); // Free not used tree
+ key2=key2->next;
+ continue;
+ }
+ else
+ {
+ SEL_ARG *next=key2->next; // Keys are not overlapping
+ if (key2_shared)
+ {
+ key1=key1->insert(new SEL_ARG(*key2)); // Must make copy
+ key2->increment_use_count(key1->use_count+1);
+ }
+ else
+ key1=key1->insert(key2); // Will destroy key2_root
+ key2=next;
+ continue;
+ }
+ }
+ }
+
+ // tmp.max >= key2.min && tmp.min <= key.max (overlapping ranges)
+ if (eq_tree(tmp->next_key_part,key2->next_key_part))
+ {
+ if (tmp->is_same(key2))
+ {
+ tmp->merge_flags(key2); // Copy maybe flags
+ key2->increment_use_count(-1); // Free not used tree
+ }
+ else
+ {
+ SEL_ARG *last=tmp;
+ while (last->next && last->next->cmp_min_to_max(key2) <= 0 &&
+ eq_tree(last->next->next_key_part,key2->next_key_part))
+ {
+ SEL_ARG *save=last;
+ last=last->next;
+ key1=key1->tree_delete(save);
+ }
+ if (last->copy_min(key2) || last->copy_max(key2))
+ { // Full range
+ key1->free_tree();
+ for (; key2 ; key2=key2->next)
+ key2->increment_use_count(-1); // Free not used tree
+ if (key1->maybe_flag)
+ return new SEL_ARG(SEL_ARG::MAYBE_KEY);
+ return 0;
+ }
+ }
+ key2=key2->next;
+ continue;
+ }
+
+ if (cmp >= 0 && tmp->cmp_min_to_min(key2) < 0)
+ { // tmp.min <= x < key2.min
+ SEL_ARG *new_arg=tmp->clone_first(key2);
+ if ((new_arg->next_key_part= key1->next_key_part))
+ new_arg->increment_use_count(key1->use_count+1);
+ tmp->copy_min_to_min(key2);
+ key1=key1->insert(new_arg);
+ }
+
+ // tmp.min >= key2.min && tmp.min <= key2.max
+ SEL_ARG key(*key2); // Get copy we can modify
+ for (;;)
+ {
+ if (tmp->cmp_min_to_min(&key) > 0)
+ { // key.min <= x < tmp.min
+ SEL_ARG *new_arg=key.clone_first(tmp);
+ if ((new_arg->next_key_part=key.next_key_part))
+ new_arg->increment_use_count(key1->use_count+1);
+ key1=key1->insert(new_arg);
+ }
+ if ((cmp=tmp->cmp_max_to_max(&key)) <= 0)
+ { // tmp.min. <= x <= tmp.max
+ tmp->maybe_flag|= key.maybe_flag;
+ key.increment_use_count(key1->use_count+1);
+ tmp->next_key_part=key_or(tmp->next_key_part,key.next_key_part);
+ if (!cmp) // Key2 is ready
+ break;
+ key.copy_max_to_min(tmp);
+ if (!(tmp=tmp->next))
+ {
+ key1=key1->insert(new SEL_ARG(key));
+ key2=key2->next;
+ goto end;
+ }
+ if (tmp->cmp_min_to_max(&key) > 0)
+ {
+ key1=key1->insert(new SEL_ARG(key));
+ break;
+ }
+ }
+ else
+ {
+ SEL_ARG *new_arg=tmp->clone_last(&key); // tmp.min <= x <= key.max
+ tmp->copy_max_to_min(&key);
+ tmp->increment_use_count(key1->use_count+1);
+ new_arg->next_key_part=key_or(tmp->next_key_part,key.next_key_part);
+ key1=key1->insert(new_arg);
+ break;
+ }
+ }
+ key2=key2->next;
+ }
+
+end:
+ while (key2)
+ {
+ SEL_ARG *next=key2->next;
+ if (key2_shared)
+ {
+ key2->increment_use_count(key1->use_count+1);
+ key1=key1->insert(new SEL_ARG(*key2)); // Must make copy
+ }
+ else
+ key1=key1->insert(key2); // Will destroy key2_root
+ key2=next;
+ }
+ key1->use_count++;
+ return key1;
+}
+
+
+/* Compare if two trees are equal */
+
+static bool eq_tree(SEL_ARG* a,SEL_ARG *b)
+{
+ if (a == b)
+ return 1;
+ if (!a || !b || !a->is_same(b))
+ return 0;
+ if (a->left != &null_element && b->left != &null_element)
+ {
+ if (!eq_tree(a->left,b->left))
+ return 0;
+ }
+ else if (a->left != &null_element || b->left != &null_element)
+ return 0;
+ if (a->right != &null_element && b->right != &null_element)
+ {
+ if (!eq_tree(a->right,b->right))
+ return 0;
+ }
+ else if (a->right != &null_element || b->right != &null_element)
+ return 0;
+ if (a->next_key_part != b->next_key_part)
+ { // Sub range
+ if (!a->next_key_part != !b->next_key_part ||
+ !eq_tree(a->next_key_part, b->next_key_part))
+ return 0;
+ }
+ return 1;
+}
+
+
+SEL_ARG *
+SEL_ARG::insert(SEL_ARG *key)
+{
+ SEL_ARG *element,**par,*last_element;
+
+ LINT_INIT(par); LINT_INIT(last_element);
+ for (element= this; element != &null_element ; )
+ {
+ last_element=element;
+ if (key->cmp_min_to_min(element) > 0)
+ {
+ par= &element->right; element= element->right;
+ }
+ else
+ {
+ par = &element->left; element= element->left;
+ }
+ }
+ *par=key;
+ key->parent=last_element;
+ /* Link in list */
+ if (par == &last_element->left)
+ {
+ key->next=last_element;
+ if ((key->prev=last_element->prev))
+ key->prev->next=key;
+ last_element->prev=key;
+ }
+ else
+ {
+ if ((key->next=last_element->next))
+ key->next->prev=key;
+ key->prev=last_element;
+ last_element->next=key;
+ }
+ key->left=key->right= &null_element;
+ SEL_ARG *root=rb_insert(key); // rebalance tree
+ root->use_count=this->use_count; // copy root info
+ root->elements= this->elements+1;
+ root->maybe_flag=this->maybe_flag;
+ return root;
+}
+
+
+/*
+** Find best key with min <= given key
+** Because the call context this should never return 0 to get_range
+*/
+
+SEL_ARG *
+SEL_ARG::find_range(SEL_ARG *key)
+{
+ SEL_ARG *element=this,*found=0;
+
+ for (;;)
+ {
+ if (element == &null_element)
+ return found;
+ int cmp=element->cmp_min_to_min(key);
+ if (cmp == 0)
+ return element;
+ if (cmp < 0)
+ {
+ found=element;
+ element=element->right;
+ }
+ else
+ element=element->left;
+ }
+}
+
+
+/*
+** Remove a element from the tree
+** This also frees all sub trees that is used by the element
+*/
+
+SEL_ARG *
+SEL_ARG::tree_delete(SEL_ARG *key)
+{
+ enum leaf_color remove_color;
+ SEL_ARG *root,*nod,**par,*fix_par;
+ root=this; this->parent= 0;
+
+ /* Unlink from list */
+ if (key->prev)
+ key->prev->next=key->next;
+ if (key->next)
+ key->next->prev=key->prev;
+ key->increment_use_count(-1);
+ if (!key->parent)
+ par= &root;
+ else
+ par=key->parent_ptr();
+
+ if (key->left == &null_element)
+ {
+ *par=nod=key->right;
+ fix_par=key->parent;
+ if (nod != &null_element)
+ nod->parent=fix_par;
+ remove_color= key->color;
+ }
+ else if (key->right == &null_element)
+ {
+ *par= nod=key->left;
+ nod->parent=fix_par=key->parent;
+ remove_color= key->color;
+ }
+ else
+ {
+ SEL_ARG *tmp=key->next; // next bigger key (exist!)
+ nod= *tmp->parent_ptr()= tmp->right; // unlink tmp from tree
+ fix_par=tmp->parent;
+ if (nod != &null_element)
+ nod->parent=fix_par;
+ remove_color= tmp->color;
+
+ tmp->parent=key->parent; // Move node in place of key
+ (tmp->left=key->left)->parent=tmp;
+ if ((tmp->right=key->right) != &null_element)
+ tmp->right->parent=tmp;
+ tmp->color=key->color;
+ *par=tmp;
+ if (fix_par == key) // key->right == key->next
+ fix_par=tmp; // new parent of nod
+ }
+
+ if (root == &null_element)
+ return 0; // Maybe root later
+ if (remove_color == BLACK)
+ root=rb_delete_fixup(root,nod,fix_par);
+ test_rb_tree(root,root->parent);
+
+ root->use_count=this->use_count; // Fix root counters
+ root->elements=this->elements-1;
+ root->maybe_flag=this->maybe_flag;
+ return root;
+}
+
+
+ /* Functions to fix up the tree after insert and delete */
+
+static void left_rotate(SEL_ARG **root,SEL_ARG *leaf)
+{
+ SEL_ARG *y=leaf->right;
+ leaf->right=y->left;
+ if (y->left != &null_element)
+ y->left->parent=leaf;
+ if (!(y->parent=leaf->parent))
+ *root=y;
+ else
+ *leaf->parent_ptr()=y;
+ y->left=leaf;
+ leaf->parent=y;
+}
+
+static void right_rotate(SEL_ARG **root,SEL_ARG *leaf)
+{
+ SEL_ARG *y=leaf->left;
+ leaf->left=y->right;
+ if (y->right != &null_element)
+ y->right->parent=leaf;
+ if (!(y->parent=leaf->parent))
+ *root=y;
+ else
+ *leaf->parent_ptr()=y;
+ y->right=leaf;
+ leaf->parent=y;
+}
+
+
+SEL_ARG *
+SEL_ARG::rb_insert(SEL_ARG *leaf)
+{
+ SEL_ARG *y,*par,*par2,*root;
+ root= this; root->parent= 0;
+
+ leaf->color=RED;
+ while (leaf != root && (par= leaf->parent)->color == RED)
+ { // This can't be root or 1 level under
+ if (par == (par2= leaf->parent->parent)->left)
+ {
+ y= par2->right;
+ if (y->color == RED)
+ {
+ par->color=BLACK;
+ y->color=BLACK;
+ leaf=par2;
+ leaf->color=RED; /* And the loop continues */
+ }
+ else
+ {
+ if (leaf == par->right)
+ {
+ left_rotate(&root,leaf->parent);
+ par=leaf; /* leaf is now parent to old leaf */
+ }
+ par->color=BLACK;
+ par2->color=RED;
+ right_rotate(&root,par2);
+ break;
+ }
+ }
+ else
+ {
+ y= par2->left;
+ if (y->color == RED)
+ {
+ par->color=BLACK;
+ y->color=BLACK;
+ leaf=par2;
+ leaf->color=RED; /* And the loop continues */
+ }
+ else
+ {
+ if (leaf == par->left)
+ {
+ right_rotate(&root,par);
+ par=leaf;
+ }
+ par->color=BLACK;
+ par2->color=RED;
+ left_rotate(&root,par2);
+ break;
+ }
+ }
+ }
+ root->color=BLACK;
+ test_rb_tree(root,root->parent);
+ return root;
+}
+
+
+SEL_ARG *rb_delete_fixup(SEL_ARG *root,SEL_ARG *key,SEL_ARG *par)
+{
+ SEL_ARG *x,*w;
+ root->parent=0;
+
+ x= key;
+ while (x != root && x->color == SEL_ARG::BLACK)
+ {
+ if (x == par->left)
+ {
+ w=par->right;
+ if (w->color == SEL_ARG::RED)
+ {
+ w->color=SEL_ARG::BLACK;
+ par->color=SEL_ARG::RED;
+ left_rotate(&root,par);
+ w=par->right;
+ }
+ if (w->left->color == SEL_ARG::BLACK && w->right->color == SEL_ARG::BLACK)
+ {
+ w->color=SEL_ARG::RED;
+ x=par;
+ }
+ else
+ {
+ if (w->right->color == SEL_ARG::BLACK)
+ {
+ w->left->color=SEL_ARG::BLACK;
+ w->color=SEL_ARG::RED;
+ right_rotate(&root,w);
+ w=par->right;
+ }
+ w->color=par->color;
+ par->color=SEL_ARG::BLACK;
+ w->right->color=SEL_ARG::BLACK;
+ left_rotate(&root,par);
+ x=root;
+ break;
+ }
+ }
+ else
+ {
+ w=par->left;
+ if (w->color == SEL_ARG::RED)
+ {
+ w->color=SEL_ARG::BLACK;
+ par->color=SEL_ARG::RED;
+ right_rotate(&root,par);
+ w=par->left;
+ }
+ if (w->right->color == SEL_ARG::BLACK && w->left->color == SEL_ARG::BLACK)
+ {
+ w->color=SEL_ARG::RED;
+ x=par;
+ }
+ else
+ {
+ if (w->left->color == SEL_ARG::BLACK)
+ {
+ w->right->color=SEL_ARG::BLACK;
+ w->color=SEL_ARG::RED;
+ left_rotate(&root,w);
+ w=par->left;
+ }
+ w->color=par->color;
+ par->color=SEL_ARG::BLACK;
+ w->left->color=SEL_ARG::BLACK;
+ right_rotate(&root,par);
+ x=root;
+ break;
+ }
+ }
+ par=x->parent;
+ }
+ x->color=SEL_ARG::BLACK;
+ return root;
+}
+
+
+ /* Test that the proporties for a red-black tree holds */
+
+#ifdef EXTRA_DEBUG
+int test_rb_tree(SEL_ARG *element,SEL_ARG *parent)
+{
+ int count_l,count_r;
+
+ if (element == &null_element)
+ return 0; // Found end of tree
+ if (element->parent != parent)
+ {
+ sql_print_error("Wrong tree: Parent doesn't point at parent");
+ return -1;
+ }
+ if (element->color == SEL_ARG::RED &&
+ (element->left->color == SEL_ARG::RED ||
+ element->right->color == SEL_ARG::RED))
+ {
+ sql_print_error("Wrong tree: Found two red in a row");
+ return -1;
+ }
+ if (element->left == element->right && element->left != &null_element)
+ { // Dummy test
+ sql_print_error("Wrong tree: Found right == left");
+ return -1;
+ }
+ count_l=test_rb_tree(element->left,element);
+ count_r=test_rb_tree(element->right,element);
+ if (count_l >= 0 && count_r >= 0)
+ {
+ if (count_l == count_r)
+ return count_l+(element->color == SEL_ARG::BLACK);
+ sql_print_error("Wrong tree: Incorrect black-count: %d - %d",
+ count_l,count_r);
+ }
+ return -1; // Error, no more warnings
+}
+
+static ulong count_key_part_usage(SEL_ARG *root, SEL_ARG *key)
+{
+ ulong count= 0;
+ for (root=root->first(); root ; root=root->next)
+ {
+ if (root->next_key_part)
+ {
+ if (root->next_key_part == key)
+ count++;
+ if (root->next_key_part->part < key->part)
+ count+=count_key_part_usage(root->next_key_part,key);
+ }
+ }
+ return count;
+}
+
+
+void SEL_ARG::test_use_count(SEL_ARG *root)
+{
+ if (this == root && use_count != 1)
+ {
+ sql_print_error("Use_count: Wrong count %lu for root",use_count);
+ return;
+ }
+ if (this->type != SEL_ARG::KEY_RANGE)
+ return;
+ uint e_count=0;
+ for (SEL_ARG *pos=first(); pos ; pos=pos->next)
+ {
+ e_count++;
+ if (pos->next_key_part)
+ {
+ ulong count=count_key_part_usage(root,pos->next_key_part);
+ if (count > pos->next_key_part->use_count)
+ {
+ sql_print_error("Use_count: Wrong count for key at %lx, %lu should be %lu",
+ pos,pos->next_key_part->use_count,count);
+ return;
+ }
+ pos->next_key_part->test_use_count(root);
+ }
+ }
+ if (e_count != elements)
+ sql_print_error("Wrong use count: %u for tree at %lx", e_count,
+ (gptr) this);
+}
+
+#endif
+
+
+
+/*****************************************************************************
+** Check how many records we will find by using the found tree
+*****************************************************************************/
+
+static ha_rows
+check_quick_select(PARAM *param,uint idx,SEL_ARG *tree)
+{
+ ha_rows records;
+ DBUG_ENTER("check_quick_select");
+
+ if (!tree)
+ DBUG_RETURN(HA_POS_ERROR); // Can't use it
+ if (tree->type == SEL_ARG::IMPOSSIBLE)
+ DBUG_RETURN(0L); // Impossible select. return
+ if (tree->type != SEL_ARG::KEY_RANGE || tree->part != 0)
+ DBUG_RETURN(HA_POS_ERROR); // Don't use tree
+ param->max_key_part=0;
+ records=check_quick_keys(param,idx,tree,param->min_key,0,param->max_key,0);
+ if (records != HA_POS_ERROR)
+ {
+ uint key=param->real_keynr[idx];
+ param->table->quick_keys|= (key_map) 1 << key;
+ param->table->quick_rows[key]=records;
+ param->table->quick_key_parts[key]=param->max_key_part+1;
+ }
+ DBUG_RETURN(records);
+}
+
+
+static ha_rows
+check_quick_keys(PARAM *param,uint idx,SEL_ARG *key_tree,
+ char *min_key,uint min_key_flag, char *max_key,
+ uint max_key_flag)
+{
+ ha_rows records=0,tmp;
+
+ param->max_key_part=max(param->max_key_part,key_tree->part);
+ if (key_tree->left != &null_element)
+ {
+ records=check_quick_keys(param,idx,key_tree->left,min_key,min_key_flag,
+ max_key,max_key_flag);
+ if (records == HA_POS_ERROR) // Impossible
+ return records;
+ }
+
+ uint tmp_min_flag,tmp_max_flag,keynr;
+ char *tmp_min_key=min_key,*tmp_max_key=max_key;
+
+ key_tree->store(param->key[idx][key_tree->part].part_length,
+ &tmp_min_key,min_key_flag,&tmp_max_key,max_key_flag);
+ uint min_key_length= (uint) (tmp_min_key- param->min_key);
+ uint max_key_length= (uint) (tmp_max_key- param->max_key);
+
+ if (key_tree->next_key_part &&
+ key_tree->next_key_part->part == key_tree->part+1 &&
+ key_tree->next_key_part->type == SEL_ARG::KEY_RANGE)
+ { // const key as prefix
+ if (min_key_length == max_key_length &&
+ !memcmp(min_key,max_key, (uint) (tmp_max_key - max_key)) &&
+ !key_tree->min_flag && !key_tree->max_flag)
+ {
+ tmp=check_quick_keys(param,idx,key_tree->next_key_part,
+ tmp_min_key, min_key_flag | key_tree->min_flag,
+ tmp_max_key, max_key_flag | key_tree->max_flag);
+ goto end; // Ugly, but efficient
+ }
+ tmp_min_flag=key_tree->min_flag;
+ tmp_max_flag=key_tree->max_flag;
+ if (!tmp_min_flag)
+ key_tree->next_key_part->store_min_key(param->key[idx], &tmp_min_key,
+ &tmp_min_flag);
+ if (!tmp_max_flag)
+ key_tree->next_key_part->store_max_key(param->key[idx], &tmp_max_key,
+ &tmp_max_flag);
+ min_key_length= (uint) (tmp_min_key- param->min_key);
+ max_key_length= (uint) (tmp_max_key- param->max_key);
+ }
+ else
+ {
+ tmp_min_flag=min_key_flag | key_tree->min_flag;
+ tmp_max_flag=max_key_flag | key_tree->max_flag;
+ }
+
+ keynr=param->real_keynr[idx];
+ if (!tmp_min_flag && ! tmp_max_flag &&
+ (uint) key_tree->part+1 == param->table->key_info[keynr].key_parts &&
+ (param->table->key_info[keynr].flags & HA_NOSAME) &&
+ min_key_length == max_key_length &&
+ !memcmp(param->min_key,param->max_key,min_key_length))
+ tmp=1; // Max one record
+ else
+ tmp=param->table->file->
+ records_in_range((int) keynr,
+ (byte*) (!min_key_length ? NullS :
+ param->min_key),
+ min_key_length,
+ (tmp_min_flag & NEAR_MIN ?
+ HA_READ_AFTER_KEY : HA_READ_KEY_EXACT),
+ (byte*) (!max_key_length ? NullS :
+ param->max_key),
+ max_key_length,
+ (tmp_max_flag & NEAR_MAX ?
+ HA_READ_BEFORE_KEY : HA_READ_AFTER_KEY));
+ end:
+ if (tmp == HA_POS_ERROR) // Impossible range
+ return tmp;
+ records+=tmp;
+ if (key_tree->right != &null_element)
+ {
+ tmp=check_quick_keys(param,idx,key_tree->right,min_key,min_key_flag,
+ max_key,max_key_flag);
+ if (tmp == HA_POS_ERROR)
+ return tmp;
+ records+=tmp;
+ }
+ return records;
+}
+
+
+/****************************************************************************
+** change a tree to a structure to be used by quick_select
+** This uses it's own malloc tree
+****************************************************************************/
+
+static QUICK_SELECT *
+get_quick_select(PARAM *param,uint idx,SEL_ARG *key_tree)
+{
+ QUICK_SELECT *quick;
+ DBUG_ENTER("get_quick_select");
+ if ((quick=new QUICK_SELECT(param->table,param->real_keynr[idx])))
+ {
+ if (quick->error ||
+ get_quick_keys(param,quick,param->key[idx],key_tree,param->min_key,0,
+ param->max_key,0))
+ {
+ delete quick;
+ quick=0;
+ }
+ else
+ {
+ quick->key_parts=(KEY_PART*)
+ sql_memdup(param->key[idx],
+ sizeof(KEY_PART)*
+ param->table->key_info[param->real_keynr[idx]].key_parts);
+ }
+ }
+ DBUG_RETURN(quick);
+}
+
+
+/*
+** Fix this to get all possible sub_ranges
+*/
+
+static bool
+get_quick_keys(PARAM *param,QUICK_SELECT *quick,KEY_PART *key,
+ SEL_ARG *key_tree,char *min_key,uint min_key_flag,
+ char *max_key, uint max_key_flag)
+{
+ QUICK_RANGE *range;
+ uint flag;
+
+ if (key_tree->left != &null_element)
+ {
+ if (get_quick_keys(param,quick,key,key_tree->left,
+ min_key,min_key_flag, max_key, max_key_flag))
+ return 1;
+ }
+ char *tmp_min_key=min_key,*tmp_max_key=max_key;
+ key_tree->store(key[key_tree->part].part_length,
+ &tmp_min_key,min_key_flag,&tmp_max_key,max_key_flag);
+
+ if (key_tree->next_key_part &&
+ key_tree->next_key_part->part == key_tree->part+1 &&
+ key_tree->next_key_part->type == SEL_ARG::KEY_RANGE)
+ { // const key as prefix
+ if (!((tmp_min_key - min_key) != (tmp_max_key - max_key) ||
+ memcmp(min_key,max_key, (uint) (tmp_max_key - max_key)) ||
+ key_tree->min_flag || key_tree->max_flag))
+ {
+ if (get_quick_keys(param,quick,key,key_tree->next_key_part,
+ tmp_min_key, min_key_flag | key_tree->min_flag,
+ tmp_max_key, max_key_flag | key_tree->max_flag))
+ return 1;
+ goto end; // Ugly, but efficient
+ }
+ {
+ uint tmp_min_flag=key_tree->min_flag,tmp_max_flag=key_tree->max_flag;
+ if (!tmp_min_flag)
+ key_tree->next_key_part->store_min_key(key, &tmp_min_key,
+ &tmp_min_flag);
+ if (!tmp_max_flag)
+ key_tree->next_key_part->store_max_key(key, &tmp_max_key,
+ &tmp_max_flag);
+ flag=tmp_min_flag | tmp_max_flag;
+ }
+ }
+ else
+ flag=key_tree->min_flag | key_tree->max_flag;
+
+ /* Ensure that some part of min_key and max_key are used. If not,
+ regard this as no lower/upper range */
+ if (tmp_min_key != param->min_key)
+ flag&= ~NO_MIN_RANGE;
+ else
+ flag|= NO_MIN_RANGE;
+ if (tmp_max_key != param->max_key)
+ flag&= ~NO_MAX_RANGE;
+ else
+ flag|= NO_MAX_RANGE;
+
+ if (flag == 0)
+ {
+ uint length= (uint) (tmp_min_key - param->min_key);
+ if (length == (uint) (tmp_max_key - param->max_key) &&
+ !memcmp(param->min_key,param->max_key,length))
+ {
+ KEY *table_key=quick->head->key_info+quick->index;
+ flag=EQ_RANGE;
+ if (table_key->flags & HA_NOSAME && key->part == table_key->key_parts-1)
+ flag|= UNIQUE_RANGE;
+ }
+ }
+
+ /* Get range for retrieving rows in QUICK_SELECT::get_next */
+ range= new QUICK_RANGE(param->min_key,
+ (uint) (tmp_min_key - param->min_key),
+ param->max_key,
+ (uint) (tmp_max_key - param->max_key),
+ flag);
+ set_if_bigger(quick->max_used_key_length,range->min_length);
+ set_if_bigger(quick->max_used_key_length,range->max_length);
+ if (!range) // Not enough memory
+ return 1;
+ quick->ranges.push_back(range);
+
+ end:
+ if (key_tree->right != &null_element)
+ return get_quick_keys(param,quick,key,key_tree->right,
+ min_key,min_key_flag,
+ max_key,max_key_flag);
+ return 0;
+}
+
+/*
+ Return 1 if there is only one range and this uses the whole primary key
+*/
+
+bool QUICK_SELECT::unique_key_range()
+{
+ if (ranges.elements == 1)
+ {
+ QUICK_RANGE *tmp;
+ if ((tmp=ranges.head())->flag & EQ_RANGE)
+ {
+ KEY *key=head->key_info+index;
+ return ((key->flags & HA_NOSAME) &&
+ key->key_length == tmp->min_length);
+ }
+ }
+ return 0;
+}
+
+/****************************************************************************
+** Create a QUICK RANGE based on a key
+****************************************************************************/
+
+QUICK_SELECT *get_quick_select_for_ref(TABLE *table, TABLE_REF *ref)
+{
+ QUICK_SELECT *quick=new QUICK_SELECT(table, ref->key, 1);
+ KEY *key_info = &table->key_info[ref->key];
+ KEY_PART *key_part;
+ uint part;
+
+ if (!quick)
+ return 0;
+ QUICK_RANGE *range= new QUICK_RANGE();
+ if (!range || cp_buffer_from_ref(ref))
+ goto err;
+ range->min_key=range->max_key=(char*) ref->key_buff;
+ range->min_length=range->max_length=ref->key_length;
+ range->flag= ((ref->key_length == key_info->key_length &&
+ (key_info->flags & HA_NOSAME)) ? EQ_RANGE : 0);
+
+ if (!(quick->key_parts=key_part=(KEY_PART *)
+ sql_alloc(sizeof(KEY_PART)*ref->key_parts)))
+ goto err;
+
+ for (part=0 ; part < ref->key_parts ;part++,key_part++)
+ {
+ key_part->part=part;
+ key_part->field= key_info->key_part[part].field;
+ key_part->part_length= key_info->key_part[part].length;
+ if (key_part->field->type() == FIELD_TYPE_BLOB)
+ key_part->part_length+=HA_KEY_BLOB_LENGTH;
+ key_part->null_bit= key_info->key_part[part].null_bit;
+ }
+ if (!quick->ranges.push_back(range))
+ return quick;
+
+err:
+ delete quick;
+ return 0;
+}
+
+ /* get next possible record using quick-struct */
+
+int QUICK_SELECT::get_next()
+{
+ DBUG_ENTER("get_next");
+
+ for (;;)
+ {
+ if (range)
+ { // Already read through key
+ int result=((range->flag & EQ_RANGE) ?
+ file->index_next_same(record, (byte*) range->min_key,
+ range->min_length) :
+ file->index_next(record));
+ if (!result && !cmp_next(*it.ref()))
+ DBUG_RETURN(0);
+ }
+ if (!(range=it++))
+ DBUG_RETURN(HA_ERR_END_OF_FILE); // All ranges used
+ if (range->flag & NO_MIN_RANGE) // Read first record
+ {
+ int error;
+ 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
+ continue;
+ }
+ if (file->index_read(record,(byte*) range->min_key,
+ range->min_length,
+ ((range->flag & NEAR_MIN) ?
+ HA_READ_AFTER_KEY:
+ (range->flag & EQ_RANGE) ?
+ HA_READ_KEY_EXACT :
+ HA_READ_KEY_OR_NEXT)))
+
+ {
+ range=0; // Not found, to next range
+ continue;
+ }
+ if (cmp_next(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
+ }
+}
+
+ /* compare if found key is over max-value */
+ /* Returns 0 if key <= range->max_key */
+
+int QUICK_SELECT::cmp_next(QUICK_RANGE *range)
+{
+ if (range->flag & NO_MAX_RANGE)
+ return (0); /* key can't be to large */
+
+ KEY_PART *key_part=key_parts;
+ for (char *key=range->max_key, *end=key+range->max_length;
+ key < end;
+ key+= key_part++->part_length)
+ {
+ int cmp;
+ if (key_part->null_bit)
+ {
+ if (*key++)
+ {
+ if (!key_part->field->is_null())
+ return 1;
+ continue;
+ }
+ else if (key_part->field->is_null())
+ return 0;
+ }
+ 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_MAX) ? 1 : 0; // Exact match
+}
+
+/*****************************************************************************
+** Print a quick range for debugging
+** TODO:
+** This should be changed to use a String to store each row instead
+** of locking the DEBUG stream !
+*****************************************************************************/
+
+#ifndef DBUG_OFF
+
+static void
+print_key(KEY_PART *key_part,const char *key,uint used_length)
+{
+ char buff[1024];
+ String tmp(buff,sizeof(buff));
+
+ for (uint length=0;
+ length < used_length ;
+ length+=key_part->part_length, key+=key_part->part_length, key_part++)
+ {
+ Field *field=key_part->field;
+ if (length != 0)
+ fputc('/',DBUG_FILE);
+ if (field->real_maybe_null())
+ {
+ length++;
+ if (*key++)
+ {
+ fwrite("NULL",sizeof(char),4,DBUG_FILE);
+ continue;
+ }
+ }
+ field->set_key_image((char*) key,key_part->part_length);
+ field->val_str(&tmp,&tmp);
+ fwrite(tmp.ptr(),sizeof(char),tmp.length(),DBUG_FILE);
+ }
+}
+
+static void print_quick(QUICK_SELECT *quick,key_map needed_reg)
+{
+ QUICK_RANGE *range;
+ DBUG_ENTER("print_param");
+ if (! _db_on_ || !quick)
+ DBUG_VOID_RETURN;
+
+ List_iterator<QUICK_RANGE> li(quick->ranges);
+ DBUG_LOCK_FILE;
+ fprintf(DBUG_FILE,"Used quick_range on key: %d (other_keys: %lu):\n",
+ quick->index, (ulong) needed_reg);
+ while ((range=li++))
+ {
+ if (!(range->flag & NO_MIN_RANGE))
+ {
+ print_key(quick->key_parts,range->min_key,range->min_length);
+ if (range->flag & NEAR_MIN)
+ fputs(" < ",DBUG_FILE);
+ else
+ fputs(" <= ",DBUG_FILE);
+ }
+ fputs("X",DBUG_FILE);
+
+ if (!(range->flag & NO_MAX_RANGE))
+ {
+ if (range->flag & NEAR_MAX)
+ fputs(" < ",DBUG_FILE);
+ else
+ fputs(" <= ",DBUG_FILE);
+ print_key(quick->key_parts,range->max_key,range->max_length);
+ }
+ fputs("\n",DBUG_FILE);
+ }
+ DBUG_UNLOCK_FILE;
+ DBUG_VOID_RETURN;
+}
+
+#endif
+
+/*****************************************************************************
+** Instansiate templates
+*****************************************************************************/
+
+#ifdef __GNUC__
+template class List<QUICK_RANGE>;
+template class List_iterator<QUICK_RANGE>;
+#endif
diff --git a/sql/opt_range.h b/sql/opt_range.h
new file mode 100644
index 00000000000..06775874494
--- /dev/null
+++ b/sql/opt_range.h
@@ -0,0 +1,106 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+
+/* classes to use when handling where clause */
+
+#ifndef _opt_range_h
+#define _opt_range_h
+
+#ifdef __GNUC__
+#pragma interface /* gcc class implementation */
+#endif
+
+#define NO_MIN_RANGE 1
+#define NO_MAX_RANGE 2
+#define NEAR_MIN 4
+#define NEAR_MAX 8
+#define UNIQUE_RANGE 16
+#define EQ_RANGE 32
+
+typedef struct st_key_part {
+ uint16 key,part,part_length;
+ uint8 null_bit;
+ Field *field;
+} KEY_PART;
+
+class QUICK_RANGE :public Sql_alloc {
+ public:
+ char *min_key,*max_key;
+ uint16 min_length,max_length,flag;
+ QUICK_RANGE(); /* Full range */
+ QUICK_RANGE(const char *min_key_arg,uint min_length_arg,
+ const char *max_key_arg,uint max_length_arg,
+ 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)
+ {}
+};
+
+class QUICK_SELECT {
+public:
+ bool next;
+ int error;
+ uint index,max_used_key_length;
+ TABLE *head;
+ handler *file;
+ byte *record;
+ List<QUICK_RANGE> ranges;
+ List_iterator<QUICK_RANGE> it;
+ QUICK_RANGE *range;
+ MEM_ROOT alloc;
+
+ KEY_PART *key_parts;
+ ha_rows records;
+ double read_time;
+
+ QUICK_SELECT(TABLE *table,uint index_arg,bool no_alloc=0);
+ ~QUICK_SELECT();
+ void reset(void) { next=0; it.rewind(); }
+ int get_next();
+ int cmp_next(QUICK_RANGE *range);
+ bool unique_key_range();
+};
+
+
+class SQL_SELECT :public Sql_alloc {
+ public:
+ QUICK_SELECT *quick; // If quick-select used
+ COND *cond; // where condition
+ TABLE *head;
+ IO_CACHE file; // Positions to used records
+ ha_rows records; // Records in use if read from file
+ double read_time; // Time to read rows
+ key_map quick_keys; // Possible quick keys
+ key_map needed_reg; // Possible quick keys after prev tables.
+ table_map const_tables,read_tables;
+ bool free_cond;
+
+ SQL_SELECT();
+ ~SQL_SELECT();
+ bool check_quick(bool force_quick_range=0, ha_rows limit = HA_POS_ERROR)
+ { return test_quick_select(~0L,0,limit, force_quick_range) < 0; }
+ inline bool skipp_record() { return cond ? cond->val_int() == 0 : 0; }
+ int test_quick_select(key_map keys,table_map prev_tables,ha_rows limit,
+ bool force_quick_range=0);
+};
+
+QUICK_SELECT *get_quick_select_for_ref(TABLE *table, struct st_table_ref *ref);
+
+#endif
diff --git a/sql/opt_sum.cc b/sql/opt_sum.cc
new file mode 100644
index 00000000000..beac829bb74
--- /dev/null
+++ b/sql/opt_sum.cc
@@ -0,0 +1,359 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+
+/* Optimizing of many different type of queries with GROUP functions */
+
+#include "mysql_priv.h"
+#include "sql_select.h"
+
+static bool find_range_key(TABLE_REF *ref, Field* field,COND *cond);
+
+/*****************************************************************************
+** This function is only called for queries with sum functions and no
+** GROUP BY part.
+** This substitutes constants for some COUNT(), MIN() and MAX() functions.
+** The function returns 1 if all items was resolved and -1 on impossible
+** conditions
+****************************************************************************/
+
+int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds)
+{
+ List_iterator<Item> it(all_fields);
+ int const_result=1;
+ bool recalc_const_item=0;
+ table_map removed_tables=0;
+ Item *item;
+
+ while ((item= it++))
+ {
+ if (item->type() == Item::SUM_FUNC_ITEM)
+ {
+ Item_sum *item_sum= (((Item_sum*) item));
+ switch (item_sum->sum_func()) {
+ case Item_sum::COUNT_FUNC:
+ /*
+ If the expr in count(expr) can never be null we can change this
+ to the number of rows in the tables
+ */
+ if (!conds && !((Item_sum_count*) item)->args[0]->maybe_null)
+ {
+ longlong count=1;
+ TABLE_LIST *table;
+ for (table=tables; table ; table=table->next)
+ {
+ if (table->on_expr || (table->table->file->option_flag() &
+ HA_NOT_EXACT_COUNT))
+ {
+ const_result=0; // Can't optimize left join
+ break;
+ }
+ tables->table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
+ count*= table->table->file->records;
+ }
+ if (!table)
+ {
+ ((Item_sum_count*) item)->make_const(count);
+ recalc_const_item=1;
+ }
+ }
+ else
+ const_result=0;
+ break;
+ case Item_sum::MIN_FUNC:
+ {
+ /*
+ If MIN(expr) is the first part of a key or if all previous
+ parts of the key is found in the COND, then we can use
+ indexes to find the key.
+ */
+ Item *expr=item_sum->args[0];
+ if (expr->type() == Item::FIELD_ITEM)
+ {
+ byte key_buff[MAX_KEY_LENGTH];
+ TABLE_REF ref;
+ ref.key_buff=key_buff;
+
+ if (!find_range_key(&ref, ((Item_field*) expr)->field,conds))
+ {
+ const_result=0;
+ break;
+ }
+ TABLE *table=((Item_field*) expr)->field->table;
+ bool error=table->file->index_init((uint) ref.key);
+ if (!ref.key_length)
+ error=table->file->index_first(table->record[0]) !=0;
+ else
+ error=table->file->index_read(table->record[0],key_buff,
+ ref.key_length,
+ HA_READ_KEY_OR_NEXT) ||
+ key_cmp(table, key_buff, ref.key, ref.key_length);
+ if (table->key_read)
+ {
+ table->key_read=0;
+ table->file->extra(HA_EXTRA_NO_KEYREAD);
+ }
+ table->file->index_end();
+ if (error)
+ return -1; // Impossible query
+ removed_tables|= table->map;
+ }
+ else if (!expr->const_item()) // This is VERY seldom false
+ {
+ const_result=0;
+ break;
+ }
+ ((Item_sum_min*) item_sum)->reset();
+ ((Item_sum_min*) item_sum)->make_const();
+ recalc_const_item=1;
+ break;
+ }
+ case Item_sum::MAX_FUNC:
+ {
+ /*
+ If MAX(expr) is the first part of a key or if all previous
+ parts of the key is found in the COND, then we can use
+ indexes to find the key.
+ */
+ Item *expr=item_sum->args[0];
+ if (expr->type() == Item::FIELD_ITEM)
+ {
+ byte key_buff[MAX_KEY_LENGTH];
+ TABLE_REF ref;
+ ref.key_buff=key_buff;
+
+ if (!find_range_key(&ref, ((Item_field*) expr)->field,conds))
+ {
+ const_result=0;
+ break;
+ }
+ TABLE *table=((Item_field*) expr)->field->table;
+ bool error=table->file->index_init((uint) ref.key);
+
+ if (!ref.key_length)
+ error=table->file->index_last(table->record[0]) !=0;
+ else
+ {
+ (void) table->file->index_read(table->record[0], key_buff,
+ ref.key_length,
+ HA_READ_AFTER_KEY);
+ error=table->file->index_prev(table->record[0]) ||
+ key_cmp(table,key_buff,ref.key,ref.key_length);
+ }
+ if (table->key_read)
+ {
+ table->key_read=0;
+ table->file->extra(HA_EXTRA_NO_KEYREAD);
+ }
+ table->file->index_end();
+ if (error)
+ return -1; // Impossible query
+ removed_tables|= table->map;
+ }
+ else if (!expr->const_item()) // This is VERY seldom false
+ {
+ const_result=0;
+ break;
+ }
+ ((Item_sum_min*) item_sum)->reset();
+ ((Item_sum_min*) item_sum)->make_const();
+ recalc_const_item=1;
+ break;
+ }
+ default:
+ const_result=0;
+ break;
+ }
+ }
+ else if (const_result)
+ {
+ if (recalc_const_item)
+ item->update_used_tables();
+ if (!item->const_item())
+ const_result=0;
+ }
+ }
+ if (conds && (conds->used_tables() & ~ removed_tables))
+ const_result=0;
+ return const_result;
+}
+
+/* Count in how many times table is used (up to MAX_KEY_PARTS+1) */
+
+uint count_table_entries(COND *cond,TABLE *table)
+{
+ if (cond->type() == Item::COND_ITEM)
+ {
+ 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());
+ Item *item;
+ uint count=0;
+ while ((item=li++))
+ {
+ if ((count+=count_table_entries(item,table)) > MAX_REF_PARTS)
+ return MAX_REF_PARTS+1;
+ }
+ return count;
+ }
+ if (cond->type() == Item::FUNC_ITEM &&
+ (((Item_func*) cond)->functype() == Item_func::EQ_FUNC ||
+ (((Item_func*) cond)->functype() == Item_func::EQUAL_FUNC)) &&
+ cond->used_tables() == table->map)
+ {
+ Item *left_item= ((Item_func*) cond)->arguments()[0];
+ Item *right_item= ((Item_func*) cond)->arguments()[1];
+ if (left_item->type() == Item::FIELD_ITEM)
+ {
+ if (!(((Item_field*) left_item)->field->flags & PART_KEY_FLAG) ||
+ !right_item->const_item())
+ return MAX_REF_PARTS+1;
+ return 1;
+ }
+ if (right_item->type() == Item::FIELD_ITEM)
+ {
+ if (!(((Item_field*) right_item)->field->flags & PART_KEY_FLAG) ||
+ !left_item->const_item())
+ return MAX_REF_PARTS+1;
+ return 1;
+ }
+ }
+ return (cond->used_tables() & table->map) ? MAX_REF_PARTS+1 : 0;
+}
+
+
+/* check that the field is usable as key part */
+
+bool part_of_cond(COND *cond,Field *field)
+{
+ if (cond->type() == Item::COND_ITEM)
+ {
+ if (((Item_cond*) cond)->functype() == Item_func::COND_OR_FUNC)
+ return 0; // Already checked
+
+ List_iterator<Item> li(*((Item_cond*) cond)->argument_list());
+ Item *item;
+ while ((item=li++))
+ {
+ if (part_of_cond(item,field))
+ return 1;
+ }
+ return 0;
+ }
+ if (cond->type() == Item::FUNC_ITEM &&
+ (((Item_func*) cond)->functype() == Item_func::EQ_FUNC ||
+ ((Item_func*) cond)->functype() == Item_func::EQUAL_FUNC) &&
+ cond->used_tables() == field->table->map)
+ {
+ Item *left_item= ((Item_func*) cond)->arguments()[0];
+ Item *right_item= ((Item_func*) cond)->arguments()[1];
+ if (left_item->type() == Item::FIELD_ITEM)
+ {
+ if (((Item_field*) left_item)->field != field ||
+ !right_item->const_item())
+ return 0;
+ }
+ else if (right_item->type() == Item::FIELD_ITEM)
+ {
+ if (((Item_field*) right_item)->field != field ||
+ !left_item->const_item())
+ return 0;
+ right_item=left_item; // const item in right
+ }
+ store_val_in_field(field,right_item);
+ return 1;
+ }
+ return 0;
+}
+
+
+/* Check if we can get value for field by using a key */
+
+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
+
+ TABLE *table=field->table;
+ if (table->file->option_flag() & HA_WRONG_ASCII_ORDER)
+ return(0); // Can't use key to find last row
+ uint idx=0;
+
+ /* Check if some key has field as first key part */
+ if (field->key_start && (! 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))
+ {
+ table->key_read=1;
+ table->file->extra(HA_EXTRA_KEYREAD);
+ }
+ return 1; // Ok to use key
+ }
+ /*
+ ** Check if WHERE consist of exactly the previous key parts for some key
+ */
+ if (!cond)
+ return 0;
+ uint table_entries= count_table_entries(cond,table);
+ if (!table_entries || table_entries > MAX_REF_PARTS)
+ return 0;
+
+ KEY *keyinfo,*keyinfo_end;
+ for (keyinfo=table->key_info, keyinfo_end=keyinfo+table->keys ;
+ keyinfo != keyinfo_end;
+ keyinfo++,idx++)
+ {
+ if (table_entries < keyinfo->key_parts)
+ {
+ byte *key_ptr=ref->key_buff;
+ KEY_PART_INFO *part,*part_end;
+ int left_length=MAX_KEY_LENGTH;
+
+ for (part=keyinfo->key_part, part_end=part+table_entries ;
+ part != part_end ;
+ part++)
+ {
+ if (!part_of_cond(cond,part->field))
+ break;
+ // Save found constant
+ if (part->null_bit)
+ *key_ptr++= (byte) test(part->field->is_null());
+ if (left_length - part->length < 0)
+ break; // Can't use this key
+ part->field->get_image((char*) key_ptr,part->length);
+ key_ptr+=part->length;
+ left_length-=part->length;
+ }
+ if (part == part_end && part->field == field)
+ {
+ ref->key_length= (uint) (key_ptr-ref->key_buff);
+ ref->key=idx;
+ if (field->part_of_key & ((table_map) 1 << idx))
+ {
+ table->key_read=1;
+ table->file->extra(HA_EXTRA_KEYREAD);
+ }
+ return 1; // Ok to use key
+ }
+ }
+ }
+ return 0; // No possible key
+}
diff --git a/sql/password.c b/sql/password.c
new file mode 100644
index 00000000000..63ab9def651
--- /dev/null
+++ b/sql/password.c
@@ -0,0 +1,191 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 */
+/*****************************************************************************
+ The main idea is that no password are sent between client & server on
+ connection and that no password are saved in mysql in a decodable form.
+
+ On connection a random string is generated and sent to the client.
+ The client generates a new string with a random generator inited with
+ the hash values from the password and the sent string.
+ This 'check' string is sent to the server where it is compared with
+ a string generated from the stored hash_value of the password and the
+ random string.
+
+ The password is saved (in user.password) by using the PASSWORD() function in
+ mysql.
+
+ Example:
+ update user set password=PASSWORD("hello") where user="test"
+ This saves a hashed number as a string in the password field.
+*****************************************************************************/
+
+#include <global.h>
+#include <my_sys.h>
+#include <m_string.h>
+#include "mysql.h"
+
+
+void randominit(struct rand_struct *rand_st,ulong seed1, ulong seed2)
+{ /* For mysql 3.21.# */
+#ifdef HAVE_purify
+ bzero((char*) rand_st,sizeof(*rand_st)); /* Avoid UMC varnings */
+#endif
+ rand_st->max_value= 0x3FFFFFFFL;
+ rand_st->max_value_dbl=(double) rand_st->max_value;
+ rand_st->seed1=seed1%rand_st->max_value ;
+ rand_st->seed2=seed2%rand_st->max_value;
+}
+
+static void old_randominit(struct rand_struct *rand_st,ulong seed1)
+{ /* For mysql 3.20.# */
+ rand_st->max_value= 0x01FFFFFFL;
+ rand_st->max_value_dbl=(double) rand_st->max_value;
+ seed1%=rand_st->max_value;
+ rand_st->seed1=seed1 ; rand_st->seed2=seed1/2;
+}
+
+double rnd(struct rand_struct *rand_st)
+{
+ rand_st->seed1=(rand_st->seed1*3+rand_st->seed2) % rand_st->max_value;
+ rand_st->seed2=(rand_st->seed1+rand_st->seed2+33) % rand_st->max_value;
+ return (((double) rand_st->seed1)/rand_st->max_value_dbl);
+}
+
+void hash_password(ulong *result, const char *password)
+{
+ register ulong nr=1345345333L, add=7, nr2=0x12345671L;
+ ulong tmp;
+ for (; *password ; password++)
+ {
+ if (*password == ' ' || *password == '\t')
+ continue; /* skipp space in password */
+ tmp= (ulong) (uchar) *password;
+ nr^= (((nr & 63)+add)*tmp)+ (nr << 8);
+ nr2+=(nr2 << 8) ^ nr;
+ add+=tmp;
+ }
+ result[0]=nr & (((ulong) 1L << 31) -1L); /* Don't use sign bit (str2int) */;
+ result[1]=nr2 & (((ulong) 1L << 31) -1L);
+ return;
+}
+
+void make_scrambled_password(char *to,const char *password)
+{
+ ulong hash_res[2];
+ hash_password(hash_res,password);
+ sprintf(to,"%08lx%08lx",hash_res[0],hash_res[1]);
+}
+
+static inline uint char_val(char X)
+{
+ return (uint) (X >= '0' && X <= '9' ? X-'0' :
+ X >= 'A' && X <= 'Z' ? X-'A'+10 :
+ X-'a'+10);
+}
+
+/*
+** This code assumes that len(password) is divideable with 8 and that
+** res is big enough (2 in mysql)
+*/
+
+void get_salt_from_password(ulong *res,const char *password)
+{
+ res[0]=res[1]=0;
+ if (password)
+ {
+ while (*password)
+ {
+ ulong val=0;
+ uint i;
+ for (i=0 ; i < 8 ; i++)
+ val=(val << 4)+char_val(*password++);
+ *res++=val;
+ }
+ }
+ return;
+}
+
+void make_password_from_salt(char *to, ulong *hash_res)
+{
+ sprintf(to,"%08lx%08lx",hash_res[0],hash_res[1]);
+}
+
+
+/*
+ * Genererate a new message based on message and password
+ * The same thing is done in client and server and the results are checked.
+ */
+
+char *scramble(char *to,const char *message,const char *password,
+ my_bool old_ver)
+{
+ struct rand_struct rand_st;
+ ulong hash_pass[2],hash_message[2];
+ if (password && password[0])
+ {
+ char *to_start=to;
+ hash_password(hash_pass,password);
+ hash_password(hash_message,message);
+ if (old_ver)
+ old_randominit(&rand_st,hash_pass[0] ^ hash_message[0]);
+ else
+ randominit(&rand_st,hash_pass[0] ^ hash_message[0],
+ hash_pass[1] ^ hash_message[1]);
+ while (*message++)
+ *to++= (char) (floor(rnd(&rand_st)*31)+64);
+ if (!old_ver)
+ { /* Make it harder to break */
+ char extra=(char) (floor(rnd(&rand_st)*31));
+ while (to_start != to)
+ *(to_start++)^=extra;
+ }
+ }
+ *to=0;
+ return to;
+}
+
+
+my_bool check_scramble(const char *scrambled, const char *message,
+ ulong *hash_pass, my_bool old_ver)
+{
+ struct rand_struct rand_st;
+ ulong hash_message[2];
+ char buff[16],*to,extra; /* Big enough for check */
+ const char *pos;
+
+ hash_password(hash_message,message);
+ if (old_ver)
+ old_randominit(&rand_st,hash_pass[0] ^ hash_message[0]);
+ else
+ randominit(&rand_st,hash_pass[0] ^ hash_message[0],
+ hash_pass[1] ^ hash_message[1]);
+ to=buff;
+ for (pos=scrambled ; *pos ; pos++)
+ *to++=(char) (floor(rnd(&rand_st)*31)+64);
+ if (old_ver)
+ extra=0;
+ else
+ extra=(char) (floor(rnd(&rand_st)*31));
+ to=buff;
+ while (*scrambled)
+ {
+ if (*scrambled++ != (char) (*to++ ^ extra))
+ return 1; /* Wrong password */
+ }
+ return 0;
+}
diff --git a/sql/procedure.cc b/sql/procedure.cc
new file mode 100644
index 00000000000..526bbe0feab
--- /dev/null
+++ b/sql/procedure.cc
@@ -0,0 +1,71 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+
+/* Procedures (functions with changes output of select) */
+
+#ifdef __GNUC__
+#pragma implementation // gcc: Class implementation
+#endif
+
+#include "mysql_priv.h"
+#include "procedure.h"
+#include "sql_analyse.h" // Includes procedure
+#ifdef USE_PROC_RANGE
+#include "proc_range.h"
+#endif
+
+static struct st_procedure_def {
+ const char *name;
+ Procedure *(*init)(THD *thd,ORDER *param,select_result *result,
+ List<Item> &field_list);
+} sql_procs[] = {
+#ifdef USE_PROC_RANGE
+ { "split_sum",proc_sum_range_init }, // Internal procedure at TCX
+ { "split_count",proc_count_range_init }, // Internal procedure at TCX
+ { "matris_ranges",proc_matris_range_init }, // Internal procedure at TCX
+#endif
+ { "analyse",proc_analyse_init } // Analyse a result
+};
+
+/*****************************************************************************
+** Setup handling of procedure
+** Return 0 if everything is ok
+*****************************************************************************/
+
+Procedure *
+setup_procedure(THD *thd,ORDER *param,select_result *result,
+ List<Item> &field_list,int *error)
+{
+ uint i;
+ DBUG_ENTER("setup_procedure");
+ *error=0;
+ if (!param)
+ DBUG_RETURN(0);
+ for (i=0 ; i < array_elements(sql_procs) ; i++)
+ {
+ if (!my_strcasecmp((*param->item)->name,sql_procs[i].name))
+ {
+ Procedure *proc=(*sql_procs[i].init)(thd,param,result,field_list);
+ *error= !proc;
+ DBUG_RETURN(proc);
+ }
+ }
+ my_printf_error(ER_UNKNOWN_PROCEDURE,ER(ER_UNKNOWN_PROCEDURE),MYF(0),
+ (*param->item)->name);
+ *error=1;
+ DBUG_RETURN(0);
+}
diff --git a/sql/procedure.h b/sql/procedure.h
new file mode 100644
index 00000000000..7632bf7347c
--- /dev/null
+++ b/sql/procedure.h
@@ -0,0 +1,124 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+
+/* When using sql procedures */
+
+#ifdef __GNUC__
+#pragma interface /* gcc class implementation */
+#endif
+
+#define PROC_NO_SORT 1 /* Bits in flags */
+#define PROC_GROUP 2 /* proc must have group */
+
+/* Procedure items used by procedures to store values for send_fields */
+
+class Item_proc :public Item
+{
+public:
+ Item_proc(const char *name_par): Item()
+ {
+ this->name=(char*) name_par;
+ }
+ enum Type type() const { return Item::PROC_ITEM; }
+ virtual void set(double nr)=0;
+ virtual void set(const char *str,uint length)=0;
+ virtual void set(longlong nr)=0;
+ virtual enum_field_types field_type() const=0;
+ void set(const char *str) { set(str,strlen(str)); }
+ void make_field(Send_field *tmp_field)
+ {
+ init_make_field(tmp_field,field_type());
+ }
+};
+
+class Item_proc_real :public Item_proc
+{
+ double value;
+public:
+ Item_proc_real(const char *name_par,uint dec) : Item_proc(name_par)
+ {
+ decimals=dec; max_length=float_length(dec);
+ }
+ enum Item_result result_type () const { return REAL_RESULT; }
+ enum_field_types field_type() const { return FIELD_TYPE_DOUBLE; }
+ void set(double nr) { value=nr; }
+ void set(longlong nr) { value=(double) nr; }
+ void set(const char *str,uint length __attribute__((unused)))
+ { value=atof(str); }
+ double val() { return value; }
+ longlong val_int() { return (longlong) value; }
+ String *val_str(String *s) { s->set(value,decimals); return s; }
+};
+
+class Item_proc_int :public Item_proc
+{
+ longlong value;
+public:
+ Item_proc_int(const char *name_par) :Item_proc(name_par)
+ { max_length=11; }
+ enum Item_result result_type () const { return INT_RESULT; }
+ enum_field_types field_type() const { return FIELD_TYPE_LONG; }
+ void set(double nr) { value=(longlong) nr; }
+ void set(longlong nr) { value=nr; }
+ void set(const char *str,uint length __attribute__((unused)))
+ { value=strtoll(str,NULL,10); }
+ double val() { return (double) value; }
+ longlong val_int() { return value; }
+ String *val_str(String *s) { s->set(value); return s; }
+};
+
+
+class Item_proc_string :public Item_proc
+{
+public:
+ Item_proc_string(const char *name_par,uint length) :Item_proc(name_par)
+ { this->max_length=length; }
+ enum Item_result result_type () const { return STRING_RESULT; }
+ enum_field_types field_type() const { return FIELD_TYPE_STRING; }
+ void set(double nr) { str_value.set(nr); }
+ void set(longlong nr) { str_value.set(nr); }
+ void set(const char *str, uint length) { str_value.copy(str,length); }
+ double val() { return atof(str_value.ptr()); }
+ longlong val_int() { return strtoll(str_value.ptr(),NULL,10); }
+ String *val_str(String*)
+ {
+ return null_value ? (String*) 0 : (String*) &str_value;
+ }
+};
+
+/* The procedure class definitions */
+
+class Procedure {
+protected:
+ List<Item> *fields;
+ select_result *result;
+public:
+ const uint flags;
+ ORDER *group,*param_fields;
+ Procedure(select_result *res,uint flags_par) :result(res),flags(flags_par),
+ group(0),param_fields(0) {}
+ virtual ~Procedure() {group=param_fields=0; fields=0; }
+ virtual void add(void)=0;
+ virtual void end_group(void)=0;
+ virtual int send_row(List<Item> &fields)=0;
+ virtual bool change_columns(List<Item> &fields)=0;
+ virtual void update_refs(void) {}
+ virtual bool end_of_records() { return 0; }
+};
+
+Procedure *setup_procedure(THD *thd,ORDER *proc_param,select_result *result,
+ List<Item> &field_list,int *error);
diff --git a/sql/records.cc b/sql/records.cc
new file mode 100644
index 00000000000..0493e4183eb
--- /dev/null
+++ b/sql/records.cc
@@ -0,0 +1,335 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 read, write and lock records */
+
+#include "mysql_priv.h"
+
+static int rr_quick(READ_RECORD *info);
+static int rr_sequential(READ_RECORD *info);
+static int rr_from_tempfile(READ_RECORD *info);
+static int rr_from_pointers(READ_RECORD *info);
+static int rr_from_cache(READ_RECORD *info);
+static int init_rr_cache(READ_RECORD *info);
+static int rr_cmp(uchar *a,uchar *b);
+
+ /* init struct for read with info->read_record */
+
+void init_read_record(READ_RECORD *info,THD *thd, TABLE *table,
+ SQL_SELECT *select,
+ bool use_record_cache, bool print_error)
+{
+ IO_CACHE *tempfile;
+ DBUG_ENTER("init_read_record");
+
+ bzero((char*) info,sizeof(*info));
+ info->thd=thd;
+ info->table=table;
+ info->file= table->file;
+ info->forms= &info->table; /* Only one table */
+ info->record=table->record[0];
+ info->ref_length=table->file->ref_length;
+ info->select=select;
+ info->print_error=print_error;
+ table->status=0; /* And it's allways found */
+
+ if (select && my_b_inited(&select->file))
+ 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
+ {
+ DBUG_PRINT("info",("using rr_from_tempfile"));
+ info->read_record=rr_from_tempfile;
+ info->io_cache=tempfile;
+ reinit_io_cache(info->io_cache,READ_CACHE,0L,0,0);
+ info->ref_pos=table->file->ref;
+ table->file->rnd_init(0);
+
+ if (! (specialflag & SPECIAL_SAFE_MODE) &&
+ my_default_record_cache_size &&
+ !table->file->fast_key_read() &&
+ (table->db_stat & HA_READ_ONLY ||
+ table->reginfo.lock_type == TL_READ) &&
+ (ulonglong) table->reclength*(table->file->records+
+ table->file->deleted) >
+ (ulonglong) MIN_FILE_LENGTH_TO_USE_ROW_CACHE &&
+ info->io_cache->end_of_file/info->ref_length*table->reclength >
+ (my_off_t) MIN_ROWS_TO_USE_TABLE_CACHE &&
+ !table->blob_fields)
+ {
+ if (! init_rr_cache(info))
+ {
+ DBUG_PRINT("info",("using rr_from_cache"));
+ info->read_record=rr_from_cache;
+ }
+ }
+ }
+ else if (table->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;
+ info->read_record= rr_from_pointers;
+ }
+ else
+ {
+ DBUG_PRINT("info",("using rr_sequential"));
+ info->read_record=rr_sequential;
+ table->file->rnd_init();
+ /* We can use record cache if we don't update dynamic length tables */
+ if (use_record_cache ||
+ (int) table->reginfo.lock_type <= (int) TL_READ_HIGH_PRIORITY ||
+ !(table->db_options_in_use & HA_OPTION_PACK_RECORD))
+ VOID(table->file->extra(HA_EXTRA_CACHE)); // Cache reads
+ }
+ DBUG_VOID_RETURN;
+} /* init_read_record */
+
+
+void end_read_record(READ_RECORD *info)
+{ /* free cache if used */
+ if (info->cache)
+ {
+ my_free_lock((char*) info->cache,MYF(0));
+ info->cache=0;
+ }
+ if (info->table)
+ {
+ (void) info->file->extra(HA_EXTRA_NO_CACHE);
+ (void) info->file->rnd_end();
+ info->table=0;
+ }
+}
+
+ /* Read a record from head-database */
+
+static int rr_quick(READ_RECORD *info)
+{
+ int tmp=info->select->quick->get_next();
+ if (tmp)
+ {
+ if (tmp == HA_ERR_END_OF_FILE)
+ tmp= -1;
+ else if (info->print_error)
+ info->file->print_error(tmp,MYF(0));
+ }
+ return tmp;
+}
+
+
+static int rr_sequential(READ_RECORD *info)
+{
+ int tmp;
+ while ((tmp=info->file->rnd_next(info->record)))
+ {
+ if (info->thd->killed)
+ {
+ my_error(ER_SERVER_SHUTDOWN,MYF(0));
+ return 1;
+ }
+ if (tmp != HA_ERR_RECORD_DELETED)
+ {
+ if (tmp == HA_ERR_END_OF_FILE)
+ tmp= -1;
+ else if (info->print_error)
+ info->table->file->print_error(tmp,MYF(0));
+ break;
+ }
+ }
+ return tmp;
+}
+
+
+static int rr_from_tempfile(READ_RECORD *info)
+{
+ if (my_b_read(info->io_cache,info->ref_pos,info->ref_length))
+ return -1; /* End of file */
+ if (TEST_IF_LASTREF(info->ref_pos,info->ref_length))
+ return -1; /* File ends with this */
+ int tmp=info->file->rnd_pos(info->record,info->ref_pos);
+ if (tmp)
+ {
+ if (tmp == HA_ERR_END_OF_FILE)
+ tmp= -1;
+ else if (info->print_error)
+ info->file->print_error(tmp,MYF(0));
+ }
+ return tmp;
+} /* rr_from_tempfile */
+
+
+static int rr_from_pointers(READ_RECORD *info)
+{
+ if (info->cache_pos == info->cache_end)
+ return -1; /* End of file */
+ byte *cache_pos=info->cache_pos;
+ info->cache_pos+=info->ref_length;
+
+ int tmp=info->file->rnd_pos(info->record,cache_pos);
+ if (tmp)
+ {
+ if (tmp == HA_ERR_END_OF_FILE)
+ tmp= -1;
+ else if (info->print_error)
+ info->file->print_error(tmp,MYF(0));
+ }
+ return tmp;
+}
+
+ /* cacheing of records from a database */
+
+static int init_rr_cache(READ_RECORD *info)
+{
+ uint rec_cache_size;
+ DBUG_ENTER("init_rr_cache");
+
+ info->struct_length=3+MAX_REFLENGTH;
+ info->reclength=ALIGN_SIZE(info->table->reclength+1);
+ if (info->reclength < info->struct_length)
+ info->reclength=ALIGN_SIZE(info->struct_length);
+
+ info->error_offset=info->table->reclength;
+ info->cache_records=my_default_record_cache_size/
+ (info->reclength+info->struct_length);
+ rec_cache_size=info->cache_records*info->reclength;
+ info->rec_cache_size=info->cache_records*info->ref_length;
+
+ if (info->cache_records <= 2 ||
+ !(info->cache=(byte*) my_malloc_lock(rec_cache_size+info->cache_records*
+ info->struct_length,
+ MYF(0))))
+ DBUG_RETURN(1);
+#ifdef HAVE_purify
+ bzero(info->cache,rec_cache_size); // Avoid warnings in qsort
+#endif
+ DBUG_PRINT("info",("Allocated buffert for %d records",info->cache_records));
+ info->read_positions=info->cache+rec_cache_size;
+ info->cache_pos=info->cache_end=info->cache;
+ DBUG_RETURN(0);
+} /* init_rr_cache */
+
+
+static int rr_from_cache(READ_RECORD *info)
+{
+ reg1 uint i;
+ ulong length;
+ my_off_t rest_of_file;
+ int16 error;
+ byte *position,*ref_position,*record_pos;
+ ulong record;
+
+ for (;;)
+ {
+ if (info->cache_pos != info->cache_end)
+ {
+ if (info->cache_pos[info->error_offset])
+ {
+ shortget(error,info->cache_pos);
+ if (info->print_error)
+ info->table->file->print_error(error,MYF(0));
+ }
+ else
+ {
+ error=0;
+ memcpy(info->record,info->cache_pos,(size_t) info->table->reclength);
+ }
+ info->cache_pos+=info->reclength;
+ return ((int) error);
+ }
+ length=info->rec_cache_size;
+ rest_of_file=info->io_cache->end_of_file - my_b_tell(info->io_cache);
+ if ((my_off_t) length > rest_of_file)
+ length= (ulong) rest_of_file;
+ if (!length || my_b_read(info->io_cache,info->cache,length))
+ {
+ DBUG_PRINT("info",("Found end of file"));
+ return -1; /* End of file */
+ }
+
+ length/=info->ref_length;
+ position=info->cache;
+ ref_position=info->read_positions;
+ for (i=0 ; i < length ; i++,position+=info->ref_length)
+ {
+ if (memcmp(position,last_ref,(size_s) info->ref_length) == 0)
+ { /* End of file */
+ if (!i)
+ {
+ DBUG_PRINT("info",("Found end of file"));
+ return -1; /* Last record and no in buffert */
+ }
+ length=i; // rows in buffer
+ break;
+ }
+ memcpy(ref_position,position,(size_s) info->ref_length);
+ ref_position+=MAX_REFLENGTH;
+ int3store(ref_position,(long) i);
+ ref_position+=3;
+ }
+ qsort(info->read_positions,length,info->struct_length,(qsort_cmp) rr_cmp);
+
+ position=info->read_positions;
+ for (i=0 ; i < length ; i++)
+ {
+ memcpy(info->ref_pos,position,(size_s) info->ref_length);
+ position+=MAX_REFLENGTH;
+ record=uint3korr(position);
+ position+=3;
+ record_pos=info->cache+record*info->reclength;
+ if ((error=(int16) info->file->rnd_pos(record_pos,info->ref_pos)))
+ {
+ record_pos[info->error_offset]=1;
+ shortstore(record_pos,error);
+ DBUG_PRINT("error",("Got error: %d:%d when reading row",
+ my_errno, error));
+ }
+ else
+ record_pos[info->error_offset]=0;
+ }
+ info->cache_end=(info->cache_pos=info->cache)+length*info->reclength;
+ }
+} /* rr_from_cache */
+
+
+static int rr_cmp(uchar *a,uchar *b)
+{
+ if (a[0] != b[0])
+ return (int) a[0] - (int) b[0];
+ if (a[1] != b[1])
+ return (int) a[1] - (int) b[1];
+ if (a[2] != b[2])
+ return (int) a[2] - (int) b[2];
+#if MAX_REFLENGTH == 4
+ return (int) a[3] - (int) b[3];
+#else
+ if (a[3] != b[3])
+ return (int) a[3] - (int) b[3];
+ if (a[4] != b[4])
+ return (int) a[4] - (int) b[4];
+ if (a[5] != b[5])
+ return (int) a[1] - (int) b[5];
+ if (a[6] != b[6])
+ return (int) a[6] - (int) b[6];
+ return (int) a[7] - (int) b[7];
+#endif
+}
diff --git a/sql/share/.cvsignore b/sql/share/.cvsignore
new file mode 100644
index 00000000000..282522db034
--- /dev/null
+++ b/sql/share/.cvsignore
@@ -0,0 +1,2 @@
+Makefile
+Makefile.in
diff --git a/sql/share/Makefile.am b/sql/share/Makefile.am
new file mode 100755
index 00000000000..9b0f0a2991f
--- /dev/null
+++ b/sql/share/Makefile.am
@@ -0,0 +1,22 @@
+## Process this file with automake to create Makefile.in
+
+# This requires gnu cp at distribution time.
+dist-hook:
+ for lang in @AVAILABLE_LANGUAGES@ charsets; \
+ do cp -a $(srcdir)/$$lang $(distdir); done
+
+install-data-local:
+ for lang in @AVAILABLE_LANGUAGES@; \
+ do \
+ $(mkinstalldirs) $(DESTDIR)$(pkgdatadir)/$$lang; \
+ ../../extra/comp_err $(srcdir)/$$lang/errmsg.txt $(srcdir)/$$lang/errmsg.sys; \
+ $(INSTALL_DATA) $(srcdir)/$$lang/errmsg.sys \
+ $(DESTDIR)$(pkgdatadir)/$$lang/errmsg.sys; \
+ $(INSTALL_DATA) $(srcdir)/$$lang/errmsg.txt \
+ $(DESTDIR)$(pkgdatadir)/$$lang/errmsg.txt; \
+ done
+ $(mkinstalldirs) $(DESTDIR)$(pkgdatadir)/charsets
+ (for f in Index README "*.conf"; \
+ do \
+ $(INSTALL_DATA) $(srcdir)/charsets/$$f $(DESTDIR)$(pkgdatadir)/charsets/; \
+ done)
diff --git a/sql/share/charsets/Index b/sql/share/charsets/Index
new file mode 100644
index 00000000000..8d5e7576d56
--- /dev/null
+++ b/sql/share/charsets/Index
@@ -0,0 +1,37 @@
+# sql/share/charsets/Index
+#
+# This file lists all of the available character sets.
+
+# THE ORDER IN WHICH CHARACTER SETS ARE LISTED IS IMPORTANT. See the
+# README file in this directory for details.
+
+
+big5 # 1
+czech # 2
+dec8 # 3
+dos # 4
+german1 # 5
+hp8 # 6
+koi8_ru # 7
+latin1 # 8
+latin2 # 9
+swe7 # 10
+usa7 # 11
+ujis # 12
+sjis # 13
+cp1251 # 14
+danish # 15
+hebrew # 16
+win1251 # 17
+tis620 # 18
+euc_kr # 19
+estonia # 20
+hungarian # 21
+koi8_ukr # 22
+win1251ukr # 23
+gb2312 # 24
+greek # 25
+win1250 # 26
+croat # 27
+gbk # 28
+cp1257 # 29
diff --git a/sql/share/charsets/README b/sql/share/charsets/README
new file mode 100644
index 00000000000..80da6ba9665
--- /dev/null
+++ b/sql/share/charsets/README
@@ -0,0 +1,43 @@
+This directory holds configuration files which allow MySQL to work with
+different character sets. It contains:
+
+*.conf
+ Each conf file contains four tables which describe character types,
+ lower- and upper-case equivalencies and sorting orders for the
+ character values in the set.
+
+Index
+ The Index file lists all of the available charset configurations.
+
+ THE ORDER OF THE CHARACTER SETS IN THIS FILE IS SIGNIFICANT.
+ The first character set is number 1, the second is number 2, etc. The
+ number is stored IN THE DATABASE TABLE FILES and must not be changed.
+ Always add new character sets to the end of the list, so that the
+ numbers of the other character sets will not be changed.
+
+Compiled in or configuration file?
+ When should a character set be compiled in to MySQL's string library
+ (libmystrings), and when should it be placed in a configuration
+ file?
+
+ If the character set requires the strcoll functions or is a
+ multi-byte character set, it MUST be compiled in to the string
+ library. If it does not require these functions, it should be
+ placed in a configuration file.
+
+ If the character set uses any one of the strcoll functions, it
+ must define all of them. Likewise, if the set uses one of the
+ multi-byte functions, it must define them all. See the manual for
+ more information on how to add a complex character set to MySQL.
+
+Syntax of configuration files
+ The syntax is very simple. Comments start with a '#' character and
+ proceed to the end of the line. Words are separated by arbitrary
+ amounts of whitespace.
+
+ For the character set configuration files, every word must be a
+ number in hexadecimal format. The ctype array takes up the first
+ 257 words; the to_lower, to_upper and sort_order arrays take up 256
+ words each after that.
+
+ The Index file is simply a list of the available character sets.
diff --git a/sql/share/charsets/cp1251.conf b/sql/share/charsets/cp1251.conf
new file mode 100644
index 00000000000..97e570757a4
--- /dev/null
+++ b/sql/share/charsets/cp1251.conf
@@ -0,0 +1,74 @@
+# Configuration file for the cp1251 character set
+
+# ctype array (must have 257 elements)
+ 00
+ 20 20 20 20 20 20 20 20 20 28 28 28 28 28 20 20
+ 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
+ 48 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
+ 84 84 84 84 84 84 84 84 84 84 10 10 10 10 10 10
+ 10 81 81 81 81 81 81 01 01 01 01 01 01 01 01 01
+ 01 01 01 01 01 01 01 01 01 01 01 10 10 10 10 10
+ 10 82 82 82 82 82 82 02 02 02 02 02 02 02 02 02
+ 02 02 02 02 02 02 02 02 02 02 02 10 10 10 10 00
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ 48 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 02 00 00 00 00 00 00 00
+ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
+ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
+ 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02
+ 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02
+
+# to_lower array (must have 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 74 75 76 77 78 79 7A 5B 5C 5D 5E 5F
+ 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F
+ 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
+ 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
+ A0 A1 A2 A3 A4 A5 A6 A7 B8 A9 AA AB AC AD AE AF
+ B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF
+ E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
+ F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF
+ E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
+ F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF
+
+# to_upper array (must have 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F
+ 60 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 7B 7C 7D 7E 7F
+ 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
+ 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
+ A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF
+ B0 B1 B2 B3 B4 B5 B6 B7 A8 B9 BA BB BC BD BE BF
+ C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
+ D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF
+ C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
+ D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF
+
+# sort_order array (must have 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 7C 7D 7E 7F 80
+ 81 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 82 83 84 85 FF
+ FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+ FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+ FF FF FF FF FF FF FF FF 61 FF FF FF FF FF FF FF
+ FF FF FF FF FF FF FF FF 61 FF FF FF FF FF FF FF
+ 5B 5C 5D 5E 5F 60 62 63 64 65 66 67 68 69 6A 6B
+ 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B
+ 5B 5C 5D 5E 5F 60 62 63 64 65 66 67 68 69 6A 6B
+ 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B
diff --git a/sql/share/charsets/cp1257.conf b/sql/share/charsets/cp1257.conf
new file mode 100644
index 00000000000..610ed5a646f
--- /dev/null
+++ b/sql/share/charsets/cp1257.conf
@@ -0,0 +1,74 @@
+# Configuration file for the cp1257 character set.
+
+# The ctype array must have 257 elements.
+ 00
+ 20 20 20 20 20 20 20 20 20 28 28 28 28 28 20 20
+ 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
+ 48 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
+ 84 84 84 84 84 84 84 84 84 84 10 10 10 10 10 10
+ 10 81 81 81 81 81 81 01 01 01 01 01 01 01 01 01
+ 01 01 01 01 01 01 01 01 01 01 01 10 10 10 10 10
+ 10 82 82 82 82 82 82 02 02 02 02 02 02 02 02 02
+ 02 02 02 02 02 02 02 02 02 02 02 10 10 10 10 00
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ 01 01 00 00 00 00 01 00 01 00 00 01 00 00 00 00
+ 01 00 00 00 00 00 00 00 01 00 00 01 00 00 01 00
+ 02 02 00 00 00 00 02 00 02 00 00 02 00 00 00 00
+ 02 00 00 00 00 00 00 00 02 00 00 02 00 00 02 00
+
+# The to_lower array must have 256 elements.
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 74 75 76 77 78 79 7A 5B 5C 5D 5E 5F
+ 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F
+ 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
+ 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
+ A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF
+ B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF
+ E0 E1 C2 C3 C4 C5 E6 C7 E8 C9 CA EB CC CD CE CF
+ F0 D1 D2 D3 D4 D5 D6 D7 F8 D9 DA FB DC DD FE DF
+ E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
+ F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF
+
+# The to_upper array must have 256 elements.
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F
+ 60 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 7B 7C 7D 7E 7F
+ 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
+ 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
+ A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF
+ B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF
+ C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
+ D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF
+ C0 C1 E2 E3 E4 E5 C6 E7 C8 E9 EA CB EC ED EE EF
+ D0 F1 F2 F3 F4 F5 F6 F7 D8 F9 FA DB FC FD DE FF
+
+# The sort_order array must have 256 elements.
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 41 43 44 46 47 4A 4B 4C 4D 50 51 52 53 54 55
+ 56 57 58 59 5B 5C 5F 60 61 4E FF 62 63 64 65 66
+ 67 41 43 44 46 47 4A 4B 4C 4D 50 51 52 53 54 55
+ 56 57 58 59 5B 5C 5F 60 61 4E FF 68 69 6A 6B FF
+ FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+ FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+ FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+ FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+ 42 4F FF FF FF FF 48 FF 45 FF FF 49 FF FF FF FF
+ 5A FF FF FF FF FF FF FF 5E FF FF 5D FF FF FF FF
+ FF 4F FF FF FF FF 48 FF 45 FF FF 49 FF FF FF FF
+ 5A FF FF FF FF FF FF FF 5E FF FF 5D FF FF FF FF
diff --git a/sql/share/charsets/croat.conf b/sql/share/charsets/croat.conf
new file mode 100644
index 00000000000..fbbe3328547
--- /dev/null
+++ b/sql/share/charsets/croat.conf
@@ -0,0 +1,74 @@
+# Configuration file for the croat character set
+
+# ctype array (must have 257 elements)
+ 00
+ 20 20 20 20 20 20 20 20 20 28 28 28 28 28 20 20
+ 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
+ 48 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
+ 84 84 84 84 84 84 84 84 84 84 10 10 10 10 10 10
+ 10 81 81 81 81 81 81 01 01 01 01 01 01 01 01 01
+ 01 01 01 01 01 01 01 01 01 01 01 10 10 10 10 10
+ 10 82 82 82 82 82 82 02 02 02 02 02 02 02 02 02
+ 02 02 02 02 02 02 02 02 02 02 02 10 10 10 10 20
+ 00 00 00 00 00 00 00 00 00 01 00 00 00 01 00 00
+ 00 00 00 00 00 00 00 00 00 02 00 00 00 02 00 00
+ 48 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
+ 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
+ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
+ 01 01 01 01 01 01 01 10 01 01 01 01 01 01 01 02
+ 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02
+ 02 02 02 02 02 02 02 10 02 02 02 02 02 02 02 02
+
+# to_lower array (must have 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 74 75 76 77 78 79 7A 5B 5C 5D 5E 5F
+ 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F
+ 80 81 82 83 84 85 86 87 88 89 9A 8B 8C 8D 9E 8F
+ 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
+ A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF
+ B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF
+ E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
+ F0 F1 F2 F3 F4 F5 F6 D7 F8 F9 FA FB FC FD FE DF
+ E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
+ F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF
+
+# to_upper array (must have 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F
+ 60 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 7B 7C 7D 7E 7F
+ 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
+ 90 91 92 93 94 95 96 97 98 99 8A 9B 9C 9D 8E 9F
+ A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF
+ B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF
+ C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
+ D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF
+ C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
+ D0 D1 D2 D3 D4 D5 D6 F7 D8 D9 DA DB DC DD DE FF
+
+# sort_order array (must have 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 41 42 43 46 48 49 4A 4B 4C 4D 4E 4F 50 51 52
+ 53 54 55 56 58 59 5A 5B 5C 5D 5E 5B 5C 5D 5E 5F
+ 60 41 42 43 46 48 49 4A 4B 4C 4D 4E 4F 50 51 52
+ 53 54 55 56 58 59 5A 5B 5C 5D 5E 7B 7C 7D 7E 7F
+ 80 81 82 83 84 85 86 87 88 89 57 8B 8C 8D 5F 8F
+ 90 91 92 93 94 95 96 97 98 99 57 9B 9C 9D 5F 9F
+ A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF
+ B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF
+ 41 41 41 41 5C 5B 45 43 44 45 45 45 49 49 49 49
+ 47 4E 4F 4F 4F 4F 5D D7 D8 55 55 55 59 59 DE DF
+ 41 41 41 41 5C 5B 45 43 44 45 45 45 49 49 49 49
+ 47 4E 4F 4F 4F 4F 5D F7 D8 55 55 55 59 59 DE FF
diff --git a/sql/share/charsets/danish.conf b/sql/share/charsets/danish.conf
new file mode 100644
index 00000000000..f99590ed6f3
--- /dev/null
+++ b/sql/share/charsets/danish.conf
@@ -0,0 +1,74 @@
+# Configuration file for the danish character set
+
+# ctype array (must have 257 elements)
+ 00
+ 20 20 20 20 20 20 20 20 20 28 28 28 28 28 20 20
+ 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
+ 48 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
+ 84 84 84 84 84 84 84 84 84 84 10 10 10 10 10 10
+ 10 81 81 81 81 81 81 01 01 01 01 01 01 01 01 01
+ 01 01 01 01 01 01 01 01 01 01 01 10 10 10 10 10
+ 10 82 82 82 82 82 82 02 02 02 02 02 02 02 02 02
+ 02 02 02 02 02 02 02 02 02 02 02 10 10 10 10 20
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ 48 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
+ 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
+ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
+ 01 01 01 01 01 01 01 10 01 01 01 01 01 01 01 02
+ 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02
+ 02 02 02 02 02 02 02 10 02 02 02 02 02 02 02 02
+
+# to_lower array (must have 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 74 75 76 77 78 79 7A 5B 5C 5D 5E 5F
+ 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F
+ 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
+ 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
+ A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF
+ B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF
+ E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
+ F0 F1 F2 F3 F4 F5 F6 D7 F8 F9 FA FB FC FD FE DF
+ E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
+ F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF
+
+# to_upper array (must have 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F
+ 60 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 7B 7C 7D 7E 7F
+ 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
+ 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
+ A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF
+ B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF
+ C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
+ D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF
+ C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
+ D0 D1 D2 D3 D4 D5 D6 F7 D8 D9 DA DB DC DD DE FF
+
+# sort_order array (must have 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F
+ 60 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 7B 7C 7D 7E 7F
+ 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
+ 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
+ A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF
+ B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF
+ 41 41 41 41 5B 5D 5B 43 45 45 45 45 49 49 49 49
+ 44 4E 4F 4F 4F 4F 5C D7 5C 55 55 55 59 59 DE DF
+ 41 41 41 41 5B 5D 5B 43 45 45 45 45 49 49 49 49
+ 44 4E 4F 4F 4F 4F 5C F7 5C 55 55 55 59 59 DE FF
diff --git a/sql/share/charsets/dec8.conf b/sql/share/charsets/dec8.conf
new file mode 100644
index 00000000000..a4849aaa04c
--- /dev/null
+++ b/sql/share/charsets/dec8.conf
@@ -0,0 +1,74 @@
+# Configuration file for the dec8 character set
+
+# ctype array (must have 257 elements)
+ 00
+ 20 20 20 20 20 20 20 20 20 28 28 28 28 28 20 20
+ 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
+ 48 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
+ 84 84 84 84 84 84 84 84 84 84 10 10 10 10 10 10
+ 10 81 81 81 81 81 81 01 01 01 01 01 01 01 01 01
+ 01 01 01 01 01 01 01 01 01 01 01 10 10 10 10 10
+ 10 82 82 82 82 82 82 02 02 02 02 02 02 02 02 02
+ 02 02 02 02 02 02 02 02 02 02 02 10 10 10 10 20
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ 48 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
+ 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
+ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
+ 01 01 01 01 01 01 01 10 01 01 01 01 01 01 01 02
+ 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02
+ 02 02 02 02 02 02 02 10 02 02 02 02 02 02 02 02
+
+# to_lower array (must have 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 74 75 76 77 78 79 7A 5B 5C 5D 5E 5F
+ 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F
+ 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
+ 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
+ A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF
+ B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF
+ E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
+ F0 F1 F2 F3 F4 F5 F6 D7 F8 F9 FA FB FC FD FE DF
+ E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
+ F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF
+
+# to_upper array (must have 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F
+ 60 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 7B 7C 7D 7E 7F
+ 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
+ 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
+ A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF
+ B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF
+ C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
+ D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF
+ C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
+ D0 D1 D2 D3 D4 D5 D6 F7 D8 D9 DA DB DC DD DE FF
+
+# sort_order array (must have 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F
+ 60 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 7B 7C 7D 7E 7F
+ 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
+ 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
+ A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF
+ B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF
+ 41 41 41 41 5C 5B 5C 43 45 45 45 45 49 49 49 49
+ 44 4E 4F 4F 4F 4F 5D D7 D8 55 55 55 59 59 DE DF
+ 41 41 41 41 5C 5B 5C 43 45 45 45 45 49 49 49 49
+ 44 4E 4F 4F 4F 4F 5D F7 D8 55 55 55 59 59 DE FF
diff --git a/sql/share/charsets/dos.conf b/sql/share/charsets/dos.conf
new file mode 100644
index 00000000000..dda86d0f3e8
--- /dev/null
+++ b/sql/share/charsets/dos.conf
@@ -0,0 +1,74 @@
+# Configuration file for the dos character set
+
+# ctype array (must have 257 elements)
+ 00
+ 20 30 30 30 30 30 30 20 20 28 28 28 28 28 30 30
+ 30 30 30 30 30 30 30 30 30 30 20 30 30 30 30 30
+ 48 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
+ 84 84 84 84 84 84 84 84 84 84 10 10 10 10 10 10
+ 10 81 81 81 81 81 81 01 01 01 01 01 01 01 01 01
+ 01 01 01 01 01 01 01 01 01 01 01 10 10 10 10 10
+ 10 82 82 82 82 82 82 02 02 02 02 02 02 02 02 02
+ 02 02 02 02 02 02 02 02 02 02 02 10 10 10 10 30
+ 02 02 02 02 02 02 02 02 02 02 02 02 02 02 01 01
+ 01 02 01 02 02 02 02 02 02 01 01 10 10 10 10 10
+ 02 02 02 02 02 01 10 10 10 10 10 10 10 10 10 10
+ 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
+ 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
+ 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
+ 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
+ 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 20
+
+# to_lower array (must have 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 74 75 76 77 78 79 7A 5B 5C 5D 5E 5F
+ 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F
+ 87 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 84 86
+ 82 91 91 93 94 95 96 97 98 94 81 9B 9C 9D 9E 9F
+ A0 A1 A2 A3 A4 A4 A6 A7 A8 A9 AA AB AC AD AE AF
+ B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF
+ C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
+ D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF
+ E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
+ F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF
+
+# to_upper array (must have 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F
+ 60 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 7B 7C 7D 7E 7F
+ 80 9A 90 41 8E 41 8F 80 45 45 45 49 49 49 8E 8F
+ 90 92 92 4F 99 4F 55 55 59 99 9A 9B 9C 9D 9E 9F
+ 41 49 4F 55 A5 A5 A6 A7 A8 A9 AA AB AC AD AE AF
+ B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF
+ C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
+ D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF
+ E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
+ F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF
+
+# sort_order array (must have 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F
+ 60 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 7B 7C 7D 7E 7F
+ 43 59 45 41 5C 41 5B 43 45 45 45 49 49 49 5C 5B
+ 45 5C 5C 4F 5D 4F 55 55 59 5D 59 24 24 24 24 24
+ 41 49 4F 55 4E 4E A6 A7 3F A9 AA AB AC 21 22 22
+ B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF
+ C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
+ D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF
+ E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
+ F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF
diff --git a/sql/share/charsets/estonia.conf b/sql/share/charsets/estonia.conf
new file mode 100644
index 00000000000..76bbc021b0c
--- /dev/null
+++ b/sql/share/charsets/estonia.conf
@@ -0,0 +1,74 @@
+# Configuration file for the estonia character set.
+
+# The ctype array must have 257 elements.
+ 00
+ 20 20 20 20 20 20 20 20 20 28 28 28 28 28 20 20
+ 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
+ 48 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
+ 84 84 84 84 84 84 84 84 84 84 10 10 10 10 10 10
+ 10 81 81 81 81 81 81 01 01 01 01 01 01 01 01 01
+ 01 01 01 01 01 01 01 01 01 01 01 10 10 10 10 10
+ 10 82 82 82 82 82 82 02 02 02 02 02 02 02 02 02
+ 02 02 02 02 02 02 02 02 02 02 02 10 10 10 10 20
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ 48 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
+ 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
+ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
+ 01 01 01 01 01 01 01 10 01 01 01 01 01 01 01 02
+ 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02
+ 02 02 02 02 02 02 02 10 02 02 02 02 02 02 02 02
+
+# The to_lower array must have 256 elements.
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 74 75 76 77 78 79 7A 5B 5C 5D 5E 5F
+ 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F
+ 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
+ 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
+ A0 A1 A2 A3 A4 A5 A6 A7 B8 A9 BA AB AC AD AE BF
+ B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF
+ E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
+ F0 F1 F2 F3 F4 F5 F6 D7 F8 F9 FA FB FC FD FE DF
+ E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
+ F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF
+
+# The to_upper array must have 256 elements.
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F
+ 60 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 7B 7C 7D 7E 7F
+ 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
+ 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
+ A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF
+ B0 B1 B2 B3 B4 B5 B6 B7 A8 B9 AA BB BC BD BE AF
+ C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
+ D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF
+ C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
+ D0 D1 D2 D3 D4 D5 D6 F7 D8 D9 DA DB DC DD DE FF
+
+# The sort_order array must have 256 elements.
+ 00 02 03 04 05 06 07 08 09 2E 2F 30 31 32 0A 0B
+ 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B
+ 2C 33 34 35 36 37 38 27 39 3A 3B 5D 3C 28 3D 3E
+ 76 7A 7C 7E 80 81 82 83 84 85 3F 40 5E 5F 60 41
+ 42 86 90 92 98 9A A4 A6 AA AC B2 B4 B8 BE C0 C6
+ CE D0 D2 D6 E5 E8 EE F0 FA FC DD 43 44 45 46 47
+ 48 87 91 93 99 9B A5 A7 AB AD B3 B5 B9 BF C1 C7
+ CF D1 D3 D7 E6 E9 EF F1 FB FD DE 49 4A 4B 4C 1C
+ 01 1D 57 1E 5A 74 71 72 1F 75 20 5B 21 4E 52 51
+ 22 55 56 58 59 73 2A 2B 23 E7 24 5C 25 4F 54 26
+ 2D FE 66 67 68 FF 4D 69 CC 6A D4 62 6B 29 6C 8E
+ 6D 61 7D 7F 50 6E 6F 70 CD 7B D5 63 77 78 79 8F
+ 8C B0 88 94 F4 8A A2 A0 96 9C DF 9E A8 B6 AE BA
+ DB C2 C4 C8 CA F2 F6 64 EC BC D8 EA F8 E1 E3 DA
+ 8D B1 89 95 F5 8B A3 A1 97 9D E0 9F A9 B7 AF BB
+ DC C3 C5 C9 CB F3 F7 65 ED BD D9 EB F9 E2 E4 53
diff --git a/sql/share/charsets/german1.conf b/sql/share/charsets/german1.conf
new file mode 100644
index 00000000000..dac77b1f08f
--- /dev/null
+++ b/sql/share/charsets/german1.conf
@@ -0,0 +1,74 @@
+# Configuration file for the german1 character set
+
+# ctype array (must have 257 elements)
+ 00
+ 20 20 20 20 20 20 20 20 20 28 28 28 28 28 20 20
+ 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
+ 48 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
+ 84 84 84 84 84 84 84 84 84 84 10 10 10 10 10 10
+ 10 81 81 81 81 81 81 01 01 01 01 01 01 01 01 01
+ 01 01 01 01 01 01 01 01 01 01 01 10 10 10 10 10
+ 10 82 82 82 82 82 82 02 02 02 02 02 02 02 02 02
+ 02 02 02 02 02 02 02 02 02 02 02 10 10 10 10 20
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ 48 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
+ 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
+ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
+ 01 01 01 01 01 01 01 10 01 01 01 01 01 01 01 02
+ 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02
+ 02 02 02 02 02 02 02 10 02 02 02 02 02 02 02 02
+
+# to_lower array (must have 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 74 75 76 77 78 79 7A 5B 5C 5D 5E 5F
+ 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F
+ 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
+ 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
+ A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF
+ B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF
+ E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
+ F0 F1 F2 F3 F4 F5 F6 D7 F8 F9 FA FB FC FD FE DF
+ E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
+ F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF
+
+# to_upper array (must have 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F
+ 60 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 7B 7C 7D 7E 7F
+ 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
+ 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
+ A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF
+ B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF
+ C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
+ D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF
+ C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
+ D0 D1 D2 D3 D4 D5 D6 F7 D8 D9 DA DB DC DD DE FF
+
+# sort_order array (must have 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F
+ 60 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 7B 7C 7D 7E 7F
+ 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
+ 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
+ A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF
+ B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF
+ 41 41 41 41 41 41 41 43 45 45 45 45 49 49 49 49
+ 44 4E 4F 4F 4F 4F 4F D7 D8 55 55 55 55 59 DE DF
+ 41 41 41 41 41 41 41 43 45 45 45 45 49 49 49 49
+ 44 4E 4F 4F 4F 4F 4F F7 D8 55 55 55 55 59 DE FF
diff --git a/sql/share/charsets/greek.conf b/sql/share/charsets/greek.conf
new file mode 100644
index 00000000000..73d67d6ee71
--- /dev/null
+++ b/sql/share/charsets/greek.conf
@@ -0,0 +1,74 @@
+# Configuration file for the greek character set
+
+# ctype array (must have 257 elements)
+ 00
+ 20 20 20 20 20 20 20 20 20 28 28 28 28 28 20 20
+ 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
+ 48 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
+ 84 84 84 84 84 84 84 84 84 84 10 10 10 10 10 10
+ 10 81 81 81 81 81 81 01 01 01 01 01 01 01 01 01
+ 01 01 01 01 01 01 01 01 01 01 01 10 10 10 10 10
+ 10 82 82 82 82 82 82 02 02 02 02 02 02 02 02 02
+ 02 02 02 02 02 02 02 02 02 02 02 10 10 10 10 20
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ 48 10 10 10 00 00 10 10 10 10 00 10 10 10 00 10
+ 10 10 10 10 10 10 01 10 01 01 01 10 01 10 01 01
+ 02 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
+ 01 01 00 01 01 01 01 01 01 01 01 01 02 02 02 02
+ 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02
+ 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 00
+
+# to_lower array (must have 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 74 75 76 77 78 79 7A 5B 5C 5D 5E 5F
+ 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F
+ 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
+ 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
+ A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF
+ B0 B1 B2 B3 B4 B5 DC B7 DD DE DF BB FC BD FD FE
+ C0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
+ F0 F1 D2 F3 F4 F5 F6 F7 F8 F9 FA FB DC DD DE DF
+ E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
+ F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF
+
+# to_upper array (must have 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F
+ 60 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 7B 7C 7D 7E 7F
+ 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
+ 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
+ A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF
+ B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF
+ DA C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
+ D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB C1 C5 C7 C9
+ DB C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
+ D0 D1 D3 D3 D4 D5 D6 D7 D8 D9 DA DB CF D5 D9 FF
+
+# sort_order array (must have 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F
+ 60 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 7B 7C 7D 7E 7F
+ 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
+ 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
+ A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF
+ B0 B1 B2 B3 B4 B5 C1 B7 C5 C7 C9 BB CF BD D5 D9
+ C9 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
+ D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 C9 D5 C1 C5 C7 C9
+ D5 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
+ D0 D1 D3 D3 D4 D5 D6 D7 D8 D9 C9 D5 CF D5 D9 FF
diff --git a/sql/share/charsets/hebrew.conf b/sql/share/charsets/hebrew.conf
new file mode 100644
index 00000000000..6a5f88eb228
--- /dev/null
+++ b/sql/share/charsets/hebrew.conf
@@ -0,0 +1,74 @@
+# Configuration file for the hebrew character set
+
+# ctype array (must have 257 elements)
+ 00
+ 20 20 20 20 20 20 20 20 20 28 28 28 28 28 20 20
+ 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
+ 48 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
+ 84 84 84 84 84 84 84 84 84 84 10 10 10 10 10 10
+ 10 81 81 81 81 81 81 01 01 01 01 01 01 01 01 01
+ 01 01 01 01 01 01 01 01 01 01 01 10 10 10 10 10
+ 10 82 82 82 82 82 82 02 02 02 02 02 02 02 02 02
+ 02 02 02 02 02 02 02 02 02 02 02 10 10 10 10 20
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ 48 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
+ 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02
+ 02 02 02 02 02 02 02 02 02 02 02 00 00 00 00 00
+
+# to_lower array (must have 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 74 75 76 77 78 79 7A 5B 5C 5D 5E 5F
+ 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F
+ 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
+ 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
+ A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF
+ B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF
+ C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
+ D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF
+ E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
+ F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF
+
+# to_upper array (must have 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F
+ 60 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 7B 7C 7D 7E 7F
+ 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
+ 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
+ A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF
+ B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF
+ C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
+ D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF
+ E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
+ F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF
+
+# sort_order array (must have 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F
+ 60 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 7B 7C 7D 7E 7F
+ 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
+ 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
+ A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF
+ B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF
+ C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
+ D0 D1 D2 D3 D4 D5 D6 F7 D8 D9 DA DB DC DD DE FF
+ E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
+ F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF
diff --git a/sql/share/charsets/hp8.conf b/sql/share/charsets/hp8.conf
new file mode 100644
index 00000000000..e9fadacbf76
--- /dev/null
+++ b/sql/share/charsets/hp8.conf
@@ -0,0 +1,74 @@
+# Configuration file for the hp8 character set
+
+# ctype array (must have 257 elements)
+ 00
+ 20 20 20 20 20 20 20 20 20 28 28 28 28 28 20 20
+ 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
+ 48 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
+ 84 84 84 84 84 84 84 84 84 84 10 10 10 10 10 10
+ 10 81 81 81 81 81 81 01 01 01 01 01 01 01 01 01
+ 01 01 01 01 01 01 01 01 01 01 01 10 10 10 10 10
+ 10 82 82 82 82 82 82 02 02 02 02 02 02 02 02 02
+ 02 02 02 02 02 02 02 02 02 02 02 10 10 10 10 20
+ 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
+ 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
+ 20 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
+ 10 20 20 10 10 10 10 10 10 10 10 10 10 10 10 10
+ 10 10 10 10 10 02 10 10 10 10 10 10 02 10 02 02
+ 01 10 10 01 02 10 10 02 01 10 01 01 01 10 10 10
+ 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
+ 10 10 20 20 20 20 10 10 10 10 10 10 10 10 10 20
+
+# to_lower array (must have 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 74 75 76 77 78 79 7A 5B 5C 5D 5E 5F
+ 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F
+ 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
+ 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
+ A0 C8 C0 C9 C1 CD D1 DD A8 A9 AA AB AC CB C3 AF
+ B0 B2 B2 B3 B5 B5 B7 B7 B8 B9 BA BB BC BD BE BF
+ C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
+ D4 D1 D6 D7 D4 D5 D6 D7 CC D9 CE CF C5 DD DE C2
+ C4 E2 E2 E4 E4 D5 D9 C6 CA EA EA EC EC C7 EF EF
+ F1 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF
+
+# to_upper array (must have 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F
+ 60 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 7B 7C 7D 7E 7F
+ 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
+ 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
+ A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF
+ B0 B1 B1 B3 B4 B4 B6 B6 B8 B9 BA BB BC BD BE BF
+ A2 A4 DF AE E0 DC E7 ED A1 A3 E8 AD D8 A5 DA DB
+ D0 A6 D2 D3 D0 E5 D2 D3 D8 E6 DA DB DC A7 DE DF
+ E0 E1 E1 E3 E3 E5 E6 E7 E8 E9 E9 EB EB ED EE EE
+ F0 F0 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF
+
+# sort_order array (must have 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 5C 5D 5B 5E 5F
+ 60 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 7B 7C 7D 7E 7F
+ 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
+ 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
+ A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF
+ B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF
+ C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
+ D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF
+ E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
+ F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF
diff --git a/sql/share/charsets/hungarian.conf b/sql/share/charsets/hungarian.conf
new file mode 100644
index 00000000000..db58d62575f
--- /dev/null
+++ b/sql/share/charsets/hungarian.conf
@@ -0,0 +1,74 @@
+# Configuration file for the hungarian character set
+
+# ctype array (must have 257 elements)
+ 00
+ 20 20 20 20 20 20 20 20 20 28 28 28 28 28 20 20
+ 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
+ 48 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
+ 84 84 84 84 84 84 84 84 84 84 10 10 10 10 10 10
+ 10 81 81 81 81 81 81 01 01 01 01 01 01 01 01 01
+ 01 01 01 01 01 01 01 01 01 01 01 10 10 10 10 10
+ 10 82 82 82 82 82 82 02 02 02 02 02 02 02 02 02
+ 02 02 02 02 02 02 02 02 02 02 02 10 10 10 10 20
+ 20 20 20 20 20 20 20 20 28 28 28 28 28 20 20 20
+ 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 48
+ 01 10 01 10 01 01 10 00 00 01 01 01 01 10 01 01
+ 10 02 10 02 10 02 02 10 10 02 02 02 02 10 02 02
+ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
+ 10 01 01 01 01 01 01 10 01 01 01 01 01 01 01 10
+ 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02
+ 02 02 02 02 02 02 02 10 02 02 02 02 02 02 02 10
+
+# to_lower array (must have 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 74 75 76 77 78 79 7A 5B 5C 5D 5E 5F
+ 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F
+ 80 81 82 83 84 85 86 87 88 89 8B 8B A1 A1 8E A0
+ 82 91 92 93 94 A2 96 A3 96 94 81 9B 9C 9D 9E 9F
+ A0 A1 A2 A3 B5 B6 A6 93 A8 B9 BA BB BC AD BE BF
+ B0 B1 B2 B3 B4 E1 B6 B7 B8 B9 BA BB BC BD BE BF
+ E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
+ D0 F1 F2 F3 F4 F5 F6 D7 F8 F9 FA FB FC FD FE DF
+ A2 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA 96 EC ED EE EF
+ F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF
+
+# to_upper array (must have 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F
+ 60 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 7B 7C 7D 7E 7F
+ 80 9A 90 83 84 85 86 87 88 89 8A 8A 8C 8D 8E 8F
+ 90 91 92 A7 99 95 98 97 98 99 9A 9B 9C 9D 9E 9F
+ 8F 8D 95 97 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF
+ B0 A0 B2 A2 B4 B5 A5 B7 B8 A9 AA AB AC BD AE AF
+ C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
+ D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF
+ E0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA EB CC CD CE CF
+ F0 D1 D2 D3 D4 D5 D6 F7 D8 D9 DA DB DC DD DE FF
+
+# sort_order array (must have 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 41 47 48 4C 4E 53 54 55 56 5A 5B 5C 60 61 64
+ 69 6A 6B 6E 72 75 7A 7B 7C 7D 7F 83 84 85 86 87
+ 88 41 47 48 4C 4E 53 54 55 56 5A 5B 5C 60 61 64
+ 69 6A 6B 6E 72 75 7A 7B 7C 7D 7F 89 8A 8B 8C 00
+ 01 78 4E 04 05 06 07 08 09 0A 67 67 56 56 0F 41
+ 4E 12 13 67 67 64 78 75 78 67 78 1C 1D 1E 1F FF
+ 41 56 64 75 5E 6F FF 67 FF 70 71 73 80 FF 81 82
+ FF 42 FF 5D FF 41 6F FF FF 70 71 73 80 FF 81 82
+ 6C 41 44 45 46 5F 49 4B 4A 4E 51 52 50 56 57 4D
+ FF 62 63 64 66 67 67 FF 6D 77 75 78 78 7E 74 FF
+ 64 41 44 45 46 5F 49 4B 4A 4E 51 78 50 56 58 4D
+ FF 62 63 64 66 67 67 FF 6D 77 75 78 78 7E 74 FF
diff --git a/sql/share/charsets/koi8_ru.conf b/sql/share/charsets/koi8_ru.conf
new file mode 100644
index 00000000000..4cfee67a236
--- /dev/null
+++ b/sql/share/charsets/koi8_ru.conf
@@ -0,0 +1,74 @@
+# Configuration file for the koi8_ru character set
+
+# ctype array (must have 257 elements)
+ 00
+ 20 20 20 20 20 20 20 20 20 28 28 28 28 28 20 20
+ 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
+ 48 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
+ 84 84 84 84 84 84 84 84 84 84 10 10 10 10 10 10
+ 10 81 81 81 81 81 81 01 01 01 01 01 01 01 01 01
+ 01 01 01 01 01 01 01 01 01 01 01 10 10 10 10 10
+ 10 82 82 82 82 82 82 02 02 02 02 02 02 02 02 02
+ 02 02 02 02 02 02 02 02 02 02 02 10 10 10 10 20
+ 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
+ 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
+ 10 10 10 02 10 10 10 10 10 10 10 10 10 10 10 10
+ 10 10 10 01 10 10 10 10 10 10 10 10 10 10 10 10
+ 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02
+ 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02
+ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
+ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
+
+# to_lower array (must have 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 74 75 76 77 78 79 7A 5B 5C 5D 5E 5F
+ 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F
+ 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
+ 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
+ A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF
+ B0 B1 B2 A3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF
+ C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
+ D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF
+ C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
+ D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF
+
+# to_upper array (must have 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F
+ 60 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 7B 7C 7D 7E 7F
+ 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
+ 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
+ A0 A1 A2 B3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF
+ B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF
+ E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
+ F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF
+ E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
+ F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF
+
+# sort_order array (must have 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F
+ 60 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 7B 7C 7D 7E 7F
+ 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
+ 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
+ A0 A1 A2 E5 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE
+ AF B0 B1 E5 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD
+ FE DF E0 F6 E3 E4 F4 E2 F5 E8 E9 EA EB EC ED EE
+ EF FF F0 F1 F2 F3 E6 E1 FC FB E7 F8 FD F9 F7 FA
+ FE DF E0 F6 E3 E4 F4 E2 F5 E8 E9 EA EB EC ED EE
+ EF FF F0 F1 F2 F3 E6 E1 FC FB E7 F8 FD F9 F7 FA
diff --git a/sql/share/charsets/koi8_ukr.conf b/sql/share/charsets/koi8_ukr.conf
new file mode 100644
index 00000000000..3e2c8e27325
--- /dev/null
+++ b/sql/share/charsets/koi8_ukr.conf
@@ -0,0 +1,74 @@
+# Configuration file for the koi8_ukr character set
+
+# ctype array (must have 257 elements)
+ 00
+ 20 20 20 20 20 20 20 20 20 28 28 28 28 28 20 20
+ 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
+ 48 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
+ 84 84 84 84 84 84 84 84 84 84 10 10 10 10 10 10
+ 10 81 81 81 81 81 81 01 01 01 01 01 01 01 01 01
+ 01 01 01 01 01 01 01 01 01 01 01 10 10 10 10 10
+ 10 82 82 82 82 82 82 02 02 02 02 02 02 02 02 02
+ 02 02 02 02 02 02 02 02 02 02 02 10 10 10 10 20
+ 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
+ 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
+ 10 10 10 02 02 10 02 02 10 10 10 10 10 02 10 10
+ 10 10 10 01 01 10 01 01 10 10 10 10 10 01 10 10
+ 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02
+ 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02
+ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
+ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
+
+# to_lower array (must have 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 74 75 76 77 78 79 7A 5B 5C 5D 5E 5F
+ 20 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F
+ 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
+ 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
+ 20 20 20 A3 A4 20 A6 A7 20 20 20 20 20 AD 20 20
+ 20 20 20 A3 A4 20 A6 A7 20 20 20 20 20 AD 20 20
+ C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
+ D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF
+ C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
+ D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF
+
+# to_upper array (must have 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F
+ 20 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 7B 7C 7D 7E 7F
+ 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
+ 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
+ 20 20 20 B3 B4 20 B6 B7 20 20 20 20 20 BD 20 20
+ 20 20 20 B3 B4 20 B6 B7 20 20 20 20 20 BD 20 20
+ E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
+ F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF
+ E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
+ F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF
+
+# sort_order array (must have 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F
+ 20 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 7B 7C 7D 7E 7F
+ A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4
+ B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4
+ C5 C6 C7 88 87 C8 8C 8D C9 CA CB CC CD 84 CE CF
+ D0 D1 D2 88 87 D3 8C 8D D4 D5 D6 D7 D8 84 D9 DA
+ A3 80 81 9B 85 86 99 83 9A 8B 8E 8F 90 91 92 93
+ 94 A4 95 96 97 98 89 82 A1 A0 8A 9D A2 9E 9C 9F
+ A3 80 81 9B 85 86 99 83 9A 8B 8E 8F 90 91 92 93
+ 94 A4 95 96 97 98 89 82 A1 A0 8A 9D A2 9E 9C 9F
diff --git a/sql/share/charsets/latin1.conf b/sql/share/charsets/latin1.conf
new file mode 100644
index 00000000000..cf974aefa14
--- /dev/null
+++ b/sql/share/charsets/latin1.conf
@@ -0,0 +1,74 @@
+# Configuration file for the latin1 character set
+
+# ctype array (must have 257 elements)
+ 00
+ 20 20 20 20 20 20 20 20 20 28 28 28 28 28 20 20
+ 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
+ 48 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
+ 84 84 84 84 84 84 84 84 84 84 10 10 10 10 10 10
+ 10 81 81 81 81 81 81 01 01 01 01 01 01 01 01 01
+ 01 01 01 01 01 01 01 01 01 01 01 10 10 10 10 10
+ 10 82 82 82 82 82 82 02 02 02 02 02 02 02 02 02
+ 02 02 02 02 02 02 02 02 02 02 02 10 10 10 10 20
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ 48 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
+ 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
+ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
+ 01 01 01 01 01 01 01 10 01 01 01 01 01 01 01 02
+ 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02
+ 02 02 02 02 02 02 02 10 02 02 02 02 02 02 02 02
+
+# to_lower array (must have 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 74 75 76 77 78 79 7A 5B 5C 5D 5E 5F
+ 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F
+ 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
+ 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
+ A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF
+ B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF
+ E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
+ F0 F1 F2 F3 F4 F5 F6 D7 F8 F9 FA FB FC FD FE DF
+ E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
+ F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF
+
+# to_upper array (must have 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F
+ 60 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 7B 7C 7D 7E 7F
+ 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
+ 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
+ A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF
+ B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF
+ C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
+ D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF
+ C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
+ D0 D1 D2 D3 D4 D5 D6 F7 D8 D9 DA DB DC DD DE FF
+
+# sort_order array (must have 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F
+ 60 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 7B 7C 7D 7E 7F
+ 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
+ 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
+ A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF
+ B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF
+ 41 41 41 41 5C 5B 5C 43 45 45 45 45 49 49 49 49
+ 44 4E 4F 4F 4F 4F 5D D7 D8 55 55 55 59 59 DE DF
+ 41 41 41 41 5C 5B 5C 43 45 45 45 45 49 49 49 49
+ 44 4E 4F 4F 4F 4F 5D F7 D8 55 55 55 59 59 DE FF
diff --git a/sql/share/charsets/latin2.conf b/sql/share/charsets/latin2.conf
new file mode 100644
index 00000000000..cc18c22c0a2
--- /dev/null
+++ b/sql/share/charsets/latin2.conf
@@ -0,0 +1,74 @@
+# Configuration file for the latin2 character set
+
+# ctype array (must have 257 elements)
+ 00
+ 20 20 20 20 20 20 20 20 20 28 28 28 28 28 20 20
+ 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
+ 48 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
+ 84 84 84 84 84 84 84 84 84 84 10 10 10 10 10 10
+ 10 81 81 81 81 81 81 01 01 01 01 01 01 01 01 01
+ 01 01 01 01 01 01 01 01 01 01 01 10 10 10 10 10
+ 10 82 82 82 82 82 82 02 02 02 02 02 02 02 02 02
+ 02 02 02 02 02 02 02 02 02 02 02 10 10 10 10 00
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ 48 01 10 01 10 01 01 10 10 01 01 01 01 10 01 01
+ 10 02 10 02 10 02 02 10 10 02 02 02 02 10 02 02
+ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
+ 10 01 01 01 01 01 01 10 01 01 01 01 01 01 01 10
+ 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02
+ 02 02 02 02 02 02 02 10 02 02 02 02 02 02 02 10
+
+# to_lower array (must have 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 74 75 76 77 78 79 7A 5B 5C 5D 5E 5F
+ 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F
+ 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
+ 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
+ A0 B1 A2 B3 A4 B5 B6 A7 A8 B9 BA BB BC AD BE BF
+ B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF
+ E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
+ D0 F1 F2 F3 F4 F5 F6 D7 F8 F9 FA FB FC FD FE DF
+ E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
+ F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF
+
+# to_upper array (must have 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F
+ 60 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 7B 7C 7D 7E 7F
+ 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
+ 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
+ A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF
+ B0 A1 B2 A3 B4 A5 A6 B7 B8 A9 AA AB AC BD AE AF
+ C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
+ D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF
+ C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
+ F0 D1 D2 D3 D4 D5 D6 F7 D8 D9 DA DB DC DD DE FF
+
+# sort_order array (must have 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 41 44 45 48 49 4B 4C 4D 4E 4F 50 51 53 54 56
+ 58 59 5A 5B 5E 5F 60 61 62 63 64 68 69 6A 6B 6C
+ 6D 41 44 45 48 49 4B 4C 4D 4E 4F 50 51 53 54 56
+ 58 59 5A 5B 5E 5F 60 61 62 63 64 6E 6F 70 71 FF
+ FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+ FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+ FF 42 FF 52 FF 51 5C FF FF 5D 5B 5E 65 FF 67 66
+ FF 42 FF 52 FF 51 5C FF FF 5D 5B 5E 65 FF 67 66
+ 5A 43 43 43 43 51 46 45 47 49 4A 49 49 4E 4E 48
+ FF 55 54 57 56 56 56 FF 5A 5F 5F 5F 5F 63 5E FF
+ 5A 43 43 43 43 51 46 45 47 49 4A 49 49 4E 4E 48
+ FF 55 54 57 56 56 56 FF 5A 5F 5F 5F 5F 63 5E FF
diff --git a/sql/share/charsets/swe7.conf b/sql/share/charsets/swe7.conf
new file mode 100644
index 00000000000..d2de48b4d1c
--- /dev/null
+++ b/sql/share/charsets/swe7.conf
@@ -0,0 +1,74 @@
+# Configuration file for the swe7 character set
+
+# ctype array (must have 257 elements)
+ 00
+ 20 20 20 20 20 20 20 20 20 28 28 28 28 28 20 20
+ 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
+ 48 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
+ 84 84 84 84 84 84 84 84 84 84 10 10 10 10 10 10
+ 01 81 81 81 81 81 81 01 01 01 01 01 01 01 01 01
+ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 10
+ 01 82 82 82 82 82 82 02 02 02 02 02 02 02 02 02
+ 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 20
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+
+# to_lower array (must have 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 5F
+ 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F
+ 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
+ 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
+ A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF
+ B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF
+ C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
+ D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF
+ E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
+ F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF
+
+# to_upper array (must have 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F
+ 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 7F
+ 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
+ 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
+ A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF
+ B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF
+ C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
+ D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF
+ E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
+ F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF
+
+# sort_order array (must have 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 45 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 5C 5D 5B 59 5F
+ 45 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 5C 5D 5B 59 7F
+ 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
+ 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
+ A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF
+ B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF
+ C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
+ D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF
+ E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
+ F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF
diff --git a/sql/share/charsets/usa7.conf b/sql/share/charsets/usa7.conf
new file mode 100644
index 00000000000..b9e7a44c894
--- /dev/null
+++ b/sql/share/charsets/usa7.conf
@@ -0,0 +1,74 @@
+# Configuration file for the usa7 character set
+
+# ctype array (must have 257 elements)
+ 00
+ 20 20 20 20 20 20 20 20 20 28 28 28 28 28 20 20
+ 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
+ 48 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
+ 84 84 84 84 84 84 84 84 84 84 10 10 10 10 10 10
+ 10 81 81 81 81 81 81 01 01 01 01 01 01 01 01 01
+ 01 01 01 01 01 01 01 01 01 01 01 10 10 10 10 10
+ 10 82 82 82 82 82 82 02 02 02 02 02 02 02 02 02
+ 02 02 02 02 02 02 02 02 02 02 02 10 10 10 10 20
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+
+# to_lower array (must have 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 74 75 76 77 78 79 7A 5B 5C 5D 5E 5F
+ 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F
+ 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
+ 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
+ A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF
+ B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF
+ C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
+ D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF
+ E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
+ F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF
+
+# to_upper array (must have 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F
+ 60 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 7B 7C 7D 7E 7F
+ 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
+ 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
+ A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF
+ B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF
+ C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
+ D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF
+ E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
+ F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF
+
+# sort_order array (must have 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 5C 5D 5B 5E 5F
+ 45 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 7B 7C 7D 59 7F
+ 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
+ 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
+ A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF
+ B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF
+ C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
+ D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF
+ E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
+ F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF
diff --git a/sql/share/charsets/win1250.conf b/sql/share/charsets/win1250.conf
new file mode 100644
index 00000000000..31d253d7381
--- /dev/null
+++ b/sql/share/charsets/win1250.conf
@@ -0,0 +1,74 @@
+# Configuration file for the win1250 character set.
+
+# The ctype array must have 257 elements.
+ 00
+ 20 20 20 20 20 20 20 20 20 28 28 28 28 28 20 20
+ 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
+ 48 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
+ 84 84 84 84 84 84 84 84 84 84 10 10 10 10 10 10
+ 10 81 81 81 81 81 81 01 01 01 01 01 01 01 01 01
+ 01 01 01 01 01 01 01 01 01 01 01 10 10 10 10 10
+ 10 82 82 82 82 82 82 02 02 02 02 02 02 02 02 02
+ 02 02 02 02 02 02 02 02 02 02 02 10 10 10 10 20
+ 20 20 10 20 10 10 10 10 20 10 01 10 01 01 01 01
+ 20 10 10 10 10 10 10 10 20 10 02 10 02 02 02 02
+ 48 10 10 01 10 01 10 01 10 10 01 10 10 10 10 01
+ 10 10 10 02 10 10 10 10 10 02 02 10 01 10 02 02
+ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
+ 01 01 01 01 01 01 01 10 01 01 01 01 01 01 01 02
+ 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02
+ 02 02 02 02 02 02 02 10 02 02 02 02 02 02 02 10
+
+# The to_lower array must have 256 elements.
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 74 75 76 77 78 79 7A 5B 5C 5D 5E 5F
+ 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F
+ 80 81 82 83 84 85 86 87 88 89 9A 8B 9C 9D 9E 9F
+ 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
+ A0 A1 A2 B3 A4 B9 A6 DF A8 A9 BA AB AC AD AE BF
+ B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BE BD BE BF
+ E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
+ F0 F1 F2 F3 F4 F5 F6 D7 F8 F9 FA FB FC FD FE DF
+ E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
+ F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF
+
+# The to_upper array must have 256 elements.
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F
+ 60 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 7B 7C 7D 7E 7F
+ 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
+ 90 91 92 93 94 95 96 97 98 99 8A 9B 8C 8D 8E 8F
+ A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF
+ B0 B1 B2 A3 B4 B5 B6 B7 B8 A5 AA BB BC BD BC AF
+ C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
+ D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE A7
+ C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
+ D0 D1 D2 D3 D4 D5 D6 F7 D8 D9 DA DB DC DD DE FF
+
+# The sort_order array must have 256 elements.
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 41 42 43 46 49 4A 4B 4C 4D 4E 4F 50 52 53 55
+ 56 57 58 59 5B 5C 5D 5E 5F 60 61 63 64 65 66 67
+ 68 41 42 43 46 49 4A 4B 4C 4D 4E 4F 50 52 53 55
+ 56 57 58 59 5B 5C 5D 5E 5F 60 61 7B 7C 7D 7E 7F
+ 80 81 82 83 84 85 86 87 88 89 5A 8B 5A 5B 62 62
+ 90 91 92 93 94 95 96 97 98 99 5A 9B 5A 5B 62 62
+ 20 A1 A2 50 A4 41 A6 59 A8 A9 59 AB AC AD AE 62
+ B0 B1 B2 50 B4 B5 B6 B7 B8 41 59 BB 50 BD 50 62
+ 58 41 41 41 41 50 45 43 44 49 49 49 49 4D 4D 46
+ 47 53 53 55 55 55 55 D7 58 5C 5C 5C 5C 60 5B 59
+ 58 41 41 41 41 50 45 43 44 49 49 49 49 4D 4D 46
+ 47 53 53 55 55 55 55 F7 58 5C 5C 5C 5C 60 5B FF
diff --git a/sql/share/charsets/win1251.conf b/sql/share/charsets/win1251.conf
new file mode 100644
index 00000000000..21f07361327
--- /dev/null
+++ b/sql/share/charsets/win1251.conf
@@ -0,0 +1,74 @@
+# Configuration file for the win1251 character set
+
+# ctype array (must have 257 elements)
+ 00
+ 20 20 20 20 20 20 20 20 20 28 28 28 28 28 20 20
+ 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
+ 48 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
+ 84 84 84 84 84 84 84 84 84 84 10 10 10 10 10 10
+ 10 81 81 81 81 81 81 01 01 01 01 01 01 01 01 01
+ 01 01 01 01 01 01 01 01 01 01 01 10 10 10 10 10
+ 10 82 82 82 82 82 82 02 02 02 02 02 02 02 02 02
+ 02 02 02 02 02 02 02 02 02 02 02 10 10 10 10 20
+ 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
+ 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
+ 10 10 10 10 10 10 10 10 01 10 10 10 10 10 10 10
+ 10 10 10 10 10 10 10 10 02 10 10 10 10 10 10 10
+ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
+ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
+ 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02
+ 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02
+
+# to_lower array (must have 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 74 75 76 77 78 79 7A 5B 5C 5D 5E 5F
+ 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F
+ 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
+ 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
+ A0 A1 A2 A3 A4 A5 A6 A7 B8 A9 AA AB AC AD AE AF
+ B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF
+ E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
+ F0 F1 F2 F3 F4 F5 F5 F7 F8 F9 FA FB FC FD FE FF
+ E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
+ F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF
+
+# to_upper array (must have 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F
+ 60 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 7B 7C 7D 7E 7F
+ 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
+ 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
+ A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF
+ B0 B1 B2 B3 B4 B5 B6 B7 A8 B9 BA BB BC BD BE BF
+ C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
+ D0 D1 D2 D3 D4 D5 D5 D7 D8 D9 DA DB DC DD DE DF
+ C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
+ D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF
+
+# sort_order array (must have 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F
+ 60 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 7B 7C 7D 7E 7F
+ 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
+ 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
+ A0 A1 A2 A3 A4 A5 A6 A7 C6 A9 AA AB AC AD AE AF
+ B0 B1 B2 B3 B4 B5 B6 B7 C6 B9 BA BB BC BD BE BF
+ C0 C1 C2 C3 C4 C5 C7 C8 C9 CA CB CC CD CE CF D0
+ D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0
+ C0 C1 C2 C3 C4 C5 C7 C8 C9 CA CB CC CD CE CF D0
+ D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0
diff --git a/sql/share/charsets/win1251ukr.conf b/sql/share/charsets/win1251ukr.conf
new file mode 100644
index 00000000000..3f3e29ad0b4
--- /dev/null
+++ b/sql/share/charsets/win1251ukr.conf
@@ -0,0 +1,74 @@
+# Configuration file for the win1251ukr character set
+
+# ctype array (must have 257 elements)
+ 00
+ 20 20 20 20 20 20 20 20 20 28 28 28 28 28 20 20
+ 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
+ 48 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
+ 84 84 84 84 84 84 84 84 84 84 10 10 10 10 10 10
+ 10 81 81 81 81 81 81 01 01 01 01 01 01 01 01 01
+ 01 01 01 01 01 01 01 01 01 01 01 10 10 10 10 10
+ 10 82 82 82 82 82 82 02 02 02 02 02 02 02 02 02
+ 02 02 02 02 02 02 02 02 02 02 02 10 10 10 10 20
+ 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
+ 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
+ 10 10 10 10 10 01 10 10 01 10 01 10 10 10 10 01
+ 10 10 01 02 02 10 10 10 02 10 02 10 10 10 10 02
+ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
+ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
+ 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02
+ 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02
+
+# to_lower array (must have 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 74 75 76 77 78 79 7A 5B 5C 5D 5E 5F
+ 20 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F
+ 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
+ 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
+ 20 20 20 20 20 A5 20 20 A8 20 AA 20 20 20 20 AF
+ 20 20 B2 B2 A5 20 20 20 A8 20 AA 20 20 20 20 AF
+ C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
+ D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF
+ C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
+ D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF
+
+# to_upper array (must have 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F
+ 20 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 7B 7C 7D 7E 7F
+ 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
+ 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
+ 20 20 20 20 20 B4 20 20 B8 20 BA 20 20 20 20 BF
+ 20 20 B3 B3 B4 20 20 20 B8 20 BA 20 20 20 20 BF
+ E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
+ F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF
+ E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
+ F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF
+
+# sort_order array (must have 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F
+ 20 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 7B 7C 7D 7E 7F
+ A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4
+ B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4
+ C5 C6 C7 C8 C9 84 CA CB 88 CC 87 CD CE CF D0 8D
+ D1 D2 8C 8C 84 D3 D4 D5 88 D6 87 D7 D8 D9 DA 8D
+ 80 81 82 83 85 86 89 8A 8B 8E 8F 90 91 92 93 94
+ 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4
+ 80 81 82 83 85 86 89 8A 8B 8E 8F 90 91 92 93 94
+ 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4
diff --git a/sql/share/czech/errmsg.sys b/sql/share/czech/errmsg.sys
new file mode 100644
index 00000000000..e509b71a857
--- /dev/null
+++ b/sql/share/czech/errmsg.sys
Binary files differ
diff --git a/sql/share/czech/errmsg.txt b/sql/share/czech/errmsg.txt
new file mode 100644
index 00000000000..7403c915bac
--- /dev/null
+++ b/sql/share/czech/errmsg.txt
@@ -0,0 +1,209 @@
+/* Copyright Abandoned 1997 TCX DataKonsult AB & Monty Program KB & Detron HB
+ This file is public domain and comes with NO WARRANTY of any kind */
+
+/* Modifikoval Petr ¹najdr, snajdr@pvt.net, snajdr@cpress.cz v.0.01
+ ISO LATIN-8852-2
+ Upravil Jan Pazdziora, adelton@fi.muni.cz
+ Tue Nov 18 17:53:55 MET 1997 verze 0.02
+ Roz¹íøeno podle 3.21.15c Jan Pazdziora, adelton@fi.muni.cz
+ Tue Dec 2 19:08:54 MET 1997 verze 0.03
+ Roz¹íøeno podle 3.21.29 Jan Pazdziora, adelton@fi.muni.cz
+ Thu May 7 17:40:49 MET DST 1998 verze 0.04
+ Podle verze 3.22.20 upravil Jan Pazdziora, adelton@fi.muni.cz
+ Thu Apr 1 20:49:57 CEST 1999
+ Podle verze 3.23.2 upravil Jan Pazdziora, adelton@fi.muni.cz
+ Mon Aug 9 13:30:09 MET DST 1999
+*/
+
+"hashchk",
+"isamchk",
+"NE",
+"ANO",
+"Nemohu vytvoøit soubor '%-.64s' (chybový kód: %d)",
+"Nemohu vytvoøit tabulku '%-.64s' (chybový kód: %d)",
+"Nemohu vytvoøit databázi '%-.64s', chyba %d",
+"Nemohu vytvoøit databázi '%-.64s', databáze ji¾ existuje",
+"Nemohu zru¹it databázi '%-.64s', databáze neexistuje",
+"Chyba pøi ru¹ení databáze (nemohu vymazat '%-.64s', chyba %d)",
+"Chyba pøi ru¹ení databáze (nemohu vymazat adresáø '%-.64s', chyba %d)",
+"Chyba pøi výmazu '%-.64s' (chybový kód: %d)",
+"Nemohu èíst záznam v systémové tabulce",
+"Nemohu získat stav '%-.64s' (chybový kód: %d)",
+"Chyba pøi zji¹»ování pracovní adresáø (chybový kód: %d)",
+"Nemohu uzamknout soubor (chybový kód: %d)",
+"Nemohu otevøít soubor '%-.64s' (chybový kód: %d)",
+"Nemohu najít soubor '%-.64s' (chybový kód: %d)",
+"Nemohu èíst adresáø '%-.64s' (chybový kód: %d)",
+"Nemohu zmìnit adresáø na '%-.64s' (chybový kód: %d)",
+"Záznam byl zmìnìn od posledního ètení v tabulce '%-.64s'",
+"Disk je plný (%s), èekám na uvolnìní nìjakého místa ...",
+"Nemohu zapsat, zdvojený klíè v tabulce '%-.64s'",
+"Chyba pøi zavírání '%-.64s' (chybový kód: %d)",
+"Chyba pøi ètení souboru '%-.64s' (chybový kód: %d)",
+"Chyba pøi pøejmenování '%-.64s' na '%-.64s' (chybový kód: %d)",
+"Chyba pøi zápisu do souboru '%-.64s' (chybový kód: %d)",
+"'%-.64s' je zamèen proti zmìnám",
+"Tøídìní pøeru¹eno",
+"Pohled '%-.64s' pro '%-.64s' neexistuje",
+"Obsluha tabulky vrátila chybu %d",
+"Obsluha tabulky '%-.64s' nemá tento parametr",
+"Nemohu najít záznam v '%-.64s'",
+"Nesprávná informace v souboru '%-.64s'",
+"Nesprávný klíè pro tabulku '%-.64s'. Pokuste se ho opravit",
+"Starý klíèový soubor pro '%-.64s'. Opravte ho.",
+"'%-.64s' je jen pro ètení",
+"Málo pamìti. Pøestartujte daemona a zkuste znovu (je potøeba %d bytù)",
+"Málo pamìti pro tøídìní. Zvy¹te velikost tøídícího bufferu",
+"Neoèekávaný konec souboru pøi ètení '%-.64s' (chybový kód: %d)",
+"Pøíli¹ mnoho spojení",
+"Málo prostoru/pamìti pro thread",
+"Nemohu zjistit jméno stroje pro Va¹i adresu",
+"Chyba pøi ustavování spojení",
+"Pøístup pro u¾ivatele '%-.32s@%-.64s' k databázi '%-.64s' není povolen",
+"Pøístup pro u¾ivatele '%-.32s@%-.64s' (s heslem %s)",
+"Nebyla vybrána ¾ádná databáze",
+"Neznámý pøíkaz",
+"Sloupec '%-.64s' nemù¾e být null",
+"Neznámá databáze '%-.64s'",
+"Tabulka '%-.64s' ji¾ existuje",
+"Neznámá tabulka '%-.64s'",
+"Sloupec '%-.64s' v %s není zcela jasný",
+"Probíhá ukonèování práce serveru",
+"Neznámý sloupec '%-.64s' v %s",
+"Pou¾ité '%-.64s' nebylo v group by",
+"Nemohu pou¾ít group na '%-.64s'",
+"Pøíkaz obsahuje zároveò funkci sum a sloupce",
+"Poèet sloupcù neodpovídá zadané hodnotì",
+"Jméno identifikátoru '%-.64s' je pøíli¹ dlouhé",
+"Zdvojené jméno sloupce '%-.64s'",
+"Zdvojené jméno klíèe '%-.64s'",
+"Zvojený klíè '%-.64s' (èíslo klíèe %d)",
+"Chybná specifikace sloupce '%-.64s'",
+"%s blízko '%-.64s' na øádku %d",
+"Výsledek dotazu je prázdný",
+"Nejednoznaèná tabulka/alias: '%-.64s'",
+"Chybná defaultní hodnota pro '%-.64s'",
+"Definováno více primárních klíèù",
+"Zadáno pøíli¹ mnoho klíèù, je povoleno nejvíce %d klíèù",
+"Zadáno pøíli¹ mnoho èást klíèù, je povoleno nejvíce %d èástí",
+"Zadaný klíè byl pøíli¹ dlouhý, nejvìt¹í délka klíèe je %d",
+"Klíèový sloupec '%-.64s' v tabulce neexistuje",
+"Blob sloupec '%-.64s' nemù¾e být pou¾it jako klíè",
+"Pøíli¹ velká délka sloupce '%-.64s' (nejvíce %d). Pou¾ijte BLOB",
+"Mù¾ete mít pouze jedno AUTO pole a to musí být definováno jako klíè",
+"%s: pøipraven na spojení\n",
+"%s: normální ukonèení\n",
+"%s: pøijat signal %d, konèím\n",
+"%s: ukonèení práce hotovo\n",
+"%s: násilné uzavøení threadu %ld u¾ivatele '%-.64s'\n",
+"Nemohu vytvoøit IP socket",
+"Tabulka '%-.64s' nemá index odpovídající CREATE INDEX. Vytvoøte tabulku znovu",
+"Argument separátoru polo¾ek nebyl oèekáván. Pøeètìte si manuál",
+"Není mo¾né pou¾ít pevný rowlength s BLOBem. Pou¾ijte 'fields terminated by'.",
+"Soubor '%-.64s' musí být v adresáøi databáze nebo èitelný pro v¹echny",
+"Soubor '%-.64s' ji¾ existuje",
+"Záznamù: %ld Vymazáno: %ld Pøeskoèeno: %ld Varování: %ld",
+"Záznamù: %ld Zdvojených: %ld",
+"Chybná podèást klíèe -- není to øetìzec nebo je del¹í ne¾ délka èásti klíèe",
+"Není mo¾né vymazat v¹echny polo¾ky s ALTER TABLE. Pou¾ijte DROP TABLE",
+"Nemohu zru¹it '%-.64s' (provést DROP). Zkontrolujte, zda neexistují záznamy/klíèe",
+"Záznamù: %ld Zdvojených: %ld Varování: %ld",
+"INSERT TABLE '%-.64s' není dovoleno v seznamu tabulek FROM",
+"Neznámá identifikace threadu: %lu",
+"Nejste vlastníkem threadu %lu",
+"Nejsou pou¾ity ¾ádné tabulky",
+"Pøíli¹ mnoho øetìzcù pro sloupec %s a SET",
+"Nemohu vytvoøit jednoznaèné jméno logovacího souboru %s.(1-999)\n",
+"Tabulka '%-.64s' byla zamèena s READ a nemù¾e být zmìnìna",
+"Tabulka '%-.64s' nebyla zamèena s LOCK TABLES",
+"Blob polo¾ka '%-.64s' nemù¾e mít defaultní hodnotu",
+"Nepøípustné jméno databáze '%-.64s'",
+"Nepøípustné jméno tabulky '%-.64s'",
+"Zadaný 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ámá chyba",
+"Neznámá procedura %s",
+"Chybný poèet parametrù procedury %s",
+"Chybné parametry procedury %s",
+"Neznámá tabulka '%-.64s' v %s",
+"Polo¾ka '%-.64s' je zadána dvakrát",
+"Nesprávné pou¾ití funkce group",
+"Tabulka '%-.64s' pou¾ívá roz¹íøení, které v této verzi MySQL není",
+"Tabulka musí mít alespoò jeden sloupec",
+"Tabulka '%-.64s' je plná",
+"Neznámá znaková sada: '%-.64s'",
+"Pøíli¹ mnoho tabulek, MySQL jich mù¾e mít v joinu jen %d",
+"Pøíli¹ mnoho polo¾ek",
+"Øá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ø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øí¾ový odkaz. Provìøte ON podmínky",
+"Sloupec '%-.32s' je pou¾it s UNIQUE nebo INDEX, ale není definován jako NOT NULL",
+"Nemohu naèíst funkci '%-.64s'",
+"Nemohu inicializovat funkci '%-.64s'; %-.80s",
+"Pro sdílenou knihovnu nejsou povoleny cesty",
+"Funkce '%-.64s' ji¾ existuje",
+"Nemohu otevøít sdílenou knihovnu '%-.64s' (errno: %d %s)",
+"Nemohu najít funkci '%-.64s' v knihovnì'",
+"Funkce '%-.64s' není definována",
+"Stroj '%-.64s' je zablokován kvùli mnoha chybám pøi pøipojování. Odblokujete pou¾itím 'mysqladmin flush-hosts'",
+"Stroj '%-.64s' nemá povoleno se k tomuto MySQL serveru pøipojit",
+"Pou¾íváte MySQL jako anonymní u¾ivatel a anonymní u¾ivatelé nemají povoleno mìnit hesla",
+"Na zmìnu hesel ostatním musíte mít právo provést update tabulek v databázi mysql",
+"V tabulce user není ¾ádný odpovídající øádek",
+"Nalezených øádkù: %ld Zmìnìno: %ld Varování: %ld",
+"Nemohu vytvoø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èet sloupcù neodpovídá poètu hodnot na øádku %ld",
+"Nemohu znovuotevøít tabulku: '%-.64s',
+"Neplatné u¾ití hodnoty NULL",
+"Regulární výraz vrátil chybu '%-.64s'",
+"Pokud není ¾ádná GROUP BY klauzule, není dovoleno souèasné pou¾ití GROUP polo¾ek (MIN(),MAX(),COUNT()...) s ne GROUP polo¾kami",
+"Neexistuje odpovídající grant pro u¾ivatele '%-.32s' na stroji '%-.64s'",
+"%-.16s pøíkaz nepøístupný pro u¾ivatele: '%-.32s@%-.64s' pro tabulku '%-.64s'",
+"%-.16s pøíkaz nepøístupný pro u¾ivatele: '%-.32s@%-.64s' pro sloupec '%-.64s' v tabulce '%-.64s'",
+"Neplatný pøíkaz GRANT/REVOKE. Prosím, pøeètìte si v manuálu, jaká privilegia je mo¾né pou¾ít.",
+"Argument pøíkazu GRANT u¾ivatel nebo stroj je pøíli¹ dlouhý",
+"Tabulka '%-64s.%s' neexistuje",
+"Neexistuje odpovídající grant pro u¾ivatele '%-.32s' na stroji '%-.64s' pro tabulku '%-.64s'",
+"Pou¾itý pøíkaz není v této verzi MySQL povolen",
+"Va¹e syntaxe je nìjaká divná",
+"Zpo¾dìný insert threadu nebyl schopen získat po¾adovaný zámek pro tabulku %-.64s",
+"Pøíli¹ mnoho zpo¾dìných threadù",
+"Zru¹eno spojení %ld do databáze: '%-.64s' u¾ivatel: '%-.64s' (%s)",
+"Zji¹tìn pøíchozí packet del¹í ne¾ 'max_allowed_packet'",
+"Zji¹tìna chyba pøi ètení z roury spojení",
+"Zji¹tìna chyba fcntl()",
+"Pøíchozí packety v chybném poøadí",
+"Nemohu rozkomprimovat komunikaèní packet",
+"Zji¹tìna chyba pøi ètení komunikaèního packetu",
+"Zji¹tìn timeout pøi ètení komunikaèního packetu",
+"Zji¹tìna chyba pøi zápisu komunikaèního packetu",
+"Zji¹tìn timeout pøi zápisu komunikaèního packetu",
+"Výsledný øetìzec je del¹í ne¾ max_allowed_packet",
+"Typ pou¾ité tabulky nepodporuje BLOB/TEXT sloupce",
+"Typ pou¾ité tabulky nepodporuje AUTO_INCREMENT sloupce",
+"INSERT DELAYED není mo¾no s tabulkou '%-.64s' pou¾ít, proto¾e je zamèená pomocí LOCK TABLES",
+"Nesprávné jméno sloupce '%-.100s'",
+"Handler pou¾ité tabulky neumí indexovat sloupce '%-.64s'",
+"V¹echny tabulky v MERGE tabulce nejsou definovány stejnì",
+"Kvùli unique constraintu nemozu zapsat do tabulky '%-.64s'",
+"BLOB sloupec '%-.64s' je pou¾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",-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
++"Handler tabulky nepodporuje check/repair",
+"You are not allowed to execute this command in a transaction",
+"Got error %d during COMMIT",
+"Got error %d during ROLLBACK",
+"Got error %d during FLUSH_LOGS",
+"Got error %d during CHECKPOINT",
+"Aborted connection %ld to db: '%-.64s' user: '%-.32s' host: `%-.64s' (%-.64s)",
+"The handler for the table does not support binary table dump",
+"Binlog closed while trying to FLUSH MASTER",
+"Failed rebuilding the index of dumped table '%-.64s'",
+"Error from master: '%-.64s'",
+"Net error reading from master",
+"Net error writing to master",
+"Can't find FULLTEXT index matching the column list",
diff --git a/sql/share/danish/errmsg.sys b/sql/share/danish/errmsg.sys
new file mode 100644
index 00000000000..e59cb624472
--- /dev/null
+++ b/sql/share/danish/errmsg.sys
Binary files differ
diff --git a/sql/share/danish/errmsg.txt b/sql/share/danish/errmsg.txt
new file mode 100644
index 00000000000..18dd8ce09b8
--- /dev/null
+++ b/sql/share/danish/errmsg.txt
@@ -0,0 +1,198 @@
+/* Copyright Abandoned 1997 TCX DataKonsult AB & Monty Program KB & Detron HB
+ This file is public domain and comes with NO WARRANTY of any kind */
+
+/* Knud Riishøjgård knudriis@post.tele.dk 99 &&
+ Carsten H. Pedersen, carsten.pedersen@bitbybit.dk oct. 1999 */
+
+"hashchk",
+"isamchk",
+"NEJ",
+"JA",
+"Kan ikke oprette filen '%-.64s' (Fejlkode: %d)",
+"Kan ikke opprette tabellen '%-.64s' (Fejlkode: %d)",
+"Kan ikke oprette databasen '%-.64s'. Fejl %d",
+"Kan ikke oprette databasen '%-.64s'. Databasen eksisterer",
+"Kan ikke slette (droppe) '%-.64s'. Databasen eksisterer ikke",
+"Fejl ved sletning (drop) af databasen (kan ikke slette '%-.64s', Fejl %d)",
+"Fejl ved sletting af database (kan ikke slette biblioteket '%-.64s', Fejl %d)",
+"Fejl ved sletning af '%-.64s' (Fejlkode: %d)",
+"Kan ikke læse posten i systembiblioteket",
+"Kan ikke læse status af '%-.64s' (Fejlkode: %d)",
+"Kan ikke læse aktive bibliotek (Fejlkode: %d)",
+"Kan ikke låse fil (Fejlkode: %d)",
+"Kan ikke åbne fil: '%-.64s'. (Fejlkode: %d)",
+"Kan ikke finde fila: '%-.64s' (Fejlkode: %d)",
+"Kan ikke læse bibliotek '%-.64s' (Fejlkode: %d)",
+"Kan ikke skifte bibliotek til '%-.64s' (Fejlkode: %d)",
+"Posten erændret siden sidst læst '%-.64s'",
+"Ikke mere diskplads (%s). Venter på at få frigjort plads....",
+"Kan ikke skrive, flere ens nøgler i tabellen '%-.64s'",
+"Fejl ved lukning af '%-.64s' (Fejlkode: %d)",
+"Fejl ved læsning af '%-.64s' (Fejlkode: %d)",
+"Fejl ved omdøbning af '%-.64s' til '%-.64s' (Fejlkode: %d)",
+"Fejl ved skriving av filen '%-.64s' (Fejlkode: %d)",
+"'%-.64s' er låst mod opdateringer",
+"Sortering afbrutt",
+"View '%-.64s' eksisterer ikke for '%-.64s'",
+"Modtog fejl %d fra tabel håndterer",
+"Tabel håndtereren for '%-.64s' har ikke denne mulighed",
+"Kan ikke finde posten i '%-.64s'",
+"Forkert indhold i: '%-.64s'",
+"Fejl i indeksfilen til tabellen '%-.64s', prøv at reparere den",
+"Gammel indeksfil for tabellen '%-.64s'; Reparer den",
+"'%-.64s' er skrivebeskyttet",
+"Ikke mere hukommelse. Genstart serveren og prøv igen (mangler %d bytes)",
+"Ikke mere sorteringshukommelse. Øg sorteringshukommelse (sort buffer size) for serveren",
+"Uventet sluttning af fil (eof) ved læsning af filen '%-.64s' (Fejlkode: %d)",
+"For mange tilkoblinger (connections)",
+"Udgået for tråde/hukommelse",
+"Kan ikke få værtsnavn for din adresse",
+"Forkert håndtryk (handshake)",
+"Adgang nægtet bruger: '%-.32s@%-.64s' til databasen '%-.64s'",
+"Adgang nægtet bruger: '%-.32s@%-.64s' (Bruger password: %s)",
+"Ingen database valgt",
+"Ukendt kommando",
+"Kolonne '%-.64s' kan ikke være nul",
+"Ukendt database '%-.64s'",
+"Tabellen '%-.64s' eksisterer allerede",
+"Ukendt tabel '%-.64s'",
+"Felt: '%-.64s' i tabel %s er ikke entydigt",
+"Database nedkobling er i gang",
+"Ukendt kolonne '%-.64s' i tabel %s",
+"Grugte '%-.64s' som ikke var i group by",
+"Kan ikke gruppere på '%-.64s'",
+"Udtrykket har summer (sum) funktioner og kolonner i samme udtryk",
+"Kolonne tæller stemmer ikke med værditæller",
+"Identifikationen '%-.64s' er for lang",
+"Feltnavnet '%-.64s' eksisterer allerede",
+"Indeksnavnet '%-.64s' eksisterer allerede",
+"Ens værdier '%-.64s' for indeks %d",
+"Forkert kolonnespecifikaton for felt '%-.64s'",
+"%s nær '%-.64s' på linje %d",
+"Forespørgsel var tom",
+"Ikke unikt tabel/alias: '%-.64s'",
+"Ugyldig standardværdi for '%-.64s'",
+"Flere primærindekser specificeret",
+"For mange indekser specificeret. Maks %d indekser tillatt",
+"For mange indeksdele specificeret. Maks %d dele tillatt",
+"Specificeret indeks var for langt. Maks indekslængde er %d",
+"Indeks felt '%-.64s' eksiterer ikke i tabellen",
+"Blob felt '%-.64s' kan ikke bruges ved specifikation af indeks",
+"For stor feltlængde for kolonne '%-.64s' (maks = %d). Brug BLOB i stedet",
+"Der kan kun bruges eet AUTO-felt og det skal være indekseret",
+"%s: klar for tilslutninger\n",
+"%s: Normal nedlukning\n",
+"%s: Opdaget signal %d. Afslutter!!\n",
+"%s: Server lukket\n",
+"%s: Forceret nedlukning af tråd: %ld bruger: '%-.64s'\n",
+"Kan ikke oprette IP socket",
+"Tabellen '%-.64s' har intet indeks som det der er brugt i CREATE INDEX. Genopret tabellen",
+"Felt adskiller er ikke som forventet, se dokumentationen",
+"Man kan ikke bruge faste feltlængder med BLOB. Brug i stedet 'fields terminated by'.",
+"Filen '%-.64s' skal være i database-biblioteket for at kunne læses af alle",
+"Filen '%-.64s' eksisterer allerede",
+"Poster: %ld Fjernet: %ld Sprunget over: %ld Advarsler: %ld",
+"Poster: %ld Ens: %ld",
+"Forkert indeksdel. Den anvendte indeksdel er ikke en streng eller den længden er større end indekslængden",
+"Man kan ikke slette alle felter med ALTER TABLE. Brug DROP TABLE i stedet.",
+"Kan ikke DROP '%-.64s'. Undersøg om felt/indeks eksisterer.",
+"Poster: %ld Ens: %ld Advarsler: %ld",
+"INSERT TABLE '%-.64s' er ikke tilladt i FROM tabel liste",
+"Ukendt tråd id: %lu",
+"Du er ikke ejer av tråden %lu",
+"Ingen tabeller i brug",
+"For mange tekststrenge kolonne %s og SET",
+"Kan ikke lave unikt loggfilnavn %s.(1-999)\n",
+"Tabellen '%-.64s' var låst med READ lås og kan ikke opdateres",
+"Tabellen '%-.64s' var ikke låst med LOCK TABLES",
+"Blob feltet '%-.64s' kan ikke have en standard værdi",
+"Ugyldigt database navn '%-.64s'",
+"Ugyldigt tabel navn '%-.64s'",
+"SELECT ville undersøge for mange poster og ville sannsynligvis tage meget lang tid. Undersøg WHERE delen og brug SET OPTION SQL_BIG_SELECTS=1 hvis SELECTen er korrekt"
+"Ukendt fejl",
+"Ukendt procedure %s",
+"Forkert antal parametre til proceduren %s",
+"Forkert(e) parametre til proceduren %s",
+"Ukendt tabel '%-.64s' i %s",
+"Feltet '%-.64s' er anvendt to ganger",
+"Forkert brug af gruppe-funktion",
+"Tabellen '%-.64s' bruger et efternavn som ikke findes i denne MySQL version",
+"En tabel skal have mindst een kolonne",
+"Tabellen '%-.64s' er fuld",
+"Ukendt karaktersæt: '%-.64s'",
+"For mange tabeller. MySQL kan kun bruge %d tabeller i et join",
+"For mange felter",
+"For store poster. Max post størrelse, unde BOLB's, er %d. Du må lave nogle felter til BLOB's",
+"Thread stack brugt: Brugt: %ld af en %ld stak. Brug 'mysqld -O thread_stack=#' for at allokere en større stak om nødvendigt",
+"Krydsreferencer fundet i OUTER JOIN. Check dine ON conditions",
+"Kolonne '%-.32s' bruges som UNIQUE eller INDEX men er ikke defineret som NOT NULL",
+"Kan ikke læse funktionen '%-.64s'",
+"Kan ikke starte funktionen '%-.64s'; %-.80s",
+"Ingen sti tilladte for delt bibliotek",
+"Funktionen '%-.64s' findes allerede",
+"Kan ikke åbne delt bibliotek '%-.64s' (errno: %d %s)",
+"Kan ikke finde funktionen '%-.64s' in bibliotek'",
+"Funktionen '%-.64s' er ikke defineret",
+"Værten er blokeret på grund af mange fejlforespørgsler. Lås op med 'mysqladmin flush-hosts'",
+"Værten '%-.64s' kan ikke tilkoble denne MySQL-server",
+"Du bruger MySQL som anonym bruger. Anonyme brugere må ikke ændre adgangskoder",
+"Du skal have tilladelse til at opdatere tabeller i MySQL databasen for at ændre andres adgangskoder",
+"Kan ikke finde nogen tilsvarende poster i bruger tabellen",
+"Poster fundet: %ld Ændret: %ld Advarsler: %ld",
+"Kan ikke danne en ny tråd (thread) (errno %d). Hvis computeren ikke er løbet tør for hukommelse, kan du se i brugervejledningen for en mulig operativ-system - afhængig fejl",
+"Kolonne antallet stemmer ikke overens med antallet af værdier i post %ld",
+"Kan ikke genåbne tabel '%-.64s',
+"Forkert brug af nulværdi (NULL)",
+"Fik fejl '%-.64s' fra regexp",
+"Sammenblanding af GROUP kolonner (MIN(),MAX(),COUNT()...) uden GROUP kolonner er ikke tilladt, hvis der ikke er noget GROUP BY prædikat",
+"Denne tilladelse findes ikke for brugeren '%-.32s' på vært '%-.64s'",
+"%-.16s-kommandoen er ikke tilladt for brugeren '%-.32s@%-.64s' for tabellen '%-.64s'",
+"%-.16s-kommandoen er ikke tilladt for brugeren '%-.32s@%-.64s' for kolonne '%-.64s' in tabellen '%-.64s'",
+"Forkert GRANT/REVOKE kommando. Se i brugervejledningen hvilke privilegier der kan specificeres.",
+"Værts- eller brugernavn for langt til GRANT",
+"Tabellen '%-.64s.%-.64s' eksisterer ikke",
+"Denne tilladelse eksisterer ikke for brugeren '%-.32s' på vært '%-.64s' for tabellen '%-.64s'",
+"Den brugte kommando er ikke tilladt med denne udgave af MySQL",
+"Der er en fejl i SQL syntaksen",
+"Forsinket indsættelse tråden (delayed insert thread) kunne ikke opnå lås på tabellen %-.64s",
+"For mange slettede tråde (threads) i brug",
+"Afbrudt forbindelse %ld til database: '%-.64s' bruger: '%-.64s' (%-.64s)",
+"Modtog en datapakke som var større end 'max_allowed_packet'",
+"Fik læsefejl fra forbindelse (connection pipe)",
+"Fik fejlmeddelelse fra fcntl()",
+"Modtog ikke datapakker i korrekt rækkefølge",
+"Kunne ikke dekomprimere kommunikations-pakke (communication packet)",
+"Fik fejlmeddelelse ved læsning af kommunikations-pakker (communication packets)"
+"Timeout-fejl ved læsning af kommunukations-pakker (communication packets)",
+"Fik fejlmeddelelse ved skrivning af kommunukations-pakker (communication packets)",
+"Timeout-fejl ved skrivning af kommunukations-pakker (communication packets)",
+"Strengen med resultater er større end max_allowed_packet",
+"Denne tabeltype understøtter ikke brug af BLOB og TEXT kolonner",
+"Denne tabeltype understøtter ikke brug af AUTO_INCREMENT kolonner",
+"INSERT DELAYED kan ikke bruges med tabellen '%-.64s', fordi tabellen er låst med LOCK TABLES",
+"Forkert kolonnenavn '%-.100s'",
+"Den brugte tabel styrer kan ikke indeksere kolonnen '%-.64s'",
+"Tabellerne i MERGE er ikke defineret ens",
+"Kan ikke skrive til tabellen '%-.64s' fordi det vil bryde CONSTRAINT regler",
+"BLOB column '%-.64s' used in key specification without a key length",
+"All parts of a PRIMARY KEY must be NOT NULL; If you need NULL in a key, use UNIQUE instead",
+"Result consisted of more than one row",
+"This table type requires a primary key",
+"This version of MySQL is not compiled with RAID support",
+"You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column",
+"Key '%-.64s' doesn't exist in table '%-.64s'",
+"Can't open table",
+"The handler for the table doesn't support check/repair",
+"You are not allowed to execute this command in a transaction",
+"Got error %d during COMMIT",
+"Got error %d during ROLLBACK",
+"Got error %d during FLUSH_LOGS",
+"Got error %d during CHECKPOINT",
+"Aborted connection %ld to db: '%-.64s' user: '%-.32s' host: `%-.64s' (%-.64s)",
+"The handler for the table does not support binary table dump",
+"Binlog closed while trying to FLUSH MASTER",
+"Failed rebuilding the index of dumped table '%-.64s'",
+"Error from master: '%-.64s'",
+"Net error reading from master",
+"Net error writing to master",
+"Can't find FULLTEXT index matching the column list",
diff --git a/sql/share/dutch/errmsg.sys b/sql/share/dutch/errmsg.sys
new file mode 100644
index 00000000000..0950a8d9bc4
--- /dev/null
+++ b/sql/share/dutch/errmsg.sys
Binary files differ
diff --git a/sql/share/dutch/errmsg.txt b/sql/share/dutch/errmsg.txt
new file mode 100644
index 00000000000..960200aa182
--- /dev/null
+++ b/sql/share/dutch/errmsg.txt
@@ -0,0 +1,195 @@
+/* Copyright Abandoned 1997 TCX DataKonsult AB & Monty Program KB & Detron HB
+ This file is public domain and comes with NO WARRANTY of any kind */
+
+"hashchk",
+"isamchk",
+"NEE",
+"JA",
+"Kan file '%-.64s' niet aanmaken. (Errcode: %d)",
+"Kan tabel '%-.64s' niet aanmaken. (Errcode: %d)",
+"Kan database '%-.64s' niet aanmaken. Error %d",
+"Kan database '%-.64s' niet aanmaken. Database bestaat al",
+"Kan database '%-.64s' niet verwijderen. Database bestaat niet",
+"Error verwijderen database (kan '%-.64s' niet verwijderen, error %d)",
+"Error verwijderen database (kan rmdir '%-.64s' niet uitvoeren, error %d)",
+"Error bij het verwijderen van '%-.64s' (Errcode: %d)",
+"Kan record niet lezen in de systeem tabel",
+"Kan de status niet krijgen van '%-.64s' (Errcode: %d)",
+"Kan de werkdirectory niet krijgen (Errcode: %d)",
+"Kan de file niet blokeren (Errcode: %d)",
+"Kan de file '%-.64s' niet openen. (Errcode: %d)",
+"Kan de file: '%-.64s' niet vinden. (Errcode: %d)",
+"Kan de directory niet lezen van '%-.64s' (Errcode: %d)",
+"Kan de directory niet veranderen naar '%-.64s' (Errcode: %d)",
+"Record is veranderd sinds de laatste lees activiteit in de tabel '%-.64s'",
+"Schijf vol (%s). Aan het wachten totdat er ruimte vrij wordt gemaakt...",
+"Kan niet schrijven, dubbele key in tabel '%-.64s'",
+"Fout bij het sluiten van '%-.64s' (Errcode: %d)",
+"Fout bij het lezen van file '%-.64s' (Errcode: %d)",
+"Fout bij het hernoemen van '%-.64s' naar '%-.64s' (Errcode: %d)",
+"Fout bij het wegschrijven van file '%-.64s' (Errcode: %d)",
+"'%-.64s' is geblokeerd tegen veranderingen",
+"Sorteren afgebroken",
+"View '%-.64s' bestaat niet voorr '%-.64s'",
+"Fout %d van tabel handler",
+"Tabel handler voor '%-.64s' heeft deze optie niet",
+"Kan record niet vinden in '%-.64s'",
+"Verkeerde info in file: '%-.64s'",
+"Verkeerde key file voor tabel: '%-.64s'. Probeer het te repareren",
+"Oude key file voor tabel '%-.64s'; Repareer het!",
+"'%-.64s' is alleen leesbaar",
+"Geen geheugen meer. Herstart server en probeer opnieuw (%d bytes nodig)",
+"Geen geheugen om te sorteren. Verhoog de server sort buffer size",
+"Onverwachte eof gevonden tijdens het lezen van file '%-.64s' (Errcode: %d)",
+"Te veel verbindingen",
+"Geen thread geheugen meer",
+"Kan de hostname niet krijgen van jou adres",
+"Verkeerde handshake",
+"Toegang geweigerd voor gebruiker: '%-.32s@%-.64s' naar database '%-.64s'",
+"Toegang geweigerd voor gebruiker: '%-.32s@%-.64s' (Wachtwoord gebruikt: %s)",
+"Geen database geselecteerd",
+"Onbekend commando",
+"Kolom '%-.64s' kan niet null zijn",
+"Onbekende database '%-.64s'",
+"Tabel '%-.64s' bestaat al",
+"Onbekende tabel '%-.64s'",
+"Kolom: '%-.64s' in %s is ambiguous",
+"Bezig met het stoppen van de server",
+"Onbekende kolom '%-.64s' in %s",
+"Opdracht gebruikt '%-.64s' dat niet in de group by voorkomt",
+"Kan '%-.64s' niet groeperen",
+"Opdracht heeft totaliseer functies en kolommen in dezelfde opdracht",
+"Het aantal kolommen komt niet overeen met het aantal opgegeven waardes",
+"Naam voor herkenning '%-.64s' is te lang",
+"Dubbele kolom naam '%-.64s'",
+"Dubbele sleutel naam '%-.64s'",
+"Dubbele ingang '%-.64s' voor sleutel %d",
+"Verkeerde kolom specificatie voor kolom '%-.64s'",
+"%s bij '%-.64s' in regel %d",
+"Query was leeg",
+"Niet unieke waarde tabel/alias: '%-.64s'",
+"Foutieve standaard waarde voor '%-.64s'",
+"Meerdere primaire sleutels gedefinieerd",
+"Teveel sleutels gedifinieerd. Maximaal zijn %d sleutels toegestaan",
+"Teveel sleutel onderdelen gespecificeerd. Maximaal %d onderdelen toegestaan",
+"Gespecificeerde sleutel was te lang. De maximale lengte is %d",
+"Sleutel kolom '%-.64s' bestaat niet in tabel",
+"Blob kolom '%-.64s' kan niet gebruikt worden bij key specificatie",
+"Te grote kolomlengte voor '%-.64s' (max = %d). Maak hiervoor gebruik van het type BLOB",
+"Er kan slechts 1 autofield zijn en deze moet als sleutel worden gedefinieerd.",
+"%s: klaar voor verbindingen\n",
+"%s: Normaal afgesloten \n",
+"%s: Signaal %d. Systeem breekt af!\n",
+"%s: Afsluiten afgerond\n",
+"%s: Afsluiten afgedwongen van thread %ld gebruiker: '%-.64s'\n",
+"Kan IP-socket niet openen",
+"Tabel '%-.64s' heeft geen INDEX zoals deze gemaakt worden met CREATE INDEX. Maak de tabel opnieuw",
+"De argumenten om velden te scheiden zijn anders dan verwacht. Controleer de handleiding","
+"Bij het gebruik van BLOBs is het niet mogelijk om vaste rijlengte te gebruiken. Maak s.v.p. gebruik van 'fields terminated by'.",
+"Het bestand '%-.64s' dient in de database directory voor the komen of leesbaar voor iedereen te zijn.",
+"Het bestand '%-.64s' bestaat reeds",
+"Records: %ld Verwijderd: %ld Overgeslagen: %ld Waarschuwingen: %ld",
+"Records: %ld Dubbel: %ld",
+"Foutief sub-gedeelte van de sleutel. De gebruikte sleutel is geen onderdeel van een string of of de gebruikte lengte is langer dan de sleutel",
+"Het is niet mogelijk alle velden te verwijderen met ALTER TABLE. Gebruik a.u.b. DROP TABLE hiervoor!",
+"Kan '%-.64s' niet weggooien. Controleer of het veld of de sleutel daadwerkelijk bestaat.",
+"Records: %ld Dubbel: %ld Waarschuwing: %ld",
+"INSERT TABLE '%-.64s' is niet toegestaan in de FROM tabel-lijst",
+"Onbekend thread id: %lu",
+"U bent geen bezitter van thread %lu",
+"Geen tabellen gebruikt.",
+"Teveel strings voor kolom %s en SET",
+"Het is niet mogelijk een unieke naam te maken voor de logfile %s.(1-999)\n",
+"Tabel '%-.64s' was gelocked met een lock om te lezen. Derhalve kunnen geen wijzigingen worden opgeslagen.",
+"Table '%-.64s' was niet gelocked met LOCK TABLES",
+"Blob veld '%-.64s' can geen standaardwaarde bevatten",
+"Databasenaam '%-.64s' is niet getoegestaan",
+"Niet toegestane tabelnaam '%-.64s'",
+"Het SELECT-statement zou te veel records analyseren en dus veel tijd in beslagnemen. Kijk het WHERE-gedeelte van de query na en kies SET OPTION SQL_BIG_SELECTS=1 als het stament in orde is.",
+"Onbekende Fout",
+"Onbekende procedure %s",
+"Foutief aantal parameters doorgegeven aan procedure %s",
+"Foutieve parameters voor procedure %s",
+"Onbekende tabel '%-.64s' in %s",
+"Veld '%-.64s' is dubbel gespecificeerd",
+"Ongeldig gebruik van GROUP-functie",
+"Tabel '%-.64s' gebruikt een extensie, die niet in deze MySQL-versie voorkomt.",
+"Een tabel moet minstens 1 kolom bevatten",
+"De tabel '%-.64s' is vol",
+"Onbekende character set: '%-.64s'",
+"Teveel tabellen. MySQL kan slechts %d tabellen in een join bevatten",
+"Te veel velden",
+"Rij-grootte is groter dan toegestaan. Maximale rij grootte, blobs niet meegeteld, is %d. U dient sommige velden in blobs te veranderen.",
+"Thread stapel overrun: Gebruikte: %ld van een %ld stack. Gebruik 'mysqld -O thread_stack=#' om een grotere stapel te definieren (indien noodzakelijk).",
+"Gekruiste afhankelijkheid gevonden in OUTER JOIN. Controleer uw ON-conditions",
+"Column '%-.64s' is used with UNIQUE or INDEX but is not defined as NOT NULL",
+"Can't load function '%-.64s'",
+"Can't initialize function '%-.64s'; %-.80s",
+"No paths allowed for shared library",
+"Function '%-.64s' already exist",
+"Can't open shared library '%-.64s' (errno: %d %s)",
+"Can't find function '%-.64s' in library'",
+"Function '%-.64s' is not defined",
+"Host '%-.64s' is blocked because of many connection errors. Unblock with 'mysqladmin flush-hosts'",
+"Host '%-.64s' is not allowed to connect to this MySQL server",
+"You are using MySQL as an anonymous users and anonymous users are not allowed to change passwords",
+"You must have privileges to update tables in the mysql database to be able to change passwords for others",
+"Can't find any matching row in the user table",
+"Rows matched: %ld Changed: %ld Warnings: %ld",
+"Can't create a new thread (errno %d). If you are not out of available memory you can consult the manual for any possible OS dependent bug",
+"Column count doesn't match value count at row %ld",
+"Can't reopen table: '%-.64s',
+"Invalid use of NULL value",
+"Got error '%-.64s' from regexp",
+"Mixing of GROUP columns (MIN(),MAX(),COUNT()...) with no GROUP columns is illegal if there is no GROUP BY clause",
+"There is no such grant defined for user '%-.32s' on host '%-.64s'",
+"%-.16s command denied to user: '%-.32s@%-.64s' for table '%-.64s'",
+"%-.16s command denied to user: '%-.32s@%-.64s' for column '%-.64s' in table '%-.64s'",
+"Illegal GRANT/REVOKE command. Please consult the manual which privleges can be used.",
+"The host or user argument to GRANT is too long",
+"Table '%-64s.%s' doesn't exist",
+"There is no such grant defined for user '%-.32s' on host '%-.64s' on table '%-.64s'",
+"The used command is not allowed with this MySQL version",
+"Something is wrong in your syntax",
+"Delayed insert thread couldn't get requested lock for table %-.64s",
+"Too many delayed threads in use",
+"Aborted connection %ld to db: '%-.64s' user: '%-.64s' (%s)",
+"Got a packet bigger than 'max_allowed_packet'",
+"Got a read error from the connection pipe",
+"Got an error from fcntl()",
+"Got packets out of order",
+"Couldn't uncompress communication packet",
+"Got an error reading communication packets"
+"Got timeout reading communication packets",
+"Got an error writing communication packets",
+"Got timeout writing communication packets",
+"Result string is longer than max_allowed_packet",
+"The used table type doesn't support BLOB/TEXT columns",
+"The used table type doesn't support AUTO_INCREMENT columns",
+"INSERT DELAYED can't be used with table '%-.64s', because it is locked with LOCK TABLES",
+"Incorrect column name '%-.100s'",
+"The used table handler can't index column '%-.64s'",
+"All tables in the MERGE table are not defined identically",
+"Can't write, because of unique constraint, to table '%-.64s'",
+"BLOB column '%-.64s' used in key specification without a key length",
+"All parts of a PRIMARY KEY must be NOT NULL; If you need NULL in a key, use UNIQUE instead",
+"Result consisted of more than one row",
+"This table type requires a primary key",
+"This version of MySQL is not compiled with RAID support",
+"You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column",
+"Key '%-.64s' doesn't exist in table '%-.64s'",
+"Can't open table",
+"The handler for the table doesn't support check/repair",
+"You are not allowed to execute this command in a transaction",
+"Got error %d during COMMIT",
+"Got error %d during ROLLBACK",
+"Got error %d during FLUSH_LOGS",
+"Got error %d during CHECKPOINT",
+"Aborted connection %ld to db: '%-.64s' user: '%-.32s' host: `%-.64s' (%-.64s)",
+"The handler for the table does not support binary table dump",
+"Binlog closed while trying to FLUSH MASTER",
+"Failed rebuilding the index of dumped table '%-.64s'",
+"Error from master: '%-.64s'",
+"Net error reading from master",
+"Net error writing to master",
+"Can't find FULLTEXT index matching the column list",
diff --git a/sql/share/english/errmsg.sys b/sql/share/english/errmsg.sys
new file mode 100644
index 00000000000..7451111fcce
--- /dev/null
+++ b/sql/share/english/errmsg.sys
Binary files differ
diff --git a/sql/share/english/errmsg.txt b/sql/share/english/errmsg.txt
new file mode 100644
index 00000000000..7c456a6f592
--- /dev/null
+++ b/sql/share/english/errmsg.txt
@@ -0,0 +1,195 @@
+/* Copyright Abandoned 1997 TCX DataKonsult AB & Monty Program KB & Detron HB
+ This file is public domain and comes with NO WARRANTY of any kind */
+
+"hashchk",
+"isamchk",
+"NO",
+"YES",
+"Can't create file '%-.64s' (errno: %d)",
+"Can't create table '%-.64s' (errno: %d)",
+"Can't create database '%-.64s'. (errno: %d)",
+"Can't create database '%-.64s'. Database exists",
+"Can't drop database '%-.64s'. Database doesn't exist",
+"Error dropping database (can't delete '%-.64s', errno: %d)",
+"Error dropping database (can't rmdir '%-.64s', errno: %d)",
+"Error on delete of '%-.64s' (errno: %d)",
+"Can't read record in system table",
+"Can't get status of '%-.64s' (errno: %d)",
+"Can't get working directory (errno: %d)",
+"Can't lock file (errno: %d)",
+"Can't open file: '%-.64s'. (errno: %d)",
+"Can't find file: '%-.64s' (errno: %d)",
+"Can't read dir of '%-.64s' (errno: %d)",
+"Can't change dir to '%-.64s' (errno: %d)",
+"Record has changed since last read in table '%-.64s'",
+"Disk full (%s). Waiting for someone to free some space....",
+"Can't write, duplicate key in table '%-.64s'",
+"Error on close of '%-.64s' (errno: %d)",
+"Error reading file '%-.64s' (errno: %d)",
+"Error on rename of '%-.64s' to '%-.64s' (errno: %d)",
+"Error writing file '%-.64s' (errno: %d)",
+"'%-.64s' is locked against change",
+"Sort aborted",
+"View '%-.64s' doesn't exist for '%-.64s'",
+"Got error %d from table handler",
+"Table handler for '%-.64s' doesn't have this option",
+"Can't find record in '%-.64s'",
+"Incorrect information in file: '%-.64s'",
+"Incorrect key file for table: '%-.64s'. Try to repair it",
+"Old key file for table '%-.64s'; Repair it!",
+"Table '%-.64s' is read only",
+"Out of memory. Restart daemon and try again (needed %d bytes)",
+"Out of sort memory. Increase daemon sort buffer size",
+"Unexpected eof found when reading file '%-.64s' (errno: %d)",
+"Too many connections",
+"Out of memory; Check if mysqld or some other process uses all available memory. If not you may have to use 'ulimit' to allow mysqld to use more memory or you can add more swap space",
+"Can't get hostname for your address",
+"Bad handshake",
+"Access denied for user: '%-.32s@%-.64s' to database '%-.64s'",
+"Access denied for user: '%-.32s@%-.64s' (Using password: %s)",
+"No Database Selected",
+"Unknown command",
+"Column '%-.64s' cannot be null",
+"Unknown database '%-.64s'",
+"Table '%-.64s' already exists",
+"Unknown table '%-.64s'",
+"Column: '%-.64s' in %-.64s is ambiguous",
+"Server shutdown in progress",
+"Unknown column '%-.64s' in '%-.64s'",
+"'%-.64s' isn't in GROUP BY",
+"Can't group on '%-.64s'",
+"Statement has sum functions and columns in same statement",
+"Column count doesn't match value count",
+"Identifier name '%-.100s' is too long",
+"Duplicate column name '%-.64s'",
+"Duplicate key name '%-.64s'",
+"Duplicate entry '%-.64s' for key %d",
+"Incorrect column specifier for column '%-.64s'",
+"%s near '%-.80s' at line %d",
+"Query was empty",
+"Not unique table/alias: '%-.64s'",
+"Invalid default value for '%-.64s'",
+"Multiple primary key defined",
+"Too many keys specified. Max %d keys allowed",
+"Too many key parts specified. Max %d parts allowed",
+"Specified key was too long. Max key length is %d",
+"Key column '%-.64s' doesn't exist in table",
+"BLOB column '%-.64s' can't be used in key specification with the used table type",
+"Too big column length for column '%-.64s' (max = %d). Use BLOB instead",
+"Incorrect table definition; There can only be one auto column and it must be defined as a key",
+"%s: ready for connections\n",
+"%s: Normal shutdown\n",
+"%s: Got signal %d. Aborting!\n",
+"%s: Shutdown Complete\n",
+"%s: Forcing close of thread %ld user: '%-.32s'\n",
+"Can't create IP socket",
+"Table '%-.64s' has no index like the one used in CREATE INDEX. Recreate the table",
+"Field separator argument is not what is expected. Check the manual","
+"You can't use fixed rowlength with BLOBs. Please use 'fields terminated by'.",
+"The file '%-.64s' must be in the database directory or be readable by all",
+"File '%-.80s' already exists",
+"Records: %ld Deleted: %ld Skipped: %ld Warnings: %ld",
+"Records: %ld Duplicates: %ld",
+"Incorrect sub part key. The used key part isn't a string or the used length is longer than the key part",
+"You can't delete all columns with ALTER TABLE. Use DROP TABLE instead",
+"Can't DROP '%-.64s'. Check that column/key exists",
+"Records: %ld Duplicates: %ld Warnings: %ld",
+"INSERT TABLE '%-.64s' isn't allowed in FROM table list",
+"Unknown thread id: %lu",
+"You are not owner of thread %lu",
+"No tables used",
+"Too many strings for column %-.64s and SET",
+"Can't generate a unique log-filename %-.64s.(1-999)\n",
+"Table '%-.64s' was locked with a READ lock and can't be updated",
+"Table '%-.64s' was not locked with LOCK TABLES",
+"BLOB column '%-.64s' can't have a default value",
+"Incorrect database name '%-.100s'",
+"Incorrect table name '%-.100s'",
+"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",
+"Unknown error",
+"Unknown procedure '%-.64s'",
+"Incorrect parameter count to procedure '%-.64s'",
+"Incorrect parameters to procedure '%-.64s'",
+"Unknown table '%-.64s' in %-.32s",
+"Column '%-.64s' specified twice",
+"Invalid use of group function",
+"Table '%-.64s' uses an extension that doesn't exist in this MySQL version",
+"A table must have at least 1 column",
+"The table '%-.64s' is full",
+"Unknown character set: '%-.64s'",
+"Too many tables. MySQL can only use %d tables in a join",
+"Too many columns",
+"Too big row size. The maximum row size, not counting BLOBs, is %d. You have to change some fields to BLOBs",
+"Thread stack overrun: Used: %ld of a %ld stack. Use 'mysqld -O thread_stack=#' to specify a bigger stack if needed",
+"Cross dependency found in OUTER JOIN. Examine your ON conditions",
+"Column '%-.64s' is used with UNIQUE or INDEX but is not defined as NOT NULL",
+"Can't load function '%-.64s'",
+"Can't initialize function '%-.64s'; %-.80s",
+"No paths allowed for shared library",
+"Function '%-.64s' already exist",
+"Can't open shared library '%-.64s' (errno: %d %-.64s)",
+"Can't find function '%-.64s' in library'",
+"Function '%-.64s' is not defined",
+"Host '%-.64s' is blocked because of many connection errors. Unblock with 'mysqladmin flush-hosts'",
+"Host '%-.64s' is not allowed to connect to this MySQL server",
+"You are using MySQL as an anonymous users and anonymous users are not allowed to change passwords",
+"You must have privileges to update tables in the mysql database to be able to change passwords for others",
+"Can't find any matching row in the user table",
+"Rows matched: %ld Changed: %ld Warnings: %ld",
+"Can't create a new thread (errno %d). If you are not out of available memory, you can consult the manual for a possible OS-dependent bug",
+"Column count doesn't match value count at row %ld",
+"Can't reopen table: '%-.64s'",
+"Invalid use of NULL value",
+"Got error '%-.64s' from regexp",
+"Mixing of GROUP columns (MIN(),MAX(),COUNT()...) with no GROUP columns is illegal if there is no GROUP BY clause",
+"There is no such grant defined for user '%-.32s' on host '%-.64s'",
+"%-.16s command denied to user: '%-.32s@%-.64s' for table '%-.64s'",
+"%-.16s command denied to user: '%-.32s@%-.64s' for column '%-.64s' in table '%-.64s'",
+"Illegal GRANT/REVOKE command. Please consult the manual which privileges can be used.",
+"The host or user argument to GRANT is too long",
+"Table '%-.64s.%-.64s' doesn't exist",
+"There is no such grant defined for user '%-.32s' on host '%-.64s' on table '%-.64s'",
+"The used command is not allowed with this MySQL version",
+"You have an error in your SQL syntax",
+"Delayed insert thread couldn't get requested lock for table %-.64s",
+"Too many delayed threads in use",
+"Aborted connection %ld to db: '%-.64s' user: '%-.32s' (%-.64s)",
+"Got a packet bigger than 'max_allowed_packet'",
+"Got a read error from the connection pipe",
+"Got an error from fcntl()",
+"Got packets out of order",
+"Couldn't uncompress communication packet",
+"Got an error reading communication packets",
+"Got timeout reading communication packets",
+"Got an error writing communication packets",
+"Got timeout writing communication packets",
+"Result string is longer than max_allowed_packet",
+"The used table type doesn't support BLOB/TEXT columns",
+"The used table type doesn't support AUTO_INCREMENT columns",
+"INSERT DELAYED can't be used with table '%-.64s', because it is locked with LOCK TABLES",
+"Incorrect column name '%-.100s'",
+"The used table handler can't index column '%-.64s'",
+"All tables in the MERGE table are not identically defined",
+"Can't write, because of unique constraint, to table '%-.64s'",
+"BLOB column '%-.64s' used in key specification without a key length",
+"All parts of a PRIMARY KEY must be NOT NULL; If you need NULL in a key, use UNIQUE instead",
+"Result consisted of more than one row",
+"This table type requires a primary key",
+"This version of MySQL is not compiled with RAID support",
+"You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column",
+"Key '%-.64s' doesn't exist in table '%-.64s'",
+"Can't open table",
+"The handler for the table doesn't support check/repair",
+"You are not allowed to execute this command in a transaction",
+"Got error %d during COMMIT",
+"Got error %d during ROLLBACK",
+"Got error %d during FLUSH_LOGS",
+"Got error %d during CHECKPOINT",
+"Aborted connection %ld to db: '%-.64s' user: '%-.32s' host: `%-.64s' (%-.64s)",
+"The handler for the table does not support binary table dump",
+"Binlog closed while trying to FLUSH MASTER",
+"Failed rebuilding the index of dumped table '%-.64s'",
+"Error from master: '%-.64s'",
+"Net error reading from master",
+"Net error writing to master",
+"Can't find FULLTEXT index matching the column list",
diff --git a/sql/share/estonia/errmsg.sys b/sql/share/estonia/errmsg.sys
new file mode 100644
index 00000000000..bd7927bdb5e
--- /dev/null
+++ b/sql/share/estonia/errmsg.sys
Binary files differ
diff --git a/sql/share/estonia/errmsg.txt b/sql/share/estonia/errmsg.txt
new file mode 100644
index 00000000000..a1614fbd3e8
--- /dev/null
+++ b/sql/share/estonia/errmsg.txt
@@ -0,0 +1,199 @@
+/* Copyright Abandoned 1997 TCX DataKonsult AB & Monty Program KB & Detron HB
+ This file is public domain and comes with NO WARRANTY of any kind
+
+ 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)",
+"'%-.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",
+"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)",
+"Liiga palju samaaegseid ühendusi",
+"Mälu sai otsa. Võimalik, et aitab swap-i lisamine või käsu 'ulimit' abil MySQL-le rohkema mälu kasutamise lubamine.",
+"Ei suuda lahendada IP aadressi masina nimeks",
+"Väär handshake",
+"Ligipääs piiratud kasutajale: '%-.32s@%-.64s' andmebaasi '%-.64s'",
+"Ligipääs piiratud kasutajale: '%-.32s@%-.64s' (Kasutab parooli: %s)",
+"Andmebaas pole valitud",
+"Tundmatu käsk",
+"Tulp '%-.64s' ei saa olla null",
+"Tundmatu andmebaas '%-.64s'",
+"Tabel '%-.64s' on juba olemas",
+"Tundmatu tabel '%-.64s'",
+"Tulp: '%-.64s' in %-.64s on väär",
+"Serveri seiskamine käib",
+"Tundmatu tulp '%-.64s' in '%-.64s'",
+"'%-.64s' puudub GROUP BY-s",
+"Ei saa grupeerida '%-.64s' järgi",
+"Lauses on korraga nii tulbad kui summad",
+"Tuplade arv tabelis erineb antud 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",
+"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",
+"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",
+"%s: ootab ühendusi\n",
+"%s: MySQL lõpetas\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",
+"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",
+"Tundmatu viga",
+"Tundmatu protseduur '%-.64s'",
+"Väär parameetrite hulk protseduurile '%-.64s'",
+"Valed parameetrid protseduurile '%-.64s'",
+"Tundmatu tabel '%-.64s' %s-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",
+"Tabel '%-.64s' on täis",
+"Tundmatu kooditabel: '%-.64s'",
+"Liiga palju tabeleid. MySQL oskab kasutada kuni %d tabelit JOINi puhul",
+"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",
+"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",
+"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',
+"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",
+"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",
+"Result consisted of more than one row",
+"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'",
+"Can't open table",
+"The handler for the table doesn't support check/repair",
+"You are not allowed to execute this command in a transaction",
+"Got error %d during COMMIT",
+"Got error %d during ROLLBACK",
+"Got error %d during FLUSH_LOGS",
+"Got error %d during CHECKPOINT",
+"Aborted connection %ld to db: '%-.64s' user: '%-.32s' host: `%-.64s' (%-.64s)",
+"The handler for the table does not support binary table dump",
+"Binlog closed while trying to FLUSH MASTER",
+"Failed rebuilding the index of dumped table '%-.64s'",
+"Error from master: '%-.64s'",
+"Net error reading from master",
+"Net error writing to master",
+"Can't find FULLTEXT index matching the column list",
diff --git a/sql/share/french/errmsg.sys b/sql/share/french/errmsg.sys
new file mode 100644
index 00000000000..6947930f875
--- /dev/null
+++ b/sql/share/french/errmsg.sys
Binary files differ
diff --git a/sql/share/french/errmsg.txt b/sql/share/french/errmsg.txt
new file mode 100644
index 00000000000..34c488b7129
--- /dev/null
+++ b/sql/share/french/errmsg.txt
@@ -0,0 +1,195 @@
+/* Copyright Abandoned 1997 TCX DataKonsult AB & Monty Program KB & Detron HB
+ This file is public domain and comes with NO WARRANTY of any kind */
+
+"hashchk",
+"isamchk",
+"NON",
+"OUI",
+"Ne peut créer le fichier '%-.64s' (Errcode: %d)",
+"Ne peut créer la table '%-.64s' (Errcode: %d)",
+"Ne peut créer la base '%-.64s'. Erreur %d",
+"Ne peut créer la base '%-.64s'. Elle existe déjà",
+"Ne peut effacer la base '%-.64s'. Elle n'existe pas",
+"Ne peut effacer la base '%-.64s' (erreur %d)",
+"Erreur en effaçant la base (rmdir '%-.64s', erreur %d)",
+"Erreur en effaçant '%-.64s' (Errcode: %d)",
+"Ne peut lire un enregistrement de la table 'system'",
+"Ne peut obtenir le status de '%-.64s' (Errcode: %d)",
+"Ne peut obtenir le répertoire de travail (Errcode: %d)",
+"Ne peut verrouiller le fichier (Errcode: %d)",
+"Ne peut ouvrir le fichier: '%-.64s'. (Errcode: %d)",
+"Ne peut trouver le fichier: '%-.64s' (Errcode: %d)",
+"Ne peut lire le répertoire de '%-.64s' (Errcode: %d)",
+"Ne peut changer le répertoire pour '%-.64s' (Errcode: %d)",
+"Enregistrement modifié depuis sa dernière lecture dans la table '%-.64s'",
+"Disque plein (%s). J'attend que quelqu'un libère de l'espace...",
+"Ecriture impossible, doublon dans une clé de la table '%-.64s'",
+"Erreur a la fermeture de '%-.64s' (Errcode: %d)",
+"Erreur en lecture du fichier '%-.64s' (Errcode: %d)",
+"Erreur en renommant '%-.64s' en '%-.64s' (Errcode: %d)",
+"Erreur d'écriture du fichier '%-.64s' (Errcode: %d)",
+"'%-.64s' est verrouillé contre les modifications",
+"Tri alphabétique abandonné",
+"La vue (View) '%-.64s' n'existe pas pour '%-.64s'",
+"Reçu l'erreur %d du handler de la table",
+"Le handler de la table '%-.64s' n'a pas cette option",
+"Ne peut trouver l'enregistrement dans '%-.64s'",
+"Information erronnée dans le fichier: '%-.64s'",
+"Index corrompu dans la table: '%-.64s'. Essayez de le réparer",
+"Vieux fichier d'index pour la table '%-.64s'; Réparez le!",
+"'%-.64s' est en lecture seulement",
+"Manque de mémoire. Redémarrez le démon et ré-essayez (%d octets nécessaires)",
+"Manque de mémoire pour le tri. Augmentez-la.",
+"Fin de fichier inattendue en lisant '%-.64s' (Errcode: %d)",
+"Trop de connections",
+"Manque de 'threads'/mémoire",
+"Ne peut obtenir de hostname pour votre adresse",
+"Mauvais 'handshake'",
+"Accès refusé pour l'utilisateur: '%-.32s@%-.64s'. Base '%-.64s'",
+"Accès refusé pour l'utilisateur: '%-.32s@%-.64s' (mot de passe: %s)",
+"Aucune base n'a été sélectionnée",
+"Commande inconnue",
+"Le champ '%-.64s' ne peut être vide (null)",
+"Base '%-.64s' inconnue",
+"La table '%-.64s' existe déjà",
+"Table '%-.64s' inconnue",
+"Champ: '%-.64s' dans %s est ambigu",
+"Arrêt du serveur en cours",
+"Champ '%-.64s' inconnu dans %s",
+"'%-.64s' n'est pas dans 'group by'",
+"Ne peut regrouper '%-.64s'",
+"Vous demandez la fonction sum() et des champs dans la même commande",
+"Column count doesn't match value count",
+"Le nom de l'identificateur '%-.64s' est trop long",
+"Nom du champ '%-.64s' déjà utilisé",
+"Nom de clef '%-.64s' déjà utilisé",
+"Duplicata du champ '%-.64s' pour la clef %d",
+"Mauvais paramètre de champ pour le champ '%-.64s'",
+"%s près de '%-.64s' à la ligne %d",
+"Query est vide",
+"Table/alias: '%-.64s' non unique",
+"Valeur par défaut invalide pour '%-.64s'",
+"Plusieurs clefs primaires définies",
+"Trop de clefs sont définies. Maximum de %d clefs alloué",
+"Trop de parties specifiées dans la clef. Maximum de %d parties",
+"La clé est trop longue. Longueur maximale: %d",
+"La clé '%-.64s' n'existe pas dans la table",
+"Champ BLOB '%-.64s' ne peut être utilisé dans une clé",
+"Champ '%-.64s' trop long (max = %d). Utilisez un BLOB",
+"Un seul champ automatique est permis et il doit être indexé",
+"%s: Prêt pour des connections\n",
+"%s: Arrêt normal du serveur\n",
+"%s: Reçu le signal %d. Abandonne!\n",
+"%s: Arrêt du serveur terminé\n",
+"%s: Arrêt forcé de la tâche (thread) %ld utilisateur: '%-.64s'\n",
+"Ne peut créer la connection IP (socket)",
+"La table '%-.64s' n'a pas d'index comme celle utilisée dans CREATE INDEX. Recréez la table",
+"Séparateur de champs inconnu. Vérifiez dans le manuel",
+"Vous ne pouvez utiliser des lignes de longueur fixe avec des BLOBs. Utiliser 'fields terminated by'.",
+"Le fichier '%-.64s' doit être dans le répertoire de la base et lisible par tous",
+"Le fichier '%-.64s' existe déjà",
+"Enregistrements: %ld Effacés: %ld Non traités: %ld Avertissements: %ld",
+"Enregistrements: %ld Doublons: %ld",
+"Mauvaise sous-clef. Ce n'est pas un 'string' ou la longueur dépasse celle définie dans la clef",
+"Vous ne pouvez effacer tous les champs avec ALTER TABLE. Utilisez DROP TABLE",
+"Ne peut effacer (DROP) '%-.64s'. Vérifiez s'il existe",
+"Enregistrements: %ld Doublons: %ld Avertissements: %ld",
+"INSERT TABLE '%-.64s' n'est pas permis dans FROM liste des tables",
+"Numéro de tâche inconnu: %lu",
+"Vous n'êtes pas propriétaire de la tâche no: %lu",
+"Aucune table utilisée",
+"Trop de chaînes dans la colonne %s avec SET",
+"Ne peut générer un unique nom de journal %s.(1-999)\n",
+"Table '%-.64s' verrouillée lecture (READ): modification impossible",
+"Table '%-.64s' non verrouillée: utilisez LOCK TABLES",
+"BLOB '%-.64s' ne peut avoir de valeur par défaut",
+"Nom de base de donnée illégal: '%-.64s'",
+"Nom de table illégal: '%-.64s'",
+"SELECT va devoir examiner beaucoup d'enregistrements ce qui va prendre du temps. Vérifiez la clause WHERE et utilisez SET OPTION SQL_BIG_SELECTS=1 si SELECT se passe bien",
+"Erreur inconnue",
+"Procédure %s inconnue",
+"Mauvais nombre de paramètres pour la procedure %s",
+"Paramètre erroné pour la procedure %s",
+"Table inconnue '%-.64s' dans %s",
+"Champ '%-.64s' spécifié deux fois",
+"Utilisation invalide de la clause GROUP",
+"Table '%-.64s' : utilise une extension invalide pour cette version de MySQL",
+"Une table doit comporter au moins une colonne",
+"La table '%-.64s' est pleine",
+"Jeu de caractères inconnu: '%-.64s'",
+"Trop de tables. MySQL ne peut utiliser que %d tables dans un JOIN",
+"Trop de champs",
+"Ligne trop grande. Le taille maximale d'une ligne, sauf les BLOBs, est %d. Changez le type de quelques colonnes en BLOB",
+"Débordement de la pile des tâches (Thread stack). Utilisées: %ld pour une pile de %ld. Essayez 'mysqld -O thread_stack=#' pour indiquer une plus grande valeur",
+"Dépendance croisée dans une clause OUTER JOIN. Vérifiez la condition ON",
+"Column '%-.32s' is used with UNIQUE or INDEX but is not defined as NOT NULL",
+"Can't load function '%-.64s'",
+"Can't initialize function '%-.64s'; %-.80s",
+"No paths allowed for shared library",
+"Function '%-.64s' already exist",
+"Can't open shared library '%-.64s' (errno: %d %s)",
+"Can't find function '%-.64s' in library'",
+"Function '%-.64s' is not defined",
+"Host '%-.64s' is blocked because of many connection errors. Unblock with 'mysqladmin flush-hosts'",
+"Host '%-.64s' is not allowed to connect to this MySQL server",
+"You are using MySQL as an anonymous users and anonymous users are not allowed to change passwords",
+"You must have privileges to update tables in the mysql database to be able to change passwords for others",
+"Can't find any matching row in the user table",
+"Rows matched: %ld Changed: %ld Warnings: %ld",
+"Can't create a new thread (errno %d). If you are not out of available memory you can consult the manual for any possible OS dependent bug",
+"Column count doesn't match value count at row %ld",
+"Can't reopen table: '%-.64s',
+"Invalid use of NULL value",
+"Got error '%-.64s' from regexp",
+"Mixing of GROUP columns (MIN(),MAX(),COUNT()...) with no GROUP columns is illegal if there is no GROUP BY clause",
+"There is no such grant defined for user '%-.32s' on host '%-.64s'",
+"%-.16s command denied to user: '%-.32s@%-.64s' for table '%-.64s'",
+"%-.16s command denied to user: '%-.32s@%-.64s' for column '%-.64s' in table '%-.64s'",
+"Illegal GRANT/REVOKE command. Please consult the manual which privleges can be used.",
+"The host or user argument to GRANT is too long",
+"Table '%-64s.%s' doesn't exist",
+"There is no such grant defined for user '%-.32s' on host '%-.64s' on table '%-.64s'",
+"The used command is not allowed with this MySQL version",
+"Something is wrong in your syntax",
+"Delayed insert thread couldn't get requested lock for table %-.64s",
+"Too many delayed threads in use",
+"Aborted connection %ld to db: '%-.64s' user: '%-.64s' (%s)",
+"Got a packet bigger than 'max_allowed_packet'",
+"Got a read error from the connection pipe",
+"Got an error from fcntl()",
+"Got packets out of order",
+"Couldn't uncompress communication packet",
+"Got an error reading communication packets"
+"Got timeout reading communication packets",
+"Got an error writing communication packets",
+"Got timeout writing communication packets",
+"Result string is longer than max_allowed_packet",
+"The used table type doesn't support BLOB/TEXT columns",
+"The used table type doesn't support AUTO_INCREMENT columns",
+"INSERT DELAYED can't be used with table '%-.64s', because it is locked with LOCK TABLES",
+"Incorrect column name '%-.100s'",
+"The used table handler can't index column '%-.64s'",
+"All tables in the MERGE table are not defined identically",
+"Can't write, because of unique constraint, to table '%-.64s'",
+"BLOB column '%-.64s' used in key specification without a key length",
+"All parts of a PRIMARY KEY must be NOT NULL; If you need NULL in a key, use UNIQUE instead",
+"Result consisted of more than one row",
+"This table type requires a primary key",
+"This version of MySQL is not compiled with RAID support",
+"You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column",
+"Key '%-.64s' doesn't exist in table '%-.64s'",
+"Can't open table",
+"The handler for the table doesn't support check/repair",
+"You are not allowed to execute this command in a transaction",
+"Got error %d during COMMIT",
+"Got error %d during ROLLBACK",
+"Got error %d during FLUSH_LOGS",
+"Got error %d during CHECKPOINT",
+"Aborted connection %ld to db: '%-.64s' user: '%-.32s' host: `%-.64s' (%-.64s)",
+"The handler for the table does not support binary table dump",
+"Binlog closed while trying to FLUSH MASTER",
+"Failed rebuilding the index of dumped table '%-.64s'",
+"Error from master: '%-.64s'",
+"Net error reading from master",
+"Net error writing to master",
+"Can't find FULLTEXT index matching the column list",
diff --git a/sql/share/german/errmsg.sys b/sql/share/german/errmsg.sys
new file mode 100644
index 00000000000..94c99a9262d
--- /dev/null
+++ b/sql/share/german/errmsg.sys
Binary files differ
diff --git a/sql/share/german/errmsg.txt b/sql/share/german/errmsg.txt
new file mode 100644
index 00000000000..adc69b823b7
--- /dev/null
+++ b/sql/share/german/errmsg.txt
@@ -0,0 +1,198 @@
+/* Copyright Abandoned 1997 TCX DataKonsult AB & Monty Program KB & Detron HB
+ This file is public domain and comes with NO WARRANTY of any kind
+
+ Dirk Munzinger (dmun@4t2.com)
+ Version: 17.03.1999 */
+
+"hashchk",
+"isamchk",
+"Nein",
+"Ja",
+"Kann Datei '%-.64s' nicht erzeugen. (Fehler: %d)",
+"Kann Tabelle '%-.64s' nicht erzeugen. (Fehler: %d)",
+"Kann Datenbank '%-.64s' nicht erzeugen. (Fehler: %d)",
+"Kann Datenbank '%-.64s' nicht erzeugen. Datenbank '%-.64s' existiert bereits.",
+"Kann Datenbank '%-.64s' nicht löschen. Keine Datenbank '%-.64s' vorhanden.",
+"Fehler beim Löschen der Datenbank. ('%-.64s' kann nicht gelöscht werden, Fehler %d)",
+"Fehler beim Löschen der Datenbank. (Verzeichnis '%-.64s' kann nicht gelöscht werden, Fehler %d)",
+"Fehler beim Löschen von '%-.64s'. (Fehler: %d)",
+"Datensatz in der Systemtabelle nicht lesbar.",
+"Kann Status von '%-.64s' nicht erhalten. (Fehler: %d)",
+"Kann Arbeitsverzeichnis nicht erhalten. (Fehler: %d)",
+"File nicht sperrbar. (Fehler: %d)",
+"Kann Datei '%-.64s' nicht öffnen. (Fehler: %d)",
+"Kann Datei '%-.64s' nicht finden. (Fehler: %d)",
+"Verzeichnis von '%-.64s' nicht lesbar. (Fehler: %d)",
+"Verzeichnis kann nicht nach '%-.64s' gewechselt werden. (Fehler: %d)",
+"Datensatz hat sich seit dem letzten Zugriff auf Tabelle '%-.64s' geändert.",
+"Festplatte voll (%-.64s). Warte bis jemand Platz schafft ...",
+"Kann nicht speichern, doppelter Schlüssel in Tabelle '%-.64s'.",
+"Fehler beim Schließen von '%-.64s'. (Fehler: %d)",
+"Fehler beim Lesen der Datei '%-.64s'. (Fehler: %d)",
+"Fehler beim Umbennenen von '%-.64s' nach '%-.64s'. (Fehler: %d)",
+"Fehler beim Speichern der Datei '%-.64s'. (Fehler: %d)",
+"'%-.64s' ist für Veränderungen gesperrt.",
+"Sortieren abgebrochen.",
+"View '%-.64s' existiert für '%-.64s' nicht.",
+"Fehler %d. (table handler)",
+"Diese Option gibt es nicht. (table handler)",
+"Kann Datensatz nicht finden.",
+"Falsche Information in Datei: '%-.64s'",
+"Falsche Schlüssel-Datei für Tabelle '%-.64s'. Versuche zu reparieren!",
+"Alte Schlüssel-Datei für Tabelle '%-.64s'. Repariere!
+"'%-.64s' ist nur lesbar.",
+"Kein Speicher (benötigt %d bytes). Server neu starten.",
+"Kein Speicher zum Sortieren. Server Sortier-Buffer erhöhen.",
+"Unerwartetes EOF beim Lesen der Datei '%-.64s'. (Fehler: %d)",
+"Zu viele Verbindungen.",
+"Zuwenig Speicher.",
+"Kann Hostname für diese Adresse nicht erhalten.",
+"Schlechter handshake.",
+"Keine Zugriffsberechtigung für Benutzer: '%-.32s@%-.64s' für Datenbank '%-.64s'.",
+"Keine Zugriffsberechtigung für Benutzer: '%-.32s@%-.64s'. (Verwendetes Passwort: %-.64s)",
+"Keine Datenbank ausgewählt.",
+"Unbekannter Befehl.",
+"Feld '%-.64s' kann nicht NULL sein.",
+"Unbekannte Datenbank '%-.64s'.",
+"Tabelle '%-.64s' bereits vorhanden.",
+"Unbekannte Tabelle '%-.64s'.",
+"Spalte: '%-.64s' in %-.64s ist mißverständlich.",
+"Der Server wird herunter gefahren...",
+"Unbekanntes Tabellenfeld '%-.64s' in %-.64s.",
+"'%-.64s' ist nicht in GROUP BY.",
+"Gruppierung nicht möglich bei '%-.64s'.",
+"Im Statement wurden sowohl sum-Funktionen als auch Spalten verwendet. Nicht möglich.",
+"Spaltenzähler entspricht nicht dem Wertzähler.",
+"Name des Identifizierers '%-.64s' ist zu lang.",
+"Doppelter Spaltenname vorhanden: '%-.64s'",
+"Doppelter Name für Schlüssel (Key) vorhanden: '%-.64s'",
+"Doppelter Eintrag '%-.64s' für Schlüssel %d.",
+"Falsche Spalten-Spezifizierung für Spalte '%-.64s'.",
+"%-.64s bei '%-.64s' in Zeile %d.",
+"Leere Abfrage.",
+"Keine eindeutige(n) Tabelle/Alias: '%-.64s'",
+"Fehlerhafter Vorgabewert (Default-Wert): '%-.64s'",
+"Mehrfacher Primärschlüssel (Primary Key) definiert.",
+"Zuviele Schlüssel definiert. Maximal %d Schlüssel erlaubt.",
+"Zuviele Teilschlüssel definiert. Maximal sind %d Teilschlüssel erlaubt.",
+"Schlüssel ist zu lang. Die maximale Schlüssellänge beträgt %d.",
+"In der Tabelle gibt es keine Schlüsselspalte '%-.64s'.",
+"BLOB-Feld '%-.64s' kann nicht als Schlüssel verwendet werden.",
+"Feldlänge für Feld '%-.64s' zu groß (max = %d). BLOB-Feld verwenden!",
+"Nur ein Auto-Feld möglich, welches als Schlüssel definiert werden muß.",
+"%-.64s: Warten auf Verbindungen.\n",
+"%-.64s: Normal beendet.\n",
+"%-.64s: Signal %d erhalten. Abbruch!\n",
+"%-.64s: Shutdown ausgeführt.\n",
+"%-.64s: Beendigung des Thread %ld veranlaßt. Benutzer: '%-.64s'\n",
+"Kann IP-Socket nicht erstellen.",
+"Tabelle '%-.64s' hat keinen solchen Index wie in CREATE INDEX verwendet. Index neu anlegen.",
+"Feld-Separator Argument ist nicht in der Form wie erwartet. Bitte im Manual nachlesen.",
+"Eine feste Reihenlänge kann für BLOBs nicht verwendet werden. Verwende 'fields terminated by' stattdessen.",
+"Feld '%-.64s' muß im Datenbank-Directory vorhanden und lesbar für alle sein.",
+"File '%-.64s' bereits vorhanden.",
+"Datensätze: %ld Gelöscht: %ld Ausgelassen: %ld Warnungen: %ld",
+"Datensätze: %ld Duplikate: %ld",
+"Falscher Subteilschlüssel. Der verwendete Schlüsselteil ist entweder kein String oder die verwendete Länge ist länger als der Teilschlüssel.",
+"Mit ALTER TABLE können nicht alle Felder auf einmal gelöscht werden. Verwende DROP TABLE stattdessen.",
+"Kann '%-.64s' nicht löschen (DROP). Existiert das Feld/der Schlüssel?",
+"Datensätze: %ld Duplikate: %ld Warnungen: %ld",
+"INSERT TABLE '%-.64s' nicht erlaubt im FROM Abschnitt.",
+"Unbekannte Thread-ID: %lu",
+"Nicht Besitzer des Threads %lu.",
+"Keine Tabellen in Verwendung.",
+"Zuviele Strings für Spalte %-.64s und SET.",
+"Kann keinen eindeutigen Log-Filenamen erstellen %-.64s.(1-999)\n",
+"Tabelle '%-.64s' mit Lese-Sperre versehen und kann nicht upgedated werden.",
+"Tabelle '%-.64s' wurde nicht mittels LOCK TABLES gesperrt.",
+"BLOB-Feld '%-.64s' kann keinen Vorgabewert (Default-Value) besitzen.",
+"Unerlaubter Datenbankname '%-.64s'.",
+"Unerlaubter Tabellenname '%-.64s'.",
+"Die Ausführung des SELECT würde zu viele Datensätze untersuchen und wahrscheinlich sehr lange daueren. Bitte WHERE überprüfen und SET OPTION SQL_BIG_SELECTS=1 verwenden, sofern SELECT ok ist.",
+"Unbekannter Fehler.",
+"Unbekannte Procedure %-.64s.",
+"Falsche Parameterzahl für Procedure %-.64s.",
+"Falsche Parameter in Procedure %-.64s.",
+"Unbekannte Tabelle '%-.64s' in %-.64s.",
+"Feld '%-.64s' wurde zweimal spezifiziert.",
+"Falsche Verwendung der GROUP-Funktion.",
+"Tabelle '%-.64s' verwendet eine Extension, die in dieser MySQL Version nicht verfügbar ist.",
+"Eine Tabelle muß mindestens eine Spalte besitzen.",
+"Tabelle '%-.64s' voll.",
+"Unbekannter Zeichensatz: '%-.64s'.",
+"Zuviele Tabellen. MySQL kann maximal %d Tabellen in einem Join verwenden.",
+"Zuviele Felder.",
+"Zuviele Spalten. Maximal sind %d Spalten erlaubt (Ohne BLOBs). Einige Felder sollten in BLOBs umgewandelt werden.",
+"Thread Stack Überlauf : Verwendet: %ld von %ld Stack. Verwende 'mysqld -O thread_stack=#' um ggf. einen größeren Stack anzulegen.",
+"OUTER JOIN enthält fehlerhafte Abhängigkeiten. Prüfen Sie Ihre ON Bedingungen.",
+"Spalte '%-.64s' wurde mit UNIQUE oder INDEX benutzt ohne als NOT NULL definiert zu sein.",
+"Kann Funktion '%-.64s' nicht laden.",
+"Kann Funktion '%-.64s' nicht initialisieren; %-.80s.",
+"Keine Pfade gestattet für Shared Library.",
+"Funktion '%-.64s' existiert schon.",
+"Kann Shared Library '%-.64s' nicht öffnen. (Fehler: %d %-.64s)",
+"Kann Funktion '%-.64s' in der Library nicht finden.",
+"Funktion '%-.64s' ist nicht definiert.",
+"Host blockiert wegen zu vieler Verbindungsfehler. Aufheben der Blockierung mit 'mysqladmin flush-hosts'.",
+"Host hat keine Berechtigung, eine Verbindung zu diesem MySQL Server herzustellen.",
+"Sie benutzen MySQL als anonymer User; diese User dürfen keine Passwörter ändern.",
+"Sie müssen autorisiert sein zum UPDATE von Tabellen in der mysql Datenbank, um für andere Benutzer Passwörter ändern zu können.",
+"Kann keinen passenden Datensatz in der User-Tabelle finden.",
+"Datensätze gefunden: %ld Geändert: %ld Warnungen: %ld",
+"Kann keinen neuen Thread erzeugen (errno %d). Sollte nicht die Speichergrenze erreicht sein, bitte im Manual nach vorhanden OS-Abhängigen Fehlern nachschauen.",
+"Spaltenzahl stimmt nicht mit der Anzahl der Werte überein in Reihe%ld",
+"Kann Tabelle'%-.64s' nicht wieder öffnen",
+"Unerlaubte Verwendung eines NULL-Wertes",
+"Fehler '%-.64s' von regexp",
+"Das Vermischen von GROUP Spalten (MIN(),MAX(),COUNT()...) mit Nicht-GROUP Spalten ist nicht erlaubt, sofern keine GROUP BY Klausel vorhanden ist.",
+"Keine solche Berechtigung für User '%-.32s' auf Host '%-.64s'",
+"%-.16s Kommando abgelehnt für User: '%-.32s@%-.64s' für Tabelle '%-.64s'",
+"%-.16s Kommando abgelehnt für User: '%-.32s@%-.64s' in Spalte '%-.64s' in Tabelle '%-.64s'",
+"Unzulässiges GRANT/REVOKE Kommando. Weiteres zum Thema Berechtigungen im Manual.",
+"Das Host oder User Argument für GRANT ist zu lang",
+"Tabelle '%-.64s.%-.64s' existiert nicht",
+"Keine solche Berechtigung für User '%-.32s' auf Host '%-.64s' an Tabelle '%-.64s'",
+"Das used Kommando ist mit dieser MySQL Version nicht erlaubt",
+"Fehler in der Syntax",
+"Verzögerter Einfüge-Thread konnte den angeforderten Lock für Tabelle %-.64s nicht bekommen",
+"Zu viele Delayed Threads in Verwendung",
+"Abbruch der Verbindung %ld zur Datenbank: '%-.64s' User: '%-.64s' (%-.64s)",
+"Empfangenes Paket ist größer als 'max_allowed_packet'",
+"Lese-Fehler bei einer Kommunikations-Pipe",
+"Fehler von fcntl()",
+"Empfangenes Paket ist nicht in Reihenfolge",
+"Communikation-Packet läßt sich nicht entpacken",
+"Fehler beim Lesen eines Communication-Packets"
+"Timeout beim Lesen eines Communication-Packets",
+"Fehler beim Schreiben eines Communication-Packets",
+"Timeout beim Schreiben eines Communication-Packets",
+"Result string is longer than max_allowed_packet",
+"The used table type doesn't support BLOB/TEXT columns",
+"The used table type doesn't support AUTO_INCREMENT columns",
+"INSERT DELAYED can't be used with table '%-.64s', because it is locked with LOCK TABLES",
+"Incorrect column name '%-.100s'",
+"The used table handler can't index column '%-.64s'",
+"All tables in the MERGE table are not defined identically",
+"Can't write, because of unique constraint, to table '%-.64s'",
+"BLOB column '%-.64s' used in key specification without a key length",
+"All parts of a PRIMARY KEY must be NOT NULL; If you need NULL in a key, use UNIQUE instead",
+"Result consisted of more than one row",
+"This table type requires a primary key",
+"This version of MySQL is not compiled with RAID support",
+"You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column",
+"Key '%-.64s' doesn't exist in table '%-.64s'",
+"Can't open table",
+"The handler for the table doesn't support check/repair",
+"You are not allowed to execute this command in a transaction",
+"Got error %d during COMMIT",
+"Got error %d during ROLLBACK",
+"Got error %d during FLUSH_LOGS",
+"Got error %d during CHECKPOINT",
+"Aborted connection %ld to db: '%-.64s' user: '%-.32s' host: `%-.64s' (%-.64s)",
+"The handler for the table does not support binary table dump",
+"Binlog closed while trying to FLUSH MASTER",
+"Failed rebuilding the index of dumped table '%-.64s'",
+"Error from master: '%-.64s'",
+"Net error reading from master",
+"Net error writing to master",
+"Can't find FULLTEXT index matching the column list",
diff --git a/sql/share/greek/errmsg.sys b/sql/share/greek/errmsg.sys
new file mode 100644
index 00000000000..8fc053c381d
--- /dev/null
+++ b/sql/share/greek/errmsg.sys
Binary files differ
diff --git a/sql/share/greek/errmsg.txt b/sql/share/greek/errmsg.txt
new file mode 100644
index 00000000000..b3a17af8ec0
--- /dev/null
+++ b/sql/share/greek/errmsg.txt
@@ -0,0 +1,195 @@
+/* Copyright Abandoned 1997 TCX DataKonsult AB & Monty Program KB & Detron HB
+ This file is public domain and comes with NO WARRANTY of any kind */
+
+"hashchk",
+"isamchk",
+"Ï×É",
+"ÍÁÉ",
+"Áäýíáôç ç äçìéïõñãßá ôïõ áñ÷åßïõ '%-.64s' (êùäéêüò ëÜèïõò: %d)",
+"Áäýíáôç ç äçìéïõñãßá ôïõ ðßíáêá '%-.64s' (êùäéêüò ëÜèïõò: %d)",
+"Áäýíáôç ç äçìéïõñãßá ôçò âÜóçò äåäïìÝíùí '%-.64s'. (êùäéêüò ëÜèïõò: %d)",
+"Áäýíáôç ç äçìéïõñãßá ôçò âÜóçò äåäïìÝíùí '%-.64s'. Ç âÜóç äåäïìÝíùí õðÜñ÷åé Þäç",
+"Áäýíáôç ç äéáãñáöÞ ôçò âÜóçò äåäïìÝíùí '%-.64s'. Ç âÜóç äåäïìÝíùí äåí õðÜñ÷åé",
+"ÐáñïõóéÜóôçêå ðñüâëçìá êáôÜ ôç äéáãñáöÞ ôçò âÜóçò äåäïìÝíùí (áäýíáôç ç äéáãñáöÞ '%-.64s', êùäéêüò ëÜèïõò: %d)",
+"ÐáñïõóéÜóôçêå ðñüâëçìá êáôÜ ôç äéáãñáöÞ ôçò âÜóçò äåäïìÝíùí (áäýíáôç ç äéáãñáöÞ ôïõ öáêÝëëïõ '%-.64s', êùäéêüò ëÜèïõò: %d)",
+"ÐáñïõóéÜóôçêå ðñüâëçìá êáôÜ ôç äéáãñáöÞ '%-.64s' (êùäéêüò ëÜèïõò: %d)",
+"Áäýíáôç ç áíÜãíùóç åããñáöÞò áðü ðßíáêá ôïõ óõóôÞìáôïò",
+"Áäýíáôç ç ëÞøç ðëçñïöïñéþí ãéá ôçí êáôÜóôáóç ôïõ '%-.64s' (êùäéêüò ëÜèïõò: %d)",
+"Ï öÜêåëëïò åñãáóßáò äåí âñÝèçêå (êùäéêüò ëÜèïõò: %d)",
+"Ôï áñ÷åßï äåí ìðïñåß íá êëåéäùèåß (êùäéêüò ëÜèïõò: %d)",
+"Äåí åßíáé äõíáôü íá áíïé÷ôåß ôï áñ÷åßï: '%-.64s'. (êùäéêüò ëÜèïõò: %d)",
+"Äåí âñÝèçêå ôï áñ÷åßï: '%-.64s' (êùäéêüò ëÜèïõò: %d)",
+"Äåí åßíáé äõíáôü íá äéáâáóôåß ï öÜêåëëïò ôïõ '%-.64s' (êùäéêüò ëÜèïõò: %d)",
+"Áäýíáôç ç áëëáãÞ ôïõ ôñÝ÷ïíôïò êáôáëüãïõ óå '%-.64s' (êùäéêüò ëÜèïõò: %d)",
+"Ç åããñáöÞ Ý÷åé áëëÜîåé áðü ôçí ôåëåõôáßá öïñÜ ðïõ áíáóýñèçêå áðü ôïí ðßíáêá '%-.64s'",
+"Äåí õðÜñ÷åé ÷þñïò óôï äßóêï (%s). Ðáñáêáëþ, ðåñéìÝíåôå íá åëåõèåñùèåß ÷þñïò....",
+"Äåí åßíáé äõíáôÞ ç êáôá÷þñçóç, ç ôéìÞ õðÜñ÷åé Þäç óôïí ðßíáêá '%-.64s'",
+"ÐáñïõóéÜóôçêå ðñüâëçìá êëåßíïíôáò ôï '%-.64s' (êùäéêüò ëÜèïõò: %d)",
+"Ðñüâëçìá êáôÜ ôçí áíÜãíùóç ôïõ áñ÷åßïõ '%-.64s' (êùäéêüò ëÜèïõò: %d)",
+"Ðñüâëçìá êáôÜ ôçí ìåôïíïìáóßá ôïõ áñ÷åßïõ '%-.64s' to '%-.64s' (êùäéêüò ëÜèïõò: %d)",
+"Ðñüâëçìá êáôÜ ôçí áðïèÞêåõóç ôïõ áñ÷åßïõ '%-.64s' (êùäéêüò ëÜèïõò: %d)",
+"'%-.64s' äåí åðéôñÝðïíôáé áëëáãÝò",
+"Ç äéáäéêáóßá ôáîéíüìéóçò áêõñþèçêå",
+"Ôï View '%-.64s' äåí õðÜñ÷åé ãéá '%-.64s'",
+"ÅëÞöèç ìÞíõìá ëÜèïõò %d áðü ôïí ÷åéñéóôÞ ðßíáêá (table handler)",
+"Ï ÷åéñéóôÞò ðßíáêá (table handler) ãéá '%-.64s' äåí äéáèÝôåé áõôÞ ôçí åðéëïãÞ",
+"Áäýíáôç ç áíåýñåóç åããñáöÞò óôï '%-.64s'",
+"ËÜèïò ðëçñïöïñßåò óôï áñ÷åßï: '%-.64s'",
+"ËÜèïò áñ÷åßï ôáîéíüìéóçò (key file) ãéá ôïí ðßíáêá: '%-.64s'. Ðáñáêáëþ, äéïñèþóôå ôï!",
+"Ðáëáéü áñ÷åßï ôáîéíüìéóçò (key file) ãéá ôïí ðßíáêá '%-.64s'; Ðáñáêáëþ, äéïñèþóôå ôï!",
+"'%-.64s' åðéôñÝðåôáé ìüíï ç áíÜãíùóç",
+"Äåí õðÜñ÷åé äéáèÝóéìç ìíÞìç. ÐñïóðáèÞóôå ðÜëé, åðáíåêéíþíôáò ôç äéáäéêáóßá (demon) (÷ñåéÜæïíôáé %d bytes)",
+"Äåí õðÜñ÷åé äéáèÝóéìç ìíÞìç ãéá ôáîéíüìéóç. ÁõîÞóôå ôï sort buffer size ãéá ôç äéáäéêáóßá (demon)",
+"ÊáôÜ ôç äéÜñêåéá ôçò áíÜãíùóçò, âñÝèçêå áðñïóäüêçôá ôï ôÝëïò ôïõ áñ÷åßïõ '%-.64s' (êùäéêüò ëÜèïõò: %d)",
+"ÕðÜñ÷ïõí ðïëëÝò óõíäÝóåéò...",
+"Ðñüâëçìá ìå ôç äéáèÝóéìç ìíÞìç (Out of thread space/memory)",
+"Äåí Ýãéíå ãíùóôü ôï hostname ãéá ôçí address óáò",
+"Ç áíáãíþñéóç (handshake) äåí Ýãéíå óùóôÜ",
+"Äåí åðéôÝñåôáé ç ðñüóâáóç óôï ÷ñÞóôç: '%-.32s@%-.64s' óôç âÜóç äåäïìÝíùí '%-.64s'",
+"Äåí åðéôÝñåôáé ç ðñüóâáóç óôï ÷ñÞóôç: '%-.32s@%-.64s' (÷ñÞóç password: %s)",
+"Äåí åðéëÝ÷èçêå âÜóç äåäïìÝíùí",
+"Áãíùóôç åíôïëÞ",
+"Ôï ðåäßï '%-.64s' äåí ìðïñåß íá åßíáé êåíü (null)",
+"Áãíùóôç âÜóç äåäïìÝíùí '%-.64s'",
+"Ï ðßíáêáò '%-.64s' õðÜñ÷åé Þäç",
+"Áãíùóôïò ðßíáêáò '%-.64s'",
+"Ôï ðåäßï: '%-.64s' óå %-.64s äåí Ý÷åé êáèïñéóôåß",
+"Åíáñîç äéáäéêáóßáò áðïóýíäåóçò ôïõ åîõðçñåôçôÞ (server shutdown)",
+"Áãíùóôï ðåäßï '%-.64s' óå '%-.64s'",
+"×ñçóéìïðïéÞèçêå '%-.64s' ðïõ äåí õðÞñ÷å óôï group by",
+"Áäýíáôç ç ïìáäïðïßçóç (group on) '%-.64s'",
+"Ç äéáôýðùóç ðåñéÝ÷åé sum functions êáé columns óôçí ßäéá äéáôýðùóç",
+"Ôï Column count äåí ôáéñéÜæåé ìå ôï value count",
+"Ôï identifier name '%-.100s' åßíáé ðïëý ìåãÜëï",
+"ÅðáíÜëçøç column name '%-.64s'",
+"ÅðáíÜëçøç key name '%-.64s'",
+"ÄéðëÞ åããñáöÞ '%-.64s' ãéá ôï êëåéäß %d",
+"ÅóöáëìÝíï column specifier ãéá ôï ðåäßï '%-.64s'",
+"%s ðëçóßïí '%-.80s' óôç ãñáììÞ %d",
+"Ôï åñþôçìá (query) ðïõ èÝóáôå Þôáí êåíü",
+"Áäýíáôç ç áíåýñåóç unique table/alias: '%-.64s'",
+"ÅóöáëìÝíç ðñïêáèïñéóìÝíç ôéìÞ (default value) ãéá '%-.64s'",
+"Ðåñéóóüôåñá áðü Ýíá primary key ïñßóôçêáí",
+"ÐÜñá ðïëëÜ key ïñßóèçêáí. Ôï ðïëý %d åðéôñÝðïíôáé",
+"ÐÜñá ðïëëÜ key parts ïñßóèçêáí. Ôï ðïëý %d åðéôñÝðïíôáé",
+"Ôï êëåéäß ðïõ ïñßóèçêå åßíáé ðïëý ìåãÜëï. Ôï ìÝãéóôï ìÞêïò åßíáé %d",
+"Ôï ðåäßï êëåéäß '%-.64s' äåí õðÜñ÷åé óôïí ðßíáêá",
+"Ðåäßï ôýðïõ Blob '%-.64s' äåí ìðïñåß íá ÷ñçóéìïðïéçèåß óôïí ïñéóìü åíüò êëåéäéïý (key specification)",
+"Ðïëý ìåãÜëï ìÞêïò ãéá ôï ðåäßï '%-.64s' (max = %d). Ðáñáêáëþ ÷ñçóéìïðïéåßóôå ôïí ôýðï BLOB",
+"Ìðïñåß íá õðÜñ÷åé ìüíï Ýíá auto field êáé ðñÝðåé íá Ý÷åé ïñéóèåß óáí key",
+"%s: óå áíáìïíÞ óõíäÝóåùí\n",
+"%s: ÖõóéïëïãéêÞ äéáäéêáóßá shutdown\n",
+"%s: ÅëÞöèç ôï ìÞíõìá %d. Ç äéáäéêáóßá åãêáôáëåßðåôáé!\n",
+"%s: Ç äéáäéêáóßá Shutdown ïëïêëçñþèçêå\n",
+"%s: Ôï thread èá êëåßóåé %ld user: '%-.64s'\n",
+"Äåí åßíáé äõíáôÞ ç äçìéïõñãßá IP socket",
+"Ï ðßíáêáò '%-.64s' äåí Ý÷åé åõñåôÞñéï (index) óáí áõôü ðïõ ÷ñçóéìïðïéåßôå óôçí CREATE INDEX. Ðáñáêáëþ, îáíáäçìéïõñãÞóôå ôïí ðßíáêá",
+"Ï äéá÷ùñéóôÞò ðåäßùí äåí åßíáé áõôüò ðïõ áíáìåíüôáí. Ðáñáêáëþ áíáôñÝîôå óôï manual","
+"Äåí ìðïñåßôå íá ÷ñçóéìïðïéÞóåôå fixed rowlength óå BLOBs. Ðáñáêáëþ ÷ñçóéìïðïéåßóôå 'fields terminated by'.",
+"Ôï áñ÷åßï '%-.64s' ðñÝðåé íá õðÜñ÷åé óôï database directory Þ íá ìðïñåß íá äéáâáóôåß áðü üëïõò",
+"Ôï áñ÷åßï '%-.64s' õðÜñ÷åé Þäç",
+"ÅããñáöÝò: %ld ÄéáãñáöÝò: %ld ÐáñåêÜìöèçóáí: %ld ÐñïåéäïðïéÞóåéò: %ld",
+"ÅããñáöÝò: %ld ÅðáíáëÞøåéò: %ld",
+"ÅóöáëìÝíï sub part key. Ôï ÷ñçóéìïðïéïýìåíï key part äåí åßíáé string Þ ôï ìÞêïò ôïõ åßíáé ìåãáëýôåñï",
+"Äåí åßíáé äõíáôÞ ç äéáãñáöÞ üëùí ôùí ðåäßùí ìå ALTER TABLE. Ðáñáêáëþ ÷ñçóéìïðïéåßóôå DROP TABLE",
+"Áäýíáôç ç äéáãñáöÞ (DROP) '%-.64s'. Ðáñáêáëþ åëÝãîôå áí ôï ðåäßï/êëåéäß õðÜñ÷åé",
+"ÅããñáöÝò: %ld ÅðáíáëÞøåéò: %ld ÐñïåéäïðïéÞóåéò: %ld",
+"INSERT TABLE '%-.64s' äåí åðéôñÝðåôáé óôï FROM table list",
+"Áãíùóôï thread id: %lu",
+"Äåí åßóèå owner ôïõ thread %lu",
+"Äåí ÷ñçóéìïðïéÞèçêáí ðßíáêåò",
+"ÐÜñá ðïëëÜ strings ãéá ôï ðåäßï %-.64s êáé SET",
+"Áäýíáôç ç äçìéïõñãßá unique log-filename %-.64s.(1-999)\n",
+"Ï ðßíáêáò '%-.64s' Ý÷åé êëåéäùèåß ìå READ lock êáé äåí åðéôñÝðïíôáé áëëáãÝò",
+"Ï ðßíáêáò '%-.64s' äåí Ý÷åé êëåéäùèåß ìå LOCK TABLES",
+"Ôá Blob ðåäßá '%-.64s' äåí ìðïñïýí íá Ý÷ïõí ðñïêáèïñéóìÝíåò ôéìÝò (default value)",
+"ËÜèïò üíïìá âÜóçò äåäïìÝíùí '%-.100s'",
+"ËÜèïò üíïìá ðßíáêá '%-.100s'",
+"Ôï SELECT èá åîåôÜóåé ìåãÜëï áñéèìü åããñáöþí êáé ðéèáíþò èá êáèõóôåñÞóåé. Ðáñáêáëþ åîåôÜóôå ôéò ðáñáìÝôñïõò ôïõ WHERE êáé ÷ñçóéìïðïéåßóôå SET OPTION SQL_BIG_SELECTS=1 áí ôï SELECT åßíáé óùóôü",
+"ÐñïÝêõøå Üãíùóôï ëÜèïò",
+"Áãíùóôç äéáäéêáóßá '%-.64s'",
+"ËÜèïò áñéèìüò ðáñáìÝôñùí óôç äéáäéêáóßá '%-.64s'",
+"ËÜèïò ðáñÜìåôñïé óôçí äéáäéêáóßá '%-.64s'",
+"Áãíùóôïò ðßíáêáò '%-.64s' óå %s",
+"Ôï ðåäßï '%-.64s' Ý÷åé ïñéóèåß äýï öïñÝò",
+"ÅóöáëìÝíç ÷ñÞóç ôçò group function",
+"Ï ðßíáêò '%-.64s' ÷ñçóéìïðïéåß êÜðïéï extension ðïõ äåí õðÜñ÷åé óôçí Ýêäïóç áõôÞ ôçò MySQL",
+"Åíáò ðßíáêáò ðñÝðåé íá Ý÷åé ôïõëÜ÷éóôïí Ýíá ðåäßï",
+"Ï ðßíáêáò '%-.64s' åßíáé ãåìÜôïò",
+"Áãíùóôï character set: '%-.64s'",
+"Ðïëý ìåãÜëïò áñéèìüò ðéíÜêùí. Ç MySQL ìðïñåß íá ÷ñçóéìïðïéÞóåé %d ðßíáêåò óå äéáäéêáóßá join",
+"Ðïëý ìåãÜëïò áñéèìüò ðåäßùí",
+"Ðïëý ìåãÜëï ìÝãåèïò åããñáöÞò. Ôï ìÝãéóôï ìÝãåèïò åããñáöÞò, ÷ùñßò íá õðïëïãßæïíôáé ôá blobs, åßíáé %d. ÐñÝðåé íá ïñßóåôå êÜðïéá ðåäßá óáí blobs",
+"Stack overrun óôï thread: Used: %ld of a %ld stack. Ðáñáêáëþ ÷ñçóéìïðïéåßóôå 'mysqld -O thread_stack=#' ãéá íá ïñßóåôå Ýíá ìåãáëýôåñï stack áí ÷ñåéÜæåôáé",
+"Cross dependency âñÝèçêå óå OUTER JOIN. Ðáñáêáëþ åîåôÜóôå ôéò óõíèÞêåò ðïõ èÝóáôå óôï ON",
+"Ôï ðåäßï '%-.64s' ÷ñçóéìïðïéåßôáé óáí UNIQUE Þ INDEX áëëÜ äåí Ý÷åé ïñéóèåß óáí NOT NULL",
+"Äåí åßíáé äõíáôÞ ç äéáäéêáóßá load ãéá ôç óõíÜñôçóç '%-.64s'",
+"Äåí åßíáé äõíáôÞ ç Ýíáñîç ôçò óõíÜñôçóçò '%-.64s'; %-.80s",
+"Äåí âñÝèçêáí paths ãéá ôçí shared library",
+"Ç óõíÜñôçóç '%-.64s' õðÜñ÷åé Þäç",
+"Äåí åßíáé äõíáôÞ ç áíÜãíùóç ôçò shared library '%-.64s' (êùäéêüò ëÜèïõò: %d %s)",
+"Äåí åßíáé äõíáôÞ ç áíåýñåóç ôçò óõíÜñôçóçò '%-.64s' óôçí âéâëéïèÞêç'",
+"Ç óõíÜñôçóç '%-.64s' äåí Ý÷åé ïñéóèåß",
+"Ï õðïëïãéóôÞò Ý÷åé áðïêëåéóèåß ëüãù ðïëëáðëþí ëáèþí óýíäåóçò. ÐñïóðáèÞóôå íá äéïñþóåôå ìå 'mysqladmin flush-hosts'",
+"Ï õðïëïãéóôÞò äåí Ý÷åé äéêáßùìá óýíäåóçò ìå ôïí MySQL server",
+"×ñçóéìïðïéåßôå ôçí MySQL óáí anonymous user êáé Ýôóé äåí ìðïñåßôå íá áëëÜîåôå ôá passwords Üëëùí ÷ñçóôþí",
+"ÐñÝðåé íá Ý÷åôå äéêáßùìá äéüñèùóçò ðéíÜêùí (update) óôç âÜóç äåäïìÝíùí mysql ãéá íá ìðïñåßôå íá áëëÜîåôå ôá passwords Üëëùí ÷ñçóôþí",
+"Äåí åßíáé äõíáôÞ ç áíåýñåóç ôçò áíôßóôïé÷çò åããñáöÞò óôïí ðßíáêá ôùí ÷ñçóôþí",
+"Rows matched: %ld Changed: %ld Warnings: %ld",
+"Can't create a new thread (errno %d). If you are not out of available memory, you can consult the manual for a possible OS-dependent bug",
+"Column count doesn't match value count at row %ld",
+"Can't reopen table: '%-.64s'",
+"Invalid use of NULL value",
+"Got error '%-.64s' from regexp",
+"Mixing of GROUP columns (MIN(),MAX(),COUNT()...) with no GROUP columns is illegal if there is no GROUP BY clause",
+"There is no such grant defined for user '%-.32s' on host '%-.64s'",
+"%-.16s command denied to user: '%-.32s@%-.64s' for table '%-.64s'",
+"%-.16s command denied to user: '%-.32s@%-.64s' for column '%-.64s' in table '%-.64s'",
+"Illegal GRANT/REVOKE command. Please consult the manual which privileges can be used.",
+"The host or user argument to GRANT is too long",
+"Table '%-.64s.%-.64s' doesn't exist",
+"There is no such grant defined for user '%-.32s' on host '%-.64s' on table '%-.64s'",
+"The used command is not allowed with this MySQL version",
+"You have an error in your SQL syntax",
+"Delayed insert thread couldn't get requested lock for table %-.64s",
+"Too many delayed threads in use",
+"Aborted connection %ld to db: '%-.64s' user: '%-32s' (%-.64s)",
+"Got a packet bigger than 'max_allowed_packet'",
+"Got a read error from the connection pipe",
+"Got an error from fcntl()",
+"Got packets out of order",
+"Couldn't uncompress communication packet",
+"Got an error reading communication packets"
+"Got timeout reading communication packets",
+"Got an error writing communication packets",
+"Got timeout writing communication packets",
+"Result string is longer than max_allowed_packet",
+"The used table type doesn't support BLOB/TEXT columns",
+"The used table type doesn't support AUTO_INCREMENT columns",
+"INSERT DELAYED can't be used with table '%-.64s', because it is locked with LOCK TABLES",
+"Incorrect column name '%-.100s'",
+"The used table handler can't index column '%-.64s'",
+"All tables in the MERGE table are not identically defined",
+"Can't write, because of unique constraint, to table '%-.64s'",
+"BLOB column '%-.64s' used in key specification without a key length",
+"All parts of a PRIMARY KEY must be NOT NULL; If you need NULL in a key, use UNIQUE instead",
+"Result consisted of more than one row",
+"This table type requires a primary key",
+"This version of MySQL is not compiled with RAID support",
+"You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column",
+"Key '%-.64s' doesn't exist in table '%-.64s'",
+"Can't open table",
+"The handler for the table doesn't support check/repair",
+"You are not allowed to execute this command in a transaction",
+"Got error %d during COMMIT",
+"Got error %d during ROLLBACK",
+"Got error %d during FLUSH_LOGS",
+"Got error %d during CHECKPOINT",
+"Aborted connection %ld to db: '%-.64s' user: '%-.32s' host: `%-.64s' (%-.64s)",
+"The handler for the table does not support binary table dump",
+"Binlog closed while trying to FLUSH MASTER",
+"Failed rebuilding the index of dumped table '%-.64s'",
+"Error from master: '%-.64s'",
+"Net error reading from master",
+"Net error writing to master",
+"Can't find FULLTEXT index matching the column list",
diff --git a/sql/share/hungarian/errmsg.sys b/sql/share/hungarian/errmsg.sys
new file mode 100644
index 00000000000..df039b66ec3
--- /dev/null
+++ b/sql/share/hungarian/errmsg.sys
Binary files differ
diff --git a/sql/share/hungarian/errmsg.txt b/sql/share/hungarian/errmsg.txt
new file mode 100644
index 00000000000..8e9e04b79b7
--- /dev/null
+++ b/sql/share/hungarian/errmsg.txt
@@ -0,0 +1,197 @@
+/* Copyright Abandoned 1997 TCX DataKonsult AB & Monty Program KB & Detron HB
+ Translated by Feher Peter. Forditotta Feher Peter (feherp@mail.matav.hu) 1998
+ Updated May, 2000
+ This file is public domain and comes with NO WARRANTY of any kind */
+
+"hashchk",
+"isamchk",
+"NEM",
+"IGEN",
+"A '%-.64s' file nem hozhato letre (hibakod: %d)",
+"A '%-.64s' tabla nem hozhato letre (hibakod: %d)",
+"Az '%-.64s' adatbazis nem hozhato letre (hibakod: %d)",
+"Az '%-.64s' adatbazis nem hozhato letre Az adatbazis mar letezik",
+"A(z) '%-.64s' adatbazis nem szuntetheto meg. Az adatbazis nem letezik",
+"Adatbazis megszuntetesi hiba ('%-.64s' nem torolheto, hibakod: %d)",
+"Adatbazis megszuntetesi hiba ('%-.64s' nem szuntetheto meg, hibakod: %d)",
+"Torlesi hiba: '%-.64s' (hibakod: %d)",
+"Nem olvashato rekord a rendszertablaban",
+"A(z) '%-.64s' statusza nem allapithato meg (hibakod: %d)",
+"A munkakonyvtar nem allapithato meg (hibakod: %d)",
+"A file nem zarolhato. (hibakod: %d)",
+"A '%-.64s' file nem nyithato meg. (hibakod: %d)",
+"A(z) '%-.64s' file nem talalhato. (hibakod: %d)",
+"A(z) '%-.64s' konyvtar nem olvashato. (hibakod: %d)",
+"Konyvtarvaltas nem lehetseges a(z) '%-.64s'-ba. (hibakod: %d)",
+"A(z) '%-.64s' tablaban talalhato rekord megvaltozott az utolso olvasas ota",
+"A lemez megtelt (%s).",
+"Irasi hiba, duplikalt kulcs a '%-.64s' tablaban.",
+"Hiba a(z) '%-.64s' zarasakor. (hibakod: %d)",
+"Hiba a '%-.64s'file olvasasakor. (hibakod: %d)",
+"Hiba a '%-.64s' file atnevezesekor. (hibakod: %d)",
+"Hiba a '%-.64s' file irasakor. (hibakod: %d)",
+"'%-.64s' a valtoztatas ellen zarolva",
+"Sikertelen rendezes",
+"A(z) '%-.64s' nezet nem letezik a(z) '%-.64s'-hoz",
+"%d hibajelzes a tablakezelotol",
+"A(z) '%-.64s' tablakezelonek nincs ilyen opcioja",
+"Nem talalhato a rekord '%-.64s'-ben",
+"Ervenytelen info a file-ban: '%-.64s'",
+"Ervenytelen kulcsfile a tablahoz: '%-.64s'. Probalja kijavitani!",
+"Regi kulcsfile a '%-.64s'tablahoz; Probalja kijavitani!",
+"'%-.64s' irasvedett",
+"Nincs eleg memoria. Inditsa ujra a demont, es probalja ismet. (%d byte szukseges.)",
+"Nincs eleg memoria a rendezeshez. Novelje a rendezo demon puffermeretet",
+"Varatlan filevege-jel a '%-.64s'olvasasakor. (hibakod: %d)",
+"Tul sok kapcsolat",
+"Elfogyott a thread-memoria",
+"A gepnev nem allapithato meg a cimbol",
+"A kapcsolatfelvetel nem sikerult (Bad handshake)",
+"A(z) '%-.32s@%-.64s' felhasznalo szamara tiltott eleres az '%-.64s' adabazishoz.",
+"A(z) '%-.32s@%-.64s' felhasznalo szamara tiltott eleres. (Hasznalja a jelszot: %s)",
+"Nincs kivalasztott adatbazis",
+"Ervenytelen parancs",
+"A(z) '%-.64s' oszlop erteke nem lehet nulla",
+"Ervenytelen adatbazis: '%-.64s'",
+"A(z) '%-.64s' tabla mar letezik",
+"Ervenytelen tabla: '%-.64s'",
+"A(z) '%-.64s' oszlop %-.64s-ben ketertelmu",
+"A szerver leallitasa folyamatban",
+"A(z) '%-.64s' oszlop ervenytelen '%-.64s'-ben",
+"Used '%-.64s' with wasn't in group by",
+"A group nem hasznalhato: '%-.64s'",
+"Statement has sum functions and columns in same statement",
+"Az oszlopban levo ertek nem egyezik meg a szamitott ertekkel",
+"A(z) '%-.100s' azonositonev tul hosszu.",
+"Duplikalt oszlopazonosito: '%-.64s'",
+"Duplikalt kulcsazonosito: '%-.64s'",
+"Duplikalt bejegyzes '%-.64s' a %d kulcs szerint.",
+"Rossz oszlopazonosito: '%-.64s'",
+"A %s a '%-.80s'-hez kozeli a %d sorban",
+"Ures lekerdezes.",
+"Nem egyedi tabla/alias: '%-.64s'",
+"Ervenytelen ertek: '%-.64s'",
+"Tobbszoros elsodleges kulcs definialas.",
+"Tul sok kulcs. Maximum %d kulcs engedelyezett.",
+"Tul sok kulcsdarabot definialt. Maximum %d resz engedelyezett",
+"A megadott kulcs tul hosszu. Maximalis kulcshosszusag: %d",
+"A(z) '%-.64s'kulcsoszlop nem letezik a tablaban",
+"Blob objektum '%-.64s' nem hasznalhato kulcskent",
+"A(z) '%-.64s' oszlop tul hosszu. (maximum = %d). Hasznaljon BLOB tipust inkabb.",
+"Csak egy auto mezo lehetseges, es azt kulcskent kell definialni.",
+"%s: kapcsolatra kesz\n",
+"%s: Normal leallitas\n",
+"%s: %d jelzes. Megszakitva!\n",
+"%s: A leallitas kesz\n",
+"%s: A(z) %ld thread kenyszeritett zarasa. Felhasznalo: '%-.64s'\n",
+"Az IP socket nem hozhato letre",
+"A(z) '%-.64s' tablahoz nincs meg a CREATE INDEX altal hasznalt index. Alakitsa at a tablat",
+"A mezoelvalaszto argumentumok nem egyeznek meg a varttal. Nezze meg a kezikonyvben!","
+"Fix hosszusagu BLOB-ok nem hasznalhatok. Hasznalja a 'mezoelvalaszto jelet' .",
+"A(z) '%-.64s'-nak az adatbazis konyvtarban kell lennie, vagy mindenki szamara olvashatonak",
+"A '%-.64s' file mar letezik.",
+"Rekordok: %ld Torolve: %ld Skipped: %ld Warnings: %ld",
+"Rekordok: %ld Duplikalva: %ld",
+"Rossz alkulcs. A hasznalt kulcsresz nem karaktersorozat vagy hosszabb, mint a kulcsresz",
+"Az osszes mezo nem torolheto az ALTER TABLE-lel. Hasznalja a DROP TABLE-t helyette",
+"A DROP '%-.64s' nem lehetseges. Ellenorizze, hogy a mezo/kulcs letezik-e",
+"Rekordok: %ld Duplikalva: %ld Warnings: %ld",
+"INSERT TABLE '%-.64s' nem engedelyezett a FROM table listabol",
+"Ervenytelen szal (thread) id: %lu",
+"A %lu thread-nek mas a tulajdonosa",
+"Nincs hasznalt tabla",
+"Tul sok karakter: %-.64s es SET",
+"Egyedi log-filenev nem generalhato: %-.64s.(1-999)\n",
+"A(z) '%-.64s' tabla zarolva lett (READ lock) es nem lehet frissiteni",
+"A(z) '%-.64s' tabla nincs zarolva a LOCK TABLES-szel",
+"A(z) '%-.64s' blob objektumnak nem lehet alapertelmezett erteke",
+"Hibas adatbazisnev: '%-.100s'",
+"Hibas tablanev: '%-.100s'",
+"A SELECT tul sok rekordot fog megvizsgalni es nagyon sokaig fog tartani. Ellenorizze a WHERE-t es hasznalja a SET OPTION SQL_BIG_SELECTS=1 beallitast, ha a SELECT ok",
+"Ismeretlen hiba",
+"Ismeretlen eljaras: '%-.64s'",
+"Rossz parameter a(z) '%-.64s'eljaras szamitasanal",
+"Rossz parameter a(z) '%-.64s' eljarasban",
+"Ismeretlen tabla: '%-.64s' %s-ban",
+"A(z) '%-.64s' mezot ketszer definialta",
+"A group funkcio ervenytelen hasznalata",
+"A(z) '%-.64s' tabla olyan bovitest hasznal, amely nem letezik ebben a MySQL versioban.",
+"A tablanak legalabb egy oszlopot tartalmazni kell",
+"A '%-.64s' tabla megtelt",
+"Ervenytelen karakterkeszlet: '%-.64s'",
+"Tul sok tabla. A MySQL csak %d tablat tud kezelni osszefuzeskor",
+"Tul sok mezo",
+"Tul nagy sormeret. A maximalis sormeret (nem szamolva a blob objektumokat) %d. Nehany mezot meg kell valtoztatnia",
+"Thread verem tullepes: Used: %ld of a %ld stack. Hasznalja a 'mysqld -O thread_stack=#' nagyobb verem definialasahoz",
+"Keresztfuggoseg van az OUTER JOIN-ban. Ellenorizze az ON felteteleket",
+"A(z) '%-.64s' oszlop INDEX vagy UNIQUE (egyedi), de a definicioja szerint nem NOT NULL",
+"A(z) '%-.64s' fuggveny nem toltheto be",
+"A(z) '%-.64s' fuggveny nem inicializalhato; %-.80s",
+"Nincs ut a megosztott konyvtarakhoz (shared library)",
+"A '%-.64s' fuggveny mar letezik",
+"A(z) '%-.64s' megosztott konyvtar nem hasznalhato (hibakod: %d %s)",
+"A(z) '%-.64s' fuggveny nem talalhato a konyvtarban",
+"A '%-.64s' fuggveny nem definialt",
+"A '%-.64s' host blokkolodott, tul sok kapcsolodasi hiba miatt. Hasznalja a 'mysqladmin flush-hosts' parancsot",
+"A '%-.64s' host szamara nem engedelyezett a kapcsolodas ehhez a MySQL szerverhez",
+"Nevtelen (anonymous) felhasznalokent nem negedelyezett a jelszovaltoztatas",
+"Onnek tabla-update joggal kell rendelkeznie a mysql adatbazisban masok jelszavanak megvaltoztatasahoz",
+"Nincs megegyezo sor a user tablaban",
+"Megegyezo sorok szama: %ld Valtozott: %ld Warnings: %ld",
+"Uj thread letrehozasa nem lehetseges (Hibakod: %d). Amenyiben van meg szabad memoria, olvassa el a kezikonyv operacios rendszerfuggo hibalehetosegekrol szolo reszet",
+"Az oszlopban talalhato ertek nem egyezik meg a %ld sorban szamitott ertekkel",
+"Nem lehet ujra-megnyitni a tablat: '%-.64s',
+"A NULL ervenytelen hasznalata",
+"'%-.64s' hiba a regularis kifejezes hasznalata soran (regexp)",
+"A GROUP mezok (MIN(),MAX(),COUNT()...) kevert hasznalata nem lehetseges GROUP BY hivatkozas nelkul",
+"A '%-.32s' felhasznalonak nincs ilyen joga a '%-.64s' host-on",
+"%-.16s parancs a '%-.32s@%-.64s' felhasznalo szamara nem engedelyezett a '%-.64s' tablaban",
+"%-.16s parancs a '%-.32s@%-.64s' felhasznalo szamara nem engedelyezett a '%-.64s' mezo eseten a '%-.64s' tablaban",
+"Ervenytelen GRANT/REVOKE parancs. Kerem, nezze meg a kezikonyvben, milyen jogok lehetsegesek",
+"A host vagy felhasznalo argumentuma tul hosszu a GRANT parancsban",
+"A '%-64s.%s' tabla nem letezik",
+"A '%-.32s' felhasznalo szamara a '%-.64s' host '%-.64s' tablajaban ez a parancs nem engedelyezett",
+"A hasznalt parancs nem engedelyezett ebben a MySQL verzioban",
+"Szintaktikai hiba",
+"A kesleltetett beillesztes (delayed insert) thread nem kapott zatolast a %-.64s tablahoz",
+"Tul sok kesletetett thread (delayed)",
+"Megszakitott kapcsolat %ld db: '%-.64s' adatbazishoz, felhasznalo: '%-.64s' (%s)",
+"A kapott csomag nagyobb, mint a maximalisan engedelyezett: 'max_allowed_packet'",
+"Olvasasi hiba a kapcsolat soran",
+"Hiba a fcntl() fuggvenyben",
+"Helytelen sorrendben erkezett adatcsomagok",
+"A kommunikacios adatcsomagok nem tomorithetok ki",
+"HIba a kommunikacios adatcsomagok olvasasa soran"
+"Idotullepes a kommunikacios adatcsomagok olvasasa soran",
+"Hiba a kommunikacios csomagok irasa soran",
+"Idotullepes a kommunikacios csomagok irasa soran",
+"Ez eredmeny sztring nagyobb, mint a lehetseges maximum: max_allowed_packet",
+"A hasznalt tabla tipus nem tamogatja a BLOB/TEXT mezoket",
+"A hasznalt tabla tipus nem tamogatja az AUTO_INCREMENT tipusu mezoket",
+"Az INSERT DELAYED nem hasznalhato a '%-.64s' tablahoz, mert a tabla zarolt (LOCK TABLES)",
+"Ervenytelen mezonev: '%-.100s'",
+"A hasznalt tablakezelo nem tudja a '%-.64s' mezot indexelni",
+"A MERGE tablaban talalhato tablak definicioja nem azonos",
+"A '%-.64s' nem irhato, az egyedi mezok miatt",
+"BLOB mezo '%-.64s' hasznalt a mezo specifikacioban, a mezohossz megadasa nelkul",
+"Az elsodleges kulcs teljes egeszeben csak NOT NULL tipusu lehet; Ha NULL mezot szeretne a kulcskent, hasznalja inkabb a UNIQUE-ot",
+"Az eredmeny tobb, mint egy sort tartalmaz",
+"Az adott tablatipushoz elsodleges kulcs hasznalata kotelezo",
+"Ezen leforditott MySQL verzio nem tartalmaz RAID support-ot",
+"On a biztonsagos update modot hasznalja, es WHERE that uses a KEY column",
+"A '%-.64s' kulcs nem letezik a '%-.64s' tablaban",
+"Nem tudom megnyitni a tablat",
+"A tabla kezeloje (handler) nem tamogatja az ellenorzest/helyreallitast",
+"Az On szamara nem engedelyezett a parancs vegrehajtasa a tranzakcioban",
+"%d hiba a COMMIT vegrehajtasa soran",
+"%d hiba a ROLLBACK vegrehajtasa soran",
+"%d hiba a FLUSH_LOGS vegrehajtasa soran",
+"%d hiba a CHECKPOINT vegrehajtasa soran",
+"Aborted connection %ld to db: '%-.64s' user: '%-.32s' host: `%-.64s' (%-.64s)",
+"The handler for the table does not support binary table dump",
+"Binlog closed while trying to FLUSH MASTER",
+"Failed rebuilding the index of dumped table '%-.64s'",
+"Error from master: '%-.64s'",
+"Net error reading from master",
+"Net error writing to master",
+"Can't find FULLTEXT index matching the column list",
diff --git a/sql/share/italian/errmsg.sys b/sql/share/italian/errmsg.sys
new file mode 100644
index 00000000000..f1300819c3c
--- /dev/null
+++ b/sql/share/italian/errmsg.sys
Binary files differ
diff --git a/sql/share/italian/errmsg.txt b/sql/share/italian/errmsg.txt
new file mode 100644
index 00000000000..0aa12667b5e
--- /dev/null
+++ b/sql/share/italian/errmsg.txt
@@ -0,0 +1,195 @@
+/* Copyright Abandoned 1997 TCX DataKonsult AB & Monty Program KB & Detron HB
+ This file is public domain and comes with NO WARRANTY of any kind */
+
+"hashchk",
+"isamchk",
+"NO",
+"SI",
+"Impossibile creare il file '%-.64s' (errno: %d)",
+"Impossibile creare la tabella '%-.64s' (errno: %d)",
+"Impossibile creare il database '%-.64s'. (errno: %d)",
+"Impossibile creare il database '%-.64s'. Il database esiste",
+"Impossibile cancellare '%-.64s'. Il database non esiste",
+"Errore durante la cancellazione del database (impossibile cancellare '%-.64s', errno: %d)",
+"Errore durante la cancellazione del database (impossibile rmdir '%-.64s', errno: %d)",
+"Errore durante la cancellazione di '%-.64s' (errno: %d)",
+"Impossibile leggere il record dalla tabella di sistema",
+"Impossibile leggere lo stato di '%-.64s' (errno: %d)",
+"Impossibile leggere la directory di lavoro (errno: %d)",
+"Impossibile il locking il file (errno: %d)",
+"Impossibile aprire il file: '%-.64s'. (errno: %d)",
+"Impossibile trovare il file: '%-.64s' (errno: %d)",
+"Impossibile leggere la directory di '%-.64s' (errno: %d)",
+"Impossibile cambiare la directory in '%-.64s' (errno: %d)",
+"Il record e` cambiato dall'ultima lettura della tabella '%-.64s'",
+"Disco pieno (%s). In attesa che qualcuno liberi un po' di spazio....",
+"Impossibile scrivere, chiave duplicata nella tabella '%-.64s'",
+"Errore durante la chiusura di '%-.64s' (errno: %d)",
+"Errore durante la lettura del file '%-.64s' (errno: %d)",
+"Errore durante la rinominazione da '%-.64s' a '%-.64s' (errno: %d)",
+"Errore durante la scrittura del file '%-.64s' (errno: %d)",
+"'%-.64s' e` soggetto a lock contro i cambiamenti",
+"Operazione di ordinamento abbandonata" ,
+"La view '%-.64s' non esiste per '%-.64s'",
+"Rilevato l'errore %d dal gestore delle tabelle",
+"Il gestore delle tabelle per '%-.64s' non ha questa opzione",
+"Impossibile trovare il record in '%-.64s'",
+"Informazione errata nel file: '%-.64s'",
+"File chiave errato per la tabella : '%-.64s'. Prova a riparalo",
+"File chiave vecchio per la tabella '%-.64s'; Riparalo!",
+"'%-.64s' e` di sola lettura",
+"Memoria esaurita. Fai ripartire il demone e riprova (richiesti %d bytes)",
+"Memoria per gli ordinamenti esaurita. Incrementare il 'sort_buffer' al demone",
+"Fine del file inaspettata durante la lettura del file '%-.64s' (errno: %d)",
+"Troppe connessioni",
+"Fine dello spazio/memoria per i thread",
+"Impossibile risalire al nome dell'host dal tuo indirizzo",
+"Negoziazione impossibile",
+"Accesso non consentito per l'utente: '%-.32s@%-.64s' al database '%-.64s'",
+"Accesso non consentito per l'utente: '%-.32s@%-.64s' (Password: %s)",
+"Nessun database selezionato",
+"Comando sconosciuto",
+"La colonna '%-.64s' non puo` essere nulla",
+"Database '%-.64s' sconosciuto",
+"La tabella '%-.64s' esiste gia`",
+"Tabella '%-.64s' sconosciuta",
+"Colonna: '%-.64s' di %-.64s e` ambigua",
+"Shutdown del server in corso",
+"Colonna sconosciuta '%-.64s' in '%-.64s'",
+"Usato '%-.64s' che non e` nel GROUP BY",
+"Impossibile raggruppare per '%-.64s'",
+"Il comando ha una funzione SUM e una colonna non specificata nella GROUP BY",
+"Il numero delle colonne non e` uguale al numero dei valori",
+"Il nome dell'identificatore '%-.100s' e` troppo lungo",
+"Nome colonna duplicato '%-.64s'",
+"Nome chiave duplicato '%-.64s'",
+"Valore duplicato '%-.64s' per la chiave %d",
+"Specifica errata per la colonna '%-.64s'",
+"%s vicino a '%-.80s' linea %d",
+"La query e` vuota",
+"Tabella/alias non unico: '%-.64s'",
+"Valore di default non valido per '%-.64s'",
+"Definite piu` chiave primarie",
+"Troppe chiavi. Sono ammesse max %d chiavi",
+"Troppe parti di chiave specificate. Sono ammesse max %d parti",
+"La chiave specificata e` troppo lunga. La max lunghezza della chiave e` %d",
+"La colonna chiave '%-.64s' non esiste nella tabella",
+"La colonna Blob '%-.64s' non puo` essere usata nella specifica della chiave",
+"La colonna '%-.64s' e` troppo grande (max=%d). Utilizza un BLOB.",
+"Puo` esserci solo un campo AUTO e deve essere definito come chiave",
+"%s: Pronto per le connessioni\n",
+"%s: Shutdown normale\n",
+"%s: Ricevuto segnale %d. Interruzione!\n",
+"%s: Shutdown completato\n",
+"%s: Forzata la chiusura del thread %ld utente: '%-.64s'\n",
+"Impossibile creare il socket IP",
+"La tabella '%-.64s' non ha nessun indice come quello specificatato dalla CREATE INDEX. Ricrea la tabella",
+"L'argomento 'Field separator' non e` quello atteso. Controlla il manuale","
+"Non possono essere usate righe a lunghezza fissa con i BLOB. Usa 'FIELDS TERMINATED BY'.",
+"Il file '%-.64s' deve essere nella directory del database e deve essere leggibile da tutti",
+"Il file '%-.64s' esiste gia`",
+"Records: %ld Cancellati: %ld Saltati: %ld Avvertimenti: %ld",
+"Records: %ld Duplicati: %ld",
+"Sotto-parte della chiave errata. La parte di chiave utilizzata non e` una stringa o la lunghezza e` maggiore della parte di chiave.",
+"Non si possono cancellare tutti i campi con una ALTER TABLE. Utilizzare DROP TABLE",
+"Impossibile cancellare '%-.64s'. Controllare che il campo chiave esista",
+"Records: %ld Duplicati: %ld Avvertimenti: %ld",
+"INSERT TABLE '%-.64s' non e` permesso nella FROM table list",
+"Thread id: %lu sconosciuto",
+"Utente non proprietario del thread %lu",
+"Nessuna tabella usata",
+"Troppe stringhe per la colonna %-.64s e la SET",
+"Impossibile generare un nome del file log unico %-.64s.(1-999)\n",
+"La tabella '%-.64s' e` soggetta a lock in lettura e non puo` essere aggiornata",
+"Non e` stato impostato il lock per la tabella '%-.64s' con LOCK TABLES",
+"Il campo Blob '%-.64s' non puo` avere un valore di default",
+"Nome database errato '%-.100s'",
+"Nome tabella errato '%-.100s'",
+"La SELECT dovrebbe esaminare troppi record e usare troppo tempo. Controllare la WHERE e usa SET OPTION SQL_BIG_SELECTS=1 se e` tutto a posto.",
+"Errore sconosciuto",
+"Procedura '%-.64s' sconosciuta",
+"Numero di parametri errato per la procedura '%-.64s'",
+"Parametri errati per la procedura '%-.64s'",
+"Tabella '%-.64s' sconosciuta in %s",
+"Campo '%-.64s' specificato 2 volte",
+"Uso non valido di una funzione di raggruppamento",
+"La tabella '%-.64s' usa un'estensione che non esiste in questa versione di MySQL",
+"Una tabella deve avere almeno 1 colonna",
+"La tabella '%-.64s' e` piena",
+"Set di caratteri '%-.64s' sconosciuto",
+"Troppe tabelle. MySQL puo` usare solo %d tabelle in una join",
+"Troppi campi",
+"Riga troppo grande. La massima grandezza di una riga, non contando i BLOB, e` %d. Devi cambiare alcuni campi in BLOB",
+"Thread stack overrun: Usati: %ld di uno stack di %ld. Usa 'mysqld -O thread_stack=#' per specificare uno stack piu` grande.",
+"Trovata una dipendenza incrociata nella OUTER JOIN. Controlla le condizioni ON",
+"La colonna '%-.64s' e` usata con UNIQUE o INDEX ma non e` definita come NOT NULL",
+"Impossibile caricare la funzione '%-.64s'",
+"Impossibile inizializzare la funzione '%-.64s'; %-.80s",
+"Non sono ammessi path per le librerie condivisa",
+"La funzione '%-.64s' esiste gia`",
+"Impossibile aprire la libreria condivisa '%-.64s' (errno: %d %s)",
+"Impossibile trovare la funzione '%-.64s' nella libreria",
+"La funzione '%-.64s' non e` definita",
+"Sistema '%-.64s' bloccato a causa di troppi errori di connessione. Per sbloccarlo: 'mysqladmin flush-hosts'",
+"Al sistema '%-.64s' non e` consentita la connessione a questo server MySQL",
+"Impossibile cambiare la password usando MySQL come utente anonimo",
+"E` necessario il privilegio di update sulle tabelle del database mysql per cambiare le password per gli altri utenti",
+"Impossibile trovare la riga corrispondente nella tabella user",
+"Rows riconosciute: %ld Cambiate: %ld Warnings: %ld",
+"Impossibile creare un nuovo thread (errno %d). Se non ci sono problemi di memoria disponibile puoi consultare il manuale per controllare possibili problemi dipendenti dal SO",
+"Il numero delle colonne non corrisponde al conteggio alla riga %ld",
+"Impossibile riaprire la tabella: '%-.64s'",
+"Uso scorretto del valore NULL",
+"Errore '%-.64s' da regexp",
+"Il mescolare funzioni di aggregazione (MIN(),MAX(),COUNT()...) e non e` illegale se non c'e` una clausula GROUP BY",
+"GRANT non definita per l'utente '%-.32s' dalla macchina '%-.64s'",
+"Comando %-.16s negato per l'utente: '%-.32s@%-.64s' sulla tabella '%-.64s'",
+"Comando %-.16s negato per l'utente: '%-.32s@%-.64s' sulla colonna '%-.64s' della tabella '%-.64s'",
+"Comando GRANT/REVOKE illegale. Prego consultare il manuale per sapere quali privilegi possono essere usati.",
+"L'argomento host o utente per la GRANT e` troppo lungo",
+"La tabella '%-64s.%s' non esiste",
+"GRANT non definita per l'utente '%-.32s' dalla macchina '%-.64s' sulla tabella '%-.64s'",
+"Il comando utilizzato non e` supportato in questa versione di MySQL",
+"Errore di sintassi nella query SQL",
+"Il thread di inserimento ritardato non riesce ad avere il lock per la tabella %-.64s",
+"Troppi threads ritardati in uso",
+"Interrotta la connessione %ld al db: '%-.64s' utente: '%-.64s' (%s)",
+"Ricevuto un pacchetto piu` grande di 'max_allowed_packet'",
+"Rilevato un errore di lettura dalla pipe di connessione",
+"Rilevato un errore da fcntl()",
+"Ricevuti pacchetti non in ordine",
+"Impossibile scompattare i pacchetti di comunicazione",
+"Rilevato un errore ricevendo i pacchetti di comunicazione",
+"Rilevato un timeout ricevendo i pacchetti di comunicazione",
+"Rilevato un errore inviando i pacchetti di comunicazione",
+"Rilevato un timeout inviando i pacchetti di comunicazione",
+"La stringa di risposta e` piu` lunga di max_allowed_packet",
+"Il tipo di tabella usata non supporta colonne di tipo BLOB/TEXT",
+"Il tipo di tabella usata non supporta colonne di tipo AUTO_INCREMENT",
+"L'inserimento ritardato (INSERT DELAYED) non puo` essere usato con la tabella '%-.64s', perche` soggetta a lock da 'LOCK TABLES'",
+"Nome colonna '%-.100s' non corretto",
+"Il gestore delle tabelle non puo` indicizzare la colonna '%-.64s'",
+"Non tutte le tabelle nella tabella di MERGE sono definite in maniera identica",
+"Impossibile scrivere nella tabella '%-.64s' per limitazione di unicita`",
+"La colonna '%-.64s' di tipo BLOB e' usata in una chiave senza specificarne la lunghezza",
+"Tutte le parti di una chiave primaria devono essere dichiarate NOT NULL; se hai bisogno del valore NULL in una chiave usa UNIQUE",
+"Il risultato consiste di piu' di una riga",
+"Questo tipo di tabella richiede una chiave primaria",
+"Questa versione di MYSQL non e' compilata con il supporto RAID",
+"Stai il modo 'safe update' e hai provato ad aggiornare una tabella senza una WHERE che usi una chiave",
+"La chiave '%-.64s' non esiste nella tabella '%-.64s'",
+"Impossibile aprire la tabella",
+"Il gestore per la tabella non supporta il controllo/riparazione",
+"Non puoi eseguire questo comando in una transazione",
+"Rilevato l'errore %d durante la COMMIT",
+"Rilevato l'errore %d durante il ROLLBACK",
+"Rilevato l'errore %d durante il FLUSH_LOGS",
+"Rilevato l'errore %d durante il CHECKPOINT",
+"Abortita la connessione %ld al db: ''%-.64s' utente: '%-.32s' host: '%-.64s' (%-.64s)",
+"Il gestore per la tabella non supporta il dump binario",
+"Binlog e' stato chiuso mentre provavo ad eseguire FLUSH MASTER",
+"Fallita la ricostruzione dell'indice della tabella copiata '%-.64s'",
+"Errore dal master: '%-.64s",
+"Errore di rete ricevendo dal master",
+"Errore di rete inviando al master",
+"Impossibile trovare un indice FULLTEXT che corrisponda all'elenco delle colonne",
diff --git a/sql/share/japanese/errmsg.sys b/sql/share/japanese/errmsg.sys
new file mode 100644
index 00000000000..1b5547999a5
--- /dev/null
+++ b/sql/share/japanese/errmsg.sys
Binary files differ
diff --git a/sql/share/japanese/errmsg.txt b/sql/share/japanese/errmsg.txt
new file mode 100644
index 00000000000..da15c0a22f1
--- /dev/null
+++ b/sql/share/japanese/errmsg.txt
@@ -0,0 +1,197 @@
+/* Copyright Abandoned 1997 TCX DataKonsult AB & Monty Program KB & Detron HB
+ This file is public domain and comes with NO WARRANTY of any kind
+ 3.22.10-beta euc-japanese (ujis) text
+*/
+
+"hashchk",
+"isamchk",
+"NO",
+"YES",
+"'%-.64s' ¥Õ¥¡¥¤¥ë¤¬ºî¤ì¤Þ¤»¤ó (errno: %d)",
+"'%-.64s' ¥Æ¡¼¥Ö¥ë¤¬ºî¤ì¤Þ¤»¤ó.(errno: %d)",
+"'%-.64s' ¥Ç¡¼¥¿¥Ù¡¼¥¹¤¬ºî¤ì¤Þ¤»¤ó (errno: %d)",
+"'%-.64s' ¥Ç¡¼¥¿¥Ù¡¼¥¹¤¬ºî¤ì¤Þ¤»¤ó.´û¤Ë¤½¤Î¥Ç¡¼¥¿¥Ù¡¼¥¹¤¬Â¸ºß¤·¤Þ¤¹",
+"'%-.64s' ¥Ç¡¼¥¿¥Ù¡¼¥¹¤òÇË´þ¤Ç¤­¤Þ¤»¤ó. ¤½¤Î¥Ç¡¼¥¿¥Ù¡¼¥¹¤¬¤Ê¤¤¤Î¤Ç¤¹.",
+"¥Ç¡¼¥¿¥Ù¡¼¥¹ÇË´þ¥¨¥é¡¼ ('%-.64s' ¤òºï½ü¤Ç¤­¤Þ¤»¤ó, errno: %d)",
+"¥Ç¡¼¥¿¥Ù¡¼¥¹ÇË´þ¥¨¥é¡¼ ('%-.64s' ¤ò rmdir ¤Ç¤­¤Þ¤»¤ó, errno: %d)",
+"'%-.64s' ¤Îºï½ü¤¬¥¨¥é¡¼ (errno: %d)",
+"system table ¤Î¥ì¥³¡¼¥É¤òÆɤà»ö¤¬¤Ç¤­¤Þ¤»¤ó¤Ç¤·¤¿",
+"'%-.64s' ¤Î¥¹¥Æ¥¤¥¿¥¹¤¬ÆÀ¤é¤ì¤Þ¤»¤ó. (errno: %d)",
+"working directory ¤òÆÀ¤ë»ö¤¬¤Ç¤­¤Þ¤»¤ó¤Ç¤·¤¿. (errno: %d)",
+"¥Õ¥¡¥¤¥ë¤ò¥í¥Ã¥¯¤Ç¤­¤Þ¤»¤ó.(errno: %d)",
+"'%-.64s' ¥Õ¥¡¥¤¥ë¤ò³«¤¯»ö¤¬¤Ç¤­¤Þ¤»¤ó.(errno: %d)",
+"'%-.64s' ¥Õ¥¡¥¤¥ë¤ò¸«ÉÕ¤±¤ë»ö¤¬¤Ç¤­¤Þ¤»¤ó.(errno: %d)",
+"'%-.64s' ¥Ç¥£¥ì¥¯¥È¥ê¤¬Æɤá¤Þ¤»¤ó.(errno: %d)",
+"'%-.64s' ¥Ç¥£¥ì¥¯¥È¥ê¤Ë chdir ¤Ç¤­¤Þ¤»¤ó.(errno: %d)",
+"Record has changed since last read in table '%-.64s'",
+"Disk full (%s). 狼¤¬²¿¤«¤ò¸º¤é¤¹¤Þ¤Ç¤Þ¤Ã¤Æ¤¯¤À¤µ¤¤...",
+"table '%-.64s' ¤Ë key ¤¬½ÅÊ£¤·¤Æ¤¤¤Æ½ñ¤­¤³¤á¤Þ¤»¤ó",
+"Error on close of '%-.64s' (errno: %d)",
+"'%-.64s' ¥Õ¥¡¥¤¥ë¤ÎÆɤ߹þ¤ß¥¨¥é¡¼ (errno: %d)",
+"'%-.64s' ¤ò '%-.64s' ¤Ë rename ¤Ç¤­¤Þ¤»¤ó (errno: %d)",
+"'%-.64s' ¥Õ¥¡¥¤¥ë¤ò½ñ¤¯»ö¤¬¤Ç¤­¤Þ¤»¤ó (errno: %d)",
+"'%-.64s' ¤Ï¥í¥Ã¥¯¤µ¤ì¤Æ¤¤¤Þ¤¹",
+"Sort ̾̂",
+"View '%-.64s' ¤¬ '%-.64s' ¤ËÄêµÁ¤µ¤ì¤Æ¤¤¤Þ¤»¤ó",
+"Got error %d from table handler",
+"Table handler for '%-.64s' doesn't have this option",
+"'%-.64s'¤Î¤Ê¤«¤Ë¥ì¥³¡¼¥É¤¬¸«ÉÕ¤«¤ê¤Þ¤»¤ó",
+"¥Õ¥¡¥¤¥ë '%-.64s' ¤Î info ¤¬´Ö°ã¤Ã¤Æ¤¤¤ë¤è¤¦¤Ç¤¹",
+"'%-.64s' ¥Æ¡¼¥Ö¥ë¤Î key file ¤¬´Ö°ã¤Ã¤Æ¤¤¤ë¤è¤¦¤Ç¤¹. ½¤Éü¤ò¤·¤Æ¤¯¤À¤µ¤¤",
+"'%-.64s' ¥Æ¡¼¥Ö¥ë¤Ï¸Å¤¤·Á¼°¤Î key file ¤Î¤è¤¦¤Ç¤¹; ½¤Éü¤ò¤·¤Æ¤¯¤À¤µ¤¤",
+"'%-.64s' ¤ÏÆɤ߹þ¤ßÀìÍѤǤ¹",
+"Out of memory. ¥Ç¡¼¥â¥ó¤ò¥ê¥¹¥¿¡¼¥È¤·¤Æ¤ß¤Æ¤¯¤À¤µ¤¤ (%d bytes ɬÍ×)",
+"Out of sort memory. sort buffer size ¤¬Â­¤ê¤Ê¤¤¤è¤¦¤Ç¤¹.",
+"'%-.64s' ¥Õ¥¡¥¤¥ë¤òÆɤ߹þ¤ßÃæ¤Ë EOF ¤¬Í½´ü¤»¤Ì½ê¤Ç¸½¤ì¤Þ¤·¤¿. (errno: %d)",
+"Àܳ¤¬Â¿¤¹¤®¤Þ¤¹",
+"Out of memory; mysqld ¤«¤½¤Î¾¤Î¥×¥í¥»¥¹¤¬¥á¥â¥ê¡¼¤òÁ´¤Æ»È¤Ã¤Æ¤¤¤ë¤«³Îǧ¤·¤Æ¤¯¤À¤µ¤¤. ¥á¥â¥ê¡¼¤ò»È¤¤ÀڤäƤ¤¤Ê¤¤¾ì¹ç¡¢'ulimit' ¤òÀßÄꤷ¤Æ mysqld ¤Î¥á¥â¥ê¡¼»ÈÍѸ³¦Î̤ò¿¤¯¤¹¤ë¤«¡¢swap space ¤òÁý¤ä¤·¤Æ¤ß¤Æ¤¯¤À¤µ¤¤",
+"¤½¤Î address ¤Î hostname ¤¬°ú¤±¤Þ¤»¤ó.",
+"Bad handshake",
+"¥æ¡¼¥¶¡¼ '%-.32s@%-.64s' ¤Î '%-.64s' ¥Ç¡¼¥¿¥Ù¡¼¥¹¤Ø¤Î¥¢¥¯¥»¥¹¤òµñÈݤ·¤Þ¤¹",
+"¥æ¡¼¥¶¡¼ '%-.32s@%-.64s' ¤òµñÈݤ·¤Þ¤¹.(Using password: %s)",
+"¥Ç¡¼¥¿¥Ù¡¼¥¹¤¬ÁªÂò¤µ¤ì¤Æ¤¤¤Þ¤»¤ó.",
+"¤½¤Î¥³¥Þ¥ó¥É¤Ï²¿¡©",
+"Column '%-.64s' ¤Ï null ¤Ë¤Ï¤Ç¤­¤Ê¤¤¤Î¤Ç¤¹",
+"'%-.64s' ¤Ê¤ó¤Æ¥Ç¡¼¥¿¥Ù¡¼¥¹¤ÏÃΤê¤Þ¤»¤ó.",
+"Table '%-.64s' ¤Ï´û¤Ë¤¢¤ê¤Þ¤¹",
+"table '%-.64s' ¤Ï¤¢¤ê¤Þ¤»¤ó.",
+"Column: '%-.64s' in %-.64s is ambiguous",
+"Server ¤ò shutdown Ãæ...",
+"'%-.64s' column ¤Ï '%-.64s' ¤Ë¤Ï¤¢¤ê¤Þ¤»¤ó.",
+"'%-.64s' isn't in GROUP BY",
+"Can't group on '%-.64s'",
+"Statement has sum functions and columns in same statement",
+"Column count doesn't match value count",
+"Identifier name '%-.100s' ¤ÏŤ¹¤®¤Þ¤¹",
+"'%-.64s' ¤È¤¤¤¦ column ̾¤Ï½ÅÊ£¤·¤Æ¤Þ¤¹",
+"'%-.64s' ¤È¤¤¤¦ key ¤Î̾Á°¤Ï½ÅÊ£¤·¤Æ¤¤¤Þ¤¹",
+"'%-.64s' ¤Ï key %d ¤Ë¤ª¤¤¤Æ½ÅÊ£¤·¤Æ¤¤¤Þ¤¹",
+"Incorrect column specifier for column '%-.64s'",
+"%s : '%-.80s' ÉÕ¶á : %d ¹ÔÌÜ",
+"Query ¤¬¶õ¤Ç¤¹.",
+"'%-.64s' ¤Ï°ì°Õ¤Î table/alias ̾¤Ç¤Ï¤¢¤ê¤Þ¤»¤ó",
+"Invalid default value for '%-.64s'",
+"Ê£¿ô¤Î primary key ¤¬ÄêµÁ¤µ¤ì¤Þ¤·¤¿",
+"key ¤Î»ØÄ꤬¿¤¹¤®¤Þ¤¹. key ¤ÏºÇÂç %d ¤Þ¤Ç¤Ç¤¹",
+"Too many key parts specified. Max %d parts allowed",
+"key ¤¬Ä¹¤¹¤®¤Þ¤¹. key ¤ÎŤµ¤ÏºÇÂç %d ¤Ç¤¹",
+"Key column '%-.64s' ¤¬¥Æ¡¼¥Ö¥ë¤Ë¤¢¤ê¤Þ¤»¤ó.",
+"BLOB column '%-.64s' can't be used in key specification with the used table type",
+"column '%-.64s' ¤Ï,³ÎÊݤ¹¤ë column ¤ÎÂ礭¤µ¤¬Â¿¤¹¤®¤Þ¤¹. (ºÇÂç %d ¤Þ¤Ç). BLOB ¤ò¤«¤ï¤ê¤Ë»ÈÍѤ·¤Æ¤¯¤À¤µ¤¤.",
+"¥Æ¡¼¥Ö¥ë¤ÎÄêµÁ¤¬°ã¤¤¤Þ¤¹; There can only be one auto column and it must be defined as a key",
+"%s: ½àÈ÷´°Î»\n",
+"%s: Normal shutdown\n",
+"%s: Got signal %d. ̾̂!\n",
+"%s: Shutdown ´°Î»\n",
+"%s: ¥¹¥ì¥Ã¥É %ld ¶¯À©½ªÎ» user: '%-.64s'\n",
+"IP socket ¤¬ºî¤ì¤Þ¤»¤ó",
+"Table '%-.64s' ¤Ï¤½¤Î¤è¤¦¤Ê index ¤ò»ý¤Ã¤Æ¤¤¤Þ¤»¤ó(CREATE INDEX ¼Â¹Ô»þ¤Ë»ØÄꤵ¤ì¤Æ¤¤¤Þ¤»¤ó). ¥Æ¡¼¥Ö¥ë¤òºî¤êľ¤·¤Æ¤¯¤À¤µ¤¤",
+"Field separator argument is not what is expected. Check the manual",
+"You can't use fixed rowlength with BLOBs. Please use 'fields terminated by'.",
+"¥Õ¥¡¥¤¥ë '%-.64s' ¤Ï databse ¤Î directory ¤Ë¤¢¤ë¤«Á´¤Æ¤Î¥æ¡¼¥¶¡¼¤¬Æɤá¤ë¤è¤¦¤Ëµö²Ä¤µ¤ì¤Æ¤¤¤Ê¤±¤ì¤Ð¤Ê¤ê¤Þ¤»¤ó.",
+"File '%-.64s' ¤Ï´û¤Ë¸ºß¤·¤Þ¤¹",
+"¥ì¥³¡¼¥É¿ô: %ld ºï½ü: %ld Skipped: %ld Warnings: %ld",
+"¥ì¥³¡¼¥É¿ô: %ld ½ÅÊ£: %ld",
+"Incorrect sub part key. The used key part isn't a string or the used length is longer than the key part",
+"ALTER TABLE ¤ÇÁ´¤Æ¤Î column ¤Ïºï½ü¤Ç¤­¤Þ¤»¤ó. DROP TABLE ¤ò»ÈÍѤ·¤Æ¤¯¤À¤µ¤¤",
+"'%-.64s' ¤òÇË´þ¤Ç¤­¤Þ¤»¤ó¤Ç¤·¤¿. Check that column/key exists",
+"¥ì¥³¡¼¥É¿ô: %ld ½ÅÊ£¿ô: %ld Warnings: %ld",
+"INSERT TABLE '%-.64s' isn't allowed in FROM table list",
+"thread id: %lu ¤Ï¤¢¤ê¤Þ¤»¤ó",
+"thread %lu ¤Î¥ª¡¼¥Ê¡¼¤Ç¤Ï¤¢¤ê¤Þ¤»¤ó",
+"No tables used",
+"Too many strings for column %-.64s and SET",
+"Can't generate a unique log-filename %-.64s.(1-999)\n",
+"Table '%-.64s' ¤Ï READ lock ¤Ë¤Ê¤Ã¤Æ¤¤¤Æ¡¢¹¹¿·¤Ï¤Ç¤­¤Þ¤»¤ó",
+"Table '%-.64s' ¤Ï LOCK TABLES ¤Ë¤è¤Ã¤Æ¥í¥Ã¥¯¤µ¤ì¤Æ¤¤¤Þ¤»¤ó",
+"BLOB column '%-.64s' can't have a default value",
+"»ØÄꤷ¤¿ database ̾ '%-.100s' ¤¬´Ö°ã¤Ã¤Æ¤¤¤Þ¤¹",
+"»ØÄꤷ¤¿ table ̾ '%-.100s' ¤Ï¤Þ¤Á¤¬¤Ã¤Æ¤¤¤Þ¤¹",
+"The SELECT would examine 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",
+"Unknown error",
+"Unknown procedure '%-.64s'",
+"Incorrect parameter count to procedure '%-.64s'",
+"Incorrect parameters to procedure '%-.64s'",
+"Unknown table '%-.64s' in %s",
+"Column '%-.64s' specified twice",
+"Invalid use of group function",
+"Table '%-.64s' uses an extension that doesn't exist in this MySQL version",
+"¥Æ¡¼¥Ö¥ë¤ÏºÇÄã 1 ¸Ä¤Î column ¤¬É¬ÍפǤ¹",
+"table '%-.64s' ¤Ï¤¤¤Ã¤Ñ¤¤¤Ç¤¹",
+"character set '%-.64s' ¤Ï¥µ¥Ý¡¼¥È¤·¤Æ¤¤¤Þ¤»¤ó",
+"¥Æ¡¼¥Ö¥ë¤¬Â¿¤¹¤®¤Þ¤¹. MySQL can only use %d tables in a join",
+"column ¤¬Â¿¤¹¤®¤Þ¤¹",
+"row size ¤¬Â礭¤¹¤®¤Þ¤¹. BLOB ¤ò´Þ¤Þ¤Ê¤¤¾ì¹ç¤Î row size ¤ÎºÇÂç¤Ï %d ¤Ç¤¹. ¤¤¤¯¤Ä¤«¤Î field ¤ò BLOB ¤ËÊѤ¨¤Æ¤¯¤À¤µ¤¤.",
+"Thread stack overrun: Used: %ld of a %ld stack. ¥¹¥¿¥Ã¥¯Îΰè¤ò¿¤¯¤È¤ê¤¿¤¤¾ì¹ç¡¢'mysqld -O thread_stack=#' ¤È»ØÄꤷ¤Æ¤¯¤À¤µ¤¤",
+"Cross dependency found in OUTER JOIN. Examine your ON conditions",
+"Column '%-.64s' ¤¬ UNIQUE ¤« INDEX ¤Ç»ÈÍѤµ¤ì¤Þ¤·¤¿. ¤³¤Î¥«¥é¥à¤Ï NOT NULL ¤ÈÄêµÁ¤µ¤ì¤Æ¤¤¤Þ¤»¤ó.",
+"function '%-.64s' ¤ò ¥í¡¼¥É¤Ç¤­¤Þ¤»¤ó",
+"function '%-.64s' ¤ò½é´ü²½¤Ç¤­¤Þ¤»¤ó; %-.80s",
+"shared library ¤Ø¤Î¥Ñ¥¹¤¬Ä̤äƤ¤¤Þ¤»¤ó",
+"Function '%-.64s' ¤Ï´û¤ËÄêµÁ¤µ¤ì¤Æ¤¤¤Þ¤¹",
+"shared library '%-.64s' ¤ò³«¤¯»ö¤¬¤Ç¤­¤Þ¤»¤ó (errno: %d %s)",
+"function '%-.64s' ¤ò¥é¥¤¥Ö¥é¥ê¡¼Ãæ¤Ë¸«ÉÕ¤±¤ë»ö¤¬¤Ç¤­¤Þ¤»¤ó",
+"Function '%-.64s' ¤ÏÄêµÁ¤µ¤ì¤Æ¤¤¤Þ¤»¤ó",
+"Host '%-.64s' ¤Ï many connection error ¤Î¤¿¤á¡¢µñÈݤµ¤ì¤Þ¤·¤¿. 'mysqladmin flush-hosts' ¤Ç²ò½ü¤·¤Æ¤¯¤À¤µ¤¤",
+"Host '%-.64s' ¤Ï MySQL server ¤ËÀܳ¤òµö²Ä¤µ¤ì¤Æ¤¤¤Þ¤»¤ó",
+"MySQL ¤ò anonymous users ¤Ç»ÈÍѤ·¤Æ¤¤¤ë¾õÂ֤Ǥϡ¢¥Ñ¥¹¥ï¡¼¥É¤ÎÊѹ¹¤Ï¤Ç¤­¤Þ¤»¤ó",
+"¾¤Î¥æ¡¼¥¶¡¼¤Î¥Ñ¥¹¥ï¡¼¥É¤òÊѹ¹¤¹¤ë¤¿¤á¤Ë¤Ï, mysql ¥Ç¡¼¥¿¥Ù¡¼¥¹¤ËÂФ·¤Æ update ¤Îµö²Ä¤¬¤Ê¤±¤ì¤Ð¤Ê¤ê¤Þ¤»¤ó.",
+"Can't find any matching row in the user table",
+"°ìÃ׿ô(Rows matched): %ld Êѹ¹: %ld Warnings: %ld",
+"¿·µ¬¤Ë¥¹¥ì¥Ã¥É¤¬ºî¤ì¤Þ¤»¤ó¤Ç¤·¤¿ (errno %d). ¤â¤·ºÇÂç»ÈÍѵö²Ä¥á¥â¥ê¡¼¿ô¤ò±Û¤¨¤Æ¤¤¤Ê¤¤¤Î¤Ë¥¨¥é¡¼¤¬È¯À¸¤·¤Æ¤¤¤ë¤Ê¤é, ¥Þ¥Ë¥å¥¢¥ë¤ÎÃ椫¤é 'possible OS-dependent bug' ¤È¤¤¤¦Ê¸»ú¤òõ¤·¤Æ¤¯¤ß¤Æ¤À¤µ¤¤.",
+"Column count doesn't match value count at row %ld",
+"Can't reopen table: '%-.64s'",
+"NULL ÃͤλÈÍÑÊýË¡¤¬ÉÔŬÀڤǤ¹",
+"Got error '%-.64s' from regexp",
+"Mixing of GROUP columns (MIN(),MAX(),COUNT()...) with no GROUP columns is illegal if there is no GROUP BY clause",
+"¥æ¡¼¥¶¡¼ '%-.32s' (¥Û¥¹¥È '%-.64s' ¤Î¥æ¡¼¥¶¡¼) ¤Ïµö²Ä¤µ¤ì¤Æ¤¤¤Þ¤»¤ó",
+"¥³¥Þ¥ó¥É %-.16s ¤Ï ¥æ¡¼¥¶¡¼ '%-.32s@%-.64s' ,¥Æ¡¼¥Ö¥ë '%-.64s' ¤ËÂФ·¤Æµö²Ä¤µ¤ì¤Æ¤¤¤Þ¤»¤ó",
+"¥³¥Þ¥ó¥É %-.16s ¤Ï ¥æ¡¼¥¶¡¼ '%-.32s@%-.64s'\n ¥«¥é¥à '%-.64s' ¥Æ¡¼¥Ö¥ë '%-.64s' ¤ËÂФ·¤Æµö²Ä¤µ¤ì¤Æ¤¤¤Þ¤»¤ó",
+"Illegal GRANT/REVOKE command. Please consult the manual which privleges can be used.",
+"The host or user argument to GRANT is too long",
+"Table '%-64s.%s' doesn't exist",
+"There is no such grant defined for user '%-.32s' on host '%-.64s' on table '%-.64s'",
+"The used command is not allowed with this MySQL version",
+"Something is wrong in your syntax",
+"Delayed insert thread couldn't get requested lock for table %-.64s",
+"Too many delayed threads in use",
+"Aborted connection %ld to db: '%-.64s' user: '%-.64s' (%s)",
+"Got a packet bigger than 'max_allowed_packet'",
+"Got a read error from the connection pipe",
+"Got an error from fcntl()",
+"Got packets out of order",
+"Couldn't uncompress communication packet",
+"Got an error reading communication packets"
+"Got timeout reading communication packets",
+"Got an error writing communication packets",
+"Got timeout writing communication packets",
+"Result string is longer than max_allowed_packet",
+"The used table type doesn't support BLOB/TEXT columns",
+"The used table type doesn't support AUTO_INCREMENT columns",
+"INSERT DELAYED can't be used with table '%-.64s', because it is locked with LOCK TABLES",
+"Incorrect column name '%-.100s'",
+"The used table handler can't index column '%-.64s'",
+"All tables in the MERGE table are not defined identically",
+"Can't write, because of unique constraint, to table '%-.64s'",
+"BLOB column '%-.64s' used in key specification without a key length",
+"All parts of a PRIMARY KEY must be NOT NULL; If you need NULL in a key, use UNIQUE instead",
+"Result consisted of more than one row",
+"This table type requires a primary key",
+"This version of MySQL is not compiled with RAID support",
+"You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column",
+"Key '%-.64s' doesn't exist in table '%-.64s'",
+"Can't open table",
+"The handler for the table doesn't support check/repair",
+"You are not allowed to execute this command in a transaction",
+"Got error %d during COMMIT",
+"Got error %d during ROLLBACK",
+"Got error %d during FLUSH_LOGS",
+"Got error %d during CHECKPOINT",
+"Aborted connection %ld to db: '%-.64s' user: '%-.32s' host: `%-.64s' (%-.64s)",
+"The handler for the table does not support binary table dump",
+"Binlog closed while trying to FLUSH MASTER",
+"Failed rebuilding the index of dumped table '%-.64s'",
+"Error from master: '%-.64s'",
+"Net error reading from master",
+"Net error writing to master",
+"Can't find FULLTEXT index matching the column list",
diff --git a/sql/share/korean/errmsg.sys b/sql/share/korean/errmsg.sys
new file mode 100644
index 00000000000..4bd754f1ff5
--- /dev/null
+++ b/sql/share/korean/errmsg.sys
Binary files differ
diff --git a/sql/share/korean/errmsg.txt b/sql/share/korean/errmsg.txt
new file mode 100644
index 00000000000..b5f231e1b70
--- /dev/null
+++ b/sql/share/korean/errmsg.txt
@@ -0,0 +1,195 @@
+/* Copyright Abandoned 1997 TCX DataKonsult AB & Monty Program KB & Detron HB
+ This È­ÀÏ is public domain and comes with NO WARRANTY of any kind */
+
+"hashchk",
+"isamchk",
+"¾Æ´Ï¿À",
+"¿¹",
+"È­ÀÏ '%-.64s'¸¦ ¸¸µéÁö ¸øÇß½À´Ï´Ù. (¿¡·¯¹øÈ£: %d)",
+"Å×À̺í '%-.64s'¸¦ ¸¸µéÁö ¸øÇß½À´Ï´Ù. (¿¡·¯¹øÈ£: %d)",
+"µ¥ÀÌŸº£À̽º '%-.64s'¸¦ ¸¸µéÁö ¸øÇß½À´Ï´Ù.. (¿¡·¯¹øÈ£: %d)",
+"µ¥ÀÌŸº£À̽º '%-.64s'¸¦ ¸¸µéÁö ¸øÇß½À´Ï´Ù.. µ¥ÀÌŸº£À̽º°¡ Á¸ÀçÇÔ",
+"µ¥ÀÌŸº£À̽º '%-.64s'¸¦ Á¦°ÅÇÏÁö ¸øÇß½À´Ï´Ù. µ¥ÀÌŸº£À̽º°¡ Á¸ÀçÇÏÁö ¾ÊÀ½ ",
+"µ¥ÀÌŸº£À̽º Á¦°Å ¿¡·¯('%-.64s'¸¦ »èÁ¦ÇÒ ¼ö ¾øÀ¾´Ï´Ù, ¿¡·¯¹øÈ£: %d)",
+"µ¥ÀÌŸº£À̽º Á¦°Å ¿¡·¯(rmdir '%-.64s'¸¦ ÇÒ ¼ö ¾øÀ¾´Ï´Ù, ¿¡·¯¹øÈ£: %d)",
+"'%-.64s' »èÁ¦ Áß ¿¡·¯ (¿¡·¯¹øÈ£: %d)",
+"system Å×ÀÌºí¿¡¼­ ·¹Äڵ带 ÀÐÀ» ¼ö ¾ø½À´Ï´Ù.",
+"'%-.64s'ÀÇ »óŸ¦ ¾òÁö ¸øÇß½À´Ï´Ù. (¿¡·¯¹øÈ£: %d)",
+"¼öÇà µð·ºÅ丮¸¦ ãÁö ¸øÇß½À´Ï´Ù. (¿¡·¯¹øÈ£: %d)",
+"È­ÀÏÀ» Àá±×Áö(lock) ¸øÇß½À´Ï´Ù. (¿¡·¯¹øÈ£: %d)",
+"È­ÀÏÀ» ¿­Áö ¸øÇß½À´Ï´Ù.: '%-.64s'. (¿¡·¯¹øÈ£: %d)",
+"È­ÀÏÀ» ãÁö ¸øÇß½À´Ï´Ù.: '%-.64s' (¿¡·¯¹øÈ£: %d)",
+"'%-.64s'µð·ºÅ丮¸¦ ÀÐÁö ¸øÇß½À´Ï´Ù. (¿¡·¯¹øÈ£: %d)",
+"'%-.64s'µð·ºÅ丮·Î À̵¿ÇÒ ¼ö ¾ø¾ú½À´Ï´Ù. (¿¡·¯¹øÈ£: %d)",
+"Å×À̺í '%-.64s'¿¡¼­ ¸¶Áö¸·À¸·Î ÀÐÀº ÈÄ Record°¡ º¯°æµÇ¾ú½À´Ï´Ù.",
+"Disk full (%s). ´Ù¸¥ »ç¶÷ÀÌ Áö¿ï¶§±îÁö ±â´Ù¸³´Ï´Ù.....",
+"±â·ÏÇÒ ¼ö ¾øÀ¾´Ï´Ù., Å×À̺í '%-.64s'¿¡¼­ Áߺ¹ Å°",
+"'%-.64s'´Ý´Â Áß ¿¡·¯ (¿¡·¯¹øÈ£: %d)",
+"'%-.64s'È­ÀÏ Àб⠿¡·¯ (¿¡·¯¹øÈ£: %d)",
+"'%-.64s'¸¦ '%-.64s'·Î À̸§ º¯°æÁß ¿¡·¯ (¿¡·¯¹øÈ£: %d)",
+"'%-.64s'È­ÀÏ ±â·Ï Áß ¿¡·¯ (¿¡·¯¹øÈ£: %d)",
+"'%-.64s'°¡ º¯°æÇÒ ¼ö ¾øµµ·Ï Àá°ÜÀÖÀ¾´Ï´Ù.",
+"¼ÒÆ®°¡ ÁߴܵǾú½À´Ï´Ù.",
+"ºä '%-.64s'°¡ '%-.64s'¿¡¼­´Â Á¸ÀçÇÏÁö ¾ÊÀ¾´Ï´Ù.",
+"Å×À̺í handler¿¡¼­ %d ¿¡·¯°¡ ¹ß»ý ÇÏ¿´½À´Ï´Ù.",
+"'%-.64s'ÀÇ Å×À̺í handler´Â ÀÌ·¯ÇÑ ¿É¼ÇÀ» Á¦°øÇÏÁö ¾ÊÀ¾´Ï´Ù.",
+"'%-.64s'¿¡¼­ ·¹Äڵ带 ãÀ» ¼ö ¾øÀ¾´Ï´Ù.",
+"È­ÀÏÀÇ ºÎÁ¤È®ÇÑ Á¤º¸: '%-.64s'",
+"'%-.64s' Å×À̺íÀÇ ºÎÁ¤È®ÇÑ Å° Á¸Àç. ¼öÁ¤ÇϽÿÀ!",
+"'%-.64s' Å×À̺íÀÇ ÀÌÀü¹öÁ¯ÀÇ Å° Á¸Àç. ¼öÁ¤ÇϽÿÀ!",
+"Å×À̺í '%-.64s'´Â ÀбâÀü¿ë ÀÔ´Ï´Ù.",
+"Out of memory. µ¥¸óÀ» Àç ½ÇÇà ÈÄ ´Ù½Ã ½ÃÀÛÇϽÿÀ (needed %d bytes)",
+"Out of sort memory. daemon sort bufferÀÇ Å©±â¸¦ Áõ°¡½ÃÅ°¼¼¿ä",
+"'%-.64s' È­ÀÏÀ» Àд µµÁß À߸øµÈ eofÀ» ¹ß°ß (¿¡·¯¹øÈ£: %d)",
+"³Ê¹« ¸¹Àº ¿¬°á... max_connectionÀ» Áõ°¡ ½ÃÅ°½Ã¿À...",
+"Out of memory; mysqld³ª ¶Ç´Ù¸¥ ÇÁ·Î¼¼¼­¿¡¼­ »ç¿ë°¡´ÉÇÑ ¸Þ¸ð¸®¸¦ »ç¿ëÇÑÁö äũÇϽÿÀ. ¸¸¾à ±×·¸Áö ¾Ê´Ù¸é ulimit ¸í·ÉÀ» ÀÌ¿¿ëÇÏ¿© ´õ¸¹Àº ¸Þ¸ð¸®¸¦ »ç¿ëÇÒ ¼ö ÀÖµµ·Ï Çϰųª ½º¿Ò ½ºÆÐÀ̽º¸¦ Áõ°¡½ÃÅ°½Ã¿À",
+"´ç½ÅÀÇ ÄÄÇ»ÅÍÀÇ È£½ºÆ®À̸§À» ¾òÀ» ¼ö ¾øÀ¾´Ï´Ù.",
+"Bad handshake",
+"'%-.32s@%-.64s' »ç¿ëÀÚ´Â '%-.64s' µ¥ÀÌŸº£À̽º¿¡ Á¢±ÙÀÌ °ÅºÎ µÇ¾ú½À´Ï´Ù.",
+"'%-.32s@%-.64s' »ç¿ëÀÚ´Â Á¢±ÙÀÌ °ÅºÎ µÇ¾ú½À´Ï´Ù. (Using password: %s)",
+"¼±ÅÃµÈ µ¥ÀÌŸº£À̽º°¡ ¾ø½À´Ï´Ù.",
+"¸í·É¾î°¡ ¹ºÁö ¸ð¸£°Ú¾î¿ä....",
+"Ä®·³ '%-.64s'´Â ³Î(Null)ÀÌ µÇ¸é ¾ÈµË´Ï´Ù. ",
+"µ¥ÀÌŸº£À̽º '%-.64s'´Â ¾Ë¼ö ¾øÀ½",
+"Å×À̺í '%-.64s'´Â ÀÌ¹Ì Á¸ÀçÇÔ",
+"Å×À̺í '%-.64s'´Â ¾Ë¼ö ¾øÀ½",
+"Ä®·³: '%-.64s' in '%-.64s' ÀÌ ¸ðÈ£ÇÔ",
+"Server°¡ ¼Ë´Ù¿î ÁßÀÔ´Ï´Ù.",
+"Unknown Ä®·³ '%-.64s' in '%-.64s'",
+"'%-.64s'Àº GROUP BY¼Ó¿¡ ¾øÀ½",
+"'%-.64s'¸¦ ±×·ìÇÒ ¼ö ¾øÀ½",
+"Statement °¡ sum±â´ÉÀ» µ¿ÀÛÁßÀÌ°í Ä®·³µµ µ¿ÀÏÇÑ statementÀÔ´Ï´Ù.",
+"Ä®·³ÀÇ Ä«¿îÆ®°¡ °ªÀÇ Ä«¿îÆ®¿Í ÀÏÄ¡ÇÏÁö ¾Ê½À´Ï´Ù.",
+"Identifier '%-.100s'´Â ³Ê¹« ±æ±º¿ä.",
+"Áߺ¹µÈ Ä®·³ À̸§: '%-.64s'",
+"Áߺ¹µÈ Å° À̸§ : '%-.64s'",
+"Áߺ¹µÈ ÀÔ·Â °ª '%-.64s': key %d",
+"Ä®·³ '%-.64s'ÀÇ ºÎÁ¤È®ÇÑ Ä®·³ Á¤ÀÇÀÚ",
+"'%-.64s' ¿¡·¯ °°À¾´Ï´Ù. ('%-.80s' ¸í·É¾î ¶óÀÎ %d)",
+"Äõ¸®°á°ú°¡ ¾ø½À´Ï´Ù.",
+"Unique ÇÏÁö ¾ÊÀº Å×À̺í/alias: '%-.64s'",
+"'%-.64s'ÀÇ À¯È¿ÇÏÁö ¸øÇÑ µðÆúÆ® °ªÀ» »ç¿ëÇϼ̽À´Ï´Ù.",
+"Multiple primary key°¡ Á¤ÀǵǾî ÀÖ½¿",
+"³Ê¹« ¸¹Àº Å°°¡ Á¤ÀǵǾî ÀÖÀ¾´Ï´Ù.. ÃÖ´ë %dÀÇ Å°°¡ °¡´ÉÇÔ",
+"³Ê¹« ¸¹Àº Å° ºÎºÐ(parts)µéÀÌ Á¤ÀǵǾî ÀÖÀ¾´Ï´Ù.. ÃÖ´ë %d ºÎºÐÀÌ °¡´ÉÇÔ",
+"Á¤ÀÇµÈ Å°°¡ ³Ê¹« ±é´Ï´Ù. ÃÖ´ë Å°ÀÇ ±æÀÌ´Â %dÀÔ´Ï´Ù.",
+"Key Ä®·³ '%-.64s'´Â Å×ÀÌºí¿¡ Á¸ÀçÇÏÁö ¾Ê½À´Ï´Ù.",
+"BLOB Ä®·³ '%-.64s'´Â Å° Á¤ÀÇ¿¡¼­ »ç¿ëµÉ ¼ö ¾ø½À´Ï´Ù.",
+"Ä®·³ '%-.64s'ÀÇ Ä®·³ ±æÀÌ°¡ ³Ê¹« ±é´Ï´Ù (ÃÖ´ë = %d). ´ë½Å¿¡ BLOB¸¦ »ç¿ëÇϼ¼¿ä.",
+"ºÎÁ¤È®ÇÑ Å×À̺í Á¤ÀÇ; Å×À̺íÀº ÇϳªÀÇ auto Ä®·³ÀÌ Á¸ÀçÇÏ°í Å°·Î Á¤ÀǵǾîÁ®¾ß ÇÕ´Ï´Ù.",
+"%s: ¿¬°á ÁغñÁßÀÔ´Ï´Ù.\n",
+"%s: Á¤»óÀûÀÎ shutdown\n",
+"%s: %d ½ÅÈ£°¡ µé¾î¿ÔÀ½. ÁßÁö!\n",
+"%s: Shutdown ÀÌ ¿Ï·áµÊ!\n",
+"%s: thread %ldÀÇ °­Á¦ Á¾·á user: '%-.64s'\n",
+"IP ¼ÒÄÏÀ» ¸¸µéÁö ¸øÇß½À´Ï´Ù.",
+"Å×À̺í '%-.64s'´Â À妽º¸¦ ¸¸µéÁö ¾Ê¾Ò½À´Ï´Ù. alter Å×À̺í¸í·ÉÀ» ÀÌ¿ëÇÏ¿© Å×À̺íÀ» ¼öÁ¤Çϼ¼¿ä...",
+"ÇÊµå ±¸ºÐÀÚ ÀμöµéÀÌ ¿ÏÀüÇÏÁö ¾Ê½À´Ï´Ù. ¸Þ´º¾óÀ» ã¾Æ º¸¼¼¿ä.",
+"BLOB·Î´Â °íÁ¤±æÀÌÀÇ lowlength¸¦ »ç¿ëÇÒ ¼ö ¾ø½À´Ï´Ù. 'fields terminated by'¸¦ »ç¿ëÇϼ¼¿ä.",
+"'%-.64s' È­ÀÏ´Â µ¥ÀÌŸº£À̽º µð·ºÅ丮¿¡ Á¸ÀçÇϰųª ¸ðµÎ¿¡°Ô Àб⠰¡´ÉÇÏ¿©¾ß ÇÕ´Ï´Ù.",
+"'%-.64s' È­ÀÏÀº ÀÌ¹Ì Á¸ÀçÇÕ´Ï´Ù.",
+"·¹ÄÚµå: %ld°³ »èÁ¦: %ld°³ ½ºÅµ: %ld°³ °æ°í: %ld°³",
+"·¹ÄÚµå: %ld°³ Áߺ¹: %ld°³",
+"ºÎÁ¤È®ÇÑ ¼­¹ö ÆÄÆ® Å°. »ç¿ëµÈ Å° ÆÄÆ®°¡ ½ºÆ®¸µÀÌ ¾Æ´Ï°Å³ª Å° ÆÄÆ®ÀÇ ±æÀÌ°¡ ³Ê¹« ±é´Ï´Ù.",
+"ALTER TABLE ¸í·ÉÀ¸·Î´Â ¸ðµç Ä®·³À» Áö¿ï ¼ö ¾ø½À´Ï´Ù. DROP TABLE ¸í·ÉÀ» ÀÌ¿ëÇϼ¼¿ä.",
+"'%-.64s'¸¦ DROPÇÒ ¼ö ¾ø½À´Ï´Ù. Ä®·³À̳ª Å°°¡ Á¸ÀçÇÏ´ÂÁö äũÇϼ¼¿ä.",
+"·¹ÄÚµå: %ld°³ Áߺ¹: %ld°³ °æ°í: %ld°³",
+"INSERT TABLE '%-.64s' ´Â FROM Å×À̺í list¿¡¼­ Çã°¡µÇÁö ¾Ê¾Ò½À´Ï´Ù.",
+"¾Ë¼ö ¾ø´Â ¾²·¹µå id: %lu",
+"¾²·¹µå(Thread) %luÀÇ ¼ÒÀ¯ÀÚ°¡ ¾Æ´Õ´Ï´Ù.",
+"¾î¶² Å×ÀÌºíµµ »ç¿ëµÇÁö ¾Ê¾Ò½À´Ï´Ù.",
+"Ä®·³ %-.64s¿Í SET¿¡¼­ ½ºÆ®¸µÀÌ ³Ê¹« ¸¹½À´Ï´Ù.",
+"Unique ·Î±×È­ÀÏ '%-.64s'¸¦ ¸¸µé¼ö ¾ø½À´Ï´Ù.(1-999)\n",
+"Å×À̺í '%-.64s'´Â READ ¶ôÀÌ Àá°ÜÀ־ °»½ÅÇÒ ¼ö ¾ø½À´Ï´Ù.",
+"Å×À̺í '%-.64s'´Â LOCK TABLES ¸í·ÉÀ¸·Î Àá±âÁö ¾Ê¾Ò½À´Ï´Ù.",
+"BLOB Ä®·³ '%-.64s' ´Â µðÆúÆ® °ªÀ» °¡Áú ¼ö ¾ø½À´Ï´Ù.",
+"'%-.100s' µ¥ÀÌŸº£À̽ºÀÇ À̸§ÀÌ ºÎÁ¤È®ÇÕ´Ï´Ù.",
+"'%-.100s' Å×À̺í À̸§ÀÌ ºÎÁ¤È®ÇÕ´Ï´Ù.",
+"SELECT ¸í·É¿¡¼­ ³Ê¹« ¸¹Àº ·¹Äڵ带 ã±â ¶§¹®¿¡ ¸¹Àº ½Ã°£ÀÌ ¼Ò¿äµË´Ï´Ù. µû¶ó¼­ WHERE ¹®À» Á¡°ËÇϰųª, ¸¸¾à SELECT°¡ okµÇ¸é SET OPTION SQL_BIG_SELECTS=1 ¿É¼ÇÀ» »ç¿ëÇϼ¼¿ä.",
+"¾Ë¼ö ¾ø´Â ¿¡·¯ÀÔ´Ï´Ù.",
+"¾Ë¼ö ¾ø´Â ¼öÇ๮ : '%-.64s'",
+"'%-.64s' ¼öÇ๮¿¡ ´ëÇÑ ºÎÁ¤È®ÇÑ ÆĶó¸ÞÅÍ",
+"'%-.64s' ¼öÇ๮¿¡ ´ëÇÑ ºÎÁ¤È®ÇÑ ÆĶó¸ÞÅÍ",
+"¾Ë¼ö ¾ø´Â Å×À̺í '%-.64s' (µ¥ÀÌŸº£À̽º %s)",
+"Ä®·³ '%-.64s'´Â µÎ¹ø Á¤ÀǵǾî ÀÖÀ¾´Ï´Ù.",
+"À߸øµÈ ±×·ì ÇÔ¼ö¸¦ »ç¿ëÇÏ¿´½À´Ï´Ù.",
+"Å×À̺í '%-.64s'´Â È®Àå¸í·ÉÀ» ÀÌ¿ëÇÏÁö¸¸ ÇöÀçÀÇ MySQL ¹öÁ¯¿¡¼­´Â Á¸ÀçÇÏÁö ¾Ê½À´Ï´Ù.",
+"ÇϳªÀÇ Å×ÀÌºí¿¡¼­´Â Àû¾îµµ ÇϳªÀÇ Ä®·³ÀÌ Á¸ÀçÇÏ¿©¾ß ÇÕ´Ï´Ù.",
+"Å×À̺í '%-.64s'°¡ full³µ½À´Ï´Ù. ",
+"¾Ë¼ö¾ø´Â ¾ð¾î Set: '%-.64s'",
+"³Ê¹« ¸¹Àº Å×À̺íÀÌ JoinµÇ¾ú½À´Ï´Ù. MySQL¿¡¼­´Â JOIN½Ã %d°³ÀÇ Å×ÀÌºí¸¸ »ç¿ëÇÒ ¼ö ÀÖ½À´Ï´Ù.",
+"Ä®·³ÀÌ ³Ê¹« ¸¹½À´Ï´Ù.",
+"³Ê¹« Å« row »çÀÌÁîÀÔ´Ï´Ù. BLOB¸¦ °è»êÇÏÁö ¾Ê°í ÃÖ´ë row »çÀÌÁî´Â %dÀÔ´Ï´Ù. ¾ó¸¶°£ÀÇ ÇʵåµéÀ» BLOB·Î ¹Ù²Ù¼Å¾ß °Ú±º¿ä..",
+"¾²·¹µå ½ºÅÃÀÌ ³ÑÃƽÀ´Ï´Ù. »ç¿ë: %ld°³ ½ºÅÃ: %ld°³. ¸¸¾à ÇÊ¿ä½Ã ´õÅ« ½ºÅÃÀ» ¿øÇÒ¶§¿¡´Â 'mysqld -O thread_stack=#' ¸¦ Á¤ÀÇÇϼ¼¿ä",
+"Cross dependency found in OUTER JOIN. Examine your ON conditions",
+"'%-.64s' Ä®·³ÀÌ UNIQUE³ª INDEX¸¦ »ç¿ëÇÏ¿´Áö¸¸ NOT NULLÀÌ Á¤ÀǵÇÁö ¾Ê¾Ò±º¿ä...",
+"'%-.64s' ÇÔ¼ö¸¦ ·ÎµåÇÏÁö ¸øÇß½À´Ï´Ù.",
+"'%-.64s' ÇÔ¼ö¸¦ ÃʱâÈ­ ÇÏÁö ¸øÇß½À´Ï´Ù.; %-.80s",
+"°øÀ¯ ¶óÀ̹ö·¯¸®¸¦ À§ÇÑ Æнº°¡ Á¤ÀǵǾî ÀÖÁö ¾Ê½À´Ï´Ù.",
+"'%-.64s' ÇÔ¼ö´Â ÀÌ¹Ì Á¸ÀçÇÕ´Ï´Ù.",
+"'%-.64s' °øÀ¯ ¶óÀ̹ö·¯¸®¸¦ ¿­¼ö ¾ø½À´Ï´Ù.(¿¡·¯¹øÈ£: %d %s)",
+"¶óÀ̹ö·¯¸®¿¡¼­ '%-.64s' ÇÔ¼ö¸¦ ãÀ» ¼ö ¾ø½À´Ï´Ù.",
+"'%-.64s' ÇÔ¼ö°¡ Á¤ÀǵǾî ÀÖÁö ¾Ê½À´Ï´Ù.",
+"³Ê¹« ¸¹Àº ¿¬°á¿À·ù·Î ÀÎÇÏ¿© È£½ºÆ® '%-.64s'´Â ºí¶ôµÇ¾ú½À´Ï´Ù. 'mysqladmin flush-hosts'¸¦ ÀÌ¿ëÇÏ¿© ºí¶ôÀ» ÇØÁ¦Çϼ¼¿ä",
+"'%-.64s' È£½ºÆ®´Â ÀÌ MySQL¼­¹ö¿¡ Á¢¼ÓÇÒ Çã°¡¸¦ ¹ÞÁö ¸øÇß½À´Ï´Ù.",
+"´ç½ÅÀº MySQL¼­¹ö¿¡ À͸íÀÇ »ç¿ëÀÚ·Î Á¢¼ÓÀ» Çϼ̽À´Ï´Ù.À͸íÀÇ »ç¿ëÀÚ´Â ¾ÏÈ£¸¦ º¯°æÇÒ ¼ö ¾ø½À´Ï´Ù.",
+"´ç½ÅÀº ´Ù¸¥»ç¿ëÀÚµéÀÇ ¾ÏÈ£¸¦ º¯°æÇÒ ¼ö ÀÖµµ·Ï µ¥ÀÌŸº£À̽º º¯°æ±ÇÇÑÀ» °¡Á®¾ß ÇÕ´Ï´Ù.",
+"»ç¿ëÀÚ Å×ÀÌºí¿¡¼­ ÀÏÄ¡ÇÏ´Â °ÍÀ» ãÀ» ¼ö ¾øÀ¾´Ï´Ù.",
+"ÀÏÄ¡ÇÏ´Â Rows : %ld°³ º¯°æµÊ: %ld°³ °æ°í: %ld°³",
+"»õ·Î¿î ¾²·¹µå¸¦ ¸¸µé ¼ö ¾ø½À´Ï´Ù.(¿¡·¯¹øÈ£ %d). ¸¸¾à ¿©À¯¸Þ¸ð¸®°¡ ÀÖ´Ù¸é OS-dependent¹ö±× ÀÇ ¸Þ´º¾ó ºÎºÐÀ» ã¾Æº¸½Ã¿À.",
+"Row %ld¿¡¼­ Ä®·³ Ä«¿îÆ®¿Í value Ä«¿îÅÍ¿Í ÀÏÄ¡ÇÏÁö ¾Ê½À´Ï´Ù.",
+"Å×À̺íÀ» ´Ù½Ã ¿­¼ö ¾ø±º¿ä: '%-.64s',
+"NULL °ªÀ» À߸ø »ç¿ëÇϼ̱º¿ä...",
+"regexp¿¡¼­ '%-.64s'°¡ ³µ½À´Ï´Ù.",
+"Mixing of GROUP Ä®·³s (MIN(),MAX(),COUNT()...) with no GROUP Ä®·³s is illegal if there is no GROUP BY clause",
+"»ç¿ëÀÚ '%-.32s' (È£½ºÆ® '%-.64s')¸¦ À§ÇÏ¿© Á¤ÀÇµÈ ±×·± ½ÂÀÎÀº ¾ø½À´Ï´Ù.",
+"'%-.16s' ¸í·ÉÀº ´ÙÀ½ »ç¿ëÀÚ¿¡°Ô °ÅºÎµÇ¾ú½À´Ï´Ù. : '%-.32s@%-.64s' for Å×À̺í '%-.64s'",
+"'%-.16s' ¸í·ÉÀº ´ÙÀ½ »ç¿ëÀÚ¿¡°Ô °ÅºÎµÇ¾ú½À´Ï´Ù. : '%-.32s@%-.64s' for Ä®·³ '%-.64s' in Å×À̺í '%-.64s'",
+"À߸øµÈ GRANT/REVOKE ¸í·É. ¾î¶² ±Ç¸®¿Í ½ÂÀÎÀÌ »ç¿ëµÇ¾î Áú ¼ö ÀÖ´ÂÁö ¸Þ´º¾óÀ» º¸½Ã¿À.",
+"½ÂÀÎ(GRANT)À» À§ÇÏ¿© »ç¿ëÇÑ »ç¿ëÀÚ³ª È£½ºÆ®ÀÇ °ªµéÀÌ ³Ê¹« ±é´Ï´Ù.",
+"Å×À̺í '%-64s.%s' ´Â Á¸ÀçÇÏÁö ¾Ê½À´Ï´Ù.",
+"»ç¿ëÀÚ '%-.32s'(È£½ºÆ® '%-.64s')´Â Å×À̺í '%-.64s'¸¦ »ç¿ëÇϱâ À§ÇÏ¿© Á¤ÀÇµÈ ½ÂÀÎÀº ¾ø½À´Ï´Ù. ",
+"»ç¿ëµÈ ¸í·ÉÀº ÇöÀçÀÇ MySQL ¹öÁ¯¿¡¼­´Â ÀÌ¿ëµÇÁö ¾Ê½À´Ï´Ù.",
+"SQL ±¸¹®¿¡ ¿À·ù°¡ ÀÖ½À´Ï´Ù.",
+"Áö¿¬µÈ insert ¾²·¹µå°¡ Å×À̺í %-.64sÀÇ ¿ä±¸µÈ ¶ôÅ·À» ó¸®ÇÒ ¼ö ¾ø¾ú½À´Ï´Ù.",
+"³Ê¹« ¸¹Àº Áö¿¬ ¾²·¹µå¸¦ »ç¿ëÇÏ°í ÀÖ½À´Ï´Ù.",
+"µ¥ÀÌŸº£À̽º Á¢¼ÓÀ» À§ÇÑ ¿¬°á %ld°¡ Áß´ÜµÊ : '%-.64s' »ç¿ëÀÚ: '%-.64s' (%s)",
+"'max_allowed_packet'º¸´Ù ´õÅ« ÆÐŶÀ» ¹Þ¾Ò½À´Ï´Ù.",
+"¿¬°á ÆÄÀÌÇÁ·ÎºÎÅÍ ¿¡·¯°¡ ¹ß»ýÇÏ¿´½À´Ï´Ù.",
+"fcntl() ÇÔ¼ö·ÎºÎÅÍ ¿¡·¯°¡ ¹ß»ýÇÏ¿´½À´Ï´Ù.",
+"¼ø¼­°¡ ¸ÂÁö¾Ê´Â ÆÐŶÀ» ¹Þ¾Ò½À´Ï´Ù.",
+"Åë½Å ÆÐŶÀÇ ¾ÐÃàÇØÁ¦¸¦ ÇÒ ¼ö ¾ø¾ú½À´Ï´Ù.",
+"Åë½Å ÆÐŶÀ» Àд Áß ¿À·ù°¡ ¹ß»ýÇÏ¿´½À´Ï´Ù."
+"Åë½Å ÆÐŶÀ» Àд Áß timeoutÀÌ ¹ß»ýÇÏ¿´½À´Ï´Ù.",
+"Åë½Å ÆÐŶÀ» ±â·ÏÇÏ´Â Áß ¿À·ù°¡ ¹ß»ýÇÏ¿´½À´Ï´Ù.",
+"Åë½Å ÆÐÆÂÀ» ±â·ÏÇÏ´Â Áß timeoutÀÌ ¹ß»ýÇÏ¿´½À´Ï´Ù.",
+"Result string is longer than max_allowed_packet",
+"The used table type doesn't support BLOB/TEXT columns",
+"The used table type doesn't support AUTO_INCREMENT columns",
+"INSERT DELAYED can't be used with table '%-.64s', because it is locked with LOCK TABLES",
+"Incorrect column name '%-.100s'",
+"The used table handler can't index column '%-.64s'",
+"All tables in the MERGE table are not defined identically",
+"Can't write, because of unique constraint, to table '%-.64s'",
+"BLOB column '%-.64s' used in key specification without a key length",
+"All parts of a PRIMARY KEY must be NOT NULL; If you need NULL in a key, use UNIQUE instead",
+"Result consisted of more than one row",
+"This table type requires a primary key",
+"This version of MySQL is not compiled with RAID support",
+"You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column",
+"Key '%-.64s' doesn't exist in table '%-.64s'",
+"Can't open table",
+"The handler for the table doesn't support check/repair",
+"You are not allowed to execute this command in a transaction",
+"Got error %d during COMMIT",
+"Got error %d during ROLLBACK",
+"Got error %d during FLUSH_LOGS",
+"Got error %d during CHECKPOINT",
+"Aborted connection %ld to db: '%-.64s' user: '%-.32s' host: `%-.64s' (%-.64s)",
+"The handler for the table does not support binary table dump",
+"Binlog closed while trying to FLUSH MASTER",
+"Failed rebuilding the index of dumped table '%-.64s'",
+"Error from master: '%-.64s'",
+"Net error reading from master",
+"Net error writing to master",
+"Can't find FULLTEXT index matching the column list",
diff --git a/sql/share/norwegian-ny/.cvsignore b/sql/share/norwegian-ny/.cvsignore
new file mode 100755
index 00000000000..2f68f259c40
--- /dev/null
+++ b/sql/share/norwegian-ny/.cvsignore
@@ -0,0 +1 @@
+errmsg.sys
diff --git a/sql/share/norwegian-ny/errmsg.txt b/sql/share/norwegian-ny/errmsg.txt
new file mode 100644
index 00000000000..75f86103f7c
--- /dev/null
+++ b/sql/share/norwegian-ny/errmsg.txt
@@ -0,0 +1,197 @@
+/* Copyright Abandoned 1997 TCX DataKonsult AB & Monty Program KB & Detron HB
+ This file is public domain and comes with NO WARRANTY of any kind */
+
+/* Roy-Magne Mo rmo@www.hivolda.no 97 */
+
+"hashchk",
+"isamchk",
+"NEI",
+"JA",
+"Kan ikkje opprette fila '%-.64s' (Feilkode: %d)",
+"Kan ikkje opprette tabellen '%-.64s' (Feilkode: %d)",
+"Kan ikkje opprette databasen '%-.64s'. Feil %d",
+"Kan ikkje opprette databasen '%-.64s'. Databasen eksisterer",
+"Kan ikkje fjerne (drop) '%-.64s'. Databasen eksisterer ikkje",
+"Feil ved fjerning (drop) av databasen (kan ikkje slette '%-.64s', feil %d)",
+"Feil ved sletting av database (kan ikkje slette katalogen '%-.64s', feil %d)",
+"Feil ved sletting av '%-.64s' (Feilkode: %d)",
+"Kan ikkje lese posten i systemkatalogen",
+"Kan ikkje lese statusen til '%-.64s' (Feilkode: %d)",
+"Kan ikkje lese aktiv katalog(Feilkode: %d)",
+"Kan ikkje låse fila (Feilkode: %d)",
+"Kan ikkje åpne fila: '%-.64s'. (Feilkode: %d)",
+"Kan ikkje finne fila: '%-.64s' (Feilkode: %d)",
+"Kan ikkje lese katalogen '%-.64s' (Feilkode: %d)",
+"Kan ikkje skifte katalog til '%-.64s' (Feilkode: %d)",
+"Posten har vorte endra sidan den sist vart lesen '%-.64s'",
+"Ikkje meir diskplass (%s). Ventar på å få frigjort plass....",
+"Kan ikkje skrive, flere like nyklar i tabellen '%-.64s'",
+"Feil ved lukking av '%-.64s' (Feilkode: %d)",
+"Feil ved lesing av '%-.64s' (Feilkode: %d)",
+"Feil ved omdøyping av '%-.64s' til '%-.64s' (Feilkode: %d)",
+"Feil ved skriving av fila '%-.64s' (Feilkode: %d)",
+"'%-.64s' er låst mot oppdateringar",
+"Sortering avbrote",
+"View '%-.64s' eksisterar ikkje for '%-.64s'",
+"Mottok feil %d fra tabell handterar",
+"Tabell håndteraren for '%-.64s' har ikkje denne moglegheita",
+"Kan ikkje finne posten i '%-.64s'",
+"Feil informasjon i fila: '%-.64s'",
+"Tabellen '%-.64s' har feil i nykkelfila, Prøv å reparere den",
+"Gammel nykkelfil for tabellen '%-.64s'; Reparer den!",
+"'%-.64s' er skrivetryggja",
+"Ikkje meir minne. Start på nytt tenesten og prøv igjen (trengte %d bytar)",
+"Ikkje meir sorteringsminne. Auk sorteringsminnet (sorteringsbffer storleik) for tenesten",
+"Uventa slutt på fil (eof) ved lesing av fila '%-.64s' (Feilkode: %d)",
+"For mange tilkoplingar (connections)",
+"Tomt for tråd plass/minne",
+"Kan ikkje få tak i vertsnavn for di adresse",
+"Feil handtrykk (handshake)",
+"Tilgang ikkje tillate for brukar: '%-.32s@%-.64s' til databasen '%-.64s' nekta",
+"Tilgang ikke tillate for brukar: '%-.32s@%-.64s' (Brukar passord: %s)",
+"Ingen database vald",
+"Ukjent kommando",
+"Kolonne '%-.64s' kan ikkje vere null",
+"Ukjent database '%-.64s'",
+"Tabellen '%-.64s' eksisterar allereide",
+"Ukjent tabell '%-.64s'",
+"Kolonne: '%-.64s' i tabell %s er ikkje eintydig",
+"Tenar nedkopling er i gang",
+"Ukjent felt '%-.64s' i tabell %s",
+"Brukte '%-.64s' som ikkje var i group by",
+"Kan ikkje gruppere på '%-.64s'",
+"Uttrykket har summer (sum) funksjoner og kolonner i same uttrykk",
+"Kolonne telling stemmer verdi telling",
+"Identifikator '%-.64s' er for lang",
+"Feltnamnet '%-.64s' eksisterte frå før",
+"Nøkkelnamnet '%-.64s' eksisterte frå før",
+"Like verdiar '%-.64s' for nykkel %d",
+"Feil kolonne spesifikator for kolonne '%-.64s'",
+"%s attmed '%-.64s' på line %d",
+"Førespurnad var tom",
+"Ikkje unikt tabell/alias: '%-.64s'",
+"Ugyldig standardverdi for '%-.64s'",
+"Fleire primærnyklar spesifisert",
+"For mange nykler spesifisert. Maks %d nyklar tillatt",
+"For mange nykkeldelar spesifisert. Maks %d delar tillatt",
+"Spesifisert nykkel var for lang. Maks nykkellengde er %d",
+"Nykkel kolonne '%-.64s' eksiterar ikkje i tabellen",
+"Blob kolonne '%-.64s' kan ikkje brukast ved spesifikasjon av nyklar",
+"For stor nykkellengde for felt '%-.64s' (maks = %d). Bruk BLOB istadenfor",
+"Bare eitt auto felt kan være definert som nøkkel.",
+"%s: klar for tilkoblingar\n",
+"%s: Normal nedkopling\n",
+"%s: Oppdaga signal %d. Avsluttar!\n",
+"%s: Nedkopling komplett\n",
+"%s: Påtvinga avslutning av tråd %ld brukar: '%-.64s'\n",
+"Kan ikkje opprette IP socket",
+"Tabellen '%-.64s' har ingen index som den som er brukt i CREATE INDEX. Oprett tabellen på nytt",
+"Felt skiljer argumenta er ikkje som venta, sjå dokumentasjonen",
+"Ein kan ikkje bruke faste feltlengder med BLOB. Vennlisgt bruk 'fields terminated by'.",
+"Filen '%-.64s' må være i database-katalogen for å være lesbar for alle",
+"Filen '%-.64s' eksisterte allereide",
+"Poster: %ld Fjerna: %ld Hoppa over: %ld Åtvaringar: %ld",
+"Poster: %ld Like: %ld",
+"Feil delnykkel. Den brukte delnykkelen er ikkje ein streng eller den oppgitte lengda er lengre enn nykkellengden",
+"Ein kan ikkje slette alle felt med ALTER TABLE. Bruk DROP TABLE istadenfor.",
+"Kan ikkje DROP '%-.64s'. Undersøk om felt/nøkkel eksisterar.",
+"Postar: %ld Like: %ld Åtvaringar: %ld",
+"INSERT TABLE '%-.64s' er ikkje tillate i FROM tabell liste",
+"Ukjent tråd id: %lu",
+"Du er ikkje eigar av tråd %lu",
+"Ingen tabellar i bruk",
+"For mange tekststrengar felt %s og SET",
+"Kan ikkje lage unikt loggfilnavn %s.(1-999)\n",
+"Tabellen '%-.64s' var låst med READ lås og kan ikkje oppdaterast",
+"Tabellen '%-.64s' var ikkje låst med LOCK TABLES",
+"Blob feltet '%-.64s' kan ikkje ha ein standard verdi",
+"Ugyldig database namn '%-.64s'",
+"Ugyldig tabell namn '%-.64s'",
+"SELECT ville undersøkje for mange postar og ville sannsynligvis ta veldig lang tid. Undersøk WHERE klausulen og bruk SET OPTION SQL_BIG_SELECTS=1 om SELECTen er korrekt"
+"Ukjend feil",
+"Ukjend prosedyre %s",
+"Feil parameter tal til prosedyra %s",
+"Feil parameter til prosedyra %s",
+"Ukjend tabell '%-.64s' i %s",
+"Feltet '%-.64s' er spesifisert to gangar",
+"Invalid use of group function",
+"Table '%-.64s' uses a extension that doesn't exist in this MySQL version",
+"A table must have at least 1 column",
+"The table '%-.64s' is full",
+"Unknown character set: '%-.64s'",
+"Too many tables. MySQL can only use %d tables in a join",
+"Too many fields",
+"Too big row size. The maximum row size, not counting blobs, is %d. You have to change some fields to blobs",
+"Thread stack overrun: Used: %ld of a %ld stack. Use 'mysqld -O thread_stack=#' to specify a bigger stack if needed",
+"Cross dependency found in OUTER JOIN. Examine your ON conditions",
+"Column '%-.32s' is used with UNIQUE or INDEX but is not defined as NOT NULL",
+"Can't load function '%-.64s'",
+"Can't initialize function '%-.64s'; %-.80s",
+"No paths allowed for shared library",
+"Function '%-.64s' already exist",
+"Can't open shared library '%-.64s' (errno: %d %s)",
+"Can't find function '%-.64s' in library'",
+"Function '%-.64s' is not defined",
+"Host '%-.64s' is blocked because of many connection errors. Unblock with 'mysqladmin flush-hosts'",
+"Host '%-.64s' is not allowed to connect to this MySQL server",
+"You are using MySQL as an anonymous users and anonymous users are not allowed to change passwords",
+"You must have privileges to update tables in the mysql database to be able to change passwords for others",
+"Can't find any matching row in the user table",
+"Rows matched: %ld Changed: %ld Warnings: %ld",
+"Can't create a new thread (errno %d). If you are not out of available memory you can consult the manual for any possible OS dependent bug",
+"Column count doesn't match value count at row %ld",
+"Can't reopen table: '%-.64s',
+"Invalid use of NULL value",
+"Got error '%-.64s' from regexp",
+"Mixing of GROUP columns (MIN(),MAX(),COUNT()...) with no GROUP columns is illegal if there is no GROUP BY clause",
+"There is no such grant defined for user '%-.32s' on host '%-.64s'",
+"%-.16s command denied to user: '%-.32s@%-.64s' for table '%-.64s'",
+"%-.16s command denied to user: '%-.32s@%-.64s' for column '%-.64s' in table '%-.64s'",
+"Illegal GRANT/REVOKE command. Please consult the manual which privleges can be used.",
+"The host or user argument to GRANT is too long",
+"Table '%-64s.%s' doesn't exist",
+"There is no such grant defined for user '%-.32s' on host '%-.64s' on table '%-.64s'",
+"The used command is not allowed with this MySQL version",
+"Something is wrong in your syntax",
+"Delayed insert thread couldn't get requested lock for table %-.64s",
+"Too many delayed threads in use",
+"Aborted connection %ld to db: '%-.64s' user: '%-.64s' (%s)",
+"Got a packet bigger than 'max_allowed_packet'",
+"Got a read error from the connection pipe",
+"Got an error from fcntl()",
+"Got packets out of order",
+"Couldn't uncompress communication packet",
+"Got an error reading communication packets"
+"Got timeout reading communication packets",
+"Got an error writing communication packets",
+"Got timeout writing communication packets",
+"Result string is longer than max_allowed_packet",
+"The used table type doesn't support BLOB/TEXT columns",
+"The used table type doesn't support AUTO_INCREMENT columns",
+"INSERT DELAYED can't be used with table '%-.64s', because it is locked with LOCK TABLES",
+"Incorrect column name '%-.100s'",
+"The used table handler can't index column '%-.64s'",
+"All tables in the MERGE table are not defined identically",
+"Can't write, because of unique constraint, to table '%-.64s'",
+"BLOB column '%-.64s' used in key specification without a key length",
+"All parts of a PRIMARY KEY must be NOT NULL; If you need NULL in a key, use UNIQUE instead",
+"Result consisted of more than one row",
+"This table type requires a primary key",
+"This version of MySQL is not compiled with RAID support",
+"You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column",
+"Key '%-.64s' doesn't exist in table '%-.64s'",
+"Can't open table",
+"The handler for the table doesn't support check/repair",
+"You are not allowed to execute this command in a transaction",
+"Got error %d during COMMIT",
+"Got error %d during ROLLBACK",
+"Got error %d during FLUSH_LOGS",
+"Got error %d during CHECKPOINT",
+"Aborted connection %ld to db: '%-.64s' user: '%-.32s' host: `%-.64s' (%-.64s)",
+"The handler for the table does not support binary table dump",
+"Binlog closed while trying to FLUSH MASTER",
+"Failed rebuilding the index of dumped table '%-.64s'",
+"Error from master: '%-.64s'",
+"Net error reading from master",
+"Net error writing to master",
+"Can't find FULLTEXT index matching the column list",
diff --git a/sql/share/norwegian/.cvsignore b/sql/share/norwegian/.cvsignore
new file mode 100755
index 00000000000..2f68f259c40
--- /dev/null
+++ b/sql/share/norwegian/.cvsignore
@@ -0,0 +1 @@
+errmsg.sys
diff --git a/sql/share/norwegian/errmsg.txt b/sql/share/norwegian/errmsg.txt
new file mode 100644
index 00000000000..7ad97882398
--- /dev/null
+++ b/sql/share/norwegian/errmsg.txt
@@ -0,0 +1,197 @@
+/* Copyright Abandoned 1997 TCX DataKonsult AB & Monty Program KB & Detron HB
+ This file is public domain and comes with NO WARRANTY of any kind */
+
+/* Roy-Magne Mo rmo@www.hivolda.no 97 */
+
+"hashchk",
+"isamchk",
+"NEI",
+"JA",
+"Kan ikke opprette fila '%-.64s' (Feilkode: %d)",
+"Kan ikke opprette tabellen '%-.64s' (Feilkode: %d)",
+"Kan ikke opprette databasen '%-.64s'. Feil %d",
+"Kan ikke opprette databasen '%-.64s'. Databasen eksisterer",
+"Kan ikke fjerne (drop) '%-.64s'. Databasen eksisterer ikke",
+"Feil ved fjerning (drop) av databasen (kan ikke slette '%-.64s', feil %d)",
+"Feil ved sletting av database (kan ikke slette katalogen '%-.64s', feil %d)",
+"Feil ved sletting av '%-.64s' (Feilkode: %d)",
+"Kan ikke lese posten i systemkatalogen",
+"Kan ikke lese statusen til '%-.64s' (Feilkode: %d)",
+"Kan ikke lese aktiv katalog(Feilkode: %d)",
+"Kan ikke låse fila (Feilkode: %d)",
+"Kan ikke åpne fila: '%-.64s'. (Feilkode: %d)",
+"Kan ikke finne fila: '%-.64s' (Feilkode: %d)",
+"Kan ikke lese katalogen '%-.64s' (Feilkode: %d)",
+"Kan ikke skifte katalog til '%-.64s' (Feilkode: %d)",
+"Posten har blitt endret siden den ble lest '%-.64s'",
+"Ikke mer diskplass (%s). Venter på å få frigjort plass....",
+"Kan ikke skrive, flere like nøkler i tabellen '%-.64s'",
+"Feil ved lukking av '%-.64s' (Feilkode: %d)",
+"Feil ved lesing av '%-.64s' (Feilkode: %d)",
+"Feil ved omdøping av '%-.64s' til '%-.64s' (Feilkode: %d)",
+"Feil ved skriving av fila '%-.64s' (Feilkode: %d)",
+"'%-.64s' er låst mot oppdateringer",
+"Sortering avbrutt",
+"View '%-.64s' eksisterer ikke for '%-.64s'",
+"Mottok feil %d fra tabell håndterer",
+"Tabell håndtereren for '%-.64s' har ikke denne muligheten",
+"Kan ikke finne posten i '%-.64s'",
+"Feil informasjon i filen: '%-.64s'",
+"Tabellen '%-.64s' har feil i nøkkelfilen, forsøk å reparer den",
+"Gammel nøkkelfil for tabellen '%-.64s'; Reparer den!",
+"'%-.64s' er skrivebeskyttet",
+"Ikke mer minne. Star på nytt tjenesten og prøv igjen (trengte %d byter)",
+"Ikke mer sorteringsminne. Øk sorteringsminnet (sort buffer size) for tjenesten",
+"Uventet slutt på fil (eof) ved lesing av filen '%-.64s' (Feilkode: %d)",
+"For mange tilkoblinger (connections)",
+"Tomt for tråd plass/minne",
+"Kan ikke få tak i vertsnavn for din adresse",
+"Feil håndtrykk (handshake)",
+"Tilgang nektet for bruker: '%-.32s@%-.64s' til databasen '%-.64s' nektet",
+"Tilgang nektet for bruker: '%-.32s@%-.64s' (Bruker passord: %s)",
+"Ingen database valgt",
+"Ukjent kommando",
+"Kolonne '%-.64s' kan ikke vere null",
+"Ukjent database '%-.64s'",
+"Tabellen '%-.64s' eksisterer allerede",
+"Ukjent tabell '%-.64s'",
+"Felt: '%-.64s' i tabell %s er ikke entydig",
+"Database nedkobling er i gang",
+"Ukjent kolonne '%-.64s' i tabell %s",
+"Brukte '%-.64s' som ikke var i group by",
+"Kan ikke gruppere på '%-.64s'",
+"Uttrykket har summer (sum) funksjoner og kolonner i samme uttrykk",
+"Felt telling stemmer verdi telling",
+"Identifikator '%-.64s' er for lang",
+"Feltnavnet '%-.64s' eksisterte fra før",
+"Nøkkelnavnet '%-.64s' eksisterte fra før",
+"Like verdier '%-.64s' for nøkkel %d",
+"Feil kolonne spesifikator for felt '%-.64s'",
+"%s nær '%-.64s' på linje %d",
+"Forespørsel var tom",
+"Ikke unikt tabell/alias: '%-.64s'",
+"Ugyldig standardverdi for '%-.64s'",
+"Fleire primærnøkle spesifisert",
+"For mange nøkler spesifisert. Maks %d nøkler tillatt",
+"For mange nøkkeldeler spesifisert. Maks %d deler tillatt",
+"Spesifisert nøkkel var for lang. Maks nøkkellengde er is %d",
+"Nøkkel felt '%-.64s' eksiterer ikke i tabellen",
+"Blob felt '%-.64s' kan ikke brukes ved spesifikasjon av nøkler",
+"For stor nøkkellengde for kolonne '%-.64s' (maks = %d). Bruk BLOB istedenfor",
+"Bare ett auto felt kan være definert som nøkkel.",
+"%s: klar for tilkoblinger\n",
+"%s: Normal avslutning\n",
+"%s: Oppdaget signal %d. Avslutter!\n",
+"%s: Avslutning komplett\n",
+"%s: Påtvinget avslutning av tråd %ld bruker: '%-.64s'\n",
+"Kan ikke opprette IP socket",
+"Tabellen '%-.64s' har ingen index som den som er brukt i CREATE INDEX. Gjenopprett tabellen",
+"Felt skiller argumentene er ikke som forventet, se dokumentasjonen",
+"En kan ikke bruke faste feltlengder med BLOB. Vennlisgt bruk 'fields terminated by'.",
+"Filen '%-.64s' må være i database-katalogen for å være lesbar for alle",
+"Filen '%-.64s' eksisterte allerede",
+"Poster: %ld Fjernet: %ld Hoppet over: %ld Advarsler: %ld",
+"Poster: %ld Like: %ld",
+"Feil delnøkkel. Den brukte delnøkkelen er ikke en streng eller den oppgitte lengde er lengre enn nøkkel lengden",
+"En kan ikke slette alle felt med ALTER TABLE. Bruk DROP TABLE isteden.",
+"Kan ikke DROP '%-.64s'. Undersøk om felt/nøkkel eksisterer.",
+"Poster: %ld Like: %ld Advarsler: %ld",
+"INSERT TABLE '%-.64s' er ikke tillatt i FROM tabell liste",
+"Ukjent tråd id: %lu",
+"Du er ikke eier av tråden %lu",
+"Ingen tabeller i bruk",
+"For mange tekststrenger kolonne %s og SET",
+"Kan ikke lage unikt loggfilnavn %s.(1-999)\n",
+"Tabellen '%-.64s' var låst med READ lås og kan ikke oppdateres",
+"Tabellen '%-.64s' var ikke låst med LOCK TABLES",
+"Blob feltet '%-.64s' kan ikke ha en standard verdi",
+"Ugyldig database navn '%-.64s'",
+"Ugyldig tabell navn '%-.64s'",
+"SELECT ville undersøke for mange poster og ville sannsynligvis ta veldig lang tid. Undersøk WHERE klausulen og bruk SET OPTION SQL_BIG_SELECTS=1 om SELECTen er korrekt"
+"Ukjent feil",
+"Ukjent prosedyre %s",
+"Feil parameter antall til prosedyren %s",
+"Feil parametre til prosedyren %s",
+"Ukjent tabell '%-.64s' i %s",
+"Feltet '%-.64s' er spesifisert to ganger",
+"Invalid use of group function",
+"Table '%-.64s' uses a extension that doesn't exist in this MySQL version",
+"A table must have at least 1 column",
+"The table '%-.64s' is full",
+"Unknown character set: '%-.64s'",
+"Too many tables. MySQL can only use %d tables in a join",
+"Too many fields",
+"Too big row size. The maximum row size, not counting blobs, is %d. You have to change some fields to blobs",
+"Thread stack overrun: Used: %ld of a %ld stack. Use 'mysqld -O thread_stack=#' to specify a bigger stack if needed",
+"Cross dependency found in OUTER JOIN. Examine your ON conditions",
+"Column '%-.32s' is used with UNIQUE or INDEX but is not defined as NOT NULL",
+"Can't load function '%-.64s'",
+"Can't initialize function '%-.64s'; %-.80s",
+"No paths allowed for shared library",
+"Function '%-.64s' already exist",
+"Can't open shared library '%-.64s' (errno: %d %s)",
+"Can't find function '%-.64s' in library'",
+"Function '%-.64s' is not defined",
+"Host '%-.64s' is blocked because of many connection errors. Unblock with 'mysqladmin flush-hosts'",
+"Host '%-.64s' is not allowed to connect to this MySQL server",
+"You are using MySQL as an anonymous users and anonymous users are not allowed to change passwords",
+"You must have privileges to update tables in the mysql database to be able to change passwords for others",
+"Can't find any matching row in the user table",
+"Rows matched: %ld Changed: %ld Warnings: %ld",
+"Can't create a new thread (errno %d). If you are not out of available memory you can consult the manual for any possible OS dependent bug",
+"Column count doesn't match value count at row %ld",
+"Can't reopen table: '%-.64s',
+"Invalid use of NULL value",
+"Got error '%-.64s' from regexp",
+"Mixing of GROUP columns (MIN(),MAX(),COUNT()...) with no GROUP columns is illegal if there is no GROUP BY clause",
+"There is no such grant defined for user '%-.32s' on host '%-.64s'",
+"%-.16s command denied to user: '%-.32s@%-.64s' for table '%-.64s'",
+"%-.16s command denied to user: '%-.32s@%-.64s' for column '%-.64s' in table '%-.64s'",
+"Illegal GRANT/REVOKE command. Please consult the manual which privleges can be used.",
+"The host or user argument to GRANT is too long",
+"Table '%-64s.%s' doesn't exist",
+"There is no such grant defined for user '%-.32s' on host '%-.64s' on table '%-.64s'",
+"The used command is not allowed with this MySQL version",
+"Something is wrong in your syntax",
+"Delayed insert thread couldn't get requested lock for table %-.64s",
+"Too many delayed threads in use",
+"Aborted connection %ld to db: '%-.64s' user: '%-.64s' (%s)",
+"Got a packet bigger than 'max_allowed_packet'",
+"Got a read error from the connection pipe",
+"Got an error from fcntl()",
+"Got packets out of order",
+"Couldn't uncompress communication packet",
+"Got an error reading communication packets"
+"Got timeout reading communication packets",
+"Got an error writing communication packets",
+"Got timeout writing communication packets",
+"Result string is longer than max_allowed_packet",
+"The used table type doesn't support BLOB/TEXT columns",
+"The used table type doesn't support AUTO_INCREMENT columns",
+"INSERT DELAYED can't be used with table '%-.64s', because it is locked with LOCK TABLES",
+"Incorrect column name '%-.100s'",
+"The used table handler can't index column '%-.64s'",
+"All tables in the MERGE table are not defined identically",
+"Can't write, because of unique constraint, to table '%-.64s'",
+"BLOB column '%-.64s' used in key specification without a key length",
+"All parts of a PRIMARY KEY must be NOT NULL; If you need NULL in a key, use UNIQUE instead",
+"Result consisted of more than one row",
+"This table type requires a primary key",
+"This version of MySQL is not compiled with RAID support",
+"You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column",
+"Key '%-.64s' doesn't exist in table '%-.64s'",
+"Can't open table",
+"The handler for the table doesn't support check/repair",
+"You are not allowed to execute this command in a transaction",
+"Got error %d during COMMIT",
+"Got error %d during ROLLBACK",
+"Got error %d during FLUSH_LOGS",
+"Got error %d during CHECKPOINT",
+"Aborted connection %ld to db: '%-.64s' user: '%-.32s' host: `%-.64s' (%-.64s)",
+"The handler for the table does not support binary table dump",
+"Binlog closed while trying to FLUSH MASTER",
+"Failed rebuilding the index of dumped table '%-.64s'",
+"Error from master: '%-.64s'",
+"Net error reading from master",
+"Net error writing to master",
+"Can't find FULLTEXT index matching the column list",
diff --git a/sql/share/polish/errmsg.sys b/sql/share/polish/errmsg.sys
new file mode 100644
index 00000000000..e3879e04810
--- /dev/null
+++ b/sql/share/polish/errmsg.sys
Binary files differ
diff --git a/sql/share/polish/errmsg.txt b/sql/share/polish/errmsg.txt
new file mode 100644
index 00000000000..b73631afed1
--- /dev/null
+++ b/sql/share/polish/errmsg.txt
@@ -0,0 +1,199 @@
+/* Copyright Abandoned 1997 TCX DataKonsult AB & Monty Program KB & Detron HB
+ This file is public domain and comes with NO WARRANTY of any kind
+
+ Changed by Jaroslaw Lewandowski <jotel@itnet.com.pl>
+ Charset ISO-8859-2
+*/
+
+"hashchk",
+"isamchk",
+"TAK",
+"NIE",
+"Nie mo¿na stworzyæ pliku '%-.64s' (Kod b³êdu: %d)",
+"Nie mo¿na stworzyæ tabeli '%-.64s' (Kod b³êdu: %d)",
+"Nie mo¿na stworzyæ bazy danych '%-.64s'. B³?d %d",
+"Nie mo¿na stworzyæ bazy danych '%-.64s'. Baza danych ju¿ istnieje",
+"Nie mo¿na usun?æ bazy danych '%-.64s'. Baza danych nie istnieje",
+"B³?d podczas usuwania bazy danych (nie mo¿na usun?æ '%-.64s', b³?d %d)",
+"B³?d podczas usuwania bazy danych (nie mo¿na wykonaæ rmdir '%-.64s', b³?d %d)",
+"B³?d podczas usuwania '%-.64s' (Kod b³êdu: %d)",
+"Nie mo¿na odczytaæ rekordu z tabeli systemowej",
+"Nie mo¿na otrzymaæ statusu '%-.64s' (Kod b³êdu: %d)",
+"Nie mo¿na rozpoznaæ aktualnego katalogu (Kod b³êdu: %d)",
+"Nie mo¿na zablokowaæ pliku (Kod b³êdu: %d)",
+"Nie mo¿na otworzyæ pliku: '%-.64s'. (Kod b³êdu: %d)",
+"Nie mo¿na znale¥æ pliku: '%-.64s' (Kod b³êdu: %d)",
+"Nie mo¿na odczytaæ katalogu '%-.64s' (Kod b³êdu: %d)",
+"Nie mo¿na zmieniæ katalogu na '%-.64s' (Kod b³êdu: %d)",
+"Rekord zosta³ zmieniony od ostaniego odczytania z tabeli '%-.64s'",
+"Dysk pe³ny (%s). Oczekiwanie na zwolnienie miejsca....",
+"Nie mo¿na zapisaæ, powtórzone klucze w tabeli '%-.64s'",
+"B³?d podczas zamykania '%-.64s' (Kod b³êdu: %d)",
+"B³?d podczas odczytu pliku '%-.64s' (Kod b³êdu: %d)",
+"B³?d podczas zmieniania nazwy '%-.64s' na '%-.64s' (Kod b³êdu: %d)",
+"B³?d podczas zapisywania pliku '%-.64s' (Kod b³êdu: %d)",
+"'%-.64s' jest zablokowany na wypadek zmian",
+"Sortowanie przerwane",
+"Widok '%-.64s' nie istnieje dla '%-.64s'",
+"Otrzymano b³?d %d z obs³ugi tabeli",
+"Obs³uga tabeli '%-.64s' nie posiada tej opcji",
+"Nie mo¿na znale¥æ rekordu w '%-.64s'",
+"Niew³a?ciwa informacja w pliku: '%-.64s'",
+"Niew³a?ciwy plik kluczy dla tabeli: '%-.64s'. Spróbuj go naprawiæ",
+"Plik kluczy dla tabeli '%-.64s' jest starego typu; Napraw go!",
+"'%-.64s' jest tylko do odczytu",
+"Zbyt ma³o pamiêci. Uruchom ponownie demona i spróbuj ponownie (potrzeba %d bajtów)",
+"Zbyt ma³o pamiêci dla sortowania. Zwiêksz wielko?æ bufora demona dla sortowania",
+"Nieoczekiwany 'eof' napotkany podczas czytania z pliku '%-.64s' (Kod b³êdu: %d)",
+"Zbyt wiele po³?czeñ",
+"Zbyt ma³o miejsca/pamiêci dla w?tku",
+"Nie mo¿na otrzymaæ nazwy hosta dla twojego adresu",
+"Z³y uchwyt(handshake)",
+"Access denied for user: '%-.32s@%-.64s' to database '%-.64s'",
+"Access denied for user: '%-.32s@%-.64s' (Using password: %s)",
+"Nie wybrano ¿adnej bazy danych",
+"Nieznana komenda",
+"Kolumna '%-.64s' nie mo¿e byæ null",
+"Nieznana baza danych '%-.64s'",
+"Tabela '%-.64s' ju¿ istnieje",
+"Nieznana tabela '%-.64s'",
+"Kolumna: '%-.64s' w %s jest dwuznaczna",
+"Trwa koñczenie dzia³ania serwera",
+"Nieznana kolumna '%-.64s' w %s",
+"U¿yto '%-.64s' bez umieszczenia w group by",
+"Nie mo¿na grupowaæ po '%-.64s'",
+"Zapytanie ma funkcje sumuj?ce i kolumny w tym samym zapytaniu",
+"Liczba kolumn nie odpowiada liczbie warto?ci",
+"Nazwa identyfikatora '%-.64s' jest zbyt d³uga",
+"Powtórzona nazwa kolumny '%-.64s'",
+"Powtórzony nazwa klucza '%-.64s'",
+"Powtórzone wyst?pienie '%-.64s' dla klucza %d",
+"B³êdna specyfikacja kolumny dla kolumny '%-.64s'",
+"%s obok '%-.64s' w linii %d",
+"Zapytanie by³o puste",
+"Tabela/alias nie s? unikalne: '%-.64s'",
+"Niew³a?ciwa warto?æ domy?lna dla '%-.64s'",
+"Zdefiniowano wiele kluczy podstawowych",
+"Okre?lono zbyt wiele kluczy. Dostêpnych jest maksymalnie %d kluczy",
+"Okre?lono zbyt wiele czê?ci klucza. Dostêpnych jest maksymalnie %d czê?ci",
+"Zdefinowany klucz jest zbyt d³ugi. Maksymaln? d³ugo?ci? klucza jest %d",
+"Kolumna '%-.64s' zdefiniowana w kluczu nie istnieje w tabeli",
+"Kolumna typu Blob '%-.64s' nie mo¿e byæ u¿yta w specyfikacji klucza",
+"Zbyt du¿a d³ugo?æ kolumny '%-.64s' (maks. = %d). W zamian u¿yj typu BLOB",
+"W tabeli mo¿e byæ tylko jedno pole auto i musi ono byæ zdefiniowane jako klucz",
+"%s: gotowe do po³?czenia\n",
+"%s: Standardowe zakoñczenie dzia³ania\n",
+"%s: Otrzymano sygna³ %d. Koñczenie dzia³ania!\n",
+"%s: Zakoñczenie dzia³ania wykonane\n",
+"%s: Wymuszenie zamkniêcia w?tku %ld u¿ytkownik: '%-.64s'\n",
+"Nie mo¿na stworzyæ socket'u IP",
+"Tabela '%-.64s' nie ma indeksu takiego jak w CREATE INDEX. Stwórz tabelê",
+"Nie oczekiwano separatora. Sprawd¥ podrêcznik","
+"Nie mo¿na u¿yæ sta³ej d³ugo?ci wiersza z polami typu BLOB. U¿yj 'fields terminated by'.",
+"Plik '%-.64s' musi znajdowaæ sie w katalogu bazy danych lub mieæ prawa czytania przez wszystkich",
+"Plik '%-.64s' ju¿ istnieje",
+"Recordów: %ld Usuniêtych: %ld Pominiêtych: %ld Ostrze¿eñ: %ld",
+"Rekordów: %ld Duplikatów: %ld",
+"B³êdna podczê?æ klucza. U¿yta czê?æ klucza nie jest ³añcuchem lub u¿yta d³ugo?æ jest wiêksza ni¿ czê?æ klucza",
+"Nie mo¿na usun?æ wszystkich pól wykorzystuj?c ALTER TABLE. W zamian u¿yj DROP TABLE",
+"Nie mo¿na wykonaæ operacji DROP '%-.64s'. Sprawd¥, czy to pole/klucz istnieje",
+"Rekordów: %ld Duplikatów: %ld Ostrze¿eñ: %ld",
+"Operacja INSERT TABLE '%-.64s' nie jest dozwolona w li?cie tabel w FROM",
+"Nieznany identyfikator w?tku: %lu",
+"Nie jeste? w³a?cicielem w?tku %lu",
+"Nie ma ¿adej u¿ytej tabeli",
+"Zbyt wiele ³añcuchów dla kolumny %s i polecenia SET",
+"Nie mo¿na stworzyæ unikalnej nazwy pliku z logiem %s.(1-999)\n",
+"Tabela '%-.64s' zosta³a zablokowana przez READ i nie mo¿e zostaæ zaktualizowana",
+"Tabela '%-.64s' nie zosta³a zablokowana poleceniem LOCK TABLES",
+"Pole typu blob '%-.64s' nie mo¿e mieæ domy?lnej warto?ci",
+"Niedozwolona nazwa bazy danych '%-.64s'",
+"Niedozwolona nazwa tabeli '%-.64s'...",
+"Operacja SELECT bêdzie dotyczy³a zbyt wielu rekordów i prawdopodobnie zajmie bardzo du¿o czasu. Sprawd¥ warunek WHERE i u¿yj SQL_OPTION BIG_SELECTS=1 je?li operacja SELECT jest poprawna",
+"Unknown error",
+"Unkown procedure %s",
+"Wrong parameter count to procedure %s",
+"Wrong parameters to procedure %s",
+"Unknown table '%-.64s' in %s",
+"Field '%-.64s' specified twice",
+"Invalid use of group function",
+"Table '%-.64s' uses a extension that doesn't exist in this MySQL version",
+"A table must have at least 1 column",
+"The table '%-.64s' is full",
+"Unknown character set: '%-.64s'",
+"Too many tables. MySQL can only use %d tables in a join",
+"Too many fields",
+"Too big row size. The maximum row size, not counting blobs, is %d. You have to change some fields to blobs",
+"Thread stack overrun: Used: %ld of a %ld stack. Use 'mysqld -O thread_stack=#' to specify a bigger stack if needed",
+"Cross dependency found in OUTER JOIN. Examine your ON conditions",
+"Column '%-.32s' is used with UNIQUE or INDEX but is not defined as NOT NULL",
+"Can't load function '%-.64s'",
+"Can't initialize function '%-.64s'; %-.80s",
+"No paths allowed for shared library",
+"Function '%-.64s' already exist",
+"Can't open shared library '%-.64s' (errno: %d %s)",
+"Can't find function '%-.64s' in library'",
+"Function '%-.64s' is not defined",
+"Host '%-.64s' is blocked because of many connection errors. Unblock with 'mysqladmin flush-hosts'",
+"Host '%-.64s' is not allowed to connect to this MySQL server",
+"You are using MySQL as an anonymous users and anonymous users are not allowed to change passwords",
+"You must have privileges to update tables in the mysql database to be able to change passwords for others",
+"Can't find any matching row in the user table",
+"Rows matched: %ld Changed: %ld Warnings: %ld",
+"Can't create a new thread (errno %d). If you are not out of available memory you can consult the manual for any possible OS dependent bug",
+"Column count doesn't match value count at row %ld",
+"Can't reopen table: '%-.64s',
+"Invalid use of NULL value",
+"Got error '%-.64s' from regexp",
+"Mixing of GROUP columns (MIN(),MAX(),COUNT()...) with no GROUP columns is illegal if there is no GROUP BY clause",
+"There is no such grant defined for user '%-.32s' on host '%-.64s'",
+"%-.16s command denied to user: '%-.32s@%-.64s' for table '%-.64s'",
+"%-.16s command denied to user: '%-.32s@%-.64s' for column '%-.64s' in table '%-.64s'",
+"Illegal GRANT/REVOKE command. Please consult the manual which privleges can be used.",
+"The host or user argument to GRANT is too long",
+"Table '%-64s.%s' doesn't exist",
+"There is no such grant defined for user '%-.32s' on host '%-.64s' on table '%-.64s'",
+"The used command is not allowed with this MySQL version",
+"Something is wrong in your syntax",
+"Delayed insert thread couldn't get requested lock for table %-.64s",
+"Too many delayed threads in use",
+"Aborted connection %ld to db: '%-.64s' user: '%-.64s' (%s)",
+"Got a packet bigger than 'max_allowed_packet'",
+"Got a read error from the connection pipe",
+"Got an error from fcntl()",
+"Got packets out of order",
+"Couldn't uncompress communication packet",
+"Got an error reading communication packets"
+"Got timeout reading communication packets",
+"Got an error writing communication packets",
+"Got timeout writing communication packets",
+"Result string is longer than max_allowed_packet",
+"The used table type doesn't support BLOB/TEXT columns",
+"The used table type doesn't support AUTO_INCREMENT columns",
+"INSERT DELAYED can't be used with table '%-.64s', because it is locked with LOCK TABLES",
+"Incorrect column name '%-.100s'",
+"The used table handler can't index column '%-.64s'",
+"All tables in the MERGE table are not defined identically",
+"Can't write, because of unique constraint, to table '%-.64s'",
+"BLOB column '%-.64s' used in key specification without a key length",
+"All parts of a PRIMARY KEY must be NOT NULL; If you need NULL in a key, use UNIQUE instead",
+"Result consisted of more than one row",
+"This table type requires a primary key",
+"This version of MySQL is not compiled with RAID support",
+"You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column",
+"Key '%-.64s' doesn't exist in table '%-.64s'",
+"Can't open table",
+"The handler for the table doesn't support check/repair",
+"You are not allowed to execute this command in a transaction",
+"Got error %d during COMMIT",
+"Got error %d during ROLLBACK",
+"Got error %d during FLUSH_LOGS",
+"Got error %d during CHECKPOINT",
+"Aborted connection %ld to db: '%-.64s' user: '%-.32s' host: `%-.64s' (%-.64s)",
+"The handler for the table does not support binary table dump",
+"Binlog closed while trying to FLUSH MASTER",
+"Failed rebuilding the index of dumped table '%-.64s'",
+"Error from master: '%-.64s'",
+"Net error reading from master",
+"Net error writing to master",
+"Can't find FULLTEXT index matching the column list",
diff --git a/sql/share/portuguese/errmsg.sys b/sql/share/portuguese/errmsg.sys
new file mode 100644
index 00000000000..e9d5d4b9cec
--- /dev/null
+++ b/sql/share/portuguese/errmsg.sys
Binary files differ
diff --git a/sql/share/portuguese/errmsg.txt b/sql/share/portuguese/errmsg.txt
new file mode 100644
index 00000000000..466a2cadfd4
--- /dev/null
+++ b/sql/share/portuguese/errmsg.txt
@@ -0,0 +1,195 @@
+/* Copyright Abandoned 1997 TCX DataKonsult AB & Monty Program KB & Detron HB
+ This file is public domain and comes with NO WARRANTY of any kind */
+
+"hashchk",
+"isamchk",
+"NO",
+"YES",
+"Nao consegui criar o arquivo '%-.64s' (Erro: %d)",
+"Nao consegui criar a tabela '%-.64s' (Erro: %d)",
+"Nao consegui criar o banco de dados '%-.64s'. Erro %d",
+"Nao consegui criar o banco de dados '%-.64s'. Este banco ja existe",
+"Nao consegui deletar o banco de dados '%-.64s'. Este banco nao existe",
+"Erro deletando o banco de dados(Nao foi possivel deletar '%-.64s', erro %d)",
+"Erro deletando o banco de dados(Nao foi possivel remover o diretorio '%-.64s', erro %d)",
+"Erro ao deletar '%-.64s' (Erro: %d)",
+"Nao foi possivel ler o registro na tabela do sistema",
+"Nao foi possivel obter o status de '%-.64s' (Erro: %d)",
+"Nao foi possivel obter o diretorio corrente (Erro: %d)",
+"Nao foi possivel travar o arquivo (Erro: %d)",
+"Nao foi possivel abrir arquivo: '%-.64s'. (Erro: %d)",
+"Nao foi possivel encontrar arquivo: '%-.64s' (Erro: %d)",
+"Nao foi possivel ler o diretorio de '%-.64s' (Erro: %d)",
+"Nao foi possivel ir para o diretorio '%-.64s' (Erro: %d)",
+"Registro alterado apos a ultima leitura da tabela '%-.64s'",
+"Disco cheio (%s). Aguardando espaco livre....",
+"Nao foi possivel gravar, chave duplicada na tabela '%-.64s'",
+"Erro ao fechar '%-.64s' (Erro: %d)",
+"Erro lendo arquivo '%-.64s' (Erro: %d)",
+"Erro ao renomear '%-.64s' to '%-.64s' (Erro: %d)",
+"Error gravando arquivo '%-.64s' (Erro: %d)",
+"'%-.64s' esta travado contra alteracoes",
+"Ordenacao cancelada",
+"Visao '%-.64s' nao existe para '%-.64s'",
+"Erro %d do manipulador de tabelas",
+"Manipulador da tabela '%-.64s' nao suporta esta opcao",
+"Nao foi possivel encontrar o registro em '%-.64s'",
+"Informacao invalida no arquivo: '%-.64s'",
+"Arquivo de indice invalido na tabela: '%-.64s'. Tente conserta-lo!",
+"Arquivo de indice destaualizado na tabela '%-.64s'; Conserte-o!",
+"'%-.64s' esta disponivel somente para leitura",
+"Sem memoria. Renicie o programa e tente novamente (Necessita de %d bytes)",
+"Sem memoria para ordenacao. Aumente o espaco de memoria para ordenacao.",
+"Fim de arquivo inesperado enquanto lendo o arquivo '%-.64s' (Erro: %d)",
+"Excesso de conexoes",
+"Thread sem memoria disponivel",
+"Nao foi possivel obter o nome da maquina para este endereco IP",
+"Comunicacao invalida",
+"Acesso negado ao usuario : '%-.32s@%-.64s' ao banco de dados '%-.64s'",
+"Acesso negado ao usuario: '%-.32s@%-.64s' (usando a senha: %s)",
+"Nenhum banco de dados selecionado",
+"Comando desconhecido",
+"Coluna '%-.64s' nao pode ser vazia",
+"Banco de dados '%-.64s' desconhecido",
+"Tabela '%-.64s' ja existe",
+"Tabela '%-.64s' desconhecida",
+"Coluna: '%-.64s' em %s e ambigua",
+"Finalizacao do servidor em andamento",
+"Coluna '%-.64s' desconhecida em %s",
+"'%-.64s' utilizado nao esta em 'group by'",
+"Nao foi possivel agrupar em '%-.64s'",
+"Clausula contem funcoes de soma e colunas juntos",
+"Contagem de colunas nao confere com a contagem de valores",
+"Nome do identificador '%-.64s' muito grande",
+"Nome da coluna '%-.64s' duplicado",
+"Nome da chave '%-.64s' duplicado",
+"Inclusao de '%-.64s' duplicada para a chave %d",
+"Especificador de coluna invalido para a coluna '%-.64s'",
+"%s proximo de '%-.64s' a linha %d",
+"Selecao vazia",
+"Tabela/alias nao e unica: '%-.64s'",
+"Valor padrao invalido para '%-.64s'",
+"Mais de uma chave primaria definida",
+"Muitas chaves definidas. O maximo permitido sao %d chaves",
+"Muitas partes de chave definidas. O maximo permitido sao %d partes",
+"Chave especificada e muito longa. O comprimento maximo permitido e %d",
+"Coluna chave '%-.64s' nao existe na tabela",
+"Coluna binaria '%-.64s' nao pode ser utilizada na definicao de chaves",
+"Comprimento da coluna '%-.64s' muito grande(max = %d). Utilize o campo binario",
+"Somente e permitido um campo auto incrementado, e ele deve ser chave da tabela",
+"%s: pronto para conexoes\n",
+"%s: Finalizacao concluida normalmente\n",
+"%s: Recebeu o sinal %d. Cancelando!\n",
+"%s: Finalizacao concluida\n",
+"%s: Forcando a finalizacao da tarefa %ld usuario: '%-.64s'\n",
+"Nao foi possivel criar o socket IP",
+"Tabela '%-.64s' nao possui um indice criado por CREATE INDEX. Recrie a tabela",
+"O separador de campos nao esta conforme esperado. Confira no manual","
+"Nao e possivel utilizar comprimento de linha fixo com campos binarios. Favor usar 'fields terminated by'.",
+"O arquivo '%-.64s' precisa estar no diretorio do banco de dados, e sua leitura permitida a todos",
+"Arquivo '%-.64s' ja existe",
+"Registros: %ld Apagados: %ld Ignorados: %ld Avisos: %ld",
+"Registros: %ld Duplicados: %ld",
+"Parte da chave errada. A parte utilizada nao e um texto ou tem comprimento maior que o definido",
+"Nao e possivel retirar todas as colunas da tabela com ALTER TABLE. Use DROP TABLE",
+"Nao foi possivel DROP '%-.64s'. Confira se este campo/chave existe",
+"Registros: %ld Duplicados: %ld Avisos: %ld",
+"INSERT TABLE '%-.64s' nao e permitido em FROM lista de tabelas",
+"Tarefa desconhecida id: %lu",
+"Voce nao e o responsavel pela tarefa %lu",
+"Nenhuma tabela em uso",
+"Muitos textos para a coluna %s e SET",
+"Nao foi possivel um unico nome para o arquivo %s.(1-999)\n",
+"Tabela '%-.64s' esta travada para leitura, e nao pode ser atualizada",
+"Tabela '%-.64s' nao foi travada com LOCK TABLES",
+"Campo binario '%-.64s' nao pode ter um valor inicial",
+"Nome de banco de dados invalido: '%-.64s'",
+"Nome de tabela invalido: '%-.64s'",
+"O SELECT muitos registros, e possivelmente vai demorar. Confira sua clausula WHERE e utilize SET OPTION SQL_BIG_SELECTS=1 se o SELECT esta correto",
+"Erro desconhecido",
+"Procedimento %s desconhecido",
+"Numero de parametros para o procedimento %s esta incorreto",
+"Parametro incorreto para o procedimento %s",
+"Tabela '%-.64s' descohecida em %s",
+"Campo '%-.64s' definido em duplicidade",
+"Invalid use of group function",
+"Table '%-.64s' uses a extension that doesn't exist in this MySQL version",
+"A table must have at least 1 column",
+"The table '%-.64s' is full",
+"Unknown character set: '%-.64s'",
+"Too many tables. MySQL can only use %d tables in a join",
+"Too many fields",
+"Too big row size. The maximum row size, not counting blobs, is %d. You have to change some fields to blobs",
+"Thread stack overrun: Used: %ld of a %ld stack. Use 'mysqld -O thread_stack=#' to specify a bigger stack if needed",
+"Cross dependency found in OUTER JOIN. Examine your ON conditions",
+"Column '%-.32s' is used with UNIQUE or INDEX but is not defined as NOT NULL",
+"Can't load function '%-.64s'",
+"Can't initialize function '%-.64s'; %-.80s",
+"No paths allowed for shared library",
+"Function '%-.64s' already exist",
+"Can't open shared library '%-.64s' (errno: %d %s)",
+"Can't find function '%-.64s' in library'",
+"Function '%-.64s' is not defined",
+"Host '%-.64s' is blocked because of many connection errors. Unblock with 'mysqladmin flush-hosts'",
+"Host '%-.64s' is not allowed to connect to this MySQL server",
+"You are using MySQL as an anonymous users and anonymous users are not allowed to change passwords",
+"You must have privileges to update tables in the mysql database to be able to change passwords for others",
+"Can't find any matching row in the user table",
+"Rows matched: %ld Changed: %ld Warnings: %ld",
+"Can't create a new thread (errno %d). If you are not out of available memory you can consult the manual for any possible OS dependent bug",
+"Column count doesn't match value count at row %ld",
+"Can't reopen table: '%-.64s',
+"Invalid use of NULL value",
+"Got error '%-.64s' from regexp",
+"Mixing of GROUP columns (MIN(),MAX(),COUNT()...) with no GROUP columns is illegal if there is no GROUP BY clause",
+"There is no such grant defined for user '%-.32s' on host '%-.64s'",
+"%-.16s command denied to user: '%-.32s@%-.64s' for table '%-.64s'",
+"%-.16s command denied to user: '%-.32s@%-.64s' for column '%-.64s' in table '%-.64s'",
+"Illegal GRANT/REVOKE command. Please consult the manual which privleges can be used.",
+"The host or user argument to GRANT is too long",
+"Table '%-64s.%s' doesn't exist",
+"There is no such grant defined for user '%-.32s' on host '%-.64s' on table '%-.64s'",
+"The used command is not allowed with this MySQL version",
+"Something is wrong in your syntax",
+"Delayed insert thread couldn't get requested lock for table %-.64s",
+"Too many delayed threads in use",
+"Aborted connection %ld to db: '%-.64s' user: '%-.64s' (%s)",
+"Got a packet bigger than 'max_allowed_packet'",
+"Got a read error from the connection pipe",
+"Got an error from fcntl()",
+"Got packets out of order",
+"Couldn't uncompress communication packet",
+"Got an error reading communication packets"
+"Got timeout reading communication packets",
+"Got an error writing communication packets",
+"Got timeout writing communication packets",
+"Result string is longer than max_allowed_packet",
+"The used table type doesn't support BLOB/TEXT columns",
+"The used table type doesn't support AUTO_INCREMENT columns",
+"INSERT DELAYED can't be used with table '%-.64s', because it is locked with LOCK TABLES",
+"Incorrect column name '%-.100s'",
+"The used table handler can't index column '%-.64s'",
+"All tables in the MERGE table are not defined identically",
+"Can't write, because of unique constraint, to table '%-.64s'",
+"BLOB column '%-.64s' used in key specification without a key length",
+"All parts of a PRIMARY KEY must be NOT NULL; If you need NULL in a key, use UNIQUE instead",
+"Result consisted of more than one row",
+"This table type requires a primary key",
+"This version of MySQL is not compiled with RAID support",
+"You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column",
+"Key '%-.64s' doesn't exist in table '%-.64s'",
+"Can't open table",
+"The handler for the table doesn't support check/repair",
+"You are not allowed to execute this command in a transaction",
+"Got error %d during COMMIT",
+"Got error %d during ROLLBACK",
+"Got error %d during FLUSH_LOGS",
+"Got error %d during CHECKPOINT",
+"Aborted connection %ld to db: '%-.64s' user: '%-.32s' host: `%-.64s' (%-.64s)",
+"The handler for the table does not support binary table dump",
+"Binlog closed while trying to FLUSH MASTER",
+"Failed rebuilding the index of dumped table '%-.64s'",
+"Error from master: '%-.64s'",
+"Net error reading from master",
+"Net error writing to master",
+"Can't find FULLTEXT index matching the column list",
diff --git a/sql/share/romania/errmsg.sys b/sql/share/romania/errmsg.sys
new file mode 100644
index 00000000000..018333d3e1e
--- /dev/null
+++ b/sql/share/romania/errmsg.sys
Binary files differ
diff --git a/sql/share/romania/errmsg.txt b/sql/share/romania/errmsg.txt
new file mode 100644
index 00000000000..5d34f32e602
--- /dev/null
+++ b/sql/share/romania/errmsg.txt
@@ -0,0 +1,199 @@
+/* Copyright Abandoned 1997 TCX DataKonsult AB & Monty Program KB & Detron HB
+ This file is public domain and comes with NO WARRANTY of any kind
+
+ Translated into Romanian by Stefan Saroiu
+ e-mail: tzoompy@cs.washington.edu
+*/
+
+"hashchk",
+"isamchk",
+"NU",
+"DA",
+"Nu pot sa creez fisierul '%-.64s' (Eroare: %d)",
+"Nu pot sa creez tabla '%-.64s' (Eroare: %d)",
+"Nu pot sa creez baza de date '%-.64s'. (Eroare: %d)",
+"Nu pot sa creez baza de date '%-.64s'. Baza de date exista deja",
+"Nu pot sa drop baza de date '%-.64s'. Baza da date este inexistenta",
+"Eroare dropuind baza de date (nu pot sa sterg '%-.64s', Eroare: %d)",
+"Eroare dropuind baza de date (nu pot sa rmdir '%-.64s', Eroare: %d)",
+"Eroare incercind sa delete '%-.64s' (Eroare: %d)",
+"Nu pot sa citesc cimpurile in tabla de system (system table)",
+"Nu pot sa obtin statusul lui '%-.64s' (Eroare: %d)",
+"Nu pot sa obtin directorul current (working directory) (Eroare: %d)",
+"Nu pot sa lock fisierul (Eroare: %d)",
+"Nu pot sa deschid fisierul: '%-.64s'. (Eroare: %d)",
+"Nu pot sa gasesc fisierul: '%-.64s' (Eroare: %d)",
+"Nu pot sa citesc directorul '%-.64s' (Eroare: %d)",
+"Nu pot sa schimb directorul '%-.64s' (Eroare: %d)",
+"Cimpul a fost schimbat de la ultima citire a tabelei '%-.64s'",
+"Hard-disk-ul este plin (%s). Astept sa se elibereze ceva spatiu....",
+"Nu pot sa scriu (can't write), cheie duplicata in tabela '%-.64s'",
+"Eroare inchizind '%-.64s' (errno: %d)",
+"Eroare citind fisierul '%-.64s' (errno: %d)",
+"Eroare incercind sa renumesc '%-.64s' in '%-.64s' (errno: %d)",
+"Eroare scriind fisierul '%-.64s' (errno: %d)",
+"'%-.64s' este blocat pentry schimbari (loccked against change)",
+"Sortare intrerupta",
+"View '%-.64s' nu exista pentru '%-.64s'",
+"Eroarea %d obtinuta din handlerul tabelei",
+"Handlerul tabelei pentru '%-.64s' nu are aceasta optiune",
+"Nu pot sa gasesc recordul in '%-.64s'",
+"Informatie incorecta in fisierul: '%-.64s'",
+"Cheia fisierului incorecta pentru tabela: '%-.64s'. Incearca s-o repari",
+"Cheia fisierului e veche pentru tabela '%-.64s'; Repar-o!",
+"Tabela '%-.64s' e read-only",
+"Out of memory. Porneste daemon-ul din nou si incearca inca o data (e nevoie de %d bytes)",
+"Out of memory pentru sortare. Largeste marimea buffer-ului pentru sortare in daemon (sort buffer size)",
+"Sfirsit de fisier neasteptat in citirea fisierului '%-.64s' (errno: %d)",
+"Prea multe conectiuni",
+"Out of memory; Verifica daca mysqld sau vreun alt proces foloseste toate memoria disponbila. Altfel, trebuie sa folosesi 'ulimit' ca sa permiti lui memoria disponbila. Altfel, trebuie sa folosesi 'ulimit' ca sa permiti lui mysqld sa foloseasca mai multa memorie ori adauga mai mult spatiu pentru swap (swap space)",
+"Nu pot sa obtin hostname-ul adresei tale",
+"Prost inceput de conectie (bad handshake)",
+"Acces interzis pentru utilizatorul: '%-.32s@%-.64s' la baza de date '%-.64s'",
+"Acces interzis pentru utilizatorul: '%-.32s@%-.64s' (Folosind parola: %s)",
+"Nici o baza de data nu a fost selectata inca",
+"Comanda invalida",
+"Coloana '%-.64s' nu poate sa fie null",
+"Baza de data invalida '%-.64s'",
+"Tabela '%-.64s' exista deja",
+"Tabela '%-.64s' este invalida",
+"Coloana: '%-.64s' in %-.64s este ambigua",
+"Terminarea serverului este in desfasurare",
+"Coloana invalida '%-.64s' in '%-.64s'",
+"'%-.64s' nu exista in clauza GROUP BY",
+"Nu pot sa grupez pe (group on) '%-.64s'",
+"Comanda are functii suma si coloane in aceeasi comanda",
+"Numarul de coloane nu este acelasi cu numarul valoarei",
+"Numele indentificatorului '%-.100s' este prea lung",
+"Numele coloanei '%-.64s' e duplicat",
+"Numele cheiei '%-.64s' e duplicat",
+"Cimpul '%-.64s' e duplicat pentru cheia %d",
+"Specificandul coloanei '%-.64s' este incorect",
+"%s linga '%-.80s' pe linia %d",
+"Query-ul a fost gol",
+"Tabela/alias: '%-.64s' nu este unic",
+"Valoarea de default este invalida pentru '%-.64s'",
+"Chei primare definite de mai multe ori",
+"Prea multe chei. Numarul de chei maxim este %d",
+"Prea multe chei. Numarul de chei maxim este %d",
+"Cheia specificata este prea lunga. Marimea maxima a unei chei este de %d",
+"Coloana cheie '%-.64s' nu exista in tabela",
+"Coloana de tip BLOB '%-.64s' nu poate fi folosita in specificarea cheii cu tipul de tabla folosit",
+"Lungimea coloanei '%-.64s' este prea lunga (maximum = %d). Foloseste BLOB mai bine",
+"Definitia tabelei este incorecta; Nu pot fi mai mult de o singura coloana de tip auto si aceasta trebuie definita ca cheie",
+"%s: sint gata pentru conectii\n",
+"%s: Terminare normala\n",
+"%s: Semnal %d obtinut. Aborting!\n",
+"%s: Terminare completa\n",
+"%s: Terminare fortata a thread-ului %ld utilizatorului: '%-.32s'\n",
+"Nu pot crea IP socket",
+"Tabela '%-.64s' nu are un index ca acela folosit in CREATE INDEX. Re-creeaza tabela",
+"Argumentul pentru separatorul de cimpuri este diferit de ce ma asteptam. Verifica manualul","
+"Nu poti folosi lungime de cimp fix pentru BLOB-uri. Foloseste 'fields terminated by'.",
+"Fisierul '%-.64s' trebuie sa fie in directorul bazei de data sau trebuie sa poata sa fie citit de catre toata lumea (verifica permisiile)",
+"Fisierul '%-.80s' exista deja",
+"Recorduri: %ld Sterse: %ld Sarite (skipped): %ld Atentionari (warnings): %ld",
+"Recorduri: %ld Duplicate: %ld",
+"Componentul cheii este incorrect. Componentul folosit al cheii nu este un sir sau lungimea folosita este mai lunga decit lungimea cheii",
+"Nu poti sterge toate coloanele cu ALTER TABLE. Foloseste DROP TABLE in schimb",
+"Nu pot sa DROP '%-.64s'. Verifica daca coloana/cheia exista",
+"Recorduri: %ld Duplicate: %ld Atentionari (warnings): %ld",
+"INSERT TABLE '%-.64s' nu este permis in lista FROM de tabele",
+"Id-ul: %lu thread-ului este necunoscut",
+"Nu sinteti proprietarul threadului %lu",
+"Nici o tabela folosita",
+"Prea multe siruri pentru coloana %-.64s si SET",
+"Nu pot sa generez un nume de log unic %-.64s.(1-999)\n",
+"Tabela '%-.64s' a fost locked cu un READ lock si nu poate fi actualizata",
+"Tabela '%-.64s' nu a fost locked cu LOCK TABLES",
+"Coloana BLOB '%-.64s' nu poate avea o valoare default",
+"Numele bazei de date este incorect '%-.100s'",
+"Numele tabelei este incorect '%-.100s'",
+"SELECT-ul ar examina prea multe cimpuri si probabil ar lua prea mult timp. Verifica clauza WHERE si foloseste SET OPTION SQL_BIG_SELECTS=1 daca SELECT-ul e ok",
+"Eroare unknown",
+"Procedura unknown '%-.64s'",
+"Procedura '%-.64s' are un numar incorect de parametri",
+"Procedura '%-.64s' are parametrii incorecti",
+"Tabla '%-.64s' invalida in %-.32s",
+"Coloana '%-.64s' specificata de doua ori",
+"Folosire incorecta a functiei group",
+"Tabela '%-.64s' foloseste o extensire inexistenta in versiunea curenta de MySQL",
+"O tabela trebuie sa aiba cel putin o coloana",
+"Tabela '%-.64s' e plina",
+"Set de caractere invalid: '%-.64s'",
+"Prea multe tabele. MySQL nu poate folosi mai mult de %d tabele intr-un join",
+"Prea multe coloane",
+"Marimea liniei (row) prea mare. Marimea maxima a liniei, excluzind BLOB-urile este de %d. Trebuie sa schimbati unele cimpuri in BLOB-uri",
+"Stack-ul thread-ului a fost depasit (prea mic): Folositi: %ld intr-un stack de %ld. Folositi 'mysqld -O thread_stack=#' ca sa specifici un stack mai mare",
+"Dependinta incrucisata (cross dependency) gasita in OUTER JOIN. Examinati conditiile ON",
+"Coloana '%-.64s' e folosita cu UNIQUE sau INDEX dar fara sa fie definita ca NOT NULL",
+"Nu pot incarca functia '%-.64s'",
+"Nu pot initializa functia '%-.64s'; %-.80s",
+"Nici un paths nu e permis pentru o librarie shared",
+"Functia '%-.64s' exista deja",
+"Nu pot deschide libraria shared '%-.64s' (Eroare: %d %-.64s)",
+"Nu pot gasi functia '%-.64s' in libraria",
+"Functia '%-.64s' nu e definita",
+"Host-ul '%-.64s' e blocat din cauza multelor erori de conectie. Poti deploca folosind 'mysqladmin flush-hosts'",
+"Host-ul '%-.64s' nu este permis a se conecta la aceste server MySQL",
+"Dumneavoastra folositi MySQL ca un utilizator anonim si utilizatorii anonimi nu au voie sa schime parolele",
+"Trebuie sa aveti privilegii sa actualizati tabelele in bazele de date mysql ca sa puteti sa schimati parolele altora",
+"Nu pot gasi nici o linie corespunzatoare in tabela utilizatorului",
+"Linii identificate (matched): %ld Schimbate: %ld Atentionari (warnings): %ld",
+"Nu pot crea un thread nou (Eroare %d). Daca mai aveti memorie disponibila in sistem, puteti consulta manualul - ar putea exista un potential bug in legatura cu sistemul de operare",
+"Numarul de coloane nu corespunde cu numarul de valori la linia %ld",
+"Nu pot redeschide tabela: '%-.64s'",
+"Folosirea unei value NULL e invalida",
+"Eroarea '%-.64s' obtinuta din expresia regulara (regexp)",
+"Amestecarea de coloane GROUP (MIN(),MAX(),COUNT()...) fara coloane GROUP este ilegala daca nu exista o clauza GROUP BY",
+"Nu exista un astfel de grant definit pentru utilzatorul '%-.32s' de pe host-ul '%-.64s'",
+"Comanda %-.16s interzisa utilizatorului: '%-.32s@%-.64s' pentru tabela '%-.64s'",
+"Comanda %-.16s interzisa utilizatorului: '%-.32s@%-.64s' pentru coloana '%-.64s' in tabela '%-.64s'",
+"Comanda GRANT/REVOKE ilegala. Consultati manualul in privinta privilegiilor ce pot fi folosite.",
+"Argumentul host-ului sau utilizatorului pentru GRANT e prea lung",
+"Tabela '%-.64s.%-.64s' nu exista",
+"Nu exista un astfel de privilegiu (grant) definit pentru utilizatorul '%-.32s' de pe host-ul '%-.64s' pentru tabela '%-.64s'",
+"Comanda folosita nu este permisa pentru aceasta versiune de MySQL",
+"Aveti o eroare in sintaxa RSQL",
+"Thread-ul pentru inserarea aminata nu a putut obtine lacatul (lock) pentru tabela %-.64s",
+"Prea multe threaduri aminate care sint in uz",
+"Conectie terminata %ld la baza de date: '%-.64s' utilizator: '%-32s' (%-.64s)",
+"Un packet mai mare decit 'max_allowed_packet' a fost primit",
+"Eroare la citire din cauza lui 'connection pipe'",
+"Eroare obtinuta de la fcntl()",
+"Packets care nu sint ordonati au fost gasiti",
+"Nu s-a putut decompresa pachetul de comunicatie (communication packet)",
+"Eroare obtinuta citind pachetele de comunicatie (communication packets)",
+"Timeout obtinut citind pachetele de comunicatie (communication packets)",
+"Eroare in scrierea pachetelor de comunicatie (communication packets)",
+"Timeout obtinut scriind pachetele de comunicatie (communication packets)",
+"Sirul rezultat este mai lung decit max_allowed_packet",
+"Tipul de tabela folosit nu suporta coloane de tip BLOB/TEXT",
+"Tipul de tabela folosit nu suporta coloane de tip AUTO_INCREMENT",
+"INSERT DELAYED nu poate fi folosit cu tabela '%-.64s', deoarece este locked folosing LOCK TABLES",
+"Nume increct de coloana '%-.100s'",
+"Handler-ul tabelei folosite nu poate indexa coloana '%-.64s'",
+"Toate tabelele din tabela MERGE nu sint definite identic",
+"Nu pot scrie pe hard-drive, din cauza constraintului unic (unique constraint) pentru tabela '%-.64s'",
+"Coloana BLOB '%-.64s' este folosita in specificarea unei chei fara ca o lungime de cheie sa fie folosita",
+"Toate partile unei chei primare (PRIMARY KEY) trebuie sa fie NOT NULL; Daca aveti nevoie de NULL in vreo cheie, folositi UNIQUE in schimb",
+"Resultatul constista din mai multe linii",
+"Aceast tip de tabela are nevoie de o cheie primara",
+"Aceasta versiune de MySQL, nu a fost compilata cu suport pentru RAID",
+"You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column",
+"Key '%-.64s' doesn't exist in table '%-.64s'",
+"Can't open table",
+"The handler for the table doesn't support check/repair",
+"You are not allowed to execute this command in a transaction",
+"Got error %d during COMMIT",
+"Got error %d during ROLLBACK",
+"Got error %d during FLUSH_LOGS",
+"Got error %d during CHECKPOINT",
+"Aborted connection %ld to db: '%-.64s' user: '%-.32s' host: `%-.64s' (%-.64s)",
+"The handler for the table does not support binary table dump","Binlog closed while trying to FLUSH MASTER",
+"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",
diff --git a/sql/share/russian/errmsg.sys b/sql/share/russian/errmsg.sys
new file mode 100644
index 00000000000..5ddaf2e2973
--- /dev/null
+++ b/sql/share/russian/errmsg.sys
Binary files differ
diff --git a/sql/share/russian/errmsg.txt b/sql/share/russian/errmsg.txt
new file mode 100644
index 00000000000..fe12cad035d
--- /dev/null
+++ b/sql/share/russian/errmsg.txt
@@ -0,0 +1,198 @@
+/* Copyright Abandoned 1998.
+ This file is public domain and comes with NO WARRANTY of any kind */
+/* Primary translation was done by "Timur I. Bakeyev" <translate@bat.ru> */
+/* Additional translation by "Alexander I. Barkov" <bar@izhcom.ru> */
+/* charset: KOI8-R */
+
+"hashchk",
+"isamchk",
+"îåô",
+"äá",
+"îÅ ÍÏÇÕ ÓÏÚÄÁÔØ ÆÁÊÌ '%-.64s' (ïÛÉÂËÁ: %d)",
+"îÅ ÍÏÇÕ ÓÏÚÄÁÔØ ÔÁÂÌÉÃÕ '%-.64s' (ïÛÉÂËÁ: %d)",
+"îÅ ÍÏÇÕ ÓÏÚÄÁÔØ ÂÁÚÕ '%-.64s'. ïÛÉÂËÁ: %d",
+"îÅ ÍÏÇÕ ÓÏÚÄÁÔØ ÂÁÚÕ '%-.64s'. âÁÚÁ ÕÖÅ ÓÕÝÅÓÔ×ÕÅÔ",
+"îÅ ÍÏÇÕ ÕÄÁÌÉÔØ ÂÁÚÕ '%-.64s'. âÁÚÁ ÎÅ ÓÕÝÅÓÔ×ÕÅÔ",
+"ïÛÉÂËÁ ÐÒÉ ÕÄÁÌÅÎÉÉ ÂÁÚÙ (îÅ ÍÏÇÕ ÕÄÁÌÉÔØ '%-.64s', ÏÛÉÂËÁ %d)",
+"ïÛÉÂËÁ ÐÒÉ ÕÄÁÌÅÎÉÉ ÂÁÚÙ (îÅ ÍÏÇÕ ÕÄÁÌÉÔØ ËÁÔÁÌÏÇ '%-.64s', ÏÛÉÂËÁ %d)",
+"ïÛÉÂËÁ ÐÒÉ ÕÄÁÌÅÎÉÉ '%-.64s' (ïÛÉÂËÁ: %d)",
+"îÅ ÍÏÇÕ ÐÒÏÞÅÓÔØ ÚÁÐÉÓØ × ÓÉÓÔÅÍÎÏÊ ÔÁÂÌÉÃÅ",
+"îÅ ÍÏÇÕ ÐÏÌÕÞÉÔØ ÓÔÁÔÕÓ '%-.64s' (ïÛÉÂËÁ: %d)",
+"îÅ ÍÏÇÕ ÏÐÒÅÄÅÌÉÔØ ÒÁÂÏÞÉÊ ËÁÔÁÌÏÇ (ïÛÉÂËÁ: %d)",
+"îÅ ÍÏÇÕ ÂÌÏËÉÒÏ×ÁÔØ ÆÁÊÌ (ïÛÉÂËÁ: %d)",
+"îÅ ÍÏÇÕ ÏÔËÒÙÔØ ÆÁÊÌ: '%-.64s'. (ïÛÉÂËÁ: %d)",
+"îÅ ÍÏÇÕ ÎÁÊÔÉ ÆÁÊÌ: '%-.64s' (ïÛÉÂËÁ: %d)",
+"îÅ ÍÏÇÕ ÐÒÏÞÅÓÔØ ËÁÔÁÌÏÇ '%-.64s' (ïÛÉÂËÁ: %d)",
+"îÅ ÍÏÇÕ ÐÅÒÅÊÔÉ × ËÁÔÁÌÏÇ '%-.64s' (ïÛÉÂËÁ: %d)",
+"úÁÐÉÓØ ÂÙÌÁ ÉÚÍÅÎÅÎÁ ÓÏ ×ÒÅÍÅÎÉ ÐÏÓÌÅÄÎÅÇÏ ÞÔÅÎÉÑ ÔÁÂÌÉÃÙ '%-.64s'",
+"ðÅÒÅÐÏÌÎÅÎ ÄÉÓË (%-.64s). íÏÖÅÔ, ËÔÏ-ÎÉÂÕÄØ ÕÂÅÒÅÔ ÚÁ ÓÏÂÏÊ ÍÕÓÏÒ....",
+"îÅ ÍÏÇÕ ÐÒÏÉÚ×ÅÓÔÉ ÚÁÐÉÓØ, ËÌÀÞ ÄÕÂÌÉÒÕÅÔÓÑ × ÔÁÂÌÉÃÅ '%-.64s'",
+"ïÛÉÂËÁ ÐÒÉ ÚÁËÒÙÔÉÉ '%-.64s' (ïÛÉÂËÁ: %d)",
+"ïÛÉÂËÁ ÞÔÅÎÉÑ ÆÁÊÌÁ '%-.64s' (ïÛÉÂËÁ: %d)",
+"ïÛÉÂËÁ ÐÒÉ ÐÅÒÅÉÍÅÎÏ×ÁÎÉÉ '%-.64s' × '%-.64s' (ïÛÉÂËÁ: %d)",
+"ïÛÉÂËÁ ÚÁÐÉÓÉ × ÆÁÊÌ '%-.64s' (ïÛÉÂËÁ: %d)",
+"'%-.64s' ÚÁÂÌÏËÉÒÏ×ÁÎ ÄÌÑ ÉÚÍÅÎÅÎÉÊ",
+"óÏÒÔÉÒÏ×ËÁ ÐÒÅÒ×ÁÎÁ",
+"View '%-.64s' ÎÅ ÓÕÝÅÓÔ×ÕÅÔ ÄÌÑ '%-.64s'",
+"ðÏÌÕÞÅÎÁ ÏÛÉÂËÁ %d ÏÔ ÄÅÓËÒÉÐÔÏÒÁ ÔÁÂÌÉÃÙ",
+"äÅÓËÒÉÐÔÏÒ ÔÁÂÌÉÃÙ '%-.64s' ÎÅ ÉÍÅÅÔ ÔÁËÏÇÏ Ó×ÏÊÓÔ×Á",
+"îÅ ÍÏÇÕ ÎÁÊÔÉ ÚÁÐÉÓØ × '%-.64s'",
+"îÅ×ÅÒÎÁÑ ÉÎÆÏÒÍÁÃÉÑ × ÆÁÊÌÅ: '%-.64s'",
+"îÅ×ÅÒÎÙÊ ÉÎÄÅËÓÎÙÊ ÆÁÊÌ ÄÌÑ ÔÁÂÌÉÃÙ: '%-.64s'. ðÏÐÒÏÂÕÊÔÅ ÅÇÏ ×ÏÓÓÏÚÄÁÔØ",
+"óÔÁÒÙÊ ÉÎÄÅËÓÎÙÊ ÆÁÊÌ ÄÌÑ ÔÁÂÌÉÃÙ '%-.64s'; òÅÉÎÄÅËÓÉÒÕÊÔÅ ÅÅ!",
+"'%-.64s' ÔÏÌØËÏ ÄÌÑ ÞÔÅÎÉÑ",
+"îÅ È×ÁÔÁÅÔ ÐÁÍÑÔÉ. ðÅÒÅÇÒÕÚÉÔÅ ÓÅÒ×ÅÒ É ÐÏÐÒÏÂÕÊÔÅ ÓÎÏ×Á (ÎÕÖÎÏ %d ÂÁÊÔ)",
+"îÅ È×ÁÔÁÅÔ ÐÁÍÑÔÉ ÄÌÑ ÓÏÒÔÉÒÏ×ËÉ. õ×ÅÌÉÞØÔÅ ÒÁÚÍÅÒ ÂÕÆÅÒÁ ÓÏÒÔÉÒÏ×ËÉ Õ ÓÅÒ×ÅÒÁ",
+"îÅÏÖÉÄÁÎÎÙÊ ËÏÎÅà ÆÁÊÌÁ '%-.64s' (ïÛÉÂËÁ: %d)",
+"óÌÉÛËÏÍ ÍÎÏÇÏ ÓÏÅÄÉÎÅÎÉÊ",
+"îÅÄÏÓÔÁÔÏË ÍÅÓÔÁ/ÐÁÍÑÔÉ ÄÌÑ ÎÉÔÉ",
+"îÅ ÍÏÇÕ ÏÐÒÅÄÅÌÉÔØ ÉÍÑ ÈÏÓÔÁ ÐÏ ÷ÁÛÅÍÕ ÁÄÒÅÓÕ",
+"îÅËÏÒÒÅËÔÎÁÑ ÉÎÉÃÉÁÌÉÚÁÃÉÑ Ó×ÑÚÉ",
+"äÏÓÔÕÐ ÚÁËÒÙÔ ÄÌÑ ÐÏÌØÚÏ×ÁÔÅÌÑ: '%-.32s@%-.64s' Ë ÂÁÚÅ '%-.64s'",
+"äÏÓÔÕÐ ÚÁËÒÙÔ ÄÌÑ ÐÏÌØÚÏ×ÁÔÅÌÑ: '%-.32s@%-.64s' (âÙÌ ÉÓÐÏÌØÚÏ×ÁÎ ÐÁÒÏÌØ: %-.64s)",
+"îÅ ×ÙÂÒÁÎÁ ÂÁÚÁ",
+"îÅÉÚ×ÅÓÔÎÁÑ ËÏÍÁÎÄÁ",
+"óÔÏÌÂÅà '%-.64s' ÎÅ ÍÏÖÅÔ ÂÙÔØ ÐÕÓÔÙÍ/ÎÕÌÅ×ÙÍ",
+"îÅÉÚ×ÅÓÔÎÁÑ ÂÁÚÁ '%-.64s'",
+"ôÁÂÌÉÃÁ '%-.64s' ÕÖÅ ÅÓÔØ",
+"îÅÉÚ×ÅÓÔÎÁÑ ÔÁÂÌÉÃÁ '%-.64s'",
+"ðÏÌÅ '%-.64s' × %-.64s ÎÅ ÏÄÎÏÚÎÁÞÎÏ",
+"ðÒÏÉÓÈÏÄÉÔ ×ÙËÌÀÞÅÎÉÅ ÓÅÒ×ÅÒÁ",
+"îÅÉÚ×ÅÓÔÎÏÅ ÐÏÌÅ '%-.64s' × %-.64s",
+" '%-.64s' ÉÓÐÏÌØÚÏ×ÁÎÏ ×ÎÅ ×ÙÒÁÖÅÎÉÑ GROUP BY",
+"îÅ ÍÏÇÕ ÐÒÏÉÚ×ÅÓÔÉ ÇÒÕÐÐÉÒÏ×ËÕ ÐÏ '%-.64s'",
+"÷ ÏÄÎÏÍ ×ÙÒÁÖÅÎÉÉ ÓÏÄÅÒÖÁÔØÓÑ É ÉÍÅÎÁ ÐÏÌÅÊ, É ÓÕÍÍÉÒÕÀÝÉÅ ÆÕÎËÃÉÉ",
+"þÉÓÌÏ ÓÔÏÌÂÃÏ× ÎÅ ÓÏÏÔ×ÅÔÓÔ×ÕÅÔ ÞÉÓÌÕ ÚÎÁÞÅÎÉÊ"
+"óÌÉÛËÏÍ ÄÌÉÎÎÙÊ ÉÄÅÎÔÉÆÉËÁÔÏÒ: '%-.64s'",
+"äÕÂÌÉÒÏ×ÁÎÎÏÅ ÉÍÑ ÐÏÌÑ '%-.64s'",
+"äÕÂÌÉÒÏ×ÁÎÎÏÅ ÉÍÑ ËÌÀÞÁ '%-.64s'",
+"ðÏ×ÔÏÒÑÀÝÅÅÓÑ ÚÎÁÞÅÎÉÅ '%-.64s' ÄÌÑ ËÌÀÞÁ %d",
+"îÅ×ÅÒÎÙÊ ÓÐÅÃÉÆÉËÁÔÏÒ ÐÏÌÑ: '%-.64s'",
+"%-.64s ÏËÏÌÏ '%-.64s', × ÓÔÒÏËÅ %d",
+"ðÕÓÔÏÊ ÚÁÐÒÏÓ",
+"îÅ ÕÎÉËÁÌØÎÁÑ ÔÁÂÌÉÃÁ/ÐÓÅ×ÄÏÎÉÍ: '%-.64s'",
+"îÅ×ÅÒÎÏÅ ÚÎÁÞÅÎÉÅ ÐÏ ÕÍÏÌÞÁÎÉÀ '%-.64s'",
+"ðÅÒ×ÉÞÎÙÊ ËÌÀÞ ÏÐÒÅÄÅÌÅÎ ÎÅÓËÏÌØËÏ ÒÁÚ",
+"ïÐÒÅÄÅÌÅÎÎÏ ÓÌÉÛËÏÍ ÍÎÏÇÏ ËÌÀÞÅÊ. ÷ÏÚÍÏÖÎÏ ÍÁËÓÉÍÁÌØÎÏ %d ËÌÀÞÅÊ",
+"ïÐÒÅÄÅÌÅÎÎÏ ÓÌÉÛËÏÍ ÍÎÏÇÏ ÓÏÓÔÁ×ÌÑÀÝÉÈ ËÌÀÞÁ. ÷ÏÚÍÏÖÎÏ ÍÁËÓÉÍÁÌØÎÏ %d ÓÏÓÔÁ×ÌÑÀÝÉÈ",
+"ëÌÀÞ ÓÌÉÛËÏÍ ÂÏÌØÛÏÊ. íÁËÓÉÍÁÌØÎÁÑ ÄÌÉÎÁ %d",
+"ëÌÀÞÅ×ÏÅ ÐÏÌÅ '%-.64s' ÎÅ ÓÏÄÅÒÖÉÔÓÑ × ÔÁÂÌÉÃÅ",
+"ïÂßÅËÔ BLOB '%-.64s' ÎÅ ÍÏÖÅÔ ÐÒÉÓÕÔÓÔ×Ï×ÁÔØ × ÏÐÒÅÄÅÌÅÎÉÉ ËÌÀÞÁ",
+"óÌÉÛËÏÍ ×ÅÌÉË ÒÁÚÍÅÒ ÐÏÌÑ '%-.64s' (max = %d). ÷ÏÓÐÏÌØÚÕÊÔÅÓØ ÏÂßÅËÔÏÍ BLOB",
+"á×ÔÏÍÁÔÉÞÅÓËÏÅ ÐÏÌÅ ÍÏÖÅÔ ÂÙÔØ ÔÏÌØËÏ ÏÄÎÏ É ÄÏÌÖÎÏ ÂÙÔØ ËÌÀÞÏÍ",
+"%-.64s: îÁ Ó×ÑÚÉ!\n",
+"%-.64s: îÏÒÍÁÌØÎÏÅ ÚÁ×ÅÒÛÅÎÉÅ\n",
+"%-.64s: ðÏÌÕÞÅÎ ÓÉÇÎÁÌ %d. õÍÙ×ÁÀ ÒÕËÉ!\n",
+"%-.64s: ïÔËÌÀÞÅÎÉÅ ×ÙÐÏÌÎÅÎÏ\n",
+"%-.64s: ðÒÉÎÕÄÉÔÅÌØÎÏÅ ÐÒÅËÒÁÝÅÎÉÅ ÎÉÔÉ %ld ÐÏÌØÚÏ×ÁÔÅÌÑ: '%-.64s'\n",
+"îÅ ÍÏÇÕ ÓÏÚÄÁÔØ IP socket",
+"ôÁÂÌÉÃÁ '%-.64s' ÉÍÅÅÔ ÉÎÄÅËÓ, ÎÅ ÓÏ×ÐÁÄÁÀÝÉÊ Ó ÕËÁÚÁÎÎÙÍ × CREATE INDEX. óÏÚÄÁÊÔÅ ÔÁÂÌÉÃÕ ÅÝÅ ÒÁÚ",
+"òÁÚÄÅÌÉÔÅÌÉ ÐÏÌÅÊ ÎÅ ÓÏ×ÐÁÄÁÀÔ Ó ÏÖÉÄÁÅÍÙÍÉ. ðÒÏÞÔÉÔÅ ÎÁËÏÎÅà ÉÎÓÔÒÕËÃÉÀ!",
+"îÅÌØÚÑ ÓÓÙÌÁÔØÓÑ ÎÁ ÆÉËÓÉÒÏ×ÁÎÎÕÀ ÄÌÉÎÕ ÓÔÒÏËÉ × BLOB. éÓÐÏÌØÚÕÊÔÅ 'fields terminated by'.",
+"æÁÊÌ '%-.64s' ÄÏÌÖÅÎ ÂÙÔØ × ËÁÔÁÌÏÇÅ ÂÁÚ ÌÉÂÏ ÄÏÓÔÕÐÅÎ ×ÓÅÍ ÄÌÑ ÞÔÅÎÉÑ",
+"æÁÊÌ '%-.64s' ÕÖÅ ÅÓÔØ",
+"úÁÐÉÓÅÊ: %ld õÄÁÌÅÎÏ: %ld ðÒÏÐÕÝÅÎÏ: %ld ðÒÅÄÕÐÒÅÖÄÅÎÉÊ: %ld",
+"úÁÐÉÓÅÊ: %ld äÕÂÌÅÊ: %ld",
+"îÅ×ÅÒÎÁÑ ÓÏÓÔÁ×ÌÑÀÝÁÑ ËÌÀÞÁ. äÁÎÎÁÑ ÓÏÓÔÁ×ÌÑÀÝÁÑ ÌÉÂÏ ÎÅ ÓÔÒÏËÏ×ÁÑ, ÌÉÂÏ ÂÏÌØÛÅ, ÞÅÍ ÍÏÖÅÔ ÂÙÔØ",
+"îÅÌØÚÑ ÕÄÁÌÉÔØ ×ÓÅ ÐÏÌÑ ÞÅÒÅÚ ALTER TABLE. ÷ÏÓÐÏÌØÚÕÊÔÅÓØ DROP TABLE",
+"îÅ ÍÏÇÕ ÓÂÒÏÓÉÔØ '%-.64s'. ðÒÏ×ÅÒØÔÅ, ÞÔÏ ÜÔÏ ÐÏÌÅ/ËÌÀÞ ÓÕÝÅÓÔ×ÕÀÔ",
+"úÁÐÉÓÅÊ: %ld äÕÂÌÅÊ: %ld ðÒÅÄÕÐÒÅÖÄÅÎÉÊ: %ld",
+"INSERT TABLE '%-.64s' ÎÅ ÒÁÚÒÅÛÅÎÏ × ÓÐÉÓËÅ FROM TABLE",
+"îÅÉÚ×ÅÓÔÎÁÑ ÎÉÔØ: %lu",
+"÷Ù ÎÅ ×ÌÁÄÅÌÅà ÎÉÔÉ %lu",
+"ôÁÂÌÉÃÙ ÎÅ ÉÓÐÏÌØÚÏ×ÁÎÙ",
+"ïÞÅÎØ ÍÎÏÇÏ ÓÔÒÏË ÄÌÑ ÐÏÌÑ %-.64s É SET",
+"îÅ ÍÏÇÕ ÓÏÚÄÁÔØ ÕÎÉËÁÌØÎÙÊ ÌÏÇ-ÆÁÊÌ %-.64s.(1-999)\n",
+"ôÁÂÌÉÃÁ '%-.64s' ÚÁÂÌÏËÉÒÏ×ÁÎÁ READ É ÎÅ ÍÏÖÅÔ ÂÙÔØ ÏÂÎÏ×ÌÅÎÁ",
+"ôÁÂÌÉÃÁ '%-.64s' ÎÅ ÂÙÌÁ ÂÌÏËÉÒÏ×ÁÎÁ LOCK TABLES",
+"ïÂßÅËÔ BLOB '%-.64s' ÎÅ ÍÏÖÅÔ ÉÍÅÅÔ ÚÎÁÞÅÎÉÊ ÐÏ ÕÍÏÌÞÁÎÉÀ",
+"îÅÄÏÐÕÓÔÉÍÏÅ ÉÍÑ ÂÁÚÙ '%-.64s'",
+"îÅÄÏÐÕÓÔÉÍÏÅ ÉÍÑ ÔÁÂÌÉÃÙ '%-.64s'",
+"SELECT ÏÂÒÁÂÏÔÁÅÔ ÏÞÅÎØ ÍÎÏÇÏ ÚÁÐÉÓÅÊ É ÜÔÏ îáäïìçï. ðÒÏ×ÅÒØÔÅ ÕÓÌÏ×ÉÅ WHERE É ×ÏÓÐÏÌØÚÕÊÔÅÓØ SQL_OPTION BIG_SELECTS=1 ÅÓÌÉ SELECT ËÏÒÒÅËÔÅÎ",
+"îÅÉÚ×ÅÓÔÎÁÑ ÏÛÉÂËÁ",
+"îÅÉÚ×ÅÓÔÎÁÑ ÐÒÏÃÅÄÕÒÁ %-.64s",
+"îÅ×ÅÒÎÏÅ ËÏÌÉÞÅÓÔ×Ï ÐÁÒÁÍÅÔÒÏ× × ×ÙÚÏ×Å %-.64s",
+"îÅ×ÅÒÎÙÅ ÐÁÒÁÍÅÔÒÙ × ÐÒÏÃÅÄÕÒÅ %-.64s",
+"îÅÉÚ×ÅÓÔÎÁÑ ÔÁÂÌÉÃÁ '%-.64s' × %-.64s",
+"ðÏÌÅ '%-.64s' ÏÂßÑ×ÌÅÎÎÏ Ä×ÁÖÄÙ",
+"îÅ×ÅÒÎÏÅ ÉÓÐÏÌØÚÏ×ÁÎÉÅ ÇÒÕÐÐÏ×ÏÊ ÆÕÎËÃÉÉ",
+"ôÁÂÌÉÃÁ '%-.64s' ÉÓÐÏÌØÚÕÅÔ ÒÁÓÛÉÒÅÎÉÅ, ÎÅ ÓÕÝÅÓÔ×ÕÀÝÅÅ × ÄÁÎÎÏÊ ×ÅÒÓÉÉ MySQL",
+"÷ ÔÁÂÌÉÃÅ ÄÏÌÖÎÏ ÂÙÔØ ÈÏÔÑ ÂÙ ÏÄÎÏ ÐÏÌÅ",
+"ôÁÂÌÉÃÁ '%-.64s' ÐÅÒÅÐÏÌÎÅÎÁ",
+"îÅÉÚ×ÅÓÔÎÙÊ ÎÁÂÏÒ ÓÉÍ×ÏÌÏ×: '%-.64s'",
+"óÌÉÛËÏÍ ÍÎÏÇÏ ÔÁÂÌÉÃ. MySQL ÍÏÖÅÔ ÉÓÐÏÌØÚÏ×ÁÔØ ÔÏÌØËÏ %d ÔÁÂÌÉÃ × ÏÂßÅÄÉÎÅÎÉÉ",
+"óÌÉÛËÏÍ ÍÎÏÇÏ ÐÏÌÅÊ",
+"óÌÉÛËÏÍ ÂÏÌØÛÏÊ ÒÁÚÍÅÒ ÚÁÐÉÓÉ. íÁËÓÉÍÁÌØÎÙÊ ÒÁÚÍÅÒ ÚÁÐÉÓÉ - %d, ÎÅ ÓÞÉÔÁÑ blob. úÁÍÅÎÉÔÅ ÎÅËÏÔÏÒÙÅ ÐÏÌÑ ÎÁ blob",
+"ðÅÒÅÐÏÌÎÅÎÉÅ ÎÉÔÅ×ÏÇÏ ÓÔÅËÁ: éÓÐÏÌØÚÏ×ÁÎÏ %ld ÉÚ %ld. åÓÌÉ ÎÅÏÂÈÏÄÉÍÏ, ÉÓÐÏÌØÚÕÊÔÅ 'mysqld -O thread_stack=#' ÞÔÏÂÙ Õ×ÅÌÉÞÉÔØ ÒÁÚÍÅÒ ÓÔÅËÁ",
+"ðÅÒÅËÒÅÓÔÎÁÑ ÚÁ×ÉÓÉÍÏÓÔØ × OUTER JOIN. ðÒÏ×ÅÒØÔÅ ÕÓÌÏ×ÉÑ ON",
+"ðÏÌÅ '%-.32s' ÉÓÐÏÌØÚÕÅÔÓÑ ËÁË UNIQUE ÉÌÉ INDEX ÎÏ ÎÅ ÏÐÒÅÄÅÌÅÎÏ ËÁË NOT NULL",
+"îÅ ÍÏÇÕ ÚÁÇÒÕÚÉÔØ ÆÕÎËÃÉÀ '%-.64s'",
+"îÅ ÍÏÇÕ ÉÎÉÃÉÁÌÉÚÉÒÏ×ÁÔØ ÆÕÎËÃÉÀ '%-.64s'; %-.80s",
+"îÅÌØÚÑ ÉÓÐÏÌØÚÏ×ÁÔØ ÐÕÔÉ ÄÌÑ ÒÁÚÄÅÌÑÅÍÙÈ ÂÉÂÌÉÏÔÅË",
+"æÕÎËÃÉÑ '%-.64s' ÕÖÅ ÓÕÝÅÓÔ×ÕÅÔ",
+"îÅ ÍÏÇÕ ÏÔËÒÙÔØ ÒÁÚÄÅÌÑÅÍÕÀ ÂÉÂÌÉÏÔÅËÕ '%-.64s' (ïÛÉÂËÁ: %d %-.64s)",
+"îÅ ÍÏÇÕ ÎÁÊÔÉ ÆÕÎËÃÉÀ '%-.64s' × ÂÉÂÌÉÏÔÅËÅ'",
+"æÕÎËÃÉÑ '%-.64s' ÎÅ ÏÐÒÅÄÅÌÅÎÁ",
+"èÏÓÔ '%-.64s' ÚÁÂÌÏËÉÒÏ×ÁÎ ÉÚ-ÚÁ ÏÂÉÌÉÑ ÏÛÉÂÏË ÓÏÅÄÉÎÅÎÉÑ. òÁÚÂÌÏËÉÒÏ×ÁÔØ ÍÏÖÎÏ Ó ÐÏÍÏÝØÀ 'mysqladmin flush-hosts'",
+"èÏÓÔÕ '%-.64s' ÎÅ ÒÁÚÒÅÛÅÎÏ ÓÏÅÄÉÎÑÔØÓÑ Ó ÄÁÎÎÙÍ ÓÅÒ×ÅÒÏÍ MySQL",
+"÷Ù ÐÏÄËÌÀÞÅÎÙ Ë MySQL ËÁË ÁÎÏÎÉÍÎÙÊ ÐÏÌØÚÏ×ÁÔÅÌØ É ÷ÁÍ ÎÅ ÒÁÚÒÅÛÅÎÏ ÉÚÍÅÎÑÔØ ÐÁÒÏÌÉ",
+"÷Ù ÄÏÌÖÎÙ ÉÍÅÔØ ÐÒÁ×Á ÎÁ ÏÂÎÏ×ÌÅÎÉÅ ÔÁÂÌÉÃ × ÂÁÚÅ, ÞÔÏÂÙ ÉÚÍÅÎÉÔØ ÐÁÒÏÌØ ÄÒÕÇÉÍ ÐÏÌØÚÏ×ÁÔÅÌÑÍ",
+"îÅ ÍÏÇÕ ÎÁÊÔÉ ÎÉ ÏÄÎÏÇÏ ÓÏÏÔ×ÅÔÓÔ×ÉÑ × ÔÁÂÌÉÃÅ ÐÏÌØÚÏ×ÁÔÅÌÅÊ",
+"óÏÏÔ×ÅÔÓÔ×ÕÀÝÉÈ ÚÁÐÉÓÅÊ: %ld éÚÍÅÎÅÎÏ: %ld ðÒÅÄÕÐÒÅÖÄÅÎÉÊ: %ld",
+"îÅ ÍÏÇÕ ÓÏÚÄÁÔØ ÎÏ×ÕÀ ÎÉÔØ (ÏÛÉÂËÁ %d). åÓÌÉ ÜÔÏ ÎÅ ÉÚ-ÚÁ ÎÅÈ×ÁÔËÉ ÐÁÍÑÔÉ, ÐÏÓÍÏÔÒÉÔÅ × ÒÕËÏ×ÏÄÓÔ×Å ×ÏÚÍÏÖÎÙÅ OS-ÚÁ×ÉÓÉÍÙÅ ÇÌÀËÉ",
+"þÉÓÌÏ ÓÔÏÌÂÃÏ× ÎÅ ÓÏÏÔ×ÅÔÓÔ×ÕÅÔ ÞÉÓÌÕ ÚÎÁÞÅÎÉÊ × ÓÔÒÏËÅ %ld",
+"îÅ ÍÏÇÕ ÚÁÎÏ×Ï ÏÔËÒÙÔØ ÔÁÂÌÉÃÕ: '%-.64s',
+"îÅÐÒÁ×ÉÌØÎÏÅ ÉÓÐÏÌØÚÏ×ÁÎÉÅ ÚÎÁÞÅÎÉÑ NULL",
+"REGEXP ×ÅÒÎÕÌ ÏÛÉÂËÕ '%-.64s'",
+"éÓÐÏÌØÚÏ×ÁÎÉÅ ÁÇÒÅÇÁÔÎÙÈ ÆÕÎËÃÉÊ (MIN(),MAX(),COUNT()...) ÓÏ×ÍÅÓÔÎÏ Ó ÏÂÙÞÎÙÍÉ ÚÎÁÞÅÎÉÑÍÉ ×ÏÚÍÏÖÎÏ ÔÏÌØËÏ ÐÒÉ ÎÁÌÉÞÉÉ ÒÁÚÄÅÌÁ GROUP BY",
+"äÌÑ ÐÏÌØÚÏ×ÁÔÅÌÑ '%-.32s' Ó ÈÏÓÔÁ '%-.64s' ÐÒÉ×ÉÌÅÇÉÉ ÎÅ ÏÐÒÅÄÅÌÅÎÙ",
+"%-.16s ËÏÍÁÎÄÁ ÎÅ ÒÁÚÒÅÛÅÎÁ ÐÏÌØÚÏ×ÁÔÅÌÀ: '%-.32s@%-.64s' ÄÌÑ ÔÁÂÌÉÃÙ '%-.64s'",
+"%-.16s ËÏÍÁÎÄÁ ÎÅ ÒÁÚÒÅÛÅÎÁ ÐÏÌØÚÏ×ÁÔÅÌÀ: '%-.32s@%-.64s'\n ÄÌÑ ÐÏÌÑ '%-.64s' ÉÚ ÔÁÂÌÉÃÙ '%-.64s'",
+"úÁÄÁÎÙ ÎÅ×ÅÒÎÙÅ ÐÒÉ×ÉÌÅÇÉÉ ÄÌÑ ÔÁÂÌÉÃÙ",
+"éÍÑ ÈÏÓÔÁ ÉÌÉ ÐÏÌØÚÏ×ÁÔÅÌÑ ÓÌÉÛËÏÍ ×ÅÌÉËÏ ÄÌÑ ÔÁÂÌÉÃÙ ÐÒÉ×ÉÌÅÇÉÊ",
+"ôÁÂÌÉÃÁ '%-.64s.%-.64s' ÎÅ ÓÕÝÅÓÔ×ÕÅÔ",
+"ðÒÉ×ÉÌÅÇÉÉ ÐÏÌØÚÏ×ÁÔÅÌÑ '%-.32s' Ó ÈÏÓÔÁ '%-.64s' ÄÌÑ ÔÁÂÌÉÃÙ '%-.64s' ÎÅ ÏÐÒÅÄÅÌÅÎÙ",
+"äÁÎÎÁÑ ËÏÍÁÎÄÁ ÎÅ ÐÏÄÄÅÒÖÉ×ÁÅÔÓÑ ÜÔÏÊ ×ÅÒÓÉÅÊ MySQL",
+"ëÁËÁÑ-ÔÏ ÓÉÎÔÁËÓÉÞÅÓËÁÑ ÏÛÉÂËÁ",
+"ðÏÔÏË ÄÌÑ delayed insert ÎÅ ÍÏÖÅÔ ÐÏÌÕÞÉÔØ ÂÌÏËÉÒÏ×ËÕ ÄÌÑ ÔÁÂÌÉÃÙ %-.64s",
+"éÓÐÏÌØÚÕÅÔÓÑ ÓÌÉÛËÏÍ ÍÎÏÇÏ delayed ÐÏÔÏËÏ×",
+"ðÒÅÒ×ÁÎÎÁÑ Ó×ÑÚØ %ld Ó ÂÁÚÏÊ ÄÁÎÎÙÈ: '%-.64s' ÐÏÌØÚÏ×ÁÔÅÌØ: '%-.64s' (%-.64s)",
+"ðÁËÅÔ ÂÏÌØÛÅ ÞÅÍ 'max_allowed_packet'",
+"ïÛÉÂËÁ ÞÔÅÎÉÑ ÉÚ ÔÒÕÂÙ ËÏÎÎÅËÔÁ",
+"fcntl() ×ÅÒÎÕÌ ÏÛÉÂËÕ",
+"ðÏÌÕÞÅÎ ÐÁËÅÔ × ÎÅÐÒÁ×ÉÌØÎÏÍ ÐÏÒÑÄËÅ",
+"îÅ ÍÏÇÕ ÒÁÓÐÁËÏ×ÁÔØ ÐÁËÅÔ",
+"ïÛÉÂËÁ ÐÒÉ ÞÔÅÎÉÉ ÐÁËÅÔÏ×"
+"Timeout ÐÒÉ ÞÔÅÎÉÉ ÐÁËÅÔÏ×",
+"ïÛÉÂËÁ ÐÒÉ ÏÔÐÒÁ×ËÅ ÐÁËÅÔÏ×",
+"ïÛÉÂËÁ ÐÒÉ ÏÔÐÒÁ×ËÅ ÐÁËÅÔÏ×",
+"òÅÚÕÌØÔÉÒÕÀÝÁÑ ÓÔÒÏËÁ ÂÏÌØÛÅ ÞÅÍ max_allowed_packet",
+"éÓÐÏÌØÚÕÅÍÁÑ ÔÁÂÌÉÃÁ ÎÅ ÐÏÄÄÅÒÖÉ×ÁÅÔ ÐÏÌÑ BLOB/TEXT",
+"éÓÐÏÌØÚÕÅÍÁÑ ÔÁÂÌÉÃÁ ÎÅ ÐÏÄÄÅÒÖÉ×ÁÅÔ ÐÏÌÑ AUTO_INCREMENT",
+"INSERT DELAYED ÎÅ ÍÏÖÅÔ ÉÓÐÏÌØÚÏ×ÁÔØÓÑ Ó ÔÁÂÌÉÃÅÊ '%-.64s', ÏÎÁ ÚÁÎÑÔÁ ÉÓÐÏÌØÚÏ×ÁÎÉÅÍ LOCK TABLES",
+"îÅ×ÅÒÎÏÅ ÉÍÑ ÐÏÌÑ '%-.100s'",
+"éÓÐÏÌØÚÕÅÍÙÊ table handler ÎÅ ÍÏÖÅÔ ÉÎÄÅËÓÉÒÏ×ÁÔØ ÐÏÌÅ '%-.64s'",
+"All tables in the MERGE table are not defined identically",
+"Can't write, because of unique constraint, to table '%-.64s'",
+"BLOB column '%-.64s' used in key specification without a key length",
+"All parts of a PRIMARY KEY must be NOT NULL; If you need NULL in a key, use UNIQUE instead",
+"Result consisted of more than one row",
+"This table type requires a primary key",
+"This version of MySQL is not compiled with RAID support",
+"You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column",
+"Key '%-.64s' doesn't exist in table '%-.64s'",
+"Can't open table",
+"The handler for the table doesn't support check/repair",
+"You are not allowed to execute this command in a transaction",
+"Got error %d during COMMIT",
+"Got error %d during ROLLBACK",
+"Got error %d during FLUSH_LOGS",
+"Got error %d during CHECKPOINT",
+"Aborted connection %ld to db: '%-.64s' user: '%-.32s' host: `%-.64s' (%-.64s)",
+"The handler for the table does not support binary table dump",
+"Binlog closed while trying to FLUSH MASTER",
+"Failed rebuilding the index of dumped table '%-.64s'",
+"Error from master: '%-.64s'",
+"Net error reading from master",
+"Net error writing to master",
+"FULLTEXT ÉÎÄÅËÓ, ÓÏÏÔ×ÅÔÓÔ×ÕÀÝÉÊ ÚÁÄÁÎÎÏÍÕ ÓÐÉÓËÕ ÓÔÏÌÂÃÏ×, ÎÅ ÎÁÊÄÅÎ",
diff --git a/sql/share/slovak/errmsg.sys b/sql/share/slovak/errmsg.sys
new file mode 100644
index 00000000000..c14049c829f
--- /dev/null
+++ b/sql/share/slovak/errmsg.sys
Binary files differ
diff --git a/sql/share/slovak/errmsg.txt b/sql/share/slovak/errmsg.txt
new file mode 100644
index 00000000000..7b5d8f9a015
--- /dev/null
+++ b/sql/share/slovak/errmsg.txt
@@ -0,0 +1,203 @@
+/* Copyright Abandoned 1997 TCX DataKonsult AB & Monty Program KB & Detron HB
+ This file is public domain and comes with NO WARRANTY of any kind */
+
+/*
+ Translated from both E n g l i s h & C z e c h error messages
+ by steve: (billik@sun.uniag.sk).
+ Encoding: ISO LATIN-8852-2
+ Server version: 3.21.25-gamma
+ Date: Streda 11. November 1998 20:58:15
+*/
+
+"hashchk",
+"isamchk",
+"NIE",
+"Áno",
+"Nemô¾em vytvori» súbor '%-.64s' (chybový kód: %d)",
+"Nemô¾em vytvori» tabuµku '%-.64s' (chybový kód: %d)",
+"Nemô¾em vytvori» databázu '%-.64s'. (chybový kód: %d)",
+"Nemô¾em vytvori» databázu '%-.64s'. Databáza existuje",
+"Nemô¾em zmaza» databázu '%-.64s'. Databáza neexistuje",
+"Chyba pri mazaní databázy (nemô¾em zmaza» '%-.64s', chybový kód: %d)",
+"Chyba pri mazaní databázy (nemô¾em vymaza» adresár '%-.64s', chybový kód: %d)",
+"Chyba pri mazaní '%-.64s' (chybový kód: %d)",
+"Nemô¾em èíta» záznam v systémovej tabuµke",
+"Nemô¾em zisti» stav '%-.64s' (chybový kód: %d)",
+"Nemô¾em zisti» pracovný adresár (chybový kód: %d)",
+"Nemô¾em zamknú» súbor (chybový kód: %d)",
+"Nemô¾em otvori» súbor: '%-.64s'. (chybový kód: %d)",
+"Nemô¾em nájs» súbor: '%-.64s' (chybový kód: %d)",
+"Nemô¾em èíta» adresár '%-.64s' (chybový kód: %d)",
+"Nemô¾em vojs» do adresára '%-.64s' (chybový kód: %d)",
+"Záznam bol zmenený od posledného èítania v tabuµke '%-.64s'",
+"Disk je plný (%s), èakám na uvoµnenie miesta....",
+"Nemô¾em zapísa», duplikát kµúèa v tabuµke '%-.64s'",
+"Chyba pri zatváraní '%-.64s' (chybový kód: %d)",
+"Chyba pri èítaní súboru '%-.64s' (chybový kód: %d)",
+"Chyba pri premenovávaní '%-.64s' na '%-.64s' (chybový kód: %d)",
+"Chyba pri zápise do súboru '%-.64s' (chybový kód: %d)",
+"'%-.64s' je zamknutý proti zmenám",
+"Triedenie preru¹ené",
+"Pohµad '%-.64s' neexistuje pre '%-.64s'",
+"Obsluha tabuµky vrátila chybu %d",
+"Obsluha tabuµky '%-.64s' nemá tento parameter",
+"Nemô¾em nájs» záznam v '%-.64s'",
+"Nesprávna informácia v súbore: '%-.64s'",
+"Nesprávny kµúè pre tabuµku '%-.64s'. Pokúste sa ho opravi»",
+"Starý kµúèový súbor pre '%-.64s'; Opravte ho!",
+"'%-.64s' is èíta» only",
+"Málo pamäti. Re¹tartujte daemona a skúste znova (je potrebných %d bytov)",
+"Málo pamäti pre triedenie, zvý¹te veµkos» triediaceho bufferu",
+"Neoèakávaný koniec súboru pri èítaní '%-.64s' (chybový kód: %d)",
+"Príli¹ mnoho spojení",
+"Málo miesta-pamäti pre vlákno",
+"Nemô¾em zisti» meno hostiteµa pre va¹u adresu",
+"Chyba pri nadväzovaní spojenia",
+"Zakázaný prístup pre u¾ívateµa: '%-.32s@%-.64s' k databázi '%-.64s'",
+"Zakázaný prístup pre u¾ívateµa: '%-.32s@%-.64s' (pou¾itie hesla: %s)",
+"Nebola vybraná databáza",
+"Neznámy príkaz",
+"Pole '%-.64s' nemô¾e by» null",
+"Neznáma databáza '%-.64s'",
+"Tabuµka '%-.64s' u¾ existuje",
+"Neznáma tabuµka '%-.64s'",
+"Pole: '%-.64s' v %-.64s je nejasné",
+"Prebieha ukonèovanie práce servera",
+"Neznáme pole '%-.64s' v '%-.64s'",
+"Pou¾ité '%-.64s' nebolo v 'group by'",
+"Nemô¾em pou¾i» 'group' na '%-.64s'",
+"Príkaz obsahuje zároveò funkciu 'sum' a poµa",
+"Poèet polí nezodpovedá zadanej hodnote",
+"Meno identifikátora '%-.100s' je príli¹ dlhé",
+"Opakované meno poµa '%-.64s'",
+"Opakované meno kµúèa '%-.64s'",
+"Opakovaný kµúè '%-.64s' (èíslo kµúèa %d)",
+"Chyba v ¹pecifikácii poµa '%-.64s'",
+"%s blízko '%-.80s' na riadku %d",
+"Výsledok po¾iadavky bol prázdny",
+"Nie jednoznaèná tabuµka/alias: '%-.64s'",
+"Chybná implicitná hodnota pre '%-.64s'",
+"Zadefinovaných viac primárnych kµúèov",
+"Zadaných ríli¹ veµa kµúèov. Najviac %d kµúèov je povolených",
+"Zadaných ríli¹ veµa èastí kµúèov. Je povolených najviac %d èastí",
+"Zadaný kµúè je príli¹ dlhý, najväè¹ia då¾ka kµúèa je %d",
+"Kµúèový ståpec '%-.64s' v tabuµke neexistuje",
+"Blob pole '%-.64s' nemô¾e by» pou¾ité ako kµúè",
+"Príli¹ veµká då¾ka pre pole '%-.64s' (maximum = %d). Pou¾ite BLOB",
+"Mô¾ete ma» iba jedno AUTO pole a to musí by» definované ako kµúè",
+"%s: pripravený na spojenie\n",
+"%s: normálne ukonèenie\n",
+"%s: prijatý signál %d, ukonèenie (Abort)!\n",
+"%s: práca ukonèená\n",
+"%s: násilné ukonèenie vlákna %ld u¾ívateµa '%-.64s'\n",
+"Nemô¾em vytvori» IP socket",
+"Tabuµka '%-.64s' nemá index zodpovedajúci CREATE INDEX. Vytvorte tabulku znova",
+"Argument oddeµovaè polí nezodpovedá po¾iadavkám. Skontrolujte v manuáli","
+"Nie je mo¾né pou¾i» fixnú då¾ku s BLOBom. Pou¾ite 'fields terminated by'.",
+"Súbor '%-.64s' musí by» v adresári databázy, alebo èitateµný pre v¹etkých",
+"Súbor '%-.64s' u¾ existuje",
+"Záznamov: %ld Zmazaných: %ld Preskoèených: %ld Varovania: %ld",
+"Záznamov: %ld Opakovaných: %ld",
+"Wrong sub part key. The used key part isn't a string or the used length is longer than the key part",
+"One nemô¾em zmaza» all fields with ALTER TABLE. Use DROP TABLE instead",
+"Nemô¾em zru¹i» (DROP) '%-.64s'. Skontrolujte, èi neexistujú záznamy/kµúèe",
+"Záznamov: %ld Opakovaných: %ld Varovania: %ld",
+"INSERT TABLE '%-.64s' nie je dovolené v zozname tabuliek FROM",
+"Neznáma identifikácia vlákna: %lu",
+"Nie ste vlastníkom vlákna %lu",
+"Nie je pou¾itá ¾iadna tabuµka",
+"Príli¹ mnoho re»azcov pre pole %-.64s a SET",
+"Nemô¾em vytvori» unikátne meno log-súboru %-.64s.(1-999)\n",
+"Tabuµka '%-.64s' bola zamknutá s READ a nemô¾e by» zmenená",
+"Tabuµka '%-.64s' nebola zamknutá s LOCK TABLES",
+"Pole BLOB '%-.64s' nemô¾e ma» implicitnú hodnotu",
+"Neprípustné meno databázy '%-.100s'",
+"Neprípustné meno tabuµky '%-.100s'",
+"Zadaná po¾iadavka SELECT by prechádzala príli¹ mnoho záznamov a trvala by príli¹ dlho. Skontrolujte tvar WHERE a ak je v poriadku, pou¾ite SET OPTION SQL_BIG_SELECTS=1",
+"Neznámá chyba",
+"Neznámá procedúra '%-.64s'",
+"Chybný poèet parametrov procedúry '%-.64s'",
+"Chybné parametre procedúry '%-.64s'",
+"Neznáma tabuµka '%-.64s' v %s",
+"Pole '%-.64s' je zadané dvakrát",
+"Nesprávne pou¾itie funkcie GROUP",
+"Tabuµka '%-.64s' pou¾íva roz¹írenie, ktoré v tejto verzii MySQL nie je",
+"Tabuµka musí ma» aspoò 1 pole",
+"Tabuµka '%-.64s' je plná",
+"Neznáma znaková sada: '%-.64s'",
+"Príli¹ mnoho tabuliek. MySQL mô¾e pou¾i» len %d v JOIN-e",
+"Príli¹ mnoho polí",
+"Riadok je príli¹ veµký. Maximálna veµkos» riadku, okrem 'BLOB', je %d. Musíte zmeni» niektoré polo¾ky na BLOB",
+"Preteèenie zásobníku vlákna: pou¾ité: %ld z %ld. Pou¾ite 'mysqld -O thread_stack=#' k zadaniu väè¹ieho zásobníka",
+"V OUTER JOIN bol nájdený krí¾ový odkaz. Skontrolujte podmienky ON",
+"Pole '%-.64s' je pou¾ité s UNIQUE alebo INDEX, ale nie je zadefinované ako NOT NULL",
+"Nemô¾em naèíta» funkciu '%-.64s'",
+"Nemô¾em inicializova» funkciu '%-.64s'; %-.80s",
+"Neprípustné ¾iadne cesty k zdieµanej kni¾nici",
+"Funkcia '%-.64s' u¾ existuje",
+"Nemô¾em otvori» zdieµanú kni¾nicu '%-.64s' (chybový kód: %d %s)",
+"Nemô¾em nájs» funkciu '%-.64s' v kni¾nici'",
+"Funkcia '%-.64s' nie je definovaná",
+"Host '%-.64s' is blocked because of many connection errors. Unblock with 'mysqladmin flush-hosts'",
+"Host '%-.64s' is not allowed to connect to this MySQL server",
+"You are using MySQL as an anonymous users and anonymous users are not allowed to change passwords",
+"You must have privileges to update tables in the mysql database to be able to change passwords for others",
+"Can't find any matching row in the user table",
+"Rows matched: %ld Changed: %ld Warnings: %ld",
+"Can't create a new thread (errno %d). If you are not out of available memory, you can consult the manual for a possible OS-dependent bug",
+"Column count doesn't match value count at row %ld",
+"Can't reopen table: '%-.64s',
+"Invalid use of NULL value",
+"Got error '%-.64s' from regexp",
+"Mixing of GROUP columns (MIN(),MAX(),COUNT()...) with no GROUP columns is illegal if there is no GROUP BY clause",
+"There is no such grant defined for user '%-.32s' on host '%-.64s'",
+"%-.16s command denied to user: '%-.32s@%-.64s' for table '%-.64s'",
+"%-.16s command denied to user: '%-.32s@%-.64s' for column '%-.64s' in table '%-.64s'",
+"Illegal GRANT/REVOKE command. Please consult the manual which privleges can be used.",
+"The host or user argument to GRANT is too long",
+"Table '%-64s.%s' doesn't exist",
+"There is no such grant defined for user '%-.32s' on host '%-.64s' on table '%-.64s'",
+"The used command is not allowed with this MySQL version",
+"Something is wrong in your syntax",
+"Delayed insert thread couldn't get requested lock for table %-.64s",
+"Too many delayed threads in use",
+"Aborted connection %ld to db: '%-.64s' user: '%-.64s' (%s)",
+"Got a packet bigger than 'max_allowed_packet'",
+"Got a read error from the connection pipe",
+"Got an error from fcntl()",
+"Got packets out of order",
+"Couldn't uncompress communication packet",
+"Got an error reading communication packets"
+"Got timeout reading communication packets",
+"Got an error writing communication packets",
+"Got timeout writing communication packets",
+"Result string is longer than max_allowed_packet",
+"The used table type doesn't support BLOB/TEXT columns",
+"The used table type doesn't support AUTO_INCREMENT columns",
+"INSERT DELAYED can't be used with table '%-.64s', because it is locked with LOCK TABLES",
+"Incorrect column name '%-.100s'",
+"The used table handler can't index column '%-.64s'",
+"All tables in the MERGE table are not defined identically",
+"Can't write, because of unique constraint, to table '%-.64s'",
+"BLOB column '%-.64s' used in key specification without a key length",
+"All parts of a PRIMARY KEY must be NOT NULL; If you need NULL in a key, use UNIQUE instead",
+"Result consisted of more than one row",
+"This table type requires a primary key",
+"This version of MySQL is not compiled with RAID support",
+"You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column",
+"Key '%-.64s' doesn't exist in table '%-.64s'",
+"Can't open table",
+"The handler for the table doesn't support check/repair",
+"You are not allowed to execute this command in a transaction",
+"Got error %d during COMMIT",
+"Got error %d during ROLLBACK",
+"Got error %d during FLUSH_LOGS",
+"Got error %d during CHECKPOINT",
+"Aborted connection %ld to db: '%-.64s' user: '%-.32s' host: `%-.64s' (%-.64s)",
+"The handler for the table does not support binary table dump",
+"Binlog closed while trying to FLUSH MASTER",
+"Failed rebuilding the index of dumped table '%-.64s'",
+"Error from master: '%-.64s'",
+"Net error reading from master",
+"Net error writing to master",
+"Can't find FULLTEXT index matching the column list",
diff --git a/sql/share/spanish/errmsg.sys b/sql/share/spanish/errmsg.sys
new file mode 100644
index 00000000000..60c71cb8e8f
--- /dev/null
+++ b/sql/share/spanish/errmsg.sys
Binary files differ
diff --git a/sql/share/spanish/errmsg.txt b/sql/share/spanish/errmsg.txt
new file mode 100644
index 00000000000..0f16b66f6d8
--- /dev/null
+++ b/sql/share/spanish/errmsg.txt
@@ -0,0 +1,196 @@
+/* Copyright Abandoned 1997 TCX DataKonsult AB & Monty Program KB & Detron HB
+ This file is public domain and comes with NO WARRANTY of any kind
+ Traduccion por Miguel Angel Fernandez Roiz -- LoboCom Sistemas, s.l. */
+
+"hashchk",
+"isamchk",
+"NO",
+"SI",
+"No puedo crear archivo '%-.64s' (Error: %d)",
+"No puedo crear tabla '%-.64s' (Error: %d)",
+"No puedo crear base de datos '%-.64s'. Error %d",
+"No puedo crear base de datos '%-.64s'. La base de datos ya existe",
+"No puedo eliminar base de datos '%-.64s'. La base de datos no existe",
+"Error eliminando la base de datos(no puedo borrar '%-.64s', error %d)",
+"Error eliminando la base de datos (No puedo borrar directorio '%-.64s', error %d)",
+"Error en el borrado de '%-.64s' (Error: %d)",
+"No puedo leer el registro en la tabla del sistema",
+"No puedo obtener el estado de '%-.64s' (Error: %d)",
+"No puedo acceder al directorio (Error: %d)",
+"No puedo bloquear archivo: (Error: %d)",
+"No puedo abrir archivo: '%-.64s'. (Error: %d)",
+"No puedo encontrar archivo: '%-.64s' (Error: %d)",
+"No puedo leer el directorio de '%-.64s' (Error: %d)",
+"No puedo cambiar al directorio de '%-.64s' (Error: %d)",
+"El registro ha cambiado desde la ultima lectura de la tabla '%-.64s'",
+"Disco lleno (%s). Esperando para que se libere algo de espacio....",
+"No puedo escribir, clave duplicada en la tabla '%-.64s'",
+"Error en el cierre de '%-.64s' (Error: %d)",
+"Error leyendo el fichero '%-.64s' (Error: %d)",
+"Error en el renombrado de '%-.64s' a '%-.64s' (Error: %d)",
+"Error escribiendo el archivo '%-.64s' (Error: %d)",
+"'%-.64s' esta bloqueado contra cambios",
+"Ordeancion cancelada",
+"La vista '%-.64s' no existe para '%-.64s'",
+"Error %d desde el manejador de la tabla",
+"El manejador de la tabla de '%-.64s' no tiene esta opcion",
+"No puedo encontrar el registro en '%-.64s'",
+"Informacion erronea en el archivo: '%-.64s'",
+"Clave de archivo erronea para la tabla: '%-.64s'. Intente repararlo",
+"Clave de archivo antigua para la tabla '%-.64s'; Reparelo!",
+"'%-.64s' es de solo lectura",
+"Memoria insuficiente. Reinicie el demonio e intentelo otra vez (necesita %d bytes)",
+"Memoria de ordenacion insuficiente. Incremente el tamano del buffer de ordenacion",
+"Inesperado fin de ficheroU mientras leiamos el archivo '%-.64s' (Error: %d)",
+"Demasiadas conexiones",
+"Memoria/espacio de tranpaso insuficiente",
+"No puedo obtener el nombre de maquina de tu direccion",
+"Protocolo erroneo",
+"Access denied for user: '%-.32s@%-.64s' to database '%-.64s'",
+"Access denied for user: '%-.32s@%-.64s' (Using password: %s)",
+"Base de datos no seleccionada",
+"Comando desconocido",
+"La columna '%-.64s' no puede ser nula",
+"Base de datos desconocida '%-.64s'",
+"La tabla '%-.64s' ya existe",
+"Tabla '%-.64s' desconocida",
+"La columna: '%-.64s' en %s es ambigua",
+"Desconexion de servidor en proceso",
+"La columna '%-.64s' en %s es desconocida",
+"Usado '%-.64s' el cual no esta group by",
+"No puedo agrupar por '%-.64s'",
+"El estamento tiene funciones de suma y columnas en el mismo estamento",
+"La columna con count no tiene valores para contar",
+"El nombre del identificador '%-.64s' es demasiado grande",
+"Nombre de columna duplicado '%-.64s'",
+"Nombre de clave duplicado '%-.64s'",
+"Entrada duplicada '%-.64s' para la clave %d",
+"Especificador de columna erroneo para la columna '%-.64s'",
+"%s cerca '%-.64s' en la linea %d",
+"La query estaba vacia",
+"Tabla/alias: '%-.64s' es no unica",
+"Valor por defecto invalido para '%-.64s'",
+"Multiples claves primarias definidas",
+"Demasiadas claves primarias declaradas. Un maximo de %d claves son permitidas",
+"Demasiadas partes de clave declaradas. Un maximo de %d partes son permitidas",
+"Declaracion de clave demasiado larga. La maxima longitud de clave es %d",
+"La columna clave '%-.64s' no existe en la tabla",
+"La columna Blob '%-.64s' no puede ser usada en una declaracion de clave",
+"Longitud de columna demasiado grande para la columna '%-.64s' (maximo = %d).Usar BLOB en su lugar",
+"Puede ser solamente un campo automatico y este debe ser definido como una clave",
+"%s: preparado para conexiones\n",
+"%s: Apagado normal\n",
+"%s: Recibiendo signal %d. Abortando!\n",
+"%s: Apagado completado\n",
+"%s: Forzando a cerrar el thread %ld usuario: '%-.64s'\n",
+"No puedo crear IP socket",
+"La tabla '%-.64s' no tiene indice como el usado en CREATE INDEX. Crea de nuevo la table",
+"Los separadores de argumentos del campo no son los especificados. Comprueba el manual","
+"No puedes usar longitudes de filas fijos con BLOBs. Por favor usa 'campos terminados por '.",
+"El archivo '%-.64s' debe estar en el directorio de la base de datos o ser de lectura por todos",
+"El archivo '%-.64s' ya existe",
+"Registros: %ld Borrados: %ld Saltados: %ld Peligros: %ld",
+"Registros: %ld Duplicados: %ld",
+"Parte de la calve es erronea. Una parte de la calve no es una cadena o la longitud usada es tan grandecomo la parte de la clave",
+"No puede borrar todos los campos con ALTER TABLE. Usa DROP TABLE para hacerlo",
+"No puedo ELIMINAR '%-.64s'. compuebe que el campo/clave existe",
+"Registros: %ld Duplicados: %ld Peligros: %ld",
+"INSERT TABLE '%-.64s' no esta permitido en FROM tabla lista",
+"Identificador del thread: %lu desconocido",
+"Tu no eres el propietario del thread%lu",
+"No ha tablas usadas",
+"Too many strings for column %s and SET",
+"Can't generate a unique logfilename %s.(1-999)\n",
+"Table '%-.64s' was locked with a READ lock and can't be updated",
+"Table '%-.64s' was not locked with LOCK TABLES",
+"Blob field '%-.64s' can't have a default value",
+"Illegal database name '%-.64s'",
+"Illegal table name '%-.64s'",
+"The SELECT would examine too many records and probably take very long time. Check your WHERE and use SET OPTION SQL_BIG_SELECTS=1 if the SELECT is ok",
+"Unknown error",
+"Unkown procedure %s",
+"Wrong parameter count to procedure %s",
+"Wrong parameters to procedure %s",
+"Unknown table '%-.64s' in %s",
+"Field '%-.64s' specified twice",
+"Invalid use of group function",
+"Table '%-.64s' uses a extension that doesn't exist in this MySQL version",
+"A table must have at least 1 column",
+"The table '%-.64s' is full",
+"Unknown character set: '%-.64s'",
+"Too many tables. MySQL can only use %d tables in a join",
+"Too many fields",
+"Too big row size. The maximum row size, not counting blobs, is %d. You have to change some fields to blobs",
+"Thread stack overrun: Used: %ld of a %ld stack. Use 'mysqld -O thread_stack=#' to specify a bigger stack if needed",
+"Cross dependency found in OUTER JOIN. Examine your ON conditions",
+"Column '%-.32s' is used with UNIQUE or INDEX but is not defined as NOT NULL",
+"Can't load function '%-.64s'",
+"Can't initialize function '%-.64s'; %-.80s",
+"No paths allowed for shared library",
+"Function '%-.64s' already exist",
+"Can't open shared library '%-.64s' (errno: %d %s)",
+"Can't find function '%-.64s' in library'",
+"Function '%-.64s' is not defined",
+"Host '%-.64s' is blocked because of many connection errors. Unblock with 'mysqladmin flush-hosts'",
+"Host '%-.64s' is not allowed to connect to this MySQL server",
+"You are using MySQL as an anonymous users and anonymous users are not allowed to change passwords",
+"You must have privileges to update tables in the mysql database to be able to change passwords for others",
+"Can't find any matching row in the user table",
+"Rows matched: %ld Changed: %ld Warnings: %ld",
+"Can't create a new thread (errno %d). If you are not out of available memory you can consult the manual for any possible OS dependent bug",
+"Column count doesn't match value count at row %ld",
+"Can't reopen table: '%-.64s',
+"Invalid use of NULL value",
+"Got error '%-.64s' from regexp",
+"Mixing of GROUP columns (MIN(),MAX(),COUNT()...) with no GROUP columns is illegal if there is no GROUP BY clause",
+"There is no such grant defined for user '%-.32s' on host '%-.64s'",
+"%-.16s command denied to user: '%-.32s@%-.64s' for table '%-.64s'",
+"%-.16s command denied to user: '%-.32s@%-.64s' for column '%-.64s' in table '%-.64s'",
+"Illegal GRANT/REVOKE command. Please consult the manual which privleges can be used.",
+"The host or user argument to GRANT is too long",
+"Table '%-64s.%s' doesn't exist",
+"There is no such grant defined for user '%-.32s' on host '%-.64s' on table '%-.64s'",
+"The used command is not allowed with this MySQL version",
+"Something is wrong in your syntax",
+"Delayed insert thread couldn't get requested lock for table %-.64s",
+"Too many delayed threads in use",
+"Aborted connection %ld to db: '%-.64s' user: '%-.64s' (%s)",
+"Got a packet bigger than 'max_allowed_packet'",
+"Got a read error from the connection pipe",
+"Got an error from fcntl()",
+"Got packets out of order",
+"Couldn't uncompress communication packet",
+"Got an error reading communication packets"
+"Got timeout reading communication packets",
+"Got an error writing communication packets",
+"Got timeout writing communication packets",
+"Result string is longer than max_allowed_packet",
+"The used table type doesn't support BLOB/TEXT columns",
+"The used table type doesn't support AUTO_INCREMENT columns",
+"INSERT DELAYED can't be used with table '%-.64s', because it is locked with LOCK TABLES",
+"Incorrect column name '%-.100s'",
+"The used table handler can't index column '%-.64s'",
+"All tables in the MERGE table are not defined identically",
+"Can't write, because of unique constraint, to table '%-.64s'",
+"BLOB column '%-.64s' used in key specification without a key length",
+"All parts of a PRIMARY KEY must be NOT NULL; If you need NULL in a key, use UNIQUE instead",
+"Result consisted of more than one row",
+"This table type requires a primary key",
+"This version of MySQL is not compiled with RAID support",
+"You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column",
+"Key '%-.64s' doesn't exist in table '%-.64s'",
+"Can't open table",
+"The handler for the table doesn't support check/repair",
+"You are not allowed to execute this command in a transaction",
+"Got error %d during COMMIT",
+"Got error %d during ROLLBACK",
+"Got error %d during FLUSH_LOGS",
+"Got error %d during CHECKPOINT",
+"Aborted connection %ld to db: '%-.64s' user: '%-.32s' host: `%-.64s' (%-.64s)",
+"The handler for the table does not support binary table dump",
+"Binlog closed while trying to FLUSH MASTER",
+"Failed rebuilding the index of dumped table '%-.64s'",
+"Error from master: '%-.64s'",
+"Net error reading from master",
+"Net error writing to master",
+"Can't find FULLTEXT index matching the column list",
diff --git a/sql/share/swedish/errmsg.OLD b/sql/share/swedish/errmsg.OLD
new file mode 100644
index 00000000000..0181d0febd6
--- /dev/null
+++ b/sql/share/swedish/errmsg.OLD
@@ -0,0 +1,195 @@
+/* Copyright Abandoned 1997 TCX DataKonsult AB & Monty Program KB & Detron HB
+ This file is public domain and comes with NO WARRANTY of any kind */
+
+"hashchk",
+"isamchk",
+"NO",
+"YES",
+"Kan inte skapa filen: '%-.64s' (Felkod: %d)",
+"Kan inte skapa tabellen: '%-.64s' (Felkod: %d)",
+"Kan inte skapa databasen '%-.64s'. (Felkod: %d)",
+"Databasen '%-.64s' existerar redan",
+"Kan inte radera databasen '%-.64s'. Databasen finns inte",
+"Fel vid radering av databasen (Kan inte radera '%-.64s'. Felkod: %d)",
+"Fel vid radering av databasen (Kan inte radera biblioteket '%-.64s'. Felkod: %d)",
+"Kan inte radera filen: '%-.64s' (Felkod: %d)",
+"Hittar inte posten i systemregistret",
+"Kan inte läsa filinformationen (stat) från '%-.64s' (Felkod: %d)",
+"Kan inte inte läsa aktivt bibliotek. (Felkod: %d)",
+"Kan inte låsa filen. (Felkod: %d)",
+"Kan inte använda: '%-.64s'. (Felkod: %d)",
+"Hittar inte filen: '%-.64s'. (Felkod: %d)",
+"Kan inte läsa från bibliotek '%-.64s'. (Felkod: %d)",
+"Kan inte byta till: '%-.64s'. (Felkod: %d)",
+"Posten har förändrats sedan den lästes i register '%-.64s'",
+"Disken är full (%s). Väntar tills det finns ledigt utrymme....",
+"Kan inte skriva, dubbel söknyckel i register '%-.64s'",
+"Fick fel vid stängning av '%-.64s' (Felkod: %d)",
+"Fick fel vid läsning av '%-.64s' (Felkod %d)",
+"Kan inte byta namn från '%-.64s' till '%-.64s' (Felkod: %d)",
+"Fick fel vid skrivning till '%-.64s' (Felkod %d)",
+"'%-.64s' är låst mot användning",
+"Sorteringen avbruten",
+"Formulär '%-.64s' finns inte i '%-.64s'",
+"Fick felkod %d från databashanteraren",
+"Registrets databas har inte denna facilitet",
+"Hittar inte posten",
+"Felaktig fil: '%-.64s'",
+"Fatalt fel vid hantering av register '%-.64s'. Kör en reparation",
+"Gammal nyckelfil '%-.64s'; Reparera registret",
+"'%-.64s' är skyddad mot förändring",
+"Oväntat slut på minnet, starta om programmet och försök på nytt (Behövde %d bytes)",
+"Sorteringsbufferten räcker inte till. Kontrollera startparametrarna",
+"Oväntat filslut vid läsning från '%-.64s' (Felkod: %d)",
+"För många anslutningar",
+"Fick slut på minnet. Kontrollera ifall mysqld eller någon annan process använder allt tillgängligt minne. Ifall inte, försök använda 'ulimit' eller allokera mera swap",
+"Kan inte hitta 'hostname' för din adress",
+"Fel vid initiering av kommunikationen med klienten",
+"Användare '%-.32s@%-.64s' är ej berättigad att använda databasen %-.64s",
+"Användare '%-.32s@%-.64s' är ej berättigad att logga in (Använder lösen: %s)",
+"Ingen databas i användning",
+"Okänt commando",
+"Kolumn '%-.64s' får inte vara NULL",
+"Okänd database '%-.64s'",
+"Tabellen '%-.64s' finns redan",
+"Okänd tabell '%-.64s'",
+"Kolumn: '%-.64s' i %s är inte unik",
+"Servern går nu ned",
+"Okänd kolumn '%-.64s' i %s",
+"'%-.64s' finns inte i GROUP BY",
+"Kan inte använda GROUP BY med '%-.64s'",
+"Kommandot har både sum functions och enkla funktioner",
+"Antalet kolumner motsvarar inte antalet värden",
+"Kolumn namn '%-.64s' är för långt",
+"Kolumn namn '%-64s finns flera gånger",
+"Nyckel namn '%-.64s' finns flera gånger",
+"Dubbel nyckel '%-.64s' för nyckel: %d",
+"Felaktigt kolumn typ för kolumn: '%-.64s'",
+"%s nära '%-.64s' på rad %d",
+"Frågan var tom",
+"Icke unikt tabell/alias: '%-.64s'",
+"Ogiltigt DEFAULT värde för '%-.64s'",
+"Flera PRIMARY KEY använda",
+"För många nycklar använda. Man får ha högst %d nycklar",
+"För många nyckel delar använda. Man får ha högst %d nyckeldelar",
+"För lång nyckel. Högsta tillåtna nyckellängd är %d",
+"Nyckel kolumn '%-.64s' finns inte",
+"En BLOB '%-.64s' kan inte vara nyckel med den använda tabellen typen",
+"För stor kolumnlängd angiven för '%-.64s' (max= %d). Använd en BLOB instället",
+"Det får finnas endast ett AUTO_INCREMENT fält och detta måste vara en nyckel",
+"%s: klar att ta emot klienter\n",
+"%s: Normal avslutning\n",
+"%s: Fick signal %d. Avslutar!\n",
+"%s: Avslutning klar\n",
+"%s: Stänger av tråd %ld användare: '%-.64s'\n",
+"Kan inte skapa IP socket",
+"Tabellen '%-.64s' har inget index som motsvarar det angivna i CREATE INDEX. Skapa om tabellen",
+"Fält separatorerna är inte emotsägande eller för långa. Kontrollera mot manualen",
+"Man kan inte använda fast radlängd med blobs. Använd 'fields terminated by'."
+"Textfilen '%' måste finnas i databas biblioteket eller vara läsbar för alla",
+"Filen '%-.64s' existerar redan",
+"Rader: %ld Bortagna: %ld Dubletter: %ld Varningar: %ld",
+"Rader: %ld Dubletter: %ld",
+"Felaktig delnyckel. Nyckeldelen är inte en sträng eller den angivna längden är längre än kolumnlängden",
+"Man kan inte radera alla fält med ALTER TABLE. Använd DROP TABLE istället",
+"Kan inte ta bort '%-.64s'. Kontrollera att fältet/nyckel finns",
+"Rader: %ld Dubletter: %ld Varningar: %ld",
+"INSERT table '%-.64s' får inte finnas i FROM tabell-listan",
+"Finns inget thread med id %lu",
+"Du är inte ägare till thread %lu",
+"Inga tabeller angivna",
+"För många alternativ till kolumn %s för SET",
+"Kan inte generera ett unikt filnamn %s.(1-999)\n",
+"Tabell '%-.64s' kan inte uppdateras emedan den är låst för läsning",
+"Tabell '%-.64s' är inte låst med LOCK TABLES",
+"BLOB fält '%-.64s' kan inte ha ett DEFAULT värde"
+"Felaktigt databas namn '%-.64s'",
+"Felaktigt tabell namn '%-.64s'",
+"Den angivna frågan skulle troligen ta mycket long tid! Kontrollar din WHERE och använd SET OPTION SQL_BIG_SELECTS=1 ifall du vill hantera stora joins",
+"Oidentifierat fel",
+"Okänd procedur: %s",
+"Felaktigt antal parametrar till procedur %s",
+"Felaktiga parametrar till procedur %s",
+"Okänd tabell '%-.64s' i '%-.64s'",
+"Fält '%-.64s' är redan använt",
+"Felaktig användning av SQL grupp function",
+"Tabell '%-.64s' har en extension som inte finns i denna version av MySQL",
+"Tabeller måste ha minst 1 kolumn",
+"Tabellen '%-.64s' är full",
+"Okänt karaktärset: '%-.64s'",
+"För många tabeller. MySQL can ha högst %d tabeller i en och samma join"
+"För många fält",
+"För stor total rad längd. Den högst tillåtna rad-längden, förutom BLOBs, är %d. Ändra några av dina fält till BLOB",
+"Tråd-stacken tog slut: Har använt %ld av %ld bytes. Använd 'mysqld -O thread_stack=#' ifall du behöver en större stack",
+"Felaktigt referens i OUTER JOIN. Kontrollera ON uttrycket",
+"Kolumn '%-.32s' är använd med UNIQUE eller INDEX men är inte definerad med NOT NULL",
+"Kan inte ladda funktionen '%-.64s'",
+"Kan inte initialisera funktionen '%-.64s'; '%-.80s'",
+"Man får inte ange sökväg för dynamiska bibliotek",
+"Funktionen '%-.64s' finns redan",
+"Kan inte öppna det dynamiska biblioteket '%-.64s' (Felkod: %d %s)",
+"Hittar inte funktionen '%-.64s' in det dynamiska biblioteket",
+"Funktionen '%-.64s' är inte definierad",
+"Denna dator '%-.64s' är blockerad pga många felaktig paket. Gör 'mysqladmin flush-hosts' för att ta bort alla blockeringarna",
+"Denna dator '%-.64s' har inte privileger att använda denna MySQL server",
+"Du använder MySQL som en anonym användare och som sådan får du inte ändra ditt lösenord",
+"För att ändra lösenord för andra måste du ha rättigheter att uppdatera mysql databasen",
+"Hittade inte användaren i 'user' tabellen",
+"Rader: %ld Uppdaterade: %ld Varningar: %ld",
+"Kan inte skapa en ny tråd (errno %d)"
+"Antalet kolumner motsvarar inte antalet värden på rad: %ld",
+"Kunde inte stänga och öppna tabell: '%-.64s',
+"Felaktig använding av NULL",
+"Fix fel '%-.64s' från REGEXP",
+"Man får ha både GROUP kolumner (MIN(),MAX(),COUNT()...) och fält i en fråga om man inte har en GROUP BY del",
+"Det finns inget privilegium definierat för användare '%-.32s' på '%-.64s'",
+"%-.16s ej tillåtet för '%-.32s@%-.64s' för tabell '%-.64s'",
+"%-.16s ej tillåtet för '%-.32s@%-.64s'\n för kolumn '%-.64s' i tabell '%-.64s'",
+"Felaktigt GRANT privilegium använt",
+"Felaktigt maskinnamn eller användarnamn använt med GRANT",
+"Det finns ingen tabell som heter '%-64s.%s'"
+"Det finns inget privilegium definierat för användare '%-.32s' på '%-.64s' för tabell '%-.64s'",
+"Du kan inte använda detta kommando med denna MySQL version",
+"Du har något fel i din syntax",
+"DELAYED INSERT tråden kunde inte låsa tabell '%-.64s'",
+"Det finns redan 'max_delayed_threads' trådar i använding",
+"Avbröt länken för tråd %ld till db: '%-.64s' användare: '%-.64s' (%s)",
+"Kommunkationspaketet är större än 'max_allowed_packet'",
+"Fick läsfel från klienten vid läsning från 'PIPE'",
+"Fick fatalt fel från 'fcntl()'",
+"Kommunikationspaketen kom i fel ordning",
+"Kunde inte packa up kommunikationspaketet",
+"Fick ett fel vid läsning från klienten",
+"Fick 'timeout' vid läsning från klienten",
+"Fick ett fel vid skrivning till klienten",
+"Fick 'timeout' vid skrivning till klienten",
+"Resultat strängen är längre än max_allowed_packet",
+"Den använda tabell typen kan inte hantera BLOB/TEXT kolumner",
+"Den använda tabell typen kan inte hantera AUTO_INCREMENT kolumner",
+"INSERT DELAYED kan inte användas med tabell '%-.64s', emedan den är låst med LOCK TABLES",
+"Felaktigt column namn '%-.100s'",
+"Den använda tabell typen kan inte indexera kolumn '%-.64s'",
+"Tabellerna i MERGE tabellen är inte identiskt definierade",
+"Kan inte skriva till tabell '%-.64s'; UNIQUE test",
+"Du har inte angett en nyckel längd för BLOB '%-.64s'",
+"Alla delar av en PRIMARY KEY måste vara NOT NULL; Om du vill ha en nyckel med NULL, använd UNIQUE istället",
+"Resultet bestod av mera än en rad",
+"Denna tabell typ kräver en PRIMARY KEY",
+"Denna version av MySQL är inte kompilerad med RAID",
+"Du använder 'säker uppdaterings mod' och försökte uppdatera en table utan en WHERE sats som använder sig av en nyckel",
+"Nyckel '%-.64s' finns inte in tabell '%-.64s'",
+"Kan inte öppna tabellen",
+"Tabellhanteraren för denna tabell kan inte göra check/repair",
+"Du får inte utföra detta kommando i en transaktion",
+"Fick fel %d vid COMMIT",
+"Fick fel %d vid ROLLBACK",
+"Fick fel %d vid FLUSH_LOGS",
+"Fick fel %d vid CHECKPOINT",
+"Avbröt länken för tråd %ld till db: '%-.64s' användare: '%-.32s' Host: '%-.64s' (%.-64s)",
+"Tabellhanteraren klarar inte en binär kopiering av tabellen",
+"Binärloggen stängdes medan vi gjorde FLUSH MASTER",
+"Failed rebuilding the index of dumped table '%-.64s'",
+"Fick en master: '%-.64s'",
+"Fick nätverksfel vid läsning från master",
+"Fick nätverksfel vid skrivning till master",
+"Hittar inte ett FULLTEXT index i kolumnlist",
diff --git a/sql/share/swedish/errmsg.sys b/sql/share/swedish/errmsg.sys
new file mode 100644
index 00000000000..d48cd88bf7b
--- /dev/null
+++ b/sql/share/swedish/errmsg.sys
Binary files differ
diff --git a/sql/share/swedish/errmsg.txt b/sql/share/swedish/errmsg.txt
new file mode 100644
index 00000000000..0181d0febd6
--- /dev/null
+++ b/sql/share/swedish/errmsg.txt
@@ -0,0 +1,195 @@
+/* Copyright Abandoned 1997 TCX DataKonsult AB & Monty Program KB & Detron HB
+ This file is public domain and comes with NO WARRANTY of any kind */
+
+"hashchk",
+"isamchk",
+"NO",
+"YES",
+"Kan inte skapa filen: '%-.64s' (Felkod: %d)",
+"Kan inte skapa tabellen: '%-.64s' (Felkod: %d)",
+"Kan inte skapa databasen '%-.64s'. (Felkod: %d)",
+"Databasen '%-.64s' existerar redan",
+"Kan inte radera databasen '%-.64s'. Databasen finns inte",
+"Fel vid radering av databasen (Kan inte radera '%-.64s'. Felkod: %d)",
+"Fel vid radering av databasen (Kan inte radera biblioteket '%-.64s'. Felkod: %d)",
+"Kan inte radera filen: '%-.64s' (Felkod: %d)",
+"Hittar inte posten i systemregistret",
+"Kan inte läsa filinformationen (stat) från '%-.64s' (Felkod: %d)",
+"Kan inte inte läsa aktivt bibliotek. (Felkod: %d)",
+"Kan inte låsa filen. (Felkod: %d)",
+"Kan inte använda: '%-.64s'. (Felkod: %d)",
+"Hittar inte filen: '%-.64s'. (Felkod: %d)",
+"Kan inte läsa från bibliotek '%-.64s'. (Felkod: %d)",
+"Kan inte byta till: '%-.64s'. (Felkod: %d)",
+"Posten har förändrats sedan den lästes i register '%-.64s'",
+"Disken är full (%s). Väntar tills det finns ledigt utrymme....",
+"Kan inte skriva, dubbel söknyckel i register '%-.64s'",
+"Fick fel vid stängning av '%-.64s' (Felkod: %d)",
+"Fick fel vid läsning av '%-.64s' (Felkod %d)",
+"Kan inte byta namn från '%-.64s' till '%-.64s' (Felkod: %d)",
+"Fick fel vid skrivning till '%-.64s' (Felkod %d)",
+"'%-.64s' är låst mot användning",
+"Sorteringen avbruten",
+"Formulär '%-.64s' finns inte i '%-.64s'",
+"Fick felkod %d från databashanteraren",
+"Registrets databas har inte denna facilitet",
+"Hittar inte posten",
+"Felaktig fil: '%-.64s'",
+"Fatalt fel vid hantering av register '%-.64s'. Kör en reparation",
+"Gammal nyckelfil '%-.64s'; Reparera registret",
+"'%-.64s' är skyddad mot förändring",
+"Oväntat slut på minnet, starta om programmet och försök på nytt (Behövde %d bytes)",
+"Sorteringsbufferten räcker inte till. Kontrollera startparametrarna",
+"Oväntat filslut vid läsning från '%-.64s' (Felkod: %d)",
+"För många anslutningar",
+"Fick slut på minnet. Kontrollera ifall mysqld eller någon annan process använder allt tillgängligt minne. Ifall inte, försök använda 'ulimit' eller allokera mera swap",
+"Kan inte hitta 'hostname' för din adress",
+"Fel vid initiering av kommunikationen med klienten",
+"Användare '%-.32s@%-.64s' är ej berättigad att använda databasen %-.64s",
+"Användare '%-.32s@%-.64s' är ej berättigad att logga in (Använder lösen: %s)",
+"Ingen databas i användning",
+"Okänt commando",
+"Kolumn '%-.64s' får inte vara NULL",
+"Okänd database '%-.64s'",
+"Tabellen '%-.64s' finns redan",
+"Okänd tabell '%-.64s'",
+"Kolumn: '%-.64s' i %s är inte unik",
+"Servern går nu ned",
+"Okänd kolumn '%-.64s' i %s",
+"'%-.64s' finns inte i GROUP BY",
+"Kan inte använda GROUP BY med '%-.64s'",
+"Kommandot har både sum functions och enkla funktioner",
+"Antalet kolumner motsvarar inte antalet värden",
+"Kolumn namn '%-.64s' är för långt",
+"Kolumn namn '%-64s finns flera gånger",
+"Nyckel namn '%-.64s' finns flera gånger",
+"Dubbel nyckel '%-.64s' för nyckel: %d",
+"Felaktigt kolumn typ för kolumn: '%-.64s'",
+"%s nära '%-.64s' på rad %d",
+"Frågan var tom",
+"Icke unikt tabell/alias: '%-.64s'",
+"Ogiltigt DEFAULT värde för '%-.64s'",
+"Flera PRIMARY KEY använda",
+"För många nycklar använda. Man får ha högst %d nycklar",
+"För många nyckel delar använda. Man får ha högst %d nyckeldelar",
+"För lång nyckel. Högsta tillåtna nyckellängd är %d",
+"Nyckel kolumn '%-.64s' finns inte",
+"En BLOB '%-.64s' kan inte vara nyckel med den använda tabellen typen",
+"För stor kolumnlängd angiven för '%-.64s' (max= %d). Använd en BLOB instället",
+"Det får finnas endast ett AUTO_INCREMENT fält och detta måste vara en nyckel",
+"%s: klar att ta emot klienter\n",
+"%s: Normal avslutning\n",
+"%s: Fick signal %d. Avslutar!\n",
+"%s: Avslutning klar\n",
+"%s: Stänger av tråd %ld användare: '%-.64s'\n",
+"Kan inte skapa IP socket",
+"Tabellen '%-.64s' har inget index som motsvarar det angivna i CREATE INDEX. Skapa om tabellen",
+"Fält separatorerna är inte emotsägande eller för långa. Kontrollera mot manualen",
+"Man kan inte använda fast radlängd med blobs. Använd 'fields terminated by'."
+"Textfilen '%' måste finnas i databas biblioteket eller vara läsbar för alla",
+"Filen '%-.64s' existerar redan",
+"Rader: %ld Bortagna: %ld Dubletter: %ld Varningar: %ld",
+"Rader: %ld Dubletter: %ld",
+"Felaktig delnyckel. Nyckeldelen är inte en sträng eller den angivna längden är längre än kolumnlängden",
+"Man kan inte radera alla fält med ALTER TABLE. Använd DROP TABLE istället",
+"Kan inte ta bort '%-.64s'. Kontrollera att fältet/nyckel finns",
+"Rader: %ld Dubletter: %ld Varningar: %ld",
+"INSERT table '%-.64s' får inte finnas i FROM tabell-listan",
+"Finns inget thread med id %lu",
+"Du är inte ägare till thread %lu",
+"Inga tabeller angivna",
+"För många alternativ till kolumn %s för SET",
+"Kan inte generera ett unikt filnamn %s.(1-999)\n",
+"Tabell '%-.64s' kan inte uppdateras emedan den är låst för läsning",
+"Tabell '%-.64s' är inte låst med LOCK TABLES",
+"BLOB fält '%-.64s' kan inte ha ett DEFAULT värde"
+"Felaktigt databas namn '%-.64s'",
+"Felaktigt tabell namn '%-.64s'",
+"Den angivna frågan skulle troligen ta mycket long tid! Kontrollar din WHERE och använd SET OPTION SQL_BIG_SELECTS=1 ifall du vill hantera stora joins",
+"Oidentifierat fel",
+"Okänd procedur: %s",
+"Felaktigt antal parametrar till procedur %s",
+"Felaktiga parametrar till procedur %s",
+"Okänd tabell '%-.64s' i '%-.64s'",
+"Fält '%-.64s' är redan använt",
+"Felaktig användning av SQL grupp function",
+"Tabell '%-.64s' har en extension som inte finns i denna version av MySQL",
+"Tabeller måste ha minst 1 kolumn",
+"Tabellen '%-.64s' är full",
+"Okänt karaktärset: '%-.64s'",
+"För många tabeller. MySQL can ha högst %d tabeller i en och samma join"
+"För många fält",
+"För stor total rad längd. Den högst tillåtna rad-längden, förutom BLOBs, är %d. Ändra några av dina fält till BLOB",
+"Tråd-stacken tog slut: Har använt %ld av %ld bytes. Använd 'mysqld -O thread_stack=#' ifall du behöver en större stack",
+"Felaktigt referens i OUTER JOIN. Kontrollera ON uttrycket",
+"Kolumn '%-.32s' är använd med UNIQUE eller INDEX men är inte definerad med NOT NULL",
+"Kan inte ladda funktionen '%-.64s'",
+"Kan inte initialisera funktionen '%-.64s'; '%-.80s'",
+"Man får inte ange sökväg för dynamiska bibliotek",
+"Funktionen '%-.64s' finns redan",
+"Kan inte öppna det dynamiska biblioteket '%-.64s' (Felkod: %d %s)",
+"Hittar inte funktionen '%-.64s' in det dynamiska biblioteket",
+"Funktionen '%-.64s' är inte definierad",
+"Denna dator '%-.64s' är blockerad pga många felaktig paket. Gör 'mysqladmin flush-hosts' för att ta bort alla blockeringarna",
+"Denna dator '%-.64s' har inte privileger att använda denna MySQL server",
+"Du använder MySQL som en anonym användare och som sådan får du inte ändra ditt lösenord",
+"För att ändra lösenord för andra måste du ha rättigheter att uppdatera mysql databasen",
+"Hittade inte användaren i 'user' tabellen",
+"Rader: %ld Uppdaterade: %ld Varningar: %ld",
+"Kan inte skapa en ny tråd (errno %d)"
+"Antalet kolumner motsvarar inte antalet värden på rad: %ld",
+"Kunde inte stänga och öppna tabell: '%-.64s',
+"Felaktig använding av NULL",
+"Fix fel '%-.64s' från REGEXP",
+"Man får ha både GROUP kolumner (MIN(),MAX(),COUNT()...) och fält i en fråga om man inte har en GROUP BY del",
+"Det finns inget privilegium definierat för användare '%-.32s' på '%-.64s'",
+"%-.16s ej tillåtet för '%-.32s@%-.64s' för tabell '%-.64s'",
+"%-.16s ej tillåtet för '%-.32s@%-.64s'\n för kolumn '%-.64s' i tabell '%-.64s'",
+"Felaktigt GRANT privilegium använt",
+"Felaktigt maskinnamn eller användarnamn använt med GRANT",
+"Det finns ingen tabell som heter '%-64s.%s'"
+"Det finns inget privilegium definierat för användare '%-.32s' på '%-.64s' för tabell '%-.64s'",
+"Du kan inte använda detta kommando med denna MySQL version",
+"Du har något fel i din syntax",
+"DELAYED INSERT tråden kunde inte låsa tabell '%-.64s'",
+"Det finns redan 'max_delayed_threads' trådar i använding",
+"Avbröt länken för tråd %ld till db: '%-.64s' användare: '%-.64s' (%s)",
+"Kommunkationspaketet är större än 'max_allowed_packet'",
+"Fick läsfel från klienten vid läsning från 'PIPE'",
+"Fick fatalt fel från 'fcntl()'",
+"Kommunikationspaketen kom i fel ordning",
+"Kunde inte packa up kommunikationspaketet",
+"Fick ett fel vid läsning från klienten",
+"Fick 'timeout' vid läsning från klienten",
+"Fick ett fel vid skrivning till klienten",
+"Fick 'timeout' vid skrivning till klienten",
+"Resultat strängen är längre än max_allowed_packet",
+"Den använda tabell typen kan inte hantera BLOB/TEXT kolumner",
+"Den använda tabell typen kan inte hantera AUTO_INCREMENT kolumner",
+"INSERT DELAYED kan inte användas med tabell '%-.64s', emedan den är låst med LOCK TABLES",
+"Felaktigt column namn '%-.100s'",
+"Den använda tabell typen kan inte indexera kolumn '%-.64s'",
+"Tabellerna i MERGE tabellen är inte identiskt definierade",
+"Kan inte skriva till tabell '%-.64s'; UNIQUE test",
+"Du har inte angett en nyckel längd för BLOB '%-.64s'",
+"Alla delar av en PRIMARY KEY måste vara NOT NULL; Om du vill ha en nyckel med NULL, använd UNIQUE istället",
+"Resultet bestod av mera än en rad",
+"Denna tabell typ kräver en PRIMARY KEY",
+"Denna version av MySQL är inte kompilerad med RAID",
+"Du använder 'säker uppdaterings mod' och försökte uppdatera en table utan en WHERE sats som använder sig av en nyckel",
+"Nyckel '%-.64s' finns inte in tabell '%-.64s'",
+"Kan inte öppna tabellen",
+"Tabellhanteraren för denna tabell kan inte göra check/repair",
+"Du får inte utföra detta kommando i en transaktion",
+"Fick fel %d vid COMMIT",
+"Fick fel %d vid ROLLBACK",
+"Fick fel %d vid FLUSH_LOGS",
+"Fick fel %d vid CHECKPOINT",
+"Avbröt länken för tråd %ld till db: '%-.64s' användare: '%-.32s' Host: '%-.64s' (%.-64s)",
+"Tabellhanteraren klarar inte en binär kopiering av tabellen",
+"Binärloggen stängdes medan vi gjorde FLUSH MASTER",
+"Failed rebuilding the index of dumped table '%-.64s'",
+"Fick en master: '%-.64s'",
+"Fick nätverksfel vid läsning från master",
+"Fick nätverksfel vid skrivning till master",
+"Hittar inte ett FULLTEXT index i kolumnlist",
diff --git a/sql/slave.cc b/sql/slave.cc
new file mode 100644
index 00000000000..fb28922c74f
--- /dev/null
+++ b/sql/slave.cc
@@ -0,0 +1,945 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 <mysql.h>
+#include "mini_client.h"
+#include <thr_alarm.h>
+#include <my_dir.h>
+
+pthread_handler_decl(handle_slave,arg);
+extern bool volatile abort_loop, abort_slave;
+
+// the master variables are defaults read from my.cnf or command line
+extern uint master_port, master_connect_retry;
+extern my_string master_user, master_password, master_host,
+ master_info_file;
+
+extern I_List<i_string> replicate_do_db, replicate_ignore_db;
+extern I_List<THD> threads;
+bool slave_running = 0;
+pthread_t slave_real_id;
+MASTER_INFO glob_mi;
+
+
+extern bool opt_log_slave_updates ;
+
+static inline bool slave_killed(THD* thd);
+static int init_slave_thread(THD* thd);
+static int init_master_info(MASTER_INFO* mi);
+static void safe_connect(THD* thd, MYSQL* mysql, MASTER_INFO* mi);
+static void 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 create_table_from_dump(THD* thd, NET* net, const char* db,
+ const char* table_name);
+
+static inline bool slave_killed(THD* thd)
+{
+ return abort_slave || abort_loop || thd->killed;
+}
+
+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())
+ return 1; // ok to replicate if the user puts no constraints
+
+ if(!db)
+ return 0; // if the user has specified restrictions on which databases to replicate
+ // and db was not selected, do not replicate
+
+ if(!do_list.is_empty()) // if the do's are not empty
+ {
+ I_List_iterator<i_string> it(do_list);
+ i_string* tmp;
+
+ while((tmp=it++))
+ {
+ if(!strcmp(tmp->ptr, db))
+ return 1; // match
+ }
+ return 0;
+ }
+ else // there are some elements in the don't, otherwise we cannot get here
+ {
+ I_List_iterator<i_string> it(ignore_list);
+ i_string* tmp;
+
+ while((tmp=it++))
+ {
+ if(!strcmp(tmp->ptr, db))
+ return 0; // match
+ }
+
+ return 1;
+
+ }
+
+ // impossible
+ return 0;
+}
+
+static void init_strvar_from_file(char* var, int max_size, FILE* f,
+ char* default_val)
+{
+
+ if(fgets(var, max_size, f))
+ {
+ *(strend(var)-1) = 0;
+ }
+ else if(default_val)
+ strmake(var, default_val, max_size);
+}
+
+static void init_intvar_from_file(int* var, FILE* f,
+ int default_val)
+{
+ char buf[32];
+
+ if(fgets(buf, sizeof(buf), f))
+ {
+ *var = atoi(buf);
+ }
+ else if(default_val)
+ *var = default_val;
+}
+
+
+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
+ TABLE_LIST tables;
+ int error = 0;
+
+ if(packet_len == packet_error)
+ {
+ send_error(&thd->net, ER_MASTER_NET_READ);
+ return 1;
+ }
+ if(net->read_pos[0] == 255) // error from master
+ {
+ net->read_pos[packet_len] = 0;
+ net_printf(&thd->net, ER_MASTER, net->read_pos + 3);
+ return 1;
+ }
+ thd->command = COM_TABLE_DUMP;
+ thd->query = sql_alloc(packet_len + 1);
+ if(!thd->query)
+ {
+ sql_print_error("create_table_from_dump: out of memory");
+ net_printf(&thd->net, ER_GET_ERRNO, "Out of memory");
+ return 1;
+ }
+ memcpy(thd->query, net->read_pos, packet_len);
+ thd->query[packet_len] = 0;
+ thd->current_tablenr = 0;
+ thd->query_error = 0;
+ thd->net.no_send_ok = 1;
+ thd->proc_info = "Creating table from master dump";
+ char* save_db = thd->db;
+ thd->db = thd->last_nx_db; // in case we are creating in a different
+ // database
+ mysql_parse(thd, thd->query, packet_len); // run create table
+ thd->db = save_db; // leave things the way the were before
+
+ if(thd->query_error)
+ {
+ close_thread_tables(thd); // mysql_parse takes care of the error send
+ return 1;
+ }
+
+ bzero((char*) &tables,sizeof(tables));
+ tables.db = (char*)db;
+ tables.name = tables.real_name = (char*)table_name;
+ tables.lock_type = TL_WRITE;
+ thd->proc_info = "Opening master dump table";
+ if(open_tables(thd, &tables) || !tables.table)
+ {
+ // open tables will send the error
+ sql_print_error("create_table_from_dump: could not open created table");
+ close_thread_tables(thd);
+ return 1;
+ }
+
+ handler *file = tables.table->file;
+ thd->proc_info = "Reading master dump table data";
+ if(file->net_read_dump(net))
+ {
+ net_printf(&thd->net, ER_MASTER_NET_READ);
+ sql_print_error("create_table_from_dump::failed in\
+ handler::net_read_dump()");
+ close_thread_tables(thd);
+ return 1;
+ }
+
+ HA_CHECK_OPT check_opt;
+ check_opt.init();
+ check_opt.quick = 1;
+ thd->proc_info = "rebuilding the index on master dump table";
+ Vio* save_vio = thd->net.vio;
+ thd->net.vio = 0; // we do not want repair() to spam us with messages
+ // just send them to the error log, and report the failure in case of
+ // problems
+ if(file->repair(thd,&check_opt ))
+ {
+ net_printf(&thd->net, ER_INDEX_REBUILD,tables.table->real_name );
+ error = 1;
+ }
+ thd->net.vio = save_vio;
+ close_thread_tables(thd);
+
+ thd->net.no_send_ok = 0;
+ return error;
+}
+
+int fetch_nx_table(THD* thd, MASTER_INFO* mi)
+{
+ 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;
+ goto err;
+ }
+
+ safe_connect(thd, mysql, mi);
+ if(slave_killed(thd))
+ goto err;
+
+ if(request_table_dump(mysql, thd->last_nx_db, thd->last_nx_table))
+ {
+ nx_errno = ER_GET_ERRNO;
+ sql_print_error("fetch_nx_table: failed on table dump request ");
+ goto err;
+ }
+
+ if(create_table_from_dump(thd, &mysql->net, thd->last_nx_db,
+ thd->last_nx_table))
+ {
+ // create_table_from_dump will have sent the error alread
+ sql_print_error("fetch_nx_table: failed on create table ");
+ goto err;
+ }
+
+ error = 0;
+ err:
+ if(mysql)
+ mc_mysql_close(mysql);
+ if(nx_errno && thd->net.vio)
+ send_error(&thd->net, nx_errno, "Error in fetch_nx_table");
+
+ return error;
+}
+
+static int init_master_info(MASTER_INFO* mi)
+{
+ FILE* file;
+ MY_STAT stat_area;
+ char fname[FN_REFLEN];
+ fn_format(fname, master_info_file, mysql_data_home, "", 4+16+32);
+
+ if(!mi->inited)
+ pthread_mutex_init(&mi->lock, NULL);
+
+ // we need a mutex while we are changing master info parameters to
+ // keep other threads from reading bogus info
+
+ pthread_mutex_lock(&mi->lock);
+
+
+ if(!my_stat(fname, &stat_area, MYF(0))) // we do not want any messages
+ // if the file does not exist
+ {
+ file = my_fopen(fname, O_CREAT|O_RDWR, MYF(MY_WME));
+ if(!file)
+ return 1;
+ mi->log_file_name[0] = 0;
+ mi->pos = 0;
+ mi->file = file;
+
+ if(master_host)
+ strmake(mi->host, master_host, sizeof(mi->host));
+ if(master_user)
+ strmake(mi->user, master_user, sizeof(mi->user));
+ if(master_password)
+ strmake(mi->password, master_password, sizeof(mi->password));
+ mi->port = master_port;
+ mi->connect_retry = master_connect_retry;
+
+ if(flush_master_info(mi))
+ return 1;
+ }
+ else
+ {
+ file = my_fopen(fname, O_RDWR, MYF(MY_WME));
+ if(!file)
+ return 1;
+
+ if(!fgets(mi->log_file_name, sizeof(mi->log_file_name), file))
+ {
+ sql_print_error("Error reading log file name from master info file ");
+ return 1;
+ }
+
+ *(strend(mi->log_file_name) - 1) = 0; // kill \n
+ char buf[FN_REFLEN];
+ if(!fgets(buf, sizeof(buf), file))
+ {
+ sql_print_error("Error reading log file position from master info file");
+ return 1;
+ }
+
+ mi->pos = atoi(buf);
+ mi->file = file;
+ init_strvar_from_file(mi->host, sizeof(mi->host), file, master_host);
+ init_strvar_from_file(mi->user, sizeof(mi->user), file, master_user);
+ init_strvar_from_file(mi->password, sizeof(mi->password), file,
+ master_password);
+
+ init_intvar_from_file((int*)&mi->port, file, master_port);
+ init_intvar_from_file((int*)&mi->connect_retry, file,
+ master_connect_retry);
+
+ }
+
+ mi->inited = 1;
+ pthread_mutex_unlock(&mi->lock);
+
+ return 0;
+}
+
+int show_master_info(THD* thd)
+{
+ DBUG_ENTER("show_master_info");
+ List<Item> field_list;
+ field_list.push_back(new Item_empty_string("Master_Host",
+ sizeof(glob_mi.host)));
+ field_list.push_back(new Item_empty_string("Master_User",
+ sizeof(glob_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",
+ 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("Replicate_do_db", 20));
+ field_list.push_back(new Item_empty_string("Replicate_ignore_db", 20));
+ 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, (longlong)glob_mi.pos);
+ pthread_mutex_unlock(&glob_mi.lock);
+ pthread_mutex_lock(&LOCK_slave);
+ net_store_data(packet, slave_running ? "Yes":"No");
+ pthread_mutex_unlock(&LOCK_slave);
+ net_store_data(packet, &replicate_do_db);
+ net_store_data(packet, &replicate_ignore_db);
+
+ if(my_net_write(&thd->net, (char*)thd->packet.ptr(), packet->length()))
+ DBUG_RETURN(-1);
+
+ send_eof(&thd->net);
+ DBUG_RETURN(0);
+}
+
+int flush_master_info(MASTER_INFO* mi)
+{
+ FILE* file = mi->file;
+ if(my_fseek(file, 0L, MY_SEEK_SET, MYF(MY_WME)) == MY_FILEPOS_ERROR ||
+ fprintf(file, "%s\n%ld\n%s\n%s\n%s\n%d\n%d\n",
+ mi->log_file_name, mi->pos, mi->host, mi->user, mi->password,
+ mi->port, mi->connect_retry) < 0 ||
+ fflush(file))
+ {
+ sql_print_error("Write error flushing master_info: %d", errno);
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static int init_slave_thread(THD* thd)
+{
+ DBUG_ENTER("init_slave_thread");
+ thd->system_thread = thd->bootstrap = 1;
+ thd->client_capabilities = 0;
+ my_net_init(&thd->net, 0);
+ thd->max_packet_length=thd->net.max_packet;
+ thd->master_access= ~0;
+ thd->priv_user = 0;
+ thd->options = (((opt_log_slave_updates) ? OPTION_BIN_LOG:0)
+ | OPTION_AUTO_COMMIT | OPTION_AUTO_IS_NULL) ;
+ thd->system_thread = 1;
+ thd->client_capabilities = CLIENT_LOCAL_FILES;
+ slave_real_id=thd->real_id=pthread_self();
+ 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->alloc) ||
+ 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();
+#ifndef __WIN__
+ sigset_t set;
+ VOID(sigemptyset(&set)); // Get mask in use
+ VOID(pthread_sigmask(SIG_UNBLOCK,&set,&thd->block_signals));
+#endif
+
+ thd->alloc.free=thd->alloc.used=0;
+ if (thd->max_join_size == (ulong) ~0L)
+ thd->options |= OPTION_BIG_SELECTS;
+
+ 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)
+{
+ thr_alarm_t alarmed;
+ thr_alarm_init(&alarmed);
+ time_t start_time= time((time_t*) 0);
+ time_t end_time= start_time+sec;
+ ALARM alarm_buff;
+
+ while (start_time < end_time)
+ {
+ int nap_time = (int) (end_time - start_time);
+ thr_alarm(&alarmed, 2 * nap_time,&alarm_buff); // the only reason we are asking for alarm is so that
+ // we will be woken up in case of murder, so if we do not get killed, set the alarm
+ // so it goes off after we wake up naturally
+ sleep(nap_time);
+ if (thr_alarm_in_use(&alarmed)) // if we wake up before the alarm goes off, hit the button
+ thr_end_alarm(&alarmed); // so it will not wake up the wife and kids :-)
+
+ if (slave_killed(thd))
+ return 1;
+ start_time=time((time_t*) 0);
+ }
+ return 0;
+}
+
+
+static int request_dump(MYSQL* mysql, MASTER_INFO* mi)
+{
+ char buf[FN_REFLEN + 6];
+ int len;
+ int binlog_flags = 0; // for now
+ char* logname = mi->log_file_name;
+ int4store(buf, mi->pos);
+ int2store(buf + 4, binlog_flags);
+ len = strlen(logname);
+ memcpy(buf + 6, logname,len);
+ if(mc_simple_command(mysql, COM_BINLOG_DUMP, buf, len + 6, 1))
+ // something went wrong, so we will just reconnect and retry later
+ // in the future, we should do a better error analysis, but for
+ // now we just fill up the error log :-)
+ {
+ sql_print_error("Error on COM_BINLOG_DUMP: %s, will retry in %d secs",
+ mc_mysql_error(mysql), master_connect_retry);
+ return 1;
+ }
+
+ return 0;
+}
+
+static int request_table_dump(MYSQL* mysql, char* db, char* table)
+{
+ char buf[1024];
+ char * p = buf;
+ uint table_len = strlen(table);
+ uint db_len = strlen(db);
+ if(table_len + db_len > sizeof(buf) - 2)
+ {
+ sql_print_error("request_table_dump: Buffer overrun");
+ return 1;
+ }
+
+ *p++ = db_len;
+ memcpy(p, db, db_len);
+ p += db_len;
+ *p++ = table_len;
+ memcpy(p, table, table_len);
+
+ if(mc_simple_command(mysql, COM_TABLE_DUMP, buf, p - buf + table_len, 1))
+ {
+ sql_print_error("request_table_dump: Error sending the table dump \
+command");
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static uint read_event(MYSQL* mysql, MASTER_INFO *mi)
+{
+ uint len = packet_error;
+ NET* net = &mysql->net;
+ int read_errno = EINTR; // for convinience lets think we start by
+ // being in the interrupted state :-)
+ // my_real_read() will time us out
+ // we check if we were told to die, and if not, try reading again
+ while (!abort_loop && !abort_slave && len == packet_error && read_errno == EINTR )
+ {
+ len = mc_net_safe_read(mysql);
+ read_errno = errno;
+ }
+ if(abort_loop || abort_slave)
+ return packet_error;
+ if (len == packet_error || (int) len < 1)
+ {
+ sql_print_error("Error reading packet from server: %s (%d)",
+ mc_mysql_error(mysql), read_errno);
+ return packet_error;
+ }
+
+ if(len == 1)
+ {
+ sql_print_error("Received 0 length packet from server, looks like master shutdown: %s (%d)",
+ mc_mysql_error(mysql), read_errno);
+ return packet_error;
+ }
+
+ DBUG_PRINT("info",( "len=%u, net->read_pos[4] = %d\n",
+ len, net->read_pos[4]));
+
+ return len - 1;
+}
+
+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);
+ if(ev)
+ {
+ switch(ev->get_type_code())
+ {
+ case QUERY_EVENT:
+ {
+ Query_log_event* qev = (Query_log_event*)ev;
+ int q_len = qev->q_len;
+ init_sql_alloc(&thd->alloc, 8192);
+ thd->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;
+ for(;;)
+ {
+ thd->query_error = 0; // clear error
+ thd->last_nx_table = thd->last_nx_db = 0;
+ thd->net.last_errno = 0;
+ thd->net.last_error[0] = 0;
+ mysql_parse(thd, thd->query, q_len); // try query
+ if(!thd->query_error || slave_killed(thd)) // break if ok
+ break;
+ // if not ok
+ if(thd->last_nx_table && thd->last_nx_db)
+ {
+ // for now, let's just fail if the table is not
+ // there, and not try to be a smart alec...
+
+ // if table was not there
+ //if(fetch_nx_table(thd,&glob_mi))
+ // try to to fetch from master
+ break; // if we can't, just break
+ }
+ else
+ break; // if failed for some other reason, bail out
+
+ // if fetched the table from master successfully
+ // we need to restore query info in thd because
+ // fetch_nx_table executes create table
+ thd->query = (char*)qev->query;
+ thd->set_time((time_t)qev->when);
+ thd->current_tablenr = 0;
+ }
+ }
+ thd->db = 0;// prevent db from being freed
+ thd->query = 0; // just to be sure
+ close_thread_tables(thd);
+ free_root(&thd->alloc);
+ if(thd->query_error)
+ {
+ sql_print_error("Slave: error running query '%s' ",
+ qev->query);
+ return 1;
+ }
+ delete ev;
+
+ 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 LOAD_EVENT:
+ {
+ Load_log_event* lev = (Load_log_event*)ev;
+ init_sql_alloc(&thd->alloc, 8192);
+ thd->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));
+
+ 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;
+
+ 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;
+
+ if (open_tables(thd, &tables))
+ {
+ sql_print_error("Slave: error opening table %s ",
+ tables.name);
+ delete ev;
+ return 1;
+ }
+
+ List<Item> fields;
+ lev->set_fields(fields);
+ 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 get confused
+ // about the packet sequence
+ if(mysql_load(thd, &ex, &tables, fields, handle_dup, 1,
+ TL_WRITE))
+ thd->query_error = 1;
+ 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 :-)
+ {
+ (void)my_net_write(net, "\xfb/dev/null", 10);
+ (void)net_flush(net);
+ (void)my_net_read(net); // discard response
+ send_ok(net); // the master expects it
+ }
+
+ 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;
+ return 1;
+ }
+ delete ev;
+
+ 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);
+ break;
+
+ case STOP_EVENT:
+ mi->inc_pos(event_len);
+ flush_master_info(mi);
+ break;
+ case ROTATE_EVENT:
+ {
+ Rotate_log_event* rev = (Rotate_log_event*)ev;
+ int ident_len = rev->ident_len;
+ memcpy(mi->log_file_name, rev->new_log_ident,ident_len );
+ mi->log_file_name[ident_len] = 0;
+ mi->pos = 0;
+ 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_pos(event_len);
+ flush_master_info(mi);
+ break;
+ }
+ }
+
+ }
+ else
+ {
+ sql_print_error("Could not parse log event entry, check the master for binlog corruption\
+ 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)))
+{
+ THD *thd;; // needs to be first for thread_stack
+ MYSQL *mysql = NULL ;
+
+ pthread_mutex_lock(&LOCK_slave);
+ if(slave_running)
+ {
+ pthread_mutex_unlock(&LOCK_slave);
+ return 0; // safety just in case
+ }
+ slave_running = 1;
+ abort_slave = 0;
+ pthread_mutex_unlock(&LOCK_slave);
+
+ int error = 1;
+
+ my_thread_init(); // needs to be up here, otherwise we get a coredump
+ // trying to use DBUG_ stuff
+ thd = new THD; // note that contructor of THD uses DBUG_ !
+ DBUG_ENTER("handle_slave");
+
+ pthread_detach_this_thread();
+ if(init_slave_thread(thd) || init_master_info(&glob_mi))
+ goto err;
+ thd->thread_stack = (char*)&thd; // remember where our stack is
+
+ threads.append(thd);
+
+ DBUG_PRINT("info",("master info: log_file_name=%s, position=%d",
+ glob_mi.log_file_name, glob_mi.pos));
+
+ mysql = mc_mysql_init(NULL);
+ if(!mysql)
+ {
+ sql_print_error("Slave thread: error in mc_mysql_init()");
+ goto err;
+ }
+
+ thd->proc_info = "connecting to master";
+ safe_connect(thd, mysql, &glob_mi);
+
+ while(!slave_killed(thd))
+ {
+ thd->proc_info = "requesting binlog dump";
+ if(request_dump(mysql, &glob_mi))
+ {
+ sql_print_error("Failed on request_dump()");
+ if(slave_killed(thd))
+ goto err;
+
+ thd->proc_info = "waiting to reconnect after a failed dump request";
+ safe_sleep(thd, glob_mi.connect_retry);
+ if(slave_killed(thd))
+ goto err;
+
+ thd->proc_info = "reconnecting after a failed dump request";
+
+ safe_reconnect(thd, mysql, &glob_mi);
+ if(slave_killed(thd))
+ goto err;
+
+ continue;
+ }
+
+
+ while(!slave_killed(thd))
+ {
+ bool reset = 0;
+ thd->proc_info = "reading master update";
+ uint event_len = read_event(mysql, &glob_mi);
+ if(slave_killed(thd))
+ goto err;
+
+ if (event_len == packet_error)
+ {
+ thd->proc_info = "waiting to reconnect after a failed read";
+ safe_sleep(thd, glob_mi.connect_retry);
+ if(slave_killed(thd))
+ goto err;
+ thd->proc_info = "reconnecting after a failed read";
+ safe_reconnect(thd, mysql, &glob_mi);
+ if(slave_killed(thd))
+ goto err;
+ reset = 1;
+ }
+
+ if(reset)
+ break;
+
+ 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");
+ 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
+ }
+
+ }
+ }
+
+ error = 0;
+ err:
+ 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;
+ pthread_cond_broadcast(&COND_slave_stopped); // tell the world we are done
+ pthread_mutex_unlock(&LOCK_slave);
+ delete thd;
+ my_thread_end();
+ pthread_exit(0);
+ DBUG_RETURN(0); // Can't return anything here
+}
+
+static void safe_connect(THD* thd, MYSQL* mysql, MASTER_INFO* mi)
+ // will try to connect until successful
+{
+ while(!slave_killed(thd) &&
+ !mc_mysql_connect(mysql, mi->host, mi->user, mi->password, 0,
+ mi->port, 0, 0))
+ {
+ sql_print_error(
+ "Slave thread: error connecting to slave:%s, retry in %d sec",
+ mc_mysql_error(mysql), mi->connect_retry);
+ safe_sleep(thd, mi->connect_retry);
+ }
+
+}
+
+// will try to connect until successful
+
+static void safe_reconnect(THD* thd, MYSQL* mysql, MASTER_INFO* mi)
+{
+ while(!slave_killed(thd) && mc_mysql_reconnect(mysql))
+ {
+ sql_print_error(
+ "Slave thread: error connecting to slave:%s, retry in %d sec",
+ mc_mysql_error(mysql), mi->connect_retry);
+ safe_sleep(thd, mi->connect_retry);
+ }
+
+}
+
+#ifdef __GNUC__
+template class I_List_iterator<i_string>;
+#endif
+
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
new file mode 100644
index 00000000000..d2f8680aee3
--- /dev/null
+++ b/sql/sql_acl.cc
@@ -0,0 +1,2547 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 privileges are saved in the following tables:
+ mysql/user ; super user who are allowed to do almoust anything
+ mysql/host ; host priviliges. This is used if host is empty in mysql/db.
+ mysql/db ; database privileges / user
+
+ data in tables is sorted according to how many not-wild-cards there is
+ in the relevant fields. Empty strings comes last.
+*/
+
+#include "mysql_priv.h"
+#include "sql_acl.h"
+#include "hash_filo.h"
+#include <m_ctype.h>
+#include <stdarg.h>
+
+/*
+ ACL_HOST is used if no host is specified
+ */
+
+struct acl_host_and_ip
+{
+ char *hostname;
+ long ip,ip_mask; // Used with masked ip:s
+};
+
+class ACL_ACCESS {
+public:
+ ulong sort;
+ uint access;
+};
+
+class ACL_HOST :public ACL_ACCESS
+{
+public:
+ acl_host_and_ip host;
+ char *db;
+};
+
+class ACL_USER :public ACL_ACCESS
+{
+public:
+ acl_host_and_ip host;
+ uint hostname_length;
+ char *user,*password;
+ ulong salt[2];
+};
+
+class ACL_DB :public ACL_ACCESS
+{
+public:
+ acl_host_and_ip host;
+ char *user,*db;
+};
+
+class acl_entry :public hash_filo_element
+{
+public:
+ uint access;
+ uint16 length;
+ char key[1]; // Key will be stored here
+};
+
+static byte* acl_entry_get_key(acl_entry *entry,uint *length,
+ my_bool not_used __attribute__((unused)))
+{
+ *length=(uint) entry->length;
+ return (byte*) entry->key;
+}
+
+#define ACL_KEY_LENGTH (sizeof(long)+NAME_LEN+17)
+
+static DYNAMIC_ARRAY acl_hosts,acl_users,acl_dbs;
+static MEM_ROOT mem, memex;
+static bool initialized=0;
+static bool allow_all_hosts=1;
+static HASH acl_check_hosts, hash_tables;
+static DYNAMIC_ARRAY acl_wild_hosts;
+static hash_filo *acl_cache;
+static uint grant_version=0;
+static uint get_access(TABLE *form,uint fieldnr);
+static int acl_compare(ACL_ACCESS *a,ACL_ACCESS *b);
+static ulong get_sort(uint count,...);
+static void init_check_host(void);
+static ACL_USER *find_acl_user(const char *host, const char *user);
+static bool update_user_table(THD *thd, const char *host, const char *user,
+ const char *new_password);
+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)
+{
+ THD *thd;
+ TABLE_LIST tables[3];
+ TABLE *table;
+ READ_RECORD read_record_info;
+ DBUG_ENTER("acl_init");
+
+ if (!acl_cache)
+ acl_cache=new hash_filo(ACL_CACHE_SIZE,0,0,
+ (hash_get_key) acl_entry_get_key,
+ (void (*)(void*)) free);
+ if (dont_read_acl_tables)
+ DBUG_RETURN(0); /* purecov: tested */
+
+ if (!(thd=new THD))
+ DBUG_RETURN(1); /* purecov: inspected */
+ acl_cache->clear(1); // Clear locked hostname cache
+ thd->version=refresh_version;
+ thd->mysys_var=my_thread_var;
+ thd->current_tablenr=0;
+ thd->open_tables=0;
+ thd->db=my_strdup("mysql",MYF(0));
+ bzero((char*) &tables,sizeof(tables));
+ tables[0].name=tables[0].real_name=(char*) "host";
+ tables[1].name=tables[1].real_name=(char*) "user";
+ tables[2].name=tables[2].real_name=(char*) "db";
+ tables[0].next=tables+1;
+ tables[1].next=tables+2;
+ tables[0].lock_type=tables[1].lock_type=tables[2].lock_type=TL_READ;
+ tables[0].db=tables[1].db=tables[2].db=thd->db;
+
+ if (open_tables(thd,tables))
+ {
+ close_thread_tables(thd); /* purecov: inspected */
+ delete thd; /* purecov: inspected */
+ DBUG_RETURN(1); /* purecov: inspected */
+ }
+ TABLE *ptr[3]; // Lock tables for quick update
+ ptr[0]= tables[0].table;
+ ptr[1]= tables[1].table;
+ ptr[2]= tables[2].table;
+ MYSQL_LOCK *lock=mysql_lock_tables(thd,ptr,3);
+ if (!lock)
+ {
+ close_thread_tables(thd); /* purecov: inspected */
+ delete thd; /* purecov: inspected */
+ DBUG_RETURN(1); /* purecov: inspected */
+ }
+
+ init_sql_alloc(&mem,1024);
+ init_read_record(&read_record_info,thd,table= tables[0].table,NULL,1,0);
+ VOID(init_dynamic_array(&acl_hosts,sizeof(ACL_HOST),20,50));
+ while (!(read_record_info.read_record(&read_record_info)))
+ {
+ ACL_HOST host;
+ update_hostname(&host.host,get_field(&mem, table,0));
+ host.db=get_field(&mem, table,1);
+ host.access=get_access(table,2);
+ host.access=fix_rights_for_db(host.access);
+ host.sort=get_sort(2,host.host.hostname,host.db);
+#ifndef TO_BE_REMOVED
+ if (table->fields == 8)
+ { // Without grant
+ if (host.access & CREATE_ACL)
+ host.access|=REFERENCES_ACL | INDEX_ACL | ALTER_ACL;
+ }
+#endif
+ VOID(push_dynamic(&acl_hosts,(gptr) &host));
+ }
+ qsort((gptr) dynamic_element(&acl_hosts,0,ACL_HOST*),acl_hosts.elements,
+ sizeof(ACL_HOST),(qsort_cmp) acl_compare);
+ end_read_record(&read_record_info);
+ freeze_size(&acl_hosts);
+
+ init_read_record(&read_record_info,thd,table=tables[1].table,NULL,1,0);
+ VOID(init_dynamic_array(&acl_users,sizeof(ACL_USER),50,100));
+ if (table->field[2]->field_length == 8 &&
+ protocol_version == PROTOCOL_VERSION)
+ {
+ sql_print_error(
+ "Old 'user' table. (Check README or the Reference manual). Continuing --old-protocol"); /* purecov: tested */
+ protocol_version=9; /* purecov: tested */
+ }
+
+ allow_all_hosts=0;
+ while (!(read_record_info.read_record(&read_record_info)))
+ {
+ ACL_USER user;
+ uint length=0;
+ update_hostname(&user.host,get_field(&mem, table,0));
+ user.user=get_field(&mem, table,1);
+ user.password=get_field(&mem, table,2);
+ if (user.password && (length=strlen(user.password)) == 8 &&
+ protocol_version == PROTOCOL_VERSION)
+ {
+ sql_print_error(
+ "Found old style password for user '%s'. Ignoring user. (You may want to restart using --old-protocol)",
+ user.user ? user.user : ""); /* purecov: tested */
+ }
+ else if (length % 8) // This holds true for passwords
+ {
+ sql_print_error(
+ "Found invalid password for user: '%s@%s'; Ignoring user",
+ user.user ? user.user : "",
+ user.host.hostname ? user.host.hostname : ""); /* purecov: tested */
+ continue; /* purecov: tested */
+ }
+ get_salt_from_password(user.salt,user.password);
+ user.access=get_access(table,3);
+ user.sort=get_sort(2,user.host.hostname,user.user);
+ user.hostname_length=user.host.hostname ? strlen(user.host.hostname) : 0;
+#ifndef TO_BE_REMOVED
+ if (table->fields <= 13)
+ { // Without grant
+ if (user.access & CREATE_ACL)
+ user.access|=REFERENCES_ACL | INDEX_ACL | ALTER_ACL;
+ }
+#endif
+ VOID(push_dynamic(&acl_users,(gptr) &user));
+ if (!user.host.hostname || user.host.hostname[0] == wild_many &&
+ !user.host.hostname[1])
+ allow_all_hosts=1; // Anyone can connect
+ }
+ qsort((gptr) dynamic_element(&acl_users,0,ACL_USER*),acl_users.elements,
+ sizeof(ACL_USER),(qsort_cmp) acl_compare);
+ end_read_record(&read_record_info);
+ freeze_size(&acl_users);
+
+ init_read_record(&read_record_info,thd,table=tables[2].table,NULL,1,0);
+ VOID(init_dynamic_array(&acl_dbs,sizeof(ACL_DB),50,100));
+ while (!(read_record_info.read_record(&read_record_info)))
+ {
+ ACL_DB db;
+ update_hostname(&db.host,get_field(&mem, table,0));
+ db.db=get_field(&mem, table,1);
+ db.user=get_field(&mem, table,2);
+ db.access=get_access(table,3);
+ db.access=fix_rights_for_db(db.access);
+ db.sort=get_sort(3,db.host.hostname,db.db,db.user);
+#ifndef TO_BE_REMOVED
+ if (table->fields <= 9)
+ { // Without grant
+ if (db.access & CREATE_ACL)
+ db.access|=REFERENCES_ACL | INDEX_ACL | ALTER_ACL;
+ }
+#endif
+ VOID(push_dynamic(&acl_dbs,(gptr) &db));
+ }
+ qsort((gptr) dynamic_element(&acl_dbs,0,ACL_DB*),acl_dbs.elements,
+ sizeof(ACL_DB),(qsort_cmp) acl_compare);
+ end_read_record(&read_record_info);
+ freeze_size(&acl_dbs);
+ init_check_host();
+
+ mysql_unlock_tables(thd, lock);
+ thd->version--; // Force close to free memory
+ close_thread_tables(thd);
+ delete thd;
+ initialized=1;
+ DBUG_RETURN(0);
+}
+
+
+void acl_free(bool end)
+{
+ free_root(&mem);
+ delete_dynamic(&acl_hosts);
+ delete_dynamic(&acl_users);
+ delete_dynamic(&acl_dbs);
+ delete_dynamic(&acl_wild_hosts);
+ hash_free(&acl_check_hosts);
+ if (!end)
+ acl_cache->clear(1); /* purecov: inspected */
+ else
+ {
+ delete acl_cache;
+ acl_cache=0;
+ }
+}
+
+ /* Reload acl list if possible */
+
+void acl_reload(void)
+{
+ DYNAMIC_ARRAY old_acl_hosts,old_acl_users,old_acl_dbs;
+ MEM_ROOT old_mem;
+ bool old_initialized;
+ DBUG_ENTER("acl_reload");
+
+ if (current_thd && current_thd->locked_tables)
+ { // Can't have locked tables here
+ current_thd->lock=current_thd->locked_tables;
+ current_thd->locked_tables=0;
+ close_thread_tables(current_thd);
+ }
+ if ((old_initialized=initialized))
+ VOID(pthread_mutex_lock(&acl_cache->lock));
+
+ old_acl_hosts=acl_hosts;
+ old_acl_users=acl_users;
+ old_acl_dbs=acl_dbs;
+ old_mem=mem;
+ delete_dynamic(&acl_wild_hosts);
+ hash_free(&acl_check_hosts);
+
+ if (acl_init(0))
+ { // Error. Revert to old list
+ acl_free(); /* purecov: inspected */
+ acl_hosts=old_acl_hosts;
+ acl_users=old_acl_users;
+ acl_dbs=old_acl_dbs;
+ mem=old_mem;
+ init_check_host();
+ }
+ else
+ {
+ free_root(&old_mem);
+ delete_dynamic(&old_acl_hosts);
+ delete_dynamic(&old_acl_users);
+ delete_dynamic(&old_acl_dbs);
+ }
+ if (old_initialized)
+ VOID(pthread_mutex_unlock(&acl_cache->lock));
+ DBUG_VOID_RETURN;
+}
+
+
+/* Get all access bits from table after fieldnr */
+
+static uint get_access(TABLE *form,uint fieldnr)
+{
+ uint access_bits=0,bit;
+ char buff[2];
+ String res(buff,sizeof(buff));
+ Field **pos;
+
+ for (pos=form->field+fieldnr,bit=1 ; *pos ; pos++ , bit<<=1)
+ {
+ (*pos)->val_str(&res,&res);
+ if (toupper(res[0]) == 'Y')
+ access_bits|=bit;
+ }
+ return access_bits;
+}
+
+
+/*
+ return a number with if sorted put string in this order:
+ no wildcards
+ wildcards
+ empty string
+ */
+
+static ulong get_sort(uint count,...)
+{
+ va_list args;
+ va_start(args,count);
+ ulong sort=0;
+
+ while (count--)
+ {
+ char *str=va_arg(args,char*);
+ uint chars=0,wild=0;
+
+ if (str)
+ {
+ for (; *str ; str++)
+ {
+ if (*str == wild_many || *str == wild_one || *str == wild_prefix)
+ wild++;
+ else
+ chars++;
+ }
+ }
+ sort= (sort << 8) + (wild ? 1 : chars ? 2 : 0);
+ }
+ va_end(args);
+ return sort;
+}
+
+
+static int acl_compare(ACL_ACCESS *a,ACL_ACCESS *b)
+{
+ if (a->sort > b->sort)
+ return -1;
+ if (a->sort < b->sort)
+ return 1;
+ return 0;
+}
+
+
+/* Get master privilges for user (priviliges for all tables) */
+
+
+uint acl_getroot(const char *host, const char *ip, const char *user,
+ const char *password,const char *message,char **priv_user,
+ bool old_ver)
+{
+ uint user_access=NO_ACCESS;
+ *priv_user=(char*) user;
+
+ if (!initialized)
+ return (uint) ~NO_ACCESS; // If no data allow anything /* purecov: tested */
+ VOID(pthread_mutex_lock(&acl_cache->lock));
+
+ /*
+ Get possible access from user_list. This is or'ed to others not
+ fully specified
+ */
+ for (uint i=0 ; i < acl_users.elements ; i++)
+ {
+ ACL_USER *acl_user=dynamic_element(&acl_users,i,ACL_USER*);
+ if (!acl_user->user || !strcmp(user,acl_user->user))
+ {
+ if (compare_hostname(&acl_user->host,host,ip))
+ {
+ if (!acl_user->password && !*password ||
+ (acl_user->password && *password &&
+ !check_scramble(password,message,acl_user->salt,
+ (my_bool) old_ver)))
+ {
+ user_access=acl_user->access;
+ if (!acl_user->user)
+ *priv_user=(char*) ""; // Change to anonymous user /* purecov: inspected */
+ break;
+ }
+#ifndef ALLOW_DOWNGRADE_OF_USERS
+ break; // Wrong password breaks loop /* purecov: inspected */
+#endif
+ }
+ }
+ }
+ VOID(pthread_mutex_unlock(&acl_cache->lock));
+ return user_access;
+}
+
+
+/*
+** Functions to add and change user and database privileges when one
+** changes things with GRANT
+*/
+
+static byte* check_get_key(ACL_USER *buff,uint *length,
+ my_bool not_used __attribute__((unused)))
+{
+ *length=buff->hostname_length;
+ return (byte*) buff->host.hostname;
+}
+
+static void acl_update_user(const char *user, const char *host,
+ const char *password, uint privileges)
+{
+ for (uint i=0 ; i < acl_users.elements ; i++)
+ {
+ ACL_USER *acl_user=dynamic_element(&acl_users,i,ACL_USER*);
+ if (!acl_user->user && !user[0] ||
+ acl_user->user &&
+ !strcmp(user,acl_user->user))
+ {
+ if (!acl_user->host.hostname && !host[0] ||
+ acl_user->host.hostname && !strcmp(host,acl_user->host.hostname))
+ {
+ acl_user->access=privileges;
+ if (password)
+ {
+ if (!password[0])
+ acl_user->password=0;
+ else
+ {
+ acl_user->password=(char*) ""; // Just point at something
+ get_salt_from_password(acl_user->salt,password);
+ }
+ }
+ break;
+ }
+ }
+ }
+}
+
+
+static void acl_insert_user(const char *user, const char *host,
+ const char *password,
+ uint privileges)
+{
+ ACL_USER acl_user;
+ acl_user.user=strdup_root(&mem,user);
+ update_hostname(&acl_user.host,strdup_root(&mem,host));
+ acl_user.password=0;
+ acl_user.access=privileges;
+ acl_user.sort=get_sort(2,acl_user.host.hostname,acl_user.user);
+ acl_user.hostname_length=strlen(acl_user.host.hostname);
+ if (password)
+ {
+ acl_user.password=(char*) ""; // Just point at something
+ get_salt_from_password(acl_user.salt,password);
+ }
+
+ VOID(push_dynamic(&acl_users,(gptr) &acl_user));
+ if (!acl_user.host.hostname || acl_user.host.hostname[0] == wild_many
+ && !acl_user.host.hostname[1])
+ allow_all_hosts=1; // Anyone can connect /* purecov: tested */
+ qsort((gptr) dynamic_element(&acl_users,0,ACL_USER*),acl_users.elements,
+ sizeof(ACL_USER),(qsort_cmp) acl_compare);
+
+ /* We must free acl_check_hosts as its memory is mapped to acl_user */
+ delete_dynamic(&acl_wild_hosts);
+ hash_free(&acl_check_hosts);
+ init_check_host();
+}
+
+
+static void acl_update_db(const char *user, const char *host, const char *db,
+ uint privileges)
+{
+ for (uint i=0 ; i < acl_dbs.elements ; i++)
+ {
+ ACL_DB *acl_db=dynamic_element(&acl_dbs,i,ACL_DB*);
+ if (!acl_db->user && !user[0] ||
+ acl_db->user &&
+ !strcmp(user,acl_db->user))
+ {
+ if (!acl_db->host.hostname && !host[0] ||
+ acl_db->host.hostname && !strcmp(host,acl_db->host.hostname))
+ {
+ if (!acl_db->db && !db[0] ||
+ acl_db->db && !strcmp(db,acl_db->db))
+ {
+ if (privileges)
+ acl_db->access=privileges;
+ else
+ delete_dynamic_element(&acl_dbs,i);
+ }
+ }
+ }
+ }
+}
+
+
+static void acl_insert_db(const char *user, const char *host, const char *db,
+ uint privileges)
+{
+ ACL_DB acl_db;
+ /* The acl_cache mutex is locked by mysql_grant */
+ acl_db.user=strdup_root(&mem,user);
+ update_hostname(&acl_db.host,strdup_root(&mem,host));
+ acl_db.db=strdup_root(&mem,db);
+ acl_db.access=privileges;
+ acl_db.sort=get_sort(3,acl_db.host.hostname,acl_db.db,acl_db.user);
+ VOID(push_dynamic(&acl_dbs,(gptr) &acl_db));
+ qsort((gptr) dynamic_element(&acl_dbs,0,ACL_DB*),acl_dbs.elements,
+ sizeof(ACL_DB),(qsort_cmp) acl_compare);
+}
+
+
+/*****************************************************************************
+** Get privilege for a host, user and db combination
+*****************************************************************************/
+
+uint acl_get(const char *host, const char *ip, const char *bin_ip,
+ const char *user, const char *db)
+{
+ uint host_access,db_access,i,key_length;
+ db_access=0; host_access= ~0;
+ char key[ACL_KEY_LENGTH],*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);
+ key_length=(uint) (end-key);
+ if ((entry=(acl_entry*) acl_cache->search(key,key_length)))
+ {
+ db_access=entry->access;
+ VOID(pthread_mutex_unlock(&acl_cache->lock));
+ return db_access;
+ }
+
+ /*
+ Check if there are some access rights for database and user
+ */
+ for (i=0 ; i < acl_dbs.elements ; i++)
+ {
+ ACL_DB *acl_db=dynamic_element(&acl_dbs,i,ACL_DB*);
+ if (!acl_db->user || !strcmp(user,acl_db->user))
+ {
+ if (compare_hostname(&acl_db->host,host,ip))
+ {
+ if (!acl_db->db || !wild_compare(db,acl_db->db))
+ {
+ db_access=acl_db->access;
+ if (acl_db->host.hostname)
+ goto exit; // Fully specified. Take it
+ break; /* purecov: tested */
+ }
+ }
+ }
+ }
+ if (!db_access)
+ goto exit; // Can't be better
+
+ /*
+ No host specified for user. Get hostdata from host table
+ */
+ host_access=0; // Host must be found
+ for (i=0 ; i < acl_hosts.elements ; i++)
+ {
+ ACL_HOST *acl_host=dynamic_element(&acl_hosts,i,ACL_HOST*);
+ if (compare_hostname(&acl_host->host,host,ip))
+ {
+ if (!acl_host->db || !wild_compare(db,acl_host->db))
+ {
+ host_access=acl_host->access; // Fully specified. Take it
+ break;
+ }
+ }
+ }
+exit:
+ /* Save entry in cache for quick retrieval */
+ if ((entry= (acl_entry*) malloc(sizeof(acl_entry)+key_length)))
+ {
+ entry->access=(db_access & host_access);
+ entry->length=key_length;
+ memcpy((gptr) entry->key,key,key_length);
+ acl_cache->add(entry);
+ }
+ VOID(pthread_mutex_unlock(&acl_cache->lock));
+ return (db_access & host_access);
+}
+
+
+int wild_case_compare(const char *str,const char *wildstr)
+{
+ reg3 int flag;
+ DBUG_ENTER("wild_case_compare");
+
+ while (*wildstr)
+ {
+ while (*wildstr && *wildstr != wild_many && *wildstr != wild_one)
+ {
+ if (*wildstr == wild_prefix && wildstr[1])
+ wildstr++;
+ if (toupper(*wildstr++) != toupper(*str++)) DBUG_RETURN(1);
+ }
+ if (! *wildstr ) DBUG_RETURN (*str != 0);
+ if (*wildstr++ == wild_one)
+ {
+ if (! *str++) DBUG_RETURN (1); /* One char; skipp */
+ }
+ else
+ { /* Found '*' */
+ if (!*wildstr) DBUG_RETURN(0); /* '*' as last char: OK */
+ flag=(*wildstr != wild_many && *wildstr != wild_one);
+ do
+ {
+ if (flag)
+ {
+ char cmp;
+ if ((cmp= *wildstr) == wild_prefix && wildstr[1])
+ cmp=wildstr[1];
+ cmp=toupper(cmp);
+ while (*str && toupper(*str) != cmp)
+ str++;
+ if (!*str) DBUG_RETURN (1);
+ }
+ if (wild_case_compare(str,wildstr) == 0) DBUG_RETURN (0);
+ } while (*str++);
+ DBUG_RETURN(1);
+ }
+ }
+ DBUG_RETURN (*str != '\0');
+}
+
+/*****************************************************************************
+** check if there are any possible matching entries for this host
+** All host names without wild cards are stored in a hash table,
+** entries with wildcards are stored in a dynamic array
+*****************************************************************************/
+
+static void init_check_host(void)
+{
+ DBUG_ENTER("init_check_host");
+ VOID(init_dynamic_array(&acl_wild_hosts,sizeof(struct acl_host_and_ip),
+ acl_users.elements,1));
+ VOID(hash_init(&acl_check_hosts,acl_users.elements,0,0,
+ (hash_get_key) check_get_key,0,HASH_CASE_INSENSITIVE));
+ if (!allow_all_hosts)
+ {
+ for (uint i=0 ; i < acl_users.elements ; i++)
+ {
+ ACL_USER *acl_user=dynamic_element(&acl_users,i,ACL_USER*);
+ if (strchr(acl_user->host.hostname,wild_many) ||
+ strchr(acl_user->host.hostname,wild_one) ||
+ acl_user->host.ip_mask)
+ { // Has wildcard
+ uint j;
+ for (j=0 ; j < acl_wild_hosts.elements ; j++)
+ { // Check if host already exists
+ acl_host_and_ip *acl=dynamic_element(&acl_wild_hosts,j,
+ acl_host_and_ip *);
+ if (!my_strcasecmp(acl_user->host.hostname,acl->hostname))
+ break; // already stored
+ }
+ if (j == acl_wild_hosts.elements) // If new
+ (void) push_dynamic(&acl_wild_hosts,(char*) &acl_user->host);
+ }
+ else if (!hash_search(&acl_check_hosts,(byte*) &acl_user->host,
+ strlen(acl_user->host.hostname)))
+ {
+ if (hash_insert(&acl_check_hosts,(byte*) acl_user))
+ { // End of memory
+ allow_all_hosts=1; // Should never happen
+ DBUG_VOID_RETURN;
+ }
+ }
+ }
+ }
+ freeze_size(&acl_wild_hosts);
+ freeze_size(&acl_check_hosts.array);
+ DBUG_VOID_RETURN;
+}
+
+
+/* Return true if there is no users that can match the given host */
+
+bool acl_check_host(const char *host, const char *ip)
+{
+ if (allow_all_hosts)
+ return 0;
+ VOID(pthread_mutex_lock(&acl_cache->lock));
+
+ if (host && hash_search(&acl_check_hosts,(byte*) host,strlen(host)) ||
+ ip && hash_search(&acl_check_hosts,(byte*) ip,strlen(ip)))
+ {
+ VOID(pthread_mutex_unlock(&acl_cache->lock));
+ return 0; // Found host
+ }
+ for (uint i=0 ; i < acl_wild_hosts.elements ; i++)
+ {
+ acl_host_and_ip *acl=dynamic_element(&acl_wild_hosts,i,acl_host_and_ip*);
+ if (compare_hostname(acl, host, ip))
+ {
+ VOID(pthread_mutex_unlock(&acl_cache->lock));
+ return 0; // Host ok
+ }
+ }
+ VOID(pthread_mutex_unlock(&acl_cache->lock));
+ return 1; // Host is not allowed
+}
+
+/*****************************************************************************
+** Change password for the user if it's not an anonymous user
+** Note: This should write the error directly to the client!
+*****************************************************************************/
+
+bool change_password(THD *thd, const char *host, const char *user,
+ char *new_password)
+{
+ uint length=0;
+ if (!user[0])
+ {
+ send_error(&thd->net, ER_PASSWORD_ANONYMOUS_USER);
+ return 1;
+ }
+ if (!initialized)
+ {
+ send_error(&thd->net, ER_PASSWORD_NOT_ALLOWED); /* purecov: inspected */
+ return 1; /* purecov: inspected */
+ }
+ if (!host)
+ host=thd->ip; /* purecov: tested */
+ /* password should always be 0 or 16 chars; simple hack to avoid cracking */
+ length=strlen(new_password);
+ new_password[length & 16]=0;
+
+ if (strcmp(thd->user,user) ||
+ my_strcasecmp(host,thd->host ? thd->host : thd->ip))
+ {
+ if (check_access(thd, UPDATE_ACL, "mysql",0,1))
+ return 1;
+ }
+ VOID(pthread_mutex_lock(&acl_cache->lock));
+ ACL_USER *acl_user;
+ if (!(acl_user= find_acl_user(host,user)) || !acl_user->user)
+ {
+ send_error(&thd->net, ER_PASSWORD_NO_MATCH);
+ VOID(pthread_mutex_unlock(&acl_cache->lock));
+ return 1;
+ }
+ if (update_user_table(thd,
+ acl_user->host.hostname ? acl_user->host.hostname : "",
+ acl_user->user, new_password))
+ {
+ VOID(pthread_mutex_unlock(&acl_cache->lock)); /* purecov: deadcode */
+ send_error(&thd->net,0); /* purecov: deadcode */
+ return 1; /* purecov: deadcode */
+ }
+ get_salt_from_password(acl_user->salt,new_password);
+ if (!new_password[0])
+ acl_user->password=0;
+ else
+ acl_user->password=(char*) ""; // Point at something
+ acl_cache->clear(1); // Clear locked hostname cache
+ VOID(pthread_mutex_unlock(&acl_cache->lock));
+
+ char buff[460];
+
+ Query_log_event qinfo(thd, buff);
+ qinfo.q_len =
+ my_sprintf(buff,
+ (buff,"SET PASSWORD FOR \"%-.120s\"@\"%-.120s\"=\"%-.120s\"",
+ acl_user->user,
+ acl_user->host.hostname ? acl_user->host.hostname : "",
+ new_password));
+ mysql_update_log.write(buff,strlen(buff));
+ mysql_bin_log.write(&qinfo);
+ return 0;
+}
+
+
+/*
+ Find first entry that matches the current user
+*/
+
+static ACL_USER *
+find_acl_user(const char *host, const char *user)
+{
+ for (uint i=0 ; i < acl_users.elements ; i++)
+ {
+ ACL_USER *acl_user=dynamic_element(&acl_users,i,ACL_USER*);
+ if (!acl_user->user && !user[0] ||
+ acl_user->user && !strcmp(user,acl_user->user))
+ {
+ if (compare_hostname(&acl_user->host,host,host))
+ return acl_user;
+ }
+ }
+ return 0;
+}
+
+/*****************************************************************************
+ Handle comparing of hostname
+ A hostname may be of type:
+ hostname (May include wildcards); monty.pp.sci.fi
+ ip (May include wildcards); 192.168.0.0
+ ip/netmask 192.168.0.0/255.255.255.0
+
+ A net mask of 0.0.0.0 is not allowed.
+*****************************************************************************/
+
+static const char *calc_ip(const char *ip, long *val, char end)
+{
+ long ip_val,tmp;
+ if (!(ip=str2int(ip,10,0,255,&ip_val)) || *ip != '.')
+ return 0;
+ ip_val<<=24;
+ if (!(ip=str2int(ip+1,10,0,255,&tmp)) || *ip != '.')
+ return 0;
+ ip_val+=tmp<<16;
+ if (!(ip=str2int(ip+1,10,0,255,&tmp)) || *ip != '.')
+ return 0;
+ ip_val+=tmp<<8;
+ if (!(ip=str2int(ip+1,10,0,255,&tmp)) || *ip != end)
+ return 0;
+ *val=ip_val+tmp;
+ return ip;
+}
+
+
+static void update_hostname(acl_host_and_ip *host, const char *hostname)
+{
+ host->hostname=(char*) hostname; // This will not be modified!
+ if (hostname &&
+ (!(hostname=calc_ip(hostname,&host->ip,'/')) ||
+ !(hostname=calc_ip(hostname+1,&host->ip_mask,'\0'))))
+ {
+ host->ip=host->ip_mask=0; // Not a masked ip
+ }
+}
+
+
+static bool compare_hostname(const acl_host_and_ip *host, const char *hostname,
+ const char *ip)
+{
+ long tmp;
+ if (host->ip_mask && ip && calc_ip(ip,&tmp,'\0'))
+ {
+ return (tmp & host->ip_mask) == host->ip;
+ }
+ return (!host->hostname ||
+ (hostname && !wild_case_compare(hostname,host->hostname)) ||
+ (ip && !wild_compare(ip,host->hostname)));
+}
+
+
+/****************************************************************************
+** Code to update grants in the user and database privilege tables
+****************************************************************************/
+
+static bool update_user_table(THD *thd, const char *host, const char *user,
+ const char *new_password)
+{
+ TABLE_LIST tables;
+ TABLE *table;
+ bool error=1;
+ DBUG_ENTER("update_user_table");
+ DBUG_PRINT("enter",("user: %s host: %s",user,host));
+
+ bzero((char*) &tables,sizeof(tables));
+ tables.name=tables.real_name=(char*) "user";
+ tables.db=(char*) "mysql";
+ if (!(table=open_ltable(thd,&tables,TL_WRITE)))
+ DBUG_RETURN(1); /* purecov: deadcode */
+ table->field[0]->store(host,strlen(host));
+ table->field[1]->store(user,strlen(user));
+
+ if (table->file->index_read_idx(table->record[0],0,
+ (byte*) table->field[0]->ptr,0,
+ HA_READ_KEY_EXACT))
+ {
+ my_error(ER_PASSWORD_NO_MATCH,MYF(0)); /* purecov: deadcode */
+ DBUG_RETURN(1); /* purecov: deadcode */
+ }
+ store_record(table,1);
+ table->field[2]->store(new_password,strlen(new_password));
+ if ((error=table->file->update_row(table->record[1],table->record[0])))
+ {
+ table->file->print_error(error,MYF(0)); /* purecov: deadcode */
+ goto end; /* purecov: deadcode */
+ }
+ error=0; // Record updated
+
+end:
+ close_thread_tables(thd);
+ DBUG_RETURN(error);
+}
+
+/****************************************************************************
+** Handle GRANT commands
+****************************************************************************/
+
+static int replace_user_table(TABLE *table, const LEX_USER &combo,
+ uint rights, char what)
+{
+ int error = -1;
+ uint i,j;
+ bool ima=0;
+ char *password,empty_string[1];
+ DBUG_ENTER("replace_user_table");
+
+ if (combo.password.str && combo.password.str[0])
+ password=combo.password.str;
+ else
+ {
+ password=empty_string;
+ empty_string[0]=0;
+ }
+
+ table->field[0]->store(combo.host.str,combo.host.length);
+ table->field[1]->store(combo.user.str,combo.user.length);
+ table->file->index_init(0);
+ if (table->file->index_read(table->record[0],
+ (byte*) table->field[0]->ptr,0,
+ HA_READ_KEY_EXACT))
+ {
+ if (what == 'N')
+ {
+ my_printf_error(ER_NONEXISTING_GRANT,ER(ER_NONEXISTING_GRANT),
+ MYF(0),combo.user.str,combo.host.str);
+ error= -1;
+ goto end;
+ }
+ ima = 0; // no row; ima on Serbian means 'there is something'
+ restore_record(table,2); // cp empty row from record[2]
+ table->field[0]->store(combo.host.str,combo.host.length);
+ table->field[1]->store(combo.user.str,combo.user.length);
+ table->field[2]->store(password,strlen(password));
+ }
+ else
+ {
+ ima = 1;
+ store_record(table,1); // Save copy for update
+ if (combo.password.str) // If password given
+ table->field[2]->store(password,strlen(password));
+ }
+
+ for (i = 3, j = SELECT_ACL; // starting from reload
+ i < table->fields;
+ i++, j <<= 1)
+ {
+ if (j & rights) // set requested privileges
+ table->field[i]->store(&what,1);
+ }
+ rights=get_access(table,3);
+
+ if (ima) // there is a row, therefore go to update, instead of insert
+ {
+ /*
+ We should NEVER delete from the user table, as a uses can still
+ use mysqld even if he doesn't have any privileges in the user table!
+ */
+ if (cmp_record(table,1) &&
+ (error=table->file->update_row(table->record[1],table->record[0])))
+ { // This should never happen
+ table->file->print_error(error,MYF(0)); /* purecov: deadcode */
+ error= -1; /* purecov: deadcode */
+ goto end; /* purecov: deadcode */
+ }
+ }
+ else if ((error=table->file->write_row(table->record[0]))) // insert
+ { // This should never happen
+ if (error && error != HA_ERR_FOUND_DUPP_KEY &&
+ error != HA_ERR_FOUND_DUPP_UNIQUE) /* purecov: inspected */
+ {
+ table->file->print_error(error,MYF(0)); /* purecov: deadcode */
+ error= -1; /* purecov: deadcode */
+ goto end; /* purecov: deadcode */
+ }
+ }
+ error=0; // Privileges granted / revoked
+
+ end:
+ if (!error)
+ {
+ acl_cache->clear(1); // Clear privilege cache
+ if (!combo.password.str)
+ password=0; // No password given on command
+ if (ima)
+ acl_update_user(combo.user.str,combo.host.str,password,rights);
+ else
+ acl_insert_user(combo.user.str,combo.host.str,password,rights);
+ }
+ table->file->index_end();
+ DBUG_RETURN(error);
+}
+
+
+/*
+** change grants in the mysql.db table
+*/
+
+static int replace_db_table(TABLE *table, const char *db,
+ const LEX_USER &combo,
+ uint rights, char what)
+{
+ uint i,j,store_rights;
+ bool ima=0;
+ int error;
+ DBUG_ENTER("replace_db_table");
+
+ // is there such a user in user table in memory ????
+ if (!initialized || !find_acl_user(combo.host.str,combo.user.str))
+ {
+ my_error(ER_PASSWORD_NO_MATCH,MYF(0));
+ DBUG_RETURN(-1);
+ }
+
+ table->field[0]->store(combo.host.str,combo.host.length);
+ table->field[1]->store(db,strlen(db));
+ table->field[2]->store(combo.user.str,combo.user.length);
+ table->file->index_init(0);
+ if (table->file->index_read(table->record[0],(byte*) table->field[0]->ptr,0,
+ HA_READ_KEY_EXACT))
+ {
+ if (what == 'N')
+ { // no row, no revoke
+ my_printf_error(ER_NONEXISTING_GRANT,ER(ER_NONEXISTING_GRANT),MYF(0),
+ combo.user.str,combo.host.str);
+ goto abort;
+ }
+ ima = 0; // no row
+ restore_record(table,2); // cp empty row from record[2]
+ table->field[0]->store(combo.host.str,combo.host.length);
+ table->field[1]->store(db,strlen(db));
+ table->field[2]->store(combo.user.str,combo.user.length);
+ }
+ else
+ {
+ ima = 1;
+ store_record(table,1);
+ }
+
+ store_rights=get_rights_for_db(rights);
+ for (i = 3, j = 1; i < table->fields; i++, j <<= 1)
+ {
+ if (j & store_rights) // do it if priv is chosen
+ table->field [i]->store(&what,1); // set requested privileges
+ }
+ rights=get_access(table,3);
+ rights=fix_rights_for_db(rights);
+
+ if (ima) // there is a row, therefore go update, else insert
+ {
+ if (rights)
+ {
+ if ((error=table->file->update_row(table->record[1],table->record[0])))
+ goto table_error; /* purecov: deadcode */
+ }
+ else /* must have been a revoke of all privileges */
+ {
+ if ((error = table->file->delete_row(table->record[1])))
+ goto table_error; /* purecov: deadcode */
+ }
+ }
+ else if ((error=table->file->write_row(table->record[0])))
+ {
+ if (error && error != HA_ERR_FOUND_DUPP_KEY) /* purecov: inspected */
+ goto table_error; /* purecov: deadcode */
+ }
+
+ acl_cache->clear(1); // Clear privilege cache
+ if (ima)
+ acl_update_db(combo.user.str,combo.host.str,db,rights);
+ else
+ acl_insert_db(combo.user.str,combo.host.str,db,rights);
+ table->file->index_end();
+ DBUG_RETURN(0);
+
+ /* This could only happen if the grant tables got corrupted */
+ table_error:
+ table->file->print_error(error,MYF(0)); /* purecov: deadcode */
+ table->file->index_end();
+
+ abort:
+ DBUG_RETURN(-1);
+}
+
+
+class GRANT_COLUMN :public Sql_alloc
+{
+public:
+ char *column;
+ uint rights, key_length;
+ GRANT_COLUMN(String &c, uint y) :rights (y)
+ {
+ column= memdup_root(&memex,c.ptr(),key_length=c.length());
+ }
+};
+
+static byte* get_key_column(GRANT_COLUMN *buff,uint *length,
+ my_bool not_used __attribute__((unused)))
+{
+ *length=buff->key_length;
+ return (byte*) buff->column;
+}
+
+class GRANT_TABLE :public Sql_alloc
+{
+public:
+ char *host,*db,*user,*tname, *hash_key;
+ uint privs, cols, key_length;
+ HASH hash_columns;
+ GRANT_TABLE (const char *h, const char *d,const char *u, const char *t,
+ uint p,uint c)
+ : privs(p), cols(c)
+ {
+ host = strdup_root(&memex,h);
+ db = strdup_root(&memex,d);
+ user = strdup_root(&memex,u);
+ tname= strdup_root(&memex,t);
+ key_length =strlen(d)+strlen(u)+strlen(t)+3;
+ hash_key = (char*) alloc_root(&memex,key_length);
+ strmov(strmov(strmov(hash_key,user)+1,db)+1,tname);
+ (void) hash_init(&hash_columns,0,0,0, (hash_get_key) get_key_column,0,
+ HASH_CASE_INSENSITIVE);
+ }
+
+ GRANT_TABLE (TABLE *form, TABLE *col_privs)
+ {
+ byte key[MAX_KEY_LENGTH];
+
+ host = get_field(&memex,form,0);
+ db = get_field(&memex,form,1);
+ user = get_field(&memex,form,2); if (!user) user=(char*) "";
+ tname = get_field(&memex,form,3);
+ if (!host || !db || !tname)
+ {
+ /* Wrong table row; Ignore it */
+ privs = cols = 0; /* purecov: inspected */
+ return; /* purecov: inspected */
+ }
+ key_length = strlen(db) + strlen(user) + 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();
+ cols = (uint) form->field[7]->val_int();
+ privs = fix_rights_for_table(privs);
+ cols = fix_rights_for_column(cols);
+
+ (void) hash_init(&hash_columns,0,0,0, (hash_get_key) get_key_column,0,
+ HASH_CASE_INSENSITIVE);
+ if (cols)
+ {
+ int key_len;
+ col_privs->field[0]->store(host,strlen(host));
+ col_privs->field[1]->store(db,strlen(db));
+ col_privs->field[2]->store(user,strlen(user));
+ col_privs->field[3]->store(tname,strlen(tname));
+ key_len=(col_privs->field[0]->pack_length()+
+ col_privs->field[1]->pack_length()+
+ col_privs->field[2]->pack_length()+
+ col_privs->field[3]->pack_length());
+ key_copy(key,col_privs,0,key_len);
+ col_privs->field[4]->store("",0);
+ col_privs->file->index_init(0);
+ if (col_privs->file->index_read(col_privs->record[0],
+ (byte*) col_privs->field[0]->ptr,
+ key_len, HA_READ_KEY_EXACT))
+ {
+ cols = 0; /* purecov: deadcode */
+ return;
+ }
+ do
+ {
+ String *res,column_name;
+ GRANT_COLUMN *mem_check;
+ /* As column name is a string, we don't have to supply a buffer */
+ res=col_privs->field[4]->val_str(&column_name,&column_name);
+ uint priv= (uint) col_privs->field[6]->val_int();
+ if (!(mem_check = new GRANT_COLUMN(*res,
+ fix_rights_for_column(priv))))
+ {
+ // Don't use this entry
+ privs = cols = 0; /* purecov: deadcode */
+ return; /* purecov: deadcode */
+ }
+ hash_insert(&hash_columns, (byte *) mem_check);
+ } while (!col_privs->file->index_next(col_privs->record[0]) &&
+ !key_cmp(col_privs,key,0,key_len));
+ }
+ }
+ bool ok() { return privs != 0 || cols != 0; }
+};
+
+static byte* get_grant_table(GRANT_TABLE *buff,uint *length,
+ my_bool not_used __attribute__((unused)))
+{
+ *length=buff->key_length;
+ return (byte*) buff->hash_key;
+}
+
+void free_grant_table(GRANT_TABLE *grant_table)
+{
+ hash_free(&grant_table->hash_columns);
+}
+
+/* Search after a matching grant. Prefer exact grants before not exact ones */
+
+static GRANT_TABLE *table_hash_search(const char *host,const char* ip,
+ const char *db,
+ const char *user, const char *tname,
+ bool exact)
+{
+ char helping [NAME_LEN*2+USERNAME_LENGTH+3];
+ uint len;
+ GRANT_TABLE *grant_table,*found=0;
+
+ len = (uint) (strmov(strmov(strmov(helping,user)+1,db)+1,tname)-helping)+ 1;
+ for (grant_table=(GRANT_TABLE*) hash_search(&hash_tables,(byte*) helping,
+ len) ;
+ grant_table ;
+ grant_table= (GRANT_TABLE*) hash_next(&hash_tables,(byte*) helping,len))
+ {
+ if (exact)
+ {
+ if ((host && !strcmp(host,grant_table->host)) ||
+ (ip && !strcmp(ip,grant_table->host)))
+ return grant_table;
+ }
+ else
+ {
+ if ((host && !wild_case_compare(host,grant_table->host)) ||
+ (ip && !wild_case_compare(ip,grant_table->host)))
+ found=grant_table; // Host ok
+ }
+ }
+ return found;
+}
+
+
+
+static inline GRANT_COLUMN *
+column_hash_search(GRANT_TABLE *t, const char *cname,
+ uint length)
+{
+ return (GRANT_COLUMN*) hash_search(&t->hash_columns, (byte*) cname,length);
+}
+
+
+static int replace_column_table(GRANT_TABLE *g_t,
+ TABLE *table, const LEX_USER &combo,
+ List <LEX_COLUMN> &columns,
+ const char *db, const char *table_name,
+ uint rights, bool revoke_grant)
+{
+ int error=0,result=0;
+ uint key_length;
+ byte key[MAX_KEY_LENGTH];
+ DBUG_ENTER("replace_column_table");
+
+ table->field[0]->store(combo.host.str,combo.host.length);
+ table->field[1]->store(db,strlen(db));
+ table->field[2]->store(combo.user.str,combo.user.length);
+ table->field[3]->store(table_name,strlen(table_name));
+ key_length=(table->field[0]->pack_length()+ table->field[1]->pack_length()+
+ table->field[2]->pack_length()+ table->field[3]->pack_length());
+ key_copy(key,table,0,key_length);
+
+ rights &= COL_ACLS; // Only ACL for columns
+
+ /* first fix privileges for all columns in column list */
+
+ List_iterator <LEX_COLUMN> iter(columns);
+ class LEX_COLUMN *xx;
+ table->file->index_init(0);
+ while ((xx=iter++))
+ {
+ uint privileges = xx->rights;
+ bool ima=0;
+ key_restore(table,key,0,key_length);
+ table->field[4]->store(xx->column.ptr(),xx->column.length());
+
+ if (table->file->index_read(table->record[0],(byte*) table->field[0]->ptr,
+ 0, HA_READ_KEY_EXACT))
+ {
+ if (revoke_grant)
+ {
+ my_printf_error(ER_NONEXISTING_TABLE_GRANT,
+ ER(ER_NONEXISTING_TABLE_GRANT),MYF(0),
+ combo.user.str, combo.host.str,table_name); /* purecov: inspected */
+ result= -1; /* purecov: inspected */
+ continue; /* purecov: inspected */
+ }
+ ima = 0;
+ restore_record(table,2); // Get empty record
+ key_restore(table,key,0,key_length);
+ table->field[4]->store(xx->column.ptr(),xx->column.length());
+ }
+ else
+ {
+ uint tmp= (uint) table->field[6]->val_int();
+ tmp=fix_rights_for_column(tmp);
+
+ if (revoke_grant)
+ privileges = tmp & ~(privileges | rights);
+ else
+ privileges |= tmp;
+ ima = 1;
+ store_record(table,1); // copy original row
+ }
+
+ table->field[6]->store((longlong) get_rights_for_column(privileges));
+
+ if (ima) // there is a row, therefore go update, else insert
+ {
+ if (privileges)
+ error=table->file->update_row(table->record[1],table->record[0]);
+ else
+ error=table->file->delete_row(table->record[1]);
+ if (error)
+ {
+ table->file->print_error(error,MYF(0)); /* purecov: inspected */
+ result= -1; /* purecov: inspected */
+ goto end; /* purecov: inspected */
+ }
+ GRANT_COLUMN *grant_column = column_hash_search(g_t,
+ xx->column.ptr(),
+ xx->column.length());
+ if (grant_column) // Should always be true
+ grant_column->rights = privileges; // Update hash
+ }
+ else // new grant
+ {
+ if ((error=table->file->write_row(table->record[0])))
+ {
+ table->file->print_error(error,MYF(0)); /* purecov: inspected */
+ result= -1; /* purecov: inspected */
+ goto end; /* purecov: inspected */
+ }
+ GRANT_COLUMN *grant_column = new GRANT_COLUMN(xx->column,privileges);
+ hash_insert(&g_t->hash_columns,(byte*) grant_column);
+ }
+ }
+ table->file->index_end();
+
+ /*
+ If revoke of privileges on the table level, remove all such privileges
+ for all columns
+ */
+
+ if (revoke_grant)
+ {
+ table->file->index_init(0);
+ if (table->file->index_read(table->record[0], (byte*) table->field[0]->ptr,
+ key_length, HA_READ_KEY_EXACT))
+ goto end;
+
+ // Scan trough all rows with the same host,db,user and table
+ do
+ {
+ uint privileges = (uint) table->field[6]->val_int();
+ privileges=fix_rights_for_column(privileges);
+ store_record(table,1);
+
+ if (privileges & rights) // is in this record the priv to be revoked ??
+ {
+ GRANT_COLUMN *grant_column = NULL;
+ char colum_name_buf[HOSTNAME_LENGTH+1];
+ String column_name(colum_name_buf,sizeof(colum_name_buf));
+
+ privileges&= ~rights;
+ table->field[6]->store((longlong)
+ get_rights_for_column(privileges));
+ table->field[4]->val_str(&column_name,&column_name);
+ grant_column = column_hash_search(g_t,
+ column_name.ptr(),
+ column_name.length());
+ if (privileges)
+ {
+ int tmp_error;
+ if ((tmp_error=table->file->update_row(table->record[1],
+ table->record[0])))
+ { /* purecov: deadcode */
+ table->file->print_error(tmp_error,MYF(0)); /* purecov: deadcode */
+ result= -1; /* purecov: deadcode */
+ goto end; /* purecov: deadcode */
+ }
+ if (grant_column)
+ grant_column->rights = privileges; // Update hash
+ }
+ else
+ {
+ int tmp_error;
+ if ((tmp_error = table->file->delete_row(table->record[1])))
+ { /* purecov: deadcode */
+ table->file->print_error(tmp_error,MYF(0)); /* purecov: deadcode */
+ result= -1; /* purecov: deadcode */
+ goto end; /* purecov: deadcode */
+ }
+ if (grant_column)
+ hash_delete(&g_t->hash_columns,(byte*) grant_column);
+ }
+ }
+ } while (!table->file->index_next(table->record[0]) &&
+ !key_cmp(table,key,0,key_length));
+ }
+
+ end:
+ table->file->index_end();
+ DBUG_RETURN(result);
+}
+
+
+static int replace_table_table(THD *thd, GRANT_TABLE *grant_table,
+ TABLE *table, const LEX_USER &combo,
+ const char *db, const char *table_name,
+ uint rights, uint kolone, bool revoke_grant)
+{
+ char grantor[HOSTNAME_LENGTH+1+USERNAME_LENGTH];
+ int ima = 1;
+ int error=0;
+ 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);
+
+ // The following should always succeed as new users are created before
+ // this function is called!
+ if (!find_acl_user(combo.host.str,combo.user.str))
+ {
+ my_error(ER_PASSWORD_NO_MATCH,MYF(0)); /* purecov: deadcode */
+ DBUG_RETURN(-1); /* purecov: deadcode */
+ }
+
+ restore_record(table,2); // Get empty record
+ table->field[0]->store(combo.host.str,combo.host.length);
+ table->field[1]->store(db,strlen(db));
+ table->field[2]->store(combo.user.str,combo.user.length);
+ table->field[3]->store(table_name,strlen(table_name));
+ store_record(table,1); // store at pos 1
+
+ if (table->file->index_read_idx(table->record[0],0,
+ (byte*) table->field[0]->ptr,0,
+ HA_READ_KEY_EXACT))
+ {
+ /*
+ The following should never happen as we first check the in memory
+ grant tables for the user. There is however always a small change that
+ the user has modified the grant tables directly.
+ */
+ if (revoke_grant)
+ { // no row, no revoke
+ my_printf_error(ER_NONEXISTING_TABLE_GRANT,
+ ER(ER_NONEXISTING_TABLE_GRANT),MYF(0),
+ combo.user.str,combo.host.str,
+ table_name); /* purecov: deadcode */
+ DBUG_RETURN(-1); /* purecov: deadcode */
+ }
+ ima = 0; // no row
+ restore_record(table,1); // Get saved record
+ }
+
+ store_table_rights=get_rights_for_table(rights);
+ store_col_rights=get_rights_for_column(kolone);
+ if (ima)
+ {
+ uint j,k;
+ store_record(table,1);
+ j = (uint) table->field[6]->val_int();
+ k = (uint) table->field[7]->val_int();
+
+ if (revoke_grant)
+ {
+ // column rights are already fixed in mysql_table_grant !
+ store_table_rights=j & ~store_table_rights;
+ }
+ else
+ {
+ store_table_rights|=j;
+ store_col_rights|=k;
+ }
+ }
+
+ table->field[4]->store(grantor,strlen(grantor));
+ table->field[6]->store((longlong) store_table_rights);
+ table->field[7]->store((longlong) store_col_rights);
+ rights=fix_rights_for_table(store_table_rights);
+ kolone=fix_rights_for_column(store_col_rights);
+
+ if (ima) // there is a row, therefore go update, else insert
+ {
+ if (store_table_rights || store_col_rights)
+ {
+ if ((error=table->file->update_row(table->record[1],table->record[0])))
+ goto table_error; /* purecov: deadcode */
+ }
+ else if ((error = table->file->delete_row(table->record[1])))
+ goto table_error; /* purecov: deadcode */
+ }
+ else
+ {
+ error=table->file->write_row(table->record[0]);
+ if (error && error != HA_ERR_FOUND_DUPP_KEY)
+ goto table_error; /* purecov: deadcode */
+ }
+
+ if (rights | kolone)
+ {
+ grant_table->privs = rights;
+ grant_table->cols = kolone;
+ }
+ else
+ {
+ hash_delete(&hash_tables,(byte*) grant_table);
+ }
+ DBUG_RETURN(0);
+
+ /* This should never happen */
+ table_error:
+ table->file->print_error(error,MYF(0)); /* purecov: deadcode */
+ DBUG_RETURN(-1); /* purecov: deadcode */
+}
+
+
+int mysql_table_grant (THD *thd, TABLE_LIST *table_list,
+ List <LEX_USER> &user_list,
+ List <LEX_COLUMN> &columns, uint rights,
+ bool revoke_grant)
+{
+ uint column_priv = 0;
+ List_iterator <LEX_USER> str_list (user_list);
+ LEX_USER *Str;
+ TABLE_LIST tables[3];
+ DBUG_ENTER("mysql_table_grant");
+
+ if (!initialized)
+ {
+ send_error(&(thd->net), ER_UNKNOWN_COM_ERROR); /* purecov: inspected */
+ return 1; /* purecov: inspected */
+ }
+ if (rights & ~TABLE_ACLS)
+ {
+ my_error(ER_ILLEGAL_GRANT_FOR_TABLE,MYF(0));
+ DBUG_RETURN(-1);
+ }
+
+ if (columns.elements && !revoke_grant)
+ {
+ TABLE *table;
+ class LEX_COLUMN *check;
+ List_iterator <LEX_COLUMN> iter(columns);
+
+ if (!(table=open_ltable(thd,table_list,TL_READ)))
+ DBUG_RETURN(-1);
+ while ((check = iter++))
+ {
+ if (!find_field_in_table(thd,table,check->column.ptr(),
+ check->column.length(),0,0))
+ {
+ my_printf_error(ER_BAD_FIELD_ERROR,ER(ER_BAD_FIELD_ERROR),MYF(0),
+ check->column.c_ptr(),table_list->name);
+ DBUG_RETURN(-1);
+ }
+ column_priv |= check->rights | (rights & COL_ACLS);
+ }
+ close_thread_tables(thd);
+ }
+ else if (!(rights & CREATE_ACL) && !revoke_grant)
+ {
+ char buf[FN_REFLEN];
+ sprintf(buf,"%s/%s/%s.frm",mysql_data_home,table_list->db,
+ table_list->name);
+ fn_format(buf,buf,"","",4+16+32);
+ if (access(buf,F_OK))
+ {
+ my_error(ER_NO_SUCH_TABLE,MYF(0),table_list->db,table_list->name);
+ DBUG_RETURN(-1);
+ }
+ }
+
+ /* open the mysql.tables_priv and mysql.columns_priv tables */
+
+ bzero((char*) &tables,sizeof(tables));
+ tables[0].name=tables[0].real_name= (char*) "user";
+ tables[1].name=tables[1].real_name= (char*) "tables_priv";
+ tables[2].name=tables[2].real_name= (char*) "columns_priv";
+ tables[0].next=tables+1;
+ /* Don't open column table if we don't need it ! */
+ tables[1].next=((column_priv ||
+ (revoke_grant && ((rights & COL_ACLS) || columns.elements)))
+ ? tables+2 : 0);
+ tables[0].lock_type=tables[1].lock_type=tables[2].lock_type=TL_WRITE;
+ tables[0].db=tables[1].db=tables[2].db=(char*) "mysql";
+
+ if (open_and_lock_tables(thd,tables))
+ { // Should never happen
+ close_thread_tables(thd); /* purecov: deadcode */
+ DBUG_RETURN(-1); /* purecov: deadcode */
+ }
+
+ int result=0;
+ pthread_mutex_lock(&LOCK_grant);
+ MEM_ROOT *old_root=my_pthread_getspecific_ptr(MEM_ROOT*,THR_MALLOC);
+ my_pthread_setspecific_ptr(THR_MALLOC,&memex);
+
+ while ((Str = str_list++))
+ {
+ GRANT_TABLE *grant_table;
+ if (!Str->host.str)
+ {
+ Str->host.str=(char*) "%";
+ Str->host.length=1;
+ }
+ if (Str->host.length > HOSTNAME_LENGTH ||
+ Str->user.length > USERNAME_LENGTH)
+ {
+ my_error(ER_GRANT_WRONG_HOST_OR_USER,MYF(0));
+ result= -1;
+ continue;
+ }
+ /* Create user if needed */
+ if ((replace_user_table(tables[0].table,
+ *Str,
+ 0,
+ revoke_grant ? 'N' : 'Y')))
+ {
+ result= -1; // Remember error
+ continue; // Add next user
+ }
+
+ /* Find/create cached table grant */
+ grant_table= table_hash_search(Str->host.str,NullS,table_list->db,
+ Str->user.str,
+ table_list->name,1);
+ if (!grant_table)
+ {
+ if (revoke_grant)
+ {
+ my_printf_error(ER_NONEXISTING_TABLE_GRANT,
+ ER(ER_NONEXISTING_TABLE_GRANT),MYF(0),
+ Str->user.str, Str->host.str,table_list->name);
+ result= -1;
+ continue;
+ }
+ grant_table = new GRANT_TABLE (Str->host.str,table_list->db,
+ Str->user.str,
+ table_list->name,
+ rights,
+ column_priv);
+ if (!grant_table) // end of memory
+ {
+ result= -1; /* purecov: deadcode */
+ continue; /* purecov: deadcode */
+ }
+ hash_insert(&hash_tables,(byte*) grant_table);
+ }
+
+ /* If revoke_grant, calculate the new column privilege for tables_priv */
+ if (revoke_grant)
+ {
+ class LEX_COLUMN *check;
+ List_iterator <LEX_COLUMN> iter(columns);
+ GRANT_COLUMN *grant_column;
+
+ /* Fix old grants */
+ while ((check = iter++))
+ {
+ grant_column = column_hash_search(grant_table,
+ check->column.ptr(),
+ check->column.length());
+ if (grant_column)
+ grant_column->rights&= ~(check->rights | rights);
+ }
+ /* scan trough all columns to get new column grant */
+ column_priv=0;
+ for (uint idx=0 ; idx < grant_table->hash_columns.records ; idx++)
+ {
+ grant_column= (GRANT_COLUMN*) hash_element(&grant_table->hash_columns,
+ idx);
+ grant_column->rights&= ~rights; // Fix other columns
+ column_priv|= grant_column->rights;
+ }
+ }
+ else
+ {
+ column_priv|= grant_table->cols;
+ }
+
+
+ /* update table and columns */
+
+ if (replace_table_table(thd,grant_table,tables[1].table,*Str,
+ table_list->db,
+ table_list->name,
+ rights, column_priv, revoke_grant))
+ { // Crashend table ??
+ result= -1; /* purecov: deadcode */
+ }
+ else if (tables[2].table)
+ {
+ if ((replace_column_table(grant_table,tables[2].table, *Str,
+ columns,
+ table_list->db,
+ table_list->name,
+ rights, revoke_grant)))
+ {
+ result= -1;
+ }
+ }
+ }
+ grant_option=TRUE;
+ my_pthread_setspecific_ptr(THR_MALLOC,old_root);
+ pthread_mutex_unlock(&LOCK_grant);
+ if (!result)
+ send_ok(&thd->net);
+ /* Tables are automaticly closed */
+ DBUG_RETURN(result);
+}
+
+
+int mysql_grant (THD *thd, const char *db, List <LEX_USER> &list, uint rights,
+ bool revoke_grant)
+{
+ List_iterator <LEX_USER> str_list (list);
+ LEX_USER *Str;
+ char what;
+ TABLE_LIST tables[2];
+ DBUG_ENTER("mysql_grant");
+
+ if (!initialized)
+ {
+ send_error(&(thd->net), ER_UNKNOWN_COM_ERROR); /* purecov: tested */
+ return 1; /* purecov: tested */
+ }
+
+ what = (revoke_grant) ? 'N' : 'Y';
+
+ /* open the mysql.user and mysql.db tables */
+
+ tables[0].name=tables[0].real_name=(char*) "user";
+ tables[1].name=tables[1].real_name=(char*) "db";
+ tables[0].next=tables+1;
+ tables[1].next=0;
+ tables[0].lock_type=tables[1].lock_type=TL_WRITE;
+ tables[0].db=tables[1].db=(char*) "mysql";
+ tables[0].table=tables[1].table=0;
+ if (open_and_lock_tables(thd,tables))
+ { // This should never happen
+ close_thread_tables(thd); /* purecov: deadcode */
+ DBUG_RETURN(-1); /* purecov: deadcode */
+ }
+
+ // go through users in user_list
+
+ pthread_mutex_lock(&LOCK_grant);
+ VOID(pthread_mutex_lock(&acl_cache->lock));
+ grant_version++;
+
+ int result=0;
+ while ((Str = str_list++))
+ {
+ if (!Str->host.str)
+ {
+ Str->host.str=(char*) "%";
+ Str->host.length=1;
+ }
+ if (Str->host.length > HOSTNAME_LENGTH ||
+ Str->user.length > USERNAME_LENGTH)
+ {
+ my_error(ER_GRANT_WRONG_HOST_OR_USER,MYF(0));
+ result= -1;
+ continue;
+ }
+ if ((replace_user_table(tables[0].table,
+ *Str,
+ (!db ? rights : 0), what)))
+ result= -1;
+ if (db)
+ if (( replace_db_table(tables[1].table, db, *Str, rights,
+ what)))
+ result= -1;
+ }
+ VOID(pthread_mutex_unlock(&acl_cache->lock));
+ pthread_mutex_unlock(&LOCK_grant);
+ close_thread_tables(thd);
+
+ if (!result)
+ send_ok(&thd->net);
+ DBUG_RETURN(result);
+}
+
+ /* Free grant array if possible */
+
+void grant_free(void)
+{
+ DBUG_ENTER("grant_free");
+ grant_option = FALSE;
+ hash_free(&hash_tables);
+ free_root(&memex);
+ DBUG_VOID_RETURN;
+}
+
+
+/* Init grant array if possible */
+
+int grant_init (void)
+{
+ THD *thd;
+ TABLE_LIST tables[2];
+ int error = 0;
+ TABLE *t_table, *c_table;
+ DBUG_ENTER("grant_init");
+
+ grant_option = FALSE;
+ (void) hash_init(&hash_tables,0,0,0, (hash_get_key) get_grant_table,
+ (hash_free_key) free_grant_table,0);
+ init_sql_alloc(&memex,1024);
+
+ if (!initialized)
+ DBUG_RETURN(0); /* purecov: tested */
+ if (!(thd=new THD))
+ DBUG_RETURN(1); /* purecov: deadcode */
+
+ thd->version=refresh_version;
+ thd->mysys_var=my_thread_var;
+ thd->current_tablenr=0;
+ thd->open_tables=0;
+ thd->db=my_strdup("mysql",MYF(0));
+ 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";
+ tables[0].next=tables+1;
+ tables[0].lock_type=tables[1].lock_type=TL_READ;
+ tables[0].db=tables[1].db=thd->db;
+
+ if (open_tables(thd,tables))
+ { // No grant tables
+ close_thread_tables(thd); /* purecov: deadcode */
+ delete thd; /* purecov: deadcode */
+ DBUG_RETURN(1); /* purecov: deadcode */
+ }
+ TABLE *ptr[2]; // Lock tables for quick update
+ ptr[0]= tables[0].table;
+ ptr[1]= tables[1].table;
+ MYSQL_LOCK *lock=mysql_lock_tables(thd,ptr,2);
+ if (!lock)
+ {
+ close_thread_tables(thd); /* purecov: deadcode */
+ delete thd; /* purecov: deadcode */
+ DBUG_RETURN(1); /* purecov: deadcode */
+ }
+
+ t_table = tables[0].table; c_table = tables[1].table;
+ t_table->file->index_init(0);
+ if (t_table->file->index_first(t_table->record[0]))
+ {
+ t_table->file->index_end();
+ mysql_unlock_tables(thd, lock);
+ close_thread_tables(thd);
+ delete thd;
+ DBUG_RETURN(0); // Empty table is ok!
+ }
+ grant_option = TRUE;
+ t_table->file->index_end();
+
+ MEM_ROOT *old_root=my_pthread_getspecific_ptr(MEM_ROOT*,THR_MALLOC);
+ my_pthread_setspecific_ptr(THR_MALLOC,&memex);
+ while (!error)
+ {
+ GRANT_TABLE *mem_check;
+ if (!(mem_check=new GRANT_TABLE(t_table,c_table)) ||
+ mem_check->ok() && hash_insert(&hash_tables,(byte*) mem_check))
+ {
+ /* This could only happen if we are out memory */
+ my_pthread_setspecific_ptr(THR_MALLOC,old_root); /* purecov: deadcode */
+ grant_option = FALSE; /* purecov: deadcode */
+ mysql_unlock_tables(thd, lock); /* purecov: deadcode */
+ close_thread_tables(thd); /* purecov: deadcode */
+ delete thd; /* purecov: deadcode */
+ DBUG_RETURN(1); /* purecov: deadcode */
+ }
+ error = t_table->file->index_next(t_table->record[0]);
+ }
+ my_pthread_setspecific_ptr(THR_MALLOC,old_root);
+ mysql_unlock_tables(thd, lock);
+ thd->version--; // Force close to free memory
+ close_thread_tables(thd);
+ delete thd;
+ DBUG_RETURN(0);
+}
+
+
+/* Reload grant array if possible */
+
+void grant_reload(void)
+{
+ HASH old_hash_tables;bool old_grant_option;
+ MEM_ROOT old_mem;
+ DBUG_ENTER("grant_reload");
+
+ // Locked tables are checked by acl_init and doesn't have to be checked here
+
+ pthread_mutex_lock(&LOCK_grant);
+ grant_version++;
+ old_hash_tables=hash_tables;
+ old_grant_option = grant_option;
+ old_mem = memex;
+
+ if (grant_init())
+ { // Error. Revert to old hash
+ grant_free(); /* purecov: deadcode */
+ hash_tables=old_hash_tables; /* purecov: deadcode */
+ grant_option = old_grant_option; /* purecov: deadcode */
+ memex = old_mem; /* purecov: deadcode */
+ }
+ else
+ {
+ hash_free(&old_hash_tables);
+ free_root(&old_mem);
+ }
+ pthread_mutex_unlock(&LOCK_grant);
+ DBUG_VOID_RETURN;
+}
+
+
+/****************************************************************************
+** Check grants
+** All errors are written directly to the client if command name is given !
+****************************************************************************/
+
+bool check_grant(THD *thd, uint want_access, TABLE_LIST *tables,
+ uint show_table)
+{
+ TABLE_LIST *table;
+ char *user = thd->priv_user;
+
+ want_access &= ~thd->master_access;
+ if (!want_access)
+ return 0; // ok
+
+ pthread_mutex_lock(&LOCK_grant);
+ for (table=tables; table ;table=table->next)
+ {
+ if (!(~table->grant.privilege & want_access))
+ {
+ 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,
+ table->real_name,0);
+ if (!grant_table)
+ {
+ want_access &= ~table->grant.privilege;
+ goto err; // No grants
+ }
+
+ table->grant.grant_table=grant_table; // Remember for column test
+ table->grant.version=grant_version;
+ table->grant.privilege|= grant_table->privs;
+ table->grant.want_privilege= ((want_access & COL_ACLS)
+ & ~table->grant.privilege);
+
+ if (!(~table->grant.privilege & want_access))
+ continue;
+ if (show_table && table->grant.privilege)
+ continue; // Test from show tables
+
+ if (want_access & ~(grant_table->cols | table->grant.privilege))
+ {
+ want_access &= ~(grant_table->cols | table->grant.privilege);
+ goto err; // impossible
+ }
+ }
+ pthread_mutex_unlock(&LOCK_grant);
+ return 0;
+
+ err:
+ pthread_mutex_unlock(&LOCK_grant);
+ if (show_table != 1) // Not a silent skip of table
+ {
+ const char *command="";
+ if (want_access & SELECT_ACL)
+ command ="select";
+ else if (want_access & INSERT_ACL)
+ command = "insert";
+ else if (want_access & UPDATE_ACL)
+ command = "update";
+ else if (want_access & DELETE_ACL)
+ command = "delete";
+ else if (want_access & DROP_ACL)
+ command = "drop";
+ else if (want_access & CREATE_ACL)
+ command = "create";
+ else if (want_access & ALTER_ACL)
+ command = "alter";
+ else if (want_access & INDEX_ACL)
+ command = "index";
+ else if (want_access & GRANT_ACL)
+ command = "grant";
+ net_printf(&thd->net,ER_TABLEACCESS_DENIED_ERROR,
+ command,
+ thd->priv_user,
+ thd->host ? thd->host : (thd->ip ? thd->ip : "unknown"),
+ table ? table->real_name : "unknown");
+ }
+ return 1;
+}
+
+
+bool check_grant_column (THD *thd,TABLE *table, const char *name,
+ uint length, uint show_tables)
+{
+ GRANT_TABLE *grant_table;
+ GRANT_COLUMN *grant_column;
+
+ uint want_access=table->grant.want_privilege;
+ if (!want_access)
+ return 0; // Already checked
+
+ pthread_mutex_lock(&LOCK_grant);
+
+ // reload table if someone has modified any grants
+
+ if (table->grant.version != grant_version)
+ {
+ table->grant.grant_table=
+ table_hash_search(thd->host,thd->ip,thd->db,
+ thd->priv_user,
+ table->real_name,0); /* purecov: inspected */
+ table->grant.version=grant_version; /* purecov: inspected */
+ }
+ if (!(grant_table=table->grant.grant_table))
+ goto err; /* purecov: deadcode */
+
+ grant_column=column_hash_search(grant_table, name, length);
+ if (grant_column && !(~grant_column->rights & want_access))
+ {
+ pthread_mutex_unlock(&LOCK_grant);
+ return 0;
+ }
+#ifdef NOT_USED
+ if (show_tables && (grant_column || table->grant.privilege & COL_ACLS))
+ {
+ pthread_mutex_unlock(&LOCK_grant); /* purecov: deadcode */
+ return 0; /* purecov: deadcode */
+ }
+#endif
+
+ /* We must use my_printf_error() here! */
+ err:
+ pthread_mutex_unlock(&LOCK_grant);
+ if (!show_tables)
+ {
+ const char *command="";
+ if (want_access & SELECT_ACL)
+ command ="select";
+ else if (want_access & INSERT_ACL)
+ command = "insert";
+ else if (want_access & UPDATE_ACL)
+ command = "update";
+ my_printf_error(ER_COLUMNACCESS_DENIED_ERROR,
+ ER(ER_COLUMNACCESS_DENIED_ERROR),
+ MYF(0),
+ command,
+ thd->priv_user,
+ thd->host ? thd->host : (thd->ip ? thd->ip : "unknown"),
+ name,
+ table ? table->real_name : "unknown");
+ }
+ return 1;
+}
+
+
+bool check_grant_all_columns(THD *thd,uint want_access, TABLE *table)
+{
+ GRANT_TABLE *grant_table;
+ GRANT_COLUMN *grant_column;
+ Field *field=0,**ptr;
+
+ want_access &= ~table->grant.privilege;
+ if (!want_access)
+ return 0; // Already checked
+
+ pthread_mutex_lock(&LOCK_grant);
+
+ // reload table if someone has modified any grants
+
+ if (table->grant.version != grant_version)
+ {
+ table->grant.grant_table=
+ table_hash_search(thd->host,thd->ip,thd->db,
+ thd->priv_user,
+ table->real_name,0); /* purecov: inspected */
+ table->grant.version=grant_version; /* purecov: inspected */
+ }
+ // The following should always be true
+ if (!(grant_table=table->grant.grant_table))
+ goto err; /* purecov: inspected */
+
+ for (ptr=table->field; (field= *ptr) ; ptr++)
+ {
+ grant_column=column_hash_search(grant_table, field->field_name,
+ strlen(field->field_name));
+ if (!grant_column || (~grant_column->rights & want_access))
+ goto err;
+ }
+ pthread_mutex_unlock(&LOCK_grant);
+ return 0;
+
+ /* We must use my_printf_error() here! */
+ err:
+ pthread_mutex_unlock(&LOCK_grant);
+
+ const char *command="";
+ if (want_access & SELECT_ACL)
+ command ="select";
+ else if (want_access & INSERT_ACL)
+ command = "insert";
+ my_printf_error(ER_COLUMNACCESS_DENIED_ERROR,
+ ER(ER_COLUMNACCESS_DENIED_ERROR),
+ MYF(0),
+ command,
+ thd->priv_user,
+ thd->host ? thd->host : (thd->ip ? thd->ip : "unknown"),
+ field ? field->field_name : "unknown",
+ table->real_name);
+ return 1;
+}
+
+
+/****************************************************************************
+** Check if a user has the right to access a database
+** Access is accepted if he has a grant for any table in the database
+** Return 1 if access is denied
+****************************************************************************/
+
+bool check_grant_db(THD *thd,const char *db)
+{
+ char helping [NAME_LEN+USERNAME_LENGTH+2];
+ uint len;
+ bool error=1;
+
+ len = (uint) (strmov(strmov(helping,thd->priv_user)+1,db)-helping)+ 1;
+ pthread_mutex_lock(&LOCK_grant);
+
+ for (uint idx=0 ; idx < hash_tables.records ; idx++)
+ {
+ GRANT_TABLE *grant_table = (GRANT_TABLE*) hash_element(&hash_tables,idx);
+ if (len < grant_table->key_length &&
+ !memcmp(grant_table->hash_key,helping,len) &&
+ (thd->host && !wild_case_compare(thd->host,grant_table->host) ||
+ (thd->ip && !wild_case_compare(thd->ip,grant_table->host))))
+ {
+ error=0; // Found match
+ break;
+ }
+ }
+ pthread_mutex_unlock(&LOCK_grant);
+ return error;
+}
+
+/*****************************************************************************
+** Functions to retrieve the grant for a table/column (for SHOW functions)
+*****************************************************************************/
+
+uint get_table_grant(THD *thd, TABLE_LIST *table)
+{
+ char *user = thd->priv_user;
+ const char *db = table->db ? table->db : thd->db;
+ GRANT_TABLE *grant_table;
+
+ pthread_mutex_lock(&LOCK_grant);
+ grant_table = table_hash_search(thd->host,thd->ip,db,user,
+ table->real_name,0);
+ table->grant.grant_table=grant_table; // Remember for column test
+ table->grant.version=grant_version;
+ if (grant_table)
+ table->grant.privilege|= grant_table->privs;
+ pthread_mutex_unlock(&LOCK_grant);
+ return table->grant.privilege;
+}
+
+
+uint get_column_grant(THD *thd, TABLE_LIST *table, Field *field)
+{
+ GRANT_TABLE *grant_table;
+ GRANT_COLUMN *grant_column;
+ uint priv;
+
+ pthread_mutex_lock(&LOCK_grant);
+ // reload table if someone has modified any grants
+ if (table->grant.version != grant_version)
+ {
+ table->grant.grant_table=
+ table_hash_search(thd->host,thd->ip,thd->db,
+ thd->priv_user,
+ table->real_name,0); /* purecov: inspected */
+ table->grant.version=grant_version; /* purecov: inspected */
+ }
+
+ if (!(grant_table=table->grant.grant_table))
+ priv=table->grant.privilege;
+ else
+ {
+ grant_column=column_hash_search(grant_table, field->field_name,
+ strlen(field->field_name));
+ if (!grant_column)
+ priv=table->grant.privilege;
+ else
+ priv=table->grant.privilege | grant_column->rights;
+ }
+ pthread_mutex_unlock(&LOCK_grant);
+ return priv;
+}
+
+
+/*****************************************************************************
+** SHOW GRANTS : send to client grant-like strings depicting user@host
+** privileges
+*****************************************************************************/
+
+static const char *command_array[]=
+{"SELECT", "INSERT","UPDATE","DELETE","CREATE", "DROP","RELOAD","SHUTDOWN",
+ "PROCESS","FILE","GRANT","REFERENCES","INDEX","ALTER"};
+static int command_lengths[]={6,6,6,6,6,4,6,8,7,4,5,9,5,5};
+
+int mysql_show_grants(THD *thd,LEX_USER *lex_user)
+{
+ uint counter, want_access,index;
+ int error = 0;
+ ACL_USER *acl_user; ACL_DB *acl_db;
+ char buff[1024];
+ DBUG_ENTER("mysql_grant");
+
+ LINT_INIT(acl_user);
+ if (!initialized)
+ {
+ send_error(&(thd->net), ER_UNKNOWN_COM_ERROR);
+ DBUG_RETURN(-1);
+ }
+ if (!lex_user->host.str)
+ {
+ lex_user->host.str=(char*) "%";
+ lex_user->host.length=1;
+ }
+ if (lex_user->host.length > HOSTNAME_LENGTH ||
+ lex_user->user.length > USERNAME_LENGTH)
+ {
+ my_error(ER_GRANT_WRONG_HOST_OR_USER,MYF(0));
+ DBUG_RETURN(-1);
+ }
+
+ for (counter=0 ; counter < acl_users.elements ; counter++)
+ {
+ const char *user,*host;
+ acl_user=dynamic_element(&acl_users,counter,ACL_USER*);
+ if (!(user=acl_user->user))
+ user="";
+ if (!(host=acl_user->host.hostname))
+ host="%";
+ if (!strcmp(lex_user->user.str,user) &&
+ !strcmp(lex_user->host.str,host))
+ break;
+ }
+ if (counter == acl_users.elements)
+ {
+ my_printf_error(ER_NONEXISTING_GRANT,ER(ER_NONEXISTING_GRANT),
+ MYF(0),lex_user->user.str,lex_user->host.str);
+ DBUG_RETURN(-1);
+ }
+
+ Item_string *field=new Item_string("",0);
+ List<Item> field_list;
+ field->name=buff;
+ field->max_length=1024;
+ strxmov(buff,"Grants for ",lex_user->user.str,"@",
+ lex_user->host.str,NullS);
+ field_list.push_back(field);
+ if (send_fields(thd,field_list,1))
+ DBUG_RETURN(-1);
+
+ VOID(pthread_mutex_lock(&acl_cache->lock));
+
+ /* Add first global access grants */
+ if (acl_user->access || acl_user->password)
+ {
+ want_access=acl_user->access;
+ String global(buff,sizeof(buff));
+ global.length(0);
+ global.append("GRANT ",6);
+
+ if (test_all_bits(want_access, (GLOBAL_ACLS & ~ GRANT_ACL)))
+ global.append("ALL PRIVILEGES",14);
+ else if (!(want_access & ~GRANT_ACL))
+ global.append("USAGE",5);
+ else
+ {
+ bool found=0;
+ uint j,test_access= want_access & ~GRANT_ACL;
+ for (counter=0, j = SELECT_ACL;j <= GLOBAL_ACLS;counter++,j <<= 1)
+ {
+ if (test_access & j)
+ {
+ if (found)
+ global.append(", ",2);
+ found=1;
+ global.append(command_array[counter],command_lengths[counter]);
+ }
+ }
+ }
+ global.append (" ON *.* TO '",12);
+ global.append(lex_user->user.str,lex_user->user.length);
+ global.append ("'@'",3);
+ global.append(lex_user->host.str,lex_user->host.length);
+ global.append ('\'');
+ if (acl_user->password)
+ {
+ char passd_buff[HASH_PASSWORD_LENGTH+1];
+ make_password_from_salt(passd_buff,acl_user->salt);
+ global.append(" IDENTIFIED BY PASSWORD '",25);
+ global.append(passd_buff);
+ global.append('\'');
+ }
+ if (want_access & GRANT_ACL)
+ global.append(" WITH GRANT OPTION",18);
+ thd->packet.length(0);
+ net_store_data(&thd->packet,global.ptr(),global.length());
+ if (my_net_write(&thd->net,(char*) thd->packet.ptr(),
+ thd->packet.length()))
+ {
+ error=-1; goto end;
+ }
+ }
+
+ /* Add database access */
+ for (counter=0 ; counter < acl_dbs.elements ; counter++)
+ {
+ const char *user,*host;
+
+ acl_db=dynamic_element(&acl_dbs,counter,ACL_DB*);
+ if (!(user=acl_db->user))
+ user="";
+ if (!(host=acl_db->host.hostname))
+ host="";
+
+ if (!strcmp(lex_user->user.str,user) &&
+ !strcmp(lex_user->host.str,host))
+ {
+ want_access=acl_db->access;
+ if (want_access)
+ {
+ String db(buff,sizeof(buff));
+ db.length(0);
+ db.append("GRANT ",6);
+
+ if (test_all_bits(want_access,(DB_ACLS & ~GRANT_ACL)))
+ db.append("ALL PRIVILEGES",14);
+ else
+ {
+ int found=0, cnt;
+ uint j,test_access= want_access & ~GRANT_ACL;
+ for (cnt=0, j = SELECT_ACL; j <= DB_ACLS; cnt++,j <<= 1)
+ {
+ if (test_access & j)
+ {
+ if (found)
+ db.append(", ",2);
+ found = 1;
+ db.append(command_array[cnt],command_lengths[cnt]);
+ }
+ }
+ }
+ db.append (" ON ",4);
+ db.append(acl_db->db);
+ db.append (".* TO '",7);
+ db.append(lex_user->user.str,lex_user->user.length);
+ db.append ("'@'",3);
+ db.append(lex_user->host.str, lex_user->host.length);
+ db.append ('\'');
+ if (want_access & GRANT_ACL)
+ db.append(" WITH GRANT OPTION",18);
+ thd->packet.length(0);
+ net_store_data(&thd->packet,db.ptr(),db.length());
+ if (my_net_write(&thd->net,(char*) thd->packet.ptr(),
+ thd->packet.length()))
+ {
+ error=-1;
+ goto end;
+ }
+ }
+ }
+ }
+
+ /* Add column access */
+ for (index=0 ; index < hash_tables.records ; index++)
+ {
+ const char *user,*host;
+ GRANT_TABLE *grant_table= (GRANT_TABLE*) hash_element(&hash_tables,index);
+
+ if (!(user=grant_table->user))
+ user="";
+ if (!(host=grant_table->host))
+ host="";
+
+ if (!strcmp(lex_user->user.str,user) &&
+ !strcmp(lex_user->host.str,host))
+ {
+ want_access=grant_table->privs;
+ if (want_access)
+ {
+ String global(buff,sizeof(buff));
+ global.length(0);
+ global.append("GRANT ",6);
+
+ if (test_all_bits(want_access,(TABLE_ACLS & ~GRANT_ACL)))
+ global.append("ALL PRIVILEGES",14);
+ else
+ {
+ int found=0;
+ uint j,test_access= want_access & ~GRANT_ACL;
+
+ for (counter=0, j = SELECT_ACL;j <= TABLE_ACLS; counter++,j <<= 1)
+ {
+ if (test_access & j)
+ {
+ if (found)
+ global.append(", ",2);
+ found = 1;
+ global.append(command_array[counter],command_lengths[counter]);
+
+ if (grant_table->cols)
+ {
+ uint found_col=0;
+ for (uint col_index=0 ;
+ col_index < grant_table->hash_columns.records ;
+ col_index++)
+ {
+ GRANT_COLUMN *grant_column = (GRANT_COLUMN*)
+ hash_element(&grant_table->hash_columns,col_index);
+ if (grant_column->rights & j)
+ {
+ if (!found_col)
+ {
+ global.append(" (",2);
+ found_col=1;
+ }
+ else
+ global.append(", ",2);
+ global.append(grant_column->column,
+ grant_column->key_length);
+ }
+ }
+ if (found_col)
+ global.append(')');
+ }
+ }
+ }
+ }
+ global.append(" ON ",4);
+ global.append(grant_table->db);
+ global.append(".",1);
+ global.append(grant_table->tname);
+ global.append(" TO '",5);
+ global.append(lex_user->user.str,lex_user->user.length);
+ global.append("'@'",3);
+ global.append(lex_user->host.str,lex_user->host.length);
+ global.append('\'');
+ if (want_access & GRANT_ACL)
+ global.append(" WITH GRANT OPTION",18);
+ thd->packet.length(0);
+ net_store_data(&thd->packet,global.ptr(),global.length());
+ if (my_net_write(&thd->net,(char*) thd->packet.ptr(),
+ thd->packet.length()))
+ {
+ error=-1;
+ goto end;
+ }
+ }
+ }
+ }
+ end:
+ VOID(pthread_mutex_unlock(&acl_cache->lock));
+ send_eof(&thd->net);
+ DBUG_RETURN(error);
+}
+
+
+/*****************************************************************************
+** Instantiate used templates
+*****************************************************************************/
+
+#ifdef __GNUC__
+template class List_iterator<LEX_COLUMN>;
+template class List_iterator<LEX_USER>;
+template class List<LEX_COLUMN>;
+template class List<LEX_USER>;
+#endif
diff --git a/sql/sql_acl.h b/sql/sql_acl.h
new file mode 100644
index 00000000000..ff9a105d76b
--- /dev/null
+++ b/sql/sql_acl.h
@@ -0,0 +1,84 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 SELECT_ACL 1
+#define INSERT_ACL 2
+#define UPDATE_ACL 4
+#define DELETE_ACL 8
+#define CREATE_ACL 16
+#define DROP_ACL 32
+#define RELOAD_ACL 64
+#define SHUTDOWN_ACL 128
+#define PROCESS_ACL 256
+#define FILE_ACL 512
+#define GRANT_ACL 1024
+#define REFERENCES_ACL 2048
+#define INDEX_ACL 4096
+#define ALTER_ACL 8192
+#define EXTRA_ACL 16384
+#define DB_ACLS (UPDATE_ACL | SELECT_ACL | INSERT_ACL | \
+ DELETE_ACL | CREATE_ACL | DROP_ACL | GRANT_ACL | \
+ REFERENCES_ACL | INDEX_ACL | ALTER_ACL)
+#define TABLE_ACLS (SELECT_ACL | INSERT_ACL | UPDATE_ACL | \
+ DELETE_ACL | CREATE_ACL | DROP_ACL | GRANT_ACL | \
+ REFERENCES_ACL | INDEX_ACL | ALTER_ACL)
+#define COL_ACLS (SELECT_ACL | INSERT_ACL | UPDATE_ACL | REFERENCES_ACL)
+#define GLOBAL_ACLS (SELECT_ACL | INSERT_ACL | UPDATE_ACL | DELETE_ACL |\
+ CREATE_ACL | DROP_ACL | RELOAD_ACL | SHUTDOWN_ACL |\
+ PROCESS_ACL | FILE_ACL | GRANT_ACL | REFERENCES_ACL |\
+ INDEX_ACL | ALTER_ACL)
+#define NO_ACCESS 32768
+
+/* defines to change the above bits to how things are stored in tables */
+
+#define fix_rights_for_db(A) (((A) & 63) | (((A) & ~63) << 4))
+#define get_rights_for_db(A) (((A) & 63) | (((A) & ~63) >> 4))
+#define fix_rights_for_table(A) (((A) & 63) | (((A) & ~63) << 4))
+#define get_rights_for_table(A) (((A) & 63) | (((A) & ~63) >> 4))
+#define fix_rights_for_column(A) (((A) & COL_ACLS) | ((A & ~COL_ACLS) << 7))
+#define get_rights_for_column(A) (((A) & COL_ACLS) | ((A & ~COL_ACLS) >> 7))
+
+/* prototypes */
+
+int acl_init(bool dont_read_acl_tables);
+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,
+ const char *password,const char *scramble,char **priv_user,
+ bool old_ver);
+bool acl_check_host(const char *host, const char *ip);
+bool change_password(THD *thd, const char *host, const char *user,
+ char *password);
+int mysql_grant(THD *thd, const char *db, List <LEX_USER> &user_list,
+ uint rights, bool revoke);
+int mysql_table_grant(THD *thd, TABLE_LIST *table, List <LEX_USER> &user_list,
+ List <LEX_COLUMN> &column_list, uint rights,
+ bool revoke);
+int grant_init(void);
+void grant_free(void);
+void grant_reload(void);
+bool check_grant(THD *thd, uint want_access, TABLE_LIST *tables,
+ uint show_command=0);
+bool check_grant_column (THD *thd,TABLE *table, const char *name,uint length,
+ uint show_command=0);
+bool check_grant_all_columns(THD *thd, uint want_access, TABLE *table);
+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);
diff --git a/sql/sql_analyse.cc b/sql/sql_analyse.cc
new file mode 100644
index 00000000000..4794a23976b
--- /dev/null
+++ b/sql/sql_analyse.cc
@@ -0,0 +1,981 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+
+/* Analyse database */
+
+/* TODO: - Check if any character fields can be of any date type
+** (date, datetime, year, time, timestamp, newdate)
+** - Check if any number field should be a timestamp
+** - type set is out of optimization yet
+*/
+
+#ifdef __GNUC__
+#pragma implementation // gcc: Class implementation
+#endif
+
+#include "mysql_priv.h"
+#include "procedure.h"
+#include "sql_analyse.h"
+#include <m_ctype.h>
+
+#define MAX_TREEMEM 8192
+#define MAX_TREE_ELEMENTS 256
+#define UINT_MAX16 0xffff
+#define UINT_MAX24 0xffffff
+#define UINT_MAX32 0xffffffff
+
+Procedure *
+proc_analyse_init(THD *thd, ORDER *param, select_result *result,
+ List<Item> &field_list)
+{
+ char *proc_name = (*param->item)->name;
+ analyse *pc = new analyse(result);
+ field_info **f_info;
+ DBUG_ENTER("proc_analyse_init");
+
+ if (!(param = param->next))
+ {
+ pc->max_tree_elements = MAX_TREE_ELEMENTS;
+ pc->max_treemem = MAX_TREEMEM;
+ }
+ else if (param->next)
+ {
+ // first parameter
+ if ((*param->item)->type() != Item::INT_ITEM ||
+ (*param->item)->val() < 0)
+ {
+ net_printf(&thd->net, ER_WRONG_PARAMETERS_TO_PROCEDURE, proc_name);
+ return 0;
+ }
+ pc->max_tree_elements = (uint) (*param->item)->val_int();
+ param = param->next;
+ if (param->next) // no third parameter possible
+ {
+ net_printf(&thd->net, ER_WRONG_PARAMCOUNT_TO_PROCEDURE, proc_name);
+ return 0;
+ }
+ // second parameter
+ if ((*param->item)->type() != Item::INT_ITEM ||
+ (*param->item)->val() < 0)
+ {
+ net_printf(&thd->net, ER_WRONG_PARAMETERS_TO_PROCEDURE, proc_name);
+ return 0;
+ }
+ pc->max_treemem = (uint) (*param->item)->val_int();
+ }
+ else if ((*param->item)->type() != Item::INT_ITEM ||
+ (*param->item)->val() < 0)
+ {
+ net_printf(&thd->net, ER_WRONG_PARAMETERS_TO_PROCEDURE, proc_name);
+ return 0;
+ }
+ // if only one parameter was given, it will be the value of max_tree_elements
+ else
+ {
+ pc->max_tree_elements = (uint) (*param->item)->val_int();
+ pc->max_treemem = MAX_TREEMEM;
+ }
+
+ if (!pc || !(pc->f_info = (field_info**)
+ sql_alloc(sizeof(field_info*)*field_list.elements)))
+ DBUG_RETURN(0);
+ pc->f_end = pc->f_info + field_list.elements;
+ pc->fields = field_list;
+
+ List_iterator<Item> it(pc->fields);
+ f_info = pc->f_info;
+
+ Item *item;
+ while ((item = it++))
+ {
+ if (item->result_type() == INT_RESULT)
+ {
+ // Check if fieldtype is ulonglong
+ if (item->type() == Item::FIELD_ITEM &&
+ ((Item_field*) item)->field->type() == FIELD_TYPE_LONGLONG &&
+ ((Field_longlong*) ((Item_field*) item)->field)->unsigned_flag)
+ *f_info++ = new field_ulonglong(item, pc);
+ else
+ *f_info++ = new field_longlong(item, pc);
+ }
+ if (item->result_type() == REAL_RESULT)
+ *f_info++ = new field_real(item, pc);
+ if (item->result_type() == STRING_RESULT)
+ *f_info++ = new field_str(item, pc);
+ }
+ return pc;
+} // proc_analyse_init
+
+
+// return 1 if number, else return 0
+// store info about found number in info
+// NOTE:It is expected, that elements of 'info' are all zero!
+bool test_if_number(NUM_INFO *info, const char *str, uint str_len)
+{
+ const char *begin, *end = str + str_len;
+
+ DBUG_ENTER("test_if_number");
+
+ // MySQL removes any endspaces of a string, so we must take care only of
+ // spaces in front of a string
+ for (; str != end && isspace(*str); str++) ;
+ if (str == end)
+ return 0;
+
+ if (*str == '-')
+ {
+ info->negative = 1;
+ if (++str == end || *str == '0') // converting -0 to a number
+ return 0; // might lose information
+ }
+ else
+ info->negative = 0;
+ begin = str;
+ for (; str != end && isdigit(*str); str++)
+ {
+ if (!info->integers && *str == '0' && (str + 1) != end &&
+ isdigit(*(str + 1)))
+ info->zerofill = 1; // could be a postnumber for example
+ info->integers++;
+ }
+ if (str == end && info->integers)
+ {
+ info->ullval = (ulonglong) strtoull(begin ,NULL, 10);
+ if (info->integers == 1)
+ return 0; // a single number can't be zerofill
+ info->maybe_zerofill = 1;
+ return 1; // a zerofill number, or an integer
+ }
+ if (*str == '.' || *str == 'e' || *str == 'E')
+ {
+ if (info->zerofill) // can't be zerofill anymore
+ return 0;
+ if ((str + 1) == end) // number was something like '123[.eE]'
+ {
+ info->ullval = (ulonglong) strtoull(begin, NULL, 10);
+ return 1;
+ }
+ if (*str == 'e' || *str == 'E') // number may be something like '1e+50'
+ {
+ str++;
+ if (*str != '-' && *str != '+')
+ return 0;
+ for (str++; str != end && isdigit(*str); str++) ;
+ if (str == end)
+ {
+ info->is_float = 1; // we can't use variable decimals here
+ return 1;
+ }
+ else
+ return 0;
+ }
+ for (str++; *(end - 1) == '0'; end--); // jump over zeros at the end
+ if (str == end) // number was something like '123.000'
+ {
+ info->ullval = (ulonglong) strtoull(begin, NULL, 10);
+ return 1;
+ }
+ for (; str != end && isdigit(*str); str++)
+ info->decimals++;
+ if (str == end)
+ {
+ info->dval = atod(begin);
+ return 1;
+ }
+ else
+ return 0;
+ }
+ else
+ return 0;
+} //test_if_number
+
+
+// Stores the biggest and the smallest value from current 'info'
+// to ev_num_info
+// If info contains an ulonglong number, which is bigger than
+// biggest positive number able to be stored in a longlong variable
+// and is marked as negative, function will return 0, else 1.
+
+bool get_ev_num_info(EV_NUM_INFO *ev_info, NUM_INFO *info, const char *num)
+{
+ if (info->negative)
+ {
+ if (((longlong) info->ullval) < 0)
+ return 0; // Impossible to store as a negative number
+ ev_info->llval = -(longlong) max((ulonglong) -ev_info->llval,
+ info->ullval);
+ ev_info->min_dval = (double) -max(-ev_info->min_dval, info->dval);
+ }
+ else // ulonglong is as big as bigint in MySQL
+ {
+ if ((check_ulonglong(num, info->integers) == REAL_NUM))
+ return 0;
+ ev_info->ullval = (ulonglong) max(ev_info->ullval, info->ullval);
+ ev_info->max_dval = (double) max(ev_info->max_dval, info->dval);
+ }
+ return 1;
+} // get_ev_num_info
+
+
+void free_string(String *s)
+{
+ s->free();
+}
+
+void field_str::add()
+{
+ char buff[MAX_FIELD_WIDTH], *ptr;
+ String s(buff, sizeof(buff)), *res;
+ ulong length;
+
+ if (!(res = item->val_str(&s)))
+ {
+ nulls++;
+ return;
+ }
+
+ if (!(length = res->length()))
+ empty++;
+ else
+ {
+ ptr = (char*) res->ptr();
+ if (*(ptr + (length - 1)) == ' ')
+ must_be_blob = 1;
+ }
+
+ if (can_be_still_num)
+ {
+ bzero((char*) &num_info, sizeof(num_info));
+ if (!test_if_number(&num_info, res->ptr(), (uint) length))
+ can_be_still_num = 0;
+ if (!found)
+ {
+ bzero((char*) &ev_num_info, sizeof(ev_num_info));
+ was_zero_fill = num_info.zerofill;
+ }
+ else if (num_info.zerofill != was_zero_fill && !was_maybe_zerofill)
+ can_be_still_num = 0; // one more check needed, when length is counted
+ if (can_be_still_num)
+ can_be_still_num = get_ev_num_info(&ev_num_info, &num_info, res->ptr());
+ was_maybe_zerofill = num_info.maybe_zerofill;
+ }
+
+ if (room_in_tree)
+ {
+ if (res != &s)
+ s.copy(*res);
+ if (!tree_search(&tree, (void*) &s)) // If not in tree
+ {
+ s.copy(); // slow, when SAFE_MALLOC is in use
+ if (!tree_insert(&tree, (void*) &s, 0))
+ {
+ room_in_tree = 0; // Remove tree, out of RAM ?
+ delete_tree(&tree);
+ }
+ else
+ {
+ bzero((char*) &s, sizeof(s)); // Let tree handle free of this
+ if ((treemem += length) > pc->max_treemem)
+ {
+ room_in_tree = 0; // Remove tree, too big tree
+ delete_tree(&tree);
+ }
+ }
+ }
+ }
+
+ if (!found)
+ {
+ found = 1;
+ min_arg.copy(*res);
+ max_arg.copy(*res);
+ min_length = max_length = length; sum=length;
+ }
+ else if (length)
+ {
+ sum += length;
+ if (length < min_length)
+ min_length = length;
+ if (length > max_length)
+ max_length = length;
+
+ if (item->binary)
+ {
+ if (stringcmp(res, &min_arg) < 0)
+ min_arg.copy(*res);
+ if (stringcmp(res, &max_arg) > 0)
+ max_arg.copy(*res);
+ }
+ else
+ {
+ if (sortcmp(res, &min_arg) < 0)
+ min_arg.copy(*res);
+ if (sortcmp(res, &max_arg) > 0)
+ max_arg.copy(*res);
+ }
+ }
+ if ((num_info.zerofill && (max_length != min_length)) ||
+ (was_zero_fill && (max_length != min_length)))
+ can_be_still_num = 0; // zerofilled numbers must be of same length
+} // field_str::add
+
+
+void field_real::add()
+{
+ char buff[MAX_FIELD_WIDTH], *ptr, *end;
+ double num = item->val();
+ uint length, zero_count, decs;
+ TREE_ELEMENT *element;
+
+ if (item->null_value)
+ {
+ nulls++;
+ return;
+ }
+ if (num == 0.0)
+ empty++;
+
+ if ((decs = decimals()) == NOT_FIXED_DEC)
+ {
+ sprintf(buff, "%g", num);
+ length = strlen(buff);
+ if (rint(num) != num)
+ max_notzero_dec_len = 1;
+ }
+ else
+ {
+ sprintf(buff, "%-.*f", (int) decs, num);
+ length = strlen(buff);
+
+ // We never need to check further than this
+ end = buff + length - 1 - decs + max_notzero_dec_len;
+
+ zero_count = 0;
+ for (ptr = buff + length - 1; ptr > end && *ptr == '0'; ptr--)
+ zero_count++;
+
+ if ((decs - zero_count > max_notzero_dec_len))
+ max_notzero_dec_len = decs - zero_count;
+ }
+
+ if (room_in_tree)
+ {
+ if (!(element = tree_insert(&tree, (void*) &num, 0)))
+ {
+ room_in_tree = 0; // Remove tree, out of RAM ?
+ delete_tree(&tree);
+ }
+ // if element->count == 1, this element can be found only once from tree
+ // if element->count == 2, or more, this element is already in tree
+ else if (element->count == 1 && (tree_elements++) > pc->max_tree_elements)
+ {
+ room_in_tree = 0; // Remove tree, too many elements
+ delete_tree(&tree);
+ }
+ }
+
+ if (!found)
+ {
+ found = 1;
+ min_arg = max_arg = sum = num;
+ sum_sqr = num * num;
+ min_length = max_length = length;
+ }
+ else if (num != 0.0)
+ {
+ sum += num;
+ sum_sqr += num * num;
+ if (length < min_length)
+ min_length = length;
+ if (length > max_length)
+ max_length = length;
+ if (compare_double(&num, &min_arg) < 0)
+ min_arg = num;
+ if (compare_double(&num, &max_arg) > 0)
+ max_arg = num;
+ }
+} // field_real::add
+
+void field_longlong::add()
+{
+ char buff[MAX_FIELD_WIDTH];
+ longlong num = item->val_int();
+ uint length = (uint) (longlong10_to_str(num, buff, -10) - buff);
+ TREE_ELEMENT *element;
+
+ if (item->null_value)
+ {
+ nulls++;
+ return;
+ }
+ if (num == 0)
+ empty++;
+
+ if (room_in_tree)
+ {
+ if (!(element = tree_insert(&tree, (void*) &num, 0)))
+ {
+ room_in_tree = 0; // Remove tree, out of RAM ?
+ delete_tree(&tree);
+ }
+ // if element->count == 1, this element can be found only once from tree
+ // if element->count == 2, or more, this element is already in tree
+ else if (element->count == 1 && (tree_elements++) > pc->max_tree_elements)
+ {
+ room_in_tree = 0; // Remove tree, too many elements
+ delete_tree(&tree);
+ }
+ }
+
+ if (!found)
+ {
+ found = 1;
+ min_arg = max_arg = sum = num;
+ sum_sqr = num * num;
+ min_length = max_length = length;
+ }
+ else if (num != 0)
+ {
+ sum += num;
+ sum_sqr += num * num;
+ if (length < min_length)
+ min_length = length;
+ if (length > max_length)
+ max_length = length;
+ if (compare_longlong(&num, &min_arg) < 0)
+ min_arg = num;
+ if (compare_longlong(&num, &max_arg) > 0)
+ max_arg = num;
+ }
+} // field_longlong::add
+
+
+void field_ulonglong::add()
+{
+ char buff[MAX_FIELD_WIDTH];
+ longlong num = item->val_int();
+ uint length = (uint) (longlong10_to_str(num, buff, 10) - buff);
+ TREE_ELEMENT *element;
+
+ if (item->null_value)
+ {
+ nulls++;
+ return;
+ }
+ if (num == 0)
+ empty++;
+
+ if (room_in_tree)
+ {
+ if (!(element = tree_insert(&tree, (void*) &num, 0)))
+ {
+ room_in_tree = 0; // Remove tree, out of RAM ?
+ delete_tree(&tree);
+ }
+ // if element->count == 1, this element can be found only once from tree
+ // if element->count == 2, or more, this element is already in tree
+ else if (element->count == 1 && (tree_elements++) > pc->max_tree_elements)
+ {
+ room_in_tree = 0; // Remove tree, too many elements
+ delete_tree(&tree);
+ }
+ }
+
+ if (!found)
+ {
+ found = 1;
+ min_arg = max_arg = sum = num;
+ sum_sqr = num * num;
+ min_length = max_length = length;
+ }
+ else if (num != 0)
+ {
+ sum += num;
+ sum_sqr += num * num;
+ if (length < min_length)
+ min_length = length;
+ if (length > max_length)
+ max_length = length;
+ if (compare_ulonglong((ulonglong*) &num, &min_arg) < 0)
+ min_arg = num;
+ if (compare_ulonglong((ulonglong*) &num, &max_arg) > 0)
+ max_arg = num;
+ }
+} // field_ulonglong::add
+
+
+int analyse::send_row(List<Item> &field_list __attribute__((unused)))
+{
+ field_info **f = f_info;
+
+ rows++;
+
+ for (;f != f_end; f++)
+ {
+ (*f)->add();
+ }
+ return 0;
+} // analyse::send_row
+
+
+bool analyse::end_of_records()
+{
+ field_info **f = f_info;
+ char buff[MAX_FIELD_WIDTH];
+ String *res, s_min(buff, sizeof(buff)), s_max(buff, sizeof(buff)),
+ ans(buff, sizeof(buff));
+
+ for (; f != f_end; f++)
+ {
+ func_items[0]->set((*f)->item->full_name());
+ if (!(*f)->found)
+ {
+ func_items[1]->null_value = 1;
+ func_items[2]->null_value = 1;
+ }
+ else
+ {
+ func_items[1]->null_value = 0;
+ res = (*f)->get_min_arg(&s_min);
+ func_items[1]->set(res->ptr(), res->length());
+ func_items[2]->null_value = 0;
+ res = (*f)->get_max_arg(&s_max);
+ func_items[2]->set(res->ptr(), res->length());
+ }
+ func_items[3]->set((longlong) (*f)->min_length);
+ func_items[4]->set((longlong) (*f)->max_length);
+ func_items[5]->set((longlong) (*f)->empty);
+ func_items[6]->set((longlong) (*f)->nulls);
+ res = (*f)->avg(&s_max, rows);
+ func_items[7]->set(res->ptr(), res->length());
+ func_items[8]->null_value = 0;
+ res = (*f)->std(&s_max, rows);
+ if (!res)
+ func_items[8]->null_value = 1;
+ else
+ func_items[8]->set(res->ptr(), res->length());
+ // count the dots, quotas, etc. in (ENUM("a","b","c"...))
+ // if tree has been removed, don't suggest ENUM.
+ // treemem is used to measure the size of tree for strings,
+ // tree_elements is used to count the elements in tree in case of numbers.
+ // max_treemem tells how long the string starting from ENUM("... and
+ // ending to ..") shall at maximum be. If case is about numbers,
+ // max_tree_elements will tell the length of the above, now
+ // every number is considered as length 1
+ if (((*f)->treemem || (*f)->tree_elements) &&
+ (*f)->tree.elements_in_tree &&
+ (((*f)->treemem ? max_treemem : max_tree_elements) >
+ (((*f)->treemem ? (*f)->treemem : (*f)->tree_elements) +
+ ((*f)->tree.elements_in_tree * 3 - 1 + 6))))
+ {
+ char tmp[331]; //331, because one double prec. num. can be this long
+ String tmp_str(tmp, sizeof(tmp));
+ TREE_INFO tree_info;
+
+ tree_info.str = &tmp_str;
+ tree_info.found = 0;
+ tree_info.item = (*f)->item;
+
+ tmp_str.set("ENUM(", 5);
+ tree_walk(&(*f)->tree, (*f)->collect_enum(), (char*) &tree_info,
+ left_root_right);
+ tmp_str.append(')');
+
+ if (!(*f)->nulls)
+ tmp_str.append(" NOT NULL");
+ output_str_length = tmp_str.length();
+ func_items[9]->set(tmp_str.ptr(), tmp_str.length());
+ if (result->send_data(result_fields))
+ return -1;
+ continue;
+ }
+
+ ans.length(0);
+ if (!(*f)->treemem && !(*f)->tree_elements)
+ ans.append("CHAR(0)", 7);
+ else if ((*f)->item->type() == Item::FIELD_ITEM)
+ {
+ switch (((Item_field*) (*f)->item)->field->real_type())
+ {
+ case FIELD_TYPE_TIMESTAMP:
+ ans.append("TIMESTAMP", 9);
+ break;
+ case FIELD_TYPE_DATETIME:
+ ans.append("DATETIME", 8);
+ break;
+ case FIELD_TYPE_DATE:
+ ans.append("DATE", 4);
+ break;
+ case FIELD_TYPE_SET:
+ ans.append("SET", 3);
+ break;
+ case FIELD_TYPE_YEAR:
+ ans.append("YEAR", 4);
+ break;
+ case FIELD_TYPE_TIME:
+ ans.append("TIME", 4);
+ break;
+ case FIELD_TYPE_NEWDATE:
+ ans.append("NEWDATE", 7);
+ break;
+ case FIELD_TYPE_DECIMAL:
+ ans.append("DECIMAL", 7);
+ // if item is FIELD_ITEM, it _must_be_ Field_num in this case
+ if (((Field_num*) (*f)->item)->zerofill)
+ ans.append(" ZEROFILL");
+ break;
+ default:
+ (*f)->get_opt_type(&ans, rows);
+ break;
+ }
+ }
+ if (!(*f)->nulls)
+ ans.append(" NOT NULL");
+ func_items[9]->set(ans.ptr(), ans.length());
+ if (result->send_data(result_fields))
+ return -1;
+ }
+ return 0;
+} // analyse::end_of_records
+
+
+void field_str::get_opt_type(String *answer, ha_rows total_rows)
+{
+ char buff[MAX_FIELD_WIDTH];
+
+ if (can_be_still_num)
+ {
+ if (num_info.is_float)
+ sprintf(buff, "DOUBLE"); // number was like 1e+50... TODO:
+ else if (num_info.decimals) // DOUBLE(%d,%d) sometime
+ {
+ if (num_info.dval > -FLT_MAX && num_info.dval < FLT_MAX)
+ sprintf(buff, "FLOAT(%d,%d)", num_info.integers, num_info.decimals);
+ else
+ sprintf(buff, "DOUBLE(%d,%d)", num_info.integers, num_info.decimals);
+ }
+ else if (ev_num_info.llval >= -128 &&
+ ev_num_info.ullval <=
+ (ulonglong) (ev_num_info.llval >= 0 ? 255 : 127))
+ sprintf(buff, "TINYINT(%d)", num_info.integers);
+ else if (ev_num_info.llval >= INT_MIN16 &&
+ ev_num_info.ullval <= (ulonglong) (ev_num_info.llval >= 0 ?
+ UINT_MAX16 : INT_MAX16))
+ sprintf(buff, "SMALLINT(%d)", num_info.integers);
+ else if (ev_num_info.llval >= INT_MIN24 &&
+ ev_num_info.ullval <= (ulonglong) (ev_num_info.llval >= 0 ?
+ UINT_MAX24 : INT_MAX24))
+ sprintf(buff, "MEDIUMINT(%d)", num_info.integers);
+ else if (ev_num_info.llval >= INT_MIN32 &&
+ ev_num_info.ullval <= (ulonglong) (ev_num_info.llval >= 0 ?
+ UINT_MAX32 : INT_MAX32))
+ sprintf(buff, "INT(%d)", num_info.integers);
+ else
+ sprintf(buff, "BIGINT(%d)", num_info.integers);
+ answer->append(buff, strlen(buff));
+ if (ev_num_info.llval >= 0 && ev_num_info.min_dval >= 0)
+ answer->append(" UNSIGNED");
+ if (num_info.zerofill)
+ answer->append(" ZEROFILL");
+ }
+ else if (max_length < 256)
+ {
+ if (must_be_blob)
+ {
+ if (item->binary)
+ answer->append("TINYBLOB", 8);
+ else
+ answer->append("TINYTEXT", 8);
+ }
+ else if ((max_length * (total_rows - nulls)) < (sum + total_rows))
+ {
+ sprintf(buff, "CHAR(%d)", (int) max_length);
+ answer->append(buff, strlen(buff));
+ }
+ else
+ {
+ sprintf(buff, "VARCHAR(%d)", (int) max_length);
+ answer->append(buff, strlen(buff));
+ }
+ }
+ else if (max_length < (1L << 16))
+ {
+ if (item->binary)
+ answer->append("BLOB", 4);
+ else
+ answer->append("TEXT", 4);
+ }
+ else if (max_length < (1L << 24))
+ {
+ if (item->binary)
+ answer->append("MEDIUMBLOB", 10);
+ else
+ answer->append("MEDIUMTEXT", 10);
+ }
+ else
+ {
+ if (item->binary)
+ answer->append("LONGBLOB", 8);
+ else
+ answer->append("LONGTEXT", 8);
+ }
+} // field_str::get_opt_type
+
+
+void field_real::get_opt_type(String *answer,
+ ha_rows total_rows __attribute__((unused)))
+{
+ char buff[MAX_FIELD_WIDTH];
+
+ if (!max_notzero_dec_len)
+ {
+ if (min_arg >= -128 && max_arg <= (min_arg >= 0 ? 255 : 127))
+ sprintf(buff, "TINYINT(%d)", (int) max_length - (item->decimals + 1));
+ else if (min_arg >= INT_MIN16 && max_arg <= (min_arg >= 0 ?
+ UINT_MAX16 : INT_MAX16))
+ sprintf(buff, "SMALLINT(%d)", (int) max_length - (item->decimals + 1));
+ else if (min_arg >= INT_MIN24 && max_arg <= (min_arg >= 0 ?
+ UINT_MAX24 : INT_MAX24))
+ sprintf(buff, "MEDIUMINT(%d)", (int) max_length - (item->decimals + 1));
+ else if (min_arg >= INT_MIN32 && max_arg <= (min_arg >= 0 ?
+ UINT_MAX32 : INT_MAX32))
+ sprintf(buff, "INT(%d)", (int) max_length - (item->decimals + 1));
+ else
+ sprintf(buff, "BIGINT(%d)", (int) max_length - (item->decimals + 1));
+ answer->append(buff, strlen(buff));
+ if (min_arg >= 0)
+ answer->append(" UNSIGNED");
+ }
+ else
+ {
+ if (min_arg >= -FLT_MAX && max_arg <= FLT_MAX)
+ sprintf(buff, "FLOAT(%d,%d)", (int) max_length - (item->decimals + 1),
+ max_notzero_dec_len);
+ else
+ sprintf(buff, "DOUBLE(%d,%d)", (int) max_length - (item->decimals + 1),
+ max_notzero_dec_len);
+ answer->append(buff, strlen(buff));
+ }
+ // if item is FIELD_ITEM, it _must_be_ Field_num in this class
+ if (item->type() == Item::FIELD_ITEM &&
+ // a single number shouldn't be zerofill
+ (max_length - (item->decimals + 1)) != 1 &&
+ ((Field_num*) ((Item_field*) item)->field)->zerofill)
+ answer->append(" ZEROFILL");
+} // field_real::get_opt_type
+
+
+void field_longlong::get_opt_type(String *answer,
+ ha_rows total_rows __attribute__((unused)))
+{
+ char buff[MAX_FIELD_WIDTH];
+
+ if (min_arg >= -128 && max_arg <= (min_arg >= 0 ? 255 : 127))
+ sprintf(buff, "TINYINT(%d)", (int) max_length);
+ else if (min_arg >= INT_MIN16 && max_arg <= (min_arg >= 0 ?
+ UINT_MAX16 : INT_MAX16))
+ sprintf(buff, "SMALLINT(%d)", (int) max_length);
+ else if (min_arg >= INT_MIN24 && max_arg <= (min_arg >= 0 ?
+ UINT_MAX24 : INT_MAX24))
+ sprintf(buff, "MEDIUMINT(%d)", (int) max_length);
+ else if (min_arg >= INT_MIN32 && max_arg <= (min_arg >= 0 ?
+ UINT_MAX32 : INT_MAX32))
+ sprintf(buff, "INT(%d)", (int) max_length);
+ else
+ sprintf(buff, "BIGINT(%d)", (int) max_length);
+ answer->append(buff, strlen(buff));
+ if (min_arg >= 0)
+ answer->append(" UNSIGNED");
+
+ // if item is FIELD_ITEM, it _must_be_ Field_num in this class
+ if ((item->type() == Item::FIELD_ITEM) &&
+ // a single number shouldn't be zerofill
+ max_length != 1 &&
+ ((Field_num*) ((Item_field*) item)->field)->zerofill)
+ answer->append(" ZEROFILL");
+} // field_longlong::get_opt_type
+
+
+void field_ulonglong::get_opt_type(String *answer,
+ ha_rows total_rows __attribute__((unused)))
+{
+ char buff[MAX_FIELD_WIDTH];
+
+ if (max_arg < 256)
+ sprintf(buff, "TINYINT(%d) UNSIGNED", (int) max_length);
+ else if (max_arg <= ((2 * INT_MAX16) + 1))
+ sprintf(buff, "SMALLINT(%d) UNSIGNED", (int) max_length);
+ else if (max_arg <= ((2 * INT_MAX24) + 1))
+ sprintf(buff, "MEDIUMINT(%d) UNSIGNED", (int) max_length);
+ else if (max_arg < (((ulonglong) 1) << 32))
+ sprintf(buff, "INT(%d) UNSIGNED", (int) max_length);
+ else
+ sprintf(buff, "BIGINT(%d) UNSIGNED", (int) max_length);
+ // if item is FIELD_ITEM, it _must_be_ Field_num in this class
+ answer->append(buff, strlen(buff));
+ if (item->type() == Item::FIELD_ITEM &&
+ // a single number shouldn't be zerofill
+ max_length != 1 &&
+ ((Field_num*) ((Item_field*) item)->field)->zerofill)
+ answer->append(" ZEROFILL");
+} //field_ulonglong::get_opt_type
+
+
+int collect_string(String *element,
+ element_count count __attribute__((unused)),
+ TREE_INFO *info)
+{
+ if (info->found)
+ info->str->append(',');
+ else
+ info->found = 1;
+ info->str->append('\'');
+ info->str->append(*element);
+ info->str->append('\'');
+ return 0;
+} // collect_string
+
+
+int collect_real(double *element, element_count count __attribute__((unused)),
+ TREE_INFO *info)
+{
+ char buff[255];
+ String s(buff, sizeof(buff));
+
+ if (info->found)
+ info->str->append(',');
+ else
+ info->found = 1;
+ info->str->append('\'');
+ s.set(*element, info->item->decimals);
+ info->str->append(s);
+ info->str->append('\'');
+ return 0;
+} // collect_real
+
+
+int collect_longlong(longlong *element,
+ element_count count __attribute__((unused)),
+ TREE_INFO *info)
+{
+ char buff[255];
+ String s(buff, sizeof(buff));
+
+ if (info->found)
+ info->str->append(',');
+ else
+ info->found = 1;
+ info->str->append('\'');
+ s.set(*element);
+ info->str->append(s);
+ info->str->append('\'');
+ return 0;
+} // collect_longlong
+
+
+int collect_ulonglong(ulonglong *element,
+ element_count count __attribute__((unused)),
+ TREE_INFO *info)
+{
+ char buff[255];
+ String s(buff, sizeof(buff));
+
+ if (info->found)
+ info->str->append(',');
+ else
+ info->found = 1;
+ info->str->append('\'');
+ s.set(*element);
+ info->str->append(s);
+ info->str->append('\'');
+ return 0;
+} // collect_ulonglong
+
+
+bool analyse::change_columns(List<Item> &field_list)
+{
+ field_list.empty();
+
+ func_items[0] = new Item_proc_string("Field_name", 255);
+ func_items[1] = new Item_proc_string("Min_value", 255);
+ func_items[1]->maybe_null = 1;
+ func_items[2] = new Item_proc_string("Max_value", 255);
+ func_items[2]->maybe_null = 1;
+ func_items[3] = new Item_proc_int("Min_length");
+ func_items[4] = new Item_proc_int("Max_length");
+ func_items[5] = new Item_proc_int("Empties_or_zeros");
+ func_items[6] = new Item_proc_int("Nulls");
+ func_items[7] = new Item_proc_string("Avg_value_or_avg_length", 255);
+ func_items[8] = new Item_proc_string("Std", 255);
+ func_items[8]->maybe_null = 1;
+ func_items[9] = new Item_proc_string("Optimal_fieldtype",
+ max(64, output_str_length));
+
+ for (uint i = 0; i < array_elements(func_items); i++)
+ field_list.push_back(func_items[i]);
+ result_fields = field_list;
+ return 0;
+} // analyse::change_columns
+
+int compare_double(const double *s, const double *t)
+{
+ return ((*s < *t) ? -1 : *s > *t ? 1 : 0);
+} /* compare_double */
+
+int compare_longlong(const longlong *s, const longlong *t)
+{
+ return ((*s < *t) ? -1 : *s > *t ? 1 : 0);
+} /* compare_longlong */
+
+ int compare_ulonglong(const ulonglong *s, const ulonglong *t)
+{
+ return ((*s < *t) ? -1 : *s > *t ? 1 : 0);
+} /* compare_ulonglong */
+
+
+uint check_ulonglong(const char *str, uint length)
+{
+ const char *long_str = "2147483647", *ulonglong_str = "18446744073709551615";
+ const uint long_len = 10, ulonglong_len = 20;
+
+ while (*str == '0' && length)
+ {
+ str++; length--;
+ }
+ if (length < long_len)
+ return NUM;
+
+ uint smaller, bigger;
+ const char *cmp;
+
+ if (length == long_len)
+ {
+ cmp = long_str;
+ smaller = NUM;
+ bigger = LONG_NUM;
+ }
+ else if (length > ulonglong_len)
+ return REAL_NUM;
+ else
+ {
+ cmp = ulonglong_str;
+ smaller = LONG_NUM;
+ bigger = REAL_NUM;
+ }
+ while (*cmp && *cmp++ == *str++) ;
+ return ((uchar) str[-1] <= (uchar) cmp[-1]) ? smaller : bigger;
+} /* check_ulonlong */
diff --git a/sql/sql_analyse.h b/sql/sql_analyse.h
new file mode 100644
index 00000000000..f9cedcde2f6
--- /dev/null
+++ b/sql/sql_analyse.h
@@ -0,0 +1,292 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+
+/* Analyse database */
+
+#ifdef __GNUC__
+#pragma interface /* gcc class implementation */
+#endif
+
+#include <my_tree.h>
+
+#define DEC_IN_AVG 4
+
+typedef struct st_number_info
+{
+ // if zerofill is true, the number must be zerofill, or string
+ bool negative, is_float, zerofill, maybe_zerofill;
+ int8 integers;
+ int8 decimals;
+ double dval;
+ ulonglong ullval;
+} NUM_INFO;
+
+typedef struct st_extreme_value_number_info
+{
+ ulonglong ullval;
+ longlong llval;
+ double max_dval, min_dval;
+} EV_NUM_INFO;
+
+typedef struct st_tree_info
+{
+ bool found;
+ String *str;
+ Item *item;
+} TREE_INFO;
+
+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 strlen);
+int compare_double(const double *s, const double *t);
+int compare_longlong(const longlong *s, const longlong *t);
+int compare_ulonglong(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*);
+class analyse;
+
+class field_info :public Sql_alloc
+{
+protected:
+ ulong treemem, tree_elements, empty, nulls, min_length, max_length;
+ uint room_in_tree;
+ my_bool found;
+ TREE tree;
+ Item *item;
+ analyse *pc;
+
+public:
+ field_info(Item* a, analyse* b) : treemem(0), tree_elements(0), empty(0),
+ nulls(0), min_length(0), max_length(0), room_in_tree(1),
+ found(0),item(a), pc(b) {};
+
+ virtual ~field_info() { delete_tree(&tree); }
+ virtual void add() = 0;
+ virtual void get_opt_type(String*, ha_rows) = 0;
+ virtual String *get_min_arg(String *) = 0;
+ virtual String *get_max_arg(String *) = 0;
+ virtual String *avg(String*, ha_rows) = 0;
+ virtual String *std(String*, ha_rows) = 0;
+ virtual tree_walk_action collect_enum() = 0;
+ virtual uint decimals() { return 0; }
+ friend class analyse;
+};
+
+
+class field_str :public field_info
+{
+ String min_arg, max_arg;
+ ulonglong sum;
+ bool must_be_blob, was_zero_fill, was_maybe_zerofill,
+ can_be_still_num;
+ NUM_INFO num_info;
+ EV_NUM_INFO ev_num_info;
+
+public:
+ field_str(Item* a, analyse* b) :field_info(a,b), min_arg(""),
+ 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); };
+
+ void add();
+ void get_opt_type(String*, ha_rows);
+ String *get_min_arg(String *not_used __attribute__((unused)))
+ { return &min_arg; }
+ String *get_max_arg(String *not_used __attribute__((unused)))
+ { return &max_arg; }
+ String *avg(String *s, ha_rows rows)
+ {
+ if (!(rows - nulls))
+ s->set((double) 0.0, 1);
+ else
+ s->set((ulonglong2double(sum) / ulonglong2double(rows - nulls)),
+ DEC_IN_AVG);
+ return s;
+ }
+ friend int collect_string(String *element, element_count count,
+ TREE_INFO *info);
+ tree_walk_action collect_enum()
+ { return (tree_walk_action) collect_string; }
+ String *std(String *s __attribute__((unused)),
+ ha_rows rows __attribute__((unused)))
+ { return (String*) 0; }
+};
+
+class field_real: public field_info
+{
+ double min_arg, max_arg;
+ double sum, sum_sqr;
+ uint max_notzero_dec_len;
+
+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); }
+
+ void add();
+ void get_opt_type(String*, ha_rows);
+ String *get_min_arg(String *s) { s->set(min_arg, item->decimals); return s; }
+ String *get_max_arg(String *s) { s->set(max_arg, item->decimals); return s; }
+ String *avg(String *s, ha_rows rows)
+ {
+ if (!(rows - nulls))
+ s->set((double) 0.0, 1);
+ else
+ s->set(((double)sum / (double) (rows - nulls)), item->decimals);
+ return s;
+ }
+ String *std(String *s, ha_rows rows)
+ {
+ double tmp = ulonglong2double(rows);
+ if (!(tmp - nulls))
+ s->set((double) 0.0, 1);
+ else
+ {
+ double tmp2 = ((sum_sqr - sum * sum / (tmp - nulls)) /
+ (tmp - nulls));
+ s->set(((double) tmp2 <= 0.0 ? 0.0 : sqrt(tmp2)), item->decimals);
+ }
+ return s;
+ }
+ uint decimals() { return item->decimals; }
+ friend int collect_real(double *element, element_count count,
+ TREE_INFO *info);
+ tree_walk_action collect_enum()
+ { return (tree_walk_action) collect_real;}
+};
+
+class field_longlong: public field_info
+{
+ longlong min_arg, max_arg;
+ longlong sum, sum_sqr;
+
+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); }
+
+ void add();
+ void get_opt_type(String*, ha_rows);
+ String *get_min_arg(String *s) { s->set(min_arg); return s; }
+ String *get_max_arg(String *s) { s->set(max_arg); return s; }
+ String *avg(String *s, ha_rows rows)
+ {
+ if (!(rows - nulls))
+ s->set((double) 0.0, 1);
+ else
+ s->set(((double) sum / (double) (rows - nulls)), DEC_IN_AVG);
+ return s;
+ }
+ String *std(String *s, ha_rows rows)
+ {
+ double tmp = ulonglong2double(rows);
+ if (!(tmp - nulls))
+ s->set((double) 0.0, 1);
+ else
+ {
+ double tmp2 = ((sum_sqr - sum * sum / (tmp - nulls)) /
+ (tmp - nulls));
+ s->set(((double) tmp2 <= 0.0 ? 0.0 : sqrt(tmp2)), DEC_IN_AVG);
+ }
+ return s;
+ }
+ friend int collect_longlong(longlong *element, element_count count,
+ TREE_INFO *info);
+ tree_walk_action collect_enum()
+ { return (tree_walk_action) collect_longlong;}
+};
+
+
+class field_ulonglong: public field_info
+{
+ ulonglong min_arg, max_arg;
+ ulonglong sum, sum_sqr;
+
+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); }
+ void add();
+ void get_opt_type(String*, ha_rows);
+ String *get_min_arg(String *s) { s->set(min_arg); return s; }
+ String *get_max_arg(String *s) { s->set(max_arg); return s; }
+ String *avg(String *s, ha_rows rows)
+ {
+ if (!(rows - nulls))
+ s->set((double) 0.0, 1);
+ else
+ s->set((ulonglong2double(sum) / ulonglong2double(rows - nulls)),
+ DEC_IN_AVG);
+ return s;
+ }
+ String *std(String *s, ha_rows rows)
+ {
+ double tmp = ulonglong2double(rows);
+ if (!(tmp - nulls))
+ s->set((double) 0.0, 1);
+ else
+ {
+ double tmp2 = ((ulonglong2double(sum_sqr) -
+ ulonglong2double(sum * sum) / (tmp - nulls)) /
+ (tmp - nulls));
+ s->set(((double) tmp2 <= 0.0 ? 0.0 : sqrt(tmp2)), DEC_IN_AVG);
+ }
+ return s;
+ }
+ friend int collect_ulonglong(ulonglong *element, element_count count,
+ TREE_INFO *info);
+ tree_walk_action collect_enum()
+ { return (tree_walk_action) collect_ulonglong; }
+};
+
+
+class analyse: public Procedure
+{
+protected:
+ Item_proc *func_items[10];
+ List<Item> fields, result_fields;
+ field_info **f_info, **f_end;
+ ha_rows rows;
+ uint output_str_length;
+
+public:
+ uint max_tree_elements, max_treemem;
+
+ analyse(select_result *res) :Procedure(res, PROC_NO_SORT), rows(0),
+ output_str_length(0) {}
+
+ ~analyse()
+ {
+ for (field_info **f=f_info; f != f_end; f++)
+ delete (*f);
+ }
+ virtual void add() {}
+ virtual bool change_columns(List<Item> &fields);
+ virtual int send_row(List<Item> &fields);
+ virtual void end_group(void) {}
+ virtual bool end_of_records(void);
+ friend Procedure *proc_analyse_init(THD *thd, ORDER *param,
+ select_result *result,
+ List<Item> &field_list);
+};
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
new file mode 100644
index 00000000000..4b245b29e83
--- /dev/null
+++ b/sql/sql_base.cc
@@ -0,0 +1,2174 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+
+/* Basic functions neaded by many modules */
+
+#include "mysql_priv.h"
+#include "sql_acl.h"
+#include <thr_alarm.h>
+#include <m_ctype.h>
+#include <my_dir.h>
+#include <hash.h>
+#include <nisam.h>
+#include <assert.h>
+#ifdef __WIN__
+#include <io.h>
+#endif
+
+#define MAX_DBKEY_LENGTH (FN_LEN*2+2)
+
+static int key_cache_used=0;
+TABLE *unused_tables; /* Used by mysql_test */
+HASH open_cache; /* Used by mysql_test */
+
+
+static int open_unireg_entry(TABLE *entry,const char *db,const char *name,
+ const char *alias);
+static bool insert_fields(THD *thd,TABLE_LIST *tables, 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(THD *thd, TABLE *table,
+ List<String> *index_list);
+
+static int send_file(THD *thd)
+{
+ NET* net = &thd->net;
+ int fd = -1,bytes, error = 1;
+ uint packet_len;
+ char fname[FN_REFLEN+1];
+ char buf[IO_SIZE*15];
+ const char *errmsg = 0;
+ int old_timeout;
+ DBUG_ENTER("send_file");
+
+ // the client might be slow loading the data, give him wait_timeout to do
+ // the job
+ old_timeout = thd->net.timeout;
+ thd->net.timeout = thd->inactive_timeout;
+
+ // 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";
+ goto err;
+ }
+
+ fn_format(fname, (char*)net->read_pos + 1, "", "", 4);
+ if(!strcmp(fname,"/dev/null")) goto end; // this is needed to make replicate-ignore-db
+ // work on the well-known system that does not have a /dev/null :-)
+
+ if ((fd = my_open(fname, O_RDONLY, MYF(MY_WME))) < 0)
+ {
+ errmsg = "Failed on my_open()";
+ goto err;
+ }
+
+ while ((bytes = (int) my_read(fd, (byte*) buf, sizeof(buf),
+ MYF(MY_WME))) > 0)
+ {
+ if (my_net_write(net, buf, bytes))
+ {
+ errmsg = "Failed on my_net_write()";
+ goto err;
+ }
+ }
+
+ end:
+ if (my_net_write(net, "", 0) || net_flush(net) ||
+ (my_net_read(net) == packet_error))
+ {
+ errmsg = "failed 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 (errmsg)
+ {
+ sql_print_error("failed in send_file() : %s", errmsg);
+ DBUG_PRINT("error", (errmsg));
+ }
+ DBUG_RETURN(error);
+}
+
+static byte *cache_key(const byte *record,uint *length,
+ my_bool not_used __attribute__((unused)))
+{
+ TABLE *entry=(TABLE*) record;
+ *length=entry->key_length;
+ return (byte*) entry->table_cache_key;
+}
+
+void table_cache_init(void)
+{
+ VOID(hash_init(&open_cache,table_cache_size,0,0,cache_key,
+ (void (*)(void*)) free_cache_entry,0));
+ mysql_rm_tmp_tables();
+}
+
+
+void table_cache_free(void)
+{
+ DBUG_ENTER("table_cache_free");
+ close_cached_tables(0);
+ if (!open_cache.records) // Safety first
+ hash_free(&open_cache);
+ DBUG_VOID_RETURN;
+}
+
+
+uint cached_tables(void)
+{
+ return open_cache.records;
+}
+
+#ifdef EXTRA_DEBUG
+static void check_unused(void)
+{
+ uint count=0,idx=0;
+ TABLE *cur_link,*start_link;
+
+ if ((start_link=cur_link=unused_tables))
+ {
+ do
+ {
+ if (cur_link != cur_link->next->prev || cur_link != cur_link->prev->next)
+ {
+ DBUG_PRINT("error",("Unused_links aren't linked properly")); /* purecov: inspected */
+ return; /* purecov: inspected */
+ }
+ } while (count++ < open_cache.records &&
+ (cur_link=cur_link->next) != start_link);
+ if (cur_link != start_link)
+ {
+ DBUG_PRINT("error",("Unused_links aren't connected")); /* purecov: inspected */
+ }
+ }
+ for (idx=0 ; idx < open_cache.records ; idx++)
+ {
+ TABLE *entry=(TABLE*) hash_element(&open_cache,idx);
+ if (!entry->in_use)
+ count--;
+ }
+ if (count != 0)
+ {
+ DBUG_PRINT("error",("Unused_links dosen't match open_cache: diff: %d", /* purecov: inspected */
+ count)); /* purecov: inspected */
+ }
+}
+#else
+#define check_unused()
+#endif
+
+void mysql_binlog_send(THD* thd, char* log_ident, ulong pos, ushort flags)
+{
+ LOG_INFO linfo;
+ char *log_file_name = linfo.log_file_name;
+ char search_file_name[FN_REFLEN];
+ FILE* log = NULL;
+ String* packet = &thd->packet;
+ int error;
+ const char *errmsg = "Unknown error";
+ NET* net = &thd->net;
+
+ DBUG_ENTER("mysql_binlog_send");
+
+ if(!mysql_bin_log.is_open())
+ {
+ errmsg = "Binary log is not open";
+ goto err;
+ }
+
+ if(log_ident[0])
+ mysql_bin_log.make_log_name(search_file_name, log_ident);
+ else
+ search_file_name[0] = 0;
+
+ if(mysql_bin_log.find_first_log(&linfo, search_file_name))
+ {
+ errmsg = "Could not find first log";
+ goto err;
+ }
+ log = my_fopen(log_file_name, O_RDONLY, MYF(MY_WME));
+
+ if(!log)
+ {
+ errmsg = "Could not open log file";
+ goto err;
+ }
+
+ if(my_fseek(log, pos, MY_SEEK_SET, MYF(MY_WME)) == MY_FILEPOS_ERROR )
+ {
+ errmsg = "Error on fseek()";
+ goto err;
+ }
+
+
+ packet->length(0);
+ packet->append("\0", 1); // we need to start a packet with something other than 255
+ // to distiquish it from error
+
+ while(!net->error && net->vio != 0 && !thd->killed)
+ {
+ while(!(error = Log_event::read_log_event(log, packet)))
+ {
+ if(my_net_write(net, (char*)packet->ptr(), packet->length()) )
+ {
+ errmsg = "Failed on my_net_write()";
+ goto err;
+ }
+ DBUG_PRINT("info", ("log event code %d",(*packet)[LOG_EVENT_OFFSET+1] ));
+ if((*packet)[LOG_EVENT_OFFSET+1] == LOAD_EVENT)
+ {
+ if(send_file(thd))
+ {
+ errmsg = "failed in send_file()";
+ goto err;
+ }
+ }
+ packet->length(0);
+ packet->append("\0",1);
+ }
+ if(error != LOG_READ_EOF)
+ {
+ errmsg = "error reading log event";
+ goto err;
+ }
+
+ 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))
+ {
+ errmsg = "failed on net_flush()";
+ goto err;
+ }
+
+ // we may have missed the update broadcast from the log
+ // that has just happened, let's try to catch it if it did
+ // if we did not miss anything, we just wait for other threads
+ // to signal us
+ {
+ pthread_mutex_t *log_lock = mysql_bin_log.get_log_lock();
+ clearerr(log);
+
+ // tell the kill thread how to wake us up
+ pthread_mutex_lock(&thd->mysys_var->mutex);
+ 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 = "Waiting for update";
+ pthread_mutex_unlock(&thd->mysys_var->mutex);
+
+ bool read_packet = 0, fatal_error = 0;
+
+ pthread_mutex_lock(log_lock); // no one will update the log while we are reading
+ // now, but we'll be quick and just read one record
+
+
+ switch(Log_event::read_log_event(log, packet))
+ {
+ case 0:
+ read_packet = 1; // we read successfully, so we'll need to send it to the
+ // slave
+ break;
+ case LOG_READ_EOF:
+ pthread_cond_wait(&COND_binlog_update, log_lock);
+ break;
+
+ default:
+ 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(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(send_file(thd))
+ {
+ errmsg = "failed in send_file()";
+ goto err;
+ }
+ }
+ packet->length(0);
+ packet->append("\0",1);
+ // no need to net_flush because we will get to flush later when
+ // we hit EOF pretty quick
+ }
+
+ if(fatal_error)
+ {
+ errmsg = "error reading log entry";
+ goto err;
+ }
+
+ clearerr(log);
+ }
+ }
+ else
+ {
+ bool loop_breaker = 0; // need this to break out of the for loop from switch
+
+ switch(mysql_bin_log.find_next_log(&linfo))
+ {
+ case LOG_INFO_EOF:
+ loop_breaker = (flags & BINLOG_DUMP_NON_BLOCK);
+ break;
+ case 0:
+ break;
+ default:
+ errmsg = "could not find next log";
+ goto err;
+ }
+
+ if(loop_breaker)
+ break;
+
+ (void) my_fclose(log, MYF(MY_WME));
+ log = my_fopen(log_file_name, O_RDONLY, MYF(MY_WME));
+ if(!log)
+ goto err;
+ // fake Rotate_log event just in case it did not make it to the log
+ // otherwise the slave make get confused about the offset
+ {
+ char header[9];
+ memset(header, 0, 4); // when does not matter
+ header[4] = ROTATE_EVENT;
+ char* p = strrchr(log_file_name, FN_LIBCHAR); // find the last slash
+ if(p)
+ p++;
+ else
+ p = log_file_name;
+
+ uint ident_len = strlen(p);
+ ulong event_len = ident_len + sizeof(header);
+ int4store(header + 5, event_len);
+ packet->append(header, sizeof(header));
+ packet->append(p,ident_len);
+ if(my_net_write(net, (char*)packet->ptr(), packet->length()))
+ {
+ errmsg = "failed on my_net_write()";
+ goto err;
+ }
+ packet->length(0);
+ packet->append("\0",1);
+ }
+ }
+ }
+
+ (void)my_fclose(log, MYF(MY_WME));
+
+ send_eof(&thd->net);
+ DBUG_VOID_RETURN;
+ err:
+ if(log)
+ (void) my_fclose(log, MYF(MY_WME));
+ send_error(&thd->net, 0, errmsg);
+ DBUG_VOID_RETURN;
+}
+
+
+/******************************************************************************
+** Send name and type of result to client.
+** Sum fields has table name empty and field_name.
+******************************************************************************/
+
+bool
+send_fields(THD *thd,List<Item> &list,uint flag)
+{
+ List_iterator<Item> it(list);
+ Item *item;
+ char buff[80];
+ CONVERT *convert=thd->convert_set;
+
+ String tmp((char*) buff,sizeof(buff)),*res,*packet= &thd->packet;
+
+ if (thd->fatal_error) // We have got an error
+ goto err;
+
+ if (flag & 1)
+ { // Packet with number of elements
+ char *pos=net_store_length(buff,(uint) list.elements);
+ (void) my_net_write(&thd->net, buff,(uint) (pos-buff));
+ }
+ while ((item=it++))
+ {
+ char *pos;
+ Send_field field;
+ item->make_field(&field);
+ packet->length(0);
+
+ if (convert)
+ {
+ if (convert->store(packet,field.table_name,strlen(field.table_name)) ||
+ convert->store(packet,field.col_name, strlen(field.col_name)) ||
+ packet->realloc(packet->length()+10))
+ goto err;
+ }
+ else if (net_store_data(packet,field.table_name) ||
+ net_store_data(packet,field.col_name) ||
+ packet->realloc(packet->length()+10))
+ goto err; /* purecov: inspected */
+ pos= (char*) packet->ptr()+packet->length();
+
+ if (!(thd->client_capabilities & CLIENT_LONG_FLAG))
+ {
+ packet->length(packet->length()+9);
+ pos[0]=3; int3store(pos+1,field.length);
+ pos[4]=1; pos[5]=field.type;
+ pos[6]=2; pos[7]=(char) field.flags; pos[8]= (char) field.decimals;
+ }
+ else
+ {
+ packet->length(packet->length()+10);
+ pos[0]=3; int3store(pos+1,field.length);
+ pos[4]=1; pos[5]=field.type;
+ pos[6]=3; int2store(pos+7,field.flags); pos[9]= (char) field.decimals;
+ }
+ if (flag & 2)
+ { // Send default value
+ if (!(res=item->val_str(&tmp)))
+ {
+ if (net_store_null(packet))
+ goto err;
+ }
+ else if (net_store_data(packet,res->ptr(),res->length()))
+ goto err;
+ }
+ 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);
+ return 0;
+ err:
+ send_error(&thd->net,ER_OUT_OF_RESOURCES); /* purecov: inspected */
+ return 1; /* purecov: inspected */
+}
+
+
+/*****************************************************************************
+ * Functions to free open table cache
+ ****************************************************************************/
+
+
+void intern_close_table(TABLE *table)
+{ // Free all structures
+ free_io_cache(table);
+ if (table->file)
+ VOID(closefrm(table)); // close file
+}
+
+
+static void free_cache_entry(TABLE *table)
+{
+ DBUG_ENTER("free_cache_entry");
+
+ intern_close_table(table);
+ if (!table->in_use)
+ {
+ table->next->prev=table->prev; /* remove from used chain */
+ table->prev->next=table->next;
+ if (table == unused_tables)
+ {
+ unused_tables=unused_tables->next;
+ if (table == unused_tables)
+ unused_tables=0;
+ }
+ check_unused(); // consisty check
+ }
+ my_free((gptr) table,MYF(0));
+ DBUG_VOID_RETURN;
+}
+
+
+void free_io_cache(TABLE *table)
+{
+ if (table->io_cache)
+ {
+ close_cached_file(table->io_cache);
+ my_free((gptr) table->io_cache,MYF(0));
+ table->io_cache=0;
+ }
+ if (table->record_pointers)
+ {
+ my_free((gptr) table->record_pointers,MYF(0));
+ table->record_pointers=0;
+ }
+}
+
+ /* Close all tables which aren't in use by any thread */
+
+bool close_cached_tables(bool if_wait_for_refresh)
+{
+ bool result=0;
+ DBUG_ENTER("close_cached_tables");
+
+ VOID(pthread_mutex_lock(&LOCK_open));
+ while (unused_tables)
+ {
+#ifdef EXTRA_DEBUG
+ if (hash_delete(&open_cache,(byte*) unused_tables))
+ printf("Warning: Couldn't delete open table from hash\n");
+#else
+ VOID(hash_delete(&open_cache,(byte*) unused_tables));
+#endif
+ }
+ if (!open_cache.records)
+ {
+ end_key_cache(); /* No tables in memory */
+ key_cache_used=0;
+ }
+ refresh_version++; // Force close of open tables
+ if (if_wait_for_refresh)
+ {
+ /*
+ If there is any table that has a lower refresh_version, wait until
+ this is closed (or this thread is killed) before returning
+ */
+ kill_delayed_threads();
+ THD *thd=current_thd;
+ pthread_mutex_lock(&thd->mysys_var->mutex);
+ thd->mysys_var->current_mutex= &LOCK_open;
+ thd->mysys_var->current_cond= &COND_refresh;
+ thd->proc_info="Flushing tables";
+ pthread_mutex_unlock(&thd->mysys_var->mutex);
+ VOID(pthread_cond_broadcast(&COND_refresh)); // If one flush is locked
+
+ close_old_data_files(thd,thd->open_tables,1);
+ bool found=1;
+ /* Wait until all threads has closed all the tables we had locked */
+ DBUG_PRINT("info", ("Waiting for others threads to close their open tables"));
+ while (found && ! thd->killed)
+ {
+ found=0;
+ for (uint idx=0 ; idx < open_cache.records ; idx++)
+ {
+ TABLE *table=(TABLE*) hash_element(&open_cache,idx);
+ if ((table->version) < refresh_version && table->db_stat)
+ {
+ found=1;
+ pthread_cond_wait(&COND_refresh,&LOCK_open);
+ break;
+ }
+ }
+ }
+ /*
+ No other thread has the locked tables open; reopen them and get the
+ old locks. This should always succeed (unless some external process
+ has removed the tables)
+ */
+ thd->in_lock_tables=1;
+ result=reopen_tables(thd,1,1);
+ thd->in_lock_tables=0;
+ }
+ VOID(pthread_mutex_unlock(&LOCK_open));
+ if (if_wait_for_refresh)
+ {
+ THD *thd=current_thd;
+ 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);
+ }
+ DBUG_RETURN(result);
+}
+
+
+/* Put all tables used by thread in free list */
+
+void close_thread_tables(THD *thd, bool locked)
+{
+ DBUG_ENTER("close_thread_tables");
+
+ if (thd->locked_tables)
+ DBUG_VOID_RETURN; // LOCK TABLES in use
+
+ TABLE *table,*next;
+ bool found_old_table=0;
+
+ if (thd->lock)
+ {
+ mysql_unlock_tables(thd, thd->lock); thd->lock=0;
+ }
+ /* VOID(pthread_sigmask(SIG_SETMASK,&thd->block_signals,NULL)); */
+ if (!locked)
+ VOID(pthread_mutex_lock(&LOCK_open));
+
+ 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);
+ }
+ 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;
+ }
+ }
+ 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 */
+ check_unused();
+ if (found_old_table)
+ {
+ /* Tell threads waiting for refresh that something has happened */
+ VOID(pthread_cond_broadcast(&COND_refresh));
+ }
+ if (!locked)
+ VOID(pthread_mutex_unlock(&LOCK_open));
+ /* VOID(pthread_sigmask(SIG_SETMASK,&thd->signals,NULL)); */
+ DBUG_VOID_RETURN;
+}
+
+ /* Close and delete temporary tables */
+
+void close_temporary(TABLE *table,bool delete_table)
+{
+ DBUG_ENTER("close_temporary");
+ char path[FN_REFLEN];
+ db_type table_type=table->db_type;
+ strmov(path,table->path);
+ free_io_cache(table);
+ closefrm(table);
+ my_free((char*) table,MYF(0));
+ if (delete_table)
+ rm_temporary_table(table_type, path);
+ DBUG_VOID_RETURN;
+}
+
+
+void close_temporary_tables(THD *thd)
+{
+ TABLE *table,*next;
+ for (table=thd->temporary_tables ; table ; table=next)
+ {
+ next=table->next;
+ close_temporary(table);
+ }
+ thd->temporary_tables=0;
+}
+
+
+TABLE **find_temporary_table(THD *thd, const char *db, const char *table_name)
+{
+ char key[MAX_DBKEY_LENGTH];
+ uint key_length= (uint) (strmov(strmov(key,db)+1,table_name)-key)+1;
+ TABLE *table,**prev;
+
+ prev= &thd->temporary_tables;
+ for (table=thd->temporary_tables ; table ; table=table->next)
+ {
+ if (table->key_length == key_length &&
+ !memcmp(table->table_cache_key,key,key_length))
+ return prev;
+ prev= &table->next;
+ }
+ return 0; // Not a temporary table
+}
+
+bool close_temporary_table(THD *thd, const char *db, const char *table_name)
+{
+ TABLE *table,**prev;
+
+ if (!(prev=find_temporary_table(thd,db,table_name)))
+ return 1;
+ table= *prev;
+ *prev= table->next;
+ close_temporary(table);
+ return 0;
+}
+
+bool rename_temporary_table(TABLE *table, const char *db,
+ const char *table_name)
+{
+ char *key;
+ if (!(key=(char*) alloc_root(&table->mem_root,
+ strlen(db)+ strlen(table_name)+2)))
+ return 1; /* purecov: inspected */
+ table->key_length=(uint)
+ (strmov((table->real_name=strmov(table->table_cache_key=key,
+ db)+1),
+ table_name) - table->table_cache_key)+1;
+ return 0;
+}
+
+
+
+
+ /* move table first in unused links */
+
+static void relink_unused(TABLE *table)
+{
+ if (table != unused_tables)
+ {
+ table->prev->next=table->next; /* Remove from unused list */
+ table->next->prev=table->prev;
+ table->next=unused_tables; /* Link in unused tables */
+ table->prev=unused_tables->prev;
+ unused_tables->prev->next=table;
+ unused_tables->prev=table;
+ unused_tables=table;
+ check_unused();
+ }
+}
+
+
+/*
+ Remove all instances of table from the current open list
+ Free all locks on tables that are done with LOCK TABLES
+ */
+
+TABLE *unlink_open_table(THD *thd, TABLE *list, TABLE *find)
+{
+ char key[MAX_DBKEY_LENGTH];
+ uint key_length=find->key_length;
+ TABLE *start=list,**prev,*next;
+ prev= &start;
+ memcpy(key,find->table_cache_key,key_length);
+ for (; list ; list=next)
+ {
+ next=list->next;
+ if (list->key_length == key_length &&
+ !memcmp(list->table_cache_key,key,key_length))
+ {
+ if (thd->locked_tables)
+ mysql_lock_remove(thd, thd->locked_tables,list);
+ VOID(hash_delete(&open_cache,(byte*) list)); // Close table
+ }
+ else
+ {
+ *prev=list; // put in use list
+ prev= &list->next;
+ }
+ }
+ *prev=0;
+ // Notify any 'refresh' threads
+ pthread_cond_broadcast(&COND_refresh);
+ return start;
+}
+
+
+/*
+ When we call the following function we must have a lock on
+ LOCK_OPEN ; This lock will be freed on return
+*/
+
+void wait_for_refresh(THD *thd)
+{
+ /* Wait until the current table is up to date */
+ const char *proc_info;
+ pthread_mutex_lock(&thd->mysys_var->mutex);
+ thd->mysys_var->current_mutex= &LOCK_open;
+ thd->mysys_var->current_cond= &COND_refresh;
+ proc_info=thd->proc_info;
+ thd->proc_info="Waiting for table";
+ pthread_mutex_unlock(&thd->mysys_var->mutex);
+ (void) pthread_cond_wait(&COND_refresh,&LOCK_open);
+
+ pthread_mutex_unlock(&LOCK_open); // Must be unlocked first
+ 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);
+}
+
+
+/******************************************************************************
+** open a table
+** Uses a cache of open tables to find a table not in use.
+** If refresh is a NULL pointer, then the is no version number checking and
+** the table is not put in the thread-open-list
+** If the return value is NULL and refresh is set then one must close
+** all tables and retry the open
+******************************************************************************/
+
+
+TABLE *open_table(THD *thd,const char *db,const char *table_name,
+ const char *alias,bool *refresh)
+{
+ reg1 TABLE *table;
+ char key[MAX_DBKEY_LENGTH];
+ uint key_length;
+ DBUG_ENTER("open_table");
+
+ /* find a unused table in the open table cache */
+ if (refresh)
+ *refresh=0;
+ if (thd->killed)
+ DBUG_RETURN(0);
+ key_length=(uint) (strmov(strmov(key,db)+1,table_name)-key)+1;
+
+ for (table=thd->temporary_tables; table ; table=table->next)
+ {
+ if (table->key_length == key_length &&
+ !memcmp(table->table_cache_key,key,key_length))
+ {
+ if (table->query_id == thd->query_id)
+ {
+ my_printf_error(ER_CANT_REOPEN_TABLE,
+ ER(ER_CANT_REOPEN_TABLE),MYF(0),table->table_name);
+ DBUG_RETURN(0);
+ }
+ table->query_id=thd->query_id;
+ goto reset;
+ }
+ }
+
+ if (thd->locked_tables)
+ { // Using table locks
+ for (table=thd->open_tables; table ; table=table->next)
+ {
+ if (table->key_length == key_length &&
+ !memcmp(table->table_cache_key,key,key_length) &&
+ !my_strcasecmp(table->table_name,alias))
+ goto reset;
+ }
+ my_printf_error(ER_TABLE_NOT_LOCKED,ER(ER_TABLE_NOT_LOCKED),MYF(0),alias);
+ DBUG_RETURN(0);
+ }
+ VOID(pthread_mutex_lock(&LOCK_open));
+
+ if (!thd->open_tables)
+ thd->version=refresh_version;
+ else if (thd->version != refresh_version && refresh)
+ {
+ /* Someone did a refresh while thread was opening tables */
+ *refresh=1;
+ VOID(pthread_mutex_unlock(&LOCK_open));
+ DBUG_RETURN(0);
+ }
+
+ for (table=(TABLE*) hash_search(&open_cache,(byte*) key,key_length) ;
+ table && table->in_use ;
+ table = (TABLE*) hash_next(&open_cache,(byte*) key,key_length))
+ {
+ if (table->version != refresh_version)
+ {
+ /*
+ ** There is a refresh in progress for this table
+ ** Wait until the table is freed or the thread is killed.
+ */
+ close_old_data_files(thd,thd->open_tables,0);
+ if (table->in_use != thd)
+ wait_for_refresh(thd);
+ else
+ VOID(pthread_mutex_unlock(&LOCK_open));
+ if (refresh)
+ *refresh=1;
+ DBUG_RETURN(0);
+ }
+ }
+ if (table)
+ {
+ if (table == unused_tables)
+ { // First unused
+ unused_tables=unused_tables->next; // Remove from link
+ if (table == unused_tables)
+ unused_tables=0;
+ }
+ table->prev->next=table->next; /* Remove from unused list */
+ table->next->prev=table->prev;
+ }
+ else
+ {
+ /* Free cache if too big */
+ while (open_cache.records >= table_cache_size && unused_tables)
+ VOID(hash_delete(&open_cache,(byte*) unused_tables)); /* purecov: tested */
+
+ /* make a new table */
+ if (!(table=(TABLE*) my_malloc(sizeof(*table),MYF(MY_WME))))
+ DBUG_RETURN(NULL);
+ if (open_unireg_entry(table,db,table_name,alias) ||
+ !(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 = strlen(table_name);
+ int db_len = 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));
+ DBUG_RETURN(NULL);
+ }
+ table->key_length=key_length;
+ table->version=refresh_version;
+ table->flush_version=flush_version;
+ if (!key_cache_used)
+ {
+ key_cache_used=1;
+ ha_key_cache();
+ }
+ DBUG_PRINT("info", ("inserting table %p into the cache", table));
+ VOID(hash_insert(&open_cache,(byte*) table));
+ }
+
+ table->in_use=thd;
+ check_unused();
+ VOID(pthread_mutex_unlock(&LOCK_open));
+ if (refresh)
+ {
+ table->next=thd->open_tables; /* Link into simple list */
+ thd->open_tables=table;
+ }
+ table->reginfo.lock_type=TL_READ; /* Assume read */
+
+ reset:
+ /* Fix alias if table name changes */
+ if (strcmp(table->table_name,alias))
+ {
+ uint length=strlen(alias)+1;
+ table->table_name= (char*) my_realloc(table->table_name,length,
+ MYF(MY_WME));
+ memcpy(table->table_name,alias,length);
+ for (uint i=0 ; i < table->fields ; i++)
+ table->field[i]->table_name=table->table_name;
+ }
+ /* These variables are also set in reopen_table() */
+ table->tablenr=thd->current_tablenr++;
+ table->used_fields=0;
+ table->const_table=0;
+ table->outer_join=table->null_row=table->maybe_null=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_RETURN(table);
+}
+
+
+TABLE *find_locked_table(THD *thd, const char *db,const char *table_name)
+{
+ char key[MAX_DBKEY_LENGTH];
+ uint key_length=(uint) (strmov(strmov(key,db)+1,table_name)-key)+1;
+
+ for (TABLE *table=thd->open_tables; table ; table=table->next)
+ {
+ if (table->key_length == key_length &&
+ !memcmp(table->table_cache_key,key,key_length))
+ return table;
+ }
+ return(0);
+}
+
+
+/****************************************************************************
+** Reopen an table because the definition has changed. The date file for the
+** table is already closed.
+** Returns 0 if ok.
+** If table can't be reopened, the entry is unchanged.
+****************************************************************************/
+
+bool reopen_table(TABLE *table,bool locked)
+{
+ TABLE tmp;
+ char *db=table->table_cache_key;
+ char *table_name=table->real_name;
+ bool error=1;
+ Field **field;
+ uint key,part;
+ DBUG_ENTER("reopen_table");
+
+#ifdef EXTRA_DEBUG
+ if (table->db_stat)
+ sql_print_error("Table %s had a open data handler in reopen_table",
+ table->table_name);
+#endif
+ if (!locked)
+ VOID(pthread_mutex_lock(&LOCK_open));
+
+ if (open_unireg_entry(&tmp,db,table_name,table->table_name))
+ goto end;
+ free_io_cache(table);
+
+ if (!(tmp.table_cache_key= memdup_root(&tmp.mem_root,db,
+ table->key_length)))
+ {
+ closefrm(&tmp); // End of memory
+ goto end;
+ }
+
+ tmp.key_length=table->key_length;
+ tmp.in_use=table->in_use;
+ tmp.used_keys=tmp.keys_in_use;
+ tmp.reginfo.lock_type=table->reginfo.lock_type;
+ tmp.version=refresh_version;
+ tmp.next=table->next;
+ tmp.prev=table->prev;
+
+ /* This list copies varibles set by open_table */
+ tmp.tablenr= table->tablenr;
+ tmp.tmp_table= table->tmp_table;
+ tmp.used_fields= table->used_fields;
+ tmp.const_table= table->const_table;
+ tmp.outer_join= table->outer_join;
+ tmp.null_row= table->null_row;
+ tmp.status= table->status;
+ tmp.grant= table->grant;
+
+ if (table->file)
+ VOID(closefrm(table)); // close file, free everything
+
+ *table=tmp;
+ table->file->change_table_ptr(table);
+
+ for (field=table->field ; *field ; field++)
+ {
+ (*field)->table=table;
+ (*field)->table_name=table->table_name;
+ }
+ for (key=0 ; key < table->keys ; key++)
+ for (part=0 ; part < table->key_info[key].usable_key_parts ; part++)
+ table->key_info[key].key_part[part].field->table=table;
+ VOID(pthread_cond_broadcast(&COND_refresh));
+ error=0;
+
+ end:
+ if (!locked)
+ VOID(pthread_mutex_unlock(&LOCK_open));
+ DBUG_RETURN(error);
+}
+
+
+/*
+ Used with ALTER TABLE:
+ Close all instanses of table when LOCK TABLES is in used;
+ Close first all instances of table and then reopen them
+ */
+
+bool close_data_tables(THD *thd,const char *db, const char *table_name)
+{
+ TABLE *table;
+ for (table=thd->open_tables; table ; table=table->next)
+ {
+ if (!strcmp(table->real_name,table_name) &&
+ !strcmp(table->table_cache_key,db))
+ {
+ mysql_lock_remove(thd, thd->locked_tables,table);
+ table->file->close();
+ table->db_stat=0;
+ }
+ }
+ return 0; // For the future
+}
+
+
+/*
+ Reopen all tables with closed data files
+ One should have lock on LOCK_open when calling this
+*/
+
+bool reopen_tables(THD *thd,bool get_locks,bool in_refresh)
+{
+ DBUG_ENTER("reopen_tables");
+ if (!thd->open_tables)
+ DBUG_RETURN(0);
+
+ TABLE *table,*next,**prev;
+ TABLE **tables,**tables_ptr; // For locks
+ bool error=0;
+ if (get_locks)
+ {
+ /* The ptr is checked later */
+ uint opens=0;
+ for (table=thd->open_tables; table ; table=table->next) opens++;
+ tables= (TABLE**) my_alloca(sizeof(TABLE*)*opens);
+ }
+ else
+ tables= &thd->open_tables;
+ tables_ptr =tables;
+
+ prev= &thd->open_tables;
+ for (table=thd->open_tables; table ; table=next)
+ {
+ uint db_stat=table->db_stat;
+ next=table->next;
+ if (!tables || (!db_stat && reopen_table(table,1)))
+ {
+ my_error(ER_CANT_REOPEN_TABLE,MYF(0),table->table_name);
+ VOID(hash_delete(&open_cache,(byte*) table));
+ error=1;
+ }
+ else
+ {
+ *prev= table;
+ prev= &table->next;
+ if (get_locks && !db_stat)
+ *tables_ptr++= table; // need new lock on this
+ if (in_refresh)
+ {
+ table->version=0;
+ table->locked_by_flush=0;
+ }
+ }
+ }
+ if (tables != tables_ptr) // Should we get back old locks
+ {
+ MYSQL_LOCK *lock;
+ /* We should always get these locks */
+ thd->some_tables_deleted=0;
+ if ((lock=mysql_lock_tables(thd,tables,(uint) (tables_ptr-tables))))
+ {
+ thd->locked_tables=mysql_lock_merge(thd->locked_tables,lock);
+ }
+ else
+ error=1;
+ }
+ if (get_locks && tables)
+ {
+ my_afree((gptr) tables);
+ }
+ VOID(pthread_cond_broadcast(&COND_refresh)); // Signal to refresh
+ *prev=0;
+ DBUG_RETURN(error);
+}
+
+/*
+ Close handlers for tables in list, but leave the TABLE structure
+ intact so that we can re-open these quickly
+ abort_locks is set if called from flush_tables.
+*/
+
+void close_old_data_files(THD *thd, TABLE *table, bool abort_locks)
+{
+ bool found=0;
+ for (; table ; table=table->next)
+ {
+ if (table->version != refresh_version)
+ {
+ found=1;
+ if (!abort_locks) // If not from flush tables
+ table->version = refresh_version; // Let other threads use table
+ if (table->db_stat)
+ {
+ if (abort_locks)
+ {
+ mysql_lock_abort(thd,table); // Close waiting threads
+ mysql_lock_remove(thd, thd->locked_tables,table);
+ table->locked_by_flush=1; // Will be reopened with locks
+ }
+ table->file->close();
+ table->db_stat=0;
+ }
+ }
+ }
+ if (found)
+ VOID(pthread_cond_broadcast(&COND_refresh)); // Signal to refresh
+}
+
+
+/*
+ Wait until all threads has closed the tables in the list
+ We have also to wait if there is thread that has a lock on this table even
+ if the table is closed
+*/
+
+static bool table_is_used(TABLE *table)
+{
+ do
+ {
+ char *key= table->table_cache_key;
+ uint key_length=table->key_length;
+ for (TABLE *search=(TABLE*) hash_search(&open_cache,(byte*) key,key_length) ;
+ search ;
+ search = (TABLE*) hash_next(&open_cache,(byte*) key,key_length))
+ {
+ if (search->locked_by_flush ||
+ search->db_stat && search->version < refresh_version)
+ return 1; // Table is used
+ }
+ } while ((table=table->next));
+ return 0;
+}
+
+
+/* Wait until all used tables are refreshed */
+
+bool wait_for_tables(THD *thd)
+{
+ bool result;
+ DBUG_ENTER("wait_for_tables");
+
+ thd->proc_info="Waiting for tables";
+ pthread_mutex_lock(&LOCK_open);
+ thd->some_tables_deleted=0;
+ close_old_data_files(thd,thd->open_tables,0);
+ if (dropping_tables)
+ {
+ (void) pthread_cond_broadcast(&COND_refresh); // Signal to refresh/delete
+ (void) pthread_cond_wait(&COND_refresh,&LOCK_open);
+ }
+
+ while (table_is_used(thd->open_tables) && ! thd->killed)
+ {
+ (void) pthread_cond_wait(&COND_refresh,&LOCK_open);
+ }
+
+ if (thd->killed)
+ result= 1; // aborted
+ else
+ {
+ /* 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;
+ DBUG_RETURN(result);
+}
+
+
+/* drop tables from locked list */
+
+bool drop_locked_tables(THD *thd,const char *db, const char *table_name)
+{
+ TABLE *table,*next,**prev;
+ bool found=0;
+ prev= &thd->open_tables;
+ for (table=thd->open_tables; table ; table=next)
+ {
+ next=table->next;
+ if (!strcmp(table->real_name,table_name) &&
+ !strcmp(table->table_cache_key,db))
+ {
+ mysql_lock_remove(thd, thd->locked_tables,table);
+ VOID(hash_delete(&open_cache,(byte*) table));
+ found=1;
+ }
+ else
+ {
+ *prev=table;
+ prev= &table->next;
+ }
+ }
+ *prev=0;
+ if (found)
+ VOID(pthread_cond_broadcast(&COND_refresh)); // Signal to refresh
+ if (thd->locked_tables && thd->locked_tables->table_count == 0)
+ {
+ my_free((gptr) thd->locked_tables,MYF(0));
+ thd->locked_tables=0;
+ }
+ return found;
+}
+
+
+/* lock table to force abort of any threads trying to use table */
+
+void abort_locked_tables(THD *thd,const char *db, const char *table_name)
+{
+ TABLE *table;
+ for (table=thd->open_tables; table ; table=table->next)
+ {
+ if (!strcmp(table->real_name,table_name) &&
+ !strcmp(table->table_cache_key,db))
+ mysql_lock_abort(thd,table);
+ }
+}
+
+/****************************************************************************
+** open_unireg_entry
+** Purpose : Load a table definition from file and open unireg table
+** Args : entry with DB and table given
+** Returns : 0 if ok
+*/
+
+static int open_unireg_entry(TABLE *entry,const char *db,const char *name,
+ const char *alias)
+{
+ char path[FN_REFLEN];
+ DBUG_ENTER("open_unireg_entry");
+
+ (void) sprintf(path,"%s/%s/%s",mysql_data_home,db,name);
+ if (openfrm(path,alias,
+ (uint) (HA_OPEN_KEYFILE | HA_OPEN_RNDFILE | HA_GET_INDEX |
+ HA_TRY_READ_ONLY),
+ READ_KEYINFO | COMPUTE_TYPES | EXTRA_RECORD,
+ entry))
+ {
+ DBUG_RETURN(1);
+ }
+ (void) entry->file->extra(HA_EXTRA_NO_READCHECK); // Not needed in SQL
+ DBUG_RETURN(0);
+}
+
+
+/*****************************************************************************
+** open all tables in list
+*****************************************************************************/
+
+int open_tables(THD *thd,TABLE_LIST *start)
+{
+ TABLE_LIST *tables;
+ bool refresh;
+ int result=0;
+ DBUG_ENTER("open_tables");
+
+ restart:
+ thd->proc_info="Opening tables";
+ for (tables=start ; tables ; tables=tables->next)
+ {
+ if (!tables->table &&
+ !(tables->table=open_table(thd,
+ tables->db ? tables->db : thd->db,
+ tables->real_name,
+ tables->name, &refresh)))
+ {
+ if (refresh) // Refresh in progress
+ {
+ /* close all 'old' tables used by this thread */
+ pthread_mutex_lock(&LOCK_open);
+ thd->version=refresh_version;
+ TABLE **prev_table= &thd->open_tables;
+ bool found=0;
+ for (TABLE_LIST *tmp=start ; tmp ; tmp=tmp->next)
+ {
+ if (tmp->table)
+ {
+ if (tmp->table->version != refresh_version ||
+ ! tmp->table->db_stat)
+ {
+ VOID(hash_delete(&open_cache,(byte*) tmp->table));
+ tmp->table=0;
+ found=1;
+ }
+ else
+ {
+ *prev_table= tmp->table; // Relink open list
+ prev_table= &tmp->table->next;
+ }
+ }
+ }
+ *prev_table=0;
+ if (found)
+ VOID(pthread_cond_broadcast(&COND_refresh)); // Signal to refresh
+ pthread_mutex_unlock(&LOCK_open);
+ goto restart;
+ }
+ result= -1; // Fatal error
+ break;
+ }
+ if (tables->lock_type != TL_UNLOCK)
+ tables->table->reginfo.lock_type=tables->lock_type;
+ tables->table->grant= tables->grant;
+ }
+ thd->proc_info=0;
+ DBUG_RETURN(result);
+}
+
+
+TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type lock_type)
+{
+ TABLE *table;
+ bool refresh;
+ DBUG_ENTER("open_ltable");
+
+#ifdef __WIN__
+ /* Win32 can't drop a file that is open */
+ if (lock_type == TL_WRITE_ALLOW_READ)
+ lock_type= TL_WRITE;
+#endif
+ thd->proc_info="Opening table";
+ while (!(table=open_table(thd,table_list->db ? table_list->db : thd->db,
+ table_list->real_name,table_list->name,
+ &refresh)) && refresh) ;
+ if (table)
+ {
+ table_list->table=table;
+ table->grant= table_list->grant;
+ if (thd->locked_tables)
+ {
+ thd->proc_info=0;
+ if ((int) lock_type >= (int) TL_WRITE_ALLOW_READ &&
+ (int) table->reginfo.lock_type < (int) TL_WRITE_ALLOW_READ)
+ {
+ my_printf_error(ER_TABLE_NOT_LOCKED_FOR_WRITE,
+ ER(ER_TABLE_NOT_LOCKED_FOR_WRITE),
+ MYF(0),table_list->name);
+ DBUG_RETURN(0);
+ }
+ thd->proc_info=0;
+ DBUG_RETURN(table);
+ }
+ if ((table->reginfo.lock_type=lock_type) != TL_UNLOCK)
+ if (!(thd->lock=mysql_lock_tables(thd,&table_list->table,1)))
+ DBUG_RETURN(0);
+ }
+ thd->proc_info=0;
+ DBUG_RETURN(table);
+}
+
+/*
+** Open all tables in list and locks them for read.
+** The lock will automaticly be freed by the close_thread_tables
+*/
+
+int open_and_lock_tables(THD *thd,TABLE_LIST *tables)
+{
+ if (open_tables(thd,tables) || lock_tables(thd,tables))
+ return -1; /* purecov: inspected */
+ return 0;
+}
+
+int lock_tables(THD *thd,TABLE_LIST *tables)
+{
+ if (tables && !thd->locked_tables)
+ {
+ uint count=0;
+ TABLE_LIST *table;
+ for (table = tables ; table ; table=table->next)
+ count++;
+ TABLE **start,**ptr;
+ if (!(ptr=start=(TABLE**) sql_alloc(sizeof(TABLE*)*count)))
+ return -1;
+ for (table = tables ; table ; table=table->next)
+ *(ptr++)= table->table;
+ if (!(thd->lock=mysql_lock_tables(thd,start,count)))
+ return -1; /* purecov: inspected */
+ }
+ return 0;
+}
+
+/*
+** Open a single table without table caching and don't set it in open_list
+** Used by alter_table to open a temporary table and when creating
+** a temporary table with CREATE TEMPORARY ...
+*/
+
+TABLE *open_temporary_table(THD *thd, const char *path, const char *db,
+ const char *table_name, bool link_in_list)
+{
+ TABLE *tmp_table;
+ DBUG_ENTER("open_temporary_table");
+ if (!(tmp_table=(TABLE*) my_malloc(sizeof(*tmp_table)+strlen(db)+
+ strlen(table_name)+2,
+ MYF(MY_WME))))
+ DBUG_RETURN(0); /* purecov: inspected */
+
+ if (openfrm(path, table_name,
+ (uint) (HA_OPEN_KEYFILE | HA_OPEN_RNDFILE | HA_GET_INDEX |
+ HA_TRY_READ_ONLY),
+ READ_KEYINFO | COMPUTE_TYPES | EXTRA_RECORD,
+ tmp_table))
+ {
+ 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 = 1;
+ tmp_table->table_cache_key=(char*) (tmp_table+1);
+ tmp_table->key_length= (uint) (strmov(strmov(tmp_table->table_cache_key,db)
+ +1, table_name)
+ - tmp_table->table_cache_key)+1;
+ if (link_in_list)
+ {
+ tmp_table->next=thd->temporary_tables;
+ thd->temporary_tables=tmp_table;
+ }
+ DBUG_RETURN(tmp_table);
+}
+
+
+bool rm_temporary_table(enum db_type base, char *path)
+{
+ bool error=0;
+ fn_format(path, path,"",reg_ext,4);
+ unpack_filename(path,path);
+ if (my_delete(path,MYF(0)))
+ error=1; /* purecov: inspected */
+ *fn_ext(path)='\0'; // remove extension
+ handler *file=get_new_handler((TABLE*) 0, base);
+ if (file && file->delete_table(path))
+ error=1;
+ delete file;
+ return error;
+}
+
+
+/*****************************************************************************
+** find field in list or tables. if field is unqualifed and unique,
+** return unique field
+******************************************************************************/
+
+#define WRONG_GRANT (Field*) -1
+
+Field *find_field_in_table(THD *thd,TABLE *table,const char *name,uint length,
+ bool check_grants, bool allow_rowid)
+{
+ Field *field;
+ if (table->name_hash.records)
+ {
+ if ((field=(Field*) hash_search(&table->name_hash,(byte*) name,
+ length)))
+ goto found;
+ }
+ else
+ {
+ Field **ptr=table->field;
+ while ((field = *ptr++))
+ {
+ if (!my_strcasecmp(field->field_name, name))
+ goto found;
+ }
+ }
+ if (allow_rowid && !my_strcasecmp(name,"_rowid") &&
+ (field=table->rowid_field))
+ goto found;
+ return (Field*) 0;
+
+ found:
+ if (thd->set_query_id)
+ {
+ if (field->query_id != thd->query_id)
+ {
+ field->query_id=thd->query_id;
+ field->table->used_fields++;
+ }
+ else
+ thd->dupp_field=field;
+ field->table->used_keys&=field->part_of_key;
+ }
+ if (check_grants && !thd->master_access && check_grant_column(thd,table,name,length))
+ return WRONG_GRANT;
+ return field;
+}
+
+
+Field *
+find_field_in_tables(THD *thd,Item_field *item,TABLE_LIST *tables)
+{
+ Field *found=0;
+ const char *db=item->db_name;
+ const char *table_name=item->table_name;
+ const char *name=item->field_name;
+ uint length=strlen(name);
+
+ if (table_name)
+ { /* Qualified field */
+ bool found_table=0;
+ for (; tables ; tables=tables->next)
+ {
+ if (!strcmp(tables->name,table_name) &&
+ (!db ||
+ (tables->db && !strcmp(db,tables->db)) ||
+ (!tables->db && !strcmp(db,thd->db))))
+ {
+ found_table=1;
+ Field *find=find_field_in_table(thd,tables->table,name,length,
+ grant_option && !thd->master_access,1);
+ if (find)
+ {
+ if (find == WRONG_GRANT)
+ return (Field*) 0;
+ if (db || !thd->where)
+ return find;
+ if (found)
+ {
+ my_printf_error(ER_NON_UNIQ_ERROR,ER(ER_NON_UNIQ_ERROR),MYF(0),
+ item->full_name(),thd->where);
+ return (Field*) 0;
+ }
+ found=find;
+ }
+ }
+ }
+ if (found)
+ return found;
+ if (!found_table)
+ {
+ char buff[NAME_LEN*2+1];
+ if (db)
+ {
+ strxmov(buff,db,".",table_name,NullS);
+ table_name=buff;
+ }
+ my_printf_error(ER_UNKNOWN_TABLE,ER(ER_UNKNOWN_TABLE),MYF(0),table_name,
+ thd->where);
+ }
+ else
+ my_printf_error(ER_BAD_FIELD_ERROR,ER(ER_BAD_FIELD_ERROR),MYF(0),
+ item->full_name(),thd->where);
+ return (Field*) 0;
+ }
+ bool allow_rowid= tables && !tables->next; // Only one table
+ for (; tables ; tables=tables->next)
+ {
+ Field *field=find_field_in_table(thd,tables->table,name,length,
+ grant_option && !thd->master_access, allow_rowid);
+ if (field)
+ {
+ if (field == WRONG_GRANT)
+ return (Field*) 0;
+ if (found)
+ {
+ if (!thd->where) // Returns first found
+ break;
+ my_printf_error(ER_NON_UNIQ_ERROR,ER(ER_NON_UNIQ_ERROR),MYF(0),
+ name,thd->where);
+ return (Field*) 0;
+ }
+ found=field;
+ }
+ }
+ if (found)
+ return found;
+ my_printf_error(ER_BAD_FIELD_ERROR,ER(ER_BAD_FIELD_ERROR),
+ MYF(0),item->full_name(),thd->where);
+ return (Field*) 0;
+}
+
+Item **
+find_item_in_list(Item *find,List<Item> &items)
+{
+ List_iterator<Item> li(items);
+ Item **found=0,*item;
+ const char *field_name=0;
+ const char *table_name=0;
+ if (find->type() == Item::FIELD_ITEM || find->type() == Item::REF_ITEM)
+ {
+ field_name= ((Item_ident*) find)->field_name;
+ table_name= ((Item_ident*) find)->table_name;
+ }
+
+ while ((item=li++))
+ {
+ if (field_name && item->type() == Item::FIELD_ITEM)
+ {
+ if (!my_strcasecmp(((Item_field*) item)->name,field_name))
+ {
+ if (!table_name)
+ {
+ if (found)
+ {
+ if ((*found)->eq(item))
+ continue; // Same field twice (Access?)
+ if (current_thd->where)
+ my_printf_error(ER_NON_UNIQ_ERROR,ER(ER_NON_UNIQ_ERROR),MYF(0),
+ find->full_name(), current_thd->where);
+ return (Item**) 0;
+ }
+ found=li.ref();
+ }
+ else if (!strcmp(((Item_field*) item)->table_name,table_name))
+ {
+ found=li.ref();
+ break;
+ }
+ }
+ }
+ else if (!table_name && (item->eq(find) ||
+ find->name &&
+ !my_strcasecmp(item->name,find->name)))
+ {
+ found=li.ref();
+ break;
+ }
+ }
+ if (!found && current_thd->where)
+ my_printf_error(ER_BAD_FIELD_ERROR,ER(ER_BAD_FIELD_ERROR),MYF(0),
+ find->full_name(),current_thd->where);
+ return found;
+}
+
+
+/****************************************************************************
+** Check that all given fields exists and fill struct with current data
+** Check also that the 'used keys' and 'ignored keys' exists and set up the
+** table structure accordingly
+****************************************************************************/
+
+int setup_fields(THD *thd, TABLE_LIST *tables, List<Item> &fields,
+ bool set_query_id, List<Item> *sum_func_list)
+{
+ 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->where="field list";
+
+ /* Remap table numbers if INSERT ... SELECT */
+ 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)
+ {
+ key_map map= get_key_map_from_key_list(thd,table->table,
+ table->use_index);
+ if (map == ~(key_map) 0)
+ DBUG_RETURN(-1);
+ table->table->keys_in_use_for_query=map;
+ }
+ if (table->ignore_index)
+ {
+ key_map map= get_key_map_from_key_list(thd,table->table,
+ table->ignore_index);
+ if (map == ~(key_map) 0)
+ DBUG_RETURN(-1);
+ table->table->keys_in_use_for_query &= ~map;
+ }
+ }
+ if (tablenr > MAX_TABLES)
+ {
+ my_error(ER_TOO_MANY_TABLES,MYF(0),MAX_TABLES);
+ DBUG_RETURN(-1);
+ }
+ while ((item=it++))
+ {
+ if (item->type() == Item::FIELD_ITEM &&
+ ((Item_field*) item)->field_name[0] == '*')
+ {
+ if (insert_fields(thd,tables,((Item_field*) item)->table_name,&it))
+ DBUG_RETURN(-1); /* purecov: inspected */
+ }
+ else
+ {
+ if (item->fix_fields(thd,tables))
+ DBUG_RETURN(-1); /* purecov: inspected */
+ if (item->with_sum_func && item->type() != Item::SUM_FUNC_ITEM)
+ item->split_sum_func(*sum_func_list);
+ }
+ }
+ DBUG_RETURN(test(thd->fatal_error));
+}
+
+
+static key_map get_key_map_from_key_list(THD *thd, TABLE *table,
+ List<String> *index_list)
+{
+ key_map map=0;
+ List_iterator<String> it(*index_list);
+ String *name;
+ uint pos;
+ while ((name=it++))
+ {
+ if ((pos=find_type(name->c_ptr(), &table->keynames, 1)) <= 0)
+ {
+ my_error(ER_KEY_COLUMN_DOES_NOT_EXITS, MYF(0), name->c_ptr(),
+ table->real_name);
+ return (~ (key_map) 0);
+ }
+ map|= ((key_map) 1) << (pos-1);
+ }
+ return map;
+}
+
+/****************************************************************************
+** This just drops in all fields instead of current '*' field
+** Returns pointer to last inserted field if ok
+****************************************************************************/
+
+static bool
+insert_fields(THD *thd,TABLE_LIST *tables, const char *table_name,
+ List_iterator<Item> *it)
+{
+ TABLE_LIST *table;
+ uint found;
+ DBUG_ENTER("insert_fields");
+
+ found=0;
+ for (table=tables ; table ; table=table->next)
+ {
+ if (grant_option && !thd->master_access &&
+ check_grant_all_columns(thd,SELECT_ACL,table->table) )
+ DBUG_RETURN(-1);
+ if (!table_name || !strcmp(table_name,table->name))
+ {
+ Field **ptr=table->table->field,*field;
+ while ((field = *ptr++))
+ {
+ Item_field *item= new Item_field(field);
+ if (!found++)
+ (void) it->replace(item);
+ else
+ it->after(item);
+ if (field->query_id == thd->query_id)
+ thd->dupp_field=field;
+ field->query_id=thd->query_id;
+ field->table->used_keys&=field->part_of_key;
+ }
+ /* All fields are used */
+ table->table->used_fields=table->table->fields;
+ }
+ }
+ if (!found)
+ {
+ if (!table_name)
+ my_error(ER_NO_TABLES_USED,MYF(0));
+ else
+ my_error(ER_BAD_TABLE_ERROR,MYF(0),table_name);
+ }
+ DBUG_RETURN(!found);
+}
+
+
+/*
+** Fix all conditions and outer join expressions
+*/
+
+int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds)
+{
+ DBUG_ENTER("setup_conds");
+ thd->set_query_id=1;
+ thd->cond_count=0;
+ thd->allow_sum_func=0;
+ if (*conds)
+ {
+ thd->where="where clause";
+ if ((*conds)->fix_fields(thd,tables))
+ DBUG_RETURN(1);
+ }
+
+ /* Check if we are using outer joins */
+ for (TABLE_LIST *table=tables ; table ; table=table->next)
+ {
+ if (table->natural_join)
+ {
+ /* Make a join of all fields with have the same name */
+ TABLE *t1=table->table;
+ TABLE *t2=table->natural_join->table;
+ Item_cond_and *cond_and=new Item_cond_and();
+ if (!cond_and) // If not out of memory
+ DBUG_RETURN(1);
+
+ uint i,j;
+ for (i=0 ; i < t1->fields ; i++)
+ {
+ // TODO: This could be optimized to use hashed names if t2 had a hash
+ for (j=0 ; j < t2->fields ; j++)
+ {
+ if (!my_strcasecmp(t1->field[i]->field_name,
+ t2->field[j]->field_name))
+ {
+ Item_func_eq *tmp=new Item_func_eq(new Item_field(t1->field[i]),
+ new Item_field(t2->field[j]));
+ if (!tmp)
+ DBUG_RETURN(1);
+ tmp->fix_length_and_dec(); // Update cmp_type
+ tmp->const_item_cache=0;
+ cond_and->list.push_back(tmp);
+ t1->used_keys&= t1->field[i]->part_of_key;
+ t2->used_keys&= t2->field[j]->part_of_key;
+ break;
+ }
+ }
+ }
+ cond_and->used_tables_cache= t1->map | t2->map;
+ thd->cond_count+=cond_and->list.elements;
+ if (!table->outer_join) // Not left join
+ {
+ if (!(*conds=and_conds(*conds, cond_and)))
+ DBUG_RETURN(1);
+ }
+ else
+ table->on_expr=cond_and;
+ }
+ else if (table->on_expr)
+ {
+ /* Make a join an a expression */
+ thd->where="on clause";
+ if (table->on_expr->fix_fields(thd,tables))
+ DBUG_RETURN(1);
+ thd->cond_count++;
+
+ /* If it's a normal join, add the ON/USING expression to the WHERE */
+ if (!table->outer_join)
+ {
+ if (!(*conds=and_conds(*conds, table->on_expr)))
+ DBUG_RETURN(1);
+ table->on_expr=0;
+ }
+ }
+ }
+ DBUG_RETURN(test(thd->fatal_error));
+}
+
+
+/******************************************************************************
+** Fill a record with data (for INSERT or UPDATE)
+** Returns : 1 if some field has wrong type
+******************************************************************************/
+
+int
+fill_record(List<Item> &fields,List<Item> &values)
+{
+ List_iterator<Item> f(fields),v(values);
+ Item *value;
+ Item_field *field;
+ DBUG_ENTER("fill_record");
+
+ while ((field=(Item_field*) f++))
+ {
+ value=v++;
+ if (value->save_in_field(field->field))
+ DBUG_RETURN(1);
+ }
+ DBUG_RETURN(0);
+}
+
+
+int
+fill_record(Field **ptr,List<Item> &values)
+{
+ List_iterator<Item> v(values);
+ Item *value;
+ DBUG_ENTER("fill_record");
+
+ Field *field;
+ while ((field = *ptr++))
+ {
+ value=v++;
+ if (value->save_in_field(field))
+ DBUG_RETURN(1);
+ }
+ DBUG_RETURN(0);
+}
+
+
+static void mysql_rm_tmp_tables(void)
+{
+ uint idx;
+ char filePath[FN_REFLEN];
+ MY_DIR *dirp;
+ FILEINFO *file;
+ DBUG_ENTER("mysql_rm_tmp_tables");
+
+ /* See if the directory exists */
+ if (!(dirp = my_dir(mysql_tmpdir,MYF(MY_WME | MY_DONT_SORT))))
+ DBUG_VOID_RETURN; /* purecov: inspected */
+
+ /*
+ ** Remove all SQLxxx tables from directory
+ */
+
+ for (idx=2 ; idx < (uint) dirp->number_off_files ; idx++)
+ {
+ file=dirp->dir_entry+idx;
+ if (!bcmp(file->name,tmp_file_prefix,tmp_file_prefix_length))
+ {
+ sprintf(filePath,"%s%s",mysql_tmpdir,file->name); /* purecov: inspected */
+ VOID(my_delete(filePath,MYF(MY_WME))); /* purecov: inspected */
+ }
+ }
+ my_dirend(dirp);
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+** CREATE INDEX and DROP INDEX are implemented by calling ALTER TABLE with
+** the proper arguments. This isn't very fast but it should work for most
+** cases.
+** One should normally create all indexes with CREATE TABLE or ALTER TABLE.
+*/
+
+int mysql_create_index(THD *thd, TABLE_LIST *table_list, List<Key> &keys)
+{
+ List<create_field> fields;
+ List<Alter_drop> drop;
+ List<Alter_column> alter;
+ HA_CREATE_INFO create_info;
+ DBUG_ENTER("mysql_create_index");
+ bzero((char*) &create_info,sizeof(create_info));
+ 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, FALSE, DUP_ERROR));
+}
+
+
+int mysql_drop_index(THD *thd, TABLE_LIST *table_list, List<Alter_drop> &drop)
+{
+ List<create_field> fields;
+ List<Key> keys;
+ List<Alter_column> alter;
+ HA_CREATE_INFO create_info;
+ DBUG_ENTER("mysql_drop_index");
+ bzero((char*) &create_info,sizeof(create_info));
+ 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, FALSE, DUP_ERROR));
+}
+
+/*****************************************************************************
+ unireg support functions
+*****************************************************************************/
+
+/*
+** Invalidate any cache entries that are for some DB
+** We can't use hash_delete when looping hash_elements. We mark them first
+** and afterwards delete those marked unused.
+*/
+
+void remove_db_from_cache(const my_string db)
+{
+ for (uint idx=0 ; idx < open_cache.records ; idx++)
+ {
+ TABLE *table=(TABLE*) hash_element(&open_cache,idx);
+ if (!strcmp(table->table_cache_key,db))
+ {
+ table->version=0L; /* Free when thread is ready */
+ if (!table->in_use)
+ relink_unused(table);
+ }
+ }
+ while (unused_tables && !unused_tables->version)
+ VOID(hash_delete(&open_cache,(byte*) unused_tables));
+}
+
+
+/*
+** free all unused tables
+*/
+
+void flush_tables()
+{
+ (void) pthread_mutex_lock(&LOCK_open);
+ while (unused_tables)
+ hash_delete(&open_cache,(byte*) unused_tables);
+ (void) pthread_mutex_unlock(&LOCK_open);
+}
+
+
+/*
+** Mark all entries with the table as deleted to force an reopen of the table
+** Returns true if the table is in use by another thread
+*/
+
+bool remove_table_from_cache(THD *thd, const char *db,const char *table_name)
+{
+ char key[MAX_DBKEY_LENGTH];
+ uint key_length;
+ TABLE *table;
+ bool result=0;
+ DBUG_ENTER("remove_table_from_cache");
+
+ key_length=(uint) (strmov(strmov(key,db)+1,table_name)-key)+1;
+ for (table=(TABLE*) hash_search(&open_cache,(byte*) key,key_length) ;
+ table;
+ table = (TABLE*) hash_next(&open_cache,(byte*) key,key_length))
+ {
+ table->version=0L; /* Free when thread is ready */
+ if (!table->in_use)
+ relink_unused(table);
+ else if (table->in_use != thd)
+ {
+ THD *in_use=table->in_use;
+
+ in_use->some_tables_deleted=1;
+ if (table->db_stat)
+ result=1;
+ /* Kill delayed insert threads */
+ if (in_use->system_thread && ! in_use->killed)
+ {
+ in_use->killed=1;
+ pthread_mutex_lock(&in_use->mysys_var->mutex);
+ if (in_use->mysys_var->current_mutex)
+ {
+ pthread_mutex_lock(in_use->mysys_var->current_mutex);
+ pthread_cond_broadcast(in_use->mysys_var->current_cond);
+ pthread_mutex_unlock(in_use->mysys_var->current_mutex);
+ }
+ pthread_mutex_unlock(&in_use->mysys_var->mutex);
+ }
+ }
+ }
+ while (unused_tables && !unused_tables->version)
+ VOID(hash_delete(&open_cache,(byte*) unused_tables));
+ DBUG_RETURN(result);
+}
+
+/*
+ Will be used for ft-query optimization someday.
+ SerG.
+ */
+int setup_ftfuncs(THD *thd,TABLE_LIST *tables, List<Item_func_match> &ftfuncs)
+{
+ List_iterator<Item_func_match> li(ftfuncs);
+ Item_func_match *ftf;
+
+ while ((ftf=li++))
+ if (ftf->fix_index())
+ return 1;
+
+ return 0;
+}
+
diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc
new file mode 100644
index 00000000000..78053d0d3e3
--- /dev/null
+++ b/sql/sql_cache.cc
@@ -0,0 +1,98 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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>
+#include <my_dir.h>
+#include <hash.h>
+
+#define SQL_CACHE_LENGTH 300
+
+HASH sql_cache;
+LEX lex_array_static[SQL_CACHE_LENGTH];
+LEX * lex_array = lex_array_static;
+int last_lex_array_item = SQL_CACHE_LENGTH - 1;
+
+/* Function to return a text string from a LEX struct */
+static byte *cache_key(const byte *record, uint *length, my_bool not_used)
+{
+#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;
+#endif
+ return 0;
+}
+
+/* At the moment we do not really want to do anything upon delete */
+static void free_cache_entry(void *entry)
+{
+}
+
+/* Initialization of the SQL cache hash -- should be called during
+ the bootstrap stage */
+bool sql_cache_init(void)
+{
+ if (query_buff_size)
+ {
+ VOID(hash_init(&sql_cache, 4096, 0, 0,
+ cache_key,
+ (void (*)(void*)) free_cache_entry,
+ 0));
+ }
+ return 0;
+}
+
+/* Clearing the SQL cache hash -- during shutdown */
+void sql_cache_free(void)
+{
+ hash_free(&sql_cache);
+}
+
+/* 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) */
+
+int sql_cache_hit(THD *thd, char *sql, uint length)
+{
+#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--;
+
+ lex_start(thd, (uchar *)sql, length);
+
+ if (hash_insert(&sql_cache, (const byte *)ptr)) {
+ fprintf(stderr, "Out of memory during hash_insert?\n");
+ }
+ 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");
+ }
+ return 0;
+ }
+#endif
+ return 1;
+}
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
new file mode 100644
index 00000000000..19b9ecdaae0
--- /dev/null
+++ b/sql/sql_class.cc
@@ -0,0 +1,593 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 classes defined in sql_class.h
+** Especially the classes to handle a result from a select
+**
+*****************************************************************************/
+
+#ifdef __GNUC__
+#pragma implementation // gcc: Class implementation
+#endif
+
+#include "mysql_priv.h"
+#include "sql_acl.h"
+#include <m_ctype.h>
+#include <sys/stat.h>
+#ifdef __WIN__
+#include <io.h>
+#endif
+
+/*****************************************************************************
+** Instansiate templates
+*****************************************************************************/
+
+#ifdef __GNUC__
+/* Used templates */
+template class List<Key>;
+template class List_iterator<Key>;
+template class List<key_part_spec>;
+template class List_iterator<key_part_spec>;
+template class List<Alter_drop>;
+template class List_iterator<Alter_drop>;
+template class List<Alter_column>;
+template class List_iterator<Alter_column>;
+#endif
+
+/****************************************************************************
+** User variables
+****************************************************************************/
+
+static byte* get_var_key(user_var_entry *entry, uint *length,
+ my_bool not_used __attribute__((unused)))
+{
+ *length=(uint) entry->name.length;
+ return (byte*) entry->name.str;
+}
+
+static void free_var(user_var_entry *entry)
+{
+ char *pos= (char*) entry+ALIGN_SIZE(sizeof(*entry));
+ if (entry->value && entry->value != pos)
+ my_free(entry->value, MYF(0));
+ my_free((char*) entry,MYF(0));
+}
+
+
+/****************************************************************************
+** Thread specific functions
+****************************************************************************/
+
+THD::THD()
+{
+ host=user=db=query=ip=0;
+ proc_info="login";
+ locked=killed=count_cuted_fields=some_tables_deleted=no_errors=password=
+ fatal_error=query_start_used=last_insert_id_used=insert_id_used=
+ user_time=bootstrap=in_lock_tables=global_read_lock=0;
+ query_length=col_access=0;
+ query_error=0;
+ server_status=SERVER_STATUS_AUTOCOMMIT;
+ next_insert_id=last_insert_id=0;
+ open_tables=temporary_tables=0;
+ tmp_table=0;
+ lock=locked_tables=0;
+ cuted_fields=0L;
+ options=thd_startup_options;
+ update_lock_default= low_priority_updates ? TL_WRITE_LOW_PRIORITY : TL_WRITE;
+ start_time=(time_t) 0;
+ last_nx_table = last_nx_db = 0;
+ inactive_timeout=net_wait_timeout;
+ cond_count=0;
+ command=COM_CONNECT;
+ set_query_id=1;
+ default_select_limit= HA_POS_ERROR;
+ max_join_size= ((::max_join_size != ~ (ulong) 0L) ? ::max_join_size :
+ HA_POS_ERROR);
+ convert_set=0;
+ mysys_var=0;
+ db_access=NO_ACCESS;
+ hash_init(&user_vars, USER_VARS_HASH_SIZE, 0, 0,
+ (hash_get_key) get_var_key,
+ (void (*)(void*)) free_var,0);
+ net.vio=0;
+ ull=0;
+ system_thread=0;
+ bzero((char*) &alloc,sizeof(alloc));
+#ifdef __WIN__
+ real_id = 0 ;
+#endif
+ transaction.bdb_lock_count=0;
+ transaction.bdb_tid=0;
+}
+
+THD::~THD()
+{
+ DBUG_ENTER("~THD()");
+ /* Close connection */
+ if (net.vio)
+ {
+ vio_delete(net.vio);
+ net_end(&net);
+ }
+ ha_rollback(this);
+ if (locked_tables)
+ {
+ lock=locked_tables; locked_tables=0;
+ close_thread_tables(this);
+ }
+ close_temporary_tables(this);
+ if (global_read_lock)
+ {
+ pthread_mutex_lock(&LOCK_open);
+ ::global_read_lock--;
+ pthread_cond_broadcast(&COND_refresh);
+ pthread_mutex_unlock(&LOCK_open);
+ }
+ if (ull)
+ {
+ pthread_mutex_lock(&LOCK_user_locks);
+ item_user_lock_release(ull);
+ pthread_mutex_unlock(&LOCK_user_locks);
+ }
+ hash_free(&user_vars);
+
+ DBUG_PRINT("info", ("freeing host"));
+
+ safeFree(host);
+ safeFree(user);
+ safeFree(db);
+ safeFree(ip);
+ free_root(&alloc);
+ mysys_var=0; // Safety (shouldn't be needed)
+ DBUG_VOID_RETURN;
+}
+
+// remember the location of thread info, the structure needed for
+// sql_alloc() and the structure for the net buffer
+
+bool THD::store_globals()
+{
+ return (my_pthread_setspecific_ptr(THR_THD, this) ||
+ my_pthread_setspecific_ptr(THR_MALLOC, &alloc) ||
+ my_pthread_setspecific_ptr(THR_NET, &net));
+}
+
+
+/*****************************************************************************
+** Functions to provide a interface to select results
+*****************************************************************************/
+
+select_result::select_result()
+{
+ thd=current_thd;
+}
+
+static String default_line_term("\n"),default_escaped("\\"),
+ default_field_term("\t");
+
+sql_exchange::sql_exchange(char *name,bool flag)
+ :file_name(name), opt_enclosed(0), dumpfile(flag), skip_lines(0)
+{
+ field_term= &default_field_term;
+ enclosed= line_start= &empty_string;
+ line_term= &default_line_term;
+ escaped= &default_escaped;
+}
+
+bool select_send::send_fields(List<Item> &list,uint flag)
+{
+ return ::send_fields(thd,list,flag);
+}
+
+
+/* Send data to client. Returns 0 if ok */
+
+bool select_send::send_data(List<Item> &items)
+{
+ List_iterator<Item> li(items);
+ String *packet= &thd->packet;
+ DBUG_ENTER("send_data");
+
+ if (thd->offset_limit)
+ { // using limit offset,count
+ thd->offset_limit--;
+ DBUG_RETURN(0);
+ }
+ packet->length(0); // Reset packet
+ Item *item;
+ while ((item=li++))
+ {
+ if (item->send(packet))
+ {
+ packet->free(); // Free used
+ my_error(ER_OUT_OF_RESOURCES,MYF(0));
+ DBUG_RETURN(1);
+ }
+ }
+ bool error=my_net_write(&thd->net,(char*) packet->ptr(),packet->length());
+ 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 */
+ if (thd->lock)
+ {
+ mysql_unlock_tables(thd, thd->lock); thd->lock=0;
+ }
+ ::send_eof(&thd->net);
+ return 0;
+}
+
+
+/***************************************************************************
+** Export of select to textfile
+***************************************************************************/
+
+
+select_export::~select_export()
+{
+ if (file >= 0)
+ { // This only happens in case of error
+ (void) end_io_cache(&cache);
+ (void) my_close(file,MYF(0));
+ file= -1;
+ }
+}
+
+int
+select_export::prepare(List<Item> &list)
+{
+ char path[FN_REFLEN];
+ uint option=4;
+ bool blob_flag=0;
+#ifdef DONT_ALLOW_FULL_LOAD_DATA_PATHS
+ option|=1; // Force use of db directory
+#endif
+ if (strlen(exchange->file_name) + NAME_LEN >= FN_REFLEN)
+ strmake(path,exchange->file_name,FN_REFLEN-1);
+ (void) fn_format(path,exchange->file_name, thd->db ? thd->db : "", "",
+ option);
+ if (!access(path,F_OK))
+ {
+ my_error(ER_FILE_EXISTS_ERROR,MYF(0),exchange->file_name);
+ return 1;
+ }
+ /* Create the file world readable */
+ if ((file=my_create(path, 0666, O_WRONLY, MYF(MY_WME))) < 0)
+ return 1;
+#ifdef HAVE_FCHMOD
+ (void) fchmod(file,0666); // Because of umask()
+#else
+ (void) chmod(path,0666);
+#endif
+ if (init_io_cache(&cache,file,0L,WRITE_CACHE,0L,1,MYF(MY_WME)))
+ {
+ my_close(file,MYF(0));
+ file= -1;
+ return 1;
+ }
+ /* Check if there is any blobs in data */
+ {
+ List_iterator<Item> li(list);
+ Item *item;
+ while ((item=li++))
+ {
+ if (item->max_length >= MAX_BLOB_WIDTH)
+ {
+ blob_flag=1;
+ break;
+ }
+ }
+ }
+ field_term_length=exchange->field_term->length();
+ if (!exchange->line_term->length())
+ exchange->line_term=exchange->field_term; // Use this if it exists
+ field_sep_char= (exchange->enclosed->length() ? (*exchange->enclosed)[0] :
+ field_term_length ? (*exchange->field_term)[0] : INT_MAX);
+ escape_char= (exchange->escaped->length() ? (*exchange->escaped)[0] : -1);
+ line_sep_char= (exchange->line_term->length() ?
+ (*exchange->line_term)[0] : INT_MAX);
+ if (!field_term_length)
+ exchange->opt_enclosed=0;
+ if (!exchange->enclosed->length())
+ exchange->opt_enclosed=1; // A little quicker loop
+ fixed_row_size= (!field_term_length && !exchange->enclosed->length() &&
+ !blob_flag);
+ return 0;
+}
+
+
+bool select_export::send_data(List<Item> &items)
+{
+
+ DBUG_ENTER("send_data");
+ char buff[MAX_FIELD_WIDTH],null_buff[2],space[MAX_FIELD_WIDTH];
+ bool space_inited=0;
+ String tmp(buff,sizeof(buff)),*res;
+ tmp.length(0);
+
+ if (thd->offset_limit)
+ { // using limit offset,count
+ thd->offset_limit--;
+ DBUG_RETURN(0);
+ }
+ row_count++;
+ Item *item;
+ char *buff_ptr=buff;
+ uint used_length=0,items_left=items.elements;
+ List_iterator<Item> li(items);
+
+ if (my_b_write(&cache,(byte*) exchange->line_start->ptr(),
+ exchange->line_start->length()))
+ goto err;
+ while ((item=li++))
+ {
+ Item_result result_type=item->result_type();
+ res=item->str_result(&tmp);
+ if (res && (!exchange->opt_enclosed || result_type == STRING_RESULT))
+ {
+ if (my_b_write(&cache,(byte*) exchange->enclosed->ptr(),
+ exchange->enclosed->length()))
+ goto err;
+ }
+ if (!res)
+ { // NULL
+ if (!fixed_row_size)
+ {
+ if (escape_char != -1) // Use \N syntax
+ {
+ null_buff[0]=escape_char;
+ null_buff[1]='N';
+ if (my_b_write(&cache,(byte*) null_buff,2))
+ goto err;
+ }
+ else if (my_b_write(&cache,(byte*) "NULL",4))
+ goto err;
+ }
+ else
+ {
+ used_length=0; // Fill with space
+ }
+ }
+ else
+ {
+ if (fixed_row_size)
+ used_length=min(res->length(),item->max_length);
+ else
+ used_length=res->length();
+ if (result_type == STRING_RESULT && escape_char != -1)
+ {
+ char *pos,*start,*end;
+
+ for (start=pos=(char*) res->ptr(),end=pos+used_length ;
+ pos != end ;
+ pos++)
+ {
+#ifdef USE_MB
+ if (use_mb(default_charset_info))
+ {
+ int l;
+ if ((l=my_ismbchar(default_charset_info, pos, end)))
+ {
+ pos += l-1;
+ continue;
+ }
+ }
+#endif
+ if ((int) *pos == escape_char || (int) *pos == field_sep_char ||
+ (int) *pos == line_sep_char || !*pos)
+ {
+ char tmp_buff[2];
+ tmp_buff[0]= escape_char;
+ tmp_buff[1]= *pos ? *pos : '0';
+ if (my_b_write(&cache,(byte*) start,(uint) (pos-start)) ||
+ my_b_write(&cache,(byte*) tmp_buff,2))
+ goto err;
+ start=pos+1;
+ }
+ }
+ if (my_b_write(&cache,(byte*) start,(uint) (pos-start)))
+ goto err;
+ }
+ else if (my_b_write(&cache,(byte*) res->ptr(),used_length))
+ goto err;
+ }
+ if (fixed_row_size)
+ { // Fill with space
+ if (item->max_length > used_length)
+ {
+ /* QQ: Fix by adding a my_b_fill() function */
+ if (!space_inited)
+ {
+ space_inited=1;
+ bfill(space,sizeof(space),' ');
+ }
+ uint length=item->max_length-used_length;
+ for ( ; length > sizeof(space) ; length-=sizeof(space))
+ {
+ if (my_b_write(&cache,(byte*) space,sizeof(space)))
+ goto err;
+ }
+ if (my_b_write(&cache,(byte*) space,length))
+ goto err;
+ }
+ }
+ buff_ptr=buff; // Place separators here
+ if (res && (!exchange->opt_enclosed || result_type == STRING_RESULT))
+ {
+ memcpy(buff_ptr,exchange->enclosed->ptr(),exchange->enclosed->length());
+ buff_ptr+=exchange->enclosed->length();
+ }
+ if (--items_left)
+ {
+ memcpy(buff_ptr,exchange->field_term->ptr(),field_term_length);
+ buff_ptr+=field_term_length;
+ }
+ if (my_b_write(&cache,(byte*) buff,(uint) (buff_ptr-buff)))
+ goto err;
+ }
+ if (my_b_write(&cache,(byte*) exchange->line_term->ptr(),
+ exchange->line_term->length()))
+ goto err;
+ DBUG_RETURN(0);
+err:
+ DBUG_RETURN(1);
+}
+
+
+void select_export::send_error(uint errcode,const char *err)
+{
+ ::send_error(&thd->net,errcode,err);
+ (void) end_io_cache(&cache);
+ (void) my_close(file,MYF(0));
+ file= -1;
+}
+
+
+bool select_export::send_eof()
+{
+ int error=test(end_io_cache(&cache));
+ if (my_close(file,MYF(MY_WME)))
+ error=1;
+ if (error)
+ ::send_error(&thd->net);
+ else
+ ::send_ok(&thd->net,row_count);
+ file= -1;
+ return error;
+}
+
+
+/***************************************************************************
+** Dump of select to a binary file
+***************************************************************************/
+
+
+select_dump::~select_dump()
+{
+ if (file >= 0)
+ { // This only happens in case of error
+ (void) end_io_cache(&cache);
+ (void) my_close(file,MYF(0));
+ file= -1;
+ }
+}
+
+int
+select_dump::prepare(List<Item> &list __attribute__((unused)))
+{
+ uint option=4;
+#ifdef DONT_ALLOW_FULL_LOAD_DATA_PATHS
+ option|=1; // Force use of db directory
+#endif
+ (void) fn_format(path,exchange->file_name, thd->db ? thd->db : "", "",
+ option);
+ if (!access(path,F_OK))
+ {
+ my_error(ER_FILE_EXISTS_ERROR,MYF(0),exchange->file_name);
+ return 1;
+ }
+ /* Create the file world readable */
+ if ((file=my_create(path, 0666, O_WRONLY, MYF(MY_WME))) < 0)
+ return 1;
+#ifdef HAVE_FCHMOD
+ (void) fchmod(file,0666); // Because of umask()
+#else
+ (void) chmod(path,0666);
+#endif
+ if (init_io_cache(&cache,file,0L,WRITE_CACHE,0L,1,MYF(MY_WME)))
+ {
+ my_close(file,MYF(0));
+ my_delete(path,MYF(0));
+ file= -1;
+ return 1;
+ }
+ return 0;
+}
+
+
+bool select_dump::send_data(List<Item> &items)
+{
+ List_iterator<Item> li(items);
+ char buff[MAX_FIELD_WIDTH];
+ String tmp(buff,sizeof(buff)),*res;
+ tmp.length(0);
+ Item *item;
+ DBUG_ENTER("send_data");
+
+ if (thd->offset_limit)
+ { // using limit offset,count
+ thd->offset_limit--;
+ DBUG_RETURN(0);
+ }
+ if (row_count++ > 1)
+ {
+ my_error(ER_TOO_MANY_ROWS,MYF(0));
+ goto err;
+ }
+ while ((item=li++))
+ {
+ Item_result result_type=item->result_type();
+ res=item->str_result(&tmp);
+ if (!res)
+ {
+ if (my_b_write(&cache,(byte*) "",1)) goto err; // NULL
+ }
+ else if (my_b_write(&cache,(byte*) res->ptr(),res->length()))
+ {
+ my_error(ER_ERROR_ON_WRITE,MYF(0), path, my_errno);
+ goto err;
+ }
+ }
+ DBUG_RETURN(0);
+err:
+ DBUG_RETURN(1);
+}
+
+
+void select_dump::send_error(uint errcode,const char *err)
+{
+ ::send_error(&thd->net,errcode,err);
+ (void) end_io_cache(&cache);
+ (void) my_close(file,MYF(0));
+ (void) my_delete(path,MYF(0)); // Delete file on error
+ file= -1;
+}
+
+
+bool select_dump::send_eof()
+{
+ int error=test(end_io_cache(&cache));
+ if (my_close(file,MYF(MY_WME)))
+ error=1;
+ if (error)
+ ::send_error(&thd->net);
+ else
+ ::send_ok(&thd->net,row_count);
+ file= -1;
+ return error;
+}
diff --git a/sql/sql_class.h b/sql/sql_class.h
new file mode 100644
index 00000000000..2ea18751dea
--- /dev/null
+++ b/sql/sql_class.h
@@ -0,0 +1,472 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+
+/* Classes in mysql */
+
+#ifdef __GNUC__
+#pragma interface /* gcc class implementation */
+#endif
+
+
+class Query_log_event;
+class Load_log_event;
+
+
+enum enum_duplicates { DUP_ERROR, DUP_REPLACE, DUP_IGNORE };
+enum enum_log_type { LOG_CLOSED, LOG_NORMAL, LOG_NEW, LOG_BIN };
+
+// log info errors
+#define LOG_INFO_EOF -1
+#define LOG_INFO_IO -2
+#define LOG_INFO_INVALID -3
+#define LOG_INFO_SEEK -4
+
+typedef struct st_log_info
+{
+ char log_file_name[FN_REFLEN];
+ my_off_t index_file_offset;
+ my_off_t pos;
+} LOG_INFO;
+
+typedef struct st_master_info
+{
+ char log_file_name[FN_REFLEN];
+ ulong pos;
+ FILE* file; // we keep the file open, so we need to remember the file pointer
+
+ // 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];
+ uint port;
+ uint connect_retry;
+ pthread_mutex_t lock;
+ bool inited;
+
+ st_master_info():inited(0) { host[0] = 0; user[0] = 0; password[0] = 0;}
+ inline void inc_pos(ulong val)
+ {
+ pthread_mutex_lock(&lock);
+ pos += val;
+ 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(ulong& var)
+ {
+ pthread_mutex_lock(&lock);
+ var = pos;
+ pthread_mutex_unlock(&lock);
+ }
+} MASTER_INFO;
+
+class MYSQL_LOG {
+ public:
+ private:
+ pthread_mutex_t LOCK_log, LOCK_index;
+ FILE *file, *index_file;
+ time_t last_time,query_start;
+ char *name;
+ enum_log_type log_type;
+ char time_buff[20],db[NAME_LEN+1];
+ char log_file_name[FN_REFLEN],index_file_name[FN_REFLEN];
+ bool write_error,inited;
+
+public:
+ MYSQL_LOG();
+ ~MYSQL_LOG();
+ pthread_mutex_t* get_log_lock() { return &LOCK_log; }
+ void set_index_file_name(const char* index_file_name = 0);
+ void open(const char *log_name,enum_log_type log_type,
+ const char *new_name=0);
+ void new_file(void);
+ void write(enum enum_server_command command,const char *format,...);
+ void write(const char *query, uint query_length, ulong time_to_do_query=0);
+ void write(Query_log_event* event_info); // binary log write
+ void write(Load_log_event* event_info);
+
+ 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);
+ void flush(void);
+ 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 get_current_log(LOG_INFO* linfo);
+
+ bool is_open() { return log_type != LOG_CLOSED; }
+ char* get_index_fname() { return index_file_name;}
+ char* get_log_fname() { return log_file_name; }
+};
+
+/* character conversion tables */
+
+class CONVERT
+{
+ const uchar *from_map,*to_map;
+ 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) {}
+ 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);
+};
+
+typedef struct st_copy_info {
+ ha_rows records;
+ ha_rows deleted;
+ ha_rows copied;
+ ha_rows error;
+ enum enum_duplicates handle_duplicates;
+ int escape_char;
+} COPY_INFO;
+
+
+class key_part_spec :public Sql_alloc {
+public:
+ const char *field_name;
+ uint length;
+ key_part_spec(const char *name,uint len=0) :field_name(name), length(len) {}
+};
+
+
+class Alter_drop :public Sql_alloc {
+public:
+ enum drop_type {KEY, COLUMN };
+ const char *name;
+ enum drop_type type;
+ Alter_drop(enum drop_type par_type,const char *par_name)
+ :name(par_name), type(par_type) {}
+};
+
+
+class Alter_column :public Sql_alloc {
+public:
+ const char *name;
+ Item *def;
+ Alter_column(const char *par_name,Item *literal)
+ :name(par_name), def(literal) {}
+};
+
+
+class Key :public Sql_alloc {
+public:
+ enum Keytype { PRIMARY, UNIQUE, MULTIPLE, FULLTEXT };
+ enum Keytype type;
+ List<key_part_spec> columns;
+ const char *Name;
+
+ Key(enum Keytype type_par,const char *name_arg,List<key_part_spec> &cols)
+ :type(type_par), columns(cols),Name(name_arg) {}
+ ~Key() {}
+ const char *name() { return Name; }
+};
+
+
+typedef struct st_mysql_lock
+{
+ TABLE **table;
+ uint table_count,lock_count;
+ THR_LOCK_DATA **locks;
+} MYSQL_LOCK;
+
+
+class LEX_COLUMN : public Sql_alloc
+{
+public:
+ String column;
+ uint rights;
+ LEX_COLUMN (const String& x,const uint& y ): column (x),rights (y) {}
+};
+
+#include "sql_lex.h" /* Must be here */
+
+// needed to be able to have an I_List of char* strings.in mysqld.cc where we cannot use String
+// because it is Sql_alloc'ed
+class i_string: public ilink
+{
+public:
+ char* ptr;
+ i_string():ptr(0) { }
+ i_string(char* s) : ptr(s) {}
+};
+
+/****************************************************************************
+** every connection is handle by a thread with a THD
+****************************************************************************/
+
+class delayed_insert;
+
+class THD :public ilink {
+public:
+ NET net;
+ LEX lex;
+ MEM_ROOT alloc;
+ HASH user_vars;
+ String packet; /* Room for 1 row */
+ struct sockaddr_in remote;
+ struct rand_struct rand;
+ char *query,*thread_stack;
+ char *host,*user,*priv_user,*db,*ip;
+ const char *proc_info;
+ uint client_capabilities,max_packet_length;
+ uint master_access,db_access;
+ TABLE *open_tables,*temporary_tables;
+ MYSQL_LOCK *lock,*locked_tables;
+ ULL *ull;
+ struct st_my_thread_var *mysys_var;
+ enum enum_server_command command;
+ 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_t connect_time,thr_create_time; // track down slow pthread_create
+ thr_lock_type update_lock_default;
+ delayed_insert *di;
+ struct st_transactions {
+ void *bdb_tid;
+ uint bdb_lock_count;
+ } transaction;
+ Item *free_list;
+ CONVERT *convert_set;
+ Field *dupp_field;
+#ifndef __WIN__
+ sigset_t signals,block_signals;
+#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;
+ 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;
+ char scramble[9];
+ 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,user_time;
+ bool volatile killed,bootstrap;
+ bool system_thread,in_lock_tables,global_read_lock;
+ bool query_error;
+ THD();
+ ~THD();
+ bool store_globals();
+ inline time_t query_start() { query_start_used=1; return start_time; }
+ inline void set_time() { if (!user_time) time(&start_time); }
+ inline void set_time(time_t t) { start_time=t; user_time=1; }
+ inline void insert_id(ulonglong id)
+ { last_insert_id=id; insert_id_used=1; }
+ inline ulonglong insert_id(void)
+ {
+ if (!last_insert_id_used)
+ {
+ last_insert_id_used=1;
+ current_insert_id=last_insert_id;
+ }
+ return last_insert_id;
+ }
+};
+
+
+class sql_exchange :public Sql_alloc
+{
+public:
+ char *file_name;
+ String *field_term,*enclosed,*line_term,*line_start,*escaped;
+ bool opt_enclosed;
+ bool dumpfile;
+ uint skip_lines;
+ sql_exchange(char *name,bool dumpfile_flag);
+ ~sql_exchange() {}
+};
+
+#include "log_event.h"
+
+/*
+** This is used to get result from a select
+*/
+
+class select_result :public Sql_alloc {
+protected:
+ THD *thd;
+public:
+ select_result();
+ virtual ~select_result() {};
+ 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 bool send_eof()=0;
+ virtual void abort() {}
+};
+
+
+class select_send :public select_result {
+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();
+};
+
+
+class select_export :public select_result {
+ sql_exchange *exchange;
+ File file;
+ IO_CACHE cache;
+ ha_rows row_count;
+ uint field_term_length;
+ int field_sep_char,escape_char,line_sep_char;
+ bool fixed_row_size;
+public:
+ select_export(sql_exchange *ex) :exchange(ex),file(-1),row_count(0L) {}
+ ~select_export();
+ int prepare(List<Item> &list);
+ 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_dump :public select_result {
+ sql_exchange *exchange;
+ File file;
+ IO_CACHE cache;
+ ha_rows row_count;
+ char path[FN_REFLEN];
+public:
+ select_dump(sql_exchange *ex) :exchange(ex),file(-1),row_count(0L)
+ { path[0]=0; }
+ ~select_dump();
+ int prepare(List<Item> &list);
+ 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_insert :public select_result {
+ protected:
+ TABLE *table;
+ List<Item> *fields;
+ uint save_time_stamp;
+ ulonglong last_insert_id;
+ COPY_INFO info;
+
+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;
+ }
+ ~select_insert();
+ int prepare(List<Item> &list);
+ 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;
+ const char *name;
+ List<create_field> *extra_fields;
+ List<Key> *keys;
+ HA_CREATE_INFO *create_info;
+ MYSQL_LOCK *lock;
+ Field **field;
+public:
+ select_create (const char *db_name, const char *table_name,
+ HA_CREATE_INFO *create_info_par,
+ List<create_field> &fields_par,
+ List<Key> &keys_par,
+ List<Item> &select_fields,enum_duplicates duplic)
+ :select_insert (NULL, &select_fields, duplic), db(db_name),
+ name(table_name), extra_fields(&fields_par),keys(&keys_par),
+ create_info(create_info_par),
+ lock(0)
+ {}
+ int prepare(List<Item> &list);
+ bool send_data(List<Item> &values);
+ bool send_eof();
+ void abort();
+};
+
+/* Structs used when sorting */
+
+typedef struct st_sort_field {
+ Field *field; /* Field to sort */
+ Item *item; /* Item if not sorting fields */
+ uint length; /* Length of sort field */
+ my_bool reverse; /* if descending sort */
+ Item_result result_type; /* Type of item */
+} SORT_FIELD;
+
+
+typedef struct st_sort_buffer {
+ uint index; /* 0 or 1 */
+ uint sort_orders;
+ uint change_pos; /* If sort-fields changed */
+ char **buff;
+ SORT_FIELD *sortorder;
+} SORT_BUFFER;
+
+
+/* Structure for db & table in sql_yacc */
+
+class Table_ident :public Sql_alloc {
+ public:
+ LEX_STRING db;
+ LEX_STRING table;
+ inline Table_ident(LEX_STRING db_arg,LEX_STRING table_arg,bool force)
+ :table(table_arg)
+ {
+ if (!force && (current_thd->client_capabilities & CLIENT_NO_SCHEMA))
+ db.str=0;
+ else
+ db= db_arg;
+ }
+ inline Table_ident(LEX_STRING table_arg) :table(table_arg) {db.str=0;}
+ inline void change_db(char *db_name)
+ { db.str= db_name; db.length=strlen(db_name); }
+};
+
+// this is needed for user_vars hash
+class user_var_entry
+{
+ public:
+ LEX_STRING name;
+ char *value;
+ ulong length;
+ Item_result type;
+};
+
diff --git a/sql/sql_crypt.cc b/sql/sql_crypt.cc
new file mode 100644
index 00000000000..371d63f8c73
--- /dev/null
+++ b/sql/sql_crypt.cc
@@ -0,0 +1,82 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 the encode() and decode() functions
+ The strongness of this crypt is large based on how good the random
+ generator is. It should be ok for short strings, but for communication one
+ needs something like 'ssh'.
+*/
+
+#ifdef __GNUC__
+#pragma implementation // gcc: Class implementation
+#endif
+
+#include "mysql_priv.h"
+
+SQL_CRYPT::SQL_CRYPT(const char *password)
+{
+ ulong rand_nr[2];
+ hash_password(rand_nr,password);
+ crypt_init(rand_nr);
+}
+
+void SQL_CRYPT::crypt_init(ulong *rand_nr)
+{
+ uint i;
+ randominit(&rand,rand_nr[0],rand_nr[1]);
+
+ for (i=0 ; i<=255; i++)
+ decode_buff[i]= (char) i;
+
+ for (i=0 ; i<= 255 ; i++)
+ {
+ int idx= (uint) (rnd(&rand)*255.0);
+ char a= decode_buff[idx];
+ decode_buff[idx]= decode_buff[i];
+ decode_buff[+i]=a;
+ }
+ for (i=0 ; i <= 255 ; i++)
+ encode_buff[(unsigned char) decode_buff[i]]=i;
+ org_rand=rand;
+ shift=0;
+}
+
+
+void SQL_CRYPT::encode(char *str,uint length)
+{
+ for (uint i=0; i < length; i++)
+ {
+ shift^=(uint) (rnd(&rand)*255.0);
+ uint idx= (uint) (uchar) str[0];
+ *str++ = (char) ((uchar) encode_buff[idx] ^ shift);
+ shift^= idx;
+ }
+}
+
+
+void SQL_CRYPT::decode(char *str,uint length)
+{
+ for (uint i=0; i < length; i++)
+ {
+ shift^=(uint) (rnd(&rand)*255.0);
+ uint idx= (uint) ((unsigned char) str[0] ^ shift);
+ *str = decode_buff[idx];
+ shift^= (uint) (uchar) *str++;
+ }
+}
diff --git a/sql/sql_crypt.h b/sql/sql_crypt.h
new file mode 100644
index 00000000000..b3a9d54133f
--- /dev/null
+++ b/sql/sql_crypt.h
@@ -0,0 +1,38 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+
+#ifdef __GNUC__
+#pragma interface /* gcc class implementation */
+#endif
+
+class SQL_CRYPT :public Sql_alloc
+{
+ struct rand_struct rand,org_rand;
+ char decode_buff[256],encode_buff[256];
+ uint shift;
+ void crypt_init(ulong *seed);
+ public:
+ SQL_CRYPT(const char *seed);
+ SQL_CRYPT(ulong *seed)
+ {
+ crypt_init(seed);
+ }
+ ~SQL_CRYPT() {}
+ void init() { shift=0; rand=org_rand; }
+ void encode(char *str, uint length);
+ void decode(char *str, uint length);
+};
diff --git a/sql/sql_db.cc b/sql/sql_db.cc
new file mode 100644
index 00000000000..33c8ee54037
--- /dev/null
+++ b/sql/sql_db.cc
@@ -0,0 +1,300 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 and drop of databases */
+
+#include "mysql_priv.h"
+#include "sql_acl.h"
+#include <my_dir.h>
+#include <m_ctype.h>
+#ifdef __WIN__
+#include <direct.h>
+#endif
+
+static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *path,
+ uint level);
+
+void mysql_create_db(THD *thd, char *db, uint create_options)
+{
+ char path[FN_REFLEN+16];
+ MY_DIR *dirp;
+ long result=1;
+ DBUG_ENTER("mysql_create_db");
+
+ if (!stripp_sp(db) || strlen(db) > NAME_LEN || check_db_name(db))
+ {
+ net_printf(&thd->net,ER_WRONG_DB_NAME, db);
+ DBUG_VOID_RETURN;
+ }
+ VOID(pthread_mutex_lock(&LOCK_mysql_create_db));
+
+ /* Check directory */
+ (void)sprintf(path,"%s/%s", mysql_data_home, db);
+ unpack_dirname(path,path); // Convert if not unix
+ if ((dirp = my_dir(path,MYF(MY_DONT_SORT))))
+ {
+ my_dirend(dirp);
+ if (!(create_options & HA_LEX_CREATE_IF_NOT_EXISTS))
+ {
+ net_printf(&thd->net,ER_DB_CREATE_EXISTS,db);
+ goto exit;
+ }
+ result = 0;
+ }
+ else
+ {
+ 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);
+ goto exit;
+ }
+ }
+ if (!thd->query)
+ {
+ thd->query = path;
+ thd->query_length = (uint) (strxmov(path,"create database ", db, NullS)-
+ path);
+ }
+ {
+ mysql_update_log.write(thd->query, thd->query_length);
+ 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);
+
+exit:
+ VOID(pthread_mutex_unlock(&LOCK_mysql_create_db));
+ DBUG_VOID_RETURN;
+}
+
+const char *del_exts[]=
+{".frm",".ISM",".ISD",".ISM",".HSH",".DAT",".MRG",".PSM",".MYI",".MYD", ".db",
+ NullS};
+static TYPELIB deletable_extentions=
+{array_elements(del_exts)-1,"del_exts", del_exts};
+
+
+void mysql_rm_db(THD *thd,char *db,bool if_exists)
+{
+ long deleted=0;
+ char path[FN_REFLEN+16];
+ MY_DIR *dirp;
+ DBUG_ENTER("mysql_rm_db");
+
+ if (!stripp_sp(db) || strlen(db) > NAME_LEN || check_db_name(db))
+ {
+ net_printf(&thd->net,ER_WRONG_DB_NAME, db);
+ DBUG_VOID_RETURN;
+ }
+
+ VOID(pthread_mutex_lock(&LOCK_mysql_create_db));
+ VOID(pthread_mutex_lock(&LOCK_open));
+
+ (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 (!if_exists)
+ net_printf(&thd->net,ER_DB_DROP_EXISTS,db);
+ else
+ send_ok(&thd->net,0);
+ goto exit;
+ }
+ remove_db_from_cache(db);
+
+ if ((deleted=mysql_rm_known_files(thd, dirp, path,0)) >= 0)
+ {
+ if (!thd->query)
+ {
+ thd->query = path;
+ thd->query_length = (uint) (strxmov(path,"drop database ", db, NullS)-
+ path);
+ }
+ mysql_update_log.write(thd->query, thd->query_length);
+ 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);
+ }
+
+exit:
+ VOID(pthread_mutex_unlock(&LOCK_open));
+ VOID(pthread_mutex_unlock(&LOCK_mysql_create_db));
+ DBUG_VOID_RETURN;
+}
+
+/*
+ Removes files with known extensions plus all found subdirectories that
+ are 2 digits (raid directories).
+*/
+
+static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *path,
+ uint level)
+{
+ long deleted=0;
+ ulong found_other_files=0;
+ char filePath[FN_REFLEN];
+ DBUG_ENTER("mysql_rm_known_files");
+ DBUG_PRINT("enter",("path: %s", path));
+ /* remove all files with known extensions */
+
+ for (uint idx=2 ;
+ idx < (uint) dirp->number_off_files && !thd->killed ;
+ idx++)
+ {
+ FILEINFO *file=dirp->dir_entry+idx;
+ DBUG_PRINT("info",("Examining: %s", file->name));
+
+ /* Check if file is a raid directory */
+ if (isdigit(file->name[0]) && isdigit(file->name[1]) &&
+ !file->name[2] && !level)
+ {
+ char newpath[FN_REFLEN];
+ MY_DIR *new_dirp;
+ strxmov(newpath,path,"/",file->name,NullS);
+ 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)
+ {
+ my_dirend(dirp);
+ DBUG_RETURN(-1);
+ }
+ }
+ continue;
+ }
+ if (find_type(fn_ext(file->name),&deletable_extentions,1) <= 0)
+ {
+ found_other_files++;
+ continue;
+ }
+ strxmov(filePath,path,"/",file->name,NullS);
+ if (my_delete(filePath,MYF(MY_WME)))
+ {
+ net_printf(&thd->net,ER_DB_DROP_DELETE,filePath,my_error);
+ my_dirend(dirp);
+ DBUG_RETURN(-1);
+ }
+ deleted++;
+ }
+
+ my_dirend(dirp);
+
+ if (thd->killed)
+ {
+ send_error(&thd->net,ER_SERVER_SHUTDOWN);
+ DBUG_RETURN(-1);
+ }
+
+ /*
+ If the directory is a symbolic link, remove the link first, then
+ remove the directory the symbolic link pointed at
+ */
+ if (!found_other_files)
+ {
+#ifdef HAVE_READLINK
+ int linkcount = readlink(path,filePath,sizeof(filePath)-1);
+ if (linkcount > 0) // If the path was a symbolic link
+ {
+ *(filePath + linkcount) = '\0';
+ if (my_delete(path,MYF(!level ? MY_WME : 0)))
+ {
+ /* Don't give errors if we can't delete 'RAID' directory */
+ if (level)
+ DBUG_RETURN(deleted);
+ send_error(&thd->net);
+ DBUG_RETURN(-1);
+ }
+ path=filePath;
+ }
+#endif
+ /* 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);
+ DBUG_RETURN(-1);
+ }
+ }
+ DBUG_RETURN(deleted);
+}
+
+
+bool mysql_change_db(THD *thd,const char *name)
+{
+ int 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)))
+ {
+ x_free(dbname); /* purecov: inspected */
+ send_error(&thd->net,ER_NO_DB_ERROR); /* purecov: inspected */
+ DBUG_RETURN(1); /* purecov: inspected */
+ }
+ if (length > NAME_LEN)
+ {
+ net_printf(&thd->net,ER_WRONG_DB_NAME, dbname);
+ DBUG_RETURN(1);
+ }
+ DBUG_PRINT("general",("Use database: %s", dbname));
+ if (test_all_bits(thd->master_access,DB_ACLS))
+ db_access=DB_ACLS;
+ else
+ db_access= (acl_get(thd->host,thd->ip,(char*) &thd->remote.sin_addr,
+ thd->priv_user,dbname) |
+ thd->master_access);
+ if (!(db_access & DB_ACLS) && (!grant_option || check_grant_db(thd,dbname)))
+ {
+ net_printf(&thd->net,ER_DBACCESS_DENIED_ERROR,
+ thd->priv_user,
+ thd->host ? thd->host : thd->ip ? thd->ip : "unknown",
+ dbname);
+ mysql_log.write(COM_INIT_DB,ER(ER_DBACCESS_DENIED_ERROR),
+ thd->priv_user,
+ thd->host ? thd->host : thd->ip ? thd->ip : "unknown",
+ dbname);
+ my_free(dbname,MYF(0));
+ DBUG_RETURN(1);
+ }
+
+ (void) sprintf(path,"%s/%s",mysql_data_home,dbname);
+ unpack_dirname(path,path); // Convert if not unix
+ if (access(path,F_OK))
+ {
+ net_printf(&thd->net,ER_BAD_DB_ERROR,dbname);
+ my_free(dbname,MYF(0));
+ DBUG_RETURN(1);
+ }
+ send_ok(&thd->net);
+ x_free(thd->db);
+ thd->db=dbname;
+ thd->db_access=db_access;
+ DBUG_RETURN(0);
+}
diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc
new file mode 100644
index 00000000000..5d21a089283
--- /dev/null
+++ b/sql/sql_delete.cc
@@ -0,0 +1,213 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 of records */
+
+#include "mysql_priv.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
+*/
+
+static 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";
+ /* 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)
+ {
+ send_ok(&thd->net); // This should return record count
+ mysql_update_log.write(thd->query,thd->query_length);
+ Query_log_event qinfo(thd, thd->query);
+ mysql_bin_log.write(&qinfo);
+ }
+ DBUG_RETURN(error ? -1 : 0);
+}
+
+
+int mysql_delete(THD *thd,TABLE_LIST *table_list,COND *conds,ha_rows limit,
+ thr_lock_type lock_type)
+{
+ int error;
+ TABLE *table;
+ SQL_SELECT *select;
+ READ_RECORD info;
+ bool using_limit=limit != HA_POS_ERROR;
+ bool use_generate_table;
+ DBUG_ENTER("mysql_delete");
+
+ if (!table_list->db)
+ table_list->db=thd->db;
+ if ((thd->options & OPTION_SAFE_UPDATES) && !conds)
+ {
+ send_error(&thd->net,ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE);
+ DBUG_RETURN(1);
+ }
+
+ use_generate_table= (!using_limit && !conds &&
+ !(specialflag &
+ (SPECIAL_NO_NEW_FUNC | SPECIAL_SAFE_MODE)) &&
+ (thd->options & OPTION_AUTO_COMMIT));
+ 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)))
+ DBUG_RETURN(-1);
+ 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))
+ DBUG_RETURN(-1);
+
+ 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))
+ {
+ delete select;
+ send_ok(&thd->net,0L);
+ DBUG_RETURN(0);
+ }
+
+ /* If running in safe sql mode, don't allow updates without keys */
+ if ((thd->options & OPTION_SAFE_UPDATES) && !table->quick_keys &&
+ limit == HA_POS_ERROR)
+ {
+ delete select;
+ send_error(&thd->net,ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE);
+ DBUG_RETURN(1);
+ }
+
+ (void) table->file->extra(HA_EXTRA_NO_READCHECK);
+ init_read_record(&info,thd,table,select,1,1);
+ ulong deleted=0L;
+ thd->proc_info="updating";
+ while (!(error=info.read_record(&info)) && !thd->killed)
+ {
+ if (!(select && select->skipp_record()))
+ {
+ if (!(error=table->file->delete_row(table->record[0])))
+ {
+ deleted++;
+ if (!--limit && using_limit)
+ {
+ error= -1;
+ break;
+ }
+ }
+ else
+ {
+ table->file->print_error(error,MYF(0));
+ error=0;
+ break;
+ }
+ }
+ }
+ thd->proc_info="end";
+ end_read_record(&info);
+ VOID(table->file->extra(HA_EXTRA_READCHECK));
+ if (deleted)
+ {
+ mysql_update_log.write(thd->query, thd->query_length);
+ Query_log_event qinfo(thd, thd->query);
+ mysql_bin_log.write(&qinfo);
+ }
+ if (ha_autocommit_or_rollback(thd,error >= 0))
+ error=1;
+ if (thd->lock)
+ {
+ mysql_unlock_tables(thd, thd->lock);
+ thd->lock=0;
+ }
+ delete select;
+ if (error >= 0) // Fatal error
+ send_error(&thd->net,thd->killed ? ER_SERVER_SHUTDOWN: 0);
+ else
+ {
+ send_ok(&thd->net,deleted);
+ DBUG_PRINT("info",("%d records deleted",deleted));
+ }
+ DBUG_RETURN(0);
+}
+
+
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
new file mode 100644
index 00000000000..a7a6a6c24c7
--- /dev/null
+++ b/sql/sql_insert.cc
@@ -0,0 +1,1346 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+
+/* Insert of records */
+
+#include "mysql_priv.h"
+#include "sql_acl.h"
+
+static int check_null_fields(THD *thd,TABLE *entry);
+static TABLE *delayed_get_table(THD *thd,TABLE_LIST *table_list);
+static int write_delayed(THD *thd,TABLE *table, enum_duplicates dup,
+ char *query, uint query_length, bool log_on);
+static void end_delayed_insert(THD *thd);
+static pthread_handler_decl(handle_delayed_insert,arg);
+static void unlink_blobs(register TABLE *table);
+
+/* Define to force use of my_malloc() if the allocated memory block is big */
+
+#ifndef HAVE_ALLOCA
+#define my_safe_alloca(size, min_length) my_alloca(size)
+#define my_safe_afree(ptr, size, min_length) my_afree(ptr)
+#else
+#define my_safe_alloca(size, min_length) ((size <= min_length) ? my_alloca(size) : my_malloc(size,MYF(0)))
+#define my_safe_afree(ptr, size, min_length) if (size > min_length) my_free(ptr,MYF(0))
+#endif
+
+
+/*
+ Check if insert fields are correct
+ Resets form->time_stamp if a timestamp value is set
+*/
+
+static int
+check_insert_fields(THD *thd,TABLE *table,List<Item> &fields,
+ List<Item> &values, ulong counter)
+{
+ if (fields.elements == 0 && values.elements != 0)
+ {
+ if (values.elements != table->fields)
+ {
+ my_printf_error(ER_WRONG_VALUE_COUNT_ON_ROW,
+ ER(ER_WRONG_VALUE_COUNT_ON_ROW),
+ MYF(0),counter);
+ return -1;
+ }
+ if (grant_option &&
+ check_grant_all_columns(thd,INSERT_ACL,table))
+ return -1;
+ table->time_stamp=0; // This should be saved
+ }
+ else
+ { // Part field list
+ if (fields.elements != values.elements)
+ {
+ my_printf_error(ER_WRONG_VALUE_COUNT_ON_ROW,
+ ER(ER_WRONG_VALUE_COUNT_ON_ROW),
+ MYF(0),counter);
+ return -1;
+ }
+ TABLE_LIST table_list;
+ bzero((char*) &table_list,sizeof(table_list));
+ table_list.name=table->table_name;
+ table_list.table=table;
+ table_list.grant=table->grant;
+
+ thd->dupp_field=0;
+ if (setup_fields(thd,&table_list,fields,1,0))
+ return -1;
+ if (thd->dupp_field)
+ {
+ my_error(ER_FIELD_SPECIFIED_TWICE,MYF(0), thd->dupp_field->field_name);
+ return -1;
+ }
+ if (table->timestamp_field && // Don't set timestamp if used
+ table->timestamp_field->query_id == thd->query_id)
+ table->time_stamp=0; // This should be saved
+ }
+ // For the values we need select_priv
+ table->grant.want_privilege=(SELECT_ACL & ~table->grant.privilege);
+ return 0;
+}
+
+
+int mysql_insert(THD *thd,TABLE_LIST *table_list, List<Item> &fields,
+ List<List_item> &values_list,enum_duplicates duplic,
+ thr_lock_type lock_type)
+{
+ int error;
+ bool log_on= ((thd->options & OPTION_UPDATE_LOG) ||
+ !(thd->master_access & PROCESS_ACL));
+ 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_item *values;
+ char *query=thd->query;
+ DBUG_ENTER("mysql_insert");
+
+ if (lock_type == TL_WRITE_DELAYED &&
+ (specialflag & (SPECIAL_NO_NEW_FUNC | SPECIAL_SAFE_MODE)) ||
+ lock_type == TL_WRITE_CONCURRENT_INSERT && duplic == DUP_REPLACE)
+ lock_type=TL_WRITE;
+
+ if (lock_type == TL_WRITE_DELAYED)
+ {
+ if (thd->locked_tables)
+ {
+ if (find_locked_table(thd,
+ table_list->db ? table_list->db : thd->db,
+ table_list->real_name))
+ {
+ my_printf_error(ER_DELAYED_INSERT_TABLE_LOCKED,
+ ER(ER_DELAYED_INSERT_TABLE_LOCKED),
+ MYF(0), table_list->real_name);
+ DBUG_RETURN(-1);
+ }
+ }
+ if (!(table = delayed_get_table(thd,table_list)) && !thd->fatal_error)
+ table = open_ltable(thd,table_list,lock_type=thd->update_lock_default);
+ }
+ else
+ table = open_ltable(thd,table_list,lock_type);
+ if (!table)
+ DBUG_RETURN(-1);
+ thd->proc_info="init";
+ save_time_stamp=table->time_stamp;
+ values= its++;
+ if (check_insert_fields(thd,table,fields,*values,1) ||
+ setup_fields(thd,table_list,*values,0,0))
+ {
+ table->time_stamp=save_time_stamp;
+ goto abort;
+ }
+ value_count= values->elements;
+ while ((values = its++))
+ {
+ counter++;
+ if (values->elements != value_count)
+ {
+ my_printf_error(ER_WRONG_VALUE_COUNT_ON_ROW,
+ ER(ER_WRONG_VALUE_COUNT_ON_ROW),
+ MYF(0),counter);
+ table->time_stamp=save_time_stamp;
+ goto abort;
+ }
+ if (setup_fields(thd,table_list,*values,0,0))
+ {
+ table->time_stamp=save_time_stamp;
+ goto abort;
+ }
+ }
+ its.rewind ();
+ /*
+ ** Fill in the given fields and dump it to the table file
+ */
+
+ info.records=info.deleted=info.copied=0;
+ info.handle_duplicates=duplic;
+ // Don't count warnings for simple inserts
+ if (values_list.elements > 1 || (thd->options & OPTION_WARNINGS))
+ thd->count_cuted_fields = 1;
+ thd->cuted_fields = 0L;
+ table->next_number_field=table->found_next_number_field;
+
+ error=0;
+ id=0;
+ thd->proc_info="update";
+ while ((values = its++))
+ {
+ if (fields.elements || !value_count)
+ {
+ restore_record(table,2); // Get empty record
+ if (fill_record(fields,*values) || check_null_fields(thd,table))
+ {
+ if (values_list.elements != 1)
+ {
+ info.records++;
+ continue;
+ }
+ error=1;
+ break;
+ }
+ }
+ else
+ {
+ table->record[0][0]=table->record[2][0]; // Fix delete marker
+ if (fill_record(table->field,*values))
+ {
+ if (values_list.elements != 1)
+ {
+ info.records++;
+ continue;
+ }
+ error=1;
+ break;
+ }
+ }
+ if (lock_type == TL_WRITE_DELAYED)
+ {
+ error=write_delayed(thd,table,duplic,query, thd->query_length, log_on);
+ query=0;
+ }
+ else
+ error=write_record(table,&info);
+ if (error)
+ break;
+ /*
+ If auto_increment values are used, save the first one
+ for LAST_INSERT_ID() and for the update log.
+ We can't use insert_id() as we don't want to touch the
+ last_insert_id_used flag.
+ */
+ if (! id && thd->insert_id_used)
+ { // Get auto increment value
+ id= thd->last_insert_id;
+ }
+ }
+ if (lock_type == TL_WRITE_DELAYED)
+ {
+ id=0; // No auto_increment id
+ info.copied=values_list.elements;
+ end_delayed_insert(thd);
+ }
+ else
+ {
+ if (id && values_list.elements != 1)
+ thd->insert_id(id); // For update log
+ else if (table->next_number_field)
+ id=table->next_number_field->val_int(); // Return auto_increment value
+ if (info.copied || info.deleted)
+ {
+ mysql_update_log.write(thd->query, thd->query_length);
+ Query_log_event qinfo(thd, thd->query);
+ mysql_bin_log.write(&qinfo);
+ }
+ error=ha_autocommit_or_rollback(thd,error);
+ if (thd->lock)
+ {
+ mysql_unlock_tables(thd, thd->lock);
+ thd->lock=0;
+ }
+ }
+ thd->proc_info="end";
+ 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 (error)
+ goto abort;
+
+ if (values_list.elements == 1 && (!(thd->options & OPTION_WARNINGS) ||
+ !thd->cuted_fields))
+ send_ok(&thd->net,info.copied+info.deleted,id);
+ else {
+ char buff[160];
+ if (duplic == DUP_IGNORE)
+ sprintf(buff,ER(ER_INSERT_INFO),info.records,info.records-info.copied,
+ thd->cuted_fields);
+ else
+ sprintf(buff,ER(ER_INSERT_INFO),info.records,info.deleted,
+ thd->cuted_fields);
+ ::send_ok(&thd->net,info.copied+info.deleted,0L,buff);
+ }
+ DBUG_RETURN(0);
+
+abort:
+ if (lock_type == TL_WRITE_DELAYED)
+ end_delayed_insert(thd);
+ DBUG_RETURN(-1);
+}
+
+
+ /* Check if there is more uniq keys after field */
+
+static int last_uniq_key(TABLE *table,uint keynr)
+{
+ while (++keynr < table->keys)
+ if (table->key_info[keynr].flags & HA_NOSAME)
+ return 0;
+ return 1;
+}
+
+
+/*
+** Write a record to table with optional deleting of conflicting records
+*/
+
+
+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)
+ 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 */
+ goto err;
+ }
+ if (table->file->option_flag() & HA_DUPP_POS)
+ {
+ if (table->file->rnd_pos(table->record[1],table->file->dupp_ref))
+ goto err;
+ }
+ else
+ {
+ if (table->file->extra(HA_EXTRA_FLUSH_CACHE)) /* Not neaded with NISAM */
+ {
+ error=my_errno;
+ goto err;
+ }
+
+ if (!key)
+ {
+ if (!(key=(char*) my_safe_alloca(table->max_unique_length,
+ MAX_KEY_LENGTH)))
+ {
+ error=ENOMEM;
+ goto err;
+ }
+ }
+ key_copy((byte*) key,table,key_nr,0);
+ if ((error=(table->file->index_read_idx(table->record[1],key_nr,
+ (byte*) key,0,
+ HA_READ_KEY_EXACT))))
+ goto err;
+ }
+ if (last_uniq_key(table,key_nr))
+ {
+ if ((error=table->file->update_row(table->record[1],table->record[0])))
+ goto err;
+ info->deleted++;
+ break; /* Update logfile and count */
+ }
+ else if ((error=table->file->delete_row(table->record[1])))
+ goto err;
+ info->deleted++;
+ }
+ info->copied++;
+ }
+ else if ((error=table->file->write_row(table->record[0])))
+ {
+ if (info->handle_duplicates != DUP_IGNORE ||
+ (error != HA_ERR_FOUND_DUPP_KEY && error != HA_ERR_FOUND_DUPP_UNIQUE))
+ goto err;
+ }
+ else
+ info->copied++;
+ if (key)
+ my_safe_afree(key,table->max_unique_length,MAX_KEY_LENGTH);
+ return 0;
+
+err:
+ if (key)
+ my_afree(key);
+ table->file->print_error(error,MYF(0));
+ return 1;
+}
+
+
+/******************************************************************************
+ Check that all fields with arn't null_fields are used
+ if DONT_USE_DEFAULT_FIELDS isn't defined use default value for not
+ set fields.
+******************************************************************************/
+
+static int check_null_fields(THD *thd __attribute__((unused)),
+ TABLE *entry __attribute__((unused)))
+{
+#ifdef DONT_USE_DEFAULT_FIELDS
+ for (Field **field=entry->field ; *field ; field++)
+ {
+ if ((*field)->query_id != thd->query_id && !(*field)->maybe_null() &&
+ *field != entry->timestamp_field &&
+ *field != entry->next_number_field)
+ {
+ my_printf_error(ER_BAD_NULL_ERROR, ER(ER_BAD_NULL_ERROR),MYF(0),
+ (*field)->field_name);
+ return 1;
+ }
+ }
+#endif
+ return 0;
+}
+
+/*****************************************************************************
+** Handling of delayed inserts
+**
+** A thread is created for each table that one uses with the DELAYED
+** attribute.
+*****************************************************************************/
+
+class delayed_row :public ilink {
+public:
+ char *record,*query;
+ enum_duplicates dup;
+ time_t start_time;
+ bool query_start_used,last_insert_id_used,insert_id_used,log_query;
+ ulonglong last_insert_id;
+ ulong time_stamp;
+ uint query_length;
+
+ delayed_row(enum_duplicates dup_arg, bool log_query_arg)
+ :record(0),query(0),dup(dup_arg),log_query(log_query_arg) {}
+ ~delayed_row()
+ {
+ x_free(record);
+ }
+};
+
+
+class delayed_insert :public ilink {
+ uint locks_in_memory;
+public:
+ THD thd;
+ TABLE *table;
+ pthread_mutex_t mutex;
+ pthread_cond_t cond,cond_client;
+ volatile uint tables_in_use,stacked_inserts;
+ volatile bool status,dead;
+ COPY_INFO info;
+ I_List<delayed_row> rows;
+ uint group_count;
+ TABLE_LIST *table_list; // Argument
+
+ delayed_insert()
+ :locks_in_memory(0),
+ table(0),tables_in_use(0),stacked_inserts(0), status(0), dead(0),
+ group_count(0)
+ {
+ thd.user=thd.host=(char*) "";
+ thd.current_tablenr=0;
+ thd.version=refresh_version;
+ thd.command=COM_DELAYED_INSERT;
+
+ bzero((char*) &thd.net,sizeof(thd.net)); // Safety
+ thd.system_thread=1;
+ bzero((char*) &info,sizeof(info));
+ pthread_mutex_init(&mutex,NULL);
+ pthread_cond_init(&cond,NULL);
+ pthread_cond_init(&cond_client,NULL);
+ VOID(pthread_mutex_lock(&LOCK_thread_count));
+ delayed_insert_threads++;
+ VOID(pthread_mutex_unlock(&LOCK_thread_count));
+ }
+ ~delayed_insert()
+ {
+ /* The following is not really neaded, but just for safety */
+ delayed_row *row;
+ while ((row=rows.get()))
+ delete row;
+ pthread_mutex_destroy(&mutex);
+ if (table)
+ close_thread_tables(&thd);
+ VOID(pthread_mutex_lock(&LOCK_thread_count));
+ thd.unlink(); // Must be unlinked under lock
+ x_free(thd.query);
+ thd.user=thd.host=0;
+ thread_count--;
+ delayed_insert_threads--;
+ VOID(pthread_cond_broadcast(&COND_thread_count)); /* Tell main we are ready */
+ VOID(pthread_mutex_unlock(&LOCK_thread_count));
+ }
+
+ /* The following is for checking when we can delete ourselves */
+ inline void lock()
+ {
+ locks_in_memory++; // Assume LOCK_delay_insert
+ }
+ void unlock()
+ {
+ pthread_mutex_lock(&LOCK_delayed_insert);
+ if (!--locks_in_memory)
+ {
+ pthread_mutex_lock(&mutex);
+ if (thd.killed && ! stacked_inserts && ! tables_in_use)
+ {
+ pthread_cond_signal(&cond);
+ status=1;
+ }
+ pthread_mutex_unlock(&mutex);
+ }
+ pthread_mutex_unlock(&LOCK_delayed_insert);
+ }
+ inline uint lock_count() { return locks_in_memory; }
+
+ TABLE* get_local_table(THD* client_thd);
+ bool handle_inserts(void);
+};
+
+
+I_List<delayed_insert> delayed_threads;
+
+
+delayed_insert *find_handler(THD *thd, TABLE_LIST *table_list)
+{
+ thd->proc_info="waiting for delay_list";
+ pthread_mutex_lock(&LOCK_delayed_insert); // Protect master list
+ I_List_iterator<delayed_insert> it(delayed_threads);
+ delayed_insert *tmp;
+ while ((tmp=it++))
+ {
+ if (!strcmp(tmp->thd.db,table_list->db) &&
+ !strcmp(table_list->real_name,tmp->table->real_name))
+ {
+ tmp->lock();
+ break;
+ }
+ }
+ pthread_mutex_unlock(&LOCK_delayed_insert); // For unlink from list
+ return tmp;
+}
+
+
+static TABLE *delayed_get_table(THD *thd,TABLE_LIST *table_list)
+{
+ int error;
+ delayed_insert *tmp;
+ DBUG_ENTER("delayed_get_table");
+
+ if (!table_list->db)
+ table_list->db=thd->db;
+
+ /* no match; create a new thread to handle the table */
+ if (!(tmp=find_handler(thd,table_list)))
+ {
+ thd->proc_info="Creating delayed handler";
+ pthread_mutex_lock(&LOCK_delayed_create);
+ if (!(tmp=find_handler(thd,table_list))) // Was just created
+ {
+ if (!(tmp=new delayed_insert()))
+ {
+ thd->fatal_error=1;
+ my_error(ER_OUTOFMEMORY,MYF(0),sizeof(delayed_insert));
+ pthread_mutex_unlock(&LOCK_delayed_create);
+ DBUG_RETURN(0);
+ }
+ if (!(tmp->thd.db=my_strdup(table_list->db,MYF(MY_WME))) ||
+ !(tmp->thd.query=my_strdup(table_list->real_name,MYF(MY_FAE))))
+ {
+ delete tmp;
+ thd->fatal_error=1;
+ my_error(ER_OUT_OF_RESOURCES,MYF(0));
+ pthread_mutex_unlock(&LOCK_delayed_create);
+ DBUG_RETURN(0);
+ }
+ tmp->table_list=table_list; // Needed to open table
+ tmp->lock();
+ pthread_mutex_lock(&LOCK_thread_count);
+ thread_count++;
+ pthread_mutex_unlock(&LOCK_thread_count);
+ pthread_mutex_lock(&tmp->mutex);
+ if ((error=pthread_create(&tmp->thd.real_id,&connection_attrib,
+ handle_delayed_insert,(void*) tmp)))
+ {
+ DBUG_PRINT("error",
+ ("Can't create thread to handle delayed insert (error %d)",
+ error));
+ pthread_mutex_unlock(&tmp->mutex);
+ tmp->unlock();
+ delete tmp;
+ thd->fatal_error=1;
+ pthread_mutex_unlock(&LOCK_delayed_create);
+ net_printf(&thd->net,ER_CANT_CREATE_THREAD,error);
+ DBUG_RETURN(0);
+ }
+
+ /* Wait until table is open */
+ thd->proc_info="waiting for handler open";
+ while (!tmp->thd.killed && !tmp->table && !thd->killed)
+ {
+ pthread_cond_wait(&tmp->cond_client,&tmp->mutex);
+ }
+ pthread_mutex_unlock(&tmp->mutex);
+ thd->proc_info="got old table";
+ if (tmp->thd.killed)
+ {
+ if (tmp->thd.fatal_error)
+ {
+ /* 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;
+ }
+ tmp->unlock();
+ pthread_mutex_unlock(&LOCK_delayed_create);
+ DBUG_RETURN(0); // Continue with normal insert
+ }
+ if (thd->killed)
+ {
+ tmp->unlock();
+ pthread_mutex_unlock(&LOCK_delayed_create);
+ DBUG_RETURN(0);
+ }
+ }
+ pthread_mutex_unlock(&LOCK_delayed_create);
+ }
+
+ pthread_mutex_lock(&tmp->mutex);
+ TABLE *table=tmp->get_local_table(thd);
+ pthread_mutex_unlock(&tmp->mutex);
+ tmp->unlock();
+ if (table)
+ thd->di=tmp;
+ else if (tmp->thd.fatal_error)
+ thd->fatal_error=1;
+ DBUG_RETURN((table_list->table=table));
+}
+
+
+/*
+ As we can't let many threads modify the same TABLE structure, we create
+ an own structure for each tread. This includes a row buffer to save the
+ column values and new fields that points to the new row buffer.
+ The memory is allocated in the client thread and is freed automaticly.
+*/
+
+TABLE *delayed_insert::get_local_table(THD* client_thd)
+{
+ my_ptrdiff_t adjust_ptrs;
+ Field **field,**org_field;
+ TABLE *copy;
+
+ /* First request insert thread to get a lock */
+ status=1;
+ tables_in_use++;
+ if (!thd.lock) // Table is not locked
+ {
+ client_thd->proc_info="waiting for handler lock";
+ pthread_cond_signal(&cond); // Tell handler to lock table
+ while (!dead && !thd.lock && ! client_thd->killed)
+ {
+ pthread_cond_wait(&cond_client,&mutex);
+ }
+ client_thd->proc_info="got handler lock";
+ if (client_thd->killed)
+ goto error;
+ if (dead)
+ {
+ strmov(client_thd->net.last_error,thd.net.last_error);
+ client_thd->net.last_errno=thd.net.last_errno;
+ goto error;
+ }
+ }
+
+ client_thd->proc_info="allocating local table";
+ copy= (TABLE*) sql_alloc(sizeof(*copy)+
+ (table->fields+1)*sizeof(Field**)+
+ table->reclength);
+ if (!copy)
+ goto error;
+ *copy= *table;
+ bzero((char*) &copy->name_hash,sizeof(copy->name_hash)); // No name hashing
+ /* We don't need to change the file handler here */
+
+ field=copy->field=(Field**) (copy+1);
+ copy->record[0]=(byte*) (field+table->fields+1);
+ memcpy((char*) copy->record[0],(char*) table->record[0],table->reclength);
+
+ /* Make a copy of all fields */
+
+ adjust_ptrs=PTR_BYTE_DIFF(copy->record[0],table->record[0]);
+
+ for (org_field=table->field ; *org_field ; org_field++,field++)
+ {
+ if (!(*field= (*org_field)->new_field(copy)))
+ return 0;
+ (*field)->move_field(adjust_ptrs); // Point at copy->record[0]
+ }
+ *field=0;
+
+ /* Adjust timestamp */
+ if (table->timestamp_field)
+ {
+ /* Restore offset as this may have been reset in handle_inserts */
+ copy->time_stamp=table->timestamp_field->offset()+1;
+ copy->timestamp_field=
+ (Field_timestamp*) copy->field[table->timestamp_field_offset];
+ }
+
+ /* _rowid is not used with delayed insert */
+ copy->rowid_field=0;
+ return copy;
+
+ /* Got fatal error */
+ error:
+ tables_in_use--;
+ status=1;
+ pthread_cond_signal(&cond); // Inform thread about abort
+ return 0;
+}
+
+
+/* Put a question in queue */
+
+static int write_delayed(THD *thd,TABLE *table,enum_duplicates duplic,
+ char *query, uint query_length, bool log_on)
+{
+ delayed_row *row=0;
+ delayed_insert *di=thd->di;
+ DBUG_ENTER("write_delayed");
+
+ thd->proc_info="waiting for handler insert";
+ pthread_mutex_lock(&di->mutex);
+ while (di->stacked_inserts >= delayed_queue_size && !thd->killed)
+ pthread_cond_wait(&di->cond_client,&di->mutex);
+ thd->proc_info="storing row into queue";
+
+ if (thd->killed || !(row= new delayed_row(duplic, log_on)))
+ goto err;
+
+ if (!query)
+ query_length=0;
+ if (!(row->record= (char*) my_malloc(table->reclength+query_length+1,
+ MYF(MY_WME))))
+ goto err;
+ memcpy(row->record,table->record[0],table->reclength);
+ if (query_length)
+ {
+ row->query=row->record+table->reclength;
+ memcpy(row->query,query,query_length+1);
+ }
+ row->query_length= query_length;
+ row->start_time= thd->start_time;
+ row->query_start_used= thd->query_start_used;
+ row->last_insert_id_used= thd->last_insert_id_used;
+ row->insert_id_used= thd->insert_id_used;
+ row->last_insert_id= thd->last_insert_id;
+ row->time_stamp= table->time_stamp;
+
+ di->rows.push_back(row);
+ di->stacked_inserts++;
+ di->status=1;
+ if (table->blob_fields)
+ unlink_blobs(table);
+ pthread_cond_signal(&di->cond);
+
+ thread_safe_increment(delayed_rows_in_use,&LOCK_delayed_status);
+ pthread_mutex_unlock(&di->mutex);
+ DBUG_RETURN(0);
+
+ err:
+ delete row;
+ pthread_mutex_unlock(&di->mutex);
+ DBUG_RETURN(1);
+}
+
+
+static void end_delayed_insert(THD *thd)
+{
+ delayed_insert *di=thd->di;
+ pthread_mutex_lock(&di->mutex);
+ if (!--di->tables_in_use || di->thd.killed)
+ { // Unlock table
+ di->status=1;
+ pthread_cond_signal(&di->cond);
+ }
+ pthread_mutex_unlock(&di->mutex);
+}
+
+
+/* We kill all delayed threads when doing flush-tables */
+
+void kill_delayed_threads(void)
+{
+ VOID(pthread_mutex_lock(&LOCK_delayed_insert)); // For unlink from list
+
+ I_List_iterator<delayed_insert> it(delayed_threads);
+ delayed_insert *tmp;
+ while ((tmp=it++))
+ {
+ pthread_mutex_lock(&tmp->mutex);
+ tmp->thd.killed=1;
+ if (tmp->thd.mysys_var)
+ {
+ pthread_mutex_lock(&tmp->thd.mysys_var->mutex);
+ if (tmp->thd.mysys_var->current_mutex)
+ {
+ if (&tmp->mutex != tmp->thd.mysys_var->current_mutex)
+ pthread_mutex_lock(tmp->thd.mysys_var->current_mutex);
+ pthread_cond_broadcast(tmp->thd.mysys_var->current_cond);
+ if (&tmp->mutex != tmp->thd.mysys_var->current_mutex)
+ pthread_mutex_unlock(tmp->thd.mysys_var->current_mutex);
+ }
+ pthread_mutex_unlock(&tmp->thd.mysys_var->mutex);
+ }
+ pthread_mutex_unlock(&tmp->mutex);
+ }
+ VOID(pthread_mutex_unlock(&LOCK_delayed_insert)); // For unlink from list
+}
+
+
+/*
+ * Create a new delayed insert thread
+*/
+
+static pthread_handler_decl(handle_delayed_insert,arg)
+{
+ delayed_insert *di=(delayed_insert*) arg;
+ THD *thd= &di->thd;
+
+ pthread_detach_this_thread();
+ /* Add thread to THD list so that's it's visible in 'show processlist' */
+ pthread_mutex_lock(&LOCK_thread_count);
+ thd->thread_id=thread_id++;
+ threads.append(thd);
+ pthread_mutex_unlock(&LOCK_thread_count);
+
+ pthread_mutex_lock(&di->mutex);
+#ifndef __WIN__ /* Win32 calls this in pthread_create */
+ if (my_thread_init())
+ {
+ strmov(thd->net.last_error,ER(thd->net.last_errno=ER_OUT_OF_RESOURCES));
+ goto end;
+ }
+#endif
+
+ DBUG_ENTER("handle_delayed_insert");
+ if (init_thr_lock() ||
+ my_pthread_setspecific_ptr(THR_THD, thd) ||
+ my_pthread_setspecific_ptr(THR_NET, &thd->net))
+ {
+ strmov(thd->net.last_error,ER(thd->net.last_errno=ER_OUT_OF_RESOURCES));
+ goto end;
+ }
+ thd->mysys_var=my_thread_var;
+ thd->dbug_thread_id=my_thread_id();
+#ifndef __WIN__
+ sigset_t set;
+ VOID(sigemptyset(&set)); // Get mask in use
+ VOID(pthread_sigmask(SIG_UNBLOCK,&set,&thd->block_signals));
+#endif
+
+ /* open table */
+
+ if (!(di->table=open_ltable(thd,di->table_list,TL_WRITE_DELAYED)))
+ {
+ thd->fatal_error=1; // Abort waiting inserts
+ goto end;
+ }
+ di->table->copy_blobs=1;
+
+ /* One can now use this */
+ pthread_mutex_lock(&LOCK_delayed_insert);
+ delayed_threads.append(di);
+ pthread_mutex_unlock(&LOCK_delayed_insert);
+
+ /* Tell client that the thread is initialized */
+ pthread_cond_signal(&di->cond_client);
+
+ /* Now wait until we get an insert or lock to handle */
+ /* We will not abort as long as a client thread uses this thread */
+
+ for (;;)
+ {
+ if (thd->killed)
+ {
+ uint lock_count;
+ /*
+ Remove this from delay insert list so that no one can request a
+ table from this
+ */
+ pthread_mutex_unlock(&di->mutex);
+ pthread_mutex_lock(&LOCK_delayed_insert);
+ di->unlink();
+ lock_count=di->lock_count();
+ pthread_mutex_unlock(&LOCK_delayed_insert);
+ pthread_mutex_lock(&di->mutex);
+ if (!lock_count && !di->tables_in_use && !di->stacked_inserts)
+ break; // Time to die
+ }
+
+ 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
+
+ /* Information for pthread_kill */
+ pthread_mutex_lock(&di->thd.mysys_var->mutex);
+ di->thd.mysys_var->current_mutex= &di->mutex;
+ di->thd.mysys_var->current_cond= &di->cond;
+ pthread_mutex_unlock(&di->thd.mysys_var->mutex);
+ di->thd.proc_info=0;
+
+ for ( ; ;)
+ {
+ int error;
+#if (defined(HAVE_BROKEN_COND_TIMEDWAIT) || defined(HAVE_LINUXTHREADS))
+ error=pthread_cond_wait(&di->cond,&di->mutex);
+#else
+ error=pthread_cond_timedwait(&di->cond,&di->mutex,&abstime);
+#ifdef EXTRA_DEBUG
+ if (error && error != EINTR)
+ {
+ fprintf(stderr, "Got error %d from pthread_cond_timedwait\n",error);
+ DBUG_PRINT("error",("Got error %d from pthread_cond_timedwait",
+ error));
+ }
+#endif
+#endif
+ if (thd->killed || di->status)
+ break;
+ if (error == ETIME || error == ETIMEDOUT)
+ {
+ thd->killed=1;
+ break;
+ }
+ }
+ pthread_mutex_lock(&di->thd.mysys_var->mutex);
+ di->thd.mysys_var->current_mutex= 0;
+ di->thd.mysys_var->current_cond= 0;
+ pthread_mutex_unlock(&di->thd.mysys_var->mutex);
+ }
+
+ if (di->tables_in_use && ! thd->lock)
+ {
+ /* request for new delayed insert */
+ if (!(thd->lock=mysql_lock_tables(thd,&di->table,1)))
+ {
+ di->dead=thd->killed=1; // Fatal error
+ }
+ pthread_cond_broadcast(&di->cond_client);
+ }
+ if (di->stacked_inserts)
+ {
+ if (di->handle_inserts())
+ {
+ di->dead=thd->killed=1; // Some fatal error
+ }
+ }
+ di->status=0;
+ if (!di->stacked_inserts && !di->tables_in_use && thd->lock)
+ {
+ /* No one is doing a insert delayed;
+ Unlock it so that other threads can use it */
+ MYSQL_LOCK *lock=thd->lock;
+ thd->lock=0;
+ pthread_mutex_unlock(&di->mutex);
+ mysql_unlock_tables(thd, lock);
+ di->group_count=0;
+ pthread_mutex_lock(&di->mutex);
+ }
+ if (di->tables_in_use)
+ pthread_cond_broadcast(&di->cond_client); // If waiting clients
+ }
+
+end:
+ /*
+ di should be unlinked from the thread handler list and have no active
+ clients
+ */
+
+ close_thread_tables(thd); // Free the table
+ di->table=0;
+ di->dead=thd->killed=1; // If error
+ pthread_cond_broadcast(&di->cond_client); // Safety
+ pthread_mutex_unlock(&di->mutex);
+
+ pthread_mutex_lock(&LOCK_delayed_create); // Because of delayed_get_table
+ pthread_mutex_lock(&LOCK_delayed_insert);
+ delete di;
+ pthread_mutex_unlock(&LOCK_delayed_insert);
+ pthread_mutex_unlock(&LOCK_delayed_create);
+
+ my_thread_end();
+ pthread_exit(0);
+ DBUG_RETURN(0);
+}
+
+
+/* Remove pointers from temporary fields to allocated values */
+
+static void unlink_blobs(register TABLE *table)
+{
+ for (Field **ptr=table->field ; *ptr ; ptr++)
+ {
+ if ((*ptr)->flags & BLOB_FLAG)
+ ((Field_blob *) (*ptr))->clear_temporary();
+ }
+}
+
+/* Free blobs stored in current row */
+
+static void free_delayed_insert_blobs(register TABLE *table)
+{
+ for (Field **ptr=table->field ; *ptr ; ptr++)
+ {
+ if ((*ptr)->flags & BLOB_FLAG)
+ {
+ char *str;
+ ((Field_blob *) (*ptr))->get_ptr(&str);
+ my_free(str,MYF(MY_ALLOW_ZERO_PTR));
+ ((Field_blob *) (*ptr))->reset();
+ }
+ }
+}
+
+
+bool delayed_insert::handle_inserts(void)
+{
+ int error;
+ uint max_rows;
+ DBUG_ENTER("handle_inserts");
+
+ /* Allow client to insert new rows */
+ pthread_mutex_unlock(&mutex);
+
+ table->next_number_field=table->found_next_number_field;
+
+ thd.proc_info="upgrading lock";
+ if (thr_upgrade_write_delay_lock(*thd.lock->locks))
+ {
+ /* This can only happen if thread is killed by shutdown */
+ sql_print_error(ER(ER_DELAYED_CANT_CHANGE_LOCK),table->real_name);
+ goto err;
+ }
+
+ thd.proc_info="insert";
+ max_rows=delayed_insert_limit;
+ if (thd.killed || table->version != refresh_version)
+ {
+ thd.killed=1;
+ max_rows= ~0; // Do as much as possible
+ }
+
+ table->file->extra(HA_EXTRA_WRITE_CACHE);
+ pthread_mutex_lock(&mutex);
+ delayed_row *row;
+ while ((row=rows.get()))
+ {
+ stacked_inserts--;
+ pthread_mutex_unlock(&mutex);
+ memcpy(table->record[0],row->record,table->reclength);
+
+ thd.start_time=row->start_time;
+ thd.query_start_used=row->query_start_used;
+ thd.last_insert_id=row->last_insert_id;
+ thd.last_insert_id_used=row->last_insert_id_used;
+ thd.insert_id_used=row->insert_id_used;
+ table->time_stamp=row->time_stamp;
+
+ info.handle_duplicates= row->dup;
+ if (write_record(table,&info))
+ {
+ info.error++; // Ignore errors
+ pthread_mutex_lock(&LOCK_delayed_status);
+ delayed_insert_errors++;
+ pthread_mutex_unlock(&LOCK_delayed_status);
+ }
+ if (row->query && row->log_query)
+ {
+ mysql_update_log.write(row->query, row->query_length);
+ Query_log_event qinfo(&thd, row->query);
+ mysql_bin_log.write(&qinfo);
+ }
+ if (table->blob_fields)
+ free_delayed_insert_blobs(table);
+ thread_safe_sub(delayed_rows_in_use,1,&LOCK_delayed_status);
+ thread_safe_increment(delayed_insert_writes,&LOCK_delayed_status);
+ pthread_mutex_lock(&mutex);
+
+ delete row;
+ /* Let READ clients do something once in a while */
+ if (group_count++ == max_rows)
+ {
+ group_count=0;
+ if (stacked_inserts || tables_in_use) // Let these wait a while
+ {
+ if (tables_in_use)
+ pthread_cond_broadcast(&cond_client); // If waiting clients
+ thd.proc_info="reschedule";
+ pthread_mutex_unlock(&mutex);
+ if ((error=table->file->extra(HA_EXTRA_NO_CACHE)))
+ {
+ /* This should never happen */
+ table->file->print_error(error,MYF(0));
+ sql_print_error("%s",thd.net.last_error);
+ goto err;
+ }
+ if (thr_reschedule_write_lock(*thd.lock->locks))
+ {
+ /* This should never happen */
+ sql_print_error(ER(ER_DELAYED_CANT_CHANGE_LOCK),table->real_name);
+ }
+ table->file->extra(HA_EXTRA_WRITE_CACHE);
+ pthread_mutex_lock(&mutex);
+ thd.proc_info="insert";
+ }
+ if (tables_in_use)
+ pthread_cond_broadcast(&cond_client); // If waiting clients
+ }
+ }
+
+ thd.proc_info=0;
+ table->next_number_field=0;
+ pthread_mutex_unlock(&mutex);
+ if ((error=table->file->extra(HA_EXTRA_NO_CACHE)))
+ { // This shouldn't happen
+ table->file->print_error(error,MYF(0));
+ sql_print_error("%s",thd.net.last_error);
+ goto err;
+ }
+ pthread_mutex_lock(&mutex);
+ DBUG_RETURN(0);
+
+ err:
+ thread_safe_increment(delayed_insert_errors, &LOCK_delayed_status);
+ pthread_mutex_lock(&mutex);
+ DBUG_RETURN(1);
+}
+
+
+
+/***************************************************************************
+** store records in INSERT ... SELECT *
+***************************************************************************/
+
+int
+select_insert::prepare(List<Item> &values)
+{
+ TABLE *form=table;
+ DBUG_ENTER("select_insert::prepare");
+
+ save_time_stamp=table->time_stamp;
+ if (check_insert_fields(thd,table,*fields,values,1))
+ DBUG_RETURN(1);
+
+ if (fields->elements)
+ {
+ restore_record(form,2); // Get empty record
+ }
+ else
+ form->record[0][0]=form->record[2][0]; // Fix delete marker
+ form->next_number_field=form->found_next_number_field;
+ thd->count_cuted_fields=1; /* calc cuted fields */
+ thd->cuted_fields=0;
+ if (info.handle_duplicates != DUP_REPLACE)
+ form->file->extra(HA_EXTRA_WRITE_CACHE);
+ DBUG_RETURN(0);
+}
+
+select_insert::~select_insert()
+{
+ if (table)
+ {
+ if (save_time_stamp)
+ table->time_stamp=save_time_stamp;
+ table->next_number_field=0;
+ }
+ thd->count_cuted_fields=0;
+}
+
+
+bool select_insert::send_data(List<Item> &values)
+{
+ if (thd->offset_limit)
+ { // using limit offset,count
+ thd->offset_limit--;
+ return 0;
+ }
+ if (fields->elements)
+ fill_record(*fields,values);
+ else
+ fill_record(table->field,values);
+ if (write_record(table,&info))
+ return 1;
+ if (table->next_number_field) // Clear for next record
+ {
+ table->next_number_field->reset();
+ if (! last_insert_id && thd->insert_id_used)
+ last_insert_id=thd->insert_id();
+ }
+ return 0;
+}
+
+
+void select_insert::send_error(uint errcode,const char *err)
+{
+ ::send_error(&thd->net,errcode,err);
+ VOID(table->file->extra(HA_EXTRA_NO_CACHE));
+}
+
+
+bool select_insert::send_eof()
+{
+ int error;
+ if ((error=table->file->extra(HA_EXTRA_NO_CACHE)))
+ {
+ table->file->print_error(error,MYF(0));
+ ::send_error(&thd->net);
+ return 1;
+ }
+ else
+ {
+ char buff[160];
+ if (info.handle_duplicates == DUP_IGNORE)
+ sprintf(buff,ER(ER_INSERT_INFO),info.records,info.records-info.copied,
+ thd->cuted_fields);
+ else
+ sprintf(buff,ER(ER_INSERT_INFO),info.records,info.deleted,
+ thd->cuted_fields);
+ if (last_insert_id)
+ thd->insert_id(last_insert_id); // For update log
+ ::send_ok(&thd->net,info.copied,last_insert_id,buff);
+ mysql_update_log.write(thd->query,thd->query_length);
+ Query_log_event qinfo(thd, thd->query);
+ mysql_bin_log.write(&qinfo);
+ return 0;
+ }
+}
+
+
+/***************************************************************************
+** CREATE TABLE (SELECT) ...
+***************************************************************************/
+
+int
+select_create::prepare(List<Item> &values)
+{
+ DBUG_ENTER("select_create::prepare");
+
+ table=create_table_from_items(thd, create_info, db, name,
+ extra_fields, keys, &values, &lock);
+ if (!table)
+ DBUG_RETURN(-1); // abort() deletes table
+
+ /* First field to copy */
+ field=table->field+table->fields - values.elements;
+
+ save_time_stamp=table->time_stamp;
+ if (table->timestamp_field) // Don't set timestamp if used
+ {
+ table->timestamp_field->set_time();
+ table->time_stamp=0; // This should be saved
+ }
+ table->next_number_field=table->found_next_number_field;
+
+ restore_record(table,2); // Get empty record
+ thd->count_cuted_fields=1; // count warnings
+ thd->cuted_fields=0;
+ DBUG_RETURN(0);
+}
+
+
+bool select_create::send_data(List<Item> &values)
+{
+ if (thd->offset_limit)
+ { // using limit offset,count
+ thd->offset_limit--;
+ return 0;
+ }
+ fill_record(field,values);
+ if (write_record(table,&info))
+ return 1;
+ if (table->next_number_field) // Clear for next record
+ {
+ table->next_number_field->reset();
+ if (! last_insert_id && thd->insert_id_used)
+ last_insert_id=thd->insert_id();
+ }
+ return 0;
+}
+
+extern HASH open_cache;
+
+bool select_create::send_eof()
+{
+ bool tmp=select_insert::send_eof();
+ if (tmp)
+ abort();
+ else
+ {
+ VOID(pthread_mutex_lock(&LOCK_open));
+ mysql_unlock_tables(thd, lock);
+ hash_delete(&open_cache,(byte*) table);
+ lock=0; table=0;
+ VOID(pthread_mutex_unlock(&LOCK_open));
+ }
+ return tmp;
+}
+
+void select_create::abort()
+{
+ VOID(pthread_mutex_lock(&LOCK_open));
+ if (lock)
+ {
+ mysql_unlock_tables(thd, lock);
+ lock=0;
+ }
+ if (table)
+ {
+ enum db_type table_type=table->db_type;
+ hash_delete(&open_cache,(byte*) table);
+ quick_rm_table(table_type,db,name);
+ table=0;
+ }
+ VOID(pthread_mutex_unlock(&LOCK_open));
+}
+
+
+/*****************************************************************************
+** Instansiate templates
+*****************************************************************************/
+
+#ifdef __GNUC__
+template class List_iterator<List_item>;
+template class I_List<delayed_insert>;
+template class I_List_iterator<delayed_insert>;
+template class I_List<delayed_row>;
+#endif
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
new file mode 100644
index 00000000000..50c9ab852c1
--- /dev/null
+++ b/sql/sql_lex.cc
@@ -0,0 +1,810 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 lexical scanner on a temporary buffer with a yacc interface */
+
+#include "mysql_priv.h"
+#include "item_create.h"
+#include <m_ctype.h>
+#include <hash.h>
+
+LEX_STRING tmp_table_alias= {(char*) "tmp-table",8};
+
+/* Macros to look like lex */
+
+#define yyGet() *(lex->ptr++)
+#define yyGetLast() lex->ptr[-1]
+#define yyPeek() lex->ptr[0]
+#define yyPeek2() lex->ptr[1]
+#define yyUnget() lex->ptr--
+#define yySkip() lex->ptr++
+#define yyLength() ((uint) (lex->ptr - lex->tok_start)-1)
+
+#if MYSQL_VERSION_ID < 32300
+#define FLOAT_NUM REAL_NUM
+#endif
+
+pthread_key(LEX*,THR_LEX);
+
+#define TOCK_NAME_LENGTH 24
+
+/*
+ The following is based on the latin1 character set, and is only
+ used when comparing keywords
+*/
+
+uchar to_upper_lex[] = {
+ 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
+};
+
+inline int lex_casecmp(const char *s, const char *t, uint len)
+{
+ while (len-- != 0 &&
+ to_upper_lex[(uchar) *s++] == to_upper_lex[(uchar) *t++]) ;
+ return (int) len+1;
+}
+
+#include "lex_hash.h"
+
+static uchar state_map[256];
+
+
+void lex_init(void)
+{
+ uint i;
+ DBUG_ENTER("lex_init");
+ for (i=0 ; i < array_elements(symbols) ; i++)
+ symbols[i].length=(uchar) strlen(symbols[i].name);
+ for (i=0 ; i < array_elements(sql_functions) ; i++)
+ sql_functions[i].length=(uchar) strlen(sql_functions[i].name);
+
+ VOID(pthread_key_create(&THR_LEX,NULL));
+
+ /* Fill state_map with states to get a faster parser */
+ for (i=0; i < 256 ; i++)
+ {
+ if (isalpha(i))
+ state_map[i]=(uchar) STATE_IDENT;
+ else if (isdigit(i))
+ state_map[i]=(uchar) STATE_NUMBER_IDENT;
+#if defined(USE_MB) && defined(USE_MB_IDENT)
+ else if (use_mb(default_charset_info) && my_ismbhead(default_charset_info, i))
+ state_map[i]=(uchar) STATE_IDENT;
+#endif
+ else if (!isgraph(i))
+ state_map[i]=(uchar) STATE_SKIP;
+ else
+ state_map[i]=(uchar) STATE_CHAR;
+ }
+ state_map[(uchar)'_']=state_map[(uchar)'$']=(uchar) STATE_IDENT;
+ state_map[(uchar)'\'']=state_map[(uchar)'"']=(uchar) STATE_STRING;
+ state_map[(uchar)'-']=state_map[(uchar)'+']=(uchar) STATE_SIGNED_NUMBER;
+ state_map[(uchar)'.']=(uchar) STATE_REAL_OR_POINT;
+ state_map[(uchar)'>']=state_map[(uchar)'=']=state_map[(uchar)'!']= (uchar) STATE_CMP_OP;
+ state_map[(uchar)'<']= (uchar) STATE_LONG_CMP_OP;
+ state_map[(uchar)'&']=state_map[(uchar)'|']=(uchar) STATE_BOOL;
+ state_map[(uchar)'#']=(uchar) STATE_COMMENT;
+ state_map[(uchar)';']=(uchar) STATE_COLON;
+ state_map[(uchar)':']=(uchar) STATE_SET_VAR;
+ state_map[0]=(uchar) STATE_EOL;
+ state_map[(uchar)'\\']= (uchar) STATE_ESCAPE;
+ state_map[(uchar)'/']= (uchar) STATE_LONG_COMMENT;
+ state_map[(uchar)'*']= (uchar) STATE_END_LONG_COMMENT;
+ state_map[(uchar)'@']= (uchar) STATE_USER_END;
+ state_map[(uchar) '`']= (uchar) STATE_USER_VARIABLE_DELIMITER;
+ if (thd_startup_options & OPTION_ANSI_MODE)
+ {
+ state_map[(uchar) '"'] = STATE_USER_VARIABLE_DELIMITER;
+ }
+ DBUG_VOID_RETURN;
+}
+
+
+void lex_free(void)
+{ // Call this when daemon ends
+ DBUG_ENTER("lex_free");
+ DBUG_VOID_RETURN;
+}
+
+
+LEX *lex_start(THD *thd, uchar *buf,uint length)
+{
+ LEX *lex= &thd->lex;
+ lex->next_state=STATE_START;
+ lex->end_of_query=(lex->ptr=buf)+length;
+ lex->yylineno = 1;
+ lex->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=(lex->thd=thd)->convert_set;
+ lex->yacc_yyss=lex->yacc_yyvs=0;
+ lex->ignore_space=test(thd->client_capabilities & CLIENT_IGNORE_SPACE);
+ return lex;
+}
+
+void lex_end(LEX *lex)
+{
+ lex->expr_list.delete_elements(); // If error when parsing sql-varargs
+ x_free(lex->yacc_yyss);
+ x_free(lex->yacc_yyvs);
+}
+
+
+static int find_keyword(LEX *lex, uint len, bool function)
+{
+ uchar *tok=lex->tok_start;
+
+ SYMBOL *symbol = get_hash_symbol((const char *)tok,len,function);
+ if (symbol)
+ {
+ lex->yylval->symbol.symbol=symbol;
+ lex->yylval->symbol.str= (char*) tok;
+ lex->yylval->symbol.length=len;
+ return symbol->tok;
+ }
+#ifdef HAVE_DLOPEN
+ udf_func *udf;
+ if (function && using_udf_functions && (udf=find_udf((char*) tok, len)))
+ {
+ switch (udf->returns) {
+ case STRING_RESULT:
+ lex->yylval->udf=udf;
+ return (udf->type == UDFTYPE_FUNCTION) ? UDF_CHAR_FUNC : UDA_CHAR_SUM;
+ case REAL_RESULT:
+ lex->yylval->udf=udf;
+ return (udf->type == UDFTYPE_FUNCTION) ? UDF_FLOAT_FUNC : UDA_FLOAT_SUM;
+ case INT_RESULT:
+ lex->yylval->udf=udf;
+ return (udf->type == UDFTYPE_FUNCTION) ? UDF_INT_FUNC : UDA_INT_SUM;
+ }
+ }
+#endif
+ return 0;
+}
+
+
+/* make a copy of token before ptr and set yytoklen */
+
+static inline 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);
+ return tmp;
+}
+
+/* Return an unescaped text literal without quotes */
+/* Fix sometimes to do only one scan of the string */
+
+static char *get_text(LEX *lex)
+{
+ reg1 uchar c,sep;
+ uint found_escape=0;
+
+ sep= yyGetLast(); // String should end with this
+ //lex->tok_start=lex->ptr-1; // Remember '
+ while (lex->ptr != lex->end_of_query)
+ {
+ c = yyGet();
+#ifdef USE_MB
+ int l;
+ if (use_mb(default_charset_info) &&
+ (l = my_ismbchar(default_charset_info,
+ (const char *)lex->ptr-1,
+ (const char *)lex->end_of_query))) {
+ lex->ptr += l-1;
+ continue;
+ }
+#endif
+ if (c == '\\')
+ { // Escaped character
+ found_escape=1;
+ if (lex->ptr == lex->end_of_query)
+ return 0;
+ yySkip();
+ }
+ else if (c == sep)
+ {
+ if (c == yyGet()) // Check if two separators in a row
+ {
+ found_escape=1; // dupplicate. Remember for delete
+ continue;
+ }
+ else
+ yyUnget();
+
+ /* Found end. Unescape and return string */
+ uchar *str,*end,*start;
+
+ str=lex->tok_start+1;
+ end=lex->ptr-1;
+ start=(uchar*) sql_alloc((uint) (end-str)+1);
+ if (!found_escape)
+ {
+ lex->yytoklen=(uint) (end-str);
+ memcpy(start,str,lex->yytoklen);
+ start[lex->yytoklen]=0;
+ }
+ else
+ {
+ uchar *to;
+ for (to=start ; str != end ; str++)
+ {
+#ifdef USE_MB
+ int l;
+ if (use_mb(default_charset_info) &&
+ (l = my_ismbchar(default_charset_info,
+ (const char *)str, (const char *)end))) {
+ while (l--)
+ *to++ = *str++;
+ str--;
+ continue;
+ }
+#endif
+ if (*str == '\\' && str+1 != end)
+ {
+ switch(*++str) {
+ case 'n':
+ *to++='\n';
+ break;
+ case 't':
+ *to++= '\t';
+ break;
+ case 'r':
+ *to++ = '\r';
+ break;
+ case 'b':
+ *to++ = '\b';
+ break;
+ case '0':
+ *to++= 0; // Ascii null
+ break;
+ case 'Z': // ^Z must be escaped on Win32
+ *to++='\032';
+ break;
+ case '_':
+ case '%':
+ *to++= '\\'; // remember prefix for wildcard
+ /* Fall through */
+ default:
+ *to++ = *str;
+ break;
+ }
+ }
+ else if (*str == sep)
+ *to++= *str++; // Two ' or "
+ else
+ *to++ = *str;
+
+ }
+ *to=0;
+ lex->yytoklen=(uint) (to-start);
+ }
+ if (lex->convert_set)
+ lex->convert_set->convert((char*) start,lex->yytoklen);
+ return (char*) start;
+ }
+ }
+ return 0; // unexpected end of query
+}
+
+
+/*
+** Calc type of integer; long integer, longlong integer or real.
+** Returns smallest type that match the string.
+** When using unsigned long long values the result is converted to a real
+** because else they will be unexpected sign changes because all calculation
+** is done with longlong or double.
+*/
+
+static const char *long_str="2147483647";
+static const uint long_len=10;
+static const char *signed_long_str="-2147483648";
+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;
+
+
+inline static uint int_token(const char *str,uint length)
+{
+ if (length < long_len) // quick normal case
+ return NUM;
+ bool neg=0;
+
+ if (*str == '+') // Remove sign and pre-zeros
+ {
+ str++; length--;
+ }
+ else if (*str == '-')
+ {
+ str++; length--;
+ neg=1;
+ }
+ while (*str == '0' && length)
+ {
+ str++; length --;
+ }
+ if (length < long_len)
+ return NUM;
+
+ uint smaller,bigger;
+ const char *cmp;
+ if (neg)
+ {
+ if (length == long_len)
+ {
+ cmp= signed_long_str+1;
+ smaller=NUM; // If <= signed_long_str
+ bigger=LONG_NUM; // If >= signed_long_str
+ }
+ else if (length < signed_longlong_len)
+ return LONG_NUM;
+ else if (length > signed_longlong_len)
+ return REAL_NUM;
+ else
+ {
+ cmp=signed_longlong_str+1;
+ smaller=LONG_NUM; // If <= signed_longlong_str
+ bigger=REAL_NUM;
+ }
+ }
+ else
+ {
+ if (length == long_len)
+ {
+ cmp= long_str;
+ smaller=NUM;
+ bigger=LONG_NUM;
+ }
+ else if (length < longlong_len)
+ return LONG_NUM;
+ else if (length > longlong_len)
+ return REAL_NUM;
+ else
+ {
+ cmp=longlong_str;
+ smaller=LONG_NUM;
+ bigger=REAL_NUM;
+ }
+ }
+ while (*cmp && *cmp++ == *str++) ;
+ return ((uchar) str[-1] <= (uchar) cmp[-1]) ? smaller : bigger;
+}
+
+
+// yylex remember the following states from the following yylex()
+// STATE_EOQ ; found end of query
+// STATE_OPERATOR_OR_IDENT ; last state was an ident, text or number
+// (which can't be followed by a signed number)
+
+int yylex(void *arg)
+{
+ reg1 uchar c;
+ int tokval;
+ uint length;
+ enum lex_states state,prev_state;
+ LEX *lex=current_lex;
+ YYSTYPE *yylval=(YYSTYPE*) arg;
+
+ lex->yylval=yylval; // The global state
+ lex->tok_start=lex->tok_end=lex->ptr;
+ prev_state=state=lex->next_state;
+ lex->next_state=STATE_OPERATOR_OR_IDENT;
+ LINT_INIT(c);
+ for (;;)
+ {
+ switch(state) {
+ case STATE_OPERATOR_OR_IDENT: // Next is operator or keyword
+ case STATE_START: // Start of token
+ // Skipp startspace
+ for (c=yyGet() ; (state_map[c] == STATE_SKIP) ; c= yyGet())
+ {
+ if (c == '\n')
+ lex->yylineno++;
+ }
+ lex->tok_start=lex->ptr-1; // Start of real token
+ state= (enum lex_states) state_map[c];
+ break;
+ case STATE_ESCAPE:
+ if (yyGet() == 'N')
+ { // Allow \N as shortcut for NULL
+ yylval->lex_str.str=(char*) "\\N";
+ yylval->lex_str.length=2;
+ return NULL_SYM;
+ }
+ case STATE_CHAR: // Unknown or single char token
+ case STATE_SKIP: // This should not happen
+ yylval->lex_str.str=(char*) (lex->ptr=lex->tok_start);// Set to first char
+ yylval->lex_str.length=1;
+ c=yyGet();
+ if (c != ')')
+ lex->next_state= STATE_START; // Allow signed numbers
+ if (c == ',')
+ lex->tok_start=lex->ptr; // Let tok_start point at next item
+ return((int) c);
+
+ case STATE_IDENT: // Incomplete keyword or ident
+#if defined(USE_MB) && defined(USE_MB_IDENT)
+ if (use_mb(default_charset_info))
+ {
+ if (my_ismbhead(default_charset_info, yyGetLast()))
+ {
+ int l = my_ismbchar(default_charset_info,
+ (const char *)lex->ptr-1,
+ (const char *)lex->end_of_query);
+ if (l == 0) {
+ state = STATE_CHAR;
+ continue;
+ }
+ lex->ptr += l - 1;
+ }
+ while (state_map[c=yyGet()] == STATE_IDENT ||
+ state_map[c] == STATE_NUMBER_IDENT)
+ {
+ if (my_ismbhead(default_charset_info, c))
+ {
+ int l;
+ if ((l = my_ismbchar(default_charset_info,
+ (const char *)lex->ptr-1,
+ (const char *)lex->end_of_query)) == 0)
+ break;
+ lex->ptr += l-1;
+ }
+ }
+ }
+ else
+#endif
+ while (state_map[c=yyGet()] == STATE_IDENT ||
+ state_map[c] == STATE_NUMBER_IDENT) ;
+ length= (uint) (lex->ptr - lex->tok_start)-1;
+ if (lex->ignore_space)
+ {
+ for ( ; state_map[c] == STATE_SKIP ; c= yyGet());
+ }
+ if (c == '.' && (state_map[yyPeek()] == STATE_IDENT ||
+ state_map[yyPeek()] == STATE_NUMBER_IDENT))
+ lex->next_state=STATE_IDENT_SEP;
+ else
+ { // '(' must follow directly if function
+ yyUnget();
+ if ((tokval = find_keyword(lex,length,c == '(')))
+ {
+ lex->next_state= STATE_START; // Allow signed numbers
+ return(tokval); // Was keyword
+ }
+ yySkip(); // next state does a unget
+ }
+ yylval->lex_str=get_token(lex,length);
+ return(IDENT);
+
+ case STATE_IDENT_SEP: // Found ident and now '.'
+ lex->next_state=STATE_IDENT_START;// Next is an ident (not a keyword)
+ yylval->lex_str.str=(char*) lex->ptr;
+ yylval->lex_str.length=1;
+ c=yyGet(); // should be '.'
+ return((int) c);
+
+ case STATE_NUMBER_IDENT: // number or ident which starts with num
+ while (isdigit((c = yyGet()))) ;
+ if (state_map[c] != STATE_IDENT)
+ { // Can't be identifier
+ state=STATE_INT_OR_REAL;
+ break;
+ }
+ if (c == 'e' || c == 'E')
+ {
+ if ((c=(yyGet())) == '+' || c == '-')
+ { // Allow 1E+10
+ if (isdigit(yyPeek())) // Number must have digit after sign
+ {
+ yySkip();
+ while (isdigit(yyGet())) ;
+ yylval->lex_str=get_token(lex,yyLength());
+ return(FLOAT_NUM);
+ }
+ }
+ yyUnget(); /* purecov: inspected */
+ }
+ else if (c == 'x' && (lex->ptr - lex->tok_start) == 2 &&
+ lex->tok_start[0] == '0' )
+ { // Varbinary
+ while (isxdigit((c = yyGet()))) ;
+ if ((lex->ptr - lex->tok_start) >= 4)
+ {
+ yylval->lex_str=get_token(lex,yyLength());
+ yylval->lex_str.str+=2; // Skipp 0x
+ yylval->lex_str.length-=2;
+ lex->yytoklen-=2;
+ return (HEX_NUM);
+ }
+ yyUnget();
+ }
+ // fall through
+ case STATE_IDENT_START: // Incomplete ident
+#if defined(USE_MB) && defined(USE_MB_IDENT)
+ if (use_mb(default_charset_info))
+ {
+ if (my_ismbhead(default_charset_info, yyGetLast()))
+ {
+ int l = my_ismbchar(default_charset_info,
+ (const char *)lex->ptr-1,
+ (const char *)lex->end_of_query);
+ if (l == 0)
+ {
+ state = STATE_CHAR;
+ continue;
+ }
+ lex->ptr += l - 1;
+ }
+ while (state_map[c=yyGet()] == STATE_IDENT ||
+ state_map[c] == STATE_NUMBER_IDENT)
+ {
+ if (my_ismbhead(default_charset_info, c))
+ {
+ int l;
+ if ((l = my_ismbchar(default_charset_info,
+ (const char *)lex->ptr-1,
+ (const char *)lex->end_of_query)) == 0)
+ break;
+ lex->ptr += l-1;
+ }
+ }
+ }
+ else
+#endif
+ while (state_map[c = yyGet()] == STATE_IDENT ||
+ state_map[c] == STATE_NUMBER_IDENT) ;
+
+ if (c == '.' && (state_map[yyPeek()] == STATE_IDENT ||
+ state_map[yyPeek()] == STATE_NUMBER_IDENT))
+ lex->next_state=STATE_IDENT_SEP;// Next is '.'
+ // fall through
+
+ case STATE_FOUND_IDENT: // Complete ident
+ yylval->lex_str=get_token(lex,yyLength());
+ return(IDENT);
+
+ case STATE_USER_VARIABLE_DELIMITER:
+ lex->tok_start=lex->ptr; // Skipp first `
+ while ((c=yyGet()) && state_map[c] != STATE_USER_VARIABLE_DELIMITER &&
+ c != (uchar) NAMES_SEP_CHAR) ;
+ yylval->lex_str=get_token(lex,yyLength());
+ if (state_map[c] == STATE_USER_VARIABLE_DELIMITER)
+ yySkip(); // Skipp end `
+ return(IDENT);
+
+ case STATE_SIGNED_NUMBER: // Incomplete signed number
+ if (prev_state == STATE_OPERATOR_OR_IDENT)
+ {
+ if (c == '-' && yyPeek() == '-' && isspace(yyPeek2()))
+ state=STATE_COMMENT;
+ else
+ state= STATE_CHAR; // Must be operator
+ break;
+ }
+ if (!isdigit(c=yyGet()) || yyPeek() == 'x')
+ {
+ if (c != '.')
+ {
+ if (c == '-' && isspace(yyPeek()))
+ state=STATE_COMMENT;
+ else
+ state = STATE_CHAR; // Return sign as single char
+ break;
+ }
+ yyUnget(); // Fix for next loop
+ }
+ while (isdigit(c=yyGet())) ; // Incomplete real or int number
+ if ((c == 'e' || c == 'E') && (yyPeek() == '+' || yyPeek() == '-'))
+ { // Real number
+ yyUnget();
+ c= '.'; // Fool next test
+ }
+ // fall through
+ case STATE_INT_OR_REAL: // Compleat int or incompleat real
+ if (c != '.')
+ { // Found complete integer number.
+ yylval->lex_str=get_token(lex,yyLength());
+ return int_token(yylval->lex_str.str,yylval->lex_str.length);
+ }
+ // fall through
+ case STATE_REAL: // Incomplete real number
+ while (isdigit(c = yyGet())) ;
+
+ if (c == 'e' || c == 'E')
+ {
+ c = yyGet();
+ if (c != '-' && c != '+')
+ { // No exp sig found
+ state= STATE_CHAR;
+ break;
+ }
+ if (!isdigit(yyGet()))
+ { // No digit after sign
+ state= STATE_CHAR;
+ break;
+ }
+ while (isdigit(yyGet())) ;
+ yylval->lex_str=get_token(lex,yyLength());
+ return(FLOAT_NUM);
+ }
+ yylval->lex_str=get_token(lex,yyLength());
+ return(REAL_NUM);
+
+ case STATE_CMP_OP: // Incomplete comparison operator
+ if (state_map[yyPeek()] == STATE_CMP_OP ||
+ state_map[yyPeek()] == STATE_LONG_CMP_OP)
+ yySkip();
+ if ((tokval = find_keyword(lex,(uint) (lex->ptr - lex->tok_start),0)))
+ {
+ lex->next_state= STATE_START; // Allow signed numbers
+ return(tokval);
+ }
+ state = STATE_CHAR; // Something fishy found
+ break;
+
+ case STATE_LONG_CMP_OP: // Incomplete comparison operator
+ if (state_map[yyPeek()] == STATE_CMP_OP ||
+ state_map[yyPeek()] == STATE_LONG_CMP_OP)
+ {
+ yySkip();
+ if (state_map[yyPeek()] == STATE_CMP_OP)
+ yySkip();
+ }
+ if ((tokval = find_keyword(lex,(uint) (lex->ptr - lex->tok_start),0)))
+ {
+ lex->next_state= STATE_START; // Found long op
+ return(tokval);
+ }
+ state = STATE_CHAR; // Something fishy found
+ break;
+
+ case STATE_BOOL:
+ if (c != yyPeek())
+ {
+ state=STATE_CHAR;
+ break;
+ }
+ yySkip();
+ tokval = find_keyword(lex,2,0); // Is a bool operator
+ lex->next_state= STATE_START; // Allow signed numbers
+ return(tokval);
+
+ case STATE_STRING: // Incomplete text string
+ if (!(yylval->lex_str.str = get_text(lex)))
+ {
+ state= STATE_CHAR; // Read char by char
+ break;
+ }
+ yylval->lex_str.length=lex->yytoklen;
+ return(TEXT_STRING);
+
+ case STATE_COMMENT: // Comment
+ while ((c = yyGet()) != '\n' && c) ;
+ yyUnget(); // Safety against eof
+ state = STATE_START; // Try again
+ break;
+ case STATE_LONG_COMMENT: /* Long C comment? */
+ if (yyPeek() != '*')
+ {
+ state=STATE_CHAR; // Probable division
+ break;
+ }
+ yySkip(); // Skip '*'
+ if (yyPeek() == '!') // MySQL command in comment
+ {
+ ulong version=MYSQL_VERSION_ID;
+ yySkip();
+ state=STATE_START;
+ if (isdigit(yyPeek()))
+ { // Version number
+ version=strtol((char*) lex->ptr,(char**) &lex->ptr,10);
+ }
+ if (version <= MYSQL_VERSION_ID)
+ {
+ lex->in_comment=1;
+ break;
+ }
+ }
+ while (lex->ptr != lex->end_of_query &&
+ ((c=yyGet()) != '*' || yyPeek() != '/'))
+ {
+ if (c == '\n')
+ lex->yylineno++;
+ }
+ if (lex->ptr != lex->end_of_query)
+ yySkip(); // remove last '/'
+ state = STATE_START; // Try again
+ break;
+ case STATE_END_LONG_COMMENT:
+ if (lex->in_comment && yyPeek() == '/')
+ {
+ yySkip();
+ lex->in_comment=0;
+ state=STATE_START;
+ }
+ else
+ state=STATE_CHAR; // Return '*'
+ break;
+ case STATE_SET_VAR: // Check if ':='
+ if (yyPeek() != '=')
+ {
+ state=STATE_CHAR; // Return ':'
+ break;
+ }
+ yySkip();
+ return (SET_VAR);
+ case STATE_COLON: // optional line terminator
+ if (yyPeek())
+ {
+ state=STATE_CHAR; // Return ';'
+ break;
+ }
+ /* fall true */
+ case STATE_EOL:
+ lex->next_state=STATE_END; // Mark for next loop
+ return(END_OF_INPUT);
+ case STATE_END:
+ lex->next_state=STATE_END;
+ return(0); // We found end of input last time
+
+ // Actually real shouldn't start
+ // with . but allow them anyhow
+ case STATE_REAL_OR_POINT:
+ if (isdigit(yyPeek()))
+ state = STATE_REAL; // Real
+ else
+ {
+ state = STATE_CHAR; // return '.'
+ lex->next_state=STATE_IDENT_START;// Next is an ident (not a keyword)
+ }
+ break;
+ case STATE_USER_END: // end '@' of user@hostname
+ if (state_map[yyPeek()] != STATE_STRING &&
+ state_map[yyPeek()] != STATE_USER_VARIABLE_DELIMITER)
+ lex->next_state=STATE_HOSTNAME; // Mark for next loop
+ yylval->lex_str.str=(char*) lex->ptr;
+ yylval->lex_str.length=1;
+ return((int) '@');
+ case STATE_HOSTNAME: // end '@' of user@hostname
+ for (c=yyGet() ;
+ isalnum(c) || c == '.' || c == '_' || c == '$';
+ c= yyGet()) ;
+ yylval->lex_str=get_token(lex,yyLength());
+ return(LEX_HOSTNAME);
+ }
+ }
+}
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
new file mode 100644
index 00000000000..6fd9f203d52
--- /dev/null
+++ b/sql/sql_lex.h
@@ -0,0 +1,149 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+
+/* YACC and LEX Definitions */
+
+/* These may not be declared yet */
+class Table_ident;
+class sql_exchange;
+class LEX_COLUMN;
+
+// The following hack is neaded because mysql_yacc.cc does not define
+// YYSTYPE before including this file
+
+#ifdef MYSQL_YACC
+#define LEX_YYSTYPE void *
+#else
+#include "lex_symbol.h"
+#include "sql_yacc.h"
+#define LEX_YYSTYPE YYSTYPE *
+#endif
+
+enum enum_sql_command {
+ SQLCOM_SELECT,SQLCOM_CREATE_TABLE,SQLCOM_CREATE_INDEX,SQLCOM_ALTER_TABLE,
+ SQLCOM_UPDATE,SQLCOM_INSERT,SQLCOM_INSERT_SELECT,SQLCOM_DELETE,
+ SQLCOM_DROP_TABLE,SQLCOM_DROP_INDEX,SQLCOM_SHOW_DATABASES,
+ SQLCOM_SHOW_TABLES,SQLCOM_SHOW_FIELDS,SQLCOM_SHOW_KEYS,
+ SQLCOM_LOAD,SQLCOM_SET_OPTION,SQLCOM_LOCK_TABLES,SQLCOM_UNLOCK_TABLES,
+ SQLCOM_GRANT, SQLCOM_CHANGE_DB, SQLCOM_CREATE_DB, SQLCOM_DROP_DB,
+ SQLCOM_REPAIR, SQLCOM_REPLACE, SQLCOM_REPLACE_SELECT, SQLCOM_SHOW_VARIABLES,
+ SQLCOM_SHOW_STATUS, SQLCOM_CREATE_FUNCTION, SQLCOM_DROP_FUNCTION,
+ SQLCOM_SHOW_PROCESSLIST,SQLCOM_REVOKE,SQLCOM_OPTIMIZE, SQLCOM_CHECK,
+ SQLCOM_FLUSH, SQLCOM_KILL, SQLCOM_SHOW_GRANTS, SQLCOM_ANALYZE,
+ SQLCOM_ROLLBACK, SQLCOM_COMMIT, SQLCOM_SLAVE_START, SQLCOM_SLAVE_STOP,
+ SQLCOM_BEGIN, SQLCOM_LOAD_MASTER_TABLE, SQLCOM_SHOW_CREATE,
+ SQLCOM_SHOW_MASTER_STAT, SQLCOM_SHOW_SLAVE_STAT, SQLCOM_CHANGE_MASTER
+};
+
+enum lex_states { STATE_START, STATE_CHAR, STATE_IDENT,
+ STATE_IDENT_SEP,
+ STATE_IDENT_START,
+ STATE_FOUND_IDENT,
+ STATE_SIGNED_NUMBER,
+ STATE_REAL,
+ STATE_CMP_OP,
+ STATE_LONG_CMP_OP,
+ STATE_STRING,
+ STATE_COMMENT,
+ STATE_END,
+ STATE_OPERATOR_OR_IDENT,
+ STATE_NUMBER_IDENT,
+ STATE_INT_OR_REAL,
+ STATE_REAL_OR_POINT,
+ STATE_BOOL,
+ STATE_EOL,
+ STATE_ESCAPE,
+ STATE_LONG_COMMENT,
+ STATE_END_LONG_COMMENT,
+ STATE_COLON,
+ STATE_SET_VAR,
+ STATE_USER_END,
+ STATE_HOSTNAME,
+ STATE_SKIP,
+ STATE_USER_VARIABLE_DELIMITER
+};
+
+typedef List<Item> List_item;
+
+typedef struct st_lex_master_info
+{
+ char* host, *user, *password,*log_file_name;
+ uint port, connect_retry;
+ ulonglong pos;
+} LEX_MASTER_INFO;
+
+/* 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;
+ uchar *ptr,*tok_start,*tok_end,*end_of_query;
+ ha_rows select_limit,offset_limit;
+ bool create_refs,drop_primary,drop_if_exists,local_file,
+ in_comment,ignore_space,verbose;
+ enum_sql_command sql_command;
+ enum lex_states next_state;
+ ulong options;
+ uint in_sum_expr,grant,grant_tot_col,which_columns, sort_default;
+ char *length,*dec,*change,*name;
+ String *wild;
+ sql_exchange *exchange;
+ thr_lock_type lock_option;
+
+ 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<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;
+ TYPELIB *interval;
+ create_field *last_field;
+
+ Item *where,*having,*default_value;
+ enum enum_duplicates duplicates;
+ ulong thread_id,type;
+ HA_CREATE_INFO create_info;
+ CONVERT *convert_set;
+ LEX_USER *grant_user;
+ char *db,*db1,*table1,*db2,*table2; /* For outer join using .. */
+ gptr yacc_yyss,yacc_yyvs;
+ THD *thd;
+ udf_func udf;
+ HA_CHECK_OPT check_opt; // check/repair options
+ LEX_MASTER_INFO mi; // used by CHANGE MASTER
+} LEX;
+
+
+void lex_init(void);
+void lex_free(void);
+LEX *lex_start(THD *thd, uchar *buf,uint length);
+void lex_end(LEX *lex);
+
+extern pthread_key(LEX*,THR_LEX);
+
+extern LEX_STRING tmp_table_alias;
+
+#define current_lex (&current_thd->lex)
diff --git a/sql/sql_list.cc b/sql/sql_list.cc
new file mode 100644
index 00000000000..7d5fc442121
--- /dev/null
+++ b/sql/sql_list.cc
@@ -0,0 +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 */
+
+
+#ifdef __GNUC__
+#pragma implementation // gcc: Class implementation
+#endif
+
+#include "mysql_priv.h"
diff --git a/sql/sql_list.h b/sql/sql_list.h
new file mode 100644
index 00000000000..725d506e62a
--- /dev/null
+++ b/sql/sql_list.h
@@ -0,0 +1,310 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 standard open memoryallocator */
+
+#ifdef __GNUC__
+#pragma interface /* gcc class implementation */
+#endif
+
+
+class Sql_alloc
+{
+public:
+ static void *operator new(size_t size) {return (void*) sql_alloc(size); }
+ static void operator delete(void *ptr, size_t size) {} /*lint -e715 */
+ inline Sql_alloc() {};
+ inline ~Sql_alloc() {};
+};
+
+/*
+** basic single linked list
+** Used for item and item_buffs.
+*/
+
+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 base_list() { empty(); }
+ inline base_list(const base_list &tmp) :Sql_alloc()
+ {
+ elements=tmp.elements;
+ first=tmp.first;
+ last=tmp.last;
+ }
+ inline bool push_back(void *info)
+ {
+ if (((*last)=new list_node(info,0)))
+ {
+ last= &(*last)->next;
+ elements++;
+ return 0;
+ }
+ return 1;
+ }
+ inline bool push_front(void *info)
+ {
+ list_node *node=new list_node(info,first);
+ if (node)
+ {
+ if (!first)
+ last= &node->next;
+ first=node;
+ elements++;
+ return 0;
+ }
+ return 1;
+ }
+ void remove(list_node **prev)
+ {
+ list_node *node=(*prev)->next;
+ delete *prev;
+ *prev=node;
+ if (!--elements)
+ {
+ last= &first;
+ first=0;
+ }
+ }
+ inline void *pop(void)
+ {
+ if (!first) 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; }
+ friend class base_list_iterator;
+
+protected:
+ void after(void *info,list_node *node)
+ {
+ list_node *new_node=new list_node(info,node->next);
+ node->next=new_node;
+ elements++;
+ if (last == &(node->next))
+ last= &new_node->next;
+ }
+};
+
+
+class base_list_iterator
+{
+ base_list *list;
+ base_list::list_node **el,**prev,*current;
+public:
+ base_list_iterator(base_list &list_par) :list(&list_par),el(&list_par.first),
+ prev(0),current(0)
+ {}
+ inline void *next(void)
+ {
+ prev=el;
+ if (!(current= *el))
+ return 0;
+ el= &current->next;
+ return current->info;
+ }
+ inline void rewind(void)
+ {
+ el= &list->first;
+ }
+ void *replace(void *element)
+ { // Return old element
+ void *tmp=current->info;
+ current->info=element;
+ return tmp;
+ }
+ void *replace(base_list &new_list)
+ {
+ void *ret_value=current->info;
+ if (new_list.first)
+ {
+ *new_list.last=current->next;
+ current->info=new_list.first->info;
+ current->next=new_list.first->next;
+ list->elements+=new_list.elements-1;
+ }
+ return ret_value; // return old element
+ }
+ inline void remove(void) // Remove current
+ {
+ list->remove(prev);
+ el=prev;
+ current=0; // Safeguard
+ }
+ void after(void *element) // Insert element after current
+ {
+ list->after(element,current);
+ current=current->next;
+ el= &current->next;
+ }
+ inline void **ref(void) // Get reference pointer
+ {
+ return &current->info;
+ }
+ inline bool is_last(void)
+ {
+ return *el == 0;
+ }
+};
+
+
+template <class T> class List :public base_list
+{
+public:
+ inline List() :base_list() {}
+ inline List(const List<T> &tmp) :base_list(tmp) {}
+ inline bool push_back(T *a) { return base_list::push_back(a); }
+ inline bool push_front(T *a) { return base_list::push_front(a); }
+ inline T* head() {return (T*) base_list::head(); }
+ inline T** head_ref() {return (T**) base_list::head_ref(); }
+ inline T* pop() {return (T*) base_list::pop(); }
+ void delete_elements(void)
+ {
+ list_node *element,*next;
+ for (element=first; element ; element=next)
+ {
+ next=element->next;
+ delete (T*) element->info;
+ }
+ empty();
+ }
+};
+
+
+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(); }
+};
+
+
+/*
+** An simple intrusive list with automaticly removes element from list
+** on delete (for THD element)
+*/
+
+struct ilink {
+ struct ilink **prev,*next;
+ inline ilink()
+ {
+ prev=0; next=0;
+ }
+ inline void unlink()
+ {
+ /* Extra tests because element doesn't have to be linked */
+ if (prev) *prev= next;
+ if (next) next->prev=prev;
+ prev=0 ; next=0;
+ }
+ virtual ~ilink() { unlink(); } /*lint -e1740 */
+};
+
+template <class T> class I_List_iterator;
+
+class base_ilist {
+ public:
+ struct ilink *first,last;
+ base_ilist() { first= &last; last.prev= &first; }
+ inline bool is_empty() { return first == &last; }
+ inline void append(ilink *a)
+ {
+ first->prev= &a->next;
+ a->next=first; a->prev= &first; first=a;
+ }
+ inline void push_back(ilink *a)
+ {
+ *last.prev= a;
+ a->next= &last;
+ a->prev= last.prev;
+ last.prev= &a->next;
+ }
+ inline struct ilink *get()
+ {
+ struct ilink *first_link=first;
+ if (first_link == &last)
+ return 0;
+ first_link->unlink(); // Unlink from list
+ return first_link;
+ }
+ friend class base_list_iterator;
+};
+
+
+class base_ilist_iterator
+{
+ base_ilist *list;
+ struct ilink **el,*current;
+public:
+ base_ilist_iterator(base_ilist &list_par) :list(&list_par),
+ el(&list_par.first),current(0) {}
+ void *next(void)
+ {
+ /* This is coded to allow push_back() while iterating */
+ current= *el;
+ if (current == &list->last) return 0;
+ el= &current->next;
+ return current;
+ }
+};
+
+
+template <class T>
+class I_List :private base_ilist {
+public:
+ I_List() :base_ilist() {}
+ inline bool is_empty() { return base_ilist::is_empty(); }
+ inline void append(T* a) { base_ilist::append(a); }
+ inline void push_back(T* a) { base_ilist::push_back(a); }
+ inline T* get() { return (T*) base_ilist::get(); }
+#ifndef _lint
+ friend class I_List_iterator<T>;
+#endif
+};
+
+
+template <class T> class I_List_iterator :public base_ilist_iterator
+{
+public:
+ I_List_iterator(I_List<T> &a) : base_ilist_iterator(a) {}
+ inline T* operator++(int) { return (T*) base_ilist_iterator::next(); }
+};
diff --git a/sql/sql_load.cc b/sql/sql_load.cc
new file mode 100644
index 00000000000..6f7db9c5a48
--- /dev/null
+++ b/sql/sql_load.cc
@@ -0,0 +1,790 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+
+/* Copy data from a textfile to table */
+
+#include "mysql_priv.h"
+#include <my_dir.h>
+#include <m_ctype.h>
+
+class READ_INFO {
+ File file;
+ byte *buffer, /* Buffer for read text */
+ *end_of_buff; /* Data in bufferts ends here */
+ uint buff_length, /* Length of buffert */
+ max_length; /* Max length of row */
+ char *field_term_ptr,*line_term_ptr,*line_start_ptr,*line_start_end;
+ uint field_term_length,line_term_length,enclosed_length;
+ int field_term_char,line_term_char,enclosed_char,escape_char;
+ int *stack,*stack_pos;
+ bool found_end_of_line,start_of_line,eof;
+ IO_CACHE cache;
+ NET *io_net;
+
+public:
+ bool error,line_cuted,found_null,enclosed;
+ byte *row_start, /* Found row starts here */
+ *row_end; /* Found row ends here */
+
+ READ_INFO(File file,uint tot_length,
+ String &field_term,String &line_start,String &line_term,
+ String &enclosed,int escape,bool get_it_from_net);
+ ~READ_INFO();
+ int read_field();
+ int read_fixed_length(void);
+ int next_line(void);
+ char unescape(char chr);
+ int terminator(char *ptr,uint length);
+ bool find_start_of_fields();
+};
+
+static int read_fixed_length(THD *thd,COPY_INFO &info,TABLE *table,
+ List<Item> &fields, READ_INFO &read_info);
+static int read_sep_field(THD *thd,COPY_INFO &info,TABLE *table,
+ List<Item> &fields, READ_INFO &read_info,
+ String &enclosed);
+
+
+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)
+{
+ char name[FN_REFLEN];
+ 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;
+ DBUG_ENTER("mysql_load");
+
+ if (escaped->length() > 1 || enclosed->length() > 1)
+ {
+ my_message(ER_WRONG_FIELD_TERMINATORS,ER(ER_WRONG_FIELD_TERMINATORS),
+ MYF(0));
+ DBUG_RETURN(-1);
+ }
+
+ if (!(table = open_ltable(thd,table_list,lock_type)))
+ DBUG_RETURN(-1);
+ if (!fields.elements)
+ {
+ Field **field;
+ for (field=table->field; *field ; field++)
+ fields.push_back(new Item_field(*field));
+ }
+ else
+ { // Part field list
+ thd->dupp_field=0;
+ if (setup_fields(thd,table_list,fields,1,0) < 0)
+ DBUG_RETURN(-1);
+ if (thd->dupp_field)
+ {
+ my_error(ER_FIELD_SPECIFIED_TWICE, MYF(0), thd->dupp_field->field_name);
+ DBUG_RETURN(-1);
+ }
+ }
+
+ uint tot_length=0;
+ bool use_blobs=0,use_timestamp=0;
+ List_iterator<Item> it(fields);
+
+ Item_field *field;
+ while ((field=(Item_field*) it++))
+ {
+ if (field->field->flags & BLOB_FLAG)
+ {
+ use_blobs=1;
+ tot_length+=256; // Will be extended if needed
+ }
+ else
+ tot_length+=field->field->field_length;
+ if (!field_term->length() && !(field->field->flags & NOT_NULL_FLAG))
+ field->field->set_notnull();
+ if (field->field == table->timestamp_field)
+ use_timestamp=1;
+ }
+ if (use_blobs && !ex->line_term->length() && !field_term->length())
+ {
+ my_message(ER_BLOBS_AND_NO_TERMINATED,ER(ER_BLOBS_AND_NO_TERMINATED),
+ MYF(0));
+ DBUG_RETURN(-1);
+ }
+
+ /* We can't give an error in the middle when using LOCAL files */
+ if (read_file_from_client && handle_duplicates == DUP_ERROR)
+ handle_duplicates=DUP_IGNORE;
+
+ if (read_file_from_client && (thd->client_capabilities & CLIENT_LOCAL_FILES))
+ {
+ 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);
+ file = -1;
+ }
+ else
+ {
+ read_file_from_client=0;
+#ifdef DONT_ALLOW_FULL_LOAD_DATA_PATHS
+ ex->file_name+=dirname_length(ex->file_name);
+#endif
+ if (!dirname_length(ex->file_name) &&
+ strlen(ex->file_name)+strlen(mysql_data_home)+strlen(thd->db)+3 <
+ FN_REFLEN)
+ {
+ (void) sprintf(name,"%s/%s/%s",mysql_data_home,thd->db,ex->file_name);
+ unpack_filename(name,name); /* Convert to system format */
+ }
+ else
+ {
+ unpack_filename(name,ex->file_name);
+#ifndef __WIN__
+ MY_STAT stat_info;
+ if (!my_stat(name,&stat_info,MYF(MY_FAE)))
+ DBUG_RETURN(-1);
+
+ // the file must be:
+ if (!(
+ (stat_info.st_mode & S_IROTH) == S_IROTH
+ && // readable by others
+ (stat_info.st_mode & S_IFLNK) != S_IFLNK
+ && // and not a symlink
+ ((stat_info.st_mode & S_IFREG) == S_IFREG
+ ||
+ (stat_info.st_mode & S_IFIFO) == S_IFIFO
+ )
+ // and either regular or a pipe
+ )
+ )
+ {
+ my_error(ER_TEXTFILE_NOT_READABLE,MYF(0),name);
+ DBUG_RETURN(-1);
+ }
+#endif
+ }
+ if ((file=my_open(name,O_RDONLY,MYF(MY_WME))) < 0)
+ DBUG_RETURN(-1);
+ }
+
+ COPY_INFO info;
+ bzero((char*) &info,sizeof(info));
+ info.handle_duplicates=handle_duplicates;
+ info.escape_char=escaped->length() ? (*escaped)[0] : INT_MAX;
+
+ READ_INFO read_info(file,tot_length,*field_term,
+ *ex->line_start, *ex->line_term, *enclosed,
+ info.escape_char,read_file_from_client);
+ if (read_info.error)
+ {
+ if (file >= 0)
+ my_close(file,MYF(0)); // no files in net reading
+ DBUG_RETURN(-1); // Can't allocate buffers
+ }
+
+ 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--)
+ {
+ if (read_info.next_line())
+ break;
+ }
+ }
+ if (!(error=test(read_info.error)))
+ {
+ uint save_time_stamp=table->time_stamp;
+ if (use_timestamp)
+ table->time_stamp=0;
+ table->next_number_field=table->found_next_number_field;
+ VOID(table->file->extra(HA_EXTRA_WRITE_CACHE));
+ table->copy_blobs=1;
+ if (!field_term->length() && !enclosed->length())
+ 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))
+ error=1; /* purecov: inspected */
+ table->time_stamp=save_time_stamp;
+ table->next_number_field=0;
+ if (thd->lock)
+ {
+ mysql_unlock_tables(thd, thd->lock);
+ thd->lock=0;
+ }
+ }
+ if (file >= 0) my_close(file,MYF(0));
+ free_blobs(table); /* if pack_blob was used */
+ table->copy_blobs=0;
+ thd->count_cuted_fields=0; /* Don`t calc cuted fields */
+ if (error)
+ DBUG_RETURN(-1); // Error on read
+ sprintf(name,ER(ER_LOAD_INFO),info.records,info.deleted,
+ info.records-info.copied,thd->cuted_fields);
+ send_ok(&thd->net,info.copied+info.deleted,0L,name);
+ mysql_update_log.write(thd->query,thd->query_length);
+
+ if(!read_file_from_client)
+ {
+ ex->skip_lines = save_skip_lines;
+ Load_log_event qinfo(thd, ex, table->table_name, fields, handle_duplicates);
+ mysql_bin_log.write(&qinfo);
+ }
+ DBUG_RETURN(0);
+}
+
+
+/****************************************************************************
+** Read of rows of fixed size + optional garage + optonal newline
+****************************************************************************/
+
+static int
+read_fixed_length(THD *thd,COPY_INFO &info,TABLE *table,List<Item> &fields,
+ READ_INFO &read_info)
+{
+ List_iterator<Item> it(fields);
+ Item_field *sql_field;
+ DBUG_ENTER("read_fixed_length");
+
+ /* No fields can be null in this format. mark all fields as not null */
+ while ((sql_field= (Item_field*) it++))
+ sql_field->field->set_notnull();
+
+ while (!read_info.read_fixed_length())
+ {
+ if (thd->killed)
+ {
+ my_error(ER_SERVER_SHUTDOWN,MYF(0));
+ DBUG_RETURN(1);
+ }
+ it.rewind();
+ byte *pos=read_info.row_start;
+#ifdef HAVE_purify
+ read_info.row_end[0]=0;
+#endif
+ while ((sql_field= (Item_field*) it++))
+ {
+ Field *field=sql_field->field;
+ if (pos == read_info.row_end)
+ {
+ thd->cuted_fields++; /* Not enough fields */
+ field->reset();
+ }
+ else
+ {
+ uint length;
+ byte save_chr;
+ if ((length=(uint) (read_info.row_end-pos)) >
+ field->field_length)
+ length=field->field_length;
+ save_chr=pos[length]; pos[length]='\0'; // Safeguard aganst malloc
+ field->store((char*) pos,length);
+ pos[length]=save_chr;
+ if ((pos+=length) > read_info.row_end)
+ pos= read_info.row_end; /* Fills rest with space */
+ }
+ }
+ if (pos != read_info.row_end)
+ thd->cuted_fields++; /* To long row */
+ if (write_record(table,&info))
+ 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
+ break;
+ if (read_info.line_cuted)
+ thd->cuted_fields++; /* To long row */
+ }
+ DBUG_RETURN(test(read_info.error));
+}
+
+
+
+static int
+read_sep_field(THD *thd,COPY_INFO &info,TABLE *table,
+ List<Item> &fields, READ_INFO &read_info,
+ String &enclosed)
+{
+ List_iterator<Item> it(fields);
+ Item_field *sql_field;
+ uint enclosed_length;
+ DBUG_ENTER("read_sep_field");
+
+ enclosed_length=enclosed.length();
+
+ for (;;it.rewind())
+ {
+ if (thd->killed)
+ {
+ my_error(ER_SERVER_SHUTDOWN,MYF(0));
+ DBUG_RETURN(1);
+ }
+ while ((sql_field=(Item_field*) it++))
+ {
+ uint length;
+ byte *pos;
+
+ if (read_info.read_field())
+ break;
+ pos=read_info.row_start;
+ length=(uint) (read_info.row_end-pos);
+ Field *field=sql_field->field;
+
+ if (!read_info.enclosed &&
+ (enclosed_length && length == 4 && !memcmp(pos,"NULL",4)) ||
+ (length == 1 && read_info.found_null))
+ {
+ field->reset();
+ field->set_null();
+ if (!field->maybe_null())
+ {
+ if (field->type() == FIELD_TYPE_TIMESTAMP)
+ ((Field_timestamp*) field)->set_time();
+ else
+ thd->cuted_fields++;
+ }
+ continue;
+ }
+ field->set_notnull();
+ read_info.row_end[0]=0; // Safe to change end marker
+ field->store((char*) read_info.row_start,length);
+ }
+ if (read_info.error)
+ break;
+ if (sql_field)
+ { // Last record
+ if (sql_field == (Item_field*) fields.head())
+ break;
+ for ( ; sql_field ; sql_field=(Item_field*) it++)
+ {
+ sql_field->field->set_null();
+ sql_field->field->reset();
+ thd->cuted_fields++;
+ }
+ }
+ if (write_record(table,&info))
+ 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
+ break;
+ if (read_info.line_cuted)
+ thd->cuted_fields++; /* To long row */
+ }
+ DBUG_RETURN(test(read_info.error));
+}
+
+
+/* Unescape all escape characters, mark \N as null */
+
+char
+READ_INFO::unescape(char chr)
+{
+ switch(chr) {
+ case 'n': return '\n';
+ case 't': return '\t';
+ case 'r': return '\r';
+ case 'b': return '\b';
+ case '0': return 0; // Ascii null
+ case 'Z': return '\032'; // Win32 end of file
+ case 'N': found_null=1;
+
+ /* fall through */
+ default: return chr;
+ }
+}
+
+
+ /* Read a line using buffering */
+ /* If last line is empty (in line mode) then it isn't outputed */
+
+
+READ_INFO::READ_INFO(File file_par, uint tot_length, String &field_term,
+ String &line_start, String &line_term,
+ String &enclosed_par, int escape, bool get_it_from_net)
+ :file(file_par),escape_char(escape)
+{
+ field_term_ptr=(char*) field_term.ptr();
+ field_term_length= field_term.length();
+ line_term_ptr=(char*) line_term.ptr();
+ line_term_length= line_term.length();
+ if (line_start.length() == 0)
+ {
+ line_start_ptr=0;
+ start_of_line= 0;
+ }
+ else
+ {
+ line_start_ptr=(char*) line_start.ptr();
+ line_start_end=line_start_ptr+line_start.length();
+ start_of_line= 1;
+ }
+ /* If field_terminator == line_terminator, don't use line_terminator */
+ if (field_term_length == line_term_length &&
+ !memcmp(field_term_ptr,line_term_ptr,field_term_length))
+ {
+ line_term_length=0;
+ line_term_ptr=(char*) "";
+ }
+ enclosed_char= (enclosed_length=enclosed_par.length()) ?
+ (uchar) enclosed_par[0] : INT_MAX;
+ field_term_char= field_term_length ? (uchar) field_term_ptr[0] : INT_MAX;
+ line_term_char= line_term_length ? (uchar) line_term_ptr[0] : INT_MAX;
+ error=eof=found_end_of_line=found_null=line_cuted=0;
+ buff_length=tot_length;
+
+
+ /* Set of a stack for unget if long terminators */
+ uint length=max(field_term_length,line_term_length)+1;
+ set_if_bigger(length,line_start.length());
+ stack=stack_pos=(int*) sql_alloc(sizeof(int)*length);
+
+ if (!(buffer=(byte*) my_malloc(buff_length+1,MYF(0))))
+ error=1; /* purecov: inspected */
+ else
+ {
+ end_of_buff=buffer+buff_length;
+ if (init_io_cache(&cache,(get_it_from_net) ? -1 : file, 0,
+ (get_it_from_net) ? READ_NET : READ_CACHE,0L,1,
+ MYF(MY_WME)))
+ {
+ my_free((gptr) buffer,MYF(0)); /* purecov: inspected */
+ error=1;
+ }
+ }
+}
+
+
+READ_INFO::~READ_INFO()
+{
+ if (!error)
+ {
+ end_io_cache(&cache);
+ my_free((gptr) buffer,MYF(0));
+ error=1;
+ }
+}
+
+
+#define GET (stack_pos != stack ? *--stack_pos : my_b_get(&cache))
+#define PUSH(A) *(stack_pos++)=(A)
+
+
+inline int READ_INFO::terminator(char *ptr,uint length)
+{
+ int chr=0; // Keep gcc happy
+ uint i;
+ for (i=1 ; i < length ; i++)
+ {
+ if ((chr=GET) != *++ptr)
+ {
+ break;
+ }
+ }
+ if (i == length)
+ return 1;
+ PUSH(chr);
+ while (i-- > 1)
+ PUSH((uchar) *--ptr);
+ return 0;
+}
+
+
+int READ_INFO::read_field()
+{
+ int chr,found_enclosed_char;
+ byte *to,*new_buffer;
+
+ found_null=0;
+ if (found_end_of_line)
+ return 1; // One have to call next_line
+
+ /* Skipp until we find 'line_start' */
+
+ if (start_of_line)
+ { // Skipp until line_start
+ start_of_line=0;
+ if (find_start_of_fields())
+ return 1;
+ }
+ if ((chr=GET) == my_b_EOF)
+ {
+ found_end_of_line=eof=1;
+ return 1;
+ }
+ to=buffer;
+ if (chr == enclosed_char)
+ {
+ found_enclosed_char=enclosed_char;
+ *to++=(byte) chr; // If error
+ }
+ else
+ {
+ found_enclosed_char= INT_MAX;
+ PUSH(chr);
+ }
+
+ for (;;)
+ {
+ while ( to < end_of_buff)
+ {
+ chr = GET;
+#ifdef USE_MB
+ if (use_mb(default_charset_info) &&
+ my_ismbhead(default_charset_info, chr) &&
+ to+my_mbcharlen(default_charset_info, chr) <= end_of_buff)
+ {
+ uchar* p = (uchar*)to;
+ *to++ = chr;
+ int ml = my_mbcharlen(default_charset_info, chr);
+ int i;
+ for (i=1; i<ml; i++) {
+ chr = GET;
+ if (chr == my_b_EOF)
+ goto found_eof;
+ *to++ = chr;
+ }
+ if (my_ismbchar(default_charset_info,
+ (const char *)p,
+ (const char *)to))
+ continue;
+ for (i=0; i<ml; i++)
+ PUSH((uchar) *--to);
+ chr = GET;
+ }
+#endif
+ if (chr == my_b_EOF)
+ goto found_eof;
+ if (chr == escape_char)
+ {
+ if ((chr=GET) == my_b_EOF)
+ {
+ *to++= (byte) escape_char;
+ goto found_eof;
+ }
+ *to++ = (byte) unescape((char) chr);
+ continue;
+ }
+#ifdef ALLOW_LINESEPARATOR_IN_STRINGS
+ if (chr == line_term_char)
+#else
+ if (chr == line_term_char && found_enclosed_char == INT_MAX)
+#endif
+ {
+ if (terminator(line_term_ptr,line_term_length))
+ { // Maybe unexpected linefeed
+ enclosed=0;
+ found_end_of_line=1;
+ row_start=buffer;
+ row_end= to;
+ return 0;
+ }
+ }
+ if (chr == found_enclosed_char)
+ {
+ if ((chr=GET) == found_enclosed_char)
+ { // Remove dupplicated
+ *to++ = (byte) chr;
+ continue;
+ }
+ // End of enclosed field if followed by field_term or line_term
+ if (chr == my_b_EOF ||
+ chr == line_term_char && terminator(line_term_ptr,
+ line_term_length))
+ { // Maybe unexpected linefeed
+ enclosed=1;
+ found_end_of_line=1;
+ row_start=buffer+1;
+ row_end= to;
+ return 0;
+ }
+ if (chr == field_term_char &&
+ terminator(field_term_ptr,field_term_length))
+ {
+ enclosed=1;
+ row_start=buffer+1;
+ row_end= to;
+ return 0;
+ }
+ /* Copy the found '"' character */
+ PUSH(chr);
+ chr='"';
+ }
+ else if (chr == field_term_char && found_enclosed_char == INT_MAX)
+ {
+ if (terminator(field_term_ptr,field_term_length))
+ {
+ enclosed=0;
+ row_start=buffer;
+ row_end= to;
+ return 0;
+ }
+ }
+ *to++ = (byte) chr;
+ }
+ /*
+ ** We come here if buffer is too small. Enlarge it and continue
+ */
+ if (!(new_buffer=(byte*) my_realloc((char*) buffer,buff_length+1+IO_SIZE,
+ MYF(MY_WME))))
+ return (error=1);
+ to=new_buffer + (to-buffer);
+ buffer=new_buffer;
+ buff_length+=IO_SIZE;
+ end_of_buff=buffer+buff_length;
+ }
+
+found_eof:
+ enclosed=0;
+ found_end_of_line=eof=1;
+ row_start=buffer;
+ row_end=to;
+ return 0;
+}
+
+/*
+** One can't use fixed length with multi-byte charset **
+*/
+
+int READ_INFO::read_fixed_length()
+{
+ int chr;
+ byte *to;
+ if (found_end_of_line)
+ return 1; // One have to call next_line
+
+ if (start_of_line)
+ { // Skipp until line_start
+ start_of_line=0;
+ if (find_start_of_fields())
+ return 1;
+ }
+
+ to=row_start=buffer;
+ while (to < end_of_buff)
+ {
+ if ((chr=GET) == my_b_EOF)
+ goto found_eof;
+ if (chr == escape_char)
+ {
+ if ((chr=GET) == my_b_EOF)
+ {
+ *to++= (byte) escape_char;
+ goto found_eof;
+ }
+ *to++ =(byte) unescape((char) chr);
+ continue;
+ }
+ if (chr == line_term_char)
+ {
+ if (terminator(line_term_ptr,line_term_length))
+ { // Maybe unexpected linefeed
+ found_end_of_line=1;
+ row_end= to;
+ return 0;
+ }
+ }
+ *to++ = (byte) chr;
+ }
+ row_end=to; // Found full line
+ return 0;
+
+found_eof:
+ found_end_of_line=eof=1;
+ row_start=buffer;
+ row_end=to;
+ return to == buffer ? 1 : 0;
+}
+
+
+int READ_INFO::next_line()
+{
+ line_cuted=0;
+ start_of_line= line_start_ptr != 0;
+ if (found_end_of_line || eof)
+ {
+ found_end_of_line=0;
+ return eof;
+ }
+ found_end_of_line=0;
+ if (!line_term_length)
+ return 0; // No lines
+ for (;;)
+ {
+ int chr = GET;
+#ifdef USE_MB
+ if (use_mb(default_charset_info) && my_ismbhead(default_charset_info, chr))
+ {
+ for (int i=1;
+ chr != my_b_EOF && i<my_mbcharlen(default_charset_info, chr);
+ i++)
+ chr = GET;
+ if (chr == escape_char)
+ continue;
+ }
+#endif
+ if (chr == my_b_EOF)
+ {
+ eof=1;
+ return 1;
+ }
+ if (chr == escape_char)
+ {
+ line_cuted=1;
+ if (GET == my_b_EOF)
+ return 1;
+ continue;
+ }
+ if (chr == line_term_char && terminator(line_term_ptr,line_term_length))
+ return 0;
+ line_cuted=1;
+ }
+}
+
+
+bool READ_INFO::find_start_of_fields()
+{
+ int chr;
+ try_again:
+ do
+ {
+ if ((chr=GET) == my_b_EOF)
+ {
+ found_end_of_line=eof=1;
+ return 1;
+ }
+ } while ((char) chr != line_start_ptr[0]);
+ for (char *ptr=line_start_ptr+1 ; ptr != line_start_end ; ptr++)
+ {
+ chr=GET; // Eof will be checked later
+ if ((char) chr != *ptr)
+ { // Can't be line_start
+ PUSH(chr);
+ while (--ptr != line_start_ptr)
+ { // Restart with next char
+ PUSH((uchar) *ptr);
+ }
+ goto try_again;
+ }
+ }
+ return 0;
+}
diff --git a/sql/sql_map.cc b/sql/sql_map.cc
new file mode 100644
index 00000000000..4578b85d10a
--- /dev/null
+++ b/sql/sql_map.cc
@@ -0,0 +1,147 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+
+#ifdef __GNUC__
+#pragma implementation // gcc: Class implementation
+#endif
+
+#include "mysql_priv.h"
+#ifdef HAVE_MMAP
+#include <sys/mman.h>
+#include <sys/stat.h>
+#endif
+
+#ifndef MAP_NORESERVE
+#define MAP_NORESERVE 0 // For IRIX
+#endif
+
+mapped_files::mapped_files(const my_string filename,byte *magic,uint magic_length)
+{
+#ifdef HAVE_MMAP
+ name=my_strdup(filename,MYF(0));
+ use_count=1;
+ error=0;
+ map=0;
+ size=0;
+ if ((file=my_open(name,O_RDONLY,MYF(MY_WME))) >= 0)
+ {
+ struct stat stat_buf;
+ if (!fstat(file,&stat_buf))
+ {
+ if (!(map=(byte*) mmap(0,(size=(ulong) stat_buf.st_size),PROT_READ,
+ MAP_SHARED | MAP_NORESERVE,file,
+ 0L)))
+ {
+ error=errno;
+ my_printf_error(0,"Can't map file: %s, errno: %d",MYF(0),
+ (my_string) name,error);
+ }
+ }
+ if (map && memcmp(map,magic,magic_length))
+ {
+ my_printf_error(0,"Wrong magic in %s",MYF(0),name);
+ VOID(munmap(map,size));
+ map=0;
+ }
+ if (!map)
+ {
+ VOID(my_close(file,MYF(0)));
+ file= -1;
+ }
+ }
+#endif
+}
+
+
+mapped_files::~mapped_files()
+{
+#ifdef HAVE_MMAP
+ if (file >= 0)
+ {
+ VOID(munmap((caddr_t) map,size));
+ VOID(my_close(file,MYF(0)));
+ file= -1; map=0;
+ }
+ my_free(name,MYF(0));
+#endif
+}
+
+
+static I_List<mapped_files> maps_in_use;
+
+/*
+** Check if a file is mapped. If it is, then return pointer to old map,
+** else alloc new object
+*/
+
+mapped_files *map_file(const my_string name,byte *magic,uint magic_length)
+{
+#ifdef HAVE_MMAP
+ VOID(pthread_mutex_lock(&LOCK_mapped_file));
+ I_List_iterator<mapped_files> list(maps_in_use);
+ mapped_files *map;
+ char path[FN_REFLEN];
+ sprintf(path,"%s/%s/%s.uniq",mysql_data_home,current_thd->db,name);
+ (void) unpack_filename(path,path);
+
+ while ((map=list++))
+ {
+ if (!strcmp(path,map->name))
+ break;
+ }
+ if (!map)
+ {
+ map=new mapped_files(path,magic,magic_length);
+ maps_in_use.append(map);
+ }
+ else
+ {
+ map->use_count++;
+ if (!map->map)
+ my_printf_error(0,"Can't map file: %s, error: %d",MYF(0),path,
+ map->error);
+ }
+ VOID(pthread_mutex_unlock(&LOCK_mapped_file));
+ return map;
+#else
+ return NULL;
+#endif
+}
+
+/*
+** free the map if there are no more users for it
+*/
+
+void unmap_file(mapped_files *map)
+{
+#ifdef HAVE_MMAP
+ VOID(pthread_mutex_lock(&LOCK_mapped_file));
+ if (!map->use_count--)
+ delete map;
+ VOID(pthread_mutex_unlock(&LOCK_mapped_file));
+#endif
+}
+
+/*****************************************************************************
+** Instansiate templates
+*****************************************************************************/
+
+#ifdef __GNUC__
+/* Used templates */
+template class I_List<mapped_files>;
+template class I_List_iterator<mapped_files>;
+#endif
diff --git a/sql/sql_map.h b/sql/sql_map.h
new file mode 100644
index 00000000000..e9093672fef
--- /dev/null
+++ b/sql/sql_map.h
@@ -0,0 +1,59 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+
+/* interface for memory mapped files */
+
+#ifdef __GNUC__
+#pragma interface /* gcc class implementation */
+#endif
+
+class mapped_files :public ilink {
+ byte *map;
+ ha_rows size;
+ char *name; // name of mapped file
+ File file; // >= 0 if open
+ int error; // If not mapped
+ uint use_count;
+
+public:
+ mapped_files(const my_string name,byte *magic,uint magic_length);
+ ~mapped_files();
+
+ friend class mapped_file;
+ friend mapped_files *map_file(const my_string name,byte *magic,
+ uint magic_length);
+ friend void unmap_file(mapped_files *map);
+};
+
+
+class mapped_file
+{
+ mapped_files *file;
+public:
+ mapped_file(const my_string name,byte *magic,uint magic_length)
+ {
+ file=map_file(name,magic,magic_length); /* old or new map */
+ }
+ ~mapped_file()
+ {
+ unmap_file(file); /* free map */
+ }
+ byte *map()
+ {
+ return file->map;
+ }
+};
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
new file mode 100644
index 00000000000..0c7b0b8187f
--- /dev/null
+++ b/sql/sql_parse.cc
@@ -0,0 +1,2627 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+
+#include "mysql_priv.h"
+#include "sql_acl.h"
+#include <m_ctype.h>
+#include <thr_alarm.h>
+#include <myisam.h>
+#include <my_dir.h>
+
+#define SCRAMBLE_LENGTH 8
+
+extern pthread_handler_decl(handle_slave,arg);
+extern bool slave_running;
+extern char* master_host;
+extern pthread_t slave_real_id;
+extern MASTER_INFO glob_mi;
+extern my_string opt_bin_logname, master_info_file;
+extern I_List<i_string> binlog_do_db, binlog_ignore_db;
+
+extern int yyparse(void);
+extern "C" pthread_mutex_t THR_LOCK_keycache;
+
+static bool check_table_access(THD *thd,uint want_access,TABLE_LIST *tables);
+static bool check_lock_tables(THD *thd,TABLE_LIST *tables);
+static bool check_dup(THD *thd,const char *db,const char *name,
+ TABLE_LIST *tables);
+static void mysql_init_query(THD *thd);
+static void remove_escape(char *name);
+static void kill_one_thread(THD *thd, ulong thread);
+static void refresh_status(void);
+static int start_slave(THD* thd = 0, bool net_report = 1);
+static int stop_slave(THD* thd = 0, bool net_report = 1);
+static int change_master(THD* thd);
+static void reset_slave();
+static void reset_master();
+
+
+static const char *any_db="*any*"; // Special symbol for check_access
+
+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","Start Slave", "Abort Slave"
+};
+
+bool volatile abort_slave = 0;
+
+#ifdef HAVE_OPENSSL
+extern VioSSLAcceptorFd* ssl_acceptor_fd;
+#endif /* HAVE_OPENSSL */
+
+#ifdef __WIN__
+static void test_signal(int sig_ptr)
+{
+#ifndef DBUG_OFF
+ MessageBox(NULL,"Test signal","DBUG",MB_OK);
+#endif
+}
+static void init_signals(void)
+{
+ int signals[7] = {SIGINT,SIGILL,SIGFPE,SIGSEGV,SIGTERM,SIGBREAK,SIGABRT } ;
+ for(int i=0 ; i < 7 ; i++)
+ signal( signals[i], test_signal) ;
+}
+#endif
+
+/*
+** 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;
+ 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->host, thd->ip, thd->user,
+ passwd, thd->scramble, &thd->priv_user,
+ protocol_version == 9 ||
+ !(thd->client_capabilities &
+ CLIENT_LONG_PASSWORD));
+ 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(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(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
+}
+
+
+/*
+** 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
+ */
+ 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
+ {
+ char ip[17];
+
+ if (vio_peer_addr(net->vio,ip))
+ return (ER_BAD_HOST_ERROR);
+ if (!(thd->ip = my_strdup(ip,MYF(0))))
+ return (ER_OUT_OF_RESOURCES);
+#if !defined(HAVE_SYS_UN_H) || defined(HAVE_mit_thread)
+ /* Fast local hostname resolve for Win32 */
+ if (!strcmp(thd->ip,"127.0.0.1"))
+ {
+ if (!(thd->host=my_strdup("localhost",MYF(0))))
+ return (ER_OUT_OF_RESOURCES);
+ }
+ else
+#endif
+ if (!(specialflag & SPECIAL_NO_RESOLVE))
+ {
+ vio_in_addr(net->vio,&thd->remote.sin_addr);
+ thd->host=ip_to_hostname(&thd->remote.sin_addr,&connect_errors);
+ 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"));
+ if (acl_check_host(thd->host,thd->ip))
+ return(ER_HOST_NOT_PRIVILEGED);
+ }
+ else /* No hostname means that the connection was on a socket */
+ {
+ DBUG_PRINT("general",("Host: localhost"));
+ 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[60],*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;
+#ifdef HAVE_COMPRESS
+ client_flags |= CLIENT_COMPRESS;
+#endif /* HAVE_COMPRESS */
+#ifdef HAVE_OPENSSL
+ if (ssl_acceptor_fd!=0)
+ 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;
+ int2store(end+3,thd->server_status);
+ bzero(end+5,13);
+ end+=18;
+ if (net_write_command(net,protocol_version, buff,
+ (uint) (end-buff)) ||
+ (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);
+#ifdef HAVE_OPENSSL
+ DBUG_PRINT("info",
+ ("pkt_len:%d, client capabilities: %d",
+ pkt_len, 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);
+ 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"));
+ inc_host_errors(&thd->remote.sin_addr);
+ return(ER_HANDSHAKE_ERROR);
+ }
+ }
+ else
+ {
+ DBUG_PRINT("info", ("Leaving IO layer intact"));
+ if (pkt_len < NORMAL_HANDSHAKE_SIZE)
+ {
+ inc_host_errors(&thd->remote.sin_addr);
+ return ER_HANDSHAKE_ERROR;
+ }
+ }
+#endif
+
+ 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;
+}
+
+
+pthread_handler_decl(handle_one_connection,arg)
+{
+ THD *thd=(THD*) arg;
+ uint launch_time =
+ (thd->thr_create_time = time(NULL)) - thd->connect_time;
+ if (launch_time >= slow_launch_time)
+ statistic_increment(slow_launch_threads,&LOCK_status );
+
+ pthread_detach_this_thread();
+
+#ifndef __WIN__ /* Win32 calls this in pthread_create */
+ if (my_thread_init()) // needed to be called first before we call
+ // DBUG_ macros
+ {
+ close_connection(&thd->net,ER_OUT_OF_RESOURCES);
+ statistic_increment(aborted_connects,&LOCK_thread_count);
+ end_thread(thd,0);
+ return 0;
+ }
+#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
+
+ 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_*
+
+#ifdef __WIN__
+ init_signals(); // IRENA; testing ?
+#else
+ sigset_t set;
+ VOID(sigemptyset(&set)); // Get mask in use
+ VOID(pthread_sigmask(SIG_UNBLOCK,&set,&thd->block_signals));
+#endif
+ if (thd->store_globals())
+ {
+ close_connection(&thd->net,ER_OUT_OF_RESOURCES);
+ statistic_increment(aborted_connects,&LOCK_thread_count);
+ end_thread(thd,0);
+ return 0;
+ }
+
+ do
+ {
+ int error;
+ NET *net= &thd->net;
+
+ thd->mysys_var=my_thread_var;
+ thd->dbug_thread_id=my_thread_id();
+ thd->thread_stack= (char*) &thd;
+
+ if ((error=check_connections(thd)))
+ { // Wrong permissions
+ if (error > 0)
+ net_printf(net,error,thd->host ? thd->host : thd->ip);
+#ifdef __NT__
+ if (vio_type(net->vio) == VIO_TYPE_NAMEDPIPE)
+ sleep(1); /* must wait after eof() */
+#endif
+ statistic_increment(aborted_connects,&LOCK_thread_count);
+ goto end_thread;
+ }
+
+ thd->alloc.free=thd->alloc.used=0;
+ if (thd->max_join_size == HA_POS_ERROR)
+ thd->options |= OPTION_BIG_SELECTS;
+ if (thd->client_capabilities & CLIENT_COMPRESS)
+ net->compress=1; // Use compression
+ if (thd->options & OPTION_ANSI_MODE)
+ thd->client_capabilities|=CLIENT_IGNORE_SPACE;
+
+ thd->proc_info=0;
+ thd->version=refresh_version;
+ thd->set_time();
+ while (!net->error && net->vio != 0 && !thd->killed)
+ {
+ if (do_command(thd))
+ break;
+ }
+ if (net->error && net->vio != 0)
+ {
+ sql_print_error(ER(ER_NEW_ABORTING_CONNECTION),
+ thd->thread_id,(thd->db ? thd->db : "unconnected"),
+ thd->user,
+ (thd->host ? thd->host : thd->ip ? thd->ip : "unknown"),
+ (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);
+ }
+
+end_thread:
+ close_connection(net);
+ end_thread(thd,1);
+ /*
+ If end_thread returns, we are either running with --one-thread
+ or this thread has been schedule to handle the next query
+ */
+ thd= current_thd;
+ } while (!(test_flags & TEST_NO_THREADS));
+ /* The following is only executed if we are not using --one-thread */
+ return(0); /* purecov: deadcode */
+}
+
+
+int handle_bootstrap(THD *thd,FILE *file)
+{
+ DBUG_ENTER("handle_bootstrap");
+ thd->thread_stack= (char*) &thd;
+
+ if (init_thr_lock() ||
+ my_pthread_setspecific_ptr(THR_THD, thd) ||
+ my_pthread_setspecific_ptr(THR_MALLOC, &thd->alloc) ||
+ my_pthread_setspecific_ptr(THR_NET, &thd->net))
+ {
+ close_connection(&thd->net,ER_OUT_OF_RESOURCES);
+ DBUG_RETURN(-1);
+ }
+ thd->mysys_var=my_thread_var;
+ thd->dbug_thread_id=my_thread_id();
+#ifndef __WIN__
+ sigset_t set;
+ VOID(sigemptyset(&set)); // Get mask in use
+ VOID(pthread_sigmask(SIG_UNBLOCK,&set,&thd->block_signals));
+#endif
+
+ thd->alloc.free=thd->alloc.used=0;
+ if (thd->max_join_size == (ulong) ~0L)
+ thd->options |= OPTION_BIG_SELECTS;
+
+ thd->proc_info=0;
+ thd->version=refresh_version;
+
+ char *buff= (char*) thd->net.buff;
+ while (fgets(buff, thd->net.max_packet, file))
+ {
+ uint length=strlen(buff);
+ while (length && (isspace(buff[length-1]) || buff[length-1] == ';'))
+ length--;
+ buff[length]=0;
+ init_sql_alloc(&thd->alloc,8192);
+ thd->current_tablenr=0;
+ thd->query= sql_memdup(buff,length+1);
+ thd->query_id=query_id++;
+ mysql_parse(thd,thd->query,length);
+ close_thread_tables(thd); // Free tables
+ if (thd->fatal_error)
+ {
+ DBUG_RETURN(-1);
+ }
+ free_root(&thd->alloc);
+ }
+ DBUG_RETURN(0);
+}
+
+
+static inline void free_items(THD *thd)
+{
+ /* This works because items are allocated with sql_alloc() */
+ for (Item *item=thd->free_list ; item ; item=item->next)
+ delete item;
+}
+
+int mysql_table_dump(THD* thd, char* db, char* tbl_name, int fd)
+{
+ TABLE* table;
+ TABLE_LIST* table_list;
+ 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))))
+ DBUG_RETURN(1); // out of memory
+ table_list->db = db;
+ table_list->real_name = table_list->name = tbl_name;
+ table_list->lock_type = TL_READ_NO_INSERT;
+ table_list->next = 0;
+ remove_escape(table_list->real_name);
+
+ if(!(table=open_ltable(thd, table_list, TL_READ_NO_INSERT)))
+ DBUG_RETURN(1);
+
+ if(check_access(thd, SELECT_ACL, db, &table_list->grant.privilege))
+ goto err;
+ if(grant_option && check_grant(thd, SELECT_ACL, table_list))
+ goto err;
+
+ thd->free_list = 0;
+ thd->query = tbl_name;
+ 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));
+
+err:
+
+ close_thread_tables(thd);
+
+ DBUG_RETURN(error);
+}
+
+
+
+ /* Execute one command from socket (query or simple command) */
+
+bool do_command(THD *thd)
+{
+ char *packet;
+ uint old_timeout,packet_length;
+ bool error=0;
+ NET *net;
+ enum enum_server_command command;
+ DBUG_ENTER("do_command");
+
+ init_sql_alloc(&thd->alloc,8192);
+ net= &thd->net;
+ thd->current_tablenr=0;
+
+ packet=0;
+ old_timeout=net->timeout;
+ net->timeout=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) ));
+ return TRUE;
+ }
+ else
+ {
+ packet=(char*) net->read_pos;
+ command = (enum enum_server_command) (uchar) packet[0];
+ DBUG_PRINT("general",("Command on socket %s = %d (%s)",
+ vio_description(net->vio), command,
+ command_name[command]));
+ }
+ net->timeout=old_timeout; /* Timeout */
+ thd->command=command;
+ VOID(pthread_mutex_lock(&LOCK_thread_count));
+ thd->query_id=query_id;
+ if (command != COM_STATISTICS && command != COM_PING)
+ query_id++;
+ thread_running++;
+ VOID(pthread_mutex_unlock(&LOCK_thread_count));
+ thd->set_time();
+ switch(command) {
+ case COM_INIT_DB:
+ if (!mysql_change_db(thd,packet+1))
+ mysql_log.write(command,"%s",thd->db);
+ break;
+ case COM_TABLE_DUMP:
+ {
+ 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);
+ char* tbl_name = db + db_len;
+ *tbl_name++ = 0;
+ memcpy(tbl_name, data + db_len + 2, tbl_len);
+ tbl_name[tbl_len] = 0;
+ if(mysql_table_dump(thd, db, tbl_name, -1))
+ send_error(&thd->net); // dump to NET
+
+ break;
+ }
+ case COM_CHANGE_USER:
+ {
+ char *user= (char*) packet+1;
+ 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;
+ char *save_user= thd->user;
+ char *save_priv_user= thd->priv_user;
+ char *save_db= thd->db;
+
+ if ((uint) ((uchar*) db - net->read_pos) > packet_length)
+ { // Check if protocol is ok
+ send_error(net, ER_UNKNOWN_COM_ERROR);
+ break;
+ }
+ if (check_user(thd, COM_CHANGE_USER, user, passwd, db,0))
+ { // Restore old user
+ x_free(thd->user);
+ x_free(thd->db);
+ thd->master_access=save_master_access;
+ thd->db_access=save_db_access;
+ thd->db=save_db;
+ thd->user=save_user;
+ thd->priv_user=save_priv_user;
+ break;
+ }
+ x_free((gptr) save_db);
+ x_free((gptr) save_user);
+ thd->password=test(passwd[0]);
+ break;
+ }
+
+ case COM_QUERY:
+ {
+ char *pos=packet+packet_length; // Point at end null
+ /* Remove garage at end of query */
+ while (packet_length > 0 && pos[-1] == ';')
+ {
+ pos--;
+ packet_length--;
+ }
+ *pos=0;
+ if (!(thd->query= (char*) sql_memdup((gptr) (packet+1),packet_length)))
+ break;
+ thd->packet.shrink(net_buffer_length); // Reclaim some memory
+ if (!(specialflag & SPECIAL_NO_PRIOR))
+ my_pthread_setprio(pthread_self(),QUERY_PRIOR);
+ mysql_log.write(command,"%s",thd->query);
+ DBUG_PRINT("query",("%s",thd->query));
+ mysql_parse(thd,thd->query,packet_length-1);
+ 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
+#ifdef DONT_ALLOW_SHOW_COMMANDS
+ send_error(&thd->net,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
+ break;
+#else
+ {
+ char *fields;
+ TABLE_LIST table_list;
+ bzero((char*) &table_list,sizeof(table_list));
+ if (!(table_list.db=thd->db))
+ {
+ send_error(net,ER_NO_DB_ERROR);
+ break;
+ }
+ thd->free_list=0;
+ table_list.name=table_list.real_name=sql_strdup(packet+1);
+ thd->query=fields=sql_strdup(strend(packet+1)+1);
+ mysql_log.write(command,"%s %s",table_list.real_name,fields);
+ remove_escape(table_list.real_name); // This can't have wildcards
+
+ if (check_access(thd,SELECT_ACL,table_list.db,&thd->col_access))
+ break;
+ table_list.grant.privilege=thd->col_access;
+ if (grant_option && check_grant(thd,SELECT_ACL,&table_list,2))
+ break;
+ mysqld_list_fields(thd,&table_list,fields);
+ free_items(thd);
+ break;
+ }
+#endif
+ case COM_QUIT:
+ mysql_log.write(command,NullS);
+ net->error=0; // Don't give 'abort' message
+ error=TRUE; // End server
+ break;
+
+ case COM_CREATE_DB:
+ {
+ char *db=sql_strdup(packet+1);
+ if (check_access(thd,CREATE_ACL,db,0,1))
+ break;
+ mysql_log.write(command,packet+1);
+ mysql_create_db(thd,db,0);
+ break;
+ }
+ case COM_DROP_DB:
+ {
+ char *db=sql_strdup(packet+1);
+ if (check_access(thd,DROP_ACL,db,0,1))
+ break;
+ mysql_log.write(command,db);
+ mysql_rm_db(thd,db,0);
+ break;
+ }
+ case COM_BINLOG_DUMP:
+ {
+ if(check_access(thd, FILE_ACL, any_db))
+ break;
+ mysql_log.write(command, 0);
+
+ ulong pos;
+ ushort flags;
+ pos = uint4korr(packet + 1);
+ flags = uint2korr(packet + 5);
+ mysql_binlog_send(thd, sql_strdup(packet + 7), pos, flags);
+ break;
+ }
+ case COM_REFRESH:
+ {
+ uint options=(uchar) packet[1];
+ if (check_access(thd,RELOAD_ACL,any_db))
+ break;
+ mysql_log.write(command,NullS);
+ if (reload_acl_and_cache(options))
+ send_error(net,0);
+ else
+ send_eof(net);
+ break;
+ }
+ case COM_SHUTDOWN:
+ if (check_access(thd,SHUTDOWN_ACL,any_db))
+ break; /* purecov: inspected */
+ DBUG_PRINT("quit",("Got shutdown command"));
+ mysql_log.write(command,NullS);
+ send_eof(net);
+#ifdef __WIN__
+ sleep(1); // must wait after eof()
+#endif
+ send_eof(net); // This is for 'quit request'
+ close_connection(net);
+ close_thread_tables(thd); // Free before kill
+ free_root(&thd->alloc);
+ kill_mysql();
+ error=TRUE;
+ break;
+
+ case COM_STATISTICS:
+ {
+ mysql_log.write(command,NullS);
+ char buff[200];
+ ulong uptime = (ulong) (time((time_t*) 0) - 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,
+ (int) thread_count,thd->query_id,long_query_count,
+ opened_tables,refresh_version, cached_tables(),
+ uptime ? (float)thd->query_id/(float)uptime : 0);
+#ifdef SAFEMALLOC
+ if (lCurMemory) // Using SAFEMALLOC
+ sprintf(strend(buff), " Memory in use: %ldK Max memory used: %ldK",
+ (lCurMemory+1023L)/1024L,(lMaxMemory+1023L)/1024L);
+ #endif
+ VOID(my_net_write(net, buff,strlen(buff)));
+ VOID(net_flush(net));
+ break;
+ }
+ case COM_PING:
+ send_ok(net); // Tell client we are alive
+ break;
+ case COM_PROCESS_INFO:
+ if (!thd->priv_user[0] && check_access(thd,PROCESS_ACL,any_db))
+ break;
+ mysql_log.write(command,NullS);
+ mysqld_list_processes(thd,thd->master_access & PROCESS_ACL ? NullS :
+ thd->priv_user,0);
+ break;
+ case COM_PROCESS_KILL:
+ {
+ ulong id=(ulong) uint4korr(packet+1);
+ kill_one_thread(thd,id);
+ break;
+ }
+ case COM_DEBUG:
+ if (check_access(thd,PROCESS_ACL,any_db))
+ break; /* purecov: inspected */
+ mysql_print_status(thd);
+ mysql_log.write(command,NullS);
+ send_eof(net);
+ break;
+ case COM_SLEEP:
+ case COM_CONNECT: // Impossible here
+ case COM_TIME: // Impossible from client
+ case COM_DELAYED_INSERT:
+ default:
+ send_error(net, ER_UNKNOWN_COM_ERROR);
+ break;
+ }
+ if (thd->lock || thd->open_tables)
+ {
+ thd->proc_info="closing tables";
+ close_thread_tables(thd); /* Free tables */
+ }
+ thd->proc_info="cleaning up";
+
+ if (thd->fatal_error)
+ send_error(net,0); // End of memory ?
+
+ time_t start_of_query=thd->start_time;
+ thd->set_time();
+ if ((ulong) (thd->start_time - start_of_query) > long_query_time)
+ {
+ long_query_count++;
+ mysql_slow_log.write(thd->query, thd->query_length,
+ (ulong) (thd->start_time - start_of_query));
+ }
+ VOID(pthread_mutex_lock(&LOCK_thread_count)); // For process list
+ thd->proc_info=0;
+ thd->command=COM_SLEEP;
+ thd->query=0;
+ thread_running--;
+ VOID(pthread_mutex_unlock(&LOCK_thread_count));
+ thd->packet.shrink(net_buffer_length); // Reclaim some memory
+ free_root(&thd->alloc);
+ DBUG_RETURN(error);
+}
+
+/****************************************************************************
+** mysql_execute_command
+** Execute command saved in thd and current_lex->sql_command
+****************************************************************************/
+
+void
+mysql_execute_command(void)
+{
+ int res=0;
+ THD *thd=current_thd;
+ LEX *lex=current_lex;
+ TABLE_LIST *tables=(TABLE_LIST*) lex->table_list.first;
+ DBUG_ENTER("mysql_execute_command");
+
+ switch (lex->sql_command) {
+ case SQLCOM_SELECT:
+ {
+ select_result *result;
+ if (lex->options & SELECT_DESCRIBE)
+ lex->exchange=0;
+ if (tables)
+ {
+ res=check_table_access(thd,
+ lex->exchange ? SELECT_ACL | FILE_ACL :
+ SELECT_ACL,
+ tables);
+ }
+ else
+ res=check_access(thd, lex->exchange ? SELECT_ACL | FILE_ACL : SELECT_ACL,
+ any_db);
+ if (res)
+ {
+ res=0;
+ 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->select_limit= HA_POS_ERROR; // no limit
+
+ if (lex->exchange)
+ {
+ if (lex->exchange->dumpfile)
+ {
+ if (!(result=new select_dump(lex->exchange)))
+ {
+ res= -1;
+ break;
+ }
+ }
+ else
+ {
+ if (!(result=new select_export(lex->exchange)))
+ {
+ res= -1;
+ break;
+ }
+ }
+ }
+ else if (!(result=new select_send()))
+ {
+ res= -1;
+#ifdef DELETE_ITEMS
+ delete lex->having;
+ delete lex->where;
+#endif
+ break;
+ }
+
+ if (lex->options & SELECT_HIGH_PRIORITY)
+ {
+ TABLE_LIST *table;
+ for (table = tables ; table ; table=table->next)
+ table->lock_type=TL_READ_HIGH_PRIORITY;
+ }
+
+ if (!(res=open_and_lock_tables(thd,tables)))
+ {
+ res=mysql_select(thd,tables,lex->item_list,
+ lex->where,
+ lex->ftfunc_list,
+ (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;
+#ifdef DELETE_ITEMS
+ delete lex->having;
+ delete lex->where;
+#endif
+ break;
+ }
+ case SQLCOM_CHANGE_MASTER:
+ {
+ if(check_access(thd, PROCESS_ACL, any_db))
+ goto error;
+ res = change_master(thd);
+ break;
+ }
+ case SQLCOM_SHOW_SLAVE_STAT:
+ {
+ if(check_access(thd, PROCESS_ACL, any_db))
+ goto error;
+ res = show_master_info(thd);
+ break;
+ }
+ case SQLCOM_SHOW_MASTER_STAT:
+ {
+ if(check_access(thd, PROCESS_ACL, any_db))
+ goto error;
+ res = show_binlog_info(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))
+ goto error; /* purecov: inspected */
+ if (grant_option)
+ {
+ /* Check that the first table has CREATE privilege */
+ TABLE_LIST *tmp_table_list=tables->next;
+ tables->next=0;
+ bool error=check_grant(thd,CREATE_ACL,tables);
+ tables->next=tmp_table_list;
+ if (error)
+ goto error;
+ }
+ if (strlen(tables->name) > NAME_LEN)
+ {
+ net_printf(&thd->net,ER_WRONG_TABLE_NAME,tables->name);
+ res=0;
+ break;
+ }
+
+ thd->last_nx_table = tables->real_name;
+ thd->last_nx_db = tables->db;
+ if(fetch_nx_table(thd, &glob_mi))
+ // fetch_nx_table is responsible for sending
+ // the error
+ {
+ res = 0;
+ thd->net.no_send_ok = 0; // easier to do it here
+ // this way we make sure that when we are done, we are clean
+ break;
+ }
+
+ res = 0;
+ send_ok(&thd->net);
+ break;
+
+ case SQLCOM_CREATE_TABLE:
+#ifdef DEMO_VERSION
+ send_error(&thd->net,ER_NOT_ALLOWED_COMMAND);
+#else
+ if (check_access(thd,CREATE_ACL,tables->db,&tables->grant.privilege))
+ goto error; /* purecov: inspected */
+ if (grant_option)
+ {
+ /* Check that the first table has CREATE privilege */
+ TABLE_LIST *tmp_table_list=tables->next;
+ tables->next=0;
+ bool error=check_grant(thd,CREATE_ACL,tables);
+ tables->next=tmp_table_list;
+ if (error)
+ goto error;
+ }
+ if (strlen(tables->name) > NAME_LEN)
+ {
+ net_printf(&thd->net,ER_WRONG_TABLE_NAME,tables->name);
+ res=0;
+ break;
+ }
+ if (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))
+ {
+ net_printf(&thd->net,ER_INSERT_TABLE_USED,tables->real_name);
+ DBUG_VOID_RETURN;
+ }
+ if (tables->next)
+ {
+ if (check_table_access(thd, SELECT_ACL, tables->next))
+ goto error; // 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->select_limit= HA_POS_ERROR; // No limit
+
+ 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,
+ lex->ftfunc_list,
+ (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;
+ }
+ else
+ res= -1;
+ }
+ }
+ else // regular create
+ {
+ res = mysql_create_table(thd,tables->db ? tables->db : thd->db,
+ tables->real_name, &lex->create_info,
+ lex->create_list,
+ lex->key_list,0, 0); // do logging
+ if (!res)
+ send_ok(&thd->net);
+ }
+ break;
+ case SQLCOM_CREATE_INDEX:
+ if (!tables->db)
+ tables->db=thd->db;
+ if (check_access(thd,INDEX_ACL,tables->db,&tables->grant.privilege))
+ goto error; /* purecov: inspected */
+ if (grant_option && check_grant(thd,INDEX_ACL,tables))
+ goto error;
+ res = mysql_create_index(thd, tables, lex->key_list);
+#endif
+ break;
+
+ case SQLCOM_SLAVE_START:
+ start_slave(thd);
+ break;
+ case SQLCOM_SLAVE_STOP:
+ stop_slave(thd);
+ break;
+
+
+ case SQLCOM_ALTER_TABLE:
+#if defined(DONT_ALLOW_SHOW_COMMANDS)
+ send_error(&thd->net,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
+ break;
+#else
+ {
+ uint priv=0;
+ if (lex->name && strlen(lex->name) > NAME_LEN)
+ {
+ net_printf(&thd->net,ER_WRONG_TABLE_NAME,lex->name);
+ res=0;
+ break;
+ }
+ if (!lex->db)
+ 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))
+ goto error; /* purecov: inspected */
+ if (!tables->db)
+ tables->db=thd->db;
+ if (grant_option)
+ {
+ if (check_grant(thd,ALTER_ACL,tables))
+ goto error;
+ if (lex->name && !test_all_bits(priv,INSERT_ACL | CREATE_ACL))
+ { // Rename of table
+ TABLE_LIST tmp_table;
+ bzero((char*) &tmp_table,sizeof(tmp_table));
+ tmp_table.real_name=lex->name;
+ tmp_table.db=lex->db;
+ tmp_table.grant.privilege=priv;
+ if (check_grant(thd,INSERT_ACL | CREATE_ACL,tables))
+ goto error;
+ }
+ }
+ /* ALTER TABLE ends previous transaction */
+ if (!(thd->options & OPTION_AUTO_COMMIT) && ha_commit(thd))
+ res= -1;
+ else
+ res= mysql_alter_table(thd, lex->db, lex->name,
+ &lex->create_info,
+ tables, lex->create_list,
+ lex->key_list, lex->drop_list, lex->alter_list,
+ lex->drop_primary, lex->duplicates);
+ break;
+ }
+#endif
+ case SQLCOM_SHOW_CREATE:
+ {
+ if(! tables->db)
+ tables->db = thd->db;
+ if (!tables->db)
+ {
+ send_error(&thd->net,ER_NO_DB_ERROR); /* purecov: inspected */
+ goto error; /* purecov: inspected */
+ }
+ res = mysqld_show_create(thd, tables);
+ break;
+ }
+ case SQLCOM_REPAIR:
+ {
+ if (!tables->db)
+ tables->db=thd->db;
+ if (check_access(thd,SELECT_ACL | INSERT_ACL,tables->db,
+ &tables->grant.privilege))
+ goto error; /* purecov: inspected */
+ if (grant_option && check_grant(thd,SELECT_ACL | INSERT_ACL,tables))
+ goto error;
+ res = mysql_repair_table(thd, tables, &lex->check_opt);
+ break;
+ }
+ case SQLCOM_CHECK:
+ {
+ if (!tables->db)
+ tables->db=thd->db;
+ if (check_access(thd,SELECT_ACL,tables->db,
+ &tables->grant.privilege))
+ goto error; /* purecov: inspected */
+ if (grant_option && check_grant(thd,SELECT_ACL,tables))
+ goto error;
+ res = mysql_check_table(thd, tables, &lex->check_opt);
+ break;
+ }
+ case SQLCOM_ANALYZE:
+ {
+ if (!tables->db)
+ tables->db=thd->db;
+ if (check_access(thd,SELECT_ACL|INSERT_ACL,tables->db,
+ &tables->grant.privilege))
+ goto error; /* purecov: inspected */
+ if (grant_option && check_grant(thd,SELECT_ACL|INSERT_ACL,tables))
+ goto error;
+ res = mysql_analyze_table(thd, tables);
+ break;
+ }
+ case SQLCOM_OPTIMIZE:
+ {
+ HA_CREATE_INFO create_info;
+ /* This is now done with ALTER TABLE, but should be done with isamchk */
+ if (!tables->db)
+ tables->db=thd->db;
+ if (check_access(thd,SELECT_ACL | INSERT_ACL,tables->db,
+ &tables->grant.privilege))
+ goto error; /* purecov: inspected */
+ if (grant_option && check_grant(thd,SELECT_ACL | INSERT_ACL,tables))
+ goto error;
+
+ lex->create_list.empty();
+ lex->key_list.empty();
+ lex->col_list.empty();
+ lex->drop_list.empty();
+ lex->alter_list.empty();
+ bzero((char*) &create_info,sizeof(create_info));
+ create_info.db_type=DB_TYPE_DEFAULT;
+ create_info.row_type=ROW_TYPE_DEFAULT;
+ res= mysql_alter_table(thd, NullS, NullS, &create_info,
+ tables, lex->create_list,
+ lex->key_list, lex->drop_list, lex->alter_list,
+ 0,DUP_ERROR);
+ break;
+ }
+ case SQLCOM_UPDATE:
+ if (check_access(thd,UPDATE_ACL,tables->db,&tables->grant.privilege))
+ goto error;
+ if (grant_option && check_grant(thd,UPDATE_ACL,tables))
+ goto error;
+ if (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);
+
+#ifdef DELETE_ITEMS
+ delete lex->where;
+#endif
+ break;
+ case SQLCOM_INSERT:
+ if (check_access(thd,INSERT_ACL,tables->db,&tables->grant.privilege))
+ goto error; /* purecov: inspected */
+ if (grant_option && check_grant(thd,INSERT_ACL,tables))
+ goto error;
+ res = mysql_insert(thd,tables,lex->field_list,lex->many_values,
+ lex->duplicates,
+ lex->lock_option);
+ break;
+ case SQLCOM_REPLACE:
+ if (check_access(thd,INSERT_ACL | UPDATE_ACL | DELETE_ACL,
+ tables->db,&tables->grant.privilege))
+ goto error; /* purecov: inspected */
+ if (grant_option && check_grant(thd,INSERT_ACL | UPDATE_ACL | DELETE_ACL,
+ tables))
+
+ goto error;
+ res = mysql_insert(thd,tables,lex->field_list,lex->many_values,
+ DUP_REPLACE,
+ lex->lock_option);
+ break;
+ case SQLCOM_REPLACE_SELECT:
+ case SQLCOM_INSERT_SELECT:
+ {
+ // Check that we have modify privileges for the first table and
+ // select privileges for the rest
+ uint privilege= (lex->sql_command == SQLCOM_INSERT_SELECT ?
+ INSERT_ACL : INSERT_ACL | UPDATE_ACL | DELETE_ACL);
+ TABLE_LIST *save_next=tables->next;
+ tables->next=0;
+ if (check_access(thd, privilege,
+ tables->db,&tables->grant.privilege) ||
+ (grant_option && check_grant(thd, privilege, tables)))
+ goto error;
+ tables->next=save_next;
+ if ((res=check_table_access(thd, SELECT_ACL, save_next)))
+ goto error;
+
+ 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->select_limit= HA_POS_ERROR; // No limit
+
+ if (check_dup(thd,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
+ 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,
+ lex->ftfunc_list,
+ (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;
+ }
+#ifdef DELETE_ITEMS
+ delete lex->having;
+ delete lex->where;
+#endif
+ break;
+ }
+ case SQLCOM_DELETE:
+ {
+ if (check_access(thd,DELETE_ACL,tables->db,&tables->grant.privilege))
+ goto error; /* purecov: inspected */
+ if (grant_option && check_grant(thd,DELETE_ACL,tables))
+ goto error;
+ // Set privilege for the WHERE clause
+ tables->grant.want_privilege=(SELECT_ACL & ~tables->grant.privilege);
+ res = mysql_delete(thd,tables,lex->where,lex->select_limit,
+ lex->lock_option);
+#ifdef DELETE_ITEMS
+ delete lex->where;
+#endif
+ break;
+ }
+ case SQLCOM_DROP_TABLE:
+ {
+ if (check_table_access(thd,DROP_ACL,tables))
+ goto error; /* purecov: inspected */
+ res = mysql_rm_table(thd,tables,lex->drop_if_exists);
+ }
+ break;
+ case SQLCOM_DROP_INDEX:
+ if (!tables->db)
+ tables->db=thd->db;
+ if (check_access(thd,INDEX_ACL,tables->db,&tables->grant.privilege))
+ goto error; /* purecov: inspected */
+ if (grant_option && check_grant(thd,INDEX_ACL,tables))
+ goto error;
+ res = mysql_drop_index(thd, tables, lex->drop_list);
+ break;
+ case SQLCOM_SHOW_DATABASES:
+#if defined(DONT_ALLOW_SHOW_COMMANDS) || defined(DEMO_VERSION)
+ send_error(&thd->net,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
+ DBUG_VOID_RETURN;
+#else
+ if ((specialflag & SPECIAL_SKIP_SHOW_DB) &&
+ check_access(thd,PROCESS_ACL,any_db))
+ goto error;
+ res= mysqld_show_dbs(thd, (lex->wild ? lex->wild->ptr() : NullS));
+ break;
+#endif
+ case SQLCOM_SHOW_PROCESSLIST:
+ if (!thd->priv_user[0] && check_access(thd,PROCESS_ACL,any_db))
+ break;
+ mysqld_list_processes(thd,thd->master_access & PROCESS_ACL ? NullS :
+ thd->priv_user,lex->verbose);
+ break;
+ case SQLCOM_SHOW_STATUS:
+ res= mysqld_show(thd,(lex->wild ? lex->wild->ptr() : NullS),status_vars);
+ break;
+ case SQLCOM_SHOW_VARIABLES:
+ res= mysqld_show(thd, (lex->wild ? lex->wild->ptr() : NullS),
+ init_vars);
+ break;
+ case SQLCOM_SHOW_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;
+ if (!db)
+ {
+ send_error(&thd->net,ER_NO_DB_ERROR); /* purecov: inspected */
+ goto error; /* purecov: inspected */
+ }
+ remove_escape(db); // Fix escaped '_'
+ if (strlen(db) > NAME_LEN)
+ {
+ net_printf(&thd->net,ER_WRONG_DB_NAME, db);
+ goto error;
+ }
+ if (check_access(thd,SELECT_ACL,db,&thd->col_access))
+ goto error; /* purecov: inspected */
+ /* grant is checked in mysqld_show_tables */
+ if (lex->options & SELECT_DESCRIBE)
+ res= mysqld_extend_show_tables(thd,db,
+ (lex->wild ? lex->wild->ptr() : NullS));
+ else
+ res= mysqld_show_tables(thd,db,
+ (lex->wild ? lex->wild->ptr() : NullS));
+ break;
+ }
+#endif
+ case SQLCOM_SHOW_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)
+ {
+ 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;
+ if (grant_option && check_grant(thd,SELECT_ACL,tables,2))
+ goto error;
+ res= mysqld_show_fields(thd,tables,
+ (lex->wild ? lex->wild->ptr() : NullS));
+ break;
+ }
+#endif
+ case SQLCOM_SHOW_KEYS:
+#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)
+ {
+ 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,db,&thd->col_access))
+ goto error; /* purecov: inspected */
+ tables->grant.privilege=thd->col_access;
+ if (grant_option && check_grant(thd,SELECT_ACL,tables,2))
+ goto error;
+ res= mysqld_show_keys(thd,tables);
+ break;
+ }
+#endif
+ case SQLCOM_CHANGE_DB:
+ mysql_change_db(thd,lex->db);
+ break;
+ case SQLCOM_LOAD:
+ {
+ uint privilege= (lex->duplicates == DUP_REPLACE ?
+ INSERT_ACL | UPDATE_ACL | DELETE_ACL : INSERT_ACL);
+ if (!(lex->local_file && (thd->client_capabilities & CLIENT_LOCAL_FILES)))
+ {
+ if (check_access(thd,privilege | FILE_ACL,tables->db))
+ goto error;
+ }
+ else
+ {
+ if (check_access(thd,privilege,tables->db,&tables->grant.privilege) ||
+ grant_option && check_grant(thd,privilege,tables))
+ goto error;
+ }
+ res=mysql_load(thd, lex->exchange, tables, lex->field_list,
+ lex->duplicates, (bool) lex->local_file, lex->lock_option);
+ break;
+ }
+ case SQLCOM_SET_OPTION:
+ {
+ uint org_options=thd->options;
+ thd->options=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;
+ 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_AUTO_COMMIT)
+ {
+ if (org_options & OPTION_AUTO_COMMIT)
+ {
+ /* We changed to auto_commit mode */
+ thd->options&= ~OPTION_BEGIN;
+ thd->server_status|= SERVER_STATUS_AUTOCOMMIT;
+ if (ha_commit(thd))
+ {
+ res= -1;
+ break;
+ }
+ }
+ else
+ thd->server_status&= ~SERVER_STATUS_AUTOCOMMIT;
+ }
+ send_ok(&thd->net);
+ break;
+ }
+ case SQLCOM_UNLOCK_TABLES:
+ if (thd->locked_tables)
+ {
+ thd->lock=thd->locked_tables;
+ thd->locked_tables=0; // Will be automaticly closed
+ }
+ 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);
+ }
+ send_ok(&thd->net);
+ break;
+ case SQLCOM_LOCK_TABLES:
+ if (thd->locked_tables)
+ {
+ thd->lock=thd->locked_tables;
+ thd->locked_tables=0; // Will be automaticly closed
+ close_thread_tables(thd);
+ }
+ if (check_lock_tables(thd,tables))
+ goto error;
+ thd->in_lock_tables=1;
+ if (!(res=open_and_lock_tables(thd,tables)))
+ {
+ thd->locked_tables=thd->lock;
+ thd->lock=0;
+ send_ok(&thd->net);
+ }
+ thd->in_lock_tables=0;
+ break;
+ case SQLCOM_CREATE_DB:
+ {
+ if (check_access(thd,CREATE_ACL,lex->name,0,1))
+ break;
+ mysql_create_db(thd,lex->name,lex->create_info.options);
+ break;
+ }
+ case SQLCOM_DROP_DB:
+ {
+ if (check_access(thd,DROP_ACL,lex->name,0,1))
+ break;
+ mysql_rm_db(thd,lex->name,lex->drop_if_exists);
+ break;
+ }
+ case SQLCOM_CREATE_FUNCTION:
+ if (check_access(thd,INSERT_ACL,"mysql",0,1))
+ break;
+#ifdef HAVE_DLOPEN
+ if (!(res = mysql_create_function(thd,&lex->udf)))
+ send_ok(&thd->net);
+#else
+ res= -1;
+#endif
+ break;
+ case SQLCOM_DROP_FUNCTION:
+ if (check_access(thd,DELETE_ACL,"mysql",0,1))
+ break;
+#ifdef HAVE_DLOPEN
+ if (!(res = mysql_drop_function(thd,lex->udf.name)))
+ send_ok(&thd->net);
+#else
+ 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 */
+
+ List_iterator <LEX_USER> user_list(lex->users_list);
+ LEX_USER *user;
+ if(thd->user)
+ 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->query,thd->query_length);
+ 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->query,thd->query_length);
+ Query_log_event qinfo(thd, thd->query);
+ mysql_bin_log.write(&qinfo);
+ }
+ }
+ break;
+ }
+ case SQLCOM_FLUSH:
+ if (check_access(thd,RELOAD_ACL,any_db))
+ goto error;
+ if (reload_acl_and_cache(lex->type))
+ send_error(&thd->net,0);
+ else
+ send_ok(&thd->net);
+ break;
+ case SQLCOM_KILL:
+ kill_one_thread(thd,lex->thread_id);
+ break;
+ case SQLCOM_SHOW_GRANTS:
+ res=0;
+ if ((thd->user && !strcmp(thd->user,lex->grant_user->user.str)) ||
+ !(check_access(thd, SELECT_ACL, "mysql")))
+ {
+ res = mysql_show_grants(thd,lex->grant_user);
+ }
+ break;
+ case SQLCOM_BEGIN:
+ thd->options|= OPTION_BEGIN;
+ thd->server_status|= SERVER_STATUS_IN_TRANS;
+ break;
+ case SQLCOM_COMMIT:
+ thd->options&= ~OPTION_BEGIN;
+ thd->server_status&= ~SERVER_STATUS_IN_TRANS;
+ if (!ha_commit(thd))
+ send_ok(&thd->net);
+ else
+ res= -1;
+ break;
+ case SQLCOM_ROLLBACK:
+ thd->options&= ~OPTION_BEGIN;
+ thd->server_status&= ~SERVER_STATUS_IN_TRANS;
+ if (!ha_rollback(thd))
+ send_ok(&thd->net);
+ else
+ res= -1;
+ break;
+ default: /* Impossible */
+ send_ok(&thd->net);
+ break;
+ }
+ thd->proc_info="query end"; // QQ
+ if (res < 0)
+ send_error(&thd->net,thd->killed ? ER_SERVER_SHUTDOWN : 0);
+
+error:
+ DBUG_VOID_RETURN;
+}
+
+
+/****************************************************************************
+** Get the user (global) and database privileges for all used tables
+** Returns true (error) if we can't get the privileges and we don't use
+** table/column grants.
+****************************************************************************/
+
+bool
+check_access(THD *thd,uint want_access,const char *db, uint *save_priv,
+ bool no_grant)
+{
+ uint db_access,dummy;
+ if (save_priv)
+ *save_priv=0;
+ else
+ save_priv= &dummy;
+
+ if (!db && !thd->db && !no_grant)
+ {
+ send_error(&thd->net,ER_NO_DB_ERROR); /* purecov: tested */
+ return TRUE; /* purecov: tested */
+ }
+
+ if ((thd->master_access & want_access) == want_access)
+ {
+ *save_priv=thd->master_access;
+ return FALSE;
+ }
+ if ((want_access & ~thd->master_access) & ~(DB_ACLS | EXTRA_ACL) ||
+ ! db && no_grant)
+ { // 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 */
+ 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 */
+ else
+ db_access=thd->db_access;
+ want_access &= ~EXTRA_ACL; // Remove SHOW attribute
+ db_access= ((*save_priv=(db_access | thd->master_access)) & want_access);
+ if (db_access == want_access ||
+ ((grant_option && !no_grant) && !(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 */
+ return TRUE; /* purecov: tested */
+}
+
+
+/*
+** Check the privilege for all used tables. Table privileges are cached
+** in the table list for GRANT checking
+*/
+
+static bool
+check_table_access(THD *thd,uint want_access,TABLE_LIST *tables)
+{
+ uint found=0,found_access=0;
+ TABLE_LIST *org_tables=tables;
+ for (; tables ; tables=tables->next)
+ {
+ if ((thd->master_access & want_access) == want_access && thd->db)
+ tables->grant.privilege= want_access;
+ else if (tables->db)
+ {
+ if (found && !grant_option) // db already checked
+ tables->grant.privilege=found_access;
+ else
+ {
+ if (check_access(thd,want_access,tables->db,&tables->grant.privilege))
+ return TRUE; // Access denied
+ found_access=tables->grant.privilege;
+ }
+ }
+ else if (check_access(thd,want_access,tables->db,&tables->grant.privilege))
+ return TRUE; // Access denied
+ }
+ if (grant_option)
+ return check_grant(thd,want_access,org_tables);
+ return FALSE;
+}
+
+
+static bool check_lock_tables(THD *thd,TABLE_LIST *tables)
+{
+ for (; tables ; tables=tables->next)
+ {
+ if (!tables->db)
+ {
+ if (!(tables->db=thd->db))
+ {
+ send_error(&thd->net,ER_NO_DB_ERROR); /* purecov: tested */
+ return TRUE; /* purecov: tested */
+ }
+ }
+ }
+ return FALSE;
+}
+
+
+/****************************************************************************
+ Check stack size; Send error if there isn't enough stack to continue
+****************************************************************************/
+
+#if STACK_DIRECTION < 0
+#define used_stack(A,B) (long) (A - B)
+#else
+#define used_stack(A,B) (long) (B - A)
+#endif
+
+bool check_stack_overrun(THD *thd,char *buf __attribute__((unused)))
+{
+ long stack_used;
+ if ((stack_used=used_stack(thd->thread_stack,(char*) &stack_used)) >=
+ (long) thread_stack_min)
+ {
+ sprintf(errbuff[0],ER(ER_STACK_OVERRUN),stack_used,thread_stack);
+ my_message(ER_STACK_OVERRUN,errbuff[0],MYF(0));
+ thd->fatal_error=1;
+ return 1;
+ }
+ return 0;
+}
+
+#define MY_YACC_INIT 1000 // Start with big alloc
+#define MY_YACC_MAX 32000 // Because of 'short'
+
+bool my_yyoverflow(short **yyss, YYSTYPE **yyvs, int *yystacksize)
+{
+ LEX *lex=current_lex;
+ int old_info=0;
+ if ((uint) *yystacksize >= MY_YACC_MAX)
+ return 1;
+ if (!lex->yacc_yyvs)
+ old_info= *yystacksize;
+ *yystacksize= set_zone((*yystacksize)*2,MY_YACC_INIT,MY_YACC_MAX);
+ if (!(lex->yacc_yyvs= (char*)
+ my_realloc((gptr) lex->yacc_yyvs,
+ *yystacksize*sizeof(**yyvs),
+ MYF(MY_ALLOW_ZERO_PTR | MY_FREE_ON_ERROR))) ||
+ !(lex->yacc_yyss= (char*)
+ my_realloc((gptr) lex->yacc_yyss,
+ *yystacksize*sizeof(**yyss),
+ MYF(MY_ALLOW_ZERO_PTR | MY_FREE_ON_ERROR))))
+ return 1;
+ if (old_info)
+ { // Copy old info from stack
+ memcpy(lex->yacc_yyss, (gptr) *yyss, old_info*sizeof(**yyss));
+ memcpy(lex->yacc_yyvs, (gptr) *yyvs, old_info*sizeof(**yyvs));
+ }
+ *yyss=(short*) lex->yacc_yyss;
+ *yyvs=(YYSTYPE*) lex->yacc_yyvs;
+ return 0;
+}
+
+
+/****************************************************************************
+ Initialize global thd variables neaded for query
+****************************************************************************/
+
+static void
+mysql_init_query(THD *thd)
+{
+ DBUG_ENTER("mysql_init_query");
+ thd->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.proc_list.first=0; // Needed by sql_select
+ thd->fatal_error=0; // Safety
+ thd->last_insert_id_used=thd->query_start_used=thd->insert_id_used=0;
+ DBUG_VOID_RETURN;
+}
+
+
+void
+mysql_parse(THD *thd,char *inBuf,uint length)
+{
+ DBUG_ENTER("mysql_parse");
+
+ 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);
+ DBUG_VOID_RETURN;
+}
+
+
+inline static void
+link_in_list(SQL_LIST *list,byte *element,byte **next)
+{
+ list->elements++;
+ (*list->next)=element;
+ list->next=next;
+ *next=0;
+}
+
+
+/*****************************************************************************
+** Store field definition for create
+** Return 0 if ok
+******************************************************************************/
+
+bool add_field_to_list(char *field_name, enum_field_types type,
+ char *length, char *decimals,
+ uint type_modifier, Item *default_value,char *change,
+ TYPELIB *interval)
+{
+ register create_field *new_field;
+ THD *thd=current_thd;
+ LEX *lex= &thd->lex;
+ uint allowed_type_modifier=0;
+ DBUG_ENTER("add_field_to_list");
+
+ if (strlen(field_name) > NAME_LEN)
+ {
+ net_printf(&thd->net, ER_TOO_LONG_IDENT, field_name); /* purecov: inspected */
+ DBUG_RETURN(1); /* purecov: inspected */
+ }
+ if (type_modifier & PRI_KEY_FLAG)
+ {
+ lex->col_list.push_back(new key_part_spec(field_name,0));
+ lex->key_list.push_back(new Key(Key::PRIMARY,NullS,
+ lex->col_list));
+ lex->col_list.empty();
+ }
+ if (type_modifier & (UNIQUE_FLAG | UNIQUE_KEY_FLAG))
+ {
+ lex->col_list.push_back(new key_part_spec(field_name,0));
+ lex->key_list.push_back(new Key(Key::UNIQUE,NullS,
+ lex->col_list));
+ lex->col_list.empty();
+ }
+
+ if (default_value && default_value->type() == Item::NULL_ITEM)
+ {
+ if ((type_modifier & (NOT_NULL_FLAG | AUTO_INCREMENT_FLAG)) ==
+ NOT_NULL_FLAG)
+ {
+ net_printf(&thd->net,ER_INVALID_DEFAULT,field_name);
+ DBUG_RETURN(1);
+ }
+ default_value=0;
+ }
+ if (!(new_field=new create_field()))
+ DBUG_RETURN(1);
+ new_field->field=0;
+ new_field->field_name=field_name;
+ new_field->def= (type_modifier & AUTO_INCREMENT_FLAG ? 0 : default_value);
+ new_field->flags= type_modifier;
+ new_field->unireg_check= (type_modifier & AUTO_INCREMENT_FLAG ?
+ Field::NEXT_NUMBER : Field::NONE);
+ new_field->decimals= decimals ? (uint) set_zone(atoi(decimals),0,
+ NOT_FIXED_DEC-1) : 0;
+ new_field->sql_type=type;
+ new_field->length=0;
+ new_field->change=change;
+ new_field->interval=0;
+ new_field->pack_length=0;
+ if (length)
+ if (!(new_field->length= (uint) atoi(length)))
+ length=0; /* purecov: inspected */
+ uint sign_len=type_modifier & UNSIGNED_FLAG ? 0 : 1;
+
+ if (new_field->length && new_field->decimals &&
+ new_field->length < new_field->decimals+2 &&
+ new_field->decimals != NOT_FIXED_DEC)
+ new_field->length=new_field->decimals+2; /* purecov: inspected */
+
+ switch (type) {
+ case FIELD_TYPE_TINY:
+ if (!length) new_field->length=3+sign_len;
+ allowed_type_modifier= AUTO_INCREMENT_FLAG;
+ break;
+ case FIELD_TYPE_SHORT:
+ if (!length) new_field->length=5+sign_len;
+ allowed_type_modifier= AUTO_INCREMENT_FLAG;
+ break;
+ case FIELD_TYPE_INT24:
+ if (!length) new_field->length=8+sign_len;
+ allowed_type_modifier= AUTO_INCREMENT_FLAG;
+ break;
+ case FIELD_TYPE_LONG:
+ if (!length) new_field->length=10+sign_len;
+ allowed_type_modifier= AUTO_INCREMENT_FLAG;
+ break;
+ case FIELD_TYPE_LONGLONG:
+ if (!length) new_field->length=20;
+ allowed_type_modifier= AUTO_INCREMENT_FLAG;
+ break;
+ case FIELD_TYPE_STRING:
+ case FIELD_TYPE_VAR_STRING:
+ case FIELD_TYPE_NULL:
+ break;
+ case FIELD_TYPE_DECIMAL:
+ if (!length)
+ new_field->length = 10; // Default length for DECIMAL
+ new_field->length+=sign_len;
+ if (new_field->decimals)
+ new_field->length++;
+ break;
+ case FIELD_TYPE_BLOB:
+ case FIELD_TYPE_TINY_BLOB:
+ case FIELD_TYPE_LONG_BLOB:
+ case FIELD_TYPE_MEDIUM_BLOB:
+ if (default_value) // Allow empty as default value
+ {
+ String str,*res;
+ res=default_value->val_str(&str);
+ if (res->length())
+ {
+ net_printf(&thd->net,ER_BLOB_CANT_HAVE_DEFAULT,field_name); /* purecov: inspected */
+ DBUG_RETURN(1); /* purecov: inspected */
+ }
+ new_field->def=0;
+ }
+ new_field->flags|=BLOB_FLAG;
+ break;
+ case FIELD_TYPE_YEAR:
+ if (!length || new_field->length != 2)
+ new_field->length=4; // Default length
+ new_field->flags|= ZEROFILL_FLAG | UNSIGNED_FLAG;
+ break;
+ case FIELD_TYPE_FLOAT:
+ /* change FLOAT(precision) to FLOAT or DOUBLE */
+ allowed_type_modifier= AUTO_INCREMENT_FLAG;
+ if (length && !decimals)
+ {
+ uint tmp_length=new_field->length;
+ if (tmp_length > PRECISION_FOR_DOUBLE)
+ {
+ net_printf(&thd->net,ER_WRONG_FIELD_SPEC,field_name);
+ DBUG_RETURN(1);
+ }
+ else if (tmp_length > PRECISION_FOR_FLOAT)
+ {
+ new_field->sql_type=FIELD_TYPE_DOUBLE;
+ new_field->length=DBL_DIG+7; // -[digits].E+###
+ }
+ else
+ new_field->length=FLT_DIG+6; // -[digits].E+##
+ new_field->decimals= NOT_FIXED_DEC;
+ break;
+ }
+ if (!length)
+ {
+ new_field->length = FLT_DIG+6;
+ new_field->decimals= NOT_FIXED_DEC;
+ }
+ break;
+ case FIELD_TYPE_DOUBLE:
+ allowed_type_modifier= AUTO_INCREMENT_FLAG;
+ if (!length)
+ {
+ new_field->length = DBL_DIG+7;
+ new_field->decimals=NOT_FIXED_DEC;
+ }
+ break;
+ case FIELD_TYPE_TIMESTAMP:
+ if (!length)
+ new_field->length= 14; // Full date YYYYMMDDHHMMSS
+ else
+ {
+ new_field->length=((new_field->length+1)/2)*2; /* purecov: inspected */
+ new_field->length= min(new_field->length,14); /* purecov: inspected */
+ }
+ new_field->flags|= ZEROFILL_FLAG | UNSIGNED_FLAG | NOT_NULL_FLAG;
+ break;
+ case FIELD_TYPE_DATE: // Old date type
+ if (protocol_version != PROTOCOL_VERSION-1)
+ new_field->sql_type=FIELD_TYPE_NEWDATE;
+ /* fall trough */
+ case FIELD_TYPE_NEWDATE:
+ new_field->length=10;
+ break;
+ case FIELD_TYPE_TIME:
+ new_field->length=10;
+ break;
+ case FIELD_TYPE_DATETIME:
+ new_field->length=19;
+ break;
+ case FIELD_TYPE_SET:
+ {
+ if (interval->count > sizeof(longlong)*8)
+ {
+ net_printf(&thd->net,ER_TOO_BIG_SET,field_name); /* purecov: inspected */
+ DBUG_RETURN(1); /* purecov: inspected */
+ }
+ new_field->pack_length=(interval->count+7)/8;
+ if (new_field->pack_length > 4)
+ new_field->pack_length=8;
+ new_field->interval=interval;
+ new_field->length=0;
+ for (const char **pos=interval->type_names; *pos ; pos++)
+ new_field->length+=strlen(*pos)+1;
+ new_field->length--;
+ set_if_smaller(new_field->length,MAX_FIELD_WIDTH-1);
+ if (default_value)
+ {
+ thd->cuted_fields=0;
+ String str,*res;
+ res=default_value->val_str(&str);
+ (void) find_set(interval,res->ptr(),res->length());
+ if (thd->cuted_fields)
+ {
+ net_printf(&thd->net,ER_INVALID_DEFAULT,field_name);
+ DBUG_RETURN(1);
+ }
+ }
+ }
+ break;
+ case FIELD_TYPE_ENUM:
+ {
+ new_field->interval=interval;
+ new_field->pack_length=interval->count < 256 ? 1 : 2; // Should be safe
+ new_field->length=strlen(interval->type_names[0]);
+ for (const char **pos=interval->type_names+1; *pos ; pos++)
+ {
+ uint length=strlen(*pos);
+ set_if_bigger(new_field->length,length);
+ }
+ set_if_smaller(new_field->length,MAX_FIELD_WIDTH-1);
+ if (default_value)
+ {
+ String str,*res;
+ res=default_value->val_str(&str);
+ if (!find_enum(interval,res->ptr(),res->length()))
+ {
+ net_printf(&thd->net,ER_INVALID_DEFAULT,field_name);
+ DBUG_RETURN(1);
+ }
+ }
+ break;
+ }
+ }
+
+ if (new_field->length >= MAX_FIELD_WIDTH ||
+ (!new_field->length && !(new_field->flags & BLOB_FLAG) &&
+ type != FIELD_TYPE_STRING))
+ {
+ net_printf(&thd->net,ER_TOO_BIG_FIELDLENGTH,field_name,
+ MAX_FIELD_WIDTH-1); /* purecov: inspected */
+ DBUG_RETURN(1); /* purecov: inspected */
+ }
+ type_modifier&= AUTO_INCREMENT_FLAG;
+ if ((~allowed_type_modifier) & type_modifier)
+ {
+ net_printf(&thd->net,ER_WRONG_FIELD_SPEC,field_name);
+ DBUG_RETURN(1);
+ }
+ if (!new_field->pack_length)
+ new_field->pack_length=calc_pack_length(new_field->sql_type ==
+ FIELD_TYPE_VAR_STRING ?
+ FIELD_TYPE_STRING :
+ new_field->sql_type,
+ new_field->length);
+ lex->create_list.push_back(new_field);
+ lex->last_field=new_field;
+ DBUG_RETURN(0);
+}
+
+/* Store position for column in ALTER TABLE .. ADD column */
+
+void store_position_for_column(const char *name)
+{
+ current_lex->last_field->after=my_const_cast(char*) (name);
+}
+
+bool
+add_proc_to_list(Item *item)
+{
+ ORDER *order;
+ Item **item_ptr;
+
+ if (!(order = (ORDER *) sql_alloc(sizeof(ORDER)+sizeof(Item*))))
+ return 1;
+ item_ptr = (Item**) (order+1);
+ *item_ptr= item;
+ order->item=item_ptr;
+ order->free_me=0;
+ link_in_list(&current_lex->proc_list,(byte*) order,(byte**) &order->next);
+ return 0;
+}
+
+
+/* Fix escaping of _, % and \ in database and table names (for ODBC) */
+
+static void remove_escape(char *name)
+{
+ char *to;
+#ifdef USE_MB
+ char *strend=name+strlen(name);
+#endif
+ for (to=name; *name ; name++)
+ {
+#ifdef USE_MB
+ int l;
+/* if ((l = ismbchar(name, name+MBMAXLEN))) { Wei He: I think it's wrong */
+ if (use_mb(default_charset_info) &&
+ (l = my_ismbchar(default_charset_info, name, strend)))
+ {
+ while (l--)
+ *to++ = *name++;
+ name--;
+ continue;
+ }
+#endif
+ if (*name == '\\' && name[1])
+ name++; // Skipp '\\'
+ *to++= *name;
+ }
+ *to=0;
+}
+
+/****************************************************************************
+** save order by and tables in own lists
+****************************************************************************/
+
+
+bool add_to_list(SQL_LIST &list,Item *item,bool asc)
+{
+ ORDER *order;
+ Item **item_ptr;
+ DBUG_ENTER("add_to_list");
+ if (!(order = (ORDER *) sql_alloc(sizeof(ORDER)+sizeof(Item*))))
+ DBUG_RETURN(1);
+ item_ptr = (Item**) (order+1);
+ *item_ptr=item;
+ order->item= item_ptr;
+ order->asc = asc;
+ order->free_me=0;
+ order->used=0;
+ link_in_list(&list,(byte*) order,(byte**) &order->next);
+ DBUG_RETURN(0);
+}
+
+
+TABLE_LIST *add_table_to_list(Table_ident *table, LEX_STRING *alias,
+ thr_lock_type flags,
+ List<String> *use_index,
+ List<String> *ignore_index)
+{
+ register TABLE_LIST *ptr;
+ THD *thd=current_thd;
+ char *alias_str;
+ const char *current_db;
+ DBUG_ENTER("add_table_to_list");
+
+ if (!table)
+ DBUG_RETURN(0); // End of memory
+ alias_str= alias ? alias->str : table->table.str;
+ if (table->table.length > NAME_LEN ||
+ table->db.str && table->db.length > NAME_LEN ||
+ check_table_name(table->table.str,table->table.length))
+ {
+ net_printf(&thd->net,ER_WRONG_TABLE_NAME,table->table.str);
+ DBUG_RETURN(0);
+ }
+
+#ifdef FN_LOWER_CASE
+ if (!alias) /* Alias is case sensitive */
+ if (!(alias_str=sql_strmake(alias_str,table->table.length)))
+ DBUG_RETURN(0);
+ if (lower_case_table_names)
+ casedn_str(table->table.str);
+#endif
+ if (!(ptr = (TABLE_LIST *) sql_calloc(sizeof(TABLE_LIST))))
+ DBUG_RETURN(0); /* purecov: inspected */
+ ptr->db= table->db.str;
+ ptr->real_name=table->table.str;
+ ptr->name=alias_str;
+ ptr->lock_type=flags;
+ if (use_index)
+ ptr->use_index=(List<String> *) sql_memdup((gptr) use_index,
+ sizeof(*use_index));
+ if (ignore_index)
+ ptr->ignore_index=(List<String> *) sql_memdup((gptr) ignore_index,
+ sizeof(*ignore_index));
+
+ /* check that used name is unique */
+ current_db=thd->db ? thd->db : "";
+ for (TABLE_LIST *tables=(TABLE_LIST*) thd->lex.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))
+ {
+ 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);
+ DBUG_RETURN(ptr);
+}
+
+void add_join_on(TABLE_LIST *b,Item *expr)
+{
+ b->on_expr=expr;
+}
+
+
+void add_join_natural(TABLE_LIST *a,TABLE_LIST *b)
+{
+ b->natural_join=a;
+}
+
+ /* Check if name is used in table list */
+
+static bool check_dup(THD *thd,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))
+ return 1;
+ return 0;
+}
+
+bool reload_acl_and_cache(uint options)
+{
+ bool result=0;
+
+ select_errors=0; /* Write if more errors */
+ mysql_log.flush(); // Flush log
+ if (options & REFRESH_GRANT)
+ {
+ acl_reload();
+ grant_reload();
+ }
+ if (options & REFRESH_LOG)
+ {
+ mysql_log.new_file();
+ mysql_update_log.new_file();
+ mysql_bin_log.new_file();
+ mysql_slow_log.new_file();
+ if (ha_flush_logs())
+ result=1;
+ }
+ if (options & (REFRESH_TABLES | REFRESH_READ_LOCK))
+ {
+ if ((options & REFRESH_READ_LOCK) && ! current_thd->global_read_lock)
+ {
+ current_thd->global_read_lock=1;
+ thread_safe_increment(global_read_lock,&LOCK_open);
+ }
+ result=close_cached_tables((options & REFRESH_FAST) ? 0 : 1);
+ }
+ if (options & REFRESH_HOSTS)
+ hostname_cache_refresh();
+ if (options & REFRESH_STATUS)
+ refresh_status();
+ if (options & REFRESH_THREADS)
+ flush_thread_cache();
+ if (options & REFRESH_MASTER)
+ reset_master();
+ if (options & REFRESH_SLAVE)
+ reset_slave();
+
+ return result;
+}
+
+
+static void kill_one_thread(THD *thd, ulong id)
+{
+ VOID(pthread_mutex_lock(&LOCK_thread_count)); // For unlink from list
+ I_List_iterator<THD> it(threads);
+ THD *tmp;
+ uint error=ER_NO_SUCH_THREAD;
+ while ((tmp=it++))
+ {
+ if (tmp->thread_id == id)
+ {
+ if ((thd->master_access & PROCESS_ACL) ||
+ !strcmp(thd->user,tmp->user))
+ {
+ thr_alarm_kill(tmp->real_id);
+ tmp->killed=1;
+ error=0;
+ if (tmp->mysys_var)
+ {
+ pthread_mutex_lock(&tmp->mysys_var->mutex);
+ if (!tmp->system_thread) // Don't abort locks
+ tmp->mysys_var->abort=1;
+ if (tmp->mysys_var->current_mutex)
+ {
+ 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);
+ }
+ }
+ else
+ error=ER_KILL_DENIED_ERROR;
+ break; // Found thread
+ }
+ }
+ VOID(pthread_mutex_unlock(&LOCK_thread_count));
+ if (!error)
+ send_ok(&thd->net);
+ else
+ net_printf(&thd->net,error,id);
+}
+
+/* Clear most status variables */
+
+static void refresh_status(void)
+{
+ pthread_mutex_lock(&THR_LOCK_keycache);
+ pthread_mutex_lock(&LOCK_status);
+ for (struct show_var_st *ptr=status_vars; ptr->name; ptr++)
+ {
+ if (ptr->type == SHOW_LONG)
+ *(ulong*) ptr->value=0;
+ }
+ pthread_mutex_unlock(&LOCK_status);
+ pthread_mutex_unlock(&THR_LOCK_keycache);
+}
+
+static int start_slave(THD* thd , bool net_report)
+{
+ if(!thd) thd = current_thd;
+ NET* net = &thd->net;
+ const char* err = 0;
+ if(check_access(thd, PROCESS_ACL, any_db))
+ return 1;
+ pthread_mutex_lock(&LOCK_slave);
+ if(!slave_running)
+ if(master_host)
+ {
+ pthread_t hThread;
+ if(pthread_create(&hThread, &connection_attrib, handle_slave, 0))
+ {
+ err = "cannot create slave thread";
+ }
+ }
+ else
+ err = "Master host not set";
+ else
+ err = "Slave already running";
+
+ pthread_mutex_unlock(&LOCK_slave);
+ if(err)
+ {
+ if(net_report) send_error(net, 0, err);
+ return 1;
+ }
+ else if(net_report)
+ send_ok(net);
+
+ return 0;
+}
+
+static int stop_slave(THD* thd, bool net_report )
+{
+ if(!thd) thd = current_thd;
+ NET* net = &thd->net;
+ const char* err = 0;
+
+ if(check_access(thd, PROCESS_ACL, any_db))
+ return 1;
+
+ pthread_mutex_lock(&LOCK_slave);
+ if (slave_running)
+ {
+ abort_slave = 1;
+ thr_alarm_kill(slave_real_id);
+ // 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";
+ pthread_cond_wait(&COND_slave_stopped, &LOCK_slave);
+ }
+ else
+ err = "Slave is not running";
+
+ pthread_mutex_unlock(&LOCK_slave);
+ thd->proc_info = 0;
+
+ if(err)
+ {
+ if(net_report) send_error(net, 0, err);
+ return 1;
+ }
+ else if(net_report)
+ send_ok(net);
+
+ return 0;
+}
+
+static void reset_slave()
+{
+ MY_STAT stat_area;
+ char fname[FN_REFLEN];
+ bool slave_was_running = slave_running;
+
+ if(slave_running)
+ stop_slave(0,0);
+
+ 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);
+}
+
+static int change_master(THD* thd)
+{
+ bool slave_was_running;
+ // kill slave thread
+ pthread_mutex_lock(&LOCK_slave);
+ if((slave_was_running = slave_running))
+ {
+ abort_slave = 1;
+ thr_alarm_kill(slave_real_id);
+ thd->proc_info = "waiting for slave to die";
+ pthread_cond_wait(&COND_slave_stopped, &LOCK_slave); // wait until done
+ }
+ pthread_mutex_unlock(&LOCK_slave);
+ thd->proc_info = "changing master";
+ LEX_MASTER_INFO* lex_mi = &thd->lex.mi;
+
+ 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 = 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)
+ glob_mi.pos = lex_mi->pos;
+
+ 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);
+ thd->proc_info = "starting slave";
+ if(slave_was_running)
+ start_slave(0,0);
+ thd->proc_info = 0;
+
+ send_ok(&thd->net);
+ return 0;
+}
+
+static void reset_master()
+{
+ if(!mysql_bin_log.is_open())
+ {
+ my_error(ER_FLUSH_MASTER_BINLOG_CLOSED, MYF(ME_BELL+ME_WAITTANG));
+ return;
+ }
+
+ LOG_INFO linfo;
+
+ if(mysql_bin_log.find_first_log(&linfo, ""))
+ return;
+
+ for(;;)
+ {
+ my_delete(linfo.log_file_name, MYF(MY_WME));
+ if(mysql_bin_log.find_next_log(&linfo))
+ break;
+ }
+ mysql_bin_log.close(1); // exiting close
+ my_delete(mysql_bin_log.get_index_fname(), MYF(MY_WME));
+
+ char tmp[FN_REFLEN];
+ if (!opt_bin_logname || !opt_bin_logname[0])
+ {
+ char hostname[FN_REFLEN];
+ if (gethostname(hostname,sizeof(hostname)-4) < 0)
+ strmov(hostname,"mysql");
+
+ strnmov(tmp,hostname,FN_REFLEN-5);
+ strmov(strcend(tmp,'.'),"-bin");
+ opt_bin_logname=tmp;
+ }
+
+ mysql_bin_log.open(opt_bin_logname,LOG_BIN);
+
+}
+
+int show_binlog_info(THD* thd)
+{
+ DBUG_ENTER("show_binlog_info");
+ List<Item> field_list;
+ field_list.push_back(new Item_empty_string("File", FN_REFLEN));
+ field_list.push_back(new Item_empty_string("Position",20));
+ 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))
+ 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);
+ net_store_data(packet, li.log_file_name);
+ 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);
+ }
+
+ if(my_net_write(&thd->net, (char*)thd->packet.ptr(), packet->length()))
+ DBUG_RETURN(-1);
+
+ send_eof(&thd->net);
+ DBUG_RETURN(0);
+}
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
new file mode 100644
index 00000000000..030b6f6fb5c
--- /dev/null
+++ b/sql/sql_select.cc
@@ -0,0 +1,6408 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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_select and join optimization */
+
+#ifdef __GNUC__
+#pragma implementation // gcc: Class implementation
+#endif
+
+#include "mysql_priv.h"
+#include "sql_select.h"
+#include <m_ctype.h>
+#include <hash.h>
+#include <ft_global.h>
+#include <assert.h>
+
+const char *join_type_str[]={ "UNKNOWN","system","const","eq_ref","ref",
+ "MAYBE_REF","ALL","range","index" };
+
+static bool make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds,
+ DYNAMIC_ARRAY *keyuse,List<Item_func_match> &ftfuncs);
+static bool update_ref_and_keys(DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab,
+ uint tables,COND *conds,table_map table_map,
+ List<Item_func_match> &ftfuncs);
+static int sort_keyuse(KEYUSE *a,KEYUSE *b);
+static void set_position(JOIN *join,uint index,JOIN_TAB *table,KEYUSE *key);
+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,
+ KEY_PART_INFO *key_part, char *key_buff,
+ uint maybe_null);
+static bool make_simple_join(JOIN *join,TABLE *tmp_table);
+static bool make_join_select(JOIN *join,SQL_SELECT *select,COND *item);
+static void make_join_readinfo(JOIN *join,uint options);
+static void join_free(JOIN *join);
+static bool only_eq_ref_tables(JOIN *join,ORDER *order,table_map tables);
+static void update_depend_map(JOIN *join);
+static void update_depend_map(JOIN *join, ORDER *order);
+static ORDER *remove_const(JOIN *join,ORDER *first_order,COND *cond,
+ bool *simple_order);
+static int return_zero_rows(select_result *res,TABLE_LIST *tables,
+ List<Item> &fields, bool send_row,
+ uint select_options, const char *info,
+ Item *having, Procedure *proc);
+static COND *optimize_cond(COND *conds,Item::cond_result *cond_value);
+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);
+static int do_select(JOIN *join,List<Item> *fields,TABLE *tmp_table,
+ Procedure *proc);
+static int sub_select_cache(JOIN *join,JOIN_TAB *join_tab,bool end_of_records);
+static int sub_select(JOIN *join,JOIN_TAB *join_tab,bool end_of_records);
+static int flush_cached_records(JOIN *join,JOIN_TAB *join_tab,bool skipp_last);
+static int end_send(JOIN *join, JOIN_TAB *join_tab, bool end_of_records);
+static int end_send_group(JOIN *join, JOIN_TAB *join_tab,bool end_of_records);
+static int end_write(JOIN *join, JOIN_TAB *join_tab, bool end_of_records);
+static int end_update(JOIN *join, JOIN_TAB *join_tab, bool end_of_records);
+static int end_unique_update(JOIN *join,JOIN_TAB *join_tab,
+ bool end_of_records);
+static int end_write_group(JOIN *join, JOIN_TAB *join_tab,
+ bool end_of_records);
+static int test_if_group_changed(List<Item_buff> &list);
+static int join_read_const_tables(JOIN *join);
+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_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_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,
+ table_map used_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);
+static int create_sort_index(JOIN_TAB *tab,ORDER *order,ha_rows select_limit);
+static int remove_duplicates(JOIN *join,TABLE *entry,List<Item> &fields);
+static int remove_dup_with_compare(THD *thd, TABLE *entry, Field **field,
+ ulong offset);
+static int remove_dup_with_hash_index(THD *thd, TABLE *table,
+ uint field_count, Field **first_field,
+ ulong key_length);
+static SORT_FIELD * make_unireg_sortorder(ORDER *order, uint *length);
+static int join_init_cache(THD *thd,JOIN_TAB *tables,uint table_count);
+static ulong used_blob_length(CACHE_FIELD **ptr);
+static bool store_record_in_cache(JOIN_CACHE *cache);
+static void reset_cache(JOIN_CACHE *cache);
+static void read_cached_record(JOIN_TAB *tab);
+static bool cmp_buffer_with_ref(JOIN_TAB *tab);
+static int setup_order(THD *thd,TABLE_LIST *tables, List<Item> &fields,
+ List <Item> &all_fields, ORDER *order);
+static int setup_group(THD *thd,TABLE_LIST *tables,List<Item> &fields,
+ List<Item> &all_fields, ORDER *order, bool *hidden);
+static bool setup_new_fields(THD *thd,TABLE_LIST *tables,List<Item> &fields,
+ List<Item> &all_fields,ORDER *new_order);
+static ORDER *create_distinct_group(ORDER *order, List<Item> &fields);
+static bool test_if_subpart(ORDER *a,ORDER *b);
+static TABLE *get_sort_by_table(ORDER *a,ORDER *b,TABLE_LIST *tables);
+static void calc_group_buffer(JOIN *join,ORDER *group);
+static bool alloc_group_fields(JOIN *join,ORDER *group);
+static bool make_sum_func_list(JOIN *join,List<Item> &fields);
+static bool change_to_use_tmp_fields(List<Item> &func);
+static bool change_refs_to_tmp_fields(THD *thd, List<Item> &func);
+static void init_tmptable_sum_functions(Item_sum **func);
+static void update_tmptable_sum_func(Item_sum **func,TABLE *tmp_table);
+static void copy_sum_funcs(Item_sum **func_ptr);
+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);
+static void describe_info(const char *info);
+
+/*****************************************************************************
+** check fields, find best join, do the select and output fields.
+** mysql_select assumes that all tables are allready opened
+*****************************************************************************/
+
+int
+mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
+ List<Item_func_match> &ftfuncs,
+ ORDER *order, ORDER *group,Item *having,ORDER *proc_param,
+ uint select_options,select_result *result)
+{
+ TABLE *tmp_table;
+ int error,tmp;
+ bool need_tmp,hidden_group_fields;
+ bool simple_order,simple_group,no_order;
+ Item::cond_result cond_value;
+ SQL_SELECT *select;
+ DYNAMIC_ARRAY keyuse;
+ JOIN join;
+ Procedure *procedure;
+ List<Item> all_fields(fields);
+ bool select_distinct;
+ DBUG_ENTER("mysql_select");
+
+ /* Check that all tables, fields, conds and order are ok */
+
+ select_distinct=test(select_options & SELECT_DISTINCT);
+ tmp_table=0;
+ select=0;
+ no_order=0;
+ bzero((char*) &keyuse,sizeof(keyuse));
+ thd->proc_info="init";
+
+ if (setup_fields(thd,tables,fields,1,&all_fields) ||
+ setup_conds(thd,tables,&conds) ||
+ setup_order(thd,tables,fields,all_fields,order) ||
+ setup_group(thd,tables,fields,all_fields,group,&hidden_group_fields) ||
+ setup_ftfuncs(thd,tables,ftfuncs))
+ DBUG_RETURN(-1); /* purecov: inspected */
+
+ if (having)
+ {
+ thd->where="having clause";
+ thd->allow_sum_func=1;
+ if (having->fix_fields(thd,tables) || thd->fatal_error)
+ DBUG_RETURN(-1); /* purecov: inspected */
+ if (having->with_sum_func)
+ having->split_sum_func(all_fields);
+ }
+ /*
+ Check if one one uses a not constant column with group functions
+ and no GROUP BY.
+ TODO: Add check of calculation of GROUP functions and fields:
+ SELECT COUNT(*)+table.col1 from table1;
+ */
+ join.table=0;
+ join.tables=0;
+ {
+ if (!group)
+ {
+ uint flag=0;
+ List_iterator<Item> it(fields);
+ Item *item;
+ while ((item= it++))
+ {
+ if (item->with_sum_func)
+ flag|=1;
+ else if (!item->const_item())
+ flag|=2;
+ }
+ if (flag == 3)
+ {
+ my_error(ER_MIX_OF_GROUP_FUNC_AND_FIELDS,MYF(0));
+ DBUG_RETURN(-1);
+ }
+ }
+ TABLE_LIST *table;
+ for (table=tables ; table ; table=table->next)
+ join.tables++;
+ }
+ procedure=setup_procedure(thd,proc_param,result,fields,&error);
+ if (error)
+ DBUG_RETURN(-1); /* purecov: inspected */
+ if (procedure)
+ {
+ if (setup_new_fields(thd,tables,fields,all_fields,procedure->param_fields))
+ { /* purecov: inspected */
+ delete procedure; /* purecov: inspected */
+ DBUG_RETURN(-1); /* purecov: inspected */
+ }
+ if (procedure->group)
+ {
+ if (!test_if_subpart(procedure->group,group))
+ { /* purecov: inspected */
+ my_message(0,"Can't handle procedures with differents groups yet",
+ MYF(0)); /* purecov: inspected */
+ delete procedure; /* purecov: inspected */
+ DBUG_RETURN(-1); /* purecov: inspected */
+ }
+ }
+#ifdef NOT_NEEDED
+ else if (!group && procedure->flags & PROC_GROUP)
+ {
+ my_message(0,"Select must have a group with this procedure",MYF(0));
+ delete procedure;
+ DBUG_RETURN(-1);
+ }
+#endif
+ if (order && (procedure->flags & PROC_NO_SORT))
+ { /* purecov: inspected */
+ my_message(0,"Can't use order with this procedure",MYF(0)); /* purecov: inspected */
+ delete procedure; /* purecov: inspected */
+ DBUG_RETURN(-1); /* purecov: inspected */
+ }
+ }
+
+ /* Init join struct */
+ join.thd=thd;
+ join.lock=thd->lock;
+ join.join_tab=0;
+ join.tmp_table_param.copy_field=0;
+ join.sum_funcs=0;
+ join.send_records=0L;
+ join.tmp_table_param.end_write_records= HA_POS_ERROR;
+ join.first_record=join.sort_and_group=0;
+ join.select_options=select_options;
+ join.result=result;
+ count_field_types(&join.tmp_table_param,all_fields);
+ join.const_tables=0;
+ join.having=0;
+ join.group= group != 0;
+
+#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));
+ delete procedure;
+ DBUG_RETURN(-1);
+ }
+#endif
+ if (!procedure && result->prepare(fields))
+ { /* purecov: inspected */
+ DBUG_RETURN(-1); /* purecov: inspected */
+ }
+
+#ifdef HAVE_REF_TO_FIELDS // Not done yet
+ /* Add HAVING to WHERE if possible */
+ if (having && !group && ! join.sum_func_count)
+ {
+ if (!conds)
+ {
+ conds=having;
+ having=0;
+ }
+ else if ((conds=new Item_cond_and(conds,having)))
+ {
+ conds->fix_fields(thd,tables);
+ conds->change_ref_to_fields(thd,tables);
+ having=0;
+ }
+ }
+#endif
+
+ conds=optimize_cond(conds,&cond_value);
+ if (thd->fatal_error) // Out of memory
+ {
+ delete procedure;
+ DBUG_RETURN(0);
+ }
+ 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",join.having,
+ procedure);
+ delete procedure;
+ DBUG_RETURN(error);
+ }
+
+ /* Optimize count(*), min() and max() */
+ if (tables && join.tmp_table_param.sum_func_count && ! group)
+ {
+ int res;
+ if ((res=opt_sum_query(tables, all_fields, conds)))
+ {
+ if (res < 0)
+ {
+ error=return_zero_rows(result, tables, fields, !group,
+ select_options,"No matching min/max row",
+ join.having,procedure);
+ delete procedure;
+ DBUG_RETURN(error);
+ }
+ if (select_options & SELECT_DESCRIBE)
+ {
+ describe_info("Select tables optimized away");
+ delete procedure;
+ DBUG_RETURN(0);
+ }
+ tables=0; // All tables resolved
+ }
+ }
+ if (!tables)
+ { // Only test of functions
+ error=0;
+ if (select_options & SELECT_DESCRIBE)
+ describe_info("No tables used");
+ else
+ {
+ result->send_fields(fields,1);
+ if (!having || having->val_int())
+ {
+ if (result->send_data(fields))
+ {
+ result->send_error(0,NullS); /* purecov: inspected */
+ error=1;
+ }
+ else
+ error=(int) result->send_eof();
+ }
+ else
+ error=(int) result->send_eof();
+ }
+ delete procedure;
+ DBUG_RETURN(0);
+ }
+
+ error = -1;
+ join.sort_by_table=get_sort_by_table(order,group,tables);
+
+ /* Calculate how to do the join */
+ thd->proc_info="statistics";
+ if (make_join_statistics(&join,tables,conds,&keyuse,ftfuncs) ||
+ 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))
+ {
+ error=return_zero_rows(result,tables,fields,
+ join.tmp_table_param.sum_func_count != 0 &&
+ !group,0,"",join.having,procedure);
+ goto err;
+ }
+ if (!(thd->options & OPTION_BIG_SELECTS) &&
+ join.best_read > (double) thd->max_join_size &&
+ !(select_options & SELECT_DESCRIBE))
+ { /* purecov: inspected */
+ result->send_error(ER_TOO_BIG_SELECT,ER(ER_TOO_BIG_SELECT)); /* purecov: inspected */
+ error= 1; /* purecov: inspected */
+ goto err; /* purecov: inspected */
+ }
+ if (join.const_tables && !thd->locked_tables)
+ mysql_unlock_some_tables(thd, join.table,join.const_tables);
+ select=make_select(*join.table, join.const_table_map,
+ join.const_table_map,conds,&error);
+ if (error)
+ { /* purecov: inspected */
+ error= -1; /* purecov: inspected */
+ goto err; /* purecov: inspected */
+ }
+ 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",
+ join.having,procedure);
+ goto err;
+ }
+
+ error= -1; /* if goto err */
+
+ /* Optimize distinct away if possible */
+ order=remove_const(&join,order,conds,&simple_order);
+ if (group || join.tmp_table_param.sum_func_count)
+ {
+ if (! hidden_group_fields)
+ select_distinct=0;
+ }
+ else if (select_distinct && join.tables - join.const_tables == 1 &&
+ (order || thd->select_limit == HA_POS_ERROR))
+ {
+ if ((group=create_distinct_group(order,fields)))
+ {
+ select_distinct=0;
+ no_order= !order;
+ join.group=1; // For end_write_group
+ }
+ else if (thd->fatal_error) // End of memory
+ goto err;
+ }
+ group=remove_const(&join,group,conds,&simple_group);
+ if (!group && join.group)
+ {
+ order=0; // The output has only one row
+ simple_order=1;
+ }
+
+ calc_group_buffer(&join,group);
+ join.send_group_parts=join.tmp_table_param.group_parts; /* Save org parts */
+ if (procedure && procedure->group)
+ {
+ group=procedure->group=remove_const(&join,procedure->group,conds,
+ &simple_group);
+ calc_group_buffer(&join,group);
+ }
+
+ if (test_if_subpart(group,order) ||
+ (!group && join.tmp_table_param.sum_func_count))
+ order=0;
+
+ // Can't use sort on head table if using cache
+ if (join.full_join)
+ {
+ if (group)
+ simple_group=0;
+ if (order)
+ simple_order=0;
+ }
+
+ need_tmp= (join.const_tables != join.tables &&
+ ((select_distinct || !simple_order || !simple_group) ||
+ (group && order) ||
+ test(select_options & OPTION_BUFFER_RESULT)));
+
+ make_join_readinfo(&join,
+ (select_options & SELECT_DESCRIBE) | SELECT_USE_CACHE);
+ DBUG_EXECUTE("info",TEST_join(&join););
+ /*
+ Because filesort always does a full table scan or a quick range scan
+ we must add the removed reference to the select for the table.
+ We only need to do this when we have a simple_order or simple_group
+ as in other cases the join is done before the sort.
+ */
+ if ((order || group) && join.join_tab[join.const_tables].type != JT_ALL &&
+ (order && simple_order || group && simple_group))
+ {
+ if (add_ref_to_table_cond(thd,&join.join_tab[join.const_tables]))
+ goto err;
+ }
+
+ if (!(select_options & SELECT_BIG_RESULT) &&
+ ((group && join.const_tables != join.tables &&
+ !test_if_skip_sort_order(&join.join_tab[join.const_tables], group,
+ HA_POS_ERROR)) ||
+ select_distinct) &&
+ join.tmp_table_param.quick_group && !procedure)
+ {
+ need_tmp=1; simple_order=simple_group=0; // Force tmp table without sort
+ }
+
+ if (select_options & SELECT_DESCRIBE)
+ {
+ if (!order && !no_order)
+ order=group;
+ if (order &&
+ (join.const_tables == join.tables ||
+ test_if_skip_sort_order(&join.join_tab[join.const_tables], order,
+ (having || group ||
+ join.const_tables != join.tables - 1) ?
+ HA_POS_ERROR : thd->select_limit)))
+ order=0;
+ select_describe(&join,need_tmp,
+ (order != 0 &&
+ (!need_tmp || order != group || simple_group)));
+ error=0;
+ goto err;
+ }
+
+ /* Create a tmp table if distinct or if the sort is too complicated */
+ if (need_tmp)
+ {
+ DBUG_PRINT("info",("Creating tmp table"));
+ thd->proc_info="Creating tmp table";
+
+ if (!(tmp_table =
+ create_tmp_table(thd,&join.tmp_table_param,all_fields,
+ ((!simple_group && !procedure &&
+ !(test_flags & TEST_NO_KEY_GROUP)) ?
+ group : (ORDER*) 0),
+ group ? 0 : select_distinct,
+ group && simple_group,
+ order == 0,
+ join.select_options)))
+ goto err; /* purecov: inspected */
+
+ if (having && (join.sort_and_group || (tmp_table->distinct && !group)))
+ join.having=having;
+
+ /* if group or order on first table, sort first */
+ if (group && simple_group)
+ {
+ DBUG_PRINT("info",("Sorting for group"));
+ thd->proc_info="Sorting for group";
+ if (create_sort_index(&join.join_tab[join.const_tables],group,
+ HA_POS_ERROR) ||
+ make_sum_func_list(&join,all_fields) ||
+ alloc_group_fields(&join,group))
+ goto err;
+ group=0;
+ }
+ else
+ {
+ if (make_sum_func_list(&join,all_fields))
+ goto err;
+ if (!group && ! tmp_table->distinct && order && simple_order)
+ {
+ DBUG_PRINT("info",("Sorting for order"));
+ thd->proc_info="Sorting for order";
+ if (create_sort_index(&join.join_tab[join.const_tables],order,
+ HA_POS_ERROR))
+ goto err; /* purecov: inspected */
+ order=0;
+ }
+ }
+ thd->proc_info="Copying to tmp table";
+ if (do_select(&join,(List<Item> *) 0,tmp_table,0))
+ goto err; /* purecov: inspected */
+ if (join.having)
+ join.having=having=0; // Allready done
+
+ /* Change sum_fields reference to calculated fields in tmp_table */
+ if (join.sort_and_group || tmp_table->group)
+ {
+ if (change_to_use_tmp_fields(all_fields))
+ goto err;
+ join.tmp_table_param.field_count+=join.tmp_table_param.sum_func_count+
+ join.tmp_table_param.func_count;
+ join.tmp_table_param.sum_func_count=join.tmp_table_param.func_count=0;
+ }
+ else
+ {
+ if (change_refs_to_tmp_fields(thd,all_fields))
+ goto err;
+ join.tmp_table_param.field_count+=join.tmp_table_param.func_count;
+ join.tmp_table_param.func_count=0;
+ }
+ if (procedure)
+ procedure->update_refs();
+ if (tmp_table->group)
+ { // Already grouped
+ if (!order && !no_order)
+ order=group; /* order by group */
+ group=0;
+ }
+
+ /*
+ ** If we have different sort & group then we must sort the data by group
+ ** and copy it to another tmp table
+ */
+
+ if (group && (!test_if_subpart(group,order) || select_distinct))
+ { /* Must copy to another table */
+ TABLE *tmp_table2;
+ DBUG_PRINT("info",("Creating group table"));
+
+ /* Free first data from old join */
+ join_free(&join);
+ if (make_simple_join(&join,tmp_table))
+ goto err;
+ calc_group_buffer(&join,group);
+ count_field_types(&join.tmp_table_param,all_fields);
+
+ /* group data to new table */
+ if (!(tmp_table2 = create_tmp_table(thd,&join.tmp_table_param,all_fields,
+ (ORDER*) 0, 0 , 1, 0,
+ join.select_options)))
+ goto err; /* purecov: inspected */
+ if (group)
+ {
+ thd->proc_info="Creating sort index";
+ if (create_sort_index(join.join_tab,group,HA_POS_ERROR) ||
+ alloc_group_fields(&join,group))
+ {
+ free_tmp_table(thd,tmp_table2); /* purecov: inspected */
+ goto err; /* purecov: inspected */
+ }
+ group=0;
+ }
+ thd->proc_info="Copying to group table";
+ if (make_sum_func_list(&join,all_fields) ||
+ do_select(&join,(List<Item> *) 0,tmp_table2,0))
+ {
+ free_tmp_table(thd,tmp_table2);
+ goto err; /* purecov: inspected */
+ }
+ end_read_record(&join.join_tab->read_record);
+ free_tmp_table(thd,tmp_table);
+ join.const_tables=join.tables; // Mark free for join_free()
+ tmp_table=tmp_table2;
+ join.join_tab[0].table=0; // Table is freed
+
+ if (change_to_use_tmp_fields(all_fields)) // No sum funcs anymore
+ goto err;
+ join.tmp_table_param.field_count+=join.tmp_table_param.sum_func_count;
+ join.tmp_table_param.sum_func_count=0;
+ }
+
+ if (tmp_table->distinct)
+ select_distinct=0; /* Each row is uniq */
+
+ join_free(&join); /* Free quick selects */
+ if (select_distinct && ! group)
+ {
+ thd->proc_info="Removing duplicates";
+ if (remove_duplicates(&join,tmp_table,fields))
+ goto err; /* purecov: inspected */
+ select_distinct=0;
+ }
+ tmp_table->reginfo.lock_type=TL_UNLOCK;
+ if (make_simple_join(&join,tmp_table))
+ goto err;
+ calc_group_buffer(&join,group);
+ count_field_types(&join.tmp_table_param,all_fields);
+ }
+ if (procedure)
+ {
+ if (procedure->change_columns(fields) ||
+ result->prepare(fields))
+ goto err;
+ count_field_types(&join.tmp_table_param,all_fields);
+ }
+ if (join.group || join.tmp_table_param.sum_func_count ||
+ (procedure && (procedure->flags & PROC_GROUP)))
+ {
+ alloc_group_fields(&join,group);
+ setup_copy_fields(&join.tmp_table_param,all_fields);
+ if (make_sum_func_list(&join,all_fields) || thd->fatal_error)
+ goto err; /* purecov: inspected */
+ }
+ if (group || order)
+ {
+ DBUG_PRINT("info",("Sorting for send_fields"));
+ thd->proc_info="Sorting result";
+ /* If we have already done the group, add HAVING to sorted table */
+ if (having && ! group && ! join.sort_and_group)
+ {
+ 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) ?
+ HA_POS_ERROR : thd->select_limit))
+ goto err; /* purecov: inspected */
+ }
+ join.having=having; // Actually a parameter
+ thd->proc_info="Sending data";
+ error=do_select(&join,&fields,NULL,procedure);
+
+err:
+ thd->proc_info="end";
+ join.lock=0; // It's faster to unlock later
+ join_free(&join);
+ thd->proc_info="end2"; // QQ
+ if (tmp_table)
+ free_tmp_table(thd,tmp_table);
+ thd->proc_info="end3"; // QQ
+ delete select;
+ delete_dynamic(&keyuse);
+ delete procedure;
+ thd->proc_info="end4"; // QQ
+ DBUG_RETURN(error);
+}
+
+/*****************************************************************************
+** Create JOIN_TABS, make a guess about the table types,
+** Approximate how many records will be used in each table
+*****************************************************************************/
+
+static ha_rows get_quick_record_count(SQL_SELECT *select,TABLE *table,
+ key_map keys)
+{
+ int error;
+ DBUG_ENTER("get_quick_record_count");
+ if (select)
+ {
+ select->head=table;
+ table->reginfo.impossible_range=0;
+ if ((error=select->test_quick_select(keys,(table_map) 0,HA_POS_ERROR))
+ == 1)
+ DBUG_RETURN(select->quick->records);
+ if (error == -1)
+ {
+ table->reginfo.impossible_range=1;
+ DBUG_RETURN(0);
+ }
+ DBUG_PRINT("warning",("Couldn't use record count on const keypart"));
+ }
+ DBUG_RETURN(HA_POS_ERROR); /* This shouldn't happend */
+}
+
+
+static bool
+make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds,
+ DYNAMIC_ARRAY *keyuse_array,
+ List<Item_func_match> &ftfuncs)
+{
+ 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 **table_vector;
+ JOIN_TAB *stat,*stat_end,*s,**stat_ref;
+ SQL_SELECT *select;
+ KEYUSE *keyuse,*start_keyuse;
+ table_map outer_join=0;
+ JOIN_TAB *stat_vector[MAX_TABLES+1];
+ DBUG_ENTER("make_join_statistics");
+
+ table_count=join->tables;
+ stat=(JOIN_TAB*) sql_calloc(sizeof(JOIN_TAB)*table_count);
+ stat_ref=(JOIN_TAB**) sql_alloc(sizeof(JOIN_TAB*)*MAX_TABLES);
+ table_vector=(TABLE**) sql_alloc(sizeof(TABLE**)*(table_count*2));
+ if (!stat || !stat_ref || !table_vector)
+ DBUG_RETURN(1); // Eom /* purecov: inspected */
+ select=0;
+
+ join->best_ref=stat_vector;
+
+ stat_end=stat+table_count;
+ const_table_map=all_table_map=0;
+ const_count=0;
+
+ for (s=stat,i=0 ; tables ; s++,tables=tables->next,i++)
+ {
+ TABLE *table;
+ stat_vector[i]=s;
+ table_vector[i]=s->table=table=tables->table;
+ table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);// record count
+ table->quick_keys=0;
+ table->reginfo.join_tab=s;
+ table->reginfo.not_exists_optimize=0;
+ bzero((char*) table->const_key_parts, sizeof(key_part_map)*table->keys);
+ all_table_map|= table->map;
+ if ((s->on_expr=tables->on_expr))
+ {
+ // table->maybe_null=table->outer_join=1; // Mark for send fields
+ s->key_dependent=s->dependent=
+ s->on_expr->used_tables() & ~(table->map);
+ s->dependent|=stat_vector[i-1]->dependent | table_vector[i-1]->map;
+ outer_join|=table->map;
+ continue;
+ }
+ if (tables->straight) // We don't have to move this
+ s->dependent= table_vector[i-1]->map | stat_vector[i-1]->dependent;
+ else
+ s->dependent=(table_map) 0;
+ s->key_dependent=(table_map) 0;
+ if ((table->system || table->file->records <= 1L) && ! s->dependent)
+ {
+ s->type=JT_SYSTEM;
+ const_table_map|=table->map;
+ set_position(join,const_count++,s,(KEYUSE*) 0);
+ }
+ }
+ stat_vector[i]=0;
+
+ /*
+ ** 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)
+ {
+ table_map used_tables=0L;
+ for (i=0 ; i < join->tables-1 ; i++)
+ {
+ if (stat_vector[i]->dependent & ~used_tables)
+ {
+ JOIN_TAB *save= stat_vector[i];
+ uint j;
+ for (j=i+1;
+ j < join->tables && stat_vector[j]->dependent & ~used_tables;
+ j++)
+ {
+ JOIN_TAB *tmp=stat_vector[j]; // Move element up
+ stat_vector[j]=save;
+ save=tmp;
+ }
+ if (j == join->tables)
+ {
+ join->tables=0; // Don't use join->table
+ my_error(ER_WRONG_OUTER_JOIN,MYF(0));
+ DBUG_RETURN(1);
+ }
+ stat_vector[i]=stat_vector[j];
+ stat_vector[j]=save;
+ }
+ used_tables|= stat_vector[i]->table->map;
+ }
+ }
+
+ if (conds || outer_join)
+ if (update_ref_and_keys(keyuse_array,stat,join->tables,
+ conds,~outer_join,ftfuncs))
+ DBUG_RETURN(1);
+
+ /* loop until no more const tables are found */
+ do
+ {
+ found_ref=0;
+ for (JOIN_TAB **pos=stat_vector+const_count; (s= *pos) ; pos++)
+ {
+ if (s->dependent) // If dependent on some table
+ {
+ if (s->dependent & ~(const_table_map)) // All dep. must be constants
+ continue;
+ if (s->table->file->records <= 1L)
+ { // system table
+ s->type=JT_SYSTEM;
+ const_table_map|=s->table->map;
+ set_position(join,const_count++,s,(KEYUSE*) 0);
+ 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)
+ {
+ start_keyuse=keyuse;
+ key=keyuse->key;
+ s->keys|= (key_map) 1 << key; // QQ: remove this ?
+
+ refs=const_ref=eq_part=0;
+ do
+ {
+ if (keyuse->val->type() != Item::NULL_ITEM)
+ {
+ if (!((~const_table_map) & keyuse->used_tables))
+ const_ref|= (key_map) 1 << keyuse->keypart;
+ else
+ refs|=keyuse->used_tables;
+ eq_part|= (uint) 1 << keyuse->keypart;
+ }
+ keyuse++;
+ } while (keyuse->table == table && keyuse->key == key);
+
+ if (eq_part == PREV_BITS(uint,table->key_info[key].key_parts) &&
+ (table->key_info[key].flags & HA_NOSAME))
+ {
+ if (const_ref == eq_part)
+ { // Found everything for ref.
+ s->type=JT_CONST;
+ const_table_map|=table->map;
+ set_position(join,const_count++,s,start_keyuse);
+ break;
+ }
+ else
+ found_ref|= refs; // Table is const if all refs are const
+ }
+ }
+ }
+ }
+ } while (const_table_map & found_ref);
+
+ /* Calc how many (possible) matched records in each table */
+
+ for (s=stat ; s < stat_end ; s++)
+ {
+ if (s->type == JT_SYSTEM || s->type == JT_CONST)
+ {
+ /* Only one matching row */
+ s->found_records=s->records=s->read_time=1; s->worst_seeks=1.0;
+ continue;
+ }
+ /* Approximate found rows and time to read them */
+ s->found_records=s->records=s->table->file->records;
+ s->read_time=(ha_rows) ((s->table->file->data_file_length)/IO_SIZE)+1;
+
+ /* Set a max range of how many seeks we can expect when using keys */
+ s->worst_seeks= (double) (s->read_time*2);
+ if (s->worst_seeks < 2.0) // Fix for small tables
+ s->worst_seeks=2.0;
+
+ /* if (s->type == JT_EQ_REF)
+ continue; */
+ if (s->const_keys)
+ {
+ ha_rows records;
+ if (!select)
+ select=make_select(s->table,const_table_map,
+ 0,
+ and_conds(conds,s->on_expr),&error);
+ records=get_quick_record_count(select,s->table, s->const_keys);
+ s->quick=select->quick;
+ s->needed_reg=select->needed_reg;
+ select->quick=0;
+ select->read_tables=const_table_map;
+ if (records != HA_POS_ERROR)
+ {
+ s->found_records=records;
+ s->read_time= (ha_rows) (s->quick ? s->quick->read_time : 0.0);
+ }
+ }
+ }
+ delete select;
+
+ /* Find best combination and return it */
+ join->join_tab=stat;
+ join->map2table=stat_ref;
+ join->table= join->all_tables=table_vector;
+ join->const_tables=const_count;
+ join->const_table_map=const_table_map;
+
+ if (join->const_tables != join->tables)
+ find_best_combination(join,all_table_map & ~const_table_map);
+ else
+ {
+ memcpy((gptr) join->best_positions,(gptr) join->positions,
+ sizeof(POSITION)*join->const_tables);
+ join->best_read=1.0;
+ }
+ DBUG_RETURN(get_best_combination(join));
+}
+
+
+/*****************************************************************************
+** check with keys are used and with tables references with tables
+** updates in stat:
+** keys Bitmap of all used keys
+** const_keys Bitmap of all keys with may be used with quick_select
+** keyuse Pointer to possible keys
+*****************************************************************************/
+
+typedef struct key_field_t { // Used when finding key fields
+ Field *field;
+ Item *val; // May be empty if diff constant
+ uint level,const_level; // QQ: Remove const_level
+ bool eq_func;
+ bool exists_optimize;
+} KEY_FIELD;
+
+
+/* merge new key definitions to old ones, remove those not used in both */
+
+static KEY_FIELD *
+merge_key_fields(KEY_FIELD *start,KEY_FIELD *new_fields,KEY_FIELD *end,
+ uint and_level)
+{
+ if (start == new_fields)
+ return start; // Impossible or
+ if (new_fields == end)
+ return start; // No new fields, skipp all
+
+ KEY_FIELD *first_free=new_fields;
+
+ /* Mark all found fields in old array */
+ for (; new_fields != end ; new_fields++)
+ {
+ for (KEY_FIELD *old=start ; old != first_free ; old++)
+ {
+ if (old->field == new_fields->field)
+ {
+ if (new_fields->val->used_tables())
+ {
+ if (old->val->eq(new_fields->val))
+ {
+ old->level=old->const_level=and_level;
+ old->exists_optimize&=new_fields->exists_optimize;
+ }
+ }
+ else if (old->val->eq(new_fields->val) && old->eq_func &&
+ new_fields->eq_func)
+ {
+ old->level=old->const_level=and_level;
+ old->exists_optimize&=new_fields->exists_optimize;
+ }
+ else // Impossible; remove it
+ {
+ if (old == --first_free) // If last item
+ break;
+ *old= *first_free; // Remove old value
+ old--; // Retry this value
+ }
+ }
+ }
+ }
+ /* Remove all not used items */
+ for (KEY_FIELD *old=start ; old != first_free ;)
+ {
+ if (old->level != and_level && old->const_level != and_level)
+ { // Not used in all levels
+ if (old == --first_free)
+ break;
+ *old= *first_free; // Remove old value
+ continue;
+ }
+ old++;
+ }
+ return first_free;
+}
+
+
+static void
+add_key_field(KEY_FIELD **key_fields,uint and_level,
+ Field *field,bool eq_func,Item *value,
+ table_map usable_tables)
+{
+ bool exists_optimize=0;
+ if (!(field->flags & PART_KEY_FLAG))
+ {
+ // 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
+ exists_optimize=1;
+ }
+ else
+ {
+ table_map used_tables=0;
+ if (value && (used_tables=value->used_tables()) &
+ (field->table->map | RAND_TABLE_BIT))
+ return;
+ if (!(usable_tables & field->table->map))
+ {
+ if (!eq_func || !value || value->type() != Item::NULL_ITEM ||
+ !field->table->maybe_null || field->null_ptr)
+ return; // Can't use left join optimize
+ exists_optimize=1;
+ }
+ else
+ {
+ JOIN_TAB *stat=field->table->reginfo.join_tab;
+ stat[0].keys|=field->key_start; // Add possible keys
+
+ if (!value)
+ { // Probably BETWEEN or IN
+ stat[0].const_keys |= field->key_start;
+ return; // Can't be used as eq key
+ }
+
+ /* Save the following cases:
+ Field op constant
+ Field LIKE constant where constant doesn't start with a wildcard
+ Field = field2 where field2 is in a different table
+ Field op formula
+ Field IS NULL
+ Field IS NOT NULL
+ */
+ stat[0].key_dependent|=used_tables;
+ if (value->const_item())
+ stat[0].const_keys |= field->key_start;
+
+ /* 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 */
+ if (!eq_func ||
+ field->result_type() == STRING_RESULT &&
+ value->result_type() != STRING_RESULT &&
+ field->cmp_type() != value->result_type())
+ return;
+ }
+ }
+ /* Store possible eq field */
+ (*key_fields)->field=field;
+ (*key_fields)->eq_func=eq_func;
+ (*key_fields)->val=value;
+ (*key_fields)->level=(*key_fields)->const_level=and_level;
+ (*key_fields)->exists_optimize=exists_optimize;
+ (*key_fields)++;
+}
+
+
+static void
+add_key_fields(JOIN_TAB *stat,KEY_FIELD **key_fields,uint *and_level,
+ COND *cond, table_map usable_tables)
+{
+ if (cond->type() == Item_func::COND_ITEM)
+ {
+ List_iterator<Item> li(*((Item_cond*) cond)->argument_list());
+ KEY_FIELD *org_key_fields= *key_fields;
+
+ if (((Item_cond*) cond)->functype() == Item_func::COND_AND_FUNC)
+ {
+ Item *item;
+ while ((item=li++))
+ add_key_fields(stat,key_fields,and_level,item,usable_tables);
+ for (; org_key_fields != *key_fields ; org_key_fields++)
+ {
+ if (org_key_fields->const_level == org_key_fields->level)
+ org_key_fields->const_level=org_key_fields->level= *and_level;
+ else
+ org_key_fields->const_level= *and_level;
+ }
+ }
+ else
+ {
+ (*and_level)++;
+ add_key_fields(stat,key_fields,and_level,li++,usable_tables);
+ Item *item;
+ while ((item=li++))
+ {
+ KEY_FIELD *start_key_fields= *key_fields;
+ (*and_level)++;
+ add_key_fields(stat,key_fields,and_level,item,usable_tables);
+ *key_fields=merge_key_fields(org_key_fields,start_key_fields,
+ *key_fields,++(*and_level));
+ }
+ }
+ return;
+ }
+ /* If item is of type 'field op field/constant' add it to key_fields */
+
+ if (cond->type() != Item::FUNC_ITEM)
+ return;
+ Item_func *cond_func= (Item_func*) cond;
+ switch (cond_func->select_optimize()) {
+ case Item_func::OPTIMIZE_NONE:
+ break;
+ case Item_func::OPTIMIZE_KEY:
+ if (cond_func->key_item()->type() == Item::FIELD_ITEM)
+ add_key_field(key_fields,*and_level,
+ ((Item_field*) (cond_func->key_item()))->field,
+ 0,(Item*) 0,usable_tables);
+ break;
+ case Item_func::OPTIMIZE_OP:
+ {
+ bool equal_func=(cond_func->functype() == Item_func::EQ_FUNC ||
+ cond_func->functype() == Item_func::EQUAL_FUNC);
+
+ if (cond_func->arguments()[0]->type() == Item::FIELD_ITEM)
+ {
+ add_key_field(key_fields,*and_level,
+ ((Item_field*) (cond_func->arguments()[0]))->field,
+ equal_func,
+ (cond_func->arguments()[1]),usable_tables);
+ }
+ if (cond_func->arguments()[1]->type() == Item::FIELD_ITEM &&
+ cond_func->functype() != Item_func::LIKE_FUNC)
+ {
+ add_key_field(key_fields,*and_level,
+ ((Item_field*) (cond_func->arguments()[1]))->field,
+ equal_func,
+ (cond_func->arguments()[0]),usable_tables);
+ }
+ break;
+ }
+ case Item_func::OPTIMIZE_NULL:
+ /* column_name IS [NOT] NULL */
+ if (cond_func->arguments()[0]->type() == Item::FIELD_ITEM)
+ {
+ add_key_field(key_fields,*and_level,
+ ((Item_field*) (cond_func->arguments()[0]))->field,
+ cond_func->functype() == Item_func::ISNULL_FUNC,
+ new Item_null, usable_tables);
+ }
+ break;
+ }
+ return;
+}
+
+/*
+** Add all keys with uses 'field' for some keypart
+** If field->and_level != and_level then only mark key_part as const_part
+*/
+
+static uint
+max_part_bit(key_map bits)
+{
+ uint found;
+ for (found=0; bits & 1 ; found++,bits>>=1) ;
+ return found;
+}
+
+
+static void
+add_key_part(DYNAMIC_ARRAY *keyuse_array,KEY_FIELD *key_field)
+{
+ Field *field=key_field->field;
+ TABLE *form= field->table;
+ KEYUSE keyuse;
+
+ if (key_field->eq_func && !key_field->exists_optimize)
+ {
+ for (uint key=0 ; key < form->keys ; key++)
+ {
+ if (!(form->keys_in_use_for_query & (((key_map) 1) << key)))
+ continue;
+ if (form->key_info[key].flags & HA_FULLTEXT)
+ continue; // ToDo: ft-keys in non-ft queries. SerG
+
+ uint key_parts= (uint) form->key_info[key].key_parts;
+ for (uint part=0 ; part < key_parts ; part++)
+ {
+ if (field->eq(form->key_info[key].key_part[part].field))
+ {
+ keyuse.table= field->table;
+ keyuse.val = key_field->val;
+ keyuse.key = key;
+ keyuse.keypart=part;
+ keyuse.used_tables=key_field->val->used_tables();
+ VOID(insert_dynamic(keyuse_array,(gptr) &keyuse));
+ }
+ }
+ }
+ }
+ /* Mark that we can optimize LEFT JOIN */
+ if (key_field->val->type() == Item::NULL_ITEM &&
+ !key_field->field->real_maybe_null())
+ key_field->field->table->reginfo.not_exists_optimize=1;
+}
+
+static void
+add_ft_keys(DYNAMIC_ARRAY *keyuse_array,
+ JOIN_TAB *stat,COND *cond,table_map usable_tables)
+{
+ /* for now, handling only the simples WHERE MATCH (...) case */
+ /* a bit more complex WHERE MATCH (...) > const,
+ AND's and (perhaps) OR's are on the way SerG */
+
+ if (cond->type() != Item::FUNC_ITEM ||
+ ((Item_func*) cond)->functype() != Item_func::FT_FUNC)
+ return;
+
+ Item_func_match *cond_func= (Item_func_match *) cond;
+ KEYUSE keyuse;
+
+ keyuse.table= cond_func->table;
+ keyuse.val = cond_func->key_item();
+ keyuse.key = cond_func->key;
+#define FT_KEYPART (MAX_REF_PARTS+10)
+ keyuse.keypart=FT_KEYPART;
+ keyuse.used_tables=keyuse.val->used_tables();
+ VOID(insert_dynamic(keyuse_array,(gptr) &keyuse));
+}
+
+static int
+sort_keyuse(KEYUSE *a,KEYUSE *b)
+{
+ if (a->table->tablenr != b->table->tablenr)
+ return (int) (a->table->tablenr - b->table->tablenr);
+ if (a->key != b->key)
+ return (int) (a->key - b->key);
+ if (a->keypart != b->keypart)
+ return (int) (a->keypart - b->keypart);
+ return test(a->used_tables) - test(b->used_tables); // Place const first
+}
+
+
+/*
+** Update keyuse array with all possible keys we can use to fetch rows
+** join_tab is a array in tablenr_order
+** stat is a reference array in 'prefered' order.
+*/
+
+static bool
+update_ref_and_keys(DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab,uint tables,
+ COND *cond, table_map normal_tables,List<Item_func_match> &ftfuncs)
+{
+ uint and_level,i,found_eq_constant;
+
+ {
+ KEY_FIELD *key_fields,*end;
+
+ if (!(key_fields=(KEY_FIELD*)
+ my_malloc(sizeof(key_fields[0])*
+ (current_thd->cond_count+1)*2,MYF(0))))
+ return TRUE; /* purecov: inspected */
+ and_level=0; end=key_fields;
+ if (cond)
+ add_key_fields(join_tab,&end,&and_level,cond,normal_tables);
+ for (i=0 ; i < tables ; i++)
+ {
+ if (join_tab[i].on_expr)
+ {
+ add_key_fields(join_tab,&end,&and_level,join_tab[i].on_expr,
+ join_tab[i].table->map);
+ }
+ }
+ if (init_dynamic_array(keyuse,sizeof(KEYUSE),20,64))
+ {
+ my_free((gptr) key_fields,MYF(0));
+ return TRUE;
+ }
+ /* fill keyuse with found key parts */
+ for (KEY_FIELD *field=key_fields ; field != end ; field++)
+ add_key_part(keyuse,field);
+ my_free((gptr) key_fields,MYF(0));
+ }
+
+ if (ftfuncs.elements)
+ {
+ add_ft_keys(keyuse,join_tab,cond,normal_tables);
+ }
+
+ /*
+ ** 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.
+ */
+ if (keyuse->elements)
+ {
+ KEYUSE end,*prev,*save_pos,*use;
+
+ qsort(keyuse->buffer,keyuse->elements,sizeof(KEYUSE),
+ (qsort_cmp) sort_keyuse);
+
+ bzero((char*) &end,sizeof(end)); /* Add for easy testing */
+ VOID(insert_dynamic(keyuse,(gptr) &end));
+
+ use=save_pos=dynamic_element(keyuse,0,KEYUSE*);
+ prev=&end;
+ found_eq_constant=0;
+ for (i=0 ; i < keyuse->elements-1 ; i++,use++)
+ {
+ if (!use->used_tables)
+ use->table->const_key_parts[use->key]|=
+ (key_part_map) 1 << use->keypart;
+ if (use->keypart != FT_KEYPART)
+ {
+ if (use->key == prev->key && use->table == prev->table)
+ {
+ if (prev->keypart+1 < use->keypart ||
+ prev->keypart == use->keypart && found_eq_constant)
+ continue; /* remove */
+ }
+ else if (use->keypart != 0) // First found must be 0
+ continue;
+ }
+
+ *save_pos= *use;
+ prev=use;
+ found_eq_constant= !use->used_tables;
+ /* Save ptr to first use */
+ if (!use->table->reginfo.join_tab->keyuse)
+ use->table->reginfo.join_tab->keyuse=save_pos;
+ use->table->reginfo.join_tab->checked_keys|= (key_map) 1 << use->key;
+ save_pos++;
+ }
+ i=(uint) (save_pos-(KEYUSE*) keyuse->buffer);
+ VOID(set_dynamic(keyuse,(gptr) &end,i));
+ keyuse->elements=i;
+ }
+ return FALSE;
+}
+
+
+/*****************************************************************************
+** Go through all combinations of not marked tables and find the one
+** which uses least records
+*****************************************************************************/
+
+/* Save const tables first as used tables */
+
+static void
+set_position(JOIN *join,uint idx,JOIN_TAB *table,KEYUSE *key)
+{
+ join->positions[idx].table= table;
+ join->positions[idx].key=key;
+ join->positions[idx].records_read=1.0; /* This is a const table */
+
+ /* Move the const table as down as possible in best_ref */
+ JOIN_TAB **pos=join->best_ref+idx+1;
+ JOIN_TAB *next=join->best_ref[idx];
+ for ( ;next != table ; pos++)
+ {
+ JOIN_TAB *tmp=pos[0];
+ pos[0]=next;
+ next=tmp;
+ }
+ join->best_ref[idx]=table;
+}
+
+
+static void
+find_best_combination(JOIN *join, table_map rest_tables)
+{
+ DBUG_ENTER("find_best_combination");
+ join->best_read=DBL_MAX;
+ find_best(join,rest_tables, join->const_tables,1.0,0.0);
+ DBUG_VOID_RETURN;
+}
+
+
+static void
+find_best(JOIN *join,table_map rest_tables,uint idx,double record_count,
+ double read_time)
+{
+ ulong rec;
+ double tmp;
+
+ if (!rest_tables)
+ {
+ DBUG_PRINT("best",("read_time: %g record_count: %g",read_time,
+ record_count));
+
+ read_time+=record_count/(double) TIME_FOR_COMPARE;
+ if (join->sort_by_table &&
+ join->sort_by_table != join->positions[join->const_tables].table->table)
+ read_time+=record_count; // We have to make a temp table
+ if (read_time < join->best_read)
+ {
+ memcpy((gptr) join->best_positions,(gptr) join->positions,
+ sizeof(POSITION)*idx);
+ join->best_read=read_time;
+ }
+ return;
+ }
+ if (read_time+record_count/(double) TIME_FOR_COMPARE >= join->best_read)
+ return; /* Found better before */
+
+ JOIN_TAB *s;
+ double best_record_count=DBL_MAX,best_read_time=DBL_MAX;
+ for (JOIN_TAB **pos=join->best_ref+idx ; (s=*pos) ; pos++)
+ {
+ table_map real_table_bit=s->table->map;
+ if ((rest_tables & real_table_bit) && !(rest_tables & s->dependent))
+ {
+ double best,best_time,records;
+ best=best_time=records=DBL_MAX;
+ KEYUSE *best_key=0;
+
+ if (s->keyuse)
+ { /* Use key if possible */
+ TABLE *table=s->table;
+ KEYUSE *keyuse,*start_key=0;
+ double best_records=DBL_MAX;
+
+ /* Test how we can use keys */
+ rec= s->records/10; /* Assume 10 records/key */
+ for (keyuse=s->keyuse ; keyuse->table == table ;)
+ {
+ key_map found_part=0;
+ table_map found_ref=0;
+ uint key=keyuse->key;
+ KEY *keyinfo=table->key_info+key;
+ bool ft_key=(keyuse->keypart == FT_KEYPART);
+
+ start_key=keyuse;
+ do
+ {
+ uint keypart=keyuse->keypart;
+ do
+ {
+ if(!ft_key)
+ {
+ table_map map;
+ if (!(rest_tables & keyuse->used_tables))
+ {
+ found_part|= (key_part_map) 1 << keypart;
+ found_ref|= keyuse->used_tables;
+ }
+ /*
+ ** If we find a ref, assume this table matches a proportional
+ ** part of this table.
+ ** For example 100 records matching this table with 5000 records
+ ** gives 5000/100 = 50 records per key
+ ** Constant tables are ignored and to avoid bad matches,
+ ** we don't make rec less than 100.
+ */
+ if (keyuse->used_tables &
+ (map=(keyuse->used_tables & ~join->const_table_map)))
+ {
+ uint tablenr;
+ for (tablenr=0 ; ! (map & 1) ; map>>=1, tablenr++) ;
+ if (map == 1) // Only one table
+ {
+ TABLE *tmp_table=join->all_tables[tablenr];
+ if (rec > tmp_table->file->records)
+ rec=max(tmp_table->file->records,100);
+ }
+ }
+ }
+ keyuse++;
+ } while (keyuse->table == table && keyuse->key == key &&
+ keyuse->keypart == keypart);
+ } while (keyuse->table == table && keyuse->key == key);
+
+ /*
+ ** Assume that that each key matches a proportional part of table.
+ */
+ if (!found_part && !ft_key)
+ continue; // Nothing usable found
+ if (rec == 0)
+ rec=1L; // Fix for small tables
+
+ /*
+ ** ft-keys require special treatment
+ */
+ if (ft_key)
+ {
+ /*
+ ** Really, there should be records=0.0 (yes!)
+ ** but 1.0 would be probably safer
+ */
+ tmp=prev_record_reads(join,found_ref);
+ records=1.0;
+ }
+ else
+ {
+ /*
+ ** Check if we found full key
+ */
+ if (found_part == PREV_BITS(uint,keyinfo->key_parts))
+ { /* use eq key */
+ if ((keyinfo->flags & (HA_NOSAME | HA_NULL_PART_KEY)) == HA_NOSAME)
+ {
+ tmp=prev_record_reads(join,found_ref);
+ records=1.0;
+ }
+ else
+ {
+ if (!found_ref) // If not const key
+ {
+ if (table->quick_keys & ((key_map) 1 << key))
+ records= (double) table->quick_rows[key];
+ else
+ records= (double) s->records; // quick_range couldn't use key!
+ }
+ else
+ {
+ if (!(records=keyinfo->rec_per_key[keyinfo->key_parts-1]))
+ { // Prefere longer keys
+ records=
+ ((double) s->records / (double) rec *
+ (1.0 +
+ ((double) (table->max_key_length-keyinfo->key_length) /
+ (double) table->max_key_length)));
+ if (records < 2.0)
+ records=2.0; // Can't be as good as a unique
+ }
+ }
+ if (table->used_keys & ((key_map) 1 << key))
+ {
+ /* we can use only index tree */
+ uint keys_per_block= table->file->block_size/2/
+ keyinfo->key_length+1;
+ tmp=(record_count*(records+keys_per_block-1)/
+ keys_per_block);
+ }
+ else
+ tmp=record_count*min(records,s->worst_seeks);
+ }
+ }
+ else
+ {
+ /*
+ ** Use as much key-parts as possible and a uniq key is better
+ ** than a not unique key
+ ** Set tmp to (previous record count) * (records / combination)
+ */
+ if (found_part & 1)
+ {
+ uint max_key_part=max_part_bit(found_part);
+ /* Check if quick_range could determinate how many rows we
+ will match */
+
+ if (table->quick_keys & ((key_map) 1 << key) &&
+ table->quick_key_parts[key] <= max_key_part)
+ tmp=records= (double) table->quick_rows[key];
+ else
+ {
+ /* Check if we have statistic about the distribution */
+ if ((records=keyinfo->rec_per_key[max_key_part-1]))
+ tmp=records;
+ else
+ {
+ /*
+ ** Assume that the first key part matches 1% of the file
+ ** and that the hole key matches 10 (dupplicates) or 1
+ ** (unique) records.
+ ** Assume also that more key matches proportionally more
+ ** records
+ ** This gives the formula:
+ ** records= (x * (b-a) + a*c-b)/(c-1)
+ **
+ ** b = records matched by whole key
+ ** a = records matched by first key part (10% of all records?)
+ ** c = number of key parts in key
+ ** x = used key parts (1 <= x <= c)
+ */
+ double rec_per_key;
+ if (!(rec_per_key=(double)
+ keyinfo->rec_per_key[keyinfo->key_parts-1]))
+ rec_per_key=(double) s->records/rec+1;
+
+ if (!s->records)
+ tmp=0;
+ else if (rec_per_key/(double) s->records >= 0.01)
+ tmp=rec_per_key;
+ else
+ {
+ double a=s->records*0.01;
+ tmp=(max_key_part * (rec_per_key - a) +
+ a*keyinfo->key_parts - rec_per_key)/
+ (keyinfo->key_parts-1);
+ set_if_bigger(tmp,1.0);
+ }
+ records=(ulong) tmp;
+ }
+ }
+ if (table->used_keys & ((key_map) 1 << key))
+ {
+ /* we can use only index tree */
+ uint keys_per_block= table->file->block_size/2/
+ keyinfo->key_length+1;
+ tmp=record_count*(tmp+keys_per_block-1)/keys_per_block;
+ }
+ else
+ tmp=record_count*min(tmp,s->worst_seeks);
+ }
+ else
+ tmp=best_time; // Do nothing
+ }
+ } /* not ftkey */
+ if (tmp < best_time - records/(double) TIME_FOR_COMPARE)
+ {
+ best_time=tmp + records/(double) TIME_FOR_COMPARE;
+ best=tmp;
+ best_records=records;
+ best_key=start_key;
+ }
+ }
+ records=best_records;
+ }
+ if (records >= s->found_records || best > s->read_time)
+ { // Check full join
+ if (s->on_expr)
+ {
+ tmp=s->found_records; // Can't use read cache
+ }
+ else
+ {
+ tmp=(double) s->read_time;
+ /* Calculate time to read through cache */
+ tmp*=(1.0+floor((double) cache_record_length(join,idx)*
+ record_count/(double) join_buff_size));
+ }
+ if (best == DBL_MAX ||
+ (tmp + record_count/(double) TIME_FOR_COMPARE*s->found_records <
+ best + record_count/(double) TIME_FOR_COMPARE*records))
+ {
+ best=tmp;
+ records=s->found_records;
+ best_key=0;
+ }
+ }
+ join->positions[idx].records_read=(double) records;
+ join->positions[idx].key=best_key;
+ join->positions[idx].table= s;
+ if (!best_key && idx == join->const_tables &&
+ s->table == join->sort_by_table)
+ join->sort_by_table= (TABLE*) 1; // Must use temporary table
+
+ /*
+ Go to the next level only if there hasn't been a better key on
+ this level! This will cut down the search for a lot simple cases!
+ */
+ double current_record_count=record_count*records;
+ double current_read_time=read_time+best;
+ if (best_record_count > current_record_count ||
+ best_read_time > current_read_time ||
+ idx == join->const_tables && s->table == join->sort_by_table)
+ {
+ if (best_record_count >= current_record_count &&
+ best_read_time >= current_read_time &&
+ (!(s->key_dependent & rest_tables) || records < 2.0))
+ {
+ best_record_count=current_record_count;
+ best_read_time=current_read_time;
+ }
+ swap(JOIN_TAB*,join->best_ref[idx],*pos);
+ find_best(join,rest_tables & ~real_table_bit,idx+1,
+ current_record_count,current_read_time);
+ swap(JOIN_TAB*,join->best_ref[idx],*pos);
+ }
+ if (join->select_options & SELECT_STRAIGHT_JOIN)
+ break; // Don't test all combinations
+ }
+ }
+}
+
+
+/*
+** Find how much space the prevous read not const tables takes in cache
+*/
+
+static uint
+cache_record_length(JOIN *join,uint idx)
+{
+ uint length;
+ JOIN_TAB **pos,**end;
+ THD *thd=current_thd;
+
+ length=0;
+ for (pos=join->best_ref+join->const_tables,end=join->best_ref+idx ;
+ pos != end ;
+ pos++)
+ {
+ JOIN_TAB *join_tab= *pos;
+ if (!join_tab->used_fieldlength)
+ { /* Not calced yet */
+ uint null_fields,blobs,fields,rec_length;
+ null_fields=blobs=fields=rec_length=0;
+
+ Field **f_ptr,*field;
+ for (f_ptr=join_tab->table->field ; (field= *f_ptr) ; f_ptr++)
+ {
+ if (field->query_id == thd->query_id)
+ {
+ uint flags=field->flags;
+ fields++;
+ rec_length+=field->pack_length();
+ if (flags & BLOB_FLAG)
+ blobs++;
+ if (!(flags & NOT_NULL_FLAG))
+ null_fields++;
+ }
+ }
+ if (null_fields)
+ rec_length+=(join_tab->table->null_fields+7)/8;
+ if (join_tab->table->maybe_null)
+ rec_length+=sizeof(my_bool);
+ if (blobs)
+ {
+ uint blob_length=(uint) (join_tab->table->file->mean_rec_length-
+ (join_tab->table->reclength- rec_length));
+ rec_length+=(uint) max(4,blob_length);
+ }
+ join_tab->used_fields=fields;
+ join_tab->used_fieldlength=rec_length;
+ join_tab->used_blobs=blobs;
+ }
+ length+=join_tab->used_fieldlength;
+ }
+ return length;
+}
+
+
+static double
+prev_record_reads(JOIN *join,table_map found_ref)
+{
+ double found=1.0;
+
+ for (POSITION *pos=join->positions ; found_ref ; pos++)
+ {
+ if (pos->table->table->map & found_ref)
+ {
+ found_ref&= ~pos->table->table->map;
+ found*=pos->records_read;
+ }
+ }
+ return found;
+}
+
+
+/*****************************************************************************
+** Set up join struct according to best position.
+*****************************************************************************/
+
+static bool
+get_best_combination(JOIN *join)
+{
+ uint i,key,tablenr;
+ table_map used_tables;
+ TABLE *table;
+ JOIN_TAB *join_tab,*j;
+ KEYUSE *keyuse;
+ KEY *keyinfo;
+ uint table_count;
+ String *ft_tmp=0;
+ char tmp1[FT_QUERY_MAXLEN];
+ String tmp2(tmp1,sizeof(tmp1));
+
+ table_count=join->tables;
+ if (!(join->join_tab=join_tab=
+ (JOIN_TAB*) sql_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;
+ for (j=join_tab, tablenr=0 ; tablenr < table_count ; tablenr++,j++)
+ {
+ 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_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;
+
+ keyinfo=table->key_info+key;
+ if (ftkey)
+ {
+ ft_tmp=keyuse->val->val_str(&tmp2);
+ length=ft_tmp->length();
+ keyparts=1;
+ }
+ else
+ {
+ keyparts=length=0;
+ do
+ {
+ if (!((~used_tables) & keyuse->used_tables))
+ {
+ if (keyparts == keyuse->keypart)
+ {
+ keyparts++;
+ length+=keyinfo->key_part[keyuse->keypart].length +
+ test(keyinfo->key_part[keyuse->keypart].null_bit);
+ }
+ }
+ 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]=keyuse->val;
+ if (!keyuse->used_tables &&
+ !(join->select_options & SELECT_DESCRIBE))
+ {
+ // AFAIK key_buff is zeroed...
+ // We don't need to free ft_tmp as the buffer will be freed atom.
+ memcpy((gptr)key_buff, (gptr) ft_tmp->ptr(), ft_tmp->length());
+ }
+ else
+ {
+ return TRUE; // not supported yet. SerG
+ }
+ j->type=JT_FT;
+ }
+ else
+ {
+ 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 (current_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)
+ {
+ j->table->const_table=1;
+ if (join->const_tables == tablenr)
+ {
+ join->const_tables++;
+ join->const_table_map|=form->map;
+ }
+ }
+ 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 */
+ j->type=JT_CONST; /* purecov: deadcode */
+ if (join->const_tables == tablenr)
+ {
+ join->const_tables++; /* purecov: deadcode */
+ join->const_table_map|=form->map;
+ }
+ }
+ else
+ j->type=JT_EQ_REF;
+ }
+ }
+
+ 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;
+}
+
+
+static store_key *
+get_store_key(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,
+ 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,
+ 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,
+ key_buff + maybe_null,
+ maybe_null ? key_buff : 0,
+ key_part->length,
+ keyuse->val);
+}
+
+/*
+** This function is only called for const items on fields which are keys
+** returns 1 if there was some conversion made when the field was stored.
+*/
+
+bool
+store_val_in_field(Field *field,Item *item)
+{
+ THD *thd=current_thd;
+ ulong cuted_fields=thd->cuted_fields;
+ thd->count_cuted_fields=1;
+ item->save_in_field(field);
+ thd->count_cuted_fields=0;
+ return cuted_fields != thd->cuted_fields;
+}
+
+
+static bool
+make_simple_join(JOIN *join,TABLE *tmp_table)
+{
+ TABLE **tableptr;
+ JOIN_TAB *join_tab;
+
+ if (!(tableptr=(TABLE**) sql_alloc(sizeof(TABLE*))) ||
+ !(join_tab=(JOIN_TAB*) sql_alloc(sizeof(JOIN_TAB))))
+ return TRUE;
+ join->join_tab=join_tab;
+ join->table=tableptr; tableptr[0]=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->first_record=join->sort_and_group=0;
+ join->sum_funcs=0;
+ join->send_records=0L;
+ join->group=0;
+
+ join_tab->cache.buff=0; /* No cacheing */
+ join_tab->table=tmp_table;
+ join_tab->select=0;
+ join_tab->select_cond=0;
+ join_tab->quick=0;
+ bzero((char*) &join_tab->read_record,sizeof(join_tab->read_record));
+ join_tab->type= JT_ALL; /* Map through all records */
+ join_tab->keys= (uint) ~0; /* test everything in quick */
+ join_tab->info=0;
+ join_tab->on_expr=0;
+ join_tab->ref.key = -1;
+ tmp_table->status=0;
+ tmp_table->null_row=0;
+ join_tab->read_first_record= join_init_read_record;
+ return FALSE;
+}
+
+
+static bool
+make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
+{
+ DBUG_ENTER("make_join_select");
+ if (select)
+ {
+ table_map used_tables;
+ if (join->tables > 1)
+ cond->update_used_tables(); // Tablenr may have changed
+ { // Check const tables
+ COND *const_cond=
+ make_cond_for_table(cond,join->const_table_map,(table_map) 0);
+ DBUG_EXECUTE("where",print_where(const_cond,"constants"););
+ if (const_cond && !const_cond->val_int())
+ DBUG_RETURN(1); // Impossible const condition
+ }
+ used_tables=(select->const_tables=join->const_table_map) | RAND_TABLE_BIT;
+ for (uint i=join->const_tables ; i < join->tables ; i++)
+ {
+ JOIN_TAB *tab=join->join_tab+i;
+ table_map current_map= tab->table->map;
+ used_tables|=current_map;
+ COND *tmp=make_cond_for_table(cond,used_tables,current_map);
+ if (tmp)
+ {
+ DBUG_EXECUTE("where",print_where(tmp,tab->table->table_name););
+ SQL_SELECT *sel=tab->select=(SQL_SELECT*)
+ sql_memdup((gptr) select, sizeof(SQL_SELECT));
+ if (!sel)
+ DBUG_RETURN(1); // End of memory
+ tab->select_cond=sel->cond=tmp;
+ sel->head=tab->table;
+ if (tab->quick)
+ {
+ if (tab->needed_reg == 0 && tab->type != JT_EQ_REF &&
+ (tab->type != JT_REF ||
+ (uint) tab->ref.key == tab->quick->index))
+ {
+ sel->quick=tab->quick; // Use value from get_quick_...
+ sel->quick_keys=0;
+ sel->needed_reg=0;
+ }
+ else
+ {
+ delete tab->quick;
+ }
+ tab->quick=0;
+ }
+ uint ref_key=(uint) sel->head->reginfo.join_tab->ref.key+1;
+ if (i == join->const_tables && ref_key)
+ {
+ if (tab->const_keys && tab->table->reginfo.impossible_range)
+ DBUG_RETURN(1);
+ }
+ else if (tab->type == JT_ALL)
+ {
+ if (tab->const_keys &&
+ tab->table->reginfo.impossible_range)
+ DBUG_RETURN(1); // Impossible range
+ /*
+ We plan to scan all rows.
+ Check again if we should use an index instead if
+ we could have used an column from a previous table in
+ the index or if we are using limit and this is the first table
+ */
+
+ 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)
+ {
+ if (sel->test_quick_select(tab->keys,
+ used_tables & ~ current_map,
+ join->thd->select_limit) < 0)
+ DBUG_RETURN(1); // Impossible range
+ }
+ else
+ {
+ sel->needed_reg=tab->needed_reg;
+ sel->quick_keys=0;
+ }
+ if ((sel->quick_keys | sel->needed_reg) & ~tab->checked_keys)
+ {
+ tab->keys=sel->quick_keys | sel->needed_reg;
+ tab->use_quick= (sel->needed_reg &&
+ (!select->quick_keys ||
+ (select->quick &&
+ (select->quick->records >= 100L)))) ?
+ 2 : 1;
+ sel->read_tables= used_tables;
+ }
+ if (i != join->const_tables && tab->use_quick != 2)
+ { /* Read with cache */
+ if ((tmp=make_cond_for_table(cond,
+ join->const_table_map |
+ current_map,
+ current_map)))
+ {
+ DBUG_EXECUTE("where",print_where(tmp,"cache"););
+ tab->cache.select=(SQL_SELECT*) sql_memdup((gptr) sel,
+ sizeof(SQL_SELECT));
+ tab->cache.select->cond=tmp;
+ tab->cache.select->read_tables=join->const_table_map;
+ }
+ }
+ }
+ if (tab->type == JT_REF && sel->quick &&
+ tab->ref.key_length < sel->quick->max_used_key_length)
+ {
+ /* Range uses longer key; Use this instead of ref on key */
+ tab->type=JT_ALL;
+ tab->use_quick=1;
+ tab->ref.key_parts=0; // Don't use ref key.
+ join->best_positions[i].records_read=sel->quick->records;
+ }
+ }
+ }
+ }
+ DBUG_RETURN(0);
+}
+
+
+static void
+make_join_readinfo(JOIN *join,uint options)
+{
+ uint i;
+ DBUG_ENTER("make_join_readinfo");
+
+ for (i=join->const_tables ; i < join->tables ; i++)
+ {
+ JOIN_TAB *tab=join->join_tab+i;
+ TABLE *table=tab->table;
+ tab->read_record.table= table;
+ tab->read_record.file=table->file;
+ tab->next_select=sub_select; /* normal select */
+ switch (tab->type) {
+ case JT_SYSTEM: // Only happens with left join
+ table->status=STATUS_NO_RECORD;
+ tab->read_first_record= join_read_system;
+ tab->read_record.read_record= join_no_more_records;
+ break;
+ case JT_CONST: // Only happens with left join
+ table->status=STATUS_NO_RECORD;
+ tab->read_first_record= join_read_const;
+ tab->read_record.read_record= join_no_more_records;
+ break;
+ case JT_EQ_REF:
+ table->status=STATUS_NO_RECORD;
+ delete tab->quick;
+ tab->quick=0;
+ 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))
+ {
+ table->key_read=1;
+ table->file->extra(HA_EXTRA_KEYREAD);
+ }
+ break;
+ case JT_REF:
+ table->status=STATUS_NO_RECORD;
+ delete tab->quick;
+ 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))
+ {
+ table->key_read=1;
+ table->file->extra(HA_EXTRA_KEYREAD);
+ }
+ break;
+ case JT_FT:
+ table->status=STATUS_NO_RECORD;
+ table->file->index_init(tab->ref.key);
+ tab->read_first_record= join_ft_read_first;
+ tab->read_record.read_record= join_ft_read_next;
+ break;
+ case JT_ALL:
+ /*
+ ** if previous table use cache
+ */
+ table->status=STATUS_NO_RECORD;
+ if (i != join->const_tables && (options & SELECT_USE_CACHE) &&
+ tab->use_quick != 2 && !tab->on_expr)
+ {
+ if ((options & SELECT_DESCRIBE) ||
+ !join_init_cache(join->thd,join->join_tab+join->const_tables,
+ i-join->const_tables))
+ {
+ tab[-1].next_select=sub_select_cache; /* Patch previous */
+ }
+ }
+ /* These init changes read_record */
+ if (tab->use_quick == 2)
+ tab->read_first_record= join_init_quick_read_record;
+ else
+ {
+ tab->read_first_record= join_init_read_record;
+ 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->read_first_record= join_init_read_first_with_key;
+ tab->type=JT_NEXT; // Read with index_first / index_next
+ }
+ }
+ break;
+ default:
+ DBUG_PRINT("error",("Table type %d found",tab->type)); /* purecov: deadcode */
+ break; /* purecov: deadcode */
+ case JT_UNKNOWN:
+ case JT_MAYBE_REF:
+ abort(); /* purecov: deadcode */
+ }
+ }
+ join->join_tab[join->tables-1].next_select=0; /* Set by do_select */
+ DBUG_VOID_RETURN;
+}
+
+
+static void
+join_free(JOIN *join)
+{
+ JOIN_TAB *tab,*end;
+
+ if (join->table)
+ {
+ /* only sorted table is cached */
+ if (join->tables > join->const_tables)
+ free_io_cache(join->table[join->const_tables]);
+ for (tab=join->join_tab,end=tab+join->tables ; tab != end ; tab++)
+ {
+ delete tab->select;
+ delete tab->quick;
+ x_free(tab->cache.buff);
+ end_read_record(&tab->read_record);
+ if (tab->table)
+ {
+ if (tab->table->key_read)
+ {
+ tab->table->key_read=0;
+ tab->table->file->extra(HA_EXTRA_NO_KEYREAD);
+ }
+ tab->table->file->index_end();
+ }
+ }
+ join->table=0;
+ }
+ // We are not using tables anymore
+ // Unlock all tables. We may be in an INSERT .... SELECT statement.
+ if (join->lock && join->thd->lock)
+ {
+ 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;
+ join->tmp_table_param.copy_field=0;
+}
+
+
+/*****************************************************************************
+** Remove the following expressions from ORDER BY and GROUP BY:
+** Constant expressions
+** Expression that only uses tables that are of type EQ_REF and the reference
+** is in the ORDER list or if all refereed tables are of the above type.
+**
+** In the following, the X field can be removed:
+** SELECT * FROM t1,t2 WHERE t1.a=t2.a ORDER BY t1.a,t2.X
+** SELECT * FROM t1,t2,t3 WHERE t1.a=t2.a AND t2.b=t3.b ORDER BY t1.a,t3.X
+**
+** These can't be optimized:
+** SELECT * FROM t1,t2 WHERE t1.a=t2.a ORDER BY t2.X,t1.a
+** SELECT * FROM t1,t2 WHERE t1.a=t2.a AND t1.b=t2.b ORDER BY t1.a,t2.c
+** SELECT * FROM t1,t2 WHERE t1.a=t2.a ORDER BY t2.b,t1.a
+*****************************************************************************/
+
+static bool
+eq_ref_table(JOIN *join, ORDER *start_order, JOIN_TAB *tab)
+{
+ if (tab->cached_eq_ref_table) // If cached
+ return tab->eq_ref_table;
+ tab->cached_eq_ref_table=1;
+ if (tab->type == JT_CONST) // We can skip const tables
+ return (tab->eq_ref_table=1); /* purecov: inspected */
+ if (tab->type != JT_EQ_REF)
+ return (tab->eq_ref_table=0); // We must use this
+ Item **ref_item=tab->ref.items;
+ Item **end=ref_item+tab->ref.key_parts;
+ uint found=0;
+ table_map map=tab->table->map;
+
+ for (; ref_item != end ; ref_item++)
+ {
+ if (! (*ref_item)->const_item())
+ { // Not a const ref
+ ORDER *order;
+ for (order=start_order ; order ; order=order->next)
+ {
+ if ((*ref_item)->eq(order->item[0]))
+ break;
+ }
+ if (order)
+ {
+ found++;
+ dbug_assert(!(order->used & map));
+ order->used|=map;
+ continue; // Used in ORDER BY
+ }
+ if (!only_eq_ref_tables(join,start_order, (*ref_item)->used_tables()))
+ return (tab->eq_ref_table=0);
+ }
+ }
+ /* Check that there was no reference to table before sort order */
+ for ( ; found && start_order ; start_order=start_order->next)
+ {
+ if (start_order->used & map)
+ {
+ found--;
+ continue;
+ }
+ if (start_order->depend_map & map)
+ return (tab->eq_ref_table=0);
+ }
+ return tab->eq_ref_table=1;
+}
+
+
+static bool
+only_eq_ref_tables(JOIN *join,ORDER *order,table_map tables)
+{
+ if (specialflag & SPECIAL_SAFE_MODE)
+ return 0; // skip this optimize /* purecov: inspected */
+ for (JOIN_TAB **tab=join->map2table ; tables ; tab++, tables>>=1)
+ {
+ if (tables & 1 && !eq_ref_table(join, order, *tab))
+ return 0;
+ }
+ return 1;
+}
+
+
+/* Update the dependency map for the tables */
+
+static void update_depend_map(JOIN *join)
+{
+ JOIN_TAB *join_tab=join->join_tab, *end=join_tab+join->tables;
+
+ for ( ; join_tab != end ; join_tab++)
+ {
+ TABLE_REF *ref= &join_tab->ref;
+ table_map depend_map=0;
+ Item **item=ref->items;
+ uint i;
+ for (i=0 ; i < ref->key_parts ; i++,item++)
+ depend_map|=(*item)->used_tables();
+ ref->depend_map=depend_map;
+ for (JOIN_TAB *join_tab2=join->join_tab;
+ depend_map ;
+ join_tab2++,depend_map>>=1 )
+ {
+ if (depend_map & 1)
+ ref->depend_map|=join_tab2->ref.depend_map;
+ }
+ }
+}
+
+
+/* Update the dependency map for the sort order */
+
+static void update_depend_map(JOIN *join, ORDER *order)
+{
+ for ( ; order ; order=order->next)
+ {
+ table_map depend_map;
+ order->item[0]->update_used_tables();
+ order->depend_map=depend_map=order->item[0]->used_tables();
+ if (!(order->depend_map & RAND_TABLE_BIT)) // Not item_sum() or RAND()
+ {
+ for (JOIN_TAB *join_tab=join->join_tab;
+ depend_map ;
+ join_tab++, depend_map>>=1)
+ {
+ if (depend_map & 1)
+ order->depend_map|=join_tab->ref.depend_map;
+ }
+ }
+ }
+}
+
+
+/*
+** simple_order is set to 1 if sort_order only uses fields from head table
+** and the head table is not a LEFT JOIN table
+*/
+
+static ORDER *
+remove_const(JOIN *join,ORDER *first_order, COND *cond, bool *simple_order)
+{
+ if (join->tables == join->const_tables)
+ return 0; // No need to sort
+ DBUG_ENTER("remove_const");
+ ORDER *order,**prev_ptr;
+ table_map first_table= join->join_tab[join->const_tables].table->map;
+ table_map not_const_tables= ~join->const_table_map;
+ table_map ref;
+ prev_ptr= &first_order;
+ *simple_order= join->join_tab[join->const_tables].on_expr ? 0 : 1;
+
+ /* NOTE: A variable of not_const_tables ^ first_table; breaks gcc 2.7 */
+
+ update_depend_map(join, first_order);
+ for (order=first_order; order ; order=order->next)
+ {
+ table_map order_tables=order->item[0]->used_tables();
+ if (order->item[0]->with_sum_func)
+ *simple_order=0; // Must do a temp table to sort
+ else if (!(order_tables & not_const_tables))
+ {
+ DBUG_PRINT("info",("removing: %s", order->item[0]->full_name()));
+ continue; // skipp const item
+ }
+ else
+ {
+ if (order_tables & RAND_TABLE_BIT)
+ *simple_order=0;
+ else
+ {
+ Item *comp_item=0;
+ if (cond && const_expression_in_where(cond,order->item[0], &comp_item))
+ {
+ DBUG_PRINT("info",("removing: %s", order->item[0]->full_name()));
+ continue;
+ }
+ if ((ref=order_tables & (not_const_tables ^ first_table)))
+ {
+ if (only_eq_ref_tables(join,first_order,ref))
+ {
+ DBUG_PRINT("info",("removing: %s", order->item[0]->full_name()));
+ continue;
+ }
+ *simple_order=0; // Must do a temp table to sort
+ }
+ }
+ }
+ *prev_ptr= order; // use this entry
+ prev_ptr= &order->next;
+ }
+ *prev_ptr=0;
+ if (!first_order) // Nothing to sort/group
+ *simple_order=1;
+ DBUG_PRINT("exit",("simple_order: %d",(int) *simple_order));
+ DBUG_RETURN(first_order);
+}
+
+static int
+return_zero_rows(select_result *result,TABLE_LIST *tables,List<Item> &fields,
+ bool send_row, uint select_options,const char *info,
+ Item *having, Procedure *procedure)
+{
+ DBUG_ENTER("return_zero_rows");
+
+ if (select_options & SELECT_DESCRIBE)
+ {
+ describe_info(info);
+ DBUG_RETURN(0);
+ }
+ if (procedure)
+ {
+ if (result->prepare(fields)) // This hasn't been done yet
+ DBUG_RETURN(-1);
+ }
+ if (send_row)
+ {
+ for (TABLE_LIST *table=tables; table ; table=table->next)
+ mark_as_null_row(table->table); // All fields are NULL
+ if (having && having->val_int() == 0.0)
+ send_row=0;
+ }
+ if (!tables || !(result->send_fields(fields,1)))
+ {
+ if (send_row)
+ result->send_data(fields);
+ if (tables) // Not from do_select()
+ result->send_eof(); // Should be safe
+ }
+ DBUG_RETURN(0);
+}
+
+
+static void clear_tables(JOIN *join)
+{
+ for (uint i=0 ; i < join->tables ; i++)
+ mark_as_null_row(join->table[i]); // All fields are NULL
+}
+
+/*****************************************************************************
+** Make som simple condition optimization:
+** If there is a test 'field = const' change all refs to 'field' to 'const'
+** Remove all dummy tests 'item = item', 'const op const'.
+** Remove all 'item is NULL', when item can never be null!
+** item->marker should be 0 for all items on entry
+** Return in cond_value FALSE if condition is impossible (1 = 2)
+*****************************************************************************/
+
+class COND_CMP :public ilink {
+public:
+ static void *operator new(size_t size) {return (void*) sql_alloc(size); }
+ static void operator delete(void *ptr __attribute__((unused)),
+ size_t size __attribute__((unused))) {} /*lint -e715 */
+
+ Item *and_level;
+ Item_func *cmp_func;
+ COND_CMP(Item *a,Item_func *b) :and_level(a),cmp_func(b) {}
+};
+
+#ifdef __GNUC__
+template class I_List<COND_CMP>;
+template class I_List_iterator<COND_CMP>;
+template class List<Item_func_match>;
+template class List_iterator<Item_func_match>;
+#endif
+
+/*
+** change field = field to field = const for each found field = const in the
+** and_level
+*/
+
+static void
+change_cond_ref_to_const(I_List<COND_CMP> *save_list,Item *and_father,
+ Item *cond, Item *field, Item *value)
+{
+ if (cond->type() == Item::COND_ITEM)
+ {
+ bool and_level= ((Item_cond*) cond)->functype() ==
+ Item_func::COND_AND_FUNC;
+ List_iterator<Item> li(*((Item_cond*) cond)->argument_list());
+ Item *item;
+ while ((item=li++))
+ change_cond_ref_to_const(save_list,and_level ? cond : item, item,
+ field, value);
+ return;
+ }
+ if (cond->eq_cmp_result() == Item::COND_OK)
+ return; // Not a boolean function
+
+ Item_bool_func2 *func= (Item_bool_func2*) cond;
+ Item *left_item= func->arguments()[0];
+ Item *right_item= func->arguments()[1];
+ Item_func::Functype functype= func->functype();
+
+ if (right_item->eq(field) && left_item != value)
+ {
+ Item *tmp=value->new_item();
+ if (tmp)
+ {
+ func->arguments()[1] = tmp;
+ func->update_used_tables();
+ if ((functype == Item_func::EQ_FUNC || functype == Item_func::EQUAL_FUNC)
+ && and_father != cond && !left_item->const_item())
+ {
+ cond->marker=1;
+ COND_CMP *tmp2;
+ if ((tmp2=new COND_CMP(and_father,func)))
+ save_list->push_back(tmp2);
+ }
+ func->set_cmp_func(item_cmp_type(func->arguments()[0]->result_type(),
+ func->arguments()[1]->result_type()));
+ }
+ }
+ else if (left_item->eq(field) && right_item != value)
+ {
+ Item *tmp=value->new_item();
+ if (tmp)
+ {
+ func->arguments()[0] = value = tmp;
+ func->update_used_tables();
+ if ((functype == Item_func::EQ_FUNC || functype == Item_func::EQUAL_FUNC)
+ && and_father != cond && !right_item->const_item())
+ {
+ func->arguments()[0] = func->arguments()[1]; // For easy check
+ func->arguments()[1] = value;
+ cond->marker=1;
+ COND_CMP *tmp2;
+ if ((tmp2=new COND_CMP(and_father,func)))
+ save_list->push_back(tmp2);
+ }
+ func->set_cmp_func(item_cmp_type(func->arguments()[0]->result_type(),
+ func->arguments()[1]->result_type()));
+ }
+ }
+}
+
+
+static void
+propagate_cond_constants(I_List<COND_CMP> *save_list,COND *and_level,
+ COND *cond)
+{
+ if (cond->type() == Item::COND_ITEM)
+ {
+ bool and_level= ((Item_cond*) cond)->functype() ==
+ Item_func::COND_AND_FUNC;
+ List_iterator<Item> li(*((Item_cond*) cond)->argument_list());
+ Item *item;
+ I_List<COND_CMP> save;
+ while ((item=li++))
+ {
+ propagate_cond_constants(&save,and_level ? cond : item, item);
+ }
+ if (and_level)
+ { // Handle other found items
+ I_List_iterator<COND_CMP> cond_itr(save);
+ COND_CMP *cond_cmp;
+ while ((cond_cmp=cond_itr++))
+ if (!cond_cmp->cmp_func->arguments()[0]->const_item())
+ change_cond_ref_to_const(&save,cond_cmp->and_level,
+ cond_cmp->and_level,
+ cond_cmp->cmp_func->arguments()[0],
+ cond_cmp->cmp_func->arguments()[1]);
+ }
+ }
+ else if (and_level != cond && !cond->marker) // In a AND group
+ {
+ if (cond->type() == Item::FUNC_ITEM &&
+ (((Item_func*) cond)->functype() == Item_func::EQ_FUNC ||
+ ((Item_func*) cond)->functype() == Item_func::EQUAL_FUNC))
+ {
+ Item_func_eq *func=(Item_func_eq*) cond;
+ bool left_const= func->arguments()[0]->const_item();
+ bool right_const=func->arguments()[1]->const_item();
+ if (!(left_const && right_const))
+ {
+ if (right_const)
+ {
+ func->arguments()[1]=resolve_const_item(func->arguments()[1],
+ func->arguments()[0]);
+ func->update_used_tables();
+ change_cond_ref_to_const(save_list,and_level,and_level,
+ func->arguments()[0],
+ func->arguments()[1]);
+ }
+ else if (left_const)
+ {
+ func->arguments()[0]=resolve_const_item(func->arguments()[0],
+ func->arguments()[1]);
+ func->update_used_tables();
+ change_cond_ref_to_const(save_list,and_level,and_level,
+ func->arguments()[1],
+ func->arguments()[0]);
+ }
+ }
+ }
+ }
+}
+
+
+static COND *
+optimize_cond(COND *conds,Item::cond_result *cond_value)
+{
+ if (!conds)
+ {
+ *cond_value= Item::COND_TRUE;
+ return conds;
+ }
+ /* change field = field to field = const for each found field = const */
+ DBUG_EXECUTE("where",print_where(conds,"original"););
+ propagate_cond_constants((I_List<COND_CMP> *) 0,conds,conds);
+ /*
+ ** Remove all instances of item == item
+ ** Remove all and-levels where CONST item != CONST item
+ */
+ DBUG_EXECUTE("where",print_where(conds,"after const change"););
+ conds=remove_eq_conds(conds,cond_value) ;
+ DBUG_EXECUTE("info",print_where(conds,"after remove"););
+ return conds;
+}
+
+
+/*
+** remove const and eq items. Return new item, or NULL if no condition
+** cond_value is set to according:
+** COND_OK query is possible (field = constant)
+** COND_TRUE always true ( 1 = 1 )
+** COND_FALSE always false ( 1 = 2 )
+*/
+
+static COND *
+remove_eq_conds(COND *cond,Item::cond_result *cond_value)
+{
+ if (cond->type() == Item::COND_ITEM)
+ {
+ bool and_level= ((Item_cond*) cond)->functype()
+ == Item_func::COND_AND_FUNC;
+ List_iterator<Item> li(*((Item_cond*) cond)->argument_list());
+ Item::cond_result tmp_cond_value;
+
+ *cond_value=Item::COND_UNDEF;
+ Item *item;
+ while ((item=li++))
+ {
+ Item *new_item=remove_eq_conds(item,&tmp_cond_value);
+ if (!new_item)
+ {
+#ifdef DELETE_ITEMS
+ delete item; // This may be shared
+#endif
+ li.remove();
+ }
+ else if (item != new_item)
+ {
+#ifdef DELETE_ITEMS
+ delete item; // This may be shared
+#endif
+ VOID(li.replace(new_item));
+ }
+ if (*cond_value == Item::COND_UNDEF)
+ *cond_value=tmp_cond_value;
+ switch (tmp_cond_value) {
+ case Item::COND_OK: // Not TRUE or FALSE
+ if (and_level || *cond_value == Item::COND_FALSE)
+ *cond_value=tmp_cond_value;
+ break;
+ case Item::COND_FALSE:
+ if (and_level)
+ {
+ *cond_value=tmp_cond_value;
+ return (COND*) 0; // Always false
+ }
+ break;
+ case Item::COND_TRUE:
+ if (!and_level)
+ {
+ *cond_value= tmp_cond_value;
+ return (COND*) 0; // Always true
+ }
+ break;
+ case Item::COND_UNDEF: // Impossible
+ break; /* purecov: deadcode */
+ }
+ }
+ if (!((Item_cond*) cond)->argument_list()->elements ||
+ *cond_value != Item::COND_OK)
+ return (COND*) 0;
+ if (((Item_cond*) cond)->argument_list()->elements == 1)
+ { // Remove list
+ item= ((Item_cond*) cond)->argument_list()->head();
+ ((Item_cond*) cond)->argument_list()->empty();
+ return item;
+ }
+ }
+ else if (cond->type() == Item::FUNC_ITEM &&
+ ((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
+ */
+
+ Item_func_isnull *func=(Item_func_isnull*) cond;
+ Item **args= func->arguments();
+ if (args[0]->type() == Item::FIELD_ITEM)
+ {
+ Field *field=((Item_field*) args[0])->field;
+ if (field->flags & AUTO_INCREMENT_FLAG && !field->table->maybe_null &&
+ (current_thd->options & OPTION_AUTO_IS_NULL) &&
+ current_thd->insert_id())
+ {
+ COND *new_cond;
+ if ((new_cond= new Item_func_eq(args[0],
+ new Item_int("last_insert_id()",
+ current_thd->insert_id(),
+ 21))))
+ {
+ cond=new_cond;
+ cond->fix_fields(current_thd,0);
+ }
+ current_thd->insert_id(0); // Clear for next request
+ }
+ /* fix to replace 'NULL' dates with '0' (shreeve@uci.edu) */
+ else if (((field->type() == FIELD_TYPE_DATE) ||
+ (field->type() == FIELD_TYPE_DATETIME)) &&
+ (field->flags & NOT_NULL_FLAG))
+ {
+ COND *new_cond;
+ if ((new_cond= new Item_func_eq(args[0],new Item_int("0", 0, 2))))
+ {
+ cond=new_cond;
+ cond->fix_fields(current_thd,0);
+ }
+ }
+ }
+ }
+ else if (cond->const_item())
+ {
+ *cond_value= eval_const_cond(cond) ? Item::COND_TRUE : Item::COND_FALSE;
+ return (COND*) 0;
+ }
+ else if ((*cond_value= cond->eq_cmp_result()) != Item::COND_OK)
+ { // boolan compare function
+ Item *left_item= ((Item_func*) cond)->arguments()[0];
+ Item *right_item= ((Item_func*) cond)->arguments()[1];
+ if (left_item->eq(right_item))
+ {
+ if (!left_item->maybe_null ||
+ ((Item_func*) cond)->functype() == Item_func::EQUAL_FUNC)
+ return (COND*) 0; // Compare of identical items
+ }
+ }
+ *cond_value=Item::COND_OK;
+ return cond; /* Point at next and level */
+}
+
+/*
+** Return 1 if the item is a const value in all the WHERE clause
+*/
+
+static bool
+const_expression_in_where(COND *cond, Item *comp_item, Item **const_item)
+{
+ if (cond->type() == Item::COND_ITEM)
+ {
+ bool and_level= (((Item_cond*) cond)->functype()
+ == Item_func::COND_AND_FUNC);
+ List_iterator<Item> li(*((Item_cond*) cond)->argument_list());
+ Item *item;
+ while ((item=li++))
+ {
+ bool res=const_expression_in_where(item, comp_item, const_item);
+ if (res) // Is a const value
+ {
+ if (and_level)
+ return 1;
+ }
+ else if (!and_level)
+ return 0;
+ }
+ return and_level ? 0 : 1;
+ }
+ else if (cond->eq_cmp_result() != Item::COND_OK)
+ { // boolan compare function
+ Item_func* func= (Item_func*) cond;
+ if (func->functype() != Item_func::EQUAL_FUNC &&
+ func->functype() != Item_func::EQ_FUNC)
+ return 0;
+ Item *left_item= ((Item_func*) cond)->arguments()[0];
+ Item *right_item= ((Item_func*) cond)->arguments()[1];
+ if (left_item->eq(comp_item))
+ {
+ if (right_item->const_item())
+ {
+ if (*const_item)
+ return right_item->eq(*const_item);
+ *const_item=right_item;
+ return 1;
+ }
+ }
+ else if (right_item->eq(comp_item))
+ {
+ if (left_item->const_item())
+ {
+ if (*const_item)
+ return left_item->eq(*const_item);
+ *const_item=left_item;
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+
+/****************************************************************************
+** Create a temp table according to a field list.
+** Set distinct if duplicates could be removed
+** Given fields field pointers are changed to point at tmp_table
+** for send_fields
+****************************************************************************/
+
+Field *create_tmp_field(TABLE *table,Item *item, Item::Type type,
+ Item_result_field ***copy_func, Field **from_field,
+ bool group, bool modify_item)
+{
+ switch (type) {
+ case Item::SUM_FUNC_ITEM:
+ {
+ Item_sum *item_sum=(Item_sum*) item;
+ bool maybe_null=item_sum->maybe_null;
+ switch (item_sum->sum_func()) {
+ case Item_sum::AVG_FUNC: /* Place for sum & count */
+ if (group)
+ return new Field_string(sizeof(double)+sizeof(longlong),
+ maybe_null, item->name,table,1);
+ else
+ return new Field_double(item_sum->max_length,maybe_null,
+ item->name, table, item_sum->decimals);
+ case Item_sum::STD_FUNC: /* Place for sum & count */
+ if (group)
+ return new Field_string(sizeof(double)*2+sizeof(longlong),
+ maybe_null, item->name,table,1);
+ else
+ return new Field_double(item_sum->max_length, maybe_null,
+ item->name,table,item_sum->decimals);
+ case Item_sum::UNIQUE_USERS_FUNC:
+ return new Field_long(9,maybe_null,item->name,table,1);
+ default:
+ switch (item_sum->result_type()) {
+ case REAL_RESULT:
+ return new Field_double(item_sum->max_length,maybe_null,
+ item->name,table,item_sum->decimals);
+ case INT_RESULT:
+ return new Field_longlong(item_sum->max_length,maybe_null,
+ item->name,table);
+ case STRING_RESULT:
+ if (item_sum->max_length > 255)
+ return new Field_blob(item_sum->max_length,maybe_null,
+ item->name,table,item->binary);
+ return new Field_string(item_sum->max_length,maybe_null,
+ item->name,table,item->binary);
+ }
+ }
+ current_thd->fatal_error=1;
+ return 0; // Error
+ }
+ case Item::FIELD_ITEM:
+ {
+ 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
+ {
+ if (modify_item)
+ ((Item_field*) item)->result_field= new_field;
+ else
+ new_field->field_name=item->name;
+ if (org_field->maybe_null())
+ new_field->flags&= ~NOT_NULL_FLAG; // Because of outer join
+ }
+ return new_field;
+ }
+ case Item::PROC_ITEM:
+ case Item::FUNC_ITEM:
+ case Item::COND_ITEM:
+ case Item::FIELD_AVG_ITEM:
+ case Item::FIELD_STD_ITEM:
+ /* The following can only happen with 'CREATE TABLE ... SELECT' */
+ case Item::INT_ITEM:
+ case Item::REAL_ITEM:
+ case Item::STRING_ITEM:
+ case Item::REF_ITEM:
+ {
+ bool maybe_null=item->maybe_null;
+ Field *new_field;
+ LINT_INIT(new_field);
+
+ switch (item->result_type()) {
+ case REAL_RESULT:
+ new_field=new Field_double(item->max_length,maybe_null,
+ item->name,table,item->decimals);
+ break;
+ case INT_RESULT:
+ new_field=new Field_longlong(item->max_length,maybe_null,
+ item->name,table);
+ break;
+ case STRING_RESULT:
+ if (item->max_length > 255)
+ new_field= new Field_blob(item->max_length,maybe_null,
+ item->name,table,item->binary);
+ else
+ new_field= new Field_string(item->max_length,maybe_null,
+ item->name,table,item->binary);
+ break;
+ }
+ if (copy_func)
+ *((*copy_func)++) = (Item_result_field*) item; // Save for copy_funcs
+ if (modify_item)
+ ((Item_result_field*) item)->result_field=new_field;
+ return new_field;
+ }
+ default: // Dosen't have to be stored
+ return 0;
+ }
+}
+
+
+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)
+{
+ TABLE *table;
+ uint i,field_count,reclength,null_count,null_pack_length,
+ blob_count,group_null_items;
+ bool using_unique_constraint=0;
+ char *tmpname,path[FN_REFLEN];
+ byte *pos,*group_buff;
+ uchar *null_flags;
+ Field **reg_field,**from_field;
+ Copy_field *copy=0;
+ KEY *keyinfo;
+ KEY_PART_INFO *key_part_info;
+ Item_result_field **copy_func;
+ MI_COLUMNDEF *recinfo;
+ DBUG_ENTER("create_tmp_table");
+ DBUG_PRINT("enter",("distinct: %d save_sum_fields: %d allow_distinct_limit: %d group: %d",
+ (int) distinct, (int) save_sum_fields,
+ (int) allow_distinct_limit,test(group)));
+
+ created_tmp_tables++; // Global, but should be safe
+ sprintf(path,"%s%s%lx_%lx_%x",mysql_tmpdir,tmp_file_prefix,current_pid,
+ thd->thread_id, thd->tmp_table++);
+ if (group)
+ {
+ 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 (param->group_length >= MAX_BLOB_WIDTH)
+ using_unique_constraint=1;
+ }
+
+ field_count=param->field_count+param->func_count+param->sum_func_count;
+ if (!my_multi_malloc(MYF(MY_WME),
+ &table,sizeof(*table),
+ &reg_field,sizeof(Field*)*(field_count+1),
+ &from_field,sizeof(Field*)*field_count,
+ &copy_func,sizeof(*copy_func)*(param->func_count+1),
+ &param->keyinfo,sizeof(*param->keyinfo),
+ &key_part_info,
+ sizeof(*key_part_info)*(param->group_parts+1),
+ &param->start_recinfo,
+ sizeof(*param->recinfo)*(field_count*2+4),
+ &tmpname,(uint) strlen(path)+1,
+ &group_buff,group && ! using_unique_constraint ?
+ param->group_length : 0,
+ NullS))
+ {
+ DBUG_RETURN(NULL); /* purecov: inspected */
+ }
+ if (!(param->copy_field=copy=new Copy_field[field_count]))
+ {
+ my_free((gptr) table,MYF(0)); /* purecov: inspected */
+ DBUG_RETURN(NULL); /* purecov: inspected */
+ }
+ param->funcs=copy_func;
+ strmov(tmpname,path);
+ /* make table according to fields */
+
+ bzero((char*) table,sizeof(*table));
+ bzero((char*) reg_field,sizeof(Field*)*(field_count+1));
+ bzero((char*) from_field,sizeof(Field*)*field_count);
+ table->field=reg_field;
+ table->real_name=table->path=tmpname;
+ table->table_name=base_name(tmpname);
+ table->reginfo.lock_type=TL_WRITE; /* Will be updated */
+ table->db_stat=HA_OPEN_KEYFILE+HA_OPEN_RNDFILE;
+ table->blob_ptr_size=mi_portable_sizeof_char_ptr;
+ table->map=1;
+ table->tmp_table=1;
+ table->db_low_byte_first=1; // True for HEAP and MyISAM
+
+ /* Calculate with type of fields we will need in heap table */
+
+ reclength=blob_count=null_count=group_null_items=0;
+
+ List_iterator<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 ||
+ item->const_item())
+ continue;
+
+ if (type == Item::SUM_FUNC_ITEM && !group && !save_sum_fields)
+ { /* Can't calc group yet */
+ ((Item_sum*) item)->result_field=0;
+ for (i=0 ; i < ((Item_sum*) item)->arg_count ; i++)
+ {
+ Item *arg= ((Item_sum*) item)->args[i];
+ if (!arg->const_item())
+ {
+ Field *new_field=
+ create_tmp_field(table,arg,arg->type(),&copy_func,tmp_from_field,
+ group != 0,1);
+ if (!new_field)
+ goto err; // Should be OOM
+ tmp_from_field++;
+ *(reg_field++)= new_field;
+ reclength+=new_field->pack_length();
+ if (!(new_field->flags & NOT_NULL_FLAG))
+ null_count++;
+ if (new_field->flags & BLOB_FLAG)
+ blob_count++;
+ ((Item_sum*) item)->args[i]= new Item_field(new_field);
+ }
+ }
+ }
+ else
+ {
+ Field *new_field=create_tmp_field(table,item,type,&copy_func,
+ tmp_from_field, group != 0,1);
+ if (!new_field)
+ {
+ if (thd->fatal_error)
+ goto err; // Got OOM
+ continue; // Some kindf of const item
+ }
+ if (type == Item::SUM_FUNC_ITEM)
+ ((Item_sum *) item)->result_field= new_field;
+ tmp_from_field++;
+ reclength+=new_field->pack_length();
+ if (!(new_field->flags & NOT_NULL_FLAG))
+ null_count++;
+ if (new_field->flags & BLOB_FLAG)
+ blob_count++;
+ if (item->marker == 4 && item->maybe_null)
+ {
+ group_null_items++;
+ new_field->flags|= GROUP_FLAG;
+ }
+ *(reg_field++) =new_field;
+ }
+ }
+ field_count=reg_field - table->field;
+
+ /* If result table is small; use a heap */
+ if (blob_count || using_unique_constraint ||
+ (select_options & (OPTION_BIG_TABLES | SELECT_SMALL_RESULT)) ==
+ OPTION_BIG_TABLES)
+ {
+ table->file=get_new_handler(table,table->db_type=DB_TYPE_MYISAM);
+ if (group &&
+ (param->group_parts > table->file->max_key_parts() ||
+ param->group_length > table->file->max_key_length()))
+ using_unique_constraint=1;
+ }
+ else
+ {
+ table->file=get_new_handler(table,table->db_type=DB_TYPE_HEAP);
+ }
+
+ if (!using_unique_constraint)
+ reclength+= group_null_items; // null flag is stored separately
+
+ table->blob_fields=blob_count;
+ if (blob_count == 0)
+ null_count++; // For delete link
+ reclength+=(null_pack_length=(null_count+7)/8);
+ if (!reclength)
+ reclength=1; // Dummy select
+
+ table->fields=field_count;
+ table->reclength=reclength;
+ {
+ uint alloc_length=ALIGN_SIZE(reclength+MI_UNIQUE_HASH_LENGTH+1);
+ table->rec_buff_length=alloc_length;
+ if (!(table->record[0]= (byte *) my_malloc(alloc_length*3, MYF(MY_WME))))
+ goto err;
+ table->record[1]= table->record[0]+alloc_length;
+ table->record[2]= table->record[1]+alloc_length;
+ }
+ copy_func[0]=0; // End marker
+
+ recinfo=param->start_recinfo;
+ null_flags=(uchar*) table->record[0];
+ pos=table->record[0]+ null_pack_length;
+ if (null_pack_length)
+ {
+ bzero((byte*) recinfo,sizeof(*recinfo));
+ recinfo->type=FIELD_NORMAL;
+ recinfo->length=null_pack_length;
+ recinfo++;
+ bfill(null_flags,null_pack_length,255); // Set null fields
+ }
+ null_count= (blob_count == 0) ? 1 : 0;
+ for (i=0,reg_field=table->field; i < field_count; i++,reg_field++,recinfo++)
+ {
+ Field *field= *reg_field;
+ uint length;
+ bzero((byte*) recinfo,sizeof(*recinfo));
+
+ if (!(field->flags & NOT_NULL_FLAG))
+ {
+ if (field->flags & GROUP_FLAG && !using_unique_constraint)
+ {
+ *pos++=0; // Null is stored here
+ recinfo->length=1;
+ recinfo->type=FIELD_NORMAL;
+ recinfo++;
+ bzero((byte*) recinfo,sizeof(*recinfo));
+ }
+ else
+ {
+ recinfo->null_bit= 1 << (null_count & 7);
+ recinfo->null_pos= null_count/8;
+ }
+ field->move_field((char*) pos,null_flags+null_count/8,
+ 1 << (null_count & 7));
+ null_count++;
+ }
+ else
+ field->move_field((char*) pos,(uchar*) 0,0);
+ field->reset();
+ if (from_field[i])
+ { /* Not a table Item */
+ copy->set(field,from_field[i],save_sum_fields);
+ copy++;
+ }
+ length=field->pack_length();
+ pos+= length;
+
+ /* Make entry for create table */
+ recinfo->length=length;
+ if (field->flags & BLOB_FLAG)
+ recinfo->type= (int) FIELD_BLOB;
+ else if (!field->zero_pack() &&
+ (field->type() == FIELD_TYPE_STRING ||
+ field->type() == FIELD_TYPE_VAR_STRING) &&
+ length >= 10 && blob_count)
+ recinfo->type=FIELD_SKIPP_ENDSPACE;
+ else
+ recinfo->type=FIELD_NORMAL;
+ }
+
+ param->copy_field_count=(uint) (copy - param->copy_field);
+ param->recinfo=recinfo;
+ store_record(table,2); // Make empty default record
+
+ table->max_rows=(((table->db_type == DB_TYPE_HEAP) ?
+ min(tmp_table_size, max_heap_table_size) : tmp_table_size)/
+ table->reclength);
+ set_if_bigger(table->max_rows,1); // For dummy start options
+ keyinfo=param->keyinfo;
+
+ if (group)
+ {
+ DBUG_PRINT("info",("Creating group key in temporary table"));
+ table->group=group; /* Table is grouped by key */
+ param->group_buff=group_buff;
+ table->keys=1;
+ table->uniques= test(using_unique_constraint);
+ table->key_info=keyinfo;
+ keyinfo->key_part=key_part_info;
+ keyinfo->flags=HA_NOSAME;
+ keyinfo->usable_key_parts=keyinfo->key_parts= param->group_parts;
+ keyinfo->key_length=0;
+ keyinfo->rec_per_key=0;
+ for (; group ; group=group->next,key_part_info++)
+ {
+ Field *field=(*group->item)->tmp_table_field();
+ bool maybe_null=(*group->item)->maybe_null;
+ key_part_info->field= field;
+ key_part_info->offset= field->offset();
+ key_part_info->length= (uint16) field->pack_length();
+ key_part_info->type= (uint8) field->key_type();
+ key_part_info->key_type =
+ ((ha_base_keytype) key_part_info->type == HA_KEYTYPE_TEXT ||
+ (ha_base_keytype) key_part_info->type == HA_KEYTYPE_VARTEXT) ?
+ 0 : FIELDFLAG_BINARY;
+ if (!using_unique_constraint)
+ {
+ group->buff=(char*) group_buff;
+ if (!(group->field=field->new_field(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
+ */
+ *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);
+ }
+ else
+ group->field->move_field((char*) group_buff);
+ group_buff+= key_part_info->length;
+ }
+ keyinfo->key_length+= key_part_info->length;
+ }
+ }
+
+ if (distinct && !group)
+ {
+ /* Create an unique key or an unique constraint over all columns */
+ keyinfo->key_parts=field_count+ test(null_count);
+ if (distinct && allow_distinct_limit)
+ {
+ set_if_smaller(table->max_rows,thd->select_limit);
+ param->end_write_records=thd->select_limit;
+ }
+ else
+ param->end_write_records= HA_POS_ERROR;
+ table->distinct=1;
+ table->keys=1;
+ if (blob_count)
+ {
+ using_unique_constraint=1;
+ table->uniques=1;
+ }
+ if (!(key_part_info= (KEY_PART_INFO*)
+ sql_calloc((keyinfo->key_parts)*sizeof(KEY_PART_INFO))))
+ goto err;
+ table->key_info=keyinfo;
+ keyinfo->key_part=key_part_info;
+ keyinfo->flags=HA_NOSAME;
+ keyinfo->key_length=(uint16) reclength;
+ keyinfo->name=(char*) "tmp";
+ if (null_count)
+ {
+ key_part_info->offset=0;
+ key_part_info->length=(null_count+7)/8;
+ key_part_info->field=new Field_string((char*) table->record[0],
+ (uint32) key_part_info->length,
+ (uchar*) 0,
+ (uint) 0,
+ Field::NONE,
+ NullS, table, (bool) 1);
+ key_part_info->key_type=FIELDFLAG_BINARY;
+ key_part_info->type= HA_KEYTYPE_BINARY;
+ key_part_info++;
+ }
+ for (i=0,reg_field=table->field; i < field_count;
+ i++, reg_field++, key_part_info++)
+ {
+ key_part_info->field= *reg_field;
+ key_part_info->offset= (*reg_field)->offset();
+ key_part_info->length= (uint16) (*reg_field)->pack_length();
+ key_part_info->type= (uint8) (*reg_field)->key_type();
+ key_part_info->key_type =
+ ((ha_base_keytype) key_part_info->type == HA_KEYTYPE_TEXT ||
+ (ha_base_keytype) key_part_info->type == HA_KEYTYPE_VARTEXT) ?
+ 0 : FIELDFLAG_BINARY;
+ }
+ }
+ if (thd->fatal_error) // If end of memory
+ goto err; /* purecov: inspected */
+ table->db_record_offset=1;
+ if (table->db_type == DB_TYPE_MYISAM)
+ {
+ if (create_myisam_tmp_table(table,param,select_options))
+ goto err;
+ }
+ if (!open_tmp_table(table))
+ DBUG_RETURN(table);
+
+ err:
+ free_tmp_table(thd,table); /* purecov: inspected */
+ DBUG_RETURN(NULL); /* purecov: inspected */
+}
+
+
+static bool open_tmp_table(TABLE *table)
+{
+ int error;
+ if ((error=table->file->ha_open(table->real_name,O_RDWR,HA_OPEN_TMP_TABLE)))
+ {
+ table->file->print_error(error,MYF(0)); /* purecov: inspected */
+ table->db_stat=0;
+ 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)
+{
+ int error;
+ MI_KEYDEF keydef;
+ MI_UNIQUEDEF uniquedef;
+ KEY *keyinfo=param->keyinfo;
+
+ DBUG_ENTER("create_myisam_tmp_table");
+ if (table->keys)
+ { // Get keys for ni_create
+ bool using_unique_constraint=0;
+ MI_KEYSEG *seg= (MI_KEYSEG*) sql_calloc(sizeof(*seg) *
+ keyinfo->key_parts);
+ if (!seg)
+ goto err;
+
+ if (keyinfo->key_length >= table->file->max_key_length() ||
+ keyinfo->key_parts > table->file->max_key_parts() ||
+ table->uniques)
+ {
+ /* Can't create a key; Make a unique constraint instead of a key */
+ table->keys=0;
+ table->uniques=1;
+ using_unique_constraint=1;
+ bzero((char*) &uniquedef,sizeof(uniquedef));
+ uniquedef.keysegs=keyinfo->key_parts;
+ uniquedef.seg=seg;
+ uniquedef.null_are_equal=1;
+
+ /* Create extra column for hash value */
+ bzero((byte*) param->recinfo,sizeof(*param->recinfo));
+ param->recinfo->type= FIELD_CHECK;
+ param->recinfo->length=MI_UNIQUE_HASH_LENGTH;
+ param->recinfo++;
+ table->reclength+=MI_UNIQUE_HASH_LENGTH;
+ }
+ else
+ {
+ /* Create an unique key */
+ bzero((char*) &keydef,sizeof(keydef));
+ keydef.flag=HA_NOSAME | HA_BINARY_PACK_KEY | HA_PACK_KEY;
+ keydef.keysegs= keyinfo->key_parts;
+ keydef.seg= seg;
+ }
+ 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;
+ if (field->flags & BLOB_FLAG)
+ {
+ seg->type=
+ ((keyinfo->key_part[i].key_type & FIELDFLAG_BINARY) ?
+ HA_KEYTYPE_VARBINARY : HA_KEYTYPE_VARTEXT);
+ seg->bit_start=seg->length - table->blob_ptr_size;
+ seg->flag= HA_BLOB_PART;
+ seg->length=0; // Whole blob in unique constraint
+ }
+ else
+ {
+ seg->type=
+ ((keyinfo->key_part[i].key_type & FIELDFLAG_BINARY) ?
+ HA_KEYTYPE_BINARY : HA_KEYTYPE_TEXT);
+ if (!(field->flags & ZEROFILL_FLAG) &&
+ (field->type() == FIELD_TYPE_STRING ||
+ field->type() == FIELD_TYPE_VAR_STRING) &&
+ keyinfo->key_part[i].length > 4)
+ seg->flag|=HA_SPACE_PACK;
+ }
+ if (using_unique_constraint &&
+ !(field->flags & NOT_NULL_FLAG))
+ {
+ seg->null_bit= field->null_bit;
+ seg->null_pos= (uint) (field->null_ptr - (uchar*) table->record[0]);
+ }
+ }
+ }
+ MI_CREATE_INFO create_info;
+ bzero((char*) &create_info,sizeof(create_info));
+ if (options & (OPTION_BIG_TABLES | SELECT_SMALL_RESULT) == OPTION_BIG_TABLES)
+ create_info.data_file_length= ~(ulonglong) 0;
+
+ if ((error=mi_create(table->real_name,table->keys,&keydef,
+ (uint) (param->recinfo-param->start_recinfo),
+ param->start_recinfo,
+ table->uniques, &uniquedef,
+ &create_info,
+ HA_CREATE_TMP_TABLE)))
+ {
+ table->file->print_error(error,MYF(0)); /* purecov: inspected */
+ table->db_stat=0;
+ goto err;
+ }
+ table->db_record_offset=1;
+ DBUG_RETURN(0);
+ err:
+ DBUG_RETURN(1);
+}
+
+
+void
+free_tmp_table(THD *thd, TABLE *entry)
+{
+ const char *save_proc_info;
+ DBUG_ENTER("free_tmp_table");
+ DBUG_PRINT("enter",("table: %s",entry->table_name));
+
+ save_proc_info=thd->proc_info;
+ thd->proc_info="removing tmp table";
+ if (entry->db_stat && entry->file)
+ {
+ (void) entry->file->close();
+ delete entry->file;
+ }
+ if (!(test_flags & TEST_KEEP_TMP_TABLES) || entry->db_type == DB_TYPE_HEAP)
+ (void) ha_delete_table(entry->db_type,entry->real_name);
+ /* free blobs */
+ for (Field **ptr=entry->field ; *ptr ; ptr++)
+ delete *ptr;
+ my_free((gptr) entry->record[0],MYF(0));
+ free_io_cache(entry);
+ my_free((gptr) entry,MYF(0));
+ thd->proc_info=save_proc_info;
+
+ DBUG_VOID_RETURN;
+}
+
+/*
+* If a HEAP table gets full, create a MyISAM table and copy all rows to this
+*/
+
+bool create_myisam_from_heap(TABLE *table, TMP_TABLE_PARAM *param, int error,
+ bool ignore_last_dupp_key_error)
+{
+ TABLE new_table;
+ const char *save_proc_info;
+ THD *thd=current_thd;
+ int write_err;
+ DBUG_ENTER("create_myisam_from_heap");
+
+ if (table->db_type != DB_TYPE_HEAP || error != HA_ERR_RECORD_FILE_FULL)
+ {
+ table->file->print_error(error,MYF(0));
+ DBUG_RETURN(1);
+ }
+ new_table= *table;
+ new_table.db_type=DB_TYPE_MYISAM;
+ if (!(new_table.file=get_new_handler(&new_table,DB_TYPE_MYISAM)))
+ DBUG_RETURN(1); // End of memory
+
+ save_proc_info=thd->proc_info;
+ thd->proc_info="converting HEAP to MyISAM";
+
+ if (create_myisam_tmp_table(&new_table,param,
+ thd->lex.options | thd->options))
+ goto err2;
+ if (open_tmp_table(&new_table))
+ goto err1;
+ table->file->index_end();
+ table->file->rnd_init();
+ /* copy all old rows */
+ while (!table->file->rnd_next(new_table.record[1]))
+ {
+ if ((write_err=new_table.file->write_row(new_table.record[1])))
+ goto err;
+ }
+ /* copy row that filled HEAP table */
+ if ((write_err=new_table.file->write_row(table->record[0])))
+ {
+ if (write_err != HA_ERR_FOUND_DUPP_KEY &&
+ write_err != HA_ERR_FOUND_DUPP_UNIQUE || !ignore_last_dupp_key_error)
+ goto err;
+ }
+
+ /* remove heap table and change to use myisam table */
+ (void) table->file->rnd_end();
+ (void) table->file->close();
+ (void) table->file->delete_table(table->real_name);
+ delete table->file;
+ table->file=0;
+ *table =new_table;
+ table->file->change_table_ptr(table);
+
+ thd->proc_info=save_proc_info;
+ DBUG_RETURN(0);
+
+ err:
+ DBUG_PRINT("error",("Got error: %d",write_err));
+ table->file->print_error(error,MYF(0)); // Give table is full error
+ (void) table->file->rnd_end();
+ (void) new_table.file->close();
+ err1:
+ new_table.file->delete_table(new_table.real_name);
+ delete new_table.file;
+ err2:
+ thd->proc_info=save_proc_info;
+ DBUG_RETURN(1);
+}
+
+
+/*****************************************************************************
+** Make a join of all tables and write it on socket or to table
+*****************************************************************************/
+
+static int
+do_select(JOIN *join,List<Item> *fields,TABLE *table,Procedure *procedure)
+{
+ int error;
+ JOIN_TAB *join_tab;
+ int (*end_select)(JOIN *, struct st_join_table *,bool);
+ DBUG_ENTER("do_select");
+
+ join->procedure=procedure;
+ /*
+ ** Tell the client how many fields there are in a row
+ */
+ if (!table)
+ join->result->send_fields(*fields,1);
+ else
+ {
+ VOID(table->file->extra(HA_EXTRA_WRITE_CACHE));
+ empty_record(table);
+ }
+ join->tmp_table=table; /* Save for easy recursion */
+ join->fields= fields;
+
+ /* Set up select_end */
+ if (table)
+ {
+ if (table->group && join->tmp_table_param.sum_func_count)
+ {
+ DBUG_PRINT("info",("Using end_update"));
+ if (table->keys)
+ {
+ end_select=end_update;
+ table->file->index_init(0);
+ }
+ else
+ end_select=end_unique_update;
+ }
+ else if (join->sort_and_group)
+ {
+ DBUG_PRINT("info",("Using end_write_group"));
+ end_select=end_write_group;
+ }
+ else
+ {
+ DBUG_PRINT("info",("Using end_write"));
+ end_select=end_write;
+ }
+ }
+ else
+ {
+ if (join->sort_and_group || (join->procedure &&
+ join->procedure->flags & PROC_GROUP))
+ end_select=end_send_group;
+ else
+ end_select=end_send;
+ }
+ join->join_tab[join->tables-1].next_select=end_select;
+
+ join_tab=join->join_tab+join->const_tables;
+ join->send_records=0;
+ if (join->tables == join->const_tables)
+ {
+ if (!(error=(*end_select)(join,join_tab,0)) || error == -3)
+ error=(*end_select)(join,join_tab,1);
+ }
+ else
+ {
+ error=sub_select(join,join_tab,0);
+ if (error >= 0)
+ error=sub_select(join,join_tab,1);
+ if (error == -3)
+ error=0; /* select_limit used */
+ }
+ if (!table)
+ {
+ if (error < 0)
+ join->result->send_error(0,NullS); /* purecov: inspected */
+ else if (join->result->send_eof())
+ error= -1;
+ }
+ 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)
+ {
+ int old_error=error,tmp;
+ if ((tmp=table->file->extra(HA_EXTRA_NO_CACHE)))
+ {
+ my_errno=tmp;
+ error= -1;
+ }
+ if (table->file->index_end())
+ {
+ my_errno=tmp;
+ error= -1;
+ }
+ if (error != old_error)
+ table->file->print_error(my_errno,MYF(0));
+ }
+ DBUG_RETURN(error < 0);
+}
+
+
+static int
+sub_select_cache(JOIN *join,JOIN_TAB *join_tab,bool end_of_records)
+{
+ int error;
+
+ if (end_of_records)
+ {
+ if ((error=flush_cached_records(join,join_tab,FALSE)) < 0)
+ return error; /* purecov: inspected */
+ return sub_select(join,join_tab,end_of_records);
+ }
+ if (join_tab->use_quick != 2 || test_if_quick_select(join_tab) <= 0)
+ {
+ if (join->thd->killed)
+ {
+ my_error(ER_SERVER_SHUTDOWN,MYF(0)); /* purecov: inspected */
+ return -2; // Aborted by user /* purecov: inspected */
+ }
+ if (!store_record_in_cache(&join_tab->cache))
+ return 0; // There is more room in cache
+ return flush_cached_records(join,join_tab,FALSE);
+ }
+ if ((error=flush_cached_records(join,join_tab,TRUE)) < 0)
+ return error; /* purecov: inspected */
+ return sub_select(join,join_tab,end_of_records); /* Use ordinary select */
+}
+
+
+static int
+sub_select(JOIN *join,JOIN_TAB *join_tab,bool end_of_records)
+{
+
+ join_tab->table->null_row=0;
+ if (end_of_records)
+ return (*join_tab->next_select)(join,join_tab+1,end_of_records);
+
+ /* Cache variables for faster loop */
+ int error;
+ bool found=0;
+ COND *on_expr=join_tab->on_expr, *select_cond=join_tab->select_cond;
+ int (*next_select)(JOIN *,struct st_join_table *,bool)=
+ join_tab->next_select;
+
+ if (!(error=(*join_tab->read_first_record)(join_tab)))
+ {
+ bool not_exists_optimize=join_tab->table->reginfo.not_exists_optimize;
+ READ_RECORD *info= &join_tab->read_record;
+
+ do
+ {
+ if (join->thd->killed) // Aborted by user
+ {
+ my_error(ER_SERVER_SHUTDOWN,MYF(0)); /* purecov: inspected */
+ return -2; /* purecov: inspected */
+ }
+ if (!on_expr || on_expr->val_int())
+ {
+ found=1;
+ if (not_exists_optimize)
+ break; // Searching after not null columns
+ if (!select_cond || select_cond->val_int())
+ {
+ if ((error=(*next_select)(join,join_tab+1,0)) < 0)
+ return error;
+ }
+ }
+ } while (!(error=info->read_record(info)));
+ if (error > 0) // Fatal error
+ return -1;
+ }
+ else if (error > 0)
+ return -1;
+
+ if (!found && on_expr)
+ { // OUTER JOIN
+ restore_record(join_tab->table,2); // Make empty record
+ mark_as_null_row(join_tab->table); // For group by without error
+ if (!select_cond || select_cond->val_int())
+ {
+ if ((error=(*next_select)(join,join_tab+1,0)) < 0)
+ return error; /* purecov: inspected */
+ }
+ }
+ return 0;
+}
+
+
+static int
+flush_cached_records(JOIN *join,JOIN_TAB *join_tab,bool skipp_last)
+{
+ int error;
+ READ_RECORD *info;
+
+ if (!join_tab->cache.records)
+ return 0; /* Nothing to do */
+ if (skipp_last)
+ (void) store_record_in_cache(&join_tab->cache); // Must save this for later
+ if (join_tab->use_quick == 2)
+ {
+ if (join_tab->select->quick)
+ { /* Used quick select last. reset it */
+ delete join_tab->select->quick;
+ join_tab->select->quick=0;
+ }
+ }
+ /* read through all records */
+ if ((error=join_init_read_record(join_tab)))
+ {
+ reset_cache(&join_tab->cache);
+ join_tab->cache.records=0; join_tab->cache.ptr_record= (uint) ~0;
+ return -error; /* No records or error */
+ }
+
+ for (JOIN_TAB *tmp=join->join_tab; tmp != join_tab ; tmp++)
+ {
+ tmp->status=tmp->table->status;
+ tmp->table->status=0;
+ }
+
+ info= &join_tab->read_record;
+ do
+ {
+ if (join->thd->killed)
+ {
+ my_error(ER_SERVER_SHUTDOWN,MYF(0)); /* purecov: inspected */
+ return -2; // Aborted by user /* purecov: inspected */
+ }
+ SQL_SELECT *select=join_tab->select;
+ if (!error && (!join_tab->cache.select ||
+ !join_tab->cache.select->skipp_record()))
+ {
+ uint i;
+ reset_cache(&join_tab->cache);
+ for (i=(join_tab->cache.records- (skipp_last ? 1 : 0)) ; i-- > 0 ;)
+ {
+ read_cached_record(join_tab);
+ if (!select || !select->skipp_record())
+ if ((error=(join_tab->next_select)(join,join_tab+1,0)) < 0)
+ return error; /* purecov: inspected */
+ }
+ }
+ } while (!(error=info->read_record(info)));
+
+ if (skipp_last)
+ read_cached_record(join_tab); // Restore current record
+ reset_cache(&join_tab->cache);
+ join_tab->cache.records=0; join_tab->cache.ptr_record= (uint) ~0;
+ if (error > 0) // Fatal error
+ return -1; /* purecov: inspected */
+ for (JOIN_TAB *tmp2=join->join_tab; tmp2 != join_tab ; tmp2++)
+ tmp2->table->status=tmp2->status;
+ return 0;
+}
+
+
+/*****************************************************************************
+** The different ways to read a record
+** Returns -1 if row was not found, 0 if row was found and 1 on errors
+*****************************************************************************/
+
+static int
+join_read_const_tables(JOIN *join)
+{
+ 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);
+ }
+ }
+ if (join->join_tab[i].on_expr && !form->null_row)
+ {
+ if ((form->null_row= test(join->join_tab[i].on_expr->val_int() == 0)))
+ empty_record(form);
+ }
+ if (!form->null_row)
+ form->maybe_null=0;
+ }
+ DBUG_RETURN(0);
+}
+
+
+static int
+join_read_system(JOIN_TAB *tab)
+{
+ TABLE *table= tab->table;
+ int error;
+ if (table->status & STATUS_GARBAGE) // If first read
+ {
+ if ((error=table->file->rnd_first(table->record[0])))
+ {
+ if (error != HA_ERR_END_OF_FILE)
+ {
+ table->file->print_error(error,MYF(0));
+ return 1;
+ }
+ table->null_row=1; // This is ok.
+ empty_record(table); // Make empty record
+ return -1;
+ }
+ store_record(table,1);
+ }
+ else if (!table->status) // Only happens with left join
+ restore_record(table,1); // restore old record
+ table->null_row=0;
+ return table->status ? -1 : 0;
+}
+
+
+static int
+join_read_const(JOIN_TAB *tab)
+{
+ int error;
+ TABLE *table= tab->table;
+ if (table->status & STATUS_GARBAGE) // If first read
+ {
+ if (cp_buffer_from_ref(&tab->ref))
+ error=HA_ERR_KEY_NOT_FOUND;
+ else
+ {
+ error=table->file->index_read_idx(table->record[0],tab->ref.key,
+ (byte*) tab->ref.key_buff,
+ tab->ref.key_length,HA_READ_KEY_EXACT);
+ }
+ if (error)
+ {
+ table->null_row=1;
+ empty_record(table);
+ if (error != HA_ERR_KEY_NOT_FOUND)
+ {
+ sql_print_error("read_const: Got error %d when reading table %s",
+ error, table->real_name);
+ table->file->print_error(error,MYF(0));
+ return 1;
+ }
+ return -1;
+ }
+ store_record(table,1);
+ }
+ else if (!table->status) // Only happens with left join
+ restore_record(table,1); // restore old record
+ table->null_row=0;
+ return table->status ? -1 : 0;
+}
+
+
+static int
+join_read_key(JOIN_TAB *tab)
+{
+ int error;
+ TABLE *table= tab->table;
+
+ if (cmp_buffer_with_ref(tab) ||
+ (table->status & (STATUS_GARBAGE | STATUS_NO_PARENT)))
+ {
+ if (tab->ref.key_err)
+ {
+ table->status=STATUS_NOT_FOUND;
+ return -1;
+ }
+ error=table->file->index_read(table->record[0],
+ tab->ref.key_buff,
+ tab->ref.key_length,HA_READ_KEY_EXACT);
+ if (error && error != HA_ERR_KEY_NOT_FOUND)
+ {
+ sql_print_error("read_key: Got error %d when reading table '%s'",error,
+ table->real_name);
+ table->file->print_error(error,MYF(0));
+ return 1;
+ }
+ }
+ return table->status ? -1 : 0;
+}
+
+
+static int
+join_read_always_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(table->record[0],
+ tab->ref.key_buff,
+ tab->ref.key_length,HA_READ_KEY_EXACT)))
+ {
+ if (error != HA_ERR_KEY_NOT_FOUND)
+ {
+ sql_print_error("read_const: Got error %d when reading table %s",error,
+ table->real_name);
+ table->file->print_error(error,MYF(0));
+ return 1;
+ }
+ return -1; /* purecov: inspected */
+ }
+ return 0;
+}
+
+
+ /* ARGSUSED */
+static int
+join_no_more_records(READ_RECORD *info __attribute__((unused)))
+{
+ return -1;
+}
+
+
+static int
+join_read_next(READ_RECORD *info)
+{
+ int error;
+ TABLE *table= info->table;
+ JOIN_TAB *tab=table->reginfo.join_tab;
+
+ if ((error=table->file->index_next_same(table->record[0],
+ tab->ref.key_buff,
+ tab->ref.key_length)))
+ {
+ if (error != HA_ERR_END_OF_FILE)
+ {
+ sql_print_error("read_next: Got error %d when reading table %s",error,
+ table->real_name);
+ table->file->print_error(error,MYF(0));
+ return 1;
+ }
+ table->status= STATUS_GARBAGE;
+ return -1;
+ }
+ return 0;
+}
+
+
+static int
+join_init_quick_read_record(JOIN_TAB *tab)
+{
+ if (test_if_quick_select(tab) == -1)
+ return -1; /* No possible records */
+ return join_init_read_record(tab);
+}
+
+
+static int
+test_if_quick_select(JOIN_TAB *tab)
+{
+ delete tab->select->quick;
+ tab->select->quick=0;
+ return tab->select->test_quick_select(tab->keys,(table_map) 0,HA_POS_ERROR);
+}
+
+
+static int
+join_init_read_record(JOIN_TAB *tab)
+{
+ if (tab->select && tab->select->quick)
+ tab->select->quick->reset();
+ init_read_record(&tab->read_record,current_thd, tab->table, tab->select,1,1);
+ return (*tab->read_record.read_record)(&tab->read_record);
+}
+
+static int
+join_init_read_first_with_key(JOIN_TAB *tab)
+{
+ int error;
+ TABLE *table=tab->table;
+ if (!table->key_read && (table->used_keys & ((key_map) 1 << tab->index)))
+ {
+ 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.table=table;
+ tab->read_record.file=table->file;
+ tab->read_record.index=tab->index;
+ tab->read_record.record=table->record[0];
+ tab->table->file->index_init(tab->index);
+ error=tab->table->file->index_first(tab->table->record[0]);
+ if (error)
+ {
+ if (error != HA_ERR_KEY_NOT_FOUND && error != HA_ERR_END_OF_FILE)
+ {
+ sql_print_error("read_first_with_key: Got error %d when reading table",error);
+ table->file->print_error(error,MYF(0));
+ return 1;
+ }
+ return -1;
+ }
+ return 0;
+}
+
+static int
+join_init_read_next_with_key(READ_RECORD *info)
+{
+ int error=info->file->index_next(info->record);
+ if (error)
+ {
+ if (error != HA_ERR_END_OF_FILE)
+ {
+ sql_print_error("read_next_with_key: Got error %d when reading table %s",
+ error, info->table->real_name);
+ info->file->print_error(error,MYF(0));
+ return 1;
+ }
+ return -1;
+ }
+ return 0;
+}
+
+static int
+join_init_read_last_with_key(JOIN_TAB *tab)
+{
+ TABLE *table=tab->table;
+ int error;
+ if (!table->key_read && (table->used_keys & ((key_map) 1 << tab->index)))
+ {
+ table->key_read=1;
+ table->file->extra(HA_EXTRA_KEYREAD);
+ }
+ tab->table->status=0;
+ tab->read_record.read_record=join_init_read_prev_with_key;
+ tab->read_record.table=table;
+ tab->read_record.file=table->file;
+ tab->read_record.index=tab->index;
+ tab->read_record.record=table->record[0];
+ tab->table->file->index_init(tab->index);
+ error=tab->table->file->index_last(tab->table->record[0]);
+ if (error)
+ {
+ if (error != HA_ERR_END_OF_FILE)
+ {
+ sql_print_error("read_first_with_key: Got error %d when reading table",
+ error, table->real_name);
+ table->file->print_error(error,MYF(0));
+ return 1;
+ }
+ return -1;
+ }
+ return 0;
+}
+
+static int
+join_init_read_prev_with_key(READ_RECORD *info)
+{
+ int error=info->file->index_prev(info->record);
+ if (error)
+ {
+ if (error != HA_ERR_END_OF_FILE)
+ {
+ sql_print_error("read_prev_with_key: Got error %d when reading table: %s",
+ error,info->table->real_name);
+ info->file->print_error(error,MYF(0));
+ return 1;
+ }
+ return -1;
+ }
+ return 0;
+}
+
+static int
+join_ft_read_first(JOIN_TAB *tab)
+{
+ int error;
+ TABLE *table= tab->table;
+
+#if 0
+ if (cp_buffer_from_ref(&tab->ref)) // as ft-key doesn't use store_key's
+ return -1;
+#endif
+ if ((error=table->file->ft_init(tab->ref.key,
+ tab->ref.key_buff,
+ tab->ref.key_length,TRUE)))
+ {
+ if (error != HA_ERR_KEY_NOT_FOUND)
+ {
+ sql_print_error("ft_read_first/init: Got error %d when reading table %s",error,
+ table->real_name);
+ table->file->print_error(error,MYF(0));
+ return 1;
+ }
+ return -1;
+ }
+
+ error=table->file->ft_read(table->record[0]);
+ if (error)
+ {
+ if (error != HA_ERR_END_OF_FILE)
+ {
+ sql_print_error("ft_read_first/read: Got error %d when reading table %s",
+ error, table->real_name);
+ table->file->print_error(error,MYF(0));
+ return 1;
+ }
+ table->file->ft_close();
+ return -1;
+ }
+ return 0;
+}
+
+static int
+join_ft_read_next(READ_RECORD *info)
+{
+ int error=info->file->ft_read(info->table->record[0]);
+ if (error)
+ {
+ if (error != HA_ERR_END_OF_FILE)
+ {
+ sql_print_error("ft_read_next: Got error %d when reading table %s",
+ error, info->table->real_name);
+ info->file->print_error(error,MYF(0));
+ return 1;
+ }
+ info->file->ft_close();
+ return -1;
+ }
+ return 0;
+}
+
+
+/*****************************************************************************
+** The different end of select functions
+** These functions returns < 0 when end is reached, 0 on ok and > 0 if a
+** fatal error (like table corruption) was detected
+*****************************************************************************/
+
+ /* ARGSUSED */
+static int
+end_send(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
+ bool end_of_records)
+{
+ DBUG_ENTER("end_send");
+ if (!end_of_records)
+ {
+ int error;
+ if (join->having && join->having->val_int() == 0.0)
+ DBUG_RETURN(0); // Didn't match having
+ if (join->procedure)
+ error=join->procedure->send_row(*join->fields);
+ else
+ error=join->result->send_data(*join->fields);
+ if (error)
+ DBUG_RETURN(-1); /* purecov: inspected */
+ if (++join->send_records >= join->thd->select_limit)
+ DBUG_RETURN(-3); // Abort nicely
+ }
+ else
+ {
+ if (join->procedure && join->procedure->end_of_records())
+ DBUG_RETURN(-1);
+ }
+ DBUG_RETURN(0);
+}
+
+
+ /* ARGSUSED */
+static int
+end_send_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
+ bool end_of_records)
+{
+ int idx= -1;
+ DBUG_ENTER("end_send_group");
+
+ if (!join->first_record || end_of_records ||
+ (idx=test_if_group_changed(join->group_fields)) >= 0)
+ {
+ if (join->first_record || (end_of_records && !join->group))
+ {
+ if (join->procedure)
+ join->procedure->end_group();
+ if (idx < (int) join->send_group_parts)
+ {
+ int error;
+ if (join->procedure)
+ {
+ if (join->having && join->having->val_int() == 0.0)
+ error= -1; // Didn't satisfy having
+ else
+ error=join->procedure->send_row(*join->fields) ? 1 : 0;
+ if (end_of_records && join->procedure->end_of_records())
+ error= 1; // Fatal error
+ }
+ else
+ {
+ if (!join->first_record)
+ clear_tables(join);
+ if (join->having && join->having->val_int() == 0.0)
+ error= -1; // Didn't satisfy having
+ else
+ error=join->result->send_data(*join->fields) ? 1 : 0;
+ }
+ if (error > 0)
+ 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 */
+ }
+ }
+ else
+ {
+ if (end_of_records)
+ DBUG_RETURN(0);
+ join->first_record=1;
+ VOID(test_if_group_changed(join->group_fields));
+ }
+ if (idx < (int) join->send_group_parts)
+ {
+ copy_fields(&join->tmp_table_param);
+ init_sum_functions(join->sum_funcs);
+ if (join->procedure)
+ join->procedure->add();
+ DBUG_RETURN(0);
+ }
+ }
+ if (update_sum_func(join->sum_funcs))
+ DBUG_RETURN(-1);
+ if (join->procedure)
+ join->procedure->add();
+ DBUG_RETURN(0);
+}
+
+
+ /* ARGSUSED */
+static int
+end_write(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
+ bool end_of_records)
+{
+ TABLE *table=join->tmp_table;
+ int error;
+ DBUG_ENTER("end_write");
+
+ if (join->thd->killed) // Aborted by user
+ {
+ my_error(ER_SERVER_SHUTDOWN,MYF(0)); /* purecov: inspected */
+ DBUG_RETURN(-2); /* purecov: inspected */
+ }
+ if (!end_of_records)
+ {
+ copy_fields(&join->tmp_table_param);
+ copy_funcs(join->tmp_table_param.funcs);
+
+ if (!table->uniques) // If not unique handling
+ {
+ /* Copy null values from group to row */
+ ORDER *group;
+ for (group=table->group ; group ; group=group->next)
+ {
+ Item *item= *group->item;
+ if (item->maybe_null)
+ {
+ Field *field=item->tmp_table_field();
+ field->ptr[-1]= (byte) (field->is_null() ? 0 : 1);
+ }
+ }
+ }
+ if (!join->having || join->having->val_int())
+ {
+ if ((error=table->file->write_row(table->record[0])))
+ {
+ if (error != HA_ERR_FOUND_DUPP_KEY &&
+ error != HA_ERR_FOUND_DUPP_UNIQUE)
+ {
+ if (create_myisam_from_heap(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
+ }
+ }
+ else
+ {
+ if (++join->send_records >= join->tmp_table_param.end_write_records)
+ DBUG_RETURN(-3);
+ }
+ }
+ }
+ DBUG_RETURN(0);
+}
+
+/* Group by searching after group record and updating it if possible */
+/* ARGSUSED */
+
+static int
+end_update(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
+ bool end_of_records)
+{
+ TABLE *table=join->tmp_table;
+ ORDER *group;
+ int error;
+ DBUG_ENTER("end_update");
+
+ if (end_of_records)
+ DBUG_RETURN(0);
+ if (join->thd->killed) // Aborted by user
+ {
+ my_error(ER_SERVER_SHUTDOWN,MYF(0)); /* purecov: inspected */
+ DBUG_RETURN(-2); /* purecov: inspected */
+ }
+
+ copy_fields(&join->tmp_table_param); // Groups are copied twice.
+ /* Make a key of group index */
+ for (group=table->group ; group ; group=group->next)
+ {
+ Item *item= *group->item;
+ item->save_org_in_field(group->field);
+ if (item->maybe_null)
+ group->buff[0]=item->null_value ? 0: 1; // Save reversed value
+ }
+ // table->file->index_init(0);
+ if (!table->file->index_read(table->record[1],
+ join->tmp_table_param.group_buff,0,
+ HA_READ_KEY_EXACT))
+ { /* Update old record */
+ restore_record(table,1);
+ update_tmptable_sum_func(join->sum_funcs,table);
+ if ((error=table->file->update_row(table->record[1],
+ table->record[0])))
+ {
+ table->file->print_error(error,MYF(0)); /* purecov: inspected */
+ DBUG_RETURN(-1); /* purecov: inspected */
+ }
+ DBUG_RETURN(0);
+ }
+
+ /* The null bits are already set */
+ KEY_PART_INFO *key_part;
+ for (group=table->group,key_part=table->key_info[0].key_part;
+ group ;
+ group=group->next,key_part++)
+ memcpy(table->record[0]+key_part->offset, group->buff, key_part->length);
+
+ init_tmptable_sum_functions(join->sum_funcs);
+ copy_funcs(join->tmp_table_param.funcs);
+ if ((error=table->file->write_row(table->record[0])))
+ {
+ if (create_myisam_from_heap(table, &join->tmp_table_param, error, 0))
+ DBUG_RETURN(-1); // Not a table_is_full error
+ /* Change method to update rows */
+ table->file->index_init(0);
+ join->join_tab[join->tables-1].next_select=end_unique_update;
+ }
+ join->send_records++;
+ DBUG_RETURN(0);
+}
+
+/* Like end_update, but this is done with unique constraints instead of keys */
+
+static int
+end_unique_update(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
+ bool end_of_records)
+{
+ TABLE *table=join->tmp_table;
+ int error;
+ DBUG_ENTER("end_unique_update");
+
+ if (end_of_records)
+ DBUG_RETURN(0);
+ if (join->thd->killed) // Aborted by user
+ {
+ my_error(ER_SERVER_SHUTDOWN,MYF(0)); /* purecov: inspected */
+ DBUG_RETURN(-2); /* purecov: inspected */
+ }
+
+ init_tmptable_sum_functions(join->sum_funcs);
+ copy_fields(&join->tmp_table_param); // Groups are copied twice.
+ copy_funcs(join->tmp_table_param.funcs);
+
+ if (!(error=table->file->write_row(table->record[0])))
+ join->send_records++; // New group
+ else
+ {
+ if ((int) table->file->get_dup_key(error) < 0)
+ {
+ table->file->print_error(error,MYF(0)); /* purecov: inspected */
+ DBUG_RETURN(-1); /* purecov: inspected */
+ }
+ if (table->file->rnd_pos(table->record[1],table->file->dupp_ref))
+ {
+ table->file->print_error(error,MYF(0)); /* purecov: inspected */
+ DBUG_RETURN(-1); /* purecov: inspected */
+ }
+ restore_record(table,1);
+ update_tmptable_sum_func(join->sum_funcs,table);
+ if ((error=table->file->update_row(table->record[1],
+ table->record[0])))
+ {
+ table->file->print_error(error,MYF(0)); /* purecov: inspected */
+ DBUG_RETURN(-1); /* purecov: inspected */
+ }
+ }
+ DBUG_RETURN(0);
+}
+
+
+ /* ARGSUSED */
+static int
+end_write_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
+ bool end_of_records)
+{
+ TABLE *table=join->tmp_table;
+ int error;
+ int idx= -1;
+ DBUG_ENTER("end_write_group");
+
+ if (join->thd->killed)
+ { // Aborted by user
+ my_error(ER_SERVER_SHUTDOWN,MYF(0)); /* purecov: inspected */
+ DBUG_RETURN(-2); /* purecov: inspected */
+ }
+ if (!join->first_record || end_of_records ||
+ (idx=test_if_group_changed(join->group_fields)) >= 0)
+ {
+ if (join->first_record || (end_of_records && !join->group))
+ {
+ if (join->procedure)
+ join->procedure->end_group();
+ if (idx < (int) join->send_group_parts)
+ {
+ if (!join->first_record)
+ clear_tables(join);
+ copy_sum_funcs(join->sum_funcs);
+ if (!join->having || join->having->val_int())
+ {
+ if ((error=table->file->write_row(table->record[0])))
+ {
+ if (create_myisam_from_heap(table, &join->tmp_table_param,
+ error, 0))
+ DBUG_RETURN(1); // Not a table_is_full error
+ }
+ else
+ join->send_records++;
+ }
+ if (end_of_records)
+ DBUG_RETURN(0);
+ }
+ }
+ else
+ {
+ join->first_record=1;
+ VOID(test_if_group_changed(join->group_fields));
+ }
+ if (idx < (int) join->send_group_parts)
+ {
+ copy_fields(&join->tmp_table_param);
+ copy_funcs(join->tmp_table_param.funcs);
+ init_sum_functions(join->sum_funcs);
+ if (join->procedure)
+ join->procedure->add();
+ DBUG_RETURN(0);
+ }
+ }
+ if (update_sum_func(join->sum_funcs))
+ DBUG_RETURN(-1);
+ if (join->procedure)
+ join->procedure->add();
+ DBUG_RETURN(0);
+}
+
+
+/*****************************************************************************
+** Remove calculation with tables that aren't yet read. Remove also tests
+** against fields that are read through key.
+** We can't remove tests that are made against columns which are stored
+** in sorted order.
+*****************************************************************************/
+
+/* Return 1 if right_item is used removable reference key on left_item */
+
+static bool test_if_ref(Item_field *left_item,Item *right_item)
+{
+ Field *field=left_item->field;
+ if (!field->table->const_table) // No need to change const test
+ {
+ Item *ref_item=part_of_refkey(field->table,field);
+ if (ref_item && ref_item->eq(right_item))
+ {
+ if (right_item->type() == Item::FIELD_ITEM)
+ return field->eq_def(((Item_field *) right_item)->field);
+ if (right_item->const_item())
+ {
+ // We can remove binary fields and numerical fields except float,
+ // as float comparison isn't 100 % secure
+ if (field->binary() &&
+ (field->type() != FIELD_TYPE_FLOAT || field->decimals() == 0))
+ {
+ return !store_val_in_field(field,right_item);
+ }
+ }
+ }
+ }
+ return 0; // keep test
+}
+
+
+static COND *
+make_cond_for_table(COND *cond,table_map tables,table_map used_table)
+{
+ if (used_table && !(cond->used_tables() & used_table))
+ return (COND*) 0; // Already checked
+ if (cond->type() == Item::COND_ITEM)
+ {
+ if (((Item_cond*) cond)->functype() == Item_func::COND_AND_FUNC)
+ {
+ Item_cond_and *new_cond=new Item_cond_and;
+ if (!new_cond)
+ return (COND*) 0; // OOM /* purecov: inspected */
+ List_iterator<Item> li(*((Item_cond*) cond)->argument_list());
+ Item *item;
+ while ((item=li++))
+ {
+ Item *fix=make_cond_for_table(item,tables,used_table);
+ if (fix)
+ new_cond->argument_list()->push_back(fix);
+ }
+ switch (new_cond->argument_list()->elements) {
+ case 0:
+ return (COND*) 0; // Always true
+ case 1:
+ return new_cond->argument_list()->head();
+ default:
+ new_cond->used_tables_cache=((Item_cond*) cond)->used_tables_cache &
+ tables;
+ return new_cond;
+ }
+ }
+ else
+ { // Or list
+ Item_cond_or *new_cond=new Item_cond_or;
+ if (!new_cond)
+ return (COND*) 0; // OOM /* purecov: inspected */
+ List_iterator<Item> li(*((Item_cond*) cond)->argument_list());
+ Item *item;
+ while ((item=li++))
+ {
+ Item *fix=make_cond_for_table(item,tables,0L);
+ if (!fix)
+ return (COND*) 0; // Always true
+ new_cond->argument_list()->push_back(fix);
+ }
+ new_cond->used_tables_cache=((Item_cond_or*) cond)->used_tables_cache;
+ return new_cond;
+ }
+ }
+
+ /*
+ ** Because the following test takes a while and it can be done
+ ** table_count times, we mark each item that we have examined with the result
+ ** of the test
+ */
+
+ if (cond->marker == 3 || (cond->used_tables() & ~tables))
+ return (COND*) 0; // Can't check this yet
+ if (cond->marker == 2 || cond->eq_cmp_result() == Item::COND_OK)
+ return cond; // Not boolean op
+
+ if (((Item_func*) cond)->functype() == Item_func::EQ_FUNC)
+ {
+ Item *left_item= ((Item_func*) cond)->arguments()[0];
+ Item *right_item= ((Item_func*) cond)->arguments()[1];
+ if (left_item->type() == Item::FIELD_ITEM &&
+ test_if_ref((Item_field*) left_item,right_item))
+ {
+ cond->marker=3; // Checked when read
+ return (COND*) 0;
+ }
+ if (right_item->type() == Item::FIELD_ITEM &&
+ test_if_ref((Item_field*) right_item,left_item))
+ {
+ cond->marker=3; // Checked when read
+ return (COND*) 0;
+ }
+ }
+ cond->marker=2;
+ return cond;
+}
+
+static Item *
+part_of_refkey(TABLE *table,Field *field)
+{
+ uint ref_parts=table->reginfo.join_tab->ref.key_parts;
+ if (ref_parts)
+ {
+ KEY_PART_INFO *key_part=
+ table->key_info[table->reginfo.join_tab->ref.key].key_part;
+
+ for (uint part=0 ; part < ref_parts ; part++,key_part++)
+ if (field->eq(key_part->field) &&
+ !(key_part->key_part_flag & HA_PART_KEY))
+ return table->reginfo.join_tab->ref.items[part];
+ }
+ return (Item*) 0;
+}
+
+
+/*****************************************************************************
+** Test if one can use the key to resolve ORDER BY
+** Returns: 1 if key is ok.
+** 0 if key can't be used
+** -1 if reverse key can be used
+*****************************************************************************/
+
+static int test_if_order_by_key(ORDER *order, TABLE *table, uint idx)
+{
+ KEY_PART_INFO *key_part,*key_part_end;
+ key_part=table->key_info[idx].key_part;
+ key_part_end=key_part+table->key_info[idx].key_parts;
+ key_part_map const_key_parts=table->const_key_parts[idx];
+ int reverse=0;
+
+ for (; order ; order=order->next, const_key_parts>>=1)
+ {
+ Field *field=((Item_field*) (*order->item))->field;
+ int flag;
+
+ /*
+ Skip key parts that are constants in the WHERE clause.
+ These are already skipped in the ORDER BY by const_expression_in_where()
+ */
+ while (const_key_parts & 1)
+ {
+ key_part++; const_key_parts>>=1;
+ }
+ if (key_part == key_part_end || key_part->field != field)
+ return 0;
+
+ /* set flag to 1 if we can use read-next on key, else to -1 */
+ flag=(order->asc == !(key_part->key_part_flag & HA_REVERSE_SORT))
+ ? 1 : -1;
+ if (reverse && flag != reverse)
+ return 0;
+ reverse=flag; // Remember if reverse
+ key_part++;
+ }
+ return reverse;
+}
+
+static uint find_shortest_key(TABLE *table, key_map usable_keys)
+{
+ uint min_length= (uint) ~0;
+ uint best= MAX_KEY;
+ for (uint nr=0; usable_keys ; usable_keys>>=1, nr++)
+ {
+ if (usable_keys & 1)
+ {
+ if (table->key_info[nr].key_length < min_length)
+ {
+ min_length=table->key_info[nr].key_length;
+ best=nr;
+ }
+ }
+ }
+ return best;
+}
+
+
+/*****************************************************************************
+** If not selecting by given key, create a index how records should be read
+** return: 0 ok
+** -1 some fatal error
+** 1 no records
+*****************************************************************************/
+
+/* Return 1 if we don't have to do file sorting */
+
+static bool
+test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit)
+{
+ int ref_key;
+ TABLE *table=tab->table;
+ SQL_SELECT *select=tab->select;
+ key_map usable_keys;
+ DBUG_ENTER("test_if_skip_sort_order");
+
+ /* Check which keys can be used to resolve ORDER BY */
+ usable_keys= ~(key_map) 0;
+ for (ORDER *tmp_order=order; tmp_order ; tmp_order=tmp_order->next)
+ {
+ if ((*tmp_order->item)->type() != Item::FIELD_ITEM)
+ {
+ usable_keys=0;
+ break;
+ }
+ usable_keys&=((Item_field*) (*tmp_order->item))->field->part_of_key;
+ }
+
+ ref_key= -1;
+ if (tab->ref.key >= 0) // Constant range in WHERE
+ ref_key=tab->ref.key;
+ else if (select && select->quick) // Range found by opt_range
+ ref_key=select->quick->index;
+
+ if (ref_key >= 0)
+ {
+ /* 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)
+ DBUG_RETURN(1); /* No need to sort */
+ }
+ else
+ {
+ /* check if we can use a key to resolve the group */
+ /* Tables using JT_NEXT are handled here */
+ uint nr;
+ key_map keys=usable_keys;
+
+ /*
+ If not used with LIMIT, only use keys if the whole query can be
+ resolved with a key; This is because filesort() is usually faster than
+ retrieving all rows through an index.
+ */
+ if (select_limit >= table->file->records)
+ keys&= table->used_keys;
+
+ for (nr=0; keys ; keys>>=1, nr++)
+ {
+ if (keys & 1)
+ {
+ int flag;
+ if ((flag=test_if_order_by_key(order,table,nr)))
+ {
+ tab->index=nr;
+ tab->read_first_record= (flag > 0 ? join_init_read_first_with_key:
+ join_init_read_last_with_key);
+ tab->type=JT_NEXT; // Read with index_first(), index_next()
+ DBUG_RETURN(1);
+ }
+ }
+ }
+ }
+ DBUG_RETURN(0); // Can't use index.
+}
+
+
+static int
+create_sort_index(JOIN_TAB *tab,ORDER *order,ha_rows select_limit)
+{
+ SORT_FIELD *sortorder;
+ uint length;
+ TABLE *table=tab->table;
+ SQL_SELECT *select=tab->select;
+ DBUG_ENTER("create_sort_index");
+
+ if (test_if_skip_sort_order(tab,order,select_limit))
+ DBUG_RETURN(0);
+ if (!(sortorder=make_unireg_sortorder(order,&length)))
+ goto err; /* purecov: inspected */
+ /* It's not fatal if the following alloc fails */
+ table->io_cache=(IO_CACHE*) my_malloc(sizeof(IO_CACHE),
+ MYF(MY_FAE | MY_ZEROFILL));
+ table->status=0; // May be wrong if quick_select
+
+ // If table has a range, move it to select
+ if (select && !select->quick && tab->ref.key >= 0)
+ {
+ if (tab->quick)
+ {
+ select->quick=tab->quick;
+ tab->quick=0;
+ /* We can only use 'Only index' if quick key is same as ref_key */
+ if (table->key_read && (uint) tab->ref.key != select->quick->index)
+ {
+ table->key_read=0;
+ table->file->extra(HA_EXTRA_NO_KEYREAD);
+ }
+ }
+ else
+ {
+ /*
+ We have a ref on a const; Change this to a range that filesort
+ can use.
+ */
+ if (!(select->quick=get_quick_select_for_ref(table, &tab->ref)))
+ goto err;
+ }
+ }
+ table->found_records=filesort(&table,sortorder,length,
+ select, 0L, select_limit);
+ delete select; // filesort did select
+ tab->select=0;
+ tab->select_cond=0;
+ tab->type=JT_ALL; // Read with normal read_record
+ tab->read_first_record= join_init_read_record;
+ if (table->key_read) // Restore if we used indexes
+ {
+ table->key_read=0;
+ table->file->extra(HA_EXTRA_NO_KEYREAD);
+ }
+ DBUG_RETURN(table->found_records == HA_POS_ERROR);
+err:
+ DBUG_RETURN(-1);
+}
+
+
+/*****************************************************************************
+** Remove duplicates from tmp table
+** This should be recoded to add a uniuqe index to the table and remove
+** dupplicates
+** Table is a locked single thread table
+** fields is the number of fields to check (from the end)
+*****************************************************************************/
+
+static bool compare_record(TABLE *table, Field **ptr)
+{
+ for (; *ptr ; ptr++)
+ {
+ if ((*ptr)->cmp_offset(table->rec_buff_length))
+ return 1;
+ }
+ return 0;
+}
+
+static bool copy_blobs(Field **ptr)
+{
+ for (; *ptr ; ptr++)
+ {
+ if ((*ptr)->flags & BLOB_FLAG)
+ if (((Field_blob *) (*ptr))->copy())
+ return 1; // Error
+ }
+ return 0;
+}
+
+static void free_blobs(Field **ptr)
+{
+ for (; *ptr ; ptr++)
+ {
+ if ((*ptr)->flags & BLOB_FLAG)
+ ((Field_blob *) (*ptr))->free();
+ }
+}
+
+
+static int
+remove_duplicates(JOIN *join, TABLE *entry,List<Item> &fields)
+{
+ int error;
+ ulong reclength,offset;
+ uint field_count;
+ 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;
+ List_iterator<Item> it(fields);
+ Item *item;
+ while ((item=it++))
+ if (item->tmp_table_field())
+ field_count++;
+
+ if (!field_count)
+ { // only const items
+ join->thd->select_limit=1; // Only send first row
+ DBUG_RETURN(0);
+ }
+ Field **first_field=entry->field+entry->fields - field_count;
+ offset=entry->field[entry->fields - field_count]->offset();
+ reclength=entry->reclength-offset;
+
+ free_io_cache(entry); // Safety
+ entry->file->info(HA_STATUS_VARIABLE);
+ if (entry->db_type == DB_TYPE_HEAP ||
+ (!entry->blob_fields &&
+ ((ALIGN_SIZE(reclength) +sizeof(HASH_LINK)) * entry->file->records <
+ sortbuff_size)))
+ error=remove_dup_with_hash_index(join->thd, entry,
+ field_count, first_field,
+ reclength);
+ else
+ error=remove_dup_with_compare(join->thd, entry, first_field, offset);
+
+ free_blobs(first_field);
+ DBUG_RETURN(error);
+}
+
+
+static int remove_dup_with_compare(THD *thd, TABLE *table, Field **first_field,
+ ulong offset)
+{
+ handler *file=table->file;
+ char *org_record,*new_record;
+ int error;
+ ulong reclength=table->reclength-offset;
+ DBUG_ENTER("remove_dup_with_compare");
+
+ org_record=(char*) table->record[0]+offset;
+ new_record=(char*) table->record[1]+offset;
+
+ file->rnd_init();
+ error=file->rnd_next(table->record[0]);
+ for (;;)
+ {
+ if (thd->killed)
+ {
+ my_error(ER_SERVER_SHUTDOWN,MYF(0));
+ error=0;
+ goto err;
+ }
+ if (error)
+ {
+ if (error == HA_ERR_RECORD_DELETED)
+ continue;
+ if (error == HA_ERR_END_OF_FILE)
+ break;
+ goto err;
+ }
+ if (copy_blobs(first_field))
+ {
+ my_error(ER_OUT_OF_SORTMEMORY,MYF(0));
+ error=0;
+ goto err;
+ }
+ memcpy(new_record,org_record,reclength);
+
+ /* Read through rest of file and mark duplicated rows deleted */
+ bool found=0;
+ for (;;)
+ {
+ if ((error=file->rnd_next(table->record[0])))
+ {
+ if (error == HA_ERR_RECORD_DELETED)
+ continue;
+ if (error == HA_ERR_END_OF_FILE)
+ break;
+ goto err;
+ }
+ if (compare_record(table, first_field) == 0)
+ {
+ if ((error=file->delete_row(table->record[0])))
+ goto err;
+ }
+ else if (!found)
+ {
+ found=1;
+ file->position(table->record[0]); // Remember position
+ }
+ }
+ if (!found)
+ break; // End of file
+ /* Restart search on next row */
+ error=file->restart_rnd_next(table->record[0],file->ref);
+ }
+
+ file->extra(HA_EXTRA_NO_CACHE);
+ DBUG_RETURN(0);
+err:
+ file->extra(HA_EXTRA_NO_CACHE);
+ if (error)
+ file->print_error(error,MYF(0));
+ DBUG_RETURN(1);
+}
+
+
+/*
+ Generate a hash index for each row to quickly find duplicate rows
+ Note that this will not work on tables with blobs!
+*/
+
+static int remove_dup_with_hash_index(THD *thd, TABLE *table,
+ uint field_count,
+ Field **first_field,
+ ulong key_length)
+{
+ byte *key_buffer, *key_pos, *record=table->record[0];
+ int error;
+ handler *file=table->file;
+ ulong extra_length=ALIGN_SIZE(key_length)-key_length;
+ uint *field_lengths,*field_length;
+ HASH hash;
+ DBUG_ENTER("remove_dup_with_hash_index");
+
+ if (!my_multi_malloc(MYF(MY_WME),
+ &key_buffer,
+ (uint) ((key_length + extra_length) *
+ (long) file->records),
+ &field_lengths,
+ (uint) (field_count*sizeof(*field_lengths)),
+ NullS))
+ DBUG_RETURN(1);
+ if (hash_init(&hash, (uint) file->records, 0, key_length,
+ (hash_get_key) 0, 0, 0))
+ {
+ my_free((char*) key_buffer,MYF(0));
+ DBUG_RETURN(1);
+ }
+ {
+ Field **ptr;
+ for (ptr= first_field, field_length=field_lengths ; *ptr ; ptr++)
+ (*field_length++)= (*ptr)->pack_length();
+ }
+
+ file->rnd_init();
+ key_pos=key_buffer;
+ for (;;)
+ {
+ if (thd->killed)
+ {
+ my_error(ER_SERVER_SHUTDOWN,MYF(0));
+ error=0;
+ goto err;
+ }
+ if ((error=file->rnd_next(record)))
+ {
+ if (error == HA_ERR_RECORD_DELETED)
+ continue;
+ if (error == HA_ERR_END_OF_FILE)
+ break;
+ goto err;
+ }
+
+ /* copy fields to key buffer */
+ field_length=field_lengths;
+ for (Field **ptr= first_field ; *ptr ; ptr++)
+ {
+ (*ptr)->sort_string((char*) key_pos,*field_length);
+ key_pos+= *field_length++;
+ }
+ /* Check if it exists before */
+ if (hash_search(&hash,key_pos-key_length,key_length))
+ {
+ /* Duplicated found ; Remove the row */
+ if ((error=file->delete_row(record)))
+ goto err;
+ }
+ (void) hash_insert(&hash, key_pos-key_length);
+ key_pos+=extra_length;
+ }
+ my_free((char*) key_buffer,MYF(0));
+ hash_free(&hash);
+ file->extra(HA_EXTRA_NO_CACHE);
+ (void) file->rnd_end();
+ DBUG_RETURN(0);
+
+err:
+ my_free((char*) key_buffer,MYF(0));
+ hash_free(&hash);
+ file->extra(HA_EXTRA_NO_CACHE);
+ (void) file->rnd_end();
+ if (error)
+ file->print_error(error,MYF(0));
+ DBUG_RETURN(1);
+}
+
+
+static SORT_FIELD *
+make_unireg_sortorder(ORDER *order, uint *length)
+{
+ uint count;
+ SORT_FIELD *sort,*pos;
+ DBUG_ENTER("make_unireg_sortorder");
+
+ count=0;
+ for (ORDER *tmp = order; tmp; tmp=tmp->next)
+ count++;
+ pos=sort=(SORT_FIELD*) sql_alloc(sizeof(SORT_FIELD)*(count+1));
+ if (!pos)
+ return 0;
+
+ for (;order;order=order->next,pos++)
+ {
+ pos->field=0; pos->item=0;
+ if (order->item[0]->type() == Item::FIELD_ITEM)
+ pos->field= ((Item_field*) (*order->item))->field;
+ else if (order->item[0]->type() == Item::SUM_FUNC_ITEM &&
+ !order->item[0]->const_item())
+ pos->field= ((Item_sum*) order->item[0])->tmp_table_field();
+ else if (order->item[0]->type() == Item::COPY_STR_ITEM)
+ { // Blob patch
+ pos->item= ((Item_copy_string*) (*order->item))->item;
+ }
+ else
+ pos->item= *order->item;
+ pos->reverse=! order->asc;
+ }
+ *length=count;
+ DBUG_RETURN(sort);
+}
+
+
+/*****************************************************************************
+** Fill join cache with packed records
+** Records are stored in tab->cache.buffer and last record in
+** last record is stored with pointers to blobs to support very big
+** records
+******************************************************************************/
+
+static int
+join_init_cache(THD *thd,JOIN_TAB *tables,uint table_count)
+{
+ reg1 uint i;
+ uint length,blobs,size;
+ CACHE_FIELD *copy,**blob_ptr;
+ JOIN_CACHE *cache;
+ DBUG_ENTER("join_init_cache");
+
+ cache= &tables[table_count].cache;
+ cache->fields=blobs=0;
+
+ for (i=0 ; i < table_count ; i++)
+ {
+ cache->fields+=tables[i].used_fields;
+ blobs+=tables[i].used_blobs;
+ }
+ if (!(cache->field=(CACHE_FIELD*)
+ sql_alloc(sizeof(CACHE_FIELD)*(cache->fields+table_count*2)+(blobs+1)*
+ sizeof(CACHE_FIELD*))))
+ {
+ my_free((gptr) cache->buff,MYF(0)); /* purecov: inspected */
+ cache->buff=0; /* purecov: inspected */
+ DBUG_RETURN(1); /* purecov: inspected */
+ }
+ copy=cache->field;
+ blob_ptr=cache->blob_ptr=(CACHE_FIELD**)
+ (cache->field+cache->fields+table_count*2);
+
+ length=0;
+ for (i=0 ; i < table_count ; i++)
+ {
+ uint null_fields=0,used_fields;
+
+ Field **f_ptr,*field;
+ for (f_ptr=tables[i].table->field,used_fields=tables[i].used_fields ;
+ used_fields ;
+ f_ptr++)
+ {
+ field= *f_ptr;
+ if (field->query_id == thd->query_id)
+ {
+ used_fields--;
+ length+=field->fill_cache_field(copy);
+ if (copy->blob_field)
+ (*blob_ptr++)=copy;
+ if (field->maybe_null())
+ null_fields++;
+ copy++;
+ }
+ }
+ /* Copy null bits from table */
+ if (null_fields && tables[i].table->null_fields)
+ { /* must copy null bits */
+ copy->str=(char*) tables[i].table->null_flags;
+ copy->length=(tables[i].table->null_fields+7)/8;
+ copy->strip=0;
+ copy->blob_field=0;
+ length+=copy->length;
+ copy++;
+ cache->fields++;
+ }
+ /* If outer join table, copy null_row flag */
+ if (tables[i].table->maybe_null)
+ {
+ copy->str= (char*) &tables[i].table->null_row;
+ copy->length=sizeof(tables[i].table->null_row);
+ copy->strip=0;
+ copy->blob_field=0;
+ length+=copy->length;
+ copy++;
+ cache->fields++;
+ }
+ }
+
+ cache->records=0; cache->ptr_record= (uint) ~0;
+ cache->length=length+blobs*sizeof(char*);
+ cache->blobs=blobs;
+ *blob_ptr=0; /* End sequentel */
+ size=max(join_buff_size,cache->length);
+ if (!(cache->buff=(uchar*) my_malloc(size,MYF(0))))
+ DBUG_RETURN(1); /* Don't use cache */ /* purecov: inspected */
+ cache->end=cache->buff+size;
+ reset_cache(cache);
+ DBUG_RETURN(0);
+}
+
+
+static ulong
+used_blob_length(CACHE_FIELD **ptr)
+{
+ uint length,blob_length;
+ for (length=0 ; *ptr ; ptr++)
+ {
+ (*ptr)->blob_length=blob_length=(*ptr)->blob_field->get_length();
+ length+=blob_length;
+ (*ptr)->blob_field->get_ptr(&(*ptr)->str);
+ }
+ return length;
+}
+
+
+static bool
+store_record_in_cache(JOIN_CACHE *cache)
+{
+ ulong length;
+ uchar *pos;
+ CACHE_FIELD *copy,*end_field;
+ bool last_record;
+
+ pos=cache->pos;
+ end_field=cache->field+cache->fields;
+
+ length=cache->length;
+ if (cache->blobs)
+ length+=used_blob_length(cache->blob_ptr);
+ if ((last_record=(length+cache->length > (uint) (cache->end - pos))))
+ cache->ptr_record=cache->records;
+
+ /*
+ ** There is room in cache. Put record there
+ */
+ cache->records++;
+ for (copy=cache->field ; copy < end_field; copy++)
+ {
+ if (copy->blob_field)
+ {
+ if (last_record)
+ {
+ copy->blob_field->get_image((char*) pos,copy->length+sizeof(char*));
+ pos+=copy->length+sizeof(char*);
+ }
+ else
+ {
+ copy->blob_field->get_image((char*) pos,copy->length); // blob length
+ memcpy(pos+copy->length,copy->str,copy->blob_length); // Blob data
+ pos+=copy->length+copy->blob_length;
+ }
+ }
+ else
+ {
+ if (copy->strip)
+ {
+ char *str,*end;
+ for (str=copy->str,end= str+copy->length;
+ end > str && end[-1] == ' ' ;
+ end--) ;
+ length=(uint) (end-str);
+ memcpy(pos+1,str,length);
+ *pos=(uchar) length;
+ pos+=length+1;
+ }
+ else
+ {
+ memcpy(pos,copy->str,copy->length);
+ pos+=copy->length;
+ }
+ }
+ }
+ cache->pos=pos;
+ return last_record || (uint) (cache->end -pos) < cache->length;
+}
+
+
+static void
+reset_cache(JOIN_CACHE *cache)
+{
+ cache->record_nr=0;
+ cache->pos=cache->buff;
+}
+
+
+static void
+read_cached_record(JOIN_TAB *tab)
+{
+ uchar *pos;
+ uint length;
+ bool last_record;
+ CACHE_FIELD *copy,*end_field;
+
+ last_record=tab->cache.record_nr++ == tab->cache.ptr_record;
+ pos=tab->cache.pos;
+
+ for (copy=tab->cache.field,end_field=copy+tab->cache.fields ;
+ copy < end_field;
+ copy++)
+ {
+ if (copy->blob_field)
+ {
+ if (last_record)
+ {
+ copy->blob_field->set_image((char*) pos,copy->length+sizeof(char*));
+ pos+=copy->length+sizeof(char*);
+ }
+ else
+ {
+ copy->blob_field->set_ptr((char*) pos,(char*) pos+copy->length);
+ pos+=copy->length+copy->blob_field->get_length();
+ }
+ }
+ else
+ {
+ if (copy->strip)
+ {
+ memcpy(copy->str,pos+1,length=(uint) *pos);
+ memset(copy->str+length,' ',copy->length-length);
+ pos+=1+length;
+ }
+ else
+ {
+ memcpy(copy->str,pos,copy->length);
+ pos+=copy->length;
+ }
+ }
+ }
+ tab->cache.pos=pos;
+ return;
+}
+
+
+static bool
+cmp_buffer_with_ref(JOIN_TAB *tab)
+{
+ bool diff;
+ if (!(diff=tab->ref.key_err))
+ {
+ memcpy(tab->ref.key_buff2, tab->ref.key_buff, tab->ref.key_length);
+ }
+ if ((tab->ref.key_err=cp_buffer_from_ref(&tab->ref)) || diff)
+ return 1;
+ return memcmp(tab->ref.key_buff2, tab->ref.key_buff, tab->ref.key_length)
+ != 0;
+}
+
+
+bool
+cp_buffer_from_ref(TABLE_REF *ref)
+{
+ for (store_key **copy=ref->key_copy ; *copy ; copy++)
+ if ((*copy)->copy())
+ return 1; // Something went wrong
+ return 0;
+}
+
+
+/*****************************************************************************
+** Group and order functions
+*****************************************************************************/
+
+/*
+** Find order/group item in requested columns and change the item to point at
+** it. If item doesn't exists, add it first in the field list
+** Return 0 if ok.
+*/
+
+static int
+find_order_in_list(THD *thd,TABLE_LIST *tables,ORDER *order,List<Item> &fields,
+ List<Item> &all_fields)
+{
+ if ((*order->item)->type() == Item::INT_ITEM)
+ { /* Order by position */
+ Item *item=0;
+ List_iterator<Item> li(fields);
+
+ for (uint count= (uint) ((Item_int*) (*order->item))->value ;
+ count-- && (item=li++) ;) ;
+ if (!item)
+ {
+ my_printf_error(ER_BAD_FIELD_ERROR,ER(ER_BAD_FIELD_ERROR),
+ MYF(0),(*order->item)->full_name(),
+ thd->where);
+ return 1;
+ }
+ order->item=li.ref();
+ order->in_field_list=1;
+ return 0;
+ }
+ const char *save_where=thd->where;
+ thd->where=0; // No error if not found
+ Item **item=find_item_in_list(*order->item,fields);
+ thd->where=save_where;
+ if (item)
+ {
+ order->item=item; // use it
+ order->in_field_list=1;
+ return 0;
+ }
+ order->in_field_list=0;
+ if ((*order->item)->fix_fields(thd,tables) || thd->fatal_error)
+ return 1; // Wrong field
+ all_fields.push_front(*order->item); // Add new field to field list
+ order->item=(Item**) all_fields.head_ref();
+ return 0;
+}
+
+
+/*
+** Change order to point at item in select list. If item isn't a number
+** and doesn't exits in the select list, add it the the field list.
+*/
+
+static int
+setup_order(THD *thd,TABLE_LIST *tables,List<Item> &fields,
+ List<Item> &all_fields, ORDER *order)
+{
+ thd->where="order clause";
+ for (; order; order=order->next)
+ {
+ if (find_order_in_list(thd,tables,order,fields,all_fields))
+ return 1;
+ }
+ return 0;
+}
+
+
+static int
+setup_group(THD *thd,TABLE_LIST *tables,List<Item> &fields,
+ List<Item> &all_fields, ORDER *order, bool *hidden_group_fields)
+{
+ *hidden_group_fields=0;
+ if (!order)
+ return 0; /* Everything is ok */
+
+ if (thd->options & OPTION_ANSI_MODE)
+ {
+ Item *item;
+ List_iterator<Item> li(fields);
+ while ((item=li++))
+ item->marker=0; /* Marker that field is not used */
+ }
+ uint org_fields=all_fields.elements;
+
+ thd->where="group statement";
+ for ( ; order; order=order->next)
+ {
+ if (find_order_in_list(thd,tables,order,fields,all_fields))
+ return 1;
+ (*order->item)->marker=1; /* Mark found */
+ if ((*order->item)->with_sum_func)
+ {
+ my_printf_error(ER_WRONG_GROUP_FIELD, ER(ER_WRONG_GROUP_FIELD),MYF(0),
+ (*order->item)->full_name());
+ return 1;
+ }
+ }
+ if (thd->options & OPTION_ANSI_MODE)
+ {
+ /* Don't allow one to use fields that is not used in GROUP BY */
+ Item *item;
+ List_iterator<Item> li(fields);
+
+ while ((item=li++))
+ {
+ if (item->type() != Item::SUM_FUNC_ITEM && !item->marker)
+ {
+ my_printf_error(ER_WRONG_FIELD_WITH_GROUP,
+ ER(ER_WRONG_FIELD_WITH_GROUP),
+ MYF(0),item->full_name());
+ return 1;
+ }
+ }
+ }
+ if (org_fields != all_fields.elements)
+ *hidden_group_fields=1; // group fields is not used
+ return 0;
+}
+
+/*
+** Add fields with aren't used at start of field list. Return FALSE if ok
+*/
+
+static bool
+setup_new_fields(THD *thd,TABLE_LIST *tables,List<Item> &fields,
+ List<Item> &all_fields, ORDER *new_field)
+{
+ Item **item;
+ DBUG_ENTER("setup_new_fields");
+
+ thd->set_query_id=1; // Not really needed, but...
+ thd->where=0; // Don't give error
+ for ( ; new_field ; new_field=new_field->next)
+ {
+ if ((item=find_item_in_list(*new_field->item,fields)))
+ new_field->item=item; /* Change to shared Item */
+ else
+ {
+ thd->where="procedure list";
+ if ((*new_field->item)->fix_fields(thd,tables))
+ DBUG_RETURN(1); /* purecov: inspected */
+ thd->where=0;
+ all_fields.push_front(*new_field->item);
+ new_field->item=all_fields.head_ref();
+ }
+ }
+ DBUG_RETURN(0);
+}
+
+/*
+** Create a group by that consist of all non const fields. Try to use
+** the fields in the order given by 'order' to allow one to optimize
+** away 'order by'.
+*/
+
+static ORDER *
+create_distinct_group(ORDER *order_list,List<Item> &fields)
+{
+ List_iterator<Item> li(fields);
+ Item *item;
+ ORDER *order,*group,**prev;
+
+ while ((item=li++))
+ item->marker=0; /* Marker that field is not used */
+
+ prev= &group; group=0;
+ for (order=order_list ; order; order=order->next)
+ {
+ if (order->in_field_list)
+ {
+ ORDER *ord=(ORDER*) sql_memdup(order,sizeof(ORDER));
+ if (!ord)
+ return 0;
+ *prev=ord;
+ prev= &ord->next;
+ (*ord->item)->marker=1;
+ }
+ }
+
+ li.rewind();
+ while ((item=li++))
+ {
+ if (item->const_item() || item->with_sum_func)
+ continue;
+ if (!item->marker)
+ {
+ ORDER *ord=(ORDER*) sql_calloc(sizeof(ORDER));
+ if (!ord)
+ return 0;
+ ord->item=li.ref();
+ ord->asc=1;
+ *prev=ord;
+ prev= &ord->next;
+ }
+ }
+ *prev=0;
+ return group;
+}
+
+
+/*****************************************************************************
+** Update join with count of the different type of fields
+*****************************************************************************/
+
+void
+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=0;
+ param->quick_group=1;
+ while ((field=li++))
+ {
+ Item::Type type=field->type();
+ if (type == Item::FIELD_ITEM)
+ param->field_count++;
+ else if (type == Item::SUM_FUNC_ITEM)
+ {
+ if (! field->const_item())
+ {
+ Item_sum *sum_item=(Item_sum*) field;
+ if (!sum_item->quick_group)
+ param->quick_group=0; // UDF SUM function
+ param->sum_func_count++;
+
+ for (uint i=0 ; i < sum_item->arg_count ; i++)
+ {
+ if (sum_item->args[0]->type() == Item::FIELD_ITEM)
+ param->field_count++;
+ else
+ param->func_count++;
+ }
+ }
+ }
+ else
+ param->func_count++;
+ }
+}
+
+
+/*
+ Return 1 if second is a subpart of first argument
+ If first parts has different direction, change it to second part
+ (group is sorted like order)
+*/
+
+static bool
+test_if_subpart(ORDER *a,ORDER *b)
+{
+ for (; a && b; a=a->next,b=b->next)
+ {
+ if ((*a->item)->eq(*b->item))
+ a->asc=b->asc;
+ else
+ return 0;
+ }
+ return test(!b);
+}
+
+/*
+ Return table number if there is only one table in sort order
+ and group and order is compatible
+ else return 0;
+*/
+
+static TABLE *
+get_sort_by_table(ORDER *a,ORDER *b,TABLE_LIST *tables)
+{
+ table_map map= (table_map) 0;
+ DBUG_ENTER("get_sort_by_table");
+
+ if (!a)
+ a=b; // Only one need to be given
+ else if (!b)
+ b=a;
+
+ for (; a && b; a=a->next,b=b->next)
+ {
+ if (!(*a->item)->eq(*b->item))
+ DBUG_RETURN(0);
+ map|=a->item[0]->used_tables();
+ }
+ if (!map || (map & RAND_TABLE_BIT))
+ DBUG_RETURN(0);
+
+ for ( ; !(map & tables->table->map) ; tables=tables->next) ;
+ if (map != tables->table->map)
+ DBUG_RETURN(0); // More than one table
+ DBUG_PRINT("exit",("sort by table: %d",tables->table->tablenr));
+ DBUG_RETURN(tables->table);
+}
+
+
+ /* calc how big buffer we need for comparing group entries */
+
+static void
+calc_group_buffer(JOIN *join,ORDER *group)
+{
+ uint key_length=0,parts=0;
+ if (group)
+ join->group= 1;
+ for (; group ; group=group->next)
+ {
+ Field *field=(*group->item)->tmp_table_field();
+ if (field)
+ {
+ if (field->type() == FIELD_TYPE_BLOB)
+ key_length+=MAX_BLOB_WIDTH; // Can't be used as a key
+ else
+ key_length+=field->pack_length();
+ }
+ else if ((*group->item)->result_type() == REAL_RESULT)
+ key_length+=sizeof(double);
+ else if ((*group->item)->result_type() == INT_RESULT)
+ key_length+=sizeof(longlong);
+ else
+ key_length+=(*group->item)->max_length;
+ parts++;
+ if ((*group->item)->maybe_null)
+ key_length++;
+ }
+ join->tmp_table_param.group_length=key_length;
+ join->tmp_table_param.group_parts=parts;
+}
+
+
+/*
+** Get a list of buffers for saveing last group
+** Groups are saved in reverse order for easyer check loop
+*/
+
+static bool
+alloc_group_fields(JOIN *join,ORDER *group)
+{
+ if (group)
+ {
+ for (; group ; group=group->next)
+ {
+ Item_buff *tmp=new_Item_buff(*group->item);
+ if (!tmp || join->group_fields.push_front(tmp))
+ return TRUE;
+ }
+ }
+ join->sort_and_group=1; /* Mark for do_select */
+ return FALSE;
+}
+
+
+static int
+test_if_group_changed(List<Item_buff> &list)
+{
+ List_iterator<Item_buff> li(list);
+ int idx= -1,i;
+ Item_buff *buff;
+
+ for (i=(int) list.elements-1 ; (buff=li++) ; i--)
+ {
+ if (buff->cmp())
+ idx=i;
+ }
+ return idx;
+}
+
+
+
+/*
+** Setup copy_fields to save fields at start of new group
+** Only FIELD_ITEM:s and FUNC_ITEM:s needs to be saved between groups.
+** Change old item_field to use a new field with points at saved fieldvalue
+** This function is only called before use of send_fields
+*/
+
+bool
+setup_copy_fields(TMP_TABLE_PARAM *param,List<Item> &fields)
+{
+ Item *pos;
+ List_iterator<Item> li(fields);
+ Copy_field *copy;
+ DBUG_ENTER("setup_copy_fields");
+
+ if (!(copy=param->copy_field= new Copy_field[param->field_count]))
+ goto err;
+
+ param->copy_funcs.empty();
+ while ((pos=li++))
+ {
+ if (pos->type() == Item::FIELD_ITEM)
+ {
+ Item_field *item=(Item_field*) pos;
+ if (item->field->flags & BLOB_FLAG)
+ {
+ if (!(pos=new Item_copy_string(pos)))
+ goto err;
+ VOID(li.replace(pos));
+ if (param->copy_funcs.push_back(pos))
+ goto err;
+ continue;
+ }
+
+ /* 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);
+ char *tmp=(char*) sql_alloc(field->pack_length()+1);
+ if (!tmp)
+ goto err;
+ copy->set(tmp, item->result_field);
+ item->result_field->move_field(copy->to_ptr,copy->to_null_ptr,1);
+ copy++;
+ }
+ else if ((pos->type() == Item::FUNC_ITEM ||
+ pos->type() == Item::COND_ITEM) &&
+ !pos->with_sum_func)
+ { // Save for send fields
+ /* TODO:
+ In most cases this result will be sent to the user.
+ This should be changed to use copy_int or copy_real depending
+ on how the value is to be used: In some cases this may be an
+ argument in a group function, like: IF(ISNULL(col),0,COUNT(*))
+ */
+ if (!(pos=new Item_copy_string(pos)))
+ goto err;
+ VOID(li.replace(pos));
+ if (param->copy_funcs.push_back(pos))
+ goto err;
+ }
+ }
+ param->copy_field_count= (uint) (copy - param->copy_field);
+ DBUG_RETURN(0);
+
+ err:
+ delete [] param->copy_field;
+ param->copy_field=0;
+ DBUG_RETURN(TRUE);
+}
+
+
+/*
+** Copy fields and null values between two tables
+*/
+
+void
+copy_fields(TMP_TABLE_PARAM *param)
+{
+ Copy_field *ptr=param->copy_field;
+ Copy_field *end=ptr+param->copy_field_count;
+
+ for ( ; ptr != end; ptr++)
+ (*ptr->do_copy)(ptr);
+
+ List_iterator<Item> it(param->copy_funcs);
+ Item_copy_string *item;
+ while ((item = (Item_copy_string*) it++))
+ {
+ item->copy();
+ }
+}
+
+
+/*****************************************************************************
+** Make an array of pointer to sum_functions to speed up sum_func calculation
+*****************************************************************************/
+
+static bool
+make_sum_func_list(JOIN *join,List<Item> &fields)
+{
+ DBUG_ENTER("make_sum_func_list");
+ Item_sum **func =
+ (Item_sum**) sql_alloc(sizeof(Item_sum*)*
+ (join->tmp_table_param.sum_func_count+1));
+ if (!func)
+ DBUG_RETURN(TRUE);
+ List_iterator<Item> it(fields);
+ join->sum_funcs=func;
+
+ Item *field;
+ while ((field=it++))
+ {
+ if (field->type() == Item::SUM_FUNC_ITEM && !field->const_item())
+ {
+ *func++=(Item_sum*) field;
+ /* let COUNT(DISTINCT) create the temporary table */
+ if (((Item_sum*) field)->setup(join->thd))
+ DBUG_RETURN(TRUE);
+ }
+ }
+ *func=0; // End marker
+ DBUG_RETURN(FALSE);
+}
+
+
+/*
+** Change all funcs and sum_funcs to fields in tmp table
+*/
+
+static bool
+change_to_use_tmp_fields(List<Item> &items)
+{
+ List_iterator<Item> it(items);
+ Item *item_field,*item;
+
+ while ((item=it++))
+ {
+ Field *field;
+ if (item->with_sum_func && item->type() != Item::SUM_FUNC_ITEM)
+ continue;
+ if (item->type() == Item::FIELD_ITEM)
+ {
+ ((Item_field*) item)->field=
+ ((Item_field*) item)->result_field;
+ }
+ else if ((field=item->tmp_table_field()))
+ {
+ if (item->type() == Item::SUM_FUNC_ITEM && field->table->group)
+ item_field=((Item_sum*) item)->result_item(field);
+ else
+ item_field=(Item*) new Item_field(field);
+ if (!item_field)
+ return TRUE; // Fatal error
+ item_field->name=item->name; /*lint -e613 */
+#ifndef DBUG_OFF
+ if (_db_on_ && !item_field->name)
+ {
+ char buff[256];
+ String str(buff,sizeof(buff));
+ str.length(0);
+ item->print(&str);
+ item_field->name=sql_strmake(str.ptr(),str.length());
+ }
+#endif
+#ifdef DELETE_ITEMS
+ delete it.replace(item_field); /*lint -e613 */
+#else
+ (void) it.replace(item_field); /*lint -e613 */
+#endif
+ }
+ }
+ return FALSE;
+}
+
+
+/*
+** Change all sum_func refs to fields to point at fields in tmp table
+** Change all funcs to be fields in tmp table
+*/
+
+static bool
+change_refs_to_tmp_fields(THD *thd,List<Item> &items)
+{
+ List_iterator<Item> it(items);
+ Item *item;
+
+ while ((item= it++))
+ {
+ if (item->type() == Item::SUM_FUNC_ITEM)
+ {
+ if (!item->const_item())
+ {
+ Item_sum *sum_item= (Item_sum*) item;
+ if (sum_item->result_field) // If not a const sum func
+ {
+ Field *result_field=sum_item->result_field;
+ for (uint i=0 ; i < sum_item->arg_count ; i++)
+ {
+ Item *arg= sum_item->args[i];
+ if (!arg->const_item())
+ {
+ if (arg->type() == Item::FIELD_ITEM)
+ ((Item_field*) arg)->field= result_field++;
+ else
+ sum_item->args[i]= new Item_field(result_field++);
+ }
+ }
+ }
+ }
+ }
+ else if (item->with_sum_func)
+ continue;
+ else if ((item->type() == Item::FUNC_ITEM ||
+ item->type() == Item::COND_ITEM) &&
+ !item->const_item())
+ { /* All funcs are stored */
+#ifdef DELETE_ITEMS
+ delete it.replace(new Item_field(((Item_func*) item)->result_field));
+#else
+ (void) it.replace(new Item_field(((Item_func*) item)->result_field));
+#endif
+ }
+ else if (item->type() == Item::FIELD_ITEM) /* Change refs */
+ {
+ ((Item_field*)item)->field=((Item_field*) item)->result_field;
+ }
+ }
+ return thd->fatal_error;
+}
+
+
+
+/******************************************************************************
+** code for calculating functions
+******************************************************************************/
+
+static void
+init_tmptable_sum_functions(Item_sum **func_ptr)
+{
+ Item_sum *func;
+ while ((func= *(func_ptr++)))
+ func->reset_field();
+}
+
+
+ /* Update record 0 in tmp_table from record 1 */
+
+static void
+update_tmptable_sum_func(Item_sum **func_ptr,
+ TABLE *tmp_table __attribute__((unused)))
+{
+ Item_sum *func;
+ while ((func= *(func_ptr++)))
+ func->update_field(0);
+}
+
+
+ /* Copy result of sum functions to record in tmp_table */
+
+static void
+copy_sum_funcs(Item_sum **func_ptr)
+{
+ Item_sum *func;
+ for (; (func = *func_ptr) ; func_ptr++)
+ (void) func->save_in_field(func->result_field);
+ return;
+}
+
+
+static void
+init_sum_functions(Item_sum **func_ptr)
+{
+ Item_sum *func;
+ for (; (func= (Item_sum*) *func_ptr) ; func_ptr++)
+ func->reset();
+}
+
+
+static bool
+update_sum_func(Item_sum **func_ptr)
+{
+ Item_sum *func;
+ for (; (func= (Item_sum*) *func_ptr) ; func_ptr++)
+ if (func->add())
+ return 1;
+ return 0;
+}
+
+ /* Copy result of functions to record in tmp_table */
+
+void
+copy_funcs(Item_result_field **func_ptr)
+{
+ Item_result_field *func;
+ for (; (func = *func_ptr) ; func_ptr++)
+ (void) func->save_in_field(func->result_field);
+ return;
+}
+
+
+/*****************************************************************************
+** Create a condition for a const reference and add this to the
+** currenct select for the table
+*****************************************************************************/
+
+static bool add_ref_to_table_cond(THD *thd, JOIN_TAB *join_tab)
+{
+ DBUG_ENTER("add_ref_to_table_cond");
+ if (!join_tab->ref.key_parts)
+ DBUG_RETURN(FALSE);
+
+ Item_cond_and *cond=new Item_cond_and();
+ TABLE *table=join_tab->table;
+ int error;
+ if (!cond)
+ DBUG_RETURN(TRUE);
+
+ for (uint i=0 ; i < join_tab->ref.key_parts ; i++)
+ {
+ Field *field=table->field[table->key_info[join_tab->ref.key].key_part[i].fieldnr-1];
+ Item *value=join_tab->ref.items[i];
+ cond->add(new Item_func_equal(new Item_field(field),value));
+ }
+ if (thd->fatal_error)
+ DBUG_RETURN(TRUE);
+ cond->fix_fields((THD *) 0,(TABLE_LIST *) 0);
+ if (join_tab->select)
+ {
+ error=(int) cond->add(join_tab->select->cond);
+ join_tab->select_cond=join_tab->select->cond=cond;
+ }
+ else if ((join_tab->select=make_select(join_tab->table, 0, 0, cond,&error)))
+ join_tab->select_cond=cond;
+
+ DBUG_RETURN(error ? TRUE : FALSE);
+}
+
+/****************************************************************************
+** Send a description about what how the select will be done to stdout
+****************************************************************************/
+
+static void select_describe(JOIN *join, bool need_tmp_table, bool need_order)
+{
+ DBUG_ENTER("select_describe");
+
+ List<Item> field_list;
+ Item *item;
+
+ 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(join->thd,field_list,1))
+ return; /* purecov: inspected */
+
+ char buff[512],*buff_ptr;
+ String tmp(buff,sizeof(buff)),*packet= &join->thd->packet;
+ for (uint i=0 ; i < join->tables ; i++)
+ {
+ 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)
+ {
+ if (tmp.length())
+ tmp.append(',');
+ tmp.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 (tmp.length())
+ tmp.append(',');
+ tmp.append((*ref)->name());
+ }
+ 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)
+ {
+ 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");
+ }
+ if (key_read)
+ {
+ if (buff != buff_ptr)
+ {
+ buff_ptr[0]=';' ; buff_ptr[1]=' '; buff_ptr+=2;
+ }
+ buff_ptr=strmov(buff_ptr,"Using index");
+ }
+ if (table->reginfo.not_exists_optimize)
+ {
+ if (buff != buff_ptr)
+ {
+ buff_ptr[0]=';' ; buff_ptr[1]=' '; buff_ptr+=2;
+ }
+ buff_ptr=strmov(buff_ptr,"Not exists");
+ }
+ if (need_tmp_table)
+ {
+ need_tmp_table=0;
+ if (buff != buff_ptr)
+ {
+ buff_ptr[0]=';' ; buff_ptr[1]=' '; buff_ptr+=2;
+ }
+ buff_ptr=strmov(buff_ptr,"Using temporary");
+ }
+ 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");
+ }
+ net_store_data(packet,buff,(uint) (buff_ptr - buff));
+ if (my_net_write(&join->thd->net,(char*) packet->ptr(),packet->length()))
+ DBUG_VOID_RETURN; /* purecov: inspected */
+ }
+ send_eof(&join->thd->net);
+ DBUG_VOID_RETURN;
+}
+
+
+static void describe_info(const char *info)
+{
+ List<Item> field_list;
+ THD *thd=current_thd;
+ String *packet= &thd->packet;
+
+ field_list.push_back(new Item_empty_string("Comment",80));
+ if (send_fields(thd,field_list,1))
+ return; /* purecov: inspected */
+ packet->length(0);
+ net_store_data(packet,info);
+ if (!my_net_write(&thd->net,(char*) packet->ptr(),packet->length()))
+ send_eof(&thd->net);
+}
diff --git a/sql/sql_select.h b/sql/sql_select.h
new file mode 100644
index 00000000000..8daba5b939e
--- /dev/null
+++ b/sql/sql_select.h
@@ -0,0 +1,291 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+
+/* classes to use when handling where clause */
+
+#ifdef __GNUC__
+#pragma interface /* gcc class implementation */
+#endif
+
+#include "procedure.h"
+#include <myisam.h>
+
+typedef struct keyuse_t {
+ TABLE *table;
+ Item *val; /* or value if no field */
+ uint key,keypart;
+ table_map used_tables;
+} KEYUSE;
+
+class store_key;
+
+typedef struct st_table_ref
+{
+ bool key_err;
+ uint key_parts; // num of ...
+ uint key_length; // length of key_buff
+ int key; // key no
+ byte *key_buff; // value to look for with key
+ byte *key_buff2; // key_buff+key_length
+ store_key **key_copy; //
+ Item **items; // val()'s for each keypart
+ table_map depend_map; // Table depends on these tables.
+} TABLE_REF;
+
+/*
+** CACHE_FIELD and JOIN_CACHE is used on full join to cache records in outer
+** table
+*/
+
+
+typedef struct st_cache_field {
+ char *str;
+ uint length,blob_length;
+ Field_blob *blob_field;
+ bool strip;
+} CACHE_FIELD;
+
+
+typedef struct st_join_cache {
+ uchar *buff,*pos,*end;
+ uint records,record_nr,ptr_record,fields,length,blobs;
+ CACHE_FIELD *field,**blob_ptr;
+ SQL_SELECT *select;
+} JOIN_CACHE;
+
+
+/*
+** The structs which holds the join connections and join states
+*/
+
+enum join_type { JT_UNKNOWN,JT_SYSTEM,JT_CONST,JT_EQ_REF,JT_REF,JT_MAYBE_REF,
+ JT_ALL, JT_RANGE, JT_NEXT, JT_FT};
+
+class JOIN;
+
+typedef struct st_join_table {
+ TABLE *table;
+ int (*read_first_record)(struct st_join_table *tab);
+ int (*next_select)(JOIN *,struct st_join_table *,bool);
+ bool cached_eq_ref_table,eq_ref_table;
+ READ_RECORD read_record;
+ uint keys; /* all keys with can be used */
+ key_map const_keys; /* Keys with constant part */
+ key_map checked_keys; /* Keys checked in find_best */
+ key_map needed_reg;
+ ha_rows records,found_records,read_time;
+ table_map dependent,key_dependent;
+ uint use_quick,index;
+ uint status; // Save status for cache
+ enum join_type type;
+ JOIN_CACHE cache;
+ KEYUSE *keyuse; /* pointer to first used key */
+ SQL_SELECT *select;
+ COND *select_cond;
+ QUICK_SELECT *quick;
+ Item *on_expr;
+ uint used_fields,used_fieldlength,used_blobs;
+ const char *info;
+ double worst_seeks;
+ TABLE_REF ref;
+} JOIN_TAB;
+
+
+typedef struct st_position { /* Used in find_best */
+ JOIN_TAB *table;
+ KEYUSE *key;
+ double records_read;
+} POSITION;
+
+
+/* Param to create temporary tables when doing SELECT:s */
+
+class TMP_TABLE_PARAM {
+ public:
+ uint copy_field_count,field_count,sum_func_count,func_count;
+ uint group_parts,group_length;
+ uint quick_group;
+ Copy_field *copy_field;
+ byte *group_buff;
+ ha_rows end_write_records;
+ Item_result_field **funcs;
+ List<Item> copy_funcs;
+ MI_COLUMNDEF *recinfo,*start_recinfo;
+ KEY *keyinfo;
+
+ TMP_TABLE_PARAM() :group_parts(0),group_length(0),copy_field(0) {}
+ ~TMP_TABLE_PARAM()
+ {
+ cleanup();
+ }
+ inline void cleanup(void)
+ {
+ delete [] copy_field;
+ copy_field=0;
+ }
+};
+
+
+class JOIN {
+ public:
+ JOIN_TAB *join_tab,**best_ref,**map2table;
+ TABLE **table,**all_tables,*sort_by_table;
+ uint tables,const_tables;
+ uint send_group_parts;
+ bool sort_and_group,first_record,full_join,group, no_field_update;
+ table_map const_table_map;
+ ha_rows send_records;
+ POSITION positions[MAX_TABLES+1],best_positions[MAX_TABLES+1];
+ double best_read;
+ List<Item> *fields;
+ List<Item_buff> group_fields;
+ TABLE *tmp_table;
+ THD *thd;
+ Item_sum **sum_funcs;
+ Procedure *procedure;
+ Item *having;
+ uint select_options;
+ select_result *result;
+ TMP_TABLE_PARAM tmp_table_param;
+ MYSQL_LOCK *lock;
+};
+
+
+typedef struct st_select_check {
+ uint const_ref,reg_ref;
+} SELECT_CHECK;
+
+extern const char *join_type_str[];
+void TEST_join(JOIN *join);
+
+/* Extern functions in sql_select.cc */
+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);
+void free_tmp_table(THD *thd, TABLE *entry);
+void count_field_types(TMP_TABLE_PARAM *param, List<Item> &fields);
+bool setup_copy_fields(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,
+ bool ignore_last_dupp_error);
+
+/* functions from opt_sum.cc */
+int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds);
+
+
+/* class to copying an field/item to a key struct */
+
+class store_key :public Sql_alloc
+{
+ protected:
+ Field *to_field; // Store data here
+ Field *key_field; // Copy of key field
+ char *null_ptr;
+ char err;
+ public:
+ store_key(Field *field_arg, char *ptr, char *null, uint length)
+ :null_ptr(null),err(0)
+ {
+ if (field_arg->type() == FIELD_TYPE_BLOB)
+ to_field=new Field_varstring(ptr, length, (uchar*) null, 1,
+ Field::NONE, field_arg->field_name,
+ field_arg->table, field_arg->binary());
+ else
+ {
+ to_field=field_arg->new_field(field_arg->table);
+ if (to_field)
+ to_field->move_field(ptr, (uchar*) null, 1);
+ }
+ }
+ virtual ~store_key() {} /* Not actually needed */
+ virtual bool copy()=0;
+ virtual const char *name() const=0;
+};
+
+
+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,
+ uint length, Field *from_field, const char *name_arg)
+ :store_key(to_field_arg,ptr,
+ null_ptr_arg ? null_ptr_arg : from_field->maybe_null() ? &err
+ : NullS,length), field_name(name_arg)
+ {
+ if (to_field)
+ {
+ copy_field.set(to_field,from_field,0);
+ }
+ }
+ bool copy()
+ {
+ copy_field.do_copy(&copy_field);
+ return err != 0;
+ }
+ const char *name() const { return field_name; }
+};
+
+
+class store_key_item :public store_key
+{
+ protected:
+ Item *item;
+public:
+ store_key_item(Field *to_field_arg, char *ptr, char *null_ptr_arg,
+ uint length, Item *item_arg)
+ :store_key(to_field_arg,ptr,
+ null_ptr_arg ? null_ptr_arg : item_arg->maybe_null ?
+ &err : NullS, length), item(item_arg)
+ {}
+ bool copy()
+ {
+ item->save_in_field(to_field);
+ return err != 0;
+ }
+ const char *name() const { return "func"; }
+};
+
+
+class store_key_const_item :public store_key_item
+{
+ bool inited;
+public:
+ store_key_const_item(Field *to_field_arg, char *ptr,
+ char *null_ptr_arg, uint length,
+ Item *item_arg)
+ :store_key_item(to_field_arg,ptr,
+ null_ptr_arg ? null_ptr_arg : item_arg->maybe_null ?
+ &err : NullS, length, item_arg), inited(0)
+ {
+ }
+ bool copy()
+ {
+ if (!inited)
+ {
+ inited=1;
+ item->save_in_field(to_field);
+ }
+ return err != 0;
+ }
+ const char *name() const { return "const"; }
+};
+
+bool cp_buffer_from_ref(TABLE_REF *ref);
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
new file mode 100644
index 00000000000..55142e21dad
--- /dev/null
+++ b/sql/sql_show.cc
@@ -0,0 +1,1032 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 with list databases, tables or fields */
+
+#undef USE_RAID
+#define USE_RAID
+#include "mysql_priv.h"
+#include "sql_select.h" // For select_describe
+#include "sql_acl.h"
+#include <my_dir.h>
+extern "C" pthread_mutex_t THR_LOCK_keycache;
+
+static const char *grant_names[]={
+ "select","insert","update","delete","create","drop","reload","shutdown",
+ "process","file","grant","references","index","alter"};
+
+static TYPELIB grant_types = { sizeof(grant_names)/sizeof(char **),
+ "grant_types",
+ grant_names};
+
+static int mysql_find_files(THD *thd,List<char> *files, const char *db,
+ const char *path, const char *wild, bool dir);
+
+static int
+store_create_info(THD *thd, TABLE *table, String* packet);
+
+/****************************************************************************
+** Send list of databases
+** A database is a directory in the mysql_data_home directory
+****************************************************************************/
+
+
+int
+mysqld_show_dbs(THD *thd,const char *wild)
+{
+ Item_string *field=new Item_string("",0);
+ List<Item> field_list;
+ char *end;
+ List<char> files;
+ char *file_name;
+ DBUG_ENTER("mysqld_show_dbs");
+
+ field->name=(char*) sql_alloc(20+ (wild ? strlen(wild)+4: 0));
+ field->max_length=NAME_LEN;
+ end=strmov(field->name,"Database");
+ if (wild && wild[0])
+ strxmov(end," (",wild,")",NullS);
+ field_list.push_back(field);
+
+ if (send_fields(thd,field_list,1))
+ DBUG_RETURN(1);
+ if (mysql_find_files(thd,&files,NullS,mysql_data_home,wild,1))
+ DBUG_RETURN(1);
+ List_iterator<char> it(files);
+ while ((file_name=it++))
+ {
+ thd->packet.length(0);
+ net_store_data(&thd->packet,file_name);
+ if (my_net_write(&thd->net,(char*) thd->packet.ptr(),thd->packet.length()))
+ DBUG_RETURN(-1);
+ }
+ send_eof(&thd->net);
+ DBUG_RETURN(0);
+}
+
+/***************************************************************************
+** List all tables in a database (fast version)
+** A table is a .frm file in the current databasedir
+***************************************************************************/
+
+int mysqld_show_tables(THD *thd,const char *db,const char *wild)
+{
+ Item_string *field=new Item_string("",0);
+ List<Item> field_list;
+ char path[FN_LEN],*end;
+ List<char> files;
+ char *file_name;
+ DBUG_ENTER("mysqld_show_tables");
+
+ field->name=(char*) sql_alloc(20+strlen(db)+(wild ? strlen(wild)+4:0));
+ end=strxmov(field->name,"Tables_in_",db,NullS);
+ if (wild && wild[0])
+ strxmov(end," (",wild,")",NullS);
+ field->max_length=NAME_LEN;
+ (void) sprintf(path,"%s/%s",mysql_data_home,db);
+ (void) unpack_dirname(path,path);
+ field_list.push_back(field);
+ if (send_fields(thd,field_list,1))
+ DBUG_RETURN(1);
+ if (mysql_find_files(thd,&files,db,path,wild,0))
+ DBUG_RETURN(-1);
+ List_iterator<char> it(files);
+ while ((file_name=it++))
+ {
+ thd->packet.length(0);
+ net_store_data(&thd->packet,file_name);
+ if (my_net_write(&thd->net,(char*) thd->packet.ptr(),thd->packet.length()))
+ DBUG_RETURN(-1);
+ }
+ send_eof(&thd->net);
+ DBUG_RETURN(0);
+}
+
+
+static int
+mysql_find_files(THD *thd,List<char> *files, const char *db,const char *path,
+ const char *wild, bool dir)
+{
+ uint i;
+ char *ext;
+ MY_DIR *dirp;
+ FILEINFO *file;
+ uint col_access=thd->col_access;
+ TABLE_LIST table_list;
+ DBUG_ENTER("mysql_find_files");
+
+ bzero((char*) &table_list,sizeof(table_list));
+
+ if (!(dirp = my_dir(path,MYF(MY_WME | (dir ? MY_WANT_STAT : 0)))))
+ DBUG_RETURN(-1);
+
+ for (i=0 ; i < (uint) dirp->number_off_files ; i++)
+ {
+ file=dirp->dir_entry+i;
+ if (dir)
+ { /* Return databases */
+#ifdef USE_SYMDIR
+ char *ext;
+ if (my_use_symdir && !strcmp(ext=fn_ext(file->name), ".sym"))
+ *ext=0; /* Remove extension */
+ else
+#endif
+ {
+ if (file->name[0] == '.' || !MY_S_ISDIR(file->mystat.st_mode) ||
+ (wild && wild[0] && wild_compare(file->name,wild)))
+ continue;
+ }
+ }
+ else
+ {
+ // Return only .frm files which isn't temp files.
+ if (my_strcasecmp(ext=fn_ext(file->name),reg_ext) ||
+ is_prefix(file->name,tmp_file_prefix)) // Mysql temp table
+ continue;
+ *ext=0;
+ if (wild && wild[0] && wild_compare(file->name,wild))
+ continue;
+ }
+ /* Don't show tables where we don't have any privileges */
+ if (db && !(col_access & TABLE_ACLS))
+ {
+ table_list.db= (char*) db;
+ table_list.real_name=file->name;
+ table_list.grant.privilege=col_access;
+ if (check_grant(thd,TABLE_ACLS,&table_list,1))
+ continue;
+ }
+ if (files->push_back(sql_strdup(file->name)))
+ {
+ my_dirend(dirp);
+ DBUG_RETURN(-1);
+ }
+ }
+ DBUG_PRINT("info",("found: %d files", files->elements));
+ my_dirend(dirp);
+ DBUG_RETURN(0);
+}
+
+/***************************************************************************
+** Extended version of mysqld_show_tables
+***************************************************************************/
+
+int mysqld_extend_show_tables(THD *thd,const char *db,const char *wild)
+{
+ Item *item;
+ List<char> files;
+ List<Item> field_list;
+ char path[FN_LEN];
+ char *file_name;
+ TABLE *table;
+ String *packet= &thd->packet;
+ DBUG_ENTER("mysqld_extend_show_tables");
+
+ (void) sprintf(path,"%s/%s",mysql_data_home,db);
+ (void) unpack_dirname(path,path);
+
+ field_list.push_back(item=new Item_empty_string("Name",NAME_LEN));
+ item->maybe_null=1;
+ field_list.push_back(item=new Item_empty_string("Type",10));
+ item->maybe_null=1;
+ field_list.push_back(item=new Item_empty_string("Row_format",10));
+ item->maybe_null=1;
+ field_list.push_back(item=new Item_int("Rows",(longlong) 1,21));
+ item->maybe_null=1;
+ field_list.push_back(item=new Item_int("Avg_row_length",(int32) 0,21));
+ item->maybe_null=1;
+ field_list.push_back(item=new Item_int("Data_length",(longlong) 1,21));
+ item->maybe_null=1;
+ field_list.push_back(item=new Item_int("Max_data_length",(longlong) 1,21));
+ item->maybe_null=1;
+ field_list.push_back(item=new Item_int("Index_length",(longlong) 1,21));
+ item->maybe_null=1;
+ field_list.push_back(item=new Item_int("Data_free",(longlong) 1,21));
+ item->maybe_null=1;
+ field_list.push_back(item=new Item_int("Auto_increment",(longlong) 1,21));
+ item->maybe_null=1;
+ field_list.push_back(item=new Item_datetime("Create_time"));
+ item->maybe_null=1;
+ field_list.push_back(item=new Item_datetime("Update_time"));
+ item->maybe_null=1;
+ field_list.push_back(item=new Item_datetime("Check_time"));
+ item->maybe_null=1;
+ field_list.push_back(item=new Item_empty_string("Create_options",255));
+ item->maybe_null=1;
+ field_list.push_back(item=new Item_empty_string("Comment",80));
+ if (send_fields(thd,field_list,1))
+ DBUG_RETURN(1);
+
+ if (mysql_find_files(thd,&files,db,path,wild,0))
+ DBUG_RETURN(-1);
+ List_iterator<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);
+ 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);
+ thd->net.last_error[0]=0;
+ }
+ else
+ {
+ 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,
+ (table->db_options_in_use & HA_OPTION_PACK_RECORD) ?
+ "Dynamic" :
+ (table->db_options_in_use & HA_OPTION_COMPRESS_RECORD)
+ ? "Compressed" : "Fixed");
+ net_store_data(packet, (longlong) file->records);
+ net_store_data(packet, (uint32) file->mean_rec_length);
+ net_store_data(packet, (longlong) file->data_file_length);
+ if (file->max_data_file_length)
+ net_store_data(packet, (longlong) file->max_data_file_length);
+ else
+ net_store_null(packet);
+ net_store_data(packet, (longlong) file->index_file_length);
+ net_store_data(packet, (longlong) file->delete_length);
+ if (table->found_next_number_field)
+ {
+ table->next_number_field=table->found_next_number_field;
+ table->next_number_field->reset();
+ file->update_auto_increment();
+ net_store_data(packet, table->next_number_field->val_int());
+ table->next_number_field=0;
+ }
+ else
+ net_store_null(packet);
+ if (!file->create_time)
+ net_store_null(packet);
+ else
+ {
+ localtime_r(&file->create_time,&tm_tmp);
+ net_store_data(packet, &tm_tmp);
+ }
+ if (!file->update_time)
+ net_store_null(packet);
+ else
+ {
+ localtime_r(&file->update_time,&tm_tmp);
+ net_store_data(packet, &tm_tmp);
+ }
+ if (!file->check_time)
+ net_store_null(packet);
+ else
+ {
+ localtime_r(&file->check_time,&tm_tmp);
+ net_store_data(packet, &tm_tmp);
+ }
+ {
+ char option_buff[350],*ptr;
+ ptr=option_buff;
+ if (table->min_rows)
+ {
+ ptr=strmov(ptr," min_rows=");
+ ptr=longlong10_to_str(table->min_rows,ptr,10);
+ }
+ if (table->max_rows)
+ {
+ ptr=strmov(ptr," max_rows=");
+ ptr=longlong10_to_str(table->max_rows,ptr,10);
+ }
+ if (table->avg_row_length)
+ {
+ ptr=strmov(ptr," avg_row_length=");
+ ptr=longlong10_to_str(table->avg_row_length,ptr,10);
+ }
+ if (table->db_create_options & HA_OPTION_PACK_KEYS)
+ ptr=strmov(ptr," pack_keys=1");
+ if (table->db_create_options & HA_OPTION_NO_PACK_KEYS)
+ ptr=strmov(ptr," pack_keys=0");
+ if (table->db_create_options & HA_OPTION_CHECKSUM)
+ ptr=strmov(ptr," checksum=1");
+ if (table->db_create_options & HA_OPTION_DELAY_KEY_WRITE)
+ ptr=strmov(ptr," delay_key_write=1");
+ if (table->row_type != ROW_TYPE_DEFAULT)
+ ptr=strxmov(ptr, " format=", ha_row_type[(uint) table->row_type],
+ NullS);
+ if (file->raid_type)
+ {
+ char buff[100];
+ sprintf(buff," raid_type=%s raid_chunks=%d raid_chunksize=%ld",
+ my_raid_type(file->raid_type), file->raid_chunks, file->raid_chunksize/RAID_BLOCK_SIZE);
+ ptr=strmov(ptr,buff);
+ }
+ net_store_data(packet, option_buff+1,
+ (ptr == option_buff ? 0 : (uint) (ptr-option_buff)-1));
+ }
+ net_store_data(packet, table->comment);
+
+ close_thread_tables(thd,0);
+ }
+ if (my_net_write(&thd->net,(char*) packet->ptr(),
+ packet->length()))
+ DBUG_RETURN(-1);
+ }
+ send_eof(&thd->net);
+ DBUG_RETURN(0);
+}
+
+
+
+/***************************************************************************
+** List all columns in a table
+***************************************************************************/
+
+int
+mysqld_show_fields(THD *thd, TABLE_LIST *table_list,const char *wild)
+{
+ TABLE *table;
+ handler *file;
+ char tmp[MAX_FIELD_WIDTH];
+ DBUG_ENTER("mysqld_show_fields");
+ DBUG_PRINT("enter",("db: %s table: %s",table_list->db,
+ table_list->real_name));
+
+ if (!(table = open_ltable(thd, table_list, TL_UNLOCK)))
+ {
+ send_error(&thd->net);
+ DBUG_RETURN(1);
+ }
+ file=table->file;
+ file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
+ (void) get_table_grant(thd, table_list);
+
+ List<Item> field_list;
+ field_list.push_back(new Item_empty_string("Field",NAME_LEN));
+ field_list.push_back(new Item_empty_string("Type",40));
+ field_list.push_back(new Item_empty_string("Null",1));
+ field_list.push_back(new Item_empty_string("Key",3));
+ field_list.push_back(new Item_empty_string("Default",NAME_LEN));
+ field_list.push_back(new Item_empty_string("Extra",20));
+ field_list.push_back(new Item_empty_string("Privileges",80));
+
+ // Send first number of fields and records
+ {
+ char *pos;
+ pos=net_store_length(tmp, (uint) field_list.elements);
+ pos=net_store_length(pos,(ulonglong) file->records);
+ (void) my_net_write(&thd->net,tmp,(uint) (pos-tmp));
+ }
+
+ if (send_fields(thd,field_list,0))
+ DBUG_RETURN(1);
+ restore_record(table,2); // Get empty record
+
+ Field **ptr,*field;
+ for (ptr=table->field; (field= *ptr) ; ptr++)
+ {
+ if (!wild || !wild[0] || !wild_case_compare(field->field_name,wild))
+ {
+#ifdef NOT_USED
+ if (thd->col_access & TABLE_ACLS ||
+ ! check_grant_column(thd,table,field->field_name,
+ strlen(field->field_name),1))
+#endif
+ {
+ byte *pos;
+ uint flags=field->flags;
+ String *packet= &thd->packet,type(tmp,sizeof(tmp));
+ uint col_access;
+ bool null_default_value=0;
+
+ packet->length(0);
+ net_store_data(packet,field->field_name);
+ field->sql_type(type);
+ net_store_data(packet,type.ptr(),type.length());
+
+ pos=(byte*) ((flags & NOT_NULL_FLAG) &&
+ field->type() != FIELD_TYPE_TIMESTAMP ?
+ "" : "YES");
+ net_store_data(packet,(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);
+
+ if (field->type() == FIELD_TYPE_TIMESTAMP ||
+ field->unireg_check == Field::NEXT_NUMBER)
+ null_default_value=1;
+ if (!null_default_value && !field->is_null())
+ { // Not null by default
+ type.set(tmp,sizeof(tmp));
+ field->val_str(&type,&type);
+ net_store_data(packet,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);
+
+ char *end=tmp;
+ if (field->unireg_check == Field::NEXT_NUMBER)
+ end=strmov(tmp,"auto_increment");
+ net_store_data(packet,tmp,(uint) (end-tmp));
+
+ /* Add grant options */
+ col_access= get_column_grant(thd,table_list,field) & COL_ACLS;
+ end=tmp;
+ for (uint bitnr=0; col_access ; col_access>>=1,bitnr++)
+ {
+ if (col_access & 1)
+ {
+ *end++=',';
+ end=strmov(end,grant_types.type_names[bitnr]);
+ }
+ }
+ net_store_data(packet,tmp+1,end == tmp ? 0 : (uint) (end-tmp-1));
+ if (my_net_write(&thd->net,(char*) packet->ptr(),packet->length()))
+ DBUG_RETURN(1);
+ }
+ }
+ }
+ send_eof(&thd->net);
+ DBUG_RETURN(0);
+}
+
+int
+mysqld_show_create(THD *thd, TABLE_LIST *table_list)
+{
+ TABLE *table;
+ DBUG_ENTER("mysqld_show_create");
+ DBUG_PRINT("enter",("db: %s table: %s",table_list->db,
+ table_list->real_name));
+
+ if (!(table = open_ltable(thd, table_list, TL_UNLOCK)))
+ {
+ send_error(&thd->net);
+ DBUG_RETURN(1);
+ }
+
+ List<Item> field_list;
+ field_list.push_back(new Item_empty_string("Table",NAME_LEN));
+ field_list.push_back(new Item_empty_string("Create Table",1024));
+
+ if (send_fields(thd,field_list,1))
+ DBUG_RETURN(1);
+
+ String *packet = &thd->packet;
+ for(;table; table = table->next)
+ {
+ packet->length(0);
+ net_store_data(packet, 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 :-) )
+ ulong store_len_offset = packet->length();
+ packet->length(store_len_offset + 4);
+ if(store_create_info(thd, table, packet))
+ DBUG_RETURN(-1);
+ ulong create_len = packet->length() - store_len_offset - 4;
+ if(create_len > 0x00ffffff) // better readable in HEX ...
+ DBUG_RETURN(1); // just in case somebody manages to create a table
+ // with *that* much stuff in the definition
+
+ // now we have to store the length in three bytes, even if it would fit
+ // into fewer, so we cannot use net_store_data() anymore,
+ // and do it ourselves
+ char* p = (char*)packet->ptr() + store_len_offset;
+ *p++ = (char) 253; // The client the length is stored using 3-bytes
+ int3store(p, create_len);
+
+ // now we are in business :-)
+ if(my_net_write(&thd->net, (char*)packet->ptr(), packet->length()))
+ DBUG_RETURN(1);
+ }
+
+ send_eof(&thd->net);
+ DBUG_RETURN(0);
+}
+
+
+int
+mysqld_show_keys(THD *thd, TABLE_LIST *table_list)
+{
+ TABLE *table;
+ char buff[256];
+ DBUG_ENTER("mysqld_show_keys");
+ DBUG_PRINT("enter",("db: %s table: %s",table_list->db,
+ table_list->real_name));
+
+ if (!(table = open_ltable(thd, table_list, TL_UNLOCK)))
+ {
+ send_error(&thd->net);
+ DBUG_RETURN(1);
+ }
+
+ List<Item> field_list;
+ Item *item;
+ field_list.push_back(new Item_empty_string("Table",NAME_LEN));
+ field_list.push_back(new Item_int("Non_unique",0,1));
+ field_list.push_back(new Item_empty_string("Key_name",NAME_LEN));
+ field_list.push_back(new Item_int("Seq_in_index",0,2));
+ field_list.push_back(new Item_empty_string("Column_name",NAME_LEN));
+ field_list.push_back(item=new Item_empty_string("Collation",1));
+ item->maybe_null=1;
+ field_list.push_back(item=new Item_int("Cardinality",0,11));
+ item->maybe_null=1;
+ field_list.push_back(item=new Item_int("Sub_part",0,3));
+ 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("Comment",255));
+ item->maybe_null=1;
+
+ if (send_fields(thd,field_list,1))
+ DBUG_RETURN(1);
+
+ KEY *key_info=table->key_info;
+ table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK | HA_STATUS_TIME);
+ for (uint i=0 ; i < table->keys ; i++,key_info++)
+ {
+ KEY_PART_INFO *key_part= key_info->key_part;
+ char *end;
+ String *packet= &thd->packet;
+ 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);
+ 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 :
+ "?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);
+ else
+ net_store_null(packet); /* purecov: inspected */
+ KEY *key=table->key_info+i;
+ if (key->rec_per_key[j])
+ {
+ 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));
+ }
+ else
+ net_store_null(packet);
+ 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 */
+ }
+ else
+ net_store_null(packet);
+ net_store_null(packet); // No pack_information yet
+ net_store_null(packet); // No comments yet
+ if (my_net_write(&thd->net,(char*) packet->ptr(),packet->length()))
+ DBUG_RETURN(1); /* purecov: inspected */
+ }
+ }
+ send_eof(&thd->net);
+ DBUG_RETURN(0);
+}
+
+
+/****************************************************************************
+** Return only fields for API mysql_list_fields
+** Use "show table wildcard" in mysql instead of this
+****************************************************************************/
+
+void
+mysqld_list_fields(THD *thd, TABLE_LIST *table_list, const char *wild)
+{
+ TABLE *table;
+ DBUG_ENTER("mysqld_list_fields");
+ DBUG_PRINT("enter",("table: %s",table_list->real_name));
+
+ if (!(table = open_ltable(thd, table_list, TL_UNLOCK)))
+ {
+ send_error(&thd->net);
+ DBUG_VOID_RETURN;
+ }
+ List<Item> field_list;
+
+ Field **ptr,*field;
+ for (ptr=table->field ; (field= *ptr); ptr++)
+ {
+ if (!wild || !wild[0] || !wild_case_compare(field->field_name,wild))
+ field_list.push_back(new Item_field(field));
+ }
+ restore_record(table,2); // Get empty record
+ if (send_fields(thd,field_list,2))
+ DBUG_VOID_RETURN;
+ VOID(net_flush(&thd->net));
+ DBUG_VOID_RETURN;
+}
+
+int
+mysqld_dump_create_info(THD *thd, TABLE *table, int fd)
+{
+ 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))
+ DBUG_RETURN(-1);
+
+ if(fd < 0)
+ {
+ 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)))
+ DBUG_RETURN(-1);
+ }
+
+ DBUG_RETURN(0);
+}
+
+static int
+store_create_info(THD *thd, TABLE *table, String* packet)
+{
+ DBUG_ENTER("store_create_info");
+ DBUG_PRINT("enter",("table: %s",table->real_name));
+
+ restore_record(table,2); // Get empty record
+
+ List<Item> field_list;
+ char tmp[MAX_FIELD_WIDTH];
+ String type(tmp, sizeof(tmp));
+ packet->append("create table ", 13);
+ packet->append(table->real_name);
+ packet->append('(');
+
+ Field **ptr,*field;
+ for (ptr=table->field ; (field= *ptr); ptr++)
+ {
+ if(ptr != table->field)
+ packet->append(',');
+
+ uint flags = field->flags;
+ packet->append(field->field_name);
+ packet->append(' ');
+ // check for surprises from the previous call to Field::sql_type()
+ if(type.ptr() != tmp)
+ type.set(tmp, sizeof(tmp));
+
+ field->sql_type(type);
+ packet->append(type.ptr(),type.length());
+
+ bool null_default_value = (field->type() == FIELD_TYPE_TIMESTAMP ||
+ field->unireg_check == Field::NEXT_NUMBER);
+ bool has_default = (field->type() != FIELD_TYPE_BLOB);
+
+ if((flags & NOT_NULL_FLAG) && !null_default_value)
+ packet->append(" not null", 9);
+
+
+ if(has_default)
+ {
+ packet->append(" default ", 9);
+ if (!null_default_value && !field->is_null())
+ { // Not null by default
+ type.set(tmp,sizeof(tmp));
+ field->val_str(&type,&type);
+ packet->append('\'');
+ packet->append(type.ptr(),type.length());
+ packet->append('\'');
+ }
+ else if (field->maybe_null() || null_default_value)
+ packet->append("NULL", 4); // Null as default
+ else
+ packet->append(tmp,0);
+ }
+
+ if (field->unireg_check == Field::NEXT_NUMBER)
+ packet->append(" auto_increment", 15 );
+
+
+ }
+
+ KEY *key_info=table->key_info;
+ table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK | HA_STATUS_TIME);
+ uint primary_key = table->primary_key;
+
+ for (uint i=0 ; i < table->keys ; i++,key_info++)
+ {
+ packet->append(',');
+
+ KEY_PART_INFO *key_part= key_info->key_part;
+ if(i == primary_key)
+ packet->append("primary", 7);
+ else if(key_info->flags & HA_NOSAME)
+ packet->append("unique", 6);
+ packet->append(" key ", 5);
+
+ if(i != primary_key)
+ packet->append(key_info->name);
+
+ packet->append('(');
+
+ for (uint j=0 ; j < key_info->key_parts ; j++,key_part++)
+ {
+ if(j)
+ packet->append(',');
+
+ if(key_part->field)
+ packet->append(key_part->field->field_name);
+ KEY *key=table->key_info+i;
+
+ if (!key_part->field ||
+ key_part->length !=
+ table->field[key_part->fieldnr-1]->key_length())
+ {
+ char buff[64];
+ buff[0] = '(';
+ char* end=int10_to_str((long) key_part->length, buff + 1,10);
+ *end++ = ')';
+ packet->append(buff,(uint) (end-buff));
+ }
+ }
+
+ packet->append(')');
+ }
+
+ packet->append(')');
+
+ handler *file = table->file;
+ packet->append(" type=", 6);
+ packet->append(file->table_type());
+ char buff[128];
+ char* p;
+
+ if(table->min_rows)
+ {
+ packet->append(" min_rows=");
+ p = longlong10_to_str(table->min_rows, buff, 10);
+ packet->append(buff, (uint) (p - buff));
+ }
+
+ if(table->max_rows)
+ {
+ packet->append(" max_rows=");
+ p = longlong10_to_str(table->max_rows, buff, 10);
+ packet->append(buff, (uint) (p - buff));
+ }
+
+ if (table->db_create_options & HA_OPTION_PACK_KEYS)
+ packet->append(" pack_keys=1", 12);
+ if (table->db_create_options & HA_OPTION_NO_PACK_KEYS)
+ packet->append(" pack_keys=0", 12);
+ if (table->db_create_options & HA_OPTION_CHECKSUM)
+ packet->append(" checksum=1", 11);
+ if (table->db_create_options & HA_OPTION_DELAY_KEY_WRITE)
+ packet->append(" delay_key_write=1",18);
+
+
+ DBUG_RETURN(0);
+}
+
+
+/****************************************************************************
+** Return info about all processes
+** returns for each thread: thread id, user, host, db, command, info
+****************************************************************************/
+
+class thread_info :public ilink {
+public:
+ static void *operator new(size_t size) {return (void*) sql_alloc(size); }
+ static void operator delete(void *ptr __attribute__((unused)),
+ size_t size __attribute__((unused))) {} /*lint -e715 */
+
+ ulong thread_id,start_time;
+ uint command;
+ const char *user,*host,*db,*proc_info,*state_info;
+ char *query;
+};
+
+#ifdef __GNUC__
+template class I_List<thread_info>;
+#endif
+
+
+void mysqld_list_processes(THD *thd,const char *user, bool verbose)
+{
+ Item *field;
+ List<Item> field_list;
+ I_List<thread_info> thread_infos;
+ ulong max_query_length= verbose ? max_allowed_packet : PROCESS_LIST_WIDTH;
+ DBUG_ENTER("mysqld_list_processes");
+
+ field_list.push_back(new Item_int("Id",0,7));
+ field_list.push_back(new Item_empty_string("User",16));
+ field_list.push_back(new Item_empty_string("Host",64));
+ field_list.push_back(field=new Item_empty_string("db",NAME_LEN));
+ field->maybe_null=1;
+ field_list.push_back(new Item_empty_string("Command",16));
+ field_list.push_back(new Item_empty_string("Time",7));
+ field_list.push_back(field=new Item_empty_string("State",30));
+ field->maybe_null=1;
+ field_list.push_back(field=new Item_empty_string("Info",max_query_length));
+ field->maybe_null=1;
+ if (send_fields(thd,field_list,1))
+ DBUG_VOID_RETURN;
+
+ VOID(pthread_mutex_lock(&LOCK_thread_count)); // For unlink from list
+ if (!thd->killed)
+ {
+ I_List_iterator<THD> it(threads);
+ THD *tmp;
+ while ((tmp=it++))
+ {
+ if ((tmp->net.vio || tmp->system_thread) &&
+ (!user || (tmp->user && !strcmp(tmp->user,user))))
+ {
+ thread_info *thd_info=new thread_info;
+
+ thd_info->thread_id=tmp->thread_id;
+ thd_info->user=sql_strdup(tmp->user ? tmp->user : (tmp->system_thread ?
+ "system user" : "unauthenticated user"));
+ thd_info->host=sql_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=sql_strdup(thd_info->db);
+ thd_info->command=(int) tmp->command;
+ if (tmp->mysys_var)
+ pthread_mutex_lock(&tmp->mysys_var->mutex);
+ thd_info->proc_info= (char*) (tmp->killed ? "Killed" : 0);
+ thd_info->state_info= (char*) (tmp->locked ? "Locked" :
+ tmp->net.reading_or_writing ?
+ (tmp->net.reading_or_writing == 2 ?
+ "Writing to net" :
+ thd_info->command == COM_SLEEP ? "" :
+ "Reading from net") :
+ tmp->proc_info ? tmp->proc_info :
+ tmp->mysys_var &&
+ tmp->mysys_var->current_cond ?
+ "Waiting on cond" : NullS);
+ if (tmp->mysys_var)
+ pthread_mutex_unlock(&tmp->mysys_var->mutex);
+
+#if !defined(DONT_USE_THR_ALARM) && ! defined(SCO)
+ if (pthread_kill(tmp->real_id,0))
+ tmp->proc_info="*** DEAD ***"; // This shouldn't happen
+#endif
+ thd_info->start_time= tmp->start_time;
+ thd_info->query=0;
+ if (tmp->query)
+ {
+ uint length=strlen(tmp->query);
+ if (length > max_query_length)
+ length=max_query_length;
+ thd_info->query=(char*) sql_memdup(tmp->query,length+1);
+ thd_info->query[length]=0;
+ }
+ thread_infos.append(thd_info);
+ }
+ }
+ }
+ VOID(pthread_mutex_unlock(&LOCK_thread_count));
+
+ thread_info *thd_info;
+ String *packet= &thd->packet;
+ while ((thd_info=thread_infos.get()))
+ {
+ 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);
+ if (thd_info->db)
+ net_store_data(packet,thd_info->db);
+ else
+ net_store_null(packet);
+ if (thd_info->proc_info)
+ net_store_data(packet,thd_info->proc_info);
+ else
+ net_store_data(packet,command_name[thd_info->command]);
+ if (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);
+ else
+ net_store_null(packet);
+ if (thd_info->query)
+ net_store_data(packet,thd_info->query);
+ else
+ net_store_null(packet);
+ if (my_net_write(&thd->net,(char*) packet->ptr(),packet->length()))
+ break; /* purecov: inspected */
+ }
+ send_eof(&thd->net);
+ DBUG_VOID_RETURN;
+}
+
+
+/*****************************************************************************
+** Status functions
+*****************************************************************************/
+
+
+int mysqld_show(THD *thd, const char *wild, show_var_st *variables)
+{
+ uint i;
+ char buff[8192];
+ String packet2(buff,sizeof(buff));
+ List<Item> field_list;
+ 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));
+ if (send_fields(thd,field_list,1))
+ DBUG_RETURN(1); /* purecov: inspected */
+
+ pthread_mutex_lock(&THR_LOCK_keycache);
+ pthread_mutex_lock(&LOCK_status);
+ for (i=0; variables[i].name; i++)
+ {
+ if (!(wild && wild[0] && wild_compare(variables[i].name,wild)))
+ {
+ packet2.length(0);
+ net_store_data(&packet2,variables[i].name);
+ switch (variables[i].type){
+ case SHOW_LONG:
+ case SHOW_LONG_CONST:
+ net_store_data(&packet2,(uint32) *(ulong*) variables[i].value);
+ break;
+ case SHOW_BOOL:
+ net_store_data(&packet2,(ulong) *(bool*) variables[i].value ?
+ "ON" : "OFF");
+ break;
+ case SHOW_MY_BOOL:
+ net_store_data(&packet2,(ulong) *(my_bool*) variables[i].value ?
+ "ON" : "OFF");
+ break;
+ case SHOW_INT_CONST:
+ case SHOW_INT:
+ net_store_data(&packet2,(uint32) *(int*) variables[i].value);
+ break;
+ case SHOW_CHAR:
+ net_store_data(&packet2,variables[i].value);
+ break;
+ case SHOW_STARTTIME:
+ net_store_data(&packet2,(uint32) (thd->query_start() - start_time));
+ break;
+ case SHOW_QUESTION:
+ net_store_data(&packet2,(uint32) thd->query_id);
+ 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 : "");
+ break;
+ }
+ }
+ if (my_net_write(&thd->net, (char*) packet2.ptr(),packet2.length()))
+ goto err; /* purecov: inspected */
+ }
+ }
+ pthread_mutex_unlock(&LOCK_status);
+ pthread_mutex_unlock(&THR_LOCK_keycache);
+ send_eof(&thd->net);
+ DBUG_RETURN(0);
+
+ err:
+ pthread_mutex_unlock(&LOCK_status);
+ pthread_mutex_unlock(&THR_LOCK_keycache);
+ DBUG_RETURN(1);
+}
+
+#ifdef __GNUC__
+template class List_iterator<char>;
+template class List<char>;
+#endif
diff --git a/sql/sql_string.cc b/sql/sql_string.cc
new file mode 100644
index 00000000000..c18f9e3807e
--- /dev/null
+++ b/sql/sql_string.cc
@@ -0,0 +1,741 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 */
+
+#ifdef __GNUC__
+#pragma implementation // gcc: Class implementation
+#endif
+
+#include <global.h>
+#include <my_sys.h>
+#include <m_string.h>
+#include <m_ctype.h>
+#ifdef HAVE_FCONVERT
+#include <floatingpoint.h>
+#endif
+
+extern gptr sql_alloc(unsigned size);
+extern void sql_element_free(void *ptr);
+
+#include "sql_string.h"
+
+/*****************************************************************************
+** String functions
+*****************************************************************************/
+
+bool String::real_alloc(uint32 arg_length)
+{
+ arg_length=ALIGN_SIZE(arg_length+1);
+ if (Alloced_length < arg_length)
+ {
+ free();
+ if (!(Ptr=(char*) my_malloc(arg_length,MYF(MY_WME))))
+ {
+ str_length=0;
+ return TRUE;
+ }
+ Alloced_length=arg_length;
+ alloced=1;
+ }
+ Ptr[0]=0;
+ str_length=0;
+ return FALSE;
+}
+
+
+/*
+** Check that string is big enough. Set string[alloc_length] to 0
+** (for C functions)
+*/
+
+bool String::realloc(uint32 alloc_length)
+{
+ uint32 len=ALIGN_SIZE(alloc_length+1);
+ if (Alloced_length < len)
+ {
+ char *new_ptr;
+ if (alloced)
+ {
+ if ((new_ptr= (char*) my_realloc(Ptr,len,MYF(MY_WME))))
+ {
+ Ptr=new_ptr;
+ Alloced_length=len;
+ }
+ else
+ return TRUE; // Signal error
+ }
+ else if ((new_ptr= (char*) my_malloc(len,MYF(MY_WME))))
+ {
+ memcpy(new_ptr,Ptr,str_length);
+ new_ptr[str_length]=0;
+ Ptr=new_ptr;
+ Alloced_length=len;
+ alloced=1;
+ }
+ else
+ return TRUE; // Signal error
+ }
+ Ptr[alloc_length]=0; // This make other funcs shorter
+ return FALSE;
+}
+
+
+#ifdef NOT_NEEDED
+bool String::set(long num)
+{
+ if (alloc(14))
+ return TRUE;
+ str_length=(uint32) (int10_to_str(num,Ptr,-10)-Ptr);
+ return FALSE;
+}
+#endif
+
+bool String::set(longlong num)
+{
+ if (alloc(21))
+ return TRUE;
+ str_length=(uint32) (longlong10_to_str(num,Ptr,-10)-Ptr);
+ return FALSE;
+}
+
+bool String::set(ulonglong num)
+{
+ if (alloc(21))
+ return TRUE;
+ str_length=(uint32) (longlong10_to_str(num,Ptr,10)-Ptr);
+ return FALSE;
+}
+
+bool String::set(double num,uint decimals)
+{
+ char buff[331];
+ if (decimals >= NOT_FIXED_DEC)
+ {
+ sprintf(buff,"%.14g",num); // Enough for a DATETIME
+ return copy(buff,strlen(buff));
+ }
+#ifdef HAVE_FCONVERT
+ int decpt,sign;
+ char *pos,*to;
+
+ VOID(fconvert(num,(int) decimals,&decpt,&sign,buff+1));
+ if (!isdigit(buff[1]))
+ { // Nan or Inf
+ pos=buff+1;
+ if (sign)
+ {
+ buff[0]='-';
+ pos=buff;
+ }
+ return copy(pos,strlen(pos));
+ }
+ if (alloc((uint32) ((uint32) decpt+3+decimals)))
+ return TRUE;
+ to=Ptr;
+ if (sign)
+ *to++='-';
+
+ pos=buff+1;
+ if (decpt < 0)
+ { /* value is < 0 */
+ *to++='0';
+ if (!decimals)
+ goto end;
+ *to++='.';
+ if ((uint32) -decpt > decimals)
+ decpt= - (int) decimals;
+ decimals=(uint32) ((int) decimals+decpt);
+ while (decpt++ < 0)
+ *to++='0';
+ }
+ else if (decpt == 0)
+ {
+ *to++= '0';
+ if (!decimals)
+ goto end;
+ *to++='.';
+ }
+ else
+ {
+ while (decpt-- > 0)
+ *to++= *pos++;
+ if (!decimals)
+ goto end;
+ *to++='.';
+ }
+ while (decimals--)
+ *to++= *pos++;
+
+end:
+ *to=0;
+ str_length=(uint32) (to-Ptr);
+ return FALSE;
+#else
+#ifdef HAVE_SNPRINTF_
+ snprintf(buff,sizeof(buff), "%.*f",(int) decimals,num);
+#else
+ sprintf(buff,"%.*f",(int) decimals,num);
+#endif
+ return copy(buff,strlen(buff));
+#endif
+}
+
+
+bool String::copy()
+{
+ if (!alloced)
+ {
+ Alloced_length=0; // Force realloc
+ return realloc(str_length);
+ }
+ return FALSE;
+}
+
+bool String::copy(const String &str)
+{
+ if (alloc(str.str_length))
+ return TRUE;
+ str_length=str.str_length;
+ bmove(Ptr,str.Ptr,str_length); // May be overlapping
+ Ptr[str_length]=0;
+ return FALSE;
+}
+
+bool String::copy(const char *str,uint32 arg_length)
+{
+ if (alloc(arg_length))
+ return TRUE;
+ str_length=arg_length;
+ memcpy(Ptr,str,arg_length);
+ Ptr[arg_length]=0;
+ return FALSE;
+}
+
+/* This is used by mysql.cc */
+
+bool String::fill(uint32 max_length,char fill_char)
+{
+ if (str_length > max_length)
+ Ptr[str_length=max_length]=0;
+ else
+ {
+ if (realloc(max_length))
+ return TRUE;
+ bfill(Ptr+str_length,max_length-str_length,fill_char);
+ str_length=max_length;
+ }
+ return FALSE;
+}
+
+void String::strip_sp()
+{
+ while (str_length && isspace(Ptr[str_length-1]))
+ str_length--;
+}
+
+bool String::append(const String &s)
+{
+ if (realloc(str_length+s.length()))
+ return TRUE;
+ memcpy(Ptr+str_length,s.ptr(),s.length());
+ str_length+=s.length();
+ return FALSE;
+}
+
+bool String::append(const char *s,uint32 arg_length)
+{
+ if (!arg_length) // Default argument
+ arg_length=strlen(s);
+ if (realloc(str_length+arg_length))
+ return TRUE;
+ memcpy(Ptr+str_length,s,arg_length);
+ str_length+=arg_length;
+ return FALSE;
+}
+
+bool String::append(FILE* file, uint32 arg_length, myf my_flags)
+{
+ if (realloc(str_length+arg_length))
+ return TRUE;
+ if (my_fread(file, (byte*) Ptr + str_length, arg_length, my_flags))
+ {
+ shrink(str_length);
+ return TRUE;
+ }
+ str_length+=arg_length;
+ return FALSE;
+}
+
+uint32 String::numchars()
+{
+#ifdef USE_MB
+ register uint32 n=0,mblen;
+ register const char *mbstr=Ptr;
+ register const char *end=mbstr+str_length;
+ if (use_mb(default_charset_info))
+ {
+ while (mbstr < end) {
+ if ((mblen=my_ismbchar(default_charset_info, mbstr,end))) mbstr+=mblen;
+ else ++mbstr;
+ ++n;
+ }
+ return n;
+ }
+ else
+#endif
+ return str_length;
+}
+
+int String::charpos(int i,uint32 offset)
+{
+#ifdef USE_MB
+ register uint32 mblen;
+ register const char *mbstr=Ptr+offset;
+ register const char *end=Ptr+str_length;
+ if (use_mb(default_charset_info))
+ {
+ if (i<=0) return i;
+ while (i && mbstr < end) {
+ if ((mblen=my_ismbchar(default_charset_info, mbstr,end))) mbstr+=mblen;
+ else ++mbstr;
+ --i;
+ }
+ if ( INT_MAX32-i <= (int) (mbstr-Ptr-offset))
+ return INT_MAX32;
+ else
+ return (mbstr-Ptr-offset)+i;
+ }
+ else
+#endif
+ return i;
+}
+
+int String::strstr(const String &s,uint32 offset)
+{
+ if (s.length()+offset <= str_length)
+ {
+ if (!s.length())
+ return 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 (*str++ == *search)
+ {
+ register char *i,*j;
+ i=(char*) str; j=(char*) search+1;
+ while (j != search_end)
+ if (*i++ != *j++) goto skipp;
+ return (int) (str-Ptr) -1;
+ }
+ }
+ }
+ return -1;
+}
+
+
+/*
+** Search string from end. Offset is offset to the end of string
+*/
+
+int String::strrstr(const String &s,uint32 offset)
+{
+ if (s.length() <= offset && offset <= str_length)
+ {
+ if (!s.length())
+ return offset; // Empty string is always found
+ register const char *str = Ptr+offset-1;
+ register const char *search=s.ptr()+s.length()-1;
+
+ const char *end=Ptr+s.length()-2;
+ const char *search_end=s.ptr()-1;
+skipp:
+ while (str != end)
+ {
+ if (*str-- == *search)
+ {
+ register char *i,*j;
+ i=(char*) str; j=(char*) search-1;
+ while (j != search_end)
+ if (*i-- != *j--) goto skipp;
+ return (int) (i-Ptr) +1;
+ }
+ }
+ }
+ return -1;
+}
+
+/*
+** replace substring with string
+** If wrong parameter or not enough memory, do nothing
+*/
+
+
+bool String::replace(uint32 offset,uint32 arg_length,const String &to)
+{
+ long diff = (long) to.length()-(long) arg_length;
+ if (offset+arg_length <= str_length)
+ {
+ if (diff < 0)
+ {
+ memcpy(Ptr+offset,to.ptr(),to.length());
+ bmove(Ptr+offset+to.length(),Ptr+offset+arg_length,
+ str_length-offset-arg_length);
+ }
+ else
+ {
+ if (diff)
+ {
+ if (realloc(str_length+(uint32) diff))
+ return TRUE;
+ bmove_upp(Ptr+str_length+diff,Ptr+str_length,
+ str_length-offset-arg_length);
+ }
+ memcpy(Ptr+offset,to.ptr(),to.length());
+ }
+ str_length+=(uint32) diff;
+ }
+ return FALSE;
+}
+
+
+int sortcmp(const String *x,const String *y)
+{
+ const char *s= x->ptr();
+ const char *t= y->ptr();
+ uint32 x_len=x->length(),y_len=y->length(),len=min(x_len,y_len);
+
+#ifdef USE_STRCOLL
+ if (use_strcoll(default_charset_info))
+ {
+#ifndef CMP_ENDSPACE
+ while (x_len && isspace(s[x_len-1]))
+ x_len--;
+ while (y_len && isspace(t[y_len-1]))
+ y_len--;
+#endif
+ return my_strnncoll(default_charset_info,
+ (unsigned char *)s,x_len,(unsigned char *)t,y_len);
+ }
+ else
+ {
+#endif /* USE_STRCOLL */
+ x_len-=len; // For easy end space test
+ y_len-=len;
+ while (len--)
+ {
+ if (my_sort_order[(uchar) *s++] != my_sort_order[(uchar) *t++])
+ return ((int) my_sort_order[(uchar) s[-1]] -
+ (int) my_sort_order[(uchar) t[-1]]);
+ }
+#ifndef CMP_ENDSPACE
+ /* Don't compare end space in strings */
+ {
+ if (y_len)
+ {
+ const char *end=t+y_len;
+ for (; t != end ; t++)
+ if (!isspace(*t))
+ return -1;
+ }
+ else
+ {
+ const char *end=s+x_len;
+ for (; s != end ; s++)
+ if (!isspace(*s))
+ return 1;
+ }
+ return 0;
+ }
+#else
+ return (int) (x_len-y_len);
+#endif /* CMP_ENDSPACE */
+#ifdef USE_STRCOLL
+ }
+#endif
+}
+
+
+int stringcmp(const String *x,const String *y)
+{
+ const char *s= x->ptr();
+ const char *t= y->ptr();
+ uint32 x_len=x->length(),y_len=y->length(),len=min(x_len,y_len);
+
+ while (len--)
+ {
+ if (*s++ != *t++)
+ return ((int) (uchar) s[-1] - (int) (uchar) t[-1]);
+ }
+ return (int) (x_len-y_len);
+}
+
+
+String *copy_if_not_alloced(String *to,String *from,uint32 from_length)
+{
+ if (from->Alloced_length >= from_length)
+ return from;
+ if (from->alloced || !to || from == to)
+ {
+ (void) from->realloc(from_length);
+ return from;
+ }
+ if (to->realloc(from_length))
+ return from; // Actually an error
+ to->str_length=min(from->str_length,from_length);
+ memcpy(to->Ptr,from->Ptr,to->str_length);
+ return to;
+}
+
+/* Make it easier to handle different charactersets */
+
+#ifdef USE_MB
+#define INC_PTR(A,B) A+=((use_mb_flag && \
+ my_ismbchar(default_charset_info,A,B)) ? \
+ my_ismbchar(default_charset_info,A,B) : 1)
+#else
+#define INC_PTR(A,B) A++
+#endif
+
+/*
+** Compare string against string with wildcard
+** 0 if matched
+** -1 if not matched with wildcard
+** 1 if matched with wildcard
+*/
+
+#ifdef LIKE_CMP_TOUPPER
+#define likeconv(A) (uchar) toupper(A)
+#else
+#define likeconv(A) (uchar) my_sort_order[(uchar) (A)]
+#endif
+
+static int wild_case_compare(const char *str,const char *str_end,
+ const char *wildstr,const char *wildend,
+ char escape)
+{
+ int result= -1; // Not found, using wildcards
+#ifdef USE_MB
+ bool use_mb_flag=use_mb(default_charset_info);
+#endif
+ while (wildstr != wildend)
+ {
+ while (*wildstr != wild_many && *wildstr != wild_one)
+ {
+ if (*wildstr == escape && wildstr+1 != wildend)
+ wildstr++;
+#ifdef USE_MB
+ int l;
+ if (use_mb_flag &&
+ (l = my_ismbchar(default_charset_info, wildstr, wildend)))
+ {
+ if (str+l > str_end || memcmp(str, wildstr, l) != 0)
+ return 1;
+ str += l;
+ wildstr += l;
+ }
+ else
+#endif
+ if (str == str_end || likeconv(*wildstr++) != likeconv(*str++))
+ return(1); // No match
+ if (wildstr == wildend)
+ 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);
+ INC_PTR(str,str_end);
+ } while (++wildstr < wildend && *wildstr == wild_one);
+ if (wildstr == wildend)
+ break;
+ }
+ if (*wildstr == wild_many)
+ { // Found wild_many
+ wildstr++;
+ /* Remove any '%' and '_' from the wild search string */
+ for ( ; wildstr != wildend ; wildstr++)
+ {
+ if (*wildstr == wild_many)
+ continue;
+ if (*wildstr == wild_one)
+ {
+ if (str == str_end)
+ return (-1);
+ INC_PTR(str,str_end);
+ continue;
+ }
+ break; // Not a wild character
+ }
+ if (wildstr == wildend)
+ return(0); // Ok if wild_many is last
+ if (str == str_end)
+ return -1;
+
+ uchar cmp;
+ if ((cmp= *wildstr) == escape && wildstr+1 != wildend)
+ cmp= *++wildstr;
+#ifdef USE_MB
+ const char* mb = wildstr;
+ int mblen;
+ LINT_INIT(mblen);
+ if (use_mb_flag)
+ mblen = my_ismbchar(default_charset_info, wildstr, wildend);
+#endif
+ INC_PTR(wildstr,wildend); // This is compared trough cmp
+ cmp=likeconv(cmp);
+ do
+ {
+#ifdef USE_MB
+ if (use_mb_flag)
+ {
+ for (;;)
+ {
+ if (str >= str_end)
+ return -1;
+ if (mblen)
+ {
+ if (str+mblen <= str_end && memcmp(str, mb, mblen) == 0)
+ {
+ str += mblen;
+ break;
+ }
+ }
+ else if (!my_ismbchar(default_charset_info, str, str_end) &&
+ likeconv(*str) == cmp)
+ {
+ str++;
+ break;
+ }
+ INC_PTR(str, str_end);
+ }
+ }
+ else
+ {
+#endif /* USE_MB */
+ while (str != str_end && likeconv(*str) != cmp)
+ str++;
+ if (str++ == str_end) return (-1);
+#ifdef USE_MB
+ }
+#endif
+ {
+ int tmp=wild_case_compare(str,str_end,wildstr,wildend,escape);
+ if (tmp <= 0)
+ return (tmp);
+ }
+ } while (str != str_end && wildstr[0] != wild_many);
+ return(-1);
+ }
+ }
+ return (str != str_end ? 1 : 0);
+}
+
+
+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);
+}
+
+/*
+** The following is used when using LIKE on binary strings
+*/
+
+static int wild_compare(const char *str,const char *str_end,
+ const char *wildstr,const char *wildend,char escape)
+{
+ int result= -1; // Not found, using wildcards
+ while (wildstr != wildend)
+ {
+ while (*wildstr != wild_many && *wildstr != wild_one)
+ {
+ if (*wildstr == escape && wildstr+1 != wildend)
+ wildstr++;
+ if (str == str_end || *wildstr++ != *str++)
+ return(1);
+ if (wildstr == wildend)
+ 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);
+ str++;
+ } while (*++wildstr == wild_one && wildstr != wildend);
+ if (wildstr == wildend)
+ break;
+ }
+ if (*wildstr == wild_many)
+ { // Found wild_many
+ wildstr++;
+ /* Remove any '%' and '_' from the wild search string */
+ for ( ; wildstr != wildend ; wildstr++)
+ {
+ if (*wildstr == wild_many)
+ continue;
+ if (*wildstr == wild_one)
+ {
+ if (str == str_end)
+ return (-1);
+ str++;
+ continue;
+ }
+ break; // Not a wild character
+ }
+ if (wildstr == wildend)
+ return(0); // Ok if wild_many is last
+ if (str == str_end)
+ return -1;
+
+ char cmp;
+ if ((cmp= *wildstr) == escape && wildstr+1 != wildend)
+ cmp= *++wildstr;
+ wildstr++; // This is compared trough cmp
+ do
+ {
+ while (str != str_end && *str != cmp)
+ str++;
+ if (str++ == str_end) return (-1);
+ {
+ int tmp=wild_compare(str,str_end,wildstr,wildend,escape);
+ if (tmp <= 0)
+ return (tmp);
+ }
+ } while (str != str_end && wildstr[0] != wild_many);
+ return(-1);
+ }
+ }
+ 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);
+}
diff --git a/sql/sql_string.h b/sql/sql_string.h
new file mode 100644
index 00000000000..5d125422c0b
--- /dev/null
+++ b/sql/sql_string.h
@@ -0,0 +1,183 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 */
+
+#ifdef __GNUC__
+#pragma interface /* gcc class implementation */
+#endif
+
+#ifndef NOT_FIXED_DEC
+#define NOT_FIXED_DEC 31
+#endif
+
+class String
+{
+ char *Ptr;
+ uint32 str_length,Alloced_length;
+ bool alloced;
+public:
+ String()
+ { Ptr=0; str_length=Alloced_length=0; alloced=0; }
+ String(uint32 length_arg)
+ { alloced=0; Alloced_length=0; (void) real_alloc(length_arg); }
+ String(const char *str)
+ { Ptr=(char*) str; str_length=strlen(str); Alloced_length=0; alloced=0;}
+ String(const char *str,uint32 len)
+ { Ptr=(char*) str; str_length=len; Alloced_length=0; alloced=0;}
+ String(char *str,uint32 len)
+ { Ptr=(char*) str; Alloced_length=str_length=len; alloced=0;}
+ String(const String &str)
+ { Ptr=str.Ptr ; str_length=str.str_length ;
+ Alloced_length=str.Alloced_length; alloced=0; }
+
+ static void *operator new(size_t size) { return (void*) sql_alloc(size); }
+ static void operator delete(void *ptr_arg,size_t size) /*lint -e715 */
+ { sql_element_free(ptr_arg); }
+ ~String() { free(); }
+
+ inline uint32 length() const { return str_length;}
+ inline uint32 alloced_length() const { return Alloced_length;}
+ inline char& operator [] (uint32 i) const { return Ptr[i]; }
+ inline void length(uint32 len) { str_length=len ; }
+ inline bool is_empty() { return (str_length == 0); }
+ inline const char *ptr() const { return Ptr; }
+ inline char *c_ptr()
+ {
+ if (!Ptr || Ptr[str_length]) /* Should be safe */
+ (void) realloc(str_length);
+ return Ptr;
+ }
+ inline char *c_ptr_quick()
+ {
+ if (Ptr && str_length < Alloced_length)
+ Ptr[str_length]=0;
+ return Ptr;
+ }
+
+ void set(String &str,uint32 offset,uint32 arg_length)
+ {
+ free();
+ Ptr=(char*) str.ptr()+offset; str_length=arg_length; alloced=0;
+ if (str.Alloced_length)
+ Alloced_length=str.Alloced_length-offset;
+ else
+ Alloced_length=0;
+ }
+ inline void set(char *str,uint32 arg_length)
+ {
+ free();
+ Ptr=(char*) str; str_length=Alloced_length=arg_length ; alloced=0;
+ }
+ inline void set(const char *str,uint32 arg_length)
+ {
+ free();
+ Ptr=(char*) str; str_length=arg_length; Alloced_length=0 ; alloced=0;
+ }
+ inline void set_quick(char *str,uint32 arg_length)
+ {
+ if (!alloced)
+ {
+ Ptr=(char*) str; str_length=Alloced_length=arg_length;
+ }
+ }
+ bool set(longlong num);
+ /* bool set(long num); */
+ bool set(ulonglong num);
+ bool set(double num,uint decimals=2);
+ inline void free()
+ {
+ if (alloced)
+ {
+ alloced=0;
+ Alloced_length=0;
+ my_free(Ptr,MYF(0));
+ Ptr=0;
+ }
+ }
+
+ inline bool alloc(uint32 arg_length)
+ {
+ if (arg_length < Alloced_length)
+ return 0;
+ return real_alloc(arg_length);
+ }
+ bool real_alloc(uint32 arg_length); // Empties old string
+ bool realloc(uint32 arg_length);
+ inline void shrink(uint32 arg_length) // Shrink buffer
+ {
+ if (arg_length < Alloced_length)
+ {
+ char *new_ptr;
+ if (!(new_ptr=(char*) my_realloc(Ptr,arg_length,MYF(0))))
+ {
+ (void) my_free(Ptr,MYF(0));
+ real_alloc(arg_length);
+ }
+ else
+ {
+ Ptr=new_ptr;
+ Alloced_length=arg_length;
+ }
+ }
+ }
+ bool is_alloced() { return alloced; }
+ inline String& operator = (const String &s)
+ {
+ if (&s != this)
+ {
+ free();
+ Ptr=s.Ptr ; str_length=s.str_length ; Alloced_length=s.Alloced_length;
+ alloced=0;
+ }
+ return *this;
+ }
+
+ bool copy(); // Alloc string if not alloced
+ bool copy(const String &s); // Allocate new string
+ bool copy(const char *s,uint32 arg_length); // Allocate new string
+ bool append(const String &s);
+ bool append(const char *s,uint32 arg_length=0);
+ bool append(FILE* file, uint32 arg_length, myf my_flags);
+ int strstr(const String &search,uint32 offset=0); // Returns offset to substring or -1
+ 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)
+ {
+ if (str_length < Alloced_length)
+ {
+ Ptr[str_length++]=chr;
+ }
+ else
+ {
+ if (realloc(str_length+1))
+ return 1;
+ Ptr[str_length++]=chr;
+ }
+ return 0;
+ }
+ bool fill(uint32 max_length,char fill);
+ void strip_sp();
+ inline void caseup() { ::caseup(Ptr,str_length); }
+ inline void casedn() { ::casedn(Ptr,str_length); }
+ friend int sortcmp(const String *a,const String *b);
+ friend int stringcmp(const String *a,const String *b);
+ friend String *copy_if_not_alloced(String *a,String *b,uint32 arg_length);
+ friend int wild_case_compare(String &match,String &wild,char escape);
+ friend int wild_compare(String &match,String &wild,char escape);
+ uint32 numchars();
+ int charpos(int i,uint32 offset=0);
+};
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
new file mode 100644
index 00000000000..ed63b12ceb1
--- /dev/null
+++ b/sql/sql_table.cc
@@ -0,0 +1,1559 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+
+/* drop and alter of tables */
+
+#include "mysql_priv.h"
+#include <hash.h>
+#include <myisam.h>
+
+#ifdef __WIN__
+#include <io.h>
+#endif
+
+extern HASH open_cache;
+
+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);
+static int copy_data_between_tables(TABLE *from,TABLE *to,
+ List<create_field> &create,
+ enum enum_duplicates handle_duplicates,
+ ulong *copied,ulong *deleted);
+
+/*****************************************************************************
+** Remove all possbile tables and give a compact errormessage for all
+** wrong tables.
+** This will wait for all users to free the table before dropping it
+*****************************************************************************/
+
+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;
+ DBUG_ENTER("mysql_rm_table");
+
+ /* mark for close and remove all cached entries */
+
+ pthread_mutex_lock(&thd->mysys_var->mutex);
+ thd->mysys_var->current_mutex= &LOCK_open;
+ thd->mysys_var->current_cond= &COND_refresh;
+ VOID(pthread_mutex_lock(&LOCK_open));
+ pthread_mutex_unlock(&thd->mysys_var->mutex);
+
+ for (TABLE_LIST *table=tables ; table ; table=table->next)
+ {
+ char *db=table->db ? table->db : thd->db;
+ if (!close_temporary_table(thd, db, table->real_name))
+ continue; // removed temporary table
+
+ abort_locked_tables(thd,db,table->real_name);
+ while (remove_table_from_cache(thd,db,table->real_name) && !thd->killed)
+ {
+ dropping_tables++;
+ (void) pthread_cond_wait(&COND_refresh,&LOCK_open);
+ dropping_tables--;
+ }
+ drop_locked_tables(thd,db,table->real_name);
+ if (thd->killed)
+ {
+ VOID(pthread_cond_broadcast(&COND_refresh)); // Signal to refresh
+ VOID(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);
+ DBUG_RETURN(-1);
+ }
+ /* remove form file and isam files */
+ (void) sprintf(path,"%s/%s/%s%s",mysql_data_home,db,table->real_name,
+ reg_ext);
+ (void) unpack_filename(path,path);
+ error=0;
+
+ table_type=get_table_type(path);
+
+ if (my_delete(path,MYF(0))) /* Delete the table definition file */
+ {
+ if (errno != ENOENT || !if_exists)
+ {
+ error=1;
+ if (errno != ENOENT)
+ {
+ my_error(ER_CANT_DELETE_FILE,MYF(0),path,errno);
+ }
+ }
+ }
+ else
+ {
+ some_tables_deleted=1;
+ *fn_ext(path)=0; // Remove extension;
+ error=ha_delete_table(table_type, path);
+ if (error == ENOENT && if_exists)
+ error = 0;
+ }
+ if (error)
+ {
+ if (wrong_tables.length())
+ wrong_tables.append(',');
+ wrong_tables.append(String(table->real_name));
+ }
+ }
+ if (some_tables_deleted)
+ {
+ mysql_update_log.write(thd->query,thd->query_length);
+ Query_log_event qinfo(thd, thd->query);
+ mysql_bin_log.write(&qinfo);
+ }
+
+ 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 (wrong_tables.length())
+ {
+ my_error(ER_BAD_TABLE_ERROR,MYF(0),wrong_tables.c_ptr());
+ DBUG_RETURN(-1);
+ }
+ send_ok(&thd->net);
+ DBUG_RETURN(0);
+}
+
+
+int quick_rm_table(enum db_type base,const char *db,
+ const char *table_name)
+{
+ char path[FN_REFLEN];
+ int error=0;
+ (void) sprintf(path,"%s/%s/%s%s",mysql_data_home,db,table_name,reg_ext);
+ unpack_filename(path,path);
+ if (my_delete(path,MYF(0)))
+ error=1; /* purecov: inspected */
+ sprintf(path,"%s/%s/%s",mysql_data_home,db,table_name);
+ return ha_delete_table(base,path) || error;
+}
+
+/*****************************************************************************
+ * Create at table.
+ * If one creates a temporary table, this is automaticly opened
+ ****************************************************************************/
+
+int mysql_create_table(THD *thd,const char *db, const char *table_name,
+ HA_CREATE_INFO *create_info,
+ List<create_field> &fields,
+ List<Key> &keys,bool tmp_table,bool no_log)
+{
+ char path[FN_REFLEN];
+ const char *key_name;
+ create_field *sql_field,*dup_field;
+ int error= -1;
+ uint db_options,field,null_fields,blob_columns;
+ ulong pos;
+ KEY *key_info,*key_info_buffer;
+ KEY_PART_INFO *key_part_info;
+ int auto_increment=0;
+ handler *file;
+ DBUG_ENTER("mysql_create_table");
+
+ /*
+ ** Check for dupplicate fields and check type of table to create
+ */
+
+ if (!fields.elements)
+ {
+ my_error(ER_TABLE_MUST_HAVE_COLUMNS,MYF(0));
+ DBUG_RETURN(-1);
+ }
+ List_iterator<create_field> it(fields),it2(fields);
+ null_fields=blob_columns=0;
+ db_options=create_info->table_options;
+ if (create_info->row_type == ROW_TYPE_DYNAMIC)
+ db_options|=HA_OPTION_PACK_RECORD;
+ file=get_new_handler((TABLE*) 0, create_info->db_type);
+
+ /* Don't pack keys in old tables if the user has requested this */
+
+ while ((sql_field=it++))
+ {
+ if ((sql_field->flags & BLOB_FLAG) ||
+ sql_field->sql_type == FIELD_TYPE_VAR_STRING &&
+ create_info->row_type != ROW_TYPE_FIXED)
+ {
+ db_options|=HA_OPTION_PACK_RECORD;
+ }
+ if (!(sql_field->flags & NOT_NULL_FLAG))
+ null_fields++;
+ while ((dup_field=it2++) != sql_field)
+ {
+ if (my_strcasecmp(sql_field->field_name, dup_field->field_name) == 0)
+ {
+ my_error(ER_DUP_FIELDNAME,MYF(0),sql_field->field_name);
+ DBUG_RETURN(-1);
+ }
+ }
+ it2.rewind();
+ }
+ /* If fixed row records, we need on bit to check for deleted rows */
+ if (!(db_options & HA_OPTION_PACK_RECORD))
+ null_fields++;
+ pos=(null_fields+7)/8;
+
+ it.rewind();
+ while ((sql_field=it++))
+ {
+ switch (sql_field->sql_type) {
+ case FIELD_TYPE_BLOB:
+ case FIELD_TYPE_MEDIUM_BLOB:
+ case FIELD_TYPE_TINY_BLOB:
+ case FIELD_TYPE_LONG_BLOB:
+ sql_field->pack_flag=FIELDFLAG_BLOB |
+ pack_length_to_packflag(sql_field->pack_length -
+ portable_sizeof_char_ptr);
+ if (sql_field->flags & BINARY_FLAG)
+ sql_field->pack_flag|=FIELDFLAG_BINARY;
+ sql_field->length=8; // Unireg field length
+ sql_field->unireg_check=Field::BLOB_FIELD;
+ blob_columns++;
+ break;
+ case FIELD_TYPE_VAR_STRING:
+ case FIELD_TYPE_STRING:
+ sql_field->pack_flag=0;
+ if (sql_field->flags & BINARY_FLAG)
+ sql_field->pack_flag|=FIELDFLAG_BINARY;
+ break;
+ case FIELD_TYPE_ENUM:
+ sql_field->pack_flag=pack_length_to_packflag(sql_field->pack_length) |
+ FIELDFLAG_INTERVAL;
+ sql_field->unireg_check=Field::INTERVAL_FIELD;
+ break;
+ case FIELD_TYPE_SET:
+ sql_field->pack_flag=pack_length_to_packflag(sql_field->pack_length) |
+ FIELDFLAG_BITFIELD;
+ sql_field->unireg_check=Field::BIT_FIELD;
+ break;
+ case FIELD_TYPE_DATE: // Rest of string types
+ case FIELD_TYPE_NEWDATE:
+ case FIELD_TYPE_TIME:
+ case FIELD_TYPE_DATETIME:
+ case FIELD_TYPE_NULL:
+ sql_field->pack_flag=f_settype((uint) sql_field->sql_type);
+ break;
+ case FIELD_TYPE_TIMESTAMP:
+ sql_field->unireg_check=Field::TIMESTAMP_FIELD;
+ /* fall through */
+ default:
+ sql_field->pack_flag=(FIELDFLAG_NUMBER |
+ (sql_field->flags & UNSIGNED_FLAG ? 0 :
+ FIELDFLAG_DECIMAL) |
+ (sql_field->flags & ZEROFILL_FLAG ?
+ FIELDFLAG_ZEROFILL : 0) |
+ f_settype((uint) sql_field->sql_type) |
+ (sql_field->decimals << FIELDFLAG_DEC_SHIFT));
+ break;
+ }
+ if (!(sql_field->flags & NOT_NULL_FLAG))
+ sql_field->pack_flag|=FIELDFLAG_MAYBE_NULL;
+ sql_field->offset= pos;
+ if (MTYP_TYPENR(sql_field->unireg_check) == Field::NEXT_NUMBER)
+ auto_increment++;
+ pos+=sql_field->pack_length;
+ }
+ if (auto_increment > 1)
+ {
+ my_error(ER_WRONG_AUTO_KEY,MYF(0));
+ DBUG_RETURN(-1);
+ }
+ if (auto_increment &&
+ (file->option_flag() & HA_WRONG_ASCII_ORDER))
+ {
+ my_error(ER_TABLE_CANT_HANDLE_AUTO_INCREMENT,MYF(0));
+ DBUG_RETURN(-1);
+ }
+
+ if (blob_columns && (file->option_flag() & HA_NO_BLOBS))
+ {
+ my_error(ER_TABLE_CANT_HANDLE_BLOB,MYF(0));
+ DBUG_RETURN(-1);
+ }
+
+ /* Create keys */
+ List_iterator<Key> key_iterator(keys);
+ uint key_parts=0,key_count=keys.elements;
+ bool primary_key=0,unique_key=0;
+ Key *key;
+ uint tmp;
+ tmp=max(file->max_keys(), MAX_KEY);
+
+ if (key_count > tmp)
+ {
+ my_error(ER_TOO_MANY_KEYS,MYF(0),tmp);
+ DBUG_RETURN(-1);
+ }
+ while ((key=key_iterator++))
+ {
+ tmp=max(file->max_key_parts(),MAX_REF_PARTS);
+ if (key->columns.elements > tmp)
+ {
+ my_error(ER_TOO_MANY_KEY_PARTS,MYF(0),tmp);
+ DBUG_RETURN(-1);
+ }
+ if (key->name() && strlen(key->name()) > NAME_LEN)
+ {
+ my_error(ER_TOO_LONG_IDENT, MYF(0), key->name());
+ DBUG_RETURN(-1);
+ }
+ key_parts+=key->columns.elements;
+ }
+ key_info_buffer=key_info=(KEY*) sql_calloc(sizeof(KEY)*key_count);
+ key_part_info=(KEY_PART_INFO*) sql_calloc(sizeof(KEY_PART_INFO)*key_parts);
+ if (!key_info_buffer || ! key_part_info)
+ DBUG_RETURN(-1); // Out of memory
+
+ key_iterator.rewind();
+ for (; (key=key_iterator++) ; key_info++)
+ {
+ uint key_length=0;
+ key_part_spec *column;
+ if (key->type == Key::PRIMARY)
+ {
+ if (primary_key)
+ {
+ my_error(ER_MULTIPLE_PRI_KEY,MYF(0));
+ DBUG_RETURN(-1);
+ }
+ primary_key=1;
+ }
+ else if (key->type == Key::UNIQUE)
+ unique_key=1;
+ key_info->flags= (key->type == Key::MULTIPLE) ? 0 :
+ (key->type == Key::FULLTEXT) ? HA_FULLTEXT : HA_NOSAME;
+ key_info->key_parts=(uint8) key->columns.elements;
+ key_info->key_part=key_part_info;
+
+ List_iterator<key_part_spec> cols(key->columns);
+ for (uint column_nr=0 ; (column=cols++) ; column_nr++)
+ {
+ it.rewind();
+ field=0;
+ while ((sql_field=it++) &&
+ my_strcasecmp(column->field_name,sql_field->field_name))
+ field++;
+ if (!sql_field)
+ {
+ my_printf_error(ER_KEY_COLUMN_DOES_NOT_EXITS,
+ ER(ER_KEY_COLUMN_DOES_NOT_EXITS),MYF(0),
+ column->field_name);
+ DBUG_RETURN(-1);
+ }
+ if (f_is_blob(sql_field->pack_flag))
+ {
+ if (!(file->option_flag() & HA_BLOB_KEY))
+ {
+ my_printf_error(ER_BLOB_USED_AS_KEY,ER(ER_BLOB_USED_AS_KEY),MYF(0),
+ column->field_name);
+ DBUG_RETURN(-1);
+ }
+ if (!column->length)
+ {
+ if (key->type == Key::FULLTEXT)
+ column->length=1; /* ft-code ignores it anyway :-) */
+ else
+ {
+ my_printf_error(ER_BLOB_KEY_WITHOUT_LENGTH,
+ ER(ER_BLOB_KEY_WITHOUT_LENGTH),MYF(0),
+ column->field_name);
+ DBUG_RETURN(-1);
+ }
+ }
+ }
+ if (!(sql_field->flags & NOT_NULL_FLAG))
+ {
+ if (key->type == Key::PRIMARY)
+ {
+ my_error(ER_PRIMARY_CANT_HAVE_NULL, MYF(0));
+ DBUG_RETURN(-1);
+ }
+ if (!(file->option_flag() & HA_NULL_KEY))
+ {
+ my_printf_error(ER_NULL_COLUMN_IN_INDEX,ER(ER_NULL_COLUMN_IN_INDEX),
+ MYF(0),column->field_name);
+ DBUG_RETURN(-1);
+ }
+ }
+ if (MTYP_TYPENR(sql_field->unireg_check) == Field::NEXT_NUMBER)
+ {
+ if (column_nr == 0 || (file->option_flag() & HA_AUTO_PART_KEY))
+ auto_increment--; // Field is used
+ }
+ key_part_info->fieldnr= field;
+ key_part_info->offset= (uint16) sql_field->offset;
+ key_part_info->key_type=sql_field->pack_flag;
+ uint length=sql_field->pack_length;
+ if (column->length)
+ {
+ if (f_is_blob(sql_field->pack_flag))
+ {
+ if ((length=column->length) > file->max_key_length())
+ {
+ my_error(ER_WRONG_SUB_KEY,MYF(0));
+ DBUG_RETURN(-1);
+ }
+ }
+ else if (column->length > length ||
+ (f_is_packed(sql_field->pack_flag) && column->length != length))
+ {
+ my_error(ER_WRONG_SUB_KEY,MYF(0));
+ DBUG_RETURN(-1);
+ }
+ length=column->length;
+ }
+ else if (length == 0)
+ {
+ my_printf_error(ER_WRONG_KEY_COLUMN, ER(ER_WRONG_KEY_COLUMN), MYF(0),
+ column->field_name);
+ DBUG_RETURN(-1);
+ }
+ key_part_info->length=(uint8) length;
+ /* Use packed keys for long strings on the first column */
+ if (!(db_options & HA_OPTION_NO_PACK_KEYS) &&
+ (length >= KEY_DEFAULT_PACK_LENGTH &&
+ (sql_field->sql_type == FIELD_TYPE_STRING ||
+ sql_field->sql_type == FIELD_TYPE_VAR_STRING ||
+ sql_field->pack_flag & FIELDFLAG_BLOB)))
+ {
+ if (column_nr == 0 && (sql_field->pack_flag & FIELDFLAG_BLOB))
+ key_info->flags|= HA_BINARY_PACK_KEY;
+ else
+ key_info->flags|= HA_PACK_KEY;
+ }
+ key_length+=length;
+ key_part_info++;
+
+ /* Create the key name based on the first column (if not given) */
+ if (column_nr == 0)
+ {
+ if (key->type == Key::PRIMARY)
+ key_name="PRIMARY";
+ else if (!(key_name = key->name()))
+ key_name=make_unique_key_name(sql_field->field_name,
+ key_info_buffer,key_info);
+ if (check_if_keyname_exists(key_name,key_info_buffer,key_info))
+ {
+ my_error(ER_DUP_KEYNAME,MYF(0),key_name);
+ DBUG_RETURN(-1);
+ }
+ key_info->name=(char*) key_name;
+ }
+ }
+ key_info->key_length=(uint16) key_length;
+ if (key_length > file->max_key_length())
+ {
+ my_error(ER_TOO_LONG_KEY,MYF(0),file->max_key_length());
+ DBUG_RETURN(-1);
+ }
+ }
+ if (auto_increment > 0)
+ {
+ my_error(ER_WRONG_AUTO_KEY,MYF(0));
+ DBUG_RETURN(-1);
+ }
+ if (!primary_key && !unique_key &&
+ (file->option_flag() & HA_REQUIRE_PRIMARY_KEY))
+ {
+ my_error(ER_REQUIRES_PRIMARY_KEY,MYF(0));
+ DBUG_RETURN(-1);
+ }
+
+ /* Check if table exists */
+ if (create_info->options & HA_LEX_CREATE_TMP_TABLE)
+ {
+ sprintf(path,"%s%s%lx_%lx_%x%s",mysql_tmpdir,tmp_file_prefix,
+ current_pid, thd->thread_id, thd->tmp_table++,reg_ext);
+ create_info->table_options|=HA_CREATE_DELAY_KEY_WRITE;
+ }
+ else
+ (void) sprintf(path,"%s/%s/%s%s",mysql_data_home,db,table_name,reg_ext);
+ unpack_filename(path,path);
+ /* Check if table already exists */
+ if ((create_info->options & HA_LEX_CREATE_TMP_TABLE)
+ && find_temporary_table(thd,db,table_name))
+ {
+ my_error(ER_TABLE_EXISTS_ERROR,MYF(0),table_name);
+ DBUG_RETURN(-1);
+ }
+ VOID(pthread_mutex_lock(&LOCK_open));
+ if (!tmp_table && !(create_info->options & HA_LEX_CREATE_TMP_TABLE))
+ {
+ if (!access(path,F_OK))
+ {
+ VOID(pthread_mutex_unlock(&LOCK_open));
+ if (create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS)
+ DBUG_RETURN(0);
+ my_error(ER_TABLE_EXISTS_ERROR,MYF(0),table_name);
+ DBUG_RETURN(-1);
+ }
+ }
+
+ thd->proc_info="creating table";
+
+ create_info->table_options=db_options;
+ if (rea_create_table(path, create_info, fields, key_count,
+ key_info_buffer))
+ {
+ /* my_error(ER_CANT_CREATE_TABLE,MYF(0),table_name,my_errno); */
+ goto end;
+ }
+ if (!tmp_table && !no_log)
+ {
+ // Must be written before unlock
+ mysql_update_log.write(thd->query, thd->query_length);
+ Query_log_event qinfo(thd, thd->query);
+ mysql_bin_log.write(&qinfo);
+ }
+ if (create_info->options & HA_LEX_CREATE_TMP_TABLE)
+ {
+ /* Open table and put in temporary table list */
+ if (!(open_temporary_table(thd, path, db, table_name, 1)))
+ {
+ (void) rm_temporary_table(create_info->db_type, path);
+ goto end;
+ }
+ }
+ error=0;
+end:
+ VOID(pthread_mutex_unlock(&LOCK_open));
+ thd->proc_info="After create";
+ DBUG_RETURN(error);
+}
+
+/*
+** Give the key name after the first field with an optional '_#' after
+**/
+
+static bool
+check_if_keyname_exists(const char *name, KEY *start, KEY *end)
+{
+ for (KEY *key=start ; key != end ; key++)
+ if (!my_strcasecmp(name,key->name))
+ return 1;
+ return 0;
+}
+
+
+static char *
+make_unique_key_name(const char *field_name,KEY *start,KEY *end)
+{
+ char buff[MAX_FIELD_NAME],*buff_end;
+
+ if (!check_if_keyname_exists(field_name,start,end))
+ return (char*) field_name; // Use fieldname
+ buff_end=strmake(buff,field_name,MAX_FIELD_NAME-4);
+ for (uint i=2 ; ; i++)
+ {
+ sprintf(buff_end,"_%d",i);
+ if (!check_if_keyname_exists(buff,start,end))
+ return sql_strdup(buff);
+ }
+}
+
+/****************************************************************************
+** Create table from a list of fields and items
+****************************************************************************/
+
+TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info,
+ const char *db, const char *name,
+ List<create_field> *extra_fields,
+ List<Key> *keys,
+ List<Item> *items,
+ MYSQL_LOCK **lock)
+{
+ TABLE tmp_table; // Used during 'create_field()'
+ TABLE *table;
+ tmp_table.table_name=0;
+ DBUG_ENTER("create_table_from_items");
+
+ /* Add selected items to field list */
+ List_iterator<Item> it(*items);
+ Item *item;
+ Field *tmp_field;
+ tmp_table.db_create_options=0;
+ tmp_table.null_row=tmp_table.maybe_null=0;
+ tmp_table.blob_ptr_size=portable_sizeof_char_ptr;
+ tmp_table.db_low_byte_first= test(create_info->db_type == DB_TYPE_MYISAM ||
+ create_info->db_type == DB_TYPE_HEAP);
+
+ while ((item=it++))
+ {
+ create_field *cr_field;
+ if (strlen(item->name) > NAME_LEN ||
+ check_column_name(item->name))
+ {
+ my_error(ER_WRONG_COLUMN_NAME,MYF(0),item->name);
+ DBUG_RETURN(0);
+ }
+
+ Field *field=create_tmp_field(&tmp_table,item,item->type(),
+ (Item_result_field***) 0, &tmp_field,0,0);
+ if (!field || !(cr_field=new create_field(field,1)))
+ DBUG_RETURN(0);
+ extra_fields->push_back(cr_field);
+ }
+ /* create and lock table */
+ /* QQ: This should be done atomic ! */
+ if (mysql_create_table(thd,db,name,create_info,*extra_fields,
+ *keys,0,1)) // no logging
+ DBUG_RETURN(0);
+ if (!(table=open_table(thd,db,name,name,(bool*) 0)))
+ {
+ quick_rm_table(create_info->db_type,db,name);
+ DBUG_RETURN(0);
+ }
+ table->reginfo.lock_type=TL_WRITE;
+ if (!((*lock)=mysql_lock_tables(thd,&table,1)))
+ {
+ hash_delete(&open_cache,(byte*) table);
+ quick_rm_table(create_info->db_type,db,name);
+ DBUG_RETURN(0);
+ }
+ table->file->extra(HA_EXTRA_WRITE_CACHE);
+ DBUG_RETURN(table);
+}
+
+
+/****************************************************************************
+** Alter a table definition
+****************************************************************************/
+
+static bool
+mysql_rename_table(enum db_type base,
+ const char *old_db,
+ const char * old_name,
+ const char *new_db,
+ const char * new_name)
+{
+ char from[FN_REFLEN],to[FN_REFLEN];
+ handler *file=get_new_handler((TABLE*) 0, base);
+ bool error=0;
+ DBUG_ENTER("mysql_rename_table");
+ (void) sprintf(from,"%s/%s/%s",mysql_data_home,old_db,old_name);
+ (void) sprintf(to,"%s/%s/%s",mysql_data_home,new_db,new_name);
+ fn_format(from,from,"","",4);
+ fn_format(to,to, "","",4);
+ if (file->rename_table((const char*) from,(const char *) to) ||
+ rename_file_ext(from,to,reg_ext))
+ error=1;
+ delete file;
+ DBUG_RETURN(error);
+}
+
+/*
+ close table in this thread and force close + reopen in other threads
+ This assumes that the calling thread has lock on LOCK_open
+ Win32 clients must also have a WRITE LOCK on the table !
+*/
+
+bool close_cached_table(THD *thd,TABLE *table)
+{
+ bool result=0;
+ DBUG_ENTER("close_cached_table");
+ if (table)
+ {
+ VOID(table->file->extra(HA_EXTRA_FORCE_REOPEN)); // Close all data files
+ /* Mark all tables that are in use as 'old' */
+ mysql_lock_abort(thd,table); // end threads waiting on lock
+
+#ifdef REMOVE_LOCKS
+ /* Wait until all there are no other threads that has this table open */
+ while (remove_table_from_cache(thd,table->table_cache_key,
+ table->table_name))
+ {
+ dropping_tables++;
+ (void) pthread_cond_wait(&COND_refresh,&LOCK_open);
+ dropping_tables--;
+ }
+#else
+ (void) remove_table_from_cache(thd,table->table_cache_key,
+ table->table_name);
+#endif
+ /* When lock on LOCK_open is freed other threads can continue */
+ pthread_cond_broadcast(&COND_refresh);
+
+ /* Close lock if this is not got with LOCK TABLES */
+ if (thd->lock)
+ {
+ mysql_unlock_tables(thd, thd->lock); thd->lock=0; // Start locked threads
+ }
+ /* Close all copies of 'table'. This also frees all LOCK TABLES lock */
+ thd->open_tables=unlink_open_table(thd,thd->open_tables,table);
+ }
+ DBUG_RETURN(result);
+}
+
+int mysql_repair_table(THD* thd, TABLE_LIST* tables, HA_CHECK_OPT* check_opt)
+{
+ TABLE_LIST *table;
+ List<Item> field_list;
+ Item* item;
+ String* packet = &thd->packet;
+
+ DBUG_ENTER("mysql_repair_table");
+
+ field_list.push_back(item = new Item_empty_string("Table", NAME_LEN*2));
+ item->maybe_null = 1;
+ field_list.push_back(item = new Item_empty_string("Op", 10));
+ item->maybe_null = 1;
+ field_list.push_back(item = new Item_empty_string("Msg_type", 10));
+ item->maybe_null = 1;
+ field_list.push_back(item = new Item_empty_string("Msg_text", 255));
+ item->maybe_null = 1;
+ if (send_fields(thd, field_list, 1))
+ DBUG_RETURN(-1);
+
+
+ for (table = tables; table; table = table->next)
+ {
+ char table_name[NAME_LEN*2+2];
+ char* db = (table->db) ? table->db : thd->db;
+ strxmov(table_name,db ? db : "",".",table->name,NullS);
+
+ table->table = open_ltable(thd, table, TL_WRITE);
+ packet->length(0);
+
+ if (!table->table)
+ {
+ const char *err_msg;
+ net_store_data(packet, table_name);
+ net_store_data(packet, "repair");
+ net_store_data(packet, "error");
+ if (!(err_msg=thd->net.last_error))
+ err_msg=ER(ER_CHECK_NO_SUCH_TABLE);
+ net_store_data(packet, err_msg);
+ thd->net.last_error[0]=0;
+ if (my_net_write(&thd->net, (char*) thd->packet.ptr(),
+ packet->length()))
+ goto err;
+ continue;
+ }
+
+ int repair_code = table->table->file->repair(thd, check_opt);
+ packet->length(0);
+ net_store_data(packet, table_name);
+ net_store_data(packet, "repair");
+
+ switch(repair_code) {
+ case HA_REPAIR_NOT_IMPLEMENTED:
+ net_store_data(packet, "error");
+ net_store_data(packet, ER(ER_CHECK_NOT_IMPLEMENTED));
+ break;
+
+ case HA_REPAIR_OK:
+ net_store_data(packet, "status");
+ net_store_data(packet, "OK");
+ break;
+
+ case HA_REPAIR_FAILED:
+ net_store_data(packet, "status");
+ net_store_data(packet, "Not repaired");
+ break;
+
+ default:
+ net_store_data(packet, "Unknown - internal error during repair");
+ break;
+ }
+ close_thread_tables(thd);
+ if (my_net_write(&thd->net, (char*) packet->ptr(),
+ packet->length()))
+ goto err;
+ }
+
+ close_thread_tables(thd);
+ send_eof(&thd->net);
+ DBUG_RETURN(0);
+ err:
+ close_thread_tables(thd);
+ DBUG_RETURN(-1);
+}
+
+int mysql_optimize_table(THD* thd, TABLE_LIST* tables)
+{
+ net_printf(&thd->net, ER_PARSE_ERROR, "Sorry; This doesn't work yet", "",
+ 0);
+ return 1;
+}
+
+int mysql_analyze_table(THD* thd, TABLE_LIST* tables)
+{
+ TABLE_LIST *table;
+ List<Item> field_list;
+ Item* item;
+ String* packet = &thd->packet;
+ DBUG_ENTER("mysql_analyze_table");
+
+ field_list.push_back(item = new Item_empty_string("Table", NAME_LEN*2));
+ item->maybe_null = 1;
+ field_list.push_back(item = new Item_empty_string("Op", 10));
+ item->maybe_null = 1;
+ field_list.push_back(item = new Item_empty_string("Msg_type", 10));
+ item->maybe_null = 1;
+ field_list.push_back(item = new Item_empty_string("Msg_text", 255));
+ item->maybe_null = 1;
+ if (send_fields(thd, field_list, 1))
+ DBUG_RETURN(-1);
+
+
+ for (table = tables; table; table = table->next)
+ {
+ char table_name[NAME_LEN*2+2];
+ char* db = (table->db) ? table->db : thd->db;
+ strxmov(table_name,db ? db : "",".",table->name,NullS);
+
+ table->table = open_ltable(thd, table, TL_READ_NO_INSERT);
+ packet->length(0);
+
+ if (!table->table)
+ {
+ const char *err_msg;
+ net_store_data(packet, table_name);
+ net_store_data(packet, "analyze");
+ net_store_data(packet, "error");
+ if (!(err_msg=thd->net.last_error))
+ err_msg=ER(ER_CHECK_NO_SUCH_TABLE);
+ net_store_data(packet, err_msg);
+ thd->net.last_error[0]=0;
+ if (my_net_write(&thd->net, (char*) thd->packet.ptr(),
+ packet->length()))
+ goto err;
+ continue;
+ }
+ if (table->table->db_stat & HA_READ_ONLY)
+ {
+ net_store_data(packet, table_name);
+ net_store_data(packet, "analyze");
+ net_store_data(packet, "error");
+ net_store_data(packet, ER(ER_OPEN_AS_READONLY));
+ if (my_net_write(&thd->net, (char*) thd->packet.ptr(),
+ packet->length()))
+ goto err;
+ continue;
+ }
+
+ int analyze_code = table->table->file->analyze(thd);
+ packet->length(0);
+ net_store_data(packet, table_name);
+ net_store_data(packet, "analyze");
+
+ switch(analyze_code) {
+ case HA_ANALYZE_NOT_IMPLEMENTED:
+ net_store_data(packet, "error");
+ net_store_data(packet, ER(ER_CHECK_NOT_IMPLEMENTED));
+ break;
+
+ case HA_ANALYZE_OK:
+ net_store_data(packet, "status");
+ net_store_data(packet, "OK");
+ break;
+
+ default:
+ net_store_data(packet, "Unknown - internal error during analyze");
+ break;
+ }
+ close_thread_tables(thd);
+ if (my_net_write(&thd->net, (char*) packet->ptr(),
+ packet->length()))
+ goto err;
+ }
+
+ close_thread_tables(thd);
+ send_eof(&thd->net);
+ DBUG_RETURN(0);
+ err:
+ close_thread_tables(thd);
+ DBUG_RETURN(-1);
+}
+
+int mysql_check_table(THD* thd, TABLE_LIST* tables,HA_CHECK_OPT* check_opt)
+{
+ TABLE_LIST *table;
+ List<Item> field_list;
+ Item* item;
+ String* packet = &thd->packet;
+
+ DBUG_ENTER("mysql_check_table");
+
+ field_list.push_back(item = new Item_empty_string("Table", NAME_LEN*2));
+ item->maybe_null = 1;
+ field_list.push_back(item = new Item_empty_string("Op", 10));
+ item->maybe_null = 1;
+ field_list.push_back(item = new Item_empty_string("Msg_type", 10));
+ item->maybe_null = 1;
+ field_list.push_back(item = new Item_empty_string("Msg_text", 255));
+ item->maybe_null = 1;
+ if (send_fields(thd, field_list, 1))
+ DBUG_RETURN(-1);
+
+
+ for (table = tables; table; table = table->next)
+ {
+ char table_name[NAME_LEN*2+2];
+ char* db = (table->db) ? table->db : thd->db;
+ strxmov(table_name,db ? db : "",".",table->name,NullS);
+
+ table->table = open_ltable(thd, table, TL_READ_NO_INSERT);
+ packet->length(0);
+
+ if (!table->table)
+ {
+ const char *err_msg;
+ net_store_data(packet, table_name);
+ net_store_data(packet, "check");
+ net_store_data(packet, "error");
+ if (!(err_msg=thd->net.last_error))
+ err_msg=ER(ER_CHECK_NO_SUCH_TABLE);
+ net_store_data(packet, err_msg);
+ thd->net.last_error[0]=0;
+ if (my_net_write(&thd->net, (char*) thd->packet.ptr(),
+ packet->length()))
+ goto err;
+ continue;
+ }
+
+ int check_code = table->table->file->check(thd, check_opt);
+ packet->length(0);
+ net_store_data(packet, table_name);
+ net_store_data(packet, "check");
+
+ switch(check_code) {
+ case HA_CHECK_NOT_IMPLEMENTED:
+ net_store_data(packet, "error");
+ net_store_data(packet, ER(ER_CHECK_NOT_IMPLEMENTED));
+ break;
+
+ case HA_CHECK_OK:
+ net_store_data(packet, "status");
+ net_store_data(packet, "OK");
+ break;
+
+ case HA_CHECK_CORRUPT:
+ net_store_data(packet, "status");
+ net_store_data(packet, "Corrupt");
+ break;
+
+ default:
+ net_store_data(packet, "Unknown - internal error during check");
+ break;
+ }
+ close_thread_tables(thd);
+ if (my_net_write(&thd->net, (char*) packet->ptr(),
+ packet->length()))
+ goto err;
+ }
+
+ close_thread_tables(thd);
+ send_eof(&thd->net);
+ DBUG_RETURN(0);
+ err:
+ close_thread_tables(thd);
+ DBUG_RETURN(-1);
+}
+
+
+
+int mysql_alter_table(THD *thd,char *new_db, char *new_name,
+ HA_CREATE_INFO *create_info,
+ TABLE_LIST *table_list,
+ List<create_field> &fields,
+ List<Key> &keys,List<Alter_drop> &drop_list,
+ List<Alter_column> &alter_list,
+ bool drop_primary,
+ enum enum_duplicates handle_duplicates)
+{
+ TABLE *table,*new_table;
+ int error;
+ char tmp_name[80],old_name[32],new_name_buff[FN_REFLEN],
+ *table_name,*db;
+ bool use_timestamp=0;
+ ulong copied,deleted;
+ uint save_time_stamp,db_create_options;
+ enum db_type old_db_type,new_db_type;
+ DBUG_ENTER("mysql_alter_table");
+
+ thd->proc_info="init";
+ table_name=table_list->real_name;
+ db=table_list->db;
+ if (!new_db)
+ new_db=db;
+
+ if (!(table=open_ltable(thd,table_list,TL_WRITE_ALLOW_READ)))
+ DBUG_RETURN(-1);
+
+ /* Check that we are not trying to rename to an existing table */
+ if (new_name)
+ {
+ strmov(new_name_buff,new_name);
+ fn_same(new_name_buff,table_name,3);
+ if (!strcmp(new_name_buff,table_name)) // Check if name changed
+ new_name=table_name; // No. Make later check easier
+ else
+ {
+ if (table->tmp_table)
+ {
+ if (find_temporary_table(thd,new_db,new_name_buff))
+ {
+ my_error(ER_TABLE_EXISTS_ERROR,MYF(0),new_name);
+ DBUG_RETURN(-1);
+ }
+ }
+ else
+ {
+ if (!access(fn_format(new_name_buff,new_name_buff,new_db,reg_ext,0),
+ F_OK))
+ {
+ /* Table will be closed in do_command() */
+ my_error(ER_TABLE_EXISTS_ERROR,MYF(0),new_name);
+ DBUG_RETURN(-1);
+ }
+ }
+ }
+ }
+ else
+ new_name=table_name;
+
+ old_db_type=table->db_type;
+ if (create_info->db_type == DB_TYPE_DEFAULT)
+ create_info->db_type=old_db_type;
+ if (create_info->row_type == ROW_TYPE_DEFAULT)
+ create_info->row_type=table->row_type;
+ new_db_type=create_info->db_type;
+
+ /* Check if the user only wants to do a simple RENAME */
+
+ 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)
+ {
+ 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)
+ {
+ mysql_update_log.write(thd->query,thd->query_length);
+ Query_log_event qinfo(thd, thd->query);
+ mysql_bin_log.write(&qinfo);
+ send_ok(&thd->net);
+ }
+
+ DBUG_RETURN(error);
+ }
+
+ /* Full alter table */
+ restore_record(table,2); // Empty record for DEFAULT
+ List_iterator<Alter_drop> drop_it(drop_list);
+ List_iterator<create_field> def_it(fields);
+ List_iterator<Alter_column> alter_it(alter_list);
+ List<create_field> create_list; // Add new fields here
+ List<Key> key_list; // Add new keys here
+
+ /*
+ ** First collect all fields from table which isn't in drop_list
+ */
+
+ create_field *def;
+ Field **f_ptr,*field;
+ for (f_ptr=table->field ; (field= *f_ptr) ; f_ptr++)
+ {
+ /* Check if field should be droped */
+ Alter_drop *drop;
+ drop_it.rewind();
+ while ((drop=drop_it++))
+ {
+ if (drop->type == Alter_drop::COLUMN &&
+ !my_strcasecmp(field->field_name, drop->name))
+ break;
+ }
+ if (drop)
+ {
+ drop_it.remove();
+ continue;
+ }
+ /* Check if field is changed */
+ def_it.rewind();
+ while ((def=def_it++))
+ {
+ if (def->change && !my_strcasecmp(field->field_name, def->change))
+ break;
+ }
+ if (def)
+ { // Field is changed
+ def->field=field;
+ if (def->sql_type == FIELD_TYPE_TIMESTAMP)
+ use_timestamp=1;
+ create_list.push_back(def);
+ def_it.remove();
+ }
+ else
+ { // Use old field value
+ create_list.push_back(def=new create_field(field));
+ if (def->sql_type == FIELD_TYPE_TIMESTAMP)
+ use_timestamp=1;
+
+ alter_it.rewind(); // Change default if ALTER
+ Alter_column *alter;
+ while ((alter=alter_it++))
+ {
+ if (!my_strcasecmp(field->field_name, alter->name))
+ break;
+ }
+ if (alter)
+ {
+ def->def=alter->def; // Use new default
+ alter_it.remove();
+ }
+ }
+ }
+ def_it.rewind();
+ List_iterator<create_field> find_it(create_list);
+ while ((def=def_it++)) // Add new columns
+ {
+ if (def->change)
+ {
+ my_error(ER_BAD_FIELD_ERROR,MYF(0),def->change,table_name);
+ DBUG_RETURN(-1);
+ }
+ if (!def->after)
+ create_list.push_back(def);
+ else if (def->after == first_keyword)
+ create_list.push_front(def);
+ else
+ {
+ create_field *find;
+ find_it.rewind();
+ while ((find=find_it++)) // Add new columns
+ {
+ if (!my_strcasecmp(def->after, find->field_name))
+ break;
+ }
+ if (!find)
+ {
+ my_error(ER_BAD_FIELD_ERROR,MYF(0),def->after,table_name);
+ DBUG_RETURN(-1);
+ }
+ find_it.after(def); // Put element after this
+ }
+ }
+ if (alter_list.elements)
+ {
+ my_error(ER_BAD_FIELD_ERROR,MYF(0),alter_list.head()->name,table_name);
+ DBUG_RETURN(-1);
+ }
+ if (!create_list.elements)
+ {
+ my_error(ER_CANT_REMOVE_ALL_FIELDS,MYF(0));
+ DBUG_RETURN(-1);
+ }
+
+ /*
+ ** Collect all keys which isn't in drop list. Add only those
+ ** for which some fields exists.
+ */
+
+ List_iterator<Key> key_it(keys);
+ List_iterator<create_field> field_it(create_list);
+ List<key_part_spec> key_parts;
+
+ KEY *key_info=table->key_info;
+ for (uint i=0 ; i < table->keys ; i++,key_info++)
+ {
+ if (drop_primary && (key_info->flags & HA_NOSAME))
+ {
+ drop_primary=0;
+ continue;
+ }
+
+ char *key_name=key_info->name;
+ Alter_drop *drop;
+ drop_it.rewind();
+ while ((drop=drop_it++))
+ {
+ if (drop->type == Alter_drop::KEY &&
+ !my_strcasecmp(key_name, drop->name))
+ break;
+ }
+ if (drop)
+ {
+ drop_it.remove();
+ continue;
+ }
+
+ KEY_PART_INFO *key_part= key_info->key_part;
+ key_parts.empty();
+ for (uint j=0 ; j < key_info->key_parts ; j++,key_part++)
+ {
+ if (!key_part->field)
+ continue; // Wrong field (from UNIREG)
+ const char *key_part_name=key_part->field->field_name;
+ create_field *cfield;
+ field_it.rewind();
+ while ((cfield=field_it++))
+ {
+ if (cfield->change)
+ {
+ if (!my_strcasecmp(key_part_name, cfield->change))
+ break;
+ }
+ else if (!my_strcasecmp(key_part_name, cfield->field_name))
+ break;
+ }
+ if (!cfield)
+ continue; // Field is removed
+ uint key_part_length=key_part->length;
+ if (cfield->field) // Not new field
+ { // Check if sub key
+ if (cfield->field->type() != FIELD_TYPE_BLOB &&
+ (cfield->field->pack_length() == key_part_length ||
+ cfield->length != cfield->pack_length ||
+ cfield->pack_length <= key_part_length))
+ key_part_length=0; // Use whole field
+ }
+ key_parts.push_back(new key_part_spec(cfield->field_name,
+ key_part_length));
+ }
+ if (key_parts.elements)
+ key_list.push_back(new Key(key_info->flags & HA_NOSAME ?
+ (!my_strcasecmp(key_name, "PRIMARY") ?
+ Key::PRIMARY : Key::UNIQUE) :
+ (key_info->flags & HA_FULLTEXT ?
+ Key::FULLTEXT : Key::MULTIPLE),
+ key_name,key_parts));
+ }
+ key_it.rewind();
+ {
+ Key *key;
+ while ((key=key_it++)) // Add new keys
+ key_list.push_back(key);
+ }
+
+ if (drop_list.elements)
+ {
+ my_error(ER_CANT_DROP_FIELD_OR_KEY,MYF(0),drop_list.head()->name);
+ goto err;
+ }
+ if (alter_list.elements)
+ {
+ my_error(ER_CANT_DROP_FIELD_OR_KEY,MYF(0),alter_list.head()->name);
+ goto err;
+ }
+
+ (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))
+ db_create_options&= ~(HA_OPTION_PACK_KEYS | HA_OPTION_NO_PACK_KEYS);
+ if (create_info->table_options &
+ (HA_OPTION_CHECKSUM | HA_OPTION_NO_CHECKSUM))
+ db_create_options&= ~(HA_OPTION_CHECKSUM | HA_OPTION_NO_CHECKSUM);
+ if (create_info->table_options &
+ (HA_OPTION_DELAY_KEY_WRITE | HA_OPTION_NO_DELAY_KEY_WRITE))
+ db_create_options&= ~(HA_OPTION_DELAY_KEY_WRITE |
+ HA_OPTION_NO_DELAY_KEY_WRITE);
+ create_info->table_options|= db_create_options;
+
+ if (table->tmp_table)
+ create_info->options|=HA_LEX_CREATE_TMP_TABLE;
+
+ if ((error=mysql_create_table(thd, new_db, tmp_name,
+ create_info,
+ create_list,key_list,1,1))) // no logging
+ DBUG_RETURN(error);
+ {
+ if (table->tmp_table)
+ new_table=open_table(thd,new_db,tmp_name,tmp_name,0);
+ else
+ {
+ char path[FN_REFLEN];
+ (void) sprintf(path,"%s/%s/%s",mysql_data_home,new_db,tmp_name);
+ fn_format(path,path,"","",4+16+32);
+ new_table=open_temporary_table(thd, path, new_db, tmp_name,0);
+ }
+ if (!new_table)
+ {
+ VOID(quick_rm_table(new_db_type,new_db,tmp_name));
+ goto err;
+ }
+ }
+
+ save_time_stamp=new_table->time_stamp;
+ if (use_timestamp)
+ new_table->time_stamp=0;
+ new_table->next_number_field=new_table->found_next_number_field;
+ thd->count_cuted_fields=1; /* calc cuted fields */
+ thd->cuted_fields=0L;
+ thd->proc_info="copy to tmp table";
+ error=copy_data_between_tables(table,new_table,create_list,handle_duplicates,
+ &copied,&deleted);
+ thd->count_cuted_fields=0; /* Don`t calc cuted fields */
+ new_table->time_stamp=save_time_stamp;
+
+ if (table->tmp_table)
+ {
+ /* We changed a temporary table */
+ if (error)
+ {
+ close_temporary_table(thd,new_db,tmp_name);
+ my_free((gptr) new_table,MYF(0));
+ goto err;
+ }
+ /* Remove link to old table and rename the new one */
+ close_temporary_table(thd,table->table_cache_key,table_name);
+ if (rename_temporary_table(new_table, new_db, new_name))
+ { // Fatal error
+ close_temporary_table(thd,new_db,tmp_name);
+ my_free((gptr) new_table,MYF(0));
+ goto err;
+ }
+ mysql_update_log.write(thd->query,thd->query_length);
+ Query_log_event qinfo(thd, thd->query);
+ mysql_bin_log.write(&qinfo);
+
+ goto end_temporary;
+ DBUG_RETURN(0);
+ }
+
+ intern_close_table(new_table); /* close temporary table */
+ my_free((gptr) new_table,MYF(0));
+ VOID(pthread_mutex_lock(&LOCK_open));
+ if (error)
+ {
+ VOID(quick_rm_table(new_db_type,new_db,tmp_name));
+ VOID(pthread_mutex_unlock(&LOCK_open));
+ goto err;
+ }
+ /*
+ ** Data is copied. Now we rename the old table to a temp name,
+ ** rename the new one to the old name, remove all entries from the old table
+ ** from the cash, free all locks, close the old table and remove it.
+ */
+
+ thd->proc_info="rename result table";
+ sprintf(old_name,"%s2-%lx-%lx", tmp_file_prefix, current_pid,
+ thd->thread_id);
+ if (new_name != table_name)
+ {
+ if (!access(new_name_buff,F_OK))
+ {
+ error=1;
+ my_error(ER_TABLE_EXISTS_ERROR,MYF(0),new_name_buff);
+ VOID(quick_rm_table(new_db_type,new_db,tmp_name));
+ VOID(pthread_mutex_unlock(&LOCK_open));
+ goto err;
+ }
+ }
+
+#ifdef __WIN__
+ // Win32 can't rename an open table, so we must close the org table!
+ table_name=sql_strdup(table_name); // must be saved
+ if (close_cached_table(thd,table))
+ { // Aborted
+ VOID(quick_rm_table(new_db_type,new_db,tmp_name));
+ VOID(pthread_mutex_unlock(&LOCK_open));
+ goto err;
+ }
+ table=0; // Marker for win32 version
+#endif
+
+ error=0;
+ if (mysql_rename_table(old_db_type,db,table_name,db,old_name))
+ {
+ error=1;
+ VOID(quick_rm_table(new_db_type,new_db,tmp_name));
+ }
+ else if (mysql_rename_table(new_db_type,new_db,tmp_name,new_db,
+ new_name))
+ { // Try to get everything back
+ error=1;
+ VOID(quick_rm_table(new_db_type,new_db,new_name));
+ VOID(quick_rm_table(new_db_type,new_db,tmp_name));
+ VOID(mysql_rename_table(old_db_type,db,old_name,db,table_name));
+ }
+ if (error)
+ {
+ // 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
+ 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
+ if (table)
+ {
+ VOID(table->file->extra(HA_EXTRA_FORCE_REOPEN)); // Use new file
+ remove_table_from_cache(thd,db,table_name); // Mark all in-use copies old
+ mysql_lock_abort(thd,table); // end threads waiting on lock
+ }
+ VOID(quick_rm_table(old_db_type,db,old_name));
+ if (close_data_tables(thd,db,table_name) ||
+ reopen_tables(thd,1,0))
+ { // This shouldn't happen
+ close_cached_table(thd,table); // Remove lock for table
+ VOID(pthread_mutex_unlock(&LOCK_open));
+ goto err;
+ }
+ }
+ if ((error = ha_commit(thd)))
+ {
+ VOID(pthread_cond_broadcast(&COND_refresh));
+ VOID(pthread_mutex_unlock(&LOCK_open));
+ goto err;
+ }
+
+ thd->proc_info="end";
+ mysql_update_log.write(thd->query,thd->query_length);
+ {
+ Query_log_event qinfo(thd, thd->query);
+ mysql_bin_log.write(&qinfo);
+ }
+ VOID(pthread_cond_broadcast(&COND_refresh));
+ VOID(pthread_mutex_unlock(&LOCK_open));
+
+end_temporary:
+ sprintf(tmp_name,ER(ER_INSERT_INFO),copied+deleted,deleted,
+ thd->cuted_fields);
+ send_ok(&thd->net,copied+deleted,0L,tmp_name);
+ thd->some_tables_deleted=0;
+ DBUG_RETURN(0);
+
+ err:
+ DBUG_RETURN(-1);
+}
+
+
+static int
+copy_data_between_tables(TABLE *from,TABLE *to,List<create_field> &create,
+ enum enum_duplicates handle_duplicates,
+ ulong *copied,ulong *deleted)
+{
+ int error;
+ Copy_field *copy,*copy_end;
+ ulong found_count,delete_count;
+ THD *thd= current_thd;
+ DBUG_ENTER("copy_data_between_tables");
+
+ if (!(copy= new Copy_field[to->fields]))
+ DBUG_RETURN(-1); /* purecov: inspected */
+
+ to->file->external_lock(thd,F_WRLCK);
+ to->file->extra(HA_EXTRA_WRITE_CACHE);
+
+ List_iterator<create_field> it(create);
+ create_field *def;
+ copy_end=copy;
+ for (Field **ptr=to->field ; *ptr ; ptr++)
+ {
+ def=it++;
+ if (def->field)
+ (copy_end++)->set(*ptr,def->field,0);
+ }
+
+ READ_RECORD info;
+ init_read_record(&info, thd, from, (SQL_SELECT *) 0, 1,1);
+
+ found_count=delete_count=0;
+ Field *next_field=to->next_number_field;
+ while (!(error=info.read_record(&info)))
+ {
+ if (thd->killed)
+ {
+ my_error(ER_SERVER_SHUTDOWN,MYF(0));
+ error= 1;
+ break;
+ }
+ if (next_field)
+ next_field->reset();
+ for (Copy_field *copy_ptr=copy ; copy_ptr != copy_end ; copy_ptr++)
+ copy_ptr->do_copy(copy_ptr);
+ if ((error=to->file->write_row((byte*) to->record[0])))
+ {
+ if (handle_duplicates != DUP_IGNORE ||
+ (error != HA_ERR_FOUND_DUPP_KEY &&
+ error != HA_ERR_FOUND_DUPP_UNIQUE))
+ {
+ to->file->print_error(error,MYF(0));
+ break;
+ }
+ delete_count++;
+ }
+ else
+ found_count++;
+ }
+ end_read_record(&info);
+ delete [] copy;
+ uint tmp_error;
+ if ((tmp_error=to->file->extra(HA_EXTRA_NO_CACHE)))
+ {
+ to->file->print_error(tmp_error,MYF(0));
+ error=1;
+ }
+ if (ha_commit(thd) || to->file->external_lock(thd,F_UNLCK))
+ error=1;
+ *copied= found_count;
+ *deleted=delete_count;
+ DBUG_RETURN(error > 0 ? -1 : 0);
+}
diff --git a/sql/sql_test.cc b/sql/sql_test.cc
new file mode 100644
index 00000000000..411a85a5c55
--- /dev/null
+++ b/sql/sql_test.cc
@@ -0,0 +1,246 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 some debug info */
+
+
+#include "mysql_priv.h"
+#include "sql_select.h"
+#include <hash.h>
+
+/* Intern key cache variables */
+extern "C" pthread_mutex_t THR_LOCK_keycache;
+
+#ifndef DBUG_OFF
+
+void
+print_where(COND *cond,const char *info)
+{
+ if (cond)
+ {
+ char buff[256];
+ String str(buff,(uint32) sizeof(buff));
+ str.length(0);
+ cond->print(&str);
+ str.append('\0');
+ DBUG_LOCK_FILE;
+ (void) fprintf(DBUG_FILE,"\nWHERE:(%s) ",info);
+ (void) fputs(str.ptr(),DBUG_FILE);
+ (void) fputc('\n',DBUG_FILE);
+ DBUG_UNLOCK_FILE;
+ }
+}
+
+ /* This is for debugging purposes */
+
+extern HASH open_cache;
+extern TABLE *unused_tables;
+
+void print_cached_tables(void)
+{
+ uint idx,count,unused;
+ TABLE *start_link,*lnk;
+
+ VOID(pthread_mutex_lock(&LOCK_open));
+ puts("DB Table Version Thread L.thread Open");
+
+ for (idx=unused=0 ; idx < open_cache.records ; idx++)
+ {
+ TABLE *entry=(TABLE*) hash_element(&open_cache,idx);
+ printf("%-14.14s %-32s%6ld%8ld%10ld%6d\n",
+ entry->table_cache_key,entry->real_name,entry->version,
+ entry->in_use ? entry->in_use->thread_id : 0L,
+ entry->in_use ? entry->in_use->dbug_thread_id : 0L,
+ entry->db_stat ? 1 : 0);
+ if (!entry->in_use)
+ unused++;
+ }
+ count=0;
+ if ((start_link=lnk=unused_tables))
+ {
+ do
+ {
+ if (lnk != lnk->next->prev || lnk != lnk->prev->next)
+ {
+ printf("unused_links isn't linked properly\n");
+ return;
+ }
+ } while (count++ < open_cache.records && (lnk=lnk->next) != start_link);
+ if (lnk != start_link)
+ {
+ printf("Unused_links aren't connected\n");
+ }
+ }
+ if (count != unused)
+ printf("Unused_links (%d) dosen't match open_cache: %d\n", count,unused);
+ printf("\nCurrent refresh version: %ld\n",refresh_version);
+ if (hash_check(&open_cache))
+ printf("Error: File hash table is corrupted\n");
+ fflush(stdout);
+ VOID(pthread_mutex_unlock(&LOCK_open));
+ return;
+}
+
+
+void TEST_filesort(TABLE **table,SORT_FIELD *sortorder,uint s_length,
+ ha_rows special)
+{
+ char buff[256],buff2[256];
+ String str(buff,sizeof(buff)),out(buff2,sizeof(buff2));
+ const char *sep;
+ DBUG_ENTER("TEST_filesort");
+
+ out.length(0);
+ for (sep=""; s_length-- ; sortorder++, sep=" ")
+ {
+ out.append(sep);
+ if (sortorder->reverse)
+ out.append('-');
+ if (sortorder->field)
+ {
+ if (sortorder->field->table_name)
+ {
+ out.append(sortorder->field->table_name);
+ out.append('.');
+ }
+ out.append(sortorder->field->field_name ? sortorder->field->field_name:
+ "tmp_table_column");
+ }
+ else
+ {
+ str.length(0);
+ sortorder->item->print(&str);
+ out.append(str);
+ }
+ }
+ out.append('\0'); // Purify doesn't like c_ptr()
+ DBUG_LOCK_FILE;
+ VOID(fputs("\nInfo about FILESORT\n",DBUG_FILE));
+ if (special)
+ fprintf(DBUG_FILE,"Records to sort: %ld\n",special);
+ fprintf(DBUG_FILE,"Sortorder: %s\n",out.ptr());
+ DBUG_UNLOCK_FILE;
+ DBUG_VOID_RETURN;
+}
+
+
+void
+TEST_join(JOIN *join)
+{
+ uint i,ref;
+ DBUG_ENTER("TEST_join");
+
+ DBUG_LOCK_FILE;
+ VOID(fputs("\nInfo about JOIN\n",DBUG_FILE));
+ for (i=0 ; i < join->tables ; i++)
+ {
+ JOIN_TAB *tab=join->join_tab+i;
+ TABLE *form=tab->table;
+ fprintf(DBUG_FILE,"%-16.16s type: %-7s q_keys: %4d refs: %d key: %d len: %d\n",
+ form->table_name,
+ join_type_str[tab->type],
+ tab->keys,
+ tab->ref.key_parts,
+ tab->ref.key,
+ tab->ref.key_length);
+ if (tab->select)
+ {
+ if (tab->use_quick == 2)
+ fprintf(DBUG_FILE,
+ " quick select checked for each record (keys: %d)\n",
+ (int) tab->select->quick_keys);
+ else if (tab->select->quick)
+ fprintf(DBUG_FILE," quick select used on key %s, length: %d\n",
+ form->key_info[tab->select->quick->index].name,
+ tab->select->quick->max_used_key_length);
+ else
+ VOID(fputs(" select used\n",DBUG_FILE));
+ }
+ if (tab->ref.key_parts)
+ {
+ VOID(fputs(" refs: ",DBUG_FILE));
+ for (ref=0 ; ref < tab->ref.key_parts ; ref++)
+ {
+ Item *item=tab->ref.items[ref];
+ fprintf(DBUG_FILE,"%s ", item->full_name());
+ }
+ VOID(fputc('\n',DBUG_FILE));
+ }
+ }
+ DBUG_UNLOCK_FILE;
+ DBUG_VOID_RETURN;
+}
+
+#endif
+
+void mysql_print_status(THD *thd)
+{
+ printf("\nStatus information:\n\n");
+ if (thd)
+ thd->proc_info="locks";
+ thr_print_locks(); // Write some debug info
+#ifndef DBUG_OFF
+ if (thd)
+ thd->proc_info="table cache";
+ print_cached_tables();
+#endif
+ /* Print key cache status */
+ if (thd)
+ thd->proc_info="key cache";
+ pthread_mutex_lock(&THR_LOCK_keycache);
+ printf("key_cache status:\n\
+blocks used:%10lu\n\
+not flushed:%10lu\n\
+w_requests: %10lu\n\
+writes: %10lu\n\
+r_requests: %10lu\n\
+reads: %10lu\n",
+ _my_blocks_used,_my_blocks_changed,_my_cache_w_requests,
+ _my_cache_write,_my_cache_r_requests,_my_cache_read);
+ pthread_mutex_unlock(&THR_LOCK_keycache);
+
+ if (thd)
+ thd->proc_info="status";
+ pthread_mutex_lock(&LOCK_status);
+ printf("\nhandler status:\n\
+read_key: %10lu\n\
+read_next: %10lu\n\
+read_rnd %10lu\n\
+read_first: %10lu\n\
+write: %10lu\n\
+delete %10lu\n\
+update: %10lu\n",
+ ha_read_key_count, ha_read_next_count,
+ ha_read_rnd_count, ha_read_first_count,
+ ha_write_count, ha_delete_count, ha_update_count);
+ pthread_mutex_unlock(&LOCK_status);
+ printf("\nTable status:\n\
+Opened tables: %10lu\n\
+Open tables: %10lu\n\
+Open files: %10lu\n\
+Open streams: %10lu\n",
+ opened_tables,
+ (ulong) cached_tables(),
+ (ulong) my_file_opened,
+ (ulong) my_stream_opened);
+ fflush(stdout);
+ if (thd)
+ thd->proc_info="malloc";
+ TERMINATE(stdout); // Write malloc information
+ if (thd)
+ thd->proc_info=0;
+}
diff --git a/sql/sql_udf.cc b/sql/sql_udf.cc
new file mode 100644
index 00000000000..7d123141169
--- /dev/null
+++ b/sql/sql_udf.cc
@@ -0,0 +1,471 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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' */
+
+/*
+** Known bugs:
+**
+** Memory for functions are never freed!
+** Shared libraries are not closed before mysqld exists;
+** - This is because we can't be sure if some threads is using
+** a functions.
+**
+** The buggs only affects applications that creates and frees a lot of
+** dynamic functions, so this shouldn't be a real problem.
+*/
+
+#ifdef __GNUC__
+#pragma implementation // gcc: implement sql_udf.h
+#endif
+
+#include "mysql_priv.h"
+#ifdef HAVE_DLOPEN
+extern "C"
+{
+#include <dlfcn.h>
+#include <stdarg.h>
+#include <hash.h>
+}
+
+#ifndef RTLD_NOW
+#define RTLD_NOW 1 // For FreeBSD 2.2.2
+#endif
+
+#ifndef HAVE_DLERROR
+#define dlerror() ""
+#endif
+
+static bool initialized = 0;
+static MEM_ROOT mem;
+static HASH udf_hash;
+static pthread_mutex_t THR_LOCK_udf;
+
+
+static udf_func *add_udf(char *name, Item_result ret, char *dl,
+ Item_udftype typ);
+static void del_udf(udf_func *udf);
+static void *find_udf_dl(const char *dl);
+
+static void init_syms(udf_func *tmp)
+{
+ char nm[MAX_FIELD_NAME+16],*end;
+
+ tmp->func = dlsym(tmp->dlhandle, tmp->name);
+ end=strmov(nm,tmp->name);
+ (void) strmov(end,"_init");
+ tmp->func_init = dlsym(tmp->dlhandle, nm);
+ (void) strmov(end,"_deinit");
+ tmp->func_deinit = dlsym(tmp->dlhandle, nm);
+ if (tmp->type == UDFTYPE_AGGREGATE)
+ {
+ (void)strmov( end, "_reset" );
+ tmp->func_reset = dlsym( tmp->dlhandle, nm );
+ (void)strmov( end, "_add" );
+ tmp->func_add = dlsym( tmp->dlhandle, nm );
+ }
+}
+
+static byte* get_hash_key(const byte *buff,uint *length,
+ my_bool not_used __attribute__((unused)))
+{
+ udf_func *udf=(udf_func*) buff;
+ *length=(uint) udf->name_length;
+ return (byte*) udf->name;
+}
+
+/*
+** Read all predeclared functions from func@mysql and accept all that
+** can be used.
+*/
+
+void udf_init()
+{
+ udf_func *tmp;
+ TABLE_LIST tables;
+ READ_RECORD read_record_info;
+ int error;
+ DBUG_ENTER("ufd_init");
+
+ if (initialized)
+ DBUG_VOID_RETURN;
+
+ pthread_mutex_init(&THR_LOCK_udf,NULL);
+
+ init_sql_alloc(&mem, 1024);
+ THD *new_thd = new THD;
+ if (!new_thd ||
+ hash_init(&udf_hash,32,0,0,get_hash_key, NULL, HASH_CASE_INSENSITIVE))
+ {
+ sql_print_error("Can't allocate memory for udf structures");
+ hash_free(&udf_hash);
+ free_root(&mem);
+ DBUG_VOID_RETURN;
+ }
+ initialized = 1;
+ new_thd->mysys_var=my_thread_var;
+ 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));
+
+ bzero((gptr) &tables,sizeof(tables));
+ tables.name = tables.real_name = (char*) "func";
+ tables.lock_type = TL_READ;
+ tables.db=new_thd->db;
+
+ if (open_tables(new_thd, &tables))
+ {
+ DBUG_PRINT("error",("Can't open udf table"));
+ sql_print_error("Can't open mysql/func table");
+ close_thread_tables(new_thd);
+ delete new_thd;
+ DBUG_VOID_RETURN;
+ }
+
+ TABLE *table = tables.table;
+ init_read_record(&read_record_info, new_thd, table, NULL,1,0);
+ while (!(error = read_record_info.read_record(&read_record_info)))
+ {
+ DBUG_PRINT("info",("init udf record"));
+ char *name=get_field(&mem, table, 0);
+ char *dl_name= get_field(&mem, table, 2);
+ bool new_dl=0;
+ Item_udftype udftype=UDFTYPE_FUNCTION;
+ if (table->fields >= 4) // New func table
+ udftype=(Item_udftype) table->field[3]->val_int();
+
+ if (!(tmp = add_udf(name,(Item_result) table->field[1]->val_int(),
+ dl_name, udftype)))
+ {
+ sql_print_error("Can't alloc memory for udf function: name");
+ continue;
+ }
+
+ void *dl = find_udf_dl(tmp->dl);
+ if (dl == NULL)
+ {
+ if (!(dl = dlopen(tmp->dl, RTLD_NOW)))
+ {
+ sql_print_error(ER(ER_CANT_OPEN_LIBRARY),
+ tmp->dl,errno,dlerror());
+ del_udf(tmp);
+ continue;
+ }
+ new_dl=1;
+ }
+ tmp->dlhandle = dl;
+ init_syms(tmp);
+ if (!tmp->func)
+ {
+ sql_print_error(ER(ER_CANT_FIND_DL_ENTRY), name);
+ del_udf(tmp);
+ if (new_dl)
+ dlclose(dl);
+ }
+ }
+ if (error > 0)
+ sql_print_error(ER(ER_GET_ERRNO), my_errno);
+ end_read_record(&read_record_info);
+ new_thd->version--; // Force close to free memory
+ close_thread_tables(new_thd);
+ delete new_thd;
+ DBUG_VOID_RETURN;
+}
+
+
+void udf_free()
+{
+ /* close all shared libraries */
+ DBUG_ENTER("udf_free");
+ for (uint idx=0 ; idx < udf_hash.records ; idx++)
+ {
+ udf_func *udf=(udf_func*) hash_element(&udf_hash,idx);
+ if (udf->dl)
+ {
+ for (uint j=idx+1 ; j < udf_hash.records ; j++)
+ {
+ udf_func *tmp=(udf_func*) hash_element(&udf_hash,j);
+ if (tmp->dl && !strcmp(udf->dl,tmp->dl))
+ tmp->dl=0;
+ }
+ }
+ dlclose(udf->dlhandle);
+ }
+ hash_free(&udf_hash);
+ free_root(&mem);
+ DBUG_VOID_RETURN;
+}
+
+
+static void del_udf(udf_func *udf)
+{
+ DBUG_ENTER("del_udf");
+ if (!--udf->usage_count)
+ {
+ hash_delete(&udf_hash,(byte*) udf);
+ using_udf_functions=udf_hash.records != 0;
+ }
+ else
+ {
+ /*
+ ** The functions is in use ; Rename the functions instead of removing it.
+ ** The functions will be automaticly removed when the least threads
+ ** doesn't use it anymore
+ */
+ char *name= udf->name;
+ uint name_length=udf->name_length;
+ udf->name=(char*) "*";
+ udf->name_length=1;
+ hash_update(&udf_hash,(byte*) udf,name,name_length);
+ }
+ DBUG_VOID_RETURN;
+}
+
+
+void free_udf(udf_func *udf)
+{
+ DBUG_ENTER("free_udf");
+ pthread_mutex_lock(&THR_LOCK_udf);
+ if (!--udf->usage_count)
+ {
+ hash_delete(&udf_hash,(byte*) udf);
+ using_udf_functions=udf_hash.records != 0;
+ if (!find_udf_dl(udf->dl))
+ dlclose(udf->dlhandle);
+ }
+ pthread_mutex_unlock(&THR_LOCK_udf);
+ DBUG_VOID_RETURN;
+}
+
+/* This is only called if using_udf_functions != 0 */
+
+udf_func *find_udf(const char *name,uint length,bool mark_used)
+{
+ udf_func *udf=0;
+ DBUG_ENTER("find_udf");
+
+ /* TODO: This should be changed to reader locks someday! */
+ pthread_mutex_lock(&THR_LOCK_udf);
+ udf=(udf_func*) hash_search(&udf_hash,name,
+ length ? length : strlen(name));
+ if (mark_used)
+ udf->usage_count++;
+ pthread_mutex_unlock(&THR_LOCK_udf);
+ DBUG_RETURN(udf);
+}
+
+static void *find_udf_dl(const char *dl)
+{
+ DBUG_ENTER("find_udf_dl");
+
+ /* because only the function name is hashed, we have to search trough
+ ** all rows to find the dl.
+ */
+ for (uint idx=0 ; idx < udf_hash.records ; idx++)
+ {
+ udf_func *udf=(udf_func*) hash_element(&udf_hash,idx);
+ if (!strcmp(dl, udf->dl) && udf->dlhandle != NULL)
+ DBUG_RETURN(udf->dlhandle);
+ }
+ DBUG_RETURN(0);
+}
+
+
+/* Assume that name && dl is already allocated */
+
+static udf_func *add_udf(char *name, Item_result ret, char *dl,
+ Item_udftype type)
+{
+ if (!name || !dl)
+ return 0;
+ udf_func *tmp= (udf_func*) alloc_root(&mem, sizeof(udf_func));
+ if (!tmp)
+ return 0;
+ bzero((char*) tmp,sizeof(*tmp));
+ tmp->name = name;
+ tmp->name_length=strlen(tmp->name);
+ tmp->dl = dl;
+ tmp->returns = ret;
+ tmp->type = type;
+ tmp->usage_count=1;
+ if (hash_insert(&udf_hash,(char*) tmp))
+ return 0;
+ using_udf_functions=1;
+ return tmp;
+}
+
+
+int mysql_create_function(THD *thd,udf_func *udf)
+{
+ int error;
+ void *dl=0;
+ bool new_dl=0;
+ TABLE *table;
+ TABLE_LIST tables;
+ udf_func *u_d;
+ DBUG_ENTER("mysql_create_function");
+
+ if (!initialized)
+ {
+ send_error(&thd->net, ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES));
+ DBUG_RETURN(1);
+ }
+
+ /*
+ Ensure that the .dll doesn't have a path
+ This is done to ensure that only approved dll from the system
+ directories are used (to make this even remotely secure).
+ */
+ if (strchr(udf->dl, '/'))
+ {
+ send_error(&thd->net, ER_UDF_NO_PATHS,ER(ER_UDF_NO_PATHS));
+ DBUG_RETURN(1);
+ }
+ if (udf->name_length > NAME_LEN)
+ {
+ net_printf(&thd->net, ER_TOO_LONG_IDENT,udf->name);
+ DBUG_RETURN(1);
+ }
+
+ pthread_mutex_lock(&THR_LOCK_udf);
+ if (hash_search(&udf_hash,udf->name, udf->name_length))
+ {
+ net_printf(&thd->net, ER_UDF_EXISTS, udf->name);
+ goto err;
+ }
+ if (!(dl = find_udf_dl(udf->dl)))
+ {
+ if (!(dl = dlopen(udf->dl, RTLD_NOW)))
+ {
+ DBUG_PRINT("error",("dlopen of %s failed, error: %d (%s)",
+ udf->dl,errno,dlerror()));
+ net_printf(&thd->net, ER_CANT_OPEN_LIBRARY, udf->dl, errno, dlerror());
+ goto err;
+ }
+ new_dl=1;
+ }
+ udf->dlhandle=dl;
+ init_syms(udf);
+
+ if (udf->func == NULL)
+ {
+ net_printf(&thd->net, ER_CANT_FIND_DL_ENTRY, udf->name);
+ goto err;
+ }
+ udf->name=strdup_root(&mem,udf->name);
+ udf->dl=strdup_root(&mem,udf->dl);
+ if (!udf->name || !udf->dl ||
+ !(u_d=add_udf(udf->name,udf->returns,udf->dl,udf->type)))
+ {
+ send_error(&thd->net,0); // End of memory
+ goto err;
+ }
+ u_d->dlhandle = dl;
+ u_d->func=udf->func;
+ u_d->func_init=udf->func_init;
+ u_d->func_deinit=udf->func_deinit;
+ u_d->func_reset=udf->func_reset;
+ u_d->func_add=udf->func_add;
+
+ /* create entry in mysql/func table */
+
+ bzero((char*) &tables,sizeof(tables));
+ tables.db= (char*) "mysql";
+ tables.real_name=tables.name= (char*) "func";
+ /* Allow creation of functions even if we can't open func table */
+ if (!(table = open_ltable(thd,&tables,TL_WRITE)))
+ goto err;
+
+ restore_record(table,2); // Get default values for fields
+ table->field[0]->store(u_d->name, u_d->name_length);
+ table->field[1]->store((longlong) u_d->returns);
+ table->field[2]->store(u_d->dl,strlen(u_d->dl));
+ if (table->fields >= 4) // If not old func format
+ table->field[3]->store((longlong) u_d->type);
+ error = table->file->write_row(table->record[0]);
+
+ close_thread_tables(thd);
+ if (error)
+ {
+ net_printf(&thd->net, ER_ERROR_ON_WRITE, "func@mysql",error);
+ del_udf(u_d);
+ goto err;
+ }
+ pthread_mutex_unlock(&THR_LOCK_udf);
+ DBUG_RETURN(0);
+
+ err:
+ if (new_dl)
+ dlclose(dl);
+ pthread_mutex_unlock(&THR_LOCK_udf);
+ DBUG_RETURN(1);
+}
+
+
+int mysql_drop_function(THD *thd,const char *udf_name)
+{
+ TABLE *table;
+ TABLE_LIST tables;
+ udf_func *udf;
+ DBUG_ENTER("mysql_drop_function");
+ if (!initialized)
+ {
+ send_error(&thd->net, ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES));
+ DBUG_RETURN(1);
+ }
+ pthread_mutex_lock(&THR_LOCK_udf);
+ if (!(udf=(udf_func*) hash_search(&udf_hash,udf_name, strlen(udf_name))))
+ {
+ net_printf(&thd->net, ER_FUNCTION_NOT_DEFINED, udf_name);
+ goto err;
+ }
+ del_udf(udf);
+ if (!find_udf_dl(udf->dl))
+ dlclose(udf->dlhandle);
+
+ bzero((char*) &tables,sizeof(tables));
+ tables.db=(char*) "mysql";
+ tables.real_name=tables.name=(char*) "func";
+ if (!(table = open_ltable(thd,&tables,TL_WRITE)))
+ goto err;
+ if (!table->file->index_read_idx(table->record[0],0,(byte*) udf_name,
+ strlen(udf_name),
+ HA_READ_KEY_EXACT))
+ {
+ int error;
+ if ((error = table->file->delete_row(table->record[0])))
+ table->file->print_error(error, MYF(0));
+ }
+ close_thread_tables(thd);
+
+ pthread_mutex_unlock(&THR_LOCK_udf);
+ DBUG_RETURN(0);
+ err:
+ pthread_mutex_unlock(&THR_LOCK_udf);
+ DBUG_RETURN(1);
+}
+
+#endif /* HAVE_DLOPEN */
+
+/*
+** Local variables:
+** tab-width: 8
+** c-basic-offset: 2
+** End:
+*/
diff --git a/sql/sql_udf.h b/sql/sql_udf.h
new file mode 100644
index 00000000000..d0b20f0a734
--- /dev/null
+++ b/sql/sql_udf.h
@@ -0,0 +1,144 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 defines structures needed by udf functions */
+
+#ifdef __GNUC__
+#pragma interface
+#endif
+
+enum Item_udftype {UDFTYPE_FUNCTION=1,UDFTYPE_AGGREGATE};
+
+typedef struct st_udf_func
+{
+ char *name;
+ int name_length;
+ Item_result returns;
+ Item_udftype type;
+ char *dl;
+ void *dlhandle;
+ void *func;
+ void *func_init;
+ void *func_deinit;
+ void *func_reset;
+ void *func_add;
+ ulong usage_count;
+} udf_func;
+
+class Item_result_field;
+struct st_table_list;
+
+class udf_handler :public Sql_alloc
+{
+ protected:
+ udf_func *u_d;
+ String *buffers;
+ UDF_ARGS f_args;
+ UDF_INIT initid;
+ char *num_buffer;
+ uchar error;
+ bool initialized;
+ Item **args;
+
+ public:
+ table_map used_tables_cache;
+ bool const_item_cache;
+ udf_handler(udf_func *udf_arg) :u_d(udf_arg), buffers(0), error(0),
+ initialized(0)
+ {}
+ ~udf_handler();
+ const char *name() const { return u_d ? u_d->name : "?"; }
+ Item_result result_type () const
+ { return u_d ? u_d->returns : STRING_RESULT;}
+ bool get_arguments();
+ bool fix_fields(THD *thd,struct st_table_list *tlist,Item_result_field *item,
+ uint arg_count,Item **args);
+ double val(my_bool *null_value)
+ {
+ if (get_arguments())
+ {
+ *null_value=1;
+ return 0.0;
+ }
+ uchar is_null=0;
+ double (*func)(UDF_INIT *, UDF_ARGS *, uchar *, uchar *)=
+ (double (*)(UDF_INIT *, UDF_ARGS *, uchar *, uchar *)) u_d->func;
+ double tmp=func(&initid, &f_args, &is_null, &error);
+ if (is_null || error)
+ {
+ *null_value=1;
+ return 0.0;
+ }
+ *null_value=0;
+ return tmp;
+ }
+ longlong val_int(my_bool *null_value)
+ {
+ if (get_arguments())
+ {
+ *null_value=1;
+ return LL(0);
+ }
+ uchar is_null=0;
+ longlong (*func)(UDF_INIT *, UDF_ARGS *, uchar *, uchar *)=
+ (longlong (*)(UDF_INIT *, UDF_ARGS *, uchar *, uchar *)) u_d->func;
+ longlong tmp=func(&initid, &f_args, &is_null, &error);
+ if (is_null || error)
+ {
+ *null_value=1;
+ return LL(0);
+ }
+ *null_value=0;
+ return tmp;
+ }
+ void reset(my_bool *null_value)
+ {
+ uchar is_null=0;
+ if (get_arguments())
+ {
+ *null_value=1;
+ return;
+ }
+ void (*func)(UDF_INIT *, UDF_ARGS *, uchar *, uchar *)=
+ (void (*)(UDF_INIT *, UDF_ARGS *, uchar *, uchar *)) u_d->func_reset;
+ func(&initid, &f_args, &is_null, &error);
+ *null_value= (my_bool) (is_null || error);
+ }
+ void add(my_bool *null_value)
+ {
+ uchar is_null=0;
+ if (get_arguments())
+ {
+ *null_value=1;
+ return;
+ }
+ void (*func)(UDF_INIT *, UDF_ARGS *, uchar *, uchar *)=
+ (void (*)(UDF_INIT *, UDF_ARGS *, uchar *, uchar *)) u_d->func_add;
+ func(&initid, &f_args, &is_null, &error);
+ *null_value= (my_bool) (is_null || error);
+ }
+ String *val_str(String *str,String *save_str);
+};
+
+
+#ifdef HAVE_DLOPEN
+void udf_init(void),udf_free(void);
+udf_func *find_udf(const char *name, uint len=0,bool mark_used=0);
+void free_udf(udf_func *udf);
+int mysql_create_function(THD *thd,udf_func *udf);
+int mysql_drop_function(THD *thd,const char *name);
+#endif
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
new file mode 100644
index 00000000000..41f0eb97456
--- /dev/null
+++ b/sql/sql_update.cc
@@ -0,0 +1,266 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 */
+
+#include "mysql_priv.h"
+#include "sql_acl.h"
+
+/* Return 0 if row hasn't changed */
+
+static bool compare_record(TABLE *table)
+{
+ if (!table->blob_fields)
+ return cmp_record(table,1);
+ ulong current_query_id=current_thd->query_id;
+
+ if (memcmp(table->null_flags,
+ table->null_flags+table->rec_buff_length,
+ table->null_bytes))
+ return 1; // Diff in NULL value
+ for (Field **ptr=table->field ; *ptr ; ptr++)
+ {
+ if ((*ptr)->query_id == current_query_id &&
+ (*ptr)->cmp_binary_offset(table->rec_buff_length))
+ return 1;
+ }
+ return 0;
+}
+
+
+int mysql_update(THD *thd,TABLE_LIST *table_list,List<Item> &fields,
+ List<Item> &values, COND *conds,
+ ha_rows limit,
+ enum enum_duplicates handle_duplicates,
+ thr_lock_type lock_type)
+{
+ bool using_limit=limit != HA_POS_ERROR;
+ bool used_key_is_modified;
+ int error=0;
+ uint save_time_stamp, used_index;
+ key_map old_used_keys;
+ TABLE *table;
+ SQL_SELECT *select;
+ READ_RECORD info;
+ DBUG_ENTER("mysql_update");
+ LINT_INIT(used_index);
+
+ if (!(table = open_ltable(thd,table_list,lock_type)))
+ DBUG_RETURN(-1);
+ save_time_stamp=table->time_stamp;
+ table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
+ thd->proc_info="init";
+
+ /*
+ ** Find the offsets of the given fields and condition
+ */
+
+ if (setup_fields(thd,table_list,fields,1,0))
+ DBUG_RETURN(-1);
+ table->grant.want_privilege=(SELECT_ACL & ~table->grant.privilege);
+ if (table->timestamp_field && // Don't set timestamp if used
+ table->timestamp_field->query_id == thd->query_id)
+ table->time_stamp=0;
+ table->used_keys=table->keys_in_use;
+ table->quick_keys=0;
+ if (setup_fields(thd,table_list,values,0,0) ||
+ setup_conds(thd,table_list,&conds))
+ {
+ table->time_stamp=save_time_stamp; // Restore timestamp pointer
+ DBUG_RETURN(-1); /* purecov: inspected */
+ }
+ old_used_keys=table->used_keys;
+ table->used_keys=0; // Can't use 'only index'
+ select=make_select(table,0,0,conds,&error);
+ if (error ||
+ (select && select->check_quick(test(thd->options & SQL_SAFE_UPDATES),
+ limit)))
+ {
+ delete select;
+ table->time_stamp=save_time_stamp; // Restore timestamp pointer
+ if (error)
+ {
+ DBUG_RETURN(-1); // Error in where
+ }
+ send_ok(&thd->net); // No matching records
+ DBUG_RETURN(0);
+ }
+ /* If running in safe sql mode, don't allow updates without keys */
+ if ((thd->options & OPTION_SAFE_UPDATES) && !table->quick_keys &&
+ limit == HA_POS_ERROR)
+ {
+ delete select;
+ table->time_stamp=save_time_stamp;
+ send_error(&thd->net,ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE);
+ DBUG_RETURN(1);
+ }
+
+ /* Check if we are modifying a key that we are used to search with */
+ if (select && select->quick)
+ used_key_is_modified= (!select->quick->unique_key_range() &&
+ check_if_key_used(table,
+ (used_index=select->quick->index),
+ fields));
+ else if ((used_index=table->file->key_used_on_scan) < MAX_KEY)
+ used_key_is_modified=check_if_key_used(table, used_index, fields);
+ else
+ used_key_is_modified=0;
+ if (used_key_is_modified)
+ {
+ /*
+ ** We can't update table directly; We must first search after all
+ ** matching rows before updating the table!
+ */
+ IO_CACHE tempfile;
+ if (open_cached_file(&tempfile, mysql_tmpdir,TEMP_PREFIX,
+ DISK_BUFFER_SIZE, MYF(MY_WME)))
+ {
+ delete select;
+ table->time_stamp=save_time_stamp; // Restore timestamp pointer
+ DBUG_RETURN(-1);
+ }
+ if (old_used_keys & ((key_map) 1 << used_index))
+ {
+ table->key_read=1;
+ table->file->extra(HA_EXTRA_KEYREAD);
+ }
+ init_read_record(&info,thd,table,select,0,1);
+ thd->proc_info="searching";
+
+ while (!(error=info.read_record(&info)) && !thd->killed)
+ {
+ if (!(select && select->skipp_record()))
+ {
+ table->file->position(table->record[0]);
+ if (my_b_write(&tempfile,table->file->ref,
+ table->file->ref_length))
+ {
+ error=1;
+ break;
+ }
+ }
+ else
+ {
+ if (!(test_flags & 512)) /* For debugging */
+ {
+ DBUG_DUMP("record",(char*) table->record[0],table->reclength);
+ }
+ }
+ }
+ end_read_record(&info);
+ if (table->key_read)
+ {
+ table->key_read=0;
+ table->file->extra(HA_EXTRA_NO_KEYREAD);
+ }
+ /* Change select to use tempfile */
+ if (select)
+ {
+ delete select->quick;
+ if (select->free_cond)
+ delete select->cond;
+ select->quick=0;
+ select->cond=0;
+ }
+ else
+ {
+ select= new SQL_SELECT;
+ select->head=table;
+ }
+ if (reinit_io_cache(&tempfile,READ_CACHE,0L,0,0))
+ error=1;
+ select->file=tempfile; // Read row ptrs from this file
+ if (error >= 0)
+ {
+ delete select;
+ table->time_stamp=save_time_stamp; // Restore timestamp pointer
+ DBUG_RETURN(-1);
+ }
+ }
+
+ if (!(test_flags & TEST_READCHECK)) /* For debugging */
+ VOID(table->file->extra(HA_EXTRA_NO_READCHECK));
+ init_read_record(&info,thd,table,select,0,1);
+
+ ha_rows updated=0L,found=0L;
+ thd->count_cuted_fields=1; /* calc cuted fields */
+ thd->cuted_fields=0L;
+ thd->proc_info="updating";
+
+ while (!(error=info.read_record(&info)) && !thd->killed)
+ {
+ if (!(select && select->skipp_record()))
+ {
+ store_record(table,1);
+ if (fill_record(fields,values))
+ break;
+ found++;
+ if (compare_record(table))
+ {
+ if (!(error=table->file->update_row((byte*) table->record[1],
+ (byte*) table->record[0])))
+ {
+ updated++;
+ if (!--limit && using_limit)
+ {
+ error= -1;
+ break;
+ }
+ }
+ else if (handle_duplicates != DUP_IGNORE ||
+ error != HA_ERR_FOUND_DUPP_KEY)
+ {
+ table->file->print_error(error,MYF(0));
+ error= 1;
+ break;
+ }
+ }
+ }
+ }
+ end_read_record(&info);
+ thd->proc_info="end";
+ VOID(table->file->extra(HA_EXTRA_READCHECK));
+ table->time_stamp=save_time_stamp; // Restore auto timestamp pointer
+ if (updated)
+ {
+ mysql_update_log.write(thd->query,thd->query_length);
+ Query_log_event qinfo(thd, thd->query);
+ mysql_bin_log.write(&qinfo);
+ }
+ if (ha_autocommit_or_rollback(thd, error >= 0))
+ error=1;
+ if (thd->lock)
+ {
+ mysql_unlock_tables(thd, thd->lock);
+ thd->lock=0;
+ }
+ delete select;
+ if (error >= 0)
+ send_error(&thd->net,thd->killed ? ER_SERVER_SHUTDOWN : 0); /* purecov: inspected */
+ else
+ {
+ char buff[80];
+ sprintf(buff,ER(ER_UPDATE_INFO), (long) found, (long) updated,
+ (long) thd->cuted_fields);
+ send_ok(&thd->net,
+ (thd->client_capabilities & CLIENT_FOUND_ROWS) ? found : updated,
+ thd->insert_id_used ? thd->insert_id() : 0L,buff);
+ DBUG_PRINT("info",("%d records updated",updated));
+ }
+ thd->count_cuted_fields=0; /* calc cuted fields */
+ DBUG_RETURN(0);
+}
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
new file mode 100644
index 00000000000..21f7ec1c48a
--- /dev/null
+++ b/sql/sql_yacc.yy
@@ -0,0 +1,2767 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* sql_yacc.y */
+
+%{
+#define MYSQL_YACC
+#define YYINITDEPTH 100
+#define YYMAXDEPTH 3200 /* Because of 64K stack */
+#define Lex current_lex
+#include "mysql_priv.h"
+#include "sql_acl.h"
+#include "lex_symbol.h"
+#include <myisam.h>
+
+extern void yyerror(const char*);
+int yylex(void *yylval);
+
+#define yyoverflow(A,B,C,D,E,F) if (my_yyoverflow((B),(D),(F))) { yyerror((char*) (A)); return 2; }
+
+inline Item *or_or_concat(Item* A, Item* B)
+{
+ return (current_thd->options & OPTION_ANSI_MODE ?
+ (Item*) new Item_func_concat(A,B) : (Item*) new Item_cond_or(A,B));
+}
+
+%}
+%union {
+ int num;
+ ulong ulong_num;
+ ulonglong ulonglong_num;
+ LEX_STRING lex_str;
+ LEX_STRING *lex_str_ptr;
+ LEX_SYMBOL symbol;
+ Table_ident *table;
+ char *simple_string;
+ Item *item;
+ List<Item> *item_list;
+ List<String> *string_list;
+ Key::Keytype key_type;
+ enum db_type db_type;
+ enum row_type row_type;
+ String *string;
+ key_part_spec *key_part;
+ TABLE_LIST *table_list;
+ udf_func *udf;
+ interval_type interval;
+ LEX_USER *lex_user;
+ enum Item_udftype udf_type;
+}
+
+%{
+bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
+%}
+
+%pure_parser /* We have threads */
+
+%token END_OF_INPUT
+
+%token EQ
+%token EQUAL_SYM
+%token GE
+%token GT_SYM
+%token LE
+%token LT
+%token NE
+%token IS
+%token SHIFT_LEFT
+%token SHIFT_RIGHT
+%token SET_VAR
+
+%token AVG_SYM
+%token COUNT_SYM
+%token MAX_SYM
+%token MIN_SYM
+%token SUM_SYM
+%token STD_SYM
+
+%token ADD
+%token ALTER
+%token AFTER_SYM
+%token ANALYZE_SYM
+%token BEGIN_SYM
+%token CHANGE
+%token COMMENT_SYM
+%token COMMIT_SYM
+%token CREATE
+%token CROSS
+%token DELETE_SYM
+%token DROP
+%token INSERT
+%token FLUSH_SYM
+%token SELECT_SYM
+%token MASTER_SYM
+%token REPAIR
+%token SLAVE
+%token START_SYM
+%token STOP_SYM
+%token ROLLBACK_SYM
+%token OPTIMIZE
+%token SHOW
+%token UPDATE_SYM
+%token KILL_SYM
+%token LOAD
+%token LOCK_SYM
+%token UNLOCK_SYM
+
+%token ACTION
+%token AGGREGATE_SYM
+%token ALL
+%token AND
+%token AS
+%token ASC
+%token AUTO_INC
+%token AUTOCOMMIT
+%token AVG_ROW_LENGTH
+%token BERKELEY_DB_SYM
+%token BINARY
+%token BIT_SYM
+%token BOOL_SYM
+%token BOTH
+%token BY
+%token CASCADE
+%token CHANGED_FILES
+%token CHECKSUM_SYM
+%token CHECK_SYM
+%token COLLECTION
+%token COLUMNS
+%token COLUMN_SYM
+%token CONSTRAINT
+%token DATABASES
+%token DATA_SYM
+%token DEFAULT
+%token DELAYED_SYM
+%token DELAY_KEY_WRITE_SYM
+%token DESC
+%token DESCRIBE
+%token DISTINCT
+%token DYNAMIC_SYM
+%token ENCLOSED
+%token ESCAPED
+%token ESCAPE_SYM
+%token EXISTS
+%token EXTENDED_SYM
+%token FILE_SYM
+%token FIRST_SYM
+%token FIXED_SYM
+%token FLOAT_NUM
+%token FOREIGN
+%token FROM
+%token FULL
+%token GRANT
+%token GRANTS
+%token GREATEST_SYM
+%token GROUP
+%token HAVING
+%token HEAP_SYM
+%token HEX_NUM
+%token HIGH_PRIORITY
+%token HOSTS_SYM
+%token IDENT
+%token IGNORE_SYM
+%token INDEX
+%token INFILE
+%token INNER_SYM
+%token INTO
+%token IN_SYM
+%token ISAM_SYM
+%token JOIN_SYM
+%token KEYS
+%token KEY_SYM
+%token LEADING
+%token LEAST_SYM
+%token LEX_HOSTNAME
+%token LIKE
+%token LINES
+%token LOCAL_SYM
+%token LOGS_SYM
+%token LONG_NUM
+%token LONG_SYM
+%token LOW_PRIORITY
+%token MASTER_HOST_SYM
+%token MASTER_USER_SYM
+%token MASTER_LOG_FILE_SYM
+%token MASTER_LOG_POS_SYM
+%token MASTER_PASSWORD_SYM
+%token MASTER_PORT_SYM
+%token MASTER_CONNECT_RETRY_SYM
+%token MATCH
+%token MAX_ROWS
+%token MERGE_SYM
+%token MIN_ROWS
+%token MYISAM_SYM
+%token NATIONAL_SYM
+%token NATURAL
+%token NCHAR_SYM
+%token NOT
+%token NO_SYM
+%token NULL_SYM
+%token NUM
+%token ON
+%token OPTION
+%token OPTIONALLY
+%token OR
+%token OR_OR_CONCAT
+%token ORDER_SYM
+%token OUTER
+%token OUTFILE
+%token DUMPFILE
+%token PACK_KEYS_SYM
+%token PARTIAL
+%token PRIMARY_SYM
+%token PRIVILEGES
+%token PROCESS
+%token PROCESSLIST_SYM
+%token RAID_0_SYM
+%token RAID_STRIPED_SYM
+%token RAID_TYPE
+%token RAID_CHUNKS
+%token RAID_CHUNKSIZE
+%token READ_SYM
+%token REAL_NUM
+%token REFERENCES
+%token REGEXP
+%token RELOAD
+%token RENAME
+%token RESTRICT
+%token REVOKE
+%token ROWS_SYM
+%token ROW_FORMAT_SYM
+%token ROW_SYM
+%token SET
+%token SHUTDOWN
+%token STARTING
+%token STATUS_SYM
+%token STRAIGHT_JOIN
+%token TABLES
+%token TABLE_SYM
+%token TEMPORARY
+%token TERMINATED
+%token TEXT_STRING
+%token TO_SYM
+%token TRAILING
+%token TYPE_SYM
+%token FUNC_ARG0
+%token FUNC_ARG1
+%token FUNC_ARG2
+%token FUNC_ARG3
+%token UDF_RETURNS_SYM
+%token UDF_SONAME_SYM
+%token UDF_SYM
+%token UNIQUE_SYM
+%token USAGE
+%token USE_SYM
+%token USING
+%token VALUES
+%token VARIABLES
+%token WHERE
+%token WITH
+%token WRITE_SYM
+%token COMPRESSED_SYM
+
+%token BIGINT
+%token BLOB_SYM
+%token CHAR_SYM
+%token COALESCE
+%token DATETIME
+%token DATE_SYM
+%token DECIMAL_SYM
+%token DOUBLE_SYM
+%token ENUM
+%token FLOAT_SYM
+%token INT_SYM
+%token LIMIT
+%token LONGBLOB
+%token LONGTEXT
+%token MEDIUMBLOB
+%token MEDIUMINT
+%token MEDIUMTEXT
+%token NUMERIC_SYM
+%token PRECISION
+%token QUICK
+%token REAL
+%token SMALLINT
+%token STRING_SYM
+%token TEXT_SYM
+%token TIMESTAMP
+%token TIME_SYM
+%token TINYBLOB
+%token TINYINT
+%token TINYTEXT
+%token UNSIGNED
+%token VARBINARY
+%token VARCHAR
+%token VARYING
+%token ZEROFILL
+
+%token AGAINST
+%token ATAN
+%token BETWEEN_SYM
+%token BIT_AND
+%token BIT_OR
+%token CASE_SYM
+%token CONCAT
+%token CONCAT_WS
+%token CURDATE
+%token CURTIME
+%token DATABASE
+%token DATE_ADD_INTERVAL
+%token DATE_SUB_INTERVAL
+%token DAY_HOUR_SYM
+%token DAY_MINUTE_SYM
+%token DAY_OF_WEEK
+%token DAY_OF_YEAR
+%token DAY_SECOND_SYM
+%token DAY_SYM
+%token DECODE_SYM
+%token ELSE
+%token ELT_FUNC
+%token ENCODE_SYM
+%token ENCRYPT
+%token EXPORT_SET
+%token EXTRACT_SYM
+%token FIELD_FUNC
+%token FORMAT_SYM
+%token FOR_SYM
+%token FROM_UNIXTIME
+%token GROUP_UNIQUE_USERS
+%token HOUR_MINUTE_SYM
+%token HOUR_SECOND_SYM
+%token HOUR_SYM
+%token IDENTIFIED_SYM
+%token IF
+%token INSERT_ID
+%token INTERVAL_SYM
+%token LAST_INSERT_ID
+%token LEFT
+%token LOCATE
+%token MAKE_SET_SYM
+%token MINUTE_SECOND_SYM
+%token MINUTE_SYM
+%token MODIFY_SYM
+%token MONTH_SYM
+%token NOW_SYM
+%token PASSWORD
+%token POSITION_SYM
+%token PROCEDURE
+%token RAND
+%token REPLACE
+%token RIGHT
+%token ROUND
+%token SECOND_SYM
+%token SEC_TO_TIME
+%token SUBSTRING
+%token SUBSTRING_INDEX
+%token TRIM
+%token UDA_CHAR_SUM
+%token UDA_FLOAT_SUM
+%token UDA_INT_SUM
+%token UDF_CHAR_FUNC
+%token UDF_FLOAT_FUNC
+%token UDF_INT_FUNC
+%token UNIQUE_USERS
+%token UNIX_TIMESTAMP
+%token USER
+%token VERSION_SYM
+%token WEEKDAY
+%token WEEK_SYM
+%token WHEN_SYM
+%token WORK_SYM
+%token YEAR_MONTH_SYM
+%token YEAR_SYM
+%token YEARWEEK
+%token BENCHMARK_SYM
+%token END
+%token THEN_SYM
+
+%token SQL_BIG_TABLES
+%token SQL_BIG_SELECTS
+%token SQL_SELECT_LIMIT
+%token SQL_MAX_JOIN_SIZE
+%token SQL_LOG_BIN
+%token SQL_LOG_OFF
+%token SQL_LOG_UPDATE
+%token SQL_LOW_PRIORITY_UPDATES
+%token SQL_SMALL_RESULT
+%token SQL_BIG_RESULT
+%token SQL_BUFFER_RESULT
+%token SQL_WARNINGS
+%token SQL_AUTO_IS_NULL
+%token SQL_SAFE_UPDATES
+
+%left SET_VAR
+%left OR_OR_CONCAT OR
+%left AND
+%left BETWEEN_SYM CASE_SYM WHEN_SYM THEN_SYM ELSE
+%left EQ EQUAL_SYM GE GT_SYM LE LT NE IS LIKE REGEXP IN_SYM
+%left '|'
+%left '&'
+%left SHIFT_LEFT SHIFT_RIGHT
+%left '-' '+'
+%left '*' '/' '%'
+%left NEG '~'
+%right NOT
+%right BINARY
+
+%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
+
+%type <lex_str_ptr>
+ opt_table_alias
+
+%type <table>
+ table_ident
+
+%type <simple_string>
+ remember_name remember_end opt_len opt_ident opt_db text_or_password
+ opt_escape
+
+%type <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
+
+%type <ulong_num>
+ ULONG_NUM raid_types
+
+%type <ulonglong_num>
+ ULONGLONG_NUM
+
+%type <item>
+ literal text_literal insert_ident group_ident order_ident
+ simple_ident select_item2 expr opt_expr opt_else sum_expr in_sum_expr
+ table_wild opt_pad no_in_expr expr_expr simple_expr no_and_expr
+ using_list
+
+%type <item_list>
+ expr_list udf_expr_list when_list ident_list
+
+%type <key_type>
+ key_type opt_unique
+
+%type <string_list>
+ key_usage_list
+
+%type <key_part>
+ key_part
+
+%type <table_list>
+ join_table_list join_table
+
+%type <udf>
+ UDF_CHAR_FUNC UDF_FLOAT_FUNC UDF_INT_FUNC
+ UDA_CHAR_SUM UDA_FLOAT_SUM UDA_INT_SUM
+
+%type <interval> interval
+
+%type <db_type> table_types
+
+%type <row_type> row_types
+
+%type <udf_type> udf_func_type
+
+%type <symbol> FUNC_ARG0 FUNC_ARG1 FUNC_ARG2 FUNC_ARG3 keyword
+
+%type <lex_user> user grant_user
+
+%type <NONE>
+ query verb_clause create change select drop insert replace insert2
+ insert_values update delete show describe load alter optimize flush
+ begin commit rollback slave master_def master_defs
+ repair analyze check field_list field_list_item field_spec kill
+ 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
+ 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_outer table_list table 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
+ flush_options flush_option insert_lock_option replace_lock_option
+ equal optional_braces opt_key_definition key_usage_list2
+ opt_mi_check_type opt_to mi_check_types normal_join
+ END_OF_INPUT
+
+%type <NONE>
+ '-' '+' '*' '/' '%' '(' ')'
+ ',' '!' '{' '}' '&' '|' AND OR OR_OR_CONCAT BETWEEN_SYM CASE_SYM THEN_SYM WHEN_SYM
+%%
+
+
+query:
+ END_OF_INPUT
+ {
+ if (!current_thd->bootstrap)
+ send_error(&current_thd->net,ER_EMPTY_QUERY);
+ YYABORT;
+ }
+ | verb_clause END_OF_INPUT {}
+
+verb_clause:
+ alter
+ | analyze
+ | begin
+ | change
+ | check
+ | commit
+ | create
+ | delete
+ | describe
+ | drop
+ | grant
+ | insert
+ | flush
+ | load
+ | lock
+ | kill
+ | optimize
+ | repair
+ | replace
+ | revoke
+ | rollback
+ | select
+ | set
+ | slave
+ | show
+ | unlock
+ | update
+ | use
+
+/* change master */
+
+change:
+ CHANGE MASTER_SYM TO_SYM
+ {
+ LEX *lex = Lex;
+ lex->sql_command = SQLCOM_CHANGE_MASTER;
+ memset(&lex->mi, 0, sizeof(lex->mi));
+ } master_defs
+
+master_defs:
+ master_def
+ |
+ master_defs ',' master_def
+
+master_def:
+ MASTER_HOST_SYM EQ TEXT_STRING
+ {
+ Lex->mi.host = $3.str;
+ }
+ |
+ MASTER_USER_SYM EQ TEXT_STRING
+ {
+ Lex->mi.user = $3.str;
+ }
+ |
+ MASTER_PASSWORD_SYM EQ TEXT_STRING
+ {
+ Lex->mi.password = $3.str;
+ }
+ |
+ MASTER_LOG_FILE_SYM EQ TEXT_STRING
+ {
+ Lex->mi.log_file_name = $3.str;
+ }
+ |
+ MASTER_PORT_SYM EQ ULONGLONG_NUM
+ {
+ Lex->mi.port = $3;
+ }
+ |
+ MASTER_LOG_POS_SYM EQ ULONGLONG_NUM
+ {
+ Lex->mi.pos = $3;
+ }
+ |
+ MASTER_CONNECT_RETRY_SYM EQ ULONGLONG_NUM
+ {
+ Lex->mi.connect_retry = $3;
+ }
+
+
+
+/* create a table */
+
+create:
+ CREATE opt_table_options TABLE_SYM opt_if_not_exists table_ident
+ {
+ LEX *lex=Lex;
+ lex->sql_command= SQLCOM_CREATE_TABLE;
+ if (!add_table_to_list($5,
+ ($2 & HA_LEX_CREATE_TMP_TABLE ?
+ &tmp_table_alias : (LEX_STRING*) 0)))
+ YYABORT;
+ lex->create_list.empty();
+ lex->key_list.empty();
+ lex->col_list.empty();
+ lex->change=NullS;
+ bzero((char*) &lex->create_info,sizeof(lex->create_info));
+ lex->create_info.options=$2 | $4;
+ lex->create_info.db_type= default_table_type;
+ }
+ create2
+
+ | CREATE opt_unique INDEX ident ON table_ident
+ {
+ Lex->sql_command= SQLCOM_CREATE_INDEX;
+ if (!add_table_to_list($6,NULL))
+ YYABORT;
+ 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();
+ }
+ | CREATE COLLECTION ident ON table_ident
+ {
+ Lex->sql_command= SQLCOM_CREATE_INDEX;
+ if (!add_table_to_list($5,NULL))
+ YYABORT;
+ Lex->create_list.empty();
+ Lex->key_list.empty();
+ Lex->col_list.empty();
+ Lex->change=NullS;
+ }
+ '(' key_list ')'
+ {
+ Lex->key_list.push_back(new Key(Key::FULLTEXT,$3.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;
+ }
+ | 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;
+ }
+ UDF_RETURNS_SYM udf_type UDF_SONAME_SYM TEXT_STRING
+ {
+ Lex->udf.returns=(Item_result) $7;
+ Lex->udf.dl=$9.str;
+ }
+
+create2:
+ '(' field_list ')' opt_create_table_options create3 {}
+ | opt_create_table_options create3 {}
+
+create3:
+ /* empty*/ {}
+ | opt_duplicate SELECT_SYM
+ {
+ LEX *lex=Lex;
+ lex->where=lex->having=0;
+ lex->select_limit=current_thd->default_select_limit;
+ lex->offset_limit=0L;
+ lex->options=0;
+ lex->exchange = 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_options select_item_list opt_select_from {}
+
+opt_table_options:
+ /* empty */ { $$= 0; }
+ | table_options { $$= $1;}
+
+table_options:
+ table_option { $$=$1; }
+ | table_option table_options { $$= $1 | $2 }
+
+table_option:
+ TEMPORARY { $$=HA_LEX_CREATE_TMP_TABLE; }
+
+opt_if_not_exists:
+ /* empty */ { $$= 0; }
+ | IF NOT EXISTS { $$=HA_LEX_CREATE_IF_NOT_EXISTS; }
+
+opt_create_table_options:
+ /* empty */
+ | create_table_options
+
+create_table_options:
+ create_table_option
+ | create_table_option 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; }
+ | 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; }
+ | 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; }
+ | RAID_TYPE EQ raid_types { Lex->create_info.raid_type= $3; Lex->create_info.used_fields|= HA_CREATE_USED_RAID;}
+ | RAID_CHUNKS EQ ULONG_NUM { Lex->create_info.raid_chunks= $3; Lex->create_info.used_fields|= HA_CREATE_USED_RAID;}
+ | RAID_CHUNKSIZE EQ ULONG_NUM { Lex->create_info.raid_chunksize= $3*RAID_BLOCK_SIZE; Lex->create_info.used_fields|= HA_CREATE_USED_RAID;}
+
+table_types:
+ ISAM_SYM { $$= DB_TYPE_ISAM; }
+ | MYISAM_SYM { $$= DB_TYPE_MYISAM; }
+ | MERGE_SYM { $$= DB_TYPE_MRG_MYISAM; }
+ | HEAP_SYM { $$= DB_TYPE_HEAP; }
+ | BERKELEY_DB_SYM { $$= DB_TYPE_BERKELEY_DB; }
+
+row_types:
+ DEFAULT { $$= ROW_TYPE_DEFAULT; }
+ | FIXED_SYM { $$= ROW_TYPE_FIXED; }
+ | DYNAMIC_SYM { $$= ROW_TYPE_DYNAMIC; }
+ | COMPRESSED_SYM { $$= ROW_TYPE_COMPRESSED; }
+
+raid_types:
+ RAID_STRIPED_SYM { $$= RAID_TYPE_0; }
+ | RAID_0_SYM { $$= RAID_TYPE_0; }
+ | ULONG_NUM { $$=$1;}
+
+opt_select_from:
+ /* empty */
+ | select_from
+
+udf_func_type:
+ /* empty */ { $$ = UDFTYPE_FUNCTION; }
+ | AGGREGATE_SYM { $$ = UDFTYPE_AGGREGATE; }
+
+udf_type:
+ STRING_SYM {$$ = (int) STRING_RESULT; }
+ | REAL {$$ = (int) REAL_RESULT; }
+ | INT_SYM {$$ = (int) INT_RESULT; }
+
+field_list:
+ field_list_item
+ | field_list ',' field_list_item
+
+
+field_list_item:
+ field_spec
+ | field_spec references
+ {
+ Lex->col_list.empty(); /* Alloced by sql_alloc */
+ }
+ | 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 */
+ }
+ | opt_constraint FOREIGN KEY_SYM '(' key_list ')' references
+ {
+ Lex->col_list.empty(); /* Alloced by sql_alloc */
+ }
+ | opt_constraint CHECK_SYM '(' expr ')'
+ {
+ Lex->col_list.empty(); /* Alloced by sql_alloc */
+ }
+
+opt_constraint:
+ /* empty */
+ | CONSTRAINT opt_ident
+
+field_spec:
+ field_ident
+ {
+ Lex->length=Lex->dec=0; Lex->type=0; Lex->interval=0;
+ Lex->default_value=0;
+ }
+ type opt_attribute
+ {
+ 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))
+ YYABORT;
+ }
+
+type:
+ int_type opt_len field_options { Lex->length=$2; $$=$1; }
+ | real_type opt_precision field_options { $$=$1; }
+ | FLOAT_SYM float_options field_options { $$=FIELD_TYPE_FLOAT; }
+ | BIT_SYM opt_len { Lex->length=(char*) "1";
+ $$=FIELD_TYPE_TINY; }
+ | BOOL_SYM { Lex->length=(char*) "1";
+ $$=FIELD_TYPE_TINY; }
+ | char '(' NUM ')' opt_binary { Lex->length=$3.str;
+ $$=FIELD_TYPE_STRING; }
+ | char opt_binary { Lex->length=(char*) "1";
+ $$=FIELD_TYPE_STRING; }
+ | BINARY '(' NUM ')' { Lex->length=$3.str;
+ Lex->type|=BINARY_FLAG;
+ $$=FIELD_TYPE_STRING; }
+ | varchar '(' NUM ')' opt_binary { Lex->length=$3.str;
+ $$=FIELD_TYPE_VAR_STRING; }
+ | VARBINARY '(' NUM ')' { Lex->length=$3.str;
+ Lex->type|=BINARY_FLAG;
+ $$=FIELD_TYPE_VAR_STRING; }
+ | YEAR_SYM opt_len field_options { $$=FIELD_TYPE_YEAR; Lex->length=$2; }
+ | DATE_SYM { $$=FIELD_TYPE_DATE; }
+ | TIME_SYM { $$=FIELD_TYPE_TIME; }
+ | TIMESTAMP { $$=FIELD_TYPE_TIMESTAMP; }
+ | TIMESTAMP '(' NUM ')' { Lex->length=$3.str;
+ $$=FIELD_TYPE_TIMESTAMP; }
+ | DATETIME { $$=FIELD_TYPE_DATETIME; }
+ | TINYBLOB { Lex->type|=BINARY_FLAG;
+ $$=FIELD_TYPE_TINY_BLOB; }
+ | BLOB_SYM { Lex->type|=BINARY_FLAG;
+ $$=FIELD_TYPE_BLOB; }
+ | MEDIUMBLOB { Lex->type|=BINARY_FLAG;
+ $$=FIELD_TYPE_MEDIUM_BLOB; }
+ | LONGBLOB { Lex->type|=BINARY_FLAG;
+ $$=FIELD_TYPE_LONG_BLOB; }
+ | LONG_SYM VARBINARY { Lex->type|=BINARY_FLAG;
+ $$=FIELD_TYPE_MEDIUM_BLOB; }
+ | LONG_SYM varchar { $$=FIELD_TYPE_MEDIUM_BLOB; }
+ | TINYTEXT { $$=FIELD_TYPE_TINY_BLOB; }
+ | TEXT_SYM { $$=FIELD_TYPE_BLOB; }
+ | MEDIUMTEXT { $$=FIELD_TYPE_MEDIUM_BLOB; }
+ | LONGTEXT { $$=FIELD_TYPE_LONG_BLOB; }
+ | DECIMAL_SYM float_options field_options
+ { $$=FIELD_TYPE_DECIMAL;}
+ | NUMERIC_SYM float_options field_options
+ { $$=FIELD_TYPE_DECIMAL;}
+ | ENUM {Lex->interval_list.empty();} '(' string_list ')'
+ {
+ Lex->interval=typelib(Lex->interval_list);
+ $$=FIELD_TYPE_ENUM;
+ }
+ | SET { Lex->interval_list.empty();} '(' string_list ')'
+ {
+ Lex->interval=typelib(Lex->interval_list);
+ $$=FIELD_TYPE_SET;
+ }
+
+char:
+ CHAR_SYM {}
+ | NCHAR_SYM {}
+ | NATIONAL_SYM CHAR_SYM {}
+
+varchar:
+ char VARYING {}
+ | VARCHAR {}
+ | NATIONAL_SYM VARCHAR {}
+ | NCHAR_SYM VARCHAR {}
+
+int_type:
+ INT_SYM { $$=FIELD_TYPE_LONG; }
+ | TINYINT { $$=FIELD_TYPE_TINY; }
+ | SMALLINT { $$=FIELD_TYPE_SHORT; }
+ | MEDIUMINT { $$=FIELD_TYPE_INT24; }
+ | BIGINT { $$=FIELD_TYPE_LONGLONG; }
+
+real_type:
+ REAL { $$= current_thd->options & OPTION_ANSI_MODE ?
+ FIELD_TYPE_FLOAT : FIELD_TYPE_DOUBLE; }
+ | DOUBLE_SYM { $$=FIELD_TYPE_DOUBLE; }
+ | DOUBLE_SYM PRECISION { $$=FIELD_TYPE_DOUBLE; }
+
+
+float_options:
+ /* empty */ {}
+ | '(' NUM ')' { Lex->length=$2.str; }
+ | '(' NUM ',' NUM ')' { Lex->length=$2.str; Lex->dec=$4.str; }
+
+field_options:
+ /* empty */ {}
+ | field_opt_list {}
+
+field_opt_list:
+ field_opt_list field_option {}
+ | field_option {}
+
+field_option:
+ UNSIGNED { Lex->type|= UNSIGNED_FLAG;}
+ | ZEROFILL { Lex->type|= UNSIGNED_FLAG | ZEROFILL_FLAG; }
+
+opt_len:
+ /* empty */ { $$=(char*) 0; } /* use default length */
+ | '(' NUM ')' { $$=$2.str; }
+
+opt_precision:
+ /* empty */ {}
+ | '(' NUM ',' NUM ')' { Lex->length=$2.str; Lex->dec=$4.str; }
+
+opt_attribute:
+ /* empty */ {}
+ | opt_attribute_list {}
+
+opt_attribute_list:
+ opt_attribute_list attribute {}
+ | attribute
+
+attribute:
+ NULL_SYM { Lex->type&= ~ NOT_NULL_FLAG; }
+ | NOT NULL_SYM { Lex->type|= NOT_NULL_FLAG; }
+ | DEFAULT literal { Lex->default_value=$2; }
+ | AUTO_INC { Lex->type|= AUTO_INCREMENT_FLAG | NOT_NULL_FLAG; }
+ | PRIMARY_SYM KEY_SYM { Lex->type|= PRI_KEY_FLAG | NOT_NULL_FLAG; }
+ | UNIQUE_SYM { Lex->type|= UNIQUE_FLAG; }
+ | UNIQUE_SYM KEY_SYM { Lex->type|= UNIQUE_KEY_FLAG; }
+
+opt_binary:
+ /* empty */ {}
+ | BINARY { Lex->type|=BINARY_FLAG; }
+
+references:
+ REFERENCES table_ident opt_on_delete {}
+ | REFERENCES table_ident '(' key_list ')' opt_on_delete
+ {
+ Lex->col_list.empty(); /* Alloced by sql_alloc */
+ }
+
+opt_on_delete:
+ /* empty */ {}
+ | opt_on_delete_list {}
+
+opt_on_delete_list:
+ opt_on_delete_list opt_on_delete_item {}
+ | opt_on_delete_item {}
+
+
+opt_on_delete_item:
+ ON DELETE_SYM delete_option {}
+ | ON UPDATE_SYM delete_option {}
+ | MATCH FULL {}
+ | MATCH PARTIAL {}
+
+delete_option:
+ RESTRICT {}
+ | CASCADE {}
+ | SET NULL_SYM {}
+ | NO_SYM ACTION {}
+ | SET DEFAULT {}
+
+key_type:
+ opt_constraint PRIMARY_SYM KEY_SYM { $$= Key::PRIMARY; }
+ | key_or_index { $$= Key::MULTIPLE; }
+ | opt_constraint UNIQUE_SYM { $$= Key::UNIQUE; }
+ | opt_constraint UNIQUE_SYM key_or_index { $$= Key::UNIQUE; }
+
+key_or_index:
+ KEY_SYM {}
+ | INDEX {}
+
+keys_or_index:
+ KEYS {}
+ | INDEX {}
+
+opt_unique:
+ /* empty */ { $$= Key::MULTIPLE; }
+ | UNIQUE_SYM { $$= Key::UNIQUE; }
+
+key_list:
+ key_list ',' key_part order_dir { Lex->col_list.push_back($3); }
+ | key_part order_dir { Lex->col_list.push_back($1); }
+
+key_part:
+ ident { $$=new key_part_spec($1.str); }
+ | ident '(' NUM ')' { $$=new key_part_spec($1.str,(uint) atoi($3.str)); }
+
+opt_ident:
+ /* empty */ { $$=(char*) 0; } /* Defaultlength */
+ | field_ident { $$=$1.str; }
+
+string_list:
+ text_string { Lex->interval_list.push_back($1); }
+ | string_list ',' text_string { Lex->interval_list.push_back($3); }
+
+/*
+** Alter table
+*/
+
+alter:
+ ALTER opt_ignore TABLE_SYM table_ident
+ {
+ LEX *lex=Lex;
+ lex->sql_command = SQLCOM_ALTER_TABLE;
+ lex->name=0;
+ if (!add_table_to_list($4, NULL))
+ YYABORT;
+ lex->drop_primary=0;
+ lex->create_list.empty();
+ lex->key_list.empty();
+ lex->col_list.empty();
+ lex->drop_list.empty();
+ lex->alter_list.empty();
+ lex->db=lex->name=0;
+ bzero((char*) &lex->create_info,sizeof(lex->create_info));
+ lex->create_info.db_type= DB_TYPE_DEFAULT;
+ }
+ alter_list opt_create_table_options
+
+alter_list:
+ alter_list_item
+ | alter_list ',' alter_list_item
+
+add_column:
+ 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
+ | MODIFY_SYM opt_column field_ident
+ {
+ Lex->length=Lex->dec=0; Lex->type=0; Lex->interval=0;
+ Lex->default_value=0;
+ }
+ type opt_attribute
+ {
+ 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))
+ YYABORT;
+ }
+ | 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 {}
+ | DROP key_or_index field_ident
+ { Lex->drop_list.push_back(new Alter_drop(Alter_drop::KEY,
+ $3.str)); }
+ | ALTER opt_column field_ident SET DEFAULT literal
+ { Lex->alter_list.push_back(new Alter_column($3.str,$6)); }
+ | ALTER opt_column field_ident DROP DEFAULT
+ { Lex->alter_list.push_back(new Alter_column($3.str,(Item*) 0)); }
+ | RENAME opt_to table_alias table_ident
+ { Lex->db=$4->db.str ; Lex->name= $4->table.str; }
+ | create_table_option
+
+opt_column:
+ /* empty */ {}
+ | COLUMN_SYM {}
+
+opt_ignore:
+ /* empty */ { Lex->duplicates=DUP_ERROR; }
+ | IGNORE_SYM { Lex->duplicates=DUP_IGNORE; }
+
+opt_restrict:
+ /* empty */ {}
+ | RESTRICT {}
+ | CASCADE {}
+
+opt_place:
+ /* empty */ {}
+ | AFTER_SYM ident { store_position_for_column($2.str); }
+ | FIRST_SYM { store_position_for_column(first_keyword); }
+
+opt_to:
+ /* empty */ {}
+ | TO_SYM {}
+
+slave:
+ SLAVE START_SYM
+ {
+ Lex->sql_command = SQLCOM_SLAVE_START;
+ Lex->type = 0;
+ }
+ |
+ SLAVE STOP_SYM
+ {
+ Lex->sql_command = SQLCOM_SLAVE_STOP;
+ Lex->type = 0;
+ };
+
+repair:
+ REPAIR table_or_tables
+ {
+ Lex->sql_command = SQLCOM_REPAIR;
+ Lex->check_opt.init();
+ }
+ table_list opt_mi_check_type
+
+
+opt_mi_check_type:
+ /* empty */ { Lex->check_opt.flags = T_MEDIUM; }
+ | TYPE_SYM EQ mi_check_types {}
+
+mi_check_types:
+ QUICK { Lex->check_opt.quick = 1; }
+ | EXTENDED_SYM { Lex->check_opt.flags = T_EXTEND; }
+
+analyze:
+ ANALYZE_SYM table_or_tables table_list
+ {
+ Lex->sql_command = SQLCOM_ANALYZE;
+ Lex->check_opt.init();
+ }
+
+check:
+ CHECK_SYM table_or_tables
+ {
+ Lex->sql_command = SQLCOM_CHECK;
+ Lex->check_opt.init();
+ }
+ table_list opt_mi_check_type
+
+optimize:
+ OPTIMIZE table_or_tables table_ident
+ {
+ Lex->sql_command = SQLCOM_OPTIMIZE;
+ if (!add_table_to_list($3, NULL))
+ YYABORT;
+ }
+
+/*
+** Select : retrieve data from table
+*/
+
+
+select:
+ SELECT_SYM
+ {
+ LEX *lex=Lex;
+ lex->where=lex->having=0;
+ lex->select_limit=current_thd->default_select_limit;
+ lex->offset_limit=0L;
+ lex->options=0;
+ lex->sql_command= SQLCOM_SELECT;
+ lex->exchange = 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_options select_item_list select_into
+
+select_into:
+ /* empty */
+ | select_from
+ | opt_into select_from
+ | select_from opt_into
+
+select_from:
+ FROM join_table_list where_clause group_clause having_clause order_clause limit_clause procedure_clause
+
+
+select_options:
+ /* empty*/
+ | select_option_list
+
+select_option_list:
+ select_option_list select_option
+ | select_option
+
+select_option:
+ STRAIGHT_JOIN { Lex->options|= SELECT_STRAIGHT_JOIN; }
+ | HIGH_PRIORITY { Lex->options|= SELECT_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; }
+ | ALL {}
+
+select_item_list:
+ select_item_list ',' select_item
+ | select_item
+ | '*'
+ {
+ if (add_item_to_list(new Item_field(NULL,NULL,"*")))
+ YYABORT;
+ }
+
+
+select_item:
+ remember_name select_item2 remember_end select_alias
+ {
+ if (add_item_to_list($2))
+ YYABORT;
+ if ($4.str)
+ $2->set_name($4.str);
+ else if (!$2->name)
+ $2->set_name($1,(uint) ($3 - $1));
+ }
+
+remember_name:
+ { $$=(char*) Lex->tok_start; }
+
+remember_end:
+ { $$=(char*) Lex->tok_end; }
+
+select_item2:
+ table_wild { $$=$1; } /* table.* */
+ | expr { $$=$1; }
+
+select_alias:
+ { $$.str=0;}
+ | AS ident { $$=$2; }
+ | AS TEXT_STRING { $$=$2; }
+ | ident { $$=$1; }
+ | TEXT_STRING { $$=$1; }
+
+optional_braces:
+ /* empty */ {}
+ | '(' ')' {}
+
+/* all possible expressions */
+expr: expr_expr {$$ = $1; }
+ | simple_expr {$$ = $1; }
+
+/* expressions that begin with 'expr' */
+expr_expr:
+ expr IN_SYM '(' expr_list ')'
+ { $$= new Item_func_in($1,*$4); }
+ | expr NOT IN_SYM '(' expr_list ')'
+ { $$= new Item_func_not(new Item_func_in($1,*$5)); }
+ | expr BETWEEN_SYM no_and_expr AND expr
+ { $$= new Item_func_between($1,$3,$5); }
+ | expr NOT BETWEEN_SYM no_and_expr AND expr
+ { $$= new Item_func_not(new Item_func_between($1,$4,$6)); }
+ | expr OR_OR_CONCAT expr { $$= or_or_concat($1,$3); }
+ | expr OR expr { $$= new Item_cond_or($1,$3); }
+ | expr AND expr { $$= new Item_cond_and($1,$3); }
+ | expr LIKE simple_expr opt_escape { $$= new Item_func_like($1,$3,$4); }
+ | expr NOT LIKE simple_expr opt_escape { $$= new Item_func_not(new Item_func_like($1,$4,$5));}
+ | expr REGEXP expr { $$= new Item_func_regex($1,$3); }
+ | expr NOT REGEXP expr { $$= new Item_func_not(new Item_func_regex($1,$4)); }
+ | expr IS NULL_SYM { $$= new Item_func_isnull($1); }
+ | expr IS NOT NULL_SYM { $$= new Item_func_isnotnull($1); }
+ | expr EQ expr { $$= new Item_func_eq($1,$3); }
+ | expr EQUAL_SYM expr { $$= new Item_func_equal($1,$3); }
+ | expr GE expr { $$= new Item_func_ge($1,$3); }
+ | expr GT_SYM expr { $$= new Item_func_gt($1,$3); }
+ | expr LE expr { $$= new Item_func_le($1,$3); }
+ | expr LT expr { $$= new Item_func_lt($1,$3); }
+ | expr NE expr { $$= new Item_func_ne($1,$3); }
+ | expr SHIFT_LEFT expr { $$= new Item_func_shift_left($1,$3); }
+ | expr SHIFT_RIGHT expr { $$= new Item_func_shift_right($1,$3); }
+ | expr '+' expr { $$= new Item_func_plus($1,$3); }
+ | expr '-' expr { $$= new Item_func_minus($1,$3); }
+ | expr '*' expr { $$= new Item_func_mul($1,$3); }
+ | expr '/' expr { $$= new Item_func_div($1,$3); }
+ | expr '|' expr { $$= new Item_func_bit_or($1,$3); }
+ | expr '&' expr { $$= new Item_func_bit_and($1,$3); }
+ | expr '%' expr { $$= new Item_func_mod($1,$3); }
+ | expr '+' INTERVAL_SYM expr interval
+ { $$= new Item_date_add_interval($1,$4,$5,0); }
+ | expr '-' INTERVAL_SYM expr interval
+ { $$= new Item_date_add_interval($1,$4,$5,1); }
+
+/* expressions that begin with 'expr' that do NOT follow IN_SYM */
+no_in_expr:
+ no_in_expr BETWEEN_SYM no_and_expr AND expr
+ { $$= new Item_func_between($1,$3,$5); }
+ | no_in_expr NOT BETWEEN_SYM no_and_expr AND expr
+ { $$= new Item_func_not(new Item_func_between($1,$4,$6)); }
+ | no_in_expr OR_OR_CONCAT expr { $$= or_or_concat($1,$3); }
+ | no_in_expr OR expr { $$= new Item_cond_or($1,$3); }
+ | no_in_expr AND expr { $$= new Item_cond_and($1,$3); }
+ | no_in_expr LIKE simple_expr opt_escape { $$= new Item_func_like($1,$3,$4); }
+ | no_in_expr NOT LIKE simple_expr opt_escape { $$= new Item_func_not(new Item_func_like($1,$4,$5)); }
+ | no_in_expr REGEXP expr { $$= new Item_func_regex($1,$3); }
+ | no_in_expr NOT REGEXP expr { $$= new Item_func_not(new Item_func_regex($1,$4)); }
+ | no_in_expr IS NULL_SYM { $$= new Item_func_isnull($1); }
+ | no_in_expr IS NOT NULL_SYM { $$= new Item_func_isnotnull($1); }
+ | no_in_expr EQ expr { $$= new Item_func_eq($1,$3); }
+ | no_in_expr EQUAL_SYM expr { $$= new Item_func_equal($1,$3); }
+ | no_in_expr GE expr { $$= new Item_func_ge($1,$3); }
+ | no_in_expr GT_SYM expr { $$= new Item_func_gt($1,$3); }
+ | no_in_expr LE expr { $$= new Item_func_le($1,$3); }
+ | no_in_expr LT expr { $$= new Item_func_lt($1,$3); }
+ | no_in_expr NE expr { $$= new Item_func_ne($1,$3); }
+ | no_in_expr SHIFT_LEFT expr { $$= new Item_func_shift_left($1,$3); }
+ | no_in_expr SHIFT_RIGHT expr { $$= new Item_func_shift_right($1,$3); }
+ | no_in_expr '+' expr { $$= new Item_func_plus($1,$3); }
+ | no_in_expr '-' expr { $$= new Item_func_minus($1,$3); }
+ | no_in_expr '*' expr { $$= new Item_func_mul($1,$3); }
+ | no_in_expr '/' expr { $$= new Item_func_div($1,$3); }
+ | no_in_expr '|' expr { $$= new Item_func_bit_or($1,$3); }
+ | no_in_expr '&' expr { $$= new Item_func_bit_and($1,$3); }
+ | no_in_expr '%' expr { $$= new Item_func_mod($1,$3); }
+ | no_in_expr '+' INTERVAL_SYM expr interval
+ { $$= new Item_date_add_interval($1,$4,$5,0); }
+ | no_in_expr '-' INTERVAL_SYM expr interval
+ { $$= new Item_date_add_interval($1,$4,$5,1); }
+ | simple_expr
+
+/* expressions that begin with 'expr' that does NOT follow AND */
+no_and_expr:
+ no_and_expr IN_SYM '(' expr_list ')'
+ { $$= new Item_func_in($1,*$4); }
+ | no_and_expr NOT IN_SYM '(' expr_list ')'
+ { $$= new Item_func_not(new Item_func_in($1,*$5)); }
+ | no_and_expr BETWEEN_SYM no_and_expr AND expr
+ { $$= new Item_func_between($1,$3,$5); }
+ | no_and_expr NOT BETWEEN_SYM no_and_expr AND expr
+ { $$= new Item_func_not(new Item_func_between($1,$4,$6)); }
+ | no_and_expr OR_OR_CONCAT expr { $$= or_or_concat($1,$3); }
+ | no_and_expr OR expr { $$= new Item_cond_or($1,$3); }
+ | no_and_expr LIKE simple_expr opt_escape { $$= new Item_func_like($1,$3,$4); }
+ | no_and_expr NOT LIKE simple_expr opt_escape { $$= new Item_func_not(new Item_func_like($1,$4,$5)); }
+ | no_and_expr REGEXP expr { $$= new Item_func_regex($1,$3); }
+ | no_and_expr NOT REGEXP expr { $$= new Item_func_not(new Item_func_regex($1,$4)); }
+ | no_and_expr IS NULL_SYM { $$= new Item_func_isnull($1); }
+ | no_and_expr IS NOT NULL_SYM { $$= new Item_func_isnotnull($1); }
+ | no_and_expr EQ expr { $$= new Item_func_eq($1,$3); }
+ | no_and_expr EQUAL_SYM expr { $$= new Item_func_equal($1,$3); }
+ | no_and_expr GE expr { $$= new Item_func_ge($1,$3); }
+ | no_and_expr GT_SYM expr { $$= new Item_func_gt($1,$3); }
+ | no_and_expr LE expr { $$= new Item_func_le($1,$3); }
+ | no_and_expr LT expr { $$= new Item_func_lt($1,$3); }
+ | no_and_expr NE expr { $$= new Item_func_ne($1,$3); }
+ | no_and_expr SHIFT_LEFT expr { $$= new Item_func_shift_left($1,$3); }
+ | no_and_expr SHIFT_RIGHT expr { $$= new Item_func_shift_right($1,$3); }
+ | no_and_expr '+' expr { $$= new Item_func_plus($1,$3); }
+ | no_and_expr '-' expr { $$= new Item_func_minus($1,$3); }
+ | no_and_expr '*' expr { $$= new Item_func_mul($1,$3); }
+ | no_and_expr '/' expr { $$= new Item_func_div($1,$3); }
+ | no_and_expr '|' expr { $$= new Item_func_bit_or($1,$3); }
+ | no_and_expr '&' expr { $$= new Item_func_bit_and($1,$3); }
+ | no_and_expr '%' expr { $$= new Item_func_mod($1,$3); }
+ | no_and_expr '+' INTERVAL_SYM expr interval
+ { $$= new Item_date_add_interval($1,$4,$5,0); }
+ | no_and_expr '-' INTERVAL_SYM expr interval
+ { $$= new Item_date_add_interval($1,$4,$5,1); }
+ | simple_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); }
+ | sum_expr
+ | '-' expr %prec NEG { $$= new Item_func_neg($2); }
+ | '~' expr %prec NEG { $$= new Item_func_bit_neg($2); }
+ | NOT expr %prec NEG { $$= new Item_func_not($2); }
+ | '!' 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))); }
+ | BINARY expr %prec NEG { $$= new Item_func_binary($2); }
+ | CASE_SYM opt_expr WHEN_SYM when_list opt_else END
+ { $$= new Item_func_case(* $4, $2, $5 ) }
+ | FUNC_ARG0 '(' ')'
+ { $$= ((Item*(*)(void))($1.symbol->create_func))();}
+ | FUNC_ARG1 '(' expr ')'
+ { $$= ((Item*(*)(Item*))($1.symbol->create_func))($3);}
+ | FUNC_ARG2 '(' expr ',' expr ')'
+ { $$= ((Item*(*)(Item*,Item*))($1.symbol->create_func))($3,$5);}
+ | FUNC_ARG3 '(' expr ',' expr ',' expr ')'
+ { $$= ((Item*(*)(Item*,Item*,Item*))($1.symbol->create_func))($3,$5,$7);}
+ | ATAN '(' expr ')'
+ { $$= new Item_func_atan($3); }
+ | ATAN '(' expr ',' expr ')'
+ { $$= new Item_func_atan($3,$5); }
+ | CHAR_SYM '(' expr_list ')'
+ { $$= new Item_func_char(*$3); }
+ | COALESCE '(' expr_list ')'
+ { $$= new Item_func_coalesce(* $3); }
+ | CONCAT '(' expr_list ')'
+ { $$= new Item_func_concat(* $3); }
+ | CONCAT_WS '(' expr ',' expr_list ')'
+ { $$= new Item_func_concat_ws($3, *$5); }
+ | CURDATE optional_braces
+ { $$= new Item_func_curdate(); }
+ | CURTIME optional_braces
+ { $$= new Item_func_curtime(); }
+ | CURTIME '(' expr ')'
+ { $$= new Item_func_curtime($3); }
+ | 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(); }
+ | 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 ',' 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); }
+ | EXPORT_SET '(' expr ',' expr ',' expr ')'
+ { $$= new Item_func_export_set($3, $5, $7); }
+ | EXPORT_SET '(' expr ',' expr ',' expr ',' expr ')'
+ { $$= new Item_func_export_set($3, $5, $7, $9); }
+ | EXPORT_SET '(' expr ',' expr ',' expr ',' expr ',' expr ')'
+ { $$= new Item_func_export_set($3, $5, $7, $9, $11); }
+ | FORMAT_SYM '(' expr ',' NUM ')'
+ { $$= new Item_func_format($3,atoi($5.str)); }
+ | FROM_UNIXTIME '(' expr ')'
+ { $$= new Item_func_from_unixtime($3); }
+ | FROM_UNIXTIME '(' expr ',' expr ')'
+ {
+ $$= new Item_func_date_format(new Item_func_from_unixtime($3),$5,0);
+ }
+ | FIELD_FUNC '(' expr ',' expr_list ')'
+ { $$= new Item_func_field($3, *$5); }
+ | HOUR_SYM '(' expr ')'
+ { $$= new Item_func_hour($3); }
+ | IF '(' expr ',' expr ',' expr ')'
+ { $$= new Item_func_if($3,$5,$7); }
+ | INSERT '(' expr ',' expr ',' expr ',' expr ')'
+ { $$= new Item_func_insert($3,$5,$7,$9); }
+ | INTERVAL_SYM expr interval '+' expr
+ /* we cannot put interval before - */
+ { $$= new Item_date_add_interval($5,$2,$3,0); }
+ | INTERVAL_SYM '(' expr ',' expr_list ')'
+ { $$= new Item_func_interval($3,* $5); }
+ | LAST_INSERT_ID '(' ')'
+ {
+ $$= new Item_int((char*) "last_insert_id()",
+ current_thd->insert_id(),21);
+ }
+ | LAST_INSERT_ID '(' expr ')'
+ {
+ $$= new Item_func_set_last_insert_id($3);
+ }
+ | LEFT '(' expr ',' expr ')'
+ { $$= new Item_func_left($3,$5); }
+ | LOCATE '(' expr ',' expr ')'
+ { $$= new Item_func_locate($5,$3); }
+ | LOCATE '(' expr ',' expr ',' expr ')'
+ { $$= new Item_func_locate($5,$3,$7); }
+ | GREATEST_SYM '(' expr ',' expr_list ')'
+ { $5->push_front($3); $$= new Item_func_max(*$5); }
+ | LEAST_SYM '(' expr ',' expr_list ')'
+ { $5->push_front($3); $$= new Item_func_min(*$5); }
+ | MINUTE_SYM '(' expr ')'
+ { $$= new Item_func_minute($3); }
+ | MONTH_SYM '(' expr ')'
+ { $$= new Item_func_month($3); }
+ | NOW_SYM optional_braces
+ { $$= new Item_func_now(); }
+ | NOW_SYM '(' expr ')'
+ { $$= new Item_func_now($3); }
+ | 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(); }
+ | REPLACE '(' expr ',' expr ',' expr ')'
+ { $$= new Item_func_replace($3,$5,$7); }
+ | RIGHT '(' expr ',' expr ')'
+ { $$= new Item_func_right($3,$5); }
+ | ROUND '(' expr ')'
+ { $$= new Item_func_round($3, new Item_int((char*)"0",0,1),0); }
+ | ROUND '(' expr ',' expr ')' { $$= new Item_func_round($3,$5,0); }
+ | SECOND_SYM '(' expr ')'
+ { $$= new Item_func_second($3); }
+ | SUBSTRING '(' expr ',' expr ',' expr ')'
+ { $$= new Item_func_substr($3,$5,$7); }
+ | SUBSTRING '(' expr ',' expr ')'
+ { $$= new Item_func_substr($3,$5); }
+ | SUBSTRING '(' expr FROM expr FOR_SYM expr ')'
+ { $$= new Item_func_substr($3,$5,$7); }
+ | SUBSTRING '(' expr FROM expr ')'
+ { $$= new Item_func_substr($3,$5); }
+ | SUBSTRING_INDEX '(' expr ',' expr ',' expr ')'
+ { $$= new Item_func_substr_index($3,$5,$7); }
+ | TRIM '(' expr ')'
+ { $$= new Item_func_trim($3,new Item_string(" ",1)); }
+ | TRIM '(' LEADING opt_pad FROM expr ')'
+ { $$= new Item_func_ltrim($6,$4); }
+ | TRIM '(' TRAILING opt_pad FROM expr ')'
+ { $$= new Item_func_rtrim($6,$4); }
+ | TRIM '(' BOTH opt_pad FROM expr ')'
+ { $$= new Item_func_trim($6,$4); }
+ | TRIM '(' expr FROM expr ')'
+ { $$= new Item_func_trim($5,$3); }
+
+ | UDA_CHAR_SUM '(' udf_expr_list ')'
+ {
+ if ($3 != NULL)
+ $$ = new Item_sum_udf_str($1, *$3);
+ else
+ $$ = new Item_sum_udf_str($1);
+ }
+ | UDA_FLOAT_SUM '(' udf_expr_list ')'
+ {
+ if ($3 != NULL)
+ $$ = new Item_sum_udf_float($1, *$3);
+ else
+ $$ = new Item_sum_udf_float($1);
+ }
+ | UDA_INT_SUM '(' udf_expr_list ')'
+ {
+ if ($3 != NULL)
+ $$ = new Item_sum_udf_int($1, *$3);
+ else
+ $$ = new Item_sum_udf_int($1);
+ }
+ | UDF_CHAR_FUNC '(' udf_expr_list ')'
+ {
+ if ($3 != NULL)
+ $$ = new Item_func_udf_str($1, *$3);
+ else
+ $$ = new Item_func_udf_str($1);
+ }
+ | UDF_FLOAT_FUNC '(' udf_expr_list ')'
+ {
+ if ($3 != NULL)
+ $$ = new Item_func_udf_float($1, *$3);
+ else
+ $$ = new Item_func_udf_float($1);
+ }
+ | UDF_INT_FUNC '(' udf_expr_list ')'
+ {
+ if ($3 != NULL)
+ $$ = new Item_func_udf_int($1, *$3);
+ else
+ $$ = new Item_func_udf_int($1);
+ }
+ | UNIQUE_USERS '(' text_literal ',' NUM ',' NUM ',' expr_list ')'
+ { $$= new Item_func_unique_users($3,atoi($5.str),atoi($7.str), * $9); }
+ | UNIX_TIMESTAMP '(' ')'
+ { $$= new Item_func_unix_timestamp(); }
+ | UNIX_TIMESTAMP '(' expr ')'
+ { $$= new Item_func_unix_timestamp($3); }
+ | USER '(' ')'
+ { $$= new Item_func_user(); }
+ | WEEK_SYM '(' expr ')'
+ { $$= new Item_func_week($3,new Item_int((char*) "0",0,1)); }
+ | WEEK_SYM '(' expr ',' expr ')'
+ { $$= new Item_func_week($3,$5); }
+ | YEAR_SYM '(' expr ')'
+ { $$= new Item_func_year($3); }
+ | YEARWEEK '(' expr ')'
+ { $$= new Item_func_yearweek($3,new Item_int((char*) "0",0,1)); }
+ | YEARWEEK '(' expr ',' expr ')'
+ { $$= new Item_func_yearweek($3, $5); }
+ | BENCHMARK_SYM '(' ULONG_NUM ',' expr ')'
+ { $$=new Item_func_benchmark($3,$5); }
+ | EXTRACT_SYM '(' interval FROM expr ')'
+ { $$=new Item_extract( $3, $5); }
+
+udf_expr_list:
+ /* empty */ { $$= NULL; }
+ | expr_list { $$= $1;}
+
+sum_expr:
+ AVG_SYM '(' in_sum_expr ')'
+ { $$=new Item_sum_avg($3); }
+ | BIT_AND '(' in_sum_expr ')'
+ { $$=new Item_sum_and($3); }
+ | BIT_OR '(' in_sum_expr ')'
+ { $$=new Item_sum_or($3); }
+ | COUNT_SYM '(' '*' ')'
+ { $$=new Item_sum_count(new Item_int((int32) 0L,1)); }
+ | COUNT_SYM '(' in_sum_expr ')'
+ { $$=new Item_sum_count($3); }
+ | COUNT_SYM '(' DISTINCT expr_list ')'
+ { $$=new Item_sum_count_distinct(* $4); }
+ | GROUP_UNIQUE_USERS '(' text_literal ',' NUM ',' NUM ',' in_sum_expr ')'
+ { $$= new Item_sum_unique_users($3,atoi($5.str),atoi($7.str),$9); }
+ | MIN_SYM '(' in_sum_expr ')'
+ { $$=new Item_sum_min($3); }
+ | MAX_SYM '(' in_sum_expr ')'
+ { $$=new Item_sum_max($3); }
+ | STD_SYM '(' in_sum_expr ')'
+ { $$=new Item_sum_std($3); }
+ | SUM_SYM '(' in_sum_expr ')'
+ { $$=new Item_sum_sum($3); }
+
+in_sum_expr:
+ { Lex->in_sum_expr++ }
+ expr
+ {
+ Lex->in_sum_expr--;
+ $$=$2;
+ }
+
+expr_list:
+ { Lex->expr_list.push_front(new List<Item>); }
+ expr_list2
+ { $$= Lex->expr_list.pop(); }
+
+expr_list2:
+ expr { Lex->expr_list.head()->push_back($1); }
+ | expr_list2 ',' expr { Lex->expr_list.head()->push_back($3); }
+
+ident_list:
+ { Lex->expr_list.push_front(new List<Item>); }
+ ident_list2
+ { $$= Lex->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); }
+
+opt_expr:
+ /* empty */ { $$= NULL; }
+ | expr { $$= $1; }
+
+opt_else:
+ /* empty */ { $$= NULL; }
+ | ELSE expr { $$= $2; }
+
+when_list:
+ { Lex->when_list.push_front(new List<Item>) }
+ when_list2
+ { $$= Lex->when_list.pop(); }
+
+when_list2:
+ expr THEN_SYM expr
+ {
+ Lex->when_list.head()->push_back($1);
+ Lex->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);
+ }
+
+opt_pad:
+ /* empty */ { $$=new Item_string(" ",1); }
+ | expr { $$=$1; }
+
+join_table_list:
+ '(' join_table_list ')' { $$=$2; }
+ | join_table { $$=$1; }
+ | 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; }
+ 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=1; $$=$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; }
+ USING '(' using_list ')'
+ { add_join_on($5,$9); $5->outer_join=1; $$=$5; }
+ | join_table_list NATURAL LEFT opt_outer JOIN_SYM join_table
+ { add_join_natural($1,$6); $6->outer_join=1; $$=$6; }
+ | join_table_list NATURAL JOIN_SYM join_table
+ { add_join_natural($1,$4); $$=$4; }
+
+normal_join:
+ ',' {}
+ | JOIN_SYM {}
+ | CROSS JOIN_SYM {}
+
+join_table:
+ { Lex->use_index_ptr=Lex->ignore_index_ptr=0; }
+ table_ident opt_table_alias opt_key_definition
+ { if (!($$=add_table_to_list($2,$3,TL_UNLOCK, Lex->use_index_ptr,
+ Lex->ignore_index_ptr))) YYABORT; }
+ | '{' ident join_table LEFT OUTER JOIN_SYM join_table ON expr '}'
+ { add_join_on($7,$9); $7->outer_join=1; $$=$7; }
+
+opt_outer:
+ /* empty */ {}
+ | OUTER {}
+
+opt_key_definition:
+ /* empty */ {}
+ | USE_SYM key_usage_list
+ { Lex->use_index= *$2; Lex->use_index_ptr= &Lex->use_index; }
+ | IGNORE_SYM key_usage_list
+ { Lex->ignore_index= *$2; Lex->ignore_index_ptr= &Lex->ignore_index;}
+
+key_usage_list:
+ key_or_index { Lex->interval_list.empty() } '(' key_usage_list2 ')'
+ { $$= &Lex->interval_list; }
+
+key_usage_list2:
+ key_usage_list2 ',' ident
+ { Lex->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)); }
+ | PRIMARY_SYM
+ { Lex->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))))
+ 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)))
+ YYABORT;
+ }
+
+interval:
+ DAY_HOUR_SYM { $$=INTERVAL_DAY_HOUR; }
+ | DAY_MINUTE_SYM { $$=INTERVAL_DAY_MINUTE; }
+ | DAY_SECOND_SYM { $$=INTERVAL_DAY_SECOND; }
+ | DAY_SYM { $$=INTERVAL_DAY; }
+ | HOUR_MINUTE_SYM { $$=INTERVAL_HOUR_MINUTE; }
+ | HOUR_SECOND_SYM { $$=INTERVAL_HOUR_SECOND; }
+ | HOUR_SYM { $$=INTERVAL_HOUR; }
+ | MINUTE_SECOND_SYM { $$=INTERVAL_MINUTE_SECOND; }
+ | MINUTE_SYM { $$=INTERVAL_MINUTE; }
+ | MONTH_SYM { $$=INTERVAL_MONTH; }
+ | SECOND_SYM { $$=INTERVAL_SECOND; }
+ | YEAR_MONTH_SYM { $$=INTERVAL_YEAR_MONTH; }
+ | YEAR_SYM { $$=INTERVAL_YEAR; }
+
+table_alias:
+ /* empty */
+ | AS
+ | EQ
+
+opt_table_alias:
+ /* empty */ { $$=0; }
+ | table_alias ident
+ { $$= (LEX_STRING*) sql_memdup(&$2,sizeof(LEX_STRING)); }
+
+
+where_clause:
+ /* empty */ { Lex->where= 0; }
+ | WHERE expr { Lex->where= $2; }
+
+having_clause:
+ /* empty */
+ | HAVING { Lex->create_refs=1; } expr
+ { Lex->having= $3; Lex->create_refs=0; }
+
+opt_escape:
+ ESCAPE_SYM TEXT_STRING { $$= $2.str; }
+ | /* empty */ { $$= (char*) "\\"; }
+
+
+/*
+** group by statement in select
+*/
+
+group_clause:
+ /* empty */
+ | GROUP BY group_list
+
+group_list:
+ group_list ',' group_ident
+ { if (add_group_to_list($3,(bool) 1)) YYABORT; }
+ | group_ident order_dir
+ { if (add_group_to_list($1,(bool) 1)) YYABORT; }
+
+/*
+** Order by statement in select
+*/
+
+order_clause:
+ /* empty */
+ | ORDER_SYM BY { Lex->sort_default=1; } order_list
+
+order_list:
+ order_list ',' order_ident order_dir
+ { if (add_order_to_list($3,(bool) $4)) YYABORT; }
+ | order_ident order_dir
+ { if (add_order_to_list($1,(bool) $2)) YYABORT; }
+
+order_dir:
+ /* empty */ { $$ = 1; }
+ | ASC { $$ = Lex->sort_default=1; }
+ | DESC { $$ = Lex->sort_default=0; }
+
+
+limit_clause:
+ /* empty */
+ {
+ Lex->select_limit= current_thd->default_select_limit;
+ Lex->offset_limit= 0L;
+ }
+ | LIMIT ULONG_NUM
+ { Lex->select_limit= $2; Lex->offset_limit=0L; }
+ | LIMIT ULONG_NUM ',' ULONG_NUM
+ { Lex->select_limit= $4; Lex->offset_limit=$2; }
+
+delete_limit_clause:
+ /* empty */
+ {
+ Lex->select_limit= HA_POS_ERROR;
+ }
+ | LIMIT ULONGLONG_NUM
+ { Lex->select_limit= (ha_rows) $2; }
+
+ULONG_NUM:
+ NUM { $$= strtoul($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); }
+ | FLOAT_NUM { $$= strtoull($1.str,NULL,10); }
+
+procedure_clause:
+ /* empty */
+ | PROCEDURE ident /* Procedure name */
+ {
+ LEX *lex=Lex;
+ lex->proc_list.elements=0;
+ lex->proc_list.first=0;
+ lex->proc_list.next= (byte**) &lex->proc_list.first;
+ if (add_proc_to_list(new Item_field(NULL,NULL,$2.str)))
+ YYABORT;
+ }
+ '(' procedure_list ')'
+
+
+procedure_list:
+ /* empty */ {}
+ | procedure_list2 {}
+
+procedure_list2:
+ procedure_list2 ',' procedure_item
+ | procedure_item
+
+procedure_item:
+ remember_name expr
+ {
+ if (add_proc_to_list($2))
+ YYABORT;
+ if (!$2->name)
+ $2->set_name($1,(uint) ((char*) Lex->tok_end - $1));
+ }
+
+opt_into:
+ INTO OUTFILE TEXT_STRING
+ {
+ if (!(Lex->exchange= new sql_exchange($3.str,0)))
+ YYABORT;
+ }
+ opt_field_term opt_line_term
+ | INTO DUMPFILE TEXT_STRING
+ {
+ if (!(Lex->exchange= new sql_exchange($3.str,1)))
+ YYABORT;
+ }
+
+
+/*
+** Drop : delete tables or index
+*/
+
+drop:
+ DROP TABLE_SYM if_exists table_list
+ {
+ 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,
+ $3.str));
+ if (!add_table_to_list($5,NULL))
+ YYABORT;
+ }
+ | DROP DATABASE if_exists ident
+ {
+ 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;
+ }
+
+
+table_list:
+ table
+ | table_list ',' table
+
+table:
+ table_ident
+ { if (!add_table_to_list($1,NULL)) YYABORT; }
+
+if_exists:
+ /* empty */ { $$=0; }
+ | IF EXISTS { $$= 1; }
+
+/*
+** Insert : add new data to table
+*/
+
+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
+
+insert_lock_option:
+ /* empty */ { Lex->lock_option= TL_WRITE_CONCURRENT_INSERT; }
+ | LOW_PRIORITY { Lex->lock_option= TL_WRITE_LOW_PRIORITY; }
+ | DELAYED_SYM { Lex->lock_option= TL_WRITE_DELAYED; }
+ | HIGH_PRIORITY { Lex->lock_option= TL_WRITE; }
+
+replace_lock_option:
+ opt_low_priority {}
+ | DELAYED_SYM { Lex->lock_option= TL_WRITE_DELAYED; }
+
+insert2:
+ INTO insert_table {}
+ | insert_table {}
+
+insert_table:
+ table
+ {
+ 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))
+ YYABORT;
+ }
+ ident_eq_list
+
+opt_field_spec:
+ /* empty */ { }
+ | '(' fields ')' { }
+ | '(' ')' { }
+
+fields:
+ fields ',' insert_ident { Lex->field_list.push_back($3); }
+ | insert_ident { Lex->field_list.push_back($1); }
+
+insert_values:
+ VALUES values_list {}
+ | SELECT_SYM
+ {
+ LEX *lex=Lex;
+ lex->where=lex->having=0;
+ lex->select_limit=current_thd->default_select_limit;
+ lex->offset_limit=0L;
+ lex->options=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;
+ lex->sql_command = (lex->sql_command == SQLCOM_INSERT ?
+ SQLCOM_INSERT_SELECT : SQLCOM_REPLACE_SELECT);
+ }
+ select_options select_item_list select_from {}
+
+values_list:
+ values_list ',' no_braces
+ | no_braces
+
+ident_eq_list:
+ ident_eq_list ',' ident_eq_value
+ |
+ ident_eq_value
+
+ident_eq_value:
+ simple_ident equal expr
+ {
+ if (Lex->field_list.push_back($1) ||
+ Lex->insert_list->push_back($3))
+ YYABORT;
+ }
+
+equal: EQ {}
+ | SET_VAR {}
+
+no_braces:
+ '('
+ {
+ if (!(Lex->insert_list = new List_item))
+ YYABORT;
+ }
+ opt_values ')'
+ {
+ if (Lex->many_values.push_back(Lex->insert_list))
+ YYABORT;
+ }
+
+opt_values:
+ /* empty */ {}
+ | values
+
+values:
+ values ',' expr
+ {
+ if (Lex->insert_list->push_back($3))
+ YYABORT;
+ }
+ | expr
+ {
+ if (Lex->insert_list->push_back($1))
+ YYABORT;
+ }
+
+/* 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_list:
+ update_list ',' simple_ident equal expr
+ {
+ if (add_item_to_list($3) || add_value_to_list($5))
+ YYABORT;
+ }
+ | simple_ident equal expr
+ {
+ if (add_item_to_list($1) || add_value_to_list($3))
+ YYABORT;
+ }
+
+opt_low_priority:
+ /* empty */ { Lex->lock_option= current_thd->update_lock_default; }
+ | LOW_PRIORITY { Lex->lock_option= TL_WRITE_LOW_PRIORITY; }
+
+/* Delete rows from a table */
+
+delete:
+ DELETE_SYM opt_low_priority FROM table where_clause delete_limit_clause
+ { Lex->sql_command= SQLCOM_DELETE; }
+
+
+/* Show things */
+
+show: SHOW { Lex->wild=0;} show_param
+
+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;}
+ | TABLE_SYM STATUS_SYM opt_db wild
+ { Lex->sql_command= SQLCOM_SHOW_TABLES;
+ Lex->options|= SELECT_DESCRIBE;
+ Lex->db= $3;
+ }
+ | COLUMNS FROM table_ident opt_db wild
+ {
+ Lex->sql_command= SQLCOM_SHOW_FIELDS;
+ if ($4)
+ $3->change_db($4);
+ if (!add_table_to_list($3,NULL))
+ YYABORT;
+ }
+ | keys_or_index FROM table_ident opt_db
+ {
+ Lex->sql_command= SQLCOM_SHOW_KEYS;
+ if ($4)
+ $3->change_db($4);
+ if (!add_table_to_list($3,NULL))
+ YYABORT;
+ }
+ | STATUS_SYM wild
+ { Lex->sql_command= SQLCOM_SHOW_STATUS; }
+ | PROCESSLIST_SYM
+ { Lex->sql_command= SQLCOM_SHOW_PROCESSLIST; Lex->verbose=0; }
+ | FULL PROCESSLIST_SYM
+ { Lex->sql_command= SQLCOM_SHOW_PROCESSLIST; Lex->verbose=1; }
+ | VARIABLES wild
+ { Lex->sql_command= SQLCOM_SHOW_VARIABLES; }
+ | GRANTS FOR_SYM user
+ { 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;
+ if(!add_table_to_list($3, NULL))
+ YYABORT;
+ }
+ | MASTER_SYM STATUS_SYM
+ {
+ Lex->sql_command = SQLCOM_SHOW_MASTER_STAT;
+ }
+ | SLAVE STATUS_SYM
+ {
+ Lex->sql_command = SQLCOM_SHOW_SLAVE_STAT;
+ }
+
+opt_db:
+ /* empty */ { $$= 0; }
+ | FROM ident { $$= $2.str; }
+
+wild:
+ /* empty */
+ | LIKE text_string { Lex->wild= $2; }
+
+/* A Oracle compatible synonym for show */
+describe:
+ describe_command table_ident
+ {
+ Lex->wild=0;
+ Lex->sql_command=SQLCOM_SHOW_FIELDS;
+ if (!add_table_to_list($2, NULL))
+ YYABORT;
+ }
+ opt_describe_column
+ | describe_command select { Lex->options|= SELECT_DESCRIBE };
+
+
+describe_command:
+ DESC
+ | DESCRIBE
+
+opt_describe_column:
+ /* empty */ {}
+ | text_string { Lex->wild= $1; }
+ | ident { Lex->wild= new String((const char*) $1.str,$1.length); }
+
+
+/* flush things */
+
+flush:
+ FLUSH_SYM {Lex->sql_command= SQLCOM_FLUSH; Lex->type=0; } flush_options
+
+flush_options:
+ flush_options ',' flush_option
+ | flush_option
+
+flush_option:
+ TABLES { Lex->type|= REFRESH_TABLES; }
+ | TABLES WITH READ_SYM LOCK_SYM { Lex->type|= REFRESH_TABLES | REFRESH_READ_LOCK; }
+ | 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; }
+
+/* kill threads */
+
+kill:
+ KILL_SYM NUM
+ {
+ Lex->sql_command=SQLCOM_KILL;
+ Lex->thread_id= (ulong) strtoul($2.str,NULL,10);
+ }
+
+/* change database */
+
+use: USE_SYM ident
+ { Lex->sql_command=SQLCOM_CHANGE_DB; Lex->db= $2.str; }
+
+/* import, export of files */
+
+load: LOAD DATA_SYM opt_low_priority opt_local INFILE TEXT_STRING
+ {
+ Lex->sql_command= SQLCOM_LOAD;
+ Lex->local_file= $4;
+ if (!(Lex->exchange= new sql_exchange($6.str,0)))
+ YYABORT;
+ Lex->field_list.empty();
+ }
+ opt_duplicate INTO TABLE_SYM table_ident opt_field_term opt_line_term
+ opt_ignore_lines opt_field_spec
+ {
+ if (!add_table_to_list($11,NULL))
+ YYABORT;
+ }
+ |
+ LOAD TABLE_SYM table_ident FROM MASTER_SYM
+ {
+ Lex->sql_command = SQLCOM_LOAD_MASTER_TABLE;
+ if (!add_table_to_list($3,NULL))
+ YYABORT;
+
+ }
+
+opt_local:
+ /* empty */ { $$=0;}
+ | LOCAL_SYM { $$=1;}
+
+opt_duplicate:
+ /* empty */ { Lex->duplicates=DUP_ERROR; }
+ | REPLACE { Lex->duplicates=DUP_REPLACE; }
+ | IGNORE_SYM { Lex->duplicates=DUP_IGNORE; }
+
+opt_field_term:
+ /* empty */
+ | COLUMNS field_term_list
+
+field_term_list:
+ field_term_list field_term
+ | field_term
+
+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;}
+ | ENCLOSED BY text_string { Lex->exchange->enclosed= $3;}
+ | ESCAPED BY text_string { Lex->exchange->escaped= $3;}
+
+opt_line_term:
+ /* empty */
+ | LINES line_term_list
+
+line_term_list:
+ line_term_list line_term
+ | line_term
+
+line_term:
+ TERMINATED BY text_string { Lex->exchange->line_term= $3;}
+ | STARTING BY text_string { Lex->exchange->line_start= $3;}
+
+opt_ignore_lines:
+ /* empty */
+ | IGNORE_SYM NUM LINES
+ { Lex->exchange->skip_lines=atol($2.str); }
+
+/* Common definitions */
+
+text_literal:
+ TEXT_STRING { $$ = new Item_string($1.str,$1.length); }
+ | text_literal TEXT_STRING
+ { ((Item_string*) $1)->append($2.str,$2.length); }
+
+text_string:
+ TEXT_STRING { $$= new String($1.str,$1.length); }
+ | HEX_NUM
+ {
+ Item *tmp = new Item_varbinary($1.str,$1.length);
+ $$= tmp ? tmp->val_str((String*) 0) : (String*) 0;
+ }
+
+literal:
+ text_literal { $$ = $1; }
+ | NUM { $$ = new Item_int($1.str, (longlong) atol($1.str),$1.length); }
+ | LONG_NUM { $$ = new Item_int($1.str); }
+ | 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)};
+ | DATE_SYM text_literal { $$ = $2; }
+ | TIME_SYM text_literal { $$ = $2; }
+ | TIMESTAMP text_literal { $$ = $2; }
+
+/**********************************************************************
+** Createing different items.
+**********************************************************************/
+
+insert_ident:
+ simple_ident { $$=$1; }
+ | table_wild { $$=$1; }
+
+table_wild:
+ ident '.' '*' { $$ = new Item_field(NullS,$1.str,"*"); }
+ | ident '.' ident '.' '*'
+ { $$ = new Item_field((current_thd->client_capabilities & CLIENT_NO_SCHEMA ? NullS : $1.str),$3.str,"*"); }
+
+group_ident:
+ order_ident
+
+order_ident:
+ expr { $$=$1; }
+
+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); }
+ | 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); }
+ | '.' 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); }
+ | 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); }
+
+
+field_ident:
+ ident { $$=$1;}
+ | ident '.' ident { $$=$3;} /* Skipp schema name in create*/
+ | '.' ident { $$=$2;} /* For Delphi */
+
+table_ident:
+ ident { $$=new Table_ident($1); }
+ | ident '.' ident { $$=new Table_ident($1,$3,0);}
+ | '.' ident { $$=new Table_ident($2);} /* For Delphi */
+
+ident:
+ IDENT { $$=$1; }
+ | keyword
+ {
+ $$.str=sql_strmake($1.str,$1.length);
+ $$.length=$1.length;
+ if (Lex->next_state != STATE_END)
+ Lex->next_state=STATE_OPERATOR_OR_IDENT;
+ }
+
+ident_or_text:
+ ident { $$=$1;}
+ | TEXT_STRING { $$=$1;}
+ | LEX_HOSTNAME { $$=$1;}
+
+user:
+ ident_or_text
+ {
+ if (!($$=(LEX_USER*) sql_alloc(sizeof(st_lex_user))))
+ YYABORT;
+ $$->user = $1; $$->host.str=NullS;
+ }
+ | ident_or_text '@' ident_or_text
+ {
+ if (!($$=(LEX_USER*) sql_alloc(sizeof(st_lex_user))))
+ YYABORT;
+ $$->user = $1; $$->host=$3;
+ }
+
+/* Keyword that we allow for identifiers */
+
+keyword:
+ ACTION {}
+ | AFTER_SYM {}
+ | AGGREGATE_SYM {}
+ | AUTOCOMMIT {}
+ | AVG_ROW_LENGTH {}
+ | AVG_SYM {}
+ | BEGIN_SYM {}
+ | BIT_SYM {}
+ | BOOL_SYM {}
+ | CHECKSUM_SYM {}
+ | CHECK_SYM {}
+ | COMMENT_SYM {}
+ | COMMIT_SYM {}
+ | COMPRESSED_SYM {}
+ | DATA_SYM {}
+ | DATETIME {}
+ | DATE_SYM {}
+ | DAY_SYM {}
+ | DELAY_KEY_WRITE_SYM {}
+ | DUMPFILE {}
+ | DYNAMIC_SYM {}
+ | END {}
+ | ENUM {}
+ | ESCAPE_SYM {}
+ | EXTENDED_SYM {}
+ | FILE_SYM {}
+ | FIRST_SYM {}
+ | FIXED_SYM {}
+ | FLUSH_SYM {}
+ | GRANTS {}
+ | HEAP_SYM {}
+ | HOSTS_SYM {}
+ | HOUR_SYM {}
+ | IDENTIFIED_SYM {}
+ | ISAM_SYM {}
+ | LOCAL_SYM {}
+ | LOGS_SYM {}
+ | MAX_ROWS {}
+ | MAX_SYM {}
+ | MASTER_SYM {}
+ | MASTER_HOST_SYM {}
+ | MASTER_PORT_SYM {}
+ | MASTER_LOG_FILE_SYM {}
+ | MASTER_LOG_POS_SYM {}
+ | MASTER_USER_SYM {}
+ | MASTER_PASSWORD_SYM {}
+ | MASTER_CONNECT_RETRY_SYM {}
+ | MERGE_SYM {}
+ | MINUTE_SYM {}
+ | MIN_ROWS {}
+ | MODIFY_SYM {}
+ | MONTH_SYM {}
+ | MYISAM_SYM {}
+ | NATIONAL_SYM {}
+ | NCHAR_SYM {}
+ | NO_SYM {}
+ | PACK_KEYS_SYM {}
+ | PASSWORD {}
+ | PROCESS {}
+ | PROCESSLIST_SYM {}
+ | RAID_0_SYM {}
+ | RAID_CHUNKS {}
+ | RAID_CHUNKSIZE {}
+ | RAID_STRIPED_SYM {}
+ | RAID_TYPE {}
+ | RELOAD {}
+ | REPAIR {}
+ | ROLLBACK_SYM {}
+ | ROWS_SYM {}
+ | ROW_FORMAT_SYM {}
+ | ROW_SYM {}
+ | SECOND_SYM {}
+ | SHUTDOWN {}
+ | START_SYM {}
+ | STATUS_SYM {}
+ | STOP_SYM {}
+ | STRING_SYM {}
+ | TEMPORARY {}
+ | TEXT_SYM {}
+ | TIMESTAMP {}
+ | TIME_SYM {}
+ | TYPE_SYM {}
+ | UDF_SYM {}
+ | VARIABLES {}
+ | WORK_SYM {}
+ | YEAR_SYM {}
+ | SLAVE {}
+ | COLLECTION {}
+
+/* Option functions */
+
+set:
+ SET opt_option
+ {
+ Lex->sql_command= SQLCOM_SET_OPTION;
+ Lex->options=current_thd->options;
+ Lex->select_limit=current_thd->default_select_limit;
+ }
+ option_value_list
+
+opt_option:
+ /* empty */ {}
+ | OPTION {}
+
+option_value_list:
+ option_value
+ | option_value_list ',' option_value
+
+option_value:
+ set_option equal NUM
+ {
+ if (atoi($3.str) == 0)
+ Lex->options&= ~$1;
+ else
+ Lex->options|= $1;
+ }
+ | SQL_SELECT_LIMIT equal ULONG_NUM
+ {
+ Lex->select_limit= $3;
+ }
+ | SQL_SELECT_LIMIT equal DEFAULT
+ {
+ Lex->select_limit= HA_POS_ERROR;
+ }
+ | SQL_MAX_JOIN_SIZE equal ULONG_NUM
+ {
+ current_thd->max_join_size= $3;
+ Lex->options&= ~OPTION_BIG_SELECTS;
+ }
+ | SQL_MAX_JOIN_SIZE equal DEFAULT
+ {
+ current_thd->max_join_size= HA_POS_ERROR;
+ }
+ | TIMESTAMP equal ULONG_NUM
+ {
+ current_thd->set_time((time_t) $3);
+ }
+ | TIMESTAMP equal DEFAULT
+ {
+ current_thd->user_time=0;
+ }
+ | LAST_INSERT_ID equal ULONGLONG_NUM
+ {
+ current_thd->insert_id($3);
+ }
+ | INSERT_ID equal ULONGLONG_NUM
+ {
+ current_thd->next_insert_id=$3;
+ }
+ | CHAR_SYM SET IDENT
+ {
+ CONVERT *tmp;
+ if (!(tmp=get_convert_set($3.str)))
+ {
+ net_printf(&current_thd->net,ER_UNKNOWN_CHARACTER_SET,$3);
+ YYABORT;
+ }
+ current_thd->convert_set=tmp;
+ }
+ | CHAR_SYM SET DEFAULT
+ {
+ current_thd->convert_set=0;
+ }
+ | PASSWORD equal text_or_password
+ {
+ if (change_password(current_thd,current_thd->host,
+ current_thd->priv_user,$3))
+ YYABORT;
+ }
+ | PASSWORD FOR_SYM user equal text_or_password
+ {
+ if (change_password(current_thd,
+ $3->host.str ? $3->host.str : current_thd->host,
+ $3->user.str,$5))
+ YYABORT;
+ }
+ | '@' ident_or_text equal expr
+ {
+ Item_func_set_user_var *item = new Item_func_set_user_var($2,$4);
+ if (item->fix_fields(current_thd,0) || item->update())
+ YYABORT;
+ }
+
+text_or_password:
+ TEXT_STRING { $$=$1.str;}
+ | PASSWORD '(' TEXT_STRING ')'
+ {
+ if (!$3.length)
+ $$=$3.str;
+ else
+ {
+ char *buff=(char*) sql_alloc(HASH_PASSWORD_LENGTH+1);
+ make_scrambled_password(buff,$3.str);
+ $$=buff;
+ }
+ }
+
+set_option:
+ SQL_BIG_TABLES { $$= OPTION_BIG_TABLES; }
+ | AUTOCOMMIT { $$= OPTION_AUTO_COMMIT; }
+ | SQL_BIG_SELECTS { $$= OPTION_BIG_SELECTS; }
+ | SQL_LOG_OFF { $$= OPTION_LOG_OFF; }
+ | SQL_LOG_UPDATE
+ {
+ $$= (opt_sql_bin_update)? OPTION_UPDATE_LOG|OPTION_BIN_LOG: OPTION_UPDATE_LOG ;
+ }
+ | SQL_LOG_BIN
+ {
+ $$= (opt_sql_bin_update)? OPTION_UPDATE_LOG|OPTION_BIN_LOG: OPTION_BIN_LOG ;
+ }
+ | SQL_WARNINGS { $$= OPTION_WARNINGS; }
+ | SQL_LOW_PRIORITY_UPDATES { $$= OPTION_LOW_PRIORITY_UPDATES; }
+ | SQL_AUTO_IS_NULL { $$= OPTION_AUTO_IS_NULL; }
+ | SQL_SAFE_UPDATES { $$= OPTION_SAFE_UPDATES; }
+ | SQL_BUFFER_RESULT { $$= OPTION_BUFFER_RESULT; }
+
+/* Lock function */
+
+lock:
+ LOCK_SYM table_or_tables
+ {
+ Lex->sql_command=SQLCOM_LOCK_TABLES;
+ }
+ table_lock_list
+
+table_or_tables:
+ TABLE_SYM
+ | TABLES
+
+table_lock_list:
+ table_lock
+ | table_lock_list ',' table_lock
+
+table_lock:
+ table_ident opt_table_alias lock_option
+ { if (!add_table_to_list($1,$2,(thr_lock_type) $3)) YYABORT; }
+
+lock_option:
+ READ_SYM { $$=TL_READ_NO_INSERT; }
+ | WRITE_SYM { $$=current_thd->update_lock_default; }
+ | LOW_PRIORITY WRITE_SYM { $$=TL_WRITE_LOW_PRIORITY; }
+ | READ_SYM LOCAL_SYM { $$= TL_READ; }
+
+unlock:
+ UNLOCK_SYM table_or_tables { Lex->sql_command=SQLCOM_UNLOCK_TABLES; }
+
+
+/* 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;
+ }
+ 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;
+ }
+ grant_privileges ON opt_table TO_SYM user_list
+ grant_option
+
+grant_privileges:
+ grant_privilege_list {}
+ | ALL PRIVILEGES { Lex->grant = UINT_MAX;}
+ | ALL { Lex->grant = UINT_MAX;}
+
+grant_privilege_list:
+ grant_privilege
+ | grant_privilege_list ',' grant_privilege
+
+grant_privilege:
+ SELECT_SYM
+ { Lex->which_columns = SELECT_ACL;}
+ opt_column_list
+ | INSERT
+ { Lex->which_columns = INSERT_ACL; }
+ opt_column_list
+ | UPDATE_SYM
+ { Lex->which_columns = UPDATE_ACL; }
+ opt_column_list
+ | DELETE_SYM { Lex->grant |= DELETE_ACL;}
+ | REFERENCES { Lex->which_columns = REFERENCES_ACL;} opt_column_list
+ | USAGE {}
+ | INDEX { Lex->grant |= INDEX_ACL;}
+ | ALTER { Lex->grant |= ALTER_ACL;}
+ | CREATE { Lex->grant |= CREATE_ACL;}
+ | DROP { Lex->grant |= DROP_ACL;}
+ | RELOAD { Lex->grant |= RELOAD_ACL;}
+ | SHUTDOWN { Lex->grant |= SHUTDOWN_ACL;}
+ | PROCESS { Lex->grant |= PROCESS_ACL;}
+ | FILE_SYM { Lex->grant |= FILE_ACL;}
+ | GRANT OPTION { Lex->grant |= GRANT_ACL;}
+
+opt_table:
+ '*'
+ {
+ Lex->db=current_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);
+ YYABORT;
+ }
+ }
+ | ident '.' '*'
+ {
+ Lex->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);
+ YYABORT;
+ }
+ }
+ | '*' '.' '*'
+ {
+ Lex->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);
+ YYABORT;
+ }
+ }
+ | table_ident
+ {
+ if (!add_table_to_list($1,NULL))
+ YYABORT;
+ if (Lex->grant == UINT_MAX)
+ Lex->grant = TABLE_ACLS & ~GRANT_ACL;
+ }
+
+
+user_list:
+ grant_user { if (Lex->users_list.push_back($1)) YYABORT;}
+ | user_list ',' grant_user { if (Lex->users_list.push_back($3)) YYABORT;}
+
+
+grant_user:
+ user IDENTIFIED_SYM BY TEXT_STRING
+ {
+ $$=$1; $1->password=$4;
+ if ($4.length)
+ {
+ char *buff=(char*) sql_alloc(HASH_PASSWORD_LENGTH+1);
+ if (buff)
+ {
+ make_scrambled_password(buff,$4.str);
+ $1->password.str=buff;
+ $1->password.length=HASH_PASSWORD_LENGTH;
+ }
+ }
+ }
+ | user IDENTIFIED_SYM BY PASSWORD TEXT_STRING
+ { $$=$1; $1->password=$5 ; }
+ | user
+ { $$=$1; $1->password.str=NullS; }
+
+
+opt_column_list:
+ /* empty */ { Lex->grant |= Lex->which_columns; }
+ | '(' column_list ')'
+
+column_list:
+ column_list ',' column_list_id
+ | column_list_id
+
+column_list_id:
+ ident
+ {
+ String *new_str = new String((const char*) $1.str,$1.length);
+ List_iterator <LEX_COLUMN> iter(Lex->columns);
+ class LEX_COLUMN *point;
+ while ((point=iter++))
+ {
+ if (!my_strcasecmp(point->column.ptr(),new_str->ptr()))
+ break;
+ }
+ Lex->grant_tot_col|= Lex->which_columns;
+ if (point)
+ point->rights |= Lex->which_columns;
+ else
+ Lex->columns.push_back(new LEX_COLUMN (*new_str,Lex->which_columns));
+ }
+
+grant_option:
+ /* empty */ {}
+ | WITH GRANT OPTION { Lex->grant |= GRANT_ACL;}
+
+begin:
+ BEGIN_SYM { Lex->sql_command = SQLCOM_COMMIT;} opt_work
+
+opt_work:
+ /* empty */ {}
+ | WORK_SYM {}
+
+commit:
+ COMMIT_SYM { Lex->sql_command = SQLCOM_COMMIT;}
+
+rollback:
+ ROLLBACK_SYM { Lex->sql_command = SQLCOM_ROLLBACK;}
diff --git a/sql/structs.h b/sql/structs.h
new file mode 100644
index 00000000000..b32f957da25
--- /dev/null
+++ b/sql/structs.h
@@ -0,0 +1,160 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 old structures from unireg */
+
+struct st_table;
+class Field;
+
+typedef struct st_date_format { /* How to print date */
+ uint pos[6]; /* Positions to YY.MM.DD HH:MM:SS */
+} DATE_FORMAT;
+
+
+typedef struct st_keyfile_info { /* used with ha_info() */
+ byte ref[MAX_REFLENGTH]; /* Pointer to current row */
+ byte dupp_ref[MAX_REFLENGTH]; /* Pointer to dupp row */
+ uint ref_length; /* Length of ref (1-8) */
+ uint block_size; /* index block size */
+ File filenr; /* (uniq) filenr for table */
+ ha_rows records; /* Records i datafilen */
+ ha_rows deleted; /* Deleted records */
+ ulonglong data_file_length; /* Length off data file */
+ ulonglong max_data_file_length; /* Length off data file */
+ ulonglong index_file_length;
+ ulonglong max_index_file_length;
+ ulonglong delete_length; /* Free bytes */
+ ulonglong auto_increment_value;
+ int errkey,sortkey; /* Last errorkey and sorted by */
+ time_t create_time; /* When table was created */
+ time_t check_time;
+ time_t update_time;
+ ulong mean_rec_length; /* physical reclength */
+} KEYFILE_INFO;
+
+
+typedef struct st_key_part_info { /* Info about a key part */
+ Field *field;
+ uint offset; /* offset in record (from 0) */
+ uint null_offset; // Offset to null_bit in record
+ uint16 length; /* Length of key_part */
+ uint16 store_length;
+ uint16 key_type;
+ uint16 fieldnr; /* Fieldnum in UNIREG */
+ uint8 key_part_flag; /* 0 or HA_REVERSE_SORT */
+ uint8 type;
+ uint8 null_bit; // Position to null_bit
+} KEY_PART_INFO ;
+
+
+typedef struct st_key {
+ uint key_length; /* Tot length of key */
+ uint flags; /* dupp key and pack flags */
+ uint key_parts; /* How many key_parts */
+ uint extra_length;
+ uint usable_key_parts; /* Should normally be = key_parts */
+ KEY_PART_INFO *key_part;
+ char *name; /* Name of key */
+ ulong *rec_per_key; /* Key part distribution */
+} KEY;
+
+
+struct st_join_table;
+
+typedef struct st_reginfo { /* Extra info about reg */
+ struct st_join_table *join_tab; /* Used by SELECT() */
+ enum thr_lock_type lock_type; /* How database is used */
+ bool not_exists_optimize;
+ bool impossible_range;
+} REGINFO;
+
+
+struct st_read_record; /* For referense later */
+class SQL_SELECT;
+class THD;
+class handler;
+
+typedef struct st_read_record { /* Parameter to read_record */
+ struct st_table *table; /* Head-form */
+ handler *file;
+ struct st_table **forms; /* head and ref forms */
+ int (*read_record)(struct st_read_record *);
+ THD *thd;
+ SQL_SELECT *select;
+ uint cache_records;
+ uint ref_length,struct_length,reclength,rec_cache_size,error_offset;
+ uint index;
+ byte *ref_pos; /* pointer to form->refpos */
+ byte *record;
+ byte *cache,*cache_pos,*cache_end,*read_positions;
+ IO_CACHE *io_cache;
+ bool print_error;
+} READ_RECORD;
+
+enum timestamp_type { TIMESTAMP_NONE, TIMESTAMP_DATE, TIMESTAMP_FULL,
+ TIMESTAMP_TIME };
+
+typedef struct st_time {
+ uint year,month,day,hour,minute,second,second_part;
+ bool neg;
+ timestamp_type time_type;
+} TIME;
+
+typedef struct {
+ long year,month,day,hour,minute,second,second_part;
+ bool neg;
+} INTERVAL;
+
+
+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};
+
+struct show_var_st {
+ const char *name;
+ char *value;
+ SHOW_TYPE type;
+};
+
+typedef struct lex_string {
+ char *str;
+ uint length;
+} LEX_STRING;
+
+typedef struct st_lex_user {
+ LEX_STRING user, host, password;
+} LEX_USER;
+
+ /* 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 */
+#define REG_UPDATE 4 /* Uppdate record */
+#define REG_DELETE 8 /* Delete found record */
+#define REG_PROG 16 /* User is updateing database */
+#define REG_CLEAR_AFTER_WRITE 32
+#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
+
+ /* 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_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 */
diff --git a/sql/table.cc b/sql/table.cc
new file mode 100644
index 00000000000..98f7b089b19
--- /dev/null
+++ b/sql/table.cc
@@ -0,0 +1,1121 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 general useful functions */
+
+#include "mysql_priv.h"
+#include <errno.h>
+#include <m_ctype.h>
+
+
+ /* Functions defined in this file */
+
+static void frm_error(int error,TABLE *form,const char *name,int errortype);
+static void fix_type_pointers(const char ***array, TYPELIB *point_to_type,
+ uint types, char **names);
+static uint find_field(TABLE *form,uint start,uint length);
+
+
+static byte* get_field_name(Field *buff,uint *length,
+ my_bool not_used __attribute__((unused)))
+{
+ *length= strlen(buff->field_name);
+ return (byte*) buff->field_name;
+}
+
+ /* Open a .frm file */
+
+int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
+ TABLE *outparam)
+{
+ reg1 uint i;
+ reg2 uchar *strpos;
+ int j,flag,error;
+ uint rec_buff_length,n_length,int_length,records,key_parts,keys,
+ interval_count,interval_parts,read_length,db_create_options;
+ ulong pos;
+ char index_file[FN_REFLEN], *names,*keynames;
+ uchar head[288],*disk_buff,new_field_pack_flag;
+ my_string record;
+ const char **int_array;
+ bool new_frm_ver,use_hash, null_field_first;
+ File file;
+ Field **field_ptr,*reg_field;
+ KEY *keyinfo;
+ KEY_PART_INFO *key_part;
+ uchar *null_pos;
+ uint null_bit;
+ SQL_CRYPT *crypted=0;
+ DBUG_ENTER("openfrm");
+ DBUG_PRINT("enter",("name: '%s' form: %lx",name,outparam));
+
+ bzero((char*) outparam,sizeof(*outparam));
+ outparam->blob_ptr_size=sizeof(char*);
+ disk_buff=NULL; record= NULL; keynames=NullS;
+ outparam->db_stat = db_stat;
+ error=1;
+
+ init_sql_alloc(&outparam->mem_root,1024);
+ MEM_ROOT *old_root=my_pthread_getspecific_ptr(MEM_ROOT*,THR_MALLOC);
+ my_pthread_setspecific_ptr(THR_MALLOC,&outparam->mem_root);
+
+ outparam->real_name=strdup_root(&outparam->mem_root,
+ name+dirname_length(name));
+ *fn_ext(outparam->real_name)='\0'; // Remove extension
+ outparam->table_name=my_strdup(alias,MYF(MY_WME));
+ if (!outparam->real_name || !outparam->table_name)
+ goto err_end;
+
+ flag= (prgflag & CHANGE_FRM) ? O_RDWR : O_RDONLY | O_SHARE;
+ if ((file=my_open(fn_format(index_file,name,"",reg_ext,4),flag,
+ MYF(0)))
+ < 0)
+ {
+ goto err_end; /* purecov: inspected */
+ }
+ error=4;
+ if (!(outparam->path= strdup_root(&outparam->mem_root,name)))
+ goto err_not_open;
+ *fn_ext(outparam->path)='\0'; // Remove extension
+
+ if (my_read(file,(byte*) head,64,MYF(MY_NABP))) goto err_not_open;
+ if (head[0] != (uchar) 254 || head[1] != 1 ||
+ (head[2] != FRM_VER && head[2] != FRM_VER+1))
+ goto err_not_open; /* purecov: inspected */
+ new_field_pack_flag=head[27];
+ new_frm_ver= (head[2] == FRM_VER+1);
+
+ error=3;
+ if (!(pos=get_form_pos(file,head,(TYPELIB*) 0)))
+ goto err_not_open; /* purecov: inspected */
+ *fn_ext(index_file)='\0'; // Remove .frm extension
+
+ outparam->db_type=ha_checktype((enum db_type) (uint) *(head+3));
+ outparam->db_create_options=db_create_options=uint2korr(head+30);
+ outparam->db_options_in_use=outparam->db_create_options;
+ null_field_first=0;
+ if (!head[32]) // New frm file in 3.23
+ {
+ outparam->avg_row_length=uint4korr(head+34);
+ outparam->row_type=(row_type) head[40];
+ outparam->raid_type= head[41];
+ outparam->raid_chunks= head[42];
+ outparam->raid_chunksize= uint4korr(head+43);
+ null_field_first=1;
+ }
+ outparam->db_record_offset=1;
+ if (db_create_options & HA_OPTION_LONG_BLOB_PTR)
+ outparam->blob_ptr_size=portable_sizeof_char_ptr;
+ outparam->db_low_byte_first=test(outparam->db_type == DB_TYPE_MYISAM ||
+ outparam->db_type == DB_TYPE_BERKELEY_DB ||
+ outparam->db_type == DB_TYPE_HEAP);
+
+ error=4;
+ outparam->max_rows=uint4korr(head+18);
+ outparam->min_rows=uint4korr(head+22);
+
+ /* Read keyinformation */
+ VOID(my_seek(file,(ulong) uint2korr(head+6),MY_SEEK_SET,MYF(0)));
+ if (read_string(file,(gptr*) &disk_buff,(uint) uint2korr(head+28)))
+ goto err_not_open; /* purecov: inspected */
+ outparam->keys=keys=disk_buff[0];
+ outparam->keys_in_use= (((key_map) 1) << keys)- (key_map) 1;
+
+ outparam->key_parts=key_parts=disk_buff[1];
+ n_length=keys*sizeof(KEY)+key_parts*sizeof(KEY_PART_INFO);
+ if (!(keyinfo = (KEY*) alloc_root(&outparam->mem_root,
+ n_length+uint2korr(disk_buff+4))))
+ goto err_not_open; /* purecov: inspected */
+ bzero((char*) keyinfo,n_length);
+ outparam->key_info=keyinfo;
+ outparam->max_key_length=0;
+ key_part= (KEY_PART_INFO*) (keyinfo+keys);
+ strpos=disk_buff+6;
+
+ ulong *rec_per_key;
+ if (!(rec_per_key= (ulong*) alloc_root(&outparam->mem_root,
+ sizeof(ulong*)*key_parts)))
+ goto err_not_open;
+
+ for (i=0 ; i < keys ; i++, keyinfo++)
+ {
+ uint null_parts=0;
+ keyinfo->flags= ((uint) strpos[0]) ^ HA_NOSAME;
+ keyinfo->key_length= (uint) uint2korr(strpos+1);
+ keyinfo->key_parts= (uint) strpos[3]; strpos+=4;
+ keyinfo->key_part= key_part;
+ keyinfo->rec_per_key= rec_per_key;
+ for (j=keyinfo->key_parts ; j-- ; key_part++)
+ {
+ *rec_per_key++=0;
+ key_part->fieldnr= (uint16) (uint2korr(strpos) & FIELD_NR_MASK);
+ key_part->offset= (uint) uint2korr(strpos+2)-1;
+ key_part->key_type= (uint) uint2korr(strpos+5);
+ // key_part->field= (Field*) 0; // Will be fixed later
+ if (new_frm_ver)
+ {
+ key_part->key_part_flag= *(strpos+4);
+ key_part->length= (uint) uint2korr(strpos+7);
+ strpos+=9;
+ }
+ else
+ {
+ key_part->length= *(strpos+4);
+ key_part->key_part_flag=0;
+ if (key_part->length > 128)
+ {
+ key_part->length&=127; /* purecov: inspected */
+ key_part->key_part_flag=HA_REVERSE_SORT; /* purecov: inspected */
+ }
+ strpos+=7;
+ }
+ key_part->store_length=key_part->length;
+ }
+ keyinfo->key_length+=null_parts;
+ set_if_bigger(outparam->max_key_length,keyinfo->key_length+
+ keyinfo->key_parts);
+ if (keyinfo->flags & HA_NOSAME)
+ set_if_bigger(outparam->max_unique_length,keyinfo->key_length);
+ }
+
+ (void) strmov(keynames= (char *) key_part,(char *) strpos);
+ outparam->reclength = uint2korr((head+16));
+ if (*(head+26) == 1)
+ outparam->system=1; /* one-record-database */
+#ifdef HAVE_CRYPTED_FRM
+ else if (*(head+26) == 2)
+ {
+ extern SQL_CRYPT *get_crypt_for_frm(void);
+ my_pthread_setspecific_ptr(THR_MALLOC,old_root);
+ crypted=get_crypt_for_frm();
+ my_pthread_setspecific_ptr(THR_MALLOC,&outparam->mem_root);
+ outparam->crypted=1;
+ }
+#endif
+
+ if (!(outparam->file= get_new_handler(outparam,outparam->db_type)))
+ goto err_not_open;
+ error=2;
+ if (db_stat)
+ {
+ if ((outparam->file->
+ ha_open(index_file,
+ (db_stat & HA_READ_ONLY ? O_RDONLY : O_RDWR),
+ (db_stat & HA_OPEN_TEMPORARY ? HA_OPEN_TMP_TABLE :
+ db_stat & HA_WAIT_IF_LOCKED ||
+ specialflag & SPECIAL_WAIT_IF_LOCKED ?
+ HA_OPEN_WAIT_IF_LOCKED :
+ (db_stat & (HA_ABORT_IF_LOCKED | HA_GET_INFO)) ?
+ HA_OPEN_ABORT_IF_LOCKED :
+ HA_OPEN_IGNORE_IF_LOCKED) | ha_open_options)))
+ goto err_not_open; /* purecov: inspected */
+ }
+ outparam->db_low_byte_first=outparam->file->low_byte_first();
+
+ error=4;
+ outparam->reginfo.lock_type= TL_UNLOCK;
+ outparam->current_lock=F_UNLCK;
+ if (db_stat & HA_OPEN_KEYFILE || (prgflag & DELAYED_OPEN)) records=2;
+ else records=1;
+ if (prgflag & (READ_ALL+EXTRA_RECORD)) records++;
+ rec_buff_length=ALIGN_SIZE(outparam->reclength+1);
+ if (!(outparam->record[0]= (byte*)
+ (record = (char *) alloc_root(&outparam->mem_root,
+ rec_buff_length * records))))
+ goto err; /* purecov: inspected */
+ record[outparam->reclength]=0; // For purify and ->c_ptr()
+ outparam->rec_buff_length=rec_buff_length;
+ if (my_pread(file,(byte*) record,(uint) outparam->reclength,
+ (ulong) (uint2korr(head+6)+uint2korr(head+14)),
+ MYF(MY_NABP)))
+ goto err; /* purecov: inspected */
+ for (i=0 ; i < records ; i++, record+=rec_buff_length)
+ {
+ outparam->record[i]=(byte*) record;
+ if (i)
+ memcpy(record,record-rec_buff_length,(uint) outparam->reclength);
+ }
+
+ if (records == 2)
+ { /* fix for select */
+ outparam->record[2]=outparam->record[1];
+ if (db_stat & HA_READ_ONLY)
+ outparam->record[1]=outparam->record[0]; /* purecov: inspected */
+ }
+
+ VOID(my_seek(file,pos,MY_SEEK_SET,MYF(0)));
+ if (my_read(file,(byte*) head,288,MYF(MY_NABP))) goto err;
+ if (crypted)
+ {
+ crypted->decode((char*) head+256,288-256);
+ if (sint2korr(head+284) != 0) // Should be 0
+ goto err; // Wrong password
+ }
+
+ outparam->fields= uint2korr(head+258);
+ pos=uint2korr(head+260); /* Length of all screens */
+ n_length=uint2korr(head+268);
+ interval_count=uint2korr(head+270);
+ interval_parts=uint2korr(head+272);
+ int_length=uint2korr(head+274);
+ outparam->null_fields=uint2korr(head+282);
+ 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));
+
+ if (!(field_ptr = (Field **)
+ alloc_root(&outparam->mem_root,
+ (uint) ((outparam->fields+1)*sizeof(Field*)+
+ interval_count*sizeof(TYPELIB)+
+ (outparam->fields+interval_parts+
+ keys+3)*sizeof(my_string)+
+ (n_length+int_length)))))
+ goto err; /* purecov: inspected */
+
+ outparam->field=field_ptr;
+ read_length=((uint) (outparam->fields*11)+pos+
+ (uint) (n_length+int_length));
+ if (read_string(file,(gptr*) &disk_buff,read_length))
+ goto err; /* purecov: inspected */
+ if (crypted)
+ {
+ crypted->decode((char*) disk_buff,read_length);
+ delete crypted;
+ crypted=0;
+ }
+ strpos= disk_buff+pos;
+
+ outparam->intervals= (TYPELIB*) (field_ptr+outparam->fields+1);
+ int_array= (const char **) (outparam->intervals+interval_count);
+ names= (char*) (int_array+outparam->fields+interval_parts+keys+3);
+ if (!interval_count)
+ outparam->intervals=0; // For better debugging
+ memcpy((char*) names, strpos+(outparam->fields*11),
+ (uint) (n_length+int_length));
+
+ fix_type_pointers(&int_array,&outparam->fieldnames,1,&names);
+ fix_type_pointers(&int_array,outparam->intervals,interval_count,
+ &names);
+ if (keynames)
+ fix_type_pointers(&int_array,&outparam->keynames,1,&keynames);
+ VOID(my_close(file,MYF(MY_WME)));
+
+ record=(char*) outparam->record[0]-1; /* Fieldstart = 1 */
+ if (null_field_first)
+ {
+ outparam->null_flags=null_pos=(uchar*) record+1;
+ null_bit= (db_create_options & HA_OPTION_PACK_RECORD) ? 1 : 2;
+ outparam->null_bytes=(outparam->null_fields+null_bit+6)/8;
+ }
+ else
+ {
+ outparam->null_bytes=(outparam->null_fields+7)/8;
+ outparam->null_flags=null_pos=
+ (uchar*) (record+1+outparam->reclength-outparam->null_bytes);
+ null_bit=1;
+ }
+
+ use_hash= outparam->fields >= MAX_FIELDS_BEFORE_HASH;
+ if (use_hash)
+ use_hash= !hash_init(&outparam->name_hash,
+ outparam->fields,0,0,
+ (hash_get_key) get_field_name,0,
+ HASH_CASE_INSENSITIVE);
+
+ for (i=0 ; i < outparam->fields; i++, strpos+= 11, field_ptr++)
+ {
+ uint pack_flag= uint2korr(strpos+6);
+ uint interval_nr= (uint) strpos[10];
+
+ *field_ptr=reg_field=
+ make_field(record+uint2korr(strpos+4),
+ (uint32) strpos[3], // field_length
+ null_pos,null_bit,
+ pack_flag,
+ (Field::utype) MTYP_TYPENR((uint) strpos[8]),
+ (interval_nr ?
+ outparam->intervals+interval_nr-1 :
+ (TYPELIB*) 0),
+ outparam->fieldnames.type_names[i],
+ outparam);
+ if (!(reg_field->flags & NOT_NULL_FLAG))
+ {
+ if ((null_bit<<=1) == 256)
+ {
+ null_pos++;
+ null_bit=1;
+ }
+ }
+ if (reg_field->unireg_check == Field::NEXT_NUMBER)
+ {
+ if ((int) (outparam->next_number_index= (uint)
+ find_ref_key(outparam,reg_field,
+ &outparam->next_number_key_offset)) < 0)
+ reg_field->unireg_check=Field::NONE; /* purecov: inspected */
+ else
+ {
+ outparam->found_next_number_field=reg_field;
+ reg_field->flags|=AUTO_INCREMENT_FLAG;
+ }
+ }
+ if (outparam->timestamp_field == reg_field)
+ outparam->timestamp_field_offset=i;
+ if (use_hash)
+ (void) hash_insert(&outparam->name_hash,(byte*) *field_ptr); // Will never fail
+ }
+ *field_ptr=0; // End marker
+
+ /* Fix key->name and key_part->field */
+ if (key_parts)
+ {
+ uint primary_key=(uint) (find_type((char*) "PRIMARY",&outparam->keynames,
+ 3)-1);
+ uint ha_option=outparam->file->option_flag();
+ keyinfo=outparam->key_info;
+ key_part=keyinfo->key_part;
+
+ for (uint key=0 ; key < outparam->keys ; key++,keyinfo++)
+ {
+ uint usable_parts=0;
+ keyinfo->name=(char*) outparam->keynames.type_names[key];
+ if (primary_key >= MAX_KEY && (keyinfo->flags & HA_NOSAME))
+ {
+ /*
+ If the UNIQUE key don't have NULL columns, declare this as
+ a primary key.
+ */
+ primary_key=key;
+ for (i=0 ; i < keyinfo->key_parts ;i++)
+ {
+ if (!key_part[i].fieldnr ||
+ outparam->field[key_part[i].fieldnr-1]->null_ptr)
+ {
+ primary_key=MAX_KEY; // Can't be used
+ break;
+ }
+ }
+ }
+
+ for (i=0 ; i < keyinfo->key_parts ; key_part++,i++)
+ {
+ if (new_field_pack_flag <= 1)
+ key_part->fieldnr=(uint16) find_field(outparam,
+ (uint) key_part->offset,
+ (uint) key_part->length);
+#ifdef EXTRA_DEBUG
+ if (key_part->fieldnr > outparam->fields)
+ goto err; // sanity check
+#endif
+ if (key_part->fieldnr)
+ { // Should always be true !
+ Field *field=key_part->field=outparam->field[key_part->fieldnr-1];
+ if (field->null_ptr)
+ {
+ key_part->null_offset=(uint) ((byte*) field->null_ptr -
+ outparam->record[0]);
+ key_part->null_bit= field->null_bit;
+ key_part->store_length+=HA_KEY_NULL_LENGTH;
+ keyinfo->flags|=HA_NULL_PART_KEY;
+ keyinfo->extra_length+= HA_KEY_NULL_LENGTH;
+ }
+ if (field->type() == FIELD_TYPE_BLOB ||
+ field->real_type() == FIELD_TYPE_VAR_STRING)
+ {
+ if (field->type() == FIELD_TYPE_BLOB)
+ key_part->key_part_flag|= HA_BLOB_PART;
+ keyinfo->extra_length+=HA_KEY_BLOB_LENGTH;
+ key_part->store_length+=HA_KEY_BLOB_LENGTH;
+ }
+ if (i == 0 && key != primary_key)
+ field->flags |=
+ ((keyinfo->flags & HA_NOSAME) &&
+ field->key_length() ==
+ keyinfo->key_length ? UNIQUE_KEY_FLAG : MULTIPLE_KEY_FLAG);
+ if (i == 0)
+ field->key_start|= ((key_map) 1 << key);
+ if (ha_option & HA_HAVE_KEY_READ_ONLY &&
+ field->key_length() == key_part->length)
+ {
+ if (field->key_type() != HA_KEYTYPE_TEXT ||
+ !(ha_option & HA_KEY_READ_WRONG_STR))
+ field->part_of_key|= ((key_map) 1 << key);
+ }
+ if (!(key_part->key_part_flag & HA_REVERSE_SORT) &&
+ usable_parts == i)
+ usable_parts++; // For FILESORT
+ field->flags|= PART_KEY_FLAG;
+ if (key == primary_key)
+ {
+ field->flags|= PRI_KEY_FLAG;
+ if (ha_option & HA_PRIMARY_KEY_IN_READ_INDEX)
+ field->part_of_key|= ((key_map) 1 << primary_key);
+ }
+ 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->field_length=key_part->length;
+ }
+ }
+ }
+ else
+ { // Error: shorten key
+ keyinfo->key_parts=usable_parts;
+ keyinfo->flags=0;
+ }
+ }
+ keyinfo->usable_key_parts=usable_parts; // Filesort
+ }
+ if (primary_key < MAX_KEY &&
+ (outparam->keys_in_use & ((key_map) 1 << primary_key)))
+ {
+ outparam->primary_key=primary_key;
+ if (outparam->key_info[primary_key].key_parts == 1)
+ {
+ Field *field= outparam->key_info[primary_key].key_part[0].field;
+ if (field && field->result_type() == INT_RESULT)
+ outparam->rowid_field=field;
+ }
+ }
+ else
+ outparam->primary_key = MAX_KEY; // we do not have a primary key
+ }
+ x_free((gptr) disk_buff);
+ if (new_field_pack_flag <= 1)
+ { /* Old file format with default null */
+ uint null_length=(outparam->null_fields+7)/8;
+ bfill(outparam->null_flags,null_length,255);
+ bfill(outparam->null_flags+outparam->rec_buff_length,null_length,255);
+ if (records > 2)
+ bfill(outparam->null_flags+outparam->rec_buff_length*2,null_length,255);
+ }
+
+ if (outparam->blob_fields)
+ {
+ Field **ptr;
+ Field_blob **save;
+
+ if (!(outparam->blob_field=save=
+ (Field_blob**) alloc_root(&outparam->mem_root,
+ (uint) (outparam->blob_fields+1)*
+ sizeof(Field_blob*))))
+ goto err;
+ for (ptr=outparam->field ; *ptr ; ptr++)
+ {
+ if ((*ptr)->flags & BLOB_FLAG)
+ (*save++)= (Field_blob*) *ptr;
+ }
+ *save=0; // End marker
+ }
+ else
+ outparam->blob_field=
+ (Field_blob**) (outparam->field+outparam->fields); // Point at null ptr
+
+ my_pthread_setspecific_ptr(THR_MALLOC,old_root);
+ opened_tables++;
+#ifndef DBUG_OFF
+ if (use_hash)
+ (void) hash_check(&outparam->name_hash);
+#endif
+ if (db_stat)
+ outparam->file->initialize();
+ DBUG_RETURN (0);
+
+ err:
+ if (outparam->file && db_stat)
+ (void) outparam->file->close();
+ err_not_open:
+ x_free((gptr) disk_buff);
+ delete crypted;
+ VOID(my_close(file,MYF(MY_WME)));
+
+ err_end: /* Here when no file */
+ delete crypted;
+ my_pthread_setspecific_ptr(THR_MALLOC,old_root);
+ frm_error(error,outparam,name,ME_ERROR+ME_WAITTANG);
+ outparam->file=0; // For easyer errorchecking
+ free_root(&outparam->mem_root);
+ my_free(outparam->table_name,MYF(MY_ALLOW_ZERO_PTR));
+ DBUG_RETURN (error);
+} /* openfrm */
+
+
+ /* close a .frm file and it's tables */
+
+int closefrm(register TABLE *table)
+{
+ int error=0;
+ DBUG_ENTER("closefrm");
+ if (table->db_stat)
+ error=table->file->close();
+ if (table->table_name)
+ {
+ my_free(table->table_name,MYF(0));
+ table->table_name=0;
+ }
+ if (table->fields)
+ {
+ for (Field **ptr=table->field ; *ptr ; ptr++)
+ delete *ptr;
+ table->fields=0;
+ }
+ delete table->file;
+ table->file=0; /* For easyer errorchecking */
+ hash_free(&table->name_hash);
+ free_root(&table->mem_root);
+ DBUG_RETURN(error);
+}
+
+
+/* Deallocate temporary blob storage */
+
+void free_blobs(register TABLE *table)
+{
+ for (Field_blob **ptr=table->blob_field ; *ptr ; ptr++)
+ (*ptr)->free();
+}
+
+
+ /* Find where a form starts */
+ /* if formname is NullS then only formnames is read */
+
+ulong get_form_pos(File file, uchar *head, TYPELIB *save_names)
+{
+ uint a_length,names,length;
+ uchar *pos,*buf;
+ ulong ret_value=0;
+ DBUG_ENTER("get_form_pos");
+
+ names=uint2korr(head+8);
+ a_length=(names+2)*sizeof(my_string); /* Room for two extra */
+
+ if (!save_names)
+ a_length=0;
+ else
+ save_names->type_names=0; /* Clear if error */
+
+ if (names)
+ {
+ length=uint2korr(head+4);
+ VOID(my_seek(file,64L,MY_SEEK_SET,MYF(0)));
+ if (!(buf= (uchar*) my_malloc((uint) length+a_length+names*4,
+ MYF(MY_WME))) ||
+ my_read(file,(byte*) buf+a_length,(uint) (length+names*4),
+ MYF(MY_NABP)))
+ { /* purecov: inspected */
+ x_free((gptr) buf); /* purecov: inspected */
+ DBUG_RETURN(0L); /* purecov: inspected */
+ }
+ pos= buf+a_length+length;
+ ret_value=uint4korr(pos);
+ }
+ if (! save_names)
+ my_free((gptr) buf,MYF(0));
+ else if (!names)
+ bzero((char*) save_names,sizeof(save_names));
+ else
+ {
+ char *str;
+ str=(char *) (buf+a_length);
+ fix_type_pointers((const char ***) &buf,save_names,1,&str);
+ }
+ DBUG_RETURN(ret_value);
+}
+
+
+ /* Read string from a file with malloc */
+
+int read_string(File file, gptr *to, uint length)
+{
+ DBUG_ENTER("read_string");
+
+ x_free((gptr) *to);
+ if (!(*to= (gptr) my_malloc(length+1,MYF(MY_WME))) ||
+ my_read(file,(byte*) *to,length,MYF(MY_NABP)))
+ {
+ x_free((gptr) *to); /* purecov: inspected */
+ *to= 0; /* purecov: inspected */
+ DBUG_RETURN(1); /* purecov: inspected */
+ }
+ *((char*) *to+length)= '\0';
+ DBUG_RETURN (0);
+} /* read_string */
+
+
+ /* Add a new form to a form file */
+
+ulong make_new_entry(File file, uchar *fileinfo, TYPELIB *formnames,
+ const char *newname)
+{
+ uint i,bufflength,maxlength,n_length,length,names;
+ ulong endpos,newpos;
+ char buff[IO_SIZE];
+ uchar *pos;
+ DBUG_ENTER("make_new_entry");
+
+ length=strlen(newname)+1;
+ n_length=uint2korr(fileinfo+4);
+ maxlength=uint2korr(fileinfo+6);
+ names=uint2korr(fileinfo+8);
+ newpos=uint4korr(fileinfo+10);
+
+ if (64+length+n_length+(names+1)*4 > maxlength)
+ { /* Expand file */
+ newpos+=IO_SIZE;
+ int4store(fileinfo+10,newpos);
+ endpos=(ulong) my_seek(file,0L,MY_SEEK_END,MYF(0)); /* Copy from file-end */
+ bufflength= (uint) (endpos & (IO_SIZE-1)); /* IO_SIZE is a power of 2 */
+
+ while (endpos > maxlength)
+ {
+ VOID(my_seek(file,(ulong) (endpos-bufflength),MY_SEEK_SET,MYF(0)));
+ if (my_read(file,(byte*) buff,bufflength,MYF(MY_NABP+MY_WME)))
+ DBUG_RETURN(0L);
+ VOID(my_seek(file,(ulong) (endpos-bufflength+IO_SIZE),MY_SEEK_SET,
+ MYF(0)));
+ if ((my_write(file,(byte*) buff,bufflength,MYF(MY_NABP+MY_WME))))
+ DBUG_RETURN(0);
+ endpos-=bufflength; bufflength=IO_SIZE;
+ }
+ bzero(buff,IO_SIZE); /* Null new block */
+ VOID(my_seek(file,(ulong) maxlength,MY_SEEK_SET,MYF(0)));
+ if (my_write(file,(byte*) buff,bufflength,MYF(MY_NABP+MY_WME)))
+ DBUG_RETURN(0L);
+ maxlength+=IO_SIZE; /* Fix old ref */
+ int2store(fileinfo+6,maxlength);
+ for (i=names, pos= (uchar*) *formnames->type_names+n_length-1; i-- ;
+ pos+=4)
+ {
+ endpos=uint4korr(pos)+IO_SIZE;
+ int4store(pos,endpos);
+ }
+ }
+
+ if (n_length == 1 )
+ { /* First name */
+ length++;
+ VOID(strxmov(buff,"/",newname,"/",NullS));
+ }
+ else
+ VOID(strxmov(buff,newname,"/",NullS)); /* purecov: inspected */
+ VOID(my_seek(file,63L+(ulong) n_length,MY_SEEK_SET,MYF(0)));
+ if (my_write(file,(byte*) buff,(uint) length+1,MYF(MY_NABP+MY_WME)) ||
+ (names && my_write(file,(byte*) (*formnames->type_names+n_length-1),
+ names*4, MYF(MY_NABP+MY_WME))) ||
+ my_write(file,(byte*) fileinfo+10,(uint) 4,MYF(MY_NABP+MY_WME)))
+ DBUG_RETURN(0L); /* purecov: inspected */
+
+ int2store(fileinfo+8,names+1);
+ int2store(fileinfo+4,n_length+length);
+ VOID(my_chsize(file,newpos,MYF(MY_WME))); /* Append file with '\0' */
+ DBUG_RETURN(newpos);
+} /* make_new_entry */
+
+
+ /* error message when opening a form file */
+
+static void frm_error(int error, TABLE *form, const char *name, myf errortype)
+{
+ int err_no;
+ char buff[FN_REFLEN];
+ const char *form_dev="",*datext;
+ DBUG_ENTER("frm_error");
+
+ switch (error) {
+ case 1:
+ if (my_errno == ENOENT)
+ {
+ char *db;
+ uint length=dirname_part(buff,name);
+ buff[length-1]=0;
+ db=buff+dirname_length(buff);
+ my_error(ER_NO_SUCH_TABLE,MYF(0),db,form->real_name);
+ }
+ else
+ my_error(ER_FILE_NOT_FOUND,errortype,
+ fn_format(buff,name,form_dev,reg_ext,0),my_errno);
+ break;
+ case 2:
+ {
+ datext=form->file ? *form->file->bas_ext() : "";
+ err_no= (my_errno == ENOENT) ? ER_FILE_NOT_FOUND : (my_errno == EAGAIN) ?
+ ER_FILE_USED : ER_CANT_OPEN_FILE;
+ my_error(err_no,errortype,
+ fn_format(buff,form->real_name,form_dev,datext,2),my_errno);
+ break;
+ }
+ default: /* Better wrong error than none */
+ case 4:
+ my_error(ER_NOT_FORM_FILE,errortype,
+ fn_format(buff,name,form_dev,reg_ext,0));
+ break;
+ }
+ DBUG_VOID_RETURN;
+} /* frm_error */
+
+
+ /*
+ ** fix a str_type to a array type
+ ** typeparts sepearated with some char. differents types are separated
+ ** with a '\0'
+ */
+
+static void
+fix_type_pointers(const char ***array, TYPELIB *point_to_type, uint types,
+ char **names)
+{
+ char *type_name, *ptr;
+ char chr;
+
+ ptr= *names;
+ while (types--)
+ {
+ point_to_type->name=0;
+ point_to_type->type_names= *array;
+
+ if ((chr= *ptr)) /* Test if empty type */
+ {
+ while ((type_name=strchr(ptr+1,chr)) != NullS)
+ {
+ *((*array)++) = ptr+1;
+ *type_name= '\0'; /* End string */
+ ptr=type_name;
+ }
+ ptr+=2; /* Skipp end mark and last 0 */
+ }
+ else
+ ptr++;
+ point_to_type->count= (uint) (*array - point_to_type->type_names);
+ point_to_type++;
+ *((*array)++)= NullS; /* End of type */
+ }
+ *names=ptr; /* Update end */
+ return;
+} /* fix_type_pointers */
+
+
+TYPELIB *typelib(List<String> &strings)
+{
+ TYPELIB *result=(TYPELIB*) sql_alloc(sizeof(TYPELIB));
+ if (!result)
+ return 0;
+ result->count=strings.elements;
+ result->name="";
+ if (!(result->type_names=(const char **) sql_alloc(sizeof(char *)*
+ (result->count+1))))
+ return 0;
+ List_iterator<String> it(strings);
+ String *tmp;
+ for (uint i=0; (tmp=it++) ; i++)
+ result->type_names[i]=tmp->ptr();
+ result->type_names[result->count]=0; // End marker
+ return result;
+}
+
+
+ /*
+ ** Search after a field with given start & length
+ ** If an exact field isn't found, return longest field with starts
+ ** at right position.
+ ** Return 0 on error, else field number+1
+ ** This is needed because in some .frm fields 'fieldnr' was saved wrong
+ */
+
+static uint find_field(TABLE *form,uint start,uint length)
+{
+ Field **field;
+ uint i,pos;
+
+ pos=0;
+
+ for (field=form->field, i=1 ; i<= form->fields ; i++,field++)
+ {
+ if ((*field)->offset() == start)
+ {
+ if ((*field)->key_length() == length)
+ return (i);
+ if (!pos || form->field[pos-1]->pack_length() <
+ (*field)->pack_length())
+ pos=i;
+ }
+ }
+ return (pos);
+}
+
+
+ /* Check that the integer is in the internvall */
+
+int set_zone(register int nr, int min_zone, int max_zone)
+{
+ if (nr<=min_zone)
+ return (min_zone);
+ if (nr>=max_zone)
+ return (max_zone);
+ return (nr);
+} /* set_zone */
+
+ /* Adjust number to next larger disk buffer */
+
+ulong next_io_size(register ulong pos)
+{
+ reg2 ulong offset;
+ if ((offset= pos & (IO_SIZE-1)))
+ return pos-offset+IO_SIZE;
+ return pos;
+} /* next_io_size */
+
+
+void append_unescaped(String *res,const char *pos)
+{
+ for ( ; *pos ; pos++)
+ {
+ switch (*pos) {
+ case 0: /* Must be escaped for 'mysql' */
+ res->append('\\');
+ res->append('0');
+ break;
+ case '\n': /* Must be escaped for logs */
+ res->append('\\');
+ res->append('n');
+ break;
+ case '\r':
+ res->append('\\'); /* This gives better readbility */
+ res->append('r');
+ break;
+ case '\\':
+ res->append('\\'); /* Because of the sql syntax */
+ res->append('\\');
+ break;
+ case '\'':
+ res->append('\''); /* Because of the sql syntax */
+ res->append('\'');
+ break;
+ default:
+ res->append(*pos);
+ break;
+ }
+ }
+}
+
+ /* Create a .frm file */
+
+File create_frm(register my_string name, uint reclength, uchar *fileinfo,
+ HA_CREATE_INFO *create_info, uint keys)
+{
+ register File file;
+ uint key_length;
+ ulong length;
+ char fill[IO_SIZE];
+
+#if SIZEOF_OFF_T > 4
+ /* Fix this in MySQL 4.0; The current limit is 4G rows (QQ) */
+ if (create_info->max_rows > ~(ulong) 0)
+ create_info->max_rows= ~(ulong) 0;
+ if (create_info->min_rows > ~(ulong) 0)
+ create_info->min_rows= ~(ulong) 0;
+#endif
+
+ if ((file=my_create(name,CREATE_MODE,O_RDWR | O_TRUNC,MYF(MY_WME))) >= 0)
+ {
+ bzero((char*) fileinfo,64);
+ fileinfo[0]=(uchar) 254; fileinfo[1]= 1; fileinfo[2]= FRM_VER+1; // Header
+ fileinfo[3]= (uchar) ha_checktype(create_info->db_type);
+ fileinfo[4]=1;
+ int2store(fileinfo+6,IO_SIZE); /* Next block starts here */
+ key_length=keys*(7+NAME_LEN+MAX_REF_PARTS*9)+16;
+ length=(ulong) next_io_size((ulong) (IO_SIZE+key_length+reclength));
+ int4store(fileinfo+10,length);
+ int2store(fileinfo+14,key_length);
+ int2store(fileinfo+16,reclength);
+ int4store(fileinfo+18,create_info->max_rows);
+ int4store(fileinfo+22,create_info->min_rows);
+ fileinfo[27]=2; // Use long pack-fields
+ create_info->table_options|=HA_OPTION_LONG_BLOB_PTR; // Use portable blob pointers
+ int2store(fileinfo+30,create_info->table_options);
+ fileinfo[32]=0; // No filename anymore
+ int4store(fileinfo+34,create_info->avg_row_length);
+ fileinfo[40]= (uchar) create_info->row_type;
+ fileinfo[41]= (uchar) create_info->raid_type;
+ fileinfo[42]= (uchar) create_info->raid_chunks;
+ int4store(fileinfo+43,create_info->raid_chunksize);
+ bzero(fill,IO_SIZE);
+ for (; length > IO_SIZE ; length-= IO_SIZE)
+ {
+ if (my_write(file,(byte*) fill,IO_SIZE,MYF(MY_WME | MY_NABP)))
+ {
+ VOID(my_close(file,MYF(0)));
+ VOID(my_delete(name,MYF(0)));
+ return(-1);
+ }
+ }
+ }
+ return (file);
+} /* create_frm */
+
+
+void update_create_info_from_table(HA_CREATE_INFO *create_info, TABLE *table)
+{
+ create_info->max_rows=table->max_rows;
+ create_info->min_rows=table->min_rows;
+ create_info->table_options=table->db_create_options;
+ create_info->avg_row_length=table->avg_row_length;
+ create_info->row_type=table->row_type;
+ create_info->raid_type=table->raid_type;
+ create_info->raid_chunks=table->raid_chunks;
+ create_info->raid_chunksize=table->raid_chunksize;
+}
+
+int
+rename_file_ext(const char * from,const char * to,const char * ext)
+{
+ char from_b[FN_REFLEN],to_b[FN_REFLEN];
+ VOID(strxmov(from_b,from,ext,NullS));
+ VOID(strxmov(to_b,to,ext,NullS));
+ return (my_rename(from_b,to_b,MYF(MY_WME)));
+}
+
+
+/*
+ Alloc a value as a string and return it
+ If field is empty, return NULL
+*/
+
+char *get_field(MEM_ROOT *mem, TABLE *table, uint fieldnr)
+{
+ Field *field=table->field[fieldnr];
+ char buff[MAX_FIELD_WIDTH];
+ String str(buff,sizeof(buff));
+ field->val_str(&str,&str);
+ uint length=str.length();
+ if (!length)
+ return NullS;
+ char *to= (char*) alloc_root(mem,length+1);
+ memcpy(to,str.ptr(),(uint) length);
+ to[length]=0;
+ return to;
+}
+
+bool check_db_name(const char *name)
+{
+ while (*name)
+ {
+#if defined(USE_MB) && defined(USE_MB_IDENT)
+ if (use_mb(default_charset_info))
+ {
+ int len=my_ismbchar(default_charset_info, name, name+MBMAXLEN);
+ if (len)
+ {
+ name += len;
+ continue;
+ }
+ }
+#endif
+ if (*name == '/' || *name == FN_LIBCHAR)
+ return 1;
+ name++;
+ }
+ return 0;
+}
+
+
+/*
+ Allow anything as a table name, as long as it doesn't contain an
+ a '/', or a '.' character
+ returns 1 on error
+*/
+
+
+bool check_table_name(const char *name, uint length)
+{
+ const char *end= name+length;
+
+ while (name != end)
+ {
+#if defined(USE_MB) && defined(USE_MB_IDENT)
+ if (use_mb(default_charset_info))
+ {
+ int len=my_ismbchar(default_charset_info, name, end);
+ if (len)
+ {
+ name += len;
+ continue;
+ }
+ }
+#endif
+ if (*name == '/' || *name == FN_LIBCHAR || *name == FN_EXTCHAR)
+ return 1;
+ name++;
+ }
+ return 0;
+}
+
+bool check_column_name(const char *name)
+{
+ while (*name)
+ {
+#if defined(USE_MB) && defined(USE_MB_IDENT)
+ if (use_mb(default_charset_info))
+ {
+ int len=my_ismbchar(default_charset_info, name, name+MBMAXLEN);
+ if (len)
+ {
+ name += len;
+ continue;
+ }
+ }
+#endif
+ if (*name == NAMES_SEP_CHAR)
+ return 1;
+ name++;
+ }
+ return 0;
+}
+
+/*
+** Get type of table from .frm file
+*/
+
+db_type get_table_type(const char *name)
+{
+ File file;
+ uchar head[4];
+ int error;
+ DBUG_ENTER("get_table_type");
+ DBUG_PRINT("enter",("name: '%s'",name));
+
+ if ((file=my_open(name,O_RDONLY, MYF(0))) < 0)
+ DBUG_RETURN(DB_TYPE_UNKNOWN);
+ error=my_read(file,(byte*) head,4,MYF(MY_NABP));
+ my_close(file,MYF(0));
+ if (error || head[0] != (uchar) 254 || head[1] != 1 ||
+ (head[2] != FRM_VER && head[2] != FRM_VER+1))
+ DBUG_RETURN(DB_TYPE_UNKNOWN);
+ DBUG_RETURN(ha_checktype((enum db_type) (uint) *(head+3)));
+}
+
+
+/*****************************************************************************
+** Instansiate templates
+*****************************************************************************/
+
+#ifdef __GNUC__
+template class List<String>;
+template class List_iterator<String>;
+#endif
diff --git a/sql/table.h b/sql/table.h
new file mode 100644
index 00000000000..7fe3e5de601
--- /dev/null
+++ b/sql/table.h
@@ -0,0 +1,136 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+
+/* Structs that defines the TABLE */
+
+class Item; /* Needed by ORDER */
+class GRANT_TABLE;
+
+/* Order clause list element */
+
+typedef struct st_order {
+ struct st_order *next;
+ Item **item; /* Point at item in select fields */
+ bool asc; /* true if ascending */
+ bool free_me; /* true if item isn't shared */
+ bool in_field_list; /* true if in select field list */
+ Field *field; /* If tmp-table group */
+ char *buff; /* If tmp-table group */
+ table_map used,depend_map;
+} ORDER;
+
+typedef struct st_grant_info
+{
+ GRANT_TABLE *grant_table;
+ uint version;
+ uint privilege;
+ uint want_privilege;
+} GRANT_INFO;
+
+/* Table cache entry struct */
+
+class Field_timestamp;
+class Field_blob;
+
+struct st_table {
+ handler *file;
+ Field **field; /* Pointer to fields */
+ Field_blob **blob_field; /* Pointer to blob fields */
+ HASH name_hash; /* hash of field names */
+ byte *record[3]; /* Pointer to records */
+ uint fields; /* field count */
+ uint reclength; /* Recordlength */
+ uint rec_buff_length;
+ uint keys,key_parts,primary_key,max_key_length,max_unique_length;
+ uint uniques;
+ uint null_fields; /* number of null fields */
+ uint blob_fields; /* number of blob fields */
+ key_map keys_in_use, keys_in_use_for_query;
+ KEY *key_info; /* data of keys in database */
+ TYPELIB keynames; /* Pointers to keynames */
+ ha_rows max_rows; /* create information */
+ ha_rows min_rows; /* create information */
+ ulong avg_row_length; /* create information */
+ ulong raid_chunksize;
+ TYPELIB fieldnames; /* Pointer to fieldnames */
+ TYPELIB *intervals; /* pointer to interval info */
+ enum db_type db_type; /* table_type for handler */
+ enum row_type row_type; /* How rows are stored */
+ uint db_create_options; /* Create options from database */
+ uint db_options_in_use; /* Options in use */
+ uint db_record_offset; /* if HA_REC_IN_SEQ */
+ uint db_stat; /* mode of file as in handler.h */
+ uint raid_type,raid_chunks;
+ uint status; /* Used by postfix.. */
+ uint system; /* Set if system record */
+ ulong time_stamp; /* Set to offset+1 of record */
+ uint timestamp_field_offset;
+ uint next_number_index;
+ uint blob_ptr_size; /* 4 or 8 */
+ uint next_number_key_offset;
+ int current_lock; /* Type of lock on 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,tmp_table,const_table;
+ my_bool key_read;
+ my_bool crypted;
+ my_bool db_low_byte_first; /* Portable row format */
+ my_bool locked_by_flush;
+ Field *next_number_field, /* Set if next_number is activated */
+ *found_next_number_field, /* Set on open */
+ *rowid_field;
+ Field_timestamp *timestamp_field;
+ my_string comment; /* Comment about table */
+ REGINFO reginfo; /* field connections */
+ MEM_ROOT mem_root;
+ GRANT_INFO grant;
+
+ char *table_cache_key;
+ char *table_name,*real_name,*path;
+ uint key_length; /* Length of key */
+ uint tablenr,used_fields,null_bytes;
+ table_map map;
+ ulong version,flush_version;
+ uchar *null_flags;
+ IO_CACHE *io_cache; /* If sorted trough file*/
+ byte *record_pointers; /* If sorted in memory */
+ ha_rows found_records; /* How many records in sort */
+ ORDER *group;
+ 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];
+ ulong query_id;
+
+ THD *in_use; /* Which thread uses this */
+ struct st_table *next,*prev;
+};
+
+
+typedef struct st_table_list {
+ struct st_table_list *next;
+ char *db,*name,*real_name;
+ thr_lock_type lock_type;
+ bool straight; /* optimize with prev table */
+ bool outer_join;
+ TABLE *table;
+ Item *on_expr; /* Used with outer join */
+ struct st_table_list *natural_join; /* natural join on this table*/
+ List<String> *use_index,*ignore_index;
+ GRANT_INFO grant;
+} TABLE_LIST;
diff --git a/sql/thr_malloc.cc b/sql/thr_malloc.cc
new file mode 100644
index 00000000000..8cf4f937546
--- /dev/null
+++ b/sql/thr_malloc.cc
@@ -0,0 +1,88 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+
+/* Mallocs for used in threads */
+
+#include "mysql_priv.h"
+
+extern "C" {
+ void sql_alloc_error_handler(void)
+ {
+ current_thd->fatal_error=1; /* purecov: inspected */
+ }
+}
+
+void init_sql_alloc(MEM_ROOT *mem_root,uint block_size)
+{
+ init_alloc_root(mem_root,block_size);
+ mem_root->error_handler=sql_alloc_error_handler;
+}
+
+
+gptr sql_alloc(uint Size)
+{
+ MEM_ROOT *root=my_pthread_getspecific_ptr(MEM_ROOT*,THR_MALLOC);
+ char *ptr= (char*) alloc_root(root,Size);
+ if (!ptr)
+ {
+ sql_print_error(ER(ER_OUT_OF_RESOURCES));
+ }
+ return ptr;
+}
+
+
+gptr sql_calloc(uint size)
+{
+ gptr ptr;
+ if ((ptr=sql_alloc(size)))
+ bzero((char*) ptr,size);
+ return ptr;
+}
+
+
+char *sql_strdup(const char *str)
+{
+ uint len=strlen(str)+1;
+ char *pos;
+ if ((pos= (char*) sql_alloc(len)))
+ memcpy(pos,str,len);
+ return pos;
+}
+
+
+char *sql_strmake(const char *str,uint len)
+{
+ char *pos;
+ if ((pos= (char*) sql_alloc(len+1)))
+ {
+ memcpy(pos,str,len);
+ pos[len]=0;
+ }
+ return pos;
+}
+
+
+gptr sql_memdup(const void *ptr,uint len)
+{
+ char *pos;
+ if ((pos= (char*) sql_alloc(len)))
+ memcpy(pos,ptr,len);
+ return pos;
+}
+
+void sql_element_free(void *ptr __attribute__((unused)))
+{} /* purecov: deadcode */
diff --git a/sql/time.cc b/sql/time.cc
new file mode 100644
index 00000000000..066979d1c9a
--- /dev/null
+++ b/sql/time.cc
@@ -0,0 +1,690 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 date and time */
+
+#include "mysql_priv.h"
+#include <m_ctype.h>
+
+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 */
+ /* Currently only my_time_zone is inited */
+
+static long my_time_zone=0;
+pthread_mutex_t LOCK_timezone;
+
+void init_time(void)
+{
+ time_t seconds;
+ struct tm *l_time,tm_tmp;;
+ TIME my_time;
+
+ seconds= (time_t) time((time_t*) 0);
+ localtime_r(&seconds,&tm_tmp);
+ l_time= &tm_tmp;
+ my_time_zone=0;
+ my_time.year= (uint) l_time->tm_year+1900;
+ my_time.month= (uint) l_time->tm_mon+1;
+ my_time.day= (uint) l_time->tm_mday;
+ my_time.hour= (uint) l_time->tm_hour;
+ my_time.minute= (uint) l_time->tm_min;
+ my_time.second= (uint) l_time->tm_sec;
+ VOID(my_gmt_sec(&my_time)); /* Init my_time_zone */
+}
+
+/*
+ Convert current time to sec. since 1970.01.01
+ 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)
+{
+ uint loop;
+ time_t tmp;
+ struct tm *l_time,tm_tmp;
+ long diff;
+
+ if (t->hour >= 24)
+ { /* Fix for time-loop */
+ t->day+=t->hour/24;
+ t->hour%=24;
+ }
+ pthread_mutex_lock(&LOCK_timezone);
+ tmp=(time_t) ((calc_daynr((uint) t->year,(uint) t->month,(uint) t->day) -
+ (long) days_at_timestart)*86400L + (long) t->hour*3600L +
+ (long) (t->minute*60 + t->second)) + (time_t) my_time_zone;
+ localtime_r(&tmp,&tm_tmp);
+ l_time=&tm_tmp;
+ for (loop=0;
+ loop < 3 &&
+ (t->hour != (uint) l_time->tm_hour ||
+ t->minute != (uint) l_time->tm_min);
+ loop++)
+ { /* One check should be enough ? */
+ /* Get difference in days */
+ int days= t->day - l_time->tm_mday;
+ if (days < -1)
+ days= 1; // Month has wrapped
+ else if (days > 1)
+ days= -1;
+ diff=(3600L*(long) (days*24+((int) t->hour - (int) l_time->tm_hour)) +
+ (long) (60*((int) t->minute - (int) l_time->tm_min)));
+ my_time_zone+=diff;
+ tmp+=(time_t) diff;
+ localtime_r(&tmp,&tm_tmp);
+ l_time=&tm_tmp;
+ }
+ /* Fix that if we are in the not existing daylight saving time hour
+ we move the start of the next real hour */
+ if (loop == 3 && t->hour != (uint) l_time->tm_hour)
+ {
+ int days= t->day - l_time->tm_mday;
+ if (days < -1)
+ days=1; // Month has wrapped
+ else if (days > 1)
+ days= -1;
+ diff=(3600L*(long) (days*24+((int) t->hour - (int) l_time->tm_hour))+
+ (long) (60*((int) t->minute - (int) l_time->tm_min)));
+ if (diff == 3600)
+ tmp+=3600 - t->minute*60 - t->second; // Move to next hour
+ else if (diff == -3600)
+ tmp-=t->minute*60 + t->second; // Move to next hour
+ }
+ if ((my_time_zone >=0 ? my_time_zone: -my_time_zone) > 3600L*12)
+ my_time_zone=0; /* Wrong date */
+ pthread_mutex_unlock(&LOCK_timezone);
+ return tmp;
+} /* my_gmt_sec */
+
+
+ /* Some functions to calculate dates */
+
+ /* Calculate nr of day since year 0 in new date-system (from 1615) */
+
+long calc_daynr(uint year,uint month,uint day)
+{
+ long delsum;
+ int temp;
+ DBUG_ENTER("calc_daynr");
+
+ if (year == 0 && month == 0 && day == 0)
+ DBUG_RETURN(0); /* Skipp errors */
+ if (year < 200)
+ {
+ if ((year=year+1900) < 1900+YY_PART_YEAR)
+ year+=100;
+ }
+ delsum= (long) (365L * year+ 31*(month-1) +day);
+ if (month <= 2)
+ year--;
+ else
+ delsum-= (long) (month*4+23)/10;
+ temp=(int) ((year/100+1)*3)/4;
+ DBUG_PRINT("exit",("year: %d month: %d day: %d -> daynr: %ld",
+ year+(month <= 2),month,day,delsum+year/4-temp));
+ DBUG_RETURN(delsum+(int) year/4-temp);
+} /* calc_daynr */
+
+
+ /* Calc weekday from daynr */
+ /* Returns 0 for monday, 1 for tuesday .... */
+
+int calc_weekday(long daynr,bool sunday_first_day_of_week)
+{
+ DBUG_ENTER("calc_weekday");
+ DBUG_RETURN ((int) ((daynr + 5L + (sunday_first_day_of_week ? 1L : 0L)) % 7));
+}
+
+ /* Calc days in one year. works with 0 <= year <= 99 */
+
+uint calc_days_in_year(uint year)
+{
+ return (year & 3) == 0 && (year%100 || (year%400 == 0 && year)) ?
+ 366 : 365;
+}
+
+/* Calculate week. If 'with_year' is not set, then return a week 0-53, where
+ 0 means that it's the last week of the previous year.
+ If 'with_year' is set then the week will always be in the range 1-53 and
+ the year out parameter will contain the year for the week */
+
+uint calc_week(TIME *l_time, bool with_year, bool sunday_first_day_of_week,
+ uint *year)
+{
+ uint days;
+ ulong daynr=calc_daynr(l_time->year,l_time->month,l_time->day);
+ 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)
+ {
+ /* Last week of the previous year */
+ if (!with_year)
+ return 0;
+ with_year=0; // Don't check the week again
+ (*year)--;
+ first_daynr-= (days=calc_days_in_year(*year));
+ weekday= (weekday + 53*7- days) % 7;
+ }
+ if (weekday >= 4)
+ days= daynr - (first_daynr+ (7-weekday));
+ else
+ days= daynr - (first_daynr - weekday);
+ if (with_year && days >= 52*7)
+ {
+ /* Check if we are on the first week of the next year (or week 53) */
+ weekday= (weekday + calc_days_in_year(*year)) % 7;
+ if (weekday < 4)
+ { // We are at first week on next year
+ (*year)++;
+ return 1;
+ }
+ }
+ return days/7+1;
+}
+
+ /* Change a daynr to year, month and day */
+ /* Daynr 0 is returned as date 00.00.00 */
+
+void get_date_from_daynr(long daynr,uint *ret_year,uint *ret_month,
+ uint *ret_day)
+{
+ uint year,temp,leap_day,day_of_year,days_in_year;
+ uchar *month_pos;
+ DBUG_ENTER("get_date_from_daynr");
+
+ if (daynr <= 365L || daynr >= 3652500)
+ { /* Fix if wrong daynr */
+ *ret_year= *ret_month = *ret_day =0;
+ }
+ else
+ {
+ year= (uint) (daynr*100 / 36525L);
+ temp=(((year-1)/100+1)*3)/4;
+ day_of_year=(uint) (daynr - (long) year * 365L) - (year-1)/4 +temp;
+ while (day_of_year > (days_in_year= calc_days_in_year(year)))
+ {
+ day_of_year-=days_in_year;
+ (year)++;
+ }
+ leap_day=0;
+ if (days_in_year == 366)
+ {
+ if (day_of_year > 31+28)
+ {
+ day_of_year--;
+ if (day_of_year == 31+28)
+ leap_day=1; /* Handle leapyears leapday */
+ }
+ }
+ *ret_month=1;
+ for (month_pos= days_in_month ;
+ day_of_year > (uint) *month_pos ;
+ day_of_year-= *(month_pos++), (*ret_month)++)
+ ;
+ *ret_year=year;
+ *ret_day=day_of_year+leap_day;
+ }
+ DBUG_VOID_RETURN;
+}
+
+/* find date from string and put it in vektor
+ Input: pos = "YYMMDD" OR "YYYYMMDD" in any order or
+ "xxxxx YYxxxMMxxxDD xxxx" where xxx is anything exept
+ a number. Month or day mustn't exeed 2 digits, year may be 4 digits.
+*/
+
+
+#ifdef NOT_NEEDED
+
+void find_date(string pos,uint *vek,uint flag)
+{
+ uint length,value;
+ string start;
+ DBUG_ENTER("find_date");
+ DBUG_PRINT("enter",("pos: '%s' flag: %d",pos,flag));
+
+ bzero((char*) vek,sizeof(int)*4);
+ while (*pos && !isdigit(*pos))
+ pos++;
+ length=strlen(pos);
+ for (uint i=0 ; i< 3; i++)
+ {
+ start=pos; value=0;
+ while (isdigit(pos[0]) &&
+ ((pos-start) < 2 || ((pos-start) < 4 && length >= 8 &&
+ !(flag & 3))))
+ {
+ value=value*10 + (uint) (uchar) (*pos - '0');
+ pos++;
+ }
+ vek[flag & 3]=value; flag>>=2;
+ while (*pos && (ispunct(*pos) || isspace(*pos)))
+ pos++;
+ }
+ DBUG_PRINT("exit",("year: %d month: %d day: %d",vek[0],vek[1],vek[2]));
+ DBUG_VOID_RETURN;
+} /* find_date */
+
+
+ /* Outputs YYMMDD if input year < 100 or YYYYMMDD else */
+
+static long calc_daynr_from_week(uint year,uint week,uint day)
+{
+ long daynr;
+ int weekday;
+
+ daynr=calc_daynr(year,1,1);
+ if ((weekday= calc_weekday(daynr,0)) >= 3)
+ daynr+= (7-weekday);
+ else
+ daynr-=weekday;
+
+ return (daynr+week*7+day-8);
+}
+
+void convert_week_to_date(string date,uint flag,uint *res_length)
+{
+ string format;
+ uint year,vek[4];
+
+ find_date(date,vek,(uint) (1*4+2*16)); /* YY-WW-DD */
+ year=vek[0];
+
+ get_date_from_daynr(calc_daynr_from_week(vek[0],vek[1],vek[2]),
+ &vek[0],&vek[1],&vek[2]);
+ *res_length=8;
+ format="%04d%02d%02d";
+ if (year < 100)
+ {
+ vek[0]= vek[0]%100;
+ *res_length=6;
+ format="%02d%02d%02d";
+ }
+ sprintf(date,format,vek[flag & 3],vek[(flag >> 2) & 3],
+ vek[(flag >> 4) & 3]);
+ return;
+}
+
+ /* returns YYWWDD or YYYYWWDD according to input year */
+ /* flag only reflects format of input date */
+
+void convert_date_to_week(string date,uint flag,uint *res_length)
+{
+ uint vek[4],weekday,days,year,week,day;
+ long daynr,first_daynr;
+ char buff[256],*format;
+
+ if (! date[0])
+ {
+ get_date(buff,0,0L); /* Use current date */
+ find_date(buff+2,vek,(uint) (1*4+2*16)); /* YY-MM-DD */
+ }
+ else
+ find_date(date,vek,flag);
+
+ year= vek[0];
+ daynr= calc_daynr(year,vek[1],vek[2]);
+ first_daynr=calc_daynr(year,1,1);
+
+ /* Caculate year and first daynr of year */
+ if (vek[1] == 1 && (weekday=calc_weekday(first_daynr,0)) >= 3 &&
+ vek[2] <= 7-weekday)
+ {
+ if (!year--)
+ year=99;
+ first_daynr=first_daynr-calc_days_in_year(year);
+ }
+ else if (vek[1] == 12 &&
+ (weekday=calc_weekday(first_daynr+calc_days_in_year(year)),0) < 3 &&
+ vek[2] > 31-weekday)
+ {
+ first_daynr=first_daynr+calc_days_in_year(year);
+ if (year++ == 99)
+ year=0;
+ }
+
+ /* Calulate daynr of first day of week 1 */
+ if ((weekday= calc_weekday(first_daynr,0)) >= 3)
+ first_daynr+= (7-weekday);
+ else
+ first_daynr-=weekday;
+
+ days=(int) (daynr-first_daynr);
+ week=days/7+1 ; day=calc_weekday(daynr,0)+1;
+
+ *res_length=8;
+ format="%04d%02d%02d";
+ if (year < 100)
+ {
+ *res_length=6;
+ format="%02d%02d%02d";
+ }
+ sprintf(date,format,year,week,day);
+ return;
+}
+
+#endif
+
+ /* Functions to handle periods */
+
+ulong convert_period_to_month(ulong period)
+{
+ ulong a,b;
+ if (period == 0)
+ return 0L;
+ if ((a=period/100) < YY_PART_YEAR)
+ a+=2000;
+ else if (a < 100)
+ a+=1900;
+ b=period%100;
+ return a*12+b-1;
+}
+
+ulong convert_month_to_period(ulong month)
+{
+ ulong year;
+ if (month == 0L)
+ return 0L;
+ if ((year=month/12) < 100)
+ {
+ year+=(year < YY_PART_YEAR) ? 2000 : 1900;
+ }
+ return year*100+month%12+1;
+}
+
+#ifdef NOT_NEEDED
+
+ulong add_to_period(ulong period,int months)
+{
+ if (period == 0L)
+ return 0L;
+ return convert_month_to_period(convert_period_to_month(period)+months);
+}
+#endif
+
+
+/*****************************************************************************
+** convert a timestamp string to a TIME value.
+** At least the following formats are recogniced (based on number of digits)
+** YYMMDD, YYYYMMDD, YYMMDDHHMMSS, YYYYMMDDHHMMSS
+** YY-MM-DD, YYYY-MM-DD, YY-MM-DD HH.MM.SS
+** Returns the type of string
+*****************************************************************************/
+
+timestamp_type
+str_to_TIME(const char *str, uint length, TIME *l_time,bool fuzzy_date)
+{
+ uint field_length,year_length,digits,i,number_of_fields,date[7];
+ bool date_used=0;
+ const char *pos;
+ const char *end=str+length;
+ DBUG_ENTER("str_to_TIME");
+ DBUG_PRINT("enter",("str: %.*s",length,str));
+
+ for (; !isdigit(*str) && str != end ; str++) ; // Skipp garbage
+ if (str == end)
+ DBUG_RETURN(TIMESTAMP_NONE);
+ /*
+ ** calculate first number of digits.
+ ** If length= 8 or >= 14 then year is of format YYYY.
+ (YYYY-MM-DD, YYYYMMDD, YYYYYMMDDHHMMSS)
+ */
+ for (pos=str; pos != end && isdigit(*pos) ; pos++) ;
+ digits= (uint) (pos-str);
+ year_length= (digits == 4 || digits == 8 || digits >= 14) ? 4 : 2;
+ field_length=year_length-1;
+ for (i=0 ; i < 6 && str != end && isdigit(*str) ; i++)
+ {
+ uint tmp_value=(uint) (uchar) (*str++ - '0');
+ while (str != end && isdigit(str[0]) && field_length--)
+ {
+ tmp_value=tmp_value*10 + (uint) (uchar) (*str - '0');
+ str++;
+ }
+ if ((date[i]=tmp_value))
+ date_used=1; // Found something
+ if (i == 2 && str != end && *str == 'T')
+ str++; // ISO8601: CCYYMMDDThhmmss
+ else
+ {
+ while (str != end && (ispunct(*str) || isspace(*str)))
+ {
+ // Only allow space between days and hours
+ if (isspace(*str) && i != 2)
+ DBUG_RETURN(TIMESTAMP_NONE);
+ str++;
+ }
+ }
+ field_length=1; // Rest fields can only be 2
+ }
+ /* Handle second fractions */
+ if (i == 6 && (uint) (end-str) >= 2 && *str == '.' && isdigit(str[1]))
+ {
+ str++;
+ uint tmp_value=(uint) (uchar) (*str - '0');
+ field_length=3;
+ while (str++ != end && isdigit(str[0]) && field_length--)
+ tmp_value=tmp_value*10 + (uint) (uchar) (*str - '0');
+ date[6]=tmp_value;
+ }
+ else
+ date[6]=0;
+
+ if (year_length == 2)
+ date[0]+= (date[0] < YY_PART_YEAR ? 2000 : 1900);
+ number_of_fields=i;
+ while (i < 6)
+ date[i++]=0;
+ if (number_of_fields < 3 || !date_used || date[1] > 12 ||
+ date[2] > 31 || date[3] > 23 || date[4] > 59 || date[5] > 59 ||
+ !fuzzy_date && (date[1] == 0 || date[2] == 0))
+ {
+ current_thd->cuted_fields++;
+ DBUG_RETURN(TIMESTAMP_NONE);
+ }
+ if (str != end && current_thd->count_cuted_fields)
+ {
+ for ( ; str != end ; str++)
+ {
+ if (!isspace(*str))
+ {
+ current_thd->cuted_fields++;
+ break;
+ }
+ }
+ }
+ l_time->year= date[0];
+ l_time->month= date[1];
+ l_time->day= date[2];
+ l_time->hour= date[3];
+ l_time->minute=date[4];
+ l_time->second=date[5];
+ l_time->second_part=date[6];
+ DBUG_RETURN(l_time->time_type=
+ (number_of_fields <= 3 ? TIMESTAMP_DATE : TIMESTAMP_FULL));
+}
+
+
+time_t str_to_timestamp(const char *str,uint length)
+{
+ TIME l_time;
+ if (str_to_TIME(str,length,&l_time,0) == TIMESTAMP_NONE)
+ return(0);
+ if (l_time.year >= TIMESTAMP_MAX_YEAR || l_time.year < 1900+YY_PART_YEAR)
+ {
+ current_thd->cuted_fields++;
+ return(0);
+ }
+ return(my_gmt_sec(&l_time));
+}
+
+
+longlong str_to_datetime(const char *str,uint length,bool fuzzy_date)
+{
+ TIME l_time;
+ if (str_to_TIME(str,length,&l_time,fuzzy_date) == TIMESTAMP_NONE)
+ return(0);
+ return (longlong) (l_time.year*LL(10000000000) +
+ l_time.month*LL(100000000)+
+ l_time.day*LL(1000000)+
+ l_time.hour*LL(10000)+
+ (longlong) (l_time.minute*100+l_time.second));
+}
+
+
+/*****************************************************************************
+** convert a time string to a (ulong) value.
+** Can use all full timestamp formats and
+** [-] DAYS [H]H:MM:SS, [H]H:MM:SS, [M]M:SS, [H]HMMSS, [M]MSS or [S]S
+** There may be an optional [.second_part] after seconds
+*****************************************************************************/
+
+bool str_to_time(const char *str,uint length,TIME *l_time)
+{
+ long date[5],value;
+ const char *end=str+length;
+ bool found_days,found_hours;
+ uint state;
+
+ l_time->neg=0;
+ for (; !isdigit(*str) && *str != '-' && str != end ; str++)
+ length--;
+ if (str != end && *str == '-')
+ {
+ l_time->neg=1;
+ str++;
+ length--;
+ }
+ if (str == end)
+ return 1;
+
+ /* Check first if this is a full TIMESTAMP */
+ if (length >= 12)
+ { // Probably full timestamp
+ if (str_to_TIME(str,length,l_time,1) == TIMESTAMP_FULL)
+ return 0; // Was an ok timestamp
+ }
+
+ /* Not a timestamp. Try to get this as a DAYS_TO_SECOND string */
+ for (value=0; str != end && isdigit(*str) ; str++)
+ value=value*10L + (long) (*str - '0');
+
+ if (*str == ' ')
+ {
+ while (++str != end && str[0] == ' ') ;
+ str--;
+ }
+
+ LINT_INIT(state);
+ found_days=found_hours=0;
+ if ((uint) (end-str) > 1 && (*str == ' ' && isdigit(str[1])))
+ { // days !
+ date[0]=value;
+ state=1; // Assume next is hours
+ found_days=1;
+ str++; // Skipp space;
+ }
+ else if ((end-str) > 1 && *str == ':' && isdigit(str[1]))
+ {
+ date[0]=0; // Assume we found hours
+ date[1]=value;
+ state=2;
+ found_hours=1;
+ str++; // skipp ':'
+ }
+ else
+ {
+ /* String given as one number; assume HHMMSS format */
+ date[0]= 0;
+ date[1]= value/10000;
+ date[2]= value/100 % 100;
+ date[3]= value % 100;
+ state=4;
+ goto fractional;
+ }
+
+ /* Read hours, minutes and seconds */
+ for (;;)
+ {
+ for (value=0; str != end && isdigit(*str) ; str++)
+ value=value*10L + (long) (*str - '0');
+ date[state++]=value;
+ if (state == 4 || (end-str) < 2 || *str != ':' || !isdigit(str[1]))
+ break;
+ str++; // Skipp ':'
+ }
+
+ if (state != 4)
+ { // Not HH:MM:SS
+ /* Fix the date to assume that seconds was given */
+ if (!found_hours && !found_days)
+ {
+ bmove_upp((char*) (date+4), (char*) (date+state),
+ sizeof(long)*(state-1));
+ bzero((char*) date, sizeof(long)*(4-state));
+ }
+ else
+ bzero((char*) (date+state), sizeof(long)*(4-state));
+ }
+
+ fractional:
+ /* Get fractional second part */
+ if ((end-str) >= 2 && *str == '.' && isdigit(str[1]))
+ {
+ uint field_length=3;
+ str++; value=(uint) (uchar) (*str - '0');
+ while (++str != end && isdigit(str[0]) && field_length--)
+ value=value*10 + (uint) (uchar) (*str - '0');
+ date[4]=value;
+ }
+ else
+ date[4]=0;
+
+ /* Some simple checks */
+ if (date[2] >= 60 || date[3] >= 60)
+ {
+ current_thd->cuted_fields++;
+ return 1;
+ }
+ l_time->month=0;
+ l_time->day=date[0];
+ l_time->hour=date[1];
+ l_time->minute=date[2];
+ l_time->second=date[3];
+ l_time->second_part=date[4];
+
+ /* Check if there is garbage at end of the TIME specification */
+ if (str != end && current_thd->count_cuted_fields)
+ {
+ do
+ {
+ if (!isspace(*str))
+ {
+ current_thd->cuted_fields++;
+ break;
+ }
+ } while (++str != end);
+ }
+ return 0;
+}
diff --git a/sql/udf_example.cc b/sql/udf_example.cc
new file mode 100644
index 00000000000..9d94006b281
--- /dev/null
+++ b/sql/udf_example.cc
@@ -0,0 +1,868 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/*
+** example file of UDF (user definable functions) that are dynamicly loaded
+** into the standard mysqld core.
+**
+** The functions name, type and shared library is saved in the new system
+** table 'func'. To be able to create new functions one must have write
+** privilege for the database 'mysql'. If one starts MySQL with
+** --skip-grant, then UDF initialization will also be skipped.
+**
+** Syntax for the new commands are:
+** create function <function_name> returns {string|real|integer}
+** soname <name_of_shared_library>
+** drop function <function_name>
+**
+** Each defined function may have a xxxx_init function and a xxxx_deinit
+** function. The init function should alloc memory for the function
+** and tell the main function about the max length of the result
+** (for string functions), number of decimals (for double functions) and
+** if the result may be a null value.
+**
+** If a function sets the 'error' argument to 1 the function will not be
+** called anymore and mysqld will return NULL for all calls to this copy
+** of the function.
+**
+** All strings arguments to functions are given as string pointer + length
+** to allow handling of binary data.
+** Remember that all functions must be thread safe. This means that one is not
+** allowed to alloc any global or static variables that changes!
+** If one needs memory one should alloc this in the init function and free
+** this on the __deinit function.
+**
+** Note that the init and __deinit functions are only called once per
+** SQL statement while the value function may be called many times
+**
+** Function 'metaphon' returns a metaphon string of the string argument.
+** This is something like a soundex string, but it's more tuned for English.
+**
+** Function 'myfunc_double' returns summary of codes of all letters
+** of arguments divided by summary length of all its arguments.
+**
+** Function 'myfunc_int' returns summary length of all its arguments.
+**
+** On the end is a couple of functions that converts hostnames to ip and
+** vice versa.
+**
+** A dynamicly loadable file should be compiled sharable
+** (something like: gcc -shared -o udf_example.so myfunc.cc).
+** You can easily get all switches right by doing:
+** cd sql ; make udf_example.o
+** Take the compile line that make writes, remove the '-c' near the end of
+** the line and add -o udf_example.so to the end of the compile line.
+** The resulting library (udf_example.so) should be copied to some dir
+** searched by ld. (/usr/lib ?)
+**
+** After the library is made one must notify mysqld about the new
+** functions with the commands:
+**
+** CREATE FUNCTION metaphon RETURNS STRING SONAME "udf_example.so";
+** CREATE FUNCTION myfunc_double RETURNS REAL SONAME "udf_example.so";
+** CREATE FUNCTION myfunc_int RETURNS INTEGER SONAME "udf_example.so";
+** CREATE FUNCTION lookup RETURNS STRING SONAME "udf_example.so";
+** CREATE FUNCTION reverse_lookup RETURNS STRING SONAME "udf_example.so";
+** CREATE AGGREGATE FUNCTION avgcost RETURNS REAL SONAME "udf_example.so";
+**
+** After this the functions will work exactly like native MySQL functions.
+** Functions should be created only once.
+**
+** The functions can be deleted by:
+**
+** DROP FUNCTION metaphon;
+** DROP FUNCTION myfunc_double;
+** DROP FUNCTION myfunc_int;
+** DROP FUNCTION lookup;
+** DROP FUNCTION reverse_lookup;
+** DROP FUNCTION avgcost;
+**
+** The CREATE FUNCTION and DROP FUNCTION update the func@mysql table. All
+** Active function will be reloaded on every restart of server
+** (if --skip-grant-tables is not given)
+**
+*/
+
+#ifdef STANDARD
+#include <stdio.h>
+#include <string.h>
+#else
+#include <global.h>
+#include <my_sys.h>
+#endif
+#include <mysql.h>
+#include <m_ctype.h>
+#include <m_string.h> // To get strmov()
+
+#ifdef HAVE_DLOPEN
+
+/* These must be right or mysqld will not find the symbol! */
+
+extern "C" {
+my_bool metaphon_init(UDF_INIT *initid, UDF_ARGS *args, char *message);
+void metaphon_deinit(UDF_INIT *initid);
+char *metaphon(UDF_INIT *initid, UDF_ARGS *args, char *result,
+ unsigned long *length, char *is_null, char *error);
+my_bool myfunc_double_init(UDF_INIT *, UDF_ARGS *args, char *message);
+double myfunc_double(UDF_INIT *initid, UDF_ARGS *args, char *is_null,
+ char *error);
+longlong myfunc_int(UDF_INIT *initid, UDF_ARGS *args, char *is_null,
+ char *error);
+}
+
+
+/*************************************************************************
+** Example of init function
+** Arguments:
+** initid Points to a structure that the init function should fill.
+** This argument is given to all other functions.
+** my_bool maybe_null 1 if function can return NULL
+** Default value is 1 if any of the arguments
+** is declared maybe_null.
+** unsigned int decimals Number of decimals.
+** Default value is max decimals in any of the
+** arguments.
+** unsigned int max_length Length of string result.
+** The default value for integer functions is 21
+** The default value for real functions is 13+
+** default number of decimals.
+** The default value for string functions is
+** the longest string argument.
+** char *ptr; A pointer that the function can use.
+**
+** args Points to a structure which contains:
+** unsigned int arg_count Number of arguments
+** enum Item_result *arg_type Types for each argument.
+** Types are STRING_RESULT, REAL_RESULT
+** and INT_RESULT.
+** char **args Pointer to constant arguments.
+** Contains 0 for not constant argument.
+** unsigned long *lengths; max string length for each argument
+** char *maybe_null Information of which arguments
+** may be NULL
+**
+** message Error message that should be passed to the user on fail.
+** The message buffer is MYSQL_ERRMSG_SIZE big, but one should
+** try to keep the error message less than 80 bytes long!
+**
+** This function should return 1 if something goes wrong. In this case
+** message should contain something usefull!
+**************************************************************************/
+
+#define MAXMETAPH 8
+
+my_bool metaphon_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ if (args->arg_count != 1 || args->arg_type[0] != STRING_RESULT)
+ {
+ strcpy(message,"Wrong arguments to metaphon; Use the source");
+ return 1;
+ }
+ initid->max_length=MAXMETAPH;
+ return 0;
+}
+
+/****************************************************************************
+** Deinit function. This should free all resources allocated by
+** this function.
+** Arguments:
+** initid Return value from xxxx_init
+****************************************************************************/
+
+
+void metaphon_deinit(UDF_INIT *initid)
+{
+}
+
+/***************************************************************************
+** UDF string function.
+** Arguments:
+** initid Structure filled by xxx_init
+** args The same structure as to xxx_init. This structure
+** contains values for all parameters.
+** Note that the functions MUST check and convert all
+** to the type it wants! Null values are represented by
+** a NULL pointer
+** result Possible buffer to save result. At least 255 byte long.
+** length Pointer to length of the above buffer. In this the function
+** should save the result length
+** is_null If the result is null, one should store 1 here.
+** error If something goes fatally wrong one should store 1 here.
+**
+** This function should return a pointer to the result string.
+** Normally this is 'result' but may also be an alloced string.
+***************************************************************************/
+
+/* Character coding array */
+static char codes[26] = {
+ 1,16,4,16,9,2,4,16,9,2,0,2,2,2,1,4,0,2,4,4,1,0,0,0,8,0
+ /* A B C D E F G H I J K L M N O P Q R S T U V W X Y Z*/
+ };
+
+/*--- Macros to access character coding array -------------*/
+
+#define ISVOWEL(x) (codes[(x) - 'A'] & 1) /* AEIOU */
+
+ /* Following letters are not changed */
+#define NOCHANGE(x) (codes[(x) - 'A'] & 2) /* FJLMNR */
+
+ /* These form diphthongs when preceding H */
+#define AFFECTH(x) (codes[(x) - 'A'] & 4) /* CGPST */
+
+ /* These make C and G soft */
+#define MAKESOFT(x) (codes[(x) - 'A'] & 8) /* EIY */
+
+ /* These prevent GH from becoming F */
+#define NOGHTOF(x) (codes[(x) - 'A'] & 16) /* BDH */
+
+
+char *metaphon(UDF_INIT *initid, UDF_ARGS *args, char *result,
+ unsigned long *length, char *is_null, char *error)
+{
+ const char *word=args->args[0];
+ if (!word) // Null argument
+ {
+ *is_null=1;
+ return 0;
+ }
+ const char *w_end=word+args->lengths[0];
+ char *org_result=result;
+
+ char *n, *n_start, *n_end; /* pointers to string */
+ char *metaph, *metaph_end; /* pointers to metaph */
+ char ntrans[32]; /* word with uppercase letters */
+ char newm[8]; /* new metaph for comparison */
+ int KSflag; /* state flag for X to KS */
+
+ /*--------------------------------------------------------
+ * Copy word to internal buffer, dropping non-alphabetic
+ * characters and converting to uppercase.
+ *-------------------------------------------------------*/
+
+ for ( n = ntrans + 1, n_end = ntrans + sizeof(ntrans)-2;
+ word != w_end && n < n_end; word++ )
+ if ( isalpha ( *word ))
+ *n++ = toupper ( *word );
+
+ if ( n == ntrans + 1 ) /* return empty string if 0 bytes */
+ {
+ *length=0;
+ return result;
+ }
+ n_end = n; /* set n_end to end of string */
+ ntrans[0] = 'Z'; /* ntrans[0] should be a neutral char */
+ n[0]=n[1]=0; /* pad with nulls */
+ n = ntrans + 1; /* assign pointer to start */
+
+ /*------------------------------------------------------------
+ * check for all prefixes:
+ * PN KN GN AE WR WH and X at start.
+ *----------------------------------------------------------*/
+
+ switch ( *n ) {
+ case 'P':
+ case 'K':
+ case 'G':
+ if ( n[1] == 'N')
+ *n++ = 0;
+ break;
+ case 'A':
+ if ( n[1] == 'E')
+ *n++ = 0;
+ break;
+ case 'W':
+ if ( n[1] == 'R' )
+ *n++ = 0;
+ else
+ if ( *(n + 1) == 'H')
+ {
+ n[1] = *n;
+ *n++ = 0;
+ }
+ break;
+ case 'X':
+ *n = 'S';
+ break;
+ }
+
+ /*------------------------------------------------------------
+ * Now, loop step through string, stopping at end of string
+ * or when the computed metaph is MAXMETAPH characters long
+ *----------------------------------------------------------*/
+
+ KSflag = 0; /* state flag for KS translation */
+
+ for ( metaph_end = result + MAXMETAPH, n_start = n;
+ n <= n_end && result < metaph_end; n++ )
+ {
+
+ if ( KSflag )
+ {
+ KSflag = 0;
+ *result++ = *n;
+ }
+ else
+ {
+ /* drop duplicates except for CC */
+ if ( *( n - 1 ) == *n && *n != 'C' )
+ continue;
+
+ /* check for F J L M N R or first letter vowel */
+ if ( NOCHANGE ( *n ) ||
+ ( n == n_start && ISVOWEL ( *n )))
+ *result++ = *n;
+ else
+ switch ( *n ) {
+ case 'B': /* check for -MB */
+ if ( n < n_end || *( n - 1 ) != 'M' )
+ *result++ = *n;
+ break;
+
+ case 'C': /* C = X ("sh" sound) in CH and CIA */
+ /* = S in CE CI and CY */
+ /* dropped in SCI SCE SCY */
+ /* else K */
+ if ( *( n - 1 ) != 'S' ||
+ !MAKESOFT ( n[1]))
+ {
+ if ( n[1] == 'I' && n[2] == 'A' )
+ *result++ = 'X';
+ else
+ if ( MAKESOFT ( n[1]))
+ *result++ = 'S';
+ else
+ if ( n[1] == 'H' )
+ *result++ = (( n == n_start &&
+ !ISVOWEL ( n[2])) ||
+ *( n - 1 ) == 'S' ) ?
+ (char)'K' : (char)'X';
+ else
+ *result++ = 'K';
+ }
+ break;
+
+ case 'D': /* J before DGE, DGI, DGY, else T */
+ *result++ =
+ ( n[1] == 'G' &&
+ MAKESOFT ( n[2])) ?
+ (char)'J' : (char)'T';
+ break;
+
+ case 'G': /* complicated, see table in text */
+ if (( n[1] != 'H' || ISVOWEL ( n[2]))
+ && (
+ n[1] != 'N' ||
+ (
+ (n + 1) < n_end &&
+ (
+ n[2] != 'E' ||
+ *( n + 3 ) != 'D'
+ )
+ )
+ )
+ && (
+ *( n - 1 ) != 'D' ||
+ !MAKESOFT ( n[1])
+ )
+ )
+ *result++ =
+ ( MAKESOFT ( *( n + 1 )) &&
+ n[2] != 'G' ) ?
+ (char)'J' : (char)'K';
+ else
+ if( n[1] == 'H' &&
+ !NOGHTOF( *( n - 3 )) &&
+ *( n - 4 ) != 'H')
+ *result++ = 'F';
+ break;
+
+ case 'H': /* H if before a vowel and not after */
+ /* C, G, P, S, T */
+
+ if ( !AFFECTH ( *( n - 1 )) &&
+ ( !ISVOWEL ( *( n - 1 )) ||
+ ISVOWEL ( n[1])))
+ *result++ = 'H';
+ break;
+
+ case 'K': /* K = K, except dropped after C */
+ if ( *( n - 1 ) != 'C')
+ *result++ = 'K';
+ break;
+
+ case 'P': /* PH = F, else P = P */
+ *result++ = *( n + 1 ) == 'H'
+ ? (char)'F' : (char)'P';
+ break;
+ case 'Q': /* Q = K (U after Q is already gone */
+ *result++ = 'K';
+ break;
+
+ case 'S': /* SH, SIO, SIA = X ("sh" sound) */
+ *result++ = ( n[1] == 'H' ||
+ ( *(n + 1) == 'I' &&
+ ( n[2] == 'O' ||
+ n[2] == 'A'))) ?
+ (char)'X' : (char)'S';
+ break;
+
+ case 'T': /* TIO, TIA = X ("sh" sound) */
+ /* TH = 0, ("th" sound ) */
+ if( *( n + 1 ) == 'I' && ( n[2] == 'O'
+ || n[2] == 'A') )
+ *result++ = 'X';
+ else
+ if ( n[1] == 'H' )
+ *result++ = '0';
+ else
+ if ( *( n + 1) != 'C' || n[2] != 'H')
+ *result++ = 'T';
+ break;
+
+ case 'V': /* V = F */
+ *result++ = 'F';
+ break;
+
+ case 'W': /* only exist if a vowel follows */
+ case 'Y':
+ if ( ISVOWEL ( n[1]))
+ *result++ = *n;
+ break;
+
+ case 'X': /* X = KS, except at start */
+ if ( n == n_start )
+ *result++ = 'S';
+ else
+ {
+ *result++ = 'K'; /* insert K, then S */
+ KSflag = 1; /* this flag will cause S to be
+ inserted on next pass thru loop */
+ }
+ break;
+
+ case 'Z':
+ *result++ = 'S';
+ break;
+ }
+ }
+ }
+ *length= (ulong) (result - org_result);
+ return org_result;
+}
+
+
+/***************************************************************************
+** UDF double function.
+** Arguments:
+** initid Structure filled by xxx_init
+** args The same structure as to xxx_init. This structure
+** contains values for all parameters.
+** Note that the functions MUST check and convert all
+** to the type it wants! Null values are represented by
+** a NULL pointer
+** is_null If the result is null, one should store 1 here.
+** error If something goes fatally wrong one should store 1 here.
+**
+** This function should return the result.
+***************************************************************************/
+
+my_bool myfunc_double_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ if (!args->arg_count)
+ {
+ strcpy(message,"myfunc_double must have at least on argument");
+ return 1;
+ }
+ /*
+ ** As this function wants to have everything as strings, force all arguments
+ ** to strings.
+ */
+ for (uint i=0 ; i < args->arg_count; i++)
+ args->arg_type[i]=STRING_RESULT;
+ initid->maybe_null=1; // The result may be null
+ initid->decimals=2; // We want 2 decimals in the result
+ initid->max_length=6; // 3 digits + . + 2 decimals
+ return 0;
+}
+
+
+double myfunc_double(UDF_INIT *initid, UDF_ARGS *args, char *is_null,
+ char *error)
+{
+ unsigned long val = 0;
+ unsigned long v = 0;
+
+ for (uint i = 0; i < args->arg_count; i++)
+ {
+ if (args->args[i] == NULL)
+ continue;
+ val += args->lengths[i];
+ for (uint j=args->lengths[i] ; j-- > 0 ;)
+ v += args->args[i][j];
+ }
+ if (val)
+ return (double) v/ (double) val;
+ *is_null=1;
+ return 0.0;
+}
+
+
+/***************************************************************************
+** UDF long long function.
+** Arguments:
+** initid Return value from xxxx_init
+** args The same structure as to xxx_init. This structure
+** contains values for all parameters.
+** Note that the functions MUST check and convert all
+** to the type it wants! Null values are represented by
+** a NULL pointer
+** is_null If the result is null, one should store 1 here.
+** error If something goes fatally wrong one should store 1 here.
+**
+** This function should return the result as a long long
+***************************************************************************/
+
+long long myfunc_int(UDF_INIT *initid, UDF_ARGS *args, char *is_null,
+ char *error)
+{
+ long long val = 0;
+ for (uint i = 0; i < args->arg_count; i++)
+ {
+ if (args->args[i] == NULL)
+ continue;
+ switch (args->arg_type[i]) {
+ case STRING_RESULT: // Add string lengths
+ val += args->lengths[i];
+ break;
+ case INT_RESULT: // Add numbers
+ val += *((long long*) args->args[i]);
+ break;
+ case REAL_RESULT: // Add numers as long long
+ val += (long long) *((double*) args->args[i]);
+ break;
+ }
+ }
+ return val;
+}
+
+
+/****************************************************************************
+** Some functions that handles IP and hostname conversions
+** The orignal function was from Zeev Suraski.
+**
+** CREATE FUNCTION lookup RETURNS STRING SONAME "udf_example.so";
+** CREATE FUNCTION reverse_lookup RETURNS STRING SONAME "udf_example.so";
+**
+****************************************************************************/
+
+#if defined(HAVE_GETHOSTBYADDR_R) && defined(HAVE_SOLARIS_STYLE_GETHOST)
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+extern "C" {
+my_bool lookup_init(UDF_INIT *initid, UDF_ARGS *args, char *message);
+char *lookup(UDF_INIT *initid, UDF_ARGS *args, char *result,
+ unsigned long *length, char *null_value, char *error);
+my_bool reverse_lookup_init(UDF_INIT *initid, UDF_ARGS *args, char *message);
+char *reverse_lookup(UDF_INIT *initid, UDF_ARGS *args, char *result,
+ unsigned long *length, char *null_value, char *error);
+}
+
+
+/****************************************************************************
+** lookup IP for an hostname.
+**
+** This code assumes that gethostbyname_r exists and inet_ntoa() is thread
+** safe (As it is in Solaris)
+****************************************************************************/
+
+
+my_bool lookup_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ if (args->arg_count != 1 || args->arg_type[0] != STRING_RESULT)
+ {
+ strmov(message,"Wrong arguments to lookup; Use the source");
+ return 1;
+ }
+ initid->max_length=11;
+ initid->maybe_null=1;
+ return 0;
+}
+
+char *lookup(UDF_INIT *initid, UDF_ARGS *args, char *result,
+ unsigned long *res_length, char *null_value, char *error)
+{
+ uint length;
+ int tmp_errno;
+ char name_buff[256],hostname_buff[2048];
+ struct hostent tmp_hostent,*hostent;
+
+ if (!args->args[0] || !(length=args->lengths[0]))
+ {
+ *null_value=1;
+ return 0;
+ }
+ if (length >= sizeof(name_buff))
+ length=sizeof(name_buff)-1;
+ memcpy(name_buff,args->args[0],length);
+ name_buff[length]=0;
+
+ if (!(hostent=gethostbyname_r(name_buff,&tmp_hostent,hostname_buff,
+ sizeof(hostname_buff), &tmp_errno)))
+ {
+ *null_value=1;
+ return 0;
+ }
+ struct in_addr in;
+ memcpy_fixed((char*) &in,(char*) *hostent->h_addr_list, sizeof(in.s_addr));
+ *res_length= (ulong) (strmov(result, inet_ntoa(in)) - result);
+ return result;
+}
+
+
+/****************************************************************************
+** return hostname for an IP number.
+** The functions can take as arguments a string "xxx.xxx.xxx.xxx" or
+** four numbers.
+****************************************************************************/
+
+my_bool reverse_lookup_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ if (args->arg_count == 1)
+ args->arg_type[0]= STRING_RESULT;
+ else if (args->arg_count == 4)
+ args->arg_type[0]=args->arg_type[1]=args->arg_type[2]=args->arg_type[3]=
+ INT_RESULT;
+ else
+ {
+ strmov(message,
+ "Wrong number of arguments to reverse_lookup; Use the source");
+ return 1;
+ }
+ initid->max_length=32;
+ initid->maybe_null=1;
+ return 0;
+}
+
+
+char *reverse_lookup(UDF_INIT *initid, UDF_ARGS *args, char *result,
+ unsigned long *res_length, char *null_value, char *error)
+{
+ char name_buff[256];
+ struct hostent tmp_hostent;
+ uint length;
+
+ if (args->arg_count == 4)
+ {
+ if (!args->args[0] || !args->args[1] ||!args->args[2] ||!args->args[3])
+ {
+ *null_value=1;
+ return 0;
+ }
+ sprintf(result,"%d.%d.%d.%d",
+ (int) *((long long*) args->args[0]),
+ (int) *((long long*) args->args[1]),
+ (int) *((long long*) args->args[2]),
+ (int) *((long long*) args->args[3]));
+ }
+ else
+ { // string argument
+ if (!args->args[0]) // Return NULL for NULL values
+ {
+ *null_value=1;
+ return 0;
+ }
+ length=args->lengths[0];
+ if (length >= (uint) *res_length-1)
+ length=(uint) *res_length;
+ memcpy(result,args->args[0],length);
+ result[length]=0;
+ }
+
+ unsigned long taddr = inet_addr(result);
+ if (taddr == (unsigned long) -1L)
+ {
+ *null_value=1;
+ return 0;
+ }
+ struct hostent *hp;
+ int tmp_errno;
+ if (!(hp=gethostbyaddr_r((char*) &taddr,sizeof(taddr), AF_INET,
+ &tmp_hostent, name_buff,sizeof(name_buff),
+ &tmp_errno)))
+ {
+ *null_value=1;
+ return 0;
+ }
+ *res_length=(ulong) (strmov(result,hp->h_name) - result);
+ return result;
+}
+
+/*
+** Syntax for the new aggregate commands are:
+** create aggregate function <function_name> returns {string|real|integer}
+** soname <name_of_shared_library>
+**
+** Syntax for avgcost: avgcost( t.quantity, t.price )
+** with t.quantity=integer, t.price=double
+** (this example is provided by Andreas F. Bobak <bobak@relog.ch>)
+*/
+
+extern "C" {
+my_bool avgcost_init( UDF_INIT* initid, UDF_ARGS* args, char* message );
+void avgcost_deinit( UDF_INIT* initid );
+void avgcost_reset( UDF_INIT* initid, UDF_ARGS* args, char* is_null, char *error );
+void avgcost_add( UDF_INIT* initid, UDF_ARGS* args, char* is_null, char *error );
+double avgcost( UDF_INIT* initid, UDF_ARGS* args, char* is_null, char *error );
+}
+
+struct avgcost_data
+{
+ unsigned long long count;
+ long long totalquantity;
+ double totalprice;
+};
+
+
+/*
+** Average Cost Aggregate Function.
+*/
+my_bool
+avgcost_init( UDF_INIT* initid, UDF_ARGS* args, char* message )
+{
+ struct avgcost_data* data;
+
+ if (args->arg_count != 2)
+ {
+ strcpy(
+ message,
+ "wrong number of arguments: AVGCOST() requires two arguments"
+ );
+ return 1;
+ }
+
+ if ((args->arg_type[0] != INT_RESULT) && (args->arg_type[1] != REAL_RESULT) )
+ {
+ strcpy(
+ message,
+ "wrong argument type: AVGCOST() requires an INT and a REAL"
+ );
+ return 1;
+ }
+
+ /*
+ ** force arguments to double.
+ */
+ /*args->arg_type[0] = REAL_RESULT;
+ args->arg_type[1] = REAL_RESULT;*/
+
+ initid->maybe_null = 0; // The result may be null
+ initid->decimals = 4; // We want 4 decimals in the result
+ initid->max_length = 20; // 6 digits + . + 10 decimals
+
+ data = new struct avgcost_data;
+ data->totalquantity = 0;
+ data->totalprice = 0.0;
+
+ initid->ptr = (char*)data;
+
+ return 0;
+}
+
+void
+avgcost_deinit( UDF_INIT* initid )
+{
+ delete initid->ptr;
+}
+
+void
+avgcost_reset( UDF_INIT* initid, UDF_ARGS* args, char* is_null, char* message )
+{
+ struct avgcost_data* data = (struct avgcost_data*)initid->ptr;
+ data->totalprice = 0.0;
+ data->totalquantity = 0;
+ data->count = 0;
+
+ *is_null = 0;
+ avgcost_add( initid, args, is_null, message );
+}
+
+
+void
+avgcost_add( UDF_INIT* initid, UDF_ARGS* args, char* is_null, char* message )
+{
+ if (args->args[0] && args->args[1])
+ {
+ struct avgcost_data* data = (struct avgcost_data*)initid->ptr;
+ long long quantity = *((long long*)args->args[0]);
+ long long newquantity = data->totalquantity + quantity;
+ double price = *((double*)args->args[1]);
+
+ data->count++;
+
+ if ( ((data->totalquantity >= 0) && (quantity < 0))
+ || ((data->totalquantity < 0) && (quantity > 0)) )
+ {
+ /*
+ ** passing from + to - or from - to +
+ */
+ if ( ((quantity < 0) && (newquantity < 0))
+ || ((quantity > 0) && (newquantity > 0)) )
+ {
+ data->totalprice = price * double(newquantity);
+ }
+ /*
+ ** sub q if totalq > 0
+ ** add q if totalq < 0
+ */
+ else
+ {
+ price = data->totalprice / double(data->totalquantity);
+ data->totalprice = price * double(newquantity);
+ }
+ data->totalquantity = newquantity;
+ }
+ else
+ {
+ data->totalquantity += quantity;
+ data->totalprice += price * double(quantity);
+ }
+
+ if (data->totalquantity == 0)
+ data->totalprice = 0.0;
+ }
+}
+
+
+double
+avgcost( UDF_INIT* initid, UDF_ARGS* args, char* is_null, char* error )
+{
+ struct avgcost_data* data = (struct avgcost_data*)initid->ptr;
+ if (!data->count || !data->totalquantity)
+ {
+ *is_null = 1;
+ return 0.0;
+ }
+
+ *is_null = 0;
+ return data->totalprice/double(data->totalquantity);
+}
+
+#endif // defined(HAVE_GETHOSTBYADDR_R) && defined(HAVE_SOLARIS_STYLE_GETHOST)
+#endif /* HAVE_DLOPEN */
diff --git a/sql/unireg.cc b/sql/unireg.cc
new file mode 100644
index 00000000000..611a4f04ec9
--- /dev/null
+++ b/sql/unireg.cc
@@ -0,0 +1,581 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 create a unireg form-file from a FIELD and a fieldname-fieldinfo
+ struct.
+ In the following functions FIELD * is a ordinary field-structure with
+ the following exeptions:
+ sc_length,typepos,row,kol,dtype,regnr and field nead not to be set.
+ str is a (long) to record position where 0 is the first position.
+*/
+
+#define USES_TYPES
+#include "mysql_priv.h"
+#include <m_ctype.h>
+
+#define FCOMP 11 /* Byte per packat f{lt */
+
+static uchar * pack_screens(List<create_field> &create_fields,
+ uint *info_length, uint *screens, bool small_file);
+static uint pack_keys(uchar *keybuff,uint key_count, KEY *key_info);
+static bool pack_header(uchar *forminfo, enum db_type table_type,
+ List<create_field> &create_fields,
+ uint info_length, uint screens, uint table_options,
+ handler *file);
+static uint get_interval_id(uint *int_count,List<create_field> &create_fields,
+ create_field *last_field);
+static bool pack_fields(File file, List<create_field> &create_fields);
+static bool make_empty_rec(int file, enum db_type table_type,
+ uint table_options,
+ List<create_field> &create_fields,
+ uint reclength,uint null_fields);
+
+
+int rea_create_table(my_string file_name,
+ HA_CREATE_INFO *create_info,
+ List<create_field> &create_fields,
+ uint keys, KEY *key_info)
+{
+ uint reclength,info_length,screens,key_info_length,maxlength,null_fields;
+ File file;
+ ulong filepos;
+ uchar fileinfo[64],forminfo[288],*keybuff;
+ TYPELIB formnames;
+ uchar *screen_buff;
+ handler *db_file;
+ DBUG_ENTER("rea_create_table");
+
+ formnames.type_names=0;
+ if (!(screen_buff=pack_screens(create_fields,&info_length,&screens,0)))
+ DBUG_RETURN(1);
+ db_file=get_new_handler((TABLE*) 0, create_info->db_type);
+ if (pack_header(forminfo, create_info->db_type,create_fields,info_length,
+ screens, create_info->table_options, db_file))
+ {
+ NET *net=my_pthread_getspecific_ptr(NET*,THR_NET);
+ my_free((gptr) screen_buff,MYF(0));
+ if (net->last_errno != ER_TOO_MANY_FIELDS)
+ DBUG_RETURN(1);
+
+ // Try again without UNIREG screens (to get more columns)
+ net->last_error[0]=0;
+ if (!(screen_buff=pack_screens(create_fields,&info_length,&screens,1)))
+ DBUG_RETURN(1);
+ if (pack_header(forminfo, create_info->db_type, create_fields,info_length,
+ screens, create_info->table_options, db_file))
+ {
+ my_free((gptr) screen_buff,MYF(0));
+ DBUG_RETURN(1);
+ }
+ }
+ reclength=uint2korr(forminfo+266);
+ null_fields=uint2korr(forminfo+282);
+
+ if ((file=create_frm(file_name, reclength, fileinfo,
+ create_info, keys)) < 0)
+ {
+ my_free((gptr) screen_buff,MYF(0));
+ DBUG_RETURN(1);
+ }
+
+ uint key_buff_length=uint2korr(fileinfo+14);
+ keybuff=(uchar*) my_alloca(key_buff_length);
+ key_info_length=pack_keys(keybuff,keys,key_info);
+ VOID(get_form_pos(file,fileinfo,&formnames));
+ if (!(filepos=make_new_entry(file,fileinfo,&formnames,"")))
+ goto err;
+ maxlength=(uint) next_io_size((ulong) (uint2korr(forminfo)+1000));
+ int2store(forminfo+2,maxlength);
+ int4store(fileinfo+10,(ulong) (filepos+maxlength));
+ fileinfo[26]= (uchar) test((create_info->max_rows == 1) &&
+ (create_info->min_rows == 1) && (keys == 0));
+ int2store(fileinfo+28,key_info_length);
+ strnmov((char*) forminfo+47,create_info->comment ? create_info->comment : "",
+ 60);
+ forminfo[46]=(uchar) strlen((char*)forminfo+47); // Length of comment
+
+ if (my_pwrite(file,(byte*) fileinfo,64,0L,MYF_RW) ||
+ my_pwrite(file,(byte*) keybuff,key_info_length,
+ (ulong) uint2korr(fileinfo+6),MYF_RW))
+ goto err;
+ VOID(my_seek(file,
+ (ulong) uint2korr(fileinfo+6)+ (ulong) key_buff_length,
+ MY_SEEK_SET,MYF(0)));
+ if (make_empty_rec(file,create_info->db_type,create_info->table_options,
+ create_fields,reclength,null_fields))
+ goto err;
+
+ VOID(my_seek(file,filepos,MY_SEEK_SET,MYF(0)));
+ if (my_write(file,(byte*) forminfo,288,MYF_RW) ||
+ my_write(file,(byte*) screen_buff,info_length,MYF_RW) ||
+ pack_fields(file,create_fields))
+ goto err;
+
+#ifdef HAVE_CRYPTED_FRM
+ if (create_info->password)
+ {
+ char tmp=2,*disk_buff=0;
+ SQL_CRYPT *crypted=new SQL_CRYPT(create_info->password);
+ if (!crypted || my_pwrite(file,&tmp,1,26,MYF_RW)) // Mark crypted
+ goto err;
+ uint read_length=uint2korr(forminfo)-256;
+ VOID(my_seek(file,filepos+256,MY_SEEK_SET,MYF(0)));
+ if (read_string(file,(gptr*) &disk_buff,read_length))
+ goto err;
+ crypted->encode(disk_buff,read_length);
+ delete crypted;
+ if (my_pwrite(file,disk_buff,read_length,filepos+256,MYF_RW))
+ {
+ my_free(disk_buff,MYF(0));
+ goto err;
+ }
+ my_free(disk_buff,MYF(0));
+ }
+#endif
+
+ my_free((gptr) screen_buff,MYF(0));
+ my_afree((gptr) keybuff);
+ VOID(my_close(file,MYF(MY_WME)));
+ if (ha_create_table(file_name,create_info,0))
+ goto err2;
+ DBUG_RETURN(0);
+
+err:
+ my_free((gptr) screen_buff,MYF(0));
+ my_afree((gptr) keybuff);
+ VOID(my_close(file,MYF(MY_WME)));
+ err2:
+ my_delete(file_name,MYF(0));
+ DBUG_RETURN(1);
+} /* rea_create_table */
+
+
+ /* Pack screens to a screen for save in a form-file */
+
+static uchar * pack_screens(List<create_field> &create_fields,
+ uint *info_length, uint *screens,
+ bool small_file)
+{
+ reg1 uint i;
+ uint row,start_row,end_row,fields_on_screen;
+ uint length,cols;
+ uchar *info,*pos,*start_screen;
+ uint fields=create_fields.elements;
+ List_iterator<create_field> it(create_fields);
+ DBUG_ENTER("pack_screens");
+
+ start_row=4; end_row=22; cols=80; fields_on_screen=end_row+1-start_row;
+
+ *screens=(fields-1)/fields_on_screen+1;
+ length= (*screens) * (SC_INFO_LENGTH+ (cols>> 1)+4);
+
+ create_field *field;
+ while ((field=it++))
+ length+=strlen(field->field_name)+1+TE_INFO_LENGTH+cols/2;
+
+ if (!(info=(uchar*) my_malloc(length,MYF(MY_WME))))
+ DBUG_RETURN(0);
+
+ start_screen=0;
+ row=end_row;
+ pos=info;
+ it.rewind();
+ for (i=0 ; i < fields ; i++)
+ {
+ create_field *cfield=it++;
+ if (row++ == end_row)
+ {
+ if (i)
+ {
+ length=(uint) (pos-start_screen);
+ int2store(start_screen,length);
+ start_screen[2]=(uchar) (fields_on_screen+1);
+ start_screen[3]=(uchar) (fields_on_screen);
+ }
+ row=start_row;
+ start_screen=pos;
+ pos+=4;
+ pos[0]= (uchar) start_row-2; /* Header string */
+ pos[1]= (uchar) (cols >> 2);
+ pos[2]= (uchar) (cols >> 1) +1;
+ strfill((my_string) pos+3,(uint) (cols >> 1),' ');
+ pos+=(cols >> 1)+4;
+ }
+ length=strlen(cfield->field_name);
+ if (length > cols-3)
+ length=cols-3;
+
+ if (!small_file)
+ {
+ pos[0]=(uchar) row;
+ pos[1]=0;
+ pos[2]=(uchar) (length+1);
+ pos=(uchar*) strmake((char*) pos+3,cfield->field_name,length)+1;
+ }
+ cfield->row=(uint8) row;
+ cfield->col=(uint8) (length+1);
+ cfield->sc_length=(uint8) min(cfield->length,cols-(length+2));
+ }
+ length=(uint) (pos-start_screen);
+ int2store(start_screen,length);
+ start_screen[2]=(uchar) (row-start_row+2);
+ start_screen[3]=(uchar) (row-start_row+1);
+
+ *info_length=(uint) (pos-info);
+ DBUG_RETURN(info);
+} /* pack_screens */
+
+
+ /* Pack keyinfo and keynames to keybuff for save in form-file. */
+
+static uint pack_keys(uchar *keybuff,uint key_count,KEY *keyinfo)
+{
+ uint key_parts,length;
+ uchar *pos,*keyname_pos;
+ KEY *key,*end;
+ KEY_PART_INFO *key_part,*key_part_end;
+ DBUG_ENTER("pack_keys");
+
+ pos=keybuff+6;
+ key_parts=0;
+ for (key=keyinfo,end=keyinfo+key_count ; key != end ; key++)
+ {
+ pos[0]=(uchar) (key->flags ^ HA_NOSAME);
+ int2store(pos+1,key->key_length);
+ pos[3]=key->key_parts;
+ pos+=4;
+ key_parts+=key->key_parts;
+ DBUG_PRINT("loop",("flags: %d key_parts: %d at %lx",
+ key->flags,key->key_parts,
+ key->key_part));
+ for (key_part=key->key_part,key_part_end=key_part+key->key_parts ;
+ key_part != key_part_end ;
+ key_part++)
+
+ {
+ DBUG_PRINT("loop",("field: %d startpos: %ld length: %ld",
+ key_part->fieldnr,key_part->offset,key_part->length));
+ int2store(pos,key_part->fieldnr+1+FIELD_NAME_USED);
+ int2store(pos+2,key_part->offset+1);
+ pos[4]=0; // Sort order
+ int2store(pos+5,key_part->key_type);
+ int2store(pos+7,key_part->length);
+ pos+=9;
+ }
+ }
+ /* Save keynames */
+ keyname_pos=pos;
+ *pos++=NAMES_SEP_CHAR;
+ for (key=keyinfo ; key != end ; key++)
+ {
+ uchar *tmp=(uchar*) strmov((char*) pos,key->name);
+ *tmp++=NAMES_SEP_CHAR;
+ *tmp=0;
+ pos=tmp;
+ }
+ *(pos++)=0;
+
+ keybuff[0]=(uchar) key_count;
+ keybuff[1]=(uchar) key_parts;
+ length=(uint) (keyname_pos-keybuff);
+ int2store(keybuff+2,length);
+ length=(uint) (pos-keyname_pos);
+ int2store(keybuff+4,length);
+ DBUG_RETURN((uint) (pos-keybuff));
+} /* pack_keys */
+
+
+ /* Make formheader */
+
+static bool pack_header(uchar *forminfo, enum db_type table_type,
+ List<create_field> &create_fields,
+ uint info_length, uint screens,uint table_options,
+ handler *file)
+{
+ uint length,int_count,int_length,no_empty, int_parts,
+ time_stamp_pos,null_fields;
+ ulong reclength,totlength,n_length;
+ DBUG_ENTER("pack_header");
+
+ if (create_fields.elements > MAX_FIELDS)
+ {
+ my_error(ER_TOO_MANY_FIELDS,MYF(0));
+ DBUG_RETURN(1);
+ }
+
+ totlength=reclength=0L;
+ no_empty=int_count=int_parts=int_length=time_stamp_pos=null_fields=0;
+ n_length=2L;
+
+ /* Check fields */
+
+ List_iterator<create_field> it(create_fields);
+ create_field *field;
+ while ((field=it++))
+ {
+ totlength+= field->length;
+ if (MTYP_TYPENR(field->unireg_check) == Field::NOEMPTY ||
+ field->unireg_check & MTYP_NOEMPTY_BIT)
+ {
+ field->unireg_check= (Field::utype) ((uint) field->unireg_check |
+ MTYP_NOEMPTY_BIT);
+ no_empty++;
+ }
+ if ((MTYP_TYPENR(field->unireg_check) == Field::TIMESTAMP_FIELD ||
+ f_packtype(field->pack_flag) == (int) FIELD_TYPE_TIMESTAMP) &&
+ !time_stamp_pos)
+ time_stamp_pos=(int) field->offset+1;
+ length=field->pack_length;
+ if ((int) field->offset+length > reclength)
+ reclength=(int) field->offset+length;
+ n_length+= (ulong) strlen(field->field_name)+1;
+ field->interval_id=0;
+ if (field->interval)
+ {
+ uint old_int_count=int_count;
+ field->interval_id=get_interval_id(&int_count,create_fields,field);
+ if (old_int_count != int_count)
+ {
+ for (const char **pos=field->interval->type_names ; *pos ; pos++)
+ int_length+=strlen(*pos)+1; // field + suffix prefix
+ int_parts+=field->interval->count+1;
+ }
+ }
+ if (f_maybe_null(field->pack_flag))
+ null_fields++;
+ }
+ int_length+=int_count*2; // 255 prefix + 0 suffix
+
+ /* Save values in forminfo */
+
+ if (reclength > (ulong) file->max_record_length())
+ {
+ my_error(ER_TOO_BIG_ROWSIZE, MYF(0), (uint) file->max_record_length());
+ DBUG_RETURN(1);
+ }
+ /* Hack to avoid bugs with small static rows in MySQL */
+ reclength=max(file->min_record_length(table_options),reclength);
+ if (info_length+(ulong) create_fields.elements*FCOMP+288+
+ n_length+int_length > 65535L || int_count > 255)
+ {
+ my_error(ER_TOO_MANY_FIELDS,MYF(0));
+ DBUG_RETURN(1);
+ }
+
+ bzero((char*)forminfo,288);
+ length=info_length+create_fields.elements*FCOMP+288+n_length+int_length;
+ int2store(forminfo,length);
+ forminfo[256] = (uint8) screens;
+ int2store(forminfo+258,create_fields.elements);
+ int2store(forminfo+260,info_length);
+ int2store(forminfo+262,totlength);
+ int2store(forminfo+264,no_empty);
+ int2store(forminfo+266,reclength);
+ int2store(forminfo+268,n_length);
+ int2store(forminfo+270,int_count);
+ 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+282,null_fields);
+ DBUG_RETURN(0);
+} /* pack_header */
+
+
+ /* get each unique interval each own id */
+
+static uint get_interval_id(uint *int_count,List<create_field> &create_fields,
+ create_field *last_field)
+{
+ List_iterator<create_field> it(create_fields);
+ create_field *field;
+ TYPELIB *interval=last_field->interval;
+
+ while ((field=it++) != last_field)
+ {
+ if (field->interval_id && field->interval->count == interval->count)
+ {
+ const char **a,**b;
+ for (a=field->interval->type_names, b=interval->type_names ;
+ *a && !strcmp(*a,*b);
+ a++,b++) ;
+
+ if (! *a)
+ {
+ return field->interval_id; // Re-use last interval
+ }
+ }
+ }
+ return ++*int_count; // New unique interval
+}
+
+
+ /* Save fields, fieldnames and intervals */
+
+static bool pack_fields(File file,List<create_field> &create_fields)
+{
+ reg2 uint i;
+ uint int_count;
+ uchar buff[MAX_FIELD_WIDTH];
+ create_field *field;
+ DBUG_ENTER("pack_fields");
+
+ /* Write field info */
+
+ List_iterator<create_field> it(create_fields);
+
+ int_count=0;
+ while ((field=it++))
+ {
+ buff[0]= (uchar) field->row;
+ buff[1]= (uchar) field->col;
+ buff[2]= (uchar) field->sc_length;
+ buff[3]= (uchar) field->length;
+ uint recpos=(uint) field->offset+1;
+ int2store(buff+4,recpos);
+ int2store(buff+6,field->pack_flag);
+ int2store(buff+8,field->unireg_check);
+ buff[10]= (uchar) field->interval_id;
+ set_if_bigger(int_count,field->interval_id);
+ if (my_write(file,(byte*) buff,FCOMP,MYF_RW))
+ DBUG_RETURN(1);
+ }
+
+ /* Write fieldnames */
+ buff[0]=NAMES_SEP_CHAR;
+ if (my_write(file,(byte*) buff,1,MYF_RW))
+ DBUG_RETURN(1);
+ i=0;
+ it.rewind();
+ while ((field=it++))
+ {
+ char *pos= strmov((char*) buff,field->field_name);
+ *pos++=NAMES_SEP_CHAR;
+ if (i == create_fields.elements-1)
+ *pos++=0;
+ if (my_write(file,(byte*) buff,(uint) (pos-(char*) buff),MYF_RW))
+ DBUG_RETURN(1);
+ i++;
+ }
+
+ /* Write intervals */
+ if (int_count)
+ {
+ String tmp((char*) buff,sizeof(buff));
+ tmp.length(0);
+ it.rewind();
+ int_count=0;
+ while ((field=it++))
+ {
+ if (field->interval_id > int_count)
+ {
+ int_count=field->interval_id;
+ tmp.append('\377');
+ for (const char **pos=field->interval->type_names ; *pos ; pos++)
+ {
+ tmp.append(*pos);
+ tmp.append('\377');
+ }
+ tmp.append('\0'); // End of intervall
+ }
+ }
+ if (my_write(file,(byte*) tmp.ptr(),tmp.length(),MYF_RW))
+ DBUG_RETURN(1);
+ }
+ DBUG_RETURN(0);
+}
+
+
+ /* save a empty record on start of formfile */
+
+static bool make_empty_rec(File file,enum db_type table_type,
+ uint table_options,
+ List<create_field> &create_fields,
+ uint reclength, uint null_fields)
+{
+ int error;
+ Field::utype type;
+ uint firstpos,null_count,null_length;
+ uchar *buff,*null_pos;
+ TABLE table;
+ create_field *field;
+ DBUG_ENTER("make_empty_rec");
+
+ /* We need a table to generate columns for default values */
+ bzero((char*) &table,sizeof(table));
+ table.db_low_byte_first=test(table_type == DB_TYPE_MYISAM ||
+ table_type == DB_TYPE_HEAP);
+ table.blob_ptr_size=portable_sizeof_char_ptr;
+
+ if (!(buff=(uchar*) my_malloc((uint) reclength,MYF(MY_WME | MY_ZEROFILL))))
+ DBUG_RETURN(1);
+ firstpos=reclength;
+ null_count=0;
+ if (!(table_options & HA_OPTION_PACK_RECORD))
+ {
+ null_fields++; // Need one bit for delete mark
+ null_count++;
+ }
+ bfill(buff,(null_length=(null_fields+7)/8),255);
+ null_pos=buff;
+
+ List_iterator<create_field> it(create_fields);
+ while ((field=it++))
+ {
+ Field *regfield=make_field((char*) buff+field->offset,field->length,
+ field->flags & NOT_NULL_FLAG ? 0:
+ null_pos+null_count/8,
+ 1 << (null_count & 7),
+ field->pack_flag,
+ field->unireg_check,
+ field->interval,
+ field->field_name,
+ &table);
+ if (!(field->flags & NOT_NULL_FLAG))
+ null_count++;
+
+ if ((uint) field->offset < firstpos &&
+ regfield->type() != FIELD_TYPE_NULL)
+ firstpos= field->offset;
+
+ type= (Field::utype) MTYP_TYPENR(field->unireg_check);
+
+ if (field->def &&
+ (regfield->real_type() != FIELD_TYPE_YEAR ||
+ field->def->val_int() != 0))
+ field->def->save_in_field(regfield);
+ else if (regfield->real_type() == FIELD_TYPE_ENUM &&
+ (field->flags & NOT_NULL_FLAG))
+ {
+ regfield->set_notnull();
+ regfield->store((longlong) 1);
+ }
+ else if (type == Field::YES) // Old unireg type
+ regfield->store(ER(ER_YES),strlen(ER(ER_YES)));
+ else if (type == Field::NO) // Old unireg type
+ regfield->store(ER(ER_NO),strlen(ER(ER_NO)));
+ else
+ regfield->reset();
+ delete regfield;
+ }
+ bfill((byte*) buff+null_length,firstpos-null_length,255);/* Fill not used startpos */
+ error=(int) my_write(file,(byte*) buff,(uint) reclength,MYF_RW);
+ my_free((gptr) buff,MYF(MY_FAE));
+ DBUG_RETURN(error);
+} /* make_empty_rec */
diff --git a/sql/unireg.h b/sql/unireg.h
new file mode 100644
index 00000000000..a0890473de8
--- /dev/null
+++ b/sql/unireg.h
@@ -0,0 +1,136 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+
+/* Extra functions used by unireg library */
+
+#ifndef _unireg_h
+
+#ifndef NO_ALARM_LOOP
+#define NO_ALARM_LOOP /* lib5 and popen can't use alarm */
+#endif
+
+/* These paths are converted to other systems (WIN95) before use */
+
+#define LANGUAGE "english/"
+#define ERRMSG_FILE "errmsg.sys"
+#define TEMP_PREFIX "MY"
+#define PROGDIR "bin/"
+#ifndef DATADIR
+#define DATADIR "data/"
+#endif
+#ifndef SHAREDIR
+#define SHAREDIR "share/"
+#endif
+
+#define ER(X) errmesg[(X)-1000]
+
+#define ERRMAPP 1 /* Errormap f|r my_error */
+#define LIBLEN FN_REFLEN-FN_LEN /* Max l{ngd p} dev */
+#define MAX_FIELD_NAME 34 /* Max colum name length +2 */
+#define MAX_KEY 32 /* Max used keys */
+#define MAX_REF_PARTS 16 /* Max parts used as ref */
+#define MAX_KEY_LENGTH 500 /* max possible key */
+#if SIZEOF_OFF_T > 4
+#define MAX_REFLENGTH 8 /* Max length for record ref */
+#else
+#define MAX_REFLENGTH 4 /* Max length for record ref */
+#endif
+
+#define MAX_FIELD_WIDTH 256 /* Max column width +1 */
+#define MAX_TABLES (sizeof(table_map)*8-1) /* Max tables in join */
+#define RAND_TABLE_BIT (((table_map) 1) << (sizeof(table_map)*8-1))
+#define MAX_FIELDS 4096 /* Limit in the .frm file */
+
+#define MAX_SORT_MEMORY (2048*1024-MALLOC_OVERHEAD)
+#define MIN_SORT_MEMORY (32*1024-MALLOC_OVERHEAD)
+#define EXTRA_RECORDS 10 /* Extra records in sort */
+#define SCROLL_EXTRA 5 /* Extra scroll-rows. */
+#define FIELD_NAME_USED ((uint) 32768) /* Bit set if fieldname used */
+#define FORM_NAME_USED ((uint) 16384) /* Bit set if formname used */
+#define FIELD_NR_MASK 16383 /* To get fieldnumber */
+#define FERR -1 /* Error from my_functions */
+#define CREATE_MODE 0 /* Default mode on new files */
+#define NAMES_SEP_CHAR '\377' /* Char to sep. names */
+#ifdef MSDOS
+#define EXTRA_FIELD_CHAR (char) '\234' /* Interchangebly with '#' */
+#else
+#define EXTRA_FIELD_CHAR '#' /* Interchangebly with '#' */
+#endif
+
+#define READ_RECORD_BUFFER (uint) (IO_SIZE*8) /* Pointer_buffer_size */
+#define DISK_BUFFER_SIZE (uint) (IO_SIZE*16) /* Size of diskbuffer */
+#define POSTFIX_ERROR DBL_MAX
+
+#define ME_INFO (ME_HOLDTANG+ME_OLDWIN+ME_NOREFRESH)
+#define ME_ERROR (ME_BELL+ME_OLDWIN+ME_NOREFRESH)
+#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_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 */
+#define SPECIAL_ENGLISH 32 /* English error messages */
+#define SPECIAL_NO_RESOLVE 64 /* Don't use gethostname */
+#define SPECIAL_NO_PRIOR 128 /* Don't prioritize threads */
+#define SPECIAL_BIG_SELECTS 256 /* Don't use heap tables */
+#define SPECIAL_NO_HOST_CACHE 512 /* Don't cache hosts */
+#define SPECIAL_LONG_LOG_FORMAT 1024
+#define SPECIAL_SAFE_MODE 2048
+#define SPECIAL_SKIP_SHOW_DB 4096 /* Don't allow 'show db' */
+
+ /* Extern defines */
+#define store_record(A,B) bmove_allign((A)->record[B],(A)->record[0],(size_t) (A)->reclength)
+#define restore_record(A,B) bmove_allign((A)->record[0],(A)->record[B],(size_t) (A)->reclength)
+#define cmp_record(A,B) memcmp((A)->record[0],(A)->record[B],(size_t) (A)->reclength)
+#define empty_record(A) { \
+bmove_allign((A)->record[0],(A)->record[2],(size_t) (A)->reclength); \
+bfill((A)->null_flags,(A)->null_bytes,255);\
+}
+
+#if MAX_REFLENGTH == 4
+#define TEST_IF_LASTREF(A,B) ((long) *((int32*) (A)) == -1L)
+#else
+#define TEST_IF_LASTREF(A,B) (bcmp(A,last_ref,B) == 0)
+#endif
+
+ /* Defines for use with openfrm, openprt and openfrd */
+
+#define READ_ALL 1 /* openfrm: Read all parameters */
+#define CHANGE_FRM 2 /* openfrm: open .frm as O_RDWR */
+#define READ_KEYINFO 4 /* L{s nyckeldata fr}n filen */
+#define EXTRA_RECORD 8 /* Reservera plats f|r extra record */
+#define DONT_OPEN_TABLES 8 /* Don't open database-files (frd) */
+#define DONT_OPEN_MASTER_REG 16 /* Don't open first reg-file (prt) */
+#define EXTRA_LONG_RECORD 16 /* Plats f|r dubbel s|k-record */
+#define COMPUTE_TYPES 32 /* Kontrollera type f|r f{ltena */
+#define SEARCH_PRG 64 /* S|k efter registret i 'prg_dev' */
+#define READ_USED_NAMES 128 /* L{s anv{nda formul{rnamn */
+#define DONT_GIVE_ERROR 256 /* Don't do frm_error on openfrm */
+#define READ_SCREENS 1024 /* Read screens, info and helpfile */
+#define DELAYED_OPEN 4096 /* Open table later */
+
+#define SC_INFO_LENGTH 4 /* Form format constant */
+#define TE_INFO_LENGTH 3
+#define MTYP_NOEMPTY_BIT 128
+
+ /* Include prototypes for unireg */
+
+#include "mysqld_error.h"
+#include "structs.h" /* All structs we need */
+
+#endif
diff --git a/sql/violite.c b/sql/violite.c
new file mode 100644
index 00000000000..7a1424b6595
--- /dev/null
+++ b/sql/violite.c
@@ -0,0 +1,399 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 <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) */
+ 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, "socket (%d)", vio->sd);
+#if !defined(___WIN__) && !defined(__EMX__)
+#if !defined(NO_FCNTL_NONBLOCK)
+ vio->fcntl_mode = fcntl(sd, F_GETFL);
+#endif
+#else /* !defined(__WIN__) && !defined(__EMX__) */
+ {
+ /* set to blocking mode by default */
+ ulong arg=0;
+ 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 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));
+#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));
+#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 (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)), my_bool onoff)
+{
+ int r=0;
+ DBUG_ENTER("vio_fastsend");
+ DBUG_PRINT("enter", ("onoff:%d", (int) onoff));
+
+#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 = errno;
+ return en == EAGAIN || en == EINTR || en == 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("error", ("close() failed, error: %d",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", 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/sql/watchdog_mysqld b/sql/watchdog_mysqld
new file mode 100755
index 00000000000..0b26bb15acd
--- /dev/null
+++ b/sql/watchdog_mysqld
@@ -0,0 +1,126 @@
+#!/usr/bin/perl
+# Copyright (C) 1979-1998 TcX AB & Monty Program KB & Detron HB
+#
+# This software is distributed with NO WARRANTY OF ANY KIND. No author or
+# distributor accepts any responsibility for the consequences of using it, or
+# for whether it serves any particular purpose or works at all, unless he or
+# she says so in writing. Refer to the Free Public License (the "License")
+# for full details.
+#
+# Every copy of this file must include a copy of the License, normally in a
+# plain ASCII text file named PUBLIC. The License grants you the right to
+# copy, modify and redistribute this file, but only under certain conditions
+# described in the License. Among other things, the License requires that
+# the copyright notice and this notice be preserved on all copies. */
+
+#
+# This scripts is started by safe_mysqld. It checks that MySQL is alive and
+# working ( = answering to ping). If not, force mysqld down, check all
+# tables and let safe_mysqld restart the server.
+#
+# For this to work, you should have procmail installed as the commands
+# 'lockfile' and is used to sync with safe_mysqld
+#
+# NOTE: You should only use this script as a last resort if mysqld locks
+# up unexpectedly in a critical application and you have to get it to
+# work temporarily while waiting for a solution from mysql@tcx.se or
+# mysql-support@tcx.se
+
+
+use POSIX "waitpid";
+
+# Arguments from safe_mysqld
+
+if ($#ARGV != 4)
+{
+ print "$0: Wrong number of arguments. Aborting\n";
+ exit 1;
+}
+
+$lock_file=shift; # File to lock to sync with safe_mysqld
+$pid_file=shift; # Pid file used by mysqld
+$bin_dir=shift; # Directory where mysqladmin is
+$test_timeout=shift; # Time between testing if mysqld is alive
+$wait_timeout=shift; # How long time to wait for ping
+
+$|=1; # autoflush
+
+# Check that mysqld has started properly
+
+for ($i=1 ; $i < 10 ; $i ++)
+{
+ last if (-e $pid_file);
+}
+sleep(1); # If server has just created the file
+if (($mysqld_pid=`cat $pid_file`) <= 0)
+{
+ print "$0: Error: Invalid pidfile (contains '$mysqld_pid'). Aborting\n";
+}
+
+# Start pinging mysqld
+
+for (;;)
+{
+ sleep($test_timeout); # Time between tests
+ `lockfile $lock_file > /dev/null 2>&1`; # Sync with safe_mysqld
+ if (($pid=fork()) == 0)
+ {
+ setpgrp(0,0);
+ exit(int(system("$bin_dir/mysqladmin -w status > /dev/null")/256));
+ }
+ for ($i=0; ($res=waitpid(-1,&POSIX::WNOHANG)) == 0 && $i < $wait_timeout ; $i++)
+ {
+ sleep(1);
+ }
+ if ($res == 0)
+ {
+ print "$0: Warning: mysqld hanged; Killing it so that safe_mysqld can restart it!\n";
+ $mysqld_pid= `cat $pid_file`;
+ if ($mysqld_pid <= 0)
+ {
+ print "$0: Error: Invalid pidfile (contains '$mysqld_pid'). Aborting\n";
+ system("rm -f $lock_file");
+ kill(-9,$pid);
+ exit 1;
+ }
+ print "$0: Sending signal 15 to $mysqld_pid\n";
+ kill(-15, $pid,$mysqld_pid); # Give it a last change to die nicely
+ for ($i=0 ; $i < 5 ; $i++) { sleep(1); } # Wait 5 seconds (signal safe)
+ waitpid(-1,&POSIX::WNOHANG);
+ if (kill(0,$pid,$mysqld_pid) != 0)
+ {
+ print "$0: Sending signal 9 to $mysqld_pid\n";
+ kill(-9,$pid,$mysqld_pid); # No time to be nice anymore
+ sleep(2); # Give system time to clean up
+ waitpid(-1,&POSIX::WNOHANG);
+ if (kill(0,$mysqld_pid) != 0)
+ {
+ print "$0: Warning: mysqld don't want to die. Aborting\n";
+ system("rm -f $lock_file");
+ exit 1;
+ }
+ }
+ # safe_mysqld will not restart mysqld if the pid file doesn't exists
+ system("rm $pid_file");
+ system("touch $pid_file");
+ }
+ elsif ($res == -1)
+ {
+ print "$0: Error: waitpid returned $res when wating for pid $pid\nPlease verify that $0 is correct for your system\n";
+ system("rm -f $lock_file");
+ exit 1;
+ }
+ else
+ {
+ $exit_code=int($?/256);
+ if ($exit_code != 0)
+ {
+ print "$0: Warning: mysqladmin returned exit code $exit_code\n";
+ }
+ else
+ {
+ #print "mysqld is alive and feeling well\n";
+ }
+ }
+ system("rm -f $lock_file"); # safemysqld will now take over
+}
diff --git a/stamp-h.in b/stamp-h.in
new file mode 100644
index 00000000000..9788f70238c
--- /dev/null
+++ b/stamp-h.in
@@ -0,0 +1 @@
+timestamp
diff --git a/strings/.cvsignore b/strings/.cvsignore
new file mode 100644
index 00000000000..4fce34e473a
--- /dev/null
+++ b/strings/.cvsignore
@@ -0,0 +1,8 @@
+.deps
+.libs
+Makefile
+Makefile.in
+ctype_autoconf.c
+ctype_extra_sources.c
+conf_to_src
+old
diff --git a/strings/Attic/bootstrap-ctype.c b/strings/Attic/bootstrap-ctype.c
new file mode 100644
index 00000000000..dea3fcbb03c
--- /dev/null
+++ b/strings/Attic/bootstrap-ctype.c
@@ -0,0 +1,91 @@
+/* Bootstrap configuration file (from the latin1 character set) */
+#include <global.h>
+#include <m_ctype.h>
+
+/*
+ * This comment is parsed by configure to create ctype.c,
+ * so don't change it unless you know what you are doing.
+ *
+ * .configure. number_BOOTSTRAP=0
+ */
+
+/* ctype array must have 257 elements */
+uchar ctype_BOOTSTRAP[257] = {
+ 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
+};
+
+/* to_lower array must have 256 elements */
+uchar to_lower_BOOTSTRAP[256] = {
+ 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
+};
+
+/* to_upper array must have 256 elements */
+uchar to_upper_BOOTSTRAP[256] = {
+ 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
+};
+
+/* sort_order array must have 256 elements */
+uchar sort_order_BOOTSTRAP[256] = {
+ 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, 92, 91, 92, 67, 69, 69, 69, 69, 73, 73, 73, 73,
+ 68, 78, 79, 79, 79, 79, 93,215,216, 85, 85, 85, 89, 89,222,223,
+ 65, 65, 65, 65, 92, 91, 92, 67, 69, 69, 69, 69, 73, 73, 73, 73,
+ 68, 78, 79, 79, 79, 79, 93,247,216, 85, 85, 85, 89, 89,222,255
+};
diff --git a/strings/Attic/ct_init.c b/strings/Attic/ct_init.c
new file mode 100644
index 00000000000..b0b1a8e126b
--- /dev/null
+++ b/strings/Attic/ct_init.c
@@ -0,0 +1,6 @@
+/* Generate definitions of ctype arrays
+*/
+
+#include <global.h>
+#define CTYPE_LIBRARY /* initialize ctype arrays */
+#include "m_ctype.h"
diff --git a/strings/Attic/ctype-cp1251.c b/strings/Attic/ctype-cp1251.c
new file mode 100644
index 00000000000..e717fd49c9e
--- /dev/null
+++ b/strings/Attic/ctype-cp1251.c
@@ -0,0 +1,88 @@
+/* ctype-cp1251.c */
+
+/*
+ * File generated by cset
+ * (C) Abandoned 1997 Zarko Mocnik <zarko.mocnik@dem.si>
+ *
+ * This file is obsolete; Please use ctype-win1251 instead!
+ */
+
+#include <global.h>
+#include "m_string.h"
+
+uchar NEAR ctype_cp1251[257] = {
+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, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 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, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+};
+
+uchar NEAR to_lower_cp1251[] = {
+ 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,184,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,247,248,249,250,251,252,253,254,255,
+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 NEAR to_upper_cp1251[] = {
+ 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,168,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,215,216,217,218,219,220,221,222,223,
+};
+
+uchar NEAR sort_order_cp1251[] = {
+ 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,124,125,126,127,128,
+129, 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,130,131,132,133,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 97,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 97,255,255,255,255,255,255,255,
+ 91, 92, 93, 94, 95, 96, 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,
+ 91, 92, 93, 94, 95, 96, 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,
+};
diff --git a/strings/Attic/ctype-cp1257.c b/strings/Attic/ctype-cp1257.c
new file mode 100644
index 00000000000..c60f71f635b
--- /dev/null
+++ b/strings/Attic/ctype-cp1257.c
@@ -0,0 +1,88 @@
+/* cp1257 (Lithuanian)
+ * Created by Miroslav Stanish , Vilnius, 1999
+ * This file is public domain and comes with no warranty of any kind
+ * Pleace send comments and bug reports to: <miroslav@mail.lt>
+ *
+ * File generated by cset
+ * (C) Abandoned 1997 Zarko Mocnik <zarko.mocnik@dem.si>
+ */
+#include <global.h>
+#include "m_string.h"
+
+uchar NEAR ctype_cp1257[257] = {
+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, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0,
+ 2, 2, 0, 0, 0, 0, 2, 0, 2, 0, 0, 2, 0, 0, 0, 0,
+ 2, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 2, 0, 0, 2, 0,
+};
+
+uchar NEAR to_lower_cp1257[] = {
+ 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,194,195,196,197,230,199,232,201,202,235,204,205,206,207,
+240,209,210,211,212,213,214,215,248,217,218,251,220,221,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 NEAR to_upper_cp1257[] = {
+ 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,226,227,228,229,198,231,200,233,234,203,236,237,238,239,
+208,241,242,243,244,245,246,247,216,249,250,219,252,253,222,255,
+};
+
+uchar NEAR sort_order_cp1257[] = {
+ 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, 67, 68, 70, 71, 74, 75, 76, 77, 80, 81, 82, 83, 84, 85,
+ 86, 87, 88, 89, 91, 92, 95, 96, 97, 78,255, 98, 99,100,101,102,
+103, 65, 67, 68, 70, 71, 74, 75, 76, 77, 80, 81, 82, 83, 84, 85,
+ 86, 87, 88, 89, 91, 92, 95, 96, 97, 78,255,104,105,106,107,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 66, 79,255,255,255,255, 72,255, 69,255,255, 73,255,255,255,255,
+ 90,255,255,255,255,255,255,255, 94,255,255, 93,255,255,255,255,
+255, 79,255,255,255,255, 72,255, 69,255,255, 73,255,255,255,255,
+ 90,255,255,255,255,255,255,255, 94,255,255, 93,255,255,255,255,
+};
+
diff --git a/strings/Attic/ctype-croat.c b/strings/Attic/ctype-croat.c
new file mode 100644
index 00000000000..144ef337705
--- /dev/null
+++ b/strings/Attic/ctype-croat.c
@@ -0,0 +1,143 @@
+/*
+ This file is free for using
+ Author: Hrvoje Devcic, hdevcic@posluh.hr;
+ Sintaxx Error Software
+ POSLuH d.o.o., Zagreb, Croatia - http://www.posluh.hr
+*/
+
+/* This implements the hr (Croatian) character-set */
+
+#include <global.h>
+#include "m_string.h"
+
+uchar NEAR ctype_croat[257] = {
+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,1,0,0,0,1,0,0,
+0,0,0,0,0,0,0,0,0,2,0,0,0,2,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 NEAR to_lower_croat[]={
+'\000','\001','\002','\003','\004','\005','\006','\007',
+'\010','\011','\012','\013','\014','\015','\016','\017',
+'\020','\021','\022','\023','\024','\025','\026','\027',
+'\030','\031','\032','\033','\034','\035','\036','\037',
+' ', '!', '"', '#', '$', '%', '&', '\'',
+'(', ')', '*', '+', ',', '-', '.', '/',
+'0', '1', '2', '3', '4', '5', '6', '7',
+'8', '9', ':', ';', '<', '=', '>', '?',
+'@', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
+'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
+'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
+'x', 'y', 'z', '[', '\\', ']', '^', '_',
+'`', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
+'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
+'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
+'x', 'y', 'z', '{', '|', '}', '~', '\177',
+
+(uchar) '\200',(uchar) '\201',(uchar) '\202',(uchar) '\203',(uchar) '\204',(uchar) '\205',(uchar) '\206',(uchar) '\207',
+(uchar) '\210',(uchar) '\211',(uchar) 154,(uchar) '\213',(uchar) '\214',(uchar) '\215',(uchar) 158,(uchar) '\217',
+(uchar) '\220',(uchar) '\221',(uchar) '\222',(uchar) '\223',(uchar) '\224',(uchar) '\225',(uchar) '\226',(uchar) '\227',
+(uchar) '\230',(uchar) '\231',(uchar) '\232',(uchar) '\233',(uchar) '\234',(uchar) '\235',(uchar) '\236',(uchar) '\237',
+(uchar) '\240',(uchar) '\241',(uchar) '\242',(uchar) '\243',(uchar) '\244',(uchar) '\245',(uchar) '\246',(uchar) '\247',
+(uchar) '\250',(uchar) '\251',(uchar) '\252',(uchar) '\253',(uchar) '\254',(uchar) '\255',(uchar) '\256',(uchar) '\257',
+(uchar) '\260',(uchar) '\261',(uchar) '\262',(uchar) '\263',(uchar) '\264',(uchar) '\265',(uchar) '\266',(uchar) '\267',
+(uchar) '\270',(uchar) '\271',(uchar) '\272',(uchar) '\273',(uchar) '\274',(uchar) '\275',(uchar) '\276',(uchar) '\277',
+(uchar) '\340',(uchar) '\341',(uchar) '\342',(uchar) '\343',(uchar) '\344',(uchar) '\345',(uchar) 230,(uchar) '\347',
+(uchar) 232,(uchar) '\351',(uchar) '\352',(uchar) '\353',(uchar) '\354',(uchar) '\355',(uchar) '\356',(uchar) '\357',
+(uchar) 240,(uchar) '\361',(uchar) '\362',(uchar) '\363',(uchar) '\364',(uchar) '\365',(uchar) '\366',(uchar) '\327',
+(uchar) '\370',(uchar) '\371',(uchar) '\372',(uchar) '\373',(uchar) '\374',(uchar) '\375',(uchar) '\376',(uchar) '\337',
+(uchar) '\340',(uchar) '\341',(uchar) '\342',(uchar) '\343',(uchar) '\344',(uchar) '\345',(uchar) '\346',(uchar) '\347',
+(uchar) '\350',(uchar) '\351',(uchar) '\352',(uchar) '\353',(uchar) '\354',(uchar) '\355',(uchar) '\356',(uchar) '\357',
+(uchar) '\360',(uchar) '\361',(uchar) '\362',(uchar) '\363',(uchar) '\364',(uchar) '\365',(uchar) '\366',(uchar) '\367',
+(uchar) '\370',(uchar) '\371',(uchar) '\372',(uchar) '\373',(uchar) '\374',(uchar) '\375',(uchar) '\376',(uchar) '\377',
+};
+
+uchar NEAR to_upper_croat[]={
+'\000','\001','\002','\003','\004','\005','\006','\007',
+'\010','\011','\012','\013','\014','\015','\016','\017',
+'\020','\021','\022','\023','\024','\025','\026','\027',
+'\030','\031','\032','\033','\034','\035','\036','\037',
+' ', '!', '"', '#', '$', '%', '&', '\'',
+'(', ')', '*', '+', ',', '-', '.', '/',
+'0', '1', '2', '3', '4', '5', '6', '7',
+'8', '9', ':', ';', '<', '=', '>', '?',
+'@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+'X', 'Y', 'Z', '[', '\\', ']', '^', '_',
+'`', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+'X', 'Y', 'Z', '{', '|', '}', '~', '\177',
+
+(uchar) '\200',(uchar) '\201',(uchar) '\202',(uchar) '\203',(uchar) '\204',(uchar) '\205',(uchar) '\206',(uchar) '\207',
+(uchar) '\210',(uchar) '\211',(uchar) '\212',(uchar) '\213',(uchar) '\214',(uchar) '\215',(uchar) '\216',(uchar) '\217',
+(uchar) '\220',(uchar) '\221',(uchar) '\222',(uchar) '\223',(uchar) '\224',(uchar) '\225',(uchar) '\226',(uchar) '\227',
+(uchar) '\230',(uchar) '\231',(uchar) 138,(uchar) '\233',(uchar) '\234',(uchar) '\235',(uchar) 142,(uchar) '\237',
+(uchar) '\240',(uchar) '\241',(uchar) '\242',(uchar) '\243',(uchar) '\244',(uchar) '\245',(uchar) '\246',(uchar) '\247',
+(uchar) '\250',(uchar) '\251',(uchar) '\252',(uchar) '\253',(uchar) '\254',(uchar) '\255',(uchar) '\256',(uchar) '\257',
+(uchar) '\260',(uchar) '\261',(uchar) '\262',(uchar) '\263',(uchar) '\264',(uchar) '\265',(uchar) '\266',(uchar) '\267',
+(uchar) '\270',(uchar) '\271',(uchar) '\272',(uchar) '\273',(uchar) '\274',(uchar) '\275',(uchar) '\276',(uchar) '\277',
+(uchar) '\300',(uchar) '\301',(uchar) '\302',(uchar) '\303',(uchar) '\304',(uchar) '\305',(uchar) '\306',(uchar) '\307',
+(uchar) '\310',(uchar) '\311',(uchar) '\312',(uchar) '\313',(uchar) '\314',(uchar) '\315',(uchar) '\316',(uchar) '\317',
+(uchar) '\320',(uchar) '\321',(uchar) '\322',(uchar) '\323',(uchar) '\324',(uchar) '\325',(uchar) '\326',(uchar) '\327',
+(uchar) '\330',(uchar) '\331',(uchar) '\332',(uchar) '\333',(uchar) '\334',(uchar) '\335',(uchar) '\336',(uchar) '\337',
+(uchar) '\300',(uchar) '\301',(uchar) '\302',(uchar) '\303',(uchar) '\304',(uchar) '\305',(uchar) 198,(uchar) '\307',
+(uchar) 200,(uchar) '\311',(uchar) '\312',(uchar) '\313',(uchar) '\314',(uchar) '\315',(uchar) '\316',(uchar) '\317',
+(uchar) 208,(uchar) '\321',(uchar) '\322',(uchar) '\323',(uchar) '\324',(uchar) '\325',(uchar) '\326',(uchar) '\367',
+(uchar) '\330',(uchar) '\331',(uchar) '\332',(uchar) '\333',(uchar) '\334',(uchar) '\335',(uchar) '\336',(uchar) '\377',
+};
+
+#ifndef __WIN32__
+uchar NEAR sort_order_croat[]={
+#else
+uchar sort_order_croat[]={
+#endif
+'\000','\001','\002','\003','\004','\005','\006','\007',
+'\010','\011','\012','\013','\014','\015','\016','\017',
+'\020','\021','\022','\023','\024','\025','\026','\027',
+'\030','\031','\032','\033','\034','\035','\036','\037',
+' ', '!', '"', '#', '$', '%', '&', '\'',
+'(', ')', '*', '+', ',', '-', '.', '/',
+'0', '1', '2', '3', '4', '5', '6', '7',
+'8', '9', ':', ';', '<', '=', '>', '?',
+'@', 65, 66, 67, 70, 72, 73, 74,
+ 75, 76, 77, 78, 79, 80, 81, 82,
+ 83, 84, 85, 86, 88, 89, 90, 91,
+ 92, 93, 94, '[', '\\', ']', '^', '_',
+'`', 65, 66, 67, 70, 72, 73, 74,
+ 75, 76, 77, 78, 79, 80, 81, 82,
+ 83, 84, 85, 86, 88, 89, 90, 91,
+ 92, 93, 94, '{', '|', '}', '~', '\177',
+
+(uchar) '\200',(uchar) '\201',(uchar) '\202',(uchar) '\203',(uchar) '\204',(uchar) '\205',(uchar) '\206',(uchar) '\207',
+(uchar) '\210',(uchar) '\211',(uchar) 87,(uchar) '\213',(uchar) '\214',(uchar) '\215',(uchar) 95,(uchar) '\217',
+(uchar) '\220',(uchar) '\221',(uchar) '\222',(uchar) '\223',(uchar) '\224',(uchar) '\225',(uchar) '\226',(uchar) '\227',
+(uchar) '\230',(uchar) '\231',(uchar) 87,(uchar) '\233',(uchar) '\234',(uchar) '\235',(uchar) 95,(uchar) '\237',
+(uchar) '\240',(uchar) '\241',(uchar) '\242',(uchar) '\243',(uchar) '\244',(uchar) '\245',(uchar) '\246',(uchar) '\247',
+(uchar) '\250',(uchar) '\251',(uchar) '\252',(uchar) '\253',(uchar) '\254',(uchar) '\255',(uchar) '\256',(uchar) '\257',
+(uchar) '\260',(uchar) '\261',(uchar) '\262',(uchar) '\263',(uchar) '\264',(uchar) '\265',(uchar) '\266',(uchar) '\267',
+(uchar) '\270',(uchar) '\271',(uchar) '\272',(uchar) '\273',(uchar) '\274',(uchar) '\275',(uchar) '\276',(uchar) '\277',
+'A', 'A', 'A', 'A', '\\', '[', 69, 'C',
+ 68, 'E', 'E', 'E', 'I', 'I', 'I', 'I',
+ 71, 'N', 'O', 'O', 'O', 'O', ']',(uchar) '\327',
+(uchar) '\330','U', 'U', 'U', 'Y', 'Y',(uchar) '\336',(uchar) '\337',
+'A', 'A', 'A', 'A', '\\', '[', 69, 'C',
+ 68, 'E', 'E', 'E', 'I', 'I', 'I', 'I',
+ 71, 'N', 'O', 'O', 'O', 'O', ']',(uchar) '\367',
+(uchar) '\330','U', 'U', 'U', 'Y', 'Y',(uchar) '\336',(uchar) '\377',
+};
diff --git a/strings/Attic/ctype-danish.c b/strings/Attic/ctype-danish.c
new file mode 100644
index 00000000000..7b74c5cba15
--- /dev/null
+++ b/strings/Attic/ctype-danish.c
@@ -0,0 +1,144 @@
+/* Copyright Abandoned 1996 TCX DataKonsult AB & Monty Program KB & Detron HB
+ This file is public domain and comes with NO WARRANTY of any kind */
+
+/*
+** This implements the ISO 8859 Latin1 character-set with danish sorting
+** This file is equivalent to ctype-latin1.c except for the last variable
+** (sort_order_danish)
+*/
+
+
+#include <global.h>
+#include "m_string.h"
+
+uchar NEAR ctype_danish[257] = {
+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 NEAR to_lower_danish[]={
+'\000','\001','\002','\003','\004','\005','\006','\007',
+'\010','\011','\012','\013','\014','\015','\016','\017',
+'\020','\021','\022','\023','\024','\025','\026','\027',
+'\030','\031','\032','\033','\034','\035','\036','\037',
+' ', '!', '"', '#', '$', '%', '&', '\'',
+'(', ')', '*', '+', ',', '-', '.', '/',
+'0', '1', '2', '3', '4', '5', '6', '7',
+'8', '9', ':', ';', '<', '=', '>', '?',
+'@', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
+'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
+'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
+'x', 'y', 'z', '[', '\\', ']', '^', '_',
+'`', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
+'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
+'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
+'x', 'y', 'z', '{', '|', '}', '~', '\177',
+
+(uchar) '\200',(uchar) '\201',(uchar) '\202',(uchar) '\203',(uchar) '\204',(uchar) '\205',(uchar) '\206',(uchar) '\207',
+(uchar) '\210',(uchar) '\211',(uchar) '\212',(uchar) '\213',(uchar) '\214',(uchar) '\215',(uchar) '\216',(uchar) '\217',
+(uchar) '\220',(uchar) '\221',(uchar) '\222',(uchar) '\223',(uchar) '\224',(uchar) '\225',(uchar) '\226',(uchar) '\227',
+(uchar) '\230',(uchar) '\231',(uchar) '\232',(uchar) '\233',(uchar) '\234',(uchar) '\235',(uchar) '\236',(uchar) '\237',
+(uchar) '\240',(uchar) '\241',(uchar) '\242',(uchar) '\243',(uchar) '\244',(uchar) '\245',(uchar) '\246',(uchar) '\247',
+(uchar) '\250',(uchar) '\251',(uchar) '\252',(uchar) '\253',(uchar) '\254',(uchar) '\255',(uchar) '\256',(uchar) '\257',
+(uchar) '\260',(uchar) '\261',(uchar) '\262',(uchar) '\263',(uchar) '\264',(uchar) '\265',(uchar) '\266',(uchar) '\267',
+(uchar) '\270',(uchar) '\271',(uchar) '\272',(uchar) '\273',(uchar) '\274',(uchar) '\275',(uchar) '\276',(uchar) '\277',
+(uchar) '\340',(uchar) '\341',(uchar) '\342',(uchar) '\343',(uchar) '\344',(uchar) '\345',(uchar) '\346',(uchar) '\347',
+(uchar) '\350',(uchar) '\351',(uchar) '\352',(uchar) '\353',(uchar) '\354',(uchar) '\355',(uchar) '\356',(uchar) '\357',
+(uchar) '\360',(uchar) '\361',(uchar) '\362',(uchar) '\363',(uchar) '\364',(uchar) '\365',(uchar) '\366',(uchar) '\327',
+(uchar) '\370',(uchar) '\371',(uchar) '\372',(uchar) '\373',(uchar) '\374',(uchar) '\375',(uchar) '\376',(uchar) '\337',
+(uchar) '\340',(uchar) '\341',(uchar) '\342',(uchar) '\343',(uchar) '\344',(uchar) '\345',(uchar) '\346',(uchar) '\347',
+(uchar) '\350',(uchar) '\351',(uchar) '\352',(uchar) '\353',(uchar) '\354',(uchar) '\355',(uchar) '\356',(uchar) '\357',
+(uchar) '\360',(uchar) '\361',(uchar) '\362',(uchar) '\363',(uchar) '\364',(uchar) '\365',(uchar) '\366',(uchar) '\367',
+(uchar) '\370',(uchar) '\371',(uchar) '\372',(uchar) '\373',(uchar) '\374',(uchar) '\375',(uchar) '\376',(uchar) '\377',
+};
+
+uchar NEAR to_upper_danish[]={
+'\000','\001','\002','\003','\004','\005','\006','\007',
+'\010','\011','\012','\013','\014','\015','\016','\017',
+'\020','\021','\022','\023','\024','\025','\026','\027',
+'\030','\031','\032','\033','\034','\035','\036','\037',
+' ', '!', '"', '#', '$', '%', '&', '\'',
+'(', ')', '*', '+', ',', '-', '.', '/',
+'0', '1', '2', '3', '4', '5', '6', '7',
+'8', '9', ':', ';', '<', '=', '>', '?',
+'@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+'X', 'Y', 'Z', '[', '\\', ']', '^', '_',
+'`', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+'X', 'Y', 'Z', '{', '|', '}', '~', '\177',
+
+(uchar) '\200',(uchar) '\201',(uchar) '\202',(uchar) '\203',(uchar) '\204',(uchar) '\205',(uchar) '\206',(uchar) '\207',
+(uchar) '\210',(uchar) '\211',(uchar) '\212',(uchar) '\213',(uchar) '\214',(uchar) '\215',(uchar) '\216',(uchar) '\217',
+(uchar) '\220',(uchar) '\221',(uchar) '\222',(uchar) '\223',(uchar) '\224',(uchar) '\225',(uchar) '\226',(uchar) '\227',
+(uchar) '\230',(uchar) '\231',(uchar) '\232',(uchar) '\233',(uchar) '\234',(uchar) '\235',(uchar) '\236',(uchar) '\237',
+(uchar) '\240',(uchar) '\241',(uchar) '\242',(uchar) '\243',(uchar) '\244',(uchar) '\245',(uchar) '\246',(uchar) '\247',
+(uchar) '\250',(uchar) '\251',(uchar) '\252',(uchar) '\253',(uchar) '\254',(uchar) '\255',(uchar) '\256',(uchar) '\257',
+(uchar) '\260',(uchar) '\261',(uchar) '\262',(uchar) '\263',(uchar) '\264',(uchar) '\265',(uchar) '\266',(uchar) '\267',
+(uchar) '\270',(uchar) '\271',(uchar) '\272',(uchar) '\273',(uchar) '\274',(uchar) '\275',(uchar) '\276',(uchar) '\277',
+(uchar) '\300',(uchar) '\301',(uchar) '\302',(uchar) '\303',(uchar) '\304',(uchar) '\305',(uchar) '\306',(uchar) '\307',
+(uchar) '\310',(uchar) '\311',(uchar) '\312',(uchar) '\313',(uchar) '\314',(uchar) '\315',(uchar) '\316',(uchar) '\317',
+(uchar) '\320',(uchar) '\321',(uchar) '\322',(uchar) '\323',(uchar) '\324',(uchar) '\325',(uchar) '\326',(uchar) '\327',
+(uchar) '\330',(uchar) '\331',(uchar) '\332',(uchar) '\333',(uchar) '\334',(uchar) '\335',(uchar) '\336',(uchar) '\337',
+(uchar) '\300',(uchar) '\301',(uchar) '\302',(uchar) '\303',(uchar) '\304',(uchar) '\305',(uchar) '\306',(uchar) '\307',
+(uchar) '\310',(uchar) '\311',(uchar) '\312',(uchar) '\313',(uchar) '\314',(uchar) '\315',(uchar) '\316',(uchar) '\317',
+(uchar) '\320',(uchar) '\321',(uchar) '\322',(uchar) '\323',(uchar) '\324',(uchar) '\325',(uchar) '\326',(uchar) '\367',
+(uchar) '\330',(uchar) '\331',(uchar) '\332',(uchar) '\333',(uchar) '\334',(uchar) '\335',(uchar) '\336',(uchar) '\377',
+};
+
+#ifndef __WIN32__
+uchar NEAR sort_order_danish[]={
+#else
+uchar sort_order_danish[]={
+#endif
+'\000','\001','\002','\003','\004','\005','\006','\007',
+'\010','\011','\012','\013','\014','\015','\016','\017',
+'\020','\021','\022','\023','\024','\025','\026','\027',
+'\030','\031','\032','\033','\034','\035','\036','\037',
+' ', '!', '"', '#', '$', '%', '&', '\'',
+'(', ')', '*', '+', ',', '-', '.', '/',
+'0', '1', '2', '3', '4', '5', '6', '7',
+'8', '9', ':', ';', '<', '=', '>', '?',
+'@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+'X', 'Y', 'Z', '[', '\\', ']', '^', '_',
+'`', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+'X', 'Y', 'Z', '{', '|', '}', '~', '\177',
+
+(uchar) '\200',(uchar) '\201',(uchar) '\202',(uchar) '\203',(uchar) '\204',(uchar) '\205',(uchar) '\206',(uchar) '\207',
+(uchar) '\210',(uchar) '\211',(uchar) '\212',(uchar) '\213',(uchar) '\214',(uchar) '\215',(uchar) '\216',(uchar) '\217',
+(uchar) '\220',(uchar) '\221',(uchar) '\222',(uchar) '\223',(uchar) '\224',(uchar) '\225',(uchar) '\226',(uchar) '\227',
+(uchar) '\230',(uchar) '\231',(uchar) '\232',(uchar) '\233',(uchar) '\234',(uchar) '\235',(uchar) '\236',(uchar) '\237',
+(uchar) '\240',(uchar) '\241',(uchar) '\242',(uchar) '\243',(uchar) '\244',(uchar) '\245',(uchar) '\246',(uchar) '\247',
+(uchar) '\250',(uchar) '\251',(uchar) '\252',(uchar) '\253',(uchar) '\254',(uchar) '\255',(uchar) '\256',(uchar) '\257',
+(uchar) '\260',(uchar) '\261',(uchar) '\262',(uchar) '\263',(uchar) '\264',(uchar) '\265',(uchar) '\266',(uchar) '\267',
+(uchar) '\270',(uchar) '\271',(uchar) '\272',(uchar) '\273',(uchar) '\274',(uchar) '\275',(uchar) '\276',(uchar) '\277',
+'A', 'A', 'A', 'A', '[', ']', '[', 'C',
+'E', 'E', 'E', 'E', 'I', 'I', 'I', 'I',
+'D', 'N', 'O', 'O', 'O', 'O', '\\', (uchar) '\327',
+'\\','U', 'U', 'U', 'Y', 'Y', (uchar) '\336',(uchar) '\337',
+'A', 'A', 'A', 'A', '[', ']', '[', 'C',
+'E', 'E', 'E', 'E', 'I', 'I', 'I', 'I',
+'D', 'N', 'O', 'O', 'O', 'O', '\\', (uchar) '\367',
+'\\','U', 'U', 'U', 'Y', 'Y', (uchar) '\336',(uchar) '\377',
+};
diff --git a/strings/Attic/ctype-dec8.c b/strings/Attic/ctype-dec8.c
new file mode 100644
index 00000000000..f32302979eb
--- /dev/null
+++ b/strings/Attic/ctype-dec8.c
@@ -0,0 +1,140 @@
+/* Copyright Abandoned 1996 TCX DataKonsult AB & Monty Program KB & Detron HB
+ This file is public domain and comes with NO WARRANTY of any kind */
+
+#include <global.h>
+#include "m_string.h"
+
+#define CTYPE /* initialize ctype arrays */
+#include "m_ctype.h"
+
+void init_ctype(void) /* Stupid linker !! */
+{} /* Some symbol must be defined */
+
+uchar ctype_dec8[257] =
+{
+0, /* For standard library */
+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 NEAR to_lower_dec8[]={
+'\000','\001','\002','\003','\004','\005','\006','\007',
+'\010','\011','\012','\013','\014','\015','\016','\017',
+'\020','\021','\022','\023','\024','\025','\026','\027',
+'\030','\031','\032','\033','\034','\035','\036','\037',
+' ', '!', '"', '#', '$', '%', '&', '\'',
+'(', ')', '*', '+', ',', '-', '.', '/',
+'0', '1', '2', '3', '4', '5', '6', '7',
+'8', '9', ':', ';', '<', '=', '>', '?',
+'@', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
+'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
+'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
+'x', 'y', 'z', '[', '\\', ']', '^', '_',
+'`', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
+'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
+'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
+'x', 'y', 'z', '{', '|', '}', '~', '\177',
+
+(uchar) '\200',(uchar) '\201',(uchar) '\202',(uchar) '\203',(uchar) '\204',(uchar) '\205',(uchar) '\206',(uchar) '\207',
+(uchar) '\210',(uchar) '\211',(uchar) '\212',(uchar) '\213',(uchar) '\214',(uchar) '\215',(uchar) '\216',(uchar) '\217',
+(uchar) '\220',(uchar) '\221',(uchar) '\222',(uchar) '\223',(uchar) '\224',(uchar) '\225',(uchar) '\226',(uchar) '\227',
+(uchar) '\230',(uchar) '\231',(uchar) '\232',(uchar) '\233',(uchar) '\234',(uchar) '\235',(uchar) '\236',(uchar) '\237',
+(uchar) '\240',(uchar) '\241',(uchar) '\242',(uchar) '\243',(uchar) '\244',(uchar) '\245',(uchar) '\246',(uchar) '\247',
+(uchar) '\250',(uchar) '\251',(uchar) '\252',(uchar) '\253',(uchar) '\254',(uchar) '\255',(uchar) '\256',(uchar) '\257',
+(uchar) '\260',(uchar) '\261',(uchar) '\262',(uchar) '\263',(uchar) '\264',(uchar) '\265',(uchar) '\266',(uchar) '\267',
+(uchar) '\270',(uchar) '\271',(uchar) '\272',(uchar) '\273',(uchar) '\274',(uchar) '\275',(uchar) '\276',(uchar) '\277',
+(uchar) '\340',(uchar) '\341',(uchar) '\342',(uchar) '\343',(uchar) '\344',(uchar) '\345',(uchar) '\346',(uchar) '\347',
+(uchar) '\350',(uchar) '\351',(uchar) '\352',(uchar) '\353',(uchar) '\354',(uchar) '\355',(uchar) '\356',(uchar) '\357',
+(uchar) '\360',(uchar) '\361',(uchar) '\362',(uchar) '\363',(uchar) '\364',(uchar) '\365',(uchar) '\366',(uchar) '\327',
+(uchar) '\370',(uchar) '\371',(uchar) '\372',(uchar) '\373',(uchar) '\374',(uchar) '\375',(uchar) '\376',(uchar) '\337',
+(uchar) '\340',(uchar) '\341',(uchar) '\342',(uchar) '\343',(uchar) '\344',(uchar) '\345',(uchar) '\346',(uchar) '\347',
+(uchar) '\350',(uchar) '\351',(uchar) '\352',(uchar) '\353',(uchar) '\354',(uchar) '\355',(uchar) '\356',(uchar) '\357',
+(uchar) '\360',(uchar) '\361',(uchar) '\362',(uchar) '\363',(uchar) '\364',(uchar) '\365',(uchar) '\366',(uchar) '\367',
+(uchar) '\370',(uchar) '\371',(uchar) '\372',(uchar) '\373',(uchar) '\374',(uchar) '\375',(uchar) '\376',(uchar) '\377',
+};
+
+uchar NEAR to_upper_dec8[]={
+'\000','\001','\002','\003','\004','\005','\006','\007',
+'\010','\011','\012','\013','\014','\015','\016','\017',
+'\020','\021','\022','\023','\024','\025','\026','\027',
+'\030','\031','\032','\033','\034','\035','\036','\037',
+' ', '!', '"', '#', '$', '%', '&', '\'',
+'(', ')', '*', '+', ',', '-', '.', '/',
+'0', '1', '2', '3', '4', '5', '6', '7',
+'8', '9', ':', ';', '<', '=', '>', '?',
+'@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+'X', 'Y', 'Z', '[', '\\', ']', '^', '_',
+'`', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+'X', 'Y', 'Z', '{', '|', '}', '~', '\177',
+
+(uchar) '\200',(uchar) '\201',(uchar) '\202',(uchar) '\203',(uchar) '\204',(uchar) '\205',(uchar) '\206',(uchar) '\207',
+(uchar) '\210',(uchar) '\211',(uchar) '\212',(uchar) '\213',(uchar) '\214',(uchar) '\215',(uchar) '\216',(uchar) '\217',
+(uchar) '\220',(uchar) '\221',(uchar) '\222',(uchar) '\223',(uchar) '\224',(uchar) '\225',(uchar) '\226',(uchar) '\227',
+(uchar) '\230',(uchar) '\231',(uchar) '\232',(uchar) '\233',(uchar) '\234',(uchar) '\235',(uchar) '\236',(uchar) '\237',
+(uchar) '\240',(uchar) '\241',(uchar) '\242',(uchar) '\243',(uchar) '\244',(uchar) '\245',(uchar) '\246',(uchar) '\247',
+(uchar) '\250',(uchar) '\251',(uchar) '\252',(uchar) '\253',(uchar) '\254',(uchar) '\255',(uchar) '\256',(uchar) '\257',
+(uchar) '\260',(uchar) '\261',(uchar) '\262',(uchar) '\263',(uchar) '\264',(uchar) '\265',(uchar) '\266',(uchar) '\267',
+(uchar) '\270',(uchar) '\271',(uchar) '\272',(uchar) '\273',(uchar) '\274',(uchar) '\275',(uchar) '\276',(uchar) '\277',
+(uchar) '\300',(uchar) '\301',(uchar) '\302',(uchar) '\303',(uchar) '\304',(uchar) '\305',(uchar) '\306',(uchar) '\307',
+(uchar) '\310',(uchar) '\311',(uchar) '\312',(uchar) '\313',(uchar) '\314',(uchar) '\315',(uchar) '\316',(uchar) '\317',
+(uchar) '\320',(uchar) '\321',(uchar) '\322',(uchar) '\323',(uchar) '\324',(uchar) '\325',(uchar) '\326',(uchar) '\327',
+(uchar) '\330',(uchar) '\331',(uchar) '\332',(uchar) '\333',(uchar) '\334',(uchar) '\335',(uchar) '\336',(uchar) '\337',
+(uchar) '\300',(uchar) '\301',(uchar) '\302',(uchar) '\303',(uchar) '\304',(uchar) '\305',(uchar) '\306',(uchar) '\307',
+(uchar) '\310',(uchar) '\311',(uchar) '\312',(uchar) '\313',(uchar) '\314',(uchar) '\315',(uchar) '\316',(uchar) '\317',
+(uchar) '\320',(uchar) '\321',(uchar) '\322',(uchar) '\323',(uchar) '\324',(uchar) '\325',(uchar) '\326',(uchar) '\367',
+(uchar) '\330',(uchar) '\331',(uchar) '\332',(uchar) '\333',(uchar) '\334',(uchar) '\335',(uchar) '\336',(uchar) '\377',
+};
+
+uchar NEAR sort_order_dec8[]={
+'\000','\001','\002','\003','\004','\005','\006','\007',
+'\010','\011','\012','\013','\014','\015','\016','\017',
+'\020','\021','\022','\023','\024','\025','\026','\027',
+'\030','\031','\032','\033','\034','\035','\036','\037',
+' ', '!', '"', '#', '$', '%', '&', '\'',
+'(', ')', '*', '+', ',', '-', '.', '/',
+'0', '1', '2', '3', '4', '5', '6', '7',
+'8', '9', ':', ';', '<', '=', '>', '?',
+'@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+'X', 'Y', 'Z', '[', '\\', ']', '^', '_',
+'`', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+'X', 'Y', 'Z', '{', '|', '}', '~', '\177',
+
+(uchar) '\200',(uchar) '\201',(uchar) '\202',(uchar) '\203',(uchar) '\204',(uchar) '\205',(uchar) '\206',(uchar) '\207',
+(uchar) '\210',(uchar) '\211',(uchar) '\212',(uchar) '\213',(uchar) '\214',(uchar) '\215',(uchar) '\216',(uchar) '\217',
+(uchar) '\220',(uchar) '\221',(uchar) '\222',(uchar) '\223',(uchar) '\224',(uchar) '\225',(uchar) '\226',(uchar) '\227',
+(uchar) '\230',(uchar) '\231',(uchar) '\232',(uchar) '\233',(uchar) '\234',(uchar) '\235',(uchar) '\236',(uchar) '\237',
+(uchar) '\240',(uchar) '\241',(uchar) '\242',(uchar) '\243',(uchar) '\244',(uchar) '\245',(uchar) '\246',(uchar) '\247',
+(uchar) '\250',(uchar) '\251',(uchar) '\252',(uchar) '\253',(uchar) '\254',(uchar) '\255',(uchar) '\256',(uchar) '\257',
+(uchar) '\260',(uchar) '\261',(uchar) '\262',(uchar) '\263',(uchar) '\264',(uchar) '\265',(uchar) '\266',(uchar) '\267',
+(uchar) '\270',(uchar) '\271',(uchar) '\272',(uchar) '\273',(uchar) '\274',(uchar) '\275',(uchar) '\276',(uchar) '\277',
+'A', 'A', 'A', 'A', '\\', '[', '\\', 'C',
+'E', 'E', 'E', 'E', 'I', 'I', 'I', 'I',
+'D', 'N', 'O', 'O', 'O', 'O', ']', (uchar) '\327',
+(uchar) '\330','U', 'U', 'U', 'Y', 'Y', (uchar) '\336',(uchar) '\337',
+'A', 'A', 'A', 'A', '\\', '[', '\\', 'C',
+'E', 'E', 'E', 'E', 'I', 'I', 'I', 'I',
+'D', 'N', 'O', 'O', 'O', 'O', ']', (uchar) '\367',
+(uchar) '\330','U', 'U', 'U', 'Y', 'Y', (uchar) '\336',(uchar) '\377',
+};
diff --git a/strings/Attic/ctype-dos.c b/strings/Attic/ctype-dos.c
new file mode 100644
index 00000000000..0578a33bfd0
--- /dev/null
+++ b/strings/Attic/ctype-dos.c
@@ -0,0 +1,139 @@
+/* Copyright Abandoned 1996 TCX DataKonsult AB & Monty Program KB & Detron HB
+ This file is public domain and comes with NO WARRANTY of any kind */
+
+#include <global.h>
+#include "m_string.h"
+
+#ifndef _WINDOWS
+uchar NEAR ctype[257] =
+{
+ 0, /* For standard library */
+ 32,48,48,48,48,48,48,32,32,40,40,40,40,40,48,48,
+ 48,48,48,48,48,48,48,48,48,48,32,48,48,48,48,48,
+ 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,48,
+
+ 2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,
+ 1,2,1,2,2,2,2,2,2,1,1,16,16,16,16,16,
+ 2,2,2,2,2,1,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,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,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,32,
+};
+
+uchar NEAR to_lower[]=
+{
+ '\000','\001','\002','\003','\004','\005','\006','\007',
+ '\010','\011','\012','\013','\014','\015','\016','\017',
+ '\020','\021','\022','\023','\024','\025','\026','\027',
+ '\030','\031','\032','\033','\034','\035','\036','\037',
+ ' ', '!', '"', '#', '$', '%', '&', '\'',
+ '(', ')', '*', '+', ',', '-', '.', '/',
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', ':', ';', '<', '=', '>', '?',
+ '@', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
+ 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
+ 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
+ 'x', 'y', 'z', '[', '\\', ']', '^', '_',
+ '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
+ 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
+ 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
+ 'x', 'y', 'z', '{', '|', '}', '~', '\177',
+ 135, 129, 130, 131, 132, 133, 134, 135,
+ 136, 137, 138, 139, 140, 141, 132, 134,
+ 130, 145, 145, 147, 148, 149, 150, 151,
+ 152, 148, 129, 155, 156, 157, 158, 159,
+ 160, 161, 162, 163, 164, 164, 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,
+ 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 NEAR to_upper[]=
+{
+ '\000','\001','\002','\003','\004','\005','\006','\007',
+ '\010','\011','\012','\013','\014','\015','\016','\017',
+ '\020','\021','\022','\023','\024','\025','\026','\027',
+ '\030','\031','\032','\033','\034','\035','\036','\037',
+ ' ', '!', '"', '#', '$', '%', '&', '\'',
+ '(', ')', '*', '+', ',', '-', '.', '/',
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', ':', ';', '<', '=', '>', '?',
+ '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+ 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+ 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+ 'X', 'Y', 'Z', '[', '\\', ']', '^', '_',
+ '`', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+ 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+ 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+ 'X', 'Y', 'Z', '{', '|', '}', '~', '\177',
+
+ 128, 154, 144, 65, 142, 65, 143, 128,
+ 69, 69, 69, 73, 73, 73, 142, 143,
+ 144, 146, 146, 79, 153, 79, 85, 85,
+ 89, 153, 154, 155, 156, 157, 158, 159,
+ 65, 73, 79, 85, 165, 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,
+ 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 NEAR sort_order[]=
+{
+ '\000','\001','\002','\003','\004','\005','\006','\007',
+ '\010','\011','\012','\013','\014','\015','\016','\017',
+ '\020','\021','\022','\023','\024','\025','\026','\027',
+ '\030','\031','\032','\033','\034','\035','\036','\037',
+ ' ', '!', '"', '#', '$', '%', '&', '\'',
+ '(', ')', '*', '+', ',', '-', '.', '/',
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', ':', ';', '<', '=', '>', '?',
+ '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+ 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+ 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+ 'X', 'Y', 'Z', '[', '\\', ']', '^', '_',
+ '`', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+ 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+ 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+ 'X', 'Y', 'Z', '{', '|', '}', '~', '\177',
+ 67, 89, 69, 65, 92, 65, 91, 67,
+ 69, 69, 69, 73, 73, 73, 92, 91,
+ 69, 92, 92, 79, 93, 79, 85, 85,
+ 89, 93, 89, 36, 36, 36, 36, 36,
+ 65, 73, 79, 85, 78, 78, 166, 167,
+ 63, 169, 170, 171, 172, 33, 34, 34,
+ 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,
+ 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,
+};
+
+#endif
diff --git a/strings/Attic/ctype-estonia.c b/strings/Attic/ctype-estonia.c
new file mode 100644
index 00000000000..f17463583c9
--- /dev/null
+++ b/strings/Attic/ctype-estonia.c
@@ -0,0 +1,93 @@
+/* See on Eesti character-set,
+mis on kasutatav koos iso-8859-1(Latin1) tähestikuga
+autor : Ülo Sõstra ylo@stat.vil.ee
+*/
+
+#include <global.h>
+#include "m_string.h"
+
+uchar NEAR ctype_estonia[257] = {
+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 NEAR to_lower_estonia[]={
+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,
+184, 169, 186, 171, 172, 173, 174, 191, 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 NEAR to_upper_estonia[]={
+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, 168, 185,
+170, 187, 188, 189, 190, 175, 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
+};
+
+#ifndef __WIN32__
+uchar NEAR sort_order_estonia[]={
+#else
+uchar sort_order_estonia[]={
+#endif
+0, 2, 3, 4, 5, 6, 7, 8, 9, 46, 47, 48, 49, 50, 10, 11, 12, 13, 14, 15,
+16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 44, 51, 52, 53, 54, 55,
+56, 39, 57, 58, 59, 93, 60, 40, 61, 62, 118, 122, 124, 126, 128, 129, 130,
+131, 132, 133, 63, 64, 94, 95, 96, 65, 66, 134, 144, 146, 152, 154, 164, 166,
+170, 172, 178, 180, 184, 190, 192, 198, 206, 208, 210, 214, 229, 232, 238, 240,
+250, 252, 221, 67, 68, 69, 70, 71, 72, 135, 145, 147, 153, 155, 165, 167, 171,
+173, 179, 181, 185, 191, 193, 199, 207, 209, 211, 215, 230, 233, 239, 241, 251,
+253, 222, 73, 74, 75, 76, 28, 1, 29, 87, 30, 90, 116, 113, 114, 31, 117, 32, 91,
+33, 78, 82, 81, 34, 85, 86, 88, 89, 115, 42, 43, 35, 231, 36, 92, 37, 79, 84, 38, 45,
+254, 102, 103, 104, 255, 77, 105, 204, 106, 212, 98, 107, 41, 108, 142, 109, 97, 125,
+127, 80, 110, 111, 112, 205, 123, 213, 99, 119, 120, 121, 143, 140, 176, 136, 148, 244,
+138, 162, 160, 150, 156, 223, 158, 168, 182, 174, 186, 219, 194, 196, 200, 202, 242, 246,
+100, 236, 188, 216, 234, 248, 225, 227, 218, 141, 177, 137, 149, 245, 139, 163, 161, 151,
+157, 224, 159, 169, 183, 175, 187, 220, 195, 197, 201, 203, 243, 247, 101, 237, 189, 217,
+235, 249, 226, 228, 83
+};
diff --git a/strings/Attic/ctype-german1.c b/strings/Attic/ctype-german1.c
new file mode 100755
index 00000000000..f767edc5f3d
--- /dev/null
+++ b/strings/Attic/ctype-german1.c
@@ -0,0 +1,135 @@
+/* Copyright Abandoned 1996 TCX DataKonsult AB & Monty Program KB & Detron HB
+ This file is public domain and comes with NO WARRANTY of any kind */
+
+/* This implements the ISO 8859 Latin1 (Modified for German) character-set */
+
+#include <global.h>
+#include "m_string.h"
+
+uchar NEAR ctype_german1[257] = {
+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 NEAR to_lower_german1[]={
+'\000','\001','\002','\003','\004','\005','\006','\007',
+'\010','\011','\012','\013','\014','\015','\016','\017',
+'\020','\021','\022','\023','\024','\025','\026','\027',
+'\030','\031','\032','\033','\034','\035','\036','\037',
+' ', '!', '"', '#', '$', '%', '&', '\'',
+'(', ')', '*', '+', ',', '-', '.', '/',
+'0', '1', '2', '3', '4', '5', '6', '7',
+'8', '9', ':', ';', '<', '=', '>', '?',
+'@', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
+'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
+'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
+'x', 'y', 'z', '[', '\\', ']', '^', '_',
+'`', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
+'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
+'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
+'x', 'y', 'z', '{', '|', '}', '~', '\177',
+
+(uchar) '\200',(uchar) '\201',(uchar) '\202',(uchar) '\203',(uchar) '\204',(uchar) '\205',(uchar) '\206',(uchar) '\207',
+(uchar) '\210',(uchar) '\211',(uchar) '\212',(uchar) '\213',(uchar) '\214',(uchar) '\215',(uchar) '\216',(uchar) '\217',
+(uchar) '\220',(uchar) '\221',(uchar) '\222',(uchar) '\223',(uchar) '\224',(uchar) '\225',(uchar) '\226',(uchar) '\227',
+(uchar) '\230',(uchar) '\231',(uchar) '\232',(uchar) '\233',(uchar) '\234',(uchar) '\235',(uchar) '\236',(uchar) '\237',
+(uchar) '\240',(uchar) '\241',(uchar) '\242',(uchar) '\243',(uchar) '\244',(uchar) '\245',(uchar) '\246',(uchar) '\247',
+(uchar) '\250',(uchar) '\251',(uchar) '\252',(uchar) '\253',(uchar) '\254',(uchar) '\255',(uchar) '\256',(uchar) '\257',
+(uchar) '\260',(uchar) '\261',(uchar) '\262',(uchar) '\263',(uchar) '\264',(uchar) '\265',(uchar) '\266',(uchar) '\267',
+(uchar) '\270',(uchar) '\271',(uchar) '\272',(uchar) '\273',(uchar) '\274',(uchar) '\275',(uchar) '\276',(uchar) '\277',
+(uchar) '\340',(uchar) '\341',(uchar) '\342',(uchar) '\343',(uchar) '\344',(uchar) '\345',(uchar) '\346',(uchar) '\347',
+(uchar) '\350',(uchar) '\351',(uchar) '\352',(uchar) '\353',(uchar) '\354',(uchar) '\355',(uchar) '\356',(uchar) '\357',
+(uchar) '\360',(uchar) '\361',(uchar) '\362',(uchar) '\363',(uchar) '\364',(uchar) '\365',(uchar) '\366',(uchar) '\327',
+(uchar) '\370',(uchar) '\371',(uchar) '\372',(uchar) '\373',(uchar) '\374',(uchar) '\375',(uchar) '\376',(uchar) '\337',
+(uchar) '\340',(uchar) '\341',(uchar) '\342',(uchar) '\343',(uchar) '\344',(uchar) '\345',(uchar) '\346',(uchar) '\347',
+(uchar) '\350',(uchar) '\351',(uchar) '\352',(uchar) '\353',(uchar) '\354',(uchar) '\355',(uchar) '\356',(uchar) '\357',
+(uchar) '\360',(uchar) '\361',(uchar) '\362',(uchar) '\363',(uchar) '\364',(uchar) '\365',(uchar) '\366',(uchar) '\367',
+(uchar) '\370',(uchar) '\371',(uchar) '\372',(uchar) '\373',(uchar) '\374',(uchar) '\375',(uchar) '\376',(uchar) '\377',
+};
+
+uchar NEAR to_upper_german1[]={
+'\000','\001','\002','\003','\004','\005','\006','\007',
+'\010','\011','\012','\013','\014','\015','\016','\017',
+'\020','\021','\022','\023','\024','\025','\026','\027',
+'\030','\031','\032','\033','\034','\035','\036','\037',
+' ', '!', '"', '#', '$', '%', '&', '\'',
+'(', ')', '*', '+', ',', '-', '.', '/',
+'0', '1', '2', '3', '4', '5', '6', '7',
+'8', '9', ':', ';', '<', '=', '>', '?',
+'@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+'X', 'Y', 'Z', '[', '\\', ']', '^', '_',
+'`', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+'X', 'Y', 'Z', '{', '|', '}', '~', '\177',
+
+(uchar) '\200',(uchar) '\201',(uchar) '\202',(uchar) '\203',(uchar) '\204',(uchar) '\205',(uchar) '\206',(uchar) '\207',
+(uchar) '\210',(uchar) '\211',(uchar) '\212',(uchar) '\213',(uchar) '\214',(uchar) '\215',(uchar) '\216',(uchar) '\217',
+(uchar) '\220',(uchar) '\221',(uchar) '\222',(uchar) '\223',(uchar) '\224',(uchar) '\225',(uchar) '\226',(uchar) '\227',
+(uchar) '\230',(uchar) '\231',(uchar) '\232',(uchar) '\233',(uchar) '\234',(uchar) '\235',(uchar) '\236',(uchar) '\237',
+(uchar) '\240',(uchar) '\241',(uchar) '\242',(uchar) '\243',(uchar) '\244',(uchar) '\245',(uchar) '\246',(uchar) '\247',
+(uchar) '\250',(uchar) '\251',(uchar) '\252',(uchar) '\253',(uchar) '\254',(uchar) '\255',(uchar) '\256',(uchar) '\257',
+(uchar) '\260',(uchar) '\261',(uchar) '\262',(uchar) '\263',(uchar) '\264',(uchar) '\265',(uchar) '\266',(uchar) '\267',
+(uchar) '\270',(uchar) '\271',(uchar) '\272',(uchar) '\273',(uchar) '\274',(uchar) '\275',(uchar) '\276',(uchar) '\277',
+(uchar) '\300',(uchar) '\301',(uchar) '\302',(uchar) '\303',(uchar) '\304',(uchar) '\305',(uchar) '\306',(uchar) '\307',
+(uchar) '\310',(uchar) '\311',(uchar) '\312',(uchar) '\313',(uchar) '\314',(uchar) '\315',(uchar) '\316',(uchar) '\317',
+(uchar) '\320',(uchar) '\321',(uchar) '\322',(uchar) '\323',(uchar) '\324',(uchar) '\325',(uchar) '\326',(uchar) '\327',
+(uchar) '\330',(uchar) '\331',(uchar) '\332',(uchar) '\333',(uchar) '\334',(uchar) '\335',(uchar) '\336',(uchar) '\337',
+(uchar) '\300',(uchar) '\301',(uchar) '\302',(uchar) '\303',(uchar) '\304',(uchar) '\305',(uchar) '\306',(uchar) '\307',
+(uchar) '\310',(uchar) '\311',(uchar) '\312',(uchar) '\313',(uchar) '\314',(uchar) '\315',(uchar) '\316',(uchar) '\317',
+(uchar) '\320',(uchar) '\321',(uchar) '\322',(uchar) '\323',(uchar) '\324',(uchar) '\325',(uchar) '\326',(uchar) '\367',
+(uchar) '\330',(uchar) '\331',(uchar) '\332',(uchar) '\333',(uchar) '\334',(uchar) '\335',(uchar) '\336',(uchar) '\377',
+};
+
+uchar NEAR sort_order_german1[]={
+'\000','\001','\002','\003','\004','\005','\006','\007',
+'\010','\011','\012','\013','\014','\015','\016','\017',
+'\020','\021','\022','\023','\024','\025','\026','\027',
+'\030','\031','\032','\033','\034','\035','\036','\037',
+' ', '!', '"', '#', '$', '%', '&', '\'',
+'(', ')', '*', '+', ',', '-', '.', '/',
+'0', '1', '2', '3', '4', '5', '6', '7',
+'8', '9', ':', ';', '<', '=', '>', '?',
+'@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+'X', 'Y', 'Z', '[', '\\', ']', '^', '_',
+'`', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+'X', 'Y', 'Z', '{', '|', '}', '~', '\177',
+
+(uchar) '\200',(uchar) '\201',(uchar) '\202',(uchar) '\203',(uchar) '\204',(uchar) '\205',(uchar) '\206',(uchar) '\207',
+(uchar) '\210',(uchar) '\211',(uchar) '\212',(uchar) '\213',(uchar) '\214',(uchar) '\215',(uchar) '\216',(uchar) '\217',
+(uchar) '\220',(uchar) '\221',(uchar) '\222',(uchar) '\223',(uchar) '\224',(uchar) '\225',(uchar) '\226',(uchar) '\227',
+(uchar) '\230',(uchar) '\231',(uchar) '\232',(uchar) '\233',(uchar) '\234',(uchar) '\235',(uchar) '\236',(uchar) '\237',
+(uchar) '\240',(uchar) '\241',(uchar) '\242',(uchar) '\243',(uchar) '\244',(uchar) '\245',(uchar) '\246',(uchar) '\247',
+(uchar) '\250',(uchar) '\251',(uchar) '\252',(uchar) '\253',(uchar) '\254',(uchar) '\255',(uchar) '\256',(uchar) '\257',
+(uchar) '\260',(uchar) '\261',(uchar) '\262',(uchar) '\263',(uchar) '\264',(uchar) '\265',(uchar) '\266',(uchar) '\267',
+(uchar) '\270',(uchar) '\271',(uchar) '\272',(uchar) '\273',(uchar) '\274',(uchar) '\275',(uchar) '\276',(uchar) '\277',
+'A', 'A', 'A', 'A', 'A', 'A', 'A', 'C',
+'E', 'E', 'E', 'E', 'I', 'I', 'I', 'I',
+'D', 'N', 'O', 'O', 'O', 'O', 'O', (uchar) '\327',
+(uchar) '\330','U', 'U', 'U', 'U', 'Y', (uchar) '\336',(uchar) '\337',
+'A', 'A', 'A', 'A', 'A', 'A', 'A', 'C',
+'E', 'E', 'E', 'E', 'I', 'I', 'I', 'I',
+'D', 'N', 'O', 'O', 'O', 'O', 'O', (uchar) '\367',
+(uchar) '\330','U', 'U', 'U', 'U', 'Y', (uchar) '\336',(uchar) '\377',
+};
diff --git a/strings/Attic/ctype-greek.c b/strings/Attic/ctype-greek.c
new file mode 100644
index 00000000000..8d101687c91
--- /dev/null
+++ b/strings/Attic/ctype-greek.c
@@ -0,0 +1,855 @@
+/* SCV: The content of this file is freeware.
+ Use it or abuse it. I couldn't care less */
+
+/* This implements the ISO 8859-7 Greek character-set */
+/* See the end of this file for a definition of the set */
+
+#include <global.h>
+#include "m_string.h"
+
+/* some definitions first */
+#define GREEK_TONOS ((uchar)('\264')) /* 180 */
+#define GREEK_DIALYTIKA_TONOS ((uchar)('\265')) /* 181 */
+#define GREEK_CAPITAL_LETTER_ALPHA_WITH_TONOS ((uchar)('\266')) /* 182 */
+#define GREEK_CAPITAL_LETTER_EPSILON_WITH_TONOS ((uchar)('\270')) /* 184 */
+#define GREEK_CAPITAL_LETTER_ETA_WITH_TONOS ((uchar)('\271')) /* 185 */
+#define GREEK_CAPITAL_LETTER_IOTA_WITH_TONOS ((uchar)('\272')) /* 186 */
+#define GREEK_CAPITAL_LETTER_OMICRON_WITH_TONOS ((uchar)('\274')) /* 188 */
+#define GREEK_CAPITAL_LETTER_UPSILON_WITH_TONOS ((uchar)('\276')) /* 190 */
+#define GREEK_CAPITAL_LETTER_OMEGA_WITH_TONOS ((uchar)('\277')) /* 191 */
+#define GREEK_SMALL_LETTER_IOTA_WITH_DIALYTIKA_AND_TONOS ((uchar)('\300')) /* 192 */
+#define GREEK_CAPITAL_LETTER_ALPHA ((uchar)('\301')) /* 193 */
+#define GREEK_CAPITAL_LETTER_BETA ((uchar)('\302')) /* 194 */
+#define GREEK_CAPITAL_LETTER_GAMMA ((uchar)('\303')) /* 195 */
+#define GREEK_CAPITAL_LETTER_DELTA ((uchar)('\304')) /* 196 */
+#define GREEK_CAPITAL_LETTER_EPSILON ((uchar)('\305')) /* 197 */
+#define GREEK_CAPITAL_LETTER_ZETA ((uchar)('\306')) /* 198 */
+#define GREEK_CAPITAL_LETTER_ETA ((uchar)('\307')) /* 199 */
+#define GREEK_CAPITAL_LETTER_THETA ((uchar)('\310')) /* 200 */
+#define GREEK_CAPITAL_LETTER_IOTA ((uchar)('\311')) /* 201 */
+#define GREEK_CAPITAL_LETTER_KAPPA ((uchar)('\312')) /* 202 */
+#define GREEK_CAPITAL_LETTER_LAMDA ((uchar)('\313')) /* 203 */
+#define GREEK_CAPITAL_LETTER_MU ((uchar)('\314')) /* 204 */
+#define GREEK_CAPITAL_LETTER_NU ((uchar)('\315')) /* 205 */
+#define GREEK_CAPITAL_LETTER_XI ((uchar)('\316')) /* 206 */
+#define GREEK_CAPITAL_LETTER_OMICRON ((uchar)('\317')) /* 207 */
+#define GREEK_CAPITAL_LETTER_PI ((uchar)('\320')) /* 208 */
+#define GREEK_CAPITAL_LETTER_RHO ((uchar)('\321')) /* 209 */
+#define GREEK_CAPITAL_LETTER_SIGMA ((uchar)('\323')) /* 211 */
+#define GREEK_CAPITAL_LETTER_TAU ((uchar)('\324')) /* 212 */
+#define GREEK_CAPITAL_LETTER_UPSILON ((uchar)('\325')) /* 213 */
+#define GREEK_CAPITAL_LETTER_PHI ((uchar)('\326')) /* 214 */
+#define GREEK_CAPITAL_LETTER_CHI ((uchar)('\327')) /* 215 */
+#define GREEK_CAPITAL_LETTER_PSI ((uchar)('\330')) /* 216 */
+#define GREEK_CAPITAL_LETTER_OMEGA ((uchar)('\331')) /* 217 */
+#define GREEK_CAPITAL_LETTER_IOTA_WITH_DIALYTIKA ((uchar)('\332')) /* 218 */
+#define GREEK_CAPITAL_LETTER_UPSILON_WITH_DIALYTIKA ((uchar)('\333')) /* 219 */
+#define GREEK_SMALL_LETTER_ALPHA_WITH_TONOS ((uchar)('\334')) /* 220 */
+#define GREEK_SMALL_LETTER_EPSILON_WITH_TONOS ((uchar)('\335')) /* 221 */
+#define GREEK_SMALL_LETTER_ETA_WITH_TONOS ((uchar)('\336')) /* 222 */
+#define GREEK_SMALL_LETTER_IOTA_WITH_TONOS ((uchar)('\337')) /* 223 */
+#define GREEK_SMALL_LETTER_UPSILON_WITH_DIALYTIKA_AND_TONOS ((uchar)('\340')) /* 224 */
+#define GREEK_SMALL_LETTER_ALPHA ((uchar)('\341')) /* 225 */
+#define GREEK_SMALL_LETTER_BETA ((uchar)('\342')) /* 226 */
+#define GREEK_SMALL_LETTER_GAMMA ((uchar)('\343')) /* 227 */
+#define GREEK_SMALL_LETTER_DELTA ((uchar)('\344')) /* 228 */
+#define GREEK_SMALL_LETTER_EPSILON ((uchar)('\345')) /* 229 */
+#define GREEK_SMALL_LETTER_ZETA ((uchar)('\346')) /* 230 */
+#define GREEK_SMALL_LETTER_ETA ((uchar)('\347')) /* 231 */
+#define GREEK_SMALL_LETTER_THETA ((uchar)('\350')) /* 232 */
+#define GREEK_SMALL_LETTER_IOTA ((uchar)('\351')) /* 233 */
+#define GREEK_SMALL_LETTER_KAPPA ((uchar)('\352')) /* 234 */
+#define GREEK_SMALL_LETTER_LAMDA ((uchar)('\353')) /* 235 */
+#define GREEK_SMALL_LETTER_MU ((uchar)('\354')) /* 236 */
+#define GREEK_SMALL_LETTER_NU ((uchar)('\355')) /* 237 */
+#define GREEK_SMALL_LETTER_XI ((uchar)('\356')) /* 238 */
+#define GREEK_SMALL_LETTER_OMICRON ((uchar)('\357')) /* 239 */
+#define GREEK_SMALL_LETTER_PI ((uchar)('\360')) /* 240 */
+#define GREEK_SMALL_LETTER_RHO ((uchar)('\361')) /* 241 */
+#define GREEK_SMALL_LETTER_FINAL_SIGMA ((uchar)('\362')) /* 242 */
+#define GREEK_SMALL_LETTER_SIGMA ((uchar)('\363')) /* 243 */
+#define GREEK_SMALL_LETTER_TAU ((uchar)('\364')) /* 244 */
+#define GREEK_SMALL_LETTER_UPSILON ((uchar)('\365')) /* 245 */
+#define GREEK_SMALL_LETTER_PHI ((uchar)('\366')) /* 246 */
+#define GREEK_SMALL_LETTER_CHI ((uchar)('\367')) /* 247 */
+#define GREEK_SMALL_LETTER_PSI ((uchar)('\370')) /* 248 */
+#define GREEK_SMALL_LETTER_OMEGA ((uchar)('\371')) /* 249 */
+#define GREEK_SMALL_LETTER_IOTA_WITH_DIALYTIKA ((uchar)('\372')) /* 250 */
+#define GREEK_SMALL_LETTER_UPSILON_WITH_DIALYTIKA ((uchar)('\373')) /* 251 */
+#define GREEK_SMALL_LETTER_OMICRON_WITH_TONOS ((uchar)('\374')) /* 252 */
+#define GREEK_SMALL_LETTER_UPSILON_WITH_TONOS ((uchar)('\375')) /* 253 */
+#define GREEK_SMALL_LETTER_OMEGA_WITH_TONOS ((uchar)('\376')) /* 254 */
+
+uchar NEAR ctype_greek[257] = {
+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,
+ /* 0 - 160 are the same as latin-1 */
+/* 160 */ 010 + 0100,
+/* 161 */ 020,
+/* 162 */ 020,
+/* 163 */ 020,
+/* 164 */ 0,
+/* 165 */ 0,
+/* 166 */ 020,
+/* 167 */ 020,
+/* 168 */ 020,
+/* 169 */ 020,
+/* 170 */ 0,
+/* 171 */ 020,
+/* 172 */ 020,
+/* 173 */ 020,
+/* 174 */ 0,
+/* 175 */ 020,
+/* 176 */ 020,
+/* 177 */ 020,
+/* 178 */ 020,
+/* 179 */ 020,
+/* 180 */ 020,
+/* 181 */ 020,
+/* 182 */ 01,
+/* 183 */ 020,
+/* 184 */ 01,
+/* 185 */ 01,
+/* 186 */ 01,
+/* 187 */ 020,
+/* 188 */ 01,
+/* 189 */ 020,
+/* 190 */ 01,
+/* 191 */ 01,
+/* 192 */ 02,
+/* 193 */ 01,
+/* 194 */ 01,
+/* 195 */ 01,
+/* 196 */ 01,
+/* 197 */ 01,
+/* 198 */ 01,
+/* 199 */ 01,
+/* 200 */ 01,
+/* 201 */ 01,
+/* 202 */ 01,
+/* 203 */ 01,
+/* 204 */ 01,
+/* 205 */ 01,
+/* 206 */ 01,
+/* 207 */ 01,
+/* 208 */ 01,
+/* 209 */ 01,
+/* 210 */ 0,
+/* 211 */ 01,
+/* 212 */ 01,
+/* 213 */ 01,
+/* 214 */ 01,
+/* 215 */ 01,
+/* 216 */ 01,
+/* 217 */ 01,
+/* 218 */ 01,
+/* 219 */ 01,
+/* 220 */ 02,
+/* 221 */ 02,
+/* 222 */ 02,
+/* 223 */ 02,
+/* 224 */ 02,
+/* 225 */ 02,
+/* 226 */ 02,
+/* 227 */ 02,
+/* 228 */ 02,
+/* 229 */ 02,
+/* 230 */ 02,
+/* 231 */ 02,
+/* 232 */ 02,
+/* 233 */ 02,
+/* 234 */ 02,
+/* 235 */ 02,
+/* 236 */ 02,
+/* 237 */ 02,
+/* 238 */ 02,
+/* 239 */ 02,
+/* 240 */ 02,
+/* 241 */ 02,
+/* 242 */ 02,
+/* 243 */ 02,
+/* 244 */ 02,
+/* 245 */ 02,
+/* 246 */ 02,
+/* 247 */ 02,
+/* 248 */ 02,
+/* 249 */ 02,
+/* 250 */ 02,
+/* 251 */ 02,
+/* 252 */ 02,
+/* 253 */ 02,
+/* 254 */ 02,
+/* 255 */ 0
+};
+
+uchar NEAR to_lower_greek[]={
+'\000','\001','\002','\003','\004','\005','\006','\007',
+'\010','\011','\012','\013','\014','\015','\016','\017',
+'\020','\021','\022','\023','\024','\025','\026','\027',
+'\030','\031','\032','\033','\034','\035','\036','\037',
+' ', '!', '"', '#', '$', '%', '&', '\'',
+'(', ')', '*', '+', ',', '-', '.', '/',
+'0', '1', '2', '3', '4', '5', '6', '7',
+'8', '9', ':', ';', '<', '=', '>', '?',
+'@', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
+'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
+'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
+'x', 'y', 'z', '[', '\\', ']', '^', '_',
+'`', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
+'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
+'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
+'x', 'y', 'z', '{', '|', '}', '~', '\177',
+
+/* 128 */ (uchar)('\200'),
+/* 129 */ (uchar)('\201'),
+/* 130 */ (uchar)('\202'),
+/* 131 */ (uchar)('\203'),
+/* 132 */ (uchar)('\204'),
+/* 133 */ (uchar)('\205'),
+/* 134 */ (uchar)('\206'),
+/* 135 */ (uchar)('\207'),
+/* 136 */ (uchar)('\210'),
+/* 137 */ (uchar)('\211'),
+/* 138 */ (uchar)('\212'),
+/* 139 */ (uchar)('\213'),
+/* 140 */ (uchar)('\214'),
+/* 141 */ (uchar)('\215'),
+/* 142 */ (uchar)('\216'),
+/* 143 */ (uchar)('\217'),
+/* 144 */ (uchar)('\220'),
+/* 145 */ (uchar)('\221'),
+/* 146 */ (uchar)('\222'),
+/* 147 */ (uchar)('\223'),
+/* 148 */ (uchar)('\224'),
+/* 149 */ (uchar)('\225'),
+/* 150 */ (uchar)('\226'),
+/* 151 */ (uchar)('\227'),
+/* 152 */ (uchar)('\230'),
+/* 153 */ (uchar)('\231'),
+/* 154 */ (uchar)('\232'),
+/* 155 */ (uchar)('\233'),
+/* 156 */ (uchar)('\234'),
+/* 157 */ (uchar)('\235'),
+/* 158 */ (uchar)('\236'),
+/* 159 */ (uchar)('\237'),
+/* 160 */ (uchar)('\240'),
+/* 161 */ (uchar)('\241'),
+/* 162 */ (uchar)('\242'),
+/* 163 */ (uchar)('\243'),
+/* 164 */ (uchar)('\244'),
+/* 165 */ (uchar)('\245'),
+/* 166 */ (uchar)('\246'),
+/* 167 */ (uchar)('\247'),
+/* 168 */ (uchar)('\250'),
+/* 169 */ (uchar)('\251'),
+/* 170 */ (uchar)('\252'),
+/* 171 */ (uchar)('\253'),
+/* 172 */ (uchar)('\254'),
+/* 173 */ (uchar)('\255'),
+/* 174 */ (uchar)('\256'),
+/* 175 */ (uchar)('\257'),
+/* 176 */ (uchar)('\260'),
+/* 177 */ (uchar)('\261'),
+/* 178 */ (uchar)('\262'),
+/* 179 */ (uchar)('\263'),
+/* 180 */ GREEK_TONOS,
+/* 181 */ GREEK_DIALYTIKA_TONOS,
+/* 182 */ GREEK_SMALL_LETTER_ALPHA_WITH_TONOS,
+/* 183 */ (uchar)('\267'),
+/* 184 */ GREEK_SMALL_LETTER_EPSILON_WITH_TONOS,
+/* 185 */ GREEK_SMALL_LETTER_ETA_WITH_TONOS,
+/* 186 */ GREEK_SMALL_LETTER_IOTA_WITH_TONOS,
+/* 187 */ (uchar)('\273'),
+/* 188 */ GREEK_SMALL_LETTER_OMICRON_WITH_TONOS,
+/* 189 */ (uchar)('\275'),
+/* 190 */ GREEK_SMALL_LETTER_UPSILON_WITH_TONOS,
+/* 191 */ GREEK_SMALL_LETTER_OMEGA_WITH_TONOS,
+/* 192 */ GREEK_SMALL_LETTER_IOTA_WITH_DIALYTIKA_AND_TONOS,
+/* 193 */ GREEK_SMALL_LETTER_ALPHA,
+/* 194 */ GREEK_SMALL_LETTER_BETA,
+/* 195 */ GREEK_SMALL_LETTER_GAMMA,
+/* 196 */ GREEK_SMALL_LETTER_DELTA,
+/* 197 */ GREEK_SMALL_LETTER_EPSILON,
+/* 198 */ GREEK_SMALL_LETTER_ZETA,
+/* 199 */ GREEK_SMALL_LETTER_ETA,
+/* 200 */ GREEK_SMALL_LETTER_THETA,
+/* 201 */ GREEK_SMALL_LETTER_IOTA,
+/* 202 */ GREEK_SMALL_LETTER_KAPPA,
+/* 203 */ GREEK_SMALL_LETTER_LAMDA,
+/* 204 */ GREEK_SMALL_LETTER_MU,
+/* 205 */ GREEK_SMALL_LETTER_NU,
+/* 206 */ GREEK_SMALL_LETTER_XI,
+/* 207 */ GREEK_SMALL_LETTER_OMICRON,
+/* 208 */ GREEK_SMALL_LETTER_PI,
+/* 209 */ GREEK_SMALL_LETTER_RHO,
+/* 210 */ (uchar)('\322'),
+/* 211 */ GREEK_SMALL_LETTER_SIGMA,
+/* 212 */ GREEK_SMALL_LETTER_TAU,
+/* 213 */ GREEK_SMALL_LETTER_UPSILON,
+/* 214 */ GREEK_SMALL_LETTER_PHI,
+/* 215 */ GREEK_SMALL_LETTER_CHI,
+/* 216 */ GREEK_SMALL_LETTER_PSI,
+/* 217 */ GREEK_SMALL_LETTER_OMEGA,
+/* 218 */ GREEK_SMALL_LETTER_IOTA_WITH_DIALYTIKA,
+/* 219 */ GREEK_SMALL_LETTER_UPSILON_WITH_DIALYTIKA,
+/* 220 */ GREEK_SMALL_LETTER_ALPHA_WITH_TONOS,
+/* 221 */ GREEK_SMALL_LETTER_EPSILON_WITH_TONOS,
+/* 222 */ GREEK_SMALL_LETTER_ETA_WITH_TONOS,
+/* 223 */ GREEK_SMALL_LETTER_IOTA_WITH_TONOS,
+/* 224 */ GREEK_SMALL_LETTER_UPSILON_WITH_DIALYTIKA_AND_TONOS,
+/* 225 */ GREEK_SMALL_LETTER_ALPHA,
+/* 226 */ GREEK_SMALL_LETTER_BETA,
+/* 227 */ GREEK_SMALL_LETTER_GAMMA,
+/* 228 */ GREEK_SMALL_LETTER_DELTA,
+/* 229 */ GREEK_SMALL_LETTER_EPSILON,
+/* 230 */ GREEK_SMALL_LETTER_ZETA,
+/* 231 */ GREEK_SMALL_LETTER_ETA,
+/* 232 */ GREEK_SMALL_LETTER_THETA,
+/* 233 */ GREEK_SMALL_LETTER_IOTA,
+/* 234 */ GREEK_SMALL_LETTER_KAPPA,
+/* 235 */ GREEK_SMALL_LETTER_LAMDA,
+/* 236 */ GREEK_SMALL_LETTER_MU,
+/* 237 */ GREEK_SMALL_LETTER_NU,
+/* 238 */ GREEK_SMALL_LETTER_XI,
+/* 239 */ GREEK_SMALL_LETTER_OMICRON,
+/* 240 */ GREEK_SMALL_LETTER_PI,
+/* 241 */ GREEK_SMALL_LETTER_RHO,
+/* 242 */ GREEK_SMALL_LETTER_FINAL_SIGMA,
+/* 243 */ GREEK_SMALL_LETTER_SIGMA,
+/* 244 */ GREEK_SMALL_LETTER_TAU,
+/* 245 */ GREEK_SMALL_LETTER_UPSILON,
+/* 246 */ GREEK_SMALL_LETTER_PHI,
+/* 247 */ GREEK_SMALL_LETTER_CHI,
+/* 248 */ GREEK_SMALL_LETTER_PSI,
+/* 249 */ GREEK_SMALL_LETTER_OMEGA,
+/* 250 */ GREEK_SMALL_LETTER_IOTA_WITH_DIALYTIKA,
+/* 251 */ GREEK_SMALL_LETTER_UPSILON_WITH_DIALYTIKA,
+/* 252 */ GREEK_SMALL_LETTER_OMICRON_WITH_TONOS,
+/* 253 */ GREEK_SMALL_LETTER_UPSILON_WITH_TONOS,
+/* 254 */ GREEK_SMALL_LETTER_OMEGA_WITH_TONOS,
+/* 255 */ (uchar)('\377')
+};
+
+uchar NEAR to_upper_greek[]={
+'\000','\001','\002','\003','\004','\005','\006','\007',
+'\010','\011','\012','\013','\014','\015','\016','\017',
+'\020','\021','\022','\023','\024','\025','\026','\027',
+'\030','\031','\032','\033','\034','\035','\036','\037',
+' ', '!', '"', '#', '$', '%', '&', '\'',
+'(', ')', '*', '+', ',', '-', '.', '/',
+'0', '1', '2', '3', '4', '5', '6', '7',
+'8', '9', ':', ';', '<', '=', '>', '?',
+'@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+'X', 'Y', 'Z', '[', '\\', ']', '^', '_',
+'`', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+'X', 'Y', 'Z', '{', '|', '}', '~', '\177',
+
+/* 128 */ (uchar)('\200'),
+/* 129 */ (uchar)('\201'),
+/* 130 */ (uchar)('\202'),
+/* 131 */ (uchar)('\203'),
+/* 132 */ (uchar)('\204'),
+/* 133 */ (uchar)('\205'),
+/* 134 */ (uchar)('\206'),
+/* 135 */ (uchar)('\207'),
+/* 136 */ (uchar)('\210'),
+/* 137 */ (uchar)('\211'),
+/* 138 */ (uchar)('\212'),
+/* 139 */ (uchar)('\213'),
+/* 140 */ (uchar)('\214'),
+/* 141 */ (uchar)('\215'),
+/* 142 */ (uchar)('\216'),
+/* 143 */ (uchar)('\217'),
+/* 144 */ (uchar)('\220'),
+/* 145 */ (uchar)('\221'),
+/* 146 */ (uchar)('\222'),
+/* 147 */ (uchar)('\223'),
+/* 148 */ (uchar)('\224'),
+/* 149 */ (uchar)('\225'),
+/* 150 */ (uchar)('\226'),
+/* 151 */ (uchar)('\227'),
+/* 152 */ (uchar)('\230'),
+/* 153 */ (uchar)('\231'),
+/* 154 */ (uchar)('\232'),
+/* 155 */ (uchar)('\233'),
+/* 156 */ (uchar)('\234'),
+/* 157 */ (uchar)('\235'),
+/* 158 */ (uchar)('\236'),
+/* 159 */ (uchar)('\237'),
+/* 160 */ (uchar)('\240'),
+/* 161 */ (uchar)('\241'),
+/* 162 */ (uchar)('\242'),
+/* 163 */ (uchar)('\243'),
+/* 164 */ (uchar)('\244'),
+/* 165 */ (uchar)('\245'),
+/* 166 */ (uchar)('\246'),
+/* 167 */ (uchar)('\247'),
+/* 168 */ (uchar)('\250'),
+/* 169 */ (uchar)('\251'),
+/* 170 */ (uchar)('\252'),
+/* 171 */ (uchar)('\253'),
+/* 172 */ (uchar)('\254'),
+/* 173 */ (uchar)('\255'),
+/* 174 */ (uchar)('\256'),
+/* 175 */ (uchar)('\257'),
+/* 176 */ (uchar)('\260'),
+/* 177 */ (uchar)('\261'),
+/* 178 */ (uchar)('\262'),
+/* 179 */ (uchar)('\263'),
+/* 180 */ GREEK_TONOS,
+/* 181 */ GREEK_DIALYTIKA_TONOS,
+/* 182 */ GREEK_CAPITAL_LETTER_ALPHA_WITH_TONOS,
+/* 183 */ (uchar)('\267'),
+/* 184 */ GREEK_CAPITAL_LETTER_EPSILON_WITH_TONOS,
+/* 185 */ GREEK_CAPITAL_LETTER_ETA_WITH_TONOS,
+/* 186 */ GREEK_CAPITAL_LETTER_IOTA_WITH_TONOS,
+/* 187 */ (uchar)('\273'),
+/* 188 */ GREEK_CAPITAL_LETTER_OMICRON_WITH_TONOS,
+/* 189 */ (uchar)('\275'),
+/* 190 */ GREEK_CAPITAL_LETTER_UPSILON_WITH_TONOS,
+/* 191 */ GREEK_CAPITAL_LETTER_OMEGA_WITH_TONOS,
+/* 192 */ GREEK_CAPITAL_LETTER_IOTA_WITH_DIALYTIKA,
+/* 193 */ GREEK_CAPITAL_LETTER_ALPHA,
+/* 194 */ GREEK_CAPITAL_LETTER_BETA,
+/* 195 */ GREEK_CAPITAL_LETTER_GAMMA,
+/* 196 */ GREEK_CAPITAL_LETTER_DELTA,
+/* 197 */ GREEK_CAPITAL_LETTER_EPSILON,
+/* 198 */ GREEK_CAPITAL_LETTER_ZETA,
+/* 199 */ GREEK_CAPITAL_LETTER_ETA,
+/* 200 */ GREEK_CAPITAL_LETTER_THETA,
+/* 201 */ GREEK_CAPITAL_LETTER_IOTA,
+/* 202 */ GREEK_CAPITAL_LETTER_KAPPA,
+/* 203 */ GREEK_CAPITAL_LETTER_LAMDA,
+/* 204 */ GREEK_CAPITAL_LETTER_MU,
+/* 205 */ GREEK_CAPITAL_LETTER_NU,
+/* 206 */ GREEK_CAPITAL_LETTER_XI,
+/* 207 */ GREEK_CAPITAL_LETTER_OMICRON,
+/* 208 */ GREEK_CAPITAL_LETTER_PI,
+/* 209 */ GREEK_CAPITAL_LETTER_RHO,
+/* 210 */ (uchar)('\322'),
+/* 211 */ GREEK_CAPITAL_LETTER_SIGMA,
+/* 212 */ GREEK_CAPITAL_LETTER_TAU,
+/* 213 */ GREEK_CAPITAL_LETTER_UPSILON,
+/* 214 */ GREEK_CAPITAL_LETTER_PHI,
+/* 215 */ GREEK_CAPITAL_LETTER_CHI,
+/* 216 */ GREEK_CAPITAL_LETTER_PSI,
+/* 217 */ GREEK_CAPITAL_LETTER_OMEGA,
+/* 218 */ GREEK_CAPITAL_LETTER_IOTA_WITH_DIALYTIKA,
+/* 219 */ GREEK_CAPITAL_LETTER_UPSILON_WITH_DIALYTIKA,
+/* 220 */ GREEK_CAPITAL_LETTER_ALPHA,
+/* 221 */ GREEK_CAPITAL_LETTER_EPSILON,
+/* 222 */ GREEK_CAPITAL_LETTER_ETA,
+/* 223 */ GREEK_CAPITAL_LETTER_IOTA,
+/* 224 */ GREEK_CAPITAL_LETTER_UPSILON_WITH_DIALYTIKA,
+/* 225 */ GREEK_CAPITAL_LETTER_ALPHA,
+/* 226 */ GREEK_CAPITAL_LETTER_BETA,
+/* 227 */ GREEK_CAPITAL_LETTER_GAMMA,
+/* 228 */ GREEK_CAPITAL_LETTER_DELTA,
+/* 229 */ GREEK_CAPITAL_LETTER_EPSILON,
+/* 230 */ GREEK_CAPITAL_LETTER_ZETA,
+/* 231 */ GREEK_CAPITAL_LETTER_ETA,
+/* 232 */ GREEK_CAPITAL_LETTER_THETA,
+/* 233 */ GREEK_CAPITAL_LETTER_IOTA,
+/* 234 */ GREEK_CAPITAL_LETTER_KAPPA,
+/* 235 */ GREEK_CAPITAL_LETTER_LAMDA,
+/* 236 */ GREEK_CAPITAL_LETTER_MU,
+/* 237 */ GREEK_CAPITAL_LETTER_NU,
+/* 238 */ GREEK_CAPITAL_LETTER_XI,
+/* 239 */ GREEK_CAPITAL_LETTER_OMICRON,
+/* 240 */ GREEK_CAPITAL_LETTER_PI,
+/* 241 */ GREEK_CAPITAL_LETTER_RHO,
+/* 242 */ GREEK_CAPITAL_LETTER_SIGMA,
+/* 243 */ GREEK_CAPITAL_LETTER_SIGMA,
+/* 244 */ GREEK_CAPITAL_LETTER_TAU,
+/* 245 */ GREEK_CAPITAL_LETTER_UPSILON,
+/* 246 */ GREEK_CAPITAL_LETTER_PHI,
+/* 247 */ GREEK_CAPITAL_LETTER_CHI,
+/* 248 */ GREEK_CAPITAL_LETTER_PSI,
+/* 249 */ GREEK_CAPITAL_LETTER_OMEGA,
+/* 250 */ GREEK_CAPITAL_LETTER_IOTA_WITH_DIALYTIKA,
+/* 251 */ GREEK_CAPITAL_LETTER_UPSILON_WITH_DIALYTIKA,
+/* 252 */ GREEK_CAPITAL_LETTER_OMICRON,
+/* 253 */ GREEK_CAPITAL_LETTER_UPSILON,
+/* 254 */ GREEK_CAPITAL_LETTER_OMEGA,
+/* 255 */ (uchar)('\377')
+};
+
+uchar NEAR sort_order_greek[]={
+'\000','\001','\002','\003','\004','\005','\006','\007',
+'\010','\011','\012','\013','\014','\015','\016','\017',
+'\020','\021','\022','\023','\024','\025','\026','\027',
+'\030','\031','\032','\033','\034','\035','\036','\037',
+' ', '!', '"', '#', '$', '%', '&', '\'',
+'(', ')', '*', '+', ',', '-', '.', '/',
+'0', '1', '2', '3', '4', '5', '6', '7',
+'8', '9', ':', ';', '<', '=', '>', '?',
+'@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+'X', 'Y', 'Z', '[', '\\', ']', '^', '_',
+'`', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+'X', 'Y', 'Z', '{', '|', '}', '~', '\177',
+
+(uchar) '\200',(uchar) '\201',(uchar) '\202',(uchar) '\203',(uchar) '\204',(uchar) '\205',(uchar) '\206',(uchar) '\207',
+(uchar) '\210',(uchar) '\211',(uchar) '\212',(uchar) '\213',(uchar) '\214',(uchar) '\215',(uchar) '\216',(uchar) '\217',
+(uchar) '\220',(uchar) '\221',(uchar) '\222',(uchar) '\223',(uchar) '\224',(uchar) '\225',(uchar) '\226',(uchar) '\227',
+(uchar) '\230',(uchar) '\231',(uchar) '\232',(uchar) '\233',(uchar) '\234',(uchar) '\235',(uchar) '\236',(uchar) '\237',
+(uchar) '\240',(uchar) '\241',(uchar) '\242',(uchar) '\243',(uchar) '\244',(uchar) '\245',(uchar) '\246',(uchar) '\247',
+(uchar) '\250',(uchar) '\251',(uchar) '\252',(uchar) '\253',(uchar) '\254',(uchar) '\255',(uchar) '\256',(uchar) '\257',
+(uchar) '\260',(uchar) '\261',(uchar) '\262',(uchar) '\263',
+ /* 0 - 180 are the same as latin-1 */
+/* 180 */ GREEK_TONOS,
+/* 181 */ GREEK_DIALYTIKA_TONOS,
+/* 182 */ GREEK_CAPITAL_LETTER_ALPHA,
+/* 183 */ (uchar)('\267'),
+/* 184 */ GREEK_CAPITAL_LETTER_EPSILON,
+/* 185 */ GREEK_CAPITAL_LETTER_ETA,
+/* 186 */ GREEK_CAPITAL_LETTER_IOTA,
+/* 187 */ (uchar)('\273'),
+/* 188 */ GREEK_CAPITAL_LETTER_OMICRON,
+/* 189 */ (uchar)('\275'),
+/* 190 */ GREEK_CAPITAL_LETTER_UPSILON,
+/* 191 */ GREEK_CAPITAL_LETTER_OMEGA,
+/* 192 */ GREEK_CAPITAL_LETTER_IOTA,
+/* 193 */ GREEK_CAPITAL_LETTER_ALPHA,
+/* 194 */ GREEK_CAPITAL_LETTER_BETA,
+/* 195 */ GREEK_CAPITAL_LETTER_GAMMA,
+/* 196 */ GREEK_CAPITAL_LETTER_DELTA,
+/* 197 */ GREEK_CAPITAL_LETTER_EPSILON,
+/* 198 */ GREEK_CAPITAL_LETTER_ZETA,
+/* 199 */ GREEK_CAPITAL_LETTER_ETA,
+/* 200 */ GREEK_CAPITAL_LETTER_THETA,
+/* 201 */ GREEK_CAPITAL_LETTER_IOTA,
+/* 202 */ GREEK_CAPITAL_LETTER_KAPPA,
+/* 203 */ GREEK_CAPITAL_LETTER_LAMDA,
+/* 204 */ GREEK_CAPITAL_LETTER_MU,
+/* 205 */ GREEK_CAPITAL_LETTER_NU,
+/* 206 */ GREEK_CAPITAL_LETTER_XI,
+/* 207 */ GREEK_CAPITAL_LETTER_OMICRON,
+/* 208 */ GREEK_CAPITAL_LETTER_PI,
+/* 209 */ GREEK_CAPITAL_LETTER_RHO,
+/* 210 */ (uchar)('\322'),
+/* 211 */ GREEK_CAPITAL_LETTER_SIGMA,
+/* 212 */ GREEK_CAPITAL_LETTER_TAU,
+/* 213 */ GREEK_CAPITAL_LETTER_UPSILON,
+/* 214 */ GREEK_CAPITAL_LETTER_PHI,
+/* 215 */ GREEK_CAPITAL_LETTER_CHI,
+/* 216 */ GREEK_CAPITAL_LETTER_PSI,
+/* 217 */ GREEK_CAPITAL_LETTER_OMEGA,
+/* 218 */ GREEK_CAPITAL_LETTER_IOTA,
+/* 219 */ GREEK_CAPITAL_LETTER_UPSILON,
+/* 220 */ GREEK_CAPITAL_LETTER_ALPHA,
+/* 221 */ GREEK_CAPITAL_LETTER_EPSILON,
+/* 222 */ GREEK_CAPITAL_LETTER_ETA,
+/* 223 */ GREEK_CAPITAL_LETTER_IOTA,
+/* 224 */ GREEK_CAPITAL_LETTER_UPSILON,
+/* 225 */ GREEK_CAPITAL_LETTER_ALPHA,
+/* 226 */ GREEK_CAPITAL_LETTER_BETA,
+/* 227 */ GREEK_CAPITAL_LETTER_GAMMA,
+/* 228 */ GREEK_CAPITAL_LETTER_DELTA,
+/* 229 */ GREEK_CAPITAL_LETTER_EPSILON,
+/* 230 */ GREEK_CAPITAL_LETTER_ZETA,
+/* 231 */ GREEK_CAPITAL_LETTER_ETA,
+/* 232 */ GREEK_CAPITAL_LETTER_THETA,
+/* 233 */ GREEK_CAPITAL_LETTER_IOTA,
+/* 234 */ GREEK_CAPITAL_LETTER_KAPPA,
+/* 235 */ GREEK_CAPITAL_LETTER_LAMDA,
+/* 236 */ GREEK_CAPITAL_LETTER_MU,
+/* 237 */ GREEK_CAPITAL_LETTER_NU,
+/* 238 */ GREEK_CAPITAL_LETTER_XI,
+/* 239 */ GREEK_CAPITAL_LETTER_OMICRON,
+/* 240 */ GREEK_CAPITAL_LETTER_PI,
+/* 241 */ GREEK_CAPITAL_LETTER_RHO,
+/* 242 */ GREEK_CAPITAL_LETTER_SIGMA,
+/* 243 */ GREEK_CAPITAL_LETTER_SIGMA,
+/* 244 */ GREEK_CAPITAL_LETTER_TAU,
+/* 245 */ GREEK_CAPITAL_LETTER_UPSILON,
+/* 246 */ GREEK_CAPITAL_LETTER_PHI,
+/* 247 */ GREEK_CAPITAL_LETTER_CHI,
+/* 248 */ GREEK_CAPITAL_LETTER_PSI,
+/* 249 */ GREEK_CAPITAL_LETTER_OMEGA,
+/* 250 */ GREEK_CAPITAL_LETTER_IOTA,
+/* 251 */ GREEK_CAPITAL_LETTER_UPSILON,
+/* 252 */ GREEK_CAPITAL_LETTER_OMICRON,
+/* 253 */ GREEK_CAPITAL_LETTER_UPSILON,
+/* 254 */ GREEK_CAPITAL_LETTER_OMEGA,
+(uchar) '\377'
+};
+
+/* let's clean after ourselves */
+#undef GREEK_TONOS
+#undef GREEK_DIALYTIKA_TONOS
+#undef GREEK_CAPITAL_LETTER_ALPHA_WITH_TONOS
+#undef GREEK_CAPITAL_LETTER_EPSILON_WITH_TONOS
+#undef GREEK_CAPITAL_LETTER_ETA_WITH_TONOS
+#undef GREEK_CAPITAL_LETTER_IOTA_WITH_TONOS
+#undef GREEK_CAPITAL_LETTER_OMICRON_WITH_TONOS
+#undef GREEK_CAPITAL_LETTER_UPSILON_WITH_TONOS
+#undef GREEK_CAPITAL_LETTER_OMEGA_WITH_TONOS
+#undef GREEK_SMALL_LETTER_IOTA_WITH_DIALYTIKA_AND_TONOS
+#undef GREEK_CAPITAL_LETTER_ALPHA
+#undef GREEK_CAPITAL_LETTER_BETA
+#undef GREEK_CAPITAL_LETTER_GAMMA
+#undef GREEK_CAPITAL_LETTER_DELTA
+#undef GREEK_CAPITAL_LETTER_EPSILON
+#undef GREEK_CAPITAL_LETTER_ZETA
+#undef GREEK_CAPITAL_LETTER_ETA
+#undef GREEK_CAPITAL_LETTER_THETA
+#undef GREEK_CAPITAL_LETTER_IOTA
+#undef GREEK_CAPITAL_LETTER_KAPPA
+#undef GREEK_CAPITAL_LETTER_LAMDA
+#undef GREEK_CAPITAL_LETTER_MU
+#undef GREEK_CAPITAL_LETTER_NU
+#undef GREEK_CAPITAL_LETTER_XI
+#undef GREEK_CAPITAL_LETTER_OMICRON
+#undef GREEK_CAPITAL_LETTER_PI
+#undef GREEK_CAPITAL_LETTER_RHO
+#undef GREEK_CAPITAL_LETTER_SIGMA
+#undef GREEK_CAPITAL_LETTER_TAU
+#undef GREEK_CAPITAL_LETTER_UPSILON
+#undef GREEK_CAPITAL_LETTER_PHI
+#undef GREEK_CAPITAL_LETTER_CHI
+#undef GREEK_CAPITAL_LETTER_PSI
+#undef GREEK_CAPITAL_LETTER_OMEGA
+#undef GREEK_CAPITAL_LETTER_IOTA_WITH_DIALYTIKA
+#undef GREEK_CAPITAL_LETTER_UPSILON_WITH_DIALYTIKA
+#undef GREEK_SMALL_LETTER_ALPHA_WITH_TONOS
+#undef GREEK_SMALL_LETTER_EPSILON_WITH_TONOS
+#undef GREEK_SMALL_LETTER_ETA_WITH_TONOS
+#undef GREEK_SMALL_LETTER_IOTA_WITH_TONOS
+#undef GREEK_SMALL_LETTER_UPSILON_WITH_DIALYTIKA_AND_TONOS ((uchar)('\340')) /* 224 */
+#undef GREEK_SMALL_LETTER_ALPHA
+#undef GREEK_SMALL_LETTER_BETA
+#undef GREEK_SMALL_LETTER_GAMMA
+#undef GREEK_SMALL_LETTER_DELTA
+#undef GREEK_SMALL_LETTER_EPSILON
+#undef GREEK_SMALL_LETTER_ZETA
+#undef GREEK_SMALL_LETTER_ETA
+#undef GREEK_SMALL_LETTER_THETA
+#undef GREEK_SMALL_LETTER_IOTA
+#undef GREEK_SMALL_LETTER_KAPPA
+#undef GREEK_SMALL_LETTER_LAMDA
+#undef GREEK_SMALL_LETTER_MU
+#undef GREEK_SMALL_LETTER_NU
+#undef GREEK_SMALL_LETTER_XI
+#undef GREEK_SMALL_LETTER_OMICRON
+#undef GREEK_SMALL_LETTER_PI
+#undef GREEK_SMALL_LETTER_RHO
+#undef GREEK_SMALL_LETTER_FINAL_SIGMA
+#undef GREEK_SMALL_LETTER_SIGMA
+#undef GREEK_SMALL_LETTER_TAU
+#undef GREEK_SMALL_LETTER_UPSILON
+#undef GREEK_SMALL_LETTER_PHI
+#undef GREEK_SMALL_LETTER_CHI
+#undef GREEK_SMALL_LETTER_PSI
+#undef GREEK_SMALL_LETTER_OMEGA
+#undef GREEK_SMALL_LETTER_IOTA_WITH_DIALYTIKA
+#undef GREEK_SMALL_LETTER_UPSILON_WITH_DIALYTIKA
+#undef GREEK_SMALL_LETTER_OMICRON_WITH_TONOS
+#undef GREEK_SMALL_LETTER_UPSILON_WITH_TONOS
+#undef GREEK_SMALL_LETTER_OMEGA_WITH_TONOS
+
+#if 0
+ISO 8859-7 (Latin/Greek Alphabet)
+Dec Hex ISO/IEC 10646-1:1993(E) Character Name
+ 32 20 SPACE
+ 33 21 EXCLAMATION MARK
+ 34 22 QUOTATION MARK
+ 35 23 NUMBER SIGN
+ 36 24 DOLLAR SIGN
+ 37 25 PERCENT SIGN
+ 38 26 AMPERSAND
+ 39 27 APOSTROPHE
+ 40 28 LEFT PARENTHESIS
+ 41 29 RIGHT PARENTHESIS
+ 42 2A ASTERISK
+ 43 2B PLUS SIGN
+ 44 2C COMMA
+ 45 2D HYPHEN-MINUS
+ 46 2E FULL STOP
+ 47 2F SOLIDUS
+ 48 30 DIGIT ZERO
+ 49 31 DIGIT ONE
+ 50 32 DIGIT TWO
+ 51 33 DIGIT THREE
+ 52 34 DIGIT FOUR
+ 53 35 DIGIT FIVE
+ 54 36 DIGIT SIX
+ 55 37 DIGIT SEVEN
+ 56 38 DIGIT EIGHT
+ 57 39 DIGIT NINE
+ 58 3A COLON
+ 59 3B SEMICOLON
+ 60 3C LESS-THAN SIGN
+ 61 3D EQUALS SIGN
+ 62 3E GREATER-THAN SIGN
+ 63 3F QUESTION MARK
+ 64 40 COMMERCIAL AT
+ 65 41 LATIN CAPITAL LETTER A
+ 66 42 LATIN CAPITAL LETTER B
+ 67 43 LATIN CAPITAL LETTER C
+ 68 44 LATIN CAPITAL LETTER D
+ 69 45 LATIN CAPITAL LETTER E
+ 70 46 LATIN CAPITAL LETTER F
+ 71 47 LATIN CAPITAL LETTER G
+ 72 48 LATIN CAPITAL LETTER H
+ 73 49 LATIN CAPITAL LETTER I
+ 74 4A LATIN CAPITAL LETTER J
+ 75 4B LATIN CAPITAL LETTER K
+ 76 4C LATIN CAPITAL LETTER L
+ 77 4D LATIN CAPITAL LETTER M
+ 78 4E LATIN CAPITAL LETTER N
+ 79 4F LATIN CAPITAL LETTER O
+ 80 50 LATIN CAPITAL LETTER P
+ 81 51 LATIN CAPITAL LETTER Q
+ 82 52 LATIN CAPITAL LETTER R
+ 83 53 LATIN CAPITAL LETTER S
+ 84 54 LATIN CAPITAL LETTER T
+ 85 55 LATIN CAPITAL LETTER U
+ 86 56 LATIN CAPITAL LETTER V
+ 87 57 LATIN CAPITAL LETTER W
+ 88 58 LATIN CAPITAL LETTER X
+ 89 59 LATIN CAPITAL LETTER Y
+ 90 5A LATIN CAPITAL LETTER Z
+ 91 5B LEFT SQUARE BRACKET
+ 92 5C REVERSE SOLIDUS
+ 93 5D RIGHT SQUARE BRACKET
+ 94 5E CIRCUMFLEX ACCENT
+ 95 5F LOW LINE
+ 96 60 GRAVE ACCENT
+ 97 61 LATIN SMALL LETTER A
+ 98 62 LATIN SMALL LETTER B
+ 99 63 LATIN SMALL LETTER C
+100 64 LATIN SMALL LETTER D
+101 65 LATIN SMALL LETTER E
+102 66 LATIN SMALL LETTER F
+103 67 LATIN SMALL LETTER G
+104 68 LATIN SMALL LETTER H
+105 69 LATIN SMALL LETTER I
+106 6A LATIN SMALL LETTER J
+107 6B LATIN SMALL LETTER K
+108 6C LATIN SMALL LETTER L
+109 6D LATIN SMALL LETTER M
+110 6E LATIN SMALL LETTER N
+111 6F LATIN SMALL LETTER O
+112 70 LATIN SMALL LETTER P
+113 71 LATIN SMALL LETTER Q
+114 72 LATIN SMALL LETTER R
+115 73 LATIN SMALL LETTER S
+116 74 LATIN SMALL LETTER T
+117 75 LATIN SMALL LETTER U
+118 76 LATIN SMALL LETTER V
+119 77 LATIN SMALL LETTER W
+120 78 LATIN SMALL LETTER X
+121 79 LATIN SMALL LETTER Y
+122 7A LATIN SMALL LETTER Z
+123 7B LEFT CURLY BRACKET
+124 7C VERTICAL LINE
+125 7D RIGHT CURLY BRACKET
+126 7E TILDE
+160 A0 NO-BREAK SPACE
+161 A1 LEFT SINGLE QUOTATION MARK
+162 A2 RIGHT SINGLE QUOTATION MARK
+163 A3 POUND SIGN
+166 A6 BROKEN BAR
+167 A7 SECTION SIGN
+168 A8 DIAERESIS
+169 A9 COPYRIGHT SIGN
+171 AB LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
+172 AC NOT SIGN
+173 AD SOFT HYPHEN
+175 AF HORIZONTAL BAR
+176 B0 DEGREE SIGN
+177 B1 PLUS-MINUS SIGN
+178 B2 SUPERSCRIPT TWO
+179 B3 SUPERSCRIPT THREE
+180 B4 GREEK TONOS
+181 B5 GREEK DIALYTIKA TONOS
+182 B6 GREEK CAPITAL LETTER ALPHA WITH TONOS
+183 B7 MIDDLE DOT
+184 B8 GREEK CAPITAL LETTER EPSILON WITH TONOS
+185 B9 GREEK CAPITAL LETTER ETA WITH TONOS
+186 BA GREEK CAPITAL LETTER IOTA WITH TONOS
+187 BB RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
+188 BC GREEK CAPITAL LETTER OMICRON WITH TONOS
+189 BD VULGAR FRACTION ONE HALF
+190 BE GREEK CAPITAL LETTER UPSILON WITH TONOS
+191 BF GREEK CAPITAL LETTER OMEGA WITH TONOS
+192 C0 GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS
+193 C1 GREEK CAPITAL LETTER ALPHA
+194 C2 GREEK CAPITAL LETTER BETA
+195 C3 GREEK CAPITAL LETTER GAMMA
+196 C4 GREEK CAPITAL LETTER DELTA
+197 C5 GREEK CAPITAL LETTER EPSILON
+198 C6 GREEK CAPITAL LETTER ZETA
+199 C7 GREEK CAPITAL LETTER ETA
+200 C8 GREEK CAPITAL LETTER THETA
+201 C9 GREEK CAPITAL LETTER IOTA
+202 CA GREEK CAPITAL LETTER KAPPA
+203 CB GREEK CAPITAL LETTER LAMDA
+204 CC GREEK CAPITAL LETTER MU
+205 CD GREEK CAPITAL LETTER NU
+206 CE GREEK CAPITAL LETTER XI
+207 CF GREEK CAPITAL LETTER OMICRON
+208 D0 GREEK CAPITAL LETTER PI
+209 D1 GREEK CAPITAL LETTER RHO
+211 D3 GREEK CAPITAL LETTER SIGMA
+212 D4 GREEK CAPITAL LETTER TAU
+213 D5 GREEK CAPITAL LETTER UPSILON
+214 D6 GREEK CAPITAL LETTER PHI
+215 D7 GREEK CAPITAL LETTER CHI
+216 D8 GREEK CAPITAL LETTER PSI
+217 D9 GREEK CAPITAL LETTER OMEGA
+218 DA GREEK CAPITAL LETTER IOTA WITH DIALYTIKA
+219 DB GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA
+220 DC GREEK SMALL LETTER ALPHA WITH TONOS
+221 DD GREEK SMALL LETTER EPSILON WITH TONOS
+222 DE GREEK SMALL LETTER ETA WITH TONOS
+223 DF GREEK SMALL LETTER IOTA WITH TONOS
+224 E0 GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS
+225 E1 GREEK SMALL LETTER ALPHA
+226 E2 GREEK SMALL LETTER BETA
+227 E3 GREEK SMALL LETTER GAMMA
+228 E4 GREEK SMALL LETTER DELTA
+229 E5 GREEK SMALL LETTER EPSILON
+230 E6 GREEK SMALL LETTER ZETA
+231 E7 GREEK SMALL LETTER ETA
+232 E8 GREEK SMALL LETTER THETA
+233 E9 GREEK SMALL LETTER IOTA
+234 EA GREEK SMALL LETTER KAPPA
+235 EB GREEK SMALL LETTER LAMDA
+236 EC GREEK SMALL LETTER MU
+237 ED GREEK SMALL LETTER NU
+238 EE GREEK SMALL LETTER XI
+239 EF GREEK SMALL LETTER OMICRON
+240 F0 GREEK SMALL LETTER PI
+241 F1 GREEK SMALL LETTER RHO
+242 F2 GREEK SMALL LETTER FINAL SIGMA
+243 F3 GREEK SMALL LETTER SIGMA
+244 F4 GREEK SMALL LETTER TAU
+245 F5 GREEK SMALL LETTER UPSILON
+246 F6 GREEK SMALL LETTER PHI
+247 F7 GREEK SMALL LETTER CHI
+248 F8 GREEK SMALL LETTER PSI
+249 F9 GREEK SMALL LETTER OMEGA
+250 FA GREEK SMALL LETTER IOTA WITH DIALYTIKA
+251 FB GREEK SMALL LETTER UPSILON WITH DIALYTIKA
+252 FC GREEK SMALL LETTER OMICRON WITH TONOS
+253 FD GREEK SMALL LETTER UPSILON WITH TONOS
+254 FE GREEK SMALL LETTER OMEGA WITH TONOS
+#endif
diff --git a/strings/Attic/ctype-hebrew.c b/strings/Attic/ctype-hebrew.c
new file mode 100644
index 00000000000..b1566b2bbe4
--- /dev/null
+++ b/strings/Attic/ctype-hebrew.c
@@ -0,0 +1,135 @@
+/* Copyright Abandoned 1996 TCX DataKonsult AB & Monty Program KB & Detron HB
+ This file is public domain and comes with NO WARRANTY of any kind */
+
+/* This implements the ISO 8859 Latin1 character-set */
+
+#include <global.h>
+#include "m_string.h"
+
+uchar NEAR ctype_hebrew[257] = {
+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,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,
+};
+
+uchar NEAR to_lower_hebrew[]={
+'\000','\001','\002','\003','\004','\005','\006','\007',
+'\010','\011','\012','\013','\014','\015','\016','\017',
+'\020','\021','\022','\023','\024','\025','\026','\027',
+'\030','\031','\032','\033','\034','\035','\036','\037',
+' ', '!', '"', '#', '$', '%', '&', '\'',
+'(', ')', '*', '+', ',', '-', '.', '/',
+'0', '1', '2', '3', '4', '5', '6', '7',
+'8', '9', ':', ';', '<', '=', '>', '?',
+'@', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
+'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
+'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
+'x', 'y', 'z', '[', '\\', ']', '^', '_',
+'`', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
+'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
+'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
+'x', 'y', 'z', '{', '|', '}', '~', '\177',
+
+(uchar) '\200',(uchar) '\201',(uchar) '\202',(uchar) '\203',(uchar) '\204',(uchar) '\205',(uchar) '\206',(uchar) '\207',
+(uchar) '\210',(uchar) '\211',(uchar) '\212',(uchar) '\213',(uchar) '\214',(uchar) '\215',(uchar) '\216',(uchar) '\217',
+(uchar) '\220',(uchar) '\221',(uchar) '\222',(uchar) '\223',(uchar) '\224',(uchar) '\225',(uchar) '\226',(uchar) '\227',
+(uchar) '\230',(uchar) '\231',(uchar) '\232',(uchar) '\233',(uchar) '\234',(uchar) '\235',(uchar) '\236',(uchar) '\237',
+(uchar) '\240',(uchar) '\241',(uchar) '\242',(uchar) '\243',(uchar) '\244',(uchar) '\245',(uchar) '\246',(uchar) '\247',
+(uchar) '\250',(uchar) '\251',(uchar) '\252',(uchar) '\253',(uchar) '\254',(uchar) '\255',(uchar) '\256',(uchar) '\257',
+(uchar) '\260',(uchar) '\261',(uchar) '\262',(uchar) '\263',(uchar) '\264',(uchar) '\265',(uchar) '\266',(uchar) '\267',
+(uchar) '\270',(uchar) '\271',(uchar) '\272',(uchar) '\273',(uchar) '\274',(uchar) '\275',(uchar) '\276',(uchar) '\277',
+(uchar) '\300',(uchar) '\301',(uchar) '\302',(uchar) '\303',(uchar) '\304',(uchar) '\305',(uchar) '\306',(uchar) '\307',
+(uchar) '\310',(uchar) '\311',(uchar) '\312',(uchar) '\313',(uchar) '\314',(uchar) '\315',(uchar) '\316',(uchar) '\317',
+(uchar) '\320',(uchar) '\321',(uchar) '\322',(uchar) '\323',(uchar) '\324',(uchar) '\325',(uchar) '\326',(uchar) '\327',
+(uchar) '\330',(uchar) '\331',(uchar) '\332',(uchar) '\333',(uchar) '\334',(uchar) '\335',(uchar) '\336',(uchar) '\337',
+(uchar) '\340',(uchar) '\341',(uchar) '\342',(uchar) '\343',(uchar) '\344',(uchar) '\345',(uchar) '\346',(uchar) '\347',
+(uchar) '\350',(uchar) '\351',(uchar) '\352',(uchar) '\353',(uchar) '\354',(uchar) '\355',(uchar) '\356',(uchar) '\357',
+(uchar) '\360',(uchar) '\361',(uchar) '\362',(uchar) '\363',(uchar) '\364',(uchar) '\365',(uchar) '\366',(uchar) '\367',
+(uchar) '\370',(uchar) '\371',(uchar) '\372',(uchar) '\373',(uchar) '\374',(uchar) '\375',(uchar) '\376',(uchar) '\377',
+};
+
+uchar NEAR to_upper_hebrew[]={
+'\000','\001','\002','\003','\004','\005','\006','\007',
+'\010','\011','\012','\013','\014','\015','\016','\017',
+'\020','\021','\022','\023','\024','\025','\026','\027',
+'\030','\031','\032','\033','\034','\035','\036','\037',
+' ', '!', '"', '#', '$', '%', '&', '\'',
+'(', ')', '*', '+', ',', '-', '.', '/',
+'0', '1', '2', '3', '4', '5', '6', '7',
+'8', '9', ':', ';', '<', '=', '>', '?',
+'@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+'X', 'Y', 'Z', '[', '\\', ']', '^', '_',
+'`', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+'X', 'Y', 'Z', '{', '|', '}', '~', '\177',
+
+(uchar) '\200',(uchar) '\201',(uchar) '\202',(uchar) '\203',(uchar) '\204',(uchar) '\205',(uchar) '\206',(uchar) '\207',
+(uchar) '\210',(uchar) '\211',(uchar) '\212',(uchar) '\213',(uchar) '\214',(uchar) '\215',(uchar) '\216',(uchar) '\217',
+(uchar) '\220',(uchar) '\221',(uchar) '\222',(uchar) '\223',(uchar) '\224',(uchar) '\225',(uchar) '\226',(uchar) '\227',
+(uchar) '\230',(uchar) '\231',(uchar) '\232',(uchar) '\233',(uchar) '\234',(uchar) '\235',(uchar) '\236',(uchar) '\237',
+(uchar) '\240',(uchar) '\241',(uchar) '\242',(uchar) '\243',(uchar) '\244',(uchar) '\245',(uchar) '\246',(uchar) '\247',
+(uchar) '\250',(uchar) '\251',(uchar) '\252',(uchar) '\253',(uchar) '\254',(uchar) '\255',(uchar) '\256',(uchar) '\257',
+(uchar) '\260',(uchar) '\261',(uchar) '\262',(uchar) '\263',(uchar) '\264',(uchar) '\265',(uchar) '\266',(uchar) '\267',
+(uchar) '\270',(uchar) '\271',(uchar) '\272',(uchar) '\273',(uchar) '\274',(uchar) '\275',(uchar) '\276',(uchar) '\277',
+(uchar) '\300',(uchar) '\301',(uchar) '\302',(uchar) '\303',(uchar) '\304',(uchar) '\305',(uchar) '\306',(uchar) '\307',
+(uchar) '\310',(uchar) '\311',(uchar) '\312',(uchar) '\313',(uchar) '\314',(uchar) '\315',(uchar) '\316',(uchar) '\317',
+(uchar) '\320',(uchar) '\321',(uchar) '\322',(uchar) '\323',(uchar) '\324',(uchar) '\325',(uchar) '\326',(uchar) '\327',
+(uchar) '\330',(uchar) '\331',(uchar) '\332',(uchar) '\333',(uchar) '\334',(uchar) '\335',(uchar) '\336',(uchar) '\337',
+(uchar) '\340',(uchar) '\341',(uchar) '\342',(uchar) '\343',(uchar) '\344',(uchar) '\345',(uchar) '\346',(uchar) '\347',
+(uchar) '\350',(uchar) '\351',(uchar) '\352',(uchar) '\353',(uchar) '\354',(uchar) '\355',(uchar) '\356',(uchar) '\357',
+(uchar) '\360',(uchar) '\361',(uchar) '\362',(uchar) '\363',(uchar) '\364',(uchar) '\365',(uchar) '\366',(uchar) '\367',
+(uchar) '\370',(uchar) '\371',(uchar) '\372',(uchar) '\373',(uchar) '\374',(uchar) '\375',(uchar) '\376',(uchar) '\377',
+};
+
+uchar NEAR sort_order_hebrew[]={
+'\000','\001','\002','\003','\004','\005','\006','\007',
+'\010','\011','\012','\013','\014','\015','\016','\017',
+'\020','\021','\022','\023','\024','\025','\026','\027',
+'\030','\031','\032','\033','\034','\035','\036','\037',
+' ', '!', '"', '#', '$', '%', '&', '\'',
+'(', ')', '*', '+', ',', '-', '.', '/',
+'0', '1', '2', '3', '4', '5', '6', '7',
+'8', '9', ':', ';', '<', '=', '>', '?',
+'@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+'X', 'Y', 'Z', '[', '\\', ']', '^', '_',
+'`', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+'X', 'Y', 'Z', '{', '|', '}', '~', '\177',
+
+(uchar) '\200',(uchar) '\201',(uchar) '\202',(uchar) '\203',(uchar) '\204',(uchar) '\205',(uchar) '\206',(uchar) '\207',
+(uchar) '\210',(uchar) '\211',(uchar) '\212',(uchar) '\213',(uchar) '\214',(uchar) '\215',(uchar) '\216',(uchar) '\217',
+(uchar) '\220',(uchar) '\221',(uchar) '\222',(uchar) '\223',(uchar) '\224',(uchar) '\225',(uchar) '\226',(uchar) '\227',
+(uchar) '\230',(uchar) '\231',(uchar) '\232',(uchar) '\233',(uchar) '\234',(uchar) '\235',(uchar) '\236',(uchar) '\237',
+(uchar) '\240',(uchar) '\241',(uchar) '\242',(uchar) '\243',(uchar) '\244',(uchar) '\245',(uchar) '\246',(uchar) '\247',
+(uchar) '\250',(uchar) '\251',(uchar) '\252',(uchar) '\253',(uchar) '\254',(uchar) '\255',(uchar) '\256',(uchar) '\257',
+(uchar) '\260',(uchar) '\261',(uchar) '\262',(uchar) '\263',(uchar) '\264',(uchar) '\265',(uchar) '\266',(uchar) '\267',
+(uchar) '\270',(uchar) '\271',(uchar) '\272',(uchar) '\273',(uchar) '\274',(uchar) '\275',(uchar) '\276',(uchar) '\277',
+(uchar) '\300',(uchar) '\301',(uchar) '\302',(uchar) '\303',(uchar) '\304',(uchar) '\305',(uchar) '\306',(uchar) '\307',
+(uchar) '\310',(uchar) '\311',(uchar) '\312',(uchar) '\313',(uchar) '\314',(uchar) '\315',(uchar) '\316',(uchar) '\317',
+(uchar) '\320',(uchar) '\321',(uchar) '\322',(uchar) '\323',(uchar) '\324',(uchar) '\325',(uchar) '\326',(uchar) '\367',
+(uchar) '\330',(uchar) '\331',(uchar) '\332',(uchar) '\333',(uchar) '\334',(uchar) '\335',(uchar) '\336',(uchar) '\377',
+(uchar) '\340',(uchar) '\341',(uchar) '\342',(uchar) '\343',(uchar) '\344',(uchar) '\345',(uchar) '\346',(uchar) '\347',
+(uchar) '\350',(uchar) '\351',(uchar) '\352',(uchar) '\353',(uchar) '\354',(uchar) '\355',(uchar) '\356',(uchar) '\357',
+(uchar) '\360',(uchar) '\361',(uchar) '\362',(uchar) '\363',(uchar) '\364',(uchar) '\365',(uchar) '\366',(uchar) '\367',
+(uchar) '\370',(uchar) '\371',(uchar) '\372',(uchar) '\373',(uchar) '\374',(uchar) '\375',(uchar) '\376',(uchar) '\377',
+};
diff --git a/strings/Attic/ctype-hp8.c b/strings/Attic/ctype-hp8.c
new file mode 100644
index 00000000000..6397c3cb974
--- /dev/null
+++ b/strings/Attic/ctype-hp8.c
@@ -0,0 +1,133 @@
+/* Copyright Abandoned 1996 TCX DataKonsult AB & Monty Program KB & Detron HB
+ This file is public domain and comes with NO WARRANTY of any kind */
+
+#include <global.h>
+#include "m_string.h"
+
+uchar NEAR ctype_hp8[257] = {
+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,
+
+32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,
+32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,
+32,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,
+16,32,32,16,16,16,16,16,16,16,16,16,16,16,16,16,
+16,16,16,16,16,2,16,16,16,16,16,16,2,16,2,2,
+1,16,16,1,2,16,16,2,1,16,1,1,1,16,16,16,
+16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,
+16,16,32,32,32,32,16,16,16,16,16,16,16,16,16,32,
+};
+
+uchar NEAR to_lower_hp8[]={
+'\000','\001','\002','\003','\004','\005','\006','\007',
+'\010','\011','\012','\013','\014','\015','\016','\017',
+'\020','\021','\022','\023','\024','\025','\026','\027',
+'\030','\031','\032','\033','\034','\035','\036','\037',
+' ', '!', '"', '#', '$', '%', '&', '\'',
+'(', ')', '*', '+', ',', '-', '.', '/',
+'0', '1', '2', '3', '4', '5', '6', '7',
+'8', '9', ':', ';', '<', '=', '>', '?',
+'@', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
+'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
+'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
+'x', 'y', 'z', '[', '\\', ']', '^', '_',
+'`', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
+'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
+'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
+'x', 'y', 'z', '{', '|', '}', '~', '\177',
+
+(uchar) '\200',(uchar) '\201',(uchar) '\202',(uchar) '\203',(uchar) '\204',(uchar) '\205',(uchar) '\206',(uchar) '\207',
+(uchar) '\210',(uchar) '\211',(uchar) '\212',(uchar) '\213',(uchar) '\214',(uchar) '\215',(uchar) '\216',(uchar) '\217',
+(uchar) '\220',(uchar) '\221',(uchar) '\222',(uchar) '\223',(uchar) '\224',(uchar) '\225',(uchar) '\226',(uchar) '\227',
+(uchar) '\230',(uchar) '\231',(uchar) '\232',(uchar) '\233',(uchar) '\234',(uchar) '\235',(uchar) '\236',(uchar) '\237',
+(uchar) '\240',(uchar) '\310',(uchar) '\300',(uchar) '\311',(uchar) '\301',(uchar) '\315',(uchar) '\321',(uchar) '\335',
+(uchar) '\250',(uchar) '\251',(uchar) '\252',(uchar) '\253',(uchar) '\254',(uchar) '\313',(uchar) '\303',(uchar) '\257',
+(uchar) '\260',(uchar) '\262',(uchar) '\262',(uchar) '\263',(uchar) '\265',(uchar) '\265',(uchar) '\267',(uchar) '\267',
+(uchar) '\270',(uchar) '\271',(uchar) '\272',(uchar) '\273',(uchar) '\274',(uchar) '\275',(uchar) '\276',(uchar) '\277',
+(uchar) '\300',(uchar) '\301',(uchar) '\302',(uchar) '\303',(uchar) '\304',(uchar) '\305',(uchar) '\306',(uchar) '\307',
+(uchar) '\310',(uchar) '\311',(uchar) '\312',(uchar) '\313',(uchar) '\314',(uchar) '\315',(uchar) '\316',(uchar) '\317',
+(uchar) '\324',(uchar) '\321',(uchar) '\326',(uchar) '\327',(uchar) '\324',(uchar) '\325',(uchar) '\326',(uchar) '\327',
+(uchar) '\314',(uchar) '\331',(uchar) '\316',(uchar) '\317',(uchar) '\305',(uchar) '\335',(uchar) '\336',(uchar) '\302',
+(uchar) '\304',(uchar) '\342',(uchar) '\342',(uchar) '\344',(uchar) '\344',(uchar) '\325',(uchar) '\331',(uchar) '\306',
+(uchar) '\312',(uchar) '\352',(uchar) '\352',(uchar) '\354',(uchar) '\354',(uchar) '\307',(uchar) '\357',(uchar) '\357',
+(uchar) '\361',(uchar) '\361',(uchar) '\362',(uchar) '\363',(uchar) '\364',(uchar) '\365',(uchar) '\366',(uchar) '\367',
+(uchar) '\370',(uchar) '\371',(uchar) '\372',(uchar) '\373',(uchar) '\374',(uchar) '\375',(uchar) '\376',(uchar) '\377',
+};
+
+uchar NEAR to_upper_hp8[]={
+'\000','\001','\002','\003','\004','\005','\006','\007',
+'\010','\011','\012','\013','\014','\015','\016','\017',
+'\020','\021','\022','\023','\024','\025','\026','\027',
+'\030','\031','\032','\033','\034','\035','\036','\037',
+' ', '!', '"', '#', '$', '%', '&', '\'',
+'(', ')', '*', '+', ',', '-', '.', '/',
+'0', '1', '2', '3', '4', '5', '6', '7',
+'8', '9', ':', ';', '<', '=', '>', '?',
+'@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+'X', 'Y', 'Z', '[', '\\', ']', '^', '_',
+'`', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+'X', 'Y', 'Z', '{', '|', '}', '~', '\177',
+(uchar) '\200',(uchar) '\201',(uchar) '\202',(uchar) '\203',(uchar) '\204',(uchar) '\205',(uchar) '\206',(uchar) '\207',
+(uchar) '\210',(uchar) '\211',(uchar) '\212',(uchar) '\213',(uchar) '\214',(uchar) '\215',(uchar) '\216',(uchar) '\217',
+(uchar) '\220',(uchar) '\221',(uchar) '\222',(uchar) '\223',(uchar) '\224',(uchar) '\225',(uchar) '\226',(uchar) '\227',
+(uchar) '\230',(uchar) '\231',(uchar) '\232',(uchar) '\233',(uchar) '\234',(uchar) '\235',(uchar) '\236',(uchar) '\237',
+(uchar) '\240',(uchar) '\241',(uchar) '\242',(uchar) '\243',(uchar) '\244',(uchar) '\245',(uchar) '\246',(uchar) '\247',
+(uchar) '\250',(uchar) '\251',(uchar) '\252',(uchar) '\253',(uchar) '\254',(uchar) '\255',(uchar) '\256',(uchar) '\257',
+(uchar) '\260',(uchar) '\261',(uchar) '\261',(uchar) '\263',(uchar) '\264',(uchar) '\264',(uchar) '\266',(uchar) '\266',
+(uchar) '\270',(uchar) '\271',(uchar) '\272',(uchar) '\273',(uchar) '\274',(uchar) '\275',(uchar) '\276',(uchar) '\277',
+(uchar) '\242',(uchar) '\244',(uchar) '\337',(uchar) '\256',(uchar) '\340',(uchar) '\334',(uchar) '\347',(uchar) '\355',
+(uchar) '\241',(uchar) '\243',(uchar) '\350',(uchar) '\255',(uchar) '\330',(uchar) '\245',(uchar) '\332',(uchar) '\333',
+(uchar) '\320',(uchar) '\246',(uchar) '\322',(uchar) '\323',(uchar) '\320',(uchar) '\345',(uchar) '\322',(uchar) '\323',
+(uchar) '\330',(uchar) '\346',(uchar) '\332',(uchar) '\333',(uchar) '\334',(uchar) '\247',(uchar) '\336',(uchar) '\337',
+(uchar) '\340',(uchar) '\341',(uchar) '\341',(uchar) '\343',(uchar) '\343',(uchar) '\345',(uchar) '\346',(uchar) '\347',
+(uchar) '\350',(uchar) '\351',(uchar) '\351',(uchar) '\353',(uchar) '\353',(uchar) '\355',(uchar) '\356',(uchar) '\356',
+(uchar) '\360',(uchar) '\360',(uchar) '\362',(uchar) '\363',(uchar) '\364',(uchar) '\365',(uchar) '\366',(uchar) '\367',
+(uchar) '\370',(uchar) '\371',(uchar) '\372',(uchar) '\373',(uchar) '\374',(uchar) '\375',(uchar) '\376',(uchar) '\377',
+};
+
+uchar NEAR sort_order_hp8[]={
+'\000','\001','\002','\003','\004','\005','\006','\007',
+'\010','\011','\012','\013','\014','\015','\016','\017',
+'\020','\021','\022','\023','\024','\025','\026','\027',
+'\030','\031','\032','\033','\034','\035','\036','\037',
+' ', '!', '"', '#', '$', '%', '&', '\'',
+'(', ')', '*', '+', ',', '-', '.', '/',
+'0', '1', '2', '3', '4', '5', '6', '7',
+'8', '9', ':', ';', '<', '=', '>', '?',
+'@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+'X', 'Y', 'Z', '\\', ']', '[', '^', '_',
+'`', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+'X', 'Y', 'Z', '{', '|', '}', '~', '\177',
+
+(uchar) '\200',(uchar) '\201',(uchar) '\202',(uchar) '\203',(uchar) '\204',(uchar) '\205',(uchar) '\206',(uchar) '\207',
+(uchar) '\210',(uchar) '\211',(uchar) '\212',(uchar) '\213',(uchar) '\214',(uchar) '\215',(uchar) '\216',(uchar) '\217',
+(uchar) '\220',(uchar) '\221',(uchar) '\222',(uchar) '\223',(uchar) '\224',(uchar) '\225',(uchar) '\226',(uchar) '\227',
+(uchar) '\230',(uchar) '\231',(uchar) '\232',(uchar) '\233',(uchar) '\234',(uchar) '\235',(uchar) '\236',(uchar) '\237',
+(uchar) '\240',(uchar) '\241',(uchar) '\242',(uchar) '\243',(uchar) '\244',(uchar) '\245',(uchar) '\246',(uchar) '\247',
+(uchar) '\250',(uchar) '\251',(uchar) '\252',(uchar) '\253',(uchar) '\254',(uchar) '\255',(uchar) '\256',(uchar) '\257',
+(uchar) '\260',(uchar) '\261',(uchar) '\262',(uchar) '\263',(uchar) '\264',(uchar) '\265',(uchar) '\266',(uchar) '\267',
+(uchar) '\270',(uchar) '\271',(uchar) '\272',(uchar) '\273',(uchar) '\274',(uchar) '\275',(uchar) '\276',(uchar) '\277',
+(uchar) '\300',(uchar) '\301',(uchar) '\302',(uchar) '\303',(uchar) '\304',(uchar) '\305',(uchar) '\306',(uchar) '\307',
+(uchar) '\310',(uchar) '\311',(uchar) '\312',(uchar) '\313',(uchar) '\314',(uchar) '\315',(uchar) '\316',(uchar) '\317',
+(uchar) '\320',(uchar) '\321',(uchar) '\322',(uchar) '\323',(uchar) '\324',(uchar) '\325',(uchar) '\326',(uchar) '\327',
+(uchar) '\330',(uchar) '\331',(uchar) '\332',(uchar) '\333',(uchar) '\334',(uchar) '\335',(uchar) '\336',(uchar) '\337',
+(uchar) '\340',(uchar) '\341',(uchar) '\342',(uchar) '\343',(uchar) '\344',(uchar) '\345',(uchar) '\346',(uchar) '\347',
+(uchar) '\350',(uchar) '\351',(uchar) '\352',(uchar) '\353',(uchar) '\354',(uchar) '\355',(uchar) '\356',(uchar) '\357',
+(uchar) '\360',(uchar) '\361',(uchar) '\362',(uchar) '\363',(uchar) '\364',(uchar) '\365',(uchar) '\366',(uchar) '\367',
+(uchar) '\370',(uchar) '\371',(uchar) '\372',(uchar) '\373',(uchar) '\374',(uchar) '\375',(uchar) '\376',(uchar) '\377',
+};
diff --git a/strings/Attic/ctype-hungarian.c b/strings/Attic/ctype-hungarian.c
new file mode 100644
index 00000000000..548c87f0d49
--- /dev/null
+++ b/strings/Attic/ctype-hungarian.c
@@ -0,0 +1,113 @@
+/*
+ * File generated by cset
+ * (C) Abandoned 1998 Zoltan Klar <klarz@svr-sun.ktg.gau.hu>
+ * (C) 1999 é,ö sort order corrected by Huba Gaspar <huba@unixoft.hu>
+ * This file is based on ctype-latin2.c
+ *
+ * n a g y k i c s i sort
+ * kod
+ * A' 143 181 193 160 225 67 ==a, ha == 65
+ * E' 144 201 130 233 79 ==e, ha == 78
+ * I' 141 140 205 161 237 86 ==i
+ * O" 167 138 213 147 139 245 103
+ * O' 149 224 211 162 243 100 ==o
+ * O: 153 214 148 246 103
+ * U" 152 235 219 150 251 120
+ * U' 151 218 163 250 117 ==u
+ * U: 154 220 129 252 120
+ */
+#define hungarian_AA_EE
+/* megadása esetén az A és Á, valamint az E és az É nincs megkülönböztetve
+ * a rendezés szempomtjából
+ */
+
+#include <global.h>
+#include "m_string.h"
+
+uchar NEAR ctype_hungarian[257] = {
+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,
+ 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,
+ 1, 16, 1, 16, 1, 1, 16, 0, 0, 1, 1, 1, 1, 16, 1, 1,
+ 16, 2, 16, 2, 16, 2, 2, 16, 16, 2, 2, 2, 2, 16, 2, 2,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 16, 1, 1, 1, 1, 1, 1, 16, 1, 1, 1, 1, 1, 1, 1, 16,
+ 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, 16
+};
+
+uchar NEAR to_lower_hungarian[] = {
+ 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,139,139,161,161,142,160,
+130,145,146,147,148,162,150,163,150,148,129,155,156,157,158,159,
+160,161,162,163,181,182,166,147,168,185,186,187,188,173,190,191,
+176,177,178,179,180,225,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,
+208,241,242,243,244,245,246,215,248,249,250,251,252,253,254,223,
+162,225,226,227,228,229,230,231,232,233,234,150,236,237,238,239,
+240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255
+};
+
+uchar NEAR to_upper_hungarian[] = {
+ 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,154,144,131,132,133,134,135,136,137,138,138,140,141,142,143,
+144,145,146,167,153,149,152,151,152,153,154,155,156,157,158,159,
+143,141,149,151,164,165,166,167,168,169,170,171,172,173,174,175,
+176,160,178,162,180,181,165,183,184,169,170,171,172,189,174,175,
+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,
+224,193,194,195,196,197,198,199,200,201,202,235,204,205,206,207,
+240,209,210,211,212,213,214,247,216,217,218,219,220,221,222,255
+};
+
+uchar NEAR sort_order_hungarian[] = {
+ 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, 71, 72, 76, 78, 83, 84, 85, 86, 90, 91, 92, 96, 97,100,
+105,106,107,110,114,117,122,123,124,125,127,131,132,133,134,135,
+136, 65, 71, 72, 76, 78, 83, 84, 85, 86, 90, 91, 92, 96, 97,100,
+105,106,107,110,114,117,122,123,124,125,127,137,138,139,140, 0,
+#ifdef hungarian_AA_EE
+ 1,120, 78, 4, 5, 6, 7, 8, 9, 10,103,103, 86, 86, 15, 65,
+ 78, 18, 19,103,103,100,120,117,120,103,120, 28, 29, 30, 31,255,
+ 65, 86,100,117, 94,111,255,103,255,112,113,115,128,255,129,130,
+255, 66,255, 93,255, 65,111,255,255,112,113,115,128,255,129,130,
+108, 65, 68, 69, 70, 95, 73, 75, 74, 78, 81, 82, 80, 86, 87, 77,
+255, 98, 99,100,102,103,103,255,109,119,117,120,120,126,116,255,
+100, 65, 68, 69, 70, 95, 73, 75, 74, 78, 81,120, 80, 86, 88, 77,
+255, 98, 99,100,102,103,103,255,109,119,117,120,120,126,116,255
+#else
+ 1,120, 79, 4, 5, 6, 7, 8, 9, 10,103,103, 86, 86, 15, 67,
+ 79, 18, 19,103,103,100,120,117,120,103,120, 28, 29, 30, 31,255,
+ 67, 86,100,117, 94,111,255,103,255,112,113,115,128,255,129,130,
+255, 66,255, 93,255, 67,111,255,255,112,113,115,128,255,129,130,
+108, 67, 68, 69, 70, 95, 73, 75, 74, 79, 81, 82, 80, 86, 87, 77,
+255, 98, 99,100,102,103,103,255,109,119,117,120,120,126,116,255,
+100, 67, 68, 69, 70, 95, 73, 75, 74, 79, 81,120, 80, 86, 88, 77,
+255, 98, 99,100,102,103,103,255,109,119,117,120,120,126,116,255
+#endif
+};
diff --git a/strings/Attic/ctype-koi8_ru.c b/strings/Attic/ctype-koi8_ru.c
new file mode 100644
index 00000000000..6619e5322e6
--- /dev/null
+++ b/strings/Attic/ctype-koi8_ru.c
@@ -0,0 +1,133 @@
+/* Copyright Abandoned 1996 TCX DataKonsult AB & Monty Program KB & Detron HB
+ This file is public domain and comes with NO WARRANTY of any kind */
+
+#include <global.h>
+#include "m_string.h"
+
+uchar NEAR ctype_koi8_ru[257] = {
+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,
+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,16,
+16,16,16,2,16,16,16,16,16,16,16,16,16,16,16,16,
+16,16,16,1,16,16,16,16,16,16,16,16,16,16,16,16,
+2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+};
+
+uchar NEAR to_lower_koi8_ru[]={
+'\000','\001','\002','\003','\004','\005','\006','\007',
+'\010','\011','\012','\013','\014','\015','\016','\017',
+'\020','\021','\022','\023','\024','\025','\026','\027',
+'\030','\031','\032','\033','\034','\035','\036','\037',
+' ', '!', '"', '#', '$', '%', '&', '\'',
+'(', ')', '*', '+', ',', '-', '.', '/',
+'0', '1', '2', '3', '4', '5', '6', '7',
+'8', '9', ':', ';', '<', '=', '>', '?',
+'@', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
+'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
+'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
+'x', 'y', 'z', '[', '\\', ']', '^', '_',
+'`', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
+'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
+'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
+'x', 'y', 'z', '{', '|', '}', '~', '\177',
+
+(uchar) '\200',(uchar) '\201',(uchar) '\202',(uchar) '\203',(uchar) '\204',(uchar) '\205',(uchar) '\206',(uchar) '\207',
+(uchar) '\210',(uchar) '\211',(uchar) '\212',(uchar) '\213',(uchar) '\214',(uchar) '\215',(uchar) '\216',(uchar) '\217',
+(uchar) '\220',(uchar) '\221',(uchar) '\222',(uchar) '\223',(uchar) '\224',(uchar) '\225',(uchar) '\226',(uchar) '\227',
+(uchar) '\230',(uchar) '\231',(uchar) '\232',(uchar) '\233',(uchar) '\234',(uchar) '\235',(uchar) '\236',(uchar) '\237',
+(uchar) '\240',(uchar) '\241',(uchar) '\242',(uchar) '\243',(uchar) '\244',(uchar) '\245',(uchar) '\246',(uchar) '\247',
+(uchar) '\250',(uchar) '\251',(uchar) '\252',(uchar) '\253',(uchar) '\254',(uchar) '\255',(uchar) '\256',(uchar) '\257',
+(uchar) '\260',(uchar) '\261',(uchar) '\262',(uchar) '\243',(uchar) '\264',(uchar) '\265',(uchar) '\266',(uchar) '\267',
+(uchar) '\270',(uchar) '\271',(uchar) '\272',(uchar) '\273',(uchar) '\274',(uchar) '\275',(uchar) '\276',(uchar) '\277',
+(uchar) '\300',(uchar) '\301',(uchar) '\302',(uchar) '\303',(uchar) '\304',(uchar) '\305',(uchar) '\306',(uchar) '\307',
+(uchar) '\310',(uchar) '\311',(uchar) '\312',(uchar) '\313',(uchar) '\314',(uchar) '\315',(uchar) '\316',(uchar) '\317',
+(uchar) '\320',(uchar) '\321',(uchar) '\322',(uchar) '\323',(uchar) '\324',(uchar) '\325',(uchar) '\326',(uchar) '\327',
+(uchar) '\330',(uchar) '\331',(uchar) '\332',(uchar) '\333',(uchar) '\334',(uchar) '\335',(uchar) '\336',(uchar) '\337',
+(uchar) '\300',(uchar) '\301',(uchar) '\302',(uchar) '\303',(uchar) '\304',(uchar) '\305',(uchar) '\306',(uchar) '\307',
+(uchar) '\310',(uchar) '\311',(uchar) '\312',(uchar) '\313',(uchar) '\314',(uchar) '\315',(uchar) '\316',(uchar) '\317',
+(uchar) '\320',(uchar) '\321',(uchar) '\322',(uchar) '\323',(uchar) '\324',(uchar) '\325',(uchar) '\326',(uchar) '\327',
+(uchar) '\330',(uchar) '\331',(uchar) '\332',(uchar) '\333',(uchar) '\334',(uchar) '\335',(uchar) '\336',(uchar) '\337',
+};
+
+uchar NEAR to_upper_koi8_ru[]={
+'\000','\001','\002','\003','\004','\005','\006','\007',
+'\010','\011','\012','\013','\014','\015','\016','\017',
+'\020','\021','\022','\023','\024','\025','\026','\027',
+'\030','\031','\032','\033','\034','\035','\036','\037',
+' ', '!', '"', '#', '$', '%', '&', '\'',
+'(', ')', '*', '+', ',', '-', '.', '/',
+'0', '1', '2', '3', '4', '5', '6', '7',
+'8', '9', ':', ';', '<', '=', '>', '?',
+'@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+'X', 'Y', 'Z', '[', '\\', ']', '^', '_',
+'`', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+'X', 'Y', 'Z', '{', '|', '}', '~', '\177',
+
+(uchar) '\200',(uchar) '\201',(uchar) '\202',(uchar) '\203',(uchar) '\204',(uchar) '\205',(uchar) '\206',(uchar) '\207',
+(uchar) '\210',(uchar) '\211',(uchar) '\212',(uchar) '\213',(uchar) '\214',(uchar) '\215',(uchar) '\216',(uchar) '\217',
+(uchar) '\220',(uchar) '\221',(uchar) '\222',(uchar) '\223',(uchar) '\224',(uchar) '\225',(uchar) '\226',(uchar) '\227',
+(uchar) '\230',(uchar) '\231',(uchar) '\232',(uchar) '\233',(uchar) '\234',(uchar) '\235',(uchar) '\236',(uchar) '\237',
+(uchar) '\240',(uchar) '\241',(uchar) '\242',(uchar) '\263',(uchar) '\244',(uchar) '\245',(uchar) '\246',(uchar) '\247',
+(uchar) '\250',(uchar) '\251',(uchar) '\252',(uchar) '\253',(uchar) '\254',(uchar) '\255',(uchar) '\256',(uchar) '\257',
+(uchar) '\260',(uchar) '\261',(uchar) '\262',(uchar) '\263',(uchar) '\264',(uchar) '\265',(uchar) '\266',(uchar) '\267',
+(uchar) '\270',(uchar) '\271',(uchar) '\272',(uchar) '\273',(uchar) '\274',(uchar) '\275',(uchar) '\276',(uchar) '\277',
+(uchar) '\340',(uchar) '\341',(uchar) '\342',(uchar) '\343',(uchar) '\344',(uchar) '\345',(uchar) '\346',(uchar) '\347',
+(uchar) '\350',(uchar) '\351',(uchar) '\352',(uchar) '\353',(uchar) '\354',(uchar) '\355',(uchar) '\356',(uchar) '\357',
+(uchar) '\360',(uchar) '\361',(uchar) '\362',(uchar) '\363',(uchar) '\364',(uchar) '\365',(uchar) '\366',(uchar) '\367',
+(uchar) '\370',(uchar) '\371',(uchar) '\372',(uchar) '\373',(uchar) '\374',(uchar) '\375',(uchar) '\376',(uchar) '\377',
+(uchar) '\340',(uchar) '\341',(uchar) '\342',(uchar) '\343',(uchar) '\344',(uchar) '\345',(uchar) '\346',(uchar) '\347',
+(uchar) '\350',(uchar) '\351',(uchar) '\352',(uchar) '\353',(uchar) '\354',(uchar) '\355',(uchar) '\356',(uchar) '\357',
+(uchar) '\360',(uchar) '\361',(uchar) '\362',(uchar) '\363',(uchar) '\364',(uchar) '\365',(uchar) '\366',(uchar) '\367',
+(uchar) '\370',(uchar) '\371',(uchar) '\372',(uchar) '\373',(uchar) '\374',(uchar) '\375',(uchar) '\376',(uchar) '\377',
+};
+
+uchar NEAR sort_order_koi8_ru[]={
+'\000','\001','\002','\003','\004','\005','\006','\007',
+'\010','\011','\012','\013','\014','\015','\016','\017',
+'\020','\021','\022','\023','\024','\025','\026','\027',
+'\030','\031','\032','\033','\034','\035','\036','\037',
+' ', '!', '"', '#', '$', '%', '&', '\'',
+'(', ')', '*', '+', ',', '-', '.', '/',
+'0', '1', '2', '3', '4', '5', '6', '7',
+'8', '9', ':', ';', '<', '=', '>', '?',
+'@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+'X', 'Y', 'Z', '[', '\\', ']', '^', '_',
+'`', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+'X', 'Y', 'Z', '{', '|', '}', '~', '\177',
+
+(uchar) '\200',(uchar) '\201',(uchar) '\202',(uchar) '\203',(uchar) '\204',(uchar) '\205',(uchar) '\206',(uchar) '\207',
+(uchar) '\210',(uchar) '\211',(uchar) '\212',(uchar) '\213',(uchar) '\214',(uchar) '\215',(uchar) '\216',(uchar) '\217',
+(uchar) '\220',(uchar) '\221',(uchar) '\222',(uchar) '\223',(uchar) '\224',(uchar) '\225',(uchar) '\226',(uchar) '\227',
+(uchar) '\230',(uchar) '\231',(uchar) '\232',(uchar) '\233',(uchar) '\234',(uchar) '\235',(uchar) '\236',(uchar) '\237',
+(uchar) '\240',(uchar) '\241',(uchar) '\242',(uchar) '\345',(uchar) '\243',(uchar) '\244',(uchar) '\245',(uchar) '\246',
+(uchar) '\247',(uchar) '\250',(uchar) '\251',(uchar) '\252',(uchar) '\253',(uchar) '\254',(uchar) '\255',(uchar) '\256',
+(uchar) '\257',(uchar) '\260',(uchar) '\261',(uchar) '\345',(uchar) '\262',(uchar) '\263',(uchar) '\264',(uchar) '\265',
+(uchar) '\266',(uchar) '\267',(uchar) '\270',(uchar) '\271',(uchar) '\272',(uchar) '\273',(uchar) '\274',(uchar) '\275',
+(uchar) '\376',(uchar) '\337',(uchar) '\340',(uchar) '\366',(uchar) '\343',(uchar) '\344',(uchar) '\364',(uchar) '\342',
+(uchar) '\365',(uchar) '\350',(uchar) '\351',(uchar) '\352',(uchar) '\353',(uchar) '\354',(uchar) '\355',(uchar) '\356',
+(uchar) '\357',(uchar) '\377',(uchar) '\360',(uchar) '\361',(uchar) '\362',(uchar) '\363',(uchar) '\346',(uchar) '\341',
+(uchar) '\374',(uchar) '\373',(uchar) '\347',(uchar) '\370',(uchar) '\375',(uchar) '\371',(uchar) '\367',(uchar) '\372',
+(uchar) '\376',(uchar) '\337',(uchar) '\340',(uchar) '\366',(uchar) '\343',(uchar) '\344',(uchar) '\364',(uchar) '\342',
+(uchar) '\365',(uchar) '\350',(uchar) '\351',(uchar) '\352',(uchar) '\353',(uchar) '\354',(uchar) '\355',(uchar) '\356',
+(uchar) '\357',(uchar) '\377',(uchar) '\360',(uchar) '\361',(uchar) '\362',(uchar) '\363',(uchar) '\346',(uchar) '\341',
+(uchar) '\374',(uchar) '\373',(uchar) '\347',(uchar) '\370',(uchar) '\375',(uchar) '\371',(uchar) '\367',(uchar) '\372',
+};
diff --git a/strings/Attic/ctype-koi8_ukr.c b/strings/Attic/ctype-koi8_ukr.c
new file mode 100644
index 00000000000..d318e026f3a
--- /dev/null
+++ b/strings/Attic/ctype-koi8_ukr.c
@@ -0,0 +1,141 @@
+//Created by Max Veremayenko (verem@tg.kiev.ua)
+//As standart for ukranian font i use ukrainian koi8 for KSI linux
+
+#include <global.h>
+#include "m_string.h"
+
+uchar NEAR ctype_koi8_ukr[257] = {
+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,
+(uchar)'\20',(uchar)'\20',(uchar)'\20',(uchar)'\20',(uchar)'\20',(uchar)'\20',(uchar)'\20',(uchar)'\20',
+(uchar)'\20',(uchar)'\20',(uchar)'\20',(uchar)'\20',(uchar)'\20',(uchar)'\20',(uchar)'\20',(uchar)'\20',
+(uchar)'\20',(uchar)'\20',(uchar)'\20',(uchar)'\20',(uchar)'\20',(uchar)'\20',(uchar)'\20',(uchar)'\20',
+(uchar)'\20',(uchar)'\20',(uchar)'\20',(uchar)'\20',(uchar)'\20',(uchar)'\20',(uchar)'\20',(uchar)'\20',
+(uchar)'\20',(uchar)'\20',(uchar)'\20',(uchar)'\2',(uchar)'\2',(uchar)'\20',(uchar)'\2',(uchar)'\2',
+(uchar)'\20',(uchar)'\20',(uchar)'\20',(uchar)'\20',(uchar)'\20',(uchar)'\2',(uchar)'\20',(uchar)'\20',
+(uchar)'\20',(uchar)'\20',(uchar)'\20',(uchar)'\1',(uchar)'\1',(uchar)'\20',(uchar)'\1',(uchar)'\1',
+(uchar)'\20',(uchar)'\20',(uchar)'\20',(uchar)'\20',(uchar)'\20',(uchar)'\1',(uchar)'\20',(uchar)'\20',
+(uchar)'\2',(uchar)'\2',(uchar)'\2',(uchar)'\2',(uchar)'\2',(uchar)'\2',(uchar)'\2',(uchar)'\2',
+(uchar)'\2',(uchar)'\2',(uchar)'\2',(uchar)'\2',(uchar)'\2',(uchar)'\2',(uchar)'\2',(uchar)'\2',
+(uchar)'\2',(uchar)'\2',(uchar)'\2',(uchar)'\2',(uchar)'\2',(uchar)'\2',(uchar)'\2',(uchar)'\2',
+(uchar)'\2',(uchar)'\2',(uchar)'\2',(uchar)'\2',(uchar)'\2',(uchar)'\2',(uchar)'\2',(uchar)'\2',
+(uchar)'\1',(uchar)'\1',(uchar)'\1',(uchar)'\1',(uchar)'\1',(uchar)'\1',(uchar)'\1',(uchar)'\1',
+(uchar)'\1',(uchar)'\1',(uchar)'\1',(uchar)'\1',(uchar)'\1',(uchar)'\1',(uchar)'\1',(uchar)'\1',
+(uchar)'\1',(uchar)'\1',(uchar)'\1',(uchar)'\1',(uchar)'\1',(uchar)'\1',(uchar)'\1',(uchar)'\1',
+(uchar)'\1',(uchar)'\1',(uchar)'\1',(uchar)'\1',(uchar)'\1',(uchar)'\1',(uchar)'\1',(uchar)'\1',
+};
+
+uchar NEAR to_lower_koi8_ukr[] = {
+'\000','\001','\002','\003','\004','\005','\006','\007',
+'\010','\011','\012','\013','\014','\015','\016','\017',
+'\020','\021','\022','\023','\024','\025','\026','\027',
+'\030','\031','\032','\033','\034','\035','\036','\037',
+' ', '!', '"', '#', '$', '%', '&', '\'',
+'(', ')', '*', '+', ',', '-', '.', '/',
+'0', '1', '2', '3', '4', '5', '6', '7',
+'8', '9', ':', ';', '<', '=', '>', '?',
+'@', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
+'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
+'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
+'x', 'y', 'z', '[', '\\', ']', '^', '_',
+' ', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
+'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
+'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
+'x', 'y', 'z', '{', '|', '}', '~', '\177',
+
+(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\40',
+(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\40',
+(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\40',
+(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\40',
+(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\243',(uchar)'\244',(uchar)'\40',(uchar)'\246',(uchar)'\247',
+(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\255',(uchar)'\40',(uchar)'\40',
+(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\243',(uchar)'\244',(uchar)'\40',(uchar)'\246',(uchar)'\247',
+(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\255',(uchar)'\40',(uchar)'\40',
+(uchar)'\300',(uchar)'\301',(uchar)'\302',(uchar)'\303',(uchar)'\304',(uchar)'\305',(uchar)'\306',(uchar)'\307',
+(uchar)'\310',(uchar)'\311',(uchar)'\312',(uchar)'\313',(uchar)'\314',(uchar)'\315',(uchar)'\316',(uchar)'\317',
+(uchar)'\320',(uchar)'\321',(uchar)'\322',(uchar)'\323',(uchar)'\324',(uchar)'\325',(uchar)'\326',(uchar)'\327',
+(uchar)'\330',(uchar)'\331',(uchar)'\332',(uchar)'\333',(uchar)'\334',(uchar)'\335',(uchar)'\336',(uchar)'\337',
+(uchar)'\300',(uchar)'\301',(uchar)'\302',(uchar)'\303',(uchar)'\304',(uchar)'\305',(uchar)'\306',(uchar)'\307',
+(uchar)'\310',(uchar)'\311',(uchar)'\312',(uchar)'\313',(uchar)'\314',(uchar)'\315',(uchar)'\316',(uchar)'\317',
+(uchar)'\320',(uchar)'\321',(uchar)'\322',(uchar)'\323',(uchar)'\324',(uchar)'\325',(uchar)'\326',(uchar)'\327',
+(uchar)'\330',(uchar)'\331',(uchar)'\332',(uchar)'\333',(uchar)'\334',(uchar)'\335',(uchar)'\336',(uchar)'\337',
+};
+
+uchar NEAR to_upper_koi8_ukr[] = {
+'\000','\001','\002','\003','\004','\005','\006','\007',
+'\010','\011','\012','\013','\014','\015','\016','\017',
+'\020','\021','\022','\023','\024','\025','\026','\027',
+'\030','\031','\032','\033','\034','\035','\036','\037',
+' ', '!', '"', '#', '$', '%', '&', '\'',
+'(', ')', '*', '+', ',', '-', '.', '/',
+'0', '1', '2', '3', '4', '5', '6', '7',
+'8', '9', ':', ';', '<', '=', '>', '?',
+'@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+'X', 'Y', 'Z', '[', '\\', ']', '^', '_',
+' ', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+'X', 'Y', 'Z', '{', '|', '}', '~', '\177',
+
+(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\40',
+(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\40',
+(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\40',
+(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\40',
+(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\263',(uchar)'\264',(uchar)'\40',(uchar)'\266',(uchar)'\267',
+(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\275',(uchar)'\40',(uchar)'\40',
+(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\263',(uchar)'\264',(uchar)'\40',(uchar)'\266',(uchar)'\267',
+(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\275',(uchar)'\40',(uchar)'\40',
+(uchar)'\340',(uchar)'\341',(uchar)'\342',(uchar)'\343',(uchar)'\344',(uchar)'\345',(uchar)'\346',(uchar)'\347',
+(uchar)'\350',(uchar)'\351',(uchar)'\352',(uchar)'\353',(uchar)'\354',(uchar)'\355',(uchar)'\356',(uchar)'\357',
+(uchar)'\360',(uchar)'\361',(uchar)'\362',(uchar)'\363',(uchar)'\364',(uchar)'\365',(uchar)'\366',(uchar)'\367',
+(uchar)'\370',(uchar)'\371',(uchar)'\372',(uchar)'\373',(uchar)'\374',(uchar)'\375',(uchar)'\376',(uchar)'\377',
+(uchar)'\340',(uchar)'\341',(uchar)'\342',(uchar)'\343',(uchar)'\344',(uchar)'\345',(uchar)'\346',(uchar)'\347',
+(uchar)'\350',(uchar)'\351',(uchar)'\352',(uchar)'\353',(uchar)'\354',(uchar)'\355',(uchar)'\356',(uchar)'\357',
+(uchar)'\360',(uchar)'\361',(uchar)'\362',(uchar)'\363',(uchar)'\364',(uchar)'\365',(uchar)'\366',(uchar)'\367',
+(uchar)'\370',(uchar)'\371',(uchar)'\372',(uchar)'\373',(uchar)'\374',(uchar)'\375',(uchar)'\376',(uchar)'\377',
+};
+
+uchar NEAR sort_order_koi8_ukr[] = {
+'\000','\001','\002','\003','\004','\005','\006','\007',
+'\010','\011','\012','\013','\014','\015','\016','\017',
+'\020','\021','\022','\023','\024','\025','\026','\027',
+'\030','\031','\032','\033','\034','\035','\036','\037',
+' ', '!', '"', '#', '$', '%', '&', '\'',
+'(', ')', '*', '+', ',', '-', '.', '/',
+'0', '1', '2', '3', '4', '5', '6', '7',
+'8', '9', ':', ';', '<', '=', '>', '?',
+'@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+'X', 'Y', 'Z', '[', '\\', ']', '^', '_',
+' ', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+'X', 'Y', 'Z', '{', '|', '}', '~', '\177',
+
+(uchar)'\245',(uchar)'\246',(uchar)'\247',(uchar)'\250',(uchar)'\251',(uchar)'\252',(uchar)'\253',(uchar)'\254',
+(uchar)'\255',(uchar)'\256',(uchar)'\257',(uchar)'\260',(uchar)'\261',(uchar)'\262',(uchar)'\263',(uchar)'\264',
+(uchar)'\265',(uchar)'\266',(uchar)'\267',(uchar)'\270',(uchar)'\271',(uchar)'\272',(uchar)'\273',(uchar)'\274',
+(uchar)'\275',(uchar)'\276',(uchar)'\277',(uchar)'\300',(uchar)'\301',(uchar)'\302',(uchar)'\303',(uchar)'\304',
+(uchar)'\305',(uchar)'\306',(uchar)'\307',(uchar)'\210',(uchar)'\207',(uchar)'\310',(uchar)'\214',(uchar)'\215',
+(uchar)'\311',(uchar)'\312',(uchar)'\313',(uchar)'\314',(uchar)'\315',(uchar)'\204',(uchar)'\316',(uchar)'\317',
+(uchar)'\320',(uchar)'\321',(uchar)'\322',(uchar)'\210',(uchar)'\207',(uchar)'\323',(uchar)'\214',(uchar)'\215',
+(uchar)'\324',(uchar)'\325',(uchar)'\326',(uchar)'\327',(uchar)'\330',(uchar)'\204',(uchar)'\331',(uchar)'\332',
+(uchar)'\243',(uchar)'\200',(uchar)'\201',(uchar)'\233',(uchar)'\205',(uchar)'\206',(uchar)'\231',(uchar)'\203',
+(uchar)'\232',(uchar)'\213',(uchar)'\216',(uchar)'\217',(uchar)'\220',(uchar)'\221',(uchar)'\222',(uchar)'\223',
+(uchar)'\224',(uchar)'\244',(uchar)'\225',(uchar)'\226',(uchar)'\227',(uchar)'\230',(uchar)'\211',(uchar)'\202',
+(uchar)'\241',(uchar)'\240',(uchar)'\212',(uchar)'\235',(uchar)'\242',(uchar)'\236',(uchar)'\234',(uchar)'\237',
+(uchar)'\243',(uchar)'\200',(uchar)'\201',(uchar)'\233',(uchar)'\205',(uchar)'\206',(uchar)'\231',(uchar)'\203',
+(uchar)'\232',(uchar)'\213',(uchar)'\216',(uchar)'\217',(uchar)'\220',(uchar)'\221',(uchar)'\222',(uchar)'\223',
+(uchar)'\224',(uchar)'\244',(uchar)'\225',(uchar)'\226',(uchar)'\227',(uchar)'\230',(uchar)'\211',(uchar)'\202',
+(uchar)'\241',(uchar)'\240',(uchar)'\212',(uchar)'\235',(uchar)'\242',(uchar)'\236',(uchar)'\234',(uchar)'\237',
+};
diff --git a/strings/Attic/ctype-latin1.c b/strings/Attic/ctype-latin1.c
new file mode 100644
index 00000000000..470b72ce34e
--- /dev/null
+++ b/strings/Attic/ctype-latin1.c
@@ -0,0 +1,142 @@
+/* Copyright Abandoned 1996 TCX DataKonsult AB & Monty Program KB & Detron HB
+ This file is public domain and comes with NO WARRANTY of any kind */
+
+/* This implements the ISO 8859 Latin1 character-set */
+
+#include <global.h>
+#include "m_string.h"
+
+#if MY_CHARSET_CURRENT == MY_CHARSET_LATIN1
+
+uchar NEAR ctype_latin1[257] = {
+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 NEAR to_lower_latin1[]={
+'\000','\001','\002','\003','\004','\005','\006','\007',
+'\010','\011','\012','\013','\014','\015','\016','\017',
+'\020','\021','\022','\023','\024','\025','\026','\027',
+'\030','\031','\032','\033','\034','\035','\036','\037',
+' ', '!', '"', '#', '$', '%', '&', '\'',
+'(', ')', '*', '+', ',', '-', '.', '/',
+'0', '1', '2', '3', '4', '5', '6', '7',
+'8', '9', ':', ';', '<', '=', '>', '?',
+'@', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
+'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
+'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
+'x', 'y', 'z', '[', '\\', ']', '^', '_',
+'`', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
+'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
+'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
+'x', 'y', 'z', '{', '|', '}', '~', '\177',
+
+(uchar) '\200',(uchar) '\201',(uchar) '\202',(uchar) '\203',(uchar) '\204',(uchar) '\205',(uchar) '\206',(uchar) '\207',
+(uchar) '\210',(uchar) '\211',(uchar) '\212',(uchar) '\213',(uchar) '\214',(uchar) '\215',(uchar) '\216',(uchar) '\217',
+(uchar) '\220',(uchar) '\221',(uchar) '\222',(uchar) '\223',(uchar) '\224',(uchar) '\225',(uchar) '\226',(uchar) '\227',
+(uchar) '\230',(uchar) '\231',(uchar) '\232',(uchar) '\233',(uchar) '\234',(uchar) '\235',(uchar) '\236',(uchar) '\237',
+(uchar) '\240',(uchar) '\241',(uchar) '\242',(uchar) '\243',(uchar) '\244',(uchar) '\245',(uchar) '\246',(uchar) '\247',
+(uchar) '\250',(uchar) '\251',(uchar) '\252',(uchar) '\253',(uchar) '\254',(uchar) '\255',(uchar) '\256',(uchar) '\257',
+(uchar) '\260',(uchar) '\261',(uchar) '\262',(uchar) '\263',(uchar) '\264',(uchar) '\265',(uchar) '\266',(uchar) '\267',
+(uchar) '\270',(uchar) '\271',(uchar) '\272',(uchar) '\273',(uchar) '\274',(uchar) '\275',(uchar) '\276',(uchar) '\277',
+(uchar) '\340',(uchar) '\341',(uchar) '\342',(uchar) '\343',(uchar) '\344',(uchar) '\345',(uchar) '\346',(uchar) '\347',
+(uchar) '\350',(uchar) '\351',(uchar) '\352',(uchar) '\353',(uchar) '\354',(uchar) '\355',(uchar) '\356',(uchar) '\357',
+(uchar) '\360',(uchar) '\361',(uchar) '\362',(uchar) '\363',(uchar) '\364',(uchar) '\365',(uchar) '\366',(uchar) '\327',
+(uchar) '\370',(uchar) '\371',(uchar) '\372',(uchar) '\373',(uchar) '\374',(uchar) '\375',(uchar) '\376',(uchar) '\337',
+(uchar) '\340',(uchar) '\341',(uchar) '\342',(uchar) '\343',(uchar) '\344',(uchar) '\345',(uchar) '\346',(uchar) '\347',
+(uchar) '\350',(uchar) '\351',(uchar) '\352',(uchar) '\353',(uchar) '\354',(uchar) '\355',(uchar) '\356',(uchar) '\357',
+(uchar) '\360',(uchar) '\361',(uchar) '\362',(uchar) '\363',(uchar) '\364',(uchar) '\365',(uchar) '\366',(uchar) '\367',
+(uchar) '\370',(uchar) '\371',(uchar) '\372',(uchar) '\373',(uchar) '\374',(uchar) '\375',(uchar) '\376',(uchar) '\377',
+};
+
+uchar NEAR to_upper_latin1[]={
+'\000','\001','\002','\003','\004','\005','\006','\007',
+'\010','\011','\012','\013','\014','\015','\016','\017',
+'\020','\021','\022','\023','\024','\025','\026','\027',
+'\030','\031','\032','\033','\034','\035','\036','\037',
+' ', '!', '"', '#', '$', '%', '&', '\'',
+'(', ')', '*', '+', ',', '-', '.', '/',
+'0', '1', '2', '3', '4', '5', '6', '7',
+'8', '9', ':', ';', '<', '=', '>', '?',
+'@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+'X', 'Y', 'Z', '[', '\\', ']', '^', '_',
+'`', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+'X', 'Y', 'Z', '{', '|', '}', '~', '\177',
+
+(uchar) '\200',(uchar) '\201',(uchar) '\202',(uchar) '\203',(uchar) '\204',(uchar) '\205',(uchar) '\206',(uchar) '\207',
+(uchar) '\210',(uchar) '\211',(uchar) '\212',(uchar) '\213',(uchar) '\214',(uchar) '\215',(uchar) '\216',(uchar) '\217',
+(uchar) '\220',(uchar) '\221',(uchar) '\222',(uchar) '\223',(uchar) '\224',(uchar) '\225',(uchar) '\226',(uchar) '\227',
+(uchar) '\230',(uchar) '\231',(uchar) '\232',(uchar) '\233',(uchar) '\234',(uchar) '\235',(uchar) '\236',(uchar) '\237',
+(uchar) '\240',(uchar) '\241',(uchar) '\242',(uchar) '\243',(uchar) '\244',(uchar) '\245',(uchar) '\246',(uchar) '\247',
+(uchar) '\250',(uchar) '\251',(uchar) '\252',(uchar) '\253',(uchar) '\254',(uchar) '\255',(uchar) '\256',(uchar) '\257',
+(uchar) '\260',(uchar) '\261',(uchar) '\262',(uchar) '\263',(uchar) '\264',(uchar) '\265',(uchar) '\266',(uchar) '\267',
+(uchar) '\270',(uchar) '\271',(uchar) '\272',(uchar) '\273',(uchar) '\274',(uchar) '\275',(uchar) '\276',(uchar) '\277',
+(uchar) '\300',(uchar) '\301',(uchar) '\302',(uchar) '\303',(uchar) '\304',(uchar) '\305',(uchar) '\306',(uchar) '\307',
+(uchar) '\310',(uchar) '\311',(uchar) '\312',(uchar) '\313',(uchar) '\314',(uchar) '\315',(uchar) '\316',(uchar) '\317',
+(uchar) '\320',(uchar) '\321',(uchar) '\322',(uchar) '\323',(uchar) '\324',(uchar) '\325',(uchar) '\326',(uchar) '\327',
+(uchar) '\330',(uchar) '\331',(uchar) '\332',(uchar) '\333',(uchar) '\334',(uchar) '\335',(uchar) '\336',(uchar) '\337',
+(uchar) '\300',(uchar) '\301',(uchar) '\302',(uchar) '\303',(uchar) '\304',(uchar) '\305',(uchar) '\306',(uchar) '\307',
+(uchar) '\310',(uchar) '\311',(uchar) '\312',(uchar) '\313',(uchar) '\314',(uchar) '\315',(uchar) '\316',(uchar) '\317',
+(uchar) '\320',(uchar) '\321',(uchar) '\322',(uchar) '\323',(uchar) '\324',(uchar) '\325',(uchar) '\326',(uchar) '\367',
+(uchar) '\330',(uchar) '\331',(uchar) '\332',(uchar) '\333',(uchar) '\334',(uchar) '\335',(uchar) '\336',(uchar) '\377',
+};
+
+#ifndef __WIN32__
+uchar NEAR sort_order_latin1[]={
+#else
+uchar sort_order_latin1[]={
+#endif
+'\000','\001','\002','\003','\004','\005','\006','\007',
+'\010','\011','\012','\013','\014','\015','\016','\017',
+'\020','\021','\022','\023','\024','\025','\026','\027',
+'\030','\031','\032','\033','\034','\035','\036','\037',
+' ', '!', '"', '#', '$', '%', '&', '\'',
+'(', ')', '*', '+', ',', '-', '.', '/',
+'0', '1', '2', '3', '4', '5', '6', '7',
+'8', '9', ':', ';', '<', '=', '>', '?',
+'@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+'X', 'Y', 'Z', '[', '\\', ']', '^', '_',
+'`', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+'X', 'Y', 'Z', '{', '|', '}', '~', '\177',
+
+(uchar) '\200',(uchar) '\201',(uchar) '\202',(uchar) '\203',(uchar) '\204',(uchar) '\205',(uchar) '\206',(uchar) '\207',
+(uchar) '\210',(uchar) '\211',(uchar) '\212',(uchar) '\213',(uchar) '\214',(uchar) '\215',(uchar) '\216',(uchar) '\217',
+(uchar) '\220',(uchar) '\221',(uchar) '\222',(uchar) '\223',(uchar) '\224',(uchar) '\225',(uchar) '\226',(uchar) '\227',
+(uchar) '\230',(uchar) '\231',(uchar) '\232',(uchar) '\233',(uchar) '\234',(uchar) '\235',(uchar) '\236',(uchar) '\237',
+(uchar) '\240',(uchar) '\241',(uchar) '\242',(uchar) '\243',(uchar) '\244',(uchar) '\245',(uchar) '\246',(uchar) '\247',
+(uchar) '\250',(uchar) '\251',(uchar) '\252',(uchar) '\253',(uchar) '\254',(uchar) '\255',(uchar) '\256',(uchar) '\257',
+(uchar) '\260',(uchar) '\261',(uchar) '\262',(uchar) '\263',(uchar) '\264',(uchar) '\265',(uchar) '\266',(uchar) '\267',
+(uchar) '\270',(uchar) '\271',(uchar) '\272',(uchar) '\273',(uchar) '\274',(uchar) '\275',(uchar) '\276',(uchar) '\277',
+'A', 'A', 'A', 'A', '\\', '[', '\\', 'C',
+'E', 'E', 'E', 'E', 'I', 'I', 'I', 'I',
+'D', 'N', 'O', 'O', 'O', 'O', ']', (uchar) '\327',
+(uchar) '\330','U', 'U', 'U', 'Y', 'Y', (uchar) '\336',(uchar) '\337',
+'A', 'A', 'A', 'A', '\\', '[', '\\', 'C',
+'E', 'E', 'E', 'E', 'I', 'I', 'I', 'I',
+'D', 'N', 'O', 'O', 'O', 'O', ']', (uchar) '\367',
+(uchar) '\330','U', 'U', 'U', 'Y', 'Y', (uchar) '\336',(uchar) '\377',
+};
+#endif /* MY_CHARSET_LATIN1 */
diff --git a/strings/Attic/ctype-latin2.c b/strings/Attic/ctype-latin2.c
new file mode 100644
index 00000000000..32ab6cface5
--- /dev/null
+++ b/strings/Attic/ctype-latin2.c
@@ -0,0 +1,186 @@
+/*
+ * File generated by cset
+ * (C) Abandoned 1997 Zarko Mocnik <zarko.mocnik@dem.si>
+ *
+ * August, 1997
+ * Regenerated, Jaroslaw Lewandowski <jotel@itnet.com.pl>
+ * - changed sort order characters with the accents :
+ * a-ogonek, c-ogonek, e-ogonek, l-slash, n-acute, o-acute,
+ * s-acute, z-acute, z-dot according to Polish alphabet standard.
+ * - changed type for character 'diaeresis' to _P
+ * Characters table are useful for Slovenian and Polish language
+ * and ISO-8859-2 character set
+ */
+
+#include <global.h>
+#include "m_string.h"
+
+#ifndef OLD_LATIN2_DEFINITION
+
+uchar NEAR ctype_latin2[257] = {
+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, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 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, 1, 16, 1, 16, 1, 1, 16, 16, 1, 1, 1, 1, 16, 1, 1,
+ 16, 2, 16, 2, 16, 2, 2, 16, 16, 2, 2, 2, 2, 16, 2, 2,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 16, 1, 1, 1, 1, 1, 1, 16, 1, 1, 1, 1, 1, 1, 1, 16,
+ 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, 16,
+};
+
+uchar NEAR to_lower_latin2[] = {
+ 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,177,162,179,164,181,182,167,168,185,186,187,188,173,190,191,
+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,
+208,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 NEAR to_upper_latin2[] = {
+ 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,161,178,163,180,165,166,183,184,169,170,171,172,189,174,175,
+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,
+240,209,210,211,212,213,214,247,216,217,218,219,220,221,222,255,
+};
+
+uchar NEAR sort_order_latin2[] = {
+ 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, 68, 69, 72, 73, 75, 76, 77, 78, 79, 80, 81, 83, 84, 86,
+ 88, 89, 90, 91, 94, 95, 96, 97, 98, 99,100,104,105,106,107,108,
+109, 65, 68, 69, 72, 73, 75, 76, 77, 78, 79, 80, 81, 83, 84, 86,
+ 88, 89, 90, 91, 94, 95, 96, 97, 98, 99,100,110,111,112,113,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255, 66,255, 82,255, 81, 92,255,255, 93, 91, 94,101,255,103,102,
+255, 66,255, 82,255, 81, 92,255,255, 93, 91, 94,101,255,103,102,
+ 90, 67, 67, 67, 67, 81, 70, 69, 71, 73, 74, 73, 73, 78, 78, 72,
+255, 85, 84, 87, 86, 86, 86,255, 90, 95, 95, 95, 95, 99, 94,255,
+ 90, 67, 67, 67, 67, 81, 70, 69, 71, 73, 74, 73, 73, 78, 78, 72,
+255, 85, 84, 87, 86, 86, 86,255, 90, 95, 95, 95, 95, 99, 94,255,
+};
+
+
+#else
+
+/*
+ * File generated by cset
+ * (C) Abandoned 1997 Zarko Mocnik <zarko.mocnik@dem.si>
+ *
+ * definition table reworked by Jaromir Dolecek <dolecek@ics.muni.cz>
+ */
+#include <global.h>
+#include "m_string.h"
+
+uchar NEAR ctype_latin2[257] = {
+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,
+ 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,
+ 1, 16, 1, 16, 1, 1, 16, 0, 0, 1, 1, 1, 1, 16, 1, 1,
+ 16, 2, 16, 2, 16, 2, 2, 16, 16, 2, 2, 2, 2, 16, 2, 2,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 16, 1, 1, 1, 1, 1, 1, 16, 1, 1, 1, 1, 1, 1, 1, 16,
+ 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, 16,
+};
+
+uchar NEAR to_lower_latin2[] = {
+ 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,
+177,161,179,163,181,182,166,167,168,185,186,187,188,173,190,191,
+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,
+208,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 NEAR to_upper_latin2[] = {
+ 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,160,178,162,180,164,165,183,184,169,170,171,172,189,174,175,
+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,
+240,209,210,211,212,213,214,247,216,217,218,219,220,221,222,255,
+};
+
+uchar NEAR sort_order_latin2[] = {
+ 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, 71, 72, 76, 78, 83, 84, 85, 86, 90, 91, 92, 96, 97,100,
+105,106,107,110,114,117,122,123,124,125,127,131,132,133,134,135,
+136, 65, 71, 72, 76, 78, 83, 84, 85, 86, 90, 91, 92, 96, 97,100,
+105,106,107,110,114,117,122,123,124,125,127,137,138,139,140, 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,255,
+ 66,255, 93,255, 94,111,255,255,255,112,113,115,128,255,129,130,
+255, 66,255, 93,255, 94,111,255,255,112,113,115,128,255,129,130,
+108, 67, 68, 69, 70, 95, 73, 75, 74, 79, 81, 82, 80, 89, 87, 77,
+255, 98, 99,101,102,103,104,255,109,119,118,120,121,126,116,255,
+108, 67, 68, 69, 70, 95, 73, 75, 74, 79, 81, 82, 80, 89, 88, 77,
+255, 98, 99,101,102,103,104,255,109,119,118,120,121,126,116,255,
+};
+
+#endif
diff --git a/strings/Attic/ctype-swe7.c b/strings/Attic/ctype-swe7.c
new file mode 100644
index 00000000000..19a79ecd3f7
--- /dev/null
+++ b/strings/Attic/ctype-swe7.c
@@ -0,0 +1,137 @@
+/* Copyright Abandoned 1996 TCX DataKonsult AB & Monty Program KB & Detron HB
+ This file is public domain and comes with NO WARRANTY of any kind */
+
+/* Define arrays to map character codes to types, uppercase,
+ lowercase and sortorder. */
+
+#include <global.h>
+#include "m_string.h"
+
+uchar NEAR ctype_swe7[257] =
+{
+ 0, /* For standard library */
+ 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,
+ 1,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,1,1,1,1,16,
+ 1,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,2,2,2,2,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,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+};
+
+uchar NEAR to_lower_swe7[]=
+{
+ '\000','\001','\002','\003','\004','\005','\006','\007',
+ '\010','\011','\012','\013','\014','\015','\016','\017',
+ '\020','\021','\022','\023','\024','\025','\026','\027',
+ '\030','\031','\032','\033','\034','\035','\036','\037',
+ ' ', '!', '"', '#', '$', '%', '&', '\'',
+ '(', ')', '*', '+', ',', '-', '.', '/',
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', ':', ';', '<', '=', '>', '?',
+ '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
+ 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
+ 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
+ 'x', 'y', 'z', '{', '|', '}', '~', '_',
+ '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
+ 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
+ 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
+ 'x', 'y', 'z', '{', '|', '}', '~', '\177',
+ (uchar) '\200',(uchar) '\201',(uchar) '\202',(uchar) '\203',(uchar) '\204',(uchar) '\205',(uchar) '\206',(uchar) '\207',
+ (uchar) '\210',(uchar) '\211',(uchar) '\212',(uchar) '\213',(uchar) '\214',(uchar) '\215',(uchar) '\216',(uchar) '\217',
+ (uchar) '\220',(uchar) '\221',(uchar) '\222',(uchar) '\223',(uchar) '\224',(uchar) '\225',(uchar) '\226',(uchar) '\227',
+ (uchar) '\230',(uchar) '\231',(uchar) '\232',(uchar) '\233',(uchar) '\234',(uchar) '\235',(uchar) '\236',(uchar) '\237',
+ (uchar) '\240',(uchar) '\241',(uchar) '\242',(uchar) '\243',(uchar) '\244',(uchar) '\245',(uchar) '\246',(uchar) '\247',
+ (uchar) '\250',(uchar) '\251',(uchar) '\252',(uchar) '\253',(uchar) '\254',(uchar) '\255',(uchar) '\256',(uchar) '\257',
+ (uchar) '\260',(uchar) '\261',(uchar) '\262',(uchar) '\263',(uchar) '\264',(uchar) '\265',(uchar) '\266',(uchar) '\267',
+ (uchar) '\270',(uchar) '\271',(uchar) '\272',(uchar) '\273',(uchar) '\274',(uchar) '\275',(uchar) '\276',(uchar) '\277',
+ (uchar) '\300',(uchar) '\301',(uchar) '\302',(uchar) '\303',(uchar) '\304',(uchar) '\305',(uchar) '\306',(uchar) '\307',
+ (uchar) '\310',(uchar) '\311',(uchar) '\312',(uchar) '\313',(uchar) '\314',(uchar) '\315',(uchar) '\316',(uchar) '\317',
+ (uchar) '\320',(uchar) '\321',(uchar) '\322',(uchar) '\323',(uchar) '\324',(uchar) '\325',(uchar) '\326',(uchar) '\327',
+ (uchar) '\330',(uchar) '\331',(uchar) '\332',(uchar) '\333',(uchar) '\334',(uchar) '\335',(uchar) '\336',(uchar) '\337',
+ (uchar) '\340',(uchar) '\341',(uchar) '\342',(uchar) '\343',(uchar) '\344',(uchar) '\345',(uchar) '\346',(uchar) '\347',
+ (uchar) '\350',(uchar) '\351',(uchar) '\352',(uchar) '\353',(uchar) '\354',(uchar) '\355',(uchar) '\356',(uchar) '\357',
+ (uchar) '\360',(uchar) '\361',(uchar) '\362',(uchar) '\363',(uchar) '\364',(uchar) '\365',(uchar) '\366',(uchar) '\367',
+ (uchar) '\370',(uchar) '\371',(uchar) '\372',(uchar) '\373',(uchar) '\374',(uchar) '\375',(uchar) '\376',(uchar) '\377',
+};
+
+uchar NEAR to_upper_swe7[]=
+{
+ '\000','\001','\002','\003','\004','\005','\006','\007',
+ '\010','\011','\012','\013','\014','\015','\016','\017',
+ '\020','\021','\022','\023','\024','\025','\026','\027',
+ '\030','\031','\032','\033','\034','\035','\036','\037',
+ ' ', '!', '"', '#', '$', '%', '&', '\'',
+ '(', ')', '*', '+', ',', '-', '.', '/',
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', ':', ';', '<', '=', '>', '?',
+ '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+ 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+ 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+ 'X', 'Y', 'Z', '[', '\\', ']', '^', '_',
+ '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+ 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+ 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+ 'X', 'Y', 'Z', '[', '\\', ']', '^', '\177',
+ (uchar) '\200',(uchar) '\201',(uchar) '\202',(uchar) '\203',(uchar) '\204',(uchar) '\205',(uchar) '\206',(uchar) '\207',
+ (uchar) '\210',(uchar) '\211',(uchar) '\212',(uchar) '\213',(uchar) '\214',(uchar) '\215',(uchar) '\216',(uchar) '\217',
+ (uchar) '\220',(uchar) '\221',(uchar) '\222',(uchar) '\223',(uchar) '\224',(uchar) '\225',(uchar) '\226',(uchar) '\227',
+ (uchar) '\230',(uchar) '\231',(uchar) '\232',(uchar) '\233',(uchar) '\234',(uchar) '\235',(uchar) '\236',(uchar) '\237',
+ (uchar) '\240',(uchar) '\241',(uchar) '\242',(uchar) '\243',(uchar) '\244',(uchar) '\245',(uchar) '\246',(uchar) '\247',
+ (uchar) '\250',(uchar) '\251',(uchar) '\252',(uchar) '\253',(uchar) '\254',(uchar) '\255',(uchar) '\256',(uchar) '\257',
+ (uchar) '\260',(uchar) '\261',(uchar) '\262',(uchar) '\263',(uchar) '\264',(uchar) '\265',(uchar) '\266',(uchar) '\267',
+ (uchar) '\270',(uchar) '\271',(uchar) '\272',(uchar) '\273',(uchar) '\274',(uchar) '\275',(uchar) '\276',(uchar) '\277',
+ (uchar) '\300',(uchar) '\301',(uchar) '\302',(uchar) '\303',(uchar) '\304',(uchar) '\305',(uchar) '\306',(uchar) '\307',
+ (uchar) '\310',(uchar) '\311',(uchar) '\312',(uchar) '\313',(uchar) '\314',(uchar) '\315',(uchar) '\316',(uchar) '\317',
+ (uchar) '\320',(uchar) '\321',(uchar) '\322',(uchar) '\323',(uchar) '\324',(uchar) '\325',(uchar) '\326',(uchar) '\327',
+ (uchar) '\330',(uchar) '\331',(uchar) '\332',(uchar) '\333',(uchar) '\334',(uchar) '\335',(uchar) '\336',(uchar) '\337',
+ (uchar) '\340',(uchar) '\341',(uchar) '\342',(uchar) '\343',(uchar) '\344',(uchar) '\345',(uchar) '\346',(uchar) '\347',
+ (uchar) '\350',(uchar) '\351',(uchar) '\352',(uchar) '\353',(uchar) '\354',(uchar) '\355',(uchar) '\356',(uchar) '\357',
+ (uchar) '\360',(uchar) '\361',(uchar) '\362',(uchar) '\363',(uchar) '\364',(uchar) '\365',(uchar) '\366',(uchar) '\367',
+ (uchar) '\370',(uchar) '\371',(uchar) '\372',(uchar) '\373',(uchar) '\374',(uchar) '\375',(uchar) '\376',(uchar) '\377',
+};
+
+uchar NEAR sort_order_swe7[]=
+{
+ '\000','\001','\002','\003','\004','\005','\006','\007',
+ '\010','\011','\012','\013','\014','\015','\016','\017',
+ '\020','\021','\022','\023','\024','\025','\026','\027',
+ '\030','\031','\032','\033','\034','\035','\036','\037',
+ ' ', '!', '"', '#', '$', '%', '&', '\'',
+ '(', ')', '*', '+', ',', '-', '.', '/',
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', ':', ';', '<', '=', '>', '?',
+ 'E', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+ 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+ 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+ 'X', 'Y', 'Z', '\\', ']', '[', 'Y', '_',
+ 'E', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+ 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+ 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+ 'X', 'Y', 'Z', '\\', ']', '[', 'Y', '\177',
+ (uchar) '\200',(uchar) '\201',(uchar) '\202',(uchar) '\203',(uchar) '\204',(uchar) '\205',(uchar) '\206',(uchar) '\207',
+ (uchar) '\210',(uchar) '\211',(uchar) '\212',(uchar) '\213',(uchar) '\214',(uchar) '\215',(uchar) '\216',(uchar) '\217',
+ (uchar) '\220',(uchar) '\221',(uchar) '\222',(uchar) '\223',(uchar) '\224',(uchar) '\225',(uchar) '\226',(uchar) '\227',
+ (uchar) '\230',(uchar) '\231',(uchar) '\232',(uchar) '\233',(uchar) '\234',(uchar) '\235',(uchar) '\236',(uchar) '\237',
+ (uchar) '\240',(uchar) '\241',(uchar) '\242',(uchar) '\243',(uchar) '\244',(uchar) '\245',(uchar) '\246',(uchar) '\247',
+ (uchar) '\250',(uchar) '\251',(uchar) '\252',(uchar) '\253',(uchar) '\254',(uchar) '\255',(uchar) '\256',(uchar) '\257',
+ (uchar) '\260',(uchar) '\261',(uchar) '\262',(uchar) '\263',(uchar) '\264',(uchar) '\265',(uchar) '\266',(uchar) '\267',
+ (uchar) '\270',(uchar) '\271',(uchar) '\272',(uchar) '\273',(uchar) '\274',(uchar) '\275',(uchar) '\276',(uchar) '\277',
+ (uchar) '\300',(uchar) '\301',(uchar) '\302',(uchar) '\303',(uchar) '\304',(uchar) '\305',(uchar) '\306',(uchar) '\307',
+ (uchar) '\310',(uchar) '\311',(uchar) '\312',(uchar) '\313',(uchar) '\314',(uchar) '\315',(uchar) '\316',(uchar) '\317',
+ (uchar) '\320',(uchar) '\321',(uchar) '\322',(uchar) '\323',(uchar) '\324',(uchar) '\325',(uchar) '\326',(uchar) '\327',
+ (uchar) '\330',(uchar) '\331',(uchar) '\332',(uchar) '\333',(uchar) '\334',(uchar) '\335',(uchar) '\336',(uchar) '\337',
+ (uchar) '\340',(uchar) '\341',(uchar) '\342',(uchar) '\343',(uchar) '\344',(uchar) '\345',(uchar) '\346',(uchar) '\347',
+ (uchar) '\350',(uchar) '\351',(uchar) '\352',(uchar) '\353',(uchar) '\354',(uchar) '\355',(uchar) '\356',(uchar) '\357',
+ (uchar) '\360',(uchar) '\361',(uchar) '\362',(uchar) '\363',(uchar) '\364',(uchar) '\365',(uchar) '\366',(uchar) '\367',
+ (uchar) '\370',(uchar) '\371',(uchar) '\372',(uchar) '\373',(uchar) '\374',(uchar) '\375',(uchar) '\376',(uchar) '\377',
+};
diff --git a/strings/Attic/ctype-usa7.c b/strings/Attic/ctype-usa7.c
new file mode 100644
index 00000000000..87e9d30f854
--- /dev/null
+++ b/strings/Attic/ctype-usa7.c
@@ -0,0 +1,134 @@
+/* Copyright Abandoned 1996 TCX DataKonsult AB & Monty Program KB & Detron HB
+ This file is public domain and comes with NO WARRANTY of any kind */
+
+#include <global.h>
+#include "m_string.h"
+
+uchar NEAR ctype_usa7[257] =
+{
+ 0, /* For standard library */
+ 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,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+};
+
+uchar NEAR to_lower_usa7[]=
+{
+ '\000','\001','\002','\003','\004','\005','\006','\007',
+ '\010','\011','\012','\013','\014','\015','\016','\017',
+ '\020','\021','\022','\023','\024','\025','\026','\027',
+ '\030','\031','\032','\033','\034','\035','\036','\037',
+ ' ', '!', '"', '#', '$', '%', '&', '\'',
+ '(', ')', '*', '+', ',', '-', '.', '/',
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', ':', ';', '<', '=', '>', '?',
+ '@', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
+ 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
+ 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
+ 'x', 'y', 'z', '[', '\\', ']', '^', '_',
+ '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
+ 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
+ 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
+ 'x', 'y', 'z', '{', '|', '}', '~', '\177',
+ (uchar) '\200',(uchar) '\201',(uchar) '\202',(uchar) '\203',(uchar) '\204',(uchar) '\205',(uchar) '\206',(uchar) '\207',
+ (uchar) '\210',(uchar) '\211',(uchar) '\212',(uchar) '\213',(uchar) '\214',(uchar) '\215',(uchar) '\216',(uchar) '\217',
+ (uchar) '\220',(uchar) '\221',(uchar) '\222',(uchar) '\223',(uchar) '\224',(uchar) '\225',(uchar) '\226',(uchar) '\227',
+ (uchar) '\230',(uchar) '\231',(uchar) '\232',(uchar) '\233',(uchar) '\234',(uchar) '\235',(uchar) '\236',(uchar) '\237',
+ (uchar) '\240',(uchar) '\241',(uchar) '\242',(uchar) '\243',(uchar) '\244',(uchar) '\245',(uchar) '\246',(uchar) '\247',
+ (uchar) '\250',(uchar) '\251',(uchar) '\252',(uchar) '\253',(uchar) '\254',(uchar) '\255',(uchar) '\256',(uchar) '\257',
+ (uchar) '\260',(uchar) '\261',(uchar) '\262',(uchar) '\263',(uchar) '\264',(uchar) '\265',(uchar) '\266',(uchar) '\267',
+ (uchar) '\270',(uchar) '\271',(uchar) '\272',(uchar) '\273',(uchar) '\274',(uchar) '\275',(uchar) '\276',(uchar) '\277',
+ (uchar) '\300',(uchar) '\301',(uchar) '\302',(uchar) '\303',(uchar) '\304',(uchar) '\305',(uchar) '\306',(uchar) '\307',
+ (uchar) '\310',(uchar) '\311',(uchar) '\312',(uchar) '\313',(uchar) '\314',(uchar) '\315',(uchar) '\316',(uchar) '\317',
+ (uchar) '\320',(uchar) '\321',(uchar) '\322',(uchar) '\323',(uchar) '\324',(uchar) '\325',(uchar) '\326',(uchar) '\327',
+ (uchar) '\330',(uchar) '\331',(uchar) '\332',(uchar) '\333',(uchar) '\334',(uchar) '\335',(uchar) '\336',(uchar) '\337',
+ (uchar) '\340',(uchar) '\341',(uchar) '\342',(uchar) '\343',(uchar) '\344',(uchar) '\345',(uchar) '\346',(uchar) '\347',
+ (uchar) '\350',(uchar) '\351',(uchar) '\352',(uchar) '\353',(uchar) '\354',(uchar) '\355',(uchar) '\356',(uchar) '\357',
+ (uchar) '\360',(uchar) '\361',(uchar) '\362',(uchar) '\363',(uchar) '\364',(uchar) '\365',(uchar) '\366',(uchar) '\367',
+ (uchar) '\370',(uchar) '\371',(uchar) '\372',(uchar) '\373',(uchar) '\374',(uchar) '\375',(uchar) '\376',(uchar) '\377',
+};
+
+uchar NEAR to_upper_usa7[]=
+{
+ '\000','\001','\002','\003','\004','\005','\006','\007',
+ '\010','\011','\012','\013','\014','\015','\016','\017',
+ '\020','\021','\022','\023','\024','\025','\026','\027',
+ '\030','\031','\032','\033','\034','\035','\036','\037',
+ ' ', '!', '"', '#', '$', '%', '&', '\'',
+ '(', ')', '*', '+', ',', '-', '.', '/',
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', ':', ';', '<', '=', '>', '?',
+ '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+ 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+ 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+ 'X', 'Y', 'Z', '[', '\\', ']', '^', '_',
+ '`', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+ 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+ 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+ 'X', 'Y', 'Z', '{', '|', '}', '~', '\177',
+ (uchar) '\200',(uchar) '\201',(uchar) '\202',(uchar) '\203',(uchar) '\204',(uchar) '\205',(uchar) '\206',(uchar) '\207',
+ (uchar) '\210',(uchar) '\211',(uchar) '\212',(uchar) '\213',(uchar) '\214',(uchar) '\215',(uchar) '\216',(uchar) '\217',
+ (uchar) '\220',(uchar) '\221',(uchar) '\222',(uchar) '\223',(uchar) '\224',(uchar) '\225',(uchar) '\226',(uchar) '\227',
+ (uchar) '\230',(uchar) '\231',(uchar) '\232',(uchar) '\233',(uchar) '\234',(uchar) '\235',(uchar) '\236',(uchar) '\237',
+ (uchar) '\240',(uchar) '\241',(uchar) '\242',(uchar) '\243',(uchar) '\244',(uchar) '\245',(uchar) '\246',(uchar) '\247',
+ (uchar) '\250',(uchar) '\251',(uchar) '\252',(uchar) '\253',(uchar) '\254',(uchar) '\255',(uchar) '\256',(uchar) '\257',
+ (uchar) '\260',(uchar) '\261',(uchar) '\262',(uchar) '\263',(uchar) '\264',(uchar) '\265',(uchar) '\266',(uchar) '\267',
+ (uchar) '\270',(uchar) '\271',(uchar) '\272',(uchar) '\273',(uchar) '\274',(uchar) '\275',(uchar) '\276',(uchar) '\277',
+ (uchar) '\300',(uchar) '\301',(uchar) '\302',(uchar) '\303',(uchar) '\304',(uchar) '\305',(uchar) '\306',(uchar) '\307',
+ (uchar) '\310',(uchar) '\311',(uchar) '\312',(uchar) '\313',(uchar) '\314',(uchar) '\315',(uchar) '\316',(uchar) '\317',
+ (uchar) '\320',(uchar) '\321',(uchar) '\322',(uchar) '\323',(uchar) '\324',(uchar) '\325',(uchar) '\326',(uchar) '\327',
+ (uchar) '\330',(uchar) '\331',(uchar) '\332',(uchar) '\333',(uchar) '\334',(uchar) '\335',(uchar) '\336',(uchar) '\337',
+ (uchar) '\340',(uchar) '\341',(uchar) '\342',(uchar) '\343',(uchar) '\344',(uchar) '\345',(uchar) '\346',(uchar) '\347',
+ (uchar) '\350',(uchar) '\351',(uchar) '\352',(uchar) '\353',(uchar) '\354',(uchar) '\355',(uchar) '\356',(uchar) '\357',
+ (uchar) '\360',(uchar) '\361',(uchar) '\362',(uchar) '\363',(uchar) '\364',(uchar) '\365',(uchar) '\366',(uchar) '\367',
+ (uchar) '\370',(uchar) '\371',(uchar) '\372',(uchar) '\373',(uchar) '\374',(uchar) '\375',(uchar) '\376',(uchar) '\377',
+};
+
+uchar NEAR sort_order_usa7[]=
+{
+ '\000','\001','\002','\003','\004','\005','\006','\007',
+ '\010','\011','\012','\013','\014','\015','\016','\017',
+ '\020','\021','\022','\023','\024','\025','\026','\027',
+ '\030','\031','\032','\033','\034','\035','\036','\037',
+ ' ', '!', '"', '#', '$', '%', '&', '\'',
+ '(', ')', '*', '+', ',', '-', '.', '/',
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', ':', ';', '<', '=', '>', '?',
+ '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+ 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+ 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+ 'X', 'Y', 'Z', '\\', ']', '[', '^', '_',
+ 'E', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+ 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+ 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+ 'X', 'Y', 'Z', '{', '|', '}', 'Y', '\177',
+ (uchar) '\200',(uchar) '\201',(uchar) '\202',(uchar) '\203',(uchar) '\204',(uchar) '\205',(uchar) '\206',(uchar) '\207',
+ (uchar) '\210',(uchar) '\211',(uchar) '\212',(uchar) '\213',(uchar) '\214',(uchar) '\215',(uchar) '\216',(uchar) '\217',
+ (uchar) '\220',(uchar) '\221',(uchar) '\222',(uchar) '\223',(uchar) '\224',(uchar) '\225',(uchar) '\226',(uchar) '\227',
+ (uchar) '\230',(uchar) '\231',(uchar) '\232',(uchar) '\233',(uchar) '\234',(uchar) '\235',(uchar) '\236',(uchar) '\237',
+ (uchar) '\240',(uchar) '\241',(uchar) '\242',(uchar) '\243',(uchar) '\244',(uchar) '\245',(uchar) '\246',(uchar) '\247',
+ (uchar) '\250',(uchar) '\251',(uchar) '\252',(uchar) '\253',(uchar) '\254',(uchar) '\255',(uchar) '\256',(uchar) '\257',
+ (uchar) '\260',(uchar) '\261',(uchar) '\262',(uchar) '\263',(uchar) '\264',(uchar) '\265',(uchar) '\266',(uchar) '\267',
+ (uchar) '\270',(uchar) '\271',(uchar) '\272',(uchar) '\273',(uchar) '\274',(uchar) '\275',(uchar) '\276',(uchar) '\277',
+ (uchar) '\300',(uchar) '\301',(uchar) '\302',(uchar) '\303',(uchar) '\304',(uchar) '\305',(uchar) '\306',(uchar) '\307',
+ (uchar) '\310',(uchar) '\311',(uchar) '\312',(uchar) '\313',(uchar) '\314',(uchar) '\315',(uchar) '\316',(uchar) '\317',
+ (uchar) '\320',(uchar) '\321',(uchar) '\322',(uchar) '\323',(uchar) '\324',(uchar) '\325',(uchar) '\326',(uchar) '\327',
+ (uchar) '\330',(uchar) '\331',(uchar) '\332',(uchar) '\333',(uchar) '\334',(uchar) '\335',(uchar) '\336',(uchar) '\337',
+ (uchar) '\340',(uchar) '\341',(uchar) '\342',(uchar) '\343',(uchar) '\344',(uchar) '\345',(uchar) '\346',(uchar) '\347',
+ (uchar) '\350',(uchar) '\351',(uchar) '\352',(uchar) '\353',(uchar) '\354',(uchar) '\355',(uchar) '\356',(uchar) '\357',
+ (uchar) '\360',(uchar) '\361',(uchar) '\362',(uchar) '\363',(uchar) '\364',(uchar) '\365',(uchar) '\366',(uchar) '\367',
+ (uchar) '\370',(uchar) '\371',(uchar) '\372',(uchar) '\373',(uchar) '\374',(uchar) '\375',(uchar) '\376',(uchar) '\377',
+};
diff --git a/strings/Attic/ctype-win1250.c b/strings/Attic/ctype-win1250.c
new file mode 100644
index 00000000000..300f6967ac4
--- /dev/null
+++ b/strings/Attic/ctype-win1250.c
@@ -0,0 +1,152 @@
+/* ctype-win1250.c */
+/*
+ * win1250 code page with Croatian sort order
+ * Created by Davor Stare, Zagreb, 1999.
+ * This file is public domain and comes with NO WARRANTY of any kind.
+ * Send comments to: davor.stare@artronic.hr
+ */
+
+#include <global.h>
+#include "m_string.h"
+
+uchar NEAR ctype_win1250[257] = {
+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,
+ 32, 32, 16, 32, 16, 16, 16, 16,
+ 32, 16, 1, 16, 1, 1, 1, 1,
+ 32, 16, 16, 16, 16, 16, 16, 16,
+ 32, 16, 2, 16, 2, 2, 2, 2,
+ 72, 16, 16, 1, 16, 1, 16, 1,
+ 16, 16, 1, 16, 16, 16, 16, 1,
+ 16, 16, 16, 2, 16, 16, 16, 16,
+ 16, 2, 2, 16, 1, 16, 2, 2,
+ 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, 16
+};
+
+uchar NEAR to_lower_win1250[]={
+ 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, 154, 139, 156, 157, 158, 159,
+144, 145, 146, 147, 148, 149, 150, 151,
+152, 153, 154, 155, 156, 157, 158, 159,
+160, 161, 162, 179, 164, 185, 166, 223,
+168, 169, 186, 171, 172, 173, 174, 191,
+176, 177, 178, 179, 180, 181, 182, 183,
+184, 185, 186, 187, 190, 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 NEAR to_upper_win1250[]={
+ 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, 138, 155, 140, 141, 142, 143,
+160, 161, 162, 163, 164, 165, 166, 167,
+168, 169, 170, 171, 172, 173, 174, 175,
+176, 177, 178, 163, 180, 181, 182, 183,
+184, 165, 170, 187, 188, 189, 188, 175,
+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, 167,
+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
+};
+
+uchar NEAR sort_order_win1250[]={
+ 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, 70, 73, 74, 75,
+ 76, 77, 78, 79, 80, 82, 83, 85,
+ 86, 87, 88, 89, 91, 92, 93, 94,
+ 95, 96, 97, 99, 100, 101, 102, 103,
+104, 65, 66, 67, 70, 73, 74, 75,
+ 76, 77, 78, 79, 80, 82, 83, 85,
+ 86, 87, 88, 89, 91, 92, 93, 94,
+ 95, 96, 97, 123, 124, 125, 126, 127,
+128, 129, 130, 131, 132, 133, 134, 135,
+136, 137, 90, 139, 90, 91, 98, 98,
+144, 145, 146, 147, 148, 149, 150, 151,
+152, 153, 90, 155, 90, 91, 98, 98,
+ 32, 161, 162, 80, 164, 65, 166, 89,
+168, 169, 89, 171, 172, 173, 174, 98,
+176, 177, 178, 80, 180, 181, 182, 183,
+184, 65, 89, 187, 80, 189, 80, 98,
+ 88, 65, 65, 65, 65, 80, 69, 67,
+ 68, 73, 73, 73, 73, 77, 77, 70,
+ 71, 83, 83, 85, 85, 85, 85, 215,
+ 88, 92, 92, 92, 92, 96, 91, 89,
+ 88, 65, 65, 65, 65, 80, 69, 67,
+ 68, 73, 73, 73, 73, 77, 77, 70,
+ 71, 83, 83, 85, 85, 85, 85, 247,
+ 88, 92, 92, 92, 92, 96, 91, 255
+};
+
diff --git a/strings/Attic/ctype-win1251.c b/strings/Attic/ctype-win1251.c
new file mode 100644
index 00000000000..fadad184dad
--- /dev/null
+++ b/strings/Attic/ctype-win1251.c
@@ -0,0 +1,135 @@
+/* ctype-win1251.c */
+/*
+ * Created by Rustam B. Abdullaev, Tashkent, 1998.
+ * This file is public domain and comes with NO WARRANTY of any kind.
+ * Send bugs and wishes to: rustik@writeme.com
+ */
+
+#include <global.h>
+#include "m_string.h"
+
+uchar NEAR ctype_win1251[257] = {
+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,
+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, 16,
+16, 16, 16, 16, 16, 16, 16, 16, 1, 16, 16, 16, 16, 16, 16, 16,
+16, 16, 16, 16, 16, 16, 16, 16, 2, 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, 1, 1, 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, 2, 2, 2, 2, 2, 2, 2, 2
+};
+
+uchar NEAR to_lower_win1251[]={
+'\0', '\x1', '\x2', '\x3', '\x4', '\x5', '\x6', '\x7',
+'\x8', '\x9', '\xA', '\xB', '\xC', '\xD', '\xE', '\xF',
+'\x10','\x11','\x12','\x13','\x14','\x15','\x16','\x17',
+'\x18','\x19','\x1A','\x1B','\x1C','\x1D','\x1E','\x1F',
+' ', '!', '"', '#', '$', '%', '&', '\'',
+'(', ')', '*', '+', ',', '-', '.', '/',
+'0', '1', '2', '3', '4', '5', '6', '7',
+'8', '9', ':', ';', '<', '=', '>', '?',
+'@', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
+'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
+'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
+'x', 'y', 'z', '[', '\\', ']', '^', '_',
+'`', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
+'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
+'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
+'x', 'y', 'z', '{', '|', '}', '~', '\x7F',
+'\x80','\x81','\x82','\x83','\x84','\x85','\x86','\x87',
+'\x88','\x89','\x8A','\x8B','\x8C','\x8D','\x8E','\x8F',
+'\x90','\x91','\x92','\x93','\x94','\x95','\x96','\x97',
+'\x98','\x99','\x9A','\x9B','\x9C','\x9D','\x9E','\x9F',
+'\xA0','\xA1','\xA2','\xA3','\xA4','\xA5','\xA6','\xA7',
+'\xB8','\xA9','\xAA','\xAB','\xAC','\xAD','\xAE','\xAF',
+'\xB0','\xB1','\xB2','\xB3','\xB4','\xB5','\xB6','\xB7',
+'\xB8','\xB9','\xBA','\xBB','\xBC','\xBD','\xBE','\xBF',
+'\xE0','\xE1','\xE2','\xE3','\xE4','\xE5','\xE6','\xE7',
+'\xE8','\xE9','\xEA','\xEB','\xEC','\xED','\xEE','\xEF',
+'\xF0','\xF1','\xF2','\xF3','\xF4','\xF5','\xF5','\xF7',
+'\xF8','\xF9','\xFA','\xFB','\xFC','\xFD','\xFE','\xFF',
+'\xE0','\xE1','\xE2','\xE3','\xE4','\xE5','\xE6','\xE7',
+'\xE8','\xE9','\xEA','\xEB','\xEC','\xED','\xEE','\xEF',
+'\xF0','\xF1','\xF2','\xF3','\xF4','\xF5','\xF6','\xF7',
+'\xF8','\xF9','\xFA','\xFB','\xFC','\xFD','\xFE','\xFF'
+};
+
+uchar NEAR to_upper_win1251[]={
+'\0', '\x1', '\x2', '\x3', '\x4', '\x5', '\x6', '\x7',
+'\x8', '\x9', '\xA', '\xB', '\xC', '\xD', '\xE', '\xF',
+'\x10','\x11','\x12','\x13','\x14','\x15','\x16','\x17',
+'\x18','\x19','\x1A','\x1B','\x1C','\x1D','\x1E','\x1F',
+' ', '!', '"', '#', '$', '%', '&', '\'',
+'(', ')', '*', '+', ',', '-', '.', '/',
+'0', '1', '2', '3', '4', '5', '6', '7',
+'8', '9', ':', ';', '<', '=', '>', '?',
+'@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+'X', 'Y', 'Z', '[', '\\', ']', '^', '_',
+'`', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+'X', 'Y', 'Z', '{', '|', '}', '~', '\x7F',
+'\x80','\x81','\x82','\x83','\x84','\x85','\x86','\x87',
+'\x88','\x89','\x8A','\x8B','\x8C','\x8D','\x8E','\x8F',
+'\x90','\x91','\x92','\x93','\x94','\x95','\x96','\x97',
+'\x98','\x99','\x9A','\x9B','\x9C','\x9D','\x9E','\x9F',
+'\xA0','\xA1','\xA2','\xA3','\xA4','\xA5','\xA6','\xA7',
+'\xA8','\xA9','\xAA','\xAB','\xAC','\xAD','\xAE','\xAF',
+'\xB0','\xB1','\xB2','\xB3','\xB4','\xB5','\xB6','\xB7',
+'\xA8','\xB9','\xBA','\xBB','\xBC','\xBD','\xBE','\xBF',
+'\xC0','\xC1','\xC2','\xC3','\xC4','\xC5','\xC6','\xC7',
+'\xC8','\xC9','\xCA','\xCB','\xCC','\xCD','\xCE','\xCF',
+'\xD0','\xD1','\xD2','\xD3','\xD4','\xD5','\xD5','\xD7',
+'\xD8','\xD9','\xDA','\xDB','\xDC','\xDD','\xDE','\xDF',
+'\xC0','\xC1','\xC2','\xC3','\xC4','\xC5','\xC6','\xC7',
+'\xC8','\xC9','\xCA','\xCB','\xCC','\xCD','\xCE','\xCF',
+'\xD0','\xD1','\xD2','\xD3','\xD4','\xD5','\xD6','\xD7',
+'\xD8','\xD9','\xDA','\xDB','\xDC','\xDD','\xDE','\xDF'
+};
+
+uchar NEAR sort_order_win1251[]={
+'\0', '\x1', '\x2', '\x3', '\x4', '\x5', '\x6', '\x7',
+'\x8', '\x9', '\xA', '\xB', '\xC', '\xD', '\xE', '\xF',
+'\x10','\x11','\x12','\x13','\x14','\x15','\x16','\x17',
+'\x18','\x19','\x1A','\x1B','\x1C','\x1D','\x1E','\x1F',
+' ', '!', '"', '#', '$', '%', '&', '\'',
+'(', ')', '*', '+', ',', '-', '.', '/',
+'0', '1', '2', '3', '4', '5', '6', '7',
+'8', '9', ':', ';', '<', '=', '>', '?',
+'@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+'X', 'Y', 'Z', '[', '\\', ']', '^', '_',
+'`', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+'X', 'Y', 'Z', '{', '|', '}', '~', '\x7F',
+'\x80','\x81','\x82','\x83','\x84','\x85','\x86','\x87',
+'\x88','\x89','\x8A','\x8B','\x8C','\x8D','\x8E','\x8F',
+'\x90','\x91','\x92','\x93','\x94','\x95','\x96','\x97',
+'\x98','\x99','\x9A','\x9B','\x9C','\x9D','\x9E','\x9F',
+'\xA0','\xA1','\xA2','\xA3','\xA4','\xA5','\xA6','\xA7',
+'\xC6','\xA9','\xAA','\xAB','\xAC','\xAD','\xAE','\xAF',
+'\xB0','\xB1','\xB2','\xB3','\xB4','\xB5','\xB6','\xB7',
+'\xC6','\xB9','\xBA','\xBB','\xBC','\xBD','\xBE','\xBF',
+'\xC0','\xC1','\xC2','\xC3','\xC4','\xC5','\xC7','\xC8',
+'\xC9','\xCA','\xCB','\xCC','\xCD','\xCE','\xCF','\xD0',
+'\xD1','\xD2','\xD3','\xD4','\xD5','\xD6','\xD7','\xD8',
+'\xD9','\xDA','\xDB','\xDC','\xDD','\xDE','\xDF','\xE0',
+'\xC0','\xC1','\xC2','\xC3','\xC4','\xC5','\xC7','\xC8',
+'\xC9','\xCA','\xCB','\xCC','\xCD','\xCE','\xCF','\xD0',
+'\xD1','\xD2','\xD3','\xD4','\xD5','\xD6','\xD7','\xD8',
+'\xD9','\xDA','\xDB','\xDC','\xDD','\xDE','\xDF','\xE0'
+};
+
diff --git a/strings/Attic/ctype-win1251ukr.c b/strings/Attic/ctype-win1251ukr.c
new file mode 100644
index 00000000000..ae33e04f38f
--- /dev/null
+++ b/strings/Attic/ctype-win1251ukr.c
@@ -0,0 +1,142 @@
+//Created by Max Veremayenko (verem@tg.kiev.ua)
+//As standart for ukranian font i use ukrainian for window95
+
+#include <global.h>
+#include "m_string.h"
+
+uchar NEAR ctype_win1251ukr[257] = {
+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,
+(uchar)'\20',(uchar)'\20',(uchar)'\20',(uchar)'\20',(uchar)'\20',(uchar)'\20',(uchar)'\20',(uchar)'\20',
+(uchar)'\20',(uchar)'\20',(uchar)'\20',(uchar)'\20',(uchar)'\20',(uchar)'\20',(uchar)'\20',(uchar)'\20',
+(uchar)'\20',(uchar)'\20',(uchar)'\20',(uchar)'\20',(uchar)'\20',(uchar)'\20',(uchar)'\20',(uchar)'\20',
+(uchar)'\20',(uchar)'\20',(uchar)'\20',(uchar)'\20',(uchar)'\20',(uchar)'\20',(uchar)'\20',(uchar)'\20',
+(uchar)'\20',(uchar)'\20',(uchar)'\20',(uchar)'\20',(uchar)'\20',(uchar)'\1',(uchar)'\20',(uchar)'\20',
+(uchar)'\1',(uchar)'\20',(uchar)'\1',(uchar)'\20',(uchar)'\20',(uchar)'\20',(uchar)'\20',(uchar)'\1',
+(uchar)'\20',(uchar)'\20',(uchar)'\1',(uchar)'\2',(uchar)'\2',(uchar)'\20',(uchar)'\20',(uchar)'\20',
+(uchar)'\2',(uchar)'\20',(uchar)'\2',(uchar)'\20',(uchar)'\20',(uchar)'\20',(uchar)'\20',(uchar)'\2',
+(uchar)'\1',(uchar)'\1',(uchar)'\1',(uchar)'\1',(uchar)'\1',(uchar)'\1',(uchar)'\1',(uchar)'\1',
+(uchar)'\1',(uchar)'\1',(uchar)'\1',(uchar)'\1',(uchar)'\1',(uchar)'\1',(uchar)'\1',(uchar)'\1',
+(uchar)'\1',(uchar)'\1',(uchar)'\1',(uchar)'\1',(uchar)'\1',(uchar)'\1',(uchar)'\1',(uchar)'\1',
+(uchar)'\1',(uchar)'\1',(uchar)'\1',(uchar)'\1',(uchar)'\1',(uchar)'\1',(uchar)'\1',(uchar)'\1',
+(uchar)'\2',(uchar)'\2',(uchar)'\2',(uchar)'\2',(uchar)'\2',(uchar)'\2',(uchar)'\2',(uchar)'\2',
+(uchar)'\2',(uchar)'\2',(uchar)'\2',(uchar)'\2',(uchar)'\2',(uchar)'\2',(uchar)'\2',(uchar)'\2',
+(uchar)'\2',(uchar)'\2',(uchar)'\2',(uchar)'\2',(uchar)'\2',(uchar)'\2',(uchar)'\2',(uchar)'\2',
+(uchar)'\2',(uchar)'\2',(uchar)'\2',(uchar)'\2',(uchar)'\2',(uchar)'\2',(uchar)'\2',(uchar)'\2',
+};
+
+uchar NEAR to_lower_win1251ukr[] = {
+'\000','\001','\002','\003','\004','\005','\006','\007',
+'\010','\011','\012','\013','\014','\015','\016','\017',
+'\020','\021','\022','\023','\024','\025','\026','\027',
+'\030','\031','\032','\033','\034','\035','\036','\037',
+' ', '!', '"', '#', '$', '%', '&', '\'',
+'(', ')', '*', '+', ',', '-', '.', '/',
+'0', '1', '2', '3', '4', '5', '6', '7',
+'8', '9', ':', ';', '<', '=', '>', '?',
+'@', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
+'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
+'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
+'x', 'y', 'z', '[', '\\', ']', '^', '_',
+' ', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
+'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
+'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
+'x', 'y', 'z', '{', '|', '}', '~', '\177',
+
+(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\40',
+(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\40',
+(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\40',
+(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\40',
+(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\245',(uchar)'\40',(uchar)'\40',
+(uchar)'\250',(uchar)'\40',(uchar)'\252',(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\257',
+(uchar)'\40',(uchar)'\40',(uchar)'\262',(uchar)'\262',(uchar)'\245',(uchar)'\40',(uchar)'\40',(uchar)'\40',
+(uchar)'\250',(uchar)'\40',(uchar)'\252',(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\257',
+(uchar)'\300',(uchar)'\301',(uchar)'\302',(uchar)'\303',(uchar)'\304',(uchar)'\305',(uchar)'\306',(uchar)'\307',
+(uchar)'\310',(uchar)'\311',(uchar)'\312',(uchar)'\313',(uchar)'\314',(uchar)'\315',(uchar)'\316',(uchar)'\317',
+(uchar)'\320',(uchar)'\321',(uchar)'\322',(uchar)'\323',(uchar)'\324',(uchar)'\325',(uchar)'\326',(uchar)'\327',
+(uchar)'\330',(uchar)'\331',(uchar)'\332',(uchar)'\333',(uchar)'\334',(uchar)'\335',(uchar)'\336',(uchar)'\337',
+(uchar)'\300',(uchar)'\301',(uchar)'\302',(uchar)'\303',(uchar)'\304',(uchar)'\305',(uchar)'\306',(uchar)'\307',
+(uchar)'\310',(uchar)'\311',(uchar)'\312',(uchar)'\313',(uchar)'\314',(uchar)'\315',(uchar)'\316',(uchar)'\317',
+(uchar)'\320',(uchar)'\321',(uchar)'\322',(uchar)'\323',(uchar)'\324',(uchar)'\325',(uchar)'\326',(uchar)'\327',
+(uchar)'\330',(uchar)'\331',(uchar)'\332',(uchar)'\333',(uchar)'\334',(uchar)'\335',(uchar)'\336',(uchar)'\337',
+};
+
+uchar NEAR to_upper_win1251ukr[] = {
+'\000','\001','\002','\003','\004','\005','\006','\007',
+'\010','\011','\012','\013','\014','\015','\016','\017',
+'\020','\021','\022','\023','\024','\025','\026','\027',
+'\030','\031','\032','\033','\034','\035','\036','\037',
+' ', '!', '"', '#', '$', '%', '&', '\'',
+'(', ')', '*', '+', ',', '-', '.', '/',
+'0', '1', '2', '3', '4', '5', '6', '7',
+'8', '9', ':', ';', '<', '=', '>', '?',
+'@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+'X', 'Y', 'Z', '[', '\\', ']', '^', '_',
+' ', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+'X', 'Y', 'Z', '{', '|', '}', '~', '\177',
+
+(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\40',
+(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\40',
+(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\40',
+(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\40',
+(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\264',(uchar)'\40',(uchar)'\40',
+(uchar)'\270',(uchar)'\40',(uchar)'\272',(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\277',
+(uchar)'\40',(uchar)'\40',(uchar)'\263',(uchar)'\263',(uchar)'\264',(uchar)'\40',(uchar)'\40',(uchar)'\40',
+(uchar)'\270',(uchar)'\40',(uchar)'\272',(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\40',(uchar)'\277',
+(uchar)'\340',(uchar)'\341',(uchar)'\342',(uchar)'\343',(uchar)'\344',(uchar)'\345',(uchar)'\346',(uchar)'\347',
+(uchar)'\350',(uchar)'\351',(uchar)'\352',(uchar)'\353',(uchar)'\354',(uchar)'\355',(uchar)'\356',(uchar)'\357',
+(uchar)'\360',(uchar)'\361',(uchar)'\362',(uchar)'\363',(uchar)'\364',(uchar)'\365',(uchar)'\366',(uchar)'\367',
+(uchar)'\370',(uchar)'\371',(uchar)'\372',(uchar)'\373',(uchar)'\374',(uchar)'\375',(uchar)'\376',(uchar)'\377',
+(uchar)'\340',(uchar)'\341',(uchar)'\342',(uchar)'\343',(uchar)'\344',(uchar)'\345',(uchar)'\346',(uchar)'\347',
+(uchar)'\350',(uchar)'\351',(uchar)'\352',(uchar)'\353',(uchar)'\354',(uchar)'\355',(uchar)'\356',(uchar)'\357',
+(uchar)'\360',(uchar)'\361',(uchar)'\362',(uchar)'\363',(uchar)'\364',(uchar)'\365',(uchar)'\366',(uchar)'\367',
+(uchar)'\370',(uchar)'\371',(uchar)'\372',(uchar)'\373',(uchar)'\374',(uchar)'\375',(uchar)'\376',(uchar)'\377',
+};
+
+uchar NEAR sort_order_win1251ukr[] = {
+'\000','\001','\002','\003','\004','\005','\006','\007',
+'\010','\011','\012','\013','\014','\015','\016','\017',
+'\020','\021','\022','\023','\024','\025','\026','\027',
+'\030','\031','\032','\033','\034','\035','\036','\037',
+' ', '!', '"', '#', '$', '%', '&', '\'',
+'(', ')', '*', '+', ',', '-', '.', '/',
+'0', '1', '2', '3', '4', '5', '6', '7',
+'8', '9', ':', ';', '<', '=', '>', '?',
+'@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+'X', 'Y', 'Z', '[', '\\', ']', '^', '_',
+' ', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+'X', 'Y', 'Z', '{', '|', '}', '~', '\177',
+
+(uchar)'\245',(uchar)'\246',(uchar)'\247',(uchar)'\250',(uchar)'\251',(uchar)'\252',(uchar)'\253',(uchar)'\254',
+(uchar)'\255',(uchar)'\256',(uchar)'\257',(uchar)'\260',(uchar)'\261',(uchar)'\262',(uchar)'\263',(uchar)'\264',
+(uchar)'\265',(uchar)'\266',(uchar)'\267',(uchar)'\270',(uchar)'\271',(uchar)'\272',(uchar)'\273',(uchar)'\274',
+(uchar)'\275',(uchar)'\276',(uchar)'\277',(uchar)'\300',(uchar)'\301',(uchar)'\302',(uchar)'\303',(uchar)'\304',
+(uchar)'\305',(uchar)'\306',(uchar)'\307',(uchar)'\310',(uchar)'\311',(uchar)'\204',(uchar)'\312',(uchar)'\313',
+(uchar)'\210',(uchar)'\314',(uchar)'\207',(uchar)'\315',(uchar)'\316',(uchar)'\317',(uchar)'\320',(uchar)'\215',
+(uchar)'\321',(uchar)'\322',(uchar)'\214',(uchar)'\214',(uchar)'\204',(uchar)'\323',(uchar)'\324',(uchar)'\325',
+(uchar)'\210',(uchar)'\326',(uchar)'\207',(uchar)'\327',(uchar)'\330',(uchar)'\331',(uchar)'\332',(uchar)'\215',
+(uchar)'\200',(uchar)'\201',(uchar)'\202',(uchar)'\203',(uchar)'\205',(uchar)'\206',(uchar)'\211',(uchar)'\212',
+(uchar)'\213',(uchar)'\216',(uchar)'\217',(uchar)'\220',(uchar)'\221',(uchar)'\222',(uchar)'\223',(uchar)'\224',
+(uchar)'\225',(uchar)'\226',(uchar)'\227',(uchar)'\230',(uchar)'\231',(uchar)'\232',(uchar)'\233',(uchar)'\234',
+(uchar)'\235',(uchar)'\236',(uchar)'\237',(uchar)'\240',(uchar)'\241',(uchar)'\242',(uchar)'\243',(uchar)'\244',
+(uchar)'\200',(uchar)'\201',(uchar)'\202',(uchar)'\203',(uchar)'\205',(uchar)'\206',(uchar)'\211',(uchar)'\212',
+(uchar)'\213',(uchar)'\216',(uchar)'\217',(uchar)'\220',(uchar)'\221',(uchar)'\222',(uchar)'\223',(uchar)'\224',
+(uchar)'\225',(uchar)'\226',(uchar)'\227',(uchar)'\230',(uchar)'\231',(uchar)'\232',(uchar)'\233',(uchar)'\234',
+(uchar)'\235',(uchar)'\236',(uchar)'\237',(uchar)'\240',(uchar)'\241',(uchar)'\242',(uchar)'\243',(uchar)'\244',
+
+};
diff --git a/strings/Attic/ctype.c.in b/strings/Attic/ctype.c.in
new file mode 100644
index 00000000000..2a76246a03a
--- /dev/null
+++ b/strings/Attic/ctype.c.in
@@ -0,0 +1,20 @@
+#include <global.h>
+#include <m_ctype.h>
+
+@CHARSET_DECLARATIONS@
+
+static CHARSET_INFO comp_cs[] = {
+@CHARSET_COMP_CS_INIT@
+};
+
+CHARSET_INFO *default_charset_info = &comp_cs[0];
+
+CHARSET_INFO *find_compiled_charset(uint8 cs_number)
+{
+ uint i;
+ for (i = 0; i < array_elements(comp_cs); ++i)
+ if (comp_cs[i].number == cs_number)
+ return &comp_cs[i];
+
+ return NULL;
+}
diff --git a/strings/Attic/memory.h b/strings/Attic/memory.h
new file mode 100644
index 00000000000..9b959336caf
--- /dev/null
+++ b/strings/Attic/memory.h
@@ -0,0 +1,33 @@
+/* File : memory.h
+ Author : Richard A. O'Keefe.
+ Updated: 1 June 1984
+ Purpose: Header file for the System V "memory(3C)" package.
+
+ All the functions in this package are the original work of Richard
+ A. O'Keefe. Any resemblance between them and any functions in AT&T
+ or other licensed software is due entirely to my use of the System V
+ memory(3C) manual page as a specification. See the READ-ME to find
+ the conditions under which this material may be used and copied.
+
+ The System V manual says that the mem* functions are declared in the
+ <memory.h> file. This file is also included in the <strings.h> file,
+ but it does no harm to #include both in either order.
+*/
+
+#ifndef DGUX
+#ifndef memeql
+
+#define memeql !memcmp
+extern int memcmp(/*char^,char^,int*/);
+#ifndef memcpy
+extern char *memcpy(/*char^,char^,int*/);
+#endif
+extern char *memccpy(/*char^,char^,char,int*/);
+extern char *memset(/*char^,char,int*/);
+extern char *memchr(/*char^,char,int*/);
+extern char *memrchr(/*char^,char,int*/);
+extern char *memmov(/*char^,char^,int*/);
+extern void memrev(/*char^,char^,int*/);
+
+#endif /* memeql */
+#endif
diff --git a/strings/Attic/ptr_cmp.c b/strings/Attic/ptr_cmp.c
new file mode 100644
index 00000000000..d3d4a36a054
--- /dev/null
+++ b/strings/Attic/ptr_cmp.c
@@ -0,0 +1,151 @@
+/*
+ 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 <global.h>
+#include "m_string.h"
+
+static int ptr_compare(uchar **a, uchar **b);
+static int ptr_compare_0(uchar **a, uchar **b);
+static int ptr_compare_1(uchar **a, uchar **b);
+static int ptr_compare_2(uchar **a, uchar **b);
+static int ptr_compare_3(uchar **a, uchar **b);
+
+#ifdef THREAD
+#include <my_pthread.h>
+#define compare_length my_thread_var->cmp_length
+#else
+static uint compare_length;
+#endif
+
+ /* Get a pointer to a optimal byte-compare function for a given size */
+
+qsort_cmp get_ptr_compare (uint size)
+{
+ compare_length=size; /* Remember for loop */
+
+ if (size < 4)
+ return (qsort_cmp) ptr_compare;
+ switch (size & 3) {
+ case 0: return (qsort_cmp) ptr_compare_0;
+ case 1: return (qsort_cmp) ptr_compare_1;
+ case 2: return (qsort_cmp) ptr_compare_2;
+ case 3: return (qsort_cmp) ptr_compare_3;
+ }
+ return 0; /* Impossible */
+}
+
+
+ /*
+ Compare to keys to see witch is smaller.
+ Loop unrolled to make it quick !!
+ */
+
+#define cmp(N) if (first[N] != last[N]) return (int) first[N] - (int) last[N]
+
+static int ptr_compare(uchar **a, uchar **b)
+{
+ reg3 int length= compare_length;
+ reg1 uchar *first,*last;
+
+ first= *a; last= *b;
+ while (--length)
+ {
+ if (*first++ != *last++)
+ return (int) first[-1] - (int) last[-1];
+ }
+ return (int) first[0] - (int) last[0];
+}
+
+
+static int ptr_compare_0(uchar **a, uchar **b)
+{
+ reg3 int length= compare_length;
+ reg1 uchar *first,*last;
+
+ first= *a; last= *b;
+ loop:
+ cmp(0);
+ cmp(1);
+ cmp(2);
+ cmp(3);
+ if ((length-=4))
+ {
+ first+=4;
+ last+=4;
+ goto loop;
+ }
+ return (0);
+}
+
+
+static int ptr_compare_1(uchar **a, uchar **b)
+{
+ reg3 int length= compare_length-1;
+ reg1 uchar *first,*last;
+
+ first= *a+1; last= *b+1;
+ cmp(-1);
+ loop:
+ cmp(0);
+ cmp(1);
+ cmp(2);
+ cmp(3);
+ if ((length-=4))
+ {
+ first+=4;
+ last+=4;
+ goto loop;
+ }
+ return (0);
+}
+
+static int ptr_compare_2(uchar **a, uchar **b)
+{
+ reg3 int length= compare_length-2;
+ reg1 uchar *first,*last;
+
+ first= *a +2 ; last= *b +2;
+ cmp(-2);
+ cmp(-1);
+ loop:
+ cmp(0);
+ cmp(1);
+ cmp(2);
+ cmp(3);
+ if ((length-=4))
+ {
+ first+=4;
+ last+=4;
+ goto loop;
+ }
+ return (0);
+}
+
+static int ptr_compare_3(uchar **a, uchar **b)
+{
+ reg3 int length= compare_length-3;
+ reg1 uchar *first,*last;
+
+ first= *a +3 ; last= *b +3;
+ cmp(-3);
+ cmp(-2);
+ cmp(-1);
+ loop:
+ cmp(0);
+ cmp(1);
+ cmp(2);
+ cmp(3);
+ if ((length-=4))
+ {
+ first+=4;
+ last+=4;
+ goto loop;
+ }
+ return (0);
+}
diff --git a/strings/ChangeLog b/strings/ChangeLog
new file mode 100755
index 00000000000..2d31f2946a1
--- /dev/null
+++ b/strings/ChangeLog
@@ -0,0 +1,38 @@
+Thu May 20 13:45:15 1993 Michael Widenius (monty at bitch)
+
+ * changed itoa() and ltoa() to use the same interface as microsoft:s
+ and zortech:s libraryes.
+
+Sun Mar 24 00:30:34 1991 Michael Widenius (monty at LYNX)
+
+ * Changed int2str to return BIG converted chars.
+
+Sun Feb 24 00:22:54 1991 Michael Widenius (monty at LYNX)
+
+ * Added new function strcend(string,char). Its eqvialent to
+ if (!(a=strchr(string,char)))
+ a=strend(string);
+
+Tue Oct 16 18:53:19 1990 Michael Widenius (monty at LYNX)
+
+ * Added define BAD_STRING_COMPILER to set define strmov()
+ if compiler is very bad at stringoperations.
+ * Changed to use cc on sun-systems instead of gcc.
+
+Sat Sep 29 18:42:31 1990 Michael Widenius (monty at LYNX)
+
+ * Added my_atof for sparc system to get some speed.
+
+Sun Mar 11 16:35:59 1990 Monty (monty at monty)
+
+ * strnmov() was changed to not fill to-string with null.
+ * strmake() changed to point at closing null.
+
+Wed Feb 7 20:15:34 1990 David Axmark (davida at isil)
+
+ * Made functon strinrstr that is reverse search.
+
+Fri Dec 2 03:37:59 1988 Monty (monty at monty)
+
+ * Fixed bug in strcont; It didn't return first found character in
+ set.
diff --git a/strings/Makefile.am b/strings/Makefile.am
new file mode 100644
index 00000000000..0c71356823c
--- /dev/null
+++ b/strings/Makefile.am
@@ -0,0 +1,84 @@
+# Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public 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 public domain and comes with NO WARRANTY of any kind
+
+INCLUDES = @MT_INCLUDES@ -I$(srcdir)/../include -I../include
+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
+else
+if ASSEMBLER_sparc
+# These file MUST all be on the same line!! Otherwise automake
+# generats a very broken makefile
+ASRCS = bmove_upp-sparc.s strappend-sparc.s strend-sparc.s strinstr-sparc.s strmake-sparc.s strmov-sparc.s strnmov-sparc.s strstr-sparc.s strxmov-sparc.s
+CSRCS = strcont.c strfill.c strcend.c is_prefix.c longlong2str.c bfill.c bmove.c bmove512.c bchange.c strxnmov.c int2str.c str2int.c r_strinstr.c atof.c bcmp.c strtol.c strtoul.c strtoll.c strtoull.c llstr.c ctype.c strnlen.c
+else
+#no assembler
+ASRCS =
+# These file MUST all be on the same line!! Otherwise automake
+# generats a very broken makefile
+CSRCS = strxmov.c bmove_upp.c strappend.c strcont.c strend.c strfill.c strcend.c is_prefix.c strstr.c strinstr.c strmake.c strnmov.c strmov.c longlong2str.c bfill.c bmove.c bmove512.c bchange.c strxnmov.c int2str.c str2int.c r_strinstr.c atof.c bcmp.c strtol.c strtoul.c strtoll.c strtoull.c llstr.c ctype.c strnlen.c
+endif
+endif
+
+libmystrings_a_SOURCES = @CHARSET_SRCS@ $(ASRCS) $(CSRCS)
+
+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_autoconf.c \
+ strto.c strings-x86.s longlong2str-x86.s \
+ 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 strnlen.c \
+ bmove_upp-sparc.s strappend-sparc.s strend-sparc.s \
+ strinstr-sparc.s strmake-sparc.s strmov-sparc.s \
+ strnmov-sparc.s strstr-sparc.s strxmov-sparc.s
+
+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
+
+libmystrings_a_LIBADD= @CHARSET_OBJS@
+ctype.c: ctype_extra_sources.c
+ctype_extra_sources.c: conf_to_src
+ ./conf_to_src $(top_srcdir) @CHARSETS_NEED_SOURCE@ > \
+ $(srcdir)/ctype_extra_sources.c
+conf_to_src_SOURCES = conf_to_src.c
+conf_to_src_LDADD=
+
+# This is because the dependency tracking misses @FOO@ vars in sources.
+strtoull.o: @CHARSET_OBJS@
+
+clean-local:
+ rm -f ctype_extra_sources.c
+
+if ASSEMBLER
+# On Linux gcc can compile the assembly files
+%.o : %.s
+ $(AS) -o $@ $<
+endif
diff --git a/strings/READ-ME b/strings/READ-ME
new file mode 100644
index 00000000000..a8b8c54ab0a
--- /dev/null
+++ b/strings/READ-ME
@@ -0,0 +1,82 @@
+File : READ-ME
+Author : Richard A. O'Keefe.
+Updated: 30 April 1984
+Purpose: Explain the new strings package.
+
+ The UNIX string libraries (described in the string(3) manual page)
+differ from UNIX to UNIX (e.g. strtok is not in V7 or 4.1bsd). Worse,
+the sources are not in the public domain, so that if there is a string
+routine which is nearly what you want but not quite you can't take a
+copy and modify it. And of course C programmers on non-UNIX systems
+are at the mercy of their supplier.
+
+ This package was designed to let me do reasonable things with C's
+strings whatever UNIX (V7, PaNiX, UX63, 4.1bsd) I happen to be using.
+Everything in the System III manual is here and does just what the S3
+manual says it does. There are also lots of new goodies. I'm sorry
+about the names, but the routines do have to work on asphyxiated-at-
+birth systems which truncate identifiers. The convention is that a
+routine is called
+ str [n] [c] <operation>
+If there is an "n", it means that the function takes an (int) "length"
+argument, which bounds the number of characters to be moved or looked
+at. If the function has a "set" argument, a "c" in the name indicates
+that the complement of the set is used. Functions or variables whose
+names start with _ are support routines which aren't really meant for
+general use. I don't know what the "p" is doing in "strpbrk", but it
+is there in the S3 manual so it's here too. "istrtok" does not follow
+this rule, but with 7 letters what can you do?
+
+ I have included new versions of atoi(3) and atol(3) as well. They
+use a new primitive str2int, which takes a pair of bounds and a radix,
+and does much more thorough checking than the normal atoi and atol do.
+The result returned by atoi & atol is valid if and only if errno == 0.
+There is also an output conversion routine int2str, with itoa and ltoa
+as interface macros. Only after writing int2str did I notice that the
+str2int routine has no provision for unsigned numbers. On reflection,
+I don't greatly care. I'm afraid that int2str may depend on your "C"
+compiler in unexpected ways. Do check the code with -S.
+
+ Several of these routines have "asm" inclusions conditional on the
+VaxAsm option. These insertions can make the routines which have them
+quite a bit faster, but there is a snag. The VAX architects, for some
+reason best known to themselves and their therapists, decided that all
+"strings" were shorter than 2^16 bytes. Even when the length operands
+are in 32-bit registers, only 16 bits count. So the "asm" versions do
+not work for long strings. If you can guarantee that all your strings
+will be short, define VaxAsm in the makefile, but in general, and when
+using other machines, do not define it.
+
+ To use this library, you need the "strings.a" library file and the
+"strings.h" and "ctypes.h" header files. The other header files are
+for compiling the library itself, though if you are hacking extensions
+you may find them useful. General users really shouldn't see them.
+I've defined a few macros I find useful in "strings.h"; if you have no
+need for "index", "rindex", "streql", and "beql", just edit them out.
+On the 4.1bsd system I am using declaring all these functions 'extern'
+does not mean that they will all be loaded; but only the ones you use.
+When using lesser systems you may find it necessary to break strings.h
+up, or you could get by with just adding "extern" declarations for the
+functions you want as you need them. Many of these functions have the
+same names as functions in the "standard C library", by design as this
+is a replacement/reimplementation of part of that library. So you may
+have to talk the loader into loading this library first. Again, I've
+found no problems on 4.1bsd.
+
+ You may wonder at my failure to provide manual pages for this code.
+For the things in V7, 4.?, or SIII, you should be able to use whichever
+manual page came with that system, and anything I might write would be
+so like it as to raise suspicions of violating AT&T copyrights. In the
+sources you will find comments which provide far more documentation for
+these routines than AT&T ever provided for their strings stuff, I just
+don't happen to have put it in nroff -man form. Had I done so, the .3
+files would have outbulked the .c files!
+
+ These files are in the public domain. This includes getopt.c, which
+is the work of Henry Spencer, University of Toronto Zoology, who says of
+it "None of this software is derived from Bell software. I had no access
+to the source for Bell's versions at the time I wrote it. This software
+is hereby explicitly placed in the public domain. It may be used for
+any purpose on any machine by anyone." I would greatly prefer it if *my*
+material received no military use.
+
diff --git a/strings/README b/strings/README
new file mode 100644
index 00000000000..ddb811ede5e
--- /dev/null
+++ b/strings/README
@@ -0,0 +1,82 @@
+File : README
+Author : Richard A. O'Keefe.
+Updated: 30 April 1984
+Purpose: Explain the new strings package.
+
+ The UNIX string libraries (described in the string(3) manual page)
+differ from UNIX to UNIX (e.g. strtok is not in V7 or 4.1bsd). Worse,
+the sources are not in the public domain, so that if there is a string
+routine which is nearly what you want but not quite you can't take a
+copy and modify it. And of course C programmers on non-UNIX systems
+are at the mercy of their supplier.
+
+ This package was designed to let me do reasonable things with C's
+strings whatever UNIX (V7, PaNiX, UX63, 4.1bsd) I happen to be using.
+Everything in the System III manual is here and does just what the S3
+manual says it does. There are also lots of new goodies. I'm sorry
+about the names, but the routines do have to work on asphyxiated-at-
+birth systems which truncate identifiers. The convention is that a
+routine is called
+ str [n] [c] <operation>
+If there is an "n", it means that the function takes an (int) "length"
+argument, which bounds the number of characters to be moved or looked
+at. If the function has a "set" argument, a "c" in the name indicates
+that the complement of the set is used. Functions or variables whose
+names start with _ are support routines which aren't really meant for
+general use. I don't know what the "p" is doing in "strpbrk", but it
+is there in the S3 manual so it's here too. "istrtok" does not follow
+this rule, but with 7 letters what can you do?
+
+ I have included new versions of atoi(3) and atol(3) as well. They
+use a new primitive str2int, which takes a pair of bounds and a radix,
+and does much more thorough checking than the normal atoi and atol do.
+The result returned by atoi & atol is valid if and only if errno == 0.
+There is also an output conversion routine int2str, with itoa and ltoa
+as interface macros. Only after writing int2str did I notice that the
+str2int routine has no provision for unsigned numbers. On reflection,
+I don't greatly care. I'm afraid that int2str may depend on your "C"
+compiler in unexpected ways. Do check the code with -S.
+
+ Several of these routines have "asm" inclusions conditional on the
+VaxAsm option. These insertions can make the routines which have them
+quite a bit faster, but there is a snag. The VAX architects, for some
+reason best known to themselves and their therapists, decided that all
+"strings" were shorter than 2^16 bytes. Even when the length operands
+are in 32-bit registers, only 16 bits count. So the "asm" versions do
+not work for long strings. If you can guarantee that all your strings
+will be short, define VaxAsm in the makefile, but in general, and when
+using other machines, do not define it.
+
+ To use this library, you need the "strings.a" library file and the
+"strings.h" and "ctypes.h" header files. The other header files are
+for compiling the library itself, though if you are hacking extensions
+you may find them useful. General users really shouldn't see them.
+I've defined a few macros I find useful in "strings.h"; if you have no
+need for "index", "rindex", "streql", and "beql", just edit them out.
+On the 4.1bsd system I am using declaring all these functions 'extern'
+does not mean that they will all be loaded; but only the ones you use.
+When using lesser systems you may find it necessary to break strings.h
+up, or you could get by with just adding "extern" declarations for the
+functions you want as you need them. Many of these functions have the
+same names as functions in the "standard C library", by design as this
+is a replacement/reimplementation of part of that library. So you may
+have to talk the loader into loading this library first. Again, I've
+found no problems on 4.1bsd.
+
+ You may wonder at my failure to provide manual pages for this code.
+For the things in V7, 4.?, or SIII, you should be able to use whichever
+manual page came with that system, and anything I might write would be
+so like it as to raise suspicions of violating AT&T copyrights. In the
+sources you will find comments which provide far more documentation for
+these routines than AT&T ever provided for their strings stuff, I just
+don't happen to have put it in nroff -man form. Had I done so, the .3
+files would have outbulked the .c files!
+
+ These files are in the public domain. This includes getopt.c, which
+is the work of Henry Spencer, University of Toronto Zoology, who says of
+it "None of this software is derived from Bell software. I had no access
+to the source for Bell's versions at the time I wrote it. This software
+is hereby explicitly placed in the public domain. It may be used for
+any purpose on any machine by anyone." I would greatly prefer it if *my*
+material received no military use.
+
diff --git a/strings/atof.c b/strings/atof.c
new file mode 100644
index 00000000000..1ce16027089
--- /dev/null
+++ b/strings/atof.c
@@ -0,0 +1,208 @@
+/* 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 */
+
+/*
+ A quicker atof. About 2-10 times faster than standard atof on sparc.
+ This don't handle iee-options (NaN...) and the presission :s is a little
+ less for some high exponential numbers (+-1 at 14th place).
+ Returns 0.0 if overflow or wrong number.
+ Must be inited with init_my_atof to handle possibly overflows.
+*/
+
+#include <global.h>
+#ifdef USE_MY_ATOF /* Skipp if we don't want it */
+#include <m_ctype.h>
+#include <floatingpoint.h>
+#include <signal.h>
+
+/* Read a double. If float is wrong return 0.
+ float ::= [space]* [sign] {digit}+ decimal-point {digit}+ [exponent] |
+ [sign] {digit}+ [decimal-point {digit}*] exponent |
+ [sign] {digit}+ decimal-point [{digit}*] exponent |
+ [sign] decimal-point {digit}* exponent |
+ exponent :: = exponent-marker [sign] {digit}+
+ exponent-marker ::= E e
+ */
+
+
+#define is_exponent_marker(ch) (ch == 'E' || ch == 'e')
+
+static void my_atof_overflow _A((int sig,int code, struct sigcontext *scp,
+ char *addr));
+static int parse_sign _A((char **str));
+static void parse_float_number_part _A((char **str,double *number, int *length));
+static void parse_decimal_number_part _A((char **str,double *number));
+static int parse_int_number_part _A((char **str,uint *number));
+
+static int volatile overflow,in_my_atof;
+static sigfpe_handler_type old_overflow_handler;
+
+void init_my_atof()
+{
+ old_overflow_handler = (sigfpe_handler_type)
+ ieee_handler("get", "overflow", old_overflow_handler);
+ VOID(ieee_handler("set", "overflow", my_atof_overflow));
+ return;
+}
+
+static void my_atof_overflow(sig, code, scp, addr)
+int sig;
+int code;
+struct sigcontext *scp;
+char *addr;
+{
+ if (!in_my_atof)
+ old_overflow_handler(sig,code,scp,addr);
+ else
+ overflow=1;
+ return;
+}
+
+double my_atof(src)
+const char *src;
+{
+ int sign, exp_sign; /* is number negative (+1) or positive (-1) */
+ int length_before_point;
+ double after_point; /* Number after decimal point and before exp */
+ uint exponent; /* Exponent value */
+ double exp_log,exp_val;
+ char *tmp_src;
+ double result_number;
+
+ tmp_src = (char*) src;
+ while (isspace(tmp_src[0]))
+ tmp_src++; /* Skipp pre-space */
+ sign = parse_sign(&tmp_src);
+ overflow=0;
+ in_my_atof=1;
+ parse_float_number_part(&tmp_src, &result_number, &length_before_point);
+ if (*tmp_src == '.')
+ {
+ tmp_src++;
+ parse_decimal_number_part(&tmp_src, &after_point);
+ result_number += after_point;
+ }
+ else if (length_before_point == 0)
+ {
+ in_my_atof=0;
+ return 0.0;
+ }
+ if (is_exponent_marker(*tmp_src))
+ {
+ tmp_src++;
+ exp_sign = parse_sign(&tmp_src);
+ overflow|=parse_int_number_part(&tmp_src, &exponent);
+
+ exp_log=10.0; exp_val=1.0;
+ for (;;)
+ {
+ if (exponent & 1)
+ {
+ exp_val*= exp_log;
+ exponent--;
+ }
+ if (!exponent)
+ break;
+ exp_log*=exp_log;
+ exponent>>=1;
+ }
+ if (exp_sign < 0)
+ result_number*=exp_val;
+ else
+ result_number/=exp_val;
+ }
+ if (sign > 0)
+ result_number= -result_number;
+
+ in_my_atof=0;
+ if (overflow)
+ return 0.0;
+ return result_number;
+}
+
+
+static int parse_sign(str)
+char **str;
+{
+ if (**str == '-')
+ {
+ (*str)++;
+ return 1;
+ }
+ if (**str == '+')
+ (*str)++;
+ return -1;
+}
+
+ /* Get number with may be separated with ',' */
+
+static void parse_float_number_part(str, number, length)
+char **str;
+double *number;
+int *length;
+{
+ *number = 0;
+ *length = 0;
+
+ for (;;)
+ {
+ while (isdigit(**str))
+ {
+ (*length)++;
+ *number = (*number * 10) + (**str - '0');
+ (*str)++;
+ }
+ if (**str != ',')
+ return; /* Skipp possibly ',' */
+ (*str)++;
+ }
+}
+
+static void parse_decimal_number_part(str, number)
+char **str;
+double *number;
+{
+ double exp_log;
+
+ *number = 0;
+ exp_log=1/10.0;
+ while (isdigit(**str))
+ {
+ *number+= (**str - '0')*exp_log;
+ exp_log/=10;
+ (*str)++;
+ }
+}
+
+ /* Parses int suitably for exponent */
+
+static int parse_int_number_part(str, number)
+char **str;
+uint *number;
+{
+ *number = 0;
+ while (isdigit(**str))
+ {
+ if (*number >= ((uint) ~0)/10)
+ return 1; /* Don't overflow */
+ *number = (*number * 10) + **str - '0';
+ (*str)++;
+ }
+ return 0;
+}
+
+#endif
diff --git a/strings/bchange.c b/strings/bchange.c
new file mode 100644
index 00000000000..99066cf1e95
--- /dev/null
+++ b/strings/bchange.c
@@ -0,0 +1,39 @@
+/* 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 */
+
+/* File : bchange.c
+ Author : Michael widenius
+ Updated: 1987-03-20
+ Defines: bchange()
+
+ bchange(dst, old_length, src, new_length, tot_length)
+ replaces old_length characters at dst to new_length characters from
+ src in a buffer with tot_length bytes.
+*/
+
+#include <global.h>
+#include "m_string.h"
+
+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)
+ bmove_upp(dst+rest+new_length,dst+tot_length,rest);
+ else
+ bmove(dst+new_length,dst+old_length,rest);
+ memcpy(dst,src,new_length);
+}
diff --git a/strings/bcmp.c b/strings/bcmp.c
new file mode 100644
index 00000000000..3dce5025b64
--- /dev/null
+++ b/strings/bcmp.c
@@ -0,0 +1,63 @@
+/* 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 */
+
+/*
+ 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.
+*/
+
+#include <global.h>
+#include "m_string.h"
+
+#if !defined(bcmp) && !defined(HAVE_BCMP)
+
+#if defined(MC68000) && defined(DS90)
+
+int bcmp(s1,s2, len)
+const char *s1;
+const char *s2;
+uint len; /* 0 <= len <= 65535 */
+{
+ asm(" movl 12(a7),d0 ");
+ asm(" subqw #1,d0 ");
+ asm(" blt .L5 ");
+ asm(" movl 4(a7),a1 ");
+ asm(" movl 8(a7),a0 ");
+ asm(".L4: cmpmb (a0)+,(a1)+ ");
+ asm(" dbne d0,.L4 ");
+ asm(".L5: addqw #1,d0 ");
+}
+
+#else
+
+#ifdef HAVE_purify
+int my_bcmp(s1, s2, len)
+#else
+int bcmp(s1, s2, len)
+#endif
+ register const char *s1;
+ register const char *s2;
+ register uint len;
+{
+ while (len-- != 0 && *s1++ == *s2++) ;
+ return len+1;
+}
+
+#endif
+#endif /* BSD_FUNCS */
diff --git a/strings/bcopy-duff.c b/strings/bcopy-duff.c
new file mode 100644
index 00000000000..2f5a709c3a0
--- /dev/null
+++ b/strings/bcopy-duff.c
@@ -0,0 +1,50 @@
+/* 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 */
+
+#define IFACTOR 4
+
+ void
+dcopy(char *chardest, char *charsrc, int size)
+{
+ register int *src, *dest, intcount ;
+ int startcharcpy, intoffset, numints2cpy, i ;
+
+ numints2cpy = size >> 2 ;
+ startcharcpy = numints2cpy << 2 ;
+ intcount = numints2cpy & ~(IFACTOR-1) ;
+ intoffset = numints2cpy - intcount ;
+
+ src = (int *)(((int) charsrc) + intcount*sizeof(int*)) ;
+ dest = (int *)(((int) chardest) + intcount*sizeof(int*)) ;
+
+ /* copy the ints */
+ switch(intoffset)
+ do
+ {
+ case 0: dest[3] = src[3] ;
+ case 3: dest[2] = src[2] ;
+ case 2: dest[1] = src[1] ;
+ case 1: dest[0] = src[0] ;
+ intcount -= IFACTOR ;
+ dest -= IFACTOR ;
+ src -= IFACTOR ;
+ } while (intcount >= 0) ;
+
+ /* copy the chars left over by the int copy at the end */
+ for(i=startcharcpy ; i<size ; i++)
+ chardest[i] = charsrc[i] ;
+}
diff --git a/strings/bfill.c b/strings/bfill.c
new file mode 100644
index 00000000000..ac5d3096b14
--- /dev/null
+++ b/strings/bfill.c
@@ -0,0 +1,81 @@
+/* File : bfill.c
+ Author : Richard A. O'Keefe.
+ Michael Widenius; ifdef MC68000
+ Updated: 23 April 1984
+ Defines: bfill()
+
+ bfill(dst, len, fill) moves "len" fill characters to "dst".
+ Thus to set a buffer to 80 spaces, do bfill(buff, 80, ' ').
+
+ Note: the "b" routines are there to exploit certain VAX order codes,
+ but the MOVC5 instruction will only move 65535 characters. The asm
+ code is presented for your interest and amusement.
+*/
+
+#include <global.h>
+#include "m_string.h"
+
+#if !defined(bfill) && !defined(HAVE_BFILL)
+
+#if VaxAsm
+
+void bfill(dst, len, fill)
+char *dst;
+uint len;
+int fill; /* actually char */
+{
+ asm("movc5 $0,*4(ap),12(ap),8(ap),*4(ap)");
+}
+
+#elif defined(MC68000) && defined(DS90)
+
+void bfill(dst, len,fill) /* Optimized with long-fill */
+char *dst;
+uint len;
+pchar fill;
+{
+asm(" movl 8.(a7),d1 ");
+asm(" jeq .L9 ");
+asm(" movl 4.(a7),a0 ");
+asm(" moveq #0,d0 ");
+asm(" movb 15.(a7),d0 ");
+asm(" movl d2,a1 ");
+asm(" movw d0,d2 ");
+asm(" aslw #8,d0 ");
+asm(" orw d2,d0 ");
+asm(" movl d0,d2 ");
+asm(" swap d0 ");
+asm(" orl d2,d0 ");
+asm(" movl a0,d2 ");
+asm(" btst #0,d2 ");
+asm(" jeq .L1 ");
+asm(" movb d0,(a0)+ ");
+asm(" subql #1,d1 ");
+asm(".L1: movl d1,d2 ");
+asm(" lsrl #2,d2 ");
+asm(" jcc .L2 ");
+asm(" movw d0,(a0)+ ");
+asm(" jra .L2 ");
+asm(".L3: movl d0,(a0)+ ");
+asm(".L2: dbra d2,.L3 ");
+asm(" addqw #1,d2 ");
+asm(" subql #1,d2 ");
+asm(" jcc .L3 ");
+asm(" andl #1,d1 ");
+asm(" jeq .L8 ");
+asm(" movb d0,(a0) ");
+asm(".L8: movl a1,d2 ");
+asm(".L9: rts ");
+}
+#else
+
+void bfill(dst, len, fill)
+register byte *dst;
+register uint len;
+register pchar fill;
+{
+ while (len-- != 0) *dst++ = fill;
+}
+
+#endif
+#endif
diff --git a/strings/bmove.c b/strings/bmove.c
new file mode 100644
index 00000000000..096a6282609
--- /dev/null
+++ b/strings/bmove.c
@@ -0,0 +1,63 @@
+/* File : bmove.c
+ Author : Richard A. O'Keefe.
+ Michael Widenius; ifdef MC68000
+ Updated: 23 April 1984
+ Defines: bmove()
+
+ bmove(dst, src, len) moves exactly "len" bytes from the source "src"
+ to the destination "dst". It does not check for NUL characters as
+ strncpy() and strnmov() do. Thus if your C compiler doesn't support
+ structure assignment, you can simulate it with
+ bmove(&to, &from, sizeof from);
+ The standard 4.2bsd routine for this purpose is bcopy. But as bcopy
+ has its first two arguments the other way around you may find this a
+ bit easier to get right.
+ No value is returned.
+
+ Note: the "b" routines are there to exploit certain VAX order codes,
+ but the MOVC3 instruction will only move 65535 characters. The asm
+ code is presented for your interest and amusement.
+*/
+
+#include <global.h>
+#include "m_string.h"
+
+#if !defined(HAVE_BMOVE) && !defined(bmove)
+
+#if VaxAsm
+
+void bmove(dst, src, len)
+ char *dst, *src;
+ uint len;
+ {
+ asm("movc3 12(ap),*8(ap),*4(ap)");
+ }
+
+#else
+#if defined(MC68000) && defined(DS90)
+
+void bmove(dst, src, len)
+char *dst,*src;
+uint len; /* 0 <= len <= 65535 */
+{
+asm(" movl 12(a7),d0 ");
+asm(" subql #1,d0 ");
+asm(" blt .L5 ");
+asm(" movl 4(a7),a1 ");
+asm(" movl 8(a7),a0 ");
+asm(".L4: movb (a0)+,(a1)+ ");
+asm(" dbf d0,.L4 ");
+asm(".L5: ");
+}
+#else
+
+void bmove(dst, src, len)
+register byte *dst;
+register const char *src;
+register uint len;
+{
+ while (len-- != 0) *dst++ = *src++;
+}
+#endif
+#endif
+#endif
diff --git a/strings/bmove512.c b/strings/bmove512.c
new file mode 100644
index 00000000000..4b0c3f5c1cb
--- /dev/null
+++ b/strings/bmove512.c
@@ -0,0 +1,129 @@
+/* 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 */
+
+/* File : bmove512.c
+ Author : Michael Widenius;
+ Defines: bmove512()
+
+ bmove512(dst, src, len) moves exactly "len" bytes from the source "src"
+ to the destination "dst". "src" and "dst" must be alligned on long
+ boundory and len must be a mutliple of 512 byte. If len is not a
+ multiple of 512 byte len/512*512+1 bytes is copyed.
+ bmove512 is moustly used to copy IO_BLOCKS. bmove512 should be the
+ fastest way to move a mutiple of 512 byte.
+*/
+
+#include <global.h>
+#include "m_string.h"
+
+#ifndef bmove512
+
+#ifdef HAVE_LONG_LONG
+#define LONG ulonglong
+#else
+#define LONG ulonglong
+#endif
+
+void bmove512(register gptr to, register const gptr from, register uint length)
+{
+ reg1 LONG *f,*t;
+ reg3 int len;
+
+ f= (LONG*) from;
+ t= (LONG*) to;
+ len= (int) length;
+
+#if defined(m88k) || defined(sparc) || defined(HAVE_LONG_LONG)
+ do {
+ t[0]=f[0]; t[1]=f[1]; t[2]=f[2]; t[3]=f[3];
+ t[4]=f[4]; t[5]=f[5]; t[6]=f[6]; t[7]=f[7];
+ t[8]=f[8]; t[9]=f[9]; t[10]=f[10]; t[11]=f[11];
+ t[12]=f[12]; t[13]=f[13]; t[14]=f[14]; t[15]=f[15];
+ t[16]=f[16]; t[17]=f[17]; t[18]=f[18]; t[19]=f[19];
+ t[20]=f[20]; t[21]=f[21]; t[22]=f[22]; t[23]=f[23];
+ t[24]=f[24]; t[25]=f[25]; t[26]=f[26]; t[27]=f[27];
+ t[28]=f[28]; t[29]=f[29]; t[30]=f[30]; t[31]=f[31];
+ t[32]=f[32]; t[33]=f[33]; t[34]=f[34]; t[35]=f[35];
+ t[36]=f[36]; t[37]=f[37]; t[38]=f[38]; t[39]=f[39];
+ t[40]=f[40]; t[41]=f[41]; t[42]=f[42]; t[43]=f[43];
+ t[44]=f[44]; t[45]=f[45]; t[46]=f[46]; t[47]=f[47];
+ t[48]=f[48]; t[49]=f[49]; t[50]=f[50]; t[51]=f[51];
+ t[52]=f[52]; t[53]=f[53]; t[54]=f[54]; t[55]=f[55];
+ t[56]=f[56]; t[57]=f[57]; t[58]=f[58]; t[59]=f[59];
+ t[60]=f[60]; t[61]=f[61]; t[62]=f[62]; t[63]=f[63];
+#ifdef HAVE_LONG_LONG
+ t+=64; f+=64;
+#else
+ t[64]=f[64]; t[65]=f[65]; t[66]=f[66]; t[67]=f[67];
+ t[68]=f[68]; t[69]=f[69]; t[70]=f[70]; t[71]=f[71];
+ t[72]=f[72]; t[73]=f[73]; t[74]=f[74]; t[75]=f[75];
+ t[76]=f[76]; t[77]=f[77]; t[78]=f[78]; t[79]=f[79];
+ t[80]=f[80]; t[81]=f[81]; t[82]=f[82]; t[83]=f[83];
+ t[84]=f[84]; t[85]=f[85]; t[86]=f[86]; t[87]=f[87];
+ t[88]=f[88]; t[89]=f[89]; t[90]=f[90]; t[91]=f[91];
+ t[92]=f[92]; t[93]=f[93]; t[94]=f[94]; t[95]=f[95];
+ t[96]=f[96]; t[97]=f[97]; t[98]=f[98]; t[99]=f[99];
+ t[100]=f[100]; t[101]=f[101]; t[102]=f[102]; t[103]=f[103];
+ t[104]=f[104]; t[105]=f[105]; t[106]=f[106]; t[107]=f[107];
+ t[108]=f[108]; t[109]=f[109]; t[110]=f[110]; t[111]=f[111];
+ t[112]=f[112]; t[113]=f[113]; t[114]=f[114]; t[115]=f[115];
+ t[116]=f[116]; t[117]=f[117]; t[118]=f[118]; t[119]=f[119];
+ t[120]=f[120]; t[121]=f[121]; t[122]=f[122]; t[123]=f[123];
+ t[124]=f[124]; t[125]=f[125]; t[126]=f[126]; t[127]=f[127];
+ t+=128; f+=128;
+#endif
+ } while ((len-=512) > 0);
+#else
+ do {
+ *t++ = *f++; *t++ = *f++; *t++ = *f++; *t++ = *f++;
+ *t++ = *f++; *t++ = *f++; *t++ = *f++; *t++ = *f++;
+ *t++ = *f++; *t++ = *f++; *t++ = *f++; *t++ = *f++;
+ *t++ = *f++; *t++ = *f++; *t++ = *f++; *t++ = *f++;
+ *t++ = *f++; *t++ = *f++; *t++ = *f++; *t++ = *f++;
+ *t++ = *f++; *t++ = *f++; *t++ = *f++; *t++ = *f++;
+ *t++ = *f++; *t++ = *f++; *t++ = *f++; *t++ = *f++;
+ *t++ = *f++; *t++ = *f++; *t++ = *f++; *t++ = *f++;
+ *t++ = *f++; *t++ = *f++; *t++ = *f++; *t++ = *f++;
+ *t++ = *f++; *t++ = *f++; *t++ = *f++; *t++ = *f++;
+ *t++ = *f++; *t++ = *f++; *t++ = *f++; *t++ = *f++;
+ *t++ = *f++; *t++ = *f++; *t++ = *f++; *t++ = *f++;
+ *t++ = *f++; *t++ = *f++; *t++ = *f++; *t++ = *f++;
+ *t++ = *f++; *t++ = *f++; *t++ = *f++; *t++ = *f++;
+ *t++ = *f++; *t++ = *f++; *t++ = *f++; *t++ = *f++;
+ *t++ = *f++; *t++ = *f++; *t++ = *f++; *t++ = *f++;
+ *t++ = *f++; *t++ = *f++; *t++ = *f++; *t++ = *f++;
+ *t++ = *f++; *t++ = *f++; *t++ = *f++; *t++ = *f++;
+ *t++ = *f++; *t++ = *f++; *t++ = *f++; *t++ = *f++;
+ *t++ = *f++; *t++ = *f++; *t++ = *f++; *t++ = *f++;
+ *t++ = *f++; *t++ = *f++; *t++ = *f++; *t++ = *f++;
+ *t++ = *f++; *t++ = *f++; *t++ = *f++; *t++ = *f++;
+ *t++ = *f++; *t++ = *f++; *t++ = *f++; *t++ = *f++;
+ *t++ = *f++; *t++ = *f++; *t++ = *f++; *t++ = *f++;
+ *t++ = *f++; *t++ = *f++; *t++ = *f++; *t++ = *f++;
+ *t++ = *f++; *t++ = *f++; *t++ = *f++; *t++ = *f++;
+ *t++ = *f++; *t++ = *f++; *t++ = *f++; *t++ = *f++;
+ *t++ = *f++; *t++ = *f++; *t++ = *f++; *t++ = *f++;
+ *t++ = *f++; *t++ = *f++; *t++ = *f++; *t++ = *f++;
+ *t++ = *f++; *t++ = *f++; *t++ = *f++; *t++ = *f++;
+ *t++ = *f++; *t++ = *f++; *t++ = *f++; *t++ = *f++;
+ *t++ = *f++; *t++ = *f++; *t++ = *f++; *t++ = *f++;
+ } while ((len-=512) > 0);
+#endif
+ return;
+} /* bmove512 */
+
+#endif /* bmove512 */
diff --git a/strings/bmove_upp-sparc.s b/strings/bmove_upp-sparc.s
new file mode 100644
index 00000000000..4fae7f5cc7c
--- /dev/null
+++ b/strings/bmove_upp-sparc.s
@@ -0,0 +1,40 @@
+! 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
+
+ .file "bmove_upp-sparc.s"
+.section ".text"
+ .align 4
+ .global bmove_upp
+ .type bmove_upp,#function
+ .proc 020
+bmove_upp:
+ subcc %o2, 1, %o2 ! o2= len
+ bcs .end
+ nop
+.loop:
+ sub %o1, 1, %o1
+ ldub [%o1], %g2
+ sub %o0, 1, %o0
+ subcc %o2, 1, %o2
+ bcc .loop
+ stb %g2, [%o0]
+.end:
+ retl
+ nop
+.bmove_upp_end:
+ .size bmove_upp,.bmove_upp_end-bmove_upp
+ .ident "Matt Wagner & Monty"
diff --git a/strings/bmove_upp.c b/strings/bmove_upp.c
new file mode 100644
index 00000000000..af6575ebf41
--- /dev/null
+++ b/strings/bmove_upp.c
@@ -0,0 +1,51 @@
+/* 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 */
+
+/* File : bmove.c
+ Author : Michael widenius
+ Updated: 1987-03-20
+ Defines: bmove_upp()
+
+ bmove_upp(dst, src, len) moves exactly "len" bytes from the source
+ "src-len" to the destination "dst-len" counting downwards.
+*/
+
+#include <global.h>
+#include "m_string.h"
+
+#if defined(MC68000) && defined(DS90)
+
+/* 0 <= len <= 65535 */
+void bmove_upp(byte *dst, const byte *src,uint len)
+{
+asm(" movl 12(a7),d0 ");
+asm(" subql #1,d0 ");
+asm(" blt .L5 ");
+asm(" movl 4(a7),a1 ");
+asm(" movl 8(a7),a0 ");
+asm(".L4: movb -(a0),-(a1) ");
+asm(" dbf d0,.L4 ");
+asm(".L5: ");
+}
+#else
+
+void bmove_upp(register char *dst, register const char *src, register uint len)
+{
+ while (len-- != 0) *--dst = *--src;
+}
+
+#endif
diff --git a/strings/bzero.c b/strings/bzero.c
new file mode 100644
index 00000000000..cc628e05277
--- /dev/null
+++ b/strings/bzero.c
@@ -0,0 +1,67 @@
+/* File : bzero.c
+ Author : Richard A. O'Keefe.
+ Michael Widenius; ifdef MC68000
+ Updated: 23 April 1984
+ Defines: bzero()
+
+ bzero(dst, len) moves "len" 0 bytes to "dst".
+ Thus to clear a disc buffer to 0s do bzero(buffer, BUFSIZ).
+
+ Note: the "b" routines are there to exploit certain VAX order codes,
+ The asm code is presented for your interest and amusement.
+*/
+
+#ifndef BSD_FUNCS
+#include "strings.h"
+
+#ifdef bzero
+#undef bzero /* remove macro */
+#endif
+
+#if VaxAsm
+
+static void _bzero64 _A((char *dst,int len));
+
+void bzero(dst, len)
+char *dst;
+uint len;
+{
+ while ((int) len >= 64*K)
+ {
+ _bzero64(dst, 64*K-1);
+ dst += 64*K-1;
+ len -= 64*K-1;
+ }
+ _bzero64(dst, len);
+}
+
+_bzero64(dst, len)
+char *dst;
+int len;
+{
+ asm("movc5 $0,*4(ap),$0,8(ap),*4(ap)");
+}
+
+#else
+
+#if defined(MC68000) && defined(DS90)
+
+void bzero(dst, len)
+char *dst;
+uint len;
+{
+ bfill(dst,len,0); /* This is very optimized ! */
+} /* bzero */
+
+#else
+
+void bzero(dst, len)
+register char *dst;
+register uint len;
+{
+ while (len-- != 0) *dst++ = 0;
+} /* bzero */
+
+#endif
+#endif
+#endif /* BSD_FUNCS */
diff --git a/strings/conf_to_src.c b/strings/conf_to_src.c
new file mode 100644
index 00000000000..76316638153
--- /dev/null
+++ b/strings/conf_to_src.c
@@ -0,0 +1,143 @@
+/* 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 */
+
+/* can't use -lmysys because this prog is used to create -lstrings */
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define CHARSETS_SUBDIR "sql/share/charsets"
+#define CTYPE_TABLE_SIZE 257
+#define TO_LOWER_TABLE_SIZE 256
+#define TO_UPPER_TABLE_SIZE 256
+#define SORT_ORDER_TABLE_SIZE 256
+#define ROW_LEN 16
+
+void print_arrays_for(char *set);
+
+char *prog;
+char buf[1024], *p, *endptr;
+
+int
+main(int argc, char **argv)
+{
+ prog = *argv;
+
+ if (argc < 2) {
+ fprintf(stderr, "usage: %s source-dir [charset [, charset]]\n", prog);
+ exit(EXIT_FAILURE);
+ }
+
+ --argc; ++argv; /* skip program name */
+
+ if (chdir(*argv) != 0) {
+ fprintf(stderr, "%s: can't cd to %s\n", prog, *argv);
+ exit(EXIT_FAILURE);
+ }
+ --argc; ++argv;
+
+ if (chdir(CHARSETS_SUBDIR) != 0) {
+ fprintf(stderr, "%s: can't cd to %s\n", prog, CHARSETS_SUBDIR);
+ exit(EXIT_FAILURE);
+ }
+
+ while (argc--)
+ print_arrays_for(*argv++);
+
+ exit(EXIT_SUCCESS);
+}
+
+void
+print_array(FILE *f, const char *set, const char *name, int n)
+{
+ int i;
+ char val[100];
+
+ printf("uchar %s_%s[] = {\n", name, set);
+
+ p = buf;
+ *buf = '\0';
+ for (i = 0; i < n; ++i)
+ {
+ /* get a word from f */
+ endptr = p;
+ for (;;)
+ {
+ while (isspace(*endptr))
+ ++endptr;
+ if (*endptr && *endptr != '#') /* not comment */
+ break;
+ if ((fgets(buf, sizeof(buf), f)) == NULL)
+ return; /* XXX: break silently */
+ endptr = buf;
+ }
+
+ p = val;
+ while (!isspace(*endptr))
+ *p++ = *endptr++;
+ *p = '\0';
+ p = endptr;
+
+ /* write the value out */
+
+ if (i == 0 || i % ROW_LEN == n % ROW_LEN)
+ printf(" ");
+
+ printf("%3d", (unsigned char) strtol(val, (char **) NULL, 16));
+
+ if (i < n - 1)
+ printf(",");
+
+ if ((i+1) % ROW_LEN == n % ROW_LEN)
+ printf("\n");
+ }
+
+ printf("};\n\n");
+}
+
+void
+print_arrays_for(char *set)
+{
+ FILE *f;
+
+ sprintf(buf, "%s.conf", set);
+
+ if ((f = fopen(buf, "r")) == NULL) {
+ fprintf(stderr, "%s: can't read conf file for charset %s\n", prog, set);
+ exit(EXIT_FAILURE);
+ }
+
+ printf("\
+/* The %s character set. Generated automatically by configure and\n\
+ * the %s program\n\
+ */\n\n",
+ set, prog);
+
+ /* it would be nice if this used the code in mysys/charset.c, but... */
+ print_array(f, set, "ctype", CTYPE_TABLE_SIZE);
+ print_array(f, set, "to_lower", TO_LOWER_TABLE_SIZE);
+ print_array(f, set, "to_upper", TO_UPPER_TABLE_SIZE);
+ print_array(f, set, "sort_order", SORT_ORDER_TABLE_SIZE);
+ printf("\n");
+
+ fclose(f);
+
+ return;
+}
diff --git a/strings/ctype-big5.c b/strings/ctype-big5.c
new file mode 100644
index 00000000000..1fb98273fec
--- /dev/null
+++ b/strings/ctype-big5.c
@@ -0,0 +1,389 @@
+/* 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 basicly usa7 character sets with some extra functions
+ * for big5 handling
+*/
+
+/*
+ * 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_big5=1
+ * .configure. mbmaxlen_big5=2
+ */
+
+#include <global.h>
+#include "m_string.h"
+#include "m_ctype.h"
+
+/* Support for Chinese(BIG5) characters, by jou@nematic.ieo.nctu.edu.tw
+ modified by Wei He (hewei@mail.ied.ac.cn) */
+
+#define isbig5head(c) (0xa1<=(uchar)(c) && (uchar)(c)<=0xf9)
+#define isbig5tail(c) ((0x40<=(uchar)(c) && (uchar)(c)<=0x7e) || \
+ (0xa1<=(uchar)(c) && (uchar)(c)<=0xfe))
+
+#define isbig5code(c,d) (isbig5head(c) && isbig5tail(d))
+#define big5code(c,d) (((uchar)(c) <<8) | (uchar)(d))
+#define big5head(e) ((uchar)(e>>8))
+#define big5tail(e) ((uchar)(e&0xff))
+
+uchar NEAR ctype_big5[257] =
+{
+ 0, /* For standard library */
+ 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,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+};
+
+uchar NEAR to_lower_big5[]=
+{
+ '\000','\001','\002','\003','\004','\005','\006','\007',
+ '\010','\011','\012','\013','\014','\015','\016','\017',
+ '\020','\021','\022','\023','\024','\025','\026','\027',
+ '\030','\031','\032','\033','\034','\035','\036','\037',
+ ' ', '!', '"', '#', '$', '%', '&', '\'',
+ '(', ')', '*', '+', ',', '-', '.', '/',
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', ':', ';', '<', '=', '>', '?',
+ '@', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
+ 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
+ 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
+ 'x', 'y', 'z', '[', '\\', ']', '^', '_',
+ '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
+ 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
+ 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
+ 'x', 'y', 'z', '{', '|', '}', '~', '\177',
+ (uchar) '\200',(uchar) '\201',(uchar) '\202',(uchar) '\203',(uchar) '\204',(uchar) '\205',(uchar) '\206',(uchar) '\207',
+ (uchar) '\210',(uchar) '\211',(uchar) '\212',(uchar) '\213',(uchar) '\214',(uchar) '\215',(uchar) '\216',(uchar) '\217',
+ (uchar) '\220',(uchar) '\221',(uchar) '\222',(uchar) '\223',(uchar) '\224',(uchar) '\225',(uchar) '\226',(uchar) '\227',
+ (uchar) '\230',(uchar) '\231',(uchar) '\232',(uchar) '\233',(uchar) '\234',(uchar) '\235',(uchar) '\236',(uchar) '\237',
+ (uchar) '\240',(uchar) '\241',(uchar) '\242',(uchar) '\243',(uchar) '\244',(uchar) '\245',(uchar) '\246',(uchar) '\247',
+ (uchar) '\250',(uchar) '\251',(uchar) '\252',(uchar) '\253',(uchar) '\254',(uchar) '\255',(uchar) '\256',(uchar) '\257',
+ (uchar) '\260',(uchar) '\261',(uchar) '\262',(uchar) '\263',(uchar) '\264',(uchar) '\265',(uchar) '\266',(uchar) '\267',
+ (uchar) '\270',(uchar) '\271',(uchar) '\272',(uchar) '\273',(uchar) '\274',(uchar) '\275',(uchar) '\276',(uchar) '\277',
+ (uchar) '\300',(uchar) '\301',(uchar) '\302',(uchar) '\303',(uchar) '\304',(uchar) '\305',(uchar) '\306',(uchar) '\307',
+ (uchar) '\310',(uchar) '\311',(uchar) '\312',(uchar) '\313',(uchar) '\314',(uchar) '\315',(uchar) '\316',(uchar) '\317',
+ (uchar) '\320',(uchar) '\321',(uchar) '\322',(uchar) '\323',(uchar) '\324',(uchar) '\325',(uchar) '\326',(uchar) '\327',
+ (uchar) '\330',(uchar) '\331',(uchar) '\332',(uchar) '\333',(uchar) '\334',(uchar) '\335',(uchar) '\336',(uchar) '\337',
+ (uchar) '\340',(uchar) '\341',(uchar) '\342',(uchar) '\343',(uchar) '\344',(uchar) '\345',(uchar) '\346',(uchar) '\347',
+ (uchar) '\350',(uchar) '\351',(uchar) '\352',(uchar) '\353',(uchar) '\354',(uchar) '\355',(uchar) '\356',(uchar) '\357',
+ (uchar) '\360',(uchar) '\361',(uchar) '\362',(uchar) '\363',(uchar) '\364',(uchar) '\365',(uchar) '\366',(uchar) '\367',
+ (uchar) '\370',(uchar) '\371',(uchar) '\372',(uchar) '\373',(uchar) '\374',(uchar) '\375',(uchar) '\376',(uchar) '\377',
+};
+
+uchar NEAR to_upper_big5[]=
+{
+ '\000','\001','\002','\003','\004','\005','\006','\007',
+ '\010','\011','\012','\013','\014','\015','\016','\017',
+ '\020','\021','\022','\023','\024','\025','\026','\027',
+ '\030','\031','\032','\033','\034','\035','\036','\037',
+ ' ', '!', '"', '#', '$', '%', '&', '\'',
+ '(', ')', '*', '+', ',', '-', '.', '/',
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', ':', ';', '<', '=', '>', '?',
+ '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+ 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+ 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+ 'X', 'Y', 'Z', '[', '\\', ']', '^', '_',
+ '`', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+ 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+ 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+ 'X', 'Y', 'Z', '{', '|', '}', '~', '\177',
+ (uchar) '\200',(uchar) '\201',(uchar) '\202',(uchar) '\203',(uchar) '\204',(uchar) '\205',(uchar) '\206',(uchar) '\207',
+ (uchar) '\210',(uchar) '\211',(uchar) '\212',(uchar) '\213',(uchar) '\214',(uchar) '\215',(uchar) '\216',(uchar) '\217',
+ (uchar) '\220',(uchar) '\221',(uchar) '\222',(uchar) '\223',(uchar) '\224',(uchar) '\225',(uchar) '\226',(uchar) '\227',
+ (uchar) '\230',(uchar) '\231',(uchar) '\232',(uchar) '\233',(uchar) '\234',(uchar) '\235',(uchar) '\236',(uchar) '\237',
+ (uchar) '\240',(uchar) '\241',(uchar) '\242',(uchar) '\243',(uchar) '\244',(uchar) '\245',(uchar) '\246',(uchar) '\247',
+ (uchar) '\250',(uchar) '\251',(uchar) '\252',(uchar) '\253',(uchar) '\254',(uchar) '\255',(uchar) '\256',(uchar) '\257',
+ (uchar) '\260',(uchar) '\261',(uchar) '\262',(uchar) '\263',(uchar) '\264',(uchar) '\265',(uchar) '\266',(uchar) '\267',
+ (uchar) '\270',(uchar) '\271',(uchar) '\272',(uchar) '\273',(uchar) '\274',(uchar) '\275',(uchar) '\276',(uchar) '\277',
+ (uchar) '\300',(uchar) '\301',(uchar) '\302',(uchar) '\303',(uchar) '\304',(uchar) '\305',(uchar) '\306',(uchar) '\307',
+ (uchar) '\310',(uchar) '\311',(uchar) '\312',(uchar) '\313',(uchar) '\314',(uchar) '\315',(uchar) '\316',(uchar) '\317',
+ (uchar) '\320',(uchar) '\321',(uchar) '\322',(uchar) '\323',(uchar) '\324',(uchar) '\325',(uchar) '\326',(uchar) '\327',
+ (uchar) '\330',(uchar) '\331',(uchar) '\332',(uchar) '\333',(uchar) '\334',(uchar) '\335',(uchar) '\336',(uchar) '\337',
+ (uchar) '\340',(uchar) '\341',(uchar) '\342',(uchar) '\343',(uchar) '\344',(uchar) '\345',(uchar) '\346',(uchar) '\347',
+ (uchar) '\350',(uchar) '\351',(uchar) '\352',(uchar) '\353',(uchar) '\354',(uchar) '\355',(uchar) '\356',(uchar) '\357',
+ (uchar) '\360',(uchar) '\361',(uchar) '\362',(uchar) '\363',(uchar) '\364',(uchar) '\365',(uchar) '\366',(uchar) '\367',
+ (uchar) '\370',(uchar) '\371',(uchar) '\372',(uchar) '\373',(uchar) '\374',(uchar) '\375',(uchar) '\376',(uchar) '\377',
+};
+
+uchar NEAR sort_order_big5[]=
+{
+ '\000','\001','\002','\003','\004','\005','\006','\007',
+ '\010','\011','\012','\013','\014','\015','\016','\017',
+ '\020','\021','\022','\023','\024','\025','\026','\027',
+ '\030','\031','\032','\033','\034','\035','\036','\037',
+ ' ', '!', '"', '#', '$', '%', '&', '\'',
+ '(', ')', '*', '+', ',', '-', '.', '/',
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', ':', ';', '<', '=', '>', '?',
+ '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+ 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+ 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+ 'X', 'Y', 'Z', '\\', ']', '[', '^', '_',
+ 'E', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+ 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+ 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+ 'X', 'Y', 'Z', '{', '|', '}', 'Y', '\177',
+ (uchar) '\200',(uchar) '\201',(uchar) '\202',(uchar) '\203',(uchar) '\204',(uchar) '\205',(uchar) '\206',(uchar) '\207',
+ (uchar) '\210',(uchar) '\211',(uchar) '\212',(uchar) '\213',(uchar) '\214',(uchar) '\215',(uchar) '\216',(uchar) '\217',
+ (uchar) '\220',(uchar) '\221',(uchar) '\222',(uchar) '\223',(uchar) '\224',(uchar) '\225',(uchar) '\226',(uchar) '\227',
+ (uchar) '\230',(uchar) '\231',(uchar) '\232',(uchar) '\233',(uchar) '\234',(uchar) '\235',(uchar) '\236',(uchar) '\237',
+ (uchar) '\240',(uchar) '\241',(uchar) '\242',(uchar) '\243',(uchar) '\244',(uchar) '\245',(uchar) '\246',(uchar) '\247',
+ (uchar) '\250',(uchar) '\251',(uchar) '\252',(uchar) '\253',(uchar) '\254',(uchar) '\255',(uchar) '\256',(uchar) '\257',
+ (uchar) '\260',(uchar) '\261',(uchar) '\262',(uchar) '\263',(uchar) '\264',(uchar) '\265',(uchar) '\266',(uchar) '\267',
+ (uchar) '\270',(uchar) '\271',(uchar) '\272',(uchar) '\273',(uchar) '\274',(uchar) '\275',(uchar) '\276',(uchar) '\277',
+ (uchar) '\300',(uchar) '\301',(uchar) '\302',(uchar) '\303',(uchar) '\304',(uchar) '\305',(uchar) '\306',(uchar) '\307',
+ (uchar) '\310',(uchar) '\311',(uchar) '\312',(uchar) '\313',(uchar) '\314',(uchar) '\315',(uchar) '\316',(uchar) '\317',
+ (uchar) '\320',(uchar) '\321',(uchar) '\322',(uchar) '\323',(uchar) '\324',(uchar) '\325',(uchar) '\326',(uchar) '\327',
+ (uchar) '\330',(uchar) '\331',(uchar) '\332',(uchar) '\333',(uchar) '\334',(uchar) '\335',(uchar) '\336',(uchar) '\337',
+ (uchar) '\340',(uchar) '\341',(uchar) '\342',(uchar) '\343',(uchar) '\344',(uchar) '\345',(uchar) '\346',(uchar) '\347',
+ (uchar) '\350',(uchar) '\351',(uchar) '\352',(uchar) '\353',(uchar) '\354',(uchar) '\355',(uchar) '\356',(uchar) '\357',
+ (uchar) '\360',(uchar) '\361',(uchar) '\362',(uchar) '\363',(uchar) '\364',(uchar) '\365',(uchar) '\366',(uchar) '\367',
+ (uchar) '\370',(uchar) '\371',(uchar) '\372',(uchar) '\373',(uchar) '\374',(uchar) '\375',(uchar) '\376',(uchar) '\377',
+};
+
+static uint16 big5strokexfrm(uint16 i)
+{
+ if ((i == 0xA440) || (i == 0xA441)) return 0xA440;
+ else if (((i >= 0xA442) && (i <= 0xA453)) || ((i >= 0xC940) && (i <= 0xC944))) return 0xA442;
+ else if (((i >= 0xA454) && (i <= 0xA47E)) || ((i >= 0xC945) && (i <= 0xC94C))) return 0xA454;
+ else if (((i >= 0xA4A1) && (i <= 0xA4FD)) || ((i >= 0xC94D) && (i <= 0xC962))) return 0xA4A1;
+ else if (((i >= 0xA4FE) && (i <= 0xA5DF)) || ((i >= 0xC963) && (i <= 0xC9AA))) return 0xA4FE;
+ else if (((i >= 0xA5E0) && (i <= 0xA6E9)) || ((i >= 0xC9AB) && (i <= 0xCA59))) return 0xA5E0;
+ else if (((i >= 0xA6EA) && (i <= 0xA8C2)) || ((i >= 0xCA5A) && (i <= 0xCBB0))) return 0xA6EA;
+ else if ((i == 0xA260) || ((i >= 0xA8C3) && (i <= 0xAB44)) || ((i >= 0xCBB1) && (i <= 0xCDDC))) return 0xA8C3;
+ else if ((i == 0xA259) || (i == 0xF9DA) || ((i >= 0xAB45) && (i <= 0xADBB)) || ((i >= 0xCDDD) && (i <= 0xD0C7))) return 0xAB45;
+ else if ((i == 0xA25A) || ((i >= 0xADBC) && (i <= 0xB0AD)) || ((i >= 0xD0C8) && (i <= 0xD44A))) return 0xADBC;
+ else if ((i == 0xA25B) || (i == 0xA25C) || ((i >= 0xB0AE) && (i <= 0xB3C2)) || ((i >= 0xD44B) && (i <= 0xD850))) return 0xB0AE;
+ else if ((i == 0xF9DB) || ((i >= 0xB3C3) && (i <= 0xB6C2)) || ((i >= 0xD851) && (i <= 0xDCB0))) return 0xB3C3;
+ else if ((i == 0xA25D) || (i == 0xA25F) || (i == 0xC6A1) || (i == 0xF9D6) || (i == 0xF9D8) || ((i >= 0xB6C3) && (i <= 0xB9AB)) || ((i >= 0xDCB1) && (i <= 0xE0EF))) return 0xB6C3;
+ else if ((i == 0xF9DC) || ((i >= 0xB9AC) && (i <= 0xBBF4)) || ((i >= 0xE0F0) && (i <= 0xE4E5))) return 0xB9AC;
+ else if ((i == 0xA261) || ((i >= 0xBBF5) && (i <= 0xBEA6)) || ((i >= 0xE4E6) && (i <= 0xE8F3))) return 0xBBF5;
+ else if ((i == 0xA25E) || (i == 0xF9D7) || (i == 0xF9D9) || ((i >= 0xBEA7) && (i <= 0xC074)) || ((i >= 0xE8F4) && (i <= 0xECB8))) return 0xBEA7;
+ else if (((i >= 0xC075) && (i <= 0xC24E)) || ((i >= 0xECB9) && (i <= 0xEFB6))) return 0xC075;
+ else if (((i >= 0xC24F) && (i <= 0xC35E)) || ((i >= 0xEFB7) && (i <= 0xF1EA))) return 0xC24F;
+ else if (((i >= 0xC35F) && (i <= 0xC454)) || ((i >= 0xF1EB) && (i <= 0xF3FC))) return 0xC35F;
+ else if (((i >= 0xC455) && (i <= 0xC4D6)) || ((i >= 0xF3FD) && (i <= 0xF5BF))) return 0xC455;
+ else if (((i >= 0xC4D7) && (i <= 0xC56A)) || ((i >= 0xF5C0) && (i <= 0xF6D5))) return 0xC4D7;
+ else if (((i >= 0xC56B) && (i <= 0xC5C7)) || ((i >= 0xF6D6) && (i <= 0xF7CF))) return 0xC56B;
+ else if (((i >= 0xC5C8) && (i <= 0xC5F0)) || ((i >= 0xF7D0) && (i <= 0xF8A4))) return 0xC5C8;
+ else if (((i >= 0xC5F1) && (i <= 0xC654)) || ((i >= 0xF8A5) && (i <= 0xF8ED))) return 0xC5F1;
+ else if (((i >= 0xC655) && (i <= 0xC664)) || ((i >= 0xF8EE) && (i <= 0xF96A))) return 0xC655;
+ else if (((i >= 0xC665) && (i <= 0xC66B)) || ((i >= 0xF96B) && (i <= 0xF9A1))) return 0xC665;
+ else if (((i >= 0xC66C) && (i <= 0xC675)) || ((i >= 0xF9A2) && (i <= 0xF9B9))) return 0xC66C;
+ else if (((i >= 0xC676) && (i <= 0xC678)) || ((i >= 0xF9BA) && (i <= 0xF9C5))) return 0xC676;
+ else if (((i >= 0xC679) && (i <= 0xC67C)) || ((i >= 0xF9C7) && (i <= 0xF9CB))) return 0xC679;
+ else if ((i == 0xC67D) || ((i >= 0xF9CC) && (i <= 0xF9CF))) return 0xC67D;
+ else if (i == 0xF9D0) return 0xF9D0;
+ else if ((i == 0xC67E) || (i == 0xF9D1)) return 0xC67E;
+ else if ((i == 0xF9C6) || (i == 0xF9D2)) return 0xF9C6;
+ else if (i == 0xF9D3) return 0xF9D3;
+ else if (i == 0xF9D4) return 0xF9D4;
+ else if (i == 0xF9D5) return 0xF9D5;
+ return 0xA140;
+}
+
+int my_strnncoll_big5(const uchar * s1, int len1, const uchar * s2, int len2)
+{
+ uint len;
+
+ len = min(len1,len2);
+ while (len--)
+ {
+ if ((len > 0) && isbig5code(*s1,*(s1+1)) && isbig5code(*s2, *(s2+1)))
+ {
+ if (*s1 != *s2 || *(s1+1) != *(s2+1))
+ return ((int) big5code(*s1,*(s1+1)) -
+ (int) big5code(*s2,*(s2+1)));
+ s1 +=2;
+ s2 +=2;
+ len--;
+ } else if (sort_order_big5[(uchar) *s1++] != sort_order_big5[(uchar) *s2++])
+ return ((int) sort_order_big5[(uchar) s1[-1]] -
+ (int) sort_order_big5[(uchar) s2[-1]]);
+ }
+ return (int) (len1-len2);
+}
+
+int my_strnxfrm_big5(uchar * dest, uchar * src, int len, int srclen)
+{
+ uint16 e;
+ /*uchar *d = dest; XXX: unused*/
+
+ len = srclen;
+ while (len--)
+ {
+ if ((len > 0) && isbig5code(*src, *(src+1)))
+ {
+ e = big5strokexfrm((uint16) big5code(*src, *(src+1)));
+ *dest++ = big5head(e);
+ *dest++ = big5tail(e);
+ src +=2;
+ len--;
+ } else
+ *dest++ = sort_order_big5[(uchar) *src++];
+ }
+ return srclen;
+}
+
+int my_strcoll_big5(const uchar * s1, const uchar * s2)
+{
+
+ while (*s1 && *s2)
+ {
+ if (*(s1+1) && *(s2+1) && isbig5code(*s1,*(s1+1)) && isbig5code(*s2, *(s2+1)))
+ {
+ if (*s1 != *s2 || *(s1+1) != *(s2+1))
+ return ((int) big5code(*s1,*(s1+1)) -
+ (int) big5code(*s2,*(s2+1)));
+ s1 +=2;
+ s2 +=2;
+ } else if (sort_order_big5[(uchar) *s1++] != sort_order_big5[(uchar) *s2++])
+ return ((int) sort_order_big5[(uchar) s1[-1]] -
+ (int) sort_order_big5[(uchar) s2[-1]]);
+ }
+ return 0;
+}
+
+int my_strxfrm_big5(uchar * dest, uchar * src, int len)
+{
+ uint16 e;
+ uchar *d = dest;
+
+ if (len < 1) return 0;
+ if (!*src)
+ {
+ *d = '\0';
+ return 0;
+ }
+ while (*src && (len > 1))
+ {
+ if (*(src+1) && isbig5code(*src, *(src+1)))
+ {
+ e = big5strokexfrm((uint16) big5code(*src, *(src+1)));
+ *d++ = big5head(e);
+ *d++ = big5tail(e);
+ src +=2;
+ len--;
+ } else
+ *d++ = sort_order_big5[(uchar) *src++];
+ }
+ *d = '\0';
+ return (int) (d-dest);
+}
+
+/*
+** Calculate min_str and max_str that ranges a LIKE string.
+** Arguments:
+** ptr Pointer to LIKE string.
+** ptr_length Length of LIKE string.
+** escape Escape character in LIKE. (Normally '\').
+** All escape characters should be removed from min_str and max_str
+** res_length Length of min_str and max_str.
+** min_str Smallest case sensitive string that ranges LIKE.
+** Should be space padded to res_length.
+** max_str Largest case sensitive string that ranges LIKE.
+** Normally padded with the biggest character sort value.
+**
+** The function should return 0 if ok and 1 if the LIKE string can't be
+** optimized !
+*/
+
+#define max_sort_char ((char) 255)
+#define wild_one '_'
+#define wild_many '%'
+
+my_bool my_like_range_big5(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+1 != end && isbig5code(ptr[0],ptr[1]))
+ {
+ *min_str++= *max_str++ = *ptr++;
+ *min_str++= *max_str++ = *ptr;
+ continue;
+ }
+ if (*ptr == escape && ptr+1 != end)
+ {
+ ptr++; /* Skipp escape */
+ *min_str++= *max_str++ = *ptr;
+ continue;
+ }
+ if (*ptr == wild_one) /* '_' in SQL */
+ {
+ *min_str++='\0'; /* This should be min 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++ = '\0'; /* 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);
+ while (min_str != min_end)
+ {
+ *min_str++ = ' '; /* Because if key compression */
+ *max_str++ = ' ';
+ }
+ return 0;
+}
+
+int ismbchar_big5(const char* p, const char *e)
+{
+ return (isbig5head(*(p)) && (e)-(p)>1 && isbig5tail(*((p)+1))? 2: 0);
+}
+
+my_bool ismbhead_big5(uint c)
+{
+ return isbig5head(c);
+}
+
+int mbcharlen_big5(uint c)
+{
+ return (isbig5head(c)? 2: 0);
+}
diff --git a/strings/ctype-czech.c b/strings/ctype-czech.c
new file mode 100644
index 00000000000..b47eaf3a63f
--- /dev/null
+++ b/strings/ctype-czech.c
@@ -0,0 +1,510 @@
+/* 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 */
+
+/* File strings/ctype-czech.c for MySQL.
+
+ This file implements the Czech sorting for the MySQL database
+ server (www.mysql.com). Due to some complicated rules the
+ Czech language has for sorting strings, a more complex
+ solution was needed than the one-to-one conversion table. To
+ note a few, here is an example of a Czech sorting sequence:
+
+ co < hlaska < hláska < hlava < chlapec < krtek
+
+ It because some of the rules are: double char 'ch' is sorted
+ between 'h' and 'i'. Accented character 'á' (a with acute) is
+ sorted after 'a' and before 'b', but only if the word is
+ otherwise the same. However, because 's' is sorted before 'v'
+ in hlava, the accentness of 'á' is overridden. There are many
+ more rules.
+
+ This file defines functions my_strxfrm and my_strcoll for
+ C-like zero terminated strings and my_strnxfrm and my_strnncoll
+ for strings where the length comes as an parameter. Also
+ defined here you will find function my_like_range that returns
+ index range strings for LIKE expression and the
+ MY_STRXFRM_MULTIPLY set to value 4 -- this is the ratio the
+ strings grows during my_strxfrm. The algorithm has four
+ passes, that's why we need four times more space for expanded
+ string.
+
+ This file also contains the ISO-Latin-2 definitions of
+ characters.
+
+ Author: (c) 1997--1998 Jan Pazdziora, adelton@fi.muni.cz
+ Jan Pazdziora has a shared copyright for this code
+
+ The original of this file can also be found at
+ http://www.fi.muni.cz/~adelton/l10n/
+
+ Bug reports and suggestions are always welcome.
+*/
+
+/*
+ * 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_czech=4
+ */
+
+#define SKIP_TRAILING_SPACES 1
+
+#define REAL_MYSQL
+
+#ifdef REAL_MYSQL
+
+#include <global.h>
+#include "m_string.h"
+
+#else
+
+#include <stdio.h>
+#define uchar unsigned char
+
+#endif
+
+/*
+ These are four tables for four passes of the algorithm. Please see
+ below for what are the "special values"
+*/
+
+static uchar * CZ_SORT_TABLE[] = {
+ (uchar*) "\000\000\000\000\000\000\000\000\000\002\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\002\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\043\044\045\046\047\050\051\052\053\054\000\000\000\000\000\000\000\003\004\377\007\010\011\012\013\015\016\017\020\022\023\024\025\026\027\031\033\034\035\036\037\040\041\000\000\000\000\000\000\003\004\377\007\010\011\012\013\015\016\017\020\022\023\024\025\026\027\031\033\034\035\036\037\040\041\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\003\000\021\000\020\032\000\000\032\032\033\042\000\042\042\000\003\000\021\000\020\032\000\000\032\032\033\042\000\042\042\027\003\003\003\003\020\006\006\006\010\010\010\010\015\015\007\007\023\023\024\024\024\024\000\030\034\034\034\034\040\033\000\027\003\003\003\003\020\006\006\006\010\010\010\010\015\015\007\007\023\023\024\024\024\024\000\030\034\034\034\034\040\033\000",
+ (uchar*) "\000\000\000\000\000\000\000\000\000\002\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\002\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\106\107\110\111\112\113\114\115\116\117\000\000\000\000\000\000\000\003\011\377\016\021\026\027\030\032\035\036\037\043\044\047\054\055\056\061\065\070\075\076\077\100\102\000\000\000\000\000\000\003\011\377\016\021\026\027\030\032\035\036\037\043\044\047\054\055\056\061\065\070\075\076\077\100\102\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\010\000\042\000\041\063\000\000\062\064\066\104\000\103\105\000\010\000\042\000\041\063\000\000\062\064\066\104\000\103\105\057\004\005\007\006\040\014\015\013\022\025\024\023\033\034\017\020\046\045\050\051\053\052\000\060\072\071\074\073\101\067\000\057\004\005\007\006\040\014\015\013\022\025\024\023\033\034\017\020\046\045\050\051\053\052\000\060\072\071\074\073\101\067\000",
+(uchar*) "\000\000\000\000\000\000\000\000\000\002\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\002\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\212\213\214\215\216\217\220\221\222\223\000\000\000\000\000\000\000\004\020\377\032\040\052\054\056\063\071\073\075\105\107\115\127\131\133\141\151\157\171\173\175\177\203\000\000\000\000\000\000\003\017\377\031\037\051\053\055\062\070\072\074\104\106\114\126\130\132\140\150\156\170\172\174\176\202\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\016\000\103\000\101\145\000\000\143\147\153\207\000\205\211\000\015\000\102\000\100\144\000\000\142\146\152\206\000\204\210\135\006\010\014\012\077\026\030\024\042\050\046\044\065\067\034\036\113\111\117\121\125\123\000\137\163\161\167\165\201\155\000\134\005\007\013\011\076\025\027\023\041\047\045\043\064\066\033\035\112\110\116\120\124\122\000\136\162\160\166\164\200\154\000",
+(uchar*) "\264\265\266\267\270\271\272\273\274\002\276\277\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317\320\321\322\323\002\230\232\253\324\252\251\234\240\241\261\260\225\262\224\235\212\213\214\215\216\217\220\221\222\223\231\226\244\257\245\227\250\004\020\377\032\040\052\054\056\063\071\073\075\105\107\115\127\131\133\141\151\157\171\173\175\177\203\242\237\243\254\255\233\003\017\377\031\037\051\053\055\062\070\072\074\104\106\114\126\130\132\140\150\156\170\172\174\176\202\246\236\247\256\325\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317\320\321\322\323\326\016\327\103\330\101\145\331\332\143\147\153\207\333\205\211\334\015\335\102\336\100\144\337\340\142\146\152\206\341\204\210\135\006\010\014\012\077\026\030\024\042\050\046\044\065\067\034\036\113\111\117\121\125\123\263\137\163\161\167\165\201\155\342\134\005\007\013\011\076\025\027\023\041\047\045\043\064\066\033\035\112\110\116\120\124\122\343\136\162\160\166\164\200\154\344",
+};
+
+/*
+ These define the valuse for the double chars that need to be
+ sorted as they were single characters -- in Czech these are
+ 'ch', 'Ch' and 'CH'.
+*/
+
+struct wordvalue
+ {
+ const char * word;
+ uchar * outvalue;
+ };
+static struct wordvalue doubles[] = {
+ { "ch", (uchar*) "\014\031\057\057" },
+ { "Ch", (uchar*) "\014\031\060\060" },
+ { "CH", (uchar*) "\014\031\061\061" },
+ { "c", (uchar*) "\005\012\021\021" },
+ { "C", (uchar*) "\005\012\022\022" },
+ };
+
+/*
+ Unformal description of the algorithm:
+
+ We walk the string left to right.
+
+ The end of the string is either passed as parameter, or is
+ *p == 0. This is hidden in the IS_END macro.
+
+ In the first two passes, we compare word by word. So we make
+ first and second pass on the first word, first and second pass
+ on the second word, etc. If we come to the end of the string
+ during the first pass, we need to jump to the last word of the
+ second pass.
+
+ End of pass is marked with value 1 on the output.
+
+ For each character, we read it's value from the table.
+
+ If the value is ignore (0), we go straight to the next character.
+
+ If the value is space/end of word (2) and we are in the first
+ or second pass, we skip all characters having value 0 -- 2 and
+ switch the passwd.
+
+ If it's the compose character (255), we check if the double
+ exists behind it, find its value.
+
+ We append 0 to the end.
+---
+ Neformální popis algoritmu:
+
+ Procházíme øetìzec zleva doprava.
+
+ Konec øetìzce je pøedán buï jako parametr, nebo je to *p == 0.
+ Toto je o¹etøeno makrem IS_END.
+
+ Pokud jsme do¹li na konec øetìzce pøi prùchodu 0, nejdeme na
+ zaèátek, ale na ulo¾enou pozici, proto¾e první a druhý prùchod
+ bì¾í souèasnì.
+
+ Konec vstupu (prùchodu) oznaèíme na výstupu hodnotou 1.
+
+ Pro ka¾dý znak øetìzce naèteme hodnotu z tøídící tabulky.
+
+ Jde-li o hodnotu ignorovat (0), skoèíme ihned na dal¹í znak..
+
+ Jde-li o hodnotu konec slova (2) a je to prùchod 0 nebo 1,
+ pøeskoèíme v¹echny dal¹í 0 -- 2 a prohodíme prùchody.
+
+ Jde-li o kompozitní znak (255), otestujeme, zda následuje
+ správný do dvojice, dohledáme správnou hodnotu.
+
+ Na konci pøipojíme znak 0
+ */
+
+#define ADD_TO_RESULT(dest, len, totlen, value) \
+ if ((totlen) < (len)) { dest[totlen] = value; } (totlen++);
+
+#define NEXT_CMP_VALUE(src, p, store, pass, value, len) \
+ while (1) /* we will make a loop */ \
+ { \
+ if (IS_END(p, src, len)) \
+ /* when we are at the end of string */ \
+ { /* return either 0 for end of string */ \
+ /* or 1 for end of pass */ \
+ if (pass == 3) { value = 0; break; } \
+ if (pass == 0) p = store; \
+ else p = src; \
+ value = 1; pass++; break; \
+ } \
+ /* not at end of string */ \
+ value = CZ_SORT_TABLE[pass][*p]; \
+ \
+ if (value == 0) { p++; continue; } /* ignore value */ \
+ if (value == 2) /* space */ \
+ { \
+ const uchar * tmp; \
+ const uchar * runner = ++p; \
+ while (!(IS_END(runner, src, len)) && (CZ_SORT_TABLE[pass][*runner] == 2)) \
+ runner++; /* skip all spaces */ \
+ if (IS_END(runner, src, len) && SKIP_TRAILING_SPACES) \
+ p = runner; \
+ if ((pass <= 2) && !(IS_END(runner, src, len))) \
+ p = runner; \
+ if (IS_END(p, src, len)) \
+ continue; \
+ /* we switch passes */ \
+ if (pass > 1) \
+ break; \
+ tmp = p; \
+ if (pass == 0) pass = 1; \
+ else pass = 0; \
+ p = store; store = tmp; \
+ break; \
+ } \
+ if (value == 255) \
+ { \
+ int i; \
+ for (i = 0; i < (int) sizeof(doubles); i++) \
+ { \
+ const char * pattern = doubles[i].word; \
+ const char * q = (const char *) p; \
+ int j = 0; \
+ while (pattern[j]) \
+ { \
+ if (IS_END(q, src, len) || (*q != pattern[j])) \
+ { break ; } \
+ j++; q++; \
+ } \
+ if (!(pattern[j])) \
+ { \
+ value = (int)(doubles[i].outvalue[pass]); \
+ p = (const uchar *) q - 1; \
+ break; \
+ } \
+ } \
+ } \
+ p++; \
+ break; \
+ }
+
+#define IS_END(p, src, len) (!(*p))
+
+/* Function strcoll, with Czech sorting, for zero terminated strings */
+int my_strcoll_czech(const uchar * s1, const uchar * s2)
+ {
+ int v1, v2;
+ const uchar * p1, * p2, * store1, * store2;
+ int pass1 = 0, pass2 = 0;
+ int diff;
+
+ p1 = s1; p2 = s2;
+ store1 = s1; store2 = s2;
+
+ do
+ {
+ NEXT_CMP_VALUE(s1, p1, store1, pass1, v1, 0);
+ NEXT_CMP_VALUE(s2, p2, store2, pass2, v2, 0);
+ diff = v1 - v2;
+ if (diff != 0) return diff;
+ }
+ while (v1);
+ return 0;
+ }
+
+/* Function strxfrm, with Czech sorting, for zero terminated strings */
+int my_strxfrm_czech(uchar * dest, const uchar * src, int len)
+{
+ int value;
+ const uchar * p, * store;
+ int pass = 0;
+ int totlen = 0;
+ p = store = src;
+
+ do
+ {
+ NEXT_CMP_VALUE(src, p, store, pass, value, 0);
+ ADD_TO_RESULT(dest, len, totlen, value);
+ }
+ while (value);
+ return totlen;
+ }
+
+#undef IS_END
+
+
+
+
+#define IS_END(p, src, len) (((char *)p - (char *)src) >= (len))
+
+/* Function strnncoll, actually strcoll, with Czech sorting, which expect
+ the length of the strings being specified */
+int my_strnncoll_czech(const uchar * s1, int len1, const uchar * s2, int len2)
+ {
+ int v1, v2;
+ const uchar * p1, * p2, * store1, * store2;
+ int pass1 = 0, pass2 = 0;
+ int diff;
+
+ p1 = s1; p2 = s2;
+ store1 = s1; store2 = s2;
+
+ do
+ {
+ NEXT_CMP_VALUE(s1, p1, store1, pass1, v1, len1);
+ NEXT_CMP_VALUE(s2, p2, store2, pass2, v2, len2);
+ diff = v1 - v2;
+
+ if (diff != 0) return diff;
+ }
+ while (v1);
+ return 0;
+ }
+
+/* Function strnxfrm, actually strxfrm, with Czech sorting, which expect
+ the length of the strings being specified */
+int my_strnxfrm_czech(uchar * dest, const uchar * src, int len, int srclen)
+ {
+ int value;
+ const uchar * p, * store;
+ int pass = 0;
+ int totlen = 0;
+ p = src; store = src;
+
+ do
+ {
+ NEXT_CMP_VALUE(src, p, store, pass, value, srclen);
+ ADD_TO_RESULT(dest, len, totlen, value);
+ }
+ while (value);
+ return totlen;
+ }
+
+#undef IS_END
+
+
+/*
+ Neformální popis algoritmu:
+
+ procházíme øetìzec zleva doprava
+ konec øetìzce poznáme podle *p == 0
+ pokud jsme do¹li na konec øetìzce pøi prùchodu 0, nejdeme na
+ zaèátek, ale na ulo¾enou pozici, proto¾e první a druhý
+ prùchod bì¾í souèasnì
+ konec vstupu (prùchodu) oznaèíme na výstupu hodnotou 1
+
+ naèteme hodnotu z tøídící tabulky
+ jde-li o hodnotu ignorovat (0), skoèíme na dal¹í prùchod
+ jde-li o hodnotu konec slova (2) a je to prùchod 0 nebo 1,
+ pøeskoèíme v¹echny dal¹í 0 -- 2 a prohodíme
+ prùchody
+ jde-li o kompozitní znak (255), otestujeme, zda následuje
+ správný do dvojice, dohledáme správnou hodnotu
+
+ na konci pøipojíme znak 0
+ */
+
+
+/*
+** Calculate min_str and max_str that ranges a LIKE string.
+** Arguments:
+** ptr Pointer to LIKE string.
+** ptr_length Length of LIKE string.
+** escape Escape character in LIKE. (Normally '\').
+** All escape characters should be removed from min_str and max_str
+** res_length Length of min_str and max_str.
+** min_str Smallest case sensitive string that ranges LIKE.
+** Should be space padded to res_length.
+** max_str Largest case sensitive string that ranges LIKE.
+** Normally padded with the biggest character sort value.
+**
+** The function should return 0 if ok and 1 if the LIKE string can't be
+** optimized !
+*/
+
+#ifdef REAL_MYSQL
+
+#define min_sort_char ' '
+#define max_sort_char '9'
+#define wild_one '_'
+#define wild_many '%'
+
+#define EXAMPLE
+
+my_bool my_like_range_czech(const char *ptr,uint ptr_length,pchar escape,
+ uint res_length, char *min_str,char *max_str,
+ uint *min_length,uint *max_length)
+{
+#ifdef EXAMPLE
+ uchar value;
+ 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 == wild_one) /* '_' in SQL */
+ { break; }
+ if (*ptr == wild_many) /* '%' in SQL */
+ { break; }
+
+ if (*ptr == escape && ptr+1 != end)
+ { ptr++; } /* Skip escape */
+
+ value = CZ_SORT_TABLE[0][(int) (uchar) *ptr];
+
+ if (value == 0) /* Ignore in the first pass */
+ { continue; }
+ if (value <= 2) /* End of pass or end of string */
+ { break; }
+ if (value == 255) /* Double char too compicated */
+ { break; }
+
+ *min_str++= *max_str++ = *ptr;
+ }
+ *min_length= (uint) (min_str - min_org);
+ *max_length= res_length;
+ while (min_str != min_end)
+ {
+ *min_str++ = min_sort_char; /* Because of key compression */
+ *max_str++ = max_sort_char;
+ }
+ return 0;
+#else
+ return 1;
+#endif
+}
+
+#endif
+
+#ifdef REAL_MYSQL
+/* This is a latin2 file */
+
+/*
+ * File generated by cset
+ * (C) Abandoned 1997 Zarko Mocnik <zarko.mocnik@dem.si>
+ *
+ * definition table reworked by Jaromir Dolecek <dolecek@ics.muni.cz>
+ */
+#include <global.h>
+#include "m_string.h"
+
+uchar NEAR ctype_czech[257] = {
+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,
+ 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,
+ 1, 16, 1, 16, 1, 1, 16, 0, 0, 1, 1, 1, 1, 16, 1, 1,
+ 16, 2, 16, 2, 16, 2, 2, 16, 16, 2, 2, 2, 2, 16, 2, 2,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 16, 1, 1, 1, 1, 1, 1, 16, 1, 1, 1, 1, 1, 1, 1, 16,
+ 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, 16,
+};
+
+uchar NEAR to_lower_czech[] = {
+ 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,
+177,161,179,163,181,182,166,167,168,185,186,187,188,173,190,191,
+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,
+208,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 NEAR to_upper_czech[] = {
+ 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,160,178,162,180,164,165,183,184,169,170,171,172,189,174,175,
+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,
+240,209,210,211,212,213,214,247,216,217,218,219,220,221,222,255,
+};
+
+uchar NEAR sort_order_czech[] = {
+ 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, 71, 72, 76, 78, 83, 84, 85, 86, 90, 91, 92, 96, 97,100,
+105,106,107,110,114,117,122,123,124,125,127,131,132,133,134,135,
+136, 65, 71, 72, 76, 78, 83, 84, 85, 86, 90, 91, 92, 96, 97,100,
+105,106,107,110,114,117,122,123,124,125,127,137,138,139,140, 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,255,
+ 66,255, 93,255, 94,111,255,255,255,112,113,115,128,255,129,130,
+255, 66,255, 93,255, 94,111,255,255,112,113,115,128,255,129,130,
+108, 67, 68, 69, 70, 95, 73, 75, 74, 79, 81, 82, 80, 89, 87, 77,
+255, 98, 99,101,102,103,104,255,109,119,118,120,121,126,116,255,
+108, 67, 68, 69, 70, 95, 73, 75, 74, 79, 81, 82, 80, 89, 88, 77,
+255, 98, 99,101,102,103,104,255,109,119,118,120,121,126,116,255,
+};
+
+#endif
diff --git a/strings/ctype-euc_kr.c b/strings/ctype-euc_kr.c
new file mode 100644
index 00000000000..13d4513ce2d
--- /dev/null
+++ b/strings/ctype-euc_kr.c
@@ -0,0 +1,198 @@
+/* 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 for Korean EUC charset, and created by powerm90@tinc.co.kr.
+ * and updated by mrpark@tinc.co.kr.
+ */
+
+/*
+ * This comment is parsed by configure to create ctype.c,
+ * so don't change it unless you know what you are doing.
+ *
+ * .configure. mbmaxlen_euc_kr=2
+ */
+
+#include <global.h>
+#include "m_string.h"
+
+uchar NEAR ctype_euc_kr[257] =
+{
+ 0, /* For standard library */
+ 0040, 0040, 0040, 0040, 0040, 0040, 0040, 0040, /* NUL ^A - ^G */
+ 0040, 0050, 0050, 0050, 0050, 0050, 0040, 0040, /* ^H - ^O */
+ 0040, 0040, 0040, 0040, 0040, 0040, 0040, 0040, /* ^P - ^W */
+ 0040, 0040, 0040, 0040, 0040, 0040, 0040, 0040, /* ^X - ^Z ^[ ^\ ^] ^^ ^_ */
+ 0110, 0020, 0020, 0020, 0020, 0020, 0020, 0020, /* SPC ! " # $ % ^ ' */
+ 0020, 0020, 0020, 0020, 0020, 0020, 0020, 0020, /* ( ) * + , - . / */
+ 0204, 0204, 0204, 0204, 0204, 0204, 0204, 0204, /* 0 1 2 3 4 5 6 7 */
+ 0204, 0204, 0020, 0020, 0020, 0020, 0020, 0020, /* 8 9 : ; < = > ? */
+ 0020, 0201, 0201, 0201, 0201, 0201, 0201, 0001, /* @ A B C D E F G */
+ 0001, 0001, 0001, 0001, 0001, 0001, 0001, 0001, /* H I J K L M N O */
+ 0001, 0001, 0001, 0001, 0001, 0001, 0001, 0001, /* P Q R S T U V W */
+ 0001, 0001, 0001, 0020, 0020, 0020, 0020, 0020, /* X Y Z [ \ ] ^ _ */
+ 0020, 0202, 0202, 0202, 0202, 0202, 0202, 0002, /* ` a b c d e f g */
+ 0002, 0002, 0002, 0002, 0002, 0002, 0002, 0002, /* h i j k l m n o */
+ 0002, 0002, 0002, 0002, 0002, 0002, 0002, 0002, /* p q r s t u v w */
+ 0002, 0002, 0002, 0020, 0020, 0020, 0020, 0040, /* x y z { | } + DEL */
+ 0020, 0020, 0020, 0020, 0020, 0020, 0020, 0020,
+ 0020, 0020, 0020, 0020, 0020, 0020, 0020, 0020,
+ 0020, 0020, 0020, 0020, 0020, 0020, 0020, 0020,
+ 0020, 0020, 0020, 0020, 0020, 0020, 0020, 0020,
+ 0020, 0020, 0020, 0020, 0020, 0020, 0020, 0020,
+ 0020, 0020, 0020, 0020, 0020, 0020, 0020, 0020,
+ 0020, 0020, 0020, 0020, 0020, 0020, 0020, 0020,
+ 0020, 0020, 0020, 0020, 0020, 0020, 0020, 0020,
+ 0020, 0020, 0020, 0020, 0020, 0020, 0020, 0020,
+ 0020, 0020, 0020, 0020, 0020, 0020, 0020, 0020,
+ 0020, 0020, 0020, 0020, 0020, 0020, 0020, 0020,
+ 0020, 0020, 0020, 0020, 0020, 0020, 0020, 0020,
+ 0020, 0020, 0020, 0020, 0020, 0020, 0020, 0020,
+ 0020, 0020, 0020, 0020, 0020, 0020, 0020, 0020,
+ 0020, 0020, 0020, 0020, 0020, 0020, 0020, 0020,
+ 0020, 0020, 0020, 0020, 0020, 0020, 0020, 0000,
+};
+
+uchar NEAR to_lower_euc_kr[]=
+{
+ '\000','\001','\002','\003','\004','\005','\006','\007',
+ '\010','\011','\012','\013','\014','\015','\016','\017',
+ '\020','\021','\022','\023','\024','\025','\026','\027',
+ '\030','\031','\032','\033','\034','\035','\036','\037',
+ ' ', '!', '"', '#', '$', '%', '&', '\'',
+ '(', ')', '*', '+', ',', '-', '.', '/',
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', ':', ';', '<', '=', '>', '?',
+ '@', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
+ 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
+ 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
+ 'x', 'y', 'z', '[', '\\', ']', '^', '_',
+ '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
+ 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
+ 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
+ 'x', 'y', 'z', '{', '|', '}', '~', '\177',
+ '\200','\201','\202','\203','\204','\205','\206','\207',
+ '\210','\211','\212','\213','\214','\215','\216','\217',
+ '\220','\221','\222','\223','\224','\225','\226','\227',
+ '\230','\231','\232','\233','\234','\235','\236','\237',
+ '\240','\241','\242','\243','\244','\245','\246','\247',
+ '\250','\251','\252','\253','\254','\255','\256','\257',
+ '\260','\261','\262','\263','\264','\265','\266','\267',
+ '\270','\271','\272','\273','\274','\275','\276','\277',
+ '\300','\301','\302','\303','\304','\305','\306','\307',
+ '\310','\311','\312','\313','\314','\315','\316','\317',
+ '\320','\321','\322','\323','\324','\325','\326','\327',
+ '\330','\331','\332','\333','\334','\335','\336','\337',
+ '\340','\341','\342','\343','\344','\345','\346','\347',
+ '\350','\351','\352','\353','\354','\355','\356','\357',
+ '\360','\361','\362','\363','\364','\365','\366','\367',
+ '\370','\371','\372','\373','\374','\375','\376','\377',
+};
+
+uchar NEAR to_upper_euc_kr[]=
+{
+ '\000','\001','\002','\003','\004','\005','\006','\007',
+ '\010','\011','\012','\013','\014','\015','\016','\017',
+ '\020','\021','\022','\023','\024','\025','\026','\027',
+ '\030','\031','\032','\033','\034','\035','\036','\037',
+ ' ', '!', '"', '#', '$', '%', '&', '\'',
+ '(', ')', '*', '+', ',', '-', '.', '/',
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', ':', ';', '<', '=', '>', '?',
+ '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+ 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+ 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+ 'X', 'Y', 'Z', '[', '\\', ']', '^', '_',
+ '`', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+ 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+ 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+ 'X', 'Y', 'Z', '{', '|', '}', '~', '\177',
+ '\200','\201','\202','\203','\204','\205','\206','\207',
+ '\210','\211','\212','\213','\214','\215','\216','\217',
+ '\220','\221','\222','\223','\224','\225','\226','\227',
+ '\230','\231','\232','\233','\234','\235','\236','\237',
+ '\240','\241','\242','\243','\244','\245','\246','\247',
+ '\250','\251','\252','\253','\254','\255','\256','\257',
+ '\260','\261','\262','\263','\264','\265','\266','\267',
+ '\270','\271','\272','\273','\274','\275','\276','\277',
+ '\300','\301','\302','\303','\304','\305','\306','\307',
+ '\310','\311','\312','\313','\314','\315','\316','\317',
+ '\320','\321','\322','\323','\324','\325','\326','\327',
+ '\330','\331','\332','\333','\334','\335','\336','\337',
+ '\340','\341','\342','\343','\344','\345','\346','\347',
+ '\350','\351','\352','\353','\354','\355','\356','\357',
+ '\360','\361','\362','\363','\364','\365','\366','\367',
+ '\370','\371','\372','\373','\374','\375','\376','\377',
+};
+
+uchar NEAR sort_order_euc_kr[]=
+{
+ '\000','\001','\002','\003','\004','\005','\006','\007',
+ '\010','\011','\012','\013','\014','\015','\016','\017',
+ '\020','\021','\022','\023','\024','\025','\026','\027',
+ '\030','\031','\032','\033','\034','\035','\036','\037',
+ ' ', '!', '"', '#', '$', '%', '&', '\'',
+ '(', ')', '*', '+', ',', '-', '.', '/',
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', ':', ';', '<', '=', '>', '?',
+ '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+ 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+ 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+ 'X', 'Y', 'Z', '[', '\\', ']', '^', '_',
+ '`', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+ 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+ 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+ 'X', 'Y', 'Z', '{', '|', '}', '~', '\177',
+ '\200','\201','\202','\203','\204','\205','\206','\207',
+ '\210','\211','\212','\213','\214','\215','\216','\217',
+ '\220','\221','\222','\223','\224','\225','\226','\227',
+ '\230','\231','\232','\233','\234','\235','\236','\237',
+ '\240','\241','\242','\243','\244','\245','\246','\247',
+ '\250','\251','\252','\253','\254','\255','\256','\257',
+ '\260','\261','\262','\263','\264','\265','\266','\267',
+ '\270','\271','\272','\273','\274','\275','\276','\277',
+ '\300','\301','\302','\303','\304','\305','\306','\307',
+ '\310','\311','\312','\313','\314','\315','\316','\317',
+ '\320','\321','\322','\323','\324','\325','\326','\327',
+ '\330','\331','\332','\333','\334','\335','\336','\337',
+ '\340','\341','\342','\343','\344','\345','\346','\347',
+ '\350','\351','\352','\353','\354','\355','\356','\357',
+ '\360','\361','\362','\363','\364','\365','\366','\367',
+ '\370','\371','\372','\373','\374','\375','\376','\377',
+};
+
+/* Support for Korean(EUC_KR) characters, by powerm90@tinc.co.kr and mrpark@tinc.co.kr */
+
+#define iseuc_kr(c) ((0xa1<=(uchar)(c) && (uchar)(c)<=0xfe))
+
+
+int ismbchar_euc_kr(const char* p, const char *e)
+{
+ return ((*(uchar*)(p)<0x80)? 0:\
+ iseuc_kr(*(p)) && (e)-(p)>1 && iseuc_kr(*((p)+1))? 2:\
+ 0);
+}
+
+my_bool ismbhead_euc_kr(uint c)
+{
+ return (iseuc_kr(c));
+}
+
+int mbcharlen_euc_kr(uint c)
+{
+ return (iseuc_kr(c) ? 2 : 0);
+}
diff --git a/strings/ctype-gb2312.c b/strings/ctype-gb2312.c
new file mode 100644
index 00000000000..a587d72905e
--- /dev/null
+++ b/strings/ctype-gb2312.c
@@ -0,0 +1,180 @@
+/* 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 for Chinese EUC character sets (GB2312), and created by Miles Tsai (net-bull@126.com).
+ */
+
+/*
+ * This comment is parsed by configure to create ctype.c,
+ * so don't change it unless you know what you are doing.
+ *
+ * .configure. mbmaxlen_gb2312=2
+ */
+
+#include <global.h>
+#include "m_string.h"
+
+uchar NEAR ctype_gb2312[257] =
+{
+ 0, /* For standard library */
+ 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,
+ 0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
+ 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
+ 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
+ 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
+ 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
+ 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,
+};
+
+uchar NEAR to_lower_gb2312[]=
+{
+ '\000','\001','\002','\003','\004','\005','\006','\007',
+ '\010','\011','\012','\013','\014','\015','\016','\017',
+ '\020','\021','\022','\023','\024','\025','\026','\027',
+ '\030','\031','\032','\033','\034','\035','\036','\037',
+ ' ', '!', '"', '#', '$', '%', '&', '\'',
+ '(', ')', '*', '+', ',', '-', '.', '/',
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', ':', ';', '<', '=', '>', '?',
+ '@', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
+ 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
+ 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
+ 'x', 'y', 'z', '[', '\\', ']', '^', '_',
+ '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
+ 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
+ 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
+ 'x', 'y', 'z', '{', '|', '}', '~', '\177',
+ (uchar) '\200',(uchar) '\201',(uchar) '\202',(uchar) '\203',(uchar) '\204',(uchar) '\205',(uchar) '\206',(uchar) '\207',
+ (uchar) '\210',(uchar) '\211',(uchar) '\212',(uchar) '\213',(uchar) '\214',(uchar) '\215',(uchar) '\216',(uchar) '\217',
+ (uchar) '\220',(uchar) '\221',(uchar) '\222',(uchar) '\223',(uchar) '\224',(uchar) '\225',(uchar) '\226',(uchar) '\227',
+ (uchar) '\230',(uchar) '\231',(uchar) '\232',(uchar) '\233',(uchar) '\234',(uchar) '\235',(uchar) '\236',(uchar) '\237',
+ (uchar) '\240',(uchar) '\241',(uchar) '\242',(uchar) '\243',(uchar) '\244',(uchar) '\245',(uchar) '\246',(uchar) '\247',
+ (uchar) '\250',(uchar) '\251',(uchar) '\252',(uchar) '\253',(uchar) '\254',(uchar) '\255',(uchar) '\256',(uchar) '\257',
+ (uchar) '\260',(uchar) '\261',(uchar) '\262',(uchar) '\263',(uchar) '\264',(uchar) '\265',(uchar) '\266',(uchar) '\267',
+ (uchar) '\270',(uchar) '\271',(uchar) '\272',(uchar) '\273',(uchar) '\274',(uchar) '\275',(uchar) '\276',(uchar) '\277',
+ (uchar) '\300',(uchar) '\301',(uchar) '\302',(uchar) '\303',(uchar) '\304',(uchar) '\305',(uchar) '\306',(uchar) '\307',
+ (uchar) '\310',(uchar) '\311',(uchar) '\312',(uchar) '\313',(uchar) '\314',(uchar) '\315',(uchar) '\316',(uchar) '\317',
+ (uchar) '\320',(uchar) '\321',(uchar) '\322',(uchar) '\323',(uchar) '\324',(uchar) '\325',(uchar) '\326',(uchar) '\327',
+ (uchar) '\330',(uchar) '\331',(uchar) '\332',(uchar) '\333',(uchar) '\334',(uchar) '\335',(uchar) '\336',(uchar) '\337',
+ (uchar) '\340',(uchar) '\341',(uchar) '\342',(uchar) '\343',(uchar) '\344',(uchar) '\345',(uchar) '\346',(uchar) '\347',
+ (uchar) '\350',(uchar) '\351',(uchar) '\352',(uchar) '\353',(uchar) '\354',(uchar) '\355',(uchar) '\356',(uchar) '\357',
+ (uchar) '\360',(uchar) '\361',(uchar) '\362',(uchar) '\363',(uchar) '\364',(uchar) '\365',(uchar) '\366',(uchar) '\367',
+ (uchar) '\370',(uchar) '\371',(uchar) '\372',(uchar) '\373',(uchar) '\374',(uchar) '\375',(uchar) '\376',(uchar) '\377',
+};
+
+uchar NEAR to_upper_gb2312[]=
+{
+ '\000','\001','\002','\003','\004','\005','\006','\007',
+ '\010','\011','\012','\013','\014','\015','\016','\017',
+ '\020','\021','\022','\023','\024','\025','\026','\027',
+ '\030','\031','\032','\033','\034','\035','\036','\037',
+ ' ', '!', '"', '#', '$', '%', '&', '\'',
+ '(', ')', '*', '+', ',', '-', '.', '/',
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', ':', ';', '<', '=', '>', '?',
+ '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+ 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+ 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+ 'X', 'Y', 'Z', '[', '\\', ']', '^', '_',
+ '`', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+ 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+ 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+ 'X', 'Y', 'Z', '{', '|', '}', '~', '\177',
+ (uchar) '\200',(uchar) '\201',(uchar) '\202',(uchar) '\203',(uchar) '\204',(uchar) '\205',(uchar) '\206',(uchar) '\207',
+ (uchar) '\210',(uchar) '\211',(uchar) '\212',(uchar) '\213',(uchar) '\214',(uchar) '\215',(uchar) '\216',(uchar) '\217',
+ (uchar) '\220',(uchar) '\221',(uchar) '\222',(uchar) '\223',(uchar) '\224',(uchar) '\225',(uchar) '\226',(uchar) '\227',
+ (uchar) '\230',(uchar) '\231',(uchar) '\232',(uchar) '\233',(uchar) '\234',(uchar) '\235',(uchar) '\236',(uchar) '\237',
+ (uchar) '\240',(uchar) '\241',(uchar) '\242',(uchar) '\243',(uchar) '\244',(uchar) '\245',(uchar) '\246',(uchar) '\247',
+ (uchar) '\250',(uchar) '\251',(uchar) '\252',(uchar) '\253',(uchar) '\254',(uchar) '\255',(uchar) '\256',(uchar) '\257',
+ (uchar) '\260',(uchar) '\261',(uchar) '\262',(uchar) '\263',(uchar) '\264',(uchar) '\265',(uchar) '\266',(uchar) '\267',
+ (uchar) '\270',(uchar) '\271',(uchar) '\272',(uchar) '\273',(uchar) '\274',(uchar) '\275',(uchar) '\276',(uchar) '\277',
+ (uchar) '\300',(uchar) '\301',(uchar) '\302',(uchar) '\303',(uchar) '\304',(uchar) '\305',(uchar) '\306',(uchar) '\307',
+ (uchar) '\310',(uchar) '\311',(uchar) '\312',(uchar) '\313',(uchar) '\314',(uchar) '\315',(uchar) '\316',(uchar) '\317',
+ (uchar) '\320',(uchar) '\321',(uchar) '\322',(uchar) '\323',(uchar) '\324',(uchar) '\325',(uchar) '\326',(uchar) '\327',
+ (uchar) '\330',(uchar) '\331',(uchar) '\332',(uchar) '\333',(uchar) '\334',(uchar) '\335',(uchar) '\336',(uchar) '\337',
+ (uchar) '\340',(uchar) '\341',(uchar) '\342',(uchar) '\343',(uchar) '\344',(uchar) '\345',(uchar) '\346',(uchar) '\347',
+ (uchar) '\350',(uchar) '\351',(uchar) '\352',(uchar) '\353',(uchar) '\354',(uchar) '\355',(uchar) '\356',(uchar) '\357',
+ (uchar) '\360',(uchar) '\361',(uchar) '\362',(uchar) '\363',(uchar) '\364',(uchar) '\365',(uchar) '\366',(uchar) '\367',
+ (uchar) '\370',(uchar) '\371',(uchar) '\372',(uchar) '\373',(uchar) '\374',(uchar) '\375',(uchar) '\376',(uchar) '\377',
+};
+
+uchar NEAR sort_order_gb2312[]=
+{
+ '\000','\001','\002','\003','\004','\005','\006','\007',
+ '\010','\011','\012','\013','\014','\015','\016','\017',
+ '\020','\021','\022','\023','\024','\025','\026','\027',
+ '\030','\031','\032','\033','\034','\035','\036','\037',
+ ' ', '!', '"', '#', '$', '%', '&', '\'',
+ '(', ')', '*', '+', ',', '-', '.', '/',
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', ':', ';', '<', '=', '>', '?',
+ '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+ 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+ 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+ 'X', 'Y', 'Z', '\\', ']', '[', '^', '_',
+ '`', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+ 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+ 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+ 'X', 'Y', 'Z', '{', '|', '}', 'Y', '\177',
+ (uchar) '\200',(uchar) '\201',(uchar) '\202',(uchar) '\203',(uchar) '\204',(uchar) '\205',(uchar) '\206',(uchar) '\207',
+ (uchar) '\210',(uchar) '\211',(uchar) '\212',(uchar) '\213',(uchar) '\214',(uchar) '\215',(uchar) '\216',(uchar) '\217',
+ (uchar) '\220',(uchar) '\221',(uchar) '\222',(uchar) '\223',(uchar) '\224',(uchar) '\225',(uchar) '\226',(uchar) '\227',
+ (uchar) '\230',(uchar) '\231',(uchar) '\232',(uchar) '\233',(uchar) '\234',(uchar) '\235',(uchar) '\236',(uchar) '\237',
+ (uchar) '\240',(uchar) '\241',(uchar) '\242',(uchar) '\243',(uchar) '\244',(uchar) '\245',(uchar) '\246',(uchar) '\247',
+ (uchar) '\250',(uchar) '\251',(uchar) '\252',(uchar) '\253',(uchar) '\254',(uchar) '\255',(uchar) '\256',(uchar) '\257',
+ (uchar) '\260',(uchar) '\261',(uchar) '\262',(uchar) '\263',(uchar) '\264',(uchar) '\265',(uchar) '\266',(uchar) '\267',
+ (uchar) '\270',(uchar) '\271',(uchar) '\272',(uchar) '\273',(uchar) '\274',(uchar) '\275',(uchar) '\276',(uchar) '\277',
+ (uchar) '\300',(uchar) '\301',(uchar) '\302',(uchar) '\303',(uchar) '\304',(uchar) '\305',(uchar) '\306',(uchar) '\307',
+ (uchar) '\310',(uchar) '\311',(uchar) '\312',(uchar) '\313',(uchar) '\314',(uchar) '\315',(uchar) '\316',(uchar) '\317',
+ (uchar) '\320',(uchar) '\321',(uchar) '\322',(uchar) '\323',(uchar) '\324',(uchar) '\325',(uchar) '\326',(uchar) '\327',
+ (uchar) '\330',(uchar) '\331',(uchar) '\332',(uchar) '\333',(uchar) '\334',(uchar) '\335',(uchar) '\336',(uchar) '\337',
+ (uchar) '\340',(uchar) '\341',(uchar) '\342',(uchar) '\343',(uchar) '\344',(uchar) '\345',(uchar) '\346',(uchar) '\347',
+ (uchar) '\350',(uchar) '\351',(uchar) '\352',(uchar) '\353',(uchar) '\354',(uchar) '\355',(uchar) '\356',(uchar) '\357',
+ (uchar) '\360',(uchar) '\361',(uchar) '\362',(uchar) '\363',(uchar) '\364',(uchar) '\365',(uchar) '\366',(uchar) '\367',
+ (uchar) '\370',(uchar) '\371',(uchar) '\372',(uchar) '\373',(uchar) '\374',(uchar) '\375',(uchar) '\376',(uchar) '\377',
+};
+
+/* Support for Chinese(GB2312) characters, by Miles Tsai (net-bull@126.com)
+ modified by Wei He (hewei@mail.ied.ac.cn) */
+
+#define isgb2312head(c) (0xa1<=(uchar)(c) && (uchar)(c)<=0xf7)
+#define isgb2312tail(c) (0xa1<=(uchar)(c) && (uchar)(c)<=0xfe)
+
+
+int ismbchar_gb2312(const char* p, const char *e)
+{
+ return (isgb2312head(*(p)) && (e)-(p)>1 && isgb2312tail(*((p)+1))? 2: 0);
+}
+
+my_bool ismbhead_gb2312(uint c)
+{
+ return isgb2312head(c);
+}
+
+int mbcharlen_gb2312(uint c)
+{
+ return (isgb2312head(c)? 2:0);
+}
diff --git a/strings/ctype-gbk.c b/strings/ctype-gbk.c
new file mode 100644
index 00000000000..9628f21b8d4
--- /dev/null
+++ b/strings/ctype-gbk.c
@@ -0,0 +1,2722 @@
+/* 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 for Chinese character sets GBK, created by Wei He
+ (hewei@mail.ied.ac.cn)
+*/
+
+/*
+ * 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_gbk=1
+ * .configure. mbmaxlen_gbk=2
+ */
+
+
+#include <global.h>
+#include "m_string.h"
+#include "m_ctype.h"
+
+/* Support for Chinese(GBK) characters, by hewei@mail.ied.ac.cn */
+
+#define isgbkhead(c) (0x81<=(uchar)(c) && (uchar)(c)<=0xfe)
+#define isgbktail(c) ((0x40<=(uchar)(c) && (uchar)(c)<=0x7e) || \
+ (0x80<=(uchar)(c) && (uchar)(c)<=0xfe))
+
+#define isgbkcode(c,d) (isgbkhead(c) && isgbktail(d))
+#define gbkcode(c,d) ((((uint) (uchar) (c)) <<8) | (uchar)(d))
+#define gbkhead(e) ((uchar)(e>>8))
+#define gbktail(e) ((uchar)(e&0xff))
+
+uchar NEAR ctype_gbk[257] =
+{
+ 0, /* For standard library */
+ 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,
+ 0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
+ 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
+ 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
+ 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
+ 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
+ 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,
+};
+
+uchar NEAR to_lower_gbk[]=
+{
+ '\000','\001','\002','\003','\004','\005','\006','\007',
+ '\010','\011','\012','\013','\014','\015','\016','\017',
+ '\020','\021','\022','\023','\024','\025','\026','\027',
+ '\030','\031','\032','\033','\034','\035','\036','\037',
+ ' ', '!', '"', '#', '$', '%', '&', '\'',
+ '(', ')', '*', '+', ',', '-', '.', '/',
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', ':', ';', '<', '=', '>', '?',
+ '@', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
+ 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
+ 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
+ 'x', 'y', 'z', '[', '\\', ']', '^', '_',
+ '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
+ 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
+ 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
+ 'x', 'y', 'z', '{', '|', '}', '~', '\177',
+ (uchar) '\200',(uchar) '\201',(uchar) '\202',(uchar) '\203',(uchar) '\204',(uchar) '\205',(uchar) '\206',(uchar) '\207',
+ (uchar) '\210',(uchar) '\211',(uchar) '\212',(uchar) '\213',(uchar) '\214',(uchar) '\215',(uchar) '\216',(uchar) '\217',
+ (uchar) '\220',(uchar) '\221',(uchar) '\222',(uchar) '\223',(uchar) '\224',(uchar) '\225',(uchar) '\226',(uchar) '\227',
+ (uchar) '\230',(uchar) '\231',(uchar) '\232',(uchar) '\233',(uchar) '\234',(uchar) '\235',(uchar) '\236',(uchar) '\237',
+ (uchar) '\240',(uchar) '\241',(uchar) '\242',(uchar) '\243',(uchar) '\244',(uchar) '\245',(uchar) '\246',(uchar) '\247',
+ (uchar) '\250',(uchar) '\251',(uchar) '\252',(uchar) '\253',(uchar) '\254',(uchar) '\255',(uchar) '\256',(uchar) '\257',
+ (uchar) '\260',(uchar) '\261',(uchar) '\262',(uchar) '\263',(uchar) '\264',(uchar) '\265',(uchar) '\266',(uchar) '\267',
+ (uchar) '\270',(uchar) '\271',(uchar) '\272',(uchar) '\273',(uchar) '\274',(uchar) '\275',(uchar) '\276',(uchar) '\277',
+ (uchar) '\300',(uchar) '\301',(uchar) '\302',(uchar) '\303',(uchar) '\304',(uchar) '\305',(uchar) '\306',(uchar) '\307',
+ (uchar) '\310',(uchar) '\311',(uchar) '\312',(uchar) '\313',(uchar) '\314',(uchar) '\315',(uchar) '\316',(uchar) '\317',
+ (uchar) '\320',(uchar) '\321',(uchar) '\322',(uchar) '\323',(uchar) '\324',(uchar) '\325',(uchar) '\326',(uchar) '\327',
+ (uchar) '\330',(uchar) '\331',(uchar) '\332',(uchar) '\333',(uchar) '\334',(uchar) '\335',(uchar) '\336',(uchar) '\337',
+ (uchar) '\340',(uchar) '\341',(uchar) '\342',(uchar) '\343',(uchar) '\344',(uchar) '\345',(uchar) '\346',(uchar) '\347',
+ (uchar) '\350',(uchar) '\351',(uchar) '\352',(uchar) '\353',(uchar) '\354',(uchar) '\355',(uchar) '\356',(uchar) '\357',
+ (uchar) '\360',(uchar) '\361',(uchar) '\362',(uchar) '\363',(uchar) '\364',(uchar) '\365',(uchar) '\366',(uchar) '\367',
+ (uchar) '\370',(uchar) '\371',(uchar) '\372',(uchar) '\373',(uchar) '\374',(uchar) '\375',(uchar) '\376',(uchar) '\377',
+};
+
+uchar NEAR to_upper_gbk[]=
+{
+ '\000','\001','\002','\003','\004','\005','\006','\007',
+ '\010','\011','\012','\013','\014','\015','\016','\017',
+ '\020','\021','\022','\023','\024','\025','\026','\027',
+ '\030','\031','\032','\033','\034','\035','\036','\037',
+ ' ', '!', '"', '#', '$', '%', '&', '\'',
+ '(', ')', '*', '+', ',', '-', '.', '/',
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', ':', ';', '<', '=', '>', '?',
+ '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+ 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+ 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+ 'X', 'Y', 'Z', '[', '\\', ']', '^', '_',
+ '`', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+ 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+ 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+ 'X', 'Y', 'Z', '{', '|', '}', '~', '\177',
+ (uchar) '\200',(uchar) '\201',(uchar) '\202',(uchar) '\203',(uchar) '\204',(uchar) '\205',(uchar) '\206',(uchar) '\207',
+ (uchar) '\210',(uchar) '\211',(uchar) '\212',(uchar) '\213',(uchar) '\214',(uchar) '\215',(uchar) '\216',(uchar) '\217',
+ (uchar) '\220',(uchar) '\221',(uchar) '\222',(uchar) '\223',(uchar) '\224',(uchar) '\225',(uchar) '\226',(uchar) '\227',
+ (uchar) '\230',(uchar) '\231',(uchar) '\232',(uchar) '\233',(uchar) '\234',(uchar) '\235',(uchar) '\236',(uchar) '\237',
+ (uchar) '\240',(uchar) '\241',(uchar) '\242',(uchar) '\243',(uchar) '\244',(uchar) '\245',(uchar) '\246',(uchar) '\247',
+ (uchar) '\250',(uchar) '\251',(uchar) '\252',(uchar) '\253',(uchar) '\254',(uchar) '\255',(uchar) '\256',(uchar) '\257',
+ (uchar) '\260',(uchar) '\261',(uchar) '\262',(uchar) '\263',(uchar) '\264',(uchar) '\265',(uchar) '\266',(uchar) '\267',
+ (uchar) '\270',(uchar) '\271',(uchar) '\272',(uchar) '\273',(uchar) '\274',(uchar) '\275',(uchar) '\276',(uchar) '\277',
+ (uchar) '\300',(uchar) '\301',(uchar) '\302',(uchar) '\303',(uchar) '\304',(uchar) '\305',(uchar) '\306',(uchar) '\307',
+ (uchar) '\310',(uchar) '\311',(uchar) '\312',(uchar) '\313',(uchar) '\314',(uchar) '\315',(uchar) '\316',(uchar) '\317',
+ (uchar) '\320',(uchar) '\321',(uchar) '\322',(uchar) '\323',(uchar) '\324',(uchar) '\325',(uchar) '\326',(uchar) '\327',
+ (uchar) '\330',(uchar) '\331',(uchar) '\332',(uchar) '\333',(uchar) '\334',(uchar) '\335',(uchar) '\336',(uchar) '\337',
+ (uchar) '\340',(uchar) '\341',(uchar) '\342',(uchar) '\343',(uchar) '\344',(uchar) '\345',(uchar) '\346',(uchar) '\347',
+ (uchar) '\350',(uchar) '\351',(uchar) '\352',(uchar) '\353',(uchar) '\354',(uchar) '\355',(uchar) '\356',(uchar) '\357',
+ (uchar) '\360',(uchar) '\361',(uchar) '\362',(uchar) '\363',(uchar) '\364',(uchar) '\365',(uchar) '\366',(uchar) '\367',
+ (uchar) '\370',(uchar) '\371',(uchar) '\372',(uchar) '\373',(uchar) '\374',(uchar) '\375',(uchar) '\376',(uchar) '\377',
+};
+
+uchar NEAR sort_order_gbk[]=
+{
+ '\000','\001','\002','\003','\004','\005','\006','\007',
+ '\010','\011','\012','\013','\014','\015','\016','\017',
+ '\020','\021','\022','\023','\024','\025','\026','\027',
+ '\030','\031','\032','\033','\034','\035','\036','\037',
+ ' ', '!', '"', '#', '$', '%', '&', '\'',
+ '(', ')', '*', '+', ',', '-', '.', '/',
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', ':', ';', '<', '=', '>', '?',
+ '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+ 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+ 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+ 'X', 'Y', 'Z', '\\', ']', '[', '^', '_',
+ '`', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+ 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+ 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+ 'X', 'Y', 'Z', '{', '|', '}', 'Y', '\177',
+ (uchar) '\200',(uchar) '\201',(uchar) '\202',(uchar) '\203',(uchar) '\204',(uchar) '\205',(uchar) '\206',(uchar) '\207',
+ (uchar) '\210',(uchar) '\211',(uchar) '\212',(uchar) '\213',(uchar) '\214',(uchar) '\215',(uchar) '\216',(uchar) '\217',
+ (uchar) '\220',(uchar) '\221',(uchar) '\222',(uchar) '\223',(uchar) '\224',(uchar) '\225',(uchar) '\226',(uchar) '\227',
+ (uchar) '\230',(uchar) '\231',(uchar) '\232',(uchar) '\233',(uchar) '\234',(uchar) '\235',(uchar) '\236',(uchar) '\237',
+ (uchar) '\240',(uchar) '\241',(uchar) '\242',(uchar) '\243',(uchar) '\244',(uchar) '\245',(uchar) '\246',(uchar) '\247',
+ (uchar) '\250',(uchar) '\251',(uchar) '\252',(uchar) '\253',(uchar) '\254',(uchar) '\255',(uchar) '\256',(uchar) '\257',
+ (uchar) '\260',(uchar) '\261',(uchar) '\262',(uchar) '\263',(uchar) '\264',(uchar) '\265',(uchar) '\266',(uchar) '\267',
+ (uchar) '\270',(uchar) '\271',(uchar) '\272',(uchar) '\273',(uchar) '\274',(uchar) '\275',(uchar) '\276',(uchar) '\277',
+ (uchar) '\300',(uchar) '\301',(uchar) '\302',(uchar) '\303',(uchar) '\304',(uchar) '\305',(uchar) '\306',(uchar) '\307',
+ (uchar) '\310',(uchar) '\311',(uchar) '\312',(uchar) '\313',(uchar) '\314',(uchar) '\315',(uchar) '\316',(uchar) '\317',
+ (uchar) '\320',(uchar) '\321',(uchar) '\322',(uchar) '\323',(uchar) '\324',(uchar) '\325',(uchar) '\326',(uchar) '\327',
+ (uchar) '\330',(uchar) '\331',(uchar) '\332',(uchar) '\333',(uchar) '\334',(uchar) '\335',(uchar) '\336',(uchar) '\337',
+ (uchar) '\340',(uchar) '\341',(uchar) '\342',(uchar) '\343',(uchar) '\344',(uchar) '\345',(uchar) '\346',(uchar) '\347',
+ (uchar) '\350',(uchar) '\351',(uchar) '\352',(uchar) '\353',(uchar) '\354',(uchar) '\355',(uchar) '\356',(uchar) '\357',
+ (uchar) '\360',(uchar) '\361',(uchar) '\362',(uchar) '\363',(uchar) '\364',(uchar) '\365',(uchar) '\366',(uchar) '\367',
+ (uchar) '\370',(uchar) '\371',(uchar) '\372',(uchar) '\373',(uchar) '\374',(uchar) '\375',(uchar) '\376',(uchar) '\377',
+};
+
+static uint16 NEAR gbk_order[]=
+{
+8653,14277,17116,11482,11160,2751,14613,3913,13337,9827,
+19496,1759,8105,7103,7836,5638,2223,21433,5878,8006,
+4851,18766,18879,16728,8129,6200,19133,6389,2500,19084,
+16228,5074,8130,5900,6201,3985,14597,11566,8588,8769,
+15885,11411,11965,1961,18012,18303,12242,14118,11490,12911,
+15015,4367,3184,2093,20937,5710,5108,10560,9993,18982,
+8393,10697,14620,19558,14970,15193,5359,18189,12666,18192,
+3310,18659,17358,7973,18673,19537,3404,9723,4221,16486,
+7023,13648,16310,1049,1726,4799,15534,4366,17133,4192,
+6219,5118,1804,2360,2279,14279,13740,4511,2361,12906,
+16650,18590,4723,2001,16313,3594,21026,12146,19561,3800,
+4161,16774,18892,17657,7025,892,7917,12245,3394,4813,
+11902,3189,20002,2365,12964,18115,17660,20227,17182,11907,
+11671,17562,17864,21131,13423,1361,12246,18897,14978,18848,
+20727,5902,10726,21241,1906,13424,1408,20519,3038,18495,
+20446,1431,17138,13464,14558,1221,6720,6137,17348,5268,
+4448,11313,1760,6172,6870,5744,13541,3044,17701,14368,
+16114,5051,9142,18776,5669,19089,11088,17867,925,10395,
+4372,10578,2138,2554,18118,21087,13862,7461,14983,3322,
+15305,11844,7924,8087,2542,20701,21772,2754,10490,8218,
+14800,15869,14436,16119,1814,11543,17398,16069,19659,17020,
+17844,5694,8833,16744,18925,4957,9812,6852,8036,12966,
+14038,12145,16833,11165,17076,17756,3673,2367,20916,9143,
+14927,6885,17486,7469,1661,2827,4627,18198,1307,19711,
+17637,2595,2262,20807,1764,8150,18547,3192,9711,16262,
+9144,2006,21629,5311,15743,14733,10991,15402,2916,17724,
+12195,12622,5141,8039,15169,7780,4568,20835,21575,10580,
+15022,9470,6853,3926,21563,1342,16745,8181,11526,1947,
+7402,18641,14145,13149,19222,2468,12920,13916,21077,2968,
+16438,19667,1768,15632,18374,4738,15517,16655,4309,2374,
+14492,8602,3679,2103,1312,18681,6613,18604,20451,2755,
+18218,19473,17854,20316,3003,4998,1391,20938,11169,7049,
+18861,17577,18091,1937,4085,2059,20633,15948,1313,20138,
+7785,16439,15081,20955,15117,17065,19924,13831,11913,20062,
+7568,10703,3717,15480,6047,7790,16867,14223,12971,8429,
+2008,2833,14026,1317,17493,19411,18551,15452,15257,18504,
+4441,1769,7249,20128,5509,1970,9420,19365,20190,21617,
+12202,15041,2871,19676,20388,21674,14258,2901,8058,5970,
+20472,13257,18226,3694,17591,10279,1318,12409,7901,9794,
+10416,10769,12876,17154,15455,19298,3970,21327,14228,13095,
+8096,16072,21748,12581,9326,2311,5683,12641,3583,2184,
+16464,6969,1795,6778,2880,15819,3433,7674,4713,17297,
+8231,4333,9995,1841,5558,17155,17298,11283,18694,7946,
+7311,13129,4753,21149,905,14010,18821,8532,11873,2190,
+19006,3456,8874,7433,2841,7680,14143,20130,1993,1699,
+976,15361,2736,2154,9202,11685,7951,12982,11008,16763,
+11829,13327,11686,2299,9940,10507,8917,1277,19790,1636,
+20143,21002,15011,19443,6026,13299,2455,9667,15612,16477,
+10261,2811,2202,13674,14760,6818,9691,10624,20145,11940,
+15524,18349,9437,11578,20132,17736,4121,4122,16023,2280,
+4371,4373,7873,18307,14602,14695,13054,5410,6065,14389,
+3979,1137,5411,6672,16311,11632,9829,19575,5901,15708,
+12553,7165,18983,10860,13664,18242,10848,2049,8075,5579,
+8083,10863,21136,5445,17851,19132,8597,18771,11054,14631,
+10997,8292,8803,11246,4999,17559,11134,15369,5155,6407,
+12054,4857,11265,12834,7322,15057,10937,15984,5544,8040,
+13291,3961,5142,19101,869,9631,2009,11315,21404,3172,
+14941,4204,7947,9997,16906,4035,4476,4477,8171,2818,
+20725,4724,11453,20868,4725,4729,8565,5109,12490,8862,
+5920,13737,2888,6930,12963,3223,6934,3395,16243,8397,
+9475,4858,13515,3777,11266,10029,21028,1671,7765,7766,
+14169,2221,5328,2907,8951,4225,4416,7770,3046,8014,
+3975,10636,20236,19825,3248,8717,2140,2908,3249,9477,
+4628,2225,12676,2909,21564,5167,1225,4186,13266,4017,
+7471,7146,18214,6890,4195,16037,16688,5583,14497,7476,
+3286,8566,2910,2862,2232,16038,10417,9492,12234,14190,
+8793,5573,6486,20322,21455,9734,8317,10143,5781,7681,
+5782,7500,7501,15466,7188,7511,7512,21003,2203,21693,
+11350,9540,21212,18183,7918,8754,17511,20869,18899,21160,
+11356,9315,8364,8798,18460,16189,17483,11415,8897,7771,
+9917,8718,7926,5228,11270,2644,9269,19404,8719,8367,
+13267,10400,1914,2157,8584,11171,3964,17881,16785,18951,
+18052,16616,14500,9323,10418,12410,14661,6963,7570,7668,
+13601,17386,18995,8437,4460,8346,15920,8318,3387,10734,
+18057,18058,10525,9654,2390,13675,13603,20000,8106,1260,
+10824,1426,5075,5076,18887,12175,8174,15558,5269,4304,
+5380,3287,8156,5386,11605,8142,18768,7580,8641,6319,
+13425,4478,13147,2019,8900,6331,19668,5756,6769,3381,
+9009,9730,9735,15160,4036,8167,13489,17009,8667,18308,
+13439,18112,11735,21667,14617,17010,16290,16291,17515,3368,
+7050,14841,5636,16826,17573,7760,18493,13306,14312,2619,
+17868,13609,8991,7038,4310,16881,14020,16422,20565,5941,
+18174,3642,20346,12080,856,13144,18158,20908,10800,15630,
+14340,15837,21707,4629,2060,19870,9632,3718,7902,994,
+5762,18391,9647,2312,9199,9648,18281,18342,19911,5367,
+9950,13834,13513,8771,9414,4057,21302,1963,1964,1967,
+902,3349,14697,5602,1071,13959,14621,21428,7288,15079,
+7039,16495,13949,3111,5580,13365,2615,4109,6202,11213,
+10792,17918,21538,3226,18658,11985,6862,18734,2752,13232,
+7838,1907,4252,6223,16703,11495,18037,3974,6301,5226,
+8514,10487,5267,10892,12763,16706,7702,20003,2616,14457,
+16083,16587,4296,14513,8355,12171,16590,10670,13651,3646,
+14626,21132,15826,17015,18911,12792,12461,21545,17848,18912,
+17396,3277,13516,5918,16115,12548,1673,4864,18438,6078,
+5880,3263,16211,21784,1909,15296,17183,6884,12796,4417,
+4299,17021,21137,14801,17484,8852,6512,15560,4300,17921,
+5819,9342,15900,17742,19525,3869,11715,17703,12554,6040,
+19865,10267,12549,10804,21670,6091,17277,9319,12531,9840,
+1060,11215,10514,15170,4892,5904,14898,19534,5469,5470,
+1128,5922,18937,7270,15971,17189,16263,9474,13382,2369,
+20210,18177,3976,12767,3618,13236,10885,5397,15621,8770,
+9830,9310,14121,21573,16634,19148,12803,4381,13051,956,
+20237,3755,19551,15744,9169,16852,866,11893,21439,3680,
+6197,17412,17324,16086,16747,16602,3834,5510,12770,12771,
+3420,16198,21552,1421,3198,6097,18178,12772,20576,9831,
+17200,19226,5584,20226,5822,10609,11641,3599,13550,15387,
+5361,15481,952,3426,19731,20581,21103,2153,16223,19719,
+20139,18533,11172,6356,20044,6584,6585,6954,21058,16397,
+14150,17888,6618,4199,11775,9843,19732,14051,2564,13093,
+18379,3377,12174,1968,19359,16350,19294,12243,1294,5362,
+20214,6898,15645,18557,6146,13005,14084,19366,6272,17534,
+10713,2104,5894,13900,16200,6964,12093,16692,12975,21496,
+9358,16216,7314,15280,3056,14008,5363,11510,13001,1474,
+997,9724,21709,20612,11383,15441,7715,2684,7622,8585,
+15456,14192,872,17497,10281,17428,6338,6779,5831,11989,
+17156,20245,2293,12512,3560,10705,6367,5040,15465,18663,
+14003,7716,17498,6462,10721,13660,9327,17501,6973,9010,
+17433,6024,10669,13098,2842,15393,3436,18133,4283,21749,
+4461,2571,6707,1986,2900,3138,3434,19771,9090,16900,
+12816,6022,9736,17830,6708,19167,18099,11781,14950,18337,
+19249,3270,20404,21152,11875,6791,17596,7723,19933,884,
+19376,8877,19687,12164,3544,17647,4150,3457,17648,12338,
+19127,21715,11831,3635,9259,15329,6901,17127,18710,4191,
+12352,21112,7195,7956,2300,18061,10887,15701,10319,6808,
+1859,19445,11794,19170,6436,10969,6216,20594,9522,10157,
+5898,11567,11326,18410,9674,10340,10229,11345,3447,2456,
+12439,12340,17368,10889,17057,4224,8845,18285,2207,19263,
+3872,9117,15331,17456,2995,6523,6919,21337,11803,17457,
+1936,9533,2248,2161,9697,19072,10607,20163,15100,6199,
+20287,7392,20107,21238,9225,11809,13650,10203,6717,19085,
+11816,16035,8643,19823,8084,12359,20004,3059,6719,4253,
+5838,15886,15982,5839,13638,13780,5840,15341,5842,19140,
+6854,5923,10582,5843,2868,16398,19872,13534,8824,12598,
+19879,19880,18208,16051,16004,16005,16039,10567,6783,19020,
+10539,10550,18184,16018,15868,12573,10392,8863,8172,19697,
+12845,12846,21424,3476,12833,17119,14167,11764,11357,7264,
+20873,18048,18901,13220,4667,8756,16106,4705,1432,8009,
+3665,7966,7128,2587,7967,12053,15477,13430,20832,5587,
+15350,8076,18496,4801,10396,13339,5438,18013,1074,10032,
+21247,4985,6322,20909,989,3323,12104,11235,7138,6138,
+10512,3008,2621,19090,6306,4110,20541,4877,5674,18543,
+4231,5748,2116,18465,17517,14702,1762,6233,3281,8548,
+3479,6000,954,17677,17278,1186,4803,1097,18938,19207,
+5954,17874,2917,13191,1374,4557,13610,19406,8518,7240,
+3675,9306,8357,7882,20573,9913,6446,1915,8078,18661,
+3600,18200,13551,15199,13252,16268,8298,10602,20739,8775,
+2704,3928,15450,1948,2829,1375,8603,4214,18952,20841,
+21403,12685,8299,11653,8726,9031,11701,7331,5169,19721,
+4311,5546,9471,4548,18163,9032,972,14386,11607,15974,
+2517,6540,1462,9789,5823,21324,1244,19595,10838,7744,
+13909,18685,5360,21578,19596,6619,4318,18552,1268,3013,
+10906,2309,16148,12551,4773,21079,7858,7887,6198,5174,
+2935,8605,12479,9418,17729,6610,4093,16233,17928,17030,
+7062,8871,19299,19417,8569,15122,14579,11123,16618,2526,
+15997,13618,21060,9639,12203,1209,20185,4112,15728,16751,
+20767,18053,20711,898,5381,18272,8607,16540,17592,10190,
+5887,9300,2294,12204,1384,2426,10427,10374,11972,12978,
+10920,11384,16040,14865,10301,1622,2072,20975,20512,8617,
+3765,2439,20849,7172,5829,13045,7943,3700,3174,18392,
+15307,20290,12928,16506,21383,13068,14230,14231,1088,12583,
+8875,3942,4462,13626,4146,3217,3701,14505,4242,4245,
+15413,3587,11432,4684,6631,15414,3271,18690,21282,7502,
+1039,13032,13072,8748,19021,12316,3766,7551,18665,1852,
+15419,9243,8322,6513,3492,13684,12987,18062,9260,16999,
+906,18151,3529,13911,7957,9427,8940,10341,18286,15427,
+16481,6514,10263,10264,13950,9675,9985,2208,18070,18291,
+9406,1106,16240,14024,21355,18735,10727,21254,21358,6353,
+9064,6357,17889,9070,14715,10820,4147,14718,18755,5496,
+7582,4769,20373,1592,15166,13637,10033,3251,17753,17613,
+11596,17130,19916,10850,4182,13264,11964,5447,12805,11003,
+11047,2440,20269,5601,5209,15535,15370,18300,1406,6926,
+20037,7229,1056,4359,3596,12118,8363,17518,3735,18497,
+6573,8553,20360,1351,6662,4610,3780,18127,1363,1032,
+16617,12536,16800,1037,7571,9731,4203,19993,7572,14677,
+4715,6902,1527,10540,2376,3886,12847,8131,11926,2135,
+17136,4517,7104,6221,3365,4816,8031,5875,16599,21029,
+11997,5995,21069,20005,4807,2552,8400,21341,18361,11496,
+17629,4669,4726,16292,4072,1075,21429,20521,11523,19918,
+15958,17185,18913,4247,11358,1436,14370,4248,6080,17849,
+4434,20728,11236,1173,4817,10034,21539,13666,14173,18439,
+10741,21482,8275,13754,3952,7040,5056,17377,6456,8339,
+5443,7327,7328,11738,20834,20673,17273,6182,5675,8491,
+8847,18364,11314,9918,12150,4302,19527,18255,14375,14566,
+5749,13543,15020,6234,17279,14316,2502,17574,10805,4827,
+11443,8723,2979,2980,15870,17708,11546,19581,12503,11626,
+20926,5924,21344,12472,16076,17280,16710,18256,16748,16841,
+18260,19582,14989,9609,8190,21375,12628,17194,21440,3929,
+10404,879,4249,10275,11146,3095,12550,8191,1949,10054,
+17413,14766,12773,6692,5001,16647,16648,15405,4581,4582,
+15709,11654,13552,8046,7979,12868,3756,17726,6421,16231,
+9150,19109,21097,11614,5002,10583,973,9033,19149,18201,
+8192,9622,3737,17195,6447,6480,3483,18605,11564,13964,
+7294,15949,19734,16351,3689,13838,10941,3378,13918,13178,
+6693,16657,12924,2936,11189,5005,7831,4086,18806,21080,
+6620,11148,932,19228,17929,7745,16352,20747,13345,15635,
+17584,16171,9790,10871,13670,14932,12361,16502,16199,3132,
+6358,7791,1245,17817,15950,5715,21662,18558,19882,13796,
+13901,10132,10944,12039,1026,10672,9002,13206,20689,19883,
+7746,13800,11302,19235,15124,11752,15542,12085,9276,11609,
+1235,12346,18996,19759,17966,10773,18749,8627,19370,11703,
+5719,7905,21307,20246,5908,9361,20563,6426,6427,1034,
+13922,10677,12423,5487,16758,13099,16174,20438,11193,17210,
+17211,11392,9864,9712,6490,5723,3572,20852,17832,18753,
+6482,16901,9011,13705,18396,2181,7625,10946,4534,4463,
+17161,19022,6168,7724,4536,14680,15209,13033,9774,17945,
+17649,11755,3943,19023,1971,907,11742,11832,10673,15800,
+2738,7958,3028,19632,12437,13822,13876,11528,18236,15363,
+19255,12988,19972,11154,1403,14431,17732,11711,4037,10186,
+19849,9247,18411,10100,7696,11743,9249,17172,19264,14855,
+6822,13579,11104,9538,10541,18292,21213,9251,8394,21477,
+17662,14984,15342,19522,21318,15232,11216,3096,12869,18145,
+11682,21506,9501,18022,1877,11517,11798,19265,10542,13830,
+13303,7230,13858,18591,18772,8010,21395,21223,6229,14563,
+18794,15793,14603,2503,13642,5375,17403,20364,3516,14419,
+6659,11115,8804,1950,20141,19831,13343,6142,20637,7482,
+11825,1770,6541,13226,14576,11826,7938,11847,20963,19677,
+1247,8885,11827,8312,13229,6339,14584,11828,14425,16469,
+17560,8886,6784,8533,19039,18830,1257,13187,2705,1258,
+4762,10511,4124,12519,21303,4828,8724,7588,21305,18092,
+14812,4131,3527,7762,4393,4394,14764,14280,11327,9907,
+17242,17243,9046,16304,9904,10796,16305,16306,16307,18541,
+4232,8998,21059,5110,5515,16061,5115,5116,17012,1390,
+7844,15716,3798,14519,20669,17576,11649,16842,16843,10758,
+10309,12474,15684,4631,17585,10500,2084,17597,8329,8391,
+9883,8392,21237,17624,11692,16188,17134,9579,4288,3503,
+6742,10206,13743,16775,5949,14364,2765,18725,19947,1157,
+18592,981,16777,7768,4290,4670,16248,12907,12663,7839,
+21769,21770,18498,8276,5161,18015,12501,9591,15773,13432,
+4865,16137,12288,1030,8924,13433,12525,15774,10036,2589,
+12463,2091,1185,15898,18016,1588,6083,8721,10649,4303,
+4990,3826,10399,4363,4375,5057,13530,18786,11438,14567,
+926,16386,6533,11113,9552,7139,3954,16387,19529,5502,
+9919,18545,7610,4258,17519,1884,13639,4736,11585,9555,
+19464,17281,13793,3517,14382,2504,15985,5349,5231,17082,
+19141,19665,9307,8616,17234,13611,2695,15316,9955,6478,
+8193,9151,11248,9034,9035,21671,5547,18164,5179,10584,
+10585,10055,4187,20740,19151,3965,5926,20741,16440,12301,
+7787,21672,8823,3930,19152,21490,20275,6621,19597,18474,
+4742,13395,18475,15636,18862,20956,14654,4319,21271,8594,
+10518,18318,10942,5932,6955,6586,15855,16795,19598,21579,
+9193,8712,18267,18268,16447,21580,2121,15200,8679,13179,
+12699,15998,4113,16882,16619,2010,15485,13801,7795,870,
+10133,16801,13060,1368,3719,12950,19418,11778,3238,14580,
+13968,15043,21588,7596,9858,8628,2233,3853,2076,3890,
+15978,10302,20433,20434,998,2031,13447,13009,3175,21713,
+3524,3525,16958,19760,12160,10221,17387,2085,1796,13182,
+7626,18232,9328,20458,9866,9867,7890,4243,21738,7721,
+8441,18574,7627,18575,8442,20405,19024,18023,11593,18705,
+18706,18824,11788,17251,7074,17601,8707,5724,3710,1040,
+21730,16369,13823,3530,10114,7818,19688,19975,19196,13859,
+7823,9660,5732,10230,10231,19319,16937,8244,2209,19345,
+8961,18287,11599,13580,2359,3159,10543,3729,3730,11805,
+18293,18294,18354,8989,18295,8861,6605,7968,2341,9938,
+8768,12561,12562,13406,20792,20522,18795,7897,15252,13598,
+12240,4852,20087,3876,11763,4648,12010,20874,6409,3412,
+3325,11359,4866,11367,18927,18928,12467,12835,8356,13863,
+14839,14878,13123,20625,14523,13643,3336,5707,12475,20508,
+7408,16232,3339,14148,12687,4061,6287,20780,17818,16400,
+18969,1192,12480,3839,5382,12040,15543,11124,7309,15602,
+6704,21044,14193,1623,5847,20247,11469,1193,8019,2236,
+20985,6342,1492,1504,20496,11136,13073,2171,4685,11015,
+1195,2739,11224,2793,7816,17258,9214,7318,1761,5147,
+7112,15831,20270,5689,10886,13188,4163,18175,1124,7840,
+21342,18140,3047,15899,18853,20918,15766,20919,17405,15986,
+5754,8835,10998,19501,1885,1763,2547,9152,7051,15026,
+14808,13284,19736,11210,15061,2064,17327,4633,8155,4327,
+16448,10191,17124,15062,20964,1923,13258,8159,8160,10282,
+19210,3348,10428,18997,2788,16006,14951,17645,11211,2313,
+16759,4637,5691,8789,8878,1513,13034,9999,9884,10342,
+7208,19346,17173,15845,19387,9539,15847,18074,3612,12524,
+6721,11524,6722,4706,8251,18309,20183,18728,4413,14016,
+4414,14663,3799,6402,16674,3664,7583,1095,14412,20469,
+15536,4954,3649,2329,20674,18787,8365,14285,19827,8041,
+3781,20470,7589,13024,12198,1463,14347,15407,7422,5256,
+4428,1475,8794,7429,1682,17439,3437,5832,7552,6264,
+11065,5836,16239,8476,7122,10397,6770,6771,18825,18826,
+18836,19941,19942,16558,18365,19706,2556,3782,19419,12386,
+2582,21425,16167,7028,21030,16314,3597,10037,4867,16320,
+16834,16192,2543,20927,8042,3094,20798,3097,16984,7154,
+20939,3065,21098,9153,17578,7857,7477,14656,7295,1595,
+5007,16449,1210,16883,20750,12413,15649,3561,20754,1676,
+2686,2387,18576,6792,10927,10271,17338,1280,13490,9371,
+13717,3895,5069,13719,5093,18895,14619,16819,4457,19220,
+11238,16588,16780,7029,17016,7841,16249,3061,19702,12664,
+3190,15371,16092,12908,6842,17740,16318,17139,8623,8277,
+18915,1238,11239,12128,8801,1174,11583,15810,5542,8283,
+19457,3670,15969,19460,4821,17017,1437,19436,17979,3064,
+1738,6656,18038,12251,14802,16835,15386,19400,11360,8772,
+14633,17022,9344,6183,8902,11416,20884,17520,15767,3827,
+6041,5750,12620,17485,14929,6328,13340,6723,2645,18788,
+17743,5604,10010,2624,14282,13531,19953,12179,3554,6754,
+17406,10801,19407,19828,12258,19955,19722,15988,7855,20577,
+10011,6042,13150,15685,1916,12969,16845,10742,18954,6179,
+2544,16786,9484,9295,3066,18955,9610,11603,4312,16788,
+3098,3557,2322,10985,9623,5646,5641,12629,8777,15745,
+10586,16868,8604,5796,11702,4142,5857,20398,19836,7885,
+7161,9956,19723,6106,13553,15406,15689,11772,2981,6832,
+17639,4282,15278,21613,7332,19412,3558,11608,20063,3840,
+2970,13315,2065,1573,6835,21581,15637,1324,17930,16353,
+5277,16450,1465,17931,6587,11173,19413,12806,14256,19110,
+2421,10875,12840,8731,900,13156,18319,13919,21614,13998,
+19229,13624,5383,20021,15132,12707,18560,15042,6665,7064,
+5516,8313,2911,11704,17535,8570,20769,19420,2042,18131,
+14446,1834,8586,17035,6859,19422,18507,9640,14053,15544,
+19118,17896,15382,20067,11316,5407,3101,12414,11470,5848,
+2665,1985,1980,1978,3176,11284,20476,15945,1035,14866,
+5648,13627,20215,8161,9726,11995,15044,7944,19212,10523,
+14260,16041,10744,12882,14352,13297,3707,20853,10283,8383,
+12648,12643,19772,12491,9860,3115,19442,2687,20986,15946,
+2474,12817,13449,12214,1335,13328,7628,2661,9737,12494,
+9012,6786,2533,19214,19215,16992,16993,3438,15415,4244,
+4177,15139,8454,2074,17434,4465,4714,9329,9362,17212,
+11285,9868,16760,1987,8443,3139,17304,15442,14485,12280,
+19025,17162,11876,3439,15443,8022,15032,6985,16515,6520,
+13218,13213,8323,2043,8750,19256,19026,10001,14089,8534,
+6504,908,18238,9098,17128,2669,19633,19217,3316,11048,
+910,11016,4136,12731,11353,9205,10989,2740,21004,11955,
+2792,18512,1860,21010,8942,8918,19446,4850,10158,11225,
+2540,6809,2254,9248,6506,17972,13691,2256,7209,8336,
+6524,14358,9808,11563,11076,15525,8477,21363,5186,19944,
+5244,7323,3962,3835,1943,7276,20814,8973,20456,13010,
+5259,7430,19761,18334,17044,20461,17050,17052,13492,6403,
+6405,4289,14622,15676,10851,3752,14272,18796,18858,18320,
+13367,9372,4512,13896,20126,20502,3797,19543,8815,5950,
+14365,2095,16110,5497,16776,3566,13744,2096,12909,7265,
+19564,1029,16825,20875,20905,3567,18301,8908,1583,8173,
+16589,6347,19948,13234,14413,20763,20038,16250,11622,12542,
+12543,1073,1020,20229,20006,1739,20880,11540,12559,18593,
+20671,20312,18440,6068,11675,18672,2642,12253,7231,10952,
+13434,2822,7233,20423,12100,11484,12910,16116,1125,3651,
+8284,9079,12829,12861,6169,11818,5398,3221,2622,17521,
+2054,6683,1109,20920,9081,4212,4213,11887,20702,5270,
+7704,3956,11486,9920,20313,10367,3828,8407,9912,8256,
+18196,17190,19661,16120,1820,5350,15671,2509,14122,8758,
+10939,11888,8182,12193,7403,14178,13957,17523,2101,4770,
+7655,8183,6886,15989,12544,20274,15038,18649,8414,16254,
+1917,21752,18677,20375,10368,15058,16121,1188,16434,16294,
+13198,14335,11249,10977,4962,3511,16649,8358,19962,21612,
+15746,15973,1355,13958,21757,16656,12631,2512,14067,10572,
+13292,5170,3655,6855,12688,14737,12872,10056,18202,20742,
+9832,5590,11679,6891,18375,20766,1952,1731,15687,21643,
+8751,12006,7737,11319,5333,10992,14052,12235,11944,7413,
+20748,8118,7414,18273,11558,6209,12344,16354,13999,11761,
+14657,21615,20712,18094,6624,1596,18476,6588,18321,21705,
+17819,8705,7046,15690,9113,9121,2422,8120,15995,6694,
+5325,2707,17426,17586,12922,2106,1289,18553,16355,3565,
+16605,21616,5326,5451,13240,13802,13619,2711,15246,15234,
+13803,12205,8685,18561,3522,20817,11914,9109,13419,17244,
+7939,11219,4328,2922,14191,15318,20350,12042,9641,15545,
+6359,20965,16202,17095,16606,13043,15730,20641,4329,11939,
+13563,20368,16752,14349,8638,13804,13990,2234,15265,8122,
+2685,2894,5849,4775,3702,12812,15070,9770,2475,2568,
+5649,10429,10303,21619,5080,6428,20369,13046,15531,6487,
+11516,7546,5720,19339,1004,20987,11782,10745,2253,8795,
+2767,14353,16042,7675,2169,12884,1662,7594,18566,5458,
+12885,6974,12417,9313,4151,17301,13910,5783,20142,19007,
+17213,2477,11592,6276,5697,3272,11727,9998,20770,6709,
+7682,7117,2025,15459,3406,1797,2375,8390,17435,1358,
+4973,21451,16175,12569,13241,4148,6463,7683,15325,13131,
+16643,7435,19378,11574,10380,21452,20254,12571,2992,6993,
+3467,14090,13276,7756,8860,3388,17543,18699,1043,8324,
+18700,4343,10993,11066,7118,15364,3531,9246,8267,18656,
+13908,18715,18711,11688,6903,7819,1717,11833,5263,21005,
+7817,9093,11343,7524,17550,9943,15396,1121,15086,10320,
+10570,13706,21006,18513,9453,1932,14761,3157,11732,17259,
+8542,9676,9130,6569,19320,10343,10265,12893,12894,12899,
+9215,17174,19266,10930,2173,19321,3154,17554,14359,10645,
+10933,11077,2580,20146,10544,15397,9698,3731,16207,3470,
+7698,9252,9704,5767,5771,6957,18101,8654,18849,5096,
+1140,12527,3715,8802,11271,16783,6092,2057,2828,5274,
+17882,7710,2416,20634,4197,19671,1129,17883,4198,11776,
+3738,4188,18970,8713,18381,6958,15960,17494,4200,18478,
+17067,11280,873,874,3633,20715,14821,9870,13450,17754,
+18870,7685,14235,7686,21462,19040,9775,1521,9528,17504,
+17505,18011,12669,12677,8419,20377,20378,1147,19690,9221,
+16487,14459,7291,7296,19678,7717,15962,4011,19137,12994,
+13466,20429,21443,21447,21453,13211,9972,21463,2846,4106,
+21215,7846,5998,12151,19461,11481,12678,12263,10127,4830,
+4569,7982,20546,18863,14293,7483,4368,20996,4466,12391,
+4467,20414,8881,15223,19646,7123,7156,6895,17513,15764,
+15348,3667,17805,2222,18456,14564,11240,11241,16084,2931,
+16740,1302,1158,7769,14460,6416,4564,5768,17920,4651,
+13221,6324,18251,20273,4565,14437,8285,18467,1742,17981,
+12528,20675,10041,6038,11368,1593,17872,6829,21627,14637,
+4625,3870,16539,3924,878,1743,983,10210,8927,15794,
+14574,6661,17923,8964,8848,7656,7929,20929,15903,6271,
+5059,17362,5957,8521,17282,9030,21142,16846,14496,20578,
+20579,5961,6045,16271,15748,21444,21722,21126,14210,11681,
+16870,12775,20768,18971,961,16277,9958,2268,16325,17473,
+4602,17975,18813,20068,6698,17857,11253,18643,19350,14773,
+16456,13275,10876,11552,7423,18479,2937,18567,15281,12600,
+7676,8573,5236,16622,2324,12813,6052,18393,9649,7183,
+10986,20150,17598,6053,11393,3076,11708,20482,6787,5977,
+17968,2874,9874,15444,8023,12418,9973,16994,19027,7189,
+6675,3350,18695,18696,9655,15420,15927,17477,4639,14429,
+20556,6027,19041,17388,17691,14198,7688,1278,8067,18405,
+911,18712,13881,11019,9668,2434,8943,3863,3864,18635,
+6920,10483,13827,10236,10646,10545,14163,15526,18355,21216,
+19936,18904,6325,14734,2028,14470,20288,1984,17891,6772,
+19191,13158,4664,12324,1141,10042,4606,13468,11921,15795,
+9298,21708,11298,6609,16087,12635,19232,21586,16342,15928,
+9305,9330,10237,12445,14794,15622,13718,1053,4209,3505,
+9582,13370,8108,1407,2494,3042,13898,12854,19565,16680,
+18079,4479,21541,13747,16113,3668,10797,2553,18905,5077,
+5370,18773,7584,14171,16293,8133,10798,16977,19860,4621,
+3922,17141,2932,14727,6475,17634,11859,2753,15018,19951,
+7925,6942,10831,1438,984,4672,18918,4818,11541,6417,
+18159,3988,17654,18530,4279,20540,20056,21718,14461,3671,
+10325,15019,11542,17145,14990,16978,5598,4878,11369,18930,
+18674,18679,14638,11766,1414,18789,11678,9105,6085,12036,
+4480,21036,3332,3009,18518,4822,14731,14306,15021,14376,
+11545,19408,20921,20314,3416,5467,12563,990,4879,1816,
+4233,1400,20361,14991,21256,12130,14627,5599,2118,18599,
+8149,10174,10898,9600,13786,20199,13996,19405,18087,12800,
+20626,18797,17351,20707,9612,14076,8590,1730,13728,1115,
+13729,1765,21485,2719,18941,3049,7472,21719,4379,4400,
+19713,4440,5399,20394,9613,19097,18942,14643,4893,13865,
+18798,8821,13311,14040,18042,4234,2918,11418,20093,11959,
+19223,7782,10175,20449,18088,13977,20635,1287,15839,9083,
+8048,1826,1356,13929,16855,9278,10177,4739,12632,16593,
+8497,5125,15113,13389,19504,10268,12182,21359,3681,17925,
+15994,20213,19535,1457,3622,5928,20813,13761,1314,7409,
+6581,16272,11937,7244,15777,7157,17414,10492,8890,2079,
+4675,15024,14993,4001,13223,19335,8195,9065,21441,2164,
+16441,8049,9485,1732,17122,4802,15566,20941,9154,9720,
+21415,9489,12807,1750,10589,3067,12973,12700,1958,2177,
+20582,4613,12019,1206,6836,2519,20201,9633,19738,19739,
+5551,5813,3967,5172,16326,3257,4489,2466,20454,12776,
+19839,18322,19740,13535,18972,13732,12637,21417,4914,9159,
+21645,21646,4658,2395,13272,11658,16278,10412,6019,7748,
+2723,8257,8226,2520,21758,13002,18147,12304,21445,21499,
+1690,12201,3903,2804,2269,10970,6448,7415,5716,17031,
+3539,5774,3739,20815,13600,11483,4965,5335,12236,14225,
+18807,14390,4216,5014,16457,16361,7297,21587,7347,18814,
+16955,18388,18328,7348,19679,6110,16663,12369,1476,18535,
+5825,17823,13967,18480,9122,18274,1353,6699,8975,7859,
+8976,14937,4748,16173,7052,11471,10877,8831,6364,15860,
+19611,19481,3070,17992,18505,20643,12370,18691,7796,18692,
+14887,19602,16362,10915,15692,7058,7797,13854,6628,9380,
+13564,17332,14606,15409,16542,14408,2779,12309,7300,18998,
+20435,4929,11948,11127,5527,7497,15300,18609,14133,19889,
+21557,11307,15133,7310,18568,7806,6674,5148,12929,10706,
+19890,13809,14585,20820,16547,15861,13805,15490,20380,14943,
+14506,8690,16890,5522,12644,5215,15238,12043,15547,5289,
+2939,20652,11894,7070,5455,13011,12953,10921,17901,5184,
+21420,16154,13096,18523,3721,7301,20976,3526,10222,14042,
+16962,6975,9771,6788,19373,12983,5864,5087,5088,16043,
+6488,14108,3179,12211,19513,7574,6431,6596,5784,11783,
+19008,5199,8631,5725,5726,10747,20588,21351,9382,9302,
+2427,3077,9502,17769,13277,14867,15892,5652,20250,15140,
+9392,10377,9824,11135,10286,2347,15141,8693,1628,10435,
+8123,20614,20325,14755,10748,11476,18525,15782,12212,21285,
+14134,13572,7358,3078,6976,18233,18030,4423,18102,20856,
+21710,3109,12603,14824,6489,9018,20659,14236,16908,2943,
+3767,4430,11338,16764,13698,10016,10150,13104,17305,13956,
+4494,20440,9353,20031,14892,4152,2480,15500,11009,15148,
+8456,15421,6793,6986,11941,16176,11841,13935,15929,20295,
+4689,13329,13672,6191,12935,5489,10184,9364,5200,16995,
+14508,21558,14031,7083,3981,7995,7513,2845,3312,14758,
+7555,10004,11581,19193,6801,14199,21731,17970,2484,5149,
+8239,21734,19042,12606,4757,6738,3493,7196,15214,12496,
+2537,2812,21294,6802,7084,7835,7303,14686,7436,13036,
+3547,18872,1660,15033,14328,9661,19171,15580,15366,11155,
+12734,16046,1734,6907,7202,12892,11690,11836,18759,5223,
+7525,19218,11897,13288,18340,12735,11140,20559,5788,2945,
+7000,8981,12517,3592,2794,5299,11156,19448,21012,6670,
+12895,9430,9397,13995,10385,9669,3158,10527,11228,6814,
+11979,10481,21007,5204,4039,19906,9677,4643,21465,15088,
+9750,7602,2798,13302,21190,10348,18289,9683,21191,2458,
+7824,4352,15099,6508,11800,19802,10238,9134,7646,17260,
+5738,8268,17458,10103,19270,7384,19200,19492,19326,17341,
+11884,1869,2211,9222,8270,14857,14362,21736,3113,13582,
+13493,2022,8170,19809,10630,9701,3160,10546,3472,8481,
+18296,9253,9228,21217,9411,9575,1108,11572,19816,10106,
+5687,6517,12857,17808,2331,2825,12804,8582,18943,8415,
+17025,17875,6069,9000,9273,8891,14905,862,17820,2629,
+13239,8606,8893,8608,2873,5568,19113,19613,17429,18697,
+16694,15460,7948,11973,6343,15695,6518,17833,12166,16996,
+17502,17837,16910,9776,2847,19043,4350,19637,2994,6526,
+1911,1912,8286,12915,2596,14082,2630,14086,21061,15203,
+15204,9650,20251,19624,9656,5733,4287,20567,11361,11362,
+18595,14464,17876,8421,12838,13390,15114,13269,18973,15961,
+18686,1977,6837,3849,20653,20047,16543,2763,15696,7949,
+14264,19168,3788,8162,9019,3165,3389,4080,7556,9803,
+1719,4040,7378,7385,21257,13293,18956,14123,8704,13125,
+18554,18129,6773,13628,6970,11974,6737,4103,18760,17463,
+5637,10935,877,7830,12293,2197,10829,10830,12290,9911,
+7237,13997,11460,16169,18089,4401,13794,17235,8221,13391,
+4002,11963,12138,8227,4189,1392,14019,10878,14001,14749,
+16184,6111,15323,14021,10479,11433,9507,15930,13816,20410,
+14071,20411,11022,10386,3868,8398,12785,18461,11633,1712,
+14377,12801,16847,13253,18205,3934,18508,20026,20762,1727,
+3474,14876,9373,11693,4515,5741,1683,20271,11161,3776,
+19946,2881,16244,4518,3320,16111,10794,13371,12447,12849,
+16675,16676,16020,8132,20793,20876,12855,8011,8012,13939,
+8490,6225,13589,1584,5137,21027,12072,8402,6390,11853,
+17866,17869,20007,18302,3413,19454,6411,6881,11856,10893,
+11109,2678,12073,1411,20877,12056,21372,20089,10122,20230,
+4728,10953,20092,16118,9594,11089,18779,4425,15717,14926,
+8925,8085,8177,18919,7234,21033,6746,1340,20232,21196,
+19437,5466,6326,12178,3039,2590,15105,2462,14981,8217,
+18039,14462,8404,4871,7106,5640,3414,19139,21089,18675,
+6685,20127,2505,16388,6308,7465,14994,4376,17705,4881,
+14075,20887,19205,16712,8657,10654,967,15679,11417,9442,
+18739,11091,13545,12529,17465,17570,15107,8903,13152,8279,
+12469,17744,20923,5676,11294,16683,13435,18931,8037,14521,
+12239,2224,7927,9925,13383,16435,5925,10806,19465,1821,
+3996,6240,18944,19334,9236,5943,9556,5331,9787,2951,
+4771,18945,15905,9322,7242,2680,8090,15171,2467,12153,
+17283,14440,9076,12453,5958,7977,11723,15972,17490,15872,
+4259,16085,9614,14879,14995,9444,14880,4024,20015,6180,
+17728,14711,2982,20493,8778,16273,16125,3931,16635,8196,
+14343,9816,6833,15317,13154,3556,8372,5511,5858,5962,
+21099,12232,6046,2264,12633,4546,2598,10405,8222,9445,
+20611,12476,15747,19725,11655,10406,11118,8050,10058,10587,
+13473,19726,11725,1619,6334,19837,9155,13254,12949,20890,
+19184,1827,1343,19832,16603,13965,4583,19833,8711,7158,
+14344,14079,12690,12343,16858,19835,13840,6589,7416,11927,
+13397,15856,4743,16636,15639,16356,13868,2066,6099,18323,
+6248,11097,10835,19230,18324,6210,14493,10943,20116,6845,
+11533,5758,2653,4321,9791,12808,12809,10910,15727,3118,
+16401,1969,6764,1831,17856,7060,7411,4788,18974,19208,
+14577,7749,20638,15453,19603,1467,11277,14526,15975,14474,
+19414,8228,3968,16054,7670,13398,15464,10220,6896,19874,
+11559,1178,19508,13557,21347,9845,2178,17201,2956,6144,
+21500,10759,19295,9119,4744,10277,16402,17092,19296,12506,
+7940,5777,15282,19885,9727,18607,11004,21405,2527,15381,
+3290,16203,5419,14055,20320,14581,10603,10688,16363,20117,
+16802,16544,13006,20243,14529,871,20023,19114,15127,15290,
+14530,863,12065,2837,16620,2011,11220,5286,6049,6673,
+17036,3626,20966,19240,7798,5258,15176,7713,6775,19158,
+5194,14849,2958,17495,19750,17782,6429,1478,1624,20977,
+7595,8809,14451,14261,11128,1000,10375,6397,19441,2235,
+4533,19372,5803,10762,13286,19619,7174,18171,2345,16989,
+7175,10304,10223,7907,5850,3102,20854,5089,13030,7718,
+3071,2961,16044,11996,15605,18664,16959,11129,15491,14262,
+5975,9728,16204,2609,5113,12206,21572,8630,12187,20495,
+2697,17902,6879,7499,18230,2902,9861,3185,15650,7549,
+3103,19341,6258,17658,14820,5650,3104,9047,17903,20978,
+12349,8444,7722,12508,3487,6789,7811,16761,12009,7075,
+16410,15146,12956,17045,17046,15253,4178,11286,13955,15142,
+20657,3105,18999,20988,16237,15394,18100,9013,18645,16007,
+13982,6167,1505,2192,14780,12602,9969,16411,14095,14088,
+2534,8099,6491,7629,9363,3218,6277,5938,20028,10192,
+6278,4935,6054,6122,17214,7503,14197,17047,1038,10378,
+11848,19634,10003,14486,3458,6599,20255,17604,19780,14681,
+18024,10085,10782,21520,19379,6794,1994,9801,3768,18707,
+6550,20660,10783,3407,19029,15210,12351,8325,15326,13215,
+21459,11877,5833,7953,12165,14091,7085,16516,2810,15332,
+15034,15884,14092,21234,9744,11102,14544,14825,11137,11849,
+19312,19313,11017,7959,12732,7197,21716,16667,15553,19197,
+19128,4133,3029,6904,13300,9261,8537,885,16413,1701,
+5533,12941,19314,1702,9094,4642,2014,10888,7526,16478,
+10666,20155,10454,9662,19447,18514,10384,15013,20997,19355,
+4038,16334,6715,17614,12048,14432,1638,2200,11226,10159,
+7375,14097,2539,5536,1706,6914,17311,10344,13242,13826,
+9678,8070,17452,19323,15190,16484,6507,18047,21188,10232,
+9181,4137,4537,6383,9182,14762,10097,19324,11103,7217,
+9806,7528,19267,9986,19065,7382,2210,3359,13676,7450,
+9216,4504,14870,19851,21470,4763,14360,9433,9217,3112,
+13491,19388,12943,4452,8473,18429,19327,13983,20164,10547,
+18419,9534,11105,14250,15398,3471,7699,2249,19329,6064,
+21214,9266,9226,11577,16241,10551,18111,17265,18432,5152,
+18436,19820,5668,17394,17395,6679,6203,21322,20357,17563,
+2639,20109,12794,21034,4673,11860,16561,12560,18920,12254,
+8580,12058,8581,12097,11457,9905,5670,17663,5671,5672,
+1567,3282,17079,20734,21198,8710,20525,4882,1078,17571,
+17572,10118,21411,12108,15354,18500,15887,14207,16389,6658,
+21091,7657,17877,6186,13592,6579,17760,17761,17236,19142,
+16686,21093,18548,14644,16345,15906,18043,20114,8583,17083,
+17974,20736,12532,6727,5679,2381,6689,2412,6757,9927,
+4902,8091,2382,12596,15840,21435,15874,5886,9299,14182,
+17884,2650,13795,6355,16860,14740,6143,18051,8837,8422,
+17415,16861,21360,8525,3682,17580,7053,16793,10493,18376,
+8223,10013,9039,6857,16088,16871,3203,16719,6211,8304,
+4966,16661,3068,4789,12481,13316,13966,16872,13317,17669,
+18975,7618,19741,5182,12305,5517,16327,14475,5569,14290,
+14291,11634,5336,16357,2424,6147,8993,21062,17068,6700,
+4790,9796,17681,7671,1479,19233,21230,16458,16032,14211,
+16885,11929,11930,2182,18227,8092,8097,10963,16505,20340,
+7936,13322,13855,6591,4490,13402,15205,18481,9934,7752,
+20216,5570,19990,11554,14664,9847,5456,15492,2357,4362,
+1842,6667,17539,17041,16805,19992,6118,6149,16892,20027,
+11515,14213,13323,18623,11130,9732,19304,16753,5408,18394,
+13052,1494,1629,3079,10436,7359,10287,12213,15178,19011,
+15893,8445,21592,6432,18822,20989,16509,10181,5978,11975,
+13712,8098,9051,3163,20296,7366,16912,16913,19012,17503,
+2668,6635,2240,18698,18103,18400,18104,13075,8536,3573,
+4179,14399,7632,4690,14958,19781,9974,8100,14299,4691,
+18105,9258,10947,15533,19030,8101,10987,8024,8025,19309,
+19044,18025,9206,15383,1996,16919,13631,21622,9751,6739,
+21208,10093,16371,19045,17549,20557,6803,3299,11934,1757,
+13882,6156,18066,7961,2742,3549,18631,6157,9262,1641,
+13824,9670,11406,13972,10528,9131,992,18071,8944,14917,
+9891,9684,10349,8463,9900,18415,16939,17617,10239,18716,
+1999,13688,19981,9263,3114,2702,5658,8338,2392,11075,
+15527,9264,21218,9254,10107,19822,20533,20731,12109,2465,
+16403,5936,8446,18652,21685,4404,2899,8671,20171,3850,
+13012,19374,13037,12060,2338,7339,2893,19614,20341,1553,
+1200,1843,2895,19515,4041,2471,11852,8109,15294,13748,
+10790,4544,5162,18363,5246,1303,14992,19530,5248,11439,
+3653,13599,13548,21566,10808,8760,12870,9490,12552,5173,
+15593,1345,13558,2957,7254,4749,8686,8229,2786,17042,
+1329,10661,7863,10679,14022,16510,9508,4153,15931,13105,
+16920,9671,4042,9945,12024,12395,1866,16940,2714,16419,
+13701,2715,1072,7105,2148,21426,5242,8645,1807,6302,
+18190,19135,4458,21357,8910,21070,11455,12255,8219,18780,
+17675,16139,10039,12256,11676,18596,19523,18040,3396,1811,
+23007,23008,23009,23010,23011,23012,23013,23014,23015,23016,
+23017,23018,23019,23020,23021,23022,23023,23024,23025,23026,
+23027,23028,23029,23030,23031,23032,23033,23034,23035,23036,
+23037,23038,23039,23040,23041,23042,23043,23044,23045,23046,
+23047,23048,23049,23050,23051,23052,23053,23054,23055,23056,
+23057,23058,23059,23060,23061,23062,23063,23064,23065,23066,
+23067,23068,23069,23070,23071,23072,23073,23074,23075,23076,
+23077,23078,23079,23080,23081,23082,23083,23084,23085,23086,
+23087,23088,23089,23090,23091,23092,23093,23094,23095,23096,
+23097,23098,23099,23100,23101,23102,11,34,37,328,
+70,72,68,118,23934,6,66,74,330,75,
+76,77,78,109,112,88,90,92,94,96,
+98,100,102,114,115,104,106,131,132,133,
+151,143,144,136,135,146,145,134,152,137,
+165,142,140,167,124,147,148,158,155,154,
+153,138,157,163,164,159,160,431,150,149,
+339,338,327,79,80,443,18,323,321,322,
+331,325,491,335,336,176,178,177,175,174,
+169,168,171,170,332,185,189,183,187,334,
+23103,23104,23105,23106,23107,23108,23109,23110,23111,23112,
+23113,23114,23115,23116,23117,23118,23119,23120,23121,23122,
+23123,23124,23125,23126,23127,23128,23129,23130,23131,23132,
+23133,23134,23135,23136,23137,23138,23139,23140,23141,23142,
+23143,23144,23145,23146,23147,23148,23149,23150,23151,23152,
+23153,23154,23155,23156,23157,23158,23159,23160,23161,23162,
+23163,23164,23165,23166,23167,23168,23169,23170,23171,23172,
+23173,23174,23175,23176,23177,23178,23179,23180,23181,23182,
+23183,23184,23185,23186,23187,23188,23189,23190,23191,23192,
+23193,23194,23195,23196,23197,23198,345,352,359,366,
+373,380,387,394,401,407,23679,23680,23681,23682,
+23683,23684,344,351,358,365,372,379,386,393,
+400,406,410,413,416,418,420,422,424,426,
+428,430,343,350,357,364,371,378,385,392,
+399,405,409,412,415,417,419,421,423,425,
+427,429,342,349,356,363,370,377,384,391,
+398,404,23685,23686,18727,4412,14015,14972,16730,10188,
+12616,1048,8127,14553,23687,23688,346,353,360,367,
+374,381,388,395,402,408,411,414,23689,23690,
+23199,23200,23201,23202,23203,23204,23205,23206,23207,23208,
+23209,23210,23211,23212,23213,23214,23215,23216,23217,23218,
+23219,23220,23221,23222,23223,23224,23225,23226,23227,23228,
+23229,23230,23231,23232,23233,23234,23235,23236,23237,23238,
+23239,23240,23241,23242,23243,23244,23245,23246,23247,23248,
+23249,23250,23251,23252,23253,23254,23255,23256,23257,23258,
+23259,23260,23261,23262,23263,23264,23265,23266,23267,23268,
+23269,23270,23271,23272,23273,23274,23275,23276,23277,23278,
+23279,23280,23281,23282,23283,23284,23285,23286,23287,23288,
+23289,23290,23291,23292,23293,23294,13,14,16,324,
+20,22,1,24,27,30,121,32,3,36,
+38,340,341,348,355,362,369,376,383,390,
+397,40,43,126,128,130,45,47,432,439,
+441,447,449,456,459,462,464,470,472,477,
+481,487,492,498,500,502,504,506,509,520,
+522,524,526,528,48,50,51,52,53,57,
+433,440,442,448,450,457,460,463,465,471,
+473,478,482,488,493,499,501,503,505,507,
+510,521,523,525,527,529,60,62,64,69,
+23295,23296,23297,23298,23299,23300,23301,23302,23303,23304,
+23305,23306,23307,23308,23309,23310,23311,23312,23313,23314,
+23315,23316,23317,23318,23319,23320,23321,23322,23323,23324,
+23325,23326,23327,23328,23329,23330,23331,23332,23333,23334,
+23335,23336,23337,23338,23339,23340,23341,23342,23343,23344,
+23345,23346,23347,23348,23349,23350,23351,23352,23353,23354,
+23355,23356,23357,23358,23359,23360,23361,23362,23363,23364,
+23365,23366,23367,23368,23369,23370,23371,23372,23373,23374,
+23375,23376,23377,23378,23379,23380,23381,23382,23383,23384,
+23385,23386,23387,23388,23389,23390,645,647,649,651,
+653,655,658,660,662,664,667,669,671,673,
+675,677,680,682,684,686,688,690,692,694,
+696,698,700,702,704,706,708,710,712,714,
+716,718,720,722,724,726,728,730,732,734,
+736,738,740,742,744,746,748,750,752,754,
+756,758,760,762,764,766,768,770,772,774,
+776,778,780,782,784,786,788,790,792,794,
+796,798,800,802,804,806,808,810,812,23691,
+23692,23693,23694,23695,23696,23697,23698,23699,23700,23701,
+23391,23392,23393,23394,23395,23396,23397,23398,23399,23400,
+23401,23402,23403,23404,23405,23406,23407,23408,23409,23410,
+23411,23412,23413,23414,23415,23416,23417,23418,23419,23420,
+23421,23422,23423,23424,23425,23426,23427,23428,23429,23430,
+23431,23432,23433,23434,23435,23436,23437,23438,23439,23440,
+23441,23442,23443,23444,23445,23446,23447,23448,23449,23450,
+23451,23452,23453,23454,23455,23456,23457,23458,23459,23460,
+23461,23462,23463,23464,23465,23466,23467,23468,23469,23470,
+23471,23472,23473,23474,23475,23476,23477,23478,23479,23480,
+23481,23482,23483,23484,23485,23486,644,646,648,650,
+652,654,657,659,661,663,666,668,670,672,
+674,676,679,681,683,685,687,689,691,693,
+695,697,699,701,703,705,707,709,711,713,
+715,717,719,721,723,725,727,729,731,733,
+735,737,739,741,743,745,747,749,751,753,
+755,757,759,761,763,765,767,769,771,773,
+775,777,779,781,783,785,787,789,791,793,
+795,797,799,801,803,805,807,809,811,656,
+665,678,23702,23703,23704,23705,23706,23707,23708,23709,
+23487,23488,23489,23490,23491,23492,23493,23494,23495,23496,
+23497,23498,23499,23500,23501,23502,23503,23504,23505,23506,
+23507,23508,23509,23510,23511,23512,23513,23514,23515,23516,
+23517,23518,23519,23520,23521,23522,23523,23524,23525,23526,
+23527,23528,23529,23530,23531,23532,23533,23534,23535,23536,
+23537,23538,23539,23540,23541,23542,23543,23544,23545,23546,
+23547,23548,23549,23550,23551,23552,23553,23554,23555,23556,
+23557,23558,23559,23560,23561,23562,23563,23564,23565,23566,
+23567,23568,23569,23570,23571,23572,23573,23574,23575,23576,
+23577,23578,23579,23580,23581,23582,530,532,534,536,
+538,540,542,544,546,548,550,552,554,556,
+558,560,562,564,566,568,570,572,574,576,
+23710,23711,23712,23713,23714,23715,23716,23717,531,533,
+535,537,539,541,543,545,547,549,551,553,
+555,557,559,561,563,565,567,569,571,573,
+575,577,23718,23719,23720,23721,23722,23723,23724,25,
+28,110,113,89,91,93,95,97,99,101,
+103,23725,23726,105,107,61,65,8,23727,82,
+87,23728,23729,23730,23731,23732,23733,23734,23735,23736,
+23583,23584,23585,23586,23587,23588,23589,23590,23591,23592,
+23593,23594,23595,23596,23597,23598,23599,23600,23601,23602,
+23603,23604,23605,23606,23607,23608,23609,23610,23611,23612,
+23613,23614,23615,23616,23617,23618,23619,23620,23621,23622,
+23623,23624,23625,23626,23627,23628,23629,23630,23631,23632,
+23633,23634,23635,23636,23637,23638,23639,23640,23641,23642,
+23643,23644,23645,23646,23647,23648,23649,23650,23651,23652,
+23653,23654,23655,23656,23657,23658,23659,23660,23661,23662,
+23663,23664,23665,23666,23667,23668,23669,23670,23671,23672,
+23673,23674,23675,23676,23677,23678,578,580,582,584,
+586,588,590,592,594,596,598,600,602,604,
+606,608,610,612,614,616,618,620,622,624,
+626,628,630,632,634,636,638,640,642,23737,
+23738,23739,23740,23741,23742,23743,23744,23745,23746,23747,
+23748,23749,23750,23751,579,581,583,585,587,589,
+591,593,595,597,599,601,603,605,607,609,
+611,613,615,617,619,621,623,625,627,629,
+631,633,635,637,639,641,643,23752,23753,23754,
+23755,23756,23757,23758,23759,23760,23761,23762,23763,23764,
+71,58,73,5,7,329,81,446,458,190,
+184,186,188,123,139,141,156,161,162,166,
+197,204,209,210,211,217,218,219,225,226,
+227,233,234,235,245,246,247,256,257,258,
+267,268,269,278,279,280,297,298,299,212,
+220,236,228,300,301,302,303,307,309,311,
+313,315,317,319,318,316,314,312,310,308,
+304,320,305,306,172,173,179,180,181,182,
+337,122,333,116,117,23765,23766,23767,23768,23769,
+23770,23771,23772,23773,23774,23775,437,434,436,435,
+455,451,454,452,469,466,468,467,497,494,
+496,495,515,511,514,512,519,516,518,517,
+513,453,438,23776,489,490,23777,461,23778,23779,
+23780,23781,813,814,815,816,817,818,819,820,
+821,822,823,824,825,826,827,828,829,830,
+831,832,833,834,835,836,837,838,839,840,
+841,842,843,844,845,846,847,848,849,23782,
+23783,23784,23785,23786,23787,23788,23789,23790,23791,23792,
+23793,23794,23795,23796,23797,23798,23799,23800,23801,23802,
+347,354,361,368,375,382,389,396,403,20773,
+484,474,486,445,475,483,444,476,479,480,
+485,41,326,67,23803,508,21167,23804,4,23805,
+23806,23807,23935,9,10,23936,23937,119,23938,23939,
+83,84,85,86,54,55,56,31,33,35,
+42,39,44,12,23,26,59,63,108,111,
+15,21,29,120,2,125,129,127,49,17,
+19,46,23808,23809,23810,23811,23812,23813,23814,23815,
+23816,23817,23818,23819,23820,0,23821,23822,23823,23824,
+23825,23826,23827,23828,23829,23830,23831,23832,23833,191,
+192,198,199,193,194,200,201,195,196,202,
+203,205,206,207,208,213,214,215,216,221,
+222,223,224,229,230,231,232,237,238,239,
+240,241,242,243,244,248,249,250,251,252,
+253,254,255,259,260,261,262,263,264,265,
+266,270,271,272,273,274,275,276,277,281,
+282,283,284,285,286,287,288,289,290,291,
+292,293,294,295,296,23834,23835,23836,23837,23838,
+23839,23840,23841,23842,23843,23844,23845,23846,23847,23848,
+8829,17231,6535,6086,20542,7042,18120,14179,15314,15901,
+9317,10807,16850,17084,1310,20931,18257,14124,5959,7983,
+12018,4587,17416,1130,12691,1620,19209,9156,7333,12998,
+9036,18384,21630,20942,20743,18167,9930,2092,21583,5037,
+4745,16637,19875,2869,16031,18206,17531,7250,1549,19478,
+18563,15235,1836,11304,15065,10689,19887,3315,19763,14531,
+6021,13003,18986,20644,2012,6025,10777,7575,11431,2185,
+1002,5217,3180,1359,1506,1495,6633,1901,9970,17909,
+15926,18626,14914,17436,14719,4149,7725,5316,8386,4033,
+6795,8879,17252,17253,11834,1558,21785,21786,21787,21788,
+21789,21790,21791,21792,21793,21794,21795,21796,21797,21798,
+21799,21800,21801,21802,21803,21804,21805,21806,21807,21808,
+21809,21810,21811,21812,21813,21814,21815,21816,21817,21818,
+21819,21820,21821,21822,21823,21824,21825,21826,21827,21828,
+21829,21830,21831,21832,21833,21834,21835,21836,21837,21838,
+21839,21840,21841,21842,21843,21844,21845,21846,21847,21848,
+21849,21850,21851,21852,21853,21854,21855,21856,21857,21858,
+21859,21860,21861,21862,21863,21864,21865,21866,21867,21868,
+21869,21870,21871,21872,21873,21874,21875,21876,21877,21878,
+6905,11896,11018,9944,11594,5692,14720,10345,15311,17313,
+11073,13677,11600,10627,17262,12754,8479,11208,21486,10333,
+15102,13369,5048,9375,1054,6226,3669,2883,5098,19567,
+12765,19568,2317,6231,16742,4819,7847,18193,10973,1202,
+19952,8405,20040,8406,7324,3397,12430,12996,18932,951,
+12470,4883,17960,3000,5431,7289,14307,3007,13669,14466,
+14378,15344,21686,10176,1444,20623,7883,7706,7474,9616,
+5680,17147,21094,18216,17786,18471,17853,15109,13192,19144,
+18090,1242,17380,17085,5708,2681,17878,12154,9347,3452,
+19224,16567,4261,2513,15633,16750,21879,21880,21881,21882,
+21883,21884,21885,21886,21887,21888,21889,21890,21891,21892,
+21893,21894,21895,21896,21897,21898,21899,21900,21901,21902,
+21903,21904,21905,21906,21907,21908,21909,21910,21911,21912,
+21913,21914,21915,21916,21917,21918,21919,21920,21921,21922,
+21923,21924,21925,21926,21927,21928,21929,21930,21931,21932,
+21933,21934,21935,21936,21937,21938,21939,21940,21941,21942,
+21943,21944,21945,21946,21947,21948,21949,21950,21951,21952,
+21953,21954,21955,21956,21957,21958,21959,21960,21961,21962,
+21963,21964,21965,21966,21967,21968,21969,21970,21971,21972,
+16716,2510,8526,10903,1315,15875,17286,2830,5964,17964,
+18262,17987,17789,4903,16862,10059,9624,7886,15277,4741,
+16257,3760,12433,20430,14083,11250,19742,9160,11251,14501,
+16404,15749,2834,1377,2472,4330,2270,1378,10413,5626,
+3784,1321,12999,21418,13200,4454,7888,4062,7860,6701,
+19680,10917,2940,17937,15646,17682,3347,13842,11254,7350,
+16459,13920,6592,17537,2863,7424,21326,2323,9797,13565,
+4098,18168,6630,10141,14536,13811,15283,18569,16545,16756,
+20654,7945,19306,10691,15548,10144,9651,9282,15761,13013,
+3229,8438,20536,1694,14752,2296,21973,21974,21975,21976,
+21977,21978,21979,21980,21981,21982,21983,21984,21985,21986,
+21987,21988,21989,21990,21991,21992,21993,21994,21995,21996,
+21997,21998,21999,22000,22001,22002,22003,22004,22005,22006,
+22007,22008,22009,22010,22011,22012,22013,22014,22015,22016,
+22017,22018,22019,22020,22021,22022,22023,22024,22025,22026,
+22027,22028,22029,22030,22031,22032,22033,22034,22035,22036,
+22037,22038,22039,22040,22041,22042,22043,22044,22045,22046,
+22047,22048,22049,22050,22051,22052,22053,22054,22055,22056,
+22057,22058,22059,22060,22061,22062,22063,22064,22065,22066,
+9052,21308,3080,18756,12724,8021,20202,13409,1006,9772,
+10979,19169,6464,16517,16723,3574,17793,20297,18106,13480,
+3494,9975,9876,13330,15149,5727,8026,4496,7891,10151,
+6988,6796,8027,912,20204,3459,7689,5816,15446,6804,
+6553,14096,15216,15737,2813,19638,7962,10346,1705,14771,
+21717,9211,17004,7203,17971,13927,16668,5090,9398,4043,
+9679,21013,13850,9709,20158,13332,15702,5736,15188,9135,
+10240,10350,9685,9265,19271,11078,17342,13335,5659,3552,
+20166,6564,1812,1822,20848,9705,14696,17347,13055,1161,
+12167,4566,3398,4797,11233,16212,22067,22068,22069,22070,
+22071,22072,22073,22074,22075,22076,22077,22078,22079,22080,
+22081,22082,22083,22084,22085,22086,22087,22088,22089,22090,
+22091,22092,22093,22094,22095,22096,22097,22098,22099,22100,
+22101,22102,22103,22104,22105,22106,22107,22108,22109,22110,
+22111,22112,22113,22114,22115,22116,22117,22118,22119,22120,
+22121,22122,22123,22124,22125,22126,22127,22128,22129,22130,
+22131,22132,22133,22134,22135,22136,22137,22138,22139,22140,
+22141,22142,22143,22144,22145,22146,22147,22148,22149,22150,
+22151,22152,22153,22154,22155,22156,22157,22158,22159,22160,
+6350,18790,1138,8373,2289,2560,10201,3484,11035,21378,
+12482,1554,21148,10202,3018,19241,12814,17208,10305,3708,
+11976,21309,10017,16765,3445,16627,19259,18343,15724,5934,
+2291,13265,14383,2227,2228,13930,15091,14397,10393,4786,
+20334,4856,12451,3878,13590,10995,1440,8146,15241,10123,
+11440,20011,4884,5330,7849,4885,15720,11441,15587,7543,
+16196,4895,11547,11444,11445,2058,15723,5061,1451,3266,
+20943,10563,12032,18741,6481,19604,19605,11447,8527,18957,
+10129,3842,6483,3455,21380,7592,2530,2325,16105,9393,
+2111,10152,3859,10020,7559,2744,22161,22162,22163,22164,
+22165,22166,22167,22168,22169,22170,22171,22172,22173,22174,
+22175,22176,22177,22178,22179,22180,22181,22182,22183,22184,
+22185,22186,22187,22188,22189,22190,22191,22192,22193,22194,
+22195,22196,22197,22198,22199,22200,22201,22202,22203,22204,
+22205,22206,22207,22208,22209,22210,22211,22212,22213,22214,
+22215,22216,22217,22218,22219,22220,22221,22222,22223,22224,
+22225,22226,22227,22228,22229,22230,22231,22232,22233,22234,
+22235,22236,22237,22238,22239,22240,22241,22242,22243,22244,
+22245,22246,22247,22248,22249,22250,22251,22252,22253,22254,
+12354,3866,3867,7773,3417,14744,20979,11522,1412,5163,
+21124,17120,17806,2446,18041,12674,17062,3191,1445,21628,
+18004,20808,4436,20891,4630,8185,14183,11699,15601,15889,
+7738,16442,6730,15388,2651,10960,8055,17418,15976,10812,
+17419,15158,12565,4201,14713,18987,1369,20510,5627,10676,
+9961,7166,15752,935,2656,1481,11255,4114,8681,18181,
+3134,14449,21064,20980,19764,4751,18483,2428,15999,5830,
+16571,6595,8842,19119,8448,16903,5616,19013,2896,6780,
+11925,3722,20516,14453,3142,19031,21634,15089,14093,3815,
+10313,10314,13216,4943,9879,13106,22255,22256,22257,22258,
+22259,22260,22261,22262,22263,22264,22265,22266,22267,22268,
+22269,22270,22271,22272,22273,22274,22275,22276,22277,22278,
+22279,22280,22281,22282,22283,22284,22285,22286,22287,22288,
+22289,22290,22291,22292,22293,22294,22295,22296,22297,22298,
+22299,22300,22301,22302,22303,22304,22305,22306,22307,22308,
+22309,22310,22311,22312,22313,22314,22315,22316,22317,22318,
+22319,22320,22321,22322,22323,22324,22325,22326,22327,22328,
+22329,22330,22331,22332,22333,22334,22335,22336,22337,22338,
+22339,22340,22341,22342,22343,22344,22345,22346,22347,22348,
+10154,9331,17220,4640,3390,19213,6155,17221,5617,16373,
+11889,19795,16417,19383,9428,9663,14784,3446,10006,10007,
+1681,7210,2577,18515,7757,20761,10891,9692,6922,9185,
+7009,17978,19348,19201,19392,15399,3732,10647,10554,10555,
+1775,1778,1079,4426,4427,13140,1389,20208,10861,11998,
+3040,10047,11370,7043,12233,5191,4263,5968,1468,2727,
+12976,875,17476,6055,6676,6056,20256,3188,6057,17480,
+18701,6059,7691,916,17694,6671,9686,12406,6134,7731,
+5119,12121,13399,13620,20323,5528,8503,8504,21150,20327,
+20328,20443,4044,12766,19283,1286,852,851,860,861,
+857,859,858,868,876,882,881,891,901,893,
+896,941,928,924,955,966,974,965,970,969,
+979,982,985,987,993,1005,1009,1023,1031,1033,
+1042,1041,1058,1061,1052,1051,1055,1062,1047,1059,
+1050,1076,1084,1093,1090,12005,1094,1105,1098,1096,
+1111,1114,1112,1120,1113,1126,1127,1131,1145,1142,
+1146,1139,1143,1144,1159,1160,1172,1175,1171,1183,
+1170,1169,1176,1184,1187,1189,1199,1201,1197,1205,
+1214,1203,1215,1204,1208,1223,1224,1220,1230,1780,
+20526,6087,6094,1781,16266,19553,4527,4967,13400,3540,
+10420,20432,9504,7908,17904,7356,12044,942,10339,17862,
+21113,3495,947,5537,9687,5138,16340,12795,19913,15721,
+17636,17023,4733,11245,11295,14640,20012,12031,4567,10866,
+17275,14645,18444,20737,18600,14384,6887,3311,20680,8930,
+8186,14441,10957,11371,21261,20628,14646,3832,11700,21568,
+2356,1747,11093,10214,15909,3871,3683,11623,11299,17988,
+20709,18472,11377,21078,11372,10912,13094,5969,6565,2548,
+3240,8376,4264,10760,17289,16874,9077,14212,15753,5814,
+16235,9473,14665,13324,9935,20751,1853,1236,1240,1243,
+1239,1237,1262,1261,1273,1263,1270,1279,1285,1290,
+1288,1284,1295,1323,1305,1297,1306,1308,1298,1301,
+1319,1320,1311,1339,1350,1349,1357,1364,1365,1373,
+1380,1387,1381,1393,1402,1405,1423,1417,1413,1496,
+1483,1501,1429,1449,1443,1427,1433,1480,1430,1456,
+1493,1428,1488,1511,1523,1519,1448,1563,1546,1550,
+1568,1569,1590,1591,1580,1605,1606,1608,1598,1615,
+1614,1630,1654,1666,1665,1672,1680,1687,1689,1700,
+1691,1686,1713,1729,1728,1744,1735,1740,1746,1745,
+9494,9172,15206,8380,12347,6839,10421,5195,21127,19620,
+6840,10704,17125,17716,6705,5815,20118,2971,7351,10964,
+6291,17939,15762,17905,4443,16666,5780,11053,16623,8812,
+3489,2399,13325,11395,4702,20257,20518,19032,3789,8796,
+11396,14893,3085,10290,2572,10750,5728,6600,14894,16921,
+12586,14430,9909,2391,7518,18702,17913,11423,5785,7519,
+18713,917,6810,7442,20560,10929,2758,14072,11842,18068,
+18634,6910,11023,11157,12440,11158,9431,8945,17951,11159,
+6923,10352,11028,10241,5660,10767,17006,15528,8622,21239,
+13193,19743,14907,20244,8482,14416,1766,1758,1779,1791,
+1798,1776,1785,1777,1829,1815,1835,1825,1844,1805,
+1809,1828,1790,1845,1830,1810,1808,1898,1894,1897,
+1896,1920,1904,1905,1908,1929,1919,1910,1931,1938,
+1944,1940,1939,1941,1953,1956,1946,1951,1957,1959,
+1972,1962,1975,1974,1976,1983,1991,2004,2007,2000,
+2003,2021,2026,2027,2034,2029,2041,2052,2067,2051,
+2050,2055,2083,2088,2105,2094,2119,2120,2117,2128,
+2122,2127,2137,2142,2139,2145,2150,2152,2166,2165,
+2186,2180,2175,2183,2229,2220,2230,2255,2261,2265,
+6285,19332,21100,7690,20298,19940,1104,3897,12790,21542,
+16782,20568,8817,5164,3370,8409,9603,4823,16562,4280,
+8624,20888,7851,1685,4297,20569,15195,16213,7878,11373,
+8187,19715,10638,16144,4306,11446,21225,11910,12454,10048,
+12122,9378,1782,12534,19430,8931,8759,13555,21171,5682,
+4313,12839,10408,16443,895,17287,18263,12184,9348,6244,
+13270,16498,13091,2089,8761,13614,2252,9283,6212,19606,
+17421,17093,1207,10269,19415,2371,2385,18385,14130,9067,
+5518,2090,6449,10371,2437,11932,15030,21448,8763,18329,
+21381,8779,2528,12708,21631,13294,2306,2285,2287,2278,
+2286,2281,2305,2310,2318,2321,2319,2335,2328,2332,
+2342,2346,2348,2340,2354,2355,2364,2373,2388,2384,
+2378,2389,2394,2404,2407,2403,2417,2405,2406,2408,
+2449,2445,2478,2447,2501,2536,2493,2495,2507,2521,
+2518,2535,2498,2496,2545,2546,2550,2551,2569,2592,
+2597,2585,2588,2584,2586,2625,2620,2618,2614,2640,
+2648,2638,2646,2675,2676,2693,2694,2703,2709,2733,
+2724,2735,2728,2726,2729,2716,2721,2756,2750,2760,
+2766,2764,2791,2774,2796,2778,2785,2775,2772,2808,
+9962,8501,1793,11256,7352,6148,13621,9465,19159,16754,
+12709,10591,11591,13923,18276,3907,16152,19236,8734,16465,
+14913,20655,4100,17099,3488,15648,11612,15732,12815,4175,
+4752,13629,13069,10692,5387,15143,4269,10146,14954,15497,
+6465,12273,8996,15734,17102,12649,9738,16511,20050,4115,
+9114,12030,18577,21312,2195,12820,1008,12190,10193,10382,
+8620,2903,2441,19121,9424,12390,12821,12822,3181,21599,
+2993,10596,6994,14238,9332,20299,7520,17053,3911,3770,
+1800,20104,13077,3608,9664,7521,16922,20497,13108,7443,
+19791,21391,6128,8738,20260,9454,2803,2805,2851,2836,
+2838,2819,2854,2859,2861,2872,2864,2867,2879,2882,
+2890,2892,21361,2898,2444,2905,2912,2913,2920,2926,
+2915,2933,2938,2963,2950,2954,2948,2974,2976,2983,
+3001,3012,3021,3022,3019,3017,3014,3006,3037,3045,
+3053,3043,3084,3069,2889,3058,3057,3093,3117,3123,
+3141,3143,3130,3153,3164,3162,3177,3170,3171,3196,
+3204,3205,3200,3207,3215,3220,3225,3231,3232,3228,
+3255,3252,3260,3267,3274,3291,3295,3308,3309,3313,
+3317,3318,3354,3329,3333,3319,3335,3342,3330,3344,
+7820,2814,18717,13633,3496,18873,12281,12282,19642,12426,
+12824,919,8701,7379,19796,13928,12125,3032,1861,18516,
+10710,17224,8946,9400,9432,21017,9680,9688,4505,13636,
+12126,19272,9693,10242,10243,11408,14858,5661,9223,1934,
+18297,13775,19949,15295,10699,17566,18531,12671,1362,4125,
+21071,21072,18737,14570,19531,20924,15776,4991,11114,15161,
+10955,2151,10494,19666,16717,21262,5755,17086,20809,5232,
+5233,14881,7934,14443,5062,9066,3684,15570,5552,5647,
+21724,10070,10414,3520,20845,1469,2807,6702,19510,19115,
+21507,6897,20646,19928,16720,17245,3331,3372,3367,3364,
+3366,3373,3403,3399,3410,3427,3411,3422,3423,3415,
+3421,3425,3451,3464,3465,3480,3481,3500,3518,3532,
+3515,3513,3519,3512,3534,3545,3535,3541,3537,3562,
+3555,3564,3579,3568,3569,3580,3589,3584,3582,3603,
+3595,3606,3617,3619,3623,3613,3620,20383,3628,3650,
+3648,3663,3693,3685,3674,3666,3677,3692,3723,3716,
+3720,3740,3736,3734,3769,3751,3745,3746,3747,3750,
+3757,3759,3758,3761,3786,3775,3790,3779,3774,3806,
+3801,3802,3805,3821,3820,3854,3858,3824,3836,3848,
+18482,20818,18748,10918,14938,3695,1326,20656,19424,7176,
+5237,15494,14944,10707,15324,5018,17941,12725,19792,6989,
+15008,2196,3441,5786,15217,9568,11879,11071,3533,9672,
+19982,20829,20167,9459,13835,17581,15967,13720,21543,2115,
+18921,17143,11714,13342,4709,6039,20013,20801,7974,20802,
+19709,8836,1177,12259,11650,9619,19466,12260,1823,10049,
+11716,21755,20810,8288,6872,15910,20945,6873,6101,19102,
+21492,20946,13731,4075,21265,11871,5008,5212,20276,14882,
+9068,5127,7987,15640,15996,18209,10599,10423,5555,21760,
+21408,1211,6966,20967,9071,9466,3873,3880,3875,3881,
+3887,3889,3906,3898,3894,3914,3918,3919,3941,3944,
+3948,3957,3950,3955,3949,3958,3978,3987,3984,3990,
+3994,3998,4005,3977,4020,4023,4029,4058,4025,4060,
+4064,4063,4070,4078,4071,4073,4076,4069,4087,4090,
+4101,4091,4092,4094,4111,4123,4119,4120,4145,4141,
+4155,4143,4170,4162,4169,4166,4171,4196,4184,4181,
+4193,4211,4219,4208,4240,4236,4226,4237,4235,4268,
+4257,4267,4255,4273,4251,4256,4305,4286,4293,4326,
+4316,4308,4360,4370,4369,4396,4395,4399,4398,4411,
+12208,9994,21675,19752,10565,10566,18751,17043,1575,7177,
+4930,1497,11949,7753,21065,21589,17827,2452,3542,9799,
+21513,19773,17910,20990,5218,5529,13812,15211,13833,7190,
+8632,1988,10980,21008,7178,10445,15095,6990,19343,16596,
+13353,9102,19033,6642,13165,7119,17444,12587,7635,21421,
+15934,21735,10508,15219,11881,14098,6811,13673,11957,19797,
+12427,7211,16066,16597,2486,6911,8947,10510,1645,14100,
+21422,9542,3161,18186,19547,14379,8015,18615,9318,18601,
+1234,1748,16197,21202,7707,3803,16689,5712,2891,18619,
+17422,2514,8807,3431,21449,17824,4418,4424,4437,4442,
+4433,4432,4439,4449,4453,4469,4456,4459,4468,4492,
+4481,4483,4499,4475,4485,4510,4514,4521,4522,4516,
+4520,4519,4541,4542,4539,4556,4555,4553,4554,4560,
+4561,4563,4575,4585,4578,4580,4576,4600,4608,4609,
+4619,4624,4620,4622,4626,4650,4661,4647,4652,4646,
+4649,4668,4680,4671,4701,4707,4704,4708,4711,4712,
+4721,4731,4730,4750,4737,4747,4722,4732,4740,4772,
+4768,4777,4780,4785,4784,4800,4806,4812,4843,4820,
+4841,4860,4869,4924,4913,4880,4904,4854,4876,4870,
+15094,5614,21419,16641,16205,18210,13326,18578,18579,15799,
+2349,15735,3816,8326,9877,16914,16809,8957,2897,20531,
+8894,8895,2485,3210,9880,20221,3168,13134,13333,4013,
+20225,10266,13170,2820,14560,4986,12858,2826,6236,12675,
+6016,14467,4654,11209,13505,21263,10050,10216,1767,1117,
+15001,6249,8056,3810,18988,14815,8052,13509,12456,9505,
+21320,2086,3575,3219,16224,8072,8612,8073,9377,12194,
+2593,10802,21199,16252,7658,15162,13222,18161,21374,19867,
+6002,2081,12295,18859,3932,14186,17088,21204,11505,5473,
+13155,11275,1226,2061,12156,10060,4894,4901,4919,4912,
+4853,4952,4951,4964,4959,4960,4956,4963,4968,4953,
+4971,4994,5000,5034,5013,4989,5004,4980,4987,4978,
+5016,4982,5006,4979,4983,4981,5015,4984,5045,5044,
+5052,5070,5085,5078,5079,5081,5091,5092,5097,5103,
+5104,5099,5123,5128,5120,5124,5150,5153,5156,5166,
+5165,5160,5159,5158,5180,5181,5201,5187,5190,5198,
+5188,5202,5213,5220,5219,5227,5250,5257,5255,5240,
+5253,5251,5247,5254,5273,5279,5275,5281,5272,5283,
+5313,5308,5309,5317,5319,5320,5332,5327,5329,5344,
+11905,4905,4487,5126,4528,14605,10857,14651,13312,11276,
+10656,5775,13442,2602,19111,18620,1422,9084,7665,15245,
+13869,6960,6007,21081,9161,3454,2069,4838,16000,9495,
+9286,8258,5628,7425,5935,15941,17098,20969,2522,15163,
+21278,21761,15857,2070,5235,5112,8905,20024,11962,17475,
+12547,9163,21648,12021,1499,5314,15358,5600,19556,7357,
+20552,6398,20755,14154,21128,10431,9963,8529,4931,20324,
+5486,12886,8530,2927,2073,21676,1875,17942,1555,15248,
+17248,12492,17686,6371,14539,19939,2941,10524,16696,3945,
+14915,7077,7800,17687,10967,4535,5348,5352,5354,5364,
+5369,5368,5376,5379,5371,5378,5366,5374,5365,5394,
+5395,5396,5404,5403,5415,5412,5414,5429,5428,5442,
+5439,5441,5446,5481,5474,5462,5485,5461,5465,5464,
+5463,5524,5495,5513,5504,5500,5501,5543,5545,5541,
+5553,5564,5563,5582,5585,5589,5594,5596,5597,5603,
+5612,5605,5607,5608,5606,5629,5625,5663,5642,5657,
+5639,5667,5688,5695,5717,5702,5699,5711,5698,5701,
+5706,5742,5753,5746,5751,5773,5769,5779,5772,5765,
+5799,5800,5812,5828,5821,5841,5856,5868,5872,5879,
+2875,4754,21288,6262,13163,13350,11202,12984,5488,14588,
+20032,6124,15501,19974,2713,13971,20758,11789,12986,17478,
+5388,12086,4067,21460,2789,14159,21289,13016,10227,7367,
+1927,6805,1515,3634,3086,18237,14110,3166,12318,12404,
+19798,16045,20258,14160,5787,18832,6434,2241,8813,12497,
+20219,6995,10307,2075,11731,15268,3167,3793,15269,9383,
+9810,17445,1862,11141,14161,3497,9885,3392,4975,7444,
+11287,9022,3357,7639,15249,9333,17453,10460,14689,20135,
+12781,12023,12736,12321,5133,8333,10461,10455,18288,3461,
+14012,21296,5424,12896,9758,14690,5883,5882,5884,5893,
+5890,5892,5891,5906,5910,5916,5933,5915,5929,5931,
+5917,5944,5942,5983,5982,5956,5953,5981,5955,5963,
+5951,5948,5993,5999,6003,6029,6028,6023,6018,6035,
+6034,6044,6036,6043,6067,6070,6096,6102,6093,6074,
+6079,6076,6075,6100,6114,6089,6081,6098,6151,6150,
+6152,6139,6166,6165,6170,6173,6174,6176,6178,6177,
+6190,6192,6184,6204,6205,6207,6239,6247,6235,6224,
+6220,6222,6286,6284,6288,6300,6305,6310,6303,6321,
+6318,6323,6366,6352,6363,6351,6373,6349,6372,6360,
+9218,9024,19647,19977,6031,20667,15367,15704,11801,2745,
+18839,12746,15615,21338,21157,4472,14789,21156,12944,21473,
+15617,10469,10353,7389,16187,19328,19812,9187,10246,13171,
+9764,9227,12904,19984,21054,13495,9765,1566,4108,21702,
+9543,14550,10632,19331,19986,21475,19821,4482,14371,20570,
+14380,11917,6088,11647,3227,20507,12863,20374,1418,1163,
+16789,14125,8625,13837,1419,15197,19145,20574,11094,15377,
+6420,5107,8294,11378,21145,2563,15115,6250,15913,2062,
+9960,21348,1118,9312,4384,13443,6107,17294,4920,9561,
+19968,10432,8232,12716,1132,20479,6348,6391,6393,6410,
+6401,6412,6404,6444,6455,6454,6461,6460,6476,6474,
+6473,6477,6501,6499,6498,6500,6511,6516,6531,6537,
+6530,6566,6576,6580,6575,6590,6593,6582,6578,6574,
+6570,6607,6611,6617,6641,6639,6644,6612,6614,6623,
+6629,6660,6664,6657,6663,6678,6684,6696,6713,6682,
+6731,6718,6774,6735,6785,6741,6763,6760,6758,6761,
+6744,6756,6743,6745,6752,6749,6830,6828,6831,6846,
+6843,6856,6867,6871,6875,6874,6888,6882,6894,6906,
+6883,6892,6929,6935,6952,6936,6965,6978,6949,6971,
+5865,6450,14029,15498,1577,11182,21633,7505,9509,17606,
+4847,11952,1336,5531,17783,7259,21352,15505,14032,4717,
+7598,11340,14033,14034,11956,2670,9826,8882,1880,6558,
+14787,7212,17314,16048,11806,9689,21783,3638,11807,15809,
+9267,14923,8111,5372,20764,8113,19524,7143,2143,21139,
+18085,19938,6237,19549,5249,16253,13755,16564,13384,11502,
+21487,15959,11862,4804,7147,14736,2952,12261,20708,14126,
+6241,20892,7045,4656,20016,13758,3402,7884,4570,3193,
+8138,20094,1064,4831,20948,12639,2710,6245,20095,17027,
+4906,17582,14388,1788,21266,13507,6938,6932,6944,6987,
+6928,6941,6947,6953,6961,7026,7033,7057,7069,7092,
+7061,7024,7041,7047,7030,7032,7063,7031,7108,7101,
+7109,7102,7168,7131,7187,7136,7126,7159,7135,7155,
+7142,7153,7152,7124,7125,7140,7130,7134,7129,7148,
+7127,7257,7236,7228,7232,7241,7227,7268,7278,7292,
+7287,7293,7307,7312,7304,7306,7305,7308,7320,7330,
+7319,7317,7334,7321,7349,7329,7325,7326,7316,7341,
+7401,7410,7400,7432,7418,7397,7404,7426,7399,7407,
+7406,7467,7498,7494,7491,7468,7458,7495,7504,7459,
+10061,21267,14318,5144,18503,4907,16147,20682,3340,2831,
+14524,21042,17196,21688,8079,1179,13475,11379,14809,21720,
+8933,7984,13763,6008,17588,7792,21174,2725,5592,1119,
+8431,8934,6362,3051,6542,5337,15540,17532,8840,7666,
+13560,5071,10657,17991,1366,17290,4915,5318,15914,13798,
+15804,19112,9419,17589,8377,5063,3843,15940,14934,7591,
+17353,6765,8432,7427,8381,2570,16607,20713,10498,2523,
+13403,14750,1198,15942,17427,6544,13180,5355,17781,15647,
+17792,17538,6255,17038,4921,15841,15186,4130,9072,4839,
+7991,6424,20819,18270,8095,4776,7470,7475,7464,7463,
+7478,7486,7473,7462,7548,7539,7540,7542,7538,7561,
+7569,7567,7566,7565,7581,7593,7585,7631,7616,7634,
+7617,7615,7606,7607,7611,7614,7609,8468,7663,7662,
+7660,7650,7661,7652,7648,7654,7687,7653,7667,7711,
+7719,7708,7709,7701,7712,7747,7736,7735,7739,7751,
+7733,7805,7767,7763,8220,7772,7788,7799,7808,7777,
+7778,7832,7829,7842,7867,7843,7848,7854,7837,7850,
+7853,7845,7869,7889,7871,7874,7870,7876,7894,7898,
+7904,7895,7903,7923,7942,7930,7941,7922,7932,7931,
+7167,17898,13734,21590,2398,4220,9652,10521,9822,2734,
+13594,14319,12717,21406,12719,16283,12980,17299,14717,16407,
+15572,16284,5175,16330,1371,21384,1955,5866,3206,10592,
+10180,12779,20457,1500,2988,10080,11150,12647,13160,15733,
+21591,5804,21649,16894,21514,17730,9835,7909,4590,13931,
+11258,19765,21620,4491,10522,17906,19242,14284,12720,17911,
+17335,7360,8735,17302,13924,11151,6979,4102,2699,3709,
+11259,10841,19892,17599,1253,14955,13351,1556,6568,5340,
+3082,11178,16512,5021,16470,15956,5421,11203,17544,9800,
+21593,1601,5807,19122,15651,5574,7919,7920,7975,7992,
+7972,7989,7986,7996,7969,7980,7993,7990,7971,8005,
+8030,8017,8016,8064,8060,8054,8068,8034,8043,8059,
+8051,8044,8032,8088,8093,8119,8110,8107,8135,8137,
+8128,8134,8126,8139,8152,8153,8143,8144,8157,8145,
+8154,8147,8213,8176,8178,8184,8175,8180,8224,8216,
+8250,8254,8253,8252,8315,8278,8301,8273,8282,8303,
+8320,8311,8290,8272,8300,8287,8293,8341,8345,8340,
+8366,8374,8354,8370,8389,8478,8401,8418,8413,8458,
+8412,8396,8399,8410,8489,8499,8494,8487,8488,8519,
+20998,20073,2479,2194,3351,17103,19893,21621,17834,14484,
+16366,5341,14114,19310,7954,19034,21386,11709,1194,5530,
+12046,21153,7368,3004,13574,14868,20076,17105,3182,7191,
+13817,15551,5027,20033,20693,5221,13907,6376,20131,15608,
+17306,15147,20694,21635,15552,6668,1960,1516,4779,3144,
+9516,15270,18339,17000,21637,9395,21332,12989,10785,20858,
+10509,11400,12392,9745,18000,21623,6996,14200,15220,10526,
+1372,18758,14058,11323,13047,6848,17166,7198,14144,17799,
+13663,18001,15224,13080,20301,21765,20826,14241,14035,9981,
+19799,4501,9886,2337,21741,7527,8515,8528,8522,8516,
+8524,8545,8544,8546,10204,8552,8554,8571,8559,8567,
+8589,8593,8591,8598,8600,8614,8626,8629,8633,8637,
+8644,8639,8647,8655,8656,8659,8664,8668,8669,8670,
+8680,8695,8692,8673,8702,8703,8708,8714,8715,8716,
+8720,8725,8741,8745,8743,8744,8757,8755,8773,8786,
+8785,8787,8790,8797,8800,8805,8819,8820,8826,8830,
+8843,8832,8841,8846,8853,8855,8857,8856,8864,8872,
+8866,8865,8884,8892,8896,8904,8909,8929,8926,8932,
+8923,8922,8950,8954,8952,8955,8971,8963,8977,8992,
+13709,2243,13936,17800,6812,6495,21698,16928,13049,20034,
+3300,14487,6815,7213,14099,7445,7562,6559,13081,3089,
+7868,7694,1531,2204,19057,11885,15225,19058,14141,13884,
+7218,1708,12959,9219,12590,18072,12747,12225,18637,11409,
+9457,17555,21701,8948,19449,17915,9401,17176,2212,7697,
+10354,2213,19276,1945,13689,17180,21712,21703,10667,17007,
+9255,9412,9809,6227,13749,21244,20700,3829,17026,19231,
+15568,20065,17291,3173,17568,4808,4809,12626,1789,12483,
+17382,20548,5176,19250,5654,21742,15425,2017,12825,16628,
+19268,9402,15432,10355,14973,5154,9008,9004,9005,9028,
+9029,9062,9075,9080,9078,9089,9088,9103,9104,9115,
+9124,9120,9127,9106,9148,9141,9173,9196,9192,9191,
+9190,9204,9195,9188,9200,9198,9237,9235,9244,9238,
+9256,9257,9279,9281,9274,9277,9270,9296,9308,9311,
+9314,9316,9340,9341,9343,9360,9357,9356,9379,9369,
+9388,9396,9425,9422,9446,9426,9417,9451,9440,9443,
+9441,9463,9464,9469,9476,9478,9486,9514,9515,9479,
+9480,9493,9558,9549,9550,9566,9547,9482,9605,9581,
+9611,9583,9578,9585,9618,9577,9584,9630,9590,9598,
+13649,14373,5471,21226,8188,10999,11247,5591,15642,8378,
+4916,14394,5593,21450,19753,962,4444,14945,10708,10182,
+1101,4446,2350,16518,1507,7199,2690,10185,8387,11142,
+20561,10621,12322,7014,7020,10548,11086,3283,18469,19502,
+19500,4676,1065,18521,5506,12997,20172,5189,18958,21268,
+18808,13799,13645,13044,6545,17295,18990,18509,13014,12933,
+19625,5342,19899,4502,14203,4694,14204,9780,11891,13053,
+5405,2682,4657,6242,2647,3194,4908,17089,12172,9107,
+12264,10189,20949,13476,16951,17533,16878,8706,6767,6695,
+17423,14153,6256,7547,3543,14155,9634,9580,9626,9588,
+9597,9576,9503,9553,9710,9721,9718,9714,9757,9725,
+9716,9717,9715,9766,9768,9793,9786,9785,9783,9819,
+9813,9815,9820,9811,9828,9842,9846,9844,9839,9841,
+9869,9855,9856,9854,9875,9857,9853,9352,9902,9908,
+9881,9859,9906,9914,9933,9926,9915,9929,9959,9952,
+9979,9977,9953,9951,9988,9957,9996,10012,10009,10027,
+10044,10067,10078,10079,10051,10028,10063,10046,10030,10052,
+10035,10112,10116,10115,10119,10128,10140,10130,10138,10126,
+10121,10145,10125,10173,10187,10205,10218,10207,10217,10226,
+2662,17943,2667,21594,16297,6710,6295,6153,12393,9746,
+13485,1012,9982,12173,13135,1014,6816,17952,3550,9339,
+5432,5435,5433,3833,13915,4377,4084,15836,12265,2599,
+13519,7246,8295,2780,10600,7071,20259,10291,7001,9365,
+6915,19450,6509,18906,13195,20018,3371,6243,20837,20838,
+20683,2383,20745,19505,16215,15770,4385,18207,15813,14106,
+6050,14504,9936,7994,1424,3660,5851,16572,17907,12484,
+3072,3908,3909,15864,8264,3083,8956,9739,9740,16624,
+9016,9747,9752,3087,14478,15045,15843,9023,11795,20859,
+3393,11837,13142,7531,15844,15846,10219,10258,10260,10257,
+10280,10273,10300,10306,10310,10308,10323,10321,10335,10322,
+10327,10369,10365,10366,10372,10466,10422,10316,10425,10401,
+10411,10444,10415,10398,10394,10434,10474,10486,10496,10488,
+10491,10505,10497,10499,10515,10519,10513,10516,10419,10517,
+10531,10532,10530,10536,10557,10558,10561,10562,10571,10579,
+10574,10573,10576,10577,10601,10612,10620,10608,10613,10616,
+10617,10618,10640,10658,10650,10653,10651,10671,10675,10684,
+10685,10686,10682,10701,10714,10712,10715,10718,10728,10729,
+10725,10730,10749,10746,10743,10761,10780,10768,10775,10776,
+10247,20545,14996,15128,20554,18888,13372,8740,2045,5245,
+3614,6572,2617,13750,13891,19917,2099,5919,4674,12129,
+12074,19459,13652,16591,12673,12291,16831,16832,8742,3830,
+1446,1080,1817,13469,15722,21544,4607,20803,11696,12180,
+21570,4824,17192,11442,13437,8674,2623,18443,12075,2557,
+17745,4380,6188,21571,5709,2511,15796,3195,10900,17524,
+17525,10731,17526,11815,16604,16594,17764,8053,19506,6181,
+9931,14184,15876,10904,2955,14444,7274,15592,8343,7054,
+17763,17666,16126,2515,16070,4003,11606,12332,5512,9461,
+20509,15201,7750,9833,14872,1621,10770,10795,10803,10799,
+10994,10793,10817,10825,10833,10840,10827,10828,10856,10849,
+10864,10865,10872,10881,10867,10890,10896,10895,10902,10922,
+10926,10916,10894,10899,10907,10945,10936,10938,10954,10959,
+10951,10958,10971,10983,10990,11001,11036,11021,11005,11037,
+11034,11046,11045,11096,11064,11072,11067,11057,11060,11055,
+11085,11116,11112,11111,11132,11117,11121,11149,11145,11147,
+11170,11162,11166,11168,11175,11181,11188,11190,11191,11204,
+11198,11200,11207,11206,11221,11217,11234,11268,11264,11274,
+11273,11272,11292,11311,11293,11300,11291,11318,11321,11325,
+10590,12368,5874,13561,2924,3428,11628,11514,13764,14445,
+2985,8199,3969,12308,5846,16664,10919,13921,4173,2657,
+10615,11988,3696,936,11611,14847,20069,21063,13843,16001,
+16461,7672,7255,4099,1482,2292,12954,16218,14714,15495,
+15134,21382,19001,9862,7072,12312,17540,10502,11977,2297,
+10437,5853,12078,2853,7577,4844,21310,10438,7630,19353,
+10480,18031,2077,15932,11710,9878,3209,5729,17440,15598,
+4497,20857,7633,6344,3208,18724,17336,15189,4716,21295,
+3409,8880,11880,8459,2848,8361,9129,9777,16103,12737,
+3213,1720,18067,11618,16669,20188,11331,11346,11332,11333,
+11339,11336,11349,11352,11355,11376,11391,11401,11364,11386,
+11385,11366,11420,11413,11428,11437,11435,11434,11436,11429,
+11467,11475,11468,11464,11474,11450,11452,11472,11458,11479,
+11485,11491,11621,11501,11494,11499,11497,11521,11518,11519,
+11531,11529,11544,11539,11549,11568,11584,11604,11602,11613,
+11615,11625,11627,11493,11635,11636,11642,11665,11648,11646,
+11643,11674,11673,11698,11707,11697,11705,18231,11712,11713,
+11729,11728,11724,11737,11741,11744,11747,11758,11760,11769,
+11799,11771,11786,11787,11768,11817,11823,11822,11830,11819,
+17312,1642,17733,9056,9132,18239,10351,6921,20098,10644,
+13496,20189,10549,11670,20099,12859,16654,5696,9980,5693,
+7647,7162,5193,2761,11152,11790,5278,7488,3845,20816,
+17766,15359,17271,2100,13616,19682,17688,8265,8163,17671,
+14339,8136,15389,14673,15458,12611,12612,5631,6496,15763,
+17100,3507,4484,12000,15378,4486,2866,10331,10066,17090,
+13319,12084,8849,4922,20217,4778,9497,19616,9287,15880,
+1846,11740,8205,6638,21595,1602,11477,3857,3983,1216,
+2110,19035,2015,10292,3355,18032,18632,3577,3462,13039,
+10387,18874,7091,7532,6916,12748,11821,11845,11851,11855,
+11861,11858,11870,11869,11866,11886,11901,11908,11912,11915,
+11928,11924,11923,11936,11954,11958,11942,11961,11968,11971,
+11969,11992,11986,11987,11994,12001,11999,12004,12011,12012,
+12007,12014,12017,12020,12016,12027,12026,12034,12033,12037,
+12045,12061,12062,12055,12059,12071,12081,12083,12094,12098,
+12099,12103,12102,12107,12110,12117,12119,12127,12131,12137,
+12141,12139,12135,12155,12148,12147,12163,12168,12181,12177,
+12183,12215,12199,12209,12200,12207,12217,12218,12192,12210,
+12231,12237,12250,12257,12284,12247,12252,12272,12306,12292,
+10389,10356,2216,14861,7370,12455,18412,18428,2040,9374,
+15833,15771,7605,12191,18896,2097,11144,5094,19700,6408,
+21561,6750,15167,20902,16093,16427,12791,16560,13721,4862,
+21245,6445,8403,7133,1021,2773,10862,13776,5996,19136,
+19498,18907,13139,12331,3672,3616,9596,19429,1304,18852,
+21250,11677,1813,1741,17779,18597,17144,6232,20347,3923,
+3823,11765,6327,10897,14463,5565,1441,16492,4875,21479,
+20882,7144,3063,11749,18017,5271,9604,13789,2155,2410,
+19710,6011,21562,9922,16714,4185,5705,3048,5444,5677,
+7613,19579,21484,4438,10819,21073,12299,12307,12294,12285,
+12327,12333,12350,12341,12355,12363,12360,12358,12381,12389,
+12387,12399,12408,12416,12419,12425,12435,12431,12443,12449,
+12450,12462,12464,12477,12458,12460,12473,12459,12466,12500,
+12502,12505,12511,12533,12539,12526,12535,12540,12558,12566,
+12555,12575,12578,12576,12580,12594,12592,12593,12597,12595,
+12601,12614,12613,12636,12638,12624,12630,12619,12615,12623,
+12646,12621,12618,12667,12701,12668,12670,12692,12686,12680,
+12660,12715,12672,12659,12698,12769,12760,12756,12758,12762,
+12797,12798,12818,12783,12787,12788,12789,12793,12784,12827,
+12856,21200,6536,4825,5058,3284,2878,7976,4378,968,
+13088,2594,12471,7879,9345,14805,21343,3285,2056,19580,
+4074,16436,9481,3997,4829,13730,19146,1918,20042,15173,
+2506,2413,16715,1674,16851,5353,21264,11375,21346,21756,
+16122,13385,15256,2414,12196,11000,17725,7978,2370,8495,
+18259,3253,5960,3254,7272,16315,19468,11863,14289,17284,
+16601,7783,11548,11461,16026,11637,10818,3050,3686,13470,
+3933,21644,9108,10409,16499,11773,9037,12577,20115,5211,
+5860,10588,2722,2921,20453,10978,9487,1266,13237,8359,
+13196,3656,7740,7900,13092,15355,12836,12837,12862,12848,
+12860,12867,12842,12851,12878,12843,12873,12919,12937,12917,
+12918,12912,12932,12952,12947,12957,12970,12972,12962,12979,
+12995,12990,13004,12991,13026,13028,13025,13041,13074,13067,
+13065,13056,13090,13107,13086,13087,13115,13132,13130,13126,
+13122,13119,13124,13138,13141,13143,13146,13148,13174,13173,
+13172,13194,13199,13204,13190,13210,13201,13228,13235,13245,
+13247,13246,13248,13249,13255,13278,13271,13273,13268,13282,
+13283,13290,13318,13308,13341,13336,13338,13392,13373,13366,
+13381,13375,13446,13421,13440,13422,13441,13431,13429,13474,
+5334,6458,13177,930,16324,1376,21125,7336,9992,15438,
+15726,3538,6394,6103,2934,2290,6538,4632,9157,14149,
+18315,18805,14308,7160,5611,2063,20684,16182,8116,1459,
+18961,11002,1282,12123,3902,13346,8682,17383,16296,19673,
+19674,5009,9792,17934,11560,2068,16638,2969,17424,1551,
+11465,933,19297,9085,9086,7545,11176,21759,21780,21665,
+13841,16985,18688,934,13477,7342,4917,10520,7343,12170,
+6251,6252,6289,18386,15977,21503,13274,11098,6626,14391,
+5082,21146,7489,16452,1832,16358,7163,4095,18621,15175,
+13562,20639,6838,14528,9194,21585,13504,13506,13511,13522,
+13514,13533,13585,13540,13575,13544,13539,13554,13547,13588,
+13597,13596,13605,13604,13607,13608,13623,13625,13615,13613,
+13644,13646,13658,13662,13665,13668,13680,13686,13687,13685,
+13690,13695,13702,13707,13710,13711,13716,13715,13713,13726,
+13752,13742,13738,13736,13746,13745,13772,13773,13778,13784,
+13790,13807,13791,13818,13810,13806,13792,13788,13829,13839,
+13836,13857,13864,13885,13873,13877,13861,13893,13892,13890,
+13895,13906,13914,13912,13933,13944,13943,13951,13952,13960,
+13962,13978,13979,13988,14002,14005,14000,14009,14014,14017,
+18534,19838,10913,19989,14810,21325,5613,13671,18005,9007,
+16453,19509,15066,19116,14532,2959,14582,19991,20647,13870,
+9643,13606,19888,9644,8261,16887,2776,17846,16002,10135,
+6899,3741,12977,21666,12537,3242,19840,2781,19754,12041,
+12579,11511,16956,4681,20025,13969,2013,11061,15236,11305,
+15067,10136,16957,5477,9280,5086,3259,15488,10639,17938,
+18608,5778,21618,5801,21781,15779,2071,12157,9197,14395,
+9301,10074,3811,15780,10858,15891,21207,938,9729,3073,
+12485,13348,7910,2962,7809,16408,16057,2033,19774,19002,
+8233,1484,10376,1924,20480,9391,14025,14027,14041,14043,
+14050,14054,14056,14066,14068,14085,14074,14077,14107,14111,
+14127,14120,14115,14119,14116,14117,14142,14147,14152,14158,
+14162,14180,14218,14170,14164,14168,14194,14175,14205,14206,
+14234,14240,14237,14224,14216,14220,14232,14259,14253,14255,
+14274,14273,14278,14281,14270,14287,14286,14292,14288,14304,
+14303,14309,14310,14315,14313,14314,14321,14323,14332,14329,
+14334,14346,14350,14341,14348,14342,14338,14337,14385,14363,
+14369,14366,14367,14387,14381,14372,14407,14414,14415,14422,
+14438,14435,14447,14442,14458,14455,14476,14465,14454,14483,
+13031,10779,18277,10081,7164,1625,5805,5945,3629,10433,
+14354,14263,3630,18056,1883,3704,3243,14398,17996,6368,
+1007,11100,10284,21045,12513,7573,11131,3074,11754,6781,
+8384,19162,14195,19117,5852,2425,6430,14131,8810,12981,
+10678,2020,20249,9510,16471,7078,12934,14507,11011,11991,
+2237,3742,13934,9423,19626,13101,2787,6466,7361,10722,
+20029,1229,19487,10446,13697,4337,15652,4616,8449,4638,
+13872,4686,9017,14891,18182,17835,5022,3490,16722,3946,
+14956,17441,17048,10224,20074,14298,7362,15239,10086,19783,
+17104,15010,11878,17946,20077,19775,14490,14498,14499,14468,
+14494,14512,14511,14522,14520,14527,14516,14510,14514,14552,
+14556,14568,14559,14555,14572,14571,14562,14561,14595,14596,
+14599,14604,14601,14600,14618,14616,14609,14612,14639,14623,
+14635,14675,14649,14625,14636,14662,14679,14642,14614,14624,
+14660,14630,14610,14615,14634,14632,14628,14629,14698,14699,
+14703,14701,14705,14710,14709,14706,14716,14708,14756,14728,
+14738,14735,14724,14751,14726,14746,14739,14745,14722,14768,
+14767,14770,14782,14774,14783,14776,14779,14775,14777,21229,
+14795,14799,14803,14797,14796,14804,14818,14807,14814,14819,
+16964,6058,909,6797,6798,7192,3030,17333,16299,11222,
+9468,7554,1995,14400,13035,9748,8691,19900,3297,15698,
+15469,20407,15240,17163,4498,3892,17607,5532,14781,7514,
+6015,13994,18059,18628,1134,4134,12438,16476,11835,2741,
+10716,12400,12823,20205,2432,20662,4408,11689,19315,3110,
+17446,12733,4447,7437,17912,8982,1579,3818,11138,9207,
+7960,13331,13166,17249,17222,15151,10482,19052,17914,17561,
+19053,9116,9429,7726,3636,20898,1292,18633,11403,6601,
+1639,15087,15426,16058,13334,13109,16528,10160,6806,11980,
+5224,20082,1256,9681,14785,21189,14806,14831,14833,14836,
+14835,14837,14838,14845,14843,14851,14848,14864,14871,14875,
+14885,14883,14886,14895,14888,14889,14897,14906,14903,14902,
+14933,14952,14949,14928,14924,14922,14921,14968,15004,14974,
+15003,14971,14976,14977,14986,14969,15017,15039,15036,15051,
+15050,15048,15047,15049,15063,15072,15084,14911,15090,15092,
+15101,15110,15111,15118,15131,15123,15126,15112,15104,15106,
+15159,15164,15165,15168,15183,15184,15182,15192,15207,15194,
+15218,15202,15208,15196,15229,15242,15243,15264,15260,15254,
+15266,15276,15275,15279,15273,15299,15292,15293,7828,15306,
+887,10021,17953,13243,9184,16186,16814,13937,13938,12741,
+10347,15097,16067,10816,20085,12498,19692,18069,7214,8082,
+17954,13359,15098,8104,4796,1882,13678,19066,17261,19804,
+8245,9781,9782,19199,13040,19269,10233,15964,6453,19979,
+10101,18587,10931,5991,8962,9220,7219,3498,10789,9458,
+9403,6497,4764,20827,16533,8987,6510,9535,7221,9435,
+6515,10628,7015,8988,10471,7393,14013,15618,9409,13595,
+17464,19080,10552,10982,1669,14930,17409,2832,6335,17814,
+3236,4911,17821,10373,6396,6051,7623,8309,1275,18279,
+20462,20463,8958,1703,17054,14830,15308,15313,15333,15328,
+15345,15352,15351,15347,15376,15379,15368,15373,15372,15384,
+15391,15385,15395,15392,15400,15423,15410,15416,15412,15403,
+15435,15439,15436,15457,15451,15448,15449,15462,15484,15486,
+15479,15482,15499,15478,15502,15516,15521,15518,15532,15530,
+15539,15537,15546,15538,15569,15563,15562,15567,15564,15584,
+15585,15590,15613,15603,15600,15604,15624,15623,15626,15625,
+15638,15654,15656,15634,15670,15691,15699,15686,15682,15678,
+15677,15707,15710,15729,15715,15725,15718,15754,15750,15768,
+15772,15775,15801,15807,15811,15816,15827,15830,15834,15838,
+3778,13376,2463,14515,8411,20571,14331,19550,5921,21548,
+17360,4547,4307,1066,2626,12865,16565,19957,19958,8496,
+12681,15908,12682,19868,8416,6728,13197,12683,21076,11462,
+16316,4677,4678,6004,4995,13655,12112,11657,3341,12478,
+2600,8296,9628,5003,20338,5436,12302,1873,17198,3783,
+1675,1749,20396,15817,5514,19293,5280,3052,6732,10813,
+5010,9932,18747,17203,9635,18976,12486,7793,14333,18809,
+16328,11381,13157,5759,13321,9350,17684,7861,13404,7279,
+16078,2372,1328,5971,17965,20714,4970,17246,9288,1485,
+19841,19511,7801,3429,3762,6733,15832,15849,15853,15850,
+15851,15871,15878,15888,15904,15917,15933,15895,15911,15897,
+15912,15938,15937,15939,15936,15944,15947,15954,15953,15965,
+15966,15968,15970,15983,15987,15992,15990,15993,16017,16019,
+16025,16030,16034,16056,16059,16071,16079,16080,16075,16082,
+16091,16102,16117,16109,16127,16146,16134,16132,16141,16172,
+16168,16179,16181,16193,16190,16201,16194,16191,16208,16214,
+16222,16226,16238,16229,16234,16251,16255,16242,16256,16247,
+16282,16264,16265,16280,16270,16261,16269,16289,16295,16308,
+16312,16309,16321,16317,16319,16339,16341,16337,16336,16344,
+15031,8206,12721,19766,8531,14946,10593,9653,3855,15573,
+9048,5937,5976,1213,4604,16466,4144,19845,15291,12955,
+13945,11661,16467,9836,3935,4334,1166,3705,16331,1979,
+11099,2187,9125,7067,15865,10883,17836,11153,7755,14586,
+17944,18335,13845,16367,5023,19894,10968,16513,13925,17546,
+17071,19245,14540,2700,15468,21180,21596,15653,19895,11012,
+9128,4032,13352,16963,16644,19994,13510,19307,7550,1150,
+14959,3054,16917,16613,9749,1151,13819,7086,16697,17798,
+5984,18827,1395,6467,18871,4079,11536,6126,6377,6736,
+10693,19037,16577,19311,15609,21047,16374,16360,16343,16379,
+16384,16391,16381,16393,16395,16378,16406,16396,16428,16444,
+16429,16423,16424,16425,16426,16489,16507,16491,16493,16494,
+16501,16527,16490,16503,16500,16497,16508,16488,16548,16541,
+16566,16557,16563,16559,16586,16595,16592,16598,16611,16610,
+16625,16630,16642,16632,16640,16646,16665,16653,16659,16651,
+16681,16679,16685,16672,16677,16684,16682,16701,16707,16711,
+16705,16704,16702,16741,16729,16746,16731,16757,16733,16743,
+16734,16772,16803,16791,16781,16770,16771,16787,16784,16827,
+16893,16828,16821,16863,16829,16869,16899,16823,16888,16849,
+2016,15014,12728,15788,14266,3713,10452,16524,21009,2430,
+13482,12319,19639,7522,10293,13231,19198,7557,16580,17447,
+10786,20593,20616,10681,5837,10155,3088,9519,10765,17448,
+2301,11404,21711,14961,13356,15597,20860,12222,7692,13486,
+1678,9887,5764,17002,7120,21314,4605,9334,8461,8462,
+19172,2201,7640,11595,17454,11427,2701,18108,14962,2795,
+2487,3463,9570,14243,18875,8029,3301,12826,3033,17369,
+14355,13219,19325,2160,9673,20280,17955,21209,20264,17510,
+10823,17619,12749,13828,7451,6032,21471,7826,1709,6073,
+4508,9434,7825,9138,11289,9690,16875,16844,16824,16853,
+16904,16817,16854,16891,16859,16884,16820,16873,16966,16952,
+16950,16948,16954,16983,16982,16979,17013,17034,17011,17018,
+17070,17063,17073,17110,17101,17096,17077,17074,17080,17117,
+17123,17121,17118,17149,17153,17135,17132,17158,17137,17188,
+17187,17199,17197,17184,17191,17186,17206,17232,17233,17269,
+17293,17266,17296,17288,17292,17274,17285,17272,17270,17320,
+17323,17343,17321,17334,17337,17328,17318,17354,17352,17349,
+17364,17359,17357,17379,17378,17389,17385,17376,17381,17417,
+17420,17438,17399,17487,17451,17425,17407,17404,17468,17472,
+13417,11808,10357,4082,17461,21194,10248,9537,10249,12092,
+18646,12326,11569,5540,19277,14790,16944,1981,13498,13584,
+1982,10757,7827,21219,21423,6608,11919,12132,21082,10733,
+4420,8555,11230,17060,8615,19923,13471,10069,17989,14811,
+15915,10270,17207,6374,16514,3546,2689,16519,3548,21401,
+5121,19572,18781,4826,4655,7774,21038,3400,18935,21074,
+7852,20805,17527,13653,20806,8492,2158,6687,13654,16145,
+10111,1267,18618,21778,1452,14317,8297,6140,18019,20681,
+18801,12013,1783,3598,4996,5798,20934,20950,13656,18947,
+16123,11503,5416,17985,20575,13438,17471,17481,17489,17482,
+17492,17491,17488,17507,17506,17508,17509,17547,17512,17522,
+17536,17514,17529,17516,17530,17558,17579,17569,17618,17603,
+17564,17565,17590,17575,17650,17631,17642,17635,17632,17643,
+17630,17627,17664,17667,17676,17683,17680,17679,17674,17696,
+17704,17699,17698,17697,17717,17721,17719,17722,17720,17735,
+17734,17746,17737,17741,17749,17750,17755,17757,17762,17780,
+17895,17790,17784,17788,17787,17831,17804,17828,17815,17826,
+17811,17845,17847,17899,17887,17870,17863,17865,17879,17871,
+17893,17890,17885,17886,17919,17927,17922,17962,17963,17959,
+19727,11058,1784,1792,2631,2627,8838,13762,7590,7479,
+11380,7789,4382,13866,21172,5713,19103,8550,17710,14105,
+9038,11753,14813,7252,9069,9562,8344,14392,5282,20685,
+10131,7169,18993,1899,21350,14884,13647,9559,17794,2168,
+9042,15571,19930,10075,2632,2271,2730,9834,12142,4589,
+5802,18331,4030,20981,12777,12710,5863,8753,12640,15694,
+14674,4932,2698,17595,3856,9049,4088,17795,17796,19931,
+5019,19623,16055,18333,6706,12115,3383,20048,15303,5422,
+6502,13814,19932,11535,8102,2129,1152,14046,11756,19251,
+7865,6505,8844,9741,9511,14542,17973,17977,17984,17983,
+18006,18007,18014,18010,18029,18036,18049,18054,18093,18077,
+18080,18075,18078,18076,18123,18116,18113,18114,18122,18117,
+18138,18141,18142,18144,18139,18137,18157,18154,18162,18165,
+18170,18166,18180,18176,18185,18188,18221,18212,18223,18215,
+18220,18261,18245,18258,18271,18250,18243,18248,18278,18266,
+18253,18252,18305,18313,18314,18310,18332,18371,18380,18401,
+18360,18367,18387,18368,18366,18382,18369,18377,18373,18442,
+18437,18446,18445,18457,18452,18459,18462,18453,18468,18455,
+18501,18494,18502,18499,18520,18524,18538,18536,18529,18570,
+10506,19038,3822,17611,17167,16525,1658,2035,7193,14109,
+1232,1508,4944,7438,21333,7439,3211,7088,3391,20105,
+4500,1857,17390,18107,1677,13699,10764,9208,1027,20261,
+5789,2047,15221,11882,2172,9779,3460,14786,15447,1533,
+9212,4947,20899,15340,14788,16219,14691,1122,17552,1870,
+2459,9186,10244,16974,17178,9224,20600,3361,8271,20168,
+14549,7456,19077,9231,18187,16822,4781,5011,4798,1103,
+6132,7017,7022,7460,5609,1594,18372,5714,8423,12377,
+10870,11119,11120,11218,14652,15002,2167,20686,8433,11125,
+15805,9733,18624,20982,8505,16960,18562,18540,18565,18550,
+18555,18544,18598,18603,18616,18617,18636,18642,18644,18648,
+18647,18662,18660,18657,18669,18682,18666,18667,18668,18687,
+18671,18683,18726,18744,18733,18745,18743,18736,18731,18732,
+18818,18770,18812,18804,18767,18800,18820,18774,18777,18785,
+18835,18864,18855,18857,18844,18843,18850,18845,18885,18903,
+18917,18909,18893,18881,18902,19048,18966,18991,18933,18891,
+18992,18984,19009,18884,18880,18946,18985,18923,18889,18948,
+18908,18894,19047,18960,18922,19093,19094,19086,19098,19095,
+19088,19091,19134,19155,19153,19150,19181,19178,19179,19183,
+14214,16368,17049,15756,19635,9245,4344,4065,13183,12095,
+7200,11312,19316,5459,13526,20464,7963,5618,3578,7529,
+10622,13527,7380,16418,8470,13529,10625,9250,14433,3639,
+5623,18362,15751,13378,7881,3124,20951,2363,7048,3430,
+3657,6484,13566,5287,14667,5760,7833,6860,13407,17685,
+11662,6980,10439,20326,1518,17692,14267,5390,21014,18026,
+2850,16932,18840,10470,8475,16942,18422,16946,18249,3899,
+4992,13379,13380,7705,7145,4524,18124,3804,6274,2102,
+15586,17812,7784,3418,13759,18125,19147,14221,12802,16124,
+7150,18126,19163,4262,4659,18203,19203,19221,19247,19227,
+19261,19219,19243,19289,19290,19291,19288,19305,19284,19318,
+19286,19340,19338,19351,19349,19357,19361,19360,19382,19362,
+19364,19368,19423,19421,19399,19401,19409,19397,19410,19403,
+19428,19438,19432,19439,19433,19452,19453,19456,19472,19455,
+19458,19477,19499,19495,19494,19518,19520,19539,19532,19517,
+19519,19545,19552,19557,19570,19612,19617,19610,19622,19562,
+19574,19608,19573,19600,19554,19588,19592,19559,19583,19658,
+19653,19656,19662,19655,19663,19657,19694,19720,19699,19705,
+19696,19745,19733,19712,19737,19749,19724,19708,19704,19756,
+18532,15052,14424,19154,17640,8425,17469,11624,2418,19475,
+20893,17747,4572,17668,2333,14345,18264,13980,21407,17855,
+18962,18963,15119,2565,6071,14393,6108,17894,20687,21273,
+20781,5448,21556,20399,5519,5012,7420,3846,10071,3658,
+18522,11590,12064,21147,5145,18977,8302,18622,20367,16149,
+18810,13508,20549,12487,1471,17752,13445,1083,3292,21689,
+15541,21232,3015,20584,19416,17858,18095,18994,6666,6112,
+14668,2126,17496,14534,6175,2144,5452,5761,13567,6776,
+7802,6485,5065,17355,16365,14396,2731,3971,11062,11320,
+4332,6703,18275,17748,5595,4422,19714,19735,19744,19717,
+19776,19695,19830,19834,19826,19854,19861,19869,19864,19873,
+19891,19858,19857,19866,19886,19884,19876,19912,19919,19929,
+19920,19921,19935,19937,19966,19964,19954,19950,19965,19943,
+19956,19961,20017,19999,20014,20001,20041,20035,20055,20075,
+20061,20059,20071,20054,20088,20101,20100,20113,20112,20110,
+20120,20121,20124,20125,20137,20144,20149,20152,20173,20184,
+20186,20191,20192,20195,20206,20198,20197,20203,20200,20224,
+20218,20212,20209,20207,20220,20234,20231,20228,20233,20277,
+20283,20292,20293,20289,20307,20332,20317,20319,20333,20335,
+1772,15798,18815,9421,21176,8906,8850,16693,7179,20983,
+13770,3136,9303,4270,8914,16896,15881,3432,1331,2188,
+19541,8764,13127,13181,14834,939,19683,17499,2529,7864,
+17300,16695,16806,5238,15054,1890,6782,8062,14899,20716,
+14900,4031,6451,2326,14873,7813,8736,13451,3106,17470,
+15212,16332,17215,4617,2573,15327,19014,11487,19164,3814,
+12335,21456,2238,2400,21400,7185,12650,15417,21387,16472,
+8207,13287,3947,20783,20252,21650,12887,21457,9849,7506,
+2843,17126,10604,14426,1657,6492,12372,19628,3860,17838,
+12380,14682,17947,14683,6861,6493,20339,20337,20348,20362,
+20370,20311,20356,20363,20358,20379,20376,20382,20384,20386,
+20389,20412,20392,20401,20395,20391,20427,20424,20436,20428,
+20426,20466,20448,20445,20447,20450,20455,20452,20483,20471,
+20475,20477,20468,20494,20492,20504,20500,20503,20506,20501,
+20505,20517,20511,20523,20524,20534,20535,20543,20550,20551,
+20538,20553,20537,20564,20566,20572,20583,20592,20602,20603,
+20613,20607,20609,20622,20642,20629,20645,20630,20661,20618,
+20619,20620,20672,20679,20670,20720,20705,20719,20699,20752,
+20733,20744,20729,20735,20726,20730,20771,20765,20772,20778,
+4345,21083,3711,17548,4939,12605,15866,7515,12780,19784,
+21521,21313,16998,6799,19124,943,17217,11555,2431,4783,
+21183,18484,18402,6643,17948,5296,11950,12652,11422,18708,
+16520,17689,15611,21114,14239,12516,9020,6669,6908,5264,
+19317,11063,17479,11139,17001,13038,2402,18046,15658,15152,
+1217,2613,12890,14688,7578,19902,17612,17449,15554,18582,
+18583,20824,19643,1640,3116,9520,11341,11342,14268,20595,
+11324,7446,20262,21692,9755,10294,1998,11981,5817,16967,
+21466,1013,1044,7915,20596,18837,6345,7603,10787,2353,
+5988,6469,2245,17839,20302,14103,20777,20779,20776,20774,
+20790,20794,20787,20791,20821,20795,20797,20811,20789,20786,
+20796,20842,20833,20843,20844,20830,20836,20831,20872,20885,
+20866,20894,20867,20870,20878,20903,20928,20940,20901,20933,
+20970,20911,20917,20907,20958,20932,20968,20914,20913,20944,
+20959,20912,20947,21025,21037,21032,21039,21041,21035,21056,
+21055,21075,21067,21068,21085,21088,21084,21090,21086,21104,
+21119,21122,21123,21133,21143,21134,21138,21154,21168,21166,
+21175,21159,21170,21169,21162,21203,21195,21201,21231,21224,
+21236,21233,21222,21269,21255,21243,21270,21251,21277,21272,
+16933,20329,4138,20785,11597,9213,4278,19356,8464,7003,
+21751,7695,1881,6817,21335,11347,20285,20345,14592,13110,
+15428,20286,12608,14488,17956,20222,15431,3468,15227,17175,
+7006,7730,9760,11892,18763,888,20415,6740,6819,19067,
+19068,14244,13692,11900,12960,4140,15338,6438,21117,6033,
+920,19273,7386,19805,7455,6826,4047,20599,17958,20165,
+9436,14434,16535,2250,9702,18841,1611,20601,18423,4355,
+2748,16537,2749,18639,2217,13693,19202,9229,2460,17556,
+11810,6528,20169,19082,3473,20422,18433,4056,16108,13741,
+17739,17751,1434,21092,14421,17816,21242,21249,21259,21253,
+21293,21298,21299,21301,21304,21317,21329,21328,21330,21345,
+21340,21349,21339,21362,21354,21356,21367,21368,21365,21385,
+21373,21376,21399,21402,21413,21410,21409,21414,21446,21430,
+21437,21438,21442,21427,21432,21480,21481,21489,21483,21501,
+21491,21478,21553,21476,21536,21554,21537,21560,21567,21559,
+21603,21582,21598,21574,21576,21610,21626,21638,21658,21660,
+21661,21663,21668,21669,21673,21687,21681,21682,21683,21704,
+21700,21714,21729,21723,21725,21737,21739,21754,21763,21764,
+21773,21779,21766,21767,21777,23849,23850,23851,23852,23853,
+12866,6246,17064,7055,6257,5909,6213,16924,16925,9888,
+5946,4048,10251,12768,9563,3570,1394,14823,17309,4758,
+21018,21024,18434,18435,2824,6691,16095,18964,18965,7337,
+1068,6313,4323,2777,7355,8746,5066,8310,4842,16897,
+1695,21184,7260,4692,16926,1858,16549,6554,3637,21600,
+4696,19059,971,12303,11506,12266,5437,11508,19538,11382,
+15005,6546,8747,6113,975,9506,11663,1425,19689,7261,
+16033,10826,16927,19049,8332,2769,15429,6527,8484,1299,
+20624,19863,4993,1942,5406,15591,18949,6006,16258,12432,
+6893,4529,15390,5645,20242,20952,2817,6927,16768,5073,
+11736,13984,12244,5322,2492,5276,11580,4342,5794,19576,
+12420,1404,16107,18527,18539,20788,3641,17661,19206,8968,
+19762,5197,15583,21221,7034,11534,11212,6933,12658,11087,
+1806,14078,5526,20268,14336,3250,18312,8430,14942,18704,
+18403,4538,12518,5745,8999,1571,20253,5586,19497,3501,
+18883,16585,8008,8816,5766,8560,9118,6945,14219,16230,
+8859,12385,8436,13064,6865,19019,8074,16322,13714,3874,
+20491,9367,13976,18886,11451,13739,19654,12329,18155,16209,
+16732,2260,2002,8640,21240,11843,8547,19434,18898,5413,
+4419,21274,14659,1472,21509,4421,5776,12379,1572,10720,
+3345,14502,8935,4634,15814,18811,2603,10873,6145,1346,
+10424,10014,6777,5067,12371,21510,7298,17900,20278,7673,
+5068,20174,7493,19246,18132,20717,14326,1696,1697,13408,
+14327,2886,20176,21108,9174,20151,3055,2401,14275,15757,
+12143,5343,17216,10735,7507,15213,5025,15461,3107,3108,
+20993,6981,20515,4066,7955,11260,2972,20078,1255,20119,
+9176,4795,2024,6998,14509,913,21334,5030,5460,14011,
+20263,9889,19054,1135,2443,16301,21011,21392,1643,19998,
+20308,3448,20159,18413,12589,14245,15896,16133,11672,5039,
+7035,4415,19521,8851,8599,21161,18910,15765,2149,7649,
+11867,11414,2717,18306,9599,13377,9551,19660,12452,19402,
+14988,4787,12968,13961,12015,21412,14732,10637,16631,1416,
+15680,5610,8774,8291,4710,18311,17528,7151,16346,21611,
+10274,15519,1688,11938,2655,16889,8018,7496,7621,8158,
+15919,17940,3386,15894,16104,14330,12852,21684,19976,3150,
+3615,16818,18128,6267,5855,2242,8986,1219,12574,6206,
+4899,4855,15103,14979,15952,18304,1819,5795,10869,17583,
+10535,12546,1751,19308,10643,9399,1725,6406,9916,17230,
+16303,19330,7964,5409,17225,20177,1540,4049,14772,18420,
+18421,18003,10272,5151,20179,19855,1473,21105,4791,19995,
+16865,15916,17039,2473,2482,17106,15507,21657,9606,14222,
+13314,13224,17240,21495,8426,13225,2601,3002,2450,3847,
+3604,17033,20400,8434,7068,2605,2783,5572,18045,15806,
+4217,5130,15267,3137,16961,20555,15137,19192,8235,7508,
+13630,2989,3187,10440,3491,13354,21522,15655,13456,2671,
+6649,13111,13082,7727,20223,15706,4410,20148,16687,8677,
+8427,2436,4549,19963,1099,12694,16183,18978,7490,10072,
+10961,8825,3041,12830,21275,8201,15023,11106,21057,11297,
+18241,7764,6273,14215,11967,8274,11620,5499,6066,3643,
+20539,13427,18775,8898,9416,5588,7775,6680,14374,5440,
+13542,20775,6851,17850,13120,5229,8911,16836,21640,21436,
+16437,19585,14420,2226,15198,2419,7480,18044,18684,4314,
+19728,17926,931,3687,21494,12378,11328,3466,15120,14658,
+11122,20585,7428,20284,13097,8439,18397,20403,2457,7759,
+7896,4977,16773,12844,8007,1155,3748,21768,1283,17700,
+5054,20925,11767,21642,2919,12298,16349,6615,16445,16965,
+5914,13307,8919,10791,16678,4540,1736,12249,1300,18670,
+15815,12038,8306,11659,18816,7170,4238,4239,21177,13568,
+21300,17356,2658,1383,20971,7280,1954,3294,8234,14753,
+16008,2839,8063,11780,17432,1925,3222,11449,14754,7677,
+13066,11051,7509,12727,16645,16473,7814,7080,11784,8208,
+11785,10594,10441,9467,16286,13573,21677,13164,12651,3140,
+21597,12238,20757,19636,4180,2973,19426,3712,20353,2442,
+16156,15504,4940,21678,11951,2132,16073,13018,20441,3724,
+15659,7089,10195,20156,1524,2692,10456,9890,15471,3358,
+15153,17003,8997,7204,20861,13020,20862,12050,21601,9754,
+20193,11733,16068,8242,17171,21052,3644,15349,7267,20915,
+21163,8867,17019,6532,20057,9608,19333,5230,16837,4889,
+12297,15404,18316,8375,18228,19160,20473,12514,14229,21651,
+10098,4761,2771,6571,10724,13465,14311,6077,5306,11033,
+17880,17541,15080,17610,8469,19177,12946,3475,2320,14919,
+1581,1352,13396,1354,4301,4435,14769,6984,19377,6154,
+16380,16673,5241,20698,8920,12330,18769,9587,12661,1156,
+5100,10259,3749,10324,2379,3647,16136,11644,11456,988,
+18194,3825,3951,8561,14177,14271,11601,5055,19138,2508,
+14573,5820,18050,9924,19922,20840,957,18953,12300,11739,
+1801,3148,8466,10022,15304,13083,13084,9852,4156,5634,
+3303,1537,1538,8334,13137,4160,2746,7010,16767,19983,
+11734,20864,9699,21021,2801,4107,16536,10252,10024,17179,
+16538,9230,13682,17623,11811,15339,13500,7098,3155,21696,
+17008,8990,8485,10025,3375,4660,15672,4218,5385,9291,
+13735,10641,883,6982,8236,8781,8782,18338,10948,8634,
+13458,10295,9366,4222,20863,18414,15674,3551,19279,19817,
+2366,20336,5752,8493,19959,17665,3337,17924,4525,13760,
+14185,8912,14742,16097,2420,3343,4315,11507,12695,10836,
+13917,8913,12923,21319,6208,6336,12197,16027,14069,3338,
+8822,3838,19108,9462,6312,5285,19881,10772,19369,9821,
+2608,17651,12325,19076,2039,7604,11520,4068,12850,6939,
+16246,17738,12761,17319,4861,18247,20009,4863,7132,9589,
+4294,8280,12287,20879,13940,17268,2282,3060,13189,16779,
+12965,12665,14172,1586,21246,8791,18851,11365,5102,12421,
+10209,1077,11459,8179,13667,13281,2591,4874,10040,11748,
+19204,10854,19285,13310,11243,14305,12967,18791,13694,1447,
+3011,8255,15902,6725,21165,15852,13089,4888,13727,17723,
+13546,6751,18086,11296,12799,7612,2679,7541,10652,19287,
+13478,8936,3659,10073,3346,991,20688,4530,8907,18506,
+12185,1322,5479,5480,12113,21276,13832,4324,1085,21120,
+20895,18556,8683,18979,13256,14669,12488,4386,5401,8230,
+7714,5684,10426,8572,13569,21106,20123,20972,14325,9848,
+19768,14297,19485,6567,13641,20587,16285,4972,13260,21109,
+11664,10082,20590,20459,9850,21518,6711,16333,2990,5869,
+8609,18869,12216,12985,5808,11730,12493,5630,1333,10595,
+12022,9825,13926,13847,7087,18485,17218,2876,3122,2944,
+5297,19490,6215,14757,5028,21523,4941,16550,1360,20442,
+19640,16551,8610,5492,20664,17108,12913,5324,7928,10719,
+15231,6238,21141,8601,1401,14575,16633,19503,4260,10901,
+19467,9620,15991,17148,4897,15172,19469,3621,17638,16267,
+9275,19225,2953,7985,12693,16864,15028,7899,11532,12634,
+1082,14741,2266,15812,19589,6539,1458,4910,16028,3424,
+3201,18222,21664,3482,7335,16276,19292,5475,5965,12828,
+4746,13765,17330,16359,2231,8568,12810,9006,16986,4322,
+1246,12002,15858,10278,12028,17933,7251,20648,14533,13904,
+11387,4361,1327,16621,6012,7066,9498,1212,7354,14910,
+9309,19302,19755,15135,11007,3980,16990,9773,3135,10015,
+19903,10457,7641,2351,21321,16529,6849,18033,20598,7728,
+20465,1892,9355,4697,4470,9984,5302,14101,8613,6560,
+18877,7093,21393,4392,19806,7533,6218,9405,12162,9700,
+9703,10358,10026,3321,21095,9818,16546,3016,21726,1600,
+9126,3025,18008,1182,1604,1607,1154,3034,1609,1610,
+11872,11874,20695,2978,18729,13774,4513,14557,13897,2162,
+5095,19546,18846,12617,20310,16338,16024,21396,3275,5997,
+3276,4254,21031,2380,11694,2643,2409,21252,15559,16140,
+13517,6726,3960,19533,11525,18793,7779,9923,18121,4168,
+8089,19470,13386,3678,8045,18860,13479,8811,17917,9899,
+6790,18134,8450,13932,21728,7079,11010,4493,12726,6265,
+17608,6214,16370,19036,16626,15085,1517,6014,15365,13879,
+18064,17254,5222,9523,6917,13488,6195,4506,11802,11079,
+5393,18929,8916,9713,3265,18926,16840,20182,12111,19451,
+9903,5049,5111,14700,10972,16036,2393,4955,1589,1022,
+7776,7651,20091,18940,10605,8520,15760,18650,867,11504,
+7110,5845,1116,8194,12545,9928,12921,5643,3841,20318,
+18204,13238,19601,960,17932,1771,8970,19926,14747,4364,
+2852,7346,14909,20431,11946,14044,10659,19239,20850,5974,
+20610,16790,9719,15289,6729,5507,9158,1344,3256,8428,
+1382,19476,21101,7935,19729,2984,15688,3289,19914,11945,
+3485,15185,18326,2604,15643,14578,20640,19479,20066,4325,
+5873,3293,16405,11551,18564,2762,18130,15319,3697,2606,
+19915,15129,10690,5651,20481,14676,1935,2663,15138,4176,
+3706,10285,2611,3230,13708,12888,17976,19777,18823,4338,
+9873,14684,10736,6552,20408,15607,4409,1559,1562,9524,
+19907,19493,10629,9573,15848,12757,14166,19560,13860,16260,
+4814,8642,1684,17628,14411,19856,3214,6876,1191,8281,
+1435,16210,8899,5703,14517,8818,20586,17542,10318,21750,
+3151,5132,6598,12337,17718,21461,6868,21706,11576,18882,
+15589,3326,14655,1895,2637,6931,8799,3502,9370,20309,
+850,18528,4815,4950,18900,3314,9586,4292,1409,1123,
+5818,13233,19180,20090,8543,17061,5581,10117,3920,11820,
+4183,11582,19435,14925,8901,6943,14417,6681,3264,9910,
+18784,17400,1442,2999,5673,6747,17758,18738,12025,8868,
+4210,7137,11214,11052,20359,11868,5321,11412,10702,2555,
+9320,5347,16709,20315,15274,20211,16839,21776,6946,4782,
+20238,11943,11187,9954,21323,20528,15565,6332,3197,14146,
+5053,6082,7036,6304,17702,16949,5718,11935,9289,18254,
+2499,3995,10489,4958,16708,9272,7269,5346,1818,17024,
+13518,17466,12627,13250,21096,21641,12465,9149,11651,19471,
+1926,17322,8225,19380,13058,18742,10905,13963,1316,14743,
+19672,20060,6311,8966,17325,17326,15059,15483,11301,16880,
+13894,2835,21505,21647,18689,16691,17331,20019,13059,19367,
+10874,2343,4840,9898,21306,6425,13062,10771,13063,17859,
+3585,1529,18097,1502,20291,16409,20782,10882,9965,3384,
+11013,18703,2046,8876,4755,11014,8939,9778,20154,2198,
+19444,6999,18407,2206,20157,6522,19358,3419,1787,3901,
+9268,9621,14832,2855,3837,3268,11550,9488,8969,7742,
+19393,9001,8117,15060,19107,2652,7743,10276,8839,16639,
+6762,13205,996,15121,4019,8730,11777,6072,2397,15262,
+5284,855,11638,6020,3714,880,897,14908,5881,15890,
+2566,12158,9460,2030,12411,12642,19238,1370,15082,3605,
+11126,12188,8388,9863,12568,2856,7720,11960,13209,10317,
+2082,3571,6013,7952,8453,18754,14004,12276,13875,1930,
+6913,11565,16377,7396,11538,10575,6346,10031,19526,19664,
+13251,19669,19897,16382,20910,12149,15515,2718,20239,5844,
+16941,20162,9694,19586,18317,21721,10837,3376,4004,20636,
+19871,4833,15711,12831,12507,2732,20129,2987,19540,19211,
+12582,21727,5888,16412,10443,9242,18234,15575,20439,15418,
+21388,17219,4021,15445,13412,2964,20079,4431,8698,15074,
+2757,3234,20080,19431,986,20372,7599,12405,2244,19800,
+9521,20194,18761,7601,15430,12509,11883,19069,18416,19070,
+11745,13887,2747,18424,10104,11081,11082,11746,17673,7732,
+14551,11084,18430,1587,14653,14692,9525,7875,5043,18856,
+9897,3508,20527,3884,12504,13388,1081,20632,20839,1067,
+10559,4961,11527,3807,14187,13116,16394,16658,10774,20514,
+4934,4464,7027,12759,12853,12662,13426,18156,17267,1028,
+2078,9189,1057,6413,8709,3921,7266,17785,3324,5427,
+10852,11237,18914,3953,7703,18081,20732,9321,9145,15025,
+18219,5548,17467,5824,8776,8417,13797,18606,16225,20122,
+16399,19599,3237,10299,21498,10908,14503,15029,7114,20513,
+9968,3588,1704,18831,3725,2636,4562,3128,18119,18466,
+6307,9146,16981,2288,6622,18559,20756,7684,13499,14165,
+13587,13368,964,5690,10683,11857,20039,17075,12106,4623,
+13787,8869,14707,15230,1450,8369,9615,19584,17237,19143,
+8806,2885,21551,4488,19590,16690,5966,5171,12696,10810,
+13781,3688,15000,17028,18967,2147,14525,16022,16866,11918,
+12871,13394,7481,12267,18653,19185,1092,4550,2423,17712,
+3993,19967,12874,4837,1922,11509,17641,4265,8435,4172,
+5418,19186,12925,1165,13989,13722,2336,11864,4662,20045,
+18865,13202,12268,5827,6253,19156,8500,3809,18980,21043,
+16987,5083,13782,6878,15380,8649,19877,10336,11639,16569,
+4202,21515,11660,16003,14670,11257,5484,8689,10076,1752,
+3020,5523,1837,12269,19757,15006,21762,1889,19483,3763,
+7299,20649,14607,14671,15818,8307,15157,18740,5859,10610,
+11656,14322,3131,11059,6361,2123,16451,16504,10911,11588,
+20478,8061,8447,9871,17605,18063,6525,2877,6880,15233,
+19161,20865,14554,15476,16094,17014,13753,19703,2641,18783,
+17361,1786,19587,6844,2107,15068,11330,17768,7911,14030,
+21331,11571,12328,16736,5743,12105,17759,17350,16170,929,
+19670,1455,5338,999,7906,2191,17602,10000,19257,17626,
+3504,3224,2251,16738,20904,11993,2677,16737,8579,2316,
+2906,15016,1582,11854,6414,2821,12176,3279,18517,21771,
+11645,4868,2330,18916,18778,15943,18213,2053,8562,18082,
+12926,14535,15302,17994,20529,1269,6115,1489,14477,2784,
+14583,1838,21279,2659,20096,12522,15918,12927,4925,20385,
+10859,12879,4926,9645,19969,12270,18447,1180,1794,7803,
+5420,14817,20753,11448,11683,11779,3698,7256,11473,15440,
+14409,18866,14939,8937,8551,1296,15921,17713,6259,7678,
+2633,4405,5315,1753,14587,11421,5877,19165,8506,21107,
+2708,17365,15922,11389,9448,6972,19769,17908,13724,21753,
+20984,14226,2664,16991,17714,13571,12271,15820,21181,6292,
+11308,8854,18571,17157,17209,17770,8507,2108,9351,7073,
+12334,13871,11101,18752,19120,5685,8722,20058,1309,15037,
+12864,8953,9061,18939,15681,13532,13153,17727,4611,2308,
+16323,2720,6333,3199,20064,9003,4320,9472,21377,13117,
+1466,15125,12951,19371,8020,13100,2688,2844,10002,11041,
+15741,6714,14842,18244,16385,6228,11267,8646,15315,10475,
+9063,8115,9297,19730,2267,17029,16568,6834,4317,13520,
+13617,6116,15731,13622,8618,21353,12035,12992,14874,12786,
+14975,2136,4727,19859,11454,11163,4164,11108,5498,1585,
+16600,6010,16383,9376,5101,14798,10208,10326,18441,14985,
+4227,10038,10853,10648,17980,12057,16138,6230,11269,7970,
+963,3917,19512,14087,8662,12931,14947,11640,3812,5979,
+13947,14678,8765,13411,17437,20591,17797,20187,15627,3261,
+5575,6279,19375,4009,10504,10925,9292,16298,17646,20030,
+1334,15144,19778,2189,15882,1850,5980,7282,6263,8347,
+4756,2170,16287,20995,14957,8348,6468,19685,15784,8938,
+21458,10568,17715,13230,14452,5939,10569,18654,2790,20305,
+8209,17303,4271,10814,12570,9512,12067,13948,2532,5239,
+9565,15596,1733,21286,20718,15979,10183,21732,8328,2315,
+19847,7369,5177,3817,15577,2298,10597,8737,10087,12277,
+10447,9518,13017,12144,8362,11261,6534,16432,9921,7238,
+20621,19092,6724,21164,7141,17873,6748,15561,18083,7586,
+10124,6392,18084,13899,15108,16713,9147,16392,21434,8342,
+2080,1190,16848,10940,6577,21228,12689,16857,15027,4026,
+21416,12342,14482,5143,4601,3099,14423,5644,10407,14846,
+17587,18224,11174,7664,15064,6625,17892,12169,7338,17990,
+16660,10909,18389,13207,8732,14351,10821,19301,12599,9642,
+13902,15301,6858,1477,17791,4969,15487,12077,11303,6632,
+19303,17430,9240,2032,6340,10660,6594,9798,21179,18750,
+10430,17967,5129,14822,14953,14196,14320,15925,2193,9175,
+21733,12219,977,12278,17307,18149,21369,9452,854,8783,
+15330,9054,4034,16521,2928,21524,20759,1348,11791,21636,
+2965,15422,3910,12729,12936,21389,6991,19785,7914,5632,
+10845,2273,15758,16918,9802,15578,5559,3262,14826,20663,
+10448,11040,10449,6452,1659,5046,9164,8749,4551,16762,
+11537,16300,6399,3563,17164,17165,6866,9851,4451,10981,
+8575,18450,3609,9804,5835,17255,4081,16011,16414,16288,
+5031,13848,7090,4348,8510,20665,15660,20344,6435,18486,
+4105,17109,19641,8766,14479,6646,16479,5032,20532,2112,
+13167,14545,6217,8983,11953,13078,15179,9567,3440,20406,
+9743,13878,12585,1522,6030,21464,5990,17616,19322,19978,
+4719,6061,1107,11143,5740,3477,11110,19528,2411,11846,
+12880,12883,16804,9865,12889,6549,7441,7440,2977,18191,
+16739,8086,20235,18782,4397,7235,8035,3328,6309,12082,
+1886,9557,13387,17410,15683,13640,8965,16347,6583,10410,
+2870,6627,13401,17094,1003,5453,15320,10137,17159,9971,
+8327,17609,11205,15222,9110,7121,6759,16053,20957,8651,
+20883,6948,4250,2176,16988,8319,2257,8033,11909,11090,
+4909,1464,19811,2377,14901,4577,18246,16735,19701,1410,
+13079,6297,15951,21624,6555,18714,11263,7523,4089,7516,
+14960,8984,6381,17949,20606,7821,20666,1560,21050,21527,
+17773,18655,10949,12029,865,5072,12938,10928,2113,3302,
+1218,17111,9756,15284,8587,18584,18718,11898,16614,13825,
+15510,15285,13021,5300,14916,2929,1863,12051,3273,1397,
+14048,5178,21528,16699,19260,6677,15790,10162,8576,15250,
+14138,15075,16302,5225,20722,20723,9293,19055,19905,15523,
+11796,16968,7262,5266,10694,8350,15056,21691,15286,15287,
+4759,16553,11489,10388,15288,11982,21680,16047,17777,5656,
+18002,9805,14721,10766,11405,10623,7921,21540,5700,11850,
+19563,14980,3278,21118,14174,13145,18195,13703,14730,9784,
+7608,12424,2141,9554,12448,16195,17193,15255,3676,16433,
+4281,8047,1655,7786,2263,1454,2174,11911,1024,19925,
+15854,16794,5449,11329,12345,899,12434,2567,9500,18229,
+13027,12412,2295,9389,20474,16902,14233,1512,11757,10674,
+14853,5047,5042,4859,11903,21497,7761,8395,1222,20180,
+14987,4988,21639,18924,11904,15343,17402,6457,12366,9483,
+12697,8728,21366,1966,20962,16799,1036,10139,14227,1627,
+3075,20460,7215,17339,14920,19544,21130,5243,16245,8921,
+1534,16530,10165,3611,14036,21625,18838,10462,8767,13022,
+3183,12656,2303,15472,10788,19385,2246,4760,8071,1644,
+14827,10315,17801,3090,10234,20160,7530,2038,9529,17131,
+16935,8635,14869,1388,20487,12897,2488,10467,6470,7094,
+12591,6820,13023,12510,9987,14102,17802,17315,2489,9025,
+14965,10167,11598,6651,12422,15226,4507,13112,13538,18489,
+15473,17392,8471,7642,21744,9892,13169,9336,4139,17656,
+20136,7007,7452,21053,3593,18153,19347,4118,8472,11899,
+15705,12610,15822,15823,20499,3893,14246,8558,7453,4644,
+15228,10390,8352,6823,19807,9762,20008,12248,14725,5140,
+17567,4872,21135,4873,2823,3327,8834,6001,7587,5351,
+17408,15631,10062,12774,4584,14283,5797,4215,14712,10178,
+13593,16274,21493,8729,17329,15641,11201,6766,14935,1597,
+5417,21379,11252,7937,20690,13903,5214,9496,18989,7353,
+1692,12388,10778,9390,11322,14057,17545,9872,20294,7553,
+12958,13076,6551,21699,18526,6977,2858,20111,19363,3877,
+6937,16431,4653,11242,8408,8672,10212,3753,3334,12530,
+11244,7239,4402,5400,17813,18160,6187,18549,10655,16980,
+6690,9767,12703,19234,12702,6395,9040,18325,3100,16279,
+21468,13085,12901,21472,9404,1541,15824,6562,17553,4207,
+5871,2491,8337,4698,3304,19073,921,21609,18136,3819,
+21292,6196,21394,7016,11691,6135,6924,13263,1710,19275,
+9027,11838,17842,7534,7535,12961,2134,21023,11231,9541,
+9407,7018,21695,8949,14276,12230,9139,4052,14918,2997,
+10529,1652,1281,10391,17226,8888,10253,4356,10359,7536,
+9232,1872,7394,18640,2218,17345,7537,16947,5664,2023,
+11812,9438,3156,13502,12070,10633,21697,10553,20196,11814,
+8486,15529,21220,9233,13985,18463,17706,1265,17711,10811,
+18146,20953,17150,19675,12711,2272,2396,8198,10879,19615,
+19927,17097,11610,904,15493,7913,6636,19248,3186,3081,
+17969,20484,12584,1997,13484,10450,1528,20161,16609,16463,
+20070,15549,16778,1613,12764,2098,10698,9593,12289,11196,
+18594,13941,7398,2802,2497,3062,17397,4543,12003,21248,
+11530,20922,20608,10211,8148,12468,10328,17078,17401,19462,
+20886,16180,20799,10043,5430,3652,9601,16142,2464,8658,
+9346,18143,13696,20930,20627,5678,12625,15873,9082,8151,
+6479,6185,6755,7781,10533,8368,927,17852,4526,5549,
+4900,8420,21550,15259,10057,2806,4679,4027,12974,20547,
+20973,19237,6634,21516,1851,15522,13815,1386,10153,6556,
+9136,2215,2283,2284,8140,1025,3852,8457,9901,11080,
+10975,10700,14844,14209,6889,10976,18265,1460,5967,1461,
+14188,8557,8650,1367,6254,13953,14039,17204,7492,7344,
+11278,17066,14877,4006,20342,11616,20402,12186,17115,10077,
+1599,1490,13954,6119,5615,5291,5260,4445,2840,6275,
+5721,11282,14113,9073,9304,10477,15862,14156,8237,19970,
+19971,2239,13523,10019,2274,14137,9074,18235,16578,18280,
+4346,6841,19786,16579,6280,1231,6281,13525,18611,16581,
+1168,944,16415,19129,9095,13632,10614,2923,9817,5862,
+7484,3690,8197,3119,14448,11553,20321,9795,9239,7065,
+12444,8260,13347,4096,2925,2451,10476,2125,8259,17993,
+10914,19300,20651,4614,15322,15247,17594,5196,3178,5216,
+14912,1693,13808,21178,17593,7912,13029,12645,2768,15496,
+21182,6370,5131,19973,13279,16159,8455,13103,13214,10381,
+21740,16907,8238,19898,9394,18282,10005,1879,2130,19482,
+1001,11363,3129,14254,15742,20043,9788,12402,3379,7059,
+1714,19028,13751,4298,5468,8675,10330,20889,18936,20677,
+6330,9607,18546,14648,20936,13549,10402,20580,11726,16329,
+9210,4022,13576,12241,15738,11797,15335,8577,6129,13634,
+2904,5619,4012,12782,8959,15512,5621,12401,8621,17058,
+6821,2247,12283,3499,6561,15337,16583,16584,5952,8563,
+4018,6768,15321,6548,9368,17659,18890,20900,19087,18454,
+3986,4291,14456,12134,5157,20036,20871,12286,2461,4295,
+13428,3645,10110,16135,1737,4228,14729,4229,4374,5747,
+19548,8517,13121,17707,2949,4997,17081,14208,14469,12564,
+20703,17276,3514,12136,18950,4127,10581,19100,8189,2415,
+10403,14471,17239,19105,21227,18473,13777,17091,2696,18378,
+19106,19591,3602,16348,11774,4128,2986,21504,3121,10442,
+9976,16496,7315,12993,7273,7113,7056,8595,3581,5084,
+7431,20175,11970,10045,1921,1385,20306,12353,12556,5038,
+9111,5136,6037,15401,5210,20272,17633,20010,5770,6084,
+20140,10855,19707,2307,11695,12679,14495,18678,2339,18370,
+6688,1888,5927,5757,17935,8974,903,11306,16089,18065,
+18630,16938,11575,1341,14641,8928,18792,20935,21488,5060,
+7933,20710,9170,13393,6962,15454,5020,2163,7149,16953,
+3624,19618,5457,7950,13521,7466,7597,12446,10832,5503,
+16749,5550,6959,8305,7340,12362,8661,13151,15258,1110,
+959,7741,5064,18327,6697,20046,16797,15489,7171,3523,
+995,17040,19188,13991,13704,9966,16060,3586,12314,15187,
+19770,17250,4683,11687,4388,6992,3528,19195,20999,10262,
+16936,9658,9665,6141,20812,18968,13203,12875,6543,5454,
+8379,6341,20103,19629,2737,15181,5989,6909,14852,5655,
+2797,20106,19384,7002,16929,10197,9526,11556,18027,20108,
+7099,7100,11492,4810,14081,11466,4663,12076,20020,2660,
+18448,953,11006,3764,3486,6337,3813,11478,2429,20343,
+10083,12653,21110,6266,20409,19125,21290,16101,10088,3973,
+19252,16810,10094,10095,6268,19130,5288,1878,10868,11430,
+3202,7485,14018,14748,2314,10473,12604,13494,12415,3506,
+17140,2860,3925,18199,19099,8727,20022,12557,2649,7669,
+4028,3851,19514,19862,5854,19945,16652,13785,6606,8013,
+13913,15374,5373,21397,11498,18542,12948,10213,3959,8549,
+10329,7290,14439,21140,21775,5566,20676,13467,20804,8038,
+5681,3963,18217,8870,13987,5885,12367,20706,11095,16096,
+10611,3247,12101,16275,11759,7988,18225,4603,19607,21584,
+3904,7487,3120,11561,11177,16217,4331,14816,2525,19352,
+5290,10501,1715,15606,20991,20371,5534,11020,14059,14201,
+10737,10738,20051,10196,11049,1707,16812,16531,9099,16969,
+19060,3449,15620,19808,10235,3360,7095,12079,18491,16420,
+16421,17059,7222,11050,11029,9408,9706,6925,890,4645,
+3363,10254,10105,923,4765,9708,1259,6160,6161,6163,
+1774,13244,15712,20650,2476,13296,8066,8069,15714,4588,
+11180,1271,15759,6824,18721,3885,2124,7345,13766,3625,
+4077,16798,13767,13208,11865,19189,13981,11512,11390,21690,
+1181,19004,18625,15574,1133,7754,6260,12114,1754,19123,
+5293,15576,7081,940,6171,5402,12832,15842,19354,15180,
+15785,17998,8788,1379,15334,20498,9753,10018,19566,16856,
+18746,14151,17644,16909,1616,13986,8308,15069,1634,1635,
+14723,5450,5483,6380,4612,6983,9203,19569,12152,10834,
+20393,7981,11680,10134,18868,18458,16430,4165,13050,14569,
+6329,21258,17982,15353,18680,18470,16792,5930,10984,2334,
+18383,6365,19751,16364,4097,1227,17936,1552,16077,10120,
+10781,14265,20072,19010,19782,4495,15215,17256,8474,3169,
+1612,3536,17897,16911,9592,6415,8077,6422,4586,14611,
+14982,17142,20881,13436,6418,4886,21774,11056,20800,3010,
+20631,15769,12704,2179,17037,21454,16997,13679,15588,15434,
+1525,9096,9140,17615,1196,4365,13357,13358,6130,13136,
+11480,7371,3610,11966,15555,15336,17551,12052,5303,1535,
+9100,15474,10297,5791,13113,18009,7011,7390,7563,2258,
+3305,6440,17263,12905,4053,16220,7395,9234,16390,13768,
+4933,10965,13602,5294,16474,13133,5940,2327,9097,13856,
+20083,14356,16482,5301,1136,15556,5426,20084,5205,1536,
+16485,6825,4050,16221,4054,4890,8141,17160,17600,17168,
+7004,20102,9381,12220,6650,19258,20086,12226,949,19131,
+17372,6441,18676,3888,13285,8967,17384,14890,5907,17822,
+18817,17825,5557,15053,8995,12712,4126,7271,6753,11920,
+13757,18519,21565,13612,12877,11279,15595,12819,4132,10884,
+10988,5185,11762,19698,3280,18018,11199,6940,5139,3478,
+17809,2368,4167,18197,21431,1547,4734,4450,894,9617,
+10215,20349,15907,3654,9112,16143,4896,17709,10809,17087,
+13057,20387,3966,11586,5312,16662,12811,4129,1325,3905,
+2438,21121,7807,3703,17995,1574,20589,5806,14045,13298,
+13481,4154,3590,7560,1933,11024,1871,8592,20896,4946,
+4976,17807,11167,8792,4158,11197,3369,14491,19829,18799,
+15174,21569,2561,11419,9171,7417,3691,15261,18169,11706,
+6009,19758,16259,1148,4174,3631,3385,12066,12538,10113,
+2386,8065,9449,6123,13070,4339,4272,16475,7815,9091,
+14427,18828,18829,8697,4116,1603,12457,9450,15808,7283,
+15957,6800,8980,7284,10606,15883,2483,19344,19996,6379,
+5985,8028,16062,16063,12436,9177,16064,21529,21530,2930,
+3912,9178,15424,5986,12891,8699,3212,8103,13184,18833,
+14006,15663,4275,4351,18283,16608,8611,19395,21315,18284,
+17257,17672,18876,19934,14049,3726,3727,7579,8960,9456,
+9337,12407,16227,10740,3149,18588,6062,13114,5562,18135,
+18352,6827,2259,13888,11031,1711,15177,12348,13946,15083,
+8978,10880,8694,11310,12403,2481,8619,9978,5538,15835,
+1439,13591,15719,4523,20678,14324,16281,16052,4887,5168,
+5505,9636,18330,12311,9241,9517,6997,20300,6095,5653,
+8353,7872,5041,18847,12499,20520,9896,16021,2884,14176,
+10974,2146,11916,1913,15375,8289,1162,12914,4545,8648,
+3989,6877,1091,19716,20738,5508,8678,12520,1887,1824,
+19960,11463,15437,3754,14904,14650,17986,15298,1453,11652,
+12262,4194,8660,9349,4403,19507,2516,7275,11587,18651,
+2470,3808,19104,8564,21173,15877,3915,6459,13556,5876,
+17264,12442,10360,10008,11813,13586,15879,8094,12541,19337,
+19394,9455,4735,3916,5571,4927,17069,20437,1626,13993,
+1086,15360,9939,5576,17999,14300,8330,1637,14963,16483,
+18488,18586,15077,8578,14061,4471,10166,16971,10198,12396,
+12397,10169,1647,1648,1649,9894,1650,14104,4766,17778,
+18464,20425,14940,18572,10142,4579,4473,4599,14565,1965,
+6951,3900,14997,16128,20397,16098,13769,19746,8382,2654,
+19190,4531,4532,15237,19187,21280,18819,21782,1491,7834,
+15550,1248,3026,15828,15007,1249,14672,4241,5895,13771,
+15755,7679,7281,1755,18573,15923,14128,15803,20746,14080,
+2706,15463,958,13867,9325,9162,15594,8762,20304,9560,
+5234,4266,3258,10564,10179,8556,7421,9285,13227,8202,
+853,13008,11947,1347,3559,8733,9043,5556,6864,12140,
+8360,15411,21512,13161,8574,14948,4335,2109,15071,6547,
+864,10312,13015,4636,10923,11397,5292,8349,11488,10147,
+19015,7258,1698,1633,15470,10784,10619,19381,21679,17997,
+3607,2199,8460,12588,10383,4135,9209,12607,3152,13019,
+3591,6912,21467,19056,2133,1646,21046,14418,3241,20974,
+1415,21546,11374,14765,10495,6956,4835,9284,8687,13733,
+3027,17366,18510,8385,4406,9387,16898,1799,11629,4341,
+1891,8535,4010,15145,19630,16905,18580,6847,5870,14685,
+7517,21390,1756,17308,1928,18709,3442,4594,20485,16522,
+5633,4347,11931,20081,6382,6647,6807,7372,6298,914,
+15509,4665,16526,5535,2114,15055,15511,1864,5203,17055,
+9021,10163,15076,15581,18719,16554,11344,15513,10752,1530,
+19803,17776,7916,14037,9026,21336,14247,2672,3450,19071,
+7008,13700,2490,16534,17373,20416,4666,5899,11030,18425,
+11351,2219,17374,10634,20170,11573,3896,16112,4230,6090,
+9386,16838,3999,8523,5861,5520,20691,7184,14094,11721,
+5035,13681,5704,7659,6048,16886,12515,3831,6423,19398,
+8112,19824,1241,20704,5472,3927,10332,13472,2559,14931,
+4383,20954,5567,17765,10534,1833,9491,5521,19748,17205,
+15644,16755,11192,937,1291,2960,6369,4336,3023,10924,
+16807,18627,7365,19254,20615,10194,9882,7638,8164,19794,
+6437,10459,5662,11619,3879,7734,9595,14217,9602,19463,
+5105,8676,3401,20365,12120,21260,17961,7243,18179,18803,
+20960,9324,16796,3239,17202,14129,21206,4635,5554,16460,
+19681,19555,3380,9123,19000,6290,2159,10311,7302,14070,
+18693,1839,4682,1847,11684,1503,1854,16010,5911,4595,
+7373,945,918,17170,19997,4699,12428,17653,10687,19747,
+4774,5973,3699,16153,16129,2607,18096,21281,20822,12159,
+17670,13783,13992,20049,16573,20851,3405,10478,19486,1848,
+1251,8440,16155,19005,13448,12567,13452,8080,12523,20530,
+19846,12189,21151,8316,21287,11906,8210,12274,20181,7313,
+10084,20692,15346,5026,18511,14608,1509,16157,16158,15009,
+10148,10709,12375,15579,21000,13820,15610,3972,18060,13536,
+14401,8081,4407,5896,1855,21185,19126,10663,21111,3443,
+5897,10156,8240,15046,13185,10815,2666,11394,1149,7076,
+6640,1632,10642,19342,20390,10225,19194,2712,1153,9179,
+19051,3771,12339,3728,13497,18959,15040,16830,13309,21398,
+1570,18602,15797,4007,8688,19621,18055,8314,19684,18730,
+2131,11500,13756,7880,10956,12063,3453,7248,5252,8752,
+9722,2524,9769,7419,1656,2809,15693,1486,8203,4190,
+3269,1330,1250,10503,1576,9201,2634,20605,13048,13883,
+12069,18173,17810,8498,3216,7877,9415,21547,2362,14999,
+6863,9359,15520,11990,10288,7576,11895,11410,3844,3882,
+3374,10065,11824,5826,9015,1010,15408,5903,12684,6005,
+9294,5987,16012,17950,16081,8538,4284,2549,17693,15012,
+10458,21370,21116,14357,12376,9057,15582,9165,21602,8739,
+12738,12739,18408,4596,14062,18409,5304,18612,16815,12383,
+3091,12384,12942,4597,6652,12940,6869,19648,15666,13537,
+17113,21604,8985,13851,14964,5578,16163,5735,15078,12900,
+2541,21015,10168,12228,15614,16972,2044,4045,18417,19908,
+21655,14063,14248,12751,21019,14856,10468,16973,10626,20488,
+11407,1046,1973,1651,3092,13461,1542,21020,19810,17841,
+6471,1802,15154,17462,9989,20467,4157,10172,16165,2087,
+3773,7643,15825,18426,10635,20418,7794,6109,19336,8684,
+5972,4340,21311,11792,10739,14047,6060,13886,12441,6320,
+12916,13374,7107,2156,6686,5310,10996,4898,12296,13942,
+17238,6017,7856,5377,3991,19182,2558,5905,5476,6104,
+9629,19474,13657,20366,13344,10068,2469,19536,13320,7277,
+11589,20961,14936,13444,15859,9087,12705,7619,18477,10839,
+14450,20562,14296,16721,9499,2782,4923,13007,13259,12722,
+16895,19767,4591,5867,5834,19003,12313,15783,13570,16236,
+9290,11039,2942,13813,11562,4936,8979,8696,5024,15073,
+19627,19488,10289,13410,1557,10843,13217,1011,10763,10822,
+8003,19078,18722,16131,12429,21158,18431,10255,10485,15619,
+17346,7226,14862,8249,16976,6529,9544,1653,13779,19096,
+1617,17678,13176,21577,15116,8972,14854,16446,16454,16455,
+19609,5146,18981,980,1272,1332,3005,15673,13071,8858,
+16074,5357,12373,19644,15191,1867,17455,12096,1868,3235,
+11348,9893,10298,17459,20178,15675,1723,8889,10361,5192,
+13128,8652,13118,9338,14073,9041,3627,4573,17771,13659,
+3435,9050,1716,4429,12275,4455,15697,1274,1510,10844,
+4937,4389,13821,13454,5389,9092,12221,21297,14301,15271,
+15700,9666,1718,15703,12224,15035,10680,19901,16916,2574,
+15503,12087,14687,6645,2037,12394,15506,16923,17391,21049,
+20486,14840,10846,12223,6813,12049,14242,6918,11042,2205,
+9759,11229,9536,4083,13501,4805,19244,13301,17129,14647,
+21197,19577,7044,4059,6950,7405,20544,21549,6419,13313,
+12521,3288,14472,20240,5434,9625,14998,15778,7245,1548,
+2562,8808,1470,17241,18269,13559,20749,8502,14666,5183,
+12008,14294,17474,13295,20248,13159,21283,13970,12930,16185,
+1498,3382,8780,19843,17431,20658,9014,6637,6293,5423,
+4618,9657,1514,2612,15150,11227,3982,10451,4104,5763,
+20760,21605,14896,7447,4223,6384,9133,12750,9761,20696,
+12229,10711,14023,10754,10755,14112,17843,9947,12902,12903,
+11570,9101,11839,1724,13683,4000,4008,11617,6282,17056,
+4014,5947,4015,4016,8125,19818,19819,18404,4974,17655,
+5734,21606,10199,5737,14269,10962,12713,12714,5050,17829,
+19793,16065,12655,9838,5117,12398,1539,12752,17840,2759,
+18356,20419,19594,3510,13723,7804,1070,6261,16130,3632,
+7116,19631,4274,13162,14135,5994,16100,11398,7866,14428,
+1167,19896,12315,10379,16574,6375,10338,20097,4559,4687,
+11513,19489,12382,11337,6127,17107,3772,20134,3576,1876,
+9183,21155,19571,19578,2683,17032,11770,11922,2865,14181,
+18854,1420,21040,1164,4571,5307,10334,21205,20241,16879,
+14295,16462,11038,14704,2036,2691,11026,13175,11750,7247,
+13405,14132,1532,3601,13042,15263,7812,15467,16915,17146,
+11092,1063,9627,15802,16876,21502,1992,9964,21632,14028,
+6294,20133,3024,17860,13844,13420,7600,5323,7173,18934,
+10064,16877,21284,4615,7434,12364,6125,19046,11107,20846,
+12718,12778,18581,3553,4834,13459,8114,8200,9937,21511,
+20147,11557,20604,7544,2628,3883,5106,21144,18802,5482,
+13455,5912,12279,10089,16160,1102,13413,12495,4942,1520,
+7201,16523,8211,3791,1856,19491,5810,12317,11718,17690,
+15362,1276,5029,20354,8321,5490,14590,3936,3352,15309,
+7822,14759,6316,17370,4390,946,16416,20558,21186,19216,
+9941,10664,15935,18834,19050,1773,16480,7636,8828,5730,
+17169,5298,6734,9354,4945,8665,17774,4206,8511,15664,
+11179,14302,20355,15272,13186,19645,11630,20597,5811,5358,
+15096,16725,13415,14202,12572,6602,15789,9569,14139,14140,
+8666,11025,2538,9527,21659,16930,19427,14403,21531,12742,
+13262,17371,11631,2966,7216,3795,3133,16151,17152,11317,
+20897,18395,14537,2531,16009,9447,9053,12133,6378,15657,
+17861,5889,15508,9335,1893,7729,16934,8335,9571,18073,
+14598,3244,4159,13304,18021,3145,1679,1264,15297,7412,
+4832,13000,20847,4836,14189,9637,16150,7253,1874,15356,
+8994,13061,1487,17247,17151,6967,7620,9823,7180,2975,
+6503,2610,20994,3743,1849,20855,7510,3861,2857,21066,
+8266,4205,3233,12374,13846,11793,12047,12654,2799,8465,
+12609,4503,3147,21210,10023,2214,9946,21694,17625,20906,
+3785,11388,17767,11402,12320,6354,8424,14257,5478,21508,
+13168,5561,21129,3938,9166,4598,11667,19061,9058,10463,
+8165,2276,7998,10598,10099,21653,9530,11043,21607,21016,
+11722,6400,19649,3662,14546,14405,6603,15667,6299,17695,
+21193,9137,21608,7205,1564,1565,6604,13581,20281,16375,
+16376,19650,2946,13852,3865,6653,9807,18344,13360,13361,
+7448,1399,4353,18490,5036,14007,7383,17072,16178,6385,
+14693,13973,17957,16555,7387,6063,16700,12091,14064,10170,
+10696,14594,14547,5622,21534,15616,15312,18589,5305,19396,
+12945,12753,16556,13974,14410,9763,1017,9385,6716,11290,
+7223,15792,13462,7391,14406,10756,5384,15136,20992,21555,
+13289,8057,19593,9638,16570,15863,7181,12161,4592,14157,
+19173,889,17316,10717,2448,8262,1228,15781,21517,19166,
+19686,2991,16670,11164,19878,16164,21364,15244,8371,8204,
+10662,8331,2743,13305,10537,16808,20153,11424,1045,10161,
+1338,17652,19480,4558,1100,12489,11717,10337,15093,5017,
+6314,15357,5722,7810,16468,4387,7182,7624,17367,18098,
+5356,9513,9742,7363,14589,15787,5809,14136,6597,7186,
+13261,10090,21652,4593,9055,2275,5560,11666,11719,3792,
+14543,21526,4718,3862,4349,13355,5033,6648,1561,14060,
+16975,13418,1664,7224,7220,21211,7564,13363,21316,19390,
+20489,8636,18035,1667,19813,13463,17393,1803,7700,18109,
+15155,6654,21746,14251,14252,4474,5792,9991,18110,11195,
+17005,20303,17344,4720,5624,6317,8883,20282,14065,20420,
+5135,5793,14489,9574,2304,9410,14791,922,13889,7225,
+17916,6442,14793,9707,9949,10668,11232,20668,17375,4358,
+10362,5666,9545,17181,3509,7111,16099,1069,6117,19484,
+20351,1840,12310,8663,15924,20279,6315,8873,20352,8508,
+19425,12730,14402,1396,2302,15661,16552,16372,13577,7558,
+12088,7377,16532,16970,6439,5134,1015,12740,15310,5620,
+18585,9384,1663,18034,10753,11288,19386,5790,14249,21745,
+9572,3296,18449,3298,13102,10751,7376,8214,13849,5425,
+1337,7862,15955,8827,5493,3661,6296,5295,8700,1526,
+10296,12841,8887,1721,4051,10966,1087,18336,9837,17442,
+16335,2578,17363,18398,15829,15557,19389,1618,9044,10842,
+13661,15786,7194,21525,17772,13578,8124,1722,6563,9948,
+11335,6712,11068,7115,8509,21235,11070,12745,1016,14361,
+9990,3356,2849,19516,17112,18762,13460,4046,9532,13280,
+1989,978,4693,19542,16726,18357,16943,13414,5913,20330,
+20417,5635,11751,18867,4928,9646,8121,1900,18390,4891,
+3787,6968,4792,13905,5114,14538,4793,11309,1252,19844,
+20823,6433,13212,4845,4688,16575,7364,14541,19779,4811,
+18537,8451,8452,12336,6519,20721,1254,18399,18148,20784,
+4552,4794,16576,11978,3353,5261,13874,10091,11223,4938,
+16161,11262,9659,1578,21001,5262,19848,3031,13483,17443,
+2575,3444,8212,18610,5491,21048,19787,18451,19788,18150,
+15821,19789,15736,19253,4117,16698,4391,5577,915,20825,
+18406,6193,17450,7285,9942,21187,18487,15662,6269,10453,
+13880,11425,5265,13725,7637,17775,22349,22350,22351,22352,
+22353,22354,22355,22356,22357,22358,22359,22360,22361,22362,
+22363,22364,22365,22366,22367,22368,22369,22370,22371,22372,
+22373,22374,22375,22376,22377,22378,22379,22380,22381,22382,
+22383,22384,22385,22386,22387,22388,22389,22390,22391,22392,
+22393,22394,22395,22396,22397,22398,22399,22400,22401,22402,
+22403,22404,22405,22406,22407,22408,22409,22410,22411,22412,
+22413,22414,22415,22416,22417,22418,22419,22420,22421,22422,
+22423,22424,22425,22426,22427,22428,22429,22430,22431,22432,
+22433,22434,22435,22436,22437,22438,22439,22440,22441,22442,
+21115,2576,10665,6194,11720,4285,10538,7286,7206,16013,
+6521,16177,1902,16724,8351,19801,1865,8539,8540,1398,
+16931,8541,8241,15980,7997,15665,4276,4277,8915,5539,
+16766,14404,9180,7693,12068,10464,12323,14763,4948,948,
+21469,12227,13416,12898,1293,3796,10465,13635,7381,8243,
+16029,18152,19850,12743,9531,18720,21371,8784,4246,9059,
+14481,12744,7999,19062,19063,8000,21532,9167,3939,12657,
+2967,5345,8215,8467,19064,21743,7005,14828,14829,2673,
+11194,13853,950,13362,15668,6386,15669,4354,7758,10847,
+4949,2947,16014,18345,6133,19909,22443,22444,22445,22446,
+22447,22448,22449,22450,22451,22452,22453,22454,22455,22456,
+22457,22458,22459,22460,22461,22462,22463,22464,22465,22466,
+22467,22468,22469,22470,22471,22472,22473,22474,22475,22476,
+22477,22478,22479,22480,22481,22482,22483,22484,22485,22486,
+22487,22488,22489,22490,22491,22492,22493,22494,22495,22496,
+22497,22498,22499,22500,22501,22502,22503,22504,22505,22506,
+22507,22508,22509,22510,22511,22512,22513,22514,22515,22516,
+22517,22518,22519,22520,22521,22522,22523,22524,22525,22526,
+22527,22528,22529,22530,22531,22532,22533,22534,22535,22536,
+12365,9060,10932,6387,19262,2887,16816,8246,3940,2018,
+4574,6388,19274,19910,17177,16615,14548,6158,2800,15514,
+17114,13975,10171,7096,5494,7388,15251,5992,3035,3036,
+19074,18638,18418,7012,9695,15739,8814,15628,15629,19075,
+16015,10695,17460,5206,15740,2435,7097,16049,20617,1018,
+18614,18764,11983,2674,21022,10200,19391,10484,1543,14859,
+21474,19651,16727,8480,19176,15433,14966,7644,19079,6472,
+1544,19278,15156,6655,4509,7645,9895,18427,5208,8169,
+17227,17228,16016,10723,21747,19814,19280,10472,16050,17229,
+18028,19081,12356,14792,10631,16945,22537,22538,22539,22540,
+22541,22542,22543,22544,22545,22546,22547,22548,22549,22550,
+22551,22552,22553,22554,22555,22556,22557,22558,22559,22560,
+22561,22562,22563,22564,22565,22566,22567,22568,22569,22570,
+22571,22572,22573,22574,22575,22576,22577,22578,22579,22580,
+22581,22582,22583,22584,22585,22586,22587,22588,22589,22590,
+22591,22592,22593,22594,22595,22596,22597,22598,22599,22600,
+22601,22602,22603,22604,22605,22606,22607,22608,22609,22610,
+22611,22612,22613,22614,22615,22616,22617,22618,22619,22620,
+22621,22622,22623,22624,22625,22626,22627,22628,22629,22630,
+18842,7021,20267,19652,20421,18723,18492,12357,11840,6443,
+11083,19281,11032,3640,19985,19815,9439,1903,10363,6162,
+10256,14863,19988,19282,5665,13503,9546,10556,14518,2005,
+17411,10053,18020,6189,21102,16718,9045,12881,5339,19842,
+15130,6120,13349,19016,16612,10149,7082,19017,18757,6557,
+20413,11027,14860,10370,7892,10092,7449,17223,3245,7454,
+7457,18298,19440,3125,1631,3126,12116,21291,7374,11069,
+19691,10164,2433,8512,9983,11668,8166,8513,8001,9682,
+17340,18290,7263,11074,9696,20490,8004,12755,10108,18299,
+3127,10732,6121,2358,4846,11183,22631,22632,22633,22634,
+22635,22636,22637,22638,22639,22640,22641,22642,22643,22644,
+22645,22646,22647,22648,22649,22650,22651,22652,22653,22654,
+22655,22656,22657,22658,22659,22660,22661,22662,22663,22664,
+22665,22666,22667,22668,22669,22670,22671,22672,22673,22674,
+22675,22676,22677,22678,22679,22680,22681,22682,22683,22684,
+22685,22686,22687,22688,22689,22690,22691,22692,22693,22694,
+22695,22696,22697,22698,22699,22700,22701,22702,22703,22704,
+22705,22706,22707,22708,22709,22710,22711,22712,22713,22714,
+22715,22716,22717,22718,22719,22720,22721,22722,22723,22724,
+11184,4848,12124,13524,13457,11426,4849,17310,9168,11186,
+2581,4767,13453,11185,11334,11354,21654,11933,4700,6616,
+7893,5686,15713,15963,6494,8941,6270,2583,6164,19018,
+3408,17051,16090,11399,12939,3744,18341,10950,18346,19980,
+3469,18240,18350,18351,20724,20697,3362,1990,18765,10934,
+20444,18359,4055,10364,4703,11281,19904,3146,13528,2352,
+16206,21192,20828,11044,1019,1668,16166,1545,2344,11133,
+3891,21519,5525,3937,4695,19852,2277,5207,2048,19853,
+15475,15599,14778,4641,16582,1089,3794,16162,21051,13487,
+14480,14591,14593,15867,8247,8002,22725,22726,22727,22728,
+22729,22730,22731,22732,22733,22734,22735,22736,22737,22738,
+22739,22740,22741,22742,22743,22744,22745,22746,22747,22748,
+22749,22750,22751,22752,22753,22754,22755,22756,22757,22758,
+22759,22760,22761,22762,22763,22764,22765,22766,22767,22768,
+22769,22770,22771,22772,22773,22774,22775,22776,22777,22778,
+22779,22780,22781,22782,22783,22784,22785,22786,22787,22788,
+22789,22790,22791,22792,22793,22794,22795,22796,22797,22798,
+22799,22800,22801,22802,22803,22804,22805,22806,22807,22808,
+22809,22810,22811,22812,22813,22814,22815,22816,22817,22818,
+6850,8248,18353,15981,14967,17317,9413,18629,16811,16813,
+6283,17622,6159,17803,16629,20331,11890,11579,12723,20381,
+7207,21533,7013,7019,2635,2453,2454,6131,18172,19174,
+17620,1233,20265,14694,21535,2579,18347,8269,15791,10102,
+10096,2770,13583,17621,19175,11804,8168,18613,2996,20052,
+19693,2815,18878,11669,20266,2998,13512,20053,18358,11984,
+4357,16671,19083,3246,21656,3733,2816,7965,18211,6105,
+19157,10228,12089,5391,12090,18348,10245,10250,5392,8596,
+3306,10109,3307,5731,13364,1670,2914,6136,8483,17557,
+19987,9271,9814,5122,9564,9967,22819,22820,22821,22822,
+22823,22824,22825,22826,22827,22828,22829,22830,22831,22832,
+22833,22834,22835,22836,22837,22838,22839,22840,22841,22842,
+22843,22844,22845,22846,22847,22848,22849,22850,22851,22852,
+22853,22854,22855,22856,22857,22858,22859,22860,22861,22862,
+22863,22864,22865,22866,22867,22868,22869,22870,22871,22872,
+22873,22874,22875,22876,22877,22878,22879,22880,22881,22882,
+22883,22884,22885,22886,22887,22888,22889,22890,22891,22892,
+22893,22894,22895,22896,22897,22898,22899,22900,22901,22902,
+22903,22904,22905,22906,22907,22908,22909,22910,22911,22912,
+16769,6900,14850,19718,12706,4918,8263,9548,886,5739,
+14473,3992,7037,17500,17731,3521,23854,23855,23856,23857,
+23858,23859,23860,23861,23862,23863,23864,23865,23866,23867,
+23868,23869,23870,23871,23872,23873,23874,23875,23876,23877,
+23878,23879,23880,23881,23882,23883,23884,23885,23886,23887,
+23888,23889,23890,23891,23892,23893,23894,23895,23896,23897,
+23898,23899,23900,23901,23902,23903,23904,23905,23906,23907,
+23908,23909,23910,23911,23912,23913,23914,23915,23916,23917,
+23918,23919,23920,23921,23922,23923,23924,23925,23926,23927,
+23928,23929,23930,23931,23932,23933,22913,22914,22915,22916,
+22917,22918,22919,22920,22921,22922,22923,22924,22925,22926,
+22927,22928,22929,22930,22931,22932,22933,22934,22935,22936,
+22937,22938,22939,22940,22941,22942,22943,22944,22945,22946,
+22947,22948,22949,22950,22951,22952,22953,22954,22955,22956,
+22957,22958,22959,22960,22961,22962,22963,22964,22965,22966,
+22967,22968,22969,22970,22971,22972,22973,22974,22975,22976,
+22977,22978,22979,22980,22981,22982,22983,22984,22985,22986,
+22987,22988,22989,22990,22991,22992,22993,22994,22995,22996,
+22997,22998,22999,23000,23001,23002,23003,23004,23005,23006
+};
+
+static uint16 gbksortorder(uint16 i)
+{
+ uint idx=gbktail(i);
+ if (idx>0x7f) idx-=0x41;
+ else idx-=0x40;
+ idx+=(gbkhead(i)-0x81)*0xbe;
+ return 0x8100+gbk_order[idx];
+}
+
+
+int my_strnncoll_gbk(const uchar * s1, int len1, const uchar * s2, int len2)
+{
+ uint len,c1,c2;
+
+ len = min(len1,len2);
+ while (len--)
+ {
+ if ((len > 0) && isgbkcode(*s1,*(s1+1)) && isgbkcode(*s2, *(s2+1)))
+ {
+ c1=gbkcode(*s1,*(s1+1));
+ c2=gbkcode(*s2,*(s2+1));
+ if (c1!=c2)
+ return ((int) gbksortorder((uint16) c1) -
+ (int) gbksortorder((uint16) c2));
+ s1+=2;
+ s2+=2;
+ --len;
+ } else if (sort_order_gbk[(uchar) *s1++] != sort_order_gbk[(uchar) *s2++])
+ return ((int) sort_order_gbk[(uchar) s1[-1]] -
+ (int) sort_order_gbk[(uchar) s2[-1]]);
+ }
+ return (int) (len1-len2);
+}
+
+int my_strcoll_gbk(const uchar * s1, const uchar * s2)
+{
+ return my_strnncoll_gbk(s1, (uint) strlen((char*) s1),
+ s2, (uint) strlen((char*) s2));
+}
+
+int my_strnxfrm_gbk(uchar * dest, uchar * src, int len, int srclen)
+{
+ uint16 e;
+
+ len = srclen;
+ while (len--)
+ {
+ if ((len > 0) && isgbkcode(*src, *(src+1)))
+ {
+ e = gbksortorder((uint16) gbkcode(*src, *(src+1)));
+ *dest++ = gbkhead(e);
+ *dest++ = gbktail(e);
+ src+=2;
+ len--;
+ } else
+ *dest++ = sort_order_gbk[(uchar) *src++];
+ }
+ return srclen;
+}
+
+int my_strxfrm_gbk(uchar * dest, 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:
+** ptr Pointer to LIKE string.
+** ptr_length Length of LIKE string.
+** escape Escape character in LIKE. (Normally '\').
+** All escape characters should be removed from min_str and max_str
+** res_length Length of min_str and max_str.
+** min_str Smallest case sensitive string that ranges LIKE.
+** Should be space padded to res_length.
+** max_str Largest case sensitive string that ranges LIKE.
+** Normally padded with the biggest character sort value.
+**
+** The function should return 0 if ok and 1 if the LIKE string can't be
+** optimized !
+*/
+
+#define max_sort_char ((uchar) 255)
+#define wild_one '_'
+#define wild_many '%'
+
+extern my_bool my_like_range_gbk(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+1 != end && isgbkcode(ptr[0],ptr[1]))
+ {
+ *min_str++= *max_str++ = *ptr++;
+ *min_str++= *max_str++ = *ptr;
+ continue;
+ }
+ if (*ptr == escape && ptr+1 != end)
+ {
+ ptr++; /* Skipp escape */
+ *min_str++= *max_str++ = *ptr;
+ continue;
+ }
+ if (*ptr == wild_one) /* '_' in SQL */
+ {
+ *min_str++='\0'; /* This should be min 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++ = '\0'; /* 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);
+ while (min_str != min_end)
+ {
+ *min_str++ = ' '; /* Because if key compression */
+ *max_str++ = ' ';
+ }
+ return 0;
+}
+
+
+int ismbchar_gbk(const char* p, const char *e)
+{
+ return (isgbkhead(*(p)) && (e)-(p)>1 && isgbktail(*((p)+1))? 2: 0);
+}
+
+my_bool ismbhead_gbk(uint c)
+{
+ return isgbkhead(c);
+}
+
+int mbcharlen_gbk(uint c)
+{
+ return (isgbkhead(c)? 2:0);
+}
diff --git a/strings/ctype-sjis.c b/strings/ctype-sjis.c
new file mode 100644
index 00000000000..e59a6f59dbb
--- /dev/null
+++ b/strings/ctype-sjis.c
@@ -0,0 +1,317 @@
+/* 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 for Shift JIS charset, and created by tommy@valley.ne.jp.
+ */
+
+#include <global.h>
+#include "m_string.h"
+#include "m_ctype.h"
+
+/*
+ * 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_sjis=1
+ * .configure. mbmaxlen_sjis=2
+ */
+
+uchar NEAR ctype_sjis[257] =
+{
+ 0, /* For standard library */
+ 0040, 0040, 0040, 0040, 0040, 0040, 0040, 0040, /* NUL ^A - ^G */
+ 0040, 0050, 0050, 0050, 0050, 0050, 0040, 0040, /* ^H - ^O */
+ 0040, 0040, 0040, 0040, 0040, 0040, 0040, 0040, /* ^P - ^W */
+ 0040, 0040, 0040, 0040, 0040, 0040, 0040, 0040, /* ^X - ^Z ^[ ^\ ^] ^^ ^_ */
+ 0110, 0020, 0020, 0020, 0020, 0020, 0020, 0020, /* SPC ! " # $ % ^ ' */
+ 0020, 0020, 0020, 0020, 0020, 0020, 0020, 0020, /* ( ) * + , - . / */
+ 0204, 0204, 0204, 0204, 0204, 0204, 0204, 0204, /* 0 1 2 3 4 5 6 7 */
+ 0204, 0204, 0020, 0020, 0020, 0020, 0020, 0020, /* 8 9 : ; < = > ? */
+ 0020, 0201, 0201, 0201, 0201, 0201, 0201, 0001, /* @ A B C D E F G */
+ 0001, 0001, 0001, 0001, 0001, 0001, 0001, 0001, /* H I J K L M N O */
+ 0001, 0001, 0001, 0001, 0001, 0001, 0001, 0001, /* P Q R S T U V W */
+ 0001, 0001, 0001, 0020, 0020, 0020, 0020, 0020, /* X Y Z [ \ ] ^ _ */
+ 0020, 0202, 0202, 0202, 0202, 0202, 0202, 0002, /* ` a b c d e f g */
+ 0002, 0002, 0002, 0002, 0002, 0002, 0002, 0002, /* h i j k l m n o */
+ 0002, 0002, 0002, 0002, 0002, 0002, 0002, 0002, /* p q r s t u v w */
+ 0002, 0002, 0002, 0020, 0020, 0020, 0020, 0040, /* x y z { | } + DEL */
+ 0020, 0020, 0020, 0020, 0020, 0020, 0020, 0020,
+ 0020, 0020, 0020, 0020, 0020, 0020, 0020, 0020,
+ 0020, 0020, 0020, 0020, 0020, 0020, 0020, 0020,
+ 0020, 0020, 0020, 0020, 0020, 0020, 0020, 0020,
+ 0020, 0020, 0020, 0020, 0020, 0020, 0020, 0020,
+ 0020, 0020, 0020, 0020, 0020, 0020, 0020, 0020,
+ 0020, 0020, 0020, 0020, 0020, 0020, 0020, 0020,
+ 0020, 0020, 0020, 0020, 0020, 0020, 0020, 0020,
+ 0020, 0020, 0020, 0020, 0020, 0020, 0020, 0020,
+ 0020, 0020, 0020, 0020, 0020, 0020, 0020, 0020,
+ 0020, 0020, 0020, 0020, 0020, 0020, 0020, 0020,
+ 0020, 0020, 0020, 0020, 0020, 0020, 0020, 0020,
+ 0020, 0020, 0020, 0020, 0020, 0020, 0020, 0020,
+ 0020, 0020, 0020, 0020, 0020, 0020, 0020, 0020,
+ 0020, 0020, 0020, 0020, 0020, 0020, 0020, 0020,
+ 0020, 0020, 0020, 0020, 0020, 0000, 0000, 0000
+};
+
+uchar NEAR to_lower_sjis[]=
+{
+ '\000','\001','\002','\003','\004','\005','\006','\007',
+ '\010','\011','\012','\013','\014','\015','\016','\017',
+ '\020','\021','\022','\023','\024','\025','\026','\027',
+ '\030','\031','\032','\033','\034','\035','\036','\037',
+ ' ', '!', '"', '#', '$', '%', '&', '\'',
+ '(', ')', '*', '+', ',', '-', '.', '/',
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', ':', ';', '<', '=', '>', '?',
+ '@', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
+ 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
+ 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
+ 'x', 'y', 'z', '[', '\\', ']', '^', '_',
+ '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
+ 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
+ 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
+ 'x', 'y', 'z', '{', '|', '}', '~', '\177',
+ '\200','\201','\202','\203','\204','\205','\206','\207',
+ '\210','\211','\212','\213','\214','\215','\216','\217',
+ '\220','\221','\222','\223','\224','\225','\226','\227',
+ '\230','\231','\232','\233','\234','\235','\236','\237',
+ '\240','\241','\242','\243','\244','\245','\246','\247',
+ '\250','\251','\252','\253','\254','\255','\256','\257',
+ '\260','\261','\262','\263','\264','\265','\266','\267',
+ '\270','\271','\272','\273','\274','\275','\276','\277',
+ '\300','\301','\302','\303','\304','\305','\306','\307',
+ '\310','\311','\312','\313','\314','\315','\316','\317',
+ '\320','\321','\322','\323','\324','\325','\326','\327',
+ '\330','\331','\332','\333','\334','\335','\336','\337',
+ '\340','\341','\342','\343','\344','\345','\346','\347',
+ '\350','\351','\352','\353','\354','\355','\356','\357',
+ '\360','\361','\362','\363','\364','\365','\366','\367',
+ '\370','\371','\372','\373','\374','\375','\376','\377'
+};
+
+uchar NEAR to_upper_sjis[]=
+{
+ '\000','\001','\002','\003','\004','\005','\006','\007',
+ '\010','\011','\012','\013','\014','\015','\016','\017',
+ '\020','\021','\022','\023','\024','\025','\026','\027',
+ '\030','\031','\032','\033','\034','\035','\036','\037',
+ ' ', '!', '"', '#', '$', '%', '&', '\'',
+ '(', ')', '*', '+', ',', '-', '.', '/',
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', ':', ';', '<', '=', '>', '?',
+ '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+ 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+ 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+ 'X', 'Y', 'Z', '[', '\\', ']', '^', '_',
+ '`', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+ 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+ 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+ 'X', 'Y', 'Z', '{', '|', '}', '~', '\177',
+ '\200','\201','\202','\203','\204','\205','\206','\207',
+ '\210','\211','\212','\213','\214','\215','\216','\217',
+ '\220','\221','\222','\223','\224','\225','\226','\227',
+ '\230','\231','\232','\233','\234','\235','\236','\237',
+ '\240','\241','\242','\243','\244','\245','\246','\247',
+ '\250','\251','\252','\253','\254','\255','\256','\257',
+ '\260','\261','\262','\263','\264','\265','\266','\267',
+ '\270','\271','\272','\273','\274','\275','\276','\277',
+ '\300','\301','\302','\303','\304','\305','\306','\307',
+ '\310','\311','\312','\313','\314','\315','\316','\317',
+ '\320','\321','\322','\323','\324','\325','\326','\327',
+ '\330','\331','\332','\333','\334','\335','\336','\337',
+ '\340','\341','\342','\343','\344','\345','\346','\347',
+ '\350','\351','\352','\353','\354','\355','\356','\357',
+ '\360','\361','\362','\363','\364','\365','\366','\367',
+ '\370','\371','\372','\373','\374','\375','\376','\377'
+};
+
+uchar NEAR sort_order_sjis[]=
+{
+ '\000','\001','\002','\003','\004','\005','\006','\007',
+ '\010','\011','\012','\013','\014','\015','\016','\017',
+ '\020','\021','\022','\023','\024','\025','\026','\027',
+ '\030','\031','\032','\033','\034','\035','\036','\037',
+ ' ', '!', '"', '#', '$', '%', '&', '\'',
+ '(', ')', '*', '+', ',', '-', '.', '/',
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', ':', ';', '<', '=', '>', '?',
+ '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+ 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+ 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+ 'X', 'Y', 'Z', '[', '\\', ']', '^', '_',
+ '`', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+ 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+ 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+ 'X', 'Y', 'Z', '{', '|', '}', '~', '\177',
+ '\200','\201','\202','\203','\204','\205','\206','\207',
+ '\210','\211','\212','\213','\214','\215','\216','\217',
+ '\220','\221','\222','\223','\224','\225','\226','\227',
+ '\230','\231','\232','\233','\234','\235','\236','\237',
+ '\240','\241','\242','\243','\244','\245','\246','\247',
+ '\250','\251','\252','\253','\254','\255','\256','\257',
+ '\260','\261','\262','\263','\264','\265','\266','\267',
+ '\270','\271','\272','\273','\274','\275','\276','\277',
+ '\300','\301','\302','\303','\304','\305','\306','\307',
+ '\310','\311','\312','\313','\314','\315','\316','\317',
+ '\320','\321','\322','\323','\324','\325','\326','\327',
+ '\330','\331','\332','\333','\334','\335','\336','\337',
+ '\340','\341','\342','\343','\344','\345','\346','\347',
+ '\350','\351','\352','\353','\354','\355','\356','\357',
+ '\360','\361','\362','\363','\364','\365','\366','\367',
+ '\370','\371','\372','\373','\374','\375','\376','\377'
+};
+
+#define issjishead(c) ((0x81<=(c) && (c)<=0x9f) || \
+ ((0xe0<=(c)) && (c)<=0xfc))
+#define issjistail(c) ((0x40<=(c) && (c)<=0x7e) || \
+ (0x80<=(c) && (c)<=0xfc))
+
+
+int ismbchar_sjis(const char* p, const char *e)
+{
+ return (issjishead((uchar) *p) && (e-p)>1 && issjistail((uchar)p[1]) ? 2: 0);
+}
+
+my_bool ismbhead_sjis(uint c)
+{
+ return issjishead((uchar) c);
+}
+
+int mbcharlen_sjis(uint c)
+{
+ return (issjishead((uchar) c) ? 2: 0);
+}
+
+
+#define sjiscode(c,d) ((((uint) (uchar)(c)) << 8) | (uint) (uchar) (d))
+
+int my_strnncoll_sjis(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) {
+ if (ismbchar_sjis((char*) s1, (char*) e1) &&
+ ismbchar_sjis((char*) s2, (char*) e2)) {
+ uint c1 = sjiscode(*s1, *(s1+1));
+ uint c2 = sjiscode(*s2, *(s2+1));
+ if (c1 != c2)
+ return c1 - c2;
+ s1 += 2;
+ s2 += 2;
+ } else {
+ if (sort_order_sjis[(uchar)*s1] != sort_order_sjis[(uchar)*s2])
+ return sort_order_sjis[(uchar)*s1] - sort_order_sjis[(uchar)*s2];
+ s1++;
+ s2++;
+ }
+ }
+ return len1 - len2;
+}
+
+int my_strcoll_sjis(const uchar *s1, const uchar *s2)
+{
+ return my_strnncoll_sjis(s1, strlen(s1), s2, strlen(s2));
+}
+
+int my_strnxfrm_sjis(uchar *dest, uchar *src, int len, int srclen)
+{
+ uchar *d_end = dest + len;
+ uchar *s_end = src + srclen;
+ while (dest < d_end && src < s_end) {
+ if (ismbchar_sjis((char*) src, (char*) s_end)) {
+ *dest++ = *src++;
+ if (dest < d_end && src < s_end)
+ *dest++ = *src++;
+ } else {
+ *dest++ = sort_order_sjis[(uchar)*src++];
+ }
+ }
+ return srclen;
+}
+
+int my_strxfrm_sjis(uchar *dest, uchar *src, int len)
+{
+ return my_strnxfrm_sjis(dest, src, len, strlen(src));
+}
+
+
+/*
+** Calculate min_str and max_str that ranges a LIKE string.
+** Arguments:
+** ptr Pointer to LIKE string.
+** ptr_length Length of LIKE string.
+** escape Escape character in LIKE. (Normally '\').
+** All escape characters should be removed from min_str and max_str
+** res_length Length of min_str and max_str.
+** min_str Smallest case sensitive string that ranges LIKE.
+** Should be space padded to res_length.
+** max_str Largest case sensitive string that ranges LIKE.
+** Normally padded with the biggest character sort value.
+**
+** The function should return 0 if ok and 1 if the LIKE string can't be
+** optimized !
+*/
+
+#define max_sort_char ((char) 255)
+#define wild_one '_'
+#define wild_many '%'
+
+my_bool my_like_range_sjis(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;
+
+ while (ptr < end && min_str < min_end) {
+ if (ismbchar_sjis(ptr, end)) {
+ *min_str++ = *max_str++ = *ptr++;
+ if (min_str < min_end)
+ *min_str++ = *max_str++ = *ptr++;
+ continue;
+ }
+ if (*ptr == escape && ptr+1 < end) {
+ ptr++; /* Skip escape */
+ if (ismbchar_sjis(ptr, end))
+ *min_str++ = *max_str++ = *ptr++;
+ if (min_str < min_end)
+ *min_str++ = *max_str++ = *ptr++;
+ continue;
+ }
+ if (*ptr == wild_one) { /* '_' in SQL */
+ *min_str++ = '\0'; /* This should be min char */
+ *max_str++ = max_sort_char;
+ ptr++;
+ 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);
+ while (min_str < min_end)
+ *min_str++ = *max_str++ = ' '; /* Because if key compression */
+ return 0;
+}
diff --git a/strings/ctype-tis620.c b/strings/ctype-tis620.c
new file mode 100644
index 00000000000..bc80819c2a9
--- /dev/null
+++ b/strings/ctype-tis620.c
@@ -0,0 +1,656 @@
+/*
+ Copyright (C) 1998, 1999 by Pruet Boonma <pruet@eng.cmu.ac.th>
+ Copyright (C) 1998 by Theppitak Karoonboonyanan <thep@links.nectec.or.th>
+ Copyright (C) 1989, 1991 by Samphan Raruenrom <samphan@thai.com>
+
+ Permission to use, copy, modify, distribute and sell this software
+ and its documentation for any purpose is hereby granted without fee,
+ provided that the above copyright notice appear in all copies.
+ Smaphan Raruenrom , Theppitak Karoonboonyanan and Pruet Boonma makes
+ no representations about the suitability of this software for any
+ purpose. It is provided "as is" without express or implied warranty.
+*/
+
+
+/* $Id$
+ This file is basicly tis620 character sets with some extra functions
+ for tis-620 handling
+*/
+
+/*
+ * 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_tis620=4
+ */
+
+#include <global.h>
+#include <my_sys.h>
+#include "m_string.h"
+#include "m_ctype.h"
+#include "t_ctype.h"
+
+static uchar* thai2sortable(const uchar *tstr,uint len);
+
+#define BUFFER_MULTIPLY 4
+#define buffsize(s) (BUFFER_MULTIPLY * (strlen(s) + 1))
+#define M L_MIDDLE
+#define U L_UPPER
+#define L L_LOWER
+#define UU L_UPRUPR
+#define X L_MIDDLE
+
+
+int t_ctype[][TOT_LEVELS] = {
+ /*0x00*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
+ /*0x01*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
+ /*0x02*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
+ /*0x03*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
+ /*0x04*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
+ /*0x05*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
+ /*0x06*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
+ /*0x07*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
+ /*0x08*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
+ /*0x09*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
+ /*0x0A*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
+ /*0x0B*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
+ /*0x0C*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
+ /*0x0D*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
+ /*0x0E*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
+ /*0x0F*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
+ /*0x10*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
+ /*0x11*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
+ /*0x12*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
+ /*0x13*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
+ /*0x14*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
+ /*0x15*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
+ /*0x16*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
+ /*0x17*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
+ /*0x18*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
+ /*0x19*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
+ /*0x1A*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
+ /*0x1B*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
+ /*0x1C*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
+ /*0x1D*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
+ /*0x1E*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
+ /*0x1F*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
+ /*0x20*/ { IGNORE, IGNORE, L3_SPACE, IGNORE, M},
+ /*0x21*/ { IGNORE, IGNORE, L3_EXCLAMATION, IGNORE, M },
+ /*0x22*/ { IGNORE, IGNORE, L3_QUOTATION, IGNORE, M },
+ /*0x23*/ { IGNORE, IGNORE, L3_NUMBER, IGNORE, M },
+ /*0x24*/ { IGNORE, IGNORE, L3_DOLLAR, IGNORE, M },
+ /*0x25*/ { IGNORE, IGNORE, L3_PERCENT, IGNORE, M },
+ /*0x26*/ { IGNORE, IGNORE, L3_AMPERSAND, IGNORE, M },
+ /*0x27*/ { IGNORE, IGNORE, L3_APOSTROPHE, IGNORE, M },
+ /*0x28*/ { IGNORE, IGNORE, L3_L_PARANTHESIS, IGNORE, M },
+ /*0x29*/ { IGNORE, IGNORE, L3_R_PARENTHESIS, IGNORE, M },
+ /*0x2A*/ { IGNORE, IGNORE, L3_ASTERISK, IGNORE, M },
+ /*0x2B*/ { IGNORE, IGNORE, L3_PLUS, IGNORE, M },
+ /*0x2C*/ { IGNORE, IGNORE, L3_COMMA, IGNORE, M },
+ /*0x2D*/ { IGNORE, IGNORE, L3_HYPHEN, IGNORE, M },
+ /*0x2E*/ { IGNORE, IGNORE, L3_FULL_STOP, IGNORE, M },
+ /*0x2F*/ { IGNORE, IGNORE, L3_SOLIDUS, IGNORE, M },
+ /*0x30*/ { L1_08, L2_BLANK, L3_BLANK, L4_BLANK, M },
+ /*0x31*/ { L1_18, L2_BLANK, L3_BLANK, L4_BLANK, M },
+ /*0x32*/ { L1_28, L2_BLANK, L3_BLANK, L4_BLANK, M },
+ /*0x33*/ { L1_38, L2_BLANK, L3_BLANK, L4_BLANK, M },
+ /*0x34*/ { L1_48, L2_BLANK, L3_BLANK, L4_BLANK, M },
+ /*0x35*/ { L1_58, L2_BLANK, L3_BLANK, L4_BLANK, M },
+ /*0x36*/ { L1_68, L2_BLANK, L3_BLANK, L4_BLANK, M },
+ /*0x37*/ { L1_78, L2_BLANK, L3_BLANK, L4_BLANK, M },
+ /*0x38*/ { L1_88, L2_BLANK, L3_BLANK, L4_BLANK, M },
+ /*0x39*/ { L1_98, L2_BLANK, L3_BLANK, L4_BLANK, M },
+ /*0x3A*/ { IGNORE, IGNORE, L3_COLON, IGNORE, M },
+ /*0x3B*/ { IGNORE, IGNORE, L3_SEMICOLON, IGNORE, M },
+ /*0x3C*/ { IGNORE, IGNORE, L3_LESS_THAN, IGNORE, M },
+ /*0x3D*/ { IGNORE, IGNORE, L3_EQUAL, IGNORE, M },
+ /*0x3E*/ { IGNORE, IGNORE, L3_GREATER_THAN, IGNORE, M },
+ /*0x3F*/ { IGNORE, IGNORE, L3_QUESTION, IGNORE, M },
+ /*0x40*/ { IGNORE, IGNORE, L3_AT, IGNORE, M },
+ /*0x41*/ { L1_A8, L2_BLANK, L3_BLANK, L4_CAP, M },
+ /*0x42*/ { L1_B8, L2_BLANK, L3_BLANK, L4_CAP, M },
+ /*0x43*/ { L1_C8, L2_BLANK, L3_BLANK, L4_CAP, M },
+ /*0x44*/ { L1_D8, L2_BLANK, L3_BLANK, L4_CAP, M },
+ /*0x45*/ { L1_E8, L2_BLANK, L3_BLANK, L4_CAP, M },
+ /*0x46*/ { L1_F8, L2_BLANK, L3_BLANK, L4_CAP, M },
+ /*0x47*/ { L1_G8, L2_BLANK, L3_BLANK, L4_CAP, M },
+ /*0x48*/ { L1_H8, L2_BLANK, L3_BLANK, L4_CAP, M },
+ /*0x49*/ { L1_I8, L2_BLANK, L3_BLANK, L4_CAP, M },
+ /*0x4A*/ { L1_J8, L2_BLANK, L3_BLANK, L4_CAP, M },
+ /*0x4B*/ { L1_K8, L2_BLANK, L3_BLANK, L4_CAP, M },
+ /*0x4C*/ { L1_L8, L2_BLANK, L3_BLANK, L4_CAP, M },
+ /*0x4D*/ { L1_M8, L2_BLANK, L3_BLANK, L4_CAP, M },
+ /*0x4E*/ { L1_N8, L2_BLANK, L3_BLANK, L4_CAP, M },
+ /*0x4F*/ { L1_O8, L2_BLANK, L3_BLANK, L4_CAP, M },
+ /*0x50*/ { L1_P8, L2_BLANK, L3_BLANK, L4_CAP, M },
+ /*0x51*/ { L1_Q8, L2_BLANK, L3_BLANK, L4_CAP, M },
+ /*0x52*/ { L1_R8, L2_BLANK, L3_BLANK, L4_CAP, M },
+ /*0x53*/ { L1_S8, L2_BLANK, L3_BLANK, L4_CAP, M },
+ /*0x54*/ { L1_T8, L2_BLANK, L3_BLANK, L4_CAP, M },
+ /*0x55*/ { L1_U8, L2_BLANK, L3_BLANK, L4_CAP, M },
+ /*0x56*/ { L1_V8, L2_BLANK, L3_BLANK, L4_CAP, M },
+ /*0x57*/ { L1_W8, L2_BLANK, L3_BLANK, L4_CAP, M },
+ /*0x58*/ { L1_X8, L2_BLANK, L3_BLANK, L4_CAP, M },
+ /*0x59*/ { L1_Y8, L2_BLANK, L3_BLANK, L4_CAP, M },
+ /*0x5A*/ { L1_Z8, L2_BLANK, L3_BLANK, L4_CAP, M },
+ /*0x5B*/ { IGNORE, IGNORE, L3_L_BRACKET, IGNORE, M },
+ /*0x5C*/ { IGNORE, IGNORE, L3_BK_SOLIDUS, IGNORE, M },
+ /*0x5D*/ { IGNORE, IGNORE, L3_R_BRACKET, IGNORE, M },
+ /*0x5E*/ { IGNORE, IGNORE, L3_CIRCUMFLEX, IGNORE, M },
+ /*0x5F*/ { IGNORE, IGNORE, L3_LOW_LINE, IGNORE, M },
+ /*0x60*/ { IGNORE, IGNORE, L3_GRAVE, IGNORE, M },
+ /*0x61*/ { L1_A8, L2_BLANK, L3_BLANK, L4_MIN, M },
+ /*0x62*/ { L1_B8, L2_BLANK, L3_BLANK, L4_MIN, M },
+ /*0x63*/ { L1_C8, L2_BLANK, L3_BLANK, L4_MIN, M },
+ /*0x64*/ { L1_D8, L2_BLANK, L3_BLANK, L4_MIN, M },
+ /*0x65*/ { L1_E8, L2_BLANK, L3_BLANK, L4_MIN, M },
+ /*0x66*/ { L1_F8, L2_BLANK, L3_BLANK, L4_MIN, M },
+ /*0x67*/ { L1_G8, L2_BLANK, L3_BLANK, L4_MIN, M },
+ /*0x68*/ { L1_H8, L2_BLANK, L3_BLANK, L4_MIN, M },
+ /*0x69*/ { L1_I8, L2_BLANK, L3_BLANK, L4_MIN, M },
+ /*0x6A*/ { L1_J8, L2_BLANK, L3_BLANK, L4_MIN, M },
+ /*0x6B*/ { L1_K8, L2_BLANK, L3_BLANK, L4_MIN, M },
+ /*0x6C*/ { L1_L8, L2_BLANK, L3_BLANK, L4_MIN, M },
+ /*0x6D*/ { L1_M8, L2_BLANK, L3_BLANK, L4_MIN, M },
+ /*0x6E*/ { L1_N8, L2_BLANK, L3_BLANK, L4_MIN, M },
+ /*0x6F*/ { L1_O8, L2_BLANK, L3_BLANK, L4_MIN, M },
+ /*0x70*/ { L1_P8, L2_BLANK, L3_BLANK, L4_MIN, M },
+ /*0x71*/ { L1_Q8, L2_BLANK, L3_BLANK, L4_MIN, M },
+ /*0x72*/ { L1_R8, L2_BLANK, L3_BLANK, L4_MIN, M },
+ /*0x73*/ { L1_S8, L2_BLANK, L3_BLANK, L4_MIN, M },
+ /*0x74*/ { L1_T8, L2_BLANK, L3_BLANK, L4_MIN, M },
+ /*0x75*/ { L1_U8, L2_BLANK, L3_BLANK, L4_MIN, M },
+ /*0x76*/ { L1_V8, L2_BLANK, L3_BLANK, L4_MIN, M },
+ /*0x77*/ { L1_W8, L2_BLANK, L3_BLANK, L4_MIN, M },
+ /*0x78*/ { L1_X8, L2_BLANK, L3_BLANK, L4_MIN, M },
+ /*0x79*/ { L1_Y8, L2_BLANK, L3_BLANK, L4_MIN, M },
+ /*0x7A*/ { L1_Z8, L2_BLANK, L3_BLANK, L4_MIN, M },
+ /*0x7B*/ { IGNORE, IGNORE, L3_L_BRACE, IGNORE, M },
+ /*0x7C*/ { IGNORE, IGNORE, L3_V_LINE, IGNORE, M },
+ /*0x7D*/ { IGNORE, IGNORE, L3_R_BRACE, IGNORE, M },
+ /*0x7E*/ { IGNORE, IGNORE, L3_TILDE, IGNORE, M },
+ /*0x7F*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
+ /*0x80*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
+ /*0x81*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
+ /*0x82*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
+ /*0x83*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
+ /*0x84*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
+ /*0x85*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
+ /*0x86*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
+ /*0x87*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
+ /*0x88*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
+ /*0x89*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
+ /*0x8A*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
+ /*0x8B*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
+ /*0x8C*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
+ /*0x8D*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
+ /*0x8E*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
+ /*0x8F*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
+ /*0x90*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
+ /*0x91*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
+ /*0x92*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
+ /*0x93*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
+ /*0x94*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
+ /*0x95*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
+ /*0x96*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
+ /*0x97*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
+ /*0x98*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
+ /*0x99*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
+ /*0x9A*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
+ /*0x9B*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
+ /*0x9C*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
+ /*0x9D*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
+ /*0x9E*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
+ /*0x9F*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
+ /*0xA0*/ { IGNORE, IGNORE, L3_NB_SACE, IGNORE, X },
+ /*0xA1*/ { L1_KO_KAI, L2_BLANK, L3_BLANK, L4_BLANK, M | _consnt},
+ /*0xA2*/ { L1_KHO_KHAI, L2_BLANK, L3_BLANK, L4_BLANK, M | _consnt},
+ /*0xA3*/ { L1_KHO_KHUAT, L2_BLANK, L3_BLANK, L4_BLANK, M | _consnt},
+ /*0xA4*/ { L1_KHO_KHWAI, L2_BLANK, L3_BLANK, L4_BLANK, M | _consnt},
+ /*0xA5*/ { L1_KHO_KHON, L2_BLANK, L3_BLANK, L4_BLANK, M | _consnt},
+ /*0xA6*/ { L1_KHO_RAKHANG, L2_BLANK, L3_BLANK, L4_BLANK, M | _consnt},
+ /*0xA7*/ { L1_NGO_NGU, L2_BLANK, L3_BLANK, L4_BLANK, M | _consnt},
+ /*0xA8*/ { L1_CHO_CHAN, L2_BLANK, L3_BLANK, L4_BLANK, M | _consnt},
+ /*0xA9*/ { L1_CHO_CHING, L2_BLANK, L3_BLANK, L4_BLANK, M | _consnt},
+ /*0xAA*/ { L1_CHO_CHANG, L2_BLANK, L3_BLANK, L4_BLANK, M | _consnt},
+ /*0xAB*/ { L1_SO_SO, L2_BLANK, L3_BLANK, L4_BLANK, M | _consnt},
+ /*0xAC*/ { L1_CHO_CHOE, L2_BLANK, L3_BLANK, L4_BLANK, M | _consnt},
+ /*0xAD*/ { L1_YO_YING, L2_BLANK, L3_BLANK, L4_BLANK, M | _consnt},
+ /*0xAE*/ { L1_DO_CHADA, L2_BLANK, L3_BLANK, L4_BLANK, M | _consnt},
+ /*0xAF*/ { L1_TO_PATAK, L2_BLANK, L3_BLANK, L4_BLANK, M | _consnt},
+ /*0xB0*/ { L1_THO_THAN, L2_BLANK,L3_BLANK, L4_BLANK, M | _consnt},
+ /*0xB1*/ { L1_THO_NANGMONTHO, L2_BLANK, L3_BLANK, L4_BLANK, M | _consnt},
+ /*0xB2*/ { L1_THO_PHUTHAO, L2_BLANK, L3_BLANK, L4_BLANK, M | _consnt},
+ /*0xB3*/ { L1_NO_NEN, L2_BLANK, L3_BLANK, L4_BLANK, M | _consnt},
+ /*0xB4*/ { L1_DO_DEK, L2_BLANK, L3_BLANK, L4_BLANK, M | _consnt},
+ /*0xB5*/ { L1_TO_TAO, L2_BLANK, L3_BLANK, L4_BLANK, M | _consnt},
+ /*0xB6*/ { L1_THO_THUNG, L2_BLANK, L3_BLANK, L4_BLANK, M | _consnt},
+ /*0xB7*/ { L1_THO_THAHAN, L2_BLANK, L3_BLANK, L4_BLANK, M | _consnt},
+ /*0xB8*/ { L1_THO_THONG, L2_BLANK, L3_BLANK, L4_BLANK, M | _consnt},
+ /*0xB9*/ { L1_NO_NU, L2_BLANK, L3_BLANK, L4_BLANK, M | _consnt},
+ /*0xBA*/ { L1_BO_BAIMAI, L2_BLANK, L3_BLANK, L4_BLANK, M | _consnt},
+ /*0xBB*/ { L1_PO_PLA, L2_BLANK, L3_BLANK, L4_BLANK, M | _consnt},
+ /*0xBC*/ { L1_PHO_PHUNG, L2_BLANK, L3_BLANK, L4_BLANK, M | _consnt},
+ /*0xBD*/ { L1_FO_FA, L2_BLANK, L3_BLANK, L4_BLANK, M | _consnt},
+ /*0xBE*/ { L1_PHO_PHAN, L2_BLANK, L3_BLANK, L4_BLANK, M | _consnt},
+ /*0xBF*/ { L1_FO_FAN, L2_BLANK, L3_BLANK, L4_BLANK, M | _consnt},
+ /*0xC0*/ { L1_PHO_SAMPHAO, L2_BLANK, L3_BLANK, L4_BLANK, M | _consnt},
+ /*0xC1*/ { L1_MO_MA, L2_BLANK, L3_BLANK, L4_BLANK, M | _consnt},
+ /*0xC2*/ { L1_YO_YAK, L2_BLANK, L3_BLANK, L4_BLANK, M | _consnt},
+ /*0xC3*/ { L1_RO_RUA, L2_BLANK, L3_BLANK, L4_BLANK, M | _consnt},
+ /*0xC4*/ { L1_RU, L2_BLANK, L3_BLANK, L4_BLANK, M | _consnt},
+ /*0xC5*/ { L1_LO_LING, L2_BLANK, L3_BLANK, L4_BLANK, M | _consnt},
+ /*0xC6*/ { L1_LU, L2_BLANK, L3_BLANK, L4_BLANK, M | _consnt},
+ /*0xC7*/ { L1_WO_WAEN, L2_BLANK, L3_BLANK, L4_BLANK, M | _consnt},
+ /*0xC8*/ { L1_SO_SALA, L2_BLANK, L3_BLANK, L4_BLANK, M | _consnt},
+ /*0xC9*/ { L1_SO_RUSI, L2_BLANK, L3_BLANK, L4_BLANK, M | _consnt},
+ /*0xCA*/ { L1_SO_SUA, L2_BLANK, L3_BLANK, L4_BLANK, M | _consnt},
+ /*0xCB*/ { L1_HO_HIP, L2_BLANK, L3_BLANK, L4_BLANK, M | _consnt},
+ /*0xCC*/ { L1_LO_CHULA, L2_BLANK, L3_BLANK, L4_BLANK, M | _consnt},
+ /*0xCD*/ { L1_O_ANG, L2_BLANK, L3_BLANK, L4_BLANK, M | _consnt},
+ /*0xCE*/ { L1_HO_NOKHUK, L2_BLANK, L3_BLANK, L4_BLANK, M | _consnt},
+ /*0xCF*/ { IGNORE, IGNORE, L3_PAIYAN_NOI, IGNORE, M},
+ /*0xD0*/ { L1_SARA_A, L2_BLANK, L3_BLANK, L4_BLANK, M | _fllwvowel},
+ /*0xD1*/ { L1_MAI_HAN_AKAT, L2_BLANK, L3_BLANK, L4_BLANK, U | _uprvowel},
+ /*0xD2*/ { L1_SARA_AA, L2_BLANK, L3_BLANK, L4_BLANK, M | _fllwvowel},
+ /*0xD3*/ { L1_SARA_AM, L2_BLANK, L3_BLANK, L4_BLANK, M | _fllwvowel},
+ /*0xD4*/ { L1_SARA_I, L2_BLANK, L3_BLANK, L4_BLANK, U | _uprvowel},
+ /*0xD5*/ { L1_SARA_II, L2_BLANK, L3_BLANK, L4_BLANK, U | _uprvowel},
+ /*0xD6*/ { L1_SARA_UE, L2_BLANK, L3_BLANK, L4_BLANK, U | _uprvowel},
+ /*0xD7*/ { L1_SARA_UEE, L2_BLANK, L3_BLANK, L4_BLANK, U | _uprvowel},
+ /*0xD8*/ { L1_SARA_U, L2_BLANK, L3_BLANK, L4_BLANK, L | _lwrvowel},
+ /*0xD9*/ { L1_SARA_UU, L2_BLANK, L3_BLANK, L4_BLANK, L | _lwrvowel},
+ /*0xDA*/ { IGNORE, L2_PINTHU, L3_BLANK, L4_BLANK, L },
+ /*0xDB*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
+ /*0xDC*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
+ /*0xDD*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
+ /*0xDE*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
+ /*0xDF*/ { IGNORE, IGNORE, L3_BAHT, IGNORE, M},
+ /*0xE0*/ { L1_SARA_E, L2_BLANK, L3_BLANK, L4_BLANK, M | _ldvowel },
+ /*0xE1*/ { L1_SARA_AE, L2_BLANK, L3_BLANK, L4_BLANK, M | _ldvowel },
+ /*0xE2*/ { L1_SARA_O, L2_BLANK, L3_BLANK, L4_BLANK, M | _ldvowel },
+ /*0xE3*/ { L1_SARA_AI_MAIMUAN, L2_BLANK, L3_BLANK, L4_BLANK, M | _ldvowel },
+ /*0xE4*/ { L1_SARA_AI_MAIMALAI, L2_BLANK, L3_BLANK, L4_BLANK, M | _ldvowel },
+ /*0xE5*/ { L1_SARA_AA, L2_BLANK, L3_BLANK, L4_EXT, M | _fllwvowel },
+ /*0xE6*/ { IGNORE, IGNORE, L3_MAI_YAMOK, IGNORE, M | _stone },
+ /*0xE7*/ { IGNORE, L2_TYKHU, L3_BLANK, L4_BLANK, U | _diacrt1 | _stone },
+ /*0xE8*/ { IGNORE, L2_TONE1, L3_BLANK, L4_BLANK, UU | _tone | _combine | _stone },
+ /*0xE9*/ { IGNORE, L2_TONE2, L3_BLANK, L4_BLANK, UU | _tone | _combine | _stone },
+ /*0xEA*/ { IGNORE, L2_TONE3, L3_BLANK, L4_BLANK, UU | _tone | _combine | _stone },
+ /*0xEB*/ { IGNORE, L2_TONE4, L3_BLANK, L4_BLANK, UU | _tone | _combine | _stone },
+ /*0xEC*/ { IGNORE, L2_GARAN, L3_BLANK, L4_BLANK, UU | _diacrt2 | _combine | _stone },
+ /*0xED*/ { L1_NKHIT, L2_BLANK, L3_BLANK, L4_BLANK, U | _diacrt1 },
+ /*0xEE*/ { IGNORE, L2_YAMAK, L3_BLANK, L4_BLANK, U | _diacrt1 },
+ /*0xEF*/ { IGNORE, IGNORE, L3_FONGMAN, IGNORE, M },
+ /*0xF0*/ { L1_08, L2_THAII, L3_BLANK, L4_BLANK, M | _tdig },
+ /*0xF1*/ { L1_18, L2_THAII, L3_BLANK, L4_BLANK, M | _tdig },
+ /*0xF2*/ { L1_28, L2_THAII, L3_BLANK, L4_BLANK, M | _tdig },
+ /*0xF3*/ { L1_38, L2_THAII, L3_BLANK, L4_BLANK, M | _tdig },
+ /*0xF4*/ { L1_48, L2_THAII, L3_BLANK, L4_BLANK, M | _tdig },
+ /*0xF5*/ { L1_58, L2_THAII, L3_BLANK, L4_BLANK, M | _tdig },
+ /*0xF6*/ { L1_68, L2_THAII, L3_BLANK, L4_BLANK, M | _tdig },
+ /*0xF7*/ { L1_78, L2_THAII, L3_BLANK, L4_BLANK, M | _tdig },
+ /*0xF8*/ { L1_88, L2_THAII, L3_BLANK, L4_BLANK, M | _tdig },
+ /*0xF9*/ { L1_98, L2_THAII, L3_BLANK, L4_BLANK, M | _tdig },
+ /*0xFA*/ { IGNORE, IGNORE, L3_ANGKHANKHU, IGNORE, X },
+ /*0xFB*/ { IGNORE, IGNORE, L3_KHOMUT, IGNORE, X },
+ /*0xFC*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
+ /*0xFD*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
+ /*0xFE*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
+ /*0xFF*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
+};
+
+uchar NEAR ctype_tis620[257] =
+{
+ 0, /* For standard library */
+ 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,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+};
+
+uchar NEAR to_lower_tis620[]=
+{
+ '\000','\001','\002','\003','\004','\005','\006','\007',
+ '\010','\011','\012','\013','\014','\015','\016','\017',
+ '\020','\021','\022','\023','\024','\025','\026','\027',
+ '\030','\031','\032','\033','\034','\035','\036','\037',
+ ' ', '!', '"', '#', '$', '%', '&', '\'',
+ '(', ')', '*', '+', ',', '-', '.', '/',
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', ':', ';', '<', '=', '>', '?',
+ '@', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
+ 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
+ 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
+ 'x', 'y', 'z', '[', '\\', ']', '^', '_',
+ '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
+ 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
+ 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
+ 'x', 'y', 'z', '{', '|', '}', '~', '\177',
+ (uchar) '\200',(uchar) '\201',(uchar) '\202',(uchar) '\203',(uchar) '\204',(uchar) '\205',(uchar) '\206',(uchar) '\207',
+ (uchar) '\210',(uchar) '\211',(uchar) '\212',(uchar) '\213',(uchar) '\214',(uchar) '\215',(uchar) '\216',(uchar) '\217',
+ (uchar) '\220',(uchar) '\221',(uchar) '\222',(uchar) '\223',(uchar) '\224',(uchar) '\225',(uchar) '\226',(uchar) '\227',
+ (uchar) '\230',(uchar) '\231',(uchar) '\232',(uchar) '\233',(uchar) '\234',(uchar) '\235',(uchar) '\236',(uchar) '\237',
+ (uchar) '\240',(uchar) '\241',(uchar) '\242',(uchar) '\243',(uchar) '\244',(uchar) '\245',(uchar) '\246',(uchar) '\247',
+ (uchar) '\250',(uchar) '\251',(uchar) '\252',(uchar) '\253',(uchar) '\254',(uchar) '\255',(uchar) '\256',(uchar) '\257',
+ (uchar) '\260',(uchar) '\261',(uchar) '\262',(uchar) '\263',(uchar) '\264',(uchar) '\265',(uchar) '\266',(uchar) '\267',
+ (uchar) '\270',(uchar) '\271',(uchar) '\272',(uchar) '\273',(uchar) '\274',(uchar) '\275',(uchar) '\276',(uchar) '\277',
+ (uchar) '\300',(uchar) '\301',(uchar) '\302',(uchar) '\303',(uchar) '\304',(uchar) '\305',(uchar) '\306',(uchar) '\307',
+ (uchar) '\310',(uchar) '\311',(uchar) '\312',(uchar) '\313',(uchar) '\314',(uchar) '\315',(uchar) '\316',(uchar) '\317',
+ (uchar) '\320',(uchar) '\321',(uchar) '\322',(uchar) '\323',(uchar) '\324',(uchar) '\325',(uchar) '\326',(uchar) '\327',
+ (uchar) '\330',(uchar) '\331',(uchar) '\332',(uchar) '\333',(uchar) '\334',(uchar) '\335',(uchar) '\336',(uchar) '\337',
+ (uchar) '\340',(uchar) '\341',(uchar) '\342',(uchar) '\343',(uchar) '\344',(uchar) '\345',(uchar) '\346',(uchar) '\347',
+ (uchar) '\350',(uchar) '\351',(uchar) '\352',(uchar) '\353',(uchar) '\354',(uchar) '\355',(uchar) '\356',(uchar) '\357',
+ (uchar) '\360',(uchar) '\361',(uchar) '\362',(uchar) '\363',(uchar) '\364',(uchar) '\365',(uchar) '\366',(uchar) '\367',
+ (uchar) '\370',(uchar) '\371',(uchar) '\372',(uchar) '\373',(uchar) '\374',(uchar) '\375',(uchar) '\376',(uchar) '\377',
+};
+
+uchar NEAR to_upper_tis620[]=
+{
+ '\000','\001','\002','\003','\004','\005','\006','\007',
+ '\010','\011','\012','\013','\014','\015','\016','\017',
+ '\020','\021','\022','\023','\024','\025','\026','\027',
+ '\030','\031','\032','\033','\034','\035','\036','\037',
+ ' ', '!', '"', '#', '$', '%', '&', '\'',
+ '(', ')', '*', '+', ',', '-', '.', '/',
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', ':', ';', '<', '=', '>', '?',
+ '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+ 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+ 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+ 'X', 'Y', 'Z', '[', '\\', ']', '^', '_',
+ '`', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+ 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+ 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+ 'X', 'Y', 'Z', '{', '|', '}', '~', '\177',
+ (uchar) '\200',(uchar) '\201',(uchar) '\202',(uchar) '\203',(uchar) '\204',(uchar) '\205',(uchar) '\206',(uchar) '\207',
+ (uchar) '\210',(uchar) '\211',(uchar) '\212',(uchar) '\213',(uchar) '\214',(uchar) '\215',(uchar) '\216',(uchar) '\217',
+ (uchar) '\220',(uchar) '\221',(uchar) '\222',(uchar) '\223',(uchar) '\224',(uchar) '\225',(uchar) '\226',(uchar) '\227',
+ (uchar) '\230',(uchar) '\231',(uchar) '\232',(uchar) '\233',(uchar) '\234',(uchar) '\235',(uchar) '\236',(uchar) '\237',
+ (uchar) '\240',(uchar) '\241',(uchar) '\242',(uchar) '\243',(uchar) '\244',(uchar) '\245',(uchar) '\246',(uchar) '\247',
+ (uchar) '\250',(uchar) '\251',(uchar) '\252',(uchar) '\253',(uchar) '\254',(uchar) '\255',(uchar) '\256',(uchar) '\257',
+ (uchar) '\260',(uchar) '\261',(uchar) '\262',(uchar) '\263',(uchar) '\264',(uchar) '\265',(uchar) '\266',(uchar) '\267',
+ (uchar) '\270',(uchar) '\271',(uchar) '\272',(uchar) '\273',(uchar) '\274',(uchar) '\275',(uchar) '\276',(uchar) '\277',
+ (uchar) '\300',(uchar) '\301',(uchar) '\302',(uchar) '\303',(uchar) '\304',(uchar) '\305',(uchar) '\306',(uchar) '\307',
+ (uchar) '\310',(uchar) '\311',(uchar) '\312',(uchar) '\313',(uchar) '\314',(uchar) '\315',(uchar) '\316',(uchar) '\317',
+ (uchar) '\320',(uchar) '\321',(uchar) '\322',(uchar) '\323',(uchar) '\324',(uchar) '\325',(uchar) '\326',(uchar) '\327',
+ (uchar) '\330',(uchar) '\331',(uchar) '\332',(uchar) '\333',(uchar) '\334',(uchar) '\335',(uchar) '\336',(uchar) '\337',
+ (uchar) '\340',(uchar) '\341',(uchar) '\342',(uchar) '\343',(uchar) '\344',(uchar) '\345',(uchar) '\346',(uchar) '\347',
+ (uchar) '\350',(uchar) '\351',(uchar) '\352',(uchar) '\353',(uchar) '\354',(uchar) '\355',(uchar) '\356',(uchar) '\357',
+ (uchar) '\360',(uchar) '\361',(uchar) '\362',(uchar) '\363',(uchar) '\364',(uchar) '\365',(uchar) '\366',(uchar) '\367',
+ (uchar) '\370',(uchar) '\371',(uchar) '\372',(uchar) '\373',(uchar) '\374',(uchar) '\375',(uchar) '\376',(uchar) '\377',
+};
+
+uchar NEAR sort_order_tis620[]=
+{
+ '\000','\001','\002','\003','\004','\005','\006','\007',
+ '\010','\011','\012','\013','\014','\015','\016','\017',
+ '\020','\021','\022','\023','\024','\025','\026','\027',
+ '\030','\031','\032','\033','\034','\035','\036','\037',
+ ' ', '!', '"', '#', '$', '%', '&', '\'',
+ '(', ')', '*', '+', ',', '-', '.', '/',
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', ':', ';', '<', '=', '>', '?',
+ '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+ 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+ 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+ 'X', 'Y', 'Z', '\\', ']', '[', '^', '_',
+ 'E', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+ 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+ 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+ 'X', 'Y', 'Z', '{', '|', '}', 'Y', '\177',
+ (uchar) '\200',(uchar) '\201',(uchar) '\202',(uchar) '\203',(uchar) '\204',(uchar) '\205',(uchar) '\206',(uchar) '\207',
+ (uchar) '\210',(uchar) '\211',(uchar) '\212',(uchar) '\213',(uchar) '\214',(uchar) '\215',(uchar) '\216',(uchar) '\217',
+ (uchar) '\220',(uchar) '\221',(uchar) '\222',(uchar) '\223',(uchar) '\224',(uchar) '\225',(uchar) '\226',(uchar) '\227',
+ (uchar) '\230',(uchar) '\231',(uchar) '\232',(uchar) '\233',(uchar) '\234',(uchar) '\235',(uchar) '\236',(uchar) '\237',
+ (uchar) '\240',(uchar) '\241',(uchar) '\242',(uchar) '\243',(uchar) '\244',(uchar) '\245',(uchar) '\246',(uchar) '\247',
+ (uchar) '\250',(uchar) '\251',(uchar) '\252',(uchar) '\253',(uchar) '\254',(uchar) '\255',(uchar) '\256',(uchar) '\257',
+ (uchar) '\260',(uchar) '\261',(uchar) '\262',(uchar) '\263',(uchar) '\264',(uchar) '\265',(uchar) '\266',(uchar) '\267',
+ (uchar) '\270',(uchar) '\271',(uchar) '\272',(uchar) '\273',(uchar) '\274',(uchar) '\275',(uchar) '\276',(uchar) '\277',
+ (uchar) '\300',(uchar) '\301',(uchar) '\302',(uchar) '\303',(uchar) '\304',(uchar) '\305',(uchar) '\306',(uchar) '\307',
+ (uchar) '\310',(uchar) '\311',(uchar) '\312',(uchar) '\313',(uchar) '\314',(uchar) '\315',(uchar) '\316',(uchar) '\317',
+ (uchar) '\320',(uchar) '\321',(uchar) '\322',(uchar) '\323',(uchar) '\324',(uchar) '\325',(uchar) '\326',(uchar) '\327',
+ (uchar) '\330',(uchar) '\331',(uchar) '\332',(uchar) '\333',(uchar) '\334',(uchar) '\335',(uchar) '\336',(uchar) '\337',
+ (uchar) '\340',(uchar) '\341',(uchar) '\342',(uchar) '\343',(uchar) '\344',(uchar) '\345',(uchar) '\346',(uchar) '\347',
+ (uchar) '\350',(uchar) '\351',(uchar) '\352',(uchar) '\353',(uchar) '\354',(uchar) '\355',(uchar) '\356',(uchar) '\357',
+ (uchar) '\360',(uchar) '\361',(uchar) '\362',(uchar) '\363',(uchar) '\364',(uchar) '\365',(uchar) '\366',(uchar) '\367',
+ (uchar) '\370',(uchar) '\371',(uchar) '\372',(uchar) '\373',(uchar) '\374',(uchar) '\375',(uchar) '\376',(uchar) '\377',
+};
+
+/* Convert thai string to "Standard C String Function" sortable string
+ Arg: const source string and length of converted string
+ Ret: Sortable string
+*/
+
+static uchar* thai2sortable(const uchar * tstr,uint len)
+{
+ const uchar* p = tstr;
+ uchar *outBuf;
+ uchar *pRight1, *pRight2, *pRight3, *pRight4;
+ uchar *pLeft1, *pLeft2, *pLeft3, *pLeft4;
+ uint bufSize;
+
+ len = (uint) strnlen((char*) tstr,len);
+ bufSize = buffsize((char*) tstr);
+ if(!(pRight1 = (uchar *)malloc(sizeof(uchar) * bufSize))) {
+ return( (uchar*) tstr);
+ }
+ pLeft1 = pRight1;
+ outBuf = pRight1;
+ if(!(pRight2 = (uchar *)malloc(sizeof(uchar) * (len + 1)))) {
+ free(pRight1);
+ return((uchar*) tstr);
+ }
+ pLeft2 = pRight2;
+ if(!(pRight3 = (uchar *)malloc(sizeof(uchar) * (len + 1)))) {
+ free(pRight1);
+ free(pRight2);
+ return((uchar*) tstr);
+ }
+ pLeft3 = pRight3;
+ if(!(pRight4 = (uchar *)malloc(sizeof(uchar) * (len + 1)))) {
+ free(pRight1);
+ free(pRight2);
+ free(pRight3);
+ return((uchar*) tstr);
+ }
+ pLeft4 = pRight4;
+ while(len--) {
+ if(isldvowel(*p) && isconsnt(p[1])) {
+ *pRight1++ = t_ctype[p[1]][0];
+ *pRight2++ = t_ctype[p[1]][1];
+ *pRight3++ = t_ctype[p[1]][2];
+ *pRight4++ = t_ctype[p[1]][3];
+ *pRight1++ = t_ctype[*p][0];
+ *pRight2++ = t_ctype[*p][1];
+ *pRight3++ = t_ctype[*p][2];
+ *pRight4++ = t_ctype[*p][3];
+ len--;
+ p += 2;
+ } else {
+ *pRight1 = t_ctype[*p][0];
+ if(*pRight1 != IGNORE) pRight1++;
+ *pRight2 = t_ctype[*p][1];
+ if(*pRight2 != IGNORE) pRight2++;
+ *pRight3 = t_ctype[*p][2];
+ if(*pRight3 != IGNORE) pRight3++;
+ *pRight4 = t_ctype[*p][3];
+ if(*pRight4 != IGNORE) pRight4++;
+ p++;
+ }
+ }
+ *pRight1++ = L2_BLANK;
+ *pRight2++ = L3_BLANK;
+ *pRight3++ = L4_BLANK;
+ *pRight4++ = '\0';
+ memcpy(pRight1, pLeft2, pRight2 - pLeft2);
+ pRight1 += pRight2 - pLeft2;
+ memcpy(pRight1, pLeft3, pRight3 - pLeft3);
+ pRight1 += pRight3 - pLeft3;
+ memcpy(pRight1, pLeft4, pRight4 - pLeft4);
+ free(pLeft2);
+ free(pLeft3);
+ free(pLeft4);
+ return(outBuf);
+}
+
+/* strncoll() replacement, compare 2 string, both are conveted to sortable string
+ Arg: 2 Strings and it compare length
+ Ret: strcmp result
+*/
+int my_strnncoll_tis620(const uchar * s1, int len1, const uchar * s2, int len2)
+{
+ uchar *tc1, *tc2;
+ int i;
+ tc1 = thai2sortable(s1, len1);
+ tc2 = thai2sortable(s2, len2);
+ i = strcmp((char*)tc1, (char*)tc2);
+ free(tc1);
+ free(tc2);
+ return(i);
+}
+
+/* strnxfrm replacment, convert Thai string to sortable string
+ Arg: Destination buffer, source string, dest length and source length
+ Ret: Conveted string size
+*/
+int my_strnxfrm_tis620(uchar * dest, uchar * src, int len, int srclen)
+{
+ uint bufSize;
+ uchar *tmp;
+ bufSize = buffsize((char*)src);
+ tmp = thai2sortable(src,srclen);
+ set_if_smaller(bufSize,(uint) len);
+ memcpy((uchar *)dest, tmp, bufSize);
+ free(tmp);
+ return (int) bufSize;
+}
+
+/* strcoll replacment, compare 2 strings
+ Arg: 2 strings
+ Ret: strcmp result
+*/
+int my_strcoll_tis620(const uchar * s1, const uchar * s2)
+{
+ uchar *tc1, *tc2;
+ int i;
+ tc1 = thai2sortable(s1, (uint) strlen((char*)s1));
+ tc2 = thai2sortable(s2, (uint) strlen((char*)s2));
+ i = strcmp((char*)tc1, (char*)tc2);
+ free(tc1);
+ free(tc2);
+ return(i);
+}
+
+/* strxfrm replacment, convert Thai string to sortable string
+ Arg: Destination buffer, String and dest buffer size
+ Ret: Converting string size
+*/
+int my_strxfrm_tis620(uchar * dest, uchar * src, int len)
+{
+ uint bufSize;
+ uchar *tmp;
+
+ bufSize = buffsize((char*) src);
+ tmp = thai2sortable(src, len);
+ memcpy((uchar *) dest, tmp, bufSize);
+ free(tmp);
+ return bufSize;
+}
+
+/* Convert SQL like string to C string
+ Arg: String, its length, escape character, resource length, minimal string and maximum string
+ Ret: Alway 0
+*/
+my_bool my_like_range_tis620(const char *ptr, uint ptr_length, pchar escape,
+ uint res_length, char *min_str, char *max_str,
+ uint *min_length,uint *max_length)
+{
+ char *end;
+ char *min_org= min_str;
+ char *min_end = min_str + res_length;
+ char *tbuff;
+ uchar *tc;
+ uint tbuff_length;
+
+ tbuff = (char*) (tc=thai2sortable((uchar*) ptr, ptr_length));
+ tbuff_length = buffsize(ptr);
+ end = tbuff + tbuff_length;
+ for(;tbuff != end && min_str != min_end; tbuff++)
+ {
+ if(*tbuff == escape && tbuff + 1 != end)
+ {
+ tbuff++;
+ *min_str++ = *max_str++ = *tbuff;
+ continue;
+ }
+ if(*tbuff == '_')
+ {
+ *min_str++ = '\0';
+ *max_str++ = '\255';
+ continue;
+ }
+ if(*tbuff == '%')
+ {
+ *min_length= (uint) (min_str - min_org);
+ *max_length= res_length;
+ do
+ {
+ *min_str++ = ' ';
+ *max_str++ = '\255';
+ } while(min_str != min_end);
+ free(tc);
+ return(0);
+ }
+ *min_str++ = *max_str++ = *tbuff;
+ }
+ *min_length= *max_length = (uint) (min_str - min_org);
+ while(min_str != min_end)
+ {
+ *min_str++ = *max_str++ = ' ';
+ }
+ free(tc);
+ return(0);
+}
+
+/* Thai normalization for input sub system
+ Arg: Buffer, 's length, String, 'length
+ Ret: Void
+*/
+void ThNormalize(uchar* ptr, uint field_length, const uchar* from, uint length)
+{
+ const uchar* fr = from;
+ uchar* p = ptr;
+
+ if(length > field_length) {
+ length = field_length;
+ }
+ while (length--)
+ {
+ if((istone(*fr) || isdiacrt1(*fr)) &&
+ (islwrvowel(fr[1]) || isuprvowel(fr[1])))
+ {
+ *p = fr[1];
+ p[1] = *fr;
+ fr += 2;
+ p += 2;
+ length--;
+ }
+ else
+ {
+ *p++ = *fr++;
+ }
+ }
+}
diff --git a/strings/ctype-ujis.c b/strings/ctype-ujis.c
new file mode 100644
index 00000000000..a29a61bf2c0
--- /dev/null
+++ b/strings/ctype-ujis.c
@@ -0,0 +1,183 @@
+/* This file is for Japanese EUC charset, and created by tommy@valley.ne.jp.
+ */
+
+/*
+ * This comment is parsed by configure to create ctype.c,
+ * so don't change it unless you know what you are doing.
+ *
+ * .configure. mbmaxlen_ujis=3
+ */
+
+#include <global.h>
+#include "m_string.h"
+
+uchar NEAR ctype_ujis[257] =
+{
+ 0, /* For standard library */
+ 0040, 0040, 0040, 0040, 0040, 0040, 0040, 0040, /* NUL ^A - ^G */
+ 0040, 0050, 0050, 0050, 0050, 0050, 0040, 0040, /* ^H - ^O */
+ 0040, 0040, 0040, 0040, 0040, 0040, 0040, 0040, /* ^P - ^W */
+ 0040, 0040, 0040, 0040, 0040, 0040, 0040, 0040, /* ^X - ^Z ^[ ^\ ^] ^^ ^_ */
+ 0110, 0020, 0020, 0020, 0020, 0020, 0020, 0020, /* SPC ! " # $ % ^ ' */
+ 0020, 0020, 0020, 0020, 0020, 0020, 0020, 0020, /* ( ) * + , - . / */
+ 0204, 0204, 0204, 0204, 0204, 0204, 0204, 0204, /* 0 1 2 3 4 5 6 7 */
+ 0204, 0204, 0020, 0020, 0020, 0020, 0020, 0020, /* 8 9 : ; < = > ? */
+ 0020, 0201, 0201, 0201, 0201, 0201, 0201, 0001, /* @ A B C D E F G */
+ 0001, 0001, 0001, 0001, 0001, 0001, 0001, 0001, /* H I J K L M N O */
+ 0001, 0001, 0001, 0001, 0001, 0001, 0001, 0001, /* P Q R S T U V W */
+ 0001, 0001, 0001, 0020, 0020, 0020, 0020, 0020, /* X Y Z [ \ ] ^ _ */
+ 0020, 0202, 0202, 0202, 0202, 0202, 0202, 0002, /* ` a b c d e f g */
+ 0002, 0002, 0002, 0002, 0002, 0002, 0002, 0002, /* h i j k l m n o */
+ 0002, 0002, 0002, 0002, 0002, 0002, 0002, 0002, /* p q r s t u v w */
+ 0002, 0002, 0002, 0020, 0020, 0020, 0020, 0040, /* x y z { | } + DEL */
+ 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000,
+ 0000, 0000, 0000, 0000, 0000, 0000, 0020, 0020,
+ 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000,
+ 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000,
+ 0000, 0020, 0020, 0020, 0020, 0020, 0020, 0020,
+ 0020, 0020, 0020, 0020, 0020, 0020, 0020, 0020,
+ 0020, 0020, 0020, 0020, 0020, 0020, 0020, 0020,
+ 0020, 0020, 0020, 0020, 0020, 0020, 0020, 0020,
+ 0020, 0020, 0020, 0020, 0020, 0020, 0020, 0020,
+ 0020, 0020, 0020, 0020, 0020, 0020, 0020, 0020,
+ 0020, 0020, 0020, 0020, 0020, 0020, 0020, 0020,
+ 0020, 0020, 0020, 0020, 0020, 0020, 0020, 0020,
+ 0020, 0020, 0020, 0020, 0020, 0020, 0020, 0020,
+ 0020, 0020, 0020, 0020, 0020, 0020, 0020, 0020,
+ 0020, 0020, 0020, 0020, 0020, 0020, 0020, 0020,
+ 0020, 0020, 0020, 0020, 0020, 0020, 0020, 0000,
+};
+
+uchar NEAR to_lower_ujis[]=
+{
+ '\000','\001','\002','\003','\004','\005','\006','\007',
+ '\010','\011','\012','\013','\014','\015','\016','\017',
+ '\020','\021','\022','\023','\024','\025','\026','\027',
+ '\030','\031','\032','\033','\034','\035','\036','\037',
+ ' ', '!', '"', '#', '$', '%', '&', '\'',
+ '(', ')', '*', '+', ',', '-', '.', '/',
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', ':', ';', '<', '=', '>', '?',
+ '@', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
+ 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
+ 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
+ 'x', 'y', 'z', '[', '\\', ']', '^', '_',
+ '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
+ 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
+ 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
+ 'x', 'y', 'z', '{', '|', '}', '~', '\177',
+ '\200','\201','\202','\203','\204','\205','\206','\207',
+ '\210','\211','\212','\213','\214','\215','\216','\217',
+ '\220','\221','\222','\223','\224','\225','\226','\227',
+ '\230','\231','\232','\233','\234','\235','\236','\237',
+ '\240','\241','\242','\243','\244','\245','\246','\247',
+ '\250','\251','\252','\253','\254','\255','\256','\257',
+ '\260','\261','\262','\263','\264','\265','\266','\267',
+ '\270','\271','\272','\273','\274','\275','\276','\277',
+ '\300','\301','\302','\303','\304','\305','\306','\307',
+ '\310','\311','\312','\313','\314','\315','\316','\317',
+ '\320','\321','\322','\323','\324','\325','\326','\327',
+ '\330','\331','\332','\333','\334','\335','\336','\337',
+ '\340','\341','\342','\343','\344','\345','\346','\347',
+ '\350','\351','\352','\353','\354','\355','\356','\357',
+ '\360','\361','\362','\363','\364','\365','\366','\367',
+ '\370','\371','\372','\373','\374','\375','\376','\377',
+};
+
+uchar NEAR to_upper_ujis[]=
+{
+ '\000','\001','\002','\003','\004','\005','\006','\007',
+ '\010','\011','\012','\013','\014','\015','\016','\017',
+ '\020','\021','\022','\023','\024','\025','\026','\027',
+ '\030','\031','\032','\033','\034','\035','\036','\037',
+ ' ', '!', '"', '#', '$', '%', '&', '\'',
+ '(', ')', '*', '+', ',', '-', '.', '/',
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', ':', ';', '<', '=', '>', '?',
+ '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+ 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+ 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+ 'X', 'Y', 'Z', '[', '\\', ']', '^', '_',
+ '`', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+ 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+ 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+ 'X', 'Y', 'Z', '{', '|', '}', '~', '\177',
+ '\200','\201','\202','\203','\204','\205','\206','\207',
+ '\210','\211','\212','\213','\214','\215','\216','\217',
+ '\220','\221','\222','\223','\224','\225','\226','\227',
+ '\230','\231','\232','\233','\234','\235','\236','\237',
+ '\240','\241','\242','\243','\244','\245','\246','\247',
+ '\250','\251','\252','\253','\254','\255','\256','\257',
+ '\260','\261','\262','\263','\264','\265','\266','\267',
+ '\270','\271','\272','\273','\274','\275','\276','\277',
+ '\300','\301','\302','\303','\304','\305','\306','\307',
+ '\310','\311','\312','\313','\314','\315','\316','\317',
+ '\320','\321','\322','\323','\324','\325','\326','\327',
+ '\330','\331','\332','\333','\334','\335','\336','\337',
+ '\340','\341','\342','\343','\344','\345','\346','\347',
+ '\350','\351','\352','\353','\354','\355','\356','\357',
+ '\360','\361','\362','\363','\364','\365','\366','\367',
+ '\370','\371','\372','\373','\374','\375','\376','\377',
+};
+
+uchar NEAR sort_order_ujis[]=
+{
+ '\000','\001','\002','\003','\004','\005','\006','\007',
+ '\010','\011','\012','\013','\014','\015','\016','\017',
+ '\020','\021','\022','\023','\024','\025','\026','\027',
+ '\030','\031','\032','\033','\034','\035','\036','\037',
+ ' ', '!', '"', '#', '$', '%', '&', '\'',
+ '(', ')', '*', '+', ',', '-', '.', '/',
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', ':', ';', '<', '=', '>', '?',
+ '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+ 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+ 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+ 'X', 'Y', 'Z', '[', '\\', ']', '^', '_',
+ '`', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+ 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+ 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+ 'X', 'Y', 'Z', '{', '|', '}', '~', '\177',
+ '\200','\201','\202','\203','\204','\205','\206','\207',
+ '\210','\211','\212','\213','\214','\215','\216','\217',
+ '\220','\221','\222','\223','\224','\225','\226','\227',
+ '\230','\231','\232','\233','\234','\235','\236','\237',
+ '\240','\241','\242','\243','\244','\245','\246','\247',
+ '\250','\251','\252','\253','\254','\255','\256','\257',
+ '\260','\261','\262','\263','\264','\265','\266','\267',
+ '\270','\271','\272','\273','\274','\275','\276','\277',
+ '\300','\301','\302','\303','\304','\305','\306','\307',
+ '\310','\311','\312','\313','\314','\315','\316','\317',
+ '\320','\321','\322','\323','\324','\325','\326','\327',
+ '\330','\331','\332','\333','\334','\335','\336','\337',
+ '\340','\341','\342','\343','\344','\345','\346','\347',
+ '\350','\351','\352','\353','\354','\355','\356','\357',
+ '\360','\361','\362','\363','\364','\365','\366','\367',
+ '\370','\371','\372','\373','\374','\375','\376','\377',
+};
+
+
+#define isujis(c) ((0xa1<=((c)&0xff) && ((c)&0xff)<=0xfe))
+#define iskata(c) ((0xa1<=((c)&0xff) && ((c)&0xff)<=0xdf))
+#define isujis_ss2(c) (((c)&0xff) == 0x8e)
+#define isujis_ss3(c) (((c)&0xff) == 0x8f)
+
+
+int ismbchar_ujis(const char* p, const char *e)
+{
+ return ((*(uchar*)(p)<0x80)? 0:\
+ isujis(*(p)) && (e)-(p)>1 && isujis(*((p)+1))? 2:\
+ isujis_ss2(*(p)) && (e)-(p)>1 && iskata(*((p)+1))? 2:\
+ isujis_ss3(*(p)) && (e)-(p)>2 && isujis(*((p)+1)) && isujis(*((p)+2))? 3:\
+ 0);
+}
+
+my_bool ismbhead_ujis(uint c)
+{
+ return (isujis(c) || isujis_ss2(c) || isujis_ss3(c));
+}
+
+int mbcharlen_ujis(uint c)
+{
+ return (isujis(c)? 2: isujis_ss2(c)? 2: isujis_ss3(c)? 3: 0);
+}
diff --git a/strings/ctype.c b/strings/ctype.c
new file mode 100644
index 00000000000..16b652d42f1
--- /dev/null
+++ b/strings/ctype.c
@@ -0,0 +1,68 @@
+/* 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>
+
+#include <m_ctype.h>
+
+/* generated by make, using conf_to_src */
+#include "ctype_extra_sources.c"
+
+/* generated by configure */
+#include "ctype_autoconf.c"
+
+CHARSET_INFO *default_charset_info = &compiled_charsets[0];
+
+CHARSET_INFO *find_compiled_charset(uint cs_number)
+{
+ CHARSET_INFO *cs;
+ for (cs = compiled_charsets; cs->number > 0; cs++)
+ if (cs->number == cs_number)
+ return cs;
+
+ return NULL;
+}
+
+CHARSET_INFO *find_compiled_charset_by_name(const char *name)
+{
+ CHARSET_INFO *cs;
+ for (cs = compiled_charsets; cs->number > 0; cs++)
+ if (!strcmp(cs->name, name))
+ return cs;
+
+ return NULL;
+}
+
+uint8 compiled_charset_number(const char *name)
+{
+ CHARSET_INFO *cs;
+ for (cs = compiled_charsets; cs->number > 0; cs++)
+ if (!strcmp(cs->name, name))
+ return cs->number;
+
+ return 0; /* this mimics find_type() */
+}
+
+const char *compiled_charset_name(uint8 charset_number)
+{
+ CHARSET_INFO *cs;
+ for (cs = compiled_charsets; cs->number > 0; cs++)
+ if (cs->number == charset_number)
+ return cs->name;
+
+ return "?"; /* this mimics get_type() */
+}
diff --git a/strings/do_ctype.c b/strings/do_ctype.c
new file mode 100644
index 00000000000..e05926bf8d3
--- /dev/null
+++ b/strings/do_ctype.c
@@ -0,0 +1,200 @@
+/* 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 */
+
+/* Prints case-convert and sort-convert tabell on stdout. This is used to
+ make _ctype.c easyer */
+
+#ifdef DBUG_OFF
+#undef DBUG_OFF
+#endif
+
+#include <global.h>
+#include <ctype.h>
+#include <my_sys.h>
+#include "m_string.h"
+
+uchar NEAR to_upper[256];
+uchar NEAR to_lower[256],NEAR sort_order[256];
+
+static int ascii_output=1;
+static string tab_names[]={ "to_lower[]={","to_upper[]={","sort_order[]={" };
+static uchar* tabell[]= {to_lower,to_upper,sort_order};
+
+void get_options(),init_case_convert();
+
+main(argc,argv)
+int argc;
+char *argv[];
+{
+ int i,j,ch;
+ DBUG_ENTER ("main");
+ DBUG_PROCESS (argv[0]);
+
+ get_options(&argc,&argv);
+ init_case_convert();
+ puts("Tabells for caseconverts and sorttest of characters\n");
+ for (i=0 ; i < 3 ; i++)
+ {
+ printf("uchar NEAR %s\n",tab_names[i]);
+ for (j=0 ; j <= 255 ; j++)
+ {
+ ch=(int) tabell[i][j];
+ if (ascii_output && isprint(ch) && ! (ch & 128))
+ {
+ if (strchr("\\'",(char) ch))
+ printf("'\\%c', ",ch);
+ else
+ printf("'%c', ",ch);
+ }
+ else
+ printf("'\\%03o',",ch);
+ if ((j+1 & 7) == 0)
+ puts("");
+ }
+ puts("};\n");
+ }
+ DBUG_RETURN(0);
+} /* main */
+
+ /* Read options */
+
+void get_options(argc,argv)
+register int *argc;
+register char **argv[];
+{
+ int help,version;
+ char *pos,*progname;
+
+ progname= (*argv)[0];
+ help=0; ascii_output=1;
+ while (--*argc >0 && *(pos = *(++*argv)) == '-' )
+ {
+ while (*++pos)
+ {
+ version=0;
+ switch(*pos) {
+ case 'n': /* Numeric output */
+ ascii_output=0;
+ break;
+ case '#':
+ DBUG_PUSH (++pos);
+ *(pos--) = '\0'; /* Skippa argument */
+ break;
+ case 'V':
+ version=1;
+ case 'I':
+ case '?':
+ printf("%s Ver 1.0\n",progname);
+ if (version)
+ break;
+ puts("Output tabells of to_lower[], to_upper[] and sortorder[]\n");
+ printf("Usage: %s [-n?I]\n",progname);
+ puts("Options: -? or -I \"Info\" -n \"numeric output\"");
+ break;
+ default:
+ fprintf(stderr,"illegal option: -%c\n",*pos);
+ break;
+ }
+ }
+ }
+ return;
+} /* get_options */
+
+
+ /* set up max character for which isupper() and toupper() gives */
+ /* right answer. Is usually 127 or 255 */
+
+#ifdef USE_INTERNAL_CTYPE
+#define MAX_CHAR_OK CHAR_MAX /* All chars is right */
+#else
+#define MAX_CHAR_OK 127 /* 7 Bit ascii */
+#endif
+
+ /* Initiate arrays for case-conversation */
+
+void init_case_convert()
+{
+ reg1 int16 i;
+ reg2 uchar *higher_pos,*lower_pos;
+ DBUG_ENTER("init_case_convert");
+
+ for (i=0 ; i <= MAX_CHAR_OK ; i++)
+ {
+ to_upper[i]= sort_order[i]= (islower(i) ? toupper(i) : (char) i);
+ to_lower[i]= (isupper(i) ? tolower(i) : (char) i);
+ }
+#if MAX_CHAR_OK != 255
+ for (i--; i++ < 255 ;)
+ to_upper[i]= sort_order[i]= to_lower[i]= (char) i;
+#endif
+
+#ifdef MSDOS
+ higher_pos= (uchar * ) "\217\216\231\232\220"; /* Extra chars to konv. */
+ lower_pos= (uchar * ) "\206\204\224\201\202";
+#else
+#if defined(HPUX) && ASCII_BITS_USED == 8
+ higher_pos= (uchar * ) "\xd0\xd8\xda\xdb\xdc\xd3";
+ lower_pos= (uchar * ) "\xd4\xcc\xce\xdf\xc9\xd7";
+#else
+#ifdef USE_INTERNAL_CTYPE
+ higher_pos=lower_pos= (uchar* ) ""; /* System converts chars */
+#else
+#if defined(DEC_MULTINATIONAL_CHAR) || defined(HP_MULTINATIONAL_CHAR)
+ higher_pos= (uchar * ) "\305\304\326\311\334";
+ lower_pos= (uchar * ) "\345\344\366\351\374";
+#else
+ higher_pos= (uchar * ) "[]\\@^";
+ lower_pos= (uchar * ) "{}|`~";
+#endif
+#endif /* USE_INTERNAL_CTYPE */
+#endif /* HPUX */
+#endif /* MSDOS */
+
+ while (*higher_pos)
+ {
+ to_upper[ *lower_pos ] = sort_order[ *lower_pos ] = (char) *higher_pos;
+ to_lower[ *higher_pos++ ] = (char) *lower_pos++;
+ }
+
+ /* sets upp sortorder; higer_pos character (upper and lower) is */
+ /* changed to lower_pos character */
+
+#ifdef MSDOS
+ higher_pos= (uchar *) "\217\216\231\232\220";
+ lower_pos= (uchar *) "\216\217\231YE";
+#else
+#if defined(HPUX) && ASCII_BITS_USED == 8
+ higher_pos= lower_pos= (uchar *) ""; /* Tecknen i r{tt ordning */
+#else
+#ifdef USE_ISO_8859_1 /* As in USG5 ICL-386 */
+ higher_pos= (uchar *) "\305\304\326\334\311";
+ lower_pos= (uchar *) "\304\305\326YE";
+#else
+ higher_pos= (uchar *) "][\\~`"; /* R{tt ordning p} tecknen */
+ lower_pos= (uchar *) "[\\]YE"; /* Ordning enligt ascii */
+#endif /* USE_ISO_8859_1 */
+#endif /* HPUX */
+#endif /* MSDOS */
+
+ while (*higher_pos)
+ {
+ sort_order[ *higher_pos ] =
+ sort_order[(uchar)to_lower[*higher_pos]] = *lower_pos;
+ higher_pos++; lower_pos++;
+ }
+ DBUG_VOID_RETURN;
+} /* init_case_convert */
diff --git a/strings/int2str.c b/strings/int2str.c
new file mode 100644
index 00000000000..4003e8a6167
--- /dev/null
+++ b/strings/int2str.c
@@ -0,0 +1,155 @@
+/* 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 */
+
+/*
+ Defines: int2str(), itoa(), ltoa()
+
+ int2str(dst, radix, val)
+ converts the (long) integer "val" to character form and moves it to
+ the destination string "dst" followed by a terminating NUL. The
+ result is normally a pointer to this NUL character, but if the radix
+ is dud the result will be NullS and nothing will be changed.
+
+ If radix is -2..-36, val is taken to be SIGNED.
+ If radix is 2.. 36, val is taken to be UNSIGNED.
+ That is, val is signed if and only if radix is. You will normally
+ use radix -10 only through itoa and ltoa, for radix 2, 8, or 16
+ unsigned is what you generally want.
+
+ _dig_vec is public just in case someone has a use for it.
+ The definitions of itoa and ltoa are actually macros in m_string.h,
+ but this is where the code is.
+
+ Note: The standard itoa() returns a pointer to the argument, when int2str
+ returns the pointer to the end-null.
+ itoa assumes that 10 -base numbers are allways signed and other arn't.
+*/
+
+#include <global.h>
+#include "m_string.h"
+
+char NEAR _dig_vec[] =
+ "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+
+
+char *int2str(register long int val, register char *dst, register int radix)
+{
+ char buffer[65];
+ register char *p;
+ long int new_val;
+
+ if (radix < 0) {
+ if (radix < -36 || radix > -2) return NullS;
+ if (val < 0) {
+ *dst++ = '-';
+ val = -val;
+ }
+ radix = -radix;
+ } else {
+ if (radix > 36 || radix < 2) return NullS;
+ }
+ /* The slightly contorted code which follows is due to the
+ fact that few machines directly support unsigned long / and %.
+ Certainly the VAX C compiler generates a subroutine call. In
+ the interests of efficiency (hollow laugh) I let this happen
+ for the first digit only; after that "val" will be in range so
+ that signed integer division will do. Sorry 'bout that.
+ CHECK THE CODE PRODUCED BY YOUR C COMPILER. The first % and /
+ should be unsigned, the second % and / signed, but C compilers
+ tend to be extraordinarily sensitive to minor details of style.
+ This works on a VAX, that's all I claim for it.
+ */
+ p = &buffer[sizeof(buffer)-1];
+ *p = '\0';
+ new_val=(ulong) val / (ulong) radix;
+ *--p = _dig_vec[(uchar) ((ulong) val- (ulong) new_val*(ulong) radix)];
+ val = new_val;
+#ifdef HAVE_LDIV
+ while (val != 0)
+ {
+ ldiv_t res;
+ res=ldiv(val,radix);
+ *--p = _dig_vec[res.rem];
+ val= res.quot;
+ }
+#else
+ while (val != 0)
+ {
+ new_val=val/radix;
+ *--p = _dig_vec[(uchar) (val-new_val*radix)];
+ val= new_val;
+ }
+#endif
+ while ((*dst++ = *p++) != 0) ;
+ return dst-1;
+}
+
+
+/*
+ This is a faster version of the above optimized for the normal case of
+ radix 10 / -10
+*/
+
+char *int10_to_str(long int val,char *dst,int radix)
+{
+ char buffer[65];
+ register char *p;
+ long int new_val;
+
+ if (radix < 0) /* -10 */
+ {
+ if (val < 0)
+ {
+ *dst++ = '-';
+ val = -val;
+ }
+ }
+
+ p = &buffer[sizeof(buffer)-1];
+ *p = '\0';
+ new_val= (long) ((unsigned long int) val / 10);
+ *--p = '0'+ (char) ((unsigned long int) val - (unsigned long) new_val * 10);
+ val = new_val;
+
+ while (val != 0)
+ {
+ new_val=val/10;
+ *--p = '0' + (char) (val-new_val*10);
+ val= new_val;
+ }
+ while ((*dst++ = *p++) != 0) ;
+ return dst-1;
+}
+
+
+#ifdef USE_MY_ITOA
+
+ /* Change to less general itoa interface */
+
+char *my_itoa(int val, char *dst, int radix)
+{
+ VOID(int2str((long) val,dst,(radix == 10 ? -10 : radix)));
+ return dst;
+}
+
+char *my_ltoa(long int val, char *dst, int radix)
+{
+ VOID(int2str((long) val,dst,(radix == 10 ? -10 : radix)));
+ return dst;
+}
+
+#endif
diff --git a/strings/is_prefix.c b/strings/is_prefix.c
new file mode 100644
index 00000000000..d3f2b148de2
--- /dev/null
+++ b/strings/is_prefix.c
@@ -0,0 +1,34 @@
+/* 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 */
+
+/* File : is_prefix.c
+ Author : Michael Widenius
+ Defines: is_prefix()
+
+ is_prefix(s, t) returns 1 if s starts with t.
+ A empty t is allways a prefix.
+*/
+
+#include <global.h>
+#include "m_string.h"
+
+int is_prefix(register const char *s, register const char *t)
+{
+ while (*t)
+ if (*s++ != *t++) return 0;
+ return 1; /* WRONG */
+}
diff --git a/strings/latin2.def b/strings/latin2.def
new file mode 100644
index 00000000000..159d01894f3
--- /dev/null
+++ b/strings/latin2.def
@@ -0,0 +1,478 @@
+; Character code definition file for latin2 languages (for use with cset)
+; it's written for Czech, but may be used generally; works
+; minimum for Slovenian alphabet too (or at least I hope so)
+;
+; Written by Jaromir Dolecek <dolecek@ics.muni.cz>
+;
+; Notes of defined sorting order:
+; Upper/Lower case is ignored
+; All characters with the accents are sorted after appropriate
+; character without accent in order:
+; Xacute, Xring , Xcaron, Xslash, Xcedilla, Xogonek, Xcircumflex,
+; Xbreve, Xhungarumlaut, Xdieresis, Xdotaccent
+;
+latin2
+***
+NUL 0 C
+SOH C
+STX C
+ETX C
+EOT C
+ENQ C
+ACK C
+BEL C
+BS C
+HT CS
+LF CS
+VT CS
+FF CS
+CR CS
+SO C
+SI C
+DLE C
+DC1 C
+DC2 C
+DC3 C
+DC4 C
+NAK C
+SYN C
+ETB C
+CAN C
+EM C
+SUB C
+ESC C
+FS C
+GS C
+RS C
+US C
+/space BS
+/exclam P
+/quotedbl P
+/numbersign P
+/dollar P
+/percent P
+/ampersand P
+/quoteright P
+/parenleft P
+/parenright P
+/asterisk P
+/plus P
+/comma P
+/minus P
+/period P
+/slash P
+/zero NX
+/one NX
+/two NX
+/three NX
+/four NX
+/five NX
+/six NX
+/seven NX
+/eight NX
+/nine NX
+/colon P
+/semicolon P
+/less P
+/equal P
+/greater P
+/question P
+/at P
+/A UX
+/B UX
+/C UX
+/D UX
+/E UX
+/F UX
+/G U
+/H U
+/I U
+/J U
+/K U
+/L U
+/M U
+/N U
+/O U
+/P U
+/Q U
+/R U
+/S U
+/T U
+/U U
+/V U
+/W U
+/X U
+/Y U
+/Z U
+/bracketleft P
+/backslash P
+/bracketright P
+/asciicircum P
+/underscore P
+/quoteleft P
+/a LX
+/b LX
+/c LX
+/d LX
+/e LX
+/f LX
+/g L
+/h L
+/i L
+/j L
+/k L
+/l L
+/m L
+/n L
+/o L
+/p L
+/q L
+/r L
+/s L
+/t L
+/u L
+/v L
+/w L
+/x L
+/y L
+/z L
+/braceleft P
+/bar P
+/braceright P
+/tilde P
+NUL_ C
+SOH_ C
+STX_ C
+ETX_ C
+EOT_ C
+ENQ_ C
+ACK_ C
+BEL_ C
+BS_ C
+HT_ CS
+LF_ CS
+VT_ CS
+FF_ CS
+CR_ CS
+SO_ C
+SI_ C
+DLE_ C
+DC1_ C
+DC2_ C
+DC3_ C
+DC4_ C
+NAK_ C
+SYN_ C
+ETB_ C
+CAN_ C
+EM_ C
+SUB_ C
+ESC_ C
+FS_ C
+GS_ C
+RS_ C
+US_ C
+/space_ SB
+/Aogonek U
+/breve P
+/Lslash U
+/currency P
+/Lcaron U
+/Sacute U
+/dieresis P
+/Scaron 169 U
+/Scedilla U
+/Tcaron U
+/Zacute U
+/hyphen P
+/Zcaron U
+/Zdotaccent U
+/degree P
+/aogonek L
+/ogonek P
+/lslash L
+/acute P
+/lcaron L
+/sacute L
+/caron P
+/cedilla P
+/scaron L
+/scedilla L
+/tcaron L
+/zacute L
+/hungarumlaut P
+/zcaron L
+/zdotaccent L
+/Racute U
+/Aacute U
+/Acircumflex U
+/Abreve U
+/Adieresis U
+/Lacute U
+/Cacute U
+/Ccedilla U
+/Ccaron U
+/Eacute U
+/Eogonek U
+/Edieresis U
+/Ecaron U
+/Iacute U
+/Icircumflex U
+/Dcaron U
+/Eth P
+/Nacute U
+/Ncaron U
+/Oacute U
+/Ocircumflex U
+/Ohungarumlaut U
+/Odieresis U
+/multiply P
+/Rcaron U
+/Uring U
+/Uacute U
+/Uhungarumlaut U
+/Udieresis U
+/Yacute U
+/Tcedilla U
+/germandbls P
+/racute L
+/aacute L
+/acircumflex L
+/abreve L
+/adieresis L
+/lacute L
+/cacute L
+/ccedilla L
+/ccaron L
+/eacute L
+/eogonek L
+/edieresis L
+/ecaron L
+/iacute L
+/icircumflex L
+/dcaron L
+/dbar L
+/nacute L
+/ncaron L
+/oacute L
+/ocircumflex L
+/ohungarumlaut L
+/odieresis L
+/divide P
+/rcaron L
+/uring L
+/uacute L
+/uhungarumlaut L
+/udieresis L
+/yacute L
+/tcedilla L
+/dotaccent P
+***
+/A /a
+/B /b
+/C /c
+/D /d
+/E /e
+/F /f
+/G /g
+/H /h
+/I /i
+/J /j
+/K /k
+/L /l
+/M /m
+/N /n
+/O /o
+/P /p
+/Q /q
+/R /r
+/S /s
+/T /t
+/U /u
+/V /v
+/W /w
+/X /x
+/Y /y
+/Z /z
+/Aogonek /aogonek
+/Lslash /lslash
+/Lcaron /lcaron
+/Sacute /sacute
+/Scaron /scaron
+/Scedilla /scedilla
+/Tcaron /tcaron
+/Zacute /zacute
+/Zcaron /zcaron
+/Zdotaccent /zdotaccent
+/Racute /racute
+/Aacute /aacute
+/Acircumflex /acircumflex
+/Abreve /abreve
+/Adieresis /adieresis
+/Lacute /lacute
+/Cacute /cacute
+/Ccedilla /ccedilla
+/Ccaron /ccaron
+/Eacute /eacute
+/Eogonek /eogonek
+/Edieresis /edieresis
+/Ecaron /ecaron
+/Iacute /iacute
+/Icircumflex /icircumflex
+/Dcaron /dcaron
+/Nacute /nacute
+/Ncaron /ncaron
+/Oacute /oacute
+/Ocircumflex /ocircumflex
+/Ohungarumlaut /ohungarumlaut
+/Odieresis /odieresis
+/Rcaron /rcaron
+/Uring /uring
+/Uacute /uacute
+/Uhungarumlaut /uhungarumlaut
+/Udieresis /udieresis
+/Yacute /yacute
+/Tcedilla /tcedilla
+***
+NUL NUL_
+SOH SOH_
+STX STX_
+ETX ETX_
+EOT EOT_
+ENQ ENQ_
+ACK ACK_
+BEL BEL_
+BS BS_
+HT HT_
+LF LF_
+VT VT_
+FF FF_
+CR CR_
+SO SO_
+SI SI_
+DLE DLE_
+DC1 DC1_
+DC2 DC2_
+DC3 DC3_
+DC4 DC4_
+NAK NAK_
+SYN SYN_
+ETB ETB_
+CAN CAN_
+EM EM_
+SUB SUB_
+ESC ESC_
+FS FS_
+GS GS_
+RS RS_
+US US_
+/space
+/exclam
+/quotedbl
+/numbersign
+/dollar
+/percent
+/ampersand
+/quoteright
+/parenleft
+/parenright
+/asterisk
+/plus
+/comma
+/minus
+/period
+/slash
+/zero
+/one
+/two
+/three
+/four
+/five
+/six
+/seven
+/eight
+/nine
+/colon
+/semicolon
+/less
+/equal
+/greater
+/question
+/at
+/A /a
+/Aogonek /aogonek
+/Aacute /aacute
+/Acircumflex /acircumflex
+/Abreve /abreve
+/Adieresis /adieresis
+/B /b
+/C /c
+/Cacute /cacute
+/Ccaron /ccaron
+/Ccedilla /ccedilla
+/D /d
+/Dcaron /dcaron
+/E /e
+/Eacute /eacute
+/Ecaron /ecaron
+/Eogonek /eogonek
+/Edieresis /edieresis
+/F /f
+/G /g
+/H /h
+/I /i
+/Icircumflex
+/icircumflex
+/Iacute /iacute
+/J /j
+/K /k
+/L /l
+/Lslash /lslash
+/Lcaron /lcaron
+/Lacute /lacute
+/M /m
+/N /n
+/Nacute /nacute
+/Ncaron /ncaron
+/O /o
+/Oacute /oacute
+/Ocircumflex /ocircumflex
+/Ohungarumlaut /ohungarumlaut
+/Odieresis /odieresis
+/P /p
+/Q /q
+/R /r
+/Racute /racute
+/Rcaron /rcaron
+/S /s
+/Sacute /sacute
+/Scaron /scaron
+/Scedilla /scedilla
+/T /t
+/Tcaron /tcaron
+/Tcedilla /tcedilla
+/U /u
+/Uacute /uacute
+/Uring /uring
+/Uhungarumlaut /uhungarumlaut
+/Udieresis /udieresis
+/V /v
+/W /w
+/X /x
+/Y /y
+/Yacute /yacute
+/Z /z
+/Zacute /zacute
+/Zcaron /zcaron
+/Zdotaccent /zdotaccent
+/bracketleft
+/backslash
+/bracketright
+/asciicircum
+/underscore
+/quoteleft
+/braceleft
+/bar
+/braceright
+/tilde
+***
diff --git a/strings/llstr.c b/strings/llstr.c
new file mode 100644
index 00000000000..a8514d7e369
--- /dev/null
+++ b/strings/llstr.c
@@ -0,0 +1,36 @@
+/* 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 */
+
+/*
+ Defines: llstr();
+
+ llstr(value, buff);
+
+ This function saves a longlong value in a buffer and returns the pointer to
+ the buffer. This is useful when trying to portable print longlong
+ variables with printf() as there is no usable printf() standard one can use.
+*/
+
+
+#include <global.h>
+#include "m_string.h"
+
+char *llstr(longlong value,char *buff)
+{
+ longlong2str(value,buff,10);
+ return buff;
+}
diff --git a/strings/longlong2str-x86.s b/strings/longlong2str-x86.s
new file mode 100644
index 00000000000..8ce711f812e
--- /dev/null
+++ b/strings/longlong2str-x86.s
@@ -0,0 +1,141 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 */
+
+ .file "longlong2str.s"
+ .version "1.01"
+
+.text
+ .align 4
+
+.globl longlong2str
+ .type longlong2str,@function
+
+longlong2str:
+ subl $80,%esp
+ pushl %ebp
+ pushl %esi
+ pushl %edi
+ pushl %ebx
+ movl 100(%esp),%esi /* Lower part of val */
+ movl 104(%esp),%ebp /* Higher part of val */
+ movl 108(%esp),%edi /* get dst */
+ movl 112(%esp),%ebx /* Radix */
+ movl %ebx,%eax
+ testl %eax,%eax
+ jge .L144
+
+ addl $36,%eax
+ cmpl $34,%eax
+ ja .Lerror /* Wrong radix */
+ testl %ebp,%ebp
+ jge .L146
+ movb $45,(%edi) /* Add sign */
+ incl %edi /* Change sign of val */
+ negl %esi
+ adcl $0,%ebp
+ negl %ebp
+.L146:
+ negl %ebx /* Change radix to positive */
+ jmp .L148
+ .p2align 4,,7
+.L144:
+ addl $-2,%eax
+ cmpl $34,%eax
+ ja .Lerror /* Radix in range */
+
+.L148:
+ movl %esi,%eax /* Test if zero (for easy loop) */
+ orl %ebp,%eax
+ jne .L150
+ movb $48,(%edi)
+ incl %edi
+ jmp .L164
+ .p2align 4,,7
+
+.L150:
+ leal 92(%esp),%ecx /* End of buffer */
+ jmp .L155
+ .p2align 4,,7
+
+.L153:
+ /* val is stored in in ebp:esi */
+
+ movl %ebp,%eax /* High part of value */
+ xorl %edx,%edx
+ divl %ebx
+ movl %eax,%ebp
+ movl %esi,%eax
+ divl %ebx
+ movl %eax,%esi /* quotent in ebp:esi */
+ movb _dig_vec(%edx),%al /* al is faster than dl */
+ decl %ecx
+ movb %al,(%ecx) /* store value in buff */
+ .p2align 4,,7
+.L155:
+ testl %ebp,%ebp
+ ja .L153
+ testl %esi,%esi /* rest value */
+ jl .L153
+ je .L160 /* Ready */
+ movl %esi,%eax
+ movl $_dig_vec,%ebp
+ .p2align 4,,7
+
+.L154: /* Do rest with integer precision */
+ cltd
+ divl %ebx
+ decl %ecx
+ movb (%edx,%ebp),%dl /* bh is always zero as ebx=radix < 36 */
+ testl %eax,%eax
+ movb %dl,(%ecx)
+ jne .L154
+
+.L160:
+ movl %ecx,%esi
+ leal 92(%esp),%ecx /* End of buffer */
+ subl %esi,%ecx
+ rep
+ movsb
+
+.L164:
+ movl %edi,%eax /* Pointer to end null */
+ movb $0,(%edi) /* Store the end null */
+
+.L165:
+ popl %ebx
+ popl %edi
+ popl %esi
+ popl %ebp
+ addl $80,%esp
+ ret
+
+.Lerror:
+ xorl %eax,%eax /* Wrong radix */
+ jmp .L165
+
+.Lfe3:
+ .size longlong2str,.Lfe3-longlong2str
+
+.globl longlong10_to_str
+ .type longlong10_str,@function
+longlong10_to_str:
+ jmp longlong2str
+
+.L10end:
+ .size longlong10_to_str,.L10end-longlong10_to_str
diff --git a/strings/longlong2str.c b/strings/longlong2str.c
new file mode 100644
index 00000000000..5c4eaf98c85
--- /dev/null
+++ b/strings/longlong2str.c
@@ -0,0 +1,143 @@
+/* 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 */
+
+/*
+ Defines: longlong2str();
+
+ longlong2str(dst, radix, val)
+ converts the (longlong) integer "val" to character form and moves it to
+ the destination string "dst" followed by a terminating NUL. The
+ result is normally a pointer to this NUL character, but if the radix
+ is dud the result will be NullS and nothing will be changed.
+
+ If radix is -2..-36, val is taken to be SIGNED.
+ If radix is 2.. 36, val is taken to be UNSIGNED.
+ That is, val is signed if and only if radix is. You will normally
+ use radix -10 only through itoa and ltoa, for radix 2, 8, or 16
+ unsigned is what you generally want.
+
+ _dig_vec is public just in case someone has a use for it.
+ The definitions of itoa and ltoa are actually macros in m_string.h,
+ but this is where the code is.
+
+ Note: The standard itoa() returns a pointer to the argument, when int2str
+ returns the pointer to the end-null.
+ itoa assumes that 10 -base numbers are allways signed and other arn't.
+*/
+
+#include <global.h>
+#include "m_string.h"
+
+#if defined(HAVE_LONG_LONG) && !defined(longlong2str) && !defined(HAVE_LONGLONG2STR)
+
+extern char NEAR _dig_vec[];
+
+/*
+ This assumes that longlong multiplication is faster than longlong division.
+*/
+
+char *longlong2str(longlong val,char *dst,int radix)
+{
+ char buffer[65];
+ register char *p;
+ long long_val;
+
+ if (radix < 0)
+ {
+ if (radix < -36 || radix > -2) return (char*) 0;
+ if (val < 0) {
+ *dst++ = '-';
+ val = -val;
+ }
+ radix = -radix;
+ }
+ else
+ {
+ if (radix > 36 || radix < 2) return (char*) 0;
+ }
+ if (val == 0)
+ {
+ *dst++='0';
+ *dst='\0';
+ return dst;
+ }
+ p = &buffer[sizeof(buffer)-1];
+ *p = '\0';
+
+ while ((ulonglong) val > (ulonglong) LONG_MAX)
+ {
+ ulonglong quo=(ulonglong) val/(uint) radix;
+ uint rem= (uint) (val- quo* (uint) radix);
+ *--p = _dig_vec[rem];
+ val= quo;
+ }
+ long_val= (long) val;
+ while (long_val != 0)
+ {
+ long quo= long_val/radix;
+ *--p = _dig_vec[(uchar) (long_val - quo*radix)];
+ long_val= quo;
+ }
+ while ((*dst++ = *p++) != 0) ;
+ return dst-1;
+}
+
+#endif
+
+#ifndef longlong10_to_str
+char *longlong10_to_str(longlong val,char *dst,int radix)
+{
+ char buffer[65];
+ register char *p;
+ long long_val;
+
+ if (radix < 0)
+ {
+ if (val < 0)
+ {
+ *dst++ = '-';
+ val = -val;
+ }
+ }
+
+ if (val == 0)
+ {
+ *dst++='0';
+ *dst='\0';
+ return dst;
+ }
+ p = &buffer[sizeof(buffer)-1];
+ *p = '\0';
+
+ while ((ulonglong) val > (ulonglong) LONG_MAX)
+ {
+ ulonglong quo=(ulonglong) val/(uint) 10;
+ uint rem= (uint) (val- quo* (uint) 10);
+ *--p = _dig_vec[rem];
+ val= quo;
+ }
+ long_val= (long) val;
+ while (long_val != 0)
+ {
+ long quo= long_val/10;
+ *--p = _dig_vec[(uchar) (long_val - quo*10)];
+ long_val= quo;
+ }
+ while ((*dst++ = *p++) != 0) ;
+ return dst-1;
+}
+#endif
diff --git a/strings/macros.asm b/strings/macros.asm
new file mode 100644
index 00000000000..4cd5397fbaa
--- /dev/null
+++ b/strings/macros.asm
@@ -0,0 +1,147 @@
+; 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
+
+; Some useful macros
+
+ .386P
+ .387
+
+_FLAT equ 0 ;FLAT memory model
+_STDCALL equ 0 ;default to _stdcall
+I386 equ 1
+
+begcode macro module
+ if _FLAT
+_TEXT segment dword use32 public 'CODE'
+ assume CS:FLAT,DS:FLAT,SS:FLAT
+ else
+_TEXT segment dword public 'CODE'
+ assume CS:_TEXT
+ endif
+ endm
+
+endcode macro module
+_TEXT ENDS
+ endm
+
+begdata macro
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; Set up segments for data
+; Regular initialized data goes in _DATA
+
+_DATA segment dword public 'DATA'
+_DATA ends
+
+;Function pointers to constructors
+XIB segment dword public 'DATA'
+XIB ends
+XI segment dword public 'DATA'
+XI ends
+XIE segment dword public 'DATA'
+XIE ends
+
+;Function pointers to destructors
+XCB segment dword public 'DATA'
+XCB ends
+XC segment dword public 'DATA'
+XC ends
+XCE segment dword public 'DATA'
+XCE ends
+
+;Constant data, such as switch tables, go here.
+
+CONST segment dword public 'CONST'
+CONST ends
+
+;Segment for uninitialized data. This is set to 0 by the startup code/OS,
+;so it does not consume room in the executable file.
+
+_BSS segment dword public 'BSS'
+_BSS ends
+
+HUGE_BSS segment dword public 'HUGE_BSS'
+HUGE_BSS ends
+
+EEND segment dword public 'ENDBSS'
+EEND ends
+
+STACK segment para stack 'STACK'
+STACK ends
+DGROUP group _DATA,XIB,XI,XIE,XCB,XC,XCE,CONST,_BSS,EEND,STACK
+
+_DATA segment
+ if _FLAT
+ assume DS:FLAT
+ else
+ assume DS:DGROUP
+ endif
+ endm
+
+enddata macro
+_DATA ends
+ endm
+
+P equ 8 ; Offset of start of parameters on the stack frame
+ ; From EBP assuming EBP was pushed.
+PS equ 4 ; Offset of start of parameters on the stack frame
+ ; From ESP assuming EBP was NOT pushed.
+ESeqDS equ 0
+FSeqDS equ 0
+GSeqDS equ 0
+SSeqDS equ 1
+SIZEPTR equ 4 ; Size of a pointer
+LPTR equ 0
+SPTR equ 1
+LCODE equ 0
+
+func macro name
+_&name proc near
+ ifndef name
+name equ _&name
+ endif
+ endm
+
+callm macro name
+ call _&name
+ endm
+
+;Macros to replace public, extrn, and endp for C-callable assembly routines,
+; and to define labels: c_label defines labels,
+; c_public replaces public, c_extrn replaces extrn, and c_endp replaces endp
+
+c_name macro name
+ name equ _&name
+ endm
+
+c_label macro name
+_&name:
+ endm
+
+c_endp macro name
+_&name ENDP
+ endm
+
+clr macro list ;clear a register
+ irp reg,<list>
+ xor reg,reg
+ endm
+ endm
+
+jmps macro lbl
+ jmp short lbl
+ endm
diff --git a/strings/make-ccc b/strings/make-ccc
new file mode 100755
index 00000000000..78d5ad1ce42
--- /dev/null
+++ b/strings/make-ccc
@@ -0,0 +1,3 @@
+ccc -DHAVE_CONFIG_H -I. -I. -I.. -I./../include -I../include -O -DDBUG_OFF -fast -O3 -fomit-frame-pointer -c atof.c bchange.c bcmp.c bfill.c bmove.c bmove512.c bmove_upp.c ct_init.c ctype-latin1.c int2str.c is_prefix.c llstr.c longlong2str.c r_strinstr.c str2int.c strappend.c strcend.c strcont.c strend.c strfill.c strinstr.c strmake.c strmov.c strnmov.c strstr.c strtol.c strtoll.c strtoul.c strtoull.c strxmov.c strxnmov.c
+rm libmystrings.a
+ar -cr libmystrings.a atof.o
diff --git a/strings/memcmp.c b/strings/memcmp.c
new file mode 100644
index 00000000000..1bb8deaeac0
--- /dev/null
+++ b/strings/memcmp.c
@@ -0,0 +1,46 @@
+/* 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 */
+
+/* memcmp(lhs, rhs, len)
+ compares the two memory areas lhs[0..len-1] ?? rhs[0..len-1]. It
+ returns an integer less than, equal to, or greater than 0 according
+ as lhs[-] is lexicographically less than, equal to, or greater than
+ rhs[-]. Note that this is not at all the same as bcmp, which tells
+ you *where* the difference is but not what.
+
+ Note: suppose we have int x, y; then memcmp(&x, &y, sizeof x) need
+ not bear any relation to x-y. This is because byte order is machine
+ dependent, and also, some machines have integer representations that
+ are shorter than a machine word and two equal integers might have
+ different values in the spare bits. On a ones complement machine,
+ -0 == 0, but the bit patterns are different.
+*/
+
+#include "strings.h"
+
+#if !defined(HAVE_MEMCPY)
+
+int memcmp(lhs, rhs, len)
+ register char *lhs, *rhs;
+ register int len;
+{
+ while (--len >= 0)
+ if (*lhs++ != *rhs++) return (uchar) lhs[-1] - (uchar) rhs[-1];
+ return 0;
+}
+
+#endif
diff --git a/strings/memcpy.c b/strings/memcpy.c
new file mode 100644
index 00000000000..4fc84fb6052
--- /dev/null
+++ b/strings/memcpy.c
@@ -0,0 +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,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should 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 */
+
+/*
+ memcpy(dst, src, len)
+ moves len bytes from src to dst. The result is dst. This is not
+ the same as strncpy or strnmov, while move a maximum of len bytes
+ and stop early if they hit a NUL character. This moves len bytes
+ exactly, no more, no less. See also bcopy() and bmove() which do
+ not return a value but otherwise do the same job.
+*/
+
+#include "strings.h"
+
+char *memcpy(char *dst, register char *src, register int len)
+{
+ register char *d;
+
+ for (d = dst; --len >= 0; *d++ = *src++) ;
+ return dst;
+}
diff --git a/strings/memset.c b/strings/memset.c
new file mode 100644
index 00000000000..57c8fea5ebe
--- /dev/null
+++ b/strings/memset.c
@@ -0,0 +1,35 @@
+/* File : memset.c
+ Author : Richard A. O'Keefe.
+ Updated: 25 May 1984
+ Defines: memset()
+
+ memset(dst, chr, len)
+ fills the memory area dst[0..len-1] with len bytes all equal to chr.
+ The result is dst. See also bfill(), which has no return value and
+ puts the last two arguments the other way around.
+
+ Note: the VAX assembly code version can only handle 0 <= len < 2^16.
+ It is presented for your interest and amusement.
+*/
+
+#include "strings.h"
+
+#if VaxAsm
+
+char *memset(char *dst,int chr, int len)
+{
+ asm("movc5 $0,*4(ap),8(ap),12(ap),*4(ap)");
+ return dst;
+}
+
+#else ~VaxAsm
+
+char *memset(char *dst, register pchar chr, register int len)
+{
+ register char *d;
+
+ for (d = dst; --len >= 0; *d++ = chr) ;
+ return dst;
+}
+
+#endif VaxAsm
diff --git a/strings/ptr_cmp.asm b/strings/ptr_cmp.asm
new file mode 100644
index 00000000000..6106016ee32
--- /dev/null
+++ b/strings/ptr_cmp.asm
@@ -0,0 +1,180 @@
+; 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
+
+ TITLE Optimized cmp of pointer to strings of unsigned chars
+
+ifndef M_I386
+ .8087
+ DOSSEG
+ .MODEL LARGE
+ .DATA
+compare_length dw 0
+ .CODE STRINGS
+
+ PUBLIC _get_ptr_compare
+_get_ptr_compare PROC
+ mov bx,sp
+ mov cx,ss:[BX+4]
+ mov compare_length,cx
+ mov dx,seg strings:_ptr_cmp
+ mov ax,offset _ptr_cmp_0
+ jcxz @F
+ mov ax,offset _ptr_cmp_1
+ dec cx
+ jz @F
+ mov ax,offset _ptr_cmp
+@@: ret
+_get_ptr_compare ENDP
+
+_ptr_cmp_0 PROC
+ mov AX,0 ; Emptyt strings are always equal
+ ret
+_ptr_cmp_0 ENDP
+
+
+_ptr_cmp_1 PROC
+ mov bx,sp
+ mov dx,si ; Save si and ds
+ mov cx,ds
+ lds si,DWORD PTR ss:[bx+4] ; s1
+ lds si,DWORD PTR ds:[si]
+ mov al,ds:[si]
+ xor ah,ah
+ lds si,DWORD PTR ss:[bx+8] ; s2
+ lds si,DWORD PTR ds:[si]
+ mov bl,ds:[si]
+ mov bh,ah
+ sub ax,bx
+ mov ds,cx ; restore si and ds
+ mov si,dx
+ ret
+_ptr_cmp_1 ENDP
+
+_ptr_cmp PROC
+ mov bx,bp ; Save bp
+ mov dx,di ; Save di
+ mov bp,sp
+ push ds
+ push si
+ mov cx,compare_length ; Length of memory-area
+ lds si,DWORD PTR [bp+4] ; s1
+ lds si,DWORD PTR ds:[si]
+ les di,DWORD PTR [bp+8] ; s2
+ les di,DWORD PTR es:[di]
+; cld ; Work uppward
+ xor ax,ax
+ repe cmpsb ; Compare strings
+ je @F ; Strings are equal
+ sbb ax,ax
+ cmc
+ adc ax,0
+
+@@: pop si
+ pop ds
+ mov di,dx
+ mov bp,bx
+ ret
+_ptr_cmp ENDP
+
+else
+
+include macros.asm
+
+fix_es MACRO fix_cld ; Load ES if neaded
+ ife ESeqDS
+ mov ax,ds
+ mov es,ax
+ endif
+ ifnb <fix_cld>
+ cld
+ endif
+ ENDM
+
+ begdata
+compare_length dd 0 ; Length of strings
+ enddata
+
+ begcode get_ptr_compare
+ public _get_ptr_compare
+_get_ptr_compare proc near
+ mov ecx,P-SIZEPTR[esp]
+ mov compare_length,ecx
+ mov eax,offset _TEXT:_ptr_cmp_0
+ jecxz @F
+ mov eax,offset _TEXT:_ptr_cmp_1
+ dec ecx
+ jz @F
+ mov eax,offset _TEXT:_ptr_cmp
+@@: ret
+_get_ptr_compare endp
+ endcode _get_ptr_compare
+
+
+ begcode ptr_cmp_0
+_ptr_cmp_0 PROC
+ mov EAX,0 ; Emptyt strings are always equal
+ ret
+_ptr_cmp_0 ENDP
+ endcode ptr_cmp_0
+
+
+ begcode ptr_cmp_1
+_ptr_cmp_1 proc near
+ mov edx,esi ; Save esi
+ mov esi,P-SIZEPTR[esp] ; *s1
+ mov esi,[esi]
+ movzx eax,[esi]
+ mov esi,P[esp] ; *s2
+ mov esi,[esi]
+ movzx ecx,[esi]
+ sub eax,ecx
+ mov esi,edx ; Restore esi
+ ret
+_ptr_cmp_1 ENDP
+ endcode ptr_cmp_1
+
+
+ begcode ptr_cmp
+_ptr_cmp proc near
+ fix_es 1
+ push ebp
+ mov ebp,esp
+ mov edx,edi ; Save esi
+ push esi
+ mov esi,P[ebp] ; *s1
+ mov esi,[esi]
+ mov edi,P+SIZEPTR[ebp] ; *s2
+ mov edi,[edi]
+ mov ecx,compare_length ; Length of memory-area
+ xor eax,eax
+ repe cmpsb ; Compare strings
+ je @F ; Strings are equal
+
+ sbb eax,eax
+ cmc
+ adc eax,0
+
+@@: pop esi
+ mov edi,edx
+ pop ebp
+ ret
+_ptr_cmp ENDP
+ endcode ptr_cmp
+
+endif
+
+ END
diff --git a/strings/r_strinstr.c b/strings/r_strinstr.c
new file mode 100644
index 00000000000..882a4eda412
--- /dev/null
+++ b/strings/r_strinstr.c
@@ -0,0 +1,52 @@
+/* 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 */
+
+/*
+ Author : David
+ strintstr(src, from, pat) looks for an instance of pat in src
+ backwards from pos from. pat is not a regex(3) pattern, it is a literal
+ string which must be matched exactly.
+ The result 0 if the pattern was not found else it is the start char of
+ the pattern counted from the begining of the string.
+*/
+
+#include <global.h>
+#include "m_string.h"
+
+uint r_strinstr(reg1 my_string str,int from, reg4 my_string search)
+{
+ reg2 my_string i, j;
+ uint len = (uint) strlen(search);
+ /* pointer to the last char of buff */
+ my_string start = str + from - 1;
+ /* pointer to the last char of search */
+ my_string search_end = search + len - 1;
+
+ skipp:
+ while (start >= str) /* Cant be != because the first char */
+ {
+ if (*start-- == *search_end)
+ {
+ i = start; j = search_end - 1;
+ while (j >= search && start > str)
+ if (*i-- != *j--)
+ goto skipp;
+ return (uint) ((start - len) - str + 3);
+ }
+ }
+ return (0);
+}
diff --git a/strings/str2int.c b/strings/str2int.c
new file mode 100644
index 00000000000..55fcd56adb9
--- /dev/null
+++ b/strings/str2int.c
@@ -0,0 +1,202 @@
+/* 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 */
+
+/*
+ str2int(src, radix, lower, upper, &val)
+ converts the string pointed to by src to an integer and stores it in
+ val. It skips leading spaces and tabs (but not newlines, formfeeds,
+ backspaces), then it accepts an optional sign and a sequence of digits
+ in the specified radix. The result should satisfy lower <= *val <= upper.
+ The result is a pointer to the first character after the number;
+ trailing spaces will NOT be skipped.
+
+ If an error is detected, the result will be NullS, the value put
+ in val will be 0, and errno will be set to
+ EDOM if there are no digits
+ ERANGE if the result would overflow or otherwise fail to lie
+ within the specified bounds.
+ Check that the bounds are right for your machine.
+ This looks amazingly complicated for what you probably thought was an
+ easy task. Coping with integer overflow and the asymmetric range of
+ twos complement machines is anything but easy.
+
+ So that users of atoi and atol can check whether an error occured,
+ I have taken a wholly unprecedented step: errno is CLEARED if this
+ call has no problems.
+*/
+
+#include <global.h>
+#include "m_string.h"
+#include "m_ctype.h"
+#include "my_sys.h" /* defines errno */
+#include <errno.h>
+
+#define char_val(X) (X >= '0' && X <= '9' ? X-'0' :\
+ X >= 'A' && X <= 'Z' ? X-'A'+10 :\
+ 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)
+{
+ int sign; /* is number negative (+1) or positive (-1) */
+ int n; /* number of digits yet to be converted */
+ long limit; /* "largest" possible valid input */
+ long scale; /* the amount to multiply next digit by */
+ long sofar; /* the running value */
+ register int d; /* (negative of) next digit */
+ char *start;
+ int digits[32]; /* Room for numbers */
+
+ /* Make sure *val is sensible in case of error */
+
+ *val = 0;
+
+ /* Check that the radix is in the range 2..36 */
+
+#ifndef DBUG_OFF
+ if (radix < 2 || radix > 36) {
+ errno=EDOM;
+ return NullS;
+ }
+#endif
+
+ /* The basic problem is: how do we handle the conversion of
+ a number without resorting to machine-specific code to
+ check for overflow? Obviously, we have to ensure that
+ no calculation can overflow. We are guaranteed that the
+ "lower" and "upper" arguments are valid machine integers.
+ On sign-and-magnitude, twos-complement, and ones-complement
+ machines all, if +|n| is representable, so is -|n|, but on
+ twos complement machines the converse is not true. So the
+ "maximum" representable number has a negative representative.
+ Limit is set to min(-|lower|,-|upper|); this is the "largest"
+ number we are concerned with. */
+
+ /* Calculate Limit using Scale as a scratch variable */
+
+ if ((limit = lower) > 0) limit = -limit;
+ if ((scale = upper) > 0) scale = -scale;
+ if (scale < limit) limit = scale;
+
+ /* Skip leading spaces and check for a sign.
+ Note: because on a 2s complement machine MinLong is a valid
+ integer but |MinLong| is not, we have to keep the current
+ converted value (and the scale!) as *negative* numbers,
+ so the sign is the opposite of what you might expect.
+ */
+ while (isspace(*src)) src++;
+ sign = -1;
+ if (*src == '+') src++; else
+ if (*src == '-') src++, sign = 1;
+
+ /* Skip leading zeros so that we never compute a power of radix
+ in scale that we won't have a need for. Otherwise sticking
+ enough 0s in front of a number could cause the multiplication
+ to overflow when it neededn't.
+ */
+ start=(char*) src;
+ while (*src == '0') src++;
+
+ /* Move over the remaining digits. We have to convert from left
+ to left in order to avoid overflow. Answer is after last digit.
+ */
+
+ for (n = 0; (digits[n]=char_val(*src)) < radix && n < 20; n++,src++) ;
+
+ /* Check that there is at least one digit */
+
+ if (start == src) {
+ errno=EDOM;
+ return NullS;
+ }
+
+ /* The invariant we want to maintain is that src is just
+ to the right of n digits, we've converted k digits to
+ sofar, scale = -radix**k, and scale < sofar < 0. Now
+ if the final number is to be within the original
+ Limit, we must have (to the left)*scale+sofar >= Limit,
+ or (to the left)*scale >= Limit-sofar, i.e. the digits
+ to the left of src must form an integer <= (Limit-sofar)/(scale).
+ In particular, this is true of the next digit. In our
+ incremental calculation of Limit,
+
+ IT IS VITAL that (-|N|)/(-|D|) = |N|/|D|
+ */
+
+ for (sofar = 0, scale = -1; --n >= 1;)
+ {
+ if ((long) -(d=digits[n]) < limit) {
+ errno=ERANGE;
+ return NullS;
+ }
+ limit = (limit+d)/radix, sofar += d*scale; scale *= radix;
+ }
+ if (n == 0)
+ {
+ if ((long) -(d=digits[n]) < limit) /* get last digit */
+ {
+ errno=ERANGE;
+ return NullS;
+ }
+ sofar+=d*scale;
+ }
+
+ /* Now it might still happen that sofar = -32768 or its equivalent,
+ so we can't just multiply by the sign and check that the result
+ is in the range lower..upper. All of this caution is a right
+ pain in the neck. If only there were a standard routine which
+ says generate thus and such a signal on integer overflow...
+ But not enough machines can do it *SIGH*.
+ */
+ if (sign < 0)
+ {
+ if (sofar < -LONG_MAX || (sofar= -sofar) > upper)
+ {
+ errno=ERANGE;
+ return NullS;
+ }
+ }
+ else if (sofar < lower)
+ {
+ errno=ERANGE;
+ return NullS;
+ }
+ *val = sofar;
+ errno=0; /* indicate that all went well */
+ return (char*) src;
+}
+
+ /* Theese are so slow compared with ordinary, optimized atoi */
+
+#ifdef WANT_OUR_ATOI
+
+int atoi(const char *src)
+{
+ long val;
+ str2int(src, 10, (long) INT_MIN, (long) INT_MAX, &val);
+ return (int) val;
+}
+
+
+long atol(const char *src)
+{
+ long val;
+ str2int(src, 10, LONG_MIN, LONG_MAX, &val);
+ return val;
+}
+
+#endif /* WANT_OUR_ATOI */
diff --git a/strings/str_test.c b/strings/str_test.c
new file mode 100644
index 00000000000..069e7a5b487
--- /dev/null
+++ b/strings/str_test.c
@@ -0,0 +1,270 @@
+/* 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 all stringfunktions that is coded in assembler */
+
+#include <global.h>
+#include <stdarg.h>
+#include "m_string.h"
+
+#define F_LEN 8
+#define F_CHAR 'A'
+#define F_FILL 'B'
+#define T_LEN 15
+#define T_CHAR 'D'
+#define T_FILL 'E'
+#define F_PREFILL '0'
+#define T_PREFILL '1'
+
+static char from_buff[100],to_buff[100];
+static my_string from,to;
+static int errors,tests;
+static int test_strarg(char *name,...);
+static void init_strings (void); /* Init from and to */
+void test_arg (my_string message,long func_value,long value);
+int compare_buff (my_string message,my_string b1,my_string b2,int length,
+ pchar fill, pchar prefill);
+
+int my_test(int a)
+{
+ return a ? 1 : 0;
+}
+
+int main(void)
+{
+ static char v1[]="Monty",v2[]="on",v3[]="Montys",v4[]="ty",v5[]="gr",
+ v6[]="hohohoo",v7[]="hohoo",v8[]="hohooo",v9[]="t",
+ cont[]="qwet";
+ errors=tests=0;
+ init_strings();
+
+ test_arg("bcmp(from,to,5)",(long) my_test(bcmp(from,to,5)),1L);
+ test_arg("bcmp(from,from,5)",(long) bcmp(from,from,5),0L);
+
+ test_arg("bcmp(from,to,0)",(long) bcmp(from,to,0),0L);
+ test_arg("strend(from)",(long) strend(from),(long) from+F_LEN);
+ test_arg("strchr(v1,'M')",(long) strchr(v1,'M'),(long) v1);
+ test_arg("strchr(v1,'y')",(long) strchr(v1,'y'),(long) v1+4);
+ test_arg("strchr(v1,'x')",(long) strchr(v1,'x'),0L);
+ test_arg("strcont(v1,cont)",(long) strcont(v1,cont),(long) v1+3);
+ test_arg("strcont(v1,v2)",(long) strcont(v1,v2),(long) v1+1);
+ test_arg("strcont(v1,v5)",(long) strcont(v1,v5),0L);
+ test_arg("is_prefix(v3,v1)",(long) is_prefix(v3,v1),1L);
+ test_arg("is_prefix(v1,v3)",(long) is_prefix(v1,v3),0L);
+ test_arg("is_prefix(v3,v4)",(long) is_prefix(v3,v4),0L);
+ test_arg("strstr(v1,v1)",(long) strstr(v1,v1),(long) v1);
+ test_arg("strstr(v1,v2)",(long) strstr(v1,v2),(long) v1+1);
+ test_arg("strstr(v1,v4)",(long) strstr(v1,v4),(long) v1+3);
+ test_arg("strstr(v6,v7)",(long) strstr(v6,v7),(long) v6+2);
+ test_arg("strstr(v1,v9)",(long) strstr(v1,v9),(long) v1+3);
+ test_arg("strstr(v1,v3)",(long) strstr(v1,v3),0L);
+ test_arg("strstr(v1,v5)",(long) strstr(v1,v5),0L);
+ test_arg("strstr(v6,v8)",(long) strstr(v6,v8),0L);
+
+ test_arg("strinstr(v1,v4)",(long) strinstr(v1,v4),4L);
+ test_arg("strinstr(v1,v5)",(long) strinstr(v1,v5),0L);
+ test_arg("strlen(from)",(long) strlen(from),(long) F_LEN);
+ test_arg("strlen(\"\")",(long) strlen(""),0L);
+#ifdef HAVE_STRNLEN
+ test_arg("strnlen(from,3)",(long) strnlen(from,3),3L);
+ test_arg("strnlen(from,0)",(long) strnlen(from,0),0L);
+ test_arg("strnlen(from,1000)",(long) strnlen(from,1000),(long) F_LEN);
+#endif
+
+ test_strarg("bfill(to,4,' ')",(bfill(to,4,' '),0L),INT_MAX32,4,' ',0,0);
+ test_strarg("bfill(from,0,' ')",(bfill(from,0,' '),0L),INT_MAX32,0,0);
+ test_strarg("bzero(to,3)",(bzero(to,3),0L),INT_MAX32,3,0,0,0);
+ test_strarg("bzero(to,0)",(bzero(to,0),0L),INT_MAX32,0,0);
+ test_strarg("bmove(to,from,4)",(bmove(to,from,4),0L),INT_MAX32,4,F_CHAR,
+ 0,0);
+ test_strarg("bmove(to,from,0)",(bmove(to,from,0),0L),INT_MAX32,0,0);
+ test_strarg("bmove_upp(to+6,from+6,3)",(bmove_upp(to+6,from+6,3),0L),INT_MAX32,
+ 3,T_CHAR,3,F_CHAR,0,0);
+ test_strarg("bmove_upp(to,from,0)",(bmove_upp(to,from,0),0L),INT_MAX32,0,0);
+ test_strarg("strappend(to,3,' ')",(strappend(to,3,' '),0L),INT_MAX32,
+ 3,T_CHAR,1,0,T_LEN-4,T_CHAR,1,0,0,0);
+ test_strarg("strappend(to,T_LEN+5,' ')",(strappend(to,T_LEN+5,' '),0L),INT_MAX32,
+ T_LEN,T_CHAR,5,' ',1,0,0,0);
+ test_strarg("strcat(to,from)",strcat(to,from),to,T_LEN,T_CHAR,
+ F_LEN,F_CHAR,1,0,0,0);
+ test_strarg("strcat(to,\"\")",strcat(to,""),INT_MAX32,0,0);
+ test_strarg("strfill(to,4,' ')",strfill(to,4,' '),to+4,4,' ',1,0,0,0);
+ test_strarg("strfill(from,0,' ')",strfill(from,0,' '),from,0,1,0,0);
+ test_strarg("strmake(to,from,4)",strmake(to,from,4),to+4,4,F_CHAR,
+ 1,0,0,0);
+ test_strarg("strmake(to,from,0)",strmake(to,from,0),to+0,1,0,0,0);
+ test_strarg("strmov(to,from)",strmov(to,from),to+F_LEN,F_LEN,F_CHAR,0,0);
+ test_strarg("strmov(to,\"\")",strmov(to,""),to,1,0,0,0);
+ test_strarg("strnmov(to,from,2)",strnmov(to,from,2),to+2,2,F_CHAR,0,0);
+ test_strarg("strnmov(to,from,F_LEN+5)",strnmov(to,from,F_LEN+5),to+F_LEN,
+ F_LEN,F_CHAR,1,0,0,0);
+ test_strarg("strnmov(to,\"\",2)",strnmov(to,"",2),to,1,0,0,0);
+ test_strarg("strxmov(to,from,\"!!\",NullS)",strxmov(to,from,"!!",NullS),to+F_LEN+2,F_LEN,F_CHAR,2,'!',0,0,0);
+ test_strarg("strxmov(to,NullS)",strxmov(to,NullS),to,1,0,0,0);
+ test_strarg("strxmov(to,from,from,from,from,from,'!!',from,NullS)",strxmov(to,from,from,from,from,from,"!!",from,NullS),to+F_LEN*6+2,F_LEN,F_CHAR,F_LEN,F_CHAR,F_LEN,F_CHAR,F_LEN,F_CHAR,F_LEN,F_CHAR,2,'!',F_LEN,F_CHAR,1,0,0,0);
+ test_strarg("bchange(to,2,from,4,6)",(bchange(to,2,from,4,6),0L),INT_MAX32,
+ 4,F_CHAR,2,T_CHAR,0,0);
+
+ printf("tests: %d errors: %d\n",tests,errors);
+ if (errors)
+ fputs("--- Some functions doesn't work!! Fix them\n",stderr);
+ return(errors > 0);
+
+ fputs("Fatal error\n",stderr);
+ return(2);
+} /* main */
+
+
+ /* Init strings */
+
+void init_strings(void)
+{
+ reg1 int i;
+ reg2 char *pos;
+
+ from=from_buff+3; to=to_buff+3;
+
+ pos=from_buff; *pos++= F_FILL; *pos++=F_FILL; *pos++=F_PREFILL;
+ for (i=0 ; i < F_LEN ; i++)
+ *pos++=F_CHAR;
+ *pos++=0;
+ for (i=0; i<50 ; i++)
+ *pos++= F_FILL;
+
+ pos=to_buff; *pos++= T_FILL; *pos++=T_FILL; *pos++=T_PREFILL;
+ for (i=0 ; i < T_LEN ; i++)
+ *pos++=T_CHAR;
+ *pos++=0;
+ for (i=0; i<50 ; i++)
+ *pos++= T_FILL;
+} /* init_strings */
+
+
+ /* Test that function return rigth value */
+
+void test_arg(my_string message, long int func_value, long int value)
+{
+ tests++;
+ printf("testing '%s'\n",message);
+ if (func_value != value)
+ {
+ printf("func: '%s' = %ld Should be: %ld\n",message,func_value,value);
+ errors++;
+ }
+} /* test_arg */
+
+ /* Test function return value and from and to arrays */
+
+static int test_strarg(char *message,...)
+{
+ long func_value,value;
+ int error,length;
+ char chr,cmp_buff[100],*pos,*pos2;
+ va_list pvar;
+
+ tests++;
+ va_start(pvar,message);
+ func_value=va_arg(pvar,long);
+ value=va_arg(pvar,long);
+
+ printf("testing '%s'\n",message);
+ if (func_value != value && value != INT_MAX32)
+ {
+ printf("func: '%s' = %ld Should be: %ld\n",message,func_value,value);
+ errors++;
+ }
+ pos= cmp_buff;
+ while ((length = va_arg(pvar, int)) != 0)
+ {
+ chr= (char) (va_arg(pvar, int));
+ while (length--)
+ *pos++=chr;
+ }
+ pos2=to+ (int)(pos-cmp_buff);
+ while (pos <= cmp_buff+T_LEN)
+ *pos++= *pos2++;
+ if (compare_buff(message,to,cmp_buff,(int) (pos-cmp_buff),T_FILL,T_PREFILL))
+ {
+ init_strings();
+ va_end(pvar);
+ return 1;
+ }
+
+ pos= cmp_buff;
+ while ((length = va_arg(pvar, int)) != 0)
+ {
+ chr= (char) (va_arg(pvar, int));
+ while (length--)
+ *pos++=chr;
+ }
+ pos2=from+ (int)(pos-cmp_buff);
+ while (pos <= cmp_buff+F_LEN)
+ *pos++= *pos2++;
+ error=compare_buff(message,from,cmp_buff,(int) (pos-cmp_buff),F_FILL,F_PREFILL);
+ init_strings();
+ va_end(pvar);
+ return (error != 0);
+} /* test_strarg */
+
+
+ /* test if function made right value */
+
+int compare_buff(my_string message, my_string b1, my_string b2, int length,
+ pchar fill, pchar prefill)
+{
+ int i,error=0;
+
+ if (bcmp(b1,b2,length))
+ {
+ errors++;
+ printf("func: '%s' Buffers differ\nIs: ",message);
+ for (i=0 ; i<length ; i++)
+ printf("%3d ",b1[i]);
+ printf("\nShould be: ");
+ for (i=0 ; i<length ; i++)
+ printf("%3d ",b2[i]);
+ puts("");
+ }
+ else if (b1[-1] != prefill || b1[-2] != fill || b1[-3] != fill)
+ {
+ printf("func: '%s' Chars before buffer is changed\n",message);
+ errors++;
+ error=1;
+ }
+ else if (b1[length] != fill || b1[length+1] != fill)
+ {
+ printf("func: '%s' Chars after buffer is changed\n",message);
+ errors++;
+ error=1;
+ }
+ return error;
+} /* compare_buff */
+
+ /* These are here to be loaded and examined */
+
+void dummy_functions(void)
+{
+ VOID(memchr(from,'a',5));
+ VOID(memcmp(from,to,5));
+ VOID(memcpy(from,to,5));
+ VOID(memset(from,' ',5));
+ VOID(strcmp(from,to));
+ VOID(strcpy(from,to));
+ VOID(strstr(from,to));
+ VOID(strrchr(from,'a'));
+ return;
+}
diff --git a/strings/strappend-sparc.s b/strings/strappend-sparc.s
new file mode 100644
index 00000000000..69bb555aa47
--- /dev/null
+++ b/strings/strappend-sparc.s
@@ -0,0 +1,49 @@
+! 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
+
+ .file "strappend-sparc.s"
+.section ".text"
+ .align 4
+ .global strappend
+ .type strappend,#function
+ .proc 020
+strappend:
+ add %o0, %o1, %g3 ! g3 = endpos
+ ldsb [%o0], %g2
+.loop1:
+ add %o0, 1, %o0 ! find end of str
+ cmp %g2, 0
+ bne,a .loop1
+ ldsb [%o0], %g2
+
+ sub %o0, 1, %o0
+ cmp %o0, %g3
+ bgeu .end
+ nop
+
+ stb %o2, [%o0]
+.loop2:
+ add %o0, 1, %o0
+ cmp %o0, %g3
+ blu,a .loop2
+ stb %o2, [%o0]
+.end:
+ retl
+ stb %g0, [%g3]
+.strappend_end:
+ .size strappend,.strappend_end-strappend
+ .ident "Matt Wagner & Monty"
diff --git a/strings/strappend.c b/strings/strappend.c
new file mode 100644
index 00000000000..d5defaeb0bf
--- /dev/null
+++ b/strings/strappend.c
@@ -0,0 +1,43 @@
+/* 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 */
+
+/* File : strappend.c
+ Author : Monty
+ Updated: 1987.02.07
+ Defines: strappend()
+
+ strappend(dest, len, fill) appends fill-characters to a string so that
+ the result length == len. If the string is longer than len it's
+ trunked. The des+len character is allways set to NULL.
+*/
+
+#include <global.h>
+#include "m_string.h"
+
+
+void strappend(register char *s, uint len, pchar fill)
+{
+ register char *endpos;
+
+ endpos = s+len;
+ while (*s++);
+ s--;
+ while (s<endpos) *(s++) = fill;
+ *(endpos) = '\0';
+} /* strappend */
+
+
diff --git a/strings/strcat.c b/strings/strcat.c
new file mode 100644
index 00000000000..699729cd7b5
--- /dev/null
+++ b/strings/strcat.c
@@ -0,0 +1,25 @@
+/* File : strcat.c
+ Author : Richard A. O'Keefe.
+ Updated: 10 April 1984
+ Defines: strcat()
+
+ strcat(s, t) concatenates t on the end of s. There had better be
+ enough room in the space s points to; strcat has no way to tell.
+ Note that strcat has to search for the end of s, so if you are doing
+ a lot of concatenating it may be better to use strmov, e.g.
+ strmov(strmov(strmov(strmov(s,a),b),c),d)
+ rather than
+ strcat(strcat(strcat(strcpy(s,a),b),c),d).
+ strcat returns the old value of s.
+*/
+
+#include "strings.h"
+
+char *strcat(register char *s, register const char *t)
+{
+ char *save;
+
+ for (save = s; *s++; ) ;
+ for (--s; *s++ = *t++; ) ;
+ return save;
+ }
diff --git a/strings/strcend.c b/strings/strcend.c
new file mode 100644
index 00000000000..246b81d7f7b
--- /dev/null
+++ b/strings/strcend.c
@@ -0,0 +1,56 @@
+/* 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 */
+
+/* File : strcend.c
+ Author : Michael Widenius: ifdef MC68000
+ Updated: 20 April 1984
+ Defines: strcend()
+
+ strcend(s, c) returns a pointer to the first place in s where c
+ occurs, or a pointer to the end-null of s if c does not occur in s.
+*/
+
+#include <global.h>
+#include "m_string.h"
+
+#if defined(MC68000) && defined(DS90)
+
+char *strcend(const char *s, pchar c)
+{
+asm(" movl 4(a7),a0 ");
+asm(" movl 8(a7),d1 ");
+asm(".L2: movb (a0)+,d0 ");
+asm(" cmpb d0,d1 ");
+asm(" beq .L1 ");
+asm(" tstb d0 ");
+asm(" bne .L2 ");
+asm(".L1: movl a0,d0 ");
+asm(" subql #1,d0 ");
+}
+
+#else
+
+char *strcend(register const char *s, register pchar c)
+{
+ for (;;)
+ {
+ if (*s == (char) c) return (char*) s;
+ if (!*s++) return (char*) s-1;
+ }
+}
+
+#endif
diff --git a/strings/strchr.c b/strings/strchr.c
new file mode 100644
index 00000000000..ef117d85635
--- /dev/null
+++ b/strings/strchr.c
@@ -0,0 +1,46 @@
+/* File : strchr.c
+ Author : Richard A. O'Keefe.
+ Michael Widenius: ifdef MC68000
+ Updated: 20 April 1984
+ Defines: strchr(), index()
+
+ strchr(s, c) returns a pointer to the first place in s where c
+ occurs, or NullS if c does not occur in s. This function is called
+ index in V7 and 4.?bsd systems; while not ideal the name is clearer
+ than strchr, so index remains in strings.h as a macro. NB: strchr
+ looks for single characters, not for sets or strings. To find the
+ NUL character which closes s, use strchr(s, '\0') or strend(s). The
+ parameter 'c' is declared 'int' so it will go in a register; if your
+ C compiler is happy with register _char_ change it to that.
+*/
+
+#include "strings.h"
+
+#if defined(MC68000) && defined(DS90)
+
+char* strchr(char *s, pchar c)
+{
+asm(" movl 4(a7),a0 ");
+asm(" movl 8(a7),d1 ");
+asm(".L2: movb (a0)+,d0 ");
+asm(" cmpb d0,d1 ");
+asm(" beq .L1 ");
+asm(" tstb d0 ");
+asm(" bne .L2 ");
+asm(" moveq #0,d0 ");
+asm(" rts ");
+asm(".L1: movl a0,d0 ");
+asm(" subql #1,d0 ");
+}
+#else
+
+char *strchr(register const char *s, register pchar c)
+{
+ for (;;)
+ {
+ if (*s == (char) c) return (char*) s;
+ if (!*s++) return NullS;
+ }
+}
+
+#endif
diff --git a/strings/strcmp.c b/strings/strcmp.c
new file mode 100644
index 00000000000..d911b2daa17
--- /dev/null
+++ b/strings/strcmp.c
@@ -0,0 +1,20 @@
+/* File : strcmp.c
+ Author : Richard A. O'Keefe.
+ Updated: 10 April 1984
+ Defines: strcmp()
+
+ strcmp(s, t) returns > 0, = 0, or < 0 when s > t, s = t, or s < t
+ according to the ordinary lexicographical order. To test for
+ equality, the macro streql(s,t) is clearer than !strcmp(s,t). Note
+ that if the string contains characters outside the range 0..127 the
+ result is machine-dependent; PDP-11s and VAXen use signed bytes,
+ some other machines use unsigned bytes.
+*/
+
+#include "strings.h"
+
+int strcmp(register const char *s, register const char *t)
+{
+ while (*s == *t++) if (!*s++) return 0;
+ return s[0]-t[-1];
+}
diff --git a/strings/strcont.c b/strings/strcont.c
new file mode 100644
index 00000000000..5c7d5d2e55f
--- /dev/null
+++ b/strings/strcont.c
@@ -0,0 +1,46 @@
+/* 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 */
+
+/* File : strcont.c
+ Author : Monty
+ Updated: 1988.07.27
+ Defines: strcont()
+
+ strcont(str, set) if str contanies any character in the string set.
+ The result is the position of the first found character in str, or NullS
+ if there isn't anything found.
+
+*/
+
+#include <global.h>
+#include "m_string.h"
+
+my_string strcont(reg1 const char *str,reg2 const char *set)
+{
+ reg3 my_string start = (my_string) set;
+
+ while (*str)
+ {
+ while (*set)
+ {
+ if (*set++ == *str)
+ return ((char*) str);
+ }
+ set=start; str++;
+ }
+ return (NullS);
+} /* strcont */
diff --git a/strings/strend-sparc.s b/strings/strend-sparc.s
new file mode 100644
index 00000000000..fd1dba4d36f
--- /dev/null
+++ b/strings/strend-sparc.s
@@ -0,0 +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,
+! but WITHOUT ANY WARRANTY; without even the implied warranty of
+! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+! Library General Public License for more details.
+!
+! You should 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
+
+ .file "strend-sparc.s"
+.section ".text"
+ .align 4
+ .global strend
+ .type strend,#function
+ .proc 0102
+strend:
+ ldsb [%o0], %g2 ! Handle first char differently to make
+.loop: ! a faster loop
+ add %o0, 1, %o0
+ cmp %g2, 0
+ bne,a .loop
+ ldsb [%o0], %g2
+ retl
+ sub %o0,1,%o0
+.strend_end:
+ .size strend,.strend_end-strend
+ .ident "Matt Wagner & Monty"
diff --git a/strings/strend.c b/strings/strend.c
new file mode 100644
index 00000000000..18b9d1fbd0d
--- /dev/null
+++ b/strings/strend.c
@@ -0,0 +1,33 @@
+/* File : strend.c
+ Author : Richard A. O'Keefe.
+ Updated: 23 April 1984
+ Defines: strend()
+
+ strend(s) returns a character pointer to the NUL which ends s. That
+ is, strend(s)-s == strlen(s). This is useful for adding things at
+ the end of strings. It is redundant, because strchr(s,'\0') could
+ be used instead, but this is clearer and faster.
+ Beware: the asm version works only if strlen(s) < 65535.
+*/
+
+#include <global.h>
+#include "m_string.h"
+
+#if VaxAsm
+
+char *strend(s)
+const char *s;
+{
+ asm("locc $0,$65535,*4(ap)");
+ asm("movl r1,r0");
+}
+
+#else /* ~VaxAsm */
+
+char *strend(register const char *s)
+{
+ while (*s++);
+ return (char*) (s-1);
+}
+
+#endif /* VaxAsm */
diff --git a/strings/strfill.c b/strings/strfill.c
new file mode 100644
index 00000000000..ef0ccb567d1
--- /dev/null
+++ b/strings/strfill.c
@@ -0,0 +1,36 @@
+/* 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 */
+
+/* File : strfill.c
+ Author : Monty
+ Updated: 1987.04.16
+ Defines: strfill()
+
+ strfill(dest, len, fill) makes a string of fill-characters. The result
+ string is of length == len. The des+len character is allways set to NULL.
+ strfill() returns pointer to dest+len;
+*/
+
+#include <global.h>
+#include "m_string.h"
+
+my_string strfill(my_string s,uint len,pchar fill)
+{
+ while (len--) *s++ = fill;
+ *(s) = '\0';
+ return(s);
+} /* strfill */
diff --git a/strings/string.doc b/strings/string.doc
new file mode 100644
index 00000000000..954f7226759
--- /dev/null
+++ b/strings/string.doc
@@ -0,0 +1,155 @@
+Speciella användbara nya string-rutiner:
+
+ 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.
+
+ bfill(dst, len, fill) moves "len" fill characters to "dst".
+ Thus to set a buffer to 80 spaces, do bfill(buff, 80, ' ').
+
+ bmove(dst, src, len) moves exactly "len" bytes from the source "src"
+ to the destination "dst". It does not check for NUL characters as
+ strncpy() and strnmov() do.
+
+ bmove_upp(dst, src, len) moves exactly "len" bytes from the source
+ "src-len" to the destination "dst-len" counting downwards.
+
+ bzero(dst, len) moves "len" 0 bytes to "dst".
+ Thus to clear a disc buffer to 0s do bzero(buffer, BUFSIZ).
+
+ int2str(dst, radix, val)
+ converts the (long) integer "val" to character form and moves it to
+ the destination string "dst" followed by a terminating NUL. The
+ result is normally a pointer to this NUL character, but if the radix
+ is dud the result will be NullS and nothing will be changed.
+ If radix is -2..-36, val is taken to be SIGNED.
+ If radix is 2.. 36, val is taken to be UNSIGNED.
+ That is, val is signed if and only if radix is. You will normally
+ use radix -10 only through itoa and ltoa, for radix 2, 8, or 16
+ unsigned is what you generally want.
+
+ m_ctype.h
+ A better inplementation of the UNIX ctype(3) library.
+ Notes: global.h should be included before ctype.h
+ - Se efter i filen \c\local\include\m_ctype.h
+ - Används istället för ctype.h för att klara internationella karakterer.
+
+ m_string.h
+ Använd instället för string.h för att supporta snabbare strängfunktioner.
+
+ strintstr(src, from, pat) looks for an instance of pat in src
+ backwards from pos from. pat is not a regex(3) pattern, it is a literal
+ string which must be matched exactly.
+ The result 0 if the pattern was not found else it is the start char of
+ the pattern counted from the begining of the string.
+
+ strappend(dest, len, fill) appends fill-characters to a string so that
+ the result length == len. If the string is longer than len it's
+ trunked. The des+len character is allways set to NULL.
+
+ strcat(s, t) concatenates t on the end of s. There had better be
+ enough room in the space s points to; strcat has no way to tell.
+ Note that strcat has to search for the end of s, so if you are doing
+ a lot of concatenating it may be better to use strmov, e.g.
+ strmov(strmov(strmov(strmov(s,a),b),c),d)
+ rather than
+ strcat(strcat(strcat(strcpy(s,a),b),c),d).
+ strcat returns the old value of s.
+ - Använd inte strcat, använd strmov (se ovan).
+
+ strcend(s, c) returns a pointer to the first place in s where c
+ occurs, or a pointer to the end-null of s if c does not occur in s.
+
+ strcont(str, set) if str contanies any character in the string set.
+ The result is the position of the first found character in str, or NullS
+ if there isn't anything found.
+
+ strend(s) returns a character pointer to the NUL which ends s. That
+ is, strend(s)-s == strlen(s). This is useful for adding things at
+ the end of strings. It is redundant, because strchr(s,'\0') could
+
+ strfill(dest, len, fill) makes a string of fill-characters. The result
+ string is of length == len. The des+len character is allways set to NULL.
+ strfill() returns pointer to dest+len;
+
+ strfind(src, pat) looks for an instance of pat in src. pat is not a
+ regex(3) pattern, it is a literal string which must be matched exactly.
+ The result is a pointer to the first character of the located instance,
+ or NullS if pat does not occur in src.
+
+ strinstr(src, pat) looks for an instance of pat in src. pat is not a
+ regex(3) pattern, it is a literal string which must be matched exactly.
+ The result 0 if the pattern was not found else it is the start char of
+ the pattern counted from the begining of the string.
+
+ strmake(dst,src,length) moves length characters, or until end, of src to
+ dst and appends a closing NUL to dst.
+ strmake() returns pointer to closing null;
+
+ strmov(dst, src) moves all the characters of src (including the
+ closing NUL) to dst, and returns a pointer to the new closing NUL in
+ dst. The similar UNIX routine strcpy returns the old value of dst,
+ which I have never found useful. strmov(strmov(dst,a),b) moves a//b
+ into dst, which seems useful.
+
+ strnmov(dst,src,length) moves length characters, or until end, of src to
+ dst and appends a closing NUL to dst if src is shorter than length.
+ The result is a pointer to the first NUL in dst, or is dst+n if dst was
+ truncated.
+
+ strrchr(s, c) returns a pointer to the last place in s where c
+ occurs, or NullS if c does not occur in s. This function is called
+ rindex in V7 and 4.?bsd systems.
+ strrchr looks for single characters, not for sets or strings.
+
+ strxmov(dst, src1, ..., srcn, NullS)
+ moves the concatenation of src1,...,srcn to dst, terminates it
+ with a NUL character, and returns a pointer to the terminating NUL.
+ It is just like strmov except that it concatenates multiple sources.
+ Beware: the last argument should be the null character pointer.
+ Take VERY great care not to omit it! Also be careful to use NullS
+ and NOT to use 0, as on some machines 0 is not the same size as a
+ character pointer, or not the same bit pattern as NullS.
+
+ strxnmov(dst, len, src1, ..., srcn, NullS)
+ moves the first len characters of the concatenation of src1,...,srcn
+ to dst. If there aren't that many characters, a NUL character will
+ be added to the end of dst to terminate it properly. This gives the
+ same effect as calling strxcpy(buff, src1, ..., srcn, NullS) with a
+ large enough buffer, and then calling strnmov(dst, buff, len).
+ It is just like strnmov except that it concatenates multiple sources.
+ Beware: the last argument should be the null character pointer.
+ Take VERY great care not to omit it! Also be careful to use NullS
+ and NOT to use 0, as on some machines 0 is not the same size as a
+ character pointer, or not the same bit pattern as NullS.
+
+ Note: strxnmov is like strnmov in that it always moves EXACTLY len
+ characters; dst will be padded on the right with NUL characters as
+ needed. strxncpy does the same. strxncat, like strncat, does NOT.
+
+
+I mysys:
+
+ stripp_sp(string str)
+ Strips end-space from string and returns new length.
+
+ strlength(const string str)
+ Return length of string with end-space:s not counted.
+
+ void caseup _A((string str,uint length));
+ void casedn _A((string str,uint length));
+ void caseup_str _A((string str));
+ void casedn_str _A((string str));
+ Converts strings or part of string to upper or lower-case.
+
+ void case_sort _A((string str,uint length));
+ Converts string to a string with can be compared with strcmp() to
+ get strings in rigth order.
+
+ string strcfind(str,search)
+ find string in another with no case_sensivity
+
+ my_strcasecmp(s,t)
+ Compare strings without regarding to case
+ - For many strings it quicker to forst use case_sort on all strings and
+ then compare them with strcmp().
diff --git a/strings/strings-not-used.h b/strings/strings-not-used.h
new file mode 100644
index 00000000000..fa4dff318f5
--- /dev/null
+++ b/strings/strings-not-used.h
@@ -0,0 +1,22 @@
+/* File : strings.h
+ Author : Richard A. O'Keefe.
+ Updated: 1 June 1984
+ Purpose: Header file for the "string(3C)" package.
+
+ All the routines in this package are the original work of
+ R.A.O'Keefe. Any resemblance between them and any routines in
+ licensed software is due entirely to these routines having been
+ written using the "man 3 string" UNIX manual page, or in some cases
+ the "man 1 sort" manual page as a specification. See the READ-ME to
+ find the conditions under which these routines may be used & copied.
+*/
+
+#ifndef NullS
+
+#include <global.h> /* Define standar vars */
+#include "m_string.h"
+
+#define NUL '\0'
+#define _AlphabetSize 256
+
+#endif /* NullS */
diff --git a/strings/strings-x86.s b/strings/strings-x86.s
new file mode 100644
index 00000000000..5d7cbde1b38
--- /dev/null
+++ b/strings/strings-x86.s
@@ -0,0 +1,406 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public 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 */
+
+.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 */
+ shrw $2,%cx
+ rep
+ movsl
+ movl %eax,%esi
+ movl %edx,%edi
+ ret
+.end:
+ .size bmove_allign,.end-bmove_allign
+
+ /* 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 */
+ 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 */
+ decl %esi
+ rep
+ 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 */
+
+.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 */
+ 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. */
+ rep
+ stosl /* (5 + 5n) */
+ movb $3,%cl /* (2) */
+ and %edx,%ecx /* (2) Fill in the odd bytes*/
+ rep
+ stosb /* Move last bytes if any */
+
+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 */
+
+.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 */
+ 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 */
+ 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 */
+ popl %esi
+ ret
+.strcont_end:
+ .size strcont,.strcont_end-strcont
+
+ /* 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 %eax,%ecx
+ decl %ecx /* ECX = -1 */
+ repne
+ scasb
+ movl %edi,%eax
+ 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 */
+
+.globl strfill
+ .type strfill,@function
+strfill:
+ pushl %edi
+ 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. */
+
+ 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 */
+ rep
+ stosb /* Move last bytes if any */
+
+ 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 */
+
+.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 */
+
+se_10: cmpb (%edi),%ah
+ jz se_20 /* Found char */
+ scasb
+ jnz se_10 /* Not end */
+ dec %edi /* Not found, point at end of string */
+se_20: movl %edi,%eax
+ movl %edx,%edi /* Restore */
+ ret
+.strcend_end:
+ .size strcend,.strcend_end-strcend
+
+ /* 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 */
+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 */
+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 */
+
+.globl strstr
+ .type strstr,@function
+
+strstr:
+ pushl %edi
+ pushl %esi
+ 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 */
+ jmp sf_10
+
+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 */
+ incl %esi
+ cmpb %al,%ah
+ 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 */
+ cmpsb
+ 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 */
+ popl %esi
+ popl %edi
+ ret
+.strstr_end:
+ .size strstr,.strstr_end-strstr
+
+
+ /* Find a substring in string, return index */
+ /* Arg: str,search */
+
+.globl strinstr
+ .type strinstr,@function
+
+strinstr:
+ pushl %ebp
+ movl %esp,%ebp
+ 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 */
+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 */
+
+.globl strmake
+ .type strmake,@function
+
+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 $ */
+ 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 */
+
+.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 */
+ popl %esi
+ popl %edi
+ ret
+.strnmov_end:
+ .size strnmov,.strnmov_end-strnmov
+
+
+.globl strmov
+ .type strmov,@function
+strmov:
+ 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 */
+smo_10: movb (%esi),%al
+ movsb /* move arg */
+ andb %al,%al
+ jnz smo_10 /* Not last */
+ movl %edi,%eax
+ dec %eax
+ movl %ecx,%esi /* Restore */
+ movl %edx,%edi
+ ret
+.strmov_end:
+ .size strmov,.strmov_end-strmov
+
+.globl strxmov
+ .type strxmov,@function
+strxmov:
+ movl %ebx,%edx /* Save %ebx, %esi and %edi */
+ mov %esi,%ecx
+ push %edi
+ leal 8(%esp),%ebx /* Get destination */
+ movl (%ebx),%edi
+ xorb %al,%al
+ jmp next_str /* Handle source ebx+4 */
+
+start_str:
+ movsb
+ cmpb -1(%edi),%al
+ jne start_str
+ 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 */
+
+ movl %edi,%eax /* Return ptr to ASCII 0 */
+ pop %edi /* Restore registers */
+ movl %ecx,%esi
+ movl %edx,%ebx
+ ret
+.strxmov_end:
+ .size strxmov,strxmov_end-strxmov
diff --git a/strings/strings.asm b/strings/strings.asm
new file mode 100644
index 00000000000..43bc23fa965
--- /dev/null
+++ b/strings/strings.asm
@@ -0,0 +1,1060 @@
+; 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 if you don't have a macro assembler (like MASM) to compile
+; this file, you can instead compile all *.c files in the string
+; directory.
+
+ TITLE Stringfunctions that we use often at MSDOS / Intel 8086
+
+ifndef M_I386
+ .8087
+ DOSSEG
+ .MODEL LARGE
+ .CODE
+
+ ;
+ ; Some macros
+ ;
+
+q_movs MACRO ; as rep movsb but quicker
+ shr cx,1
+ rep movsw ; Move 2 bytes at a time
+ adc cx,cx
+ rep movsb ; Move last byte if any
+ ENDM
+
+q_stos MACRO ; as rep stosb but quicker
+ mov ah,al ; For word store
+ shr cx,1
+ rep stosw ; Move 2 bytes at a time
+ adc cx,cx
+ rep stosb ; Move last byte if any
+ ENDM
+
+ifndef ZTC ; If not using ZORTECH compiler
+ ;
+ ; Compare memory
+ ; Args: s1,s2,length
+ ;
+
+ PUBLIC _bcmp
+_bcmp PROC
+ mov bx,bp ; Save bp
+ mov dx,di ; Save di
+ mov bp,sp
+ push ds
+ push si
+ les di,DWORD PTR [bp+8] ; s2
+ lds si,DWORD PTR [bp+4] ; s1
+ mov cx,WORD PTR [bp+12] ; Length of memory-area
+ jcxz @F ; Length = 0, return same
+; cld ; Work uppward
+ repe cmpsb ; Compare strings
+ jz @F ; Match found
+ inc cx ; return matchpoint +1
+@@: mov ax,cx ; Return 0 if match, else pos from end
+ pop si
+ pop ds
+ mov di,dx
+ mov bp,bx
+ ret
+_bcmp ENDP
+
+ ;
+ ; Find a char in a string
+ ; Arg: str,char
+ ; Ret: pointer to found char or NullS
+ ;
+
+ifdef better_stringfunctions ; Breaks window linkage (broken linking)
+
+ PUBLIC _strchr
+_strchr PROC
+ mov bx,bp ; Save bp and di
+ mov dx,di
+ mov bp,sp
+ les di,DWORD PTR [bp+4] ; str
+ mov ah,BYTE PTR [bp+8] ; search
+ xor al,al ; for scasb to find end
+
+@@: cmp ah,es:[di]
+ jz @F ; Found char
+ scasb
+ jnz @B ; Not end
+ xor di,di ; Not found
+ mov es,di
+@@: mov ax,di
+ mov di,dx ; Restore
+ mov dx,es ; Seg adr
+ mov bp,bx ; Restore
+ ret
+_strchr ENDP
+
+ ;
+ ; Find length of string
+ ; arg: str
+ ; ret: length
+ ;
+
+ PUBLIC _strlen
+_strlen PROC
+ mov bx,sp
+ mov dx,di
+ les di,DWORD PTR ss:[bx+4] ; Str
+ xor al,al ; Find end of string
+ mov cx,-1
+; cld
+ repne scasb ; Find strend or length
+ inc cx ; Calc strlength
+ not cx
+ mov ax,cx
+ mov di,dx ; Restore register
+ ret
+_strlen ENDP
+
+endif
+
+ ;
+ ; Move a string
+ ; arg: dst,src
+ ; ret: end-null of to
+ ;
+
+ PUBLIC _strmov
+_strmov PROC
+ mov bx,bp
+ mov cx,si
+ mov bp,sp
+ push ds
+ push di
+ les di,DWORD PTR [bp+4] ; dst
+ lds si,DWORD PTR [bp+8] ; src
+; cld
+@@: mov al,ds:[si]
+ movsb ; move arg
+ and al,al
+ jnz @B ; Not last
+ lea ax,WORD PTR [di-1] ; Set DX:AX to point at last null
+ mov dx,es
+ pop di
+ pop ds
+ mov si,cx
+ mov bp,bx
+ ret
+_strmov ENDP
+
+ ;
+ ; Fill a area of memory with a walue
+ ; Args: to,length,fillchar
+ ;
+
+ PUBLIC _bfill
+_bfill PROC
+ mov bx,sp ; Get args through BX
+ mov al,BYTE PTR ss:[bx+10] ; Fill
+bfill_10:
+ mov dx,di ; Save di
+ les di,DWORD PTR ss:[bx+4] ; Memory pointer
+ mov cx,WORD PTR ss:[bx+8] ; Length
+; cld
+ q_stos
+ mov di,dx
+ ret
+_bfill ENDP
+
+ ;
+ ; Fill a area with null
+ ; Args: to,length
+
+ PUBLIC _bzero
+_bzero PROC
+ mov bx,sp ; Get args through BX
+ mov al,0 ; Fill with null
+ jmp short bfill_10
+_bzero ENDP
+
+endif ; ZTC
+
+ ;
+ ; Move a memory area
+ ; Args: to,from,length
+ ;
+
+ PUBLIC _bmove
+_bmove PROC
+ mov bx,bp
+ mov dx,di
+ mov ax,si
+ mov bp,sp
+ push ds
+ lds si,DWORD PTR [bp+8] ; from
+ les di,DWORD PTR [bp+4] ; to
+ mov cx,WORD PTR [bp+12] ; Length of memory-area
+; cld ; Work uppward
+ rep movsb ; Not q_movs because overlap ?
+ pop ds
+ mov si,ax
+ mov di,dx
+ mov bp,bx
+ ret
+_bmove ENDP
+
+ ;
+ ; Move a alligned, not overlapped, by (long) divided memory area
+ ; Args: to,from,length
+ ;
+
+ PUBLIC _bmove_allign
+_bmove_allign PROC
+ mov bx,bp
+ mov dx,di
+ mov ax,si
+ mov bp,sp
+ push ds
+ lds si,DWORD PTR [bp+8] ; from
+ les di,DWORD PTR [bp+4] ; to
+ mov cx,WORD PTR [bp+12] ; Length of memory-area
+; cld ; Work uppward
+ inc cx ; fix if not divisible with word
+ shr cx,1
+ rep movsw ; Move 2 bytes at a time
+ pop ds
+ mov si,ax
+ mov di,dx
+ mov bp,bx
+ ret
+_bmove_allign ENDP
+
+ ;
+ ; Move a string from higher to lower
+ ; Arg from+1,to+1,length
+ ;
+
+ PUBLIC _bmove_upp
+_bmove_upp PROC
+ mov bx,bp
+ mov dx,di
+ mov ax,si
+ mov bp,sp
+ push ds
+ lds si,DWORD PTR [bp+8] ; from
+ les di,DWORD PTR [bp+4] ; to
+ mov cx,WORD PTR [bp+12] ; Length of memory-area
+ dec di ; Don't move last arg
+ dec si
+ std ; Work downward
+ rep movsb ; Not q_movs because overlap ?
+ cld ; C compilator want cld
+ pop ds
+ mov si,ax
+ mov di,dx
+ mov bp,bx
+ ret
+_bmove_upp ENDP
+
+ ;
+ ; Append fillchars to string
+ ; Args: dest,len,fill
+ ;
+
+ PUBLIC _strappend
+_strappend PROC
+ mov bx,bp
+ mov dx,di
+ mov bp,sp
+ les di,DWORD PTR [bp+4] ; Memory pointer
+ mov cx,WORD PTR [bp+8] ; Length
+ sub al,al ; Find end of string
+; cld
+ repne scasb
+ jnz sa_99 ; String to long, shorten it
+ mov al,BYTE PTR [bp+10] ; Fillchar
+ dec di ; Point at end null
+ inc cx ; rep made one dec for null-char
+ q_stos ; Store al in string
+sa_99: mov BYTE PTR es:[di],0 ; End of string
+ mov di,dx
+ mov bp,bx
+ ret
+_strappend ENDP
+
+ ;
+ ; Find if string contains any char in another string
+ ; Arg: str,set
+ ; Ret: Pointer to first found char in str
+ ;
+
+ PUBLIC _strcont
+_strcont PROC
+ mov bx,bp ; Save bp and di in regs
+ mov dx,di
+ mov bp,sp
+ push ds
+ push si
+ lds si,DWORD PTR [bp+4] ; str
+ les di,DWORD PTR [bp+8] ; Set
+ mov cx,di ; Save for loop
+ xor ah,ah ; For endtest
+ jmp sc_60
+
+sc_10: scasb
+ jz sc_fo ; Found char
+sc_20: cmp ah,es:[di] ; Test if null
+ jnz sc_10 ; Not end of set yet
+ inc si ; Next char in str
+ mov di,cx ; es:di = Set
+sc_60: mov al,ds:[si] ; Test if this char exist
+ and al,al
+ jnz sc_20 ; Not end of string
+ sub si,si ; Return Null
+ mov ds,si
+sc_fo: mov ax,si ; Char found here
+ mov di,dx ; Restore
+ mov dx,ds ; Seg of found char
+ pop si
+ pop ds
+ mov bp,bx
+ ret
+_strcont ENDP
+
+ ;
+ ; Found end of string
+ ; Arg: str
+ ; ret: Pointer to end null
+ ;
+
+ PUBLIC _strend
+_strend PROC
+ mov bx,sp
+ mov dx,di ; Save
+ les di,DWORD PTR ss:[bx+4] ; str
+ mov cx,-1
+ sub al,al ; Find end of string
+; cld
+ repne scasb
+ lea ax,WORD PTR [di-1] ; Endpos i DX:AX
+ mov di,dx ; Restore
+ mov dx,es
+ ret
+_strend ENDP
+
+ ;
+ ; Make a string with len fill-chars and endnull
+ ; Args: dest,len,fill
+ ; Ret: dest+len
+ ;
+
+ PUBLIC _strfill
+_strfill PROC
+ mov bx,bp ; Save sp
+ mov bp,sp
+ push di
+ les di,DWORD PTR [bp+4] ; Memory pointer
+ mov cx,WORD PTR [bp+8] ; Length
+ mov al,BYTE PTR [bp+10] ; Fill
+; cld
+ q_stos
+ mov BYTE PTR es:[di],0 ; End NULL
+ mov ax,di ; End i DX:AX
+ mov dx,es
+ pop di
+ mov bp,bx
+ ret
+_strfill ENDP
+
+ ;
+ ; Find a char in or end of a string
+ ; Arg: str,char
+ ; Ret: pointer to found char or NullS
+ ;
+
+ PUBLIC _strcend
+_strcend PROC
+ mov bx,bp ; Save bp and di
+ mov dx,di
+ mov bp,sp
+ les di,DWORD PTR [bp+4] ; str
+ mov ah,BYTE PTR [bp+8] ; search
+ xor al,al ; for scasb to find end
+
+@@: cmp ah,es:[di]
+ jz @F ; Found char
+ scasb
+ jnz @B ; Not end
+ dec di ; Not found, point at end of string
+@@: mov ax,di
+ mov di,dx ; Restore
+ mov dx,es ; Seg adr
+ mov bp,bx ; Restore
+ ret
+_strcend ENDP
+
+ ;
+ ; Test if string has a given suffix
+ ;
+
+PUBLIC _is_prefix
+_is_prefix PROC
+ mov dx,di ; Save di
+ mov bx,sp ; Arguments through bx
+ push ds
+ push si
+ les di,DWORD PTR ss:[bx+8] ; s2
+ lds si,DWORD PTR ss:[bx+4] ; s1
+ mov ax,1 ; Ok and zero-test
+; cld ; Work uppward
+@@: cmp ah,es:[di]
+ jz suf_ok ; End of string; found suffix
+ cmpsb ; Compare strings
+ jz @B ; Same, possible prefix
+ xor ax,ax ; Not suffix
+suf_ok: pop si
+ pop ds
+ mov di,dx
+ ret
+_is_prefix ENDP
+
+ ;
+ ; Find a substring in string
+ ; Arg: str,search
+ ;
+
+ PUBLIC _strstr
+_strstr PROC
+ mov bx,bp
+ mov bp,sp
+ push ds
+ push di
+ push si
+ lds si,DWORD PTR [bp+4] ; str
+ les di,DWORD PTR [bp+8] ; search
+ mov cx,di
+ inc cx ; CX = search+1
+ mov ah,es:[di] ; AH = First char in search
+ jmp sf_10
+
+sf_00: mov si,dx ; si = Current str-pos
+sf_10: mov al,ds:[si] ; Test if this char exist
+ and al,al
+ jz sf_90 ; End of string, didn't find search
+ inc si
+ cmp al,ah
+ jnz sf_10 ; Didn't find first char, continue
+ mov dx,si ; Save str-pos in DX
+ mov di,cx
+sf_20: cmp BYTE PTR es:[di],0
+ jz sf_fo ; Found substring
+ cmpsb
+ jz sf_20 ; Char ok
+ jmp sf_00 ; Next str-pos
+
+sf_90: sub dx,dx ; Return Null
+ mov ds,dx
+ inc dx ; Because of following dec
+sf_fo: mov ax,dx ; Char found here
+ dec ax ; Pointed one after
+ mov dx,ds
+ pop si
+ pop di ; End
+ pop ds
+ mov bp,bx
+ ret
+_strstr ENDP
+
+ ;
+ ; Find a substring in string, return index
+ ; Arg: str,search
+ ;
+
+ PUBLIC _strinstr
+_strinstr PROC
+ push bp
+ mov bp,sp
+ push di
+ les di,DWORD PTR [bp+10] ; search
+ push es
+ push di
+ les di,DWORD PTR [bp+6] ; str
+ push es
+ push di
+ call _strstr
+ mov cx,ax
+ or cx,dx
+ jz si_99
+ sub ax,di ; Pos from start
+ inc ax ; And first pos = 1
+si_99: add sp,8
+ pop di
+ pop bp
+ ret
+_strinstr ENDP
+
+ ;
+ ; Make a string of len length from another string
+ ; Arg: dst,src,length
+ ; ret: end of dst
+ ;
+
+ PUBLIC _strmake
+_strmake PROC
+ mov bx,bp
+ mov bp,sp
+ push ds
+ push di
+ push si
+ les di,DWORD PTR [bp+4] ; dst
+ lds si,DWORD PTR [bp+8] ; src
+ mov cx,WORD PTR [bp+12] ; Length of memory-area
+ xor al,al ; For test of end-null
+ jcxz sm_90 ; Nothing to move, put zero at end.
+; cld ; Work uppward
+
+@@: cmp al,ds:[si] ; Next char to move
+ movsb ; move arg
+ jz sm_99 ; last char, we are ready
+ loop @B ; Continue moving
+sm_90: mov BYTE PTR es:[di],al ; Set end pos
+ inc di ; Fix that di points at end null
+sm_99: dec di ; di points now at end null
+ mov ax,di ; Ret value in DX:AX
+ mov dx,es
+ pop si
+ pop di
+ pop ds
+ mov bp,bx
+ ret
+_strmake ENDP
+
+ ;
+ ; Find length of string with maxlength
+ ; arg: str,maxlength
+ ; ret: length
+ ;
+
+ PUBLIC _strnlen
+_strnlen PROC
+ mov bx,bp
+ mov bp,sp
+ push di
+ les di,DWORD PTR [bp+4] ; Str
+ mov cx,WORD PTR [bp+8] ; length
+ mov dx,di ; Save str to calc length
+ jcxz sn_10 ; Length = 0
+ xor al,al ; Find end of string
+; cld
+ repne scasb ; Find strend or length
+ jnz sn_10
+ dec di ; DI points at last null
+sn_10: mov ax,di
+ sub ax,dx ; Ax = length
+ pop di
+ mov bp,bx
+ ret
+_strnlen ENDP
+
+ ;
+ ; Move a string with max len chars
+ ; arg: dst,src,len
+ ; ret: pos to first null or dst+len
+
+ PUBLIC _strnmov
+_strnmov PROC
+ mov bx,bp
+ mov bp,sp
+ push ds
+ push di
+ push si
+ les di,DWORD PTR [bp+4] ; dst
+ lds si,DWORD PTR [bp+8] ; src
+ mov cx,WORD PTR [bp+12] ; length
+ jcxz snm_99 ; Nothing to do
+ xor al,al ; For test of end-null
+; cld
+
+@@: cmp al,ds:[si] ; Next char to move
+ movsb ; move arg
+ jz snm_20 ; last char, fill with null
+ loop @B ; Continue moving
+ inc di ; Point two after last
+snm_20: dec di ; Point at first null (or last+1)
+snm_99: mov ax,di ; Pointer at last char
+ mov dx,es ; To-segment
+ pop si
+ pop di
+ pop ds
+ mov bp,bx ; Restore
+ ret
+_strnmov ENDP
+
+else ; M_I386
+
+include macros.asm
+
+q_stos MACRO ; as rep stosb but quicker, Uses edx
+ mov ah,al ;(2) Set up a 32 bit pattern.
+ mov edx,eax ;(2)
+ shl edx,16 ;(3)
+ or eax,edx ;(2) EAX has the 32 bit pattern.
+
+ mov edx,ecx ;(2) Save the count of bytes.
+ shr ecx,2 ;(2) Number of dwords.
+ rep stosd ;(5 + 5n)
+ mov cl,3 ;(2)
+ and ecx,edx ;(2) Fill in the remaining odd bytes.
+ rep stosb ; Move last bytes if any
+ ENDM
+
+fix_es MACRO fix_cld ; Load ES if neaded
+ ife ESeqDS
+ mov ax,ds
+ mov es,ax
+ endif
+ ifnb <fix_cld>
+ cld
+ endif
+ ENDM
+
+ ;
+ ; Move a memory area
+ ; Args: to,from,length
+ ; Acts as one byte was moved a-time from dst to source.
+ ;
+
+ begcode bmove
+ public _bmove
+_bmove proc near
+ fix_es 1
+ mov edx,edi
+ mov eax,esi
+ mov edi,P-SIZEPTR[esp] ;p1
+ mov esi,P[esp] ;p2
+ mov ecx,P+SIZEPTR[esp]
+ rep movsb ; Not q_movs because overlap ?
+ mov esi,eax
+ mov edi,edx
+ ret
+_bmove ENDP
+ endcode bmove
+
+ ;
+ ; Move a alligned, not overlapped, by (long) divided memory area
+ ; Args: to,from,length
+ ;
+
+ begcode bmove_allign
+ public _bmove_allign
+_bmove_allign proc near
+ fix_es 1
+ mov edx,edi
+ mov eax,esi
+ mov edi,P-SIZEPTR[esp] ;to
+ mov esi,P[esp] ;from
+ mov ecx,P+SIZEPTR[esp] ;length
+ add cx,3 ;fix if not divisible with long
+ shr cx,2
+ rep movsd
+ mov esi,eax
+ mov edi,edx
+ ret
+_bmove_allign ENDP
+ endcode bmove_allign
+
+ ;
+ ; Move a string from higher to lower
+ ; Arg from+1,to+1,length
+ ;
+
+ begcode bmove_upp
+ public _bmove_upp
+_bmove_upp proc near
+ fix_es
+ std ; Work downward
+ mov edx,edi
+ mov eax,esi
+ mov edi,P-SIZEPTR[esp] ;p1
+ mov esi,P[esp] ;p2
+ mov ecx,P+SIZEPTR[esp]
+ dec edi ; Don't move last arg
+ dec esi
+ rep movsb ; One byte a time because overlap !
+ cld ; C compilator wants cld
+ mov esi,eax
+ mov edi,edx
+ ret
+_bmove_upp ENDP
+ endcode bmove_upp
+
+ ;
+ ; Append fillchars to string
+ ; Args: dest,len,fill
+ ;
+
+ begcode strappend
+ public _strappend
+_strappend proc near
+ push ebp
+ mov ebp,esp
+ fix_es 1
+ push edi
+ mov edi,P[ebp] ; Memory pointer
+ mov ecx,P+SIZEPTR[ebp] ; Length
+ clr eax ; Find end of string
+ repne scasb
+ jnz sa_99 ; String to long, shorten it
+ movzx eax,byte ptr P+(2*SIZEPTR)[ebp] ; Fillchar
+ dec edi ; Point at end null
+ inc ecx ; rep made one dec for null-char
+ q_stos ; Store al in string
+sa_99: mov BYTE PTR [edi],0 ; End of string
+ pop edi
+ pop ebp
+ ret
+_strappend ENDP
+ endcode strappend
+
+ ;
+ ; Find if string contains any char in another string
+ ; Arg: str,set
+ ; Ret: Pointer to first found char in str
+ ;
+
+ begcode strcont
+ PUBLIC _strcont
+_strcont proc near
+ push ebp
+ mov ebp,esp
+ fix_es 1
+ mov edx,edi
+ push esi
+ mov esi,P[ebp] ; str
+ mov ecx,P+SIZEPTR[ebp] ; Set
+ clr ah ; For endtest
+ jmps sc_60
+
+sc_10: scasb
+ jz sc_fo ; Found char
+sc_20: cmp ah,[edi] ; Test if null
+ jnz sc_10 ; Not end of set yet
+ inc esi ; Next char in str
+sc_60: mov edi,ecx ; edi = Set
+ mov al,[esi] ; Test if this char exist
+ and al,al
+ jnz sc_20 ; Not end of string
+ clr esi ; Return Null
+sc_fo: mov eax,esi ; Char found here
+ mov edi,edx ; Restore
+ pop esi
+ pop ebp
+ ret
+_strcont ENDP
+ endcode strcont
+
+ ;
+ ; Found end of string
+ ; Arg: str
+ ; ret: Pointer to end null
+ ;
+
+ begcode strend
+ public _strend
+_strend proc near
+ fix_es 1
+ mov edx,edi ; Save
+ mov edi,P-SIZEPTR[esp] ; str
+ clr eax ; Find end of string
+ mov ecx,eax
+ dec ecx ; ECX = -1
+ repne scasb
+ mov eax,edi
+ dec eax
+ mov edi,edx ; Restore
+ ret
+_strend endp
+ endcode strend
+
+ ;
+ ; Make a string with len fill-chars and endnull
+ ; Args: dest,len,fill
+ ; Ret: dest+len
+ ;
+
+ begcode strfill
+ public _strfill
+_strfill proc near
+ push ebp
+ mov ebp,esp
+ fix_es 1
+ push edi
+ mov edi,P[ebp] ; Memory pointer
+ mov ecx,P+SIZEPTR[ebp] ; Length
+ movzx eax,byte ptr P+(2*SIZEPTR)[ebp] ; Fill
+ q_stos
+ mov BYTE PTR [edi],0 ; End NULL
+ mov eax,edi ; End i DX:AX
+ pop edi
+ pop ebp
+ ret
+_strfill endp
+ endcode strfill
+
+ ;
+ ; Find a char in or end of a string
+ ; Arg: str,char
+ ; Ret: pointer to found char or NullS
+ ;
+
+ begcode strcend
+ public _strcend
+_strcend proc near
+ push ebp
+ mov ebp,esp
+ fix_es 1
+ mov edx,edi
+ mov edi,P[ebp] ; str
+ mov ah,P+SIZEPTR[ebp] ; search
+ clr al ; for scasb to find end
+
+@@: cmp ah,[edi]
+ jz @F ; Found char
+ scasb
+ jnz @B ; Not end
+ dec edi ; Not found, point at end of string
+@@: mov eax,edi
+ mov edi,edx ; Restore
+ pop ebp
+ ret
+_strcend ENDP
+ endcode strcend
+
+ ;
+ ; Test if string has a given suffix
+ ;
+
+ begcode is_prefix
+ public _is_prefix
+_is_prefix proc near
+ fix_es 1
+ mov edx,edi ; Save edi
+ mov eax,esi ; Save esi
+ mov esi,P[esp] ; get suffix
+ mov edi,P-SIZEPTR[esp] ; s1
+ push eax ; push esi
+ mov eax,1 ; Ok and zero-test
+@@: cmp ah,[esi]
+ jz suf_ok ; End of string; found suffix
+ cmpsb ; Compare strings
+ jz @B ; Same, possible prefix
+ xor eax,eax ; Not suffix
+suf_ok: pop esi
+ mov edi,edx
+ ret
+_is_prefix endp
+ endcode _is_prefix
+
+ ;
+ ; Find a substring in string
+ ; Arg: str,search
+ ;
+
+ begcode strstr
+ public _strstr
+_strstr proc near
+ push ebp
+ mov ebp,esp
+ fix_es 1
+ push EDI
+ push ESI
+ mov esi,P[ebp] ; str
+ mov edi,P+SIZEPTR[ebp] ; search
+ mov ecx,edi
+ inc ecx ; ECX = search+1
+ mov ah,[edi] ; AH = First char in search
+ jmps sf_10
+
+sf_00: mov esi,edx ; si = Current str-pos
+sf_10: mov al,[esi] ; Test if this char exist
+ and al,al
+ jz sf_90 ; End of string, didn't find search
+ inc esi
+ cmp al,ah
+ jnz sf_10 ; Didn't find first char, continue
+ mov edx,esi ; Save str-pos in EDX
+ mov edi,ecx
+sf_20: cmp BYTE PTR [edi],0
+ jz sf_fo ; Found substring
+ cmpsb
+ jz sf_20 ; Char ok
+ jmps sf_00 ; Next str-pos
+
+sf_90: mov edx,1 ; Return Null
+sf_fo: mov eax,edx ; Char found here
+ dec eax ; Pointed one after
+ pop ESI
+ pop EDI
+ pop ebp
+ ret
+_strstr endp
+ endcode strstr
+
+ ;
+ ; Find a substring in string, return index
+ ; Arg: str,search
+ ;
+
+ begcode strinstr
+ public _strinstr
+_strinstr proc near
+ push ebp
+ mov ebp,esp
+ push P+SIZEPTR[ebp] ; search
+ push P[ebp] ; str
+ call _strstr
+ add esp,SIZEPTR*2
+ or eax,eax
+ jz si_99 ; Not found, return NULL
+ sub eax,P[ebp] ; Pos from start
+ inc eax ; And first pos = 1
+si_99: pop ebp
+ ret
+_strinstr endp
+ endcode strinstr
+
+ ;
+ ; Make a string of len length from another string
+ ; Arg: dst,src,length
+ ; ret: end of dst
+ ;
+
+ begcode strmake
+ public _strmake
+_strmake proc near
+ push ebp
+ mov ebp,esp
+ fix_es 1
+ push EDI
+ push ESI
+ mov edi,P[ebp] ; dst
+ mov esi,P+SIZEPTR[ebp] ; src
+ mov ecx,P+SIZEPTR*2[ebp] ; Length of memory-area
+ clr al ; For test of end-null
+ jcxz sm_90 ; Nothing to move, put zero at end.
+
+@@: cmp al,[esi] ; Next char to move
+ movsb ; move arg
+ jz sm_99 ; last char, we are ready
+ loop @B ; Continue moving
+sm_90: mov BYTE PTR [edi],al ; Set end pos
+ inc edi ; Fix that di points at end null
+sm_99: dec edi ; di points now at end null
+ mov eax,edi ; Ret value in DX:AX
+ pop ESI
+ pop EDI
+ pop ebp
+ ret
+_strmake ENDP
+ endcode strmake
+
+ ;
+ ; Find length of string with maxlength
+ ; arg: str,maxlength
+ ; ret: length
+ ;
+
+ begcode strnlen
+ public _strnlen
+_strnlen proc near
+ push ebp
+ mov ebp,esp
+ fix_es 1
+ push edi
+ mov edi,P[ebp] ; Str
+ mov ecx,P+SIZEPTR[ebp] ; length
+ mov edx,edi ; Save str to calc length
+ jcxz sn_10 ; Length = 0
+ clr al ; Find end of string
+ repne scasb ; Find strend or length
+ jnz sn_10
+ dec edi ; DI points at last null
+sn_10: mov eax,edi
+ sub eax,edx ; Ax = length
+ pop edi
+ pop ebp
+ ret
+_strnlen ENDP
+ endcode strnlen
+
+ ;
+ ; Move a string with max len chars
+ ; arg: dst,src,len
+ ; ret: pos to first null or dst+len
+
+ begcode strnmov
+ public _strnmov
+_strnmov PROC near
+ push ebp
+ mov ebp,esp
+ fix_es 1
+ push EDI
+ push ESI
+ mov edi,P[ebp] ; dst
+ mov esi,P+SIZEPTR[ebp] ; src
+ mov ecx,P+(SIZEPTR*2)[ebp] ; length
+ jcxz snm_99 ; Nothing to do
+ clr al ; For test of end-null
+
+@@: cmp al,[esi] ; Next char to move
+ movsb ; move arg
+ jz snm_20 ; last char, fill with null
+ loop @B ; Continue moving
+ inc edi ; Point two after last
+snm_20: dec edi ; Point at first null (or last+1)
+snm_99: mov eax,edi ; Pointer at last char
+ pop ESI
+ pop EDI
+ pop ebp
+ ret
+_strnmov ENDP
+ endcode strnmov
+
+;
+; Zortech has this one in standard library
+;
+
+ begcode strmov
+ public _strmov
+_strmov proc near
+ mov ecx,esi ; Save old esi and edi
+ mov edx,edi
+ mov esi,P[esp] ; get source pointer (s2)
+ mov edi,P-SIZEPTR[esp] ; EDI -> s1
+ fix_es 1
+@@: mov al,[esi]
+ movsb ; move arg
+ and al,al
+ jnz @B ; Not last
+ mov eax,edi
+ dec eax
+ mov esi,ecx ; Restore args
+ mov edi,edx
+ ret
+_strmov endp
+ endcode strmov
+
+endif ; M_I386
+
+ END
diff --git a/strings/strinstr-sparc.s b/strings/strinstr-sparc.s
new file mode 100644
index 00000000000..b9881743683
--- /dev/null
+++ b/strings/strinstr-sparc.s
@@ -0,0 +1,43 @@
+! 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
+
+ .file "strinstr-sparc.s"
+.section ".text"
+ .align 4
+ .global strinstr
+ .type strinstr,#function
+ .proc 0102
+strinstr:
+ save %sp,-96,%sp
+ or %g0,%i1,%o1
+ call strstr,2 ! Result = %o0
+ or %g0,%i0,%o0
+ orcc %g0,%o0,%o0
+ bne .end
+ sub %o0,%i0,%i0
+ ret
+ restore %g0,%g0,%o0
+.end:
+ ret
+ restore %i0,1,%o0 ! Offset for return value is from 1
+
+.strinstr_end:
+ .size strinstr,.strinstr_end-strinstr
+ .ident "Matt Wagner & Monty"
+
+
+
diff --git a/strings/strinstr.c b/strings/strinstr.c
new file mode 100644
index 00000000000..e1d502f4004
--- /dev/null
+++ b/strings/strinstr.c
@@ -0,0 +1,50 @@
+/* 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 */
+
+/* File : strinstr.c
+ Author : Monty & David
+ Updated: 1986.12.08
+ Defines: strinstr()
+
+ strinstr(src, pat) looks for an instance of pat in src. pat is not a
+ regex(3) pattern, it is a literal string which must be matched exactly.
+ The result 0 if the pattern was not found else it is the start char of
+ the pattern counted from the beginning of the string, where the first
+ char is 1.
+*/
+
+#include <global.h>
+#include "m_string.h"
+
+uint strinstr(reg1 const char *str,reg4 const char *search)
+{
+ reg2 my_string i,j;
+ my_string start = (my_string) str;
+
+ skipp:
+ while (*str != '\0')
+ {
+ if (*str++ == *search)
+ {
+ i=(my_string) str; j= (my_string) search+1;
+ while (*j)
+ if (*i++ != *j++) goto skipp;
+ return ((uint) (str - start));
+ }
+ }
+ return (0);
+}
diff --git a/strings/strlen.c b/strings/strlen.c
new file mode 100644
index 00000000000..c142a7f2b14
--- /dev/null
+++ b/strings/strlen.c
@@ -0,0 +1,50 @@
+/* File : strlen.c
+ Author : Richard A. O'Keefe. / Monty
+ Michael Widenius; ifdef MC68000
+ Updated: 1986-11-30
+ Defines: strlen()
+
+ strlen(s) returns the number of characters in s, that is, the number
+ of non-NUL characters found before the closing NULEosCh. Note: some
+ non-standard C compilers for 32-bit machines take int to be 16 bits,
+ either put up with short strings or change int to long throughout
+ this package. Better yet, BOYCOTT such shoddy compilers.
+ Beware: the asm version works only if strlen(s) < 65536.
+*/
+
+#include "strings.h"
+
+#if VaxAsm
+
+size_s strlen(char *s)
+{
+ asm("locc $0,$65535,*4(ap)");
+ asm("subl3 r0,$65535,r0");
+}
+
+#else
+#if defined(MC68000) && defined(DS90)
+
+size_s strlen(char *s)
+{
+asm(" movl 4(a7),a0 ");
+asm(" movl a0,a1 ");
+asm(".L4: tstb (a0)+ ");
+asm(" jne .L4 ");
+asm(" movl a0,d0 ");
+asm(" subl a1,d0 ");
+asm(" subql #1,d0 ");
+}
+#else
+
+size_s strlen(register char *s)
+{
+ register char *startpos;
+
+ startpos = s;
+ while (*s++);
+ return ((size_s) (s-startpos-1));
+}
+
+#endif
+#endif
diff --git a/strings/strmake-sparc.s b/strings/strmake-sparc.s
new file mode 100644
index 00000000000..9fe72a9f9a2
--- /dev/null
+++ b/strings/strmake-sparc.s
@@ -0,0 +1,43 @@
+! 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
+
+ .file "strmake-sparc.s"
+.section ".text"
+ .align 4
+ .global strmake
+ .type strmake,#function
+ .proc 0102
+strmake:
+ orcc %g0,%o2,%g0
+ be,a .end
+ nop
+ ldsb [%o1],%g2
+.loop:
+ stb %g2,[%o0]
+ cmp %g2,0
+ be .end ! Jump to end on end of string
+ add %o1,1,%o1
+ add %o0,1,%o0
+ subcc %o2,1,%o2
+ bne,a .loop
+ ldsb [%o1],%g2
+.end:
+ retl
+ stb %g0,[%o0]
+.strmake_end:
+ .size strmake,.strmake_end-strmake
+ .ident "Matt Wagner & Monty"
diff --git a/strings/strmake.c b/strings/strmake.c
new file mode 100644
index 00000000000..d4edce689a5
--- /dev/null
+++ b/strings/strmake.c
@@ -0,0 +1,53 @@
+/* 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 */
+
+/* File : strmake.c
+ Author : Michael Widenius
+ Updated: 20 Jul 1984
+ Defines: strmake()
+
+ strmake(dst,src,length) moves length characters, or until end, of src to
+ dst and appends a closing NUL to dst.
+ strmake() returns pointer to closing null;
+*/
+
+#include <global.h>
+#include "m_string.h"
+
+#ifdef BAD_STRING_COMPILER
+
+char *strmake(char *dst,const char *src,uint length)
+{
+ reg1 char *res;
+
+ if ((res=memccpy(dst,src,0,length)))
+ return res-1;
+ dst[length]=0;
+ return dst+length;
+}
+
+#define strmake strmake_overlapp /* Use orginal for overlapping str */
+#endif
+
+char *strmake(register char *dst, register const char *src, uint length)
+{
+ while (length--)
+ if (! (*dst++ = *src++))
+ return dst-1;
+ *dst=0;
+ return dst;
+}
diff --git a/strings/strmov-sparc.s b/strings/strmov-sparc.s
new file mode 100644
index 00000000000..6114b0bf6e2
--- /dev/null
+++ b/strings/strmov-sparc.s
@@ -0,0 +1,36 @@
+! 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
+
+ .file "strmov-sparc.s"
+.section ".text"
+ .align 4
+ .global strmov
+ .type strmov,#function
+ .proc 0102
+strmov:
+.loop:
+ ldub [%o1], %g2
+ stb %g2, [%o0]
+ add %o1, 1, %o1
+ cmp %g2, 0
+ bne,a .loop
+ add %o0, 1, %o0
+ retl
+ nop
+.strmov_end:
+ .size strmov,.strmov_end-strmov
+ .ident "Matt Wagner"
diff --git a/strings/strmov.c b/strings/strmov.c
new file mode 100644
index 00000000000..8f5beb41f41
--- /dev/null
+++ b/strings/strmov.c
@@ -0,0 +1,59 @@
+/* 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 */
+
+/*
+ strmov(dst, src) moves all the characters of src (including the
+ closing NUL) to dst, and returns a pointer to the new closing NUL in
+ dst. The similar UNIX routine strcpy returns the old value of dst,
+ which I have never found useful. strmov(strmov(dst,a),b) moves a//b
+ into dst, which seems useful.
+*/
+
+#include <global.h>
+#include "m_string.h"
+
+#ifdef BAD_STRING_COMPILER
+#undef strmov
+#define strmov strmov_overlapp
+#endif
+
+#ifndef strmov
+
+#if !defined(MC68000) && !defined(DS90)
+
+char *strmov(register char *dst, register const char *src)
+{
+ while ((*dst++ = *src++)) ;
+ return dst-1;
+}
+
+#else
+
+char *strmov(dst, src)
+ char *dst, *src;
+{
+ asm(" movl 4(a7),a1 ");
+ asm(" movl 8(a7),a0 ");
+ asm(".L4: movb (a0)+,(a1)+ ");
+ asm(" jne .L4 ");
+ asm(" movl a1,d0 ");
+ asm(" subql #1,d0 ");
+}
+
+#endif
+
+#endif /* strmov */
diff --git a/strings/strnlen.c b/strings/strnlen.c
new file mode 100644
index 00000000000..6eb872ee08d
--- /dev/null
+++ b/strings/strnlen.c
@@ -0,0 +1,36 @@
+/* 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 */
+
+/* File : strnlen.c
+ Author : Michael Widenius
+ Updated: 20 April 1984
+ Defines: strnlen.
+ strnlen(s, len) returns the length of s or len if s is longer than len.
+*/
+
+#include <global.h>
+#include "m_string.h"
+
+#ifndef HAVE_STRNLEN
+
+uint strnlen(register const char *s, register uint maxlen)
+{
+ const char *end= memchr(s, '\0', maxlen);
+ return end ? (uint) (end - s) : maxlen;
+}
+
+#endif
diff --git a/strings/strnmov-sparc.s b/strings/strnmov-sparc.s
new file mode 100644
index 00000000000..2dfcb95ab76
--- /dev/null
+++ b/strings/strnmov-sparc.s
@@ -0,0 +1,43 @@
+! 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
+
+ .file "strnmov-sparc.s"
+.section ".text"
+ .align 4
+ .global strnmov
+ .type strnmov,#function
+ .proc 0102
+strnmov:
+ orcc %g0,%o2,%g0
+ be,a .end
+ nop
+ ldsb [%o1],%g2
+.loop:
+ stb %g2,[%o0]
+ cmp %g2,0
+ be .end ! Jump to end on end of string
+ add %o1,1,%o1
+ add %o0,1,%o0
+ subcc %o2,1,%o2
+ bne,a .loop
+ ldsb [%o1],%g2
+.end:
+ retl
+ nop
+.strnmov_end:
+ .size strnmov,.strnmov_end-strnmov
+ .ident "Matt Wagner"
diff --git a/strings/strnmov.c b/strings/strnmov.c
new file mode 100644
index 00000000000..ffc4a62f75e
--- /dev/null
+++ b/strings/strnmov.c
@@ -0,0 +1,36 @@
+/* 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 */
+
+/*
+ strnmov(dst,src,length) moves length characters, or until end, of src to
+ dst and appends a closing NUL to dst if src is shorter than length.
+ The result is a pointer to the first NUL in dst, or is dst+n if dst was
+ truncated.
+*/
+
+#include <global.h>
+#include "m_string.h"
+
+char *strnmov(register char *dst, register const char *src, uint n)
+{
+ while (n-- != 0) {
+ if (!(*dst++ = *src++)) {
+ return (char*) dst-1;
+ }
+ }
+ return dst;
+}
diff --git a/strings/strrchr.c b/strings/strrchr.c
new file mode 100644
index 00000000000..5a045ac3740
--- /dev/null
+++ b/strings/strrchr.c
@@ -0,0 +1,24 @@
+/* File : strrchr.c
+ Author : Richard A. O'Keefe.
+ Updated: 10 April 1984
+ Defines: strrchr(), rindex()
+
+ strrchr(s, c) returns a pointer to the last place in s where c
+ occurs, or NullS if c does not occur in s. This function is called
+ rindex in V7 and 4.?bsd systems; while not ideal the name is clearer
+ than strrchr, so rindex remains in strings.h as a macro. NB:
+ strrchr looks for single characters, not for sets or strings. The
+ parameter 'c' is declared 'int' so it will go in a register; if your
+ C compiler is happy with register char change it to that.
+*/
+
+#include "strings.h"
+
+char *strrchr(register const char *s, register pchar c)
+{
+ reg3 char *t;
+
+ t = NullS;
+ do if (*s == (char) c) t = (char*) s; while (*s++);
+ return (char*) t;
+}
diff --git a/strings/strstr-sparc.s b/strings/strstr-sparc.s
new file mode 100644
index 00000000000..d0d3659b1f8
--- /dev/null
+++ b/strings/strstr-sparc.s
@@ -0,0 +1,75 @@
+! 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
+
+ .file "strstr-sparc.s"
+.section ".text"
+ .align 4
+ .global strstr
+ .type strstr,#function
+ .proc 0102
+strstr:
+
+!char *strstr(register const char *str,const char *search)
+!{
+! register char *i,*j;
+!skipp:
+! while (*str != '\0') {
+! if (*str++ == *search) {
+! i=(char*) str; j=(char*) search+1;
+
+ ldsb [%o1],%g6 ! g6= First char of search
+.top:
+ ldsb [%o0],%g3 ! g3= First char of rest of str
+ cmp %g3,0
+ be .abort ! Found end null ;
+ cmp %g3,%g6
+ bne .top
+ add %o0,1,%o0
+
+.outloop1:
+
+! while (*j)
+! if (*i++ != *j++) goto skipp;
+
+ or %g0,%o0,%g2
+ add %o1,1,%g3 ! g3= search+1
+ ldsb [%o0],%o5 ! o5= [current_str+1]
+
+.loop2:
+ ldsb [%g3],%g4
+ add %g3,1,%g3
+ cmp %g4,0
+ be .end
+ cmp %o5,%g4
+ bne .top
+ add %g2,1,%g2
+ ba .loop2
+ ldsb [%g2],%o5
+
+.end:
+ retl
+ sub %o0,1,%o0
+.abort:
+ retl
+ or %g0,0,%o0
+
+.strstr_end:
+ .size strstr,.strstr_end-strstr
+ .ident "Matt Wagner & Monty"
+
+
+
diff --git a/strings/strstr.c b/strings/strstr.c
new file mode 100644
index 00000000000..572bf88c95c
--- /dev/null
+++ b/strings/strstr.c
@@ -0,0 +1,35 @@
+/* File : strstr.c
+ Author : Monty
+ Updated: 1986.11.24
+ Defines: strstr()
+
+ strstr(src, pat) looks for an instance of pat in src. pat is not a
+ regex(3) pattern, it is a literal string which must be matched exactly.
+ The result is a pointer to the first character of the located instance,
+ or NullS if pat does not occur in src.
+
+*/
+
+#include <global.h>
+#include "m_string.h"
+
+#ifndef HAVE_STRSTR
+
+char *strstr(register const char *str,const char *search)
+{
+ register char *i,*j;
+ register char first= *search;
+
+skipp:
+ while (*str != '\0') {
+ if (*str++ == first) {
+ i=(char*) str; j=(char*) search+1;
+ while (*j)
+ if (*i++ != *j++) goto skipp;
+ return ((char*) str-1);
+ }
+ }
+ return ((char*) 0);
+} /* strstr */
+
+#endif
diff --git a/strings/strto.c b/strings/strto.c
new file mode 100644
index 00000000000..eb8caab2ab6
--- /dev/null
+++ b/strings/strto.c
@@ -0,0 +1,204 @@
+/* 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 */
+
+/*
+ strtol,strtoul,strtoll,strtoull
+ convert string to long, unsigned long, long long or unsigned long long.
+ strtoxx(char *src,char **ptr,int base)
+ converts the string pointed to by src to an long of appropriate long and
+ returnes it. It skips leading spaces and tabs (but not newlines, formfeeds,
+ backspaces), then it accepts an optional sign and a sequence of digits
+ in the specified radix.
+ If the value of ptr is not (char **)NULL, a pointer to the character
+ terminating the scan is returned in the location pointed to by ptr.
+ Trailing spaces will NOT be skipped.
+
+ If an error is detected, the result will be LONG_MIN, 0 or LONG_MAX,
+ (or LONGLONG..) and errno will be set to
+ EDOM if there are no digits
+ ERANGE if the result would overflow.
+ the ptr will be set to src.
+ This file is based on the strtol from the the GNU C Library.
+ it can be compiled with the UNSIGNED and/or LONGLONG flag set
+*/
+
+#include <global.h>
+#include "m_string.h"
+#include "m_ctype.h"
+#include "my_sys.h" /* defines errno */
+#include <errno.h>
+
+#ifdef LONGLONG
+#define UTYPE_MAX (~(ulonglong) 0)
+#define TYPE_MIN LONGLONG_MIN
+#define TYPE_MAX LONGLONG_MAX
+#define longtype longlong
+#define ulongtype ulonglong
+#ifdef UNSIGNED
+#define function ulongtype strtoull
+#else
+#define function longtype strtoll
+#endif
+#else
+#define UTYPE_MAX (ulong) ~0L
+#define TYPE_MIN LONG_MIN
+#define TYPE_MAX LONG_MAX
+#define longtype long
+#define ulongtype unsigned long
+#ifdef UNSIGNED
+#define function ulongtype strtoul
+#else
+#define function longtype strtol
+#endif
+#endif
+
+
+/* Convert NPTR to an `unsigned long int' or `long int' in base BASE.
+ If BASE is 0 the base is determined by the presence of a leading
+ zero, indicating octal or a leading "0x" or "0X", indicating hexadecimal.
+ If BASE is < 2 or > 36, it is reset to 10.
+ If ENDPTR is not NULL, a pointer to the character after the last
+ one converted is stored in *ENDPTR. */
+
+
+function (const char *nptr,char **endptr,int base)
+{
+ int negative;
+ register ulongtype cutoff;
+ register unsigned int cutlim;
+ register ulongtype i;
+ register const char *s;
+ register unsigned char c;
+ const char *save;
+ int overflow;
+
+ if (base < 0 || base == 1 || base > 36)
+ base = 10;
+
+ s = nptr;
+
+ /* Skip white space. */
+ while (isspace (*s))
+ ++s;
+ if (*s == '\0')
+ {
+ goto noconv;
+ }
+
+ /* Check for a sign. */
+ if (*s == '-')
+ {
+ negative = 1;
+ ++s;
+ }
+ else if (*s == '+')
+ {
+ negative = 0;
+ ++s;
+ }
+ else
+ negative = 0;
+
+ if (base == 16 && s[0] == '0' && toupper (s[1]) == 'X')
+ s += 2;
+
+ /* If BASE is zero, figure it out ourselves. */
+ if (base == 0)
+ {
+ if (*s == '0')
+ {
+ if (toupper (s[1]) == 'X')
+ {
+ s += 2;
+ base = 16;
+ }
+ else
+ base = 8;
+ }
+ else
+ base = 10;
+ }
+
+ /* Save the pointer so we can check later if anything happened. */
+ save = s;
+
+ cutoff = UTYPE_MAX / (unsigned long int) base;
+ cutlim = (uint) (UTYPE_MAX % (unsigned long int) base);
+
+ overflow = 0;
+ i = 0;
+ for (c = *s; c != '\0'; c = *++s)
+ {
+ if (isdigit (c))
+ c -= '0';
+ else if (isalpha (c))
+ c = toupper (c) - 'A' + 10;
+ else
+ break;
+ if (c >= base)
+ break;
+ /* Check for overflow. */
+ if (i > cutoff || (i == cutoff && c > cutlim))
+ overflow = 1;
+ else
+ {
+ i *= (ulongtype) base;
+ i += c;
+ }
+ }
+
+ /* Check if anything actually happened. */
+ if (s == save)
+ goto noconv;
+
+ /* Store in ENDPTR the address of one character
+ past the last character we converted. */
+ if (endptr != NULL)
+ *endptr = (char *) s;
+
+#ifndef UNSIGNED
+ /* Check for a value that is within the range of
+ `unsigned long int', but outside the range of `long int'. */
+ if (negative)
+ {
+ if (i > (ulongtype) TYPE_MIN)
+ overflow = 1;
+ }
+ else if (i > (ulongtype) TYPE_MAX)
+ overflow = 1;
+#endif
+
+ if (overflow)
+ {
+ my_errno=ERANGE;
+#ifdef UNSIGNED
+ return UTYPE_MAX;
+#else
+ return negative ? TYPE_MIN : TYPE_MAX;
+#endif
+ }
+
+ /* Return the result of the appropriate sign. */
+ return (negative ? -((longtype) i) : i);
+
+noconv:
+ /* There was no number to convert. */
+ my_errno=EDOM;
+ if (endptr != NULL)
+ *endptr = (char *) nptr;
+ return 0L;
+}
diff --git a/strings/strtol.c b/strings/strtol.c
new file mode 100644
index 00000000000..ae3fdd0e2b3
--- /dev/null
+++ b/strings/strtol.c
@@ -0,0 +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,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should 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 defines strtol() if neaded */
+
+#include <global.h>
+#if !defined(MSDOS) && !defined(HAVE_STRTOUL) && !defined(__WIN__)
+#include "strto.c"
+#endif
diff --git a/strings/strtoll.c b/strings/strtoll.c
new file mode 100644
index 00000000000..f43dae726f5
--- /dev/null
+++ b/strings/strtoll.c
@@ -0,0 +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,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should 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 defines strtoll() if neaded */
+
+#include <global.h>
+#include <m_string.h>
+#if !defined(HAVE_STRTOULL) && defined(HAVE_LONG_LONG)
+#define LONGLONG
+#include "strto.c"
+#endif
diff --git a/strings/strtoul.c b/strings/strtoul.c
new file mode 100644
index 00000000000..bbfaa6ad22a
--- /dev/null
+++ b/strings/strtoul.c
@@ -0,0 +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,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should 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 defines strtoul() if neaded */
+
+#include <global.h>
+#if !defined(MSDOS) && !defined(HAVE_STRTOUL)
+#define UNSIGNED
+#include "strto.c"
+#endif
diff --git a/strings/strtoull.c b/strings/strtoull.c
new file mode 100644
index 00000000000..42ce5ea4177
--- /dev/null
+++ b/strings/strtoull.c
@@ -0,0 +1,26 @@
+/* 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 is defines strtoull() */
+
+#include <global.h>
+#include <m_string.h>
+#if !defined(HAVE_STRTOULL) && defined(HAVE_LONG_LONG)
+#define UNSIGNED
+#define LONGLONG
+#include "strto.c"
+#endif
diff --git a/strings/strxmov-sparc.s b/strings/strxmov-sparc.s
new file mode 100644
index 00000000000..e65b56d317d
--- /dev/null
+++ b/strings/strxmov-sparc.s
@@ -0,0 +1,49 @@
+! 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
+
+ .file "strxmov-sparc.s"
+.section ".text"
+ .align 4
+ .global strxmov
+ .type strxmov,#function
+ .proc 0102
+strxmov:
+ st %o2, [%sp+76] ! store 3rd param before other params
+ st %o3, [%sp+80] ! store 4th param " "
+ cmp %o1, 0 ! check if no from args
+ st %o4, [%sp+84] ! store 5th param
+ be .end
+ st %o5, [%sp+88] ! store last
+ add %sp, 76, %g2 ! put pointer to 3rd arg
+.loop:
+ ldub [%o1], %g1 ! set values of src (o1)
+ add %o1, 1, %o1 ! inc src
+ stb %g1, [%o0] ! and dst (o2) equal
+ cmp %g1, 0 ! second while cmp
+ bne,a .loop
+ add %o0, 1, %o0 ! inc dst
+ ld [%g2], %o1 ! get next param
+ cmp %o1, 0 ! check if last param
+ bne .loop
+ add %g2, 4, %g2 ! advance to next param
+.end:
+ retl
+ stb %g0, [%o0]
+.strxmov_end:
+ .size strxmov,.strxmov_end-strxmov
+ .ident "Matt Wagner & Monty"
+
diff --git a/strings/strxmov.asm b/strings/strxmov.asm
new file mode 100644
index 00000000000..9b027ad4276
--- /dev/null
+++ b/strings/strxmov.asm
@@ -0,0 +1,103 @@
+; 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
+
+ TITLE Optimized strxmov for MSDOS / Intel 8086
+
+ifndef M_I386
+ .8087
+ DOSSEG
+ .MODEL LARGE
+ .CODE
+
+ PUBLIC _strxmov
+_strxmov PROC
+ mov bx,sp
+ add bx,4
+ push si
+ push di
+ mov cx,ds ; Save ds
+ASSUME DS: NOTHING
+ASSUME ES: NOTHING
+ les di,DWORD PTR ss:[bx] ; dst
+ jmp next_str
+
+start_str:
+ mov al,ds:[si]
+ movsb ; move arg
+ and al,al
+ jnz start_str ; Not last
+ dec di
+
+next_str:
+ add bx,4
+ lds si,DWORD PTR ss:[bx]
+ mov ax,ds
+ or ax,si
+ jnz start_str
+
+ mov byte ptr es:[di],0 ; Force end null (if no source)
+ mov ds,cx
+ mov ax,di ; Return ptr to last 0
+ mov dx,es
+ pop di
+ pop si
+ ret
+_strxmov ENDP
+
+else
+
+include macros.asm
+
+ begcode strxmov
+ public _strxmov
+
+_strxmov PROC near
+ASSUME DS: NOTHING
+ASSUME ES: NOTHING
+ push EBP
+ mov EBP,ESP
+ mov EDX,EBX ; Save EBX
+ mov ECX,ESI ; Save ESI
+ push EDI
+ mov EDI,8[EBP] ; Get destination
+ lea EBX,8[EBP] ; Get adress to first source - 4
+ xor al,al
+ jmp next_str
+
+start_str: movsb
+ cmp AL,[EDI-1]
+ jne start_str
+ dec EDI ; Don't copy last null
+
+next_str: add EBX,4
+ mov ESI,[EBX]
+ or ESI,ESI
+ jne start_str
+ mov byte ptr [EDI],0 ; Force last null
+
+ mov EAX,EDI ; Return ptr to null
+ pop EDI
+ mov ESI,ECX
+ mov EBX,EDX
+ pop EBP
+ ret
+_strxmov endp
+ endcode strxmov
+
+endif
+
+ END
diff --git a/strings/strxmov.c b/strings/strxmov.c
new file mode 100644
index 00000000000..7ee1d303ee8
--- /dev/null
+++ b/strings/strxmov.c
@@ -0,0 +1,33 @@
+/* File : strxmov.c
+ Author : Richard A. O'Keefe.
+ Updated: 25 may 1984
+ Defines: strxmov()
+
+ strxmov(dst, src1, ..., srcn, NullS)
+ moves the concatenation of src1,...,srcn to dst, terminates it
+ with a NUL character, and returns a pointer to the terminating NUL.
+ It is just like strmov except that it concatenates multiple sources.
+ Beware: the last argument should be the null character pointer.
+ Take VERY great care not to omit it! Also be careful to use NullS
+ and NOT to use 0, as on some machines 0 is not the same size as a
+ character pointer, or not the same bit pattern as NullS.
+*/
+
+#include <global.h>
+#include "m_string.h"
+#include <stdarg.h>
+
+char *strxmov(char *dst,const char *src, ...)
+{
+ va_list pvar;
+
+ va_start(pvar,src);
+ while (src != NullS) {
+ while ((*dst++ = *src++)) ;
+ dst--;
+ src = va_arg(pvar, char *);
+ }
+ va_end(pvar);
+ *dst = 0; /* there might have been no sources! */
+ return dst;
+}
diff --git a/strings/strxnmov.c b/strings/strxnmov.c
new file mode 100644
index 00000000000..494b227209f
--- /dev/null
+++ b/strings/strxnmov.c
@@ -0,0 +1,46 @@
+/* File : strxnmov.c
+ Author : Richard A. O'Keefe.
+ Updated: 2 June 1984
+ Defines: strxnmov()
+
+ strxnmov(dst, len, src1, ..., srcn, NullS)
+ moves the first len characters of the concatenation of src1,...,srcn
+ to dst. If there aren't that many characters, a NUL character will
+ be added to the end of dst to terminate it properly. This gives the
+ same effect as calling strxcpy(buff, src1, ..., srcn, NullS) with a
+ large enough buffer, and then calling strnmov(dst, buff, len).
+ It is just like strnmov except that it concatenates multiple sources.
+ Beware: the last argument should be the null character pointer.
+ Take VERY great care not to omit it! Also be careful to use NullS
+ and NOT to use 0, as on some machines 0 is not the same size as a
+ character pointer, or not the same bit pattern as NullS.
+
+ Note: strxnmov is like strnmov in that it always moves EXACTLY len
+ characters; dst will be padded on the right with NUL characters as
+ needed. strxncpy does the same. strxncat, like strncat, does NOT.
+*/
+
+#include <global.h>
+#include "m_string.h"
+#include <stdarg.h>
+
+char *strxnmov(char *dst,uint len, const char *src, ...)
+{
+ va_list pvar;
+ char *result;
+
+ va_start(pvar,src);
+ while (src != NullS) {
+ do if (len-- == 0)
+ {
+ va_end(pvar);
+ return dst;
+ }
+ while ((*dst++ = *src++) != 0);
+ dst--;
+ src = va_arg(pvar, char *);
+ }
+ for (result= dst; len-- != 0; *dst++ = 0) ;
+ va_end(pvar);
+ return result;
+}
diff --git a/strings/t_ctype.h b/strings/t_ctype.h
new file mode 100644
index 00000000000..f60e6d98272
--- /dev/null
+++ b/strings/t_ctype.h
@@ -0,0 +1,243 @@
+/*
+ Copyright (C) 1998, 1999 by Pruet Boonma, all rights reserved.
+ Copyright (C) 1998 by Theppitak Karoonboonyanan, all rights reserved.
+ Permission to use, copy, modify, distribute and sell this software
+ and its documentation for any purpose is hereby granted without fee,
+ provided that the above copyright notice appear in all copies.
+ Smaphan Raruenrom and Pruet Boonma makes no representations about
+ the suitability of this software for any purpose. It is provided
+ "as is" without express or implied warranty.
+*/
+
+/* $Id$
+ LC_COLLATE category + Level information
+*/
+
+#ifndef _t_ctype_h
+#define _t_ctype_h
+
+typedef unsigned char tchar;
+
+#define TOT_LEVELS 5
+#define LAST_LEVEL 4 /* TOT_LEVELS - 1 */
+
+#define IGNORE 0
+
+
+// level 1 symbols & order
+enum l1_symbols {
+ L1_08 = TOT_LEVELS,
+ L1_18,
+ L1_28,
+ L1_38,
+ L1_48,
+ L1_58,
+ L1_68,
+ L1_78,
+ L1_88,
+ L1_98,
+ L1_A8,
+ L1_B8,
+ L1_C8,
+ L1_D8,
+ L1_E8,
+ L1_F8,
+ L1_G8,
+ L1_H8,
+ L1_I8,
+ L1_J8,
+ L1_K8,
+ L1_L8,
+ L1_M8,
+ L1_N8,
+ L1_O8,
+ L1_P8,
+ L1_Q8,
+ L1_R8,
+ L1_S8,
+ L1_T8,
+ L1_U8,
+ L1_V8,
+ L1_W8,
+ L1_X8,
+ L1_Y8,
+ L1_Z8,
+ L1_KO_KAI,
+ L1_KHO_KHAI,
+ L1_KHO_KHUAT,
+ L1_KHO_KHWAI,
+ L1_KHO_KHON,
+ L1_KHO_RAKHANG,
+ L1_NGO_NGU,
+ L1_CHO_CHAN,
+ L1_CHO_CHING,
+ L1_CHO_CHANG,
+ L1_SO_SO,
+ L1_CHO_CHOE,
+ L1_YO_YING,
+ L1_DO_CHADA,
+ L1_TO_PATAK,
+ L1_THO_THAN,
+ L1_THO_NANGMONTHO,
+ L1_THO_PHUTHAO,
+ L1_NO_NEN,
+ L1_DO_DEK,
+ L1_TO_TAO,
+ L1_THO_THUNG,
+ L1_THO_THAHAN,
+ L1_THO_THONG,
+ L1_NO_NU,
+ L1_BO_BAIMAI,
+ L1_PO_PLA,
+ L1_PHO_PHUNG,
+ L1_FO_FA,
+ L1_PHO_PHAN,
+ L1_FO_FAN,
+ L1_PHO_SAMPHAO,
+ L1_MO_MA,
+ L1_YO_YAK,
+ L1_RO_RUA,
+ L1_RU,
+ L1_LO_LING,
+ L1_LU,
+ L1_WO_WAEN,
+ L1_SO_SALA,
+ L1_SO_RUSI,
+ L1_SO_SUA,
+ L1_HO_HIP,
+ L1_LO_CHULA,
+ L1_O_ANG,
+ L1_HO_NOKHUK,
+ L1_NKHIT,
+ L1_SARA_A,
+ L1_MAI_HAN_AKAT,
+ L1_SARA_AA,
+ L1_SARA_AM,
+ L1_SARA_I,
+ L1_SARA_II,
+ L1_SARA_UE,
+ L1_SARA_UEE,
+ L1_SARA_U,
+ L1_SARA_UU,
+ L1_SARA_E,
+ L1_SARA_AE,
+ L1_SARA_O,
+ L1_SARA_AI_MAIMUAN,
+ L1_SARA_AI_MAIMALAI,
+};
+
+// level 2 symbols & order
+enum l2_symbols {
+ L2_BLANK = TOT_LEVELS,
+ L2_THAII,
+ L2_YAMAK,
+ L2_PINTHU,
+ L2_GARAN,
+ L2_TYKHU,
+ L2_TONE1,
+ L2_TONE2,
+ L2_TONE3,
+ L2_TONE4,
+};
+
+// level 3 symbols & order
+enum l3_symbols {
+ L3_BLANK = TOT_LEVELS,
+ L3_SPACE,
+ L3_NB_SACE,
+ L3_LOW_LINE,
+ L3_HYPHEN,
+ L3_COMMA,
+ L3_SEMICOLON,
+ L3_COLON,
+ L3_EXCLAMATION,
+ L3_QUESTION,
+ L3_SOLIDUS,
+ L3_FULL_STOP,
+ L3_PAIYAN_NOI,
+ L3_MAI_YAMOK,
+ L3_GRAVE,
+ L3_CIRCUMFLEX,
+ L3_TILDE,
+ L3_APOSTROPHE,
+ L3_QUOTATION,
+ L3_L_PARANTHESIS,
+ L3_L_BRACKET,
+ L3_L_BRACE,
+ L3_R_BRACE,
+ L3_R_BRACKET,
+ L3_R_PARENTHESIS,
+ L3_AT,
+ L3_BAHT,
+ L3_DOLLAR,
+ L3_FONGMAN,
+ L3_ANGKHANKHU,
+ L3_KHOMUT,
+ L3_ASTERISK,
+ L3_BK_SOLIDUS,
+ L3_AMPERSAND,
+ L3_NUMBER,
+ L3_PERCENT,
+ L3_PLUS,
+ L3_LESS_THAN,
+ L3_EQUAL,
+ L3_GREATER_THAN,
+ L3_V_LINE,
+};
+
+// level 4 symbols & order
+enum l4_symbols {
+ L4_BLANK = TOT_LEVELS,
+ L4_MIN,
+ L4_CAP,
+ L4_EXT,
+};
+
+enum level_symbols {
+ L_UPRUPR = TOT_LEVELS,
+ L_UPPER,
+ L_MIDDLE,
+ L_LOWER
+};
+
+#define _is(c) (t_ctype[(c)][LAST_LEVEL])
+#define _level 8
+#define _consnt 16
+#define _ldvowel 32
+#define _fllwvowel 64
+#define _uprvowel 128
+#define _lwrvowel 256
+#define _tone 512
+#define _diacrt1 1024
+#define _diacrt2 2048
+#define _combine 4096
+#define _stone 8192
+#define _tdig 16384
+#define _rearvowel (_fllwvowel | _uprvowel | _lwrvowel)
+#define _diacrt (_diacrt1 | _diacrt2)
+#define levelof(c) ( _is(c) & _level )
+#define isthai(c) ( (c) >= 128 )
+#define istalpha(c) ( _is(c) & (_consnt|_ldvowel|_rearvowel|\
+ _tone|_diacrt1|_diacrt2) )
+#define isconsnt(c) ( _is(c) & _consnt )
+#define isldvowel(c) ( _is(c) & _ldvowel )
+#define isfllwvowel(c) ( _is(c) & _fllwvowel )
+#define ismidvowel(c) ( _is(c) & (_ldvowel|_fllwvowel) )
+#define isuprvowel(c) ( _is(c) & _uprvowel )
+#define islwrvowel(c) ( _is(c) & _lwrvowel )
+#define isuprlwrvowel(c) ( _is(c) & (_lwrvowel | _uprvowel))
+#define isrearvowel(c) ( _is(c) & _rearvowel )
+#define isvowel(c) ( _is(c) & (_ldvowel|_rearvowel) )
+#define istone(c) ( _is(c) & _tone )
+#define isunldable(c) ( _is(c) & (_rearvowel|_tone|_diacrt1|_diacrt2) )
+#define iscombinable(c) ( _is(c) & _combine )
+#define istdigit(c) ( _is(c) & _tdig )
+#define isstone(c) ( _is(c) & _stone )
+#define isdiacrt1(c) ( _is(c) & _diacrt1)
+#define isdiacrt2(c) ( _is(c) & _diacrt2)
+#define isdiacrt(c) ( _is(c) & _diacrt)
+
+/* Function prototype called by sql/field.cc */
+void ThNormalize(uchar* ptr, uint field_length, const uchar* from, uint length);
+
+#endif
diff --git a/strings/udiv.c b/strings/udiv.c
new file mode 100644
index 00000000000..07af323a706
--- /dev/null
+++ b/strings/udiv.c
@@ -0,0 +1,38 @@
+/* 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 */
+
+/* Do udiv and urem if machine dosn't have it */
+
+#include <global.h>
+#include <math.h>
+
+unsigned long udiv(long unsigned int a, long unsigned int b)
+{
+ if (a < INT_MAX32 && b < INT_MAX32)
+ return (unsigned long) ((long) a / (long) b);
+ if (!(b & 1))
+ return (unsigned long) ((long) (a >> 1) / (long) (b >> 1));
+
+ return (unsigned long) floor(((double) a / (double) b));
+}
+
+unsigned long urem(long unsigned int a, long unsigned int b)
+{
+ if (a < INT_MAX32 && b < INT_MAX32)
+ return (unsigned long) ((long) a % (long) b);
+ return a-udiv(a,b)*b;
+}
diff --git a/support-files/.cvsignore b/support-files/.cvsignore
new file mode 100644
index 00000000000..97f52806614
--- /dev/null
+++ b/support-files/.cvsignore
@@ -0,0 +1,13 @@
+Makefile
+Makefile.in
+binary-configure
+my-example.cnf
+my-huge.cnf
+my-large.cnf
+my-medium.cnf
+my-small.cnf
+mysql-3.*-alpha.spec
+mysql-3.23.21-beta.spec
+mysql-log-rotate
+mysql.server
+mysql.spec
diff --git a/support-files/Attic/my-example.cnf.sh b/support-files/Attic/my-example.cnf.sh
new file mode 100644
index 00000000000..f91478a3037
--- /dev/null
+++ b/support-files/Attic/my-example.cnf.sh
@@ -0,0 +1,39 @@
+# Example mysql config file.
+# You can copy this to one of:
+# @sysconfdir@/my.cnf to set global options,
+# mysql-data-dir/my.cnf to set server-specific options (in this
+# installation this directory is @localstatedir@) or
+# ~/.my.cnf to set user-specific options.
+#
+# One can use all long options that the program supports.
+# Run the program with --help to get a list of available options
+
+# This will be passed to all mysql clients
+[client]
+#password = my_password
+port = @MYSQL_TCP_PORT@
+socket = @MYSQL_UNIX_ADDR@
+
+# Here is entries for some specific programs
+# The following values assume you have at least 32M ram
+
+# The MySQL server
+[mysqld]
+port = @MYSQL_TCP_PORT@
+socket = @MYSQL_UNIX_ADDR@
+skip-locking
+set-variable = key_buffer=16M
+set-variable = max_allowed_packet=1M
+set-variable = thread_stack=128K
+# Start logging
+log
+
+[mysqldump]
+quick
+set-variable = max_allowed_packet=16M
+
+[mysql]
+no-auto-rehash
+
+[isamchk]
+set-variable = key_buffer=16M
diff --git a/support-files/Attic/my-huge.cfg.sh b/support-files/Attic/my-huge.cfg.sh
new file mode 100644
index 00000000000..75faa1da276
--- /dev/null
+++ b/support-files/Attic/my-huge.cfg.sh
@@ -0,0 +1,60 @@
+# Example mysql config file for very large systems.
+#
+# This is for large system with memory of 1G-2G where the system runs mainly
+# MySQL.
+#
+# You can copy this file to
+# /etc/mf.cnf to set global options,
+# mysql-data-dir/my.cnf to set server-specific options (in this
+# installation this directory is @localstatedir@) or
+# ~/.my.cnf to set user-specific options.
+#
+# One can in this file use all long options that the program supports.
+# If you want to know which options a program support, run the program
+# with --help option.
+
+# The following options will be passed to all MySQL clients
+[client]
+#password = your_password
+port = @MYSQL_TCP_PORT@
+socket = @MYSQL_UNIX_ADDR@
+
+# Here follows entries for some specific programs
+
+# The MySQL server
+[mysqld]
+port = @MYSQL_TCP_PORT@
+socket = @MYSQL_UNIX_ADDR@
+#tmpdir = /tmp/ # Put this on a dedicated disk
+skip-locking
+set-variable = key_buffer=512M
+set-variable = max_allowed_packet=1M
+set-variable = table_cache=512
+set-variable = sort_buffer=2M
+set-variable = record_buffer=2M
+set-variable = thread_cache=8
+set-variable = thread_concurrency=8 # Try number of CPU's*2
+set-variable = myisam_sort_buffer_size=64M
+#set-variable = bdb_cache_size=256M
+# Only log updates
+log-update
+
+[mysqldump]
+quick
+set-variable = max_allowed_packet=16M
+
+[mysql]
+no-auto-rehash
+#safe-updates # Remove the comment character if you are not familiar with SQL
+
+[isamchk]
+set-variable = key_buffer=256M
+set-variable = sort_buffer=256M
+set-variable = read-buffer=2M
+set-variable = write-buffer=2M
+
+[myisamchk]
+set-variable = key_buffer=256M
+set-variable = sort_buffer=256M
+set-variable = read-buffer=2M
+set-variable = write-buffer=2M
diff --git a/support-files/Attic/my-large.cfg.sh b/support-files/Attic/my-large.cfg.sh
new file mode 100644
index 00000000000..01e830ae16c
--- /dev/null
+++ b/support-files/Attic/my-large.cfg.sh
@@ -0,0 +1,60 @@
+# Example mysql config file for large systems.
+#
+# This is for large system with memory = 512M where the system runs mainly
+# MySQL.
+#
+# You can copy this file to
+# /etc/mf.cnf to set global options,
+# mysql-data-dir/my.cnf to set server-specific options (in this
+# installation this directory is @localstatedir@) or
+# ~/.my.cnf to set user-specific options.
+#
+# One can in this file use all long options that the program supports.
+# If you want to know which options a program support, run the program
+# with --help option.
+
+# The following options will be passed to all MySQL clients
+[client]
+#password = your_password
+port = @MYSQL_TCP_PORT@
+socket = @MYSQL_UNIX_ADDR@
+
+# Here follows entries for some specific programs
+
+# The MySQL server
+[mysqld]
+port = @MYSQL_TCP_PORT@
+socket = @MYSQL_UNIX_ADDR@
+#tmpdir = /tmp/ # Put this on a dedicated disk
+skip-locking
+set-variable = key_buffer=256M
+set-variable = max_allowed_packet=1M
+set-variable = table_cache=256
+set-variable = sort_buffer=1M
+set-variable = record_buffer=1M
+set-variable = myisam_sort_buffer_size=64M
+set-variable = thread_cache=8
+set-variable = thread_concurrency=8 # Try number of CPU's*2
+#set-variable = bdb_cache_size=64M
+# Only log updates
+log-update
+
+[mysqldump]
+quick
+set-variable = max_allowed_packet=16M
+
+[mysql]
+no-auto-rehash
+#safe-updates # Remove the comment character if you are not familiar with SQL
+
+[isamchk]
+set-variable = key_buffer=128M
+set-variable = sort_buffer=128M
+set-variable = read-buffer=2M
+set-variable = write-buffer=2M
+
+[myisamchk]
+set-variable = key_buffer=128M
+set-variable = sort_buffer=128M
+set-variable = read-buffer=2M
+set-variable = write-buffer=2M
diff --git a/support-files/Attic/my-medium.cfg.sh b/support-files/Attic/my-medium.cfg.sh
new file mode 100644
index 00000000000..18c297fe151
--- /dev/null
+++ b/support-files/Attic/my-medium.cfg.sh
@@ -0,0 +1,58 @@
+# Example mysql config file for medium systems.
+#
+# This is for a system with little memory (32M - 64M) where MySQL plays
+# a important part and systems up to 128M very MySQL is used together with
+# other programs (like a web server)
+#
+# You can copy this file to
+# /etc/mf.cnf to set global options,
+# mysql-data-dir/my.cnf to set server-specific options (in this
+# installation this directory is @localstatedir@) or
+# ~/.my.cnf to set user-specific options.
+#
+# One can in this file use all long options that the program supports.
+# If you want to know which options a program support, run the program
+# with --help option.
+
+# The following options will be passed to all MySQL clients
+[client]
+#password = your_password
+port = @MYSQL_TCP_PORT@
+socket = @MYSQL_UNIX_ADDR@
+
+# Here follows entries for some specific programs
+
+# The MySQL server
+[mysqld]
+port = @MYSQL_TCP_PORT@
+socket = @MYSQL_UNIX_ADDR@
+#tmpdir = /tmp/ # Put this on a dedicated disk
+skip-locking
+set-variable = key_buffer=16M
+set-variable = max_allowed_packet=1M
+set-variable = table_cache=64
+set-variable = sort_buffer=512K
+set-variable = net_buffer_length=8K
+set-variable = myisam_sort_buffer_size=8M
+#set-variable = bdb_cache_size=1M
+log-update
+
+[mysqldump]
+quick
+set-variable = max_allowed_packet=16M
+
+[mysql]
+no-auto-rehash
+#safe-updates # Remove the comment character if you are not familiar with SQL
+
+[isamchk]
+set-variable = key_buffer=20M
+set-variable = sort_buffer=20M
+set-variable = read-buffer=2M
+set-variable = write-buffer=2M
+
+[myisamchk]
+set-variable = key_buffer=20M
+set-variable = sort_buffer=20M
+set-variable = read-buffer=2M
+set-variable = write-buffer=2M
diff --git a/support-files/Attic/my-small.cfg.sh b/support-files/Attic/my-small.cfg.sh
new file mode 100644
index 00000000000..69a816da3fb
--- /dev/null
+++ b/support-files/Attic/my-small.cfg.sh
@@ -0,0 +1,53 @@
+# Example mysql config file for small systems.
+#
+# This is for a system with little memory (<= 64M) where MySQL is only used
+# from time to time and it's important that the mysqld deamon
+# doesn't use much resources.
+#
+# You can copy this file to
+# /etc/mf.cnf to set global options,
+# mysql-data-dir/my.cnf to set server-specific options (in this
+# installation this directory is @localstatedir@) or
+# ~/.my.cnf to set user-specific options.
+#
+# One can in this file use all long options that the program supports.
+# If you want to know which options a program support, run the program
+# with --help option.
+
+# The following options will be passed to all MySQL clients
+[client]
+#password = your_password
+port = @MYSQL_TCP_PORT@
+socket = @MYSQL_UNIX_ADDR@
+
+# Here follows entries for some specific programs
+
+# The MySQL server
+[mysqld]
+port = @MYSQL_TCP_PORT@
+socket = @MYSQL_UNIX_ADDR@
+skip-locking
+set-variable = key_buffer=16K
+set-variable = max_allowed_packet=1M
+set-variable = thread_stack=64K
+set-variable = table_cache=4
+set-variable = sort_buffer=64K
+set-variable = net_buffer_length=2K
+# Don't log things
+#log
+
+[mysqldump]
+quick
+set-variable = max_allowed_packet=16M
+
+[mysql]
+no-auto-rehash
+#safe-updates # Remove the comment character if you are not familiar with SQL
+
+[isamchk]
+set-variable = key_buffer=8M
+set-variable = sort_buffer=8M
+
+[myisamchk]
+set-variable = key_buffer=8M
+set-variable = sort_buffer=8M
diff --git a/support-files/Makefile.am b/support-files/Makefile.am
new file mode 100755
index 00000000000..29d2e7cf235
--- /dev/null
+++ b/support-files/Makefile.am
@@ -0,0 +1,90 @@
+# 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 = mysql.spec.sh \
+ my-small.cnf.sh \
+ my-medium.cnf.sh \
+ my-large.cnf.sh \
+ my-huge.cnf.sh \
+ mysql-log-rotate.sh \
+ mysql.server.sh \
+ binary-configure.sh
+
+pkgdata_DATA = my-small.cnf \
+ my-medium.cnf \
+ my-large.cnf \
+ my-huge.cnf \
+ mysql-log-rotate \
+ mysql-@VERSION@.spec \
+ mysql.server \
+ binary-configure
+
+CLEANFILES = my-small.cnf \
+ my-medium.cnf \
+ my-large.cnf \
+ my-huge.cnf \
+ mysql.spec \
+ mysql-@VERSION@.spec \
+ mysql.server
+
+mysql-@VERSION@.spec: mysql.spec
+ rm -f $@
+ cp -p mysql.spec $@
+
+SUFFIXES = .sh
+
+.sh:
+ @RM@ -f $@ $@-t
+ @SED@ \
+ -e 's!@''bindir''@!$(bindir)!g' \
+ -e 's!@''scriptdir''@!$(bindir)!g' \
+ -e 's!@''prefix''@!$(prefix)!g' \
+ -e 's!@''datadir''@!$(datadir)!g' \
+ -e 's!@''localstatedir''@!$(localstatedir)!g' \
+ -e 's!@''libexecdir''@!$(libexecdir)!g' \
+ -e 's!@''CC''@!@CC@!'\
+ -e 's!@''CXX''@!@CXX@!'\
+ -e 's!@''GXX''@!@GXX@!'\
+ -e 's!@''PERL''@!@PERL@!' \
+ -e 's!@''CFLAGS''@!@SAVE_CFLAGS@!'\
+ -e 's!@''CXXFLAGS''@!@SAVE_CXXFLAGS@!'\
+ -e 's!@''LDFLAGS''@!@SAVE_LDFLAGS@!'\
+ -e 's!@''VERSION''@!@VERSION@!' \
+ -e 's!@''COMPILATION_COMMENT''@!@COMPILATION_COMMENT@!' \
+ -e 's!@''MACHINE_TYPE''@!@MACHINE_TYPE@!' \
+ -e 's!@''HOSTNAME''@!@HOSTNAME@!' \
+ -e 's!@''SYSTEM_TYPE''@!@SYSTEM_TYPE@!' \
+ -e 's!@''CHECK_PID''@!@CHECK_PID@!' \
+ -e 's!@''FIND_PROC''@!@FIND_PROC@!' \
+ -e 's!@''MYSQLD_DEFAULT_SWITCHES''@!@MYSQLD_DEFAULT_SWITCHES@!' \
+ -e 's!@''MYSQL_UNIX_ADDR''@!@MYSQL_UNIX_ADDR@!' \
+ -e 's!@''IS_LINUX''@!@IS_LINUX@!' \
+ -e "s!@""CONF_COMMAND""@!@CONF_COMMAND@!" \
+ -e 's!@''MYSQLD_USER''@!@MYSQLD_USER@!' \
+ -e 's!@''sysconfdir''@!@sysconfdir@!' \
+ -e 's!@''SHORT_MYSQL_INTRO''@!@SHORT_MYSQL_INTRO@!' \
+ -e 's!@''SHARED_LIB_VERSION''@!@SHARED_LIB_VERSION@!' \
+ -e 's!@''MYSQL_BASE_VERSION''@!@MYSQL_BASE_VERSION@!' \
+ -e 's!@''MYSQL_NO_DASH_VERSION''@!@MYSQL_NO_DASH_VERSION@!' \
+ -e 's!@''MYSQL_TCP_PORT''@!@MYSQL_TCP_PORT@!' \
+ -e 's!@''PERL_DBI_VERSION''@!@PERL_DBI_VERSION@!' \
+ -e 's!@''PERL_DBD_VERSION''@!@PERL_DBD_VERSION@!' \
+ -e 's!@''PERL_DATA_DUMPER''@!@PERL_DATA_DUMPER@!' \
+ $< > $@-t
+ @MV@ $@-t $@
diff --git a/support-files/binary-configure.sh b/support-files/binary-configure.sh
new file mode 100755
index 00000000000..c67d2ba2827
--- /dev/null
+++ b/support-files/binary-configure.sh
@@ -0,0 +1,16 @@
+#!/bin/sh
+if test ! -x ./scripts/mysql_install_db
+then
+ echo "I didn't find the script './scripts/mysql_install_db'."
+ echo "Please execute this script in the mysql distribution directory!"
+ exit 1;
+fi
+
+./scripts/mysql_install_db
+if [ $? = 0 ]
+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 &
+fi
diff --git a/support-files/maxsql.spec.sh b/support-files/maxsql.spec.sh
new file mode 100644
index 00000000000..e410bc7a18d
--- /dev/null
+++ b/support-files/maxsql.spec.sh
@@ -0,0 +1,410 @@
+%define mysql_version @VERSION@
+%define shared_lib_version @SHARED_LIB_VERSION@
+%define release 2
+%define mysqld_user mysql
+%define db_version 3.1.14
+
+%define see_base For a description of MySQL see the base MySQL RPM or http://www.mysql.com
+
+Name: MySQL
+Summary: MySQL: a very fast and reliable SQL database engine
+Group: Applications/Databases
+Summary(pt_BR): MySQL: Um servidor SQL rápido e confiável.
+Group(pt_BR): Aplicações/Banco_de_Dados
+Version: @MYSQL_NO_DASH_VERSION@
+Release: %{release}
+Copyright: GPL / LGPL
+Source: http://www.mysql.com/Downloads/MySQL-@MYSQL_BASE_VERSION@/mysql-%{mysql_version}.tar.gz
+Source1: ftp://ftp.mysql.com/pub/mysql/Downloads/db/db-%{db_version}.tar.gz
+Icon: mysql.gif
+URL: http://www.mysql.com/
+Packager: David Axmark <david@mysql.com>
+Provides: msqlormysql MySQL-server
+Obsoletes: mysql
+
+# Think about what you use here since the first step is to
+# run a rm -rf
+BuildRoot: /var/tmp/mysql
+
+# From the manual
+%description
+MySQL is a true multi-user, multi-threaded SQL (Structured Query
+Language) database server. MySQL is a client/server implementation
+that consists of a server daemon (mysqld) and many different client
+programs/libraries.
+
+The main goals of MySQL are speed, robustness and ease of use. MySQL
+was originally developed because we needed a SQL server that could
+handle very big databases with magnitude higher speed than what any
+database vendor could offer to us. And since we did not need all the
+features that made their server slow we made our own. We have now been
+using MySQL since 1996 in a environment with more than 40 databases,
+10,000 tables, of which more than 500 have more than 7 million
+rows. This is about 200G of data.
+
+The base upon which MySQL is built is a set of routines that have been
+used in a highly demanding production environment for many
+years. While MySQL is still in development, it already offers a rich
+and highly useful function set.
+
+See the documentation for more information
+
+%description -l pt_BR
+O MySQL é um servidor de banco de dados SQL realmente multiusuário e\
+multi-tarefa. A linguagem SQL é a mais popular linguagem para banco de\
+dados no mundo. O MySQL é uma implementação cliente/servidor que\
+consiste de um servidor chamado mysqld e diversos\
+programas/bibliotecas clientes. Os principais objetivos do MySQL são:\
+velocidade, robustez e facilidade de uso. O MySQL foi originalmente\
+desenvolvido porque nós na Tcx precisávamos de um servidor SQL que\
+pudesse lidar com grandes bases de dados e com uma velocidade muito\
+maior do que a que qualquer vendedor podia nos oferecer. Estamos\
+usando\
+o MySQL desde 1996 em um ambiente com mais de 40 bases de dados com 10.000\
+tabelas, das quais mais de 500 têm mais de 7 milhões de linhas. Isto é o\
+equivalente a aproximadamente 50G de dados críticos. A base da construção do\
+MySQL é uma série de rotinas que foram usadas em um ambiente de produção com\
+alta demanda por muitos anos. Mesmo o MySQL estando ainda em desenvolvimento,\
+ele já oferece um conjunto de funções muito ricas e úteis. Veja a documentação\
+para maiores informações.
+
+%package client
+Release: %{release}
+Summary: MySQL - Client
+Group: Applications/Databases
+Summary(pt_BR): MySQL - Cliente
+Group(pt_BR): Aplicações/Banco_de_Dados
+Obsoletes: mysql-client
+
+%description client
+This package contains the standard MySQL clients.
+
+%{see_base}
+
+%description client -l pt_BR
+Este pacote contém os clientes padrão para o MySQL.
+
+%package bench
+Release: %{release}
+Requires: MySQL-client MySQL-DBI-perl-bin perl
+Summary: MySQL - Benchmarks
+Group: Applications/Databases
+Summary(pt_BR): MySQL - Medições de desempenho
+Group(pt_BR): Aplicações/Banco_de_Dados
+Obsoletes: mysql-bench
+
+%description bench
+This package contains MySQL benchmark scripts and data.
+
+%{see_base}
+
+%description bench -l pt_BR
+Este pacote contém medições de desempenho de scripts e dados do MySQL.
+
+%package devel
+Release: %{release}
+Requires: MySQL-client
+Summary: MySQL - Development header files and libraries
+Group: Applications/Databases
+Summary(pt_BR): MySQL - Medições de desempenho
+Group(pt_BR): Aplicações/Banco_de_Dados
+Obsoletes: mysql-devel
+
+%description devel
+This package contains the development header files and libraries
+necessary to develop MySQL client applications.
+
+%{see_base}
+
+%description devel -l pt_BR
+Este pacote contém os arquivos de cabeçalho (header files) e bibliotecas
+necessárias para desenvolver aplicações clientes do MySQL.
+
+%package shared
+Release: %{release}
+Summary: MySQL - Shared libraries
+Group: Applications/Databases
+
+%description shared
+This package contains the shared libraries (*.so*) which certain
+languages and applications need to dynamically load and use MySQL.
+
+%prep
+%setup -n mysql-%{mysql_version}
+%setup -T -D -a 1 -n mysql-%{mysql_version}
+
+%build
+# The all-static flag is to make the RPM work on different
+# distributions. This version tries to put shared mysqlcliet libraries
+# in a separate package.
+
+BuildMySQL() {
+# The --enable-assembler simply does nothing on systems that does not
+# support assembler speedups.
+sh -c "PATH=\"${MYSQL_BUILD_PATH:-/bin:/usr/bin}\" \
+ CC=\"${MYSQL_BUILD_CC:-egcs}\" \
+ CFLAGS=\"${MYSQL_BUILD_CFLAGS:- -O6 -fomit-frame-pointer}\" \
+ CXX=\"${MYSQL_BUILD_CXX:-egcs}\" \
+ CXXFLAGS=\"${MYSQL_BUILD_CXXFLAGS:- -O6 -fomit-frame-pointer \
+ -felide-constructors -fno-exceptions -fno-rtti}\" \
+ ./configure \
+ $* \
+ --enable-assembler \
+ --with-mysqld-user=%{mysqld_user} \
+ --with-unix-socket-path=/var/lib/mysql/mysql.sock \
+ --prefix=/ \
+ --with-extra-charsets=complex \
+ --exec-prefix=/usr \
+ --libexecdir=/usr/sbin \
+ --sysconfdir=/etc \
+ --datadir=/usr/share \
+ --localstatedir=/var/lib/mysql \
+ --infodir=/usr/info \
+ --includedir=/usr/include \
+ --mandir=/usr/man \
+ --with-berkeley-db=$RPM_BUILD_ROOT/usr/BDB \
+ --with-comment=\"Official MySQL RPM\";
+ # Add this for more debugging support
+ # --with-debug
+ "
+
+ # benchdir does not fit in above model. Maybe a separate bench distribution
+ make benchdir=$RPM_BUILD_ROOT/usr/share/sql-bench
+}
+
+# Use the build root for temporary storage of the shared libraries.
+
+RBR=$RPM_BUILD_ROOT
+MBD=$RPM_BUILD_DIR/mysql-%{mysql_version}
+if test -z "$RBR" -o "$RBR" = "/"
+then
+ echo "RPM_BUILD_ROOT has stupid value"
+ exit 1
+fi
+rm -rf $RBR
+mkdir -p $RBR
+
+cd $MBD/db-%{db_version}/dist
+./configure --prefix=$RBR/usr/BDB
+make install
+
+echo $RBR $MBD
+cd $MBD
+
+BuildMySQL "--enable-shared --enable-thread-safe-client --without-server"
+
+# Save everything for debus
+tar cf $RBR/all.tar .
+
+# Save shared libraries
+(cd libmysql/.libs; tar cf $RBR/shared-libs.tar *.so*)
+
+# Save manual to avoid rebuilding
+mv Docs/manual.ps Docs/manual.ps.save
+make distclean
+mv Docs/manual.ps.save Docs/manual.ps
+
+BuildMySQL "--disable-shared" \
+ "--with-mysqld-ldflags='-all-static'" \
+ "--with-client-ldflags='-all-static'"
+
+%install -n mysql-%{mysql_version}
+RBR=$RPM_BUILD_ROOT
+MBD=$RPM_BUILD_DIR/mysql-%{mysql_version}
+# Ensure that needed directories exists
+install -d $RBR/etc/{logrotate.d,rc.d/init.d}
+install -d $RBR/var/lib/mysql/mysql
+install -d $RBR/usr/share/sql-bench
+install -d $RBR/usr/{sbin,share,man,include}
+install -d $RBR/usr/doc/MySQL-%{mysql_version}
+install -d $RBR/usr/lib
+# Make install
+make install DESTDIR=$RBR benchdir=/usr/share/sql-bench
+
+# Install shared libraries (Disable for architectures that don't support it)
+(cd $RBR/usr/lib; tar xf $RBR/shared-libs.tar)
+
+# Install logrotate and autostart
+install -m644 $MBD/support-files/mysql-log-rotate $RBR/etc/logrotate.d/mysql
+install -m755 $MBD/support-files/mysql.server $RBR/etc/rc.d/init.d/mysql
+
+# Install docs
+install -m644 $RPM_BUILD_DIR/mysql-%{mysql_version}/Docs/mysql.info \
+ $RBR/usr/info/mysql.info
+for file in README COPYING COPYING.LIB Docs/manual_toc.html Docs/manual.html \
+ Docs/manual.txt Docs/manual.texi Docs/manual.ps \
+ support-files/my-huge.cnf support-files/my-large.cnf \
+ support-files/my-medium.cnf support-files/my-small.cnf
+do
+ b=`basename $file`
+ install -m644 $MBD/$file $RBR/usr/doc/MySQL-%{mysql_version}/$b
+done
+
+%pre
+if test -x /etc/rc.d/init.d/mysql
+then
+ /etc/rc.d/init.d/mysql stop > /dev/null 2>&1
+ echo "Giving mysqld a couple of seconds to exit nicely"
+ sleep 5
+fi
+
+%post
+mysql_datadir=/var/lib/mysql
+
+# Create data directory if needed
+if test ! -d $mysql_datadir; then mkdir $mysql_datadir; fi
+if test ! -d $mysql_datadir/mysql; then mkdir $mysql_datadir/mysql; fi
+if test ! -d $mysql_datadir/test; then mkdir $mysql_datadir/test; fi
+
+# Make MySQL start/shutdown automatically when the machine does it.
+/sbin/chkconfig --add mysql
+
+# Create a MySQL user. Do not report any problems if it already
+# exists. This is redhat specific and should be handled more portable
+useradd -M -r -d $mysql_datadir -s /bin/bash -c "MySQL server" mysql 2> /dev/null || true
+
+# Change permissions so that the user that will run the MySQL daemon
+# owns all database files.
+chown -R mysql $mysql_datadir
+
+# Initiate databases
+mysql_install_db -IN-RPM
+
+# Change permissions again to fix any new files.
+chown -R mysql $mysql_datadir
+
+# Fix permissions for the permission database so that only the user
+# can read them.
+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
+sleep 2
+
+%preun
+if test -x /etc/rc.d/init.d/mysql
+then
+ /etc/rc.d/init.d/mysql stop > /dev/null
+fi
+# Remove autostart of mysql
+if test $1 = 0
+then
+ /sbin/chkconfig --del mysql
+fi
+# We do not remove the mysql user since it may still own a lot of
+# database files.
+
+%files
+%attr(-, root, root) %doc /usr/doc/MySQL-%{mysql_version}/
+
+%attr(755, root, root) /usr/bin/isamchk
+%attr(755, root, root) /usr/bin/isamlog
+%attr(755, root, root) /usr/bin/pack_isam
+%attr(755, root, root) /usr/bin/myisamchk
+%attr(755, root, root) /usr/bin/myisamlog
+%attr(755, root, root) /usr/bin/myisampack
+%attr(755, root, root) /usr/bin/mysql_fix_privilege_tables
+%attr(755, root, root) /usr/bin/mysql_convert_table_format
+%attr(755, root, root) /usr/bin/mysql_install_db
+%attr(755, root, root) /usr/bin/mysql_setpermission
+%attr(755, root, root) /usr/bin/mysql_zap
+%attr(755, root, root) /usr/bin/mysqlbug
+%attr(755, root, root) /usr/bin/mysqlhotcopy
+%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/my_print_defaults
+
+%attr(644, root, root) /usr/info/mysql.info
+
+%attr(755, root, root) /usr/sbin/mysqld
+
+%attr(644, root, root) /etc/logrotate.d/mysql
+%attr(755, root, root) /etc/rc.d/init.d/mysql
+
+%attr(755, root, root) /usr/share/mysql/
+
+%files client
+%attr(755, root, root) /usr/bin/msql2mysql
+%attr(755, root, root) /usr/bin/mysql
+%attr(755, root, root) /usr/bin/mysqlaccess
+%attr(755, root, root) /usr/bin/mysqladmin
+%attr(755, root, root) /usr/bin/mysql_find_rows
+%attr(755, root, root) /usr/bin/mysqldump
+%attr(755, root, root) /usr/bin/mysqlimport
+%attr(755, root, root) /usr/bin/mysqlshow
+%attr(755, root, root) /usr/bin/mysqlbinlog
+
+%attr(644, root, man) %doc /usr/man/man1/mysql.1
+
+%post shared
+/sbin/ldconfig
+
+%postun shared
+/sbin/ldconfig
+
+%files devel
+%attr(755, root, root) /usr/bin/comp_err
+%attr(755, root, root) /usr/include/mysql/
+%attr(755, root, root) /usr/lib/mysql/
+
+%files shared
+# Shared libraries (omit for architectures that don't support them)
+%attr(755, root, root) /usr/lib/*
+
+%files bench
+%attr(-, root, root) /usr/share/sql-bench
+
+%changelog
+
+* Fri Jun 29 2000 Steven Lawrance <slawrance@technologist.com>
+
+- Merged changes from official MySQL RPM and upgraded Berkeley DB to
+ 3.1.14 within this RPM.
+
+* Wed Sep 28 1999 David Axmark <davida@mysql.com>
+
+- Added the support-files/my-example.cnf to the docs directory.
+
+- Removed devel dependency on base since it is about client
+ development.
+
+* Wed Sep 8 1999 David Axmark <davida@mysql.com>
+
+- Cleaned up some for 3.23.
+
+* Thu Jul 1 1999 David Axmark <davida@mysql.com>
+
+- Added support for shared libraries in a separate sub
+ package. Original fix by David Fox (dsfox@cogsci.ucsd.edu)
+
+- The --enable-assembler switch is now automatically disables on
+ platforms there assembler code is unavailable. This should allow
+ building this RPM on non i386 systems.
+
+* Mon Feb 22 1999 David Axmark <david@detron.se>
+
+- Removed unportable cc switches from the spec file. The defaults can
+ now be overridden with environment variables. This feature is used
+ to compile the official RPM with optimal (but compiler version
+ specific) switches.
+
+- Removed the repetitive description parts for the sub rpms. Maybe add
+ again if RPM gets a multiline macro capability.
+
+- Added support for a pt_BR translation. Translation contributed by
+ Jorge Godoy <jorge@bestway.com.br>.
+
+* Wed Nov 4 1998 David Axmark <david@detron.se>
+
+- A lot of changes in all the rpm and install scripts. This may even
+ be a working RPM :-)
+
+* Sun Aug 16 1998 David Axmark <david@detron.se>
+
+- A developers changelog for MySQL is available in the source RPM. And
+ there is a history of major user visible changed in the Reference
+ Manual. Only RPM specific changes will be documented here.
diff --git a/support-files/my-huge.cnf.sh b/support-files/my-huge.cnf.sh
new file mode 100644
index 00000000000..fd0d70b2d04
--- /dev/null
+++ b/support-files/my-huge.cnf.sh
@@ -0,0 +1,64 @@
+# Example mysql config file for very large systems.
+#
+# This is for large system with memory of 1G-2G where the system runs mainly
+# MySQL.
+#
+# You can copy this file to
+# /etc/mf.cnf to set global options,
+# mysql-data-dir/my.cnf to set server-specific options (in this
+# installation this directory is @localstatedir@) or
+# ~/.my.cnf to set user-specific options.
+#
+# One can in this file use all long options that the program supports.
+# If you want to know which options a program support, run the program
+# with --help option.
+
+# The following options will be passed to all MySQL clients
+[client]
+#password = your_password
+port = @MYSQL_TCP_PORT@
+socket = @MYSQL_UNIX_ADDR@
+
+# Here follows entries for some specific programs
+
+# The MySQL server
+[mysqld]
+port = @MYSQL_TCP_PORT@
+socket = @MYSQL_UNIX_ADDR@
+skip-locking
+set-variable = key_buffer=384M
+set-variable = max_allowed_packet=1M
+set-variable = table_cache=512
+set-variable = sort_buffer=2M
+set-variable = record_buffer=2M
+set-variable = thread_cache=8
+set-variable = thread_concurrency=8 # Try number of CPU's*2
+set-variable = myisam_sort_buffer_size=64M
+log-update
+
+# Uncomment the following if you are using BDB tables
+#set-variable = bdb_cache_size=384M
+
+# Point the following paths to different dedicated disks
+#tmpdir = /tmp/
+#log-update = /path-to-dedicated-directory/hostname
+
+[mysqldump]
+quick
+set-variable = max_allowed_packet=16M
+
+[mysql]
+no-auto-rehash
+#safe-updates # Remove the comment character if you are not familiar with SQL
+
+[isamchk]
+set-variable = key_buffer=256M
+set-variable = sort_buffer=256M
+set-variable = read_buffer=2M
+set-variable = write_buffer=2M
+
+[myisamchk]
+set-variable = key_buffer=256M
+set-variable = sort_buffer=256M
+set-variable = read_buffer=2M
+set-variable = write_buffer=2M
diff --git a/support-files/my-large.cnf.sh b/support-files/my-large.cnf.sh
new file mode 100644
index 00000000000..8b58bed642f
--- /dev/null
+++ b/support-files/my-large.cnf.sh
@@ -0,0 +1,64 @@
+# Example mysql config file for large systems.
+#
+# This is for large system with memory = 512M where the system runs mainly
+# MySQL.
+#
+# You can copy this file to
+# /etc/mf.cnf to set global options,
+# mysql-data-dir/my.cnf to set server-specific options (in this
+# installation this directory is @localstatedir@) or
+# ~/.my.cnf to set user-specific options.
+#
+# One can in this file use all long options that the program supports.
+# If you want to know which options a program support, run the program
+# with --help option.
+
+# The following options will be passed to all MySQL clients
+[client]
+#password = your_password
+port = @MYSQL_TCP_PORT@
+socket = @MYSQL_UNIX_ADDR@
+
+# Here follows entries for some specific programs
+
+# The MySQL server
+[mysqld]
+port = @MYSQL_TCP_PORT@
+socket = @MYSQL_UNIX_ADDR@
+skip-locking
+set-variable = key_buffer=256M
+set-variable = max_allowed_packet=1M
+set-variable = table_cache=256
+set-variable = sort_buffer=1M
+set-variable = record_buffer=1M
+set-variable = myisam_sort_buffer_size=64M
+set-variable = thread_cache=8
+set-variable = thread_concurrency=8 # Try number of CPU's*2
+log-update
+
+# Uncomment the following if you are using BDB tables
+#set-variable = bdb_cache_size=64M
+
+# Point the following paths to different dedicated disks
+#tmpdir = /tmp/
+#log-update = /path-to-dedicated-directory/hostname
+
+[mysqldump]
+quick
+set-variable = max_allowed_packet=16M
+
+[mysql]
+no-auto-rehash
+#safe-updates # Remove the comment character if you are not familiar with SQL
+
+[isamchk]
+set-variable = key_buffer=128M
+set-variable = sort_buffer=128M
+set-variable = read_buffer=2M
+set-variable = write_buffer=2M
+
+[myisamchk]
+set-variable = key_buffer=128M
+set-variable = sort_buffer=128M
+set-variable = read_buffer=2M
+set-variable = write_buffer=2M
diff --git a/support-files/my-medium.cnf.sh b/support-files/my-medium.cnf.sh
new file mode 100644
index 00000000000..13bf8e739ec
--- /dev/null
+++ b/support-files/my-medium.cnf.sh
@@ -0,0 +1,63 @@
+# Example mysql config file for medium systems.
+#
+# This is for a system with little memory (32M - 64M) where MySQL plays
+# a important part and systems up to 128M very MySQL is used together with
+# other programs (like a web server)
+#
+# You can copy this file to
+# /etc/mf.cnf to set global options,
+# mysql-data-dir/my.cnf to set server-specific options (in this
+# installation this directory is @localstatedir@) or
+# ~/.my.cnf to set user-specific options.
+#
+# One can in this file use all long options that the program supports.
+# If you want to know which options a program support, run the program
+# with --help option.
+
+# The following options will be passed to all MySQL clients
+[client]
+#password = your_password
+port = @MYSQL_TCP_PORT@
+socket = @MYSQL_UNIX_ADDR@
+
+# Here follows entries for some specific programs
+
+# The MySQL server
+[mysqld]
+port = @MYSQL_TCP_PORT@
+socket = @MYSQL_UNIX_ADDR@
+skip-locking
+set-variable = key_buffer=16M
+set-variable = max_allowed_packet=1M
+set-variable = table_cache=64
+set-variable = sort_buffer=512K
+set-variable = net_buffer_length=8K
+set-variable = myisam_sort_buffer_size=8M
+log-update
+
+# Uncomment the following if you are using BDB tables
+#set-variable = bdb_cache_size=4M
+
+# Point the following paths to different dedicated disks
+#tmpdir = /tmp/
+#log-update = /path-to-dedicated-directory/hostname
+
+[mysqldump]
+quick
+set-variable = max_allowed_packet=16M
+
+[mysql]
+no-auto-rehash
+#safe-updates # Remove the comment character if you are not familiar with SQL
+
+[isamchk]
+set-variable = key_buffer=20M
+set-variable = sort_buffer=20M
+set-variable = read_buffer=2M
+set-variable = write_buffer=2M
+
+[myisamchk]
+set-variable = key_buffer=20M
+set-variable = sort_buffer=20M
+set-variable = read_buffer=2M
+set-variable = write_buffer=2M
diff --git a/support-files/my-small.cnf.sh b/support-files/my-small.cnf.sh
new file mode 100644
index 00000000000..48017226a51
--- /dev/null
+++ b/support-files/my-small.cnf.sh
@@ -0,0 +1,57 @@
+# Example mysql config file for small systems.
+#
+# This is for a system with little memory (<= 64M) where MySQL is only used
+# from time to time and it's important that the mysqld deamon
+# doesn't use much resources.
+#
+# You can copy this file to
+# /etc/mf.cnf to set global options,
+# mysql-data-dir/my.cnf to set server-specific options (in this
+# installation this directory is @localstatedir@) or
+# ~/.my.cnf to set user-specific options.
+#
+# One can in this file use all long options that the program supports.
+# If you want to know which options a program support, run the program
+# with --help option.
+
+# The following options will be passed to all MySQL clients
+[client]
+#password = your_password
+port = @MYSQL_TCP_PORT@
+socket = @MYSQL_UNIX_ADDR@
+
+# Here follows entries for some specific programs
+
+# The MySQL server
+[mysqld]
+port = @MYSQL_TCP_PORT@
+socket = @MYSQL_UNIX_ADDR@
+skip-locking
+set-variable = key_buffer=16K
+set-variable = max_allowed_packet=1M
+set-variable = thread_stack=64K
+set-variable = table_cache=4
+set-variable = sort_buffer=64K
+set-variable = net_buffer_length=2K
+
+# Uncomment the following if you are NOT using BDB tables
+#skip-bdb
+
+# Uncomment the following if you want to log updates
+#log-update
+
+[mysqldump]
+quick
+set-variable = max_allowed_packet=16M
+
+[mysql]
+no-auto-rehash
+#safe-updates # Remove the comment character if you are not familiar with SQL
+
+[isamchk]
+set-variable = key_buffer=8M
+set-variable = sort_buffer=8M
+
+[myisamchk]
+set-variable = key_buffer=8M
+set-variable = sort_buffer=8M
diff --git a/support-files/mysql-log-rotate.sh b/support-files/mysql-log-rotate.sh
new file mode 100644
index 00000000000..a1153c66f40
--- /dev/null
+++ b/support-files/mysql-log-rotate.sh
@@ -0,0 +1,29 @@
+# This logname is set in mysql.server.sh that ends up in /etc/rc.d/init.d/mysql
+#
+# If the root user has a password you have to create a
+# /root/.my.cnf configuration file with the following
+# content:
+#
+# [mysqladmin]
+# password = <secret>
+# user= root
+#
+# where "<secret>" is the password.
+#
+# ATTENTION: This /root/.my.cnf should be readable ONLY
+# for root !
+
+@localstatedir@/mysqld.log {
+ # create 600 mysql mysql
+ notifempty
+ daily
+ rotate 3
+ missingok
+ compress
+ postrotate
+ # just if mysqld is really running
+ if test -n "`ps acx|grep mysqld`"; then
+ @bindir@/mysqladmin flush-logs
+ fi
+ endscript
+}
diff --git a/support-files/mysql.server-sys5.sh b/support-files/mysql.server-sys5.sh
new file mode 100755
index 00000000000..4bda51acc4d
--- /dev/null
+++ b/support-files/mysql.server-sys5.sh
@@ -0,0 +1,86 @@
+#!/bin/sh
+#
+# This is an example SysV-init-script by Winfried Truemper that you can use
+# and modify to your liking
+#
+
+PATH="$PATH:@prefix@"
+export PATH
+MY_CFG="@prefix@/mysql.cfg"
+
+read_mysql_config() {
+ # this routine requires a sed, which reads even the last line of input
+
+ MY_CONFIG_FILE="$1" # file to read setting from
+ MY_CONFIG_SECTION="$2" # section inside the file
+ MY_CONFIG_TAG="$3" # name of the setting inside the section
+ TAB=`printf "\t" ""` # makes the code cut&paste safe
+
+ sed -n -f - "$MY_CONFIG_FILE" <<EOF
+1,/^\[$MY_CONFIG_SECTION\]/ d
+/^\[[a-z]/ q
+/^$MY_CONFIG_TAG/ {
+s/^$MY_CONFIG_TAG[ $TAB]*=[ $TAB]*\([^ $TAB]*\)/\1/
+p
+q
+}
+EOF
+}
+
+
+
+do_start() {
+ nohup ./bin/mysqld --defaults-file="$MY_CFG" &
+}
+
+do_stop() {
+ ./bin/mysqladmin --defaults-file="$MY_CFG" shutdown
+}
+
+do_kill_all() {
+ PIDS=`ps -efo pid,args | grep mysql | sed -e "s, *.*,," | sort | uniq`
+ kill $PIDS
+ sleep 5
+ kill -9 $PIDS
+}
+
+do_kill() {
+ MY_PIDFILE=`read_mysql_config "$MY_CFG" "mysqld" "pidfile" `
+ read MY_PID < "$MY_PIDFILE"
+ kill "$MY_PID"
+ sleep 2
+ kill -KILL "$MY_PID"
+}
+
+# z.B. mysql.sh admin "ping"
+do_admin() {
+ shift
+ ./bin/mysqladmin --defaults-file="$MY_CFG" $@
+ exit
+}
+
+do_repair() {
+ MY_DATADIR=`read_mysql_config "$MY_CFG" "mysqld" "datadir" `
+ ./bin/isamchk --defaults-file="$MY_CFG" --repair "$MY_DATADIR/$1"
+ shift
+}
+
+
+do_repair_all() {
+ MY_DATADIR=`read_mysql_config "$MY_CFG" "mysqld" "datadir" `
+ for i in `find "$MY_DATADIR" -name "*.ISM"`
+ do
+ ./bin/isamchk --defaults-file="$MY_CFG" --repair "$MY_DATADIR/$i"
+ done
+}
+
+
+
+MY_BASEDIR=`read_mysql_config "$MY_CFG" "mysqld" "basedir"`
+cd "$MY_BASEDIR" || exit 1
+while test $# -gt 0
+do
+ MY_ARG="$1"
+ do_$MY_ARG $@
+ shift
+done
diff --git a/support-files/mysql.server.sh b/support-files/mysql.server.sh
new file mode 100644
index 00000000000..f6a75e22fea
--- /dev/null
+++ b/support-files/mysql.server.sh
@@ -0,0 +1,123 @@
+#!/bin/sh
+# Copyright Abandoned 1996 TCX DataKonsult AB & Monty Program KB & Detron HB
+# This file is public domain and comes with NO WARRANTY of any kind
+
+# Mysql daemon start/stop script.
+
+# Usually this is put in /etc/init.d (at least on machines SYSV R4
+# based systems) and linked to /etc/rc3.d/S99mysql and /etc/rc0.d/S01mysql.
+# When this is done the mysql server will be started when the machine is started
+# and shut down when the systems goes down.
+
+# Comments to support chkconfig on RedHat Linux
+# chkconfig: 2345 90 90
+# description: A very fast and reliable SQL database engine.
+
+PATH=/sbin:/usr/sbin:/bin:/usr/bin
+basedir=@prefix@
+bindir=@bindir@
+datadir=@localstatedir@
+pid_file=@localstatedir@/mysqld.pid
+log_file=@localstatedir@/mysqld.log
+# Run mysqld as this user.
+mysql_daemon_user=@MYSQLD_USER@
+export PATH
+
+mode=$1
+
+if test -w / # determine if we should look at the root config file
+then # or user config file
+ conf=/etc/my.cnf
+else
+ conf=$HOME/.my.cnf # Using the users config file
+fi
+
+# The following code tries to get the variables safe_mysqld needs from the
+# config file. This isn't perfect as this ignores groups, but it should
+# work as the options doesn't conflict with anything else.
+
+if test -f "$conf" # Extract those fields we need from config file.
+then
+ if grep "^datadir" $conf >/dev/null
+ then
+ datadir=`grep "^datadir" $conf | cut -f 2 -d= | tr -d ' '`
+ fi
+ if grep "^user" $conf >/dev/null
+ then
+ mysql_daemon_user=`grep "^user" $conf | cut -f 2 -d= | tr -d ' ' | head -1`
+ fi
+ if grep "^pid-file" $conf >/dev/null
+ then
+ pid_file=`grep "^pid-file" $conf | cut -f 2 -d= | tr -d ' '`
+ else
+ if test -d "$datadir"
+ then
+ pid_file=$datadir/`hostname`.pid
+ fi
+ fi
+ if grep "^basedir" $conf >/dev/null
+ then
+ basedir=`grep "^basedir" $conf | cut -f 2 -d= | tr -d ' '`
+ bindir=$basedir/bin
+ fi
+ if grep "^bindir" $conf >/dev/null
+ then
+ bindir=`grep "^bindir" $conf | cut -f 2 -d= | tr -d ' '`
+ fi
+ if grep "^log[ \t]*=" $conf >/dev/null
+ then
+ log_file=`grep "log[ \t]*=" $conf | cut -f 2 -d= | tr -d ' '`
+ fi
+fi
+
+
+# Safeguard (relative paths, core dumps..)
+cd $basedir
+
+case "$mode" in
+ 'start')
+ # Start daemon
+
+ if test -x $bindir/safe_mysqld
+ then
+ # Give extra arguments to mysqld with the my.cnf file. This script may
+ # be overwritten at next upgrade.
+ $bindir/safe_mysqld \
+ --user=$mysql_daemon_user --datadir=$datadir --pid-file=$pid_file --log=$log_file &
+ else
+ echo "Can't execute $bindir/safe_mysqld"
+ fi
+ ;;
+
+ 'stop')
+ # Stop daemon. We use a signal here to avoid having to know the
+ # root password.
+ if test -f "$pid_file"
+ then
+ mysqld_pid=`cat $pid_file`
+ echo "Killing mysqld with pid $mysqld_pid"
+ kill $mysqld_pid
+ # mysqld should remove the pid_file when it exits, so wait for it.
+
+ sleep 1
+ while [ -s $pid_file -a "$flags" != aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ]
+ do [ -z "$flags" ] && echo "Wait for mysqld to exit\c" || echo ".\c"
+ flags=a$flags
+ sleep 1
+ done
+ if [ -s $pid_file ]
+ then echo " gave up waiting!"
+ elif [ -n "$flags" ]
+ then echo " done"
+ fi
+ else
+ echo "No mysqld pid file found. Looked for $pid_file."
+ fi
+ ;;
+
+ *)
+ # usage
+ echo "usage: $0 start|stop"
+ exit 1
+ ;;
+esac
diff --git a/support-files/mysql.spec.sh b/support-files/mysql.spec.sh
new file mode 100644
index 00000000000..bd50f3cfc4b
--- /dev/null
+++ b/support-files/mysql.spec.sh
@@ -0,0 +1,396 @@
+%define mysql_version @VERSION@
+%define shared_lib_version @SHARED_LIB_VERSION@
+%define release 1
+%define mysqld_user mysql
+
+%define see_base For a description of MySQL see the base MySQL RPM or http://www.mysql.com
+
+Name: MySQL
+Summary: MySQL: a very fast and reliable SQL database engine
+Group: Applications/Databases
+Summary(pt_BR): MySQL: Um servidor SQL rápido e confiável.
+Group(pt_BR): Aplicações/Banco_de_Dados
+Version: @MYSQL_NO_DASH_VERSION@
+Release: %{release}
+Copyright: GPL / LGPL
+Source: http://www.mysql.com/Downloads/MySQL-@MYSQL_BASE_VERSION@/mysql-%{mysql_version}.tar.gz
+Icon: mysql.gif
+URL: http://www.mysql.com/
+Packager: David Axmark <david@mysql.com>
+Provides: msqlormysql MySQL-server
+Obsoletes: mysql
+
+# Think about what you use here since the first step is to
+# run a rm -rf
+BuildRoot: /var/tmp/mysql
+
+# From the manual
+%description
+MySQL is a true multi-user, multi-threaded SQL (Structured Query
+Language) database server. MySQL is a client/server implementation
+that consists of a server daemon (mysqld) and many different client
+programs/libraries.
+
+The main goals of MySQL are speed, robustness and ease of use. MySQL
+was originally developed because we needed a SQL server that could
+handle very big databases with magnitude higher speed than what any
+database vendor could offer to us. And since we did not need all the
+features that made their server slow we made our own. We have now been
+using MySQL since 1996 in a environment with more than 40 databases,
+10,000 tables, of which more than 500 have more than 7 million
+rows. This is about 200G of data.
+
+The base upon which MySQL is built is a set of routines that have been
+used in a highly demanding production environment for many
+years. While MySQL is still in development, it already offers a rich
+and highly useful function set.
+
+See the documentation for more information
+
+%description -l pt_BR
+O MySQL é um servidor de banco de dados SQL realmente multiusuário e\
+multi-tarefa. A linguagem SQL é a mais popular linguagem para banco de\
+dados no mundo. O MySQL é uma implementação cliente/servidor que\
+consiste de um servidor chamado mysqld e diversos\
+programas/bibliotecas clientes. Os principais objetivos do MySQL são:\
+velocidade, robustez e facilidade de uso. O MySQL foi originalmente\
+desenvolvido porque nós na Tcx precisávamos de um servidor SQL que\
+pudesse lidar com grandes bases de dados e com uma velocidade muito\
+maior do que a que qualquer vendedor podia nos oferecer. Estamos\
+usando\
+o MySQL desde 1996 em um ambiente com mais de 40 bases de dados com 10.000\
+tabelas, das quais mais de 500 têm mais de 7 milhões de linhas. Isto é o\
+equivalente a aproximadamente 50G de dados críticos. A base da construção do\
+MySQL é uma série de rotinas que foram usadas em um ambiente de produção com\
+alta demanda por muitos anos. Mesmo o MySQL estando ainda em desenvolvimento,\
+ele já oferece um conjunto de funções muito ricas e úteis. Veja a documentação\
+para maiores informações.
+
+%package client
+Release: %{release}
+Summary: MySQL - Client
+Group: Applications/Databases
+Summary(pt_BR): MySQL - Cliente
+Group(pt_BR): Aplicações/Banco_de_Dados
+Obsoletes: mysql-client
+
+%description client
+This package contains the standard MySQL clients.
+
+%{see_base}
+
+%description client -l pt_BR
+Este pacote contém os clientes padrão para o MySQL.
+
+%package bench
+Release: %{release}
+Requires: MySQL-client MySQL-DBI-perl-bin perl
+Summary: MySQL - Benchmarks
+Group: Applications/Databases
+Summary(pt_BR): MySQL - Medições de desempenho
+Group(pt_BR): Aplicações/Banco_de_Dados
+Obsoletes: mysql-bench
+
+%description bench
+This package contains MySQL benchmark scripts and data.
+
+%{see_base}
+
+%description bench -l pt_BR
+Este pacote contém medições de desempenho de scripts e dados do MySQL.
+
+%package devel
+Release: %{release}
+Requires: MySQL-client
+Summary: MySQL - Development header files and libraries
+Group: Applications/Databases
+Summary(pt_BR): MySQL - Medições de desempenho
+Group(pt_BR): Aplicações/Banco_de_Dados
+Obsoletes: mysql-devel
+
+%description devel
+This package contains the development header files and libraries
+necessary to develop MySQL client applications.
+
+%{see_base}
+
+%description devel -l pt_BR
+Este pacote contém os arquivos de cabeçalho (header files) e bibliotecas
+necessárias para desenvolver aplicações clientes do MySQL.
+
+%package shared
+Release: %{release}
+Summary: MySQL - Shared libraries
+Group: Applications/Databases
+
+%description shared
+This package contains the shared libraries (*.so*) which certain
+languages and applications need to dynamically load and use MySQL.
+
+%prep
+%setup -n mysql-%{mysql_version}
+
+%build
+# The all-static flag is to make the RPM work on different
+# distributions. This version tries to put shared mysqlcliet libraries
+# in a separate package.
+
+BuildMySQL() {
+# The --enable-assembler simply does nothing on systems that does not
+# support assembler speedups.
+sh -c "PATH=\"${MYSQL_BUILD_PATH:-/bin:/usr/bin}\" \
+ CC=\"${MYSQL_BUILD_CC:-egcs}\" \
+ CFLAGS=\"${MYSQL_BUILD_CFLAGS:- -O6 -fomit-frame-pointer}\" \
+ CXX=\"${MYSQL_BUILD_CXX:-egcs}\" \
+ CXXFLAGS=\"${MYSQL_BUILD_CXXFLAGS:- -O6 -fomit-frame-pointer \
+ -felide-constructors -fno-exceptions -fno-rtti}\" \
+ ./configure \
+ $* \
+ --enable-assembler \
+ --with-mysqld-user=%{mysqld_user} \
+ --with-unix-socket-path=/var/lib/mysql/mysql.sock \
+ --prefix=/ \
+ --with-extra-charsets=complex \
+ --exec-prefix=/usr \
+ --libexecdir=/usr/sbin \
+ --sysconfdir=/etc \
+ --datadir=/usr/share \
+ --localstatedir=/var/lib/mysql \
+ --infodir=/usr/info \
+ --includedir=/usr/include \
+ --mandir=/usr/man \
+ --with-comment=\"Official MySQL RPM\";
+ # Add this for more debugging support
+ # --with-debug
+ "
+
+ # benchdir does not fit in above model. Maybe a separate bench distribution
+ make benchdir=$RPM_BUILD_ROOT/usr/share/sql-bench
+}
+
+# Use the build root for temporary storage of the shared libraries.
+
+RBR=$RPM_BUILD_ROOT
+MBD=$RPM_BUILD_DIR/mysql-%{mysql_version}
+if test -z "$RBR" -o "$RBR" = "/"
+then
+ echo "RPM_BUILD_ROOT has stupid value"
+ exit 1
+fi
+rm -rf $RBR
+mkdir -p $RBR
+
+BuildMySQL "--enable-shared --enable-thread-safe-client --without-server"
+
+# Save everything for debus
+tar cf $RBR/all.tar .
+
+# Save shared libraries
+(cd libmysql/.libs; tar cf $RBR/shared-libs.tar *.so*)
+
+# Save manual to avoid rebuilding
+mv Docs/manual.ps Docs/manual.ps.save
+make distclean
+mv Docs/manual.ps.save Docs/manual.ps
+
+BuildMySQL "--disable-shared" \
+ "--with-mysqld-ldflags='-all-static'" \
+ "--with-client-ldflags='-all-static'"
+
+%install -n mysql-%{mysql_version}
+RBR=$RPM_BUILD_ROOT
+MBD=$RPM_BUILD_DIR/mysql-%{mysql_version}
+# Ensure that needed directories exists
+install -d $RBR/etc/{logrotate.d,rc.d/init.d}
+install -d $RBR/var/lib/mysql/mysql
+install -d $RBR/usr/share/sql-bench
+install -d $RBR/usr/{sbin,share,man,include}
+install -d $RBR/usr/doc/MySQL-%{mysql_version}
+install -d $RBR/usr/lib
+# Make install
+make install DESTDIR=$RBR benchdir=/usr/share/sql-bench
+
+# Install shared libraries (Disable for architectures that don't support it)
+(cd $RBR/usr/lib; tar xf $RBR/shared-libs.tar)
+
+# Install logrotate and autostart
+install -m644 $MBD/support-files/mysql-log-rotate $RBR/etc/logrotate.d/mysql
+install -m755 $MBD/support-files/mysql.server $RBR/etc/rc.d/init.d/mysql
+
+# Install docs
+install -m644 $RPM_BUILD_DIR/mysql-%{mysql_version}/Docs/mysql.info \
+ $RBR/usr/info/mysql.info
+for file in README COPYING COPYING.LIB Docs/manual_toc.html Docs/manual.html \
+ Docs/manual.txt Docs/manual.texi Docs/manual.ps \
+ support-files/my-huge.cnf support-files/my-large.cnf \
+ support-files/my-medium.cnf support-files/my-small.cnf
+do
+ b=`basename $file`
+ install -m644 $MBD/$file $RBR/usr/doc/MySQL-%{mysql_version}/$b
+done
+
+%pre
+if test -x /etc/rc.d/init.d/mysql
+then
+ /etc/rc.d/init.d/mysql stop > /dev/null 2>&1
+ echo "Giving mysqld a couple of seconds to exit nicely"
+ sleep 5
+fi
+
+%post
+mysql_datadir=/var/lib/mysql
+
+# Create data directory if needed
+if test ! -d $mysql_datadir; then mkdir $mysql_datadir; fi
+if test ! -d $mysql_datadir/mysql; then mkdir $mysql_datadir/mysql; fi
+if test ! -d $mysql_datadir/test; then mkdir $mysql_datadir/test; fi
+
+# Make MySQL start/shutdown automatically when the machine does it.
+/sbin/chkconfig --add mysql
+
+# Create a MySQL user. Do not report any problems if it already
+# exists. This is redhat specific and should be handled more portable
+useradd -M -r -d $mysql_datadir -s /bin/bash -c "MySQL server" mysql 2> /dev/null || true
+
+# Change permissions so that the user that will run the MySQL daemon
+# owns all database files.
+chown -R mysql $mysql_datadir
+
+# Initiate databases
+mysql_install_db -IN-RPM
+
+# Change permissions again to fix any new files.
+chown -R mysql $mysql_datadir
+
+# Fix permissions for the permission database so that only the user
+# can read them.
+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
+sleep 2
+
+%preun
+if test -x /etc/rc.d/init.d/mysql
+then
+ /etc/rc.d/init.d/mysql stop > /dev/null
+fi
+# Remove autostart of mysql
+if test $1 = 0
+then
+ /sbin/chkconfig --del mysql
+fi
+# We do not remove the mysql user since it may still own a lot of
+# database files.
+
+%files
+%attr(-, root, root) %doc /usr/doc/MySQL-%{mysql_version}/
+
+%attr(755, root, root) /usr/bin/isamchk
+%attr(755, root, root) /usr/bin/isamlog
+%attr(755, root, root) /usr/bin/pack_isam
+%attr(755, root, root) /usr/bin/myisamchk
+%attr(755, root, root) /usr/bin/myisamlog
+%attr(755, root, root) /usr/bin/myisampack
+%attr(755, root, root) /usr/bin/mysql_fix_privilege_tables
+%attr(755, root, root) /usr/bin/mysql_convert_table_format
+%attr(755, root, root) /usr/bin/mysql_install_db
+%attr(755, root, root) /usr/bin/mysql_config
+%attr(755, root, root) /usr/bin/mysql_setpermission
+%attr(755, root, root) /usr/bin/mysql_zap
+%attr(755, root, root) /usr/bin/mysqlbug
+%attr(755, root, root) /usr/bin/mysqlhotcopy
+%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/my_print_defaults
+
+%attr(644, root, root) /usr/info/mysql.info
+
+%attr(755, root, root) /usr/sbin/mysqld
+
+%attr(644, root, root) /etc/logrotate.d/mysql
+%attr(755, root, root) /etc/rc.d/init.d/mysql
+
+%attr(755, root, root) /usr/share/mysql/
+
+%files client
+%attr(755, root, root) /usr/bin/msql2mysql
+%attr(755, root, root) /usr/bin/mysql
+%attr(755, root, root) /usr/bin/mysqlaccess
+%attr(755, root, root) /usr/bin/mysqladmin
+%attr(755, root, root) /usr/bin/mysql_find_rows
+%attr(755, root, root) /usr/bin/mysqldump
+%attr(755, root, root) /usr/bin/mysqlimport
+%attr(755, root, root) /usr/bin/mysqlshow
+%attr(755, root, root) /usr/bin/mysqlbinlog
+
+%attr(644, root, man) %doc /usr/man/man1/mysql.1
+
+%post shared
+/sbin/ldconfig
+
+%postun shared
+/sbin/ldconfig
+
+%files devel
+%attr(755, root, root) /usr/bin/comp_err
+%attr(755, root, root) /usr/include/mysql/
+%attr(755, root, root) /usr/lib/mysql/
+%attr(755, root, root) /usr/bin/mysql_config
+
+%files shared
+# Shared libraries (omit for architectures that don't support them)
+%attr(755, root, root) /usr/lib/*
+
+%files bench
+%attr(-, root, root) /usr/share/sql-bench
+
+%changelog
+
+* Wed Sep 28 1999 David Axmark <davida@mysql.com>
+
+- Added the support-files/my-example.cnf to the docs directory.
+
+- Removed devel dependency on base since it is about client
+ development.
+
+* Wed Sep 8 1999 David Axmark <davida@mysql.com>
+
+- Cleaned up some for 3.23.
+
+* Thu Jul 1 1999 David Axmark <davida@mysql.com>
+
+- Added support for shared libraries in a separate sub
+ package. Original fix by David Fox (dsfox@cogsci.ucsd.edu)
+
+- The --enable-assembler switch is now automatically disables on
+ platforms there assembler code is unavailable. This should allow
+ building this RPM on non i386 systems.
+
+* Mon Feb 22 1999 David Axmark <david@detron.se>
+
+- Removed unportable cc switches from the spec file. The defaults can
+ now be overridden with environment variables. This feature is used
+ to compile the official RPM with optimal (but compiler version
+ specific) switches.
+
+- Removed the repetitive description parts for the sub rpms. Maybe add
+ again if RPM gets a multiline macro capability.
+
+- Added support for a pt_BR translation. Translation contributed by
+ Jorge Godoy <jorge@bestway.com.br>.
+
+* Wed Nov 4 1998 David Axmark <david@detron.se>
+
+- A lot of changes in all the rpm and install scripts. This may even
+ be a working RPM :-)
+
+* Sun Aug 16 1998 David Axmark <david@detron.se>
+
+- A developers changelog for MySQL is available in the source RPM. And
+ there is a history of major user visible changed in the Reference
+ Manual. Only RPM specific changes will be documented here.
diff --git a/tests/.cvsignore b/tests/.cvsignore
new file mode 100644
index 00000000000..282522db034
--- /dev/null
+++ b/tests/.cvsignore
@@ -0,0 +1,2 @@
+Makefile
+Makefile.in
diff --git a/tests/Makefile.am b/tests/Makefile.am
new file mode 100644
index 00000000000..e0cc44b5153
--- /dev/null
+++ b/tests/Makefile.am
@@ -0,0 +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,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Library General Public License for more details.
+#
+# You should 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 = auto_increment.res auto_increment.tst \
+ function.res function.tst lock_test.pl lock_test.res \
+ export.pl big_record.pl \
+ fork_test.pl fork2_test.pl fork3_test.pl \
+ insert_and_repair.pl \
+ grant.pl grant.res test_delayed_insert.pl \
+ pmail.pl mail_to_db.pl table_types.pl \
+ udf_test udf_test.res
diff --git a/tests/auto_increment.res b/tests/auto_increment.res
new file mode 100644
index 00000000000..fa7b5428708
--- /dev/null
+++ b/tests/auto_increment.res
@@ -0,0 +1,114 @@
+--------------
+drop table if exists auto_incr_test,auto_incr_test2
+--------------
+
+Query OK, 0 rows affected
+
+--------------
+create table auto_incr_test (id int not null auto_increment, name char(40), timestamp timestamp, primary key (id))
+--------------
+
+Query OK, 0 rows affected
+
+--------------
+insert into auto_incr_test (name) values ("first record")
+--------------
+
+Query OK, 1 row affected
+
+--------------
+insert into auto_incr_test values (last_insert_id()+1,"second record",null)
+--------------
+
+Query OK, 1 row affected
+
+--------------
+insert into auto_incr_test (id,name) values (10,"tenth record")
+--------------
+
+Query OK, 1 row affected
+
+--------------
+insert into auto_incr_test values (0,"eleventh record",null)
+--------------
+
+Query OK, 1 row affected
+
+--------------
+insert into auto_incr_test values (last_insert_id()+1,"12","1997-01-01")
+--------------
+
+Query OK, 1 row affected
+
+--------------
+insert into auto_incr_test values (12,"this will not work",NULL)
+--------------
+
+ERROR 1062 at line 15: Duplicate entry '12' for key 1
+--------------
+replace into auto_incr_test values (12,"twelfth record",NULL)
+--------------
+
+Query OK, 2 rows affected
+
+--------------
+select * from auto_incr_test
+--------------
+
+id name timestamp
+1 first record 19980817042654
+2 second record 19980817042655
+10 tenth record 19980817042655
+11 eleventh record 19980817042655
+12 twelfth record 19980817042655
+5 rows in set
+
+--------------
+create table auto_incr_test2 (id int not null auto_increment, name char(40), primary key (id))
+--------------
+
+Query OK, 0 rows affected
+
+--------------
+insert into auto_incr_test2 select NULL,name from auto_incr_test
+--------------
+
+Query OK, 5 rows affected
+Records: 5 Duplicates: 0 Warnings: 0
+
+--------------
+insert into auto_incr_test2 select id,name from auto_incr_test
+--------------
+
+Query OK, 3 rows affected
+Records: 5 Duplicates: 2 Warnings: 0
+
+--------------
+replace into auto_incr_test2 select id,name from auto_incr_test
+--------------
+
+Query OK, 5 rows affected
+Records: 5 Duplicates: 5 Warnings: 0
+
+--------------
+select * from auto_incr_test2
+--------------
+
+id name
+1 first record
+2 second record
+3 tenth record
+4 eleventh record
+5 twelfth record
+10 tenth record
+11 eleventh record
+12 twelfth record
+8 rows in set
+
+--------------
+drop table auto_incr_test,auto_incr_test2
+--------------
+
+Query OK, 0 rows affected
+
+Bye
diff --git a/tests/auto_increment.tst b/tests/auto_increment.tst
new file mode 100644
index 00000000000..a11a05c8eff
--- /dev/null
+++ b/tests/auto_increment.tst
@@ -0,0 +1,27 @@
+#
+# Test of auto_increment
+#
+# run this program with mysql -vvf test < this file
+
+drop table if exists auto_incr_test,auto_incr_test2 ;
+
+create table auto_incr_test (id int not null auto_increment, name char(40), timestamp timestamp, primary key (id)) ;
+
+insert into auto_incr_test (name) values ("first record");
+insert into auto_incr_test values (last_insert_id()+1,"second record",null);
+insert into auto_incr_test (id,name) values (10,"tenth record");
+insert into auto_incr_test values (0,"eleventh record",null);
+insert into auto_incr_test values (last_insert_id()+1,"12","1997-01-01");
+insert into auto_incr_test values (12,"this will not work",NULL);
+replace into auto_incr_test values (12,"twelfth record",NULL);
+
+select * from auto_incr_test ;
+
+create table auto_incr_test2 (id int not null auto_increment, name char(40), primary key (id)) ;
+insert into auto_incr_test2 select NULL,name from auto_incr_test;
+insert into auto_incr_test2 select id,name from auto_incr_test;
+replace into auto_incr_test2 select id,name from auto_incr_test;
+
+select * from auto_incr_test2 ;
+
+drop table auto_incr_test,auto_incr_test2;
diff --git a/tests/big_record.pl b/tests/big_record.pl
new file mode 100755
index 00000000000..52d3dca5f7b
--- /dev/null
+++ b/tests/big_record.pl
@@ -0,0 +1,58 @@
+#!/usr/bin/perl
+
+# This is a test with stores big records in a blob
+# Note that for the default test the mysql server should have been
+# started with at least 'mysqld -O max_allowed_packet=200k'
+
+$host= shift || "";
+$test_db="test";
+$opt_user=$opt_password="";
+
+use DBI;
+$|= 1; # Autoflush
+
+$table="test_big_record";
+$rows=20; # Test of blobs up to ($rows-1)*10000+1 bytes
+
+print "Connection to database $test_db\n";
+
+$dbh = DBI->connect("DBI:mysql:$test_db:$host",$opt_user,$opt_password) || die "Can't connect: $DBI::errstr\n";
+
+$dbh->do("drop table if exists $table");
+
+print "Creating table $table\n";
+
+($dbh->do("\
+CREATE TABLE $table (
+ auto int(5) unsigned NOT NULL DEFAULT '0' auto_increment,
+ test mediumblob,
+ PRIMARY KEY (auto))")) or die $DBI::errstr;
+
+print "Inserting $rows records\n";
+
+for ($i=0 ; $i < $rows ; $i++)
+{
+ $tmp= chr(65+$i) x ($i*10000+1);
+ $tmp= $dbh->quote($tmp);
+ $dbh->do("insert into $table (test) values ($tmp)") or die $DBI::errstr;
+}
+
+print "Testing records\n";
+
+$sth=$dbh->prepare("select * from $table") or die $dbh->errstr;
+$sth->execute() or die $sth->errstr;
+
+$i=0;
+while (($row = $sth->fetchrow_arrayref))
+{
+ print $row->[0]," ",length($row->[1]),"\n";
+ die "Record $i had wrong data in blob" if ($row->[1] ne (chr(65+$i)) x ($i*10000+1));
+ $i++;
+}
+
+die "Didn't get all rows from server" if ($i != $rows);
+
+$dbh->do("drop table $table") or die $DBI::errstr;
+
+print "Test ok\n";
+exit 0;
diff --git a/tests/export.pl b/tests/export.pl
new file mode 100755
index 00000000000..47a13bab8e6
--- /dev/null
+++ b/tests/export.pl
@@ -0,0 +1,164 @@
+#!/usr/bin/perl
+
+# This is a test with uses two processes to a database.
+# The other inserts records in two tables, the other does a lot of joins
+# on these.
+#
+# Warning, the output from this test will differ in 'found' from time to time,
+# but there should never be any errors
+#
+
+$host= shift || "";
+$test_db="test";
+
+use Mysql;
+$|= 1; # Autoflush
+
+$org_file="/tmp/export-org.$$";
+$tmp_file="/tmp/export-old.$$";
+$tmp_file2="/tmp/export-new.$$";
+
+print "Connection to database $test_db\n";
+
+$dbh = Mysql->Connect($host) || die "Can't connect: $Mysql::db_errstr\n";
+$dbh->SelectDB($test_db) || die "Can't use database $test_db: $Mysql::db_errstr\n";
+
+$dbh->Query("drop table export"); # Ignore this error
+
+print "Creating table\n";
+
+($dbh->Query("\
+CREATE TABLE export (
+ auto int(5) unsigned NOT NULL DEFAULT '0' auto_increment,
+ string char(11) NOT NULL,
+ tiny tinyint(4) NOT NULL DEFAULT '0',
+ short smallint(6) NOT NULL DEFAULT '0',
+ medium mediumint(8) NOT NULL DEFAULT '0',
+ longint int(11) NOT NULL DEFAULT '0',
+ longlong bigint(20) NOT NULL DEFAULT '0',
+ real_float float(13,1) NOT NULL DEFAULT '0.0',
+ real_double double(13,1) NOT NULL,
+ utiny tinyint(3) unsigned NOT NULL DEFAULT '0',
+ ushort smallint(5) unsigned zerofill NOT NULL DEFAULT '00000',
+ umedium mediumint(8) unsigned NOT NULL DEFAULT '0',
+ ulong int(11) unsigned NOT NULL DEFAULT '0',
+ ulonglong bigint(20) unsigned NOT NULL DEFAULT '0',
+ time_stamp timestamp,
+ blob_col blob,
+ tinyblob_col tinyblob,
+ mediumblob_col tinyblob not null,
+ longblob_col longblob not null,
+ PRIMARY KEY (auto),
+ KEY (string(5)),
+ KEY unsigned_tinykey (utiny),
+ KEY (tiny),
+ KEY (short),
+ FOREIGN KEY (medium) references export,
+ KEY (longlong),
+ KEY (real_float),
+ KEY (real_double),
+ KEY (ushort),
+ KEY (umedium),
+ KEY (ulong),
+ KEY (ulonglong),
+ KEY (ulonglong,ulong))")) or die $Mysql::db_errstr;
+
+print "Inserting data\n";
+
+@A=("insert into export values (10, 1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1)",
+ "insert into export values (NULL,2,2,2,2,2,2,2,2,2,2,2,2,2,NULL,NULL,NULL,2,2)",
+ "insert into export values (0,1/3,3,3,3,3,3,3,3,3,3,3,3,3,3,'','','','3')",
+ "insert into export values (0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,'-1')",
+ "insert into export values (0,-4294967295,-4294967295,-4294967295,-4294967295,-4294967295,-4294967295,-4294967295,-4294967295,-4294967295,-4294967295,-4294967295,-4294967295,-4294967295,-4294967295,-4294967295,-4294967295,-4294967295,'-4294967295')",
+ "insert into export values (0,4294967295,4294967295,4294967295,4294967295,4294967295,4294967295,4294967295,4294967295,4294967295,4294967295,4294967295,4294967295,4294967295,4294967295,4294967295,4294967295,4294967295,'4294967295')",
+ "insert into export (string,tinyblob_col) values ('special','''\\0\\t\t\n''')",
+ "insert into export (string) values (',,!!\\\\##')",
+ "insert into export (tinyblob_col) values (',,!!!\\\\\\##')"
+ );
+
+foreach $A (@A)
+{
+ $dbh->Query($A) or die "query: $A returned: " . $Mysql::db_errstr;
+}
+
+
+print "Doing dump, load, check on different formats\n";
+
+@A=(# Ordinary format
+ "",
+ # Field terminated by something
+ "fields optionally enclosed by '+' escaped by '' terminated by ',,,' lines terminated by ',,,,'",
+ "fields enclosed by '' terminated by ',' lines terminated by ''",
+ "fields enclosed by '' terminated by ',' lines terminated by '!!'",
+ #Fields enclosed by
+ #"fields enclosed by '+' terminated by ''",
+ #"fields enclosed by '+' terminated by '' lines terminated by ''",
+ "fields enclosed by '+' terminated by ',,' lines terminated by '!!!'",
+ "fields enclosed by '+' terminated by ',,' lines terminated by '##'",
+ "fields enclosed by '+' escaped by '' terminated by ',,' lines terminated by '###'",
+ "fields enclosed by '+' escaped by '' terminated by '!' lines terminated by ''",
+ "fields enclosed by '+' terminated by ',' lines terminated by ''",
+ #Fields optionally enclosed by
+ "fields optionally enclosed by '+' terminated by ','",
+ "fields optionally enclosed by '+' terminated by ',' lines terminated by ''",
+ "fields optionally enclosed by '''' terminated by ',' lines starting by 'INSERT INTO a VALUES(' terminated by ');\n'",
+ );
+
+$dbh->Query("select * into outfile '$org_file' from export") or die $Mysql::db_errstr;
+
+
+foreach $A (@A)
+{
+ unlink($tmp_file);
+ unlink($tmp_file2);
+ $dbh->Query("select * into outfile '$tmp_file' $A from export") or die $Mysql::db_errstr;
+ $dbh->Query("delete from export") or die $Mysql::db_errstr;
+ $dbh->Query("load data infile '$tmp_file' into table export $A") or die $Mysql::db_errstr . " with format: $A\n";
+ $dbh->Query("select * into outfile '$tmp_file2' from export") or die $Mysql::db_errstr;
+ if (`cmp $tmp_file2 $org_file`)
+ {
+ print "Using format $A\n";
+ print "$tmp_file2 and $org_file differ. Plese check files\n";
+ exit 1;
+ }
+}
+
+
+@A=(#Fixed size fields
+ "fields enclosed by '' escaped by '' terminated by ''",
+ "fields enclosed by '' escaped by '' terminated by '' lines terminated by '\\r\\n'",
+ "fields enclosed by '' terminated by '' lines terminated by ''"
+ );
+
+unlink($org_file);
+
+$field_list="auto,ifnull(string,''),tiny,short,medium,longint,longlong,real_float,ifnull(real_double,''),utiny,ushort,umedium,ulong,ulonglong,time_stamp";
+
+$dbh->Query("select $field_list into outfile '$org_file' from export") or die $Mysql::db_errstr;
+
+$field_list="auto,string,tiny,short,medium,longint,longlong,real_float,real_double,utiny,ushort,umedium,ulong,ulonglong,time_stamp";
+
+foreach $A (@A)
+{
+ unlink($tmp_file);
+ unlink($tmp_file2);
+ $dbh->Query("select $field_list into outfile '$tmp_file' $A from export") or die $Mysql::db_errstr;
+ $dbh->Query("delete from export") or die $Mysql::db_errstr;
+ $dbh->Query("load data infile '$tmp_file' into table export $A ($field_list)") or die $Mysql::db_errstr;
+ $dbh->Query("select $field_list into outfile '$tmp_file2' from export") or die $Mysql::db_errstr;
+ if (`cmp $tmp_file2 $org_file`)
+ {
+ print "Using format $A\n";
+ print "$tmp_file2 and $org_file differ. Plese check files\n";
+ exit 1;
+ }
+}
+
+unlink($tmp_file);
+unlink($tmp_file2);
+unlink($org_file);
+
+$dbh->Query("drop table export") or die $Mysql::db_errstr;
+
+print "Test ok\n";
+exit 0;
diff --git a/tests/fork2_test.pl b/tests/fork2_test.pl
new file mode 100755
index 00000000000..e8a579d9d81
--- /dev/null
+++ b/tests/fork2_test.pl
@@ -0,0 +1,210 @@
+#!/usr/bin/perl -w
+
+# This is a test with uses 5 processes to insert, update and select from
+# two tables.
+# One inserts records in the tables, one updates some record in it and
+# the last 3 does different selects on the tables.
+# Er, hmmm..., something like that :^)
+# Modified to do crazy-join, à la Nasdaq.
+
+$opt_loop_count=10000; # Change this to make test harder/easier
+
+##################### Standard benchmark inits ##############################
+
+use Mysql;
+use Getopt::Long;
+use Benchmark;
+
+package main;
+
+$opt_skip_create=$opt_skip_in=$opt_verbose=$opt_fast_insert=
+ $opt_lock_tables=$opt_debug=$opt_skip_delete=$opt_fast=$opt_force=0;
+$opt_host=""; $opt_db="test";
+
+GetOptions("host=s","db=s","loop-count=i","skip-create","skip-in",
+ "skip-delete", "verbose","fast-insert","lock-tables","debug","fast",
+ "force") || die "Aborted";
+$opt_verbose=$opt_debug=$opt_lock_tables=$opt_fast_insert=$opt_fast=$opt_skip_in=$Mysql::db_errstr=$opt_force=undef; # Ignore warnings from these
+
+print "Testing 9 multiple connections to a server with 1 insert/update\n";
+print "and 8 select connections.\n";
+
+
+@testtables = qw(bench_f21 bench_f22 bench_f23 bench_f24 bench_f25);
+$numtables = $#testtables; # make emacs happier
+$dtable = "directory";
+####
+#### Start timeing and start test
+####
+
+$start_time=new Benchmark;
+if (!$opt_skip_create)
+{
+ $dbh = Mysql->Connect($opt_host, $opt_db) || die $Mysql::db_errstr;
+ $Mysql::QUIET = 1;
+ foreach $table (@testtables) {
+ $dbh->Query("drop table $table");
+ }
+ $dbh->Query("drop table $dtable");
+ $Mysql::QUIET = 0;
+
+ foreach $table (@testtables) {
+ print "Creating table $table in database $opt_db\n";
+ $dbh->Query("create table $table".
+ " (id int(6) not null,".
+ " info varchar(32),".
+ " marker timestamp,".
+ " primary key(id))")
+ or die $Mysql::db_errstr;
+ }
+ print "Creating directory table $dtable in $opt_db\n";
+ $dbh->Query("create table $dtable (id int(6), last int(6))")
+ or die $Mysql::db_errstr;
+ # Populate directory table
+ for $i ( 0 .. $numtables ) {
+ $dbh->Query("insert into $dtable values($i, 0)");
+ }
+ $dbh=0; # Close handler
+}
+$|= 1; # Autoflush
+
+####
+#### Start the tests
+####
+
+#$test_index = 0;
+
+test_1() if (($pid=fork()) == 0); $work{$pid}="insert";
+test_2() if (($pid=fork()) == 0); $work{$pid}="simple1";
+test_3() if (($pid=fork()) == 0); $work{$pid}="funny1";
+test_2() if (($pid=fork()) == 0); $work{$pid}="simple2";
+test_3() if (($pid=fork()) == 0); $work{$pid}="funny2";
+test_2() if (($pid=fork()) == 0); $work{$pid}="simple3";
+test_3() if (($pid=fork()) == 0); $work{$pid}="funny3";
+test_2() if (($pid=fork()) == 0); $work{$pid}="simple4";
+test_3() if (($pid=fork()) == 0); $work{$pid}="funny4";
+
+$errors=0;
+while (($pid=wait()) != -1)
+{
+ $ret=$?/256;
+ print "thread '" . $work{$pid} . "' finnished with exit code $ret\n";
+ $errors++ if ($ret != 0);
+}
+
+if (!$opt_skip_delete && !$errors)
+{
+ $dbh = Mysql->Connect($opt_host, $opt_db) || die $Mysql::db_errstr;
+ foreach $table (@testtables) {
+ $dbh->Query("drop table $table");
+ }
+}
+print ($errors ? "Test failed\n" :"Test ok\n");
+
+$end_time=new Benchmark;
+print "Total time: " .
+ timestr(timediff($end_time, $start_time),"noc") . "\n";
+
+exit(0);
+
+#
+# Insert records in the ?? tables the Nasdaq way
+#
+
+sub test_1
+{
+ my ($dbh,$table,$tmpvar,$rows,$found,$i);
+
+ $dbh = Mysql->Connect($opt_host, $opt_db) || die $Mysql::db_errstr;
+ $tmpvar=1;
+ $rows=$found=0;
+ for ($i=0 ; $i < $opt_loop_count; $i++)
+ {
+ $tmpvar^= ((($tmpvar + 63) + $i)*3 % $numtables);
+ # Nasdaq step 1:
+ $sth=$dbh->Query("select id,last from $dtable where id='$tmpvar'")
+ or die "Select directory row: $Mysql::db_errstr\n";
+ # Nasdaq step 2:
+ my ($did,$dlast) = $sth->FetchRow
+ or die "Fetch directory row: $Mysql::db_errstr\n";
+ $dlast++;
+ $sth=$dbh->Query("INSERT into $testtables[$did]".
+ " VALUES($dlast,'This is entry $dlast',NULL)")
+ || die "Got error on insert table $testtable[$did]:".
+ " $Mysql::db_errstr\n";
+ # Nasdaq step 3 - where my application hangs
+ $sth=$dbh->Query("update $dtable set last='$dlast' where id='$tmpvar'")
+ or die "Updating directory for table $testtable[$did]:".
+ " Mysql::db_errstr\n";
+ $rows++;
+ }
+ $dbh=0;
+ print "Test_1: Inserted $rows rows\n";
+ exit(0);
+}
+
+#
+# Nasdaq simple select
+#
+
+sub test_2
+{
+ my ($dbh,$id,$tmpvar,$rows,$found,$i);
+
+ $dbh = Mysql->Connect($opt_host, $opt_db) || die $Mysql::db_errstr;
+ $rows=$found=0;
+ $tmpvar=1;
+ for ($i=0 ; $i < $opt_loop_count ; $i++)
+ {
+ $tmpvar^= ((($tmpvar + 63) + $i)*3 % $numtables);
+ $sth=$dbh->Query("select a.id,a.info from $testtables[$tmpvar] as a,".
+ "$dtable as d".
+ " where a.id=d.last and $i >= 0")
+ || die "Got error select max: $Mysql::db_errstr\n";
+ if ((@row = $sth->FetchRow()) && defined($row[0]))
+ {
+ $found++;
+ }
+ }
+ $dbh=0;
+ print "Test_2: Found $found rows\n";
+ exit(0);
+}
+
+
+#
+# Nasdaq not-so-simple select
+#
+
+sub test_3
+{
+ my ($dbh,$id,$tmpvar,$rows,$i);
+ $dbh = Mysql->Connect($opt_host, $opt_db) || die $Mysql::db_errstr;
+ $rows=0;
+ $tmpvar ||= $numtables;
+ for ($i=0 ; $i < $opt_loop_count ; $i++)
+ {
+ $tmpvar^= ((($tmpvar + 63) + $i)*3 % $numtables);
+ $id1 = ($tmpvar+1) % $numtables;
+ $id2 = ($id1+1) % $numtables;
+ $id3 = ($id2+1) % $numtables;
+ $sth = $dbh->Query("SELECT greatest(a.id, b.id, c.id), a.info".
+ " FROM $testtables[$id1] as a,".
+ " $testtables[$id2] as b,".
+ " $testtables[$id3] as c,".
+ " $dtable as d1, $dtable as d2, $dtable as d3".
+ " WHERE ".
+ " d1.last=a.id AND d2.last=b.id AND d3.last=c.id".
+ " AND d1.id='$id1' AND d2.id='$id2'".
+ " AND d3.id='$id3'")
+ or die "Funny select: $Mysql::db_errstr\n";
+ $rows+=$sth->numrows;
+ }
+ $dbh=0;
+ print "Test_3: Found $rows rows\n";
+ exit(0);
+}
+
+
+
+
diff --git a/tests/fork3_test.pl b/tests/fork3_test.pl
new file mode 100755
index 00000000000..0ede221a7f4
--- /dev/null
+++ b/tests/fork3_test.pl
@@ -0,0 +1,150 @@
+#!/usr/bin/perl -w
+#
+# This is a test with uses 3 processes to insert, delete and select
+#
+
+$opt_loop_count=100000; # Change this to make test harder/easier
+
+##################### Standard benchmark inits ##############################
+
+use DBI;
+use Getopt::Long;
+use Benchmark;
+
+package main;
+
+$opt_skip_create=$opt_skip_in=$opt_verbose=$opt_fast_insert=
+ $opt_lock_tables=$opt_debug=$opt_skip_delete=$opt_fast=$opt_force=0;
+$opt_host=""; $opt_db="test";
+
+GetOptions("host=s","db=s","loop-count=i","skip-create","skip-in","skip-delete",
+"verbose","fast-insert","lock-tables","debug","fast","force") || die "Aborted";
+$opt_verbose=$opt_debug=$opt_lock_tables=$opt_fast_insert=$opt_fast=$opt_skip_in=$opt_force=undef; # Ignore warnings from these
+
+print "Testing 3 multiple connections to a server with 1 insert, 1 delete\n";
+print "and 1 select connections.\n";
+
+$firsttable = "bench_f1";
+
+####
+#### Start timeing and start test
+####
+
+$start_time=new Benchmark;
+if (!$opt_skip_create)
+{
+ $dbh = DBI->connect("DBI:mysql:$opt_db:$opt_host",
+ $opt_user, $opt_password,
+ { PrintError => 0}) || die $DBI::errstr;
+ $dbh->do("drop table if exists $firsttable");
+
+ print "Creating table $firsttable in database $opt_db\n";
+ $dbh->do("create table $firsttable (id int(6) not null, info varchar(32), marker char(1), primary key(id))") || die $DBI::errstr;
+ $dbh->disconnect; $dbh=0; # Close handler
+}
+$|= 1; # Autoflush
+
+####
+#### Start the tests
+####
+
+test_insert() if (($pid=fork()) == 0); $work{$pid}="insert";
+test_delete() if (($pid=fork()) == 0); $work{$pid}="delete";
+test_select() if (($pid=fork()) == 0); $work{$pid}="select1";
+
+$errors=0;
+while (($pid=wait()) != -1)
+{
+ $ret=$?/256;
+ print "thread '" . $work{$pid} . "' finnished with exit code $ret\n";
+ $errors++ if ($ret != 0);
+}
+
+if (!$opt_skip_delete && !$errors)
+{
+ $dbh = DBI->connect("DBI:mysql:$opt_db:$opt_host",
+ $opt_user, $opt_password,
+ { PrintError => 0}) || die $DBI::errstr;
+ $dbh->do("drop table $firsttable");
+ $dbh->disconnect; $dbh=0; # Close handler
+}
+print ($errors ? "Test failed\n" :"Test ok\n");
+
+$end_time=new Benchmark;
+print "Total time: " .
+ timestr(timediff($end_time, $start_time),"noc") . "\n";
+
+exit(0);
+
+#
+# Insert records in the table
+#
+
+sub test_insert
+{
+ my ($dbh,$i,$sth);
+
+ $dbh = DBI->connect("DBI:mysql:$opt_db:$opt_host",
+ $opt_user, $opt_password,
+ { PrintError => 0}) || die $DBI::errstr;
+ for ($i=0 ; $i < $opt_loop_count; $i++)
+ {
+ $sth=$dbh->do("insert into $firsttable values ($i,'This is entry $i','')") || die "Got error on insert: $Mysql::db_errstr\n";
+ $sth=0;
+ }
+ $dbh->disconnect; $dbh=0;
+ print "Test_insert: Inserted $i rows\n";
+ exit(0);
+}
+
+sub test_delete
+{
+ my ($dbh,$i,$sth,@row);
+
+ $dbh = DBI->connect("DBI:mysql:$opt_db:$opt_host",
+ $opt_user, $opt_password,
+ { PrintError => 0}) || die $DBI::errstr;
+ for ($i=0 ; $i < $opt_loop_count ; $i++)
+ {
+ sleep(5);
+ if ($opt_lock_tables)
+ {
+ $sth=$dbh->do("lock tables $firsttable WRITE") || die "Got error on lock tables $firsttable: $Mysql::db_errstr\n";
+ }
+ $sth=$dbh->prepare("select count(*) from $firsttable") || die "Got error on select from $firsttable: $dbh->errstr\n";
+ $sth->execute || die $dbh->errstr;
+ if ((@row = $sth->fetchrow_array()))
+ {
+ last if (!$row[0]); # Insert thread is probably ready
+ }
+ $sth=$dbh->do("delete from $firsttable") || die "Got error on delete from $firsttable: $dbh->errstr;\n";
+ }
+ $sth=0;
+ $dbh->disconnect; $dbh=0;
+ print "Test_delete: Deleted all rows $i times\n";
+ exit(0);
+}
+
+
+#
+# select records
+#
+
+sub test_select
+{
+ my ($dbh,$i,$sth,@row);
+
+ $dbh = DBI->connect("DBI:mysql:$opt_db:$opt_host",
+ $opt_user, $opt_password,
+ { PrintError => 0}) || die $DBI::errstr;
+ for ($i=0 ; $i < $opt_loop_count ; $i++)
+ {
+ $sth=$dbh->prepare("select count(*) from $firsttable") || die "Got error on select from $firsttable: $dbh->errstr;\n";
+ $sth->execute || die $dbh->errstr;
+ @row = $sth->fetchrow_array();
+ $sth=0;
+ }
+ $dbh->disconnect; $dbh=0;
+ print "Test_select: ok\n";
+ exit(0);
+}
diff --git a/tests/fork_test.pl b/tests/fork_test.pl
new file mode 100755
index 00000000000..cd166b84555
--- /dev/null
+++ b/tests/fork_test.pl
@@ -0,0 +1,247 @@
+#!/usr/bin/perl -w
+
+# This is a test with uses 5 processes to insert, update and select from
+# two tables.
+# One inserts records in the tables, one updates some record in it and
+# the last 3 does different selects on the tables.
+#
+
+$opt_loop_count=10000; # Change this to make test harder/easier
+
+##################### Standard benchmark inits ##############################
+
+use Mysql;
+use Getopt::Long;
+use Benchmark;
+
+package main;
+
+$opt_skip_create=$opt_skip_in=$opt_verbose=$opt_fast_insert=
+ $opt_lock_tables=$opt_debug=$opt_skip_delete=$opt_fast=$opt_force=0;
+$opt_host=""; $opt_db="test";
+
+GetOptions("host=s","db=s","loop-count=i","skip-create","skip-in",
+ "skip-delete","verbose","fast-insert","lock-tables","debug","fast",
+ "force") || die "Aborted";
+$opt_verbose=$opt_debug=$opt_lock_tables=$opt_fast_insert=$opt_fast=$opt_skip_in=$Mysql::db_errstr=$opt_force=undef; # Ignore warnings from these
+
+print "Testing 5 multiple connections to a server with 1 insert, 1 update\n";
+print "and 3 select connections.\n";
+
+
+$firsttable = "bench_f1";
+$secondtable = "bench_f2";
+
+####
+#### Start timeing and start test
+####
+
+$start_time=new Benchmark;
+if (!$opt_skip_create)
+{
+ $dbh = Mysql->Connect($opt_host, $opt_db) || die $Mysql::db_errstr;
+ $Mysql::QUIET = 1;
+ $dbh->Query("drop table $firsttable");
+ $dbh->Query("drop table $secondtable");
+ $Mysql::QUIET = 0;
+
+ print "Creating tables $firsttable and $secondtable in database $opt_db\n";
+ $dbh->Query("create table $firsttable (id int(6) not null, info varchar(32), marker char(1), primary key(id))") or die $Mysql::db_errstr;
+ $dbh->Query("create table $secondtable (id int(6) not null, row int(3) not null,value double, primary key(id,row))") or die $Mysql::db_errstr;
+
+ $dbh=0; # Close handler
+}
+$|= 1; # Autoflush
+
+####
+#### Start the tests
+####
+
+test_1() if (($pid=fork()) == 0); $work{$pid}="insert";
+test_2() if (($pid=fork()) == 0); $work{$pid}="update";
+test_3() if (($pid=fork()) == 0); $work{$pid}="select1";
+test_4() if (($pid=fork()) == 0); $work{$pid}="select2";
+test_5() if (($pid=fork()) == 0); $work{$pid}="select3";
+
+$errors=0;
+while (($pid=wait()) != -1)
+{
+ $ret=$?/256;
+ print "thread '" . $work{$pid} . "' finnished with exit code $ret\n";
+ $errors++ if ($ret != 0);
+}
+
+if (!$opt_skip_delete && !$errors)
+{
+ $dbh = Mysql->Connect($opt_host, $opt_db) || die $Mysql::db_errstr;
+ $dbh->Query("drop table $firsttable");
+ $dbh->Query("drop table $secondtable");
+}
+print ($errors ? "Test failed\n" :"Test ok\n");
+
+$end_time=new Benchmark;
+print "Total time: " .
+ timestr(timediff($end_time, $start_time),"noc") . "\n";
+
+exit(0);
+
+#
+# Insert records in the two tables
+#
+
+sub test_1
+{
+ my ($dbh,$tmpvar,$rows,$found,$i);
+
+ $dbh = Mysql->Connect($opt_host, $opt_db) || die $Mysql::db_errstr;
+ $tmpvar=1;
+ $rows=$found=0;
+ for ($i=0 ; $i < $opt_loop_count; $i++)
+ {
+ $tmpvar^= ((($tmpvar + 63) + $i)*3 % 100000);
+ $sth=$dbh->Query("insert into $firsttable values ($i,'This is entry $i','')") || die "Got error on insert: $Mysql::db_errstr\n";
+ $row_count=($i % 7)+1;
+ $rows+=1+$row_count;
+ for ($j=0 ; $j < $row_count; $j++)
+ {
+ $sth=$dbh->Query("insert into $secondtable values ($i,$j,0)") || die "Got error on insert: $Mysql::db_errstr\n";
+ }
+ if (($tmpvar % 10) == 0)
+ {
+ $sth=$dbh->Query("select max(info) from $firsttable") || die "Got error on select max(info): $Mysql::db_errstr\n";
+ $sth=$dbh->Query("select max(value) from $secondtable") || die "Got error on select max(info): $Mysql::db_errstr\n";
+ $found+=2;
+ }
+ }
+ $dbh=0;
+ print "Test_1: Inserted $rows rows, found $found rows\n";
+ exit(0);
+}
+
+#
+# Update records in both tables
+#
+
+sub test_2
+{
+ my ($dbh,$id,$tmpvar,$rows,$found,$i,$max_id,$tmp);
+
+ $dbh = Mysql->Connect($opt_host, $opt_db) || die $Mysql::db_errstr;
+ $tmpvar=111111;
+ $rows=$found=$max_id=$id=0;
+ for ($i=0 ; $i < $opt_loop_count ; $i++)
+ {
+ $tmp=(($tmpvar + 63) + $i)*3;
+ $tmp=$tmp-int($tmp/100000)*100000;
+ $tmpvar^= $tmp;
+ $tmp=$tmpvar - int($tmpvar/10)*10;
+ if ($max_id < 2 || $tmp == 0)
+ {
+ $max_id=0;
+ $sth=$dbh->Query("select max(id) from $firsttable where marker=''") || die "Got error select max: $Mysql::db_errstr\n";
+ if ((@row = $sth->FetchRow()) && defined($row[0]))
+ {
+ $found++;
+ $max_id=$id=$row[0];
+ }
+ }
+ else
+ {
+ $id= $tmpvar % ($max_id-1)+1;
+ }
+ if ($id)
+ {
+ $sth=$dbh->Query("update $firsttable set marker='x' where id=$id") || die "Got error update $firsttable: $Mysql::db_errstr\n";
+ $rows+=$sth->affected_rows;
+ if ($sth->affected_rows)
+ {
+ $sth=$dbh->Query("update $secondtable set value=$i where id=$id") || die "Got error update $firsttable: $Mysql::db_errstr\n";
+ $rows+=$sth->affected_rows;
+ }
+ }
+ }
+ $dbh=0;
+ print "Test_2: Found $found rows, Updated $rows rows\n";
+ exit(0);
+}
+
+
+#
+# select records
+#
+
+sub test_3
+{
+ my ($dbh,$id,$tmpvar,$rows,$i);
+ $dbh = Mysql->Connect($opt_host, $opt_db) || die $Mysql::db_errstr;
+ $tmpvar=222222;
+ $rows=0;
+ for ($i=0 ; $i < $opt_loop_count ; $i++)
+ {
+ $tmpvar^= ((($tmpvar + 63) + $i)*3 % 100000);
+ $id=$tmpvar % $opt_loop_count;
+ $sth=$dbh->Query("select id from $firsttable where id=$id") || die "Got error on select from $firsttable: $Mysql::db_errstr\n";
+ $rows+=$sth->numrows;
+ }
+ $dbh=0;
+ print "Test_3: Found $rows rows\n";
+ exit(0);
+}
+
+
+#
+# Note that this uses row=1 and in some cases won't find any matching
+# records
+#
+
+sub test_4
+{
+ my ($dbh,$id,$tmpvar,$rows,$i);
+ $dbh = Mysql->Connect($opt_host, $opt_db) || die $Mysql::db_errstr;
+ $tmpvar=333333;
+ $rows=0;
+ for ($i=0 ; $i < $opt_loop_count; $i++)
+ {
+ $tmpvar^= ((($tmpvar + 63) + $i)*3 % 100000);
+ $id=$tmpvar % $opt_loop_count;
+ $sth=$dbh->Query("select id from $secondtable where id=$id") || die "Got error on select form $secondtable: $Mysql::db_errstr\n";
+ $rows+=$sth->numrows;
+ }
+ $dbh=0;
+ print "Test_4: Found $rows rows\n";
+ exit(0);
+}
+
+
+sub test_5
+{
+ my ($dbh,$id,$tmpvar,$rows,$i,$max_id);
+ $dbh = Mysql->Connect($opt_host, $opt_db) || die $Mysql::db_errstr;
+ $tmpvar=444444;
+ $rows=$max_id=0;
+ for ($i=0 ; $i < $opt_loop_count ; $i++)
+ {
+ $tmpvar^= ((($tmpvar + 63) + $i)*3 % 100000);
+ if ($max_id == 0 || ($tmpvar % 10 == 0))
+ {
+ $sth=$dbh->Query("select max(id) from $firsttable") || die "Got error select max: $Mysql::db_errstr\n";
+ if ((@row = $sth->FetchRow()) && defined($row[0]))
+ {
+ $max_id=$id=$row[0];
+ }
+ else
+ {
+ $id=0;
+ }
+ }
+ else
+ {
+ $id= $tmpvar % $max_id;
+ }
+ $sth=$dbh->Query("select value from $firsttable,$secondtable where $firsttable.id=$id and $secondtable.id=$firsttable.id") || die "Got error on select form $secondtable: $Mysql::db_errstr\n";
+ $rows+=$sth->numrows;
+ }
+ $dbh=0;
+ print "Test_5: Found $rows rows\n";
+ exit(0);
+}
diff --git a/tests/function.res b/tests/function.res
new file mode 100644
index 00000000000..a2322020d74
--- /dev/null
+++ b/tests/function.res
@@ -0,0 +1,258 @@
+--------------
+select 1+1,1-1,1+1*2,8/5,8%5,mod(8,5),mod(8,5)|0,-(1+1)*-2,sign(-5)
+--------------
+
+1+1 1-1 1+1*2 8/5 8%5 mod(8,5) mod(8,5)|0 -(1+1)*-2 sign(-5)
+2 0 3 1.60 3 3 3 4 -1
+--------------
+select floor(5.5),floor(-5.5),ceiling(5.5),ceiling(-5.5),round(5.5),round(-5.5)
+--------------
+
+floor(5.5) floor(-5.5) ceiling(5.5) ceiling(-5.5) round(5.5) round(-5.5)
+5 -6 6 -5 6 -6
+--------------
+select abs(-10),log(exp(10)),exp(log(sqrt(10))*2),pow(10,log10(10)),rand(999999),rand()
+--------------
+
+abs(-10) log(exp(10)) exp(log(sqrt(10))*2) pow(10,log10(10)) rand(999999) rand()
+10 10.000000 10.000000 10.000000 0.1844 0.7637
+--------------
+select least(6,1.0,2.0),greatest(3,4,5,0)
+--------------
+
+least(6,1.0,2.0) greatest(3,4,5,0)
+1.0 5
+--------------
+select 1 | (1+1),5 & 3,bit_count(7)
+--------------
+
+1 | (1+1) 5 & 3 bit_count(7)
+3 1 3
+--------------
+select 0=0,1>0,1>=1,1<0,1<=0,strcmp("abc","abcd"),strcmp("b","a"),strcmp("a","a")
+--------------
+
+0=0 1>0 1>=1 1<0 1<=0 strcmp("abc","abcd") strcmp("b","a") strcmp("a","a")
+1 1 1 0 0 -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 "abc" like "a%", "abc" not like "%d%", "ab" like "a\%", "a%" like "a\%","abcd" like "a%b_%d"
+--------------
+
+"abc" like "a%" "abc" not like "%d%" "ab" like "a\%" "a%" like "a\%" "abcd" like "a%b_%d"
+1 1 0 1 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 !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 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 '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 concat("monty"," was here ","again"),length("hello"),ascii("hello")
+--------------
+
+concat("monty"," was here ","again") length("hello") ascii("hello")
+monty was here again 5 104
+--------------
+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
+--------------
+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 concat("!",ltrim(" left "),"!",rtrim(" right "),"!")
+--------------
+
+concat("!",ltrim(" left "),"!",rtrim(" right "),"!")
+!left ! right!
+--------------
+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
+--------------
+select password("test")
+--------------
+
+password("test")
+378b243e220ca493
+--------------
+select 0x41,0x41+0,0x41 | 0x7fffffffffffffff | 0,0xffffffffffffffff | 0
+--------------
+
+0x41 0x41+0 0x41 | 0x7fffffffffffffff | 0 0xffffffffffffffff | 0
+A 65 9223372036854775807 -1
+--------------
+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 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 database(),user()
+--------------
+
+database() user()
+ monty
+--------------
+select 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 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 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,NULL IS NULL, NULL IS NOT NULL,IFNULL(NULL,1.1)+0,IFNULL(NULL,1) | 0
+--------------
+
+NULL=NULL NULL<>NULL NULL IS NULL NULL IS NOT NULL IFNULL(NULL,1.1)+0 IFNULL(NULL,1) | 0
+NULL NULL 1 0 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 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
+--------------
+
+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
+0 0 NULL NULL NULL 0 0
+--------------
+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")
+--------------
+
+elt(2,1) field(NULL,"a","b","c")
+NULL 0
+--------------
+select locate("a","b",2),locate("","a",1),ltrim("a"),rtrim("a")
+--------------
+
+locate("a","b",2) locate("","a",1) ltrim("a") rtrim("a")
+0 1 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 from_days(to_days("960101")),to_days(960201)-to_days("19960101"),to_days(curdate()+1)-to_days(curdate()),weekday("1997-01-01")
+--------------
+
+from_days(to_days("960101")) to_days(960201)-to_days("19960101") to_days(curdate()+1)-to_days(curdate()) weekday("1997-01-01")
+1996-01-01 31 1 2
+--------------
+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 now(),now()+0,curdate(),weekday(curdate()),weekday(now()),unix_timestamp(),unix_timestamp(now())
+--------------
+
+now() now()+0 curdate() weekday(curdate()) weekday(now()) unix_timestamp() unix_timestamp(now())
+1998-08-17 04:24:33 19980817042433 1998-08-17 0 0 903317073 903317073
diff --git a/tests/function.tst b/tests/function.tst
new file mode 100644
index 00000000000..5b8746e8d3c
--- /dev/null
+++ b/tests/function.tst
@@ -0,0 +1,80 @@
+# Test of functions
+#
+# mysql -v < this_file
+
+#
+# numerical functions
+#
+select 1+1,1-1,1+1*2,8/5,8%5,mod(8,5),mod(8,5)|0,-(1+1)*-2,sign(-5) ;
+select floor(5.5),floor(-5.5),ceiling(5.5),ceiling(-5.5),round(5.5),round(-5.5);
+select abs(-10),log(exp(10)),exp(log(sqrt(10))*2),pow(10,log10(10)),rand(999999),rand();
+select least(6,1.0,2.0),greatest(3,4,5,0) ;
+select 1 | (1+1),5 & 3,bit_count(7) ;
+#
+# test functions
+#
+select 0=0,1>0,1>=1,1<0,1<=0,strcmp("abc","abcd"),strcmp("b","a"),strcmp("a","a") ;
+select "a"<"b","a"<="b","b">="a","b">"a","a"="A","a"<>"b";
+select "abc" like "a%", "abc" not like "%d%", "ab" like "a\%", "a%" like "a\%","abcd" like "a%b_%d";
+select "Det här är svenska" regexp "h[[:alpha:]]+r", "aba" regexp "^(a|b)*$";
+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;
+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 ;
+select 2 between 1 and 3, "monty" between "max" and "my",2=2 and "monty" between "max" and "my" and 3=3;
+select 2 in (3,2,5,9,5,1),"monty" in ("david","monty","allan"), 1.2 in (1.4,1.2,1.0);
+
+#
+# string functions
+#
+select 'hello',"'hello'",'""hello""','''h''e''l''l''o''',"hel""lo",'hel\'lo';
+select concat("monty"," was here ","again"),length("hello"),ascii("hello");
+select locate("he","hello"),locate("he","hello",2),locate("lo","hello",2) ;
+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 concat("!",ltrim(" left "),"!",rtrim(" right "),"!");
+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");
+#
+# varbinary as string and number
+#
+select 0x41,0x41+0,0x41 | 0x7fffffffffffffff | 0,0xffffffffffffffff | 0 ;
+
+#
+# misc functions
+#
+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;
+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);
+
+#
+# system functions
+#
+select database(),user();
+
+#
+# Null tests
+#
+select 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;
+select 1 | NULL,1 & NULL,1+NULL,1-NULL;
+select NULL=NULL,NULL<>NULL,NULL IS NULL, NULL IS NOT NULL,IFNULL(NULL,1.1)+0,IFNULL(NULL,1) | 0;
+select strcmp("a",NULL),(1<NULL)+0.0,NULL regexp "a",null like "a%","a%" like 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);
+select field(NULL,"a","b","c");
+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;
+#
+# Wrong or 'funny' use of functions.
+#
+select insert("aa",100,1,"b"),insert("aa",1,3,"b"),left("aa",-1),substring("a",1,2);
+select elt(2,1),field(NULL,"a","b","c");
+select locate("a","b",2),locate("","a",1),ltrim("a"),rtrim("a");
+select concat("1","2")|0,concat("1",".5")+0.0;
+
+#
+# time functions
+# The last line should return new values for each test run
+#
+select from_days(to_days("960101")),to_days(960201)-to_days("19960101"),to_days(curdate()+1)-to_days(curdate()),weekday("1997-01-01") ;
+select period_add("9602",-12),period_diff(199505,"9404") ;
+select now()-now(),weekday(curdate())-weekday(now()),unix_timestamp()-unix_timestamp(now());
+select now(),now()+0,curdate(),weekday(curdate()),weekday(now()),unix_timestamp(),unix_timestamp(now());
diff --git a/tests/grant.pl b/tests/grant.pl
new file mode 100644
index 00000000000..a34a2909897
--- /dev/null
+++ b/tests/grant.pl
@@ -0,0 +1,545 @@
+#!/usr/bin/perl
+#
+# Testing of grants.
+# Note that this will delete all table and column grants !
+#
+
+use DBI;
+use Getopt::Long;
+use strict;
+
+use vars qw($dbh $user_dbh $opt_help $opt_Information $opt_force $opt_debug
+ $opt_verbose $opt_server $opt_root_user $opt_password $opt_user
+ $opt_database $opt_host $version $user $tables_cols $columns_cols);
+
+$version="1.0";
+$opt_help=$opt_Information=$opt_force=$opt_debug=$opt_verbose=0;
+$opt_host="localhost",
+$opt_server="mysql";
+$opt_root_user="root";
+$opt_password="";
+$opt_user="grant_user";
+$opt_database="grant_test";
+
+GetOptions("Information","help","server=s","root-user=s","password=s","user","database=s","force","host=s","debug","verbose") || usage();
+usage() if ($opt_help || $opt_Information);
+
+$user="$opt_user\@$opt_host";
+
+if (!$opt_force)
+{
+ print_info()
+}
+
+$|=1;
+
+$tables_cols="Host, Db, User, Table_name, Grantor, Table_priv, Column_priv";
+$columns_cols="Host, Db, User, Table_name, Column_name, Column_priv";
+
+#
+# clear grant tables
+#
+
+$dbh = DBI->connect("DBI:mysql:mysql:$opt_host;mysql_read_default_group=perl",
+ $opt_root_user,$opt_password,
+ { PrintError => 0}) || die "Can't connect to mysql server: $DBI::errstr\n";
+
+safe_query("delete from user where user='$opt_user' or user='${opt_user}2'");
+safe_query("delete from db where user='$opt_user'");
+safe_query("delete from tables_priv");
+safe_query("delete from columns_priv");
+safe_query("lock tables mysql.user write"); # Test lock tables
+safe_query("flush privileges");
+safe_query("unlock tables"); # should already be unlocked
+safe_query("drop database $opt_database",2);
+safe_query("create database $opt_database");
+
+# check that the user can't login yet
+
+user_connect(1);
+#goto test;
+
+#
+# Test grants on user level
+#
+
+safe_query("grant select on *.* to $user");
+safe_query("set password FOR ${opt_user}2\@$opt_host = password('test')",1);
+safe_query("set password FOR $opt_user=password('test')");
+user_connect(1);
+safe_query("set password FOR $opt_user=''");
+user_connect(0);
+user_query("select * from mysql.user where user = '$opt_user'");
+user_query("select * from mysql.db where user = '$opt_user'");
+safe_query("grant select on *.* to $user,$user");
+
+# The following should fail
+user_query("insert into mysql.user (host,user) values ('error','$opt_user')",1);
+user_query("update mysql.user set host='error' WHERE user='$opt_user'",1);
+user_query("create table $opt_database.test (a int,b int)",1);
+user_query("grant select on *.* to ${opt_user}2\@$opt_host",1);
+safe_query("revoke select on $opt_database.test from $opt_user\@opt_host",1);
+safe_query("revoke select on $opt_database.* from $opt_user\@opt_host",1);
+safe_query("revoke select on *.* from $opt_user",1);
+safe_query("grant select on $opt_database.not_exists to $opt_user",1);
+safe_query("grant FILE on $opt_database.test to $opt_user",1);
+safe_query("grant select on *.* to wrong___________user_name",1);
+safe_query("grant select on $opt_database.* to wrong___________user_name",1);
+user_query("grant select on $opt_database.test to $opt_user with grant option",1);
+safe_query("set password FOR ''\@''=''",1);
+user_query("set password FOR root\@$opt_host = password('test')",1);
+
+# Change privileges for user
+safe_query("revoke select on *.* from $user");
+safe_query("grant create on *.* to $user");
+user_connect(0);
+user_query("create table $opt_database.test (a int,b int)");
+
+safe_query("grant select(c) on $opt_database.test to $user",1);
+safe_query("revoke select(c) on $opt_database.test from $user",1);
+safe_query("grant select on $opt_database.test to wrong___________user_name",1);
+user_query("INSERT INTO $opt_database.test values (2,0)",1);
+
+safe_query("grant ALL PRIVILEGES on *.* to $user");
+safe_query("REVOKE INSERT on *.* from $user");
+user_connect(0);
+user_query("INSERT INTO $opt_database.test values (1,0)",1);
+safe_query("grant INSERT on *.* to $user");
+user_connect(0);
+user_query("INSERT INTO $opt_database.test values (2,0)");
+user_query("select count(*) from $opt_database.test");
+safe_query("revoke SELECT on *.* from $user");
+user_connect(0);
+user_query("select count(*) from $opt_database.test",1);
+user_query("INSERT INTO $opt_database.test values (3,0)");
+safe_query("grant SELECT on *.* to $user");
+user_connect(0);
+user_query("select count(*) from $opt_database.test");
+safe_query("revoke ALL PRIVILEGES on *.* from $user");
+user_connect(1);
+safe_query("delete from user where user='$opt_user'");
+safe_query("flush privileges");
+if (0) # Only if no anonymous user on localhost.
+{
+ safe_query("grant select on *.* to $opt_user");
+ user_connect(0);
+ safe_query("revoke select on *.* from $opt_user");
+ user_connect(1);
+}
+safe_query("delete from user where user='$opt_user'");
+safe_query("flush privileges");
+
+#
+# Test grants on database level
+#
+safe_query("grant select on $opt_database.* to $user");
+safe_query("select * from mysql.user where user = '$opt_user'");
+safe_query("select * from mysql.db where user = '$opt_user'");
+user_connect(0);
+user_query("select count(*) from $opt_database.test");
+# The following should fail
+user_query("select * from mysql.user where user = '$opt_user'",1);
+user_query("insert into $opt_database.test values (4,0)",1);
+user_query("update $opt_database.test set a=1",1);
+user_query("delete from $opt_database.test",1);
+user_query("create table $opt_database.test2 (a int)",1);
+user_query("ALTER TABLE $opt_database.test add c int",1);
+user_query("CREATE INDEX dummy ON $opt_database.test (a)",1);
+user_query("drop table $opt_database.test",1);
+user_query("grant ALL PRIVILEGES on $opt_database.* to ${opt_user}2\@$opt_host",1);
+
+# Change privileges for user
+safe_query("grant ALL PRIVILEGES on $opt_database.* to $user WITH GRANT OPTION");
+user_connect(0);
+user_query("insert into $opt_database.test values (5,0)");
+safe_query("REVOKE ALL PRIVILEGES on * from $user",1);
+safe_query("REVOKE ALL PRIVILEGES on *.* from $user");
+safe_query("REVOKE ALL PRIVILEGES on $opt_database.* from $user");
+safe_query("REVOKE ALL PRIVILEGES on $opt_database.* from $user");
+user_connect(0);
+user_query("insert into $opt_database.test values (6,0)",1);
+safe_query("REVOKE GRANT OPTION on $opt_database.* from $user");
+user_connect(1);
+safe_query("grant ALL PRIVILEGES on $opt_database.* to $user");
+
+user_connect(0);
+user_query("select * from mysql.user where user = '$opt_user'",1);
+user_query("insert into $opt_database.test values (7,0)");
+user_query("update $opt_database.test set a=3 where a=2");
+user_query("delete from $opt_database.test where a=3");
+user_query("create table $opt_database.test2 (a int not null)");
+user_query("alter table $opt_database.test2 add b int");
+user_query("create index dummy on $opt_database.test2 (a)");
+user_query("drop table $opt_database.test2");
+user_query("show tables");
+
+# These should fail
+user_query("insert into mysql.user (host,user) values ('error','$opt_user',0)",1);
+
+# Revoke database privileges
+safe_query("revoke ALL PRIVILEGES on $opt_database.* from $user");
+safe_query("select * from mysql.user where user = '$opt_user'");
+safe_query("select * from mysql.db where user = '$opt_user'");
+user_connect(1);
+
+#
+# Test of grants on table level
+#
+
+safe_query("grant create on $opt_database.test2 to $user");
+user_connect(0);
+user_query("create table $opt_database.test2 (a int not null)");
+user_query("show tables"); # Should only show test, not test2
+user_query("show columns from test",1);
+user_query("show keys from test",1);
+user_query("show columns from test2");
+user_query("show keys from test2");
+user_query("select * from test",1);
+safe_query("grant insert on $opt_database.test to $user");
+user_query("show tables");
+user_query("insert into $opt_database.test values (8,0)");
+user_query("update $opt_database.test set b=1",1);
+safe_query("grant update on $opt_database.test to $user");
+user_query("update $opt_database.test set b=2");
+user_query("delete from $opt_database.test",1);
+safe_query("grant delete on $opt_database.test to $user");
+user_query("delete from $opt_database.test where a=1",1);
+user_query("update $opt_database.test set b=3 where b=1",1);
+user_query("update $opt_database.test set b=b+1",1);
+
+# Add one privilege at a time until the user has all privileges
+user_query("select * from test",1);
+safe_query("grant select on $opt_database.test to $user");
+user_query("delete from $opt_database.test where a=1");
+user_query("update $opt_database.test set b=2 where b=1");
+user_query("update $opt_database.test set b=b+1");
+user_query("select count(*) from test");
+
+user_query("create table $opt_database.test3 (a int)",1);
+user_query("alter table $opt_database.test2 add c int",1);
+safe_query("grant alter on $opt_database.test2 to $user");
+user_query("alter table $opt_database.test2 add c int");
+user_query("create index dummy ON $opt_database.test (a)",1);
+safe_query("grant index on $opt_database.test2 to $user");
+user_query("create index dummy ON $opt_database.test2 (a)");
+user_query("insert into test2 SELECT a,a from test",1);
+safe_query("grant insert on test2 to $user",1); # No table: mysql.test2
+safe_query("grant insert(a) on $opt_database.test2 to $user");
+user_query("insert into test2 SELECT a,a from test",1);
+safe_query("grant insert(c) on $opt_database.test2 to $user");
+user_query("insert into test2 SELECT a,a from test");
+user_query("select count(*) from test2,test",1);
+user_query("select count(*) from test,test2",1);
+user_query("replace into test2 SELECT a from test",1);
+safe_query("grant update on $opt_database.test2 to $user");
+user_query("replace into test2 SELECT a,a from test",1);
+safe_query("grant DELETE on $opt_database.test2 to $user");
+user_query("replace into test2 SELECT a,a from test");
+user_query("insert into test (a) SELECT a from test2",1);
+
+user_query("drop table $opt_database.test2",1);
+user_query("grant select on $opt_database.test2 to $user with grant option",1);
+safe_query("grant drop on $opt_database.test2 to $user with grant option");
+user_query("grant drop on $opt_database.test2 to $user with grant option");
+user_query("grant select on $opt_database.test2 to $user with grant option",1);
+user_query("drop table $opt_database.test2");
+
+# Check that the user doesn't have some user privileges
+user_query("create database $opt_database",1);
+user_query("drop database $opt_database",1);
+user_query("flush tables",1);
+safe_query("flush privileges");
+
+safe_query("select $tables_cols from mysql.tables_priv");
+safe_query("revoke ALL PRIVILEGES on $opt_database.test from $user");
+safe_query("revoke ALL PRIVILEGES on $opt_database.test2 from $user");
+safe_query("revoke GRANT OPTION on $opt_database.test2 from $user");
+safe_query("select $tables_cols from mysql.tables_priv");
+
+user_query("select count(a) from test",1);
+
+#
+# Test some grants on column level
+#
+
+user_query("delete from $opt_database.test where a=2",1);
+user_query("delete from $opt_database.test where A=2",1);
+user_query("update test set b=5 where b>0",1);
+safe_query("grant update(b),delete on $opt_database.test to $user");
+safe_query("revoke update(a) on $opt_database.test from $user",1);
+user_query("delete from $opt_database.test where a=2",1);
+user_query("update test set b=5 where b>0",1);
+safe_query("grant select(a),select(b) on $opt_database.test to $user");
+user_query("delete from $opt_database.test where a=2");
+user_query("delete from $opt_database.test where A=2");
+user_query("update test set b=5 where b>0");
+user_query("update test set a=11 where b>5",1);
+user_query("select a,A from test");
+
+safe_query("select $tables_cols from mysql.tables_priv");
+safe_query("revoke ALL PRIVILEGES on $opt_database.test from $user");
+safe_query("select $tables_cols from mysql.tables_priv");
+safe_query("revoke GRANT OPTION on $opt_database.test from $user",1);
+#
+# Test grants on database level
+#
+
+safe_query("grant select(a) on $opt_database.test to $user");
+user_query("show columns from test");
+safe_query("grant insert (b), update (b) on $opt_database.test to $user");
+
+user_query("select count(a) from test");
+user_query("select count(skr.a) from test as skr");
+user_query("select count(a) from test where a > 5");
+user_query("insert into test (b) values (5)");
+user_query("insert into test (b) values (a)");
+user_query("update test set b=3 where a > 0");
+
+user_query("select * from test",1);
+user_query("select b from test",1);
+user_query("select a from test where b > 0",1);
+user_query("insert into test (a) values (10)",1);
+user_query("insert into test (b) values (b)",1);
+user_query("insert into test (a,b) values (1,5)",1);
+user_query("insert into test (b) values (1),(b)",1);
+user_query("update test set b=3 where b > 0",1);
+
+safe_query("select $tables_cols from mysql.tables_priv");
+safe_query("select $columns_cols from mysql.columns_priv");
+safe_query("revoke select(a), update (b) on $opt_database.test from $user");
+safe_query("select $tables_cols from mysql.tables_priv");
+safe_query("select $columns_cols from mysql.columns_priv");
+
+user_query("select count(a) from test",1);
+user_query("update test set b=4",1);
+
+safe_query("grant select(a,b), update (a,b) on $opt_database.test to $user");
+user_query("select count(a),count(b) from test where a+b > 0");
+user_query("insert into test (b) values (9)");
+user_query("update test set b=6 where b > 0");
+
+safe_query("flush privileges"); # Test restoring privileges from disk
+safe_query("select $tables_cols from mysql.tables_priv");
+safe_query("select $columns_cols from mysql.columns_priv");
+
+# Try mixing of table and database privileges
+
+user_query("insert into test (a,b) values (12,12)",1);
+safe_query("grant insert on $opt_database.* to $user");
+user_connect(0);
+user_query("insert into test (a,b) values (13,13)");
+
+# This grants and revokes SELECT on different levels.
+safe_query("revoke select(b) on $opt_database.test from $user");
+user_query("select count(a) from test where a+b > 0",1);
+user_query("update test set b=5 where a=2");
+safe_query("grant select on $opt_database.test to $user");
+user_connect(0);
+user_query("select count(a) from test where a+b > 0");
+safe_query("revoke select(b) on $opt_database.test from $user");
+user_query("select count(a) from test where a+b > 0");
+safe_query("revoke select on $opt_database.test from $user");
+user_connect(0);
+user_query("select count(a) from test where a+b > 0",1);
+safe_query("grant select(a) on $opt_database.test to $user");
+user_query("select count(a) from test where a+b > 0",1);
+safe_query("grant select on *.* to $user");
+user_connect(0);
+user_query("select count(a) from test where a+b > 0");
+safe_query("revoke select on *.* from $user");
+safe_query("grant select(b) on $opt_database.test to $user");
+user_connect(0);
+user_query("select count(a) from test where a+b > 0");
+
+
+safe_query("select * from mysql.db where user = '$opt_user'");
+safe_query("select $tables_cols from mysql.tables_priv where user = '$opt_user'");
+safe_query("select $columns_cols from mysql.columns_priv where user = '$opt_user'");
+
+safe_query("revoke ALL PRIVILEGES on $opt_database.test from $user");
+user_query("select count(a) from test",1);
+user_query("select * from mysql.user",1);
+safe_query("select * from mysql.db where user = '$opt_user'");
+safe_query("select $tables_cols from mysql.tables_priv where user = '$opt_user'");
+safe_query("select $columns_cols from mysql.columns_priv where user = '$opt_user'");
+
+#
+# Test IDENTIFIED BY
+#
+
+safe_query("delete from user where user='$opt_user'");
+safe_query("flush privileges");
+safe_query("grant ALL PRIVILEGES on $opt_database.test to $user identified by 'dummy', ${opt_user}\@127.0.0.1 identified by 'dummy2'");
+user_connect(0,"dummy");
+safe_query("grant SELECT on $opt_database.* to $user identified by ''");
+user_connect(0);
+
+#
+# Clean up things
+#
+
+safe_query("drop database $opt_database");
+safe_query("delete from user where user='$opt_user'");
+safe_query("delete from db where user='$opt_user'");
+safe_query("delete from tables_priv");
+safe_query("delete from columns_priv");
+safe_query("flush privileges");
+
+print "end of test\n";
+exit 0;
+
+sub usage
+{
+ print <<EOF;
+$0 Ver $version
+
+This program tests that the GRANT commands works by creating a temporary
+database ($opt_database) and user ($opt_user).
+
+Options:
+
+--database (Default $opt_database)
+ In which database the test tables are created.
+
+--force
+ Don''t ask any question before starting this test.
+
+--host='host name' (Default $opt_host)
+ Host name where the database server is located.
+
+--Information
+--help
+ Print this help
+
+--password
+ Password for root-user.
+
+--server='server name' (Default $opt_server)
+ Run the test on the given SQL server.
+
+--user (Default $opt_user)
+ A non-existing user on which we will test the GRANT commands.
+
+--verbose
+ Write all queries when we are execute them.
+
+--root-user='user name' (Default $opt_root_user)
+ User with privileges to modify the 'mysql' database.
+EOF
+ exit(0);
+}
+
+
+sub print_info
+{
+ my $tmp;
+ print <<EOF;
+This test will clear your table and column grant table and recreate the
+$opt_database database ! All privileges for $user will be destroyed !
+
+Don\'t run this test if you have done any GRANT commands that you want to keep!
+EOF
+ for (;;)
+ {
+ print "Start test (yes/no) ? ";
+ $tmp=<STDIN>; chomp($tmp); $tmp=lc($tmp);
+ last if ($tmp =~ /^yes$/i);
+ exit 1 if ($tmp =~ /^n/i);
+ print "\n";
+ }
+}
+
+
+sub user_connect
+{
+ my ($ignore_error,$password)=@_;
+ $password="" if (!defined($password));
+
+ print "Connecting $opt_user\n" if ($opt_verbose);
+ $user_dbh->disconnect if (defined($user_dbh));
+
+ $user_dbh=DBI->connect("DBI:mysql:$opt_database:$opt_host",$opt_user,
+ $password, { PrintError => 0});
+ if (!$user_dbh)
+ {
+ print "$DBI::errstr\n";
+ if (!$ignore_error)
+ {
+ die "The above should not have failed!";
+ }
+ }
+ elsif ($ignore_error)
+ {
+ die "Connect succeeded when it shouldn't have !\n";
+ }
+}
+
+sub safe_query
+{
+ my ($query,$ignore_error)=@_;
+ if (do_query($dbh,$query))
+ {
+ if (!defined($ignore_error))
+ {
+ die "The above should not have failed!";
+ }
+ }
+ elsif (defined($ignore_error) && $ignore_error == 1)
+ {
+ die "Query '$query' succeeded when it shouldn't have !\n";
+ }
+}
+
+
+sub user_query
+{
+ my ($query,$ignore_error)=@_;
+ if (do_query($user_dbh,$query))
+ {
+ if (!defined($ignore_error))
+ {
+ die "The above should not have failed!";
+ }
+ }
+ elsif (defined($ignore_error) && $ignore_error == 1)
+ {
+ die "Query '$query' succeeded when it shouldn't have !\n";
+ }
+}
+
+
+sub do_query
+{
+ my ($my_dbh, $query)=@_;
+ my ($sth,$row,$tab,$col,$found);
+
+ print "$query\n" if ($opt_debug || $opt_verbose);
+ if (!($sth= $my_dbh->prepare($query)))
+ {
+ print "Error in prepare: $DBI::errstr\n";
+ return 1;
+ }
+ if (!$sth->execute)
+ {
+ print "Error in execute: $DBI::errstr\n";
+ die if ($DBI::errstr =~ /parse error/);
+ $sth->finish;
+ return 1;
+ }
+ $found=0;
+ while (($row=$sth->fetchrow_arrayref))
+ {
+ $found=1;
+ $tab="";
+ foreach $col (@$row)
+ {
+ print $tab;
+ print defined($col) ? $col : "NULL";
+ $tab="\t";
+ }
+ print "\n";
+ }
+ print "\n" if ($found);
+ $sth->finish;
+ return 0;
+}
diff --git a/tests/grant.res b/tests/grant.res
new file mode 100644
index 00000000000..7cc08807fd1
--- /dev/null
+++ b/tests/grant.res
@@ -0,0 +1,436 @@
+delete from user where user='grant_user' or user='grant_user2'
+delete from db where user='grant_user'
+delete from tables_priv
+delete from columns_priv
+lock tables mysql.user write
+flush privileges
+unlock tables
+drop database grant_test
+Error in execute: Can't drop database 'grant_test'. Database doesn't exist
+create database grant_test
+Connecting grant_user
+Access denied for user: '@localhost' to database 'grant_test'
+grant select on *.* to grant_user@localhost
+set password FOR grant_user2@localhost = password('test')
+Error in execute: Can't find any matching row in the user table
+set password FOR grant_user=password('test')
+Connecting grant_user
+Access denied for user: 'grant_user@localhost' (Using password: NO)
+set password FOR grant_user=''
+Connecting grant_user
+select * from mysql.user where user = 'grant_user'
+localhost grant_user Y N N N N N N N N N N N N N
+
+select * from mysql.db where user = 'grant_user'
+grant select on *.* to grant_user@localhost,grant_user@localhost
+insert into mysql.user (host,user) values ('error','grant_user')
+Error in execute: Access denied for user: 'grant_user@localhost' to database 'mysql'
+update mysql.user set host='error' WHERE user='grant_user'
+Error in execute: Access denied for user: 'grant_user@localhost' to database 'mysql'
+create table grant_test.test (a int,b int)
+Error in execute: Access denied for user: 'grant_user@localhost' to database 'grant_test'
+grant select on *.* to grant_user2@localhost
+Error in execute: Access denied for user: 'grant_user@localhost' (Using password: NO)
+revoke select on grant_test.test from grant_user@opt_host
+Error in execute: There is no such grant defined for user 'grant_user' on host 'opt_host'
+revoke select on grant_test.* from grant_user@opt_host
+Error in execute: There is no such grant defined for user 'grant_user' on host 'opt_host'
+revoke select on *.* from grant_user
+Error in execute: There is no such grant defined for user 'grant_user' on host '%'
+grant select on grant_test.not_exists to grant_user
+Error in execute: Table 'grant_test.not_exists' doesn't exist
+grant FILE on grant_test.test to grant_user
+Error in execute: Illegal GRANT/REVOKE command. Please consult the manual which privileges can be used.
+grant select on *.* to wrong___________user_name
+Error in execute: The host or user argument to GRANT is too long
+grant select on grant_test.* to wrong___________user_name
+Error in execute: The host or user argument to GRANT is too long
+grant select on grant_test.test to grant_user with grant option
+Error in execute: grant command denied to user: 'grant_user@localhost' for table 'test'
+set password FOR ''@''=''
+Error in execute: You are using MySQL as an anonymous users and anonymous users are not allowed to change passwords
+set password FOR root@localhost = password('test')
+Error in execute: Access denied for user: 'grant_user@localhost' to database 'mysql'
+revoke select on *.* from grant_user@localhost
+grant create on *.* to grant_user@localhost
+Connecting grant_user
+create table grant_test.test (a int,b int)
+grant select(c) on grant_test.test to grant_user@localhost
+Error in execute: Unknown column 'c' in 'test'
+revoke select(c) on grant_test.test from grant_user@localhost
+Error in execute: There is no such grant defined for user 'grant_user' on host 'localhost' on table 'test'
+grant select on grant_test.test to wrong___________user_name
+Error in execute: The host or user argument to GRANT is too long
+INSERT INTO grant_test.test values (2,0)
+Error in execute: insert command denied to user: 'grant_user@localhost' for table 'test'
+grant ALL PRIVILEGES on *.* to grant_user@localhost
+REVOKE INSERT on *.* from grant_user@localhost
+Connecting grant_user
+INSERT INTO grant_test.test values (1,0)
+Error in execute: insert command denied to user: 'grant_user@localhost' for table 'test'
+grant INSERT on *.* to grant_user@localhost
+Connecting grant_user
+INSERT INTO grant_test.test values (2,0)
+select count(*) from grant_test.test
+1
+
+revoke SELECT on *.* from grant_user@localhost
+Connecting grant_user
+select count(*) from grant_test.test
+Error in execute: select command denied to user: 'grant_user@localhost' for table 'test'
+INSERT INTO grant_test.test values (3,0)
+grant SELECT on *.* to grant_user@localhost
+Connecting grant_user
+select count(*) from grant_test.test
+2
+
+revoke ALL PRIVILEGES on *.* from grant_user@localhost
+Connecting grant_user
+Access denied for user: 'grant_user@localhost' to database 'grant_test'
+delete from user where user='grant_user'
+flush privileges
+delete from user where user='grant_user'
+flush privileges
+grant select on grant_test.* to grant_user@localhost
+select * from mysql.user where user = 'grant_user'
+localhost grant_user N N N N N N N N N N N N N N
+
+select * from mysql.db where user = 'grant_user'
+localhost grant_test grant_user Y N N N N N N N N N
+
+Connecting grant_user
+select count(*) from grant_test.test
+2
+
+select * from mysql.user where user = 'grant_user'
+Error in execute: Access denied for user: 'grant_user@localhost' to database 'mysql'
+insert into grant_test.test values (4,0)
+Error in execute: Access denied for user: 'grant_user@localhost' to database 'grant_test'
+update grant_test.test set a=1
+Error in execute: Access denied for user: 'grant_user@localhost' to database 'grant_test'
+delete from grant_test.test
+Error in execute: Access denied for user: 'grant_user@localhost' to database 'grant_test'
+create table grant_test.test2 (a int)
+Error in execute: Access denied for user: 'grant_user@localhost' to database 'grant_test'
+ALTER TABLE grant_test.test add c int
+Error in execute: Access denied for user: 'grant_user@localhost' to database 'grant_test'
+CREATE INDEX dummy ON grant_test.test (a)
+Error in execute: Access denied for user: 'grant_user@localhost' to database 'grant_test'
+drop table grant_test.test
+Error in execute: Access denied for user: 'grant_user@localhost' to database 'grant_test'
+grant ALL PRIVILEGES on grant_test.* to grant_user2@localhost
+Error in execute: Access denied for user: 'grant_user@localhost' (Using password: NO)
+grant ALL PRIVILEGES on grant_test.* to grant_user@localhost WITH GRANT OPTION
+Connecting grant_user
+insert into grant_test.test values (5,0)
+REVOKE ALL PRIVILEGES on * from grant_user@localhost
+Error in execute: There is no such grant defined for user 'grant_user' on host 'localhost'
+REVOKE ALL PRIVILEGES on *.* from grant_user@localhost
+REVOKE ALL PRIVILEGES on grant_test.* from grant_user@localhost
+REVOKE ALL PRIVILEGES on grant_test.* from grant_user@localhost
+Connecting grant_user
+insert into grant_test.test values (6,0)
+Error in execute: Access denied for user: 'grant_user@localhost' to database 'grant_test'
+REVOKE GRANT OPTION on grant_test.* from grant_user@localhost
+Connecting grant_user
+Access denied for user: 'grant_user@localhost' to database 'grant_test'
+grant ALL PRIVILEGES on grant_test.* to grant_user@localhost
+Connecting grant_user
+select * from mysql.user where user = 'grant_user'
+Error in execute: Access denied for user: 'grant_user@localhost' to database 'mysql'
+insert into grant_test.test values (7,0)
+update grant_test.test set a=3 where a=2
+delete from grant_test.test where a=3
+create table grant_test.test2 (a int not null)
+alter table grant_test.test2 add b int
+create index dummy on grant_test.test2 (a)
+drop table grant_test.test2
+show tables
+insert into mysql.user (host,user) values ('error','grant_user',0)
+Error in execute: Access denied for user: 'grant_user@localhost' to database 'mysql'
+revoke ALL PRIVILEGES on grant_test.* from grant_user@localhost
+select * from mysql.user where user = 'grant_user'
+localhost grant_user N N N N N N N N N N N N N N
+
+select * from mysql.db where user = 'grant_user'
+Connecting grant_user
+Access denied for user: 'grant_user@localhost' to database 'grant_test'
+grant create on grant_test.test2 to grant_user@localhost
+Connecting grant_user
+create table grant_test.test2 (a int not null)
+show tables
+test2
+
+show columns from test
+Error in execute: select command denied to user: 'grant_user@localhost' for table 'test'
+show keys from test
+Error in execute: select command denied to user: 'grant_user@localhost' for table 'test'
+show columns from test2
+a int(11) 0
+
+show keys from test2
+select * from test
+Error in execute: select command denied to user: 'grant_user@localhost' for table 'test'
+grant insert on grant_test.test to grant_user@localhost
+show tables
+test
+test2
+
+insert into grant_test.test values (8,0)
+update grant_test.test set b=1
+Error in execute: update command denied to user: 'grant_user@localhost' for table 'test'
+grant update on grant_test.test to grant_user@localhost
+update grant_test.test set b=2
+delete from grant_test.test
+Error in execute: delete command denied to user: 'grant_user@localhost' for table 'test'
+grant delete on grant_test.test to grant_user@localhost
+delete from grant_test.test where a=1
+Error in execute: select command denied to user: 'grant_user@localhost' for column 'a' in table 'test'
+update grant_test.test set b=3 where b=1
+Error in execute: select command denied to user: 'grant_user@localhost' for column 'b' in table 'test'
+update grant_test.test set b=b+1
+Error in execute: select command denied to user: 'grant_user@localhost' for column 'b' in table 'test'
+select * from test
+Error in execute: select command denied to user: 'grant_user@localhost' for table 'test'
+grant select on grant_test.test to grant_user@localhost
+delete from grant_test.test where a=1
+update grant_test.test set b=2 where b=1
+update grant_test.test set b=b+1
+select count(*) from test
+3
+
+create table grant_test.test3 (a int)
+Error in execute: create command denied to user: 'grant_user@localhost' for table 'test3'
+alter table grant_test.test2 add c int
+Error in execute: alter command denied to user: 'grant_user@localhost' for table 'test2'
+grant alter on grant_test.test2 to grant_user@localhost
+alter table grant_test.test2 add c int
+create index dummy ON grant_test.test (a)
+Error in execute: index command denied to user: 'grant_user@localhost' for table 'test'
+grant index on grant_test.test2 to grant_user@localhost
+create index dummy ON grant_test.test2 (a)
+insert into test2 SELECT a,a from test
+Error in execute: insert command denied to user: 'grant_user@localhost' for table 'test2'
+grant insert on test2 to grant_user@localhost
+Error in execute: Table 'mysql.test2' doesn't exist
+grant insert(a) on grant_test.test2 to grant_user@localhost
+insert into test2 SELECT a,a from test
+Error in execute: insert command denied to user: 'grant_user@localhost' for column 'c' in table 'test2'
+grant insert(c) on grant_test.test2 to grant_user@localhost
+insert into test2 SELECT a,a from test
+select count(*) from test2,test
+Error in execute: select command denied to user: 'grant_user@localhost' for table 'test2'
+select count(*) from test,test2
+Error in execute: select command denied to user: 'grant_user@localhost' for table 'test2'
+replace into test2 SELECT a from test
+Error in execute: update command denied to user: 'grant_user@localhost' for table 'test2'
+grant update on grant_test.test2 to grant_user@localhost
+replace into test2 SELECT a,a from test
+Error in execute: delete command denied to user: 'grant_user@localhost' for table 'test2'
+grant DELETE on grant_test.test2 to grant_user@localhost
+replace into test2 SELECT a,a from test
+insert into test (a) SELECT a from test2
+Error in execute: select command denied to user: 'grant_user@localhost' for table 'test2'
+drop table grant_test.test2
+Error in execute: drop command denied to user: 'grant_user@localhost' for table 'test2'
+grant select on grant_test.test2 to grant_user@localhost with grant option
+Error in execute: select command denied to user: 'grant_user@localhost' for table 'test2'
+grant drop on grant_test.test2 to grant_user@localhost with grant option
+grant drop on grant_test.test2 to grant_user@localhost with grant option
+grant select on grant_test.test2 to grant_user@localhost with grant option
+Error in execute: select command denied to user: 'grant_user@localhost' for table 'test2'
+drop table grant_test.test2
+create database grant_test
+Error in execute: Access denied for user: 'grant_user@localhost' to database 'grant_test'
+drop database grant_test
+Error in execute: Access denied for user: 'grant_user@localhost' to database 'grant_test'
+flush tables
+Error in execute: Access denied for user: 'grant_user@localhost' (Using password: NO)
+flush privileges
+select Host, Db, User, Table_name, Grantor, Table_priv, Column_priv from mysql.tables_priv
+localhost grant_test grant_user test2 grant_user@localhost Update,Delete,Create,Drop,Grant,Index,Alter Insert
+localhost grant_test grant_user test root@localhost Select,Insert,Update,Delete
+
+revoke ALL PRIVILEGES on grant_test.test from grant_user@localhost
+revoke ALL PRIVILEGES on grant_test.test2 from grant_user@localhost
+revoke GRANT OPTION on grant_test.test2 from grant_user@localhost
+select Host, Db, User, Table_name, Grantor, Table_priv, Column_priv from mysql.tables_priv
+localhost grant_test grant_user test2 root@localhost Grant,Index,Alter
+
+select count(a) from test
+Error in execute: select command denied to user: 'grant_user@localhost' for table 'test'
+delete from grant_test.test where a=2
+Error in execute: delete command denied to user: 'grant_user@localhost' for table 'test'
+delete from grant_test.test where A=2
+Error in execute: delete command denied to user: 'grant_user@localhost' for table 'test'
+update test set b=5 where b>0
+Error in execute: update command denied to user: 'grant_user@localhost' for table 'test'
+grant update(b),delete on grant_test.test to grant_user@localhost
+revoke update(a) on grant_test.test from grant_user@localhost
+Error in execute: There is no such grant defined for user 'grant_user' on host 'localhost' on table 'test'
+delete from grant_test.test where a=2
+Error in execute: select command denied to user: 'grant_user@localhost' for column 'a' in table 'test'
+update test set b=5 where b>0
+Error in execute: select command denied to user: 'grant_user@localhost' for column 'b' in table 'test'
+grant select(a),select(b) on grant_test.test to grant_user@localhost
+delete from grant_test.test where a=2
+delete from grant_test.test where A=2
+update test set b=5 where b>0
+update test set a=11 where b>5
+Error in execute: update command denied to user: 'grant_user@localhost' for column 'a' in table 'test'
+select a,A from test
+8 8
+5 5
+7 7
+
+select Host, Db, User, Table_name, Grantor, Table_priv, Column_priv from mysql.tables_priv
+localhost grant_test grant_user test2 root@localhost Grant,Index,Alter
+localhost grant_test grant_user test root@localhost Delete Select,Update
+
+revoke ALL PRIVILEGES on grant_test.test from grant_user@localhost
+select Host, Db, User, Table_name, Grantor, Table_priv, Column_priv from mysql.tables_priv
+localhost grant_test grant_user test2 root@localhost Grant,Index,Alter
+
+revoke GRANT OPTION on grant_test.test from grant_user@localhost
+Error in execute: There is no such grant defined for user 'grant_user' on host 'localhost' on table 'test'
+grant select(a) on grant_test.test to grant_user@localhost
+show columns from test
+a int(11) YES NULL select
+b int(11) YES NULL
+
+grant insert (b), update (b) on grant_test.test to grant_user@localhost
+select count(a) from test
+3
+
+select count(skr.a) from test as skr
+3
+
+select count(a) from test where a > 5
+2
+
+insert into test (b) values (5)
+insert into test (b) values (a)
+update test set b=3 where a > 0
+select * from test
+Error in execute: select command denied to user: 'grant_user@localhost' for column 'b' in table 'test'
+select b from test
+Error in execute: select command denied to user: 'grant_user@localhost' for column 'b' in table 'test'
+select a from test where b > 0
+Error in execute: select command denied to user: 'grant_user@localhost' for column 'b' in table 'test'
+insert into test (a) values (10)
+Error in execute: insert command denied to user: 'grant_user@localhost' for column 'a' in table 'test'
+insert into test (b) values (b)
+Error in execute: select command denied to user: 'grant_user@localhost' for column 'b' in table 'test'
+insert into test (a,b) values (1,5)
+Error in execute: insert command denied to user: 'grant_user@localhost' for column 'a' in table 'test'
+insert into test (b) values (1),(b)
+Error in execute: select command denied to user: 'grant_user@localhost' for column 'b' in table 'test'
+update test set b=3 where b > 0
+Error in execute: select command denied to user: 'grant_user@localhost' for column 'b' in table 'test'
+select Host, Db, User, Table_name, Grantor, Table_priv, Column_priv from mysql.tables_priv
+localhost grant_test grant_user test2 root@localhost Grant,Index,Alter
+localhost grant_test grant_user test root@localhost Select,Insert,Update
+
+select Host, Db, User, Table_name, Column_name, Column_priv from mysql.columns_priv
+localhost grant_test grant_user test b Insert,Update
+localhost grant_test grant_user test a Select
+
+revoke select(a), update (b) on grant_test.test from grant_user@localhost
+select Host, Db, User, Table_name, Grantor, Table_priv, Column_priv from mysql.tables_priv
+localhost grant_test grant_user test2 root@localhost Grant,Index,Alter
+localhost grant_test grant_user test root@localhost Insert
+
+select Host, Db, User, Table_name, Column_name, Column_priv from mysql.columns_priv
+localhost grant_test grant_user test b Insert
+
+select count(a) from test
+Error in execute: select command denied to user: 'grant_user@localhost' for table 'test'
+update test set b=4
+Error in execute: update command denied to user: 'grant_user@localhost' for table 'test'
+grant select(a,b), update (a,b) on grant_test.test to grant_user@localhost
+select count(a),count(b) from test where a+b > 0
+3 3
+
+insert into test (b) values (9)
+update test set b=6 where b > 0
+flush privileges
+select Host, Db, User, Table_name, Grantor, Table_priv, Column_priv from mysql.tables_priv
+localhost grant_test grant_user test2 root@localhost Grant,Index,Alter
+localhost grant_test grant_user test root@localhost Select,Insert,Update
+
+select Host, Db, User, Table_name, Column_name, Column_priv from mysql.columns_priv
+localhost grant_test grant_user test b Select,Insert,Update
+localhost grant_test grant_user test a Select,Update
+
+insert into test (a,b) values (12,12)
+Error in execute: insert command denied to user: 'grant_user@localhost' for column 'a' in table 'test'
+grant insert on grant_test.* to grant_user@localhost
+Connecting grant_user
+insert into test (a,b) values (13,13)
+revoke select(b) on grant_test.test from grant_user@localhost
+select count(a) from test where a+b > 0
+Error in execute: select command denied to user: 'grant_user@localhost' for column 'b' in table 'test'
+update test set b=5 where a=2
+grant select on grant_test.test to grant_user@localhost
+Connecting grant_user
+select count(a) from test where a+b > 0
+4
+
+revoke select(b) on grant_test.test from grant_user@localhost
+select count(a) from test where a+b > 0
+4
+
+revoke select on grant_test.test from grant_user@localhost
+Connecting grant_user
+select count(a) from test where a+b > 0
+Error in execute: select command denied to user: 'grant_user@localhost' for table 'test'
+grant select(a) on grant_test.test to grant_user@localhost
+select count(a) from test where a+b > 0
+Error in execute: select command denied to user: 'grant_user@localhost' for column 'b' in table 'test'
+grant select on *.* to grant_user@localhost
+Connecting grant_user
+select count(a) from test where a+b > 0
+4
+
+revoke select on *.* from grant_user@localhost
+grant select(b) on grant_test.test to grant_user@localhost
+Connecting grant_user
+select count(a) from test where a+b > 0
+4
+
+select * from mysql.db where user = 'grant_user'
+localhost grant_test grant_user N Y N N N N N N N N
+
+select Host, Db, User, Table_name, Grantor, Table_priv, Column_priv from mysql.tables_priv where user = 'grant_user'
+localhost grant_test grant_user test2 root@localhost Grant,Index,Alter
+localhost grant_test grant_user test root@localhost Select,Insert,Update
+
+select Host, Db, User, Table_name, Column_name, Column_priv from mysql.columns_priv where user = 'grant_user'
+localhost grant_test grant_user test b Select,Insert,Update
+localhost grant_test grant_user test a Select,Update
+
+revoke ALL PRIVILEGES on grant_test.test from grant_user@localhost
+select count(a) from test
+Error in execute: select command denied to user: 'grant_user@localhost' for table 'test'
+select * from mysql.user
+Error in execute: select command denied to user: 'grant_user@localhost' for table 'user'
+select * from mysql.db where user = 'grant_user'
+localhost grant_test grant_user N Y N N N N N N N N
+
+select Host, Db, User, Table_name, Grantor, Table_priv, Column_priv from mysql.tables_priv where user = 'grant_user'
+localhost grant_test grant_user test2 root@localhost Grant,Index,Alter
+
+select Host, Db, User, Table_name, Column_name, Column_priv from mysql.columns_priv where user = 'grant_user'
+delete from user where user='grant_user'
+flush privileges
+grant ALL PRIVILEGES on grant_test.test to grant_user@localhost identified by 'dummy', grant_user@127.0.0.1 identified by 'dummy2'
+Connecting grant_user
+grant SELECT on grant_test.* to grant_user@localhost identified by ''
+Connecting grant_user
+drop database grant_test
+delete from user where user='grant_user'
+delete from db where user='grant_user'
+delete from tables_priv
+delete from columns_priv
+flush privileges
+end of test
diff --git a/tests/insert_and_repair.pl b/tests/insert_and_repair.pl
new file mode 100755
index 00000000000..4d68c2ab9a0
--- /dev/null
+++ b/tests/insert_and_repair.pl
@@ -0,0 +1,180 @@
+#!/usr/bin/perl -w
+#
+# This is a test of insert and repair/check.
+#
+
+$opt_loop_count=100000; # Change this to make test harder/easier
+
+##################### Standard benchmark inits ##############################
+
+use DBI;
+use Getopt::Long;
+use Benchmark;
+
+package main;
+
+$opt_skip_create=$opt_skip_in=$opt_verbose=$opt_fast_insert=
+ $opt_lock_tables=$opt_debug=$opt_skip_delete=$opt_fast=$opt_force=0;
+$opt_host=$opt_user=$opt_password=""; $opt_db="test";
+
+GetOptions("host=s","db=s","loop-count=i","skip-create","skip-in",
+ "skip-delete","verbose","fast-insert","lock-tables","debug","fast",
+ "force","user=s","password=s") || die "Aborted";
+$opt_verbose=$opt_debug=$opt_lock_tables=$opt_fast_insert=$opt_fast=$opt_skip_in=$opt_force=undef; # Ignore warnings from these
+
+$firsttable = "bench_f1";
+$secondtable = "bench_f2";
+
+####
+#### Start timeing and start test
+####
+
+$start_time=new Benchmark;
+if (!$opt_skip_create)
+{
+ $dbh = DBI->connect("DBI:mysql:$opt_db:$opt_host",
+ $opt_user, $opt_password,
+ { PrintError => 0}) || die $DBI::errstr;
+ $dbh->do("drop table if exists $firsttable, $secondtable");
+
+ print "Creating tables $firsttable and $secondtable in database $opt_db\n";
+ $dbh->do("create table $firsttable (id int(7) not null, thread tinyint not null, info varchar(32), marker char(1), primary key(id,thread))") or die $DBI::errstr;
+ $dbh->do("create table $secondtable (id int(7) not null, thread tinyint not null, row int(3) not null,value double, primary key(id,thread,row)) delay_key_write=1") or die $DBI::errstr;
+ $dbh->disconnect; $dbh=0; # Close handler
+}
+$|= 1; # Autoflush
+
+####
+#### Start the tests
+####
+
+insert_in_bench1() if (($pid=fork()) == 0); $work{$pid}="insert in bench1";
+insert_in_bench2() if (($pid=fork()) == 0); $work{$pid}="insert in bench2";
+repair_and_check() if (($pid=fork()) == 0); $work{$pid}="repair/check";
+
+$errors=0;
+while (($pid=wait()) != -1)
+{
+ $ret=$?/256;
+ print "thread '" . $work{$pid} . "' finnished with exit code $ret\n";
+ $errors++ if ($ret != 0);
+}
+
+if (!$opt_skip_delete && !$errors)
+{
+ $dbh = DBI->connect("DBI:mysql:$opt_db:$opt_host",
+ $opt_user, $opt_password,
+ { PrintError => 0}) || die $DBI::errstr;
+ $dbh->do("drop table $firsttable,$secondtable");
+}
+print ($errors ? "Test failed\n" :"Test ok\n");
+
+$end_time=new Benchmark;
+print "Total time: " .
+ timestr(timediff($end_time, $start_time),"noc") . "\n";
+
+exit(0);
+
+#
+# Insert records in the two tables
+#
+
+sub insert_in_bench1
+{
+ my ($dbh,$rows,$found,$i);
+
+ $dbh = DBI->connect("DBI:mysql:$opt_db:$opt_host",
+ $opt_user, $opt_password,
+ { PrintError => 0}) || die $DBI::errstr;
+ $rows=$found=0;
+ for ($i=0 ; $i < $opt_loop_count; $i++)
+ {
+ $sth=$dbh->do("insert into $firsttable values ($i,0,'This is entry $i','')") || die "Got error on insert: $DBI::errstr\n";
+ $row_count=($i % 7)+1;
+ $rows+=1+$row_count;
+ for ($j=0 ; $j < $row_count; $j++)
+ {
+ $sth=$dbh->do("insert into $secondtable values ($i,0,$j,0)") || die "Got error on insert: $DBI::errstr\n";
+ }
+ }
+ $dbh->disconnect; $dbh=0;
+ print "insert_in_bench1: Inserted $rows rows\n";
+ exit(0);
+}
+
+sub insert_in_bench2
+{
+ my ($dbh,$rows,$found,$i);
+
+ $dbh = DBI->connect("DBI:mysql:$opt_db:$opt_host",
+ $opt_user, $opt_password,
+ { PrintError => 0}) || die $DBI::errstr;
+ $rows=$found=0;
+ for ($i=0 ; $i < $opt_loop_count; $i++)
+ {
+ $sth=$dbh->do("insert into $firsttable values ($i,1,'This is entry $i','')") || die "Got error on insert: $DBI::errstr\n";
+ $row_count=((7-$i) % 7)+1;
+ $rows+=1+$row_count;
+ for ($j=0 ; $j < $row_count; $j++)
+ {
+ $sth=$dbh->do("insert into $secondtable values ($i,1,$j,0)") || die "Got error on insert: $DBI::errstr\n";
+ }
+ }
+ $dbh->disconnect; $dbh=0;
+ print "insert_in_bench2: Inserted $rows rows\n";
+ exit(0);
+}
+
+
+sub repair_and_check
+{
+ my ($dbh,$row,@row,$found1,$found2,$last_found1,$last_found2,$i,$type,
+ $table);
+ $found1=$found2=0; $last_found1=$last_found2= -1;
+
+ $dbh = DBI->connect("DBI:mysql:$opt_db:$opt_host",
+ $opt_user, $opt_password,
+ { PrintError => 0}) || die $DBI::errstr;
+
+ for ($i=0; $found1 != $last_found1 && $found2 != $last_found1 ; $i++)
+ {
+ $type=($i & 2) ? "repair" : "check";
+ if ($i & 1)
+ {
+ $table=$firsttable;
+ $last_found1=$found1;
+ }
+ else
+ {
+ $table=$secondtable;
+ $last_found2=$found2;
+ }
+ $sth=$dbh->prepare("$type table $table") || die "Got error on prepare: $dbh->errstr\n";
+ $sth->execute || die $dbh->errstr;
+
+ while (($row=$sth->fetchrow_arrayref))
+ {
+ if ($row->[3] ne "OK")
+ {
+ print "Got error " . $row->[3] . " when doing $type on $table\n";
+ exit(1);
+ }
+ }
+ $sth=$dbh->prepare("select count(*) from $table") || die "Got error on prepare: $dbh->errstr\n";
+ $sth->execute || die $dbh->errstr;
+ @row = $sth->fetchrow_array();
+ if ($i & 1)
+ {
+ $found1= $row[0];
+ }
+ else
+ {
+ $found2= $row[0];
+ }
+ $sth->finish;
+ sleep(2);
+ }
+ $dbh->disconnect; $dbh=0;
+ print "check/repair: Did $i repair/checks\n";
+ exit(0);
+}
diff --git a/tests/lock_test.pl b/tests/lock_test.pl
new file mode 100755
index 00000000000..5daeeddad8e
--- /dev/null
+++ b/tests/lock_test.pl
@@ -0,0 +1,94 @@
+#!/usr/bin/perl
+
+# This is a test with uses two processes to a database.
+# The other inserts records in two tables, the other does a lot of joins
+# on these.
+# Every time the read thread outputs info, it does a ALTER TABLE command
+# which should stop the insert thread until the ALTER TABLE command is ready.
+#
+# Warning, the output from this test will differ in 'found' from time to time,
+# but there should never be any errors
+#
+
+$host = shift || "";
+$test_db="test";
+$test_count=10000;
+srand 0; # Repeatable test
+
+use Mysql;
+$|= 1; # Autoflush
+
+$dbh = Mysql->Connect($host) || die "Can't connect: $Mysql::db_errstr\n";
+$dbh->SelectDB($test_db) || die "Can't use database $test_db: $Mysql::db_errstr\n";
+
+$firsttable = "test_lock_1";
+$secondtable = "test_lock_2";
+$dbh->Query("drop table $firsttable");
+$dbh->Query("drop table $secondtable");
+
+print "Creating tables $firsttable and $secondtable in database $test_db\n";
+$dbh->Query("create table $firsttable (id int(6) not null, info char(32), auto int(11) not null auto_increment, primary key(id),key(auto))") or die $Mysql::db_errstr;
+
+$dbh->Query("create table $secondtable (id int(6) not null, info varchar(32), key(id))") or die $Mysql::db_errstr;
+
+$dbh=0; # Close handler
+
+if (fork() == 0)
+{ # Insert process
+ $dbh = Mysql->Connect($host) || die "Can't connect: $Mysql::db_errstr\n";
+ $dbh->SelectDB($test_db) || die "Can't use database $test_db: $Mysql::db_errstr\n";
+ $first_id=1; $second_id=1;
+ $first_count=$second_count=0;
+ print "Writing started\n";
+ for ($i=1 ; $i <= $test_count ; $i++)
+ {
+ if (rand(3) <= 1)
+ {
+ $sth=$dbh->Query("insert into $firsttable values ($first_id,'This is entry $i',NULL)") || die "Got error on insert: $Mysql::db_errstr\n";
+ die "Row not inserted, aborting\n" if ($sth->affected_rows != 1);
+ $first_id++;
+ $first_count++;
+ }
+ else
+ {
+ $sth=$dbh->Query("insert into $secondtable values ($second_id,'This is entry $i')") || die "Got error on insert: $Mysql::db_errstr\n";
+ die "Row not inserted, aborting\n" if ($sth->affected_rows != 1);
+ $second_id++ if (rand(10) <= 1); # Don't always count it up
+ $second_count++;
+ }
+ print "Write: $i\n" if ($i % 1000 == 0);
+ }
+ print "Writing done ($first_count $second_count)\n";
+}
+else
+{
+ $dbh = Mysql->Connect($host) || die "Can't connect: $Mysql::db_errstr\n";
+ $dbh->SelectDB($test_db) || die "Can't use database $test_db: $Mysql::db_errstr\n";
+ $locked=$found=0;
+ print "Reading started\n";
+ for ($i=1 ; $i <= $test_count ; $i++)
+ {
+ $id=int(rand($test_count)/3)+1;
+ $sth=$dbh->Query("select count(*) from $firsttable,$secondtable where $firsttable.id = $secondtable.id and $firsttable.id=$id") || die "Got error on select: $Mysql::db_errstr\n";
+ $found++ if ($sth->numrows);
+ if ($i % 1000 == 0)
+ {
+ print "Read: $i Found: $found\n";
+ if ($found)
+ {
+ $locked=1-$locked;
+ if ($locked)
+ {
+ $sth=$dbh->Query("lock tables $firsttable write,$secondtable write");
+ }
+ $sth=$dbh->Query("alter table $firsttable CHANGE id id int(6) not null") || die "Got error on ALTER TABLE: $Mysql::db_errstr\n";
+ $sth=$dbh->Query("alter table $secondtable CHANGE info info char(32) not null") || die "Got error on ALTER TABLE: $Mysql::db_errstr\n";
+ if ($locked)
+ {
+ $sth=$dbh->Query("unlock tables");
+ }
+ }
+ }
+ }
+ print "Reading done Found: $found\n";
+}
diff --git a/tests/lock_test.res b/tests/lock_test.res
new file mode 100644
index 00000000000..5a9464d59ec
--- /dev/null
+++ b/tests/lock_test.res
@@ -0,0 +1,25 @@
+Creating tables test_lock_1 and test_lock_2 in database test
+Reading started
+Writing started
+Write: 1000
+Read: 1000 Found: 28
+Write: 2000
+Write: 3000
+Read: 2000 Found: 79
+Write: 4000
+Write: 5000
+Read: 3000 Found: 165
+Write: 6000
+Write: 7000
+Read: 4000 Found: 291
+Write: 8000
+Write: 9000
+Write: 10000
+Writing done
+Read: 5000 Found: 482
+Read: 6000 Found: 680
+Read: 7000 Found: 862
+Read: 8000 Found: 1076
+Read: 9000 Found: 1275
+Read: 10000 Found: 1507
+Reading done Found: 1507
diff --git a/tests/mail_to_db.pl b/tests/mail_to_db.pl
new file mode 100755
index 00000000000..7886ffb7e0f
--- /dev/null
+++ b/tests/mail_to_db.pl
@@ -0,0 +1,310 @@
+#!/usr/bin/perl
+# Copyright Abandoned 1998 TCX DataKonsult AB & Monty Program KB & Detron HB
+# This file is public domain and comes with NO WARRANTY of any kind
+#
+# This program is brought to you by Janne-Petteri Koilo with the
+# administration of Michael Widenius.
+
+# This program takes your mails and puts them into your database. It ignores
+# messages with the same from, date and message text.
+# You can use mail-files that are compressed or gzipped and ends with
+# -.gz or -.Z.
+
+use DBI;
+use Getopt::Long;
+
+$VER = "1.6";
+
+$opt_db = "mail";
+$opt_table = "mails";
+$opt_max_mail_size = 65536;
+$opt_db_engine = "mysql";
+$opt_host = "localhost";
+$opt_user = $opt_password = "";
+$opt_help = $opt_version = $opt_test=0;
+
+GetOptions("help","version","user=s","password=s",
+ "db_engine=s","db=s","host=s","max_mail_size=s","test") || usage();
+
+usage($VER) if ($opt_help || $opt_version || !$ARGV[0]);
+
+%months= ('Jan' => 1, 'Feb' => 2, 'Mar' => 3, 'Apr' => 4, 'May' => 5,
+ 'Jun' => 6, 'Jul' => 7, 'Aug' => 8, 'Sep' => 9, 'Oct' => 10,
+ 'Nov' => 11, 'Des' => 12);
+
+$count_no_from = $count_no_txt = $count_too_big = 0;
+$count_forwarded_msgs = $count_duplicates = $no_subject = 0;
+$inserted_mails = 0;
+$dbh=0;
+
+$dbh = DBI->connect("DBI:$opt_db_engine:$opt_db:$opt_host",$opt_user,
+ $opt_password,{ PrintError => 0}) || die $DBI::errstr;
+if (!$opt_test)
+{
+ create_table_if_needed($dbh);
+}
+
+foreach (@ARGV)
+{
+ if (/^(.*)\.(gz|Z)$/) #checks if the file is compressed or gzipped
+ {
+ open(FILE, "zcat $_ |");
+ process_mail_file($dbh,$1);
+ }
+ else
+ {
+ open(FILE,$_);
+ process_mail_file($dbh,$_);
+ }
+}
+$dbh->disconnect if (!$opt_test);
+
+$ignored = $count_no_from + $count_no_txt + $count_too_big + $count_duplicates + $no_subject;
+print "Mails inserted:\t\t\t$inserted_mails\n";
+print "Mails ignored:\t\t\t$ignored\n";
+print "Mails without \"From:\" -field:\t$count_no_from\n";
+print "Mails without message:\t\t$count_no_txt\n";
+print "Too big mails (> $opt_max_mail_size):\t$count_too_big\n";
+print "Duplicate mails:\t\t$count_duplicates\n";
+print "Forwarded mails:\t\t$count_forwarded_msgs\n";
+print "No subject:\t\t\t$no_subject\n";
+print "Mails altogether:\t\t";
+print $inserted_mails+$ignored;
+print "\n";
+exit(0);
+
+sub usage
+{
+ my($VER)=@_;
+
+ $0 =~ s/.\/(.+)/$1/;
+ if ($opt_version)
+ {
+ print "$0 version $VER\n";
+ }
+ else
+ {
+ print <<EOF;
+$0 version $VER
+
+Usage: $0 [options] file1 [file2 file3 ...]
+
+Description: Inserts mails from file(s) into a database
+
+Options:
+--help show this help and exit
+--version shows the version of the program
+--db_engine=... database server (default: $opt_db_engine)
+--db=... database to be used (default: $opt_db)
+--host=... hostname to be used (default: $opt_host)
+--password=... user password for the db server
+--user=... username for the db server
+--max_mail_size=# max size of a mail to be inserted into the db.
+ mail will be ignored if it exceeds this size
+ (default $opt_max_mail_size)
+--test Don\'t connect to the database, just write the
+ queries to stdout
+EOF
+ }
+ exit(0);
+}
+
+sub create_table_if_needed
+{
+ my ($dbh)=@_;
+ my ($sth,$create);
+
+ $sth = $dbh->prepare("select count(*) from $opt_table") or die $dbh->errstr;
+ if (!$sth->execute)
+ {
+ $create = "CREATE TABLE $opt_table (msg_nro mediumint unsigned not null ";
+ $create .= "auto_increment, date DATETIME NOT NULL, time_zone CHAR(6) ";
+ $create .= "NOT NULL, mail_from char(120) not null, reply char(120), ";
+ $create .= "mail_to TEXT, cc TEXT, sbj char(200), txt MEDIUMTEXT NOT ";
+ $create .= "NULL, file char(32) noT NULL, hash INT NOT NULL, key ";
+ $create .= "(msg_nro), primary key (mail_from, date, time_zone, hash))";
+ $sth = $dbh->prepare($create) or die $dbh->errstr;
+ $sth->execute() or die $dbh->errstr;
+ }
+}
+
+sub process_mail_file
+{
+ my ($dbh,$file_name)= @_;
+ my (%values,$type,$check);
+
+ %values=(); $type="";
+ $check=0;
+
+ while (<FILE>)
+ {
+ chop;
+ if ($type ne "message")
+ {
+ if (/^Reply-To: (.*)/i) # finding different fields from file
+ {
+ $type="reply";
+ $values{$type}= $1;
+ }
+ elsif (/^From: (.*)/i)
+ {
+ $type="from";
+ $values{$type}= $1;
+ }
+ elsif (/^To: (.*)/i)
+ {
+ $type="to";
+ $values{$type}= $1;
+ }
+ elsif (/^Cc: (.*)/i)
+ {
+ $type="cc";
+ $values{$type}= $1;
+ }
+ elsif (/^Subject: (.*)/i)
+ {
+ $type="subject";
+ $values{$type}= $1;
+ }
+ elsif (/^Date: (.*)/i)
+ {
+ date_parser($1,\%values);
+ $type="rubbish";
+ }
+ elsif (/^[\w\W-]+:\s/)
+ {
+ $type="rubbish";
+ }
+ elsif ($_ eq "")
+ {
+ $type="message";
+ $values{$type}="";
+ }
+ else
+ {
+ s/^\s*/ /;
+ $values{$type}.= $_;
+ }
+ }
+ elsif ($check!=0 && $_ ne "") # in case of forwarded messages
+ {
+ $values{$type}.= "\n" . $_;
+ $check--;
+ }
+ elsif (/^From .* \d\d:\d\d:\d\d\s\d\d\d\d$/)
+ {
+ $values{'hash'}= checksum("$values{'message'}");
+ update_table($dbh,$file_name,\%values);
+ %values=(); $type="";
+ $check=0;
+ }
+ elsif (/-* forwarded message .*-*/i) # in case of forwarded messages
+ {
+ $values{$type}.= "\n" . $_;
+ $check++;
+ $count_forwarded_msgs++;
+ }
+ else
+ {
+ $values{$type}.= "\n" . $_;
+ }
+ }
+ $values{'hash'}= checksum("$values{'message'}");
+ update_table($dbh,$file_name,\%values);
+}
+
+########
+
+# converts date to the right form
+
+sub date_parser
+{
+ my ($date_raw,$values)=@_;
+
+ $date_raw =~ /\s*(\d{1,2}) (\w+) (\d{2,4}) (\d+:\d+:\d+)\s*([\w-+]{3-5})?/;
+
+ $values->{'date'}=$3 . "-" . $months{$2} . "-" . "$1 $4";
+ $values->{'time_zone'}=$5;
+}
+
+#########
+
+# this is runned when the whole mail is gathered.
+# this actually puts the mail to the database.
+
+sub update_table
+{
+ my($dbh,$file_name,$values)=@_;
+ my($query);
+
+ if (! defined($values->{'subject'}) || !defined($values->{'to'}))
+ {
+ $no_subject++;
+ return; # Ignore these
+ }
+ $values->{'message'} =~ s/^\s*//; #removes whitespaces from the beginning
+ $values->{'message'} =~ s/\s*$//; #removes whitespaces from the end
+ $query = "insert into $opt_table values (NULL,'" . $values->{'date'};
+ $query .= "','" . $values->{'time_zone'} . "',";
+ $query .= (defined($values->{'from'}) ? $dbh->quote($values->{'from'}) : "NULL") . ",";
+ $query .= (defined($values->{'reply'}) ? $dbh->quote($values->{'reply'}) : "NULL") . ",";
+
+ $query .= (defined($values->{'to'}) ? $dbh->quote($values->{'to'}) : "NULL") . ",";
+ $query .= (defined($values->{'cc'}) ? $dbh->quote($values->{'cc'}) : "NULL") . ",";
+ $query .= $dbh->quote($values->{'subject'}) . ",";
+ $query .= $dbh->quote($values->{'message'}) . "," . $dbh->quote($file_name);
+ $query .= ",'" . $values->{'hash'} . "')";
+
+ if (length($values->{'message'}) > $opt_max_mail_size) #disables big message
+ {
+ $count_too_big++;
+ }
+ elsif ($values->{'from'} eq "") #disables mails with no from field
+ {
+ $count_no_from++;
+ }
+ elsif ($opt_test)
+ {
+ print "$query\n";
+ $inserted_mails++;
+ }
+ elsif ($values->{'message'} eq "") #disables mails with no message text
+ {
+ $count_no_msg_text++;
+ }
+ elsif ($dbh->do($query))
+ {
+ $inserted_mails++;
+ }
+ elsif (!($dbh->errstr =~ /Duplicate entry /)) #disables duplicates
+ {
+ die "Aborting: Got error '" . $dbh->errstr ."' for query: '$query'\n";
+ }
+ else
+ {
+ $count_duplicates++;
+ }
+ $query="";
+}
+
+
+##########
+
+# In case you have two identical messages we wanted to identify them
+# and remove additionals; We do this by calculating a hash number of the
+# message and ignoring messages with the same from, date and hash.
+# This function calculates a simple 32 bit hash value for the message.
+
+sub checksum
+{
+ my ($txt)= @_;
+ my ($crc,$i,$count);
+ $count = length($txt);
+ for ($crc = $i = 0; $i < $count ; $i++)
+ {
+ $crc = (($crc << 1) + (ord (substr ($txt, $i, 1)))) +
+ (($crc & (1 << 30)) ? 1 : 0);
+ $crc &= ((1 << 31) -1);
+ }
+ return $crc;
+}
diff --git a/tests/pmail.pl b/tests/pmail.pl
new file mode 100755
index 00000000000..4ca2033b4d1
--- /dev/null
+++ b/tests/pmail.pl
@@ -0,0 +1,195 @@
+#!/usr/bin/perl
+#
+# Prints mails to standard output
+#
+####
+#### Standard inits and get options
+####
+
+use DBI;
+use Getopt::Long;
+
+$VER="1.4a";
+
+@fldnms= ("mail_from","mail_to","cc","date","time_zone","file","sbj","txt");
+$fields=8;
+@mail= (@from,@to,@cc,@date,@time_zone,@file,@sbj,@txt);
+
+$opt_user= $opt_password= "";
+$opt_socket= "/tmp/mysql.sock";
+$opt_port= 3306;
+$opt_db="test";
+$opt_table="mails";
+$opt_help=$opt_count=0;
+
+GetOptions("help","count","port=i","db=s","table=s","host=s","password=s",
+ "user=s","socket=s") || usage();
+
+if ($opt_host eq '')
+{
+ $opt_host = "localhost";
+}
+
+if ($opt_help || !$ARGV[0])
+{
+ usage();
+}
+
+####
+#### Connect and parsing the query to MySQL
+####
+
+$dbh= DBI->connect("DBI:mysql:$opt_db:$opt_host:port=$opt_port:mysql_socket=$opt_mysql_socket", $opt_user,$opt_password, { PrintError => 0})
+|| die $DBI::errstr;
+
+if ($opt_count)
+{
+ count_mails();
+}
+
+$fields=0;
+$query = "select ";
+foreach $val (@fldnms)
+{
+ if (!$fields)
+ {
+ $query.= "$val";
+ }
+ else
+ {
+ $query.= ",$val";
+ }
+ $fields++;
+}
+$query.= " from $opt_table where $ARGV[0]";
+
+####
+#### Send query and save result
+####
+
+$sth= $dbh->prepare($query);
+if (!$sth->execute)
+{
+ print "$DBI::errstr\n";
+ $sth->finish;
+ die;
+}
+for ($i=0; ($row= $sth->fetchrow_arrayref); $i++)
+{
+ for ($j=0; $j < $fields; $j++)
+ {
+ $mail[$j][$i]= $row->[$j];
+ }
+}
+
+####
+#### Print to stderr
+####
+
+for ($i=0; $mail[0][$i]; $i++)
+{
+ print "#" x 33;
+ print " " . ($i+1) . ". Mail ";
+ print "#" x 33;
+ print "\nFrom: $mail[0][$i]\n";
+ print "To: $mail[1][$i]\n";
+ print "Cc: $mail[2][$i]\n";
+ print "Date: $mail[3][$i]\n";
+ print "Timezone: $mail[4][$i]\n";
+ print "File: $mail[5][$i]\n";
+ print "Subject: $mail[6][$i]\n";
+ print "Message:\n$mail[7][$i]\n";
+}
+print "#" x 20;
+print " Summary: ";
+if ($i == 1)
+{
+ print "$i Mail ";
+ print "matches the query ";
+}
+else
+{
+ print "$i Mails ";
+ print "match the query ";
+}
+print "#" x 20;
+print "\n";
+
+####
+#### Count mails that matches the query, but don't show them
+####
+
+sub count_mails
+{
+ $sth= $dbh->prepare("select count(*) from $opt_table where $ARGV[0]");
+ if (!$sth->execute)
+ {
+ print "$DBI::errstr\n";
+ $sth->finish;
+ die;
+ }
+ while (($row= $sth->fetchrow_arrayref))
+ {
+ $mail_count= $row->[0];
+ }
+ if ($mail_count == 1)
+ {
+ print "$mail_count Mail matches the query.\n";
+ }
+ else
+ {
+ print "$mail_count Mails match the query.\n";
+ }
+ exit;
+}
+
+####
+#### Usage
+####
+
+sub usage
+{
+ print <<EOF;
+ pmail version $VER by Jani Tolonen
+
+ Usage: pmail [options] "SQL where clause"
+ Options:
+ --help show this help
+ --count Shows how many mails matches the query, but not the mails.
+ --db= database to use (Default: $opt_db)
+ --table= table to use (Default: $opt_table)
+ --host= Hostname which to connect (Default: $opt_host)
+ --socket= Unix socket to be used for connection (Default: $opt_socket)
+ --password= Password to use for mysql
+ --user= User to be used for mysql connection, if not current user
+ --port= mysql port to be used (Default: $opt_port)
+ "SQL where clause" is the end of the select clause,
+ where the condition is expressed. The result will
+ be the mail(s) that matches the condition and
+ will be displayed with the fields:
+ - From
+ - To
+ - Cc
+ - Date
+ - Timezone
+ - File (Where from the current mail was loaded into the database)
+ - Subject
+ - Message text
+ The field names that can be used in the where clause are:
+ Field Type
+ - mail_from varchar(120)
+ - date datetime
+ - sbj varchar(200)
+ - txt mediumtext
+ - cc text
+ - mail_to text
+ - time_zone varchar(6)
+ - reply varchar(120)
+ - file varchar(32)
+ - hash int(11)
+ An example of the pmail:
+ pmail "txt like '%libmysql.dll%' and sbj like '%delphi%'"
+ NOTE: the txt field is NOT case sensitive!
+EOF
+ exit(0);
+}
diff --git a/tests/table_types.pl b/tests/table_types.pl
new file mode 100755
index 00000000000..8198cd9ba86
--- /dev/null
+++ b/tests/table_types.pl
@@ -0,0 +1,224 @@
+#!/usr/bin/perl
+#
+
+use DBI;
+use Benchmark;
+
+$opt_loop_count=100000; # number of rows/3
+$small_loop_count=10; # Loop for full table retrieval
+$range_loop_count=$small_loop_count*50;
+$many_keys_loop_count=$opt_loop_count;
+
+chomp($pwd = `pwd`); $pwd = "." if ($pwd eq '');
+require "$pwd/bench-init.pl" || die "Can't read Configuration file: $!\n";
+
+if ($opt_loop_count < 256)
+{
+ $opt_loop_count=256; # Some tests must have some data to work!
+}
+
+if ($opt_small_test)
+{
+ $opt_loop_count/=100;
+ $range_loop_count/=10;
+ $many_keys_loop_count=$opt_loop_count/10;
+}
+elsif ($opt_small_tables)
+{
+ $opt_loop_count=10000; # number of rows/3
+ $many_keys_loop_count=$opt_loop_count;
+}
+elsif ($opt_small_key_tables)
+{
+ $many_keys_loop_count/=10;
+}
+
+print "Testing the speed difference between some table types\n";
+
+####
+#### Generating random keys
+####
+
+print "Generating random keys\n";
+$random[$opt_loop_count]=0;
+for ($i=0 ; $i < $opt_loop_count ; $i++)
+{
+ $random[$i]=$i+$opt_loop_count;
+}
+
+my $tmpvar=1;
+for ($i=0 ; $i < $opt_loop_count ; $i++)
+{
+ $tmpvar^= ((($tmpvar + 63) + $i)*3 % $opt_loop_count);
+ $swap=$tmpvar % $opt_loop_count;
+ $tmp=$random[$i]; $random[$i]=$random[$swap]; $random[$swap]=$tmp;
+}
+
+$total_rows=$opt_loop_count*3;
+
+####
+#### Connect and start timeing
+####
+$start_time=new Benchmark;
+$dbh = $server->connect();
+####
+#### Create needed tables
+####
+
+$table_name="bench1";
+<<<<<<< table_types.pl
+||||||| 1.2
+test("n","type=isam","char"); test("m","type=myisam pack_keys=1","char"); exit(1);
+
+=======
+
+>>>>>>> /tmp/T4a17019
+test($table_name,"type=isam","char");
+test($table_name,"type=myisam pack_keys=0","char");
+test($table_name,"type=myisam pack_keys=0","char");
+test($table_name,"type=myisam pack_keys=0 checksum=1","char");
+test($table_name,"type=myisam pack_keys=1","char");
+
+test($table_name,"type=isam","varchar");
+test($table_name,"type=myisam pack_keys=1","varchar");
+test($table_name,"type=myisam pack_keys=0","varchar");
+test($table_name,"type=myisam pack_keys=0 checksum=1","varchar");
+
+#test("type=heap","char"); # The default table sizes is a bit big for this one
+
+$dbh->disconnect;
+exit (0);
+
+sub test {
+ my ($name,$options,$chartype)=@_;
+
+ print "\nTesting with options: '$options'\n";
+ $dbh->do("drop table $name");
+ do_many($dbh,$server->create("$name",
+ ["id int NOT NULL",
+ "id2 int NOT NULL",
+ "id3 int NOT NULL",
+ "dummy1 $chartype(30)"],
+ ["primary key (id,id2)",
+ "index index_id3 (id3)"],
+ $options));
+
+ if ($opt_lock_tables)
+ {
+ $sth = $dbh->do("LOCK TABLES $name WRITE") || die $DBI::errstr;
+ }
+
+ if ($opt_fast && defined($server->{vacuum}))
+ {
+ $server->vacuum(\$dbh,1);
+ }
+
+ ####
+ #### Insert $total_rows records in order, in reverse order and random.
+ ####
+
+ $loop_time=new Benchmark;
+
+ if ($opt_fast_insert)
+ {
+ $query="insert into $name values ";
+ }
+ else
+ {
+ $query="insert into $name (id,id2,id3,dummy1) values ";
+ }
+
+ if (($opt_fast || $opt_fast_insert) && $limits->{'multi_value_insert'})
+ {
+ $query_size=$server->{'limits'}->{'query_size'};
+
+ print "Inserting $opt_loop_count multiple-value rows in order\n";
+ $res=$query;
+ for ($i=0 ; $i < $opt_loop_count ; $i++)
+ {
+ $tmp= "($i,$i,$i,'ABCDEFGHIJ'),";
+ if (length($tmp)+length($res) < $query_size)
+ {
+ $res.= $tmp;
+ }
+ else
+ {
+ $sth = $dbh->do(substr($res,0,length($res)-1)) or die $DBI::errstr;
+ $res=$query . $tmp;
+ }
+ }
+ print "Inserting $opt_loop_count multiple-value rows in reverse order\n";
+ for ($i=0 ; $i < $opt_loop_count ; $i++)
+ {
+ $tmp= "(" . ($total_rows-1-$i) . "," .($total_rows-1-$i) .
+ "," .($total_rows-1-$i) . ",'BCDEFGHIJK'),";
+ if (length($tmp)+length($res) < $query_size)
+ {
+ $res.= $tmp;
+ }
+ else
+ {
+ $sth = $dbh->do(substr($res,0,length($res)-1)) or die $DBI::errstr;
+ $res=$query . $tmp;
+ }
+ }
+ print "Inserting $opt_loop_count multiple-value rows in random order\n";
+ for ($i=0 ; $i < $opt_loop_count ; $i++)
+ {
+ $tmp= "(" . $random[$i] . "," . $random[$i] . "," . $random[$i] .
+ ",'CDEFGHIJKL')," or die $DBI::errstr;
+ if (length($tmp)+length($res) < $query_size)
+ {
+ $res.= $tmp;
+ }
+ else
+ {
+ $sth = $dbh->do(substr($res,0,length($res)-1)) or die $DBI::errstr;
+ $res=$query . $tmp;
+ }
+ }
+ $sth = $dbh->do(substr($res,0,length($res)-1)) or die $DBI::errstr;
+ }
+ else
+ {
+ print "Inserting $opt_loop_count rows in order\n";
+ for ($i=0 ; $i < $opt_loop_count ; $i++)
+ {
+ $sth = $dbh->do($query . "($i,$i,$i,'ABCDEFGHIJ')") or die $DBI::errstr;
+ }
+
+ print "Inserting $opt_loop_count rows in reverse order\n";
+ for ($i=0 ; $i < $opt_loop_count ; $i++)
+ {
+ $sth = $dbh->do($query . "(" . ($total_rows-1-$i) . "," .
+ ($total_rows-1-$i) . "," .
+ ($total_rows-1-$i) . ",'BCDEFGHIJK')")
+ or die $DBI::errstr;
+ }
+
+ print "Inserting $opt_loop_count rows in random order\n";
+
+ for ($i=0 ; $i < $opt_loop_count ; $i++)
+ {
+ $sth = $dbh->do($query . "(". $random[$i] . "," . $random[$i] .
+ "," . $random[$i] . ",'CDEFGHIJKL')") or die $DBI::errstr;
+ }
+ }
+
+ $end_time=new Benchmark;
+ print "Time for insert (" . ($total_rows) . "): " .
+ timestr(timediff($end_time, $loop_time),"all") . "\n\n";
+
+ if ($opt_fast && defined($server->{vacuum}))
+ {
+ $server->vacuum(\$dbh,1);
+ }
+
+ $sth=$dbh->prepare("show table status like '$name'");
+ $sth->execute || die "Show table status returned error: $DBI::errstr\n";
+ while (@row = $sth->fetchrow_array)
+ {
+ print join("| ",@row) . " |\n";
+ }
+ $dbh->do("drop table $name") if (!$opt_skip_delete);
+}
diff --git a/tests/test_delayed_insert.pl b/tests/test_delayed_insert.pl
new file mode 100755
index 00000000000..e49d73a19bd
--- /dev/null
+++ b/tests/test_delayed_insert.pl
@@ -0,0 +1,365 @@
+#!/usr/bin/perl -w
+
+# This is a test for INSERT DELAYED
+#
+
+$opt_loop_count=10000; # Change this to make test harder/easier
+
+##################### Standard benchmark inits ##############################
+
+use DBI;
+use Getopt::Long;
+use Benchmark;
+
+package main;
+
+$opt_skip_create=$opt_skip_in=$opt_verbose=$opt_fast_insert=
+ $opt_lock_tables=$opt_debug=$opt_skip_delete=$opt_fast=$opt_force=0;
+$opt_host=$opt_user=$opt_password=""; $opt_db="test";
+
+GetOptions("host=s","db=s","loop-count=i","skip-create","skip-in","skip-delete",
+"verbose","fast-insert","lock-tables","debug","fast","force") || die "Aborted";
+$opt_verbose=$opt_debug=$opt_lock_tables=$opt_fast_insert=$opt_fast=$opt_skip_in=$opt_force=undef; # Ignore warnings from these
+
+print "Testing 8 multiple connections to a server with 1 insert, 2 delayed\n";
+print "insert, 1 update, 1 delete, 1 flush tables and 3 select connections.\n";
+
+$firsttable = "bench_f1";
+$secondtable = "bench_f2";
+
+####
+#### Start timeing and start test
+####
+
+$start_time=new Benchmark;
+if (!$opt_skip_create)
+{
+ $dbh = DBI->connect("DBI:mysql:$opt_db:$opt_host") || die $DBI::errstr;
+ $Mysql::QUIET = 1;
+ $dbh->do("drop table if exists $firsttable,$secondtable");
+ $Mysql::QUIET = 0;
+
+ print "Creating tables $firsttable and $secondtable in database $opt_db\n";
+ $dbh->do("create table $firsttable (id int(6) not null, info varchar(32), marker char(1), primary key(id))") or die $DBI::errstr;
+ $dbh->do("create table $secondtable (id int(6) not null, row int(3) not null,value double, primary key(id,row))") or die $DBI::errstr;
+
+ $dbh->disconnect;
+}
+$|= 1; # Autoflush
+
+####
+#### Start the tests
+####
+
+test_1() if (($pid=fork()) == 0); $work{$pid}="insert";
+test_delayed_1() if (($pid=fork()) == 0); $work{$pid}="delayed_insert1";
+test_delayed_2() if (($pid=fork()) == 0); $work{$pid}="delayed_insert2";
+test_2() if (($pid=fork()) == 0); $work{$pid}="update";
+test_3() if (($pid=fork()) == 0); $work{$pid}="select1";
+test_4() if (($pid=fork()) == 0); $work{$pid}="select2";
+test_5() if (($pid=fork()) == 0); $work{$pid}="select3";
+test_del() if (($pid=fork()) == 0); $work{$pid}="delete";
+test_flush() if (($pid=fork()) == 0); $work{$pid}="flush";
+
+$errors=0;
+while (($pid=wait()) != -1)
+{
+ $ret=$?/256;
+ print "thread '" . $work{$pid} . "' finnished with exit code $ret\n";
+ $errors++ if ($ret != 0);
+}
+
+if (!$opt_skip_delete && !$errors)
+{
+ $dbh = DBI->connect("DBI:mysql:$opt_db:$opt_host") || die $DBI::errstr;
+ $dbh->do("drop table $firsttable");
+ $dbh->do("drop table $secondtable");
+}
+print ($errors ? "Test failed\n" :"Test ok\n");
+
+$end_time=new Benchmark;
+print "Total time: " .
+ timestr(timediff($end_time, $start_time),"noc") . "\n";
+
+exit(0);
+
+#
+# Insert records in the two tables
+#
+
+sub test_1
+{
+ my ($dbh,$tmpvar,$rows,$found,$i);
+
+ $dbh = DBI->connect("DBI:mysql:$opt_db:$opt_host") || die $DBI::errstr;
+ $tmpvar=1;
+ $rows=$found=0;
+ for ($i=0 ; $i < $opt_loop_count; $i++)
+ {
+ $tmpvar^= ((($tmpvar + 63) + $i)*3 % 100000);
+ $dbh->do("insert into $firsttable values ($i,'This is entry $i','')") || die "Got error on insert: $DBI::errstr\n";
+ $row_count=($i % 7)+1;
+ $rows+=1+$row_count;
+ for ($j=0 ; $j < $row_count; $j++)
+ {
+ $dbh->do("insert into $secondtable values ($i,$j,0)") || die "Got error on insert: $DBI::errstr\n";
+ }
+ }
+ $dbh->disconnect;
+ print "Test_1: Inserted $rows rows\n";
+ exit(0);
+}
+
+
+sub test_delayed_1
+{
+ my ($dbh,$tmpvar,$rows,$found,$i,$id);
+
+ $dbh = DBI->connect("DBI:mysql:$opt_db:$opt_host") || die $DBI::errstr;
+ $tmpvar=1;
+ $rows=$found=0;
+ for ($i=0 ; $i < $opt_loop_count; $i++)
+ {
+ $tmpvar^= ((($tmpvar + 63) + $i)*3 % 100000);
+ $id=$i+$opt_loop_count;
+ $dbh->do("insert delayed into $firsttable values ($id,'This is entry $id','')") || die "Got error on insert: $DBI::errstr\n";
+ $row_count=($i % 7)+1;
+ $rows+=1+$row_count;
+ for ($j=0 ; $j < $row_count; $j++)
+ {
+ $dbh->do("insert into $secondtable values ($id,$j,0)") || die "Got error on insert: $DBI::errstr\n";
+ }
+ if (($tmpvar % 100) == 0)
+ {
+ $dbh->do("select max(info) from $firsttable") || die "Got error on select max(info): $DBI::errstr\n";
+ $dbh->do("select max(value) from $secondtable") || die "Got error on select max(info): $DBI::errstr\n";
+ $found+=2;
+ }
+ }
+ $dbh->disconnect;
+ print "Test_1: Inserted delayed $rows rows, found $found rows\n";
+ exit(0);
+}
+
+
+sub test_delayed_2
+{
+ my ($dbh,$tmpvar,$rows,$found,$i,$id);
+
+ $dbh = DBI->connect("DBI:mysql:$opt_db:$opt_host") || die $DBI::errstr;
+ $tmpvar=1;
+ $rows=$found=0;
+ for ($i=0 ; $i < $opt_loop_count; $i++)
+ {
+ $tmpvar^= ((($tmpvar + 63) + $i)*3 % 100000);
+ $id=$i+$opt_loop_count*2;
+ $dbh->do("insert delayed into $firsttable values ($id,'This is entry $id','')") || die "Got error on insert: $DBI::errstr\n";
+ $row_count=($i % 7)+1;
+ $rows+=1+$row_count;
+ for ($j=0 ; $j < $row_count; $j++)
+ {
+ $dbh->do("insert delayed into $secondtable values ($id,$j,0)") || die "Got error on insert: $DBI::errstr\n";
+ }
+ if (($tmpvar % 100) == 0)
+ {
+ $dbh->do("select max(info) from $firsttable") || die "Got error on select max(info): $DBI::errstr\n";
+ $dbh->do("select max(value) from $secondtable") || die "Got error on select max(info): $DBI::errstr\n";
+ $found+=2;
+ }
+ }
+ $dbh->disconnect;
+ print "Test_1: Inserted delayed $rows rows, found $found rows\n";
+ exit(0);
+}
+
+#
+# Update records in both tables
+#
+
+sub test_2
+{
+ my ($dbh,$id,$tmpvar,$rows,$found,$i,$max_id,$tmp,$sth,$count);
+
+ $dbh = DBI->connect("DBI:mysql:$opt_db:$opt_host") || die $DBI::errstr;
+ $tmpvar=111111;
+ $rows=$found=$max_id=$id=0;
+ for ($i=0 ; $i < $opt_loop_count ; $i++)
+ {
+ $tmp=(($tmpvar + 63) + $i)*3;
+ $tmp=$tmp-int($tmp/100000)*100000;
+ $tmpvar^= $tmp;
+ $tmp=$tmpvar - int($tmpvar/10)*10;
+ if ($max_id*$tmp == 0)
+ {
+ $max_id=0;
+ $sth=$dbh->prepare("select max(id) from $firsttable where marker=''");
+ $sth->execute() || die "Got error select max: $DBI::errstr\n";
+ if ((@row = $sth->fetchrow_array()) && defined($row[0]))
+ {
+ $found++;
+ $max_id=$id=$row[0];
+ }
+ $sth->finish;
+ }
+ else
+ {
+ $id= $tmpvar % ($max_id-1)+1;
+ }
+ if ($id)
+ {
+ ($count=$dbh->do("update $firsttable set marker='x' where id=$id")) || die "Got error update $firsttable: $DBI::errstr\n";
+ $rows+=$count;
+ if ($count > 0)
+ {
+ $count=$dbh->do("update $secondtable set value=$i where id=$id") || die "Got error update $firsttable: $DBI::errstr\n";
+ $rows+=$count;
+ }
+ }
+ }
+ $dbh->disconnect;
+ print "Test_2: Found $found rows, Updated $rows rows\n";
+ exit(0);
+}
+
+
+#
+# select records
+#
+
+sub test_3
+{
+ my ($dbh,$id,$tmpvar,$rows,$i,$count);
+ $dbh = DBI->connect("DBI:mysql:$opt_db:$opt_host") || die $DBI::errstr;
+ $tmpvar=222222;
+ $rows=0;
+ for ($i=0 ; $i < $opt_loop_count ; $i++)
+ {
+ $tmpvar^= ((($tmpvar + 63) + $i)*3 % 100000);
+ $id=$tmpvar % $opt_loop_count;
+ $count=$dbh->do("select id from $firsttable where id=$id") || die "Got error on select from $firsttable: $DBI::errstr\n";
+ $rows+=$count;
+ }
+ $dbh->disconnect;
+ print "Test_3: Found $rows rows\n";
+ exit(0);
+}
+
+
+#
+# Note that this uses row=1 and in some cases won't find any matching
+# records
+#
+
+sub test_4
+{
+ my ($dbh,$id,$tmpvar,$rows,$i,$count);
+ $dbh = DBI->connect("DBI:mysql:$opt_db:$opt_host") || die $DBI::errstr;
+ $tmpvar=333333;
+ $rows=0;
+ for ($i=0 ; $i < $opt_loop_count; $i++)
+ {
+ $tmpvar^= ((($tmpvar + 63) + $i)*3 % 100000);
+ $id=$tmpvar % $opt_loop_count;
+ $count=$dbh->do("select id from $secondtable where id=$id") || die "Got error on select from $secondtable: $DBI::errstr\n";
+ $rows+=$count;
+ }
+ $dbh->disconnect;
+ print "Test_4: Found $rows rows\n";
+ exit(0);
+}
+
+
+sub test_5
+{
+ my ($dbh,$id,$tmpvar,$rows,$i,$max_id,$count,$sth);
+ $dbh = DBI->connect("DBI:mysql:$opt_db:$opt_host") || die $DBI::errstr;
+ $tmpvar=444444;
+ $rows=$max_id=0;
+ for ($i=0 ; $i < $opt_loop_count ; $i++)
+ {
+ $tmpvar^= ((($tmpvar + 63) + $i)*3 % 100000);
+ if ($max_id == 0 || ($tmpvar % 10 == 0))
+ {
+ $sth=$dbh->prepare("select max(id) from $firsttable");
+ $sth->execute() || die "Got error select max: $DBI::errstr\n";
+ if ((@row = $sth->fetchrow_array()) && defined($row[0]))
+ {
+ $max_id=$id=$row[0];
+ }
+ else
+ {
+ $id=0;
+ }
+ $sth->finish;
+ }
+ else
+ {
+ $id= $tmpvar % $max_id;
+ }
+ $count=$dbh->do("select value from $firsttable,$secondtable where $firsttable.id=$id and $secondtable.id=$firsttable.id") || die "Got error on select from $secondtable: $DBI::errstr\n";
+ $rows+=$count;
+ }
+ $dbh->disconnect;
+ print "Test_5: Found $rows rows\n";
+ exit(0);
+}
+
+
+#
+# Delete the smallest row
+#
+
+sub test_del
+{
+ my ($dbh,$min_id,$i,$sth,$rows);
+ $dbh = DBI->connect("DBI:mysql:$opt_db:$opt_host") || die $DBI::errstr;
+ $rows=0;
+ for ($i=0 ; $i < $opt_loop_count/3; $i++)
+ {
+ $sth=$dbh->prepare("select min(id) from $firsttable");
+ $sth->execute() || die "Got error on select from $firsttable: $DBI::errstr\n";
+ if ((@row = $sth->fetchrow_array()) && defined($row[0]))
+ {
+ $min_id=$row[0];
+ }
+ $sth->finish;
+ $dbh->do("delete from $firsttable where id = $min_id") || die "Got error on DELETE from $firsttable: $DBI::errstr\n";
+ $rows++;
+ }
+ $dbh->disconnect;
+ print "Test_del: Deleted $rows rows\n";
+ exit(0);
+}
+
+
+#
+# Do a flush tables once in a while
+#
+
+sub test_flush
+{
+ my ($dbh,$sth,$found1,$last_found1,$i,@row);
+ $found1=0; $last_found1=-1;
+
+ $dbh = DBI->connect("DBI:mysql:$opt_db:$opt_host",
+ $opt_user, $opt_password,
+ { PrintError => 0}) || die $DBI::errstr;
+
+ for ($i=0; $found1 != $last_found1 ; $i++)
+ {
+ $sth=$dbh->prepare("flush tables") || die "Got error on prepare: $dbh->errstr\n";
+ $sth->execute || die $dbh->errstr;
+ $sth->finish;
+
+ $sth=$dbh->prepare("select count(*) from $firsttable") || die "Got error on prepare: $dbh->errstr\n";
+ $sth->execute || die $dbh->errstr;
+ @row = $sth->fetchrow_array();
+ $last_found1=$found1;
+ $found1= $row[0];
+ $sth->finish;
+ sleep(5);
+ }
+ $dbh->disconnect; $dbh=0;
+ print "flush: Did $i repair/checks\n";
+ exit(0);
+}
diff --git a/tests/udf_test b/tests/udf_test
new file mode 100644
index 00000000000..4621a7b34a5
--- /dev/null
+++ b/tests/udf_test
@@ -0,0 +1,30 @@
+#
+# For this script to work, you need to compile and install the
+# udf_example script !
+#
+
+CREATE FUNCTION metaphon RETURNS STRING SONAME "udf_example.so";
+CREATE FUNCTION myfunc_double RETURNS REAL SONAME "udf_example.so";
+CREATE FUNCTION myfunc_int RETURNS INTEGER SONAME "udf_example.so";
+CREATE FUNCTION lookup RETURNS STRING SONAME "udf_example.so";
+CREATE FUNCTION reverse_lookup RETURNS STRING SONAME "udf_example.so";
+CREATE AGGREGATE FUNCTION avgcost RETURNS REAL SONAME "udf_example.so";
+
+select metaphon("hello");
+select myfunc_double("hello","world");
+select myfunc_int(1,2,3),myfunc_int("1","11","111");
+select lookup("localhost");
+select reverse_lookup("127.0.0.1");
+
+create temporary table t1 (a int,b double);
+insert into t1 values (1,5),(1,4),(2,8),(3,9),(4,11);
+select avgcost(a,b) from t1;
+select avgcost(a,b) from t1 group by a;
+drop table t1;
+
+DROP FUNCTION metaphon;
+DROP FUNCTION myfunc_double;
+DROP FUNCTION myfunc_int;
+DROP FUNCTION lookup;
+DROP FUNCTION reverse_lookup;
+DROP FUNCTION avgcost;
diff --git a/tests/udf_test.res b/tests/udf_test.res
new file mode 100644
index 00000000000..66634e13616
--- /dev/null
+++ b/tests/udf_test.res
@@ -0,0 +1,151 @@
+--------------
+CREATE FUNCTION metaphon RETURNS STRING SONAME "udf_example.so"
+--------------
+
+Query OK, 0 rows affected
+
+--------------
+CREATE FUNCTION myfunc_double RETURNS REAL SONAME "udf_example.so"
+--------------
+
+Query OK, 0 rows affected
+
+--------------
+CREATE FUNCTION myfunc_int RETURNS INTEGER SONAME "udf_example.so"
+--------------
+
+Query OK, 0 rows affected
+
+--------------
+CREATE FUNCTION lookup RETURNS STRING SONAME "udf_example.so"
+--------------
+
+Query OK, 0 rows affected
+
+--------------
+CREATE FUNCTION reverse_lookup RETURNS STRING SONAME "udf_example.so"
+--------------
+
+Query OK, 0 rows affected
+
+--------------
+CREATE AGGREGATE FUNCTION avgcost RETURNS REAL SONAME "udf_example.so"
+--------------
+
+Query OK, 0 rows affected
+
+--------------
+select metaphon("hello")
+--------------
+
+metaphon("hello")
+HL
+1 row in set
+
+--------------
+select myfunc_double("hello","world")
+--------------
+
+myfunc_double("hello","world")
+108.40
+1 row in set
+
+--------------
+select myfunc_int(1,2,3),myfunc_int("1","11","111")
+--------------
+
+myfunc_int(1,2,3) myfunc_int("1","11","111")
+6 6
+1 row in set
+
+--------------
+select lookup("localhost")
+--------------
+
+lookup("localhost")
+127.0.0.1
+1 row in set
+
+--------------
+select reverse_lookup("127.0.0.1")
+--------------
+
+reverse_lookup("127.0.0.1")
+localhost
+1 row in set
+
+--------------
+create temporary table t1 (a int,b double)
+--------------
+
+Query OK, 0 rows affected
+
+--------------
+insert into t1 values (1,5),(1,4),(2,8),(3,9),(4,11)
+--------------
+
+Query OK, 5 rows affected
+Records: 0 Duplicates: 5 Warnings: 0
+
+--------------
+select avgcost(a,b) from t1
+--------------
+
+avgcost(a,b)
+8.7273
+1 row in set
+
+--------------
+select avgcost(a,b) from t1 group by a
+--------------
+
+avgcost(a,b)
+4.5000
+8.0000
+9.0000
+11.0000
+4 rows in set
+
+--------------
+drop table t1
+--------------
+
+Query OK, 0 rows affected
+
+--------------
+DROP FUNCTION metaphon
+--------------
+
+Query OK, 0 rows affected
+
+--------------
+DROP FUNCTION myfunc_double
+--------------
+
+Query OK, 0 rows affected
+
+--------------
+DROP FUNCTION myfunc_int
+--------------
+
+Query OK, 0 rows affected
+
+--------------
+DROP FUNCTION lookup
+--------------
+
+Query OK, 0 rows affected
+
+--------------
+DROP FUNCTION reverse_lookup
+--------------
+
+Query OK, 0 rows affected
+
+--------------
+DROP FUNCTION avgcost
+--------------
+
+Query OK, 0 rows affected
+
+Bye
diff --git a/vio/.cvsignore b/vio/.cvsignore
new file mode 100644
index 00000000000..c17bb8b88e1
--- /dev/null
+++ b/vio/.cvsignore
@@ -0,0 +1 @@
+skr99
diff --git a/vio/Makefile.am b/vio/Makefile.am
new file mode 100644
index 00000000000..dcdfb9c2112
--- /dev/null
+++ b/vio/Makefile.am
@@ -0,0 +1,44 @@
+# Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+INCLUDES = -I$(srcdir)/../include -I../include \
+ @OPENSSL_INCLUDES@
+LDADD = libvio.la
+
+
+pkglib_LTLIBRARIES = libvio.la
+noinst_PROGRAMS =
+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
+
+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 \
+ openssl/x509 openssl/ssl.h openssl/err.h \
+ openssl/pem.h openssl/asn1.h
+
diff --git a/vio/Vio.cc b/vio/Vio.cc
new file mode 100644
index 00000000000..b15f9cfa6d2
--- /dev/null
+++ b/vio/Vio.cc
@@ -0,0 +1,23 @@
+/*
+** 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
new file mode 100644
index 00000000000..959d472873f
--- /dev/null
+++ b/vio/Vio.h
@@ -0,0 +1,64 @@
+/*
+ * 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
new file mode 100644
index 00000000000..4572e2cb71b
--- /dev/null
+++ b/vio/VioAcceptorFd.cc
@@ -0,0 +1,18 @@
+
+/*
+** 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
new file mode 100644
index 00000000000..e0441780db9
--- /dev/null
+++ b/vio/VioAcceptorFd.h
@@ -0,0 +1,23 @@
+/*
+** 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
new file mode 100644
index 00000000000..49f81077a84
--- /dev/null
+++ b/vio/VioConnectorFd.cc
@@ -0,0 +1,22 @@
+
+/*
+ * 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
new file mode 100644
index 00000000000..da684df5f1b
--- /dev/null
+++ b/vio/VioConnectorFd.h
@@ -0,0 +1,19 @@
+/*
+ * 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
new file mode 100644
index 00000000000..3c6b0108fee
--- /dev/null
+++ b/vio/VioFd.cc
@@ -0,0 +1,156 @@
+/*
+** 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
new file mode 100644
index 00000000000..f1c009d848c
--- /dev/null
+++ b/vio/VioFd.h
@@ -0,0 +1,38 @@
+/*
+ * 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
new file mode 100644
index 00000000000..5d6f9f36496
--- /dev/null
+++ b/vio/VioPipe.cc
@@ -0,0 +1,25 @@
+/*
+** 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
new file mode 100644
index 00000000000..a6bb587c548
--- /dev/null
+++ b/vio/VioPipe.h
@@ -0,0 +1,38 @@
+/*
+ * 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
new file mode 100644
index 00000000000..a8efacf912f
--- /dev/null
+++ b/vio/VioSSL.cc
@@ -0,0 +1,292 @@
+/*
+** 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
new file mode 100644
index 00000000000..6446c10700e
--- /dev/null
+++ b/vio/VioSSL.h
@@ -0,0 +1,54 @@
+/*
+ * 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
new file mode 100644
index 00000000000..f821685430e
--- /dev/null
+++ b/vio/VioSSLAcceptorFd.cc
@@ -0,0 +1,4 @@
+
+#ifdef __GNUC__
+#pragma interface /* gcc class implementation */
+#endif
diff --git a/vio/VioSSLFactoriesFd.cc b/vio/VioSSLFactoriesFd.cc
new file mode 100644
index 00000000000..3fa660c049c
--- /dev/null
+++ b/vio/VioSSLFactoriesFd.cc
@@ -0,0 +1,360 @@
+/*
+** 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
new file mode 100644
index 00000000000..ed5a24f6b4a
--- /dev/null
+++ b/vio/VioSSLFactoriesFd.h
@@ -0,0 +1,64 @@
+/*
+ * 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
new file mode 100644
index 00000000000..cefb0b4bdc1
--- /dev/null
+++ b/vio/VioSocket.cc
@@ -0,0 +1,326 @@
+/* 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
new file mode 100644
index 00000000000..e2c6eafa516
--- /dev/null
+++ b/vio/VioSocket.h
@@ -0,0 +1,55 @@
+/*
+** 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/version.cc b/vio/version.cc
new file mode 100644
index 00000000000..7c09d431a9d
--- /dev/null
+++ b/vio/version.cc
@@ -0,0 +1,7 @@
+#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
new file mode 100644
index 00000000000..0c3d279695d
--- /dev/null
+++ b/vio/vio-global.h
@@ -0,0 +1,33 @@
+#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/vioelitexx.cc b/vio/vioelitexx.cc
new file mode 100644
index 00000000000..0eac28eaf55
--- /dev/null
+++ b/vio/vioelitexx.cc
@@ -0,0 +1,26 @@
+/* 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
new file mode 100644
index 00000000000..fc480f59db1
--- /dev/null
+++ b/vio/violite.h
@@ -0,0 +1,101 @@
+/* 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/vio/viotest-ssl.cc b/vio/viotest-ssl.cc
new file mode 100644
index 00000000000..a708831ba67
--- /dev/null
+++ b/vio/viotest-ssl.cc
@@ -0,0 +1,106 @@
+#include "all.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <stdio.h>
+#include <unistd.h>
+
+
+VIO_RCSID(vio, viotest_ssl, "$Id$")
+
+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/viotest-sslconnect.cc b/vio/viotest-sslconnect.cc
new file mode 100644
index 00000000000..505aac024f7
--- /dev/null
+++ b/vio/viotest-sslconnect.cc
@@ -0,0 +1,82 @@
+
+/*
+** Virtual I/O library
+** Written by Andrei Errapart <andreie@no.spam.ee>
+*/
+
+#include "all.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <stdio.h>
+#include <unistd.h>
+
+
+VIO_RCSID(vio, viotest_sslconnect, "$Id$")
+
+void
+fatal_error( const char* r)
+{
+ perror(r);
+ exit(0);
+}
+
+void
+print_usage()
+{
+ printf("viotest-sslconnect: testing SSL virtual IO. Usage:\n");
+ printf("viotest-sslconnect key cert\n");
+}
+
+int
+main( int argc,
+ char** argv)
+{
+ char* key = 0;
+ char* cert = 0;
+
+ if (argc<3)
+ {
+ print_usage();
+ return 1;
+ }
+
+ char ip[4] = {127, 0, 0, 1};
+ unsigned long addr = (unsigned long)
+ ((unsigned long)ip[0]<<24L)|
+ ((unsigned long)ip[1]<<16L)|
+ ((unsigned long)ip[2]<< 8L)|
+ ((unsigned long)ip[3]);
+ int fd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (fd<0)
+ fatal_error("socket");
+ struct sockaddr_in sa;
+ sa.sin_family = AF_INET;
+ sa.sin_port=htons(4433);
+ sa.sin_addr.s_addr=htonl(addr);
+ int sa_size = sizeof sa;
+ if (connect(fd, reinterpret_cast<const sockaddr*>(&sa), sa_size)==-1)
+ fatal_error("connect");
+ key = argv[1];
+ cert = argv[2];
+ printf("Key : %s\n", key);
+ printf("Cert : %s\n", cert);
+
+ VIO_NS::VioSSLConnectorFd* ssl_connector = new VIO_NS::VioSSLConnectorFd(cert, key,0,0);
+
+ VIO_NS::VioSSL* vio = ssl_connector->connect(fd);
+
+ char xbuf[100];
+ int r = vio->read(xbuf, sizeof(xbuf));
+ if (r<=0) {
+ delete ssl_connector;
+ delete vio;
+ fatal_error("client:SSL_read");
+ }
+ xbuf[r] = 0;
+ printf("client:got %s\n", xbuf);
+ delete vio;
+ delete ssl_connector;
+ return 0;
+}
diff --git a/vio/viotest.cc b/vio/viotest.cc
new file mode 100644
index 00000000000..f675267665d
--- /dev/null
+++ b/vio/viotest.cc
@@ -0,0 +1,49 @@
+/*
+** Virtual I/O library
+** Written by Andrei Errapart <andreie@no.spam.ee>
+*/
+
+#include "all.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
+
+#include <string.h>
+
+VIO_RCSID(vio, Vio, "$Id$")
+
+VIO_NS_USING;
+
+int
+main( int argc,
+ char** argv)
+{
+ VioFd* fs = 0;
+ VioSocket* ss = 0;
+ int fd = -1;
+ char* hh = "hshshsh\n";
+
+ DBUG_ENTER("main");
+ DBUG_PROCESS(argv[0]);
+ DBUG_PUSH("d:t");
+
+ fd = open("/dev/tty", O_WRONLY);
+ if (fd<0)
+ {
+ perror("open");
+ return 1;
+ }
+ fs = new VioFd(fd);
+ ss = new VioSocket(fd);
+ if (fs->write(hh,strlen(hh)) < 0)
+ perror("write");
+ ss->write(hh,strlen(hh));
+ printf("peer_name:%s\n", ss->peer_name());
+ printf("cipher_description:%s\n", ss->cipher_description());
+ delete fs;
+ delete ss;
+
+ DBUG_RETURN(0);
+}
+
diff --git a/vio/viotypes.h b/vio/viotypes.h
new file mode 100644
index 00000000000..8d36a35c86f
--- /dev/null
+++ b/vio/viotypes.h
@@ -0,0 +1,32 @@
+/*
+** 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_ */
+